summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
-rw-r--r--.gitignore1
-rw-r--r--adv_cmds/.upstream_base_commits3
-rw-r--r--adv_cmds/adv_cmds.xcodeproj/project.pbxproj1806
-rw-r--r--adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--adv_cmds/cap_mkdb/cap_mkdb.1101
-rw-r--r--adv_cmds/cap_mkdb/cap_mkdb.c228
-rw-r--r--adv_cmds/colldef/colldef.1274
-rw-r--r--adv_cmds/colldef/common.h36
-rw-r--r--adv_cmds/colldef/locale/collate.h121
-rw-r--r--adv_cmds/colldef/parse.y1416
-rw-r--r--adv_cmds/colldef/scan.l398
-rw-r--r--adv_cmds/finger/extern.h68
-rw-r--r--adv_cmds/finger/finger.1257
-rw-r--r--adv_cmds/finger/finger.c416
-rw-r--r--adv_cmds/finger/finger.conf.591
-rw-r--r--adv_cmds/finger/finger.h78
-rw-r--r--adv_cmds/finger/lprint.c367
-rw-r--r--adv_cmds/finger/net.c250
-rw-r--r--adv_cmds/finger/pathnames.h41
-rw-r--r--adv_cmds/finger/sprint.c187
-rw-r--r--adv_cmds/finger/util.c419
-rw-r--r--adv_cmds/gencat/gencat.1177
-rw-r--r--adv_cmds/gencat/gencat.c199
-rw-r--r--adv_cmds/gencat/gencat.h87
-rw-r--r--adv_cmds/gencat/genlib.c836
-rw-r--r--adv_cmds/last/last.1111
-rw-r--r--adv_cmds/last/last.c419
-rw-r--r--adv_cmds/locale/locale.1101
-rw-r--r--adv_cmds/locale/locale.cc428
-rw-r--r--adv_cmds/localedef/charmap.p-123
-rw-r--r--adv_cmds/localedef/charmap.p-2115
-rw-r--r--adv_cmds/localedef/charmap.test38
-rw-r--r--adv_cmds/localedef/def.a556
-rw-r--r--adv_cmds/localedef/def.p-1157
-rw-r--r--adv_cmds/localedef/def.p-2280
-rw-r--r--adv_cmds/localedef/localedef.1122
-rw-r--r--adv_cmds/localedef/localedef.pl1166
-rw-r--r--adv_cmds/lsvfs/lsvfs.167
-rw-r--r--adv_cmds/lsvfs/lsvfs.c99
-rw-r--r--adv_cmds/mklocale/extern.h40
-rw-r--r--adv_cmds/mklocale/ldef.h68
-rw-r--r--adv_cmds/mklocale/lex.l179
-rw-r--r--adv_cmds/mklocale/mklocale.1308
-rw-r--r--adv_cmds/mklocale/runefile.h87
-rw-r--r--adv_cmds/mklocale/yacc.y929
-rw-r--r--adv_cmds/pkill/entitlements.plist8
-rw-r--r--adv_cmds/pkill/pkill.1232
-rw-r--r--adv_cmds/pkill/pkill.c1111
-rw-r--r--adv_cmds/ps/entitlements.plist10
-rw-r--r--adv_cmds/ps/extern.h98
-rw-r--r--adv_cmds/ps/fmt.c132
-rw-r--r--adv_cmds/ps/keyword.c340
-rw-r--r--adv_cmds/ps/nlist.c86
-rw-r--r--adv_cmds/ps/print.c1225
-rw-r--r--adv_cmds/ps/ps.1663
-rw-r--r--adv_cmds/ps/ps.c1373
-rw-r--r--adv_cmds/ps/ps.h131
-rw-r--r--adv_cmds/ps/tasks.c246
-rw-r--r--adv_cmds/stty/cchar.c153
-rw-r--r--adv_cmds/stty/extern.h49
-rw-r--r--adv_cmds/stty/gfmt.c135
-rw-r--r--adv_cmds/stty/key.c297
-rw-r--r--adv_cmds/stty/modes.c308
-rw-r--r--adv_cmds/stty/print.c291
-rw-r--r--adv_cmds/stty/stty.1633
-rw-r--r--adv_cmds/stty/stty.c164
-rw-r--r--adv_cmds/stty/stty.h59
-rw-r--r--adv_cmds/stty/util.c68
-rw-r--r--adv_cmds/tabs/tabs.1160
-rw-r--r--adv_cmds/tabs/tabs.c240
-rw-r--r--adv_cmds/tty/tty.187
-rw-r--r--adv_cmds/tty/tty.c83
-rw-r--r--adv_cmds/whois/whois.1287
-rw-r--r--adv_cmds/whois/whois.c629
-rw-r--r--adv_cmds/xcodescripts/variant_links.sh11
-rw-r--r--basic_cmds/basic_cmds.xcodeproj/project.pbxproj546
-rw-r--r--basic_cmds/mesg/mesg.1112
-rw-r--r--basic_cmds/mesg/mesg.c116
-rw-r--r--basic_cmds/uudecode/base64.c317
-rw-r--r--basic_cmds/uudecode/uudecode.11
-rw-r--r--basic_cmds/uudecode/uudecode.c504
-rw-r--r--basic_cmds/uuencode/base64.c317
-rw-r--r--basic_cmds/uuencode/uuencode.1192
-rw-r--r--basic_cmds/uuencode/uuencode.5100
-rw-r--r--basic_cmds/uuencode/uuencode.c226
-rw-r--r--basic_cmds/write/write.1106
-rw-r--r--basic_cmds/write/write.c332
-rw-r--r--bootstrap_cmds/.gitignore6
-rw-r--r--bootstrap_cmds/APPLE_LICENSE335
-rw-r--r--bootstrap_cmds/mig.xcodeproj/project.pbxproj310
-rw-r--r--bootstrap_cmds/migcom.tproj/alloc.h54
-rw-r--r--bootstrap_cmds/migcom.tproj/error.c111
-rw-r--r--bootstrap_cmds/migcom.tproj/error.h61
-rw-r--r--bootstrap_cmds/migcom.tproj/global.c151
-rw-r--r--bootstrap_cmds/migcom.tproj/global.h113
-rw-r--r--bootstrap_cmds/migcom.tproj/handler.c754
-rw-r--r--bootstrap_cmds/migcom.tproj/header.c569
-rw-r--r--bootstrap_cmds/migcom.tproj/lexxer.h52
-rw-r--r--bootstrap_cmds/migcom.tproj/lexxer.l314
-rw-r--r--bootstrap_cmds/migcom.tproj/mig.188
-rw-r--r--bootstrap_cmds/migcom.tproj/mig.c405
-rw-r--r--bootstrap_cmds/migcom.tproj/mig.sh218
-rw-r--r--bootstrap_cmds/migcom.tproj/mig_errors.h84
-rw-r--r--bootstrap_cmds/migcom.tproj/mig_machine.h16
-rw-r--r--bootstrap_cmds/migcom.tproj/migcom.173
-rw-r--r--bootstrap_cmds/migcom.tproj/parser.y803
-rw-r--r--bootstrap_cmds/migcom.tproj/routine.c1844
-rw-r--r--bootstrap_cmds/migcom.tproj/routine.h549
-rw-r--r--bootstrap_cmds/migcom.tproj/server.c2772
-rw-r--r--bootstrap_cmds/migcom.tproj/statement.c68
-rw-r--r--bootstrap_cmds/migcom.tproj/statement.h98
-rw-r--r--bootstrap_cmds/migcom.tproj/strdefs.h93
-rw-r--r--bootstrap_cmds/migcom.tproj/string.c132
-rw-r--r--bootstrap_cmds/migcom.tproj/type.c899
-rw-r--r--bootstrap_cmds/migcom.tproj/type.h270
-rw-r--r--bootstrap_cmds/migcom.tproj/user.c3260
-rw-r--r--bootstrap_cmds/migcom.tproj/utils.c1043
-rw-r--r--bootstrap_cmds/migcom.tproj/utils.h140
-rw-r--r--bootstrap_cmds/migcom.tproj/write.h78
-rw-r--r--bootstrap_cmds/xcodescripts/install-mig.sh8
-rw-r--r--developer_cmds/asa/asa.185
-rw-r--r--developer_cmds/asa/asa.c131
-rw-r--r--developer_cmds/ctags/C.c555
-rw-r--r--developer_cmds/ctags/ctags.1221
-rw-r--r--developer_cmds/ctags/ctags.c282
-rw-r--r--developer_cmds/ctags/ctags.h92
-rw-r--r--developer_cmds/ctags/fortran.c175
-rw-r--r--developer_cmds/ctags/lisp.c112
-rw-r--r--developer_cmds/ctags/print.c122
-rw-r--r--developer_cmds/ctags/test/ctags.test69
-rw-r--r--developer_cmds/ctags/tree.c142
-rw-r--r--developer_cmds/ctags/yacc.c158
-rw-r--r--developer_cmds/developer_cmds.xcodeproj/project.pbxproj787
-rw-r--r--developer_cmds/developer_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--developer_cmds/indent/args.c327
-rw-r--r--developer_cmds/indent/indent.1559
-rw-r--r--developer_cmds/indent/indent.c1234
-rw-r--r--developer_cmds/indent/indent.h47
-rw-r--r--developer_cmds/indent/indent_codes.h70
-rw-r--r--developer_cmds/indent/indent_globs.h329
-rw-r--r--developer_cmds/indent/io.c667
-rw-r--r--developer_cmds/indent/lexi.c608
-rw-r--r--developer_cmds/indent/parse.c332
-rw-r--r--developer_cmds/indent/pr_comment.c429
-rw-r--r--developer_cmds/lorder/lorder.175
-rw-r--r--developer_cmds/lorder/lorder.sh104
-rw-r--r--developer_cmds/rpcgen/rpc_clntout.c230
-rw-r--r--developer_cmds/rpcgen/rpc_cout.c741
-rw-r--r--developer_cmds/rpcgen/rpc_hout.c534
-rw-r--r--developer_cmds/rpcgen/rpc_main.c1170
-rw-r--r--developer_cmds/rpcgen/rpc_parse.c643
-rw-r--r--developer_cmds/rpcgen/rpc_parse.h168
-rw-r--r--developer_cmds/rpcgen/rpc_sample.c261
-rw-r--r--developer_cmds/rpcgen/rpc_scan.c521
-rw-r--r--developer_cmds/rpcgen/rpc_scan.h104
-rw-r--r--developer_cmds/rpcgen/rpc_svcout.c980
-rw-r--r--developer_cmds/rpcgen/rpc_tblout.c179
-rw-r--r--developer_cmds/rpcgen/rpc_util.c513
-rw-r--r--developer_cmds/rpcgen/rpc_util.h178
-rw-r--r--developer_cmds/rpcgen/rpcgen.1452
-rw-r--r--developer_cmds/unifdef/unifdef.1415
-rw-r--r--developer_cmds/unifdef/unifdef.c1235
-rw-r--r--developer_cmds/unifdef/unifdefall.sh79
-rw-r--r--developer_cmds/xcodescripts/install-lorder.sh7
-rw-r--r--developer_cmds/xcodescripts/install-unifdefall.sh9
-rw-r--r--diskdev_cmds/APPLE_LICENSE367
-rw-r--r--diskdev_cmds/dev_mkdb.tproj/dev_mkdb.881
-rw-r--r--diskdev_cmds/dev_mkdb.tproj/dev_mkdb.c202
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/project.pbxproj2411
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings8
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/All_MacOSX.xcscheme61
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/All_iOS.xcscheme61
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/Common.xcscheme61
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/dev_mkdb.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/edquota.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fdisk.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fsck.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_msdos.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_ntfs.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_udf.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fuser.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/libdisk.xcscheme61
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount_devfs.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount_fdesc.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quota.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quotacheck.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quotaon.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/repquota.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/setclass.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/umount.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/vndevice.xcscheme88
-rw-r--r--diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/vsdbutil.xcscheme88
-rw-r--r--diskdev_cmds/disklib/dkcksum.c77
-rw-r--r--diskdev_cmds/disklib/dkdisklabel.c193
-rw-r--r--diskdev_cmds/disklib/dkopen.c57
-rw-r--r--diskdev_cmds/disklib/dkopen.h56
-rw-r--r--diskdev_cmds/disklib/dksecsize.c75
-rw-r--r--diskdev_cmds/disklib/pathnames.h63
-rw-r--r--diskdev_cmds/disklib/preen.c392
-rw-r--r--diskdev_cmds/disklib/vfslist.c112
-rw-r--r--diskdev_cmds/edquota.tproj/edquota.8184
-rw-r--r--diskdev_cmds/edquota.tproj/edquota.c1228
-rw-r--r--diskdev_cmds/edquota.tproj/pathnames.h61
-rw-r--r--diskdev_cmds/edt_fstab/edt_fstab.c180
-rw-r--r--diskdev_cmds/edt_fstab/edt_fstab.h47
-rw-r--r--diskdev_cmds/fdisk.tproj/auto.c155
-rw-r--r--diskdev_cmds/fdisk.tproj/auto.h31
-rw-r--r--diskdev_cmds/fdisk.tproj/cmd.c507
-rw-r--r--diskdev_cmds/fdisk.tproj/cmd.h105
-rw-r--r--diskdev_cmds/fdisk.tproj/disk.c309
-rw-r--r--diskdev_cmds/fdisk.tproj/disk.h83
-rw-r--r--diskdev_cmds/fdisk.tproj/fdisk.8377
-rw-r--r--diskdev_cmds/fdisk.tproj/fdisk.c289
-rw-r--r--diskdev_cmds/fdisk.tproj/getrawpartition.c87
-rw-r--r--diskdev_cmds/fdisk.tproj/mbr.c553
-rw-r--r--diskdev_cmds/fdisk.tproj/mbr.h114
-rw-r--r--diskdev_cmds/fdisk.tproj/mbrcode.h119
-rw-r--r--diskdev_cmds/fdisk.tproj/misc.c183
-rw-r--r--diskdev_cmds/fdisk.tproj/misc.h74
-rw-r--r--diskdev_cmds/fdisk.tproj/opendev.c111
-rw-r--r--diskdev_cmds/fdisk.tproj/part.c425
-rw-r--r--diskdev_cmds/fdisk.tproj/part.h80
-rw-r--r--diskdev_cmds/fdisk.tproj/user.c275
-rw-r--r--diskdev_cmds/fdisk.tproj/user.h65
-rw-r--r--diskdev_cmds/fdisk.tproj/util.h137
-rw-r--r--diskdev_cmds/fsck.tproj/fsck.8176
-rw-r--r--diskdev_cmds/fsck.tproj/fsck.c1339
-rw-r--r--diskdev_cmds/fsck.tproj/fsck.h121
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp.841
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp.c167
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_msdos.841
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_msdos.c213
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_ntfs.841
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_ntfs.c206
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_udf.840
-rw-r--r--diskdev_cmds/fstyp.tproj/fstyp_udf.c306
-rw-r--r--diskdev_cmds/fuser.tproj/fuser.1200
-rwxr-xr-xdiskdev_cmds/fuser.tproj/fuser.pl92
-rw-r--r--diskdev_cmds/mount.tproj/fstab.5222
-rw-r--r--diskdev_cmds/mount.tproj/mount.8293
-rw-r--r--diskdev_cmds/mount.tproj/mount.c1696
-rw-r--r--diskdev_cmds/mount.tproj/mount.entitlements12
-rw-r--r--diskdev_cmds/mount.tproj/pathnames.h63
-rw-r--r--diskdev_cmds/mount_devfs.tproj/mount_devfs.c117
-rw-r--r--diskdev_cmds/mount_fdesc.tproj/mount_fdesc.8171
-rw-r--r--diskdev_cmds/mount_fdesc.tproj/mount_fdesc.c128
-rw-r--r--diskdev_cmds/mount_flags_dir/mount_flags.c88
-rw-r--r--diskdev_cmds/mount_flags_dir/mount_flags.h66
-rw-r--r--diskdev_cmds/quota.tproj/quota.1137
-rw-r--r--diskdev_cmds/quota.tproj/quota.c858
-rw-r--r--diskdev_cmds/quotacheck.tproj/hfs_quotacheck.c169
-rw-r--r--diskdev_cmds/quotacheck.tproj/quotacheck.8156
-rw-r--r--diskdev_cmds/quotacheck.tproj/quotacheck.c972
-rw-r--r--diskdev_cmds/quotacheck.tproj/quotacheck.h87
-rw-r--r--diskdev_cmds/quotaon.tproj/quotaon.8159
-rw-r--r--diskdev_cmds/quotaon.tproj/quotaon.c400
-rw-r--r--diskdev_cmds/repquota.tproj/repquota.8109
-rw-r--r--diskdev_cmds/repquota.tproj/repquota.c630
-rw-r--r--diskdev_cmds/setclass.tproj/setclass.846
-rw-r--r--diskdev_cmds/setclass.tproj/setclass.c153
-rw-r--r--diskdev_cmds/umount.tproj/umount.8133
-rw-r--r--diskdev_cmds/umount.tproj/umount.c655
-rw-r--r--diskdev_cmds/vndevice.tproj/vndevice.c134
-rw-r--r--diskdev_cmds/vsdbutil.tproj/com.apple.vsdbutil.plist21
-rw-r--r--diskdev_cmds/vsdbutil.tproj/vsdbutil.849
-rw-r--r--diskdev_cmds/vsdbutil.tproj/vsdbutil_main.c1213
-rw-r--r--doc_cmds/checknr/checknr.1163
-rw-r--r--doc_cmds/checknr/checknr.c607
-rw-r--r--doc_cmds/colcrt/colcrt.1124
-rw-r--r--doc_cmds/colcrt/colcrt.c287
-rw-r--r--doc_cmds/doc_cmds.plist72
-rw-r--r--doc_cmds/doc_cmds.txt134
-rw-r--r--doc_cmds/doc_cmds.xcodeproj/project.pbxproj538
-rw-r--r--doc_cmds/intro.174
-rw-r--r--doc_cmds/makewhatis/makewhatis.8133
-rw-r--r--doc_cmds/makewhatis/makewhatis.c1094
-rw-r--r--doc_cmds/makewhatis/makewhatis.local.869
-rw-r--r--doc_cmds/makewhatis/makewhatis.local.sh64
-rw-r--r--file_cmds/.upstream_base_commits2
-rw-r--r--file_cmds/chflags/chflags.1185
-rw-r--r--file_cmds/chflags/chflags.c204
-rw-r--r--file_cmds/chmod/chmod.1604
-rw-r--r--file_cmds/chmod/chmod.c458
-rw-r--r--file_cmds/chmod/chmod_acl.c859
-rw-r--r--file_cmds/chmod/chmod_acl.h90
-rw-r--r--file_cmds/chown/chgrp.1144
-rw-r--r--file_cmds/chown/chown.8177
-rw-r--r--file_cmds/chown/chown.c345
-rw-r--r--file_cmds/cksum/cksum.1182
-rw-r--r--file_cmds/cksum/cksum.c148
-rw-r--r--file_cmds/cksum/crc.c148
-rw-r--r--file_cmds/cksum/crc32.c122
-rw-r--r--file_cmds/cksum/extern.h52
-rw-r--r--file_cmds/cksum/print.c75
-rw-r--r--file_cmds/cksum/sum.11
-rw-r--r--file_cmds/cksum/sum1.c77
-rw-r--r--file_cmds/cksum/sum2.c79
-rw-r--r--file_cmds/compress/compress.1253
-rw-r--r--file_cmds/compress/compress.c467
-rw-r--r--file_cmds/compress/doc/NOTES142
-rw-r--r--file_cmds/compress/doc/README284
-rw-r--r--file_cmds/compress/doc/revision.log118
-rw-r--r--file_cmds/compress/uncompress.11
-rw-r--r--file_cmds/compress/zcat.sh38
-rw-r--r--file_cmds/compress/zopen.3137
-rw-r--r--file_cmds/compress/zopen.c738
-rw-r--r--file_cmds/compress/zopen.h34
-rw-r--r--file_cmds/cp/cp.1311
-rw-r--r--file_cmds/cp/cp.c571
-rw-r--r--file_cmds/cp/extern.h61
-rw-r--r--file_cmds/cp/utils.c541
-rw-r--r--file_cmds/csh/strpct.c99
-rw-r--r--file_cmds/dd/args.c421
-rw-r--r--file_cmds/dd/conv.c273
-rw-r--r--file_cmds/dd/conv_tab.c289
-rw-r--r--file_cmds/dd/dd.1382
-rw-r--r--file_cmds/dd/dd.c481
-rw-r--r--file_cmds/dd/dd.entitlements9
-rw-r--r--file_cmds/dd/dd.h102
-rw-r--r--file_cmds/dd/extern.h73
-rw-r--r--file_cmds/dd/install_symlink.sh16
-rw-r--r--file_cmds/dd/misc.c108
-rw-r--r--file_cmds/dd/position.c169
-rw-r--r--file_cmds/df/df.1217
-rw-r--r--file_cmds/df/df.c639
-rw-r--r--file_cmds/df/vfslist.c103
-rw-r--r--file_cmds/du/du.1172
-rw-r--r--file_cmds/du/du.c730
-rw-r--r--file_cmds/file_cmds.xcodeproj/project.pbxproj3984
-rw-r--r--file_cmds/gzip/futimens.c100
-rw-r--r--file_cmds/gzip/gzexe179
-rw-r--r--file_cmds/gzip/gzexe.173
-rw-r--r--file_cmds/gzip/gzip.1234
-rw-r--r--file_cmds/gzip/gzip.c2256
-rw-r--r--file_cmds/gzip/gzip.plist29
-rw-r--r--file_cmds/gzip/gzip.xcconfig49
-rw-r--r--file_cmds/gzip/install_scripts.sh22
-rw-r--r--file_cmds/gzip/unbzip2.c141
-rw-r--r--file_cmds/gzip/unpack.c329
-rw-r--r--file_cmds/gzip/unxz.c153
-rw-r--r--file_cmds/gzip/zdiff142
-rw-r--r--file_cmds/gzip/zdiff.1142
-rw-r--r--file_cmds/gzip/zforce55
-rw-r--r--file_cmds/gzip/zforce.153
-rw-r--r--file_cmds/gzip/zmore82
-rw-r--r--file_cmds/gzip/zmore.1110
-rw-r--r--file_cmds/gzip/znew137
-rw-r--r--file_cmds/gzip/znew.171
-rw-r--r--file_cmds/gzip/zuncompress.c396
-rw-r--r--file_cmds/install/install.1253
-rw-r--r--file_cmds/install/pathnames.h41
-rw-r--r--file_cmds/install/xinstall.c816
-rw-r--r--file_cmds/ipcrm/ipcrm.184
-rw-r--r--file_cmds/ipcrm/ipcrm.c179
-rw-r--r--file_cmds/ipcs/ipcs.1132
-rw-r--r--file_cmds/ipcs/ipcs.c553
-rw-r--r--file_cmds/ln/link.11
-rw-r--r--file_cmds/ln/ln.1233
-rw-r--r--file_cmds/ln/ln.c272
-rw-r--r--file_cmds/ln/symlink.7457
-rw-r--r--file_cmds/ls/cmp.c226
-rw-r--r--file_cmds/ls/extern.h73
-rw-r--r--file_cmds/ls/ls.1715
-rw-r--r--file_cmds/ls/ls.c977
-rw-r--r--file_cmds/ls/ls.h108
-rw-r--r--file_cmds/ls/print.c837
-rw-r--r--file_cmds/ls/util.c231
-rw-r--r--file_cmds/mkdir/mkdir.1108
-rw-r--r--file_cmds/mkdir/mkdir.c144
-rw-r--r--file_cmds/mkfifo/mkfifo.1103
-rw-r--r--file_cmds/mkfifo/mkfifo.c128
-rw-r--r--file_cmds/mknod/mknod.8137
-rw-r--r--file_cmds/mknod/mknod.c405
-rw-r--r--file_cmds/mtree/commoncrypto.c378
-rw-r--r--file_cmds/mtree/commoncrypto.h36
-rw-r--r--file_cmds/mtree/compare.c688
-rw-r--r--file_cmds/mtree/create.c611
-rw-r--r--file_cmds/mtree/excludes.c114
-rw-r--r--file_cmds/mtree/extern.h71
-rwxr-xr-xfile_cmds/mtree/fix_failure_locations.py77
-rw-r--r--file_cmds/mtree/metrics.c155
-rw-r--r--file_cmds/mtree/metrics.h48
-rw-r--r--file_cmds/mtree/misc.c189
-rw-r--r--file_cmds/mtree/mtree.8393
-rw-r--r--file_cmds/mtree/mtree.c358
-rw-r--r--file_cmds/mtree/mtree.h120
-rw-r--r--file_cmds/mtree/spec.c470
-rw-r--r--file_cmds/mtree/specspec.c327
-rw-r--r--file_cmds/mtree/test/test00.sh67
-rw-r--r--file_cmds/mtree/test/test01.sh40
-rw-r--r--file_cmds/mtree/test/test02.sh36
-rw-r--r--file_cmds/mtree/test/test03.sh60
-rw-r--r--file_cmds/mtree/test/test04.sh51
-rw-r--r--file_cmds/mtree/verify.c341
-rw-r--r--file_cmds/mv/mv.1184
-rw-r--r--file_cmds/mv/mv.c505
-rw-r--r--file_cmds/mv/pathnames.h45
-rw-r--r--file_cmds/pathchk/pathchk.1121
-rw-r--r--file_cmds/pathchk/pathchk.c196
-rw-r--r--file_cmds/pax/ar_io.c1318
-rw-r--r--file_cmds/pax/ar_subs.c1517
-rw-r--r--file_cmds/pax/buf_subs.c994
-rw-r--r--file_cmds/pax/cache.c426
-rw-r--r--file_cmds/pax/cache.h78
-rw-r--r--file_cmds/pax/cpio.1304
-rw-r--r--file_cmds/pax/cpio.c1149
-rw-r--r--file_cmds/pax/cpio.h155
-rw-r--r--file_cmds/pax/extern.h347
-rw-r--r--file_cmds/pax/file_subs.c1180
-rw-r--r--file_cmds/pax/ftree.c585
-rw-r--r--file_cmds/pax/ftree.h56
-rw-r--r--file_cmds/pax/gen_subs.c458
-rw-r--r--file_cmds/pax/getoldopt.c74
-rw-r--r--file_cmds/pax/options.c1747
-rw-r--r--file_cmds/pax/options.h118
-rw-r--r--file_cmds/pax/pat_rep.c1211
-rw-r--r--file_cmds/pax/pat_rep.h56
-rw-r--r--file_cmds/pax/pax.11185
-rw-r--r--file_cmds/pax/pax.c446
-rw-r--r--file_cmds/pax/pax.h255
-rw-r--r--file_cmds/pax/pax_format.c1624
-rw-r--r--file_cmds/pax/pax_format.h158
-rw-r--r--file_cmds/pax/sel_subs.c614
-rw-r--r--file_cmds/pax/sel_subs.h77
-rw-r--r--file_cmds/pax/tables.c1278
-rw-r--r--file_cmds/pax/tables.h175
-rw-r--r--file_cmds/pax/tar.c1206
-rw-r--r--file_cmds/pax/tar.h161
-rw-r--r--file_cmds/pax/tty_subs.c200
-rw-r--r--file_cmds/rm/rm.1216
-rw-r--r--file_cmds/rm/rm.c601
-rw-r--r--file_cmds/rm/unlink.11
-rw-r--r--file_cmds/rmdir/rmdir.1100
-rw-r--r--file_cmds/rmdir/rmdir.c122
-rw-r--r--file_cmds/rmt/rmt.8220
-rw-r--r--file_cmds/rmt/rmt.c259
-rw-r--r--file_cmds/shar/shar.1105
-rw-r--r--file_cmds/shar/shar.sh76
-rw-r--r--file_cmds/stat/readlink.11
-rw-r--r--file_cmds/stat/stat.1534
-rw-r--r--file_cmds/stat/stat.c1004
-rw-r--r--file_cmds/tests/chgrp.sh26
-rw-r--r--file_cmds/tests/file_cmds.plist33
-rw-r--r--file_cmds/touch/touch.1221
-rw-r--r--file_cmds/touch/touch.c430
-rw-r--r--file_cmds/xcodescripts/hardlink.sh16
-rw-r--r--mail_cmds/Makefile5
-rw-r--r--mail_cmds/biff/Makefile10
-rw-r--r--mail_cmds/biff/biff.1127
-rw-r--r--mail_cmds/biff/biff.c117
-rw-r--r--mail_cmds/comsat/Makefile11
-rw-r--r--mail_cmds/comsat/comsat.8115
-rw-r--r--mail_cmds/comsat/comsat.c314
-rw-r--r--mail_cmds/comsat/comsat.plist29
-rw-r--r--mail_cmds/from/Makefile10
-rw-r--r--mail_cmds/from/from.199
-rw-r--r--mail_cmds/from/from.c173
-rw-r--r--mail_cmds/mail/Makefile24
-rw-r--r--mail_cmds/mail/USD.doc/Makefile12
-rw-r--r--mail_cmds/mail/USD.doc/mail0.nr71
-rw-r--r--mail_cmds/mail/USD.doc/mail1.nr92
-rw-r--r--mail_cmds/mail/USD.doc/mail2.nr617
-rw-r--r--mail_cmds/mail/USD.doc/mail3.nr133
-rw-r--r--mail_cmds/mail/USD.doc/mail4.nr437
-rw-r--r--mail_cmds/mail/USD.doc/mail5.nr1042
-rw-r--r--mail_cmds/mail/USD.doc/mail6.nr125
-rw-r--r--mail_cmds/mail/USD.doc/mail7.nr107
-rw-r--r--mail_cmds/mail/USD.doc/mail8.nr75
-rw-r--r--mail_cmds/mail/USD.doc/mail9.nr203
-rw-r--r--mail_cmds/mail/USD.doc/maila.nr33
-rw-r--r--mail_cmds/mail/aux.c635
-rw-r--r--mail_cmds/mail/cmd1.c487
-rw-r--r--mail_cmds/mail/cmd2.c587
-rw-r--r--mail_cmds/mail/cmd3.c840
-rw-r--r--mail_cmds/mail/cmdtab.c133
-rw-r--r--mail_cmds/mail/collect.c998
-rw-r--r--mail_cmds/mail/def.h283
-rw-r--r--mail_cmds/mail/edit.c231
-rw-r--r--mail_cmds/mail/extern.h268
-rw-r--r--mail_cmds/mail/fio.c475
-rw-r--r--mail_cmds/mail/getname.c77
-rw-r--r--mail_cmds/mail/glob.h112
-rw-r--r--mail_cmds/mail/head.c291
-rw-r--r--mail_cmds/mail/lex.c736
-rw-r--r--mail_cmds/mail/list.c843
-rw-r--r--mail_cmds/mail/mail.11272
-rw-r--r--mail_cmds/mail/mailx.11
-rw-r--r--mail_cmds/mail/main.c395
-rw-r--r--mail_cmds/mail/misc/mail.help23
-rw-r--r--mail_cmds/mail/misc/mail.rc2
-rw-r--r--mail_cmds/mail/misc/mail.tildehelp36
-rw-r--r--mail_cmds/mail/names.c793
-rw-r--r--mail_cmds/mail/pathnames.h47
-rw-r--r--mail_cmds/mail/popen.c402
-rw-r--r--mail_cmds/mail/quit.c505
-rw-r--r--mail_cmds/mail/rcv.h52
-rw-r--r--mail_cmds/mail/send.c629
-rw-r--r--mail_cmds/mail/strings.c131
-rw-r--r--mail_cmds/mail/strlcpy.c74
-rw-r--r--mail_cmds/mail/temp.c94
-rw-r--r--mail_cmds/mail/tty.c306
-rw-r--r--mail_cmds/mail/v7.local.c101
-rw-r--r--mail_cmds/mail/vars.c196
-rw-r--r--mail_cmds/mail/version.c48
-rw-r--r--mail_cmds/msgs/Makefile11
-rw-r--r--mail_cmds/msgs/msgs.1236
-rw-r--r--mail_cmds/msgs/msgs.c923
-rw-r--r--mail_cmds/msgs/pathnames.h40
-rw-r--r--misc_cmds/calendar/calendar.1265
-rw-r--r--misc_cmds/calendar/calendar.c153
-rw-r--r--misc_cmds/calendar/calendar.h93
-rw-r--r--misc_cmds/calendar/calendars/calendar.all20
-rw-r--r--misc_cmds/calendar/calendars/calendar.australia58
-rw-r--r--misc_cmds/calendar/calendars/calendar.birthday299
-rw-r--r--misc_cmds/calendar/calendars/calendar.christian32
-rw-r--r--misc_cmds/calendar/calendars/calendar.computer76
-rw-r--r--misc_cmds/calendar/calendars/calendar.croatian12
-rw-r--r--misc_cmds/calendar/calendars/calendar.dutch78
-rw-r--r--misc_cmds/calendar/calendars/calendar.freebsd283
-rw-r--r--misc_cmds/calendar/calendars/calendar.french12
-rw-r--r--misc_cmds/calendar/calendars/calendar.german12
-rw-r--r--misc_cmds/calendar/calendars/calendar.history476
-rw-r--r--misc_cmds/calendar/calendars/calendar.holiday563
-rw-r--r--misc_cmds/calendar/calendars/calendar.hungarian12
-rw-r--r--misc_cmds/calendar/calendars/calendar.judaic227
-rw-r--r--misc_cmds/calendar/calendars/calendar.lotr48
-rw-r--r--misc_cmds/calendar/calendars/calendar.music240
-rw-r--r--misc_cmds/calendar/calendars/calendar.newzealand25
-rw-r--r--misc_cmds/calendar/calendars/calendar.russian12
-rw-r--r--misc_cmds/calendar/calendars/calendar.southafrica23
-rw-r--r--misc_cmds/calendar/calendars/calendar.ukrainian12
-rw-r--r--misc_cmds/calendar/calendars/calendar.usholiday42
-rw-r--r--misc_cmds/calendar/calendars/calendar.world19
-rw-r--r--misc_cmds/calendar/calendars/de_AT.ISO_8859-15/calendar.feiertag62
-rw-r--r--misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.all17
-rw-r--r--misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag56
-rw-r--r--misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte198
-rw-r--r--misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.kirche32
-rw-r--r--misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.literatur54
-rw-r--r--misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.musik66
-rw-r--r--misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft19
-rw-r--r--misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.all14
-rw-r--r--misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.fetes630
-rw-r--r--misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.french12
-rw-r--r--misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.jferies46
-rw-r--r--misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.proverbes354
-rw-r--r--misc_cmds/calendar/calendars/hr_HR.ISO8859-2/calendar.all12
-rw-r--r--misc_cmds/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici44
-rw-r--r--misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.all13
-rw-r--r--misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.nevnapok386
-rw-r--r--misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.unnepek53
-rw-r--r--misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.all17
-rw-r--r--misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.common90
-rw-r--r--misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.holiday25
-rw-r--r--misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.military27
-rw-r--r--misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.msk16
-rw-r--r--misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox34
-rw-r--r--misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.pagan42
-rw-r--r--misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.all14
-rw-r--r--misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.holiday22
-rw-r--r--misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.misc18
-rw-r--r--misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.orthodox35
-rw-r--r--misc_cmds/calendar/day.c498
-rw-r--r--misc_cmds/calendar/io.c470
-rw-r--r--misc_cmds/calendar/ostern.c111
-rw-r--r--misc_cmds/calendar/paskha.c93
-rw-r--r--misc_cmds/calendar/pathnames.h40
-rw-r--r--misc_cmds/leave/leave.1100
-rw-r--r--misc_cmds/leave/leave.c196
-rw-r--r--misc_cmds/misc_cmds.xcodeproj/project.pbxproj971
-rw-r--r--misc_cmds/ncal/calendar.c330
-rw-r--r--misc_cmds/ncal/calendar.h42
-rw-r--r--misc_cmds/ncal/easter.c101
-rw-r--r--misc_cmds/ncal/ncal.1198
-rw-r--r--misc_cmds/ncal/ncal.c1177
-rw-r--r--misc_cmds/tsort/tsort.190
-rw-r--r--misc_cmds/tsort/tsort.c443
-rw-r--r--misc_cmds/units/pathnames.h33
-rw-r--r--misc_cmds/units/units.1181
-rw-r--r--misc_cmds/units/units.c749
-rw-r--r--misc_cmds/units/units.lib732
-rw-r--r--network_cmds/APPLE_LICENSE370
-rw-r--r--network_cmds/arp.tproj/IMPORT_NOTES3
-rw-r--r--network_cmds/arp.tproj/arp.8251
-rw-r--r--network_cmds/arp.tproj/arp.c1163
-rw-r--r--network_cmds/arp.tproj/arp4.4123
-rw-r--r--network_cmds/cfilutil/cfilstat.c341
-rw-r--r--network_cmds/cfilutil/cfilutil.156
-rw-r--r--network_cmds/cfilutil/cfilutil.c987
-rw-r--r--network_cmds/dnctl/dnctl.8508
-rw-r--r--network_cmds/dnctl/dnctl.c1313
-rw-r--r--network_cmds/ecnprobe/base.h57
-rw-r--r--network_cmds/ecnprobe/capture.c204
-rw-r--r--network_cmds/ecnprobe/capture.h58
-rw-r--r--network_cmds/ecnprobe/ecn.c1119
-rw-r--r--network_cmds/ecnprobe/ecn.h49
-rw-r--r--network_cmds/ecnprobe/ecn_probe.c469
-rw-r--r--network_cmds/ecnprobe/ecnprobe.120
-rw-r--r--network_cmds/ecnprobe/gmt2local.c66
-rw-r--r--network_cmds/ecnprobe/gmt2local.h27
-rw-r--r--network_cmds/ecnprobe/history.c211
-rw-r--r--network_cmds/ecnprobe/history.h75
-rw-r--r--network_cmds/ecnprobe/inet.c503
-rw-r--r--network_cmds/ecnprobe/inet.h206
-rw-r--r--network_cmds/ecnprobe/session.c785
-rw-r--r--network_cmds/ecnprobe/session.h183
-rw-r--r--network_cmds/ecnprobe/support.c246
-rw-r--r--network_cmds/ecnprobe/support.h132
-rw-r--r--network_cmds/frame_delay/frame_delay.845
-rw-r--r--network_cmds/frame_delay/frame_delay.c595
-rw-r--r--network_cmds/ifconfig.tproj/af_inet.c316
-rw-r--r--network_cmds/ifconfig.tproj/af_inet6.c753
-rw-r--r--network_cmds/ifconfig.tproj/af_link.c164
-rw-r--r--network_cmds/ifconfig.tproj/if6lowpan.c178
-rw-r--r--network_cmds/ifconfig.tproj/ifbond.c284
-rw-r--r--network_cmds/ifconfig.tproj/ifbridge.c952
-rw-r--r--network_cmds/ifconfig.tproj/ifclone.c170
-rw-r--r--network_cmds/ifconfig.tproj/ifconfig.81109
-rw-r--r--network_cmds/ifconfig.tproj/ifconfig.c2692
-rw-r--r--network_cmds/ifconfig.tproj/ifconfig.h186
-rw-r--r--network_cmds/ifconfig.tproj/iffake.c138
-rw-r--r--network_cmds/ifconfig.tproj/ifmedia.c872
-rw-r--r--network_cmds/ifconfig.tproj/ifvlan.c207
-rw-r--r--network_cmds/ifconfig.tproj/nexus.c98
-rw-r--r--network_cmds/ip6addrctl.tproj/ip6addrctl.8126
-rw-r--r--network_cmds/ip6addrctl.tproj/ip6addrctl.c467
-rw-r--r--network_cmds/ip6addrctl.tproj/ip6addrctl.conf12
-rw-r--r--network_cmds/kdumpd.tproj/com.apple.kdumpd.plist36
-rw-r--r--network_cmds/kdumpd.tproj/kdump.h114
-rwxr-xr-xnetwork_cmds/kdumpd.tproj/kdumpd.883
-rw-r--r--network_cmds/kdumpd.tproj/kdumpd.c726
-rw-r--r--network_cmds/kdumpd.tproj/kdumpsubs.c273
-rw-r--r--network_cmds/kdumpd.tproj/kdumpsubs.h72
-rw-r--r--network_cmds/mnc.tproj/LICENCE37
-rw-r--r--network_cmds/mnc.tproj/README63
-rw-r--r--network_cmds/mnc.tproj/mnc.1101
-rw-r--r--network_cmds/mnc.tproj/mnc.h92
-rw-r--r--network_cmds/mnc.tproj/mnc_error.c95
-rw-r--r--network_cmds/mnc.tproj/mnc_main.c131
-rw-r--r--network_cmds/mnc.tproj/mnc_multicast.c404
-rw-r--r--network_cmds/mnc.tproj/mnc_opts.c182
-rw-r--r--network_cmds/mptcp_client/conn_lib.c233
-rw-r--r--network_cmds/mptcp_client/conn_lib.h53
-rw-r--r--network_cmds/mptcp_client/mptcp_client.121
-rw-r--r--network_cmds/mptcp_client/mptcp_client.c701
-rw-r--r--network_cmds/mtest.tproj/COPYING27
-rw-r--r--network_cmds/mtest.tproj/mtest.8175
-rw-r--r--network_cmds/mtest.tproj/mtest.c825
-rw-r--r--network_cmds/ndp.tproj/gnuc.h2
-rw-r--r--network_cmds/ndp.tproj/ndp.8236
-rw-r--r--network_cmds/ndp.tproj/ndp.c1696
-rw-r--r--network_cmds/netstat.tproj/DERIVED_FILES1
-rw-r--r--network_cmds/netstat.tproj/data.c28
-rw-r--r--network_cmds/netstat.tproj/if.c2259
-rw-r--r--network_cmds/netstat.tproj/inet.c1361
-rw-r--r--network_cmds/netstat.tproj/inet6.c1333
-rw-r--r--network_cmds/netstat.tproj/ipsec.c376
-rw-r--r--network_cmds/netstat.tproj/main.c638
-rw-r--r--network_cmds/netstat.tproj/mbuf.c476
-rw-r--r--network_cmds/netstat.tproj/mcast.c887
-rw-r--r--network_cmds/netstat.tproj/misc.c122
-rw-r--r--network_cmds/netstat.tproj/mptcp.c170
-rw-r--r--network_cmds/netstat.tproj/netstat.1445
-rw-r--r--network_cmds/netstat.tproj/netstat.h170
-rw-r--r--network_cmds/netstat.tproj/route.c795
-rw-r--r--network_cmds/netstat.tproj/systm.c503
-rw-r--r--network_cmds/netstat.tproj/tp_astring.c74
-rw-r--r--network_cmds/netstat.tproj/unix.c231
-rw-r--r--network_cmds/netstat.tproj/vsock.c187
-rw-r--r--network_cmds/network-client-server-entitlements.plist10
-rw-r--r--network_cmds/network_cmds.plist26
-rwxr-xr-xnetwork_cmds/network_cmds.xcodeproj/project.pbxproj5098
-rw-r--r--network_cmds/ping.tproj/ping.8616
-rw-r--r--network_cmds/ping.tproj/ping.c2134
-rw-r--r--network_cmds/ping6.tproj/md5.c308
-rw-r--r--network_cmds/ping6.tproj/md5.h75
-rw-r--r--network_cmds/ping6.tproj/ping6.8625
-rw-r--r--network_cmds/ping6.tproj/ping6.c3340
-rw-r--r--network_cmds/pktapctl/pktapctl.841
-rw-r--r--network_cmds/pktapctl/pktapctl.c189
-rw-r--r--network_cmds/pktmnglr/packet_mangler.c329
-rw-r--r--network_cmds/rarpd.tproj/rarpd.892
-rw-r--r--network_cmds/rarpd.tproj/rarpd.c830
-rwxr-xr-xnetwork_cmds/route.tproj/gen_header.pl15
-rw-r--r--network_cmds/route.tproj/keywords49
-rw-r--r--network_cmds/route.tproj/keywords.h119
-rw-r--r--network_cmds/route.tproj/route.8405
-rw-r--r--network_cmds/route.tproj/route.c1571
-rw-r--r--network_cmds/rtadvd.tproj/advcap.c483
-rw-r--r--network_cmds/rtadvd.tproj/advcap.h45
-rw-r--r--network_cmds/rtadvd.tproj/config.c1313
-rw-r--r--network_cmds/rtadvd.tproj/config.h46
-rw-r--r--network_cmds/rtadvd.tproj/dump.c283
-rw-r--r--network_cmds/rtadvd.tproj/dump.h32
-rw-r--r--network_cmds/rtadvd.tproj/if.c604
-rw-r--r--network_cmds/rtadvd.tproj/if.h64
-rw-r--r--network_cmds/rtadvd.tproj/pathnames.h4
-rw-r--r--network_cmds/rtadvd.tproj/rrenum.c484
-rw-r--r--network_cmds/rtadvd.tproj/rrenum.h33
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.8207
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.c1650
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.conf20
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.conf.5509
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd.h205
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd_logging.c45
-rw-r--r--network_cmds/rtadvd.tproj/rtadvd_logging.h24
-rw-r--r--network_cmds/rtadvd.tproj/timer.c205
-rw-r--r--network_cmds/rtadvd.tproj/timer.h64
-rw-r--r--network_cmds/rtsol.tproj/dump.c172
-rw-r--r--network_cmds/rtsol.tproj/if.c501
-rw-r--r--network_cmds/rtsol.tproj/probe.c221
-rw-r--r--network_cmds/rtsol.tproj/rtsock.c179
-rw-r--r--network_cmds/rtsol.tproj/rtsol.8224
-rw-r--r--network_cmds/rtsol.tproj/rtsol.c343
-rw-r--r--network_cmds/rtsol.tproj/rtsold.c791
-rw-r--r--network_cmds/rtsol.tproj/rtsold.h96
-rw-r--r--network_cmds/spray.tproj/spray.874
-rw-r--r--network_cmds/spray.tproj/spray.c247
-rw-r--r--network_cmds/spray.tproj/spray.x24
-rw-r--r--network_cmds/traceroute.tproj/README126
-rw-r--r--network_cmds/traceroute.tproj/as.c242
-rw-r--r--network_cmds/traceroute.tproj/as.h42
-rw-r--r--network_cmds/traceroute.tproj/findsaddr-socket.c246
-rw-r--r--network_cmds/traceroute.tproj/findsaddr.h23
-rw-r--r--network_cmds/traceroute.tproj/gnuc.h43
-rw-r--r--network_cmds/traceroute.tproj/ifaddrlist.c202
-rw-r--r--network_cmds/traceroute.tproj/ifaddrlist.h57
-rw-r--r--network_cmds/traceroute.tproj/mean.awk50
-rw-r--r--network_cmds/traceroute.tproj/median.awk67
-rw-r--r--network_cmds/traceroute.tproj/traceroute.8439
-rw-r--r--network_cmds/traceroute.tproj/traceroute.c1822
-rw-r--r--network_cmds/traceroute.tproj/traceroute.h26
-rw-r--r--network_cmds/traceroute.tproj/version.c1
-rw-r--r--network_cmds/traceroute6.tproj/traceroute6.8178
-rw-r--r--network_cmds/traceroute6.tproj/traceroute6.c1423
-rw-r--r--patch_cmds/diffstat/CHANGES373
-rw-r--r--patch_cmds/diffstat/aclocal.m41306
-rw-r--r--patch_cmds/diffstat/config.guess1508
-rw-r--r--patch_cmds/diffstat/config.h38
-rw-r--r--patch_cmds/diffstat/config.sub1739
-rw-r--r--patch_cmds/diffstat/config_h.in8
-rw-r--r--patch_cmds/diffstat/configure7291
-rw-r--r--patch_cmds/diffstat/configure.in54
-rw-r--r--patch_cmds/diffstat/diffstat.1235
-rw-r--r--patch_cmds/diffstat/diffstat.c2491
-rw-r--r--patch_cmds/diffstat/install-sh294
-rw-r--r--patch_cmds/diffstat/makefile.in144
-rw-r--r--patch_cmds/diffstat/makefile.wnt35
-rw-r--r--patch_cmds/diffstat/package/debian/changelog25
-rw-r--r--patch_cmds/diffstat/package/debian/compat1
-rw-r--r--patch_cmds/diffstat/package/debian/control15
-rw-r--r--patch_cmds/diffstat/package/debian/copyright109
-rw-r--r--patch_cmds/diffstat/package/debian/docs1
-rw-r--r--patch_cmds/diffstat/package/debian/rules92
-rw-r--r--patch_cmds/diffstat/package/debian/source/format1
-rw-r--r--patch_cmds/diffstat/package/debian/watch4
-rw-r--r--patch_cmds/diffstat/package/diffstat.spec54
-rw-r--r--patch_cmds/diffstat/porting/getopt.c79
-rw-r--r--patch_cmds/diffstat/porting/getopt.h4
-rw-r--r--patch_cmds/diffstat/porting/system.h85
-rw-r--r--patch_cmds/diffstat/porting/wildcard.c109
-rw-r--r--patch_cmds/diffstat/testing/case01.pat417
-rw-r--r--patch_cmds/diffstat/testing/case01.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01R.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01Rp0.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01b.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01f0.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01k.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01p1.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01p9.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01r1.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01r2.ref28
-rw-r--r--patch_cmds/diffstat/testing/case01u.ref28
-rw-r--r--patch_cmds/diffstat/testing/case02.pat486
-rw-r--r--patch_cmds/diffstat/testing/case02.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02R.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02Rp0.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02b.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02f0.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02k.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02p1.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02p9.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02r1.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02r2.ref4
-rw-r--r--patch_cmds/diffstat/testing/case02u.ref4
-rw-r--r--patch_cmds/diffstat/testing/case03.pat35
-rw-r--r--patch_cmds/diffstat/testing/case03.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03R.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03Rp0.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03b.ref4
-rw-r--r--patch_cmds/diffstat/testing/case03f0.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03k.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03p1.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03p9.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03r1.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03r2.ref6
-rw-r--r--patch_cmds/diffstat/testing/case03u.ref6
-rw-r--r--patch_cmds/diffstat/testing/case04.pat352
-rw-r--r--patch_cmds/diffstat/testing/case04.ref41
-rw-r--r--patch_cmds/diffstat/testing/case04R.ref41
-rw-r--r--patch_cmds/diffstat/testing/case04Rp0.ref41
-rw-r--r--patch_cmds/diffstat/testing/case04b.ref39
-rw-r--r--patch_cmds/diffstat/testing/case04f0.ref41
-rw-r--r--patch_cmds/diffstat/testing/case04k.ref81
-rw-r--r--patch_cmds/diffstat/testing/case04p1.ref41
-rw-r--r--patch_cmds/diffstat/testing/case04p9.ref41
-rw-r--r--patch_cmds/diffstat/testing/case04r1.ref41
-rw-r--r--patch_cmds/diffstat/testing/case04r2.ref41
-rw-r--r--patch_cmds/diffstat/testing/case04u.ref41
-rw-r--r--patch_cmds/diffstat/testing/case05.pat17
-rw-r--r--patch_cmds/diffstat/testing/case05.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case05u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case06.pat323
-rw-r--r--patch_cmds/diffstat/testing/case06.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06R.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06Rp0.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06b.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06f0.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06k.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06p1.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06p9.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06r1.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06r2.ref6
-rw-r--r--patch_cmds/diffstat/testing/case06u.ref6
-rw-r--r--patch_cmds/diffstat/testing/case07.pat107
-rw-r--r--patch_cmds/diffstat/testing/case07.ref3
-rw-r--r--patch_cmds/diffstat/testing/case07R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case07Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case07b.ref3
-rw-r--r--patch_cmds/diffstat/testing/case07f0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case07k.ref3
-rw-r--r--patch_cmds/diffstat/testing/case07p1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case07p9.ref3
-rw-r--r--patch_cmds/diffstat/testing/case07r1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case07r2.ref3
-rw-r--r--patch_cmds/diffstat/testing/case07u.ref3
-rw-r--r--patch_cmds/diffstat/testing/case08.pat343
-rw-r--r--patch_cmds/diffstat/testing/case08.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08R.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08Rp0.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08b.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08f0.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08k.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08p1.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08p9.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08r1.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08r2.ref9
-rw-r--r--patch_cmds/diffstat/testing/case08u.ref9
-rw-r--r--patch_cmds/diffstat/testing/case09.pat13
-rw-r--r--patch_cmds/diffstat/testing/case09.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09R.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09Rp0.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09b.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09f0.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09k.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09p1.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09p9.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09r1.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09r2.ref1
-rw-r--r--patch_cmds/diffstat/testing/case09u.ref1
-rw-r--r--patch_cmds/diffstat/testing/case10.pat67
-rw-r--r--patch_cmds/diffstat/testing/case10.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10R.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10Rp0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10b.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10f0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10k.ref4
-rw-r--r--patch_cmds/diffstat/testing/case10p1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10p9.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10r1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10r2.ref3
-rw-r--r--patch_cmds/diffstat/testing/case10u.ref3
-rw-r--r--patch_cmds/diffstat/testing/case11.pat12
-rw-r--r--patch_cmds/diffstat/testing/case11.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case11u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case12.pat163
-rw-r--r--patch_cmds/diffstat/testing/case12.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12R.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12Rp0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12b.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12f0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12k.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12p1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12p9.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12r1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12r2.ref3
-rw-r--r--patch_cmds/diffstat/testing/case12u.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13.pat303
-rw-r--r--patch_cmds/diffstat/testing/case13.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13R.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13Rp0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13b.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13f0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13k.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13p1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13p9.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13r1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13r2.ref3
-rw-r--r--patch_cmds/diffstat/testing/case13u.ref3
-rw-r--r--patch_cmds/diffstat/testing/case14.pat12
-rw-r--r--patch_cmds/diffstat/testing/case14.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case14u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case15.pat443
-rw-r--r--patch_cmds/diffstat/testing/case15.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15R.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15Rp0.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15b.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15f0.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15k.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15p1.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15p9.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15r1.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15r2.ref13
-rw-r--r--patch_cmds/diffstat/testing/case15u.ref13
-rw-r--r--patch_cmds/diffstat/testing/case16.pat2036
-rw-r--r--patch_cmds/diffstat/testing/case16.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16R.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16Rp0.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16b.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16f0.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16k.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16p1.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16p9.ref25
-rw-r--r--patch_cmds/diffstat/testing/case16r1.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16r2.ref30
-rw-r--r--patch_cmds/diffstat/testing/case16u.ref30
-rw-r--r--patch_cmds/diffstat/testing/case17.pat115
-rw-r--r--patch_cmds/diffstat/testing/case17.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17R.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17Rp0.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17b.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17f0.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17k.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17p1.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17p9.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17r1.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17r2.ref4
-rw-r--r--patch_cmds/diffstat/testing/case17u.ref4
-rw-r--r--patch_cmds/diffstat/testing/case18.pat7
-rw-r--r--patch_cmds/diffstat/testing/case18.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case18u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19.pat14
-rw-r--r--patch_cmds/diffstat/testing/case19.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case19u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case20.pat111
-rw-r--r--patch_cmds/diffstat/testing/case20.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20R.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20Rp0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20b.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20f0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20k.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20p1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20p9.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20r1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20r2.ref3
-rw-r--r--patch_cmds/diffstat/testing/case20u.ref3
-rw-r--r--patch_cmds/diffstat/testing/case21.pat74
-rw-r--r--patch_cmds/diffstat/testing/case21.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case21u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case22.pat651
-rw-r--r--patch_cmds/diffstat/testing/case22.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22R.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22Rp0.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22b.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22f0.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22k.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22p1.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22p9.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22r1.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22r2.ref37
-rw-r--r--patch_cmds/diffstat/testing/case22u.ref37
-rw-r--r--patch_cmds/diffstat/testing/case23.pat227
-rw-r--r--patch_cmds/diffstat/testing/case23.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23R.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23Rp0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23b.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23f0.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23k.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23p1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23p9.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23r1.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23r2.ref3
-rw-r--r--patch_cmds/diffstat/testing/case23u.ref3
-rw-r--r--patch_cmds/diffstat/testing/case24.pat217
-rw-r--r--patch_cmds/diffstat/testing/case24.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24R.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24Rp0.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24b.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24f0.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24k.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24p1.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24p9.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24r1.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24r2.ref6
-rw-r--r--patch_cmds/diffstat/testing/case24u.ref6
-rw-r--r--patch_cmds/diffstat/testing/case25.pat471
-rw-r--r--patch_cmds/diffstat/testing/case25.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25R.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25Rp0.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25b.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25f0.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25k.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25p1.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25p9.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25r1.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25r2.ref7
-rw-r--r--patch_cmds/diffstat/testing/case25u.ref7
-rw-r--r--patch_cmds/diffstat/testing/case26.pat1901
-rw-r--r--patch_cmds/diffstat/testing/case26.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26R.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26Rp0.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26b.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26f0.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26k.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26p1.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26p9.ref27
-rw-r--r--patch_cmds/diffstat/testing/case26r1.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26r2.ref35
-rw-r--r--patch_cmds/diffstat/testing/case26u.ref35
-rw-r--r--patch_cmds/diffstat/testing/case27.pat409
-rw-r--r--patch_cmds/diffstat/testing/case27.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27R.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27Rp0.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27b.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27f0.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27k.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27p1.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27p9.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27r1.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27r2.ref8
-rw-r--r--patch_cmds/diffstat/testing/case27u.ref8
-rw-r--r--patch_cmds/diffstat/testing/case28.pat326
-rw-r--r--patch_cmds/diffstat/testing/case28.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case28u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29.pat193
-rw-r--r--patch_cmds/diffstat/testing/case29.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case29u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31.pat22
-rw-r--r--patch_cmds/diffstat/testing/case31.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31l.pat8
-rw-r--r--patch_cmds/diffstat/testing/case31l.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lR.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lRp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lb.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lf0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lk.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lp1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lp9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lr1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lr2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31lu.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31u.pat51
-rw-r--r--patch_cmds/diffstat/testing/case31u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31uR.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31uRp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31ub.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31uf0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31uk.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31up1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31up9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31ur1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31ur2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case31uu.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32.pat13
-rw-r--r--patch_cmds/diffstat/testing/case32.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case32u.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33.pat13
-rw-r--r--patch_cmds/diffstat/testing/case33.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33R.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33Rp0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33b.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33f0.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33k.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33p1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33p9.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33r1.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33r2.ref2
-rw-r--r--patch_cmds/diffstat/testing/case33u.ref2
-rw-r--r--patch_cmds/diffstat/testing/run_atac.sh6
-rw-r--r--patch_cmds/diffstat/testing/run_test.sh51
-rw-r--r--patch_cmds/patch/Makefile6
-rw-r--r--patch_cmds/patch/backupfile.c235
-rw-r--r--patch_cmds/patch/backupfile.h38
-rw-r--r--patch_cmds/patch/common.h117
-rw-r--r--patch_cmds/patch/inp.c471
-rw-r--r--patch_cmds/patch/inp.h31
-rw-r--r--patch_cmds/patch/mkpath.c74
-rw-r--r--patch_cmds/patch/patch.1698
-rw-r--r--patch_cmds/patch/patch.c1058
-rw-r--r--patch_cmds/patch/pathnames.h11
-rw-r--r--patch_cmds/patch/pch.c1544
-rw-r--r--patch_cmds/patch/pch.h56
-rw-r--r--patch_cmds/patch/util.c420
-rw-r--r--patch_cmds/patch/util.h50
-rw-r--r--patch_cmds/patch_cmds.plist54
-rw-r--r--patch_cmds/patch_cmds.txt50
-rw-r--r--patch_cmds/patch_cmds.xcodeproj/project.pbxproj398
-rw-r--r--remote_cmds/APPLE_LICENSE370
-rw-r--r--remote_cmds/Makefile12
-rw-r--r--remote_cmds/logger.tproj/Makefile11
-rw-r--r--remote_cmds/logger.tproj/logger.1102
-rw-r--r--remote_cmds/logger.tproj/logger.c329
-rw-r--r--remote_cmds/talk.tproj/Makefile14
-rw-r--r--remote_cmds/talk.tproj/ctl.c128
-rw-r--r--remote_cmds/talk.tproj/ctl_transact.c125
-rw-r--r--remote_cmds/talk.tproj/display.c198
-rw-r--r--remote_cmds/talk.tproj/get_addrs.c71
-rw-r--r--remote_cmds/talk.tproj/get_iface.c103
-rw-r--r--remote_cmds/talk.tproj/get_names.c126
-rw-r--r--remote_cmds/talk.tproj/init_disp.c245
-rw-r--r--remote_cmds/talk.tproj/invite.c202
-rw-r--r--remote_cmds/talk.tproj/io.c188
-rw-r--r--remote_cmds/talk.tproj/look_up.c127
-rw-r--r--remote_cmds/talk.tproj/msgs.c87
-rw-r--r--remote_cmds/talk.tproj/talk.1172
-rw-r--r--remote_cmds/talk.tproj/talk.c92
-rw-r--r--remote_cmds/talk.tproj/talk.h97
-rw-r--r--remote_cmds/talk.tproj/talk_ctl.h43
-rw-r--r--remote_cmds/talkd.tproj/Makefile14
-rw-r--r--remote_cmds/talkd.tproj/announce.c179
-rw-r--r--remote_cmds/talkd.tproj/extern.h40
-rw-r--r--remote_cmds/talkd.tproj/ntalk.plist29
-rw-r--r--remote_cmds/talkd.tproj/ntalkd.898
-rw-r--r--remote_cmds/talkd.tproj/print.c96
-rw-r--r--remote_cmds/talkd.tproj/process.c279
-rw-r--r--remote_cmds/talkd.tproj/table.c241
-rw-r--r--remote_cmds/talkd.tproj/talkd.c145
-rw-r--r--remote_cmds/telnet.tproj/Makefile18
-rw-r--r--remote_cmds/telnet.tproj/authenc.c109
-rw-r--r--remote_cmds/telnet.tproj/commands.c3063
-rw-r--r--remote_cmds/telnet.tproj/defines.h56
-rw-r--r--remote_cmds/telnet.tproj/externs.h495
-rw-r--r--remote_cmds/telnet.tproj/fdset.h49
-rw-r--r--remote_cmds/telnet.tproj/general.h45
-rw-r--r--remote_cmds/telnet.tproj/krb4-proto.h230
-rw-r--r--remote_cmds/telnet.tproj/main.c379
-rw-r--r--remote_cmds/telnet.tproj/misc-proto.h80
-rw-r--r--remote_cmds/telnet.tproj/misc.h42
-rw-r--r--remote_cmds/telnet.tproj/network.c182
-rw-r--r--remote_cmds/telnet.tproj/ring.c322
-rw-r--r--remote_cmds/telnet.tproj/ring.h107
-rw-r--r--remote_cmds/telnet.tproj/sys_bsd.c1145
-rw-r--r--remote_cmds/telnet.tproj/telnet.11417
-rw-r--r--remote_cmds/telnet.tproj/telnet.c2418
-rw-r--r--remote_cmds/telnet.tproj/terminal.c242
-rw-r--r--remote_cmds/telnet.tproj/tn3270.c435
-rw-r--r--remote_cmds/telnet.tproj/types.h52
-rw-r--r--remote_cmds/telnet.tproj/utilities.c912
-rw-r--r--remote_cmds/telnetd.tproj/Makefile50
-rw-r--r--remote_cmds/telnetd.tproj/authenc.c87
-rw-r--r--remote_cmds/telnetd.tproj/defs.h258
-rw-r--r--remote_cmds/telnetd.tproj/entitlements.plist8
-rw-r--r--remote_cmds/telnetd.tproj/ext.h222
-rw-r--r--remote_cmds/telnetd.tproj/global.c52
-rw-r--r--remote_cmds/telnetd.tproj/pathnames.h56
-rw-r--r--remote_cmds/telnetd.tproj/slc.c484
-rw-r--r--remote_cmds/telnetd.tproj/state.c1631
-rw-r--r--remote_cmds/telnetd.tproj/strlcpy.c74
-rw-r--r--remote_cmds/telnetd.tproj/sys_term.c1410
-rw-r--r--remote_cmds/telnetd.tproj/telnet.plist35
-rw-r--r--remote_cmds/telnetd.tproj/telnetd.8607
-rw-r--r--remote_cmds/telnetd.tproj/telnetd.c1330
-rw-r--r--remote_cmds/telnetd.tproj/telnetd.h49
-rw-r--r--remote_cmds/telnetd.tproj/termstat.c632
-rw-r--r--remote_cmds/telnetd.tproj/utility.c1081
-rw-r--r--remote_cmds/telnetd.tproj/vasprintf.c66
-rw-r--r--remote_cmds/tftp.tproj/Makefile12
-rw-r--r--remote_cmds/tftp.tproj/extern.h38
-rw-r--r--remote_cmds/tftp.tproj/main.c920
-rw-r--r--remote_cmds/tftp.tproj/tftp.1243
-rw-r--r--remote_cmds/tftp.tproj/tftp.c742
-rw-r--r--remote_cmds/tftp.tproj/tftpsubs.c287
-rw-r--r--remote_cmds/tftp.tproj/tftpsubs.h54
-rw-r--r--remote_cmds/tftpd.tproj/DERIVED_FILES5
-rw-r--r--remote_cmds/tftpd.tproj/Makefile16
-rw-r--r--remote_cmds/tftpd.tproj/tftp.plist33
-rw-r--r--remote_cmds/tftpd.tproj/tftpd.8233
-rw-r--r--remote_cmds/tftpd.tproj/tftpd.c1238
-rw-r--r--remote_cmds/tftpd.tproj/tftpsubs.c285
-rw-r--r--remote_cmds/tftpd.tproj/tftpsubs.h48
-rw-r--r--remote_cmds/wall.tproj/Makefile16
-rw-r--r--remote_cmds/wall.tproj/ttymsg.c179
-rw-r--r--remote_cmds/wall.tproj/ttymsg.h3
-rw-r--r--remote_cmds/wall.tproj/wall.183
-rw-r--r--remote_cmds/wall.tproj/wall.c361
-rw-r--r--shell_cmds/.upstream_base_commits4
-rw-r--r--shell_cmds/alias/alias.11
-rw-r--r--shell_cmds/alias/builtin.1333
-rw-r--r--shell_cmds/alias/generic.sh4
-rw-r--r--shell_cmds/apply/apply.1140
-rw-r--r--shell_cmds/apply/apply.c267
-rw-r--r--shell_cmds/basename/basename.1114
-rw-r--r--shell_cmds/basename/basename.c119
-rw-r--r--shell_cmds/basename/dirname.11
-rw-r--r--shell_cmds/chroot/chroot.8102
-rw-r--r--shell_cmds/chroot/chroot.c178
-rw-r--r--shell_cmds/date/date.1472
-rw-r--r--shell_cmds/date/date.c365
-rw-r--r--shell_cmds/date/date.plist.part22
-rw-r--r--shell_cmds/date/extern.h35
-rw-r--r--shell_cmds/date/netdate.c181
-rw-r--r--shell_cmds/date/vary.c506
-rw-r--r--shell_cmds/date/vary.h36
-rw-r--r--shell_cmds/dirname/dirname.c84
-rw-r--r--shell_cmds/echo/echo.1101
-rw-r--r--shell_cmds/echo/echo.c182
-rw-r--r--shell_cmds/env/env.1482
-rw-r--r--shell_cmds/env/env.c144
-rw-r--r--shell_cmds/env/envopts.c468
-rw-r--r--shell_cmds/env/envopts.h37
-rw-r--r--shell_cmds/expr/expr.1235
-rw-r--r--shell_cmds/expr/expr.y571
-rw-r--r--shell_cmds/false/false.160
-rw-r--r--shell_cmds/false/false.c2
-rw-r--r--shell_cmds/false/false.sh2
-rw-r--r--shell_cmds/find/extern.h124
-rw-r--r--shell_cmds/find/find.11078
-rw-r--r--shell_cmds/find/find.c323
-rw-r--r--shell_cmds/find/find.h145
-rw-r--r--shell_cmds/find/find.plist.part30
-rw-r--r--shell_cmds/find/function.c1772
-rw-r--r--shell_cmds/find/getdate.y961
-rw-r--r--shell_cmds/find/ls.c124
-rw-r--r--shell_cmds/find/main.c166
-rw-r--r--shell_cmds/find/misc.c106
-rw-r--r--shell_cmds/find/operator.c273
-rw-r--r--shell_cmds/find/option.c201
-rw-r--r--shell_cmds/getopt/getopt.1134
-rw-r--r--shell_cmds/getopt/getopt.c32
-rw-r--r--shell_cmds/hexdump/conv.c178
-rw-r--r--shell_cmds/hexdump/display.c417
-rw-r--r--shell_cmds/hexdump/hexdump.1342
-rw-r--r--shell_cmds/hexdump/hexdump.c86
-rw-r--r--shell_cmds/hexdump/hexdump.h108
-rw-r--r--shell_cmds/hexdump/hexsyntax.c147
-rw-r--r--shell_cmds/hexdump/od.1267
-rw-r--r--shell_cmds/hexdump/odsyntax.c447
-rw-r--r--shell_cmds/hexdump/parse.c523
-rw-r--r--shell_cmds/hostname/hostname.167
-rw-r--r--shell_cmds/hostname/hostname.c105
-rw-r--r--shell_cmds/id/groups.163
-rw-r--r--shell_cmds/id/id.1167
-rw-r--r--shell_cmds/id/id.c529
-rw-r--r--shell_cmds/id/open_directory.c229
-rw-r--r--shell_cmds/id/open_directory.h18
-rw-r--r--shell_cmds/id/whoami.160
-rw-r--r--shell_cmds/jot/jot.1251
-rw-r--r--shell_cmds/jot/jot.c490
-rw-r--r--shell_cmds/kill/kill.1152
-rw-r--r--shell_cmds/kill/kill.c230
-rw-r--r--shell_cmds/kill/kill.plist.part18
-rw-r--r--shell_cmds/killall/killall.1159
-rw-r--r--shell_cmds/killall/killall.c549
-rw-r--r--shell_cmds/lastcomm/lastcomm.1132
-rw-r--r--shell_cmds/lastcomm/lastcomm.c235
-rw-r--r--shell_cmds/lastcomm/pathnames.h36
-rw-r--r--shell_cmds/locate/bigram/locate.bigram.81
-rw-r--r--shell_cmds/locate/bigram/locate.bigram.c110
-rw-r--r--shell_cmds/locate/code/locate.code.823
-rw-r--r--shell_cmds/locate/code/locate.code.c279
-rw-r--r--shell_cmds/locate/locate/com.apple.locate.plist35
-rw-r--r--shell_cmds/locate/locate/concatdb.sh70
-rw-r--r--shell_cmds/locate/locate/fastfind.c338
-rw-r--r--shell_cmds/locate/locate/locate.1276
-rw-r--r--shell_cmds/locate/locate/locate.c389
-rw-r--r--shell_cmds/locate/locate/locate.h76
-rw-r--r--shell_cmds/locate/locate/locate.rc26
-rwxr-xr-xshell_cmds/locate/locate/locate.updatedb.875
-rw-r--r--shell_cmds/locate/locate/mklocatedb.sh92
-rw-r--r--shell_cmds/locate/locate/pathnames.h36
-rw-r--r--shell_cmds/locate/locate/updatedb.sh106
-rw-r--r--shell_cmds/locate/locate/util.c278
-rw-r--r--shell_cmds/logname/logname.178
-rw-r--r--shell_cmds/logname/logname.c92
-rw-r--r--shell_cmds/mktemp/mktemp.1215
-rw-r--r--shell_cmds/mktemp/mktemp.c182
-rw-r--r--shell_cmds/mktemp/mktemp.plist.part21
-rw-r--r--shell_cmds/nice/nice.1120
-rw-r--r--shell_cmds/nice/nice.c122
-rw-r--r--shell_cmds/nohup/nohup.1124
-rw-r--r--shell_cmds/nohup/nohup.c149
-rw-r--r--shell_cmds/path_helper/path_helper.876
-rw-r--r--shell_cmds/path_helper/path_helper.c201
-rw-r--r--shell_cmds/printenv/printenv.184
-rw-r--r--shell_cmds/printenv/printenv.c99
-rw-r--r--shell_cmds/printf/printf.1418
-rw-r--r--shell_cmds/printf/printf.c697
-rw-r--r--shell_cmds/printf/printf.plist.part18
-rw-r--r--shell_cmds/printf/tests/Makefile23
-rw-r--r--shell_cmds/printf/tests/Makefile.depend11
-rw-r--r--shell_cmds/printf/tests/legacy_test.sh6
-rw-r--r--shell_cmds/printf/tests/regress.b.out1
-rw-r--r--shell_cmds/printf/tests/regress.bwidth.out1
-rw-r--r--shell_cmds/printf/tests/regress.d.out1
-rw-r--r--shell_cmds/printf/tests/regress.f.out1
-rw-r--r--shell_cmds/printf/tests/regress.l1.out1
-rw-r--r--shell_cmds/printf/tests/regress.l2.out1
-rw-r--r--shell_cmds/printf/tests/regress.m1.outbin0 -> 7 bytes
-rw-r--r--shell_cmds/printf/tests/regress.m2.out2
-rw-r--r--shell_cmds/printf/tests/regress.m3.out4
-rw-r--r--shell_cmds/printf/tests/regress.m4.out1
-rw-r--r--shell_cmds/printf/tests/regress.m5.out1
-rw-r--r--shell_cmds/printf/tests/regress.missingpos1.out1
-rw-r--r--shell_cmds/printf/tests/regress.s.out1
-rw-r--r--shell_cmds/printf/tests/regress.sh32
-rw-r--r--shell_cmds/printf/tests/regress.zero.out1
-rw-r--r--shell_cmds/pwd/pwd.1103
-rw-r--r--shell_cmds/pwd/pwd.c127
-rw-r--r--shell_cmds/renice/renice.8138
-rw-r--r--shell_cmds/renice/renice.c203
-rw-r--r--shell_cmds/script/script.1217
-rw-r--r--shell_cmds/script/script.c546
-rw-r--r--shell_cmds/script/script.plist.part20
-rw-r--r--shell_cmds/seq/seq.1187
-rw-r--r--shell_cmds/seq/seq.c453
-rw-r--r--shell_cmds/sh/Makefile70
-rw-r--r--shell_cmds/sh/Makefile.depend19
-rw-r--r--shell_cmds/sh/TOUR301
-rw-r--r--shell_cmds/sh/alias.c256
-rw-r--r--shell_cmds/sh/alias.h45
-rw-r--r--shell_cmds/sh/arith.h37
-rw-r--r--shell_cmds/sh/arith_yacc.c381
-rw-r--r--shell_cmds/sh/arith_yacc.h93
-rw-r--r--shell_cmds/sh/arith_yylex.c248
-rw-r--r--shell_cmds/sh/bltin/bltin.h81
-rw-r--r--shell_cmds/sh/bltin/echo.c109
-rw-r--r--shell_cmds/sh/builtins.def96
-rw-r--r--shell_cmds/sh/cd.c430
-rw-r--r--shell_cmds/sh/cd.h32
-rw-r--r--shell_cmds/sh/error.c199
-rw-r--r--shell_cmds/sh/error.h95
-rw-r--r--shell_cmds/sh/eval.c1381
-rw-r--r--shell_cmds/sh/eval.h70
-rw-r--r--shell_cmds/sh/exec.c780
-rw-r--r--shell_cmds/sh/exec.h77
-rw-r--r--shell_cmds/sh/expand.c1550
-rw-r--r--shell_cmds/sh/expand.h62
-rw-r--r--shell_cmds/sh/funcs/cmv49
-rw-r--r--shell_cmds/sh/funcs/dirs73
-rw-r--r--shell_cmds/sh/funcs/login38
-rw-r--r--shell_cmds/sh/funcs/newgrp37
-rw-r--r--shell_cmds/sh/funcs/popd73
-rw-r--r--shell_cmds/sh/funcs/pushd73
-rw-r--r--shell_cmds/sh/funcs/suspend39
-rw-r--r--shell_cmds/sh/histedit.c502
-rw-r--r--shell_cmds/sh/input.c536
-rw-r--r--shell_cmds/sh/input.h65
-rw-r--r--shell_cmds/sh/jobs.c1552
-rw-r--r--shell_cmds/sh/jobs.h67
-rw-r--r--shell_cmds/sh/mail.c117
-rw-r--r--shell_cmds/sh/mail.h38
-rw-r--r--shell_cmds/sh/main.c351
-rw-r--r--shell_cmds/sh/main.h42
-rw-r--r--shell_cmds/sh/memalloc.c344
-rw-r--r--shell_cmds/sh/memalloc.h88
-rw-r--r--shell_cmds/sh/miscbltin.c534
-rwxr-xr-xshell_cmds/sh/mkbuiltins137
-rw-r--r--shell_cmds/sh/mknodes.c467
-rw-r--r--shell_cmds/sh/mksyntax.c331
-rw-r--r--shell_cmds/sh/mktokens93
-rw-r--r--shell_cmds/sh/myhistedit.h44
-rw-r--r--shell_cmds/sh/mystring.c100
-rw-r--r--shell_cmds/sh/mystring.h43
-rw-r--r--shell_cmds/sh/nodes.c.pat193
-rw-r--r--shell_cmds/sh/nodetypes145
-rw-r--r--shell_cmds/sh/options.c594
-rw-r--r--shell_cmds/sh/options.h115
-rw-r--r--shell_cmds/sh/output.c370
-rw-r--r--shell_cmds/sh/output.h85
-rw-r--r--shell_cmds/sh/parser.c2120
-rw-r--r--shell_cmds/sh/parser.h87
-rw-r--r--shell_cmds/sh/redir.c365
-rw-r--r--shell_cmds/sh/redir.h47
-rw-r--r--shell_cmds/sh/sh.12879
-rw-r--r--shell_cmds/sh/sh.plist.part23
-rw-r--r--shell_cmds/sh/shell.h79
-rw-r--r--shell_cmds/sh/show.c410
-rw-r--r--shell_cmds/sh/show.h42
-rw-r--r--shell_cmds/sh/tests/Makefile14
-rw-r--r--shell_cmds/sh/tests/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/builtins/Makefile185
-rw-r--r--shell_cmds/sh/tests/builtins/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/builtins/alias.09
-rw-r--r--shell_cmds/sh/tests/builtins/alias.0.stdout4
-rw-r--r--shell_cmds/sh/tests/builtins/alias.13
-rw-r--r--shell_cmds/sh/tests/builtins/alias.1.stderr1
-rw-r--r--shell_cmds/sh/tests/builtins/alias3.012
-rw-r--r--shell_cmds/sh/tests/builtins/alias3.0.stdout4
-rw-r--r--shell_cmds/sh/tests/builtins/alias4.04
-rw-r--r--shell_cmds/sh/tests/builtins/break1.016
-rw-r--r--shell_cmds/sh/tests/builtins/break2.012
-rw-r--r--shell_cmds/sh/tests/builtins/break2.0.stdout1
-rw-r--r--shell_cmds/sh/tests/builtins/break3.015
-rw-r--r--shell_cmds/sh/tests/builtins/break4.47
-rw-r--r--shell_cmds/sh/tests/builtins/break5.412
-rw-r--r--shell_cmds/sh/tests/builtins/break6.08
-rw-r--r--shell_cmds/sh/tests/builtins/builtin1.031
-rw-r--r--shell_cmds/sh/tests/builtins/case1.013
-rw-r--r--shell_cmds/sh/tests/builtins/case10.016
-rw-r--r--shell_cmds/sh/tests/builtins/case11.06
-rw-r--r--shell_cmds/sh/tests/builtins/case12.06
-rw-r--r--shell_cmds/sh/tests/builtins/case13.012
-rw-r--r--shell_cmds/sh/tests/builtins/case14.05
-rw-r--r--shell_cmds/sh/tests/builtins/case15.05
-rw-r--r--shell_cmds/sh/tests/builtins/case16.07
-rw-r--r--shell_cmds/sh/tests/builtins/case17.03
-rw-r--r--shell_cmds/sh/tests/builtins/case18.07
-rw-r--r--shell_cmds/sh/tests/builtins/case19.07
-rw-r--r--shell_cmds/sh/tests/builtins/case2.0106
-rw-r--r--shell_cmds/sh/tests/builtins/case20.09
-rw-r--r--shell_cmds/sh/tests/builtins/case21.010
-rw-r--r--shell_cmds/sh/tests/builtins/case22.010
-rw-r--r--shell_cmds/sh/tests/builtins/case3.095
-rw-r--r--shell_cmds/sh/tests/builtins/case4.06
-rw-r--r--shell_cmds/sh/tests/builtins/case5.057
-rw-r--r--shell_cmds/sh/tests/builtins/case6.052
-rw-r--r--shell_cmds/sh/tests/builtins/case7.024
-rw-r--r--shell_cmds/sh/tests/builtins/case8.032
-rw-r--r--shell_cmds/sh/tests/builtins/case9.039
-rw-r--r--shell_cmds/sh/tests/builtins/cd1.030
-rw-r--r--shell_cmds/sh/tests/builtins/cd10.06
-rw-r--r--shell_cmds/sh/tests/builtins/cd2.016
-rw-r--r--shell_cmds/sh/tests/builtins/cd3.021
-rw-r--r--shell_cmds/sh/tests/builtins/cd4.038
-rw-r--r--shell_cmds/sh/tests/builtins/cd5.023
-rw-r--r--shell_cmds/sh/tests/builtins/cd6.010
-rw-r--r--shell_cmds/sh/tests/builtins/cd7.015
-rw-r--r--shell_cmds/sh/tests/builtins/cd8.026
-rw-r--r--shell_cmds/sh/tests/builtins/cd9.08
-rw-r--r--shell_cmds/sh/tests/builtins/cd9.0.stdout2
-rw-r--r--shell_cmds/sh/tests/builtins/command1.05
-rw-r--r--shell_cmds/sh/tests/builtins/command10.014
-rw-r--r--shell_cmds/sh/tests/builtins/command11.014
-rw-r--r--shell_cmds/sh/tests/builtins/command12.07
-rw-r--r--shell_cmds/sh/tests/builtins/command2.03
-rw-r--r--shell_cmds/sh/tests/builtins/command3.014
-rw-r--r--shell_cmds/sh/tests/builtins/command3.0.stdout7
-rw-r--r--shell_cmds/sh/tests/builtins/command4.02
-rw-r--r--shell_cmds/sh/tests/builtins/command5.015
-rw-r--r--shell_cmds/sh/tests/builtins/command5.0.stdout8
-rw-r--r--shell_cmds/sh/tests/builtins/command6.022
-rw-r--r--shell_cmds/sh/tests/builtins/command6.0.stdout7
-rw-r--r--shell_cmds/sh/tests/builtins/command7.034
-rw-r--r--shell_cmds/sh/tests/builtins/command8.045
-rw-r--r--shell_cmds/sh/tests/builtins/command9.014
-rw-r--r--shell_cmds/sh/tests/builtins/dot1.021
-rw-r--r--shell_cmds/sh/tests/builtins/dot2.021
-rw-r--r--shell_cmds/sh/tests/builtins/dot3.010
-rw-r--r--shell_cmds/sh/tests/builtins/dot4.012
-rw-r--r--shell_cmds/sh/tests/builtins/echo1.06
-rw-r--r--shell_cmds/sh/tests/builtins/echo2.07
-rw-r--r--shell_cmds/sh/tests/builtins/echo3.05
-rw-r--r--shell_cmds/sh/tests/builtins/eval1.09
-rw-r--r--shell_cmds/sh/tests/builtins/eval2.07
-rw-r--r--shell_cmds/sh/tests/builtins/eval3.09
-rw-r--r--shell_cmds/sh/tests/builtins/eval4.05
-rw-r--r--shell_cmds/sh/tests/builtins/eval5.04
-rw-r--r--shell_cmds/sh/tests/builtins/eval6.05
-rw-r--r--shell_cmds/sh/tests/builtins/eval7.09
-rw-r--r--shell_cmds/sh/tests/builtins/eval8.77
-rw-r--r--shell_cmds/sh/tests/builtins/exec1.025
-rw-r--r--shell_cmds/sh/tests/builtins/exec2.025
-rw-r--r--shell_cmds/sh/tests/builtins/exit1.06
-rw-r--r--shell_cmds/sh/tests/builtins/exit2.87
-rw-r--r--shell_cmds/sh/tests/builtins/exit3.05
-rw-r--r--shell_cmds/sh/tests/builtins/export1.03
-rw-r--r--shell_cmds/sh/tests/builtins/fc1.027
-rw-r--r--shell_cmds/sh/tests/builtins/fc2.034
-rw-r--r--shell_cmds/sh/tests/builtins/for1.04
-rw-r--r--shell_cmds/sh/tests/builtins/for2.09
-rw-r--r--shell_cmds/sh/tests/builtins/for3.08
-rw-r--r--shell_cmds/sh/tests/builtins/getopts1.025
-rw-r--r--shell_cmds/sh/tests/builtins/getopts1.0.stdout8
-rw-r--r--shell_cmds/sh/tests/builtins/getopts10.011
-rw-r--r--shell_cmds/sh/tests/builtins/getopts2.06
-rw-r--r--shell_cmds/sh/tests/builtins/getopts2.0.stdout1
-rw-r--r--shell_cmds/sh/tests/builtins/getopts3.06
-rw-r--r--shell_cmds/sh/tests/builtins/getopts4.010
-rw-r--r--shell_cmds/sh/tests/builtins/getopts5.010
-rw-r--r--shell_cmds/sh/tests/builtins/getopts6.07
-rw-r--r--shell_cmds/sh/tests/builtins/getopts7.06
-rw-r--r--shell_cmds/sh/tests/builtins/getopts8.08
-rw-r--r--shell_cmds/sh/tests/builtins/getopts8.0.stdout5
-rw-r--r--shell_cmds/sh/tests/builtins/getopts9.09
-rw-r--r--shell_cmds/sh/tests/builtins/getopts9.0.stdout3
-rw-r--r--shell_cmds/sh/tests/builtins/hash1.05
-rw-r--r--shell_cmds/sh/tests/builtins/hash1.0.stdout1
-rw-r--r--shell_cmds/sh/tests/builtins/hash2.04
-rw-r--r--shell_cmds/sh/tests/builtins/hash2.0.stdout1
-rw-r--r--shell_cmds/sh/tests/builtins/hash3.03
-rw-r--r--shell_cmds/sh/tests/builtins/hash3.0.stdout2
-rw-r--r--shell_cmds/sh/tests/builtins/hash4.06
-rw-r--r--shell_cmds/sh/tests/builtins/jobid1.07
-rw-r--r--shell_cmds/sh/tests/builtins/jobid2.09
-rw-r--r--shell_cmds/sh/tests/builtins/kill1.08
-rw-r--r--shell_cmds/sh/tests/builtins/kill2.07
-rw-r--r--shell_cmds/sh/tests/builtins/lineno.016
-rw-r--r--shell_cmds/sh/tests/builtins/lineno.0.stdout9
-rw-r--r--shell_cmds/sh/tests/builtins/lineno2.010
-rw-r--r--shell_cmds/sh/tests/builtins/lineno3.06
-rw-r--r--shell_cmds/sh/tests/builtins/lineno3.0.stdout2
-rw-r--r--shell_cmds/sh/tests/builtins/local1.013
-rw-r--r--shell_cmds/sh/tests/builtins/local2.017
-rw-r--r--shell_cmds/sh/tests/builtins/local3.026
-rw-r--r--shell_cmds/sh/tests/builtins/local4.012
-rw-r--r--shell_cmds/sh/tests/builtins/local5.015
-rw-r--r--shell_cmds/sh/tests/builtins/local6.010
-rw-r--r--shell_cmds/sh/tests/builtins/local7.010
-rw-r--r--shell_cmds/sh/tests/builtins/locale1.0134
-rw-r--r--shell_cmds/sh/tests/builtins/locale2.05
-rw-r--r--shell_cmds/sh/tests/builtins/printf1.03
-rw-r--r--shell_cmds/sh/tests/builtins/printf2.03
-rw-r--r--shell_cmds/sh/tests/builtins/printf3.05
-rw-r--r--shell_cmds/sh/tests/builtins/printf4.05
-rw-r--r--shell_cmds/sh/tests/builtins/read1.026
-rw-r--r--shell_cmds/sh/tests/builtins/read1.0.stdout20
-rw-r--r--shell_cmds/sh/tests/builtins/read2.031
-rw-r--r--shell_cmds/sh/tests/builtins/read3.011
-rw-r--r--shell_cmds/sh/tests/builtins/read3.0.stdout9
-rw-r--r--shell_cmds/sh/tests/builtins/read4.010
-rw-r--r--shell_cmds/sh/tests/builtins/read4.0.stdout8
-rw-r--r--shell_cmds/sh/tests/builtins/read5.032
-rw-r--r--shell_cmds/sh/tests/builtins/read6.05
-rw-r--r--shell_cmds/sh/tests/builtins/read7.05
-rw-r--r--shell_cmds/sh/tests/builtins/read8.017
-rw-r--r--shell_cmds/sh/tests/builtins/read9.010
-rw-r--r--shell_cmds/sh/tests/builtins/return1.07
-rw-r--r--shell_cmds/sh/tests/builtins/return2.17
-rw-r--r--shell_cmds/sh/tests/builtins/return3.13
-rw-r--r--shell_cmds/sh/tests/builtins/return4.016
-rw-r--r--shell_cmds/sh/tests/builtins/return5.017
-rw-r--r--shell_cmds/sh/tests/builtins/return6.43
-rw-r--r--shell_cmds/sh/tests/builtins/return7.46
-rw-r--r--shell_cmds/sh/tests/builtins/return8.013
-rw-r--r--shell_cmds/sh/tests/builtins/set1.032
-rw-r--r--shell_cmds/sh/tests/builtins/set2.03
-rw-r--r--shell_cmds/sh/tests/builtins/set3.04
-rw-r--r--shell_cmds/sh/tests/builtins/trap1.022
-rw-r--r--shell_cmds/sh/tests/builtins/trap10.06
-rw-r--r--shell_cmds/sh/tests/builtins/trap11.08
-rw-r--r--shell_cmds/sh/tests/builtins/trap12.010
-rw-r--r--shell_cmds/sh/tests/builtins/trap13.08
-rw-r--r--shell_cmds/sh/tests/builtins/trap14.010
-rw-r--r--shell_cmds/sh/tests/builtins/trap15.05
-rw-r--r--shell_cmds/sh/tests/builtins/trap16.020
-rw-r--r--shell_cmds/sh/tests/builtins/trap17.010
-rw-r--r--shell_cmds/sh/tests/builtins/trap2.052
-rw-r--r--shell_cmds/sh/tests/builtins/trap3.011
-rw-r--r--shell_cmds/sh/tests/builtins/trap4.017
-rw-r--r--shell_cmds/sh/tests/builtins/trap5.019
-rw-r--r--shell_cmds/sh/tests/builtins/trap6.09
-rw-r--r--shell_cmds/sh/tests/builtins/trap7.03
-rw-r--r--shell_cmds/sh/tests/builtins/trap8.07
-rw-r--r--shell_cmds/sh/tests/builtins/trap9.03
-rw-r--r--shell_cmds/sh/tests/builtins/type1.08
-rw-r--r--shell_cmds/sh/tests/builtins/type1.0.stderr4
-rw-r--r--shell_cmds/sh/tests/builtins/type2.026
-rw-r--r--shell_cmds/sh/tests/builtins/type3.03
-rw-r--r--shell_cmds/sh/tests/builtins/unalias.021
-rw-r--r--shell_cmds/sh/tests/builtins/var-assign.055
-rw-r--r--shell_cmds/sh/tests/builtins/var-assign2.055
-rw-r--r--shell_cmds/sh/tests/builtins/wait1.023
-rw-r--r--shell_cmds/sh/tests/builtins/wait10.05
-rw-r--r--shell_cmds/sh/tests/builtins/wait2.015
-rw-r--r--shell_cmds/sh/tests/builtins/wait3.021
-rw-r--r--shell_cmds/sh/tests/builtins/wait4.012
-rw-r--r--shell_cmds/sh/tests/builtins/wait5.012
-rw-r--r--shell_cmds/sh/tests/builtins/wait6.03
-rw-r--r--shell_cmds/sh/tests/builtins/wait7.04
-rw-r--r--shell_cmds/sh/tests/builtins/wait8.07
-rw-r--r--shell_cmds/sh/tests/builtins/wait9.1273
-rw-r--r--shell_cmds/sh/tests/errors/Makefile35
-rw-r--r--shell_cmds/sh/tests/errors/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/errors/assignment-error1.030
-rw-r--r--shell_cmds/sh/tests/errors/assignment-error2.08
-rw-r--r--shell_cmds/sh/tests/errors/backquote-error1.04
-rw-r--r--shell_cmds/sh/tests/errors/backquote-error2.07
-rw-r--r--shell_cmds/sh/tests/errors/bad-binary1.12612
-rw-r--r--shell_cmds/sh/tests/errors/bad-keyword1.04
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp1.07
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp2.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp2.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp3.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp3.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp4.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp4.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp5.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp5.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp6.22
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp6.2.stderr1
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp7.04
-rw-r--r--shell_cmds/sh/tests/errors/bad-parm-exp8.04
-rw-r--r--shell_cmds/sh/tests/errors/option-error.046
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error.053
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error2.24
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error3.054
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error4.07
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error5.05
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error6.012
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error7.07
-rw-r--r--shell_cmds/sh/tests/errors/redirection-error8.05
-rw-r--r--shell_cmds/sh/tests/errors/write-error1.03
-rw-r--r--shell_cmds/sh/tests/execution/Makefile57
-rw-r--r--shell_cmds/sh/tests/execution/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/execution/bg1.03
-rw-r--r--shell_cmds/sh/tests/execution/bg10.04
-rw-r--r--shell_cmds/sh/tests/execution/bg10.0.stdout1
-rw-r--r--shell_cmds/sh/tests/execution/bg2.05
-rw-r--r--shell_cmds/sh/tests/execution/bg3.05
-rw-r--r--shell_cmds/sh/tests/execution/bg4.06
-rw-r--r--shell_cmds/sh/tests/execution/bg5.04
-rw-r--r--shell_cmds/sh/tests/execution/bg6.04
-rw-r--r--shell_cmds/sh/tests/execution/bg6.0.stdout1
-rw-r--r--shell_cmds/sh/tests/execution/bg7.05
-rw-r--r--shell_cmds/sh/tests/execution/bg8.05
-rw-r--r--shell_cmds/sh/tests/execution/bg9.05
-rw-r--r--shell_cmds/sh/tests/execution/fork1.010
-rw-r--r--shell_cmds/sh/tests/execution/fork2.09
-rw-r--r--shell_cmds/sh/tests/execution/fork3.04
-rw-r--r--shell_cmds/sh/tests/execution/func1.04
-rw-r--r--shell_cmds/sh/tests/execution/func2.012
-rw-r--r--shell_cmds/sh/tests/execution/func3.07
-rw-r--r--shell_cmds/sh/tests/execution/hash1.012
-rw-r--r--shell_cmds/sh/tests/execution/int-cmd1.03
-rw-r--r--shell_cmds/sh/tests/execution/killed1.08
-rw-r--r--shell_cmds/sh/tests/execution/killed2.010
-rw-r--r--shell_cmds/sh/tests/execution/not1.04
-rw-r--r--shell_cmds/sh/tests/execution/not2.06
-rw-r--r--shell_cmds/sh/tests/execution/path1.015
-rw-r--r--shell_cmds/sh/tests/execution/redir1.027
-rw-r--r--shell_cmds/sh/tests/execution/redir2.029
-rw-r--r--shell_cmds/sh/tests/execution/redir3.03
-rw-r--r--shell_cmds/sh/tests/execution/redir4.04
-rw-r--r--shell_cmds/sh/tests/execution/redir5.03
-rw-r--r--shell_cmds/sh/tests/execution/redir6.021
-rw-r--r--shell_cmds/sh/tests/execution/redir7.021
-rw-r--r--shell_cmds/sh/tests/execution/set-C1.012
-rw-r--r--shell_cmds/sh/tests/execution/set-n1.07
-rw-r--r--shell_cmds/sh/tests/execution/set-n2.05
-rw-r--r--shell_cmds/sh/tests/execution/set-n3.04
-rw-r--r--shell_cmds/sh/tests/execution/set-n4.03
-rw-r--r--shell_cmds/sh/tests/execution/set-x1.08
-rw-r--r--shell_cmds/sh/tests/execution/set-x2.09
-rw-r--r--shell_cmds/sh/tests/execution/set-x3.09
-rw-r--r--shell_cmds/sh/tests/execution/set-x4.07
-rw-r--r--shell_cmds/sh/tests/execution/shellproc1.011
-rw-r--r--shell_cmds/sh/tests/execution/subshell1.06
-rw-r--r--shell_cmds/sh/tests/execution/subshell1.0.stdout2
-rw-r--r--shell_cmds/sh/tests/execution/subshell2.010
-rw-r--r--shell_cmds/sh/tests/execution/subshell3.04
-rw-r--r--shell_cmds/sh/tests/execution/subshell4.03
-rw-r--r--shell_cmds/sh/tests/execution/unknown1.029
-rw-r--r--shell_cmds/sh/tests/execution/var-assign1.03
-rw-r--r--shell_cmds/sh/tests/expansion/Makefile105
-rw-r--r--shell_cmds/sh/tests/expansion/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/expansion/arith1.030
-rw-r--r--shell_cmds/sh/tests/expansion/arith10.035
-rw-r--r--shell_cmds/sh/tests/expansion/arith11.012
-rw-r--r--shell_cmds/sh/tests/expansion/arith12.04
-rw-r--r--shell_cmds/sh/tests/expansion/arith13.06
-rw-r--r--shell_cmds/sh/tests/expansion/arith14.040
-rw-r--r--shell_cmds/sh/tests/expansion/arith2.077
-rw-r--r--shell_cmds/sh/tests/expansion/arith3.014
-rw-r--r--shell_cmds/sh/tests/expansion/arith4.020
-rw-r--r--shell_cmds/sh/tests/expansion/arith5.017
-rw-r--r--shell_cmds/sh/tests/expansion/arith6.016
-rw-r--r--shell_cmds/sh/tests/expansion/arith7.012
-rw-r--r--shell_cmds/sh/tests/expansion/arith8.04
-rw-r--r--shell_cmds/sh/tests/expansion/arith9.020
-rw-r--r--shell_cmds/sh/tests/expansion/assign1.037
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst1.048
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst10.051
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst11.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst12.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst13.012
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst14.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst15.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst16.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst17.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst18.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst19.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst2.043
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst20.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst21.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst22.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst23.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst24.024
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst25.07
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst26.06
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst3.023
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst4.04
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst5.05
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst6.053
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst7.031
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst8.017
-rw-r--r--shell_cmds/sh/tests/expansion/cmdsubst9.011
-rw-r--r--shell_cmds/sh/tests/expansion/export1.013
-rw-r--r--shell_cmds/sh/tests/expansion/export2.024
-rw-r--r--shell_cmds/sh/tests/expansion/export3.030
-rw-r--r--shell_cmds/sh/tests/expansion/heredoc1.025
-rw-r--r--shell_cmds/sh/tests/expansion/heredoc2.015
-rw-r--r--shell_cmds/sh/tests/expansion/ifs1.035
-rw-r--r--shell_cmds/sh/tests/expansion/ifs2.024
-rw-r--r--shell_cmds/sh/tests/expansion/ifs3.021
-rw-r--r--shell_cmds/sh/tests/expansion/ifs4.039
-rw-r--r--shell_cmds/sh/tests/expansion/ifs5.04
-rw-r--r--shell_cmds/sh/tests/expansion/ifs6.06
-rw-r--r--shell_cmds/sh/tests/expansion/ifs7.05
-rw-r--r--shell_cmds/sh/tests/expansion/length1.012
-rw-r--r--shell_cmds/sh/tests/expansion/length2.04
-rw-r--r--shell_cmds/sh/tests/expansion/length3.010
-rw-r--r--shell_cmds/sh/tests/expansion/length4.011
-rw-r--r--shell_cmds/sh/tests/expansion/length5.027
-rw-r--r--shell_cmds/sh/tests/expansion/length6.08
-rw-r--r--shell_cmds/sh/tests/expansion/length7.014
-rw-r--r--shell_cmds/sh/tests/expansion/length8.014
-rw-r--r--shell_cmds/sh/tests/expansion/local1.028
-rw-r--r--shell_cmds/sh/tests/expansion/local2.034
-rw-r--r--shell_cmds/sh/tests/expansion/pathname1.065
-rw-r--r--shell_cmds/sh/tests/expansion/pathname2.035
-rw-r--r--shell_cmds/sh/tests/expansion/pathname3.029
-rw-r--r--shell_cmds/sh/tests/expansion/pathname4.028
-rw-r--r--shell_cmds/sh/tests/expansion/pathname5.03
-rw-r--r--shell_cmds/sh/tests/expansion/pathname6.029
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus1.076
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus2.04
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus3.044
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus4.038
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus5.031
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus6.034
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus7.026
-rw-r--r--shell_cmds/sh/tests/expansion/plus-minus8.05
-rw-r--r--shell_cmds/sh/tests/expansion/question1.022
-rw-r--r--shell_cmds/sh/tests/expansion/readonly1.07
-rw-r--r--shell_cmds/sh/tests/expansion/redir1.026
-rw-r--r--shell_cmds/sh/tests/expansion/set-u1.029
-rw-r--r--shell_cmds/sh/tests/expansion/set-u2.012
-rw-r--r--shell_cmds/sh/tests/expansion/set-u3.06
-rw-r--r--shell_cmds/sh/tests/expansion/tilde1.056
-rw-r--r--shell_cmds/sh/tests/expansion/tilde2.090
-rw-r--r--shell_cmds/sh/tests/expansion/trim1.085
-rw-r--r--shell_cmds/sh/tests/expansion/trim2.055
-rw-r--r--shell_cmds/sh/tests/expansion/trim3.046
-rw-r--r--shell_cmds/sh/tests/expansion/trim4.015
-rw-r--r--shell_cmds/sh/tests/expansion/trim5.028
-rw-r--r--shell_cmds/sh/tests/expansion/trim6.022
-rw-r--r--shell_cmds/sh/tests/expansion/trim7.016
-rw-r--r--shell_cmds/sh/tests/expansion/trim8.075
-rw-r--r--shell_cmds/sh/tests/expansion/trim9.061
-rwxr-xr-xshell_cmds/sh/tests/functional_test.sh72
-rw-r--r--shell_cmds/sh/tests/invocation/Makefile16
-rw-r--r--shell_cmds/sh/tests/invocation/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/invocation/sh-ac1.07
-rw-r--r--shell_cmds/sh/tests/invocation/sh-c-missing1.03
-rw-r--r--shell_cmds/sh/tests/invocation/sh-c1.04
-rw-r--r--shell_cmds/sh/tests/invocation/sh-ca1.07
-rw-r--r--shell_cmds/sh/tests/invocation/sh-fca1.07
-rw-r--r--shell_cmds/sh/tests/parameters/Makefile29
-rw-r--r--shell_cmds/sh/tests/parameters/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/parameters/env1.011
-rw-r--r--shell_cmds/sh/tests/parameters/exitstatus1.09
-rw-r--r--shell_cmds/sh/tests/parameters/ifs1.010
-rw-r--r--shell_cmds/sh/tests/parameters/mail1.015
-rw-r--r--shell_cmds/sh/tests/parameters/mail2.015
-rw-r--r--shell_cmds/sh/tests/parameters/optind1.03
-rw-r--r--shell_cmds/sh/tests/parameters/optind2.03
-rw-r--r--shell_cmds/sh/tests/parameters/positional1.013
-rw-r--r--shell_cmds/sh/tests/parameters/positional2.065
-rw-r--r--shell_cmds/sh/tests/parameters/positional3.04
-rw-r--r--shell_cmds/sh/tests/parameters/positional4.04
-rw-r--r--shell_cmds/sh/tests/parameters/positional5.014
-rw-r--r--shell_cmds/sh/tests/parameters/positional6.07
-rw-r--r--shell_cmds/sh/tests/parameters/positional7.08
-rw-r--r--shell_cmds/sh/tests/parameters/positional8.031
-rw-r--r--shell_cmds/sh/tests/parameters/positional9.018
-rw-r--r--shell_cmds/sh/tests/parameters/pwd1.011
-rw-r--r--shell_cmds/sh/tests/parameters/pwd2.024
-rw-r--r--shell_cmds/sh/tests/parser/Makefile88
-rw-r--r--shell_cmds/sh/tests/parser/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/parser/alias1.05
-rw-r--r--shell_cmds/sh/tests/parser/alias10.09
-rw-r--r--shell_cmds/sh/tests/parser/alias11.06
-rw-r--r--shell_cmds/sh/tests/parser/alias12.06
-rw-r--r--shell_cmds/sh/tests/parser/alias13.06
-rw-r--r--shell_cmds/sh/tests/parser/alias14.06
-rw-r--r--shell_cmds/sh/tests/parser/alias15.012
-rw-r--r--shell_cmds/sh/tests/parser/alias15.0.stdout4
-rw-r--r--shell_cmds/sh/tests/parser/alias16.07
-rw-r--r--shell_cmds/sh/tests/parser/alias17.07
-rw-r--r--shell_cmds/sh/tests/parser/alias18.08
-rw-r--r--shell_cmds/sh/tests/parser/alias2.06
-rw-r--r--shell_cmds/sh/tests/parser/alias3.06
-rw-r--r--shell_cmds/sh/tests/parser/alias4.05
-rw-r--r--shell_cmds/sh/tests/parser/alias5.05
-rw-r--r--shell_cmds/sh/tests/parser/alias6.06
-rw-r--r--shell_cmds/sh/tests/parser/alias7.04
-rw-r--r--shell_cmds/sh/tests/parser/alias8.04
-rw-r--r--shell_cmds/sh/tests/parser/alias9.06
-rw-r--r--shell_cmds/sh/tests/parser/and-pipe-not.02
-rw-r--r--shell_cmds/sh/tests/parser/case1.014
-rw-r--r--shell_cmds/sh/tests/parser/case2.032
-rw-r--r--shell_cmds/sh/tests/parser/comment1.03
-rw-r--r--shell_cmds/sh/tests/parser/comment2.424
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote1.012
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote10.010
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote11.08
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote12.07
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote13.08
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote2.05
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote3.022
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote4.019
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote5.012
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote6.05
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote7.06
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote8.011
-rw-r--r--shell_cmds/sh/tests/parser/dollar-quote9.08
-rw-r--r--shell_cmds/sh/tests/parser/empty-braces1.07
-rw-r--r--shell_cmds/sh/tests/parser/empty-cmd1.03
-rw-r--r--shell_cmds/sh/tests/parser/for1.029
-rw-r--r--shell_cmds/sh/tests/parser/for2.015
-rw-r--r--shell_cmds/sh/tests/parser/func1.025
-rw-r--r--shell_cmds/sh/tests/parser/func2.06
-rw-r--r--shell_cmds/sh/tests/parser/func3.06
-rw-r--r--shell_cmds/sh/tests/parser/heredoc1.085
-rw-r--r--shell_cmds/sh/tests/parser/heredoc10.049
-rw-r--r--shell_cmds/sh/tests/parser/heredoc11.026
-rw-r--r--shell_cmds/sh/tests/parser/heredoc12.047
-rw-r--r--shell_cmds/sh/tests/parser/heredoc13.021
-rw-r--r--shell_cmds/sh/tests/parser/heredoc2.039
-rw-r--r--shell_cmds/sh/tests/parser/heredoc3.07
-rw-r--r--shell_cmds/sh/tests/parser/heredoc4.044
-rw-r--r--shell_cmds/sh/tests/parser/heredoc5.056
-rw-r--r--shell_cmds/sh/tests/parser/heredoc6.05
-rw-r--r--shell_cmds/sh/tests/parser/heredoc7.019
-rw-r--r--shell_cmds/sh/tests/parser/heredoc8.020
-rw-r--r--shell_cmds/sh/tests/parser/heredoc9.058
-rw-r--r--shell_cmds/sh/tests/parser/line-cont1.016
-rw-r--r--shell_cmds/sh/tests/parser/line-cont10.018
-rw-r--r--shell_cmds/sh/tests/parser/line-cont11.023
-rw-r--r--shell_cmds/sh/tests/parser/line-cont2.04
-rw-r--r--shell_cmds/sh/tests/parser/line-cont3.07
-rw-r--r--shell_cmds/sh/tests/parser/line-cont4.08
-rw-r--r--shell_cmds/sh/tests/parser/line-cont5.014
-rw-r--r--shell_cmds/sh/tests/parser/line-cont6.023
-rw-r--r--shell_cmds/sh/tests/parser/line-cont7.07
-rw-r--r--shell_cmds/sh/tests/parser/line-cont8.06
-rw-r--r--shell_cmds/sh/tests/parser/line-cont9.06
-rw-r--r--shell_cmds/sh/tests/parser/no-space1.018
-rw-r--r--shell_cmds/sh/tests/parser/no-space2.07
-rw-r--r--shell_cmds/sh/tests/parser/nul1.012
-rw-r--r--shell_cmds/sh/tests/parser/only-redir1.03
-rw-r--r--shell_cmds/sh/tests/parser/only-redir2.02
-rw-r--r--shell_cmds/sh/tests/parser/only-redir3.02
-rw-r--r--shell_cmds/sh/tests/parser/only-redir4.02
-rw-r--r--shell_cmds/sh/tests/parser/pipe-not1.03
-rw-r--r--shell_cmds/sh/tests/parser/set-v1.08
-rw-r--r--shell_cmds/sh/tests/parser/set-v1.0.stderr5
-rw-r--r--shell_cmds/sh/tests/parser/var-assign1.019
-rw-r--r--shell_cmds/sh/tests/set-e/Makefile46
-rw-r--r--shell_cmds/sh/tests/set-e/Makefile.depend11
-rw-r--r--shell_cmds/sh/tests/set-e/and1.03
-rw-r--r--shell_cmds/sh/tests/set-e/and2.14
-rw-r--r--shell_cmds/sh/tests/set-e/and3.04
-rw-r--r--shell_cmds/sh/tests/set-e/and4.04
-rw-r--r--shell_cmds/sh/tests/set-e/background1.03
-rw-r--r--shell_cmds/sh/tests/set-e/cmd1.03
-rw-r--r--shell_cmds/sh/tests/set-e/cmd2.14
-rw-r--r--shell_cmds/sh/tests/set-e/elif1.07
-rw-r--r--shell_cmds/sh/tests/set-e/elif2.07
-rw-r--r--shell_cmds/sh/tests/set-e/eval1.03
-rw-r--r--shell_cmds/sh/tests/set-e/eval2.14
-rw-r--r--shell_cmds/sh/tests/set-e/for1.09
-rw-r--r--shell_cmds/sh/tests/set-e/func1.07
-rw-r--r--shell_cmds/sh/tests/set-e/func2.17
-rw-r--r--shell_cmds/sh/tests/set-e/if1.05
-rw-r--r--shell_cmds/sh/tests/set-e/if2.07
-rw-r--r--shell_cmds/sh/tests/set-e/if3.05
-rw-r--r--shell_cmds/sh/tests/set-e/not1.04
-rw-r--r--shell_cmds/sh/tests/set-e/not2.04
-rw-r--r--shell_cmds/sh/tests/set-e/or1.03
-rw-r--r--shell_cmds/sh/tests/set-e/or2.03
-rw-r--r--shell_cmds/sh/tests/set-e/or3.14
-rw-r--r--shell_cmds/sh/tests/set-e/pipe1.14
-rw-r--r--shell_cmds/sh/tests/set-e/pipe2.03
-rw-r--r--shell_cmds/sh/tests/set-e/return1.011
-rw-r--r--shell_cmds/sh/tests/set-e/semi1.14
-rw-r--r--shell_cmds/sh/tests/set-e/semi2.14
-rw-r--r--shell_cmds/sh/tests/set-e/subshell1.03
-rw-r--r--shell_cmds/sh/tests/set-e/subshell2.14
-rw-r--r--shell_cmds/sh/tests/set-e/until1.05
-rw-r--r--shell_cmds/sh/tests/set-e/until2.05
-rw-r--r--shell_cmds/sh/tests/set-e/until3.09
-rw-r--r--shell_cmds/sh/tests/set-e/while1.05
-rw-r--r--shell_cmds/sh/tests/set-e/while2.05
-rw-r--r--shell_cmds/sh/tests/set-e/while3.09
-rw-r--r--shell_cmds/sh/trap.c556
-rw-r--r--shell_cmds/sh/trap.h50
-rw-r--r--shell_cmds/sh/var.c971
-rw-r--r--shell_cmds/sh/var.h132
-rw-r--r--shell_cmds/shell_cmds.xcodeproj/project.pbxproj5903
-rw-r--r--shell_cmds/shell_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--shell_cmds/shlock/shlock.1147
-rw-r--r--shell_cmds/shlock/shlock.c364
-rw-r--r--shell_cmds/sleep/sleep.1124
-rw-r--r--shell_cmds/sleep/sleep.c131
-rw-r--r--shell_cmds/su/su.1213
-rw-r--r--shell_cmds/su/su.c737
-rw-r--r--shell_cmds/su/su.pam7
-rw-r--r--shell_cmds/su/su_entitlements.plist10
-rw-r--r--shell_cmds/systime/systime.176
-rw-r--r--shell_cmds/systime/systime.c365
-rw-r--r--shell_cmds/tee/tee.190
-rw-r--r--shell_cmds/tee/tee.c156
-rw-r--r--shell_cmds/test/[.11
-rw-r--r--shell_cmds/test/test.1390
-rw-r--r--shell_cmds/test/test.c611
-rw-r--r--shell_cmds/test/test.plist.part19
-rw-r--r--shell_cmds/test/tests/Makefile15
-rw-r--r--shell_cmds/test/tests/legacy_test.sh203
-rw-r--r--shell_cmds/tests/regress.m459
-rw-r--r--shell_cmds/tests/shell_cmds.plist53
-rwxr-xr-xshell_cmds/time/tests/test_time.sh60
-rw-r--r--shell_cmds/time/time.1116
-rw-r--r--shell_cmds/time/time.c245
-rw-r--r--shell_cmds/true/true.160
-rw-r--r--shell_cmds/true/true.c2
-rw-r--r--shell_cmds/true/true.sh2
-rw-r--r--shell_cmds/uname/uname.187
-rw-r--r--shell_cmds/uname/uname.c208
-rw-r--r--shell_cmds/users/users.161
-rw-r--r--shell_cmds/users/users.c123
-rw-r--r--shell_cmds/w/extern.h44
-rw-r--r--shell_cmds/w/fmt.c129
-rw-r--r--shell_cmds/w/pr_time.c117
-rw-r--r--shell_cmds/w/proc_compare.c144
-rw-r--r--shell_cmds/w/uptime.152
-rw-r--r--shell_cmds/w/w.1127
-rw-r--r--shell_cmds/w/w.c776
-rw-r--r--shell_cmds/what/what.170
-rw-r--r--shell_cmds/what/what.c97
-rw-r--r--shell_cmds/whereis/whereis.170
-rw-r--r--shell_cmds/whereis/whereis.c128
-rw-r--r--shell_cmds/which/which.185
-rw-r--r--shell_cmds/which/which.c146
-rw-r--r--shell_cmds/who/utmpentry.c348
-rw-r--r--shell_cmds/who/utmpentry.h78
-rw-r--r--shell_cmds/who/who.1130
-rw-r--r--shell_cmds/who/who.c453
-rw-r--r--shell_cmds/xargs/pathnames.h36
-rw-r--r--shell_cmds/xargs/strnsubst.c109
-rw-r--r--shell_cmds/xargs/xargs.1389
-rw-r--r--shell_cmds/xargs/xargs.c840
-rw-r--r--shell_cmds/xcconfigs/base.xcconfig59
-rw-r--r--shell_cmds/xcconfigs/sh.xcconfig33
-rw-r--r--shell_cmds/xcodescripts/builtins-manpages.txt85
-rw-r--r--shell_cmds/xcodescripts/builtins.txt14
-rw-r--r--shell_cmds/xcodescripts/install-files.sh66
-rw-r--r--shell_cmds/yes/yes.156
-rw-r--r--shell_cmds/yes/yes.c63
-rw-r--r--system_cmds/.upstream_base_commits2
-rw-r--r--system_cmds/APPLE_LICENSE370
-rw-r--r--system_cmds/ac.tproj/ac.886
-rw-r--r--system_cmds/ac.tproj/ac.c540
-rw-r--r--system_cmds/accton.tproj/accton.842
-rw-r--r--system_cmds/accton.tproj/accton.c87
-rw-r--r--system_cmds/arch.tproj/arch.1245
-rw-r--r--system_cmds/arch.tproj/arch.c802
-rw-r--r--system_cmds/arch.tproj/machine.149
-rw-r--r--system_cmds/at.tproj/LEGAL29
-rw-r--r--system_cmds/at.tproj/at.1369
-rw-r--r--system_cmds/at.tproj/at.c960
-rw-r--r--system_cmds/at.tproj/at.h31
-rw-r--r--system_cmds/at.tproj/panic.c92
-rw-r--r--system_cmds/at.tproj/panic.h32
-rw-r--r--system_cmds/at.tproj/parsetime.c736
-rw-r--r--system_cmds/at.tproj/parsetime.h26
-rw-r--r--system_cmds/at.tproj/pathnames.h69
-rw-r--r--system_cmds/at.tproj/perm.c125
-rw-r--r--system_cmds/at.tproj/perm.h28
-rw-r--r--system_cmds/at.tproj/privs.h110
-rw-r--r--system_cmds/atrun.tproj/atrun.875
-rw-r--r--system_cmds/atrun.tproj/atrun.c571
-rw-r--r--system_cmds/atrun.tproj/com.apple.atrun.plist16
-rw-r--r--system_cmds/atrun.tproj/gloadavg.c72
-rw-r--r--system_cmds/atrun.tproj/gloadavg.h29
-rw-r--r--system_cmds/base.xcconfig9
-rw-r--r--system_cmds/chkpasswd.tproj/chkpasswd.859
-rw-r--r--system_cmds/chkpasswd.tproj/chkpasswd.pam5
-rw-r--r--system_cmds/chkpasswd.tproj/file_passwd.c276
-rw-r--r--system_cmds/chkpasswd.tproj/nis_passwd.c210
-rw-r--r--system_cmds/chkpasswd.tproj/od_passwd.c105
-rw-r--r--system_cmds/chkpasswd.tproj/pam_passwd.c81
-rw-r--r--system_cmds/chkpasswd.tproj/passwd.c174
-rw-r--r--system_cmds/chkpasswd.tproj/passwd.h5
-rw-r--r--system_cmds/chkpasswd.tproj/stringops.c261
-rw-r--r--system_cmds/chkpasswd.tproj/stringops.h39
-rw-r--r--system_cmds/chpass.tproj/IMPORT_NOTES1
-rw-r--r--system_cmds/chpass.tproj/chpass.1315
-rw-r--r--system_cmds/chpass.tproj/chpass.c457
-rw-r--r--system_cmds/chpass.tproj/chpass.h132
-rw-r--r--system_cmds/chpass.tproj/edit.c415
-rw-r--r--system_cmds/chpass.tproj/field.c345
-rw-r--r--system_cmds/chpass.tproj/open_directory.c205
-rw-r--r--system_cmds/chpass.tproj/open_directory.h13
-rw-r--r--system_cmds/chpass.tproj/pw_copy.c127
-rw-r--r--system_cmds/chpass.tproj/pw_copy.h56
-rw-r--r--system_cmds/chpass.tproj/table.c117
-rw-r--r--system_cmds/chpass.tproj/util.c335
-rw-r--r--system_cmds/cpuctl.tproj/cpuctl.867
-rw-r--r--system_cmds/cpuctl.tproj/cpuctl.c145
-rw-r--r--system_cmds/dmesg.tproj/dmesg.855
-rw-r--r--system_cmds/dmesg.tproj/dmesg.c101
-rw-r--r--system_cmds/dynamic_pager.tproj/com.apple.dynamic_pager.plist21
-rw-r--r--system_cmds/dynamic_pager.tproj/dynamic_pager.832
-rw-r--r--system_cmds/dynamic_pager.tproj/dynamic_pager.c114
-rw-r--r--system_cmds/dynamic_pager.tproj/entitlements.plist8
-rw-r--r--system_cmds/dynamic_pager.tproj/generate_plist.sh16
-rw-r--r--system_cmds/fs_usage.tproj/fs_usage.1178
-rw-r--r--system_cmds/fs_usage.tproj/fs_usage.c3922
-rw-r--r--system_cmds/gcore.tproj/convert.c1117
-rw-r--r--system_cmds/gcore.tproj/convert.h24
-rw-r--r--system_cmds/gcore.tproj/corefile.c852
-rw-r--r--system_cmds/gcore.tproj/corefile.h71
-rw-r--r--system_cmds/gcore.tproj/dyld.c314
-rw-r--r--system_cmds/gcore.tproj/dyld.h35
-rw-r--r--system_cmds/gcore.tproj/dyld_shared_cache.c108
-rw-r--r--system_cmds/gcore.tproj/dyld_shared_cache.h36
-rw-r--r--system_cmds/gcore.tproj/gcore-entitlements.plist8
-rw-r--r--system_cmds/gcore.tproj/gcore-internal.1201
-rw-r--r--system_cmds/gcore.tproj/gcore.1105
-rw-r--r--system_cmds/gcore.tproj/loader_additions.h103
-rw-r--r--system_cmds/gcore.tproj/main.c863
-rw-r--r--system_cmds/gcore.tproj/options.h62
-rw-r--r--system_cmds/gcore.tproj/region.h133
-rw-r--r--system_cmds/gcore.tproj/sparse.c497
-rw-r--r--system_cmds/gcore.tproj/sparse.h72
-rw-r--r--system_cmds/gcore.tproj/threads.c81
-rw-r--r--system_cmds/gcore.tproj/threads.h14
-rw-r--r--system_cmds/gcore.tproj/utils.c421
-rw-r--r--system_cmds/gcore.tproj/utils.h42
-rw-r--r--system_cmds/gcore.tproj/vanilla.c911
-rw-r--r--system_cmds/gcore.tproj/vanilla.h17
-rw-r--r--system_cmds/gcore.tproj/vm.c493
-rw-r--r--system_cmds/gcore.tproj/vm.h47
-rw-r--r--system_cmds/getconf.tproj/confstr.gperf73
-rw-r--r--system_cmds/getconf.tproj/fake-gperf.awk66
-rw-r--r--system_cmds/getconf.tproj/getconf.1212
-rw-r--r--system_cmds/getconf.tproj/getconf.c189
-rw-r--r--system_cmds/getconf.tproj/getconf.h43
-rw-r--r--system_cmds/getconf.tproj/limits.gperf142
-rw-r--r--system_cmds/getconf.tproj/pathconf.gperf88
-rw-r--r--system_cmds/getconf.tproj/progenv.gperf70
-rw-r--r--system_cmds/getconf.tproj/sysconf.gperf187
-rw-r--r--system_cmds/getty.tproj/chat.c492
-rw-r--r--system_cmds/getty.tproj/com.apple.getty.internal.plist33
-rw-r--r--system_cmds/getty.tproj/com.apple.getty.plist24
-rw-r--r--system_cmds/getty.tproj/com.apple.serialdebugconsole.plist39
-rw-r--r--system_cmds/getty.tproj/extern.h60
-rw-r--r--system_cmds/getty.tproj/generate_plist.sh16
-rw-r--r--system_cmds/getty.tproj/getty.8128
-rw-r--r--system_cmds/getty.tproj/gettytab.5546
-rw-r--r--system_cmds/getty.tproj/gettytab.h177
-rw-r--r--system_cmds/getty.tproj/init.c156
-rw-r--r--system_cmds/getty.tproj/main.c858
-rw-r--r--system_cmds/getty.tproj/pathnames.h40
-rw-r--r--system_cmds/getty.tproj/subr.c710
-rw-r--r--system_cmds/getty.tproj/ttys.5168
-rw-r--r--system_cmds/hostinfo.tproj/hostinfo.889
-rw-r--r--system_cmds/hostinfo.tproj/hostinfo.c163
-rw-r--r--system_cmds/iosim.tproj/iosim.1100
-rw-r--r--system_cmds/iosim.tproj/iosim.c673
-rw-r--r--system_cmds/iostat.tproj/iostat.8302
-rw-r--r--system_cmds/iostat.tproj/iostat.c998
-rw-r--r--system_cmds/kpgo.tproj/kpgo.c144
-rw-r--r--system_cmds/latency.tproj/latency.1106
-rw-r--r--system_cmds/latency.tproj/latency.c2793
-rw-r--r--system_cmds/login.tproj/klogin.c207
-rw-r--r--system_cmds/login.tproj/login.1186
-rw-r--r--system_cmds/login.tproj/login.c1509
-rw-r--r--system_cmds/login.tproj/login.entitlements8
-rw-r--r--system_cmds/login.tproj/login.h37
-rw-r--r--system_cmds/login.tproj/login_audit.c230
-rw-r--r--system_cmds/login.tproj/pam.d/login11
-rw-r--r--system_cmds/login.tproj/pam.d/login.term4
-rw-r--r--system_cmds/login.tproj/pathnames.h42
-rw-r--r--system_cmds/lskq.tproj/common.h167
-rw-r--r--system_cmds/lskq.tproj/lskq.1236
-rw-r--r--system_cmds/lskq.tproj/lskq.c963
-rw-r--r--system_cmds/lsmp.tproj/common.h204
-rw-r--r--system_cmds/lsmp.tproj/entitlements.plist10
-rw-r--r--system_cmds/lsmp.tproj/json.h119
-rw-r--r--system_cmds/lsmp.tproj/lsmp.161
-rw-r--r--system_cmds/lsmp.tproj/lsmp.c239
-rw-r--r--system_cmds/lsmp.tproj/port_details.c746
-rw-r--r--system_cmds/lsmp.tproj/task_details.c507
-rw-r--r--system_cmds/ltop.tproj/ltop.159
-rw-r--r--system_cmds/ltop.tproj/ltop.c491
-rw-r--r--system_cmds/mean.tproj/mean.c128
-rw-r--r--system_cmds/memory_pressure.tproj/memory_pressure.128
-rw-r--r--system_cmds/memory_pressure.tproj/memory_pressure.c777
-rw-r--r--system_cmds/mkfile.tproj/mkfile.847
-rw-r--r--system_cmds/mkfile.tproj/mkfile.c204
-rw-r--r--system_cmds/mslutil/mslutil.146
-rw-r--r--system_cmds/mslutil/mslutil.c96
-rw-r--r--system_cmds/newgrp.tproj/newgrp.195
-rw-r--r--system_cmds/newgrp.tproj/newgrp.c352
-rw-r--r--system_cmds/nologin.tproj/nologin.596
-rw-r--r--system_cmds/nologin.tproj/nologin.857
-rw-r--r--system_cmds/nologin.tproj/nologin.c51
-rw-r--r--system_cmds/nvram.tproj/nvram.893
-rw-r--r--system_cmds/nvram.tproj/nvram.c965
-rw-r--r--system_cmds/pagesize.tproj/pagesize.158
-rw-r--r--system_cmds/pagesize.tproj/pagesize.sh40
-rw-r--r--system_cmds/passwd.tproj/file_passwd.c237
-rw-r--r--system_cmds/passwd.tproj/nis_passwd.c265
-rw-r--r--system_cmds/passwd.tproj/od_passwd.c253
-rw-r--r--system_cmds/passwd.tproj/pam_passwd.c80
-rw-r--r--system_cmds/passwd.tproj/passwd.1134
-rw-r--r--system_cmds/passwd.tproj/passwd.c302
-rw-r--r--system_cmds/passwd.tproj/passwd.entitlements12
-rw-r--r--system_cmds/passwd.tproj/passwd.h47
-rw-r--r--system_cmds/passwd.tproj/passwd.pam5
-rw-r--r--system_cmds/proc_uuid_policy.tproj/proc_uuid_policy.154
-rw-r--r--system_cmds/proc_uuid_policy.tproj/proc_uuid_policy.c470
-rw-r--r--system_cmds/purge.tproj/purge.814
-rw-r--r--system_cmds/purge.tproj/purge.c42
-rw-r--r--system_cmds/pwd_mkdb.tproj/pw_scan.c160
-rw-r--r--system_cmds/pwd_mkdb.tproj/pw_scan.h59
-rw-r--r--system_cmds/pwd_mkdb.tproj/pwd_mkdb.8177
-rw-r--r--system_cmds/pwd_mkdb.tproj/pwd_mkdb.c625
-rw-r--r--system_cmds/reboot.tproj/kextmanager.defs6
-rw-r--r--system_cmds/reboot.tproj/reboot.8115
-rw-r--r--system_cmds/reboot.tproj/reboot.c378
-rw-r--r--system_cmds/sa.tproj/db.c211
-rw-r--r--system_cmds/sa.tproj/extern.h127
-rw-r--r--system_cmds/sa.tproj/main.c608
-rw-r--r--system_cmds/sa.tproj/pathnames.h35
-rw-r--r--system_cmds/sa.tproj/pdb.c469
-rw-r--r--system_cmds/sa.tproj/sa.8262
-rw-r--r--system_cmds/sa.tproj/usrdb.c261
-rw-r--r--system_cmds/sc_usage.tproj/sc_usage.1133
-rw-r--r--system_cmds/sc_usage.tproj/sc_usage.c1787
-rw-r--r--system_cmds/shutdown.tproj/kextmanager.defs6
-rw-r--r--system_cmds/shutdown.tproj/pathnames.h29
-rw-r--r--system_cmds/shutdown.tproj/shutdown.8176
-rw-r--r--system_cmds/shutdown.tproj/shutdown.c796
-rw-r--r--system_cmds/stackshot.tproj/stackshot.c248
-rw-r--r--system_cmds/sync.tproj/sync.868
-rw-r--r--system_cmds/sync.tproj/sync.c52
-rw-r--r--system_cmds/sysctl.tproj/sysctl.8390
-rw-r--r--system_cmds/sysctl.tproj/sysctl.c1009
-rw-r--r--system_cmds/sysctl.tproj/sysctl.conf.575
-rw-r--r--system_cmds/system_cmds.xcodeproj/project.pbxproj9146
-rw-r--r--system_cmds/system_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--system_cmds/system_cmds.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings10
-rw-r--r--system_cmds/system_cmds.xcodeproj/xcshareddata/xcschemes/All_MacOSX.xcscheme71
-rw-r--r--system_cmds/system_cmds.xcodeproj/xcshareddata/xcschemes/All_iOS.xcscheme75
-rw-r--r--system_cmds/taskpolicy.tproj/taskpolicy-entitlements.plist8
-rw-r--r--system_cmds/taskpolicy.tproj/taskpolicy.875
-rw-r--r--system_cmds/taskpolicy.tproj/taskpolicy.c324
-rw-r--r--system_cmds/tests/system_cmds.plist214
-rw-r--r--system_cmds/trace.tproj/trace.1380
-rw-r--r--system_cmds/trace.tproj/trace.c2941
-rw-r--r--system_cmds/vifs.tproj/vifs.846
-rw-r--r--system_cmds/vifs.tproj/vifs.c120
-rw-r--r--system_cmds/vipw.tproj/pw_util.c239
-rw-r--r--system_cmds/vipw.tproj/pw_util.h65
-rw-r--r--system_cmds/vipw.tproj/vipw.892
-rw-r--r--system_cmds/vipw.tproj/vipw.c147
-rw-r--r--system_cmds/vm_purgeable_stat.tproj/entitlements.plist8
-rw-r--r--system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.135
-rw-r--r--system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c250
-rw-r--r--system_cmds/vm_stat.tproj/vm_stat.189
-rw-r--r--system_cmds/vm_stat.tproj/vm_stat.c267
-rw-r--r--system_cmds/wait4path/wait4path.137
-rw-r--r--system_cmds/wait4path/wait4path.c64
-rw-r--r--system_cmds/wait4path/wait4path.version5
-rw-r--r--system_cmds/wordexp-helper.tproj/wordexp-helper.c43
-rw-r--r--system_cmds/xcconfigs/base.xcconfig88
-rw-r--r--system_cmds/xcconfigs/development.xcconfig29
-rw-r--r--system_cmds/xcconfigs/executable.xcconfig45
-rw-r--r--system_cmds/xcconfigs/wait4path.xcconfig16
-rw-r--r--system_cmds/xscripts/darwinversion.sh228
-rw-r--r--system_cmds/zdump.tproj/zdump.849
-rw-r--r--system_cmds/zdump.tproj/zdump.c390
-rw-r--r--system_cmds/zic.tproj/Arts.htm178
-rw-r--r--system_cmds/zic.tproj/Makefile.zoneinfo.dist90
-rw-r--r--system_cmds/zic.tproj/README88
-rw-r--r--system_cmds/zic.tproj/Theory552
-rw-r--r--system_cmds/zic.tproj/ZIC_HACK6
-rwxr-xr-xsystem_cmds/zic.tproj/build_zichost.sh50
-rwxr-xr-xsystem_cmds/zic.tproj/generate_zone_file_list.sh28
-rwxr-xr-xsystem_cmds/zic.tproj/generate_zoneinfo.sh105
-rw-r--r--system_cmds/zic.tproj/ialloc.c91
-rwxr-xr-xsystem_cmds/zic.tproj/install_zoneinfo.sh47
-rw-r--r--system_cmds/zic.tproj/private.h272
-rw-r--r--system_cmds/zic.tproj/scheck.c68
-rw-r--r--system_cmds/zic.tproj/tz-art.htm278
-rw-r--r--system_cmds/zic.tproj/tz-link.htm443
-rw-r--r--system_cmds/zic.tproj/tzfile.h192
-rw-r--r--system_cmds/zic.tproj/zic.8468
-rw-r--r--system_cmds/zic.tproj/zic.c2770
-rw-r--r--system_cmds/zlog.tproj/SymbolicationHelper.c181
-rw-r--r--system_cmds/zlog.tproj/SymbolicationHelper.h35
-rw-r--r--system_cmds/zlog.tproj/entitlements.plist8
-rw-r--r--system_cmds/zlog.tproj/zlog.156
-rw-r--r--system_cmds/zlog.tproj/zlog.c257
-rw-r--r--system_cmds/zprint.tproj/entitlements.plist8
-rw-r--r--system_cmds/zprint.tproj/test_zprint.lua89
-rw-r--r--system_cmds/zprint.tproj/zprint.190
-rw-r--r--system_cmds/zprint.tproj/zprint.c1092
-rw-r--r--system_cmds/zprint.tproj/zprint.lua281
-rw-r--r--text_cmds/.upstream_base_commits10
-rw-r--r--text_cmds/banner/banner.682
-rw-r--r--text_cmds/banner/banner.c1186
-rw-r--r--text_cmds/cat/cat.1201
-rw-r--r--text_cmds/cat/cat.c314
-rw-r--r--text_cmds/col/README48
-rw-r--r--text_cmds/col/col.1156
-rw-r--r--text_cmds/col/col.c552
-rw-r--r--text_cmds/colrm/colrm.191
-rw-r--r--text_cmds/colrm/colrm.c146
-rw-r--r--text_cmds/column/column.1101
-rw-r--r--text_cmds/column/column.c334
-rw-r--r--text_cmds/comm/comm.1124
-rw-r--r--text_cmds/comm/comm.c220
-rw-r--r--text_cmds/csplit/csplit.1157
-rw-r--r--text_cmds/csplit/csplit.c467
-rw-r--r--text_cmds/cut/cut.1166
-rw-r--r--text_cmds/cut/cut.c468
-rw-r--r--text_cmds/ed/POSIX101
-rw-r--r--text_cmds/ed/README24
-rw-r--r--text_cmds/ed/buf.c284
-rw-r--r--text_cmds/ed/cbc.c402
-rw-r--r--text_cmds/ed/ed.11004
-rw-r--r--text_cmds/ed/ed.h282
-rw-r--r--text_cmds/ed/glbl.c218
-rw-r--r--text_cmds/ed/io.c341
-rw-r--r--text_cmds/ed/main.c1455
-rw-r--r--text_cmds/ed/re.c132
-rw-r--r--text_cmds/ed/red.11
-rw-r--r--text_cmds/ed/sub.c256
-rw-r--r--text_cmds/ed/test/=.err1
-rw-r--r--text_cmds/ed/test/README32
-rw-r--r--text_cmds/ed/test/TODO15
-rw-r--r--text_cmds/ed/test/a.d5
-rw-r--r--text_cmds/ed/test/a.r8
-rw-r--r--text_cmds/ed/test/a.t9
-rw-r--r--text_cmds/ed/test/a1.err3
-rw-r--r--text_cmds/ed/test/a2.err3
-rw-r--r--text_cmds/ed/test/addr.d9
-rw-r--r--text_cmds/ed/test/addr.r2
-rw-r--r--text_cmds/ed/test/addr.t5
-rw-r--r--text_cmds/ed/test/addr1.err1
-rw-r--r--text_cmds/ed/test/addr2.err1
-rw-r--r--text_cmds/ed/test/ascii.d.uu9
-rw-r--r--text_cmds/ed/test/ascii.r.uu9
-rw-r--r--text_cmds/ed/test/ascii.t0
-rw-r--r--text_cmds/ed/test/bang1.d0
-rw-r--r--text_cmds/ed/test/bang1.err1
-rw-r--r--text_cmds/ed/test/bang1.r1
-rw-r--r--text_cmds/ed/test/bang1.t5
-rw-r--r--text_cmds/ed/test/bang2.err1
-rw-r--r--text_cmds/ed/test/c.d5
-rw-r--r--text_cmds/ed/test/c.r4
-rw-r--r--text_cmds/ed/test/c.t12
-rw-r--r--text_cmds/ed/test/c1.err3
-rw-r--r--text_cmds/ed/test/c2.err3
-rwxr-xr-xtext_cmds/ed/test/ckscripts.sh37
-rw-r--r--text_cmds/ed/test/d.d5
-rw-r--r--text_cmds/ed/test/d.err1
-rw-r--r--text_cmds/ed/test/d.r1
-rw-r--r--text_cmds/ed/test/d.t3
-rw-r--r--text_cmds/ed/test/e1.d1
-rw-r--r--text_cmds/ed/test/e1.err1
-rw-r--r--text_cmds/ed/test/e1.r1
-rw-r--r--text_cmds/ed/test/e1.t1
-rw-r--r--text_cmds/ed/test/e2.d1
-rw-r--r--text_cmds/ed/test/e2.err1
-rw-r--r--text_cmds/ed/test/e2.r1
-rw-r--r--text_cmds/ed/test/e2.t1
-rw-r--r--text_cmds/ed/test/e3.d1
-rw-r--r--text_cmds/ed/test/e3.err1
-rw-r--r--text_cmds/ed/test/e3.r1
-rw-r--r--text_cmds/ed/test/e3.t1
-rw-r--r--text_cmds/ed/test/e4.d1
-rw-r--r--text_cmds/ed/test/e4.r1
-rw-r--r--text_cmds/ed/test/e4.t1
-rw-r--r--text_cmds/ed/test/f1.err1
-rw-r--r--text_cmds/ed/test/f2.err1
-rw-r--r--text_cmds/ed/test/g1.d5
-rw-r--r--text_cmds/ed/test/g1.err1
-rw-r--r--text_cmds/ed/test/g1.r15
-rw-r--r--text_cmds/ed/test/g1.t6
-rw-r--r--text_cmds/ed/test/g2.d5
-rw-r--r--text_cmds/ed/test/g2.err1
-rw-r--r--text_cmds/ed/test/g2.r1
-rw-r--r--text_cmds/ed/test/g2.t2
-rw-r--r--text_cmds/ed/test/g3.d5
-rw-r--r--text_cmds/ed/test/g3.err1
-rw-r--r--text_cmds/ed/test/g3.r5
-rw-r--r--text_cmds/ed/test/g3.t4
-rw-r--r--text_cmds/ed/test/g4.d5
-rw-r--r--text_cmds/ed/test/g4.r7
-rw-r--r--text_cmds/ed/test/g4.t13
-rw-r--r--text_cmds/ed/test/g5.d3
-rw-r--r--text_cmds/ed/test/g5.r9
-rw-r--r--text_cmds/ed/test/g5.t2
-rw-r--r--text_cmds/ed/test/h.err1
-rw-r--r--text_cmds/ed/test/i.d5
-rw-r--r--text_cmds/ed/test/i.r8
-rw-r--r--text_cmds/ed/test/i.t9
-rw-r--r--text_cmds/ed/test/i1.err3
-rw-r--r--text_cmds/ed/test/i2.err3
-rw-r--r--text_cmds/ed/test/i3.err3
-rw-r--r--text_cmds/ed/test/j.d5
-rw-r--r--text_cmds/ed/test/j.r4
-rw-r--r--text_cmds/ed/test/j.t2
-rw-r--r--text_cmds/ed/test/k.d5
-rw-r--r--text_cmds/ed/test/k.r5
-rw-r--r--text_cmds/ed/test/k.t10
-rw-r--r--text_cmds/ed/test/k1.err1
-rw-r--r--text_cmds/ed/test/k2.err1
-rw-r--r--text_cmds/ed/test/k3.err1
-rw-r--r--text_cmds/ed/test/k4.err6
-rw-r--r--text_cmds/ed/test/l.d0
-rw-r--r--text_cmds/ed/test/l.r0
-rw-r--r--text_cmds/ed/test/l.t0
-rw-r--r--text_cmds/ed/test/m.d5
-rw-r--r--text_cmds/ed/test/m.err4
-rw-r--r--text_cmds/ed/test/m.r5
-rw-r--r--text_cmds/ed/test/m.t7
-rwxr-xr-xtext_cmds/ed/test/mkscripts.sh75
-rw-r--r--text_cmds/ed/test/n.d0
-rw-r--r--text_cmds/ed/test/n.r0
-rw-r--r--text_cmds/ed/test/n.t0
-rw-r--r--text_cmds/ed/test/nl.err1
-rw-r--r--text_cmds/ed/test/nl1.d5
-rw-r--r--text_cmds/ed/test/nl1.r8
-rw-r--r--text_cmds/ed/test/nl1.t8
-rw-r--r--text_cmds/ed/test/nl2.d5
-rw-r--r--text_cmds/ed/test/nl2.r6
-rw-r--r--text_cmds/ed/test/nl2.t4
-rw-r--r--text_cmds/ed/test/p.d0
-rw-r--r--text_cmds/ed/test/p.r0
-rw-r--r--text_cmds/ed/test/p.t0
-rw-r--r--text_cmds/ed/test/q.d0
-rw-r--r--text_cmds/ed/test/q.r0
-rw-r--r--text_cmds/ed/test/q.t5
-rw-r--r--text_cmds/ed/test/q1.err1
-rw-r--r--text_cmds/ed/test/r1.d5
-rw-r--r--text_cmds/ed/test/r1.err1
-rw-r--r--text_cmds/ed/test/r1.r7
-rw-r--r--text_cmds/ed/test/r1.t3
-rw-r--r--text_cmds/ed/test/r2.d5
-rw-r--r--text_cmds/ed/test/r2.err1
-rw-r--r--text_cmds/ed/test/r2.r10
-rw-r--r--text_cmds/ed/test/r2.t1
-rw-r--r--text_cmds/ed/test/r3.d1
-rw-r--r--text_cmds/ed/test/r3.r2
-rw-r--r--text_cmds/ed/test/r3.t1
-rw-r--r--text_cmds/ed/test/s1.d5
-rw-r--r--text_cmds/ed/test/s1.err1
-rw-r--r--text_cmds/ed/test/s1.r5
-rw-r--r--text_cmds/ed/test/s1.t6
-rw-r--r--text_cmds/ed/test/s10.err4
-rw-r--r--text_cmds/ed/test/s2.d5
-rw-r--r--text_cmds/ed/test/s2.err4
-rw-r--r--text_cmds/ed/test/s2.r5
-rw-r--r--text_cmds/ed/test/s2.t4
-rw-r--r--text_cmds/ed/test/s3.d0
-rw-r--r--text_cmds/ed/test/s3.err1
-rw-r--r--text_cmds/ed/test/s3.r1
-rw-r--r--text_cmds/ed/test/s3.t6
-rw-r--r--text_cmds/ed/test/s4.err1
-rw-r--r--text_cmds/ed/test/s5.err1
-rw-r--r--text_cmds/ed/test/s6.err1
-rw-r--r--text_cmds/ed/test/s7.err5
-rw-r--r--text_cmds/ed/test/s8.err4
-rw-r--r--text_cmds/ed/test/s9.err4
-rw-r--r--text_cmds/ed/test/t.d5
-rw-r--r--text_cmds/ed/test/t.r16
-rw-r--r--text_cmds/ed/test/t1.d5
-rw-r--r--text_cmds/ed/test/t1.err1
-rw-r--r--text_cmds/ed/test/t1.r16
-rw-r--r--text_cmds/ed/test/t1.t3
-rw-r--r--text_cmds/ed/test/t2.d5
-rw-r--r--text_cmds/ed/test/t2.err1
-rw-r--r--text_cmds/ed/test/t2.r6
-rw-r--r--text_cmds/ed/test/t2.t1
-rw-r--r--text_cmds/ed/test/u.d5
-rw-r--r--text_cmds/ed/test/u.err1
-rw-r--r--text_cmds/ed/test/u.r9
-rw-r--r--text_cmds/ed/test/u.t31
-rw-r--r--text_cmds/ed/test/v.d5
-rw-r--r--text_cmds/ed/test/v.r11
-rw-r--r--text_cmds/ed/test/v.t6
-rw-r--r--text_cmds/ed/test/w.d5
-rw-r--r--text_cmds/ed/test/w.r10
-rw-r--r--text_cmds/ed/test/w.t2
-rw-r--r--text_cmds/ed/test/w1.err1
-rw-r--r--text_cmds/ed/test/w2.err1
-rw-r--r--text_cmds/ed/test/w3.err1
-rw-r--r--text_cmds/ed/test/x.err1
-rw-r--r--text_cmds/ed/test/z.err2
-rw-r--r--text_cmds/ed/undo.c150
-rw-r--r--text_cmds/ee/Changes40
-rw-r--r--text_cmds/ee/Makefile29
-rw-r--r--text_cmds/ee/README.ee119
-rwxr-xr-xtext_cmds/ee/create.make292
-rw-r--r--text_cmds/ee/ee.1543
-rw-r--r--text_cmds/ee/ee.c5348
-rw-r--r--text_cmds/ee/ee.i18n.guide158
-rw-r--r--text_cmds/ee/ee.msg186
-rw-r--r--text_cmds/ee/ee_version.h6
-rwxr-xr-xtext_cmds/ee/genstr32
-rw-r--r--text_cmds/ee/make.default57
-rw-r--r--text_cmds/ee/new_curse.c3819
-rw-r--r--text_cmds/ee/new_curse.h260
-rw-r--r--text_cmds/expand/expand.1118
-rw-r--r--text_cmds/expand/expand.c200
-rw-r--r--text_cmds/expand/xcodescripts/link-man-pages.sh3
-rw-r--r--text_cmds/fmt/fmt.1196
-rw-r--r--text_cmds/fmt/fmt.c668
-rw-r--r--text_cmds/fold/fold.190
-rw-r--r--text_cmds/fold/fold.c228
-rw-r--r--text_cmds/grep/file.c347
-rw-r--r--text_cmds/grep/grep.1500
-rw-r--r--text_cmds/grep/grep.c783
-rw-r--r--text_cmds/grep/grep.h161
-rw-r--r--text_cmds/grep/queue.c107
-rw-r--r--text_cmds/grep/util.c599
-rw-r--r--text_cmds/head/head.169
-rw-r--r--text_cmds/head/head.c199
-rw-r--r--text_cmds/join/join.1235
-rw-r--r--text_cmds/join/join.c685
-rw-r--r--text_cmds/lam/lam.1141
-rw-r--r--text_cmds/lam/lam.c234
-rw-r--r--text_cmds/look/look.1124
-rw-r--r--text_cmds/look/look.c357
-rw-r--r--text_cmds/look/pathnames.h36
-rw-r--r--text_cmds/md5/commoncrypto.c108
-rw-r--r--text_cmds/md5/commoncrypto.h8
-rw-r--r--text_cmds/md5/md5.195
-rw-r--r--text_cmds/md5/md5.c419
-rw-r--r--text_cmds/nl/nl.1253
-rw-r--r--text_cmds/nl/nl.c439
-rw-r--r--text_cmds/paste/paste.1150
-rw-r--r--text_cmds/paste/paste.c280
-rw-r--r--text_cmds/pr/egetopt.c218
-rw-r--r--text_cmds/pr/extern.h61
-rw-r--r--text_cmds/pr/pr.1402
-rw-r--r--text_cmds/pr/pr.c1856
-rw-r--r--text_cmds/pr/pr.h74
-rw-r--r--text_cmds/rev/rev.149
-rw-r--r--text_cmds/rev/rev.c118
-rw-r--r--text_cmds/rs/rs.1239
-rw-r--r--text_cmds/rs/rs.c553
-rw-r--r--text_cmds/sed/POSIX204
-rw-r--r--text_cmds/sed/TEST/hanoi.sed103
-rw-r--r--text_cmds/sed/TEST/math.sed439
-rw-r--r--text_cmds/sed/TEST/sed.test556
-rw-r--r--text_cmds/sed/compile.c987
-rw-r--r--text_cmds/sed/defs.h151
-rw-r--r--text_cmds/sed/extern.h60
-rw-r--r--text_cmds/sed/main.c547
-rw-r--r--text_cmds/sed/misc.c73
-rw-r--r--text_cmds/sed/process.c791
-rw-r--r--text_cmds/sed/sed.1668
-rw-r--r--text_cmds/sort/bwstring.c1142
-rw-r--r--text_cmds/sort/bwstring.h142
-rw-r--r--text_cmds/sort/coll.c1324
-rw-r--r--text_cmds/sort/coll.h168
-rw-r--r--text_cmds/sort/commoncrypto.c98
-rw-r--r--text_cmds/sort/commoncrypto.h8
-rw-r--r--text_cmds/sort/file.c1684
-rw-r--r--text_cmds/sort/file.h126
-rw-r--r--text_cmds/sort/mem.c81
-rw-r--r--text_cmds/sort/mem.h45
-rw-r--r--text_cmds/sort/nls/C.msg16
-rw-r--r--text_cmds/sort/nls/hu_HU.ISO8859-2.msg16
-rw-r--r--text_cmds/sort/radixsort.c746
-rw-r--r--text_cmds/sort/radixsort.h38
-rw-r--r--text_cmds/sort/sort.1.in639
-rw-r--r--text_cmds/sort/sort.c1325
-rw-r--r--text_cmds/sort/sort.h139
-rw-r--r--text_cmds/sort/testsuite/README.txt19
-rw-r--r--text_cmds/sort/testsuite/bigsample.txt.xzbin0 -> 50904 bytes
-rwxr-xr-xtext_cmds/sort/testsuite/run.sh436
-rw-r--r--text_cmds/sort/testsuite/sample.txtbin0 -> 1672 bytes
-rw-r--r--text_cmds/sort/vsort.c265
-rw-r--r--text_cmds/sort/vsort.h37
-rw-r--r--text_cmds/split/split.1142
-rw-r--r--text_cmds/split/split.c342
-rw-r--r--text_cmds/tail/extern.h76
-rw-r--r--text_cmds/tail/forward.c520
-rw-r--r--text_cmds/tail/misc.c119
-rw-r--r--text_cmds/tail/read.c214
-rw-r--r--text_cmds/tail/reverse.c287
-rw-r--r--text_cmds/tail/tail.1188
-rw-r--r--text_cmds/tail/tail.c349
-rw-r--r--text_cmds/tests/Makefile6
-rw-r--r--text_cmds/tests/sort_vers.c23
-rw-r--r--text_cmds/text_cmds.plist607
-rw-r--r--text_cmds/text_cmds.xcodeproj/project.pbxproj3890
-rw-r--r--text_cmds/text_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata7
-rw-r--r--text_cmds/tr/cmap.c212
-rw-r--r--text_cmds/tr/cmap.h83
-rw-r--r--text_cmds/tr/cset.c290
-rw-r--r--text_cmds/tr/cset.h74
-rw-r--r--text_cmds/tr/extern.h55
-rw-r--r--text_cmds/tr/str.c450
-rw-r--r--text_cmds/tr/tr.1420
-rw-r--r--text_cmds/tr/tr.c378
-rw-r--r--text_cmds/ul/ul.1104
-rw-r--r--text_cmds/ul/ul.c569
-rw-r--r--text_cmds/unexpand/unexpand.c231
-rw-r--r--text_cmds/uniq/uniq.1151
-rw-r--r--text_cmds/uniq/uniq.c367
-rw-r--r--text_cmds/unvis/unvis.159
-rw-r--r--text_cmds/unvis/unvis.c126
-rw-r--r--text_cmds/vis/extern.h36
-rw-r--r--text_cmds/vis/foldit.c82
-rw-r--r--text_cmds/vis/vis.1140
-rw-r--r--text_cmds/vis/vis.c194
-rw-r--r--text_cmds/wc/wc.1163
-rw-r--r--text_cmds/wc/wc.c294
-rw-r--r--text_cmds/xcconfigs/base.xcconfig59
-rw-r--r--text_cmds/xcconfigs/ee.xcconfig27
-rw-r--r--text_cmds/xcconfigs/grep.xcconfig19
-rw-r--r--text_cmds/xcconfigs/sort.xcconfig15
-rw-r--r--text_cmds/xcodescripts/grep_variant_links.sh13
-rw-r--r--text_cmds/xcodescripts/install-opensource.sh9
-rw-r--r--text_cmds/xcodescripts/install-sort-man.sh3
2627 files changed, 497181 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..df967b9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+base
diff --git a/adv_cmds/.upstream_base_commits b/adv_cmds/.upstream_base_commits
new file mode 100644
index 0000000..2e37ca8
--- /dev/null
+++ b/adv_cmds/.upstream_base_commits
@@ -0,0 +1,3 @@
+#freebsd = https://github.com/freebsd/freebsd.git
+usr.bin/whois/whois.c freebsd whois/whois.c 872b698bd4a1bfc0bf008c09228e6fd238809c75
+usr.bin/whois/whois.1 freebsd whois/whois.1 7e6cabd06e6caa6a02eeb86308dc0cb3f27e10da
diff --git a/adv_cmds/adv_cmds.xcodeproj/project.pbxproj b/adv_cmds/adv_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..d1eda3c
--- /dev/null
+++ b/adv_cmds/adv_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,1806 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FD0D7F98108FE550004F2A1C /* localedef */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FD0D7FA2108FE56E004F2A1C /* Build configuration list for PBXAggregateTarget "localedef" */;
+ buildPhases = (
+ FD0D7F97108FE550004F2A1C /* ShellScript */,
+ FD0D7FA5108FE5AA004F2A1C /* Install man1 */,
+ );
+ dependencies = (
+ );
+ name = localedef;
+ productName = localedef2;
+ };
+ FD201DCD14369D0C00906237 /* pgrep */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FD201DCE14369D0C00906237 /* Build configuration list for PBXAggregateTarget "pgrep" */;
+ buildPhases = (
+ FD201DD014369D1000906237 /* ShellScript */,
+ );
+ dependencies = (
+ FD201DD214369D5C00906237 /* PBXTargetDependency */,
+ );
+ name = pgrep;
+ productName = pgrep;
+ };
+ FDF2764E0FC60ECD00D7A3C6 /* Embedded */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDF276580FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Embedded" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FD201DD614369D6700906237 /* PBXTargetDependency */,
+ FD201DBF14369B1700906237 /* PBXTargetDependency */,
+ FDF2766D0FC60F0D00D7A3C6 /* PBXTargetDependency */,
+ FDF2766B0FC60F0D00D7A3C6 /* PBXTargetDependency */,
+ );
+ name = Embedded;
+ productName = Embedded;
+ };
+ FDF276500FC60EDA00D7A3C6 /* Desktop */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDF276570FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Desktop" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FDF277670FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF277650FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF277630FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF2775F0FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF2775D0FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF2775B0FC6102600D7A3C6 /* PBXTargetDependency */,
+ FD0D7FA9108FE5C3004F2A1C /* PBXTargetDependency */,
+ FDF277570FC6102600D7A3C6 /* PBXTargetDependency */,
+ FDF277530FC6102600D7A3C6 /* PBXTargetDependency */,
+ FD201DD414369D6300906237 /* PBXTargetDependency */,
+ FD201DC114369B1D00906237 /* PBXTargetDependency */,
+ FDF2766F0FC60F0F00D7A3C6 /* PBXTargetDependency */,
+ FDF276710FC60F1300D7A3C6 /* PBXTargetDependency */,
+ FDF2776D0FC6102B00D7A3C6 /* PBXTargetDependency */,
+ FDF2776B0FC6102B00D7A3C6 /* PBXTargetDependency */,
+ FDF277690FC6102B00D7A3C6 /* PBXTargetDependency */,
+ );
+ name = Desktop;
+ productName = Desktop;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ FD0D7FA4108FE58C004F2A1C /* localedef.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277140FC60FDF00D7A3C6 /* localedef.1 */; };
+ FD201DC214369B4200906237 /* pkill.c in Sources */ = {isa = PBXBuildFile; fileRef = FD201DB014369AD000906237 /* pkill.c */; };
+ FD201DC314369B4600906237 /* pkill.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD201DAF14369AD000906237 /* pkill.1 */; };
+ FDCD383B143BC63000AB81C6 /* libsysmon.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDCD383A143BC63000AB81C6 /* libsysmon.dylib */; };
+ FDF2774B0FC6100400D7A3C6 /* cap_mkdb.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */; };
+ FDF277730FC6105F00D7A3C6 /* cap_mkdb.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */; };
+ FDF277790FC610EC00D7A3C6 /* finger.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276EC0FC60FDF00D7A3C6 /* finger.c */; };
+ FDF2777A0FC610EC00D7A3C6 /* lprint.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276EF0FC60FDF00D7A3C6 /* lprint.c */; };
+ FDF2777B0FC610EC00D7A3C6 /* net.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F10FC60FDF00D7A3C6 /* net.c */; };
+ FDF2777C0FC610EC00D7A3C6 /* sprint.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F30FC60FDF00D7A3C6 /* sprint.c */; };
+ FDF2777D0FC610EC00D7A3C6 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276F40FC60FDF00D7A3C6 /* util.c */; };
+ FDF2779D0FC611B800D7A3C6 /* finger.conf.5 in Install man5 */ = {isa = PBXBuildFile; fileRef = FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */; };
+ FDF2779E0FC611BA00D7A3C6 /* finger.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276EB0FC60FDF00D7A3C6 /* finger.1 */; };
+ FDF277BE0FC612B000D7A3C6 /* whois.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277490FC60FDF00D7A3C6 /* whois.c */; };
+ FDF277C20FC612C800D7A3C6 /* whois.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277480FC60FDF00D7A3C6 /* whois.1 */; };
+ FDF277C40FC6133400D7A3C6 /* tty.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277450FC60FDF00D7A3C6 /* tty.c */; };
+ FDF277C70FC6137B00D7A3C6 /* tty.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277440FC60FDF00D7A3C6 /* tty.1 */; };
+ FDF277D70FC613F500D7A3C6 /* tabs.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277410FC60FDF00D7A3C6 /* tabs.c */; };
+ FDF277D90FC6140400D7A3C6 /* tabs.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FDF277400FC60FDF00D7A3C6 /* tabs.1 */; };
+ FDF277E80FC6144400D7A3C6 /* libtermcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */; };
+ FDF277EE0FC6148500D7A3C6 /* cchar.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277330FC60FDF00D7A3C6 /* cchar.c */; };
+ FDF277EF0FC6148500D7A3C6 /* gfmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277350FC60FDF00D7A3C6 /* gfmt.c */; };
+ FDF277F00FC6148500D7A3C6 /* key.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277360FC60FDF00D7A3C6 /* key.c */; };
+ FDF277F10FC6148500D7A3C6 /* modes.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277380FC60FDF00D7A3C6 /* modes.c */; };
+ FDF277F20FC6148500D7A3C6 /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277390FC60FDF00D7A3C6 /* print.c */; };
+ FDF277F30FC6148500D7A3C6 /* stty.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2773B0FC60FDF00D7A3C6 /* stty.c */; };
+ FDF277F40FC6148500D7A3C6 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2773D0FC60FDF00D7A3C6 /* util.c */; };
+ FDF277F80FC614A300D7A3C6 /* stty.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF2773A0FC60FDF00D7A3C6 /* stty.1 */; };
+ FDF278060FC6151E00D7A3C6 /* fmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277290FC60FDF00D7A3C6 /* fmt.c */; };
+ FDF278070FC6151E00D7A3C6 /* keyword.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772A0FC60FDF00D7A3C6 /* keyword.c */; };
+ FDF278080FC6151E00D7A3C6 /* nlist.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772C0FC60FDF00D7A3C6 /* nlist.c */; };
+ FDF278090FC6151E00D7A3C6 /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772D0FC60FDF00D7A3C6 /* print.c */; };
+ FDF2780A0FC6151E00D7A3C6 /* ps.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2772F0FC60FDF00D7A3C6 /* ps.c */; };
+ FDF2780B0FC6151E00D7A3C6 /* tasks.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277310FC60FDF00D7A3C6 /* tasks.c */; };
+ FDF278280FC615F900D7A3C6 /* ps.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF2772E0FC60FDF00D7A3C6 /* ps.1 */; };
+ FDF278370FC6167800D7A3C6 /* lex.l in Sources */ = {isa = PBXBuildFile; fileRef = FDF277220FC60FDF00D7A3C6 /* lex.l */; };
+ FDF278380FC6167800D7A3C6 /* yacc.y in Sources */ = {isa = PBXBuildFile; fileRef = FDF277260FC60FDF00D7A3C6 /* yacc.y */; };
+ FDF278A30FC61D8900D7A3C6 /* mklocale.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277240FC60FDF00D7A3C6 /* mklocale.1 */; };
+ FDF278C60FC61FDF00D7A3C6 /* lsvfs.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277180FC60FDF00D7A3C6 /* lsvfs.c */; };
+ FDF278CA0FC61FFD00D7A3C6 /* lsvfs.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */; };
+ FDF278D60FC6204E00D7A3C6 /* locale.cc in Sources */ = {isa = PBXBuildFile; fileRef = FDF2770A0FC60FDF00D7A3C6 /* locale.cc */; };
+ FDF278DA0FC6206500D7A3C6 /* locale.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277090FC60FDF00D7A3C6 /* locale.1 */; };
+ FDF278DB0FC6208600D7A3C6 /* last.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277060FC60FDF00D7A3C6 /* last.c */; };
+ FDF278E00FC620A000D7A3C6 /* last.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF277050FC60FDF00D7A3C6 /* last.1 */; };
+ FDF278F50FC623D300D7A3C6 /* gencat.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF276FE0FC60FDF00D7A3C6 /* gencat.c */; };
+ FDF278F60FC623D300D7A3C6 /* genlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF277000FC60FDF00D7A3C6 /* genlib.c */; };
+ FDF2792D0FC625B800D7A3C6 /* gencat.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */; };
+ FDF279390FC6263E00D7A3C6 /* parse.y in Sources */ = {isa = PBXBuildFile; fileRef = FDF276E70FC60FDF00D7A3C6 /* parse.y */; };
+ FDF2793A0FC6263E00D7A3C6 /* scan.l in Sources */ = {isa = PBXBuildFile; fileRef = FDF276E80FC60FDF00D7A3C6 /* scan.l */; };
+ FDF2795E0FC6272500D7A3C6 /* libl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FDF2795D0FC6272500D7A3C6 /* libl.a */; };
+ FDF2798F0FC62B0800D7A3C6 /* colldef.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDF276E10FC60FDF00D7A3C6 /* colldef.1 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ FD0D7FA8108FE5C3004F2A1C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD0D7F98108FE550004F2A1C;
+ remoteInfo = localedef;
+ };
+ FD201DBE14369B1700906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DB414369B0300906237;
+ remoteInfo = pkill;
+ };
+ FD201DC014369B1D00906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DB414369B0300906237;
+ remoteInfo = pkill;
+ };
+ FD201DD114369D5C00906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DB414369B0300906237;
+ remoteInfo = pkill;
+ };
+ FD201DD314369D6300906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DCD14369D0C00906237;
+ remoteInfo = pgrep;
+ };
+ FD201DD514369D6700906237 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD201DCD14369D0C00906237;
+ remoteInfo = pgrep;
+ };
+ FDF2766A0FC60F0D00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276630FC60EFD00D7A3C6;
+ remoteInfo = stty;
+ };
+ FDF2766C0FC60F0D00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF2765B0FC60EF600D7A3C6;
+ remoteInfo = ps;
+ };
+ FDF2766E0FC60F0F00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF2765B0FC60EF600D7A3C6;
+ remoteInfo = ps;
+ };
+ FDF276700FC60F1300D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276630FC60EFD00D7A3C6;
+ remoteInfo = stty;
+ };
+ FDF277520FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276B00FC60F7600D7A3C6;
+ remoteInfo = mklocale;
+ };
+ FDF277560FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276A40FC60F5E00D7A3C6;
+ remoteInfo = lsvfs;
+ };
+ FDF2775A0FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276980FC60F5000D7A3C6;
+ remoteInfo = locale;
+ };
+ FDF2775C0FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276920FC60F4B00D7A3C6;
+ remoteInfo = last;
+ };
+ FDF2775E0FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF2768C0FC60F3D00D7A3C6;
+ remoteInfo = gencat;
+ };
+ FDF277620FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276800FC60F3100D7A3C6;
+ remoteInfo = finger;
+ };
+ FDF277640FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF2767A0FC60F2A00D7A3C6;
+ remoteInfo = colldef;
+ };
+ FDF277660FC6102600D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276740FC60F2100D7A3C6;
+ remoteInfo = cap_mkdb;
+ };
+ FDF277680FC6102B00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276C20FC60F8A00D7A3C6;
+ remoteInfo = whois;
+ };
+ FDF2776A0FC6102B00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276BC0FC60F8400D7A3C6;
+ remoteInfo = tty;
+ };
+ FDF2776C0FC6102B00D7A3C6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDF276430FC60E9000D7A3C6 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDF276B60FC60F7F00D7A3C6;
+ remoteInfo = tabs;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ FD0D7FA5108FE5AA004F2A1C /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FD0D7FA4108FE58C004F2A1C /* localedef.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD201DB314369B0300906237 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FD201DC314369B4600906237 /* pkill.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277780FC610A400D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277730FC6105F00D7A3C6 /* cap_mkdb.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277A10FC611D800D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF2779E0FC611BA00D7A3C6 /* finger.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277A20FC611D800D7A3C6 /* Install man5 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF2779D0FC611B800D7A3C6 /* finger.conf.5 in Install man5 */,
+ );
+ name = "Install man5";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277C30FC612D900D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277C20FC612C800D7A3C6 /* whois.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277C60FC6135D00D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277C70FC6137B00D7A3C6 /* tty.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF277E60FC6143000D7A3C6 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277D90FC6140400D7A3C6 /* tabs.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278030FC614B900D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF277F80FC614A300D7A3C6 /* stty.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278300FC6160800D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278280FC615F900D7A3C6 /* ps.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278A40FC61D9600D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278A30FC61D8900D7A3C6 /* mklocale.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278D50FC6201600D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278CA0FC61FFD00D7A3C6 /* lsvfs.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278E70FC620B600D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278E00FC620A000D7A3C6 /* last.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF278E80FC620B600D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF278DA0FC6206500D7A3C6 /* locale.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF279300FC625CB00D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF2792D0FC625B800D7A3C6 /* gencat.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDF279930FC62B0B00D7A3C6 /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDF2798F0FC62B0800D7A3C6 /* colldef.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ FD201DAF14369AD000906237 /* pkill.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; name = pkill.1; path = pkill/pkill.1; sourceTree = "<group>"; };
+ FD201DB014369AD000906237 /* pkill.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = pkill.c; path = pkill/pkill.c; sourceTree = "<group>"; };
+ FD201DB514369B0400906237 /* pkill */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pkill; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDCD383A143BC63000AB81C6 /* libsysmon.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsysmon.dylib; path = /usr/lib/libsysmon.dylib; sourceTree = "<absolute>"; };
+ FDF2765C0FC60EF600D7A3C6 /* ps */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ps; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276640FC60EFD00D7A3C6 /* stty */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stty; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276750FC60F2100D7A3C6 /* cap_mkdb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cap_mkdb; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF2767B0FC60F2A00D7A3C6 /* colldef */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = colldef; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276810FC60F3100D7A3C6 /* finger */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = finger; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF2768D0FC60F3D00D7A3C6 /* gencat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gencat; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276930FC60F4B00D7A3C6 /* last */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = last; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276990FC60F5000D7A3C6 /* locale */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locale; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276A50FC60F5E00D7A3C6 /* lsvfs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lsvfs; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276B10FC60F7600D7A3C6 /* mklocale */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mklocale; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276B70FC60F7F00D7A3C6 /* tabs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tabs; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276BD0FC60F8400D7A3C6 /* tty */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tty; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276C30FC60F8A00D7A3C6 /* whois */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = whois; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = cap_mkdb.1; sourceTree = "<group>"; };
+ FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cap_mkdb.c; sourceTree = "<group>"; };
+ FDF276E10FC60FDF00D7A3C6 /* colldef.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = colldef.1; sourceTree = "<group>"; };
+ FDF276E20FC60FDF00D7A3C6 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+ FDF276E50FC60FDF00D7A3C6 /* collate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = collate.h; sourceTree = "<group>"; };
+ FDF276E70FC60FDF00D7A3C6 /* parse.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = parse.y; sourceTree = "<group>"; };
+ FDF276E80FC60FDF00D7A3C6 /* scan.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = scan.l; sourceTree = "<group>"; };
+ FDF276EA0FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FDF276EB0FC60FDF00D7A3C6 /* finger.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = finger.1; sourceTree = "<group>"; };
+ FDF276EC0FC60FDF00D7A3C6 /* finger.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = finger.c; sourceTree = "<group>"; };
+ FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = finger.conf.5; sourceTree = "<group>"; };
+ FDF276EE0FC60FDF00D7A3C6 /* finger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = finger.h; sourceTree = "<group>"; };
+ FDF276EF0FC60FDF00D7A3C6 /* lprint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lprint.c; sourceTree = "<group>"; };
+ FDF276F10FC60FDF00D7A3C6 /* net.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = net.c; sourceTree = "<group>"; };
+ FDF276F20FC60FDF00D7A3C6 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FDF276F30FC60FDF00D7A3C6 /* sprint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sprint.c; sourceTree = "<group>"; };
+ FDF276F40FC60FDF00D7A3C6 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FDF276F60FC60FDF00D7A3C6 /* finger.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = finger.plist; sourceTree = "<group>"; };
+ FDF276F70FC60FDF00D7A3C6 /* fingerd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = fingerd.8; sourceTree = "<group>"; };
+ FDF276F80FC60FDF00D7A3C6 /* fingerd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fingerd.c; sourceTree = "<group>"; };
+ FDF276FA0FC60FDF00D7A3C6 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = gencat.1; sourceTree = "<group>"; };
+ FDF276FE0FC60FDF00D7A3C6 /* gencat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gencat.c; sourceTree = "<group>"; };
+ FDF276FF0FC60FDF00D7A3C6 /* gencat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gencat.h; sourceTree = "<group>"; };
+ FDF277000FC60FDF00D7A3C6 /* genlib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = genlib.c; sourceTree = "<group>"; };
+ FDF277050FC60FDF00D7A3C6 /* last.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = last.1; sourceTree = "<group>"; };
+ FDF277060FC60FDF00D7A3C6 /* last.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = last.c; sourceTree = "<group>"; };
+ FDF277090FC60FDF00D7A3C6 /* locale.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = locale.1; sourceTree = "<group>"; };
+ FDF2770A0FC60FDF00D7A3C6 /* locale.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = locale.cc; sourceTree = "<group>"; };
+ FDF277140FC60FDF00D7A3C6 /* localedef.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = localedef.1; sourceTree = "<group>"; };
+ FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = lsvfs.1; sourceTree = "<group>"; };
+ FDF277180FC60FDF00D7A3C6 /* lsvfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lsvfs.c; sourceTree = "<group>"; };
+ FDF2771F0FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FDF277210FC60FDF00D7A3C6 /* ldef.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ldef.h; sourceTree = "<group>"; };
+ FDF277220FC60FDF00D7A3C6 /* lex.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = lex.l; sourceTree = "<group>"; };
+ FDF277240FC60FDF00D7A3C6 /* mklocale.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mklocale.1; sourceTree = "<group>"; };
+ FDF277250FC60FDF00D7A3C6 /* runefile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = runefile.h; sourceTree = "<group>"; };
+ FDF277260FC60FDF00D7A3C6 /* yacc.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = yacc.y; sourceTree = "<group>"; };
+ FDF277280FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FDF277290FC60FDF00D7A3C6 /* fmt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fmt.c; sourceTree = "<group>"; };
+ FDF2772A0FC60FDF00D7A3C6 /* keyword.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = keyword.c; sourceTree = "<group>"; };
+ FDF2772C0FC60FDF00D7A3C6 /* nlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nlist.c; sourceTree = "<group>"; };
+ FDF2772D0FC60FDF00D7A3C6 /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; };
+ FDF2772E0FC60FDF00D7A3C6 /* ps.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ps.1; sourceTree = "<group>"; };
+ FDF2772F0FC60FDF00D7A3C6 /* ps.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ps.c; sourceTree = "<group>"; };
+ FDF277300FC60FDF00D7A3C6 /* ps.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ps.h; sourceTree = "<group>"; };
+ FDF277310FC60FDF00D7A3C6 /* tasks.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tasks.c; sourceTree = "<group>"; };
+ FDF277330FC60FDF00D7A3C6 /* cchar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cchar.c; sourceTree = "<group>"; };
+ FDF277340FC60FDF00D7A3C6 /* extern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FDF277350FC60FDF00D7A3C6 /* gfmt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gfmt.c; sourceTree = "<group>"; };
+ FDF277360FC60FDF00D7A3C6 /* key.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = key.c; sourceTree = "<group>"; };
+ FDF277380FC60FDF00D7A3C6 /* modes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = modes.c; sourceTree = "<group>"; };
+ FDF277390FC60FDF00D7A3C6 /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; };
+ FDF2773A0FC60FDF00D7A3C6 /* stty.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = stty.1; sourceTree = "<group>"; };
+ FDF2773B0FC60FDF00D7A3C6 /* stty.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stty.c; sourceTree = "<group>"; };
+ FDF2773C0FC60FDF00D7A3C6 /* stty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stty.h; sourceTree = "<group>"; };
+ FDF2773D0FC60FDF00D7A3C6 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FDF277400FC60FDF00D7A3C6 /* tabs.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = tabs.1; sourceTree = "<group>"; };
+ FDF277410FC60FDF00D7A3C6 /* tabs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tabs.c; sourceTree = "<group>"; };
+ FDF277440FC60FDF00D7A3C6 /* tty.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = tty.1; sourceTree = "<group>"; };
+ FDF277450FC60FDF00D7A3C6 /* tty.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tty.c; sourceTree = "<group>"; };
+ FDF277480FC60FDF00D7A3C6 /* whois.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = whois.1; sourceTree = "<group>"; };
+ FDF277490FC60FDF00D7A3C6 /* whois.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = whois.c; sourceTree = "<group>"; };
+ FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libtermcap.dylib; path = /usr/lib/libtermcap.dylib; sourceTree = "<absolute>"; };
+ FDF2795D0FC6272500D7A3C6 /* libl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libl.a; path = /usr/lib/libl.a; sourceTree = "<absolute>"; };
+ FDF279760FC629B100D7A3C6 /* localedef.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = localedef.pl; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FD201DB214369B0300906237 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDCD383B143BC63000AB81C6 /* libsysmon.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2765A0FC60EF600D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276620FC60EFD00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276730FC60F2100D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276790FC60F2A00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF2795E0FC6272500D7A3C6 /* libl.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2767F0FC60F3100D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2768B0FC60F3D00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276910FC60F4B00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276970FC60F5000D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276A30FC60F5E00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276AF0FC60F7600D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276B50FC60F7F00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277E80FC6144400D7A3C6 /* libtermcap.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276BB0FC60F8400D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276C10FC60F8A00D7A3C6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ FD201DAD14369AB300906237 /* pkill */ = {
+ isa = PBXGroup;
+ children = (
+ FD201DB014369AD000906237 /* pkill.c */,
+ FD201DAF14369AD000906237 /* pkill.1 */,
+ );
+ name = pkill;
+ sourceTree = "<group>";
+ };
+ FDF276410FC60E9000D7A3C6 = {
+ isa = PBXGroup;
+ children = (
+ FDF276DA0FC60FD800D7A3C6 /* Source */,
+ FDF2765D0FC60EF600D7A3C6 /* Products */,
+ FDF277E70FC6144400D7A3C6 /* libtermcap.dylib */,
+ FDF2795D0FC6272500D7A3C6 /* libl.a */,
+ FDCD383A143BC63000AB81C6 /* libsysmon.dylib */,
+ );
+ sourceTree = "<group>";
+ };
+ FDF2765D0FC60EF600D7A3C6 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FDF2765C0FC60EF600D7A3C6 /* ps */,
+ FDF276640FC60EFD00D7A3C6 /* stty */,
+ FDF276750FC60F2100D7A3C6 /* cap_mkdb */,
+ FDF2767B0FC60F2A00D7A3C6 /* colldef */,
+ FDF276810FC60F3100D7A3C6 /* finger */,
+ FDF2768D0FC60F3D00D7A3C6 /* gencat */,
+ FDF276930FC60F4B00D7A3C6 /* last */,
+ FDF276990FC60F5000D7A3C6 /* locale */,
+ FDF276A50FC60F5E00D7A3C6 /* lsvfs */,
+ FDF276B10FC60F7600D7A3C6 /* mklocale */,
+ FDF276B70FC60F7F00D7A3C6 /* tabs */,
+ FDF276BD0FC60F8400D7A3C6 /* tty */,
+ FDF276C30FC60F8A00D7A3C6 /* whois */,
+ FD201DB514369B0400906237 /* pkill */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FDF276DA0FC60FD800D7A3C6 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276DC0FC60FDF00D7A3C6 /* cap_mkdb */,
+ FDF276E00FC60FDF00D7A3C6 /* colldef */,
+ FDF276E90FC60FDF00D7A3C6 /* finger */,
+ FDF276F50FC60FDF00D7A3C6 /* fingerd */,
+ FDF276FB0FC60FDF00D7A3C6 /* gencat */,
+ FDF277040FC60FDF00D7A3C6 /* last */,
+ FDF277080FC60FDF00D7A3C6 /* locale */,
+ FDF2770C0FC60FDF00D7A3C6 /* localedef */,
+ FDF277160FC60FDF00D7A3C6 /* lsvfs */,
+ FDF2771E0FC60FDF00D7A3C6 /* mklocale */,
+ FD201DAD14369AB300906237 /* pkill */,
+ FDF277270FC60FDF00D7A3C6 /* ps */,
+ FDF277320FC60FDF00D7A3C6 /* stty */,
+ FDF2773E0FC60FDF00D7A3C6 /* tabs */,
+ FDF277420FC60FDF00D7A3C6 /* tty */,
+ FDF277460FC60FDF00D7A3C6 /* whois */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ FDF276DC0FC60FDF00D7A3C6 /* cap_mkdb */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276DE0FC60FDF00D7A3C6 /* cap_mkdb.c */,
+ FDF276DD0FC60FDF00D7A3C6 /* cap_mkdb.1 */,
+ );
+ path = cap_mkdb;
+ sourceTree = "<group>";
+ };
+ FDF276E00FC60FDF00D7A3C6 /* colldef */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276E70FC60FDF00D7A3C6 /* parse.y */,
+ FDF276E80FC60FDF00D7A3C6 /* scan.l */,
+ FDF276E20FC60FDF00D7A3C6 /* common.h */,
+ FDF276E40FC60FDF00D7A3C6 /* locale */,
+ FDF276E10FC60FDF00D7A3C6 /* colldef.1 */,
+ );
+ path = colldef;
+ sourceTree = "<group>";
+ };
+ FDF276E40FC60FDF00D7A3C6 /* locale */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276E50FC60FDF00D7A3C6 /* collate.h */,
+ );
+ path = locale;
+ sourceTree = "<group>";
+ };
+ FDF276E90FC60FDF00D7A3C6 /* finger */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276EC0FC60FDF00D7A3C6 /* finger.c */,
+ FDF276EF0FC60FDF00D7A3C6 /* lprint.c */,
+ FDF276F10FC60FDF00D7A3C6 /* net.c */,
+ FDF276F30FC60FDF00D7A3C6 /* sprint.c */,
+ FDF276F40FC60FDF00D7A3C6 /* util.c */,
+ FDF276EA0FC60FDF00D7A3C6 /* extern.h */,
+ FDF276EE0FC60FDF00D7A3C6 /* finger.h */,
+ FDF276F20FC60FDF00D7A3C6 /* pathnames.h */,
+ FDF276EB0FC60FDF00D7A3C6 /* finger.1 */,
+ FDF276ED0FC60FDF00D7A3C6 /* finger.conf.5 */,
+ );
+ path = finger;
+ sourceTree = "<group>";
+ };
+ FDF276F50FC60FDF00D7A3C6 /* fingerd */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276F80FC60FDF00D7A3C6 /* fingerd.c */,
+ FDF276FA0FC60FDF00D7A3C6 /* pathnames.h */,
+ FDF276F70FC60FDF00D7A3C6 /* fingerd.8 */,
+ FDF276F60FC60FDF00D7A3C6 /* finger.plist */,
+ );
+ path = fingerd;
+ sourceTree = "<group>";
+ };
+ FDF276FB0FC60FDF00D7A3C6 /* gencat */ = {
+ isa = PBXGroup;
+ children = (
+ FDF276FE0FC60FDF00D7A3C6 /* gencat.c */,
+ FDF277000FC60FDF00D7A3C6 /* genlib.c */,
+ FDF276FF0FC60FDF00D7A3C6 /* gencat.h */,
+ FDF276FD0FC60FDF00D7A3C6 /* gencat.1 */,
+ );
+ path = gencat;
+ sourceTree = "<group>";
+ };
+ FDF277040FC60FDF00D7A3C6 /* last */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277050FC60FDF00D7A3C6 /* last.1 */,
+ FDF277060FC60FDF00D7A3C6 /* last.c */,
+ );
+ path = last;
+ sourceTree = "<group>";
+ };
+ FDF277080FC60FDF00D7A3C6 /* locale */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277090FC60FDF00D7A3C6 /* locale.1 */,
+ FDF2770A0FC60FDF00D7A3C6 /* locale.cc */,
+ );
+ path = locale;
+ sourceTree = "<group>";
+ };
+ FDF2770C0FC60FDF00D7A3C6 /* localedef */ = {
+ isa = PBXGroup;
+ children = (
+ FDF279760FC629B100D7A3C6 /* localedef.pl */,
+ FDF277140FC60FDF00D7A3C6 /* localedef.1 */,
+ );
+ path = localedef;
+ sourceTree = "<group>";
+ };
+ FDF277160FC60FDF00D7A3C6 /* lsvfs */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277170FC60FDF00D7A3C6 /* lsvfs.1 */,
+ FDF277180FC60FDF00D7A3C6 /* lsvfs.c */,
+ );
+ path = lsvfs;
+ sourceTree = "<group>";
+ };
+ FDF2771E0FC60FDF00D7A3C6 /* mklocale */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277220FC60FDF00D7A3C6 /* lex.l */,
+ FDF277260FC60FDF00D7A3C6 /* yacc.y */,
+ FDF2771F0FC60FDF00D7A3C6 /* extern.h */,
+ FDF277210FC60FDF00D7A3C6 /* ldef.h */,
+ FDF277250FC60FDF00D7A3C6 /* runefile.h */,
+ FDF277240FC60FDF00D7A3C6 /* mklocale.1 */,
+ );
+ path = mklocale;
+ sourceTree = "<group>";
+ };
+ FDF277270FC60FDF00D7A3C6 /* ps */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277290FC60FDF00D7A3C6 /* fmt.c */,
+ FDF2772A0FC60FDF00D7A3C6 /* keyword.c */,
+ FDF2772C0FC60FDF00D7A3C6 /* nlist.c */,
+ FDF2772D0FC60FDF00D7A3C6 /* print.c */,
+ FDF2772F0FC60FDF00D7A3C6 /* ps.c */,
+ FDF277310FC60FDF00D7A3C6 /* tasks.c */,
+ FDF277300FC60FDF00D7A3C6 /* ps.h */,
+ FDF277280FC60FDF00D7A3C6 /* extern.h */,
+ FDF2772E0FC60FDF00D7A3C6 /* ps.1 */,
+ );
+ path = ps;
+ sourceTree = "<group>";
+ };
+ FDF277320FC60FDF00D7A3C6 /* stty */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277330FC60FDF00D7A3C6 /* cchar.c */,
+ FDF277350FC60FDF00D7A3C6 /* gfmt.c */,
+ FDF277360FC60FDF00D7A3C6 /* key.c */,
+ FDF277380FC60FDF00D7A3C6 /* modes.c */,
+ FDF277390FC60FDF00D7A3C6 /* print.c */,
+ FDF2773B0FC60FDF00D7A3C6 /* stty.c */,
+ FDF2773D0FC60FDF00D7A3C6 /* util.c */,
+ FDF277340FC60FDF00D7A3C6 /* extern.h */,
+ FDF2773C0FC60FDF00D7A3C6 /* stty.h */,
+ FDF2773A0FC60FDF00D7A3C6 /* stty.1 */,
+ );
+ path = stty;
+ sourceTree = "<group>";
+ };
+ FDF2773E0FC60FDF00D7A3C6 /* tabs */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277400FC60FDF00D7A3C6 /* tabs.1 */,
+ FDF277410FC60FDF00D7A3C6 /* tabs.c */,
+ );
+ path = tabs;
+ sourceTree = "<group>";
+ };
+ FDF277420FC60FDF00D7A3C6 /* tty */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277440FC60FDF00D7A3C6 /* tty.1 */,
+ FDF277450FC60FDF00D7A3C6 /* tty.c */,
+ );
+ path = tty;
+ sourceTree = "<group>";
+ };
+ FDF277460FC60FDF00D7A3C6 /* whois */ = {
+ isa = PBXGroup;
+ children = (
+ FDF277480FC60FDF00D7A3C6 /* whois.1 */,
+ FDF277490FC60FDF00D7A3C6 /* whois.c */,
+ );
+ path = whois;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ FD201DB414369B0300906237 /* pkill */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD201DBC14369B0400906237 /* Build configuration list for PBXNativeTarget "pkill" */;
+ buildPhases = (
+ FD201DB114369B0300906237 /* Sources */,
+ FD201DB214369B0300906237 /* Frameworks */,
+ FD201DB314369B0300906237 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pkill;
+ productName = pkill;
+ productReference = FD201DB514369B0400906237 /* pkill */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF2765B0FC60EF600D7A3C6 /* ps */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276600FC60EF700D7A3C6 /* Build configuration list for PBXNativeTarget "ps" */;
+ buildPhases = (
+ FDF276590FC60EF600D7A3C6 /* Sources */,
+ FDF2765A0FC60EF600D7A3C6 /* Frameworks */,
+ FDF278300FC6160800D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ps;
+ productName = ps;
+ productReference = FDF2765C0FC60EF600D7A3C6 /* ps */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276630FC60EFD00D7A3C6 /* stty */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276690FC60EFF00D7A3C6 /* Build configuration list for PBXNativeTarget "stty" */;
+ buildPhases = (
+ FDF276610FC60EFD00D7A3C6 /* Sources */,
+ FDF276620FC60EFD00D7A3C6 /* Frameworks */,
+ FDF278030FC614B900D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = stty;
+ productName = stty;
+ productReference = FDF276640FC60EFD00D7A3C6 /* stty */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276740FC60F2100D7A3C6 /* cap_mkdb */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276C80FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "cap_mkdb" */;
+ buildPhases = (
+ FDF276720FC60F2100D7A3C6 /* Sources */,
+ FDF276730FC60F2100D7A3C6 /* Frameworks */,
+ FDF277780FC610A400D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cap_mkdb;
+ productName = cap_mkdb;
+ productReference = FDF276750FC60F2100D7A3C6 /* cap_mkdb */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF2767A0FC60F2A00D7A3C6 /* colldef */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276C90FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "colldef" */;
+ buildPhases = (
+ FDF276780FC60F2A00D7A3C6 /* Sources */,
+ FDF276790FC60F2A00D7A3C6 /* Frameworks */,
+ FDF279930FC62B0B00D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = colldef;
+ productName = colldef;
+ productReference = FDF2767B0FC60F2A00D7A3C6 /* colldef */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276800FC60F3100D7A3C6 /* finger */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276CA0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "finger" */;
+ buildPhases = (
+ FDF2767E0FC60F3100D7A3C6 /* Sources */,
+ FDF2767F0FC60F3100D7A3C6 /* Frameworks */,
+ FDF277A10FC611D800D7A3C6 /* Install man1 */,
+ FDF277A20FC611D800D7A3C6 /* Install man5 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = finger;
+ productName = finger;
+ productReference = FDF276810FC60F3100D7A3C6 /* finger */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF2768C0FC60F3D00D7A3C6 /* gencat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276CC0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "gencat" */;
+ buildPhases = (
+ FDF2768A0FC60F3D00D7A3C6 /* Sources */,
+ FDF2768B0FC60F3D00D7A3C6 /* Frameworks */,
+ FDF279300FC625CB00D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = gencat;
+ productName = gencat;
+ productReference = FDF2768D0FC60F3D00D7A3C6 /* gencat */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276920FC60F4B00D7A3C6 /* last */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276CD0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "last" */;
+ buildPhases = (
+ FDF276900FC60F4B00D7A3C6 /* Sources */,
+ FDF276910FC60F4B00D7A3C6 /* Frameworks */,
+ FDF278E70FC620B600D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = last;
+ productName = last;
+ productReference = FDF276930FC60F4B00D7A3C6 /* last */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276980FC60F5000D7A3C6 /* locale */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276CE0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "locale" */;
+ buildPhases = (
+ FDF276960FC60F5000D7A3C6 /* Sources */,
+ FDF276970FC60F5000D7A3C6 /* Frameworks */,
+ FDF278E80FC620B600D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = locale;
+ productName = locale;
+ productReference = FDF276990FC60F5000D7A3C6 /* locale */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276A40FC60F5E00D7A3C6 /* lsvfs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D00FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "lsvfs" */;
+ buildPhases = (
+ FDF276A20FC60F5E00D7A3C6 /* Sources */,
+ FDF276A30FC60F5E00D7A3C6 /* Frameworks */,
+ FDF278D50FC6201600D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lsvfs;
+ productName = lsvfs;
+ productReference = FDF276A50FC60F5E00D7A3C6 /* lsvfs */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276B00FC60F7600D7A3C6 /* mklocale */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D20FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "mklocale" */;
+ buildPhases = (
+ FDF276AE0FC60F7600D7A3C6 /* Sources */,
+ FDF276AF0FC60F7600D7A3C6 /* Frameworks */,
+ FDF278A40FC61D9600D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mklocale;
+ productName = mklocale;
+ productReference = FDF276B10FC60F7600D7A3C6 /* mklocale */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276B60FC60F7F00D7A3C6 /* tabs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D30FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tabs" */;
+ buildPhases = (
+ FDF276B40FC60F7F00D7A3C6 /* Sources */,
+ FDF276B50FC60F7F00D7A3C6 /* Frameworks */,
+ FDF277E60FC6143000D7A3C6 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tabs;
+ productName = tabs;
+ productReference = FDF276B70FC60F7F00D7A3C6 /* tabs */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276BC0FC60F8400D7A3C6 /* tty */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D40FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tty" */;
+ buildPhases = (
+ FDF276BA0FC60F8400D7A3C6 /* Sources */,
+ FDF276BB0FC60F8400D7A3C6 /* Frameworks */,
+ FDF277C60FC6135D00D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tty;
+ productName = tty;
+ productReference = FDF276BD0FC60F8400D7A3C6 /* tty */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDF276C20FC60F8A00D7A3C6 /* whois */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDF276D50FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "whois" */;
+ buildPhases = (
+ FDF276C00FC60F8A00D7A3C6 /* Sources */,
+ FDF276C10FC60F8A00D7A3C6 /* Frameworks */,
+ FDF277C30FC612D900D7A3C6 /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = whois;
+ productName = whois;
+ productReference = FDF276C30FC60F8A00D7A3C6 /* whois */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FDF276430FC60E9000D7A3C6 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0820;
+ };
+ buildConfigurationList = FDF276460FC60E9000D7A3C6 /* Build configuration list for PBXProject "adv_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = FDF276410FC60E9000D7A3C6;
+ productRefGroup = FDF2765D0FC60EF600D7A3C6 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FDF276500FC60EDA00D7A3C6 /* Desktop */,
+ FDF2764E0FC60ECD00D7A3C6 /* Embedded */,
+ FDF276740FC60F2100D7A3C6 /* cap_mkdb */,
+ FDF2767A0FC60F2A00D7A3C6 /* colldef */,
+ FDF276800FC60F3100D7A3C6 /* finger */,
+ FDF2768C0FC60F3D00D7A3C6 /* gencat */,
+ FDF276920FC60F4B00D7A3C6 /* last */,
+ FDF276980FC60F5000D7A3C6 /* locale */,
+ FD0D7F98108FE550004F2A1C /* localedef */,
+ FDF276A40FC60F5E00D7A3C6 /* lsvfs */,
+ FDF276B00FC60F7600D7A3C6 /* mklocale */,
+ FD201DCD14369D0C00906237 /* pgrep */,
+ FD201DB414369B0300906237 /* pkill */,
+ FDF2765B0FC60EF600D7A3C6 /* ps */,
+ FDF276630FC60EFD00D7A3C6 /* stty */,
+ FDF276B60FC60F7F00D7A3C6 /* tabs */,
+ FDF276BC0FC60F8400D7A3C6 /* tty */,
+ FDF276C20FC60F8A00D7A3C6 /* whois */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FD0D7F97108FE550004F2A1C /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -ex\n/usr/bin/install -m ${INSTALL_MODE_FLAG} ${SRCROOT}/localedef/localedef.pl ${INSTALL_DIR}/localedef\n${CHMOD} +x ${INSTALL_DIR}/localedef";
+ };
+ FD201DD014369D1000906237 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". ${SRCROOT}/xcodescripts/variant_links.sh";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FD201DB114369B0300906237 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD201DC214369B4200906237 /* pkill.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276590FC60EF600D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278060FC6151E00D7A3C6 /* fmt.c in Sources */,
+ FDF278070FC6151E00D7A3C6 /* keyword.c in Sources */,
+ FDF278080FC6151E00D7A3C6 /* nlist.c in Sources */,
+ FDF278090FC6151E00D7A3C6 /* print.c in Sources */,
+ FDF2780A0FC6151E00D7A3C6 /* ps.c in Sources */,
+ FDF2780B0FC6151E00D7A3C6 /* tasks.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276610FC60EFD00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277EE0FC6148500D7A3C6 /* cchar.c in Sources */,
+ FDF277EF0FC6148500D7A3C6 /* gfmt.c in Sources */,
+ FDF277F00FC6148500D7A3C6 /* key.c in Sources */,
+ FDF277F10FC6148500D7A3C6 /* modes.c in Sources */,
+ FDF277F20FC6148500D7A3C6 /* print.c in Sources */,
+ FDF277F30FC6148500D7A3C6 /* stty.c in Sources */,
+ FDF277F40FC6148500D7A3C6 /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276720FC60F2100D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF2774B0FC6100400D7A3C6 /* cap_mkdb.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276780FC60F2A00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF279390FC6263E00D7A3C6 /* parse.y in Sources */,
+ FDF2793A0FC6263E00D7A3C6 /* scan.l in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2767E0FC60F3100D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277790FC610EC00D7A3C6 /* finger.c in Sources */,
+ FDF2777A0FC610EC00D7A3C6 /* lprint.c in Sources */,
+ FDF2777B0FC610EC00D7A3C6 /* net.c in Sources */,
+ FDF2777C0FC610EC00D7A3C6 /* sprint.c in Sources */,
+ FDF2777D0FC610EC00D7A3C6 /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF2768A0FC60F3D00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278F50FC623D300D7A3C6 /* gencat.c in Sources */,
+ FDF278F60FC623D300D7A3C6 /* genlib.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276900FC60F4B00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278DB0FC6208600D7A3C6 /* last.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276960FC60F5000D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278D60FC6204E00D7A3C6 /* locale.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276A20FC60F5E00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278C60FC61FDF00D7A3C6 /* lsvfs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276AE0FC60F7600D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF278380FC6167800D7A3C6 /* yacc.y in Sources */,
+ FDF278370FC6167800D7A3C6 /* lex.l in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276B40FC60F7F00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277D70FC613F500D7A3C6 /* tabs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276BA0FC60F8400D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277C40FC6133400D7A3C6 /* tty.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDF276C00FC60F8A00D7A3C6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF277BE0FC612B000D7A3C6 /* whois.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ FD0D7FA9108FE5C3004F2A1C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD0D7F98108FE550004F2A1C /* localedef */;
+ targetProxy = FD0D7FA8108FE5C3004F2A1C /* PBXContainerItemProxy */;
+ };
+ FD201DBF14369B1700906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DB414369B0300906237 /* pkill */;
+ targetProxy = FD201DBE14369B1700906237 /* PBXContainerItemProxy */;
+ };
+ FD201DC114369B1D00906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DB414369B0300906237 /* pkill */;
+ targetProxy = FD201DC014369B1D00906237 /* PBXContainerItemProxy */;
+ };
+ FD201DD214369D5C00906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DB414369B0300906237 /* pkill */;
+ targetProxy = FD201DD114369D5C00906237 /* PBXContainerItemProxy */;
+ };
+ FD201DD414369D6300906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DCD14369D0C00906237 /* pgrep */;
+ targetProxy = FD201DD314369D6300906237 /* PBXContainerItemProxy */;
+ };
+ FD201DD614369D6700906237 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD201DCD14369D0C00906237 /* pgrep */;
+ targetProxy = FD201DD514369D6700906237 /* PBXContainerItemProxy */;
+ };
+ FDF2766B0FC60F0D00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276630FC60EFD00D7A3C6 /* stty */;
+ targetProxy = FDF2766A0FC60F0D00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2766D0FC60F0D00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF2765B0FC60EF600D7A3C6 /* ps */;
+ targetProxy = FDF2766C0FC60F0D00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2766F0FC60F0F00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF2765B0FC60EF600D7A3C6 /* ps */;
+ targetProxy = FDF2766E0FC60F0F00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF276710FC60F1300D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276630FC60EFD00D7A3C6 /* stty */;
+ targetProxy = FDF276700FC60F1300D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277530FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276B00FC60F7600D7A3C6 /* mklocale */;
+ targetProxy = FDF277520FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277570FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276A40FC60F5E00D7A3C6 /* lsvfs */;
+ targetProxy = FDF277560FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2775B0FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276980FC60F5000D7A3C6 /* locale */;
+ targetProxy = FDF2775A0FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2775D0FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276920FC60F4B00D7A3C6 /* last */;
+ targetProxy = FDF2775C0FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2775F0FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF2768C0FC60F3D00D7A3C6 /* gencat */;
+ targetProxy = FDF2775E0FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277630FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276800FC60F3100D7A3C6 /* finger */;
+ targetProxy = FDF277620FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277650FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF2767A0FC60F2A00D7A3C6 /* colldef */;
+ targetProxy = FDF277640FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277670FC6102600D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276740FC60F2100D7A3C6 /* cap_mkdb */;
+ targetProxy = FDF277660FC6102600D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF277690FC6102B00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276C20FC60F8A00D7A3C6 /* whois */;
+ targetProxy = FDF277680FC6102B00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2776B0FC6102B00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276BC0FC60F8400D7A3C6 /* tty */;
+ targetProxy = FDF2776A0FC6102B00D7A3C6 /* PBXContainerItemProxy */;
+ };
+ FDF2776D0FC6102B00D7A3C6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDF276B60FC60F7F00D7A3C6 /* tabs */;
+ targetProxy = FDF2776C0FC6102B00D7A3C6 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ FD0D7F99108FE550004F2A1C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = localedef;
+ };
+ name = Release;
+ };
+ FD201DBD14369B0400906237 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = pkill/entitlements.plist;
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FD201DCF14369D0C00906237 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FDF276450FC60E9000D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
+ GCC_WARN_MISSING_PARENTHESES = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_VALUE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = macosx.internal;
+ USE_HEADERMAP = NO;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = __;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ FDF2764F0FC60ECD00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = Embedded;
+ };
+ name = Release;
+ };
+ FDF276510FC60EDA00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = Desktop;
+ };
+ name = Release;
+ };
+ FDF2765F0FC60EF700D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = ps/entitlements.plist;
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ "INSTALL_MODE_FLAG[sdk=macosx*]" = "u+sw,go-w,a+rX";
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = ps;
+ WARNING_CFLAGS = "-Wno-#warnings";
+ };
+ name = Release;
+ };
+ FDF276660FC60EFD00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = stty;
+ };
+ name = Release;
+ };
+ FDF276770FC60F2100D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = cap_mkdb;
+ };
+ name = Release;
+ };
+ FDF2767D0FC60F2A00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ COLLATE_DEBUG,
+ YY_NO_UNPUT,
+ );
+ GCC_WARN_UNUSED_FUNCTION = NO;
+ GCC_WARN_UNUSED_VARIABLE = NO;
+ INSTALL_PATH = /usr/bin;
+ LEXFLAGS = "-8";
+ LEX_CASE_INSENSITIVE_SCANNER = YES;
+ PRODUCT_NAME = colldef;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/colldef $(SRCROOT)/colldef/locale";
+ };
+ name = Release;
+ };
+ FDF276830FC60F3100D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = finger;
+ };
+ name = Release;
+ };
+ FDF2768F0FC60F3E00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = gencat;
+ };
+ name = Release;
+ };
+ FDF276950FC60F4C00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = last;
+ };
+ name = Release;
+ };
+ FDF2769B0FC60F5100D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = locale;
+ };
+ name = Release;
+ };
+ FDF276A70FC60F5F00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = lsvfs;
+ };
+ name = Release;
+ };
+ FDF276B30FC60F7700D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = mklocale;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/mklocale";
+ };
+ name = Release;
+ };
+ FDF276B90FC60F8000D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = tabs;
+ };
+ name = Release;
+ };
+ FDF276BF0FC60F8500D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = tty;
+ };
+ name = Release;
+ };
+ FDF276C50FC60F8A00D7A3C6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = whois;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ FD0D7FA2108FE56E004F2A1C /* Build configuration list for PBXAggregateTarget "localedef" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD0D7F99108FE550004F2A1C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD201DBC14369B0400906237 /* Build configuration list for PBXNativeTarget "pkill" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD201DBD14369B0400906237 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD201DCE14369D0C00906237 /* Build configuration list for PBXAggregateTarget "pgrep" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD201DCF14369D0C00906237 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276460FC60E9000D7A3C6 /* Build configuration list for PBXProject "adv_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276450FC60E9000D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276570FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Desktop" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276510FC60EDA00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276580FC60EE600D7A3C6 /* Build configuration list for PBXAggregateTarget "Embedded" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2764F0FC60ECD00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276600FC60EF700D7A3C6 /* Build configuration list for PBXNativeTarget "ps" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2765F0FC60EF700D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276690FC60EFF00D7A3C6 /* Build configuration list for PBXNativeTarget "stty" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276660FC60EFD00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276C80FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "cap_mkdb" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276770FC60F2100D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276C90FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "colldef" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2767D0FC60F2A00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276CA0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "finger" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276830FC60F3100D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276CC0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "gencat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2768F0FC60F3E00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276CD0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "last" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276950FC60F4C00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276CE0FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "locale" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF2769B0FC60F5100D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D00FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "lsvfs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276A70FC60F5F00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D20FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "mklocale" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276B30FC60F7700D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D30FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tabs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276B90FC60F8000D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D40FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "tty" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276BF0FC60F8500D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDF276D50FC60F9700D7A3C6 /* Build configuration list for PBXNativeTarget "whois" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDF276C50FC60F8A00D7A3C6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FDF276430FC60E9000D7A3C6 /* Project object */;
+}
diff --git a/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/adv_cmds/adv_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/adv_cmds/cap_mkdb/cap_mkdb.1 b/adv_cmds/cap_mkdb/cap_mkdb.1
new file mode 100644
index 0000000..5bc4674
--- /dev/null
+++ b/adv_cmds/cap_mkdb/cap_mkdb.1
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)cap_mkdb.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd "June 6, 1993"
+.Dt CAP_MKDB 1
+.Os
+.Sh NAME
+.Nm cap_mkdb
+.Nd create capability database
+.Pp
+.Sh SYNOPSIS
+.Nm cap_mkdb
+.Op Fl v
+.Op Fl f Ar outfile
+.Ar file1
+.Op Ar file2 ...
+.Pp
+.Sh DESCRIPTION
+.Nm Cap_mkdb
+builds a hashed database out of the
+.Xr getcap 3
+logical database constructed by the concatenation of the specified
+files .
+.Pp
+The database is named by the basename of the first file argument and
+the string
+.Dq .db .
+The
+.Xr getcap 3
+routines can access the database in this form much more quickly
+than they can the original text file(s).
+.Pp
+The ``tc'' capabilities of the records are expanded before the
+record is stored into the database.
+.Pp
+The options as as follows:
+.Bl -tag -width XXXXXX
+.It Fl f Ar outfile
+Specify a different database basename.
+.It Fl v
+Print out the number of capability records in the database.
+.El
+.Pp
+.Sh FORMAT
+Each record is stored in the database using two different types of keys.
+.Pp
+The first type is a key which consists of the first capability of
+the record (not including the trailing colon (``:'')) with a data
+field consisting of a special byte followed by the rest of the record.
+The special byte is either a 0 or 1, where a 0 means that the record
+is okay, and a 1 means that there was a ``tc'' capability in the record
+that couldn't be expanded.
+.Pp
+The second type is a key which consists of one of the names from the
+first capability of the record with a data field consisting a special
+byte followed by the the first capability of the record.
+The special byte is a 2.
+.Pp
+In normal operation names are looked up in the database, resulting
+in a key/data pair of the second type.
+The data field of this key/data pair is used to look up a key/data
+pair of the first type which has the real data associated with the
+name.
+.Sh RETURN VALUE
+The
+.Nm cap_mkdb
+utility exits 0 on success and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr dbopen 3 ,
+.Xr getcap 3 ,
+.Xr termcap 5
diff --git a/adv_cmds/cap_mkdb/cap_mkdb.c b/adv_cmds/cap_mkdb/cap_mkdb.c
new file mode 100644
index 0000000..9c26d59
--- /dev/null
+++ b/adv_cmds/cap_mkdb/cap_mkdb.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
+ *
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * The NEXTSTEP Software License Agreement specifies the terms
+ * and conditions for redistribution.
+ *
+ * @(#)cap_mkdb.c 8.2 (Berkeley) 4/27/95
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void db_build __P((char **));
+void dounlink __P((void));
+void usage __P((void));
+
+DB *capdbp;
+int verbose;
+char *capdb, *capname, buf[8 * 1024];
+
+HASHINFO openinfo = {
+ 4096, /* bsize */
+ 16, /* ffactor */
+ 256, /* nelem */
+ 2048 * 1024, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+
+/*
+ * Mkcapdb creates a capability hash database for quick retrieval of capability
+ * records. The database contains 2 types of entries: records and references
+ * marked by the first byte in the data. A record entry contains the actual
+ * capability record whereas a reference contains the name (key) under which
+ * the correct record is stored.
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+
+ capname = NULL;
+ while ((c = getopt(argc, argv, "f:v")) != EOF) {
+ switch(c) {
+ case 'f':
+ capname = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv == NULL)
+ usage();
+
+ /*
+ * The database file is the first argument if no name is specified.
+ * Make arrangements to unlink it if exit badly.
+ */
+ (void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
+ if ((capname = strdup(buf)) == NULL)
+ err(1, "");
+ if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,
+ DEFFILEMODE, DB_HASH, &openinfo)) == NULL)
+ err(1, "%s", buf);
+
+ if (atexit(dounlink))
+ err(1, "atexit");
+
+ db_build(argv);
+
+ if (capdbp->close(capdbp) < 0)
+ err(1, "%s", capname);
+ capname = NULL;
+ exit(0);
+}
+
+void
+dounlink()
+{
+ if (capname != NULL)
+ (void)unlink(capname);
+}
+
+/*
+ * Any changes to these definitions should be made also in the getcap(3)
+ * library routines.
+ */
+#define RECOK (char)0
+#define TCERR (char)1
+#define SHADOW (char)2
+
+/*
+ * Db_build() builds the name and capabilty databases according to the
+ * details above.
+ */
+void
+db_build(ifiles)
+ char **ifiles;
+{
+ DBT key, data;
+ recno_t reccnt;
+ size_t len, bplen;
+ int st;
+ char *bp, *p, *t;
+
+ data.data = NULL;
+ key.data = NULL;
+ for (reccnt = 0, bplen = 0; (st = cgetnext(&bp, ifiles)) > 0;) {
+
+ /*
+ * Allocate enough memory to store record, terminating
+ * NULL and one extra byte.
+ */
+ len = strlen(bp);
+ if (bplen <= len + 2) {
+ bplen += MAX(256, len + 2);
+ if ((data.data = realloc(data.data, bplen)) == NULL)
+ err(1, "");
+ }
+
+ /* Find the end of the name field. */
+ if ((p = strchr(bp, ':')) == NULL) {
+ warnx("no name field: %.*s", MIN(len, 20), bp);
+ continue;
+ }
+
+ /* First byte of stored record indicates status. */
+ switch(st) {
+ case 1:
+ ((char *)(data.data))[0] = RECOK;
+ break;
+ case 2:
+ ((char *)(data.data))[0] = TCERR;
+ warnx("Record not tc expanded: %.*s", p - bp, bp);
+ break;
+ }
+
+ /* Create the stored record. */
+ memmove(&((u_char *)(data.data))[1], bp, len + 1);
+ data.size = len + 2;
+
+ /* Store the record under the name field. */
+ key.data = bp;
+ key.size = p - bp;
+
+ switch(capdbp->put(capdbp, &key, &data, R_NOOVERWRITE)) {
+ case -1:
+ err(1, "put");
+ /* NOTREACHED */
+ case 1:
+ warnx("ignored duplicate: %.*s",
+ key.size, (char *)key.data);
+ continue;
+ }
+ ++reccnt;
+
+ /* If only one name, ignore the rest. */
+ if ((p = strchr(bp, '|')) == NULL)
+ continue;
+
+ /* The rest of the names reference the entire name. */
+ ((char *)(data.data))[0] = SHADOW;
+ memmove(&((u_char *)(data.data))[1], key.data, key.size);
+ data.size = key.size + 1;
+
+ /* Store references for other names. */
+ for (p = t = bp;; ++p) {
+ if (p > t && (*p == ':' || *p == '|')) {
+ key.size = p - t;
+ key.data = t;
+ switch(capdbp->put(capdbp,
+ &key, &data, R_NOOVERWRITE)) {
+ case -1:
+ err(1, "put");
+ /* NOTREACHED */
+ case 1:
+ warnx("ignored duplicate: %.*s",
+ key.size, (char *)key.data);
+ }
+ t = p + 1;
+ }
+ if (*p == ':')
+ break;
+ }
+ }
+
+ switch(st) {
+ case -1:
+ err(1, "file argument");
+ /* NOTREACHED */
+ case -2:
+ errx(1, "potential reference loop detected");
+ /* NOTREACHED */
+ }
+
+ if (verbose)
+ (void)printf("cap_mkdb: %d capability records\n", reccnt);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: cap_mkdb [-v] [-f outfile] file1 [file2 ...]\n");
+ exit(1);
+}
diff --git a/adv_cmds/colldef/colldef.1 b/adv_cmds/colldef/colldef.1
new file mode 100644
index 0000000..f4f875b
--- /dev/null
+++ b/adv_cmds/colldef/colldef.1
@@ -0,0 +1,274 @@
+.\" Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+.\" at Electronni Visti IA, Kiev, Ukraine.
+.\" 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 ``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.
+.\"
+.\" $FreeBSD: src/usr.bin/colldef/colldef.1,v 1.21 2004/05/19 09:45:46 ru Exp $
+.\"
+.Dd January 27, 1995
+.Dt COLLDEF 1
+.Os
+.Sh NAME
+.Nm colldef
+.Nd convert collation sequence source definition
+.Sh SYNOPSIS
+.Nm
+.Op Fl I Ar map_dir
+.Op Fl o Ar out_file
+.Op Ar filename
+.Sh DESCRIPTION
+The
+.Nm
+utility converts a collation sequence source definition
+into a format usable by the
+.Fn strxfrm
+and
+.Fn strcoll
+functions.
+It is used to define the many ways in which
+strings can be ordered and collated.
+The
+.Fn strxfrm
+function transforms
+its first argument and places the result in its second
+argument.
+The transformed string is such that it can be
+correctly ordered with other transformed strings by using
+.Fn strcmp ,
+.Fn strncmp ,
+or
+.Fn memcmp .
+The
+.Fn strcoll
+function transforms its arguments and does a
+comparison.
+.Pp
+The
+.Nm
+utility reads the collation sequence source definition
+from the standard input and stores the converted definition in filename.
+The output file produced contains the
+database with collating sequence information in a form
+usable by system commands and routines.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl I Ar map_dir
+Set directory name where
+.Ar charmap
+files can be found, current directory by default.
+.It Fl o Ar out_file
+Set output file name,
+.Ar LC_COLLATE
+by default.
+.El
+.Pp
+The collation sequence definition specifies a set of collating elements and
+the rules defining how strings containing these should be ordered.
+This is most useful for different language definitions.
+.Pp
+The specification file can consist of three statements:
+.Ar charmap ,
+.Ar substitute
+and
+.Ar order .
+.Pp
+Of these, only the
+.Ar order
+statement is required.
+When
+.Ar charmap
+or
+.Ar substitute
+is
+supplied, these statements must be ordered as above.
+Any
+statements after the order statement are ignored.
+.Pp
+Lines in the specification file beginning with a
+.Ql #
+are
+treated as comments and are ignored.
+Blank lines are also
+ignored.
+.Pp
+.Dl "charmap charmapfile"
+.Pp
+.Ar Charmap
+defines where a mapping of the character
+and collating element symbols to the actual
+character encoding can be found.
+.Pp
+The format of
+.Ar charmapfile
+is shown below.
+Symbol
+names are separated from their values by TAB or
+SPACE characters.
+Symbol-value can be specified in
+a hexadecimal (\ex\fI??\fR) or octal (\e\fI???\fR)
+representation, and can be only one character in length.
+.Pp
+.Bd -literal -offset indent
+symbol-name1 symbol-value1
+symbol-name2 symbol-value2
+\&...
+.Ed
+.Pp
+Symbol names cannot be specified in
+.Ar substitute
+fields.
+.Pp
+The
+.Ar charmap
+statement is optional.
+.Pp
+.Bd -literal -offset indent
+substitute "symbol" with "repl_string"
+.Ed
+.Pp
+The
+.Ar substitute
+statement substitutes the character
+.Ar symbol
+with the string
+.Ar repl_string .
+Symbol names cannot be specified in
+.Ar repl_string
+field.
+The
+.Ar substitute
+statement is optional.
+.Pp
+.Dl "order order_list"
+.Pp
+.Ar Order_list
+is a list of symbols, separated by semi colons, that defines the
+collating sequence.
+The
+special symbol
+.Ar ...
+specifies, in a short-hand
+form, symbols that are sequential in machine code
+order.
+.Pp
+An order list element
+can be represented in any one of the following
+ways:
+.Bl -bullet
+.It
+The symbol itself (for example,
+.Ar a
+for the lower-case letter
+.Ar a ) .
+.It
+The symbol in octal representation (for example,
+.Ar \e141
+for the letter
+.Ar a ) .
+.It
+The symbol in hexadecimal representation (for example,
+.Ar \ex61
+for the letter
+.Ar a ) .
+.It
+The symbol name as defined in the
+.Ar charmap
+file (for example,
+.Ar <letterA>
+for
+.Ar letterA \e023
+record in
+.Ar charmapfile ) .
+If character map name have
+.Ar >
+character, it must be escaped as
+.Ar /> ,
+single
+.Ar /
+must be escaped as
+.Ar // .
+.It
+Symbols
+.Ar \ea ,
+.Ar \eb ,
+.Ar \ef ,
+.Ar \en ,
+.Ar \er ,
+.Ar \ev
+are permitted in its usual C-language meaning.
+.It
+The symbol chain (for example:
+.Ar abc ,
+.Ar <letterA><letterB>c ,
+.Ar \exf1b\exf2 )
+.It
+The symbol range (for example,
+.Ar a;...;z ) .
+.It
+Comma-separated symbols, ranges and chains enclosed in parenthesis (for example
+.Ar \&(
+.Ar sym1 ,
+.Ar sym2 ,
+.Ar ...
+.Ar \&) )
+are assigned the
+same primary ordering but different secondary
+ordering.
+.It
+Comma-separated symbols, ranges and chains enclosed in curly brackets (for example
+.Ar \&{
+.Ar sym1 ,
+.Ar sym2 ,
+.Ar ...
+.Ar \&} )
+are assigned the same primary ordering only.
+.El
+.Pp
+The backslash character
+.Ar \e
+is used for continuation.
+In this case, no characters are permitted
+after the backslash character.
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exits with the following values:
+.Bl -tag -width indent
+.It Li 0
+No errors were found and the output was successfully created.
+.It Li !=0
+Errors were found.
+.El
+.Sh FILES
+.Bl -tag -width indent
+.It Pa /usr/share/locale/ Ns Ao Ar language Ac Ns Pa /LC_COLLATE
+The standard shared location for collation orders
+under the locale
+.Aq Ar language .
+.El
+.Sh SEE ALSO
+.Xr mklocale 1 ,
+.Xr setlocale 3 ,
+.Xr strcoll 3 ,
+.Xr strxfrm 3
diff --git a/adv_cmds/colldef/common.h b/adv_cmds/colldef/common.h
new file mode 100644
index 0000000..b59c125
--- /dev/null
+++ b/adv_cmds/colldef/common.h
@@ -0,0 +1,36 @@
+/*
+ * $FreeBSD: src/usr.bin/colldef/common.h,v 1.2 2001/11/28 09:50:24 ache Exp $
+ */
+
+#include <sys/types.h>
+#include <db.h>
+#include <fcntl.h>
+
+#define CHARMAP_SYMBOL_LEN 64
+#define BUFSIZE 80
+
+#define NOTEXISTS 0
+#define EXISTS 1
+
+#define SYMBOL_CHAR 0
+#define SYMBOL_CHAIN 1
+#define SYMBOL_SYMBOL 2
+#define SYMBOL_STRING 3
+#define SYMBOL_IGNORE 4
+#define SYMBOL_ELLIPSIS 5
+struct symbol {
+ int type;
+ int val;
+ wchar_t name[CHARMAP_SYMBOL_LEN];
+ union {
+ wchar_t wc;
+ wchar_t str[STR_LEN];
+ } u;
+};
+
+extern int line_no;
+
+struct symbol *getsymbol(const wchar_t *, int);
+extern char *showwcs(const wchar_t *, int);
+
+extern char map_name[FILENAME_MAX];
diff --git a/adv_cmds/colldef/locale/collate.h b/adv_cmds/colldef/locale/collate.h
new file mode 100644
index 0000000..494e231
--- /dev/null
+++ b/adv_cmds/colldef/locale/collate.h
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * 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 ``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.
+ *
+ * $FreeBSD: src/lib/libc/locale/collate.h,v 1.14 2002/08/30 20:26:02 ache Exp $
+ */
+
+#ifndef _COLLATE_H_
+#define _COLLATE_H_
+
+#include <sys/cdefs.h>
+#ifndef __LIBC__
+#include <sys/types.h>
+#endif /* !__LIBC__ */
+#include <limits.h>
+
+#define STR_LEN 10
+#define TABLE_SIZE 100
+#define COLLATE_VERSION "1.0\n"
+#define COLLATE_VERSION1_1 "1.1\n"
+#define COLLATE_VERSION1_1A "1.1A\n"
+/* see discussion in string/FreeBSD/strxfrm for this value */
+#define COLLATE_MAX_PRIORITY ((1 << 24) - 1)
+
+#define DIRECTIVE_UNDEF 0x00
+#define DIRECTIVE_FORWARD 0x01
+#define DIRECTIVE_BACKWARD 0x02
+#define DIRECTIVE_POSITION 0x04
+
+#define DIRECTIVE_DIRECTION_MASK (DIRECTIVE_FORWARD | DIRECTIVE_BACKWARD)
+
+#define COLLATE_SUBST_DUP 0x0001
+
+#define IGNORE_EQUIV_CLASS 1
+
+struct __collate_st_info {
+ __uint8_t directive[COLL_WEIGHTS_MAX];
+ __uint8_t flags;
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ __uint8_t directive_count:4;
+ __uint8_t chain_max_len:4;
+#else
+ __uint8_t chain_max_len:4;
+ __uint8_t directive_count:4;
+#endif
+ __int32_t undef_pri[COLL_WEIGHTS_MAX];
+ __int32_t subst_count[COLL_WEIGHTS_MAX];
+ __int32_t chain_count;
+ __int32_t large_pri_count;
+};
+
+struct __collate_st_char_pri {
+ __int32_t pri[COLL_WEIGHTS_MAX];
+};
+struct __collate_st_chain_pri {
+ __darwin_wchar_t str[STR_LEN];
+ __int32_t pri[COLL_WEIGHTS_MAX];
+};
+struct __collate_st_large_char_pri {
+ __int32_t val;
+ struct __collate_st_char_pri pri;
+};
+struct __collate_st_subst {
+ __int32_t val;
+ __darwin_wchar_t str[STR_LEN];
+};
+
+#ifndef __LIBC__
+extern int __collate_load_error;
+extern int __collate_substitute_nontrivial;
+#define __collate_char_pri_table (*__collate_char_pri_table_ptr)
+extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
+extern struct __collate_st_chain_pri *__collate_chain_pri_table;
+extern __int32_t *__collate_chain_equiv_table;
+extern struct __collate_st_info __collate_info;
+#endif /* !__LIBC__ */
+
+__BEGIN_DECLS
+#ifdef __LIBC__
+__darwin_wchar_t *__collate_mbstowcs(const char *, locale_t);
+__darwin_wchar_t *__collate_wcsdup(const __darwin_wchar_t *);
+__darwin_wchar_t *__collate_substitute(const __darwin_wchar_t *, int, locale_t);
+int __collate_load_tables(const char *, locale_t);
+void __collate_lookup_l(const __darwin_wchar_t *, int *, int *, int *, locale_t);
+void __collate_lookup_which(const __darwin_wchar_t *, int *, int *, int, locale_t);
+void __collate_xfrm(const __darwin_wchar_t *, __darwin_wchar_t **, locale_t);
+int __collate_range_cmp(__darwin_wchar_t, __darwin_wchar_t, locale_t);
+size_t __collate_collating_symbol(__darwin_wchar_t *, size_t, const char *, size_t, __darwin_mbstate_t *, locale_t);
+int __collate_equiv_class(const char *, size_t, __darwin_mbstate_t *, locale_t);
+size_t __collate_equiv_match(int, __darwin_wchar_t *, size_t, __darwin_wchar_t, const char *, size_t, __darwin_mbstate_t *, size_t *, locale_t);
+#else /* !__LIBC__ */
+void __collate_lookup(const unsigned char *, int *, int *, int *);
+#endif /* __LIBC__ */
+#ifdef COLLATE_DEBUG
+void __collate_print_tables(void);
+#endif
+__END_DECLS
+
+#endif /* !_COLLATE_H_ */
diff --git a/adv_cmds/colldef/parse.y b/adv_cmds/colldef/parse.y
new file mode 100644
index 0000000..495c2f3
--- /dev/null
+++ b/adv_cmds/colldef/parse.y
@@ -0,0 +1,1416 @@
+%{
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * 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 ``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/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/colldef/parse.y,v 1.31 2002/10/16 12:56:22 charnier Exp $");
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <limits.h>
+#include "collate.h"
+#include "common.h"
+
+#define PRI_UNDEFINED (-1)
+#define PRI_IGNORE 0
+#define LINE_NONE (-1)
+#define LINE_NORMAL 0
+#define LINE_ELLIPSIS 1
+#define LINE_UNDEFINED 2
+/* If UNDEFINED is specified with ellipses, we reposition prim_pri to
+ * UNDEFINED_PRI, leaving gap for undefined characters. */
+#define UNDEFINED_PRI (COLLATE_MAX_PRIORITY - (COLLATE_MAX_PRIORITY >> 2))
+
+extern FILE *yyin;
+void yyerror(const char *fmt, ...) __printflike(1, 2);
+int yyparse(void);
+int yylex(void);
+static void usage(void);
+static void collate_print_tables(void);
+static struct __collate_st_char_pri *getpri(int32_t);
+static struct __collate_st_char_pri *haspri(int32_t);
+static struct __collate_st_chain_pri *getchain(const wchar_t *, int);
+static struct symbol *getsymbolbychar(wchar_t);
+static struct symbol *hassymbolbychar(wchar_t);
+static void setsymbolbychar(struct symbol *);
+struct symbol *getstring(const wchar_t *);
+static void makeforwardref(int, const struct symbol *, const struct symbol *);
+static int charpricompar(const void *, const void *);
+static int substcompar(const void *, const void *);
+static int chainpricompar(const void *, const void *);
+static void putsubst(int32_t, int, const wchar_t *);
+static int hassubst(int32_t, int);
+static const wchar_t *__collate_wcsnchr(const wchar_t *, wchar_t, int);
+static int __collate_wcsnlen(const wchar_t *, int);
+char *showwcs(const wchar_t *, int);
+static char *charname(wchar_t);
+static char *charname2(wchar_t);
+
+char map_name[FILENAME_MAX] = ".";
+wchar_t curr_chain[STR_LEN + 1];
+
+char __collate_version[STR_LEN];
+DB *charmapdb;
+static DB *charmapdb2;
+static DB *largemapdb;
+static int nlargemap = 0;
+static DB *substdb[COLL_WEIGHTS_MAX];
+static int nsubst[COLL_WEIGHTS_MAX];
+static DB *chaindb;
+static int nchain = 0;
+static DB *stringdb;
+static DB *forward_ref[COLL_WEIGHTS_MAX];
+static struct symbol *prev_weight_table[COLL_WEIGHTS_MAX];
+static struct symbol *prev2_weight_table[COLL_WEIGHTS_MAX];
+static struct symbol *weight_table[COLL_WEIGHTS_MAX];
+static int prev_line = LINE_NONE;
+static struct symbol *prev_elem;
+static int weight_index = 0;
+static int allow_ellipsis = 0;
+static struct symbol sym_ellipsis = {SYMBOL_ELLIPSIS, PRI_UNDEFINED};
+static struct symbol sym_ignore = {SYMBOL_IGNORE, PRI_IGNORE};
+static struct symbol sym_undefined = {SYMBOL_CHAR, PRI_UNDEFINED};
+static int order_pass = 0;
+
+#undef __collate_char_pri_table
+struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1];
+struct __collate_st_chain_pri *__collate_chain_pri_table;
+struct __collate_st_subst *__collate_substitute_table[COLL_WEIGHTS_MAX];
+struct __collate_st_large_char_pri *__collate_large_char_pri_table;
+
+int prim_pri = 2, sec_pri = 2;
+#ifdef COLLATE_DEBUG
+int debug;
+#endif
+struct __collate_st_info info = {{DIRECTIVE_FORWARD, DIRECTIVE_FORWARD}, 0, 0, 0, {PRI_UNDEFINED, PRI_UNDEFINED}};
+
+/* Some of the code expects COLL_WEIGHTS_MAX == 2 */
+int directive_count = COLL_WEIGHTS_MAX;
+
+const char *out_file = "LC_COLLATE";
+%}
+%union {
+ int32_t ch;
+ wchar_t str[BUFSIZE];
+}
+%token SUBSTITUTE WITH
+%token START_LC_COLLATE END_LC_COLLATE COLLATING_ELEMENT FROM COLLATING_SYMBOL
+%token ELLIPSIS IGNORE UNDEFINED
+%token ORDER RANGE ORDER_START ORDER_END ORDER_SECOND_PASS
+%token <str> STRING
+%token <str> DEFN
+%token <str> ELEM
+%token <ch> CHAR
+%token <ch> ORDER_DIRECTIVE
+%%
+collate : datafile {
+ FILE *fp;
+ int localedef = (stringdb != NULL);
+ int z;
+
+ if (nchain > 0) {
+ DBT key, val;
+ struct __collate_st_chain_pri *t, *v;
+ wchar_t *wp, *tp;
+ int flags, i, len;
+
+ if ((__collate_chain_pri_table = (struct __collate_st_chain_pri *)malloc(nchain * sizeof(struct __collate_st_chain_pri))) == NULL)
+ err(1, "chain malloc");
+ flags = R_FIRST;
+ t = __collate_chain_pri_table;
+ for(i = 0; i < nchain; i++) {
+ if (chaindb->seq(chaindb, &key, &val, flags) != 0)
+ err(1, "Can't retrieve chaindb %d", i);
+ memcpy(&v, val.data, sizeof(struct __collate_st_chain_pri *));
+ *t++ = *v;
+ if ((len = __collate_wcsnlen(v->str, STR_LEN)) > info.chain_max_len)
+ info.chain_max_len = len;
+ flags = R_NEXT;
+ }
+ if (chaindb->seq(chaindb, &key, &val, flags) == 0)
+ err(1, "More in chaindb after retrieving %d", nchain);
+ qsort(__collate_chain_pri_table, nchain, sizeof(struct __collate_st_chain_pri), chainpricompar);
+ }
+ for(z = 0; z < directive_count; z++) {
+ if (nsubst[z] > 0) {
+ DBT key, val;
+ struct __collate_st_subst *t;
+ wchar_t *wp, *tp;
+ int flags, i, j;
+ int32_t cval;
+
+ if ((__collate_substitute_table[z] = (struct __collate_st_subst *)calloc(nsubst[z], sizeof(struct __collate_st_subst))) == NULL)
+ err(1, "__collate_substitute_table[%d] calloc", z);
+ flags = R_FIRST;
+ t = __collate_substitute_table[z];
+ for(i = 0; i < nsubst[z]; i++) {
+ if (substdb[z]->seq(substdb[z], &key, &val, flags) != 0)
+ err(1, "Can't retrieve substdb[%d]", z);
+ memcpy(&cval, key.data, sizeof(int32_t));
+ /* we don't set the byte order of t->val, since we
+ * need it for sorting */
+ t->val = cval;
+ for(wp = (wchar_t *)val.data, tp = t->str, j = STR_LEN; *wp && j-- > 0;)
+ *tp++ = htonl(*wp++);
+ t++;
+ flags = R_NEXT;
+ }
+ if (substdb[z]->seq(substdb[z], &key, &val, flags) == 0)
+ err(1, "More in substdb[%d] after retrieving %d", z, nsubst[z]);
+ qsort(__collate_substitute_table[z], nsubst[z], sizeof(struct __collate_st_subst), substcompar);
+ }
+ }
+ if (nlargemap > 0) {
+ DBT key, val;
+ struct __collate_st_large_char_pri *t;
+ struct __collate_st_char_pri *p;
+ int flags, i, z;
+ int32_t cval;
+
+ if ((__collate_large_char_pri_table = (struct __collate_st_large_char_pri *)malloc(nlargemap * sizeof(struct __collate_st_large_char_pri))) == NULL)
+ err(1, "nlargemap malloc");
+ flags = R_FIRST;
+ t = __collate_large_char_pri_table;
+ for(i = 0; i < nlargemap; i++) {
+ if (largemapdb->seq(largemapdb, &key, &val, flags) != 0)
+ err(1, "Can't retrieve largemapdb %d", i);
+ memcpy(&cval, key.data, sizeof(int32_t));
+ memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *));
+ /* we don't set the byte order of t->val, since we
+ * need it for sorting */
+ t->val = cval;
+ for(z = 0; z < directive_count; z++)
+ t->pri.pri[z] = htonl(p->pri[z]);
+ t++;
+ flags = R_NEXT;
+ }
+ if (largemapdb->seq(largemapdb, &key, &val, flags) == 0)
+ err(1, "More in largemapdb after retrieving %d", nlargemap);
+ qsort(__collate_large_char_pri_table, nlargemap, sizeof(struct __collate_st_large_char_pri), charpricompar);
+ }
+
+ if (info.undef_pri[0] == PRI_UNDEFINED) {
+ int i;
+ info.undef_pri[0] = prim_pri;
+ for(i = 1; i < directive_count; i++)
+ info.undef_pri[i] = -prim_pri;
+ }
+
+ if (localedef) {
+ int ch, z, ret;
+ if (sym_undefined.val == PRI_UNDEFINED) {
+ int flags = R_FIRST;
+ DBT key, val;
+ struct symbol *v;
+ while((ret = charmapdb->seq(charmapdb, &key, &val, flags)) == 0) {
+ memcpy(&v, val.data, sizeof(struct symbol *));
+ switch(v->type) {
+ case SYMBOL_CHAR: {
+ struct __collate_st_char_pri *p = haspri(v->u.wc);
+ if (!p || p->pri[0] == PRI_UNDEFINED)
+ warnx("<%s> was not defined", showwcs((const wchar_t *)key.data, key.size / sizeof(wchar_t)));
+ break;
+ }
+ case SYMBOL_CHAIN: {
+ struct __collate_st_chain_pri *p = getchain(v->u.str, EXISTS);
+ if (p->pri[0] == PRI_UNDEFINED)
+ warnx("<%s> was not defined", showwcs((const wchar_t *)key.data, key.size / sizeof(wchar_t)));
+ break;
+ }
+ }
+ flags = R_NEXT;
+ }
+ if (ret < 0)
+ err(1, "Error retrieving from charmapdb");
+ }
+ for (ch = 1; ch < UCHAR_MAX + 1; ch++) {
+ for(z = 0; z < directive_count; z++)
+ if (__collate_char_pri_table[ch].pri[z] == PRI_UNDEFINED)
+ __collate_char_pri_table[ch].pri[z] = (info.undef_pri[z] >= 0) ? info.undef_pri[z] : (ch - info.undef_pri[z]);
+ }
+ for (ch = 0; ch < nlargemap; ch++) {
+ for(z = 0; z < directive_count; z++)
+ if (__collate_large_char_pri_table[ch].pri.pri[z] == PRI_UNDEFINED)
+ __collate_large_char_pri_table[ch].pri.pri[z] = (info.undef_pri[z] >= 0) ? info.undef_pri[z] : (__collate_large_char_pri_table[ch].val - info.undef_pri[z]);
+ }
+ } else {
+ int ch, substed, ordered;
+ int fatal = 0;
+ for (ch = 1; ch < UCHAR_MAX + 1; ch++) {
+ substed = hassubst(ch, 0);
+ ordered = (__collate_char_pri_table[ch].pri[0] != PRI_UNDEFINED);
+ if (!ordered && !substed) {
+ fatal = 1;
+ warnx("%s not found", charname(ch));
+ }
+ if (substed && ordered) {
+ fatal = 1;
+ warnx("%s can't be ordered since substituted", charname(ch));
+ }
+ }
+ if (fatal)
+ exit(1);
+ }
+
+ /* COLLATE_SUBST_DUP depends on COLL_WEIGHTS_MAX == 2 */
+ if (localedef) {
+ if (nsubst[0] == nsubst[1] && (nsubst[0] == 0 ||
+ memcmp(__collate_substitute_table[0], __collate_substitute_table[1], nsubst[0] * sizeof(struct __collate_st_subst)) == 0)) {
+ info.flags |= COLLATE_SUBST_DUP;
+ nsubst[1] = 0;
+ }
+ } else {
+ info.flags |= COLLATE_SUBST_DUP;
+ nsubst[1] = 0;
+ }
+
+ for(z = 0; z < directive_count; z++)
+ info.subst_count[z] = nsubst[z];
+
+ info.directive_count = directive_count;
+ info.chain_count = nchain;
+ info.large_pri_count = nlargemap;
+
+ if ((fp = fopen(out_file, "w")) == NULL)
+ err(EX_UNAVAILABLE, "can't open destination file %s",
+ out_file);
+
+ strcpy(__collate_version, COLLATE_VERSION1_1A);
+ if (fwrite(__collate_version, sizeof(__collate_version), 1, fp) != 1)
+ err(EX_IOERR,
+ "IO error writting collate version to destination file %s",
+ out_file);
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ for(z = 0; z < directive_count; z++) {
+ info.undef_pri[z] = htonl(info.undef_pri[z]);
+ info.subst_count[z] = htonl(info.subst_count[z]);
+ }
+ info.chain_count = htonl(info.chain_count);
+ info.large_pri_count = htonl(info.large_pri_count);
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(&info, sizeof(info), 1, fp) != 1)
+ err(EX_IOERR,
+ "IO error writting collate info to destination file %s",
+ out_file);
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ {
+ int i, z;
+ struct __collate_st_char_pri *p = __collate_char_pri_table;
+
+ for(i = UCHAR_MAX + 1; i-- > 0; p++) {
+ for(z = 0; z < directive_count; z++)
+ p->pri[z] = htonl(p->pri[z]);
+ }
+ }
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(__collate_char_pri_table,
+ sizeof(__collate_char_pri_table), 1, fp) != 1)
+ err(EX_IOERR,
+ "IO error writting char table to destination file %s",
+ out_file);
+ for(z = 0; z < directive_count; z++) {
+ if (nsubst[z] > 0) {
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ struct __collate_st_subst *t = __collate_substitute_table[z];
+ int i;
+ for(i = nsubst[z]; i > 0; i--) {
+ t->val = htonl(t->val);
+ t++;
+ }
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(__collate_substitute_table[z], sizeof(struct __collate_st_subst), nsubst[z], fp) != nsubst[z])
+ err(EX_IOERR,
+ "IO error writting large substprim table %d to destination file %s",
+ z, out_file);
+ }
+ }
+ if (nchain > 0) {
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ int i, j, z;
+ struct __collate_st_chain_pri *p = __collate_chain_pri_table;
+ wchar_t *w;
+
+ for(i = nchain; i-- > 0; p++) {
+ for(j = STR_LEN, w = p->str; *w && j-- > 0; w++)
+ *w = htonl(*w);
+ for(z = 0; z < directive_count; z++)
+ p->pri[z] = htonl(p->pri[z]);
+ }
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(__collate_chain_pri_table,
+ sizeof(*__collate_chain_pri_table), nchain, fp) !=
+ (size_t)nchain)
+ err(EX_IOERR,
+ "IO error writting chain table to destination file %s",
+ out_file);
+ }
+
+ if (nlargemap > 0) {
+#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN
+ struct __collate_st_large_char_pri *t = __collate_large_char_pri_table;
+ int i;
+ for(i = 0; i < nlargemap; i++) {
+ t->val = htonl(t->val);
+ t++;
+ }
+#endif /* __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN */
+ if (fwrite(__collate_large_char_pri_table, sizeof(struct __collate_st_large_char_pri), nlargemap, fp) != nlargemap)
+ err(EX_IOERR,
+ "IO error writting large pri tables to destination file %s",
+ out_file);
+ }
+
+ if (fclose(fp) != 0)
+ err(EX_IOERR, "IO error closing destination file %s",
+ out_file);
+
+#ifdef COLLATE_DEBUG
+ if (debug)
+ collate_print_tables();
+#endif
+ exit(EX_OK);
+}
+;
+datafile : statment_list
+ | blank_lines start_localedef localedef_sections blank_lines end_localedef blank_lines
+;
+statment_list : statment
+ | statment_list '\n' statment
+;
+statment :
+ | charmap
+ | substitute
+ | order
+;
+blank_lines :
+ | '\n'
+ | blank_lines '\n'
+;
+start_localedef : START_LC_COLLATE '\n' {
+ int i;
+ if ((stringdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen stringdb");
+ directive_count = 0;
+ for(i = 0; i < COLL_WEIGHTS_MAX; i++)
+ info.directive[i] = DIRECTIVE_UNDEF;
+}
+;
+end_localedef : END_LC_COLLATE '\n'
+;
+localedef_sections : localedef_preface localedef_order
+;
+localedef_preface : localedef_statment '\n'
+ | localedef_preface localedef_statment '\n'
+;
+localedef_statment :
+ | charmap
+ | collating_element
+ | collating_symbol
+;
+collating_element : COLLATING_ELEMENT ELEM FROM STRING {
+ int len;
+ struct symbol *s;
+ if (wcslen($2) > CHARMAP_SYMBOL_LEN)
+ yyerror("collating-element symbol name '%s' is too long", showwcs($2, CHARMAP_SYMBOL_LEN));
+ if ((len = wcslen($4)) > STR_LEN)
+ yyerror("collating-element string '%s' is too long", showwcs($4, STR_LEN));
+ if (len < 2)
+ yyerror("collating-element string '%s' must be at least two characters", showwcs($4, STR_LEN));
+ s = getsymbol($2, NOTEXISTS);
+ s->val = PRI_UNDEFINED;
+ s->type = SYMBOL_CHAIN;
+ wcsncpy(s->u.str, $4, STR_LEN);
+ getchain($4, NOTEXISTS);
+}
+;
+collating_symbol : COLLATING_SYMBOL ELEM {
+ struct symbol *s;
+ if (wcslen($2) > CHARMAP_SYMBOL_LEN)
+ yyerror("collating-element symbol name '%s' is too long", showwcs($2, CHARMAP_SYMBOL_LEN));
+ s = getsymbol($2, NOTEXISTS);
+ s->val = PRI_UNDEFINED;
+ s->type = SYMBOL_SYMBOL;
+}
+;
+localedef_order : order_start order_lines1 order_second_pass order_lines2 order_end
+;
+order_start: ORDER_START order_start_list '\n'
+;
+order_second_pass: ORDER_SECOND_PASS {
+ prev_line = LINE_NONE;
+ prev_elem = NULL;
+ order_pass++;
+}
+;
+order_start_list : order_start_list_directives {
+ if (directive_count > 0)
+ yyerror("Multiple order_start lines not allowed");
+ if ((info.directive[0] & DIRECTIVE_DIRECTION_MASK) == 0)
+ info.directive[0] |= DIRECTIVE_FORWARD;
+ directive_count++;
+}
+ | order_start_list ';' order_start_list_directives {
+ if (directive_count >= COLL_WEIGHTS_MAX)
+ yyerror("only COLL_WEIGHTS_MAX weights allowed");
+ if ((info.directive[directive_count] & DIRECTIVE_DIRECTION_MASK) == 0)
+ info.directive[directive_count] |= DIRECTIVE_FORWARD;
+ directive_count++;
+}
+;
+order_start_list_directives : ORDER_DIRECTIVE {
+ info.directive[directive_count] = $1;
+}
+ | order_start_list_directives ',' ORDER_DIRECTIVE {
+ int direction = ($3 & DIRECTIVE_DIRECTION_MASK);
+ int prev = (info.directive[directive_count] & DIRECTIVE_DIRECTION_MASK);
+ if (direction && prev && direction != prev)
+ yyerror("The forward and backward directives are mutually exclusive");
+ info.directive[directive_count] |= $3;
+}
+;
+order_lines1 : order_line1 '\n'
+ | order_lines1 order_line1 '\n'
+;
+order_line1 :
+ | ELEM {
+ struct symbol *s = getsymbol($1, EXISTS);
+ if (s->val != PRI_UNDEFINED)
+ yyerror("<%s> redefined", showwcs($1, CHARMAP_SYMBOL_LEN));
+ if (prev_line == LINE_ELLIPSIS) {
+ struct symbol *m;
+ wchar_t i;
+ int v;
+ switch (s->type) {
+ case SYMBOL_CHAIN:
+ yyerror("Chain <%s> can't be endpoints of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN));
+ case SYMBOL_SYMBOL:
+ yyerror("Collating symbol <%s> can't be endpoints of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN));
+ }
+ if (s->u.wc <= prev_elem->u.wc)
+ yyerror("<%s> is before starting point of ellipsis", showwcs($1, CHARMAP_SYMBOL_LEN));
+ for(i = prev_elem->u.wc + 1, v = prev_elem->val + 1; i < s->u.wc; i++, v++) {
+ m = getsymbolbychar(i);
+ if (m->val != PRI_UNDEFINED)
+ yyerror("<%s> was previously defined while filling ellipsis symbols", showwcs(m->name, CHARMAP_SYMBOL_LEN));
+ m->val = v;
+ }
+ s->val = v;
+ } else
+ s->val = prim_pri;
+ prim_pri = s->val + 1;
+ weight_index = 0;
+} weights {
+ int i;
+ struct symbol *s = getsymbol($1, EXISTS);
+ if (s->type == SYMBOL_SYMBOL) {
+ if (weight_index != 0)
+ yyerror("Can't specify weights for collating symbol <%s>", showwcs($1, CHARMAP_SYMBOL_LEN));
+ } else if (weight_index == 0) {
+ for(i = 0; i < directive_count; i++)
+ weight_table[i] = s;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_NORMAL;
+ prev_elem = s;
+}
+ | ELLIPSIS { weight_index = 0; allow_ellipsis = 1; } weights {
+ int i;
+ if (prev_line == LINE_ELLIPSIS)
+ yyerror("Illegal sequential ellipsis lines");
+ if (prev_line == LINE_UNDEFINED)
+ yyerror("Ellipsis line can not follow UNDEFINED line");
+ if (prev_line == LINE_NONE)
+ yyerror("Ellipsis line must follow a collating identifier lines");
+ if (weight_index == 0) {
+ for(i = 0; i < directive_count; i++)
+ weight_table[i] = &sym_ellipsis;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ for(i = 0; i < directive_count; i++) {
+ if (weight_table[i]->type != SYMBOL_ELLIPSIS)
+ continue;
+ switch (prev_weight_table[i]->type) {
+ case SYMBOL_CHAIN:
+ yyerror("Startpoint of ellipsis can't be a collating element");
+ case SYMBOL_IGNORE:
+ yyerror("Startpoint of ellipsis can't be IGNORE");
+ case SYMBOL_SYMBOL:
+ yyerror("Startpoint of ellipsis can't be a collating symbol");
+ case SYMBOL_STRING:
+ yyerror("Startpoint of ellipsis can't be a string");
+ }
+ }
+ memcpy(prev2_weight_table, prev_weight_table, sizeof(prev_weight_table));
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_ELLIPSIS;
+ allow_ellipsis = 0;
+}
+ | UNDEFINED {
+ if (sym_undefined.val != PRI_UNDEFINED)
+ yyerror("Multiple UNDEFINED lines not allowed");
+ sym_undefined.val = prim_pri++;
+ weight_index = 0;
+ allow_ellipsis = 1;
+} weights {
+ int i;
+ if (weight_index == 0) {
+ weight_table[0] = &sym_undefined;
+ for(i = 1; i < directive_count; i++)
+ weight_table[i] = &sym_ellipsis;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_UNDEFINED;
+}
+;
+order_lines2 : order_line2 '\n'
+ | order_lines2 order_line2 '\n'
+;
+order_line2 :
+ | ELEM { weight_index = 0; } weights {
+ int i;
+ struct symbol *s = getsymbol($1, EXISTS);
+ if (s->val == PRI_UNDEFINED)
+ yyerror("<%s> undefined", showwcs($1, CHARMAP_SYMBOL_LEN));
+ if (s->type == SYMBOL_SYMBOL) {
+ if (weight_index != 0)
+ yyerror("Can't specify weights for collating symbol <%s>", showwcs($1, CHARMAP_SYMBOL_LEN));
+ } else if (weight_index == 0) {
+ for(i = 0; i < directive_count; i++)
+ weight_table[i] = s;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ if (prev_line == LINE_ELLIPSIS) {
+ int w, x;
+ for(i = 0; i < directive_count; i++) {
+ switch (prev_weight_table[i]->type) {
+ case SYMBOL_CHAR:
+ case SYMBOL_CHAIN:
+ case SYMBOL_IGNORE:
+ case SYMBOL_SYMBOL:
+ for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) {
+ struct __collate_st_char_pri *p = getpri(w);
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", w);
+ p->pri[i] = prev_weight_table[i]->val;
+ }
+ break;
+ case SYMBOL_ELLIPSIS:
+
+ switch (weight_table[i]->type) {
+ case SYMBOL_STRING:
+ yyerror("Strings can't be endpoints of ellipsis");
+ case SYMBOL_CHAIN:
+ yyerror("Chains can't be endpoints of ellipsis");
+ case SYMBOL_IGNORE:
+ yyerror("IGNORE can't be endpoints of ellipsis");
+ case SYMBOL_SYMBOL:
+ yyerror("Collation symbols can't be endpoints of ellipsis");
+ }
+ if (s->val - prev_elem->val != weight_table[i]->val - prev2_weight_table[i]->val)
+ yyerror("Range mismatch in weight %d", i);
+ x = prev2_weight_table[i]->val + 1;
+ for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) {
+ struct __collate_st_char_pri *p = getpri(w);
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", w);
+ p->pri[i] = x++;
+ }
+ break;
+ case SYMBOL_STRING:
+ for (w = prev_elem->u.wc + 1; w < s->u.wc; w++) {
+ struct __collate_st_char_pri *p = getpri(w);
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", w);
+ putsubst(w, i, prev_weight_table[i]->u.str);
+ p->pri[i] = prev_weight_table[i]->val;
+ }
+ break;
+ }
+ }
+ }
+ switch(s->type) {
+ case SYMBOL_CHAR: {
+ struct __collate_st_char_pri *p = getpri(s->u.wc);
+ for(i = 0; i < directive_count; i++) {
+ switch (weight_table[i]->type) {
+ case SYMBOL_CHAR:
+ case SYMBOL_CHAIN:
+ case SYMBOL_IGNORE:
+ case SYMBOL_SYMBOL:
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", s->u.wc);
+ p->pri[i] = weight_table[i]->val;
+ break;
+ case SYMBOL_STRING:
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Char 0x02x previously defined", s->u.wc);
+ putsubst(s->u.wc, i, weight_table[i]->u.str);
+ p->pri[i] = weight_table[i]->val;
+ break;
+ }
+ }
+ break;
+ }
+ case SYMBOL_CHAIN: {
+ struct __collate_st_chain_pri *p = getchain(s->u.str, EXISTS);
+ for(i = 0; i < directive_count; i++) {
+ switch (weight_table[i]->type) {
+ case SYMBOL_CHAR:
+ case SYMBOL_CHAIN:
+ case SYMBOL_IGNORE:
+ case SYMBOL_SYMBOL:
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Chain %s previously defined", showwcs(s->u.str, STR_LEN));
+ p->pri[i] = weight_table[i]->val;
+ break;
+ case SYMBOL_STRING :
+ if (wcsncmp(s->u.str, weight_table[i]->u.str, STR_LEN) != 0)
+ yyerror("Chain/string mismatch");
+ if (p->pri[i] != PRI_UNDEFINED)
+ yyerror("Chain %s previously defined", showwcs(s->u.str, STR_LEN));
+ /* negative value mean don't substitute
+ * the chain, but it is in an
+ * equivalence class */
+ p->pri[i] = -weight_table[i]->val;
+ }
+ }
+ break;
+ }
+ }
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_NORMAL;
+ prev_elem = s;
+}
+ | ELLIPSIS { weight_index = 0; allow_ellipsis = 1; } weights {
+ int i;
+ if (prev_line == LINE_ELLIPSIS)
+ yyerror("Illegal sequential ellipsis lines");
+ if (prev_line == LINE_UNDEFINED)
+ yyerror("Ellipsis line can not follow UNDEFINED line");
+ if (prev_line == LINE_NONE)
+ yyerror("Ellipsis line must follow a collating identifier lines");
+ if (weight_index == 0) {
+ for(i = 0; i < directive_count; i++)
+ weight_table[i] = &sym_ellipsis;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ for(i = 0; i < directive_count; i++) {
+ if (weight_table[i]->type != SYMBOL_ELLIPSIS)
+ continue;
+ switch (prev_weight_table[i]->type) {
+ case SYMBOL_CHAIN:
+ yyerror("Startpoint of ellipsis can't be a collating element");
+ case SYMBOL_IGNORE:
+ yyerror("Startpoint of ellipsis can't be IGNORE");
+ case SYMBOL_SYMBOL:
+ yyerror("Startpoint of ellipsis can't be a collating symbol");
+ case SYMBOL_STRING:
+ yyerror("Startpoint of ellipsis can't be a string");
+ }
+ }
+ memcpy(prev2_weight_table, prev_weight_table, sizeof(prev_weight_table));
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_ELLIPSIS;
+ allow_ellipsis = 0;
+}
+ | UNDEFINED { weight_index = 0; allow_ellipsis = 1; } weights {
+ int i;
+
+ if (weight_index == 0) {
+ weight_table[0] = &sym_undefined;
+ for(i = 1; i < directive_count; i++)
+ weight_table[i] = &sym_ellipsis;
+ } else if (weight_index != directive_count)
+ yyerror("Not enough weights specified");
+ for(i = 0; i < directive_count; i++) {
+ switch (weight_table[i]->type) {
+ case SYMBOL_CHAR:
+ case SYMBOL_CHAIN:
+ case SYMBOL_IGNORE:
+ case SYMBOL_SYMBOL:
+ info.undef_pri[i] = weight_table[i]->val;
+ break;
+ case SYMBOL_ELLIPSIS :
+ /* Negative values mean that the priority is
+ * relative to the lexical value */
+ info.undef_pri[i] = -sym_undefined.val;
+ prim_pri = UNDEFINED_PRI;
+ break;
+ case SYMBOL_STRING :
+ yyerror("Strings can't be used with UNDEFINED");
+ }
+ }
+ memcpy(prev_weight_table, weight_table, sizeof(weight_table));
+ prev_line = LINE_UNDEFINED;
+}
+;
+weights :
+ | weight
+ | weights ';' weight
+;
+weight : ELEM {
+ struct symbol *s;
+ if (weight_index >= directive_count)
+ yyerror("More weights than specified by order_start");
+ s = getsymbol($1, EXISTS);
+ if (order_pass && s->val == PRI_UNDEFINED)
+ yyerror("<%s> is undefined", showwcs($1, CHARMAP_SYMBOL_LEN));
+ weight_table[weight_index++] = s;
+}
+ | ELLIPSIS {
+ if (weight_index >= directive_count)
+ yyerror("More weights than specified by order_start");
+ if (!allow_ellipsis)
+ yyerror("Ellipsis weight not allowed");
+ weight_table[weight_index++] = &sym_ellipsis;
+}
+ | IGNORE {
+ if (weight_index >= directive_count)
+ yyerror("More weights than specified by order_start");
+ weight_table[weight_index++] = &sym_ignore;
+}
+ | STRING {
+ if (weight_index >= directive_count)
+ yyerror("More weights than specified by order_start");
+ if (wcslen($1) > STR_LEN)
+ yyerror("String '%s' is too long", showwcs($1, STR_LEN));
+ weight_table[weight_index++] = getstring($1);
+}
+;
+order_end : ORDER_END '\n'
+;
+charmap : DEFN CHAR {
+ int len = wcslen($1);
+ struct symbol *s;
+ if (len > CHARMAP_SYMBOL_LEN)
+ yyerror("Charmap symbol name '%s' is too long", showwcs($1, CHARMAP_SYMBOL_LEN));
+ s = getsymbol($1, NOTEXISTS);
+ s->type = SYMBOL_CHAR;
+ s->val = PRI_UNDEFINED;
+ s->u.wc = $2;
+ setsymbolbychar(s);
+}
+;
+substitute : SUBSTITUTE CHAR WITH STRING {
+ if (wcslen($4) + 1 > STR_LEN)
+ yyerror("%s substitution is too long", charname($2));
+ putsubst($2, 0, $4);
+}
+;
+order : ORDER order_list
+;
+order_list : item
+ | order_list ';' item
+;
+chain : CHAR CHAR {
+ curr_chain[0] = $1;
+ curr_chain[1] = $2;
+ if (curr_chain[0] == '\0' || curr_chain[1] == '\0')
+ yyerror("\\0 can't be chained");
+ curr_chain[2] = '\0';
+}
+ | chain CHAR {
+ static wchar_t tb[2];
+ tb[0] = $2;
+ if (tb[0] == '\0')
+ yyerror("\\0 can't be chained");
+ if (wcslen(curr_chain) + 1 > STR_LEN)
+ yyerror("Chain '%s' grows too long", curr_chain);
+ (void)wcscat(curr_chain, tb);
+}
+;
+item : CHAR {
+ struct __collate_st_char_pri *p = getpri($1);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname($1));
+ p->pri[0] = p->pri[1] = prim_pri;
+ sec_pri = ++prim_pri;
+}
+ | chain {
+ struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS);
+ c->pri[0] = c->pri[1] = prim_pri;
+ sec_pri = ++prim_pri;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+ struct __collate_st_char_pri *p;
+
+ if ($3 <= $1)
+ yyerror("Illegal range %s -- %s", charname($1), charname2($3));
+
+ for (i = $1; i <= $3; i++) {
+ p = getpri(i);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname(i));
+ p->pri[0] = p->pri[1] = prim_pri++;
+ }
+ sec_pri = prim_pri;
+}
+ | '{' mixed_order_list '}' {
+ prim_pri = sec_pri;
+}
+ | '(' sec_order_list ')' {
+ prim_pri = sec_pri;
+}
+;
+mixed_order_list : mixed_sub_list {
+ sec_pri++;
+}
+ | mixed_order_list ';' mixed_sub_list {
+ sec_pri++;
+}
+;
+mixed_sub_list : mixed_sub_item
+ | mixed_sub_list ',' mixed_sub_item
+;
+sec_order_list : sec_sub_item
+ | sec_order_list ',' sec_sub_item
+;
+mixed_sub_item : CHAR {
+ struct __collate_st_char_pri *p = getpri($1);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname($1));
+ p->pri[0] = prim_pri;
+ p->pri[1] = sec_pri;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+ struct __collate_st_char_pri *p;
+
+ if ($3 <= $1)
+ yyerror("Illegal range %s -- %s",
+ charname($1), charname2($3));
+
+ for (i = $1; i <= $3; i++) {
+ p = getpri(i);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname(i));
+ p->pri[0] = prim_pri;
+ p->pri[1] = sec_pri;
+ }
+}
+ | chain {
+ struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS);
+ c->pri[0] = prim_pri;
+ c->pri[1] = sec_pri;
+}
+sec_sub_item : CHAR {
+ struct __collate_st_char_pri *p = getpri($1);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname($1));
+ p->pri[0] = prim_pri;
+ p->pri[1] = sec_pri++;
+}
+ | CHAR RANGE CHAR {
+ u_int i;
+ struct __collate_st_char_pri *p;
+
+ if ($3 <= $1)
+ yyerror("Illegal range %s -- %s",
+ charname($1), charname2($3));
+
+ for (i = $1; i <= $3; i++) {
+ p = getpri(i);
+ if (p->pri[0] >= 0)
+ yyerror("%s duplicated", charname(i));
+ p->pri[0] = prim_pri;
+ p->pri[1] = sec_pri++;
+ }
+}
+ | chain {
+ struct __collate_st_chain_pri *c = getchain(curr_chain, NOTEXISTS);
+ c->pri[0] = prim_pri;
+ c->pri[1] = sec_pri++;
+}
+;
+%%
+int
+main(int ac, char **av)
+{
+ int ch, z;
+
+ if ((charmapdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen charmapdb");
+ if ((charmapdb2 = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen charmapdb");
+ if ((largemapdb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen largemapdb");
+ if ((substdb[0] = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen substdb[0]");
+ if ((chaindb = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen chaindb");
+ /* -1 means an undefined priority, which we adjust after parsing */
+ for (ch = 0; ch <= UCHAR_MAX; ch++)
+ for(z = 0; z < COLL_WEIGHTS_MAX; z++)
+ __collate_char_pri_table[ch].pri[z] = PRI_UNDEFINED;
+#ifdef COLLATE_DEBUG
+ while((ch = getopt(ac, av, ":do:I:")) != -1) {
+#else
+ while((ch = getopt(ac, av, ":o:I:")) != -1) {
+#endif
+ switch (ch)
+ {
+#ifdef COLLATE_DEBUG
+ case 'd':
+ debug++;
+ break;
+#endif
+ case 'o':
+ out_file = optarg;
+ break;
+
+ case 'I':
+ strlcpy(map_name, optarg, sizeof(map_name));
+ break;
+
+ default:
+ usage();
+ }
+ }
+ ac -= optind;
+ av += optind;
+ if (ac > 0) {
+ if ((yyin = fopen(*av, "r")) == NULL)
+ err(EX_UNAVAILABLE, "can't open source file %s", *av);
+ }
+ yyparse();
+ return 0;
+}
+
+static struct __collate_st_char_pri *
+getpri(int32_t c)
+{
+ DBT key, val;
+ struct __collate_st_char_pri *p;
+ int ret;
+
+ if (c <= UCHAR_MAX)
+ return &__collate_char_pri_table[c];
+ key.data = &c;
+ key.size = sizeof(int32_t);
+ if ((ret = largemapdb->get(largemapdb, &key, &val, 0)) < 0)
+ err(1, "getpri: Error getting %s", charname(c));
+ if (ret != 0) {
+ struct __collate_st_char_pri *pn;
+ int z;
+ if ((pn = (struct __collate_st_char_pri *)malloc(sizeof(struct __collate_st_char_pri))) == NULL)
+ err(1, "getpri: malloc");
+ for(z = 0; z < COLL_WEIGHTS_MAX; z++)
+ pn->pri[z] = PRI_UNDEFINED;
+ val.data = &pn;
+ val.size = sizeof(struct __collate_st_char_pri *);
+ if (largemapdb->put(largemapdb, &key, &val, 0) < 0)
+ err(1, "getpri: Error storing %s", charname(c));
+ nlargemap++;
+ }
+ memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *));
+ return p;
+}
+
+static struct __collate_st_char_pri *
+haspri(int32_t c)
+{
+ DBT key, val;
+ struct __collate_st_char_pri *p;
+ int ret;
+
+ if (c <= UCHAR_MAX)
+ return &__collate_char_pri_table[c];
+ key.data = &c;
+ key.size = sizeof(int32_t);
+ if ((ret = largemapdb->get(largemapdb, &key, &val, 0)) < 0)
+ err(1, "haspri: Error getting %s", charname(c));
+ if (ret != 0)
+ return NULL;
+ memcpy(&p, val.data, sizeof(struct __collate_st_char_pri *));
+ return p;
+}
+
+static struct __collate_st_chain_pri *
+getchain(const wchar_t *wcs, int exists)
+{
+ DBT key, val;
+ struct __collate_st_chain_pri *p;
+ int ret;
+
+ key.data = (void *)wcs;
+ key.size = __collate_wcsnlen(wcs, STR_LEN) * sizeof(wchar_t);
+ if ((ret = chaindb->get(chaindb, &key, &val, 0)) < 0)
+ err(1, "getchain: Error getting \"%s\"", showwcs(wcs, STR_LEN));
+ if (ret != 0) {
+ struct __collate_st_chain_pri *pn;
+ int z;
+ if (exists > 0)
+ errx(1, "getchain: \"%s\" is not defined", showwcs(wcs, STR_LEN));
+ if ((pn = (struct __collate_st_chain_pri *)malloc(sizeof(struct __collate_st_chain_pri))) == NULL)
+ err(1, "getchain: malloc");
+ for(z = 0; z < COLL_WEIGHTS_MAX; z++)
+ pn->pri[z] = PRI_UNDEFINED;
+ bzero(pn->str, sizeof(pn->str));
+ wcsncpy(pn->str, wcs, STR_LEN);
+ val.data = &pn;
+ val.size = sizeof(struct __collate_st_chain_pri *);
+ if (chaindb->put(chaindb, &key, &val, 0) < 0)
+ err(1, "getchain: Error storing \"%s\"", showwcs(wcs, STR_LEN));
+ nchain++;
+ } else if (exists == 0)
+ errx(1, "getchain: \"%s\" already exists", showwcs(wcs, STR_LEN));
+ memcpy(&p, val.data, sizeof(struct __collate_st_chain_pri *));
+ return p;
+}
+
+struct symbol *
+getsymbol(const wchar_t *wcs, int exists)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = (void *)wcs;
+ key.size = wcslen(wcs) * sizeof(wchar_t);
+ if ((ret = charmapdb->get(charmapdb, &key, &val, 0)) < 0)
+ err(1, "getsymbol: Error getting \"%s\"", showwcs(wcs, CHARMAP_SYMBOL_LEN));
+ if (ret != 0) {
+ struct symbol *pn;
+ if (exists > 0)
+ errx(1, "getsymbol: \"%s\" is not defined", showwcs(wcs, CHARMAP_SYMBOL_LEN));
+ if ((pn = (struct symbol *)malloc(sizeof(struct symbol))) == NULL)
+ err(1, "getsymbol: malloc");
+ pn->val = PRI_UNDEFINED;
+ wcsncpy(pn->name, wcs, CHARMAP_SYMBOL_LEN);
+ val.data = &pn;
+ val.size = sizeof(struct symbol *);
+ if (charmapdb->put(charmapdb, &key, &val, 0) < 0)
+ err(1, "getsymbol: Error storing \"%s\"", showwcs(wcs, CHARMAP_SYMBOL_LEN));
+ } else if (exists == 0)
+ errx(1, "getsymbol: \"%s\" already exists", showwcs(wcs, CHARMAP_SYMBOL_LEN));
+ memcpy(&p, val.data, sizeof(struct symbol *));
+ return p;
+}
+
+static struct symbol *
+getsymbolbychar(wchar_t wc)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = &wc;
+ key.size = sizeof(wchar_t);
+ if ((ret = charmapdb2->get(charmapdb2, &key, &val, 0)) < 0)
+ err(1, "getsymbolbychar: Error getting Char 0x%02x", wc);
+ if (ret != 0)
+ errx(1, "getsymbolbychar: Char 0x%02x is not defined", wc);
+ memcpy(&p, val.data, sizeof(struct symbol *));
+ return p;
+}
+
+static struct symbol *
+hassymbolbychar(wchar_t wc)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = &wc;
+ key.size = sizeof(wchar_t);
+ if ((ret = charmapdb2->get(charmapdb2, &key, &val, 0)) < 0)
+ err(1, "hassymbolbychar: Error getting Char 0x%02x", wc);
+ if (ret != 0)
+ return NULL;
+ memcpy(&p, val.data, sizeof(struct symbol *));
+ return p;
+}
+
+static void
+setsymbolbychar(struct symbol *s)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = &s->u.wc;
+ key.size = sizeof(wchar_t);
+ val.data = &s;
+ val.size = sizeof(struct symbol *);
+ if (charmapdb2->put(charmapdb2, &key, &val, 0) < 0)
+ err(1, "setsymbolbychar: Error storing <%s>", showwcs(s->name, CHARMAP_SYMBOL_LEN));
+}
+
+struct symbol *
+getstring(const wchar_t *wcs)
+{
+ DBT key, val;
+ struct symbol *p;
+ int ret;
+
+ key.data = (void *)wcs;
+ key.size = wcslen(wcs) * sizeof(wchar_t);
+ if ((ret = stringdb->get(stringdb, &key, &val, 0)) < 0)
+ err(1, "getstring: Error getting \"%s\"", showwcs(wcs, STR_LEN));
+ if (ret != 0) {
+ struct symbol *pn;
+ if ((pn = (struct symbol *)malloc(sizeof(struct symbol))) == NULL)
+ err(1, "getstring: malloc");
+ pn->type = SYMBOL_STRING;
+ pn->val = prim_pri++;
+ wcsncpy(pn->u.str, wcs, STR_LEN);
+ val.data = &pn;
+ val.size = sizeof(struct symbol *);
+ if (stringdb->put(stringdb, &key, &val, 0) < 0)
+ err(1, "getstring: Error storing \"%s\"", showwcs(wcs, STR_LEN));
+ }
+ memcpy(&p, val.data, sizeof(struct symbol *));
+ return p;
+}
+
+static void
+makeforwardref(int i, const struct symbol *from, const struct symbol * to)
+{
+}
+
+static void
+putsubst(int32_t c, int i, const wchar_t *str)
+{
+ DBT key, val;
+ int ret;
+ wchar_t clean[STR_LEN];
+
+ if (!substdb[i])
+ if ((substdb[i] = dbopen(NULL, O_CREAT | O_RDWR, 0600, DB_HASH, NULL)) == NULL)
+ err(1, "dbopen substdb[%d]", i);
+ key.data = &c;
+ key.size = sizeof(int32_t);
+ bzero(clean, sizeof(clean));
+ wcsncpy(clean, str, STR_LEN);
+ val.data = clean;
+ val.size = sizeof(clean);
+ if ((ret = substdb[i]->put(substdb[i], &key, &val, R_NOOVERWRITE)) < 0)
+ err(1, "putsubst: Error on %s", charname(c));
+ if (ret != 0)
+ errx(1, "putsubst: Duplicate substitution of %s", charname(c));
+ nsubst[i]++;
+}
+
+static int
+hassubst(int32_t c, int i)
+{
+ DBT key, val;
+ int ret;
+
+ if (!substdb[i])
+ return 0;
+ key.data = &c;
+ key.size = sizeof(int32_t);
+ if ((ret = substdb[i]->get(substdb[i], &key, &val, 0)) < 0)
+ err(1, "hassubst: Error getting %s", charname(c));
+ return (ret == 0);
+}
+
+static int
+chainpricompar(const void *a, const void *b)
+{
+ return wcsncmp(((struct __collate_st_chain_pri *)a)->str, ((struct __collate_st_chain_pri *)b)->str, STR_LEN);
+}
+
+static int
+charpricompar(const void *a, const void *b)
+{
+ return ((struct __collate_st_large_char_pri *)a)->val - ((struct __collate_st_large_char_pri *)b)->val;
+}
+
+static int
+substcompar(const void *a, const void *b)
+{
+ return ((struct __collate_st_subst *)a)->val - ((struct __collate_st_subst *)b)->val;
+}
+
+static const wchar_t *
+__collate_wcsnchr(const wchar_t *s, wchar_t c, int len)
+{
+ while (*s && len > 0) {
+ if (*s == c)
+ return s;
+ s++;
+ len--;
+ }
+ return NULL;
+}
+
+static int
+__collate_wcsnlen(const wchar_t *s, int len)
+{
+ int n = 0;
+ while (*s && n < len) {
+ s++;
+ n++;
+ }
+ return n;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: colldef [-o out_file] [-I map_dir] [filename]\n");
+ exit(EX_USAGE);
+}
+
+void
+yyerror(const char *fmt, ...)
+{
+ va_list ap;
+ char msg[128];
+
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+ errx(EX_UNAVAILABLE, "%s, near line %d", msg, line_no);
+}
+
+char *
+showwcs(const wchar_t *t, int len)
+{
+ static char buf[8* CHARMAP_SYMBOL_LEN];
+ char *cp = buf;
+
+ for(; *t && len > 0; len--, t++) {
+ if (*t >=32 && *t <= 126)
+ *cp++ = *t;
+ else {
+ sprintf(cp, "\\x{%02x}", *t);
+ cp += strlen(cp);
+ }
+ }
+ *cp = 0;
+ return buf;
+}
+
+static char *
+charname(wchar_t wc)
+{
+ static char buf[CHARMAP_SYMBOL_LEN + 1];
+ struct symbol *s = hassymbolbychar(wc);
+
+ if (s)
+ strcpy(buf, showwcs(s->name, CHARMAP_SYMBOL_LEN));
+ else
+ sprintf(buf, "Char 0x%02x", wc);
+ return buf;
+}
+
+static char *
+charname2(wchar_t wc)
+{
+ static char buf[CHARMAP_SYMBOL_LEN + 1];
+ struct symbol *s = hassymbolbychar(wc);
+
+ if (s)
+ strcpy(buf, showwcs(s->name, CHARMAP_SYMBOL_LEN));
+ else
+ sprintf(buf, "Char 0x%02x", wc);
+ return buf;
+}
+
+#ifdef COLLATE_DEBUG
+static char *
+show(int c)
+{
+ static char buf[5];
+
+ if (c >=32 && c <= 126)
+ sprintf(buf, "'%c' ", c);
+ else
+ sprintf(buf, "\\x{%02x}", c);
+ return buf;
+}
+
+static void
+collate_print_tables(void)
+{
+ int i, z;
+
+ printf("Info: p=%d s=%d f=0x%02x m=%d dc=%d up=%d us=%d pc=%d sc=%d cc=%d lc=%d\n",
+ info.directive[0], info.directive[1],
+ info.flags, info.chain_max_len,
+ info.directive_count,
+ info.undef_pri[0], info.undef_pri[1],
+ info.subst_count[0], info.subst_count[1],
+ info.chain_count, info.large_pri_count);
+ for(z = 0; z < info.directive_count; z++) {
+ if (info.subst_count[z] > 0) {
+ struct __collate_st_subst *p2 = __collate_substitute_table[z];
+ if (z == 0 && (info.flags & COLLATE_SUBST_DUP))
+ printf("Both substitute tables:\n");
+ else
+ printf("Substitute table %d:\n", z);
+ for (i = info.subst_count[z]; i-- > 0; p2++)
+ printf("\t%s --> \"%s\"\n",
+ show(p2->val),
+ showwcs(p2->str, STR_LEN));
+ }
+ }
+ if (info.chain_count > 0) {
+ printf("Chain priority table:\n");
+ struct __collate_st_chain_pri *p2 = __collate_chain_pri_table;
+ for (i = info.chain_count; i-- > 0; p2++) {
+ printf("\t\"%s\" :", showwcs(p2->str, STR_LEN));
+ for(z = 0; z < info.directive_count; z++)
+ printf(" %d", p2->pri[z]);
+ putchar('\n');
+ }
+ }
+ printf("Char priority table:\n");
+ {
+ struct __collate_st_char_pri *p2 = __collate_char_pri_table;
+ for (i = 0; i < UCHAR_MAX + 1; i++, p2++) {
+ printf("\t%s :", show(i));
+ for(z = 0; z < info.directive_count; z++)
+ printf(" %d", p2->pri[z]);
+ putchar('\n');
+ }
+ }
+ if (info.large_pri_count > 0) {
+ struct __collate_st_large_char_pri *p2 = __collate_large_char_pri_table;
+ printf("Large priority table:\n");
+ for (i = info.large_pri_count; i-- > 0; p2++) {
+ printf("\t%s :", show(p2->val));
+ for(z = 0; z < info.directive_count; z++)
+ printf(" %d", p2->pri.pri[z]);
+ putchar('\n');
+ }
+ }
+}
+#endif
diff --git a/adv_cmds/colldef/scan.l b/adv_cmds/colldef/scan.l
new file mode 100644
index 0000000..ce14492
--- /dev/null
+++ b/adv_cmds/colldef/scan.l
@@ -0,0 +1,398 @@
+%x string s_name charmap defn nchar subs subs2 ldef elem
+%{
+/*-
+ * Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
+ * at Electronni Visti IA, Kiev, Ukraine.
+ * 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 ``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/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/colldef/scan.l,v 1.19 2002/08/23 04:18:26 ache Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <unistd.h>
+#include <string.h>
+#include <wchar.h>
+#include <sysexits.h>
+#include <sys/types.h>
+#include "collate.h"
+#include "common.h"
+#include "y.tab.h"
+
+int line_no = 1, save_no, fromsubs;
+wchar_t buf0[BUFSIZE], *ptr;
+wchar_t *buf = buf0;
+wchar_t bufstr[BUFSIZE], *ptrsave;
+FILE *map_fp;
+YY_BUFFER_STATE main_buf, map_buf;
+#ifdef FLEX_DEBUG
+YYSTYPE yylval;
+#endif /* FLEX_DEBUG */
+int yylex(void);
+static int localedefmode = 0;
+static orderpass = 0;
+%}
+%%
+<INITIAL,charmap,nchar,subs,subs2,ldef>[ \t]+ ;
+<subs2,ldef>\" { ptr = buf; BEGIN(string); }
+<string>\< {
+ if(localedefmode) {
+ ptrsave = ptr;
+ ptr = buf = bufstr;
+ BEGIN(s_name);
+ } else {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '<'",
+ line_no);
+ *ptr++ = '<';
+ }
+}
+<subs>\< { ptr = buf; fromsubs = 1; BEGIN(s_name); }
+<ldef>[,;] return *yytext;
+<ldef>forward { yylval.ch = DIRECTIVE_FORWARD; return ORDER_DIRECTIVE; }
+<ldef>backward { yylval.ch = DIRECTIVE_BACKWARD; return ORDER_DIRECTIVE; }
+<ldef>position { yylval.ch = DIRECTIVE_POSITION; return ORDER_DIRECTIVE; }
+<ldef>collating[-_]element return COLLATING_ELEMENT;
+<ldef>collating[-_]symbol return COLLATING_SYMBOL;
+<ldef>from return FROM;
+<ldef>\.\.\. return ELLIPSIS;
+<ldef>IGNORE return IGNORE;
+<ldef>UNDEFINED return UNDEFINED;
+<ldef>order[-_]start return ORDER_START;
+<ldef>order[-_]end {
+ char line[YY_BUF_SIZE];
+ if (orderpass)
+ return ORDER_END;
+ /* The first pass only defined the left-most symbol. We reread the
+ * order lines, and forward references should now be resolved. */
+ orderpass++;
+ YY_FLUSH_BUFFER;
+ rewind(yyin);
+ for(;;) {
+ if (fgets(line, sizeof(line), yyin) == NULL)
+ errx(EX_UNAVAILABLE, "EOF rescanning for order_start");
+ if (*line == '#')
+ continue;
+ if (strstr(line, "order_start") != NULL)
+ break;
+ }
+ return ORDER_SECOND_PASS;
+}
+<ldef>END[ \t]+LC_COLLATE return END_LC_COLLATE;
+<ldef>\n {
+ line_no++;
+ return '\n';
+}
+<ldef>\< { ptr = buf; BEGIN(elem); }
+<INITIAL>\< { ptr = buf; fromsubs = 0; BEGIN(s_name); }
+<*>^#.*\n line_no++;
+^\n line_no++;
+<INITIAL>\\\n line_no++;
+<INITIAL,nchar,subs>\\t { yylval.ch = '\t'; return CHAR; }
+<INITIAL,nchar,subs>\\n { yylval.ch = '\n'; return CHAR; }
+<INITIAL,nchar,subs>\\b { yylval.ch = '\b'; return CHAR; }
+<INITIAL,nchar,subs>\\f { yylval.ch = '\f'; return CHAR; }
+<INITIAL,nchar,subs>\\v { yylval.ch = '\v'; return CHAR; }
+<INITIAL,nchar,subs>\\r { yylval.ch = '\r'; return CHAR; }
+<INITIAL,nchar,subs>\\a { yylval.ch = '\a'; return CHAR; }
+<subs2>\n {
+ line_no++;
+ BEGIN(INITIAL);
+ return '\n';
+}
+<INITIAL,nchar>\n {
+ line_no++;
+ if (map_fp != NULL) {
+ ptr = buf;
+ BEGIN(defn);
+ }
+ return '\n';
+}
+<INITIAL>[;,{}()] return *yytext;
+<INITIAL>substitute { BEGIN(subs); return SUBSTITUTE; }
+<INITIAL>LC_COLLATE { BEGIN(ldef); localedefmode++; return START_LC_COLLATE; }
+<subs>with { BEGIN(subs2); return WITH; }
+<INITIAL>order return ORDER;
+<INITIAL,ldef>charmap BEGIN(charmap);
+<INITIAL>;[ \t]*\.\.\.[ \t]*; return RANGE;
+<INITIAL,nchar,subs>\\([0-7]{3}) {
+ u_int v;
+
+ sscanf(&yytext[1], "%o", &v);
+ yylval.ch = v;
+ return CHAR;
+}
+<INITIAL,nchar,subs>\\x\{([0-9a-fA-F]{2,8})\} {
+ u_int v;
+
+ sscanf(&yytext[3], "%x", &v);
+ yylval.ch = v;
+ return CHAR;
+}
+<INITIAL,nchar,subs>\\x([0-9a-fA-F]{2}) {
+ u_int v;
+
+ sscanf(&yytext[2], "%x", &v);
+ yylval.ch = v;
+ return CHAR;
+}
+<INITIAL,nchar,subs>\\. { yylval.ch = yytext[1]; return CHAR; }
+<INITIAL,nchar,subs>. { yylval.ch = *(u_char *)yytext; return CHAR; }
+<defn>^\n line_no++;
+<defn>[ \t]+ {
+ if (ptr == buf)
+ errx(EX_UNAVAILABLE, "map expected near line %u of %s",
+ line_no, map_name);
+ *ptr = 0;
+ if (localedefmode && *buf == '<' && ptr[-1] == '>') {
+ if (ptr == buf + 2)
+ errx(EX_UNAVAILABLE, "map expected near line %u of %s",
+ line_no, map_name);
+ *--ptr = 0;
+ wcscpy(yylval.str, buf + 1);
+ } else
+ wcscpy(yylval.str, buf);
+ BEGIN(nchar);
+ return DEFN;
+}
+<s_name,elem>\/\/ {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "name buffer overflow near line %u, character '/'",
+ line_no);
+ *ptr++ = '/';
+}
+<s_name,elem>\/\> {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "name buffer overflow near line %u, character '>'",
+ line_no);
+ *ptr++ = '>';
+}
+<string>\\\" {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\"'",
+ line_no);
+ *ptr++ = '"';
+}
+<elem>\> {
+ if (ptr == buf)
+ errx(EX_UNAVAILABLE, "non-empty name expected near line %u",
+ line_no);
+ *ptr = 0;
+ wcscpy(yylval.str, buf);
+ BEGIN(ldef);
+ return ELEM;
+}
+<s_name>\> {
+ struct symbol *s;
+
+ if (ptr == buf)
+ errx(EX_UNAVAILABLE, "non-empty name expected near line %u",
+ line_no);
+ *ptr = 0;
+ s = getsymbol(buf, EXISTS);
+ switch (s->type) {
+ case SYMBOL_CHAR:
+ break;
+ case SYMBOL_CHAIN:
+ errx(EX_UNAVAILABLE, "name <%s> is chain type near line %u",
+ showwcs(buf, CHARMAP_SYMBOL_LEN), line_no);
+ case SYMBOL_SYMBOL:
+ errx(EX_UNAVAILABLE, "name <%s> is symbol type near line %u",
+ showwcs(buf, CHARMAP_SYMBOL_LEN), line_no);
+ default:
+ errx(EX_UNAVAILABLE, "name <%s>: unknown symbol type (%d) near line %u",
+ showwcs(buf, CHARMAP_SYMBOL_LEN), s->type, line_no);
+ }
+ if (localedefmode) {
+ ptr = ptrsave;
+ buf = buf0;
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character <%s>",
+ line_no, showwcs(bufstr, CHARMAP_SYMBOL_LEN));
+ *ptr++ = s->u.wc;
+ BEGIN(string);
+ } else {
+ yylval.ch = s->u.wc;
+ if (fromsubs)
+ BEGIN(subs);
+ else
+ BEGIN(INITIAL);
+ return CHAR;
+ }
+}
+<string>\" {
+ *ptr = 0;
+ wcscpy(yylval.str, buf);
+ if (localedefmode)
+ BEGIN(ldef);
+ else
+ BEGIN(subs2);
+ return STRING;
+}
+<s_name,defn,elem>. {
+ const char *s = (map_fp != NULL) ? map_name : "input";
+
+ if (!isascii(*yytext) || !isprint(*yytext))
+ errx(EX_UNAVAILABLE, "non-ASCII or non-printable character 0x%02x not allowed in the map/name near line %u of %s",
+ *yytext, line_no, s);
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "map/name buffer overflow near line %u of %s, character '%c'",
+ line_no, s, *yytext);
+ *ptr++ = *yytext;
+}
+<string>\\t {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\t'",
+ line_no);
+ *ptr++ = '\t';
+}
+<string>\\b {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\b'",
+ line_no);
+ *ptr++ = '\b';
+}
+<string>\\f {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\f'",
+ line_no);
+ *ptr++ = '\f';
+}
+<string>\\v {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\v'",
+ line_no);
+ *ptr++ = '\v';
+}
+<string>\\n {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\n'",
+ line_no);
+ *ptr++ = '\n';
+}
+<string>\\r {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\r'",
+ line_no);
+ *ptr++ = '\r';
+}
+<string>\\a {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '\\a'",
+ line_no);
+ *ptr++ = '\a';
+}
+<s_name,string,defn,elem>\n {
+ const char *s = (map_fp != NULL) ? map_name : "input";
+
+ errx(EX_UNAVAILABLE, "unterminated map/name/string near line %u of %s", line_no, s);
+}
+<s_name,string,nchar,elem><<EOF>> {
+ const char *s = (map_fp != NULL) ? map_name : "input";
+
+ errx(EX_UNAVAILABLE, "premature EOF in the name/string/char near line %u of %s", line_no, s);
+}
+<string>\\x\{([0-9a-f]{2,8})\} {
+ u_int v;
+
+ sscanf(&yytext[3], "%x", &v);
+ *ptr++ = v;
+}
+<string>\\x([0-9a-f]{2}) {
+ u_int v;
+
+ sscanf(&yytext[2], "%x", &v);
+ *ptr++ = v;
+}
+<string>\\([0-7]{3}) {
+ u_int v;
+
+ sscanf(&yytext[1], "%o", &v);
+ *ptr++ = v;
+}
+<string>\\. {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '%c'",
+ line_no, yytext[1]);
+ *ptr++ = yytext[1];
+}
+<string>. {
+ if(ptr >= buf + BUFSIZE - 1)
+ errx(EX_UNAVAILABLE, "string buffer overflow near line %u, character '%c'",
+ line_no, *yytext);
+ *ptr++ = *yytext;
+}
+<charmap>[^ \t\n]+ {
+ if(*yytext == '/')
+ strcpy(map_name, yytext);
+ else {
+ strcat(map_name, "/");
+ strcat(map_name, yytext);
+ }
+ if((map_fp = fopen(map_name, "r")) == NULL)
+ err(EX_UNAVAILABLE, "can't open 'charmap' file %s",
+ map_name);
+ save_no = line_no;
+ line_no = 1;
+ map_buf = yy_new_buffer(map_fp, YY_BUF_SIZE);
+ main_buf = YY_CURRENT_BUFFER;
+ yy_switch_to_buffer(map_buf);
+ ptr = buf;
+ BEGIN(defn);
+}
+<charmap>\n {
+ errx(EX_UNAVAILABLE, "'charmap' file name expected near line %u",
+ line_no);
+}
+<charmap><<EOF>> {
+ errx(EX_UNAVAILABLE, "'charmap' file name expected near line %u",
+ line_no);
+}
+<INITIAL,defn><<EOF>> {
+ if(map_fp != NULL) {
+ if (ptr != buf)
+ errx(EX_UNAVAILABLE, "premature EOF in the map near line %u of %s", line_no, map_name);
+ yy_switch_to_buffer(main_buf);
+ yy_delete_buffer(map_buf);
+ fclose(map_fp);
+ map_fp = NULL;
+ line_no = save_no;
+ if (localedefmode)
+ BEGIN(ldef);
+ else
+ BEGIN(INITIAL);
+ } else
+ yyterminate();
+}
+%%
+#ifdef FLEX_DEBUG
+main()
+{
+ while(yylex())
+ ;
+ return 0;
+}
+#endif /* FLEX_DEBUG */
diff --git a/adv_cmds/finger/extern.h b/adv_cmds/finger/extern.h
new file mode 100644
index 0000000..7b8f29c
--- /dev/null
+++ b/adv_cmds/finger/extern.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/28/95
+ * $FreeBSD: src/usr.bin/finger/extern.h,v 1.10 2005/09/19 10:11:46 dds Exp $
+ */
+
+#ifndef _EXTERN_H_
+#define _EXTERN_H_
+
+extern char tbuf[1024]; /* Temp buffer for anybody. */
+extern int entries; /* Number of people. */
+extern DB *db; /* Database. */
+extern int d_first;
+extern sa_family_t family;
+extern int gflag;
+extern int lflag;
+extern time_t now;
+extern int oflag;
+extern int pplan; /* don't show .plan/.project */
+#ifndef __APPLE__
+extern int Tflag;
+#endif
+extern int invoker_root; /* Invoked by root */
+
+void enter_lastlog(PERSON *);
+PERSON *enter_person(struct passwd *);
+void enter_where(struct utmpx *, PERSON *);
+PERSON *find_person(const char *);
+int hide(struct passwd *);
+void lflag_print(void);
+int match(struct passwd *, const char *);
+void netfinger(char *);
+PERSON *palloc(void);
+char *prphone(char *);
+void sflag_print(void);
+int show_text(const char *, const char *, const char *);
+
+#endif /* !_EXTERN_H_ */
diff --git a/adv_cmds/finger/finger.1 b/adv_cmds/finger/finger.1
new file mode 100644
index 0000000..4fbdfeb
--- /dev/null
+++ b/adv_cmds/finger/finger.1
@@ -0,0 +1,257 @@
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)finger.1 8.3 (Berkeley) 5/5/94
+.\" $FreeBSD: src/usr.bin/finger/finger.1,v 1.31 2005/09/19 10:11:46 dds Exp $
+.\"
+.Dd July 17, 2004
+.Dt FINGER 1
+.Os
+.Sh NAME
+.Nm finger
+.Nd user information lookup program
+.Sh SYNOPSIS
+.Nm
+.Op Fl 46gklmpsho
+.Op Ar user ...\&
+.Op Ar user@host ...\&
+.Sh DESCRIPTION
+The
+.Nm
+utility displays information about the system users.
+.Pp
+Options are:
+.Bl -tag -width indent
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl g
+This option restricts the gecos output to only the users' real
+name.
+It also has the side-effect of restricting the output
+of the remote host when used in conjunction with the
+.Fl h
+option.
+.It Fl h
+When used in conjunction with the
+.Fl s
+option, the name of the remote host is displayed instead of the office
+location and office phone.
+.It Fl k
+Disable all use of
+.Xr utmpx 5 .
+.It Fl l
+Produce a multi-line format displaying all of the information
+described for the
+.Fl s
+option as well as the user's home directory, home phone number, login
+shell, mail status, and the contents of the files
+.Pa .forward ,
+.Pa .plan ,
+.Pa .project
+and
+.Pa .pubkey
+from the user's home directory.
+.Pp
+If idle time is at least a minute and less than a day, it is
+presented in the form ``hh:mm''.
+Idle times greater than a day are presented as ``d day[s]hh:mm''.
+.Pp
+Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''.
+Numbers specified as ten or seven digits are printed as the appropriate
+subset of that string.
+Numbers specified as five digits are printed as ``xN-NNNN''.
+Numbers specified as four digits are printed as ``xNNNN''.
+.Pp
+If write permission is denied to the device, the phrase ``(messages off)''
+is appended to the line containing the device name.
+One entry per user is displayed with the
+.Fl l
+option; if a user is logged on multiple times, terminal information
+is repeated once per login.
+.Pp
+Mail status is shown as ``No Mail.'' if there is no mail at all, ``Mail
+last read DDD MMM ## HH:MM YYYY (TZ)'' if the person has looked at their
+mailbox since new mail arriving, or ``New mail received ...'', ``Unread
+since ...'' if they have new mail.
+.It Fl m
+Prevent matching of
+.Ar user
+names.
+.Ar User
+is usually a login name; however, matching will also be done on the
+users' real names, unless the
+.Fl m
+option is supplied.
+All name matching performed by
+.Nm
+is case insensitive.
+.It Fl o
+When used in conjunction with the
+.Fl s
+option, the office location and office phone information is displayed
+instead of the name of the remote host.
+.It Fl p
+Prevent
+the
+.Fl l
+option of
+.Nm
+from displaying the contents of the
+.Pa .forward ,
+.Pa .plan ,
+.Pa .project
+and
+.Pa .pubkey
+files.
+.It Fl s
+Display the user's login name, real name, terminal name and write
+status (as a ``*'' before the terminal name if write permission is
+denied), idle time, login time, and either office location and office
+phone number, or the remote host.
+If
+.Fl o
+is given, the office location and office phone number is printed
+(the default).
+If
+.Fl h
+is given, the remote host is printed instead.
+.Pp
+Idle time is in minutes if it is a single integer, hours and minutes
+if a ``:'' is present, or days if a ``d'' is present.
+If it is an
+.Dq * ,
+the login time indicates the time of last login.
+Login time is displayed as the day name if less than 6 days, else month, day;
+hours and minutes, unless more than six months ago, in which case the year
+is displayed rather than the hours and minutes.
+.Pp
+Unknown devices as well as nonexistent idle and login times are
+displayed as single asterisks.
+.El
+.Pp
+If no options are specified,
+.Nm
+defaults to the
+.Fl l
+style output if operands are provided, otherwise to the
+.Fl s
+style.
+Note that some fields may be missing, in either format, if information
+is not available for them.
+.Pp
+If no arguments are specified,
+.Nm
+will print an entry for each user currently logged into the system.
+.Pp
+The
+.Nm
+utility may be used to look up users on a remote machine.
+The format is to specify a
+.Ar user
+as
+.Dq Li user@host ,
+or
+.Dq Li @host ,
+where the default output
+format for the former is the
+.Fl l
+style, and the default output format for the latter is the
+.Fl s
+style.
+The
+.Fl l
+option is the only option that may be passed to a remote machine.
+.Pp
+If the file
+.Pa .nofinger
+exists in the user's home directory,
+and the program is not run with superuser privileges,
+.Nm
+behaves as if the user in question does not exist.
+.Pp
+The optional
+.Xr finger.conf 5
+configuration file can be used to specify aliases.
+Since
+.Nm
+is invoked by
+.Xr fingerd 8 ,
+aliases will work for both local and network queries.
+.Sh ENVIRONMENT
+The
+.Nm
+utility utilizes the following environment variable, if it exists:
+.Bl -tag -width Fl
+.It Ev FINGER
+This variable may be set with favored options to
+.Nm .
+.El
+.Sh FILES
+.Bl -tag -width /var/log/lastlog -compact
+.It Pa /etc/finger.conf
+alias definition data base
+.It Pa /var/log/lastlog
+last login data base
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr w 1 ,
+.Xr who 1 ,
+.Xr finger.conf 5 ,
+.Xr fingerd 8
+.Rs
+.%A D. Zimmerman
+.%T The Finger User Information Protocol
+.%R RFC 1288
+.%D December, 1991
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
+.Sh BUGS
+The current FINGER protocol RFC requires that the client keep the connection
+fully open until the server closes.
+This prevents the use of the optimal
+three-packet T/TCP exchange.
+(Servers which depend on this requirement are
+bogus but have nonetheless been observed in the Internet at large.)
+.Pp
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/adv_cmds/finger/finger.c b/adv_cmds/finger/finger.c
new file mode 100644
index 0000000..0cbb887
--- /dev/null
+++ b/adv_cmds/finger/finger.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Luke Mewburn <lm@rmit.edu.au> added the following on 940622:
+ * - mail status ("No Mail", "Mail read:...", or "New Mail ...,
+ * Unread since ...".)
+ * - 4 digit phone extensions (3210 is printed as x3210.)
+ * - host/office toggling in short format with -h & -o.
+ * - short day names (`Tue' printed instead of `Jun 21' if the
+ * login time is < 6 days.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/finger.c,v 1.36 2005/09/19 10:11:46 dds Exp $");
+
+/*
+ * Finger prints out information about users. It is not portable since
+ * certain fields (e.g. the full user name, office, and phone numbers) are
+ * extracted from the gecos field of the passwd file which other UNIXes
+ * may not have or may use for other things.
+ *
+ * There are currently two output formats; the short format is one line
+ * per user and displays login name, tty, login time, real name, idle time,
+ * and either remote host information (default) or office location/phone
+ * number, depending on if -h or -o is used respectively.
+ * The long format gives the same information (in a more legible format) as
+ * well as home directory, shell, mail info, and .plan/.project files.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <db.h>
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include <locale.h>
+
+#include "finger.h"
+#include "pathnames.h"
+
+DB *db;
+time_t now;
+int entries, gflag, kflag, lflag, mflag, pplan, sflag, oflag, Tflag;
+sa_family_t family = PF_UNSPEC;
+int d_first = -1;
+char tbuf[1024];
+int invoker_root = 0;
+
+static void loginlist(void);
+static int option(int, char **);
+static void usage(void);
+static void userlist(int, char **);
+
+static int
+option(int argc, char **argv)
+{
+ int ch;
+
+ optind = 1; /* reset getopt */
+
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "46gklmpsho")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "46gklmpshoT")) != -1)
+#endif
+ switch(ch) {
+ case '4':
+ family = AF_INET;
+ break;
+ case '6':
+ family = AF_INET6;
+ break;
+ case 'g':
+ gflag = 1;
+ break;
+ case 'k':
+ kflag = 1; /* keep going without utmpx */
+ break;
+ case 'l':
+ lflag = 1; /* long format */
+ break;
+ case 'm':
+ mflag = 1; /* force exact match of names */
+ break;
+ case 'p':
+ pplan = 1; /* don't show .plan/.project */
+ break;
+ case 's':
+ sflag = 1; /* short format */
+ break;
+ case 'h':
+ oflag = 0; /* remote host info */
+ break;
+ case 'o':
+ oflag = 1; /* office info */
+ break;
+#ifndef __APPLE__
+ case 'T':
+ Tflag = 1; /* disable T/TCP */
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+
+ return optind;
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: finger [-46gklmpshoT] [user ...] [user@host ...]\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int envargc, argcnt;
+ char *envargv[3];
+ struct passwd *pw;
+ static char myname[] = "finger";
+
+ if (getuid() == 0 || geteuid() == 0) {
+ invoker_root = 1;
+ if ((pw = getpwnam(UNPRIV_NAME)) && pw->pw_uid > 0) {
+ setgid(pw->pw_gid);
+ setuid(pw->pw_uid);
+ } else {
+ setgid(UNPRIV_UGID);
+ setuid(UNPRIV_UGID);
+ }
+ }
+
+ (void) setlocale(LC_ALL, "");
+
+ /* remove this line to get remote host */
+ oflag = 1; /* default to old "office" behavior */
+
+ /*
+ * Process environment variables followed by command line arguments.
+ */
+ if ((envargv[1] = getenv("FINGER"))) {
+ envargc = 2;
+ envargv[0] = myname;
+ envargv[2] = NULL;
+ (void) option(envargc, envargv);
+ }
+
+ argcnt = option(argc, argv);
+ argc -= argcnt;
+ argv += argcnt;
+
+ (void)time(&now);
+ setpassent(1);
+ if (!*argv) {
+ /*
+ * Assign explicit "small" format if no names given and -l
+ * not selected. Force the -s BEFORE we get names so proper
+ * screening will be done.
+ */
+ if (!lflag)
+ sflag = 1; /* if -l not explicit, force -s */
+ loginlist();
+ if (entries == 0)
+ (void)printf("No one logged on.\n");
+ } else {
+ userlist(argc, argv);
+ /*
+ * Assign explicit "large" format if names given and -s not
+ * explicitly stated. Force the -l AFTER we get names so any
+ * remote finger attempts specified won't be mishandled.
+ */
+ if (!sflag)
+ lflag = 1; /* if -s not explicit, force -l */
+ }
+ if (entries) {
+ if (lflag)
+ lflag_print();
+ else
+ sflag_print();
+ }
+ return (0);
+}
+
+static void
+loginlist(void)
+{
+ PERSON *pn;
+ DBT data, key;
+ struct passwd *pw;
+ struct utmpx *user;
+ int r, sflag1;
+ char name[_UTX_USERSIZE + 1];
+
+ if (kflag)
+ errx(1, "can't list logins without reading utmpx");
+
+ setutxent();
+ name[_UTX_USERSIZE] = '\0';
+ while ((user = getutxent()) != NULL) {
+ if (!user->ut_user[0] || user->ut_type != USER_PROCESS)
+ continue;
+ if ((pn = find_person(user->ut_user)) == NULL) {
+ bcopy(user->ut_user, name, _UTX_USERSIZE);
+ if ((pw = getpwnam(name)) == NULL)
+ continue;
+ if (hide(pw))
+ continue;
+ pn = enter_person(pw);
+ }
+ enter_where(user, pn);
+ }
+ endutxent();
+ if (db && lflag)
+ for (sflag1 = R_FIRST;; sflag1 = R_NEXT) {
+ PERSON *tmp;
+
+ r = (*db->seq)(db, &key, &data, sflag1);
+ if (r == -1)
+ err(1, "db seq");
+ if (r == 1)
+ break;
+ memmove(&tmp, data.data, sizeof tmp);
+ enter_lastlog(tmp);
+ }
+}
+
+static void
+userlist(int argc, char **argv)
+{
+ PERSON *pn;
+ DBT data, key;
+ struct utmpx *user;
+ struct passwd *pw;
+ int r, sflag1, *used, *ip;
+ char **ap, **nargv, **np, **p;
+ FILE *conf_fp;
+ char conf_alias[LINE_MAX];
+ char *conf_realname;
+ int conf_length;
+
+ if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL ||
+ (used = calloc(argc, sizeof(int))) == NULL)
+ err(1, NULL);
+
+ /* Pull out all network requests. */
+ for (ap = p = argv, np = nargv; *p; ++p)
+ if (index(*p, '@'))
+ *np++ = *p;
+ else
+ *ap++ = *p;
+
+ *np++ = NULL;
+ *ap++ = NULL;
+
+ if (!*argv)
+ goto net;
+
+ /*
+ * Mark any arguments beginning with '/' as invalid so that we
+ * don't accidently confuse them with expansions from finger.conf
+ */
+ for (p = argv, ip = used; *p; ++p, ++ip)
+ if (**p == '/') {
+ *ip = 1;
+ warnx("%s: no such user", *p);
+ }
+
+ /*
+ * Traverse the finger alias configuration file of the form
+ * alias:(user|alias), ignoring comment lines beginning '#'.
+ */
+ if ((conf_fp = fopen(_PATH_FINGERCONF, "r")) != NULL) {
+ while(fgets(conf_alias, sizeof(conf_alias), conf_fp) != NULL) {
+ conf_length = strlen(conf_alias);
+ if (*conf_alias == '#' || conf_alias[--conf_length] != '\n')
+ continue;
+ conf_alias[conf_length] = '\0'; /* Remove trailing LF */
+ if ((conf_realname = strchr(conf_alias, ':')) == NULL)
+ continue;
+ *conf_realname = '\0'; /* Replace : with NUL */
+ for (p = argv; *p; ++p) {
+ if (strcmp(*p, conf_alias) == 0) {
+ if ((*p = strdup(conf_realname+1)) == NULL) {
+ err(1, NULL);
+ }
+ }
+ }
+ }
+ (void)fclose(conf_fp);
+ }
+
+ /*
+ * Traverse the list of possible login names and check the login name
+ * and real name against the name specified by the user. If the name
+ * begins with a '/', try to read the file of that name instead of
+ * gathering the traditional finger information.
+ */
+ if (mflag)
+ for (p = argv, ip = used; *p; ++p, ++ip) {
+ if (**p != '/' || *ip == 1 || !show_text("", *p, "")) {
+ if (((pw = getpwnam(*p)) != NULL) && !hide(pw))
+ enter_person(pw);
+ else if (!*ip)
+ warnx("%s: no such user", *p);
+ }
+ }
+ else {
+ while ((pw = getpwent()) != NULL) {
+ for (p = argv, ip = used; *p; ++p, ++ip)
+ if (**p == '/' && *ip != 1
+ && show_text("", *p, ""))
+ *ip = 1;
+ else if (match(pw, *p) && !hide(pw)) {
+ enter_person(pw);
+ *ip = 1;
+ }
+ }
+ for (p = argv, ip = used; *p; ++p, ++ip)
+ if (!*ip)
+ warnx("%s: no such user", *p);
+ }
+
+ /* Handle network requests. */
+net: for (p = nargv; *p;) {
+ netfinger(*p++);
+ if (*p || entries)
+ printf("\n");
+ }
+
+ if (entries == 0)
+ return;
+
+ if (kflag)
+ return;
+
+ /*
+ * Scan thru the list of users currently logged in, saving
+ * appropriate data whenever a match occurs.
+ */
+ setutxent();
+ while ((user = getutxent()) != NULL) {
+ if (!user->ut_user && user->ut_type != USER_PROCESS)
+ continue;
+ if ((pn = find_person(user->ut_user)) == NULL)
+ continue;
+ enter_where(user, pn);
+ }
+ endutxent();
+ if (db)
+ for (sflag1 = R_FIRST;; sflag1 = R_NEXT) {
+ PERSON *tmp;
+
+ r = (*db->seq)(db, &key, &data, sflag1);
+ if (r == -1)
+ err(1, "db seq");
+ if (r == 1)
+ break;
+ memmove(&tmp, data.data, sizeof tmp);
+ enter_lastlog(tmp);
+ }
+}
diff --git a/adv_cmds/finger/finger.conf.5 b/adv_cmds/finger/finger.conf.5
new file mode 100644
index 0000000..83ebc5b
--- /dev/null
+++ b/adv_cmds/finger/finger.conf.5
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2000 Mark Knight <markk@knigma.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/finger/finger.conf.5,v 1.6 2005/02/09 18:04:22 ru Exp $
+.\"
+.Dd August 16, 2000
+.Dt FINGER.CONF 5
+.Os
+.Sh NAME
+.Nm finger.conf
+.Nd
+.Xr finger 1
+alias configuration file
+.Sh DESCRIPTION
+The optional
+.Nm
+file is used to provide aliases that can be fingered by local
+and network users.
+This may be useful where a user's login name is not the same
+as their preferred mail address, or for providing virtual login names
+than can be fingered.
+.Pp
+Lines beginning with ``#'' are comments.
+Other lines must consist of an
+alias name and a target name separated by a colon.
+A target name should be either a user, a forward
+reference to another alias or the path of a world readable file.
+.Pp
+Where an alias points to a file, the contents of that file will be displayed
+when the alias is fingered.
+.Sh FILES
+.Bl -tag -width /etc/finger.conf -compact
+.It Pa /etc/finger.conf
+.Xr finger 1
+alias definition data base
+.El
+.Sh EXAMPLES
+.Bd -literal
+# /etc/finger.conf alias definition file
+#
+# Format alias:(user|alias)
+#
+# Individual aliases
+#
+markk:mkn
+john.smith:dev329
+john:dev329
+sue:/etc/finger/sue.txt
+#
+# Network status message
+#
+status:/usr/local/etc/status.txt
+#
+# Administrative redirects
+#
+root:admin
+postmaster:admin
+abuse:admin
+#
+# For the time being, 'sod' is sysadmin.
+#
+admin:sod
+.Ed
+.Sh SEE ALSO
+.Xr finger 1
+.Sh HISTORY
+Support for the
+.Nm
+file was submitted by Mark Knight <markk@knigma.org> and first appeared in
+.Fx 4.2 .
diff --git a/adv_cmds/finger/finger.h b/adv_cmds/finger/finger.h
new file mode 100644
index 0000000..19b30fb
--- /dev/null
+++ b/adv_cmds/finger/finger.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)finger.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/finger/finger.h,v 1.5 2004/03/14 06:43:34 jmallett Exp $
+ */
+
+#ifndef _FINGER_H_
+#define _FINGER_H_
+
+typedef struct person {
+ uid_t uid; /* user id */
+ char *dir; /* user's home directory */
+ char *homephone; /* pointer to home phone no. */
+ char *name; /* login name */
+ char *office; /* pointer to office name */
+ char *officephone; /* pointer to office phone no. */
+ char *realname; /* pointer to full name */
+ char *shell; /* user's shell */
+ time_t mailread; /* last time mail was read */
+ time_t mailrecv; /* last time mail was received */
+ struct where *whead, *wtail; /* list of where user is or has been */
+} PERSON;
+
+enum status { LASTLOG, LOGGEDIN };
+
+typedef struct where {
+ struct where *next; /* next place user is or has been */
+ enum status info; /* type/status of request */
+ short writable; /* tty is writable */
+ time_t loginat; /* time of (last) login */
+ time_t idletime; /* how long idle (if logged in) */
+ char tty[_UTX_LINESIZE+1]; /* null terminated tty line */
+ char host[_UTX_HOSTSIZE+1]; /* null terminated remote host name */
+} WHERE;
+
+#define UNPRIV_NAME "nobody" /* Preferred privilege level */
+#define UNPRIV_UGID 32767 /* Default uid and gid */
+#define OUTPUT_MAX 100000 /* Do not keep listinging forever */
+#define TIME_LIMIT 360 /* Do not keep listinging forever */
+
+#define UT_NAMESIZE 8 /* old utmp.h value */
+
+#include "extern.h"
+
+#endif /* !_FINGER_H_ */
diff --git a/adv_cmds/finger/lprint.c b/adv_cmds/finger/lprint.c
new file mode 100644
index 0000000..6e9b42d
--- /dev/null
+++ b/adv_cmds/finger/lprint.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/lprint.c,v 1.25 2004/03/14 06:43:34 jmallett Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <db.h>
+#include <err.h>
+#include <fcntl.h>
+#include <langinfo.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include "finger.h"
+#include "pathnames.h"
+
+#define LINE_LEN 80
+#define TAB_LEN 8 /* 8 spaces between tabs */
+
+static int demi_print(char *, int);
+static void lprint(PERSON *);
+static void vputc(unsigned char);
+
+void
+lflag_print(void)
+{
+ PERSON *pn;
+ int sflag, r;
+ PERSON *tmp;
+ DBT data, key;
+
+ for (sflag = R_FIRST;; sflag = R_NEXT) {
+ r = (*db->seq)(db, &key, &data, sflag);
+ if (r == -1)
+ err(1, "db seq");
+ if (r == 1)
+ break;
+ memmove(&tmp, data.data, sizeof tmp);
+ pn = tmp;
+ if (sflag != R_FIRST)
+ putchar('\n');
+ lprint(pn);
+ if (!pplan) {
+ (void)show_text(pn->dir,
+ _PATH_FORWARD, "Mail forwarded to");
+ (void)show_text(pn->dir, _PATH_PROJECT, "Project");
+ if (!show_text(pn->dir, _PATH_PLAN, "Plan"))
+ (void)printf("No Plan.\n");
+ (void)show_text(pn->dir,
+ _PATH_PUBKEY, "Public key");
+ }
+ }
+}
+
+static void
+lprint(PERSON *pn)
+{
+ struct tm *delta;
+ WHERE *w;
+ int cpr, len, maxlen;
+ struct tm *tp;
+ int oddfield;
+ char t[80];
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ /*
+ * long format --
+ * login name
+ * real name
+ * home directory
+ * shell
+ * office, office phone, home phone if available
+ * mail status
+ */
+ (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s",
+ pn->name, pn->realname, pn->dir);
+ (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL);
+
+ if (gflag)
+ goto no_gecos;
+ /*
+ * try and print office, office phone, and home phone on one line;
+ * if that fails, do line filling so it looks nice.
+ */
+#define OFFICE_TAG "Office"
+#define OFFICE_PHONE_TAG "Office Phone"
+ oddfield = 0;
+ if (pn->office && pn->officephone &&
+ strlen(pn->office) + strlen(pn->officephone) +
+ sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) {
+ (void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s",
+ OFFICE_TAG, pn->office, prphone(pn->officephone));
+ oddfield = demi_print(tbuf, oddfield);
+ } else {
+ if (pn->office) {
+ (void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
+ OFFICE_TAG, pn->office);
+ oddfield = demi_print(tbuf, oddfield);
+ }
+ if (pn->officephone) {
+ (void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
+ OFFICE_PHONE_TAG, prphone(pn->officephone));
+ oddfield = demi_print(tbuf, oddfield);
+ }
+ }
+ if (pn->homephone) {
+ (void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone",
+ prphone(pn->homephone));
+ oddfield = demi_print(tbuf, oddfield);
+ }
+ if (oddfield)
+ putchar('\n');
+
+no_gecos:
+ /*
+ * long format con't:
+ * if logged in
+ * terminal
+ * idle time
+ * if messages allowed
+ * where logged in from
+ * if not logged in
+ * when last logged in
+ */
+ /* find out longest device name for this user for formatting */
+ for (w = pn->whead, maxlen = -1; w != NULL; w = w->next)
+ if ((len = strlen(w->tty)) > maxlen)
+ maxlen = len;
+ /* find rest of entries for user */
+ for (w = pn->whead; w != NULL; w = w->next) {
+ if (w->info == LOGGEDIN) {
+ tp = localtime(&w->loginat);
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R (%Z)" : "%a %b %e %R (%Z)",
+ tp);
+ cpr = printf("On since %s on %s", t, w->tty);
+ /*
+ * idle time is tough; if have one, print a comma,
+ * then spaces to pad out the device name, then the
+ * idle time. Follow with a comma if a remote login.
+ */
+ delta = gmtime(&w->idletime);
+ if (w->idletime != -1 && (delta->tm_yday ||
+ delta->tm_hour || delta->tm_min)) {
+ cpr += printf("%-*s idle ",
+ maxlen - (int)strlen(w->tty) + 1, ",");
+ if (delta->tm_yday > 0) {
+ cpr += printf("%d day%s ",
+ delta->tm_yday,
+ delta->tm_yday == 1 ? "" : "s");
+ }
+ cpr += printf("%d:%02d",
+ delta->tm_hour, delta->tm_min);
+ if (*w->host) {
+ putchar(',');
+ ++cpr;
+ }
+ }
+ if (!w->writable)
+ cpr += printf(" (messages off)");
+ } else if (w->loginat == 0) {
+ cpr = printf("Never logged in.");
+ } else {
+ tp = localtime(&w->loginat);
+ if (now - w->loginat > 86400 * 365 / 2) {
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R %Y (%Z)" :
+ "%a %b %e %R %Y (%Z)",
+ tp);
+ } else {
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R (%Z)" :
+ "%a %b %e %R (%Z)",
+ tp);
+ }
+ cpr = printf("Last login %s on %s", t, w->tty);
+ }
+ if (*w->host) {
+ if (LINE_LEN < (cpr + 6 + strlen(w->host)))
+ (void)printf("\n ");
+ (void)printf(" from %s", w->host);
+ }
+ putchar('\n');
+ }
+ if (pn->mailrecv == -1)
+ printf("No Mail.\n");
+ else if (pn->mailrecv > pn->mailread) {
+ tp = localtime(&pn->mailrecv);
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R %Y (%Z)" :
+ "%a %b %e %R %Y (%Z)",
+ tp);
+ printf("New mail received %s\n", t);
+ tp = localtime(&pn->mailread);
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R %Y (%Z)" :
+ "%a %b %e %R %Y (%Z)",
+ tp);
+ printf(" Unread since %s\n", t);
+ } else {
+ tp = localtime(&pn->mailread);
+ strftime(t, sizeof(t),
+ d_first ? "%a %e %b %R %Y (%Z)" :
+ "%a %b %e %R %Y (%Z)",
+ tp);
+ printf("Mail last read %s\n", t);
+ }
+}
+
+static int
+demi_print(char *str, int oddfield)
+{
+ static int lenlast;
+ int lenthis, maxlen;
+
+ lenthis = strlen(str);
+ if (oddfield) {
+ /*
+ * We left off on an odd number of fields. If we haven't
+ * crossed the midpoint of the screen, and we have room for
+ * the next field, print it on the same line; otherwise,
+ * print it on a new line.
+ *
+ * Note: we insist on having the right hand fields start
+ * no less than 5 tabs out.
+ */
+ maxlen = 5 * TAB_LEN;
+ if (maxlen < lenlast)
+ maxlen = lenlast;
+ if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) +
+ lenthis) <= LINE_LEN) {
+ while(lenlast < (4 * TAB_LEN)) {
+ putchar('\t');
+ lenlast += TAB_LEN;
+ }
+ (void)printf("\t%s\n", str); /* force one tab */
+ } else {
+ (void)printf("\n%s", str); /* go to next line */
+ oddfield = !oddfield; /* this'll be undone below */
+ }
+ } else
+ (void)printf("%s", str);
+ oddfield = !oddfield; /* toggle odd/even marker */
+ lenlast = lenthis;
+ return(oddfield);
+}
+
+int
+show_text(const char *directory, const char *file_name, const char *header)
+{
+ struct stat sb;
+ FILE *fp;
+ int ch, cnt;
+ char *p, lastc;
+ int fd, nr;
+
+ lastc = '\0';
+
+ (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name);
+ if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) ||
+ sb.st_size == 0)
+ return(0);
+
+ /* If short enough, and no newlines, show it on a single line.*/
+ if (sb.st_size <= LINE_LEN - strlen(header) - 5) {
+ nr = read(fd, tbuf, sizeof(tbuf));
+ if (nr <= 0) {
+ (void)close(fd);
+ return(0);
+ }
+ for (p = tbuf, cnt = nr; cnt--; ++p)
+ if (*p == '\n')
+ break;
+ if (cnt <= 1) {
+ if (*header != '\0')
+ (void)printf("%s: ", header);
+ for (p = tbuf, cnt = nr; cnt--; ++p)
+ if (*p != '\r')
+ vputc(lastc = *p);
+ if (lastc != '\n')
+ (void)putchar('\n');
+ (void)close(fd);
+ return(1);
+ }
+ else
+ (void)lseek(fd, 0L, SEEK_SET);
+ }
+ if ((fp = fdopen(fd, "r")) == NULL)
+ return(0);
+ if (*header != '\0')
+ (void)printf("%s:\n", header);
+ while ((ch = getc(fp)) != EOF)
+ if (ch != '\r')
+ vputc(lastc = ch);
+ if (lastc != '\n')
+ (void)putchar('\n');
+ (void)fclose(fp);
+ return(1);
+}
+
+static void
+vputc(unsigned char ch)
+{
+ int meta;
+
+ if (!isprint(ch) && !isascii(ch)) {
+ (void)putchar('M');
+ (void)putchar('-');
+ ch = toascii(ch);
+ meta = 1;
+ } else
+ meta = 0;
+ if (isprint(ch) || (!meta && (ch == ' ' || ch == '\t' || ch == '\n')))
+ (void)putchar(ch);
+ else {
+ (void)putchar('^');
+ (void)putchar(ch == '\177' ? '?' : ch | 0100);
+ }
+}
diff --git a/adv_cmds/finger/net.c b/adv_cmds/finger/net.c
new file mode 100644
index 0000000..cf0699d
--- /dev/null
+++ b/adv_cmds/finger/net.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)net.c 8.4 (Berkeley) 4/28/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/net.c,v 1.23 2004/05/16 22:08:15 stefanf Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <ctype.h>
+#include <db.h>
+#include <err.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include "finger.h"
+
+static void cleanup(int sig);
+static int do_protocol(const char *name, const struct addrinfo *ai);
+static void trying(const struct addrinfo *ai);
+
+void
+netfinger(char *name)
+{
+ int error, multi;
+ char *host;
+ struct addrinfo *ai, *ai0;
+ static struct addrinfo hint;
+
+ host = strrchr(name, '@');
+ if (host == 0)
+ return;
+ *host++ = '\0';
+ signal(SIGALRM, cleanup);
+ alarm(TIME_LIMIT);
+
+ hint.ai_flags = AI_CANONNAME;
+ hint.ai_family = family;
+ hint.ai_socktype = SOCK_STREAM;
+
+ error = getaddrinfo(host, "finger", &hint, &ai0);
+ if (error) {
+ warnx("%s: %s", host, gai_strerror(error));
+ return;
+ }
+
+ multi = (ai0->ai_next) != 0;
+
+ /* ai_canonname may not be filled in if the user specified an IP. */
+ if (ai0->ai_canonname == 0)
+ printf("[%s]\n", host);
+ else
+ printf("[%s]\n", ai0->ai_canonname);
+
+ for (ai = ai0; ai != 0; ai = ai->ai_next) {
+ if (multi)
+ trying(ai);
+
+ error = do_protocol(name, ai);
+ if (!error)
+ break;
+ }
+ alarm(0);
+ freeaddrinfo(ai0);
+}
+
+static int
+do_protocol(const char *name, const struct addrinfo *ai)
+{
+ int cnt, line_len, s;
+ FILE *fp;
+ int c, lastc;
+ struct iovec iov[3];
+ struct msghdr msg;
+ static char slash_w[] = "/W ";
+ static char neteol[] = "\r\n";
+
+ s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (s < 0) {
+ warn("socket(%d, %d, %d)", ai->ai_family, ai->ai_socktype,
+ ai->ai_protocol);
+ return -1;
+ }
+
+ msg.msg_name = (void *)ai->ai_addr;
+ msg.msg_namelen = ai->ai_addrlen;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 0;
+ msg.msg_control = 0;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ /* -l flag for remote fingerd */
+ if (lflag) {
+ iov[msg.msg_iovlen].iov_base = slash_w;
+ iov[msg.msg_iovlen++].iov_len = 3;
+ }
+ /* send the name followed by <CR><LF> */
+ iov[msg.msg_iovlen].iov_base = strdup(name);
+ iov[msg.msg_iovlen++].iov_len = strlen(name);
+ iov[msg.msg_iovlen].iov_base = neteol;
+ iov[msg.msg_iovlen++].iov_len = 2;
+
+#ifdef __APPLE__
+ if (connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+#else
+ /*
+ * -T disables data-on-SYN: compatibility option to finger broken
+ * hosts. Also, the implicit-open API is broken on IPv6, so do
+ * the explicit connect there, too.
+ */
+ if ((Tflag || ai->ai_addr->sa_family == AF_INET6)
+ && connect(s, ai->ai_addr, ai->ai_addrlen) < 0) {
+#endif
+ warn("connect");
+ close(s);
+ return -1;
+ }
+
+ if (sendmsg(s, &msg, 0) < 0) {
+ warn("sendmsg");
+ close(s);
+ return -1;
+ }
+
+ /*
+ * Read from the remote system; once we're connected, we assume some
+ * data. If none arrives, we hang until the user interrupts.
+ *
+ * If we see a <CR> or a <CR> with the high bit set, treat it as
+ * a newline; if followed by a newline character, only output one
+ * newline.
+ *
+ * Otherwise, all high bits are stripped; if it isn't printable and
+ * it isn't a space, we can simply set the 7th bit. Every ASCII
+ * character with bit 7 set is printable.
+ */
+ lastc = 0;
+ if ((fp = fdopen(s, "r")) != NULL) {
+ cnt = 0;
+ line_len = 0;
+ while ((c = getc(fp)) != EOF) {
+ if (++cnt > OUTPUT_MAX) {
+ printf("\n\n Output truncated at %d bytes...\n",
+ cnt - 1);
+ break;
+ }
+ if (c == 0x0d) {
+ if (lastc == '\r') /* ^M^M - skip dupes */
+ continue;
+ c = '\n';
+ lastc = '\r';
+ } else {
+ if (!isprint(c) && !isspace(c)) {
+ c &= 0x7f;
+ c |= 0x40;
+ }
+ if (lastc != '\r' || c != '\n')
+ lastc = c;
+ else {
+ lastc = '\n';
+ continue;
+ }
+ }
+ putchar(c);
+ if (c != '\n' && ++line_len > _POSIX2_LINE_MAX) {
+ putchar('\\');
+ putchar('\n');
+ lastc = '\r';
+ }
+ if (lastc == '\n' || lastc == '\r')
+ line_len = 0;
+ }
+ if (ferror(fp)) {
+ /*
+ * Assume that whatever it was set errno...
+ */
+ warn("reading from network");
+ }
+ if (lastc != '\n')
+ putchar('\n');
+
+ fclose(fp);
+ }
+ return 0;
+}
+
+static void
+trying(const struct addrinfo *ai)
+{
+ char buf[NI_MAXHOST];
+
+ if (getnameinfo(ai->ai_addr, ai->ai_addrlen, buf, sizeof buf,
+ (char *)0, 0, NI_NUMERICHOST) != 0)
+ return; /* XXX can't happen */
+
+ printf("Trying %s...\n", buf);
+}
+
+void
+cleanup(int sig __unused)
+{
+#define ERRSTR "Timed out.\n"
+ write(STDERR_FILENO, ERRSTR, sizeof ERRSTR);
+ exit(1);
+}
+
diff --git a/adv_cmds/finger/pathnames.h b/adv_cmds/finger/pathnames.h
new file mode 100644
index 0000000..160252d
--- /dev/null
+++ b/adv_cmds/finger/pathnames.h
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2000 Mark Knight <markk@knigma.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/finger/pathnames.h,v 1.5 2001/07/30 16:50:47 yar Exp $
+ */
+
+#ifndef PATHNAMES_H
+
+#define _PATH_FORWARD ".forward"
+#define _PATH_NOFINGER ".nofinger"
+#define _PATH_PLAN ".plan"
+#define _PATH_PROJECT ".project"
+#define _PATH_PUBKEY ".pubkey"
+
+#ifndef _PATH_FINGERCONF
+#define _PATH_FINGERCONF "/etc/finger.conf"
+#endif /* _PATH_FINGERCONF */
+
+#endif /* PATHNAMES_H */
diff --git a/adv_cmds/finger/sprint.c b/adv_cmds/finger/sprint.c
new file mode 100644
index 0000000..8de1cba
--- /dev/null
+++ b/adv_cmds/finger/sprint.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)sprint.c 8.3 (Berkeley) 4/28/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/sprint.c,v 1.22 2003/04/02 20:22:29 rwatson Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <db.h>
+#include <err.h>
+#include <langinfo.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <utmpx.h>
+#include "finger.h"
+
+static void stimeprint(WHERE *);
+
+void
+sflag_print(void)
+{
+ PERSON *pn;
+ WHERE *w;
+ int sflag, r, namelen;
+ char p[80];
+ PERSON *tmp;
+ DBT data, key;
+ struct tm *lc;
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ /*
+ * short format --
+ * login name
+ * real name
+ * terminal name (the XX of ttyXX)
+ * if terminal writeable (add an '*' to the terminal name
+ * if not)
+ * if logged in show idle time and day logged in, else
+ * show last login date and time.
+ * If > 6 months, show year instead of time.
+ * if (-o)
+ * office location
+ * office phone
+ * else
+ * remote host
+ */
+#define MAXREALNAME 20
+#define MAXHOSTNAME 17 /* in reality, hosts are never longer than 16 */
+ (void)printf("%-*s %-*s%s %s\n", UT_NAMESIZE, "Login", MAXREALNAME,
+ "Name", " TTY Idle Login Time ", (gflag) ? "" :
+ oflag ? "Office Phone" : "Where");
+
+ for (sflag = R_FIRST;; sflag = R_NEXT) {
+ r = (*db->seq)(db, &key, &data, sflag);
+ if (r == -1)
+ err(1, "db seq");
+ if (r == 1)
+ break;
+ memmove(&tmp, data.data, sizeof tmp);
+ pn = tmp;
+
+ for (w = pn->whead; w != NULL; w = w->next) {
+ namelen = MAXREALNAME;
+ if (w->info == LOGGEDIN && !w->writable)
+ --namelen; /* leave space before `*' */
+ (void)printf("%-*.*s %-*.*s", UT_NAMESIZE, _UTX_USERSIZE,
+ pn->name, MAXREALNAME, namelen,
+ pn->realname ? pn->realname : "");
+ if (!w->loginat) {
+ (void)printf(" * * No logins ");
+ goto office;
+ }
+ (void)putchar(w->info == LOGGEDIN && !w->writable ?
+ '*' : ' ');
+ if (*w->tty)
+ (void)printf("%-3.3s ",
+ (strncmp(w->tty, "tty", 3)
+ && strncmp(w->tty, "cua", 3))
+ ? w->tty : w->tty + 3);
+ else
+ (void)printf(" ");
+ if (w->info == LOGGEDIN) {
+ stimeprint(w);
+ (void)printf(" ");
+ } else
+ (void)printf(" * ");
+ lc = localtime(&w->loginat);
+#define SECSPERDAY 86400
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+ if (now - w->loginat < SECSPERDAY * (DAYSPERWEEK - 1)) {
+ (void)strftime(p, sizeof(p), "%a", lc);
+ } else {
+ (void)strftime(p, sizeof(p),
+ d_first ? "%e %b" : "%b %e", lc);
+ }
+ (void)printf("%-6.6s", p);
+ if (now - w->loginat >= SECSPERDAY * DAYSPERNYEAR / 2) {
+ (void)strftime(p, sizeof(p), "%Y", lc);
+ } else {
+ (void)strftime(p, sizeof(p), "%R", lc);
+ }
+ (void)printf(" %-5.5s", p);
+office:
+ if (gflag)
+ goto no_gecos;
+ if (oflag) {
+ if (pn->office)
+ (void)printf(" %-7.7s", pn->office);
+ else if (pn->officephone)
+ (void)printf(" %-7.7s", " ");
+ if (pn->officephone)
+ (void)printf(" %-.9s",
+ prphone(pn->officephone));
+ } else
+ (void)printf(" %.*s", MAXHOSTNAME, w->host);
+no_gecos:
+ putchar('\n');
+ }
+ }
+}
+
+static void
+stimeprint(WHERE *w)
+{
+ struct tm *delta;
+
+ if (w->idletime == -1) {
+ (void)printf(" ");
+ return;
+ }
+
+ delta = gmtime(&w->idletime);
+ if (!delta->tm_yday)
+ if (!delta->tm_hour)
+ if (!delta->tm_min)
+ (void)printf(" ");
+ else
+ (void)printf("%5d", delta->tm_min);
+ else
+ (void)printf("%2d:%02d",
+ delta->tm_hour, delta->tm_min);
+ else
+ (void)printf("%4dd", delta->tm_yday);
+}
diff --git a/adv_cmds/finger/util.c b/adv_cmds/finger/util.c
new file mode 100644
index 0000000..6e7c925
--- /dev/null
+++ b/adv_cmds/finger/util.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/finger/util.c,v 1.22 2005/09/19 10:11:47 dds Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include "finger.h"
+#include "pathnames.h"
+
+static void find_idle_and_ttywrite(WHERE *);
+static void userinfo(PERSON *, struct passwd *);
+static WHERE *walloc(PERSON *);
+
+int
+match(struct passwd *pw, const char *user)
+{
+ char *p, *t;
+ char name[1024];
+
+ if (!strcasecmp(pw->pw_name, user))
+ return(1);
+
+ /*
+ * XXX
+ * Why do we skip asterisks!?!?
+ */
+ (void)strncpy(p = tbuf, pw->pw_gecos, sizeof(tbuf));
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ if (*p == '*')
+ ++p;
+
+ /* Ampersands get replaced by the login name. */
+ if ((p = strtok(p, ",")) == NULL)
+ return(0);
+
+ for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) {
+ if (*t == '&') {
+ (void)strncpy(t, pw->pw_name,
+ sizeof(name) - (t - name));
+ name[sizeof(name) - 1] = '\0';
+ while (t < &name[sizeof(name) - 1] && *++t)
+ continue;
+ } else {
+ ++t;
+ }
+ }
+ *t = '\0';
+ for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL)
+ if (!strcasecmp(p, user))
+ return(1);
+ return(0);
+}
+
+void
+enter_lastlog(PERSON *pn)
+{
+ WHERE *w;
+ struct lastlogx l, *ll;
+ char doit = 0;
+
+ if ((ll = getlastlogxbyname(pn->name, &l)) == NULL) {
+ bzero(&l, sizeof(l));
+ ll = &l;
+ }
+ if ((w = pn->whead) == NULL)
+ doit = 1;
+ else if (ll->ll_tv.tv_sec != 0) {
+ /* if last login is earlier than some current login */
+ for (; !doit && w != NULL; w = w->next)
+ if (w->info == LOGGEDIN && w->loginat < ll->ll_tv.tv_sec)
+ doit = 1;
+ /*
+ * and if it's not any of the current logins
+ * can't use time comparison because there may be a small
+ * discrepancy since login calls time() twice
+ */
+ for (w = pn->whead; doit && w != NULL; w = w->next)
+ if (w->info == LOGGEDIN &&
+ strncmp(w->tty, ll->ll_line, _UTX_LINESIZE) == 0)
+ doit = 0;
+ }
+ if (doit) {
+ w = walloc(pn);
+ w->info = LASTLOG;
+ bcopy(ll->ll_line, w->tty, _UTX_LINESIZE);
+ w->tty[_UTX_LINESIZE] = 0;
+ bcopy(ll->ll_host, w->host, _UTX_HOSTSIZE);
+ w->host[_UTX_HOSTSIZE] = 0;
+ w->loginat = ll->ll_tv.tv_sec;
+ }
+}
+
+void
+enter_where(struct utmpx *ut, PERSON *pn)
+{
+ WHERE *w;
+
+ w = walloc(pn);
+ w->info = LOGGEDIN;
+ bcopy(ut->ut_line, w->tty, _UTX_LINESIZE);
+ w->tty[_UTX_LINESIZE] = 0;
+ bcopy(ut->ut_host, w->host, _UTX_HOSTSIZE);
+ w->host[_UTX_HOSTSIZE] = 0;
+ w->loginat = (time_t)ut->ut_tv.tv_sec;
+ find_idle_and_ttywrite(w);
+}
+
+PERSON *
+enter_person(struct passwd *pw)
+{
+ DBT data, key;
+ PERSON *pn;
+
+ if (db == NULL &&
+ (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
+ err(1, NULL);
+
+ key.data = pw->pw_name;
+ key.size = strlen(pw->pw_name);
+
+ switch ((*db->get)(db, &key, &data, 0)) {
+ case 0:
+ memmove(&pn, data.data, sizeof pn);
+ return (pn);
+ default:
+ case -1:
+ err(1, "db get");
+ /* NOTREACHED */
+ case 1:
+ ++entries;
+ pn = palloc();
+ userinfo(pn, pw);
+ pn->whead = NULL;
+
+ data.size = sizeof(PERSON *);
+ data.data = &pn;
+ if ((*db->put)(db, &key, &data, 0))
+ err(1, "db put");
+ return (pn);
+ }
+}
+
+PERSON *
+find_person(const char *name)
+{
+ struct passwd *pw;
+
+ int cnt;
+ DBT data, key;
+ PERSON *p;
+ char buf[_UTX_USERSIZE + 1];
+
+ if (!db)
+ return(NULL);
+
+ if ((pw = getpwnam(name)) && hide(pw))
+ return(NULL);
+
+ /* Name may be only _UTX_USERSIZE long and not NUL terminated. */
+ for (cnt = 0; cnt < _UTX_USERSIZE && *name; ++name, ++cnt)
+ buf[cnt] = *name;
+ buf[cnt] = '\0';
+ key.data = buf;
+ key.size = cnt;
+
+ if ((*db->get)(db, &key, &data, 0))
+ return (NULL);
+ memmove(&p, data.data, sizeof p);
+ return (p);
+}
+
+PERSON *
+palloc(void)
+{
+ PERSON *p;
+
+ if ((p = malloc(sizeof(PERSON))) == NULL)
+ err(1, NULL);
+ return(p);
+}
+
+static WHERE *
+walloc(PERSON *pn)
+{
+ WHERE *w;
+
+ if ((w = malloc(sizeof(WHERE))) == NULL)
+ err(1, NULL);
+ if (pn->whead == NULL)
+ pn->whead = pn->wtail = w;
+ else {
+ pn->wtail->next = w;
+ pn->wtail = w;
+ }
+ w->next = NULL;
+ return(w);
+}
+
+char *
+prphone(char *num)
+{
+ char *p;
+ int len;
+ static char pbuf[20];
+
+ /* don't touch anything if the user has their own formatting */
+ for (p = num; *p; ++p)
+ if (!isdigit(*p))
+ return(num);
+ len = p - num;
+ p = pbuf;
+ switch(len) {
+ case 11: /* +0-123-456-7890 */
+ *p++ = '+';
+ *p++ = *num++;
+ *p++ = '-';
+ /* FALLTHROUGH */
+ case 10: /* 012-345-6789 */
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = '-';
+ /* FALLTHROUGH */
+ case 7: /* 012-3456 */
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ break;
+ case 5: /* x0-1234 */
+ case 4: /* x1234 */
+ *p++ = 'x';
+ *p++ = *num++;
+ break;
+ default:
+ return(num);
+ }
+ if (len != 4) {
+ *p++ = '-';
+ *p++ = *num++;
+ }
+ *p++ = *num++;
+ *p++ = *num++;
+ *p++ = *num++;
+ *p = '\0';
+ return(pbuf);
+}
+
+static void
+find_idle_and_ttywrite(WHERE *w)
+{
+ struct stat sb;
+ time_t touched;
+ int error;
+
+ (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
+
+ error = stat(tbuf, &sb);
+ if (error < 0 && errno == ENOENT) {
+ /*
+ * The terminal listed is not actually a terminal (i.e.,
+ * ":0"). This is a failure, so we'll skip printing
+ * out the idle time, which is non-ideal but better
+ * than a bogus warning and idle time.
+ */
+ w->idletime = -1;
+ return;
+ } else if (error < 0) {
+ warn("%s", tbuf);
+ w->idletime = -1;
+ return;
+ }
+ touched = sb.st_atime;
+ if (touched < w->loginat) {
+ /* tty untouched since before login */
+ touched = w->loginat;
+ }
+ w->idletime = now < touched ? 0 : now - touched;
+
+#define TALKABLE 0220 /* tty is writable if 220 mode */
+ w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
+}
+
+static void
+userinfo(PERSON *pn, struct passwd *pw)
+{
+ char *p, *t;
+ char *bp, name[1024];
+ struct stat sb;
+
+ pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
+
+ pn->uid = pw->pw_uid;
+ if ((pn->name = strdup(pw->pw_name)) == NULL)
+ err(1, "strdup failed");
+ if ((pn->dir = strdup(pw->pw_dir)) == NULL)
+ err(1, "strdup failed");
+ if ((pn->shell = strdup(pw->pw_shell)) == NULL)
+ err(1, "strdup failed");
+
+ /* why do we skip asterisks!?!? */
+ (void)strncpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf));
+ tbuf[sizeof(tbuf) - 1] = '\0';
+ if (*bp == '*')
+ ++bp;
+
+ /* ampersands get replaced by the login name */
+ if (!(p = strsep(&bp, ",")))
+ return;
+ for (t = name; t < &name[sizeof(name) - 1] && (*t = *p) != '\0'; ++p) {
+ if (*t == '&') {
+ (void)strncpy(t, pw->pw_name,
+ sizeof(name) - (t - name));
+ name[sizeof(name) - 1] = '\0';
+ if (islower(*t))
+ *t = toupper(*t);
+ while (t < &name[sizeof(name) - 1] && *++t)
+ continue;
+ } else {
+ ++t;
+ }
+ }
+ *t = '\0';
+ if ((pn->realname = strdup(name)) == NULL)
+ err(1, "strdup failed");
+ pn->office = ((p = strsep(&bp, ",")) && *p) ?
+ strdup(p) : NULL;
+ pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
+ strdup(p) : NULL;
+ pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
+ strdup(p) : NULL;
+ (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, pw->pw_name);
+ pn->mailrecv = -1; /* -1 == not_valid */
+ if (stat(tbuf, &sb) < 0) {
+ if (errno != ENOENT) {
+ warn("%s", tbuf);
+ return;
+ }
+ } else if (sb.st_size != 0) {
+ pn->mailrecv = sb.st_mtime;
+ pn->mailread = sb.st_atime;
+ }
+}
+
+/*
+ * Is this user hiding from finger?
+ * If ~<user>/.nofinger exists, return 1 (hide), else return 0 (nohide).
+ * Nobody can hide from root.
+ */
+
+int
+hide(struct passwd *pw)
+{
+ struct stat st;
+ char buf[MAXPATHLEN];
+
+ if (invoker_root || !pw->pw_dir)
+ return 0;
+
+ snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, _PATH_NOFINGER);
+
+ if (stat(buf, &st) == 0)
+ return 1;
+
+ return 0;
+}
diff --git a/adv_cmds/gencat/gencat.1 b/adv_cmds/gencat/gencat.1
new file mode 100644
index 0000000..bcead36
--- /dev/null
+++ b/adv_cmds/gencat/gencat.1
@@ -0,0 +1,177 @@
+.\" $OpenBSD: gencat.1,v 1.3 1997/06/11 15:39:54 kstailey Exp $
+.\"
+.\" Copyright (c) 1997 Ken Stailey
+.\"
+.\" 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. 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.
+.\"
+.\" $FreeBSD: src/usr.bin/gencat/gencat.1,v 1.9 2001/11/23 14:37:27 dd Exp $
+.\"
+.Dd June 11, 1997
+.Dt GENCAT 1
+.Os
+.Sh NAME
+.Nm gencat
+.Nd NLS catalog compiler
+.Sh SYNOPSIS
+.Nm
+.Ar "output-file"
+.Ar "input-files..."
+.Sh DESCRIPTION
+The
+.Nm
+utility merges the text NLS input files
+.Ar "input-files..."
+into a formatted message catalog file
+.Ar "output-file" .
+The file
+.Ar "output-file"
+will be created if it does not already exist. If
+.Ar "output-file"
+does exist, its messages will be included in the new
+.Ar "output-file" .
+If set and message numbers collide, the new message text defined in
+.Ar "input-files..."
+will replace the old message text currently contained in
+.Ar "output-file" .
+.Sh INPUT FILES
+The format of a message text source file is defined below. Note that
+the fields of a message text source line are separated by a single space
+character: any other space characters are considered to be part of the
+field contents.
+.Pp
+.Bl -tag -width 3n
+.It Li $set Ar n comment
+This line specifies the set identifier of the following messages until
+the next
+.Li $set
+or end-of-file appears. The argument
+.Ar n
+is the set identifier which is defined as a number in the range
+[1, (NL_SETMAX)]. Set identifiers must occur in ascending order within
+a single source file, but need not be contiguous. Any string following
+a space following the set identifier is treated as a comment. If no
+.Li $set
+directive is specified in a given source file, all messages will
+be located in the default message set NL_SETD.
+.It Li $del Ar n comment
+This line deletes messages from set
+.Ar n
+from a message catalog. The
+.Ar n
+specifies a set number. Any string following a space following the set
+number is treated as a comment.
+.It Li $ Ar comment
+A line beginning with
+.Li $
+followed by a space is treated as a comment.
+.It Ar m message-text
+A message line consists of a message identifier
+.Ar m
+in the range [1, (NL_MSGMAX)]. The
+.Ar message-text
+is stored in the message catalog with the set identifier specified by
+the last
+.Li $set
+directive, and the message identifier
+.Ar m .
+If the
+.Ar message-text
+is empty, and there is a space character following the message identifier,
+an empty string is stored in the message catalog. If the
+.Ar message-text
+is empty, and if there is no space character following the message
+identifier, then the existing message in the current set with the
+specified message identifier is deleted from the catalog. Message
+identifiers must be in ascending order within a single set, but
+need not be contiguous. The
+.Ar message-text
+length must be in the range [0, (NL_TEXTMAX)].
+.It Li $quote Ar c
+This line specifies an optional quote character
+.Ar c
+which can be used to surround
+.Ar message-text
+so that trailing space or empty messages are visible in message
+source files. By default, or if an empty
+.Li $quote
+directive is specified, no quoting of
+.Ar message-text
+will be recognized.
+.El
+.Pp
+Empty lines in message source files are ignored. The effect of lines
+beginning with any character other than those described above is
+undefined.
+.Pp
+Text strings can contain the following special characters and escape
+sequences. In addition, if a quote character is defined, it may be
+escaped as well to embed a literal quote character.
+.Pp
+.Bl -tag -width "\eooo" -offset indent -compact
+.It Li \en
+line feed
+.It Li \et
+horizontal tab
+.It Li \ev
+vertical tab
+.It Li \eb
+backspace
+.It Li \er
+carriage return
+.It Li \ef
+form feed
+.It Li \e\e
+backslash
+.It Li \eooo
+octal number in the range [000, 377]
+.El
+.Pp
+A backslash character immediately before the end of the line in a file
+is used to continue the line onto the next line, e.g.:
+.Pp
+.Dl 1 This line is continued \e
+.Dl on this line.
+.Pp
+If the character following the backslash is not one of those specified,
+the backslash is ignored.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr catclose 3 ,
+.Xr catgets 3 ,
+.Xr catopen 3
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -xpg4
+standard.
+.Sh AUTHORS
+.An -nosplit
+This manual page was originally written by
+.An Ken Stailey
+and later revised by
+.An Terry Lambert .
+.Sh BUGS
+A message catalog file created from a blank input file cannot be revised;
+it must be deleted and recreated.
diff --git a/adv_cmds/gencat/gencat.c b/adv_cmds/gencat/gencat.c
new file mode 100644
index 0000000..e0d00e3
--- /dev/null
+++ b/adv_cmds/gencat/gencat.c
@@ -0,0 +1,199 @@
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/gencat/gencat.c,v 1.9 2002/05/29 14:23:10 tjr Exp $");
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "gencat.h"
+
+/*
+ * The spec says the syntax is "gencat catfile msgfile...".
+ * We extend it to:
+ * gencat [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]...
+ * Flags are order dependent, we'll take whatever lang was most recently chosen
+ * and use it to generate the next header file. The header files are generated
+ * at the point in the command line they are listed. Thus the sequence:
+ * gencat -lang C foo.cat foo.mcs -h foo.h -lang C++ bar.mcs -h bar.H
+ * will put constants from foo.mcs into foo.h and constants from bar.mcs into
+ * bar.h. Constants are not saved in the catalog file, so nothing will come
+ * from that, even if things have been defined before. The constants in foo.h
+ * will be in C syntax, in bar.H in C++ syntax.
+ */
+
+static void writeIfChanged(char *, int, int);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: gencat [-new] [-or] [-lang C|C++|ANSIC]\n"
+ " catfile msgfile [-h <header-file>]...\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int ofd = -1, ifd, i;
+ char *catfile = NULL;
+ char *input = NULL;
+ int lang = MCLangC;
+ int new = FALSE;
+ int orConsts = FALSE;
+
+ for (i = 1; i < argc; ++i) {
+ if (argv[i][0] == '-') {
+ if (strcmp(argv[i], "-lang") == 0) {
+ ++i;
+ if (strcmp(argv[i], "C") == 0) lang = MCLangC;
+ else if (strcmp(argv[i], "C++") == 0) lang = MCLangCPlusPlus;
+ else if (strcmp(argv[i], "ANSIC") == 0) lang = MCLangANSIC;
+ else {
+ errx(1, "unrecognized language: %s", argv[i]);
+ }
+ } else if (strcmp(argv[i], "-h") == 0) {
+ if (!input)
+ errx(1, "can't write to a header before reading something");
+ ++i;
+ writeIfChanged(argv[i], lang, orConsts);
+ } else if (strcmp(argv[i], "-new") == 0) {
+ if (catfile)
+ errx(1, "you must specify -new before the catalog file name");
+ new = TRUE;
+ } else if (strcmp(argv[i], "-or") == 0) {
+ orConsts = ~orConsts;
+ } else {
+ usage();
+ }
+ } else {
+ if (!catfile) {
+ catfile = argv[i];
+ if (new) {
+ if ((ofd = open(catfile, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0)
+ errx(1, "unable to create a new %s", catfile);
+ } else if ((ofd = open(catfile, O_RDONLY)) < 0) {
+ if ((ofd = open(catfile, O_WRONLY|O_CREAT, 0666)) < 0)
+ errx(1, "unable to create %s", catfile);
+ } else {
+ MCReadCat(ofd);
+ close(ofd);
+ if ((ofd = open(catfile, O_WRONLY|O_TRUNC)) < 0)
+ errx(1, "unable to truncate %s", catfile);
+ }
+ } else {
+ input = argv[i];
+ if ((ifd = open(input, O_RDONLY)) < 0)
+ errx(1, "unable to read %s", input);
+ MCParse(ifd);
+ close(ifd);
+ }
+ }
+ }
+ if (catfile) {
+ MCWriteCat(ofd);
+ exit(0);
+ } else {
+ usage();
+ }
+ return 0;
+}
+
+static void
+writeIfChanged(char *fname, int lang, int orConsts)
+{
+ char tmpname[] = _PATH_TMP"/gencat.XXXXXX";
+ char buf[BUFSIZ], tbuf[BUFSIZ], *cptr, *tptr;
+ int fd, tfd;
+ int diff = FALSE;
+ int len, tlen;
+ struct stat sbuf;
+
+ /* If it doesn't exist, just create it */
+ if (stat(fname, &sbuf)) {
+ if ((fd = open(fname, O_WRONLY|O_CREAT, 0666)) < 0)
+ errx(1, "unable to create header file %s", fname);
+ MCWriteConst(fd, lang, orConsts);
+ close(fd);
+ return;
+ }
+
+ /* If it does exist, create a temp file for now */
+ if ((tfd = mkstemp(tmpname)) < 0)
+ err(1, "mkstemp");
+ unlink(tmpname);
+
+ /* Write to the temp file and rewind */
+ MCWriteConst(tfd, lang, orConsts);
+
+ /* Open the real header file */
+ if ((fd = open(fname, O_RDONLY)) < 0)
+ errx(1, "unable to read header file: %s", fname);
+
+ /* Backup to the start of the temp file */
+ if (lseek(tfd, (off_t)0, L_SET) < 0)
+ errx(1, "unable to seek in tempfile: %s", tmpname);
+
+ /* Now compare them */
+ while ((tlen = read(tfd, tbuf, BUFSIZ)) > 0) {
+ if ((len = read(fd, buf, BUFSIZ)) != tlen) {
+ diff = TRUE;
+ goto done;
+ }
+ for (cptr = buf, tptr = tbuf; cptr < buf+len; ++cptr, ++tptr) {
+ if (*tptr != *cptr) {
+ diff = TRUE;
+ goto done;
+ }
+ }
+ }
+done:
+ if (diff) {
+ if (lseek(tfd, (off_t)0, L_SET) < 0)
+ errx(1, "unable to seek in tempfile: %s", tmpname);
+ close(fd);
+ if ((fd = open(fname, O_WRONLY|O_TRUNC)) < 0)
+ errx(1, "unable to truncate header file: %s", fname);
+ while ((len = read(tfd, buf, BUFSIZ)) > 0) {
+ if (write(fd, buf, (size_t)len) != len)
+ warnx("error writing to header file: %s", fname);
+ }
+ }
+ close(fd);
+ close(tfd);
+}
diff --git a/adv_cmds/gencat/gencat.h b/adv_cmds/gencat/gencat.h
new file mode 100644
index 0000000..5e7e459
--- /dev/null
+++ b/adv_cmds/gencat/gencat.h
@@ -0,0 +1,87 @@
+/* $FreeBSD: src/usr.bin/gencat/gencat.h,v 1.4 2002/03/26 12:39:08 charnier Exp $ */
+
+#ifndef GENCAT_H
+#define GENCAT_H
+
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+/*
+ * $set n comment
+ * My extension: If the comment begins with # treat the next string
+ * as a constant identifier.
+ * $delset n comment
+ * n goes from 1 to NL_SETMAX
+ * Deletes a set from the MC
+ * $ comment
+ * My extension: If comment begins with # treat the next string as
+ * a constant identifier for the next message.
+ * m message-text
+ * m goes from 1 to NL_MSGMAX
+ * If message-text is empty, and a space or tab is present, put
+ * empty string in catalog.
+ * If message-text is empty, delete the message.
+ * Length of text is 0 to NL_TEXTMAX
+ * My extension: If '#' is used instead of a number, the number
+ * is generated automatically. A # followed by anything is an empty message.
+ * $quote c
+ * Optional quote character which can surround message-text to
+ * show where spaces are.
+ *
+ * Escape Characters
+ * \n (newline), \t (horiz tab), \v (vert tab), \b (backspace),
+ * \r (carriage return), \f (formfeed), \\ (backslash), \ddd (bitpattern
+ * in octal).
+ * Also, \ at end of line is a continuation.
+ *
+ */
+
+#define MCLangC 0
+#define MCLangCPlusPlus 1
+#define MCLangANSIC 2
+
+#define MAXTOKEN 1024
+
+#define TRUE 1
+#define FALSE 0
+
+extern void MCAddSet(int, char *);
+extern void MCDelSet(int);
+extern void MCAddMsg(int, const char *, char *);
+extern void MCDelMsg(int);
+extern void MCParse(int);
+extern void MCReadCat(int);
+extern void MCWriteConst(int, int, int);
+extern void MCWriteCat(int);
+extern long MCGetByteOrder(void);
+
+#endif /* GENCAT_H */
diff --git a/adv_cmds/gencat/genlib.c b/adv_cmds/gencat/genlib.c
new file mode 100644
index 0000000..42b7ae2
--- /dev/null
+++ b/adv_cmds/gencat/genlib.c
@@ -0,0 +1,836 @@
+/***********************************************************
+Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that Alfalfa's name not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
+ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
+ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
+ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+SOFTWARE.
+
+If you make any modifications, bugfixes or other changes to this software
+we'd appreciate it if you could send a copy to us so we can keep things
+up-to-date. Many thanks.
+ Kee Hinckley
+ Alfalfa Software, Inc.
+ 267 Allston St., #3
+ Cambridge, MA 02139 USA
+ nazgul@alfalfa.com
+
+******************************************************************/
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/gencat/genlib.c,v 1.13 2002/12/24 07:40:10 davidxu Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "msgcat.h"
+#include "gencat.h"
+#include <machine/endian.h>
+/* libkern/OSByteOrder is needed for the 64 bit byte swap */
+#include <libkern/OSByteOrder.h>
+
+#ifndef htonll
+#define htonll(x) OSSwapHostToBigInt64(x)
+#define ntohll(x) OSSwapBigToHostInt64(x)
+#endif
+
+static char *curline = NULL;
+static long lineno = 0;
+
+static void
+warning(char *cptr, const char *msg)
+{
+ warnx("%s on line %ld\n%s", msg, lineno, (curline == NULL ? "" : curline) );
+ if (cptr) {
+ char *tptr;
+ for (tptr = curline; tptr < cptr; ++tptr) putc(' ', stderr);
+ fprintf(stderr, "^\n");
+ }
+}
+
+static void
+error(char *cptr, const char *msg)
+{
+ warning(cptr, msg);
+ exit(1);
+}
+
+static void
+corrupt(void) {
+ error(NULL, "corrupt message catalog");
+}
+
+static void
+nomem(void) {
+ error(NULL, "out of memory");
+}
+
+static char *
+gencat_getline(int fd)
+{
+ static size_t curlen = BUFSIZ;
+ static char buf[BUFSIZ], *bptr = buf, *bend = buf;
+ char *cptr, *cend;
+ long buflen;
+
+ if (!curline) {
+ curline = (char *) malloc(curlen);
+ if (!curline) nomem();
+ }
+ ++lineno;
+
+ cptr = curline;
+ cend = curline + curlen;
+ while (TRUE) {
+ for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
+ if (*bptr == '\n') {
+ *cptr = '\0';
+ ++bptr;
+ return(curline);
+ } else *cptr = *bptr;
+ }
+ if (bptr == bend) {
+ buflen = read(fd, buf, BUFSIZ);
+ if (buflen <= 0) {
+ if (cptr > curline) {
+ *cptr = '\0';
+ return(curline);
+ }
+ return(NULL);
+ }
+ bend = buf + buflen;
+ bptr = buf;
+ }
+ if (cptr == cend) {
+ cptr = curline = (char *) realloc(curline, curlen *= 2);
+ if (!curline) nomem();
+ cend = curline + curlen;
+ }
+ }
+}
+
+static char *
+token(char *cptr)
+{
+ static char tok[MAXTOKEN+1];
+ char *tptr = tok;
+
+ while (*cptr && isspace((unsigned char)*cptr)) ++cptr;
+ while (*cptr && !isspace((unsigned char)*cptr)) *tptr++ = *cptr++;
+ *tptr = '\0';
+ return(tok);
+}
+
+static char *
+wskip(char *cptr)
+{
+ if (!*cptr || !isspace((unsigned char)*cptr)) {
+ warning(cptr, "expected a space");
+ return(cptr);
+ }
+ while (*cptr && isspace((unsigned char)*cptr)) ++cptr;
+ return(cptr);
+}
+
+static char *
+cskip(char *cptr)
+{
+ if (!*cptr || isspace((unsigned char)*cptr)) {
+ warning(cptr, "wasn't expecting a space");
+ return(cptr);
+ }
+ while (*cptr && !isspace((unsigned char)*cptr)) ++cptr;
+ return(cptr);
+}
+
+static char *
+getmsg(int fd, char *cptr, char quote)
+{
+ static char *msg = NULL;
+ static size_t msglen = 0;
+ size_t clen, i;
+ char *tptr;
+ int needq;
+
+ if (quote && *cptr == quote) {
+ needq = TRUE;
+ ++cptr;
+ } else needq = FALSE;
+
+ clen = strlen(cptr) + 1;
+ if (clen > msglen) {
+ if (msglen) msg = (char *) realloc(msg, clen);
+ else msg = (char *) malloc(clen);
+ if (!msg) nomem();
+ msglen = clen;
+ }
+ tptr = msg;
+
+ while (*cptr) {
+ if (quote && *cptr == quote) {
+ char *tmp;
+ tmp = cptr+1;
+ if (*tmp && (!isspace((unsigned char)*tmp) || *wskip(tmp))) {
+ warning(cptr, "unexpected quote character, ignoring");
+ *tptr++ = *cptr++;
+ } else {
+ *cptr = '\0';
+ }
+ } else if (*cptr == '\\') {
+ ++cptr;
+ switch (*cptr) {
+ case '\0':
+ cptr = gencat_getline(fd);
+ if (!cptr) error(NULL, "premature end of file");
+ msglen += strlen(cptr);
+ i = tptr - msg;
+ msg = (char *) realloc(msg, msglen);
+ if (!msg) nomem();
+ tptr = msg + i;
+ break;
+
+#define CASEOF(CS, CH) \
+ case CS: \
+ *tptr++ = CH; \
+ ++cptr; \
+ break;
+
+ CASEOF('n', '\n')
+ CASEOF('t', '\t')
+ CASEOF('v', '\v')
+ CASEOF('b', '\b')
+ CASEOF('r', '\r')
+ CASEOF('f', '\f')
+ CASEOF('"', '"')
+ CASEOF('\'', '\'')
+ CASEOF('\\', '\\')
+
+ default:
+ if (isdigit((unsigned char)*cptr)) {
+ *tptr = 0;
+ for (i = 0; i < 3; ++i) {
+ if (!isdigit((unsigned char)*cptr)) break;
+ if (*cptr > '7') warning(cptr, "octal number greater than 7?!");
+ *tptr *= 8;
+ *tptr += (*cptr - '0');
+ ++cptr;
+ }
+ ++tptr;
+ } else {
+ warning(cptr, "unrecognized escape sequence");
+ }
+ }
+ } else {
+ *tptr++ = *cptr++;
+ }
+ }
+ *tptr = '\0';
+ return(msg);
+}
+
+static char *
+dupstr(const char *ostr)
+{
+ char *nstr;
+
+ nstr = strdup(ostr);
+ if (!nstr) error(NULL, "unable to allocate storage");
+ return(nstr);
+}
+
+/*
+ * The Global Stuff
+ */
+
+typedef struct _msgT {
+ long msgId;
+ char *str;
+ char *hconst;
+ long offset;
+ struct _msgT *prev, *next;
+} msgT;
+
+typedef struct _setT {
+ long setId;
+ char *hconst;
+ msgT *first, *last;
+ struct _setT *prev, *next;
+} setT;
+
+typedef struct {
+ setT *first, *last;
+} catT;
+
+static setT *curSet;
+static catT *cat;
+
+/*
+ * Find the current byte order. There are of course some others, but
+ * this will do for now. Note that all we care about is "long".
+ */
+long
+MCGetByteOrder(void) {
+ long l = 0x00010203;
+ char *cptr = (char *) &l;
+
+ if (cptr[0] == 0 && cptr[1] == 1 && cptr[2] == 2 && cptr[3] == 3)
+ return MC68KByteOrder;
+ else return MCn86ByteOrder;
+}
+
+void
+MCParse(int fd)
+{
+ char *cptr, *str;
+ int setid = 1, msgid = 0;
+ char hconst[MAXTOKEN+1];
+ char quote = 0;
+
+ if (!cat) {
+ cat = (catT *) malloc(sizeof(catT));
+ if (!cat) nomem();
+ bzero(cat, sizeof(catT));
+ }
+
+ hconst[0] = '\0';
+
+ while ((cptr = gencat_getline(fd)) != NULL) {
+ if (*cptr == '$') {
+ ++cptr;
+ if (strncmp(cptr, "set", 3) == 0) {
+ cptr += 3;
+ cptr = wskip(cptr);
+ setid = atoi(cptr);
+ cptr = cskip(cptr);
+ if (*cptr) cptr = wskip(cptr);
+ if (*cptr == '#') {
+ ++cptr;
+ MCAddSet(setid, token(cptr));
+ } else MCAddSet(setid, NULL);
+ msgid = 0;
+ } else if (strncmp(cptr, "delset", 6) == 0) {
+ cptr += 6;
+ cptr = wskip(cptr);
+ setid = atoi(cptr);
+ MCDelSet(setid);
+ } else if (strncmp(cptr, "quote", 5) == 0) {
+ cptr += 5;
+ if (!*cptr) quote = 0;
+ else {
+ cptr = wskip(cptr);
+ if (!*cptr) quote = 0;
+ else quote = *cptr;
+ }
+ } else if (isspace((unsigned char)*cptr)) {
+ cptr = wskip(cptr);
+ if (*cptr == '#') {
+ ++cptr;
+ strcpy(hconst, token(cptr));
+ }
+ } else {
+ if (*cptr) {
+ cptr = wskip(cptr);
+ if (*cptr) warning(cptr, "unrecognized line");
+ }
+ }
+ } else {
+ if (!curSet) MCAddSet(setid, NULL);
+ if (isdigit((unsigned char)*cptr) || *cptr == '#') {
+ if (*cptr == '#') {
+ ++msgid;
+ ++cptr;
+ if (!*cptr) {
+ MCAddMsg(msgid, "", hconst);
+ hconst[0] = '\0';
+ continue;
+ }
+ if (!isspace((unsigned char)*cptr)) warning(cptr, "expected a space");
+ ++cptr;
+ if (!*cptr) {
+ MCAddMsg(msgid, "", hconst);
+ hconst[0] = '\0';
+ continue;
+ }
+ } else {
+ msgid = atoi(cptr);
+ cptr = cskip(cptr);
+ if (isspace(*cptr))
+ cptr++;
+ /* if (*cptr) ++cptr; */
+ }
+ if (!*cptr) {
+ if (isspace(cptr[-1])) {
+ MCAddMsg(msgid, "", hconst);
+ hconst[0] = '\0';
+ } else {
+ MCDelMsg(msgid);
+ }
+ } else {
+ str = getmsg(fd, cptr, quote);
+ MCAddMsg(msgid, str, hconst);
+ hconst[0] = '\0';
+ }
+ }
+ }
+ }
+}
+
+void
+MCReadCat(int fd)
+{
+ MCHeaderT mcHead;
+ MCMsgT mcMsg;
+ MCSetT mcSet;
+ msgT *msg;
+ setT *set;
+ int i;
+ char *data;
+
+ cat = (catT *) malloc(sizeof(catT));
+ if (!cat) nomem();
+ bzero(cat, sizeof(catT));
+
+ /* While we deal with read/write this in network byte order we do NOT
+ deal with struct member padding issues, or even sizeof(long) issues,
+ those are left for a future genneration to curse either me, or the
+ original author for */
+
+ if (read(fd, &mcHead, sizeof(mcHead)) != sizeof(mcHead)) corrupt();
+ if (strncmp(mcHead.magic, MCMagic, MCMagicLen) != 0) corrupt();
+ if (ntohl(mcHead.majorVer) != MCMajorVer) error(NULL, "unrecognized catalog version");
+ if ((ntohl(mcHead.flags) & MC68KByteOrder) == 0) error(NULL, "wrong byte order");
+
+ if (lseek(fd, ntohll(mcHead.firstSet), L_SET) == -1) corrupt();
+
+ while (TRUE) {
+ if (read(fd, &mcSet, sizeof(mcSet)) != sizeof(mcSet)) corrupt();
+ if (mcSet.invalid) continue;
+
+ set = (setT *) malloc(sizeof(setT));
+ if (!set) nomem();
+ bzero(set, sizeof(*set));
+ if (cat->first) {
+ cat->last->next = set;
+ set->prev = cat->last;
+ cat->last = set;
+ } else cat->first = cat->last = set;
+
+ set->setId = ntohl(mcSet.setId);
+
+ /* Get the data */
+ if (mcSet.dataLen) {
+ data = (char *) malloc((size_t)ntohl(mcSet.dataLen));
+ if (!data) nomem();
+ if (lseek(fd, ntohll(mcSet.data.off), L_SET) == -1) corrupt();
+ if (read(fd, data, (size_t)ntohl(mcSet.dataLen)) != ntohl(mcSet.dataLen)) corrupt();
+ if (lseek(fd, ntohll(mcSet.u.firstMsg), L_SET) == -1) corrupt();
+
+ for (i = 0; i < ntohl(mcSet.numMsgs); ++i) {
+ if (read(fd, &mcMsg, sizeof(mcMsg)) != sizeof(mcMsg)) corrupt();
+ if (mcMsg.invalid) {
+ --i;
+ continue;
+ }
+
+ msg = (msgT *) malloc(sizeof(msgT));
+ if (!msg) nomem();
+ bzero(msg, sizeof(*msg));
+ if (set->first) {
+ set->last->next = msg;
+ msg->prev = set->last;
+ set->last = msg;
+ } else set->first = set->last = msg;
+
+ msg->msgId = ntohl(mcMsg.msgId);
+ msg->str = dupstr((char *) (data + ntohll(mcMsg.msg.off)));
+ }
+ free(data);
+ }
+ if (!mcSet.nextSet) break;
+ if (lseek(fd, ntohll(mcSet.nextSet), L_SET) == -1) corrupt();
+ }
+}
+
+
+static void
+printS(int fd, const char *str)
+{
+ if (str)
+ write(fd, str, strlen(str));
+}
+
+static void
+printL(int fd, long l)
+{
+ char buf[32];
+ sprintf(buf, "%ld", l);
+ write(fd, buf, strlen(buf));
+}
+
+static void
+printLX(int fd, long l)
+{
+ char buf[32];
+ sprintf(buf, "%lx", l);
+ write(fd, buf, strlen(buf));
+}
+
+static void
+genconst(int fd, int type, char *setConst, char *msgConst, long val)
+{
+ switch (type) {
+ case MCLangC:
+ if (!msgConst) {
+ printS(fd, "\n#define ");
+ printS(fd, setConst);
+ printS(fd, "Set");
+ } else {
+ printS(fd, "#define ");
+ printS(fd, setConst);
+ printS(fd, msgConst);
+ }
+ printS(fd, "\t0x");
+ printLX(fd, val);
+ printS(fd, "\n");
+ break;
+ case MCLangCPlusPlus:
+ case MCLangANSIC:
+ if (!msgConst) {
+ printS(fd, "\nconst long ");
+ printS(fd, setConst);
+ printS(fd, "Set");
+ } else {
+ printS(fd, "const long ");
+ printS(fd, setConst);
+ printS(fd, msgConst);
+ }
+ printS(fd, "\t= ");
+ printL(fd, val);
+ printS(fd, ";\n");
+ break;
+ default:
+ error(NULL, "not a recognized (programming) language type");
+ }
+}
+
+void
+MCWriteConst(int fd, int type, int orConsts)
+{
+ msgT *msg;
+ setT *set;
+ long id;
+
+ if (orConsts && (type == MCLangC || type == MCLangCPlusPlus || type == MCLangANSIC)) {
+ printS(fd, "/* Use these Macros to compose and decompose setId's and msgId's */\n");
+ printS(fd, "#ifndef MCMakeId\n");
+ printS(fd, "# define MCMakeId(s,m)\t(unsigned long)(((unsigned short)s<<(sizeof(short)*8))\\\n");
+ printS(fd, "\t\t\t\t\t|(unsigned short)m)\n");
+ printS(fd, "# define MCSetId(id)\t(unsigned int) (id >> (sizeof(short) * 8))\n");
+ printS(fd, "# define MCMsgId(id)\t(unsigned int) ((id << (sizeof(short) * 8))\\\n");
+ printS(fd, "\t\t\t\t\t>> (sizeof(short) * 8))\n");
+ printS(fd, "#endif\n");
+ }
+
+ for (set = cat->first; set; set = set->next) {
+ if (set->hconst) genconst(fd, type, set->hconst, NULL, set->setId);
+
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst) {
+ if (orConsts) id = MCMakeId(set->setId, msg->msgId);
+ else id = msg->msgId;
+ genconst(fd, type, set->hconst, msg->hconst, id);
+ free(msg->hconst);
+ msg->hconst = NULL;
+ }
+ }
+ if (set->hconst) {
+ free(set->hconst);
+ set->hconst = NULL;
+ }
+ }
+}
+
+void
+MCWriteCat(int fd)
+{
+ MCHeaderT mcHead;
+ int cnt;
+ setT *set;
+ msgT *msg;
+ MCSetT mcSet;
+ MCMsgT mcMsg;
+ off_t pos;
+
+ bcopy(MCMagic, mcHead.magic, MCMagicLen);
+ mcHead.majorVer = htonl(MCMajorVer);
+ mcHead.minorVer = htonl(MCMinorVer);
+ mcHead.flags = htonl(MC68KByteOrder);
+ mcHead.firstSet = 0; /* We'll be back to set this in a minute */
+
+ if (cat == NULL)
+ error(NULL, "cannot write empty catalog set");
+
+ for (cnt = 0, set = cat->first; set; set = set->next) ++cnt;
+ mcHead.numSets = htonl(cnt);
+
+ /* I'm not inclined to mess with it, but it looks odd that we write
+ the header twice...and that we get the firstSet value from another
+ lseek rather then just 'sizeof(mcHead)' */
+
+ /* Also, this code doesn't seem to check returns from write! */
+
+ lseek(fd, (off_t)0L, L_SET);
+ write(fd, &mcHead, sizeof(mcHead));
+ mcHead.firstSet = htonll(lseek(fd, (off_t)0L, L_INCR));
+ lseek(fd, (off_t)0L, L_SET);
+ write(fd, &mcHead, sizeof(mcHead));
+
+ for (set = cat->first; set; set = set->next) {
+ bzero(&mcSet, sizeof(mcSet));
+
+ mcSet.setId = htonl(set->setId);
+ mcSet.invalid = FALSE;
+
+ /* The rest we'll have to come back and change in a moment */
+ pos = lseek(fd, (off_t)0L, L_INCR);
+ write(fd, &mcSet, sizeof(mcSet));
+
+ /* Now write all the string data */
+ mcSet.data.off = htonll(lseek(fd, (off_t)0L, L_INCR));
+ cnt = 0;
+ for (msg = set->first; msg; msg = msg->next) {
+ msg->offset = lseek(fd, (off_t)0L, L_INCR) - ntohll(mcSet.data.off);
+ mcSet.dataLen += write(fd, msg->str, strlen(msg->str) + 1);
+ ++cnt;
+ }
+ mcSet.u.firstMsg = htonll(lseek(fd, (off_t)0L, L_INCR));
+ mcSet.numMsgs = htonl(cnt);
+ mcSet.dataLen = htonl(mcSet.dataLen);
+
+ /* Now write the message headers */
+ for (msg = set->first; msg; msg = msg->next) {
+ mcMsg.msgId = htonl(msg->msgId);
+ mcMsg.msg.off = htonll(msg->offset);
+ mcMsg.invalid = FALSE;
+ write(fd, &mcMsg, sizeof(mcMsg));
+ }
+
+ /* Go back and fix things up */
+
+ if (set == cat->last) {
+ mcSet.nextSet = 0;
+ lseek(fd, pos, L_SET);
+ write(fd, &mcSet, sizeof(mcSet));
+ } else {
+ mcSet.nextSet = htonll(lseek(fd, (off_t)0L, L_INCR));
+ lseek(fd, pos, L_SET);
+ write(fd, &mcSet, sizeof(mcSet));
+ lseek(fd, ntohll(mcSet.nextSet), L_SET);
+ }
+ }
+}
+
+void
+MCAddSet(int setId, char *hconst)
+{
+ setT *set;
+
+ if (setId <= 0) {
+ error(NULL, "setId's must be greater than zero");
+ return;
+ }
+
+ if (hconst && !*hconst) hconst = NULL;
+ for (set = cat->first; set; set = set->next) {
+ if (set->setId == setId) {
+ if (set->hconst && hconst) free(set->hconst);
+ set->hconst = NULL;
+ break;
+ } else if (set->setId > setId) {
+ setT *newSet;
+
+ newSet = (setT *) malloc(sizeof(setT));
+ if (!newSet) nomem();
+ bzero(newSet, sizeof(setT));
+ newSet->prev = set->prev;
+ newSet->next = set;
+ if (set->prev) set->prev->next = newSet;
+ else cat->first = newSet;
+ set->prev = newSet;
+ set = newSet;
+ break;
+ }
+ }
+ if (!set) {
+ set = (setT *) malloc(sizeof(setT));
+ if (!set) nomem();
+ bzero(set, sizeof(setT));
+
+ if (cat->first) {
+ set->prev = cat->last;
+ set->next = NULL;
+ cat->last->next = set;
+ cat->last = set;
+ } else {
+ set->prev = set->next = NULL;
+ cat->first = cat->last = set;
+ }
+ }
+ set->setId = setId;
+ if (hconst) set->hconst = dupstr(hconst);
+ curSet = set;
+}
+
+void
+MCAddMsg(int msgId, const char *str, char *hconst)
+{
+ msgT *msg;
+
+ if (!curSet)
+ error(NULL, "can't specify a message when no set exists");
+
+ if (msgId <= 0) {
+ error(NULL, "msgId's must be greater than zero");
+ return;
+ }
+
+ if (hconst && !*hconst) hconst = NULL;
+ for (msg = curSet->first; msg; msg = msg->next) {
+ if (msg->msgId == msgId) {
+ if (msg->hconst && hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+ msg->hconst = msg->str = NULL;
+ break;
+ } else if (msg->msgId > msgId) {
+ msgT *newMsg;
+
+ newMsg = (msgT *) malloc(sizeof(msgT));
+ if (!newMsg) nomem();
+ bzero(newMsg, sizeof(msgT));
+ newMsg->prev = msg->prev;
+ newMsg->next = msg;
+ if (msg->prev) msg->prev->next = newMsg;
+ else curSet->first = newMsg;
+ msg->prev = newMsg;
+ msg = newMsg;
+ break;
+ }
+ }
+ if (!msg) {
+ msg = (msgT *) malloc(sizeof(msgT));
+ if (!msg) nomem();
+ bzero(msg, sizeof(msgT));
+
+ if (curSet->first) {
+ msg->prev = curSet->last;
+ msg->next = NULL;
+ curSet->last->next = msg;
+ curSet->last = msg;
+ } else {
+ msg->prev = msg->next = NULL;
+ curSet->first = curSet->last = msg;
+ }
+ }
+ msg->msgId = msgId;
+ if (hconst) msg->hconst = dupstr(hconst);
+ msg->str = dupstr(str);
+}
+
+void
+MCDelSet(int setId)
+{
+ setT *set;
+ msgT *msg;
+
+ for (set = cat->first; set; set = set->next) {
+ if (set->setId == setId) {
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+ free(msg);
+ }
+ if (set->hconst) free(set->hconst);
+
+ if (set->prev) set->prev->next = set->next;
+ else cat->first = set->next;
+
+ if (set->next) set->next->prev = set->prev;
+ else cat->last = set->prev;
+
+ free(set);
+ return;
+ } else if (set->setId > setId) break;
+ }
+ warning(NULL, "specified set doesn't exist");
+}
+
+void
+MCDelMsg(int msgId)
+{
+ msgT *msg;
+
+ if (!curSet)
+ error(NULL, "you can't delete a message before defining the set");
+
+ for (msg = curSet->first; msg; msg = msg->next) {
+ if (msg->msgId == msgId) {
+ if (msg->hconst) free(msg->hconst);
+ if (msg->str) free(msg->str);
+
+ if (msg->prev) msg->prev->next = msg->next;
+ else curSet->first = msg->next;
+
+ if (msg->next) msg->next->prev = msg->prev;
+ else curSet->last = msg->prev;
+
+ free(msg);
+ return;
+ } else if (msg->msgId > msgId) break;
+ }
+ warning(NULL, "specified msg doesn't exist");
+}
+
+#if 0 /* this function is unsed and looks like debug thing */
+
+void
+MCDumpcat(fp)
+FILE *fp;
+{
+ msgT *msg;
+ setT *set;
+
+ if (!cat)
+ errx(1, "no catalog open");
+
+ for (set = cat->first; set; set = set->next) {
+ fprintf(fp, "$set %ld", set->setId);
+ if (set->hconst)
+ fprintf(fp, " # %s", set->hconst);
+ fprintf(fp, "\n\n");
+
+ for (msg = set->first; msg; msg = msg->next) {
+ if (msg->hconst)
+ fprintf(fp, "# %s\n", msg->hconst);
+ fprintf(fp, "%ld\t%s\n", msg->msgId, msg->str);
+ }
+ fprintf(fp, "\n");
+ }
+
+}
+#endif /* 0 */
diff --git a/adv_cmds/last/last.1 b/adv_cmds/last/last.1
new file mode 100644
index 0000000..8ffd49d
--- /dev/null
+++ b/adv_cmds/last/last.1
@@ -0,0 +1,111 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)last.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LAST 1
+.Os BSD 4
+.Sh NAME
+.Nm last
+.Nd indicate last logins of users and ttys
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ns Ar n
+.Op Fl h Ar host
+.Op Fl t Ar tty
+.Op user ...
+.Sh DESCRIPTION
+.Nm Last
+will list the sessions of specified
+.Ar users ,
+.Ar ttys ,
+and
+.Ar hosts ,
+in reverse time order. Each line of output contains
+the user name, the tty from which the session was conducted, any
+hostname, the start and stop times for the session, and the duration
+of the session. If the session is still continuing or was cut short by
+a crash or shutdown,
+.Nm
+will so indicate.
+.Pp
+.Bl -tag -width indent-two
+.It Fl Ns Ar n
+Limits the report to
+.Ar n
+lines.
+.It Fl h Ar host
+.Ar Host
+names may be names or internet numbers.
+.It Fl t Ar tty
+Specify the
+.Ar tty .
+Tty names may be given fully or abbreviated, for example,
+.Dq Li "last -t 03"
+is
+equivalent to
+.Dq Li "last -t tty03" .
+.El
+.Pp
+If
+multiple arguments are given, the information which applies to any of the
+arguments is printed, e.g.,
+.Dq Li "last root -t console"
+would list all of
+.Dq Li root Ns 's
+sessions as well as all sessions on the console terminal. If no
+users, hostnames or terminals are specified,
+.Nm
+prints a record of
+all logins and logouts.
+.Pp
+The pseudo-user
+.Ar reboot
+logs in at reboots of the system, thus
+.Dq Li last reboot
+will give an indication of mean time between reboot.
+.Pp
+If
+.Nm
+is interrupted, it indicates to what date the search has
+progressed. If interrupted with a quit signal
+.Nm
+indicates how
+far the search has progressed and then continues.
+.Sh SEE ALSO
+.Xr lastcomm 1 ,
+.Xr utmpx 5 ,
+.Xr ac 8
+.Sh HISTORY
+.Nm Last
+appeared in
+.Bx 3.0 .
diff --git a/adv_cmds/last/last.c b/adv_cmds/last/last.c
new file mode 100644
index 0000000..6439dd1
--- /dev/null
+++ b/adv_cmds/last/last.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved
+ *
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * The NEXTSTEP Software License Agreement specifies the terms
+ * and conditions for redistribution.
+ *
+ * @(#)last.c 8.2 (Berkeley) 4/2/94
+ */
+
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <utmpx.h>
+#include <ctype.h>
+
+#define NO 0 /* false/no */
+#define YES 1 /* true/yes */
+
+static const struct utmpx *prev; /* previous utmpx structure */
+
+/* values from utmp.h, used for print formatting */
+#define UT_NAMESIZE 8 /* old utmp.h value */
+#define UT_LINESIZE 8
+#define UT_HOSTSIZE 16
+
+typedef struct arg {
+ const char *name; /* argument */
+#define HOST_TYPE -2
+#define TTY_TYPE -3
+#define USER_TYPE -4
+ int type; /* type of arg */
+ struct arg *next; /* linked list pointer */
+} ARG;
+ARG *arglist; /* head of linked list */
+
+typedef struct ttytab {
+ long logout; /* log out time */
+ char id[_UTX_IDSIZE]; /* terminal id */
+ pid_t pid;
+ struct ttytab *next; /* linked list pointer */
+} TTY;
+TTY *ttylist; /* head of linked list */
+
+static const char *crmsg; /* cause of last reboot */
+static long currentout, /* current logout value */
+ maxrec; /* records to display */
+time_t now;
+
+void addarg __P((int, const char *));
+TTY *addtty __P((const char *, pid_t));
+void hostconv __P((const char *));
+void onintr __P((int));
+const char *ttyconv __P((const char *));
+int want __P((struct utmpx *, int));
+void wtmp __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern int optind;
+ extern char *optarg;
+ int ch;
+ char *p;
+ char *myname = *argv;
+
+ if ((p = strrchr(myname, '/')) != NULL)
+ myname = p + 1;
+ maxrec = -1;
+ while ((ch = getopt(argc, argv, "0123456789f:h:t:")) != EOF)
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ /*
+ * kludge: last was originally designed to take
+ * a number after a dash.
+ */
+ if (maxrec == -1) {
+ p = argv[optind - 1];
+ if (p[0] == '-' && p[1] == ch && !p[2])
+ maxrec = atol(++p);
+ else
+ maxrec = atol(argv[optind] + 1);
+ if (!maxrec)
+ exit(0);
+ }
+ break;
+ case 'h':
+ hostconv(optarg);
+ addarg(HOST_TYPE, optarg);
+ break;
+ case 't':
+ addarg(TTY_TYPE, ttyconv(optarg));
+ break;
+ case 'f':
+ warnx("-f is unsupported");
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr,
+ "usage: last [-#] [-t tty] [-h hostname] [user ...]\n");
+ exit(1);
+ }
+
+ if (argc) {
+ setlinebuf(stdout);
+ for (argv += optind; *argv; ++argv) {
+#define COMPATIBILITY
+#ifdef COMPATIBILITY
+ /* code to allow "last p5" to work */
+ addarg(TTY_TYPE, ttyconv(*argv));
+#endif
+ addarg(USER_TYPE, *argv);
+ }
+ }
+ wtmp();
+ exit(0);
+}
+
+/*
+ * wtmp --
+ * read through the wtmp file
+ */
+
+void
+wtmp()
+{
+
+ struct utmpx *bp; /* current structure */
+ TTY *T; /* tty list entry */
+ long delta; /* time difference */
+ char *ct;
+
+ (void)time(&now);
+ (void)signal(SIGINT, onintr);
+ (void)signal(SIGQUIT, onintr);
+
+ setutxent_wtmp(0); /* zero means reverse chronological order */
+ while ((bp = getutxent_wtmp()) != NULL) {
+ prev = bp;
+ switch(bp->ut_type) {
+ case BOOT_TIME:
+ case SHUTDOWN_TIME:
+ /* everybody just logged out */
+ for (T = ttylist; T; T = T->next)
+ T->logout = -bp->ut_tv.tv_sec;
+ currentout = -bp->ut_tv.tv_sec;
+ crmsg = bp->ut_type == BOOT_TIME ? "crash" : "shutdown";
+ if (want(bp, NO)) {
+ ct = ctime(&bp->ut_tv.tv_sec);
+ printf("%-*s %-*s %-*.*s %10.10s %5.5s \n",
+ UT_NAMESIZE, bp->ut_type == BOOT_TIME ? "reboot" : "shutdown",
+ UT_LINESIZE, "~",
+ UT_HOSTSIZE, _UTX_HOSTSIZE,
+ bp->ut_host, ct, ct + 11);
+ if (maxrec != -1 && !--maxrec)
+ return;
+ }
+ continue;
+ case OLD_TIME:
+ case NEW_TIME:
+ if (want(bp, NO)) {
+ ct = ctime(&bp->ut_tv.tv_sec);
+ printf("%-*s %-*s %-*.*s %10.10s %5.5s \n",
+ UT_NAMESIZE, "date",
+ UT_LINESIZE, bp->ut_type == OLD_TIME ? "|" : "{",
+ UT_HOSTSIZE, _UTX_HOSTSIZE, bp->ut_host,
+ ct, ct + 11);
+ if (maxrec && !--maxrec)
+ return;
+ }
+ continue;
+ case USER_PROCESS:
+ case DEAD_PROCESS:
+ /* find associated tty */
+ for (T = ttylist;; T = T->next) {
+ if (!T) {
+ /* add new one */
+ T = addtty(bp->ut_id, bp->ut_pid);
+ break;
+ }
+ if (!memcmp(T->id, bp->ut_id, _UTX_IDSIZE) && T->pid == bp->ut_pid)
+ break;
+ }
+ if (bp->ut_type != DEAD_PROCESS && want(bp, YES)) {
+ ct = ctime(&bp->ut_tv.tv_sec);
+ printf("%-*.*s %-*.*s %-*.*s %10.10s %5.5s ",
+ UT_NAMESIZE, _UTX_USERSIZE, bp->ut_user,
+ UT_LINESIZE, _UTX_LINESIZE, bp->ut_line,
+ UT_HOSTSIZE, _UTX_HOSTSIZE, bp->ut_host,
+ ct, ct + 11);
+ if (!T->logout)
+ puts(" still logged in");
+ else {
+ if (T->logout < 0) {
+ T->logout = -T->logout;
+ printf("- %s", crmsg);
+ }
+ else
+ printf("- %5.5s",
+ ctime(&T->logout)+11);
+ delta = T->logout - bp->ut_tv.tv_sec;
+ if (delta < SECSPERDAY)
+ printf(" (%5.5s)\n",
+ asctime(gmtime(&delta))+11);
+ else
+ printf(" (%ld+%5.5s)\n",
+ delta / SECSPERDAY,
+ asctime(gmtime(&delta))+11);
+ }
+ if (maxrec != -1 && !--maxrec)
+ return;
+ }
+ T->logout = bp->ut_tv.tv_sec;
+ continue;
+ }
+ }
+ endutxent_wtmp();
+ ct = ctime(prev ? &prev->ut_tv.tv_sec : &now);
+ printf("\nwtmp begins %10.10s %5.5s \n", ct, ct + 11);
+}
+
+/*
+ * want --
+ * see if want this entry
+ */
+int
+want(bp, check)
+ struct utmpx *bp;
+ int check;
+{
+ ARG *step;
+
+ if (!arglist)
+ return (YES);
+
+ for (step = arglist; step; step = step->next)
+ switch(step->type) {
+ case HOST_TYPE:
+ if (!strncasecmp(step->name, bp->ut_host, _UTX_HOSTSIZE))
+ return (YES);
+ break;
+ case TTY_TYPE:
+ {
+ char *line = bp->ut_line;
+ if (check) {
+ /*
+ * when uucp and ftp log in over a network, the entry in
+ * the utmpx file is the name plus their process id. See
+ * etc/ftpd.c and usr.bin/uucp/uucpd.c for more information.
+ */
+ if (!strncmp(line, "ftp", sizeof("ftp") - 1))
+ line = "ftp";
+ else if (!strncmp(line, "uucp", sizeof("uucp") - 1))
+ line = "uucp";
+ }
+ if (!strncmp(step->name, line, _UTX_LINESIZE))
+ return (YES);
+ break;
+ }
+ case USER_TYPE:
+ if (bp->ut_type == BOOT_TIME && !strncmp(step->name, "reboot", _UTX_USERSIZE))
+ return (YES);
+ if (bp->ut_type == SHUTDOWN_TIME && !strncmp(step->name, "shutdown", _UTX_USERSIZE))
+ return (YES);
+ if (!strncmp(step->name, bp->ut_user, _UTX_USERSIZE))
+ return (YES);
+ break;
+ }
+ return (NO);
+}
+
+/*
+ * addarg --
+ * add an entry to a linked list of arguments
+ */
+void
+addarg(type, arg)
+ int type;
+ const char *arg;
+{
+ ARG *cur;
+
+ if (!(cur = (ARG *)malloc((u_int)sizeof(ARG))))
+ err(1, "malloc failure");
+ cur->next = arglist;
+ cur->type = type;
+ cur->name = arg;
+ arglist = cur;
+}
+
+/*
+ * addtty --
+ * add an entry to a linked list of ttys
+ */
+TTY *
+addtty(id, pid)
+ const char *id;
+ pid_t pid;
+{
+ TTY *cur;
+
+ if (!(cur = (TTY *)malloc((u_int)sizeof(TTY))))
+ err(1, "malloc failure");
+ cur->next = ttylist;
+ cur->logout = currentout;
+ memmove(cur->id, id, _UTX_IDSIZE);
+ cur->pid = pid;
+ return (ttylist = cur);
+}
+
+/*
+ * hostconv --
+ * convert the hostname to search pattern; if the supplied host name
+ * has a domain attached that is the same as the current domain, rip
+ * off the domain suffix since that's what login(1) does.
+ */
+void
+hostconv(arg)
+ const char *arg;
+{
+ static int first = 1;
+ static char *hostdot, name[MAXHOSTNAMELEN];
+ char *argdot;
+
+ if (!(argdot = strchr(arg, '.')))
+ return;
+ if (first) {
+ first = 0;
+ if (gethostname(name, sizeof(name)))
+ err(1, "gethostname");
+ hostdot = strchr(name, '.');
+ }
+ if (hostdot && !strcasecmp(hostdot, argdot))
+ *argdot = '\0';
+}
+
+/*
+ * ttyconv --
+ * convert tty to correct name.
+ */
+const char *
+ttyconv(arg)
+ const char *arg;
+{
+ char *mval;
+ int kludge = 0;
+ int len = strlen(arg);
+
+ /*
+ * kludge -- we assume that most tty's end with
+ * a two character suffix.
+ */
+ if (len == 2)
+ kludge = 8; /* either 6 for "ttyxx" or 8 for "console"; use largest */
+ /*
+ * kludge -- we assume cloning ptys names are "ttys" followed by
+ * more than one digit
+ */
+ else if (len > 2 && *arg == 's') {
+ const char *cp = arg + 1;
+ while(*cp && isdigit(*cp))
+ cp++;
+ if (*cp == 0)
+ kludge = len + sizeof("tty");
+ }
+ if (kludge) {
+ if (!(mval = malloc(kludge)))
+ err(1, "malloc failure");
+ if (!strcmp(arg, "co"))
+ (void)strcpy(mval, "console");
+ else {
+ (void)strcpy(mval, "tty");
+ (void)strcpy(mval + sizeof("tty") - 1, arg);
+ }
+ return (mval);
+ }
+ if (!strncmp(arg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
+ return (arg + sizeof(_PATH_DEV) - 1);
+ return (arg);
+}
+
+/*
+ * onintr --
+ * on interrupt, we inform the user how far we've gotten
+ */
+void
+onintr(signo)
+ int signo;
+{
+ char *ct;
+
+ ct = ctime(prev ? &prev->ut_tv.tv_sec : &now);
+ printf("\ninterrupted %10.10s %5.5s \n", ct, ct + 11);
+ if (signo == SIGINT)
+ exit(1);
+ (void)fflush(stdout); /* fix required for rsh */
+}
diff --git a/adv_cmds/locale/locale.1 b/adv_cmds/locale/locale.1
new file mode 100644
index 0000000..e4df365
--- /dev/null
+++ b/adv_cmds/locale/locale.1
@@ -0,0 +1,101 @@
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.\"See Also:
+.\"man mdoc.samples for a complete listing of options
+.\"man mdoc for the short list of editing options
+.\"/usr/share/misc/mdoc.template
+.Dd August 27, 2004
+.Dt LOCALE 1
+.Os Darwin
+.Sh NAME
+.Nm locale
+.Nd display locale settings
+.Sh SYNOPSIS
+.Nm
+.Op Fl a|m
+.Nm
+.Op Fl ck
+.Ar name
+.Op ...
+.Sh DESCRIPTION
+.Nm
+displays information about the current locale, or a list of all available
+locales.
+.Pp
+When
+.Nm
+is run with no arguments,
+it will display the current source of each locale category.
+.Pp
+When
+.Nm
+is given the name of a category,
+it acts as if it had been given each keyword in that category.
+For each keyword it is given, the current value
+is displayed.
+.Sh OPTIONS
+.Bl -tag -width -indent
+.It Fl a
+Lists all public locales.
+.It Fl c Ar name ...
+Lists the category name before each keyword,
+unless it is the same category as the previously displayed keyword.
+.It Fl k Ar name ...
+Displays the name of each keyword prior to its value.
+.It Fl m
+Lists all available public charmaps.
+Darwin locales do not support charmaps, so list all CODESETs instead.
+.El
+.Pp
+.Sh OPERANDS
+The following operand is supported:
+.Pp
+.Ar name
+is the name of a keyword or category to display. A list of all keywords
+and categories can be shown with the following command:
+.Bd -literal
+locale -ck LC_ALL
+.Ed
+.Pp
+.Sh ENVIRONMENT
+.Bl -tag -width "LC_MESSAGES"
+.It Ev LANG
+Used as a substitute for any unset
+.Ev LC_*
+variable. If
+.Ev LANG
+is unset, it will act as if set to "C". If any of
+.Ev LANG
+or
+.Ev LC_*
+are set to invalid values,
+.Nm
+acts as if they are all unset.
+.It Ev LC_ALL
+Will override the setting of all other
+.Ev LC_*
+variables.
+.It Ev LC_COLLATE
+Sets the locale for the LC_COLLATE category.
+.It Ev LC_CTYPE
+Sets the locale for the LC_CTYPE category.
+.It Ev LC_MESSAGES
+Sets the locale for the LC_MESSAGES category.
+.It Ev LC_MONETARY
+Sets the locale for the LC_MONETARY category.
+.It Ev LC_NUMERIC
+Sets the locale for the LC_NUMERIC category.
+.It Ev LC_TIME
+Sets the locale for the LC_TIME category.
+.El
+.Sh SEE ALSO
+.Xr localedef 1 ,
+.Xr localeconv 3 ,
+.Xr nl_langinfo 3 ,
+.Xr setlocale 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to IEEE Std 1003.1-2001 (``POSIX.1'').
+.Sh HISTORY
+.Nm
+appeared in Mac OS X 10.4
diff --git a/adv_cmds/locale/locale.cc b/adv_cmds/locale/locale.cc
new file mode 100644
index 0000000..88c7784
--- /dev/null
+++ b/adv_cmds/locale/locale.cc
@@ -0,0 +1,428 @@
+#include <iostream>
+#include <sstream>
+#include <map>
+#include <set>
+#include <vector>
+#include <algorithm>
+
+#include <unistd.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <xlocale.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#define LAST(array) array + (sizeof(array) / sizeof(*array))
+
+#define LC_SPECIAL (LC_COLLATE+LC_CTYPE+LC_MESSAGES+LC_MONETARY+LC_NUMERIC+LC_TIME)
+
+using namespace std;
+
+enum vtype {
+ V_STR, V_NUM
+};
+
+template<typename T> string tostr(T val) {
+ ostringstream ss;
+ ss << val;
+ return ss.str();
+}
+
+string quote(string s) {
+ return '"' + s + '"';
+}
+
+class keyword {
+ public:
+ virtual string get_category() const { return category; }
+ virtual string get_keyword() const { return kword; }
+ virtual string get_value(bool show_quotes) const {
+ return (show_quotes && t == V_STR) ? quote(value) : value; }
+
+ virtual ~keyword() { }
+ protected:
+ keyword(int category_, string kword, string value, vtype t)
+ : kword(kword), value(value), t(t) {
+ switch(category_) {
+ case LC_COLLATE:
+ category = "LC_COLLATE";
+ break;
+ case LC_CTYPE:
+ category = "LC_CTYPE";
+ break;
+ case LC_MESSAGES:
+ category = "LC_MESSAGES";
+ break;
+ case LC_MONETARY:
+ category = "LC_MONETARY";
+ break;
+ case LC_NUMERIC:
+ category = "LC_NUMERIC";
+ break;
+ case LC_TIME:
+ category = "LC_TIME";
+ break;
+ case LC_SPECIAL:
+ category = "LC_SPECIAL";
+ break;
+ default:
+ {
+ ostringstream lc;
+ lc << "LC_" << category_;
+ category = lc.str();
+ }
+ break;
+ }
+ }
+
+ string category, kword, value;
+ vtype t;
+};
+
+struct keyword_cmp {
+ bool operator()(const keyword *a, const keyword *b) const {
+ return a->get_category() < b->get_category();
+ }
+};
+
+class li_keyword : public keyword {
+ public:
+ li_keyword(int category, string kword, int itemnum, vtype t = V_STR)
+ : keyword(category, kword, nl_langinfo(itemnum), t) { }
+};
+
+class lia_keyword : public keyword {
+ protected:
+ vector<string> values;
+ public:
+ virtual string get_value(bool show_quotes) const {
+ ostringstream ss;
+ vector<string>::const_iterator s(values.begin()), e(values.end()), i(s);
+
+ for(; i < e; ++i) {
+ if (i != s) {
+ ss << ';';
+ }
+ if (show_quotes && t == V_STR) {
+ ss << quote(*i);
+ } else {
+ ss << *i;
+ }
+ }
+
+ return ss.str();
+ }
+
+ lia_keyword(int category, string kword, int *s, int *e, vtype t = V_STR)
+ : keyword(category, kword, "", t) {
+ for(; s < e; ++s) {
+ values.push_back(nl_langinfo(*s));
+ }
+ }
+};
+
+class lc_keyword : public keyword {
+ public:
+ lc_keyword(int category, string kword, string value, vtype t = V_STR)
+ : keyword(category, kword, value, t) { }
+};
+
+void usage(char *argv0) {
+ clog << "usage: " << argv0 << "[-a|-m]\n or: "
+ << argv0 << " [-cCk] name..." << endl;
+}
+
+void list_all_valid_locales() {
+ string locale_dir("/usr/share/locale");
+ bool found_C = false, found_POSIX = false;
+ DIR *d = opendir(locale_dir.c_str());
+ struct dirent *de;
+ static string expected[] = { "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES",
+ "LC_NUMERIC", "LC_TIME" };
+
+ for(de = readdir(d); de; de = readdir(d)) {
+ string lname(de->d_name, de->d_namlen);
+ string ldir(locale_dir + "/" + lname);
+ int cnt = 0;
+ DIR *ld = opendir(ldir.c_str());
+ if (ld) {
+ struct dirent *lde;
+ for(lde = readdir(ld); lde; lde = readdir(ld)) {
+ string fname(lde->d_name, lde->d_namlen);
+ if (LAST(expected) != find(expected, LAST(expected), fname)) {
+ cnt++;
+ }
+ }
+ closedir(ld);
+
+ if (cnt == LAST(expected) - expected) {
+ cout << lname << endl;
+ if (lname == "C") {
+ found_C = true;
+ }
+ if (lname == "POSIX") {
+ found_POSIX = true;
+ }
+ }
+ }
+ }
+ closedir(d);
+ if (!found_C) {
+ cout << "C" << endl;
+ }
+ if (!found_POSIX) {
+ cout << "POSIX" << endl;
+ }
+}
+
+void show_all_unique_codesets() {
+ string locale_dir("/usr/share/locale");
+ DIR *d = opendir(locale_dir.c_str());
+ struct dirent *de;
+ static string expected[] = { "LC_COLLATE", "LC_CTYPE", "LC_MESSAGES",
+ "LC_NUMERIC", "LC_TIME" };
+ set<string> codesets;
+ for(de = readdir(d); de; de = readdir(d)) {
+ string lname(de->d_name, de->d_namlen);
+ string ldir(locale_dir + "/" + lname);
+ int cnt = 0;
+ DIR *ld = opendir(ldir.c_str());
+ if (ld) {
+ struct dirent *lde;
+ for(lde = readdir(ld); lde; lde = readdir(ld)) {
+ string fname(lde->d_name, lde->d_namlen);
+ if (LAST(expected) != find(expected, LAST(expected), fname)) {
+ cnt++;
+ }
+ }
+ closedir(ld);
+
+ if (cnt == LAST(expected) - expected) {
+ locale_t xloc = newlocale(LC_ALL_MASK, lname.c_str(), NULL);
+ if (xloc) {
+ char *cs = nl_langinfo_l(CODESET, xloc);
+ if (cs && *cs && (codesets.find(cs) == codesets.end())) {
+ cout << cs << endl;
+ codesets.insert(cs);
+ }
+ freelocale(xloc);
+ }
+ }
+ }
+ }
+ closedir(d);
+}
+
+typedef map<string, keyword *> keywords_t;
+keywords_t keywords;
+
+typedef map<string, vector<keyword *> > catorgies_t;
+catorgies_t catoriges;
+
+void add_kw(keyword *k) {
+ keywords.insert(make_pair(k->get_keyword(), k));
+ catorgies_t::iterator c = catoriges.find(k->get_category());
+ if (c != catoriges.end()) {
+ c->second.push_back(k);
+ } else {
+ vector<keyword *> v;
+ v.push_back(k);
+ catoriges.insert(make_pair(k->get_category(), v));
+ }
+}
+
+string grouping(char *g) {
+ ostringstream ss;
+ if (*g == 0) {
+ ss << "0";
+ } else {
+ ss << static_cast<int>(*g);
+ while(*++g) {
+ ss << ";" << static_cast<int>(*g);
+ }
+ }
+ return ss.str();
+}
+
+void init_keywords() {
+ struct lconv *lc = localeconv();
+ if (lc) {
+ add_kw(new lc_keyword(LC_NUMERIC, "decimal_point", lc->decimal_point));
+ add_kw(new lc_keyword(LC_NUMERIC, "thousands_sep", lc->thousands_sep));
+ add_kw(new lc_keyword(LC_NUMERIC, "grouping", grouping(lc->grouping)));
+ add_kw(new lc_keyword(LC_MONETARY, "int_curr_symbol", lc->int_curr_symbol));
+ add_kw(new lc_keyword(LC_MONETARY, "currency_symbol", lc->currency_symbol));
+ add_kw(new lc_keyword(LC_MONETARY, "mon_decimal_point", lc->mon_decimal_point));
+ add_kw(new lc_keyword(LC_MONETARY, "mon_thousands_sep", lc->mon_thousands_sep));
+ add_kw(new lc_keyword(LC_MONETARY, "mon_grouping", grouping(lc->mon_grouping)));
+ add_kw(new lc_keyword(LC_MONETARY, "positive_sign", lc->positive_sign));
+ add_kw(new lc_keyword(LC_MONETARY, "negative_sign", lc->negative_sign));
+ add_kw(new lc_keyword(LC_MONETARY, "int_frac_digits", tostr((int)lc->int_frac_digits), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "frac_digits", tostr((int)lc->frac_digits), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "p_cs_precedes", tostr((int)lc->p_cs_precedes), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "p_sep_by_space", tostr((int)lc->p_sep_by_space), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "n_cs_precedes", tostr((int)lc->n_cs_precedes), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "n_sep_by_space", tostr((int)lc->n_sep_by_space), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "p_sign_posn", tostr((int)lc->p_sign_posn), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "n_sign_posn", tostr((int)lc->n_sign_posn), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_p_cs_precedes", tostr((int)lc->int_p_cs_precedes), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_n_cs_precedes", tostr((int)lc->int_n_cs_precedes), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_p_sep_by_space", tostr((int)lc->int_p_sep_by_space), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_n_sep_by_space", tostr((int)lc->int_n_sep_by_space), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_p_sign_posn", tostr((int)lc->int_p_sign_posn), V_NUM));
+ add_kw(new lc_keyword(LC_MONETARY, "int_n_sign_posn", tostr((int)lc->int_n_sign_posn), V_NUM));
+ }
+
+ int abdays[] = {ABDAY_1, ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7};
+ add_kw(new lia_keyword(LC_TIME, "ab_day", abdays, LAST(abdays)));
+ add_kw(new lia_keyword(LC_TIME, "abday", abdays, LAST(abdays)));
+
+ int days[] = {DAY_1, DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7};
+ add_kw(new lia_keyword(LC_TIME, "day", days, LAST(days)));
+
+ int abmons[] = {ABMON_1, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, ABMON_11, ABMON_12};
+ add_kw(new lia_keyword(LC_TIME, "abmon", abmons, LAST(abmons)));
+
+ int mons[] = {MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12};
+ add_kw(new lia_keyword(LC_TIME, "mon", mons, LAST(mons)));
+
+ int am_pms[] = {AM_STR, PM_STR};
+ add_kw(new lia_keyword(LC_TIME, "am_pm", am_pms, LAST(am_pms)));
+
+ add_kw(new li_keyword(LC_TIME, "t_fmt_ampm", T_FMT_AMPM));
+ add_kw(new li_keyword(LC_TIME, "era", ERA));
+ add_kw(new li_keyword(LC_TIME, "era_d_fmt", ERA_D_FMT));
+ add_kw(new li_keyword(LC_TIME, "era_t_fmt", ERA_T_FMT));
+ add_kw(new li_keyword(LC_TIME, "era_d_t_fmt", ERA_D_T_FMT));
+ add_kw(new li_keyword(LC_TIME, "alt_digits", ALT_DIGITS));
+
+ add_kw(new li_keyword(LC_TIME, "d_t_fmt", D_T_FMT));
+ add_kw(new li_keyword(LC_TIME, "d_fmt", D_FMT));
+ add_kw(new li_keyword(LC_TIME, "t_fmt", T_FMT));
+
+ add_kw(new li_keyword(LC_MESSAGES, "yesexpr", YESEXPR));
+ add_kw(new li_keyword(LC_MESSAGES, "noexpr", NOEXPR));
+ add_kw(new li_keyword(LC_MESSAGES, "yesstr", YESSTR));
+ add_kw(new li_keyword(LC_MESSAGES, "nostr", NOSTR));
+
+ add_kw(new li_keyword(LC_CTYPE, "charmap", CODESET));
+ add_kw(new lc_keyword(LC_SPECIAL, "categories", "LC_COLLATE LC_CTYPE LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME"));
+
+ // add_kw: CRNCYSTR D_MD_ORDER CODESET RADIXCHAR THOUSEP
+}
+
+void show_keyword(string &last_cat, bool sw_categories, bool sw_keywords,
+ keyword *k) {
+ if (sw_categories && last_cat != k->get_category()) {
+ last_cat = k->get_category();
+ cout << last_cat << endl;
+ }
+ if (sw_keywords) {
+ cout << k->get_keyword() << "=";
+ }
+ cout << k->get_value(sw_keywords) << endl;
+}
+
+int main(int argc, char *argv[]) {
+ int sw;
+ bool sw_all_locales = false, sw_categories = false, sw_keywords = false,
+ sw_charmaps = false;
+
+ while(-1 != (sw = getopt(argc, argv, "ackm"))) {
+ switch(sw) {
+ case 'a':
+ sw_all_locales = true;
+ break;
+ case 'c':
+ sw_categories = true;
+ break;
+ case 'k':
+ sw_keywords = true;
+ break;
+ case 'm':
+ sw_charmaps = true;
+ break;
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+ if ((sw_all_locales && sw_charmaps)
+ || ((sw_all_locales || sw_charmaps) && (sw_keywords || sw_categories))
+ ) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ setlocale(LC_ALL, "");
+
+ if (!(sw_all_locales || sw_categories || sw_keywords || sw_charmaps)
+ && argc == optind) {
+ char *lang = getenv("LANG");
+ cout << "LANG=" << quote(lang ? lang : "") << endl;
+ cout << "LC_COLLATE=" << quote(setlocale(LC_COLLATE, NULL)) << endl;
+ cout << "LC_CTYPE=" << quote(setlocale(LC_CTYPE, NULL)) << endl;
+ cout << "LC_MESSAGES=" << quote(setlocale(LC_MESSAGES, NULL)) << endl;
+ cout << "LC_MONETARY=" << quote(setlocale(LC_MONETARY, NULL)) << endl;
+ cout << "LC_NUMERIC=" << quote(setlocale(LC_NUMERIC, NULL)) << endl;
+ cout << "LC_TIME=" << quote(setlocale(LC_TIME, NULL)) << endl;
+ if (getenv("LC_ALL")) {
+ cout << "LC_ALL=" << quote(setlocale(LC_ALL, NULL)) << endl;
+ } else {
+ cout << "LC_ALL=" << endl;
+ }
+
+ return 0;
+ }
+
+ if (sw_all_locales) {
+ list_all_valid_locales();
+ return 0;
+ }
+
+ if (sw_charmaps) {
+ show_all_unique_codesets();
+ return 0;
+ }
+
+ init_keywords();
+ string last_cat("");
+ int exit_val = 0;
+ for(int i = optind; i < argc; ++i) {
+ keywords_t::iterator ki = keywords.find(argv[i]);
+ if (ki != keywords.end()) {
+ show_keyword(last_cat, sw_categories, sw_keywords, ki->second);
+ } else {
+ catorgies_t::iterator ci = catoriges.find(argv[i]);
+ if (ci != catoriges.end()) {
+ vector<keyword *>::iterator vi(ci->second.begin()),
+ ve(ci->second.end());
+ for(; vi != ve; ++vi) {
+ show_keyword(last_cat, sw_categories, sw_keywords, *vi);
+ }
+ } else if (argv[i] == string("LC_ALL")) {
+ ki = keywords.begin();
+ keywords_t::iterator ke = keywords.end();
+ for(; ki != ke; ++ki) {
+ show_keyword(last_cat, sw_categories, sw_keywords, ki->second);
+ }
+ } else {
+ if (argv[i] == string("LC_CTYPE")
+ || argv[i] == string("LC_COLLATE")) {
+ // It would be nice to print a warning,
+ // but we aren't allowed (locale.ex test#14)
+ if (sw_categories) {
+ cout << argv[i] << endl;
+ }
+ } else {
+ clog << "unknown keyword "
+ << argv[i] << endl;
+ exit_val = 1;
+ }
+ }
+ }
+ }
+
+ return exit_val;
+}
diff --git a/adv_cmds/localedef/charmap.p-1 b/adv_cmds/localedef/charmap.p-1
new file mode 100644
index 0000000..3901dd9
--- /dev/null
+++ b/adv_cmds/localedef/charmap.p-1
@@ -0,0 +1,23 @@
+CHARMAP
+<space> \x20
+<dollar> \x24
+<A> \101
+<a> \141
+<A-acute> \346
+<a-acute> \365
+<A-grave> \300
+<a-grave> \366
+<b> \142
+<B> \102
+<C> \103
+<c> \143
+<c-cedilla> \347
+<d> \x64
+<E> \x65
+<H> \110
+<h> \150
+<eszet> \xb7
+<s> \x73
+<z> \x7a
+<e> \x65
+END CHARMAP
diff --git a/adv_cmds/localedef/charmap.p-2 b/adv_cmds/localedef/charmap.p-2
new file mode 100644
index 0000000..75a3fdf
--- /dev/null
+++ b/adv_cmds/localedef/charmap.p-2
@@ -0,0 +1,115 @@
+CHARMAP
+<NUL> \000
+<alert> \007
+<backspace> \010
+<tab> \011
+<newline> \012
+<vertical-tab> \013
+<form-feed> \014
+<carriage-return> \015
+<space> \040
+<exclamation-mark> \041
+<quotation-mark> \042
+<number-sign> \043
+<dollar-sign> \044
+<percent-sign> \045
+<ampersand> \046
+<apostrophe> \047
+<left-parenthesis> \050
+<right-parenthesis> \051
+<asterisk> \052
+<plus-sign> \053
+<comma> \054
+<hyphen> \055
+<hyphen-minus> \055
+<period> \056
+<full-stop> \056
+<slash> \057
+<solidus> \057
+<zero> \060
+<one> \061
+<two> \062
+<three> \063
+<four> \064
+<five> \065
+<six> \066
+<seven> \067
+<eight> \070
+<nine> \071
+<colon> \072
+<semicolon> \073
+<less-then-sign> \074
+<equals-sign> \075
+<greater-then-sign> \076
+<question-mark> \077
+<commercial-at> \100
+<A> \101
+<B> \102
+<C> \103
+<D> \104
+<E> \105
+<F> \106
+<G> \107
+<H> \110
+<I> \111
+<J> \112
+<K> \113
+<L> \114
+<M> \115
+<N> \116
+<O> \117
+<P> \120
+<Q> \121
+<R> \122
+<S> \123
+<T> \124
+<U> \125
+<V> \126
+<W> \127
+<X> \130
+<Y> \131
+<Z> \132
+<left-square-bracket> \133
+<backslash> \134
+<reverse-solidus> \134
+<right-square-bracket> \135
+<circumflex> \136
+<circumflex-accent> \136
+<underscore> \137
+<underline> \137
+<low-line> \137
+<grave-accent> \140
+<a> \141
+<b> \142
+<c> \143
+<d> \144
+<e> \145
+<f> \146
+<g> \147
+<h> \150
+<i> \151
+<j> \152
+<k> \153
+<l> \154
+<m> \155
+<n> \156
+<o> \157
+<p> \160
+<q> \161
+<r> \162
+<s> \163
+<t> \164
+<u> \165
+<v> \166
+<w> \167
+<x> \170
+<y> \171
+<z> \172
+<left-brace> \173
+<left-curly-bracket> \173
+<vertical-line> \174
+<right-brace> \175
+<right-curly-bracket> \175
+<tilde> \176
+<DEL> \177
+END CHARMAP
diff --git a/adv_cmds/localedef/charmap.test b/adv_cmds/localedef/charmap.test
new file mode 100644
index 0000000..fd40463
--- /dev/null
+++ b/adv_cmds/localedef/charmap.test
@@ -0,0 +1,38 @@
+CHARMAP
+<mb_cur_max> 2
+<mb_cur_min> 2
+
+<acute-accent> \047
+<grave-accent> \140
+
+<A> \x41
+<B> \102
+<C> C
+<D> \104
+<E> "E"
+<F> \d70
+
+<backslash> \\
+<double-E> "<E><E>"
+
+<A-grave> \x60\x41
+<A-acute> \x27\x41
+<a-grave> \x60\x61
+<a-acute> \x27\x61
+
+<j0101>...<j0104> \x12\x34
+END CHARMAP
+
+WIDTH
+<A>...<D> 1
+<j0101>...<j0104> 2
+<no-such-symbol> 27
+
+<A-grave> 2
+<A-acute> 2
+<a-grave> 2
+<a-acute> 2
+
+WIDTH_DEFAULT 1
+
+END WIDTH
diff --git a/adv_cmds/localedef/def.a55 b/adv_cmds/localedef/def.a55
new file mode 100644
index 0000000..386e1c1
--- /dev/null
+++ b/adv_cmds/localedef/def.a55
@@ -0,0 +1,6 @@
+LC_COLLATE
+order_start forward
+order_start forward;forward;forward
+<a>
+order_end
+END LC_COLLATE
diff --git a/adv_cmds/localedef/def.p-1 b/adv_cmds/localedef/def.p-1
new file mode 100644
index 0000000..adef476
--- /dev/null
+++ b/adv_cmds/localedef/def.p-1
@@ -0,0 +1,157 @@
+#
+LC_CTYPE
+lower <a>;<b>;<c>;<c-cedilla>;<d>;...;<z>
+upper A;B;C;C;...;Z
+space \x20;\x09;\x0a;\x0b;\x0c;\x0d
+blank \040;\011
+toupper (<a>,<A>);(b,B);(c,C);(c,C);(d,D);(z,Z)
+digit 3;2
+END LC_CTYPE
+#
+LC_COLLATE
+#
+# The following example of collation is based on the proposed
+# Canadian standard Z243.4.1-1990, "Canadian Alphanumeric
+# Ordering Standard For Character sets of CSA Z234.4 Standard".
+# (Other parts of this example locale definition file do not
+# purport to relate to Canada, or to any other real culture.)
+# The proposed standard defines a 4-weight collation, such that
+# in the first pass, characters are compared without regard to
+# case or accents; in second pass, backwards compare without
+# regard to case; in the third pass, forward compare without
+# regard to diacriticals. In the 3 first passes, non-alphabetic
+# characters are ignored; in the fourth pass, only special
+# characters are considered, such that "The string that has a
+# special character in the lowest position comes first. If two
+# strings have a special character in the same position, the
+# collation value of the special character determines ordering.
+#
+# Only a subset of the character set is used here; mostly to
+# illustrate the set-up.
+#
+#
+collating-symbol <LOW_VALUE>
+collating-symbol <LOWER-CASE>
+collating-symbol <SUBSCRIPT-LOWER>
+collating-symbol <SUPERSCRIPT-LOWER>
+collating-symbol <UPPER-CASE>
+collating-symbol <NO-ACCENT>
+collating-symbol <PECULIAR>
+collating-symbol <LIGATURE>
+collating-symbol <ACUTE>
+collating-symbol <GRAVE>
+collating-symbol <RING-ABOVE>
+collating-symbol <DIAERESIS>
+collating-symbol <TILDE>
+# Further collating-symbols follow.
+#
+# Properly, the standard does not include any multi-character
+# collating elements; the one below is added for completeness.
+#
+collating_element <ch> from "<c><h>"
+collating_element <CH> from "<C><H>"
+collating_element <Ch> from "<C><h>"
+collating_element <AE> from "<A><E>"
+collating_element <ae> from "<a><e>"
+#
+order_start forward;backward;forward;forward,position
+#
+# Collating symbols are specified first in the sequence to allocate
+# basic collation values to them, lower than that of any character.
+<LOW_VALUE>
+<LOWER-CASE>
+<SUBSCRIPT-LOWER>
+<SUPERSCRIPT-LOWER>
+<UPPER-CASE>
+<NO-ACCENT>
+<PECULIAR>
+<LIGATURE>
+<ACUTE>
+<GRAVE>
+<RING-ABOVE>
+<DIAERESIS>
+<TILDE>
+# Further collating symbols are given a basic collating value here.
+#
+# Here follow special characters.
+<space> IGNORE;IGNORE;IGNORE;<space>
+# Other special characters follow here.
+#
+# Here follow the regular characters.
+<a> <a>;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<A> <a>;<NO-ACCENT>;<UPPER-CASE>;IGNORE
+<a-acute> <a>;<ACUTE>;<LOWER-CASE>;IGNORE
+<A-acute> <a>;<ACUTE>;<UPPER-CASE>;IGNORE
+<a-grave> <a>;<GRAVE>;<LOWER-CASE>;IGNORE
+<A-grave> <a>;<GRAVE>;<UPPER-CASE>;IGNORE
+<ae> "<a><e>";"<LIGATURE><LIGATURE>";\
+ "<LOWER-CASE><LOWER-CASE>";IGNORE
+<AE> "<a><e>";"<LIGATURE><LIGATURE>";\
+ "<UPPER-CASE><UPPER-CASE>";IGNORE
+<b> <b>;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+... ...;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<z> ...;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<B> <b>;<NO-ACCENT>;<UPPER-CASE>;IGNORE
+<c> <c>;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<C> <c>;<NO-ACCENT>;<UPPER-CASE>;IGNORE
+<ch> <ch>;<NO-ACCENT>;<LOWER-CASE>;IGNORE
+<Ch> <ch>;<NO-ACCENT>;<PECULIAR>;IGNORE
+<CH> <ch>;<NO-ACCENT>;<UPPER-CASE>;IGNORE
+#
+# As an example, the strings "Bach" and "bach" could be encoded (for
+# compare purposes) as:
+# "Bach" <b>;<a>;<ch>;<LOW_VALUE>;<NO_ACCENT>;<NO_ACCENT>;\
+# <NO_ACCENT>;<LOW_VALUE>;<UPPER>;<LOWER>;<LOWER>;<NULL>
+# "bach" <b>;<a>;<ch>;<LOW_VALUE>;<NO_ACCENT>;<NO_ACCENT>;\
+# <NO_ACCENT>;<LOW_VALUE>;<LOWER>;<LOWER>;<LOWER>;<NULL>
+#
+# The two strings are equal in pass 1 and 2, but differ in pass 3.
+#
+# Further characters follow.
+#
+UNDEFINED IGNORE;IGNORE;IGNORE;IGNORE
+#
+order_end
+#
+END LC_COLLATE
+#
+LC_MONETARY
+int_curr_symbol "USD "
+currency_symbol "$"
+mon_decimal_point "."
+mon_grouping 3;0
+positive_sign ""
+negative_sign "-"
+p_cs_precedes 1
+n_sign_posn 0
+END LC_MONETARY
+#
+LC_NUMERIC
+copy "US_en.ASCII"
+decimal_point .
+thousands_sep \,
+grouping 3;3
+END LC_NUMERIC
+#
+LC_TIME
+abday "Sun";"Mon";"Tue";"Wed";"Thu";"Fri";"Sat"
+#
+day "Sunday";"Monday";"Tuesday";"Wednesday";\
+ "Thursday";"Friday";"Saturday"
+#
+abmon "Jan";"Feb";"Mar";"Apr";"May";"Jun";\
+ "Jul";"Aug";"Sep";"Oct";"Nov";"Dec"
+#
+mon "January";"February";"March";"April";\
+ "May";"June";"July";"August";"September";\
+ "October";"November";"December"
+#
+d_t_fmt "%a %b %d %T %Z %Y\n"
+am_pm "Am";"Pm"
+END LC_TIME
+#
+LC_MESSAGES
+yesexpr "^([yY][[:alpha:]]*)|(OK)"
+#
+noexpr "^[nN][[:alpha:]]*"
+END LC_MESSAGES
diff --git a/adv_cmds/localedef/def.p-2 b/adv_cmds/localedef/def.p-2
new file mode 100644
index 0000000..9b6ee15
--- /dev/null
+++ b/adv_cmds/localedef/def.p-2
@@ -0,0 +1,280 @@
+LC_CTYPE
+# The following is the POSIX locale LC_CTYPE.
+# "alpha" is by default "upper" and "lower"
+# "alnum" is by definition "alpha" and "digit"
+# "print" is by default "alnum", "punct" and the <space> character
+# "graph" is by default "alnum" and "punct"
+#
+upper <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>
+#
+lower <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>
+#
+digit <zero>;<one>;<two>;<three>;<four>;<five>;<six>;\
+ <seven>;<eight>;<nine>
+#
+space <tab>;<newline>;<vertical-tab>;<form-feed>;\
+ <carriage-return>;<space>
+#
+cntrl <alert>;<backspace>;<tab>;<newline>;<vertical-tab>;\
+ <form-feed>;<carriage-return>;\
+ <NUL>;<SOH>;<STX>;<ETX>;<EOT>;<ENQ>;<ACK>;<SO>;\
+ <SI>;<DLE>;<DC1>;<DC2>;<DC3>;<DC4>;<NAK>;<SYN>;\
+ <ETB>;<CAN>;<EM>;<SUB>;<ESC>;<IS4>;<IS3>;<IS2>;\
+ <IS1>;<DEL>
+#
+punct <exclamation-mark>;<quotation-mark>;<number-sign>;\
+ <dollar-sign>;<percent-sign>;<ampersand>;<apostrophe>;\
+ <left-parenthesis>;<right-parenthesis>;<asterisk>;\
+ <plus-sign>;<comma>;<hyphen>;<period>;<slash>;\
+ <colon>;<semicolon>;<less-than-sign>;<equals-sign>;\
+ <greater-than-sign>;<question-mark>;<commercial-at>;\
+ <left-square-bracket>;<backslash>;<right-square-bracket>;\
+ <circumflex>;<underscore>;<grave-accent>;<left-curly-bracket>;\
+ <vertical-line>;<right-curly-bracket>;<tilde>
+#
+xdigit <zero>;<one>;<two>;<three>;<four>;<five>;<six>;<seven>;\
+ <eight>;<nine>;<A>;<B>;<C>;<D>;<E>;<F>;<a>;<b>;<c>;<d>;<e>;<f>
+#
+blank <space>;<tab>
+#
+toupper (<a>,<A>);(<b>,<B>);(<c>,<C>);(<d>,<D>);(<e>,<E>);\
+ (<f>,<F>);(<g>,<G>);(<h>,<H>);(<i>,<I>);(<j>,<J>);\
+ (<k>,<K>);(<l>,<L>);(<m>,<M>);(<n>,<N>);(<o>,<O>);\
+ (<p>,<P>);(<q>,<Q>);(<r>,<R>);(<s>,<S>);(<t>,<T>);\
+ (<u>,<U>);(<v>,<V>);(<w>,<W>);(<x>,<X>);(<y>,<Y>);(<z>,<Z>)
+#
+tolower (<A>,<a>);(<B>,<b>);(<C>,<c>);(<D>,<d>);(<E>,<e>);\
+ (<F>,<f>);(<G>,<g>);(<H>,<h>);(<I>,<i>);(<J>,<j>);\
+ (<K>,<k>);(<L>,<l>);(<M>,<m>);(<N>,<n>);(<O>,<o>);\
+ (<P>,<p>);(<Q>,<q>);(<R>,<r>);(<S>,<s>);(<T>,<t>);\
+ (<U>,<u>);(<V>,<v>);(<W>,<w>);(<X>,<x>);(<Y>,<y>);(<Z>,<z>)
+END LC_CTYPE
+LC_COLLATE
+# This is the POSIX locale definition for the LC_COLLATE category.
+# The order is the same as in the ASCII codeset.
+order_start forward
+<NUL>
+<SOH>
+<STX>
+<ETX>
+<EOT>
+<ENQ>
+<ACK>
+<alert>
+<backspace>
+<tab>
+<newline>
+<vertical-tab>
+<form-feed>
+<carriage-return>
+<SO>
+<SI>
+<DLE>
+<DC1>
+<DC2>
+<DC3>
+<DC4>
+<NAK>
+<SYN>
+<ETB>
+<CAN>
+<EM>
+<SUB>
+<ESC>
+<IS4>
+<IS3>
+<IS2>
+<IS1>
+<space>
+<exclamation-mark>
+<quotation-mark>
+<number-sign>
+<dollar-sign>
+<percent-sign>
+<ampersand>
+<apostrophe>
+<left-parenthesis>
+<right-parenthesis>
+<asterisk>
+<plus-sign>
+<comma>
+<hyphen>
+<period>
+<slash>
+<zero>
+<one>
+<two>
+<three>
+<four>
+<five>
+<six>
+<seven>
+<eight>
+<nine>
+<colon>
+<semicolon>
+<less-than-sign>
+<equals-sign>
+<greater-than-sign>
+<question-mark>
+<commercial-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>
+<left-square-bracket>
+<backslash>
+<right-square-bracket>
+<circumflex>
+<underscore>
+<grave-accent>
+<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>
+<left-curly-bracket>
+<vertical-line>
+<right-curly-bracket>
+<tilde>
+<DEL>
+order_end
+#
+END LC_COLLATE
+LC_MONETARY
+# This is the POSIX locale definition for
+# the LC_MONETARY category.
+#
+int_curr_symbol ""
+currency_symbol ""
+mon_decimal_point ""
+mon_thousands_sep ""
+mon_grouping -1
+positive_sign ""
+negative_sign ""
+int_frac_digits -1
+p_cs_precedes -1
+p_sep_by_space -1
+n_cs_precedes -1
+n_sep_by_space -1
+p_sign_posn -1
+n_sign_posn -1
+#
+END LC_MONETARY
+LC_NUMERIC
+# This is the POSIX locale definition for
+# the LC_NUMERIC category.
+#
+decimal_point "<period>"
+thousands_sep ""
+grouping -1
+#
+END LC_NUMERIC
+LC_TIME
+# This is the POSIX locale definition for
+# the LC_TIME category.
+#
+# Abbreviated weekday names (%a)
+abday "<S><u><n>";"<M><o><n>";"<T><u><e>";"<W><e><d>";\
+ "<T><h><u>";"<F><r><i>";"<S><a><t>"
+#
+# Full weekday names (%A)
+day "<S><u><n><d><a><y>";"<M><o><n><d><a><y>";\
+ "<T><u><e><s><d><a><y>";"<W><e><d><n><e><s><d><a><y>";\
+ "<T><h><u><r><s><d><a><y>";"<F><r><i><d><a><y>";\
+ "<S><a><t><u><r><d><a><y>"
+#
+# Abbreviated month names (%b)
+abmon "<J><a><n>";"<F><e><b>";"<M><a><r>";\
+ "<A><p><r>";"<M><a><y>";"<J><u><n>";\
+ "<J><u><l>";"<A><u><g>";"<S><e><p>";\
+ "<O><c><t>";"<N><o><v>";"<D><e><c>"
+#
+# Full month names (%B)
+mon "<J><a><n><u><a><r><y>";"<F><e><b><r><u><a><r><y>";\
+ "<M><a><r><c><h>";"<A><p><r><i><l>";\
+ "<M><a><y>";"<J><u><n><e>";\
+ "<J><u><l><y>";"<A><u><g><u><s><t>";\
+ "<S><e><p><t><e><m><b><e><r>";"<O><c><t><o><b><e><r>";\
+ "<N><o><v><e><m><b><e><r>";"<D><e><c><e><m><b><e><r>"
+#
+# Equivalent of AM/PM (%p) "AM";"PM"
+am_pm "<A><M>";"<P><M>"
+#
+# Appropriate date and time representation (%c)
+# "%a %b %e %H:%M:%S %Y"
+d_t_fmt "<percent-sign><a><space><percent-sign><b>\
+ <space><percent-sign><e><space><percent-sign><H>\
+ <colon><percent-sign><M><colon><percent-sign><S>\
+ <space><percent-sign><Y>"
+#
+# Appropriate date representation (%x) "%m/%d/%y"
+d_fmt "<percent-sign><m><slash><percent-sign><d>\
+ <slash><percent-sign><y>"
+#
+# Appropriate time representation (%X) "%H:%M:%S"
+t_fmt "<percent-sign><H><colon><percent-sign><M>\
+ <colon><percent-sign><S>"
+#
+# Appropriate 12-hour time representation (%r) "%I:%M:%S %p"
+t_fmt_ampm "<percent-sign><I><colon><percent-sign><M><colon>\
+ <percent-sign><S> <percent-sign><p>"
+#
+END LC_TIME
+LC_MESSAGES
+# This is the POSIX locale definition for
+# the LC_MESSAGES category.
+#
+yesexpr "<circumflex><left-square-bracket><y><Y><right-square-bracket>"
+#
+noexpr "<circumflex><left-square-bracket><n><N><right-square-bracket>"
+#
+yesstr "yes"
+nostr "no"
+END LC_MESSAGES
+
diff --git a/adv_cmds/localedef/localedef.1 b/adv_cmds/localedef/localedef.1
new file mode 100644
index 0000000..c8f3907
--- /dev/null
+++ b/adv_cmds/localedef/localedef.1
@@ -0,0 +1,122 @@
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.Dd September 9, 2004
+.Dt LOCALEDEF 1
+.Os Darwin
+.Sh NAME
+.Nm localedef
+.Nd define locale environment
+.Sh SYNOPSIS
+.Nm
+.Op Fl c
+.Op Fl f Ar charmap
+.Op Fl i Ar sourcefile
+.Ar name
+." localedef [-c][-f charmap][-i sourcefile] name
+.Sh DESCRIPTION
+The
+.Nm
+utility reads source definitions for one or more locale categories
+belonging to the same locale from the file named in the
+.Fl i
+option (if specified) or from standard input.
+.Pp
+The
+.Ar name
+operand identifies the target locale. The
+.Nm
+utility supports
+the creation of public, or generally accessible locales, as well
+as private, or restricted-access locales.
+.Pp
+Each category source definition is identified by the corresponding
+environment variable name and terminated by an END category-name
+statement.
+.Pp
+.Bl -tag -width "LC_MONETARY" -compact -offset indent
+.It LC_CTYPE
+Defines character classification and case conversion.
+.It LC_COLLATE
+Defines collation rules.
+.It LC_MONETARY
+Defines the format and symbols used in formatting of monetary information.
+.It LC_NUMERIC
+Defines the decimal delimiter, grouping, and grouping symbol for non-monetary numeric editing.
+.It LC_TIME
+Defines the format and content of date and time information.
+.It LC_MESSAGES
+Defines the format and values of affirmative and negative responses.
+.El
+.Sh OPTIONS
+The following options are supported:
+.Pp
+.Bl -tag -width -indent
+.It Fl c
+Create permanent output even if warning messages have been issued.
+.It Fl f Ar charmap
+Specify the pathname of a file containing a mapping of character symbols and collating element symbols to actual character encodings.
+.It Fl i Ar sourcefile
+The pathname of a file containing the source definitions. If this option is not present, source definitions will be read from standard input.
+.El
+.Sh OPERANDS
+The following operand is supported:
+.Bl -tag -width -indent
+.It Ar name
+Identifies the locale.
+If the name contains one or more slash characters,
+.Ar name
+will be interpreted as a pathname
+where the created locale definitions will be stored.
+If
+.Ar name
+does not contain any slash characters,
+the locale will be public.
+This capability is restricted to users with appropriate privileges.
+(As a consequence of specifying one name,
+although several categories can be processed in one execution,
+only categories belonging to the same locale can be processed.)
+.El
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width "LC_COLLATE"
+.It Ev LANG
+Provide a default value for the internationalization variables
+that are unset or null.
+If LANG is unset or null,
+the corresponding value from the implementation-dependent default locale
+will be used.
+If any of the internationalization variables contains an invalid setting,
+the utility will behave as if none of the variables had been defined.
+.It Ev LC_ALL
+If set to a non-empty string value, override the values of all the other internationalization variables.
+.It Ev LC_COLLATE
+(This variable has no effect on
+.Nm ;
+the POSIX locale will be used for this category.)
+.It Ev LC_CTYPE
+Determine the locale for the interpretation of sequences of bytes
+of text data as characters
+(for example, single- as opposed to multi-byte characters
+in arguments and input files).
+This variable has no effect on the processing of
+.Nm
+input data;
+the POSIX locale is used for this purpose,
+regardless of the value of this variable.
+.It Ev LC_MESSAGES
+Determine the locale that should be used to affect the format and contents of diagnostic messages written to standard error.
+.It Ev NLSPATH
+Determine the location of message catalogues for the processing of LC_MESSAGES.
+.El
+.Sh EXIT STATUS
+The following exit values are returned:
+.Bl -tag -width -indent
+.It 0
+No errors occurred and the locales were successfully created.
+.It 1
+Warnings occurred and the locales were successfully created.
+.It 2
+The locale specification exceeded implementation limits or the coded character set or sets used were not supported by the implementation, and no locale was created.
+.It >2
+Warnings or errors occurred and no output was created.
+.El
diff --git a/adv_cmds/localedef/localedef.pl b/adv_cmds/localedef/localedef.pl
new file mode 100644
index 0000000..222eda0
--- /dev/null
+++ b/adv_cmds/localedef/localedef.pl
@@ -0,0 +1,1166 @@
+#!/usr/bin/perl -w
+
+use strict;
+use Getopt::Std;
+use Fcntl qw(O_TRUNC O_CREAT O_WRONLY SEEK_SET);
+use File::Temp qw(tempfile);
+use IO::File;
+
+my %opt;
+getopts("cf:u:i:", \%opt);
+
+my $comment_char = "#";
+my $escape_char = "\\";
+my $val_match = undef; # set in set_escape
+my %sym = ();
+my %width = ();
+my %ctype_classes = (
+ # there are the charactors that get automagically included, there is no
+ # standard way to avoid them. XXX even if you have a charset without
+ # some of these charactors defined!
+
+ # They are accessable in a regex via [:classname:], and libc has a
+ # isX() for most of these.
+ upper => {map { ($_, 1); } qw(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)},
+ lower => {map { ($_, 1); } qw(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)},
+ alpha => {},
+ #alnum => {},
+ digit => {map { ($_, 1); } qw(0 1 2 3 4 5 6 7 8 9)},
+ space => {},
+ cntrl => {},
+ punct => {},
+ graph => {},
+ print => {},
+ xdigit => {map { ($_, 1); } qw(0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f)},
+ blank => {" " => 1, "\t" => 1},
+
+ toupper => {map { ($_, "\U$_"); } qw(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)},
+ tolower => {map { ($_, "\L$_"); } qw(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)},
+);
+
+my %cele = (
+ # collating-elements -- these are a lot like %sym that only works
+ # in LC_COLLATE, can also be accessed in a regex via [.element.]
+);
+
+my %csym = (
+ # collating-symbols -- these are used to define a set of charactors
+ # that compare as equals (in one or more passes), can also be accessed
+ # in a regex via [=symbol=]
+);
+
+my @corder = (); # collating order
+my @corder_weights = (); # collating directions (forward, backward, position)
+
+my @colldef = ();
+
+my(%monetary, %numeric, %time, %messages);
+
+# This is the default charmap, unlike %ctype_classes you _can_ avoid this
+# merely by having your own charmap definition file
+my $default_charmap = <<EOT;
+CHARMAP
+<NUL> \\000
+<alert> \\007
+<backspace> \\010
+<tab> \\011
+<newline> \\012
+<vertical-tab> \\013
+<form-feed> \\014
+<carriage-return> \\015
+<space> \\040
+<exclamation-mark> \\041
+<quotation-mark> \\042
+<number-sign> \\043
+<dollar-sign> \\044
+<percent-sign> \\045
+<ampersand> \\046
+<apostrophe> \\047
+<left-parenthesis> \\050
+<right-parenthesis> \\051
+<asterisk> \\052
+<plus-sign> \\053
+<comma> \\054
+<hyphen> \\055
+<hyphen-minus> \\055
+<period> \\056
+<full-stop> \\056
+<slash> \\057
+<solidus> \\057
+<zero> \\060
+<one> \\061
+<two> \\062
+<three> \\063
+<four> \\064
+<five> \\065
+<six> \\066
+<seven> \\067
+<eight> \\070
+<nine> \\071
+<colon> \\072
+<semicolon> \\073
+<less-then-sign> \\074
+<less-than-sign> \\074
+<equals-sign> \\075
+<greater-then-sign> \\076
+<greater-than-sign> \\076
+<question-mark> \\077
+<commercial-at> \\100
+<A> \\101
+<B> \\102
+<C> \\103
+<D> \\104
+<E> \\105
+<F> \\106
+<G> \\107
+<H> \\110
+<I> \\111
+<J> \\112
+<K> \\113
+<L> \\114
+<M> \\115
+<N> \\116
+<O> \\117
+<P> \\120
+<Q> \\121
+<R> \\122
+<S> \\123
+<T> \\124
+<U> \\125
+<V> \\126
+<W> \\127
+<X> \\130
+<Y> \\131
+<Z> \\132
+<left-square-bracket> \\133
+<backslash> \\134
+<reverse-solidus> \\134
+<right-square-bracket> \\135
+<circumflex> \\136
+<circumflex-accent> \\136
+<underscore> \\137
+<underline> \\137
+<low-line> \\137
+<grave-accent> \\140
+<a> \\141
+<b> \\142
+<c> \\143
+<d> \\144
+<e> \\145
+<f> \\146
+<g> \\147
+<h> \\150
+<i> \\151
+<j> \\152
+<k> \\153
+<l> \\154
+<m> \\155
+<n> \\156
+<o> \\157
+<p> \\160
+<q> \\161
+<r> \\162
+<s> \\163
+<t> \\164
+<u> \\165
+<v> \\166
+<w> \\167
+<x> \\170
+<y> \\171
+<z> \\172
+<left-brace> \\173
+<left-curly-bracket> \\173
+<vertical-line> \\174
+<right-brace> \\175
+<right-curly-bracket> \\175
+<tilde> \\176
+<DEL> \\177
+
+<SOH> \\x01
+<STX> \\x02
+<ETX> \\x03
+<EOT> \\x04
+<ENQ> \\x05
+<ACK> \\x06
+<BEL> \\x07
+<BS> \\x08
+<HT> \\x09
+<NL> \\x0a
+<VT> \\x0b
+<NP> \\x0c
+<CR> \\x0d
+<SO> \\x0e
+<SI> \\x0f
+<DLE> \\x10
+<DC1> \\x11
+<DC2> \\x12
+<DC3> \\x13
+<DC4> \\x14
+<NAK> \\x15
+<SYN> \\x16
+<ETB> \\x17
+<CAN> \\x18
+<EM> \\x19
+<SUB> \\x1a
+<ESC> \\x1b
+<FS> \\x1c
+<IS4> \\x1c
+<GS> \\x1d
+<IS3> \\x1d
+<RS> \\x1e
+<IS2> \\x1e
+<US> \\x1f
+<IS1> \\x1f
+END CHARMAP
+EOT
+
+&set_escape($escape_char);
+
+use strict qw(vars);
+
+if (@ARGV != 1) {
+ &exit(4, "usage: $0 [-c] [-f charmap-file] [-u codesetname] [-i localdef-file] LOCALENAME\n");
+}
+
+my $locale_dir = $ARGV[0];
+$locale_dir = "/usr/share/locale/$locale_dir" unless ($locale_dir =~ m{/});
+
+my $CMAP;
+if (defined($opt{'f'})) {
+ # Using new IO::File $opt{'f'}, "r" runs into problems with long path names
+ sysopen(CMAP_KLUDGE, $opt{'f'}, O_RDONLY) || &exit(4, "Can't open $opt{f}: $!\n");
+ $CMAP = new IO::Handle;
+ $CMAP->fdopen(fileno(CMAP_KLUDGE), "r") || &exit(4, "Can't fdopen $opt{f}: $!\n");
+} else {
+ # er, not everyone gets IO::Scalar, so use an unamed tmp file
+ # $CMAP = new IO::Scalar \$default_charmap;
+ $CMAP = new_tmpfile IO::File;
+ print $CMAP $default_charmap;
+ seek $CMAP, 0, SEEK_SET;
+}
+
+while(<$CMAP>) {
+ if (m/^\s*CHARMAP\s*$/) {
+ &parse_charmaps();
+ } elsif (m/^\s*WIDTH\s*$/) {
+ &parse_widths();
+ } elsif (m/^\s*($comment_char.*)?$/) {
+ } else {
+ chomp;
+ &exit(4, "syntax error on line $. ($_)");
+ }
+}
+&parse_widths() if (0 == %width);
+
+if (defined($opt{'i'})) {
+ sysopen(STDIN, $opt{'i'}, 0) || &exit(4, "Can't open localdef file $opt{i}: $!");
+} else {
+ $opt{'i'} = "/dev/stdin";
+}
+
+my %LC_parsers = (
+ NONE => [\&parse_LC_NONE, qr/^\s*((escape|comment)_char\s+$val_match\s*)?$/],
+ CTYPE => [\&parse_LC_CTYPE, qr/^\s*(\S+)\s+(\S+.*?)\s*$/],
+ COLLATE => [\&parse_LC_COLLATE, qr/^\s*(<[^>\s]+>|order_end|END|(\S*)\s+(\S+.*?)|collating[_-]element\s*<[^>]+>\s+from\s+$val_match)\s*$/, 1],
+ TIME => [\&parse_LC_TIME, qr/^\s*(ab_?day|day|abmon|mon|d_t_fmt|d_fmt|t_fmt|am_pm|t_fmt_ampm|era|era_d_fmt|era_t_fmt|era_d_t_fmt|alt_digits|copy|END)\s+(\S+.*?)\s*$/],
+ NUMERIC => [\&parse_LC_NUMERIC, qr/^\s*(decimal_point|thousands_sep|grouping|END|copy)\s+(\S+.*?)\s*$/],
+ MONETARY => [\&parse_LC_MONETARY, qr/^\s*(int_curr_symbol|currency_symbol|mon_decimal_point|mon_thousands_sep|mon_grouping|positive_sign|negative_sign|int_frac_digits|frac_digits|p_cs_precedes|p_sep_by_space|n_cs_precedes|n_sep_by_space|p_sign_posn|n_sign_posn|int_p_cs_precedes|int_n_cs_precedes|int_p_sep_by_space|int_n_sep_by_space|int_p_sign_posn|int_n_sign_posn|copy|END)\s+(\S+.*?)\s*$/],
+ MESSAGES => [\&parse_LC_MESSAGES, qr/^\s*(END|yesexpr|noexpr|yesstr|nostr|copy)\s+(\S+.*?)\s*$/],
+ "COLLATE order" => [\&parse_collate_order, qr/^\s*(order_end|(<[^>\s]+>|UNDEFINED|\Q...\E)(\s+\S+.*)?)\s*$/],
+);
+my($current_LC, $parse_func, $validate_line, $call_parse_on_END)
+ = ("NONE", $LC_parsers{"NONE"}->[0], $LC_parsers{"NONE"}->[1], undef);
+
+while(<STDIN>) {
+ next if (m/^\s*($comment_char.*)?\s*$/);
+ if (m/\Q$escape_char\E$/) {
+ chomp;
+ chop;
+ my $tmp = <STDIN>;
+ if (!defined($tmp)) {
+ &exit(4, "Syntax error, last line ($.) of $opt{i} is marked as a continued line\n");
+ }
+ $tmp =~ s/^\s*//;
+ $_ .= $tmp;
+ redo;
+ }
+
+ if ($current_LC eq "NONE" && m/^\s*LC_([A-Z]+)\s*$/) {
+ &set_parser($1);
+ next;
+ }
+
+ unless (m/$validate_line/) {
+ &exit(4, "Syntax error on line $. of $opt{i}\n");
+ }
+
+ my($action, $args);
+ if (m/^\s*(\S*)(\s+(\S+.*?))?\s*$/) {
+ ($action, $args) = ($1, $3);
+ } else {
+ $action = $_;
+ chomp $action;
+ }
+
+ if ($action eq "END") {
+ if ($args ne "LC_$current_LC" || $current_LC eq "NONE") {
+ &exit(4, "Syntax error on line $. of $opt{i} attempting to end $args when LC_$current_LC is open\n");
+ }
+ if ($call_parse_on_END) {
+ &{$parse_func}($action, $args);
+ }
+ &set_parser("NONE");
+ } else {
+ &{$parse_func}($action, $args);
+ }
+}
+
+mkdir($locale_dir);
+&run_mklocale();
+&write_lc_money();
+&write_lc_time();
+&write_lc_messages();
+&write_lc_numeric();
+&write_lc_collate();
+exit 0;
+
+sub parse_charmaps {
+ while(<$CMAP>) {
+ # XXX need to parse out <code_set_name>, <mb_cur_max>, <mb_cur_min>,
+ # <escape_char>, and <comment_char> before the generic "<sym> val"
+ if (m/^\s*<([\w\-]+)>\s+($val_match+)\s*$/) {
+ my($sym, $val) = ($1, $2);
+ $val = &parse_value_double_backwhack($val);
+ $sym{$sym} = $val;
+ } elsif (m/^\s*<([\w\-]*\d)>\s*\Q...\E\s*<([\w\-]*\d)>\s+($val_match+)\s*$/) {
+ # We don't deal with $se < $ss, or overflow of the last byte of $vs
+ # then again the standard doesn't say anything in particular needs
+ # to happen for those cases
+ my($ss, $se, $vs) = ($1, $2, $3);
+ $vs = &parse_value_double_backwhack($vs);
+ my $vlast = length($vs) -1;
+ for(my($s, $v) = ($ss, $vs); $s cmp $se; $s++) {
+ $sym{$s} = $v;
+ substr($v, $vlast) = chr(ord(substr($v, $vlast)) +1)
+ }
+ } elsif (m/^\s*END\s+CHARMAP\s*$/) {
+ return;
+ } elsif (m/^\s*($comment_char.*)?$/) {
+ } else {
+ &exit(4, "syntax error on line $.");
+ }
+ }
+}
+
+sub parse_widths {
+ my $default = 1;
+ my @syms;
+
+ while(<$CMAP>) {
+ if (m/^\s*<([\w\-]+)>\s+(\d+)\s*$/) {
+ my($sym, $w) = ($1, $2);
+ print "$sym width $w\n";
+ if (!defined($sym{$sym})) {
+ warn "localedef: can't set width of unknown symbol $sym on line $.\n";
+ } else {
+ $width{$sym} = $w;
+ }
+ } elsif (m/^\s*<([\w\-]+)>\s*\Q...\E\s*<([\w\-]+)>\s+(\d+)\s*$/) {
+ my($ss, $se, $w) = ($1, $2, $3);
+ if (!@syms) {
+ @syms = sort { $a cmp $b } keys(%sym);
+ }
+
+ # Yes, we could do a binary search for find $ss in @syms
+ foreach my $s (@syms) {
+ if (($s cmp $ss) >= 0) {
+ last if (($s cmp $se) > 0);
+ }
+ }
+ } elsif (m/^\s*WIDTH_DEFAULT\s+(\d+)\s*$/) {
+ $default = $1;
+ } elsif (m/^\s*END\s+WIDTH\s*$/) {
+ last;
+ } elsif (m/^\s*($comment_char.*)?$/) {
+ } else {
+ &exit(4, "syntax error on line $.");
+ }
+ }
+
+ foreach my $s (keys(%sym)) {
+ if (!defined($width{$s})) {
+ $width{$s} = $default;
+ }
+ }
+}
+
+# This parses a single value in any of the 7 forms it can appear in,
+# returns [0] the parsed value and [1] the remander of the string
+sub parse_value_return_extra {
+ my $val = "";
+ local($_) = $_[0];
+
+ while(1) {
+ $val .= &unsym($1), next
+ if (m/\G"((?:[^"\Q$escape_char\E]+|\Q$escape_char\E.)*)"/gc);
+ $val .= chr(oct($1)), next
+ if (m/\G\Q$escape_char\E([0-7]+)/gc);
+ $val .= chr(0+$1), next
+ if (m/\G\Q$escape_char\Ed([0-9]+)/gc);
+ $val .= pack("H*", $1), next
+ if (m/\G\Q$escape_char\Ex([0-9a-fA-F]+)/gc);
+ $val .= $1, next
+ if (m/\G([^,;<>\s\Q$escape_char()\E])/gc);
+ $val .= $1
+ if (m/\G(?:\Q$escape_char\E)([,;<>\Q$escape_char()\E])/gc);
+ $val .= &unsym($1), next
+ if (m/\G(<[^>]+>)/gc);
+
+ m/\G(.*)$/;
+
+ return ($val, $1);
+ }
+}
+
+# Parse one value, if there is more then one value alert the media
+sub parse_value {
+ my ($ret, $err) = &parse_value_return_extra($_[0]);
+ if ($err ne "") {
+ &exit(4, "Syntax error, unexpected '$err' in value (after '$ret') on line $.\n");
+ }
+
+ return $ret;
+}
+
+sub parse_value_double_backwhack {
+ my($val) = @_;
+
+ my ($ret, $err) = &parse_value_return_extra($val);
+ return $ret if ($err eq "");
+
+ $val =~ s{\\\\}{\\}g;
+ ($ret, $err) = &parse_value_return_extra($val);
+ if ($err ne "") {
+ &exit(4, "Syntax error, unexpected '$err' in value (after '$ret') on line $.\n");
+ }
+
+ return $ret;
+}
+# $values is the string to parse, $dot_expand is a function ref that will
+# return an array to insert when "X;...;Y" is parsed (undef means that
+# construct is a syntax error), $nest is true if parens indicate a nested
+# value string should be parsed and put in an array ref, $return_extra
+# is true if any unparsable trailing junk should be returned as the last
+# element (otherwise it is a syntax error). Any text matching the regex
+# $specials is returned as an hash.
+sub parse_values {
+ my($values, $sep, $dot_expand, $nest, $return_extra, $specials) = @_;
+ my(@ret, $live_dots);
+
+ while($values ne "") {
+ if (defined($specials) && $values =~ s/^($specials)($sep|$)//) {
+ push(@ret, { $1, undef });
+ next;
+ }
+ if ($nest && $values =~ s/^\(//) {
+ my @subret = &parse_values($values, ',', $dot_expand, $nest, 1, $specials);
+ $values = pop(@subret);
+ push(@ret, [@subret]);
+ unless ($values =~ s/^\)($sep)?//) {
+ &exit(4, "Syntax error, unmatched open paren on line $. of $opt{i}\n");
+ }
+ next;
+ }
+
+ my($v, $l) = &parse_value_return_extra($values);
+ $values = $l;
+
+ if ($live_dots) {
+ splice(@ret, -1, 1, &{$dot_expand}($ret[$#ret], $v));
+ $live_dots = 0;
+ } else {
+ push(@ret, $v);
+ }
+
+ if (defined($dot_expand) && $values =~ s/^$sep\Q...\E$sep//) {
+ $live_dots = 1;
+ } elsif($values =~ s/^$sep//) {
+ # Normal case
+ } elsif($values =~ m/^$/) {
+ last;
+ } else {
+ last if ($return_extra);
+ &exit(4, "Syntax error parsing arguments on line $. of $opt{i}\n");
+ }
+ }
+
+ if ($live_dots) {
+ splice(@ret, -1, 1, &{$dot_expand}($ret[$#ret], undef));
+ }
+ if ($return_extra) {
+ push(@ret, $values);
+ }
+
+ return @ret;
+}
+
+sub parse_LC_NONE {
+ my($cmd, $arg) = @_;
+
+ if ($cmd eq "comment_char") {
+ $comment_char = &parse_value($arg);
+ } elsif($cmd eq "escape_char") {
+ &set_escape_char(&parse_value($arg));
+ } elsif($cmd eq "") {
+ } else {
+ &exit(4, "Syntax error on line $. of $opt{i}\n");
+ }
+}
+
+sub parse_LC_CTYPE {
+ my($cmd, $arg) = @_;
+
+ my $ctype_classes = join("|", keys(%ctype_classes));
+ if ($cmd eq "copy") {
+ # XXX -- the locale command line utility doesn't currently
+ # output any LC_CTYPE info, so there isn't much of a way
+ # to implent copy yet
+ &exit(2, "copy not supported on line $. of $opt{i}\n");
+ } elsif($cmd eq "charclass") {
+ my $cc = &parse_value($arg);
+ if (!defined($ctype_classes{$cc})) {
+ $ctype_classes{$cc} = [];
+ } else {
+ warn "charclass $cc defined more then once\n";
+ }
+ } elsif($cmd =~ m/^to(upper|lower)$/) {
+ my @arg = &parse_values($arg, ';', undef, 1);
+ foreach my $p (@arg) {
+ &exit(4, "Syntax error on line $. of $opt{i} ${cmd}'s arguments must be character pairs like (a,A);(b,B)\n") if ("ARRAY" ne ref $p || 2 != @$p);
+ }
+ foreach my $pair (@arg) {
+ $ctype_classes{$cmd}{$pair->[0]} = $pair->[1];
+ }
+ } elsif($cmd =~ m/^($ctype_classes)$/) {
+ my @arg = &parse_values($arg, ';', \&dot_expand, 0);
+ foreach my $c (@arg) {
+ $ctype_classes{$1}->{$c} = 1;
+ }
+ } elsif($cmd =~ "END") {
+ &add_to_ctype_class('alpha', keys(%{$ctype_classes{'lower'}}));
+ &add_to_ctype_class('alpha', keys(%{$ctype_classes{'upper'}}));
+ foreach my $c (qw(alpha lower upper)) {
+ foreach my $d (qw(cntrl digit punct space)) {
+ &deny_in_ctype_class($c, $d, keys(%{$ctype_classes{$d}}));
+ }
+ }
+
+ &add_to_ctype_class('space', keys(%{$ctype_classes{'blank'}}));
+ foreach my $d (qw(upper lower alpha digit graph xdigit)) {
+ &deny_in_ctype_class('space', $d, keys(%{$ctype_classes{$d}}));
+ }
+
+ foreach my $d (qw(upper lower alpha digit punct graph print xdigit)) {
+ &deny_in_ctype_class('cntrl', $d, keys(%{$ctype_classes{$d}}));
+ }
+
+ foreach my $d (qw(upper lower alpha digit cntrl xdigit space)) {
+ &deny_in_ctype_class('punct', $d, keys(%{$ctype_classes{$d}}));
+ }
+
+ foreach my $c (qw(graph print)) {
+ foreach my $a (qw(upper lower alpha digit xdigit punct)) {
+ &add_to_ctype_class($c, keys(%{$ctype_classes{$a}}));
+ }
+ foreach my $d (qw(cntrl)) {
+ &deny_in_ctype_class($c, $d, keys(%{$ctype_classes{$d}}));
+ }
+ }
+ &add_to_ctype_class('print', keys(%{$ctype_classes{'space'}}));
+
+ # Yes, this is a requirment of the standard
+ &exit(2, "The digit class must have exactly 10 elements\n") if (10 != values(%{$ctype_classes{'digit'}}));
+ foreach my $d (values %{$ctype_classes{'digit'}}) {
+ if (!defined $ctype_classes{'xdigits'}->{$d}) {
+ &exit(4, "$d isn't in class xdigits, but all digits must appaer in xdigits\n");
+ }
+ }
+
+ $ctype_classes{'alnum'} = {} unless defined $ctype_classes{'alnum'};
+ foreach my $a (qw(alpha digit)) {
+ &add_to_ctype_class('alnum', keys(%{$ctype_classes{$a}}));
+ }
+
+ } else {
+ &exit(4, "Syntax error on line $. of $opt{i}\n");
+ }
+}
+
+sub parse_LC_COLLATE {
+ my ($cmd, $arg) = @_;
+ if (defined($arg) && $arg ne "") {
+ push(@colldef, "$cmd $arg");
+ } else {
+ push(@colldef, "$cmd");
+ }
+}
+
+sub parse_collate_order {
+ my($cmd, $arg) = @_;
+
+ if ($cmd =~ m/order[-_]end/) {
+ # restore the parent parser
+ &set_parser("COLLATE");
+ my $undef_at;
+ for(my $i = 0; $i <= $#corder; ++$i) {
+ next unless "ARRAY" eq ref($corder[$i]);
+ # If ... appears as the "key" for a order entry it means the
+ # rest of the line is duplicated once for everything in the
+ # open ended range (key-pev-line, key-next-line). Any ...
+ # in the weight fields are delt with by &fixup_collate_order_args
+ if ($corder[$i]->[0] eq "...") {
+ my(@sym, $from, $to);
+
+ my @charset = sort { $sym{$a} cmp $sym{$b} } keys(%sym);
+ if ($i != 0) {
+ $from = $corder[$i -1]->[0];
+ } else {
+ $from = $charset[0];
+ }
+ if ($i != $#corder) {
+ $to = $corder[$i +1]->[0];
+ } else {
+ $to = $charset[$#charset];
+ }
+
+ my @expand;
+ my($s, $e) = (&parse_value($from), &parse_value($to));
+ foreach my $c (@charset) {
+ if (($sym{$c} cmp $s) > 0) {
+ last if (($sym{$c} cmp $e) >= 0);
+ my @entry = @{$corder[$i]};
+ $entry[0] = "<$c>";
+ push(@expand, \@entry);
+ }
+ }
+ splice(@corder, $i, 1, @expand);
+ } elsif($corder[$i]->[0] eq "UNDEFINED") {
+ $undef_at = $i;
+ next;
+ }
+ &fixup_collate_order_args($corder[$i]);
+ }
+
+ if ($undef_at) {
+ my @insert;
+ my %cused = map { ("ARRAY" eq ref $_) ? ($_->[0], undef) : () } @corder;
+ foreach my $s (keys(%sym)) {
+ next if (exists $cused{"<$s>"});
+ my @entry = @{$corder[$undef_at]};
+ $entry[0] = "<$s>";
+ &fixup_collate_order_args(\@entry);
+ push(@insert, \@entry);
+ }
+ splice(@corder, $undef_at, 1, @insert);
+ }
+ } elsif((!defined $arg) || $arg eq "") {
+ if (!exists($csym{$cmd})) {
+ my($decode, $was_sym) = &unsym_with_check($cmd);
+ if ($was_sym) {
+ my %dots = ( "..." => undef );
+ my @dots = (\%dots) x (0+@corder_weights);
+ push(@corder, [$cmd, @dots]);
+ } else {
+ warn "Undefined collation symbol $cmd used on line $. of $opt{i}\n";
+ }
+ } else {
+ push(@corder, $cmd);
+ }
+ } else {
+ unless (defined($cele{$cmd} || defined $sym{$cmd})) {
+ warn "Undefined collation element or charset sym $cmd used on line $. of $opt{i}\n";
+ } else {
+ # This expands all the symbols (but not colating elements), which
+ # makes life easier for dealing with ..., but harder for
+ # outputing the actual table at the end where we end up
+ # converting literal sequences back into symbols in some cases
+ my @args = &parse_values($arg, ';', undef, 0, 0,
+ qr/IGNORE|\Q...\E/);
+
+ if (@args != @corder_weights) {
+ if (@args < @corder_weights) {
+ &exit(4, "Only " . (0 + @args)
+ . " weights supplied on line $. of $opt{i}, needed "
+ . (0 + @corder_weights)
+ . "\n");
+ } else {
+ &exit(4, "Too many weights supplied on line $. of $opt{i},"
+ . " wanted " . (0 + @corder_weights) . " but had "
+ . (0 + @args)
+ . "\n");
+ }
+ }
+
+ push(@corder, [$cmd, @args]);
+ }
+ }
+}
+
+sub parse_LC_MONETARY {
+ my($cmd, $arg) = @_;
+
+ if ($cmd eq "copy") {
+ &do_copy(&parse_value($arg));
+ } elsif($cmd eq "END") {
+ } elsif($cmd eq "mon_grouping") {
+ my @v = &parse_values($arg, ';', undef, 0);
+ $monetary{$cmd} = \@v;
+ } else {
+ my $v = &parse_value($arg);
+ $monetary{$cmd} = $v;
+ }
+}
+
+sub parse_LC_MESSAGES {
+ my($cmd, $arg) = @_;
+
+ if ($cmd eq "copy") {
+ &do_copy(&parse_value($arg));
+ } elsif($cmd eq "END") {
+ } else {
+ my $v = &parse_value($arg);
+ $messages{$cmd} = $v;
+ }
+}
+
+sub parse_LC_NUMERIC {
+ my($cmd, $arg) = @_;
+
+ if ($cmd eq "copy") {
+ &do_copy(&parse_value($arg));
+ } elsif($cmd eq "END") {
+ } elsif($cmd eq "grouping") {
+ my @v = &parse_values($arg, ';', undef, 0);
+ $numeric{$cmd} = \@v;
+ } else {
+ my $v = &parse_value($arg);
+ $numeric{$cmd} = $v;
+ }
+}
+
+sub parse_LC_TIME {
+ my($cmd, $arg) = @_;
+
+ $cmd =~ s/^ab_day$/abday/;
+
+ if ($cmd eq "copy") {
+ &do_copy(&parse_value($arg));
+ } elsif($cmd eq "END") {
+ } elsif($cmd =~ m/abday|day|mon|abmon|am_pm|alt_digits/) {
+ my @v = &parse_values($arg, ';', undef, 0);
+ $time{$cmd} = \@v;
+ } elsif($cmd eq "era") {
+ my @v = &parse_values($arg, ':', undef, 0);
+ $time{$cmd} = \@v;
+ } else {
+ my $v = &parse_value($arg);
+ $time{$cmd} = $v;
+ }
+}
+
+
+###############################################################################
+
+sub run_mklocale {
+ my $L = (new IO::File "|/usr/bin/mklocale -o $locale_dir/LC_CTYPE") || &exit(5, "$0: Can't start mklocale $!\n");
+ if (defined($opt{'u'})) {
+ $L->print(qq{ENCODING "$opt{u}"\n});
+ } else {
+ if ($ARGV[0] =~ m/(big5|euc|gb18030|gb2312|gbk|mskanji|utf-8)/i) {
+ my $enc = uc($1);
+ $L->print(qq{ENCODING "$enc"\n});
+ } elsif($ARGV[0] =~ m/utf8/) {
+ $L->print(qq{ENCODING "UTF-8"\n});
+ } else {
+ $L->print(qq{ENCODING "NONE"\n});
+ }
+ }
+ foreach my $class (keys(%ctype_classes)) {
+ unless ($class =~ m/^(tolower|toupper|alpha|control|digit|grah|lower|space|upper|xdigit|blank|print|ideogram|special|phonogram)$/) {
+ $L->print("# skipping $class\n");
+ next;
+ }
+
+ if (!%{$ctype_classes{$class}}) {
+ $L->print("# Nothing in \U$class\n");
+ next;
+ }
+
+ if ($class =~ m/^to/) {
+ my $t = $class;
+ $t =~ s/^to/map/;
+ $L->print("\U$t ");
+
+ foreach my $from (keys(%{$ctype_classes{$class}})) {
+ $L->print("[", &hexchars($from), " ",
+ &hexchars($ctype_classes{$class}->{$from}), "] ");
+ }
+ } else {
+ $L->print("\U$class ");
+
+ foreach my $rune (keys(%{$ctype_classes{$class}})) {
+ $L->print(&hexchars($rune), " ");
+ }
+ }
+ $L->print("\n");
+ }
+
+ my @width;
+ foreach my $s (keys(%width)) {
+ my $w = $width{$s};
+ $w = 3 if ($w > 3);
+ push(@{$width[$w]}, &hexchars($sym{$s}));
+ }
+ for(my $w = 0; $w <= $#width; ++$w) {
+ next if (!defined $width[$w]);
+ next if (0 == @{$width[$w]});
+ $L->print("SWIDTH$w ", join(" ", @{$width[$w]}), "\n");
+ }
+
+ if (!$L->close()) {
+ if (0 == $!) {
+ &exit(5, "Bad return from mklocale $?");
+ } else {
+ &exit(5, "Couldn't close mklocale pipe: $!");
+ }
+ }
+}
+
+###############################################################################
+
+sub hexchars {
+ my($str) = $_[0];
+ my($ret);
+
+ $ret = unpack "H*", $str;
+ &exit(2, "Rune >4 bytes ($ret; for $str)") if (length($ret) > 8);
+
+ return "0x" . $ret;
+}
+
+sub hexseq {
+ my($str) = $_[0];
+ my($ret);
+
+ $ret = unpack "H*", $str;
+ $ret =~ s/(..)/\\x$1/g;
+
+ return $ret;
+}
+
+# dot_expand in the target charset
+sub dot_expand {
+ my($s, $e) = @_;
+ my(@ret);
+
+ my @charset = sort { $a cmp $b } values(%sym);
+ foreach my $c (@charset) {
+ if (($c cmp $s) >= 0) {
+ last if (($c cmp $e) > 0);
+ push(@ret, $c);
+ }
+ }
+
+ return @ret;
+}
+
+# Convert symbols into literal values
+sub unsym {
+ my @ret = &unsym_with_check(@_);
+ return $ret[0];
+}
+
+# Convert symbols into literal values (return[0]), and a count of how
+# many symbols were converted (return[1]).
+sub unsym_with_check {
+ my($str) = $_[0];
+
+ my $rx = join("|", keys(%sym));
+ return ($str, 0) if ($rx eq "");
+ my $found = $str =~ s/<($rx)>/$sym{$1}/eg;
+
+ return ($str, $found);
+}
+
+# Convert a string of literals back into symbols. It is an error
+# for there to be literal values that can't be mapped back. The
+# converter uses a gredy algo. It is likely this could be done
+# more efficently with a regex ctrated at runtime. It would also be
+# a good idea to only create %rsym if %sym changes, but that isn't
+# the simplest thing to do in perl5.
+sub resym {
+ my($str) = $_[0];
+ my(%rsym, $k, $v);
+ my $max_len = 0;
+ my $ret = "";
+
+ while(($k, $v) = each(%sym)) {
+ # Collisions in $v are ok, we merely need a mapping, not the
+ # identical mapping
+ $rsym{$v} = $k;
+ $max_len = length($v) if (length($v) > $max_len);
+ }
+
+ SYM: while("" ne $str) {
+ foreach my $l ($max_len .. 1) {
+ next if ($l > length($str));
+ my $s = substr($str, 0, $l);
+ if (defined($rsym{$s})) {
+ $ret .= "<" . $rsym{$s} . ">";
+ substr($str, 0, $l) = "";
+ next SYM;
+ }
+ }
+ &exit(4, "Can't convert $str ($_[0]) back into symbolic form\n");
+ }
+
+ return $ret;
+}
+
+sub set_escape {
+ $escape_char = $_[0];
+ $val_match = qr/"(?:[^"\Q$escape_char\E]+|\Q$escape_char\E")+"|(?:\Q$escape_char\E(?:[0-7]+|d[0-9]+|x[0-9a-fA-F]+))|[^,;<>\s\Q$escape_char\E]|(?:\Q$escape_char\E)[,;<>\Q$escape_char\E]/;
+}
+
+sub set_parser {
+ my $section = $_[0];
+ ($current_LC, $parse_func, $validate_line, $call_parse_on_END)
+ = ($section, $LC_parsers{$section}->[0], $LC_parsers{$section}->[1],
+ $LC_parsers{$section}->[2]);
+ unless (defined $parse_func) {
+ &exit(4, "Unknown section name LC_$section on line $. of $opt{i}\n");
+ }
+}
+
+sub do_copy {
+ my($from) = @_;
+ local($ENV{LC_ALL}) = $from;
+
+ my $C = (new IO::File "/usr/bin/locale -k LC_$current_LC |") || &exit(5, "can't fork locale during copy of LC_$current_LC");
+ while(<$C>) {
+ if (s/=\s*$/ ""/ || s/=/ /) {
+ if (m/$validate_line/ && m/^\s*(\S*)(\s+(\S+.*?))?\s*$/) {
+ my($action, $args) = ($1, $3);
+ &{$parse_func}($action, $args);
+ } else {
+ &exit(4, "Syntax error on line $. of locale -k output"
+ . " during copy $current_LC\n");
+ }
+ } else {
+ &exit(4, "Ill-formed line $. from locale -k during copy $current_LC\n");
+ }
+ }
+ $C->close() || &exit(5, "copying LC_$current_LC from $from failed");
+}
+
+sub fixup_collate_order_args {
+ my $co = $_[0];
+
+ foreach my $s (@{$co}[1..$#{$co}]) {
+ if ("HASH" eq ref($s) && exists($s->{"..."})) {
+ $s = $co->[0];
+ }
+ }
+}
+
+sub add_to_ctype_class {
+ my($class, @runes) = @_;
+
+ my $c = $ctype_classes{$class};
+ foreach my $r (@runes) {
+ $c->{$r} = 2 unless exists $c->{$r};
+ }
+}
+
+sub deny_in_ctype_class {
+ my($class, $deny_reason, @runes) = @_;
+
+ my $c = $ctype_classes{$class};
+ foreach my $r (@runes) {
+ next unless exists $c->{$r};
+ $deny_reason =~ s/^(\S+)$/can't belong in class $class and in class $1 at the same time/;
+ &exit(4, &hexchars($r) . " " . $deny_reason . "\n");
+ }
+}
+
+# write_lc_{money,time,messages} all use the existing Libc format, which
+# is raw text with each record terminated by a newline, and records
+# in a predetermined order.
+
+sub write_lc_money {
+ my $F = (new IO::File "$locale_dir/LC_MONETARY", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_MONETARY: $!");
+ foreach my $s (qw(int_curr_symbol currency_symbol mon_decimal_point mon_thousands_sep mon_grouping positive_sign negative_sign int_frac_digits frac_digits p_cs_precedes p_sep_by_space n_cs_precedes n_sep_by_space p_sign_posn n_sign_posn int_p_cs_precedes int_n_cs_precedes int_p_sep_by_space int_n_sep_by_space int_p_sign_posn int_n_sign_posn)) {
+ if (exists $monetary{$s}) {
+ my $v = $monetary{$s};
+ if ("ARRAY" eq ref $v) {
+ $F->print(join(";", @$v), "\n");
+ } else {
+ $F->print("$v\n");
+ }
+ } else {
+ if ($s =~ m/^(int_curr_symbol|currency_symbol|mon_decimal_point|mon_thousands_sep|positive_sign|negative_sign)$/) {
+ $F->print("\n");
+ } else {
+ $F->print("-1\n");
+ }
+ }
+ }
+}
+
+sub write_lc_time {
+ my $F = (new IO::File "$locale_dir/LC_TIME", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_TIME: $!");
+ my %array_cnt = (abmon => 12, mon => 12, abday => 7, day => 7, alt_month => 12, am_pm => 2);
+
+ $time{"md_order"} = "md" unless defined $time{"md_order"};
+
+ foreach my $s (qw(abmon mon abday day t_fmt d_fmt d_t_fmt am_pm d_t_fmt mon md_order t_fmt_ampm)) {
+ my $cnt = $array_cnt{$s};
+ my $v = $time{$s};
+
+ if (defined $v) {
+ if (defined $cnt) {
+ my @a = @{$v};
+ &exit(4, "$0: $s has " . (0 + @a)
+ . " elements, it needs to have exactly $cnt\n")
+ unless (@a == $cnt);
+ $F->print(join("\n", @a), "\n");
+ } else {
+ $F->print("$v\n");
+ }
+ } else {
+ $cnt = 1 if !defined $cnt;
+ $F->print("\n" x $cnt);
+ }
+ }
+}
+
+sub write_lc_messages {
+ mkdir("$locale_dir/LC_MESSAGES");
+ my $F = (new IO::File "$locale_dir/LC_MESSAGES/LC_MESSAGES", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_MESSAGES/LC_MESSAGES: $!");
+
+ foreach my $s (qw(yesexpr noexpr yesstr nostr)) {
+ my $v = $messages{$s};
+
+ if (defined $v) {
+ $F->print("$v\n");
+ } else {
+ $F->print("\n");
+ }
+ }
+}
+
+sub write_lc_numeric {
+ my $F = (new IO::File "$locale_dir/LC_NUMERIC", O_TRUNC|O_WRONLY|O_CREAT, 0666) || &exit(4, "$0 can't create $locale_dir/LC_NUMERIC: $!");
+
+ foreach my $s (qw(decimal_point thousands_sep grouping)) {
+ if (exists $numeric{$s}) {
+ my $v = $numeric{$s};
+ if ("ARRAY" eq ref $v) {
+ $F->print(join(";", @$v), "\n");
+ } else {
+ $F->print("$v\n");
+ }
+ } else {
+ $F->print("\n");
+ }
+ }
+}
+
+sub bylenval {
+ return 0 if ("ARRAY" ne ref $a || "ARRAY" ne ref $b);
+
+ my($aval, $af) = &unsym_with_check($a->[0]);
+ $aval = $cele{$a->[0]} unless $af;
+ my($bval, $bf) = &unsym_with_check($b->[0]);
+ $bval = $cele{$b->[0]} unless $bf;
+
+ my $r = length($aval) - length($bval);
+ return $r if $r;
+ return $aval cmp $bval;
+}
+
+sub write_lc_collate {
+ return unless @colldef;
+
+ # colldef doesn't parse the whole glory of SuSv3 charmaps, and we
+ # already have, so we cna spit out a simplifyed one; unfortunitly
+ # it doesn't like "/dev/fd/N" so we need a named tmp file
+ my($CMAP, $cmapname) = tempfile(DIR => "/tmp");
+ foreach my $s (keys(%sym)) {
+ $CMAP->print("<$s>\t", sprintf "\\x%02x\n", ord($sym{$s}));
+ }
+ $CMAP->flush();
+ unshift(@colldef, qq{charmap $cmapname});
+ unshift(@colldef, "LC_COLLATE");
+ $colldef[$#colldef] = "END LC_COLLATE";
+
+ # Can't just use /dev/stdin, colldef appears to use seek,
+ # and even seems to need a named temp file (re-open?)
+ my($COL, $colname) = tempfile(DIR => "/tmp");
+ $COL->print(join("\n", @colldef), "\n");
+ $COL->flush();
+
+ my $rc = system(
+ "/usr/bin/colldef -o $locale_dir/LC_COLLATE $colname");
+ unlink $colname, $cmapname;
+ if ($rc) {
+ &exit(1, "Bad return from colldef $rc");
+ }
+}
+
+# Pack an int of unknown size into a series of bytes, each of which
+# contains 7 bits of data, and the top bit is clear on the last
+# byte of data. Also works on arrays -- does not encode the size of
+# the array. This format is great for data that tends to have fewer
+# then 21 bits.
+sub pack_p_int {
+ if (@_ > 1) {
+ my $ret = "";
+ foreach my $v (@_) {
+ $ret .= &pack_p_int($v);
+ }
+
+ return $ret;
+ }
+
+ my $v = $_[0];
+ my $b;
+
+ &exit(4, "pack_p_int only works on positive values") if ($v < 0);
+ if ($v < 128) {
+ $b = chr($v);
+ } else {
+ $b = chr(($v & 0x7f) | 0x80);
+ $b .= pack_p_int($v >> 7);
+ }
+ return $b;
+}
+
+sub strip_angles {
+ my $s = $_[0];
+ $s =~ s/^<(.*)>$/$1/;
+ return $s;
+}
+
+# For localedef
+# xc=0 "no warnings, locale defined"
+# xc=1 "warnings, locale defined"
+# xc=2 "implmentation limits or unsupported charactor sets, no locale defined"
+# xc=3 "can't create new locales"
+# xc=4+ "wornings or errors, no locale defined"
+sub exit {
+ my($xc, $message) = @_;
+
+ print STDERR $message;
+ exit $xc;
+}
diff --git a/adv_cmds/lsvfs/lsvfs.1 b/adv_cmds/lsvfs/lsvfs.1
new file mode 100644
index 0000000..411ea17
--- /dev/null
+++ b/adv_cmds/lsvfs/lsvfs.1
@@ -0,0 +1,67 @@
+.\" Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd January 4, 2003
+.Dt LSVFS 1
+.Os
+.Sh NAME
+.Nm lsvfs
+.Nd list known virtual file systems
+.Sh SYNOPSIS
+.Nm
+.Op Ar vfsname Ar ...
+.Sh DESCRIPTION
+The
+.Nm
+command lists information about the currently loaded virtual filesystem
+modules.
+When
+.Ar vfsname
+arguments are given,
+.Nm
+lists information about the specified VFS modules.
+Otherwise,
+.Nm
+lists all currently loaded modules.
+The information is as follows:
+.Pp
+.Bl -tag -compact -width Filesystem
+.It Filesystem
+the name of the filesystem, as would be used in the
+.Ar type
+parameter to
+.Xr mount 2
+and the
+.Fl t
+option to
+.Xr mount 8
+.It Refs
+the number of references to this VFS; i.e., the number of currently
+mounted filesystems of this type
+.It Flags
+flag bits
+.El
+.Sh SEE ALSO
+.Xr mount 2 ,
+.Xr mount 8
+.Sh HISTORY
+The command from which this tool was derived, as well as this manual,
+originally appeared in
+.Fx 2.0 .
diff --git a/adv_cmds/lsvfs/lsvfs.c b/adv_cmds/lsvfs/lsvfs.c
new file mode 100644
index 0000000..73f4135
--- /dev/null
+++ b/adv_cmds/lsvfs/lsvfs.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 1998-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define FMT "%-32.32s %5d %s\n"
+#define HDRFMT "%-32.32s %5.5s %s\n"
+#define DASHES "-------------------------------- ----- ---------------\n"
+
+static const char *fmt_flags(int flags);
+
+int
+main(int argc, char *argv[])
+{
+ struct vfsconf vfc;
+ int mib[4], max, x;
+ size_t len;
+
+ printf(HDRFMT, "Filesystem", "Refs", "Flags");
+ fputs(DASHES, stdout);
+
+ if (argc > 1) {
+ for (x = 1; x < argc; x++)
+ if (getvfsbyname(argv[x], &vfc) == 0)
+ printf(FMT, vfc.vfc_name, vfc.vfc_refcount,
+ fmt_flags(vfc.vfc_flags));
+ else
+ warnx("VFS %s unknown or not loaded", argv[x]);
+ } else {
+ mib[0] = CTL_VFS;
+ mib[1] = VFS_GENERIC;
+ mib[2] = VFS_MAXTYPENUM;
+ len = sizeof(int);
+ if (sysctl(mib, 3, &max, &len, NULL, 0) != 0)
+ errx(1, "sysctl");
+ mib[2] = VFS_CONF;
+
+ len = sizeof(vfc);
+ for (x = 0; x < max; x++) {
+ mib[3] = x;
+ if (sysctl(mib, 4, &vfc, &len, NULL, 0) != 0) {
+ if (errno != ENOTSUP)
+ errx(1, "sysctl");
+ } else {
+ printf(FMT, vfc.vfc_name, vfc.vfc_refcount,
+ fmt_flags(vfc.vfc_flags));
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const char *
+fmt_flags(int flags)
+{
+ static char buf[sizeof "local, dovolfs"];
+ int comma = 0;
+
+ buf[0] = '\0';
+
+ if(flags & MNT_LOCAL) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "local");
+ }
+
+ if(flags & MNT_DOVOLFS) {
+ if(comma++) strcat(buf, ", ");
+ strcat(buf, "dovolfs");
+ }
+
+ return buf;
+}
diff --git a/adv_cmds/mklocale/extern.h b/adv_cmds/mklocale/extern.h
new file mode 100644
index 0000000..f2037dd
--- /dev/null
+++ b/adv_cmds/mklocale/extern.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/mklocale/extern.h,v 1.1 2002/04/28 12:34:54 markm Exp $
+ */
+
+int yylex(void);
+int yyparse(void);
diff --git a/adv_cmds/mklocale/ldef.h b/adv_cmds/mklocale/ldef.h
new file mode 100644
index 0000000..da9e015
--- /dev/null
+++ b/adv_cmds/mklocale/ldef.h
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ldef.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/mklocale/ldef.h,v 1.5 2007/11/07 14:46:22 rafan Exp $
+ */
+
+#include <sys/types.h>
+#ifdef __APPLE__
+#include <inttypes.h>
+#include <limits.h>
+#endif /* __APPLE__ */
+#include "runefile.h"
+
+/*
+ * This should look a LOT like a _RuneEntry
+ */
+typedef struct rune_list {
+ int32_t min;
+ int32_t max;
+ int32_t map;
+ uint32_t *types;
+ struct rune_list *next;
+} rune_list;
+
+typedef struct rune_map {
+ uint32_t map[_CACHED_RUNES];
+ rune_list *root;
+} rune_map;
+
+#ifdef __APPLE__
+typedef struct {
+ char name[CHARCLASS_NAME_MAX];
+ uint32_t mask;
+} rune_charclass;
+#endif /* __APPLE__ */
diff --git a/adv_cmds/mklocale/lex.l b/adv_cmds/mklocale/lex.l
new file mode 100644
index 0000000..9ffbaca
--- /dev/null
+++ b/adv_cmds/mklocale/lex.l
@@ -0,0 +1,179 @@
+%{
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lex.l 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/mklocale/lex.l,v 1.9 2005/02/26 21:47:54 ru Exp $");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ldef.h"
+#include "y.tab.h"
+#include "extern.h"
+%}
+
+ODIGIT [0-7]
+DIGIT [0-9]
+XDIGIT [0-9a-fA-F]
+W [\t\n\r ]
+
+%%
+\'.\' { yylval.rune = (unsigned char)yytext[1];
+ return(RUNE); }
+
+'\\a' { yylval.rune = '\a';
+ return(RUNE); }
+'\\b' { yylval.rune = '\b';
+ return(RUNE); }
+'\\f' { yylval.rune = '\f';
+ return(RUNE); }
+'\\n' { yylval.rune = '\n';
+ return(RUNE); }
+'\\r' { yylval.rune = '\r';
+ return(RUNE); }
+'\\t' { yylval.rune = '\t';
+ return(RUNE); }
+'\\v' { yylval.rune = '\v';
+ return(RUNE); }
+
+0x{XDIGIT}+ { yylval.rune = strtol(yytext, 0, 16);
+ return(RUNE); }
+0{ODIGIT}+ { yylval.rune = strtol(yytext, 0, 8);
+ return(RUNE); }
+{DIGIT}+ { yylval.rune = strtol(yytext, 0, 10);
+ return(RUNE); }
+
+
+MAPLOWER { return(MAPLOWER); }
+MAPUPPER { return(MAPUPPER); }
+TODIGIT { return(DIGITMAP); }
+INVALID { return(INVALID); }
+
+ALPHA { yylval.i = _CTYPE_A|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+CONTROL { yylval.i = _CTYPE_C;
+ return(LIST); }
+DIGIT { yylval.i = _CTYPE_D|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+GRAPH { yylval.i = _CTYPE_G|_CTYPE_R;
+ return(LIST); }
+LOWER { yylval.i = _CTYPE_L|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+PUNCT { yylval.i = _CTYPE_P|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+SPACE { yylval.i = _CTYPE_S;
+ return(LIST); }
+UPPER { yylval.i = _CTYPE_U|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+XDIGIT { yylval.i = _CTYPE_X|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+BLANK { yylval.i = _CTYPE_B;
+ return(LIST); }
+PRINT { yylval.i = _CTYPE_R;
+ return(LIST); }
+IDEOGRAM { yylval.i = _CTYPE_I|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+SPECIAL { yylval.i = _CTYPE_T|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+PHONOGRAM { yylval.i = _CTYPE_Q|_CTYPE_R|_CTYPE_G;
+ return(LIST); }
+SWIDTH0 { yylval.i = _CTYPE_SW0; return(LIST); }
+SWIDTH1 { yylval.i = _CTYPE_SW1; return(LIST); }
+SWIDTH2 { yylval.i = _CTYPE_SW2; return(LIST); }
+SWIDTH3 { yylval.i = _CTYPE_SW3; return(LIST); }
+
+VARIABLE[\t ] { static char vbuf[1024];
+ char *v = vbuf;
+ while ((*v = input()) && *v != '\n')
+ ++v;
+ if (*v) {
+ unput(*v);
+ *v = 0;
+ }
+ yylval.str = vbuf;
+ return(VARIABLE);
+ }
+
+ENCODING { return(ENCODING); }
+
+CHARCLASS { return(CHARCLASS); }
+
+\".*\" { char *e = yytext + 1;
+ yylval.str = e;
+ while (*e && *e != '"')
+ ++e;
+ *e = 0;
+ return(STRING); }
+
+\<|\(|\[ { return(LBRK); }
+
+\>|\)|\] { return(RBRK); }
+
+\- { return(THRU); }
+\.\.\. { return(THRU); }
+
+\: { return(':'); }
+
+{W}+ ;
+
+^\#.*\n ;
+\/\* { char lc = 0;
+ do {
+ while ((lc) != '*')
+ if ((lc = input()) == 0)
+ break;
+ } while((lc = input()) != '/');
+ }
+
+\\$ ;
+. { printf("Lex is skipping '%s'\n", yytext); }
+%%
+
+#if !defined(yywrap)
+int
+yywrap()
+{
+ return(1);
+}
+#endif
diff --git a/adv_cmds/mklocale/mklocale.1 b/adv_cmds/mklocale/mklocale.1
new file mode 100644
index 0000000..8f2ec0e
--- /dev/null
+++ b/adv_cmds/mklocale/mklocale.1
@@ -0,0 +1,308 @@
+.\" Copyright (c) 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Borman at Krystal Technologies.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mklocale.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/mklocale/mklocale.1,v 1.28 2008/01/22 00:04:50 ache Exp $
+.\"
+.Dd October 17, 2004
+.Dt MKLOCALE 1
+.Os
+.Sh NAME
+.Nm mklocale
+.Nd make LC_CTYPE locale files
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Ar "< src-file"
+.Ar "> language/LC_CTYPE"
+.Nm
+.Op Fl d
+.Fl o
+.Ar language/LC_CTYPE
+.Ar src-file
+.Sh DESCRIPTION
+The
+.Nm
+utility reads a
+.Dv LC_CTYPE
+source file from standard input and produces a
+.Dv LC_CTYPE
+binary file on standard output suitable for placement in
+.Pa /usr/share/locale/ Ns Ar language Ns Pa /LC_CTYPE .
+.Pp
+The format of
+.Ar src-file
+is quite simple.
+It consists of a series of lines which start with a keyword and have
+associated data following.
+C style comments are used
+to place comments in the file.
+.Pp
+Following options are available:
+.Bl -tag -width indent
+.It Fl d
+Turns on debugging messages.
+.It Fl o
+Specify output file.
+.El
+.Pp
+Besides the keywords which will be listed below,
+the following are valid tokens in
+.Ar src-file :
+.Bl -tag -width ".Ar literal"
+.It Dv RUNE
+A
+.Dv RUNE
+may be any of the following:
+.Bl -tag -width ".Ar 0x[0-9a-z]*"
+.It Ar 'x'
+The ASCII character
+.Ar x .
+.It Ar '\ex'
+The ANSI C character
+.Ar \ex
+where
+.Ar \ex
+is one of
+.Dv \ea ,
+.Dv \eb ,
+.Dv \ef ,
+.Dv \en ,
+.Dv \er ,
+.Dv \et ,
+or
+.Dv \ev .
+.It Ar 0x[0-9a-z]*
+A hexadecimal number representing a rune code.
+.It Ar 0[0-7]*
+An octal number representing a rune code.
+.It Ar [1-9][0-9]*
+A decimal number representing a rune code.
+.El
+.It Dv STRING
+A string enclosed in double quotes (").
+.It Dv THRU
+Either
+.Dv ...
+or
+.Dv - .
+Used to indicate ranges.
+.It Ar literal
+The follow characters are taken literally:
+.Bl -tag -width ".Dv <\|\|(\|\|["
+.It Dv "<\|(\|["
+Used to start a mapping.
+All are equivalent.
+.It Dv ">\|\^)\|]"
+Used to end a mapping.
+All are equivalent.
+.It Dv :
+Used as a delimiter in mappings.
+.El
+.El
+.Pp
+Key words which should only appear once are:
+.Bl -tag -width ".Dv PHONOGRAM"
+.It Dv ENCODING
+Followed by a
+.Dv STRING
+which indicates the encoding mechanism to be used for this locale.
+The current encodings are:
+.Bl -tag -width ".Dv MSKanji"
+.It Dv ASCII
+American Standard Code for Information Interchange.
+.It Dv BIG5
+The
+.Dq Big5
+encoding of Chinese.
+.It Dv EUC
+.Dv EUC
+encoding as used by several
+vendors of
+.Ux
+systems.
+.It Dv GB18030
+PRC national standard for encoding of Chinese text.
+.It Dv GB2312
+Older PRC national standard for encoding Chinese text.
+.It Dv GBK
+A widely used encoding method for Chinese text,
+backwards compatible with GB\ 2312-1980.
+.It Dv MSKanji
+The method of encoding Japanese used by Microsoft,
+loosely based on JIS.
+Also known as
+.Dq "Shift JIS"
+and
+.Dq SJIS .
+.It Dv NONE
+No translation and the default.
+.It Dv UTF-8
+The
+.Dv UTF-8
+transformation format of
+.Tn ISO
+10646
+as defined by RFC 2279.
+.El
+.It Dv VARIABLE
+This keyword must be followed by a single tab or space character,
+after which encoding specific data is placed.
+Currently only the
+.Dv "EUC"
+encoding requires variable data.
+See
+.Xr euc 5
+for further details.
+.It Dv INVALID
+(obsolete)
+A single
+.Dv RUNE
+follows and is used as the invalid rune for this locale.
+.El
+.Pp
+The following keywords may appear multiple times and have the following
+format for data:
+.Bl -tag -width ".Dv <RUNE1 THRU RUNEn : RUNE2>" -offset indent
+.It Dv <RUNE1 RUNE2>
+.Dv RUNE1
+is mapped to
+.Dv RUNE2 .
+.It Dv <RUNE1 THRU RUNEn : RUNE2>
+Runes
+.Dv RUNE1
+through
+.Dv RUNEn
+are mapped to
+.Dv RUNE2
+through
+.Dv RUNE2
++ n-1.
+.El
+.Bl -tag -width ".Dv PHONOGRAM"
+.It Dv MAPLOWER
+Defines the tolower mappings.
+.Dv RUNE2
+is the lower case representation of
+.Dv RUNE1 .
+.It Dv MAPUPPER
+Defines the toupper mappings.
+.Dv RUNE2
+is the upper case representation of
+.Dv RUNE1 .
+.It Dv TODIGIT
+Defines a map from runes to their digit value.
+.Dv RUNE2
+is the integer value represented by
+.Dv RUNE1 .
+For example, the ASCII character
+.Ql 0
+would map to the decimal value 0.
+Only values up to 255
+are allowed.
+.El
+.Pp
+The following keywords may appear multiple times and have the following
+format for data:
+.Bl -tag -width ".Dv RUNE1 THRU RUNEn" -offset indent
+.It Dv RUNE
+This rune has the property defined by the keyword.
+.It Dv "RUNE1 THRU RUNEn"
+All the runes between and including
+.Dv RUNE1
+and
+.Dv RUNEn
+have the property defined by the keyword.
+.El
+.Bl -tag -width ".Dv PHONOGRAM"
+.It Dv ALPHA
+Defines runes which are alphabetic, printable and graphic.
+.It Dv CONTROL
+Defines runes which are control characters.
+.It Dv DIGIT
+Defines runes which are decimal digits, printable and graphic.
+.It Dv GRAPH
+Defines runes which are graphic and printable.
+.It Dv LOWER
+Defines runes which are lower case, printable and graphic.
+.It Dv PUNCT
+Defines runes which are punctuation, printable and graphic.
+.It Dv SPACE
+Defines runes which are spaces.
+.It Dv UPPER
+Defines runes which are upper case, printable and graphic.
+.It Dv XDIGIT
+Defines runes which are hexadecimal digits, printable and graphic.
+.It Dv BLANK
+Defines runes which are blank.
+.It Dv PRINT
+Defines runes which are printable.
+.It Dv IDEOGRAM
+Defines runes which are ideograms, printable and graphic.
+.It Dv SPECIAL
+Defines runes which are special characters, printable and graphic.
+.It Dv PHONOGRAM
+Defines runes which are phonograms, printable and graphic.
+.It Dv SWIDTH0
+Defines runes with display width 0.
+.It Dv SWIDTH1
+Defines runes with display width 1.
+.It Dv SWIDTH2
+Defines runes with display width 2.
+.It Dv SWIDTH3
+Defines runes with display width 3.
+.El
+.Pp
+If no display width explicitly defined, width 1 assumed
+for printable runes by default.
+.Sh SEE ALSO
+.Xr colldef 1 ,
+.Xr setlocale 3 ,
+.Xr wcwidth 3 ,
+.Xr big5 5 ,
+.Xr euc 5 ,
+.Xr gb18030 5 ,
+.Xr gb2312 5 ,
+.Xr gbk 5 ,
+.Xr mskanji 5 ,
+.Xr utf8 5
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Nm
+utility is overly simplistic.
diff --git a/adv_cmds/mklocale/runefile.h b/adv_cmds/mklocale/runefile.h
new file mode 100644
index 0000000..6b3f9f7
--- /dev/null
+++ b/adv_cmds/mklocale/runefile.h
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2005 Ruslan Ermilov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc/locale/runefile.h,v 1.1 2005/05/16 09:32:41 ru Exp $
+ */
+
+#ifndef _RUNEFILE_H_
+#define _RUNEFILE_H_
+
+#include <sys/types.h>
+
+#ifndef _CACHED_RUNES
+#define _CACHED_RUNES (1 << 8)
+#endif
+
+typedef struct {
+ int32_t min;
+ int32_t max;
+ int32_t map;
+#ifdef __APPLE__
+ int32_t __types_fake;
+#endif /* __APPLE__ */
+} _FileRuneEntry;
+
+typedef struct {
+ char magic[8];
+ char encoding[32];
+
+#ifdef __APPLE__
+ int32_t __sgetrune_fake;
+ int32_t __sputrune_fake;
+ int32_t __invalid_rune;
+#endif /* __APPLE__ */
+
+ uint32_t runetype[_CACHED_RUNES];
+ int32_t maplower[_CACHED_RUNES];
+ int32_t mapupper[_CACHED_RUNES];
+
+ int32_t runetype_ext_nranges;
+#ifdef __APPLE__
+ int32_t __runetype_ext_ranges_fake;
+#endif /* __APPLE__ */
+ int32_t maplower_ext_nranges;
+#ifdef __APPLE__
+ int32_t __maplower_ext_ranges_fake;
+#endif /* __APPLE__ */
+ int32_t mapupper_ext_nranges;
+#ifdef __APPLE__
+ int32_t __mapupper_ext_ranges_fake;
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+ int32_t __variable_fake;
+#endif /* __APPLE__ */
+ int32_t variable_len;
+
+#ifdef __APPLE__
+ int32_t ncharclasses;
+ int32_t __charclasses_fake;
+#endif /* __APPLE__ */
+} _FileRuneLocale;
+
+#define _FILE_RUNE_MAGIC_1 "RuneMag1"
+
+#endif /* !_RUNEFILE_H_ */
diff --git a/adv_cmds/mklocale/yacc.y b/adv_cmds/mklocale/yacc.y
new file mode 100644
index 0000000..f76498d
--- /dev/null
+++ b/adv_cmds/mklocale/yacc.y
@@ -0,0 +1,929 @@
+%{
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Borman at Krystal Technologies.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)yacc.y 8.1 (Berkeley) 6/6/93";
+#endif /* 0 */
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/mklocale/yacc.y,v 1.28 2008/01/22 00:04:50 ache Exp $");
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ldef.h"
+#include "extern.h"
+#include "runefile.h"
+
+#define MAX_CHARCLASS 4
+#define CHARCLASSBIT 4
+
+static void *xmalloc(unsigned int sz);
+static uint32_t *xlalloc(unsigned int sz);
+void yyerror(const char *s);
+static uint32_t *xrelalloc(uint32_t *old, unsigned int sz);
+static void dump_tables(void);
+static void cleanout(void);
+
+const char *locale_file = "<stdout>";
+
+rune_map maplower = { { 0 }, NULL };
+rune_map mapupper = { { 0 }, NULL };
+rune_map types = { { 0 }, NULL };
+
+_FileRuneLocale new_locale = { "", "", 0, 0, 0, {}, {}, {}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+char *variable = NULL;
+
+rune_charclass charclasses[MAX_CHARCLASS];
+int charclass_index = 0;
+
+void set_map(rune_map *, rune_list *, uint32_t);
+void set_digitmap(rune_map *, rune_list *);
+void add_map(rune_map *, rune_list *, uint32_t);
+static void usage(void);
+%}
+
+%union {
+ int32_t rune;
+ int i;
+ char *str;
+
+ rune_list *list;
+}
+
+%token <rune> RUNE
+%token LBRK
+%token RBRK
+%token THRU
+%token MAPLOWER
+%token MAPUPPER
+%token DIGITMAP
+%token CHARCLASS
+%token <i> LIST
+%token <str> VARIABLE
+%token ENCODING
+%token INVALID
+%token <str> STRING
+
+%type <list> list
+%type <list> map
+
+
+%%
+
+locale : /* empty */
+ | table
+ { dump_tables(); }
+ ;
+
+table : entry
+ | table entry
+ ;
+
+entry : ENCODING STRING
+ { if (strcmp($2, "NONE") &&
+ strcmp($2, "ASCII") &&
+ strcmp($2, "UTF-8") &&
+ strcmp($2, "EUC") &&
+ strcmp($2, "GBK") &&
+ strcmp($2, "GB18030") &&
+ strcmp($2, "GB2312") &&
+ strcmp($2, "BIG5") &&
+ strcmp($2, "MSKanji") &&
+ strcmp($2, "UTF2"))
+ warnx("ENCODING %s is not supported by libc", $2);
+ strncpy(new_locale.encoding, $2,
+ sizeof(new_locale.encoding)); }
+ | VARIABLE
+ { new_locale.variable_len = strlen($1) + 1;
+ variable = xmalloc(new_locale.variable_len);
+ strcpy(variable, $1);
+ }
+ | INVALID RUNE
+ { warnx("the INVALID keyword is deprecated"); }
+ | LIST list
+ { set_map(&types, $2, $1); }
+ | MAPLOWER map
+ { set_map(&maplower, $2, 0); }
+ | MAPUPPER map
+ { set_map(&mapupper, $2, 0); }
+ | DIGITMAP map
+ {
+ if (($2->map >= 0) && ($2->map <= 255)) { /* Data corruption otherwise */
+ set_digitmap(&types, $2);
+ }
+ }
+ | CHARCLASS STRING list
+ {
+ int i;
+ if (strlen($2) > CHARCLASS_NAME_MAX)
+ errx(1, "Exceeded maximum charclass name size (%d) \"%s\"", CHARCLASS_NAME_MAX, $2);
+ for(i = 0; i < charclass_index; i++)
+ if (strncmp(charclasses[i].name, $2, CHARCLASS_NAME_MAX) == 0)
+ break;
+ if (i >= charclass_index) {
+ if (charclass_index >= MAX_CHARCLASS)
+ errx(1, "Exceeded maximum number of charclasses (%d)", MAX_CHARCLASS);
+ strncpy(charclasses[charclass_index].name, $2, CHARCLASS_NAME_MAX);
+ charclasses[charclass_index].mask = (1 << (charclass_index + CHARCLASSBIT));
+ charclass_index++;
+ }
+ set_map(&types, $3, charclasses[i].mask);
+ }
+ ;
+
+list : RUNE
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $1;
+ $$->max = $1;
+ $$->next = 0;
+ }
+ | RUNE THRU RUNE
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $1;
+ $$->max = $3;
+ $$->next = 0;
+ }
+ | list RUNE
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $2;
+ $$->next = $1;
+ }
+ | list RUNE THRU RUNE
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $4;
+ $$->next = $1;
+ }
+ ;
+
+map : LBRK RUNE RUNE RBRK
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $2;
+ $$->map = $3;
+ $$->next = 0;
+ }
+ | map LBRK RUNE RUNE RBRK
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $3;
+ $$->max = $3;
+ $$->map = $4;
+ $$->next = $1;
+ }
+ | LBRK RUNE THRU RUNE ':' RUNE RBRK
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $2;
+ $$->max = $4;
+ $$->map = $6;
+ $$->next = 0;
+ }
+ | map LBRK RUNE THRU RUNE ':' RUNE RBRK
+ {
+ $$ = (rune_list *)xmalloc(sizeof(rune_list));
+ $$->min = $3;
+ $$->max = $5;
+ $$->map = $7;
+ $$->next = $1;
+ }
+ ;
+%%
+
+int debug;
+FILE *fp;
+
+static void
+cleanout(void)
+{
+ if (fp != NULL)
+ unlink(locale_file);
+}
+
+int
+main(int ac, char *av[])
+{
+ int x;
+
+ fp = stdout;
+
+ while ((x = getopt(ac, av, "do:")) != -1) {
+ switch(x) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'o':
+ locale_file = optarg;
+ if ((fp = fopen(locale_file, "w")) == NULL)
+ err(1, "%s: fopen", locale_file);
+ atexit(cleanout);
+ break;
+ default:
+ usage();
+ }
+ }
+
+ switch (ac - optind) {
+ case 0:
+ break;
+ case 1:
+ if (freopen(av[optind], "r", stdin) == 0)
+ err(1, "%s: freopen", av[optind]);
+ break;
+ default:
+ usage();
+ }
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ mapupper.map[x] = x;
+ maplower.map[x] = x;
+ }
+ memcpy(new_locale.magic, _RUNE_MAGIC_A, sizeof(new_locale.magic));
+
+ yyparse();
+
+ return(0);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: mklocale [-d] [-o output] [source]\n");
+ exit(1);
+}
+
+void
+yyerror(s)
+ const char *s;
+{
+ fprintf(stderr, "%s\n", s);
+}
+
+static void *
+xmalloc(sz)
+ unsigned int sz;
+{
+ void *r = malloc(sz);
+ if (!r)
+ errx(1, "xmalloc");
+ return(r);
+}
+
+static uint32_t *
+xlalloc(sz)
+ unsigned int sz;
+{
+ uint32_t *r = (uint32_t *)malloc(sz * sizeof(uint32_t));
+ if (!r)
+ errx(1, "xlalloc");
+ return(r);
+}
+
+static uint32_t *
+xrelalloc(old, sz)
+ uint32_t *old;
+ unsigned int sz;
+{
+ uint32_t *r = (uint32_t *)realloc((char *)old,
+ sz * sizeof(uint32_t));
+ if (!r)
+ errx(1, "xrelalloc");
+ return(r);
+}
+
+void
+set_map(map, list, flag)
+ rune_map *map;
+ rune_list *list;
+ uint32_t flag;
+{
+ while (list) {
+ rune_list *nlist = list->next;
+ add_map(map, list, flag);
+ list = nlist;
+ }
+}
+
+void
+set_digitmap(map, list)
+ rune_map *map;
+ rune_list *list;
+{
+ int32_t i;
+
+ while (list) {
+ rune_list *nlist = list->next;
+ for (i = list->min; i <= list->max; ++i) {
+ if (list->map + (i - list->min)) {
+ rune_list *tmp = (rune_list *)xmalloc(sizeof(rune_list));
+ tmp->min = i;
+ tmp->max = i;
+ add_map(map, tmp, list->map + (i - list->min));
+ }
+ }
+ free(list);
+ list = nlist;
+ }
+}
+
+void
+add_map(map, list, flag)
+ rune_map *map;
+ rune_list *list;
+ uint32_t flag;
+{
+ int32_t i;
+ rune_list *lr = 0;
+ rune_list *r;
+ int32_t run;
+
+ while (list->min < _CACHED_RUNES && list->min <= list->max) {
+ if (flag)
+ map->map[list->min++] |= flag;
+ else
+ map->map[list->min++] = list->map++;
+ }
+
+ if (list->min > list->max) {
+ free(list);
+ return;
+ }
+
+ run = list->max - list->min + 1;
+
+ if (!(r = map->root) || (list->max < r->min - 1)
+ || (!flag && list->max == r->min - 1)) {
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = map->root;
+ map->root = list;
+ return;
+ }
+
+ for (r = map->root; r && r->max + 1 < list->min; r = r->next)
+ lr = r;
+
+ if (!r) {
+ /*
+ * We are off the end.
+ */
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = 0;
+ lr->next = list;
+ return;
+ }
+
+ if (list->max < r->min - 1) {
+ /*
+ * We come before this range and we do not intersect it.
+ * We are not before the root node, it was checked before the loop
+ */
+ if (flag) {
+ list->types = xlalloc(run);
+ for (i = 0; i < run; ++i)
+ list->types[i] = flag;
+ }
+ list->next = lr->next;
+ lr->next = list;
+ return;
+ }
+
+ /*
+ * At this point we have found that we at least intersect with
+ * the range pointed to by `r', we might intersect with one or
+ * more ranges beyond `r' as well.
+ */
+
+ if (!flag && list->map - list->min != r->map - r->min) {
+ /*
+ * There are only two cases when we are doing case maps and
+ * our maps needn't have the same offset. When we are adjoining
+ * but not intersecting.
+ */
+ if (list->max + 1 == r->min) {
+ lr->next = list;
+ list->next = r;
+ return;
+ }
+ if (list->min - 1 == r->max) {
+ list->next = r->next;
+ r->next = list;
+ return;
+ }
+ errx(1, "error: conflicting map entries");
+ }
+
+ if (list->min >= r->min && list->max <= r->max) {
+ /*
+ * Subset case.
+ */
+
+ if (flag) {
+ for (i = list->min; i <= list->max; ++i)
+ r->types[i - r->min] |= flag;
+ }
+ free(list);
+ return;
+ }
+ if (list->min <= r->min && list->max >= r->max) {
+ /*
+ * Superset case. Make him big enough to hold us.
+ * We might need to merge with the guy after him.
+ */
+ if (flag) {
+ list->types = xlalloc(list->max - list->min + 1);
+
+ for (i = list->min; i <= list->max; ++i)
+ list->types[i - list->min] = flag;
+
+ for (i = r->min; i <= r->max; ++i)
+ list->types[i - list->min] |= r->types[i - r->min];
+
+ free(r->types);
+ r->types = list->types;
+ } else {
+ r->map = list->map;
+ }
+ r->min = list->min;
+ r->max = list->max;
+ free(list);
+ } else if (list->min < r->min) {
+ /*
+ * Our tail intersects his head.
+ */
+ if (flag) {
+ list->types = xlalloc(r->max - list->min + 1);
+
+ for (i = r->min; i <= r->max; ++i)
+ list->types[i - list->min] = r->types[i - r->min];
+
+ for (i = list->min; i < r->min; ++i)
+ list->types[i - list->min] = flag;
+
+ for (i = r->min; i <= list->max; ++i)
+ list->types[i - list->min] |= flag;
+
+ free(r->types);
+ r->types = list->types;
+ } else {
+ r->map = list->map;
+ }
+ r->min = list->min;
+ free(list);
+ return;
+ } else {
+ /*
+ * Our head intersects his tail.
+ * We might need to merge with the guy after him.
+ */
+ if (flag) {
+ r->types = xrelalloc(r->types, list->max - r->min + 1);
+
+ for (i = list->min; i <= r->max; ++i)
+ r->types[i - r->min] |= flag;
+
+ for (i = r->max+1; i <= list->max; ++i)
+ r->types[i - r->min] = flag;
+ }
+ r->max = list->max;
+ free(list);
+ }
+
+ /*
+ * Okay, check to see if we grew into the next guy(s)
+ */
+ while ((lr = r->next) && r->max >= lr->min) {
+ if (flag) {
+ if (r->max >= lr->max) {
+ /*
+ * Good, we consumed all of him.
+ */
+ for (i = lr->min; i <= lr->max; ++i)
+ r->types[i - r->min] |= lr->types[i - lr->min];
+ } else {
+ /*
+ * "append" him on to the end of us.
+ */
+ r->types = xrelalloc(r->types, lr->max - r->min + 1);
+
+ for (i = lr->min; i <= r->max; ++i)
+ r->types[i - r->min] |= lr->types[i - lr->min];
+
+ for (i = r->max+1; i <= lr->max; ++i)
+ r->types[i - r->min] = lr->types[i - lr->min];
+
+ r->max = lr->max;
+ }
+ } else {
+ if (lr->max > r->max)
+ r->max = lr->max;
+ }
+
+ r->next = lr->next;
+
+ if (flag)
+ free(lr->types);
+ free(lr);
+ }
+}
+
+static void
+dump_tables()
+{
+ int x, first_d, curr_d;
+ rune_list *list;
+
+ /*
+ * See if we can compress some of the istype arrays
+ */
+ for(list = types.root; list; list = list->next) {
+ list->map = list->types[0];
+ for (x = 1; x < list->max - list->min + 1; ++x) {
+ if ((int32_t)list->types[x] != list->map) {
+ list->map = 0;
+ break;
+ }
+ }
+ }
+
+ first_d = curr_d = -1;
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ uint32_t r = types.map[x];
+
+ if (r & _CTYPE_D) {
+ if (first_d < 0)
+ first_d = curr_d = x;
+ else if (x != curr_d + 1)
+ errx(1, "error: DIGIT range is not contiguous");
+ else if (x - first_d > 9)
+ errx(1, "error: DIGIT range is too big");
+ else
+ curr_d++;
+ if (!(r & _CTYPE_X))
+ errx(1,
+ "error: DIGIT range is not a subset of XDIGIT range");
+ }
+ }
+ if (first_d < 0)
+ errx(1, "error: no DIGIT range defined in the single byte area");
+ else if (curr_d - first_d < 9)
+ errx(1, "error: DIGIT range is too small in the single byte area");
+
+ new_locale.ncharclasses = htonl(charclass_index);
+
+ /*
+ * Fill in our tables. Do this in network order so that
+ * diverse machines have a chance of sharing data.
+ * (Machines like Crays cannot share with little machines due to
+ * word size. Sigh. We tried.)
+ */
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ new_locale.runetype[x] = htonl(types.map[x]);
+ new_locale.maplower[x] = htonl(maplower.map[x]);
+ new_locale.mapupper[x] = htonl(mapupper.map[x]);
+ }
+
+ /*
+ * Count up how many ranges we will need for each of the extents.
+ */
+ list = types.root;
+
+ while (list) {
+ new_locale.runetype_ext_nranges++;
+ list = list->next;
+ }
+ new_locale.runetype_ext_nranges =
+ htonl(new_locale.runetype_ext_nranges);
+
+ list = maplower.root;
+
+ while (list) {
+ new_locale.maplower_ext_nranges++;
+ list = list->next;
+ }
+ new_locale.maplower_ext_nranges =
+ htonl(new_locale.maplower_ext_nranges);
+
+ list = mapupper.root;
+
+ while (list) {
+ new_locale.mapupper_ext_nranges++;
+ list = list->next;
+ }
+ new_locale.mapupper_ext_nranges =
+ htonl(new_locale.mapupper_ext_nranges);
+
+ new_locale.variable_len = htonl(new_locale.variable_len);
+
+ /*
+ * Okay, we are now ready to write the new locale file.
+ */
+
+ /*
+ * PART 1: The _FileRuneLocale structure
+ */
+ if (fwrite((char *)&new_locale, sizeof(new_locale), 1, fp) != 1) {
+ err(1, "%s: _FileRuneLocale structure", locale_file);
+ }
+ /*
+ * PART 2: The runetype_ext structures (not the actual tables)
+ */
+ list = types.root;
+
+ while (list) {
+ _FileRuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+#ifdef __APPLE__
+ re.__types_fake = 0;
+#endif
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ err(1, "%s: runetype_ext structures", locale_file);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 3: The maplower_ext structures
+ */
+ list = maplower.root;
+
+ while (list) {
+ _FileRuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+#ifdef __APPLE__
+ re.__types_fake = 0;
+#endif
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ err(1, "%s: maplower_ext structures", locale_file);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 4: The mapupper_ext structures
+ */
+ list = mapupper.root;
+
+ while (list) {
+ _FileRuneEntry re;
+
+ re.min = htonl(list->min);
+ re.max = htonl(list->max);
+ re.map = htonl(list->map);
+#ifdef __APPLE__
+ re.__types_fake = 0;
+#endif
+
+ if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
+ err(1, "%s: mapupper_ext structures", locale_file);
+ }
+
+ list = list->next;
+ }
+ /*
+ * PART 5: The runetype_ext tables
+ */
+ list = types.root;
+
+ while (list) {
+ for (x = 0; x < list->max - list->min + 1; ++x)
+ list->types[x] = htonl(list->types[x]);
+
+ if (!list->map) {
+ if (fwrite((char *)list->types,
+ (list->max - list->min + 1) * sizeof(uint32_t),
+ 1, fp) != 1) {
+ err(1, "%s: runetype_ext tables", locale_file);
+ }
+ }
+ list = list->next;
+ }
+ /*
+ * PART 6: The charclass names table
+ */
+ for (x = 0; x < charclass_index; ++x) {
+ charclasses[x].mask = ntohl(charclasses[x].mask);
+ if (fwrite((char *)&charclasses[x], sizeof(rune_charclass), 1, fp) != 1) {
+ err(1, "%s: charclass names tables", locale_file);
+ }
+ }
+ /*
+ * PART 7: And finally the variable data
+ * SUSv3 says fwrite returns zero when either size or nitems is zero.
+ */
+ if (ntohl(new_locale.variable_len) > 0 && fwrite(variable,
+ ntohl(new_locale.variable_len), 1, fp) != 1) {
+ err(1, "%s: variable data", locale_file);
+ }
+ if (fclose(fp) != 0) {
+ err(1, "%s: fclose", locale_file);
+ }
+ fp = NULL;
+
+ if (!debug)
+ return;
+
+ if (new_locale.encoding[0])
+ fprintf(stderr, "ENCODING %s\n", new_locale.encoding);
+ if (variable)
+ fprintf(stderr, "VARIABLE %s\n", variable);
+
+ fprintf(stderr, "\nMAPLOWER:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ if (isprint(maplower.map[x]))
+ fprintf(stderr, " '%c'", (int)maplower.map[x]);
+ else if (maplower.map[x])
+ fprintf(stderr, "%04x", maplower.map[x]);
+ else
+ fprintf(stderr, "%4x", 0);
+ if ((x & 0xf) == 0xf)
+ fprintf(stderr, "\n");
+ else
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "\n");
+
+ for (list = maplower.root; list; list = list->next)
+ fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
+
+ fprintf(stderr, "\nMAPUPPER:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ if (isprint(mapupper.map[x]))
+ fprintf(stderr, " '%c'", (int)mapupper.map[x]);
+ else if (mapupper.map[x])
+ fprintf(stderr, "%04x", mapupper.map[x]);
+ else
+ fprintf(stderr, "%4x", 0);
+ if ((x & 0xf) == 0xf)
+ fprintf(stderr, "\n");
+ else
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "\n");
+
+ for (list = mapupper.root; list; list = list->next)
+ fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
+
+
+ fprintf(stderr, "\nTYPES:\n\n");
+
+ for (x = 0; x < _CACHED_RUNES; ++x) {
+ uint32_t r = types.map[x];
+
+ if (r) {
+ if (isprint(x))
+ fprintf(stderr, " '%c': %2d", x, (int)(r & 0xff));
+ else
+ fprintf(stderr, "%04x: %2d", x, (int)(r & 0xff));
+
+ fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ }
+ }
+
+ for (list = types.root; list; list = list->next) {
+ if (list->map && list->min + 3 < list->max) {
+ uint32_t r = list->map;
+
+ fprintf(stderr, "%04x: %2d",
+ (uint32_t)list->min, (int)(r & 0xff));
+
+ fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
+ fprintf(stderr, "\n...\n");
+
+ fprintf(stderr, "%04x: %2d",
+ (uint32_t)list->max, (int)(r & 0xff));
+
+ fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ } else
+ for (x = list->min; x <= list->max; ++x) {
+ uint32_t r = ntohl(list->types[x - list->min]);
+
+ if (r) {
+ fprintf(stderr, "%04x: %2d", x, (int)(r & 0xff));
+
+ fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
+ fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
+ fprintf(stderr, "\n");
+ }
+ }
+ }
+}
diff --git a/adv_cmds/pkill/entitlements.plist b/adv_cmds/pkill/entitlements.plist
new file mode 100644
index 0000000..b0a6726
--- /dev/null
+++ b/adv_cmds/pkill/entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.sysmond.client</key>
+ <true/>
+</dict>
+</plist>
diff --git a/adv_cmds/pkill/pkill.1 b/adv_cmds/pkill/pkill.1
new file mode 100644
index 0000000..672b185
--- /dev/null
+++ b/adv_cmds/pkill/pkill.1
@@ -0,0 +1,232 @@
+.\" $NetBSD: pkill.1,v 1.8 2003/02/14 15:59:18 grant Exp $
+.\"
+.\" $FreeBSD: src/bin/pkill/pkill.1,v 1.8 2010/07/12 01:58:46 brian Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Andrew Doran.
+.\"
+.\" 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.
+.\"
+.Dd February 11, 2010
+.Dt PKILL 1
+.Os
+.Sh NAME
+.Nm pgrep , pkill
+.Nd find or signal processes by name
+.Sh SYNOPSIS
+.Nm pgrep
+.Op Fl Lafilnoqvx
+.Op Fl F Ar pidfile
+.Op Fl G Ar gid
+.Op Fl P Ar ppid
+.Op Fl U Ar uid
+.Op Fl d Ar delim
+.Op Fl g Ar pgrp
+.Op Fl t Ar tty
+.Op Fl u Ar euid
+.Ar pattern ...
+.Nm pkill
+.Op Fl Ar signal
+.Op Fl ILafilnovx
+.Op Fl F Ar pidfile
+.Op Fl G Ar gid
+.Op Fl P Ar ppid
+.Op Fl U Ar uid
+.Op Fl g Ar pgrp
+.Op Fl t Ar tty
+.Op Fl u Ar euid
+.Ar pattern ...
+.Sh DESCRIPTION
+The
+.Nm pgrep
+command searches the process table on the running system and prints the
+process IDs of all processes that match the criteria given on the command
+line.
+.Pp
+The
+.Nm pkill
+command searches the process table on the running system and signals all
+processes that match the criteria given on the command line.
+.Pp
+The following options are available:
+.Bl -tag -width ".Fl F Ar pidfile"
+.It Fl F Ar pidfile
+Restrict matches to a process whose PID is stored in the
+.Ar pidfile
+file.
+.It Fl G Ar gid
+Restrict matches to processes with a real group ID in the comma-separated
+list
+.Ar gid .
+.It Fl I
+Request confirmation before attempting to signal each process.
+.It Fl L
+The
+.Ar pidfile
+file given for the
+.Fl F
+option must be locked with the
+.Xr flock 2
+syscall or created with
+.Xr pidfile 3 .
+.It Fl P Ar ppid
+Restrict matches to processes with a parent process ID in the
+comma-separated list
+.Ar ppid .
+.It Fl U Ar uid
+Restrict matches to processes with a real user ID in the comma-separated
+list
+.Ar uid .
+.It Fl d Ar delim
+Specify a delimiter to be printed between each process ID.
+The default is a newline.
+This option can only be used with the
+.Nm pgrep
+command.
+.It Fl a
+Include process ancestors in the match list.
+By default, the current
+.Nm pgrep
+or
+.Nm pkill
+process and all of its ancestors are excluded (unless
+.Fl v
+is used).
+.It Fl f
+Match against full argument lists.
+The default is to match against process names.
+.It Fl g Ar pgrp
+Restrict matches to processes with a process group ID in the comma-separated
+list
+.Ar pgrp .
+The value zero is taken to mean the process group ID of the running
+.Nm pgrep
+or
+.Nm pkill
+command.
+.It Fl i
+Ignore case distinctions in both the process table and the supplied pattern.
+.It Fl l
+Long output.
+For
+.Nm pgrep ,
+print the process name in addition to the process ID for each matching
+process.
+If used in conjunction with
+.Fl f ,
+print the process ID and the full argument list for each matching process.
+For
+.Nm pkill ,
+display the kill command used for each process killed.
+.It Fl n
+Select only the newest (most recently started) of the matching processes.
+.It Fl o
+Select only the oldest (least recently started) of the matching processes.
+.It Fl q
+Do not write anything to standard output.
+.It Fl t Ar tty
+Restrict matches to processes associated with a terminal in the
+comma-separated list
+.Ar tty .
+Terminal names may be of the form
+.Pa tty Ns Ar xx
+or the shortened form
+.Ar xx .
+A single dash
+.Pq Ql -
+matches processes not associated with a terminal.
+.It Fl u Ar euid
+Restrict matches to processes with an effective user ID in the
+comma-separated list
+.Ar euid .
+.It Fl v
+Reverse the sense of the matching; display processes that do not match the
+given criteria.
+.It Fl x
+Require an exact match of the process name, or argument list if
+.Fl f
+is given.
+The default is to match any substring.
+.It Fl Ns Ar signal
+A non-negative decimal number or symbolic signal name specifying the signal
+to be sent instead of the default
+.Dv TERM .
+This option is valid only when given as the first argument to
+.Nm pkill .
+.El
+.Pp
+If any
+.Ar pattern
+operands are specified, they are used as regular expressions to match
+the command name or full argument list of each process.
+.Pp
+Note that a running
+.Nm pgrep
+or
+.Nm pkill
+process will never consider itself as
+a potential match.
+.Sh EXIT STATUS
+The
+.Nm pgrep
+and
+.Nm pkill
+utilities
+return one of the following values upon exit:
+.Bl -tag -width indent
+.It 0
+One or more processes were matched.
+.It 1
+No processes were matched.
+.It 2
+Invalid options were specified on the command line.
+.It 3
+An internal error occurred.
+.El
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr killall 1 ,
+.Xr ps 1 ,
+.Xr flock 2 ,
+.Xr kill 2 ,
+.Xr sigaction 2 ,
+.Xr pidfile 3 ,
+.Xr re_format 7
+.\" Xr signal 7
+.Sh HISTORY
+The
+.Nm pkill
+and
+.Nm pgrep
+utilities
+first appeared in
+.Nx 1.6 .
+They are modelled after utilities of the same name that appeared in Sun
+Solaris 7.
+They made their first appearance in
+.Fx 5.3 .
+.Sh AUTHORS
+.An Andrew Doran
+.Aq ad@NetBSD.org
diff --git a/adv_cmds/pkill/pkill.c b/adv_cmds/pkill/pkill.c
new file mode 100644
index 0000000..668d656
--- /dev/null
+++ b/adv_cmds/pkill/pkill.c
@@ -0,0 +1,1111 @@
+/* $NetBSD: pkill.c,v 1.16 2005/10/10 22:13:20 kleink Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/pkill/pkill.c,v 1.12 2011/02/04 16:40:50 jilles Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/user.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <paths.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <regex.h>
+#include <ctype.h>
+#include <fcntl.h>
+#ifndef __APPLE__
+#include <kvm.h>
+#endif
+#include <err.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <locale.h>
+
+#ifdef __APPLE__
+#include <xpc/xpc.h>
+#include <sys/proc_info.h>
+#include <os/assumes.h>
+#include <sysmon.h>
+#endif
+
+#define STATUS_MATCH 0
+#define STATUS_NOMATCH 1
+#define STATUS_BADUSAGE 2
+#define STATUS_ERROR 3
+
+#define MIN_PID 5
+#define MAX_PID 99999
+
+#ifdef __APPLE__
+/* Ignore system processes and myself. */
+#define PSKIP(kp) ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == mypid || \
+ ((xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_SYSTEM) != 0))
+#else
+/* Ignore system-processes (if '-S' flag is not specified) and myself. */
+#define PSKIP(kp) ((kp)->ki_pid == mypid || \
+ (!kthreads && ((kp)->ki_flag & P_KTHREAD) != 0))
+#endif
+
+enum listtype {
+ LT_GENERIC,
+ LT_USER,
+ LT_GROUP,
+ LT_TTY,
+ LT_PGRP,
+#ifndef __APPLE__
+ LT_JID,
+#endif
+ LT_SID
+};
+
+struct list {
+ SLIST_ENTRY(list) li_chain;
+ long li_number;
+};
+
+SLIST_HEAD(listhead, list);
+
+#ifdef __APPLE__
+static sysmon_table_t plist;
+#else
+static struct kinfo_proc *plist;
+#endif
+static char *selected;
+static const char *delim = "\n";
+static int nproc;
+static int pgrep;
+static int signum = SIGTERM;
+static int newest;
+static int oldest;
+static int interactive;
+static int inverse;
+static int longfmt;
+static int matchargs;
+static int fullmatch;
+#ifndef __APPLE__
+static int kthreads;
+#endif
+static int cflags = REG_EXTENDED;
+static int quiet;
+#ifndef __APPLE__
+static kvm_t *kd;
+#endif
+static pid_t mypid;
+
+static struct listhead euidlist = SLIST_HEAD_INITIALIZER(euidlist);
+static struct listhead ruidlist = SLIST_HEAD_INITIALIZER(ruidlist);
+static struct listhead rgidlist = SLIST_HEAD_INITIALIZER(rgidlist);
+static struct listhead pgrplist = SLIST_HEAD_INITIALIZER(pgrplist);
+static struct listhead ppidlist = SLIST_HEAD_INITIALIZER(ppidlist);
+static struct listhead tdevlist = SLIST_HEAD_INITIALIZER(tdevlist);
+#ifndef __APPLE__
+static struct listhead sidlist = SLIST_HEAD_INITIALIZER(sidlist);
+static struct listhead jidlist = SLIST_HEAD_INITIALIZER(jidlist);
+#endif
+
+static void usage(void) __attribute__((__noreturn__));
+#ifdef __APPLE__
+static int killact(const sysmon_row_t);
+static int grepact(const sysmon_row_t);
+#else
+static int killact(const struct kinfo_proc *);
+static int grepact(const struct kinfo_proc *);
+#endif
+static void makelist(struct listhead *, enum listtype, char *);
+static int takepid(const char *, int);
+
+#ifdef __APPLE__
+static sysmon_table_t
+copy_process_info(void)
+{
+ dispatch_semaphore_t sema;
+ sysmon_request_t request;
+ __block sysmon_table_t result = NULL;
+
+ sema = dispatch_semaphore_create(0);
+ request = sysmon_request_create_with_error(SYSMON_REQUEST_TYPE_PROCESS, ^(sysmon_table_t table, const char *error_str) {
+ if (table) {
+ result = sysmon_retain(table);
+ } else {
+ fprintf(stderr, "sysmon request failed with error: %s\n", error_str);
+ }
+ dispatch_semaphore_signal(sema);
+ });
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_FLAGS);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_UID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_COMM);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_ARGUMENTS);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RUID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_RGID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PPID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_PGID);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_TDEV);
+ sysmon_request_add_attribute(request, SYSMON_ATTR_PROC_START);
+ sysmon_request_execute(request);
+ dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+ dispatch_release(sema);
+ sysmon_release(request);
+
+ return result;
+}
+#endif /* __APPLE__ */
+
+int
+main(int argc, char **argv)
+{
+#ifdef __APPLE__
+ char buf[_POSIX2_LINE_MAX], *bufp, *mstr, *p, *q, *pidfile;
+ xpc_object_t pargv;
+#else
+ char buf[_POSIX2_LINE_MAX], *mstr, **pargv, *p, *q, *pidfile;
+ const char *execf, *coref;
+#endif
+ int ancestors, debug_opt, did_action;
+ int i, ch, bestidx, rv, criteria, pidfromfile, pidfilelock;
+#ifdef __APPLE__
+ __block size_t jsz;
+ int (*action)(const sysmon_row_t);
+ sysmon_row_t kp;
+#else
+ size_t jsz;
+ int (*action)(const struct kinfo_proc *);
+ struct kinfo_proc *kp;
+#endif
+ struct list *li;
+#ifdef __APPLE__
+ int64_t best_tval;
+#else
+ struct timeval best_tval;
+#endif
+ regex_t reg;
+ regmatch_t regmatch;
+ pid_t pid;
+
+ setlocale(LC_ALL, "");
+
+ if (strcmp(getprogname(), "pgrep") == 0) {
+ action = grepact;
+ pgrep = 1;
+ } else {
+ action = killact;
+ p = argv[1];
+
+ if (argc > 1 && p[0] == '-') {
+ p++;
+ i = (int)strtol(p, &q, 10);
+ if (*q == '\0') {
+ signum = i;
+ argv++;
+ argc--;
+ } else {
+ if (strncasecmp(p, "SIG", 3) == 0)
+ p += 3;
+ for (i = 1; i < NSIG; i++)
+ if (strcasecmp(sys_signame[i], p) == 0)
+ break;
+ if (i != NSIG) {
+ signum = i;
+ argv++;
+ argc--;
+ }
+ }
+ }
+ }
+
+ ancestors = 0;
+ criteria = 0;
+ debug_opt = 0;
+ pidfile = NULL;
+ pidfilelock = 0;
+ quiet = 0;
+#ifndef __APPLE__
+ execf = NULL;
+ coref = _PATH_DEVNULL;
+#endif
+
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "DF:G:ILP:U:ad:fg:ilnoqt:u:vx")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "DF:G:ILM:N:P:SU:ad:fg:ij:lnoqs:t:u:vx")) != -1)
+#endif
+ switch (ch) {
+ case 'D':
+ debug_opt++;
+ break;
+ case 'F':
+ pidfile = optarg;
+ criteria = 1;
+ break;
+ case 'G':
+ makelist(&rgidlist, LT_GROUP, optarg);
+ criteria = 1;
+ break;
+ case 'I':
+ if (pgrep)
+ usage();
+ interactive = 1;
+ break;
+ case 'L':
+ pidfilelock = 1;
+ break;
+#ifndef __APPLE__
+ case 'M':
+ coref = optarg;
+ break;
+ case 'N':
+ execf = optarg;
+ break;
+#endif
+ case 'P':
+ makelist(&ppidlist, LT_GENERIC, optarg);
+ criteria = 1;
+ break;
+#ifndef __APPLE__
+ case 'S':
+ if (!pgrep)
+ usage();
+ kthreads = 1;
+ break;
+#endif
+ case 'U':
+ makelist(&ruidlist, LT_USER, optarg);
+ criteria = 1;
+ break;
+ case 'a':
+ ancestors++;
+ break;
+ case 'd':
+ if (!pgrep)
+ usage();
+ delim = optarg;
+ break;
+ case 'f':
+ matchargs = 1;
+ break;
+ case 'g':
+ makelist(&pgrplist, LT_PGRP, optarg);
+ criteria = 1;
+ break;
+ case 'i':
+ cflags |= REG_ICASE;
+ break;
+#ifndef __APPLE__
+ case 'j':
+ makelist(&jidlist, LT_JID, optarg);
+ criteria = 1;
+ break;
+#endif
+ case 'l':
+ longfmt = 1;
+ break;
+ case 'n':
+ newest = 1;
+ criteria = 1;
+ break;
+ case 'o':
+ oldest = 1;
+ criteria = 1;
+ break;
+ case 'q':
+ if (!pgrep)
+ usage();
+ quiet = 1;
+ break;
+#ifndef __APPLE__
+ case 's':
+ makelist(&sidlist, LT_SID, optarg);
+ criteria = 1;
+ break;
+#endif /* !__APPLE__ */
+ case 't':
+ makelist(&tdevlist, LT_TTY, optarg);
+ criteria = 1;
+ break;
+ case 'u':
+ makelist(&euidlist, LT_USER, optarg);
+ criteria = 1;
+ break;
+ case 'v':
+ inverse = 1;
+ break;
+ case 'x':
+ fullmatch = 1;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc != 0)
+ criteria = 1;
+ if (!criteria)
+ usage();
+ if (newest && oldest)
+ errx(STATUS_ERROR, "Options -n and -o are mutually exclusive");
+ if (pidfile != NULL)
+ pidfromfile = takepid(pidfile, pidfilelock);
+ else {
+ if (pidfilelock) {
+ errx(STATUS_ERROR,
+ "Option -L doesn't make sense without -F");
+ }
+ pidfromfile = -1;
+ }
+
+ mypid = getpid();
+
+#ifdef __APPLE__
+ plist = copy_process_info();
+ if (plist == NULL) {
+ errx(STATUS_ERROR, "Cannot get process list");
+ }
+ nproc = sysmon_table_get_count(plist);
+#else
+ /*
+ * Retrieve the list of running processes from the kernel.
+ */
+ kd = kvm_openfiles(execf, coref, NULL, O_RDONLY, buf);
+ if (kd == NULL)
+ errx(STATUS_ERROR, "Cannot open kernel files (%s)", buf);
+
+ /*
+ * Use KERN_PROC_PROC instead of KERN_PROC_ALL, since we
+ * just want processes and not individual kernel threads.
+ */
+ plist = kvm_getprocs(kd, KERN_PROC_PROC, 0, &nproc);
+ if (plist == NULL) {
+ errx(STATUS_ERROR, "Cannot get process list (%s)",
+ kvm_geterr(kd));
+ }
+#endif
+
+ /*
+ * Allocate memory which will be used to keep track of the
+ * selection.
+ */
+ if ((selected = malloc(nproc)) == NULL) {
+ err(STATUS_ERROR, "Cannot allocate memory for %d processes",
+ nproc);
+ }
+ memset(selected, 0, nproc);
+
+ /*
+ * Refine the selection.
+ */
+ for (; *argv != NULL; argv++) {
+ if ((rv = regcomp(&reg, *argv, cflags)) != 0) {
+ regerror(rv, &reg, buf, sizeof(buf));
+ errx(STATUS_BADUSAGE,
+ "Cannot compile regular expression `%s' (%s)",
+ *argv, buf);
+ }
+
+#ifdef __APPLE__
+ for (i = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (PSKIP(kp)) {
+ if (debug_opt > 0)
+ fprintf(stderr, "* Skipped %5d %3d %s\n",
+#ifdef __APPLE__
+ (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
+ (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)),
+ xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM)));
+#else
+ kp->ki_pid, kp->ki_uid, kp->ki_comm);
+#endif
+ continue;
+ }
+
+#ifdef __APPLE__
+ if (matchargs &&
+ (pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) {
+ jsz = 0;
+ os_assert(sizeof(buf) == _POSIX2_LINE_MAX);
+ bufp = buf;
+ xpc_array_apply(pargv, ^(size_t index, xpc_object_t value) {
+ if (jsz >= _POSIX2_LINE_MAX) {
+ return (bool)false;
+ }
+ jsz += snprintf(bufp + jsz,
+ _POSIX2_LINE_MAX - jsz,
+ index < xpc_array_get_count(pargv) - 1 ? "%s " : "%s",
+ xpc_string_get_string_ptr(value));
+ return (bool)true;
+ });
+#else
+ if (matchargs &&
+ (pargv = kvm_getargv(kd, kp, 0)) != NULL) {
+ jsz = 0;
+ while (jsz < sizeof(buf) && *pargv != NULL) {
+ jsz += snprintf(buf + jsz,
+ sizeof(buf) - jsz,
+ pargv[1] != NULL ? "%s " : "%s",
+ pargv[0]);
+ pargv++;
+ }
+#endif
+ mstr = buf;
+ } else
+#ifdef __APPLE__
+ {
+ /*
+ * comm is limited to 15 bytes (MAXCOMLEN - 1).
+ * Try to use argv[0] (trimmed) if available.
+ */
+ mstr = NULL;
+ pargv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS);
+ if (pargv != NULL && xpc_array_get_count(pargv) > 0) {
+ const char *tmp = xpc_array_get_string(pargv, 0);
+ if (tmp != NULL) {
+ mstr = strrchr(tmp, '/');
+ if (mstr != NULL) {
+ mstr++;
+ } else {
+ mstr = (char *)tmp;
+ }
+ }
+ }
+
+ /* Fall back to "comm" if we failed to get argv[0]. */
+ if (mstr == NULL || *mstr == '\0') {
+ mstr = (char *)xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM));
+ }
+
+ /* Couldn't find process name, it probably exited. */
+ if (mstr == NULL) {
+ continue;
+ }
+ }
+#else
+ mstr = kp->ki_comm;
+#endif
+
+ rv = regexec(&reg, mstr, 1, &regmatch, 0);
+ if (rv == 0) {
+ if (fullmatch) {
+ if (regmatch.rm_so == 0 &&
+ regmatch.rm_eo ==
+ (off_t)strlen(mstr))
+ selected[i] = 1;
+ } else
+ selected[i] = 1;
+ } else if (rv != REG_NOMATCH) {
+ regerror(rv, &reg, buf, sizeof(buf));
+ errx(STATUS_ERROR,
+ "Regular expression evaluation error (%s)",
+ buf);
+ }
+ if (debug_opt > 1) {
+ const char *rv_res = "NoMatch";
+ if (selected[i])
+ rv_res = "Matched";
+ fprintf(stderr, "* %s %5d %3d %s\n", rv_res,
+#ifdef __APPLE__
+ (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
+ (uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)),
+ mstr);
+#else
+ kp->ki_pid, kp->ki_uid, mstr);
+#endif
+ }
+ }
+
+ regfree(&reg);
+ }
+
+#ifdef __APPLE__
+ for (i = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (PSKIP(kp))
+ continue;
+
+#ifdef __APPLE__
+ if (pidfromfile >= 0 && (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) != pidfromfile) {
+#else
+ if (pidfromfile >= 0 && kp->ki_pid != pidfromfile) {
+#endif
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &ruidlist, li_chain)
+#ifdef __APPLE__
+ if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RUID)) == (uid_t)li->li_number)
+#else
+ if (kp->ki_ruid == (uid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&ruidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &rgidlist, li_chain)
+#ifdef __APPLE__
+ if ((gid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_RGID)) == (gid_t)li->li_number)
+#else
+ if (kp->ki_rgid == (gid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&rgidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &euidlist, li_chain)
+#ifdef __APPLE__
+ if ((uid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_UID)) == (uid_t)li->li_number)
+#else
+ if (kp->ki_uid == (uid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&euidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &ppidlist, li_chain)
+#ifdef __APPLE__
+ if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID)) == (pid_t)li->li_number)
+#else
+ if (kp->ki_ppid == (pid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&ppidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &pgrplist, li_chain)
+#ifdef __APPLE__
+ if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PGID)) == (pid_t)li->li_number)
+#else
+ if (kp->ki_pgid == (pid_t)li->li_number)
+#endif
+ break;
+ if (SLIST_FIRST(&pgrplist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &tdevlist, li_chain) {
+ if (li->li_number == -1 &&
+#ifdef __APPLE__
+ (xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_FLAGS)) & PROC_FLAG_CONTROLT) == 0)
+#else
+ (kp->ki_flag & P_CONTROLT) == 0)
+#endif
+ break;
+#ifdef __APPLE__
+ if ((dev_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_TDEV)) == (dev_t)li->li_number)
+#else
+ if (kp->ki_tdev == (dev_t)li->li_number)
+#endif
+ break;
+ }
+ if (SLIST_FIRST(&tdevlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+#ifndef __APPLE__
+ SLIST_FOREACH(li, &sidlist, li_chain)
+ if (kp->ki_sid == (pid_t)li->li_number)
+ break;
+ if (SLIST_FIRST(&sidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+
+ SLIST_FOREACH(li, &jidlist, li_chain) {
+ /* A particular jail ID, including 0 (not in jail) */
+ if (kp->ki_jid == (int)li->li_number)
+ break;
+ /* Any jail */
+ if (kp->ki_jid > 0 && li->li_number == -1)
+ break;
+ }
+ if (SLIST_FIRST(&jidlist) != NULL && li == NULL) {
+ selected[i] = 0;
+ continue;
+ }
+#endif /* !__APPLE__ */
+
+ if (argc == 0)
+ selected[i] = 1;
+ }
+
+ if (!ancestors) {
+ pid = mypid;
+ while (pid) {
+#ifdef __APPLE__
+ for (i = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (PSKIP(kp))
+ continue;
+#ifdef __APPLE__
+ if ((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)) == pid) {
+ selected[i] = 0;
+ pid = (pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PPID));
+ break;
+ }
+#else
+ if (kp->ki_pid == pid) {
+ selected[i] = 0;
+ pid = kp->ki_ppid;
+ break;
+ }
+#endif
+ }
+ if (i == nproc) {
+ if (pid == mypid)
+ pid = getppid();
+ else
+ break; /* Maybe we're in a jail ? */
+ }
+ }
+ }
+
+ if (newest || oldest) {
+#ifdef __APPLE__
+ best_tval = 0;
+#else
+ best_tval.tv_sec = 0;
+ best_tval.tv_usec = 0;
+#endif
+ bestidx = -1;
+
+#ifdef __APPLE__
+ for (i = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (!selected[i])
+ continue;
+ if (bestidx == -1) {
+ /* The first entry of the list which matched. */
+ ;
+#ifdef __APPLE__
+ } else if (xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START)) > best_tval) {
+#else
+ } else if (timercmp(&kp->ki_start, &best_tval, >)) {
+#endif
+ /* This entry is newer than previous "best". */
+ if (oldest) /* but we want the oldest */
+ continue;
+ } else {
+ /* This entry is older than previous "best". */
+ if (newest) /* but we want the newest */
+ continue;
+ }
+ /* This entry is better than previous "best" entry. */
+#ifdef __APPLE__
+ best_tval = xpc_date_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_START));
+#else
+ best_tval.tv_sec = kp->ki_start.tv_sec;
+ best_tval.tv_usec = kp->ki_start.tv_usec;
+#endif
+ bestidx = i;
+ }
+
+ memset(selected, 0, nproc);
+ if (bestidx != -1)
+ selected[bestidx] = 1;
+ }
+
+ /*
+ * Take the appropriate action for each matched process, if any.
+ */
+ did_action = 0;
+#ifdef __APPLE__
+ for (i = 0, rv = 0; i < nproc; i++) {
+ kp = sysmon_table_get_row(plist, i);
+#else
+ for (i = 0, rv = 0, kp = plist; i < nproc; i++, kp++) {
+#endif
+ if (PSKIP(kp))
+ continue;
+ if (selected[i]) {
+ if (longfmt && !pgrep) {
+ did_action = 1;
+#ifdef __APPLE__
+ printf("kill -%d %d\n", signum, (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
+#else
+ printf("kill -%d %d\n", signum, kp->ki_pid);
+#endif
+ }
+ if (inverse)
+ continue;
+ } else if (!inverse)
+ continue;
+ rv |= (*action)(kp);
+ }
+ if (!did_action && !pgrep && longfmt)
+ fprintf(stderr,
+ "No matching processes belonging to you were found\n");
+
+ exit(rv ? STATUS_MATCH : STATUS_NOMATCH);
+}
+
+static void
+usage(void)
+{
+ const char *ustr;
+
+ if (pgrep)
+#ifdef __APPLE__
+ ustr = "[-Lfilnoqvx] [-d delim]";
+#else
+ ustr = "[-LSfilnoqvx] [-d delim]";
+#endif
+ else
+ ustr = "[-signal] [-ILfilnovx]";
+
+ fprintf(stderr,
+#ifdef __APPLE__
+ "usage: %s %s [-F pidfile] [-G gid]\n"
+ " [-P ppid] [-U uid] [-g pgrp]\n"
+#else
+ "usage: %s %s [-F pidfile] [-G gid] [-M core] [-N system]\n"
+ " [-P ppid] [-U uid] [-g pgrp] [-j jid] [-s sid]\n"
+#endif
+ " [-t tty] [-u euid] pattern ...\n", getprogname(),
+ ustr);
+
+ exit(STATUS_BADUSAGE);
+}
+
+static void
+#ifdef __APPLE__
+show_process(const sysmon_row_t kp)
+#else
+show_process(const struct kinfo_proc *kp)
+#endif
+{
+#ifdef __APPLE__
+ xpc_object_t argv;
+#else
+ char **argv;
+#endif
+
+ if (quiet) {
+ assert(pgrep);
+ return;
+ }
+#ifdef __APPLE__
+ if ((longfmt || !pgrep) && matchargs &&
+ (argv = sysmon_row_get_value(kp, SYSMON_ATTR_PROC_ARGUMENTS)) != NULL) {
+ printf("%d ", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
+ (void)xpc_array_apply(argv, ^(size_t index, xpc_object_t value) {
+ printf("%s", xpc_string_get_string_ptr(value));
+ if (index < xpc_array_get_count(argv) - 1)
+ putchar(' ');
+ return (bool)true;
+ });
+ } else if (longfmt || !pgrep)
+ printf("%d %s",
+ (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)),
+ xpc_string_get_string_ptr(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_COMM)));
+ else
+ printf("%d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
+#else
+ if ((longfmt || !pgrep) && matchargs &&
+ (argv = kvm_getargv(kd, kp, 0)) != NULL) {
+ printf("%d ", (int)kp->ki_pid);
+ for (; *argv != NULL; argv++) {
+ printf("%s", *argv);
+ if (argv[1] != NULL)
+ putchar(' ');
+ }
+ } else if (longfmt || !pgrep)
+ printf("%d %s", (int)kp->ki_pid, kp->ki_comm);
+ else
+ printf("%d", (int)kp->ki_pid);
+#endif
+}
+
+static int
+#ifdef __APPLE__
+killact(const sysmon_row_t kp)
+#else
+killact(const struct kinfo_proc *kp)
+#endif
+{
+ int ch, first;
+
+ if (interactive) {
+ /*
+ * Be careful, ask before killing.
+ */
+ printf("kill ");
+ show_process(kp);
+ printf("? ");
+ fflush(stdout);
+ first = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+ if (first != 'y' && first != 'Y')
+ return (1);
+ }
+#ifdef __APPLE__
+ if (kill((pid_t)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)), signum) == -1) {
+#else
+ if (kill(kp->ki_pid, signum) == -1) {
+#endif
+ /*
+ * Check for ESRCH, which indicates that the process
+ * disappeared between us matching it and us
+ * signalling it; don't issue a warning about it.
+ */
+ if (errno != ESRCH)
+#ifdef __APPLE__
+ warn("signalling pid %d", (int)xpc_uint64_get_value(sysmon_row_get_value(kp, SYSMON_ATTR_PROC_PID)));
+#else
+ warn("signalling pid %d", (int)kp->ki_pid);
+#endif
+ /*
+ * Return 0 to indicate that the process should not be
+ * considered a match, since we didn't actually get to
+ * signal it.
+ */
+ return (0);
+ }
+ return (1);
+}
+
+static int
+#ifdef __APPLE__
+grepact(const sysmon_row_t kp)
+#else
+grepact(const struct kinfo_proc *kp)
+#endif
+{
+
+ show_process(kp);
+ if (!quiet)
+ printf("%s", delim);
+ return (1);
+}
+
+static void
+makelist(struct listhead *head, enum listtype type, char *src)
+{
+ struct list *li;
+ struct passwd *pw;
+ struct group *gr;
+ struct stat st;
+ const char *cp;
+ char *sp, *ep, buf[MAXPATHLEN];
+ int empty;
+
+ empty = 1;
+
+ while ((sp = strsep(&src, ",")) != NULL) {
+ if (*sp == '\0')
+ usage();
+
+ if ((li = malloc(sizeof(*li))) == NULL) {
+ err(STATUS_ERROR, "Cannot allocate %zu bytes",
+ sizeof(*li));
+ }
+
+ SLIST_INSERT_HEAD(head, li, li_chain);
+ empty = 0;
+
+ li->li_number = (uid_t)strtol(sp, &ep, 0);
+ if (*ep == '\0') {
+ switch (type) {
+ case LT_PGRP:
+ if (li->li_number == 0)
+ li->li_number = getpgrp();
+ break;
+#ifndef __APPLE__
+ case LT_SID:
+ if (li->li_number == 0)
+ li->li_number = getsid(mypid);
+ break;
+ case LT_JID:
+ if (li->li_number < 0)
+ errx(STATUS_BADUSAGE,
+ "Negative jail ID `%s'", sp);
+ /* For compatibility with old -j */
+ if (li->li_number == 0)
+ li->li_number = -1; /* any jail */
+ break;
+#endif /* !__APPLE__ */
+ case LT_TTY:
+ if (li->li_number < 0)
+ errx(STATUS_BADUSAGE,
+ "Negative /dev/pts tty `%s'", sp);
+ snprintf(buf, sizeof(buf), _PATH_DEV "pts/%s",
+ sp);
+ if (stat(buf, &st) != -1)
+ goto foundtty;
+ if (errno == ENOENT)
+ errx(STATUS_BADUSAGE, "No such tty: `"
+ _PATH_DEV "pts/%s'", sp);
+ err(STATUS_ERROR, "Cannot access `"
+ _PATH_DEV "pts/%s'", sp);
+ break;
+ default:
+ break;
+ }
+ continue;
+ }
+
+ switch (type) {
+ case LT_USER:
+ if ((pw = getpwnam(sp)) == NULL)
+ errx(STATUS_BADUSAGE, "Unknown user `%s'", sp);
+ li->li_number = pw->pw_uid;
+ break;
+ case LT_GROUP:
+ if ((gr = getgrnam(sp)) == NULL)
+ errx(STATUS_BADUSAGE, "Unknown group `%s'", sp);
+ li->li_number = gr->gr_gid;
+ break;
+ case LT_TTY:
+ if (strcmp(sp, "-") == 0) {
+ li->li_number = -1;
+ break;
+ } else if (strcmp(sp, "co") == 0) {
+ cp = "console";
+ } else {
+ cp = sp;
+ }
+
+ snprintf(buf, sizeof(buf), _PATH_DEV "%s", cp);
+ if (stat(buf, &st) != -1)
+ goto foundtty;
+
+ snprintf(buf, sizeof(buf), _PATH_DEV "tty%s", cp);
+ if (stat(buf, &st) != -1)
+ goto foundtty;
+
+ if (errno == ENOENT)
+ errx(STATUS_BADUSAGE, "No such tty: `%s'", sp);
+ err(STATUS_ERROR, "Cannot access `%s'", sp);
+
+foundtty: if ((st.st_mode & S_IFCHR) == 0)
+ errx(STATUS_BADUSAGE, "Not a tty: `%s'", sp);
+
+ li->li_number = st.st_rdev;
+ break;
+#ifndef __APPLE__
+ case LT_JID:
+ if (strcmp(sp, "none") == 0)
+ li->li_number = 0;
+ else if (strcmp(sp, "any") == 0)
+ li->li_number = -1;
+ else if (*ep != '\0')
+ errx(STATUS_BADUSAGE,
+ "Invalid jail ID `%s'", sp);
+ break;
+#endif /* !__APPLE__ */
+ default:
+ usage();
+ }
+ }
+
+ if (empty)
+ usage();
+}
+
+static int
+takepid(const char *pidfile, int pidfilelock)
+{
+ char *endp, line[BUFSIZ];
+ FILE *fh;
+ long rval;
+
+ fh = fopen(pidfile, "r");
+ if (fh == NULL)
+ err(STATUS_ERROR, "Cannot open pidfile `%s'", pidfile);
+
+ if (pidfilelock) {
+ /*
+ * If we can lock pidfile, this means that daemon is not
+ * running, so would be better not to kill some random process.
+ */
+ if (flock(fileno(fh), LOCK_EX | LOCK_NB) == 0) {
+ (void)fclose(fh);
+ errx(STATUS_ERROR, "File '%s' can be locked", pidfile);
+ } else {
+ if (errno != EWOULDBLOCK) {
+ errx(STATUS_ERROR,
+ "Error while locking file '%s'", pidfile);
+ }
+ }
+ }
+
+ if (fgets(line, sizeof(line), fh) == NULL) {
+ if (feof(fh)) {
+ (void)fclose(fh);
+ errx(STATUS_ERROR, "Pidfile `%s' is empty", pidfile);
+ }
+ (void)fclose(fh);
+ err(STATUS_ERROR, "Cannot read from pid file `%s'", pidfile);
+ }
+ (void)fclose(fh);
+
+ rval = strtol(line, &endp, 10);
+ if (*endp != '\0' && !isspace((unsigned char)*endp))
+ errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
+ else if (rval < MIN_PID || rval > MAX_PID)
+ errx(STATUS_ERROR, "Invalid pid in file `%s'", pidfile);
+ return (rval);
+}
diff --git a/adv_cmds/ps/entitlements.plist b/adv_cmds/ps/entitlements.plist
new file mode 100644
index 0000000..eaaf1de
--- /dev/null
+++ b/adv_cmds/ps/entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.system-task-ports</key>
+ <true/>
+ <key>task_for_pid-allow</key>
+ <true/>
+</dict>
+</plist>
diff --git a/adv_cmds/ps/extern.h b/adv_cmds/ps/extern.h
new file mode 100644
index 0000000..d3f6503
--- /dev/null
+++ b/adv_cmds/ps/extern.h
@@ -0,0 +1,98 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.3 (Berkeley) 4/2/94
+ * $FreeBSD: extern.h,v 1.8 1998/05/25 05:07:17 steve Exp $
+ */
+
+struct kinfo;
+struct nlist;
+struct var;
+struct varent;
+
+extern fixpt_t ccpu;
+extern int cflag, eval, fscale, nlistread, rawcpu;
+#ifdef __APPLE__
+extern uint64_t mempages;
+#else
+extern unsigned long mempages;
+#endif
+extern time_t now;
+extern int showthreads, sumrusage, termwidth, totwidth;
+extern STAILQ_HEAD(velisthead, varent) varlist;
+
+__BEGIN_DECLS
+int get_task_info(KINFO *);
+void command(KINFO *, VARENT *);
+void just_command(KINFO *, VARENT *);
+void args(KINFO *, VARENT *);
+int s_command(KINFO *);
+int s_just_command(KINFO *);
+int s_args(KINFO *);
+void cputime(KINFO *, VARENT *);
+void pstime(KINFO *, VARENT *);
+void p_etime(KINFO *, VARENT *);
+int s_etime(KINFO *);
+void putime(KINFO *, VARENT *);
+int donlist(void);
+void evar(KINFO *, VARENT *);
+VARENT *find_varentry(VAR *);
+const char *fmt_argv(char **, char *, size_t);
+int getpcpu(KINFO *);
+double getpmem(KINFO *);
+void logname(KINFO *, VARENT *);
+void longtname(KINFO *, VARENT *);
+void lstarted(KINFO *, VARENT *);
+void maxrss(KINFO *, VARENT *);
+void nlisterr(struct nlist *);
+void p_rssize(KINFO *, VARENT *);
+void pagein(KINFO *, VARENT *);
+void parsefmt(const char *, int);
+void pcpu(KINFO *, VARENT *);
+void pmem(KINFO *, VARENT *);
+void pri(KINFO *, VARENT *);
+void rtprior(KINFO *, VARENT *);
+void printheader(void);
+void pvar(KINFO *, VARENT *);
+void runame(KINFO *, VARENT *);
+void rvar(KINFO *, VARENT *);
+int s_runame(KINFO *);
+int s_uname(KINFO *);
+void showkey(void);
+void started(KINFO *, VARENT *);
+void state(KINFO *, VARENT *);
+void tdev(KINFO *, VARENT *);
+void tname(KINFO *, VARENT *);
+void tsize(KINFO *, VARENT *);
+void ucomm(KINFO *, VARENT *);
+void uname(KINFO *, VARENT *);
+void uvar(KINFO *, VARENT *);
+void vsize(KINFO *, VARENT *);
+void wchan(KINFO *, VARENT *);
+void wq(KINFO *, VARENT *);
+__END_DECLS
diff --git a/adv_cmds/ps/fmt.c b/adv_cmds/ps/fmt.c
new file mode 100644
index 0000000..26ba3dc
--- /dev/null
+++ b/adv_cmds/ps/fmt.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)fmt.c 8.4 (Berkeley) 4/15/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ps/fmt.c,v 1.34 2004/06/22 02:18:29 gad Exp $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+
+#include "ps.h"
+
+static char *cmdpart(char *);
+static char *shquote(char **);
+
+static char *
+shquote(char **argv)
+{
+ long arg_max;
+ static size_t buf_size;
+ size_t len;
+ char **p, *dst, *src;
+ static char *buf = NULL;
+
+ if (buf == NULL) {
+ if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
+ errx(1, "sysconf _SC_ARG_MAX failed");
+ if (arg_max >= LONG_MAX / 4 || arg_max >= (long)(SIZE_MAX / 4))
+ errx(1, "sysconf _SC_ARG_MAX preposterously large");
+ buf_size = 4 * arg_max + 1;
+ if ((buf = malloc(buf_size)) == NULL)
+ errx(1, "malloc failed");
+ }
+
+ if (*argv == NULL) {
+ buf[0] = '\0';
+ return (buf);
+ }
+ dst = buf;
+ for (p = argv; (src = *p++) != NULL; ) {
+ if (*src == '\0')
+ continue;
+ len = (buf_size - 1 - (dst - buf)) / 4;
+ strvisx(dst, src, strlen(src) < len ? strlen(src) : len,
+ VIS_NL | VIS_CSTYLE);
+ while (*dst != '\0')
+ dst++;
+ if ((buf_size - 1 - (dst - buf)) / 4 > 0)
+ *dst++ = ' ';
+ }
+ /* Chop off trailing space */
+ if (dst != buf && dst[-1] == ' ')
+ dst--;
+ *dst = '\0';
+ return (buf);
+}
+
+static char *
+cmdpart(char *arg0)
+{
+ char *cp;
+
+ return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
+}
+
+const char *
+fmt_argv(char **argv, char *cmd, size_t maxlen)
+{
+ size_t len;
+ char *ap, *cp;
+
+ if (argv == NULL || argv[0] == NULL) {
+ if (cmd == NULL)
+ return ("");
+ ap = NULL;
+ len = maxlen + 3;
+ } else {
+ ap = shquote(argv);
+ len = strlen(ap) + maxlen + 4;
+ }
+ cp = malloc(len);
+ if (cp == NULL)
+ errx(1, "malloc failed");
+ if (ap == NULL)
+ sprintf(cp, "[%.*s]", (int)maxlen, cmd);
+ else if (strncmp(cmdpart(argv[0]), cmd, maxlen) != 0)
+ sprintf(cp, "%s (%.*s)", ap, (int)maxlen, cmd);
+ else
+ strcpy(cp, ap);
+ return (cp);
+}
diff --git a/adv_cmds/ps/keyword.c b/adv_cmds/ps/keyword.c
new file mode 100644
index 0000000..ff311b4
--- /dev/null
+++ b/adv_cmds/ps/keyword.c
@@ -0,0 +1,340 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)keyword.c 8.5 (Berkeley) 4/2/94";
+#else
+static const char rcsid[] =
+ "$FreeBSD: keyword.c,v 1.23 1999/01/26 02:38:09 julian Exp $";
+#endif /* not lint */
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/proc.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ps.h"
+
+VAR *findvar(char *, int, char **header);
+static int vcmp(const void *, const void *);
+
+/* Compute offset in common structures. */
+#define POFF(x) offsetof(struct extern_proc, x)
+#define EOFF(x) offsetof(struct eproc, x)
+#define UOFF(x) offsetof(struct usave, x)
+#define ROFF(x) offsetof(struct rusage, x)
+
+#define EMULLEN 13 /* enough for "FreeBSD ELF32" */
+#define LWPFMT "d"
+#define LWPLEN 6
+#define NLWPFMT "d"
+#define NLWPLEN 4
+#ifdef __APPLE__
+#define UIDFMT "d"
+#else
+#define UIDFMT "u"
+#endif
+#define UIDLEN 5
+#define PIDFMT "d"
+#define PIDLEN 5
+#define USERLEN 16
+
+/* PLEASE KEEP THE TABLE BELOW SORTED ALPHABETICALLY!!! */
+static VAR var[] = {
+ /* 4133537: 5 characters to accomodate 100% or more */
+ {"%cpu", "%CPU", NULL, 0, pcpu, NULL, 5, 0, CHAR, NULL, 0},
+ {"%mem", "%MEM", NULL, 0, pmem, NULL, 4},
+ {"acflag", "ACFLG",
+ NULL, 0, pvar, NULL, 3, POFF(p_acflag), USHORT, "x"},
+ {"acflg", "", "acflag"},
+ {"args", "ARGS", NULL, COMM|LJUST|USER|DSIZ, args, s_args, 64},
+ {"blocked", "", "sigmask"},
+ {"caught", "", "sigcatch"},
+ {"comm", "COMM", NULL, COMM|LJUST|USER|DSIZ, just_command, s_just_command, 16},
+ {"command", "COMMAND", NULL, COMM|LJUST|USER|DSIZ, command, s_command, 16},
+ {"cpu", "CPU", NULL, 0, pvar, NULL, 3, POFF(p_estcpu), UINT, "d"},
+ {"cputime", "", "time"},
+ {"etime", "ELAPSED", NULL, USER|DSIZ, p_etime, s_etime, 20},
+ /* 5861775: Make F column 8 characters. */
+ {"f", "F", NULL, 0, pvar, NULL, 8, POFF(p_flag), INT, "x"},
+ {"flags", "", "f"},
+ {"gid", "GID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_ucred.cr_gid),
+ UINT, UIDFMT},
+ {"group", "GROUP", "gid"},
+ {"ignored", "", "sigignore"},
+ {"inblk", "INBLK",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_inblock), LONG, "ld"},
+ {"inblock", "", "inblk"},
+ {"jobc", "JOBC", NULL, 0, evar, NULL, 4, EOFF(e_jobc), SHORT, "d"},
+ {"ktrace", "KTRACE",
+ NULL, 0, pvar, NULL, 8, POFF(p_traceflag), INT, "x"},
+ {"ktracep", "KTRACEP",
+ NULL, 0, pvar, NULL, 8, POFF(p_tracep), LONG, "lx"},
+ {"lim", "LIM", NULL, 0, maxrss, NULL, 5},
+ {"login", "LOGIN", NULL, LJUST, logname, NULL, MAXLOGNAME-1},
+ {"logname", "", "login"},
+ {"lstart", "STARTED", NULL, LJUST|USER, lstarted, NULL, 28},
+ {"majflt", "MAJFLT",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_majflt), LONG, "ld"},
+ {"minflt", "MINFLT",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_minflt), LONG, "ld"},
+ {"msgrcv", "MSGRCV",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_msgrcv), LONG, "ld"},
+ {"msgsnd", "MSGSND",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_msgsnd), LONG, "ld"},
+ {"ni", "", "nice"},
+ {"nice", "NI", NULL, 0, pvar, NULL, 2, POFF(p_nice), CHAR, "d"},
+ {"nivcsw", "NIVCSW",
+ NULL, USER, rvar, NULL, 5, ROFF(ru_nivcsw), LONG, "ld"},
+ {"nsignals", "", "nsigs"},
+ {"nsigs", "NSIGS",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_nsignals), LONG, "ld"},
+ {"nswap", "NSWAP",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_nswap), LONG, "ld"},
+ {"nvcsw", "NVCSW",
+ NULL, USER, rvar, NULL, 5, ROFF(ru_nvcsw), LONG, "ld"},
+ {"nwchan", "WCHAN", NULL, 0, pvar, NULL, 6, POFF(p_wchan), KPTR, "lx"},
+ {"oublk", "OUBLK",
+ NULL, USER, rvar, NULL, 4, ROFF(ru_oublock), LONG, "ld"},
+ {"oublock", "", "oublk"},
+ {"p_ru", "P_RU", NULL, 0, pvar, NULL, 6, POFF(p_ru), KPTR, "lx"},
+ {"paddr", "PADDR", NULL, 0, evar, NULL, sizeof(void *) * 2, EOFF(e_paddr), KPTR, "lx"},
+ {"pagein", "PAGEIN", NULL, USER, pagein, NULL, 6},
+ {"pcpu", "", "%cpu"},
+ {"pending", "", "sig"},
+ {"pgid", "PGID",
+ NULL, 0, evar, NULL, PIDLEN, EOFF(e_pgid), UINT, PIDFMT},
+ {"pid", "PID", NULL, 0, pvar, NULL, PIDLEN, POFF(p_pid), UINT, PIDFMT},
+ {"pmem", "", "%mem"},
+ {"ppid", "PPID",
+ NULL, 0, evar, NULL, PIDLEN, EOFF(e_ppid), UINT, PIDFMT},
+ {"pri", "PRI", NULL, 0, pri, NULL, 3},
+ {"pstime", "", "stime"},
+ {"putime", "", "utime"},
+ {"re", "RE", NULL, 0, pvar, NULL, 3, POFF(p_swtime), UINT, "d"},
+ {"rgid", "RGID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_pcred.p_rgid),
+ UINT, UIDFMT},
+ {"rgroup", "RGROUP", "rgid"},
+ {"rss", "RSS", NULL, 0, p_rssize, NULL, 6},
+#if FIXME
+ {"rtprio", "RTPRIO", NULL, 0, rtprior, NULL, 7, POFF(p_rtprio)},
+#endif /* FIXME */
+ {"ruid", "RUID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_pcred.p_ruid),
+ UINT, UIDFMT},
+ {"ruser", "RUSER", NULL, LJUST|DSIZ, runame, s_runame, USERLEN},
+ {"sess", "SESS", NULL, 0, evar, NULL, 6, EOFF(e_sess), KPTR, "lx"},
+ {"sig", "PENDING", NULL, 0, pvar, NULL, 8, POFF(p_siglist), INT, "x"},
+#if FIXME
+ {"sigcatch", "CAUGHT",
+ NULL, 0, evar, NULL, 8, EOFF(e_procsig.ps_sigcatch), UINT, "x"},
+ {"sigignore", "IGNORED",
+ NULL, 0, evar, NULL, 8, EOFF(e_procsig.ps_sigignore), UINT, "x"},
+#endif /* FIXME */
+ {"sigmask", "BLOCKED",
+ NULL, 0, pvar, NULL, 8, POFF(p_sigmask), UINT, "x"},
+ {"sl", "SL", NULL, 0, pvar, NULL, 3, POFF(p_slptime), UINT, "d"},
+ {"start", "STARTED", NULL, LJUST|USER, started, NULL, 7},
+ {"stat", "", "state"},
+ {"state", "STAT", NULL, 0, state, NULL, 4},
+ {"stime", "STIME", NULL, USER, pstime, NULL, 9},
+ {"svgid", "SVGID", NULL, 0,
+ evar, NULL, UIDLEN, EOFF(e_pcred.p_svgid), UINT, UIDFMT},
+ {"svuid", "SVUID", NULL, 0,
+ evar, NULL, UIDLEN, EOFF(e_pcred.p_svuid), UINT, UIDFMT},
+ {"tdev", "TDEV", NULL, 0, tdev, NULL, 4},
+ {"time", "TIME", NULL, USER, cputime, NULL, 9},
+ {"tpgid", "TPGID",
+ NULL, 0, evar, NULL, 4, EOFF(e_tpgid), UINT, PIDFMT},
+ {"tsess", "TSESS", NULL, 0, evar, NULL, 6, EOFF(e_tsess), KPTR, "lx"},
+ {"tsiz", "TSIZ", NULL, 0, tsize, NULL, 8},
+ {"tt", "TT ", NULL, 0, tname, NULL, 5},
+ {"tty", "TTY", NULL, LJUST, longtname, NULL, 8},
+ {"ucomm", "UCOMM", NULL, LJUST, ucomm, NULL, MAXCOMLEN},
+ {"uid", "UID", NULL, 0, evar, NULL, UIDLEN, EOFF(e_ucred.cr_uid),
+ UINT, UIDFMT},
+ {"upr", "UPR", NULL, 0, pvar, NULL, 3, POFF(p_usrpri), CHAR, "d"},
+ {"user", "USER", NULL, LJUST|DSIZ, uname, s_uname, USERLEN},
+ {"usrpri", "", "upr"},
+ {"utime", "UTIME", NULL, USER, putime, NULL, 9},
+ {"vsize", "", "vsz"},
+ {"vsz", "VSZ", NULL, 0, vsize, NULL, 8},
+ {"wchan", "WCHAN", NULL, LJUST, wchan, NULL, 6},
+ {"wq", "WQ", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0},
+ {"wqb", "WQB", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0},
+ {"wql", "WQL", NULL, 0, wq, NULL, 3, 0, CHAR, NULL, 0},
+ {"wqr", "WQR", NULL, 0, wq, NULL, 4, 0, CHAR, NULL, 0},
+ {"xstat", "XSTAT", NULL, 0, pvar, NULL, 4, POFF(p_xstat), USHORT, "x"},
+ {""},
+};
+
+void
+showkey(void)
+{
+ VAR *v;
+ int i;
+ const char *p, *sep;
+
+ i = 0;
+ sep = "";
+ for (v = var; *(p = v->name); ++v) {
+ int len = strlen(p);
+ if (termwidth && (i += len + 1) > termwidth) {
+ i = len;
+ sep = "\n";
+ }
+ (void) printf("%s%s", sep, p);
+ sep = " ";
+ }
+ (void) printf("\n");
+}
+
+void
+parsefmt(const char *p, int user)
+{
+ char *tempstr, *tempstr1;
+
+#define FMTSEP " \t,\n"
+ tempstr1 = tempstr = strdup(p);
+ while (tempstr && *tempstr) {
+ char *cp, *hp;
+ VAR *v;
+ struct varent *vent;
+
+#ifndef __APPLE__
+ /*
+ * If an item contains an equals sign, it specifies a column
+ * header, may contain embedded separator characters and
+ * is always the last item.
+ */
+ if (tempstr[strcspn(tempstr, "="FMTSEP)] != '=')
+#endif /* !__APPLE__ */
+ while ((cp = strsep(&tempstr, FMTSEP)) != NULL &&
+ *cp == '\0')
+ /* void */;
+#ifndef __APPLE__
+ else {
+ cp = tempstr;
+ tempstr = NULL;
+ }
+#endif /* !__APPLE__ */
+ if (cp == NULL || !(v = findvar(cp, user, &hp)))
+ continue;
+ if (!user) {
+ /*
+ * If the user is NOT adding this field manually,
+ * get on with our lives if this VAR is already
+ * represented in the list.
+ */
+ vent = find_varentry(v);
+ if (vent != NULL)
+ continue;
+ }
+ if ((vent = malloc(sizeof(struct varent))) == NULL)
+ errx(1, "malloc failed");
+ vent->header = v->header;
+ if (hp) {
+ hp = strdup(hp);
+ if (hp)
+ vent->header = hp;
+ }
+ vent->var = malloc(sizeof(*vent->var));
+ if (vent->var == NULL)
+ errx(1, "malloc failed");
+ memcpy(vent->var, v, sizeof(*vent->var));
+ STAILQ_INSERT_TAIL(&varlist, vent, next_ve);
+ }
+ free(tempstr1);
+ if (STAILQ_EMPTY(&varlist)) {
+ warnx("no valid keywords; valid keywords:");
+ showkey();
+ exit(1);
+ }
+}
+
+VAR *
+findvar(char *p, int user, char **header)
+{
+ size_t rflen;
+ VAR *v, key;
+ char *hp, *realfmt;
+
+ hp = strchr(p, '=');
+ if (hp)
+ *hp++ = '\0';
+
+ key.name = p;
+ v = bsearch(&key, var, sizeof(var)/sizeof(VAR) - 1, sizeof(VAR), vcmp);
+
+ if (v && v->alias) {
+ /*
+ * If the user specified an alternate-header for this
+ * (aliased) format-name, then we need to copy that
+ * alternate-header when making the recursive call to
+ * process the alias.
+ */
+ if (hp == NULL)
+ parsefmt(v->alias, user);
+ else {
+ /*
+ * XXX - This processing will not be correct for
+ * any alias which expands into a list of format
+ * keywords. Presently there are no aliases
+ * which do that.
+ */
+ rflen = strlen(v->alias) + strlen(hp) + 2;
+ realfmt = malloc(rflen);
+ snprintf(realfmt, rflen, "%s=%s", v->alias, hp);
+ parsefmt(realfmt, user);
+ }
+ return ((VAR *)NULL);
+ }
+ if (!v) {
+ warnx("%s: keyword not found", p);
+ eval = 1;
+ }
+ if (header)
+ *header = hp;
+ return (v);
+}
+
+static int
+vcmp(const void *a, const void *b)
+{
+ return (strcmp(((const VAR *)a)->name, ((const VAR *)b)->name));
+}
diff --git a/adv_cmds/ps/nlist.c b/adv_cmds/ps/nlist.c
new file mode 100644
index 0000000..90a2303
--- /dev/null
+++ b/adv_cmds/ps/nlist.c
@@ -0,0 +1,86 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)nlist.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ps/nlist.c,v 1.21 2004/04/06 20:06:49 markm Exp $");
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#ifdef __APPLE__
+#include <sys/resource.h>
+#endif
+
+#include <stddef.h>
+
+#include "ps.h"
+
+fixpt_t ccpu; /* kernel _ccpu variable */
+int nlistread; /* if nlist already read. */
+#ifdef __APPLE__
+uint64_t mempages; /* number of pages of phys. memory */
+#else
+unsigned long mempages; /* number of pages of phys. memory */
+#endif
+int fscale; /* kernel _fscale variable */
+
+int
+donlist(void)
+{
+#ifdef __APPLE__
+ int mib[2];
+#endif
+ size_t oldlen;
+
+#ifdef __APPLE__
+ mib[0] = CTL_HW;
+ mib[1] = HW_MEMSIZE;
+ oldlen = sizeof(mempages);
+ if (sysctl(mib, 2, &mempages, &oldlen, NULL, 0) == -1)
+ return (1);
+ fscale = 100;
+#else
+ oldlen = sizeof(ccpu);
+ if (sysctlbyname("kern.ccpu", &ccpu, &oldlen, NULL, 0) == -1)
+ return (1);
+ oldlen = sizeof(fscale);
+ if (sysctlbyname("kern.fscale", &fscale, &oldlen, NULL, 0) == -1)
+ return (1);
+ oldlen = sizeof(mempages);
+ if (sysctlbyname("hw.availpages", &mempages, &oldlen, NULL, 0) == -1)
+ return (1);
+#endif
+ nlistread = 1;
+ return (0);
+}
diff --git a/adv_cmds/ps/print.c b/adv_cmds/ps/print.c
new file mode 100644
index 0000000..103ba48
--- /dev/null
+++ b/adv_cmds/ps/print.c
@@ -0,0 +1,1225 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: print.c,v 1.33 1998/11/25 09:34:00 dfr Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/ucred.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
+
+#include <sys/ucred.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <sys/cdefs.h>
+
+#if FIXME
+#include <vm/vm.h>
+#endif /* FIXME */
+#include <err.h>
+#include <langinfo.h>
+#include <libproc.h>
+#include <math.h>
+#include <nlist.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <vis.h>
+#include <pwd.h>
+
+#include "ps.h"
+
+extern int mflg, print_all_thread, print_thread_num;
+
+void
+printheader(void)
+{
+ VAR *v;
+ struct varent *vent;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve)
+ if (*vent->header != '\0')
+ break;
+ if (!vent)
+ return;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ v = vent->var;
+ if (v->flag & LJUST) {
+ if (STAILQ_NEXT(vent, next_ve) == NULL) /* last one */
+ (void)printf("%s", vent->header);
+ else
+ (void)printf("%-*s", v->width, vent->header);
+ } else
+ (void)printf("%*s", v->width, vent->header);
+ if (STAILQ_NEXT(vent, next_ve) != NULL)
+ (void)putchar(' ');
+ }
+ (void)putchar('\n');
+}
+
+/*
+ * Get command and arguments.
+ *
+ * If the global variable eflg is non-zero and the user has permission to view
+ * the process's environment, the environment is included.
+ *
+ * on return argvlen is the length of the extracted string, argv0len is
+ * the length of the command (same as argvlen if show_args is true)
+ */
+static void
+getproclline(KINFO *k, char **command_name, int *argvlen, int *argv0len,
+ int show_args)
+{
+ int mib[3], argmax, nargs, c = 0;
+ size_t size;
+ char *procargs, *sp, *np, *cp;
+ extern int eflg;
+
+ /* Get the maximum process arguments size. */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+
+ size = sizeof(argmax);
+ if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
+ goto ERROR_A;
+ }
+
+ /* Allocate space for the arguments. */
+ procargs = (char *)malloc(argmax);
+ if (procargs == NULL) {
+ goto ERROR_A;
+ }
+
+ /*
+ * Make a sysctl() call to get the raw argument space of the process.
+ * The layout is documented in start.s, which is part of the Csu
+ * project. In summary, it looks like:
+ *
+ * /---------------\ 0x00000000
+ * : :
+ * : :
+ * |---------------|
+ * | argc |
+ * |---------------|
+ * | arg[0] |
+ * |---------------|
+ * : :
+ * : :
+ * |---------------|
+ * | arg[argc - 1] |
+ * |---------------|
+ * | 0 |
+ * |---------------|
+ * | env[0] |
+ * |---------------|
+ * : :
+ * : :
+ * |---------------|
+ * | env[n] |
+ * |---------------|
+ * | 0 |
+ * |---------------| <-- Beginning of data returned by sysctl() is here.
+ * | argc |
+ * |---------------|
+ * | exec_path |
+ * |:::::::::::::::|
+ * | |
+ * | String area. |
+ * | |
+ * |---------------| <-- Top of stack.
+ * : :
+ * : :
+ * \---------------/ 0xffffffff
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS2;
+ mib[2] = KI_PROC(k)->p_pid;
+
+ size = (size_t)argmax;
+ if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
+ goto ERROR_B;
+ }
+
+ memcpy(&nargs, procargs, sizeof(nargs));
+ cp = procargs + sizeof(nargs);
+
+ /* Skip the saved exec_path. */
+ for (; cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ /* End of exec_path reached. */
+ break;
+ }
+ }
+ if (cp == &procargs[size]) {
+ goto ERROR_B;
+ }
+
+ /* Skip trailing '\0' characters. */
+ for (; cp < &procargs[size]; cp++) {
+ if (*cp != '\0') {
+ /* Beginning of first argument reached. */
+ break;
+ }
+ }
+ if (cp == &procargs[size]) {
+ goto ERROR_B;
+ }
+ /* Save where the argv[0] string starts. */
+ sp = cp;
+
+ /*
+ * Iterate through the '\0'-terminated strings and convert '\0' to ' '
+ * until a string is found that has a '=' character in it (or there are
+ * no more strings in procargs). There is no way to deterministically
+ * know where the command arguments end and the environment strings
+ * start, which is why the '=' character is searched for as a heuristic.
+ */
+ for (np = NULL; c < nargs && cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ c++;
+ if (np != NULL) {
+ /* Convert previous '\0'. */
+ *np = ' ';
+ } else {
+ *argv0len = cp - sp;
+ }
+ /* Note location of current '\0'. */
+ np = cp;
+
+ if (!show_args) {
+ /*
+ * Don't convert '\0' characters to ' '.
+ * However, we needed to know that the
+ * command name was terminated, which we
+ * now know.
+ */
+ break;
+ }
+ }
+ }
+
+ /*
+ * If eflg is non-zero, continue converting '\0' characters to ' '
+ * characters until no more strings that look like environment settings
+ * follow.
+ */
+ if ( show_args && (eflg != 0) && ( (getuid() == 0) || (KI_EPROC(k)->e_pcred.p_ruid == getuid()) ) ) {
+ for (; cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ if (np != NULL) {
+ if (&np[1] == cp) {
+ /*
+ * Two '\0' characters in a row.
+ * This should normally only
+ * happen after all the strings
+ * have been seen, but in any
+ * case, stop parsing.
+ */
+ break;
+ }
+ /* Convert previous '\0'. */
+ *np = ' ';
+ }
+ /* Note location of current '\0'. */
+ np = cp;
+ }
+ }
+ }
+
+ /*
+ * sp points to the beginning of the arguments/environment string, and
+ * np should point to the '\0' terminator for the string.
+ */
+ if (np == NULL || np == sp) {
+ /* Empty or unterminated string. */
+ goto ERROR_B;
+ }
+
+ /* Make a copy of the string. */
+ *argvlen = asprintf(command_name, "%s", sp);
+
+ /* Clean up. */
+ free(procargs);
+ return;
+
+ ERROR_B:
+ free(procargs);
+ ERROR_A:
+ *argv0len = *argvlen
+ = asprintf(command_name, "(%s)", KI_PROC(k)->p_comm);
+}
+
+/* Return value is malloc'ed, please free it */
+char *
+get_command_and_or_args(KINFO *k, int show_cmd, int show_args)
+{
+ char *vis_args;
+
+ char *rawcmd, *cmd;
+ int cmdlen, argv0len = 0;
+
+
+ if(!mflg || (print_all_thread && (print_thread_num== 0))) {
+ getproclline(k, &rawcmd, &cmdlen, &argv0len, show_args);
+
+ if (cflag) {
+ /* Ignore the path in cmd, if any. */
+ for (cmd = &rawcmd[cmdlen - 1]; cmd > rawcmd; cmd--) {
+ if (*cmd == '/') {
+ cmd++;
+ break;
+ }
+ }
+ } else {
+ cmd = rawcmd;
+ }
+
+ if (!show_cmd) {
+ cmd += argv0len;
+ if (*cmd) {
+ cmd++;
+ }
+ }
+
+ if ((vis_args = malloc(strlen(cmd) * 4 + 1)) == NULL)
+ err(1, NULL);
+ strvis(vis_args, cmd, VIS_TAB | VIS_NL | VIS_NOSLASH);
+ free(rawcmd);
+ return vis_args;
+ } else {
+ return strdup("");
+ }
+}
+
+int
+s_command_and_or_args(KINFO *k, int show_cmd, int show_args)
+{
+ char *s = get_command_and_or_args(k, show_cmd, show_args);
+ int sz = strlen(s);
+ free(s);
+
+ return sz;
+}
+
+void
+p_command_and_or_args(KINFO *k, VARENT *ve, int show_cmd, int show_args,
+ int no_trunc)
+{
+ VAR *v = ve->var;
+ char *s = get_command_and_or_args(k, show_cmd, show_args);
+
+ if (STAILQ_NEXT(ve, next_ve) == NULL) {
+ /* last field */
+ if (termwidth == UNLIMITED) {
+ fputs(s, stdout);
+ } else {
+ int left;
+ char *cp;
+
+ left = termwidth - (totwidth - v->width);
+ if (left < 1 || no_trunc) {
+ /* already wrapped, just use std * width */
+ left = v->width;
+ }
+ for(cp = s; --left >= 0 && *cp;) {
+ (void)putchar(*cp++);
+ }
+ }
+ } else {
+ /* XXX env? */
+ (void)printf("%-*.*s", v->width, v->width, s);
+ }
+
+ free(s);
+}
+
+int s_command(KINFO *k) {
+ return s_command_and_or_args(k, 1, !cflag);
+}
+
+int s_args(KINFO *k) {
+ return s_command_and_or_args(k, 1, 1);
+}
+
+int s_just_command(KINFO *k) {
+ return s_command_and_or_args(k, 1, 0);
+}
+
+void command(KINFO *k, VARENT *ve) {
+ p_command_and_or_args(k, ve, 1, !cflag, 0);
+}
+
+void args(KINFO *k, VARENT *ve) {
+ p_command_and_or_args(k, ve, 1, 1, 1);
+}
+
+void just_command(KINFO *k, VARENT *ve) {
+ p_command_and_or_args(k, ve, 1, 0, 0);
+}
+
+void
+ucomm(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ (void)printf("%-*s", v->width, KI_PROC(k)->p_comm);
+}
+
+char *getname(uid)
+ uid_t uid;
+{
+ register struct passwd *pw;
+ struct passwd *getpwuid();
+
+ pw = getpwuid((short)uid);
+ if (pw == NULL) {
+ return( "UNKNOWN" );
+ }
+ return( pw->pw_name );
+}
+
+void
+logname(KINFO *k, VARENT *ve)
+{
+ VAR *v;
+ char *s;
+
+ v = ve->var;
+ (void)printf("%-*s", v->width, (s = getname(KI_EPROC(k)->e_ucred.cr_uid), *s) ? s : "-");
+}
+
+extern int mach_state_order();
+void
+state(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ struct extern_proc *p;
+ int flag,j;
+ char *cp;
+ VAR *v;
+ char buf[16];
+ extern char mach_state_table[];
+
+ v = ve->var;
+ p = KI_PROC(k);
+ flag = p->p_flag;
+ cp = buf;
+
+ if(!mflg ) {
+ switch (p->p_stat) {
+
+ case SSTOP:
+ *cp = 'T';
+ break;
+
+ case SZOMB:
+ *cp = 'Z';
+ break;
+
+ default:
+ *cp = mach_state_table[k->state];
+ }
+ cp++;
+ if (p->p_nice < 0)
+ *cp++ = '<';
+ else if (p->p_nice > 0)
+ *cp++ = 'N';
+ if (flag & P_TRACED)
+ *cp++ = 'X';
+ if (flag & P_WEXIT && p->p_stat != SZOMB)
+ *cp++ = 'E';
+ if (flag & P_PPWAIT)
+ *cp++ = 'V';
+ if (flag & (P_SYSTEM | P_NOSWAP | P_PHYSIO))
+ *cp++ = 'L';
+ if (KI_EPROC(k)->e_flag & EPROC_SLEADER)
+ *cp++ = 's';
+ if ((flag & P_CONTROLT) && KI_EPROC(k)->e_pgid == KI_EPROC(k)->e_tpgid)
+ *cp++ = '+';
+ *cp = '\0';
+ (void)printf("%-*s", v->width, buf);
+ } else if (print_all_thread) {
+ j = mach_state_order(k->thval[print_thread_num].tb.run_state,
+ k->thval[print_thread_num].tb.sleep_time);
+ *cp++ = mach_state_table[j];
+ *cp++='\0';
+ (void)printf("%-*s", v->width, buf);
+ } else {
+ (void)printf("%-*s", v->width, " ");
+ }
+
+}
+
+void
+pri(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ int j=0;
+ char c = '?';
+
+ v = ve->var;
+ if (!mflg ) {
+ (void)printf("%*d", v->width, k->curpri);
+ } else if (print_all_thread) {
+ switch(k->thval[print_thread_num].tb.policy) {
+ case POLICY_TIMESHARE :
+ j = k->thval[print_thread_num].schedinfo.tshare.cur_priority;
+ c = 'T';
+ break;
+ case POLICY_FIFO :
+ j = k->thval[print_thread_num].schedinfo.fifo.base_priority;
+ c = 'F';
+ break;
+ case POLICY_RR :
+ j = k->thval[print_thread_num].schedinfo.rr.base_priority;
+ c = 'R';
+ break;
+ default :
+ j = 0;
+ }
+ (void)printf("%*d%c", v->width - 1, j, c);
+ }else {
+ j=0;
+ (void)printf("%*d", v->width, j);
+
+ }
+}
+
+void
+uname(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ if(!mflg || (print_all_thread && (print_thread_num== 0)))
+ (void)printf("%-*s",
+ (int)v->width,
+ user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0));
+ else
+ (void)printf("%-*s", (int)v->width, " ");
+}
+
+int
+s_uname(KINFO *k)
+{
+ return (strlen(user_from_uid(KI_EPROC(k)->e_ucred.cr_uid, 0)));
+}
+
+void
+runame(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ (void)printf("%-*s",
+ (int)v->width, user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0));
+}
+
+int
+s_runame(KINFO *k)
+{
+ return (strlen(user_from_uid(KI_EPROC(k)->e_pcred.p_ruid, 0)));
+}
+
+void
+tdev(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ dev_t dev;
+ char buff[16];
+
+ v = ve->var;
+ dev = KI_EPROC(k)->e_tdev;
+ if (dev == NODEV)
+ (void)printf("%*s", v->width, "??");
+ else {
+ (void)snprintf(buff, sizeof(buff),
+ "%d/%d", major(dev), minor(dev));
+ (void)printf("%*s", v->width, buff);
+ }
+}
+
+void
+tname(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ dev_t dev;
+ char *ttname;
+
+ v = ve->var;
+
+ if(!mflg || (print_all_thread && (print_thread_num== 0))) {
+ dev = KI_EPROC(k)->e_tdev;
+ if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
+ (void)printf("%*s ", v->width-1, "??");
+ else {
+ if (strncmp(ttname, "tty", 3) == 0 ||
+ strncmp(ttname, "cua", 3) == 0)
+ ttname += 3;
+ (void)printf("%*.*s%c", v->width-1, v->width-1, ttname,
+ KI_EPROC(k)->e_flag & EPROC_CTTY ? ' ' : '-');
+ }
+ }
+ else {
+ (void)printf("%*s ", v->width-1, " ");
+ }
+}
+
+void
+longtname(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ dev_t dev;
+ char *ttname;
+
+ v = ve->var;
+ dev = KI_EPROC(k)->e_tdev;
+ if (dev == NODEV || (ttname = devname(dev, S_IFCHR)) == NULL)
+ (void)printf("%-*s", v->width, "??");
+ else
+ (void)printf("%-*s", v->width, ttname);
+}
+
+void
+started(KINFO *k, VARENT *ve)
+{
+ VAR *v;
+ time_t then;
+ struct tm *tp;
+ static int use_ampm = -1;
+ char buf[100];
+
+ v = ve->var;
+ if (use_ampm < 0)
+ use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
+ then = KI_PROC(k)->p_starttime.tv_sec;
+ tp = localtime(&then);
+ if (now - KI_PROC(k)->p_starttime.tv_sec < 24 * 3600) {
+ (void)strftime(buf, sizeof(buf),
+ use_ampm ? "%l:%M%p" : "%k:%M ", tp);
+ } else if (now - KI_PROC(k)->p_starttime.tv_sec < 7 * 86400) {
+ (void)strftime(buf, sizeof(buf),
+ use_ampm ? "%a%I%p" : "%a%H ", tp);
+ } else
+ (void)strftime(buf, sizeof(buf), "%e%b%y", tp);
+ (void)printf("%-*s", v->width, buf);
+}
+
+void
+lstarted(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ time_t then;
+ char buf[100];
+
+ v = ve->var;
+ then = KI_PROC(k)->p_starttime.tv_sec;
+ (void)strftime(buf, sizeof(buf) -1, "%c", localtime(&then));
+ (void)printf("%-*s", v->width, buf);
+}
+
+char *get_etime(KINFO *k) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ long e = tv.tv_sec - KI_PROC(k)->p_starttime.tv_sec;
+
+ char *ret;
+
+ if (e > 100*60*60*24) {
+ asprintf(&ret, "%ld-%02ld:%02ld:%02ld",
+ e / (60*60*24),
+ (e / (60*60)) % 24,
+ (e / 60) % 60,
+ e % 60);
+ } else if (e > 60*60*24) {
+ asprintf(&ret, "%02ld-%02ld:%02ld:%02ld",
+ e / (60*60*24),
+ (e / (60*60)) % 24,
+ (e / 60) % 60,
+ e % 60);
+ } else if (e > 60*60) {
+ asprintf(&ret, "%02ld:%02ld:%02ld",
+ (e / (60*60)),
+ (e / 60) % 60,
+ e % 60);
+ } else {
+ asprintf(&ret, "%02ld:%02ld",
+ (e / 60),
+ e % 60);
+ }
+
+ return ret;
+}
+
+void p_etime(KINFO *k, VARENT *ve) {
+ char *str = get_etime(k);
+ printf("%*s", ve->var->width, str);
+ free(str);
+}
+
+int s_etime(KINFO *k) {
+ char *str = get_etime(k);
+ int sz = strlen(str);
+ free(str);
+ return sz;
+}
+
+void
+wchan(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ if (KI_PROC(k)->p_wchan) {
+ if (KI_PROC(k)->p_wmesg)
+ (void)printf("%-*.*s", v->width, v->width,
+ KI_EPROC(k)->e_wmesg);
+ else
+#if FIXME
+ (void)printf("%-*lx", v->width,
+ (long)KI_PROC(k)->p_wchan &~ KERNBASE);
+#else /* FIXME */
+ (void)printf("%-*lx", v->width,
+ (long)KI_PROC(k)->p_wchan);
+#endif /* FIXME */
+ } else
+ (void)printf("%-*s", v->width, "-");
+}
+
+#define pgtok(a) (((a)*getpagesize())/1024)
+
+void
+vsize(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+#if FIXME
+ (void)printf("%*d", v->width,
+ (KI_EPROC(k)->e_vm.vm_map.size/1024));
+#else /* FIXME */
+ (void)printf("%*lu", v->width,
+ (u_long)((k)->tasks_info.virtual_size)/1024);
+#endif /* FIXME */
+}
+
+void
+p_rssize(k, ve) /* doesn't account for text */
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+/* FIXME LATER */
+ v = ve->var;
+ /* (void)printf("%*ld", v->width, "-"); */
+ (void)printf("%*lu", v->width,
+ (u_long)((k)->tasks_info.resident_size)/1024);
+}
+
+void
+cputime(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ long secs;
+ long psecs; /* "parts" of a second. first micro, then centi */
+ char obuff[128];
+ time_value_t total_time, system_time;
+ v = ve->var;
+#if FIXME
+ if (KI_PROC(k)->p_stat == SZOMB || !k->ki_u.u_valid) {
+ secs = 0;
+ psecs = 0;
+ } else {
+ /*
+ * This counts time spent handling interrupts. We could
+ * fix this, but it is not 100% trivial (and interrupt
+ * time fractions only work on the sparc anyway). XXX
+ */
+#if FIXME
+ secs = KI_PROC(k)->p_runtime / 1000000;
+ psecs = KI_PROC(k)->p_runtime % 1000000;
+#endif /* FIXME */
+ if (sumrusage) {
+ secs += k->ki_u.u_cru.ru_utime.tv_sec +
+ k->ki_u.u_cru.ru_stime.tv_sec;
+ psecs += k->ki_u.u_cru.ru_utime.tv_usec +
+ k->ki_u.u_cru.ru_stime.tv_usec;
+ }
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+ }
+#else /* FIXME */
+ total_time = k->tasks_info.user_time;
+ system_time = k->tasks_info.system_time;
+
+ time_value_add(&total_time, &k->times.user_time);
+ time_value_add(&system_time, &k->times.system_time);
+ time_value_add(&total_time, &system_time);
+
+ secs = total_time.seconds;
+ psecs = total_time.microseconds;
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+#endif /* FIXME */
+ (void)snprintf(obuff, sizeof(obuff),
+ "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
+ (void)printf("%*s", v->width, obuff);
+}
+
+void
+putime(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ long secs;
+ long psecs; /* "parts" of a second. first micro, then centi */
+ char obuff[128];
+ time_value_t user_time;
+
+
+ v = ve->var;
+ if (!mflg) {
+ user_time = k->tasks_info.user_time;
+ time_value_add(&user_time, &k->times.user_time);
+ } else if (print_all_thread) {
+ user_time = k->thval[print_thread_num].tb.user_time;
+ } else {
+ user_time.seconds =0;
+ user_time.microseconds =0;
+ }
+
+ secs = user_time.seconds;
+ psecs = user_time.microseconds;
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+
+ (void)snprintf(obuff, sizeof(obuff),
+ "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
+ (void)printf("%*s", v->width, obuff);
+}
+
+void
+pstime(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ long secs;
+ long psecs; /* "parts" of a second. first micro, then centi */
+ char obuff[128];
+ time_value_t system_time;
+
+ v = ve->var;
+ if (!mflg) {
+ system_time = k->tasks_info.system_time;
+ time_value_add(&system_time, &k->times.system_time);
+ } else if (print_all_thread) {
+ system_time = k->thval[print_thread_num].tb.system_time;
+ } else {
+ system_time.seconds =0;
+ system_time.microseconds =0;
+ }
+ secs = system_time.seconds;
+ psecs = system_time.microseconds;
+ /*
+ * round and scale to 100's
+ */
+ psecs = (psecs + 5000) / 10000;
+ secs += psecs / 100;
+ psecs = psecs % 100;
+
+ (void)snprintf(obuff, sizeof(obuff),
+ "%3ld:%02ld.%02ld", secs/60, secs%60, psecs);
+ (void)printf("%*s", v->width, obuff);
+
+}
+
+int
+getpcpu(k)
+ KINFO *k;
+{
+#if FIXME
+ struct proc *p;
+ static int failure;
+
+ if (!nlistread)
+ failure = donlist();
+ if (failure)
+ return (0.0);
+ p = KI_PROC(k);
+#define fxtofl(fixpt) ((double)(fixpt) / fscale)
+
+ /* XXX - I don't like this */
+ if (p->p_swtime == 0 || (p->p_flag & P_INMEM) == 0)
+ return (0.0);
+ if (rawcpu)
+ return (100.0 * fxtofl(p->p_pctcpu));
+ return (100.0 * fxtofl(p->p_pctcpu) /
+ (1.0 - exp(p->p_swtime * log(fxtofl(ccpu)))));
+#else
+ return (k->cpu_usage);
+#endif /* FIXME */
+}
+
+#ifndef TH_USAGE_SCALE
+#define TH_USAGE_SCALE 1000
+#endif /* !TH_USAGE_SCALE */
+
+void
+pcpu(KINFO *k, VARENT *ve)
+{
+ VAR *v;
+ int cp;
+
+ if (!mflg) {
+ cp = getpcpu(k);
+ } else if (print_all_thread) {
+ cp = k->thval[print_thread_num].tb.cpu_usage;
+ } else {
+ cp = 0;
+ }
+
+ v = ve->var;
+ (void)printf("%*.1f", v->width, ((double)cp) * 100.0 / ((double)TH_USAGE_SCALE));
+}
+
+double
+getpmem(k)
+ KINFO *k;
+{
+ static int failure;
+ double fracmem;
+
+ if (!nlistread)
+ failure = donlist();
+ if (failure)
+ return (0.0);
+#if FIXME
+ p = KI_PROC(k);
+ e = KI_EPROC(k);
+ if ((p->p_flag & P_INMEM) == 0)
+ return (0.0);
+ /* XXX want pmap ptpages, segtab, etc. (per architecture) */
+ szptudot = UPAGES;
+ /* XXX don't have info about shared */
+ fracmem = ((float)e->e_vm.vm_rssize + szptudot)/mempages;
+ return (100.0 * fracmem);
+#else /* FIXME */
+ fracmem = ((float)k->tasks_info.resident_size)/(double)mempages;
+ return (100.0 * fracmem);
+#endif /* FIXME */
+}
+
+void
+pmem(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ (void)printf("%*.1f", v->width, getpmem(k));
+}
+
+void
+pagein(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ (void)printf("%*ld", v->width,
+ k->ki_u.u_valid ? k->ki_u.u_ru.ru_majflt : 0);
+}
+
+void
+maxrss(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ /* XXX not yet */
+ (void)printf("%*s", v->width, "-");
+}
+
+void
+tsize(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+ int dummy=0;
+
+ v = ve->var;
+#if 0
+ (void)printf("%*ld", v->width, (long)pgtok(KI_EPROC(k)->e_vm.vm_tsize));
+#else
+ (void)printf("%*ld", v->width, (long)dummy);
+#endif
+}
+
+void
+rtprior(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+#if FIXME
+
+ VAR *v;
+ struct rtprio *prtp;
+ char str[8];
+ unsigned prio, type;
+
+ v = ve->var;
+ prtp = (struct rtprio *) ((char *)KI_PROC(k) + v->off);
+ prio = prtp->prio;
+ type = prtp->type;
+ switch (type) {
+ case RTP_PRIO_REALTIME:
+ snprintf(str, sizeof(str), "real:%u", prio);
+ break;
+ case RTP_PRIO_NORMAL:
+ strncpy(str, "normal", sizeof(str));
+ break;
+ case RTP_PRIO_IDLE:
+ snprintf(str, sizeof(str), "idle:%u", prio);
+ break;
+ default:
+ snprintf(str, sizeof(str), "%u:%u", type, prio);
+ break;
+ }
+ str[sizeof(str) - 1] = '\0';
+ (void)printf("%*s", v->width, str);
+#endif /* FIXME */
+}
+
+/*
+ * Generic output routines. Print fields from various prototype
+ * structures.
+ */
+static void
+printval(void *bp, VAR *v)
+{
+ static char ofmt[32] = "%";
+ const char *fcp;
+ char *cp;
+
+ cp = ofmt + 1;
+ fcp = v->fmt;
+ if (v->flag & LJUST)
+ *cp++ = '-';
+ *cp++ = '*';
+ while ((*cp++ = *fcp++));
+
+ switch (v->type) {
+ case CHAR:
+ (void)printf(ofmt, v->width, *(char *)bp);
+ break;
+ case UCHAR:
+ (void)printf(ofmt, v->width, *(u_char *)bp);
+ break;
+ case SHORT:
+ (void)printf(ofmt, v->width, *(short *)bp);
+ break;
+ case USHORT:
+ (void)printf(ofmt, v->width, *(u_short *)bp);
+ break;
+ case INT:
+ (void)printf(ofmt, v->width, *(int *)bp);
+ break;
+ case UINT:
+ (void)printf(ofmt, v->width, *(u_int *)bp);
+ break;
+ case LONG:
+ (void)printf(ofmt, v->width, *(long *)bp);
+ break;
+ case ULONG:
+ (void)printf(ofmt, v->width, *(u_long *)bp);
+ break;
+ case KPTR:
+#if FIXME
+ (void)printf(ofmt, v->width, *(u_long *)bp &~ KERNBASE);
+#else /* FIXME */
+ (void)printf(ofmt, v->width, *(u_long *)bp);
+#endif /* FIXME */
+ break;
+ default:
+ errx(1, "unknown type %d", v->type);
+ }
+}
+
+void
+pvar(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ printval((char *)((char *)KI_PROC(k) + v->off), v);
+}
+
+void
+evar(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ printval((char *)((char *)KI_EPROC(k) + v->off), v);
+}
+
+void
+uvar(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ if (k->ki_u.u_valid)
+ printval((char *)((char *)&k->ki_u + v->off), v);
+ else
+ (void)printf("%*s", v->width, "-");
+}
+
+void
+rvar(k, ve)
+ KINFO *k;
+ VARENT *ve;
+{
+ VAR *v;
+
+ v = ve->var;
+ if (k->ki_u.u_valid)
+ printval((char *)((char *)(&k->ki_u.u_ru) + v->off), v);
+ else
+ (void)printf("%*s", v->width, "-");
+}
+
+void
+wq(KINFO *k, VARENT *ve)
+{
+ VAR *v;
+ struct proc_workqueueinfo wqinfo;
+ int len;
+ int ret;
+ uint32_t nthreads;
+
+ len = sizeof(wqinfo);
+ ret = proc_pidinfo(KI_PROC(k)->p_pid, PROC_PIDWORKQUEUEINFO, 0, &wqinfo, len);
+
+ v = ve->var;
+
+ if (len == ret && len == PROC_PIDWORKQUEUEINFO_SIZE) {
+ if (strcmp(v->name, "wql") == 0) {
+ char *s;
+ switch (wqinfo.pwq_state & (WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT | WQ_EXCEEDED_TOTAL_THREAD_LIMIT)) {
+ case 0:
+ s = "-";
+ break;
+ case WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT:
+ s = "C";
+ break;
+ case WQ_EXCEEDED_TOTAL_THREAD_LIMIT:
+ s = "T";
+ break;
+ default:
+ s = "CT";
+ break;
+ }
+ printf("%*s", v->width, s);
+ return;
+ }
+ if (strcmp(v->name, "wqr") == 0)
+ nthreads = wqinfo.pwq_runthreads;
+ else if (strcmp(v->name, "wqb") == 0)
+ nthreads = wqinfo.pwq_blockedthreads;
+ else
+ nthreads = wqinfo.pwq_nthreads;
+ printf("%*d", v->width, nthreads);
+ } else
+ printf("%*s", v->width, "-");
+}
diff --git a/adv_cmds/ps/ps.1 b/adv_cmds/ps/ps.1
new file mode 100644
index 0000000..20eed1c
--- /dev/null
+++ b/adv_cmds/ps/ps.1
@@ -0,0 +1,663 @@
+.\"-
+.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
+.\" $FreeBSD: src/bin/ps/ps.1,v 1.86 2005/04/29 11:10:27 maxim Exp $
+.\"
+.Dd March 20, 2005
+.Dt PS 1
+.Os
+.Sh NAME
+.Nm ps
+.Nd process status
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaCcEefhjlMmrSTvwXx
+.Op Fl O Ar fmt | Fl o Ar fmt
+.Op Fl G Ar gid Ns Op , Ns Ar gid Ns Ar ...
+.Op Fl g Ar grp Ns Op , Ns Ar grp Ns Ar ...
+.Op Fl u Ar uid Ns Op , Ns Ar uid Ns Ar ...
+.Op Fl p Ar pid Ns Op , Ns Ar pid Ns Ar ...
+.Op Fl t Ar tty Ns Op , Ns Ar tty Ns Ar ...
+.Op Fl U Ar user Ns Op , Ns Ar user Ns Ar ...
+.Nm
+.Op Fl L
+.Sh DESCRIPTION
+The
+.Nm
+utility
+displays a header line, followed by lines containing information about
+all of your
+processes that have controlling terminals.
+.Pp
+A different set of processes can be selected for display by using any
+combination of the
+.Fl a , G , g , p , T , t , U ,
+and
+.Fl u
+options.
+If more than one of these options are given, then
+.Nm
+will select all processes which are matched by at least one of the
+given options.
+.Pp
+For the processes which have been selected for display,
+.Nm
+will usually display one line per process.
+The
+.Fl M
+option may result in multiple output lines (one line per thread) for
+some processes.
+By default all of these output lines are sorted first by controlling
+terminal, then by process ID.
+The
+.Fl m , r ,
+and
+.Fl v
+options will change the sort order.
+If more than one sorting option was given, then the selected processes
+will be sorted by the last sorting option which was specified.
+.Pp
+For the processes which have been selected for display, the information
+to display is selected based on a set of keywords (see the
+.Fl L , O ,
+and
+.Fl o
+options).
+The default output format includes, for each process, the process' ID,
+controlling terminal, CPU time (including both user and system time),
+state, and associated command.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl A
+Display information about other users' processes,
+including those without controlling terminals.
+.It Fl a
+Display information about other users' processes as well as your own.
+This will skip any processes which do not have a controlling terminal,
+unless the
+.Fl x
+option is also specified.
+.It Fl C
+Change the way the CPU percentage is calculated by using a
+.Dq raw
+CPU calculation that ignores
+.Dq resident
+time (this normally has
+no effect).
+.It Fl c
+Change the
+.Dq command
+column output to just contain the executable name,
+rather than the full command line.
+.It Fl d
+Like
+.Fl A ,
+but excludes session leaders.
+.It Fl E
+Display the environment as well.
+This does not reflect changes in the environment after process launch.
+.It Fl e
+Identical to
+.Fl A .
+.It Fl f
+Display the uid, pid, parent pid, recent CPU usage, process start time,
+controlling tty, elapsed CPU usage, and the associated command.
+If the
+.Fl u
+option is also used, display the user name rather then the numeric uid.
+When
+.Fl o
+or
+.Fl O
+is used to add to the display following
+.Fl f ,
+the command field is not truncated as severely as it is in other formats.
+.It Fl G
+Display information about processes
+which are running with the specified real group IDs.
+.It Fl g
+Display information about processes with the specified
+process group leaders.
+.It Fl h
+Repeat the information header as often as necessary
+to guarantee one header per page of information.
+.It Fl j
+Print information associated with the following keywords:
+.Cm user , pid , ppid , pgid , sess , jobc , state , tt , time ,
+and
+.Cm command .
+.It Fl L
+List the set of keywords available for the
+.Fl O
+and
+.Fl o
+options.
+.It Fl l
+Display information associated with the following keywords:
+.Cm uid , pid , ppid , flags , cpu , pri , nice , vsz=SZ , rss ,
+.Cm wchan , state=S , paddr=ADDR , tty , time ,
+and
+.Cm command=CMD .
+.It Fl M
+Print the threads corresponding to each task.
+.It Fl m
+Sort by memory usage, instead of the combination of controlling
+terminal and process ID.
+.It Fl O
+Add the information associated with the space or comma separated list
+of keywords specified, after the process ID,
+in the default information
+display.
+Keywords may be appended with an equals
+.Pq Ql =
+sign and a string.
+This causes the printed header to use the specified string instead of
+the standard header.
+.It Fl o
+Display information associated with the space or comma separated
+list of keywords specified.
+Multiple keywords may also be given in the form of more than one
+.Fl o
+option.
+Keywords may be appended with an equals
+.Pq Ql =
+sign and a string.
+This causes the printed header to use the specified string instead of
+the standard header.
+If all keywords have empty header texts, no header line is written.
+.It Fl p
+Display information about processes which match the specified process IDs.
+.It Fl r
+Sort by current CPU usage, instead of the combination of controlling
+terminal and process ID.
+.It Fl S
+Change the way the process time is calculated by summing all exited
+children to their parent process.
+.It Fl T
+Display information about processes attached to the device associated
+with the standard input.
+.It Fl t
+Display information about processes attached to the specified terminal
+devices.
+.It Fl U
+Display the processes belonging to the specified real user IDs.
+.It Fl u
+Display the processes belonging to the specified usernames.
+.It Fl v
+Display information associated with the following keywords:
+.Cm pid , state , time , sl , re , pagein , vsz , rss , lim , tsiz ,
+.Cm %cpu , %mem ,
+and
+.Cm command .
+The
+.Fl v
+option implies the
+.Fl m
+option.
+.It Fl w
+Use 132 columns to display information, instead of the default which
+is your window size.
+If the
+.Fl w
+option is specified more than once,
+.Nm
+will use as many columns as necessary without regard for your window size.
+When output is not to a terminal, an unlimited number of columns are
+always used.
+.It Fl X
+When displaying processes matched by other options, skip any processes
+which do not have a controlling terminal.
+.It Fl x
+When displaying processes matched by other options, include processes
+which do not have a controlling terminal.
+This is the opposite of the
+.Fl X
+option.
+If both
+.Fl X
+and
+.Fl x
+are specified in the same command, then
+.Nm
+will use the one which was specified last.
+.El
+.Pp
+A complete list of the available keywords is given below.
+Some of these keywords are further specified as follows:
+.Bl -tag -width lockname
+.It Cm %cpu
+The CPU utilization of the process;
+this is a decaying average over up to a minute of previous (real) time.
+Because the time base over which this is computed varies
+(some processes may be very young),
+it is possible for the sum of all
+.Cm %cpu
+fields to exceed 100%.
+.It Cm %mem
+The percentage of real memory used by this process.
+.It Cm flags
+The flags associated with the process as in
+the include file
+.In sys/proc.h :
+.Bl -column P_STOPPED_SINGLE 0x4000000
+.It Dv "P_ADVLOCK" Ta No "0x00001 Process may hold a POSIX advisory lock"
+.It Dv "P_CONTROLT" Ta No "0x00002 Has a controlling terminal"
+.It Dv "P_LP64" Ta No "0x00004 Process is LP64"
+.It Dv "P_NOCLDSTOP" Ta No "0x00008 No SIGCHLD when children stop"
+.It Dv "P_PPWAIT" Ta No "0x00010 Parent is waiting for child to exec/exit"
+.It Dv "P_PROFIL" Ta No "0x00020 Has started profiling"
+.It Dv "P_SELECT" Ta No "0x00040 Selecting; wakeup/waiting danger"
+.It Dv "P_CONTINUED" Ta No "0x00080 Process was stopped and continued"
+.It Dv "P_SUGID" Ta No "0x00100 Had set id privileges since last exec"
+.It Dv "P_SYSTEM" Ta No "0x00200 System proc: no sigs, stats or swapping"
+.It Dv "P_TIMEOUT" Ta No "0x00400 Timing out during sleep"
+.It Dv "P_TRACED" Ta No "0x00800 Debugged process being traced"
+.It Dv "P_WAITED" Ta No "0x01000 Debugging process has waited for child"
+.It Dv "P_WEXIT" Ta No "0x02000 Working on exiting"
+.It Dv "P_EXEC" Ta No "0x04000 Process called exec"
+.It Dv "P_OWEUPC" Ta No "0x08000 Owe process an addupc() call at next ast"
+.It Dv "P_WAITING" Ta No "0x40000 Process has a wait() in progress"
+.It Dv "P_KDEBUG" Ta No "0x80000 Kdebug tracing on for this process"
+.El
+.It Cm lim
+The soft limit on memory used, specified via a call to
+.Xr setrlimit 2 .
+.It Cm lstart
+The exact time the command started, using the
+.Ql %c
+format described in
+.Xr strftime 3 .
+.It Cm nice
+The process scheduling increment (see
+.Xr setpriority 2 ) .
+.It Cm rss
+the real memory (resident set) size of the process (in 1024 byte units).
+.It Cm start
+The time the command started.
+If the command started less than 24 hours ago, the start time is
+displayed using the
+.Dq Li %l:ps.1p
+format described in
+.Xr strftime 3 .
+If the command started less than 7 days ago, the start time is
+displayed using the
+.Dq Li %a6.15p
+format.
+Otherwise, the start time is displayed using the
+.Dq Li %e%b%y
+format.
+.It Cm state
+The state is given by a sequence of characters, for example,
+.Dq Li RWNA .
+The first character indicates the run state of the process:
+.Pp
+.Bl -tag -width indent -compact
+.It Li I
+Marks a process that is idle (sleeping for longer than about 20 seconds).
+.It Li R
+Marks a runnable process.
+.It Li S
+Marks a process that is sleeping for less than about 20 seconds.
+.It Li T
+Marks a stopped process.
+.It Li U
+Marks a process in uninterruptible wait.
+.It Li Z
+Marks a dead process (a
+.Dq zombie ) .
+.El
+.Pp
+Additional characters after these, if any, indicate additional state
+information:
+.Pp
+.Bl -tag -width indent -compact
+.It Li +
+The process is in the foreground process group of its control terminal.
+.It Li <
+The process has raised CPU scheduling priority.
+.It Li >
+The process has specified a soft limit on memory requirements and is
+currently exceeding that limit; such a process is (necessarily) not
+swapped.
+.It Li A
+the process has asked for random page replacement
+.Pf ( Dv VA_ANOM ,
+from
+.Xr vadvise 2 ,
+for example,
+.Xr lisp 1
+in a garbage collect).
+.It Li E
+The process is trying to exit.
+.It Li L
+The process has pages locked in core (for example, for raw
+.Tn I/O ) .
+.It Li N
+The process has reduced CPU scheduling priority (see
+.Xr setpriority 2 ) .
+.It Li S
+The process has asked for
+.Tn FIFO
+page replacement
+.Pf ( Dv VA_SEQL ,
+from
+.Xr vadvise 2 ,
+for example, a large image processing program using virtual memory to
+sequentially address voluminous data).
+.It Li s
+The process is a session leader.
+.It Li V
+The process is suspended during a
+.Xr vfork 2 .
+.It Li W
+The process is swapped out.
+.It Li X
+The process is being traced or debugged.
+.El
+.It Cm tt
+An abbreviation for the pathname of the controlling terminal, if any.
+The abbreviation consists of the three letters following
+.Pa /dev/tty ,
+or, for the console,
+.Dq Li con .
+This is followed by a
+.Ql -
+if the process can no longer reach that
+controlling terminal (i.e., it has been revoked).
+.It Cm wchan
+The event (an address in the system) on which a process waits.
+When printed numerically, the initial part of the address is
+trimmed off and the result is printed in hex, for example, 0x80324000 prints
+as 324000.
+.El
+.Pp
+When printing using the command keyword, a process that has exited and
+has a parent that has not yet waited for the process (in other words, a zombie)
+is listed as
+.Dq Li <defunct> ,
+and a process which is blocked while trying
+to exit is listed as
+.Dq Li <exiting> .
+If the arguments cannot be located (usually because it has not been set, as is
+the case of system processes and/or kernel threads) the command name is printed
+within square brackets.
+The process can change the arguments shown with
+.Xr setproctitle 3 .
+Otherwise,
+.Nm
+makes an educated guess as to the file name and arguments given when the
+process was created by examining memory or the swap area.
+The method is inherently somewhat unreliable and in any event a process
+is entitled to destroy this information.
+The ucomm (accounting) keyword can, however, be depended on.
+If the arguments are unavailable or do not agree with the ucomm keyword,
+the value for the ucomm keyword is appended to the arguments in parentheses.
+.Sh KEYWORDS
+The following is a complete list of the available keywords and their
+meanings.
+Several of them have aliases (keywords which are synonyms).
+.Pp
+.Bl -tag -width ".Cm sigignore" -compact
+.It Cm %cpu
+percentage CPU usage (alias
+.Cm pcpu )
+.It Cm %mem
+percentage memory usage (alias
+.Cm pmem )
+.It Cm acflag
+accounting flag (alias
+.Cm acflg )
+.It Cm args
+command and arguments
+.It Cm comm
+command
+.It Cm command
+command and arguments
+.It Cm cpu
+short-term CPU usage factor (for scheduling)
+.It Cm etime
+elapsed running time
+.It Cm flags
+the process flags, in hexadecimal (alias
+.Cm f )
+.It Cm gid
+processes group id (alias
+.Cm group )
+.It Cm inblk
+total blocks read (alias
+.Cm inblock )
+.It Cm jobc
+job control count
+.It Cm ktrace
+tracing flags
+.It Cm ktracep
+tracing vnode
+.It Cm lim
+memoryuse limit
+.It Cm logname
+login name of user who started the session
+.It Cm lstart
+time started
+.It Cm majflt
+total page faults
+.It Cm minflt
+total page reclaims
+.It Cm msgrcv
+total messages received (reads from pipes/sockets)
+.It Cm msgsnd
+total messages sent (writes on pipes/sockets)
+.It Cm nice
+nice value (alias
+.Cm ni )
+.It Cm nivcsw
+total involuntary context switches
+.It Cm nsigs
+total signals taken (alias
+.Cm nsignals )
+.It Cm nswap
+total swaps in/out
+.It Cm nvcsw
+total voluntary context switches
+.It Cm nwchan
+wait channel (as an address)
+.It Cm oublk
+total blocks written (alias
+.Cm oublock )
+.It Cm p_ru
+resource usage (valid only for zombie)
+.It Cm paddr
+swap address
+.It Cm pagein
+pageins (same as majflt)
+.It Cm pgid
+process group number
+.It Cm pid
+process ID
+.It Cm ppid
+parent process ID
+.It Cm pri
+scheduling priority
+.It Cm re
+core residency time (in seconds; 127 = infinity)
+.It Cm rgid
+real group ID
+.It Cm rss
+resident set size
+.It Cm ruid
+real user ID
+.It Cm ruser
+user name (from ruid)
+.It Cm sess
+session ID
+.It Cm sig
+pending signals (alias
+.Cm pending )
+.It Cm sigmask
+blocked signals (alias
+.Cm blocked )
+.It Cm sl
+sleep time (in seconds; 127 = infinity)
+.It Cm start
+time started
+.It Cm state
+symbolic process state (alias
+.Cm stat )
+.It Cm svgid
+saved gid from a setgid executable
+.It Cm svuid
+saved UID from a setuid executable
+.It Cm tdev
+control terminal device number
+.It Cm time
+accumulated CPU time, user + system (alias
+.Cm cputime )
+.It Cm tpgid
+control terminal process group ID
+.\".It Cm trss
+.\"text resident set size (in Kbytes)
+.It Cm tsess
+control terminal session ID
+.It Cm tsiz
+text size (in Kbytes)
+.It Cm tt
+control terminal name (two letter abbreviation)
+.It Cm tty
+full name of control terminal
+.It Cm ucomm
+name to be used for accounting
+.It Cm uid
+effective user ID
+.It Cm upr
+scheduling priority on return from system call (alias
+.Cm usrpri )
+.It Cm user
+user name (from UID)
+.It Cm utime
+user CPU time (alias
+.Cm putime )
+.It Cm vsz
+virtual size in Kbytes (alias
+.Cm vsize )
+.It Cm wchan
+wait channel (as a symbolic name)
+.It Cm wq
+total number of workqueue threads
+.It Cm wqb
+number of blocked workqueue threads
+.It Cm wqr
+number of running workqueue threads
+.It Cm wql
+workqueue limit status (C = constrained thread limit, T = total thread limit)
+.It Cm xstat
+exit or stop status (valid only for stopped or zombie process)
+.El
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width ".Ev COLUMNS"
+.It Ev COLUMNS
+If set, specifies the user's preferred output width in column positions.
+By default,
+.Nm
+attempts to automatically determine the terminal width.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /boot/kernel/kernel" -compact
+.It Pa /dev
+special files and device names
+.It Pa /var/run/dev.db
+/dev name database
+.It Pa /var/db/kvm_kernel.db
+system namelist database
+.El
+.Sh LEGACY DESCRIPTION
+In legacy mode,
+.Nm
+functions as described above, with the following differences:
+.Bl -tag -width indent
+.It Fl e
+Display the environment as well. Same as
+.Fl E .
+.It Fl g
+Ignored for compatibility. Takes no argument.
+.It Fl l
+Display information associated with the following keywords:
+.Cm uid , pid , ppid , cpu , pri , nice , vsz , rss , wchan , state ,
+.Cm tt, time ,
+and
+.Cm command .
+.It Fl u
+Display information associated with the following keywords:
+.Cm user , pid , %cpu , %mem , vsz , rss , tt , state , start , time ,
+and
+.Cm command .
+The
+.Fl u
+option implies the
+.Fl r
+option.
+.El
+.Pp
+The biggest change is in the interpretation of the
+.Fl u
+option,
+which now displays processes belonging to the specified username(s).
+Thus, "ps -aux" will fail (unless you want to know about user "x").
+As a convenience, however, "ps aux" still works as it did in Tiger.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr w 1 ,
+.Xr kvm 3 ,
+.Xr strftime 3 ,
+.Xr sysctl 8
+.Sh STANDARDS
+The
+.Nm
+utility supports the
+.St -susv3
+standard.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.At v4 .
+.Sh BUGS
+Since
+.Nm
+cannot run faster than the system and is run as any other scheduled
+process, the information it displays can never be exact.
+.Pp
+The
+.Nm
+utility does not correctly display argument lists containing multibyte
+characters.
diff --git a/adv_cmds/ps/ps.c b/adv_cmds/ps/ps.c
new file mode 100644
index 0000000..72c0242
--- /dev/null
+++ b/adv_cmds/ps/ps.c
@@ -0,0 +1,1373 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ------+---------+---------+-------- + --------+---------+---------+---------*
+ * Copyright (c) 2004 - Garance Alistair Drosehn <gad@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Significant modifications made to bring `ps' options somewhat closer
+ * to the standard for `ps' as described in SingleUnixSpec-v3.
+ * ------+---------+---------+-------- + --------+---------+---------+---------*
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)ps.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ps/ps.c,v 1.110 2005/02/09 17:37:38 ru Exp $");
+
+#include <sys/param.h>
+#ifdef __APPLE__
+#include <sys/time.h>
+#endif /* __APPLE__ */
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/mount.h>
+#include <sys/resourcevar.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#ifndef __APPLE__
+#include <kvm.h>
+#endif /* !__APPLE__ */
+#include <limits.h>
+#include <locale.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ps.h"
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else /* !__APPLE__ */
+#define COMPAT_MODE(func, mode) (1)
+#endif /* __APPLE__ */
+
+#define W_SEP " \t" /* "Whitespace" list separators */
+#define T_SEP "," /* "Terminate-element" list separators */
+
+#ifdef LAZY_PS
+#define DEF_UREAD 0
+#define OPT_LAZY_f "f"
+#else
+#define DEF_UREAD 1 /* Always do the more-expensive read. */
+#define OPT_LAZY_f /* I.e., the `-f' option is not added. */
+#endif
+
+/*
+ * isdigit takes an `int', but expects values in the range of unsigned char.
+ * This wrapper ensures that values from a 'char' end up in the correct range.
+ */
+#define isdigitch(Anychar) isdigit((u_char)(Anychar))
+
+int cflag; /* -c */
+int eval; /* Exit value */
+time_t now; /* Current time(3) value */
+int rawcpu; /* -C */
+int sumrusage; /* -S */
+int termwidth; /* Width of the screen (0 == infinity). */
+int totwidth; /* Calculated-width of requested variables. */
+
+struct velisthead varlist = STAILQ_HEAD_INITIALIZER(varlist);
+
+#ifndef __APPLE__
+static int forceuread = DEF_UREAD; /* Do extra work to get u-area. */
+static kvm_t *kd;
+#endif /* !__APPLE__ */
+static KINFO *kinfo;
+static int needcomm; /* -o "command" */
+static int needenv; /* -e */
+static int needuser; /* -o "user" */
+static int optfatal; /* Fatal error parsing some list-option. */
+
+static enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
+
+struct listinfo;
+typedef int addelem_rtn(struct listinfo *_inf, const char *_elem);
+
+struct listinfo {
+ int count;
+ int maxcount;
+ int elemsize;
+ addelem_rtn *addelem;
+ const char *lname;
+ union {
+ gid_t *gids;
+ pid_t *pids;
+ dev_t *ttys;
+ uid_t *uids;
+ void *ptr;
+ } l;
+};
+
+#ifndef __APPLE__
+static int check_procfs(void);
+#endif /* !__APPLE__ */
+static int addelem_gid(struct listinfo *, const char *);
+static int addelem_pid(struct listinfo *, const char *);
+static int addelem_tty(struct listinfo *, const char *);
+static int addelem_uid(struct listinfo *, const char *);
+static void add_list(struct listinfo *, const char *);
+static void dynsizevars(KINFO *);
+static void *expand_list(struct listinfo *);
+#ifndef __APPLE__
+static const char *
+ fmt(char **(*)(kvm_t *, const struct kinfo_proc *, int),
+ KINFO *, char *, int);
+#endif /* !__APPLE__ */
+static void free_list(struct listinfo *);
+static void init_list(struct listinfo *, addelem_rtn, int, const char *);
+static char *kludge_oldps_options(const char *, char *, const char *, int *);
+static int pscomp(const void *, const void *);
+static void saveuser(KINFO *);
+static void scanvars(void);
+static void sizevars(void);
+static void usage(int);
+
+/* 5842004: Fix -f option. */
+VAR *findvar(char *, int, char **);
+
+/* p_ == POSIX/SUSv3/UNIX2003 format */
+static char dfmt[] = "pid,tt,state,time,command";
+static char jfmt[] = "user,pid,ppid,pgid,sess,jobc,state,tt,time,command";
+static char lfmt[] = "uid,pid,ppid,cpu,pri,nice,vsz,rss,wchan,state,"
+ "tt,time,command";
+static char o1[] = "pid";
+static char o2[] = "tt,state,time,command";
+static char ufmt[] = "user,pid,%cpu,%mem,vsz,rss,tt,state,start,time,command";
+static char vfmt[] = "pid,state,time,sl,re,pagein,vsz,rss,lim,tsiz,"
+ "%cpu,%mem,command";
+#ifndef __APPLE__
+static char Zfmt[] = "label";
+#endif /* !__APPLE__ */
+char p_dfmt[] = "pid tty time command=CMD";
+char p_ffmt[] = "uid pid ppid cpu=C start=STIME tty time command=CMD";
+char p_uffmt[] = "user pid ppid cpu=C start=STIME tty time command=CMD";
+char p_lfmt[] = "uid pid ppid flags cpu pri nice vsz=SZ rss wchan state=S paddr=ADDR tty time command=CMD";
+char mfmt[] = "user pid tt %cpu state pri stime utime command";
+
+int eflg = 0;
+int mflg = 0; /* if -M option to display all mach threads */
+int print_thread_num = 0;
+int print_all_thread = 0;
+
+#define PS_ARGS (u03 ? "aACcdeEfg:G:hjLlMmO:o:p:rSTt:U:u:vwx" : \
+ "aACcdeEgG:hjLlMmO:o:p:rSTt:U:uvwx")
+
+int
+main(int argc, char *argv[])
+{
+ struct listinfo gidlist, pgrplist, pidlist;
+ struct listinfo ruidlist, sesslist, ttylist, uidlist;
+ struct kinfo_proc *kp;
+ KINFO *next_KINFO;
+ struct varent *vent;
+ struct winsize ws;
+#ifndef __APPLE__
+ const char *nlistf, *memf;
+#endif /* !__APPLE__ */
+ char *cols;
+ int all, ch, elem, flag, _fmt, i, lineno;
+ int nentries, nkept, nselectors;
+ int prtheader, showthreads, wflag, what, xkeep, xkeep_implied;
+#ifndef __APPLE__
+ char errbuf[_POSIX2_LINE_MAX];
+#endif /* !__APPLE__ */
+ struct kinfo_proc *kprocbuf;
+ int j;
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+ size_t bufSize = 0;
+ size_t orig_bufSize = 0;
+ int local_error=0;
+ int retry_count = 0;
+ int u03 = COMPAT_MODE("bin/ps", "unix2003");
+#ifdef __APPLE__
+ int dflag = 0;
+#endif /* __APPLE__ */
+
+ (void) setlocale(LC_ALL, "");
+ time(&now); /* Used by routines in print.c. */
+
+ if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0')
+ termwidth = atoi(cols);
+ else if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
+ ioctl(STDERR_FILENO, TIOCGWINSZ, (char *)&ws) == -1 &&
+ ioctl(STDIN_FILENO, TIOCGWINSZ, (char *)&ws) == -1) ||
+ ws.ws_col == 0)
+ termwidth = 79;
+ else
+ termwidth = ws.ws_col - 1;
+
+ /*
+ * Hide a number of option-processing kludges in a separate routine,
+ * to support some historical BSD behaviors, such as `ps axu'.
+ */
+ if (argc > 1)
+ argv[1] = kludge_oldps_options(PS_ARGS, argv[1], argv[2], &u03);
+
+ all = _fmt = nselectors = optfatal = 0;
+ prtheader = showthreads = wflag = xkeep_implied = 0;
+ xkeep = -1; /* Neither -x nor -X. */
+ init_list(&gidlist, addelem_gid, sizeof(gid_t), "group");
+ init_list(&pgrplist, addelem_pid, sizeof(pid_t), "process group");
+ init_list(&pidlist, addelem_pid, sizeof(pid_t), "process id");
+ init_list(&ruidlist, addelem_uid, sizeof(uid_t), "ruser");
+ init_list(&sesslist, addelem_pid, sizeof(pid_t), "session id");
+ init_list(&ttylist, addelem_tty, sizeof(dev_t), "tty");
+ init_list(&uidlist, addelem_uid, sizeof(uid_t), "user");
+#ifndef __APPLE__
+ memf = nlistf = _PATH_DEVNULL;
+#endif /* !__APPLE__ */
+ while ((ch = getopt(argc, argv, PS_ARGS)) != -1)
+ switch ((char)ch) {
+#ifdef __APPLE__
+ case 'd':
+ dflag = 1;
+#endif /* __APPLE__ */
+ case 'A':
+ /*
+ * Exactly the same as `-ax'. This has been
+ * added for compatability with SUSv3, but for
+ * now it will not be described in the man page.
+ */
+ nselectors++;
+ all = xkeep = 1;
+ break;
+ case 'a':
+ nselectors++;
+ all = 1;
+ break;
+ case 'C':
+ rawcpu = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'e': /* XXX set ufmt */
+ if (u03) {
+ nselectors++;
+ all = xkeep = 1;
+ break;
+ }
+ case 'E':
+ needenv = 1;
+ eflg = 1;
+ break;
+#ifdef LAZY_PS
+ case 'f':
+ if (getuid() == 0 || getgid() == 0)
+ forceuread = 1;
+ break;
+#endif
+ case 'f':
+ termwidth = UNLIMITED; /* 4990408 */
+ if (u03 && uidlist.count == 0) {
+ parsefmt(p_ffmt, 0);
+ /* This is a unplesent little trick that makes
+ ./ps -f -p PID -o pid,comm,args
+ print out the whole command even if they slap
+ more fields on after it and gobble up too much
+ space */
+ VAR *v = findvar("command", 0, NULL);
+ if (v) {
+ v->width = 64;
+ }
+ } else {
+ parsefmt(p_uffmt, 0);
+ }
+ _fmt = 1;
+ break;
+ case 'G':
+ add_list(&gidlist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+ case 'g':
+ /* The historical BSD-ish (from SunOS) behavior. */
+ if (!u03) break;
+
+ add_list(&pgrplist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+#ifndef __APPLE__
+ case 'H':
+ showthreads = KERN_PROC_INC_THREAD;
+ break;
+#endif /* !__APPLE__ */
+ case 'h':
+ prtheader = ws.ws_row > 5 ? ws.ws_row : 22;
+ break;
+ case 'j':
+ parsefmt(jfmt, 0);
+ _fmt = 1;
+ jfmt[0] = '\0';
+ break;
+ case 'L':
+ showkey();
+ exit(0);
+ case 'l':
+ parsefmt(u03 ? p_lfmt : lfmt, 0);
+ _fmt = 1;
+ lfmt[0] = '\0';
+ break;
+ case 'M':
+#ifndef __APPLE__
+ memf = optarg;
+#else
+ parsefmt(mfmt, 0);
+ _fmt = 1;
+ mfmt[0] = '\0';
+ mflg = 1;
+#endif /* 0 */
+ break;
+ case 'm':
+ sortby = SORTMEM;
+ break;
+#ifndef __APPLE__
+ case 'N':
+ nlistf = optarg;
+ break;
+#endif /* !__APPLE__ */
+ case 'O':
+ parsefmt(o1, 1);
+ parsefmt(optarg, 1);
+ parsefmt(o2, 1);
+ o1[0] = o2[0] = '\0';
+ _fmt = 1;
+ break;
+ case 'o':
+ parsefmt(optarg, 1);
+ _fmt = 1;
+ break;
+ case 'p':
+ add_list(&pidlist, optarg);
+ /*
+ * Note: `-p' does not *set* xkeep, but any values
+ * from pidlist are checked before xkeep is. That
+ * way they are always matched, even if the user
+ * specifies `-X'.
+ */
+ nselectors++;
+ break;
+ case 'r':
+ sortby = SORTCPU;
+ break;
+ case 'S':
+ sumrusage = 1;
+ break;
+ case 'T':
+ if ((optarg = ttyname(STDIN_FILENO)) == NULL)
+ errx(1, "stdin: not a terminal");
+ /* FALLTHROUGH */
+ case 't':
+ add_list(&ttylist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+ case 'U':
+ add_list(&ruidlist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+ case 'u':
+ if (u03) {
+ /* This is what SUSv3 defines as the `-u' option. */
+ add_list(&uidlist, optarg);
+ xkeep_implied = 1;
+ nselectors++;
+ break;
+ }
+ parsefmt(ufmt, 0);
+ sortby = SORTCPU;
+ _fmt = 1;
+ ufmt[0] = '\0';
+ break;
+ case 'v':
+ parsefmt(vfmt, 0);
+ sortby = SORTMEM;
+ _fmt = 1;
+ vfmt[0] = '\0';
+ break;
+ case 'w':
+ if (wflag)
+ termwidth = UNLIMITED;
+ else if (termwidth < 131)
+ termwidth = 131;
+ wflag++;
+ break;
+ case 'X':
+ /*
+ * Note that `-X' and `-x' are not standard "selector"
+ * options. For most selector-options, we check *all*
+ * processes to see if any are matched by the given
+ * value(s). After we have a set of all the matched
+ * processes, then `-X' and `-x' govern whether we
+ * modify that *matched* set for processes which do
+ * not have a controlling terminal. `-X' causes
+ * those processes to be deleted from the matched
+ * set, while `-x' causes them to be kept.
+ */
+ xkeep = 0;
+ break;
+ case 'x':
+ xkeep = 1;
+ break;
+ case '?':
+ default:
+ usage(u03);
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifdef __APPLE__
+ /* 3862041 */
+ if (!isatty(STDOUT_FILENO))
+ termwidth = UNLIMITED;
+#endif /* __APPLE__ */
+
+ /*
+ * If the user specified ps -e then they want a copy of the process
+ * environment kvm_getenvv(3) attempts to open /proc/<pid>/mem.
+ * Check to make sure that procfs is mounted on /proc, otherwise
+ * print a warning informing the user that output will be incomplete.
+ */
+#ifndef __APPLE__
+ if (needenv == 1 && check_procfs() == 0)
+ warnx("Process environment requires procfs(5)");
+#endif /* !__APPLE__ */
+ /*
+ * If there arguments after processing all the options, attempt
+ * to treat them as a list of process ids.
+ */
+ while (*argv) {
+ if (!isdigitch(**argv))
+ break;
+ add_list(&pidlist, *argv);
+ argv++;
+ }
+ if (*argv) {
+ fprintf(stderr, "%s: illegal argument: %s\n",
+ getprogname(), *argv);
+ usage(u03);
+ }
+ if (optfatal)
+ exit(1); /* Error messages already printed. */
+ if (xkeep < 0) /* Neither -X nor -x was specified. */
+ xkeep = xkeep_implied;
+
+#if FIXME
+ kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
+ if (kd == 0)
+ errx(1, "%s", errbuf);
+#endif /* FIXME */
+
+ if (!_fmt) {
+ if (u03 && uidlist.count != 0) {
+ parsefmt("uid", 0);
+ }
+ parsefmt(u03 ? p_dfmt : dfmt, 0);
+ }
+
+ if (nselectors == 0) {
+ uidlist.l.ptr = malloc(sizeof(uid_t));
+ if (uidlist.l.ptr == NULL)
+ errx(1, "malloc failed");
+ nselectors = 1;
+ uidlist.count = uidlist.maxcount = 1;
+ *uidlist.l.uids = getuid();
+ }
+
+ /*
+ * scan requested variables, noting what structures are needed,
+ * and adjusting header widths as appropriate.
+ */
+ scanvars();
+
+ /*
+ * Get process list. If the user requested just one selector-
+ * option, then kvm_getprocs can be asked to return just those
+ * processes. Otherwise, have it return all processes, and
+ * then this routine will search that full list and select the
+ * processes which match any of the user's selector-options.
+ */
+ what = KERN_PROC_ALL;
+ flag = 0;
+ if (nselectors == 1) {
+ if (gidlist.count == 1) {
+#if 0
+ what = KERN_PROC_RGID | showthreads;
+ flag = *gidlist.l.gids;
+ nselectors = 0;
+#endif /* 0 */
+ } else if (pgrplist.count == 1) {
+ what = KERN_PROC_PGRP | showthreads;
+ flag = *pgrplist.l.pids;
+ nselectors = 0;
+ } else if (pidlist.count == 1) {
+ what = KERN_PROC_PID | showthreads;
+ flag = *pidlist.l.pids;
+ nselectors = 0;
+ } else if (ruidlist.count == 1) {
+ what = KERN_PROC_RUID | showthreads;
+ flag = *ruidlist.l.uids;
+ nselectors = 0;
+ } else if (sesslist.count == 1) {
+ what = KERN_PROC_SESSION | showthreads;
+ flag = *sesslist.l.pids;
+ nselectors = 0;
+ } else if (ttylist.count == 1) {
+ what = KERN_PROC_TTY | showthreads;
+ flag = *ttylist.l.ttys;
+ nselectors = 0;
+ } else if (uidlist.count == 1) {
+ what = (xkeep ? KERN_PROC_RUID : KERN_PROC_UID) | showthreads;
+ flag = *uidlist.l.uids;
+ nselectors = 0;
+ }
+ }
+
+ /*
+ * select procs
+ */
+ nentries = -1;
+#if FIXME
+ kp = kvm_getprocs(kd, what, flag, &nentries);
+ if ((kp == NULL && nentries > 0) || (kp != NULL && nentries < 0))
+ errx(1, "%s", kvm_geterr(kd));
+#else /* FIXME */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = what;
+ mib[3] = flag;
+
+ if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
+ perror("Failure calling sysctl");
+ return 0;
+ }
+
+ kprocbuf= kp = (struct kinfo_proc *)malloc(bufSize);
+
+ retry_count = 0;
+ orig_bufSize = bufSize;
+ for(retry_count=0; ; retry_count++) {
+ /* retry for transient errors due to load in the system */
+ local_error = 0;
+ bufSize = orig_bufSize;
+ if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) {
+ if (retry_count < 1000) {
+ /* 1 sec back off */
+ sleep(1);
+ continue;
+ }
+ perror("Failure calling sysctl");
+ return 0;
+ } else if (local_error == 0) {
+ break;
+ }
+ /* 1 sec back off */
+ sleep(1);
+ }
+
+ /* This has to be after the second sysctl since the bufSize
+ may have changed. */
+ nentries = bufSize / sizeof(struct kinfo_proc);
+#endif /* FIXME */
+ nkept = 0;
+ if (nentries > 0) {
+ if ((kinfo = calloc(nentries, sizeof(*kinfo))) == NULL)
+ errx(1, "malloc failed");
+ for (i = nentries; --i >= 0; ++kp) {
+#ifdef __APPLE__
+ if (kp->kp_proc.p_pid == 0) {
+ continue;
+ }
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+ if (dflag && (kp->kp_proc.p_pid == kp->kp_eproc.e_pgid))
+ continue;
+#endif /* __APPLE__ */
+
+ /*
+ * If the user specified multiple selection-criteria,
+ * then keep any process matched by the inclusive OR
+ * of all the selection-criteria given.
+ */
+ if (pidlist.count > 0) {
+ for (elem = 0; elem < pidlist.count; elem++)
+ if (kp->kp_proc.p_pid == pidlist.l.pids[elem])
+ goto keepit;
+ }
+ /*
+ * Note that we had to process pidlist before
+ * filtering out processes which do not have
+ * a controlling terminal.
+ */
+ if (xkeep == 0) {
+ if ((kp->kp_eproc.e_tdev == NODEV ||
+ (kp->kp_proc.p_flag & P_CONTROLT) == 0))
+ continue;
+ }
+ if (all || nselectors == 0)
+ goto keepit;
+ if (gidlist.count > 0) {
+ for (elem = 0; elem < gidlist.count; elem++)
+ if (kp->kp_eproc.e_pcred.p_rgid == gidlist.l.gids[elem])
+ goto keepit;
+ }
+ if (pgrplist.count > 0) {
+ for (elem = 0; elem < pgrplist.count; elem++)
+ if (kp->kp_eproc.e_pgid ==
+ pgrplist.l.pids[elem])
+ goto keepit;
+ }
+ if (ruidlist.count > 0) {
+ for (elem = 0; elem < ruidlist.count; elem++)
+ if (kp->kp_eproc.e_pcred.p_ruid ==
+ ruidlist.l.uids[elem])
+ goto keepit;
+ }
+#if 0
+ if (sesslist.count > 0) {
+ for (elem = 0; elem < sesslist.count; elem++)
+ if (kp->ki_sid == sesslist.l.pids[elem])
+ goto keepit;
+ }
+#endif
+ if (ttylist.count > 0) {
+ for (elem = 0; elem < ttylist.count; elem++)
+ if (kp->kp_eproc.e_tdev == ttylist.l.ttys[elem])
+ goto keepit;
+ }
+ if (uidlist.count > 0) {
+ for (elem = 0; elem < uidlist.count; elem++)
+ if (kp->kp_eproc.e_ucred.cr_uid == uidlist.l.uids[elem])
+ goto keepit;
+ }
+ /*
+ * This process did not match any of the user's
+ * selector-options, so skip the process.
+ */
+ continue;
+
+ keepit:
+ next_KINFO = &kinfo[nkept];
+ next_KINFO->ki_p = kp;
+ get_task_info(next_KINFO);
+#ifndef __APPLE__
+ next_KINFO->ki_pcpu = getpcpu(next_KINFO);
+ if (sortby == SORTMEM)
+ next_KINFO->ki_memsize = kp->ki_tsize +
+ kp->ki_dsize + kp->ki_ssize;
+#endif /* !__APPLE__ */
+ if (needuser)
+ saveuser(next_KINFO);
+ dynsizevars(next_KINFO);
+ nkept++;
+ }
+ }
+
+ sizevars();
+
+ /*
+ * print header
+ */
+ printheader();
+ if (nkept == 0)
+ exit(1);
+
+ /*
+ * sort proc list
+ */
+ qsort(kinfo, nkept, sizeof(KINFO), pscomp);
+ /*
+ * For each process, call each variable output function.
+ */
+ for (i = lineno = 0; i < nkept; i++) {
+ if(mflg) {
+ print_all_thread = 1;
+ for(j=0; j < kinfo[i].thread_count; j++) {
+ print_thread_num = j;
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ (vent->var->oproc)(&kinfo[i], vent);
+ if (STAILQ_NEXT(vent, next_ve) != NULL)
+ (void)putchar(' ');
+ }
+
+ (void)putchar('\n');
+ if (prtheader && lineno++ == prtheader - 4) {
+ (void)putchar('\n');
+ printheader();
+ lineno = 0;
+ }
+ }
+ print_all_thread = 0;
+ } else {
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ (vent->var->oproc)(&kinfo[i], vent);
+ if (STAILQ_NEXT(vent, next_ve) != NULL)
+ (void)putchar(' ');
+ }
+
+ (void)putchar('\n');
+ if (prtheader && lineno++ == prtheader - 4) {
+ (void)putchar('\n');
+ printheader();
+ lineno = 0;
+ }
+ }
+ }
+ for (i = 0; i < nkept; i++) {
+ if (kinfo[i].invalid_tinfo == 0 && kinfo[i].thread_count)
+ free(kinfo[i].thval);
+ }
+ free(kprocbuf);
+ free(kinfo);
+ free_list(&gidlist);
+ free_list(&pidlist);
+ free_list(&pgrplist);
+ free_list(&ruidlist);
+ free_list(&sesslist);
+ free_list(&ttylist);
+ free_list(&uidlist);
+
+ exit(eval);
+}
+
+static int
+addelem_gid(struct listinfo *inf, const char *elem)
+{
+ struct group *grp;
+ const char *nameorID;
+ char *endp;
+ u_long bigtemp;
+
+ if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) {
+ if (*elem == '\0')
+ warnx("Invalid (zero-length) %s name", inf->lname);
+ else
+ warnx("%s name too long: %s", inf->lname, elem);
+ optfatal = 1;
+ return (0); /* Do not add this value. */
+ }
+
+ /*
+ * SUSv3 states that `ps -G grouplist' should match "real-group
+ * ID numbers", and does not mention group-names. I do want to
+ * also support group-names, so this tries for a group-id first,
+ * and only tries for a name if that doesn't work. This is the
+ * opposite order of what is done in addelem_uid(), but in
+ * practice the order would only matter for group-names which
+ * are all-numeric.
+ */
+ grp = NULL;
+ nameorID = "named";
+ errno = 0;
+ bigtemp = strtoul(elem, &endp, 10);
+ if (errno == 0 && *endp == '\0' && bigtemp <= GID_MAX) {
+ nameorID = "name or ID matches";
+ grp = getgrgid((gid_t)bigtemp);
+ }
+ if (grp == NULL)
+ grp = getgrnam(elem);
+ if (grp == NULL) {
+ warnx("No %s %s '%s'", inf->lname, nameorID, elem);
+ optfatal = 1;
+ return (0);
+ }
+ if (inf->count >= inf->maxcount)
+ expand_list(inf);
+ inf->l.gids[(inf->count)++] = grp->gr_gid;
+ return (1);
+}
+
+#define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc.h. */
+static int
+addelem_pid(struct listinfo *inf, const char *elem)
+{
+ char *endp;
+ long tempid;
+
+ if (*elem == '\0') {
+ warnx("Invalid (zero-length) process id");
+ optfatal = 1;
+ return (0); /* Do not add this value. */
+ }
+
+ errno = 0;
+ tempid = strtol(elem, &endp, 10);
+ if (*endp != '\0' || tempid < 0 || elem == endp) {
+ warnx("Invalid %s: %s", inf->lname, elem);
+ errno = ERANGE;
+ } else if (errno != 0 || tempid > BSD_PID_MAX) {
+ warnx("%s too large: %s", inf->lname, elem);
+ errno = ERANGE;
+ }
+ if (errno == ERANGE) {
+ optfatal = 1;
+ return (0);
+ }
+ if (inf->count >= inf->maxcount)
+ expand_list(inf);
+ inf->l.pids[(inf->count)++] = tempid;
+ return (1);
+}
+#undef BSD_PID_MAX
+
+/*-
+ * The user can specify a device via one of three formats:
+ * 1) fully qualified, e.g.: /dev/ttyp0 /dev/console
+ * 2) missing "/dev", e.g.: ttyp0 console
+ * 3) two-letters, e.g.: p0 co
+ * (matching letters that would be seen in the "TT" column)
+ */
+static int
+addelem_tty(struct listinfo *inf, const char *elem)
+{
+ const char *ttypath;
+ struct stat sb;
+ char pathbuf[PATH_MAX], pathbuf2[PATH_MAX];
+
+ ttypath = NULL;
+ pathbuf2[0] = '\0';
+ switch (*elem) {
+ case '/':
+ ttypath = elem;
+ break;
+ case 'c':
+ if (strcmp(elem, "co") == 0) {
+ ttypath = _PATH_CONSOLE;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ strlcpy(pathbuf, _PATH_DEV, sizeof(pathbuf));
+ strlcat(pathbuf, elem, sizeof(pathbuf));
+ ttypath = pathbuf;
+ if (strncmp(pathbuf, _PATH_TTY, strlen(_PATH_TTY)) == 0)
+ break;
+ if (strcmp(pathbuf, _PATH_CONSOLE) == 0)
+ break;
+ /* Check to see if /dev/tty${elem} exists */
+ strlcpy(pathbuf2, _PATH_TTY, sizeof(pathbuf2));
+ strlcat(pathbuf2, elem, sizeof(pathbuf2));
+ if (stat(pathbuf2, &sb) == 0 && S_ISCHR(sb.st_mode)) {
+ /* No need to repeat stat() && S_ISCHR() checks */
+ ttypath = NULL;
+ break;
+ }
+ break;
+ }
+ if (ttypath) {
+#ifdef __APPLE__
+ if (access(ttypath, F_OK) == -1 || stat(ttypath, &sb) == -1) {
+#else
+ if (stat(ttypath, &sb) == -1) {
+#endif
+ if (pathbuf2[0] != '\0')
+ warn("%s and %s", pathbuf2, ttypath);
+ else
+ warn("%s", ttypath);
+ optfatal = 1;
+ return (0);
+ }
+ if (!S_ISCHR(sb.st_mode)) {
+ if (pathbuf2[0] != '\0')
+ warnx("%s and %s: Not a terminal", pathbuf2,
+ ttypath);
+ else
+ warnx("%s: Not a terminal", ttypath);
+ optfatal = 1;
+ return (0);
+ }
+ }
+ if (inf->count >= inf->maxcount)
+ expand_list(inf);
+ inf->l.ttys[(inf->count)++] = sb.st_rdev;
+ return (1);
+}
+
+static int
+addelem_uid(struct listinfo *inf, const char *elem)
+{
+ struct passwd *pwd;
+ char *endp;
+ u_long bigtemp;
+
+ if (*elem == '\0' || strlen(elem) >= MAXLOGNAME) {
+ if (*elem == '\0')
+ warnx("Invalid (zero-length) %s name", inf->lname);
+ else
+ warnx("%s name too long: %s", inf->lname, elem);
+ optfatal = 1;
+ return (0); /* Do not add this value. */
+ }
+
+ pwd = getpwnam(elem);
+ if (pwd == NULL) {
+ errno = 0;
+ bigtemp = strtoul(elem, &endp, 10);
+ if (errno != 0 || *endp != '\0' || bigtemp > UID_MAX)
+ warnx("No %s named '%s'", inf->lname, elem);
+ else {
+ /* The string is all digits, so it might be a userID. */
+ pwd = getpwuid((uid_t)bigtemp);
+ if (pwd == NULL)
+ warnx("No %s name or ID matches '%s'",
+ inf->lname, elem);
+ }
+ }
+ if (pwd == NULL) {
+ /*
+ * These used to be treated as minor warnings (and the
+ * option was simply ignored), but now they are fatal
+ * errors (and the command will be aborted).
+ */
+ optfatal = 1;
+ return (0);
+ }
+ if (inf->count >= inf->maxcount)
+ expand_list(inf);
+ inf->l.uids[(inf->count)++] = pwd->pw_uid;
+ return (1);
+}
+
+static void
+add_list(struct listinfo *inf, const char *argp)
+{
+ const char *savep;
+ char *cp, *endp;
+ int toolong;
+ char elemcopy[PATH_MAX];
+
+ if (*argp == 0)
+ inf->addelem(inf, elemcopy);
+ while (*argp != '\0') {
+ while (*argp != '\0' && strchr(W_SEP, *argp) != NULL)
+ argp++;
+ savep = argp;
+ toolong = 0;
+ cp = elemcopy;
+ if (strchr(T_SEP, *argp) == NULL) {
+ endp = elemcopy + sizeof(elemcopy) - 1;
+ while (*argp != '\0' && cp <= endp &&
+ strchr(W_SEP T_SEP, *argp) == NULL)
+ *cp++ = *argp++;
+ if (cp > endp)
+ toolong = 1;
+ }
+ if (!toolong) {
+ *cp = '\0';
+ /*
+ * Add this single element to the given list.
+ */
+ inf->addelem(inf, elemcopy);
+ } else {
+ /*
+ * The string is too long to copy. Find the end
+ * of the string to print out the warning message.
+ */
+ while (*argp != '\0' && strchr(W_SEP T_SEP,
+ *argp) == NULL)
+ argp++;
+ warnx("Value too long: %.*s", (int)(argp - savep),
+ savep);
+ optfatal = 1;
+ }
+ /*
+ * Skip over any number of trailing whitespace characters,
+ * but only one (at most) trailing element-terminating
+ * character.
+ */
+ while (*argp != '\0' && strchr(W_SEP, *argp) != NULL)
+ argp++;
+ if (*argp != '\0' && strchr(T_SEP, *argp) != NULL) {
+ argp++;
+#if 0
+ /* Catch case where string ended with a comma. */
+ if (*argp == '\0')
+ inf->addelem(inf, argp);
+#endif /* 0 */
+ }
+ }
+}
+
+static void *
+expand_list(struct listinfo *inf)
+{
+ void *newlist;
+ int newmax;
+
+ newmax = (inf->maxcount + 1) << 1;
+ newlist = realloc(inf->l.ptr, newmax * inf->elemsize);
+ if (newlist == NULL) {
+ free(inf->l.ptr);
+ errx(1, "realloc to %d %ss failed", newmax, inf->lname);
+ }
+ inf->maxcount = newmax;
+ inf->l.ptr = newlist;
+
+ return (newlist);
+}
+
+static void
+free_list(struct listinfo *inf)
+{
+
+ inf->count = inf->elemsize = inf->maxcount = 0;
+ if (inf->l.ptr != NULL)
+ free(inf->l.ptr);
+ inf->addelem = NULL;
+ inf->lname = NULL;
+ inf->l.ptr = NULL;
+}
+
+static void
+init_list(struct listinfo *inf, addelem_rtn artn, int elemsize,
+ const char *lname)
+{
+
+ inf->count = inf->maxcount = 0;
+ inf->elemsize = elemsize;
+ inf->addelem = artn;
+ inf->lname = lname;
+ inf->l.ptr = NULL;
+}
+
+VARENT *
+find_varentry(VAR *v)
+{
+ struct varent *vent;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ if (strcmp(vent->var->name, v->name) == 0)
+ return vent;
+ }
+ return NULL;
+}
+
+static void
+scanvars(void)
+{
+ struct varent *vent;
+ VAR *v;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ v = vent->var;
+ if (v->flag & DSIZ) {
+ v->dwidth = v->width;
+ v->width = 0;
+ }
+ if (v->flag & USER)
+ needuser = 1;
+ if (v->flag & COMM)
+ needcomm = 1;
+ }
+}
+
+static void
+dynsizevars(KINFO *ki)
+{
+ struct varent *vent;
+ VAR *v;
+ int i;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ v = vent->var;
+ if (!(v->flag & DSIZ))
+ continue;
+ i = (v->sproc)( ki);
+ if (v->width < i)
+ v->width = i;
+ if (v->width > v->dwidth)
+ v->width = v->dwidth;
+ }
+}
+
+static void
+sizevars(void)
+{
+ struct varent *vent;
+ VAR *v;
+ int i;
+
+ STAILQ_FOREACH(vent, &varlist, next_ve) {
+ v = vent->var;
+ i = strlen(vent->header);
+ if (v->width < i)
+ v->width = i;
+ totwidth += v->width + 1; /* +1 for space */
+ }
+ totwidth--;
+}
+
+#ifndef __APPLE__
+static const char *
+fmt(char **(*fn)(kvm_t *, const struct kinfo_proc *, int), KINFO *ki,
+ char *comm, int maxlen)
+{
+ const char *s;
+
+ s = fmt_argv((*fn)(kd, ki->ki_p, termwidth), comm, maxlen);
+ return (s);
+}
+#endif /* !__APPLE__ */
+
+#define UREADOK(ki) (forceuread || (KI_PROC(ki)->p_flag & P_INMEM))
+
+static void
+saveuser(KINFO *ki)
+{
+ struct usave *usp;
+#if FIXME
+ struct user *u_addr = (struct user *)USRSTACK;
+#endif /* FIXME */
+
+ usp = &ki->ki_u;
+#if FIXME
+ if (UREADOK(ki) && kvm_uread(kd, KI_PROC(ki), (unsigned long)&u_addr->u_stats,
+ (char *)&pstats, sizeof(pstats)) == sizeof(pstats))
+ {
+ /*
+ * The u-area might be swapped out, and we can't get
+ * at it because we have a crashdump and no swap.
+ * If it's here fill in these fields, otherwise, just
+ * leave them 0.
+ */
+ usp->u_start = pstats.p_start;
+ usp->u_ru = pstats.p_ru;
+ usp->u_cru = pstats.p_cru;
+ usp->u_valid = 1;
+ } else
+ usp->u_valid = 0;
+#else /* FIXME */
+ usp->u_valid = 0;
+#endif /* FIXME */
+ /*
+ * save arguments if needed
+ */
+#if FIXME
+ if (needcomm && UREADOK(ki)) {
+ ki->ki_args = fmt(kvm_getargv, ki, KI_PROC(ki)->p_comm,
+ MAXCOMLEN);
+ } else if (needcomm) {
+ ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3);
+ sprintf(ki->ki_args, "(%s)", KI_PROC(ki)->p_comm);
+ } else {
+ ki->ki_args = NULL;
+ }
+#else /* FIXME */
+ ki->ki_args = malloc(strlen(KI_PROC(ki)->p_comm) + 3);
+ sprintf(ki->ki_args, "%s", KI_PROC(ki)->p_comm);
+ //ki->ki_args = malloc(10);
+ //strcpy(ki->ki_args, "()");
+#endif /* FIXME */
+#if FIXME
+ if (needenv && UREADOK(ki)) {
+ ki->ki_env = fmt(kvm_getenvv, ki, (char *)NULL, 0);
+ } else if (needenv) {
+ ki->ki_env = malloc(3);
+ strcpy(ki->ki_env, "()");
+ } else {
+ ki->ki_env = NULL;
+ }
+#else /* FIXME */
+ ki->ki_env = malloc(10);
+ strcpy(ki->ki_env, "");
+#endif /* FIXME */
+}
+
+static int
+pscomp(const void *a, const void *b)
+{
+ int i;
+#if FIXME
+#define VSIZE(k) (KI_EPROC(k)->e_vm.vm_dsize + KI_EPROC(k)->e_vm.vm_ssize + \
+ KI_EPROC(k)->e_vm.vm_tsize)
+#else /* FIXME */
+#define VSIZE(k) ((k)->tasks_info.resident_size)
+
+#endif /* FIXME */
+
+ if (sortby == SORTCPU)
+ return (getpcpu((KINFO *)b) - getpcpu((KINFO *)a));
+ if (sortby == SORTMEM)
+ return (VSIZE((KINFO *)b) - VSIZE((KINFO *)a));
+ i = KI_EPROC((KINFO *)a)->e_tdev - KI_EPROC((KINFO *)b)->e_tdev;
+ if (i == 0)
+ i = KI_PROC((KINFO *)a)->p_pid - KI_PROC((KINFO *)b)->p_pid;
+ return (i);
+}
+
+/*
+ * ICK (all for getopt), would rather hide the ugliness
+ * here than taint the main code.
+ *
+ * ps foo -> ps -foo
+ * ps 34 -> ps -p34
+ *
+ * The old convention that 't' with no trailing tty arg means the users
+ * tty, is only supported if argv[1] doesn't begin with a '-'. This same
+ * feature is available with the option 'T', which takes no argument.
+ */
+static char *
+kludge_oldps_options(const char *optlist, char *origval, const char *nextarg, int *u03)
+{
+ size_t len;
+ char *argp, *cp, *newopts, *ns, *optp, *pidp;
+
+ /*
+ * See if the original value includes any option which takes an
+ * argument (and will thus use up the remainder of the string).
+ */
+ argp = NULL;
+ if (optlist != NULL) {
+ for (cp = origval; *cp != '\0'; cp++) {
+ optp = strchr(optlist, *cp);
+ if ((optp != NULL) && *(optp + 1) == ':') {
+ argp = cp;
+ break;
+ }
+ }
+ }
+ if (argp != NULL && *origval == '-')
+ return (origval);
+
+ /*
+ * if last letter is a 't' flag with no argument (in the context
+ * of the oldps options -- option string NOT starting with a '-' --
+ * then convert to 'T' (meaning *this* terminal, i.e. ttyname(0)).
+ *
+ * However, if a flag accepting a string argument is found earlier
+ * in the option string (including a possible `t' flag), then the
+ * remainder of the string must be the argument to that flag; so
+ * do not modify that argument. Note that a trailing `t' would
+ * cause argp to be set, if argp was not already set by some
+ * earlier option.
+ */
+ len = strlen(origval);
+ cp = origval + len - 1;
+ pidp = NULL;
+ if (*cp == 't' && *origval != '-' && cp == argp) {
+ if (nextarg == NULL || *nextarg == '-' || isdigitch(*nextarg))
+ *cp = 'T';
+ } else if (argp == NULL) {
+ /*
+ * The original value did not include any option which takes
+ * an argument (and that would include `p' and `t'), so check
+ * the value for trailing number, or comma-separated list of
+ * numbers, which we will treat as a pid request.
+ */
+ if (isdigitch(*cp)) {
+ while (cp >= origval && (*cp == ',' || isdigitch(*cp)))
+ --cp;
+ pidp = cp + 1;
+ }
+ }
+
+ /*
+ * If nothing needs to be added to the string, then return
+ * the "original" (although possibly modified) value.
+ */
+ if (*origval == '-' && pidp == NULL)
+ return (origval);
+
+ /*
+ * Create a copy of the string to add '-' and/or 'p' to the
+ * original value.
+ */
+ if ((newopts = ns = malloc(len + 3)) == NULL)
+ errx(1, "malloc failed");
+
+ if (*origval != '-') {
+ *ns++ = '-'; /* add option flag */
+ *u03 = 0;
+ }
+
+ if (pidp == NULL)
+ strcpy(ns, origval);
+ else {
+ /*
+ * Copy everything before the pid string, add the `p',
+ * and then copy the pid string.
+ */
+ len = pidp - origval;
+ memcpy(ns, origval, len);
+ ns += len;
+ *ns++ = 'p';
+ strcpy(ns, pidp);
+ }
+
+ return (newopts);
+}
+
+#ifndef __APPLE__
+static int
+check_procfs(void)
+{
+ struct statfs mnt;
+
+ if (statfs("/proc", &mnt) < 0)
+ return (0);
+ if (strcmp(mnt.f_fstypename, "procfs") != 0)
+ return (0);
+ return (1);
+}
+#endif /* !__APPLE__ */
+
+static void
+usage(int u03)
+{
+#define SINGLE_OPTS "[-AaCcEefhjlMmrSTvwXx]"
+
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
+ "usage: ps " SINGLE_OPTS " [-O fmt | -o fmt] [-G gid[,gid...]]",
+ (u03 ? " [-g grp[,grp...]] [-u [uid,uid...]]" : " [-u]"),
+ " [-p pid[,pid...]] [-t tty[,tty...]] [-U user[,user...]]",
+ " ps [-L]");
+ exit(1);
+}
diff --git a/adv_cmds/ps/ps.h b/adv_cmds/ps/ps.h
new file mode 100644
index 0000000..a077eff
--- /dev/null
+++ b/adv_cmds/ps/ps.h
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ps.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: ps.h,v 1.6 1998/09/14 08:32:20 dfr Exp $
+ */
+
+#include <sys/queue.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/policy.h>
+#include <mach/task_info.h>
+#include <mach/thread_info.h>
+
+#define UNLIMITED 0 /* unlimited terminal width */
+enum type { CHAR, UCHAR, SHORT, USHORT, INT, UINT, LONG, ULONG, KPTR, PGTOK };
+
+struct usave {
+ struct timeval u_start;
+ struct rusage u_ru;
+ struct rusage u_cru;
+ char u_acflag;
+ char u_valid;
+};
+
+#define KI_PROC(ki) (&(ki)->ki_p->kp_proc)
+#define KI_EPROC(ki) (&(ki)->ki_p->kp_eproc)
+
+typedef struct thread_values {
+ struct thread_basic_info tb;
+ /* struct policy_infos schedinfo; */
+ union {
+ struct policy_timeshare_info tshare;
+ struct policy_rr_info rr;
+ struct policy_fifo_info fifo;
+ } schedinfo;
+} thread_values_t;
+
+typedef struct kinfo {
+ struct kinfo_proc *ki_p; /* kinfo_proc structure */
+ struct usave ki_u; /* interesting parts of user */
+ char *ki_args; /* exec args */
+ char *ki_env; /* environment */
+ task_port_t task;
+ int state;
+ int cpu_usage;
+ int curpri;
+ int basepri;
+ int swapped;
+ struct task_basic_info tasks_info;
+ struct task_thread_times_info times;
+ /* struct policy_infos schedinfo; */
+ union {
+ struct policy_timeshare_info tshare;
+ struct policy_rr_info rr;
+ struct policy_fifo_info fifo;
+ } schedinfo;
+ int invalid_tinfo;
+ unsigned int thread_count;
+ thread_port_array_t thread_list;
+ thread_values_t *thval;
+ int invalid_thinfo;
+} KINFO;
+
+/* Variables. */
+typedef struct varent {
+ STAILQ_ENTRY(varent) next_ve;
+ const char *header;
+ struct var *var;
+} VARENT;
+
+typedef struct var {
+ const char *name; /* name(s) of variable */
+ const char *header; /* default header */
+ const char *alias; /* aliases */
+#define COMM 0x01 /* needs exec arguments and environment (XXX) */
+#define LJUST 0x02 /* left adjust on output (trailing blanks) */
+#define USER 0x04 /* needs user structure */
+#define DSIZ 0x08 /* field size is dynamic*/
+#define INF127 0x10 /* values >127 displayed as 127 */
+ u_int flag;
+ /* output routine */
+ void (*oproc)(struct kinfo *, struct varent *);
+ /* sizing routine*/
+ int (*sproc)(struct kinfo *);
+ short width; /* printing width */
+ /*
+ * The following (optional) elements are hooks for passing information
+ * to the generic output routine pvar (which prints simple elements
+ * from the well known kinfo_proc structure).
+ */
+ size_t off; /* offset in structure */
+ enum type type; /* type of element */
+ const char *fmt; /* printf format */
+ short dwidth; /* dynamic printing width */
+ /*
+ * glue to link selected fields together
+ */
+} VAR;
+
+#include "extern.h"
diff --git a/adv_cmds/ps/tasks.c b/adv_cmds/ps/tasks.c
new file mode 100644
index 0000000..4548b56
--- /dev/null
+++ b/adv_cmds/ps/tasks.c
@@ -0,0 +1,246 @@
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <pwd.h>
+
+#include "ps.h"
+#include <mach/shared_memory_server.h>
+
+extern kern_return_t task_for_pid(task_port_t task, pid_t pid, task_port_t *target);
+
+#define STATE_MAX 7
+
+int
+mach_state_order(s, sleep_time)
+int s;
+long sleep_time;
+{
+switch (s) {
+case TH_STATE_RUNNING: return(1);
+case TH_STATE_UNINTERRUPTIBLE:
+ return(2);
+ case TH_STATE_WAITING: return((sleep_time > 20) ? 4 : 3);
+ case TH_STATE_STOPPED: return(5);
+ case TH_STATE_HALTED: return(6);
+ default: return(7);
+ }
+}
+ /*01234567 */
+char mach_state_table[] = " RUSITH?";
+
+
+int
+thread_schedinfo(
+ KINFO *ki,
+ thread_port_t thread,
+ policy_t pol,
+ void * buf)
+{
+ unsigned int count;
+ int ret = KERN_FAILURE;
+
+ switch (pol) {
+
+ case POLICY_TIMESHARE:
+ count = POLICY_TIMESHARE_INFO_COUNT;
+ ret = thread_info(thread, THREAD_SCHED_TIMESHARE_INFO,
+ (thread_info_t)buf, &count);
+ if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_timeshare_info *)buf)->cur_priority)))
+ ki->curpri = ((struct policy_timeshare_info *)buf)->cur_priority;
+ break;
+
+ case POLICY_FIFO:
+ count = POLICY_FIFO_INFO_COUNT;
+ ret = thread_info(thread, THREAD_SCHED_FIFO_INFO,
+ buf, &count);
+ if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_fifo_info *)buf)->base_priority)))
+ ki->curpri = ((struct policy_fifo_info *)buf)->base_priority;
+ break;
+
+ case POLICY_RR:
+ count = POLICY_RR_INFO_COUNT;
+ ret = thread_info(thread, THREAD_SCHED_RR_INFO,
+ buf, &count);
+ if((ret == KERN_SUCCESS) && (ki->curpri < (((struct policy_rr_info *)buf)->base_priority)))
+ ki->curpri = ((struct policy_rr_info *)buf)->base_priority;
+ break;
+ }
+ return(ret);
+}
+
+int get_task_info (KINFO *ki)
+{
+ kern_return_t error;
+ unsigned int info_count = TASK_BASIC_INFO_COUNT;
+ unsigned int thread_info_count = THREAD_BASIC_INFO_COUNT;
+ pid_t pid;
+ int j, err = 0;
+
+ ki->state = STATE_MAX;
+
+ pid = KI_PROC(ki)->p_pid;
+ if (task_for_pid(mach_task_self(), pid, &ki->task) != KERN_SUCCESS) {
+ return(1);
+ }
+ info_count = TASK_BASIC_INFO_COUNT;
+ error = task_info(ki->task, TASK_BASIC_INFO, (task_info_t)&ki->tasks_info, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+ {
+ vm_region_basic_info_data_64_t b_info;
+ vm_address_t address = GLOBAL_SHARED_TEXT_SEGMENT;
+ vm_size_t size;
+ mach_port_t object_name;
+
+ /*
+ * try to determine if this task has the split libraries
+ * mapped in... if so, adjust its virtual size down by
+ * the 2 segments that are used for split libraries
+ */
+ info_count = VM_REGION_BASIC_INFO_COUNT_64;
+ error = vm_region_64(ki->task, &address, &size, VM_REGION_BASIC_INFO,
+ (vm_region_info_t)&b_info, &info_count, &object_name);
+ if (error == KERN_SUCCESS) {
+ if (b_info.reserved && size == (SHARED_TEXT_REGION_SIZE) &&
+ ki->tasks_info.virtual_size > (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE))
+ ki->tasks_info.virtual_size -= (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE);
+ }
+ }
+ info_count = TASK_THREAD_TIMES_INFO_COUNT;
+ error = task_info(ki->task, TASK_THREAD_TIMES_INFO, (task_info_t)&ki->times, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+ switch(ki->tasks_info.policy) {
+ case POLICY_TIMESHARE :
+ info_count = POLICY_TIMESHARE_INFO_COUNT;
+ error = task_info(ki->task, TASK_SCHED_TIMESHARE_INFO, (task_info_t)&ki->schedinfo.tshare, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+
+ ki->curpri = ki->schedinfo.tshare.cur_priority;
+ ki->basepri = ki->schedinfo.tshare.base_priority;
+ break;
+ case POLICY_RR :
+ info_count = POLICY_RR_INFO_COUNT;
+ error = task_info(ki->task, TASK_SCHED_RR_INFO, (task_info_t)&ki->schedinfo.rr, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+
+ ki->curpri = ki->schedinfo.rr.base_priority;
+ ki->basepri = ki->schedinfo.rr.base_priority;
+ break;
+
+ case POLICY_FIFO :
+ info_count = POLICY_FIFO_INFO_COUNT;
+ error = task_info(ki->task, TASK_SCHED_FIFO_INFO, (task_info_t)&ki->schedinfo.fifo, &info_count);
+ if (error != KERN_SUCCESS) {
+ ki->invalid_tinfo=1;
+#ifdef DEBUG
+ mach_error("Error calling task_info()", error);
+#endif
+ return(1);
+ }
+
+ ki->curpri = ki->schedinfo.fifo.base_priority;
+ ki->basepri = ki->schedinfo.fifo.base_priority;
+ break;
+ }
+
+ ki->invalid_tinfo=0;
+
+ ki->cpu_usage=0;
+ error = task_threads(ki->task, &ki->thread_list, &ki->thread_count);
+ if (error != KERN_SUCCESS) {
+ mach_port_deallocate(mach_task_self(),ki->task);
+#ifdef DEBUG
+ mach_error("Call to task_threads() failed", error);
+#endif
+ return(1);
+ }
+ err=0;
+ //ki->curpri = 255;
+ //ki->basepri = 255;
+ ki->swapped = 1;
+ ki->thval = calloc(ki->thread_count, sizeof(struct thread_values));
+ for (j = 0; j < ki->thread_count; j++) {
+ int tstate;
+ thread_info_count = THREAD_BASIC_INFO_COUNT;
+ error = thread_info(ki->thread_list[j], THREAD_BASIC_INFO,
+ (thread_info_t)&ki->thval[j].tb,
+ &thread_info_count);
+ if (error != KERN_SUCCESS) {
+#ifdef DEBUG
+ mach_error("Call to thread_info() failed", error);
+#endif
+ err=1;
+ } else {
+ ki->cpu_usage += ki->thval[j].tb.cpu_usage;
+ }
+ error = thread_schedinfo(ki, ki->thread_list[j],
+ ki->thval[j].tb.policy, &ki->thval[j].schedinfo);
+ if (error != KERN_SUCCESS) {
+#ifdef DEBUG
+ mach_error("Call to thread_schedinfo() failed", error);
+#endif
+ err=1;
+ }
+ tstate = mach_state_order(ki->thval[j].tb.run_state,
+ ki->thval[j].tb.sleep_time);
+ if (tstate < ki->state)
+ ki->state = tstate;
+ if ((ki->thval[j].tb.flags & TH_FLAGS_SWAPPED ) == 0)
+ ki->swapped = 0;
+ mach_port_deallocate(mach_task_self(),
+ ki->thread_list[j]);
+ }
+ ki->invalid_thinfo = err;
+ /* Deallocate the list of threads. */
+ error = vm_deallocate(mach_task_self(),
+ (vm_address_t)(ki->thread_list),
+ sizeof(*ki->thread_list) * ki->thread_count);
+ if (error != KERN_SUCCESS) {
+#ifdef DEBUG
+ mach_error("Trouble freeing thread_list", error);
+#endif
+ }
+
+ mach_port_deallocate(mach_task_self(),ki->task);
+ return(0);
+}
diff --git a/adv_cmds/stty/cchar.c b/adv_cmds/stty/cchar.c
new file mode 100644
index 0000000..da9d523
--- /dev/null
+++ b/adv_cmds/stty/cchar.c
@@ -0,0 +1,153 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cchar.c 8.5 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/cchar.c,v 1.13 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stty.h"
+#include "extern.h"
+
+static int c_cchar(const void *, const void *);
+
+/*
+ * Special control characters.
+ *
+ * Cchars1 are the standard names, cchars2 are the old aliases.
+ * The first are displayed, but both are recognized on the
+ * command line.
+ */
+struct cchar cchars1[] = {
+ { "discard", VDISCARD, CDISCARD },
+ { "dsusp", VDSUSP, CDSUSP },
+ { "eof", VEOF, CEOF },
+ { "eol", VEOL, CEOL },
+ { "eol2", VEOL2, CEOL },
+ { "erase", VERASE, CERASE },
+#ifndef __APPLE__
+ { "erase2", VERASE2, CERASE2 },
+#endif
+ { "intr", VINTR, CINTR },
+ { "kill", VKILL, CKILL },
+ { "lnext", VLNEXT, CLNEXT },
+ { "min", VMIN, CMIN },
+ { "quit", VQUIT, CQUIT },
+ { "reprint", VREPRINT, CREPRINT },
+ { "start", VSTART, CSTART },
+ { "status", VSTATUS, CSTATUS },
+ { "stop", VSTOP, CSTOP },
+ { "susp", VSUSP, CSUSP },
+ { "time", VTIME, CTIME },
+ { "werase", VWERASE, CWERASE },
+ { NULL, 0, 0},
+};
+
+struct cchar cchars2[] = {
+ { "brk", VEOL, CEOL },
+ { "flush", VDISCARD, CDISCARD },
+ { "rprnt", VREPRINT, CREPRINT },
+ { NULL, 0, 0 },
+};
+
+static int
+c_cchar(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct cchar *)a)->name, ((const struct cchar *)b)->name));
+}
+
+int
+csearch(char ***argvp, struct info *ip)
+{
+ struct cchar *cp, tmp;
+ long val;
+ char *arg, *ep, *name;
+
+ name = **argvp;
+
+ tmp.name = name;
+ if (!(cp = (struct cchar *)bsearch(&tmp, cchars1,
+ sizeof(cchars1)/sizeof(struct cchar) - 1, sizeof(struct cchar),
+ c_cchar)) && !(cp = (struct cchar *)bsearch(&tmp, cchars2,
+ sizeof(cchars2)/sizeof(struct cchar) - 1, sizeof(struct cchar),
+ c_cchar)))
+ return (0);
+
+ arg = *++*argvp;
+ if (!arg) {
+ warnx("option requires an argument -- %s", name);
+ usage();
+ }
+
+#define CHK(s) (*arg == s[0] && !strcmp(arg, s))
+ if (CHK("undef") || CHK("<undef>"))
+ ip->t.c_cc[cp->sub] = _POSIX_VDISABLE;
+ else if (cp->sub == VMIN || cp->sub == VTIME) {
+ val = strtol(arg, &ep, 10);
+#ifdef __APPLE__
+ if (val == _POSIX_VDISABLE) {
+ warnx("value of %ld would disable the option -- %s",
+ val, name);
+ usage();
+ }
+#endif
+ if (val > UCHAR_MAX) {
+ warnx("maximum option value is %d -- %s",
+ UCHAR_MAX, name);
+ usage();
+ }
+ if (*ep != '\0') {
+ warnx("option requires a numeric argument -- %s", name);
+ usage();
+ }
+ ip->t.c_cc[cp->sub] = val;
+ } else if (arg[0] == '^')
+ ip->t.c_cc[cp->sub] = (arg[1] == '?') ? 0177 :
+ (arg[1] == '-') ? _POSIX_VDISABLE : arg[1] & 037;
+ else
+ ip->t.c_cc[cp->sub] = arg[0];
+ ip->set = 1;
+ return (1);
+}
diff --git a/adv_cmds/stty/extern.h b/adv_cmds/stty/extern.h
new file mode 100644
index 0000000..193142a
--- /dev/null
+++ b/adv_cmds/stty/extern.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: src/bin/stty/extern.h,v 1.9 2002/02/02 06:50:56 imp Exp $
+ */
+
+int c_cchars(const void *, const void *);
+int c_modes(const void *, const void *);
+int csearch(char ***, struct info *);
+void checkredirect(void);
+void gprint(struct termios *, struct winsize *, int);
+void gread(struct termios *, char *);
+int ksearch(char ***, struct info *);
+int msearch(char ***, struct info *);
+void optlist(void);
+void print(struct termios *, struct winsize *, int, enum FMT);
+void usage(void);
+
+extern struct cchar cchars1[], cchars2[];
diff --git a/adv_cmds/stty/gfmt.c b/adv_cmds/stty/gfmt.c
new file mode 100644
index 0000000..4e5203f
--- /dev/null
+++ b/adv_cmds/stty/gfmt.c
@@ -0,0 +1,135 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)gfmt.c 8.6 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/gfmt.c,v 1.18 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "stty.h"
+#include "extern.h"
+
+static void gerr(const char *s);
+
+static void
+gerr(const char *s)
+{
+ if (s)
+ errx(1, "illegal gfmt1 option -- %s", s);
+ else
+ errx(1, "illegal gfmt1 option");
+}
+
+void
+#ifndef __APPLE__
+gprint(struct termios *tp, struct winsize *wp __unused, int ldisc __unused)
+#else
+gprint(struct termios *tp, struct winsize *wp, int ldisc)
+#endif
+{
+ struct cchar *cp;
+
+ (void)printf("gfmt1:cflag=%lx:iflag=%lx:lflag=%lx:oflag=%lx:",
+ (u_long)tp->c_cflag, (u_long)tp->c_iflag, (u_long)tp->c_lflag,
+ (u_long)tp->c_oflag);
+ for (cp = cchars1; cp->name; ++cp)
+ (void)printf("%s=%x:", cp->name, tp->c_cc[cp->sub]);
+ (void)printf("ispeed=%lu:ospeed=%lu\n",
+ (u_long)cfgetispeed(tp), (u_long)cfgetospeed(tp));
+}
+
+void
+gread(struct termios *tp, char *s)
+{
+ struct cchar *cp;
+ char *ep, *p;
+ long tmp;
+
+ if ((s = strchr(s, ':')) == NULL)
+ gerr(NULL);
+ for (++s; s != NULL;) {
+ p = strsep(&s, ":\0");
+ if (!p || !*p)
+ break;
+ if (!(ep = strchr(p, '=')))
+ gerr(p);
+ *ep++ = '\0';
+ (void)sscanf(ep, "%lx", &tmp);
+
+#define CHK(s) (*p == s[0] && !strcmp(p, s))
+ if (CHK("cflag")) {
+ tp->c_cflag = tmp;
+ continue;
+ }
+ if (CHK("iflag")) {
+ tp->c_iflag = tmp;
+ continue;
+ }
+ if (CHK("ispeed")) {
+ (void)sscanf(ep, "%ld", &tmp);
+ tp->c_ispeed = tmp;
+ continue;
+ }
+ if (CHK("lflag")) {
+ tp->c_lflag = tmp;
+ continue;
+ }
+ if (CHK("oflag")) {
+ tp->c_oflag = tmp;
+ continue;
+ }
+ if (CHK("ospeed")) {
+ (void)sscanf(ep, "%ld", &tmp);
+ tp->c_ospeed = tmp;
+ continue;
+ }
+ for (cp = cchars1; cp->name != NULL; ++cp)
+ if (CHK(cp->name)) {
+ if (cp->sub == VMIN || cp->sub == VTIME)
+ (void)sscanf(ep, "%ld", &tmp);
+ tp->c_cc[cp->sub] = tmp;
+ break;
+ }
+ if (cp->name == NULL)
+ gerr(p);
+ }
+}
diff --git a/adv_cmds/stty/key.c b/adv_cmds/stty/key.c
new file mode 100644
index 0000000..b38cab8
--- /dev/null
+++ b/adv_cmds/stty/key.c
@@ -0,0 +1,297 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)key.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/key.c,v 1.17 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "stty.h"
+#include "extern.h"
+
+__BEGIN_DECLS
+static int c_key(const void *, const void *);
+void f_all(struct info *);
+void f_cbreak(struct info *);
+void f_columns(struct info *);
+void f_dec(struct info *);
+void f_ek(struct info *);
+void f_everything(struct info *);
+void f_extproc(struct info *);
+void f_ispeed(struct info *);
+void f_nl(struct info *);
+void f_ospeed(struct info *);
+void f_raw(struct info *);
+void f_rows(struct info *);
+void f_sane(struct info *);
+void f_size(struct info *);
+void f_speed(struct info *);
+void f_tty(struct info *);
+__END_DECLS
+
+static struct key {
+ const char *name; /* name */
+ void (*f)(struct info *); /* function */
+#define F_NEEDARG 0x01 /* needs an argument */
+#define F_OFFOK 0x02 /* can turn off */
+ int flags;
+} keys[] = {
+ { "all", f_all, 0 },
+ { "cbreak", f_cbreak, F_OFFOK },
+ { "cols", f_columns, F_NEEDARG },
+ { "columns", f_columns, F_NEEDARG },
+ { "cooked", f_sane, 0 },
+ { "dec", f_dec, 0 },
+ { "ek", f_ek, 0 },
+ { "everything", f_everything, 0 },
+ { "extproc", f_extproc, F_OFFOK },
+ { "ispeed", f_ispeed, F_NEEDARG },
+ { "new", f_tty, 0 },
+ { "nl", f_nl, F_OFFOK },
+ { "old", f_tty, 0 },
+ { "ospeed", f_ospeed, F_NEEDARG },
+ { "raw", f_raw, F_OFFOK },
+ { "rows", f_rows, F_NEEDARG },
+ { "sane", f_sane, 0 },
+ { "size", f_size, 0 },
+ { "speed", f_speed, 0 },
+ { "tty", f_tty, 0 },
+};
+
+static int
+c_key(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct key *)a)->name, ((const struct key *)b)->name));
+}
+
+int
+ksearch(char ***argvp, struct info *ip)
+{
+ char *name;
+ struct key *kp, tmp;
+
+ name = **argvp;
+ if (*name == '-') {
+ ip->off = 1;
+ ++name;
+ } else
+ ip->off = 0;
+
+ tmp.name = name;
+ if (!(kp = (struct key *)bsearch(&tmp, keys,
+ sizeof(keys)/sizeof(struct key), sizeof(struct key), c_key)))
+ return (0);
+ if (!(kp->flags & F_OFFOK) && ip->off) {
+ warnx("illegal option -- -%s", name);
+ usage();
+ }
+ if (kp->flags & F_NEEDARG && !(ip->arg = *++*argvp)) {
+ warnx("option requires an argument -- %s", name);
+ usage();
+ }
+ kp->f(ip);
+ return (1);
+}
+
+void
+f_all(struct info *ip)
+{
+ print(&ip->t, &ip->win, ip->ldisc, BSD);
+}
+
+void
+f_cbreak(struct info *ip)
+{
+
+ if (ip->off)
+ f_sane(ip);
+ else {
+ ip->t.c_iflag |= BRKINT|IXON|IMAXBEL;
+ ip->t.c_oflag |= OPOST;
+ ip->t.c_lflag |= ISIG|IEXTEN;
+ ip->t.c_lflag &= ~ICANON;
+ ip->set = 1;
+ }
+}
+
+void
+f_columns(struct info *ip)
+{
+
+ ip->win.ws_col = atoi(ip->arg);
+ ip->wset = 1;
+}
+
+void
+f_dec(struct info *ip)
+{
+
+ ip->t.c_cc[VERASE] = (u_char)0177;
+ ip->t.c_cc[VKILL] = CTRL('u');
+ ip->t.c_cc[VINTR] = CTRL('c');
+ ip->t.c_lflag &= ~ECHOPRT;
+ ip->t.c_lflag |= ECHOE|ECHOKE|ECHOCTL;
+ ip->t.c_iflag &= ~IXANY;
+ ip->set = 1;
+}
+
+void
+f_ek(struct info *ip)
+{
+
+ ip->t.c_cc[VERASE] = CERASE;
+ ip->t.c_cc[VKILL] = CKILL;
+ ip->set = 1;
+}
+
+void
+f_everything(struct info *ip)
+{
+
+ print(&ip->t, &ip->win, ip->ldisc, BSD);
+}
+
+void
+f_extproc(struct info *ip)
+{
+
+ if (ip->off) {
+ int tmp = 0;
+ (void)ioctl(ip->fd, TIOCEXT, &tmp);
+ } else {
+ int tmp = 1;
+ (void)ioctl(ip->fd, TIOCEXT, &tmp);
+ }
+}
+
+void
+f_ispeed(struct info *ip)
+{
+
+ cfsetispeed(&ip->t, (speed_t)atoi(ip->arg));
+ ip->set = 1;
+}
+
+void
+f_nl(struct info *ip)
+{
+
+ if (ip->off) {
+ ip->t.c_iflag |= ICRNL;
+ ip->t.c_oflag |= ONLCR;
+ } else {
+ ip->t.c_iflag &= ~ICRNL;
+ ip->t.c_oflag &= ~ONLCR;
+ }
+ ip->set = 1;
+}
+
+void
+f_ospeed(struct info *ip)
+{
+
+ cfsetospeed(&ip->t, (speed_t)atoi(ip->arg));
+ ip->set = 1;
+}
+
+void
+f_raw(struct info *ip)
+{
+
+ if (ip->off)
+ f_sane(ip);
+ else {
+ cfmakeraw(&ip->t);
+ ip->t.c_cflag &= ~(CSIZE|PARENB);
+ ip->t.c_cflag |= CS8;
+ ip->set = 1;
+ }
+}
+
+void
+f_rows(struct info *ip)
+{
+
+ ip->win.ws_row = atoi(ip->arg);
+ ip->wset = 1;
+}
+
+void
+f_sane(struct info *ip)
+{
+
+ ip->t.c_cflag = TTYDEF_CFLAG | (ip->t.c_cflag & CLOCAL);
+ ip->t.c_iflag = TTYDEF_IFLAG;
+ ip->t.c_iflag |= ICRNL;
+ /* preserve user-preference flags in lflag */
+#define LKEEP (ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH)
+ ip->t.c_lflag = TTYDEF_LFLAG | (ip->t.c_lflag & LKEEP);
+ ip->t.c_oflag = TTYDEF_OFLAG;
+ ip->set = 1;
+}
+
+void
+f_size(struct info *ip)
+{
+
+ (void)printf("%d %d\n", ip->win.ws_row, ip->win.ws_col);
+}
+
+void
+f_speed(struct info *ip)
+{
+
+ (void)printf("%lu\n", (u_long)cfgetospeed(&ip->t));
+}
+
+void
+f_tty(struct info *ip)
+{
+ int tmp;
+
+ tmp = TTYDISC;
+ if (ioctl(ip->fd, TIOCSETD, &tmp) < 0)
+ err(1, "TIOCSETD");
+}
diff --git a/adv_cmds/stty/modes.c b/adv_cmds/stty/modes.c
new file mode 100644
index 0000000..0313c87
--- /dev/null
+++ b/adv_cmds/stty/modes.c
@@ -0,0 +1,308 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)modes.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/modes.c,v 1.12 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <string.h>
+#include "stty.h"
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+int msearch(char ***, struct info *);
+
+struct modes {
+ const char *name;
+ long set;
+ long unset;
+};
+
+/*
+ * The code in optlist() depends on minus options following regular
+ * options, i.e. "foo" must immediately precede "-foo".
+ */
+struct modes cmodes[] = {
+ { "cs5", CS5, CSIZE },
+ { "cs6", CS6, CSIZE },
+ { "cs7", CS7, CSIZE },
+ { "cs8", CS8, CSIZE },
+ { "cstopb", CSTOPB, 0 },
+ { "-cstopb", 0, CSTOPB },
+ { "cread", CREAD, 0 },
+ { "-cread", 0, CREAD },
+ { "parenb", PARENB, 0 },
+ { "-parenb", 0, PARENB },
+ { "parodd", PARODD, 0 },
+ { "-parodd", 0, PARODD },
+ { "parity", PARENB | CS7, PARODD | CSIZE },
+ { "-parity", CS8, PARODD | PARENB | CSIZE },
+ { "evenp", PARENB | CS7, PARODD | CSIZE },
+ { "-evenp", CS8, PARODD | PARENB | CSIZE },
+ { "oddp", PARENB | CS7 | PARODD, CSIZE },
+ { "-oddp", CS8, PARODD | PARENB | CSIZE },
+ { "pass8", CS8, PARODD | PARENB | CSIZE },
+ { "-pass8", PARENB | CS7, PARODD | CSIZE },
+ { "hupcl", HUPCL, 0 },
+ { "-hupcl", 0, HUPCL },
+ { "hup", HUPCL, 0 },
+ { "-hup", 0, HUPCL },
+ { "clocal", CLOCAL, 0 },
+ { "-clocal", 0, CLOCAL },
+ { "crtscts", CRTSCTS, 0 },
+ { "-crtscts", 0, CRTSCTS },
+ { "ctsflow", CCTS_OFLOW, 0 },
+ { "-ctsflow", 0, CCTS_OFLOW },
+ { "dsrflow", CDSR_OFLOW, 0 },
+ { "-dsrflow", 0, CDSR_OFLOW },
+ { "dtrflow", CDTR_IFLOW, 0 },
+ { "-dtrflow", 0, CDTR_IFLOW },
+ { "rtsflow", CRTS_IFLOW, 0 },
+ { "-rtsflow", 0, CRTS_IFLOW },
+ { "mdmbuf", MDMBUF, 0 },
+ { "-mdmbuf", 0, MDMBUF },
+ { NULL, 0, 0 },
+};
+
+struct modes imodes[] = {
+ { "ignbrk", IGNBRK, 0 },
+ { "-ignbrk", 0, IGNBRK },
+ { "brkint", BRKINT, 0 },
+ { "-brkint", 0, BRKINT },
+ { "ignpar", IGNPAR, 0 },
+ { "-ignpar", 0, IGNPAR },
+ { "parmrk", PARMRK, 0 },
+ { "-parmrk", 0, PARMRK },
+ { "inpck", INPCK, 0 },
+ { "-inpck", 0, INPCK },
+ { "istrip", ISTRIP, 0 },
+ { "-istrip", 0, ISTRIP },
+ { "inlcr", INLCR, 0 },
+ { "-inlcr", 0, INLCR },
+ { "igncr", IGNCR, 0 },
+ { "-igncr", 0, IGNCR },
+ { "icrnl", ICRNL, 0 },
+ { "-icrnl", 0, ICRNL },
+ { "ixon", IXON, 0 },
+ { "-ixon", 0, IXON },
+ { "flow", IXON, 0 },
+ { "-flow", 0, IXON },
+ { "ixoff", IXOFF, 0 },
+ { "-ixoff", 0, IXOFF },
+ { "tandem", IXOFF, 0 },
+ { "-tandem", 0, IXOFF },
+ { "ixany", IXANY, 0 },
+ { "-ixany", 0, IXANY },
+ { "decctlq", 0, IXANY },
+ { "-decctlq", IXANY, 0 },
+ { "imaxbel", IMAXBEL, 0 },
+ { "-imaxbel", 0, IMAXBEL },
+ { "iutf8", IUTF8, 0 },
+ { "-iutf8", 0, IUTF8 },
+ { NULL, 0, 0 },
+};
+
+struct modes lmodes[] = {
+ { "echo", ECHO, 0 },
+ { "-echo", 0, ECHO },
+ { "echoe", ECHOE, 0 },
+ { "-echoe", 0, ECHOE },
+ { "crterase", ECHOE, 0 },
+ { "-crterase", 0, ECHOE },
+ { "crtbs", ECHOE, 0 }, /* crtbs not supported, close enough */
+ { "-crtbs", 0, ECHOE },
+ { "echok", ECHOK, 0 },
+ { "-echok", 0, ECHOK },
+ { "echoke", ECHOKE, 0 },
+ { "-echoke", 0, ECHOKE },
+ { "crtkill", ECHOKE, 0 },
+ { "-crtkill", 0, ECHOKE },
+ { "altwerase", ALTWERASE, 0 },
+ { "-altwerase", 0, ALTWERASE },
+ { "iexten", IEXTEN, 0 },
+ { "-iexten", 0, IEXTEN },
+ { "echonl", ECHONL, 0 },
+ { "-echonl", 0, ECHONL },
+ { "echoctl", ECHOCTL, 0 },
+ { "-echoctl", 0, ECHOCTL },
+ { "ctlecho", ECHOCTL, 0 },
+ { "-ctlecho", 0, ECHOCTL },
+ { "echoprt", ECHOPRT, 0 },
+ { "-echoprt", 0, ECHOPRT },
+ { "prterase", ECHOPRT, 0 },
+ { "-prterase", 0, ECHOPRT },
+ { "isig", ISIG, 0 },
+ { "-isig", 0, ISIG },
+ { "icanon", ICANON, 0 },
+ { "-icanon", 0, ICANON },
+ { "noflsh", NOFLSH, 0 },
+ { "-noflsh", 0, NOFLSH },
+ { "tostop", TOSTOP, 0 },
+ { "-tostop", 0, TOSTOP },
+ { "flusho", FLUSHO, 0 },
+ { "-flusho", 0, FLUSHO },
+ { "pendin", PENDIN, 0 },
+ { "-pendin", 0, PENDIN },
+ { "crt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT },
+ { "-crt", ECHOK, ECHOE|ECHOKE|ECHOCTL },
+ { "newcrt", ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT },
+ { "-newcrt", ECHOK, ECHOE|ECHOKE|ECHOCTL },
+ { "nokerninfo", NOKERNINFO, 0 },
+ { "-nokerninfo",0, NOKERNINFO },
+ { "kerninfo", 0, NOKERNINFO },
+ { "-kerninfo", NOKERNINFO, 0 },
+ { NULL, 0, 0 },
+};
+
+struct modes omodes[] = {
+ { "opost", OPOST, 0 },
+ { "-opost", 0, OPOST },
+ { "litout", 0, OPOST },
+ { "-litout", OPOST, 0 },
+ { "onlcr", ONLCR, 0 },
+ { "-onlcr", 0, ONLCR },
+#ifndef __APPLE__
+ { "ocrnl", OCRNL, 0 },
+ { "-ocrnl", 0, OCRNL },
+#endif
+ { "tabs", 0, OXTABS }, /* "preserve" tabs */
+ { "-tabs", OXTABS, 0 },
+ { "oxtabs", OXTABS, 0 },
+ { "-oxtabs", 0, OXTABS },
+#ifndef __APPLE__
+ { "onocr", ONOCR, 0 },
+ { "-onocr", 0, ONOCR },
+ { "onlret", ONLRET, 0 },
+ { "-onlret", 0, ONLRET },
+#endif
+ { NULL, 0, 0 },
+};
+
+struct modes umodes[] = { /* For Unix conformance only */
+ { "ocrnl", OCRNL, 0 },
+ { "-ocrnl", 0, OCRNL },
+ { "onocr", ONOCR, 0 },
+ { "-onocr", 0, ONOCR },
+ { "onlret", ONLRET, 0 },
+ { "-onlret", 0, ONLRET },
+
+ { "ofill", OFILL, 0 },
+ { "-ofill", 0, OFILL },
+
+ { "ofdel", OFDEL, 0 },
+ { "-ofdel", 0, OFDEL },
+
+ { "bs0", BS0, 0 },
+ { "bs1", BS1, 0 },
+
+ { "cr0", CR0, 0 },
+ { "cr1", CR1, 0 },
+ { "cr2", CR2, 0 },
+ { "cr3", CR3, 0 },
+
+ { "ff0", FF0, 0 },
+ { "ff1", FF1, 0 },
+
+ { "nl0", NL0, 0 },
+ { "nl1", NL1, 0 },
+
+ { "tab0", TAB0, 0 },
+ { "tab1", TAB1, 0 },
+ { "tab2", TAB2, 0 },
+ { "tab3", TAB3, 0 },
+
+ { "vt0", VT0, 0 },
+ { "vt1", VT1, 0 },
+
+ { NULL, 0, 0 },
+};
+
+#define CHK(s) (*name == s[0] && !strcmp(name, s))
+
+int
+msearch(char ***argvp, struct info *ip)
+{
+ struct modes *mp;
+ char *name;
+
+ name = **argvp;
+
+ for (mp = cmodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_cflag &= ~mp->unset;
+ ip->t.c_cflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = imodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_iflag &= ~mp->unset;
+ ip->t.c_iflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = lmodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_lflag &= ~mp->unset;
+ ip->t.c_lflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ for (mp = omodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_oflag &= ~mp->unset;
+ ip->t.c_oflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ if (COMPAT_MODE("bin/stty", "Unix2003")) {
+ for (mp = umodes; mp->name; ++mp)
+ if (CHK(mp->name)) {
+ ip->t.c_oflag &= ~mp->unset;
+ ip->t.c_oflag |= mp->set;
+ ip->set = 1;
+ return (1);
+ }
+ }
+ return (0);
+}
diff --git a/adv_cmds/stty/print.c b/adv_cmds/stty/print.c
new file mode 100644
index 0000000..ef59bf1
--- /dev/null
+++ b/adv_cmds/stty/print.c
@@ -0,0 +1,291 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c 8.6 (Berkeley) 4/16/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/print.c,v 1.18 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "stty.h"
+#include "extern.h"
+
+#include <sys/ioctl_compat.h> /* XXX NTTYDISC is too well hidden */
+
+static void binit(const char *);
+static void bput(const char *);
+static const char *ccval(struct cchar *, int);
+
+void
+print(struct termios *tp, struct winsize *wp, int ldisc, enum FMT fmt)
+{
+ struct cchar *p;
+ long tmp;
+ u_char *cc;
+ int cnt, ispeed, ospeed;
+ char buf1[100], buf2[100];
+
+ cnt = 0;
+
+ /* Line discipline. */
+ if (ldisc != TTYDISC) {
+ switch(ldisc) {
+ case NTTYDISC:
+ cnt += printf("new tty disc; ");
+ break;
+#ifdef __APPLE__
+ case TABLDISC:
+ cnt += printf("tablet disc; ");
+ break;
+#endif
+ case SLIPDISC:
+ cnt += printf("slip disc; ");
+ break;
+ case PPPDISC:
+ cnt += printf("ppp disc; ");
+ break;
+ default:
+ cnt += printf("#%d disc; ", ldisc);
+ break;
+ }
+ }
+
+ /* Line speed. */
+ ispeed = cfgetispeed(tp);
+ ospeed = cfgetospeed(tp);
+ if (ispeed != ospeed)
+ cnt +=
+ printf("ispeed %d baud; ospeed %d baud;", ispeed, ospeed);
+ else
+ cnt += printf("speed %d baud;", ispeed);
+ if (fmt >= BSD)
+ cnt += printf(" %d rows; %d columns;", wp->ws_row, wp->ws_col);
+ if (cnt)
+ (void)printf("\n");
+
+#define on(f) ((tmp & (f)) != 0)
+#define put(n, f, d) \
+ if (fmt >= BSD || on(f) != (d)) \
+ bput((n) + on(f));
+
+ /* "local" flags */
+ tmp = tp->c_lflag;
+ binit("lflags");
+ put("-icanon", ICANON, 1);
+ put("-isig", ISIG, 1);
+ put("-iexten", IEXTEN, 1);
+ put("-echo", ECHO, 1);
+ put("-echoe", ECHOE, 0);
+ put("-echok", ECHOK, 0);
+ put("-echoke", ECHOKE, 0);
+ put("-echonl", ECHONL, 0);
+ put("-echoctl", ECHOCTL, 0);
+ put("-echoprt", ECHOPRT, 0);
+ put("-altwerase", ALTWERASE, 0);
+ put("-noflsh", NOFLSH, 0);
+ put("-tostop", TOSTOP, 0);
+ put("-flusho", FLUSHO, 0);
+ put("-pendin", PENDIN, 0);
+ put("-nokerninfo", NOKERNINFO, 0);
+ put("-extproc", EXTPROC, 0);
+
+ /* input flags */
+ tmp = tp->c_iflag;
+ binit("iflags");
+ put("-istrip", ISTRIP, 0);
+ put("-icrnl", ICRNL, 1);
+ put("-inlcr", INLCR, 0);
+ put("-igncr", IGNCR, 0);
+ put("-ixon", IXON, 1);
+ put("-ixoff", IXOFF, 0);
+ put("-ixany", IXANY, 1);
+ put("-imaxbel", IMAXBEL, 1);
+ put("-iutf8", IUTF8, 0);
+ put("-ignbrk", IGNBRK, 0);
+ put("-brkint", BRKINT, 1);
+ put("-inpck", INPCK, 0);
+ put("-ignpar", IGNPAR, 0);
+ put("-parmrk", PARMRK, 0);
+
+ /* output flags */
+ tmp = tp->c_oflag;
+ binit("oflags");
+ put("-opost", OPOST, 1);
+ put("-onlcr", ONLCR, 1);
+#ifndef __APPLE__
+ put("-ocrnl", OCRNL, 0);
+#endif
+ put("-oxtabs", OXTABS, 1);
+ put("-onocr", OXTABS, 0);
+ put("-onlret", OXTABS, 0);
+
+ /* control flags (hardware state) */
+ tmp = tp->c_cflag;
+ binit("cflags");
+ put("-cread", CREAD, 1);
+ switch(tmp&CSIZE) {
+ case CS5:
+ bput("cs5");
+ break;
+ case CS6:
+ bput("cs6");
+ break;
+ case CS7:
+ bput("cs7");
+ break;
+ case CS8:
+ bput("cs8");
+ break;
+ }
+ bput("-parenb" + on(PARENB));
+ put("-parodd", PARODD, 0);
+ put("-hupcl", HUPCL, 1);
+ put("-clocal", CLOCAL, 0);
+ put("-cstopb", CSTOPB, 0);
+ switch(tmp & (CCTS_OFLOW | CRTS_IFLOW)) {
+ case CCTS_OFLOW:
+ bput("ctsflow");
+ break;
+ case CRTS_IFLOW:
+ bput("rtsflow");
+ break;
+ default:
+ put("-crtscts", CCTS_OFLOW | CRTS_IFLOW, 0);
+ break;
+ }
+ put("-dsrflow", CDSR_OFLOW, 0);
+ put("-dtrflow", CDTR_IFLOW, 0);
+ put("-mdmbuf", MDMBUF, 0); /* XXX mdmbuf == dtrflow */
+
+ /* special control characters */
+ cc = tp->c_cc;
+ if (fmt == POSIX) {
+ binit("cchars");
+ for (p = cchars1; p->name; ++p) {
+ (void)snprintf(buf1, sizeof(buf1), "%s = %s;",
+ p->name, ccval(p, cc[p->sub]));
+ bput(buf1);
+ }
+ binit(NULL);
+ } else {
+ binit(NULL);
+ for (p = cchars1, cnt = 0; p->name; ++p) {
+ if (fmt != BSD && cc[p->sub] == p->def)
+ continue;
+#define WD "%-8s"
+ (void)snprintf(buf1 + cnt * 8, sizeof(buf1) - cnt * 8,
+ WD, p->name);
+ (void)snprintf(buf2 + cnt * 8, sizeof(buf2) - cnt * 8,
+ WD, ccval(p, cc[p->sub]));
+ if (++cnt == LINELENGTH / 8) {
+ cnt = 0;
+ (void)printf("%s\n", buf1);
+ (void)printf("%s\n", buf2);
+ }
+ }
+ if (cnt) {
+ (void)printf("%s\n", buf1);
+ (void)printf("%s\n", buf2);
+ }
+ }
+}
+
+static int col;
+static const char *label;
+
+static void
+binit(const char *lb)
+{
+
+ if (col) {
+ (void)printf("\n");
+ col = 0;
+ }
+ label = lb;
+}
+
+static void
+bput(const char *s)
+{
+
+ if (col == 0) {
+ col = printf("%s: %s", label, s);
+ return;
+ }
+ if ((col + strlen(s)) > LINELENGTH) {
+ (void)printf("\n\t");
+ col = printf("%s", s) + 8;
+ return;
+ }
+ col += printf(" %s", s);
+}
+
+static const char *
+ccval(struct cchar *p, int c)
+{
+ static char buf[5];
+ char *bp;
+
+ if (p->sub == VMIN || p->sub == VTIME) {
+ (void)snprintf(buf, sizeof(buf), "%d", c);
+ return (buf);
+ }
+ if (c == _POSIX_VDISABLE)
+ return ("<undef>");
+ bp = buf;
+ if (c & 0200) {
+ *bp++ = 'M';
+ *bp++ = '-';
+ c &= 0177;
+ }
+ if (c == 0177) {
+ *bp++ = '^';
+ *bp++ = '?';
+ }
+ else if (c < 040) {
+ *bp++ = '^';
+ *bp++ = c + '@';
+ }
+ else
+ *bp++ = c;
+ *bp = '\0';
+ return (buf);
+}
diff --git a/adv_cmds/stty/stty.1 b/adv_cmds/stty/stty.1
new file mode 100644
index 0000000..9a864b4
--- /dev/null
+++ b/adv_cmds/stty/stty.1
@@ -0,0 +1,633 @@
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)stty.1 8.4 (Berkeley) 4/18/94
+.\" $FreeBSD: src/bin/stty/stty.1,v 1.27 2001/11/29 15:46:54 green Exp $
+.\"
+.Dd April 18, 1994
+.Dt STTY 1
+.Os
+.Sh NAME
+.Nm stty
+.Nd set the options for a terminal device interface
+.Sh SYNOPSIS
+.Nm
+.Op Fl a | Fl e | Fl g
+.Op Fl f Ar file
+.Op operands
+.Sh DESCRIPTION
+The
+.Nm
+utility sets or reports on terminal
+characteristics for the device that is its standard input.
+If no options or operands are specified, it reports the settings of a subset
+of characteristics as well as additional ones if they differ from their
+default values.
+Otherwise it modifies
+the terminal state according to the specified arguments.
+Some combinations of arguments are mutually
+exclusive on some terminal types.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+Display all the current settings for the terminal to standard output
+as per
+.St -p1003.2 .
+.It Fl e
+Display all the current settings for the terminal to standard output
+in the traditional
+.Bx
+``all'' and ``everything'' formats.
+.It Fl f
+Open and use the terminal named by
+.Ar file
+rather than using standard input. The file is opened
+using the
+.Dv O_NONBLOCK
+flag of
+.Fn open ,
+making it possible to
+set or display settings on a terminal that might otherwise
+block on the open.
+.It Fl g
+Display all the current settings for the terminal to standard output
+in a form that may be used as an argument to a subsequent invocation of
+.Nm
+to restore the current terminal state as per
+.St -p1003.2 .
+.El
+.Pp
+The following arguments are available to set the terminal
+characteristics:
+.Ss Control Modes:
+.Pp
+Control mode flags affect hardware characteristics associated with the
+terminal. This corresponds to the c_cflag in the termios structure.
+.Bl -tag -width Fl
+.It Ar number
+Set terminal baud rate to the number given, if possible.
+If the baud rate is set to zero,
+modem control is no longer asserted.
+.It Cm clocal Pq Fl clocal
+Assume a line without (with) modem control.
+.It Cm cread Pq Fl cread
+Enable (disable) the receiver.
+.It Cm crtscts Pq Fl crtscts
+Enable (disable) RTS/CTS flow control.
+.It Cm cs5 cs6 cs7 cs8
+Select character size, if possible.
+.It Cm cstopb Pq Fl cstopb
+Use two (one) stop bits per character.
+.It Cm hup Pq Fl hup
+Same as
+.Cm hupcl
+.Pq Fl hupcl .
+.It Cm hupcl Pq Fl hupcl
+Stop asserting modem control
+(do not stop asserting modem control) on last close.
+.It Cm ispeed Ar number
+Set terminal input baud rate to the number given, if possible.
+If the input baud rate is set to zero,
+the input baud rate is set to the value of the output baud rate.
+.It Cm ospeed Ar number
+Set terminal output baud rate to the number given, if possible.
+If the output baud rate is set to zero,
+modem control is no longer asserted.
+.It Cm parenb Pq Fl parenb
+Enable (disable) parity generation and detection.
+.It Cm parodd Pq Fl parodd
+Select odd (even) parity.
+.It Cm speed Ar number
+This sets both
+.Cm ispeed
+and
+.Cm ospeed
+to
+.Ar number .
+.El
+.Ss Input Modes:
+This corresponds to the c_iflag in the termios structure.
+.Bl -tag -width Fl
+.It Cm brkint Pq Fl brkint
+Signal (do not signal)
+.Dv INTR
+on
+break.
+.It Cm icrnl Pq Fl icrnl
+Map (do not map)
+.Dv CR
+to
+.Dv NL
+on input.
+.It Cm ignbrk Pq Fl ignbrk
+Ignore (do not ignore) break on input.
+.It Cm igncr Pq Fl igncr
+Ignore (do not ignore)
+.Dv CR
+on input.
+.It Cm ignpar Pq Fl ignpar
+Ignore (do not ignore) characters with parity errors.
+.It Cm imaxbel Pq Fl imaxbel
+The system imposes a limit of
+.Dv MAX_INPUT
+(currently 255) characters in the input queue. If
+.Cm imaxbel
+is set and the input queue limit has been reached,
+subsequent input causes the system to send an ASCII BEL
+character to the output queue (the terminal beeps at you). Otherwise,
+if
+.Cm imaxbel
+is unset and the input queue is full, the next input character causes
+the entire input and output queues to be discarded.
+.It Cm inlcr Pq Fl inlcr
+Map (do not map)
+.Dv NL
+to
+.Dv CR
+on input.
+.It Cm inpck Pq Fl inpck
+Enable (disable) input parity checking.
+.It Cm istrip Pq Fl istrip
+Strip (do not strip) input characters to seven bits.
+.It Cm iutf8 Pq Fl iutf8
+Assume input characters are UTF-8 encoded.
+.It Cm ixany Pq Fl ixany
+Allow any character (allow only
+.Dv START )
+to restart output.
+.It Cm ixoff Pq Fl ixoff
+Request that the system send (not send)
+.Dv START/STOP
+characters when the input queue is nearly empty/full.
+.It Cm ixon Pq Fl ixon
+Enable (disable)
+.Dv START/STOP
+output control.
+Output from the system is stopped when the system receives
+.Dv STOP
+and started when the system receives
+.Dv START ,
+or if
+.Cm ixany
+is set, any character restarts output.
+.It Cm parmrk Pq Fl parmrk
+Mark (do not mark) characters with parity errors.
+.El
+.Ss Output Modes:
+This corresponds to the c_oflag of the termios structure.
+.Bl -tag -width Fl
+.It Cm bs0 bs1
+Select the style of delay for backspaces (e.g., set BSDLY to BS0).
+.It Cm cr0 cr1 cr2 cr3
+Select the style of delay for carriage returns (e.g., set CRDLY to CR0).
+.It Cm ff0 ff1
+Select the style of delay for form feeds (e.g., set FFDLY to FF0).
+.It Cm nl0 nl1
+Select the style of delay for newlines (e.g., set NLDLY to NL0).
+.It Cm ocrnl Pq Fl ocrnl
+Map (do not map) carriage return to newline on output.
+.It Cm ofdel Pq Fl odell
+Use DELs (NULs) as fill characters.
+.It Cm ofill Pq Fl ofill
+Use fill characters (use timing) for delays.
+.It Cm onlcr Pq Fl onlcr
+Map (do not map)
+.Dv NL
+to
+.Dv CR-NL
+on output.
+.It Cm onlret Pq Fl onlret
+On the terminal, NL performs (does not perform) the CR function.
+.It Cm onocr Pq Fl onocr
+Do not (do) output CRs at column zero.
+.It Cm opost Pq Fl opost
+Post-process output (do not post-process output;
+ignore all other output modes).
+.It Cm oxtabs Pq Fl oxtabs
+Expand (do not expand) tabs to spaces on output.
+.It Cm tab0 tab1 tab2 tab3
+Select the style of delay for horizontal tabs (e.g., set TABDLY to TAB0).
+.It Cm tabs Pq Fl tabs
+Same as
+.Cm tab0
+.Cm ( tab3 ) .
+.It Cm vt0 vt1
+Select the style of delay for vertical tabs (e.g., set VTDLY to VT0).
+.El
+.Ss Local Modes:
+.Pp
+Local mode flags (lflags) affect various and sundry characteristics
+of terminal processing.
+Historically the term "local" pertained to new job control features
+implemented by Jim Kulp on a
+.Tn Pdp 11/70
+at
+.Tn IIASA .
+Later, the driver ran on the first
+.Tn VAX
+at Evans Hall, UC Berkeley, where the job control details
+were greatly modified,
+but the structure definitions and names remained essentially unchanged.
+The second interpretation of the 'l' in lflag
+is ``line discipline flag'', which corresponds to the
+.Ar c_lflag
+of the
+.Ar termios
+structure.
+.Bl -tag -width Fl
+.It Cm altwerase Pq Fl altwerase
+Use (do not use) an alternate word erase algorithm when processing
+.Dv WERASE
+characters.
+This alternate algorithm considers sequences of
+alphanumeric/underscores as words.
+It also skips the first preceding character in its classification
+(as a convenience, since the one preceding character could have been
+erased with simply an
+.Dv ERASE
+character.)
+.It Cm echo Pq Fl echo
+Echo back (do not echo back) every character typed.
+.It Cm echoctl Pq Fl echoctl
+If
+.Cm echoctl
+is set, echo control characters as ^X.
+Otherwise, control characters echo as themselves.
+.It Cm echoe Pq Fl echoe
+The
+.Dv ERASE
+character shall (shall not) visually erase the last character
+in the current line from the display, if possible.
+.It Cm echok Pq Fl echok
+Echo (do not echo)
+.Dv NL
+after
+.Dv KILL
+character.
+.It Cm echoke Pq Fl echoke
+The
+.Dv KILL
+character shall (shall
+not) visually erase the
+current line from the
+display, if possible.
+.It Cm echonl Pq Fl echonl
+Echo (do not echo)
+.Dv NL ,
+even if echo is disabled.
+.It Cm echoprt Pq Fl echoprt
+For printing terminals.
+If set, echo erased characters backwards within ``\\'' and ``/''.
+Otherwise, disable this feature.
+.It Cm flusho Pq Fl flusho
+Indicates output is (is not) being discarded.
+.It Cm icanon Pq Fl icanon
+Enable (disable) canonical input
+.Pf ( Dv ERASE
+and
+.Dv KILL
+processing).
+.It Cm iexten Pq Fl iexten
+Enable (disable) any implementation-defined special control characters
+that are not currently controlled by
+.Cm icanon ,
+.Cm isig ,
+.Cm ixoff ,
+or
+.Cm ixon .
+.It Cm isig Pq Fl isig
+Enable (disable) the checking of characters
+against the special control characters
+.Dv INTR , QUIT ,
+and
+.Dv SUSP .
+.It Cm mdmbuf Pq Fl mdmbuf
+If set, flow control output based on condition of Carrier Detect.
+Otherwise, writes return an error if Carrier Detect is low
+(and Carrier is not being ignored with the
+.Dv CLOCAL
+flag.)
+.It Cm noflsh Pq Fl noflsh
+Disable (enable) flush after
+.Dv INTR , QUIT ,
+or
+.Dv SUSP .
+.It Cm pendin Pq Fl pendin
+Indicates input is (is not) pending
+after a switch from non-canonical to canonical mode
+and will be re-input when a read becomes pending or more input arrives.
+.It Cm tostop Pq Fl tostop
+Send (do not send)
+.Dv SIGTTOU
+for background output.
+This causes background jobs to stop if they attempt terminal output.
+.El
+.Ss Control Characters:
+.Bl -tag -width Fl
+.It Ar control-character Ar string
+Set
+.Ar control-character
+to
+.Ar string .
+If string is a single character,
+the control character is set to
+that character.
+If string is the
+two character sequence "^-" or the
+string "undef" the control character
+is disabled (i.e. set to
+.Pf { Dv _POSIX_VDISABLE Ns } . )
+.Pp
+Recognized control-characters:
+.Bd -ragged -offset indent
+.Bl -column character Subscript
+.It control-
+.It character Ta Subscript Ta Description
+.It _________ Ta _________ Ta _______________
+.It eof Ta Tn VEOF Ta EOF No character
+.It eol Ta Tn VEOL Ta EOL No character
+.It eol2 Ta Tn VEOL2 Ta EOL2 No character
+.It erase Ta Tn VERASE Ta ERASE No character
+.It erase2 Ta Tn VERASE2 Ta ERASE2 No character
+.It werase Ta Tn VWERASE Ta WERASE No character
+.It intr Ta Tn VINTR Ta INTR No character
+.It kill Ta Tn VKILL Ta KILL No character
+.It quit Ta Tn VQUIT Ta QUIT No character
+.It susp Ta Tn VSUSP Ta SUSP No character
+.It start Ta Tn VSTART Ta START No character
+.It stop Ta Tn VSTOP Ta STOP No character
+.It dsusp Ta Tn VDSUSP Ta DSUSP No character
+.It lnext Ta Tn VLNEXT Ta LNEXT No character
+.It reprint Ta Tn VREPRINT Ta REPRINT No character
+.It status Ta Tn VSTATUS Ta STATUS No character
+.El
+.Ed
+.It Cm min Ar number
+.It Cm time Ar number
+Set the value of min or time to number.
+.Dv MIN
+and
+.Dv TIME
+are used in Non-Canonical mode input processing (-icanon).
+.El
+.Ss Combination Modes:
+.Pp
+.Bl -tag -width Fl
+.It Ar saved settings
+Set the current terminal characteristics
+to the saved settings produced by the
+.Fl g
+option.
+.It Cm cols Ar number
+Same as
+.Cm columns .
+.It Cm columns Ar number
+The terminal size is recorded as having
+.Ar number
+columns.
+.It Cm crt Pq Fl crt
+Set (disable) all modes suitable for a CRT display device.
+.It Cm dec
+Set modes suitable for users of Digital Equipment Corporation systems
+.Dv ( ERASE ,
+.Dv KILL ,
+and
+.Dv INTR
+characters are set to ^?, ^U, and ^C;
+.Dv ixany
+is disabled, and
+.Dv crt
+is enabled.)
+.It Cm ek
+Reset
+.Dv ERASE ,
+.Dv ERASE2 ,
+and
+.Dv KILL
+characters
+back to system defaults.
+.It Fl evenp
+Same as
+.Fl oddp
+and
+.Fl parity .
+.It Cm evenp
+Enable
+.Cm parenb
+and
+.Cm cs7 ;
+disable
+.Cm parodd .
+.It Cm extproc Pq Fl extproc
+If set, this flag indicates that some amount of terminal processing
+is being performed by either the terminal hardware
+or by the remote side connected to a pty.
+.It Cm kerninfo Pq Fl kerninfo
+Enable (disable) the system generated status line associated with
+processing a
+.Dv STATUS
+character (usually set to ^T). The status line consists of the
+system load average, the current command name, its process ID, the
+event the process is waiting on (or the status of the process), the user
+and system times, percent cpu, and current memory usage.
+.It Cm \&nl Pq Fl \&nl
+Enable (disable)
+.Cm icrnl .
+In addition,
+.Fl nl
+unsets
+.Cm inlcr
+and
+.Cm igncr .
+.It Fl oddp
+Same as
+.Fl evenp
+and
+.Fl parity .
+.It Cm oddp
+Enable
+.Cm parenb ,
+.Cm cs7 ,
+and
+.Cm parodd .
+.It Fl parity
+Disable
+.Cm parenb ;
+set
+.Cm cs8 .
+.It Cm parity
+Same as
+.Cm evenp .
+.It Cm raw Pq Fl raw
+If set, change the modes of the terminal
+so that no input or output processing is performed.
+If unset, change the modes of the terminal to some reasonable state
+that performs input and output processing.
+Note that since the terminal driver no longer has a single
+.Dv RAW
+bit, it is not possible to intuit what flags were set prior to setting
+.Cm raw .
+This means that unsetting
+.Cm raw
+may not put back all the setting that were previously in effect.
+To set the terminal into a raw state and then accurately restore it,
+the following shell code is recommended:
+.Bd -literal
+save_state=$(stty -g)
+stty raw
+\&...
+stty "$save_state"
+.Ed
+.It Cm rows Ar number
+The terminal size is recorded as having
+.Ar number
+rows.
+.It Cm sane
+Resets all modes to reasonable values for interactive terminal use.
+.It Cm size
+The size of the terminal is printed as two numbers on a single line,
+first rows, then columns.
+.It Cm tty
+Set the line discipline to the standard terminal line discipline
+.Dv TTYDISC .
+.El
+.Ss Compatibility Modes:
+.Pp
+These modes remain for compatibility with the previous version of
+the
+.Nm
+command.
+.Bl -tag -width Fl
+.It Cm all
+Reports all the terminal modes as with
+.Cm stty Fl a ,
+except that the control characters are printed in a columnar format.
+.It Cm brk Ar value
+Same as the control character
+.Cm eol .
+.It Cm cbreak
+If set, enables
+.Cm brkint , ixon , imaxbel , opost , isig , iexten ,
+and
+.Fl icanon .
+If unset, same as
+.Cm sane .
+.It Cm cooked
+Same as
+.Cm sane .
+.It Cm crtbs Pq Fl crtbs
+Same as
+.Cm echoe .
+.It Cm crterase Pq Fl crterase
+Same as
+.Cm echoe .
+.It Cm crtkill Pq Fl crtkill
+Same as
+.Cm echoke .
+.It Cm ctlecho Pq Fl ctlecho
+Same as
+.Cm echoctl .
+.It Cm decctlq Pq Fl decctlq
+The converse of
+.Cm ixany .
+.It Cm everything
+Same as
+.Cm all .
+.It Cm flush Ar value
+Same as the control character
+.Cm discard .
+.It Cm litout Pq Fl litout
+The converse of
+.Cm opost .
+.It Cm new
+Same as
+.Cm tty .
+.It Cm newcrt Pq Fl newcrt
+Same as
+.Cm crt .
+.It Cm old
+Same as
+.Cm tty .
+.It Cm pass8
+The converse of
+.Cm parity .
+.It Cm prterase Pq Fl prterase
+Same as
+.Cm echoprt .
+.It Cm rprnt Ar value
+Same as the control character
+.Cm reprint .
+.It Cm tabs Pq Fl tabs
+The converse of
+.Cm oxtabs .
+.It Cm tandem Pq Fl tandem
+Same as
+.Cm ixoff .
+.El
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh LEGACY DESCRIPTION
+In legacy operation, the
+.Cm bs[01] ,
+.Cm cr[0-3] ,
+.Cm ff[01] ,
+.Cm nl[01] ,
+.Cm tab[0-3] ,
+and
+.Cm vt[01]
+control modes are not accepted, nor are
+.Cm ocrnl Pq Fl ocrnl ,
+.Cm ofdel Pq Fl ofdel ,
+.Cm ofill Pq Fl ofill ,
+.Cm onlret Pq Fl onlret ,
+and
+.Cm onocr Pq Fl onocr .
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr termios 4 ,
+.Xr compat 5
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible. The flags
+.Fl e
+and
+.Fl f
+are
+extensions to the standard.
diff --git a/adv_cmds/stty/stty.c b/adv_cmds/stty/stty.c
new file mode 100644
index 0000000..a7feaf0
--- /dev/null
+++ b/adv_cmds/stty/stty.c
@@ -0,0 +1,164 @@
+/*-
+ * Copyright (c) 1989, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1989, 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)stty.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/stty.c,v 1.20 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "stty.h"
+#include "extern.h"
+
+int
+main(int argc, char *argv[])
+{
+ struct info i;
+ enum FMT fmt;
+ int ch;
+
+ fmt = NOTSET;
+ i.fd = STDIN_FILENO;
+
+ opterr = 0;
+ while (optind < argc &&
+ strspn(argv[optind], "-aefg") == strlen(argv[optind]) &&
+ (ch = getopt(argc, argv, "aef:g")) != -1)
+ switch(ch) {
+ case 'a': /* undocumented: POSIX compatibility */
+ fmt = POSIX;
+ break;
+ case 'e':
+ fmt = BSD;
+ break;
+ case 'f':
+ if ((i.fd = open(optarg, O_RDONLY | O_NONBLOCK)) < 0)
+ err(1, "%s", optarg);
+ break;
+ case 'g':
+ fmt = GFLAG;
+ break;
+ case '?':
+ default:
+ goto args;
+ }
+
+args: argc -= optind;
+ argv += optind;
+
+ if (tcgetattr(i.fd, &i.t) < 0)
+ errx(1, "stdin isn't a terminal");
+ if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0)
+ err(1, "TIOCGETD");
+ if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
+ warn("TIOCGWINSZ");
+
+ checkredirect(); /* conversion aid */
+
+ switch(fmt) {
+ case NOTSET:
+ if (*argv)
+ break;
+ /* FALLTHROUGH */
+ case BSD:
+ case POSIX:
+ print(&i.t, &i.win, i.ldisc, fmt);
+ break;
+ case GFLAG:
+ gprint(&i.t, &i.win, i.ldisc);
+ break;
+ }
+
+ for (i.set = i.wset = 0; *argv; ++argv) {
+ if (ksearch(&argv, &i))
+ continue;
+
+ if (csearch(&argv, &i))
+ continue;
+
+ if (msearch(&argv, &i))
+ continue;
+
+ if (isdigit(**argv)) {
+ speed_t speed;
+
+ speed = atoi(*argv);
+ cfsetospeed(&i.t, speed);
+ cfsetispeed(&i.t, speed);
+ i.set = 1;
+ continue;
+ }
+
+ if (!strncmp(*argv, "gfmt1", sizeof("gfmt1") - 1)) {
+ gread(&i.t, *argv + sizeof("gfmt1") - 1);
+ i.set = 1;
+ continue;
+ }
+
+ warnx("illegal option -- %s", *argv);
+ usage();
+ }
+
+ if (i.set && tcsetattr(i.fd, 0, &i.t) < 0)
+ err(1, "tcsetattr");
+ if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
+ warn("TIOCSWINSZ");
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: stty [-a|-e|-g] [-f file] [options]\n");
+ exit (1);
+}
diff --git a/adv_cmds/stty/stty.h b/adv_cmds/stty/stty.h
new file mode 100644
index 0000000..91c710f
--- /dev/null
+++ b/adv_cmds/stty/stty.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)stty.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: src/bin/stty/stty.h,v 1.8 2001/05/18 11:04:19 kris Exp $
+ */
+
+#include <sys/ioctl.h>
+#include <termios.h>
+
+struct info {
+ int fd; /* file descriptor */
+ int ldisc; /* line discipline */
+ int off; /* turn off */
+ int set; /* need set */
+ int wset; /* need window set */
+ const char *arg; /* argument */
+ struct termios t; /* terminal info */
+ struct winsize win; /* window info */
+};
+
+struct cchar {
+ const char *name;
+ int sub;
+ u_char def;
+};
+
+enum FMT { NOTSET, GFLAG, BSD, POSIX };
+
+#define LINELENGTH 72
diff --git a/adv_cmds/stty/util.c b/adv_cmds/stty/util.c
new file mode 100644
index 0000000..9695365
--- /dev/null
+++ b/adv_cmds/stty/util.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/stty/util.c,v 1.10 2002/06/30 05:15:04 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "stty.h"
+#include "extern.h"
+
+/*
+ * Gross, but since we're changing the control descriptor from 1 to 0, most
+ * users will be probably be doing "stty > /dev/sometty" by accident. If 1
+ * and 2 are both ttys, but not the same, assume that 1 was incorrectly
+ * redirected.
+ */
+void
+checkredirect(void)
+{
+ struct stat sb1, sb2;
+
+ if (isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) &&
+ !fstat(STDOUT_FILENO, &sb1) && !fstat(STDERR_FILENO, &sb2) &&
+ (sb1.st_rdev != sb2.st_rdev))
+warnx("stdout appears redirected, but stdin is the control descriptor");
+}
diff --git a/adv_cmds/tabs/tabs.1 b/adv_cmds/tabs/tabs.1
new file mode 100644
index 0000000..b2f8523
--- /dev/null
+++ b/adv_cmds/tabs/tabs.1
@@ -0,0 +1,160 @@
+.\" Copyright (c) 2002 Tim J. Robbins.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/tabs/tabs.1,v 1.7 2005/01/17 07:44:29 ru Exp $
+.\"
+.Dd May 20, 2002
+.Dt TABS 1
+.Os
+.Sh NAME
+.Nm tabs
+.Nd set terminal tabs
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ar n | Fl a | a2 | c | c2 | c3 | f | p | s | u
+.Op Cm +m Ns Op Ar n
+.Op Fl T Ar type
+.Nm
+.Op Fl T Ar type
+.Op Cm + Ns Op Ar n
+.Ar n1 Ns Op Ns , Ns Ar n2 , Ns ...
+.Sh DESCRIPTION
+The
+.Nm
+utility displays a series of characters that clear the hardware terminal
+tab settings then initialises tab stops at specified positions, and
+optionally adjusts the margin.
+.Pp
+In the first synopsis form, the tab stops set depend on the command line
+options used, and may be one of the predefined formats or at regular
+intervals.
+.Pp
+In the second synopsis form, tab stops are set at positions
+.Ar n1 , n2 ,
+etc.
+If a position is preceded by a
+.Ql + ,
+it is relative to the previous position set.
+No more than 20 positions may be specified.
+.Pp
+If no tab stops are specified, the
+.Dq standard
+.Ux
+tab width of 8 is used.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl Ar n
+Set a tab stop every
+.Ar n
+columns.
+If
+.Ar n
+is 0, the tab stops are cleared but no new ones are set.
+.It Fl a
+Assembler format (columns 1, 10, 16, 36, 72).
+.It Fl a2
+Assembler format (columns 1, 10, 16, 40, 72).
+.It Fl c
+.Tn COBOL
+normal format (columns 1, 8, 12, 16, 20, 55)
+.It Fl c2
+.Tn COBOL
+compact format (columns 1, 6, 10, 14, 49)
+.It Fl c3
+.Tn COBOL
+compact format (columns 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46,
+50, 54, 58, 62, 67).
+.It Fl f
+.Tn FORTRAN
+format (columns 1, 7, 11, 15, 19, 23).
+.It Fl p
+.Tn PL/1
+format (columns 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53,
+57, 61).
+.It Fl s
+.Tn SNOBOL
+format (columns 1, 10, 55).
+.It Fl u
+Assembler format (columns 1, 12, 20, 44).
+.It Xo
+.Cm +m Ns Op Ar n ,
+.Cm + Ns Op Ar n
+.Xc
+Set an
+.Ar n
+character left margin, or 10 if
+.Ar n
+is omitted.
+.It Fl T Ar type
+Output escape sequence for the terminal type
+.Ar type .
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_CTYPE
+and
+.Ev TERM
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Pp
+The
+.Fl T
+option overrides the setting of the
+.Ev TERM
+environment variable.
+If neither
+.Ev TERM
+nor the
+.Fl T
+option are present,
+.Nm
+will fail.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr expand 1 ,
+.Xr stty 1 ,
+.Xr tput 1 ,
+.Xr unexpand 1 ,
+.Xr termcap 5
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in PWB UNIX.
+This implementation was introduced in
+.Fx 5.0 .
+.Sh BUGS
+The current
+.Xr termcap 5
+database does not define the
+.Ql ML
+(set left soft margin) capability for any terminals.
diff --git a/adv_cmds/tabs/tabs.c b/adv_cmds/tabs/tabs.c
new file mode 100644
index 0000000..8130b8b
--- /dev/null
+++ b/adv_cmds/tabs/tabs.c
@@ -0,0 +1,240 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * 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.
+ */
+
+/*
+ * tabs -- set terminal tabs
+ *
+ * This utility displays a series of characters that clears the terminal
+ * hardware tab settings, then initialises them to specified values,
+ * and optionally sets a soft margin.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tabs/tabs.c,v 1.3 2002/06/08 11:33:22 tjr Exp $");
+
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif
+#include <sys/types.h>
+#include <sys/tty.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <term.h>
+#include <unistd.h>
+
+/* Maximum number of tab stops allowed in table. */
+#define NSTOPS 20
+
+#define NELEMS(a) (sizeof(a) / sizeof(a[0]))
+
+/* Predefined formats, taken from IEEE Std 1003.1-2001. */
+static const struct {
+ const char *name; /* Format name used on cmd. line */
+ long stops[NSTOPS]; /* Column positions */
+} formats[] = {
+ { "a", { 1, 10, 16, 36, 72 } },
+ { "a2", { 1, 10, 16, 40, 72 } },
+ { "c", { 1, 8, 12, 16, 20, 55 } },
+ { "c2", { 1, 6, 10, 14, 49 } },
+ { "c3", { 1, 6, 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 50, 54, 58,
+ 62, 67 } },
+ { "f", { 1, 7, 11, 15, 19, 23 } },
+ { "p", { 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57,
+ 61 } },
+ { "s", { 1, 10, 55 } },
+ { "u", { 1, 12, 20, 44 } }
+};
+
+static void gettabs(char *, long *, long *);
+static int ttywidth(void);
+static void usage(void);
+
+int
+main(int argc __unused, char *argv[])
+{
+ long cols, i, inc, j, margin, nstops, stops[NSTOPS];
+ const char *cr, *ct, *st, *ML;
+ char area[1024], *ap, *arg, *end;
+
+ setlocale(LC_ALL, "");
+
+ inc = 8;
+ margin = 0;
+ nstops = -1;
+ while ((arg = *++argv) != NULL && (*arg == '-' || *arg == '+')) {
+ if (*arg == '+') {
+ /* +m[n] or +[n] */
+ if (*++arg == 'm')
+ arg++;
+ if (*arg != '\0') {
+ errno = 0;
+ margin = strtol(arg, &end, 10);
+ if (errno != 0 || *end != '\0' || margin < 0)
+ errx(1, "%s: invalid margin width",
+ arg);
+ } else
+ margin = 10;
+ } else if (isdigit(arg[1])) {
+ /* -n */
+ errno = 0;
+ inc = strtol(arg + 1, &end, 10);
+ if (errno != 0 || *end != '\0' || inc < 0)
+ errx(1, "%s: invalid increment", arg + 1);
+ } else if (arg[1] == 'T') {
+ /* -Ttype or -T type */
+ if (arg[2] != '\0')
+ setenv("TERM", arg + 2, 1);
+ else {
+ if ((arg = *++argv) == NULL)
+ usage();
+ setenv("TERM", arg, 1);
+ }
+ } else if (arg[1] == '-') {
+ arg = *++argv;
+ break;
+ } else {
+ /* Predefined format */
+ for (i = 0; i < (int)NELEMS(formats); i++)
+ if (strcmp(formats[i].name, arg + 1) == 0)
+ break;
+ if (i == NELEMS(formats))
+ usage();
+ for (j = nstops = 0; j < NSTOPS &&
+ formats[i].stops[j] != 0; j++)
+ stops[nstops++] = formats[i].stops[j];
+ }
+ }
+
+ if (arg != NULL) {
+ if (nstops != -1)
+ usage();
+ gettabs(arg, stops, &nstops);
+ }
+
+ /* Initialise terminal, get the strings we need */
+ setupterm(NULL, 1, NULL);
+ ap = area;
+ if ((ct = tgetstr("ct", &ap)) == NULL)
+ errx(1, "terminal cannot clear tabs");
+ if ((st = tgetstr("st", &ap)) == NULL)
+ errx(1, "terminal cannot set tabs");
+ if ((cr = tgetstr("cr", &ap)) == NULL)
+ cr = "\r";
+ ML = tgetstr("ML", &ap);
+ cols = ttywidth();
+
+ /* Clear all tabs. */
+ putp(cr);
+ putp(ct);
+
+ /*
+ * Set soft margin.
+ * XXX Does this actually work?
+ */
+ if (ML != NULL) {
+ printf("%*s", (int)margin, "");
+ putp(ML);
+ } else if (margin != 0)
+ warnx("terminal cannot set left margin");
+
+ /* Optionally output new tab stops. */
+ if (nstops >= 0) {
+ printf("%*s", (int)stops[0] - 1, "");
+ putp(st);
+ for (i = 1; i < nstops; i++) {
+ printf("%*s", (int)(stops[i] - stops[i - 1]), "");
+ putp(st);
+ }
+ } else if (inc > 0) {
+ for (i = 0; i < cols / inc; i++) {
+ putp(st);
+ printf("%*s", (int)inc, "");
+ }
+ putp(st);
+ }
+ putp(cr);
+
+ exit(0);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+"usage: tabs [-n|-a|-a2|-c|-c2|-c3|-f|-p|-s|-u] [+m[n]] [-T type]\n");
+ fprintf(stderr,
+" tabs [-T type] [+[n]] n1,[n2,...]\n");
+ exit(1);
+}
+
+static void
+gettabs(char *arg, long stops[], long *nstops)
+{
+ char *tok, *end;
+ long last, stop;
+
+ for (last = *nstops = 0, tok = strtok(arg, ","); tok != NULL;
+ tok = strtok(NULL, ",")) {
+ if (*nstops >= NSTOPS)
+ errx(1, "too many tab stops (limit %d)", NSTOPS);
+ errno = 0;
+ stop = strtol(tok, &end, 10);
+ if (errno != 0 || *end != '\0' || stop <= 0)
+ errx(1, "%s: invalid tab stop", tok);
+ if (*tok == '+') {
+ if (tok == arg)
+ errx(1, "%s: first tab may not be relative",
+ tok);
+ stop += last;
+ }
+ if (last > stop)
+ errx(1, "cannot go backwards");
+ last = stops[(*nstops)++] = stop;
+ }
+}
+
+static int
+ttywidth(void)
+{
+ struct winsize ws;
+ int width;
+
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
+ width = ws.ws_col;
+ else if ((width = tgetnum("co")) == 0) {
+ width = 80;
+ warnx("cannot find terminal width; defaulted to %d", width);
+ }
+
+ return (width);
+}
diff --git a/adv_cmds/tty/tty.1 b/adv_cmds/tty/tty.1
new file mode 100644
index 0000000..1fd66b8
--- /dev/null
+++ b/adv_cmds/tty/tty.1
@@ -0,0 +1,87 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tty.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/tty/tty.1,v 1.9 2006/12/13 20:15:49 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt TTY 1
+.Os
+.Sh NAME
+.Nm tty
+.Nd return user's terminal name
+.Sh SYNOPSIS
+.Nm
+.Op Fl s
+.Sh DESCRIPTION
+The
+.Nm
+utility writes the name of the terminal attached to standard input
+to standard output.
+The name that is written is the string returned by
+.Xr ttyname 3 .
+If the standard input is not a terminal, the message
+.Dq Li "not a tty"
+is written.
+The options are as follows:
+.Bl -tag -width indent
+.It Fl s
+Do not write the terminal name; only the exit status is affected
+when this option is specified.
+The
+.Fl s
+option is deprecated in favor of the
+.Dq Li "test -t 0"
+command.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility
+exits 0 if the standard input is a terminal, 1 if the standard input is
+not a terminal, and >1 if an error occurs.
+.Sh SEE ALSO
+.Xr test 1 ,
+.Xr ttyname 3
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/adv_cmds/tty/tty.c b/adv_cmds/tty/tty.c
new file mode 100644
index 0000000..806fe4b
--- /dev/null
+++ b/adv_cmds/tty/tty.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tty/tty.c,v 1.9 2002/05/29 17:12:30 jmallett Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, sflag;
+ char *t;
+
+ sflag = 0;
+ while ((ch = getopt(argc, argv, "s")) != -1)
+ switch (ch) {
+ case 's':
+ sflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ t = ttyname(0);
+ if (!sflag)
+ puts(t ? t : "not a tty");
+ exit(t ? 0 : 1);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: tty [-s]\n");
+ exit(2);
+}
diff --git a/adv_cmds/whois/whois.1 b/adv_cmds/whois/whois.1
new file mode 100644
index 0000000..0177b48
--- /dev/null
+++ b/adv_cmds/whois/whois.1
@@ -0,0 +1,287 @@
+.\" Copyright (c) 1985, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" From: @(#)whois.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd April 25, 2016
+.Dt WHOIS 1
+.Os
+.Sh NAME
+.Nm whois
+.Nd "Internet domain name and network number directory service"
+.Sh SYNOPSIS
+.Nm
+.Op Fl aAbfgiIklmPQrRS
+.Op Fl c Ar TLD | Fl h Ar host
+.Op Fl p Ar port
+.Op Fl -
+.Ar name ...
+.Sh DESCRIPTION
+The
+.Nm
+utility looks up records in the databases maintained by several
+Network Information Centers
+.Pq Tn NICs .
+.Pp
+By default
+.Nm
+starts by querying the Internet Assigned Numbers Authority (IANA) whois server,
+and follows referrals to whois servers
+that have more specific details about the query
+.Ar name .
+The IANA whois server knows about
+IP address and AS numbers
+as well as domain names.
+.Pp
+There are a few special cases where referrals do not work, so
+.Nm
+goes directly to the appropriate server.
+These include point-of-contact handles for ARIN,
+.Pa nic.at ,
+NORID, and RIPE,
+and domain names under
+.Pa ac.uk .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a
+Use the American Registry for Internet Numbers
+.Pq Tn ARIN
+database.
+It contains network numbers used in those parts of the world covered neither by
+.Tn APNIC , AfriNIC , LACNIC ,
+nor by
+.Tn RIPE .
+The query syntax is documented at
+.Pa https://www.arin.net/resources/whoisrws/whois_api.html#nicname
+.It Fl A
+Use the Asia/Pacific Network Information Center
+.Pq Tn APNIC
+database.
+It contains network numbers used in East Asia, Australia,
+New Zealand, and the Pacific islands.
+Get query syntax documentation using
+.Ic whois -A help
+.It Fl b
+Use the Network Abuse Clearinghouse database.
+It contains addresses to which network abuse should be reported,
+indexed by domain name.
+.It Fl c Ar TLD
+This is the equivalent of using the
+.Fl h
+option with an argument of
+.Qq Ar TLD Ns Li .whois-servers.net .
+This can be helpful for locating country-class TLD whois servers.
+.It Fl f
+Use the African Network Information Centre
+.Pq Tn AfriNIC
+database.
+It contains network numbers used in Africa and the islands of the
+western Indian Ocean.
+Get query syntax documentation using
+.Ic whois -f help
+.It Fl g
+Use the US non-military federal government database, which contains points of
+contact for subdomains of
+.Pa .GOV .
+.It Fl h Ar host
+Use the specified host instead of the default.
+Either a host name or an IP address may be specified.
+.It Fl i
+Use the traditional Network Information Center (InterNIC)
+.Pq Pa whois.internic.net
+database.
+This now contains only registrations for domain names under
+.Pa .COM ,
+.Pa .NET ,
+.Pa .EDU .
+You can specify the type of object to search for like
+.Ic whois -i ' Ns Ar type Ar name Ns Ic '
+where
+.Ar type
+can be
+.Nm domain , nameserver , registrar .
+The
+.Ar name
+can contain
+.Li *
+wildcards.
+.It Fl I
+Use the Internet Assigned Numbers Authority
+.Pq Tn IANA
+database.
+.It Fl k
+Use the National Internet Development Agency of Korea's
+.Pq Tn KRNIC
+database.
+It contains network numbers and domain contact information
+for Korea.
+.It Fl l
+Use the Latin American and Caribbean IP address Regional Registry
+.Pq Tn LACNIC
+database.
+It contains network numbers used in much of Latin America and the
+Caribbean.
+.It Fl m
+Use the Route Arbiter Database
+.Pq Tn RADB
+database.
+It contains route policy specifications for a large
+number of operators' networks.
+.It Fl p Ar port
+Connect to the whois server on
+.Ar port .
+If this option is not specified,
+.Nm
+defaults to port 43.
+.It Fl P
+Use the PeeringDB database of AS numbers.
+It contains details about presence at internet peering points
+for many network operators.
+.It Fl Q
+Do a quick lookup;
+.Nm
+will not attempt to follow referrals to other whois servers.
+This is the default if a server is explicitly specified
+using one of the other options or in an environment variable.
+See also the
+.Fl R
+option.
+.It Fl r
+Use the R\(aaeseaux IP Europ\(aaeens
+.Pq Tn RIPE
+database.
+It contains network numbers and domain contact information
+for Europe.
+Get query syntax documentation using
+.Ic whois -r help
+.It Fl R
+Do a recursive lookup;
+.Nm
+will attempt to follow referrals to other whois servers.
+This is the default if no server is explicitly specified.
+See also the
+.Fl Q
+option.
+.It Fl S
+By default
+.Nm
+adjusts simple queries (without spaces) to produce more useful output
+from certain whois servers,
+and it suppresses some uninformative output.
+With the
+.Fl S
+option,
+.Nm
+sends the query and prints the output verbatim.
+.El
+.Pp
+The operands specified to
+.Nm
+are treated independently and may be used
+as queries on different whois servers.
+.Sh ENVIRONMENT
+.Bl -tag -width WHOIS_SERVER
+.It Ev WHOIS_SERVER
+The primary default whois server.
+If this is unset,
+.Nm
+uses the
+.Ev RA_SERVER
+environment variable.
+.It Ev RA_SERVER
+The secondary default whois server.
+If this is unset,
+.Nm
+will use
+.Pa whois.iana.org .
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+To obtain contact information about an
+administrator located in the Russian
+.Tn TLD
+domain
+.Qq Li RU ,
+use the
+.Fl c
+option as shown in the following example, where
+.Ar CONTACT-ID
+is substituted with the actual contact identifier.
+.Pp
+.Dl Ic whois -c RU CONTACT-ID
+.Pp
+(Note: This example is specific to the
+.Tn TLD
+.Qq Li RU ,
+but other
+.Tn TLDs
+can be queried by using a similar syntax.)
+.Pp
+The following example demonstrates how to query
+a whois server using a non-standard port, where
+.Dq Li query-data
+is the query to be sent to
+.Dq Li whois.example.com
+on port
+.Dq Li rwhois
+(written numerically as 4321).
+.Pp
+.Dl Ic whois -h whois.example.com -p rwhois query-data
+.Pp
+Some whois servers support complex queries
+with dash-letter options.
+You can use the
+.Fl -
+option to separate
+.Nm
+command options from whois server query options.
+A query containing spaces must be quoted as one
+argument to the
+.Nm
+command.
+The following example asks the RIPE whois server
+to return a brief description of its
+.Dq Li domain
+object type:
+.Pp
+.Dl Ic whois -r -- '-t domain'
+.Sh SEE ALSO
+.Rs
+.%A Ken Harrenstien
+.%A Vic White
+.%T NICNAME/WHOIS
+.%D 1 March 1982
+.%O RFC 812
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/adv_cmds/whois/whois.c b/adv_cmds/whois/whois.c
new file mode 100644
index 0000000..a6c4f6c
--- /dev/null
+++ b/adv_cmds/whois/whois.c
@@ -0,0 +1,629 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)whois.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifdef __APPLE__
+#ifndef SOCK_NONBLOCK
+#define SOCK_NONBLOCK 0
+#endif
+#ifndef INFTIM
+#define INFTIM -1
+#endif
+#endif
+
+#define ABUSEHOST "whois.abuse.net"
+#define ANICHOST "whois.arin.net"
+#define DENICHOST "whois.denic.de"
+#define DKNICHOST "whois.dk-hostmaster.dk"
+#define FNICHOST "whois.afrinic.net"
+#define GNICHOST "whois.nic.gov"
+#define IANAHOST "whois.iana.org"
+#define INICHOST "whois.internic.net"
+#define KNICHOST "whois.krnic.net"
+#define LNICHOST "whois.lacnic.net"
+#define MNICHOST "whois.ra.net"
+#define PDBHOST "whois.peeringdb.com"
+#define PNICHOST "whois.apnic.net"
+#define QNICHOST_TAIL ".whois-servers.net"
+#define RNICHOST "whois.ripe.net"
+#define VNICHOST "whois.verisign-grs.com"
+
+#ifdef __APPLE__
+#define DEFAULT_PORT "nicname"
+#else
+#define DEFAULT_PORT "whois"
+#endif
+
+#define WHOIS_RECURSE 0x01
+#define WHOIS_QUICK 0x02
+#define WHOIS_SPAM_ME 0x04
+
+#define CHOPSPAM ">>> Last update of WHOIS database:"
+
+#define ishost(h) (isalnum((unsigned char)h) || h == '.' || h == '-')
+
+#define SCAN(p, end, check) \
+ while ((p) < (end)) \
+ if (check) ++(p); \
+ else break
+
+static struct {
+ const char *suffix, *server;
+} whoiswhere[] = {
+ /* Various handles */
+ { "-ARIN", ANICHOST },
+ { "-NICAT", "at" QNICHOST_TAIL },
+ { "-NORID", "no" QNICHOST_TAIL },
+ { "-RIPE", RNICHOST },
+ /* Nominet's whois server doesn't return referrals to JANET */
+ { ".ac.uk", "ac.uk" QNICHOST_TAIL },
+ { ".gov.uk", "ac.uk" QNICHOST_TAIL },
+ { "", IANAHOST }, /* default */
+ { NULL, NULL } /* safety belt */
+};
+
+#define WHOIS_REFERRAL(s) { s, sizeof(s) - 1 }
+static struct {
+ const char *prefix;
+ size_t len;
+} whois_referral[] = {
+ WHOIS_REFERRAL("whois:"), /* IANA */
+ WHOIS_REFERRAL("Whois Server:"),
+ WHOIS_REFERRAL("Registrar WHOIS Server:"), /* corporatedomains.com */
+ WHOIS_REFERRAL("ReferralServer: whois://"), /* ARIN */
+ WHOIS_REFERRAL("descr: region. Please query"), /* AfriNIC */
+ { NULL, 0 }
+};
+
+/*
+ * We have a list of patterns for RIRs that assert ignorance rather than
+ * providing referrals. If that happens, we guess that ARIN will be more
+ * helpful. But, before following a referral to an RIR, we check if we have
+ * asked that RIR already, and if so we make another guess.
+ */
+static const char *actually_arin[] = {
+ "netname: ERX-NETBLOCK\n", /* APNIC */
+ "netname: NON-RIPE-NCC-MANAGED-ADDRESS-BLOCK\n",
+ NULL
+};
+
+static struct {
+ int loop;
+ const char *host;
+} try_rir[] = {
+ { 0, ANICHOST },
+ { 0, RNICHOST },
+ { 0, PNICHOST },
+ { 0, FNICHOST },
+ { 0, LNICHOST },
+ { 0, NULL }
+};
+
+static void
+reset_rir(void) {
+ int i;
+
+ for (i = 0; try_rir[i].host != NULL; i++)
+ try_rir[i].loop = 0;
+}
+
+static const char *port = DEFAULT_PORT;
+
+static const char *choose_server(char *);
+static struct addrinfo *gethostinfo(char const *host, int exitnoname);
+#ifdef __APPLE__
+static void s_asprintf(char **ret, const char *format, ...) __attribute__((__format__(printf, 2, 3)));
+#else
+static void s_asprintf(char **ret, const char *format, ...) __printflike(2, 3);
+#endif
+static void usage(void);
+static void whois(const char *, const char *, int);
+
+int
+main(int argc, char *argv[])
+{
+ const char *country, *host;
+ int ch, flags;
+
+#ifdef SOCKS
+ SOCKSinit(argv[0]);
+#endif
+
+ country = host = NULL;
+ flags = 0;
+ while ((ch = getopt(argc, argv, "aAbc:fgh:iIklmp:PQrRS")) != -1) {
+ switch (ch) {
+ case 'a':
+ host = ANICHOST;
+ break;
+ case 'A':
+ host = PNICHOST;
+ break;
+ case 'b':
+ host = ABUSEHOST;
+ break;
+ case 'c':
+ country = optarg;
+ break;
+ case 'f':
+ host = FNICHOST;
+ break;
+ case 'g':
+ host = GNICHOST;
+ break;
+ case 'h':
+ host = optarg;
+ break;
+ case 'i':
+ host = INICHOST;
+ break;
+ case 'I':
+ host = IANAHOST;
+ break;
+ case 'k':
+ host = KNICHOST;
+ break;
+ case 'l':
+ host = LNICHOST;
+ break;
+ case 'm':
+ host = MNICHOST;
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 'P':
+ host = PDBHOST;
+ break;
+ case 'Q':
+ flags |= WHOIS_QUICK;
+ break;
+ case 'r':
+ host = RNICHOST;
+ break;
+ case 'R':
+ flags |= WHOIS_RECURSE;
+ break;
+ case 'S':
+ flags |= WHOIS_SPAM_ME;
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!argc || (country != NULL && host != NULL))
+ usage();
+
+ /*
+ * If no host or country is specified, rely on referrals from IANA.
+ */
+ if (host == NULL && country == NULL) {
+ if ((host = getenv("WHOIS_SERVER")) == NULL &&
+ (host = getenv("RA_SERVER")) == NULL) {
+ if (!(flags & WHOIS_QUICK))
+ flags |= WHOIS_RECURSE;
+ }
+ }
+ while (argc-- > 0) {
+ if (country != NULL) {
+ char *qnichost;
+ s_asprintf(&qnichost, "%s%s", country, QNICHOST_TAIL);
+ whois(*argv, qnichost, flags);
+ free(qnichost);
+ } else
+ whois(*argv, host != NULL ? host :
+ choose_server(*argv), flags);
+ reset_rir();
+ argv++;
+ }
+ exit(0);
+}
+
+static const char *
+choose_server(char *domain)
+{
+ size_t len = strlen(domain);
+ int i;
+
+ for (i = 0; whoiswhere[i].suffix != NULL; i++) {
+ size_t suffix_len = strlen(whoiswhere[i].suffix);
+ if (len > suffix_len &&
+ strcasecmp(domain + len - suffix_len,
+ whoiswhere[i].suffix) == 0)
+ return (whoiswhere[i].server);
+ }
+ errx(EX_SOFTWARE, "no default whois server");
+}
+
+static struct addrinfo *
+gethostinfo(char const *host, int exit_on_noname)
+{
+ struct addrinfo hints, *res;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ res = NULL;
+ error = getaddrinfo(host, port, &hints, &res);
+ if (error && (exit_on_noname || error != EAI_NONAME))
+ err(EX_NOHOST, "%s: %s", host, gai_strerror(error));
+ return (res);
+}
+
+/*
+ * Wrapper for asprintf(3) that exits on error.
+ */
+static void
+s_asprintf(char **ret, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+ if (vasprintf(ret, format, ap) == -1) {
+ va_end(ap);
+ err(EX_OSERR, "vasprintf()");
+ }
+ va_end(ap);
+}
+
+static int
+connect_to_any_host(struct addrinfo *hostres)
+{
+ struct addrinfo *res;
+ nfds_t i, j;
+ size_t count;
+ struct pollfd *fds;
+ int timeout = 180, s = -1;
+
+ for (res = hostres, count = 0; res; res = res->ai_next)
+ count++;
+ fds = calloc(count, sizeof(*fds));
+ if (fds == NULL)
+ err(EX_OSERR, "calloc()");
+
+ /*
+ * Traverse the result list elements and make non-block
+ * connection attempts.
+ */
+ count = i = 0;
+ for (res = hostres; res != NULL; res = res->ai_next) {
+ s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
+ res->ai_protocol);
+ if (s < 0)
+ continue;
+#ifdef __APPLE__
+ int flags = fcntl(s, F_GETFL, 0);
+ if (flags < 0) {
+ close(s);
+ continue;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(s, F_SETFL, flags) != 0) {
+ close(s);
+ continue;
+ }
+#endif
+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ if (errno == EINPROGRESS) {
+ /* Add the socket to poll list */
+ fds[i].fd = s;
+ fds[i].events = POLLERR | POLLHUP |
+ POLLIN | POLLOUT;
+ /*
+ * From here until a socket connects, the
+ * socket fd is owned by the fds[] poll array.
+ */
+ s = -1;
+ count++;
+ i++;
+ } else {
+ close(s);
+ s = -1;
+
+ /*
+ * Poll only if we have something to poll,
+ * otherwise just go ahead and try next
+ * address
+ */
+ if (count == 0)
+ continue;
+ }
+ } else
+ goto done;
+
+ /*
+ * If we are at the last address, poll until a connection is
+ * established or we failed all connection attempts.
+ */
+ if (res->ai_next == NULL)
+ timeout = INFTIM;
+
+ /*
+ * Poll the watched descriptors for successful connections:
+ * if we still have more untried resolved addresses, poll only
+ * once; otherwise, poll until all descriptors have errors,
+ * which will be considered as ETIMEDOUT later.
+ */
+ do {
+ int n;
+
+ n = poll(fds, i, timeout);
+ if (n == 0) {
+ /*
+ * No event reported in time. Try with a
+ * smaller timeout (but cap at 2-3ms)
+ * after a new host have been added.
+ */
+ if (timeout >= 3)
+ timeout >>= 1;
+
+ break;
+ } else if (n < 0) {
+ /*
+ * errno here can only be EINTR which we would
+ * want to clean up and bail out.
+ */
+ s = -1;
+ goto done;
+ }
+
+ /*
+ * Check for the event(s) we have seen.
+ */
+ for (j = 0; j < i; j++) {
+ if (fds[j].fd == -1 || fds[j].events == 0 ||
+ fds[j].revents == 0)
+ continue;
+ if (fds[j].revents & ~(POLLIN | POLLOUT)) {
+ close(fds[j].fd);
+ fds[j].fd = -1;
+ fds[j].events = 0;
+ count--;
+ continue;
+ } else if (fds[j].revents & (POLLIN | POLLOUT)) {
+ /* Connect succeeded. */
+ s = fds[j].fd;
+ fds[j].fd = -1;
+
+ goto done;
+ }
+
+ }
+ } while (timeout == INFTIM && count != 0);
+ }
+
+ /* All attempts were failed */
+ s = -1;
+ if (count == 0)
+ errno = ETIMEDOUT;
+
+done:
+ /* Close all watched fds except the succeeded one */
+ for (j = 0; j < i; j++)
+ if (fds[j].fd != -1)
+ close(fds[j].fd);
+ free(fds);
+ return (s);
+}
+
+static void
+whois(const char *query, const char *hostname, int flags)
+{
+ FILE *fp;
+ struct addrinfo *hostres;
+ char *buf, *host, *nhost, *p;
+ int comment, s, f;
+ size_t len, i;
+
+ hostres = gethostinfo(hostname, 1);
+ s = connect_to_any_host(hostres);
+ if (s == -1)
+ err(EX_OSERR, "connect()");
+
+ /* Restore default blocking behavior. */
+ if ((f = fcntl(s, F_GETFL)) == -1)
+ err(EX_OSERR, "fcntl()");
+ f &= ~O_NONBLOCK;
+ if (fcntl(s, F_SETFL, f) == -1)
+ err(EX_OSERR, "fcntl()");
+
+ fp = fdopen(s, "r+");
+ if (fp == NULL)
+ err(EX_OSERR, "fdopen()");
+
+ if (!(flags & WHOIS_SPAM_ME) &&
+ (strcasecmp(hostname, DENICHOST) == 0 ||
+ strcasecmp(hostname, "de" QNICHOST_TAIL) == 0)) {
+ const char *q;
+ int idn = 0;
+ for (q = query; *q != '\0'; q++)
+ if (!isascii(*q))
+ idn = 1;
+ fprintf(fp, "-T dn%s %s\r\n", idn ? "" : ",ace", query);
+ } else if (!(flags & WHOIS_SPAM_ME) &&
+ (strcasecmp(hostname, DKNICHOST) == 0 ||
+ strcasecmp(hostname, "dk" QNICHOST_TAIL) == 0))
+ fprintf(fp, "--show-handles %s\r\n", query);
+ else if ((flags & WHOIS_SPAM_ME) ||
+ strchr(query, ' ') != NULL)
+ fprintf(fp, "%s\r\n", query);
+ else if (strcasecmp(hostname, ANICHOST) == 0) {
+ if (strncasecmp(query, "AS", 2) == 0 &&
+ strspn(query+2, "0123456789") == strlen(query+2))
+ fprintf(fp, "+ a %s\r\n", query+2);
+ else
+ fprintf(fp, "+ %s\r\n", query);
+ } else if (strcasecmp(hostres->ai_canonname, VNICHOST) == 0)
+ fprintf(fp, "domain %s\r\n", query);
+ else
+ fprintf(fp, "%s\r\n", query);
+ fflush(fp);
+
+ comment = 0;
+ if (!(flags & WHOIS_SPAM_ME) &&
+ (strcasecmp(hostname, ANICHOST) == 0 ||
+ strcasecmp(hostname, RNICHOST) == 0)) {
+ comment = 2;
+ }
+
+ nhost = NULL;
+ while ((buf = fgetln(fp, &len)) != NULL) {
+ /* Nominet */
+ if (!(flags & WHOIS_SPAM_ME) &&
+ len == 5 && strncmp(buf, "-- \r\n", 5) == 0)
+ break;
+ /* RIRs */
+ if (comment == 1 && buf[0] == '#')
+ break;
+ else if (comment == 2) {
+ if (strchr("#%\r\n", buf[0]) != NULL)
+ continue;
+ else
+ comment = 1;
+ }
+
+ printf("%.*s", (int)len, buf);
+
+ if ((flags & WHOIS_RECURSE) && nhost == NULL) {
+ for (i = 0; whois_referral[i].prefix != NULL; i++) {
+ p = buf;
+ SCAN(p, buf+len, *p == ' ');
+ if (strncasecmp(p, whois_referral[i].prefix,
+ whois_referral[i].len) != 0)
+ continue;
+ p += whois_referral[i].len;
+ SCAN(p, buf+len, *p == ' ');
+ host = p;
+ SCAN(p, buf+len, ishost(*p));
+ if (p > host)
+ s_asprintf(&nhost, "%.*s",
+ (int)(p - host), host);
+ break;
+ }
+ for (i = 0; actually_arin[i] != NULL; i++) {
+ if (strncmp(buf, actually_arin[i], len) == 0) {
+ s_asprintf(&nhost, "%s", ANICHOST);
+ break;
+ }
+ }
+ }
+ /* Verisign etc. */
+ if (!(flags & WHOIS_SPAM_ME) &&
+ len >= sizeof(CHOPSPAM)-1 &&
+ (strncasecmp(buf, CHOPSPAM, sizeof(CHOPSPAM)-1) == 0 ||
+ strncasecmp(buf, CHOPSPAM+4, sizeof(CHOPSPAM)-5) == 0)) {
+ printf("\n");
+ break;
+ }
+ }
+ fclose(fp);
+ freeaddrinfo(hostres);
+
+ f = 0;
+ for (i = 0; try_rir[i].host != NULL; i++) {
+ /* Remember visits to RIRs */
+ if (try_rir[i].loop == 0 &&
+ strcasecmp(try_rir[i].host, hostname) == 0)
+ try_rir[i].loop = 1;
+ /* Do we need to find an alternative RIR? */
+ if (try_rir[i].loop != 0 && nhost != NULL &&
+ strcasecmp(try_rir[i].host, nhost) == 0) {
+ free(nhost);
+ nhost = NULL;
+ f = 1;
+ }
+ }
+ if (f) {
+ /* Find a replacement RIR */
+ for (i = 0; try_rir[i].host != NULL; i++) {
+ if (try_rir[i].loop == 0) {
+ s_asprintf(&nhost, "%s",
+ try_rir[i].host);
+ break;
+ }
+ }
+ }
+ if (nhost != NULL) {
+ /* Ignore self-referrals */
+ if (strcasecmp(hostname, nhost) != 0) {
+ printf("# %s\n\n", nhost);
+ whois(query, nhost, flags);
+ }
+ free(nhost);
+ }
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: whois [-aAbfgiIklmPQrRS] [-c country-code | -h hostname] "
+ "[-p port] name ...\n");
+ exit(EX_USAGE);
+}
diff --git a/adv_cmds/xcodescripts/variant_links.sh b/adv_cmds/xcodescripts/variant_links.sh
new file mode 100644
index 0000000..523c755
--- /dev/null
+++ b/adv_cmds/xcodescripts/variant_links.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+#
+# Variant links cannot be created in the actual target, because Strip/CodeSign/etc are
+# after all other phases. Running it in the aggregate target guarantees that the variants
+# are really linked to the actual stripped/signed binary.
+#
+
+set -ex
+
+ln ${DSTROOT}/usr/bin/pkill ${DSTROOT}/usr/bin/pgrep
+ln ${DSTROOT}/usr/share/man/man1/pkill.1 ${DSTROOT}/usr/share/man/man1/pgrep.1
diff --git a/basic_cmds/basic_cmds.xcodeproj/project.pbxproj b/basic_cmds/basic_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..093906e
--- /dev/null
+++ b/basic_cmds/basic_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,546 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 721D59C60FC5FA20009D810A /* Build All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 721D59C90FC5FA4E009D810A /* Build configuration list for PBXAggregateTarget "Build All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 721D59D50FC5FB18009D810A /* PBXTargetDependency */,
+ 721D59D30FC5FB18009D810A /* PBXTargetDependency */,
+ 721D59D10FC5FB18009D810A /* PBXTargetDependency */,
+ 721D59CF0FC5FB18009D810A /* PBXTargetDependency */,
+ );
+ name = "Build All";
+ productName = "Build All";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 721D59850FC5F414009D810A /* mesg.c in Sources */ = {isa = PBXBuildFile; fileRef = 721D59840FC5F414009D810A /* mesg.c */; };
+ 721D598D0FC5F49F009D810A /* mesg.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 721D59830FC5F414009D810A /* mesg.1 */; };
+ 721D59920FC5F53E009D810A /* write.c in Sources */ = {isa = PBXBuildFile; fileRef = 721D59900FC5F533009D810A /* write.c */; };
+ 721D59940FC5F566009D810A /* write.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 721D598F0FC5F533009D810A /* write.1 */; };
+ 721D599C0FC5F593009D810A /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = 721D599A0FC5F593009D810A /* base64.c */; };
+ 721D599D0FC5F593009D810A /* uudecode.c in Sources */ = {isa = PBXBuildFile; fileRef = 721D599B0FC5F593009D810A /* uudecode.c */; };
+ 721D59A10FC5F5C3009D810A /* uudecode.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 721D599F0FC5F5A8009D810A /* uudecode.1 */; };
+ 721D59B30FC5F6D9009D810A /* base64.c in Sources */ = {isa = PBXBuildFile; fileRef = 721D59AF0FC5F6D9009D810A /* base64.c */; };
+ 721D59B40FC5F6D9009D810A /* uuencode.c in Sources */ = {isa = PBXBuildFile; fileRef = 721D59B20FC5F6D9009D810A /* uuencode.c */; };
+ 721D59B60FC5F6F4009D810A /* uuencode.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 721D59B00FC5F6D9009D810A /* uuencode.1 */; };
+ 721D59B70FC5F6F4009D810A /* uuencode.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 721D59B10FC5F6D9009D810A /* uuencode.5 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 721D59CE0FC5FB18009D810A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 721D59560FC5F325009D810A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 721D597C0FC5F36F009D810A;
+ remoteInfo = write;
+ };
+ 721D59D00FC5FB18009D810A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 721D59560FC5F325009D810A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 721D59730FC5F347009D810A;
+ remoteInfo = mesg;
+ };
+ 721D59D20FC5FB18009D810A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 721D59560FC5F325009D810A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 721D596C0FC5F33E009D810A;
+ remoteInfo = uudecode;
+ };
+ 721D59D40FC5FB18009D810A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 721D59560FC5F325009D810A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 721D59630FC5F336009D810A;
+ remoteInfo = uuencode;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 721D598C0FC5F43F009D810A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 721D598D0FC5F49F009D810A /* mesg.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 721D59980FC5F56F009D810A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 721D59940FC5F566009D810A /* write.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 721D59A40FC5F5CA009D810A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 721D59A10FC5F5C3009D810A /* uudecode.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 721D59BC0FC5F70F009D810A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 721D59B60FC5F6F4009D810A /* uuencode.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 721D59CD0FC5FA9D009D810A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ 721D59B70FC5F6F4009D810A /* uuencode.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 721D59640FC5F336009D810A /* uuencode */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = uuencode; sourceTree = BUILT_PRODUCTS_DIR; };
+ 721D596D0FC5F33E009D810A /* uudecode */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = uudecode; sourceTree = BUILT_PRODUCTS_DIR; };
+ 721D59740FC5F347009D810A /* mesg */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mesg; sourceTree = BUILT_PRODUCTS_DIR; };
+ 721D597D0FC5F370009D810A /* write */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = write; sourceTree = BUILT_PRODUCTS_DIR; };
+ 721D59830FC5F414009D810A /* mesg.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mesg.1; sourceTree = "<group>"; };
+ 721D59840FC5F414009D810A /* mesg.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mesg.c; sourceTree = "<group>"; };
+ 721D598F0FC5F533009D810A /* write.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = write.1; sourceTree = "<group>"; };
+ 721D59900FC5F533009D810A /* write.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = write.c; sourceTree = "<group>"; };
+ 721D599A0FC5F593009D810A /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = "<group>"; };
+ 721D599B0FC5F593009D810A /* uudecode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uudecode.c; sourceTree = "<group>"; };
+ 721D599F0FC5F5A8009D810A /* uudecode.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = uudecode.1; sourceTree = "<group>"; };
+ 721D59AF0FC5F6D9009D810A /* base64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = base64.c; sourceTree = "<group>"; };
+ 721D59B00FC5F6D9009D810A /* uuencode.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = uuencode.1; sourceTree = "<group>"; };
+ 721D59B10FC5F6D9009D810A /* uuencode.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = uuencode.5; sourceTree = "<group>"; };
+ 721D59B20FC5F6D9009D810A /* uuencode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = uuencode.c; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 721D59620FC5F336009D810A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 721D596B0FC5F33E009D810A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 721D59720FC5F347009D810A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 721D597B0FC5F36F009D810A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 721D59540FC5F325009D810A = {
+ isa = PBXGroup;
+ children = (
+ 721D59A70FC5F613009D810A /* uuencode */,
+ 721D59970FC5F56F009D810A /* uudecode */,
+ 721D59810FC5F38E009D810A /* mesg */,
+ 721D598E0FC5F4AC009D810A /* write */,
+ 721D59650FC5F336009D810A /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 721D59650FC5F336009D810A /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 721D59640FC5F336009D810A /* uuencode */,
+ 721D596D0FC5F33E009D810A /* uudecode */,
+ 721D59740FC5F347009D810A /* mesg */,
+ 721D597D0FC5F370009D810A /* write */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 721D59810FC5F38E009D810A /* mesg */ = {
+ isa = PBXGroup;
+ children = (
+ 721D59830FC5F414009D810A /* mesg.1 */,
+ 721D59840FC5F414009D810A /* mesg.c */,
+ );
+ path = mesg;
+ sourceTree = "<group>";
+ };
+ 721D598E0FC5F4AC009D810A /* write */ = {
+ isa = PBXGroup;
+ children = (
+ 721D598F0FC5F533009D810A /* write.1 */,
+ 721D59900FC5F533009D810A /* write.c */,
+ );
+ path = write;
+ sourceTree = "<group>";
+ };
+ 721D59970FC5F56F009D810A /* uudecode */ = {
+ isa = PBXGroup;
+ children = (
+ 721D599A0FC5F593009D810A /* base64.c */,
+ 721D599F0FC5F5A8009D810A /* uudecode.1 */,
+ 721D599B0FC5F593009D810A /* uudecode.c */,
+ );
+ path = uudecode;
+ sourceTree = "<group>";
+ };
+ 721D59A70FC5F613009D810A /* uuencode */ = {
+ isa = PBXGroup;
+ children = (
+ 721D59AF0FC5F6D9009D810A /* base64.c */,
+ 721D59B00FC5F6D9009D810A /* uuencode.1 */,
+ 721D59B10FC5F6D9009D810A /* uuencode.5 */,
+ 721D59B20FC5F6D9009D810A /* uuencode.c */,
+ );
+ path = uuencode;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 721D59630FC5F336009D810A /* uuencode */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 721D59690FC5F337009D810A /* Build configuration list for PBXNativeTarget "uuencode" */;
+ buildPhases = (
+ 721D59610FC5F336009D810A /* Sources */,
+ 721D59620FC5F336009D810A /* Frameworks */,
+ 721D59BC0FC5F70F009D810A /* CopyFiles */,
+ 721D59CD0FC5FA9D009D810A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = uuencode;
+ productName = uuencode;
+ productReference = 721D59640FC5F336009D810A /* uuencode */;
+ productType = "com.apple.product-type.tool";
+ };
+ 721D596C0FC5F33E009D810A /* uudecode */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 721D59780FC5F348009D810A /* Build configuration list for PBXNativeTarget "uudecode" */;
+ buildPhases = (
+ 721D596A0FC5F33E009D810A /* Sources */,
+ 721D596B0FC5F33E009D810A /* Frameworks */,
+ 721D59A40FC5F5CA009D810A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = uudecode;
+ productName = uudecode;
+ productReference = 721D596D0FC5F33E009D810A /* uudecode */;
+ productType = "com.apple.product-type.tool";
+ };
+ 721D59730FC5F347009D810A /* mesg */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 721D59790FC5F348009D810A /* Build configuration list for PBXNativeTarget "mesg" */;
+ buildPhases = (
+ 721D59710FC5F347009D810A /* Sources */,
+ 721D59720FC5F347009D810A /* Frameworks */,
+ 721D598C0FC5F43F009D810A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mesg;
+ productName = mesg;
+ productReference = 721D59740FC5F347009D810A /* mesg */;
+ productType = "com.apple.product-type.tool";
+ };
+ 721D597C0FC5F36F009D810A /* write */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 721D59820FC5F38E009D810A /* Build configuration list for PBXNativeTarget "write" */;
+ buildPhases = (
+ 721D597A0FC5F36F009D810A /* Sources */,
+ 721D597B0FC5F36F009D810A /* Frameworks */,
+ 721D59980FC5F56F009D810A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = write;
+ productName = write;
+ productReference = 721D597D0FC5F370009D810A /* write */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 721D59560FC5F325009D810A /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0500;
+ };
+ buildConfigurationList = 721D59590FC5F325009D810A /* Build configuration list for PBXProject "basic_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 721D59540FC5F325009D810A;
+ productRefGroup = 721D59650FC5F336009D810A /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 721D59C60FC5FA20009D810A /* Build All */,
+ 721D59630FC5F336009D810A /* uuencode */,
+ 721D596C0FC5F33E009D810A /* uudecode */,
+ 721D59730FC5F347009D810A /* mesg */,
+ 721D597C0FC5F36F009D810A /* write */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 721D59610FC5F336009D810A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 721D59B30FC5F6D9009D810A /* base64.c in Sources */,
+ 721D59B40FC5F6D9009D810A /* uuencode.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 721D596A0FC5F33E009D810A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 721D599C0FC5F593009D810A /* base64.c in Sources */,
+ 721D599D0FC5F593009D810A /* uudecode.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 721D59710FC5F347009D810A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 721D59850FC5F414009D810A /* mesg.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 721D597A0FC5F36F009D810A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 721D59920FC5F53E009D810A /* write.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 721D59CF0FC5FB18009D810A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 721D597C0FC5F36F009D810A /* write */;
+ targetProxy = 721D59CE0FC5FB18009D810A /* PBXContainerItemProxy */;
+ };
+ 721D59D10FC5FB18009D810A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 721D59730FC5F347009D810A /* mesg */;
+ targetProxy = 721D59D00FC5FB18009D810A /* PBXContainerItemProxy */;
+ };
+ 721D59D30FC5FB18009D810A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 721D596C0FC5F33E009D810A /* uudecode */;
+ targetProxy = 721D59D20FC5FB18009D810A /* PBXContainerItemProxy */;
+ };
+ 721D59D50FC5FB18009D810A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 721D59630FC5F336009D810A /* uuencode */;
+ targetProxy = 721D59D40FC5FB18009D810A /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 721D59580FC5F325009D810A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ INSTALL_MODE_FLAG = "gou-w,a+rX";
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ USE_HEADERMAP = NO;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_BUILDER = "$(USER)";
+ VERSION_INFO_FILE = "$(PRODUCT_NAME)_vers.c";
+ VERSION_INFO_PREFIX = __;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 721D59680FC5F337009D810A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = uuencode;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 721D59700FC5F33F009D810A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = uudecode;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 721D59770FC5F348009D810A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mesg;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 721D59800FC5F370009D810A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_GROUP = tty;
+ INSTALL_MODE_FLAG = "gou-w,a+rX,g+s";
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = write;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 721D59C80FC5FA20009D810A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = basic_cmds;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 721D59590FC5F325009D810A /* Build configuration list for PBXProject "basic_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 721D59580FC5F325009D810A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 721D59690FC5F337009D810A /* Build configuration list for PBXNativeTarget "uuencode" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 721D59680FC5F337009D810A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 721D59780FC5F348009D810A /* Build configuration list for PBXNativeTarget "uudecode" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 721D59700FC5F33F009D810A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 721D59790FC5F348009D810A /* Build configuration list for PBXNativeTarget "mesg" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 721D59770FC5F348009D810A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 721D59820FC5F38E009D810A /* Build configuration list for PBXNativeTarget "write" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 721D59800FC5F370009D810A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 721D59C90FC5FA4E009D810A /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 721D59C80FC5FA20009D810A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 721D59560FC5F325009D810A /* Project object */;
+}
diff --git a/basic_cmds/mesg/mesg.1 b/basic_cmds/mesg/mesg.1
new file mode 100644
index 0000000..de2f7a4
--- /dev/null
+++ b/basic_cmds/mesg/mesg.1
@@ -0,0 +1,112 @@
+.\" Copyright (c) 1987, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mesg.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/mesg/mesg.1,v 1.10 2002/07/25 05:16:49 tjr Exp $
+.\"
+.Dd May 5, 2002
+.Dt MESG 1
+.Os
+.Sh NAME
+.Nm mesg
+.Nd display (do not display) messages from other users
+.Sh SYNOPSIS
+.Nm
+.Op Cm n | Cm y
+.Sh DESCRIPTION
+The
+.Nm
+utility is invoked by a user to control write access others
+have to a terminal device.
+Write access is allowed by default, and programs such as
+.Xr talk 1
+and
+.Xr write 1
+may display messages on the terminal.
+.Pp
+The first terminal device in the sequence of devices associated with standard
+input, standard output and standard error is affected.
+.Pp
+Options available:
+.Bl -tag -width flag
+.It Cm n
+Disallows messages.
+.It Cm y
+Permits messages to be displayed.
+.El
+.Pp
+If no arguments are given,
+.Nm
+displays the present message status to the standard output.
+.Sh EXAMPLES
+Disallow messages from other users to the current terminal:
+.Pp
+.Dl "mesg n"
+.Pp
+Allow messages from other users to
+.Pa ttyp1
+(assuming you are also logged in on that terminal):
+.Pp
+.Dl "mesg y </dev/ttyp1"
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width flag -compact -offset indent
+.Pp
+.It Li "\ 0"
+Messages are allowed.
+.It Li "\ 1"
+Messages are not allowed.
+.It Li ">1"
+An error has occurred.
+.El
+.Sh COMPATIBILITY
+Previous versions of the
+.Nm
+utility wrote the message status to the standard error output and
+affected the terminal attached to standard error without first trying the
+standard input or output devices.
+.Sh SEE ALSO
+.Xr biff 1 ,
+.Xr talk 1 ,
+.Xr wall 1 ,
+.Xr write 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/basic_cmds/mesg/mesg.c b/basic_cmds/mesg/mesg.c
new file mode 100644
index 0000000..b66980b
--- /dev/null
+++ b/basic_cmds/mesg/mesg.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mesg.c 8.2 (Berkeley) 1/21/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/mesg/mesg.c,v 1.8 2002/09/04 23:29:04 dwmalone Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ char *tty;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ }
+// argc -= optind;
+ argv += optind;
+
+ if ((tty = ttyname(STDIN_FILENO)) == NULL &&
+ (tty = ttyname(STDOUT_FILENO)) == NULL &&
+ (tty = ttyname(STDERR_FILENO)) == NULL)
+ err(2, "ttyname");
+ if (stat(tty, &sb) < 0)
+ err(2, "%s", tty);
+
+ if (*argv == NULL) {
+ if (sb.st_mode & S_IWGRP) {
+ (void)puts("is y");
+ exit(0);
+ }
+ (void)puts("is n");
+ exit(1);
+ }
+
+ switch (*argv[0]) {
+ case 'y':
+ if (chmod(tty, sb.st_mode | S_IWGRP) < 0)
+ err(2, "%s", tty);
+ exit(0);
+ case 'n':
+ if (chmod(tty, sb.st_mode & ~S_IWGRP) < 0)
+ err(2, "%s", tty);
+ exit(1);
+ }
+
+ usage();
+ return(0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: mesg [y | n]\n");
+ exit(2);
+}
diff --git a/basic_cmds/uudecode/base64.c b/basic_cmds/uudecode/base64.c
new file mode 100644
index 0000000..b537171
--- /dev/null
+++ b/basic_cmds/uudecode/base64.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+#include <sys/cdefs.h>
+__unused static char rcsid[] = "$FreeBSD: src/lib/libc/net/base64.c,v 1.4 1999/11/04 04:30:43 ache Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(src, target, targsize)
+ char const *src;
+ u_char *target;
+ size_t targsize;
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/basic_cmds/uudecode/uudecode.1 b/basic_cmds/uudecode/uudecode.1
new file mode 100644
index 0000000..ace1742
--- /dev/null
+++ b/basic_cmds/uudecode/uudecode.1
@@ -0,0 +1 @@
+.so man1/uuencode.1
diff --git a/basic_cmds/uudecode/uudecode.c b/basic_cmds/uudecode/uudecode.c
new file mode 100644
index 0000000..4831cab
--- /dev/null
+++ b/basic_cmds/uudecode/uudecode.c
@@ -0,0 +1,504 @@
+/*-
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)uudecode.c 8.2 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/usr.bin/uudecode/uudecode.c 214010 2010-10-18 05:44:11Z edwin $");
+
+/*
+ * uudecode [file ...]
+ *
+ * create the specified file, decoding as you go.
+ * used with uuencode.
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <pwd.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static const char *infile, *outfile;
+static FILE *infp, *outfp;
+static int base64, cflag, iflag, oflag, pflag, rflag, sflag;
+
+static void usage(void);
+static int decode(void);
+static int decode2(void);
+static int uu_decode(void);
+static int base64_decode(void);
+
+int
+main(int argc, char *argv[])
+{
+ int rval, ch;
+
+ if (strcmp(basename(argv[0]), "b64decode") == 0)
+ base64 = 1;
+
+ while ((ch = getopt(argc, argv, "cimo:prs")) != -1) {
+ switch (ch) {
+ case 'c':
+ if (oflag || rflag)
+ usage();
+ cflag = 1; /* multiple uudecode'd files */
+ break;
+ case 'i':
+ iflag = 1; /* ask before override files */
+ break;
+ case 'm':
+ base64 = 1;
+ break;
+ case 'o':
+ if (cflag || pflag || rflag || sflag)
+ usage();
+ oflag = 1; /* output to the specified file */
+ sflag = 1; /* do not strip pathnames for output */
+ outfile = optarg; /* set the output filename */
+ break;
+ case 'p':
+ if (oflag)
+ usage();
+ pflag = 1; /* print output to stdout */
+ break;
+ case 'r':
+ if (cflag || oflag)
+ usage();
+ rflag = 1; /* decode raw data */
+ break;
+ case 's':
+ if (oflag)
+ usage();
+ sflag = 1; /* do not strip pathnames for output */
+ break;
+ default:
+ usage();
+ }
+ }
+// argc -= optind;
+ argv += optind;
+
+ if (*argv != NULL) {
+ rval = 0;
+ do {
+ infp = fopen(infile = *argv, "r");
+ if (infp == NULL) {
+ warn("%s", *argv);
+ rval = 1;
+ continue;
+ }
+ rval |= decode();
+ fclose(infp);
+ } while (*++argv);
+ } else {
+ infile = "stdin";
+ infp = stdin;
+ rval = decode();
+ }
+ exit(rval);
+}
+
+static int
+decode(void)
+{
+ int r, v;
+
+ if (rflag) {
+ /* relaxed alternative to decode2() */
+ outfile = "/dev/stdout";
+ outfp = stdout;
+ if (base64)
+ return (base64_decode());
+ else
+ return (uu_decode());
+ }
+ v = decode2();
+ if (v == EOF) {
+ warnx("%s: missing or bad \"begin\" line", infile);
+ return (1);
+ }
+ for (r = v; cflag; r |= v) {
+ v = decode2();
+ if (v == EOF)
+ break;
+ }
+ return (r);
+}
+
+static int
+decode2(void)
+{
+ int flags, fd, mode;
+ size_t n, m;
+ char *p, *q = NULL, *orig_outfile = NULL;
+ void *handle;
+ struct passwd *pw;
+ struct stat st;
+ char buf[MAXPATHLEN + 1];
+
+ base64 = 0;
+ /* search for header line */
+ for (;;) {
+ if (fgets(buf, sizeof(buf), infp) == NULL)
+ return (EOF);
+ p = buf;
+ if (strncmp(p, "begin-base64 ", 13) == 0) {
+ base64 = 1;
+ p += 13;
+ } else if (strncmp(p, "begin ", 6) == 0)
+ p += 6;
+ else
+ continue;
+ /* p points to mode */
+ q = strchr(p, ' ');
+ if (q == NULL)
+ continue;
+ *q++ = '\0';
+ /* q points to filename */
+ n = strlen(q);
+ while (n > 0 && (q[n-1] == '\n' || q[n-1] == '\r'))
+ q[--n] = '\0';
+ /* found valid header? */
+ if (n > 0)
+ break;
+ }
+ orig_outfile = q;
+ handle = setmode(p);
+ if (handle == NULL) {
+ warnx("%s: unable to parse file mode", infile);
+ return (1);
+ }
+ mode = getmode(handle, 0);
+ free(handle);
+
+ if (sflag) {
+ /* don't strip, so try ~user/file expansion */
+ p = NULL;
+ pw = NULL;
+ if (*q == '~')
+ p = strchr(q, '/');
+ if (p != NULL) {
+ *p = '\0';
+ pw = getpwnam(q + 1);
+ *p = '/';
+ }
+ if (pw != NULL) {
+ n = strlen(pw->pw_dir);
+ if (buf + n > p) {
+ /* make room */
+ m = strlen(p);
+ if (sizeof(buf) < n + m) {
+ warnx("%s: bad output filename",
+ infile);
+ return (1);
+ }
+ p = memmove(buf + n, p, m);
+ }
+ q = memcpy(p - n, pw->pw_dir, n);
+ }
+ } else {
+ /* strip down to leaf name */
+ p = strrchr(q, '/');
+ if (p != NULL)
+ q = p + 1;
+ }
+ if (!oflag) {
+ outfile = q ? strdup(q) : q;
+ }
+
+ /* POSIX says "/dev/stdout" is a 'magic cookie' not a special file. */
+ if (pflag || (strcmp(oflag ? outfile : orig_outfile, "/dev/stdout") == 0)) {
+ outfp = stdout;
+ } else {
+ char pwd[MAXPATHLEN] = "";
+ char targetpath[MAXPATHLEN];
+ flags = O_WRONLY | O_CREAT | O_EXCL;
+ if (lstat(outfile, &st) == 0) {
+ if (iflag && !S_ISFIFO(st.st_mode)) {
+ warnc(EEXIST, "%s: %s", infile, outfile);
+ return (0);
+ }
+
+ flags = O_RDWR;
+ switch (st.st_mode & S_IFMT) {
+ case S_IFREG:
+ flags |= O_NOFOLLOW | O_TRUNC;
+ break;
+ case S_IFLNK:
+ if (NULL == realpath(".", pwd)) {
+ warn("Unable to get realpath for .");
+ return (1);
+ }
+ flags |= O_CREAT; // for dangling symlinks
+ break;
+ case S_IFDIR:
+ warnc(EISDIR, "%s: %s", infile, outfile);
+ return (1);
+ case S_IFIFO:
+ flags &= ~O_EXCL;
+ break;
+ default:
+ if (oflag) {
+ /* trust command-line names */
+ flags &= ~O_EXCL;
+ break;
+ }
+ warnc(EEXIST, "%s: %s", infile, outfile);
+ return (1);
+ }
+ } else if (errno != ENOENT) {
+ warn("%s: %s", infile, outfile);
+ return (1);
+ }
+ fd = open(outfile, flags, mode);
+ if (fd < 0) {
+ warn("%s: %s", infile, outfile);
+ return (1);
+ }
+ if (pwd[0]) {
+ if (-1 != fcntl(fd, F_GETPATH, targetpath)) {
+ if (strstr(targetpath, pwd) != targetpath) {
+ warnx("Target path %s is not based at %s", targetpath, pwd);
+ close(fd);
+ return (1);
+ }
+ ftruncate(fd, 0);
+ } else {
+ close(fd);
+ warn("Unable to get path for target: %s", outfile);
+ return (1);
+ }
+ }
+ if ((outfp = fdopen(fd, "w")) == NULL) {
+ warn("%s: %s", infile, outfile);
+ close(fd);
+ return (1);
+ }
+ if (fchmod(fileno(outfp), mode) && (EPERM != errno)) {
+ warn("%s: %s", infile, outfile);
+ close(fd);
+ return 1;
+ }
+ }
+ if (base64)
+ return (base64_decode());
+ else
+ return (uu_decode());
+}
+
+static int
+uugetline(char *buf, size_t size)
+{
+
+ if (fgets(buf, size, infp) != NULL)
+ return (2);
+ if (rflag)
+ return (0);
+ warnx("%s: %s: short file", infile, outfile);
+ return (1);
+}
+
+static int
+checkend(const char *ptr, const char *end, const char *msg)
+{
+ size_t n;
+
+ n = strlen(end);
+ if (strncmp(ptr, end, n) != 0 ||
+ strspn(ptr + n, " \t\r\n") != strlen(ptr + n)) {
+ warnx("%s: %s: %s", infile, outfile, msg);
+ return (1);
+ }
+ if (fclose(outfp) != 0) {
+ warn("%s: %s", infile, outfile);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+uu_decode(void)
+{
+ int i, ch;
+ char *p;
+ char buf[MAXPATHLEN+1];
+
+ /* for each input line */
+ for (;;) {
+ switch (uugetline(buf, sizeof(buf))) {
+ case 0:
+ return (0);
+ case 1:
+ return (1);
+ }
+
+#define DEC(c) (((c) - ' ') & 077) /* single character decode */
+#define IS_DEC(c) ( (((c) - ' ') >= 0) && (((c) - ' ') <= 077 + 1) )
+
+#define OUT_OF_RANGE do { \
+ warnx("%s: %s: character out of range: [%d-%d]", \
+ infile, outfile, 1 + ' ', 077 + ' ' + 1); \
+ return (1); \
+} while (0)
+
+ /*
+ * `i' is used to avoid writing out all the characters
+ * at the end of the file.
+ */
+ p = buf;
+ if ((i = DEC(*p)) <= 0)
+ break;
+ for (++p; i > 0; p += 4, i -= 3)
+ if (i >= 3) {
+ if (!(IS_DEC(*p) && IS_DEC(*(p + 1)) &&
+ IS_DEC(*(p + 2)) && IS_DEC(*(p + 3))))
+ OUT_OF_RANGE;
+
+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
+ putc(ch, outfp);
+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+ putc(ch, outfp);
+ ch = DEC(p[2]) << 6 | DEC(p[3]);
+ putc(ch, outfp);
+ } else {
+ if (i >= 1) {
+ if (!(IS_DEC(*p) && IS_DEC(*(p + 1))))
+ OUT_OF_RANGE;
+ ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
+ putc(ch, outfp);
+ }
+ if (i >= 2) {
+ if (!(IS_DEC(*(p + 1)) &&
+ IS_DEC(*(p + 2))))
+ OUT_OF_RANGE;
+
+ ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
+ putc(ch, outfp);
+ }
+ if (i >= 3) {
+ if (!(IS_DEC(*(p + 2)) &&
+ IS_DEC(*(p + 3))))
+ OUT_OF_RANGE;
+ ch = DEC(p[2]) << 6 | DEC(p[3]);
+ putc(ch, outfp);
+ }
+ }
+ }
+ switch (uugetline(buf, sizeof(buf))) {
+ case 0:
+ return (0);
+ case 1:
+ return (1);
+ default:
+ return (checkend(buf, "end", "no \"end\" line"));
+ }
+}
+
+static int
+base64_decode(void)
+{
+ int n, count, count4;
+ char inbuf[MAXPATHLEN + 1], *p;
+ unsigned char outbuf[MAXPATHLEN * 4];
+ char leftover[MAXPATHLEN + 1];
+
+ leftover[0] = '\0';
+ for (;;) {
+ strcpy(inbuf, leftover);
+ switch (uugetline(inbuf + strlen(inbuf),
+ sizeof(inbuf) - strlen(inbuf))) {
+ case 0:
+ return (0);
+ case 1:
+ return (1);
+ }
+
+ count = 0;
+ count4 = -1;
+ p = inbuf;
+ while (*p != '\0') {
+ /*
+ * Base64 encoded strings have the following
+ * characters in them: A-Z, a-z, 0-9 and +, / and =
+ */
+ if (isalnum(*p) || *p == '+' || *p == '/' || *p == '=')
+ count++;
+ if (count % 4 == 0)
+ count4 = p - inbuf;
+ p++;
+ }
+
+ strcpy(leftover, inbuf + count4 + 1);
+ inbuf[count4 + 1] = 0;
+
+ n = b64_pton(inbuf, outbuf, sizeof(outbuf));
+
+ if (n < 0)
+ break;
+ fwrite(outbuf, 1, n, outfp);
+ }
+ return (checkend(inbuf, "====", "error decoding base64 input stream"));
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: uudecode [-cimprs] [file ...]\n"
+ " uudecode [-i] -o output_file [file]\n"
+ " b64decode [-cimprs] [file ...]\n"
+ " b64decode [-i] -o output_file [file]\n");
+ exit(1);
+}
diff --git a/basic_cmds/uuencode/base64.c b/basic_cmds/uuencode/base64.c
new file mode 100644
index 0000000..b537171
--- /dev/null
+++ b/basic_cmds/uuencode/base64.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+#include <sys/cdefs.h>
+__unused static char rcsid[] = "$FreeBSD: src/lib/libc/net/base64.c,v 1.4 1999/11/04 04:30:43 ache Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(src, target, targsize)
+ char const *src;
+ u_char *target;
+ size_t targsize;
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace((unsigned char)ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/basic_cmds/uuencode/uuencode.1 b/basic_cmds/uuencode/uuencode.1
new file mode 100644
index 0000000..20a8bf4
--- /dev/null
+++ b/basic_cmds/uuencode/uuencode.1
@@ -0,0 +1,192 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)uuencode.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/uuencode/uuencode.1,v 1.9.2.6 2002/04/27 01:55:11 jmallett Exp $
+.\"
+.Dd January 27, 2002
+.Dt UUENCODE 1
+.Os
+.Sh NAME
+.Nm uudecode ,
+.Nm uuencode
+.Nd encode/decode a binary file
+.Sh SYNOPSIS
+.Nm uuencode
+.Op Fl m
+.Op Fl o Ar output_file
+.Op Ar file
+.Ar name
+.Nm uudecode
+.Op Fl cips
+.Op Ar
+.Nm uudecode
+.Op Fl i
+.Fl o Ar output_file
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm uuencode
+and
+.Nm uudecode
+utilities are used to transmit binary files over transmission mediums
+that do not support other than simple
+.Tn ASCII
+data.
+.Pp
+The
+.Nm uuencode
+utility reads
+.Ar file
+(or by default the standard input) and writes an encoded version
+to the standard output, or
+.Ar output_file
+if one has been specified.
+The encoding uses only printing
+.Tn ASCII
+characters and includes the
+mode of the file and the operand
+.Ar name
+for use by
+.Nm uudecode .
+.Pp
+The
+.Nm uudecode
+utility transforms
+.Em uuencoded
+files (or by default, the standard input) into the original form.
+The resulting file is named either
+.Ar name
+or (depending on options passed to
+.Nm uudecode )
+.Ar output_file
+and will have the mode of the original file except that setuid
+and execute bits are not retained.
+The
+.Nm uudecode
+utility ignores any leading and trailing lines.
+.Pp
+The following options are available for
+.Nm uuencode :
+.Bl -tag -width ident
+.It Fl m
+Use the Base64 method of encoding, rather than the traditional
+.Nm uuencode
+algorithm.
+.It Fl o Ar output_file
+Output to
+.Ar output_file
+instead of standard output.
+.El
+.Pp
+The following options are available for
+.Nm uudecode :
+.Bl -tag -width ident
+.It Fl c
+Decode more than one uuencode'd file from
+.Ar file
+if possible.
+.It Fl i
+Do not overwrite files.
+.It Fl o Ar output_file
+Output to
+.Ar output_file
+instead of any pathname contained in the input data.
+.It Fl p
+Decode
+.Ar file
+and write output to standard output.
+.It Fl s
+Do not strip output pathname to base filename.
+By default
+.Nm uudecode
+deletes any prefix ending with the last slash '/' for security
+purpose.
+.El
+.Sh EXAMPLES
+The following example packages up a source tree, compresses it,
+uuencodes it and mails it to a user on another system.
+When
+.Nm uudecode
+is run on the target system, the file ``src_tree.tar.Z'' will be
+created which may then be uncompressed and extracted into the original
+tree.
+.Pp
+.Bd -literal -offset indent -compact
+tar cf \- src_tree \&| compress \&|
+uuencode src_tree.tar.Z \&| mail sys1!sys2!user
+.Ed
+.Pp
+The following example unpack all uuencode'd
+files from your mailbox into your current working directory.
+.Pp
+.Bd -literal -offset indent -compact
+uudecode -c < $MAIL
+.Ed
+.Pp
+The following example extract a compress'ed tar
+archive from your mailbox
+.Pp
+.Bd -literal -offset indent -compact
+uudecode -o /dev/stdout < $MAIL | zcat | tar xfv -
+.Ed
+.Sh LEGACY DESCRIPTION
+In legacy operation,
+.Nm uudecode
+masks file modes with 0666,
+preventing the creation of executable files.
+.Pp
+.Nm uudecode
+cannot change the mode of a created file
+which is not owned by the current user (unless that user is root).
+In legacy operation,
+.Xr fchmod 2
+allows the mode to be changed.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr basename 1 ,
+.Xr compress 1 ,
+.Xr mail 1 ,
+.Xr uucp 1 ,
+.Xr fchmod 2 ,
+.Xr uuencode 5
+.Sh BUGS
+Files encoded using the traditional algorithm are expanded by 35%
+(3 bytes become 4, plus control information).
+.Sh HISTORY
+The
+.Nm uudecode
+and
+.Nm uuencode
+utilities appeared in
+.Bx 4.0 .
diff --git a/basic_cmds/uuencode/uuencode.5 b/basic_cmds/uuencode/uuencode.5
new file mode 100644
index 0000000..3914dad
--- /dev/null
+++ b/basic_cmds/uuencode/uuencode.5
@@ -0,0 +1,100 @@
+.TH uuencode 5 "May, 2001" "Apple Computer, Inc."
+.SH NAME
+uuencode file format
+.NM uuencode
+.ND description of the uuencode file format
+.SH DESCRIPTION
+
+The
+.XR uuencode 1
+command generates files in a format that allows them to be successfully
+transferred by systems which strip the high bit from an 8-bit byte.
+.XR uudecode 1
+decodes uuencoded files.
+
+.PP
+The uuencode file format consists of three sections: header, body, and trailer.
+The header is a line is of the form:
+
+.PP
+begin 644 "filename.ext"
+
+.PP
+where "644" is a
+.XR chmod 1
+-format permissions byte for the file and "filename.ext" is the name of
+the encoded file.
+
+.PP
+The body section is the encoded representation of the source file. Three
+bytes of input file data are encoded into four bytes of output data.
+.PP
+The 24 input bits are divided up into four pieces of six bits
+each. The integer value 32 (the ASCII value for the space character) is
+added to each of these pieces to move them outside of the range of control
+characters. To avoid using the space character in the encoding, pieces with
+value zero are encoded using backquote (ASCII value 96) instead of zero. The
+resulting character is one of the this set (ASCII values 96,33-95):
+
+.DQ `!"#$%&'()*+,-./012356789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_
+
+.PP
+A line itself contains three segments: a length character (encoded using
+the "add a space" algorithm described above), the body of the line,
+typically (although not required to be) 60 output characters long,
+representing 45 input bytes, and (of course) a linefeed. The length
+character specifies the number of valid input bytes on the line (so, for
+a line which is 60 encoded bytes, the length value would be 45).
+Decoding programs should decode no further than the specified length on
+a single line.
+
+.PP
+The trailer, which must exist, consists of a single backquote
+("`", ASCII 96) character on a line by itself, directly followed by
+.DQ end
+on a line by itself.
+
+.PP
+.DQ .uue
+is the canonical filename extension for uuencoded files.
+
+.SH BUGS
+uudecode does not read all permutations of the file format described in
+this man page.
+
+.PP
+Ancient versions of uuencode used a space character (ASCII 32) in the
+encoding to represent zero. Many (arguably broken) mailers and transport
+agents stripped, rewrapped, or otherwise mangled this format, so the space
+was later changed to the backquote, ASCII 96. Decoders may attempt to
+read the older format if they wish, though it's unlikely to be encountered
+in practice at this point in time.
+
+.PP
+The uuencode encoding method is highly ASCII-centric. In particular, the
+character set used doesn't work well on EBCDIC-based systems. (EBCDIC,
+generally used by IBM mainframes, is an old alternative character encoding;
+most computers use ASCII instead).
+
+.PP
+Many variants of uuencode on various platforms generate different forms
+of line checksums, using to represent the checksum one or more encoded
+characters after the last counted character in a line. Because these
+formats are different and impossible to distinguish (with certainty),
+such characters should be ignored by decoding implementations.
+
+.PP
+The uuencode encoding format has no provisions for segmented files.
+Writers of segmenting utilities should be careful to avoid using
+character sequences that may naturally occur in the encoding (such
+as sequences of dashes ("---")) to divide sections.
+
+.SH SEE ALSO
+The MIME Base64 encoding (documented in RFC 2045) is a consistent,
+cross-platform-savvy message encoding which should be used in place of
+UUEncode wherever possible.
+
+.PP
+The Unix-Hater's Handbook (IDG, 1994) identifies the folly of the
+older zero-encoded-as-space versions of uuencode.
+
diff --git a/basic_cmds/uuencode/uuencode.c b/basic_cmds/uuencode/uuencode.c
new file mode 100644
index 0000000..bb528a6
--- /dev/null
+++ b/basic_cmds/uuencode/uuencode.c
@@ -0,0 +1,226 @@
+/*-
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#include <sys/cdefs.h>
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)uuencode.c 8.2 (Berkeley) 4/2/94";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/uuencode/uuencode.c,v 1.4.2.4 2002/06/17 05:01:46 jmallett Exp $";
+#endif /* not lint */
+
+/*
+ * uuencode [input] output
+ *
+ * Encode a file so it can be mailed to a remote system.
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+
+#include <err.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int b64_ntop __P((u_char const *, size_t, char *, size_t));
+int b64_pton __P((char const *, u_char *, size_t));
+void encode(void);
+void base64_encode(void);
+static void usage(void);
+
+FILE *output;
+int mode;
+char **av;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct stat sb;
+ int base64;
+ char ch;
+ char *outfile;
+
+ base64 = 0;
+ outfile = NULL;
+
+ while ((ch = getopt(argc, argv, "mo:")) != -1) {
+ switch (ch) {
+ case 'm':
+ base64 = 1;
+ break;
+ case 'o':
+ outfile = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ switch(argc) {
+ case 2: /* optional first argument is input file */
+ if (!freopen(*argv, "r", stdin) || fstat(fileno(stdin), &sb))
+ err(1, "%s", *argv);
+#define RWX (S_IRWXU|S_IRWXG|S_IRWXO)
+ mode = sb.st_mode & RWX;
+ ++argv;
+ break;
+ case 1:
+#define RW (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)
+ mode = RW & ~umask(RW);
+ break;
+ case 0:
+ default:
+ usage();
+ }
+
+ av = argv;
+
+ if (outfile != NULL) {
+ output = fopen(outfile, "w+");
+ if (output == NULL)
+ err(1, "unable to open %s for output", outfile);
+ } else
+ output = stdout;
+ if (base64)
+ base64_encode();
+ else
+ encode();
+ if (ferror(output))
+ errx(1, "write error");
+ exit(0);
+}
+
+/* ENC is the basic 1 character encoding function to make a char printing */
+#define ENC(c) ((c) ? ((c) & 077) + ' ': '`')
+
+/*
+ * Copy from in to out, encoding in base64 as you go along.
+ */
+void
+base64_encode()
+{
+ /*
+ * Output must fit into 80 columns, chunks come in 4, leave 1.
+ */
+#define GROUPS ((80 / 4) - 1)
+ unsigned char buf[3];
+ char buf2[sizeof(buf) * 2 + 1];
+ size_t n;
+ int rv, sequence;
+
+ sequence = 0;
+
+ fprintf(output, "begin-base64 %o %s\n", mode, *av);
+ while ((n = fread(buf, 1, sizeof(buf), stdin))) {
+ ++sequence;
+ rv = b64_ntop(buf, n, buf2, (sizeof(buf2) / sizeof(buf2[0])));
+ if (rv == -1)
+ errx(1, "b64_ntop: error encoding base64");
+ fprintf(output, "%s%s", buf2, (sequence % GROUPS) ? "" : "\n");
+ }
+ if (sequence % GROUPS)
+ fprintf(output, "\n");
+ fprintf(output, "====\n");
+}
+
+/*
+ * Copy from in to out, encoding as you go along.
+ */
+void
+encode()
+{
+ register int ch, n;
+ register char *p;
+ char buf[80];
+
+ (void)fprintf(output, "begin %o %s\n", mode, *av);
+ while ((n = fread(buf, 1, 45, stdin))) {
+ ch = ENC(n);
+ if (fputc(ch, output) == EOF)
+ break;
+ for (p = buf; n > 0; n -= 3, p += 3) {
+ /* Pad with nulls if not a multiple of 3. */
+ if (n < 3) {
+ p[2] = '\0';
+ if (n < 2)
+ p[1] = '\0';
+ }
+ ch = *p >> 2;
+ ch = ENC(ch);
+ if (fputc(ch, output) == EOF)
+ break;
+ ch = ((*p << 4) & 060) | ((p[1] >> 4) & 017);
+ ch = ENC(ch);
+ if (fputc(ch, output) == EOF)
+ break;
+ ch = ((p[1] << 2) & 074) | ((p[2] >> 6) & 03);
+ ch = ENC(ch);
+ if (fputc(ch, output) == EOF)
+ break;
+ ch = p[2] & 077;
+ ch = ENC(ch);
+ if (fputc(ch, output) == EOF)
+ break;
+ }
+ if (fputc('\n', output) == EOF)
+ break;
+ }
+ if (ferror(stdin))
+ errx(1, "read error");
+ (void)fprintf(output, "%c\nend\n", ENC('\0'));
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,"usage: uuencode [-m] [-o outfile] [infile] remotefile\n");
+ exit(1);
+}
diff --git a/basic_cmds/write/write.1 b/basic_cmds/write/write.1
new file mode 100644
index 0000000..c7c2df1
--- /dev/null
+++ b/basic_cmds/write/write.1
@@ -0,0 +1,106 @@
+.\" Copyright (c) 1989, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Jef Poskanzer and Craig Leres of the Lawrence Berkeley Laboratory.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)write.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/write/write.1,v 1.10 2002/04/20 12:18:12 charnier Exp $
+.\"
+.Dd June 6, 1993
+.Dt WRITE 1
+.Os
+.Sh NAME
+.Nm write
+.Nd send a message to another user
+.Sh SYNOPSIS
+.Nm
+.Ar user
+.Op Ar ttyname
+.Sh DESCRIPTION
+The
+.Nm
+utility allows you to communicate with other users, by copying lines from
+your terminal to theirs.
+.Pp
+When you run the
+.Nm
+command, the user you are writing to gets a message of the form:
+.Pp
+.Dl Message from yourname@yourhost on yourtty at hh:mm ...
+.Pp
+Any further lines you enter will be copied to the specified user's
+terminal.
+If the other user wants to reply, they must run
+.Nm
+as well.
+.Pp
+When you are done, type an end-of-file or interrupt character.
+The other user will see the message
+.Ql EOF
+indicating that the
+conversation is over.
+.Pp
+You can prevent people (other than the super-user) from writing to you
+with the
+.Xr mesg 1
+command.
+.Pp
+If the user you want to write to is logged in on more than one terminal,
+you can specify which terminal to write to by specifying the terminal
+name as the second operand to the
+.Nm
+command.
+Alternatively, you can let
+.Nm
+select one of the terminals \- it will pick the one with the shortest
+idle time.
+This is so that if the user is logged in at work and also dialed up from
+home, the message will go to the right place.
+.Pp
+The traditional protocol for writing to someone is that the string
+.Ql \-o ,
+either at the end of a line or on a line by itself, means that it's the
+other person's turn to talk.
+The string
+.Ql oo
+means that the person believes the conversation to be
+over.
+.Sh SEE ALSO
+.Xr mesg 1 ,
+.Xr talk 1 ,
+.Xr wall 1 ,
+.Xr who 1
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/basic_cmds/write/write.c b/basic_cmds/write/write.c
new file mode 100644
index 0000000..e3f2255
--- /dev/null
+++ b/basic_cmds/write/write.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jef Poskanzer and Craig Leres of the Lawrence Berkeley Laboratory.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)write.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+
+__RCSID("$FreeBSD: src/usr.bin/write/write.c,v 1.17 2002/09/04 23:29:09 dwmalone Exp $");
+
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <err.h>
+#include <locale.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+
+void done(int);
+void do_write(char *, char *, uid_t);
+static void usage(void);
+int term_chk(char *, int *, time_t *, int);
+void wr_fputs(unsigned char *s);
+void search_utmp(char *, char *, char *, uid_t);
+int utmp_chk(char *, char *);
+
+int
+main(int argc, char **argv)
+{
+ char *cp;
+ time_t atime;
+ uid_t myuid;
+ int msgsok, myttyfd;
+ char tty[MAXPATHLEN], *mytty;
+
+ (void)setlocale(LC_CTYPE, "");
+
+ while (getopt(argc, argv, "") != -1)
+ usage();
+ argc -= optind;
+ argv += optind;
+
+ /* check that sender has write enabled */
+ if (isatty(fileno(stdin)))
+ myttyfd = fileno(stdin);
+ else if (isatty(fileno(stdout)))
+ myttyfd = fileno(stdout);
+ else if (isatty(fileno(stderr)))
+ myttyfd = fileno(stderr);
+ else
+ myttyfd=-1;
+ if(myttyfd == -1)
+ mytty = "tty??";
+ else
+ {
+ if (!(mytty = ttyname(myttyfd)))
+ errx(1, "can't find your tty's name");
+ if ((cp = rindex(mytty, '/')))
+ mytty = cp + 1;
+ if (term_chk(mytty, &msgsok, &atime, 1))
+ exit(1);
+ if (!msgsok)
+ errx(1, "you have write permission turned off");
+ }
+ myuid = getuid();
+
+ /* check args */
+ switch (argc) {
+ case 1:
+ search_utmp(argv[0], tty, mytty, myuid);
+ do_write(tty, mytty, myuid);
+ break;
+ case 2:
+ if (!strncmp(argv[1], _PATH_DEV, strlen(_PATH_DEV)))
+ argv[1] += strlen(_PATH_DEV);
+ if (utmp_chk(argv[0], argv[1]))
+ errx(1, "%s is not logged in on %s", argv[0], argv[1]);
+ if (term_chk(argv[1], &msgsok, &atime, 1))
+ exit(1);
+ if (myuid && !msgsok)
+ errx(1, "%s has messages disabled on %s", argv[0], argv[1]);
+ do_write(argv[1], mytty, myuid);
+ break;
+ default:
+ usage();
+ }
+ done(0);
+ return (0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: write user [tty]\n");
+ exit(1);
+}
+
+/*
+ * utmp_chk - checks that the given user is actually logged in on
+ * the given tty
+ */
+int
+utmp_chk(char *user, char *tty)
+{
+ struct utmpx *u;
+
+ setutxent();
+ while((u = getutxent()) != NULL)
+ if(strncmp(u->ut_line, tty, sizeof(u->ut_line)) == 0) {
+ if(u->ut_type == USER_PROCESS &&
+ strncmp(u->ut_user, user, sizeof(u->ut_user)) == 0) {
+ endutxent();
+ return 0;
+ }
+ break;
+ }
+ endutxent();
+ return 1;
+}
+
+/*
+ * search_utmp - search utmp for the "best" terminal to write to
+ *
+ * Ignores terminals with messages disabled, and of the rest, returns
+ * the one with the most recent access time. Returns as value the number
+ * of the user's terminals with messages enabled, or -1 if the user is
+ * not logged in at all.
+ *
+ * Special case for writing to yourself - ignore the terminal you're
+ * writing from, unless that's the only terminal with messages enabled.
+ */
+void
+search_utmp(char *user, char *tty, char *mytty, uid_t myuid)
+{
+ struct utmpx ux, *u;
+ time_t bestatime, atime;
+ int nloggedttys, nttys, msgsok, user_is_me;
+ char atty[sizeof(ux.ut_line) + 1];
+
+ nloggedttys = nttys = 0;
+ bestatime = 0;
+ user_is_me = 0;
+ setutxent();
+ while ((u = getutxent()) != NULL) {
+ if (u->ut_type != USER_PROCESS)
+ continue;
+ if (strncmp(user, u->ut_user, sizeof(u->ut_user)) == 0) {
+ ++nloggedttys;
+ (void)strlcpy(atty, u->ut_line, sizeof(atty));
+ if (term_chk(atty, &msgsok, &atime, 0))
+ continue; /* bad term? skip */
+ if (myuid && !msgsok)
+ continue; /* skip ttys with msgs off */
+ if (strcmp(atty, mytty) == 0) {
+ user_is_me = 1;
+ continue; /* don't write to yourself */
+ }
+ ++nttys;
+ if (atime > bestatime) {
+ bestatime = atime;
+ (void)strcpy(tty, atty);
+ }
+ }
+ }
+
+ endutxent();
+ if (nloggedttys == 0)
+ errx(1, "%s is not logged in", user);
+ if (nttys == 0) {
+ if (user_is_me) { /* ok, so write to yourself! */
+ (void)strcpy(tty, mytty);
+ return;
+ }
+ errx(1, "%s has messages disabled", user);
+ } else if (nttys > 1) {
+ warnx("%s is logged in more than once; writing to %s", user, tty);
+ }
+}
+
+/*
+ * term_chk - check that a terminal exists, and get the message bit
+ * and the access time
+ */
+int
+term_chk(char *tty, int *msgsokP, time_t *atimeP, int showerror)
+{
+ struct stat s;
+ char path[MAXPATHLEN];
+
+ (void)snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty);
+ if (stat(path, &s) < 0) {
+ if (showerror)
+ warn("%s", path);
+ return(1);
+ }
+ *msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
+ *atimeP = s.st_atime;
+ return(0);
+}
+
+/*
+ * do_write - actually make the connection
+ */
+void
+do_write(char *tty, char *mytty, uid_t myuid)
+{
+ const char *login;
+ char *nows;
+ struct passwd *pwd;
+ time_t now;
+ char path[MAXPATHLEN], host[MAXHOSTNAMELEN], line[512];
+
+ /* Determine our login name before the we reopen() stdout */
+ if ((login = getlogin()) == NULL) {
+ if ((pwd = getpwuid(myuid)))
+ login = pwd->pw_name;
+ else
+ login = "???";
+ }
+
+ (void)snprintf(path, sizeof(path), "%s%s", _PATH_DEV, tty);
+ if ((freopen(path, "w", stdout)) == NULL)
+ err(1, "%s", path);
+
+ (void)signal(SIGINT, done);
+ (void)signal(SIGHUP, done);
+
+ /* print greeting */
+ if (gethostname(host, sizeof(host)) < 0)
+ (void)strcpy(host, "???");
+ now = time((time_t *)NULL);
+ nows = ctime(&now);
+ nows[16] = '\0';
+ (void)printf("\r\n\007\007\007Message from %s@%s on %s at %s ...\r\n",
+ login, host, mytty, nows + 11);
+
+ while (fgets(line, sizeof(line), stdin) != NULL)
+ wr_fputs((unsigned char *)line);
+}
+
+/*
+ * done - cleanup and exit
+ */
+void
+done(int n)
+{
+ (void)printf("EOF\r\n");
+ exit(0);
+}
+
+/*
+ * wr_fputs - like fputs(), but makes control characters visible and
+ * turns \n into \r\n
+ */
+void
+wr_fputs(unsigned char *s)
+{
+
+#define PUTC(c) if (putchar(c) == EOF) err(1, NULL);
+
+ for (; *s != '\0'; ++s) {
+ if (*s == '\n') {
+ PUTC('\r');
+ } else if (((*s & 0x80) && *s < 0xA0) ||
+ /* disable upper controls */
+ (!isprint(*s) && !isspace(*s) &&
+ *s != '\a' && *s != '\b')
+ ) {
+ if (*s & 0x80) {
+ *s &= ~0x80;
+ PUTC('M');
+ PUTC('-');
+ }
+ if (iscntrl(*s)) {
+ *s ^= 0x40;
+ PUTC('^');
+ }
+ }
+ PUTC(*s);
+ }
+ return;
+#undef PUTC
+}
diff --git a/bootstrap_cmds/.gitignore b/bootstrap_cmds/.gitignore
new file mode 100644
index 0000000..e073c02
--- /dev/null
+++ b/bootstrap_cmds/.gitignore
@@ -0,0 +1,6 @@
+BUILD/
+build/
+.DS_Store
+/mig.xcodeproj/project.xcworkspace/
+/mig.xcodeproj/xcuserdata/
+*~
diff --git a/bootstrap_cmds/APPLE_LICENSE b/bootstrap_cmds/APPLE_LICENSE
new file mode 100644
index 0000000..71fe6fd
--- /dev/null
+++ b/bootstrap_cmds/APPLE_LICENSE
@@ -0,0 +1,335 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 2.0 - August 6, 2003
+
+Please read this License carefully before downloading this software. By
+downloading or using this software, you are agreeing to be bound by the terms
+of this License. If you do not or cannot agree to the terms of this License,
+please do not download or use the software.
+
+Apple Note: In January 2007, Apple changed its corporate name from "Apple
+Computer, Inc." to "Apple Inc." This change has been reflected below and
+copyright years updated, but no other changes have been made to the APSL 2.0.
+
+1. General; Definitions. This License applies to any program or other
+work which Apple Inc. ("Apple") makes publicly available and which contains a
+notice placed by Apple identifying such program or work as "Original Code" and
+stating that it is subject to the terms of this Apple Public Source License
+version 2.0 ("License"). As used in this License:
+
+1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is the
+grantor of rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to Apple and (ii) that cover subject matter contained in
+the Original Code, but only to the extent necessary to use, reproduce and/or
+distribute the Original Code without infringement; and (b) in the case where
+You are the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to You and (ii) that cover subject matter in
+Your Modifications, taken alone or in combination with Original Code.
+
+1.2 "Contributor" means any person or entity that creates or contributes to
+the creation of Modifications.
+
+1.3 "Covered Code" means the Original Code, Modifications, the combination
+of Original Code and any Modifications, and/or any respective portions thereof.
+
+1.4 "Externally Deploy" means: (a) to sublicense, distribute or otherwise
+make Covered Code available, directly or indirectly, to anyone other than You;
+and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way
+to provide a service, including but not limited to delivery of content, through
+electronic communication with a client other than You.
+
+1.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "Modifications" mean any addition to, deletion from, and/or change to,
+the substance and/or structure of the Original Code, any previous
+Modifications, the combination of Original Code and any previous Modifications,
+and/or any respective portions thereof. When code is released as a series of
+files, a Modification is: (a) any addition to or deletion from the contents of
+a file containing Covered Code; and/or (b) any new file or other representation
+of computer program statements that contains any part of Covered Code.
+
+1.7 "Original Code" means (a) the Source Code of a program or other work as
+originally made available by Apple under this License, including the Source
+Code of any updates or upgrades to such programs or works made available by
+Apple under this License, and that has been expressly identified by Apple as
+such in the header file(s) of such work; and (b) the object code compiled from
+such Source Code and originally made available by Apple under this License
+
+1.8 "Source Code" means the human readable form of a program or other work
+that is suitable for making modifications to it, including all modules it
+contains, plus any associated interface definition files, scripts used to
+control compilation and installation of an executable (object code).
+
+1.9 "You" or "Your" means an individual or a legal entity exercising rights
+under this License. For legal entities, "You" or "Your" includes any entity
+which controls, is controlled by, or is under common control with, You, where
+"control" means (a) the power, direct or indirect, to cause the direction or
+management of such entity, whether by contract or otherwise, or (b) ownership
+of fifty percent (50%) or more of the outstanding shares or beneficial
+ownership of such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms and
+conditions of this License, Apple hereby grants You, effective on the date You
+accept this License and download the Original Code, a world-wide, royalty-free,
+non-exclusive license, to the extent of Apple's Applicable Patent Rights and
+copyrights covering the Original Code, to do the following:
+
+2.1 Unmodified Code. You may use, reproduce, display, perform, internally
+distribute within Your organization, and Externally Deploy verbatim, unmodified
+copies of the Original Code, for commercial or non-commercial purposes,
+provided that in each instance:
+
+(a) You must retain and reproduce in all copies of Original Code the
+copyright and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code that
+refer to this License; and
+
+(b) You must include a copy of this License with every copy of Source Code
+of Covered Code and documentation You distribute or Externally Deploy, and You
+may not offer or impose any terms on such Source Code that alter or restrict
+this License or the recipients' rights hereunder, except as permitted under
+Section 6.
+
+2.2 Modified Code. You may modify Covered Code and use, reproduce,
+display, perform, internally distribute within Your organization, and
+Externally Deploy Your Modifications and Covered Code, for commercial or
+non-commercial purposes, provided that in each instance You also meet all of
+these conditions:
+
+(a) You must satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) You must duplicate, to the extent it does not already exist, the notice
+in Exhibit A in each file of the Source Code of all Your Modifications, and
+cause the modified files to carry prominent notices stating that You changed
+the files and the date of any change; and
+
+(c) If You Externally Deploy Your Modifications, You must make Source Code
+of all Your Externally Deployed Modifications either available to those to whom
+You have Externally Deployed Your Modifications, or publicly available. Source
+Code of Your Externally Deployed Modifications must be released under the terms
+set forth in this License, including the license grants set forth in Section 3
+below, for as long as you Externally Deploy the Covered Code or twelve (12)
+months from the date of initial External Deployment, whichever is longer. You
+should preferably distribute the Source Code of Your Externally Deployed
+Modifications electronically (e.g. download from a web site).
+
+2.3 Distribution of Executable Versions. In addition, if You Externally
+Deploy Covered Code (Original Code and/or Modifications) in object code,
+executable form only, You must include a prominent notice, in the code itself
+as well as in related documentation, stating that Source Code of the Covered
+Code is available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+2.4 Third Party Rights. You expressly acknowledge and agree that although
+Apple and each Contributor grants the licenses to their respective portions of
+the Covered Code set forth herein, no assurances are provided by Apple or any
+Contributor that the Covered Code does not infringe the patent or other
+intellectual property rights of any other entity. Apple and each Contributor
+disclaim any liability to You for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a condition to
+exercising the rights and licenses granted hereunder, You hereby assume sole
+responsibility to secure any other intellectual property rights needed, if any.
+For example, if a third party patent license is required to allow You to
+distribute the Covered Code, it is Your responsibility to acquire that license
+before distributing the Covered Code.
+
+3. Your Grants. In consideration of, and as a condition to, the licenses
+granted to You under this License, You hereby grant to any person or entity
+receiving or distributing Covered Code under this License a non-exclusive,
+royalty-free, perpetual, irrevocable license, under Your Applicable Patent
+Rights and other intellectual property rights (other than patent) owned or
+controlled by You, to use, reproduce, display, perform, modify, sublicense,
+distribute and Externally Deploy Your Modifications of the same scope and
+extent as Apple's licenses under Sections 2.1 and 2.2 above.
+
+4. Larger Works. You may create a Larger Work by combining Covered Code
+with other code not governed by the terms of this License and distribute the
+Larger Work as a single product. In each such instance, You must make sure the
+requirements of this License are fulfilled for the Covered Code or any portion
+thereof.
+
+5. Limitations on Patent License. Except as expressly stated in Section
+2, no other patent rights, express or implied, are granted by Apple herein.
+Modifications and/or Larger Works may require additional patent licenses from
+Apple which Apple may grant in its sole discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee for,
+warranty, support, indemnity or liability obligations and/or other rights
+consistent with the scope of the license granted herein ("Additional Terms") to
+one or more recipients of Covered Code. However, You may do so only on Your own
+behalf and as Your sole responsibility, and not on behalf of Apple or any
+Contributor. You must obtain the recipient's agreement that any such Additional
+Terms are offered by You alone, and You hereby agree to indemnify, defend and
+hold Apple and every Contributor harmless for any liability incurred by or
+claims asserted against Apple or such Contributor by reason of any such
+Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new versions
+of this License from time to time. Each version will be given a distinguishing
+version number. Once Original Code has been published under a particular
+version of this License, You may continue to use it under the terms of that
+version. You may also choose to use such Original Code under the terms of any
+subsequent version of this License published by Apple. No one other than Apple
+has the right to modify the terms applicable to Covered Code created under this
+License.
+
+8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
+part pre-release, untested, or not fully tested works. The Covered Code may
+contain errors that could cause failures or loss of data, and may be incomplete
+or contain inaccuracies. You expressly acknowledge and agree that use of the
+Covered Code, or any portion thereof, is at Your sole and entire risk. THE
+COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF
+ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE"
+FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
+ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF
+SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF
+QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE AND EACH
+CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE
+COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR
+REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
+ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR
+WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE AUTHORIZED
+REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You acknowledge
+that the Covered Code is not intended for use in the operation of nuclear
+facilities, aircraft navigation, communication systems, or air traffic control
+machines in which case the failure of the Covered Code could lead to death,
+personal injury, or severe physical or environmental damage.
+
+9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
+EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR
+YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER
+UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS
+LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL
+PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF
+LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT
+APPLY TO YOU. In no event shall Apple's total liability to You for all damages
+(other than as may be required by applicable law) under this License exceed the
+amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+trademarks or trade names "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime
+Streaming Server" or any other trademarks, service marks, logos or trade names
+belonging to Apple (collectively "Apple Marks") or to any trademark, service
+mark, logo or trade name belonging to any Contributor. You agree not to use
+any Apple Marks in or as part of the name of products derived from the Original
+Code or to endorse or promote products derived from the Original Code other
+than as expressly permitted by and in strict compliance at all times with
+Apple's third party trademark usage guidelines which are posted at
+http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Subject to the licenses granted under this License, each
+Contributor retains all rights, title and interest in and to any Modifications
+made by such Contributor. Apple retains all rights, title and interest in and
+to the Original Code and any Modifications made by or on behalf of Apple
+("Apple Modifications"), and such Apple Modifications will not be automatically
+subject to this License. Apple may, at its sole discretion, choose to license
+such Apple Modifications under this License, or on different terms from those
+contained in this License or may choose not to license them at all.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+terminate:
+
+(a) automatically without notice from Apple if You fail to comply with any
+term(s) of this License and fail to cure such breach within 30 days of becoming
+aware of such breach;
+(b) immediately in the event of the circumstances described in Section
+13.5(b); or
+(c) automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement against Apple;
+provided that Apple did not first commence an action for patent infringement
+against You in that instance.
+
+12.2 Effect of Termination. Upon termination, You agree to immediately stop
+any further use, reproduction, modification, sublicensing and distribution of
+the Covered Code. All sublicenses to the Covered Code which have been properly
+granted prior to termination shall survive any termination of this License.
+Provisions which, by their nature, should remain in effect beyond the
+termination of this License shall survive, including but not limited to
+Sections 3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other
+for compensation, indemnity or damages of any sort solely as a result of
+terminating this License in accordance with its terms, and termination of this
+License will be without prejudice to any other right or remedy of any party.
+
+13. Miscellaneous.
+
+13.1 Government End Users. The Covered Code is a "commercial item" as
+defined in FAR 2.101. Government software and technical data rights in the
+Covered Code include only those rights customarily provided to the public as
+defined in this License. This customary commercial license in technical data
+and software is provided in accordance with FAR 12.211 (Technical Data) and
+12.212 (Computer Software) and, for Department of Defense purchases, DFAR
+252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in
+Commercial Computer Software or Computer Software Documentation). Accordingly,
+all U.S. Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2 Relationship of Parties. This License will not be construed as
+creating an agency, partnership, joint venture or any other form of legal
+association between or among You, Apple or any Contributor, and You will not
+represent to the contrary, whether expressly, by implication, appearance or
+otherwise.
+
+13.3 Independent Development. Nothing in this License will impair Apple's
+right to acquire, license, develop, have others develop for it, market and/or
+distribute technology or products that perform the same or similar functions
+as, or otherwise compete with, Modifications, Larger Works, technology or
+products that You may develop, produce, market or distribute.
+
+13.4 Waiver; Construction. Failure by Apple or any Contributor to enforce
+any provision of this License will not be deemed a waiver of future enforcement
+of that or any other provision. Any law or regulation which provides that the
+language of a contract shall be construed against the drafter will not apply to
+this License.
+
+13.5 Severability. (a) If for any reason a court of competent jurisdiction
+finds any provision of this License, or portion thereof, to be unenforceable,
+that provision of the License will be enforced to the maximum extent
+permissible so as to effect the economic benefits and intent of the parties,
+and the remainder of this License will continue in full force and effect. (b)
+Notwithstanding the foregoing, if applicable law prohibits or restricts You
+from fully and/or specifically complying with Sections 2 and/or 3 or prevents
+the enforceability of either of those Sections, this License will immediately
+terminate and You must immediately discontinue any use of the Covered Code and
+destroy all copies of it that are in your possession or control.
+
+13.6 Dispute Resolution. Any litigation or other dispute resolution between
+You and Apple relating to this License shall take place in the Northern
+District of California, and You and Apple hereby consent to the personal
+jurisdiction of, and venue in, the state and federal courts within that
+District with respect to this License. The application of the United Nations
+Convention on Contracts for the International Sale of Goods is expressly
+excluded.
+
+13.7 Entire Agreement; Governing Law. This License constitutes the entire
+agreement between the parties with respect to the subject matter hereof. This
+License shall be governed by the laws of the United States and the State of
+California, except that body of California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following clause
+applies: The parties hereby confirm that they have requested that this License
+and all related documents be drafted in English. Les parties ont exigé que le
+présent contrat et tous les documents connexes soient rédigés en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
+
+This file contains Original Code and/or Modifications of Original Code as
+defined in and that are subject to the Apple Public Source License Version 2.0
+(the 'License'). You may not use this file except in compliance with the
+License. Please obtain a copy of the License at
+http://www.opensource.apple.com/apsl/ and read it before using this file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
+OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
+specific language governing rights and limitations under the License."
+
diff --git a/bootstrap_cmds/mig.xcodeproj/project.pbxproj b/bootstrap_cmds/mig.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..8173f62
--- /dev/null
+++ b/bootstrap_cmds/mig.xcodeproj/project.pbxproj
@@ -0,0 +1,310 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 50;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ FC2E1879149BF95600349D18 /* mig.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCAD5337149BF58700CE0B4B /* mig.1 */; };
+ FC2E187A149BF95600349D18 /* migcom.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCAD533C149BF58700CE0B4B /* migcom.1 */; };
+ FCAD539C149BF58700CE0B4B /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD532B149BF58700CE0B4B /* error.c */; };
+ FCAD539D149BF58700CE0B4B /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD532D149BF58700CE0B4B /* global.c */; };
+ FCAD539F149BF58700CE0B4B /* header.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5330149BF58700CE0B4B /* header.c */; };
+ FCAD53A0149BF58700CE0B4B /* lexxer.l in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5334149BF58700CE0B4B /* lexxer.l */; };
+ FCAD53A2149BF58700CE0B4B /* mig.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5338149BF58700CE0B4B /* mig.c */; };
+ FCAD53A3149BF58700CE0B4B /* parser.y in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5340149BF58700CE0B4B /* parser.y */; };
+ FCAD53A4149BF58700CE0B4B /* routine.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5343149BF58700CE0B4B /* routine.c */; };
+ FCAD53A5149BF58700CE0B4B /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5345149BF58700CE0B4B /* server.c */; };
+ FCAD53A6149BF58700CE0B4B /* statement.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5346149BF58700CE0B4B /* statement.c */; };
+ FCAD53A7149BF58700CE0B4B /* string.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5349149BF58700CE0B4B /* string.c */; };
+ FCAD53A8149BF58700CE0B4B /* type.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD534A149BF58700CE0B4B /* type.c */; };
+ FCAD53A9149BF58700CE0B4B /* user.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD534C149BF58700CE0B4B /* user.c */; };
+ FCAD53AA149BF58700CE0B4B /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD534D149BF58700CE0B4B /* utils.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ FC2DBC52149BF01800EACA9D /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "$(DT_TOOLCHAIN_DIR)/usr/share/man/man1/";
+ dstSubfolderSpec = 0;
+ files = (
+ FC2E1879149BF95600349D18 /* mig.1 in CopyFiles */,
+ FC2E187A149BF95600349D18 /* migcom.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ FC2DBC54149BF01800EACA9D /* migcom */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = migcom; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC2E188C149C017900349D18 /* install-mig.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-mig.sh"; sourceTree = "<group>"; };
+ FCAD532A149BF58700CE0B4B /* alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alloc.h; sourceTree = "<group>"; };
+ FCAD532B149BF58700CE0B4B /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = "<group>"; };
+ FCAD532C149BF58700CE0B4B /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = "<group>"; };
+ FCAD532D149BF58700CE0B4B /* global.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = global.c; sourceTree = "<group>"; };
+ FCAD532E149BF58700CE0B4B /* global.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = global.h; sourceTree = "<group>"; };
+ FCAD532F149BF58700CE0B4B /* handler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = handler.c; sourceTree = "<group>"; };
+ FCAD5330149BF58700CE0B4B /* header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = header.c; sourceTree = "<group>"; };
+ FCAD5333149BF58700CE0B4B /* lexxer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lexxer.h; sourceTree = "<group>"; };
+ FCAD5334149BF58700CE0B4B /* lexxer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = lexxer.l; sourceTree = "<group>"; };
+ FCAD5337149BF58700CE0B4B /* mig.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mig.1; sourceTree = "<group>"; };
+ FCAD5338149BF58700CE0B4B /* mig.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mig.c; sourceTree = "<group>"; };
+ FCAD5339149BF58700CE0B4B /* mig.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = mig.sh; sourceTree = "<group>"; };
+ FCAD533A149BF58700CE0B4B /* mig_errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mig_errors.h; sourceTree = "<group>"; };
+ FCAD533B149BF58700CE0B4B /* mig_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mig_machine.h; sourceTree = "<group>"; };
+ FCAD533C149BF58700CE0B4B /* migcom.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = migcom.1; sourceTree = "<group>"; };
+ FCAD5340149BF58700CE0B4B /* parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = parser.y; sourceTree = "<group>"; };
+ FCAD5343149BF58700CE0B4B /* routine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = routine.c; sourceTree = "<group>"; };
+ FCAD5344149BF58700CE0B4B /* routine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = routine.h; sourceTree = "<group>"; };
+ FCAD5345149BF58700CE0B4B /* server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = "<group>"; };
+ FCAD5346149BF58700CE0B4B /* statement.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = statement.c; sourceTree = "<group>"; };
+ FCAD5347149BF58700CE0B4B /* statement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = statement.h; sourceTree = "<group>"; };
+ FCAD5348149BF58700CE0B4B /* strdefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdefs.h; sourceTree = "<group>"; };
+ FCAD5349149BF58700CE0B4B /* string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = string.c; sourceTree = "<group>"; };
+ FCAD534A149BF58700CE0B4B /* type.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = type.c; sourceTree = "<group>"; };
+ FCAD534B149BF58700CE0B4B /* type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = type.h; sourceTree = "<group>"; };
+ FCAD534C149BF58700CE0B4B /* user.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = user.c; sourceTree = "<group>"; };
+ FCAD534D149BF58700CE0B4B /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = "<group>"; };
+ FCAD534E149BF58700CE0B4B /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
+ FCAD534F149BF58700CE0B4B /* write.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = write.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FC2DBC51149BF01800EACA9D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ FC2DBC49149BF01800EACA9D = {
+ isa = PBXGroup;
+ children = (
+ FCAD5329149BF58700CE0B4B /* migcom */,
+ FC2E188B149C017900349D18 /* xcodescripts */,
+ FC2DBC55149BF01800EACA9D /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ FC2DBC55149BF01800EACA9D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FC2DBC54149BF01800EACA9D /* migcom */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FC2E188B149C017900349D18 /* xcodescripts */ = {
+ isa = PBXGroup;
+ children = (
+ FC2E188C149C017900349D18 /* install-mig.sh */,
+ );
+ path = xcodescripts;
+ sourceTree = "<group>";
+ };
+ FCAD5329149BF58700CE0B4B /* migcom */ = {
+ isa = PBXGroup;
+ children = (
+ FCAD532A149BF58700CE0B4B /* alloc.h */,
+ FCAD532B149BF58700CE0B4B /* error.c */,
+ FCAD532C149BF58700CE0B4B /* error.h */,
+ FCAD532D149BF58700CE0B4B /* global.c */,
+ FCAD532E149BF58700CE0B4B /* global.h */,
+ FCAD532F149BF58700CE0B4B /* handler.c */,
+ FCAD5330149BF58700CE0B4B /* header.c */,
+ FCAD5333149BF58700CE0B4B /* lexxer.h */,
+ FCAD5334149BF58700CE0B4B /* lexxer.l */,
+ FCAD5337149BF58700CE0B4B /* mig.1 */,
+ FCAD5338149BF58700CE0B4B /* mig.c */,
+ FCAD5339149BF58700CE0B4B /* mig.sh */,
+ FCAD533A149BF58700CE0B4B /* mig_errors.h */,
+ FCAD533B149BF58700CE0B4B /* mig_machine.h */,
+ FCAD533C149BF58700CE0B4B /* migcom.1 */,
+ FCAD5340149BF58700CE0B4B /* parser.y */,
+ FCAD5343149BF58700CE0B4B /* routine.c */,
+ FCAD5344149BF58700CE0B4B /* routine.h */,
+ FCAD5345149BF58700CE0B4B /* server.c */,
+ FCAD5346149BF58700CE0B4B /* statement.c */,
+ FCAD5347149BF58700CE0B4B /* statement.h */,
+ FCAD5348149BF58700CE0B4B /* strdefs.h */,
+ FCAD5349149BF58700CE0B4B /* string.c */,
+ FCAD534A149BF58700CE0B4B /* type.c */,
+ FCAD534B149BF58700CE0B4B /* type.h */,
+ FCAD534C149BF58700CE0B4B /* user.c */,
+ FCAD534D149BF58700CE0B4B /* utils.c */,
+ FCAD534E149BF58700CE0B4B /* utils.h */,
+ FCAD534F149BF58700CE0B4B /* write.h */,
+ );
+ name = migcom;
+ path = migcom.tproj;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ FC2DBC53149BF01800EACA9D /* migcom */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC2DBC5E149BF01800EACA9D /* Build configuration list for PBXNativeTarget "migcom" */;
+ buildPhases = (
+ FC2DBC50149BF01800EACA9D /* Sources */,
+ FC2DBC51149BF01800EACA9D /* Frameworks */,
+ FC2DBC52149BF01800EACA9D /* CopyFiles */,
+ FC2E1884149BFF0900349D18 /* Run Script */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = migcom;
+ productName = mig;
+ productReference = FC2DBC54149BF01800EACA9D /* migcom */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FC2DBC4B149BF01800EACA9D /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1100;
+ ORGANIZATIONNAME = "Apple Inc.";
+ };
+ buildConfigurationList = FC2DBC4E149BF01800EACA9D /* Build configuration list for PBXProject "mig" */;
+ compatibilityVersion = "Xcode 9.3";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = FC2DBC49149BF01800EACA9D;
+ productRefGroup = FC2DBC55149BF01800EACA9D /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FC2DBC53149BF01800EACA9D /* migcom */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FC2E1884149BFF0900349D18 /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-mig.sh";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FC2DBC50149BF01800EACA9D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCAD53A3149BF58700CE0B4B /* parser.y in Sources */,
+ FCAD53A0149BF58700CE0B4B /* lexxer.l in Sources */,
+ FCAD539C149BF58700CE0B4B /* error.c in Sources */,
+ FCAD539D149BF58700CE0B4B /* global.c in Sources */,
+ FCAD539F149BF58700CE0B4B /* header.c in Sources */,
+ FCAD53A2149BF58700CE0B4B /* mig.c in Sources */,
+ FCAD53A4149BF58700CE0B4B /* routine.c in Sources */,
+ FCAD53A5149BF58700CE0B4B /* server.c in Sources */,
+ FCAD53A6149BF58700CE0B4B /* statement.c in Sources */,
+ FCAD53A7149BF58700CE0B4B /* string.c in Sources */,
+ FCAD53A8149BF58700CE0B4B /* type.c in Sources */,
+ FCAD53A9149BF58700CE0B4B /* user.c in Sources */,
+ FCAD53AA149BF58700CE0B4B /* utils.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ FC2DBC5D149BF01800EACA9D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ SDKROOT = macosx.internal;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = __;
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = Release;
+ };
+ FC2DBC60149BF01800EACA9D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "MIG_VERSION=\\\"$(RC_ProjectNameAndSourceVersion)\\\"";
+ INSTALL_PATH = "$(DT_TOOLCHAIN_DIR)/usr/libexec";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ FC2DBC4E149BF01800EACA9D /* Build configuration list for PBXProject "mig" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC2DBC5D149BF01800EACA9D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC2DBC5E149BF01800EACA9D /* Build configuration list for PBXNativeTarget "migcom" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC2DBC60149BF01800EACA9D /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FC2DBC4B149BF01800EACA9D /* Project object */;
+}
diff --git a/bootstrap_cmds/migcom.tproj/alloc.h b/bootstrap_cmds/migcom.tproj/alloc.h
new file mode 100644
index 0000000..87b9b5f
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/alloc.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1999, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#ifndef _ALLOC_H
+#define _ALLOC_H
+
+#include <stdlib.h>
+
+#endif /* _ALLOC_H */
diff --git a/bootstrap_cmds/migcom.tproj/error.c b/bootstrap_cmds/migcom.tproj/error.c
new file mode 100644
index 0000000..37bcae3
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/error.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1999, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "global.h"
+#include "error.h"
+
+extern int lineno;
+extern char *yyinname;
+
+static char *program;
+__private_extern__
+int mig_errors = 0;
+
+/*ARGSUSED*/
+/*VARARGS1*/
+void
+fatal(char *format, ...)
+{
+ va_list pvar;
+ va_start(pvar, format);
+ fprintf(stderr, "%s: fatal: \"%s\", line %d: ", program, yyinname, lineno-1);
+ (void) vfprintf(stderr, format, pvar);
+ fprintf(stderr, "\n");
+ va_end(pvar);
+ exit(1);
+}
+
+__private_extern__
+/*ARGSUSED*/
+/*VARARGS1*/
+void
+warn(char *format, ...)
+{
+ va_list pvar;
+ va_start(pvar, format);
+ if (!BeQuiet && (mig_errors == 0)) {
+ fprintf(stderr, "\"%s\", line %d: warning: ", yyinname, lineno-1);
+ (void) vfprintf(stderr, format, pvar);
+ fprintf(stderr, "\n");
+ }
+ va_end(pvar);
+}
+
+/*ARGSUSED*/
+/*VARARGS1*/
+void
+error(char *format, ...)
+{
+ va_list pvar;
+ va_start(pvar, format);
+ fprintf(stderr, "\"%s\", line %d: ", yyinname, lineno-1);
+ (void) vfprintf(stderr, format, pvar);
+ fprintf(stderr, "\n");
+ va_end(pvar);
+ mig_errors++;
+}
+
+void
+set_program_name(char *name)
+{
+ program = name;
+}
diff --git a/bootstrap_cmds/migcom.tproj/error.h b/bootstrap_cmds/migcom.tproj/error.h
new file mode 100644
index 0000000..9ffd599
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/error.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1999, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#ifndef _ERROR_H
+#define _ERROR_H
+
+#include <errno.h>
+
+extern void fatal(char *format, ...);
+extern void warn(char *format, ...);
+extern void error(char *format, ...);
+
+extern int mig_errors;
+extern void set_program_name(char *name);
+
+#endif /* _ERROR_H */
diff --git a/bootstrap_cmds/migcom.tproj/global.c b/bootstrap_cmds/migcom.tproj/global.c
new file mode 100644
index 0000000..15c26f5
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/global.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 1999, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "strdefs.h"
+#include "global.h"
+#include "error.h"
+#include "mig_machine.h"
+
+boolean_t PrintVersion = FALSE;
+boolean_t BeQuiet = FALSE;
+boolean_t BeVerbose = FALSE;
+boolean_t UseMsgRPC = TRUE;
+boolean_t GenSymTab = FALSE;
+boolean_t UseEventLogger = FALSE;
+boolean_t BeLint = FALSE;
+boolean_t BeAnsiC = TRUE;
+boolean_t CheckNDR = FALSE;
+boolean_t PackMsg = PACK_MESSAGES;
+boolean_t UseSplitHeaders = FALSE;
+boolean_t ShortCircuit = FALSE;
+boolean_t UseRPCTrap = FALSE;
+boolean_t TestRPCTrap= FALSE;
+boolean_t IsVoucherCodeAllowed = TRUE;
+
+boolean_t IsKernelUser = FALSE;
+boolean_t IsKernelServer = FALSE;
+boolean_t UseSpecialReplyPort = FALSE;
+boolean_t HasUseSpecialReplyPort = FALSE;
+boolean_t HasConsumeOnSendError = FALSE;
+u_int ConsumeOnSendError = 0;
+
+string_t RCSId = strNULL;
+
+string_t SubsystemName = strNULL;
+u_int SubsystemBase = 0;
+
+string_t MsgOption = strNULL;
+string_t WaitTime = strNULL;
+string_t SendTime = strNULL;
+string_t ErrorProc = "MsgError";
+string_t ServerPrefix = "";
+string_t UserPrefix = "";
+string_t ServerDemux = strNULL;
+string_t ServerImpl = strNULL;
+string_t ServerSubsys = strNULL;
+int MaxMessSizeOnStack = -1; /* by default, always on stack */
+int UserTypeLimit = -1; /* by default, assume unlimited size. */
+
+string_t yyinname;
+
+char NewCDecl[] = "(defined(__STDC__) || defined(c_plusplus))";
+char LintLib[] = "defined(LINTLIBRARY)";
+
+void
+init_global()
+{
+ yyinname = strmake("<no name yet>");
+}
+
+string_t UserFilePrefix = strNULL;
+string_t UserHeaderFileName = strNULL;
+string_t ServerHeaderFileName = strNULL;
+string_t InternalHeaderFileName = strNULL;
+string_t DefinesHeaderFileName = strNULL;
+string_t UserFileName = strNULL;
+string_t ServerFileName = strNULL;
+string_t GenerationDate = strNULL;
+
+void
+more_global()
+{
+ if (SubsystemName == strNULL)
+ fatal("no SubSystem declaration");
+
+ if (UserHeaderFileName == strNULL)
+ UserHeaderFileName = strconcat(SubsystemName, ".h");
+ else if (streql(UserHeaderFileName, "/dev/null"))
+ UserHeaderFileName = strNULL;
+
+ if (UserFileName == strNULL)
+ UserFileName = strconcat(SubsystemName, "User.c");
+ else if (streql(UserFileName, "/dev/null"))
+ UserFileName = strNULL;
+
+ if (ServerFileName == strNULL)
+ ServerFileName = strconcat(SubsystemName, "Server.c");
+ else if (streql(ServerFileName, "/dev/null"))
+ ServerFileName = strNULL;
+
+ if (ServerDemux == strNULL)
+ ServerDemux = strconcat(SubsystemName, "_server");
+
+ if (ServerImpl == strNULL)
+ ServerImpl = strconcat(SubsystemName, "_impl");
+
+ if (ServerSubsys == strNULL) {
+ if (ServerPrefix != strNULL)
+ ServerSubsys = strconcat(ServerPrefix, SubsystemName);
+ else
+ ServerSubsys = SubsystemName;
+ ServerSubsys = strconcat(ServerSubsys, "_subsystem");
+ }
+ if (HasUseSpecialReplyPort && !BeAnsiC) {
+ fatal("Cannot use UseSpecialReplyPort in non ANSI mode\n");
+ }
+}
diff --git a/bootstrap_cmds/migcom.tproj/global.h b/bootstrap_cmds/migcom.tproj/global.h
new file mode 100644
index 0000000..39a133b
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/global.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#ifndef _GLOBAL_H
+#define _GLOBAL_H
+
+#include "type.h"
+
+extern boolean_t PrintVersion; /* print bootstrap_cmds project version and exit */
+extern boolean_t BeQuiet; /* no warning messages */
+extern boolean_t BeVerbose; /* summarize types, routines */
+extern boolean_t BeDebug; /* enters in the debug mode */
+extern boolean_t UseMsgRPC;
+extern boolean_t GenSymTab;
+extern boolean_t UseEventLogger;
+extern boolean_t BeLint;
+extern boolean_t BeAnsiC;
+extern boolean_t CheckNDR;
+extern boolean_t PackMsg;
+extern boolean_t UseSplitHeaders;
+extern boolean_t ShortCircuit;
+extern boolean_t UseRPCTrap;
+extern boolean_t TestRPCTrap;
+extern boolean_t IsVoucherCodeAllowed;
+
+extern boolean_t IsKernelUser;
+extern boolean_t IsKernelServer;
+extern boolean_t UseSpecialReplyPort;
+extern boolean_t HasUseSpecialReplyPort; /* whether UseSpecialReplyPort has ever been set to TRUE */
+extern boolean_t HasConsumeOnSendError; /* whether ConsumeOnSendError has ever been set */
+extern u_int ConsumeOnSendError;
+
+extern string_t RCSId;
+
+extern string_t SubsystemName;
+extern u_int SubsystemBase;
+
+extern string_t MsgOption;
+extern string_t WaitTime;
+extern string_t SendTime;
+extern string_t ErrorProc;
+extern string_t ServerPrefix;
+extern string_t UserPrefix;
+extern string_t ServerDemux;
+extern string_t ServerImpl;
+extern string_t ServerSubsys;
+extern int MaxMessSizeOnStack;
+extern int UserTypeLimit;
+
+extern int yylineno;
+extern string_t yyinname;
+
+extern void init_global(void);
+
+extern string_t UserFilePrefix;
+extern string_t UserHeaderFileName;
+extern string_t ServerHeaderFileName;
+extern string_t InternalHeaderFileName;
+extern string_t DefinesHeaderFileName;
+extern string_t UserFileName;
+extern string_t ServerFileName;
+
+extern void more_global(void);
+
+extern char NewCDecl[];
+extern char LintLib[];
+
+#endif /* _GLOBAL_H */
diff --git a/bootstrap_cmds/migcom.tproj/handler.c b/bootstrap_cmds/migcom.tproj/handler.c
new file mode 100644
index 0000000..b5156aa
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/handler.c
@@ -0,0 +1,754 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/********************************************************
+ * Abstract:
+ * routines to write pieces of the Handler module.
+ * exports WriteHandler which directs the writing of
+ * the Handler module
+ *
+ *
+ * $Header: /Users/Shared/bootstrap_cmds/bootstrap_cmds/migcom.tproj/handler.c,v 1.2 2005/02/06 07:28:59 lindak Exp $
+ *
+ * HISTORY
+ * 03-Jul-97 Daniel Wade (danielw) at Apple
+ * Generated code is now ANSI C compliant
+ *
+ * 10-Sep-91 Gregg Kellogg (gk) at NeXT
+ * Created.
+ *******************************************************/
+
+#include <mach/message.h>
+#include "write.h"
+#include "utils.h"
+#include "global.h"
+
+static void
+WriteIncludes(FILE *file)
+{
+ fprintf(file, "#define EXPORT_BOOLEAN\n");
+ fprintf(file, "#include <mach/boolean.h>\n");
+ fprintf(file, "#include <mach/message.h>\n");
+ fprintf(file, "#include <mach/mig_errors.h>\n");
+ if (IsCamelot) {
+ fprintf(file, "#include <cam/camelot_types.h>\n");
+ fprintf(file, "#include <mach/msg_type.h>\n");
+ }
+ fprintf(file, "#include \"%s\"\n", ServerHeaderFileName);
+ fprintf(file, "\n");
+}
+
+static void
+WriteGlobalDecls(FILE *file)
+{
+ fprintf(file, "#define novalue void\n");
+ fprintf(file, "\n");
+
+ if (RCSId != strNULL)
+ WriteRCSDecl(file, strconcat(SubsystemName, "_handler"), RCSId);
+
+ /* Used for locations in the request message, *not* reply message.
+ Reply message locations aren't dependent on IsKernel. */
+
+ if (IsKernel)
+ {
+ fprintf(file, "#define msg_request_port\tmsg_remote_port\n");
+ fprintf(file, "#define msg_reply_port\t\tmsg_local_port\n");
+ }
+ else
+ {
+ fprintf(file, "#define msg_request_port\tmsg_local_port\n");
+ fprintf(file, "#define msg_reply_port\t\tmsg_remote_port\n");
+ }
+}
+
+static void
+WriteProlog(FILE *file)
+{
+ fprintf(file, "/* Module %s */\n", SubsystemName);
+ fprintf(file, "\n");
+
+ WriteIncludes(file);
+ WriteBogusDefines(file);
+ WriteGlobalDecls(file);
+}
+
+
+static void
+WriteSymTabEntries(FILE *file statement_t *stats)
+{
+ statement_t *stat;
+ u_int current = 0;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ int num = stat->stRoutine->rtNumber;
+ char *name = stat->stRoutine->rtName;
+ while (++current <= num)
+ fprintf(file,"\t\t\t{ \"\", 0, 0 },\n");
+ fprintf(file, "\t{ \"%s\", %d, _X%s },\n",
+ name,
+ SubsystemBase + current - 1,
+ name);
+ }
+ while (++current <= rtNumber)
+ fprintf(file,"\t{ \"\", 0, 0 },\n");
+}
+
+static void
+WriteArrayEntries(FILE *file, statement_t *stats)
+{
+ u_int current = 0;
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine)
+ {
+ routine_t *rt = stat->stRoutine;
+
+ while (current++ < rt->rtNumber)
+ fprintf(file, "\t\t\t0,\n");
+ fprintf(file, "\t\t\t_X%s,\n", rt->rtName);
+ }
+ while (current++ < rtNumber)
+ fprintf(file, "\t\t\t0,\n");
+}
+
+static void
+WriteEpilog(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+ u_int MaxReply = 0;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind != skRoutine)
+ continue;
+ if (stat->stRoutine->rtMaxReplySize > MaxReply)
+ MaxReply = stat->stRoutine->rtMaxReplySize;
+ }
+
+ fprintf(file, "\n");
+
+ fprintf(file, "kern_return_t %s (\n", ServerProcName);
+ fprintf(file, "\tmsg_header_t *InHeadP,\n\t%s_t *%s)\n", SubsystemName, SubsystemName);
+
+ fprintf(file, "{\n");
+ fprintf(file, "\tchar OutBuf[%d];\n", MaxReply);
+ fprintf(file, "\tmsg_header_t *InP = InHeadP;\n");
+
+ if (IsCamelot)
+ fprintf(file, "\tcamelot_death_pill_t *OutP = (camelot_death_pill_t *) OutBuf;\n");
+ else
+ fprintf(file, "\tdeath_pill_t *OutP = (death_pill_t *) OutBuf;\n");
+
+ fprintf(file, "\n");
+
+ WriteStaticDecl(file, itRetCodeType, itRetCodeType->itDeallocate, itRetCodeType->itLongForm, "RetCodeType");
+ fprintf(file, "\n");
+
+ if (IsCamelot)
+ {
+ WriteStaticDecl(file, itDummyType, itDummyType->itDeallocate, itDummyType->itLongForm, "DummyType");
+ fprintf(file, "\n");
+ WriteStaticDecl(file, itTidType, itTidType->itDeallocate, itTidType->itLongForm, "TidType");
+ fprintf(file, "\n");
+ }
+
+ fprintf(file, "\tOutP->Head.msg_simple = TRUE;\n");
+ fprintf(file, "\tOutP->Head.msg_size = (mach_msg_size_t)sizeof(*OutP);\n");
+ fprintf(file, "\tOutP->Head.msg_type = InP->msg_type;\n");
+ fprintf(file, "\tOutP->Head.msg_local_port = PORT_NULL;\n");
+ fprintf(file, "\tOutP->Head.msg_remote_port = InP->msg_reply_port;\n");
+ fprintf(file, "\tOutP->Head.msg_id = InP->msg_id + 100;\n");
+ fprintf(file, "\n");
+ WritePackMsgType(file, itRetCodeType, itRetCodeType->itDeallocate, itRetCodeType->itLongForm, "OutP->RetCodeType", "RetCodeType");
+ fprintf(file, "\tOutP->RetCode = MIG_BAD_ID;\n");
+ fprintf(file, "\n");
+
+ if (IsCamelot)
+ {
+ WritePackMsgType(file, itDummyType, itDummyType->itDeallocate, itDummyType->itLongForm, "OutP->DummyType", "DummyType");
+ fprintf(file, "\t/* dummy doesn't need a value */\n");
+ fprintf(file, "\n");
+ WritePackMsgType(file, itTidType, itTidType->itDeallocate, itTidType->itLongForm, "OutP->TidType", "TidType");
+ fprintf(file, "\tOutP->Tid = ((camelot_death_pill_t *)InP)->Tid;\n");
+ fprintf(file, "\n");
+ }
+
+ fprintf(file, "\tif ((InP->msg_id > %d) || (InP->msg_id < %d))\n", SubsystemBase + rtNumber - 1, SubsystemBase);
+ fprintf(file, "\t\treturn OutP->RetCode;\n");
+ fprintf(file, "\telse {\n");
+ fprintf(file, "\t\ttypedef novalue (*SERVER_STUB_PROC) (\n");
+ fprintf(file, "\t\t\tmsg_header_t *,\n"
+ "\t\t\tmsg_header_t *,\n"
+ "\t\t\t%s_t *);\n", SubsystemName);
+ fprintf(file, "\t\tstatic const SERVER_STUB_PROC routines[] = {\n");
+
+ WriteArrayEntries(file, stats);
+
+ fprintf(file, "\t\t};\n");
+ fprintf(file, "\n");
+
+ /* Call appropriate routine */
+ fprintf(file, "\t\tif (routines[InP->msg_id - %d])\n", SubsystemBase);
+ fprintf(file, "\t\t\t(routines[InP->msg_id - %d]) (\n"
+ "\t\t\t\tInP, &OutP->Head, %s);\n",
+ SubsystemBase, SubsystemName);
+ fprintf(file, "\t\t else\n");
+ fprintf(file, "\t\t\treturn MIG_BAD_ID;\n");
+
+ fprintf(file, "\t}\n");
+
+ fprintf(file, "\tif (OutP->RetCode == MIG_NO_REPLY)\n");
+ fprintf(file, "\t\treturn KERN_SUCCESS;\n");
+ fprintf(file, "\treturn msg_send(&OutP->Head,\n");
+ fprintf(file, "\t\t%s->timeout >= 0 ? SEND_TIMEOUT : MSG_OPTION_NONE,\n", SubsystemName);
+ fprintf(file, "\t\t%s->timeout);\n", SubsystemName);
+ fprintf(file, "}\n");
+
+ /* symtab */
+
+ if (GenSymTab) {
+ fprintf(file,"\nmig_symtab_t _%sSymTab[] = {\n",SubsystemName);
+ WriteSymTabEntries(file,stats);
+ fprintf(file,"};\n");
+ fprintf(file,"int _%sSymTabBase = %d;\n",SubsystemName,SubsystemBase);
+ fprintf(file,"int _%sSymTabEnd = %d;\n",SubsystemName,SubsystemBase+rtNumber);
+ }
+}
+
+/*
+ * Returns the return type of the server-side work function.
+ * Suitable for "extern %s serverfunc()".
+ */
+static char *
+HandlerSideType(routine_t *rt)
+{
+ if (rt->rtServerReturn == argNULL)
+ return "void";
+ else
+ return rt->rtServerReturn->argType->itTransType;
+}
+
+static void
+WriteLocalVarDecl(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ if (it->itInLine && it->itVarArray)
+ {
+ ipc_type_t *btype = it->itElement;
+
+ fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, it->itNumber/btype->itNumber);
+ }
+ else
+ fprintf(file, "\t%s %s", it->itTransType, arg->argVarName);
+}
+
+static void
+_WriteHandlerVarDecl(FILE *file, argument_t *arg)
+{
+ fprintf(file, "%s %s%s", arg->argType->itTransType, argByReferenceServer(arg) ? "*" : "", arg->argVarName);
+}
+
+/*
+ * Writes the local variable declarations which are always
+ * present: InP, OutP, the server-side work function.
+ */
+static void
+WriteVarDecls(FILE *file, routine_t *rt)
+{
+ int i;
+
+ fprintf(file, "\tRequest *In0P = (Request *) InHeadP;\n");
+ for (i = 1; i <= rt->rtMaxRequestPos; i++)
+ fprintf(file, "\tRequest *In%dP;\n", i);
+ fprintf(file, "\tReply *OutP = (Reply *) OutHeadP;\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tboolean_t msg_simple;\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "\tunsigned int msg_size;\n");
+
+ /* if either request or reply is variable, we need msg_size_delta */
+ if ((rt->rtNumRequestVar > 0) || (rt->rtNumReplyVar > 0))
+ fprintf(file, "\tunsigned int msg_size_delta;\n");
+
+ fprintf(file, "\n");
+}
+
+static void
+WriteMsgError(FILE *file, argument_t *arg, char *error)
+{
+ if (arg == argNULL)
+ fprintf(file, "\t\t{ OutP->RetCode = %s; return; }\n", error);
+ else {
+ fprintf(file, "\t\t{ OutP->RetCode = %s; goto punt%d; }\n", error, arg->argPuntNum);
+ fprintf(file, "#define\tlabel_punt%d\n", arg->argPuntNum);
+ }
+}
+
+static void
+WriteReplyInit(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\n");
+ fprintf(file, "\tmsg_size = %d;\t\n", rt->rtReplySize);
+ if (rt->rtNumReplyVar > 0)
+ fprintf(file, "\t/* Maximum reply size %d */\n", rt->rtMaxReplySize);
+}
+
+static void
+WriteReplyHead(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\n");
+ if (rt->rtMaxReplyPos > 0)
+ fprintf(file, "\tOutP = (Reply *) OutHeadP;\n");
+
+ fprintf(file, "\tOutP->Head.msg_simple = %s;\n", strbool(rt->rtSimpleSendReply));
+ fprintf(file, "\tOutP->Head.msg_size = msg_size;\n");
+}
+
+static void
+WriteCheckHead(FILE *file, routine_t *rt)
+{
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tmsg_size = In0P->Head.msg_size;\n");
+ fprintf(file, "\tmsg_simple = In0P->Head.msg_simple;\n");
+
+ if (rt->rtNumRequestVar > 0) {
+ fprintf(file, "\tif ((msg_size < %d)", rt->rtRequestSize);
+ fprintf(file, " || (msg_size > %d)", rt->rtMaxRequestSize);
+ }
+ else
+ fprintf(file, "\tif ((msg_size != %d)", rt->rtRequestSize);
+ if (rt->rtSimpleCheckRequest)
+ fprintf(file, " || (msg_simple != %s)", strbool(rt->rtSimpleReceiveRequest));
+ fprintf(file, ")\n");
+ WriteMsgError(file, argNULL, "MIG_BAD_ARGUMENTS");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ fprintf(file, "\n");
+}
+
+static void
+WriteTypeCheck(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ routine_t *rt = arg->argRoutine;
+
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ if (akCheck(arg->argKind, akbQuickCheck))
+ {
+ fprintf(file, "#if\tUseStaticMsgType\n");
+ fprintf(file, "\tif (* (int *) &In%dP->%s != * (int *) &%sCheck)\n", arg->argRequestPos, arg->argTTName, arg->argVarName);
+ fprintf(file, "#else\t/* UseStaticMsgType */\n");
+ }
+ fprintf(file, "\tif ((In%dP->%s%s.msg_type_inline != %s) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? ".msg_type_header" : "", strbool(it->itInLine));
+ fprintf(file, "\t (In%dP->%s%s.msg_type_longform != %s) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? ".msg_type_header" : "", strbool(arg->argLongForm));
+ if (it->itOutName == MSG_TYPE_POLYMORPHIC)
+ {
+ if (!rt->rtSimpleCheckRequest)
+ fprintf(file, "\t (MSG_TYPE_PORT_ANY(In%dP->%s.msg_type_%sname) && msg_simple) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? "long_" : "");
+ }
+ else
+ fprintf(file, "\t (In%dP->%s.msg_type_%sname != %s) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? "long_" : "", it->itOutNameStr);
+ if (!it->itVarArray)
+ fprintf(file, "\t (In%dP->%s.msg_type_%snumber != %d) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? "long_" : "", it->itNumber);
+ fprintf(file, "\t (In%dP->%s.msg_type_%ssize != %d))\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? "long_" : "", it->itSize);
+ if (akCheck(arg->argKind, akbQuickCheck))
+ fprintf(file, "#endif\t/* UseStaticMsgType */\n");
+ WriteMsgError(file, arg, "MIG_BAD_ARGUMENTS");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ fprintf(file, "\n");
+}
+
+static void
+WriteCheckMsgSize(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+ ipc_type_t *btype = arg->argType->itElement;
+ argument_t *count = arg->argCount;
+ boolean_t NoMoreArgs, LastVarArg;
+
+ /* If there aren't any more In args after this, then
+ msg_size_delta value will only get used by TypeCheck code,
+ so put the assignment under the TypeCheck conditional. */
+
+ NoMoreArgs = arg->argRequestPos == rt->rtMaxRequestPos;
+
+ /* If there aren't any more variable-sized arguments after this,
+ then we must check for exact msg-size and we don't need
+ to update msg_size. */
+
+ LastVarArg = arg->argRequestPos+1 == rt->rtNumRequestVar;
+
+ if (NoMoreArgs)
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ /* calculate the actual size in bytes of the data field. note
+ that this quantity must be a multiple of four. hence, if
+ the base type size isn't a multiple of four, we have to
+ round up. note also that btype->itNumber must
+ divide btype->itTypeSize (see itCalculateSizeInfo). */
+
+ if (btype->itTypeSize % 4 != 0)
+ fprintf(file, "\tmsg_size_delta = (%d * In%dP->%s + 3) & ~3;\n", btype->itTypeSize/btype->itNumber, arg->argRequestPos, count->argMsgField);
+ else
+ fprintf(file, "\tmsg_size_delta = %d * In%dP->%s;\n", btype->itTypeSize/btype->itNumber, arg->argRequestPos, count->argMsgField);
+
+ if (!NoMoreArgs)
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ /* Don't decrement msg_size until we've checked it won't underflow. */
+
+ if (LastVarArg)
+ fprintf(file, "\tif (msg_size != %d + msg_size_delta)\n", rt->rtRequestSize);
+ else
+ fprintf(file, "\tif (msg_size < %d + msg_size_delta)\n", rt->rtRequestSize);
+ WriteMsgError(file, arg, "MIG_BAD_ARGUMENTS");
+
+ if (!LastVarArg)
+ fprintf(file, "\tmsg_size -= msg_size_delta;\n");
+
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ fprintf(file, "\n");
+}
+
+static void
+WriteExtractArgValue(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ if (arg->argMultiplier > 1)
+ WriteCopyType(file, it, FALSE, "%s /* %d %s %d */", "/* %s */ In%dP->%s / %d", arg->argVarName, arg->argRequestPos, arg->argMsgField, arg->argMultiplier);
+ else if (it->itInTrans != strNULL)
+ WriteCopyType(file, it, FALSE, "%s /* %s %d %s */", "/* %s */ %s(In%dP->%s)", arg->argVarName, it->itInTrans, arg->argRequestPos, arg->argMsgField);
+ else
+ WriteCopyType(file, it, FALSE, "%s /* %d %s */", "/* %s */ In%dP->%s", arg->argVarName, arg->argRequestPos, arg->argMsgField);
+ fprintf(file, "\n");
+}
+
+static void
+WriteInitializeCount(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argParent->argType;
+ ipc_type_t *btype = ptype->itElement;
+
+ /*
+ * Initialize 'count' argument for variable-length inline OUT parameter
+ * with maximum allowed number of elements.
+ */
+
+ fprintf(file, "\t%s = %d;\n", arg->argVarName, ptype->itNumber/btype->itNumber);
+ fprintf(file, "\n");
+}
+
+static void
+WriteExtractArg(FILE *file, argument_t *arg)
+{
+ if (akCheck(arg->argKind, akbRequest))
+ WriteTypeCheck(file, arg);
+
+ if (akCheckAll(arg->argKind, akbVariable|akbRequest))
+ WriteCheckMsgSize(file, arg);
+
+ if (akCheckAll(arg->argKind, akbSendRcv|akbVarNeeded))
+ WriteExtractArgValue(file, arg);
+
+ if ((akIdent(arg->argKind) == akeCount) && akCheck(arg->argKind, akbReturnSnd)) {
+ ipc_type_t *ptype = arg->argParent->argType;
+
+ if (ptype->itInLine && ptype->itVarArray)
+ WriteInitializeCount(file, arg);
+ }
+
+ /* This assumes that the count argument directly follows the
+ associated variable-sized argument and any other implicit
+ arguments it may have. */
+
+ if ((akIdent(arg->argKind) == akeCount) && akCheck(arg->argKind, akbSendRcv) && (arg->argRequestPos < arg->argRoutine->rtMaxRequestPos)) {
+ ipc_type_t *ptype = arg->argParent->argType;
+
+ if (ptype->itInLine && ptype->itVarArray) {
+ fprintf(file, "\tIn%dP = (Request *) ((char *) In%dP + msg_size_delta - %d);\n", arg->argRequestPos+1, arg->argRequestPos, ptype->itTypeSize + ptype->itPadSize);
+ fprintf(file, "\n");
+ }
+ }
+}
+
+static void
+WriteHandlerCallArg(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ boolean_t NeedClose = FALSE;
+
+ if (argByReferenceServer(arg))
+ fprintf(file, "&");
+
+ if ((it->itInTrans != strNULL) && akCheck(arg->argKind, akbSendRcv) && !akCheck(arg->argKind, akbVarNeeded)) {
+ fprintf(file, "%s(", it->itInTrans);
+ NeedClose = TRUE;
+ }
+
+ if (akCheck(arg->argKind, akbVarNeeded))
+ fprintf(file, "%s", arg->argVarName);
+ else if (akCheck(arg->argKind, akbSendRcv))
+ fprintf(file, "In%dP->%s", arg->argRequestPos, arg->argMsgField);
+ else
+ fprintf(file, "OutP->%s", arg->argMsgField);
+
+ if (NeedClose)
+ fprintf(file, ")");
+
+ if (!argByReferenceServer(arg) && (arg->argMultiplier > 1))
+ fprintf(file, " / %d", arg->argMultiplier);
+}
+
+static void
+WriteDestroyArg(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ fprintf(file, "#ifdef\tlabel_punt%d\n", arg->argPuntNum+1);
+ fprintf(file, "#undef\tlabel_punt%d\n", arg->argPuntNum+1);
+ fprintf(file, "punt%d:\n", arg->argPuntNum+1);
+ fprintf(file, "#endif\t/* label_punt%d */\n", arg->argPuntNum+1);
+
+ if (akCheck(arg->argKind, akbVarNeeded))
+ fprintf(file, "\t%s(%s);\n", it->itDestructor, arg->argVarName);
+ else
+ fprintf(file, "\t%s(In%dP->%s);\n", it->itDestructor, arg->argRequestPos, arg->argMsgField);
+}
+
+static void
+WriteHandlerCall(FILE *file, routine_t *rt)
+{
+ boolean_t NeedClose = FALSE;
+
+ fprintf(file, "\tif (%s->%s == 0)\n", SubsystemName, rt->rtName);
+ WriteMsgError(file, argNULL, "MIG_BAD_ID");
+
+ fprintf(file, "\t");
+ if (rt->rtServerReturn != argNULL) {
+ argument_t *arg = rt->rtServerReturn;
+ ipc_type_t *it = arg->argType;
+
+ if (rt->rtOneWay)
+ fprintf(file, "(void) ");
+ else
+ fprintf(file, "OutP->%s = ", arg->argMsgField);
+ if (it->itOutTrans != strNULL) {
+ fprintf(file, "%s(", it->itOutTrans);
+ NeedClose = TRUE;
+ }
+ }
+ fprintf(file, "(*%s->%s)(%s->arg", SubsystemName, rt->rtName, SubsystemName);
+ WriteListSkipFirst(file, rt->rtArgs, WriteHandlerCallArg, akbServerArg,
+ ", ", "");
+ if (NeedClose)
+ fprintf(file, ")");
+ fprintf(file, ");\n");
+}
+
+static void
+WriteGetReturnValue(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\t" "OutP->%s = %s;\n", rt->rtRetCode->argMsgField, rt->rtOneWay ? "MIG_NO_REPLY" : "KERN_SUCCESS");
+}
+
+static void
+WriteCheckReturnValue(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\tif (OutP->%s != KERN_SUCCESS)\n", rt->rtRetCode->argMsgField);
+ fprintf(file, "\t\treturn;\n");
+}
+
+static void
+WritePackArgType(FILE *file, argument_t *arg)
+{
+ fprintf(file, "\n");
+
+ WritePackMsgType(file, arg->argType, arg->argDeallocate, arg->argLongForm, "OutP->%s", "%s", arg->argTTName);
+}
+
+static void
+WritePackArgValue(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ fprintf(file, "\n");
+
+ if (it->itInLine && it->itVarArray) {
+ argument_t *count = arg->argCount;
+ ipc_type_t *btype = it->itElement;
+
+ /* Note btype->itNumber == count->argMultiplier */
+
+ fprintf(file, "\tbcopy((char *) %s, (char *) OutP->%s, ", arg->argVarName, arg->argMsgField);
+ fprintf(file, "%d * %s);\n", btype->itTypeSize, count->argVarName);
+ }
+ else if (arg->argMultiplier > 1)
+ WriteCopyType(file, it, TRUE, "OutP->%s /* %d %s */", "/* %s */ %d * %s", arg->argMsgField, arg->argMultiplier, arg->argVarName);
+ else if (it->itOutTrans != strNULL)
+ WriteCopyType(file, it, TRUE, "OutP->%s /* %s %s */", "/* %s */ %s(%s)", arg->argMsgField, it->itOutTrans, arg->argVarName);
+ else
+ WriteCopyType(file, it, TRUE, "OutP->%s /* %s */", "/* %s */ %s", arg->argMsgField, arg->argVarName);
+}
+
+static void
+WriteCopyArgValue(FILE *file, argument_t *arg)
+{
+ fprintf(file, "\n");
+ WriteCopyType(file, arg->argType, TRUE, "/* %d */ OutP->%s", "In%dP->%s", arg->argRequestPos, arg->argMsgField);
+}
+
+static void
+WriteAdjustMsgSize(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argParent->argType;
+ ipc_type_t *btype = ptype->itElement;
+
+ fprintf(file, "\n");
+
+ /* calculate the actual size in bytes of the data field.
+ note that this quantity must be a multiple of four.
+ hence, if the base type size isn't a multiple of four,
+ we have to round up. */
+
+ if (btype->itTypeSize % 4 != 0)
+ fprintf(file, "\tmsg_size_delta = (%d * %s + 3) & ~3;\n", btype->itTypeSize, arg->argVarName);
+ else
+ fprintf(file, "\tmsg_size_delta = %d * %s;\n", btype->itTypeSize, arg->argVarName);
+
+ fprintf(file, "\tmsg_size += msg_size_delta;\n");
+
+ /* Don't bother moving OutP unless there are more Out arguments. */
+ if (arg->argReplyPos < arg->argRoutine->rtMaxReplyPos) {
+ fprintf(file, "\tOutP = (Reply *) ((char *) OutP + ");
+ fprintf(file, "msg_size_delta - %d);\n", ptype->itTypeSize + ptype->itPadSize);
+ }
+}
+
+static void
+WritePackArg(FILE *file, argument_t *arg)
+{
+ if (akCheck(arg->argKind, akbReplyInit))
+ WritePackArgType(file, arg);
+
+ if (akCheckAll(arg->argKind, akbReturnSnd|akbVarNeeded))
+ WritePackArgValue(file, arg);
+
+ if (akCheck(arg->argKind, akbReplyCopy))
+ WriteCopyArgValue(file, arg);
+
+ if ((akIdent(arg->argKind) == akeCount) && akCheck(arg->argKind, akbReturnSnd)) {
+ ipc_type_t *ptype = arg->argParent->argType;
+
+ if (ptype->itInLine && ptype->itVarArray)
+ WriteAdjustMsgSize(file, arg);
+ }
+}
+
+static void
+WriteFieldDecl(FILE *file, argument_t *arg)
+{
+ WriteFieldDeclPrim(file, arg, FetchServerType);
+}
+
+static void
+WriteRoutine(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\n");
+
+ fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
+ fprintf(file, "mig_internal novalue _X%s (\n", rt->rtName);
+ fprintf(file, "\tmsg_header_t *InHeadP,\n"
+ "\tmsg_header_t *OutHeadP,\n"
+ "\t%s_t *%s)\n", SubsystemName, SubsystemName);
+
+ fprintf(file, "{\n");
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request");
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply");
+
+ WriteVarDecls(file, rt);
+
+ WriteList(file, rt->rtArgs, WriteCheckDecl, akbQuickCheck|akbRequest, "\n", "\n");
+ WriteList(file, rt->rtArgs, WriteTypeDecl, akbReplyInit, "\n", "\n");
+
+ WriteList(file, rt->rtArgs, WriteLocalVarDecl, akbVarNeeded, ";\n", ";\n\n");
+
+ WriteCheckHead(file, rt);
+
+ WriteList(file, rt->rtArgs, WriteExtractArg, akbNone, "", "");
+
+ WriteHandlerCall(file, rt);
+ WriteGetReturnValue(file, rt);
+
+ /* In reverse order so we can jump into the middle. */
+
+ WriteReverseList(file, rt->rtArgs, WriteDestroyArg, akbDestroy, "", "");
+ fprintf(file, "#ifdef\tlabel_punt0\n");
+ fprintf(file, "#undef\tlabel_punt0\n");
+ fprintf(file, "punt0:\n");
+ fprintf(file, "#endif\t/* label_punt0 */\n");
+
+ if (rt->rtOneWay)
+ fprintf(file, "\t;\n");
+ else {
+ WriteCheckReturnValue(file, rt);
+ WriteReplyInit(file, rt);
+ WriteList(file, rt->rtArgs, WritePackArg, akbNone, "", "");
+ WriteReplyHead(file, rt);
+ }
+
+ fprintf(file, "}\n");
+}
+
+void
+WriteHandler(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ WriteProlog(file);
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skRoutine:
+ WriteRoutine(file, stat->stRoutine);
+ break;
+
+ case skImport:
+ case skSImport:
+ WriteImport(file, stat->stFileName);
+ break;
+
+ case skUImport:
+ break;
+
+ default:
+ fatal("WriteHandler(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+ WriteEpilog(file, stats);
+}
+
diff --git a/bootstrap_cmds/migcom.tproj/header.c b/bootstrap_cmds/migcom.tproj/header.c
new file mode 100644
index 0000000..505cdd3
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/header.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "write.h"
+#include "utils.h"
+#include "global.h"
+#include "strdefs.h"
+#include "error.h"
+#include <stdlib.h>
+
+void
+WriteIncludes(FILE *file, boolean_t isuser, boolean_t isdef)
+{
+ if (isdef) {
+ fprintf(file, "#include <mach/port.h>\n");
+ fprintf(file, "#include <mach/machine/kern_return.h>\n");
+ if (!isuser)
+ fprintf(file, "#include <mach/mig_errors.h>\n");
+ }
+ else {
+ fprintf(file, "#include <string.h>\n");
+ fprintf(file, "#include <mach/ndr.h>\n");
+ fprintf(file, "#include <mach/boolean.h>\n");
+ fprintf(file, "#include <mach/kern_return.h>\n");
+ fprintf(file, "#include <mach/notify.h>\n");
+ fprintf(file, "#include <mach/mach_types.h>\n");
+ fprintf(file, "#include <mach/message.h>\n");
+ fprintf(file, "#include <mach/mig_errors.h>\n");
+ fprintf(file, "#include <mach/port.h>\n");
+
+ if (IsVoucherCodeAllowed && !IsKernelUser && !IsKernelServer) {
+ fprintf(file, "\t\n/* BEGIN VOUCHER CODE */\n\n");
+ fprintf(file, "#ifndef KERNEL\n");
+ fprintf(file, "#if defined(__has_include)\n");
+ fprintf(file, "#if __has_include(<mach/mig_voucher_support.h>)\n");
+ fprintf(file, "#ifndef USING_VOUCHERS\n");
+ fprintf(file, "#define USING_VOUCHERS\n");
+ fprintf(file, "#endif\n");
+
+
+ fprintf(file, "#ifndef __VOUCHER_FORWARD_TYPE_DECLS__\n");
+ fprintf(file, "#define __VOUCHER_FORWARD_TYPE_DECLS__\n");
+
+ fprintf(file, "#ifdef __cplusplus\n");
+ fprintf(file, "extern \"C\" {\n");
+ fprintf(file, "#endif\n");
+
+ fprintf(file, "\textern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));\n");
+
+ fprintf(file, "#ifdef __cplusplus\n");
+ fprintf(file, "}\n");
+ fprintf(file, "#endif\n");
+
+ fprintf(file, "#endif // __VOUCHER_FORWARD_TYPE_DECLS__\n");
+ fprintf(file, "#endif // __has_include(<mach/mach_voucher_types.h>)\n");
+ fprintf(file, "#endif // __has_include\n");
+ fprintf(file, "#endif // !KERNEL\n");
+
+ fprintf(file, "\t\n/* END VOUCHER CODE */\n\n");
+ }
+
+ fprintf(file, "\t\n/* BEGIN MIG_STRNCPY_ZEROFILL CODE */\n\n");
+ fprintf(file, "#if defined(__has_include)\n");
+ fprintf(file, "#if __has_include(<mach/mig_strncpy_zerofill_support.h>)\n");
+ fprintf(file, "#ifndef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "#define USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "#endif\n");
+
+ fprintf(file, "#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n");
+ fprintf(file, "#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n");
+
+ fprintf(file, "#ifdef __cplusplus\n");
+ fprintf(file, "extern \"C\" {\n");
+ fprintf(file, "#endif\n");
+
+ fprintf(file, "\textern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));\n");
+
+ fprintf(file, "#ifdef __cplusplus\n");
+ fprintf(file, "}\n");
+ fprintf(file, "#endif\n");
+
+ fprintf(file, "#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */\n");
+ fprintf(file, "#endif /* __has_include(<mach/mig_strncpy_zerofill_support.h>) */\n");
+ fprintf(file, "#endif /* __has_include */\n");
+ fprintf(file, "\t\n/* END MIG_STRNCPY_ZEROFILL CODE */\n\n");
+
+ if (ShortCircuit)
+ fprintf(file, "#include <mach/rpc.h>\n");
+ if (isuser && IsKernelUser) {
+ fprintf(file, "#if\t(__MigKernelSpecificCode) || (_MIG_KERNEL_SPECIFIC_CODE_)\n");
+ fprintf(file, "#include <kern/ipc_mig.h>\n");
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+ }
+ }
+ fprintf(file, "\n");
+}
+
+static void
+WriteETAPDefines(FILE *file)
+{
+ statement_t *stat;
+ int fnum;
+ char *fname;
+ int first = TRUE;
+
+ fprintf(file, "\n#ifndef subsystem_to_name_map_%s\n", SubsystemName);
+ fprintf(file, "#define subsystem_to_name_map_%s \\\n", SubsystemName);
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ fnum = SubsystemBase + stat->stRoutine->rtNumber;
+ fname = stat->stRoutine->rtName;
+ if (! first)
+ fprintf(file, ",\\\n");
+ fprintf(file, " { \"%s\", %d }", fname, fnum);
+ first = FALSE;
+ }
+ fprintf(file, "\n#endif\n");
+}
+
+static void
+WriteProlog(FILE *file, char *protect, boolean_t more, boolean_t isuser)
+{
+ if (protect != strNULL) {
+ fprintf(file, "#ifndef\t_%s\n", protect);
+ fprintf(file, "#define\t_%s\n", protect);
+ fprintf(file, "\n");
+ }
+
+ fprintf(file, "/* Module %s */\n", SubsystemName);
+ fprintf(file, "\n");
+
+ if (more) {
+ WriteIncludes(file, isuser, UseSplitHeaders);
+ }
+ fprintf(file, "#ifdef AUTOTEST\n");
+ fprintf(file, "#ifndef FUNCTION_PTR_T\n");
+ fprintf(file, "#define FUNCTION_PTR_T\n");
+ fprintf(file, "typedef void (*function_ptr_t)");
+ fprintf(file, "(mach_port_t, char *, mach_msg_type_number_t);\n");
+ fprintf(file, "typedef struct {\n");
+ fprintf(file, " char *name;\n");
+ fprintf(file, " function_ptr_t function;\n");
+ fprintf(file, "} function_table_entry;\n");
+ fprintf(file, "typedef function_table_entry *function_table_t;\n");
+ fprintf(file, "#endif /* FUNCTION_PTR_T */\n");
+ fprintf(file, "#endif /* AUTOTEST */\n");
+ fprintf(file, "\n#ifndef\t%s_MSG_COUNT\n", SubsystemName);
+ fprintf(file, "#define\t%s_MSG_COUNT\t%d\n", SubsystemName, rtNumber);
+ fprintf(file, "#endif\t/* %s_MSG_COUNT */\n\n", SubsystemName);
+}
+
+static void
+WriteEpilog(FILE *file, char *protect, boolean_t isuser)
+{
+ char *defname = isuser ? "__AfterMigUserHeader" : "__AfterMigServerHeader";
+
+ WriteETAPDefines(file);
+ fprintf(file, "\n#ifdef %s\n%s\n#endif /* %s */\n", defname, defname, defname);
+ if (protect != strNULL) {
+ fprintf(file, "\n");
+ fprintf(file, "#endif\t /* _%s */\n", protect);
+ }
+}
+
+static void
+WriteUserRoutine(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\n");
+ fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
+ WriteMigExternal(file);
+ fprintf(file, "%s %s\n", ReturnTypeStr(rt), rt->rtUserName);
+ if (BeLint) {
+ fprintf(file, "#if\t%s\n", LintLib);
+ fprintf(file, " (");
+ WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", " , "");
+ fprintf(file, ")\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n");
+ fprintf(file, "{ ");
+ fprintf(file, "return ");
+ fprintf(file, "%s(", rt->rtUserName);
+ WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", "");
+ fprintf(file, "); }\n");
+ fprintf(file, "#else\n");
+ }
+ if (BeAnsiC) {
+ fprintf(file, "(\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
+ fprintf(file, ");\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "(\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
+ fprintf(file, ");\n");
+ fprintf(file, "#else\n");
+
+ fprintf(file, " ();\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+ if (BeLint) {
+ fprintf(file, "#endif\t/* %s */\n", LintLib);
+ }
+}
+
+void
+WriteUserRequestUnion(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ fprintf(file, "/* union of all requests */\n\n");
+ fprintf(file, "#ifndef __RequestUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName);
+ fprintf(file, "#define __RequestUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName);
+ fprintf(file, "union __RequestUnion__%s%s_subsystem {\n", UserPrefix, SubsystemName);
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind == skRoutine) {
+ routine_t *rt;
+
+ rt = stat->stRoutine;
+ fprintf(file, "\t__Request__%s_t Request_%s;\n", rt->rtName, rt->rtUserName);
+ }
+ }
+ fprintf(file, "};\n");
+ fprintf(file, "#endif /* !__RequestUnion__%s%s_subsystem__defined */\n", UserPrefix, SubsystemName);
+}
+
+void
+WriteUserReplyUnion(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ fprintf(file, "/* union of all replies */\n\n");
+ fprintf(file, "#ifndef __ReplyUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName);
+ fprintf(file, "#define __ReplyUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName);
+ fprintf(file, "union __ReplyUnion__%s%s_subsystem {\n", UserPrefix, SubsystemName);
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind == skRoutine) {
+ routine_t *rt;
+
+ rt = stat->stRoutine;
+ fprintf(file, "\t__Reply__%s_t Reply_%s;\n", rt->rtName, rt->rtUserName);
+ }
+ }
+ fprintf(file, "};\n");
+ fprintf(file, "#endif /* !__RequestUnion__%s%s_subsystem__defined */\n", UserPrefix, SubsystemName);
+}
+
+void
+WriteUserHeader(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+ char *protect = strconcat(SubsystemName, "_user_");
+
+ WriteProlog(file, protect, TRUE, TRUE);
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skImport:
+ case skUImport:
+ case skDImport:
+ WriteImport(file, stat->stFileName);
+ break;
+
+ case skRoutine:
+ case skSImport:
+ case skIImport:
+ break;
+
+ default:
+ fatal("WriteHeader(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+ fprintf(file, "\n");
+ fprintf(file, "#ifdef __BeforeMigUserHeader\n");
+ fprintf(file, "__BeforeMigUserHeader\n");
+ fprintf(file, "#endif /* __BeforeMigUserHeader */\n");
+ fprintf(file, "\n");
+ fprintf(file, "#include <sys/cdefs.h>\n");
+ fprintf(file, "__BEGIN_DECLS\n");
+ fprintf(file, "\n");
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind == skRoutine)
+ WriteUserRoutine(file, stat->stRoutine);
+ }
+ fprintf(file, "\n");
+ fprintf(file, "__END_DECLS\n");
+
+ fprintf(file, "\n");
+ fprintf(file, "/********************** Caution **************************/\n");
+ fprintf(file, "/* The following data types should be used to calculate */\n");
+ fprintf(file, "/* maximum message sizes only. The actual message may be */\n");
+ fprintf(file, "/* smaller, and the position of the arguments within the */\n");
+ fprintf(file, "/* message layout may vary from what is presented here. */\n");
+ fprintf(file, "/* For example, if any of the arguments are variable- */\n");
+ fprintf(file, "/* sized, and less than the maximum is sent, the data */\n");
+ fprintf(file, "/* will be packed tight in the actual message to reduce */\n");
+ fprintf(file, "/* the presence of holes. */\n");
+ fprintf(file, "/********************** Caution **************************/\n");
+ fprintf(file, "\n");
+
+ WriteRequestTypes(file, stats);
+ WriteUserRequestUnion(file, stats);
+
+ WriteReplyTypes(file, stats);
+ WriteUserReplyUnion(file, stats);
+
+ WriteEpilog(file, protect, TRUE);
+}
+
+static void
+WriteDefinesRoutine(FILE *file, routine_t *rt)
+{
+ char *up = (char *)malloc(strlen(rt->rtName)+1);
+
+ up = toupperstr(strcpy(up, rt->rtName));
+ fprintf(file, "#define\tMACH_ID_%s\t\t%d\t/* %s() */\n", up, rt->rtNumber + SubsystemBase, rt->rtName);
+ if (rt->rtKind == rkRoutine)
+ fprintf(file, "#define\tMACH_ID_%s_REPLY\t\t%d\t/* %s() */\n", up, rt->rtNumber + SubsystemBase + 100, rt->rtName);
+ fprintf(file, "\n");
+}
+
+void
+WriteServerRoutine(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\n");
+ fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
+ WriteMigExternal(file);
+
+ // MIG_SERVER_ROUTINE can be defined by system headers to resolve to an attribute that
+ // tells the compiler that this is a MIG server routine. Useful for static analysis.
+ fprintf(file, "MIG_SERVER_ROUTINE\n%s %s\n", ReturnTypeStr(rt), rt->rtServerName);
+
+ if (BeLint) {
+ fprintf(file, "#if\t%s\n", LintLib);
+ fprintf(file, " (");
+ WriteList(file, rt->rtArgs, WriteNameDecl, akbServerArg, ", " , "");
+ fprintf(file, ")\n");
+ WriteList(file, rt->rtArgs, WriteServerVarDecl, akbServerArg, ";\n", ";\n");
+ fprintf(file, "{ ");
+ fprintf(file, "return ");
+ fprintf(file, "%s(", rt->rtServerName);
+ WriteList(file, rt->rtArgs, WriteNameDecl, akbServerArg, ", ", "");
+ fprintf(file, "); }\n");
+ fprintf(file, "#else /* %s */\n",LintLib);
+ }
+ if (BeAnsiC) {
+ fprintf(file, "(\n");
+ WriteList(file, rt->rtArgs, WriteServerVarDecl, akbServerArg, ",\n", "\n");
+ fprintf(file, ");\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "(\n");
+ WriteList(file, rt->rtArgs, WriteServerVarDecl, akbServerArg, ",\n", "\n");
+ fprintf(file, ");\n");
+ fprintf(file, "#else\n");
+
+ fprintf(file, " ();\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+ if (BeLint) {
+ fprintf(file, "#endif\t/* %s */\n", LintLib);
+ }
+}
+
+static void
+WriteDispatcher(FILE *file)
+{
+ statement_t *stat;
+ int descr_count = 0;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ routine_t *rt = stat->stRoutine;
+ descr_count += rtCountArgDescriptors(rt->rtArgs, (int *) 0);
+ }
+ fprintf(file, "\n");
+
+ WriteMigExternal(file);
+ fprintf(file, "boolean_t %s(\n", ServerDemux);
+ fprintf(file, "\t\tmach_msg_header_t *InHeadP,\n");
+ fprintf(file, "\t\tmach_msg_header_t *OutHeadP);\n\n");
+
+ WriteMigExternal(file);
+ fprintf(file, "mig_routine_t %s_routine(\n", ServerDemux);
+ fprintf(file, "\t\tmach_msg_header_t *InHeadP);\n\n");
+
+ fprintf(file, "\n/* Description of this subsystem, for use in direct RPC */\n");
+ fprintf(file, "extern const struct %s {\n", ServerSubsys);
+ if (UseRPCTrap) {
+ fprintf(file, "\tstruct subsystem *\tsubsystem;\t/* Reserved for system use */\n");
+ }
+ else {
+ fprintf(file, "\tmig_server_routine_t\tserver;\t/* Server routine */\n");
+ }
+ fprintf(file, "\tmach_msg_id_t\tstart;\t/* Min routine number */\n");
+ fprintf(file, "\tmach_msg_id_t\tend;\t/* Max routine number + 1 */\n");
+ fprintf(file, "\tunsigned int\tmaxsize;\t/* Max msg size */\n");
+ if (UseRPCTrap) {
+ fprintf(file, "\tvm_address_t\tbase_addr;\t/* Base address */\n");
+ fprintf(file, "\tstruct rpc_routine_descriptor\t/*Array of routine descriptors */\n");
+ }
+ else {
+ fprintf(file, "\tvm_address_t\treserved;\t/* Reserved */\n");
+ fprintf(file, "\tstruct routine_descriptor\t/*Array of routine descriptors */\n");
+ }
+ fprintf(file, "\t\troutine[%d];\n", rtNumber);
+ if (UseRPCTrap) {
+ fprintf(file, "\tstruct rpc_routine_arg_descriptor\t/*Array of arg descriptors */\n");
+ fprintf(file, "\t\targ_descriptor[%d];\n", descr_count);
+ }
+ fprintf(file, "} %s;\n", ServerSubsys);
+ fprintf(file, "\n");
+}
+
+void
+WriteBogusServerRoutineAnnotationDefine(FILE *file) {
+ // MIG_SERVER_ROUTINE can be defined by system headers to resolve to
+ // an attribute that tells the compiler that this is a MIG server routine.
+ // Useful for static analysis.
+ fprintf(file, "#ifndef MIG_SERVER_ROUTINE\n");
+ fprintf(file, "#define MIG_SERVER_ROUTINE\n");
+ fprintf(file, "#endif\n");
+ fprintf(file, "\n");
+}
+
+void
+WriteServerHeader(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+ char *protect = strconcat(SubsystemName, "_server_");
+
+ WriteProlog(file, protect, TRUE, FALSE);
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skImport:
+ case skSImport:
+ case skDImport:
+ WriteImport(file, stat->stFileName);
+ break;
+
+ case skRoutine:
+ case skUImport:
+ case skIImport:
+ break;
+
+ default:
+ fatal("WriteServerHeader(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+ fprintf(file, "\n#ifdef __BeforeMigServerHeader\n");
+ fprintf(file, "__BeforeMigServerHeader\n");
+ fprintf(file, "#endif /* __BeforeMigServerHeader */\n\n");
+
+ WriteBogusServerRoutineAnnotationDefine(file);
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind == skRoutine)
+ WriteServerRoutine(file, stat->stRoutine);
+ }
+ WriteDispatcher(file);
+
+ WriteRequestTypes(file, stats);
+ WriteServerRequestUnion(file, stats);
+
+ WriteReplyTypes(file, stats);
+ WriteServerReplyUnion(file, stats);
+
+ WriteEpilog(file, protect, FALSE);
+}
+
+static void
+WriteInternalRedefine(FILE *file, routine_t *rt)
+{
+ fprintf(file, "#define %s %s_external\n", rt->rtUserName, rt->rtUserName);
+}
+
+void
+WriteInternalHeader(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skRoutine:
+ WriteInternalRedefine(file, stat->stRoutine);
+ break;
+
+ case skImport:
+ case skUImport:
+ case skSImport:
+ case skDImport:
+ case skIImport:
+ break;
+
+ default:
+ fatal("WriteInternalHeader(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+}
+
+void
+WriteDefinesHeader(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+ char *protect = strconcat(SubsystemName, "_defines");
+
+ WriteProlog(file, protect, FALSE, FALSE);
+ fprintf(file, "\n/*\tDefines related to the Subsystem %s\t*/\n\n", SubsystemName);
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skRoutine:
+ WriteDefinesRoutine(file, stat->stRoutine);
+ break;
+
+ case skImport:
+ case skSImport:
+ case skUImport:
+ break;
+
+ default:
+ fatal("WriteDefinesHeader(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+ WriteEpilog(file, protect, FALSE);
+}
diff --git a/bootstrap_cmds/migcom.tproj/lexxer.h b/bootstrap_cmds/migcom.tproj/lexxer.h
new file mode 100644
index 0000000..6f1cfa5
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/lexxer.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+extern void LookFileName(void);
+extern void LookString(void);
+extern void LookQString(void);
+extern void LookNormal(void);
diff --git a/bootstrap_cmds/migcom.tproj/lexxer.l b/bootstrap_cmds/migcom.tproj/lexxer.l
new file mode 100644
index 0000000..82b32e5
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/lexxer.l
@@ -0,0 +1,314 @@
+%k 10000
+%n 5000
+%a 20000
+%e 10000
+%p 25000
+
+Ident ([A-Za-z_][A-Za-z_0-9]*)
+Number ([0-9]+)
+String ([-/._$A-Za-z0-9]+)
+QString (\"[^"\n]*\")
+AString (\<[^>\n]*\>)
+FileName ({QString}|{AString})
+
+/* new flex syntax to accomplish the same thing as #define YY_NO_UNPUT */
+%option nounput
+
+%{
+/*
+ * Copyright (c) 1999-2018 Apple, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999, 2008 Apple Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include "strdefs.h"
+#include "type.h"
+#include <sys/types.h>
+#include <mach/message.h>
+#include <mach/std_types.h>
+#include "statement.h"
+#include "global.h"
+#include "y.tab.h" // was parser.h
+#include "lexxer.h"
+#include "mig_machine.h"
+
+#define PortSize (sizeof (mach_port_t) * NBBY)
+#ifdef __STDC__
+#define stringize(x) #x
+#else /* __STDC__ */
+#define stringize(x) "x"
+#endif /* __STDC__ */
+
+#ifdef LDEBUG
+#define RETURN(sym) \
+{ \
+ printf("yylex: returning '%s' (%d)\n", stringize(sym), (sym)); \
+ return (sym); \
+}
+#else /* LDEBUG */
+#define RETURN(sym) return (sym)
+#endif /* LDEBUG */
+
+#define TPRETURN(intype, outtype, tsize) \
+{ \
+ yylval.symtype.innumber = (intype); \
+ yylval.symtype.instr = stringize(intype); \
+ yylval.symtype.outnumber = (outtype); \
+ yylval.symtype.outstr = stringize(outtype); \
+ yylval.symtype.size = (tsize); \
+ RETURN(sySymbolicType); \
+}
+
+#define TRETURN(type, tsize) TPRETURN(type,type,tsize)
+
+#define SAVE(s) do {oldYYBegin = s; BEGIN s; } while (0)
+
+#define RESTORE BEGIN oldYYBegin
+
+#define FRETURN(val) \
+{ \
+ yylval.flag = (val); \
+ RETURN(syIPCFlag); \
+}
+
+#define YY_NO_UNPUT /* suppress yyunput generation */
+
+static int oldYYBegin = 0;
+
+int lineno = 0; /* Replaces lex yylineno */
+
+static void doSharp(char *); /* process body of # directives */
+extern void yyerror(char *);
+%}
+
+%Start Normal String FileName QString SkipToEOL
+
+%%
+
+<Normal>[Rr][Oo][Uu][Tt][Ii][Nn][Ee] RETURN(syRoutine);
+<Normal>[Ss][Ii][Mm][Pp][Ll][Ee][Rr][Oo][Uu][Tt][Ii][Nn][Ee] RETURN(sySimpleRoutine);
+<Normal>[Ss][Uu][Bb][Ss][Yy][Ss][Tt][Ee][Mm] RETURN(sySubsystem);
+<Normal>[Mm][Ss][Gg][Oo][Pp][Tt][Ii][Oo][Nn] RETURN(syMsgOption);
+<Normal>[Uu][Ss][Ee][Ss][Pp][Ee][Cc][Ii][Aa][Ll][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syUseSpecialReplyPort);
+<Normal>[Cc][Oo][Nn][Ss][Uu][Mm][Ee][Oo][Nn][Ss][Ee][Nn][Dd][Ee][Rr][Rr][Oo][Rr] RETURN(syConsumeOnSendError);
+<Normal>[Mm][Ss][Gg][Ss][Ee][Qq][Nn][Oo] RETURN(syMsgSeqno);
+<Normal>[Ww][Aa][Ii][Tt][Tt][Ii][Mm][Ee] RETURN(syWaitTime);
+<Normal>[Ss][Ee][Nn][Dd][Tt][Ii][Mm][Ee] RETURN(sySendTime);
+<Normal>[Nn][Oo][Ww][Aa][Ii][Tt][Tt][Ii][Mm][Ee] RETURN(syNoWaitTime);
+<Normal>[Nn][Oo][Ss][Ee][Nn][Dd][Tt][Ii][Mm][Ee] RETURN(syNoSendTime);
+<Normal>[Ii][Nn] RETURN(syIn);
+<Normal>[Oo][Uu][Tt] RETURN(syOut);
+<Normal>[Uu][Ss][Ee][Rr][Ii][Mm][Pp][Ll] RETURN(syUserImpl);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Ii][Mm][Pp][Ll] RETURN(syServerImpl);
+<Normal>[Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(sySecToken);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(syServerSecToken);
+<Normal>[Uu][Ss][Ee][Rr][Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(syUserSecToken);
+<Normal>[Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syAuditToken);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syServerAuditToken);
+<Normal>[Uu][Ss][Ee][Rr][Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syUserAuditToken);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Cc][Oo][Nn][Tt][Ee][Xx][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syServerContextToken);
+<Normal>[Ii][Nn][Oo][Uu][Tt] RETURN(syInOut);
+<Normal>[Rr][Ee][Qq][Uu][Ee][Ss][Tt][Pp][Oo][Rr][Tt] RETURN(syRequestPort);
+<Normal>[Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syReplyPort);
+<Normal>[Uu][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syUReplyPort);
+<Normal>[Ss][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(sySReplyPort);
+<Normal>[Aa][Rr][Rr][Aa][Yy] RETURN(syArray);
+<Normal>[Oo][Ff] RETURN(syOf);
+<Normal>[Ee][Rr][Rr][Oo][Rr] RETURN(syErrorProc);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Pp][Rr][Ee][Ff][Ii][Xx] RETURN(syServerPrefix);
+<Normal>[Uu][Ss][Ee][Rr][Pp][Rr][Ee][Ff][Ii][Xx] RETURN(syUserPrefix);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Dd][Ee][Mm][Uu][Xx] RETURN(syServerDemux);
+<Normal>[Rr][Cc][Ss][Ii][Dd] RETURN(syRCSId);
+<Normal>[Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syImport);
+<Normal>[Uu][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syUImport);
+<Normal>[Ss][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(sySImport);
+<Normal>[Dd][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syDImport);
+<Normal>[Ii][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syIImport);
+<Normal>[Tt][Yy][Pp][Ee] RETURN(syType);
+<Normal>[Kk][Ee][Rr][Nn][Ee][Ll][Ss][Ee][Rr][Vv][Ee][Rr] RETURN(syKernelServer);
+<Normal>[Kk][Ee][Rr][Nn][Ee][Ll][Uu][Ss][Ee][Rr] RETURN(syKernelUser);
+<Normal>[Ss][Kk][Ii][Pp] RETURN(sySkip);
+<Normal>[Ss][Tt][Rr][Uu][Cc][Tt] RETURN(syStruct);
+<Normal>[Ii][Nn][Tt][Rr][Aa][Nn] RETURN(syInTran);
+<Normal>[Oo][Uu][Tt][Tt][Rr][Aa][Nn] RETURN(syOutTran);
+<Normal>[Dd][Ee][Ss][Tt][Rr][Uu][Cc][Tt][Oo][Rr] RETURN(syDestructor);
+<Normal>[Cc][Tt][Yy][Pp][Ee] RETURN(syCType);
+<Normal>[Cc][Uu][Ss][Ee][Rr][Tt][Yy][Pp][Ee] RETURN(syCUserType);
+<Normal>[Cc][Ss][Ee][Rr][Vv][Ee][Rr][Tt][Yy][Pp][Ee] RETURN(syCServerType);
+<Normal>[Cc]_[Ss][Tt][Rr][Ii][Nn][Gg] RETURN(syCString);
+
+<Normal>[Ss][Aa][Mm][Ee][Cc][Oo][Uu][Nn][Tt] FRETURN(flSameCount);
+<Normal>[Rr][Ee][Tt][Cc][Oo][Dd][Ee] FRETURN(flRetCode);
+<Normal>[Pp][Hh][Yy][Ss][Ii][Cc][Aa][Ll][Cc][Oo][Pp][Yy] FRETURN(flPhysicalCopy);
+<Normal>[Oo][Vv][Ee][Rr][Ww][Rr][Ii][Tt][Ee] FRETURN(flOverwrite);
+<Normal>[Dd][Ee][Aa][Ll][Ll][Oo][Cc] FRETURN(flDealloc);
+<Normal>[Nn][Oo][Tt][Dd][Ee][Aa][Ll][Ll][Oo][Cc] FRETURN(flNotDealloc);
+<Normal>[Cc][Oo][Uu][Nn][Tt][Ii][Nn][Oo][Uu][Tt] FRETURN(flCountInOut);
+<Normal>[Pp][Oo][Ll][Yy][Mm][Oo][Rr][Pp][Hh][Ii][Cc] TPRETURN(MACH_MSG_TYPE_POLYMORPHIC, MACH_MSG_TYPE_POLYMORPHIC, PortSize);
+<Normal>[Aa][Uu][Tt][Oo] FRETURN(flAuto);
+<Normal>[Cc][Oo][Nn][Ss][Tt] FRETURN(flConst);
+<Normal>"PointerTo" RETURN(syPointerTo);
+<Normal>"PointerToIfNot" RETURN(syPointerToIfNot);
+<Normal>"ValueOf" RETURN(syValueOf);
+<Normal>"UserTypeLimit" RETURN(syUserTypeLimit);
+<Normal>"OnStackLimit" RETURN(syOnStackLimit);
+
+
+<Normal>"MACH_MSG_TYPE_UNSTRUCTURED" TRETURN(MACH_MSG_TYPE_UNSTRUCTURED,0);
+<Normal>"MACH_MSG_TYPE_BIT" TRETURN(MACH_MSG_TYPE_BIT,1);
+<Normal>"MACH_MSG_TYPE_BOOLEAN" TRETURN(MACH_MSG_TYPE_BOOLEAN,32);
+<Normal>"MACH_MSG_TYPE_INTEGER_8" TRETURN(MACH_MSG_TYPE_INTEGER_8,8);
+<Normal>"MACH_MSG_TYPE_INTEGER_16" TRETURN(MACH_MSG_TYPE_INTEGER_16,16);
+<Normal>"MACH_MSG_TYPE_INTEGER_32" TRETURN(MACH_MSG_TYPE_INTEGER_32,32);
+<Normal>"MACH_MSG_TYPE_INTEGER_64" TRETURN(MACH_MSG_TYPE_INTEGER_64,64);
+<Normal>"MACH_MSG_TYPE_REAL_32" TRETURN(MACH_MSG_TYPE_REAL_32,32);
+<Normal>"MACH_MSG_TYPE_REAL_64" TRETURN(MACH_MSG_TYPE_REAL_64,64);
+<Normal>"MACH_MSG_TYPE_CHAR" TRETURN(MACH_MSG_TYPE_CHAR,8);
+<Normal>"MACH_MSG_TYPE_BYTE" TRETURN(MACH_MSG_TYPE_BYTE,8);
+
+<Normal>"MACH_MSG_TYPE_MOVE_RECEIVE" TPRETURN(MACH_MSG_TYPE_MOVE_RECEIVE,MACH_MSG_TYPE_PORT_RECEIVE,PortSize);
+<Normal>"MACH_MSG_TYPE_COPY_SEND" TPRETURN(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize);
+<Normal>"MACH_MSG_TYPE_MAKE_SEND" TPRETURN(MACH_MSG_TYPE_MAKE_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize);
+<Normal>"MACH_MSG_TYPE_MOVE_SEND" TPRETURN(MACH_MSG_TYPE_MOVE_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize);
+<Normal>"MACH_MSG_TYPE_MAKE_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_MAKE_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize);
+<Normal>"MACH_MSG_TYPE_MOVE_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_MOVE_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize);
+
+<Normal>"MACH_MSG_TYPE_PORT_NAME" TRETURN(MACH_MSG_TYPE_PORT_NAME,PortSize);
+<Normal>"MACH_MSG_TYPE_PORT_RECEIVE" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_RECEIVE,PortSize);
+<Normal>"MACH_MSG_TYPE_PORT_SEND" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_SEND,PortSize);
+<Normal>"MACH_MSG_TYPE_PORT_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize);
+<Normal>"MACH_MSG_TYPE_POLYMORPHIC" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC, MACH_MSG_TYPE_POLYMORPHIC, PortSize);
+
+<Normal>":" RETURN(syColon);
+<Normal>";" RETURN(sySemi);
+<Normal>"," RETURN(syComma);
+<Normal>"+" RETURN(syPlus);
+<Normal>"-" RETURN(syMinus);
+<Normal>"*" RETURN(syStar);
+<Normal>"/" RETURN(syDiv);
+<Normal>"(" RETURN(syLParen);
+<Normal>")" RETURN(syRParen);
+<Normal>"=" RETURN(syEqual);
+<Normal>"^" RETURN(syCaret);
+<Normal>"~" RETURN(syTilde);
+<Normal>"<" RETURN(syLAngle);
+<Normal>">" RETURN(syRAngle);
+<Normal>"[" RETURN(syLBrack);
+<Normal>"]" RETURN(syRBrack);
+<Normal>"|" RETURN(syBar);
+
+<Normal>{Ident} { yylval.identifier = strmake(yytext);
+ RETURN(syIdentifier); }
+<Normal>{Number} { yylval.number = atoi(yytext); RETURN(syNumber); }
+
+<String>{String} { yylval.string = strmake(yytext);
+ SAVE(Normal); RETURN(syString); }
+<FileName>{FileName} { yylval.string = strmake(yytext);
+ SAVE(Normal); RETURN(syFileName); }
+<QString>{QString} { yylval.string = strmake(yytext);
+ SAVE(Normal); RETURN(syQString); }
+
+^\#[ \t]*{Number}[ \t]*\"[^"]*\" { doSharp(yytext+1);
+ BEGIN SkipToEOL; }
+^\#\ *{Number} { doSharp(yytext+1);
+ BEGIN SkipToEOL; }
+^\#pragma { BEGIN SkipToEOL; }
+^\# { yyerror("illegal # directive");
+ BEGIN SkipToEOL; }
+
+<SkipToEOL>\n { RESTORE; lineno++; }
+<SkipToEOL>. ;
+
+[ \t] ;
+\n lineno++;
+. { SAVE(Normal); RETURN(syError); }
+
+%%
+
+extern void
+LookNormal()
+{
+ SAVE(Normal);
+}
+
+extern void
+LookString()
+{
+ SAVE(String);
+}
+
+extern void
+LookQString()
+{
+ SAVE(QString);
+}
+
+extern void
+LookFileName()
+{
+ SAVE(FileName);
+}
+
+static void
+doSharp(char *body)
+{
+ char *startName, *endName;
+
+ lineno = atoi(body);
+ startName = strchr(body, '"');
+ if (startName != NULL) {
+ endName = strrchr(body, '"');
+ *endName = '\0';
+ strfree(yyinname);
+ yyinname = strmake(startName+1);
+ }
+}
+
+int
+yywrap()
+{
+ return 1;
+}
diff --git a/bootstrap_cmds/migcom.tproj/mig.1 b/bootstrap_cmds/migcom.tproj/mig.1
new file mode 100644
index 0000000..6ab8cda
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/mig.1
@@ -0,0 +1,88 @@
+.TH MIG 1 "Nov 20, 2009" "Apple Computer, Inc."
+.SH NAME
+mig \- Mach Interface Generator
+.SH SYNOPSIS
+.B mig
+[
+.I "option \&..."
+]
+.I "file"
+
+.SH DESCRIPTION
+The
+.I mig
+command invokes the Mach Interface Generator to generate Remote Procedure Call (RPC)
+code for client-server style Mach IPC from specification files.
+.SH OPTIONS
+.TP
+.B \-q/-Q
+Omit /
+.I emit
+warning messages.
+.TP
+.B \-v/-V
+Verbose mode ( on /
+.I off
+) will summarize types and routines as they are processed.
+.TP
+.B \-l/-L
+Controls (
+.I off
+/ on ) whether or not generated code logs RPC events to system logs.
+.TP
+.B \-k/-K
+Controls (
+.I on
+/ off ) whether generated code complies with ANSI C standards.
+.TP
+.B \-s/-S
+Controls ( on /
+.I off
+) whether generated server-side code includes a generated symbol table.
+.TP
+.BI \-i " prefix"
+Specify User file prefix.
+.TP
+.BI \-user " path"
+Specify name of user-side RPC generated source file.
+.TP
+.BI \-server " path"
+Specify name of server-side RPC generated source file.
+.TP
+.BI \-header " path"
+Specify name of user-side generated header file.
+.TP
+.BI \-sheader " path"
+Specify name of server-side generated header file.
+.TP
+.BI \-iheader " path"
+Specify internal header file name.
+.TP
+.BI \-dheader " path"
+Specify defines generated header file.
+.TP
+.BI \-maxonstack " value"
+Specify maximum size of message on stack.
+.TP
+.B \-split
+Use split headers.
+.TP
+.BI \-arch " arch"
+Specify machine architecture for target code.
+.TP
+.B \-MD
+Option is passed to the C compiler for dependency generation.
+.TP
+.B \-cpp
+This option is ignored.
+.TP
+.BI \-cc " path"
+Specify pathname to specific C compiler to use as the preprocessor.
+.TP
+.BI \-migcom " path"
+Specify pathname to specific migcom compiler to use for source code generation.
+.TP
+.BI \-isysroot " path"
+Specify SDK root directory.
+.TP
+Additional options provided are passed along to the C compiler unchanged.
diff --git a/bootstrap_cmds/migcom.tproj/mig.c b/bootstrap_cmds/migcom.tproj/mig.c
new file mode 100644
index 0000000..9bdd304
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/mig.c
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Switches are;
+ * -[v,Q] verbose or not quiet: prints out type
+ * and routine information as mig runs.
+ * -[V,q] not verbose or quiet : don't print
+ * information during compilation
+ * (this is the default)
+ * -[r,R] do or don't use rpc calls instead of
+ * send/receive pairs. Default is -r.
+ * -[s,S] generate symbol table or not: generate a
+ * table of rpc-name, number, routine triplets
+ * as an external data structure -- main use is
+ * for protection system's specification of rights
+ * and for protection dispatch code. Default is -s.
+ * -[l,L] -L generate code that insert code for logging
+ * the most important events that happen at the
+ * stub level (message conception, target routine
+ * calls). Default is -l.
+ * -[k,K] -K enforces MIG to generate K&R C language, with the
+ * addition of ANSI C syntax under #ifdef __STDC__.
+ * Default is -k.
+ * -[n,N] -n enforces NDR checking and conversion logic generation.
+ * Default is -N (no checking).
+ * -i <prefix>
+ * Put each user routine in its own file. The
+ * file is named <prefix><routine-name>.c.
+ * -user <name>
+ * Name the user-side file <name>
+ * -server <name>
+ * Name the server-side file <name>
+ * -header <name>
+ * Name the user-side header file <name>
+ * -iheader <name>
+ * Name the user-side internal header file <name>
+ * -sheader <name>
+ * Name the server-side header file <name>
+ * -dheader <name>
+ * Name the defines (msgh_ids) header file <name>
+ *
+ * DESIGN:
+ * Mig uses a lexxer module created by lex from lexxer.l and
+ * a parser module created by yacc from parser.y to parse an
+ * interface definitions module for a mach server.
+ * The parser module calls routines in statement.c
+ * and routines.c to build a list of statement structures.
+ * The most interesting statements are the routine definitions
+ * which contain information about the name, type, characteristics
+ * of the routine, an argument list containing information for
+ * each argument type, and a list of special arguments. The
+ * argument type structures are build by routines in type.c
+ * Once parsing is completed, the three code generation modules:
+ * header.c user.c and server.c are called sequentially. These
+ * do some code generation directly and also call the routines
+ * in utils.c for common (parameterized) code generation.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include "error.h"
+#include "lexxer.h"
+#include "global.h"
+#include "write.h"
+
+extern int yyparse(void);
+static FILE *myfopen(const char *name, const char *mode);
+
+static void
+parseArgs(int argc,char *argv[])
+{
+ if (argc == 2 && streql(argv[1], "-version")) {
+ PrintVersion = TRUE;
+ return;
+ }
+
+ while (--argc > 0)
+ if ((++argv)[0][0] == '-') {
+ switch (argv[0][1]) {
+
+ case 'q':
+ BeQuiet = TRUE;
+ break;
+
+ case 'Q':
+ BeQuiet = FALSE;
+ break;
+
+ case 'v':
+ BeVerbose = TRUE;
+ break;
+
+ case 'V':
+ BeVerbose = FALSE;
+ break;
+
+ case 'r':
+ UseMsgRPC = TRUE;
+ break;
+
+ case 'R':
+ UseMsgRPC = FALSE;
+ break;
+
+ case 'l':
+ UseEventLogger = FALSE;
+ break;
+
+ case 'L':
+ UseEventLogger = TRUE;
+ break;
+
+ case 'k':
+ BeAnsiC = TRUE;
+ break;
+
+ case 'K':
+ BeAnsiC = FALSE;
+ break;
+
+ case 'n':
+ if (streql(argv[0], "-novouchers")) {
+ IsVoucherCodeAllowed = FALSE;
+ } else {
+ CheckNDR = TRUE;
+ }
+ break;
+
+ case 'N':
+ CheckNDR = FALSE;
+ break;
+
+ case 's':
+ if (streql(argv[0], "-server")) {
+ --argc; ++argv;
+ if (argc == 0)
+ fatal("missing name for -server option");
+ ServerFileName = strmake(argv[0]);
+ }
+ else if (streql(argv[0], "-sheader")) {
+ --argc; ++argv;
+ if (argc == 0)
+ fatal ("missing name for -sheader option");
+ ServerHeaderFileName = strmake(argv[0]);
+ }
+ else if (streql(argv[0], "-split"))
+ UseSplitHeaders = TRUE;
+ else
+ GenSymTab = TRUE;
+ break;
+
+ case 'S':
+ GenSymTab = FALSE;
+ break;
+
+ case 't':
+ warn("Mach RPC traps not fully supported");
+ TestRPCTrap = TRUE;
+ UseRPCTrap = TRUE;
+ break;
+
+ case 'T':
+ UseRPCTrap = FALSE;
+ break;
+
+ case 'i':
+ if (streql(argv[0], "-iheader")) {
+ --argc; ++argv;
+ if (argc == 0)
+ fatal("missing name for -iheader option");
+ InternalHeaderFileName = strmake(argv[0]);
+ }
+ else {
+ --argc; ++argv;
+ if (argc == 0)
+ fatal("missing prefix for -i option");
+ UserFilePrefix = strmake(argv[0]);
+ }
+ break;
+
+ case 'u':
+ if (streql(argv[0], "-user")) {
+ --argc; ++argv;
+ if (argc == 0)
+ fatal("missing name for -user option");
+ UserFileName = strmake(argv[0]);
+ }
+ else
+ fatal("unknown flag: '%s'", argv[0]);
+ break;
+
+ case 'h':
+ if (streql(argv[0], "-header")) {
+ --argc; ++argv;
+ if (argc == 0)
+ fatal("missing name for -header option");
+ UserHeaderFileName = strmake(argv[0]);
+ }
+ else
+ fatal("unknown flag: '%s'", argv[0]);
+ break;
+
+ case 'd':
+ if (streql(argv[0], "-dheader")) {
+ --argc; ++argv;
+ if (argc == 0)
+ fatal("missing name for -dheader option");
+ DefinesHeaderFileName = strmake(argv[0]);
+ }
+ else
+ fatal("unknown flag: '%s'", argv[0]);
+ break;
+
+ case 'm':
+ if (streql(argv[0], "-maxonstack")) {
+ --argc; ++argv;
+ if (argc == 0)
+ fatal("missing size for -maxonstack option");
+ MaxMessSizeOnStack = atoi(argv[0]);
+ }
+ else
+ fatal("unknown flag: '%s'", argv[0]);
+ break;
+
+ case 'X':
+ ShortCircuit = FALSE;
+ break;
+
+ case 'x':
+ ShortCircuit = TRUE;
+ /* fall thru - no longer supported */
+
+ default:
+ fatal("unknown/unsupported flag: '%s'", argv[0]);
+ /*NOTREACHED*/
+ }
+ }
+ else
+ fatal("bad argument: '%s'", *argv);
+}
+
+FILE *uheader, *server, *user;
+
+int
+main(int argc, char *argv[])
+{
+ FILE *iheader = 0;
+ FILE *sheader = 0;
+ FILE *dheader = 0;
+ time_t loc;
+ extern string_t GenerationDate;
+
+ set_program_name("mig");
+ parseArgs(argc, argv);
+ if (PrintVersion) {
+ printf("%s\n", MIG_VERSION);
+ fflush(stdout);
+ exit(0);
+ }
+ init_global();
+ init_type();
+ loc = time((time_t *)0);
+ GenerationDate = ctime(&loc);
+
+ LookNormal();
+ (void) yyparse();
+
+ if (mig_errors > 0)
+ fatal("%d errors found. Abort.\n", mig_errors);
+
+ more_global();
+
+ uheader = myfopen(UserHeaderFileName, "w");
+ if (!UserFilePrefix)
+ user = myfopen(UserFileName, "w");
+ server = myfopen(ServerFileName, "w");
+ if (ServerHeaderFileName)
+ sheader = myfopen(ServerHeaderFileName, "w");
+ if (IsKernelServer) {
+ iheader = myfopen(InternalHeaderFileName, "w");
+ }
+ if (DefinesHeaderFileName)
+ dheader = myfopen(DefinesHeaderFileName, "w");
+ if (BeVerbose) {
+ printf("Writing %s ... ", UserHeaderFileName);
+ fflush(stdout);
+ }
+ WriteUserHeader(uheader, stats);
+ fclose(uheader);
+ if (ServerHeaderFileName) {
+ if (BeVerbose) {
+ printf ("done.\nWriting %s ...", ServerHeaderFileName);
+ fflush (stdout);
+ }
+ WriteServerHeader(sheader, stats);
+ fclose(sheader);
+ }
+ if (IsKernelServer) {
+ if (BeVerbose) {
+ printf("done.\nWriting %s ... ", InternalHeaderFileName);
+ fflush(stdout);
+ }
+ WriteInternalHeader(iheader, stats);
+ fclose(iheader);
+ }
+ if (DefinesHeaderFileName) {
+ if (BeVerbose) {
+ printf ("done.\nWriting %s ...", DefinesHeaderFileName);
+ fflush (stdout);
+ }
+ WriteDefinesHeader(dheader, stats);
+ fclose(dheader);
+ }
+ if (UserFilePrefix) {
+ if (BeVerbose) {
+ printf("done.\nWriting individual user files ... ");
+ fflush(stdout);
+ }
+ WriteUserIndividual(stats);
+ }
+ else {
+ if (BeVerbose) {
+ printf("done.\nWriting %s ... ", UserFileName);
+ fflush(stdout);
+ }
+ WriteUser(user, stats);
+ fclose(user);
+ }
+ if (BeVerbose) {
+ printf("done.\nWriting %s ... ", ServerFileName);
+ fflush(stdout);
+ }
+ WriteServer(server, stats);
+ fclose(server);
+ if (BeVerbose)
+ printf("done.\n");
+
+ exit(0);
+}
+
+static FILE *
+myfopen(const char *name, const char *mode)
+{
+ const char *realname;
+ FILE *file;
+
+ if (name == strNULL)
+ realname = "/dev/null";
+ else
+ realname = name;
+
+ file = fopen(realname, mode);
+ if (file == NULL)
+ fatal("fopen(%s): %s", realname, strerror(errno));
+
+ return file;
+}
diff --git a/bootstrap_cmds/migcom.tproj/mig.sh b/bootstrap_cmds/migcom.tproj/mig.sh
new file mode 100644
index 0000000..85cf5a2
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/mig.sh
@@ -0,0 +1,218 @@
+#!/bin/bash
+#
+# Copyright (c) 1999-2008 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# "Portions Copyright (c) 1999, 2008 Apple Inc. All Rights
+# Reserved. This file contains Original Code and/or Modifications of
+# Original Code as defined in and that are subject to the Apple Public
+# Source License Version 1.0 (the 'License'). You may not use this file
+# except in compliance with the License. Please obtain a copy of the
+# License at http://www.apple.com/publicsource and read it before using
+# this file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+# License for the specific language governing rights and limitations
+# under the License."
+#
+# @APPLE_LICENSE_HEADER_END@
+#
+# Mach Operating System
+# Copyright (c) 1991,1990 Carnegie Mellon University
+# All Rights Reserved.
+#
+# Permission to use, copy, modify and distribute this software and its
+# documentation is hereby granted, provided that both the copyright
+# notice and this permission notice appear in all copies of the
+# software, derivative works or modified versions, and any portions
+# thereof, and that both notices appear in supporting documentation.
+#
+# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+#
+# Carnegie Mellon requests users of this software to return to
+#
+# Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+# School of Computer Science
+# Carnegie Mellon University
+# Pittsburgh PA 15213-3890
+#
+# any improvements or extensions that they make and grant Carnegie Mellon
+# the rights to redistribute these changes.
+#
+
+realpath()
+{
+ local FILE="$1"
+ local PARENT=$(dirname "$FILE")
+ local BASE=$(basename "$FILE")
+ pushd "$PARENT" >/dev/null 2>&1 || return 0
+ local DIR=$(pwd -P)
+ popd >/dev/null
+ if [ "$DIR" == "/" ]; then
+ echo "/$BASE"
+ else
+ echo "$DIR/$BASE"
+ fi
+ return 1
+}
+
+scriptPath=$(realpath "$0")
+scriptRoot=$(dirname "$scriptPath")
+migcomPath=$(realpath "${scriptRoot}/../libexec/migcom")
+
+if [ -n "${SDKROOT}" ]; then
+ sdkRoot="${SDKROOT}";
+fi
+
+if [ -z "${MIGCC}" ]; then
+ xcrunPath="/usr/bin/xcrun"
+ if [ -x "${xcrunPath}" ]; then
+ MIGCC=`"${xcrunPath}" -sdk "$sdkRoot" -find cc`
+ else
+ MIGCC=$(realpath "${scriptRoot}/cc")
+ fi
+fi
+
+C=${MIGCC}
+M=${MIGCOM-${migcomPath}}
+
+if [ $# -eq 1 ] && [ "$1" = "-version" ] ; then
+ "$M" "$@"
+ exit $?
+fi
+
+cppflags="-D__MACH30__"
+
+files=
+arch=`/usr/bin/arch`
+
+WORKTMP=`/usr/bin/mktemp -d "${TMPDIR:-/tmp}/mig.XXXXXX"`
+if [ $? -ne 0 ]; then
+ echo "Failure creating temporary work directory: ${WORKTMP}"
+ echo "Exiting..."
+ exit 1
+fi
+
+# parse out the arguments until we hit plain file name(s)
+
+until [ $# -eq 0 ]
+do
+ case "$1" in
+ -[dtqkKQvVtTrRsSlLxXnN] ) migflags=( "${migflags[@]}" "$1" ); shift;;
+ -i ) sawI=1; migflags=( "${migflags[@]}" "$1" "$2" ); shift; shift;;
+ -user ) user="$2"; if [ ! "${sawI-}" ]; then migflags=( "${migflags[@]}" "$1" "$2" ); fi; shift; shift;;
+ -server ) server="$2"; migflags=( "${migflags[@]}" "$1" "$2" ); shift; shift;;
+ -header ) header="$2"; migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;;
+ -sheader ) sheader="$2"; migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;;
+ -iheader ) iheader="$2"; migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;;
+ -dheader ) dheader="$2"; migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;;
+ -arch ) arch="$2"; shift; shift;;
+ -target ) target=( "$1" "$2"); shift; shift;;
+ -maxonstack ) migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;;
+ -split ) migflags=( "${migflags[@]}" "$1" ); shift;;
+ -novouchers ) migflags=( "${migflags[@]}" "$1" ); shift;;
+ -MD ) sawMD=1; cppflags=( "${cppflags[@]}" "$1"); shift;;
+ -cpp) shift; shift;;
+ -cc) C="$2"; shift; shift;;
+ -migcom) M="$2"; shift; shift;;
+ -isysroot) sdkRoot=$(realpath "$2"); shift; shift;;
+ -* ) cppflags=( "${cppflags[@]}" "$1"); shift;;
+ * ) break;;
+ esac
+done
+
+# process the rest as files
+until [ $# -eq 0 ]
+do
+ case "$1" in
+ -[dtqkKQvVtTrRsSlLxXnN] ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;;
+ -i ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -user ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -server ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -header ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -sheader ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -iheader ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -dheader ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -arch ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift ; shift; continue;;
+ -target ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift ; shift; continue;;
+ -maxonstack ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -split ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;;
+ -novouchers ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;;
+ -MD ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;;
+ -cpp) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -cc) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -migcom) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -isysroot) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;;
+ -* ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;;
+ * ) file="$1"; shift;;
+ esac
+ base="$(basename "${file}" .defs)"
+ temp="${WORKTMP}/${base}.$$"
+ sourcedir="$(dirname "${file}")"
+ if [ -n "${sdkRoot}" ]
+ then
+ iSysRootParm=( "-isysroot" "${sdkRoot}" )
+ fi
+ if [ ! -r "${file}" ]
+ then
+ echo "error: cannot read file ${file}"
+ rm -rf ${WORKTMP}
+ exit 1
+ fi
+ rm -f "${temp}.c" "${temp}.d"
+ (echo '#line 1 '\"${file}\" ; cat "${file}" ) > "${temp}.c"
+ "$C" -E -arch ${arch} "${target[@]}" "${cppflags[@]}" -I "${sourcedir}" "${iSysRootParm[@]}" "${temp}.c" | "$M" "${migflags[@]}"
+ if [ $? -ne 0 ]
+ then
+ rm -rf "${temp}.c" "${temp}.d" "${WORKTMP}"
+ exit 1
+ fi
+ if [ "${sawMD}" -a -f "${temp}.d" ]
+ then
+ deps=
+ s=
+ rheader="${header-${base}.h}"
+ if [ "${rheader}" != /dev/null ]; then
+ deps="${deps}${s}${rheader}"; s=" "
+ fi
+ ruser="${user-${base}User.c}"
+ if [ "${ruser}" != /dev/null ]; then
+ deps="${deps}${s}${ruser}"; s=" "
+ fi
+ rserver="${server-${base}Server.c}"
+ if [ "${rserver}" != /dev/null ]; then
+ deps="${deps}${s}${rserver}"; s=" "
+ fi
+ rsheader="${sheader-/dev/null}"
+ if [ "${rsheader}" != /dev/null ]; then
+ deps="${deps}${s}${rsheader}"; s=" "
+ fi
+ riheader="${iheader-/dev/null}"
+ if [ "${riheader}" != /dev/null ]; then
+ deps="${deps}${s}${riheader}"; s=" "
+ fi
+ rdheader="${dheader-/dev/null}"
+ if [ "${rdheader}" != /dev/null ]; then
+ deps="${deps}${s}${rdheader}"; s=" "
+ fi
+ for target in "${deps}"
+ do
+ sed -e 's;^'"${temp}"'.o[ ]*:;'"${target}"':;' \
+ -e 's;: '"${temp}"'.c;: '"$file"';' \
+ < "${temp}.d" > "${target}.d"
+ done
+ rm -f "${temp}.d"
+ fi
+ rm -f "${temp}.c"
+done
+
+/bin/rmdir "${WORKTMP}"
+exit 0
+
diff --git a/bootstrap_cmds/migcom.tproj/mig_errors.h b/bootstrap_cmds/migcom.tproj/mig_errors.h
new file mode 100644
index 0000000..f951667
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/mig_errors.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1987 Carnegie-Mellon University
+ * All rights reserved. The CMU software License Agreement specifies
+ * the terms and conditions for use and redistribution.
+ */
+/*
+ * Mach Interface Generator errors
+ *
+ * $Header: /Users/Shared/bootstrap_cmds/bootstrap_cmds/migcom.tproj/mig_errors.h,v 1.1.1.2 2000/01/11 00:36:18 wsanchez Exp $
+ *
+ * HISTORY
+ * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University
+ * Extensive revamping. Added polymorphic arguments.
+ * Allow multiple variable-sized inline arguments in messages.
+ *
+ * 28-Apr-88 Bennet Yee (bsy) at Carnegie-Mellon University
+ * Put mig_symtab back.
+ *
+ * 2-Dec-87 David Golub (dbg) at Carnegie-Mellon University
+ * Added MIG_ARRAY_TOO_LARGE.
+ *
+ * 25-May-87 Richard Draves (rpd) at Carnegie-Mellon University
+ * Added definition of death_pill_t.
+ *
+ * 31-Jul-86 Michael Young (mwyoung) at Carnegie-Mellon University
+ * Created.
+ */
+#ifndef _MIG_ERRORS_H
+#define _MIG_ERRORS_H
+
+#include <mach/kern_return.h>
+#include <mach/message.h>
+
+#define MIG_TYPE_ERROR -300 /* Type check failure */
+#define MIG_REPLY_MISMATCH -301 /* Wrong return message ID */
+#define MIG_REMOTE_ERROR -302 /* Server detected error */
+#define MIG_BAD_ID -303 /* Bad message ID */
+#define MIG_BAD_ARGUMENTS -304 /* Server found wrong arguments */
+#define MIG_NO_REPLY -305 /* Server shouldn't reply */
+#define MIG_EXCEPTION -306 /* Server raised exception */
+#define MIG_ARRAY_TOO_LARGE -307 /* User specified array not large enough
+ to hold returned array */
+
+typedef struct {
+ msg_header_t Head;
+ msg_type_t RetCodeType;
+ kern_return_t RetCode;
+} death_pill_t;
+
+typedef struct mig_symtab {
+ char *ms_routine_name;
+ int ms_routine_number;
+#ifdef hc
+ void
+#else
+ int
+#endif
+ (*ms_routine)();
+} mig_symtab_t;
+
+#endif _MIG_ERRORS_H
diff --git a/bootstrap_cmds/migcom.tproj/mig_machine.h b/bootstrap_cmds/migcom.tproj/mig_machine.h
new file mode 100644
index 0000000..aab5801
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/mig_machine.h
@@ -0,0 +1,16 @@
+#if !defined(_MIG_MACHINE_H)
+#define _MIG_MACHINE_H
+
+#define machine_alignment(SZ,ESZ) \
+(((SZ) = ((SZ) + 3) & ~3), (SZ) += (ESZ))
+
+#define machine_padding(BYTES) \
+((BYTES & 3) ? (4 - (BYTES & 3)) : 0)
+
+#ifndef NBBY
+#define NBBY 8
+#endif
+
+#define PACK_MESSAGES TRUE
+
+#endif
diff --git a/bootstrap_cmds/migcom.tproj/migcom.1 b/bootstrap_cmds/migcom.tproj/migcom.1
new file mode 100644
index 0000000..3ade83b
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/migcom.1
@@ -0,0 +1,73 @@
+.TH MIGCOM 1 "Nov 20, 2009" "Apple Computer, Inc."
+.SH NAME
+migcom \- Mach Interface Generator COMpiler
+.SH SYNOPSIS
+.B migcom
+[
+.I "option \&..."
+]
+.I "<file"
+
+.SH DESCRIPTION
+.I migcom
+is the actual compiler used by the
+.I mig
+command to generate Remote Procedure Call (RPC) source code for
+client-server style Mach IPC from specification files. It is not normally
+used independently. Rather, it is invoked by the
+.I mig
+command after pre-processing the provided specifications file with the C
+preprocessor. It is only documented here for the sake of completeness.
+.SH OPTIONS
+.TP
+.B \-q/-Q
+Omit /
+.I emit
+warning messages.
+.TP
+.B \-v/-V
+Verbose mode ( on /
+.I off
+) will summarize types and routines as they are processed.
+.TP
+.B \-l/-L
+Controls (
+.I off
+/ on ) whether or not generated code logs RPC events to system logs.
+.TP
+.B \-k/-K
+Controls (
+.I on
+/ off ) whether generated code complies with ANSI C standards.
+.TP
+.B \-s/-S
+Controls ( on /
+.I off
+) whether generated server-side code includes a generated symbol table.
+.TP
+.BI \-i " prefix"
+Specify User file prefix.
+.TP
+.BI \-user " path"
+Specify name of user-side RPC generated source file.
+.TP
+.BI \-server " path"
+Specify name of server-side RPC generated source file.
+.TP
+.BI \-header " path"
+Specify name of user-side generated header file.
+.TP
+.BI \-sheader " path"
+Specify name of server-side generated header file.
+.TP
+.BI \-iheader " path"
+Specify internal header file name.
+.TP
+.BI \-dheader " path"
+Specify defines generated header file.
+.TP
+.BI \-maxonstack " value"
+Specify maximum size of message on stack.
+.TP
+.B \-split
+Use split headers.
diff --git a/bootstrap_cmds/migcom.tproj/parser.y b/bootstrap_cmds/migcom.tproj/parser.y
new file mode 100644
index 0000000..1df43e4
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/parser.y
@@ -0,0 +1,803 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+%token sySkip
+%token syRoutine
+%token sySimpleRoutine
+
+%token sySubsystem
+%token syKernelUser
+%token syKernelServer
+
+%token syMsgOption
+%token syUseSpecialReplyPort
+%token syConsumeOnSendError
+%token syMsgSeqno
+%token syWaitTime
+%token sySendTime
+%token syNoWaitTime
+%token syNoSendTime
+%token syErrorProc
+%token syServerPrefix
+%token syUserPrefix
+%token syServerDemux
+%token syRCSId
+
+%token syImport
+%token syUImport
+%token sySImport
+%token syIImport
+%token syDImport
+
+%token syIn
+%token syOut
+%token syInOut
+%token syUserImpl
+%token syServerImpl
+%token syRequestPort
+%token syReplyPort
+%token sySReplyPort
+%token syUReplyPort
+
+%token syType
+%token syArray
+%token syStruct
+%token syOf
+
+%token syInTran
+%token syOutTran
+%token syDestructor
+%token syCType
+%token syCUserType
+%token syUserTypeLimit
+%token syOnStackLimit
+%token syCServerType
+%token syPointerTo
+%token syPointerToIfNot
+%token syValueOf
+
+%token syCString
+%token sySecToken
+%token syUserSecToken
+%token syServerSecToken
+%token syAuditToken
+%token syUserAuditToken
+%token syServerAuditToken
+%token syServerContextToken
+
+%token syColon
+%token sySemi
+%token syComma
+%token syPlus
+%token syMinus
+%token syStar
+%token syDiv
+%token syLParen
+%token syRParen
+%token syEqual
+%token syCaret
+%token syTilde
+%token syLAngle
+%token syRAngle
+%token syLBrack
+%token syRBrack
+%token syBar
+
+%token syError /* lex error */
+
+%token <number> syNumber
+%token <symtype> sySymbolicType
+%token <identifier> syIdentifier
+%token <string> syString syQString
+%token <string> syFileName
+%token <flag> syIPCFlag
+
+%left syPlus syMinus
+%left syStar syDiv
+
+
+%type <statement_kind> ImportIndicant
+%type <number> VarArrayHead ArrayHead StructHead IntExp
+%type <type> NamedTypeSpec TransTypeSpec NativeTypeSpec TypeSpec
+%type <type> CStringSpec
+%type <type> BasicTypeSpec PrevTypeSpec ArgumentType
+%type <identifier> TypePhrase
+%type <symtype> PrimIPCType IPCType
+%type <routine> RoutineDecl Routine SimpleRoutine
+%type <direction> Direction TrImplKeyword
+%type <argument> Argument Trailer Arguments ArgumentList
+%type <flag> IPCFlags
+
+%{
+
+#include <stdio.h>
+#include "lexxer.h"
+#include "strdefs.h"
+#include "type.h"
+#include "routine.h"
+#include "statement.h"
+#include "global.h"
+#include "error.h"
+
+static char *import_name(statement_kind_t sk);
+extern int yylex(void);
+
+/* forward declaration */
+void yyerror(char *s);
+
+%}
+
+%union
+{
+ u_int number;
+ identifier_t identifier;
+ string_t string;
+ statement_kind_t statement_kind;
+ ipc_type_t *type;
+ struct
+ {
+ u_int innumber; /* msgt_name value, when sending */
+ string_t instr;
+ u_int outnumber; /* msgt_name value, when receiving */
+ string_t outstr;
+ u_int size; /* 0 means there is no default size */
+ } symtype;
+ routine_t *routine;
+ arg_kind_t direction;
+ argument_t *argument;
+ ipc_flags_t flag;
+}
+
+%%
+
+Statements : /* empty */
+ | Statements Statement
+ ;
+
+Statement : Subsystem sySemi
+ | WaitTime sySemi
+ | SendTime sySemi
+ | MsgOption sySemi
+ | UseSpecialReplyPort sySemi
+ | ConsumeOnSendError sySemi
+ | UserTypeLimit sySemi
+ | OnStackLimit sySemi
+ | Error sySemi
+ | ServerPrefix sySemi
+ | UserPrefix sySemi
+ | ServerDemux sySemi
+ | TypeDecl sySemi
+ | RoutineDecl sySemi
+{
+ statement_t *st = stAlloc();
+
+ st->stKind = skRoutine;
+ st->stRoutine = $1;
+ rtCheckRoutine($1);
+ if (BeVerbose)
+ rtPrintRoutine($1);
+}
+ | sySkip sySemi
+ { rtSkip(); }
+ | Import sySemi
+ | RCSDecl sySemi
+ | sySemi
+ | error sySemi
+ { yyerrok; }
+ ;
+
+Subsystem : SubsystemStart SubsystemMods
+ SubsystemName SubsystemBase
+{
+ if (BeVerbose) {
+ printf("Subsystem %s: base = %u%s%s\n\n",
+ SubsystemName, SubsystemBase,
+ IsKernelUser ? ", KernelUser" : "",
+ IsKernelServer ? ", KernelServer" : "");
+ }
+}
+ ;
+
+SubsystemStart : sySubsystem
+{
+ if (SubsystemName != strNULL) {
+ warn("previous Subsystem decl (of %s) will be ignored", SubsystemName);
+ IsKernelUser = FALSE;
+ IsKernelServer = FALSE;
+ strfree(SubsystemName);
+ }
+}
+ ;
+
+SubsystemMods : /* empty */
+ | SubsystemMods SubsystemMod
+ ;
+
+SubsystemMod : syKernelUser
+{
+ if (IsKernelUser)
+ warn("duplicate KernelUser keyword");
+ if (!UseMsgRPC) {
+ warn("with KernelUser the -R option is meaningless");
+ UseMsgRPC = TRUE;
+ }
+ IsKernelUser = TRUE;
+}
+ | syKernelServer
+{
+ if (IsKernelServer)
+ warn("duplicate KernelServer keyword");
+ IsKernelServer = TRUE;
+}
+ ;
+
+SubsystemName : syIdentifier { SubsystemName = $1; }
+ ;
+
+SubsystemBase : syNumber { SubsystemBase = $1; }
+ ;
+
+MsgOption : LookString syMsgOption syString
+{
+ if (streql($3, "MACH_MSG_OPTION_NONE")) {
+ MsgOption = strNULL;
+ if (BeVerbose)
+ printf("MsgOption: canceled\n\n");
+ }
+ else {
+ MsgOption = $3;
+ if (BeVerbose)
+ printf("MsgOption %s\n\n",$3);
+ }
+}
+ ;
+
+UseSpecialReplyPort : syUseSpecialReplyPort syNumber
+{
+ UseSpecialReplyPort = ($2 != 0);
+ HasUseSpecialReplyPort |= UseSpecialReplyPort;
+}
+ ;
+
+ConsumeOnSendError : LookString syConsumeOnSendError syString
+{
+ if (strcasecmp($3, "None") == 0) {
+ ConsumeOnSendError = ConsumeOnSendErrorNone;
+ } else if (strcasecmp($3, "Timeout") == 0) {
+ ConsumeOnSendError = ConsumeOnSendErrorTimeout;
+ HasConsumeOnSendError = TRUE;
+ } else if (strcasecmp($3, "Any") == 0) {
+ ConsumeOnSendError = ConsumeOnSendErrorAny;
+ HasConsumeOnSendError = TRUE;
+ } else {
+ error("syntax error");
+ }
+}
+ ;
+
+UserTypeLimit : syUserTypeLimit syNumber
+ {UserTypeLimit = $2; }
+ ;
+OnStackLimit : syOnStackLimit syNumber
+ {MaxMessSizeOnStack = $2; }
+ ;
+
+WaitTime : LookString syWaitTime syString
+{
+ WaitTime = $3;
+ if (BeVerbose)
+ printf("WaitTime %s\n\n", WaitTime);
+}
+ | syNoWaitTime
+{
+ WaitTime = strNULL;
+ if (BeVerbose)
+ printf("NoWaitTime\n\n");
+}
+ ;
+
+SendTime : LookString sySendTime syString
+{
+ SendTime = $3;
+ if (BeVerbose)
+ printf("SendTime %s\n\n", SendTime);
+}
+ | syNoSendTime
+{
+ SendTime = strNULL;
+ if (BeVerbose)
+ printf("NoSendTime\n\n");
+}
+ ;
+
+Error : syErrorProc syIdentifier
+{
+ ErrorProc = $2;
+ if (BeVerbose)
+ printf("ErrorProc %s\n\n", ErrorProc);
+}
+ ;
+
+ServerPrefix : syServerPrefix syIdentifier
+{
+ ServerPrefix = $2;
+ if (BeVerbose)
+ printf("ServerPrefix %s\n\n", ServerPrefix);
+}
+ ;
+
+UserPrefix : syUserPrefix syIdentifier
+{
+ UserPrefix = $2;
+ if (BeVerbose)
+ printf("UserPrefix %s\n\n", UserPrefix);
+}
+ ;
+
+ServerDemux : syServerDemux syIdentifier
+{
+ ServerDemux = $2;
+ if (BeVerbose)
+ printf("ServerDemux %s\n\n", ServerDemux);
+}
+ ;
+
+Import : LookFileName ImportIndicant syFileName
+{
+ statement_t *st = stAlloc();
+ st->stKind = $2;
+ st->stFileName = $3;
+
+ if (BeVerbose)
+ printf("%s %s\n\n", import_name($2), $3);
+}
+ ;
+
+ImportIndicant : syImport { $$ = skImport; }
+ | syUImport { $$ = skUImport; }
+ | sySImport { $$ = skSImport; }
+ | syIImport { $$ = skIImport; }
+ | syDImport { $$ = skDImport; }
+ ;
+
+RCSDecl : LookQString syRCSId syQString
+{
+ if (RCSId != strNULL)
+ warn("previous RCS decl will be ignored");
+ if (BeVerbose)
+ printf("RCSId %s\n\n", $3);
+ RCSId = $3;
+}
+ ;
+
+TypeDecl : syType NamedTypeSpec
+{
+ identifier_t name = $2->itName;
+
+ if (itLookUp(name) != itNULL)
+ warn("overriding previous definition of %s", name);
+ itInsert(name, $2);
+}
+ ;
+
+NamedTypeSpec : syIdentifier syEqual TransTypeSpec
+ { itTypeDecl($1, $$ = $3); }
+ ;
+
+TransTypeSpec : TypeSpec
+ { $$ = itResetType($1); }
+ | TransTypeSpec syInTran syColon syIdentifier
+ syIdentifier syLParen syIdentifier syRParen
+{
+ $$ = $1;
+
+ if (($$->itTransType != strNULL) && !streql($$->itTransType, $4))
+ warn("conflicting translation types (%s, %s)", $$->itTransType, $4);
+ $$->itTransType = $4;
+
+ if (($$->itInTrans != strNULL) && !streql($$->itInTrans, $5))
+ warn("conflicting in-translation functions (%s, %s)", $$->itInTrans, $5);
+ $$->itInTrans = $5;
+
+ if (($$->itServerType != strNULL) && !streql($$->itServerType, $7))
+ warn("conflicting server types (%s, %s)", $$->itServerType, $7);
+ $$->itServerType = $7;
+}
+ | TransTypeSpec syOutTran syColon syIdentifier
+ syIdentifier syLParen syIdentifier syRParen
+{
+ $$ = $1;
+
+ if (($$->itServerType != strNULL) && !streql($$->itServerType, $4))
+ warn("conflicting server types (%s, %s)", $$->itServerType, $4);
+ $$->itServerType = $4;
+
+ if (($$->itOutTrans != strNULL) && !streql($$->itOutTrans, $5))
+ warn("conflicting out-translation functions (%s, %s)", $$->itOutTrans, $5);
+ $$->itOutTrans = $5;
+
+ if (($$->itTransType != strNULL) && !streql($$->itTransType, $7))
+ warn("conflicting translation types (%s, %s)", $$->itTransType, $7);
+ $$->itTransType = $7;
+}
+ | TransTypeSpec syDestructor syColon syIdentifier
+ syLParen syIdentifier syRParen
+{
+ $$ = $1;
+
+ if (($$->itDestructor != strNULL) && !streql($$->itDestructor, $4))
+ warn("conflicting destructor functions (%s, %s)", $$->itDestructor, $4);
+ $$->itDestructor = $4;
+
+ if (($$->itTransType != strNULL) && !streql($$->itTransType, $6))
+ warn("conflicting translation types (%s, %s)", $$->itTransType, $6);
+ $$->itTransType = $6;
+}
+ | TransTypeSpec syCType syColon syIdentifier
+{
+ $$ = $1;
+
+ if (($$->itUserType != strNULL) && !streql($$->itUserType, $4))
+ warn("conflicting user types (%s, %s)", $$->itUserType, $4);
+ $$->itUserType = $4;
+
+ if (($$->itServerType != strNULL) && !streql($$->itServerType, $4))
+ warn("conflicting server types (%s, %s)", $$->itServerType, $4);
+ $$->itServerType = $4;
+}
+ | TransTypeSpec syCUserType syColon syIdentifier
+{
+ $$ = $1;
+
+ if (($$->itUserType != strNULL) && !streql($$->itUserType, $4))
+ warn("conflicting user types (%s, %s)", $$->itUserType, $4);
+ $$->itUserType = $4;
+}
+ | TransTypeSpec syCServerType
+ syColon syIdentifier
+{
+ $$ = $1;
+
+ if (($$->itServerType != strNULL) && !streql($$->itServerType, $4))
+ warn("conflicting server types (%s, %s)",
+ $$->itServerType, $4);
+ $$->itServerType = $4;
+}
+ ;
+
+TypeSpec : BasicTypeSpec
+ { $$ = $1; }
+ | PrevTypeSpec
+ { $$ = $1; }
+ | VarArrayHead TypeSpec
+ { $$ = itVarArrayDecl($1, $2); }
+ | ArrayHead TypeSpec
+ { $$ = itArrayDecl($1, $2); }
+ | syCaret TypeSpec
+ { $$ = itPtrDecl($2); }
+ | StructHead TypeSpec
+ { $$ = itStructDecl($1, $2); }
+ | CStringSpec
+ { $$ = $1; }
+ | NativeTypeSpec
+ { $$ = $1; }
+ ;
+
+NativeTypeSpec : syPointerTo syLParen TypePhrase syRParen
+ { $$ = itNativeType($3, TRUE, 0); }
+ | syPointerToIfNot syLParen TypePhrase syComma
+ TypePhrase syRParen
+ { $$ = itNativeType($3, TRUE, $5); }
+ | syValueOf syLParen TypePhrase syRParen
+ { $$ = itNativeType($3, FALSE, 0); }
+ ;
+
+BasicTypeSpec : IPCType
+{
+ $$ = itShortDecl($1.innumber, $1.instr,
+ $1.outnumber, $1.outstr,
+ $1.size);
+}
+ | syLParen IPCType syComma IntExp
+ IPCFlags syRParen
+{
+ error("Long form type declarations aren't allowed any longer\n");
+}
+ ;
+
+PrimIPCType : syNumber
+{
+ $$.innumber = $$.outnumber = $1;
+ $$.instr = $$.outstr = strNULL;
+ $$.size = 0;
+}
+ | sySymbolicType
+ { $$ = $1; }
+ ;
+
+IPCType : PrimIPCType
+ { $$ = $1; }
+ | PrimIPCType syBar PrimIPCType
+{
+ if ($1.size != $3.size) {
+ if ($1.size == 0)
+ $$.size = $3.size;
+ else if ($3.size == 0)
+ $$.size = $1.size;
+ else {
+ error("sizes in IPCTypes (%d, %d) aren't equal",
+ $1.size, $3.size);
+ $$.size = 0;
+ }
+ }
+ else
+ $$.size = $1.size;
+ $$.innumber = $1.innumber;
+ $$.instr = $1.instr;
+ $$.outnumber = $3.outnumber;
+ $$.outstr = $3.outstr;
+}
+ ;
+
+PrevTypeSpec : syIdentifier
+ { $$ = itPrevDecl($1); }
+ ;
+
+VarArrayHead : syArray syLBrack syRBrack syOf
+ { $$ = 0; }
+ | syArray syLBrack syStar syRBrack syOf
+ { $$ = 0; }
+ | syArray syLBrack syStar syColon IntExp
+ syRBrack syOf
+ { $$ = $5; }
+ ;
+
+ArrayHead : syArray syLBrack IntExp syRBrack syOf
+ { $$ = $3; }
+ ;
+
+StructHead : syStruct syLBrack IntExp syRBrack syOf
+ { $$ = $3; }
+ ;
+
+CStringSpec : syCString syLBrack IntExp syRBrack
+ { $$ = itCStringDecl($3, FALSE); }
+ | syCString syLBrack syStar syColon
+ IntExp syRBrack
+ { $$ = itCStringDecl($5, TRUE); }
+ ;
+
+TypePhrase : syIdentifier
+ { $$ = $1; }
+ | TypePhrase syIdentifier
+ { $$ = strphrase($1, $2); strfree($2); }
+ ;
+
+IntExp : IntExp syPlus IntExp
+ { $$ = $1 + $3; }
+ | IntExp syMinus IntExp
+ { $$ = $1 - $3; }
+ | IntExp syStar IntExp
+ { $$ = $1 * $3; }
+ | IntExp syDiv IntExp
+ { $$ = $1 / $3; }
+ | syNumber
+ { $$ = $1; }
+ | syLParen IntExp syRParen
+ { $$ = $2; }
+ ;
+
+
+RoutineDecl : Routine { $$ = $1; }
+ | SimpleRoutine { $$ = $1; }
+ ;
+
+Routine : syRoutine syIdentifier Arguments
+ { $$ = rtMakeRoutine($2, $3); }
+ ;
+
+SimpleRoutine : sySimpleRoutine syIdentifier Arguments
+ { $$ = rtMakeSimpleRoutine($2, $3); }
+ ;
+
+Arguments : syLParen syRParen
+ { $$ = argNULL; }
+ | syLParen ArgumentList syRParen
+ { $$ = $2; }
+
+ ;
+
+ArgumentList : Argument
+ { $$ = $1; }
+ | Trailer
+ { $$ = $1; }
+ | Argument sySemi ArgumentList
+{
+ $$ = $1;
+ $$->argNext = $3;
+}
+ | Trailer sySemi ArgumentList
+{
+ $$ = $1;
+ $$->argNext = $3;
+}
+ ;
+
+Argument : Direction syIdentifier ArgumentType IPCFlags
+{
+ $$ = argAlloc();
+ $$->argKind = $1;
+ $$->argName = $2;
+ $$->argType = $3;
+ $$->argFlags = $4;
+ if ($3 && $3->itNative) {
+ if ($1 != akIn && $1 != akOut && $1 != akInOut)
+ error("Illegal direction specified");
+
+ if (!($3->itNativePointer) && $1 != akIn)
+ error("ValueOf only valid for in");
+
+ if (($3->itBadValue) != NULL && $1 != akIn)
+ error("PointerToIfNot only valid for in");
+ }
+}
+ ;
+
+Trailer : TrImplKeyword syIdentifier ArgumentType
+{
+ $$ = argAlloc();
+ $$->argKind = $1;
+ $$->argName = $2;
+ $$->argType = $3;
+}
+ ;
+
+
+Direction : /* empty */ { $$ = akNone; }
+ | syIn { $$ = akIn; }
+ | syOut { $$ = akOut; }
+ | syInOut { $$ = akInOut; }
+ | syRequestPort { $$ = akRequestPort; }
+ | syReplyPort { $$ = akReplyPort; }
+ | sySReplyPort { $$ = akSReplyPort; }
+ | syUReplyPort { $$ = akUReplyPort; }
+ | syWaitTime { $$ = akWaitTime; }
+ | sySendTime { $$ = akSendTime; }
+ | syMsgOption { $$ = akMsgOption; }
+ | sySecToken { $$ = akSecToken; }
+ | syServerSecToken { $$ = akServerSecToken; }
+ | syUserSecToken { $$ = akUserSecToken; }
+ | syAuditToken { $$ = akAuditToken; }
+ | syServerAuditToken { $$ = akServerAuditToken; }
+ | syUserAuditToken { $$ = akUserAuditToken; }
+ | syServerContextToken { $$ = akServerContextToken; }
+ | syMsgSeqno { $$ = akMsgSeqno; }
+ ;
+
+
+
+TrImplKeyword : syServerImpl { $$ = akServerImpl; }
+ | syUserImpl { $$ = akUserImpl; }
+ ;
+
+
+ArgumentType : syColon syIdentifier
+{
+ $$ = itLookUp($2);
+ if ($$ == itNULL)
+ error("type '%s' not defined", $2);
+}
+ | syColon NamedTypeSpec
+ { $$ = $2; }
+ | syColon NativeTypeSpec
+ { $$ = $2; }
+ ;
+
+IPCFlags : /* empty */
+ { $$ = flNone; }
+ | IPCFlags syComma syIPCFlag
+{
+ if ($1 & $3)
+ warn("redundant IPC flag ignored");
+ else
+ $$ = $1 | $3;
+}
+ | IPCFlags syComma syIPCFlag syLBrack syRBrack
+{
+ if ($3 != flDealloc)
+ warn("only Dealloc is variable");
+ else
+ $$ = $1 | flMaybeDealloc;
+}
+
+LookString : /* empty */
+ { LookString(); }
+ ;
+
+LookFileName : /* empty */
+ { LookFileName(); }
+ ;
+
+LookQString : /* empty */
+ { LookQString(); }
+ ;
+
+%%
+
+void
+yyerror(char *s)
+{
+ error(s);
+}
+
+static char *
+import_name(statement_kind_t sk)
+{
+ switch (sk) {
+
+ case skImport:
+ return "Import";
+
+ case skSImport:
+ return "SImport";
+
+ case skUImport:
+ return "UImport";
+
+ case skIImport:
+ return "IImport";
+
+ case skDImport:
+ return "DImport";
+
+ default:
+ fatal("import_name(%d): not import statement", (int) sk);
+ /*NOTREACHED*/
+ return strNULL;
+ }
+}
diff --git a/bootstrap_cmds/migcom.tproj/routine.c b/bootstrap_cmds/migcom.tproj/routine.c
new file mode 100644
index 0000000..f4c0778
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/routine.c
@@ -0,0 +1,1844 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include "type.h"
+
+#include <mach/message.h>
+#include <mach/kern_return.h>
+#include "mig_machine.h"
+#include "error.h"
+#include "alloc.h"
+#include "global.h"
+#include "routine.h"
+#include "write.h"
+
+u_int rtNumber = 0;
+
+static void rtSizeDelta(FILE *file, u_int mask, routine_t *rt);
+
+routine_t *
+rtAlloc(void)
+{
+ routine_t *new;
+
+ new = (routine_t *) calloc(1, sizeof *new);
+ if (new == rtNULL)
+ fatal("rtAlloc(): %s", strerror(errno));
+ new->rtNumber = rtNumber++;
+ new->rtName = strNULL;
+ new->rtErrorName = strNULL;
+ new->rtUserName = strNULL;
+ new->rtServerName = strNULL;
+
+ return new;
+}
+
+void
+rtSkip(void)
+{
+ rtNumber++;
+}
+
+argument_t *
+argAlloc(void)
+{
+ extern void KPD_error(FILE *file, argument_t *arg);
+
+ static argument_t prototype =
+ {
+ .argName = strNULL,
+ .argNext = argNULL,
+ .argKind = akNone,
+ .argType = itNULL,
+ .argKPD_Type = argKPD_NULL,
+ .argKPD_Template = (void(*)(FILE *, argument_t *, boolean_t))KPD_error,
+ .argKPD_Init = KPD_error,
+ .argKPD_Pack = KPD_error,
+ .argKPD_Extract = KPD_error,
+ .argKPD_TypeCheck = KPD_error,
+ .argVarName = strNULL,
+ .argMsgField = strNULL,
+ .argTTName = strNULL,
+ .argPadName = strNULL,
+ .argSuffix = strNULL,
+ .argFlags = flNone,
+ .argDeallocate = d_NO,
+ .argCountInOut = FALSE,
+ .argRoutine = rtNULL,
+ .argCount = argNULL,
+ .argSubCount = argNULL,
+ .argCInOut = argNULL,
+ .argPoly = argNULL,
+ .argDealloc = argNULL,
+ .argSameCount = argNULL,
+ .argParent = argNULL,
+ .argMultiplier = 1,
+ .argRequestPos = 0,
+ .argReplyPos = 0,
+ .argByReferenceUser = FALSE,
+ .argByReferenceServer = FALSE,
+ .argTempOnStack = FALSE
+ };
+ argument_t *new;
+
+ new = (argument_t *) malloc(sizeof *new);
+ if (new == argNULL)
+ fatal("argAlloc(): %s", strerror(errno));
+ *new = prototype;
+ return new;
+}
+
+routine_t *
+rtMakeRoutine(identifier_t name, argument_t *args)
+{
+ routine_t *rt = rtAlloc();
+
+ rt->rtName = name;
+ rt->rtKind = rkRoutine;
+ rt->rtArgs = args;
+
+ return rt;
+}
+
+routine_t *
+rtMakeSimpleRoutine(identifier_t name, argument_t *args)
+{
+ routine_t *rt = rtAlloc();
+
+ rt->rtName = name;
+ rt->rtKind = rkSimpleRoutine;
+ rt->rtArgs = args;
+
+ return rt;
+}
+
+char *
+rtRoutineKindToStr(routine_kind_t rk)
+{
+ switch (rk) {
+
+ case rkRoutine:
+ return "Routine";
+
+ case rkSimpleRoutine:
+ return "SimpleRoutine";
+
+ default:
+ fatal("rtRoutineKindToStr(%d): not a routine_kind_t", rk);
+ /*NOTREACHED*/
+ return strNULL;
+ }
+}
+
+static void
+rtPrintArg(argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ if (!akCheck(arg->argKind, akbUserArg|akbServerArg) ||
+ (akIdent(arg->argKind) == akeCount) ||
+ (akIdent(arg->argKind) == akeDealloc) ||
+ (akIdent(arg->argKind) == akeNdrCode) ||
+ (akIdent(arg->argKind) == akePoly))
+ return;
+
+ printf("\n\t");
+
+ switch (akIdent(arg->argKind)) {
+
+ case akeRequestPort:
+ printf("RequestPort");
+ break;
+
+ case akeReplyPort:
+ printf("ReplyPort");
+ break;
+
+ case akeWaitTime:
+ printf("WaitTime");
+ break;
+
+ case akeSendTime:
+ printf("SendTime");
+ break;
+
+ case akeMsgOption:
+ printf("MsgOption");
+ break;
+
+ case akeMsgSeqno:
+ printf("MsgSeqno\t");
+ break;
+
+ case akeSecToken:
+ printf("SecToken\t");
+ break;
+
+ case akeAuditToken:
+ printf("AuditToken\t");
+ break;
+
+ case akeContextToken:
+ printf("ContextToken\t");
+ break;
+
+ case akeImplicit:
+ printf("Implicit\t");
+ break;
+
+ default:
+ if (akCheck(arg->argKind, akbRequest)) {
+ if (akCheck(arg->argKind, akbSend))
+ printf("In");
+ else
+ printf("(In)");
+ }
+ if (akCheck(arg->argKind, akbReply)) {
+ if (akCheck(arg->argKind, akbReturn))
+ printf("Out");
+ else
+ printf("(Out)");
+ }
+ printf("\t");
+ }
+
+ printf("\t%s: %s", arg->argName, it->itName);
+
+ if (arg->argDeallocate == d_YES)
+ printf(", Dealloc");
+ else if (arg->argDeallocate == d_MAYBE)
+ printf(", Dealloc[]");
+
+ if (arg->argCountInOut)
+ printf(", CountInOut");
+
+ if (arg->argFlags & flSameCount)
+ printf(", SameCount");
+
+ if (arg->argFlags & flPhysicalCopy)
+ printf(", PhysicalCopy");
+
+ if (arg->argFlags & flRetCode)
+ printf(", PhysicalCopy");
+
+ if (arg->argFlags & flOverwrite)
+ printf(", Overwrite");
+
+ if (arg->argFlags & flAuto)
+ printf(", Auto");
+
+ if (arg->argFlags & flConst)
+ printf(", Const");
+}
+
+void
+rtPrintRoutine(routine_t *rt)
+{
+ argument_t *arg;
+
+ printf("%s (%d) %s(", rtRoutineKindToStr(rt->rtKind), rt->rtNumber, rt->rtName);
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ rtPrintArg(arg);
+
+ printf(")\n");
+ printf("\n");
+}
+
+/*
+ * Determines appropriate value of msg-simple for the message.
+ * One version for both In & Out.
+ */
+
+static void
+rtCheckSimple(argument_t *args, u_int mask, boolean_t *simple)
+{
+ argument_t *arg;
+ boolean_t MustBeComplex = FALSE;
+
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, mask)) {
+ ipc_type_t *it = arg->argType;
+
+ if (IS_KERN_PROC_DATA(it))
+ MustBeComplex = TRUE;
+ }
+
+ *simple = !MustBeComplex;
+}
+
+static void
+rtCheckFit(routine_t *rt, u_int mask, boolean_t *fitp, boolean_t *uselimp, u_int *knownp)
+{
+ boolean_t uselim = FALSE;
+ argument_t *arg;
+ u_int size = sizeof(mach_msg_header_t);
+
+ if (!rt->rtSimpleRequest)
+ machine_alignment(size,sizeof(mach_msg_body_t));
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, mask)) {
+ ipc_type_t *it = arg->argType;
+
+ machine_alignment(size, it->itMinTypeSize);
+ if (it->itNative)
+ uselim = TRUE;
+ else if (IS_VARIABLE_SIZED_UNTYPED(it)) {
+ machine_alignment(size, it->itTypeSize);
+ size += it->itPadSize;
+ }
+ }
+ *knownp = size;
+ if (MaxMessSizeOnStack == -1) {
+ *fitp = TRUE;
+ *uselimp = FALSE;
+ }
+ else if (size > MaxMessSizeOnStack) {
+ *fitp = FALSE;
+ *uselimp = FALSE;
+ }
+ else if (!uselim) {
+ *fitp = TRUE;
+ *uselimp = FALSE;
+ }
+ else if (UserTypeLimit == -1) {
+ *fitp = FALSE;
+ *uselimp = FALSE;
+ }
+ else if (size + UserTypeLimit > MaxMessSizeOnStack) {
+ *fitp = FALSE;
+ *uselimp = TRUE;
+ }
+ else {
+ *fitp = TRUE;
+ *uselimp = TRUE;
+ }
+}
+
+static void
+rtFindHowMany(routine_t *rt)
+{
+ argument_t *arg;
+ int multiplier = 1;
+ boolean_t test;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ if (!it->itVarArray)
+ multiplier = it->itKPD_Number;
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ it = it->itElement;
+ }
+ else
+ test = !it->itVarArray;
+
+ if (akCheck(arg->argKind, akbSendKPD)) {
+
+ if (it->itInLine)
+ rt->rtCountPortsIn += it->itNumber * multiplier;
+ else if (it->itPortType) {
+ if (test)
+ rt->rtCountOolPortsIn += it->itNumber * multiplier;
+ }
+ else {
+ if (test)
+ rt->rtCountOolIn += (it->itNumber * it->itSize + 7)/8 * multiplier;
+ }
+ }
+ if (akCheckAll(arg->argKind, akbReturnKPD)) {
+ if (it->itInLine)
+ rt->rtCountPortsOut += it->itNumber * multiplier;
+ else if (it->itPortType) {
+ if (test)
+ rt->rtCountOolPortsOut += it->itNumber * multiplier;
+ }
+ else {
+ if (test)
+ rt->rtCountOolOut += ((it->itNumber * it->itSize + 7)/8) * multiplier;
+ }
+ }
+ }
+}
+
+boolean_t
+rtCheckMask(argument_t *args, u_int mask)
+{
+ argument_t *arg;
+
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, mask))
+ return TRUE;
+ return FALSE;
+}
+
+boolean_t
+rtCheckMaskFunction(argument_t *args, u_int mask, boolean_t (*func)(argument_t *arg))
+{
+ argument_t *arg;
+
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, mask))
+ if ((*func)(arg))
+ return TRUE;
+ return FALSE;
+}
+
+
+int
+rtCountKPDs(argument_t *args, u_int mask)
+{
+ argument_t *arg;
+ int count = 0;
+
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, mask))
+ count += arg->argType->itKPD_Number;
+ return count;
+}
+
+int
+rtCountFlags(argument_t *args, u_int flag)
+{
+ argument_t *arg;
+ int count = 0;
+
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (arg->argFlags & flag)
+ count++;
+ return count;
+}
+
+int
+rtCountArgDescriptors(argument_t *args, int *argcount)
+{
+ argument_t *arg;
+ int count = 0;
+
+ if (argcount)
+ *argcount = 0;
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, akbServerArg)) {
+ if (RPCFixedArray(arg) ||
+ RPCPort(arg) ||
+ RPCVariableArray(arg) ||
+ RPCPortArray(arg)) {
+ count++;
+ if (argcount)
+ (*argcount)++;
+ }
+ else {
+ if (argcount) {
+ if (arg->argType->itStruct && arg->argType->itNumber &&
+ (arg->argType->itSize >= 32))
+ *argcount += arg->argType->itNumber * (arg->argType->itSize / 32);
+ else
+ (*argcount)++;
+ }
+ }
+ }
+ return count;
+}
+
+int
+rtCountMask(argument_t *args, u_int mask)
+{
+ argument_t *arg;
+ int count = 0;
+
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, mask))
+ count++;
+ return count;
+}
+
+/* arg->argType may be NULL in this function */
+
+static void
+rtDefaultArgKind(routine_t *rt, argument_t *arg)
+{
+ if ((arg->argKind == akNone) && (rt->rtRequestPort == argNULL))
+ arg->argKind = akRequestPort;
+
+ if (arg->argKind == akNone)
+ arg->argKind = akIn;
+}
+
+/*
+ * Initializes arg->argDeallocate,
+ * arg->argCountInOut from arg->argFlags
+ * and perform consistency check over the
+ * flags.
+ */
+
+static ipc_flags_t
+rtProcessDeallocFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, dealloc_t *what, string_t name)
+{
+
+ /* only one of flDealloc, flNotDealloc, flMaybeDealloc */
+
+ if (flags & flMaybeDealloc) {
+ if (flags & (flDealloc|flNotDealloc)) {
+ warn("%s: Dealloc and NotDealloc ignored with Dealloc[]", name);
+ flags &= ~(flDealloc|flNotDealloc);
+ }
+ }
+
+ if ((flags&(flDealloc|flNotDealloc)) == (flDealloc|flNotDealloc)) {
+ warn("%s: Dealloc and NotDealloc cancel out", name);
+ flags &= ~(flDealloc|flNotDealloc);
+ }
+
+ if (((IsKernelServer && akCheck(kind, akbReturn)) ||
+ (IsKernelUser && akCheck(kind, akbSend))) &&
+ (flags & flDealloc)) {
+ /*
+ * For a KernelServer interface and an Out argument,
+ * or a KernelUser interface and an In argument,
+ * we avoid a possible spurious warning about the deallocate bit.
+ * For compatibility with Mach 2.5, the deallocate bit
+ * may need to be enabled on some inline arguments.
+ */
+
+ *what= d_YES;
+ }
+ else if (flags & (flMaybeDealloc|flDealloc)) {
+ /* only give semantic warnings if the user specified something */
+ if (it->itInLine && !it->itPortType) {
+ warn("%s: Dealloc is ignored: it is meaningless for that type of argument", name);
+ flags &= ~(flMaybeDealloc|flDealloc);
+ }
+ else
+ *what = (flags & flMaybeDealloc) ? d_MAYBE : d_YES;
+ }
+ return flags;
+}
+
+static void
+rtProcessSameCountFlag(argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ ipc_flags_t flags = arg->argFlags;
+ string_t name = arg->argVarName;
+ static argument_t *old_arg;
+
+ if (flags & flSameCount) {
+ if (!it->itVarArray) {
+ warn("%s: SameCount is ignored - the argument is not variable", name);
+ flags &= ~flSameCount;
+ }
+ if (old_arg) {
+ if (old_arg->argParent)
+ old_arg = old_arg->argParent;
+ if (old_arg->argSameCount)
+ old_arg = old_arg->argSameCount;
+
+ if (!old_arg->argType->itVarArray) {
+ warn("%s: SameCount is ignored - adjacent argument is not variable", name);
+ flags &= ~flSameCount;
+ }
+
+#define SAMECOUNT_MASK akeBITS|akbSend|akbReturn|akbRequest|akbReply|akbUserArg|akbServerArg
+ if (akCheck(old_arg->argKind, SAMECOUNT_MASK) !=
+ akCheck(arg->argKind, SAMECOUNT_MASK) ||
+ old_arg->argCountInOut != arg->argCountInOut) {
+ warn("%s: SameCount is ignored - inconsistencies with the adjacent argument\n", name);
+ flags &= ~flSameCount;
+ }
+ arg->argSameCount = old_arg;
+ }
+ arg->argFlags = flags;
+ }
+ old_arg = arg;
+}
+
+static ipc_flags_t
+rtProcessCountInOutFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, boolean_t *what, string_t name)
+{
+ if (flags & flCountInOut) {
+ if (!akCheck(kind, akbReply)) {
+ warn("%s: CountInOut is ignored: argument must be Out\n", name);
+ flags &= ~flCountInOut;
+ }
+ else if (!it->itVarArray || !it->itInLine) {
+ warn("%s: CountInOut is ignored: argument isn't variable or in-line\n", name);
+ flags &= ~flCountInOut;
+ }
+ else
+ *what = TRUE;
+ }
+ return flags;
+}
+
+static ipc_flags_t
+rtProcessPhysicalCopyFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, string_t name)
+{
+ if (flags & flPhysicalCopy) {
+ if (it->itInLine) {
+ warn("%s: PhysicalCopy is ignored, argument copied inline anyway", name);
+ flags &= ~flPhysicalCopy;
+ }
+ if (it->itPortType) {
+ warn("%s: PhysicalCopy is ignored, it does not apply to ports and array of ports", name);
+ flags &= ~flPhysicalCopy;
+ }
+ }
+ return flags;
+}
+
+static void
+rtProcessRetCodeFlag(argument_t *thisarg)
+{
+ ipc_type_t *it = thisarg->argType;
+ ipc_flags_t flags = thisarg->argFlags;
+ string_t name = thisarg->argVarName;
+ routine_t *thisrout = thisarg->argRoutine;
+
+ if (flags & flRetCode) {
+ if (!it->itInLine || !it->itStruct ||
+ it->itSize != 32 || it->itNumber != 1) {
+ warn("%s: RetCode is ignored - the type doesn't match a MIG RetCode", name);
+ flags &= ~flRetCode;
+ }
+ else if (thisrout->rtKind != rkSimpleRoutine) {
+ fatal("%s: RetCode is allowed only for SimpleRoutines", name);
+ }
+ else if (thisrout->rtRetCArg != argNULL) {
+ warn("%s: RetCode is ignored - only one argument can be flagged as RetCode", name);
+ flags &= ~flRetCode;
+ }
+ else {
+ thisrout->rtRetCArg = thisarg;
+ }
+ thisarg->argFlags = flags;
+ }
+}
+
+static ipc_flags_t
+rtProcessOverwriteFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, string_t name)
+{
+ if (flags & flOverwrite)
+ if (it->itInLine || it->itMigInLine ||
+ /* among In, Out, InOut, we want only the Out! */
+ !akCheck(kind, akbReturn) || akCheck(kind, akbSend)) {
+ warn("%s: Overwrite is ignored - it must be Out AND Ool!", name);
+ flags &= ~flOverwrite;
+ }
+ return flags;
+}
+
+static void
+rtDetectKPDArg(argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *string;
+
+ if (IS_KERN_PROC_DATA(it)) {
+ if (akCheck(arg->argKind, akbSendBody)) {
+ arg->argKind = akRemFeature(arg->argKind, akbSendBody);
+ arg->argKind = akAddFeature(arg->argKind, akbSendKPD);
+ }
+ if (akCheck(arg->argKind, akbReturnBody)) {
+ arg->argKind = akRemFeature(arg->argKind, akbReturnBody);
+ arg->argKind = akAddFeature(arg->argKind, akbReturnKPD);
+ }
+ if (it->itInLine) {
+ string = "mach_msg_port_descriptor_t";
+ arg->argKPD_Type = MACH_MSG_PORT_DESCRIPTOR;
+ }
+ else if (it->itPortType) {
+ string = "mach_msg_ool_ports_descriptor_t";
+ arg->argKPD_Type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
+ }
+ else {
+ string = "mach_msg_ool_descriptor_t";
+ arg->argKPD_Type = MACH_MSG_OOL_DESCRIPTOR;
+ }
+ it->itKPDType = string;
+ }
+}
+
+static void
+rtAugmentArgKind(argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ /* akbVariable means variable-sized inline */
+
+ if (IS_VARIABLE_SIZED_UNTYPED(it)) {
+ if (akCheckAll(arg->argKind, akbRequest|akbReply))
+ error("%s: Inline variable-sized arguments can't be InOut", arg->argName);
+ arg->argKind = akAddFeature(arg->argKind, akbVariable);
+ }
+ if (IS_OPTIONAL_NATIVE(it))
+ arg->argKind = akAddFeature(arg->argKind, akbVariable);
+
+ /*
+ * Need to use a local variable in the following cases:
+ * 1) There is a translate-out function & the argument is being
+ * returned. We need to translate it before it hits the message.
+ * 2) There is a translate-in function & the argument is
+ * sent and returned. We need a local variable for its address.
+ * 3) There is a destructor function, which will be used
+ * (SendRcv and not ReturnSnd), and there is a translate-in
+ * function whose value must be saved for the destructor.
+ * 4) This is Complex KPD (array of KPD), and as such it has to
+ * be copied to a local array in input and output
+ * 5) Both poly and dealloc generate warnings compile time, because
+ * we attempt to take address of bit-field structure member
+ */
+
+ if (
+ ((it->itOutTrans != strNULL) && akCheck(arg->argKind, akbReturnSnd)) ||
+ ((it->itInTrans != strNULL) && akCheckAll(arg->argKind, akbSendRcv|akbReturnSnd)) ||
+ ((it->itDestructor != strNULL) && akCheck(arg->argKind, akbSendRcv) && !akCheck(arg->argKind, akbReturnSnd) && (it->itInTrans != strNULL)) ||
+ (IS_MULTIPLE_KPD(it)) ||
+ ((akIdent(arg->argKind) == akePoly) && akCheck(arg->argKind, akbReturnSnd)) ||
+ ((akIdent(arg->argKind) == akeDealloc) && akCheck(arg->argKind, akbReturnSnd))
+ ) {
+ arg->argKind = akRemFeature(arg->argKind, akbReplyCopy);
+ arg->argKind = akAddFeature(arg->argKind, akbVarNeeded);
+ }
+}
+
+/*
+ * The Suffix allows to handle KPDs as normal data.
+ * it is used in InArgMsgField.
+ */
+static void
+rtSuffixExtArg(argument_t *args)
+{
+ argument_t *arg;
+ char *subindex;
+ char string[MAX_STR_LEN];
+
+ for (arg = args; arg != argNULL; arg = arg->argNext) {
+ if (akCheck(arg->argKind, akbSendKPD | akbReturnKPD)) {
+ if (IS_MULTIPLE_KPD(arg->argType))
+ subindex = "[0]";
+ else
+ subindex = "";
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ (void)sprintf(string, "%s.name", subindex);
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ (void)sprintf(string, "%s.address", subindex);
+ break;
+
+ default:
+ error("Type of kernel processed data unknown\n");
+ }
+ arg->argSuffix = strconcat(arg->argMsgField, string);
+ /* see above the list of VarNeeded cases */
+ /*
+ * argCount has been removed from the VarNeeded list,
+ * because VarSize arrays have their Count in the untyped
+ * section of the message, and because it is not possible
+ * to move anything in-line/out-of-line
+ */
+ }
+ else if (akIdent(arg->argKind) == akePoly &&
+ akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) {
+ argument_t *par_arg = arg->argParent;
+
+ if (IS_MULTIPLE_KPD(par_arg->argType))
+ subindex = "[0]";
+ else
+ subindex = "";
+ switch (par_arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ (void)sprintf(string, "%s.disposition", subindex);
+ arg->argSuffix = strconcat(par_arg->argMsgField, string);
+ break;
+
+ default:
+ error("Type of kernel processed data inconsistent\n");
+ }
+ }
+ else if (akIdent(arg->argKind) == akeDealloc &&
+ akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) {
+ argument_t *par_arg = arg->argParent;
+
+ if (IS_MULTIPLE_KPD(par_arg->argType))
+ subindex = "[0]";
+ else
+ subindex = "";
+ switch (par_arg->argKPD_Type) {
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ (void)sprintf(string, "%s.deallocate", subindex);
+ arg->argSuffix = strconcat(par_arg->argMsgField, string);
+ break;
+
+ default:
+ error("Type of kernel processed data inconsistent\n");
+ }
+ }
+ }
+}
+
+/* arg->argType may be NULL in this function */
+
+static void
+rtCheckRoutineArg(routine_t *rt, argument_t *arg)
+{
+ switch (akIdent(arg->argKind)) {
+
+ case akeRequestPort:
+ if (rt->rtRequestPort != argNULL)
+ warn("multiple RequestPort args in %s; %s won't be used", rt->rtName, rt->rtRequestPort->argName);
+ rt->rtRequestPort = arg;
+ break;
+
+ case akeReplyPort:
+ if (rt->rtReplyPort != argNULL)
+ warn("multiple ReplyPort args in %s; %s won't be used", rt->rtName, rt->rtReplyPort->argName);
+ rt->rtReplyPort = arg;
+ break;
+
+ case akeWaitTime:
+ if (rt->rtWaitTime != argNULL)
+ warn("multiple WaitTime/SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName);
+ rt->rtWaitTime = arg;
+ break;
+
+ case akeSendTime:
+ if (rt->rtWaitTime != argNULL) {
+ if (akIdent(rt->rtWaitTime->argKind) == akeWaitTime) {
+ warn("SendTime type argument after a WaitTime in %s; SendTime %s won't be used", rt->rtName, arg->argName);
+ break;
+ } else {
+ warn("multiple SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName);
+ }
+ }
+ rt->rtWaitTime = arg;
+ break;
+
+ case akeMsgOption:
+ if (rt->rtMsgOption != argNULL)
+ warn("multiple MsgOption args in %s; %s won't be used", rt->rtName, rt->rtMsgOption->argName);
+ rt->rtMsgOption = arg;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* arg->argType may be NULL in this function */
+
+static void
+rtSetArgDefaults(routine_t *rt, argument_t *arg)
+{
+ arg->argRoutine = rt;
+ if (arg->argVarName == strNULL)
+ arg->argVarName = arg->argName;
+ if (arg->argMsgField == strNULL)
+ switch(akIdent(arg->argKind)) {
+
+ case akeRequestPort:
+ arg->argMsgField = "Head.msgh_request_port";
+ break;
+
+ case akeReplyPort:
+ arg->argMsgField = "Head.msgh_reply_port";
+ break;
+
+ case akeNdrCode:
+ arg->argMsgField = "NDR";
+ break;
+
+ case akeSecToken:
+ arg->argMsgField = "msgh_sender";
+ break;
+
+ case akeAuditToken:
+ arg->argMsgField = "msgh_audit";
+ break;
+
+ case akeContextToken:
+ arg->argMsgField = "msgh_context";
+ break;
+
+ case akeMsgSeqno:
+ arg->argMsgField = "msgh_seqno";
+ break;
+
+ case akeImplicit:
+ /* the field is set directly by Yacc */
+ break;
+
+ default:
+ arg->argMsgField = arg->argName;
+ break;
+ }
+
+ if (arg->argTTName == strNULL)
+ arg->argTTName = strconcat(arg->argName, "Template");
+ if (arg->argPadName == strNULL)
+ arg->argPadName = strconcat(arg->argName, "Pad");
+
+ /*
+ * The poly args for the request and reply ports have special defaults,
+ * because their msg-type-name values aren't stored in normal fields.
+ */
+
+ if ((rt->rtRequestPort != argNULL) &&
+ (rt->rtRequestPort->argPoly == arg) &&
+ (arg->argType != itNULL)) {
+ arg->argMsgField = "Head.msgh_bits";
+ arg->argType->itInTrans = "MACH_MSGH_BITS_REQUEST";
+ }
+
+ if ((rt->rtReplyPort != argNULL) &&
+ (rt->rtReplyPort->argPoly == arg) &&
+ (arg->argType != itNULL)) {
+ arg->argMsgField = "Head.msgh_bits";
+ arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY";
+ }
+}
+
+static void
+rtAddCountArg(argument_t *arg)
+{
+ argument_t *count, *master;
+ ipc_type_t *it = arg->argType;
+
+ count = argAlloc();
+
+ if (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray) {
+ count->argName = strconcat(arg->argName, "Subs");
+ count->argType = itMakeSubCountType(it->itKPD_Number, it->itVarArray, arg->argVarName);
+ count->argKind = akeSubCount;
+ arg->argSubCount = count;
+ }
+ else {
+ count->argName = strconcat(arg->argName, "Cnt");
+ count->argType = itMakeCountType();
+ count->argKind = akeCount;
+ arg->argCount = count;
+ if (arg->argParent != argNULL) {
+ /* this is the case where we are at the second level of recursion:
+ we want the Parent to access it through argCount */
+ arg->argParent->argCount = count;
+ }
+ }
+ master = (arg->argParent != argNULL) ? arg->argParent : arg;
+ if (IS_MULTIPLE_KPD(master->argType))
+ count->argMultiplier = 1;
+ else
+ count->argMultiplier = it->itElement->itNumber;
+ count->argParent = arg;
+ count->argNext = arg->argNext;
+ arg->argNext = count;
+
+ if (arg->argType->itString) {
+ /* C String gets no Count argument on either side, but are still in the msg */
+ count->argKind = akAddFeature(count->argKind, akCheck(arg->argKind, akbSend) ? akbSendRcv : akbReturnRcv);
+ count->argVarName = (char *)0;
+ }
+ else {
+ /*
+ * Count arguments have to be present on the message body (NDR encoded)
+ * akbVariable has to be turned down, has it foul the algorithm
+ * for detecting the in-line variable sized arrays
+ */
+ count->argKind |= akAddFeature(akbUserArg|akbServerArg, (arg->argKind) & ~akeBITS);
+ count->argKind = akRemFeature(count->argKind, akbVariable|akbVarNeeded);
+ if (IS_VARIABLE_SIZED_UNTYPED(arg->argType))
+ /*
+ * Count arguments for the above types are explicitly declared
+ * BEFORE the variable (with those bits, they would come afterwards)
+ */
+ count->argKind = akRemFeature(count->argKind, akbRequest|akbReply);
+ }
+}
+
+static void
+rtAddCountInOutArg(argument_t *arg)
+{
+ argument_t *count;
+
+ /*
+ * The user sees a single count variable. However, to get the
+ * count passed from user to server for variable-sized inline OUT
+ * arrays, we need two count arguments internally. This is
+ * because the count value lives in different message fields (and
+ * is scaled differently) in the request and reply messages.
+ *
+ * The two variables have the same name to simplify code generation.
+ *
+ * This variable has a null argParent field because it has akbRequest.
+ * For example, see rtCheckVariable.
+ */
+
+ count = argAlloc();
+ count->argName = strconcat(arg->argName, "Cnt");
+ count->argType = itMakeCountType();
+ count->argParent = argNULL;
+ count->argNext = arg->argNext;
+ arg->argNext = count;
+ (count->argCInOut = arg->argCount)->argCInOut = count;
+ count->argKind = akCountInOut;
+}
+
+static void
+rtAddPolyArg(argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ argument_t *poly;
+ arg_kind_t akbsend, akbreturn;
+
+ poly = argAlloc();
+ poly->argName = strconcat(arg->argName, "Poly");
+ poly->argType = itMakePolyType();
+ poly->argParent = arg;
+ poly->argNext = arg->argNext;
+ arg->argNext = poly;
+ arg->argPoly = poly;
+
+ /*
+ * akbsend is bits added if the arg is In;
+ * akbreturn is bits added if the arg is Out.
+ * The mysterious business with KernelServer subsystems:
+ * when packing Out arguments, they use OutNames instead
+ * of InNames, and the OutName determines if they are poly-in
+ * as well as poly-out.
+ */
+
+ akbsend = akbSend;
+ akbreturn = akbReturn;
+
+ if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC) {
+ akbsend |= akbUserArg|akbSendSnd;
+ if (!IsKernelServer)
+ akbreturn |= akbServerArg|akbReturnSnd;
+ }
+ if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) {
+ akbsend |= akbServerArg|akbSendRcv;
+ akbreturn |= akbUserArg|akbReturnRcv;
+ if (IsKernelServer)
+ akbreturn |= akbServerArg|akbReturnSnd;
+ }
+
+ poly->argKind = akPoly;
+ if (akCheck(arg->argKind, akbSend))
+ poly->argKind = akAddFeature(poly->argKind, akCheck(arg->argKind, akbsend));
+ if (akCheck(arg->argKind, akbReturn))
+ poly->argKind = akAddFeature(poly->argKind, akCheck(arg->argKind, akbreturn));
+}
+
+static void
+rtAddDeallocArg(argument_t *arg)
+{
+ argument_t *dealloc;
+
+ dealloc = argAlloc();
+ dealloc->argName = strconcat(arg->argName, "Dealloc");
+ dealloc->argType = itMakeDeallocType();
+ dealloc->argParent = arg;
+ dealloc->argNext = arg->argNext;
+ arg->argNext = dealloc;
+ arg->argDealloc = dealloc;
+
+ /*
+ * Dealloc flag can only be associated to KPDs.
+ */
+
+ dealloc->argKind = akeDealloc;
+ if (akCheck(arg->argKind, akbSend))
+ dealloc->argKind = akAddFeature(dealloc->argKind, akCheck(arg->argKind, akbUserArg|akbSend|akbSendSnd));
+ if (akCheck(arg->argKind, akbReturn)) {
+ dealloc->argKind = akAddFeature(dealloc->argKind, akCheck(arg->argKind, akbServerArg|akbReturn|akbReturnSnd));
+ dealloc->argByReferenceServer = TRUE;
+ }
+}
+
+static void
+rtCheckRoutineArgs(routine_t *rt)
+{
+ argument_t *arg;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+
+ rtDefaultArgKind(rt, arg);
+ rtCheckRoutineArg(rt, arg);
+
+ /* need to set argTTName before adding implicit args */
+ rtSetArgDefaults(rt, arg);
+
+ /* the arg may not have a type (if there was some error in parsing it),
+ in which case we don't want to do these steps. */
+
+ if (it != itNULL) {
+ arg->argFlags = rtProcessDeallocFlag(it, arg->argFlags, arg->argKind, &arg->argDeallocate, arg->argVarName);
+ arg->argFlags = rtProcessCountInOutFlag(it, arg->argFlags, arg->argKind, &arg->argCountInOut, arg->argVarName);
+ rtProcessSameCountFlag(arg);
+ arg->argFlags = rtProcessPhysicalCopyFlag(it, arg->argFlags, arg->argKind, arg->argVarName);
+ rtProcessRetCodeFlag(arg);
+ arg->argFlags = rtProcessOverwriteFlag(it, arg->argFlags, arg->argKind, arg->argVarName);
+ rtAugmentArgKind(arg);
+
+ /* args added here will get processed in later iterations */
+ /* order of args is 'arg poly countinout count dealloc' */
+
+ if (arg->argDeallocate == d_MAYBE)
+ rtAddDeallocArg(arg);
+ if (it->itVarArray || (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray))
+ rtAddCountArg(arg);
+ if (arg->argCountInOut)
+ rtAddCountInOutArg(arg);
+ if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) || (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC))
+ rtAddPolyArg(arg);
+ /*
+ * Detects whether the arg has to become part of the
+ * Kernel Processed Data section; if yes, define the proper
+ * itUserKPDType, itServerKPDType
+ */
+ rtDetectKPDArg(arg);
+ }
+ }
+}
+
+boolean_t
+rtCheckTrailerType(argument_t *arg)
+{
+ if (akIdent(arg->argKind) == akeSecToken ||
+ akIdent(arg->argKind) == akeAuditToken ||
+ akIdent(arg->argKind) == akeContextToken )
+ itCheckTokenType(arg->argVarName, arg->argType);
+
+ if (akIdent(arg->argKind) == akeMsgSeqno)
+ itCheckIntType(arg->argVarName, arg->argType);
+ /*
+ * if the built-in are not used, we cannot match
+ * the type/size of the desciption provided by the user
+ * with the one defined in message.h.
+ */
+
+ return TRUE;
+}
+
+static void
+rtCheckArgTypes(routine_t *rt)
+{
+ if (rt->rtRequestPort == argNULL)
+ error("%s %s doesn't have a server port argument", rtRoutineKindToStr(rt->rtKind), rt->rtName);
+
+ if ((rt->rtRequestPort != argNULL) &&
+ (rt->rtRequestPort->argType != itNULL))
+ itCheckRequestPortType(rt->rtRequestPort->argName, rt->rtRequestPort->argType);
+
+ if ((rt->rtReplyPort != argNULL) &&
+ (rt->rtReplyPort->argType != itNULL))
+ itCheckReplyPortType(rt->rtReplyPort->argName, rt->rtReplyPort->argType);
+
+ if ((rt->rtWaitTime != argNULL) &&
+ (rt->rtWaitTime->argType != itNULL))
+ itCheckIntType(rt->rtWaitTime->argName, rt->rtWaitTime->argType);
+
+ if ((rt->rtMsgOption != argNULL) &&
+ (rt->rtMsgOption->argType != itNULL))
+ itCheckIntType(rt->rtMsgOption->argName, rt->rtMsgOption->argType);
+
+ if ((IsKernelServer && rt->rtServerImpl) ||
+ (IsKernelUser && rt->rtUserImpl))
+ fatal("Implicit data is not supported in the KernelUser and KernelServer modes");
+ /* rtCheckTrailerType will hit a fatal() if something goes wrong */
+ if (rt->rtServerImpl)
+ rtCheckMaskFunction(rt->rtArgs, akbServerImplicit, rtCheckTrailerType);
+ if (rt->rtUserImpl)
+ rtCheckMaskFunction(rt->rtArgs, akbUserImplicit, rtCheckTrailerType);
+}
+
+/*
+ * Check for arguments which are missing seemingly needed functions.
+ * We make this check here instead of in itCheckDecl, because here
+ * we can take into account what kind of argument the type is
+ * being used with.
+ *
+ * These are warnings, not hard errors, because mig will generate
+ * reasonable code in any case. The generated code will work fine
+ * if the ServerType and TransType are really the same, even though
+ * they have different names.
+ */
+
+static void
+rtCheckArgTrans(routine_t *rt)
+{
+ argument_t *arg;
+
+ /* the arg may not have a type (if there was some error in parsing it) */
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+
+ if ((it != itNULL) && !streql(it->itServerType, it->itTransType)) {
+ if (akCheck(arg->argKind, akbSendRcv) && (it->itInTrans == strNULL))
+ warn("%s: argument has no in-translation function", arg->argName);
+
+ if (akCheck(arg->argKind, akbReturnSnd) && (it->itOutTrans == strNULL))
+ warn("%s: argument has no out-translation function", arg->argName);
+ }
+ }
+}
+
+/*
+ * Adds an implicit return-code argument. It exists in the reply message,
+ * where it is the first piece of data (After the NDR format label)..
+ */
+
+static void
+rtAddRetCode(routine_t *rt)
+{
+ argument_t *arg = argAlloc();
+
+ arg->argName = "RetCode";
+ arg->argType = itRetCodeType;
+ arg->argKind = akRetCode;
+ rt->rtRetCode = arg;
+
+ arg->argNext = rt->rtArgs;
+ rt->rtArgs = arg;
+}
+
+/*
+ * Process the Return Code.
+ * The MIG protocol says that RetCode != 0 are only sent through
+ * mig_reply_error_t structures. Therefore, there is no need
+ * for reserving a RetCode in a complex Reply message.
+ */
+static void
+rtProcessRetCode(routine_t *rt)
+{
+ if (!rt->rtOneWay && !rt->rtSimpleReply) {
+ argument_t *arg = rt->rtRetCode;
+
+ arg->argKind = akRemFeature(arg->argKind, akbReply);
+ /* we want the RetCode to be a local variable instead */
+ arg->argKind = akAddFeature(arg->argKind, akbVarNeeded);
+ }
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ argument_t *arg = rt->rtRetCArg;
+
+ arg->argKind = akeRetCode|akbUserArg|akbServerArg|akbSendRcv;
+ }
+}
+
+/*
+ * Adds an implicit NDR argument. It exists in the reply message,
+ * where it is the first piece of data.
+ */
+
+static void
+rtAddNdrCode(routine_t *rt)
+{
+ argument_t *arg = argAlloc();
+
+ arg->argName = "NDR_record";
+ arg->argType = itNdrCodeType;
+ arg->argKind = akeNdrCode;
+ rt->rtNdrCode = arg;
+
+ /* add at beginning, so ndr-code is first in the reply message */
+ arg->argNext = rt->rtArgs;
+ rt->rtArgs = arg;
+}
+
+/*
+ * Process the NDR Code.
+ * We stick a NDR format label iff there is untyped data
+ */
+static void
+rtProcessNdrCode(routine_t *rt)
+{
+ argument_t *ndr = rt->rtNdrCode;
+ argument_t *arg;
+ boolean_t found;
+
+ /* akbSendSnd|akbSendBody initialize the NDR format label */
+#define ndr_send akbRequest|akbSend|akbSendSnd|akbSendBody
+ /* akbReplyInit initializes the NDR format label */
+#define ndr_rcv akbReply|akbReplyInit|akbReturn|akbReturnBody
+
+ ndr->argKind = akAddFeature(ndr->argKind, ndr_send|ndr_rcv);
+
+ for (found = FALSE, arg = ndr->argNext; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, akbSendRcv|akbSendBody) &&
+ !akCheck(arg->argKind, akbServerImplicit) && !arg->argType->itPortType &&
+ (!arg->argParent || akIdent(arg->argKind) == akeCount ||
+ akIdent(arg->argKind) == akeCountInOut)) {
+ arg->argKind = akAddFeature(arg->argKind, akbSendNdr);
+ found = TRUE;
+ }
+ if (!found)
+ ndr->argKind = akRemFeature(ndr->argKind, ndr_send);
+
+ found = FALSE;
+ if (!rt->rtOneWay)
+ for (arg = ndr->argNext; arg != argNULL; arg = arg->argNext)
+ if ((arg == rt->rtRetCode && akCheck(arg->argKind, akbReply)) ||
+ (arg != rt->rtRetCode &&
+ akCheck(arg->argKind, akbReturnRcv|akbReturnBody) &&
+ !akCheck(arg->argKind, akbUserImplicit) && !arg->argType->itPortType &&
+ (!arg->argParent || akIdent(arg->argKind) == akeCount ||
+ akIdent(arg->argKind) == akeCountInOut))) {
+ arg->argKind = akAddFeature(arg->argKind, akbReturnNdr);
+ found = TRUE;
+ }
+ if (!found && !akCheck(rt->rtRetCode->argKind, akbReply))
+ ndr->argKind = akRemFeature(ndr->argKind, ndr_rcv);
+}
+
+/*
+ * Adds a dummy WaitTime argument to the function.
+ * This argument doesn't show up in any C argument lists;
+ * it implements the global WaitTime statement.
+ */
+
+static void
+rtAddWaitTime(routine_t *rt, identifier_t name, arg_kind_t kind)
+{
+ argument_t *arg = argAlloc();
+ argument_t **loc;
+
+ arg->argName = "dummy WaitTime arg";
+ arg->argVarName = name;
+ arg->argType = itWaitTimeType;
+ arg->argKind = kind;
+ rt->rtWaitTime = arg;
+
+ /* add wait-time after msg-option, if possible */
+
+ if (rt->rtMsgOption != argNULL)
+ loc = &rt->rtMsgOption->argNext;
+ else
+ loc = &rt->rtArgs;
+
+ arg->argNext = *loc;
+ *loc = arg;
+
+ rtSetArgDefaults(rt, arg);
+}
+
+/*
+ * Adds a dummy MsgOption argument to the function.
+ * This argument doesn't show up in any C argument lists;
+ * it implements the global MsgOption statement.
+ */
+
+static void
+rtAddMsgOption(routine_t *rt, identifier_t name)
+{
+ argument_t *arg = argAlloc();
+ argument_t **loc;
+
+ arg->argName = "dummy MsgOption arg";
+ arg->argVarName = name;
+ arg->argType = itMsgOptionType;
+ arg->argKind = akeMsgOption;
+ rt->rtMsgOption = arg;
+
+ /* add msg-option after msg-seqno */
+
+ loc = &rt->rtArgs;
+
+ arg->argNext = *loc;
+ *loc = arg;
+
+ rtSetArgDefaults(rt, arg);
+}
+
+/*
+ * Process the MsgOption Code.
+ * We must add the information to post a receive with the right
+ * Trailer options.
+ */
+static void
+rtProcessMsgOption(routine_t *rt)
+{
+ argument_t *msgop = rt->rtMsgOption;
+ argument_t *arg;
+ boolean_t sectoken = FALSE;
+ boolean_t audittoken = FALSE;
+ boolean_t contexttoken = FALSE;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, akbReturn|akbUserImplicit)) {
+ if (akIdent(arg->argKind) == akeSecToken)
+ sectoken = TRUE;
+ else if (akIdent(arg->argKind) == akeAuditToken)
+ audittoken = TRUE;
+ else if (akIdent(arg->argKind) == akeContextToken)
+ contexttoken = TRUE;
+ }
+
+ if (contexttoken == TRUE)
+ msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX)");
+ else if (audittoken == TRUE)
+ msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)");
+ else if (sectoken == TRUE)
+ msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)");
+ /* other implicit data received by the user will be handled here */
+}
+
+static void
+rtProcessUseSpecialReplyPort(routine_t *rt)
+{
+ if (IsKernelUser || IsKernelServer) {
+ fatal("UseSpecialReplyPort option cannot be used with KernelUser / KernelServer\n");
+ }
+ rt->rtMsgOption->argVarName = strconcat(rt->rtMsgOption->argVarName, "|__MigSpecialReplyPortMsgOption");
+}
+
+/*
+ * Adds a dummy reply port argument to the function.
+ */
+
+static void
+rtAddDummyReplyPort(routine_t *rt, ipc_type_t *type)
+{
+ argument_t *arg = argAlloc();
+ argument_t **loc;
+
+ arg->argName = "dummy ReplyPort arg";
+ arg->argVarName = "dummy ReplyPort arg";
+ arg->argType = type;
+ arg->argKind = akeReplyPort;
+ rt->rtReplyPort = arg;
+
+ /* add the reply port after the request port */
+
+ if (rt->rtRequestPort != argNULL)
+ loc = &rt->rtRequestPort->argNext;
+ else
+ loc = &rt->rtArgs;
+
+ arg->argNext = *loc;
+ *loc = arg;
+
+ rtSetArgDefaults(rt, arg);
+}
+
+
+/*
+ * At least one overwrite keyword has been detected:
+ * we tag all the OOL entries (ports + data) with
+ * akbOverwrite which will tell us that we have to
+ * fill a KPD entry in the message-template
+ */
+static void
+rtCheckOverwrite(routine_t *rt)
+{
+ argument_t *arg;
+ int howmany = rt->rtOverwrite;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+
+ if (akCheck(arg->argKind, akbReturnKPD) && !it->itInLine) {
+ /* among OUT args, we want OOL, OOL ports and MigInLine */
+ arg->argKind = akAddFeature(arg->argKind, akbOverwrite);
+ if (arg->argFlags & flOverwrite)
+ howmany--;
+ if (!howmany)
+ return;
+ }
+ }
+}
+
+/*
+ * Initializes argRequestPos, argReplyPos, rtMaxRequestPos, rtMaxReplyPos,
+ * rtNumRequestVar, rtNumReplyVar, and adds akbVarNeeded to those arguments
+ * that need it because of variable-sized inline considerations.
+ *
+ * argRequestPos and argReplyPos get -1 if the value shouldn't be used.
+ */
+static void
+rtCheckVariable(routine_t *rt)
+{
+ argument_t *arg;
+ int NumRequestVar = 0;
+ int NumReplyVar = 0;
+ int MaxRequestPos = 0;
+ int MaxReplyPos = 0;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ argument_t *parent = arg->argParent;
+
+ /*
+ * We skip KPDs. We have to make sure that the KPDs count
+ * present in the message body follow the RequestPos/ReplyPos logic
+ * The rest of the parameters are defaulted to have
+ * Arg{Request, Reply}Pos = 0
+ */
+ if (parent == argNULL || akCheck(parent->argKind, akbSendKPD|akbReturnKPD)) {
+ if (akCheckAll(arg->argKind, akbSend|akbSendBody)) {
+ arg->argRequestPos = NumRequestVar;
+ MaxRequestPos = NumRequestVar;
+ if (akCheck(arg->argKind, akbVariable))
+ NumRequestVar++;
+ }
+ if (akCheckAll(arg->argKind, akbReturn|akbReturnBody)) {
+ arg->argReplyPos = NumReplyVar;
+ MaxReplyPos = NumReplyVar;
+ if (akCheck(arg->argKind, akbVariable))
+ NumReplyVar++;
+ }
+ }
+ else {
+ arg->argRequestPos = parent->argRequestPos;
+ arg->argReplyPos = parent->argReplyPos;
+ }
+ /*
+ printf("Var %s Kind %x RequestPos %d\n", arg->argVarName, arg->argKind, arg->argRequestPos);
+ printf("* Var %s Kind %x ReplyPos %d\n", arg->argVarName, arg->argKind, arg->argReplyPos);
+ */
+
+ /* Out variables that follow a variable-sized field
+ need VarNeeded or ReplyCopy; they can't be stored
+ directly into the reply message. */
+
+ if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody) &&
+ !akCheck(arg->argKind, akbReplyCopy|akbVarNeeded) &&
+ (arg->argReplyPos > 0))
+ arg->argKind = akAddFeature(arg->argKind, akbVarNeeded);
+ }
+
+ rt->rtNumRequestVar = NumRequestVar;
+ rt->rtNumReplyVar = NumReplyVar;
+ rt->rtMaxRequestPos = MaxRequestPos;
+ rt->rtMaxReplyPos = MaxReplyPos;
+}
+
+/*
+ * Adds akbDestroy where needed.
+ */
+
+static void
+rtCheckDestroy(routine_t *rt)
+{
+ argument_t *arg;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+
+ if(akCheck(arg->argKind, akbSendRcv) &&
+ !akCheck(arg->argKind, akbReturnSnd) &&
+ (it->itDestructor != strNULL || IS_MIG_INLINE_EMUL(it))) {
+ arg->argKind = akAddFeature(arg->argKind, akbDestroy);
+ }
+ if (argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
+ arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR &&
+ (arg->argFlags & flAuto))
+ arg->argKind = akAddFeature(arg->argKind, akbDestroy);
+ }
+}
+
+/*
+ * Sets ByReferenceUser and ByReferenceServer.
+ */
+
+static void
+rtAddByReference(routine_t *rt)
+{
+ argument_t *arg;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+
+ if (akCheck(arg->argKind, akbReturnRcv) && it->itStruct) {
+ arg->argByReferenceUser = TRUE;
+
+ /*
+ * A CountInOut arg itself is not akbReturnRcv,
+ * so we need to set argByReferenceUser specially.
+ */
+
+ if (arg->argCInOut != argNULL)
+ arg->argCInOut->argByReferenceUser = TRUE;
+ }
+
+ if ((akCheck(arg->argKind, akbReturnSnd) ||
+ (akCheck(arg->argKind, akbServerImplicit) &&
+ akCheck(arg->argKind, akbReturnRcv) &&
+ akCheck(arg->argKind, akbSendRcv)))
+ && it->itStruct) {
+ arg->argByReferenceServer = TRUE;
+ }
+ }
+}
+
+/*
+ * This procedure can be executed only when all the akb* and ake* have
+ * been set properly (when rtAddCountArg is executed, akbVarNeeded
+ * might not be set yet - see rtCheckVariable)
+ */
+void
+rtAddSameCount(routine_t *rt)
+{
+ argument_t *arg;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (arg->argFlags & flSameCount) {
+ ipc_type_t *it = arg->argType;
+ argument_t *tmp_count;
+ argument_t *my_count = arg->argCount;
+ argument_t *ref_count = arg->argSameCount->argCount;
+
+ tmp_count = argAlloc();
+ *tmp_count = *ref_count;
+ /*
+ * if our count is a akbVarNeeded, we need to copy this
+ * attribute to the master count!
+ */
+ tmp_count->argKind = akeSameCount;
+ ref_count->argKind = akAddFeature(ref_count->argKind, akCheck(my_count->argKind, akbVarNeeded));
+ tmp_count->argKind = akAddFeature(tmp_count->argKind, akCheck(my_count->argKind, akbVarNeeded));
+ tmp_count->argNext = my_count->argNext;
+ tmp_count->argMultiplier = my_count->argMultiplier;
+ tmp_count->argType = my_count->argType;
+ tmp_count->argParent = arg;
+ /* we don't need more */
+ arg->argCount = tmp_count;
+ arg->argNext = tmp_count;
+ /* for these args, Cnt is not akbRequest, and therefore size is embedded */
+ if (IS_VARIABLE_SIZED_UNTYPED(it))
+ it->itMinTypeSize = 0;
+ tmp_count->argType->itMinTypeSize = 0;
+ tmp_count->argType->itTypeSize = 0;
+ }
+}
+
+void
+rtCheckRoutine(routine_t *rt)
+{
+ /* Initialize random fields. */
+
+ rt->rtErrorName = ErrorProc;
+ rt->rtOneWay = (rt->rtKind == rkSimpleRoutine);
+ rt->rtServerName = strconcat(ServerPrefix, rt->rtName);
+ rt->rtUserName = strconcat(UserPrefix, rt->rtName);
+ rt->rtUseSpecialReplyPort = UseSpecialReplyPort && !rt->rtOneWay;
+ rt->rtConsumeOnSendError = ConsumeOnSendError;
+
+ /* Add implicit arguments. */
+
+ rtAddRetCode(rt);
+ rtAddNdrCode(rt);
+
+ /* Check out the arguments and their types. Add count, poly
+ implicit args. Any arguments added after rtCheckRoutineArgs
+ should have rtSetArgDefaults called on them. */
+
+ rtCheckRoutineArgs(rt);
+
+ /* Add dummy WaitTime and MsgOption arguments, if the routine
+ doesn't have its own args and the user specified global values. */
+
+ if (rt->rtReplyPort == argNULL) {
+ if (rt->rtOneWay)
+ rtAddDummyReplyPort(rt, itZeroReplyPortType);
+ else
+ rtAddDummyReplyPort(rt, itRealReplyPortType);
+ } else if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) {
+ /* If an explicit ReplyPort is used, we can't assume it will be the SRP */
+ rt->rtUseSpecialReplyPort = FALSE;
+ }
+ if (rt->rtMsgOption == argNULL) {
+ if (MsgOption == strNULL)
+ rtAddMsgOption(rt, "MACH_MSG_OPTION_NONE");
+ else
+ rtAddMsgOption(rt, MsgOption);
+ }
+ if (rt->rtWaitTime == argNULL) {
+ if (WaitTime != strNULL)
+ rtAddWaitTime(rt, WaitTime, akeWaitTime);
+ else if (SendTime != strNULL)
+ rtAddWaitTime(rt, SendTime, akeSendTime);
+ }
+ if (rt->rtWaitTime && rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) {
+ warn("%s %s specifies a SendTime/WaitTime which may leak resources, "
+ "adopt \"ConsumeOnSendError Timeout\"",
+ rtRoutineKindToStr(rt->rtKind), rt->rtName);
+ }
+
+
+ /* Now that all the arguments are in place, do more checking. */
+
+ rtCheckArgTypes(rt);
+ rtCheckArgTrans(rt);
+
+ if (rt->rtOneWay) {
+ if (rtCheckMask(rt->rtArgs, akbReturn) || rt->rtUserImpl)
+ error("%s %s has OUT argument", rtRoutineKindToStr(rt->rtKind), rt->rtName);
+ }
+
+ /* If there were any errors, don't bother calculating more info
+ that is only used in code generation anyway. Therefore,
+ the following functions don't have to worry about null types. */
+
+ if (mig_errors > 0)
+ fatal("%d errors found. Abort.\n", mig_errors);
+
+ rt->rtServerImpl = rtCountMask(rt->rtArgs, akbServerImplicit);
+ rt->rtUserImpl = rtCountMask(rt->rtArgs, akbUserImplicit);
+ /*
+ * ASSUMPTION:
+ * kernel cannot change a message from simple to complex,
+ * therefore SimpleSendReply and SimpleRcvReply become SimpleReply
+ */
+ rtCheckSimple(rt->rtArgs, akbRequest, &rt->rtSimpleRequest);
+ rtCheckSimple(rt->rtArgs, akbReply, &rt->rtSimpleReply);
+
+ rt->rtRequestKPDs = rtCountKPDs(rt->rtArgs, akbSendKPD);
+ rt->rtReplyKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD);
+ /*
+ * Determine how many overwrite parameters we have:
+ * # of Overwrite args -> rt->rtOverwrite
+ * flOverwrite -> the arg has to be overwritten
+ * akbOverwrite -> the arg has to be declared in the message-template
+ * (only as a placeholder if !flOverwrite).
+ */
+ if ((rt->rtOverwrite = rtCountFlags(rt->rtArgs, flOverwrite))) {
+ rtCheckOverwrite(rt);
+ rt->rtOverwriteKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD|akbOverwrite);
+ if (IsKernelUser)
+ fatal("Overwrite option(s) do not match with the KernelUser personality\n");
+ }
+
+ rtCheckFit(rt, akbRequest, &rt->rtRequestFits, &rt->rtRequestUsedLimit, &rt->rtRequestSizeKnown);
+ rtCheckFit(rt, akbReply, &rt->rtReplyFits, &rt->rtReplyUsedLimit, &rt->rtReplySizeKnown);
+
+ rtCheckVariable(rt);
+ rtCheckDestroy(rt);
+ rtAddByReference(rt);
+ rtSuffixExtArg(rt->rtArgs);
+ rtAddSameCount(rt);
+ rtProcessRetCode(rt);
+ rtProcessNdrCode(rt);
+ if (rt->rtUserImpl)
+ rtProcessMsgOption(rt);
+ if (rt->rtUseSpecialReplyPort)
+ rtProcessUseSpecialReplyPort(rt);
+
+ rt->rtNoReplyArgs = !rtCheckMask(rt->rtArgs, akbReturnSnd);
+
+ if (UseEventLogger)
+ /* some more info's are needed for Event logging/Stats */
+ rtFindHowMany(rt);
+}
+
+void
+rtMinRequestSize(FILE *file, routine_t *rt, char *str)
+{
+ fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str);
+ rtSizeDelta(file, akbRequest, rt);
+ fprintf(file, ")");
+}
+
+void
+rtMinReplySize(FILE *file, routine_t *rt, char *str)
+{
+ fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str);
+ rtSizeDelta(file, akbReply, rt);
+ fprintf(file, ")");
+}
+
+static void
+rtSizeDelta(FILE *file, u_int mask, routine_t *rt)
+{
+ argument_t *arg;
+ u_int min_size = sizeof(mach_msg_header_t);
+ u_int max_size;
+ boolean_t output = FALSE;
+
+ if (!rt->rtSimpleRequest)
+ machine_alignment(min_size, sizeof(mach_msg_body_t));
+ max_size = min_size;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, mask)) {
+ ipc_type_t *it = arg->argType;
+
+ machine_alignment(min_size, it->itMinTypeSize);
+ machine_alignment(max_size, it->itMinTypeSize);
+
+ if (IS_VARIABLE_SIZED_UNTYPED(it)) {
+ machine_alignment(max_size, it->itTypeSize);
+ max_size += it->itPadSize;
+ }
+ if (IS_OPTIONAL_NATIVE(it)) {
+ if (output)
+ fprintf(file, " + ");
+ else {
+ output = TRUE;
+ fprintf(file, " - (");
+ }
+ fprintf(file, "_WALIGNSZ_(%s)", it->itUserType);
+ }
+ }
+ if (min_size != max_size) {
+ if (output)
+ fprintf(file, " + ");
+ else
+ fprintf(file, " - ");
+ fprintf(file, "%d", max_size - min_size);
+ }
+ if (output)
+ fprintf(file, ")");
+}
+
diff --git a/bootstrap_cmds/migcom.tproj/routine.h b/bootstrap_cmds/migcom.tproj/routine.h
new file mode 100644
index 0000000..1b63a03
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/routine.h
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <assert.h>
+
+#ifndef _ROUTINE_H
+#define _ROUTINE_H
+
+#include "type.h"
+#include <stdio.h>
+#include <mach/message.h>
+#include <mach/boolean.h>
+#include <sys/types.h>
+
+/* base kind arg */
+#define akeNone (0)
+#define akeNormal (1) /* a normal, user-defined argument */
+#define akeRequestPort (2) /* pointed at by rtRequestPort */
+#define akeWaitTime (3) /* pointed at by rtWaitTime */
+#define akeReplyPort (4) /* pointed at by rtReplyPort */
+#define akeMsgOption (5) /* pointed at by rtMsgOption */
+#define akeMsgSeqno (6) /* pointed at by rtMsgSeqno */
+#define akeRetCode (7) /* pointed at by rtRetCode */
+#define akeNdrCode (8) /* pointed at by rtNdrCode */
+#define akeCount (9) /* a count arg for argParent */
+#define akePoly (10) /* a poly arg for argParent */
+#define akeDealloc (11) /* a deallocate arg for argParent */
+#define akeCountInOut (12) /* a count-in-out arg */
+#define akeSameCount (13) /* a samecount case: in fact, a no count! */
+#define akeSubCount (14) /* a array of array case: subordinate arrays count */
+#define akeImplicit (15) /* an implicit argument, from the trailer */
+#define akeSecToken (16) /* an argument from the trailer: the security token */
+#define akeAuditToken (17) /* an argument from the trailer: the audit token */
+#define akeContextToken (18) /* an argument from the trailer: the context token */
+#define akeSendTime (19) /* pointed at by rtWaitTime */
+
+#define akeBITS (0x0000003f)
+#define akbRequest (0x00000040) /* has a msg_type in request */
+#define akbReply (0x00000080) /* has a msg_type in reply */
+#define akbUserArg (0x00000100) /* an arg on user-side */
+#define akbServerArg (0x00000200) /* an arg on server-side */
+#define akbSend (0x00000400) /* value carried in request */
+#define akbSendBody (0x00000800) /* value carried in request body */
+#define akbSendSnd (0x00001000) /* value stuffed into request */
+#define akbSendRcv (0x00002000) /* value grabbed from request */
+#define akbReturn (0x00004000) /* value carried in reply */
+#define akbReturnBody (0x00008000) /* value carried in reply body */
+#define akbReturnSnd (0x00010000) /* value stuffed into reply */
+#define akbReturnRcv (0x00020000) /* value grabbed from reply */
+#define akbReturnNdr (0x00040000) /* needs NDR conversion in reply */
+#define akbReplyInit (0x00080000) /* reply value doesn't come from target routine */
+#define akbReplyCopy (0x00200000) /* copy reply value from request */
+#define akbVarNeeded (0x00400000) /* may need local var in server */
+#define akbDestroy (0x00800000) /* call destructor function */
+#define akbVariable (0x01000000) /* variable size inline data */
+#define akbSendNdr (0x04000000) /* needs NDR conversion in request */
+#define akbSendKPD (0x08000000) /* the arg is sent in the Kernel Processed Data
+ section of the Request message */
+#define akbReturnKPD (0x10000000) /* the arg is sent in the Kernel Processed Data
+ section of the Reply message */
+#define akbUserImplicit (0x20000000) /* the arg is Impl */
+#define akbServerImplicit (0x40000000) /* the arg is Impl */
+#define akbOverwrite (0x80000000)
+/* be careful, there aren't many bits left */
+
+typedef u_int arg_kind_t;
+
+/*
+ * akbRequest means msg_type/data fields are allocated in the request
+ * msg. akbReply means msg_type/data fields are allocated in the
+ * reply msg. These bits * control msg structure declarations packing,
+ * and checking of mach_msg_type_t fields.
+ *
+ * akbUserArg means this argument is an argument to the user-side stub.
+ * akbServerArg means this argument is an argument to
+ * the server procedure called by the server-side stub.
+ *
+ * The akbSend* and akbReturn* bits control packing/extracting values
+ * in the request and reply messages.
+ *
+ * akbSend means the argument's value is carried in the request msg.
+ * akbSendBody implies akbSend; the value is carried in the msg body.
+ * akbSendKPD is the equivalent of akbSendBody for Kernel Processed Data.
+ * akbSendSnd implies akbSend; the value is stuffed into the request.
+ * akbSendRcv implies akbSend; the value is pulled out of the request.
+ *
+ * akbReturn, akbReturnBody, akbReturnSnd, akbReturnRcv are defined
+ * similarly but apply to the reply message.
+ *
+ * User-side code generation (header.c, user.c) and associated code
+ * should use akbSendSnd and akbReturnRcv, but not akbSendRcv and
+ * akbReturnSnd. Server-side code generation (server.c) is reversed.
+ * Code generation should use the more specific akb{Send,Return}{Snd,Rcv}
+ * bits when possible, instead of akb{Send,Return}.
+ *
+ * Note that akRetCode and akReturn lack any Return bits, although
+ * there is a value in the msg. These guys are packed/unpacked
+ * with special code, unlike other arguments.
+ *
+ * akbReplyInit implies akbReply. It means the server-side stub
+ * should initialize the field, because its value does not come
+ * from the execution of the target routine: the setting of the
+ * NDR record is the sole example (at the moment) of use of this flag.
+ *
+ * akbVariable means the argument has variable-sized inline data.
+ * It isn't currently used for code generation, but routine.c
+ * does use it internally. It is added in rtAugmentArgKind.
+ *
+ * akbReplyCopy and akbVarNeeded help control code generation in the
+ * server-side stub. The preferred method of handling data in the
+ * server-side stub avoids copying into/out-of local variables. In
+ * arguments get passed directly to the server proc from the request msg.
+ * Out arguments get stuffed directly into the reply msg by the server proc.
+ * For InOut arguments, the server proc gets the address of the data in
+ * the request msg, and the resulting data gets copied to the reply msg.
+ * Some arguments need a local variable in the server-side stub. The
+ * code extracts the data from the request msg into the variable, and
+ * stuff the reply msg from the variable.
+ *
+ * akbReplyCopy implies akbReply. It means the data should get copied
+ * from the request msg to the reply msg after the server proc is called.
+ * It is only used by akInOut. akTid doesn't need it because the tid
+ * data in the reply msg is initialized in the server demux function.
+ *
+ * akbVarNeeded means the argument needs a local variable in the
+ * server-side stub. It is added in rtAugmentArgKind and
+ * rtCheckVariable. An argument shouldn't have all three of
+ * akbReturnSnd, akbVarNeeded and akbReplyCopy, because this indicates
+ * the reply msg should be stuffed both ways.
+ *
+ * akbDestroy helps control code generation in the server-side stub.
+ * It means this argument has a destructor function which should be called.
+ *
+ * akbOverwrite is used to identify the arguments that have to put an entry in
+ * the scatter list (the message-template used by the User stub to specify
+ * where the out-of-line data sent by server has to land).
+ *
+ * akbUserImplicit (akbServerImplicit) is used to mark the arguments that
+ * correspond to implicit data (data generated by the kernel and inserted in
+ * the trailer).
+ *
+ * Header file generation (header.c) uses:
+ * akbUserArg
+ *
+ * User stub generation (user.c) uses:
+ * akbUserArg, akbRequest, akbReply, akbSendSnd,
+ * akbSendBody, akbSendKPD, akbReturnRcv, akbOverwrite, akbUserImplicit
+ *
+ * Server stub generation (server.c) uses:
+ * akbServerArg, akbRequest, akbReply, akbSendRcv, akbReturnSnd,
+ * akbReplyCopy, akbVarNeeded, akbSendBody, akbServerImplicit
+ *
+ *
+ * During code generation, the routine, argument, and type data structures
+ * are read-only. The code generation functions' output is their only
+ * side-effect.
+ *
+ *
+ * Style note:
+ * Code can use logical operators (|, &, ~) on akb values.
+ * ak values should be manipulated with the ak functions.
+ */
+
+/* various useful combinations */
+
+#define akbNone (0)
+#define akbAll (~akbNone)
+#define akbAllBits (~akeBITS)
+
+#define akbSendBits (akbSend|akbSendBody|akbSendSnd|akbSendRcv)
+#define akbReturnBits (akbReturn|akbReturnBody|akbReturnSnd|akbReturnRcv)
+#define akbSendReturnBits (akbSendBits|akbReturnBits)
+
+#define akNone akeNone
+
+#define akIn akAddFeature(akeNormal, \
+ akbUserArg|akbServerArg|akbRequest|akbSendBits)
+
+#define akOut akAddFeature(akeNormal, \
+ akbUserArg|akbServerArg|akbReply|akbReturnBits)
+
+#define akServerImpl akAddFeature(akeImplicit, \
+ akbServerArg|akbServerImplicit|akbSend|akbSendRcv)
+#define akUserImpl akAddFeature(akeImplicit, \
+ akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv)
+
+#define akServerSecToken akAddFeature(akeSecToken, \
+ akbServerArg|akbServerImplicit|akbSend|akbSendRcv)
+#define akUserSecToken akAddFeature(akeSecToken, \
+ akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv)
+#define akSecToken akAddFeature(akeSecToken, \
+ akbServerArg|akbServerImplicit|akbSend|akbSendRcv| \
+ akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv)
+
+#define akServerAuditToken akAddFeature(akeAuditToken, \
+ akbServerArg|akbServerImplicit|akbSend|akbSendRcv)
+#define akUserAuditToken akAddFeature(akeAuditToken, \
+ akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv)
+#define akAuditToken akAddFeature(akeAuditToken, \
+ akbServerArg|akbServerImplicit|akbSend|akbSendRcv| \
+ akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv)
+
+#define akServerContextToken akAddFeature(akeContextToken, \
+ akbServerArg|akbServerImplicit|akbSend|akbSendRcv)
+
+#define akMsgSeqno akAddFeature(akeMsgSeqno, \
+ akbServerArg|akbServerImplicit|akbSend|akbSendRcv)
+
+#define akInOut akAddFeature(akeNormal, \
+ akbUserArg|akbServerArg|akbRequest|akbReply| \
+ akbSendBits|akbReturnBits|akbReplyCopy)
+
+#define akRequestPort akAddFeature(akeRequestPort, \
+ akbUserArg|akbServerArg|akbSend|akbSendSnd|akbSendRcv)
+
+#define akWaitTime akAddFeature(akeWaitTime, akbUserArg)
+
+#define akSendTime akAddFeature(akeSendTime, akbUserArg)
+
+#define akMsgOption akAddFeature(akeMsgOption, akbUserArg)
+
+#define akReplyPort akAddFeature(akeReplyPort, \
+ akbUserArg|akbServerArg|akbSend|akbSendSnd|akbSendRcv)
+
+#define akUReplyPort akAddFeature(akeReplyPort, \
+ akbUserArg|akbSend|akbSendSnd|akbSendRcv)
+
+#define akSReplyPort akAddFeature(akeReplyPort, \
+ akbServerArg|akbSend|akbSendSnd|akbSendRcv)
+
+#define akRetCode akAddFeature(akeRetCode, akbReply|akbReturnBody)
+
+#define akCount akAddFeature(akeCount, \
+ akbUserArg|akbServerArg)
+
+#define akPoly akePoly
+
+#define akDealloc akAddFeature(akeDealloc, akbUserArg)
+
+#define akCountInOut akAddFeature(akeCountInOut, akbRequest|akbSendBits)
+
+#define akCheck(ak, bits) ((ak) & (bits))
+#define akCheckAll(ak, bits) (akCheck(ak, bits) == (bits))
+#define akAddFeature(ak, bits) ((ak)|(bits))
+#define akRemFeature(ak, bits) ((ak)&~(bits))
+#define akIdent(ak) ((ak) & akeBITS)
+
+#define argIsIn(arg) (akIdent(arg->argKind) == akeNormal && \
+ akCheck(arg->argKind, akbRequest))
+#define argIsOut(arg) (akIdent(arg->argKind) == akeNormal && \
+ akCheck(arg->argKind, akbReply))
+
+/*
+ * The arguments to a routine/function are linked in left-to-right order.
+ * argName is used for error messages and pretty-printing,
+ * not code generation. Code generation shouldn't make any assumptions
+ * about the order of arguments, esp. count and poly arguments.
+ * (Unfortunately, code generation for inline variable-sized arguments
+ * does make such assumptions.)
+ *
+ * argVarName is the name used in generated code for function arguments
+ * and local variable names. argMsgField is the name used in generated
+ * code for the field in msgs where the argument's value lives.
+ * argTTName is the name used in generated code for msg-type fields and
+ * static variables used to initialize those fields. argPadName is the
+ * name used in generated code for a padding field in msgs.
+ *
+ * argFlags can be used to override the deallocate bits
+ * in the argument's type. rtProcessArgFlags sets argDeallocate
+ * from it and the type. Code generation shouldn't use
+ * argFlags.
+ *
+ * argCount, argPoly, and argDealloc get to the implicit count, poly,
+ * and dealloc arguments associated with the argument; they should be
+ * used instead of argNext. In these implicit arguments, argParent is
+ * a pointer to the "real" arg.
+ *
+ * In count arguments, argMultiplier is a scaling factor applied to
+ * the count arg's value to get msg-type-number. It is equal to
+ * argParent->argType->itElement->itNumber
+ *
+ */
+
+typedef struct argument
+{
+ /* if argKind == akReturn, then argName is name of the function */
+ identifier_t argName;
+ struct argument *argNext;
+
+ arg_kind_t argKind;
+ ipc_type_t *argType;
+ /* Kernel Processed Data */
+ mach_msg_descriptor_type_t argKPD_Type; /* KPD type: port, ool, port+ool */
+ void (* argKPD_Template)(FILE *file, struct argument *arg, boolean_t in); /* KPD discipline for static templates */
+ void (* argKPD_Init)(FILE *file, struct argument *arg); /* KPD discipline for initializing */
+ void (* argKPD_Pack)(FILE *file, struct argument *ar); /* KPD discipline for packing */
+ void (* argKPD_Extract)(FILE *file, struct argument *arg); /* KPD discipline for extracting */
+ void (* argKPD_TypeCheck)(FILE *file, struct argument *ar); /* KPD discipline for type checking */
+
+ string_t argVarName; /* local variable and argument names */
+ string_t argMsgField; /* message field's name */
+ string_t argTTName; /* name for msg_type fields, static vars */
+ string_t argPadName; /* name for pad field in msg */
+ string_t argSuffix; /* name extension for KPDs */
+
+ ipc_flags_t argFlags;
+ dealloc_t argDeallocate; /* overrides argType->itDeallocate */
+ boolean_t argCountInOut;
+
+ struct routine *argRoutine; /* routine we are part of */
+
+ struct argument *argCount; /* our count arg, if present */
+ struct argument *argSubCount; /* our sub-count arg, if present (variable subordinate arrays) */
+ struct argument *argCInOut; /* our CountInOut arg, if present */
+ struct argument *argPoly; /* our poly arg, if present */
+ struct argument *argDealloc; /* our dealloc arg, if present */
+ struct argument *argSameCount; /* the arg to take the count from, if present */
+ struct argument *argParent; /* in a count or poly arg, the base arg */
+ u_int argMultiplier; /* for Count argument: parent is a multiple
+ of a basic IPC type. Argument must be
+ multiplied by Multiplier to get IPC
+ number-of-elements. */
+
+ /* how variable/inline args precede this one, in request and reply */
+ u_int argRequestPos;
+ u_int argReplyPos;
+ /* whether argument is by reference, on user and server side */
+ boolean_t argByReferenceUser;
+ boolean_t argByReferenceServer;
+
+ boolean_t argTempOnStack; /* A temporary for the short-circuiting
+ * code when -maxonstack is used.
+ */
+} argument_t;
+
+/*
+ * The various routine kinds' peculiarities are abstracted by rtCheckRoutine
+ * into attributes like rtOneWay, etc. These are what
+ * code generation should use. It is Bad Form for code generation to
+ * test rtKind.
+ */
+
+typedef enum
+{
+ rkRoutine,
+ rkSimpleRoutine
+} routine_kind_t;
+
+typedef struct routine
+{
+ identifier_t rtName;
+ routine_kind_t rtKind;
+ argument_t *rtArgs;
+ u_int rtNumber; /* used for making msg ids */
+
+ identifier_t rtUserName; /* user-visible name (UserPrefix + Name) */
+ identifier_t rtServerName; /* server-side name (ServerPrefix + Name) */
+
+ identifier_t rtErrorName; /* error-handler name */
+
+ boolean_t rtOneWay; /* SimpleRoutine */
+
+ boolean_t rtSimpleRequest;
+ boolean_t rtSimpleReply;
+ boolean_t rtUseSpecialReplyPort;
+ u_int rtConsumeOnSendError;
+
+ u_int rtNumRequestVar; /* number of variable/inline args in request */
+ u_int rtNumReplyVar; /* number of variable/inline args in reply */
+
+ u_int rtMaxRequestPos; /* maximum of argRequestPos */
+ u_int rtMaxReplyPos; /* maximum of argReplyPos */
+
+ u_int rtRequestKPDs; /* number of Kernel Processed Data entries */
+ u_int rtReplyKPDs; /* number of Kernel Processed Data entries */
+ u_int rtOverwrite; /* number of Overwrite entries */
+ u_int rtOverwriteKPDs; /* number of entries in the Overwrite template */
+
+ boolean_t rtNoReplyArgs; /* if so, no reply message arguments beyond
+ what the server dispatch routine inserts */
+
+ boolean_t rtRequestFits; /* Request fits within onstack limit */
+ boolean_t rtReplyFits; /* Reply fits within onstack limit */
+ boolean_t rtRequestUsedLimit;/* User type limit used in deciding whether
+ request fits within onstack limit */
+ boolean_t rtReplyUsedLimit; /* User type limit used in deciding whether
+ reply fits within onstack limit */
+ u_int rtRequestSizeKnown; /* Max size of known portion of request */
+ u_int rtReplySizeKnown; /* Max size of known portion of request */
+
+ u_int rtServerImpl; /* Implicit data requested */
+ u_int rtUserImpl; /* Implicit data requested */
+
+ /* distinguished arguments */
+ argument_t *rtRetCArg; /* the Routine has this argument tagged as RetCode */
+ argument_t *rtRequestPort; /* always non-NULL, defaults to first arg */
+ argument_t *rtReplyPort; /* always non-NULL, defaults to Mig-supplied */
+ argument_t *rtRetCode; /* always non-NULL */
+ argument_t *rtNdrCode; /* always non-NULL */
+ argument_t *rtWaitTime; /* if non-NULL, will use MACH_RCV_TIMEOUT */
+ argument_t *rtMsgOption; /* always non-NULL, defaults to NONE */
+
+ /* more info's used only when UseEventLogger is turned on */
+ u_int rtCountPortsIn; /* how many in-line Ports are sent */
+ u_int rtCountOolPortsIn; /* how many out_of-line Ports are sent */
+ u_int rtCountOolIn; /* how many bytes out_of-line are sent */
+
+ u_int rtCountPortsOut; /* how many in-line Ports are rcv'd */
+ u_int rtCountOolPortsOut; /* how many out_of-line Ports are rcv'd */
+ u_int rtCountOolOut; /* how many bytes out_of-line are rcv'd */
+
+ u_int rtTempBytesOnStack; /* A temporary for the short-circuiting
+ * code when -maxonstack is used.
+ */
+
+} routine_t;
+
+#define rtNULL ((routine_t *) 0)
+#define argNULL ((argument_t *) 0)
+#define argKPD_NULL ((mach_msg_descriptor_type_t) -1)
+
+#define rtMessOnStack(rt) ((rt)->rtRequestFits && (rt)->rtReplyFits)
+
+/*
+ * These are the ways MiG organizes stub parameters
+ */
+#define IS_VARIABLE_SIZED_UNTYPED(x) ((x)->itVarArray && \
+ (x)->itInLine && \
+ !(x)->itPortType)
+#define IS_KERN_PROC_DATA(x) (!(x)->itInLine || (x)->itPortType)
+#define IS_OPTIONAL_NATIVE(x) ((x)->itNative && \
+ (x)->itNativePointer && \
+ (x)->itBadValue != NULL)
+
+/*
+ * I consider the case of fixed/variable bounded arrays of ports or ool or oolport
+ */
+#define IS_MULTIPLE_KPD(x) ((x)->itKPD_Number > 1)
+/*
+ * I consider the case of MiG presenting data as it is inLine, even
+ * if it is sent/rcvd as out-of-line
+ */
+#define IS_MIG_INLINE_EMUL(x) ((x)->itMigInLine)
+
+extern u_int rtNumber;
+/* rt->rtNumber will be initialized */
+extern routine_t *rtAlloc(void);
+/* skip a number */
+extern void rtSkip(void);
+
+extern argument_t *argAlloc(void);
+
+extern boolean_t
+rtCheckMask(argument_t *args, u_int mask);
+
+extern boolean_t
+rtCheckMaskFunction(argument_t *args, u_int mask,
+ boolean_t (*func)(argument_t *arg));
+
+extern routine_t *
+rtMakeRoutine(identifier_t name, argument_t *args);
+extern routine_t *
+rtMakeSimpleRoutine(identifier_t name, argument_t *args);
+
+extern void rtPrintRoutine(routine_t *rt);
+extern void rtCheckRoutine(routine_t *rt);
+
+extern char *rtRoutineKindToStr(routine_kind_t rk);
+
+extern int rtCountArgDescriptors(argument_t *args, int *argcount);
+
+extern void rtMinRequestSize(FILE *file, routine_t *rt, char *str);
+extern void rtMinReplySize(FILE *file, routine_t *rt, char *str);
+
+#define RPCUserStruct(arg) (arg->argType->itStruct && arg->argType->itInLine)
+
+#define RPCString(arg) (arg->argType->itString && arg->argType->itInLine)
+
+#define RPCOutStruct(arg) (arg->argType->itStruct &&\
+ argIsOut(arg) && (! arg->argType->itVarArray))
+#define RPCOutWord(arg) (RPCUserStruct(arg) &&\
+ (arg->argType->itSize <= 32) &&\
+ (arg->argType->itNumber == 1) && argIsOut(arg))
+
+#define RPCPort(arg) (arg->argKPD_Type == MACH_MSG_PORT_DESCRIPTOR)
+
+#define RPCPortArray(arg) (arg->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR)
+
+#define RPCVariableArray(arg) ((arg->argType->itVarArray) &&\
+ !RPCPort(arg) && !RPCPortArray(arg))
+
+#define RPCFixedArray(arg) (((! arg->argType->itVarArray) &&\
+ !RPCPort(arg) && !RPCPortArray(arg) &&\
+ (arg->argType->itNumber > 1) &&\
+ !RPCUserStruct(arg)) ||\
+ RPCString(arg) ||\
+ RPCOutWord(arg) ||\
+ RPCOutStruct(arg))
+
+
+#endif /* _ROUTINE_H */
+
+
+
diff --git a/bootstrap_cmds/migcom.tproj/server.c b/bootstrap_cmds/migcom.tproj/server.c
new file mode 100644
index 0000000..7bbed53
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/server.c
@@ -0,0 +1,2772 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * @OSF_COPYRIGHT@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <mach/message.h>
+#include "write.h"
+#include "utils.h"
+#include "global.h"
+#include "error.h"
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif /* max */
+
+void WriteLogDefines(FILE *file, string_t who);
+void WriteIdentificationString(FILE *file);
+static void WriteFieldDecl(FILE *file, argument_t *arg);
+
+static void
+WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t varying, argument_t *arg, boolean_t bracket)
+{
+ ipc_type_t *it = arg->argType;
+ char string[MAX_STR_LEN];
+
+ fprintf(file, "\t{\n");
+ fprintf(file, "\t %s\t*ptr;\n", it->itKPDType);
+ fprintf(file, "\t int\ti");
+ if (varying && !in)
+ fprintf(file, ", j");
+ fprintf(file, ";\n\n");
+
+ if (in)
+ sprintf(string, "In%dP", arg->argRequestPos);
+ else
+ sprintf(string, "OutP");
+
+ fprintf(file, "\t ptr = &%s->%s[0];\n", string, arg->argMsgField);
+
+ if (varying) {
+ argument_t *count = arg->argCount;
+
+ if (in)
+ fprintf(file, "\t for (i = 0; i < In%dP->%s; ptr++, i++) %s\n", count->argRequestPos, count->argMsgField, (bracket) ? "{" : "");
+ else {
+ fprintf(file, "\t j = min(%d, ", it->itKPD_Number);
+ if (akCheck(count->argKind, akbVarNeeded))
+ fprintf(file, "%s);\n", count->argName);
+ else
+ fprintf(file, "%s->%s);\n", string, count->argMsgField);
+ fprintf(file, "\t for (i = 0; i < j; ptr++, i++) %s\n", (bracket) ? "{" : "");
+ }
+}
+ else
+ fprintf(file, "\t for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number, (bracket) ? "{" : "");
+}
+
+static void
+WriteMyIncludes(FILE *file, statement_t *stats)
+{
+ if (ServerHeaderFileName == strNULL || UseSplitHeaders)
+ WriteIncludes(file, FALSE, FALSE);
+ if (ServerHeaderFileName != strNULL)
+ {
+ char *cp;
+
+ /* Strip any leading path from ServerHeaderFileName. */
+ cp = strrchr(ServerHeaderFileName, '/');
+ if (cp == 0)
+ cp = ServerHeaderFileName;
+ else
+ cp++; /* skip '/' */
+ fprintf(file, "#include \"%s\"\n", cp);
+ }
+ if (ServerHeaderFileName == strNULL || UseSplitHeaders)
+ WriteImplImports(file, stats, FALSE);
+ if (UseEventLogger) {
+ if (IsKernelServer) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "#include <mig_debug.h>\n");
+ fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
+ }
+ fprintf(file, "#if MIG_DEBUG\n");
+ fprintf(file, "#include <mach/mig_log.h>\n");
+ fprintf(file, "#endif /* MIG_DEBUG */\n");
+ }
+
+ fprintf(file, "\n");
+}
+
+static void
+WriteGlobalDecls(FILE *file)
+{
+ if (BeAnsiC) {
+ fprintf(file, "#define novalue void\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "#define novalue void\n");
+ fprintf(file, "#else\n");
+ fprintf(file, "#define novalue int\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+ fprintf(file, "\n");
+
+ if (RCSId != strNULL)
+ WriteRCSDecl(file, strconcat(SubsystemName, "_server"), RCSId);
+
+ /* Used for locations in the request message, *not* reply message.
+ Reply message locations aren't dependent on IsKernelServer. */
+
+ if (IsKernelServer) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
+ fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
+ fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
+ fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
+ fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
+ fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
+ fprintf(file, "#else\n");
+ }
+ fprintf(file, "#define msgh_request_port\tmsgh_local_port\n");
+ fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
+ fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
+ fprintf(file, "#define msgh_reply_port\t\tmsgh_remote_port\n");
+ fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
+ fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
+ if (IsKernelServer) {
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+ }
+ fprintf(file, "\n");
+ if (UseEventLogger)
+ WriteLogDefines(file, "MACH_MSG_LOG_SERVER");
+ fprintf(file, "#define MIG_RETURN_ERROR(X, code)\t{\\\n");
+ fprintf(file, "\t\t\t\t((mig_reply_error_t *)X)->RetCode = code;\\\n");
+ fprintf(file, "\t\t\t\t((mig_reply_error_t *)X)->NDR = NDR_record;\\\n");
+ fprintf(file, "\t\t\t\treturn;\\\n");
+ fprintf(file, "\t\t\t\t}\n");
+ fprintf(file, "\n");
+}
+
+
+static void
+WriteForwardDeclarations(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ fprintf(file, "/* Forward Declarations */\n\n");
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ fprintf(file, "\nmig_internal novalue _X%s\n", stat->stRoutine->rtName);
+ fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);\n");
+ }
+ fprintf(file, "\n");
+}
+
+static void
+WriteMIGCheckDefines(FILE *file)
+{
+ fprintf(file, "#define\t__MIG_check__Request__%s_subsystem__ 1\n", SubsystemName);
+ fprintf(file, "\n");
+}
+
+static void
+WriteNDRDefines(FILE *file)
+{
+ fprintf(file, "#define\t__NDR_convert__Request__%s_subsystem__ 1\n", SubsystemName);
+ fprintf(file, "\n");
+}
+
+static void
+WriteProlog(FILE *file, statement_t *stats)
+{
+ WriteIdentificationString(file);
+ fprintf(file, "\n");
+ fprintf(file, "/* Module %s */\n", SubsystemName);
+ fprintf(file, "\n");
+ WriteMIGCheckDefines(file);
+ if (CheckNDR)
+ WriteNDRDefines(file);
+ WriteMyIncludes(file, stats);
+ WriteBogusDefines(file);
+ WriteApplDefaults(file, "Rcv");
+ WriteGlobalDecls(file);
+ if (ServerHeaderFileName == strNULL) {
+ WriteRequestTypes(file, stats);
+ WriteReplyTypes(file, stats);
+ WriteServerReplyUnion(file, stats);
+ }
+}
+
+static void
+WriteSymTabEntries(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+ u_int current = 0;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ int num = stat->stRoutine->rtNumber;
+ char *name = stat->stRoutine->rtName;
+ while (++current <= num)
+ fprintf(file,"\t\t\t{ \"\", 0, 0 },\n");
+ fprintf(file, "\t{ \"%s\", %d, _X%s },\n", name, SubsystemBase + current - 1, name);
+ }
+ while (++current <= rtNumber)
+ fprintf(file,"\t{ \"\", 0, 0 },\n");
+}
+
+static void
+WriteRoutineEntries(FILE *file, statement_t *stats)
+{
+ u_int current = 0;
+ statement_t *stat;
+ char *sig_array, *rt_name;
+ int arg_count, descr_count;
+ int offset = 0;
+ size_t serverSubsysNameLen = strlen(ServerSubsys);
+
+ fprintf(file, "\t{\n");
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ routine_t *rt = stat->stRoutine;
+ size_t rtNameLen = strlen(rt->rtName);
+
+ // Include length of rt->rtName in calculation of necessary buffer size, since that string
+ // is actually written into the buffer along with the Server Subsystem name.
+ sig_array = (char *) malloc(serverSubsysNameLen + rtNameLen + 80);
+ rt_name = (char *) malloc(rtNameLen + 5);
+ while (current++ < rt->rtNumber)
+ fprintf(file, "\t\t{0, 0, 0, 0, 0, 0},\n");
+ // NOTE: if either of the two string constants in the sprintf() function calls below get
+ // much longer, be sure to increase the constant '80' (in the first malloc() call) to ensure
+ // that the allocated buffer is large enough. (Currently, I count 66 characters in the first
+ // string constant, 65 in the second. 80 ought to be enough for now...)
+ if (UseRPCTrap) {
+ sprintf(sig_array, "&%s.arg_descriptor[%d], (mach_msg_size_t)sizeof(__Reply__%s_t)", ServerSubsys, offset, rt->rtName);
+ }
+ else {
+ sprintf(sig_array, "(routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__%s_t)", rt->rtName);
+ }
+ sprintf(rt_name, "_X%s", rt->rtName);
+ descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count);
+ offset += descr_count;
+ WriteRPCRoutineDescriptor(file, rt, arg_count, (UseRPCTrap) ? descr_count : 0, rt_name, sig_array);
+ fprintf(file, ",\n");
+ free(sig_array);
+ free(rt_name);
+ }
+ while (current++ < rtNumber)
+ fprintf(file, "\t\t{0, 0, 0, 0, 0, 0},\n");
+
+ fprintf(file, "\t}");
+}
+
+static void
+WriteArgDescriptorEntries(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ fprintf(file, ",\n\n\t{\n");
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ routine_t *rt = stat->stRoutine;
+
+ /* For each arg of the routine, write an arg descriptor:
+ */
+ WriteRPCRoutineArgDescriptor(file, rt);
+ }
+ fprintf(file, "\t},\n\n");
+}
+
+
+/*
+ * Write out the description of this subsystem, for use in direct RPC
+ */
+static void
+WriteSubsystem(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+ int descr_count = 0;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ routine_t *rt = stat->stRoutine;
+ descr_count += rtCountArgDescriptors(rt->rtArgs, (int *) 0);
+ }
+ fprintf(file, "\n");
+ if (ServerHeaderFileName == strNULL) {
+ WriteMigExternal(file);
+ fprintf(file, "boolean_t %s(", ServerDemux);
+ if (BeAnsiC) {
+ fprintf(file, "\n\t\tmach_msg_header_t *InHeadP,");
+ fprintf(file, "\n\t\tmach_msg_header_t *OutHeadP");
+ }
+ fprintf(file, ");\n\n");
+
+ WriteMigExternal(file);
+ fprintf(file, "mig_routine_t %s_routine(", ServerDemux);
+ if (BeAnsiC) {
+ fprintf(file, "\n\t\tmach_msg_header_t *InHeadP");
+ }
+ fprintf(file, ");\n\n");
+ }
+ fprintf(file, "\n/* Description of this subsystem, for use in direct RPC */\n");
+ if (ServerHeaderFileName == strNULL) {
+ fprintf(file, "const struct %s {\n", ServerSubsys);
+ if (UseRPCTrap) {
+ fprintf(file, "\tstruct subsystem *\tsubsystem;\t/* Reserved for system use */\n");
+ }
+ else {
+ fprintf(file, "\tmig_server_routine_t \tserver;\t/* Server routine */\n");
+ }
+ fprintf(file, "\tmach_msg_id_t\tstart;\t/* Min routine number */\n");
+ fprintf(file, "\tmach_msg_id_t\tend;\t/* Max routine number + 1 */\n");
+ fprintf(file, "\tunsigned int\tmaxsize;\t/* Max msg size */\n");
+ if (UseRPCTrap) {
+ fprintf(file, "\tvm_address_t\tbase_addr;\t/* Base address */\n");
+ fprintf(file, "\tstruct rpc_routine_descriptor\t/*Array of routine descriptors */\n");
+ }
+ else {
+ fprintf(file, "\tvm_address_t\treserved;\t/* Reserved */\n");
+ fprintf(file, "\tstruct routine_descriptor\t/*Array of routine descriptors */\n");
+ }
+ fprintf(file, "\t\troutine[%d];\n", rtNumber);
+ if (UseRPCTrap) {
+ fprintf(file, "\tstruct rpc_routine_arg_descriptor\t/*Array of arg descriptors */\n");
+ fprintf(file, "\t\targ_descriptor[%d];\n", descr_count);
+ }
+ fprintf(file, "} %s = {\n", ServerSubsys);
+ }
+ else {
+ fprintf(file, "const struct %s %s = {\n", ServerSubsys, ServerSubsys);
+ }
+ if (UseRPCTrap) {
+ fprintf(file, "\t0,\n");
+ }
+ else {
+ fprintf(file, "\t%s_routine,\n", ServerDemux);
+ }
+ fprintf(file, "\t%d,\n", SubsystemBase);
+ fprintf(file, "\t%d,\n", SubsystemBase + rtNumber);
+ fprintf(file, "\t(mach_msg_size_t)sizeof(union __ReplyUnion__%s),\n", ServerSubsys);
+ if (UseRPCTrap) {
+ fprintf(file, "\t(vm_address_t)&%s,\n", ServerSubsys);
+ }
+ else {
+ fprintf(file, "\t(vm_address_t)0,\n");
+ }
+ WriteRoutineEntries(file, stats);
+
+ if (UseRPCTrap)
+ WriteArgDescriptorEntries(file, stats);
+ else
+ fprintf(file, "\n");
+
+ fprintf(file, "};\n\n");
+}
+
+#if NOT_CURRENTLY_USED
+
+static void
+WriteArraySizes(FILE *file, statement_t *stats)
+{
+ u_int current = 0;
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ routine_t *rt = stat->stRoutine;
+
+ while (current++ < rt->rtNumber)
+ fprintf(file, "\t\t0,\n");
+ fprintf(file, "\t\t(mach_msg_size_t)sizeof(__Reply__%s_t),\n", rt->rtName);
+ }
+ while (current++ < rtNumber)
+ fprintf(file, "\t\t\t0,\n");
+}
+
+#endif /* NOT_CURRENTLY_USED */
+
+void
+WriteServerRequestUnion(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ fprintf(file, "\n");
+ fprintf(file, "/* union of all requests */\n\n");
+ fprintf(file, "#ifndef __RequestUnion__%s__defined\n", ServerSubsys);
+ fprintf(file, "#define __RequestUnion__%s__defined\n", ServerSubsys);
+ fprintf(file, "union __RequestUnion__%s {\n", ServerSubsys);
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind == skRoutine) {
+ routine_t *rt;
+
+ rt = stat->stRoutine;
+ fprintf(file, "\t__Request__%s_t Request_%s;\n", rt->rtName, rt->rtName);
+ }
+ }
+ fprintf(file, "};\n");
+ fprintf(file, "#endif /* __RequestUnion__%s__defined */\n", ServerSubsys);
+}
+
+void
+WriteServerReplyUnion(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ fprintf(file, "\n");
+ fprintf(file, "/* union of all replies */\n\n");
+ fprintf(file, "#ifndef __ReplyUnion__%s__defined\n", ServerSubsys);
+ fprintf(file, "#define __ReplyUnion__%s__defined\n", ServerSubsys);
+ fprintf(file, "union __ReplyUnion__%s {\n", ServerSubsys);
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind == skRoutine) {
+ routine_t *rt;
+
+ rt = stat->stRoutine;
+ fprintf(file, "\t__Reply__%s_t Reply_%s;\n", rt->rtName, rt->rtName);
+ }
+ }
+ fprintf(file, "};\n");
+ fprintf(file, "#endif /* __ReplyUnion__%s__defined */\n", ServerSubsys);
+}
+
+static void
+WriteDispatcher(FILE *file, statement_t *stats)
+{
+ /*
+ * Write the subsystem stuff.
+ */
+ fprintf(file, "\n");
+ WriteSubsystem(file, stats);
+
+ /*
+ * Then, the server routine
+ */
+ fprintf(file, "mig_external boolean_t %s\n", ServerDemux);
+ if (BeAnsiC) {
+ fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
+ fprintf(file, "#else\n");
+ fprintf(file, "\t(InHeadP, OutHeadP)\n");
+ fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+
+ fprintf(file, "{\n");
+ fprintf(file, "\t/*\n");
+ fprintf(file, "\t * typedef struct {\n");
+ fprintf(file, "\t * \tmach_msg_header_t Head;\n");
+ fprintf(file, "\t * \tNDR_record_t NDR;\n");
+ fprintf(file, "\t * \tkern_return_t RetCode;\n");
+ fprintf(file, "\t * } mig_reply_error_t;\n");
+ fprintf(file, "\t */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "\tmig_routine_t routine;\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "\tOutHeadP->msgh_bits = ");
+ fprintf(file, "MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);\n");
+ fprintf(file, "\tOutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;\n");
+ fprintf(file, "\t/* Minimal size: routine() will update it if different */\n");
+ fprintf(file, "\tOutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);\n");
+ fprintf(file, "\tOutHeadP->msgh_local_port = MACH_PORT_NULL;\n");
+ fprintf(file, "\tOutHeadP->msgh_id = InHeadP->msgh_id + 100;\n");
+ fprintf(file, "\tOutHeadP->msgh_reserved = 0;\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "\tif ((InHeadP->msgh_id > %d) || (InHeadP->msgh_id < %d) ||\n", SubsystemBase + rtNumber - 1, SubsystemBase);
+ fprintf(file, "\t ((routine = %s.routine[InHeadP->msgh_id - %d].stub_routine) == 0)) {\n", ServerSubsys, SubsystemBase);
+ fprintf(file, "\t\t((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;\n");
+ fprintf(file, "\t\t((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;\n");
+ if (UseEventLogger) {
+ fprintf(file, "#if MIG_DEBUG\n");
+ fprintf(file, "\t\tLOG_ERRORS(MACH_MSG_LOG_SERVER, MACH_MSG_ERROR_UNKNOWN_ID,\n");
+ fprintf(file, "\t\t\t&InHeadP->msgh_id, __FILE__, __LINE__);\n");
+ fprintf(file, "#endif /* MIG_DEBUG */\n");
+ }
+ fprintf(file, "\t\treturn FALSE;\n");
+ fprintf(file, "\t}\n");
+
+ /* Call appropriate routine */
+ fprintf(file, "\t(*routine) (InHeadP, OutHeadP);\n");
+ fprintf(file, "\treturn TRUE;\n");
+ fprintf(file, "}\n");
+ fprintf(file, "\n");
+
+ /*
+ * Then, the <subsystem>_server_routine routine
+ */
+ fprintf(file, "mig_external mig_routine_t %s_routine\n", ServerDemux);
+ if (BeAnsiC) {
+ fprintf(file, "\t(mach_msg_header_t *InHeadP)\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "\t(mach_msg_header_t *InHeadP)\n");
+ fprintf(file, "#else\n");
+ fprintf(file, "\t(InHeadP)\n");
+ fprintf(file, "\tmach_msg_header_t *InHeadP;\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+
+ fprintf(file, "{\n");
+ fprintf(file, "\tint msgh_id;\n");
+ fprintf(file, "\n");
+ fprintf(file, "\tmsgh_id = InHeadP->msgh_id - %d;\n", SubsystemBase);
+ fprintf(file, "\n");
+ fprintf(file, "\tif ((msgh_id > %d) || (msgh_id < 0))\n", rtNumber - 1);
+ fprintf(file, "\t\treturn 0;\n");
+ fprintf(file, "\n");
+ fprintf(file, "\treturn %s.routine[msgh_id].stub_routine;\n", ServerSubsys);
+ fprintf(file, "}\n");
+
+ /* symtab */
+
+ if (GenSymTab) {
+ fprintf(file,"\nmig_symtab_t _%sSymTab[] = {\n",SubsystemName);
+ WriteSymTabEntries(file,stats);
+ fprintf(file,"};\n");
+ fprintf(file,"int _%sSymTabBase = %d;\n",SubsystemName,SubsystemBase);
+ fprintf(file,"int _%sSymTabEnd = %d;\n",SubsystemName,SubsystemBase+rtNumber);
+ }
+}
+
+#if NOT_CURRENTLY_USED
+/*
+ * Returns the return type of the server-side work function.
+ * Suitable for "extern %s serverfunc()".
+ */
+static char *
+ServerSideType(routine_t *rt)
+{
+ return rt->rtRetCode->argType->itTransType;
+}
+#endif /* NOT_CURRENTLY_USED */
+
+static void
+WriteRetCode(FILE *file, argument_t *ret)
+{
+ ipc_type_t *it = ret->argType;
+
+ if (akCheck(ret->argKind, akbVarNeeded)) {
+ fprintf(file, "\t%s %s;\n", it->itTransType, ret->argVarName);
+ }
+}
+
+static void
+WriteLocalVarDecl(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ ipc_type_t *btype = it->itElement;
+
+ if (IS_VARIABLE_SIZED_UNTYPED(it))
+ fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, btype->itNumber ? it->itNumber/btype->itNumber : 0);
+ else if (IS_MULTIPLE_KPD(it)) {
+ if (btype->itTransType != strNULL)
+ fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, it->itKPD_Number);
+ else
+ /* arrays of ool or oolport */
+ fprintf(file, "\tvoid *%s[%d]", arg->argVarName, it->itKPD_Number);
+ }
+ else
+ fprintf(file, "\t%s %s", it->itTransType, arg->argVarName);
+}
+
+#if NOT_CURRENTLY_USED
+static void
+WriteServerArgDecl(FILE *file, argument_t *arg)
+{
+ fprintf(file, "%s %s%s", arg->argType->itTransType, arg->argByReferenceServer ? "*" : "", arg->argVarName);
+}
+#endif /* NOT_CURRENTLY_USED */
+
+/*
+ * Writes the local variable declarations which are always
+ * present: InP, OutP, the server-side work function.
+ */
+static void
+WriteVarDecls(FILE *file, routine_t *rt)
+{
+ int i;
+
+ fprintf(file, "\tRequest *In0P = (Request *) InHeadP;\n");
+ for (i = 1; i <= rt->rtMaxRequestPos; i++)
+ fprintf(file, "\tRequest *In%dP;\n", i);
+ fprintf(file, "\tReply *OutP = (Reply *) OutHeadP;\n");
+
+ /* if reply is variable, we may need msgh_size_delta and msgh_size */
+ if (rt->rtNumReplyVar > 1)
+ fprintf(file, "\tunsigned int msgh_size;\n");
+ if (rt->rtMaxReplyPos > 0)
+ fprintf(file, "\tunsigned int msgh_size_delta;\n");
+ if (rt->rtNumReplyVar > 1 || rt->rtMaxReplyPos > 0)
+ fprintf(file, "\n");
+
+ if (rt->rtServerImpl) {
+ fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n");
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tunsigned int trailer_size __attribute__((unused));\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ fprintf(file, "#ifdef\t__MIG_check__Request__%s_t__defined\n", rt->rtName);
+ fprintf(file, "\tkern_return_t check_result;\n");
+ fprintf(file, "#endif\t/* __MIG_check__Request__%s_t__defined */\n", rt->rtName);
+ fprintf(file, "\n");
+}
+
+static void
+WriteReplyInit(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\n");
+ if (rt->rtNumReplyVar > 1 || rt->rtMaxReplyPos)
+ /* WritheAdjustMsgSize() has been executed at least once! */
+ fprintf(file, "\tOutP = (Reply *) OutHeadP;\n");
+
+ if (!rt->rtSimpleReply) /* complex reply message */
+ fprintf(file, "\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
+
+ if (rt->rtNumReplyVar == 0) {
+ fprintf(file, "\tOutP->Head.msgh_size = ");
+ rtMinReplySize(file, rt, "Reply");
+ fprintf(file, ";\n");
+ }
+ else if (rt->rtNumReplyVar > 1)
+ fprintf(file, "\tOutP->Head.msgh_size = msgh_size;\n");
+ /* the case rt->rtNumReplyVar = 1 is taken care of in WriteAdjustMsgSize() */
+}
+
+static void
+WriteRetCArgCheckError(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\tif (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&\n");
+ fprintf(file, "\t (In0P->Head.msgh_size == (mach_msg_size_t)sizeof(mig_reply_error_t)))\n");
+ fprintf(file, "\t{\n");
+}
+
+static void
+WriteRetCArgFinishError(FILE *file, routine_t *rt)
+{
+ argument_t *retcode = rt->rtRetCArg;
+
+ fprintf(file, "\treturn;\n");
+ fprintf(file, "\t}\n");
+ retcode->argMsgField = "KERN_SUCCESS";
+}
+
+static void
+WriteCheckHead(FILE *file, routine_t *rt)
+{
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ if (rt->rtNumRequestVar > 0)
+ fprintf(file, "\tmsgh_size = In0P->Head.msgh_size;\n");
+
+ if (rt->rtSimpleRequest) {
+ /* Expecting a simple message. */
+ fprintf(file, "\tif ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
+ if (rt->rtNumRequestVar > 0) {
+ fprintf(file, "\t (msgh_size < ");
+ rtMinRequestSize(file, rt, "__Request");
+ fprintf(file, ") || (msgh_size > (mach_msg_size_t)sizeof(__Request)))\n");
+ }
+ else
+ fprintf(file, "\t (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request)))\n");
+ }
+ else {
+ /* Expecting a complex message. */
+
+ fprintf(file, "\tif (");
+ if (rt->rtRetCArg != argNULL)
+ fprintf(file, "(");
+ fprintf(file, "!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
+ fprintf(file, "\t (In0P->msgh_body.msgh_descriptor_count != %d) ||\n", rt->rtRequestKPDs);
+ if (rt->rtNumRequestVar > 0) {
+ fprintf(file, "\t (msgh_size < ");
+ rtMinRequestSize(file, rt, "__Request");
+ fprintf(file, ") || (msgh_size > (mach_msg_size_t)sizeof(__Request))");
+ }
+ else
+ fprintf(file, "\t (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request))");
+ if (rt->rtRetCArg == argNULL)
+ fprintf(file, ")\n");
+ else {
+ fprintf(file, ") &&\n");
+ fprintf(file, "\t ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
+ fprintf(file, "\t In0P->Head.msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n");
+ fprintf(file, "\t ((mig_reply_error_t *)In0P)->RetCode == KERN_SUCCESS))\n");
+ }
+ }
+ fprintf(file, "\t\treturn MIG_BAD_ARGUMENTS;\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ fprintf(file, "\n");
+}
+
+void
+WriteRequestNDRConvertIntRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ fprintf(file, "defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+}
+
+void
+WriteRequestNDRConvertCharRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
+ fprintf(file, "defined(__NDR_convert__char_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+ else
+ fprintf(file, "0");
+}
+
+void
+WriteRequestNDRConvertFloatRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
+ fprintf(file, "defined(__NDR_convert__float_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+ else
+ fprintf(file, "0");
+}
+
+void
+WriteRequestNDRConvertIntRepArgDecl(FILE *file, argument_t *arg)
+{
+ WriteNDRConvertArgDecl(file, arg, "int_rep", "Request");
+}
+
+void
+WriteRequestNDRConvertCharRepArgDecl(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
+ WriteNDRConvertArgDecl(file, arg, "char_rep", "Request");
+}
+
+void
+WriteRequestNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
+ WriteNDRConvertArgDecl(file, arg, "float_rep", "Request");
+}
+
+void
+WriteRequestNDRConvertArgUse(FILE *file, argument_t *arg, char *convert)
+{
+ routine_t *rt = arg->argRoutine;
+ argument_t *count = arg->argCount;
+ char argname[MAX_STR_LEN];
+
+ if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) &&
+ (arg->argParent && akCheck(arg->argParent->argKind, akbSendNdr)))
+ return;
+
+ if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+ if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) {
+ fprintf(file, "#if defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)\n", rt->rtName, count->argMsgField);
+ fprintf(file, "\t\t__NDR_convert__int_rep__Request__%s_t__%s(&In%dP->%s, In%dP->NDR.int_rep);\n", rt->rtName, count->argMsgField, count->argRequestPos, count->argMsgField, count->argRequestPos);
+ fprintf(file, "#endif\t/* __NDR_convert__int_rep__Request__%s_t__%s__defined */\n", rt->rtName, count->argMsgField);
+ }
+
+ sprintf(argname, "(%s)(In%dP->%s.address)", FetchServerType(arg->argType), arg->argRequestPos, arg->argMsgField);
+ }
+ else {
+ sprintf(argname, "&In%dP->%s", arg->argRequestPos, arg->argMsgField);
+ }
+
+ fprintf(file, "#if defined(__NDR_convert__%s__Request__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField);
+ fprintf(file, "\t\t__NDR_convert__%s__Request__%s_t__%s(%s, In0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert);
+ if (count)
+ fprintf(file, ", In%dP->%s", count->argRequestPos, count->argMsgField);
+ fprintf(file, ");\n");
+ fprintf(file, "#endif\t/* __NDR_convert__%s__Request__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField);
+}
+
+void
+WriteRequestNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ fprintf(file, "#if defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField);
+ fprintf(file, "\tif (In0P->NDR.int_rep != NDR_record.int_rep)\n");
+ fprintf(file, "\t\t__NDR_convert__int_rep__Request__%s_t__%s(&In%dP->%s, In%dP->NDR.int_rep);\n", rt->rtName, arg->argMsgField, arg->argRequestPos, arg->argMsgField, arg->argRequestPos);
+ fprintf(file, "#endif\t/* __NDR_convert__int_rep__Request__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField);
+}
+
+void
+WriteRequestNDRConvertIntRepArgUse(FILE *file, argument_t *arg)
+{
+ WriteRequestNDRConvertArgUse(file, arg, "int_rep");
+}
+
+void
+WriteRequestNDRConvertCharRepArgUse(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
+ WriteRequestNDRConvertArgUse(file, arg, "char_rep");
+}
+
+void
+WriteRequestNDRConvertFloatRepArgUse(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
+ WriteRequestNDRConvertArgUse(file, arg, "float_rep");
+}
+
+static void
+WriteCalcArgSize(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+
+ if (PackMsg == FALSE) {
+ fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
+ return;
+ }
+
+ if (IS_OPTIONAL_NATIVE(ptype))
+ fprintf(file, "(In%dP->__Present__%s ? _WALIGNSZ_(%s) : 0)" , arg->argRequestPos, arg->argMsgField, ptype->itServerType);
+ else {
+ ipc_type_t *btype = ptype->itElement;
+ argument_t *count = arg->argCount;
+ int multiplier = btype->itTypeSize;
+
+ if (btype->itTypeSize % itWordAlign != 0)
+ fprintf(file, "_WALIGN_");
+ fprintf(file, "(");
+
+ if (multiplier > 1)
+ fprintf(file, "%d * ", multiplier);
+ fprintf(file, "In%dP->%s", count->argRequestPos, count->argMsgField);
+ fprintf(file, ")");
+ }
+}
+
+static void
+WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator)
+{
+ ipc_type_t *ptype = arg->argType;
+
+
+ fprintf(file, "\tif (((msgh_size - ");
+ rtMinRequestSize(file, rt, "__Request");
+ fprintf(file, ") ");
+ if (PackMsg == FALSE) {
+ fprintf(file, "%s %d)", comparator, ptype->itTypeSize + ptype->itPadSize);
+ } else if (IS_OPTIONAL_NATIVE(ptype)) {
+ fprintf(file, "%s (In%dP->__Present__%s ? _WALIGNSZ_(%s) : 0))" , comparator, arg->argRequestPos, arg->argMsgField, ptype->itServerType);
+ } else {
+ ipc_type_t *btype = ptype->itElement;
+ argument_t *count = arg->argCount;
+ int multiplier = btype->itTypeSize;
+
+ if (multiplier > 1)
+ fprintf(file, "/ %d ", multiplier);
+ fprintf(file, "< In%dP->%s) ||\n", count->argRequestPos, count->argMsgField);
+ fprintf(file, "\t (msgh_size %s ", comparator);
+ rtMinRequestSize(file, rt, "__Request");
+ fprintf(file, " + ");
+ WriteCalcArgSize(file, arg);
+ fprintf(file, ")");
+ }
+ fprintf(file, ")\n\t\treturn MIG_BAD_ARGUMENTS;\n");
+}
+
+static void
+WriteCheckMsgSize(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ if (arg->argCount && !arg->argSameCount)
+ WriteRequestNDRConvertIntRepOneArgUse(file, arg->argCount);
+ if (arg->argRequestPos == rt->rtMaxRequestPos) {
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ /* verify that the user-code-provided count does not exceed the maximum count allowed by the type. */
+ fprintf(file, "\t" "if ( In%dP->%s > %d )\n", arg->argCount->argRequestPos, arg->argCount->argMsgField, arg->argType->itNumber);
+ fputs("\t\t" "return MIG_BAD_ARGUMENTS;\n", file);
+ /* ...end... */
+
+ WriteCheckArgSize(file, rt, arg, "!=");
+
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ else {
+ /* If there aren't any more variable-sized arguments after this,
+ then we must check for exact msg-size and we don't need to
+ update msgh_size. */
+
+ boolean_t LastVarArg = arg->argRequestPos+1 == rt->rtNumRequestVar;
+
+ /* calculate the actual size in bytes of the data field. note
+ that this quantity must be a multiple of four. hence, if
+ the base type size isn't a multiple of four, we have to
+ round up. note also that btype->itNumber must
+ divide btype->itTypeSize (see itCalculateSizeInfo). */
+
+ fprintf(file, "\tmsgh_size_delta = ");
+ WriteCalcArgSize(file, arg);
+ fprintf(file, ";\n");
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ /* verify that the user-code-provided count does not exceed the maximum count allowed by the type. */
+ fprintf(file, "\t" "if ( In%dP->%s > %d )\n", arg->argCount->argRequestPos, arg->argCount->argMsgField, arg->argType->itNumber);
+ fputs("\t\t" "return MIG_BAD_ARGUMENTS;\n", file);
+ /* ...end... */
+
+ /* Don't decrement msgh_size until we've checked that
+ it won't underflow. */
+ WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<");
+
+ if (!LastVarArg)
+ fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
+
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ fprintf(file, "\n");
+}
+
+static char *
+InArgMsgField(argument_t *arg, char *str)
+{
+ static char buffer[MAX_STR_LEN];
+ char who[20] = {0};
+
+ /*
+ * Inside the kernel, the request and reply port fields
+ * really hold ipc_port_t values, not mach_port_t values.
+ * Hence we must cast the values.
+ */
+
+ if (!(arg->argFlags & flRetCode)) {
+ if (akCheck(arg->argKind, akbServerImplicit))
+ sprintf(who, "TrailerP->");
+ else
+ sprintf(who, "In%dP->", arg->argRequestPos);
+ }
+
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelServer &&
+ ((akIdent(arg->argKind) == akeRequestPort) ||
+ (akIdent(arg->argKind) == akeReplyPort)))
+ sprintf(buffer, "(ipc_port_t) %s%s%s", who, str, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
+ else
+#endif
+ sprintf(buffer, "%s%s%s", who, str, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
+
+ return buffer;
+}
+
+static void
+WriteExtractArgValue(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ string_t recast;
+
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelServer && it->itPortType && streql(it->itServerType, "ipc_port_t")
+ && akIdent(arg->argKind) != akeRequestPort
+ && akIdent(arg->argKind) != akeReplyPort)
+ recast = "(mach_port_t)";
+ else
+#endif
+ recast = "";
+ if (it->itInTrans != strNULL)
+ WriteCopyType(file, it, FALSE, "%s", "/* %s */ %s(%s%s)", arg->argVarName, it->itInTrans, recast, InArgMsgField(arg, ""));
+ else
+ WriteCopyType(file, it, FALSE, "%s", "/* %s */ %s%s", arg->argVarName, recast, InArgMsgField(arg, ""));
+
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_Extract discipline for Port types.
+ */
+static void
+WriteExtractKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *recast = "";
+
+ WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
+ /* translation function do not apply to complex types */
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelServer)
+ recast = "(mach_port_t)";
+#endif
+ fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast);
+ fprintf(file, "\t}\n");
+}
+
+/*
+ * argKPD_Extract discipline for out-of-line types.
+ */
+static void
+WriteExtractKPD_ool(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
+ fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
+ fprintf(file, "\t}\n");
+}
+
+/*
+ * argKPD_Extract discipline for out-of-line Port types.
+ */
+static void
+WriteExtractKPD_oolport(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
+ fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
+ fprintf(file, "\t}\n");
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendRcv)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceServer ? "*" : "";
+
+ fprintf(file, "\t%s%s = In%dP->%s[0].disposition;\n", pref, poly->argVarName, arg->argRequestPos, arg->argMsgField);
+ }
+}
+
+
+static void
+WriteInitializeCount(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argParent->argType;
+ ipc_type_t *btype = ptype->itElement;
+ identifier_t newstr;
+
+ /*
+ * Initialize 'count' argument for variable-length inline OUT parameter
+ * with maximum allowed number of elements.
+ */
+
+ if (akCheck(arg->argKind, akbVarNeeded))
+ newstr = arg->argMsgField;
+ else
+ newstr = (identifier_t)strconcat("OutP->", arg->argMsgField);
+
+ fprintf(file, "\t%s = ", newstr);
+ if (IS_MULTIPLE_KPD(ptype))
+ fprintf(file, "%d;\n", ptype->itKPD_Number);
+ else
+ fprintf(file, "%d;\n", btype->itNumber? ptype->itNumber/btype->itNumber : 0);
+
+ /*
+ * If the user passed in a count, then we use the minimum.
+ * We can't let the user completely override our maximum,
+ * or the user might convince the server to overwrite the buffer.
+ */
+
+ if (arg->argCInOut != argNULL) {
+ char *msgfield = InArgMsgField(arg->argCInOut, "");
+
+ fprintf(file, "\tif (%s < %s)\n", msgfield, newstr);
+ fprintf(file, "\t\t%s = %s;\n", newstr, msgfield);
+ }
+
+ fprintf(file, "\n");
+}
+
+static void
+WriteAdjustRequestMsgPtr(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+
+ if (PackMsg == FALSE) {
+ fprintf(file, "\t*In%dPP = In%dP = (__Request *) ((pointer_t) In%dP);\n\n", arg->argRequestPos+1, arg->argRequestPos+1, arg->argRequestPos);
+ return;
+ }
+
+ fprintf(file, "\t*In%dPP = In%dP = (__Request *) ((pointer_t) In%dP + msgh_size_delta - ", arg->argRequestPos+1, arg->argRequestPos+1, arg->argRequestPos);
+ if (IS_OPTIONAL_NATIVE(ptype))
+ fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType);
+ else
+ fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
+ fprintf(file, ");\n\n");
+}
+
+static void
+WriteCheckRequestTrailerArgs(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+
+ if (rt->rtServerImpl)
+ WriteCheckTrailerHead(file, rt, FALSE);
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akCheck(arg->argKind, akbServerImplicit))
+ WriteCheckTrailerSize(file, FALSE, arg);
+ }
+}
+
+static void
+WriteExtractArg(FILE *file, argument_t *arg)
+{
+ if (akCheckAll(arg->argKind, akbSendRcv|akbVarNeeded)) {
+ if (akCheck(arg->argKind, akbSendKPD))
+ (*arg->argKPD_Extract)(file, arg);
+ else
+ WriteExtractArgValue(file, arg);
+ }
+
+ if ((akIdent(arg->argKind) == akeCount) &&
+ akCheck(arg->argKind, akbReturnSnd)) {
+
+ ipc_type_t *ptype = arg->argParent->argType;
+ /*
+ * the count will be initialized to 0 in the case of
+ * unbounded arrays (MigInLine = TRUE): this is because
+ * the old interface used to pass to the target procedure
+ * the maximum in-line size (it was 2048 bytes)
+ */
+ if (IS_VARIABLE_SIZED_UNTYPED(ptype) ||
+ IS_MIG_INLINE_EMUL(ptype) ||
+ (IS_MULTIPLE_KPD(ptype) && ptype->itVarArray))
+ WriteInitializeCount(file, arg);
+ }
+}
+
+static void
+WriteServerCallArg(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ boolean_t NeedClose = FALSE;
+ u_int elemsize = 0;
+ string_t at = (arg->argByReferenceServer ||
+ it->itNativePointer) ? "&" : "";
+ string_t star = (arg->argByReferenceServer) ? " *" : "";
+ string_t msgfield =
+ (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField;
+
+ if ((it->itInTrans != strNULL) &&
+ akCheck(arg->argKind, akbSendRcv) &&
+ !akCheck(arg->argKind, akbVarNeeded)) {
+ fprintf(file, "%s%s(", at, it->itInTrans);
+ NeedClose = TRUE;
+ }
+
+ if (akCheckAll(arg->argKind, akbVarNeeded|akbServerArg))
+ fprintf(file, "%s%s", at, arg->argVarName);
+ else if (akCheckAll(arg->argKind, akbSendRcv|akbSendKPD)) {
+ if (!it->itInLine)
+ /* recast the void *, although it is not necessary */
+ fprintf(file, "(%s%s)%s(%s)", it->itTransType, star, at, InArgMsgField(arg, ""));
+ else
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelServer && streql(it->itServerType, "ipc_port_t"))
+ /* recast the port to the kernel internal form value */
+ fprintf(file, "(ipc_port_t%s)%s(%s)", star, at, InArgMsgField(arg, ""));
+ else
+#endif
+ fprintf(file, "%s%s", at, InArgMsgField(arg, ""));
+ }
+ else if (akCheck(arg->argKind, akbSendRcv)) {
+ if (IS_OPTIONAL_NATIVE(it)) {
+ fprintf(file, "(%s ? ", InArgMsgField(arg, "__Present__"));
+ fprintf(file, "%s%s.__Real__%s : %s)", at, InArgMsgField(arg, ""), arg->argMsgField, it->itBadValue);
+ }
+ else {
+ if (akIdent(arg->argKind) == akeCount && arg->argParent) {
+ char *suffix = arg->argParent->argSuffix;
+ ipc_type_t *elemType = arg->argParent->argType->itElement;
+ /* temporarily squash any name suffix such as ".address" (we'll be adding our own) */
+ arg->argParent->argSuffix = NULL;
+ switch (arg->argParent->argKPD_Type) {
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ /* count of the number of descriptors */
+ fprintf(file, "%s%s.count", at, InArgMsgField(arg->argParent, ""));
+ break;
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* descriptor buffer size / element size */
+ if (!(arg->argByReferenceServer || it->itNativePointer)) {
+ fprintf(file, "%s%s.size", at, InArgMsgField(arg->argParent, ""));
+ elemsize = ((elemType->itNumber * elemType->itSize) + 7) / 8;
+ if (elemsize > 1) {
+ fprintf(file, " / %d", elemsize);
+ }
+ } else {
+ fprintf(file, "%s%s", at, InArgMsgField(arg, ""));
+ }
+ break;
+ default:
+ fprintf(file, "%s%s", at, InArgMsgField(arg, ""));
+ break;
+ }
+ arg->argParent->argSuffix = suffix;
+ } else {
+ fprintf(file, "%s%s", at, InArgMsgField(arg, ""));
+ }
+ }
+ }
+ else if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnKPD)) {
+ if (!it->itInLine)
+ /* recast the void *, although it is not necessary */
+ fprintf(file, "(%s%s)%s(OutP->%s)", it->itTransType, star, at, msgfield);
+ else
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelServer && streql(it->itServerType, "ipc_port_t"))
+ /* recast the port to the kernel internal form value */
+ fprintf(file, "(mach_port_t%s)%s(OutP->%s)", star, at, msgfield);
+ else
+#endif
+ fprintf(file, "%sOutP->%s", at, msgfield);
+
+ }
+ else if (akCheck(arg->argKind, akbReturnSnd))
+ fprintf(file, "%sOutP->%s", at, msgfield);
+
+ if (NeedClose)
+ fprintf(file, ")");
+}
+
+/*
+ * Shrunk version of WriteServerCallArg, to implement the RetCode functionality:
+ * we have received a mig_reply_error_t, therefore we want to call the target
+ * routine with all 0s except for the error code (and the implicit data).
+ * We know that we are a SimpleRoutine.
+ */
+static void
+WriteConditionalCallArg(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ boolean_t NeedClose = FALSE;
+
+ if ((it->itInTrans != strNULL) &&
+ akCheck(arg->argKind, akbSendRcv) &&
+ !akCheck(arg->argKind, akbVarNeeded)) {
+ fprintf(file, "%s(", it->itInTrans);
+ NeedClose = TRUE;
+ }
+
+ if (akCheck(arg->argKind, akbSendRcv)) {
+ if (akIdent(arg->argKind) == akeRequestPort ||
+ akCheck(arg->argKind, akbServerImplicit))
+ fprintf(file, "%s", InArgMsgField(arg, ""));
+ else if (akIdent(arg->argKind) == akeRetCode)
+ fprintf(file, "((mig_reply_error_t *)In0P)->RetCode");
+ else
+ fprintf(file, "(%s)(0)", it->itTransType);
+ }
+
+ if (NeedClose)
+ fprintf(file, ")");
+}
+
+static void
+WriteDestroyArg(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ /*
+ * Deallocate IN/INOUT out-of-line args if specified by "auto" flag.
+ *
+ * We also have to deallocate in the cases where the target routine
+ * is given a itInLine semantic whereas the underlying transmission
+ * was out-of-line
+ */
+ if ((argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
+ arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR &&
+ (arg->argFlags & flAuto))
+ ||
+ IS_MIG_INLINE_EMUL(it)
+ ) {
+ /*
+ * Deallocate only if out-of-line.
+ */
+ argument_t *count = arg->argCount;
+ ipc_type_t *btype = it->itElement;
+ int multiplier = btype->itNumber ? btype->itSize / (8 * btype->itNumber) : 0;
+
+ if (IsKernelServer) {
+ fprintf(file, "#if __MigKernelSpecificCode\n");
+ fprintf(file, "\tvm_map_copy_discard(%s);\n", InArgMsgField(arg, ""));
+ fprintf(file, "#else\n");
+ }
+ fprintf(file, "\tmig_deallocate((vm_offset_t) %s, ", InArgMsgField(arg, ""));
+ if (it->itVarArray) {
+ char *suffix = arg->argSuffix;
+ /*
+ * temporarily squash any name suffix such as ".address"
+ * (we'll be adding our own)
+ */
+ arg->argSuffix = NULL;
+ switch (arg->argKPD_Type) {
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ if (multiplier > 1) {
+ fprintf(file, "%d * ", multiplier);
+ }
+ fprintf(file, "%s.count);\n", InArgMsgField(arg, ""));
+ break;
+ case MACH_MSG_OOL_DESCRIPTOR:
+ fprintf(file, "%s.size);\n", InArgMsgField(arg, ""));
+ break;
+ default:
+ if (multiplier > 1) {
+ fprintf(file, "%d * ", multiplier);
+ }
+ fprintf(file, "%s);\n", InArgMsgField(count, ""));
+ break;
+ }
+ arg->argSuffix = suffix;
+ }
+ else
+ fprintf(file, "%d);\n", (it->itNumber * it->itSize + 7) / 8);
+ if (IsKernelServer) {
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+ }
+ fprintf(file, "\t%s = (void *) 0;\n", InArgMsgField(arg, ""));
+ fprintf(file, "\tIn%dP->%s.%s = (mach_msg_size_t) 0;\n", arg->argRequestPos, arg->argMsgField, (RPCPortArray(arg) ? "count" : "size"));
+ }
+ else {
+ if (akCheck(arg->argKind, akbVarNeeded))
+ fprintf(file, "\t%s(%s);\n", it->itDestructor, arg->argVarName);
+ else
+ fprintf(file, "\t%s(%s);\n", it->itDestructor, InArgMsgField(arg, ""));
+ }
+}
+
+static void
+WriteDestroyPortArg(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ /*
+ * If a translated port argument occurs in the body of a request
+ * message, and the message is successfully processed, then the
+ * port right should be deallocated. However, the called function
+ * didn't see the port right; it saw the translation. So we have
+ * to release the port right for it.
+ *
+ * The test over it->itInTrans will exclude any complex type
+ * made out of ports
+ */
+ if ((it->itInTrans != strNULL) &&
+ (it->itOutName == MACH_MSG_TYPE_PORT_SEND)) {
+ fprintf(file, "\n");
+ fprintf(file, "\tif (IP_VALID((ipc_port_t)%s))\n", InArgMsgField(arg, ""));
+ fprintf(file, "\t\tipc_port_release_send((ipc_port_t)%s);\n", InArgMsgField(arg, ""));
+ }
+}
+
+/*
+ * Check whether WriteDestroyPortArg would generate any code for arg.
+ */
+boolean_t
+CheckDestroyPortArg(argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ if ((it->itInTrans != strNULL) &&
+ (it->itOutName == MACH_MSG_TYPE_PORT_SEND)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+WriteServerCall(FILE *file, routine_t *rt, void (*func)(FILE *, argument_t *))
+{
+ argument_t *arg = rt->rtRetCode;
+ ipc_type_t *it = arg->argType;
+ boolean_t NeedClose = FALSE;
+
+ fprintf(file, "\t");
+ if (akCheck(arg->argKind, akbVarNeeded))
+ fprintf(file, "%s = ", arg->argMsgField);
+ else
+ fprintf(file, "OutP->%s = ", arg->argMsgField);
+ if (it->itOutTrans != strNULL) {
+ fprintf(file, "%s(", it->itOutTrans);
+ NeedClose = TRUE;
+ }
+ fprintf(file, "%s(", rt->rtServerName);
+ WriteList(file, rt->rtArgs, func, akbServerArg, ", ", "");
+ if (NeedClose)
+ fprintf(file, ")");
+ fprintf(file, ");\n");
+}
+
+static void
+WriteCheckReturnValue(FILE *file, routine_t *rt)
+{
+ argument_t *arg = rt->rtRetCode;
+ char string[MAX_STR_LEN];
+
+ if (akCheck(arg->argKind, akbVarNeeded))
+ sprintf(string, "%s", arg->argMsgField);
+ else
+ sprintf(string, "OutP->%s", arg->argMsgField);
+ fprintf(file, "\tif (%s != KERN_SUCCESS) {\n", string);
+ fprintf(file, "\t\tMIG_RETURN_ERROR(OutP, %s);\n", string);
+ fprintf(file, "\t}\n");
+}
+
+/*
+ * WriteInitKPD_port, WriteInitKPD_ool, WriteInitKPD_oolport
+ * initializes the OutP KPD fields (this job cannot be done once
+ * the target routine has been called, otherwise informations
+ * would be lost)
+ */
+/*
+ * argKPD_Init discipline for Port types.
+ */
+static void
+WriteInitKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *subindex = "";
+ boolean_t close = FALSE;
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ subindex = "[i]";
+ close = TRUE;
+ }
+ else {
+ (void)sprintf(firststring, "OutP->%s", arg->argMsgField);
+ (void)sprintf(string, "OutP->%s.", arg->argMsgField);
+ }
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ if (IS_MULTIPLE_KPD(it) && it->itVarArray)
+ fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string);
+ if (arg->argPoly == argNULL) {
+ if (IsKernelServer) {
+ fprintf(file, "#if __MigKernelSpecificCode\n");
+ fprintf(file, "\t%sdisposition = %s;\n", string, it->itOutNameStr);
+ fprintf(file, "#else\n");
+ }
+ fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr);
+ if (IsKernelServer)
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+ }
+ fprintf(file, "#if !(defined(KERNEL) && defined(__LP64__))\n");
+ fprintf(file, "\t%spad1 = 0;\n", string);
+ fprintf(file, "#endif\n");
+ fprintf(file, "\t%spad2 = 0;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
+ fprintf(file, "#if defined(KERNEL)\n");
+ fprintf(file, "\t%spad_end = 0;\n", string);
+ fprintf(file, "#endif\n");
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ if (close)
+ fprintf(file, "\t }\n\t}\n");
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_Init discipline for out-of-line types.
+ */
+static void
+WriteInitKPD_ool(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+ boolean_t VarArray;
+ u_int howmany, howbig;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ VarArray = it->itElement->itVarArray;
+ howmany = it->itElement->itNumber;
+ howbig = it->itElement->itSize;
+ }
+ else {
+ (void)sprintf(firststring, "OutP->%s", arg->argMsgField);
+ (void)sprintf(string, "OutP->%s.", arg->argMsgField);
+ VarArray = it->itVarArray;
+ howmany = it->itNumber;
+ howbig = it->itSize;
+ }
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ if (!VarArray)
+ fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8);
+ if (arg->argDeallocate != d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
+ fprintf(file, "\t%scopy = %s;\n", string, (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY");
+#ifdef ALIGNMENT
+ fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, arg->argMsgField, (howbig < 8) ? 1 : howbig / 8);
+#endif
+ fprintf(file, "\t%spad1 = 0;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
+ fprintf(file, "#if defined(KERNEL) && !defined(__LP64__)\n");
+ fprintf(file, "\t%spad_end = 0;\n", string);
+ fprintf(file, "#endif\n");
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n\t}\n");
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_Init discipline for out-of-line Port types.
+ */
+static void
+WriteInitKPD_oolport(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ boolean_t VarArray;
+ ipc_type_t *howit;
+ u_int howmany;
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ VarArray = it->itElement->itVarArray;
+ howmany = it->itElement->itNumber;
+ howit = it->itElement;
+ }
+ else {
+ (void)sprintf(firststring, "OutP->%s", arg->argMsgField);
+ (void)sprintf(string, "OutP->%s.", arg->argMsgField);
+ VarArray = it->itVarArray;
+ howmany = it->itNumber;
+ howit = it;
+ }
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+
+ if (!VarArray)
+ fprintf(file, "\t%scount = %d;\n", string, howmany);
+ if (arg->argPoly == argNULL) {
+ if (IsKernelServer) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "\t%sdisposition = %s;\n", string, howit->itOutNameStr);
+ fprintf(file, "#else\n");
+ }
+ fprintf(file, "\t%sdisposition = %s;\n", string, howit->itInNameStr);
+ if (IsKernelServer)
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+ }
+ if (arg->argDeallocate != d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
+ fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n\t}\n");
+ fprintf(file, "\n");
+}
+
+static void
+WriteInitKPDValue(FILE *file, argument_t *arg)
+{
+ (*arg->argKPD_Init)(file, arg);
+}
+
+static void
+WriteAdjustMsgCircular(FILE *file, argument_t *arg)
+{
+ fprintf(file, "\n");
+
+ fprintf(file,"#if\t__MigKernelSpecificCode\n");
+ if (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
+ fprintf(file, "\tif (%s == MACH_MSG_TYPE_PORT_RECEIVE)\n", arg->argPoly->argVarName);
+
+ /*
+ * The carried port right can be accessed in OutP->XXXX. Normally
+ * the server function stuffs it directly there. If it is InOut,
+ * then it has already been copied into the reply message.
+ * If the server function deposited it into a variable (perhaps
+ * because the reply message is variable-sized) then it has already
+ * been copied into the reply message.
+ *
+ * The old MiG does not check for circularity in the case of
+ * array of ports. So do I ...
+ */
+
+ fprintf(file, "\t if (IP_VALID((ipc_port_t) In0P->Head.msgh_reply_port) &&\n");
+ fprintf(file, "\t IP_VALID((ipc_port_t) OutP->%s.name) &&\n", arg->argMsgField);
+ fprintf(file, "\t ipc_port_check_circularity((ipc_port_t) OutP->%s.name, (ipc_port_t) In0P->Head.msgh_reply_port))\n", arg->argMsgField);
+ fprintf(file, "\t\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;\n");
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+}
+
+/*
+ * argKPD_Pack discipline for Port types.
+ */
+static void
+WriteKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *subindex = "";
+ char *recast = "";
+ boolean_t close = FALSE;
+ char string[MAX_STR_LEN];
+ ipc_type_t *real_it;
+
+ if (akCheck(arg->argKind, akbVarNeeded)) {
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(string, "\tptr->");
+ subindex = "[i]";
+ close = TRUE;
+ real_it = it->itElement;
+ }
+ else {
+ (void)sprintf(string, "OutP->%s.", arg->argMsgField);
+ real_it = it;
+ }
+#ifdef MIG_KERNEL_PORT_CONVERSIONS
+ if (IsKernelServer && streql(real_it->itTransType, "ipc_port_t"))
+ recast = "(mach_port_t)";
+#endif
+
+ if (it->itOutTrans != strNULL && !close)
+ fprintf(file, "\t%sname = (mach_port_t)%s(%s);\n", string, it->itOutTrans, arg->argVarName);
+ else
+ fprintf(file, "\t%sname = %s%s%s;\n", string, recast, arg->argVarName, subindex);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd)) {
+ argument_t *poly = arg->argPoly;
+
+ if (akCheck(arg->argPoly->argKind, akbVarNeeded))
+ fprintf(file, "\t%sdisposition = %s;\n", string, poly->argVarName);
+ else if (close)
+ fprintf(file, "\t%sdisposition = OutP->%s;\n", string, poly->argSuffix);
+ }
+ if (close)
+ fprintf(file, "\t }\n\t}\n");
+ fprintf(file, "\n");
+ }
+ else if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd|akbVarNeeded))
+ fprintf(file, "\tOutP->%s.disposition = %s;\n", arg->argMsgField, arg->argPoly->argVarName);
+ /*
+ * If this is a KernelServer, and the reply message contains
+ * a receive right, we must check for the possibility of a
+ * port/message circularity. If queueing the reply message
+ * would cause a circularity, we mark the reply message
+ * with the circular bit.
+ */
+ if (IsKernelServer && !(IS_MULTIPLE_KPD(it)) &&
+ ((arg->argType->itOutName == MACH_MSG_TYPE_PORT_RECEIVE) ||
+ (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)))
+ WriteAdjustMsgCircular(file, arg);
+}
+
+/*
+ * argKPD_Pack discipline for out-of-line types.
+ */
+static void
+WriteKPD_ool(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char string[MAX_STR_LEN];
+ boolean_t VarArray;
+ argument_t *count;
+ u_int howbig;
+ char *subindex;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(string, "\tptr->");
+ VarArray = it->itElement->itVarArray;
+ count = arg->argSubCount;
+ howbig = it->itElement->itSize;
+ subindex = "[i]";
+ }
+ else {
+ (void)sprintf(string, "OutP->%s.", arg->argMsgField);
+ VarArray = it->itVarArray;
+ count = arg->argCount;
+ howbig = it->itSize;
+ subindex = "";
+ }
+
+ if (akCheck(arg->argKind, akbVarNeeded))
+ fprintf(file, "\t%saddress = (void *)%s%s;\n", string, arg->argMsgField, subindex);
+ if (arg->argDealloc != argNULL)
+ if (akCheck(arg->argDealloc->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+ if (VarArray) {
+ fprintf(file, "\t%ssize = ", string);
+ if (akCheck(count->argKind, akbVarNeeded))
+ fprintf(file, "%s%s", count->argName, subindex);
+ else
+ fprintf(file, "OutP->%s%s", count->argMsgField, subindex);
+
+ if (count->argMultiplier > 1 || howbig > 8)
+ fprintf(file, " * %d;\n", count->argMultiplier * howbig / 8);
+ else
+ fprintf(file, ";\n");
+ }
+
+ if (IS_MULTIPLE_KPD(it)) {
+ fprintf(file, "\t }\n");
+ if (it->itVarArray && !it->itElement->itVarArray) {
+ fprintf(file, "\t for (i = j; i < %d; ptr++, i++)\n", it->itKPD_Number);
+ /* since subordinate arrays aren't variable, they are initialized from template:
+ here we must no-op 'em */
+ fprintf(file, "\t\tptr->size = 0;\n");
+ }
+ fprintf(file, "\t}\n");
+ }
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_Pack discipline for out-of-line Port types.
+ */
+static void
+WriteKPD_oolport(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ boolean_t VarArray;
+ argument_t *count;
+ char *subindex, string[MAX_STR_LEN];
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(string, "\tptr->");
+ VarArray = it->itElement->itVarArray;
+ count = arg->argSubCount;
+ subindex = "[i]";
+ }
+ else {
+ (void)sprintf(string, "OutP->%s.", arg->argMsgField);
+ VarArray = it->itVarArray;
+ count = arg->argCount;
+ subindex = "";
+ }
+
+ if (akCheck(arg->argKind, akbVarNeeded))
+ fprintf(file, "\t%saddress = (void *)%s%s;\n", string, arg->argMsgField, subindex);
+ if (arg->argDealloc != argNULL)
+ if (akCheck(arg->argDealloc->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+ if (VarArray) {
+ fprintf(file, "\t%scount = ", string);
+ if (akCheck(count->argKind, akbVarNeeded))
+ fprintf(file, "%s%s;\n", count->argName, subindex);
+ else
+ fprintf(file, "OutP->%s%s;\n", count->argMsgField, subindex);
+ }
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd))
+ if (akCheck(arg->argPoly->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t%sdisposition = %s;\n", string, arg->argPoly->argVarName);
+ if (IS_MULTIPLE_KPD(it)) {
+ fprintf(file, "\t }\n");
+ if (it->itVarArray && !it->itElement->itVarArray) {
+ fprintf(file, "\t for (i = j; i < %d; ptr++, i++)\n", it->itKPD_Number);
+ /* since subordinate arrays aren't variable, they are initialized from template:
+ here we must no-op 'em */
+ fprintf(file, "\t%scount = 0;\n", string);
+ }
+ fprintf(file, "\t}\n");
+ }
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for Port types.
+ */
+static void
+WriteTCheckKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab = "";
+ char string[MAX_STR_LEN];
+ boolean_t close = FALSE;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
+ (void)sprintf(string, "ptr->");
+ tab = "\t";
+ close = TRUE;
+ }
+ else
+ (void)sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
+
+ fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string);
+ /*
+ * We can't check disposition on varArray
+ * (because some of the entries could be empty).
+ */
+ if (!it->itVarArray) {
+ if (arg->argPoly != argNULL) {
+ switch (it->itOutName) {
+
+ case MACH_MSG_TYPE_MOVE_RECEIVE:
+ fprintf(file, " || \n\t%s %sdisposition != MACH_MSG_TYPE_MOVE_RECEIVE", tab, string);
+ break;
+
+ case MACH_MSG_TYPE_MOVE_SEND_ONCE:
+ fprintf(file, " || (\n\t%s %sdisposition != MACH_MSG_TYPE_MOVE_SEND_ONCE", tab, string);
+ fprintf(file, " && \n\t%s %sdisposition != MACH_MSG_TYPE_MAKE_SEND_ONCE)", tab, string);
+ break;
+
+ case MACH_MSG_TYPE_MOVE_SEND:
+ fprintf(file, " || (\n\t%s %sdisposition != MACH_MSG_TYPE_MOVE_SEND", tab, string);
+ fprintf(file, " && \n\t%s %sdisposition != MACH_MSG_TYPE_MAKE_SEND", tab, string);
+ fprintf(file, " && \n\t%s %sdisposition != MACH_MSG_TYPE_COPY_SEND)", tab, string);
+ break;
+ }
+ }
+ else {
+ fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, it->itOutNameStr);
+ }
+ }
+ fprintf(file, ")\n");
+ fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
+ if (close)
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for out-of-line types.
+ */
+static void
+WriteTCheckKPD_ool(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab, string[MAX_STR_LEN];
+ boolean_t test;
+ u_int howmany, howbig;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
+ tab = "\t\t\t";
+ sprintf(string, "ptr->");
+ howmany = it->itElement->itNumber;
+ howbig = it->itElement->itSize;
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ }
+ else {
+ tab = "";
+ sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
+ howmany = it->itNumber;
+ howbig = it->itSize;
+ test = !it->itVarArray;
+ }
+
+ fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string);
+ if (test) {
+ /* if VarArray we may use no-op; if itElement->itVarArray size might change */
+ fprintf(file, " ||\n\t%s %ssize != %d", tab, string, (howmany * howbig + 7)/8);
+ }
+
+ fprintf(file, ")\n");
+ fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
+
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for out-of-line Port types.
+ */
+static void
+WriteTCheckKPD_oolport(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab, string[MAX_STR_LEN];
+ boolean_t test;
+ u_int howmany;
+ char *howstr;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ howmany = it->itElement->itNumber;
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ howstr = it->itElement->itOutNameStr;
+ }
+ else {
+ tab = "";
+ sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
+ howmany = it->itNumber;
+ test = !it->itVarArray;
+ howstr = it->itOutNameStr;
+ }
+
+ fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string);
+ if (test)
+ /* if VarArray we may use no-op; if itElement->itVarArray size might change */
+ fprintf(file, " ||\n\t%s %scount != %d", tab, string, howmany);
+ if (arg->argPoly == argNULL)
+ fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, howstr);
+ fprintf(file, ")\n");
+ fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
+
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*************************************************************
+ * Writes code to check that the type of each of the arguments
+ * in the reply message is what is expected. Called by
+ * WriteRoutine for each in && typed argument in the request message.
+ *************************************************************/
+static void
+WriteTypeCheck(FILE *file, argument_t *arg)
+{
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ (*arg->argKPD_TypeCheck)(file, arg);
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+}
+
+static void
+WritePackArgValueNormal(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) {
+ if (it->itString) {
+ /*
+ * Copy variable-size C string with mig_strncpy.
+ * Save the string length (+ 1 for trailing 0)
+ * in the argument`s count field.
+ */
+ fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n");
+ fprintf(file, "\t\tOutP->%s = (%s) mig_strncpy_zerofill(OutP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber);
+ fprintf(file, "\t} else {\n");
+ fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
+
+ fprintf(file, "\t\tOutP->%s = (%s) mig_strncpy(OutP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber);
+
+ fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
+
+ fprintf(file, "\tOutP->%sOffset = 0;\n", arg->argMsgField);
+ }
+ else if (it->itNoOptArray)
+ fprintf(file, "\t(void)memcpy((char *) OutP->%s, (const char *) %s, %d);\n", arg->argMsgField, arg->argVarName, it->itTypeSize);
+ else {
+ argument_t *count = arg->argCount;
+ ipc_type_t *btype = it->itElement;
+ identifier_t newstr;
+
+ /* Note btype->itNumber == count->argMultiplier */
+
+ fprintf(file, "\t(void)memcpy((char *) OutP->%s, (const char *) %s, ", arg->argMsgField, arg->argVarName);
+ if (btype->itTypeSize > 1)
+ fprintf(file, "%d * ", btype->itTypeSize);
+ /* count is a akbVarNeeded if arg is akbVarNeeded */
+ if (akCheck(count->argKind, akbVarNeeded))
+ newstr = count->argVarName;
+ else
+ newstr = (identifier_t)strconcat("OutP->", count->argMsgField);
+ fprintf(file, "%s);\n", newstr);
+ }
+ }
+ else if (it->itOutTrans != strNULL)
+ WriteCopyType(file, it, TRUE, "OutP->%s", "/* %s */ %s(%s)", arg->argMsgField, it->itOutTrans, arg->argVarName);
+ else
+ WriteCopyType(file, it, TRUE, "OutP->%s", "/* %s */ %s", arg->argMsgField, arg->argVarName);
+
+ if (arg->argPadName != NULL && it->itPadSize != 0) {
+ fprintf(file, "\t for (int i = 0; i < %d; i++)\n", it->itPadSize);
+ fprintf(file, "\t\t OutP->%s[i] = 0;\n", arg->argPadName);
+ }
+}
+
+static void
+WritePackArgValueVariable(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ /*
+ * only itString are treated here so far
+ */
+ if (it->itString) {
+ /*
+ * Emit logic to call strlen to calculate the size of the argument, and ensure that it fits within the 32-bit result field
+ * in the Reply, when targeting a 64-bit architecture. If a 32-bit architecture is the target, we emit code to just call
+ * strlen() directly (since it'll return a 32-bit value that is guaranteed to fit).
+ */
+ fputs("#ifdef __LP64__\n", file);
+ fprintf(file, "\t{\n"
+ "\t\t" "size_t strLength = strlen(OutP->%s) + 1;\n", arg->argMsgField);
+ fputs( "\t\t" "if (strLength > 0xffffffff)\n"
+ "\t\t\t" "MIG_RETURN_ERROR(OutP, MIG_BAD_ARGUMENTS);\n", file);
+ fprintf(file, "\t\t" "OutP->%s = (mach_msg_type_number_t) strLength;\n"
+ "\t}\n", arg->argCount->argMsgField);
+ fputs("#else\n", file);
+ fprintf(file, "\tOutP->%s = (mach_msg_type_number_t) strlen(OutP->%s) + 1;\n", arg->argCount->argMsgField, arg->argMsgField);
+ fputs("#endif /* __LP64__ */\n", file);
+
+ }
+}
+
+static void
+WriteCopyArgValue(FILE *file, argument_t *arg)
+{
+ fprintf(file, "\n");
+ WriteCopyType(file, arg->argType, TRUE, "/* %d */ OutP->%s", "In%dP->%s", arg->argRequestPos, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
+}
+
+static void
+WriteInitArgValue(FILE *file, argument_t *arg)
+{
+ fprintf(file, "\n");
+ fprintf(file, "\tOutP->%s = %s;\n\n", arg->argMsgField, arg->argVarName);
+}
+
+/*
+ * Calculate the size of a variable-length message field.
+ */
+static void
+WriteArgSize(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+ int bsize = ptype->itElement->itTypeSize;
+ argument_t *count = arg->argCount;
+
+ /* If the base type size of the data field isn`t a multiple of 4,
+ we have to round up. */
+ if (bsize % itWordAlign != 0)
+ fprintf(file, "_WALIGN_");
+
+ /* Here, we generate ((value + %d) & ~%d). We have to put two (( at the
+ * the beginning.
+ */
+ fprintf(file, "((");
+ if (bsize > 1)
+ fprintf(file, "%d * ", bsize);
+ if (ptype->itString || !akCheck(count->argKind, akbVarNeeded))
+ /* get count from descriptor in message */
+ fprintf(file, "OutP->%s", count->argMsgField);
+ else
+ /* get count from argument */
+ fprintf(file, "%s", count->argVarName);
+
+ /*
+ * If the base type size is not a multiple of sizeof(natural_t),
+ * we have to round up.
+ */
+ if (bsize % sizeof(natural_t) != 0)
+ fprintf(file, " + %d) & ~%d)", (int)sizeof(natural_t)-1, (int)sizeof(natural_t)-1);
+ else
+ fprintf(file, "))");
+}
+
+/*
+ * Adjust message size and advance reply pointer.
+ * Called after packing a variable-length argument that
+ * has more arguments following.
+ */
+static void
+WriteAdjustMsgSize(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+ ipc_type_t *ptype = arg->argType;
+
+ /* There are more Out arguments. We need to adjust msgh_size
+ and advance OutP, so we save the size of the current field
+ in msgh_size_delta. */
+
+ fprintf(file, "\tmsgh_size_delta = ");
+ WriteArgSize(file, arg);
+ fprintf(file, ";\n");
+
+ if (rt->rtNumReplyVar == 1) {
+ /* We can still address the message header directly. Fill
+ in the size field. */
+
+ fprintf(file, "\tOutP->Head.msgh_size = ");
+ rtMinReplySize(file, rt, "Reply");
+ fprintf(file, " + msgh_size_delta;\n");
+ }
+ else if (arg->argReplyPos == 0) {
+ /* First variable-length argument. The previous msgh_size value
+ is the minimum reply size. */
+
+ fprintf(file, "\tmsgh_size = ");
+ rtMinReplySize(file, rt, "Reply");
+ fprintf(file, " + msgh_size_delta;\n");
+ }
+ else
+ fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
+
+ fprintf(file, "\tOutP = (Reply *) ((pointer_t) OutP + msgh_size_delta - %d);\n", ptype->itTypeSize + ptype->itPadSize);
+}
+
+/*
+ * Calculate the size of the message. Called after the
+ * last argument has been packed.
+ */
+static void
+WriteFinishMsgSize(FILE *file, argument_t *arg)
+{
+ /* No more Out arguments. If this is the only variable Out
+ argument, we can assign to msgh_size directly. */
+
+ if (arg->argReplyPos == 0) {
+ fprintf(file, "\tOutP->Head.msgh_size = ");
+ rtMinReplySize(file, arg->argRoutine, "Reply");
+ fprintf(file, " + (");
+ WriteArgSize(file, arg);
+ fprintf(file, ");\n");
+ }
+ else {
+ fprintf(file, "\tmsgh_size += ");
+ WriteArgSize(file, arg);
+ fprintf(file, ";\n");
+ }
+}
+
+/*
+ * Handle reply arguments - fill in message types and copy arguments
+ * that need to be copied.
+ */
+static void
+WriteReplyArgs(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ argument_t *lastVarArg;
+
+ /*
+ * 1. The Kernel Processed Data
+ */
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnKPD))
+ (*arg->argKPD_Pack)(file, arg);
+ /*
+ * 2. The Data Stream
+ */
+ lastVarArg = argNULL;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ /*
+ * Adjust message size and advance message pointer if
+ * the last request argument was variable-length and the
+ * request position will change.
+ */
+ if (lastVarArg != argNULL &&
+ lastVarArg->argReplyPos < arg->argReplyPos) {
+ WriteAdjustMsgSize(file, lastVarArg);
+ lastVarArg = argNULL;
+ }
+
+ if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVarNeeded))
+ WritePackArgValueNormal(file, arg);
+ else if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVariable))
+ WritePackArgValueVariable(file, arg);
+
+ if (akCheck(arg->argKind, akbReplyCopy))
+ WriteCopyArgValue(file, arg);
+ if (akCheck(arg->argKind, akbReplyInit))
+ WriteInitArgValue(file, arg);
+ /*
+ * Remember whether this was variable-length.
+ */
+ if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVariable))
+ lastVarArg = arg;
+ }
+ /*
+ * Finish the message size.
+ */
+ if (lastVarArg != argNULL)
+ WriteFinishMsgSize(file, lastVarArg);
+}
+
+static void
+WriteFieldDecl(FILE *file, argument_t *arg)
+{
+ if (akCheck(arg->argKind, akbSendKPD) ||
+ akCheck(arg->argKind, akbReturnKPD))
+ WriteFieldDeclPrim(file, arg, FetchKPDType);
+ else
+ WriteFieldDeclPrim(file, arg, FetchServerType);
+}
+
+static void
+InitKPD_Disciplines(argument_t *args)
+{
+ argument_t *arg;
+ extern void KPD_noop(FILE *file, argument_t *arg);
+ extern void KPD_error(FILE *file, argument_t *arg);
+ extern void WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in);
+ extern void WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in);
+ extern void WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in);
+
+ /*
+ * WriteInitKPD_port, WriteKPD_port, WriteExtractKPD_port,
+ * WriteInitKPD_ool, WriteKPD_ool, WriteExtractKPD_ool,
+ * WriteInitKPD_oolport, WriteKPD_oolport, WriteExtractKPD_oolport
+ * are local to this module (which is the reason why this initialization
+ * takes place here rather than in utils.c).
+ * Common routines for user and server will be established SOON, and
+ * all of them (including the initialization) will be transfert to
+ * utils.c
+ * All the KPD disciplines are defaulted to be KPD_error().
+ * Note that akbSendKPD and akbReturnKPd are not exclusive,
+ * because of inout type of parameters.
+ */
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD))
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Extract =
+ (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_port : WriteExtractArgValue;
+ arg->argKPD_TypeCheck = WriteTCheckKPD_port;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_port;
+ arg->argKPD_Init = WriteInitKPD_port;
+ arg->argKPD_Pack = WriteKPD_port;
+ }
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Extract =
+ (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_ool : WriteExtractArgValue;
+ arg->argKPD_TypeCheck = WriteTCheckKPD_ool;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_ool;
+ arg->argKPD_Init = WriteInitKPD_ool;
+ arg->argKPD_Pack = WriteKPD_ool;
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Extract =
+ (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_oolport : WriteExtractArgValue;
+ arg->argKPD_TypeCheck = WriteTCheckKPD_oolport;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_oolport;
+ arg->argKPD_Init = WriteInitKPD_oolport;
+ arg->argKPD_Pack = WriteKPD_oolport;
+ }
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+}
+
+static void WriteStringTerminatorCheck(FILE *file, routine_t *rt)
+{
+ // generate code to verify that the length of a C string is not greater than the size of the
+ // buffer in which it is stored.
+ argument_t *argPtr;
+ int msg_limit_calculated = FALSE;
+ int found_string_argument = FALSE;
+ int variable_length_args_present = (rt->rtMaxRequestPos > 0);
+
+ // scan through arguments to see if there are any strings
+ for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
+ if ((argPtr->argKind & akbRequest) && argPtr->argType->itString) {
+ found_string_argument = TRUE;
+ break;
+ }
+ }
+
+ if (found_string_argument) {
+ // create a new scope, for local variables
+ fputs("#if __MigTypeCheck\n" "\t" "{" "\n", file);
+
+ for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
+ if ((argPtr->argKind & akbRequest) && argPtr->argType->itString) {
+ //fprintf(stderr, "### found itString: variable name = %s, max length = %d\n", argPtr->argName, argPtr->argType->itNumber);
+
+ if (!msg_limit_calculated) {
+ msg_limit_calculated = TRUE; // only need to do this once
+ fputs("\t\t" "char * msg_limit = ((char *) In0P) + In0P->Head.msgh_size;\n", file);
+ if (IsKernelServer) {
+ fputs("#if __MigKernelSpecificCode\n", file);
+ fputs("\t\t" "size_t strnlen_limit;" "\n", file);
+ fputs("#else\n", file);
+ }
+ fputs("\t\t" "size_t memchr_limit;" "\n", file);
+ if (IsKernelServer) {
+ fputs("#endif /* __MigKernelSpecificCode */" "\n", file);
+ }
+ fputc('\n', file);
+ }
+
+ // I would really prefer to use strnlen() here, to ensure that the byte scanning logic does not extend beyond
+ // the end of the buffer, but it's not necessarily guaranteed to be available. Instead, I'll use memchr(),
+ // and let it look for the terminating null byte.
+ // (later...)
+ // It turns out that the kernel does not have memchr() available, but strnlen() IS available, so we'll just
+ // have to emit some conditional code to use the appropriate runtime environment scanning function.
+ //
+ if (IsKernelServer) {
+ fputs("#if __MigKernelSpecificCode\n", file);
+ fputs("\t\t" "strnlen_limit = min((msg_limit - ", file);
+ // If there are variable-length arguments within the message, the proper (adjusted)
+ // pointers must be used to access those strings
+ fprintf(file, "In%dP->%s), %d);" "\n", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
+ fputs("\t\t" "if (", file);
+ fprintf(file, "( strnlen(In%dP->%s, strnlen_limit) >= %d + 1 )", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
+ fputs(")" "\n" "\t\t\t" "return MIG_BAD_ARGUMENTS; // string length exceeds buffer length!" "\n", file);
+ fputs("#else\n", file);
+ }
+ // If there are variable-length arguments within the message, the proper (adjusted)
+ // pointers must be used to access those strings
+ fprintf(file, "\t\t" "memchr_limit = min((msg_limit - In%dP->%s), %d);" "\n", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
+ fputs("\t\t" "if (", file);
+ fprintf(file, "( memchr(In%dP->%s, '\\0', memchr_limit) == NULL )", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName);
+ fputs(")" "\n" "\t\t\t" "return MIG_BAD_ARGUMENTS; // string length exceeds buffer length!" "\n", file);
+ if (IsKernelServer) {
+ fputs("#endif /* __MigKernelSpecificCode */" "\n", file);
+ }
+ }
+ }
+ fputs("\t" "}" "\n" "#endif" "\t" "/* __MigTypeCheck */" "\n\n", file); // terminate new scope
+ }
+
+ return;
+}
+
+static void
+WriteOOLSizeCheck(FILE *file, routine_t *rt)
+{
+ /* Emit code to validate the actual size of ool data vs. the reported size */
+
+ argument_t *argPtr;
+ boolean_t openedTypeCheckConditional = FALSE;
+
+ // scan through arguments to see if there are any ool data blocks
+ for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
+ if (akCheck(argPtr->argKind, akbSendKPD)) {
+ ipc_type_t *it = argPtr->argType;
+ boolean_t multiple_kpd = IS_MULTIPLE_KPD(it);
+ char string[MAX_STR_LEN];
+ boolean_t test;
+ argument_t *argCountPtr;
+ char *tab;
+
+ if (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+
+ if (multiple_kpd) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+ WriteKPD_Iterator(file, TRUE, FALSE, argPtr, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ it = it->itElement; // point to element descriptor, so size calculation is correct
+ argCountPtr = argPtr->argSubCount;
+ } else {
+ tab = "";
+ sprintf(string, "In%dP->%s.", argPtr->argRequestPos, argPtr->argMsgField);
+ test = !it->itVarArray;
+ argCountPtr = argPtr->argCount;
+ }
+
+ if (!test) {
+ int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1;
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ fprintf(file, "\t%s" "if (%ssize ", tab, string);
+ if (multiplier > 1)
+ fprintf(file, "/ %d ", multiplier);
+ fprintf(file,"!= In%dP->%s%s", argCountPtr->argRequestPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : "");
+ if (it->itOOL_Number) {
+ fprintf(file," || In%dP->%s%s > %d", argCountPtr->argRequestPos,
+ argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number);
+ }
+
+ fprintf(file,")\n");
+ fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
+ }
+
+ if (multiple_kpd)
+ fprintf(file, "\t }\n\t}\n");
+ } else if (argPtr->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR) {
+ if (multiple_kpd) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+ WriteKPD_Iterator(file, TRUE, FALSE, argPtr, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ it = it->itElement; // point to element descriptor, so size calculation is correct
+ argCountPtr = argPtr->argSubCount;
+ } else {
+ tab = "";
+ sprintf(string, "In%dP->%s.", argPtr->argRequestPos, argPtr->argMsgField);
+ test = !it->itVarArray;
+ argCountPtr = argPtr->argCount;
+ }
+
+ if (!test) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ fprintf(file, "\t%s" "if (%scount ", tab, string);
+ fprintf(file,"!= In%dP->%s%s", argCountPtr->argRequestPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : "");
+ if (it->itOOL_Number) {
+ fprintf(file," || In%dP->%s%s > %d", argCountPtr->argRequestPos,
+ argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number);
+ }
+ fprintf(file,")\n");
+ fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
+ }
+
+ if (multiple_kpd)
+ fprintf(file, "\t }\n\t}\n");
+ }
+ }
+ }
+
+ if ( openedTypeCheckConditional )
+ fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file);
+}
+
+
+void
+WriteCheckRequest(FILE *file, routine_t *rt)
+{
+ int i;
+
+ /* initialize the disciplines for the handling of KPDs */
+ InitKPD_Disciplines(rt->rtArgs);
+
+ fprintf(file, "\n");
+ fprintf(file, "#if ( __MigTypeCheck ");
+ if (CheckNDR)
+ fprintf(file, "|| __NDR_convert__ ");
+ fprintf(file, ")\n");
+ fprintf(file, "#if __MIG_check__Request__%s_subsystem__\n", SubsystemName);
+ fprintf(file, "#if !defined(__MIG_check__Request__%s_t__defined)\n", rt->rtName);
+ fprintf(file, "#define __MIG_check__Request__%s_t__defined\n", rt->rtName);
+ if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbRequest)) {
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgDecl, akbSendNdr, "", "");
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgDecl, akbSendNdr, "", "");
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgDecl, akbSendNdr, "", "");
+ }
+ fprintf(file, "\n");
+ fprintf(file, "mig_internal kern_return_t __MIG_check__Request__%s_t(__attribute__((__unused__)) __Request__%s_t *In0P", rt->rtName, rt->rtName);
+ for (i = 1; i <= rt->rtMaxRequestPos; i++)
+ fprintf(file, ", __attribute__((__unused__)) __Request__%s_t **In%dPP", rt->rtName, i);
+ fprintf(file, ")\n{\n");
+
+ fprintf(file, "\n\ttypedef __Request__%s_t __Request;\n", rt->rtName);
+ for (i = 1; i <= rt->rtMaxRequestPos; i++)
+ fprintf(file, "\t__Request *In%dP;\n", i);
+ if (rt->rtNumRequestVar > 0) {
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tunsigned int msgh_size;\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ if (rt->rtMaxRequestPos > 0)
+ fprintf(file, "\tunsigned int msgh_size_delta;\n");
+ if (rt->rtNumRequestVar > 0 || rt->rtMaxRequestPos > 0)
+ fprintf(file, "\n");
+
+ WriteCheckHead(file, rt);
+
+ WriteList(file, rt->rtArgs, WriteTypeCheck, akbSendKPD, "\n", "\n");
+
+ {
+ argument_t *arg, *lastVarArg;
+
+ lastVarArg = argNULL;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (lastVarArg != argNULL &&
+ lastVarArg->argRequestPos < arg->argRequestPos) {
+ WriteAdjustRequestMsgPtr(file, lastVarArg);
+ lastVarArg = argNULL;
+ }
+ if (akCheckAll(arg->argKind, akbSendRcv|akbSendBody)) {
+ if (akCheck(arg->argKind, akbVariable)) {
+ WriteCheckMsgSize(file, arg);
+ lastVarArg = arg;
+ }
+ }
+ }
+ }
+
+ if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbRequest)) {
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgCond, akbSendNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (In0P->NDR.int_rep != NDR_record.int_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgUse, akbSendNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n");
+
+ WriteOOLSizeCheck(file, rt);
+
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgCond, akbSendNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (In0P->NDR.char_rep != NDR_record.char_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgUse, akbSendNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n");
+
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgCond, akbSendNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (In0P->NDR.float_rep != NDR_record.float_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgUse, akbSendNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n");
+ } else {
+ WriteOOLSizeCheck(file, rt);
+ }
+
+ WriteStringTerminatorCheck(file, rt);
+
+ fprintf(file, "\treturn MACH_MSG_SUCCESS;\n");
+ fprintf(file, "}\n");
+ fprintf(file, "#endif /* !defined(__MIG_check__Request__%s_t__defined) */\n", rt->rtName);
+ fprintf(file, "#endif /* __MIG_check__Request__%s_subsystem__ */\n", SubsystemName);
+ fprintf(file, "#endif /* ( __MigTypeCheck ");
+ if (CheckNDR)
+ fprintf(file, "|| __NDR_convert__ ");
+ fprintf(file, ") */\n");
+ fprintf(file, "\n");
+}
+
+void
+WriteCheckRequestCall(FILE *file, routine_t *rt)
+{
+ int i;
+
+ fprintf(file, "\n");
+ fprintf(file, "#if\tdefined(__MIG_check__Request__%s_t__defined)\n", rt->rtName);
+ fprintf(file, "\tcheck_result = __MIG_check__Request__%s_t((__Request *)In0P", rt->rtName);
+ for (i = 1; i <= rt->rtMaxRequestPos; i++)
+ fprintf(file, ", (__Request **)&In%dP", i);
+ fprintf(file, ");\n");
+ fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS)\n");
+ fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, check_result); }\n");
+ fprintf(file, "#endif\t/* defined(__MIG_check__Request__%s_t__defined) */\n", rt->rtName);
+ fprintf(file, "\n");
+}
+
+void
+WriteCheckRequests(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine)
+ WriteCheckRequest(file, stat->stRoutine);
+}
+
+static void
+WriteRoutine(FILE *file, routine_t *rt)
+{
+ /* Declare the server work function: */
+ if (ServerHeaderFileName == strNULL)
+ WriteServerRoutine(file, rt);
+
+ fprintf(file, "\n");
+
+ fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
+ fprintf(file, "mig_internal novalue _X%s\n", rt->rtName);
+ if (BeAnsiC) {
+ fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
+ fprintf(file, "#else\n");
+ fprintf(file, "\t(InHeadP, OutHeadP)\n");
+ fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+
+ fprintf(file, "{\n");
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, TRUE, rt->rtServerImpl, FALSE);
+ fprintf(file, "\ttypedef __Request__%s_t __Request;\n", rt->rtName);
+ fprintf(file, "\ttypedef __Reply__%s_t Reply __attribute__((unused));\n\n", rt->rtName);
+
+ /*
+ * Define a Minimal Reply structure to be used in case of errors
+ */
+ fprintf(file, "\t/*\n");
+ fprintf(file, "\t * typedef struct {\n");
+ fprintf(file, "\t * \tmach_msg_header_t Head;\n");
+ fprintf(file, "\t * \tNDR_record_t NDR;\n");
+ fprintf(file, "\t * \tkern_return_t RetCode;\n");
+ fprintf(file, "\t * } mig_reply_error_t;\n");
+ fprintf(file, "\t */\n");
+ fprintf(file, "\n");
+
+ WriteVarDecls(file, rt);
+
+ if (IsKernelServer) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ WriteList(file, rt->rtArgs, WriteTemplateDeclOut, akbReturnKPD, "\n", "\n");
+ fprintf(file, "#else\n");
+ }
+ WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbReturnKPD, "\n", "\n");
+ if (IsKernelServer) {
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+ }
+ WriteRetCode(file, rt->rtRetCode);
+ WriteList(file, rt->rtArgs, WriteLocalVarDecl, akbVarNeeded | akbServerArg, ";\n", ";\n\n");
+ WriteApplMacro(file, "Rcv", "Declare", rt);
+ WriteApplMacro(file, "Rcv", "Before", rt);
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ WriteRetCArgCheckError(file, rt);
+ if (rt->rtServerImpl)
+ WriteCheckTrailerHead(file, rt, FALSE);
+ WriteServerCall(file, rt, WriteConditionalCallArg);
+ WriteRetCArgFinishError(file, rt);
+ }
+
+ WriteCheckRequestCall(file, rt);
+ WriteCheckRequestTrailerArgs(file, rt);
+
+ /*
+ * Initialize the KPD records in the Reply structure with the
+ * templates. We do this beforehand because the call to the procedure
+ * will overwrite some of the values (after the call it would be impossible
+ * to initialize the KPD records from the static Templates, because we
+ * would lose data).
+ */
+ WriteList(file, rt->rtArgs, WriteInitKPDValue, akbReturnKPD, "\n", "\n");
+
+ WriteList(file, rt->rtArgs, WriteExtractArg, akbNone, "", "");
+
+ if (UseEventLogger)
+ WriteLogMsg(file, rt, LOG_SERVER, LOG_REQUEST);
+
+ WriteServerCall(file, rt, WriteServerCallArg);
+
+ WriteReverseList(file, rt->rtArgs, WriteDestroyArg, akbDestroy, "", "");
+
+ /*
+ * For one-way routines, it doesn`t make sense to check the return
+ * code, because we return immediately afterwards. However,
+ * kernel servers may want to deallocate port arguments - and the
+ * deallocation must not be done if the return code is not KERN_SUCCESS.
+ */
+ if (rt->rtOneWay || rt->rtNoReplyArgs) {
+ if (IsKernelServer) {
+ fprintf(file,"#if\t__MigKernelSpecificCode\n");
+ if (rtCheckMaskFunction(rt->rtArgs, akbSendKPD, CheckDestroyPortArg)) {
+ WriteCheckReturnValue(file, rt);
+ }
+ WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg, akbSendKPD, "", "");
+ fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
+ }
+ /* although we have an empty reply, we still have to make sure that
+ some fields such as NDR get properly initialized */
+ if (!rt->rtOneWay)
+ WriteList(file, rt->rtArgs, WriteInitArgValue, akbReplyInit, "\n", "\n");
+ }
+ else {
+ WriteCheckReturnValue(file, rt);
+
+ if (IsKernelServer) {
+ fprintf(file,"#if\t__MigKernelSpecificCode\n");
+ WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg, akbSendKPD, "", "");
+ fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
+ }
+ WriteReplyArgs(file, rt);
+ WriteReplyInit(file, rt);
+ if (!rt->rtSimpleReply)
+ fprintf(file, "\tOutP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtReplyKPDs);
+ }
+ if (UseEventLogger)
+ WriteLogMsg(file, rt, LOG_SERVER, LOG_REPLY);
+
+ WriteApplMacro(file, "Rcv", "After", rt);
+ fprintf(file, "}\n");
+}
+
+void
+WriteServer(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ WriteProlog(file, stats);
+ if (BeAnsiC)
+ WriteForwardDeclarations(file, stats);
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skRoutine:
+ WriteCheckRequest(file, stat->stRoutine);
+ WriteRoutine(file, stat->stRoutine);
+ break;
+
+ case skIImport:
+ case skImport:
+ case skSImport:
+ case skDImport:
+ case skUImport:
+ break;
+
+ default:
+ fatal("WriteServer(): bad statement_kind_t (%d)",
+ (int) stat->stKind);
+ }
+ WriteDispatcher(file, stats);
+}
diff --git a/bootstrap_cmds/migcom.tproj/statement.c b/bootstrap_cmds/migcom.tproj/statement.c
new file mode 100644
index 0000000..5a2476d
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/statement.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "error.h"
+#include "alloc.h"
+#include "statement.h"
+
+statement_t *stats = stNULL;
+static statement_t **last = &stats;
+
+statement_t *
+stAlloc(void)
+{
+ statement_t *new;
+
+ new = (statement_t *) malloc(sizeof *new);
+ if (new == stNULL)
+ fatal("stAlloc(): %s", strerror(errno));
+ *last = new;
+ last = &new->stNext;
+ new->stNext = stNULL;
+ return new;
+}
diff --git a/bootstrap_cmds/migcom.tproj/statement.h b/bootstrap_cmds/migcom.tproj/statement.h
new file mode 100644
index 0000000..ca3f5ba
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/statement.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University
+ * Extensive revamping. Added polymorphic arguments.
+ * Allow multiple variable-sized inline arguments in messages.
+ *
+ * 27-May-87 Richard Draves (rpd) at Carnegie-Mellon University
+ * Created.
+ */
+
+#ifndef _STATEMENT_H
+#define _STATEMENT_H
+
+#include "routine.h"
+
+typedef enum statement_kind
+{
+ skRoutine,
+ skImport,
+ skUImport,
+ skSImport,
+ skDImport,
+ skIImport,
+ skRCSDecl
+} statement_kind_t;
+
+typedef struct statement
+{
+ statement_kind_t stKind;
+ struct statement *stNext;
+ union
+ {
+ /* when stKind == skRoutine */
+ routine_t *_stRoutine;
+ /* when stKind == skImport, skUImport, skSImport, skDImport, skIImport */
+ string_t _stFileName;
+ } data;
+} statement_t;
+
+#define stRoutine data._stRoutine
+#define stFileName data._stFileName
+
+#define stNULL ((statement_t *) 0)
+
+/* stNext will be initialized to put the statement in the list */
+extern statement_t *stAlloc(void);
+
+/* list of statements, in order they occur in the .defs file */
+extern statement_t *stats;
+
+#endif /* _STATEMENT_H */
diff --git a/bootstrap_cmds/migcom.tproj/strdefs.h b/bootstrap_cmds/migcom.tproj/strdefs.h
new file mode 100644
index 0000000..00a386d
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/strdefs.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1999, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * 91/02/05 17:55:57 mrt
+ * Changed to new Mach copyright
+ * [91/02/01 17:56:03 mrt]
+ *
+ * 90/06/02 15:05:49 rpd
+ * Created for new IPC.
+ * [90/03/26 21:13:56 rpd]
+ *
+ * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University
+ * Extensive revamping. Added polymorphic arguments.
+ * Allow multiple variable-sized inline arguments in messages.
+ *
+ * 15-Jun-87 David Black (dlb) at Carnegie-Mellon University
+ * Fixed strNULL to be the null string instead of the null string
+ * pointer.
+ *
+ * 27-May-87 Richard Draves (rpd) at Carnegie-Mellon University
+ * Created.
+ */
+
+#ifndef STRDEFS_H
+#define STRDEFS_H
+
+#include <string.h>
+#include <mach/boolean.h>
+
+typedef char *string_t;
+typedef string_t identifier_t;
+
+#define MAX_STR_LEN 200
+
+#define strNULL ((string_t) 0)
+
+extern string_t strmake( char *string );
+extern string_t strconcat( string_t left, string_t right );
+extern string_t strphrase( string_t left, string_t right );
+extern void strfree( string_t string );
+
+#define streql(a, b) (strcmp((a), (b)) == 0)
+
+extern char *strbool( boolean_t bool );
+extern char *strstring( string_t string );
+extern char *toupperstr( char *string );
+
+#endif /* STRDEFS_H */
diff --git a/bootstrap_cmds/migcom.tproj/string.c b/bootstrap_cmds/migcom.tproj/string.c
new file mode 100644
index 0000000..b7e0355
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/string.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <mach/boolean.h>
+#include <ctype.h>
+#include "error.h"
+#include "alloc.h"
+#include "strdefs.h"
+
+string_t
+strmake(char *string)
+{
+ string_t saved;
+
+ saved = malloc(strlen(string) + 1);
+ if (saved == strNULL)
+ fatal("strmake('%s'): %s", string, strerror(errno));
+ return strcpy(saved, string);
+}
+
+string_t
+strconcat(string_t left, string_t right)
+{
+ string_t saved;
+
+ saved = malloc(strlen(left) + strlen(right) + 1);
+ if (saved == strNULL)
+ fatal("strconcat('%s', '%s'): %s", left, right, strerror(errno));
+ return strcat(strcpy(saved, left), right);
+}
+
+string_t
+strphrase(string_t left, string_t right)
+{
+ string_t saved;
+ string_t current;
+ size_t llen;
+
+ llen = strlen(left);
+ saved = malloc(llen + strlen(right) + 2);
+ if (saved == strNULL)
+ fatal("strphrase('%s', '%s'): %s", left, right, strerror(errno));
+ strcpy(saved, left);
+ current = saved + llen;
+ *(current++) = ' ';
+ strcpy(current, right);
+ free(left);
+ return(saved);
+}
+
+void
+strfree(string_t string)
+{
+ free(string);
+}
+
+char *
+strbool(boolean_t bool)
+{
+ if (bool)
+ return "TRUE";
+ else
+ return "FALSE";
+}
+
+char *
+strstring(string_t string)
+{
+ if (string == strNULL)
+ return "NULL";
+ else
+ return string;
+}
+
+char *
+toupperstr(char *p)
+{
+ char *s = p;
+ char c;
+
+ while ((c = *s)) {
+ if (islower(c))
+ *s = toupper(c);
+ s++;
+ }
+ return(p);
+}
diff --git a/bootstrap_cmds/migcom.tproj/type.c b/bootstrap_cmds/migcom.tproj/type.c
new file mode 100644
index 0000000..db9473f
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/type.c
@@ -0,0 +1,899 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include "type.h"
+#include <sys/types.h>
+#include <mach/message.h>
+#include <mach/std_types.h>
+#include <mach/ndr.h>
+#include "mig_machine.h"
+#include "routine.h"
+#include "error.h"
+#include "alloc.h"
+#include "global.h"
+#include <stdio.h>
+
+#define PortSize (sizeof (mach_port_t) * NBBY)
+
+ipc_type_t *itRetCodeType; /* used for return codes */
+ipc_type_t *itNdrCodeType; /* used for NDR format labels */
+ipc_type_t *itDummyType; /* used for camelot dummy args */
+ipc_type_t *itTidType; /* used for camelot tids */
+ipc_type_t *itRequestPortType; /* used for default Request port arg */
+ipc_type_t *itZeroReplyPortType;/* used for dummy Reply port arg */
+ipc_type_t *itRealReplyPortType;/* used for default Reply port arg */
+ipc_type_t *itWaitTimeType; /* used for dummy WaitTime args */
+ipc_type_t *itMsgOptionType; /* used for dummy MsgOption args */
+
+static ipc_type_t *list = itNULL;
+
+static char *machine_integer_name;
+static u_int machine_integer_size;
+static u_int machine_integer_bits;
+
+/*
+ * Searches for a named type. We use a simple
+ * self-organizing linked list.
+ */
+ipc_type_t *
+itLookUp(identifier_t name)
+{
+ ipc_type_t *it, **last;
+
+ for (it = *(last = &list); it != itNULL; it = *(last = &it->itNext))
+ if (streql(name, it->itName)) {
+ /* move this type to the front of the list */
+ *last = it->itNext;
+ it->itNext = list;
+ list = it;
+
+ return it;
+ }
+
+ return itNULL;
+}
+
+/*
+ * Enters a new name-type association into
+ * our self-organizing linked list.
+ */
+void
+itInsert(identifier_t name, ipc_type_t *it)
+{
+ it->itName = name;
+ it->itNext = list;
+ list = it;
+}
+
+static ipc_type_t *
+itAlloc(void)
+{
+ static ipc_type_t prototype =
+ {
+ strNULL, /* identifier_t itName */
+ 0, /* ipc_type_t *itNext */
+ 0, /* u_int itTypeSize */
+ 0, /* u_int itPadSize */
+ 0, /* u_int itMinTypeSize */
+ 0, /* u_int itInName */
+ 0, /* u_int itOutName */
+ 0, /* u_int itSize */
+ 1, /* u_int itNumber */
+ 0, /* u_int itKPD_Number */
+ TRUE, /* boolean_t itInLine */
+ FALSE, /* boolean_t itMigInLine */
+ FALSE, /* boolean_t itPortType */
+ strNULL, /* string_t itInNameStr */
+ strNULL, /* string_t itOutNameStr */
+ TRUE, /* boolean_t itStruct */
+ FALSE, /* boolean_t itString */
+ FALSE, /* boolean_t itVarArray */
+ FALSE, /* boolean_t itNoOptArray */
+ FALSE, /* boolean_t itNative */
+ FALSE, /* boolean_t itNativePointer */
+ itNULL, /* ipc_type_t *itElement */
+ strNULL, /* identifier_t itUserType */
+ strNULL, /* identifier_t itServerType */
+ strNULL, /* identifier_t itTransType */
+ strNULL, /* identifier_t itUserKPDType */
+ strNULL, /* identifier_t itServerKPDType */
+ strNULL, /* identifier_t itInTrans */
+ strNULL, /* identifier_t itOutTrans */
+ strNULL, /* identifier_t itDestructor */
+ };
+ ipc_type_t *new;
+
+ new = (ipc_type_t *) malloc(sizeof *new);
+ if (new == itNULL)
+ fatal("itAlloc(): %s", strerror(errno));
+ *new = prototype;
+ return new;
+}
+
+/*
+ * Convert an IPC type-name into a string.
+ */
+static char *
+itNameToString(u_int name)
+{
+ char buffer[100];
+
+ (void) sprintf(buffer, "%u", name);
+ return strmake(buffer);
+}
+
+/*
+ * Calculate itTypeSize, itPadSize, itMinTypeSize
+ * Every type needs this info; it is recalculated
+ * when itInLine, itNumber, or itSize changes.
+ */
+static void
+itCalculateSizeInfo(ipc_type_t *it)
+{
+ if (!IS_KERN_PROC_DATA(it))
+ {
+ u_int bytes = (it->itNumber * it->itSize + 7) / 8;
+ u_int padding = machine_padding(bytes);
+
+ it->itTypeSize = bytes;
+ it->itPadSize = padding;
+ if (IS_VARIABLE_SIZED_UNTYPED(it)) {
+ /*
+ * for these arrays, the argCount is not a akbRequest|akbReply,
+ * therefore we need to account here for the space of the count
+ * (itMinTypeSize is used only in rtFindSize)
+ */
+ it->itMinTypeSize = sizeof (mach_msg_type_number_t);
+ /*
+ * NDR encoded VarString carry the extra offset 4-bytes fields
+ * for MIG, it should be always 0;
+ */
+ if (it->itString)
+ it->itMinTypeSize += sizeof (mach_msg_type_number_t);
+ }
+ else
+ it->itMinTypeSize = bytes + padding;
+ }
+ else {
+ /*
+ * 1) ports 2) OOL 3) ports OOL
+ * all have the same size = sizeof(mach_msg_descriptor_t)
+ */
+ u_int bytes;
+ if (IS_MULTIPLE_KPD(it))
+ bytes = it->itKPD_Number * 12 /* sizeof(mach_msg_descriptor_t) */;
+ else
+ bytes = 12 /* sizeof(mach_msg_descriptor_t) */;
+
+ it->itTypeSize = bytes;
+ it->itPadSize = 0;
+ it->itMinTypeSize = bytes;
+ }
+
+ /* Unfortunately, these warning messages can't give a type name;
+ we haven't seen a name yet (it might stay anonymous.) */
+
+ if ((it->itTypeSize == 0) && !it->itVarArray && !it->itNative)
+ warn("sizeof(%s) == 0");
+}
+
+/*
+ * Fill in default values for some fields used in code generation:
+ * itInNameStr, itOutNameStr, itUserType, itServerType, itTransType
+ * Every argument's type should have these values filled in.
+ */
+static void
+itCalculateNameInfo(ipc_type_t *it)
+{
+ if (it->itInNameStr == strNULL)
+ it->itInNameStr = strmake(itNameToString(it->itInName));
+ if (it->itOutNameStr == strNULL)
+ it->itOutNameStr = strmake(itNameToString(it->itOutName));
+
+ if (it->itUserType == strNULL)
+ it->itUserType = it->itName;
+ if (it->itServerType == strNULL)
+ it->itServerType = it->itName;
+#if 0
+ /*
+ * KernelServer and KernelUser interfaces get special treatment here.
+ * On the kernel side of the interface, ports are really internal
+ * port pointers (ipc_port_t), not port names (mach_port_t).
+ * At this point, we don't know if the argument is in or out,
+ * so we don't know if we should look at itInName or itOutName.
+ * Looking at both should be OK.
+ *
+ * This is definitely a hack, but I think it is cleaner than
+ * mucking with type declarations throughout the kernel .def files,
+ * hand-conditionalizing on KERNEL_SERVER and KERNEL_USER.
+ */
+
+ if (IsKernelServer &&
+ streql(it->itServerType, "mach_port_t") &&
+ (((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) &&
+ (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) ||
+ MACH_MSG_TYPE_PORT_ANY(it->itInName) ||
+ MACH_MSG_TYPE_PORT_ANY(it->itOutName)))
+ it->itServerType = "ipc_port_t";
+
+ if (IsKernelUser &&
+ streql(it->itUserType, "mach_port_t") &&
+ (((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) &&
+ (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) ||
+ MACH_MSG_TYPE_PORT_ANY(it->itInName) ||
+ MACH_MSG_TYPE_PORT_ANY(it->itOutName)))
+ it->itUserType = "ipc_port_t";
+#endif /* 0 */
+
+ if (it->itTransType == strNULL)
+ it->itTransType = it->itServerType;
+}
+
+/******************************************************
+ * Checks for non-implemented types, conflicting type
+ * flags and whether the long or short form of msg type
+ * descriptor is appropriate. Called after each type statement
+ * is parsed.
+ ******************************************************/
+static void
+itCheckDecl(identifier_t name, ipc_type_t *it)
+{
+ it->itName = name;
+
+ itCalculateNameInfo(it);
+
+ /* do a bit of error checking, mostly necessary because of
+ limitations in Mig */
+
+ if (it->itVarArray) {
+ if ((it->itInTrans != strNULL) || (it->itOutTrans != strNULL))
+ error("%s: can't translate variable-sized arrays", name);
+
+ if (it->itDestructor != strNULL)
+ error("%s: can't destroy variable-sized array", name);
+ }
+}
+
+/*
+ * Pretty-prints translation/destruction/type information.
+ */
+static void
+itPrintTrans(ipc_type_t *it)
+{
+ if (!streql(it->itName, it->itUserType))
+ printf("\tCUserType:\t%s\n", it->itUserType);
+
+ if (!streql(it->itName, it->itServerType))
+ printf("\tCServerType:\t%s\n", it->itServerType);
+
+ if (it->itInTrans != strNULL)
+ printf("\tInTran:\t\t%s %s(%s)\n", it->itTransType, it->itInTrans, it->itServerType);
+
+ if (it->itOutTrans != strNULL)
+ printf("\tOutTran:\t%s %s(%s)\n", it->itServerType, it->itOutTrans, it->itTransType);
+
+ if (it->itDestructor != strNULL)
+ printf("\tDestructor:\t%s(%s)\n", it->itDestructor, it->itTransType);
+}
+
+/*
+ * Pretty-prints type declarations.
+ */
+static void
+itPrintDecl(identifier_t name, ipc_type_t *it)
+{
+ printf("Type %s = ", name);
+ if (!it->itInLine)
+ printf("^ ");
+ if (it->itVarArray)
+ if (it->itNumber == 0 || it->itMigInLine)
+ printf("array [] of ");
+ else
+ printf("array [*:%d] of ", it->itNumber);
+ else if (it->itStruct && ((it->itNumber != 1) ||
+ (it->itInName == MACH_MSG_TYPE_STRING_C)))
+ printf("struct [%d] of ", it->itNumber);
+ else if (it->itNumber != 1)
+ printf("array [%d] of ", it->itNumber);
+
+ if (streql(it->itInNameStr, it->itOutNameStr))
+ printf("(%s,", it->itInNameStr);
+ else
+ printf("(%s|%s", it->itInNameStr, it->itOutNameStr);
+
+ printf(" %d)\n", it->itSize);
+
+ itPrintTrans(it);
+
+ printf("\n");
+}
+
+/*
+ * Handles named type-specs, which can occur in type
+ * declarations or in argument lists. For example,
+ * type foo = type-spec; // itInsert will get called later
+ * routine foo(arg : bar = type-spec); // itInsert won't get called
+ */
+void
+itTypeDecl(identifier_t name, ipc_type_t *it)
+{
+ itCheckDecl(name, it);
+
+ if (BeVerbose)
+ itPrintDecl(name, it);
+}
+
+/*
+ * Handles declarations like
+ * type new = name;
+ * type new = inname|outname;
+ */
+ipc_type_t *
+itShortDecl(u_int inname, string_t instr, u_int outname, string_t outstr, u_int defsize)
+{
+ ipc_type_t *it;
+
+ if (defsize == 0)
+ error("must use full IPC type decl");
+
+ it = itAlloc();
+ it->itInName = inname;
+ it->itInNameStr = instr;
+ it->itOutName = outname;
+ it->itOutNameStr = outstr;
+ it->itSize = defsize;
+ if (inname == MACH_MSG_TYPE_STRING_C)
+ {
+ it->itStruct = FALSE;
+ it->itString = TRUE;
+ }
+ /*
+ * I check only inname, because outname
+ * has to be a port as well (polymorphic types
+ * are now restricted to port rights)
+ */
+ if (MACH_MSG_TYPE_PORT_ANY(inname) ||
+ inname == MACH_MSG_TYPE_POLYMORPHIC) {
+ it->itPortType = TRUE;
+ it->itKPD_Number = 1;
+ }
+
+ itCalculateSizeInfo(it);
+ return it;
+}
+
+static ipc_type_t *
+itCopyType(ipc_type_t *old)
+{
+ ipc_type_t *new = itAlloc();
+
+ *new = *old;
+ new->itName = strNULL;
+ new->itNext = itNULL;
+ new->itElement = old;
+
+ /* size info still valid */
+ return new;
+}
+
+/*
+ * A call to itCopyType is almost always followed with itResetType.
+ * The exception is itPrevDecl. Also called before adding any new
+ * translation/destruction/type info (see parser.y).
+ *
+ * type new = old; // new doesn't get old's info
+ * type new = array[*:10] of old;
+ * // new doesn't get old's info, but new->itElement does
+ * type new = array[*:10] of struct[3] of old;
+ * // new and new->itElement don't get old's info
+ */
+
+ipc_type_t *
+itResetType(ipc_type_t *old)
+{
+ /* reset all special translation/destruction/type info */
+
+ old->itInTrans = strNULL;
+ old->itOutTrans = strNULL;
+ old->itDestructor = strNULL;
+ old->itUserType = strNULL;
+ old->itServerType = strNULL;
+ old->itTransType = strNULL;
+ return old;
+}
+
+/*
+ * Handles the declaration
+ * type new = old;
+ */
+ipc_type_t *
+itPrevDecl(identifier_t name)
+{
+ ipc_type_t *old;
+
+ old = itLookUp(name);
+ if (old == itNULL) {
+ error("type '%s' not defined", name);
+ return itAlloc();
+ }
+ else
+ return itCopyType(old);
+}
+
+/*
+ * Handles the declarations
+ * type new = array[] of old; // number is oo
+ * type new = array[*] of old; // number is oo
+ * type new = array[*:number] of old;
+ */
+ipc_type_t *
+itVarArrayDecl(u_int number, ipc_type_t *old)
+{
+ ipc_type_t *it = itResetType(itCopyType(old));
+
+ if (!it->itInLine) {
+ /* already an initialized KPD */
+ if (it->itKPD_Number != 1 || !number)
+ error("IPC type decl is too complicated for Kernel Processed Data");
+ it->itKPD_Number *= number;
+ it->itNumber = 1;
+ it->itInLine = FALSE;
+ it->itStruct = FALSE;
+ it->itOOL_Number = number;
+ }
+ else if (it->itVarArray)
+ error("IPC type decl is too complicated");
+ else if (number) {
+ it->itNumber *= number;
+ /*
+ * Bounded [Scalar, Port] VarArray: in-line!
+ */
+ it->itInLine = TRUE;
+ it->itStruct = FALSE;
+ if (it->itPortType)
+ it->itKPD_Number *= number;
+ it->itOOL_Number = number;
+ }
+ else {
+ it->itNumber = 0;
+ /*
+ * UnBounded [Scalar, Port] VarArray: always in-line
+ * interface and out-of-line mechanism!
+ */
+ it->itMigInLine = TRUE;
+ it->itInLine = FALSE;
+ it->itStruct = TRUE;
+ it->itKPD_Number = 1;
+ it->itOOL_Number = 0;
+ }
+
+ it->itVarArray = TRUE;
+ it->itString = FALSE;
+
+ itCalculateSizeInfo(it);
+ return it;
+}
+
+/*
+ * Handles the declaration
+ * type new = array[number] of old;
+ */
+ipc_type_t *
+itArrayDecl(u_int number, ipc_type_t *old)
+{
+ ipc_type_t *it = itResetType(itCopyType(old));
+
+ if (!it->itInLine) {
+ /* already an initialized KPD */
+ if (it->itKPD_Number != 1)
+ error("IPC type decl is too complicated for Kernel Processed Data");
+ it->itKPD_Number *= number;
+ it->itNumber = 1;
+ it->itStruct = FALSE;
+ it->itString = FALSE;
+ it->itVarArray = FALSE;
+ }
+ else if (it->itVarArray)
+ error("IPC type decl is too complicated");
+ else {
+ it->itNumber *= number;
+ it->itStruct = FALSE;
+ it->itString = FALSE;
+ if (it->itPortType)
+ it->itKPD_Number *= number;
+ }
+
+ itCalculateSizeInfo(it);
+ return it;
+}
+
+/*
+ * Handles the declaration
+ * type new = ^ old;
+ */
+ipc_type_t *
+itPtrDecl(ipc_type_t *it)
+{
+ if (!it->itInLine && !it->itMigInLine)
+ error("IPC type decl is already defined to be Out-Of-Line");
+ it->itInLine = FALSE;
+ it->itStruct = TRUE;
+ it->itString = FALSE;
+ it->itMigInLine = FALSE;
+ it->itKPD_Number = 1;
+
+ itCalculateSizeInfo(it);
+ return it;
+}
+
+/*
+ * Handles the declaration
+ * type new = struct[number] of old;
+ */
+ipc_type_t *
+itStructDecl(u_int number, ipc_type_t *old)
+{
+ ipc_type_t *it = itResetType(itCopyType(old));
+
+ if (!it->itInLine || it->itVarArray)
+ error("IPC type decl is too complicated");
+ it->itNumber *= number;
+ it->itStruct = TRUE;
+ it->itString = FALSE;
+
+ itCalculateSizeInfo(it);
+ return it;
+}
+
+/*
+ * Treat 'c_string[n]' as
+ * 'array[n] of (MSG_TYPE_STRING_C, 8)'
+ */
+ipc_type_t *
+itCStringDecl(int count, boolean_t varying)
+{
+ ipc_type_t *it;
+ ipc_type_t *itElement;
+
+ itElement = itShortDecl(MACH_MSG_TYPE_STRING_C, "MACH_MSG_TYPE_STRING_C", MACH_MSG_TYPE_STRING_C, "MACH_MSG_TYPE_STRING_C", 8);
+ itCheckDecl("char", itElement);
+
+ it = itResetType(itCopyType(itElement));
+ it->itNumber = count;
+ it->itVarArray = varying;
+ it->itStruct = FALSE;
+ it->itString = TRUE;
+
+ itCalculateSizeInfo(it);
+ return it;
+}
+
+extern ipc_type_t *
+itMakeSubCountType(int count, boolean_t varying, string_t name)
+{
+ ipc_type_t *it;
+ ipc_type_t *itElement;
+
+ itElement = itShortDecl(machine_integer_size, machine_integer_name, machine_integer_size, machine_integer_name, machine_integer_bits);
+ itCheckDecl("mach_msg_type_number_t", itElement);
+
+ it = itResetType(itCopyType(itElement));
+ it->itNumber = count;
+ /*
+ * I cannot consider it as a Fixed array, otherwise MiG will try
+ * to follow the path for efficient copy of arrays
+ */
+ it->itVarArray = FALSE;
+ it->itStruct = FALSE;
+ it->itString = FALSE;
+ it->itInLine = TRUE;
+ it->itName = "mach_msg_type_number_t *";
+ if (varying)
+ it->itVarArray = TRUE;
+ else
+ /* to skip the optimized copy of fixed array: in fact we need to
+ * reference each element and we also miss a user type for it */
+ it->itNoOptArray = TRUE;
+
+ itCalculateSizeInfo(it);
+ itCalculateNameInfo(it);
+ return it;
+}
+
+extern ipc_type_t *
+itMakeCountType(void)
+{
+ ipc_type_t *it = itAlloc();
+
+ it->itName = "mach_msg_type_number_t";
+ it->itInName = machine_integer_size;
+ it->itInNameStr = machine_integer_name;
+ it->itOutName = machine_integer_size;
+ it->itOutNameStr = machine_integer_name;
+ it->itSize = machine_integer_bits;
+
+ itCalculateSizeInfo(it);
+ itCalculateNameInfo(it);
+ return it;
+}
+
+extern ipc_type_t *
+itMakePolyType(void)
+{
+ ipc_type_t *it = itAlloc();
+
+ it->itName = "mach_msg_type_name_t";
+ it->itInName = machine_integer_size;
+ it->itInNameStr = machine_integer_name;
+ it->itOutName = machine_integer_size;
+ it->itOutNameStr = machine_integer_name;
+ it->itSize = machine_integer_bits;
+
+ itCalculateSizeInfo(it);
+ itCalculateNameInfo(it);
+ return it;
+}
+
+extern ipc_type_t *
+itMakeDeallocType(void)
+{
+ ipc_type_t *it = itAlloc();
+
+ it->itName = "boolean_t";
+ it->itInName = MACH_MSG_TYPE_BOOLEAN;
+ it->itInNameStr = "MACH_MSG_TYPE_BOOLEAN";
+ it->itOutName = MACH_MSG_TYPE_BOOLEAN;
+ it->itOutNameStr = "MACH_MSG_TYPE_BOOLEAN";
+ it->itSize = machine_integer_bits;
+
+ itCalculateSizeInfo(it);
+ itCalculateNameInfo(it);
+ return it;
+}
+
+extern ipc_type_t *
+itNativeType(identifier_t id, boolean_t ptr, identifier_t badval)
+{
+ ipc_type_t *it = itAlloc();
+
+ it->itInName = MACH_MSG_TYPE_BYTE;
+ it->itInNameStr = "MACH_MSG_TYPE_BYTE";
+ it->itOutName = MACH_MSG_TYPE_BYTE;
+ it->itOutNameStr = "MACH_MSG_TYPE_BYTE";
+ it->itInLine = TRUE;
+ it->itNative = TRUE;
+ it->itNativePointer = ptr;
+ it->itServerType = id;
+ it->itUserType = id;
+ it->itTransType = id;
+ it->itBadValue = badval;
+
+ itCalculateSizeInfo(it);
+ itCalculateNameInfo(it);
+ return it;
+}
+
+/*
+ * Initializes the pre-defined types.
+ */
+void
+init_type(void)
+{
+ u_int size;
+
+ size = NBBY * sizeof (natural_t);
+ if (size == 32) {
+ machine_integer_name = "MACH_MSG_TYPE_INTEGER_32";
+ machine_integer_size = MACH_MSG_TYPE_INTEGER_32;
+ }
+ else if (size == 64) {
+ machine_integer_name = "MACH_MSG_TYPE_INTEGER_64";
+ machine_integer_size = MACH_MSG_TYPE_INTEGER_64;
+ }
+ else
+ error("init_type unknown size %d", size);
+
+ machine_integer_bits = size;
+
+ itRetCodeType = itAlloc();
+ itRetCodeType->itName = "kern_return_t";
+ itRetCodeType->itInName = machine_integer_size;
+ itRetCodeType->itInNameStr = machine_integer_name;
+ itRetCodeType->itOutName = machine_integer_size;
+ itRetCodeType->itOutNameStr = machine_integer_name;
+ itRetCodeType->itSize = machine_integer_bits;
+ itCalculateSizeInfo(itRetCodeType);
+ itCalculateNameInfo(itRetCodeType);
+
+ itNdrCodeType = itAlloc();
+ itNdrCodeType->itName = "NDR_record_t";
+ itNdrCodeType->itInName = 0;
+ itNdrCodeType->itInNameStr = "NDR_record_t";
+ itNdrCodeType->itOutName = 0;
+ itNdrCodeType->itOutNameStr = "NDR_record_t";
+ itNdrCodeType->itSize = sizeof(NDR_record_t) * 8;
+ itCalculateSizeInfo(itNdrCodeType);
+ itCalculateNameInfo(itNdrCodeType);
+
+ itDummyType = itAlloc();
+ itDummyType->itName = "char *";
+ itDummyType->itInName = MACH_MSG_TYPE_UNSTRUCTURED;
+ itDummyType->itInNameStr = "MACH_MSG_TYPE_UNSTRUCTURED";
+ itDummyType->itOutName = MACH_MSG_TYPE_UNSTRUCTURED;
+ itDummyType->itOutNameStr = "MACH_MSG_TYPE_UNSTRUCTURED";
+ itDummyType->itSize = PortSize;
+ itCalculateSizeInfo(itDummyType);
+ itCalculateNameInfo(itDummyType);
+
+ itTidType = itAlloc();
+ itTidType->itName = "tid_t";
+ itTidType->itInName = machine_integer_size;
+ itTidType->itInNameStr = machine_integer_name;
+ itTidType->itOutName = machine_integer_size;
+ itTidType->itOutNameStr = machine_integer_name;
+ itTidType->itSize = machine_integer_bits;
+ itTidType->itNumber = 6;
+ itCalculateSizeInfo(itTidType);
+ itCalculateNameInfo(itTidType);
+
+ itRequestPortType = itAlloc();
+ itRequestPortType->itName = "mach_port_t";
+ itRequestPortType->itInName = MACH_MSG_TYPE_COPY_SEND;
+ itRequestPortType->itInNameStr = "MACH_MSG_TYPE_COPY_SEND";
+ itRequestPortType->itOutName = MACH_MSG_TYPE_PORT_SEND;
+ itRequestPortType->itOutNameStr = "MACH_MSG_TYPE_PORT_SEND";
+ itRequestPortType->itSize = PortSize;
+ itCalculateSizeInfo(itRequestPortType);
+ itCalculateNameInfo(itRequestPortType);
+
+ itZeroReplyPortType = itAlloc();
+ itZeroReplyPortType->itName = "mach_port_t";
+ itZeroReplyPortType->itInName = 0;
+ itZeroReplyPortType->itInNameStr = "0";
+ itZeroReplyPortType->itOutName = 0;
+ itZeroReplyPortType->itOutNameStr = "0";
+ itZeroReplyPortType->itSize = PortSize;
+ itCalculateSizeInfo(itZeroReplyPortType);
+ itCalculateNameInfo(itZeroReplyPortType);
+
+ itRealReplyPortType = itAlloc();
+ itRealReplyPortType->itName = "mach_port_t";
+ itRealReplyPortType->itInName = MACH_MSG_TYPE_MAKE_SEND_ONCE;
+ itRealReplyPortType->itInNameStr = "MACH_MSG_TYPE_MAKE_SEND_ONCE";
+ itRealReplyPortType->itOutName = MACH_MSG_TYPE_PORT_SEND_ONCE;
+ itRealReplyPortType->itOutNameStr = "MACH_MSG_TYPE_PORT_SEND_ONCE";
+ itRealReplyPortType->itSize = PortSize;
+ itCalculateSizeInfo(itRealReplyPortType);
+ itCalculateNameInfo(itRealReplyPortType);
+
+ itWaitTimeType = itMakeCountType();
+ itMsgOptionType = itMakeCountType();
+}
+
+/******************************************************
+ * Make sure return values of functions are assignable.
+ ******************************************************/
+void
+itCheckReturnType(identifier_t name, ipc_type_t *it)
+{
+ if (!it->itStruct)
+ error("type of %s is too complicated", name);
+ if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) ||
+ (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC))
+ error("type of %s can't be polymorphic", name);
+}
+
+
+/******************************************************
+ * Called by routine.c to check that request ports are
+ * simple and correct ports with send rights.
+ ******************************************************/
+void
+itCheckRequestPortType(identifier_t name, ipc_type_t *it)
+{
+ /* error("Port size = %d %d name = %s\n", PortSize, it->itSize, it->itName);
+ error("server = %s user = %x\n",it->itServerType, it->itUserType);
+ */
+ if (((it->itOutName != MACH_MSG_TYPE_PORT_SEND) &&
+ (it->itOutName != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
+ (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC)) ||
+ (it->itNumber != 1) ||
+ (it->itSize != PortSize) ||
+ !it->itInLine ||
+ !it->itStruct ||
+ it->itVarArray)
+ error("argument %s isn't a proper request port", name);
+}
+
+
+/******************************************************
+ * Called by routine.c to check that reply ports are
+ * simple and correct ports with send rights.
+ ******************************************************/
+void
+itCheckReplyPortType(identifier_t name, ipc_type_t *it)
+{
+ if (((it->itOutName != MACH_MSG_TYPE_PORT_SEND) &&
+ (it->itOutName != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
+ (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) &&
+ (it->itOutName != 0)) ||
+ (it->itNumber != 1) ||
+ (it->itSize != PortSize) ||
+ !it->itInLine ||
+ !it->itStruct ||
+ it->itVarArray)
+ error("argument %s isn't a proper reply port", name);
+}
+
+
+/******************************************************
+ * Used by routine.c to check that WaitTime is a
+ * simple bit machine_integer_bits integer.
+ ******************************************************/
+void
+itCheckIntType(identifier_t name, ipc_type_t *it)
+{
+ if ((it->itInName != machine_integer_size) ||
+ (it->itOutName != machine_integer_size) ||
+ (it->itNumber != 1) ||
+ (it->itSize != machine_integer_bits) ||
+ !it->itInLine ||
+ !it->itStruct ||
+ it->itVarArray)
+ error("argument %s isn't a proper integer", name);
+}
+
+void
+itCheckTokenType(identifier_t name, ipc_type_t *it)
+{
+ if (it->itMigInLine || it->itNoOptArray || it->itString ||
+ it->itTypeSize != 8 || !it->itInLine || !it->itStruct ||
+ it->itVarArray || it->itPortType)
+ error("argument %s isn't a proper Token", name);
+
+}
diff --git a/bootstrap_cmds/migcom.tproj/type.h b/bootstrap_cmds/migcom.tproj/type.h
new file mode 100644
index 0000000..b1b514b
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/type.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* HISTORY
+ * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University
+ * Extensive revamping. Added polymorphic arguments.
+ * Allow multiple variable-sized inline arguments in messages.
+ *
+ * 16-Nov-87 David Golub (dbg) at Carnegie-Mellon University
+ * Changed itVarArrayDecl to take a 'max' parameter.
+ * Added itDestructor.
+ *
+ * 18-Aug-87 Mary Thompson @ Carnegie Mellon
+ * Added itPortType
+ * Added itTidType
+ */
+
+#ifndef _TYPE_H
+#define _TYPE_H
+
+#include <mach/boolean.h>
+#include "strdefs.h"
+
+#ifdef linux
+#include <linux/types.h>
+#else /* linux */
+#include <sys/types.h>
+#endif /* linux */
+typedef u_int ipc_flags_t;
+
+/*
+ * MIG built-in types
+ */
+#define MACH_MSG_TYPE_UNSTRUCTURED 0
+#define MACH_MSG_TYPE_BIT 0
+#define MACH_MSG_TYPE_BOOLEAN 0
+#define MACH_MSG_TYPE_INTEGER_8 9
+#define MACH_MSG_TYPE_INTEGER_16 1
+#define MACH_MSG_TYPE_INTEGER_32 2
+#define MACH_MSG_TYPE_INTEGER_64 3
+#define MACH_MSG_TYPE_CHAR 8
+#define MACH_MSG_TYPE_BYTE 9
+#define MACH_MSG_TYPE_REAL_32 10
+#define MACH_MSG_TYPE_REAL_64 11
+#define MACH_MSG_TYPE_STRING 12
+#define MACH_MSG_TYPE_STRING_C 12
+
+#define flNone (0x00)
+#define flPhysicalCopy (0x01) /* Physical Copy specified */
+#define flOverwrite (0x02) /* Overwrite mode specified */
+#define flDealloc (0x04) /* Dealloc specified */
+#define flNotDealloc (0x08) /* NotDealloc specified */
+#define flMaybeDealloc (0x10) /* Dealloc[] specified */
+#define flSameCount (0x20) /* SamCount specified, used by co-bounded arrays */
+#define flCountInOut (0x40) /* CountInOut specified */
+#define flRetCode (0x80) /* RetCode specified */
+#define flAuto (0x100) /* Will not be referenced by server after RPC */
+#define flConst (0x200) /* Will not be modified by server during RPC */
+
+typedef enum dealloc {
+ d_NO, /* do not deallocate */
+ d_YES, /* always deallocate */
+ d_MAYBE /* deallocate according to parameter */
+} dealloc_t;
+
+/* Convert dealloc_t to TRUE/FALSE */
+#define strdealloc(d) (strbool(d == d_YES))
+
+/*
+ * itName and itNext are internal fields (not used for code generation).
+ * They are only meaningful for types entered into the symbol table.
+ * The symbol table is a simple self-organizing linked list.
+ *
+ * The function itCheckDecl checks & fills in computed information.
+ * Every type actually used (pointed at by argType) is so processed.
+ *
+ * The itInName, itOutName, itSize, itNumber, fields correspond directly
+ * to mach_msg_type_t fields.
+ * For out-of-line variable sized types, itNumber is zero. For
+ * in-line variable sized types, itNumber is the maximum size of the
+ * array. itInName is the name value supplied to the kernel,
+ * and itOutName is the name value received from the kernel.
+ * When the type describes a MACH port, either or both may be
+ * MACH_MSG_TYPE_POLYMORPHIC, indicating a "polymorphic" name.
+ * For itInName, this means the user supplies the value with an argument.
+ * For itOutName, this means the value is returned in an argument.
+ *
+ * The itInNameStr and itOutNameStr fields contain "printing" versions
+ * of the itInName and itOutName values. The mapping from number->string
+ * is not into (eg, MACH_MSG_TYPE_UNSTRUCTURED/MACH_MSG_TYPE_BOOLEAN/
+ * MACH_MSG_TYPE_BIT). These fields are used for code-generation and
+ * pretty-printing.
+ *
+ * itTypeSize is the calculated size of the C type, in bytes.
+ * itPadSize is the size of any padded needed after the data field.
+ * itMinTypeSize is the minimum size of the data field, including padding.
+ * For variable-length inline data, it is zero.
+ *
+ * itUserType, itServerType, itTransType are the C types used in
+ * code generation. itUserType is the C type passed to the user-side stub
+ * and used for msg declarations in the user-side stub. itServerType
+ * is the C type used for msg declarations in the server-side stub.
+ * itTransType is the C type passed to the server function by the
+ * server-side stub. Normally it differs from itServerType only when
+ * translation functions are defined.
+ *
+ * itInTrans and itOutTrans are translation functions. itInTrans
+ * takes itServerType values and returns itTransType values. itOutTrans
+ * takes itTransType vaulues and returns itServerType values.
+ * itDestructor is a finalization function applied to In arguments
+ * after the server-side stub calls the server function. It takes
+ * itTransType values. Any combination of these may be defined.
+ *
+ * The following type specification syntax modifies these values:
+ * type new = old
+ * ctype: name // itUserType and itServerType
+ * cusertype: itUserType
+ * cservertype: itServerType
+ * intran: itTransType itInTrans(itServerType)
+ * outtran: itServerType itOutTrans(itTransType)
+ * destructor: itDestructor(itTransType);
+ *
+ * At most one of itStruct and itString should be TRUE. If both are
+ * false, then this is assumed to be an array type (msg data is passed
+ * by reference). If itStruct is TRUE, then msg data is passed by value
+ * and can be assigned with =. If itString is TRUE, then the msg_data
+ * is a null-terminated string, assigned with strncpy. The itNumber
+ * value is a maximum length for the string; the msg field always
+ * takes up this much space.
+ * NoOptArray has been introduced for the cases where the special
+ * code generated for array assignments would not work (either because
+ * there is not a ctype (array of automagically generated MiG variables)
+ * or because we need to reference the single elements of the array
+ * (array of variable sized ool regions).
+ *
+ * itVarArray means this is a variable-sized array. If it is inline,
+ * then itStruct and itString are FALSE. If it is out-of-line, then
+ * itStruct is TRUE (because pointers can be assigned).
+ *
+ * itMigInLine means this is an indefinite-length array. Although the
+ * argument was not specified as out-of-line, MIG will send it anyway
+ * os an out-of-line.
+ *
+ * itUserKPDType (itServerKPDType) identify the type of Kernel Processed
+ * Data that we must deal with: it can be either "mach_msg_port_descriptor_t"
+ * or "mach_msg_ool_ports_descriptor_t" or "mach_msg_ool_descriptor_t".
+ *
+ * itKPD_Number is used any time a single argument require more than
+ * one Kernel Processed Data entry: i.e., an in-line array of ports, an array
+ * of pointers (out-of-line data)
+ *
+ * itElement points to any substructure that the type may have.
+ * It is only used with variable-sized array types.
+ */
+
+typedef struct ipc_type
+ {
+ identifier_t itName; /* Mig's name for this type */
+ struct ipc_type *itNext; /* next type in symbol table */
+
+ u_int itTypeSize; /* size of the C type */
+ u_int itPadSize; /* amount of padding after data */
+ u_int itMinTypeSize; /* minimal amount of space occupied by data */
+
+ u_int itInName; /* name supplied to kernel in sent msg */
+ u_int itOutName; /* name in received msg */
+ u_int itSize;
+ u_int itNumber;
+ u_int itKPD_Number; /* number of Kernel Processed Data entries */
+ boolean_t itInLine;
+ boolean_t itMigInLine; /* MiG presents data as InLine, although it is sent OOL */
+ boolean_t itPortType;
+
+ string_t itInNameStr; /* string form of itInName */
+ string_t itOutNameStr; /* string form of itOutName */
+
+ boolean_t itStruct;
+ boolean_t itString;
+ boolean_t itVarArray;
+ boolean_t itNoOptArray;
+ boolean_t itNative; /* User specified a native (C) type. */
+ boolean_t itNativePointer;/* The user will pass a pointer to the */
+ /* native C type. */
+
+ struct ipc_type *itElement; /* may be NULL */
+
+ identifier_t itUserType;
+ identifier_t itServerType;
+ identifier_t itTransType;
+
+ identifier_t itKPDType; /* descriptors for KPD type of arguments */
+
+ identifier_t itInTrans; /* may be NULL */
+ identifier_t itOutTrans; /* may be NULL */
+ identifier_t itDestructor;/* may be NULL */
+ identifier_t itBadValue; /* Excluded value for PointerToIfNot. May
+ be NULL. */
+ u_int itOOL_Number;
+ } ipc_type_t;
+
+enum {
+ ConsumeOnSendErrorNone,
+ ConsumeOnSendErrorTimeout,
+ ConsumeOnSendErrorAny,
+};
+
+
+#define itNULL ((ipc_type_t *) 0)
+
+#define itWordAlign sizeof(natural_t)
+
+extern ipc_type_t *itLookUp(identifier_t name);
+extern void itInsert(identifier_t name, ipc_type_t *it);
+extern void itTypeDecl(identifier_t name, ipc_type_t *it);
+
+extern ipc_type_t *itShortDecl(u_int inname, string_t instr,
+ u_int outname, string_t outstr,
+ u_int dfault);
+extern ipc_type_t *itPrevDecl(identifier_t name);
+extern ipc_type_t *itResetType(ipc_type_t *it);
+extern ipc_type_t *itVarArrayDecl(u_int number, ipc_type_t *it);
+extern ipc_type_t *itArrayDecl(u_int number, ipc_type_t *it);
+extern ipc_type_t *itPtrDecl(ipc_type_t *it);
+extern ipc_type_t *itStructDecl(u_int number, ipc_type_t *it);
+extern ipc_type_t *itCStringDecl(int count, boolean_t varying);
+extern ipc_type_t *itNativeType(identifier_t CType, boolean_t pointer,
+ identifier_t NotVal);
+
+extern ipc_type_t *itRetCodeType;
+extern ipc_type_t *itNdrCodeType;
+extern ipc_type_t *itDummyType;
+extern ipc_type_t *itTidType;
+extern ipc_type_t *itRequestPortType;
+extern ipc_type_t *itZeroReplyPortType;
+extern ipc_type_t *itRealReplyPortType;
+extern ipc_type_t *itWaitTimeType;
+extern ipc_type_t *itMsgOptionType;
+extern ipc_type_t *itMakeCountType(void);
+extern ipc_type_t *itMakeSubCountType(int count, boolean_t varying, string_t name);
+extern ipc_type_t *itMakePolyType(void);
+extern ipc_type_t *itMakeDeallocType(void);
+
+extern void init_type(void);
+
+extern void itCheckReturnType(identifier_t name, ipc_type_t *it);
+extern void itCheckRequestPortType(identifier_t name, ipc_type_t *it);
+extern void itCheckReplyPortType(identifier_t name, ipc_type_t *it);
+extern void itCheckIntType(identifier_t name, ipc_type_t *it);
+extern void itCheckTokenType(identifier_t name, ipc_type_t *it);
+
+#endif /* _TYPE_H */
diff --git a/bootstrap_cmds/migcom.tproj/user.c b/bootstrap_cmds/migcom.tproj/user.c
new file mode 100644
index 0000000..839732d
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/user.c
@@ -0,0 +1,3260 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <mach/message.h>
+#include "write.h"
+#include "error.h"
+#include "utils.h"
+#include "global.h"
+
+#ifndef DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT
+#define DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT 1
+#endif
+
+#ifndef DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR
+#define DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR 1
+#endif
+
+#ifndef USE_IMMEDIATE_SEND_TIMEOUT
+#define USE_IMMEDIATE_SEND_TIMEOUT 0
+#endif
+
+char *MessAllocRoutine = "mig_user_allocate";
+char *MessFreeRoutine = "mig_user_deallocate";
+
+char stRetCode[] = "ReturnValue";
+char stRetNone[] = "";
+
+void WriteLogDefines(FILE *file, string_t who);
+void WriteIdentificationString(FILE *file);
+
+static void
+WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t overwrite, boolean_t varying, argument_t *arg, boolean_t bracket)
+{
+ ipc_type_t *it = arg->argType;
+ char string[MAX_STR_LEN];
+
+ fprintf(file, "\t{\n");
+ fprintf(file, "\t %s\t*ptr;\n", it->itKPDType);
+ fprintf(file, "\t int\ti");
+ if (varying && !in)
+ fprintf(file, ", j");
+ fprintf(file, ";\n\n");
+
+ if (in)
+ sprintf(string, "InP");
+ else if (overwrite)
+ sprintf(string, "InOvTemplate");
+ else
+ sprintf(string, "Out%dP", arg->argRequestPos);
+
+ fprintf(file, "\t ptr = &%s->%s[0];\n", string, arg->argMsgField);
+
+ if (varying) {
+ argument_t *count = arg->argCount;
+ char *cref = count->argByReferenceUser ? "*" : "";
+
+ if (in || overwrite) {
+ fprintf(file, "\t if (%s%s > %d)\n", cref, count->argVarName, it->itKPD_Number);
+ WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
+ fprintf(file, "\t for (i = 0; i < %s%s; ptr++, i++) %s\n", cref, count->argVarName, (bracket) ? "{" : "");
+ }
+ else {
+ fprintf(file, "\t j = min(Out%dP->%s, %s%s);\n", count->argReplyPos, count->argVarName, cref, count->argVarName);
+ fprintf(file, "\t for (i = 0; i < j; ptr++, i++) %s\n",(bracket) ? "{" : "");
+}
+ }
+ else
+ fprintf(file, "\t for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number, (bracket) ? "{" : "");
+}
+
+/*************************************************************
+ * Writes the standard includes. The subsystem specific
+ * includes are in <SubsystemName>.h and writen by
+ * header:WriteHeader. Called by WriteProlog.
+ *************************************************************/
+static void
+WriteMyIncludes(FILE *file, statement_t *stats)
+{
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelServer)
+ {
+ /*
+ * We want to get the user-side definitions of types
+ * like task_t, ipc_space_t, etc. in mach/mach_types.h.
+ */
+
+ fprintf(file, "#undef\tMACH_KERNEL\n");
+
+ if (InternalHeaderFileName != strNULL)
+ {
+ char *cp;
+
+ /* Strip any leading path from InternalHeaderFileName. */
+ cp = strrchr(InternalHeaderFileName, '/');
+ if (cp == 0)
+ cp = InternalHeaderFileName;
+ else
+ cp++; /* skip '/' */
+ fprintf(file, "#include \"%s\"\n", cp);
+ }
+ }
+#endif
+
+ if (UserHeaderFileName == strNULL || UseSplitHeaders)
+ WriteIncludes(file, TRUE, FALSE);
+ if (UserHeaderFileName != strNULL)
+ {
+ char *cp;
+
+ /* Strip any leading path from UserHeaderFileName. */
+ cp = strrchr(UserHeaderFileName, '/');
+ if (cp == 0)
+ cp = UserHeaderFileName;
+ else
+ cp++; /* skip '/' */
+ fprintf(file, "#include \"%s\"\n", cp);
+ }
+ if (UseSplitHeaders)
+ WriteImplImports(file, stats, TRUE);
+
+ if (UseEventLogger) {
+ if (IsKernelUser) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "#include <mig_debug.h>\n");
+ fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
+ }
+ fprintf(file, "#if MIG_DEBUG\n");
+ fprintf(file, "#include <mach/mig_log.h>\n");
+ fprintf(file, "#endif /* MIG_DEBUG */\n");
+ }
+ if (HasConsumeOnSendError && !IsKernelUser) {
+ fprintf(file, "#include <mach/mach.h>\n");
+ }
+ if (BeLint) {
+ fprintf(file, "/* LINTLIBRARY */\n");
+ }
+ fprintf(file, "\n");
+ if (!BeAnsiC) {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "#else\t/* %s */\n", NewCDecl);
+ fprintf(file, "extern mach_port_t mig_get_reply_port();\n");
+ fprintf(file, "extern void mig_dealloc_reply_port();\n");
+ fprintf(file, "extern char *%s();\n", MessAllocRoutine);
+ fprintf(file, "extern void %s();\n", MessFreeRoutine);
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+ if (HasUseSpecialReplyPort) {
+ fprintf(file, "\n");
+ fprintf(file, "#include <TargetConditionals.h>\n");
+ fprintf(file, "#include <mach/mach_sync_ipc.h>\n");
+#if DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR
+ fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n");
+ fprintf(file, "#if TARGET_OS_SIMULATOR\n");
+ fprintf(file, "#define __MigCanUseSpecialReplyPort 0\n");
+ fprintf(file, "#define mig_get_special_reply_port() MACH_PORT_DEAD\n");
+ fprintf(file, "#define mig_dealloc_special_reply_port(port) __builtin_trap()\n");
+ fprintf(file, "#endif\n");
+ fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n");
+#endif
+#if DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT
+ fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n");
+ fprintf(file, "#if TARGET_OS_OSX\n");
+ fprintf(file, "extern _Bool _os_xbs_chrooted;\n");
+ fprintf(file, "#define __MigCanUseSpecialReplyPort (!_os_xbs_chrooted)\n");
+ fprintf(file, "#endif\n");
+ fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n");
+#endif
+ fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n");
+ fprintf(file, "#define __MigCanUseSpecialReplyPort 1\n");
+ fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n");
+ fprintf(file, "#ifndef __MigSpecialReplyPortMsgOption\n");
+ fprintf(file, "#define __MigSpecialReplyPortMsgOption (__MigCanUseSpecialReplyPort ? "
+ "(MACH_SEND_SYNC_OVERRIDE|MACH_SEND_SYNC_USE_THRPRI|MACH_RCV_SYNC_WAIT) : MACH_MSG_OPTION_NONE)\n");
+ fprintf(file, "#endif /* __MigSpecialReplyPortMsgOption */\n");
+ }
+ /*
+ * extern the definition of mach_msg_destroy
+ * (to avoid inserting mach/mach.h everywhere)
+ */
+ fprintf(file, "/* TODO: #include <mach/mach.h> */\n");
+ fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n");
+ fprintf(file, "extern void mach_msg_destroy(mach_msg_header_t *);\n");
+ fprintf(file, "#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n");
+
+ fprintf(file, "\n");
+}
+
+static void
+WriteGlobalDecls(FILE *file)
+{
+ if (RCSId != strNULL)
+ WriteRCSDecl(file, strconcat(SubsystemName, "_user"), RCSId);
+
+ fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
+ fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
+ fprintf(file, "\n");
+ if (UseEventLogger)
+ WriteLogDefines(file, "MACH_MSG_LOG_USER");
+ fprintf(file, "\n");
+}
+
+static void
+WriteOneMachErrorDefine(FILE *file, char *name, boolean_t timeout, boolean_t SpecialReplyPort)
+{
+ fprintf(file, "#ifndef\t%s\n", name);
+ fprintf(file, "#define\t%s(_R_) { \\\n", name);
+ fprintf(file, "\tswitch (_R_) { \\\n");
+ fprintf(file, "\tcase MACH_SEND_INVALID_DATA: \\\n");
+ fprintf(file, "\tcase MACH_SEND_INVALID_DEST: \\\n");
+ fprintf(file, "\tcase MACH_SEND_INVALID_HEADER: \\\n");
+ if (SpecialReplyPort) {
+ fprintf(file, "\t\tif (!__MigCanUseSpecialReplyPort) { \\\n");
+ fprintf(file, "\t\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n");
+ fprintf(file, "\t\t} \\\n");
+ } else {
+ fprintf(file, "\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n");
+ }
+ fprintf(file, "\t\tbreak; \\\n");
+ if (timeout) {
+ fprintf(file, "\tcase MACH_SEND_TIMED_OUT: \\\n");
+ fprintf(file, "\tcase MACH_RCV_TIMED_OUT: \\\n");
+ }
+ fprintf(file, "\tdefault: \\\n");
+ if (SpecialReplyPort) {
+ fprintf(file, "\t\tif (__MigCanUseSpecialReplyPort) { \\\n");
+ fprintf(file, "\t\t\tmig_dealloc_special_reply_port(InP->Head.msgh_reply_port); \\\n");
+ fprintf(file, "\t\t} else { \\\n");
+ fprintf(file, "\t\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n");
+ fprintf(file, "\t\t} \\\n");
+ } else {
+ fprintf(file, "\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n");
+ }
+ fprintf(file, "\t} \\\n}\n");
+ fprintf(file, "#endif\t/* %s */\n", name);
+ fprintf(file, "\n");
+}
+
+static void
+WriteMachErrorDefines(FILE *file)
+{
+ WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeout", TRUE, FALSE);
+ WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeout", FALSE, FALSE);
+ if (HasUseSpecialReplyPort) {
+ WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeoutSRP", TRUE, TRUE);
+ WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeoutSRP", FALSE, TRUE);
+ }
+}
+
+static void
+WriteMIGCheckDefines(FILE *file)
+{
+ fprintf(file, "#define\t__MIG_check__Reply__%s_subsystem__ 1\n", SubsystemName);
+ fprintf(file, "\n");
+}
+
+static void
+WriteNDRDefines(FILE *file)
+{
+ fprintf(file, "#define\t__NDR_convert__Reply__%s_subsystem__ 1\n", SubsystemName);
+ fprintf(file, "#define\t__NDR_convert__mig_reply_error_subsystem__ 1\n");
+ fprintf(file, "\n");
+}
+
+/*************************************************************
+ * Writes the standard #includes, #defines, and
+ * RCS declaration. Called by WriteUser.
+ *************************************************************/
+static void
+WriteProlog(FILE *file, statement_t *stats)
+{
+ WriteIdentificationString(file);
+ WriteMIGCheckDefines(file);
+ if (CheckNDR)
+ WriteNDRDefines(file);
+ WriteMyIncludes(file, stats);
+ WriteBogusDefines(file);
+ WriteMachErrorDefines(file);
+ WriteApplDefaults(file, "Send");
+ WriteGlobalDecls(file);
+}
+
+/*ARGSUSED*/
+static void
+WriteEpilog(FILE *file)
+{
+ /* nothing to see here, move along... */
+}
+
+static string_t
+WriteHeaderPortType(argument_t *arg)
+{
+ if (arg->argType->itInName == MACH_MSG_TYPE_POLYMORPHIC)
+ return arg->argPoly->argVarName;
+ else
+ return arg->argType->itInNameStr;
+}
+
+static void
+WriteRequestHead(FILE *file, routine_t *rt)
+{
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest)
+ fprintf(file, "ready_to_send:\n");
+
+ if (rt->rtMaxRequestPos > 0) {
+ if (rt->rtOverwrite)
+ fprintf(file, "\tInP = &MessRequest;\n");
+ else
+ fprintf(file, "\tInP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->"));
+ }
+
+ fprintf(file, "\tInP->Head.msgh_bits =");
+ if (rt->rtRetCArg == argNULL && !rt->rtSimpleRequest)
+ fprintf(file, " MACH_MSGH_BITS_COMPLEX|");
+ fprintf(file, "\n");
+ fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n", WriteHeaderPortType(rt->rtRequestPort), WriteHeaderPortType(rt->rtReplyPort));
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ fprintf(file, "\tif (!%s)\n", rt->rtRetCArg->argVarName);
+ fprintf(file, "\t\tInP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
+ }
+
+
+ fprintf(file, "\t/* msgh_size passed as argument */\n");
+
+ /*
+ * KernelUser stubs need to cast the request and reply ports
+ * from ipc_port_t to mach_port_t.
+ */
+
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelUser)
+ fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName);
+ else
+#endif
+ fprintf(file, "\tInP->%s = %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName);
+
+ if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) {
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelUser)
+ fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName);
+ else
+#endif
+ fprintf(file, "\tInP->%s = %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName);
+ }
+ else if (rt->rtOneWay)
+ fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n", rt->rtReplyPort->argMsgField);
+ else if (rt->rtUseSpecialReplyPort)
+ fprintf(file, "\tInP->%s = __MigCanUseSpecialReplyPort ? mig_get_special_reply_port() : mig_get_reply_port();\n", rt->rtReplyPort->argMsgField);
+ else
+ fprintf(file, "\tInP->%s = mig_get_reply_port();\n", rt->rtReplyPort->argMsgField);
+
+ fprintf(file, "\tInP->Head.msgh_id = %d;\n", rt->rtNumber + SubsystemBase);
+ fprintf(file, "\tInP->Head.msgh_reserved = 0;\n");
+
+
+ if (IsVoucherCodeAllowed && !IsKernelUser && !IsKernelServer) {
+ fprintf(file, "\t\n/* BEGIN VOUCHER CODE */\n\n");
+ fprintf(file, "#ifdef USING_VOUCHERS\n");
+ fprintf(file, "\tif (voucher_mach_msg_set != NULL) {\n");
+ fprintf(file, "\t\tvoucher_mach_msg_set(&InP->Head);\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif // USING_VOUCHERS\n");
+ fprintf(file, "\t\n/* END VOUCHER CODE */\n");
+ }
+}
+
+/*************************************************************
+ * Writes declarations for the message types, variables
+ * and return variable if needed. Called by WriteRoutine.
+ *************************************************************/
+static void
+WriteVarDecls(FILE *file, routine_t *rt)
+{
+ int i;
+
+ if (rt->rtOverwrite) {
+ fprintf(file, "\tRequest MessRequest;\n");
+ fprintf(file, "\tRequest *InP = &MessRequest;\n\n");
+
+ fprintf(file, "\tunion {\n");
+ fprintf(file, "\t\tOverwriteTemplate In;\n");
+ fprintf(file, "\t\tReply Out;\n");
+ fprintf(file, "\t} MessReply;\n");
+
+ fprintf(file, "\tOverwriteTemplate *InOvTemplate = &MessReply.In;\n");
+ fprintf(file, "\tReply *Out0P = &MessReply.Out;\n");
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i);
+ }
+ else {
+ if (rtMessOnStack(rt))
+ fprintf(file, "\tunion {\n");
+ else
+ fprintf(file, "\tunion %sMessU {\n", rt->rtName);
+ fprintf(file, "\t\tRequest In;\n");
+ if (!rt->rtOneWay)
+ fprintf(file, "\t\tReply Out;\n");
+ if (rtMessOnStack(rt))
+ fprintf(file, "\t} Mess;\n");
+ else
+ fprintf(file, "\t} *Mess = (union %sMessU *) %s(sizeof(*Mess));\n",
+ rt->rtName, MessAllocRoutine);
+ fprintf(file, "\n");
+
+ fprintf(file, "\tRequest *InP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->"));
+ if (!rt->rtOneWay) {
+ fprintf(file, "\tReply *Out0P = &Mess%sOut;\n", (rtMessOnStack(rt) ? "." : "->"));
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i);
+ }
+ }
+
+ fprintf(file, "\n");
+
+ fprintf(file, "\tmach_msg_return_t msg_result;\n");
+
+ /* if request is variable, we need msgh_size_delta and msgh_size */
+ if (rt->rtNumRequestVar > 0)
+ fprintf(file, "\tunsigned int msgh_size;\n");
+ if (rt->rtMaxRequestPos > 0)
+ fprintf(file, "\tunsigned int msgh_size_delta;\n");
+ if (rt->rtNumRequestVar > 1 || rt->rtMaxRequestPos > 0)
+ fprintf(file, "\n");
+
+ if (rt->rtUserImpl) {
+ fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n");
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tunsigned int trailer_size __attribute__((unused));\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ fprintf(file, "\n");
+ fprintf(file, "#ifdef\t__MIG_check__Reply__%s_t__defined\n", rt->rtName);
+ fprintf(file, "\tkern_return_t check_result;\n");
+ fprintf(file, "#endif\t/* __MIG_check__Reply__%s_t__defined */\n", rt->rtName);
+ fprintf(file, "\n");
+ WriteApplMacro(file, "Send", "Declare", rt);
+ fprintf(file, "\n");
+}
+
+static void
+WriteReturn(FILE *file, routine_t *rt, char *before, char *value, char *after, boolean_t deallocate_mess)
+{
+ if (rtMessOnStack(rt)) {
+ if (value != stRetCode) {
+ /* get the easy case (no braces needed) out of the way */
+ fprintf(file, "%sreturn%s%s;%s", before, (*value ? " " : ""), value, after);
+ return;
+ }
+ else {
+ fprintf(file, "%s{\n", before);
+ fprintf(file, "%s\treturn Out0P->RetCode;\n%s}%s", before, before, after);
+ return;
+ }
+ }
+
+ if (value == stRetCode) {
+ fprintf(file, "%s{\n%s\t%s ReturnValue;\n", before, before, ReturnTypeStr(rt));
+ fprintf(file, "%s\tReturnValue = Out0P->RetCode;\n%s\t", before, before);
+ }
+ else {
+ fprintf(file, "%s{ ", before);
+ }
+
+ if (deallocate_mess) {
+ fprintf(file, "%s((char *) Mess, sizeof(*Mess)); ", MessFreeRoutine);
+ }
+
+ if (value == stRetCode)
+ fprintf(file, "return ReturnValue;\n%s}%s", before, after);
+ else if (value == stRetNone)
+ fprintf(file, "return; }%s", after);
+ else
+ fprintf(file, "return %s; }%s", value, after);
+}
+
+static void
+WriteRetCodeArg(FILE *file, routine_t *rt)
+{
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ argument_t *arg = rt->rtRetCArg;
+
+ fprintf(file, "\tif (%s) {\n", arg->argVarName);
+ fprintf(file, "\t\t((mig_reply_error_t *)InP)->RetCode = %s;\n", arg->argVarName);
+ fprintf(file, "\t\t((mig_reply_error_t *)InP)->NDR = NDR_record;\n");
+ fprintf(file, "\t\tgoto ready_to_send;\n");
+ fprintf(file, "\t}\n\n");
+ }
+}
+
+/*************************************************************
+ * Writes the logic to check for a message send timeout, and
+ * deallocate any relocated ool data so as not to leak.
+ *************************************************************/
+static void
+WriteMsgCheckForSendErrors(FILE *file, routine_t *rt)
+{
+ if (rt->rtConsumeOnSendError != ConsumeOnSendErrorAny && rt->rtWaitTime == argNULL) {
+ return;
+ }
+
+ if (rt->rtConsumeOnSendError == ConsumeOnSendErrorAny) {
+ // other errors mean the kernel consumed some of the rights
+ // and we can't possibly know if there's something left to destroy
+ fputs("\n"
+ "\t" "if (msg_result == MACH_SEND_INVALID_DEST ||" "\n"
+ "\t\t" "msg_result == MACH_SEND_TIMED_OUT) {" "\n", file);
+ } else {
+ fputs("\n"
+ "\t" "if (msg_result == MACH_SEND_TIMED_OUT) {" "\n", file);
+ }
+
+ if (rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) {
+ argument_t *arg_ptr;
+
+ // iterate over arg list
+ for (arg_ptr = rt->rtArgs; arg_ptr != NULL; arg_ptr = arg_ptr->argNext) {
+
+ // if argument contains ool data
+ if (akCheck(arg_ptr->argKind, akbSendKPD) && arg_ptr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+ // generate code to test current arg address vs. address before the msg_send call
+ // if not at the same address, mig_deallocate the argument
+ fprintf(file, "\t\t" "if((vm_offset_t) InP->%s.address != (vm_offset_t) %s)\n",
+ arg_ptr->argVarName, arg_ptr->argVarName);
+ fprintf(file, "\t\t\t" "mig_deallocate((vm_offset_t) InP->%s.address, "
+ "(vm_size_t) InP->%s.size);\n", arg_ptr->argVarName, arg_ptr->argVarName);
+ }
+ }
+ } else {
+ /*
+ * The original MIG would leak most resources on send timeout without
+ * leaving a chance for callers to know how to dispose of most of the
+ * resources, as the caller can't possibly guess the new names
+ * picked during pseudo-receive.
+ */
+ if (IsKernelUser) {
+ fputs("#if\t__MigKernelSpecificCode" "\n", file);
+ fputs("\t\t" "mach_msg_destroy_from_kernel(&InP->Head);" "\n", file);
+ fputs("#endif\t/* __MigKernelSpecificCode */" "\n", file);
+ } else {
+ fputs("\t\t" "/* mach_msg_destroy doesn't handle the local port */" "\n", file);
+ fputs("\t\t" "switch (MACH_MSGH_BITS_LOCAL(InP->Head.msgh_bits)) {" "\n", file);
+ fputs("\t\t" "case MACH_MSG_TYPE_MOVE_SEND:" "\n", file);
+ fputs("\t\t\t" "mach_port_deallocate(mach_task_self(), InP->Head.msgh_local_port);" "\n", file);
+ fputs("\t\t\t" "break;" "\n", file);
+ fputs("\t\t" "}" "\n", file);
+ fputs("\t\t" "mach_msg_destroy(&InP->Head);" "\n", file);
+ }
+ }
+
+ fputs("\t" "}" "\n\n", file);
+ return;
+}
+
+/*************************************************************
+ * Writes the send call when there is to be no subsequent
+ * receive. Called by WriteRoutine SimpleRoutines
+ *************************************************************/
+static void
+WriteMsgSend(FILE *file, routine_t *rt)
+{
+ char *SendSize = "";
+ char string[MAX_STR_LEN];
+
+ if (rt->rtNumRequestVar == 0)
+ SendSize = "(mach_msg_size_t)sizeof(Request)";
+ else
+ SendSize = "msgh_size";
+
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
+ SendSize = strconcat(string, SendSize);
+ }
+
+ if (IsKernelUser) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "\tmsg_result = mach_msg_send_from_kernel(");
+ fprintf(file, "&InP->Head, %s);\n", SendSize);
+ fprintf(file, "#else\n");
+ }
+ fprintf(file, "\tmsg_result = mach_msg("
+ "&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, MACH_PORT_NULL, %s, MACH_PORT_NULL);\n",
+ rt->rtWaitTime !=argNULL ? "MACH_SEND_TIMEOUT|" : "",
+ rt->rtMsgOption->argVarName,
+ SendSize,
+ rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName:"MACH_MSG_TIMEOUT_NONE");
+
+ if (IsKernelUser) {
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+ }
+
+ WriteApplMacro(file, "Send", "After", rt);
+
+ WriteMsgCheckForSendErrors(file, rt);
+
+ WriteReturn(file, rt, "\t", "msg_result", "\n", TRUE);
+}
+
+/*************************************************************
+ * Writes to code to check for error returns from receive.
+ * Called by WriteMsgSendReceive and WriteMsgRPC
+ *************************************************************/
+static void
+WriteMsgCheckReceiveCleanupMigReplyPort(FILE *file, routine_t *rt, char *success)
+{
+ if (!akCheck(rt->rtReplyPort->argKind, akbUserArg))
+ {
+ /* If we aren't using a user-supplied reply port, then
+ deallocate the reply port when it is invalid or
+ for TIMED_OUT errors. */
+ fprintf(file, "\tif (msg_result != %s) {\n", success);
+ if (rt->rtWaitTime != argNULL) {
+ fprintf(file, "\t\t__MachMsgErrorWithTimeout%s(msg_result);\n",
+ rt->rtUseSpecialReplyPort ? "SRP" : "");
+ } else {
+ fprintf(file, "\t\t__MachMsgErrorWithoutTimeout%s(msg_result);\n",
+ rt->rtUseSpecialReplyPort ? "SRP" : "");
+ }
+ fprintf(file, "\t}\n");
+ }
+}
+
+static void
+WriteMsgCheckReceive(FILE *file, routine_t *rt, char *success)
+{
+ fprintf(file, "\tif (msg_result != %s) {\n", success);
+ WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result");
+ fprintf(file, "\t}\n");
+}
+
+/*************************************************************
+ * Writes the send and receive calls and code to check
+ * for errors. Normally the rpc code is generated instead
+ * although, the subsytem can be compiled with the -R option
+ * which will cause this code to be generated. Called by
+ * WriteRoutine if UseMsgRPC option is false.
+ *************************************************************/
+static void
+WriteMsgSendReceive(FILE *file, routine_t *rt)
+{
+ char *SendSize = "";
+ char string[MAX_STR_LEN];
+
+ if (rt->rtNumRequestVar == 0)
+ SendSize = "(mach_msg_size_t)sizeof(Request)";
+ else
+ SendSize = "msgh_size";
+
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
+ SendSize = strconcat(string, SendSize);
+ }
+
+ /* IsKernelUser to be done! */
+ fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, ", rt->rtWaitTime != argNULL ? "MACH_SEND_TIMEOUT|" : "", rt->rtMsgOption->argVarName, SendSize);
+ fprintf(file, " MACH_PORT_NULL, %s, MACH_PORT_NULL);\n",
+#if !USE_IMMEDIATE_SEND_TIMEOUT
+ (rt->rtWaitTime != argNULL) ? rt->rtWaitTime->argVarName :
+#endif
+ "MACH_MSG_TIMEOUT_NONE");
+ fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
+ WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result");
+ fprintf(file, "\n");
+
+ fprintf(file, "\tmsg_result = mach_msg(&Out0P->Head, MACH_RCV_MSG|%s%s%s, 0, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, %s, MACH_PORT_NULL);\n",
+ rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
+ (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? "MACH_RCV_TIMEOUT|" : "",
+ rt->rtMsgOption->argVarName,
+ (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
+ WriteApplMacro(file, "Send", "After", rt);
+ WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS");
+ WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
+ fprintf(file, "\n");
+}
+
+/*************************************************************
+ * Writes the rpc call and the code to check for errors.
+ * This is the default code to be generated. Called by WriteRoutine
+ * for all routine types except SimpleRoutine.
+ *************************************************************/
+static void
+WriteMsgRPC(FILE *file, routine_t *rt)
+{
+ char *SendSize = "";
+ char string[MAX_STR_LEN];
+
+ if (rt->rtNumRequestVar == 0)
+ SendSize = "(mach_msg_size_t)sizeof(Request)";
+ else
+ SendSize = "msgh_size";
+
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
+ SendSize = strconcat(string, SendSize);
+ }
+
+ if (IsKernelUser) {
+ fprintf(file, "#if\t(__MigKernelSpecificCode) || (_MIG_KERNELSPECIFIC_CODE_)\n");
+ fprintf(file, "\tmsg_result = mach_msg_rpc_from_kernel(&InP->Head, %s, (mach_msg_size_t)sizeof(Reply));\n", SendSize);
+ fprintf(file, "#else\n");
+ }
+ if (rt->rtOverwrite) {
+ fprintf(file, "\tmsg_result = mach_msg_overwrite(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_OVERWRITE|%s%s%s, %s, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL, ",
+ rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
+ rt->rtWaitTime != argNULL ?
+ (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "",
+ rt->rtMsgOption->argVarName,
+ SendSize,
+ rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
+ fprintf(file, " &InOvTemplate->Head, (mach_msg_size_t)sizeof(OverwriteTemplate));\n");
+ }
+ else {
+ fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|%s%s%s, %s, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL);\n",
+ rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
+ rt->rtWaitTime != argNULL ?
+ (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "",
+ rt->rtMsgOption->argVarName,
+ SendSize,
+ rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
+ }
+ if (IsKernelUser)
+ fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
+ WriteApplMacro(file, "Send", "After", rt);
+
+ WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS");
+ WriteMsgCheckForSendErrors(file, rt);
+
+ WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_Pack discipline for Port types.
+ */
+static void
+WriteKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *subindex = "";
+ char *recast = "";
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ ipc_type_t *real_it;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ subindex = "[i]";
+ real_it = it->itElement;
+ }
+ else {
+ (void)sprintf(firststring, "InP->%s", arg->argMsgField);
+ (void)sprintf(string, "InP->%s.", arg->argMsgField);
+ real_it = it;
+ }
+
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t"))
+ recast = "(mach_port_t)";
+#endif
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ /* ref is required also in the Request part, because of inout parameters */
+ fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
+ argument_t *poly = arg->argPoly;
+
+ fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName);
+ }
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
+ argument_t *poly = arg->argPoly;
+
+ fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName);
+ }
+ else
+ fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr);
+ fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ if (IS_MULTIPLE_KPD(it)) {
+ fprintf(file, "\t }\n");
+ if (it->itVarArray) {
+ fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
+ /* fill the rest of the statically allocated KPD entries with MACH_PORT_NULL */
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t }\n");
+ }
+ fprintf(file, "\t}\n");
+ }
+ fprintf(file, "\n");
+}
+
+static void
+WriteKPD_ool_varsize(FILE *file, argument_t *arg, char *who, char *where, boolean_t iscomplex)
+{
+ ipc_type_t *it = arg->argType;
+ argument_t *count;
+ char *cref;
+
+ if (iscomplex) {
+ it = it->itElement;
+ count = arg->argSubCount;
+ }
+ else
+ count = arg->argCount;
+ cref = count->argByReferenceUser ? "*" : "";
+
+ /* size has to be expressed in bytes! */
+ if (count->argMultiplier > 1 || it->itSize > 8)
+ fprintf(file, "\t%s->%s = %s%s%s * %d;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : "", count->argMultiplier * it->itSize / 8);
+ else
+ fprintf(file, "\t%s->%s = %s%s%s;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : "");
+}
+
+/*
+ * argKPD_Pack discipline for out-of-line types.
+ */
+static void
+WriteKPD_ool(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+ boolean_t VarArray;
+ u_int howmany, howbig;
+ char *subindex;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ VarArray = it->itElement->itVarArray;
+ howmany = it->itElement->itNumber;
+ howbig = it->itElement->itSize;
+ subindex = "[i]";
+ }
+ else {
+ (void)sprintf(firststring, "InP->%s", arg->argMsgField);
+ (void)sprintf(string, "InP->%s.", arg->argMsgField);
+ VarArray = it->itVarArray;
+ howmany = it->itNumber;
+ howbig = it->itSize;
+ subindex = "";
+ }
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
+ if (VarArray) {
+ if (IS_MULTIPLE_KPD(it))
+ WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE);
+ else
+ WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE);
+ }
+
+ if (arg->argDeallocate == d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+
+ fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
+ if (VarArray)
+ if (IS_MULTIPLE_KPD(it))
+ WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE);
+ else
+ WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE);
+ else
+ fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8);
+ if (arg->argDeallocate == d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+ else
+ fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
+ fprintf(file, "\t%scopy = %s;\n", string, (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY");
+#ifdef ALIGNMENT
+ fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, (it->itElement->itSize < 8) ? 1 : it->itElement->itSize / 8);
+#endif
+ fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
+
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ if (IS_MULTIPLE_KPD(it)) {
+ fprintf(file, "\t }\n");
+ if (it->itVarArray) {
+ fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
+ /* fill the rest of the statically allocated KPD entries with size NULL */
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ if (!VarArray)
+ fprintf(file, "\t%ssize = 0;\n", string);
+ /* otherwise the size in the template would be != 0! */
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t%ssize = 0;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t }\n");
+ }
+ fprintf(file, "\t}\n");
+ }
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_Pack discipline for out-of-line Port types.
+ */
+static void
+WriteKPD_oolport(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ argument_t *count;
+ boolean_t VarArray;
+ string_t howstr;
+ u_int howmany;
+ char *subindex;
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ VarArray = it->itElement->itVarArray;
+ howmany = it->itElement->itNumber;
+ howstr = it->itElement->itInNameStr;
+ count = arg->argSubCount;
+ subindex = "[i]";
+ }
+ else {
+ (void)sprintf(firststring, "InP->%s", arg->argMsgField);
+ (void)sprintf(string, "InP->%s.", arg->argMsgField);
+ VarArray = it->itVarArray;
+ howmany = it->itNumber;
+ howstr = it->itInNameStr;
+ count = arg->argCount;
+ subindex = "";
+ }
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
+ if (VarArray)
+ fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName);
+ }
+ if (arg->argDeallocate == d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+
+ fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
+ if (VarArray)
+ fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex);
+ else
+ fprintf(file, "\t%scount = %d;\n", string, howmany);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName);
+ }
+ else
+ fprintf(file, "\t%sdisposition = %s;\n", string, howstr);
+ if (arg->argDeallocate == d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+ else
+ fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
+ fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
+
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\n");
+
+ if (IS_MULTIPLE_KPD(it)) {
+ fprintf(file, "\t }\n");
+ if (it->itVarArray) {
+ fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
+ /* fill the rest of the statically allocated KPD entries with size NULL */
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ if (!VarArray)
+ fprintf(file, "\t%scount = 0;\n", string);
+ /* otherwise the size in the template would be != 0! */
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t%scount = 0;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t }\n");
+ }
+ fprintf(file, "\t}\n");
+ }
+ fprintf(file, "\n");
+}
+
+static void
+WriteOverwriteTemplate(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ char string[MAX_STR_LEN];
+ char *subindex = "";
+ boolean_t finish = FALSE;
+
+ fprintf(file, "\t/* Initialize the template for overwrite */\n");
+ fprintf(file, "\tInOvTemplate->msgh_body.msgh_descriptor_count = %d;\n", rt->rtOverwriteKPDs);
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ argument_t *count;
+ char *cref;
+ boolean_t VarIndex;
+ u_int howmany, howbig;
+
+ if (akCheck(arg->argKind, akbOverwrite)) {
+ if (arg->argFlags & flOverwrite) {
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, TRUE, it->itVarArray, arg, TRUE);
+ if (it->itVarArray)
+ finish = TRUE;
+ sprintf(string, "\tptr->");
+ subindex = "[i]";
+ count = arg->argSubCount;
+ VarIndex = it->itElement->itVarArray;
+ howmany = it->itElement->itNumber;
+ howbig = it->itElement->itSize;
+ }
+ else {
+ sprintf(string, "InOvTemplate->%s.", arg->argMsgField);
+ subindex = "";
+ count = arg->argCount;
+ VarIndex = it->itVarArray;
+ howmany = it->itNumber;
+ howbig = it->itSize;
+ }
+
+ fprintf(file, "\t%saddress = (void *) %s%s%s;\n", string, ref, arg->argVarName, subindex);
+
+ if (it->itPortType) {
+ fprintf(file, "\t%scount = ", string);
+ if (VarIndex) {
+ cref = count->argByReferenceUser ? "*" : "";
+ fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex);
+ }
+ else
+ fprintf(file, "%d;\n", howmany);
+ }
+ else {
+ fprintf(file, "\t%ssize = ", string);
+ if (VarIndex) {
+ cref = count->argByReferenceUser ? "*" : "";
+ if (count->argMultiplier > 1 || howbig > 8)
+ fprintf(file, "%s%s%s * %d;\n", cref, count->argVarName, subindex, count->argMultiplier * howbig / 8);
+ else
+ fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex);
+ }
+ else
+ fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8);
+ }
+ fprintf(file, "\t%scopy = MACH_MSG_OVERWRITE;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_OOL_%sDESCRIPTOR;\n", string, (it->itPortType) ? "PORTS_" : "");
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n");
+ if (finish) {
+ fprintf(file, "\t for (i = %s%s; i < %d; ptr++, i++) {\n", (arg->argCount->argByReferenceUser) ? "*" : "", arg->argCount->argVarName, it->itKPD_Number);
+ fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n");
+ fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : "");
+ fprintf(file, "\t }\n");
+ }
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t}\n");
+ }
+ else {
+ /* just a placeholder */
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, TRUE, FALSE, arg, TRUE);
+ fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n");
+ fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : "");
+ fprintf(file, "\t }\n\t}\n");
+ }
+ else {
+ fprintf(file, "\tInOvTemplate->%s.copy = MACH_MSG_ALLOCATE;\n", arg->argMsgField);
+ /* not sure whether this is needed */
+ fprintf(file, "\tInOvTemplate->%s.type = MACH_MSG_OOL_%sDESCRIPTOR;\n", arg->argMsgField, (it->itPortType) ? "PORTS_" : "");
+ }
+ }
+ }
+ }
+ fprintf(file, "\n");
+}
+
+/*************************************************************
+ * Writes code to copy an argument into the request message.
+ * Called by WriteRoutine for each argument that is to placed
+ * in the request message.
+ *************************************************************/
+
+static void
+WritePackArgValueNormal(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *ref = (arg->argByReferenceUser ||
+ it->itNativePointer) ? "*" : "";
+
+ if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) {
+ if (it->itString) {
+ /*
+ * Copy variable-size C string with mig_strncpy.
+ * Save the string length (+ 1 for trailing 0)
+ * in the argument`s count field.
+ */
+ fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n");
+ fprintf(file, "\t\tInP->%s = (%s) mig_strncpy_zerofill(InP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber);
+ fprintf(file, "\t} else {\n");
+ fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
+
+ fprintf(file, "\t\tInP->%s = (%s) mig_strncpy(InP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber);
+
+ fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
+
+ fprintf(file, "\tInP->%sOffset = 0;\n", arg->argMsgField);
+ }
+ else if (it->itNoOptArray)
+ fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, %d);\n", arg->argMsgField, ref, arg->argVarName, it->itTypeSize);
+ else {
+
+ /*
+ * Copy in variable-size inline array with (void)memcpy,
+ * after checking that number of elements doesn`t
+ * exceed declared maximum.
+ */
+ argument_t *count = arg->argCount;
+ char *countRef = count->argByReferenceUser ? "*" : "";
+ ipc_type_t *btype = it->itElement;
+
+ /* Note btype->itNumber == count->argMultiplier */
+
+ if (akIdent(arg->argKind) != akeSubCount) {
+ /* we skip the SubCount case, as we have already taken care of */
+ fprintf(file, "\tif (%s%s > %d) {\n", countRef, count->argVarName, it->itNumber/btype->itNumber);
+ WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
+ fprintf(file, "\t}\n");
+ }
+
+ fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, ", arg->argMsgField, ref, arg->argVarName);
+ if (btype->itTypeSize > 1)
+ fprintf(file, "%d * ", btype->itTypeSize);
+ fprintf(file, "%s%s);\n", countRef, count->argVarName);
+ }
+ }
+ else if (IS_OPTIONAL_NATIVE(it)) {
+ fprintf(file, "\tif ((InP->__Present__%s = (%s != %s))) {\n", arg->argMsgField, arg->argVarName, it->itBadValue);
+ WriteCopyType(file, it, TRUE, "\tInP->%s.__Real__%s", "/* %s%s */ %s%s", arg->argMsgField, arg->argMsgField, ref, arg->argVarName);
+ fprintf(file, "\t}\n");
+ }
+ else
+ WriteCopyType(file, it, TRUE, "InP->%s", "/* %s */ %s%s", arg->argMsgField, ref, arg->argVarName);
+
+ if (arg->argPadName != NULL && it->itPadSize != 0) {
+ fprintf(file, "\t for (int i = 0; i < %d; i++)\n", it->itPadSize);
+ fprintf(file, "\t\t InP->%s[i] = 0;\n", arg->argPadName);
+ }
+ fprintf(file, "\n");
+}
+
+/*
+ * Calculate the size of a variable-length message field.
+ */
+static void
+WriteArgSizeVariable(FILE *file, argument_t *arg, ipc_type_t *ptype)
+{
+ int bsize = ptype->itElement->itTypeSize;
+ argument_t *count = arg->argCount;
+
+ if (PackMsg == FALSE) {
+ fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
+ return;
+ }
+
+ /* If the base type size of the data field isn`t a multiple of 4,
+ we have to round up. */
+ if (bsize % itWordAlign != 0)
+ fprintf(file, "_WALIGN_");
+ fprintf(file, "(");
+ if (bsize > 1)
+ fprintf(file, "%d * ", bsize);
+ if (ptype->itString)
+ /* get count from descriptor in message */
+ fprintf(file, "InP->%s", count->argMsgField);
+ else
+ /* get count from argument */
+ fprintf(file, "%s%s", count->argByReferenceUser ? "*" : "", count->argVarName);
+ fprintf(file, ")");
+}
+
+static void
+WriteArgSizeOptional(FILE *file, argument_t *arg, ipc_type_t *ptype)
+{
+ fprintf(file, "(InP->__Present__%s ? _WALIGNSZ_(%s) : 0)", arg->argVarName, ptype->itUserType);
+}
+
+static void
+WriteArgSize(FILE *file, argument_t *arg)
+
+{
+ ipc_type_t *ptype = arg->argType;
+
+ if (IS_OPTIONAL_NATIVE(ptype))
+ WriteArgSizeOptional(file, arg, ptype);
+ else
+ WriteArgSizeVariable(file, arg, ptype);
+}
+
+/*
+ * Adjust message size and advance request pointer.
+ * Called after packing a variable-length argument that
+ * has more arguments following.
+ */
+static void
+WriteAdjustMsgSize(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+
+ /* There are more In arguments. We need to adjust msgh_size
+ and advance InP, so we save the size of the current field
+ in msgh_size_delta. */
+
+ fprintf(file, "\tmsgh_size_delta = ");
+ WriteArgSize(file, arg);
+ fprintf(file, ";\n");
+
+ if (arg->argRequestPos == 0) {
+ /* First variable-length argument. The previous msgh_size value
+ is the minimum request size. */
+
+ fprintf(file, "\tmsgh_size = ");
+ rtMinRequestSize(file, arg->argRoutine, "Request");
+ fprintf(file, " + msgh_size_delta;\n");
+ }
+ else
+ fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
+
+ if (PackMsg == TRUE) {
+ fprintf(file, "\tInP = (Request *) ((pointer_t) InP + msgh_size_delta - ");
+ if (IS_OPTIONAL_NATIVE(ptype))
+ fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType);
+ else
+ fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
+ fprintf(file, ");\n\n");
+ }
+}
+
+/*
+ * Calculate the size of the message. Called after the
+ * last argument has been packed.
+ */
+static void
+WriteFinishMsgSize(FILE *file, argument_t *arg)
+{
+ /* No more In arguments. If this is the only variable In
+ argument, the previous msgh_size value is the minimum
+ request size. */
+
+ if (arg->argRequestPos == 0) {
+ fprintf(file, "\tmsgh_size = ");
+ rtMinRequestSize(file, arg->argRoutine, "Request");
+ fprintf(file, " + (");
+ WriteArgSize(file, arg);
+ fprintf(file, ");\n");
+ }
+ else {
+ fprintf(file, "\tmsgh_size += ");
+ WriteArgSize(file, arg);
+ fprintf(file, ";\n");
+ }
+}
+
+static void
+WriteInitializeCount(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argCInOut->argParent->argType;
+ ipc_type_t *btype = ptype->itElement;
+
+ fprintf(file, "\tif (%s%s < %d)\n", arg->argByReferenceUser ? "*" : "", arg->argVarName, ptype->itNumber/btype->itNumber);
+ fprintf(file, "\t\tInP->%s = %s%s;\n", arg->argMsgField, arg->argByReferenceUser ? "*" : "", arg->argVarName);
+ fprintf(file, "\telse\n");
+ fprintf(file, "\t\tInP->%s = %d;\n", arg->argMsgField, ptype->itNumber/btype->itNumber);
+ fprintf(file, "\n");
+}
+
+/*
+ * Generate code to fill in all of the request arguments and their
+ * message types.
+ */
+static void
+WriteRequestArgs(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ argument_t *lastVarArg;
+
+ /*
+ * 1. The Kernel Processed Data
+ */
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, akbSendSnd|akbSendKPD))
+ (*arg->argKPD_Pack)(file, arg);
+
+ /*
+ * 2. The Data Stream
+ */
+ lastVarArg = argNULL;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ /*
+ * Adjust message size and advance message pointer if
+ * the last request argument was variable-length and the
+ * request position will change.
+ */
+ if (lastVarArg != argNULL &&
+ lastVarArg->argRequestPos < arg->argRequestPos) {
+ WriteAdjustMsgSize(file, lastVarArg);
+ lastVarArg = argNULL;
+ }
+
+ if ((akIdent(arg->argKind) == akeCountInOut) &&
+ akCheck(arg->argKind, akbSendSnd))
+ WriteInitializeCount(file, arg);
+ else if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody))
+ WritePackArgValueNormal(file, arg);
+ /*
+ * Remember whether this was variable-length.
+ */
+ if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody|akbVariable))
+ lastVarArg = arg;
+ }
+ /*
+ * Finish the message size.
+ */
+ if (lastVarArg != argNULL)
+ WriteFinishMsgSize(file, lastVarArg);
+}
+
+/*************************************************************
+ * Writes code to check that the return msgh_id is correct and that
+ * the size of the return message is correct. Called by
+ * WriteRoutine.
+ *************************************************************/
+static void
+WriteCheckIdentity(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\tif (Out0P->Head.msgh_id != %d) {\n", rt->rtNumber + SubsystemBase + 100);
+ fprintf(file, "\t if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n");
+ fprintf(file, "\t\t{ return MIG_SERVER_DIED; }\n");
+ fprintf(file, "\t else\n");
+ fprintf(file, "\t\t{ return MIG_REPLY_MISMATCH; }\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "\n");
+ if (!rt->rtSimpleReply)
+ fprintf(file, "\tmsgh_simple = !(Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n");
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ if (!rt->rtNoReplyArgs)
+ fprintf(file, "\tmsgh_size = Out0P->Head.msgh_size;\n\n");
+
+ if (rt->rtSimpleReply) {
+ /* Expecting a simple message. We can factor out the check for
+ * a simple message, since the error reply message is also simple.
+ */
+ fprintf(file, "\tif ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
+ if (rt->rtNoReplyArgs)
+ fprintf(file, "\t (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))\n");
+ else {
+ /*
+ * We have an error iff:
+ * 1) the message size is not the one expected AND
+ * 2) the message size is also different from sizeof(mig_reply_error_t)
+ * or the RetCode == KERN_SUCCESS
+ */
+ if (rt->rtNumReplyVar > 0) {
+ fprintf(file, "\t ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < ");
+ rtMinReplySize(file, rt, "__Reply");
+ fprintf(file, ") &&\n");
+ }
+ else
+ fprintf(file, "\t ((msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n");
+ fprintf(file, "\t (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n");
+ fprintf(file, "\t Out0P->RetCode == KERN_SUCCESS)))\n");
+ }
+ }
+ else {
+ /* Expecting a complex message. */
+
+ fprintf(file, "\t" "if ((msgh_simple || Out0P->msgh_body.msgh_descriptor_count != %d ||\n", rt->rtReplyKPDs);
+ if (rt->rtNumReplyVar > 0) {
+ fprintf(file, "\t msgh_size < ");
+ rtMinReplySize(file, rt, "__Reply");
+ fprintf(file, " || msgh_size > (mach_msg_size_t)sizeof(__Reply)) &&\n");
+ }
+ else
+ fprintf(file, "\t msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n");
+ fprintf(file, "\t (!msgh_simple || msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n");
+ fprintf(file, "\t ((mig_reply_error_t *)Out0P)->RetCode == KERN_SUCCESS))\n");
+ }
+ fprintf(file, "\t\t{ return MIG_TYPE_ERROR ; }\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ fprintf(file, "\n");
+}
+
+/*************************************************************
+ * Write code to generate error handling code if the RetCode
+ * argument of a Routine is not KERN_SUCCESS.
+ *************************************************************/
+static void
+WriteRetCodeCheck(FILE *file, routine_t *rt)
+{
+ if (rt->rtSimpleReply)
+ fprintf(file, "\tif (Out0P->RetCode != KERN_SUCCESS) {\n");
+ else
+ fprintf(file, "\tif (msgh_simple) {\n");
+ if (CheckNDR) {
+ fprintf(file, "#ifdef\t__NDR_convert__mig_reply_error_t__defined\n");
+ fprintf(file, "\t\t__NDR_convert__mig_reply_error_t((mig_reply_error_t *)Out0P);\n");
+ fprintf(file, "#endif\t/* __NDR_convert__mig_reply_error_t__defined */\n");
+ }
+ fprintf(file, "\t\treturn ((mig_reply_error_t *)Out0P)->RetCode;\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for Port types.
+ */
+static void
+WriteTCheckKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab = "";
+ char string[MAX_STR_LEN];
+ boolean_t close = FALSE;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
+ (void)sprintf(string, "ptr->");
+ tab = "\t";
+ close = TRUE;
+ }
+ else
+ (void)sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
+ fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string);
+ if (arg->argPoly == argNULL && !it->itVarArray)
+ /* we can't check disposition when poly or VarArray,
+ (because some of the entries could be empty) */
+ fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, it->itOutNameStr);
+ fprintf(file,
+ ") {\n"
+ "\t\t%s" "return MIG_TYPE_ERROR;\n"
+ "\t%s" "}\n"
+ , tab, tab);
+ if (close)
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for out-of-line types.
+ */
+static void
+WriteTCheckKPD_ool(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab, string[MAX_STR_LEN];
+ boolean_t test;
+ u_int howmany, howbig;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ howmany = it->itElement->itNumber;
+ howbig = it->itElement->itSize;
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ }
+ else {
+ tab = "";
+ sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
+ howmany = it->itNumber;
+ howbig = it->itSize;
+ test = !it->itVarArray;
+ }
+
+ fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string);
+ if (test)
+ /* if VarArray we may use no-op; if itElement->itVarArray size might change */
+ fprintf(file, " ||\n\t%s %ssize != %d", tab, string, (howmany * howbig + 7)/8);
+ fprintf(file,
+ ") {\n"
+ "\t\t%s" "return MIG_TYPE_ERROR;\n"
+ "\t%s" "}\n"
+ , tab, tab);
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for out-of-line Port types.
+ */
+static void
+WriteTCheckKPD_oolport(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab, string[MAX_STR_LEN];
+ boolean_t test;
+ u_int howmany;
+ char *howstr;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ howmany = it->itElement->itNumber;
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ howstr = it->itElement->itOutNameStr;
+ }
+ else {
+ tab = "";
+ sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
+ howmany = it->itNumber;
+ test = !it->itVarArray;
+ howstr = it->itOutNameStr;
+ }
+
+ fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string);
+ if (test)
+ /* if VarArray we may use no-op; if itElement->itVarArray size might change */
+ fprintf(file, " ||\n\t%s %scount != %d", tab, string, howmany);
+ if (arg->argPoly == argNULL)
+ fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, howstr);
+ fprintf(file, ") {\n"
+ "\t\t%s" "return MIG_TYPE_ERROR;\n"
+ "\t%s" "}\n"
+ ,tab, tab);
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*************************************************************
+ * Writes code to check that the type of each of the arguments
+ * in the reply message is what is expected. Called by
+ * WriteRoutine for each out && typed argument in the reply message.
+ *************************************************************/
+static void
+WriteTypeCheck(FILE *file, argument_t *arg)
+{
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ (*arg->argKPD_TypeCheck)(file, arg);
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+}
+
+
+/*
+ * argKPD_Extract discipline for Port types.
+ */
+static void
+WriteExtractKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ char *subindex;
+ char *recast = "";
+ ipc_type_t *real_it;
+
+ real_it = (IS_MULTIPLE_KPD(it)) ? it->itElement : it;
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t"))
+ recast = "(mach_port_t)";
+#endif
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
+
+ fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast);
+ if (it->itVarArray) {
+ argument_t *count = arg->argCount;
+ char *cref = count->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t if (Out%dP->%s >",count->argReplyPos, count->argVarName);
+ if (arg->argCountInOut) {
+ fprintf(file, " %s%s)\n", cref, count->argVarName);
+ }
+ else {
+ fprintf(file, " %d)\n", it->itNumber/it->itElement->itNumber);
+ }
+ WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
+ }
+ fprintf(file, "\t}\n");
+ subindex = "[0]";
+ }
+ else {
+ fprintf(file, "\t%s%s = %sOut%dP->%s.name;\n", ref, arg->argVarName, recast, arg->argReplyPos, arg->argMsgField);
+ subindex = "";
+ }
+
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex);
+ }
+}
+
+/*
+ * argKPD_Extract discipline for out-of-line types.
+ */
+static void
+WriteExtractKPD_ool(FILE *file, argument_t *arg)
+{
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ ipc_type_t *it = arg->argType;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
+ fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
+ fprintf(file, "\t}\n");
+ }
+ else
+ fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField);
+ /*
+ * In case of variable sized arrays,
+ * the count field will be retrieved from the untyped
+ * section of the message
+ */
+}
+
+/*
+ * argKPD_Extract discipline for out-of-line Port types.
+ */
+static void
+WriteExtractKPD_oolport(FILE *file, argument_t *arg)
+{
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ ipc_type_t *it = arg->argType;
+ char *subindex;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
+ fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
+ fprintf(file, "\t}\n");
+ subindex = "[0]";
+ }
+ else {
+ fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField);
+ subindex = "";
+ }
+ /*
+ * In case of variable sized arrays,
+ * the count field will be retrieved from the untyped
+ * section of the message
+ */
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex);
+ }
+}
+
+/*************************************************************
+ * Write code to copy an argument from the reply message
+ * to the parameter. Called by WriteRoutine for each argument
+ * in the reply message.
+ *************************************************************/
+
+static void
+WriteExtractArgValueNormal(FILE *file, argument_t *arg)
+{
+ ipc_type_t *argType = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ char who[20];
+
+ if (akCheck(arg->argKind, akbUserImplicit))
+ sprintf(who, "TrailerP");
+ else
+ sprintf(who, "Out%dP", arg->argReplyPos);
+
+ if (IS_VARIABLE_SIZED_UNTYPED(argType) || argType->itNoOptArray) {
+ if (argType->itString) {
+ /*
+ * Copy out variable-size C string with mig_strncpy, not the zerofill variant.
+ * We don't risk leaking process / kernel memory on this copy-out because
+ * we've already zero-filled the buffer on copy-in.
+ */
+ fprintf(file, "\t(void) mig_strncpy(%s%s, %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itNumber);
+ }
+ else if (argType->itNoOptArray)
+ fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itTypeSize);
+ else {
+
+ /*
+ * Copy out variable-size inline array with (void)memcpy,
+ * after checking that number of elements doesn`t
+ * exceed user`s maximum.
+ */
+ argument_t *count = arg->argCount;
+ char *countRef = count->argByReferenceUser ? "*" : "";
+ ipc_type_t *btype = argType->itElement;
+
+ /* Note count->argMultiplier == btype->itNumber */
+ /* Note II: trailer logic isn't supported in this case */
+ fprintf(file, "\tif (Out%dP->%s", count->argReplyPos, count->argMsgField);
+ if (arg->argCountInOut) {
+ fprintf(file, " > %s%s) {\n", countRef, count->argVarName);
+ }
+ else {
+ fprintf(file, " > %d) {\n", argType->itNumber/btype->itNumber);
+ }
+
+ /*
+ * If number of elements is too many for user receiving area,
+ * fill user`s area as much as possible. Return the correct
+ * number of elements.
+ */
+ fprintf(file, "\t\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField);
+ if (btype->itTypeSize > 1)
+ fprintf(file, "%d * ", btype->itTypeSize);
+ if (arg->argCountInOut) {
+ fprintf(file, " %s%s);\n", countRef, count->argVarName);
+ }
+ else {
+ fprintf(file, " %d);\n", argType->itNumber/btype->itNumber);
+ }
+ fprintf(file, "\t\t%s%s = Out%dP->%s", countRef, count->argVarName, count->argReplyPos, count->argMsgField);
+ fprintf(file, ";\n");
+ WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
+
+ fprintf(file, "\t}\n");
+
+ fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField);
+ if (btype->itTypeSize > 1)
+ fprintf(file, "%d * ", btype->itTypeSize);
+ fprintf(file, "Out%dP->%s);\n", count->argReplyPos, count->argMsgField);
+ }
+ }
+ else
+ WriteCopyType(file, argType, FALSE, "%s%s", "/* %s%s */ %s->%s", ref, arg->argVarName, who, arg->argMsgField);
+ fprintf(file, "\n");
+}
+
+static void
+WriteCalcArgSize(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+ ipc_type_t *btype = ptype->itElement;
+ argument_t *count = arg->argCount;
+ int multiplier = btype->itTypeSize;
+
+ /* If the base type size of the data field isn`t a multiple of 4,
+ we have to round up. */
+ if (btype->itTypeSize % itWordAlign != 0)
+ fprintf(file, "_WALIGN_(");
+
+ fprintf(file, "Out%dP->%s", count->argReplyPos, count->argMsgField);
+ if (multiplier > 1)
+ fprintf(file, " * %d", multiplier);
+
+ if (btype->itTypeSize % itWordAlign != 0)
+ fprintf(file, ")");
+}
+
+static void
+WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator)
+{
+ ipc_type_t *ptype = arg->argType;
+ ipc_type_t *btype = ptype->itElement;
+ argument_t *count = arg->argCount;
+ int multiplier = btype->itTypeSize;
+
+ fprintf(file, "\tif (((msgh_size - ");
+ rtMinReplySize(file, rt, "__Reply");
+ fprintf(file, ")");
+ if (multiplier > 1)
+ fprintf(file, " / %d", multiplier);
+ fprintf(file, "< Out%dP->%s) ||\n", count->argReplyPos, count->argMsgField);
+ fprintf(file, "\t (msgh_size %s ", comparator);
+ rtMinReplySize(file, rt, "__Reply");
+ fprintf(file, " + ");
+ WriteCalcArgSize(file, arg);
+ fprintf(file, ")");
+ fprintf(file, ")\n\t\t{ return MIG_TYPE_ERROR ; }\n");
+}
+
+
+/* NDR Conversion routines */
+
+
+void
+WriteReplyNDRConvertIntRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ fprintf(file, "defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+}
+
+void
+WriteReplyNDRConvertCharRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ fprintf(file, "defined(__NDR_convert__char_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+ else
+ fprintf(file, "0");
+}
+
+void
+WriteReplyNDRConvertFloatRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ fprintf(file, "defined(__NDR_convert__float_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+ else
+ fprintf(file, "0");
+}
+
+void
+WriteReplyNDRConvertIntRepArgDecl(FILE *file, argument_t *arg)
+{
+ WriteNDRConvertArgDecl(file, arg, "int_rep", "Reply");
+}
+
+void
+WriteReplyNDRConvertCharRepArgDecl(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ WriteNDRConvertArgDecl(file, arg, "char_rep", "Reply");
+}
+
+void
+WriteReplyNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ WriteNDRConvertArgDecl(file, arg, "float_rep", "Reply");
+}
+
+
+
+void
+WriteReplyNDRConvertArgUse(FILE *file, argument_t *arg, char *convert)
+{
+ routine_t *rt = arg->argRoutine;
+ argument_t *count = arg->argCount;
+ char argname[MAX_STR_LEN];
+
+ if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) &&
+ (arg->argParent && akCheck(arg->argParent->argKind, akbReturnNdr)))
+ return;
+
+ if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+ if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) {
+ fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, count->argMsgField);
+ fprintf(file, "\t\t__NDR_convert__int_rep__Reply__%s_t__%s(&Out%dP->%s, Out%dP->NDR.int_rep);\n", rt->rtName, count->argMsgField, count->argReplyPos, count->argMsgField, count->argReplyPos);
+ fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, count->argMsgField);
+ }
+
+ sprintf(argname, "(%s)(Out%dP->%s.address)", FetchServerType(arg->argType), arg->argReplyPos, arg->argMsgField);
+ }
+ else {
+ sprintf(argname, "&Out%dP->%s", arg->argReplyPos, arg->argMsgField);
+ }
+
+ fprintf(file, "#if defined(__NDR_convert__%s__Reply__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField);
+ fprintf(file, "\t\t__NDR_convert__%s__Reply__%s_t__%s(%s, Out0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert);
+ if (count)
+ fprintf(file, ", Out%dP->%s", count->argReplyPos, count->argMsgField);
+ fprintf(file, ");\n");
+ fprintf(file, "#endif /* __NDR_convert__%s__Reply__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField);
+}
+
+void
+WriteReplyNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField);
+ fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep)\n");
+ fprintf(file, "\t\t__NDR_convert__int_rep__Reply__%s_t__%s(&Out%dP->%s, Out%dP->NDR.int_rep);\n", rt->rtName, arg->argMsgField, arg->argReplyPos, arg->argMsgField, arg->argReplyPos);
+ fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField);
+}
+
+void
+WriteReplyNDRConvertIntRepArgUse(FILE *file, argument_t *arg)
+{
+ WriteReplyNDRConvertArgUse(file, arg, "int_rep");
+}
+
+void
+WriteReplyNDRConvertCharRepArgUse(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ WriteReplyNDRConvertArgUse(file, arg, "char_rep");
+}
+
+void
+WriteReplyNDRConvertFloatRepArgUse(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ WriteReplyNDRConvertArgUse(file, arg, "float_rep");
+}
+
+static void
+WriteCheckMsgSize(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ /* If there aren't any more Out args after this, then
+ we can use the msgh_size_delta value directly in
+ the TypeCheck conditional. */
+
+ if (CheckNDR && arg->argCount && !arg->argSameCount)
+ WriteReplyNDRConvertIntRepOneArgUse(file, arg->argCount);
+
+ if (arg->argReplyPos == rt->rtMaxReplyPos) {
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ /*
+ * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type.
+ */
+ fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos, arg->argCount->argMsgField, arg->argType->itNumber);
+ fputs("\t\t" "return MIG_TYPE_ERROR;\n", file);
+ /* ...end... */
+
+ WriteCheckArgSize(file, rt, arg, "!=");
+
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ else {
+ /* If there aren't any more variable-sized arguments after this,
+ then we must check for exact msg-size and we don't need
+ to update msgh_size. */
+
+ boolean_t LastVarArg = arg->argReplyPos+1 == rt->rtNumReplyVar;
+
+ /* calculate the actual size in bytes of the data field. note
+ that this quantity must be a multiple of four. hence, if
+ the base type size isn't a multiple of four, we have to
+ round up. note also that btype->itNumber must
+ divide btype->itTypeSize (see itCalculateSizeInfo). */
+
+ fprintf(file, "\tmsgh_size_delta = ");
+ WriteCalcArgSize(file, arg);
+ fprintf(file, ";\n");
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ /*
+ * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type.
+ */
+ fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos, arg->argCount->argMsgField, arg->argType->itNumber);
+ fputs("\t\t" "return MIG_TYPE_ERROR;\n", file);
+ /* ...end... */
+
+ WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<");
+
+ if (!LastVarArg)
+ fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
+
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ fprintf(file, "\n");
+}
+
+void
+WriteAdjustReplyMsgPtr(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+
+ fprintf(file, "\t*Out%dPP = Out%dP = (__Reply *) ((pointer_t) Out%dP + msgh_size_delta - %d);\n\n",
+ arg->argReplyPos+1, arg->argReplyPos +1, arg->argReplyPos, ptype->itTypeSize + ptype->itPadSize);
+}
+
+static void
+WriteReplyArgs(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) {
+ WriteExtractArgValueNormal(file, arg);
+ }
+ else if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnKPD)) {
+ /*
+ * KPDs have argReplyPos 0, therefore they escape the above logic
+ */
+ (*arg->argKPD_Extract)(file, arg);
+ }
+ else if (akCheck(arg->argKind, akbUserImplicit)) {
+ WriteExtractArgValueNormal(file, arg);
+ }
+ }
+}
+
+/*************************************************************
+ * Writes code to return the return value. Called by WriteRoutine
+ * for routines and functions.
+ *************************************************************/
+static void
+WriteReturnValue(FILE *file, routine_t *rt)
+{
+ /* If returning RetCode, we have already checked that it is KERN_SUCCESS */
+ WriteReturn(file, rt, "\t", "KERN_SUCCESS", "\n", TRUE);
+}
+
+/*************************************************************
+ * Writes the elements of the message type declaration: the
+ * msg_type structure, the argument itself and any padding
+ * that is required to make the argument a multiple of 4 bytes.
+ * Called by WriteRoutine for all the arguments in the request
+ * message first and then the reply message.
+ *************************************************************/
+static void
+WriteFieldDecl(FILE *file, argument_t *arg)
+{
+ if (akCheck(arg->argKind, akbSendKPD) ||
+ akCheck(arg->argKind, akbReturnKPD))
+ WriteFieldDeclPrim(file, arg, FetchKPDType);
+ else
+ WriteFieldDeclPrim(file, arg, FetchUserType);
+}
+
+/* Fill in the string with an expression that refers to the size
+ * of the specified array:
+ */
+static void
+GetArraySize(argument_t *arg, char *size)
+{
+ ipc_type_t *it = arg->argType;
+
+ if (it->itVarArray) {
+ if (arg->argCount->argByReferenceUser) {
+ sprintf(size, "*%s", arg->argCount->argVarName);
+ }
+ else
+ sprintf(size, "%s", arg->argCount->argVarName);
+ }
+ else {
+ sprintf(size, "%d", (it->itNumber * it->itSize + 7) / 8);
+ }
+}
+
+
+static void
+WriteRPCPortDisposition(FILE *file, argument_t *arg)
+{
+ /*
+ * According to the MIG specification, the port disposition could be different
+ * on input and output. If we stay with this then a new bitfield will have
+ * to be added. Right now the port disposition is the same for in and out cases.
+ */
+ switch(arg->argType->itInName) {
+
+ case MACH_MSG_TYPE_MOVE_RECEIVE:
+ fprintf(file, " | MACH_RPC_MOVE_RECEIVE");
+ break;
+
+ case MACH_MSG_TYPE_MOVE_SEND:
+ fprintf(file, " | MACH_RPC_MOVE_SEND");
+ break;
+
+ case MACH_MSG_TYPE_MOVE_SEND_ONCE:
+ fprintf(file, " | MACH_RPC_MOVE_SEND_ONCE");
+ break;
+
+ case MACH_MSG_TYPE_COPY_SEND:
+ fprintf(file, " | MACH_RPC_COPY_SEND");
+ break;
+
+ case MACH_MSG_TYPE_MAKE_SEND:
+ fprintf(file, " | MACH_RPC_MAKE_SEND");
+ break;
+
+ case MACH_MSG_TYPE_MAKE_SEND_ONCE:
+ fprintf(file, " | MACH_RPC_MAKE_SEND_ONCE");
+ break;
+ }
+}
+
+static void
+WriteRPCArgDescriptor(FILE *file, argument_t *arg, int offset)
+{
+ fprintf(file, " {\n 0 ");
+ if (RPCPort(arg)) {
+ fprintf(file, "| MACH_RPC_PORT ");
+ if (arg->argType->itNumber > 1)
+ fprintf(file, "| MACH_RPC_ARRAY ");
+ if (arg->argType->itVarArray)
+ fprintf(file, "| MACH_RPC_VARIABLE ");
+ WriteRPCPortDisposition(file, arg);
+ }
+ else if (RPCPortArray(arg)) {
+ fprintf(file, "| MACH_RPC_PORT_ARRAY ");
+ if (arg->argType->itVarArray)
+ fprintf(file, "| MACH_RPC_VARIABLE ");
+ WriteRPCPortDisposition(file, arg);
+ }
+ else if (RPCFixedArray(arg))
+ fprintf(file, "| MACH_RPC_ARRAY_FIXED ");
+ else if (RPCVariableArray(arg))
+ fprintf(file, "| MACH_RPC_ARRAY_VARIABLE ");
+ if (argIsIn(arg))
+ fprintf(file, " | MACH_RPC_IN ");
+ if (argIsOut(arg))
+ fprintf(file, " | MACH_RPC_OUT ");
+ if ((! arg->argType->itInLine) && (! arg->argType->itMigInLine))
+ fprintf(file, " | MACH_RPC_POINTER ");
+ if (arg->argFlags & flDealloc)
+ fprintf(file, " | MACH_RPC_DEALLOCATE ");
+ if (arg->argFlags & flPhysicalCopy)
+ fprintf(file, " | MACH_RPC_PHYSICAL_COPY ");
+ fprintf(file, ",\n");
+ fprintf(file, " %d,\n", (arg->argType->itSize / 8));
+ fprintf(file, " %d,\n", arg->argType->itNumber);
+ fprintf(file, " %d,\n },\n", offset);
+}
+
+void
+WriteRPCRoutineDescriptor(FILE *file, routine_t *rt, int arg_count, int descr_count, string_t stub_routine, string_t sig_array)
+{
+ fprintf(file, " { (mig_impl_routine_t) 0,\n\
+ (mig_stub_routine_t) %s, ", stub_routine);
+ fprintf(file, "%d, %d, %s}", arg_count, descr_count, sig_array);
+}
+
+void
+WriteRPCRoutineArgDescriptor(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ int offset = 0;
+ int size = 0;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ boolean_t compound = arg->argType->itStruct && arg->argType->itInLine;
+
+ if (RPCPort(arg) || RPCPortArray(arg) ||
+ RPCFixedArray(arg) || RPCVariableArray(arg)) {
+ WriteRPCArgDescriptor(file, arg, offset);
+ size = 4;
+ }
+ if (! size) {
+ if (compound)
+ size = arg->argType->itNumber * (arg->argType->itSize / 8);
+ else
+ size = (arg->argType->itSize / 8);
+ }
+ if (akCheck(arg->argKind, akbServerArg))
+ offset += size;
+ size = 0;
+ }
+}
+
+
+static void
+WriteRPCSignature(FILE *file, routine_t *rt)
+{
+ int arg_count = 0;
+ int descr_count = 0;
+
+ fprintf(file, " kern_return_t rtn;\n");
+ descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count);
+ fprintf(file, " const static struct\n {\n");
+ fprintf(file, " struct rpc_routine_descriptor rd;\n");
+ fprintf(file, " struct rpc_routine_arg_descriptor rad[%d];\n", descr_count);
+ fprintf(file, " } sig =\n {\n");
+ WriteRPCRoutineDescriptor(file, rt, arg_count, descr_count, "0", "sig.rad, 0");
+ fprintf(file, ",\n");
+ fprintf(file, " {\n");
+ WriteRPCRoutineArgDescriptor(file, rt);
+ fprintf(file, "\n }\n");
+ fprintf(file, "\n };\n\n");
+}
+
+static void
+WriteRPCCall(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ int i;
+
+ i = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akIdent(arg->argKind) == akeRequestPort) {
+ fprintf(file, " rtn = (MACH_RPC(&sig, (mach_msg_size_t)sizeof(sig), %d, %s,\n", rt->rtNumber + SubsystemBase, arg->argVarName);
+ fprintf(file, " (%s", arg->argVarName);
+ }
+ else if (akCheck(arg->argKind, akbServerArg)) {
+ if (i && (i++ % 6 == 0))
+ fprintf(file, ",\n ");
+ else
+ fprintf(file, ", ");
+ fprintf(file, "%s", arg->argVarName);
+ }
+ }
+ fprintf(file, ")));\n");
+ fprintf(file, "\n");
+ fprintf(file, " if (rtn != KERN_NO_ACCESS) return rtn;\n\n");
+ fprintf(file, "/* The following message rpc code is generated for the network case */\n\n");
+}
+
+static int
+CheckRPCCall(routine_t *rt)
+{
+ argument_t *arg;
+ int i;
+
+ i = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akCheck(arg->argKind, akbUserArg) &&
+ ((arg->argType->itOutName == -1) || (arg->argType->itInName == -1))) {
+ return FALSE;
+ }
+ if (arg->argFlags & flMaybeDealloc) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static void
+WriteRPCRoutine(FILE *file, routine_t *rt)
+{
+ if (CheckRPCCall(rt)) {
+ WriteRPCSignature(file, rt);
+ WriteRPCCall(file, rt);
+ }
+}
+
+/********************** End UserRPCTrap Routines*************************/
+
+/* Process an IN/INOUT arg before the short-circuited RPC */
+static void
+WriteShortCircInArgBefore(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char size[128];
+
+ fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName);
+
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* Arg is an out-of-line array: */
+ if (!(arg->argFlags & flDealloc) &&
+ (!(arg->argFlags & flAuto) || !(arg->argFlags & flConst))) {
+ /* Need to map a copy of the array: */
+ GetArraySize(arg, size);
+ fprintf(file, "\t(void)vm_read(mach_task_self(),\n");
+ fprintf(file, "\t\t (vm_address_t) %s%s, %s, (vm_address_t *) &_%sTemp_, &_MIG_Ignore_Count_);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size, arg->argVarName);
+ /* Point argument at the copy: */
+ fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
+ }
+ else if ((arg->argFlags & flDealloc) &&
+ ((arg->argFlags & flAuto) || it->itMigInLine)) {
+ /* Point the temp var at the original argument: */
+ fprintf(file, "\t_%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+ }
+ else if (it->itNumber > 1) {
+ if (it->itStruct) {
+ /* Arg is a struct -- nothing to do. */
+ }
+ else {
+ /* Arg is a C string or an in-line array: */
+ if (!argIsOut(arg) && !(arg->argFlags & flConst)) {
+ /* Have to copy it into a temp. Use a stack var, if this would
+ * not overflow the -maxonstack specification:
+ * Conservatively assume ILP32 thresholds
+ */
+ if (it->itTypeSize <= sizeof(natural_t) ||
+ rtMessOnStack(arg->argRoutine) ||
+ arg->argRoutine->rtTempBytesOnStack +
+ it->itTypeSize <= MaxMessSizeOnStack) {
+ fprintf(file, "\t{ char _%sTemp_[%d];\n", arg->argVarName, it->itTypeSize);
+ arg->argRoutine->rtTempBytesOnStack += it->itTypeSize;
+ arg->argTempOnStack = TRUE;
+ }
+ else {
+ fprintf(file, "\t{ _%sTemp_ = (char *) %s(%d);\n", arg->argVarName, MessAllocRoutine, it->itTypeSize);
+ arg->argTempOnStack = FALSE;
+ }
+ WriteCopyArg(file, arg, TRUE, "_%sTemp_", "/* %s */ (char *) %s", arg->argVarName, arg->argVarName);
+ /* Point argument at temp: */
+ fprintf(file, "\t *(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
+ fprintf(file, "\t}\n");
+ }
+ }
+ }
+}
+
+
+/* Process an INOUT/OUT arg before the short-circuited RPC */
+static void
+WriteShortCircOutArgBefore(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName);
+
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* Arg is an out-of-line array: */
+ if (!argIsIn(arg) && (arg->argFlags & flOverwrite)) {
+ /* Point the temp var at the original argument: */
+ fprintf(file, "\t _%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+ }
+ else if (it->itNumber > 1) {
+ /* Arg is an in-line array: */
+ }
+}
+
+
+
+/* Process an IN arg after the short-circuited RPC */
+static void
+WriteShortCircInArgAfter(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char size[128];
+
+ fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName);
+
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* Arg is an out-of-line array: */
+ GetArraySize(arg, size);
+ if ((!(arg->argFlags & flAuto) && it->itMigInLine) ||
+ ((arg->argFlags & flAuto) &&
+ ((arg->argFlags & flDealloc) ||
+ !(arg->argFlags & flConst))
+ )) {
+ /* Need to dealloc the temporary: */
+ fprintf(file, "\t(void)vm_deallocate(mach_task_self(),");
+ fprintf(file, " (vm_address_t *) _%sTemp_, %s);\n", arg->argVarName, size);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+ }
+ else if (it->itNumber > 1) {
+ if (it->itStruct) {
+ /* Arg is a struct -- nothing to do. */
+ }
+ else {
+ /* Arg is a C string or an in-line array: */
+ if (!argIsOut(arg) && !(arg->argFlags & flConst)) {
+ /* A temp needs to be deallocated, if not on stack: */
+ if (!arg->argTempOnStack) {
+ fprintf(file, "\t%s(_%sTemp_, %d);\n", MessFreeRoutine, arg->argVarName, it->itTypeSize);
+ }
+ }
+ }
+ }
+}
+
+static void
+WriteShortCircOutArgAfter(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char size[128];
+
+ fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName);
+
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* Arg is an out-of-line array: */
+
+ /* Calculate size of array: */
+ GetArraySize(arg, size);
+ if (!(arg->argFlags & flDealloc) || (arg->argFlags & flOverwrite)) {
+ /* Copy argument to vm_allocated Temp: */
+ fprintf(file, "\t(void)vm_read(mach_task_self(),\n");
+ fprintf(file, "\t\t (vm_address_t) %s%s, %s, (vm_address_t *) &_%sTemp_, &_MIG_Ignore_Count_);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size, arg->argVarName);
+ if (!argIsIn(arg) && (arg->argFlags & flDealloc) &&
+ (arg->argFlags & flOverwrite)) {
+ /* Deallocate argument returned by server */
+ fprintf(file, "\t(void)vm_deallocate(mach_task_self(),");
+ fprintf(file, " (vm_address_t *) %s%s, %s);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size);
+ }
+ /* Point argument at new temporary: */
+ fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+ }
+ else if (it->itNumber != 1) {
+ /* Arg is an in-line array: */
+ }
+}
+
+
+static void
+WriteShortCircRPC(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ int server_argc, i;
+ boolean_t ShortCircOkay = TRUE;
+ boolean_t first_OOL_arg = TRUE;
+
+ fprintf(file, " if (0 /* Should be: !(%s & 0x3) XXX */) {\n", rt->rtRequestPort->argVarName);
+
+ if (rt->rtOneWay) {
+ /* Do not short-circuit simple routines: */
+ ShortCircOkay = FALSE;
+ }
+ else {
+ /* Scan for any types we can't yet handle. If found, give up on short-
+ * circuiting and fall back to mach_msg:
+ */
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (arg->argFlags & flMaybeDealloc) {
+ ShortCircOkay = FALSE;
+ break;
+ }
+ /* Can't yet handle ports: */
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
+ (arg->argKPD_Type == MACH_MSG_PORT_DESCRIPTOR ||
+ arg->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR)) {
+ ShortCircOkay = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (ShortCircOkay) {
+
+ fprintf(file," rpc_subsystem_t subsystem = ((rpc_port_t)%s)->rp_subsystem;\n", rt->rtRequestPort->argVarName);
+ fprintf(file, "\n");
+ fprintf(file, " if (subsystem && subsystem->start == %d) {\n", SubsystemBase);
+ fprintf(file, "\tkern_return_t rtn;\n");
+ fprintf(file, "\n");
+
+ /* Declare temp vars for out-of-line array args, and for all array
+ * args, if -maxonstack has forced us to allocate in-line arrays
+ * off the stack:
+ */
+ rt->rtTempBytesOnStack = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ arg->argTempOnStack = FALSE;
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
+ arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+ if (first_OOL_arg) {
+ /* Need a garbage temporary to hold the datacount
+ * returned by vm_read, which we always ignore:
+ */
+ fprintf(file, "\tmach_msg_type_number_t _MIG_Ignore_Count_;\n");
+ first_OOL_arg = FALSE;
+ }
+ }
+ else if (!rtMessOnStack(rt) &&
+ arg->argType->itNumber > 1 && !arg->argType->itStruct) {
+ }
+ else
+ continue;
+ fprintf(file, "\tchar *_%sTemp_;\n", arg->argVarName);
+ /* Conservatively assume ILP32 thresholds */
+ rt->rtTempBytesOnStack += sizeof(natural_t);
+ }
+
+ /* Process the IN arguments, in order: */
+
+ fprintf(file, "\t/* Pre-Process the IN arguments: */\n");
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (argIsIn(arg))
+ WriteShortCircInArgBefore(file, arg);
+ if (argIsOut(arg))
+ WriteShortCircOutArgBefore(file, arg);
+ }
+ fprintf(file, "\n");
+
+ /* Count the number of server args: */
+ server_argc = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, akbServerArg))
+ server_argc++;
+
+ /* Call RPC_SIMPLE to switch to server stack and function: */
+ i = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akIdent(arg->argKind) == akeRequestPort) {
+ fprintf(file, "\trtn = RPC_SIMPLE(%s, %d, %d, (", arg->argVarName, rt->rtNumber + SubsystemBase, server_argc);
+ fprintf(file, "%s", arg->argVarName);
+ }
+ else if (akCheck(arg->argKind, akbServerArg)) {
+ if (i++ % 6 == 0)
+ fprintf(file, ",\n\t\t");
+ else
+ fprintf(file, ", ");
+ fprintf(file, "%s", arg->argVarName);
+ }
+ }
+ fprintf(file, "));\n");
+ fprintf(file, "\n");
+
+ /* Process the IN and OUT arguments, in order: */
+ fprintf(file, "\t/* Post-Process the IN and OUT arguments: */\n");
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (argIsIn(arg))
+ WriteShortCircInArgAfter(file, arg);
+ if (argIsOut(arg))
+ WriteShortCircOutArgAfter(file, arg);
+ }
+ fprintf(file, "\n");
+
+ fprintf(file, "\treturn rtn;\n");
+ fprintf(file, " }\n");
+ }
+
+ /* In latest design, the following is not necessary, because in
+ * kernel-loaded tasks, the Mach port name is the same as the handle
+ * used by the RPC mechanism, namely a pointer to the ipc_port, and
+ * in user-mode tasks, the Mach port name gets renamed to be a pointer
+ * to the user-mode rpc_port_t struct.
+ */
+#if 0
+ if (IsKernelUser)
+ fprintf(file, " %s = (ipc_port_t)%s->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName);
+ else
+ fprintf(file, " %s = ((rpc_port_t)%s)->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName);
+#endif
+
+ fprintf(file, " }\n");
+}
+
+static void
+WriteStubDecl(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\n");
+ fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
+ fprintf(file, "mig_external %s %s\n", ReturnTypeStr(rt), rt->rtUserName);
+ if (BeAnsiC) {
+ fprintf(file, "(\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
+ fprintf(file, ")\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "(\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
+ fprintf(file, ")\n");
+ fprintf(file, "#else\n");
+ fprintf(file, "\t(");
+ WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", "");
+ fprintf(file, ")\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+ fprintf(file, "{\n");
+}
+
+static void
+InitKPD_Disciplines(argument_t *args)
+{
+ argument_t *arg;
+ extern void KPD_noop(FILE *file, argument_t *arg);
+ extern void KPD_error(FILE *file, argument_t *arg);
+ extern void WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in);
+ extern void WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in);
+ extern void WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in);
+
+ /*
+ * WriteKPD_port, WriteExtractKPD_port,
+ * WriteKPD_ool, WriteExtractKPD_ool,
+ * WriteKPD_oolport, WriteExtractKPD_oolport
+ * are local to this module (which is the reason why this initialization
+ * takes place here rather than in utils.c).
+ * Common routines for user and server will be established SOON, and
+ * all of them (including the initialization) will be transfert to
+ * utils.c
+ * All the KPD disciplines are defaulted to be KPD_error().
+ * Note that akbSendKPD and akbReturnKPd are not exclusive,
+ * because of inout type of parameters.
+ */
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD))
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ arg->argKPD_Init = KPD_noop;
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_port;
+ arg->argKPD_Pack = WriteKPD_port;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_Extract = WriteExtractKPD_port;
+ arg->argKPD_TypeCheck = WriteTCheckKPD_port;
+ }
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ arg->argKPD_Init = KPD_noop;
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_ool;
+ arg->argKPD_Pack = WriteKPD_ool;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_TypeCheck = WriteTCheckKPD_ool;
+ arg->argKPD_Extract = WriteExtractKPD_ool;
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ arg->argKPD_Init = KPD_noop;
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_oolport;
+ arg->argKPD_Pack = WriteKPD_oolport;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_TypeCheck = WriteTCheckKPD_oolport;
+ arg->argKPD_Extract = WriteExtractKPD_oolport;
+ }
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+}
+
+static void
+WriteLimitCheck(FILE *file, routine_t *rt)
+{
+ if (MaxMessSizeOnStack == -1 || UserTypeLimit == -1)
+ return;
+ if (!rt->rtRequestUsedLimit && !rt->rtReplyUsedLimit)
+ return;
+ fprintf(file, "#if LimitCheck\n");
+ if (rt->rtRequestUsedLimit) {
+ if (rt->rtRequestFits) {
+ fprintf(file, "\tif ((sizeof(Request) - %d) > %d)\n", rt->rtRequestSizeKnown, UserTypeLimit);
+ fprintf(file, "\t __RequestOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ else if (rt->rtReplyFits) {
+ fprintf(file, "\tif (sizeof(Request) < %d)\n", MaxMessSizeOnStack);
+ fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ }
+ if (rt->rtReplyUsedLimit) {
+ if (rt->rtReplyFits) {
+ fprintf(file, "\tif ((sizeof(Reply) - %d) > %d)\n", rt->rtReplySizeKnown, UserTypeLimit);
+ fprintf(file, "\t __ReplyOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ else if (rt->rtRequestFits) {
+ fprintf(file, "\tif (sizeof(Reply) < %d)\n", MaxMessSizeOnStack);
+ fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ }
+ if (rt->rtRequestUsedLimit && rt->rtReplyUsedLimit &&
+ ! (rt->rtRequestFits || rt->rtReplyFits)) {
+ fprintf(file, "\tif (sizeof(Request) < %d \n", MaxMessSizeOnStack);
+ fprintf(file, "&& sizeof(Reply) < %d)\n", MaxMessSizeOnStack);
+ fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ fprintf(file, "#endif /* LimitCheck */\n");
+}
+
+static void
+WriteOOLSizeCheck(FILE *file, routine_t *rt)
+{
+ /* Emit code to validate the actual size of ool data vs. the reported size */
+ argument_t *argPtr;
+ boolean_t openedTypeCheckConditional = FALSE;
+
+ // scan through arguments to see if there are any ool data blocks
+ for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
+ if (akCheck(argPtr->argKind, akbReturnKPD)) {
+ ipc_type_t *it = argPtr->argType;
+ boolean_t multiple_kpd = IS_MULTIPLE_KPD(it);
+ char string[MAX_STR_LEN];
+ boolean_t test;
+ argument_t *argCountPtr;
+ char *tab;
+
+ if (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+
+ if (multiple_kpd) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ it = it->itElement; // point to element descriptor, so size calculation is correct
+ argCountPtr = argPtr->argSubCount;
+ } else {
+ tab = "";
+ sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField);
+ test = !it->itVarArray;
+ argCountPtr = argPtr->argCount;
+ }
+
+ if (!test) {
+ int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1;
+
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ fprintf(file, "\t%s" "if (%ssize ", tab, string);
+ if (multiplier > 1)
+ fprintf(file, "/ %d ", multiplier);
+ fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : "");
+ if (it->itOOL_Number) {
+ fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos,
+ argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number);
+ }
+ fprintf(file,")\n");
+ fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
+ }
+
+ if (multiple_kpd)
+ fprintf(file, "\t }\n\t}\n");
+ } else if (argPtr->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR) {
+ if (multiple_kpd) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ it = it->itElement; // point to element descriptor, so size calculation is correct
+ argCountPtr = argPtr->argSubCount;
+ } else {
+ tab = "";
+ sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField);
+ test = !it->itVarArray;
+ argCountPtr = argPtr->argCount;
+ }
+
+ if (!test) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ fprintf(file, "\t%s" "if (%scount ", tab, string);
+ fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : "");
+ if (it->itOOL_Number) {
+ fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos,
+ argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number);
+ }
+ fprintf(file,")\n");
+ fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
+ }
+
+ if (multiple_kpd)
+ fprintf(file, "\t }\n\t}\n");
+ }
+ }
+ }
+
+ if ( openedTypeCheckConditional )
+ fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file);
+}
+
+static void
+WriteCheckReply(FILE *file, routine_t *rt)
+{
+ int i;
+
+ /* initialize the disciplines for the handling of KPDs */
+ InitKPD_Disciplines(rt->rtArgs);
+
+ if (rt->rtOneWay)
+ return;
+
+ fprintf(file, "\n");
+ fprintf(file, "#if ( __MigTypeCheck ");
+ if (CheckNDR)
+ fprintf(file, "|| __NDR_convert__ ");
+ fprintf(file, ")\n");
+ fprintf(file, "#if __MIG_check__Reply__%s_subsystem__\n", SubsystemName);
+ fprintf(file, "#if !defined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName);
+ fprintf(file, "#define __MIG_check__Reply__%s_t__defined\n", rt->rtName);
+ if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) {
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgDecl, akbReturnNdr, "\n", "\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgDecl, akbReturnNdr, "\n", "\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgDecl, akbReturnNdr, "\n", "\n");
+ }
+ fprintf(file, "\n");
+ fprintf(file, "mig_internal kern_return_t __MIG_check__Reply__%s_t(__Reply__%s_t *Out0P", rt->rtName, rt->rtName);
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, ", __Reply__%s_t **Out%dPP", rt->rtName, i);
+ fprintf(file, ")\n{\n");
+
+
+ fprintf(file, "\n\ttypedef __Reply__%s_t __Reply __attribute__((unused));\n", rt->rtName);
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, "\t__Reply *Out%dP;\n", i);
+ if (!rt->rtSimpleReply)
+ fprintf(file, "\tboolean_t msgh_simple;\n");
+ if (!rt->rtNoReplyArgs) {
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tunsigned int msgh_size;\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ if (rt->rtMaxReplyPos > 0)
+ fprintf(file, "\tunsigned int msgh_size_delta;\n");
+ if (rt->rtNumReplyVar > 0 || rt->rtMaxReplyPos > 0)
+ fprintf(file, "\n");
+
+ /* Check the values that are returned in the reply message */
+
+ WriteCheckIdentity(file, rt);
+
+ /* Check the remote port is NULL */
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tif (Out0P->Head.msgh_request_port != MACH_PORT_NULL) {\n");
+ fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+
+ /* If the reply message has no Out parameters or return values
+ other than the return code, we can type-check it and
+ return it directly. */
+
+ if (rt->rtNoReplyArgs && !rt->rtUserImpl) {
+ if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply) && rt->rtRetCode)
+ WriteReplyNDRConvertIntRepOneArgUse(file, rt->rtRetCode);
+ WriteReturn(file, rt, "\t", stRetCode, "\n", FALSE);
+ }
+ else {
+ if (UseEventLogger)
+ WriteLogMsg(file, rt, LOG_USER, LOG_REPLY);
+
+ WriteRetCodeCheck(file, rt);
+
+ /* Type Checking for the Out parameters which are typed */
+ WriteList(file, rt->rtArgs, WriteTypeCheck, akbReturnKPD, "\n", "\n");
+
+ {
+ argument_t *arg, *lastVarArg;
+
+ lastVarArg = argNULL;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ /*
+ * Advance message pointer if the last reply argument was
+ * variable-length and the reply position will change.
+ */
+ if (lastVarArg != argNULL &&
+ lastVarArg->argReplyPos < arg->argReplyPos) {
+ WriteAdjustReplyMsgPtr(file, lastVarArg);
+ lastVarArg = argNULL;
+ }
+
+ if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) {
+ if (akCheck(arg->argKind, akbVariable)) {
+ WriteCheckMsgSize(file, arg);
+ lastVarArg = arg;
+ }
+ }
+ }
+ }
+
+ if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) {
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgUse, akbReturnNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n");
+
+ WriteOOLSizeCheck(file, rt);
+
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (Out0P->NDR.char_rep != NDR_record.char_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgUse, akbReturnNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n");
+
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (Out0P->NDR.float_rep != NDR_record.float_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgUse, akbReturnNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n");
+ } else {
+ WriteOOLSizeCheck(file, rt);
+ }
+ fprintf(file, "\treturn MACH_MSG_SUCCESS;\n");
+ }
+ fprintf(file, "}\n");
+ fprintf(file, "#endif /* !defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName);
+ fprintf(file, "#endif /* __MIG_check__Reply__%s_subsystem__ */\n", SubsystemName);
+ fprintf(file, "#endif /* ( __MigTypeCheck ");
+ if (CheckNDR)
+ fprintf(file, "|| __NDR_convert__ ");
+ fprintf(file, ") */\n\n");
+}
+
+static void
+WriteCheckReplyCall(FILE *file, routine_t *rt)
+{
+ int i;
+
+ fprintf(file, "\n");
+ fprintf(file, "#if\tdefined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName);
+ fprintf(file, "\tcheck_result = __MIG_check__Reply__%s_t((__Reply__%s_t *)Out0P", rt->rtName, rt->rtName);
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, ", (__Reply__%s_t **)&Out%dP", rt->rtName, i);
+ fprintf(file, ");\n");
+ fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS) {\n");
+ if (IsKernelUser) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "\t\tmach_msg_destroy_from_kernel(&Out0P->Head);\n");
+ fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
+ } else {
+ fprintf(file, "\t\tmach_msg_destroy(&Out0P->Head);\n");
+ }
+ WriteReturnMsgError(file, rt, TRUE, argNULL, "check_result");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif\t/* defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName);
+ fprintf(file, "\n");
+}
+
+void
+WriteCheckReplies(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine)
+ WriteCheckReply(file, stat->stRoutine);
+}
+
+static void
+WriteCheckReplyTrailerArgs(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+
+ if (rt->rtUserImpl)
+ WriteCheckTrailerHead(file, rt, TRUE);
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akCheck(arg->argKind, akbUserImplicit))
+ WriteCheckTrailerSize(file, TRUE, arg);
+ }
+ if (rt->rtUserImpl)
+ fprintf(file, "\n");
+}
+
+
+/*************************************************************
+ * Writes all the code comprising a routine body. Called by
+ * WriteUser for each routine.
+ *************************************************************/
+static void
+WriteRoutine(FILE *file, routine_t *rt)
+{
+ /* write the stub's declaration */
+ WriteStubDecl(file, rt);
+
+ /* Use the RPC trap for user-user and user-kernel RPC */
+ if (UseRPCTrap)
+ WriteRPCRoutine(file, rt);
+
+ /* write the code for doing a short-circuited RPC: */
+ if (ShortCircuit)
+ WriteShortCircRPC(file, rt);
+
+ /* typedef of structure for Request and Reply messages */
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, FALSE, FALSE, FALSE);
+ if (!rt->rtOneWay) {
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply", rt->rtSimpleReply, TRUE, rt->rtUserImpl, FALSE);
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "__Reply", rt->rtSimpleReply, FALSE, FALSE, FALSE);
+ }
+ if (rt->rtOverwrite)
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply|akbOverwrite, "OverwriteTemplate", FALSE, TRUE, FALSE, TRUE);
+ /*
+ * Define a Minimal Reply structure to be used in case of errors
+ */
+ fprintf(file, "\t/*\n");
+ fprintf(file, "\t * typedef struct {\n");
+ fprintf(file, "\t * \tmach_msg_header_t Head;\n");
+ fprintf(file, "\t * \tNDR_record_t NDR;\n");
+ fprintf(file, "\t * \tkern_return_t RetCode;\n");
+ fprintf(file, "\t * } mig_reply_error_t;\n");
+ fprintf(file, "\t */\n");
+ fprintf(file, "\n");
+
+
+ /* declarations for local vars: Union of Request and Reply messages,
+ InP, OutP and return value */
+
+ WriteVarDecls(file, rt);
+
+ /* declarations and initializations of the mach_msg_type_descriptor_t variables
+ for each argument that is a Kernel Processed Data */
+
+ WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbRequest | akbSendKPD, "\n", "\n");
+
+ WriteLimitCheck(file, rt);
+ WriteRetCodeArg(file, rt);
+
+ /* fill in the fields that are non related to parameters */
+
+ if (!rt->rtSimpleRequest)
+ fprintf(file, "\tInP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtRequestKPDs);
+
+ /* fill in all the request message types and then arguments */
+
+ WriteRequestArgs(file, rt);
+
+ /* fill in request message head */
+
+ WriteRequestHead(file, rt);
+ fprintf(file, "\n");
+
+ /* give the application a chance to do some stuff. */
+ WriteApplMacro(file, "Send", "Before", rt);
+
+ /* Write the send/receive or rpc call */
+
+ if (UseEventLogger)
+ WriteLogMsg(file, rt, LOG_USER, LOG_REQUEST);
+
+
+ if (rt->rtOneWay) {
+ WriteMsgSend(file, rt);
+ }
+ else {
+ if (UseMsgRPC
+#if USE_IMMEDIATE_SEND_TIMEOUT
+ && (rt->rtWaitTime == argNULL)
+#endif
+ ) {
+ /* overwrite mode meaningful only when UseMsgRPC is enabled */
+ if (rt->rtOverwrite)
+ WriteOverwriteTemplate(file, rt);
+ WriteMsgRPC(file, rt);
+ }
+ else
+ WriteMsgSendReceive(file, rt);
+
+ WriteCheckReplyCall(file, rt);
+ WriteCheckReplyTrailerArgs(file, rt);
+
+ if (UseEventLogger)
+ WriteLogMsg(file, rt, LOG_USER, LOG_REPLY);
+
+ WriteReplyArgs(file, rt);
+ }
+ /* return the return value, if any */
+ if (!rt->rtOneWay) // WriteMsgSend() already wrote the 'return'
+ WriteReturnValue(file, rt);
+ fprintf(file, "}\n");
+}
+
+static void
+WriteRPCClientFunctions(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+ char *fname;
+ char *argfmt = "(mach_port_t, char *, mach_msg_type_number_t)";
+
+ fprintf(file, "#ifdef AUTOTEST\n");
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ fname = stat->stRoutine->rtName;
+ fprintf(file, "extern void client_%s%s;\n", fname, argfmt);
+ }
+ fprintf(file, "function_table_entry %s_client_functions[] =\n", SubsystemName);
+ fprintf(file, "{\n");
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ fname = stat->stRoutine->rtName;
+ fprintf(file, " { \"%s\", client_%s },\n", fname, fname);
+ }
+ fprintf(file, " { (char *) 0, (function_ptr_t) 0 }\n");
+ fprintf(file, "};\n");
+ fprintf(file, "#endif /* AUTOTEST */\n");
+}
+
+/*************************************************************
+ * Writes out the xxxUser.c file. Called by mig.c
+ *************************************************************/
+void
+WriteUser(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ WriteProlog(file, stats);
+ if (TestRPCTrap)
+ WriteRPCClientFunctions(file, stats);
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skRoutine:
+ WriteCheckReply(file, stat->stRoutine);
+ WriteRoutine(file, stat->stRoutine);
+ break;
+
+ case skImport:
+ case skUImport:
+ case skSImport:
+ case skDImport:
+ case skIImport:
+ break;
+
+ default:
+ fatal("WriteUser(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+ WriteEpilog(file);
+}
+
+/*************************************************************
+ * Writes out individual .c user files for each routine. Called by mig.c
+ *************************************************************/
+void
+WriteUserIndividual(statement_t *stats)
+{
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skRoutine: {
+ FILE *file;
+ char *filename;
+
+ filename = strconcat(UserFilePrefix, strconcat(stat->stRoutine->rtName, ".c"));
+ file = fopen(filename, "w");
+ if (file == NULL)
+ fatal("fopen(%s): %s", filename, strerror(errno));
+ WriteProlog(file, stats);
+ WriteRoutine(file, stat->stRoutine);
+ WriteEpilog(file);
+ fclose(file);
+ strfree(filename);
+ }
+ break;
+
+ case skImport:
+ case skUImport:
+ case skSImport:
+ case skDImport:
+ case skIImport:
+ break;
+
+ default:
+ fatal("WriteUserIndividual(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+}
diff --git a/bootstrap_cmds/migcom.tproj/utils.c b/bootstrap_cmds/migcom.tproj/utils.c
new file mode 100644
index 0000000..7a609a4
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/utils.c
@@ -0,0 +1,1043 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <mach/message.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "routine.h"
+#include "write.h"
+#include "global.h"
+#include "utils.h"
+#include "error.h"
+
+extern char *MessFreeRoutine;
+
+void
+WriteIdentificationString(FILE *file)
+{
+ extern char * GenerationDate;
+
+ fprintf(file, "/*\n");
+ fprintf(file, " * IDENTIFICATION:\n");
+ fprintf(file, " * stub generated %s", GenerationDate);
+ fprintf(file, " * with a MiG generated by " MIG_VERSION "\n");
+ fprintf(file, " * OPTIONS: \n");
+ if (IsKernelUser)
+ fprintf(file, " *\tKernelUser\n");
+ if (IsKernelServer)
+ fprintf(file, " *\tKernelServer\n");
+ if (!UseMsgRPC)
+ fprintf(file, " *\t-R (no RPC calls)\n");
+ fprintf(file, " */\n");
+}
+
+void
+WriteMigExternal(FILE *file)
+{
+ fprintf(file, "#ifdef\tmig_external\n");
+ fprintf(file, "mig_external\n");
+ fprintf(file, "#else\n");
+ fprintf(file, "extern\n");
+ fprintf(file, "#endif\t/* mig_external */\n");
+}
+
+void
+WriteMigInternal(FILE *file)
+{
+ fprintf(file, "#ifdef\tmig_internal\n");
+ fprintf(file, "mig_internal\n");
+ fprintf(file, "#else\n");
+ fprintf(file, "static\n");
+ fprintf(file, "#endif\t/* mig_internal */\n");
+}
+
+void
+WriteImport(FILE *file, string_t filename)
+{
+ fprintf(file, "#include %s\n", filename);
+}
+
+void
+WriteImplImports(FILE *file, statement_t *stats, boolean_t isuser)
+{
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skImport:
+ case skIImport:
+ WriteImport(file, stat->stFileName);
+ break;
+
+ case skSImport:
+ if (!isuser)
+ WriteImport(file, stat->stFileName);
+ break;
+
+ case skUImport:
+ if (isuser)
+ WriteImport(file, stat->stFileName);
+ break;
+
+ case skRoutine:
+ case skDImport:
+ break;
+
+ default:
+ fatal("WriteImplImport(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+}
+
+void
+WriteRCSDecl(FILE *file, identifier_t name, string_t rcs)
+{
+ fprintf(file, "#ifndef\tlint\n");
+ fprintf(file, "#if\tUseExternRCSId\n");
+ fprintf(file, "%s char %s_rcsid[] = %s;\n", (BeAnsiC) ? "const" : "", name, rcs);
+ fprintf(file, "#else\t/* UseExternRCSId */\n");
+ fprintf(file, "static %s char rcsid[] = %s;\n", (BeAnsiC) ? "const" : "", rcs);
+ fprintf(file, "#endif\t/* UseExternRCSId */\n");
+ fprintf(file, "#endif\t/* lint */\n");
+ fprintf(file, "\n");
+}
+
+static void
+WriteOneApplDefault(FILE *file, char *word1, char *word2, char *word3)
+{
+ char buf[50];
+
+ sprintf(buf, "__%s%s%s", word1, word2, word3);
+ fprintf(file, "#ifndef\t%s\n", buf);
+ fprintf(file, "#define\t%s(_NUM_, _NAME_)\n", buf);
+ fprintf(file, "#endif\t/* %s */\n", buf);
+ fprintf(file, "\n");
+}
+
+void
+WriteApplDefaults(FILE *file, char *dir)
+{
+ WriteOneApplDefault(file, "Declare", dir, "Rpc");
+ WriteOneApplDefault(file, "Before", dir, "Rpc");
+ WriteOneApplDefault(file, "After", dir, "Rpc");
+ WriteOneApplDefault(file, "Declare", dir, "Simple");
+ WriteOneApplDefault(file, "Before", dir, "Simple");
+ WriteOneApplDefault(file, "After", dir, "Simple");
+}
+
+void
+WriteApplMacro(FILE *file, char *dir, char *when, routine_t *rt)
+{
+ char *what = (rt->rtOneWay) ? "Simple" : "Rpc";
+
+ fprintf(file, "\t__%s%s%s(%d, \"%s\")\n", when, dir, what, SubsystemBase + rt->rtNumber, rt->rtName);
+}
+
+
+void
+WriteBogusDefines(FILE *file)
+{
+ fprintf(file, "#ifndef\tmig_internal\n");
+ fprintf(file, "#define\tmig_internal\tstatic __inline__\n");
+ fprintf(file, "#endif\t/* mig_internal */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#ifndef\tmig_external\n");
+ fprintf(file, "#define mig_external\n");
+ fprintf(file, "#endif\t/* mig_external */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#if\t!defined(__MigTypeCheck) && defined(TypeCheck)\n");
+ fprintf(file, "#define\t__MigTypeCheck\t\tTypeCheck\t/* Legacy setting */\n");
+ fprintf(file, "#endif\t/* !defined(__MigTypeCheck) */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#if\t!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)\n");
+ fprintf(file, "#define\t__MigKernelSpecificCode\t_MIG_KERNEL_SPECIFIC_CODE_\t/* Legacy setting */\n");
+ fprintf(file, "#endif\t/* !defined(__MigKernelSpecificCode) */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#ifndef\tLimitCheck\n");
+ fprintf(file, "#define\tLimitCheck 0\n");
+ fprintf(file, "#endif\t/* LimitCheck */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#ifndef\tmin\n");
+ fprintf(file, "#define\tmin(a,b) ( ((a) < (b))? (a): (b) )\n");
+ fprintf(file, "#endif\t/* min */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#if !defined(_WALIGN_)\n");
+ fprintf(file, "#define _WALIGN_(x) (((x) + %d) & ~%d)\n", (int)(itWordAlign - 1), (int)(itWordAlign - 1));
+ fprintf(file, "#endif /* !defined(_WALIGN_) */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#if !defined(_WALIGNSZ_)\n");
+ fprintf(file, "#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))\n");
+ fprintf(file, "#endif /* !defined(_WALIGNSZ_) */\n");
+ fprintf(file, "\n");
+
+ fprintf(file, "#ifndef\tUseStaticTemplates\n");
+ if (BeAnsiC) {
+ fprintf(file, "#define\tUseStaticTemplates\t0\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "#define\tUseStaticTemplates\t0\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\n");
+
+ WriteBogusServerRoutineAnnotationDefine(file);
+}
+
+void
+WriteList(FILE *file, argument_t *args, void (*func)(FILE *, argument_t *), u_int mask, char *between, char *after)
+{
+ argument_t *arg;
+ boolean_t sawone = FALSE;
+
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, mask)) {
+ if (sawone)
+ fprintf(file, "%s", between);
+ sawone = TRUE;
+
+ (*func)(file, arg);
+ }
+
+ if (sawone)
+ fprintf(file, "%s", after);
+}
+
+
+static boolean_t
+WriteReverseListPrim(FILE *file, argument_t *arg, void (*func)(FILE *, argument_t *), u_int mask, char *between)
+{
+ boolean_t sawone = FALSE;
+
+ if (arg != argNULL) {
+ sawone = WriteReverseListPrim(file, arg->argNext, func, mask, between);
+
+ if (akCheckAll(arg->argKind, mask)) {
+ if (sawone)
+ fprintf(file, "%s", between);
+ sawone = TRUE;
+
+ (*func)(file, arg);
+ }
+ }
+
+ return sawone;
+}
+
+void
+WriteReverseList(FILE *file, argument_t *args, void (*func)(FILE *file, argument_t *args), u_int mask, char *between, char *after)
+{
+ boolean_t sawone;
+
+ sawone = WriteReverseListPrim(file, args, func, mask, between);
+
+ if (sawone)
+ fprintf(file, "%s", after);
+}
+
+void
+WriteNameDecl(FILE *file, argument_t *arg)
+{
+ fprintf(file, "%s", arg->argVarName);
+}
+
+void
+WriteUserVarDecl(FILE *file, argument_t *arg)
+{
+ boolean_t pointer = (arg->argByReferenceUser ||arg->argType->itNativePointer);
+ char *ref = (pointer) ? "*" : "";
+ char *cnst = ((arg->argFlags & flConst) &&
+ (IS_VARIABLE_SIZED_UNTYPED(arg->argType) ||
+ arg->argType->itNoOptArray || arg->argType->itString)) ? "const " : "";
+
+ fprintf(file, "\t%s%s %s%s", cnst, arg->argType->itUserType, ref, arg->argVarName);
+}
+
+void
+WriteServerVarDecl(FILE *file, argument_t *arg)
+{
+ char *ref = (arg->argByReferenceServer ||
+ arg->argType->itNativePointer) ? "*" : "";
+ char *cnst = ((arg->argFlags & flConst) &&
+ (IS_VARIABLE_SIZED_UNTYPED(arg->argType) ||
+ arg->argType->itNoOptArray || arg->argType->itString)) ? "const " : "";
+
+ fprintf(file, "\t%s%s %s%s", cnst, arg->argType->itTransType, ref, arg->argVarName);
+}
+
+char *
+ReturnTypeStr(routine_t *rt)
+{
+ return rt->rtRetCode->argType->itUserType;
+}
+
+char *
+FetchUserType(ipc_type_t *it)
+{
+ return it->itUserType;
+}
+
+char *
+FetchServerType(ipc_type_t *it)
+{
+ return it->itServerType;
+}
+
+char *
+FetchKPDType(ipc_type_t *it)
+{
+ return it->itKPDType;
+}
+
+void
+WriteTrailerDecl(FILE *file, boolean_t trailer)
+{
+ if (trailer)
+ fprintf(file, "\t\tmach_msg_max_trailer_t trailer;\n");
+ else
+ fprintf(file, "\t\tmach_msg_trailer_t trailer;\n");
+}
+
+void
+WriteFieldDeclPrim(FILE *file, argument_t *arg, char *(*tfunc)(ipc_type_t *it))
+{
+ ipc_type_t *it = arg->argType;
+
+ if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) {
+ argument_t *count = arg->argCount;
+ ipc_type_t *btype = it->itElement;
+
+ /*
+ * Build our own declaration for a varying array:
+ * use the element type and maximum size specified.
+ * Note arg->argCount->argMultiplier == btype->itNumber.
+ */
+ /*
+ * NDR encoded VarStrings requires the offset field.
+ * Since it is not used, it wasn't worthwhile to create an extra
+ * parameter
+ */
+ if (it->itString)
+ fprintf(file, "\t\t%s %sOffset; /* MiG doesn't use it */\n", (*tfunc)(count->argType), arg->argName);
+
+ if (!(arg->argFlags & flSameCount) && !it->itNoOptArray)
+ /* in these cases we would have a count, which we don't want */
+ fprintf(file, "\t\t%s %s;\n", (*tfunc)(count->argType), count->argMsgField);
+ fprintf(file, "\t\t%s %s[%d];", (*tfunc)(btype), arg->argMsgField, it->itNumber/btype->itNumber);
+ }
+ else if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t\t%s %s[%d];", (*tfunc)(it), arg->argMsgField, it->itKPD_Number);
+ else if (IS_OPTIONAL_NATIVE(it)) {
+ fprintf(file, "\t\tboolean_t __Present__%s;\n", arg->argMsgField);
+ fprintf(file, "\t\tunion {\n");
+ fprintf(file, "\t\t %s __Real__%s;\n", (*tfunc)(it), arg->argMsgField);
+ fprintf(file, "\t\t char __Phony__%s[_WALIGNSZ_(%s)];\n", arg->argMsgField, (*tfunc)(it));
+ fprintf(file, "\t\t} %s;", arg->argMsgField);
+ }
+ else {
+ /* either simple KPD or simple in-line */
+ fprintf(file, "\t\t%s %s;", (*tfunc)(it), arg->argMsgField);
+ }
+
+ /* Kernel Processed Data has always PadSize = 0 */
+ if (it->itPadSize != 0)
+ fprintf(file, "\n\t\tchar %s[%d];", arg->argPadName, it->itPadSize);
+}
+
+void
+WriteKPDFieldDecl(FILE *file, argument_t *arg)
+{
+ if (akCheck(arg->argKind, akbSendKPD) ||
+ akCheck(arg->argKind, akbReturnKPD))
+ WriteFieldDeclPrim(file, arg, FetchKPDType);
+ else
+ WriteFieldDeclPrim(file, arg, FetchServerType);
+}
+
+void
+WriteStructDecl(
+ FILE *file,
+ argument_t *args,
+ void (*func)(FILE *, argument_t *),
+ u_int mask,
+ char *name,
+ boolean_t simple,
+ boolean_t trailer,
+ boolean_t trailer_t,
+ boolean_t template_only)
+{
+ fprintf(file, "\n#ifdef __MigPackStructs\n#pragma pack(push, %lu)\n#endif\n",sizeof(natural_t));
+ fprintf(file, "\ttypedef struct {\n");
+ fprintf(file, "\t\tmach_msg_header_t Head;\n");
+ if (simple == FALSE) {
+ fprintf(file, "\t\t/* start of the kernel processed data */\n");
+ fprintf(file, "\t\tmach_msg_body_t msgh_body;\n");
+ if (mask == akbRequest)
+ WriteList(file, args, func, mask | akbSendKPD, "\n", "\n");
+ else
+ WriteList(file, args, func, mask | akbReturnKPD, "\n", "\n");
+ fprintf(file, "\t\t/* end of the kernel processed data */\n");
+ }
+ if (!template_only) {
+ if (mask == akbRequest)
+ WriteList(file, args, func, mask | akbSendBody, "\n", "\n");
+
+ else
+ WriteList(file, args, func, mask | akbReturnBody, "\n", "\n");
+ if (trailer)
+ WriteTrailerDecl(file, trailer_t);
+ }
+ fprintf(file, "\t} %s __attribute__((unused));\n", name);
+ fprintf(file, "#ifdef __MigPackStructs\n#pragma pack(pop)\n#endif\n");
+}
+
+void
+WriteTemplateDeclIn(FILE *file, argument_t *arg)
+{
+ (*arg->argKPD_Template)(file, arg, TRUE);
+}
+
+void
+WriteTemplateDeclOut(FILE *file, argument_t *arg)
+{
+ (*arg->argKPD_Template)(file, arg, FALSE);
+}
+
+void
+WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in)
+{
+ ipc_type_t *it = arg->argType;
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName);
+
+ fprintf(file, "\t\t/* name = */\t\tMACH_PORT_NULL,\n");
+ fprintf(file, "\t\t/* pad1 = */\t\t0,\n");
+ fprintf(file, "\t\t/* pad2 = */\t\t0,\n");
+ fprintf(file, "\t\t/* disp = */\t\t%s,\n", in ? it->itInNameStr: it->itOutNameStr);
+ fprintf(file, "\t\t/* type = */\t\tMACH_MSG_PORT_DESCRIPTOR,\n");
+
+ fprintf(file, "\t};\n");
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+}
+
+void
+WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in)
+{
+ ipc_type_t *it = arg->argType;
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName);
+
+ if (IS_MULTIPLE_KPD(it))
+ it = it->itElement;
+
+ fprintf(file, "\t\t/* addr = */\t\t(void *)0,\n");
+ if (it->itVarArray)
+ fprintf(file, "\t\t/* size = */\t\t0,\n");
+ else
+ fprintf(file, "\t\t/* size = */\t\t%d,\n", (it->itNumber * it->itSize + 7)/8);
+ fprintf(file, "\t\t/* deal = */\t\t%s,\n", (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
+ /* the d_MAYBE case will be fixed runtime */
+ fprintf(file, "\t\t/* copy = */\t\t%s,\n", (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY");
+ /* the PHYSICAL COPY flag has not been established yet */
+ fprintf(file, "\t\t/* pad2 = */\t\t0,\n");
+ fprintf(file, "\t\t/* type = */\t\tMACH_MSG_OOL_DESCRIPTOR,\n");
+
+ fprintf(file, "\t};\n");
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+}
+
+void
+WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in)
+{
+ ipc_type_t *it = arg->argType;
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName);
+
+ if (IS_MULTIPLE_KPD(it))
+ it = it->itElement;
+
+ fprintf(file, "\t\t/* addr = */\t\t(void *)0,\n");
+ if (!it->itVarArray)
+ fprintf(file, "\t\t/* coun = */\t\t%d,\n", it->itNumber);
+ else
+ fprintf(file, "\t\t/* coun = */\t\t0,\n");
+ fprintf(file, "\t\t/* deal = */\t\t%s,\n", (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
+ fprintf(file, "\t\t/* copy is meaningful only in overwrite mode */\n");
+ fprintf(file, "\t\t/* copy = */\t\tMACH_MSG_PHYSICAL_COPY,\n");
+ fprintf(file, "\t\t/* disp = */\t\t%s,\n", in ? it->itInNameStr: it->itOutNameStr);
+ fprintf(file, "\t\t/* type = */\t\tMACH_MSG_OOL_PORTS_DESCRIPTOR,\n");
+
+ fprintf(file, "\t};\n");
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+}
+
+void
+WriteReplyTypes(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ fprintf(file, "/* typedefs for all replies */\n\n");
+ fprintf(file, "#ifndef __Reply__%s_subsystem__defined\n", SubsystemName);
+ fprintf(file, "#define __Reply__%s_subsystem__defined\n", SubsystemName);
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind == skRoutine) {
+ routine_t *rt;
+ char str[MAX_STR_LEN];
+
+ rt = stat->stRoutine;
+ sprintf(str, "__Reply__%s_t", rt->rtName);
+ WriteStructDecl(file, rt->rtArgs, WriteKPDFieldDecl, akbReply, str, rt->rtSimpleReply, FALSE, FALSE, FALSE);
+ }
+ }
+ fprintf(file, "#endif /* !__Reply__%s_subsystem__defined */\n", SubsystemName);
+ fprintf(file, "\n");
+}
+
+void
+WriteRequestTypes(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ fprintf(file, "/* typedefs for all requests */\n\n");
+ fprintf(file, "#ifndef __Request__%s_subsystem__defined\n", SubsystemName);
+ fprintf(file, "#define __Request__%s_subsystem__defined\n", SubsystemName);
+ for (stat = stats; stat != stNULL; stat = stat->stNext) {
+ if (stat->stKind == skRoutine) {
+ routine_t *rt;
+ char str[MAX_STR_LEN];
+
+ rt = stat->stRoutine;
+ sprintf(str, "__Request__%s_t", rt->rtName);
+ WriteStructDecl(file, rt->rtArgs, WriteKPDFieldDecl, akbRequest, str, rt->rtSimpleRequest, FALSE, FALSE, FALSE);
+ }
+ }
+ fprintf(file, "#endif /* !__Request__%s_subsystem__defined */\n", SubsystemName);
+ fprintf(file, "\n");
+}
+
+void
+WriteNDRConvertArgDecl(FILE *file, argument_t *arg, char *convert, char *dir)
+{
+ argument_t *count = arg->argCount;
+ argument_t *parent = arg->argParent;
+ char *carg = (count) ? ", c" : "";
+ routine_t *rt = arg->argRoutine;
+ ipc_type_t *ptype = arg->argType;
+ ipc_type_t *btype;
+ int multi, array;
+ char domain[MAX_STR_LEN];
+
+ fprintf(file, "#ifndef __NDR_convert__%s__%s__%s_t__%s__defined\n#", convert, dir, rt->rtName, arg->argMsgField);
+
+ for (btype = ptype, multi = (!parent) ? arg->argMultiplier : 1, array = 0;
+ btype;
+ ptype = btype, array += ptype->itVarArray, btype = btype->itElement) {
+ char *bttype;
+
+ if (btype->itNumber < ptype->itNumber && !ptype->itVarArray && !parent) {
+ multi *= ptype->itNumber / btype->itNumber;
+ if (!btype->itString)
+ continue;
+ }
+ else if (array && ptype->itVarArray)
+ continue;
+ if (btype != ptype)
+ fprintf(file, "#el");
+
+ bttype = (multi > 1 && btype->itString) ? "string" : FetchServerType(btype);
+ sprintf(domain, "__%s", SubsystemName);
+ do {
+ fprintf(file, "if\tdefined(__NDR_convert__%s%s__%s__defined)\n", convert, domain, bttype);
+ fprintf(file, "#define\t__NDR_convert__%s__%s__%s_t__%s__defined\n", convert, dir, rt->rtName, arg->argMsgField);
+ fprintf(file, "#define\t__NDR_convert__%s__%s__%s_t__%s(a, f%s) \\\n\t", convert, dir, rt->rtName, arg->argMsgField, carg);
+ if (multi > 1) {
+ if (array) {
+ if (btype->itString)
+ fprintf(file, "__NDR_convert__2DARRAY((%s *)(a), f, %d, c, ", bttype, multi);
+ else
+ fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, %d * (c), ", bttype, multi);
+ }
+ else if (!btype->itString)
+ fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, %d, ", bttype, multi);
+ }
+ else if (array)
+ fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, c, ", bttype);
+ fprintf(file, "__NDR_convert__%s%s__%s", convert, domain, bttype);
+ if (multi > 1) {
+ if (!array && btype->itString)
+ fprintf(file, "(a, f, %d", multi);
+ }
+ else if (!array)
+ fprintf(file, "((%s *)(a), f%s", bttype, carg);
+ fprintf(file, ")\n");
+ } while (strcmp(domain, "") && ((void)(domain[0] = '\0'), fprintf(file, "#el")));
+ }
+ fprintf(file, "#endif /* defined(__NDR_convert__*__defined) */\n");
+ fprintf(file, "#endif /* __NDR_convert__%s__%s__%s_t__%s__defined */\n\n", convert, dir, rt->rtName, arg->argMsgField);
+}
+
+/*
+ * Like vfprintf, but omits a leading comment in the format string
+ * and skips the items that would be printed by it. Only %s, %d,
+ * and %f are recognized.
+ */
+void
+SkipVFPrintf(FILE *file, char *fmt, va_list pvar)
+{
+ if (*fmt == 0)
+ return; /* degenerate case */
+
+ if (fmt[0] == '/' && fmt[1] == '*') {
+ /* Format string begins with C comment. Scan format
+ string until end-comment delimiter, skipping the
+ items in pvar that the enclosed format items would
+ print. */
+
+ int c;
+
+ fmt += 2;
+ for (;;) {
+ c = *fmt++;
+ if (c == 0)
+ return; /* nothing to format */
+ if (c == '*') {
+ if (*fmt == '/') {
+ break;
+ }
+ }
+ else if (c == '%') {
+ /* Field to skip */
+ c = *fmt++;
+ switch (c) {
+
+ case 's':
+ (void) va_arg(pvar, char *);
+ break;
+
+ case 'd':
+ (void) va_arg(pvar, int);
+ break;
+
+ case 'f':
+ (void) va_arg(pvar, double);
+ break;
+
+ case '\0':
+ return; /* error - fmt ends with '%' */
+
+ default:
+ break;
+ }
+ }
+ }
+ /* End of comment. To be pretty, skip
+ the space that follows. */
+ fmt++;
+ if (*fmt == ' ')
+ fmt++;
+ }
+
+ /* Now format the string. */
+ (void) vfprintf(file, fmt, pvar);
+}
+
+static void
+vWriteCopyType(FILE *file, ipc_type_t *it, boolean_t mig_allocated_buf, char *left, char *right, va_list pvar)
+{
+ va_list pvar2;
+ va_copy(pvar2, pvar);
+
+ if (it->itStruct) {
+
+ fprintf(file, "\t");
+ (void) SkipVFPrintf(file, left, pvar);
+ fprintf(file, " = ");
+ (void) SkipVFPrintf(file, right, pvar2);
+ fprintf(file, ";\n");
+ }
+ else if (it->itString) {
+ va_list pvar3, pvar4;
+ va_copy(pvar3, pvar);
+ va_copy(pvar4, pvar);
+
+ if (mig_allocated_buf) {
+ /*
+ * zero-fill MIG allocated buffers: we control the size so there's
+ * no risk of buffer overrun, and we avoid leaking process/kernel
+ * memory on the copy-out
+ */
+ fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n");
+ fprintf(file, "\t\t(void) mig_strncpy_zerofill(");
+ (void) SkipVFPrintf(file, left, pvar);
+ fprintf(file, ", ");
+ (void) SkipVFPrintf(file, right, pvar2);
+ fprintf(file, ", %d);\n", it->itTypeSize);
+ fprintf(file, "\t} else {\n");
+ fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n\t");
+ }
+ fprintf(file, "\t(void) mig_strncpy(");
+
+ (void) SkipVFPrintf(file, left, pvar3);
+ fprintf(file, ", ");
+ (void) SkipVFPrintf(file, right, pvar4);
+ fprintf(file, ", %d);\n", it->itTypeSize);
+
+ if (mig_allocated_buf) {
+ fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
+ }
+
+ va_end(pvar3);
+ va_end(pvar4);
+ }
+ else {
+ fprintf(file, "\t{ typedef struct { char data[%d]; } *sp;\n", it->itTypeSize);
+ fprintf(file, "\t * (sp) ");
+ (void) SkipVFPrintf(file, left, pvar);
+ fprintf(file, " = * (sp) ");
+ (void) SkipVFPrintf(file, right, pvar2);
+ fprintf(file, ";\n\t}\n");
+ }
+
+ va_end(pvar2);
+}
+
+
+/*ARGSUSED*/
+/*VARARGS4*/
+void
+WriteCopyType(FILE *file, ipc_type_t *it, boolean_t mig_allocated_buf, char *left, char *right, ...)
+{
+ va_list pvar;
+ va_start(pvar, right);
+
+ vWriteCopyType(file, it, mig_allocated_buf, left, right, pvar);
+
+ va_end(pvar);
+}
+
+
+/*ARGSUSED*/
+/*VARARGS4*/
+void
+WriteCopyArg(FILE *file, argument_t *arg, boolean_t mig_allocated_buf, char *left, char *right, ...)
+{
+ va_list pvar;
+ va_start(pvar, right);
+
+ {
+ ipc_type_t *it = arg->argType;
+ if (it->itVarArray && !it->itString) {
+ fprintf(file, "\t (void)memcpy(");
+ (void) SkipVFPrintf(file, left, pvar);
+ va_end(pvar);
+ fprintf(file, ", ");
+ va_start(pvar, right);
+ (void) SkipVFPrintf(file, right, pvar);
+ fprintf(file, ", %s);\n", arg->argCount->argVarName);
+ }
+ else
+ vWriteCopyType(file, it, mig_allocated_buf, left, right, pvar);
+ }
+
+ va_end(pvar);
+}
+
+
+/*
+ * Global KPD disciplines
+ */
+void
+KPD_error(FILE *file, argument_t *arg)
+{
+ printf("MiG internal error: argument is %s\n", arg->argVarName);
+ exit(1);
+}
+
+void
+KPD_noop(FILE *file, argument_t *arg)
+{
+ /* Nothing to see here, people. Move it along... */
+}
+
+static void
+WriteStringDynArgs(argument_t *args, u_int mask, string_t InPOutP, string_t *str_oolports, string_t *str_ool)
+{
+ argument_t *arg;
+ char loc[100], sub[20];
+ string_t tmp_str1 = "";
+ string_t tmp_str2 = "";
+ int cnt, multiplier = 1;
+ boolean_t test, complex = FALSE;
+
+ for (arg = args; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ test = it->itVarArray || it->itElement->itVarArray;
+ if (test) {
+ multiplier = it->itKPD_Number;
+ it = it->itElement;
+ complex = TRUE;
+ }
+ }
+ else
+ test = it->itVarArray;
+
+ cnt = multiplier;
+ while (cnt) {
+ if (complex)
+ sprintf(sub, "[%d]", multiplier - cnt);
+ if (akCheck(arg->argKind, mask) &&
+ it->itPortType && !it->itInLine && test) {
+ sprintf(loc, " + %s->%s%s.count", InPOutP, arg->argMsgField, complex ? sub : "");
+ tmp_str1 = strconcat(tmp_str1, loc);
+ }
+ if (akCheck(arg->argKind, mask) &&
+ !it->itInLine && !it->itPortType && test) {
+ sprintf(loc, " + %s->%s%s.size", InPOutP, arg->argMsgField, complex ? sub : "");
+ tmp_str2 = strconcat(tmp_str2, loc);
+ }
+ cnt--;
+ }
+ }
+ *str_oolports = tmp_str1;
+ *str_ool = tmp_str2;
+}
+
+/*
+ * Utilities for Logging Events that happen at the stub level
+ */
+void
+WriteLogMsg(FILE *file, routine_t *rt, int where, int what)
+{
+ string_t ptr_str;
+ string_t StringOolPorts = strNULL;
+ string_t StringOOL = strNULL;
+ u_int ports, oolports, ool;
+ string_t event;
+
+ fprintf(file, "\n#if MIG_DEBUG\n");
+ if (where == LOG_USER)
+ fprintf(file, "\tLOG_TRACE(MACH_MSG_LOG_USER,\n");
+ else
+ fprintf(file, "\tLOG_TRACE(MACH_MSG_LOG_SERVER,\n");
+ if (where == LOG_USER && what == LOG_REQUEST) {
+ ptr_str = "InP";
+ event = "MACH_MSG_REQUEST_BEING_SENT";
+ }
+ else if (where == LOG_USER && what == LOG_REPLY) {
+ ptr_str = "Out0P";
+ event = "MACH_MSG_REPLY_BEING_RCVD";
+ }
+ else if (where == LOG_SERVER && what == LOG_REQUEST) {
+ ptr_str = "In0P";
+ event = "MACH_MSG_REQUEST_BEING_RCVD";
+ }
+ else {
+ ptr_str = "OutP";
+ event = "MACH_MSG_REPLY_BEING_SENT";
+ }
+ WriteStringDynArgs(rt->rtArgs, (what == LOG_REQUEST) ? akbSendKPD : akbReturnKPD, ptr_str, &StringOolPorts, &StringOOL);
+ fprintf(file, "\t\t%s,\n", event);
+ fprintf(file, "\t\t%s->Head.msgh_id,\n", ptr_str);
+ if (where == LOG_USER && what == LOG_REQUEST) {
+ if (rt->rtNumRequestVar)
+ fprintf(file, "\t\tmsgh_size,\n");
+ else
+ fprintf(file, "\t\t(mach_msg_size_t)sizeof(Request),\n");
+ }
+ else
+ fprintf(file, "\t\t%s->Head.msgh_size,\n", ptr_str);
+ if ((what == LOG_REQUEST && rt->rtSimpleRequest == FALSE) ||
+ (what == LOG_REPLY && rt->rtSimpleReply == FALSE))
+ fprintf(file, "\t\t%s->msgh_body.msgh_descriptor_count,\n", ptr_str);
+ else
+ fprintf(file, "\t\t0, /* Kernel Proc. Data entries */\n");
+ if (what == LOG_REQUEST) {
+ fprintf(file, "\t\t0, /* RetCode */\n");
+ ports = rt->rtCountPortsIn;
+ oolports = rt->rtCountOolPortsIn;
+ ool = rt->rtCountOolIn;
+ }
+ else {
+ if (akCheck(rt->rtRetCode->argKind, akbReply))
+ fprintf(file, "\t\t%s->RetCode,\n", ptr_str);
+ else
+ fprintf(file, "\t\t0, /* RetCode */\n");
+ ports = rt->rtCountPortsOut;
+ oolports = rt->rtCountOolPortsOut;
+ ool = rt->rtCountOolOut;
+ }
+ fprintf(file, "\t\t/* Ports */\n");
+ fprintf(file, "\t\t%d,\n", ports);
+ fprintf(file, "\t\t/* Out-of-Line Ports */\n");
+ fprintf(file, "\t\t%d", oolports);
+ if (StringOolPorts != strNULL)
+ fprintf(file, "%s,\n", StringOolPorts);
+ else
+ fprintf(file, ",\n");
+ fprintf(file, "\t\t/* Out-of-Line Bytes */\n");
+ fprintf(file, "\t\t%d", ool);
+ if (StringOOL != strNULL)
+ fprintf(file, "%s,\n", StringOOL);
+ else
+ fprintf(file, ",\n");
+ fprintf(file, "\t\t__FILE__, __LINE__);\n");
+ fprintf(file, "#endif /* MIG_DEBUG */\n\n");
+}
+
+void
+WriteLogDefines(FILE *file, string_t who)
+{
+ fprintf(file, "#if MIG_DEBUG\n");
+ fprintf(file, "#define LOG_W_E(X)\tLOG_ERRORS(%s, \\\n", who);
+ fprintf(file, "\t\t\tMACH_MSG_ERROR_WHILE_PARSING, (void *)(X), __FILE__, __LINE__)\n");
+ fprintf(file, "#else /* MIG_DEBUG */\n");
+ fprintf(file, "#define LOG_W_E(X)\n");
+ fprintf(file, "#endif /* MIG_DEBUG */\n");
+ fprintf(file, "\n");
+}
+
+/* common utility to report errors */
+void
+WriteReturnMsgError(FILE *file, routine_t *rt, boolean_t isuser, argument_t *arg, string_t error)
+{
+ char space[MAX_STR_LEN];
+ string_t string = &space[0];
+
+ if (UseEventLogger && arg != argNULL)
+ sprintf(string, "LOG_W_E(\"%s\"); ", arg->argVarName);
+ else
+ string = "";
+
+ fprintf(file, "\t\t{ ");
+
+ if (isuser) {
+ if (! rtMessOnStack(rt))
+ fprintf(file, "%s((char *) Mess, (mach_msg_size_t)sizeof(*Mess)); ", MessFreeRoutine);
+
+ fprintf(file, "%sreturn %s; }\n", string, error);
+ }
+ else
+ fprintf(file, "%sMIG_RETURN_ERROR(OutP, %s); }\n", string, error);
+}
+
+/* executed iff elements are defined */
+void
+WriteCheckTrailerHead(FILE *file, routine_t *rt, boolean_t isuser)
+{
+ string_t who = (isuser) ? "Out0P" : "In0P";
+
+ fprintf(file, "\tTrailerP = (mach_msg_max_trailer_t *)((vm_offset_t)%s +\n", who);
+ fprintf(file, "\t\tround_msg(%s->Head.msgh_size));\n", who);
+ fprintf(file, "\tif (TrailerP->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0)\n");
+ if (isuser)
+ fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
+ else
+ fprintf(file, "\t\t{ MIG_RETURN_ERROR(%s, MIG_TRAILER_ERROR); }\n", who);
+
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\ttrailer_size = TrailerP->msgh_trailer_size -\n");
+ fprintf(file, "\t\t(mach_msg_size_t)(sizeof(mach_msg_trailer_type_t) - sizeof(mach_msg_trailer_size_t));\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+}
+
+/* executed iff elements are defined */
+void
+WriteCheckTrailerSize(FILE *file, boolean_t isuser, argument_t *arg)
+{
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ if (akIdent(arg->argKind) == akeMsgSeqno) {
+ fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(mach_port_seqno_t))\n");
+ if (isuser)
+ fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
+ else
+ fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n");
+ fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(mach_port_seqno_t);\n");
+ }
+ else if (akIdent(arg->argKind) == akeSecToken) {
+ fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(security_token_t))\n");
+ if (isuser)
+ fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
+ else
+ fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n");
+ fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(security_token_t);\n");
+ }
+ else if (akIdent(arg->argKind) == akeAuditToken) {
+ fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(audit_token_t))\n");
+ if (isuser)
+ fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
+ else
+ fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n");
+ fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(audit_token_t);\n");
+ }
+ else if (akIdent(arg->argKind) == akeContextToken) {
+ fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(mach_vm_address_t))\n");
+ if (isuser)
+ fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n");
+ else
+ fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n");
+ fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(mach_vm_address_t);\n");
+ }
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+}
+
diff --git a/bootstrap_cmds/migcom.tproj/utils.h b/bootstrap_cmds/migcom.tproj/utils.h
new file mode 100644
index 0000000..a804920
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/utils.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 1999-2002, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University
+ * Extensive revamping. Added polymorphic arguments.
+ * Allow multiple variable-sized inline arguments in messages.
+ *
+ * 28-May-87 Richard Draves (rpd) at Carnegie-Mellon University
+ * Created.
+ */
+
+#ifndef _UTILS_H
+#define _UTILS_H
+
+/* definitions used by the Event Logger */
+
+#define LOG_USER 0
+#define LOG_SERVER 1
+
+#define LOG_REQUEST 0
+#define LOG_REPLY 1
+
+/* stuff used by more than one of header.c, user.c, server.c */
+
+extern void WriteMigExternal(FILE *file);
+extern void WriteMigInternal(FILE *file);
+
+extern void WriteImport(FILE *file, string_t filename);
+extern void WriteRCSDecl( FILE *file, identifier_t name, string_t rcs );
+extern void WriteBogusDefines( FILE *file );
+
+extern void WriteList( FILE *file, argument_t *args,
+ void (*func)(FILE *file, argument_t *arg),
+ u_int mask, char *between, char *after );
+
+extern void WriteReverseList( FILE *file, argument_t *args,
+ void (*func)(FILE *file, argument_t *arg),
+ u_int mask, char *between, char *after );
+
+/* good as arguments to WriteList */
+extern void WriteNameDecl( FILE *file, argument_t *arg );
+extern void WriteUserVarDecl( FILE *file, argument_t *arg );
+extern void WriteServerVarDecl( FILE *file, argument_t *arg );
+extern void WriteTemplateDeclIn( FILE *file, argument_t *arg );
+extern void WriteTemplateDeclOut( FILE *file, argument_t *arg );
+extern void WriteCheckDecl( FILE *file, argument_t *arg );
+
+extern char *ReturnTypeStr( routine_t *rt );
+
+extern char *FetchUserType( ipc_type_t *it );
+extern char *FetchServerType( ipc_type_t *it );
+extern char *FetchKPDType( ipc_type_t *it );
+extern void WriteKPDFieldDecl(FILE *file, argument_t *arg);
+
+extern void WriteFieldDeclPrim( FILE *file, argument_t *arg, char *(*tfunc)(ipc_type_t *it) );
+
+extern void WriteStructDecl( FILE *file, argument_t *args,
+ void (*func)(FILE *file, argument_t *arg),
+ u_int mask, char *name,
+ boolean_t simple, boolean_t trailer,
+ boolean_t isuser,
+ boolean_t template_only );
+
+extern void WriteStaticDecl( FILE *file, argument_t *arg );
+
+extern void WriteCopyType(FILE *file, ipc_type_t *it, boolean_t mig_allocated_buf, char *left, char *right, ...);
+
+extern void WriteCopyArg(FILE *file, argument_t *arg, boolean_t mig_allocated_buf, char *left, char *right, ...);
+
+extern void WriteLogMsg( FILE *file, routine_t *rt, int where, int what );
+
+extern void WriteCheckTrailerHead( FILE *file, routine_t *rt, boolean_t isuser );
+
+extern void WriteCheckTrailerSize( FILE *file, boolean_t isuser, argument_t *arg );
+
+extern void WriteReturnMsgError( FILE *file, routine_t *rt, boolean_t isuser, argument_t *arg, string_t error );
+
+extern void WriteRPCRoutineDescriptor( FILE *file, routine_t *rt, int arg_count, int descr_count, string_t stub_routine, string_t sig_array );
+
+extern void WriteRPCRoutineArgDescriptor( FILE *file, routine_t *rt );
+
+extern void WriteRequestTypes( FILE *file, statement_t *stats);
+extern void WriteCheckRequests( FILE *file, statement_t *stats);
+extern void WriteUserRequestUnion( FILE *file, statement_t *stats );
+extern void WriteServerRequestUnion( FILE *file, statement_t *stats );
+
+extern void WriteReplyTypes( FILE *file, statement_t *stats);
+extern void WriteCheckReplies( FILE *file, statement_t *stats);
+extern void WriteUserReplyUnion( FILE *file, statement_t *stats );
+extern void WriteServerReplyUnion( FILE *file, statement_t *stats );
+
+extern void WriteNDRConvertArgDecl( FILE *file, argument_t *arg, char *convert, char *dir);
+
+#endif /* _UTILS_H */
diff --git a/bootstrap_cmds/migcom.tproj/write.h b/bootstrap_cmds/migcom.tproj/write.h
new file mode 100644
index 0000000..0e935aa
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/write.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1999, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University
+ * Extensive revamping. Added polymorphic arguments.
+ * Allow multiple variable-sized inline arguments in messages.
+ *
+ * 27-May-87 Richard Draves (rpd) at Carnegie-Mellon University
+ * Created.
+ */
+
+#ifndef _WRITE_H
+#define _WRITE_H
+
+#include <stdio.h>
+#include "statement.h"
+
+extern void WriteUserHeader( FILE *file, statement_t *stats );
+extern void WriteServerHeader( FILE *file, statement_t *stats );
+extern void WriteServerRoutine( FILE *file, routine_t *rt );
+extern void WriteInternalHeader( FILE *file, statement_t *stats );
+extern void WriteDefinesHeader( FILE *file, statement_t *stats );
+extern void WriteUser( FILE *file, statement_t *stats );
+extern void WriteUserIndividual( statement_t *stats );
+extern void WriteServer( FILE *file, statement_t *stats );
+extern void WriteIncludes( FILE *file, boolean_t isuser, boolean_t is_def );
+extern void WriteImplImports( FILE *file, statement_t *stats, boolean_t isuser );
+extern void WriteApplDefaults( FILE *file, char *dir );
+extern void WriteApplMacro( FILE *file, char *dir, char *when, routine_t *rt );
+extern void WriteBogusServerRoutineAnnotationDefine( FILE *file );
+
+#endif /* _WRITE_H */
diff --git a/bootstrap_cmds/xcodescripts/install-mig.sh b/bootstrap_cmds/xcodescripts/install-mig.sh
new file mode 100644
index 0000000..f0f742e
--- /dev/null
+++ b/bootstrap_cmds/xcodescripts/install-mig.sh
@@ -0,0 +1,8 @@
+set -e -x
+
+BINDIR="$DSTROOT/$DT_TOOLCHAIN_DIR/usr/bin"
+
+install -d -o root -g wheel -m 0755 "$BINDIR"
+install -c -o root -g wheel -m 0755 \
+ "$PROJECT_DIR/migcom.tproj/mig.sh" \
+ "$BINDIR"/mig
diff --git a/developer_cmds/asa/asa.1 b/developer_cmds/asa/asa.1
new file mode 100644
index 0000000..4c388a0
--- /dev/null
+++ b/developer_cmds/asa/asa.1
@@ -0,0 +1,85 @@
+.\" $NetBSD: asa.1,v 1.5 1997/09/20 14:55:00 lukem Exp $
+.\"
+.\" Copyright (c) 1993 Winning Strategies, 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" 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.
+.\"
+.Dd September 23, 1993
+.Dt ASA 1
+.Os
+.Sh NAME
+.Nm asa
+.Nd interpret carriage-control characters.
+.Sh SYNOPSIS
+.Nm
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility reads files sequentially, mapping
+.Tn FORTRAN
+carriage-control characters to line-printer control sequences,
+and writes them to the standard output.
+.Pp
+The first character of each line is interpreted as a carriage-control
+character. The following characters are interpreted as follows:
+.Bl -tag -width "<space>"
+.It <space>
+Output the rest of the line without change.
+.It 0
+Output a <newline> character before printing the rest of the line.
+.It 1
+Output a <formfeed> character before printing the rest of the line.
+.It +
+The trailing <newline> of the previous line is replaced by a <carriage-return>
+before printing the rest of the line.
+.El
+.Pp
+Lines beginning with characters other than the above are treated as if they
+begin with <space>.
+.Sh EXAMPLES
+To view a file containing the output of a
+.Tn FORTRAN program:
+.Dl asa file
+.Pp
+To format the output of a
+.Tn FORTRAN
+program and redirect it to a line-printer.
+.Dl a.out | asa | lpr
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exit 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr f77 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+.Sh AUTHORS
+J.T. Conklin, Winning Strategies, Inc.
diff --git a/developer_cmds/asa/asa.c b/developer_cmds/asa/asa.c
new file mode 100644
index 0000000..9516a45
--- /dev/null
+++ b/developer_cmds/asa/asa.c
@@ -0,0 +1,131 @@
+/* $NetBSD: asa.c,v 1.11 1997/09/20 14:55:00 lukem Exp $ */
+
+/*
+ * Copyright (c) 1993,94 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: asa.c,v 1.11 1997/09/20 14:55:00 lukem Exp $");
+#endif
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void asa __P((FILE *));
+int main __P((int, char *[]));
+
+int main(int argc, char **argv)
+{
+ FILE *fp;
+ int exit_val = 0;
+ /* skip progname */
+ argv++;
+
+ if (*argv && !strcmp(*argv, "--")) {
+ argv++;
+ argc--;
+ }
+
+ if (argc == 1) {
+ asa(stdin);
+ exit(exit_val);
+ }
+
+ do {
+ if (*argv) {
+ if (!(fp = fopen(*argv, "r"))) {
+ warn ("%s", *argv);
+ exit_val = 1;
+ continue;
+ } else {
+ asa(fp);
+ (void)fclose(fp);
+ }
+ }
+ } while (*argv++);
+
+ exit (exit_val);
+}
+
+static void
+asa(f)
+ FILE *f;
+{
+ char *buf;
+ size_t len;
+
+ if ((buf = fgetln (f, &len)) != NULL) {
+ if (buf[len - 1] == '\n')
+ buf[--len] = '\0';
+ /* special case the first line */
+ switch (buf[0]) {
+ case '0':
+ putchar ('\n');
+ break;
+ case '1':
+ putchar ('\f');
+ break;
+ }
+
+ if (len > 1 && buf[0] && buf[1]) {
+ printf("%.*s", (int)(len - 1), buf + 1);
+ }
+
+ while ((buf = fgetln(f, &len)) != NULL) {
+ if (buf[len - 1] == '\n')
+ buf[--len] = '\0';
+ switch (buf[0]) {
+ default:
+ case ' ':
+ putchar ('\n');
+ break;
+ case '0':
+ putchar ('\n');
+ putchar ('\n');
+ break;
+ case '1':
+ putchar ('\n');
+ putchar ('\f');
+ break;
+ case '+':
+ putchar ('\r');
+ break;
+ }
+
+ if (len > 1 && buf[0] && buf[1]) {
+ printf("%.*s", (int)(len - 1), buf + 1);
+ }
+ }
+
+ putchar ('\n');
+ }
+}
diff --git a/developer_cmds/ctags/C.c b/developer_cmds/ctags/C.c
new file mode 100644
index 0000000..c99d617
--- /dev/null
+++ b/developer_cmds/ctags/C.c
@@ -0,0 +1,555 @@
+/* $NetBSD: C.c,v 1.5 1998/07/24 07:30:08 ross Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)C.c 8.4 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: C.c,v 1.5 1998/07/24 07:30:08 ross Exp $");
+#endif
+#endif /* not lint */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ctags.h"
+
+static int func_entry __P((void));
+static void hash_entry __P((void));
+static void skip_string __P((int));
+static int str_entry __P((int));
+
+/*
+ * c_entries --
+ * read .c and .h files and call appropriate routines
+ */
+void
+c_entries()
+{
+ int c; /* current character */
+ int level; /* brace level */
+ int token; /* if reading a token */
+ int t_def; /* if reading a typedef */
+ int t_level; /* typedef's brace level */
+ char *sp; /* buffer pointer */
+ char tok[MAXTOKEN]; /* token buffer */
+
+ lineftell = ftell(inf);
+ sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1;
+ while (GETC(!=, EOF)) {
+ switch (c) {
+ /*
+ * Here's where it DOESN'T handle: {
+ * foo(a)
+ * {
+ * #ifdef notdef
+ * }
+ * #endif
+ * if (a)
+ * puts("hello, world");
+ * }
+ */
+ case '{':
+ ++level;
+ goto endtok;
+ case '}':
+ /*
+ * if level goes below zero, try and fix
+ * it, even though we've already messed up
+ */
+ if (--level < 0)
+ level = 0;
+ goto endtok;
+
+ case '\n':
+ SETLINE;
+ /*
+ * the above 3 cases are similar in that they
+ * are special characters that also end tokens.
+ */
+ endtok: if (sp > tok) {
+ *sp = EOS;
+ token = YES;
+ sp = tok;
+ }
+ else
+ token = NO;
+ continue;
+
+ /*
+ * We ignore quoted strings and character constants
+ * completely.
+ */
+ case '"':
+ case '\'':
+ (void)skip_string(c);
+ break;
+
+ /*
+ * comments can be fun; note the state is unchanged after
+ * return, in case we found:
+ * "foo() XX comment XX { int bar; }"
+ */
+ case '/':
+ if (GETC(==, '*')) {
+ skip_comment();
+ continue;
+ }
+ (void)ungetc(c, inf);
+ c = '/';
+ goto storec;
+
+ /* hash marks flag #define's. */
+ case '#':
+ if (sp == tok) {
+ hash_entry();
+ break;
+ }
+ goto storec;
+
+ /*
+ * if we have a current token, parenthesis on
+ * level zero indicates a function.
+ */
+ case '(':
+ if (!level && token) {
+ int curline;
+
+ if (sp != tok)
+ *sp = EOS;
+ /*
+ * grab the line immediately, we may
+ * already be wrong, for example,
+ * foo\n
+ * (arg1,
+ */
+ ct_getline();
+ curline = lineno;
+ if (func_entry()) {
+ ++level;
+ pfnote(tok, curline);
+ }
+ break;
+ }
+ goto storec;
+
+ /*
+ * semi-colons indicate the end of a typedef; if we find a
+ * typedef we search for the next semi-colon of the same
+ * level as the typedef. Ignoring "structs", they are
+ * tricky, since you can find:
+ *
+ * "typedef long time_t;"
+ * "typedef unsigned int u_int;"
+ * "typedef unsigned int u_int [10];"
+ *
+ * If looking at a typedef, we save a copy of the last token
+ * found. Then, when we find the ';' we take the current
+ * token if it starts with a valid token name, else we take
+ * the one we saved. There's probably some reasonable
+ * alternative to this...
+ */
+ case ';':
+ if (t_def && level == t_level) {
+ t_def = NO;
+ ct_getline();
+ if (sp != tok)
+ *sp = EOS;
+ pfnote(tok, lineno);
+ break;
+ }
+ goto storec;
+
+ /*
+ * store characters until one that can't be part of a token
+ * comes along; check the current token against certain
+ * reserved words.
+ */
+ default:
+ storec: if (!intoken(c)) {
+ if (sp == tok)
+ break;
+ *sp = EOS;
+ if (tflag) {
+ /* no typedefs inside typedefs */
+ if (!t_def &&
+ !memcmp(tok, "typedef",8)) {
+ t_def = YES;
+ t_level = level;
+ break;
+ }
+ /* catch "typedef struct" */
+ if ((!t_def || t_level < level)
+ && (!memcmp(tok, "struct", 7)
+ || !memcmp(tok, "union", 6)
+ || !memcmp(tok, "enum", 5))) {
+ /*
+ * get line immediately;
+ * may change before '{'
+ */
+ ct_getline();
+ if (str_entry(c))
+ ++level;
+ break;
+ /* } */
+ }
+ }
+ sp = tok;
+ }
+ else if (sp != tok || begtoken(c)) {
+ *sp++ = c;
+ token = YES;
+ }
+ continue;
+ }
+
+ sp = tok;
+ token = NO;
+ }
+}
+
+/*
+ * func_entry --
+ * handle a function reference
+ */
+static int
+func_entry()
+{
+ int c; /* current character */
+ int level = 0; /* for matching '()' */
+ static char attribute[] = "__attribute__";
+ char maybe_attribute[sizeof attribute + 1],
+ *anext;
+
+ /*
+ * Find the end of the assumed function declaration.
+ * Note that ANSI C functions can have type definitions so keep
+ * track of the parentheses nesting level.
+ */
+ while (GETC(!=, EOF)) {
+ switch (c) {
+ case '\'':
+ case '"':
+ /* skip strings and character constants */
+ skip_string(c);
+ break;
+ case '/':
+ /* skip comments */
+ if (GETC(==, '*'))
+ skip_comment();
+ break;
+ case '(':
+ level++;
+ break;
+ case ')':
+ if (level == 0)
+ goto fnd;
+ level--;
+ break;
+ case '\n':
+ SETLINE;
+ }
+ }
+ return (NO);
+fnd:
+ /*
+ * we assume that the character after a function's right paren
+ * is a token character if it's a function and a non-token
+ * character if it's a declaration. Comments don't count...
+ */
+ for (anext = maybe_attribute;;) {
+ while (GETC(!=, EOF) && iswhite(c))
+ if (c == '\n')
+ SETLINE;
+ if (c == EOF)
+ return NO;
+ /*
+ * Recognize the gnu __attribute__ extension, which would
+ * otherwise make the heuristic test DTWT
+ */
+ if (anext == maybe_attribute) {
+ if (intoken(c)) {
+ *anext++ = c;
+ continue;
+ }
+ } else {
+ if (intoken(c)) {
+ if (anext - maybe_attribute
+ < (int)(sizeof attribute - 1))
+ *anext++ = c;
+ else break;
+ continue;
+ } else {
+ *anext++ = '\0';
+ if (strcmp(maybe_attribute, attribute) == 0) {
+ (void)ungetc(c, inf);
+ return NO;
+ }
+ break;
+ }
+ }
+ if (intoken(c) || c == '{')
+ break;
+ if (c == '/' && GETC(==, '*'))
+ skip_comment();
+ else { /* don't ever "read" '/' */
+ (void)ungetc(c, inf);
+ return (NO);
+ }
+ }
+ if (c != '{')
+ (void)skip_key('{');
+ return (YES);
+}
+
+/*
+ * hash_entry --
+ * handle a line starting with a '#'
+ */
+static void
+hash_entry()
+{
+ int c; /* character read */
+ int curline; /* line started on */
+ char *sp; /* buffer pointer */
+ char tok[MAXTOKEN]; /* storage buffer */
+
+ curline = lineno;
+ for (sp = tok;;) { /* get next token */
+ if (GETC(==, EOF))
+ return;
+ if (iswhite(c))
+ break;
+ *sp++ = c;
+ }
+ *sp = EOS;
+ if (memcmp(tok, "define", 6)) /* only interested in #define's */
+ goto skip;
+ for (;;) { /* this doesn't handle "#define \n" */
+ if (GETC(==, EOF))
+ return;
+ if (!iswhite(c))
+ break;
+ }
+ for (sp = tok;;) { /* get next token */
+ *sp++ = c;
+ if (GETC(==, EOF))
+ return;
+ /*
+ * this is where it DOESN'T handle
+ * "#define \n"
+ */
+ if (!intoken(c))
+ break;
+ }
+ *sp = EOS;
+ if (dflag || c == '(') { /* only want macros */
+ ct_getline();
+ pfnote(tok, curline);
+ }
+skip: if (c == '\n') { /* get rid of rest of define */
+ SETLINE
+ if (*(sp - 1) != '\\')
+ return;
+ }
+ (void)skip_key('\n');
+}
+
+/*
+ * str_entry --
+ * handle a struct, union or enum entry
+ */
+static int
+str_entry(c)
+ int c; /* current character */
+{
+ int curline; /* line started on */
+ char *sp; /* buffer pointer */
+ char tok[LINE_MAX]; /* storage buffer */
+
+ curline = lineno;
+ while (iswhite(c))
+ if (GETC(==, EOF))
+ return (NO);
+ if (c == '{') /* it was "struct {" */
+ return (YES);
+ for (sp = tok;;) { /* get next token */
+ *sp++ = c;
+ if (GETC(==, EOF))
+ return (NO);
+ if (!intoken(c))
+ break;
+ }
+
+ switch (c) {
+ case '{': /* it was "struct foo{" */
+ --sp;
+ break;
+ case '\n': /* it was "struct foo\n" */
+ SETLINE;
+ if(GETC(!=, '/'))
+ {
+ while (GETC(!=, EOF))
+ if (!iswhite(c))
+ break;
+ if (c != '{') {
+ (void)ungetc(c, inf);
+ return (NO);
+ }
+ break;
+ }
+ case '/':
+ /* skip comments */
+ if (GETC(==, '*')) {
+ skip_comment();
+ }
+ /*FALLTHROUGH*/
+ default: /* probably "struct foo " */
+ while (GETC(!=, EOF))
+ if (!iswhite(c))
+ break;
+ if (c != '{') {
+ (void)ungetc(c, inf);
+ return (NO);
+ }
+ }
+ *sp = EOS;
+ pfnote(tok, curline);
+ return (YES);
+}
+
+/*
+ * skip_comment --
+ * skip over comment
+ */
+void
+skip_comment()
+{
+ int c; /* character read */
+ int star; /* '*' flag */
+
+ for (star = 0; GETC(!=, EOF);)
+ switch(c) {
+ /* comments don't nest, nor can they be escaped. */
+ case '*':
+ star = YES;
+ break;
+ case '/':
+ if (star)
+ return;
+ break;
+ case '\n':
+ SETLINE;
+ /*FALLTHROUGH*/
+ default:
+ star = NO;
+ break;
+ }
+}
+
+/*
+ * skip_string --
+ * skip to the end of a string or character constant.
+ */
+void
+skip_string(key)
+ int key;
+{
+ int c,
+ skip;
+
+ for (skip = NO; GETC(!=, EOF); )
+ switch (c) {
+ case '\\': /* a backslash escapes anything */
+ skip = !skip; /* we toggle in case it's "\\" */
+ break;
+ case '\n':
+ SETLINE;
+ /*FALLTHROUGH*/
+ default:
+ if (c == key && !skip)
+ return;
+ skip = NO;
+ }
+}
+
+/*
+ * skip_key --
+ * skip to next char "key"
+ */
+int
+skip_key(key)
+ int key;
+{
+ int c,
+ skip,
+ retval;
+
+ for (skip = retval = NO; GETC(!=, EOF);)
+ switch(c) {
+ case '\\': /* a backslash escapes anything */
+ skip = !skip; /* we toggle in case it's "\\" */
+ break;
+ case ';': /* special case for yacc; if one */
+ case '|': /* of these chars occurs, we may */
+ retval = YES; /* have moved out of the rule */
+ break; /* not used by C */
+ case '\'':
+ case '"':
+ /* skip strings and character constants */
+ skip_string(c);
+ break;
+ case '/':
+ /* skip comments */
+ if (GETC(==, '*')) {
+ skip_comment();
+ break;
+ }
+ (void)ungetc(c, inf);
+ c = '/';
+ goto norm;
+ case '\n':
+ SETLINE;
+ /*FALLTHROUGH*/
+ default:
+ norm:
+ if (c == key && !skip)
+ return (retval);
+ skip = NO;
+ }
+ return (retval);
+}
diff --git a/developer_cmds/ctags/ctags.1 b/developer_cmds/ctags/ctags.1
new file mode 100644
index 0000000..353c990
--- /dev/null
+++ b/developer_cmds/ctags/ctags.1
@@ -0,0 +1,221 @@
+.\" $NetBSD: ctags.1,v 1.5 1997/10/18 13:18:24 lukem Exp $
+.\"
+.\" Copyright (c) 1987, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ctags.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt CTAGS 1
+.Os BSD 4
+.Sh NAME
+.Nm ctags
+.Nd create a tags file
+.Sh SYNOPSIS
+.Nm
+.Op Fl BFadtuwvx
+.Op Fl f Ar tags_file
+.Ar name ...
+.Sh DESCRIPTION
+.Nm
+makes a tags file for
+.Xr ex 1
+from the specified C,
+Pascal, Fortran,
+.Tn YACC ,
+lex, and lisp sources.
+A tags file gives the locations of specified objects in a group of files.
+Each line of the tags file contains the object name, the file in which it
+is defined, and a search pattern for the object definition, separated by
+white-space.
+.Pp
+Using the
+.Ar tags
+file,
+.Xr ex 1
+can quickly locate these object definitions.
+Depending upon the options provided to
+.Nm ,
+objects will consist of subroutines, typedefs, defines, structs,
+enums, and unions.
+.Bl -tag -width Ds
+.It Fl a
+append to
+.Ar tags
+file.
+.It Fl B
+use backward searching patterns
+.Pq Li ?...? .
+.It Fl d
+create tags for
+.Li #defines
+that don't take arguments;
+.Li #defines
+that take arguments are tagged automatically.
+.It Fl F
+use forward searching patterns
+.Pq Li /.../
+(the default).
+.It Fl f
+Places the tag descriptions in a file called
+.Ar tags_file .
+The default behavior is to place them in a file called
+.Ar tags .
+.It Fl t
+create tags for typedefs, structs, unions, and enums.
+.It Fl u
+update the specified files in the
+.Ar tags
+file, that is, all
+references to them are deleted, and the new values are appended to the
+file. (Beware: this option is implemented in a way which is rather
+slow; it is usually faster to simply rebuild the
+.Ar tags
+file.)
+.It Fl v
+An index of the form expected by
+.Xr vgrind 1
+is produced on the standard output. This listing
+contains the object name, file name, and page number (assuming 64-line pages).
+Because the output will be sorted into lexicographic order,
+it may be desirable to run the output through
+.Xr sort 1 .
+Sample use:
+.Bd -literal -offset indent
+ctags \-v files \&| sort \-f > index
+vgrind \-x index
+.Ed
+.It Fl w
+suppress warning diagnostics.
+.It Fl x
+.Nm
+produces a list of object
+names, the line number and file name on which each is defined, as well
+as the text of that line and prints this on the standard output. This
+is a simple function index which can be printed out for reading off-line.
+.El
+.Pp
+Files whose names end in
+.Sq \&.c
+or
+.Sq \&.h
+are assumed to be C
+source files and are searched for C style routine and macro definitions.
+Files whose names end in
+.Sq \&.y
+are assumed to be
+.Tn YACC
+source files.
+Files whose names end in
+.Sq \&.l
+are assumed to be lisp files if their
+first non-blank character is `;', `(', or `[',
+otherwise, they are treated
+as lex files. Other files are first examined to see if they
+contain any Pascal or Fortran routine definitions; if not, they are
+searched for C-style definitions.
+.Pp
+The tag
+.Li main
+is treated specially in C programs. The tag formed
+is created by prepending
+.Ar M
+to the name of the file, with the
+trailing
+.Sq \&.c
+and any leading pathname components removed. This
+makes use of
+.Nm
+practical in directories with more than one
+program.
+.Pp
+Yacc and lex files each have a special tag.
+.Ar Yyparse
+is the start
+of the second section of the yacc file, and
+.Ar yylex
+is the start of
+the second section of the lex file.
+.Sh FILES
+.Bl -tag -width tagsxxx -compact
+.It Pa tags
+default output tags file
+.El
+.Sh DIAGNOSTICS
+.Nm
+exits with a value of 1 if an error occurred, 0 otherwise.
+Duplicate objects are not considered to be errors.
+.Sh SEE ALSO
+.Xr cc 1 ,
+.Xr ex 1 ,
+.Xr lex 1 ,
+.Xr sort 1 ,
+.\" .Xr vgrind 1 ,
+.Xr vi 1 ,
+.Xr yacc 1
+.Sh BUGS
+Recognition of
+.Em functions ,
+.Em subroutines ,
+and
+.Em procedures
+for
+.Tn FORTRAN
+and Pascal is done in a very simple-minded way. No attempt
+is made to deal with block structure; if you have Pascal procedures
+with the same name in different blocks, you lose.
+.Nm
+doesn't
+understand about Pascal types.
+.Pp
+The method of deciding whether to look for C, Pascal, or
+.Tn FORTRAN
+functions is a hack.
+.Pp
+.Nm
+relies on the input being well formed, so any syntactical
+errors will completely confuse it. It also finds some legal syntax
+to be confusing; for example, because it doesn't understand
+.Li #ifdef Ns 's
+(incidentally, that's a feature, not a bug), any code with unbalanced
+braces inside
+.Li #ifdef Ns 's
+will cause it to become somewhat disoriented.
+In a similar fashion, multiple line changes within a definition will
+cause it to enter the last line of the object, rather than the first, as
+the searching pattern. The last line of multiple line
+.Li typedef Ns 's
+will similarly be noted.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/developer_cmds/ctags/ctags.c b/developer_cmds/ctags/ctags.c
new file mode 100644
index 0000000..490f91d
--- /dev/null
+++ b/developer_cmds/ctags/ctags.c
@@ -0,0 +1,282 @@
+/* $NetBSD: ctags.c,v 1.6 1998/08/25 20:59:36 ross Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ctags.c 8.4 (Berkeley) 2/7/95";
+#endif
+__RCSID("$NetBSD: ctags.c,v 1.6 1998/08/25 20:59:36 ross Exp $");
+#endif /* not lint */
+
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "ctags.h"
+
+/*
+ * ctags: create a tags file
+ */
+
+NODE *head; /* head of the sorted binary tree */
+
+ /* boolean "func" (see init()) */
+bool _wht[256], _etk[256], _itk[256], _btk[256], _gd[256];
+
+FILE *inf; /* ioptr for current input file */
+FILE *outf; /* ioptr for tags file */
+
+long lineftell; /* ftell after getc( inf ) == '\n' */
+
+int lineno; /* line number of current line */
+int dflag; /* -d: non-macro defines */
+int tflag=1; /* -t: create tags for typedefs */
+int vflag; /* -v: vgrind style index output */
+int wflag; /* -w: suppress warnings */
+int xflag; /* -x: cxref style output */
+
+char *curfile; /* current input file name */
+char searchar = '/'; /* use /.../ searches by default */
+char lbuf[LINE_MAX];
+
+void init __P((void));
+int main __P((int, char **));
+void find_entries __P((char *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ static char *outfile = "tags"; /* output file */
+ int aflag; /* -a: append to tags */
+ int uflag; /* -u: update tags */
+ int exit_val; /* exit value */
+ int step; /* step through args */
+ int ch; /* getopts char */
+ char cmd[100]; /* too ugly to explain */
+
+ aflag = uflag = NO;
+ while ((ch = getopt(argc, argv, "BFadf:tuwvx")) != -1)
+ switch(ch) {
+ case 'B':
+ searchar = '?';
+ break;
+ case 'F':
+ searchar = '/';
+ break;
+ case 'a':
+ aflag++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'f':
+ outfile = optarg;
+ break;
+ case 't':
+ tflag++;
+ break;
+ case 'T':
+ tflag--;
+ break;
+ case 'u':
+ uflag++;
+ break;
+ case 'w':
+ wflag++;
+ break;
+ case 'v':
+ vflag++;
+ case 'x':
+ xflag++;
+ break;
+ case '?':
+ default:
+ goto usage;
+ }
+ argv += optind;
+ argc -= optind;
+ if (!argc) {
+usage: (void)fprintf(stderr,
+ "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
+ exit(1);
+ }
+
+ init();
+
+ for (exit_val = step = 0; step < argc; ++step)
+ if (!(inf = fopen(argv[step], "r"))) {
+ warn("%s", argv[step]);
+ exit_val = 1;
+ }
+ else {
+ curfile = argv[step];
+ find_entries(argv[step]);
+ (void)fclose(inf);
+ }
+
+ if (head) {
+ if (xflag)
+ put_entries(head);
+ else {
+ if (uflag) {
+ for (step = 0; step < argc; step++) {
+ (void)sprintf(cmd,
+ "mv %s OTAGS; fgrep -v '\t%s\t' OTAGS >%s; rm OTAGS",
+ outfile, argv[step],
+ outfile);
+ system(cmd);
+ }
+ ++aflag;
+ }
+ if (!(outf = fopen(outfile, aflag ? "a" : "w")))
+ err(exit_val ? exit_val : 1, "%s", outfile);
+ put_entries(head);
+ (void)fclose(outf);
+ if (uflag) {
+ (void)sprintf(cmd, "sort -o %s %s",
+ outfile, outfile);
+ system(cmd);
+ }
+ }
+ }
+ exit(exit_val);
+}
+
+/*
+ * init --
+ * this routine sets up the boolean psuedo-functions which work by
+ * setting boolean flags dependent upon the corresponding character.
+ * Every char which is NOT in that string is false with respect to
+ * the pseudo-function. Therefore, all of the array "_wht" is NO
+ * by default and then the elements subscripted by the chars in
+ * CWHITE are set to YES. Thus, "_wht" of a char is YES if it is in
+ * the string CWHITE, else NO.
+ */
+void
+init()
+{
+ int i;
+ unsigned char *sp;
+
+ for (i = 0; i < 256; i++) {
+ _wht[i] = _etk[i] = _itk[i] = _btk[i] = NO;
+ _gd[i] = YES;
+ }
+#define CWHITE (unsigned char *)" \f\t\n"
+ for (sp = CWHITE; *sp; sp++) /* white space chars */
+ _wht[*sp] = YES;
+#define CTOKEN (unsigned char *)" \t\n\"'#()[]{}=-+%*/&|^~!<>;,.:?"
+ for (sp = CTOKEN; *sp; sp++) /* token ending chars */
+ _etk[*sp] = YES;
+#define CINTOK (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz0123456789"
+ for (sp = CINTOK; *sp; sp++) /* valid in-token chars */
+ _itk[*sp] = YES;
+#define CBEGIN (unsigned char *)"ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
+ for (sp = CBEGIN; *sp; sp++) /* token starting chars */
+ _btk[*sp] = YES;
+#define CNOTGD (unsigned char *)",;"
+ for (sp = CNOTGD; *sp; sp++) /* invalid after-function chars */
+ _gd[*sp] = NO;
+}
+
+/*
+ * find_entries --
+ * this routine opens the specified file and calls the function
+ * which searches the file.
+ */
+void
+find_entries(file)
+ char *file;
+{
+ char *cp;
+
+ lineno = 0; /* should be 1 ?? KB */
+ if ((cp = strrchr(file, '.')) != NULL) {
+ if (cp[1] == 'l' && !cp[2]) {
+ int c;
+
+ for (;;) {
+ if (GETC(==, EOF))
+ return;
+ if (!iswhite(c)) {
+ rewind(inf);
+ break;
+ }
+ }
+#define LISPCHR ";(["
+/* lisp */ if (strchr(LISPCHR, c)) {
+ l_entries();
+ return;
+ }
+/* lex */ else {
+ /*
+ * we search all 3 parts of a lex file
+ * for C references. This may be wrong.
+ */
+ toss_yysec();
+ (void)strcpy(lbuf, "%%$");
+ pfnote("yylex", lineno);
+ rewind(inf);
+ }
+ }
+/* yacc */ else if (cp[1] == 'y' && !cp[2]) {
+ /*
+ * we search only the 3rd part of a yacc file
+ * for C references. This may be wrong.
+ */
+ toss_yysec();
+ (void)strcpy(lbuf, "%%$");
+ pfnote("yyparse", lineno);
+ y_entries();
+ }
+/* fortran */ else if ((cp[1] != 'c' && cp[1] != 'h') && !cp[2]) {
+ if (PF_funcs())
+ return;
+ rewind(inf);
+ }
+ }
+/* C */ c_entries();
+}
diff --git a/developer_cmds/ctags/ctags.h b/developer_cmds/ctags/ctags.h
new file mode 100644
index 0000000..99ba934
--- /dev/null
+++ b/developer_cmds/ctags/ctags.h
@@ -0,0 +1,92 @@
+/* $NetBSD: ctags.h,v 1.3 1995/03/26 20:14:07 glass Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ctags.h 8.3 (Berkeley) 4/2/94
+ */
+
+#define bool char
+
+#define YES 1
+#define NO 0
+#define EOS '\0'
+
+#define ENDLINE 50 /* max length of pattern */
+#define MAXTOKEN 250 /* max size of single token */
+
+#define SETLINE {++lineno;lineftell = ftell(inf);}
+#define GETC(op,exp) ((c = getc(inf)) op (int)exp)
+
+#define iswhite(arg) (_wht[(unsigned)arg]) /* T if char is white */
+#define begtoken(arg) (_btk[(unsigned)arg]) /* T if char can start token */
+#define intoken(arg) (_itk[(unsigned)arg]) /* T if char can be in token */
+#define endtoken(arg) (_etk[(unsigned)arg]) /* T if char ends tokens */
+#define isgood(arg) (_gd[(unsigned)arg]) /* T if char can be after ')' */
+
+typedef struct nd_st { /* sorting structure */
+ struct nd_st *left,
+ *right; /* left and right sons */
+ char *entry, /* function or type name */
+ *file, /* file name */
+ *pat; /* search pattern */
+ int lno; /* for -x option */
+ bool been_warned; /* set if noticed dup */
+} NODE;
+
+extern char *curfile; /* current input file name */
+extern NODE *head; /* head of the sorted binary tree */
+extern FILE *inf; /* ioptr for current input file */
+extern FILE *outf; /* ioptr for current output file */
+extern long lineftell; /* ftell after getc( inf ) == '\n' */
+extern int lineno; /* line number of current line */
+extern int dflag; /* -d: non-macro defines */
+extern int tflag; /* -t: create tags for typedefs */
+extern int vflag; /* -v: vgrind style index output */
+extern int wflag; /* -w: suppress warnings */
+extern int xflag; /* -x: cxref style output */
+extern bool _wht[], _etk[], _itk[], _btk[], _gd[];
+extern char lbuf[LINE_MAX];
+extern char *lbp;
+extern char searchar; /* ex search character */
+
+extern int cicmp __P((char *));
+extern void ct_getline __P((void));
+extern void pfnote __P((char *, int));
+extern int skip_key __P((int));
+extern void put_entries __P((NODE *));
+extern void toss_yysec __P((void));
+extern void l_entries __P((void));
+extern void y_entries __P((void));
+extern int PF_funcs __P((void));
+extern void c_entries __P((void));
+extern void skip_comment __P((void));
diff --git a/developer_cmds/ctags/fortran.c b/developer_cmds/ctags/fortran.c
new file mode 100644
index 0000000..a4b4178
--- /dev/null
+++ b/developer_cmds/ctags/fortran.c
@@ -0,0 +1,175 @@
+/* $NetBSD: fortran.c,v 1.4 1997/10/18 13:18:37 lukem Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)fortran.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: fortran.c,v 1.4 1997/10/18 13:18:37 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ctags.h"
+
+static void takeprec __P((void));
+
+char *lbp; /* line buffer pointer */
+
+int
+PF_funcs()
+{
+ bool pfcnt; /* pascal/fortran functions found */
+ char *cp;
+ char tok[MAXTOKEN];
+
+ for (pfcnt = NO;;) {
+ lineftell = ftell(inf);
+ if (!fgets(lbuf, sizeof(lbuf), inf))
+ return (pfcnt);
+ ++lineno;
+ lbp = lbuf;
+ if (*lbp == '%') /* Ratfor escape to fortran */
+ ++lbp;
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (!*lbp)
+ continue;
+ switch (*lbp | ' ') { /* convert to lower-case */
+ case 'c':
+ if (cicmp("complex") || cicmp("character"))
+ takeprec();
+ break;
+ case 'd':
+ if (cicmp("double")) {
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (!*lbp)
+ continue;
+ if (cicmp("precision"))
+ break;
+ continue;
+ }
+ break;
+ case 'i':
+ if (cicmp("integer"))
+ takeprec();
+ break;
+ case 'l':
+ if (cicmp("logical"))
+ takeprec();
+ break;
+ case 'r':
+ if (cicmp("real"))
+ takeprec();
+ break;
+ }
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (!*lbp)
+ continue;
+ switch (*lbp | ' ') {
+ case 'f':
+ if (cicmp("function"))
+ break;
+ continue;
+ case 'p':
+ if (cicmp("program") || cicmp("procedure"))
+ break;
+ continue;
+ case 's':
+ if (cicmp("subroutine"))
+ break;
+ default:
+ continue;
+ }
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (!*lbp)
+ continue;
+ for (cp = lbp + 1; *cp && intoken(*cp); ++cp)
+ continue;
+ if ((cp = lbp + 1) != NULL)
+ continue;
+ *cp = EOS;
+ (void)strcpy(tok, lbp);
+ ct_getline(); /* process line for ex(1) */
+ pfnote(tok, lineno);
+ pfcnt = YES;
+ }
+ /*NOTREACHED*/
+}
+
+/*
+ * cicmp --
+ * do case-independent strcmp
+ */
+int
+cicmp(cp)
+ char *cp;
+{
+ int len;
+ char *bp;
+
+ for (len = 0, bp = lbp; *cp && (*cp &~ ' ') == (*bp++ &~ ' ');
+ ++cp, ++len)
+ continue;
+ if (!*cp) {
+ lbp += len;
+ return (YES);
+ }
+ return (NO);
+}
+
+static void
+takeprec()
+{
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ if (*lbp == '*') {
+ for (++lbp; isspace(*lbp); ++lbp)
+ continue;
+ if (!isdigit(*lbp))
+ --lbp; /* force failure */
+ else
+ while (isdigit(*++lbp))
+ continue;
+ }
+}
diff --git a/developer_cmds/ctags/lisp.c b/developer_cmds/ctags/lisp.c
new file mode 100644
index 0000000..e925c1b
--- /dev/null
+++ b/developer_cmds/ctags/lisp.c
@@ -0,0 +1,112 @@
+/* $NetBSD: lisp.c,v 1.4 1997/10/18 13:18:45 lukem Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lisp.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: lisp.c,v 1.4 1997/10/18 13:18:45 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ctags.h"
+
+/*
+ * lisp tag functions
+ * just look for (def or (DEF
+ */
+void
+l_entries()
+{
+ int special;
+ char *cp;
+ char savedc;
+ char tok[MAXTOKEN];
+
+ for (;;) {
+ lineftell = ftell(inf);
+ if (!fgets(lbuf, sizeof(lbuf), inf))
+ return;
+ ++lineno;
+ lbp = lbuf;
+ if (!cicmp("(def"))
+ continue;
+ special = NO;
+ switch(*lbp | ' ') {
+ case 'm':
+ if (cicmp("method"))
+ special = YES;
+ break;
+ case 'w':
+ if (cicmp("wrapper") || cicmp("whopper"))
+ special = YES;
+ }
+ for (; !isspace(*lbp); ++lbp)
+ continue;
+ for (; isspace(*lbp); ++lbp)
+ continue;
+ for (cp = lbp; *cp && *cp != '\n'; ++cp)
+ continue;
+ *cp = EOS;
+ if (special) {
+ if (!(cp = strchr(lbp, ')')))
+ continue;
+ for (; cp >= lbp && *cp != ':'; --cp)
+ continue;
+ if (cp < lbp)
+ continue;
+ lbp = cp;
+ for (; *cp && *cp != ')' && *cp != ' '; ++cp)
+ continue;
+ }
+ else
+ for (cp = lbp + 1;
+ *cp && *cp != '(' && *cp != ' '; ++cp)
+ continue;
+ savedc = *cp;
+ *cp = EOS;
+ (void)strcpy(tok, lbp);
+ *cp = savedc;
+ ct_getline();
+ pfnote(tok, lineno);
+ }
+ /*NOTREACHED*/
+}
diff --git a/developer_cmds/ctags/print.c b/developer_cmds/ctags/print.c
new file mode 100644
index 0000000..a6c4aaf
--- /dev/null
+++ b/developer_cmds/ctags/print.c
@@ -0,0 +1,122 @@
+/* $NetBSD: print.c,v 1.5 1997/10/18 13:18:52 lukem Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: print.c,v 1.5 1997/10/18 13:18:52 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ctags.h"
+
+/*
+ * ct_getline --
+ * get the line the token of interest occurred on,
+ * prepare it for printing.
+ */
+void
+ct_getline()
+{
+ long saveftell;
+ int c;
+ int cnt;
+ char *cp;
+
+ saveftell = ftell(inf);
+ (void)fseek(inf, lineftell, SEEK_SET);
+ if (xflag)
+ for (cp = lbuf; GETC(!=, '\n'); *cp++ = c)
+ continue;
+ /*
+ * do all processing here, so we don't step through the
+ * line more than once; means you don't call this routine
+ * unless you're sure you've got a keeper.
+ */
+ else for (cnt = 0, cp = lbuf; GETC(!=, EOF) && cnt < ENDLINE; ++cnt) {
+ if (c == '\\') { /* backslashes */
+ if (cnt > ENDLINE - 2)
+ break;
+ *cp++ = '\\'; *cp++ = '\\';
+ ++cnt;
+ }
+ else if (c == (int)searchar) { /* search character */
+ if (cnt > ENDLINE - 2)
+ break;
+ *cp++ = '\\'; *cp++ = c;
+ ++cnt;
+ }
+ else if (c == '\n') { /* end of keep */
+ *cp++ = '$'; /* can find whole line */
+ break;
+ }
+ else
+ *cp++ = c;
+ }
+ *cp = EOS;
+ (void)fseek(inf, saveftell, SEEK_SET);
+}
+
+/*
+ * put_entries --
+ * write out the tags
+ */
+void
+put_entries(node)
+ NODE *node;
+{
+
+ if (node->left)
+ put_entries(node->left);
+ if (vflag)
+ printf("%s %s %d\n",
+ node->entry, node->file, (node->lno + 63) / 64);
+ else if (xflag)
+ printf("%-16s%4d %-16s %s\n",
+ node->entry, node->lno, node->file, node->pat);
+ else
+ fprintf(outf, "%s\t%s\t%c^%s%c\n",
+ node->entry, node->file, searchar, node->pat, searchar);
+ if (node->right)
+ put_entries(node->right);
+}
diff --git a/developer_cmds/ctags/test/ctags.test b/developer_cmds/ctags/test/ctags.test
new file mode 100644
index 0000000..658a073
--- /dev/null
+++ b/developer_cmds/ctags/test/ctags.test
@@ -0,0 +1,69 @@
+/* $NetBSD: ctags.test,v 1.2 1995/03/26 20:14:14 glass Exp $ */
+
+int bar = (1 + 5);
+
+FOO("here is a #define test: ) {");
+char sysent[20];
+int nsysent = sizeof (sysent) / sizeof (sysent[0]);
+/*
+ * now is the time for a comment.
+ * four lines in length...
+ */struct struct_xtra{int list;};r4(x,y){};typedef struct{int bar;}struct_xxe;
+#define FOO BAR
+struct struct_three {
+ int list;
+};
+#define SINGLE
+int BAD();
+enum color {red, green, gold, brown};
+char qq[] = " quote(one,two) {int bar;} ";
+typedef struct {
+ int bar;
+ struct struct_two {
+ int foo;
+ union union_3 {
+ struct struct_three entry;
+ char size[25];
+ };
+ struct last {
+ struct struct_three xentry;
+ char list[34];
+ };
+ };
+} struct_one;
+#define TWOLINE ((MAXLIST + FUTURE + 15) \
+ / (time_to_live ? 3 : 4))
+#if (defined(BAR))
+int bar;
+#endif
+#define MULTIPLE {\
+ multiple(one,two); \
+ lineno++; \
+ callroute(one,two); \
+}
+#if defined(BAR)
+int bar;
+#endif
+union union_one {
+ struct struct_three s3;
+ char foo[25];
+};
+#define XYZ(A,B) (A + B / 2) * (3 - 26 + l_lineno)
+routine1(one,two) /* comments here are fun... */
+ struct {
+ int entry;
+ char bar[34];
+ } *one;
+ char two[10];
+{
+typedef unsigned char u_char;
+ register struct buf *bp;
+ five(one,two);
+}
+ routine2 (one,two) { puts("hello\n"); }
+ routine3
+(one,
+two) { puts("world\n"); }
+routine4(int one, char (*two)(void)) /* test ANSI arguments */
+{
+}
diff --git a/developer_cmds/ctags/tree.c b/developer_cmds/ctags/tree.c
new file mode 100644
index 0000000..c31975c
--- /dev/null
+++ b/developer_cmds/ctags/tree.c
@@ -0,0 +1,142 @@
+/* $NetBSD: tree.c,v 1.5 1997/10/18 13:18:58 lukem Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tree.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: tree.c,v 1.5 1997/10/18 13:18:58 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ctags.h"
+
+static void add_node __P((NODE *, NODE *));
+static void free_tree __P((NODE *));
+
+/*
+ * pfnote --
+ * enter a new node in the tree
+ */
+void
+pfnote(name, ln)
+ char *name;
+ int ln;
+{
+ NODE *np;
+ char *fp;
+ char nbuf[MAXTOKEN];
+
+ /*NOSTRICT*/
+ if (!(np = (NODE *)malloc(sizeof(NODE)))) {
+ warnx("too many entries to sort");
+ put_entries(head);
+ free_tree(head);
+ /*NOSTRICT*/
+ if (!(head = np = (NODE *)malloc(sizeof(NODE))))
+ err(1, "out of space");
+ }
+ if (!xflag && !strcmp(name, "main")) {
+ if (!(fp = strrchr(curfile, '/')))
+ fp = curfile;
+ else
+ ++fp;
+ (void)sprintf(nbuf, "M%s", fp);
+ fp = strrchr(nbuf, '.');
+ if (fp && !fp[2])
+ *fp = EOS;
+ name = nbuf;
+ }
+ if (!(np->entry = strdup(name)))
+ err(1, "strdup");
+ np->file = curfile;
+ np->lno = ln;
+ np->left = np->right = 0;
+ if (!(np->pat = strdup(lbuf)))
+ err(1, "strdup");
+ if (!head)
+ head = np;
+ else
+ add_node(np, head);
+}
+
+static void
+add_node(node, cur_node)
+ NODE *node,
+ *cur_node;
+{
+ int dif;
+
+ dif = strcmp(node->entry, cur_node->entry);
+ if (!dif) {
+ if (node->file == cur_node->file) {
+ if (!wflag)
+ fprintf(stderr, "Duplicate entry in file %s, line %d: %s\nSecond entry ignored\n", node->file, lineno, node->entry);
+ return;
+ }
+ if (!cur_node->been_warned)
+ if (!wflag)
+ fprintf(stderr, "Duplicate entry in files %s and %s: %s (Warning only)\n", node->file, cur_node->file, node->entry);
+ cur_node->been_warned = YES;
+ }
+ else if (dif < 0)
+ if (cur_node->left)
+ add_node(node, cur_node->left);
+ else
+ cur_node->left = node;
+ else if (cur_node->right)
+ add_node(node, cur_node->right);
+ else
+ cur_node->right = node;
+}
+
+static void
+free_tree(node)
+ NODE *node;
+{
+ while (node) {
+ if (node->right)
+ free_tree(node->right);
+ free(node);
+ node = node->left;
+ }
+}
diff --git a/developer_cmds/ctags/yacc.c b/developer_cmds/ctags/yacc.c
new file mode 100644
index 0000000..17edfa6
--- /dev/null
+++ b/developer_cmds/ctags/yacc.c
@@ -0,0 +1,158 @@
+/* $NetBSD: yacc.c,v 1.4 1997/10/18 13:19:04 lukem Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)yacc.c 8.3 (Berkeley) 4/2/94";
+#else
+__RCSID("$NetBSD: yacc.c,v 1.4 1997/10/18 13:19:04 lukem Exp $");
+#endif
+#endif /* not lint */
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "ctags.h"
+
+/*
+ * y_entries:
+ * find the yacc tags and put them in.
+ */
+void
+y_entries()
+{
+ int c;
+ char *sp;
+ bool in_rule;
+ char tok[MAXTOKEN];
+
+ in_rule = NO;
+
+ while (GETC(!=, EOF))
+ switch (c) {
+ case '\n':
+ SETLINE;
+ /* FALLTHROUGH */
+ case ' ':
+ case '\f':
+ case '\r':
+ case '\t':
+ break;
+ case '{':
+ if (skip_key('}'))
+ in_rule = NO;
+ break;
+ case '\'':
+ case '"':
+ if (skip_key(c))
+ in_rule = NO;
+ break;
+ case '%':
+ if (GETC(==, '%'))
+ return;
+ (void)ungetc(c, inf);
+ break;
+ case '/':
+ if (GETC(==, '*'))
+ skip_comment();
+ else
+ (void)ungetc(c, inf);
+ break;
+ case '|':
+ case ';':
+ in_rule = NO;
+ break;
+ default:
+ if (in_rule || (!isalpha(c) && c != '.' && c != '_'))
+ break;
+ sp = tok;
+ *sp++ = c;
+ while (GETC(!=, EOF) && (intoken(c) || c == '.'))
+ *sp++ = c;
+ *sp = EOS;
+ ct_getline(); /* may change before ':' */
+ while (iswhite(c)) {
+ if (c == '\n')
+ SETLINE;
+ if (GETC(==, EOF))
+ return;
+ }
+ if (c == ':') {
+ pfnote(tok, lineno);
+ in_rule = YES;
+ }
+ else
+ (void)ungetc(c, inf);
+ }
+}
+
+/*
+ * toss_yysec --
+ * throw away lines up to the next "\n%%\n"
+ */
+void
+toss_yysec()
+{
+ int c; /* read character */
+ int state;
+
+ /*
+ * state == 0 : waiting
+ * state == 1 : received a newline
+ * state == 2 : received first %
+ * state == 3 : recieved second %
+ */
+ lineftell = ftell(inf);
+ for (state = 0; GETC(!=, EOF);)
+ switch (c) {
+ case '\n':
+ ++lineno;
+ lineftell = ftell(inf);
+ if (state == 3) /* done! */
+ return;
+ state = 1; /* start over */
+ break;
+ case '%':
+ if (state) /* if 1 or 2 */
+ ++state; /* goto 3 */
+ break;
+ default:
+ state = 0; /* reset */
+ break;
+ }
+}
diff --git a/developer_cmds/developer_cmds.xcodeproj/project.pbxproj b/developer_cmds/developer_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..e43393a
--- /dev/null
+++ b/developer_cmds/developer_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,787 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FDA9C8500FD5E85100A6EA6E /* default */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDA9C85E0FD5E86100A6EA6E /* Build configuration list for PBXAggregateTarget "default" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FDA9C8590FD5E85C00A6EA6E /* PBXTargetDependency */,
+ FDA9C85B0FD5E85E00A6EA6E /* PBXTargetDependency */,
+ FDA9C8B60FD5EAA500A6EA6E /* PBXTargetDependency */,
+ FDA9C9870FD5F06900A6EA6E /* PBXTargetDependency */,
+ FDA9C8DA0FD5EBB200A6EA6E /* PBXTargetDependency */,
+ FDA9C8FC0FD5EC3300A6EA6E /* PBXTargetDependency */,
+ );
+ name = default;
+ productName = Default;
+ };
+ FDA9C97F0FD5F05400A6EA6E /* lorder */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDA9C98B0FD5F08700A6EA6E /* Build configuration list for PBXAggregateTarget "lorder" */;
+ buildPhases = (
+ FDA9C97E0FD5F05400A6EA6E /* ShellScript */,
+ FDA9C9A20FD5F12200A6EA6E /* Install man1 */,
+ );
+ dependencies = (
+ );
+ name = lorder;
+ productName = lorder;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ FDA9C83F0FD5E7E300A6EA6E /* asa.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7E40FD5D90F00A6EA6E /* asa.c */; };
+ FDA9C84D0FD5E82800A6EA6E /* asa.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDA9C7E30FD5D90F00A6EA6E /* asa.1 */; };
+ FDA9C85F0FD5E87200A6EA6E /* C.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7E70FD5D92800A6EA6E /* C.c */; };
+ FDA9C8600FD5E87200A6EA6E /* ctags.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7E90FD5D92800A6EA6E /* ctags.c */; };
+ FDA9C8610FD5E87200A6EA6E /* fortran.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7EB0FD5D92800A6EA6E /* fortran.c */; };
+ FDA9C8620FD5E87200A6EA6E /* lisp.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7EC0FD5D92800A6EA6E /* lisp.c */; };
+ FDA9C8630FD5E87200A6EA6E /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7EE0FD5D92800A6EA6E /* print.c */; };
+ FDA9C8640FD5E87200A6EA6E /* tree.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7F10FD5D92800A6EA6E /* tree.c */; };
+ FDA9C8650FD5E87200A6EA6E /* yacc.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7F20FD5D92800A6EA6E /* yacc.c */; };
+ FDA9C86B0FD5E88900A6EA6E /* ctags.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDA9C7E80FD5D92800A6EA6E /* ctags.1 */; };
+ FDA9C8BA0FD5EAD700A6EA6E /* args.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C7FF0FD5D92800A6EA6E /* args.c */; };
+ FDA9C8BB0FD5EAD700A6EA6E /* indent.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8010FD5D92800A6EA6E /* indent.c */; };
+ FDA9C8BC0FD5EAD700A6EA6E /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8040FD5D92800A6EA6E /* io.c */; };
+ FDA9C8BD0FD5EAD700A6EA6E /* lexi.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8050FD5D92800A6EA6E /* lexi.c */; };
+ FDA9C8BE0FD5EAD700A6EA6E /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8070FD5D92800A6EA6E /* parse.c */; };
+ FDA9C8BF0FD5EAD700A6EA6E /* pr_comment.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8080FD5D92800A6EA6E /* pr_comment.c */; };
+ FDA9C8C10FD5EAEA00A6EA6E /* indent.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDA9C8000FD5D92800A6EA6E /* indent.1 */; };
+ FDA9C8DF0FD5EBE600A6EA6E /* rpc_clntout.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8180FD5D92800A6EA6E /* rpc_clntout.c */; };
+ FDA9C8E00FD5EBE600A6EA6E /* rpc_cout.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8190FD5D92800A6EA6E /* rpc_cout.c */; };
+ FDA9C8E10FD5EBE600A6EA6E /* rpc_hout.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C81A0FD5D92800A6EA6E /* rpc_hout.c */; };
+ FDA9C8E20FD5EBE600A6EA6E /* rpc_main.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C81B0FD5D92800A6EA6E /* rpc_main.c */; };
+ FDA9C8E30FD5EBE600A6EA6E /* rpc_parse.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C81C0FD5D92800A6EA6E /* rpc_parse.c */; };
+ FDA9C8E40FD5EBE600A6EA6E /* rpc_sample.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C81E0FD5D92800A6EA6E /* rpc_sample.c */; };
+ FDA9C8E50FD5EBE600A6EA6E /* rpc_scan.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C81F0FD5D92800A6EA6E /* rpc_scan.c */; };
+ FDA9C8E60FD5EBE600A6EA6E /* rpc_svcout.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8210FD5D92800A6EA6E /* rpc_svcout.c */; };
+ FDA9C8E70FD5EBE600A6EA6E /* rpc_tblout.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8220FD5D92800A6EA6E /* rpc_tblout.c */; };
+ FDA9C8E80FD5EBE600A6EA6E /* rpc_util.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8230FD5D92800A6EA6E /* rpc_util.c */; };
+ FDA9C8EA0FD5EBF600A6EA6E /* rpcgen.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDA9C8250FD5D92800A6EA6E /* rpcgen.1 */; };
+ FDA9C9010FD5EC4800A6EA6E /* unifdef.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA9C8290FD5D92800A6EA6E /* unifdef.c */; };
+ FDA9C9030FD5EC5F00A6EA6E /* unifdef.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDA9C8280FD5D92800A6EA6E /* unifdef.1 */; };
+ FDA9C9900FD5F10200A6EA6E /* lorder.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDA9C80B0FD5D92800A6EA6E /* lorder.1 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ FDA9C8580FD5E85C00A6EA6E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDA9C7D70FD5D84000A6EA6E /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDA9C8390FD5E7DB00A6EA6E;
+ remoteInfo = asa;
+ };
+ FDA9C85A0FD5E85E00A6EA6E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDA9C7D70FD5D84000A6EA6E /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDA9C8540FD5E85900A6EA6E;
+ remoteInfo = ctags;
+ };
+ FDA9C8B50FD5EAA500A6EA6E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDA9C7D70FD5D84000A6EA6E /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDA9C8B10FD5EAA100A6EA6E;
+ remoteInfo = indent;
+ };
+ FDA9C8D90FD5EBB200A6EA6E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDA9C7D70FD5D84000A6EA6E /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDA9C8D50FD5EBA400A6EA6E;
+ remoteInfo = rpcgen;
+ };
+ FDA9C8FB0FD5EC3300A6EA6E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDA9C7D70FD5D84000A6EA6E /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDA9C8F70FD5EC2A00A6EA6E;
+ remoteInfo = unifdef;
+ };
+ FDA9C9860FD5F06900A6EA6E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDA9C7D70FD5D84000A6EA6E /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDA9C97F0FD5F05400A6EA6E;
+ remoteInfo = lorder;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ FDA9C84F0FD5E82D00A6EA6E /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = "$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+ dstSubfolderSpec = 0;
+ files = (
+ FDA9C84D0FD5E82800A6EA6E /* asa.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDA9C8730FD5E89700A6EA6E /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = "$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+ dstSubfolderSpec = 0;
+ files = (
+ FDA9C86B0FD5E88900A6EA6E /* ctags.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDA9C8CA0FD5EAFC00A6EA6E /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = "$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+ dstSubfolderSpec = 0;
+ files = (
+ FDA9C8C10FD5EAEA00A6EA6E /* indent.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDA9C8F40FD5EC0F00A6EA6E /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = "$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+ dstSubfolderSpec = 0;
+ files = (
+ FDA9C8EA0FD5EBF600A6EA6E /* rpcgen.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDA9C9040FD5EC6800A6EA6E /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = "$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+ dstSubfolderSpec = 0;
+ files = (
+ FDA9C9030FD5EC5F00A6EA6E /* unifdef.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDA9C9A20FD5F12200A6EA6E /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = "$(DT_TOOLCHAIN_DIR)/usr/share/man/man1";
+ dstSubfolderSpec = 0;
+ files = (
+ FDA9C9900FD5F10200A6EA6E /* lorder.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ FDA9C7E30FD5D90F00A6EA6E /* asa.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = asa.1; sourceTree = "<group>"; };
+ FDA9C7E40FD5D90F00A6EA6E /* asa.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = asa.c; sourceTree = "<group>"; };
+ FDA9C7E70FD5D92800A6EA6E /* C.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = C.c; sourceTree = "<group>"; };
+ FDA9C7E80FD5D92800A6EA6E /* ctags.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ctags.1; sourceTree = "<group>"; };
+ FDA9C7E90FD5D92800A6EA6E /* ctags.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ctags.c; sourceTree = "<group>"; };
+ FDA9C7EA0FD5D92800A6EA6E /* ctags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ctags.h; sourceTree = "<group>"; };
+ FDA9C7EB0FD5D92800A6EA6E /* fortran.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = fortran.c; sourceTree = "<group>"; };
+ FDA9C7EC0FD5D92800A6EA6E /* lisp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lisp.c; sourceTree = "<group>"; };
+ FDA9C7EE0FD5D92800A6EA6E /* print.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; };
+ FDA9C7F00FD5D92800A6EA6E /* ctags.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ctags.test; sourceTree = "<group>"; };
+ FDA9C7F10FD5D92800A6EA6E /* tree.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tree.c; sourceTree = "<group>"; };
+ FDA9C7F20FD5D92800A6EA6E /* yacc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = yacc.c; sourceTree = "<group>"; };
+ FDA9C7FF0FD5D92800A6EA6E /* args.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = args.c; sourceTree = "<group>"; };
+ FDA9C8000FD5D92800A6EA6E /* indent.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = indent.1; sourceTree = "<group>"; };
+ FDA9C8010FD5D92800A6EA6E /* indent.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = indent.c; sourceTree = "<group>"; };
+ FDA9C8020FD5D92800A6EA6E /* indent_codes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = indent_codes.h; sourceTree = "<group>"; };
+ FDA9C8030FD5D92800A6EA6E /* indent_globs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = indent_globs.h; sourceTree = "<group>"; };
+ FDA9C8040FD5D92800A6EA6E /* io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = io.c; sourceTree = "<group>"; };
+ FDA9C8050FD5D92800A6EA6E /* lexi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = lexi.c; sourceTree = "<group>"; };
+ FDA9C8070FD5D92800A6EA6E /* parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parse.c; sourceTree = "<group>"; };
+ FDA9C8080FD5D92800A6EA6E /* pr_comment.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pr_comment.c; sourceTree = "<group>"; };
+ FDA9C8090FD5D92800A6EA6E /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ FDA9C80B0FD5D92800A6EA6E /* lorder.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = lorder.1; sourceTree = "<group>"; };
+ FDA9C80C0FD5D92800A6EA6E /* lorder.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = lorder.sh; sourceTree = "<group>"; };
+ FDA9C8180FD5D92800A6EA6E /* rpc_clntout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_clntout.c; sourceTree = "<group>"; };
+ FDA9C8190FD5D92800A6EA6E /* rpc_cout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_cout.c; sourceTree = "<group>"; };
+ FDA9C81A0FD5D92800A6EA6E /* rpc_hout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_hout.c; sourceTree = "<group>"; };
+ FDA9C81B0FD5D92800A6EA6E /* rpc_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_main.c; sourceTree = "<group>"; };
+ FDA9C81C0FD5D92800A6EA6E /* rpc_parse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_parse.c; sourceTree = "<group>"; };
+ FDA9C81D0FD5D92800A6EA6E /* rpc_parse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rpc_parse.h; sourceTree = "<group>"; };
+ FDA9C81E0FD5D92800A6EA6E /* rpc_sample.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_sample.c; sourceTree = "<group>"; };
+ FDA9C81F0FD5D92800A6EA6E /* rpc_scan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_scan.c; sourceTree = "<group>"; };
+ FDA9C8200FD5D92800A6EA6E /* rpc_scan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rpc_scan.h; sourceTree = "<group>"; };
+ FDA9C8210FD5D92800A6EA6E /* rpc_svcout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_svcout.c; sourceTree = "<group>"; };
+ FDA9C8220FD5D92800A6EA6E /* rpc_tblout.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_tblout.c; sourceTree = "<group>"; };
+ FDA9C8230FD5D92800A6EA6E /* rpc_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rpc_util.c; sourceTree = "<group>"; };
+ FDA9C8240FD5D92800A6EA6E /* rpc_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rpc_util.h; sourceTree = "<group>"; };
+ FDA9C8250FD5D92800A6EA6E /* rpcgen.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = rpcgen.1; sourceTree = "<group>"; };
+ FDA9C8280FD5D92800A6EA6E /* unifdef.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = unifdef.1; sourceTree = "<group>"; };
+ FDA9C8290FD5D92800A6EA6E /* unifdef.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unifdef.c; sourceTree = "<group>"; };
+ FDA9C82A0FD5D92800A6EA6E /* unifdefall.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = unifdefall.sh; sourceTree = "<group>"; };
+ FDA9C83A0FD5E7DB00A6EA6E /* asa */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = asa; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDA9C8550FD5E85900A6EA6E /* ctags */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ctags; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDA9C8B20FD5EAA100A6EA6E /* indent */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = indent; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDA9C8D60FD5EBA400A6EA6E /* rpcgen */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rpcgen; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDA9C8F80FD5EC2A00A6EA6E /* unifdef */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unifdef; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FDA9C8380FD5E7DB00A6EA6E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA9C8530FD5E85900A6EA6E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA9C8B00FD5EAA100A6EA6E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA9C8D40FD5EBA400A6EA6E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA9C8F60FD5EC2A00A6EA6E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ FDA9C7D50FD5D84000A6EA6E = {
+ isa = PBXGroup;
+ children = (
+ FDA9C9280FD5ED6700A6EA6E /* Source */,
+ FDA9C83B0FD5E7DB00A6EA6E /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ FDA9C7E20FD5D90F00A6EA6E /* asa */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C7E30FD5D90F00A6EA6E /* asa.1 */,
+ FDA9C7E40FD5D90F00A6EA6E /* asa.c */,
+ );
+ path = asa;
+ sourceTree = "<group>";
+ };
+ FDA9C7E60FD5D92800A6EA6E /* ctags */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C7E70FD5D92800A6EA6E /* C.c */,
+ FDA9C7E90FD5D92800A6EA6E /* ctags.c */,
+ FDA9C7EB0FD5D92800A6EA6E /* fortran.c */,
+ FDA9C7EC0FD5D92800A6EA6E /* lisp.c */,
+ FDA9C7EE0FD5D92800A6EA6E /* print.c */,
+ FDA9C7F10FD5D92800A6EA6E /* tree.c */,
+ FDA9C7F20FD5D92800A6EA6E /* yacc.c */,
+ FDA9C7EA0FD5D92800A6EA6E /* ctags.h */,
+ FDA9C7E80FD5D92800A6EA6E /* ctags.1 */,
+ FDA9C7EF0FD5D92800A6EA6E /* test */,
+ );
+ path = ctags;
+ sourceTree = "<group>";
+ };
+ FDA9C7EF0FD5D92800A6EA6E /* test */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C7F00FD5D92800A6EA6E /* ctags.test */,
+ );
+ path = test;
+ sourceTree = "<group>";
+ };
+ FDA9C7FE0FD5D92800A6EA6E /* indent */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C7FF0FD5D92800A6EA6E /* args.c */,
+ FDA9C8010FD5D92800A6EA6E /* indent.c */,
+ FDA9C8040FD5D92800A6EA6E /* io.c */,
+ FDA9C8050FD5D92800A6EA6E /* lexi.c */,
+ FDA9C8070FD5D92800A6EA6E /* parse.c */,
+ FDA9C8080FD5D92800A6EA6E /* pr_comment.c */,
+ FDA9C8020FD5D92800A6EA6E /* indent_codes.h */,
+ FDA9C8030FD5D92800A6EA6E /* indent_globs.h */,
+ FDA9C8000FD5D92800A6EA6E /* indent.1 */,
+ FDA9C8090FD5D92800A6EA6E /* README */,
+ );
+ path = indent;
+ sourceTree = "<group>";
+ };
+ FDA9C80A0FD5D92800A6EA6E /* lorder */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C80C0FD5D92800A6EA6E /* lorder.sh */,
+ FDA9C80B0FD5D92800A6EA6E /* lorder.1 */,
+ );
+ path = lorder;
+ sourceTree = "<group>";
+ };
+ FDA9C8160FD5D92800A6EA6E /* rpcgen */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C8180FD5D92800A6EA6E /* rpc_clntout.c */,
+ FDA9C8190FD5D92800A6EA6E /* rpc_cout.c */,
+ FDA9C81A0FD5D92800A6EA6E /* rpc_hout.c */,
+ FDA9C81B0FD5D92800A6EA6E /* rpc_main.c */,
+ FDA9C81C0FD5D92800A6EA6E /* rpc_parse.c */,
+ FDA9C81E0FD5D92800A6EA6E /* rpc_sample.c */,
+ FDA9C81F0FD5D92800A6EA6E /* rpc_scan.c */,
+ FDA9C8210FD5D92800A6EA6E /* rpc_svcout.c */,
+ FDA9C8220FD5D92800A6EA6E /* rpc_tblout.c */,
+ FDA9C8230FD5D92800A6EA6E /* rpc_util.c */,
+ FDA9C81D0FD5D92800A6EA6E /* rpc_parse.h */,
+ FDA9C8200FD5D92800A6EA6E /* rpc_scan.h */,
+ FDA9C8240FD5D92800A6EA6E /* rpc_util.h */,
+ FDA9C8250FD5D92800A6EA6E /* rpcgen.1 */,
+ );
+ path = rpcgen;
+ sourceTree = "<group>";
+ };
+ FDA9C8260FD5D92800A6EA6E /* unifdef */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C8290FD5D92800A6EA6E /* unifdef.c */,
+ FDA9C8280FD5D92800A6EA6E /* unifdef.1 */,
+ FDA9C82A0FD5D92800A6EA6E /* unifdefall.sh */,
+ );
+ path = unifdef;
+ sourceTree = "<group>";
+ };
+ FDA9C83B0FD5E7DB00A6EA6E /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C83A0FD5E7DB00A6EA6E /* asa */,
+ FDA9C8550FD5E85900A6EA6E /* ctags */,
+ FDA9C8B20FD5EAA100A6EA6E /* indent */,
+ FDA9C8D60FD5EBA400A6EA6E /* rpcgen */,
+ FDA9C8F80FD5EC2A00A6EA6E /* unifdef */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FDA9C9280FD5ED6700A6EA6E /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ FDA9C7E20FD5D90F00A6EA6E /* asa */,
+ FDA9C7E60FD5D92800A6EA6E /* ctags */,
+ FDA9C7FE0FD5D92800A6EA6E /* indent */,
+ FDA9C80A0FD5D92800A6EA6E /* lorder */,
+ FDA9C8160FD5D92800A6EA6E /* rpcgen */,
+ FDA9C8260FD5D92800A6EA6E /* unifdef */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ FDA9C8390FD5E7DB00A6EA6E /* asa */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDA9C83E0FD5E7DC00A6EA6E /* Build configuration list for PBXNativeTarget "asa" */;
+ buildPhases = (
+ FDA9C8370FD5E7DB00A6EA6E /* Sources */,
+ FDA9C8380FD5E7DB00A6EA6E /* Frameworks */,
+ FDA9C84F0FD5E82D00A6EA6E /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = asa;
+ productName = asa;
+ productReference = FDA9C83A0FD5E7DB00A6EA6E /* asa */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDA9C8540FD5E85900A6EA6E /* ctags */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDA9C85D0FD5E86100A6EA6E /* Build configuration list for PBXNativeTarget "ctags" */;
+ buildPhases = (
+ FDA9C8520FD5E85900A6EA6E /* Sources */,
+ FDA9C8530FD5E85900A6EA6E /* Frameworks */,
+ FDA9C8730FD5E89700A6EA6E /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ctags;
+ productName = ctags;
+ productReference = FDA9C8550FD5E85900A6EA6E /* ctags */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDA9C8B10FD5EAA100A6EA6E /* indent */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDA9C8B90FD5EAAD00A6EA6E /* Build configuration list for PBXNativeTarget "indent" */;
+ buildPhases = (
+ FDA9C8AF0FD5EAA100A6EA6E /* Sources */,
+ FDA9C8B00FD5EAA100A6EA6E /* Frameworks */,
+ FDA9C8CA0FD5EAFC00A6EA6E /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = indent;
+ productName = indent;
+ productReference = FDA9C8B20FD5EAA100A6EA6E /* indent */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDA9C8D50FD5EBA400A6EA6E /* rpcgen */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDA9C8DE0FD5EBB300A6EA6E /* Build configuration list for PBXNativeTarget "rpcgen" */;
+ buildPhases = (
+ FDA9C8D30FD5EBA400A6EA6E /* Sources */,
+ FDA9C8D40FD5EBA400A6EA6E /* Frameworks */,
+ FDA9C8F40FD5EC0F00A6EA6E /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rpcgen;
+ productName = rpcgen;
+ productReference = FDA9C8D60FD5EBA400A6EA6E /* rpcgen */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDA9C8F70FD5EC2A00A6EA6E /* unifdef */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDA9C9000FD5EC3B00A6EA6E /* Build configuration list for PBXNativeTarget "unifdef" */;
+ buildPhases = (
+ FDA9C8F50FD5EC2A00A6EA6E /* Sources */,
+ FDA9C8F60FD5EC2A00A6EA6E /* Frameworks */,
+ FDA9C9040FD5EC6800A6EA6E /* Install man1 */,
+ FDA9C9080FD5EC7500A6EA6E /* Install unifdefall */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = unifdef;
+ productName = unifdef;
+ productReference = FDA9C8F80FD5EC2A00A6EA6E /* unifdef */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FDA9C7D70FD5D84000A6EA6E /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ };
+ buildConfigurationList = FDA9C7DA0FD5D84000A6EA6E /* Build configuration list for PBXProject "developer_cmds" */;
+ compatibilityVersion = "Xcode 2.4";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = FDA9C7D50FD5D84000A6EA6E;
+ productRefGroup = FDA9C83B0FD5E7DB00A6EA6E /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FDA9C8500FD5E85100A6EA6E /* default */,
+ FDA9C8390FD5E7DB00A6EA6E /* asa */,
+ FDA9C8540FD5E85900A6EA6E /* ctags */,
+ FDA9C8B10FD5EAA100A6EA6E /* indent */,
+ FDA9C97F0FD5F05400A6EA6E /* lorder */,
+ FDA9C8D50FD5EBA400A6EA6E /* rpcgen */,
+ FDA9C8F70FD5EC2A00A6EA6E /* unifdef */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FDA9C9080FD5EC7500A6EA6E /* Install unifdefall */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Install unifdefall";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-unifdefall.sh";
+ showEnvVarsInLog = 0;
+ };
+ FDA9C97E0FD5F05400A6EA6E /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-lorder.sh";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FDA9C8370FD5E7DB00A6EA6E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDA9C83F0FD5E7E300A6EA6E /* asa.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA9C8520FD5E85900A6EA6E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDA9C85F0FD5E87200A6EA6E /* C.c in Sources */,
+ FDA9C8600FD5E87200A6EA6E /* ctags.c in Sources */,
+ FDA9C8610FD5E87200A6EA6E /* fortran.c in Sources */,
+ FDA9C8620FD5E87200A6EA6E /* lisp.c in Sources */,
+ FDA9C8630FD5E87200A6EA6E /* print.c in Sources */,
+ FDA9C8640FD5E87200A6EA6E /* tree.c in Sources */,
+ FDA9C8650FD5E87200A6EA6E /* yacc.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA9C8AF0FD5EAA100A6EA6E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDA9C8BA0FD5EAD700A6EA6E /* args.c in Sources */,
+ FDA9C8BB0FD5EAD700A6EA6E /* indent.c in Sources */,
+ FDA9C8BC0FD5EAD700A6EA6E /* io.c in Sources */,
+ FDA9C8BD0FD5EAD700A6EA6E /* lexi.c in Sources */,
+ FDA9C8BE0FD5EAD700A6EA6E /* parse.c in Sources */,
+ FDA9C8BF0FD5EAD700A6EA6E /* pr_comment.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA9C8D30FD5EBA400A6EA6E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDA9C8DF0FD5EBE600A6EA6E /* rpc_clntout.c in Sources */,
+ FDA9C8E00FD5EBE600A6EA6E /* rpc_cout.c in Sources */,
+ FDA9C8E10FD5EBE600A6EA6E /* rpc_hout.c in Sources */,
+ FDA9C8E20FD5EBE600A6EA6E /* rpc_main.c in Sources */,
+ FDA9C8E30FD5EBE600A6EA6E /* rpc_parse.c in Sources */,
+ FDA9C8E40FD5EBE600A6EA6E /* rpc_sample.c in Sources */,
+ FDA9C8E50FD5EBE600A6EA6E /* rpc_scan.c in Sources */,
+ FDA9C8E60FD5EBE600A6EA6E /* rpc_svcout.c in Sources */,
+ FDA9C8E70FD5EBE600A6EA6E /* rpc_tblout.c in Sources */,
+ FDA9C8E80FD5EBE600A6EA6E /* rpc_util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA9C8F50FD5EC2A00A6EA6E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDA9C9010FD5EC4800A6EA6E /* unifdef.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ FDA9C8590FD5E85C00A6EA6E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDA9C8390FD5E7DB00A6EA6E /* asa */;
+ targetProxy = FDA9C8580FD5E85C00A6EA6E /* PBXContainerItemProxy */;
+ };
+ FDA9C85B0FD5E85E00A6EA6E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDA9C8540FD5E85900A6EA6E /* ctags */;
+ targetProxy = FDA9C85A0FD5E85E00A6EA6E /* PBXContainerItemProxy */;
+ };
+ FDA9C8B60FD5EAA500A6EA6E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDA9C8B10FD5EAA100A6EA6E /* indent */;
+ targetProxy = FDA9C8B50FD5EAA500A6EA6E /* PBXContainerItemProxy */;
+ };
+ FDA9C8DA0FD5EBB200A6EA6E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDA9C8D50FD5EBA400A6EA6E /* rpcgen */;
+ targetProxy = FDA9C8D90FD5EBB200A6EA6E /* PBXContainerItemProxy */;
+ };
+ FDA9C8FC0FD5EC3300A6EA6E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDA9C8F70FD5EC2A00A6EA6E /* unifdef */;
+ targetProxy = FDA9C8FB0FD5EC3300A6EA6E /* PBXContainerItemProxy */;
+ };
+ FDA9C9870FD5F06900A6EA6E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDA9C97F0FD5F05400A6EA6E /* lorder */;
+ targetProxy = FDA9C9860FD5F06900A6EA6E /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ FDA9C7D90FD5D84000A6EA6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ INSTALL_MODE_FLAG = "ugo-w,a+rX";
+ PREBINDING = NO;
+ USE_HEADERMAP = NO;
+ VERSIONING_SYSTEM = "apple-generic";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ FDA9C83D0FD5E7DB00A6EA6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = "$(DT_TOOLCHAIN_DIR)/usr/bin";
+ PRODUCT_NAME = asa;
+ };
+ name = Release;
+ };
+ FDA9C8510FD5E85100A6EA6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = default;
+ };
+ name = Release;
+ };
+ FDA9C8570FD5E85900A6EA6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = "$(DT_TOOLCHAIN_DIR)/usr/bin";
+ PRODUCT_NAME = ctags;
+ };
+ name = Release;
+ };
+ FDA9C8B40FD5EAA200A6EA6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = "$(DT_TOOLCHAIN_DIR)/usr/bin";
+ PRODUCT_NAME = indent;
+ };
+ name = Release;
+ };
+ FDA9C8D80FD5EBA400A6EA6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = "$(DT_TOOLCHAIN_DIR)/usr/bin";
+ PRODUCT_NAME = rpcgen;
+ };
+ name = Release;
+ };
+ FDA9C8FA0FD5EC2A00A6EA6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = "$(DT_TOOLCHAIN_DIR)/usr/bin";
+ PRODUCT_NAME = unifdef;
+ };
+ name = Release;
+ };
+ FDA9C9800FD5F05400A6EA6E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = lorder;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ FDA9C7DA0FD5D84000A6EA6E /* Build configuration list for PBXProject "developer_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA9C7D90FD5D84000A6EA6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDA9C83E0FD5E7DC00A6EA6E /* Build configuration list for PBXNativeTarget "asa" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA9C83D0FD5E7DB00A6EA6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDA9C85D0FD5E86100A6EA6E /* Build configuration list for PBXNativeTarget "ctags" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA9C8570FD5E85900A6EA6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDA9C85E0FD5E86100A6EA6E /* Build configuration list for PBXAggregateTarget "default" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA9C8510FD5E85100A6EA6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDA9C8B90FD5EAAD00A6EA6E /* Build configuration list for PBXNativeTarget "indent" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA9C8B40FD5EAA200A6EA6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDA9C8DE0FD5EBB300A6EA6E /* Build configuration list for PBXNativeTarget "rpcgen" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA9C8D80FD5EBA400A6EA6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDA9C9000FD5EC3B00A6EA6E /* Build configuration list for PBXNativeTarget "unifdef" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA9C8FA0FD5EC2A00A6EA6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDA9C98B0FD5F08700A6EA6E /* Build configuration list for PBXAggregateTarget "lorder" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA9C9800FD5F05400A6EA6E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FDA9C7D70FD5D84000A6EA6E /* Project object */;
+}
diff --git a/developer_cmds/developer_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/developer_cmds/developer_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/developer_cmds/developer_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/developer_cmds/indent/args.c b/developer_cmds/indent/args.c
new file mode 100644
index 0000000..507be03
--- /dev/null
+++ b/developer_cmds/indent/args.c
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)args.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/indent/args.c,v 1.16 2010/03/31 17:05:30 avg Exp $");
+
+/*
+ * Argument scanning and profile reading code. Default parameters are set
+ * here as well.
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "indent_globs.h"
+#include "indent.h"
+
+/* profile types */
+#define PRO_SPECIAL 1 /* special case */
+#define PRO_BOOL 2 /* boolean */
+#define PRO_INT 3 /* integer */
+#define PRO_FONT 4 /* troff font */
+
+/* profile specials for booleans */
+#define ON 1 /* turn it on */
+#define OFF 0 /* turn it off */
+
+/* profile specials for specials */
+#define IGN 1 /* ignore it */
+#define CLI 2 /* case label indent (float) */
+#define STDIN 3 /* use stdin */
+#define KEY 4 /* type (keyword) */
+
+static void scan_profile(FILE *);
+
+const char *option_source = "?";
+
+/*
+ * N.B.: because of the way the table here is scanned, options whose names are
+ * substrings of other options must occur later; that is, with -lp vs -l, -lp
+ * must be first. Also, while (most) booleans occur more than once, the last
+ * default value is the one actually assigned.
+ */
+struct pro {
+ const char *p_name; /* name, e.g. -bl, -cli */
+ int p_type; /* type (int, bool, special) */
+ int p_default; /* the default value (if int) */
+ int p_special; /* depends on type */
+ int *p_obj; /* the associated variable */
+} pro[] = {
+
+ {"T", PRO_SPECIAL, 0, KEY, 0},
+ {"bacc", PRO_BOOL, false, ON, &blanklines_around_conditional_compilation},
+ {"badp", PRO_BOOL, false, ON, &blanklines_after_declarations_at_proctop},
+ {"bad", PRO_BOOL, false, ON, &blanklines_after_declarations},
+ {"bap", PRO_BOOL, false, ON, &blanklines_after_procs},
+ {"bbb", PRO_BOOL, false, ON, &blanklines_before_blockcomments},
+ {"bc", PRO_BOOL, true, OFF, &ps.leave_comma},
+ {"bl", PRO_BOOL, true, OFF, &btype_2},
+ {"br", PRO_BOOL, true, ON, &btype_2},
+ {"bs", PRO_BOOL, false, ON, &Bill_Shannon},
+ {"cdb", PRO_BOOL, true, ON, &comment_delimiter_on_blankline},
+ {"cd", PRO_INT, 0, 0, &ps.decl_com_ind},
+ {"ce", PRO_BOOL, true, ON, &cuddle_else},
+ {"ci", PRO_INT, 0, 0, &continuation_indent},
+ {"cli", PRO_SPECIAL, 0, CLI, 0},
+ {"c", PRO_INT, 33, 0, &ps.com_ind},
+ {"di", PRO_INT, 16, 0, &ps.decl_indent},
+ {"dj", PRO_BOOL, false, ON, &ps.ljust_decl},
+ {"d", PRO_INT, 0, 0, &ps.unindent_displace},
+ {"eei", PRO_BOOL, false, ON, &extra_expression_indent},
+ {"ei", PRO_BOOL, true, ON, &ps.else_if},
+ {"fbc", PRO_FONT, 0, 0, (int *) &blkcomf},
+ {"fbs", PRO_BOOL, true, ON, &function_brace_split},
+ {"fbx", PRO_FONT, 0, 0, (int *) &boxcomf},
+ {"fb", PRO_FONT, 0, 0, (int *) &bodyf},
+ {"fc1", PRO_BOOL, true, ON, &format_col1_comments},
+ {"fcb", PRO_BOOL, true, ON, &format_block_comments},
+ {"fc", PRO_FONT, 0, 0, (int *) &scomf},
+ {"fk", PRO_FONT, 0, 0, (int *) &keywordf},
+ {"fs", PRO_FONT, 0, 0, (int *) &stringf},
+ {"ip", PRO_BOOL, true, ON, &ps.indent_parameters},
+ {"i", PRO_INT, 8, 0, &ps.ind_size},
+ {"lc", PRO_INT, 0, 0, &block_comment_max_col},
+ {"ldi", PRO_INT, -1, 0, &ps.local_decl_indent},
+ {"lp", PRO_BOOL, true, ON, &lineup_to_parens},
+ {"l", PRO_INT, 78, 0, &max_col},
+ {"nbacc", PRO_BOOL, false, OFF, &blanklines_around_conditional_compilation},
+ {"nbadp", PRO_BOOL, false, OFF, &blanklines_after_declarations_at_proctop},
+ {"nbad", PRO_BOOL, false, OFF, &blanklines_after_declarations},
+ {"nbap", PRO_BOOL, false, OFF, &blanklines_after_procs},
+ {"nbbb", PRO_BOOL, false, OFF, &blanklines_before_blockcomments},
+ {"nbc", PRO_BOOL, true, ON, &ps.leave_comma},
+ {"nbs", PRO_BOOL, false, OFF, &Bill_Shannon},
+ {"ncdb", PRO_BOOL, true, OFF, &comment_delimiter_on_blankline},
+ {"nce", PRO_BOOL, true, OFF, &cuddle_else},
+ {"ndj", PRO_BOOL, false, OFF, &ps.ljust_decl},
+ {"neei", PRO_BOOL, false, OFF, &extra_expression_indent},
+ {"nei", PRO_BOOL, true, OFF, &ps.else_if},
+ {"nfbs", PRO_BOOL, true, OFF, &function_brace_split},
+ {"nfc1", PRO_BOOL, true, OFF, &format_col1_comments},
+ {"nfcb", PRO_BOOL, true, OFF, &format_block_comments},
+ {"nip", PRO_BOOL, true, OFF, &ps.indent_parameters},
+ {"nlp", PRO_BOOL, true, OFF, &lineup_to_parens},
+ {"npcs", PRO_BOOL, false, OFF, &proc_calls_space},
+ {"npro", PRO_SPECIAL, 0, IGN, 0},
+ {"npsl", PRO_BOOL, true, OFF, &procnames_start_line},
+ {"nps", PRO_BOOL, false, OFF, &pointer_as_binop},
+ {"nsc", PRO_BOOL, true, OFF, &star_comment_cont},
+ {"nsob", PRO_BOOL, false, OFF, &swallow_optional_blanklines},
+ {"nut", PRO_BOOL, true, OFF, &use_tabs},
+ {"nv", PRO_BOOL, false, OFF, &verbose},
+ {"pcs", PRO_BOOL, false, ON, &proc_calls_space},
+ {"psl", PRO_BOOL, true, ON, &procnames_start_line},
+ {"ps", PRO_BOOL, false, ON, &pointer_as_binop},
+ {"sc", PRO_BOOL, true, ON, &star_comment_cont},
+ {"sob", PRO_BOOL, false, ON, &swallow_optional_blanklines},
+ {"st", PRO_SPECIAL, 0, STDIN, 0},
+ {"ta", PRO_BOOL, false, ON, &auto_typedefs},
+ {"troff", PRO_BOOL, false, ON, &troff},
+ {"ut", PRO_BOOL, true, ON, &use_tabs},
+ {"v", PRO_BOOL, false, ON, &verbose},
+ /* whew! */
+ {0, 0, 0, 0, 0}
+};
+
+/*
+ * set_profile reads $HOME/.indent.pro and ./.indent.pro and handles arguments
+ * given in these files.
+ */
+void
+set_profile(void)
+{
+ FILE *f;
+ char fname[PATH_MAX];
+ static char prof[] = ".indent.pro";
+
+ snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), prof);
+ if ((f = fopen(option_source = fname, "r")) != NULL) {
+ scan_profile(f);
+ (void) fclose(f);
+ }
+ if ((f = fopen(option_source = prof, "r")) != NULL) {
+ scan_profile(f);
+ (void) fclose(f);
+ }
+ option_source = "Command line";
+}
+
+static void
+scan_profile(FILE *f)
+{
+ int comment, i;
+ char *p;
+ char buf[BUFSIZ];
+
+ while (1) {
+ p = buf;
+ comment = 0;
+ while ((i = getc(f)) != EOF) {
+ if (i == '*' && !comment && p > buf && p[-1] == '/') {
+ comment = p - buf;
+ *p++ = i;
+ } else if (i == '/' && comment && p > buf && p[-1] == '*') {
+ p = buf + comment - 1;
+ comment = 0;
+ } else if (isspace(i)) {
+ if (p > buf && !comment)
+ break;
+ } else {
+ *p++ = i;
+ }
+ }
+ if (p != buf) {
+ *p++ = 0;
+ if (verbose)
+ printf("profile: %s\n", buf);
+ set_option(buf);
+ }
+ else if (i == EOF)
+ return;
+ }
+}
+
+const char *param_start;
+
+static int
+eqin(const char *s1, const char *s2)
+{
+ while (*s1) {
+ if (*s1++ != *s2++)
+ return (false);
+ }
+ param_start = s2;
+ return (true);
+}
+
+/*
+ * Set the defaults.
+ */
+void
+set_defaults(void)
+{
+ struct pro *p;
+
+ /*
+ * Because ps.case_indent is a float, we can't initialize it from the
+ * table:
+ */
+ ps.case_indent = 0.0; /* -cli0.0 */
+ for (p = pro; p->p_name; p++)
+ if (p->p_type != PRO_SPECIAL && p->p_type != PRO_FONT)
+ *p->p_obj = p->p_default;
+}
+
+void
+set_option(char *arg)
+{
+ struct pro *p;
+
+ arg++; /* ignore leading "-" */
+ for (p = pro; p->p_name; p++)
+ if (*p->p_name == *arg && eqin(p->p_name, arg))
+ goto found;
+ errx(1, "%s: unknown parameter \"%s\"", option_source, arg - 1);
+found:
+ switch (p->p_type) {
+
+ case PRO_SPECIAL:
+ switch (p->p_special) {
+
+ case IGN:
+ break;
+
+ case CLI:
+ if (*param_start == 0)
+ goto need_param;
+ ps.case_indent = atof(param_start);
+ break;
+
+ case STDIN:
+ if (input == 0)
+ input = stdin;
+ if (output == 0)
+ output = stdout;
+ break;
+
+ case KEY:
+ if (*param_start == 0)
+ goto need_param;
+ {
+ char *str = strdup(param_start);
+ if (str == NULL)
+ err(1, NULL);
+ addkey(str, 4);
+ }
+ break;
+
+ default:
+ errx(1, "set_option: internal error: p_special %d", p->p_special);
+ }
+ break;
+
+ case PRO_BOOL:
+ if (p->p_special == OFF)
+ *p->p_obj = false;
+ else
+ *p->p_obj = true;
+ break;
+
+ case PRO_INT:
+ if (!isdigit(*param_start)) {
+ need_param:
+ errx(1, "%s: ``%s'' requires a parameter", option_source, arg - 1);
+ }
+ *p->p_obj = atoi(param_start);
+ break;
+
+ case PRO_FONT:
+ parsefont((struct fstate *) p->p_obj, param_start);
+ break;
+
+ default:
+ errx(1, "set_option: internal error: p_type %d", p->p_type);
+ }
+}
diff --git a/developer_cmds/indent/indent.1 b/developer_cmds/indent/indent.1
new file mode 100644
index 0000000..f35ea95
--- /dev/null
+++ b/developer_cmds/indent/indent.1
@@ -0,0 +1,559 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 1976 Board of Trustees of the University of Illinois.
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)indent.1 8.1 (Berkeley) 7/1/93
+.\" $FreeBSD: src/usr.bin/indent/indent.1,v 1.28 2010/03/31 17:05:30 avg Exp $
+.\"
+.Dd June 29, 2004
+.Dt INDENT 1
+.Os
+.Sh NAME
+.Nm indent
+.Nd indent and format C program source
+.Sh SYNOPSIS
+.Nm
+.Op Ar input_file Op Ar output_file
+.Op Fl bacc | Fl nbacc
+.Op Fl bad | Fl nbad
+.Op Fl bap | Fl nbap
+.Bk -words
+.Op Fl bbb | Fl nbbb
+.Ek
+.Op Fl \&bc | Fl nbc
+.Op Fl \&bl
+.Op Fl \&br
+.Op Fl c Ns Ar n
+.Op Fl \&cd Ns Ar n
+.Bk -words
+.Op Fl cdb | Fl ncdb
+.Ek
+.Op Fl \&ce | Fl nce
+.Op Fl \&ci Ns Ar n
+.Op Fl cli Ns Ar n
+.Op Fl d Ns Ar n
+.Op Fl \&di Ns Ar n
+.Bk -words
+.Op Fl ei | Fl ei
+.Op Fl eei | Fl eei
+.Op Fl fbs | Fl nfbs
+.Op Fl fc1 | Fl nfc1
+.Op Fl fcb | Fl nfcb
+.Ek
+.Op Fl i Ns Ar n
+.Op Fl \&ip | Fl nip
+.Op Fl l Ns Ar n
+.Op Fl \&lc Ns Ar n
+.Op Fl \&ldi Ns Ar n
+.Op Fl \&lp | Fl nlp
+.Op Fl npro
+.Op Fl pcs | Fl npcs
+.Op Fl psl | Fl npsl
+.Op Fl \&sc | Fl nsc
+.Bk -words
+.Op Fl sob | Fl nsob
+.Ek
+.Op Fl \&st
+.Op Fl \&ta
+.Op Fl troff
+.Op Fl ut | Fl nut
+.Op Fl v | Fl \&nv
+.Sh DESCRIPTION
+.Nm
+is a
+.Em C
+program formatter.
+It reformats the
+.Em C
+program in the
+.Ar input_file
+according to the switches.
+The switches which can be
+specified are described below.
+They may appear before or after the file
+names.
+.Pp
+.Sy NOTE :
+If you only specify an
+.Ar input_file ,
+the formatting is
+done `in-place', that is, the formatted file is written back into
+.Ar input_file
+and a backup copy of
+.Ar input_file
+is written in the current directory.
+If
+.Ar input_file
+is named
+.Sq Pa /blah/blah/file ,
+the backup file is named
+.Sq Pa file.BAK .
+.Pp
+If
+.Ar output_file
+is specified,
+.Nm
+checks to make sure that it is different from
+.Ar input_file .
+.Pp
+The options listed below control the formatting style imposed by
+.Nm .
+.Bl -tag -width Op
+.It Fl bacc , nbacc
+If
+.Fl bacc
+is specified, a blank line is forced around every conditional
+compilation block.
+For example, in front of every #ifdef and after every #endif.
+Other blank lines surrounding such blocks will be swallowed.
+The default is
+.Fl nbacc .
+.It Fl bad , nbad
+If
+.Fl bad
+is specified, a blank line is forced after every block of
+declarations.
+The default is
+.Fl nbad .
+.It Fl bap , nbap
+If
+.Fl bap
+is specified, a blank line is forced after every procedure body.
+The default is
+.Fl nbap .
+.It Fl bbb , nbbb
+If
+.Fl bbb
+is specified, a blank line is forced before every block comment.
+The default is
+.Fl nbbb .
+.It Fl \&bc , nbc
+If
+.Fl \&bc
+is specified, then a newline is forced after each comma in a declaration.
+.Fl nbc
+turns off this option.
+The default is
+.Fl \&nbc .
+.It Fl \&br , \&bl
+Specifying
+.Fl \&bl
+lines-up compound statements like this:
+.Bd -literal -offset indent
+if (...)
+{
+ code
+}
+.Ed
+.Pp
+Specifying
+.Fl \&br
+(the default) makes them look like this:
+.Bd -literal -offset indent
+if (...) {
+ code
+}
+.Ed
+.Pp
+.It Fl c Ns Ar n
+The column in which comments on code start.
+The default is 33.
+.It Fl cd Ns Ar n
+The column in which comments on declarations start.
+The default
+is for these comments to start in the same column as those on code.
+.It Fl cdb , ncdb
+Enables (disables) the placement of comment delimiters on blank lines.
+With
+this option enabled, comments look like this:
+.Bd -literal -offset indent
+ /*
+ * this is a comment
+ */
+.Ed
+.Pp
+Rather than like this:
+.Bd -literal -offset indent
+ /* this is a comment */
+.Ed
+.Pp
+This only affects block comments, not comments to the right of
+code.
+The default is
+.Fl cdb .
+.It Fl ce , nce
+Enables (disables) forcing of `else's to cuddle up to the immediately preceding
+`}'.
+The default is
+.Fl \&ce .
+.It Fl \&ci Ns Ar n
+Sets the continuation indent to be
+.Ar n .
+Continuation
+lines will be indented that far from the beginning of the first line of the
+statement.
+Parenthesized expressions have extra indentation added to
+indicate the nesting, unless
+.Fl \&lp
+is in effect
+or the continuation indent is exactly half of the main indent.
+.Fl \&ci
+defaults to the same value as
+.Fl i .
+.It Fl cli Ns Ar n
+Causes case labels to be indented
+.Ar n
+tab stops to the right of the containing
+.Ic switch
+statement.
+.Fl cli0.5
+causes case labels to be indented half a tab stop.
+The
+default is
+.Fl cli0 .
+.It Fl d Ns Ar n
+Controls the placement of comments which are not to the
+right of code.
+For example,
+.Fl \&d\&1
+means that such comments are placed one indentation level to the
+left of code.
+Specifying the default
+.Fl \&d\&0
+lines-up these comments with the code.
+See the section on comment
+indentation below.
+.It Fl \&di Ns Ar n
+Specifies the indentation, in character positions,
+of global variable names and all struct/union member names
+relative to the beginning of their type declaration.
+The default is
+.Fl di16 .
+.It Fl dj , ndj
+.Fl \&dj
+left justifies declarations.
+.Fl ndj
+indents declarations the same as code.
+The default is
+.Fl ndj .
+.It Fl \&ei , nei
+Enables (disables) special
+.Ic else-if
+processing.
+If it is enabled, an
+.Ic if
+following an
+.Ic else
+will have the same indentation as the preceding
+.Ic \&if
+statement.
+The default is
+.Fl ei .
+.It Fl eei , neei
+Enables (disables) extra indentation on continuation lines of
+the expression part of
+.Ic if
+and
+.Ic while
+statements.
+These continuation lines will be indented one extra level.
+The default is
+.Fl neei .
+.It Fl fbs , nfbs
+Enables (disables) splitting the function declaration and opening brace
+across two lines.
+The default is
+.Fl fbs .
+.It Fl fc1 , nfc1
+Enables (disables) the formatting of comments that start in column 1.
+Often, comments whose leading `/' is in column 1 have been carefully
+hand formatted by the programmer.
+In such cases,
+.Fl nfc1
+should be
+used.
+The default is
+.Fl fc1 .
+.It Fl fcb , nfcb
+Enables (disables) the formatting of block comments (ones that begin
+with `/*\\n').
+Often, block comments have been not so carefully hand formatted by the
+programmer, but reformatting that would just change the line breaks is not
+wanted.
+In such cases,
+.Fl nfcb
+should be used.
+Block comments are then handled like box comments.
+The default is
+.Fl fcb .
+.It Fl i Ns Ar n
+The number of spaces for one indentation level.
+The default is 8.
+.It Fl \&ip , nip
+Enables (disables) the indentation of parameter declarations from the left
+margin.
+The default is
+.Fl \&ip .
+.It Fl l Ns Ar n
+Maximum length of an output line.
+The default is 78.
+.It Fl \&ldi Ns Ar n
+Specifies the indentation, in character positions,
+of local variable names
+relative to the beginning of their type declaration.
+The default is for local variable names to be indented
+by the same amount as global ones.
+.It Fl \&lp , nlp
+Lines-up code surrounded by parenthesis in continuation lines.
+If a line
+has a left paren which is not closed on that line, then continuation lines
+will be lined up to start at the character position just after the left
+paren.
+For example, here is how a piece of continued code looks with
+.Fl nlp
+in effect:
+.Bd -literal -offset indent
+p1 = first_procedure(second_procedure(p2, p3),
+\ \ third_procedure(p4, p5));
+.Ed
+.Pp
+With
+.Fl lp
+in effect (the default) the code looks somewhat clearer:
+.Bd -literal -offset indent
+p1\ =\ first_procedure(second_procedure(p2,\ p3),
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4,\ p5));
+.Ed
+.Pp
+Inserting two more newlines we get:
+.Bd -literal -offset indent
+p1\ =\ first_procedure(second_procedure(p2,
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p3),
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ third_procedure(p4,
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ p5));
+.Ed
+.It Fl npro
+Causes the profile files,
+.Sq Pa ./.indent.pro
+and
+.Sq Pa ~/.indent.pro ,
+to be ignored.
+.It Fl pcs , npcs
+If true
+.Pq Fl pcs
+all procedure calls will have a space inserted between
+the name and the `('.
+The default is
+.Fl npcs .
+.It Fl psl , npsl
+If true
+.Pq Fl psl
+the names of procedures being defined are placed in
+column 1 \- their types, if any, will be left on the previous lines.
+The
+default is
+.Fl psl .
+.It Fl \&sc , nsc
+Enables (disables) the placement of asterisks (`*'s) at the left edge of all
+comments.
+The default is
+.Fl sc .
+.It Fl sob , nsob
+If
+.Fl sob
+is specified, indent will swallow optional blank lines.
+You can use this to
+get rid of blank lines after declarations.
+The default is
+.Fl nsob .
+.It Fl \&st
+Causes
+.Nm
+to take its input from stdin and put its output to stdout.
+.It Fl ta
+Automatically add all identifiers ending in "_t" to the list
+of type keywords.
+.It Fl T Ns Ar typename
+Adds
+.Ar typename
+to the list of type keywords.
+Names accumulate:
+.Fl T
+can be specified more than once.
+You need to specify all the typenames that
+appear in your program that are defined by
+.Ic typedef
+\- nothing will be
+harmed if you miss a few, but the program will not be formatted as nicely as
+it should.
+This sounds like a painful thing to have to do, but it is really
+a symptom of a problem in C:
+.Ic typedef
+causes a syntactic change in the
+language and
+.Nm
+cannot find all
+instances of
+.Ic typedef .
+.It Fl troff
+Causes
+.Nm
+to format the program for processing by
+.Xr troff 1 .
+.\" It will produce a fancy
+.\" listing in much the same spirit as
+.\" .Xr vgrind 1 .
+If the output file is not specified, the default is standard output,
+rather than formatting in place.
+.It Fl ut , nut
+Enables (disables) the use of tab characters in the output.
+Tabs are assumed to be aligned on columns divisible by 8.
+The default is
+.Fl ut .
+.It Fl v , \&nv
+.Fl v
+turns on `verbose' mode;
+.Fl \&nv
+turns it off.
+When in verbose mode,
+.Nm
+reports when it splits one line of input into two or more lines of output,
+and gives some size statistics at completion.
+The default is
+.Fl \&nv .
+.El
+.Pp
+You may set up your own `profile' of defaults to
+.Nm
+by creating a file called
+.Pa .indent.pro
+in your login directory and/or the current directory and including
+whatever switches you like.
+A `.indent.pro' in the current directory takes
+precedence over the one in your login directory.
+If
+.Nm
+is run and a profile file exists, then it is read to set up the program's
+defaults.
+Switches on the command line, though, always override profile
+switches.
+The switches should be separated by spaces, tabs or newlines.
+.Pp
+.Ss Comments
+.Sq Em Box
+.Em comments .
+.Nm
+assumes that any comment with a dash or star immediately after the start of
+comment (that is, `/*\-' or `/**') is a comment surrounded by a box of stars.
+Each line of such a comment is left unchanged, except that its indentation
+may be adjusted to account for the change in indentation of the first line
+of the comment.
+.Pp
+.Em Straight text .
+All other comments are treated as straight text.
+.Nm
+fits as many words (separated by blanks, tabs, or newlines) on a
+line as possible.
+Blank lines break paragraphs.
+.Pp
+.Ss Comment indentation
+If a comment is on a line with code it is started in the `comment column',
+which is set by the
+.Fl c Ns Ns Ar n
+command line parameter.
+Otherwise, the comment is started at
+.Ar n
+indentation levels less than where code is currently being placed, where
+.Ar n
+is specified by the
+.Fl d Ns Ns Ar n
+command line parameter.
+If the code on a line extends past the comment
+column, the comment starts further to the right, and the right margin may be
+automatically extended in extreme cases.
+.Pp
+.Ss Preprocessor lines
+In general,
+.Nm
+leaves preprocessor lines alone.
+The only
+reformatting that it will do is to straighten up trailing comments.
+It
+leaves embedded comments alone.
+Conditional compilation
+.Pq Ic #ifdef...#endif
+is recognized and
+.Nm
+attempts to correctly
+compensate for the syntactic peculiarities introduced.
+.Pp
+.Ss C syntax
+.Nm
+understands a substantial amount about the syntax of C, but it
+has a `forgiving' parser.
+It attempts to cope with the usual sorts of
+incomplete and misformed syntax.
+In particular, the use of macros like:
+.Pp
+.Dl #define forever for(;;)
+.Pp
+is handled properly.
+.Sh ENVIRONMENT
+.Nm
+uses the
+.Ev HOME
+environment variable.
+.Sh FILES
+.Bl -tag -width "./.indent.pro" -compact
+.It Pa ./.indent.pro
+profile file
+.It Pa ~/.indent.pro
+profile file
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Sh BUGS
+.Nm
+has even more switches than
+.Xr ls 1 .
+.Pp
+A common mistake that often causes grief is typing:
+.Pp
+.Dl indent *.c
+.Pp
+to the shell in an attempt to indent all the
+.Tn C
+programs in a directory.
+This is probably a bug, not a feature.
diff --git a/developer_cmds/indent/indent.c b/developer_cmds/indent/indent.c
new file mode 100644
index 0000000..b88118e
--- /dev/null
+++ b/developer_cmds/indent/indent.c
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1976 Board of Trustees of the University of Illinois.
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1985 Sun Microsystems, Inc.\n\
+@(#) Copyright (c) 1976 Board of Trustees of the University of Illinois.\n\
+@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)indent.c 5.17 (Berkeley) 6/7/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/indent/indent.c,v 1.28 2011/12/30 11:02:40 uqs Exp $");
+
+#include <sys/param.h>
+#include <err.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "indent_globs.h"
+#include "indent_codes.h"
+#include "indent.h"
+
+static void bakcopy(void);
+
+const char *in_name = "Standard Input"; /* will always point to name of input
+ * file */
+const char *out_name = "Standard Output"; /* will always point to name
+ * of output file */
+char bakfile[MAXPATHLEN] = "";
+
+int
+main(int argc, char **argv)
+{
+
+ int dec_ind; /* current indentation for declarations */
+ int di_stack[20]; /* a stack of structure indentation levels */
+ int flushed_nl; /* used when buffering up comments to remember
+ * that a newline was passed over */
+ int force_nl; /* when true, code must be broken */
+ int hd_type = 0; /* used to store type of stmt for if (...),
+ * for (...), etc */
+ int i; /* local loop counter */
+ int scase; /* set to true when we see a case, so we will
+ * know what to do with the following colon */
+ int sp_sw; /* when true, we are in the expression of
+ * if(...), while(...), etc. */
+ int squest; /* when this is positive, we have seen a ?
+ * without the matching : in a <c>?<s>:<s>
+ * construct */
+ const char *t_ptr; /* used for copying tokens */
+ int tabs_to_var; /* true if using tabs to indent to var name */
+ int type_code; /* the type of token, returned by lexi */
+
+ int last_else = 0; /* true iff last keyword was an else */
+
+
+ /*-----------------------------------------------*\
+ | INITIALIZATION |
+ \*-----------------------------------------------*/
+
+ found_err = 0;
+
+ ps.p_stack[0] = stmt; /* this is the parser's stack */
+ ps.last_nl = true; /* this is true if the last thing scanned was
+ * a newline */
+ ps.last_token = semicolon;
+ combuf = (char *) malloc(bufsize);
+ if (combuf == NULL)
+ err(1, NULL);
+ labbuf = (char *) malloc(bufsize);
+ if (labbuf == NULL)
+ err(1, NULL);
+ codebuf = (char *) malloc(bufsize);
+ if (codebuf == NULL)
+ err(1, NULL);
+ tokenbuf = (char *) malloc(bufsize);
+ if (tokenbuf == NULL)
+ err(1, NULL);
+ l_com = combuf + bufsize - 5;
+ l_lab = labbuf + bufsize - 5;
+ l_code = codebuf + bufsize - 5;
+ l_token = tokenbuf + bufsize - 5;
+ combuf[0] = codebuf[0] = labbuf[0] = ' '; /* set up code, label, and
+ * comment buffers */
+ combuf[1] = codebuf[1] = labbuf[1] = '\0';
+ ps.else_if = 1; /* Default else-if special processing to on */
+ s_lab = e_lab = labbuf + 1;
+ s_code = e_code = codebuf + 1;
+ s_com = e_com = combuf + 1;
+ s_token = e_token = tokenbuf + 1;
+
+ in_buffer = (char *) malloc(10);
+ if (in_buffer == NULL)
+ err(1, NULL);
+ in_buffer_limit = in_buffer + 8;
+ buf_ptr = buf_end = in_buffer;
+ line_no = 1;
+ had_eof = ps.in_decl = ps.decl_on_line = break_comma = false;
+ sp_sw = force_nl = false;
+ ps.in_or_st = false;
+ ps.bl_line = true;
+ dec_ind = 0;
+ di_stack[ps.dec_nest = 0] = 0;
+ ps.want_blank = ps.in_stmt = ps.ind_stmt = false;
+
+ scase = ps.pcase = false;
+ squest = 0;
+ sc_end = 0;
+ bp_save = 0;
+ be_save = 0;
+
+ output = 0;
+ tabs_to_var = 0;
+
+ /*--------------------------------------------------*\
+ | COMMAND LINE SCAN |
+ \*--------------------------------------------------*/
+
+#ifdef undef
+ max_col = 78; /* -l78 */
+ lineup_to_parens = 1; /* -lp */
+ ps.ljust_decl = 0; /* -ndj */
+ ps.com_ind = 33; /* -c33 */
+ star_comment_cont = 1; /* -sc */
+ ps.ind_size = 8; /* -i8 */
+ verbose = 0;
+ ps.decl_indent = 16; /* -di16 */
+ ps.local_decl_indent = -1; /* if this is not set to some nonnegative value
+ * by an arg, we will set this equal to
+ * ps.decl_ind */
+ ps.indent_parameters = 1; /* -ip */
+ ps.decl_com_ind = 0; /* if this is not set to some positive value
+ * by an arg, we will set this equal to
+ * ps.com_ind */
+ btype_2 = 1; /* -br */
+ cuddle_else = 1; /* -ce */
+ ps.unindent_displace = 0; /* -d0 */
+ ps.case_indent = 0; /* -cli0 */
+ format_block_comments = 1; /* -fcb */
+ format_col1_comments = 1; /* -fc1 */
+ procnames_start_line = 1; /* -psl */
+ proc_calls_space = 0; /* -npcs */
+ comment_delimiter_on_blankline = 1; /* -cdb */
+ ps.leave_comma = 1; /* -nbc */
+#endif
+
+ for (i = 1; i < argc; ++i)
+ if (strcmp(argv[i], "-npro") == 0)
+ break;
+ set_defaults();
+ if (i >= argc)
+ set_profile();
+
+ for (i = 1; i < argc; ++i) {
+
+ /*
+ * look thru args (if any) for changes to defaults
+ */
+ if (argv[i][0] != '-') {/* no flag on parameter */
+ if (input == NULL) { /* we must have the input file */
+ in_name = argv[i]; /* remember name of input file */
+ input = fopen(in_name, "r");
+ if (input == NULL) /* check for open error */
+ err(1, "%s", in_name);
+ continue;
+ }
+ else if (output == NULL) { /* we have the output file */
+ out_name = argv[i]; /* remember name of output file */
+ if (strcmp(in_name, out_name) == 0) { /* attempt to overwrite
+ * the file */
+ errx(1, "input and output files must be different");
+ }
+ output = fopen(out_name, "w");
+ if (output == NULL) /* check for create error */
+ err(1, "%s", out_name);
+ continue;
+ }
+ errx(1, "unknown parameter: %s", argv[i]);
+ }
+ else
+ set_option(argv[i]);
+ } /* end of for */
+ if (input == NULL)
+ input = stdin;
+ if (output == NULL) {
+ if (troff || input == stdin)
+ output = stdout;
+ else {
+ out_name = in_name;
+ bakcopy();
+ }
+ }
+ if (ps.com_ind <= 1)
+ ps.com_ind = 2; /* dont put normal comments before column 2 */
+ if (troff) {
+ if (bodyf.font[0] == 0)
+ parsefont(&bodyf, "R");
+ if (scomf.font[0] == 0)
+ parsefont(&scomf, "I");
+ if (blkcomf.font[0] == 0)
+ blkcomf = scomf, blkcomf.size += 2;
+ if (boxcomf.font[0] == 0)
+ boxcomf = blkcomf;
+ if (stringf.font[0] == 0)
+ parsefont(&stringf, "L");
+ if (keywordf.font[0] == 0)
+ parsefont(&keywordf, "B");
+ writefdef(&bodyf, 'B');
+ writefdef(&scomf, 'C');
+ writefdef(&blkcomf, 'L');
+ writefdef(&boxcomf, 'X');
+ writefdef(&stringf, 'S');
+ writefdef(&keywordf, 'K');
+ }
+ if (block_comment_max_col <= 0)
+ block_comment_max_col = max_col;
+ if (ps.local_decl_indent < 0) /* if not specified by user, set this */
+ ps.local_decl_indent = ps.decl_indent;
+ if (ps.decl_com_ind <= 0) /* if not specified by user, set this */
+ ps.decl_com_ind = ps.ljust_decl ? (ps.com_ind <= 10 ? 2 : ps.com_ind - 8) : ps.com_ind;
+ if (continuation_indent == 0)
+ continuation_indent = ps.ind_size;
+ fill_buffer(); /* get first batch of stuff into input buffer */
+
+ parse(semicolon);
+ {
+ char *p = buf_ptr;
+ int col = 1;
+
+ while (1) {
+ if (*p == ' ')
+ col++;
+ else if (*p == '\t')
+ col = ((col - 1) & ~7) + 9;
+ else
+ break;
+ p++;
+ }
+ if (col > ps.ind_size)
+ ps.ind_level = ps.i_l_follow = col / ps.ind_size;
+ }
+ if (troff) {
+ const char *p = in_name,
+ *beg = in_name;
+
+ while (*p)
+ if (*p++ == '/')
+ beg = p;
+ fprintf(output, ".Fn \"%s\"\n", beg);
+ }
+ /*
+ * START OF MAIN LOOP
+ */
+
+ while (1) { /* this is the main loop. it will go until we
+ * reach eof */
+ int is_procname;
+
+ type_code = lexi(); /* lexi reads one token. The actual
+ * characters read are stored in "token". lexi
+ * returns a code indicating the type of token */
+ is_procname = ps.procname[0];
+
+ /*
+ * The following code moves everything following an if (), while (),
+ * else, etc. up to the start of the following stmt to a buffer. This
+ * allows proper handling of both kinds of brace placement.
+ */
+
+ flushed_nl = false;
+ while (ps.search_brace) { /* if we scanned an if(), while(),
+ * etc., we might need to copy stuff
+ * into a buffer we must loop, copying
+ * stuff into save_com, until we find
+ * the start of the stmt which follows
+ * the if, or whatever */
+ switch (type_code) {
+ case newline:
+ ++line_no;
+ flushed_nl = true;
+ case form_feed:
+ break; /* form feeds and newlines found here will be
+ * ignored */
+
+ case lbrace: /* this is a brace that starts the compound
+ * stmt */
+ if (sc_end == 0) { /* ignore buffering if a comment wasn't
+ * stored up */
+ ps.search_brace = false;
+ goto check_type;
+ }
+ if (btype_2) {
+ save_com[0] = '{'; /* we either want to put the brace
+ * right after the if */
+ goto sw_buffer; /* go to common code to get out of
+ * this loop */
+ }
+ case comment: /* we have a comment, so we must copy it into
+ * the buffer */
+ if (!flushed_nl || sc_end != 0) {
+ if (sc_end == 0) { /* if this is the first comment, we
+ * must set up the buffer */
+ save_com[0] = save_com[1] = ' ';
+ sc_end = &(save_com[2]);
+ }
+ else {
+ *sc_end++ = '\n'; /* add newline between
+ * comments */
+ *sc_end++ = ' ';
+ --line_no;
+ }
+ *sc_end++ = '/'; /* copy in start of comment */
+ *sc_end++ = '*';
+
+ for (;;) { /* loop until we get to the end of the comment */
+ *sc_end = *buf_ptr++;
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+
+ if (*sc_end++ == '*' && *buf_ptr == '/')
+ break; /* we are at end of comment */
+
+ if (sc_end >= &(save_com[sc_size])) { /* check for temp buffer
+ * overflow */
+ diag2(1, "Internal buffer overflow - Move big comment from right after if, while, or whatever");
+ fflush(output);
+ exit(1);
+ }
+ }
+ *sc_end++ = '/'; /* add ending slash */
+ if (++buf_ptr >= buf_end) /* get past / in buffer */
+ fill_buffer();
+ break;
+ }
+ default: /* it is the start of a normal statement */
+ if (flushed_nl) /* if we flushed a newline, make sure it is
+ * put back */
+ force_nl = true;
+ if ((type_code == sp_paren && *token == 'i'
+ && last_else && ps.else_if)
+ || (type_code == sp_nparen && *token == 'e'
+ && e_code != s_code && e_code[-1] == '}'))
+ force_nl = false;
+
+ if (sc_end == 0) { /* ignore buffering if comment wasn't
+ * saved up */
+ ps.search_brace = false;
+ goto check_type;
+ }
+ if (force_nl) { /* if we should insert a nl here, put it into
+ * the buffer */
+ force_nl = false;
+ --line_no; /* this will be re-increased when the nl is
+ * read from the buffer */
+ *sc_end++ = '\n';
+ *sc_end++ = ' ';
+ if (verbose && !flushed_nl) /* print error msg if the line
+ * was not already broken */
+ diag2(0, "Line broken");
+ flushed_nl = false;
+ }
+ for (t_ptr = token; *t_ptr; ++t_ptr)
+ *sc_end++ = *t_ptr; /* copy token into temp buffer */
+ ps.procname[0] = 0;
+
+ sw_buffer:
+ ps.search_brace = false; /* stop looking for start of
+ * stmt */
+ bp_save = buf_ptr; /* save current input buffer */
+ be_save = buf_end;
+ buf_ptr = save_com; /* fix so that subsequent calls to
+ * lexi will take tokens out of
+ * save_com */
+ *sc_end++ = ' ';/* add trailing blank, just in case */
+ buf_end = sc_end;
+ sc_end = 0;
+ break;
+ } /* end of switch */
+ if (type_code != 0) /* we must make this check, just in case there
+ * was an unexpected EOF */
+ type_code = lexi(); /* read another token */
+ /* if (ps.search_brace) ps.procname[0] = 0; */
+ if ((is_procname = ps.procname[0]) && flushed_nl
+ && !procnames_start_line && ps.in_decl
+ && type_code == ident)
+ flushed_nl = 0;
+ } /* end of while (search_brace) */
+ last_else = 0;
+check_type:
+ if (type_code == 0) { /* we got eof */
+ if (s_lab != e_lab || s_code != e_code
+ || s_com != e_com) /* must dump end of line */
+ dump_line();
+ if (ps.tos > 1) /* check for balanced braces */
+ diag2(1, "Stuff missing from end of file");
+
+ if (verbose) {
+ printf("There were %d output lines and %d comments\n",
+ ps.out_lines, ps.out_coms);
+ printf("(Lines with comments)/(Lines with code): %6.3f\n",
+ (1.0 * ps.com_lines) / code_lines);
+ }
+ fflush(output);
+ exit(found_err);
+ }
+ if (
+ (type_code != comment) &&
+ (type_code != newline) &&
+ (type_code != preesc) &&
+ (type_code != form_feed)) {
+ if (force_nl &&
+ (type_code != semicolon) &&
+ (type_code != lbrace || !btype_2)) {
+ /* we should force a broken line here */
+ if (verbose && !flushed_nl)
+ diag2(0, "Line broken");
+ flushed_nl = false;
+ dump_line();
+ ps.want_blank = false; /* dont insert blank at line start */
+ force_nl = false;
+ }
+ ps.in_stmt = true; /* turn on flag which causes an extra level of
+ * indentation. this is turned off by a ; or
+ * '}' */
+ if (s_com != e_com) { /* the turkey has embedded a comment
+ * in a line. fix it */
+ *e_code++ = ' ';
+ for (t_ptr = s_com; *t_ptr; ++t_ptr) {
+ CHECK_SIZE_CODE;
+ *e_code++ = *t_ptr;
+ }
+ *e_code++ = ' ';
+ *e_code = '\0'; /* null terminate code sect */
+ ps.want_blank = false;
+ e_com = s_com;
+ }
+ }
+ else if (type_code != comment) /* preserve force_nl thru a comment */
+ force_nl = false; /* cancel forced newline after newline, form
+ * feed, etc */
+
+
+
+ /*-----------------------------------------------------*\
+ | do switch on type of token scanned |
+ \*-----------------------------------------------------*/
+ CHECK_SIZE_CODE;
+ switch (type_code) { /* now, decide what to do with the token */
+
+ case form_feed: /* found a form feed in line */
+ ps.use_ff = true; /* a form feed is treated much like a newline */
+ dump_line();
+ ps.want_blank = false;
+ break;
+
+ case newline:
+ if (ps.last_token != comma || ps.p_l_follow > 0
+ || !ps.leave_comma || ps.block_init || !break_comma || s_com != e_com) {
+ dump_line();
+ ps.want_blank = false;
+ }
+ ++line_no; /* keep track of input line number */
+ break;
+
+ case lparen: /* got a '(' or '[' */
+ ++ps.p_l_follow; /* count parens to make Healy happy */
+ if (ps.want_blank && *token != '[' &&
+ (ps.last_token != ident || proc_calls_space
+ || (ps.its_a_keyword && (!ps.sizeof_keyword || Bill_Shannon))))
+ *e_code++ = ' ';
+ if (ps.in_decl && !ps.block_init)
+ if (troff && !ps.dumped_decl_indent && !is_procname && ps.last_token == decl) {
+ ps.dumped_decl_indent = 1;
+ sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
+ e_code += strlen(e_code);
+ }
+ else {
+ while ((e_code - s_code) < dec_ind) {
+ CHECK_SIZE_CODE;
+ *e_code++ = ' ';
+ }
+ *e_code++ = token[0];
+ }
+ else
+ *e_code++ = token[0];
+ ps.paren_indents[ps.p_l_follow - 1] = e_code - s_code;
+ if (sp_sw && ps.p_l_follow == 1 && extra_expression_indent
+ && ps.paren_indents[0] < 2 * ps.ind_size)
+ ps.paren_indents[0] = 2 * ps.ind_size;
+ ps.want_blank = false;
+ if (ps.in_or_st && *token == '(' && ps.tos <= 2) {
+ /*
+ * this is a kluge to make sure that declarations will be
+ * aligned right if proc decl has an explicit type on it, i.e.
+ * "int a(x) {..."
+ */
+ parse(semicolon); /* I said this was a kluge... */
+ ps.in_or_st = false; /* turn off flag for structure decl or
+ * initialization */
+ }
+ if (ps.sizeof_keyword)
+ ps.sizeof_mask |= 1 << ps.p_l_follow;
+ break;
+
+ case rparen: /* got a ')' or ']' */
+ rparen_count--;
+ if (ps.cast_mask & (1 << ps.p_l_follow) & ~ps.sizeof_mask) {
+ ps.last_u_d = true;
+ ps.cast_mask &= (1 << ps.p_l_follow) - 1;
+ ps.want_blank = false;
+ } else
+ ps.want_blank = true;
+ ps.sizeof_mask &= (1 << ps.p_l_follow) - 1;
+ if (--ps.p_l_follow < 0) {
+ ps.p_l_follow = 0;
+ diag3(0, "Extra %c", *token);
+ }
+ if (e_code == s_code) /* if the paren starts the line */
+ ps.paren_level = ps.p_l_follow; /* then indent it */
+
+ *e_code++ = token[0];
+
+ if (sp_sw && (ps.p_l_follow == 0)) { /* check for end of if
+ * (...), or some such */
+ sp_sw = false;
+ force_nl = true;/* must force newline after if */
+ ps.last_u_d = true; /* inform lexi that a following
+ * operator is unary */
+ ps.in_stmt = false; /* dont use stmt continuation
+ * indentation */
+
+ parse(hd_type); /* let parser worry about if, or whatever */
+ }
+ ps.search_brace = btype_2; /* this should insure that constructs
+ * such as main(){...} and int[]{...}
+ * have their braces put in the right
+ * place */
+ break;
+
+ case unary_op: /* this could be any unary operation */
+ if (ps.want_blank)
+ *e_code++ = ' ';
+
+ if (troff && !ps.dumped_decl_indent && ps.in_decl && !is_procname) {
+ sprintf(e_code, "\n.Du %dp+\200p \"%s\"\n", dec_ind * 7, token);
+ ps.dumped_decl_indent = 1;
+ e_code += strlen(e_code);
+ }
+ else {
+ const char *res = token;
+
+ if (ps.in_decl && !ps.block_init) { /* if this is a unary op
+ * in a declaration, we
+ * should indent this
+ * token */
+ for (i = 0; token[i]; ++i); /* find length of token */
+ while ((e_code - s_code) < (dec_ind - i)) {
+ CHECK_SIZE_CODE;
+ *e_code++ = ' '; /* pad it */
+ }
+ }
+ if (troff && token[0] == '-' && token[1] == '>')
+ res = "\\(->";
+ for (t_ptr = res; *t_ptr; ++t_ptr) {
+ CHECK_SIZE_CODE;
+ *e_code++ = *t_ptr;
+ }
+ }
+ ps.want_blank = false;
+ break;
+
+ case binary_op: /* any binary operation */
+ if (ps.want_blank)
+ *e_code++ = ' ';
+ {
+ const char *res = token;
+
+ if (troff)
+ switch (token[0]) {
+ case '<':
+ if (token[1] == '=')
+ res = "\\(<=";
+ break;
+ case '>':
+ if (token[1] == '=')
+ res = "\\(>=";
+ break;
+ case '!':
+ if (token[1] == '=')
+ res = "\\(!=";
+ break;
+ case '|':
+ if (token[1] == '|')
+ res = "\\(br\\(br";
+ else if (token[1] == 0)
+ res = "\\(br";
+ break;
+ }
+ for (t_ptr = res; *t_ptr; ++t_ptr) {
+ CHECK_SIZE_CODE;
+ *e_code++ = *t_ptr; /* move the operator */
+ }
+ }
+ ps.want_blank = true;
+ break;
+
+ case postop: /* got a trailing ++ or -- */
+ *e_code++ = token[0];
+ *e_code++ = token[1];
+ ps.want_blank = true;
+ break;
+
+ case question: /* got a ? */
+ squest++; /* this will be used when a later colon
+ * appears so we can distinguish the
+ * <c>?<n>:<n> construct */
+ if (ps.want_blank)
+ *e_code++ = ' ';
+ *e_code++ = '?';
+ ps.want_blank = true;
+ break;
+
+ case casestmt: /* got word 'case' or 'default' */
+ scase = true; /* so we can process the later colon properly */
+ goto copy_id;
+
+ case colon: /* got a ':' */
+ if (squest > 0) { /* it is part of the <c>?<n>: <n> construct */
+ --squest;
+ if (ps.want_blank)
+ *e_code++ = ' ';
+ *e_code++ = ':';
+ ps.want_blank = true;
+ break;
+ }
+ if (ps.in_or_st) {
+ *e_code++ = ':';
+ ps.want_blank = false;
+ break;
+ }
+ ps.in_stmt = false; /* seeing a label does not imply we are in a
+ * stmt */
+ for (t_ptr = s_code; *t_ptr; ++t_ptr)
+ *e_lab++ = *t_ptr; /* turn everything so far into a label */
+ e_code = s_code;
+ *e_lab++ = ':';
+ *e_lab++ = ' ';
+ *e_lab = '\0';
+
+ force_nl = ps.pcase = scase; /* ps.pcase will be used by
+ * dump_line to decide how to
+ * indent the label. force_nl
+ * will force a case n: to be
+ * on a line by itself */
+ scase = false;
+ ps.want_blank = false;
+ break;
+
+ case semicolon: /* got a ';' */
+ ps.in_or_st = false;/* we are not in an initialization or
+ * structure declaration */
+ scase = false; /* these will only need resetting in an error */
+ squest = 0;
+ if (ps.last_token == rparen && rparen_count == 0)
+ ps.in_parameter_declaration = 0;
+ ps.cast_mask = 0;
+ ps.sizeof_mask = 0;
+ ps.block_init = 0;
+ ps.block_init_level = 0;
+ ps.just_saw_decl--;
+
+ if (ps.in_decl && s_code == e_code && !ps.block_init)
+ while ((e_code - s_code) < (dec_ind - 1)) {
+ CHECK_SIZE_CODE;
+ *e_code++ = ' ';
+ }
+
+ ps.in_decl = (ps.dec_nest > 0); /* if we were in a first level
+ * structure declaration, we
+ * arent any more */
+
+ if ((!sp_sw || hd_type != forstmt) && ps.p_l_follow > 0) {
+
+ /*
+ * This should be true iff there were unbalanced parens in the
+ * stmt. It is a bit complicated, because the semicolon might
+ * be in a for stmt
+ */
+ diag2(1, "Unbalanced parens");
+ ps.p_l_follow = 0;
+ if (sp_sw) { /* this is a check for an if, while, etc. with
+ * unbalanced parens */
+ sp_sw = false;
+ parse(hd_type); /* dont lose the if, or whatever */
+ }
+ }
+ *e_code++ = ';';
+ ps.want_blank = true;
+ ps.in_stmt = (ps.p_l_follow > 0); /* we are no longer in the
+ * middle of a stmt */
+
+ if (!sp_sw) { /* if not if for (;;) */
+ parse(semicolon); /* let parser know about end of stmt */
+ force_nl = true;/* force newline after an end of stmt */
+ }
+ break;
+
+ case lbrace: /* got a '{' */
+ ps.in_stmt = false; /* dont indent the {} */
+ if (!ps.block_init)
+ force_nl = true;/* force other stuff on same line as '{' onto
+ * new line */
+ else if (ps.block_init_level <= 0)
+ ps.block_init_level = 1;
+ else
+ ps.block_init_level++;
+
+ if (s_code != e_code && !ps.block_init) {
+ if (!btype_2) {
+ dump_line();
+ ps.want_blank = false;
+ }
+ else if (ps.in_parameter_declaration && !ps.in_or_st) {
+ ps.i_l_follow = 0;
+ if (function_brace_split) { /* dump the line prior to the
+ * brace ... */
+ dump_line();
+ ps.want_blank = false;
+ } else /* add a space between the decl and brace */
+ ps.want_blank = true;
+ }
+ }
+ if (ps.in_parameter_declaration)
+ prefix_blankline_requested = 0;
+
+ if (ps.p_l_follow > 0) { /* check for preceding unbalanced
+ * parens */
+ diag2(1, "Unbalanced parens");
+ ps.p_l_follow = 0;
+ if (sp_sw) { /* check for unclosed if, for, etc. */
+ sp_sw = false;
+ parse(hd_type);
+ ps.ind_level = ps.i_l_follow;
+ }
+ }
+ if (s_code == e_code)
+ ps.ind_stmt = false; /* dont put extra indentation on line
+ * with '{' */
+ if (ps.in_decl && ps.in_or_st) { /* this is either a structure
+ * declaration or an init */
+ di_stack[ps.dec_nest++] = dec_ind;
+ /* ? dec_ind = 0; */
+ }
+ else {
+ ps.decl_on_line = false; /* we can't be in the middle of
+ * a declaration, so don't do
+ * special indentation of
+ * comments */
+ if (blanklines_after_declarations_at_proctop
+ && ps.in_parameter_declaration)
+ postfix_blankline_requested = 1;
+ ps.in_parameter_declaration = 0;
+ }
+ dec_ind = 0;
+ parse(lbrace); /* let parser know about this */
+ if (ps.want_blank) /* put a blank before '{' if '{' is not at
+ * start of line */
+ *e_code++ = ' ';
+ ps.want_blank = false;
+ *e_code++ = '{';
+ ps.just_saw_decl = 0;
+ break;
+
+ case rbrace: /* got a '}' */
+ if (ps.p_stack[ps.tos] == decl && !ps.block_init) /* semicolons can be
+ * omitted in
+ * declarations */
+ parse(semicolon);
+ if (ps.p_l_follow) {/* check for unclosed if, for, else. */
+ diag2(1, "Unbalanced parens");
+ ps.p_l_follow = 0;
+ sp_sw = false;
+ }
+ ps.just_saw_decl = 0;
+ ps.block_init_level--;
+ if (s_code != e_code && !ps.block_init) { /* '}' must be first on
+ * line */
+ if (verbose)
+ diag2(0, "Line broken");
+ dump_line();
+ }
+ *e_code++ = '}';
+ ps.want_blank = true;
+ ps.in_stmt = ps.ind_stmt = false;
+ if (ps.dec_nest > 0) { /* we are in multi-level structure
+ * declaration */
+ dec_ind = di_stack[--ps.dec_nest];
+ if (ps.dec_nest == 0 && !ps.in_parameter_declaration)
+ ps.just_saw_decl = 2;
+ ps.in_decl = true;
+ }
+ prefix_blankline_requested = 0;
+ parse(rbrace); /* let parser know about this */
+ ps.search_brace = cuddle_else && ps.p_stack[ps.tos] == ifhead
+ && ps.il[ps.tos] >= ps.ind_level;
+ if (ps.tos <= 1 && blanklines_after_procs && ps.dec_nest <= 0)
+ postfix_blankline_requested = 1;
+ break;
+
+ case swstmt: /* got keyword "switch" */
+ sp_sw = true;
+ hd_type = swstmt; /* keep this for when we have seen the
+ * expression */
+ goto copy_id; /* go move the token into buffer */
+
+ case sp_paren: /* token is if, while, for */
+ sp_sw = true; /* the interesting stuff is done after the
+ * expression is scanned */
+ hd_type = (*token == 'i' ? ifstmt :
+ (*token == 'w' ? whilestmt : forstmt));
+
+ /*
+ * remember the type of header for later use by parser
+ */
+ goto copy_id; /* copy the token into line */
+
+ case sp_nparen: /* got else, do */
+ ps.in_stmt = false;
+ if (*token == 'e') {
+ if (e_code != s_code && (!cuddle_else || e_code[-1] != '}')) {
+ if (verbose)
+ diag2(0, "Line broken");
+ dump_line();/* make sure this starts a line */
+ ps.want_blank = false;
+ }
+ force_nl = true;/* also, following stuff must go onto new line */
+ last_else = 1;
+ parse(elselit);
+ }
+ else {
+ if (e_code != s_code) { /* make sure this starts a line */
+ if (verbose)
+ diag2(0, "Line broken");
+ dump_line();
+ ps.want_blank = false;
+ }
+ force_nl = true;/* also, following stuff must go onto new line */
+ last_else = 0;
+ parse(dolit);
+ }
+ goto copy_id; /* move the token into line */
+
+ case decl: /* we have a declaration type (int, register,
+ * etc.) */
+ parse(decl); /* let parser worry about indentation */
+ if (ps.last_token == rparen && ps.tos <= 1) {
+ ps.in_parameter_declaration = 1;
+ if (s_code != e_code) {
+ dump_line();
+ ps.want_blank = 0;
+ }
+ }
+ if (ps.in_parameter_declaration && ps.indent_parameters && ps.dec_nest == 0) {
+ ps.ind_level = ps.i_l_follow = 1;
+ ps.ind_stmt = 0;
+ }
+ ps.in_or_st = true; /* this might be a structure or initialization
+ * declaration */
+ ps.in_decl = ps.decl_on_line = true;
+ if ( /* !ps.in_or_st && */ ps.dec_nest <= 0)
+ ps.just_saw_decl = 2;
+ prefix_blankline_requested = 0;
+ for (i = 0; token[i++];); /* get length of token */
+
+ if (ps.ind_level == 0 || ps.dec_nest > 0) {
+ /* global variable or struct member in local variable */
+ dec_ind = ps.decl_indent > 0 ? ps.decl_indent : i;
+ tabs_to_var = (use_tabs ? ps.decl_indent > 0 : 0);
+ } else {
+ /* local variable */
+ dec_ind = ps.local_decl_indent > 0 ? ps.local_decl_indent : i;
+ tabs_to_var = (use_tabs ? ps.local_decl_indent > 0 : 0);
+ }
+ goto copy_id;
+
+ case ident: /* got an identifier or constant */
+ if (ps.in_decl) { /* if we are in a declaration, we must indent
+ * identifier */
+ if (is_procname == 0 || !procnames_start_line) {
+ if (!ps.block_init) {
+ if (troff && !ps.dumped_decl_indent) {
+ if (ps.want_blank)
+ *e_code++ = ' ';
+ ps.want_blank = false;
+ sprintf(e_code, "\n.De %dp+\200p\n", dec_ind * 7);
+ ps.dumped_decl_indent = 1;
+ e_code += strlen(e_code);
+ } else {
+ int cur_dec_ind;
+ int pos, startpos;
+
+ /*
+ * in order to get the tab math right for
+ * indentations that are not multiples of 8 we
+ * need to modify both startpos and dec_ind
+ * (cur_dec_ind) here by eight minus the
+ * remainder of the current starting column
+ * divided by eight. This seems to be a
+ * properly working fix
+ */
+ startpos = e_code - s_code;
+ cur_dec_ind = dec_ind;
+ pos = startpos;
+ if ((ps.ind_level * ps.ind_size) % 8 != 0) {
+ pos += (ps.ind_level * ps.ind_size) % 8;
+ cur_dec_ind += (ps.ind_level * ps.ind_size) % 8;
+ }
+
+ if (tabs_to_var) {
+ while ((pos & ~7) + 8 <= cur_dec_ind) {
+ CHECK_SIZE_CODE;
+ *e_code++ = '\t';
+ pos = (pos & ~7) + 8;
+ }
+ }
+ while (pos < cur_dec_ind) {
+ CHECK_SIZE_CODE;
+ *e_code++ = ' ';
+ pos++;
+ }
+ if (ps.want_blank && e_code - s_code == startpos)
+ *e_code++ = ' ';
+ ps.want_blank = false;
+ }
+ }
+ } else {
+ if (ps.want_blank)
+ *e_code++ = ' ';
+ ps.want_blank = false;
+ if (dec_ind && s_code != e_code)
+ dump_line();
+ dec_ind = 0;
+ }
+ }
+ else if (sp_sw && ps.p_l_follow == 0) {
+ sp_sw = false;
+ force_nl = true;
+ ps.last_u_d = true;
+ ps.in_stmt = false;
+ parse(hd_type);
+ }
+ copy_id:
+ if (ps.want_blank)
+ *e_code++ = ' ';
+ if (troff && ps.its_a_keyword) {
+ e_code = chfont(&bodyf, &keywordf, e_code);
+ for (t_ptr = token; *t_ptr; ++t_ptr) {
+ CHECK_SIZE_CODE;
+ *e_code++ = keywordf.allcaps && islower(*t_ptr)
+ ? toupper(*t_ptr) : *t_ptr;
+ }
+ e_code = chfont(&keywordf, &bodyf, e_code);
+ }
+ else
+ for (t_ptr = token; *t_ptr; ++t_ptr) {
+ CHECK_SIZE_CODE;
+ *e_code++ = *t_ptr;
+ }
+ ps.want_blank = true;
+ break;
+
+ case period: /* treat a period kind of like a binary
+ * operation */
+ *e_code++ = '.'; /* move the period into line */
+ ps.want_blank = false; /* dont put a blank after a period */
+ break;
+
+ case comma:
+ ps.want_blank = (s_code != e_code); /* only put blank after comma
+ * if comma does not start the
+ * line */
+ if (ps.in_decl && is_procname == 0 && !ps.block_init)
+ while ((e_code - s_code) < (dec_ind - 1)) {
+ CHECK_SIZE_CODE;
+ *e_code++ = ' ';
+ }
+
+ *e_code++ = ',';
+ if (ps.p_l_follow == 0) {
+ if (ps.block_init_level <= 0)
+ ps.block_init = 0;
+ if (break_comma && (!ps.leave_comma || compute_code_target() + (e_code - s_code) > max_col - 8))
+ force_nl = true;
+ }
+ break;
+
+ case preesc: /* got the character '#' */
+ if ((s_com != e_com) ||
+ (s_lab != e_lab) ||
+ (s_code != e_code))
+ dump_line();
+ *e_lab++ = '#'; /* move whole line to 'label' buffer */
+ {
+ int in_comment = 0;
+ int com_start = 0;
+ char quote = 0;
+ int com_end = 0;
+
+ while (*buf_ptr == ' ' || *buf_ptr == '\t') {
+ buf_ptr++;
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+ }
+ while (*buf_ptr != '\n' || (in_comment && !had_eof)) {
+ CHECK_SIZE_LAB;
+ *e_lab = *buf_ptr++;
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+ switch (*e_lab++) {
+ case BACKSLASH:
+ if (troff)
+ *e_lab++ = BACKSLASH;
+ if (!in_comment) {
+ *e_lab++ = *buf_ptr++;
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+ }
+ break;
+ case '/':
+ if (*buf_ptr == '*' && !in_comment && !quote) {
+ in_comment = 1;
+ *e_lab++ = *buf_ptr++;
+ com_start = e_lab - s_lab - 2;
+ }
+ break;
+ case '"':
+ if (quote == '"')
+ quote = 0;
+ break;
+ case '\'':
+ if (quote == '\'')
+ quote = 0;
+ break;
+ case '*':
+ if (*buf_ptr == '/' && in_comment) {
+ in_comment = 0;
+ *e_lab++ = *buf_ptr++;
+ com_end = e_lab - s_lab;
+ }
+ break;
+ }
+ }
+
+ while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
+ e_lab--;
+ if (e_lab - s_lab == com_end && bp_save == 0) { /* comment on
+ * preprocessor line */
+ if (sc_end == 0) /* if this is the first comment, we
+ * must set up the buffer */
+ sc_end = &(save_com[0]);
+ else {
+ *sc_end++ = '\n'; /* add newline between
+ * comments */
+ *sc_end++ = ' ';
+ --line_no;
+ }
+ bcopy(s_lab + com_start, sc_end, com_end - com_start);
+ sc_end += com_end - com_start;
+ if (sc_end >= &save_com[sc_size])
+ abort();
+ e_lab = s_lab + com_start;
+ while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
+ e_lab--;
+ bp_save = buf_ptr; /* save current input buffer */
+ be_save = buf_end;
+ buf_ptr = save_com; /* fix so that subsequent calls to
+ * lexi will take tokens out of
+ * save_com */
+ *sc_end++ = ' '; /* add trailing blank, just in case */
+ buf_end = sc_end;
+ sc_end = 0;
+ }
+ *e_lab = '\0'; /* null terminate line */
+ ps.pcase = false;
+ }
+
+ if (strncmp(s_lab, "#if", 3) == 0) {
+ if (blanklines_around_conditional_compilation) {
+ int c;
+ prefix_blankline_requested++;
+ while ((c = getc(input)) == '\n');
+ ungetc(c, input);
+ }
+ if ((size_t)ifdef_level < sizeof(state_stack)/sizeof(state_stack[0])) {
+ match_state[ifdef_level].tos = -1;
+ state_stack[ifdef_level++] = ps;
+ }
+ else
+ diag2(1, "#if stack overflow");
+ }
+ else if (strncmp(s_lab, "#else", 5) == 0)
+ if (ifdef_level <= 0)
+ diag2(1, "Unmatched #else");
+ else {
+ match_state[ifdef_level - 1] = ps;
+ ps = state_stack[ifdef_level - 1];
+ }
+ else if (strncmp(s_lab, "#endif", 6) == 0) {
+ if (ifdef_level <= 0)
+ diag2(1, "Unmatched #endif");
+ else {
+ ifdef_level--;
+
+#ifdef undef
+ /*
+ * This match needs to be more intelligent before the
+ * message is useful
+ */
+ if (match_state[ifdef_level].tos >= 0
+ && bcmp(&ps, &match_state[ifdef_level], sizeof ps))
+ diag2(0, "Syntactically inconsistent #ifdef alternatives");
+#endif
+ }
+ if (blanklines_around_conditional_compilation) {
+ postfix_blankline_requested++;
+ n_real_blanklines = 0;
+ }
+ }
+ break; /* subsequent processing of the newline
+ * character will cause the line to be printed */
+
+ case comment: /* we have gotten a / followed by * this is a biggie */
+ if (flushed_nl) { /* we should force a broken line here */
+ flushed_nl = false;
+ dump_line();
+ ps.want_blank = false; /* dont insert blank at line start */
+ force_nl = false;
+ }
+ pr_comment();
+ break;
+ } /* end of big switch stmt */
+
+ *e_code = '\0'; /* make sure code section is null terminated */
+ if (type_code != comment && type_code != newline && type_code != preesc)
+ ps.last_token = type_code;
+ } /* end of main while (1) loop */
+}
+
+/*
+ * copy input file to backup file if in_name is /blah/blah/blah/file, then
+ * backup file will be ".Bfile" then make the backup file the input and
+ * original input file the output
+ */
+static void
+bakcopy(void)
+{
+ int n,
+ bakchn;
+ char buff[8 * 1024];
+ const char *p;
+
+ /* construct file name .Bfile */
+ for (p = in_name; *p; p++); /* skip to end of string */
+ while (p > in_name && *p != '/') /* find last '/' */
+ p--;
+ if (*p == '/')
+ p++;
+ sprintf(bakfile, "%s.BAK", p);
+
+ /* copy in_name to backup file */
+ bakchn = creat(bakfile, 0600);
+ if (bakchn < 0)
+ err(1, "%s", bakfile);
+ while ((n = read(fileno(input), buff, sizeof buff)) != 0)
+ if (write(bakchn, buff, n) != n)
+ err(1, "%s", bakfile);
+ if (n < 0)
+ err(1, "%s", in_name);
+ close(bakchn);
+ fclose(input);
+
+ /* re-open backup file as the input file */
+ input = fopen(bakfile, "r");
+ if (input == NULL)
+ err(1, "%s", bakfile);
+ /* now the original input file will be the output */
+ output = fopen(in_name, "w");
+ if (output == NULL) {
+ unlink(bakfile);
+ err(1, "%s", in_name);
+ }
+}
diff --git a/developer_cmds/indent/indent.h b/developer_cmds/indent/indent.h
new file mode 100644
index 0000000..ac40f01
--- /dev/null
+++ b/developer_cmds/indent/indent.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2001 Jens Schweikhardt
+ * 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 ``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.
+ */
+
+#if 0
+__FBSDID("$FreeBSD: src/usr.bin/indent/indent.h,v 1.2 2002/03/30 17:10:20 dwmalone Exp $");
+#endif
+
+void addkey(char *, int);
+int compute_code_target(void);
+int compute_label_target(void);
+int count_spaces(int, char *);
+int lexi(void);
+void diag2(int, const char *);
+void diag3(int, const char *, int);
+void diag4(int, const char *, int, int);
+void dump_line(void);
+void fill_buffer(void);
+void parse(int);
+void parsefont(struct fstate *, const char *);
+void pr_comment(void);
+void set_defaults(void);
+void set_option(char *);
+void set_profile(void);
+void writefdef(struct fstate *f, int);
diff --git a/developer_cmds/indent/indent_codes.h b/developer_cmds/indent/indent_codes.h
new file mode 100644
index 0000000..008bf2b
--- /dev/null
+++ b/developer_cmds/indent/indent_codes.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)indent_codes.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/indent/indent_codes.h,v 1.2 2000/12/09 09:52:51 obrien Exp $
+ */
+
+#define newline 1
+#define lparen 2
+#define rparen 3
+#define unary_op 4
+#define binary_op 5
+#define postop 6
+#define question 7
+#define casestmt 8
+#define colon 9
+#define semicolon 10
+#define lbrace 11
+#define rbrace 12
+#define ident 13
+#define comma 14
+#define comment 15
+#define swstmt 16
+#define preesc 17
+#define form_feed 18
+#define decl 19
+#define sp_paren 20
+#define sp_nparen 21
+#define ifstmt 22
+#define whilestmt 23
+#define forstmt 24
+#define stmt 25
+#define stmtl 26
+#define elselit 27
+#define dolit 28
+#define dohead 29
+#define ifhead 30
+#define elsehead 31
+#define period 32
diff --git a/developer_cmds/indent/indent_globs.h b/developer_cmds/indent/indent_globs.h
new file mode 100644
index 0000000..3ff82fa
--- /dev/null
+++ b/developer_cmds/indent/indent_globs.h
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)indent_globs.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/indent/indent_globs.h,v 1.12 2010/03/31 17:05:30 avg Exp $
+ */
+
+#define BACKSLASH '\\'
+#define bufsize 200 /* size of internal buffers */
+#define sc_size 5000 /* size of save_com buffer */
+#define label_offset 2 /* number of levels a label is placed to left
+ * of code */
+
+#define tabsize 8 /* the size of a tab */
+#define tabmask 0177770 /* mask used when figuring length of lines
+ * with tabs */
+
+
+#define false 0
+#define true 1
+
+
+FILE *input; /* the fid for the input file */
+FILE *output; /* the output file */
+
+#define CHECK_SIZE_CODE \
+ if (e_code >= l_code) { \
+ int nsize = l_code-s_code+400; \
+ codebuf = (char *) realloc(codebuf, nsize); \
+ if (codebuf == NULL) \
+ err(1, NULL); \
+ e_code = codebuf + (e_code-s_code) + 1; \
+ l_code = codebuf + nsize - 5; \
+ s_code = codebuf + 1; \
+ }
+#define CHECK_SIZE_COM \
+ if (e_com >= l_com) { \
+ int nsize = l_com-s_com+400; \
+ combuf = (char *) realloc(combuf, nsize); \
+ if (combuf == NULL) \
+ err(1, NULL); \
+ e_com = combuf + (e_com-s_com) + 1; \
+ l_com = combuf + nsize - 5; \
+ s_com = combuf + 1; \
+ }
+#define CHECK_SIZE_LAB \
+ if (e_lab >= l_lab) { \
+ int nsize = l_lab-s_lab+400; \
+ labbuf = (char *) realloc(labbuf, nsize); \
+ if (labbuf == NULL) \
+ err(1, NULL); \
+ e_lab = labbuf + (e_lab-s_lab) + 1; \
+ l_lab = labbuf + nsize - 5; \
+ s_lab = labbuf + 1; \
+ }
+#define CHECK_SIZE_TOKEN \
+ if (e_token >= l_token) { \
+ int nsize = l_token-s_token+400; \
+ tokenbuf = (char *) realloc(tokenbuf, nsize); \
+ if (tokenbuf == NULL) \
+ err(1, NULL); \
+ e_token = tokenbuf + (e_token-s_token) + 1; \
+ l_token = tokenbuf + nsize - 5; \
+ s_token = tokenbuf + 1; \
+ }
+
+char *labbuf; /* buffer for label */
+char *s_lab; /* start ... */
+char *e_lab; /* .. and end of stored label */
+char *l_lab; /* limit of label buffer */
+
+char *codebuf; /* buffer for code section */
+char *s_code; /* start ... */
+char *e_code; /* .. and end of stored code */
+char *l_code; /* limit of code section */
+
+char *combuf; /* buffer for comments */
+char *s_com; /* start ... */
+char *e_com; /* ... and end of stored comments */
+char *l_com; /* limit of comment buffer */
+
+#define token s_token
+char *tokenbuf; /* the last token scanned */
+char *s_token;
+char *e_token;
+char *l_token;
+
+char *in_buffer; /* input buffer */
+char *in_buffer_limit; /* the end of the input buffer */
+char *buf_ptr; /* ptr to next character to be taken from
+ * in_buffer */
+char *buf_end; /* ptr to first after last char in in_buffer */
+
+char save_com[sc_size]; /* input text is saved here when looking for
+ * the brace after an if, while, etc */
+char *sc_end; /* pointer into save_com buffer */
+
+char *bp_save; /* saved value of buf_ptr when taking input
+ * from save_com */
+char *be_save; /* similarly saved value of buf_end */
+
+
+int found_err;
+int pointer_as_binop;
+int blanklines_after_declarations;
+int blanklines_before_blockcomments;
+int blanklines_after_procs;
+int blanklines_around_conditional_compilation;
+int swallow_optional_blanklines;
+int n_real_blanklines;
+int prefix_blankline_requested;
+int postfix_blankline_requested;
+int break_comma; /* when true and not in parens, break after a
+ * comma */
+int btype_2; /* when true, brace should be on same line as
+ * if, while, etc */
+float case_ind; /* indentation level to be used for a "case
+ * n:" */
+int code_lines; /* count of lines with code */
+int had_eof; /* set to true when input is exhausted */
+int line_no; /* the current line number. */
+int max_col; /* the maximum allowable line length */
+int verbose; /* when true, non-essential error messages are
+ * printed */
+int cuddle_else; /* true if else should cuddle up to '}' */
+int star_comment_cont; /* true iff comment continuation lines should
+ * have stars at the beginning of each line. */
+int comment_delimiter_on_blankline;
+int troff; /* true iff were generating troff input */
+int procnames_start_line; /* if true, the names of procedures
+ * being defined get placed in column
+ * 1 (ie. a newline is placed between
+ * the type of the procedure and its
+ * name) */
+int proc_calls_space; /* If true, procedure calls look like:
+ * foo(bar) rather than foo (bar) */
+int format_block_comments; /* true if comments beginning with
+ * `/ * \n' are to be reformatted */
+int format_col1_comments; /* If comments which start in column 1
+ * are to be magically reformatted
+ * (just like comments that begin in
+ * later columns) */
+int inhibit_formatting; /* true if INDENT OFF is in effect */
+int suppress_blanklines;/* set iff following blanklines should be
+ * suppressed */
+int continuation_indent;/* set to the indentation between the edge of
+ * code and continuation lines */
+int lineup_to_parens; /* if true, continued code within parens will
+ * be lined up to the open paren */
+int Bill_Shannon; /* true iff a blank should always be inserted
+ * after sizeof */
+int blanklines_after_declarations_at_proctop; /* This is vaguely
+ * similar to
+ * blanklines_after_decla
+ * rations except that
+ * it only applies to
+ * the first set of
+ * declarations in a
+ * procedure (just after
+ * the first '{') and it
+ * causes a blank line
+ * to be generated even
+ * if there are no
+ * declarations */
+int block_comment_max_col;
+int extra_expression_indent; /* true if continuation lines from the
+ * expression part of "if(e)",
+ * "while(e)", "for(e;e;e)" should be
+ * indented an extra tab stop so that
+ * they don't conflict with the code
+ * that follows */
+int function_brace_split; /* split function declaration and
+ * brace onto separate lines */
+int use_tabs; /* set true to use tabs for spacing,
+ * false uses all spaces */
+int auto_typedefs; /* set true to recognize identifiers
+ * ending in "_t" like typedefs */
+
+/* -troff font state information */
+
+struct fstate {
+ char font[4];
+ char size;
+ int allcaps:1;
+};
+char *chfont(struct fstate *, struct fstate *, char *);
+
+struct fstate
+ keywordf, /* keyword font */
+ stringf, /* string font */
+ boxcomf, /* Box comment font */
+ blkcomf, /* Block comment font */
+ scomf, /* Same line comment font */
+ bodyf; /* major body font */
+
+
+#define STACKSIZE 150
+
+struct parser_state {
+ int last_token;
+ struct fstate cfont; /* Current font */
+ int p_stack[STACKSIZE]; /* this is the parsers stack */
+ int il[STACKSIZE]; /* this stack stores indentation levels */
+ float cstk[STACKSIZE];/* used to store case stmt indentation levels */
+ int box_com; /* set to true when we are in a "boxed"
+ * comment. In that case, the first non-blank
+ * char should be lined up with the / in / followed by * */
+ int comment_delta,
+ n_comment_delta;
+ int cast_mask; /* indicates which close parens close off
+ * casts */
+ int sizeof_mask; /* indicates which close parens close off
+ * sizeof''s */
+ int block_init; /* true iff inside a block initialization */
+ int block_init_level; /* The level of brace nesting in an
+ * initialization */
+ int last_nl; /* this is true if the last thing scanned was
+ * a newline */
+ int in_or_st; /* Will be true iff there has been a
+ * declarator (e.g. int or char) and no left
+ * paren since the last semicolon. When true,
+ * a '{' is starting a structure definition or
+ * an initialization list */
+ int bl_line; /* set to 1 by dump_line if the line is blank */
+ int col_1; /* set to true if the last token started in
+ * column 1 */
+ int com_col; /* this is the column in which the current
+ * comment should start */
+ int com_ind; /* the column in which comments to the right
+ * of code should start */
+ int com_lines; /* the number of lines with comments, set by
+ * dump_line */
+ int dec_nest; /* current nesting level for structure or init */
+ int decl_com_ind; /* the column in which comments after
+ * declarations should be put */
+ int decl_on_line; /* set to true if this line of code has part
+ * of a declaration on it */
+ int i_l_follow; /* the level to which ind_level should be set
+ * after the current line is printed */
+ int in_decl; /* set to true when we are in a declaration
+ * stmt. The processing of braces is then
+ * slightly different */
+ int in_stmt; /* set to 1 while in a stmt */
+ int ind_level; /* the current indentation level */
+ int ind_size; /* the size of one indentation level */
+ int ind_stmt; /* set to 1 if next line should have an extra
+ * indentation level because we are in the
+ * middle of a stmt */
+ int last_u_d; /* set to true after scanning a token which
+ * forces a following operator to be unary */
+ int leave_comma; /* if true, never break declarations after
+ * commas */
+ int ljust_decl; /* true if declarations should be left
+ * justified */
+ int out_coms; /* the number of comments processed, set by
+ * pr_comment */
+ int out_lines; /* the number of lines written, set by
+ * dump_line */
+ int p_l_follow; /* used to remember how to indent following
+ * statement */
+ int paren_level; /* parenthesization level. used to indent
+ * within statements */
+ short paren_indents[20]; /* column positions of each paren */
+ int pcase; /* set to 1 if the current line label is a
+ * case. It is printed differently from a
+ * regular label */
+ int search_brace; /* set to true by parse when it is necessary
+ * to buffer up all info up to the start of a
+ * stmt after an if, while, etc */
+ int unindent_displace; /* comments not to the right of code
+ * will be placed this many
+ * indentation levels to the left of
+ * code */
+ int use_ff; /* set to one if the current line should be
+ * terminated with a form feed */
+ int want_blank; /* set to true when the following token should
+ * be prefixed by a blank. (Said prefixing is
+ * ignored in some cases.) */
+ int else_if; /* True iff else if pairs should be handled
+ * specially */
+ int decl_indent; /* column to indent declared identifiers to */
+ int local_decl_indent; /* like decl_indent but for locals */
+ int its_a_keyword;
+ int sizeof_keyword;
+ int dumped_decl_indent;
+ float case_indent; /* The distance to indent case labels from the
+ * switch statement */
+ int in_parameter_declaration;
+ int indent_parameters;
+ int tos; /* pointer to top of stack */
+ char procname[100]; /* The name of the current procedure */
+ int just_saw_decl;
+} ps;
+
+int ifdef_level;
+int rparen_count;
+struct parser_state state_stack[5];
+struct parser_state match_state[5];
diff --git a/developer_cmds/indent/io.c b/developer_cmds/indent/io.c
new file mode 100644
index 0000000..d6fd5ef
--- /dev/null
+++ b/developer_cmds/indent/io.c
@@ -0,0 +1,667 @@
+/*
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/indent/io.c,v 1.17 2011/12/30 11:02:40 uqs Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "indent_globs.h"
+#include "indent.h"
+
+int comment_open;
+static int paren_target;
+static int pad_output(int current, int target);
+
+void
+dump_line(void)
+{ /* dump_line is the routine that actually
+ * effects the printing of the new source. It
+ * prints the label section, followed by the
+ * code section with the appropriate nesting
+ * level, followed by any comments */
+ int cur_col,
+ target_col = 1;
+ static int not_first_line;
+
+ if (ps.procname[0]) {
+ if (troff) {
+ if (comment_open) {
+ comment_open = 0;
+ fprintf(output, ".*/\n");
+ }
+ fprintf(output, ".Pr \"%s\"\n", ps.procname);
+ }
+ ps.ind_level = 0;
+ ps.procname[0] = 0;
+ }
+ if (s_code == e_code && s_lab == e_lab && s_com == e_com) {
+ if (suppress_blanklines > 0)
+ suppress_blanklines--;
+ else {
+ ps.bl_line = true;
+ n_real_blanklines++;
+ }
+ }
+ else if (!inhibit_formatting) {
+ suppress_blanklines = 0;
+ ps.bl_line = false;
+ if (prefix_blankline_requested && not_first_line) {
+ if (swallow_optional_blanklines) {
+ if (n_real_blanklines == 1)
+ n_real_blanklines = 0;
+ }
+ else {
+ if (n_real_blanklines == 0)
+ n_real_blanklines = 1;
+ }
+ }
+ while (--n_real_blanklines >= 0)
+ putc('\n', output);
+ n_real_blanklines = 0;
+ if (ps.ind_level == 0)
+ ps.ind_stmt = 0; /* this is a class A kludge. dont do
+ * additional statement indentation if we are
+ * at bracket level 0 */
+
+ if (e_lab != s_lab || e_code != s_code)
+ ++code_lines; /* keep count of lines with code */
+
+
+ if (e_lab != s_lab) { /* print lab, if any */
+ if (comment_open) {
+ comment_open = 0;
+ fprintf(output, ".*/\n");
+ }
+ while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
+ e_lab--;
+ cur_col = pad_output(1, compute_label_target());
+ if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0
+ || strncmp(s_lab, "#endif", 6) == 0)) {
+ char *s = s_lab;
+ if (e_lab[-1] == '\n') e_lab--;
+ do putc(*s++, output);
+ while (s < e_lab && 'a' <= *s && *s<='z');
+ while ((*s == ' ' || *s == '\t') && s < e_lab)
+ s++;
+ if (s < e_lab)
+ fprintf(output, s[0]=='/' && s[1]=='*' ? "\t%.*s" : "\t/* %.*s */",
+ (int)(e_lab - s), s);
+ }
+ else fprintf(output, "%.*s", (int)(e_lab - s_lab), s_lab);
+ cur_col = count_spaces(cur_col, s_lab);
+ }
+ else
+ cur_col = 1; /* there is no label section */
+
+ ps.pcase = false;
+
+ if (s_code != e_code) { /* print code section, if any */
+ char *p;
+
+ if (comment_open) {
+ comment_open = 0;
+ fprintf(output, ".*/\n");
+ }
+ target_col = compute_code_target();
+ {
+ int i;
+
+ for (i = 0; i < ps.p_l_follow; i++)
+ if (ps.paren_indents[i] >= 0)
+ ps.paren_indents[i] = -(ps.paren_indents[i] + target_col);
+ }
+ cur_col = pad_output(cur_col, target_col);
+ for (p = s_code; p < e_code; p++)
+ if (*p == (char) 0200)
+ fprintf(output, "%d", target_col * 7);
+ else
+ putc(*p, output);
+ cur_col = count_spaces(cur_col, s_code);
+ }
+ if (s_com != e_com) {
+ if (troff) {
+ int all_here = 0;
+ char *p;
+
+ if (e_com[-1] == '/' && e_com[-2] == '*')
+ e_com -= 2, all_here++;
+ while (e_com > s_com && e_com[-1] == ' ')
+ e_com--;
+ *e_com = 0;
+ p = s_com;
+ while (*p == ' ')
+ p++;
+ if (p[0] == '/' && p[1] == '*')
+ p += 2, all_here++;
+ else if (p[0] == '*')
+ p += p[1] == '/' ? 2 : 1;
+ while (*p == ' ')
+ p++;
+ if (*p == 0)
+ goto inhibit_newline;
+ if (comment_open < 2 && ps.box_com) {
+ comment_open = 0;
+ fprintf(output, ".*/\n");
+ }
+ if (comment_open == 0) {
+ if ('a' <= *p && *p <= 'z')
+ *p = *p + 'A' - 'a';
+ if (e_com - p < 50 && all_here == 2) {
+ char *follow = p;
+ fprintf(output, "\n.nr C! \\w\1");
+ while (follow < e_com) {
+ switch (*follow) {
+ case '\n':
+ putc(' ', output);
+ case 1:
+ break;
+ case '\\':
+ putc('\\', output);
+ default:
+ putc(*follow, output);
+ }
+ follow++;
+ }
+ putc(1, output);
+ }
+ fprintf(output, "\n./* %dp %d %dp\n",
+ ps.com_col * 7,
+ (s_code != e_code || s_lab != e_lab) - ps.box_com,
+ target_col * 7);
+ }
+ comment_open = 1 + ps.box_com;
+ while (*p) {
+ if (*p == BACKSLASH)
+ putc(BACKSLASH, output);
+ putc(*p++, output);
+ }
+ }
+ else { /* print comment, if any */
+ int target = ps.com_col;
+ char *com_st = s_com;
+
+ target += ps.comment_delta;
+ while (*com_st == '\t')
+ com_st++, target += 8; /* ? */
+ while (target <= 0)
+ if (*com_st == ' ')
+ target++, com_st++;
+ else if (*com_st == '\t')
+ target = ((target - 1) & ~7) + 9, com_st++;
+ else
+ target = 1;
+ if (cur_col > target) { /* if comment can't fit on this line,
+ * put it on next line */
+ putc('\n', output);
+ cur_col = 1;
+ ++ps.out_lines;
+ }
+ while (e_com > com_st && isspace(e_com[-1]))
+ e_com--;
+ cur_col = pad_output(cur_col, target);
+ if (!ps.box_com) {
+ if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1)) {
+ if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1)
+ com_st[1] = '*';
+ else
+ fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output);
+ }
+ }
+ fwrite(com_st, e_com - com_st, 1, output);
+ ps.comment_delta = ps.n_comment_delta;
+ cur_col = count_spaces(cur_col, com_st);
+ ++ps.com_lines; /* count lines with comments */
+ }
+ }
+ if (ps.use_ff)
+ putc('\014', output);
+ else
+ putc('\n', output);
+inhibit_newline:
+ ++ps.out_lines;
+ if (ps.just_saw_decl == 1 && blanklines_after_declarations) {
+ prefix_blankline_requested = 1;
+ ps.just_saw_decl = 0;
+ }
+ else
+ prefix_blankline_requested = postfix_blankline_requested;
+ postfix_blankline_requested = 0;
+ }
+ ps.decl_on_line = ps.in_decl; /* if we are in the middle of a
+ * declaration, remember that fact for
+ * proper comment indentation */
+ ps.ind_stmt = ps.in_stmt & ~ps.in_decl; /* next line should be
+ * indented if we have not
+ * completed this stmt and if
+ * we are not in the middle of
+ * a declaration */
+ ps.use_ff = false;
+ ps.dumped_decl_indent = 0;
+ *(e_lab = s_lab) = '\0'; /* reset buffers */
+ *(e_code = s_code) = '\0';
+ *(e_com = s_com) = '\0';
+ ps.ind_level = ps.i_l_follow;
+ ps.paren_level = ps.p_l_follow;
+ paren_target = -ps.paren_indents[ps.paren_level - 1];
+ not_first_line = 1;
+}
+
+int
+compute_code_target(void)
+{
+ int target_col = ps.ind_size * ps.ind_level + 1;
+
+ if (ps.paren_level)
+ if (!lineup_to_parens)
+ target_col += continuation_indent
+ * (2 * continuation_indent == ps.ind_size ? 1 : ps.paren_level);
+ else {
+ int w;
+ int t = paren_target;
+
+ if ((w = count_spaces(t, s_code) - max_col) > 0
+ && count_spaces(target_col, s_code) <= max_col) {
+ t -= w + 1;
+ if (t > target_col)
+ target_col = t;
+ }
+ else
+ target_col = t;
+ }
+ else if (ps.ind_stmt)
+ target_col += continuation_indent;
+ return target_col;
+}
+
+int
+compute_label_target(void)
+{
+ return
+ ps.pcase ? (int) (case_ind * ps.ind_size) + 1
+ : *s_lab == '#' ? 1
+ : ps.ind_size * (ps.ind_level - label_offset) + 1;
+}
+
+
+/*
+ * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
+ *
+ * All rights reserved
+ *
+ *
+ * NAME: fill_buffer
+ *
+ * FUNCTION: Reads one block of input into input_buffer
+ *
+ * HISTORY: initial coding November 1976 D A Willcox of CAC 1/7/77 A
+ * Willcox of CAC Added check for switch back to partly full input
+ * buffer from temporary buffer
+ *
+ */
+void
+fill_buffer(void)
+{ /* this routine reads stuff from the input */
+ char *p;
+ int i;
+ FILE *f = input;
+
+ if (bp_save != 0) { /* there is a partly filled input buffer left */
+ buf_ptr = bp_save; /* dont read anything, just switch buffers */
+ buf_end = be_save;
+ bp_save = be_save = 0;
+ if (buf_ptr < buf_end)
+ return; /* only return if there is really something in
+ * this buffer */
+ }
+ for (p = in_buffer;;) {
+ if (p >= in_buffer_limit) {
+ int size = (in_buffer_limit - in_buffer) * 2 + 10;
+ int offset = p - in_buffer;
+ in_buffer = realloc(in_buffer, size);
+ if (in_buffer == NULL)
+ errx(1, "input line too long");
+ p = in_buffer + offset;
+ in_buffer_limit = in_buffer + size - 2;
+ }
+ if ((i = getc(f)) == EOF) {
+ *p++ = ' ';
+ *p++ = '\n';
+ had_eof = true;
+ break;
+ }
+ *p++ = i;
+ if (i == '\n')
+ break;
+ }
+ buf_ptr = in_buffer;
+ buf_end = p;
+ if (p[-2] == '/' && p[-3] == '*') {
+ if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
+ fill_buffer(); /* flush indent error message */
+ else {
+ int com = 0;
+
+ p = in_buffer;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '/' && p[1] == '*') {
+ p += 2;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
+ && p[4] == 'N' && p[5] == 'T') {
+ p += 6;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '*')
+ com = 1;
+ else if (*p == 'O') {
+ if (*++p == 'N')
+ p++, com = 1;
+ else if (*p == 'F' && *++p == 'F')
+ p++, com = 2;
+ }
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) {
+ if (s_com != e_com || s_lab != e_lab || s_code != e_code)
+ dump_line();
+ if (!(inhibit_formatting = com - 1)) {
+ n_real_blanklines = 0;
+ postfix_blankline_requested = 0;
+ prefix_blankline_requested = 0;
+ suppress_blanklines = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (inhibit_formatting) {
+ p = in_buffer;
+ do
+ putc(*p, output);
+ while (*p++ != '\n');
+ }
+}
+
+/*
+ * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
+ *
+ * All rights reserved
+ *
+ *
+ * NAME: pad_output
+ *
+ * FUNCTION: Writes tabs and spaces to move the current column up to the desired
+ * position.
+ *
+ * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
+ *
+ * PARAMETERS: current integer The current column target
+ * nteger The desired column
+ *
+ * RETURNS: Integer value of the new column. (If current >= target, no action is
+ * taken, and current is returned.
+ *
+ * GLOBALS: None
+ *
+ * CALLS: write (sys)
+ *
+ * CALLED BY: dump_line
+ *
+ * HISTORY: initial coding November 1976 D A Willcox of CAC
+ *
+ */
+static int
+pad_output(int current, int target)
+ /* writes tabs and blanks (if necessary) to
+ * get the current output position up to the
+ * target column */
+ /* current: the current column value */
+ /* target: position we want it at */
+{
+ int curr; /* internal column pointer */
+ int tcur;
+
+ if (troff)
+ fprintf(output, "\\h'|%dp'", (target - 1) * 7);
+ else {
+ if (current >= target)
+ return (current); /* line is already long enough */
+ curr = current;
+ if (use_tabs) {
+ while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) {
+ putc('\t', output);
+ curr = tcur;
+ }
+ }
+ while (curr++ < target)
+ putc(' ', output); /* pad with final blanks */
+ }
+ return (target);
+}
+
+/*
+ * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
+ *
+ * All rights reserved
+ *
+ *
+ * NAME: count_spaces
+ *
+ * FUNCTION: Find out where printing of a given string will leave the current
+ * character position on output.
+ *
+ * ALGORITHM: Run thru input string and add appropriate values to current
+ * position.
+ *
+ * RETURNS: Integer value of position after printing "buffer" starting in column
+ * "current".
+ *
+ * HISTORY: initial coding November 1976 D A Willcox of CAC
+ *
+ */
+int
+count_spaces(int current, char *buffer)
+/*
+ * this routine figures out where the character position will be after
+ * printing the text in buffer starting at column "current"
+ */
+{
+ char *buf; /* used to look thru buffer */
+ int cur; /* current character counter */
+
+ cur = current;
+
+ for (buf = buffer; *buf != '\0'; ++buf) {
+ switch (*buf) {
+
+ case '\n':
+ case 014: /* form feed */
+ cur = 1;
+ break;
+
+ case '\t':
+ cur = ((cur - 1) & tabmask) + tabsize + 1;
+ break;
+
+ case 010: /* backspace */
+ --cur;
+ break;
+
+ default:
+ ++cur;
+ break;
+ } /* end of switch */
+ } /* end of for loop */
+ return (cur);
+}
+
+void
+diag4(int level, const char *msg, int a, int b)
+{
+ if (level)
+ found_err = 1;
+ if (output == stdout) {
+ fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+ fprintf(stdout, msg, a, b);
+ fprintf(stdout, " */\n");
+ }
+ else {
+ fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+ fprintf(stderr, msg, a, b);
+ fprintf(stderr, "\n");
+ }
+}
+
+void
+diag3(int level, const char *msg, int a)
+{
+ if (level)
+ found_err = 1;
+ if (output == stdout) {
+ fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+ fprintf(stdout, msg, a);
+ fprintf(stdout, " */\n");
+ }
+ else {
+ fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+ fprintf(stderr, msg, a);
+ fprintf(stderr, "\n");
+ }
+}
+
+void
+diag2(int level, const char *msg)
+{
+ if (level)
+ found_err = 1;
+ if (output == stdout) {
+ fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+ fprintf(stdout, "%s", msg);
+ fprintf(stdout, " */\n");
+ }
+ else {
+ fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
+ fprintf(stderr, "%s", msg);
+ fprintf(stderr, "\n");
+ }
+}
+
+void
+writefdef(struct fstate *f, int nm)
+{
+ fprintf(output, ".ds f%c %s\n.nr s%c %d\n",
+ nm, f->font, nm, f->size);
+}
+
+char *
+chfont(struct fstate *of, struct fstate *nf, char *s)
+{
+ if (of->font[0] != nf->font[0]
+ || of->font[1] != nf->font[1]) {
+ *s++ = '\\';
+ *s++ = 'f';
+ if (nf->font[1]) {
+ *s++ = '(';
+ *s++ = nf->font[0];
+ *s++ = nf->font[1];
+ }
+ else
+ *s++ = nf->font[0];
+ }
+ if (nf->size != of->size) {
+ *s++ = '\\';
+ *s++ = 's';
+ if (nf->size < of->size) {
+ *s++ = '-';
+ *s++ = '0' + of->size - nf->size;
+ }
+ else {
+ *s++ = '+';
+ *s++ = '0' + nf->size - of->size;
+ }
+ }
+ return s;
+}
+
+void
+parsefont(struct fstate *f, const char *s0)
+{
+ const char *s = s0;
+ int sizedelta = 0;
+
+ bzero(f, sizeof *f);
+ while (*s) {
+ if (isdigit(*s))
+ f->size = f->size * 10 + *s - '0';
+ else if (isupper(*s))
+ if (f->font[0])
+ f->font[1] = *s;
+ else
+ f->font[0] = *s;
+ else if (*s == 'c')
+ f->allcaps = 1;
+ else if (*s == '+')
+ sizedelta++;
+ else if (*s == '-')
+ sizedelta--;
+ else {
+ errx(1, "bad font specification: %s", s0);
+ }
+ s++;
+ }
+ if (f->font[0] == 0)
+ f->font[0] = 'R';
+ if (bodyf.size == 0)
+ bodyf.size = 11;
+ if (f->size == 0)
+ f->size = bodyf.size + sizedelta;
+ else if (sizedelta > 0)
+ f->size += bodyf.size;
+ else
+ f->size = bodyf.size - f->size;
+}
diff --git a/developer_cmds/indent/lexi.c b/developer_cmds/indent/lexi.c
new file mode 100644
index 0000000..fbee368
--- /dev/null
+++ b/developer_cmds/indent/lexi.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)lexi.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/indent/lexi.c,v 1.21 2010/04/15 21:41:07 avg Exp $");
+
+/*
+ * Here we have the token scanner for indent. It scans off one token and puts
+ * it in the global variable "token". It returns a code, indicating the type
+ * of token scanned.
+ */
+
+#include <err.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "indent_globs.h"
+#include "indent_codes.h"
+#include "indent.h"
+
+#define alphanum 1
+#define opchar 3
+
+struct templ {
+ const char *rwd;
+ int rwcode;
+};
+
+struct templ specials[1000] =
+{
+ {"switch", 1},
+ {"case", 2},
+ {"break", 0},
+ {"struct", 3},
+ {"union", 3},
+ {"enum", 3},
+ {"default", 2},
+ {"int", 4},
+ {"char", 4},
+ {"float", 4},
+ {"double", 4},
+ {"long", 4},
+ {"short", 4},
+ {"typdef", 4},
+ {"unsigned", 4},
+ {"register", 4},
+ {"static", 4},
+ {"global", 4},
+ {"extern", 4},
+ {"void", 4},
+ {"const", 4},
+ {"volatile", 4},
+ {"goto", 0},
+ {"return", 0},
+ {"if", 5},
+ {"while", 5},
+ {"for", 5},
+ {"else", 6},
+ {"do", 6},
+ {"sizeof", 7},
+ {0, 0}
+};
+
+char chartype[128] =
+{ /* this is used to facilitate the decision of
+ * what type (alphanumeric, operator) each
+ * character is */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 3, 0, 0, 1, 3, 3, 0,
+ 0, 0, 3, 3, 0, 3, 0, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 0, 0, 3, 3, 3, 3,
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 3, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 3, 0, 3, 0
+};
+
+int
+lexi(void)
+{
+ int unary_delim; /* this is set to 1 if the current token
+ * forces a following operator to be unary */
+ static int last_code; /* the last token type returned */
+ static int l_struct; /* set to 1 if the last token was 'struct' */
+ int code; /* internal code to be returned */
+ char qchar; /* the delimiter character for a string */
+
+ e_token = s_token; /* point to start of place to save token */
+ unary_delim = false;
+ ps.col_1 = ps.last_nl; /* tell world that this token started in
+ * column 1 iff the last thing scanned was nl */
+ ps.last_nl = false;
+
+ while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */
+ ps.col_1 = false; /* leading blanks imply token is not in column
+ * 1 */
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+ }
+
+ /* Scan an alphanumeric token */
+ if (chartype[(int)*buf_ptr] == alphanum || (buf_ptr[0] == '.' && isdigit(buf_ptr[1]))) {
+ /*
+ * we have a character or number
+ */
+ const char *j; /* used for searching thru list of
+ *
+ * reserved words */
+ struct templ *p;
+
+ if (isdigit(*buf_ptr) || (buf_ptr[0] == '.' && isdigit(buf_ptr[1]))) {
+ int seendot = 0,
+ seenexp = 0,
+ seensfx = 0;
+ if (*buf_ptr == '0' &&
+ (buf_ptr[1] == 'x' || buf_ptr[1] == 'X')) {
+ *e_token++ = *buf_ptr++;
+ *e_token++ = *buf_ptr++;
+ while (isxdigit(*buf_ptr)) {
+ CHECK_SIZE_TOKEN;
+ *e_token++ = *buf_ptr++;
+ }
+ }
+ else
+ while (1) {
+ if (*buf_ptr == '.') {
+ if (seendot)
+ break;
+ else
+ seendot++;
+ }
+ CHECK_SIZE_TOKEN;
+ *e_token++ = *buf_ptr++;
+ if (!isdigit(*buf_ptr) && *buf_ptr != '.') {
+ if ((*buf_ptr != 'E' && *buf_ptr != 'e') || seenexp)
+ break;
+ else {
+ seenexp++;
+ seendot++;
+ CHECK_SIZE_TOKEN;
+ *e_token++ = *buf_ptr++;
+ if (*buf_ptr == '+' || *buf_ptr == '-')
+ *e_token++ = *buf_ptr++;
+ }
+ }
+ }
+ while (1) {
+ if (!(seensfx & 1) &&
+ (*buf_ptr == 'U' || *buf_ptr == 'u')) {
+ CHECK_SIZE_TOKEN;
+ *e_token++ = *buf_ptr++;
+ seensfx |= 1;
+ continue;
+ }
+ if (!(seensfx & 2) &&
+ (*buf_ptr == 'L' || *buf_ptr == 'l')) {
+ CHECK_SIZE_TOKEN;
+ if (buf_ptr[1] == buf_ptr[0])
+ *e_token++ = *buf_ptr++;
+ *e_token++ = *buf_ptr++;
+ seensfx |= 2;
+ continue;
+ }
+ break;
+ }
+ }
+ else
+ while (chartype[(int)*buf_ptr] == alphanum || *buf_ptr == BACKSLASH) {
+ /* fill_buffer() terminates buffer with newline */
+ if (*buf_ptr == BACKSLASH) {
+ if (*(buf_ptr + 1) == '\n') {
+ buf_ptr += 2;
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+ } else
+ break;
+ }
+ CHECK_SIZE_TOKEN;
+ /* copy it over */
+ *e_token++ = *buf_ptr++;
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+ }
+ *e_token++ = '\0';
+ while (*buf_ptr == ' ' || *buf_ptr == '\t') { /* get rid of blanks */
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+ }
+ ps.its_a_keyword = false;
+ ps.sizeof_keyword = false;
+ if (l_struct && !ps.p_l_follow) {
+ /* if last token was 'struct' and we're not
+ * in parentheses, then this token
+ * should be treated as a declaration */
+ l_struct = false;
+ last_code = ident;
+ ps.last_u_d = true;
+ return (decl);
+ }
+ ps.last_u_d = l_struct; /* Operator after identifier is binary
+ * unless last token was 'struct' */
+ l_struct = false;
+ last_code = ident; /* Remember that this is the code we will
+ * return */
+
+ if (auto_typedefs) {
+ const char *q = s_token;
+ size_t q_len = strlen(q);
+ /* Check if we have an "_t" in the end */
+ if (q_len > 2 &&
+ (strcmp(q + q_len - 2, "_t") == 0)) {
+ ps.its_a_keyword = true;
+ ps.last_u_d = true;
+ goto found_auto_typedef;
+ }
+ }
+
+ /*
+ * This loop will check if the token is a keyword.
+ */
+ for (p = specials; (j = p->rwd) != 0; p++) {
+ const char *q = s_token; /* point at scanned token */
+ if (*j++ != *q++ || *j++ != *q++)
+ continue; /* This test depends on the fact that
+ * identifiers are always at least 1 character
+ * long (ie. the first two bytes of the
+ * identifier are always meaningful) */
+ if (q[-1] == 0)
+ break; /* If its a one-character identifier */
+ while (*q++ == *j)
+ if (*j++ == 0)
+ goto found_keyword; /* I wish that C had a multi-level
+ * break... */
+ }
+ if (p->rwd) { /* we have a keyword */
+ found_keyword:
+ ps.its_a_keyword = true;
+ ps.last_u_d = true;
+ switch (p->rwcode) {
+ case 1: /* it is a switch */
+ return (swstmt);
+ case 2: /* a case or default */
+ return (casestmt);
+
+ case 3: /* a "struct" */
+ /*
+ * Next time around, we will want to know that we have had a
+ * 'struct'
+ */
+ l_struct = true;
+ /* FALLTHROUGH */
+
+ case 4: /* one of the declaration keywords */
+ found_auto_typedef:
+ if (ps.p_l_follow) {
+ ps.cast_mask |= (1 << ps.p_l_follow) & ~ps.sizeof_mask;
+ break; /* inside parens: cast, param list or sizeof */
+ }
+ last_code = decl;
+ return (decl);
+
+ case 5: /* if, while, for */
+ return (sp_paren);
+
+ case 6: /* do, else */
+ return (sp_nparen);
+
+ case 7:
+ ps.sizeof_keyword = true;
+ default: /* all others are treated like any other
+ * identifier */
+ return (ident);
+ } /* end of switch */
+ } /* end of if (found_it) */
+ if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0) {
+ char *tp = buf_ptr;
+ while (tp < buf_end)
+ if (*tp++ == ')' && (*tp == ';' || *tp == ','))
+ goto not_proc;
+ strncpy(ps.procname, token, sizeof ps.procname - 1);
+ ps.in_parameter_declaration = 1;
+ rparen_count = 1;
+ not_proc:;
+ }
+ /*
+ * The following hack attempts to guess whether or not the current
+ * token is in fact a declaration keyword -- one that has been
+ * typedefd
+ */
+ if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr) || *buf_ptr == '_')
+ && !ps.p_l_follow
+ && !ps.block_init
+ && (ps.last_token == rparen || ps.last_token == semicolon ||
+ ps.last_token == decl ||
+ ps.last_token == lbrace || ps.last_token == rbrace)) {
+ ps.its_a_keyword = true;
+ ps.last_u_d = true;
+ last_code = decl;
+ return decl;
+ }
+ if (last_code == decl) /* if this is a declared variable, then
+ * following sign is unary */
+ ps.last_u_d = true; /* will make "int a -1" work */
+ last_code = ident;
+ return (ident); /* the ident is not in the list */
+ } /* end of procesing for alpanum character */
+
+ /* Scan a non-alphanumeric token */
+
+ *e_token++ = *buf_ptr; /* if it is only a one-character token, it is
+ * moved here */
+ *e_token = '\0';
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+
+ switch (*token) {
+ case '\n':
+ unary_delim = ps.last_u_d;
+ ps.last_nl = true; /* remember that we just had a newline */
+ code = (had_eof ? 0 : newline);
+
+ /*
+ * if data has been exhausted, the newline is a dummy, and we should
+ * return code to stop
+ */
+ break;
+
+ case '\'': /* start of quoted character */
+ case '"': /* start of string */
+ qchar = *token;
+ if (troff) {
+ e_token[-1] = '`';
+ if (qchar == '"')
+ *e_token++ = '`';
+ e_token = chfont(&bodyf, &stringf, e_token);
+ }
+ do { /* copy the string */
+ while (1) { /* move one character or [/<char>]<char> */
+ if (*buf_ptr == '\n') {
+ diag2(1, "Unterminated literal");
+ goto stop_lit;
+ }
+ CHECK_SIZE_TOKEN; /* Only have to do this once in this loop,
+ * since CHECK_SIZE guarantees that there
+ * are at least 5 entries left */
+ *e_token = *buf_ptr++;
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+ if (*e_token == BACKSLASH) { /* if escape, copy extra char */
+ if (*buf_ptr == '\n') /* check for escaped newline */
+ ++line_no;
+ if (troff) {
+ *++e_token = BACKSLASH;
+ if (*buf_ptr == BACKSLASH)
+ *++e_token = BACKSLASH;
+ }
+ *++e_token = *buf_ptr++;
+ ++e_token; /* we must increment this again because we
+ * copied two chars */
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+ }
+ else
+ break; /* we copied one character */
+ } /* end of while (1) */
+ } while (*e_token++ != qchar);
+ if (troff) {
+ e_token = chfont(&stringf, &bodyf, e_token - 1);
+ if (qchar == '"')
+ *e_token++ = '\'';
+ }
+stop_lit:
+ code = ident;
+ break;
+
+ case ('('):
+ case ('['):
+ unary_delim = true;
+ code = lparen;
+ break;
+
+ case (')'):
+ case (']'):
+ code = rparen;
+ break;
+
+ case '#':
+ unary_delim = ps.last_u_d;
+ code = preesc;
+ break;
+
+ case '?':
+ unary_delim = true;
+ code = question;
+ break;
+
+ case (':'):
+ code = colon;
+ unary_delim = true;
+ break;
+
+ case (';'):
+ unary_delim = true;
+ code = semicolon;
+ break;
+
+ case ('{'):
+ unary_delim = true;
+
+ /*
+ * if (ps.in_or_st) ps.block_init = 1;
+ */
+ /* ? code = ps.block_init ? lparen : lbrace; */
+ code = lbrace;
+ break;
+
+ case ('}'):
+ unary_delim = true;
+ /* ? code = ps.block_init ? rparen : rbrace; */
+ code = rbrace;
+ break;
+
+ case 014: /* a form feed */
+ unary_delim = ps.last_u_d;
+ ps.last_nl = true; /* remember this so we can set 'ps.col_1'
+ * right */
+ code = form_feed;
+ break;
+
+ case (','):
+ unary_delim = true;
+ code = comma;
+ break;
+
+ case '.':
+ unary_delim = false;
+ code = period;
+ break;
+
+ case '-':
+ case '+': /* check for -, +, --, ++ */
+ code = (ps.last_u_d ? unary_op : binary_op);
+ unary_delim = true;
+
+ if (*buf_ptr == token[0]) {
+ /* check for doubled character */
+ *e_token++ = *buf_ptr++;
+ /* buffer overflow will be checked at end of loop */
+ if (last_code == ident || last_code == rparen) {
+ code = (ps.last_u_d ? unary_op : postop);
+ /* check for following ++ or -- */
+ unary_delim = false;
+ }
+ }
+ else if (*buf_ptr == '=')
+ /* check for operator += */
+ *e_token++ = *buf_ptr++;
+ else if (*buf_ptr == '>') {
+ /* check for operator -> */
+ *e_token++ = *buf_ptr++;
+ if (!pointer_as_binop) {
+ unary_delim = false;
+ code = unary_op;
+ ps.want_blank = false;
+ }
+ }
+ break; /* buffer overflow will be checked at end of
+ * switch */
+
+ case '=':
+ if (ps.in_or_st)
+ ps.block_init = 1;
+#ifdef undef
+ if (chartype[*buf_ptr] == opchar) { /* we have two char assignment */
+ e_token[-1] = *buf_ptr++;
+ if ((e_token[-1] == '<' || e_token[-1] == '>') && e_token[-1] == *buf_ptr)
+ *e_token++ = *buf_ptr++;
+ *e_token++ = '='; /* Flip =+ to += */
+ *e_token = 0;
+ }
+#else
+ if (*buf_ptr == '=') {/* == */
+ *e_token++ = '='; /* Flip =+ to += */
+ buf_ptr++;
+ *e_token = 0;
+ }
+#endif
+ code = binary_op;
+ unary_delim = true;
+ break;
+ /* can drop thru!!! */
+
+ case '>':
+ case '<':
+ case '!': /* ops like <, <<, <=, !=, etc */
+ if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
+ *e_token++ = *buf_ptr;
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+ }
+ if (*buf_ptr == '=')
+ *e_token++ = *buf_ptr++;
+ code = (ps.last_u_d ? unary_op : binary_op);
+ unary_delim = true;
+ break;
+
+ default:
+ if (token[0] == '/' && *buf_ptr == '*') {
+ /* it is start of comment */
+ *e_token++ = '*';
+
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+
+ code = comment;
+ unary_delim = ps.last_u_d;
+ break;
+ }
+ while (*(e_token - 1) == *buf_ptr || *buf_ptr == '=') {
+ /*
+ * handle ||, &&, etc, and also things as in int *****i
+ */
+ *e_token++ = *buf_ptr;
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+ }
+ code = (ps.last_u_d ? unary_op : binary_op);
+ unary_delim = true;
+
+
+ } /* end of switch */
+ if (code != newline) {
+ l_struct = false;
+ last_code = code;
+ }
+ if (buf_ptr >= buf_end) /* check for input buffer empty */
+ fill_buffer();
+ ps.last_u_d = unary_delim;
+ *e_token = '\0'; /* null terminate the token */
+ return (code);
+}
+
+/*
+ * Add the given keyword to the keyword table, using val as the keyword type
+ */
+void
+addkey(char *key, int val)
+{
+ struct templ *p = specials;
+ while (p->rwd)
+ if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0)
+ return;
+ else
+ p++;
+ if (p >= specials + sizeof specials / sizeof specials[0])
+ return; /* For now, table overflows are silently
+ * ignored */
+ p->rwd = key;
+ p->rwcode = val;
+ p[1].rwd = 0;
+ p[1].rwcode = 0;
+}
diff --git a/developer_cmds/indent/parse.c b/developer_cmds/indent/parse.c
new file mode 100644
index 0000000..7720ff1
--- /dev/null
+++ b/developer_cmds/indent/parse.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/indent/parse.c,v 1.10 2003/06/15 09:28:17 charnier Exp $");
+
+#include <stdio.h>
+#include "indent_globs.h"
+#include "indent_codes.h"
+#include "indent.h"
+
+static void reduce(void);
+
+void
+parse(int tk) /* tk: the code for the construct scanned */
+{
+ int i;
+
+#ifdef debug
+ printf("%2d - %s\n", tk, token);
+#endif
+
+ while (ps.p_stack[ps.tos] == ifhead && tk != elselit) {
+ /* true if we have an if without an else */
+ ps.p_stack[ps.tos] = stmt; /* apply the if(..) stmt ::= stmt
+ * reduction */
+ reduce(); /* see if this allows any reduction */
+ }
+
+
+ switch (tk) { /* go on and figure out what to do with the
+ * input */
+
+ case decl: /* scanned a declaration word */
+ ps.search_brace = btype_2;
+ /* indicate that following brace should be on same line */
+ if (ps.p_stack[ps.tos] != decl) { /* only put one declaration
+ * onto stack */
+ break_comma = true; /* while in declaration, newline should be
+ * forced after comma */
+ ps.p_stack[++ps.tos] = decl;
+ ps.il[ps.tos] = ps.i_l_follow;
+
+ if (ps.ljust_decl) {/* only do if we want left justified
+ * declarations */
+ ps.ind_level = 0;
+ for (i = ps.tos - 1; i > 0; --i)
+ if (ps.p_stack[i] == decl)
+ ++ps.ind_level; /* indentation is number of
+ * declaration levels deep we are */
+ ps.i_l_follow = ps.ind_level;
+ }
+ }
+ break;
+
+ case ifstmt: /* scanned if (...) */
+ if (ps.p_stack[ps.tos] == elsehead && ps.else_if) /* "else if ..." */
+ ps.i_l_follow = ps.il[ps.tos];
+ case dolit: /* 'do' */
+ case forstmt: /* for (...) */
+ ps.p_stack[++ps.tos] = tk;
+ ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
+ ++ps.i_l_follow; /* subsequent statements should be indented 1 */
+ ps.search_brace = btype_2;
+ break;
+
+ case lbrace: /* scanned { */
+ break_comma = false; /* don't break comma in an initial list */
+ if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl
+ || ps.p_stack[ps.tos] == stmtl)
+ ++ps.i_l_follow; /* it is a random, isolated stmt group or a
+ * declaration */
+ else {
+ if (s_code == e_code) {
+ /*
+ * only do this if there is nothing on the line
+ */
+ --ps.ind_level;
+ /*
+ * it is a group as part of a while, for, etc.
+ */
+ if (ps.p_stack[ps.tos] == swstmt && ps.case_indent >= 1)
+ --ps.ind_level;
+ /*
+ * for a switch, brace should be two levels out from the code
+ */
+ }
+ }
+
+ ps.p_stack[++ps.tos] = lbrace;
+ ps.il[ps.tos] = ps.ind_level;
+ ps.p_stack[++ps.tos] = stmt;
+ /* allow null stmt between braces */
+ ps.il[ps.tos] = ps.i_l_follow;
+ break;
+
+ case whilestmt: /* scanned while (...) */
+ if (ps.p_stack[ps.tos] == dohead) {
+ /* it is matched with do stmt */
+ ps.ind_level = ps.i_l_follow = ps.il[ps.tos];
+ ps.p_stack[++ps.tos] = whilestmt;
+ ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
+ }
+ else { /* it is a while loop */
+ ps.p_stack[++ps.tos] = whilestmt;
+ ps.il[ps.tos] = ps.i_l_follow;
+ ++ps.i_l_follow;
+ ps.search_brace = btype_2;
+ }
+
+ break;
+
+ case elselit: /* scanned an else */
+
+ if (ps.p_stack[ps.tos] != ifhead)
+ diag2(1, "Unmatched 'else'");
+ else {
+ ps.ind_level = ps.il[ps.tos]; /* indentation for else should
+ * be same as for if */
+ ps.i_l_follow = ps.ind_level + 1; /* everything following should
+ * be in 1 level */
+ ps.p_stack[ps.tos] = elsehead;
+ /* remember if with else */
+ ps.search_brace = btype_2 | ps.else_if;
+ }
+ break;
+
+ case rbrace: /* scanned a } */
+ /* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */
+ if (ps.p_stack[ps.tos - 1] == lbrace) {
+ ps.ind_level = ps.i_l_follow = ps.il[--ps.tos];
+ ps.p_stack[ps.tos] = stmt;
+ }
+ else
+ diag2(1, "Statement nesting error");
+ break;
+
+ case swstmt: /* had switch (...) */
+ ps.p_stack[++ps.tos] = swstmt;
+ ps.cstk[ps.tos] = case_ind;
+ /* save current case indent level */
+ ps.il[ps.tos] = ps.i_l_follow;
+ case_ind = ps.i_l_follow + ps.case_indent; /* cases should be one
+ * level down from
+ * switch */
+ ps.i_l_follow += ps.case_indent + 1; /* statements should be two
+ * levels in */
+ ps.search_brace = btype_2;
+ break;
+
+ case semicolon: /* this indicates a simple stmt */
+ break_comma = false; /* turn off flag to break after commas in a
+ * declaration */
+ ps.p_stack[++ps.tos] = stmt;
+ ps.il[ps.tos] = ps.ind_level;
+ break;
+
+ default: /* this is an error */
+ diag2(1, "Unknown code to parser");
+ return;
+
+
+ } /* end of switch */
+
+ reduce(); /* see if any reduction can be done */
+
+#ifdef debug
+ for (i = 1; i <= ps.tos; ++i)
+ printf("(%d %d)", ps.p_stack[i], ps.il[i]);
+ printf("\n");
+#endif
+
+ return;
+}
+
+/*
+ * NAME: reduce
+ *
+ * FUNCTION: Implements the reduce part of the parsing algorithm
+ *
+ * ALGORITHM: The following reductions are done. Reductions are repeated
+ * until no more are possible.
+ *
+ * Old TOS New TOS
+ * <stmt> <stmt> <stmtl>
+ * <stmtl> <stmt> <stmtl>
+ * do <stmt> "dostmt"
+ * if <stmt> "ifstmt"
+ * switch <stmt> <stmt>
+ * decl <stmt> <stmt>
+ * "ifelse" <stmt> <stmt>
+ * for <stmt> <stmt>
+ * while <stmt> <stmt>
+ * "dostmt" while <stmt>
+ *
+ * On each reduction, ps.i_l_follow (the indentation for the following line)
+ * is set to the indentation level associated with the old TOS.
+ *
+ * PARAMETERS: None
+ *
+ * RETURNS: Nothing
+ *
+ * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos =
+ *
+ * CALLS: None
+ *
+ * CALLED BY: parse
+ *
+ * HISTORY: initial coding November 1976 D A Willcox of CAC
+ *
+ */
+/*----------------------------------------------*\
+| REDUCTION PHASE |
+\*----------------------------------------------*/
+static void
+reduce(void)
+{
+ int i;
+
+ for (;;) { /* keep looping until there is nothing left to
+ * reduce */
+
+ switch (ps.p_stack[ps.tos]) {
+
+ case stmt:
+ switch (ps.p_stack[ps.tos - 1]) {
+
+ case stmt:
+ case stmtl:
+ /* stmtl stmt or stmt stmt */
+ ps.p_stack[--ps.tos] = stmtl;
+ break;
+
+ case dolit: /* <do> <stmt> */
+ ps.p_stack[--ps.tos] = dohead;
+ ps.i_l_follow = ps.il[ps.tos];
+ break;
+
+ case ifstmt:
+ /* <if> <stmt> */
+ ps.p_stack[--ps.tos] = ifhead;
+ for (i = ps.tos - 1;
+ (
+ ps.p_stack[i] != stmt
+ &&
+ ps.p_stack[i] != stmtl
+ &&
+ ps.p_stack[i] != lbrace
+ );
+ --i);
+ ps.i_l_follow = ps.il[i];
+ /*
+ * for the time being, we will assume that there is no else on
+ * this if, and set the indentation level accordingly. If an
+ * else is scanned, it will be fixed up later
+ */
+ break;
+
+ case swstmt:
+ /* <switch> <stmt> */
+ case_ind = ps.cstk[ps.tos - 1];
+
+ case decl: /* finish of a declaration */
+ case elsehead:
+ /* <<if> <stmt> else> <stmt> */
+ case forstmt:
+ /* <for> <stmt> */
+ case whilestmt:
+ /* <while> <stmt> */
+ ps.p_stack[--ps.tos] = stmt;
+ ps.i_l_follow = ps.il[ps.tos];
+ break;
+
+ default: /* <anything else> <stmt> */
+ return;
+
+ } /* end of section for <stmt> on top of stack */
+ break;
+
+ case whilestmt: /* while (...) on top */
+ if (ps.p_stack[ps.tos - 1] == dohead) {
+ /* it is termination of a do while */
+ ps.tos -= 2;
+ break;
+ }
+ else
+ return;
+
+ default: /* anything else on top */
+ return;
+
+ }
+ }
+}
diff --git a/developer_cmds/indent/pr_comment.c b/developer_cmds/indent/pr_comment.c
new file mode 100644
index 0000000..ad7fe2e
--- /dev/null
+++ b/developer_cmds/indent/pr_comment.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 1985 Sun Microsystems, Inc.
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)pr_comment.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/indent/pr_comment.c,v 1.8 2003/06/15 09:28:17 charnier Exp $");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "indent_globs.h"
+#include "indent.h"
+/*
+ * NAME:
+ * pr_comment
+ *
+ * FUNCTION:
+ * This routine takes care of scanning and printing comments.
+ *
+ * ALGORITHM:
+ * 1) Decide where the comment should be aligned, and if lines should
+ * be broken.
+ * 2) If lines should not be broken and filled, just copy up to end of
+ * comment.
+ * 3) If lines should be filled, then scan thru input_buffer copying
+ * characters to com_buf. Remember where the last blank, tab, or
+ * newline was. When line is filled, print up to last blank and
+ * continue copying.
+ *
+ * HISTORY:
+ * November 1976 D A Willcox of CAC Initial coding
+ * 12/6/76 D A Willcox of CAC Modification to handle
+ * UNIX-style comments
+ *
+ */
+
+/*
+ * this routine processes comments. It makes an attempt to keep comments from
+ * going over the max line length. If a line is too long, it moves everything
+ * from the last blank to the next comment line. Blanks and tabs from the
+ * beginning of the input line are removed
+ */
+
+void
+pr_comment(void)
+{
+ int now_col; /* column we are in now */
+ int adj_max_col; /* Adjusted max_col for when we decide to
+ * spill comments over the right margin */
+ char *last_bl; /* points to the last blank in the output
+ * buffer */
+ char *t_ptr; /* used for moving string */
+ int unix_comment; /* tri-state variable used to decide if it is
+ * a unix-style comment. 0 means only blanks
+ * since /+*, 1 means regular style comment, 2
+ * means unix style comment */
+ int break_delim = comment_delimiter_on_blankline;
+ int l_just_saw_decl = ps.just_saw_decl;
+ /*
+ * int ps.last_nl = 0; true iff the last significant thing
+ * weve seen is a newline
+ */
+ int one_liner = 1; /* true iff this comment is a one-liner */
+ adj_max_col = max_col;
+ ps.just_saw_decl = 0;
+ last_bl = 0; /* no blanks found so far */
+ ps.box_com = false; /* at first, assume that we are not in
+ * a boxed comment or some other
+ * comment that should not be touched */
+ ++ps.out_coms; /* keep track of number of comments */
+ unix_comment = 1; /* set flag to let us figure out if there is a
+ * unix-style comment ** DISABLED: use 0 to
+ * reenable this hack! */
+
+ /* Figure where to align and how to treat the comment */
+
+ if (ps.col_1 && !format_col1_comments) { /* if comment starts in column
+ * 1 it should not be touched */
+ ps.box_com = true;
+ ps.com_col = 1;
+ }
+ else {
+ if (*buf_ptr == '-' || *buf_ptr == '*' ||
+ (*buf_ptr == '\n' && !format_block_comments)) {
+ ps.box_com = true; /* A comment with a '-' or '*' immediately
+ * after the /+* is assumed to be a boxed
+ * comment. A comment with a newline
+ * immediately after the /+* is assumed to
+ * be a block comment and is treated as a
+ * box comment unless format_block_comments
+ * is nonzero (the default). */
+ break_delim = 0;
+ }
+ if ( /* ps.bl_line && */ (s_lab == e_lab) && (s_code == e_code)) {
+ /* klg: check only if this line is blank */
+ /*
+ * If this (*and previous lines are*) blank, dont put comment way
+ * out at left
+ */
+ ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1;
+ adj_max_col = block_comment_max_col;
+ if (ps.com_col <= 1)
+ ps.com_col = 1 + !format_col1_comments;
+ }
+ else {
+ int target_col;
+ break_delim = 0;
+ if (s_code != e_code)
+ target_col = count_spaces(compute_code_target(), s_code);
+ else {
+ target_col = 1;
+ if (s_lab != e_lab)
+ target_col = count_spaces(compute_label_target(), s_lab);
+ }
+ ps.com_col = ps.decl_on_line || ps.ind_level == 0 ? ps.decl_com_ind : ps.com_ind;
+ if (ps.com_col < target_col)
+ ps.com_col = ((target_col + 7) & ~7) + 1;
+ if (ps.com_col + 24 > adj_max_col)
+ adj_max_col = ps.com_col + 24;
+ }
+ }
+ if (ps.box_com) {
+ buf_ptr[-2] = 0;
+ ps.n_comment_delta = 1 - count_spaces(1, in_buffer);
+ buf_ptr[-2] = '/';
+ }
+ else {
+ ps.n_comment_delta = 0;
+ while (*buf_ptr == ' ' || *buf_ptr == '\t')
+ buf_ptr++;
+ }
+ ps.comment_delta = 0;
+ *e_com++ = '/'; /* put '/' followed by '*' into buffer */
+ *e_com++ = '*';
+ if (*buf_ptr != ' ' && !ps.box_com)
+ *e_com++ = ' ';
+
+ *e_com = '\0';
+ if (troff) {
+ now_col = 1;
+ adj_max_col = 80;
+ }
+ else
+ now_col = count_spaces(ps.com_col, s_com); /* figure what column we
+ * would be in if we
+ * printed the comment
+ * now */
+
+ /* Start to copy the comment */
+
+ while (1) { /* this loop will go until the comment is
+ * copied */
+ if (*buf_ptr > 040 && *buf_ptr != '*')
+ ps.last_nl = 0;
+ CHECK_SIZE_COM;
+ switch (*buf_ptr) { /* this checks for various spcl cases */
+ case 014: /* check for a form feed */
+ if (!ps.box_com) { /* in a text comment, break the line here */
+ ps.use_ff = true;
+ /* fix so dump_line uses a form feed */
+ dump_line();
+ last_bl = 0;
+ *e_com++ = ' ';
+ *e_com++ = '*';
+ *e_com++ = ' ';
+ while (*++buf_ptr == ' ' || *buf_ptr == '\t');
+ }
+ else {
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+ *e_com++ = 014;
+ }
+ break;
+
+ case '\n':
+ if (had_eof) { /* check for unexpected eof */
+ printf("Unterminated comment\n");
+ *e_com = '\0';
+ dump_line();
+ return;
+ }
+ one_liner = 0;
+ if (ps.box_com || ps.last_nl) { /* if this is a boxed comment,
+ * we dont ignore the newline */
+ if (s_com == e_com) {
+ *e_com++ = ' ';
+ *e_com++ = ' ';
+ }
+ *e_com = '\0';
+ if (!ps.box_com && e_com - s_com > 3) {
+ if (break_delim == 1 && s_com[0] == '/'
+ && s_com[1] == '*' && s_com[2] == ' ') {
+ char *t = e_com;
+ break_delim = 2;
+ e_com = s_com + 2;
+ *e_com = 0;
+ if (blanklines_before_blockcomments)
+ prefix_blankline_requested = 1;
+ dump_line();
+ e_com = t;
+ s_com[0] = s_com[1] = s_com[2] = ' ';
+ }
+ dump_line();
+ CHECK_SIZE_COM;
+ *e_com++ = ' ';
+ *e_com++ = ' ';
+ }
+ dump_line();
+ now_col = ps.com_col;
+ }
+ else {
+ ps.last_nl = 1;
+ if (unix_comment != 1) { /* we not are in unix_style
+ * comment */
+ if (unix_comment == 0 && s_code == e_code) {
+ /*
+ * if it is a UNIX-style comment, ignore the
+ * requirement that previous line be blank for
+ * unindention
+ */
+ ps.com_col = (ps.ind_level - ps.unindent_displace) * ps.ind_size + 1;
+ if (ps.com_col <= 1)
+ ps.com_col = 2;
+ }
+ unix_comment = 2; /* permanently remember that we are in
+ * this type of comment */
+ dump_line();
+ ++line_no;
+ now_col = ps.com_col;
+ *e_com++ = ' ';
+ /*
+ * fix so that the star at the start of the line will line
+ * up
+ */
+ do /* flush leading white space */
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+ while (*buf_ptr == ' ' || *buf_ptr == '\t');
+ break;
+ }
+ if (*(e_com - 1) == ' ' || *(e_com - 1) == '\t')
+ last_bl = e_com - 1;
+ /*
+ * if there was a space at the end of the last line, remember
+ * where it was
+ */
+ else { /* otherwise, insert one */
+ last_bl = e_com;
+ CHECK_SIZE_COM;
+ *e_com++ = ' ';
+ ++now_col;
+ }
+ }
+ ++line_no; /* keep track of input line number */
+ if (!ps.box_com) {
+ int nstar = 1;
+ do { /* flush any blanks and/or tabs at start of
+ * next line */
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+ if (*buf_ptr == '*' && --nstar >= 0) {
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+ if (*buf_ptr == '/')
+ goto end_of_comment;
+ }
+ } while (*buf_ptr == ' ' || *buf_ptr == '\t');
+ }
+ else if (++buf_ptr >= buf_end)
+ fill_buffer();
+ break; /* end of case for newline */
+
+ case '*': /* must check for possibility of being at end
+ * of comment */
+ if (++buf_ptr >= buf_end) /* get to next char after * */
+ fill_buffer();
+
+ if (unix_comment == 0) /* set flag to show we are not in
+ * unix-style comment */
+ unix_comment = 1;
+
+ if (*buf_ptr == '/') { /* it is the end!!! */
+ end_of_comment:
+ if (++buf_ptr >= buf_end)
+ fill_buffer();
+
+ if (*(e_com - 1) != ' ' && !ps.box_com) { /* insure blank before
+ * end */
+ *e_com++ = ' ';
+ ++now_col;
+ }
+ if (break_delim == 1 && !one_liner && s_com[0] == '/'
+ && s_com[1] == '*' && s_com[2] == ' ') {
+ char *t = e_com;
+ break_delim = 2;
+ e_com = s_com + 2;
+ *e_com = 0;
+ if (blanklines_before_blockcomments)
+ prefix_blankline_requested = 1;
+ dump_line();
+ e_com = t;
+ s_com[0] = s_com[1] = s_com[2] = ' ';
+ }
+ if (break_delim == 2 && e_com > s_com + 3
+ /* now_col > adj_max_col - 2 && !ps.box_com */ ) {
+ *e_com = '\0';
+ dump_line();
+ now_col = ps.com_col;
+ }
+ CHECK_SIZE_COM;
+ *e_com++ = '*';
+ *e_com++ = '/';
+ *e_com = '\0';
+ ps.just_saw_decl = l_just_saw_decl;
+ return;
+ }
+ else { /* handle isolated '*' */
+ *e_com++ = '*';
+ ++now_col;
+ }
+ break;
+ default: /* we have a random char */
+ if (unix_comment == 0 && *buf_ptr != ' ' && *buf_ptr != '\t')
+ unix_comment = 1; /* we are not in unix-style comment */
+
+ *e_com = *buf_ptr++;
+ if (buf_ptr >= buf_end)
+ fill_buffer();
+
+ if (*e_com == '\t') /* keep track of column */
+ now_col = ((now_col - 1) & tabmask) + tabsize + 1;
+ else if (*e_com == '\b') /* this is a backspace */
+ --now_col;
+ else
+ ++now_col;
+
+ if (*e_com == ' ' || *e_com == '\t')
+ last_bl = e_com;
+ /* remember we saw a blank */
+
+ ++e_com;
+ if (now_col > adj_max_col && !ps.box_com && unix_comment == 1 && e_com[-1] > ' ') {
+ /*
+ * the comment is too long, it must be broken up
+ */
+ if (break_delim == 1 && s_com[0] == '/'
+ && s_com[1] == '*' && s_com[2] == ' ') {
+ char *t = e_com;
+ break_delim = 2;
+ e_com = s_com + 2;
+ *e_com = 0;
+ if (blanklines_before_blockcomments)
+ prefix_blankline_requested = 1;
+ dump_line();
+ e_com = t;
+ s_com[0] = s_com[1] = s_com[2] = ' ';
+ }
+ if (last_bl == 0) { /* we have seen no blanks */
+ last_bl = e_com; /* fake it */
+ *e_com++ = ' ';
+ }
+ *e_com = '\0'; /* print what we have */
+ *last_bl = '\0';
+ while (last_bl > s_com && last_bl[-1] < 040)
+ *--last_bl = 0;
+ e_com = last_bl;
+ dump_line();
+
+ *e_com++ = ' '; /* add blanks for continuation */
+ *e_com++ = ' ';
+ *e_com++ = ' ';
+
+ t_ptr = last_bl + 1;
+ last_bl = 0;
+ if (t_ptr >= e_com) {
+ while (*t_ptr == ' ' || *t_ptr == '\t')
+ t_ptr++;
+ while (*t_ptr != '\0') { /* move unprinted part of
+ * comment down in buffer */
+ if (*t_ptr == ' ' || *t_ptr == '\t')
+ last_bl = e_com;
+ *e_com++ = *t_ptr++;
+ }
+ }
+ *e_com = '\0';
+ now_col = count_spaces(ps.com_col, s_com); /* recompute current
+ * position */
+ }
+ break;
+ }
+ }
+}
diff --git a/developer_cmds/lorder/lorder.1 b/developer_cmds/lorder/lorder.1
new file mode 100644
index 0000000..45fe0e6
--- /dev/null
+++ b/developer_cmds/lorder/lorder.1
@@ -0,0 +1,75 @@
+.\" $NetBSD: lorder.1,v 1.6 1997/10/19 04:21:49 lukem Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lorder.1 8.2 (Berkeley) 4/28/95
+.\"
+.Dd April 28, 1995
+.Dt LORDER 1
+.Os
+.Sh NAME
+.Nm lorder
+.Nd list dependencies for object files
+.Sh SYNOPSIS
+.Nm
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility uses
+.Xr nm 1
+to determine interdependencies in the list of object files
+specified on the command line.
+.Nm
+outputs a list of file names where the first file contains a symbol
+which is defined by the second file.
+.Pp
+The output is normally used with
+.Xr tsort 1
+when a library is created to determine the optimum ordering of the
+object modules so that all references may be resolved in a single
+pass of the loader.
+.Sh EXAMPLES
+.Bd -literal -offset indent
+ar cr library.a `lorder ${OBJS} | tsort`
+.Ed
+.Sh SEE ALSO
+.Xr ar 1 ,
+.Xr ld 1 ,
+.Xr nm 1 ,
+.Xr ranlib 1 ,
+.Xr tsort 1
+.Sh HISTORY
+An
+.Nm
+utility appeared in
+.At v7 .
diff --git a/developer_cmds/lorder/lorder.sh b/developer_cmds/lorder/lorder.sh
new file mode 100644
index 0000000..b6ed479
--- /dev/null
+++ b/developer_cmds/lorder/lorder.sh
@@ -0,0 +1,104 @@
+#!/bin/sh -
+# $NetBSD: lorder.sh,v 1.7 1998/04/09 05:28:07 fair Exp $
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)lorder.sh 8.1 (Berkeley) 6/6/93
+#
+
+# If the user has set ${NM} then we use it, otherwise we use 'nm'.
+# We try to find the compiler in the user's path, and if that fails we
+# try to find it in the default path. If we can't find it, we punt.
+# Once we find it, we canonicalize its name and set the path to the
+# default path so that other commands we use are picked properly.
+
+if ! type "${NM:=nm}" > /dev/null 2>&1; then
+ PATH=/bin:/usr/bin
+ export PATH
+ if ! type "${NM}" > /dev/null 2>&1; then
+ echo "lorder: ${NM}: not found"
+ exit 1
+ fi
+fi
+cmd='set `type "${NM}"` ; eval echo \$$#'
+NM=`eval $cmd`
+
+# only one argument is a special case, just output the name twice
+case $# in
+ 0)
+ echo "usage: lorder file ...";
+ exit ;;
+ 1)
+ echo $1 $1;
+ exit ;;
+esac
+
+# temporary files
+R=/tmp/_reference_$$
+S=/tmp/_symbol_$$
+
+# remove temporary files on HUP, INT, QUIT, PIPE, TERM
+trap "rm -f $R $S; exit 1" 1 2 3 13 15
+
+# if the line ends in a colon, assume it's the first occurrence of a new
+# object file. Echo it twice, just to make sure it gets into the output.
+#
+# if the line has " T " or " D " it's a globally defined symbol, put it
+# into the symbol file.
+#
+# if the line has " U " it's a globally undefined symbol, put it into
+# the reference file.
+(for file in $* ; do echo $file":" ; done ; $NM -go $*) | sed "
+ /:$/ {
+ s/://
+ s/.*/& &/
+ p
+ d
+ }
+ / [TDGR] / {
+ s/:.* [TDGR] / /
+ w $S
+ d
+ }
+ / U / {
+ s/:.* U / /
+ w $R
+ }
+ d
+"
+
+# sort symbols and references on the first field (the symbol)
+# join on that field, and print out the file names.
+sort -k 2 $R -o $R
+sort -k 2 $S -o $S
+join -j 2 -o "1.1 2.1" $R $S
+rm -f $R $S
diff --git a/developer_cmds/rpcgen/rpc_clntout.c b/developer_cmds/rpcgen/rpc_clntout.c
new file mode 100644
index 0000000..e0d2263
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_clntout.c
@@ -0,0 +1,230 @@
+/* $NetBSD: rpc_clntout.c,v 1.8 1997/10/18 10:53:37 lukem Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_clntout.c 1.11 89/02/22 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_clntout.c,v 1.8 1997/10/18 10:53:37 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_clntout.c, Client-stub outputter for the RPC protocol compiler
+ * Copyright (C) 1987, Sun Microsytsems, Inc.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <rpc/types.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+static void write_program __P((definition *));
+static char *ampr __P((char *));
+static void printbody __P((proc_list *));
+
+#define DEFAULT_TIMEOUT 25 /* in seconds */
+static char RESULT[] = "clnt_res";
+
+
+void
+write_stubs()
+{
+ list *l;
+ definition *def;
+
+ f_print(fout,
+ "\n/* Default timeout can be changed using clnt_control() */\n");
+ f_print(fout, "static struct timeval TIMEOUT = { %d, 0 };\n",
+ DEFAULT_TIMEOUT);
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ write_program(def);
+ }
+ }
+}
+
+static void
+write_program(def)
+ definition *def;
+{
+ version_list *vp;
+ proc_list *proc;
+
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\n");
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "*\n");
+ pvname(proc->proc_name, vp->vers_num);
+ printarglist(proc, "clnt", "CLIENT *");
+ f_print(fout, "{\n");
+ printbody(proc);
+ f_print(fout, "}\n");
+ }
+ }
+}
+/* Writes out declarations of procedure's argument list.
+ In either ANSI C style, in one of old rpcgen style (pass by reference),
+ or new rpcgen style (multiple arguments, pass by value);
+ */
+
+/* sample addargname = "clnt"; sample addargtype = "CLIENT * " */
+
+void
+printarglist(proc, addargname, addargtype)
+ proc_list *proc;
+ char *addargname, *addargtype;
+{
+
+ decl_list *l;
+
+ if (!newstyle) { /* old style: always pass argument by
+ * reference */
+ if (Cflag) { /* C++ style heading */
+ f_print(fout, "(");
+ ptype(proc->args.decls->decl.prefix, proc->args.decls->decl.type, 1);
+ f_print(fout, "*argp, %s%s)\n", addargtype, addargname);
+ } else {
+ f_print(fout, "(argp, %s)\n", addargname);
+ f_print(fout, "\t");
+ ptype(proc->args.decls->decl.prefix, proc->args.decls->decl.type, 1);
+ f_print(fout, "*argp;\n");
+ }
+ } else
+ if (streq(proc->args.decls->decl.type, "void")) {
+ /* newstyle, 0 argument */
+ if (Cflag)
+ f_print(fout, "(%s%s)\n", addargtype, addargname);
+ else
+ f_print(fout, "(%s)\n", addargname);
+ } else {
+ /* new style, 1 or multiple arguments */
+ if (!Cflag) {
+ f_print(fout, "(");
+ for (l = proc->args.decls; l != NULL; l = l->next)
+ f_print(fout, "%s, ", l->decl.name);
+ f_print(fout, "%s)\n", addargname);
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ pdeclaration(proc->args.argname, &l->decl, 1, ";\n");
+ }
+ } else {/* C++ style header */
+ f_print(fout, "(");
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ pdeclaration(proc->args.argname, &l->decl, 0, ", ");
+ }
+ f_print(fout, " %s%s)\n", addargtype, addargname);
+ }
+ }
+
+ if (!Cflag)
+ f_print(fout, "\t%s%s;\n", addargtype, addargname);
+}
+
+
+
+static char *
+ampr(type)
+ char *type;
+{
+ if (isvectordef(type, REL_ALIAS)) {
+ return ("");
+ } else {
+ return ("&");
+ }
+}
+
+static void
+printbody(proc)
+ proc_list *proc;
+{
+ decl_list *l;
+ bool_t args2 = (proc->arg_num > 1);
+
+ /* For new style with multiple arguments, need a structure in which to
+ * stuff the arguments. */
+ if (newstyle && args2) {
+ f_print(fout, "\t%s", proc->args.argname);
+ f_print(fout, " arg;\n");
+ }
+ f_print(fout, "\tstatic ");
+ if (streq(proc->res_type, "void")) {
+ f_print(fout, "char ");
+ } else {
+ ptype(proc->res_prefix, proc->res_type, 0);
+ }
+ f_print(fout, "%s;\n", RESULT);
+ f_print(fout, "\n");
+ f_print(fout, "\tmemset((char *)%s%s, 0, sizeof(%s));\n",
+ ampr(proc->res_type), RESULT, RESULT);
+ if (newstyle && !args2 && (streq(proc->args.decls->decl.type, "void"))) {
+ /* newstyle, 0 arguments */
+ f_print(fout,
+ "\tif (clnt_call(clnt, %s, xdr_void", proc->proc_name);
+ f_print(fout,
+ ", NULL, xdr_%s, %s%s, TIMEOUT) != RPC_SUCCESS) {\n",
+ stringfix(proc->res_type), ampr(proc->res_type), RESULT);
+
+ } else
+ if (newstyle && args2) {
+ /* newstyle, multiple arguments: stuff arguments into
+ * structure */
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ f_print(fout, "\targ.%s = %s;\n",
+ l->decl.name, l->decl.name);
+ }
+ f_print(fout,
+ "\tif (clnt_call(clnt, %s, xdr_%s, &arg, xdr_%s, %s%s, TIMEOUT) != RPC_SUCCESS)\n",
+ proc->proc_name,
+ proc->args.argname,
+ stringfix(proc->res_type),
+ ampr(proc->res_type), RESULT);
+ } else { /* single argument, new or old style */
+ f_print(fout,
+ "\tif (clnt_call(clnt, %s, xdr_%s, %s%s, xdr_%s, %s%s, TIMEOUT) != RPC_SUCCESS)\n",
+ proc->proc_name,
+ stringfix(proc->args.decls->decl.type),
+ (newstyle ? "&" : ""),
+ (newstyle ? proc->args.decls->decl.name : "argp"),
+ stringfix(proc->res_type),
+ ampr(proc->res_type), RESULT);
+ }
+ f_print(fout, "\t\treturn (NULL);\n");
+ if (streq(proc->res_type, "void")) {
+ f_print(fout, "\treturn ((void *)%s%s);\n",
+ ampr(proc->res_type), RESULT);
+ } else {
+ f_print(fout, "\treturn (%s%s);\n", ampr(proc->res_type), RESULT);
+ }
+}
diff --git a/developer_cmds/rpcgen/rpc_cout.c b/developer_cmds/rpcgen/rpc_cout.c
new file mode 100644
index 0000000..ca4eb7b
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_cout.c
@@ -0,0 +1,741 @@
+/* $NetBSD: rpc_cout.c,v 1.14 1998/08/25 20:59:40 ross Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_cout.c 1.13 89/02/22 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_cout.c,v 1.14 1998/08/25 20:59:40 ross Exp $");
+#endif
+#endif
+
+/*
+ * rpc_cout.c, XDR routine outputter for the RPC protocol compiler
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+static int findtype __P((definition *, char *));
+static int undefined __P((char *));
+static void print_generic_header __P((char *, int));
+static void print_header __P((definition *));
+static void print_prog_header __P((proc_list *));
+static void print_trailer __P((void));
+static void print_ifopen __P((int, char *));
+static void print_ifarg __P((char *));
+static void print_ifsizeof __P((char *, char *));
+static void print_ifclose __P((int));
+static void print_ifstat __P((int, char *, char *, relation, char *, char *, char *));
+static void emit_enum __P((definition *));
+static void emit_program __P((definition *));
+static void emit_union __P((definition *));
+static void emit_struct __P((definition *));
+static void emit_typedef __P((definition *));
+static void print_stat __P((int, declaration *));
+
+/*
+ * Emit the C-routine for the given definition
+ */
+void
+emit(def)
+ definition *def;
+{
+ if (def->def_kind == DEF_CONST) {
+ return;
+ }
+ if (def->def_kind == DEF_PROGRAM) {
+ emit_program(def);
+ return;
+ }
+ if (def->def_kind == DEF_TYPEDEF) {
+ /* now we need to handle declarations like struct typedef foo
+ * foo; since we dont want this to be expanded into 2 calls to
+ * xdr_foo */
+
+ if (strcmp(def->def.ty.old_type, def->def_name) == 0)
+ return;
+ };
+
+ print_header(def);
+
+ switch (def->def_kind) {
+ case DEF_UNION:
+ emit_union(def);
+ break;
+ case DEF_ENUM:
+ emit_enum(def);
+ break;
+ case DEF_STRUCT:
+ emit_struct(def);
+ break;
+ case DEF_TYPEDEF:
+ emit_typedef(def);
+ break;
+ case DEF_PROGRAM:
+ case DEF_CONST:
+ errx(1, "Internal error %s, %d: Case %d not handled\n",
+ __FILE__, __LINE__, def->def_kind);
+ break;
+ }
+ print_trailer();
+}
+
+static int
+findtype(def, type)
+ definition *def;
+ char *type;
+{
+
+ if (def->def_kind == DEF_PROGRAM || def->def_kind == DEF_CONST) {
+ return (0);
+ } else {
+ return (streq(def->def_name, type));
+ }
+}
+
+static int
+undefined(type)
+ char *type;
+{
+ definition *def;
+
+ def = (definition *) FINDVAL(defined, type, findtype);
+
+
+ return (def == NULL);
+}
+
+static void
+print_generic_header(procname, pointerp)
+ char *procname;
+ int pointerp;
+{
+ f_print(fout, "\n");
+ f_print(fout, "bool_t\n");
+ if (Cflag) {
+ f_print(fout, "xdr_%s(", procname);
+ f_print(fout, "XDR *xdrs, ");
+ f_print(fout, "%s ", procname);
+ if (pointerp)
+ f_print(fout, "*");
+ f_print(fout, "objp)\n{\n");
+ } else {
+ f_print(fout, "xdr_%s(xdrs, objp)\n", procname);
+ f_print(fout, "\tXDR *xdrs;\n");
+ f_print(fout, "\t%s ", procname);
+ if (pointerp)
+ f_print(fout, "*");
+ f_print(fout, "objp;\n{\n");
+ }
+}
+
+static void
+print_header(def)
+ definition *def;
+{
+ print_generic_header(def->def_name,
+ def->def_kind != DEF_TYPEDEF ||
+ !isvectordef(def->def.ty.old_type, def->def.ty.rel));
+}
+
+static void
+print_prog_header(plist)
+ proc_list *plist;
+{
+ print_generic_header(plist->args.argname, 1);
+}
+
+static void
+print_trailer()
+{
+ f_print(fout, "\treturn (TRUE);\n");
+ f_print(fout, "}\n");
+}
+
+
+static void
+print_ifopen(indent, name)
+ int indent;
+ char *name;
+{
+ tabify(fout, indent);
+ f_print(fout, "if (!xdr_%s(xdrs", name);
+}
+
+static void
+print_ifarg(arg)
+ char *arg;
+{
+ f_print(fout, ", %s", arg);
+}
+
+static void
+print_ifsizeof(prefix, type)
+ char *prefix;
+ char *type;
+{
+ if (streq(type, "bool")) {
+ f_print(fout, ", sizeof(bool_t), (xdrproc_t)xdr_bool");
+ } else {
+ f_print(fout, ", sizeof(");
+ if (undefined(type) && prefix) {
+ f_print(fout, "%s ", prefix);
+ }
+ f_print(fout, "%s), (xdrproc_t)xdr_%s", type, type);
+ }
+}
+
+static void
+print_ifclose(indent)
+ int indent;
+{
+ f_print(fout, "))\n");
+ tabify(fout, indent);
+ f_print(fout, "\treturn (FALSE);\n");
+}
+
+static void
+print_ifstat(indent, prefix, type, rel, amax, objname, name)
+ int indent;
+ char *prefix;
+ char *type;
+ relation rel;
+ char *amax;
+ char *objname;
+ char *name;
+{
+ char *alt = NULL;
+
+ switch (rel) {
+ case REL_POINTER:
+ print_ifopen(indent, "pointer");
+ print_ifarg("(char **)");
+ f_print(fout, "%s", objname);
+ print_ifsizeof(prefix, type);
+ break;
+ case REL_VECTOR:
+ if (streq(type, "string")) {
+ alt = "string";
+ } else
+ if (streq(type, "opaque")) {
+ alt = "opaque";
+ }
+ if (alt) {
+ print_ifopen(indent, alt);
+ print_ifarg(objname);
+ } else {
+ print_ifopen(indent, "vector");
+ print_ifarg("(char *)");
+ f_print(fout, "%s", objname);
+ }
+ print_ifarg(amax);
+ if (!alt) {
+ print_ifsizeof(prefix, type);
+ }
+ break;
+ case REL_ARRAY:
+ if (streq(type, "string")) {
+ alt = "string";
+ } else
+ if (streq(type, "opaque")) {
+ alt = "bytes";
+ }
+ if (streq(type, "string")) {
+ print_ifopen(indent, alt);
+ print_ifarg(objname);
+ } else {
+ if (alt) {
+ print_ifopen(indent, alt);
+ } else {
+ print_ifopen(indent, "array");
+ }
+ print_ifarg("(char **)");
+ if (*objname == '&') {
+ f_print(fout, "%s.%s_val, (u_int *)%s.%s_len",
+ objname, name, objname, name);
+ } else {
+ f_print(fout, "&%s->%s_val, (u_int *)&%s->%s_len",
+ objname, name, objname, name);
+ }
+ }
+ print_ifarg(amax);
+ if (!alt) {
+ print_ifsizeof(prefix, type);
+ }
+ break;
+ case REL_ALIAS:
+ print_ifopen(indent, type);
+ print_ifarg(objname);
+ break;
+ }
+ print_ifclose(indent);
+}
+/* ARGSUSED */
+static void
+emit_enum(def)
+ definition *def;
+{
+ fprintf(fout, "\n");
+ print_ifopen(1, "enum");
+ print_ifarg("(enum_t *)objp");
+ print_ifclose(1);
+}
+
+static void
+emit_program(def)
+ definition *def;
+{
+ decl_list *dl;
+ version_list *vlist;
+ proc_list *plist;
+
+ for (vlist = def->def.pr.versions; vlist != NULL; vlist = vlist->next)
+ for (plist = vlist->procs; plist != NULL; plist = plist->next) {
+ if (!newstyle || plist->arg_num < 2)
+ continue; /* old style, or single
+ * argument */
+ print_prog_header(plist);
+ for (dl = plist->args.decls; dl != NULL;
+ dl = dl->next)
+ print_stat(1, &dl->decl);
+ print_trailer();
+ }
+}
+
+
+static void
+emit_union(def)
+ definition *def;
+{
+ declaration *dflt;
+ case_list *cl;
+ declaration *cs;
+ char *object;
+ char *vecformat = "objp->%s_u.%s";
+ char *format = "&objp->%s_u.%s";
+
+ f_print(fout, "\n");
+ print_stat(1, &def->def.un.enum_decl);
+ f_print(fout, "\tswitch (objp->%s) {\n", def->def.un.enum_decl.name);
+ for (cl = def->def.un.cases; cl != NULL; cl = cl->next) {
+ f_print(fout, "\tcase %s:\n", cl->case_name);
+ if (cl->contflag == 1) /* a continued case statement */
+ continue;
+ cs = &cl->case_decl;
+ if (!streq(cs->type, "void")) {
+ object = alloc(strlen(def->def_name) + strlen(format) +
+ strlen(cs->name) + 1);
+ if (isvectordef(cs->type, cs->rel)) {
+ s_print(object, vecformat, def->def_name,
+ cs->name);
+ } else {
+ s_print(object, format, def->def_name,
+ cs->name);
+ }
+ print_ifstat(2, cs->prefix, cs->type, cs->rel,
+ cs->array_max, object, cs->name);
+ free(object);
+ }
+ f_print(fout, "\t\tbreak;\n");
+ }
+ dflt = def->def.un.default_decl;
+ f_print(fout, "\tdefault:\n");
+ if (dflt != NULL) {
+ if (!streq(dflt->type, "void")) {
+ object = alloc(strlen(def->def_name) + strlen(format) +
+ strlen(dflt->name) + 1);
+ if (isvectordef(dflt->type, dflt->rel)) {
+ s_print(object, vecformat, def->def_name,
+ dflt->name);
+ } else {
+ s_print(object, format, def->def_name,
+ dflt->name);
+ }
+ print_ifstat(2, dflt->prefix, dflt->type, dflt->rel,
+ dflt->array_max, object, dflt->name);
+ free(object);
+ }
+ f_print(fout, "\t\tbreak;\n");
+ } else {
+ f_print(fout, "\t\treturn (FALSE);\n");
+ }
+
+ f_print(fout, "\t}\n");
+}
+
+static void
+emit_struct(def)
+ definition *def;
+{
+ decl_list *dl;
+ int i, j, size, flag;
+ decl_list *cur = NULL, *psav;
+ bas_type *ptr;
+ char *sizestr, *plus;
+ char ptemp[256];
+ int can_inline;
+
+
+ if (doinline == 0) {
+ fprintf(fout, "\n");
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ print_stat(1, &dl->decl);
+ return;
+ }
+ size = 0;
+ can_inline = 0;
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ if ((dl->decl.prefix == NULL) &&
+ ((ptr = find_type(dl->decl.type)) != NULL) &&
+ ((dl->decl.rel == REL_ALIAS) || (dl->decl.rel == REL_VECTOR))) {
+
+ if (dl->decl.rel == REL_ALIAS)
+ size += ptr->length;
+ else {
+ can_inline = 1;
+ break; /* can be inlined */
+ };
+ } else {
+ if (size >= doinline) {
+ can_inline = 1;
+ break; /* can be inlined */
+ }
+ size = 0;
+ }
+ if (size > doinline)
+ can_inline = 1;
+
+ if (can_inline == 0) { /* can not inline, drop back to old mode */
+ fprintf(fout, "\n");
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ print_stat(1, &dl->decl);
+ return;
+ };
+
+ /* May cause lint to complain. but ... */
+ f_print(fout, "\tint32_t *buf;\n");
+
+ flag = PUT;
+ f_print(fout, "\n\tif (xdrs->x_op == XDR_ENCODE) {\n");
+
+ for (j = 0; j < 2; j++) {
+ i = 0;
+ size = 0;
+ sizestr = NULL;
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next) { /* xxx */
+
+ /* now walk down the list and check for basic types */
+ if ((dl->decl.prefix == NULL) && ((ptr = find_type(dl->decl.type)) != NULL) && ((dl->decl.rel == REL_ALIAS) || (dl->decl.rel == REL_VECTOR))) {
+ if (i == 0)
+ cur = dl;
+ i++;
+
+ if (dl->decl.rel == REL_ALIAS)
+ size += ptr->length;
+ else {
+ /* this is required to handle arrays */
+
+ if (sizestr == NULL)
+ plus = "";
+ else
+ plus = " + ";
+
+ if (ptr->length != 1)
+ s_print(ptemp, "%s%s * %d", plus, dl->decl.array_max, ptr->length);
+ else
+ s_print(ptemp, "%s%s", plus, dl->decl.array_max);
+
+ /* now concatenate to sizestr !!!! */
+ if (sizestr == NULL)
+ sizestr = strdup(ptemp);
+ else {
+ sizestr = (char *) realloc(sizestr, strlen(sizestr) + strlen(ptemp) + 1);
+ if (sizestr == NULL) {
+
+ f_print(stderr, "Fatal error : no memory\n");
+ crash();
+ };
+ sizestr = strcat(sizestr, ptemp); /* build up length of
+ * array */
+
+ }
+ }
+
+ } else {
+ if (i > 0) {
+ if (sizestr == NULL && size < doinline) {
+ /* don't expand into inline
+ * code if size < doinline */
+ while (cur != dl) {
+ print_stat(2, &cur->decl);
+ cur = cur->next;
+ }
+ } else {
+
+
+
+ /* were already looking at a
+ * xdr_inlineable structure */
+ if (sizestr == NULL)
+ f_print(fout, "\t\tbuf = (int32_t *)XDR_INLINE(xdrs, %d * BYTES_PER_XDR_UNIT);\n",
+ size);
+ else
+ if (size == 0)
+ f_print(fout,
+ "\t\tbuf = (int32_t *)XDR_INLINE(xdrs, %s * BYTES_PER_XDR_UNIT);\n",
+ sizestr);
+ else
+ f_print(fout,
+ "\t\tbuf = (int32_t *)XDR_INLINE(xdrs, (%d + %s) * BYTES_PER_XDR_UNIT);\n",
+ size, sizestr);
+
+ f_print(fout, "\t\tif (buf == NULL) {\n");
+
+ psav = cur;
+ while (cur != dl) {
+ print_stat(3, &cur->decl);
+ cur = cur->next;
+ }
+
+ f_print(fout, "\t\t} else {\n");
+
+ cur = psav;
+ while (cur != dl) {
+ emit_inline(&cur->decl, flag);
+ cur = cur->next;
+ }
+
+ f_print(fout, "\t\t}\n");
+ }
+ }
+ size = 0;
+ i = 0;
+ sizestr = NULL;
+ print_stat(2, &dl->decl);
+ }
+
+ }
+ if (i > 0) {
+ if (sizestr == NULL && size < doinline) {
+ /* don't expand into inline code if size <
+ * doinline */
+ while (cur != dl) {
+ print_stat(2, &cur->decl);
+ cur = cur->next;
+ }
+ } else {
+
+ /* were already looking at a xdr_inlineable
+ * structure */
+ if (sizestr == NULL)
+ f_print(fout, "\t\tbuf = (int32_t *)XDR_INLINE(xdrs, %d * BYTES_PER_XDR_UNIT);\n",
+ size);
+ else
+ if (size == 0)
+ f_print(fout,
+ "\t\tbuf = (int32_t *)XDR_INLINE(xdrs, %s * BYTES_PER_XDR_UNIT);\n",
+ sizestr);
+ else
+ f_print(fout,
+ "\t\tbuf = (int32_t *)XDR_INLINE(xdrs, (%d + %s) * BYTES_PER_XDR_UNIT);\n",
+ size, sizestr);
+
+ f_print(fout, "\t\tif (buf == NULL) {\n");
+
+ psav = cur;
+ while (cur != NULL) {
+ print_stat(3, &cur->decl);
+ cur = cur->next;
+ }
+ f_print(fout, "\t\t} else {\n");
+
+ cur = psav;
+ while (cur != dl) {
+ emit_inline(&cur->decl, flag);
+ cur = cur->next;
+ }
+
+ f_print(fout, "\t\t}\n");
+
+ }
+ }
+ if (flag == PUT) {
+ flag = GET;
+ f_print(fout, "\t} else if (xdrs->x_op == XDR_DECODE) {\n");
+ }
+ }
+
+ f_print(fout, "\t} else {\n");
+
+ /* now take care of XDR_FREE case */
+
+ for (dl = def->def.st.decls; dl != NULL; dl = dl->next)
+ print_stat(2, &dl->decl);
+
+ f_print(fout, "\t}\n");
+}
+
+static void
+emit_typedef(def)
+ definition *def;
+{
+ char *prefix = def->def.ty.old_prefix;
+ char *type = def->def.ty.old_type;
+ char *amax = def->def.ty.array_max;
+ relation rel = def->def.ty.rel;
+
+ fprintf(fout, "\n");
+ print_ifstat(1, prefix, type, rel, amax, "objp", def->def_name);
+}
+
+static void
+print_stat(indent, dec)
+ declaration *dec;
+ int indent;
+{
+ char *prefix = dec->prefix;
+ char *type = dec->type;
+ char *amax = dec->array_max;
+ relation rel = dec->rel;
+ char name[256];
+
+ if (isvectordef(type, rel)) {
+ s_print(name, "objp->%s", dec->name);
+ } else {
+ s_print(name, "&objp->%s", dec->name);
+ }
+ print_ifstat(indent, prefix, type, rel, amax, name, dec->name);
+}
+
+
+void
+emit_inline(decl, flag)
+ declaration *decl;
+ int flag;
+{
+
+/*check whether an array or not */
+
+ switch (decl->rel) {
+ case REL_ALIAS:
+ emit_single_in_line(decl, flag, REL_ALIAS);
+ break;
+ case REL_VECTOR:
+ f_print(fout, "\t\t\t{\n");
+ f_print(fout, "\t\t\t\tint i;\n");
+ f_print(fout, "\t\t\t\t%s *genp;\n", decl->type);
+ f_print(fout, "\n");
+ f_print(fout, "\t\t\t\tfor (i = 0, genp = objp->%s;\n",
+ decl->name);
+ f_print(fout, "\t\t\t\t i < %s; i++) {\n\t\t",
+ decl->array_max);
+ emit_single_in_line(decl, flag, REL_VECTOR);
+ f_print(fout, "\t\t\t\t}\n\t\t\t}\n");
+ break;
+ case REL_ARRAY:
+ case REL_POINTER:
+ errx(1, "Internal error %s, %d: Case %d not handled\n",
+ __FILE__, __LINE__, decl->rel);
+ }
+}
+
+void
+emit_single_in_line(decl, flag, rel)
+ declaration *decl;
+ int flag;
+ relation rel;
+{
+ char *upp_case;
+ int freed = 0;
+
+ if (flag == PUT)
+ f_print(fout, "\t\t\tIXDR_PUT_");
+ else
+ if (rel == REL_ALIAS)
+ f_print(fout, "\t\t\tobjp->%s = IXDR_GET_", decl->name);
+ else
+ f_print(fout, "\t\t\t*genp++ = IXDR_GET_");
+
+ upp_case = upcase(decl->type);
+
+ /* hack - XX */
+ if (strcmp(upp_case, "INT") == 0) {
+ free(upp_case);
+ freed = 1;
+ upp_case = "LONG";
+ }
+ if (strcmp(upp_case, "U_INT") == 0) {
+ free(upp_case);
+ freed = 1;
+ upp_case = "U_LONG";
+ }
+ if (flag == PUT)
+ if (rel == REL_ALIAS)
+ f_print(fout, "%s(buf, objp->%s);\n", upp_case, decl->name);
+ else
+ f_print(fout, "%s(buf, *genp++);\n", upp_case);
+
+ else
+ f_print(fout, "%s(buf);\n", upp_case);
+ if (!freed)
+ free(upp_case);
+
+}
+
+
+char *
+upcase(str)
+ char *str;
+{
+ char *ptr, *hptr;
+
+
+ ptr = (char *) malloc(strlen(str) + 1);
+ if (ptr == (char *) NULL) {
+ f_print(stderr, "malloc failed\n");
+ exit(1);
+ };
+
+ hptr = ptr;
+ while (*str != '\0')
+ *ptr++ = toupper(*str++);
+
+ *ptr = '\0';
+ return (hptr);
+
+}
diff --git a/developer_cmds/rpcgen/rpc_hout.c b/developer_cmds/rpcgen/rpc_hout.c
new file mode 100644
index 0000000..3b8811f
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_hout.c
@@ -0,0 +1,534 @@
+/* $NetBSD: rpc_hout.c,v 1.9 1998/02/11 23:11:17 lukem Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_hout.c 1.12 89/02/22 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_hout.c,v 1.9 1998/02/11 23:11:17 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_hout.c, Header file outputter for the RPC protocol compiler
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <err.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+static void pconstdef __P((definition *));
+static void pargdef __P((definition *));
+static void pstructdef __P((definition *));
+static void puniondef __P((definition *));
+static void pdefine __P((char *, char *));
+static void puldefine __P((char *, char *));
+static int define_printed __P((proc_list *, version_list *));
+static void pprogramdef __P((definition *));
+static void parglist __P((proc_list *, char *));
+static void penumdef __P((definition *));
+static void ptypedef __P((definition *));
+static int undefined2 __P((char *, char *));
+
+/*
+ * Print the C-version of an xdr definition
+ */
+void
+print_datadef(def)
+ definition *def;
+{
+
+ if (def->def_kind == DEF_PROGRAM) /* handle data only */
+ return;
+
+ if (def->def_kind != DEF_CONST) {
+ f_print(fout, "\n");
+ }
+ switch (def->def_kind) {
+ case DEF_STRUCT:
+ pstructdef(def);
+ break;
+ case DEF_UNION:
+ puniondef(def);
+ break;
+ case DEF_ENUM:
+ penumdef(def);
+ break;
+ case DEF_TYPEDEF:
+ ptypedef(def);
+ break;
+ case DEF_PROGRAM:
+ pprogramdef(def);
+ break;
+ case DEF_CONST:
+ pconstdef(def);
+ break;
+ }
+ if (def->def_kind != DEF_PROGRAM && def->def_kind != DEF_CONST) {
+ pxdrfuncdecl(def->def_name,
+ def->def_kind != DEF_TYPEDEF ||
+ !isvectordef(def->def.ty.old_type, def->def.ty.rel));
+
+ }
+}
+
+
+void
+print_funcdef(def)
+ definition *def;
+{
+ switch (def->def_kind) {
+ case DEF_PROGRAM:
+ f_print(fout, "\n");
+ pprogramdef(def);
+ break;
+ case DEF_CONST:
+ case DEF_TYPEDEF:
+ case DEF_ENUM:
+ case DEF_UNION:
+ case DEF_STRUCT:
+ break;
+ }
+}
+
+void
+pxdrfuncdecl(name, pointerp)
+ char *name;
+ int pointerp;
+{
+
+ f_print(fout, "#ifdef __cplusplus\n");
+ f_print(fout, "extern \"C\" bool_t xdr_%s(XDR *, %s%s);\n",
+ name,
+ name, pointerp ? ("*") : "");
+ f_print(fout, "#elif __STDC__\n");
+ f_print(fout, "extern bool_t xdr_%s(XDR *, %s%s);\n",
+ name,
+ name, pointerp ? ("*") : "");
+ f_print(fout, "#else /* Old Style C */\n");
+ f_print(fout, "bool_t xdr_%s();\n", name);
+ f_print(fout, "#endif /* Old Style C */\n\n");
+}
+
+
+static void
+pconstdef(def)
+ definition *def;
+{
+ pdefine(def->def_name, def->def.co);
+}
+/* print out the definitions for the arguments of functions in the
+ header file
+*/
+static void
+pargdef(def)
+ definition *def;
+{
+ decl_list *l;
+ version_list *vers;
+ char *name;
+ proc_list *plist;
+
+
+ for (vers = def->def.pr.versions; vers != NULL; vers = vers->next) {
+ for (plist = vers->procs; plist != NULL;
+ plist = plist->next) {
+
+ if (!newstyle || plist->arg_num < 2) {
+ continue; /* old style or single args */
+ }
+ name = plist->args.argname;
+ f_print(fout, "struct %s {\n", name);
+ for (l = plist->args.decls;
+ l != NULL; l = l->next) {
+ pdeclaration(name, &l->decl, 1, ";\n");
+ }
+ f_print(fout, "};\n");
+ f_print(fout, "typedef struct %s %s;\n", name, name);
+ pxdrfuncdecl(name, 0);
+ f_print(fout, "\n");
+ }
+ }
+
+}
+
+
+static void
+pstructdef(def)
+ definition *def;
+{
+ decl_list *l;
+ char *name = def->def_name;
+
+ f_print(fout, "struct %s {\n", name);
+ for (l = def->def.st.decls; l != NULL; l = l->next) {
+ pdeclaration(name, &l->decl, 1, ";\n");
+ }
+ f_print(fout, "};\n");
+ f_print(fout, "typedef struct %s %s;\n", name, name);
+}
+
+static void
+puniondef(def)
+ definition *def;
+{
+ case_list *l;
+ char *name = def->def_name;
+ declaration *decl;
+
+ f_print(fout, "struct %s {\n", name);
+ decl = &def->def.un.enum_decl;
+ if (streq(decl->type, "bool")) {
+ f_print(fout, "\tbool_t %s;\n", decl->name);
+ } else {
+ f_print(fout, "\t%s %s;\n", decl->type, decl->name);
+ }
+ f_print(fout, "\tunion {\n");
+ for (l = def->def.un.cases; l != NULL; l = l->next) {
+ if (l->contflag == 0)
+ pdeclaration(name, &l->case_decl, 2, ";\n");
+ }
+ decl = def->def.un.default_decl;
+ if (decl && !streq(decl->type, "void")) {
+ pdeclaration(name, decl, 2, ";\n");
+ }
+ f_print(fout, "\t} %s_u;\n", name);
+ f_print(fout, "};\n");
+ f_print(fout, "typedef struct %s %s;\n", name, name);
+}
+
+static void
+pdefine(name, num)
+ char *name;
+ char *num;
+{
+ f_print(fout, "#define %s %s\n", name, num);
+}
+
+static void
+puldefine(name, num)
+ char *name;
+ char *num;
+{
+ f_print(fout, "#define %s ((rpc_uint)%s)\n", name, num);
+}
+
+static int
+define_printed(stop, start)
+ proc_list *stop;
+ version_list *start;
+{
+ version_list *vers;
+ proc_list *proc;
+
+ for (vers = start; vers != NULL; vers = vers->next) {
+ for (proc = vers->procs; proc != NULL; proc = proc->next) {
+ if (proc == stop) {
+ return (0);
+ } else
+ if (streq(proc->proc_name, stop->proc_name)) {
+ return (1);
+ }
+ }
+ }
+ errx(1, "Internal error %s, %d: procedure not found\n",
+ __FILE__, __LINE__);
+ /* NOTREACHED */
+}
+
+static void
+pprogramdef(def)
+ definition *def;
+{
+ version_list *vers;
+ proc_list *proc;
+ int i;
+ char *ext;
+
+ pargdef(def);
+
+ puldefine(def->def_name, def->def.pr.prog_num);
+ for (vers = def->def.pr.versions; vers != NULL; vers = vers->next) {
+ if (tblflag) {
+ f_print(fout, "extern struct rpcgen_table %s_%s_table[];\n",
+ locase(def->def_name), vers->vers_num);
+ f_print(fout, "extern %s_%s_nproc;\n",
+ locase(def->def_name), vers->vers_num);
+ }
+ puldefine(vers->vers_name, vers->vers_num);
+
+ /* Print out 3 definitions, one for ANSI-C, another for C++, a
+ * third for old style C */
+
+ for (i = 0; i < 3; i++) {
+ if (i == 0) {
+ f_print(fout, "\n#ifdef __cplusplus\n");
+ ext = "extern \"C\" ";
+ } else
+ if (i == 1) {
+ f_print(fout, "\n#elif __STDC__\n");
+ ext = "extern ";
+ } else {
+ f_print(fout, "\n#else /* Old Style C */\n");
+ ext = "extern ";
+ }
+
+
+ for (proc = vers->procs; proc != NULL; proc = proc->next) {
+ if (!define_printed(proc, def->def.pr.versions)) {
+ puldefine(proc->proc_name, proc->proc_num);
+ }
+ f_print(fout, "%s", ext);
+ pprocdef(proc, vers, "CLIENT *", 0, i);
+ f_print(fout, "%s", ext);
+ pprocdef(proc, vers, "struct svc_req *", 1, i);
+
+ }
+
+ }
+ f_print(fout, "#endif /* Old Style C */\n");
+ }
+}
+
+void
+pprocdef(proc, vp, addargtype, server_p, mode)
+ proc_list *proc;
+ version_list *vp;
+ char *addargtype;
+ int server_p;
+ int mode;
+{
+
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, "* ");
+ if (server_p)
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else
+ pvname(proc->proc_name, vp->vers_num);
+
+ /*
+ * mode 0 == cplusplus, mode 1 = ANSI-C, mode 2 = old style C
+ */
+ if (mode == 0 || mode == 1)
+ parglist(proc, addargtype);
+ else
+ f_print(fout, "();\n");
+}
+
+
+/* print out argument list of procedure */
+static void
+parglist(proc, addargtype)
+ proc_list *proc;
+ char *addargtype;
+{
+ decl_list *dl;
+
+ f_print(fout, "(");
+
+ if (proc->arg_num < 2 && newstyle &&
+ streq(proc->args.decls->decl.type, "void")) {
+ /* 0 argument in new style: do nothing */
+ } else {
+ for (dl = proc->args.decls; dl != NULL; dl = dl->next) {
+ ptype(dl->decl.prefix, dl->decl.type, 1);
+ if (!newstyle)
+ f_print(fout, "*"); /* old style passes by
+ * reference */
+
+ f_print(fout, ", ");
+ }
+ }
+
+ f_print(fout, "%s);\n", addargtype);
+}
+
+static void
+penumdef(def)
+ definition *def;
+{
+ char *name = def->def_name;
+ enumval_list *l;
+ char *last = NULL;
+ int count = 0;
+
+ f_print(fout, "enum %s {\n", name);
+ for (l = def->def.en.vals; l != NULL; l = l->next) {
+ f_print(fout, "\t%s", l->name);
+ if (l->assignment) {
+ f_print(fout, " = %s", l->assignment);
+ last = l->assignment;
+ count = 1;
+ } else {
+ if (last == NULL) {
+ f_print(fout, " = %d", count++);
+ } else {
+ f_print(fout, " = %s + %d", last, count++);
+ }
+ }
+ f_print(fout, ",\n");
+ }
+ f_print(fout, "};\n");
+ f_print(fout, "typedef enum %s %s;\n", name, name);
+}
+
+static void
+ptypedef(def)
+ definition *def;
+{
+ char *name = def->def_name;
+ char *old = def->def.ty.old_type;
+ char prefix[8]; /* enough to contain "struct ", including NUL */
+ relation rel = def->def.ty.rel;
+
+
+ if (!streq(name, old)) {
+ if (streq(old, "string")) {
+ old = "char";
+ rel = REL_POINTER;
+ } else
+ if (streq(old, "opaque")) {
+ old = "char";
+ } else
+ if (streq(old, "bool")) {
+ old = "bool_t";
+ }
+ if (undefined2(old, name) && def->def.ty.old_prefix) {
+ s_print(prefix, "%s ", def->def.ty.old_prefix);
+ } else {
+ prefix[0] = 0;
+ }
+ f_print(fout, "typedef ");
+ switch (rel) {
+ case REL_ARRAY:
+ f_print(fout, "struct {\n");
+ f_print(fout, "\tu_int %s_len;\n", name);
+ f_print(fout, "\t%s%s *%s_val;\n", prefix, old, name);
+ f_print(fout, "} %s", name);
+ break;
+ case REL_POINTER:
+ f_print(fout, "%s%s *%s", prefix, old, name);
+ break;
+ case REL_VECTOR:
+ f_print(fout, "%s%s %s[%s]", prefix, old, name,
+ def->def.ty.array_max);
+ break;
+ case REL_ALIAS:
+ f_print(fout, "%s%s %s", prefix, old, name);
+ break;
+ }
+ f_print(fout, ";\n");
+ }
+}
+
+void
+pdeclaration(name, dec, tab, separator)
+ char *name;
+ declaration *dec;
+ int tab;
+ char *separator;
+{
+ char buf[8]; /* enough to hold "struct ", include NUL */
+ char *prefix;
+ char *type;
+
+ if (streq(dec->type, "void")) {
+ return;
+ }
+ tabify(fout, tab);
+ if (streq(dec->type, name) && !dec->prefix) {
+ f_print(fout, "struct ");
+ }
+ if (streq(dec->type, "string")) {
+ f_print(fout, "char *%s", dec->name);
+ } else {
+ prefix = "";
+ if (streq(dec->type, "bool")) {
+ type = "bool_t";
+ } else
+ if (streq(dec->type, "opaque")) {
+ type = "char";
+ } else {
+ if (dec->prefix) {
+ s_print(buf, "%s ", dec->prefix);
+ prefix = buf;
+ }
+ type = dec->type;
+ }
+ switch (dec->rel) {
+ case REL_ALIAS:
+ f_print(fout, "%s%s %s", prefix, type, dec->name);
+ break;
+ case REL_VECTOR:
+ f_print(fout, "%s%s %s[%s]", prefix, type, dec->name,
+ dec->array_max);
+ break;
+ case REL_POINTER:
+ f_print(fout, "%s%s *%s", prefix, type, dec->name);
+ break;
+ case REL_ARRAY:
+ f_print(fout, "struct {\n");
+ tabify(fout, tab);
+ f_print(fout, "\tu_int %s_len;\n", dec->name);
+ tabify(fout, tab);
+ f_print(fout, "\t%s%s *%s_val;\n", prefix, type, dec->name);
+ tabify(fout, tab);
+ f_print(fout, "} %s", dec->name);
+ break;
+ }
+ }
+ f_print(fout, "%s", separator);
+}
+
+static int
+undefined2(type, stop)
+ char *type;
+ char *stop;
+{
+ list *l;
+ definition *def;
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ if (streq(def->def_name, stop)) {
+ return (1);
+ } else
+ if (streq(def->def_name, type)) {
+ return (0);
+ }
+ }
+ }
+ return (1);
+}
diff --git a/developer_cmds/rpcgen/rpc_main.c b/developer_cmds/rpcgen/rpc_main.c
new file mode 100644
index 0000000..a7a15a8
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_main.c
@@ -0,0 +1,1170 @@
+/* $NetBSD: rpc_main.c,v 1.14 1997/10/18 10:53:53 lukem Exp $ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_main.c 1.30 89/03/30 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_main.c,v 1.14 1997/10/18 10:53:53 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_main.c, Top level of the RPC protocol compiler.
+ */
+
+#define RPCGEN_VERSION "199506"/* This program's version (year & month) */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <err.h>
+#include <sys/types.h>
+#ifdef __TURBOC__
+#define MAXPATHLEN 80
+#include <process.h>
+#include <dir.h>
+#else
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#endif
+#include <sys/stat.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define EXTEND 1 /* alias for TRUE */
+#define DONT_EXTEND 0 /* alias for FALSE */
+
+#define SVR4_CPP "/usr/ccs/lib/cpp"
+#define SUNOS_CPP "/lib/cpp"
+static int cppDefined = 0; /* explicit path for C preprocessor */
+
+struct commandline {
+ int cflag; /* xdr C routines */
+ int hflag; /* header file */
+ int lflag; /* client side stubs */
+ int mflag; /* server side stubs */
+ int nflag; /* netid flag */
+ int sflag; /* server stubs for the given transport */
+ int tflag; /* dispatch Table file */
+ int Ssflag; /* produce server sample code */
+ int Scflag; /* produce client sample code */
+ char *infile; /* input module name */
+ char *outfile; /* output module name */
+};
+
+
+static char *cmdname;
+
+static char *svcclosetime = "120";
+static char *CPP = "/usr/bin/cpp";
+static char CPPFLAGS[] = "-C";
+static char pathbuf[MAXPATHLEN + 1];
+static char *allv[] = {
+ "rpcgen", "-s", "udp", "-s", "tcp",
+};
+static int allc = sizeof(allv) / sizeof(allv[0]);
+static char *allnv[] = {
+ "rpcgen", "-s", "netpath",
+};
+static int allnc = sizeof(allnv) / sizeof(allnv[0]);
+
+#define ARGLISTLEN 20
+#define FIXEDARGS 2
+
+static char *arglist[ARGLISTLEN];
+static int argcount = FIXEDARGS;
+
+
+int nonfatalerrors; /* errors */
+int inetdflag /* = 1 */ ; /* Support for inetd *//* is now the default */
+int pmflag; /* Support for port monitors */
+int logflag; /* Use syslog instead of fprintf for errors */
+int tblflag; /* Support for dispatch table file */
+int callerflag; /* Generate svc_caller() function */
+
+#define INLINE 3
+/*length at which to start doing an inline */
+
+int doinline = INLINE; /* length at which to start doing an inline. 3
+ * = default if 0, no xdr_inline code */
+
+int indefinitewait; /* If started by port monitors, hang till it
+ * wants */
+int exitnow; /* If started by port monitors, exit after the
+ * call */
+int timerflag; /* TRUE if !indefinite && !exitnow */
+int newstyle; /* newstyle of passing arguments (by value) */
+int Cflag = 0; /* ANSI C syntax */
+static int allfiles; /* generate all files */
+int tirpcflag = 0; /* generating code for tirpc, by default */
+
+#ifdef __MSDOS__
+static char *dos_cppfile = NULL;
+#endif
+
+int main __P((int, char *[]));
+
+static char *extendfile __P((char *, char *));
+static void open_output __P((char *, char *));
+static void add_warning __P((void));
+static void clear_args __P((void));
+static void find_cpp __P((void));
+static void open_input __P((char *, char *));
+static int check_nettype __P((char *, char *[]));
+static void c_output __P((char *, char *, int, char *));
+static void c_initialize __P((void));
+static char *generate_guard __P((char *));
+static void h_output __P((char *, char *, int, char *));
+static void s_output __P((int, char *[], char *, char *, int, char *, int, int));
+static void l_output __P((char *, char *, int, char *));
+static void t_output __P((char *, char *, int, char *));
+static void svc_output __P((char *, char *, int, char *));
+static void clnt_output __P((char *, char *, int, char *));
+static int do_registers __P((int, char *[]));
+static void addarg __P((char *));
+static void putarg __P((int, char *));
+static void checkfiles __P((char *, char *));
+static int parseargs __P((int, char *[], struct commandline *));
+static void usage __P((void));
+static void options_usage __P((void));
+
+pid_t childpid;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct commandline cmd;
+
+ (void) memset((char *) &cmd, 0, sizeof(struct commandline));
+ clear_args();
+ if (!parseargs(argc, argv, &cmd))
+ usage();
+
+ if (cmd.cflag || cmd.hflag || cmd.lflag || cmd.tflag || cmd.sflag ||
+ cmd.mflag || cmd.nflag || cmd.Ssflag || cmd.Scflag) {
+ checkfiles(cmd.infile, cmd.outfile);
+ } else
+ checkfiles(cmd.infile, NULL);
+
+ if (cmd.cflag) {
+ c_output(cmd.infile, "-DRPC_XDR", DONT_EXTEND, cmd.outfile);
+ } else
+ if (cmd.hflag) {
+ h_output(cmd.infile, "-DRPC_HDR", DONT_EXTEND, cmd.outfile);
+ } else
+ if (cmd.lflag) {
+ l_output(cmd.infile, "-DRPC_CLNT", DONT_EXTEND, cmd.outfile);
+ } else
+ if (cmd.sflag || cmd.mflag || (cmd.nflag)) {
+ s_output(argc, argv, cmd.infile, "-DRPC_SVC", DONT_EXTEND,
+ cmd.outfile, cmd.mflag, cmd.nflag);
+ } else
+ if (cmd.tflag) {
+ t_output(cmd.infile, "-DRPC_TBL", DONT_EXTEND, cmd.outfile);
+ } else
+ if (cmd.Ssflag) {
+ svc_output(cmd.infile, "-DRPC_SERVER", DONT_EXTEND, cmd.outfile);
+ } else
+ if (cmd.Scflag) {
+ clnt_output(cmd.infile, "-DRPC_CLIENT", DONT_EXTEND, cmd.outfile);
+ } else {
+ /* the rescans
+ * are
+ * required,
+ * since cpp
+ * may effect
+ * input */
+ c_output(cmd.infile, "-DRPC_XDR", EXTEND, "_xdr.c");
+ reinitialize();
+ h_output(cmd.infile, "-DRPC_HDR", EXTEND, ".h");
+ reinitialize();
+ l_output(cmd.infile, "-DRPC_CLNT", EXTEND, "_clnt.c");
+ reinitialize();
+ if (inetdflag || !tirpcflag)
+ s_output(allc, allv, cmd.infile, "-DRPC_SVC", EXTEND,
+ "_svc.c", cmd.mflag, cmd.nflag);
+ else
+ s_output(allnc, allnv, cmd.infile, "-DRPC_SVC",
+ EXTEND, "_svc.c", cmd.mflag, cmd.nflag);
+ if (tblflag) {
+ reinitialize();
+ t_output(cmd.infile, "-DRPC_TBL", EXTEND, "_tbl.i");
+ }
+ if (allfiles) {
+ reinitialize();
+ svc_output(cmd.infile, "-DRPC_SERVER", EXTEND, "_server.c");
+ }
+ if (allfiles) {
+ reinitialize();
+ clnt_output(cmd.infile, "-DRPC_CLIENT", EXTEND, "_client.c");
+ }
+ }
+#ifdef __MSDOS__
+ if (dos_cppfile != NULL) {
+ (void) fclose(fin);
+ (void) unlink(dos_cppfile);
+ }
+#endif
+ exit(nonfatalerrors);
+ /* NOTREACHED */
+}
+/*
+ * add extension to filename
+ */
+static char *
+extendfile(path, ext)
+ char *path;
+ char *ext;
+{
+ char *file;
+ char *res;
+ char *p;
+
+ if ((file = strrchr(path, '/')) == NULL)
+ file = path;
+ else
+ file++;
+
+ res = alloc(strlen(file) + strlen(ext) + 1);
+ if (res == NULL) {
+ errx(1, "Out of memory");
+ }
+ p = strrchr(file, '.');
+ if (p == NULL) {
+ p = file + strlen(file);
+ }
+ (void) strcpy(res, file);
+ (void) strcpy(res + (p - file), ext);
+ return (res);
+}
+/*
+ * Open output file with given extension
+ */
+static void
+open_output(infile, outfile)
+ char *infile;
+ char *outfile;
+{
+
+ if (outfile == NULL) {
+ fout = stdout;
+ return;
+ }
+ if (infile != NULL && streq(outfile, infile)) {
+ f_print(stderr, "%s: output would overwrite %s\n", cmdname,
+ infile);
+ crash();
+ }
+ fout = fopen(outfile, "w");
+ if (fout == NULL) {
+ f_print(stderr, "%s: unable to open ", cmdname);
+ perror(outfile);
+ crash();
+ }
+ record_open(outfile);
+
+}
+
+static void
+add_warning()
+{
+ f_print(fout, "/*\n");
+ f_print(fout, " * Please do not edit this file.\n");
+ f_print(fout, " * It was generated using rpcgen.\n");
+ f_print(fout, " */\n\n");
+}
+/* clear list of arguments */
+static void
+clear_args()
+{
+ int i;
+ for (i = FIXEDARGS; i < ARGLISTLEN; i++)
+ arglist[i] = NULL;
+ argcount = FIXEDARGS;
+}
+/* make sure that a CPP exists */
+static void
+find_cpp()
+{
+ struct stat buf;
+
+ if (stat(CPP, &buf) < 0) { /* SVR4 or explicit cpp does not exist */
+ if (cppDefined) {
+ fprintf(stderr, "cannot find C preprocessor: %s\n", CPP);
+ crash();
+ } else { /* try the other one */
+ CPP = SUNOS_CPP;
+ if (stat(CPP, &buf) < 0) { /* can't find any cpp */
+ fprintf(stderr, "cannot find any C preprocessor (cpp)\n");
+ crash();
+ }
+ }
+ }
+}
+/*
+ * Open input file with given define for C-preprocessor
+ */
+static void
+open_input(infile, define)
+ char *infile;
+ char *define;
+{
+ int pd[2];
+
+ infilename = (infile == NULL) ? "<stdin>" : infile;
+#ifdef __MSDOS__
+#define DOSCPP "\\prog\\bc31\\bin\\cpp.exe"
+ {
+ int retval;
+ char drive[MAXDRIVE], dir[MAXDIR], name[MAXFILE], ext[MAXEXT];
+ char cppfile[MAXPATH];
+ char *cpp;
+
+ if ((cpp = searchpath("cpp.exe")) == NULL
+ && (cpp = getenv("RPCGENCPP")) == NULL)
+ cpp = DOSCPP;
+
+ putarg(0, cpp);
+ putarg(1, "-P-");
+ putarg(2, CPPFLAGS);
+ addarg(define);
+ addarg(infile);
+ addarg(NULL);
+
+ retval = spawnvp(P_WAIT, arglist[0], arglist);
+ if (retval != 0) {
+ fprintf(stderr, "%s: C PreProcessor failed\n", cmdname);
+ crash();
+ }
+ fnsplit(infile, drive, dir, name, ext);
+ fnmerge(cppfile, drive, dir, name, ".i");
+
+ fin = fopen(cppfile, "r");
+ if (fin == NULL) {
+ f_print(stderr, "%s: ", cmdname);
+ perror(cppfile);
+ crash();
+ }
+ dos_cppfile = strdup(cppfile);
+ if (dos_cppfile == NULL) {
+ fprintf(stderr, "%s: out of memory\n", cmdname);
+ crash();
+ }
+ }
+#else
+ (void) pipe(pd);
+ switch (childpid = fork()) {
+ case 0:
+ find_cpp();
+ putarg(0, CPP);
+ putarg(1, CPPFLAGS);
+ addarg(define);
+ addarg(infile);
+ addarg((char *) NULL);
+ (void) close(1);
+ (void) dup2(pd[1], 1);
+ (void) close(pd[0]);
+ execv(arglist[0], arglist);
+ perror("execv");
+ exit(1);
+ case -1:
+ perror("fork");
+ exit(1);
+ }
+ (void) close(pd[1]);
+ fin = fdopen(pd[0], "r");
+#endif
+ if (fin == NULL) {
+ f_print(stderr, "%s: ", cmdname);
+ perror(infilename);
+ crash();
+ }
+}
+/* valid tirpc nettypes */
+static char *valid_ti_nettypes[] =
+{
+ "netpath",
+ "visible",
+ "circuit_v",
+ "datagram_v",
+ "circuit_n",
+ "datagram_n",
+ "udp",
+ "tcp",
+ "raw",
+ NULL
+};
+/* valid inetd nettypes */
+static char *valid_i_nettypes[] =
+{
+ "udp",
+ "tcp",
+ NULL
+};
+
+static int
+check_nettype(name, list_to_check)
+ char *name;
+ char *list_to_check[];
+{
+ int i;
+ for (i = 0; list_to_check[i] != NULL; i++) {
+ if (strcmp(name, list_to_check[i]) == 0) {
+ return 1;
+ }
+ }
+ f_print(stderr, "illegal nettype :\'%s\'\n", name);
+ return 0;
+}
+/*
+ * Compile into an XDR routine output file
+ */
+
+static void
+c_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ char *include;
+ char *outfilename;
+ long tell;
+
+ c_initialize();
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ /* .h file already contains rpc/rpc.h */
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+ tell = ftell(fout);
+ while ((def = get_definition()) != NULL) {
+ emit(def);
+ }
+ if (extend && tell == ftell(fout)) {
+ (void) unlink(outfilename);
+ }
+}
+
+
+static void
+c_initialize()
+{
+
+ /* add all the starting basic types */
+
+ add_type(1, "int");
+ add_type(1, "long");
+ add_type(1, "short");
+ add_type(1, "bool");
+
+ add_type(1, "u_int");
+ add_type(1, "u_long");
+ add_type(1, "u_short");
+
+}
+
+char rpcgen_table_dcl[] = "struct rpcgen_table {\n\
+ char *(*proc)();\n\
+ xdrproc_t xdr_arg;\n\
+ unsigned len_arg;\n\
+ xdrproc_t xdr_res;\n\
+ unsigned len_res;\n\
+};\n";
+
+
+static char *
+generate_guard(pathname)
+ char *pathname;
+{
+ char *filename, *guard, *tmp;
+
+ filename = strrchr(pathname, '/'); /* find last component */
+ filename = ((filename == 0) ? pathname : filename + 1);
+ guard = strdup(filename);
+ /* convert to upper case */
+ tmp = guard;
+ while (*tmp) {
+ if (islower(*tmp))
+ *tmp = toupper(*tmp);
+ tmp++;
+ }
+
+ guard = extendfile(guard, "_H_RPCGEN");
+ return (guard);
+}
+/*
+ * Compile into an XDR header file
+ */
+
+static void
+h_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ char *outfilename;
+ long tell;
+ char *guard;
+ list *l;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ guard = generate_guard(outfilename ? outfilename : infile);
+
+ f_print(fout, "#ifndef _%s\n#define _%s\n\n", guard,
+ guard);
+
+ f_print(fout, "#define RPCGEN_VERSION\t%s\n\n", RPCGEN_VERSION);
+ f_print(fout, "#include <rpc/rpc.h>\n\n");
+
+ tell = ftell(fout);
+ /* print data definitions */
+ while ((def = get_definition()) != NULL) {
+ print_datadef(def);
+ }
+
+ /* print function declarations. Do this after data definitions
+ * because they might be used as arguments for functions */
+ for (l = defined; l != NULL; l = l->next) {
+ print_funcdef(l->val);
+ }
+ if (extend && tell == ftell(fout)) {
+ (void) unlink(outfilename);
+ } else
+ if (tblflag) {
+ f_print(fout, "%s", rpcgen_table_dcl);
+ }
+ f_print(fout, "\n#endif /* !_%s */\n", guard);
+}
+/*
+ * Compile into an RPC service
+ */
+static void
+s_output(argc, argv, infile, define, extend, outfile, nomain, netflag)
+ int argc;
+ char *argv[];
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+ int nomain;
+ int netflag;
+{
+ char *include;
+ definition *def;
+ int foundprogram = 0;
+ char *outfilename;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+
+ f_print(fout, "#include <sys/ioctl.h>\n");
+ f_print(fout, "#include <fcntl.h>\n");
+ f_print(fout, "#include <stdio.h>\n");
+ f_print(fout, "#include <stdlib.h>\n");
+ if (Cflag) {
+ f_print(fout, "#include <unistd.h>\n");
+ f_print(fout,
+ "#include <rpc/pmap_clnt.h>\n");
+ f_print(fout, "#include <string.h>\n");
+ }
+ f_print(fout, "#include <netdb.h>\n");
+ if (strcmp(svcclosetime, "-1") == 0)
+ indefinitewait = 1;
+ else
+ if (strcmp(svcclosetime, "0") == 0)
+ exitnow = 1;
+ else
+ if (inetdflag || pmflag) {
+ f_print(fout, "#include <signal.h>\n");
+ timerflag = 1;
+ }
+ if (!tirpcflag && inetdflag)
+ f_print(fout, "#include <sys/ttycom.h>\n");
+ if (Cflag && (inetdflag || pmflag)) {
+ f_print(fout, "#ifdef __cplusplus\n");
+ f_print(fout, "#include <sysent.h>\n");
+ f_print(fout, "#endif /* __cplusplus */\n");
+ }
+ if (tirpcflag)
+ f_print(fout, "#include <sys/types.h>\n");
+
+ f_print(fout, "#include <memory.h>\n");
+ if (tirpcflag)
+ f_print(fout, "#include <stropts.h>\n");
+
+ if (inetdflag || !tirpcflag) {
+ f_print(fout, "#include <sys/socket.h>\n");
+ f_print(fout, "#include <netinet/in.h>\n");
+ }
+ if ((netflag || pmflag) && tirpcflag) {
+ f_print(fout, "#include <netconfig.h>\n");
+ }
+ if ( /* timerflag && */ tirpcflag)
+ f_print(fout, "#include <sys/resource.h>\n");
+ if (logflag || inetdflag || pmflag)
+ f_print(fout, "#include <syslog.h>\n");
+
+ /* for ANSI-C */
+ f_print(fout, "\n#ifdef __STDC__\n#define SIG_PF void(*)(int)\n#endif\n");
+
+ f_print(fout, "\n#ifdef DEBUG\n#define RPC_SVC_FG\n#endif\n");
+ if (timerflag)
+ f_print(fout, "\n#define _RPCSVC_CLOSEDOWN %s\n", svcclosetime);
+ while ((def = get_definition()) != NULL) {
+ foundprogram |= (def->def_kind == DEF_PROGRAM);
+ }
+ if (extend && !foundprogram) {
+ (void) unlink(outfilename);
+ return;
+ }
+ if (callerflag) /* EVAS */
+ f_print(fout, "\nstatic SVCXPRT *caller;\n"); /* EVAS */
+ write_most(infile, netflag, nomain);
+ if (!nomain) {
+ if (!do_registers(argc, argv)) {
+ if (outfilename)
+ (void) unlink(outfilename);
+ usage();
+ }
+ write_rest();
+ }
+}
+/*
+ * generate client side stubs
+ */
+static void
+l_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ char *include;
+ definition *def;
+ int foundprogram = 0;
+ char *outfilename;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ if (Cflag)
+ f_print(fout, "#include <memory.h>\n");
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+ while ((def = get_definition()) != NULL) {
+ foundprogram |= (def->def_kind == DEF_PROGRAM);
+ }
+ if (extend && !foundprogram) {
+ (void) unlink(outfilename);
+ return;
+ }
+ write_stubs();
+}
+/*
+ * generate the dispatch table
+ */
+static void
+t_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ int foundprogram = 0;
+ char *outfilename;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ open_output(infile, outfilename);
+ add_warning();
+ while ((def = get_definition()) != NULL) {
+ foundprogram |= (def->def_kind == DEF_PROGRAM);
+ }
+ if (extend && !foundprogram) {
+ (void) unlink(outfilename);
+ return;
+ }
+ write_tables();
+}
+/* sample routine for the server template */
+static void
+svc_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ char *include;
+ char *outfilename;
+ long tell;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ checkfiles(infile, outfilename); /* check if outfile already
+ * exists. if so, print an
+ * error message and exit */
+ open_output(infile, outfilename);
+ add_sample_msg();
+
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+
+ tell = ftell(fout);
+ while ((def = get_definition()) != NULL) {
+ write_sample_svc(def);
+ }
+ if (extend && tell == ftell(fout)) {
+ (void) unlink(outfilename);
+ }
+}
+
+
+/* sample main routine for client */
+static void
+clnt_output(infile, define, extend, outfile)
+ char *infile;
+ char *define;
+ int extend;
+ char *outfile;
+{
+ definition *def;
+ char *include;
+ char *outfilename;
+ long tell;
+ int has_program = 0;
+
+ open_input(infile, define);
+ outfilename = extend ? extendfile(infile, outfile) : outfile;
+ checkfiles(infile, outfilename); /* check if outfile already
+ * exists. if so, print an
+ * error message and exit */
+
+ open_output(infile, outfilename);
+ add_sample_msg();
+ if (infile && (include = extendfile(infile, ".h"))) {
+ f_print(fout, "#include \"%s\"\n", include);
+ free(include);
+ } else
+ f_print(fout, "#include <rpc/rpc.h>\n");
+ tell = ftell(fout);
+ while ((def = get_definition()) != NULL) {
+ has_program += write_sample_clnt(def);
+ }
+
+ if (has_program)
+ write_sample_clnt_main();
+
+ if (extend && tell == ftell(fout)) {
+ (void) unlink(outfilename);
+ }
+}
+/*
+ * Perform registrations for service output
+ * Return 0 if failed; 1 otherwise.
+ */
+static int
+do_registers(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+
+ if (inetdflag || !tirpcflag) {
+ for (i = 1; i < argc; i++) {
+ if (streq(argv[i], "-s")) {
+ if (!check_nettype(argv[i + 1], valid_i_nettypes))
+ return 0;
+ write_inetd_register(argv[i + 1]);
+ i++;
+ }
+ }
+ } else {
+ for (i = 1; i < argc; i++)
+ if (streq(argv[i], "-s")) {
+ if (!check_nettype(argv[i + 1], valid_ti_nettypes))
+ return 0;
+ write_nettype_register(argv[i + 1]);
+ i++;
+ } else
+ if (streq(argv[i], "-n")) {
+ write_netid_register(argv[i + 1]);
+ i++;
+ }
+ }
+ return 1;
+}
+/*
+ * Add another argument to the arg list
+ */
+static void
+addarg(cp)
+ char *cp;
+{
+ if (argcount >= ARGLISTLEN) {
+ f_print(stderr, "rpcgen: too many defines\n");
+ crash();
+ /* NOTREACHED */
+ }
+ arglist[argcount++] = cp;
+
+}
+
+static void
+putarg(where, cp)
+ char *cp;
+ int where;
+{
+ if (where >= ARGLISTLEN) {
+ f_print(stderr, "rpcgen: arglist coding error\n");
+ crash();
+ /* NOTREACHED */
+ }
+ arglist[where] = cp;
+
+}
+/*
+ * if input file is stdin and an output file is specified then complain
+ * if the file already exists. Otherwise the file may get overwritten
+ * If input file does not exist, exit with an error
+ */
+
+static void
+checkfiles(infile, outfile)
+ char *infile;
+ char *outfile;
+{
+
+ struct stat buf;
+
+ if (infile) /* infile ! = NULL */
+ if (stat(infile, &buf) < 0) {
+ perror(infile);
+ crash();
+ };
+#if 0
+ if (outfile) {
+ if (stat(outfile, &buf) < 0)
+ return; /* file does not exist */
+ else {
+ f_print(stderr,
+ "file '%s' already exists and may be overwritten\n", outfile);
+ crash();
+ }
+ }
+#endif
+}
+/*
+ * Parse command line arguments
+ */
+static int
+parseargs(argc, argv, cmd)
+ int argc;
+ char *argv[];
+ struct commandline *cmd;
+{
+ int i;
+ int j;
+ int c;
+ char flag[(1 << 8 * sizeof(char))];
+ int nflags;
+
+ cmdname = argv[0];
+ cmd->infile = cmd->outfile = NULL;
+ if (argc < 2) {
+ return (0);
+ }
+ allfiles = 0;
+ flag['c'] = 0;
+ flag['h'] = 0;
+ flag['l'] = 0;
+ flag['m'] = 0;
+ flag['o'] = 0;
+ flag['s'] = 0;
+ flag['n'] = 0;
+ flag['t'] = 0;
+ flag['S'] = 0;
+ flag['C'] = 0;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-') {
+ if (cmd->infile) {
+ f_print(stderr, "Cannot specify more than one input file!\n");
+
+ return (0);
+ }
+ cmd->infile = argv[i];
+ } else {
+ for (j = 1; argv[i][j] != 0; j++) {
+ c = argv[i][j];
+ switch (c) {
+ case 'A':
+ callerflag = 1;
+ break;
+ case 'a':
+ allfiles = 1;
+ break;
+ case 'c':
+ case 'h':
+ case 'l':
+ case 'm':
+ case 't':
+ if (flag[c]) {
+ return (0);
+ }
+ flag[c] = 1;
+ break;
+ case 'S':
+ /* sample flag: Ss or Sc. Ss means set
+ * flag['S']; Sc means set flag['C']; */
+ c = argv[i][++j]; /* get next char */
+ if (c == 's')
+ c = 'S';
+ else
+ if (c == 'c')
+ c = 'C';
+ else
+ return (0);
+
+ if (flag[c]) {
+ return (0);
+ }
+ flag[c] = 1;
+ break;
+ case 'C': /* ANSI C syntax */
+ Cflag = 1;
+ break;
+
+ case 'b': /* turn TIRPC flag off for
+ * generating backward
+ * compatible */
+ tirpcflag = 0;
+ break;
+
+ case 'I':
+ inetdflag = 1;
+ break;
+ case 'N':
+ newstyle = 1;
+ break;
+ case 'L':
+ logflag = 1;
+ break;
+ case 'K':
+ if (++i == argc) {
+ return (0);
+ }
+ svcclosetime = argv[i];
+ goto nextarg;
+ case 'T':
+ tblflag = 1;
+ break;
+ case 'i':
+ if (++i == argc) {
+ return (0);
+ }
+ doinline = atoi(argv[i]);
+ goto nextarg;
+ case 'n':
+ case 'o':
+ case 's':
+ if (argv[i][j - 1] != '-' ||
+ argv[i][j + 1] != 0) {
+ return (0);
+ }
+ flag[c] = 1;
+ if (++i == argc) {
+ return (0);
+ }
+ if (c == 's') {
+ if (!streq(argv[i], "udp") &&
+ !streq(argv[i], "tcp")) {
+ return (0);
+ }
+ } else
+ if (c == 'o') {
+ if (cmd->outfile) {
+ return (0);
+ }
+ cmd->outfile = argv[i];
+ }
+ goto nextarg;
+ case 'D':
+ if (argv[i][j - 1] != '-') {
+ return (0);
+ }
+ (void) addarg(argv[i]);
+ goto nextarg;
+ case 'Y':
+ if (++i == argc) {
+ return (0);
+ }
+ (void) strcpy(pathbuf, argv[i]);
+ (void) strcat(pathbuf, "/cpp");
+ CPP = pathbuf;
+ cppDefined = 1;
+ goto nextarg;
+
+
+
+ default:
+ return (0);
+ }
+ }
+ nextarg:
+ ;
+ }
+ }
+
+ cmd->cflag = flag['c'];
+ cmd->hflag = flag['h'];
+ cmd->lflag = flag['l'];
+ cmd->mflag = flag['m'];
+ cmd->nflag = flag['n'];
+ cmd->sflag = flag['s'];
+ cmd->tflag = flag['t'];
+ cmd->Ssflag = flag['S'];
+ cmd->Scflag = flag['C'];
+
+ if (tirpcflag) {
+ pmflag = inetdflag ? 0 : 1; /* pmflag or inetdflag is
+ * always TRUE */
+ if ((inetdflag && cmd->nflag)) { /* netid not allowed
+ * with inetdflag */
+ f_print(stderr, "Cannot use netid flag with inetd flag!\n");
+ return (0);
+ }
+ } else { /* 4.1 mode */
+ pmflag = 0; /* set pmflag only in tirpcmode */
+ inetdflag = 1; /* inetdflag is TRUE by default */
+ if (cmd->nflag) { /* netid needs TIRPC */
+ f_print(stderr, "Cannot use netid flag without TIRPC!\n");
+ return (0);
+ }
+ }
+
+ if (newstyle && (tblflag || cmd->tflag)) {
+ f_print(stderr, "Cannot use table flags with newstyle!\n");
+ return (0);
+ }
+ /* check no conflicts with file generation flags */
+ nflags = cmd->cflag + cmd->hflag + cmd->lflag + cmd->mflag +
+ cmd->sflag + cmd->nflag + cmd->tflag + cmd->Ssflag + cmd->Scflag;
+
+ if (nflags == 0) {
+ if (cmd->outfile != NULL || cmd->infile == NULL) {
+ return (0);
+ }
+ } else
+ if (nflags > 1) {
+ f_print(stderr, "Cannot have more than one file generation flag!\n");
+ return (0);
+ }
+ return (1);
+}
+
+static void
+usage()
+{
+ f_print(stderr, "usage: %s infile\n", cmdname);
+ f_print(stderr, "\t%s [-a][-b][-C][-Dname[=value]] -i size [-I [-K seconds]] [-A][-L][-M toolkit][-N][-T] infile\n",
+ cmdname);
+ f_print(stderr, "\t%s [-c | -h | -l | -m | -t | -Sc | -Ss] [-o outfile] [infile]\n",
+ cmdname);
+ f_print(stderr, "\t%s [-s nettype]* [-o outfile] [infile]\n", cmdname);
+ f_print(stderr, "\t%s [-n netid]* [-o outfile] [infile]\n", cmdname);
+ options_usage();
+ exit(1);
+}
+
+static void
+options_usage()
+{
+ f_print(stderr, "options:\n");
+ f_print(stderr, "-A\t\tgenerate svc_caller() function\n");
+ f_print(stderr, "-a\t\tgenerate all files, including samples\n");
+ f_print(stderr, "-b\t\tbackward compatibility mode (generates code for SunOS 4.1)\n");
+ f_print(stderr, "-c\t\tgenerate XDR routines\n");
+ f_print(stderr, "-C\t\tANSI C mode\n");
+ f_print(stderr, "-Dname[=value]\tdefine a symbol (same as #define)\n");
+ f_print(stderr, "-h\t\tgenerate header file\n");
+ f_print(stderr, "-i size\t\tsize at which to start generating inline code\n");
+ f_print(stderr, "-I\t\tgenerate code for inetd support in server (for SunOS 4.1)\n");
+ f_print(stderr, "-K seconds\tserver exits after K seconds of inactivity\n");
+ f_print(stderr, "-l\t\tgenerate client side stubs\n");
+ f_print(stderr, "-L\t\tserver errors will be printed to syslog\n");
+ f_print(stderr, "-m\t\tgenerate server side stubs\n");
+ f_print(stderr, "-n netid\tgenerate server code that supports named netid\n");
+ f_print(stderr, "-N\t\tsupports multiple arguments and call-by-value\n");
+ f_print(stderr, "-o outfile\tname of the output file\n");
+ f_print(stderr, "-s nettype\tgenerate server code that supports named nettype\n");
+ f_print(stderr, "-Sc\t\tgenerate sample client code that uses remote procedures\n");
+ f_print(stderr, "-Ss\t\tgenerate sample server code that defines remote procedures\n");
+ f_print(stderr, "-t\t\tgenerate RPC dispatch table\n");
+ f_print(stderr, "-T\t\tgenerate code to support RPC dispatch tables\n");
+ f_print(stderr, "-Y path\t\tdirectory name to find C preprocessor (cpp)\n");
+
+ exit(1);
+}
diff --git a/developer_cmds/rpcgen/rpc_parse.c b/developer_cmds/rpcgen/rpc_parse.c
new file mode 100644
index 0000000..db0c1f1
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_parse.c
@@ -0,0 +1,643 @@
+/* $NetBSD: rpc_parse.c,v 1.9 1998/02/11 23:11:18 lukem Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_parse.c 1.8 89/02/22 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_parse.c,v 1.9 1998/02/11 23:11:18 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_parse.c, Parser for the RPC protocol compiler
+ * Copyright (C) 1987 Sun Microsystems, Inc.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rpc/types.h"
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define ARGNAME "arg"
+
+static void isdefined __P((definition *));
+static void def_struct __P((definition *));
+static void def_program __P((definition *));
+static void def_enum __P((definition *));
+static void def_const __P((definition *));
+static void def_union __P((definition *));
+static void check_type_name __P((char *, int));
+static void def_typedef __P((definition *));
+static void get_declaration __P((declaration *, defkind));
+static void get_prog_declaration __P((declaration *, defkind, int));
+static void get_type __P((char **, char **, defkind));
+static void unsigned_dec __P((char **));
+
+/*
+ * return the next definition you see
+ */
+definition *
+get_definition()
+{
+ definition *defp;
+ token tok;
+
+ defp = ALLOC(definition);
+ get_token(&tok);
+ switch (tok.kind) {
+ case TOK_STRUCT:
+ def_struct(defp);
+ break;
+ case TOK_UNION:
+ def_union(defp);
+ break;
+ case TOK_TYPEDEF:
+ def_typedef(defp);
+ break;
+ case TOK_ENUM:
+ def_enum(defp);
+ break;
+ case TOK_PROGRAM:
+ def_program(defp);
+ break;
+ case TOK_CONST:
+ def_const(defp);
+ break;
+ case TOK_EOF:
+ return (NULL);
+ default:
+ error("definition keyword expected");
+ }
+ scan(TOK_SEMICOLON, &tok);
+ isdefined(defp);
+ return (defp);
+}
+
+static void
+isdefined(defp)
+ definition *defp;
+{
+ STOREVAL(&defined, defp);
+}
+
+static void
+def_struct(defp)
+ definition *defp;
+{
+ token tok;
+ declaration dec;
+ decl_list *decls;
+ decl_list **tailp;
+
+ defp->def_kind = DEF_STRUCT;
+
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_LBRACE, &tok);
+ tailp = &defp->def.st.decls;
+ do {
+ get_declaration(&dec, DEF_STRUCT);
+ decls = ALLOC(decl_list);
+ decls->decl = dec;
+ *tailp = decls;
+ tailp = &decls->next;
+ scan(TOK_SEMICOLON, &tok);
+ peek(&tok);
+ } while (tok.kind != TOK_RBRACE);
+ get_token(&tok);
+ *tailp = NULL;
+}
+
+static void
+def_program(defp)
+ definition *defp;
+{
+ token tok;
+ declaration dec;
+ decl_list *decls;
+ decl_list **tailp;
+ version_list *vlist;
+ version_list **vtailp;
+ proc_list *plist;
+ proc_list **ptailp;
+ int num_args;
+ bool_t isvoid = FALSE; /* whether first argument is void */
+ defp->def_kind = DEF_PROGRAM;
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_LBRACE, &tok);
+ vtailp = &defp->def.pr.versions;
+ tailp = &defp->def.st.decls;
+ scan(TOK_VERSION, &tok);
+ do {
+ scan(TOK_IDENT, &tok);
+ vlist = ALLOC(version_list);
+ vlist->vers_name = tok.str;
+ scan(TOK_LBRACE, &tok);
+ ptailp = &vlist->procs;
+ do {
+ /* get result type */
+ plist = ALLOC(proc_list);
+ get_type(&plist->res_prefix, &plist->res_type,
+ DEF_PROGRAM);
+ if (streq(plist->res_type, "opaque")) {
+ error("illegal result type");
+ }
+ scan(TOK_IDENT, &tok);
+ plist->proc_name = tok.str;
+ scan(TOK_LPAREN, &tok);
+ /* get args - first one */
+ num_args = 1;
+ isvoid = FALSE;
+ /* type of DEF_PROGRAM in the first
+ * get_prog_declaration and DEF_STURCT in the next
+ * allows void as argument if it is the only argument */
+ get_prog_declaration(&dec, DEF_PROGRAM, num_args);
+ if (streq(dec.type, "void"))
+ isvoid = TRUE;
+ decls = ALLOC(decl_list);
+ plist->args.decls = decls;
+ decls->decl = dec;
+ tailp = &decls->next;
+ /* get args */
+ while (peekscan(TOK_COMMA, &tok)) {
+ num_args++;
+ get_prog_declaration(&dec, DEF_STRUCT,
+ num_args);
+ decls = ALLOC(decl_list);
+ decls->decl = dec;
+ *tailp = decls;
+ if (streq(dec.type, "void"))
+ isvoid = TRUE;
+ tailp = &decls->next;
+ }
+ /* multiple arguments are only allowed in newstyle */
+ if (!newstyle && num_args > 1) {
+ error("only one argument is allowed");
+ }
+ if (isvoid && num_args > 1) {
+ error("illegal use of void in program definition");
+ }
+ *tailp = NULL;
+ scan(TOK_RPAREN, &tok);
+ scan(TOK_EQUAL, &tok);
+ scan_num(&tok);
+ scan(TOK_SEMICOLON, &tok);
+ plist->proc_num = tok.str;
+ plist->arg_num = num_args;
+ *ptailp = plist;
+ ptailp = &plist->next;
+ peek(&tok);
+ } while (tok.kind != TOK_RBRACE);
+ *ptailp = NULL;
+ *vtailp = vlist;
+ vtailp = &vlist->next;
+ scan(TOK_RBRACE, &tok);
+ scan(TOK_EQUAL, &tok);
+ scan_num(&tok);
+ vlist->vers_num = tok.str;
+ /* make the argument structure name for each arg */
+ for (plist = vlist->procs; plist != NULL;
+ plist = plist->next) {
+ plist->args.argname = make_argname(plist->proc_name,
+ vlist->vers_num);
+ /* free the memory ?? */
+ }
+ scan(TOK_SEMICOLON, &tok);
+ scan2(TOK_VERSION, TOK_RBRACE, &tok);
+ } while (tok.kind == TOK_VERSION);
+ scan(TOK_EQUAL, &tok);
+ scan_num(&tok);
+ defp->def.pr.prog_num = tok.str;
+ *vtailp = NULL;
+}
+
+
+static void
+def_enum(defp)
+ definition *defp;
+{
+ token tok;
+ enumval_list *elist;
+ enumval_list **tailp;
+
+ defp->def_kind = DEF_ENUM;
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_LBRACE, &tok);
+ tailp = &defp->def.en.vals;
+ do {
+ scan(TOK_IDENT, &tok);
+ elist = ALLOC(enumval_list);
+ elist->name = tok.str;
+ elist->assignment = NULL;
+ scan3(TOK_COMMA, TOK_RBRACE, TOK_EQUAL, &tok);
+ if (tok.kind == TOK_EQUAL) {
+ scan_num(&tok);
+ elist->assignment = tok.str;
+ scan2(TOK_COMMA, TOK_RBRACE, &tok);
+ }
+ *tailp = elist;
+ tailp = &elist->next;
+ } while (tok.kind != TOK_RBRACE);
+ *tailp = NULL;
+}
+
+static void
+def_const(defp)
+ definition *defp;
+{
+ token tok;
+
+ defp->def_kind = DEF_CONST;
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_EQUAL, &tok);
+ scan2(TOK_IDENT, TOK_STRCONST, &tok);
+ defp->def.co = tok.str;
+}
+
+static void
+def_union(defp)
+ definition *defp;
+{
+ token tok;
+ declaration dec;
+ case_list *cases;
+ case_list **tailp;
+ int flag;
+
+ defp->def_kind = DEF_UNION;
+ scan(TOK_IDENT, &tok);
+ defp->def_name = tok.str;
+ scan(TOK_SWITCH, &tok);
+ scan(TOK_LPAREN, &tok);
+ get_declaration(&dec, DEF_UNION);
+ defp->def.un.enum_decl = dec;
+ tailp = &defp->def.un.cases;
+ scan(TOK_RPAREN, &tok);
+ scan(TOK_LBRACE, &tok);
+ scan(TOK_CASE, &tok);
+ while (tok.kind == TOK_CASE) {
+ scan2(TOK_IDENT, TOK_CHARCONST, &tok);
+ cases = ALLOC(case_list);
+ cases->case_name = tok.str;
+ scan(TOK_COLON, &tok);
+ /* now peek at next token */
+ flag = 0;
+ if (peekscan(TOK_CASE, &tok)) {
+
+ do {
+ scan2(TOK_IDENT, TOK_CHARCONST, &tok);
+ cases->contflag = 1; /* continued case
+ * statement */
+ *tailp = cases;
+ tailp = &cases->next;
+ cases = ALLOC(case_list);
+ cases->case_name = tok.str;
+ scan(TOK_COLON, &tok);
+
+ } while (peekscan(TOK_CASE, &tok));
+ } else
+ if (flag) {
+
+ *tailp = cases;
+ tailp = &cases->next;
+ cases = ALLOC(case_list);
+ };
+
+ get_declaration(&dec, DEF_UNION);
+ cases->case_decl = dec;
+ cases->contflag = 0; /* no continued case statement */
+ *tailp = cases;
+ tailp = &cases->next;
+ scan(TOK_SEMICOLON, &tok);
+
+ scan3(TOK_CASE, TOK_DEFAULT, TOK_RBRACE, &tok);
+ }
+ *tailp = NULL;
+ if (tok.kind == TOK_DEFAULT) {
+ scan(TOK_COLON, &tok);
+ get_declaration(&dec, DEF_UNION);
+ defp->def.un.default_decl = ALLOC(declaration);
+ *defp->def.un.default_decl = dec;
+ scan(TOK_SEMICOLON, &tok);
+ scan(TOK_RBRACE, &tok);
+ } else {
+ defp->def.un.default_decl = NULL;
+ }
+}
+
+static char *reserved_words[] = {
+ "array",
+ "bytes",
+ "destroy",
+ "free",
+ "getpos",
+ "inline",
+ "pointer",
+ "reference",
+ "setpos",
+ "sizeof",
+ "union",
+ "vector",
+ NULL
+};
+
+static char *reserved_types[] = {
+ "opaque",
+ "string",
+ NULL
+};
+/* check that the given name is not one that would eventually result in
+ xdr routines that would conflict with internal XDR routines. */
+static void
+check_type_name(name, new_type)
+ int new_type;
+ char *name;
+{
+ int i;
+ char tmp[100];
+
+ for (i = 0; reserved_words[i] != NULL; i++) {
+ if (strcmp(name, reserved_words[i]) == 0) {
+ sprintf(tmp,
+ "illegal (reserved) name :\'%s\' in type definition", name);
+ error(tmp);
+ }
+ }
+ if (new_type) {
+ for (i = 0; reserved_types[i] != NULL; i++) {
+ if (strcmp(name, reserved_types[i]) == 0) {
+ sprintf(tmp,
+ "illegal (reserved) name :\'%s\' in type definition", name);
+ error(tmp);
+ }
+ }
+ }
+}
+
+static void
+def_typedef(defp)
+ definition *defp;
+{
+ declaration dec;
+
+ defp->def_kind = DEF_TYPEDEF;
+ get_declaration(&dec, DEF_TYPEDEF);
+ defp->def_name = dec.name;
+ check_type_name(dec.name, 1);
+ defp->def.ty.old_prefix = dec.prefix;
+ defp->def.ty.old_type = dec.type;
+ defp->def.ty.rel = dec.rel;
+ defp->def.ty.array_max = dec.array_max;
+}
+
+static void
+get_declaration(dec, dkind)
+ declaration *dec;
+ defkind dkind;
+{
+ token tok;
+
+ get_type(&dec->prefix, &dec->type, dkind);
+ dec->rel = REL_ALIAS;
+ if (streq(dec->type, "void")) {
+ return;
+ }
+ check_type_name(dec->type, 0);
+
+ scan2(TOK_STAR, TOK_IDENT, &tok);
+ if (tok.kind == TOK_STAR) {
+ dec->rel = REL_POINTER;
+ scan(TOK_IDENT, &tok);
+ }
+ dec->name = tok.str;
+ if (peekscan(TOK_LBRACKET, &tok)) {
+ if (dec->rel == REL_POINTER) {
+ error("no array-of-pointer declarations -- use typedef");
+ }
+ dec->rel = REL_VECTOR;
+ scan_num(&tok);
+ dec->array_max = tok.str;
+ scan(TOK_RBRACKET, &tok);
+ } else
+ if (peekscan(TOK_LANGLE, &tok)) {
+ if (dec->rel == REL_POINTER) {
+ error("no array-of-pointer declarations -- use typedef");
+ }
+ dec->rel = REL_ARRAY;
+ if (peekscan(TOK_RANGLE, &tok)) {
+ dec->array_max = "~0"; /* unspecified size, use
+ * max */
+ } else {
+ scan_num(&tok);
+ dec->array_max = tok.str;
+ scan(TOK_RANGLE, &tok);
+ }
+ }
+ if (streq(dec->type, "opaque")) {
+ if (dec->rel != REL_ARRAY && dec->rel != REL_VECTOR) {
+ error("array declaration expected");
+ }
+ } else
+ if (streq(dec->type, "string")) {
+ if (dec->rel != REL_ARRAY) {
+ error("variable-length array declaration expected");
+ }
+ }
+}
+
+static void
+get_prog_declaration(dec, dkind, num)
+ declaration *dec;
+ defkind dkind;
+ int num; /* arg number */
+{
+ token tok;
+ char name[10]; /* argument name */
+
+ if (dkind == DEF_PROGRAM) {
+ peek(&tok);
+ if (tok.kind == TOK_RPAREN) { /* no arguments */
+ dec->rel = REL_ALIAS;
+ dec->type = "void";
+ dec->prefix = NULL;
+ dec->name = NULL;
+ return;
+ }
+ }
+ get_type(&dec->prefix, &dec->type, dkind);
+ dec->rel = REL_ALIAS;
+ if (peekscan(TOK_IDENT, &tok)) /* optional name of argument */
+ strcpy(name, tok.str);
+ else
+ sprintf(name, "%s%d", ARGNAME, num); /* default name of
+ * argument */
+
+ dec->name = (char *) strdup(name);
+
+ if (streq(dec->type, "void")) {
+ return;
+ }
+ if (streq(dec->type, "opaque")) {
+ error("opaque -- illegal argument type");
+ }
+ if (peekscan(TOK_STAR, &tok)) {
+ if (streq(dec->type, "string")) {
+ error("pointer to string not allowed in program arguments\n");
+ }
+ dec->rel = REL_POINTER;
+ if (peekscan(TOK_IDENT, &tok)) /* optional name of argument */
+ dec->name = (char *) strdup(tok.str);
+ }
+ if (peekscan(TOK_LANGLE, &tok)) {
+ if (!streq(dec->type, "string")) {
+ error("arrays cannot be declared as arguments to procedures -- use typedef");
+ }
+ dec->rel = REL_ARRAY;
+ if (peekscan(TOK_RANGLE, &tok)) {
+ dec->array_max = "~0"; /* unspecified size, use max */
+ } else {
+ scan_num(&tok);
+ dec->array_max = tok.str;
+ scan(TOK_RANGLE, &tok);
+ }
+ }
+ if (streq(dec->type, "string")) {
+ if (dec->rel != REL_ARRAY) { /* .x specifies just string as
+ * type of argument - make it
+ * string<> */
+ dec->rel = REL_ARRAY;
+ dec->array_max = "~0"; /* unspecified size, use max */
+ }
+ }
+}
+
+
+
+static void
+get_type(prefixp, typep, dkind)
+ char **prefixp;
+ char **typep;
+ defkind dkind;
+{
+ token tok;
+
+ *prefixp = NULL;
+ get_token(&tok);
+ switch (tok.kind) {
+ case TOK_IDENT:
+ *typep = tok.str;
+ break;
+ case TOK_STRUCT:
+ case TOK_ENUM:
+ case TOK_UNION:
+ *prefixp = tok.str;
+ scan(TOK_IDENT, &tok);
+ *typep = tok.str;
+ break;
+ case TOK_UNSIGNED:
+ unsigned_dec(typep);
+ break;
+ case TOK_SHORT:
+ *typep = "short";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_LONG:
+ *typep = "long";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_HYPER:
+ *typep = "int64_t";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_VOID:
+ if (dkind != DEF_UNION && dkind != DEF_PROGRAM) {
+ error("voids allowed only inside union and program definitions with one argument");
+ }
+ *typep = tok.str;
+ break;
+ case TOK_STRING:
+ case TOK_OPAQUE:
+ case TOK_CHAR:
+ case TOK_INT:
+ case TOK_FLOAT:
+ case TOK_DOUBLE:
+ case TOK_QUAD:
+ case TOK_BOOL:
+ *typep = tok.str;
+ break;
+ default:
+ error("expected type specifier");
+ }
+}
+
+static void
+unsigned_dec(typep)
+ char **typep;
+{
+ token tok;
+
+ peek(&tok);
+ switch (tok.kind) {
+ case TOK_CHAR:
+ get_token(&tok);
+ *typep = "u_char";
+ break;
+ case TOK_SHORT:
+ get_token(&tok);
+ *typep = "u_short";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_LONG:
+ get_token(&tok);
+ *typep = "u_long";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_HYPER:
+ get_token(&tok);
+ *typep = "u_int64_t";
+ (void) peekscan(TOK_INT, &tok);
+ break;
+ case TOK_INT:
+ get_token(&tok);
+ *typep = "u_int";
+ break;
+ default:
+ *typep = "u_int";
+ break;
+ }
+}
diff --git a/developer_cmds/rpcgen/rpc_parse.h b/developer_cmds/rpcgen/rpc_parse.h
new file mode 100644
index 0000000..e235bf5
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_parse.h
@@ -0,0 +1,168 @@
+/* $NetBSD: rpc_parse.h,v 1.4 1997/10/11 21:01:42 christos Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/* @(#)rpc_parse.h 1.3 90/08/29 (C) 1987 SMI */
+
+/*
+ * rpc_parse.h, Definitions for the RPCL parser
+ */
+
+enum defkind {
+ DEF_CONST,
+ DEF_STRUCT,
+ DEF_UNION,
+ DEF_ENUM,
+ DEF_TYPEDEF,
+ DEF_PROGRAM
+};
+typedef enum defkind defkind;
+
+typedef char *const_def;
+
+enum relation {
+ REL_VECTOR, /* fixed length array */
+ REL_ARRAY, /* variable length array */
+ REL_POINTER, /* pointer */
+ REL_ALIAS, /* simple */
+};
+typedef enum relation relation;
+
+struct typedef_def {
+ char *old_prefix;
+ char *old_type;
+ relation rel;
+ char *array_max;
+};
+typedef struct typedef_def typedef_def;
+
+struct enumval_list {
+ char *name;
+ char *assignment;
+ struct enumval_list *next;
+};
+typedef struct enumval_list enumval_list;
+
+struct enum_def {
+ enumval_list *vals;
+};
+typedef struct enum_def enum_def;
+
+struct declaration {
+ char *prefix;
+ char *type;
+ char *name;
+ relation rel;
+ char *array_max;
+};
+typedef struct declaration declaration;
+
+struct decl_list {
+ declaration decl;
+ struct decl_list *next;
+};
+typedef struct decl_list decl_list;
+
+struct struct_def {
+ decl_list *decls;
+};
+typedef struct struct_def struct_def;
+
+struct case_list {
+ char *case_name;
+ int contflag;
+ declaration case_decl;
+ struct case_list *next;
+};
+typedef struct case_list case_list;
+
+struct union_def {
+ declaration enum_decl;
+ case_list *cases;
+ declaration *default_decl;
+};
+typedef struct union_def union_def;
+
+struct arg_list {
+ char *argname; /* name of struct for arg*/
+ decl_list *decls;
+};
+
+typedef struct arg_list arg_list;
+
+struct proc_list {
+ char *proc_name;
+ char *proc_num;
+ arg_list args;
+ int arg_num;
+ char *res_type;
+ char *res_prefix;
+ struct proc_list *next;
+};
+typedef struct proc_list proc_list;
+
+struct version_list {
+ char *vers_name;
+ char *vers_num;
+ proc_list *procs;
+ struct version_list *next;
+};
+typedef struct version_list version_list;
+
+struct program_def {
+ char *prog_num;
+ version_list *versions;
+};
+typedef struct program_def program_def;
+
+struct definition {
+ char *def_name;
+ defkind def_kind;
+ union {
+ const_def co;
+ struct_def st;
+ union_def un;
+ enum_def en;
+ typedef_def ty;
+ program_def pr;
+ } def;
+};
+typedef struct definition definition;
+
+definition *get_definition __P((void));
+
+struct bas_type
+{
+ char *name;
+ int length;
+ struct bas_type *next;
+};
+
+typedef struct bas_type bas_type;
diff --git a/developer_cmds/rpcgen/rpc_sample.c b/developer_cmds/rpcgen/rpc_sample.c
new file mode 100644
index 0000000..3fee135
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_sample.c
@@ -0,0 +1,261 @@
+/* $NetBSD: rpc_sample.c,v 1.5 1997/10/18 10:54:01 lukem Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_sample.c 1.1 90/08/30 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_sample.c,v 1.5 1997/10/18 10:54:01 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_sample.c, Sample client-server code outputter for the RPC protocol compiler
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+static char RQSTP[] = "rqstp";
+
+static void write_sample_client __P((char *, version_list *));
+static void write_sample_server __P((definition *));
+static void return_type __P((proc_list *));
+
+void
+write_sample_svc(def)
+ definition *def;
+{
+
+ if (def->def_kind != DEF_PROGRAM)
+ return;
+ write_sample_server(def);
+}
+
+
+int
+write_sample_clnt(def)
+ definition *def;
+{
+ version_list *vp;
+ int count = 0;
+
+ if (def->def_kind != DEF_PROGRAM)
+ return (0);
+ /* generate sample code for each version */
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ write_sample_client(def->def_name, vp);
+ ++count;
+ }
+ return (count);
+}
+
+
+static void
+write_sample_client(program_name, vp)
+ char *program_name;
+ version_list *vp;
+{
+ proc_list *proc;
+ int i;
+ decl_list *l;
+
+ f_print(fout, "\n\nvoid\n");
+ pvname(program_name, vp->vers_num);
+ if (Cflag)
+ f_print(fout, "( char* host )\n{\n");
+ else
+ f_print(fout, "(host)\nchar *host;\n{\n");
+ f_print(fout, "\tCLIENT *clnt;\n");
+
+ i = 0;
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\t");
+ ptype(proc->res_prefix, proc->res_type, 1);
+ f_print(fout, " *result_%d;\n", ++i);
+ /* print out declarations for arguments */
+ if (proc->arg_num < 2 && !newstyle) {
+ f_print(fout, "\t");
+ if (!streq(proc->args.decls->decl.type, "void"))
+ ptype(proc->args.decls->decl.prefix, proc->args.decls->decl.type, 1);
+ else
+ f_print(fout, "char* "); /* cannot have "void"
+ * type */
+ f_print(fout, " ");
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_arg;\n");
+ } else
+ if (!streq(proc->args.decls->decl.type, "void")) {
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ f_print(fout, "\t");
+ ptype(l->decl.prefix, l->decl.type, 1);
+ f_print(fout, " ");
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_%s;\n", l->decl.name);
+/* pdeclaration(proc->args.argname, &l->decl, 1, ";\n" );*/
+ }
+ }
+ }
+
+ /* generate creation of client handle */
+ f_print(fout, "\tclnt = clnt_create(host, %s, %s, \"%s\");\n",
+ program_name, vp->vers_name, tirpcflag ? "netpath" : "udp");
+ f_print(fout, "\tif (clnt == NULL) {\n");
+ f_print(fout, "\t\tclnt_pcreateerror(host);\n");
+ f_print(fout, "\t\texit(1);\n\t}\n");
+
+ /* generate calls to procedures */
+ i = 0;
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\tresult_%d = ", ++i);
+ pvname(proc->proc_name, vp->vers_num);
+ if (proc->arg_num < 2 && !newstyle) {
+ f_print(fout, "(");
+ if (streq(proc->args.decls->decl.type, "void")) /* cast to void* */
+ f_print(fout, "(void*)");
+ f_print(fout, "&");
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_arg, clnt);\n");
+ } else
+ if (streq(proc->args.decls->decl.type, "void")) {
+ f_print(fout, "(clnt);\n");
+ } else {
+ f_print(fout, "(");
+ for (l = proc->args.decls; l != NULL; l = l->next) {
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_%s, ", l->decl.name);
+ }
+ f_print(fout, "clnt);\n");
+ }
+ f_print(fout, "\tif (result_%d == NULL) {\n", i);
+ f_print(fout, "\t\tclnt_perror(clnt, \"call failed:\");\n");
+ f_print(fout, "\t}\n");
+ }
+
+ f_print(fout, "\tclnt_destroy( clnt );\n");
+ f_print(fout, "}\n");
+}
+
+static void
+write_sample_server(def)
+ definition *def;
+{
+ version_list *vp;
+ proc_list *proc;
+
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\n");
+/* if( Cflag )
+ f_print( fout, "extern \"C\"{\n");
+*/
+ return_type(proc);
+ f_print(fout, "*\n");
+ if (Cflag)
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else
+ pvname(proc->proc_name, vp->vers_num);
+ printarglist(proc, RQSTP, "struct svc_req *");
+
+ f_print(fout, "{\n");
+ f_print(fout, "\n\tstatic ");
+ if (!streq(proc->res_type, "void"))
+ return_type(proc);
+ else
+ f_print(fout, "char*"); /* cannot have void type */
+ f_print(fout, " result;\n");
+ f_print(fout,
+ "\n\t/*\n\t * insert server code here\n\t */\n\n");
+ if (!streq(proc->res_type, "void"))
+ f_print(fout, "\treturn(&result);\n}\n");
+ else /* cast back to void * */
+ f_print(fout, "\treturn((void*) &result);\n}\n");
+/* if( Cflag)
+ f_print( fout, "};\n");
+*/
+
+ }
+ }
+}
+
+static void
+return_type(plist)
+ proc_list *plist;
+{
+ ptype(plist->res_prefix, plist->res_type, 1);
+}
+
+void
+add_sample_msg()
+{
+ f_print(fout, "/*\n");
+ f_print(fout, " * This is sample code generated by rpcgen.\n");
+ f_print(fout, " * These are only templates and you can use them\n");
+ f_print(fout, " * as a guideline for developing your own functions.\n");
+ f_print(fout, " */\n\n");
+}
+
+void
+write_sample_clnt_main()
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+
+ f_print(fout, "\n\n");
+ if (Cflag)
+ f_print(fout, "main( int argc, char* argv[] )\n{\n");
+ else
+ f_print(fout, "main(argc, argv)\nint argc;\nchar *argv[];\n{\n");
+
+ f_print(fout, "\tchar *host;");
+ f_print(fout, "\n\n\tif(argc < 2) {");
+ f_print(fout, "\n\t\tprintf(\"usage: %%s server_host\\n\", argv[0]);\n");
+ f_print(fout, "\t\texit(1);\n\t}");
+ f_print(fout, "\n\thost = argv[1];\n");
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout, "\t");
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, "( host );\n");
+ }
+ }
+ f_print(fout, "}\n");
+}
diff --git a/developer_cmds/rpcgen/rpc_scan.c b/developer_cmds/rpcgen/rpc_scan.c
new file mode 100644
index 0000000..4130107
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_scan.c
@@ -0,0 +1,521 @@
+/* $NetBSD: rpc_scan.c,v 1.6 1997/10/18 10:54:05 lukem Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_scan.c 1.11 89/02/22 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_scan.c,v 1.6 1997/10/18 10:54:05 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_scan.c, Scanner for the RPC protocol compiler
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define startcomment(where) (where[0] == '/' && where[1] == '*')
+#define endcomment(where) (where[-1] == '*' && where[0] == '/')
+
+static void unget_token __P((token *));
+static void findstrconst __P((char **, char **));
+static void findchrconst __P((char **, char **));
+static void findconst __P((char **, char **));
+static void findkind __P((char **, token *));
+static int cppline __P((char *));
+static int directive __P((char *));
+static void printdirective __P((char *));
+static void docppline __P((char *, int *, char **));
+
+static int pushed = 0; /* is a token pushed */
+static token lasttok; /* last token, if pushed */
+
+/*
+ * scan expecting 1 given token
+ */
+void
+scan(expect, tokp)
+ tok_kind expect;
+ token *tokp;
+{
+ get_token(tokp);
+ if (tokp->kind != expect) {
+ expected1(expect);
+ }
+}
+/*
+ * scan expecting any of the 2 given tokens
+ */
+void
+scan2(expect1, expect2, tokp)
+ tok_kind expect1;
+ tok_kind expect2;
+ token *tokp;
+{
+ get_token(tokp);
+ if (tokp->kind != expect1 && tokp->kind != expect2) {
+ expected2(expect1, expect2);
+ }
+}
+/*
+ * scan expecting any of the 3 given token
+ */
+void
+scan3(expect1, expect2, expect3, tokp)
+ tok_kind expect1;
+ tok_kind expect2;
+ tok_kind expect3;
+ token *tokp;
+{
+ get_token(tokp);
+ if (tokp->kind != expect1 && tokp->kind != expect2
+ && tokp->kind != expect3) {
+ expected3(expect1, expect2, expect3);
+ }
+}
+/*
+ * scan expecting a constant, possibly symbolic
+ */
+void
+scan_num(tokp)
+ token *tokp;
+{
+ get_token(tokp);
+ switch (tokp->kind) {
+ case TOK_IDENT:
+ break;
+ default:
+ error("constant or identifier expected");
+ }
+}
+/*
+ * Peek at the next token
+ */
+void
+peek(tokp)
+ token *tokp;
+{
+ get_token(tokp);
+ unget_token(tokp);
+}
+/*
+ * Peek at the next token and scan it if it matches what you expect
+ */
+int
+peekscan(expect, tokp)
+ tok_kind expect;
+ token *tokp;
+{
+ peek(tokp);
+ if (tokp->kind == expect) {
+ get_token(tokp);
+ return (1);
+ }
+ return (0);
+}
+/*
+ * Get the next token, printing out any directive that are encountered.
+ */
+void
+get_token(tokp)
+ token *tokp;
+{
+ int commenting;
+ int stat = 0;
+
+ if (pushed) {
+ pushed = 0;
+ *tokp = lasttok;
+ return;
+ }
+ commenting = 0;
+ for (;;) {
+ if (*where == 0) {
+ for (;;) {
+ if (!fgets(curline, MAXLINESIZE, fin)) {
+ tokp->kind = TOK_EOF;
+ /* now check if cpp returned non NULL value */
+ waitpid(childpid, &stat, WUNTRACED);
+ if (stat > 0) {
+ /* Set return value from rpcgen */
+ nonfatalerrors = stat >> 8;
+ }
+ *where = 0;
+ return;
+ }
+ linenum++;
+ if (commenting) {
+ break;
+ } else
+ /* skip lines beginning with #pragma */
+ if (!strncmp(curline, "#pragma", 7)) *curline = 0;
+ else if (cppline(curline)) {
+ docppline(curline, &linenum,
+ &infilename);
+ } else
+ if (directive(curline)) {
+ printdirective(curline);
+ } else {
+ break;
+ }
+ }
+ where = curline;
+ } else
+ if (isspace(*where)) {
+ while (isspace(*where)) {
+ where++; /* eat */
+ }
+ } else
+ if (commenting) {
+ for (where++; *where; where++) {
+ if (endcomment(where)) {
+ where++;
+ commenting--;
+ break;
+ }
+ }
+ } else
+ if (startcomment(where)) {
+ where += 2;
+ commenting++;
+ } else {
+ break;
+ }
+ }
+
+ /*
+ * 'where' is not whitespace, comment or directive Must be a token!
+ */
+ switch (*where) {
+ case ':':
+ tokp->kind = TOK_COLON;
+ where++;
+ break;
+ case ';':
+ tokp->kind = TOK_SEMICOLON;
+ where++;
+ break;
+ case ',':
+ tokp->kind = TOK_COMMA;
+ where++;
+ break;
+ case '=':
+ tokp->kind = TOK_EQUAL;
+ where++;
+ break;
+ case '*':
+ tokp->kind = TOK_STAR;
+ where++;
+ break;
+ case '[':
+ tokp->kind = TOK_LBRACKET;
+ where++;
+ break;
+ case ']':
+ tokp->kind = TOK_RBRACKET;
+ where++;
+ break;
+ case '{':
+ tokp->kind = TOK_LBRACE;
+ where++;
+ break;
+ case '}':
+ tokp->kind = TOK_RBRACE;
+ where++;
+ break;
+ case '(':
+ tokp->kind = TOK_LPAREN;
+ where++;
+ break;
+ case ')':
+ tokp->kind = TOK_RPAREN;
+ where++;
+ break;
+ case '<':
+ tokp->kind = TOK_LANGLE;
+ where++;
+ break;
+ case '>':
+ tokp->kind = TOK_RANGLE;
+ where++;
+ break;
+
+ case '"':
+ tokp->kind = TOK_STRCONST;
+ findstrconst(&where, &tokp->str);
+ break;
+ case '\'':
+ tokp->kind = TOK_CHARCONST;
+ findchrconst(&where, &tokp->str);
+ break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ tokp->kind = TOK_IDENT;
+ findconst(&where, &tokp->str);
+ break;
+
+ default:
+ if (!(isalpha(*where) || *where == '_')) {
+ char buf[100];
+ char *p;
+
+ s_print(buf, "illegal character in file: ");
+ p = buf + strlen(buf);
+ if (isprint(*where)) {
+ s_print(p, "%c", *where);
+ } else {
+ s_print(p, "%d", *where);
+ }
+ error(buf);
+ }
+ findkind(&where, tokp);
+ break;
+ }
+}
+
+static void
+unget_token(tokp)
+ token *tokp;
+{
+ lasttok = *tokp;
+ pushed = 1;
+}
+
+static void
+findstrconst(str, val)
+ char **str;
+ char **val;
+{
+ char *p;
+ int size;
+
+ p = *str;
+ do {
+ p++;
+ } while (*p && *p != '"');
+ if (*p == 0) {
+ error("unterminated string constant");
+ }
+ p++;
+ size = p - *str;
+ *val = alloc(size + 1);
+ (void) strncpy(*val, *str, size);
+ (*val)[size] = 0;
+ *str = p;
+}
+
+static void
+findchrconst(str, val)
+ char **str;
+ char **val;
+{
+ char *p;
+ int size;
+
+ p = *str;
+ do {
+ p++;
+ } while (*p && *p != '\'');
+ if (*p == 0) {
+ error("unterminated string constant");
+ }
+ p++;
+ size = p - *str;
+ if (size != 3) {
+ error("empty char string");
+ }
+ *val = alloc(size + 1);
+ (void) strncpy(*val, *str, size);
+ (*val)[size] = 0;
+ *str = p;
+}
+
+static void
+findconst(str, val)
+ char **str;
+ char **val;
+{
+ char *p;
+ int size;
+
+ p = *str;
+ if (*p == '0' && *(p + 1) == 'x') {
+ p++;
+ do {
+ p++;
+ } while (isxdigit(*p));
+ } else {
+ do {
+ p++;
+ } while (isdigit(*p));
+ }
+ size = p - *str;
+ *val = alloc(size + 1);
+ (void) strncpy(*val, *str, size);
+ (*val)[size] = 0;
+ *str = p;
+}
+
+static token symbols[] = {
+ {TOK_CONST, "const"},
+ {TOK_UNION, "union"},
+ {TOK_SWITCH, "switch"},
+ {TOK_CASE, "case"},
+ {TOK_DEFAULT, "default"},
+ {TOK_STRUCT, "struct"},
+ {TOK_TYPEDEF, "typedef"},
+ {TOK_ENUM, "enum"},
+ {TOK_OPAQUE, "opaque"},
+ {TOK_BOOL, "bool"},
+ {TOK_VOID, "void"},
+ {TOK_CHAR, "char"},
+ {TOK_INT, "int"},
+ {TOK_UNSIGNED, "unsigned"},
+ {TOK_SHORT, "short"},
+ {TOK_LONG, "long"},
+ {TOK_HYPER, "hyper"},
+ {TOK_FLOAT, "float"},
+ {TOK_DOUBLE, "double"},
+ {TOK_QUAD, "quadruple"},
+ {TOK_STRING, "string"},
+ {TOK_PROGRAM, "program"},
+ {TOK_VERSION, "version"},
+ {TOK_EOF, "??????"},
+};
+
+static void
+findkind(mark, tokp)
+ char **mark;
+ token *tokp;
+{
+ int len;
+ token *s;
+ char *str;
+
+ str = *mark;
+ for (s = symbols; s->kind != TOK_EOF; s++) {
+ len = strlen(s->str);
+ if (strncmp(str, s->str, len) == 0) {
+ if (!isalnum(str[len]) && str[len] != '_') {
+ tokp->kind = s->kind;
+ tokp->str = s->str;
+ *mark = str + len;
+ return;
+ }
+ }
+ }
+ tokp->kind = TOK_IDENT;
+ for (len = 0; isalnum(str[len]) || str[len] == '_'; len++);
+ tokp->str = alloc(len + 1);
+ (void) strncpy(tokp->str, str, len);
+ tokp->str[len] = 0;
+ *mark = str + len;
+}
+
+static int
+cppline(line)
+ char *line;
+{
+ return (line == curline && *line == '#');
+}
+
+static int
+directive(line)
+ char *line;
+{
+ return (line == curline && *line == '%');
+}
+
+static void
+printdirective(line)
+ char *line;
+{
+ f_print(fout, "%s", line + 1);
+}
+
+static void
+docppline(line, lineno, fname)
+ char *line;
+ int *lineno;
+ char **fname;
+{
+ char *file;
+ int num;
+ char *p;
+
+ line++;
+ while (isspace(*line)) {
+ line++;
+ }
+ num = atoi(line);
+ while (isdigit(*line)) {
+ line++;
+ }
+ while (isspace(*line)) {
+ line++;
+ }
+ if (*line != '"') {
+ error("preprocessor error");
+ }
+ line++;
+ p = file = alloc(strlen(line) + 1);
+ while (*line && *line != '"') {
+ *p++ = *line++;
+ }
+ if (*line == 0) {
+ error("preprocessor error");
+ }
+ *p = 0;
+ if (*file == 0) {
+ *fname = NULL;
+ } else {
+ *fname = file;
+ }
+ *lineno = num - 1;
+}
diff --git a/developer_cmds/rpcgen/rpc_scan.h b/developer_cmds/rpcgen/rpc_scan.h
new file mode 100644
index 0000000..e4c57c8
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_scan.h
@@ -0,0 +1,104 @@
+/* $NetBSD: rpc_scan.h,v 1.4 1997/10/11 21:01:50 christos Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/* @(#)rpc_scan.h 1.3 90/08/29 (C) 1987 SMI */
+
+/*
+ * rpc_scan.h, Definitions for the RPCL scanner
+ */
+
+/*
+ * kinds of tokens
+ */
+enum tok_kind {
+ TOK_IDENT,
+ TOK_CHARCONST,
+ TOK_STRCONST,
+ TOK_LPAREN,
+ TOK_RPAREN,
+ TOK_LBRACE,
+ TOK_RBRACE,
+ TOK_LBRACKET,
+ TOK_RBRACKET,
+ TOK_LANGLE,
+ TOK_RANGLE,
+ TOK_STAR,
+ TOK_COMMA,
+ TOK_EQUAL,
+ TOK_COLON,
+ TOK_SEMICOLON,
+ TOK_CONST,
+ TOK_STRUCT,
+ TOK_UNION,
+ TOK_SWITCH,
+ TOK_CASE,
+ TOK_DEFAULT,
+ TOK_ENUM,
+ TOK_TYPEDEF,
+ TOK_INT,
+ TOK_SHORT,
+ TOK_LONG,
+ TOK_HYPER,
+ TOK_UNSIGNED,
+ TOK_FLOAT,
+ TOK_DOUBLE,
+ TOK_QUAD,
+ TOK_OPAQUE,
+ TOK_CHAR,
+ TOK_STRING,
+ TOK_BOOL,
+ TOK_VOID,
+ TOK_PROGRAM,
+ TOK_VERSION,
+ TOK_EOF
+};
+typedef enum tok_kind tok_kind;
+
+/*
+ * a token
+ */
+struct token {
+ tok_kind kind;
+ char *str;
+};
+typedef struct token token;
+
+
+/*
+ * routine interface
+ */
+void scan __P((tok_kind, token *));
+void scan2 __P((tok_kind, tok_kind, token *));
+void scan3 __P((tok_kind, tok_kind, tok_kind, token *));
+void scan_num __P((token *));
+void peek __P((token *));
+int peekscan __P((tok_kind, token *));
+void get_token __P((token *));
diff --git a/developer_cmds/rpcgen/rpc_svcout.c b/developer_cmds/rpcgen/rpc_svcout.c
new file mode 100644
index 0000000..cb0ed46
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_svcout.c
@@ -0,0 +1,980 @@
+/* $NetBSD: rpc_svcout.c,v 1.10 1997/10/18 10:54:07 lukem Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_svcout.c 1.29 89/03/30 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_svcout.c,v 1.10 1997/10/18 10:54:07 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_svcout.c, Server-skeleton outputter for the RPC protocol compiler
+ */
+#include <stdio.h>
+#include <string.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+static char RQSTP[] = "rqstp";
+static char TRANSP[] = "transp";
+static char ARG[] = "argument";
+static char RESULT[] = "result";
+static char ROUTINE[] = "local";
+
+static void p_xdrfunc __P((char *, char *));
+static void internal_proctype __P((proc_list *));
+static void write_real_program __P((definition *));
+static void write_program __P((definition *, char *));
+static void printerr __P((char *, char *));
+static void printif __P((char *, char *, char *, char *));
+static void write_inetmost __P((char *));
+static void print_return __P((char *));
+static void print_pmapunset __P((char *));
+static void print_err_message __P((char *));
+static void write_timeout_func __P((void));
+static void write_caller_func __P((void));
+static void write_pm_most __P((char *, int));
+static void write_rpc_svc_fg __P((char *, char *));
+static void open_log_file __P((char *, char *));
+
+char _errbuf[256]; /* For all messages */
+
+static void
+p_xdrfunc(rname, typename)
+ char *rname;
+ char *typename;
+{
+ if (Cflag)
+ f_print(fout, "\t\txdr_%s = (xdrproc_t) xdr_%s;\n", rname,
+ stringfix(typename));
+ else
+ f_print(fout, "\t\txdr_%s = xdr_%s;\n", rname, stringfix(typename));
+}
+
+static void
+internal_proctype(plist)
+ proc_list *plist;
+{
+ f_print(fout, "static ");
+ ptype(plist->res_prefix, plist->res_type, 1);
+ f_print(fout, "*");
+}
+
+
+/*
+ * write most of the service, that is, everything but the registrations.
+ */
+void
+write_most(infile, netflag, nomain)
+ char *infile; /* our name */
+ int netflag;
+ int nomain;
+{
+ if (inetdflag || pmflag) {
+ char *var_type;
+ var_type = (nomain ? "extern" : "static");
+ f_print(fout, "%s int _rpcpmstart;", var_type);
+ f_print(fout, "\t\t/* Started by a port monitor ? */\n");
+ f_print(fout, "%s int _rpcfdtype;", var_type);
+ f_print(fout, "\t\t/* Whether Stream or Datagram ? */\n");
+ if (timerflag) {
+ f_print(fout, "%s int _rpcsvcdirty;", var_type);
+ f_print(fout, "\t/* Still serving ? */\n");
+ }
+ write_svc_aux(nomain);
+ }
+ /* write out dispatcher and stubs */
+ write_programs(nomain ? (char *) NULL : "static");
+
+ if (nomain)
+ return;
+
+ f_print(fout, "\n\n");
+ if (Cflag)
+ f_print(fout, "int main( int argc, char* argv[] );\n");
+ f_print(fout, "\nint\n");
+ if (Cflag)
+ f_print(fout, "main( int argc, char* argv[] )\n");
+ else
+ f_print(fout, "main(argc, argv)\nint argc;\nchar *argv[];\n");
+ f_print(fout, "{\n");
+ if (inetdflag) {
+ write_inetmost(infile); /* Includes call to write_rpc_svc_fg() */
+ } else {
+ if (tirpcflag) {
+ if (netflag) {
+ f_print(fout, "\tSVCXPRT *%s;\n", TRANSP);
+ f_print(fout, "\tstruct netconfig *nconf = NULL;\n");
+ }
+ f_print(fout, "\tpid_t pid;\n");
+ f_print(fout, "\tint i;\n");
+ f_print(fout, "\tchar mname[FMNAMESZ + 1];\n\n");
+ write_pm_most(infile, netflag);
+ f_print(fout, "\telse {\n");
+ write_rpc_svc_fg(infile, "\t\t");
+ f_print(fout, "\t}\n");
+ } else {
+ f_print(fout, "\tSVCXPRT *%s;\n", TRANSP);
+ f_print(fout, "\n");
+ print_pmapunset("\t");
+ }
+ }
+
+ if (logflag && !inetdflag) {
+ open_log_file(infile, "\t");
+ }
+}
+/*
+ * write a registration for the given transport
+ */
+void
+write_netid_register(transp)
+ char *transp;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+ char *sp;
+ char tmpbuf[32];
+
+ sp = "";
+ f_print(fout, "\n");
+ f_print(fout, "%s\tnconf = getnetconfigent(\"%s\");\n", sp, transp);
+ f_print(fout, "%s\tif (nconf == NULL) {\n", sp);
+ (void) sprintf(_errbuf, "cannot find %s netid.", transp);
+ sprintf(tmpbuf, "%s\t\t", sp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+ f_print(fout, "%s\t%s = svc_tli_create(RPC_ANYFD, nconf, 0, 0, 0);\n",
+ sp, TRANSP);
+ f_print(fout, "%s\tif (%s == NULL) {\n", sp, TRANSP);
+ (void) sprintf(_errbuf, "cannot create %s service.", transp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout,
+ "%s\t(void) rpcb_unset(%s, %s, nconf);\n",
+ sp, def->def_name, vp->vers_name);
+ f_print(fout,
+ "%s\tif (!svc_reg(%s, %s, %s, ",
+ sp, TRANSP, def->def_name, vp->vers_name);
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, ", nconf)) {\n");
+ (void) sprintf(_errbuf, "unable to register (%s, %s, %s).",
+ def->def_name, vp->vers_name, transp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+ }
+ }
+ f_print(fout, "%s\tfreenetconfigent(nconf);\n", sp);
+}
+/*
+ * write a registration for the given transport for TLI
+ */
+void
+write_nettype_register(transp)
+ char *transp;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout, "\tif (!svc_create(");
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, ", %s, %s, \"%s\")) {\n ",
+ def->def_name, vp->vers_name, transp);
+ (void) sprintf(_errbuf,
+ "unable to create (%s, %s) for %s.",
+ def->def_name, vp->vers_name, transp);
+ print_err_message("\t\t");
+ f_print(fout, "\t\texit(1);\n");
+ f_print(fout, "\t}\n");
+ }
+ }
+}
+/*
+ * write the rest of the service
+ */
+void
+write_rest()
+{
+ f_print(fout, "\n");
+ if (inetdflag) {
+ f_print(fout, "\tif (%s == (SVCXPRT *)NULL) {\n", TRANSP);
+ (void) sprintf(_errbuf, "could not create a handle");
+ print_err_message("\t\t");
+ f_print(fout, "\t\texit(1);\n");
+ f_print(fout, "\t}\n");
+ if (timerflag) {
+ f_print(fout, "\tif (_rpcpmstart) {\n");
+ f_print(fout,
+ "\t\t(void) signal(SIGALRM, %s closedown);\n",
+ Cflag ? "(SIG_PF)" : "(void(*)())");
+ f_print(fout, "\t\t(void) alarm(_RPCSVC_CLOSEDOWN);\n");
+ f_print(fout, "\t}\n");
+ }
+ }
+ f_print(fout, "\tsvc_run();\n");
+ (void) sprintf(_errbuf, "svc_run returned");
+ print_err_message("\t");
+ f_print(fout, "\texit(1);\n");
+ f_print(fout, "\t/* NOTREACHED */\n");
+ f_print(fout, "}\n");
+}
+
+void
+write_programs(storage)
+ char *storage;
+{
+ list *l;
+ definition *def;
+
+ /* write out stubs for procedure definitions */
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ write_real_program(def);
+ }
+ }
+
+ /* write out dispatcher for each program */
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ write_program(def, storage);
+ }
+ }
+
+
+}
+/* write out definition of internal function (e.g. _printmsg_1(...))
+ which calls server's defintion of actual function (e.g. printmsg_1(...)).
+ Unpacks single user argument of printmsg_1 to call-by-value format
+ expected by printmsg_1. */
+static void
+write_real_program(def)
+ definition *def;
+{
+ version_list *vp;
+ proc_list *proc;
+ decl_list *l;
+
+ if (!newstyle)
+ return; /* not needed for old style */
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\n");
+ internal_proctype(proc);
+ f_print(fout, "\n_");
+ pvname(proc->proc_name, vp->vers_num);
+ if (Cflag) {
+ f_print(fout, "(");
+ /* arg name */
+ if (proc->arg_num > 1)
+ f_print(fout, "%s", proc->args.argname);
+ else
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 0);
+ f_print(fout, " *argp, struct svc_req *%s)\n",
+ RQSTP);
+ } else {
+ f_print(fout, "(argp, %s)\n", RQSTP);
+ /* arg name */
+ if (proc->arg_num > 1)
+ f_print(fout, "\t%s *argp;\n", proc->args.argname);
+ else {
+ f_print(fout, "\t");
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 0);
+ f_print(fout, " *argp;\n");
+ }
+ f_print(fout, " struct svc_req *%s;\n", RQSTP);
+ }
+
+ f_print(fout, "{\n");
+ f_print(fout, "\treturn(");
+ pvname_svc(proc->proc_name, vp->vers_num);
+ f_print(fout, "(");
+ if (proc->arg_num < 2) { /* single argument */
+ if (!streq(proc->args.decls->decl.type, "void"))
+ f_print(fout, "*argp, "); /* non-void */
+ } else {
+ for (l = proc->args.decls; l != NULL; l = l->next)
+ f_print(fout, "argp->%s, ", l->decl.name);
+ }
+ f_print(fout, "%s));\n}\n", RQSTP);
+ }
+ }
+}
+
+static void
+write_program(def, storage)
+ definition *def;
+ char *storage;
+{
+ version_list *vp;
+ proc_list *proc;
+ int filled;
+
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ if (Cflag) {
+ f_print(fout, "\n");
+ if (storage != NULL) {
+ f_print(fout, "%s ", storage);
+ }
+ f_print(fout, "void ");
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, "(struct svc_req *%s, ", RQSTP);
+ f_print(fout, "SVCXPRT *%s);\n", TRANSP);
+ }
+ f_print(fout, "\n");
+ if (storage != NULL) {
+ f_print(fout, "%s ", storage);
+ }
+ f_print(fout, "void\n");
+ pvname(def->def_name, vp->vers_num);
+
+ if (Cflag) {
+ f_print(fout, "(struct svc_req *%s, ", RQSTP);
+ f_print(fout, "SVCXPRT *%s)\n", TRANSP);
+ } else {
+ f_print(fout, "(%s, %s)\n", RQSTP, TRANSP);
+ f_print(fout, " struct svc_req *%s;\n", RQSTP);
+ f_print(fout, " SVCXPRT *%s;\n", TRANSP);
+ }
+
+ f_print(fout, "{\n");
+
+ filled = 0;
+ f_print(fout, "\tunion {\n");
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ if (proc->arg_num < 2) { /* single argument */
+ if (streq(proc->args.decls->decl.type,
+ "void")) {
+ continue;
+ }
+ filled = 1;
+ f_print(fout, "\t\t");
+ ptype(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type, 0);
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_arg;\n");
+
+ } else {
+ filled = 1;
+ f_print(fout, "\t\t%s", proc->args.argname);
+ f_print(fout, " ");
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, "_arg;\n");
+ }
+ }
+ if (!filled) {
+ f_print(fout, "\t\tint fill;\n");
+ }
+ f_print(fout, "\t} %s;\n", ARG);
+ f_print(fout, "\tchar *%s;\n", RESULT);
+
+ if (Cflag) {
+ f_print(fout, "\txdrproc_t xdr_%s, xdr_%s;\n", ARG, RESULT);
+ f_print(fout,
+ "\tchar *(*%s)(char *, struct svc_req *);\n",
+ ROUTINE);
+ } else {
+ f_print(fout, "\tbool_t (*xdr_%s)(), (*xdr_%s)();\n", ARG, RESULT);
+ f_print(fout, "\tchar *(*%s)();\n", ROUTINE);
+ }
+
+ f_print(fout, "\n");
+
+ if (callerflag)
+ f_print(fout, "\tcaller = transp;\n"); /* EVAS */
+ if (timerflag)
+ f_print(fout, "\t_rpcsvcdirty = 1;\n");
+ f_print(fout, "\tswitch (%s->rq_proc) {\n", RQSTP);
+ if (!nullproc(vp->procs)) {
+ f_print(fout, "\tcase NULLPROC:\n");
+ f_print(fout,
+ "\t\t(void) svc_sendreply(%s, (xdrproc_t) xdr_void, (char *)NULL);\n",
+ TRANSP);
+ print_return("\t\t");
+ f_print(fout, "\n");
+ }
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ f_print(fout, "\tcase %s:\n", proc->proc_name);
+ if (proc->arg_num < 2) { /* single argument */
+ p_xdrfunc(ARG, proc->args.decls->decl.type);
+ } else {
+ p_xdrfunc(ARG, proc->args.argname);
+ }
+ p_xdrfunc(RESULT, proc->res_type);
+ if (Cflag)
+ f_print(fout,
+ "\t\t%s = (char *(*)(char *, struct svc_req *)) ",
+ ROUTINE);
+ else
+ f_print(fout, "\t\t%s = (char *(*)()) ", ROUTINE);
+
+ if (newstyle) { /* new style: calls internal routine */
+ f_print(fout, "_");
+ }
+ if (!newstyle)
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else
+ pvname(proc->proc_name, vp->vers_num);
+ f_print(fout, ";\n");
+ f_print(fout, "\t\tbreak;\n\n");
+ }
+ f_print(fout, "\tdefault:\n");
+ printerr("noproc", TRANSP);
+ print_return("\t\t");
+ f_print(fout, "\t}\n");
+
+ f_print(fout, "\t(void) memset((char *)&%s, 0, sizeof (%s));\n", ARG, ARG);
+ printif("getargs", TRANSP, "(caddr_t) &", ARG);
+ printerr("decode", TRANSP);
+ print_return("\t\t");
+ f_print(fout, "\t}\n");
+
+ if (Cflag)
+ f_print(fout, "\t%s = (*%s)((char *)&%s, %s);\n",
+ RESULT, ROUTINE, ARG, RQSTP);
+ else
+ f_print(fout, "\t%s = (*%s)(&%s, %s);\n",
+ RESULT, ROUTINE, ARG, RQSTP);
+ f_print(fout,
+ "\tif (%s != NULL && !svc_sendreply(%s, (xdrproc_t) xdr_%s, %s)) {\n",
+ RESULT, TRANSP, RESULT, RESULT);
+ printerr("systemerr", TRANSP);
+ f_print(fout, "\t}\n");
+
+ printif("freeargs", TRANSP, "(caddr_t) &", ARG);
+ (void) sprintf(_errbuf, "unable to free arguments");
+ print_err_message("\t\t");
+ f_print(fout, "\t\texit(1);\n");
+ f_print(fout, "\t}\n");
+ print_return("\t");
+ f_print(fout, "}\n");
+ }
+}
+
+static void
+printerr(err, transp)
+ char *err;
+ char *transp;
+{
+ f_print(fout, "\t\tsvcerr_%s(%s);\n", err, transp);
+}
+
+static void
+printif(proc, transp, prefix, arg)
+ char *proc;
+ char *transp;
+ char *prefix;
+ char *arg;
+{
+ f_print(fout, "\tif (!svc_%s(%s, xdr_%s, %s%s)) {\n",
+ proc, transp, arg, prefix, arg);
+}
+
+int
+nullproc(proc)
+ proc_list *proc;
+{
+ for (; proc != NULL; proc = proc->next) {
+ if (streq(proc->proc_num, "0")) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void
+write_inetmost(infile)
+ char *infile;
+{
+ f_print(fout, "\tSVCXPRT *%s = NULL;\n", TRANSP);
+ f_print(fout, "\tint sock;\n");
+ f_print(fout, "\tint proto = 0;\n");
+ f_print(fout, "\tstruct sockaddr_in saddr;\n");
+ f_print(fout, "\tint asize = sizeof (saddr);\n");
+ f_print(fout, "\n");
+ f_print(fout,
+ "\tif (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) {\n");
+ f_print(fout, "\t\tint ssize = sizeof (int);\n\n");
+ f_print(fout, "\t\tif (saddr.sin_family != AF_INET)\n");
+ f_print(fout, "\t\t\texit(1);\n");
+ f_print(fout, "\t\tif (getsockopt(0, SOL_SOCKET, SO_TYPE,\n");
+ f_print(fout, "\t\t\t\t(char *)&_rpcfdtype, &ssize) == -1)\n");
+ f_print(fout, "\t\t\texit(1);\n");
+ f_print(fout, "\t\tsock = 0;\n");
+ f_print(fout, "\t\t_rpcpmstart = 1;\n");
+ f_print(fout, "\t\tproto = 0;\n");
+ open_log_file(infile, "\t\t");
+ f_print(fout, "\t} else {\n");
+ write_rpc_svc_fg(infile, "\t\t");
+ f_print(fout, "\t\tsock = RPC_ANYSOCK;\n");
+ print_pmapunset("\t\t");
+ f_print(fout, "\t}\n");
+}
+
+static void
+print_return(space)
+ char *space;
+{
+ if (exitnow)
+ f_print(fout, "%sexit(0);\n", space);
+ else {
+ if (timerflag)
+ f_print(fout, "%s_rpcsvcdirty = 0;\n", space);
+ f_print(fout, "%sreturn;\n", space);
+ }
+}
+
+static void
+print_pmapunset(space)
+ char *space;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ for (vp = def->def.pr.versions; vp != NULL;
+ vp = vp->next) {
+ f_print(fout, "%s(void) pmap_unset(%s, %s);\n",
+ space, def->def_name, vp->vers_name);
+ }
+ }
+ }
+}
+
+static void
+print_err_message(space)
+ char *space;
+{
+ if (logflag)
+ f_print(fout, "%ssyslog(LOG_ERR, \"%%s\", \"%s\");\n", space, _errbuf);
+ else
+ if (inetdflag || pmflag)
+ f_print(fout, "%s_msgout(\"%s\");\n", space, _errbuf);
+ else
+ f_print(fout, "%sfprintf(stderr, \"%%s\", \"%s\");\n", space, _errbuf);
+}
+/*
+ * Write the server auxiliary function ( _msgout, timeout)
+ */
+void
+write_svc_aux(nomain)
+ int nomain;
+{
+ if (!logflag)
+ write_msg_out();
+ if (!nomain)
+ write_timeout_func();
+ if (callerflag) /* EVAS */
+ write_caller_func(); /* EVAS */
+}
+/*
+ * Write the _msgout function
+ */
+void
+write_msg_out()
+{
+ f_print(fout, "\n");
+ f_print(fout, "static\n");
+ if (!Cflag) {
+ f_print(fout, "void _msgout(msg)\n");
+ f_print(fout, "\tchar *msg;\n");
+ } else {
+ f_print(fout, "void _msgout(char* msg)\n");
+ }
+ f_print(fout, "{\n");
+ f_print(fout, "#ifdef RPC_SVC_FG\n");
+ if (inetdflag || pmflag)
+ f_print(fout, "\tif (_rpcpmstart)\n");
+ f_print(fout, "\t\tsyslog(LOG_ERR, \"%%s\", msg);\n");
+ f_print(fout, "\telse\n");
+ f_print(fout, "\t\t(void) fprintf(stderr, \"%%s\\n\", msg);\n");
+ f_print(fout, "#else\n");
+ f_print(fout, "\tsyslog(LOG_ERR, \"%%s\", msg);\n");
+ f_print(fout, "#endif\n");
+ f_print(fout, "}\n");
+}
+/*
+ * Write the timeout function
+ */
+static void
+write_timeout_func()
+{
+ if (!timerflag)
+ return;
+ if (Cflag) {
+ f_print(fout, "\n");
+ f_print(fout, "static void closedown(void);\n");
+ }
+ f_print(fout, "\n");
+ f_print(fout, "static void\n");
+ f_print(fout, "closedown()\n");
+ f_print(fout, "{\n");
+ f_print(fout, "\tif (_rpcsvcdirty == 0) {\n");
+ f_print(fout, "\t\textern fd_set svc_fdset;\n");
+ f_print(fout, "\t\tstatic int size;\n");
+ f_print(fout, "\t\tint i, openfd;\n");
+ if (tirpcflag && pmflag) {
+ f_print(fout, "\t\tstruct t_info tinfo;\n\n");
+ f_print(fout, "\t\tif (!t_getinfo(0, &tinfo) && (tinfo.servtype == T_CLTS))\n");
+ } else {
+ f_print(fout, "\n\t\tif (_rpcfdtype == SOCK_DGRAM)\n");
+ }
+ f_print(fout, "\t\t\texit(0);\n");
+ f_print(fout, "\t\tif (size == 0) {\n");
+ if (tirpcflag) {
+ f_print(fout, "\t\t\tstruct rlimit rl;\n\n");
+ f_print(fout, "\t\t\trl.rlim_max = 0;\n");
+ f_print(fout, "\t\t\tgetrlimit(RLIMIT_NOFILE, &rl);\n");
+ f_print(fout, "\t\t\tif ((size = rl.rlim_max) == 0)\n");
+ f_print(fout, "\t\t\t\treturn;\n");
+ } else {
+ f_print(fout, "\t\t\tsize = getdtablesize();\n");
+ }
+ f_print(fout, "\t\t}\n");
+ f_print(fout, "\t\tfor (i = 0, openfd = 0; i < size && openfd < 2; i++)\n");
+ f_print(fout, "\t\t\tif (FD_ISSET(i, &svc_fdset))\n");
+ f_print(fout, "\t\t\t\topenfd++;\n");
+ f_print(fout, "\t\tif (openfd <= (_rpcpmstart?0:1))\n");
+ f_print(fout, "\t\t\texit(0);\n");
+ f_print(fout, "\t}\n");
+ f_print(fout, "\t(void) alarm(_RPCSVC_CLOSEDOWN);\n");
+ f_print(fout, "}\n");
+}
+
+static void
+write_caller_func()
+{ /* EVAS */
+#define P(s) f_print(fout, s);
+
+ P("\n");
+ P("char *svc_caller()\n");
+ P("{\n");
+ P(" struct sockaddr_in actual;\n");
+ P(" struct hostent *hp;\n");
+ P(" static struct in_addr prev;\n");
+ P(" static char cname[128];\n\n");
+
+ P(" actual = *svc_getcaller(caller);\n\n");
+
+ P(" if (memcmp((char *)&actual.sin_addr, (char *)&prev,\n");
+ P(" sizeof(struct in_addr)) == 0)\n");
+ P(" return (cname);\n\n");
+
+ P(" prev = actual.sin_addr;\n\n");
+
+ P(" hp = gethostbyaddr((char *) &actual.sin_addr, sizeof(actual.sin_addr), AF_INET);\n");
+ P(" if (hp == NULL) { /* dummy one up */\n");
+ P(" extern char *inet_ntoa();\n");
+ P(" strcpy(cname, inet_ntoa(actual.sin_addr));\n");
+ P(" } else {\n");
+ P(" strcpy(cname, hp->h_name);\n");
+ P(" }\n\n");
+
+ P(" return (cname);\n");
+ P("}\n");
+
+#undef P
+}
+/*
+ * Write the most of port monitor support
+ */
+static void
+write_pm_most(infile, netflag)
+ char *infile;
+ int netflag;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+
+ f_print(fout, "\tif (!ioctl(0, I_LOOK, mname) &&\n");
+ f_print(fout, "\t\t(!strcmp(mname, \"sockmod\") ||");
+ f_print(fout, " !strcmp(mname, \"timod\"))) {\n");
+ f_print(fout, "\t\tchar *netid;\n");
+ if (!netflag) { /* Not included by -n option */
+ f_print(fout, "\t\tstruct netconfig *nconf = NULL;\n");
+ f_print(fout, "\t\tSVCXPRT *%s;\n", TRANSP);
+ }
+ if (timerflag)
+ f_print(fout, "\t\tint pmclose;\n");
+/* not necessary, defined in /usr/include/stdlib */
+/* f_print(fout, "\t\textern char *getenv();\n");*/
+ f_print(fout, "\n");
+ f_print(fout, "\t\t_rpcpmstart = 1;\n");
+ if (logflag)
+ open_log_file(infile, "\t\t");
+ f_print(fout, "\t\tif ((netid = getenv(\"NLSPROVIDER\")) == NULL) {\n");
+ sprintf(_errbuf, "cannot get transport name");
+ print_err_message("\t\t\t");
+ f_print(fout, "\t\t} else if ((nconf = getnetconfigent(netid)) == NULL) {\n");
+ sprintf(_errbuf, "cannot get transport info");
+ print_err_message("\t\t\t");
+ f_print(fout, "\t\t}\n");
+ /*
+ * A kludgy support for inetd services. Inetd only works with
+ * sockmod, and RPC works only with timod, hence all this jugglery
+ */
+ f_print(fout, "\t\tif (strcmp(mname, \"sockmod\") == 0) {\n");
+ f_print(fout, "\t\t\tif (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, \"timod\")) {\n");
+ sprintf(_errbuf, "could not get the right module");
+ print_err_message("\t\t\t\t");
+ f_print(fout, "\t\t\t\texit(1);\n");
+ f_print(fout, "\t\t\t}\n");
+ f_print(fout, "\t\t}\n");
+ if (timerflag)
+ f_print(fout, "\t\tpmclose = (t_getstate(0) != T_DATAXFER);\n");
+ f_print(fout, "\t\tif ((%s = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {\n",
+ TRANSP);
+ sprintf(_errbuf, "cannot create server handle");
+ print_err_message("\t\t\t");
+ f_print(fout, "\t\t\texit(1);\n");
+ f_print(fout, "\t\t}\n");
+ f_print(fout, "\t\tif (nconf)\n");
+ f_print(fout, "\t\t\tfreenetconfigent(nconf);\n");
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout,
+ "\t\tif (!svc_reg(%s, %s, %s, ",
+ TRANSP, def->def_name, vp->vers_name);
+ pvname(def->def_name, vp->vers_num);
+ f_print(fout, ", 0)) {\n");
+ (void) sprintf(_errbuf, "unable to register (%s, %s).",
+ def->def_name, vp->vers_name);
+ print_err_message("\t\t\t");
+ f_print(fout, "\t\t\texit(1);\n");
+ f_print(fout, "\t\t}\n");
+ }
+ }
+ if (timerflag) {
+ f_print(fout, "\t\tif (pmclose) {\n");
+ f_print(fout, "\t\t\t(void) signal(SIGALRM, %s closedown);\n",
+ Cflag ? "(SIG_PF)" : "(void(*)())");
+ f_print(fout, "\t\t\t(void) alarm(_RPCSVC_CLOSEDOWN);\n");
+ f_print(fout, "\t\t}\n");
+ }
+ f_print(fout, "\t\tsvc_run();\n");
+ f_print(fout, "\t\texit(1);\n");
+ f_print(fout, "\t\t/* NOTREACHED */\n");
+ f_print(fout, "\t}\n");
+}
+/*
+ * Support for backgrounding the server if self started.
+ */
+static void
+write_rpc_svc_fg(infile, sp)
+ char *infile;
+ char *sp;
+{
+ f_print(fout, "#ifndef RPC_SVC_FG\n");
+ f_print(fout, "%sint size;\n", sp);
+ if (tirpcflag)
+ f_print(fout, "%sstruct rlimit rl;\n", sp);
+ if (inetdflag)
+ f_print(fout, "%sint pid, i;\n\n", sp);
+ f_print(fout, "%spid = fork();\n", sp);
+ f_print(fout, "%sif (pid < 0) {\n", sp);
+ f_print(fout, "%s\tperror(\"cannot fork\");\n", sp);
+ f_print(fout, "%s\texit(1);\n", sp);
+ f_print(fout, "%s}\n", sp);
+ f_print(fout, "%sif (pid)\n", sp);
+ f_print(fout, "%s\texit(0);\n", sp);
+ /* get number of file descriptors */
+ if (tirpcflag) {
+ f_print(fout, "%srl.rlim_max = 0;\n", sp);
+ f_print(fout, "%sgetrlimit(RLIMIT_NOFILE, &rl);\n", sp);
+ f_print(fout, "%sif ((size = rl.rlim_max) == 0)\n", sp);
+ f_print(fout, "%s\texit(1);\n", sp);
+ } else {
+ f_print(fout, "%ssize = getdtablesize();\n", sp);
+ }
+
+ f_print(fout, "%sfor (i = 0; i < size; i++)\n", sp);
+ f_print(fout, "%s\t(void) close(i);\n", sp);
+ /* Redirect stderr and stdout to console */
+ f_print(fout, "%si = open(\"/dev/console\", 2);\n", sp);
+ f_print(fout, "%s(void) dup2(i, 1);\n", sp);
+ f_print(fout, "%s(void) dup2(i, 2);\n", sp);
+ /* This removes control of the controlling terminal */
+ if (tirpcflag)
+ f_print(fout, "%ssetsid();\n", sp);
+ else {
+ f_print(fout, "%si = open(\"/dev/tty\", 2);\n", sp);
+ f_print(fout, "%sif (i >= 0) {\n", sp);
+ f_print(fout, "%s\t(void) ioctl(i, TIOCNOTTY, (char *)NULL);\n", sp);;
+ f_print(fout, "%s\t(void) close(i);\n", sp);
+ f_print(fout, "%s}\n", sp);
+ }
+ if (!logflag)
+ open_log_file(infile, sp);
+ f_print(fout, "#endif\n");
+ if (logflag)
+ open_log_file(infile, sp);
+}
+
+static void
+open_log_file(infile, sp)
+ char *infile;
+ char *sp;
+{
+ char *s, *p;
+
+ s = strrchr(infile, '.');
+ if (s)
+ *s = '\0';
+ p = strrchr(infile, '/');
+ if (p)
+ p++;
+ else
+ p = infile;
+ f_print(fout, "%sopenlog(\"%s\", LOG_PID, LOG_DAEMON);\n", sp, p);
+ if (s)
+ *s = '.';
+}
+
+/*
+ * write a registration for the given transport for Inetd
+ */
+void
+write_inetd_register(transp)
+ char *transp;
+{
+ list *l;
+ definition *def;
+ version_list *vp;
+ char *sp;
+ int isudp;
+ char tmpbuf[32];
+
+ if (inetdflag)
+ sp = "\t";
+ else
+ sp = "";
+ if (streq(transp, "udp"))
+ isudp = 1;
+ else
+ isudp = 0;
+ f_print(fout, "\n");
+ if (inetdflag) {
+ f_print(fout, "\tif ((_rpcfdtype == 0) || (_rpcfdtype == %s)) {\n",
+ isudp ? "SOCK_DGRAM" : "SOCK_STREAM");
+ }
+ if (inetdflag && streq(transp, "tcp")) {
+ f_print(fout, "%s\tif (_rpcpmstart)\n", sp);
+
+ f_print(fout, "%s\t\t%s = svc%s_create(%s",
+ sp, TRANSP, "fd", inetdflag ? "sock" : "RPC_ANYSOCK");
+ if (!isudp)
+ f_print(fout, ", 0, 0");
+ f_print(fout, ");\n");
+
+ f_print(fout, "%s\telse\n", sp);
+
+ f_print(fout, "%s\t\t%s = svc%s_create(%s",
+ sp, TRANSP, transp, inetdflag ? "sock" : "RPC_ANYSOCK");
+ if (!isudp)
+ f_print(fout, ", 0, 0");
+ f_print(fout, ");\n");
+
+ } else {
+ f_print(fout, "%s\t%s = svc%s_create(%s",
+ sp, TRANSP, transp, inetdflag ? "sock" : "RPC_ANYSOCK");
+ if (!isudp)
+ f_print(fout, ", 0, 0");
+ f_print(fout, ");\n");
+ }
+ f_print(fout, "%s\tif (%s == NULL) {\n", sp, TRANSP);
+ (void) sprintf(_errbuf, "cannot create %s service.", transp);
+ (void) sprintf(tmpbuf, "%s\t\t", sp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+
+ if (inetdflag) {
+ f_print(fout, "%s\tif (!_rpcpmstart)\n\t", sp);
+ f_print(fout, "%s\tproto = IPPROTO_%s;\n",
+ sp, isudp ? "UDP" : "TCP");
+ }
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind != DEF_PROGRAM) {
+ continue;
+ }
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ f_print(fout, "%s\tif (!svc_register(%s, %s, %s, ",
+ sp, TRANSP, def->def_name, vp->vers_name);
+ pvname(def->def_name, vp->vers_num);
+ if (inetdflag)
+ f_print(fout, ", proto)) {\n");
+ else
+ f_print(fout, ", IPPROTO_%s)) {\n",
+ isudp ? "UDP" : "TCP");
+ (void) sprintf(_errbuf, "unable to register (%s, %s, %s).",
+ def->def_name, vp->vers_name, transp);
+ print_err_message(tmpbuf);
+ f_print(fout, "%s\t\texit(1);\n", sp);
+ f_print(fout, "%s\t}\n", sp);
+ }
+ }
+ if (inetdflag)
+ f_print(fout, "\t}\n");
+}
diff --git a/developer_cmds/rpcgen/rpc_tblout.c b/developer_cmds/rpcgen/rpc_tblout.c
new file mode 100644
index 0000000..610dcd0
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_tblout.c
@@ -0,0 +1,179 @@
+/* $NetBSD: rpc_tblout.c,v 1.7 1997/10/18 10:54:11 lukem Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_tblout.c 1.4 89/02/22 (C) 1988 SMI";
+#else
+__RCSID("$NetBSD: rpc_tblout.c,v 1.7 1997/10/18 10:54:11 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_tblout.c, Dispatch table outputter for the RPC protocol compiler
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define TABSIZE 8
+#define TABCOUNT 5
+#define TABSTOP (TABSIZE*TABCOUNT)
+
+static char tabstr[TABCOUNT + 1] = "\t\t\t\t\t";
+
+static char tbl_hdr[] = "struct rpcgen_table %s_table[] = {\n";
+static char tbl_end[] = "};\n";
+
+static char null_entry[] = "\t(char *(*)())0,\n\
+ \t(xdrproc_t)xdr_void,\t\t0,\n\
+ \t(xdrproc_t)xdr_void,\t\t0,\n";
+
+static char tbl_nproc[] = "int %s_nproc =\n\tsizeof(%s_table)/sizeof(%s_table[0]);\n\n";
+
+static void write_table __P((definition *));
+static void printit __P((char *, char *));
+
+void
+write_tables()
+{
+ list *l;
+ definition *def;
+
+ f_print(fout, "\n");
+ for (l = defined; l != NULL; l = l->next) {
+ def = (definition *) l->val;
+ if (def->def_kind == DEF_PROGRAM) {
+ write_table(def);
+ }
+ }
+}
+
+static void
+write_table(def)
+ definition *def;
+{
+ version_list *vp;
+ proc_list *proc;
+ int current;
+ int expected;
+ char progvers[100];
+ int warning;
+
+ for (vp = def->def.pr.versions; vp != NULL; vp = vp->next) {
+ warning = 0;
+ s_print(progvers, "%s_%s",
+ locase(def->def_name), vp->vers_num);
+ /* print the table header */
+ f_print(fout, tbl_hdr, progvers);
+
+ if (nullproc(vp->procs)) {
+ expected = 0;
+ } else {
+ expected = 1;
+ f_print(fout, "%s", null_entry);
+ }
+ for (proc = vp->procs; proc != NULL; proc = proc->next) {
+ if (expected != 0)
+ f_print(fout, "\n");
+ current = atoi(proc->proc_num);
+ if (current != expected++) {
+ f_print(fout,
+ "/*\n * WARNING: table out of order\n */\n\n");
+ if (warning == 0) {
+ f_print(stderr,
+ "WARNING %s table is out of order\n",
+ progvers);
+ warning = 1;
+ nonfatalerrors = 1;
+ }
+ expected = current + 1;
+ }
+ f_print(fout, "\t(char *(*)())RPCGEN_ACTION(");
+
+ /* routine to invoke */
+ if (!newstyle)
+ pvname_svc(proc->proc_name, vp->vers_num);
+ else {
+ if (newstyle)
+ f_print(fout, "_"); /* calls internal func */
+ pvname(proc->proc_name, vp->vers_num);
+ }
+ f_print(fout, "),\n");
+
+ /* argument info */
+ if (proc->arg_num > 1)
+ printit((char *) NULL, proc->args.argname);
+ else
+ /* do we have to do something special for
+ * newstyle */
+ printit(proc->args.decls->decl.prefix,
+ proc->args.decls->decl.type);
+ /* result info */
+ printit(proc->res_prefix, proc->res_type);
+ }
+
+ /* print the table trailer */
+ f_print(fout, "%s", tbl_end);
+ f_print(fout, tbl_nproc, progvers, progvers, progvers);
+ }
+}
+
+static void
+printit(prefix, type)
+ char *prefix;
+ char *type;
+{
+ int len;
+ int tabs;
+
+
+ len = fprintf(fout, "\txdr_%s,", stringfix(type));
+ /* account for leading tab expansion */
+ len += TABSIZE - 1;
+ /* round up to tabs required */
+ tabs = (TABSTOP - len + TABSIZE - 1) / TABSIZE;
+ f_print(fout, "%s", &tabstr[TABCOUNT - tabs]);
+
+ if (streq(type, "void")) {
+ f_print(fout, "0");
+ } else {
+ f_print(fout, "sizeof ( ");
+ /* XXX: should "follow" be 1 ??? */
+ ptype(prefix, type, 0);
+ f_print(fout, ")");
+ }
+ f_print(fout, ",\n");
+}
diff --git a/developer_cmds/rpcgen/rpc_util.c b/developer_cmds/rpcgen/rpc_util.c
new file mode 100644
index 0000000..f51114c
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_util.c
@@ -0,0 +1,513 @@
+/* $NetBSD: rpc_util.c,v 1.8 1997/10/18 10:54:14 lukem Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rpc_util.c 1.11 89/02/22 (C) 1987 SMI";
+#else
+__RCSID("$NetBSD: rpc_util.c,v 1.8 1997/10/18 10:54:14 lukem Exp $");
+#endif
+#endif
+
+/*
+ * rpc_util.c, Utility routines for the RPC protocol compiler
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include "rpc_scan.h"
+#include "rpc_parse.h"
+#include "rpc_util.h"
+
+#define ARGEXT "argument"
+
+static void printwhere __P((void));
+
+char curline[MAXLINESIZE]; /* current read line */
+char *where = curline; /* current point in line */
+int linenum = 0; /* current line number */
+
+char *infilename; /* input filename */
+
+#define NFILES 7
+char *outfiles[NFILES]; /* output file names */
+int nfiles;
+
+FILE *fout; /* file pointer of current output */
+FILE *fin; /* file pointer of current input */
+
+list *defined; /* list of defined things */
+
+static char *toktostr __P((tok_kind));
+static void printbuf __P((void));
+static void printwhere __P((void));
+static int findit __P((definition *, char *));
+static char *fixit __P((char *, char *));
+static int typedefed __P((definition *, char *));
+
+/*
+ * Reinitialize the world
+ */
+void
+reinitialize()
+{
+ memset(curline, 0, MAXLINESIZE);
+ where = curline;
+ linenum = 0;
+ defined = NULL;
+}
+/*
+ * string equality
+ */
+int
+streq(a, b)
+ char *a;
+ char *b;
+{
+ return (strcmp(a, b) == 0);
+}
+/*
+ * find a value in a list
+ */
+definition *
+findval(lst, val, cmp)
+ list *lst;
+ char *val;
+ int (*cmp) __P((definition *, char *));
+
+{
+
+ for (; lst != NULL; lst = lst->next) {
+ if ((*cmp) (lst->val, val)) {
+ return (lst->val);
+ }
+ }
+ return (NULL);
+}
+/*
+ * store a value in a list
+ */
+void
+storeval(lstp, val)
+ list **lstp;
+ definition *val;
+{
+ list **l;
+ list *lst;
+
+
+ for (l = lstp; *l != NULL; l = (list **) & (*l)->next);
+ lst = ALLOC(list);
+ lst->val = val;
+ lst->next = NULL;
+ *l = lst;
+}
+
+static int
+findit(def, type)
+ definition *def;
+ char *type;
+{
+ return (streq(def->def_name, type));
+}
+
+static char *
+fixit(type, orig)
+ char *type;
+ char *orig;
+{
+ definition *def;
+
+ def = (definition *) FINDVAL(defined, type, findit);
+ if (def == NULL || def->def_kind != DEF_TYPEDEF) {
+ return (orig);
+ }
+ switch (def->def.ty.rel) {
+ case REL_VECTOR:
+ return (def->def.ty.old_type);
+ case REL_ALIAS:
+ return (fixit(def->def.ty.old_type, orig));
+ default:
+ return (orig);
+ }
+}
+
+char *
+fixtype(type)
+ char *type;
+{
+ return (fixit(type, type));
+}
+
+char *
+stringfix(type)
+ char *type;
+{
+ if (streq(type, "string")) {
+ return ("wrapstring");
+ } else {
+ return (type);
+ }
+}
+
+void
+ptype(prefix, type, follow)
+ char *prefix;
+ char *type;
+ int follow;
+{
+ if (prefix != NULL) {
+ if (streq(prefix, "enum")) {
+ f_print(fout, "enum ");
+ } else {
+ f_print(fout, "struct ");
+ }
+ }
+ if (streq(type, "bool")) {
+ f_print(fout, "bool_t ");
+ } else
+ if (streq(type, "string")) {
+ f_print(fout, "char *");
+ } else {
+ f_print(fout, "%s ", follow ? fixtype(type) : type);
+ }
+}
+
+static int
+typedefed(def, type)
+ definition *def;
+ char *type;
+{
+ if (def->def_kind != DEF_TYPEDEF || def->def.ty.old_prefix != NULL) {
+ return (0);
+ } else {
+ return (streq(def->def_name, type));
+ }
+}
+
+int
+isvectordef(type, rel)
+ char *type;
+ relation rel;
+{
+ definition *def;
+
+ for (;;) {
+ switch (rel) {
+ case REL_VECTOR:
+ return (!streq(type, "string"));
+ case REL_ARRAY:
+ return (0);
+ case REL_POINTER:
+ return (0);
+ case REL_ALIAS:
+ def = (definition *) FINDVAL(defined, type, typedefed);
+ if (def == NULL) {
+ return (0);
+ }
+ type = def->def.ty.old_type;
+ rel = def->def.ty.rel;
+ }
+ }
+}
+
+char *
+locase(str)
+ char *str;
+{
+ char c;
+ static char buf[100];
+ char *p = buf;
+
+ while ((c = *str++) != '\0') {
+ *p++ = (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c;
+ }
+ *p = 0;
+ return (buf);
+}
+
+void
+pvname_svc(pname, vnum)
+ char *pname;
+ char *vnum;
+{
+ f_print(fout, "%s_%s_svc", locase(pname), vnum);
+}
+
+void
+pvname(pname, vnum)
+ char *pname;
+ char *vnum;
+{
+ f_print(fout, "%s_%s", locase(pname), vnum);
+}
+/*
+ * print a useful (?) error message, and then die
+ */
+void
+error(msg)
+ char *msg;
+{
+ printwhere();
+ f_print(stderr, "%s, line %d: ", infilename, linenum);
+ f_print(stderr, "%s\n", msg);
+ crash();
+}
+/*
+ * Something went wrong, unlink any files that we may have created and then
+ * die.
+ */
+void
+crash()
+{
+ int i;
+
+ for (i = 0; i < nfiles; i++) {
+ (void) unlink(outfiles[i]);
+ }
+ exit(1);
+}
+
+void
+record_open(file)
+ char *file;
+{
+ if (nfiles < NFILES) {
+ outfiles[nfiles++] = file;
+ } else {
+ f_print(stderr, "too many files!\n");
+ crash();
+ }
+}
+
+static char expectbuf[100];
+
+/*
+ * error, token encountered was not the expected one
+ */
+void
+expected1(exp1)
+ tok_kind exp1;
+{
+ s_print(expectbuf, "expected '%s'",
+ toktostr(exp1));
+ error(expectbuf);
+}
+/*
+ * error, token encountered was not one of two expected ones
+ */
+void
+expected2(exp1, exp2)
+ tok_kind exp1, exp2;
+{
+ s_print(expectbuf, "expected '%s' or '%s'",
+ toktostr(exp1),
+ toktostr(exp2));
+ error(expectbuf);
+}
+/*
+ * error, token encountered was not one of 3 expected ones
+ */
+void
+expected3(exp1, exp2, exp3)
+ tok_kind exp1, exp2, exp3;
+{
+ s_print(expectbuf, "expected '%s', '%s' or '%s'",
+ toktostr(exp1),
+ toktostr(exp2),
+ toktostr(exp3));
+ error(expectbuf);
+}
+
+void
+tabify(f, tab)
+ FILE *f;
+ int tab;
+{
+ while (tab--) {
+ (void) fputc('\t', f);
+ }
+}
+
+
+static token tokstrings[] = {
+ {TOK_IDENT, "identifier"},
+ {TOK_CONST, "const"},
+ {TOK_RPAREN, ")"},
+ {TOK_LPAREN, "("},
+ {TOK_RBRACE, "}"},
+ {TOK_LBRACE, "{"},
+ {TOK_LBRACKET, "["},
+ {TOK_RBRACKET, "]"},
+ {TOK_STAR, "*"},
+ {TOK_COMMA, ","},
+ {TOK_EQUAL, "="},
+ {TOK_COLON, ":"},
+ {TOK_SEMICOLON, ";"},
+ {TOK_UNION, "union"},
+ {TOK_STRUCT, "struct"},
+ {TOK_SWITCH, "switch"},
+ {TOK_CASE, "case"},
+ {TOK_DEFAULT, "default"},
+ {TOK_ENUM, "enum"},
+ {TOK_TYPEDEF, "typedef"},
+ {TOK_INT, "int"},
+ {TOK_SHORT, "short"},
+ {TOK_LONG, "long"},
+ {TOK_UNSIGNED, "unsigned"},
+ {TOK_DOUBLE, "double"},
+ {TOK_FLOAT, "float"},
+ {TOK_CHAR, "char"},
+ {TOK_STRING, "string"},
+ {TOK_OPAQUE, "opaque"},
+ {TOK_BOOL, "bool"},
+ {TOK_VOID, "void"},
+ {TOK_PROGRAM, "program"},
+ {TOK_VERSION, "version"},
+ {TOK_EOF, "??????"}
+};
+
+static char *
+toktostr(kind)
+ tok_kind kind;
+{
+ token *sp;
+
+ for (sp = tokstrings; sp->kind != TOK_EOF && sp->kind != kind; sp++);
+ return (sp->str);
+}
+
+static void
+printbuf()
+{
+ char c;
+ int i;
+ int cnt;
+
+#define TABSIZE 4
+
+ for (i = 0; (c = curline[i]) != '\0'; i++) {
+ if (c == '\t') {
+ cnt = 8 - (i % TABSIZE);
+ c = ' ';
+ } else {
+ cnt = 1;
+ }
+ while (cnt--) {
+ (void) fputc(c, stderr);
+ }
+ }
+}
+
+static void
+printwhere()
+{
+ int i;
+ char c;
+ int cnt;
+
+ printbuf();
+ for (i = 0; i < where - curline; i++) {
+ c = curline[i];
+ if (c == '\t') {
+ cnt = 8 - (i % TABSIZE);
+ } else {
+ cnt = 1;
+ }
+ while (cnt--) {
+ (void) fputc('^', stderr);
+ }
+ }
+ (void) fputc('\n', stderr);
+}
+
+char *
+make_argname(pname, vname)
+ char *pname;
+ char *vname;
+{
+ char *name;
+
+ name = (char *) malloc(strlen(pname) + strlen(vname) + strlen(ARGEXT) + 3);
+ if (!name) {
+ fprintf(stderr, "failed in malloc");
+ exit(1);
+ }
+ sprintf(name, "%s_%s_%s", locase(pname), vname, ARGEXT);
+ return (name);
+}
+
+bas_type *typ_list_h;
+bas_type *typ_list_t;
+
+void
+add_type(len, type)
+ int len;
+ char *type;
+{
+ bas_type *ptr;
+
+ if ((ptr = (bas_type *) malloc(sizeof(bas_type))) == (bas_type *) NULL) {
+ fprintf(stderr, "failed in malloc");
+ exit(1);
+ }
+ ptr->name = type;
+ ptr->length = len;
+ ptr->next = NULL;
+ if (typ_list_t == NULL) {
+ typ_list_t = ptr;
+ typ_list_h = ptr;
+ } else {
+ typ_list_t->next = ptr;
+ typ_list_t = ptr;
+ }
+}
+
+bas_type *
+find_type(type)
+ char *type;
+{
+ bas_type *ptr;
+
+ ptr = typ_list_h;
+
+
+ while (ptr != NULL) {
+ if (strcmp(ptr->name, type) == 0)
+ return (ptr);
+ else
+ ptr = ptr->next;
+ }
+ return (NULL);
+}
diff --git a/developer_cmds/rpcgen/rpc_util.h b/developer_cmds/rpcgen/rpc_util.h
new file mode 100644
index 0000000..33a84b3
--- /dev/null
+++ b/developer_cmds/rpcgen/rpc_util.h
@@ -0,0 +1,178 @@
+/* $NetBSD: rpc_util.h,v 1.4 1997/10/11 21:01:58 christos Exp $ */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+/* @(#)rpc_util.h 1.5 90/08/29 (C) 1987 SMI */
+
+/*
+ * rpc_util.h, Useful definitions for the RPC protocol compiler
+ */
+#include <sys/types.h>
+#include <stdlib.h>
+
+#define alloc(size) (void *)malloc((unsigned)(size))
+#define ALLOC(object) (object *) malloc(sizeof(object))
+
+#define s_print (void) sprintf
+#define f_print (void) fprintf
+
+struct list {
+ definition *val;
+ struct list *next;
+};
+typedef struct list list;
+
+#define PUT 1
+#define GET 2
+
+/*
+ * Global variables
+ */
+#define MAXLINESIZE 1024
+extern char curline[MAXLINESIZE];
+extern char *where;
+extern int linenum;
+
+extern char *infilename;
+extern FILE *fout;
+extern FILE *fin;
+
+extern list *defined;
+
+
+extern bas_type *typ_list_h;
+extern bas_type *typ_list_t;
+
+/*
+ * All the option flags
+ */
+extern int inetdflag;
+extern int pmflag;
+extern int tblflag;
+extern int logflag;
+extern int newstyle;
+extern int Cflag; /* C++ flag */
+extern int tirpcflag; /* flag for generating tirpc code */
+extern int doinline; /* if this is 0, then do not generate inline code */
+extern int callerflag;
+
+/*
+ * Other flags related with inetd jumpstart.
+ */
+extern int indefinitewait;
+extern int exitnow;
+extern int timerflag;
+
+extern int nonfatalerrors;
+
+extern pid_t childpid;
+
+/*
+ * rpc_util routines
+ */
+
+#define STOREVAL(list,item) \
+ storeval(list,item)
+
+#define FINDVAL(list,item,finder) \
+ findval(list, item, finder)
+
+void reinitialize __P((void));
+int streq __P((char *, char *));
+definition *findval __P((list *, char *, int (*)(definition *, char *)));
+void storeval __P((list **, definition *));
+char *fixtype __P((char *));
+char *stringfix __P((char *));
+void ptype __P((char *, char *, int));
+int isvectordef __P((char *, relation));
+char *locase __P((char *));
+void pvname_svc __P((char *, char *));
+void pvname __P((char *, char *));
+void error __P((char *));
+void crash __P((void));
+void record_open __P((char *));
+void expected1 __P((tok_kind));
+void expected2 __P((tok_kind, tok_kind ));
+void expected3 __P((tok_kind, tok_kind, tok_kind));
+void tabify __P((FILE *, int));
+void record_open __P((char *));
+char *make_argname __P((char *, char *));
+void add_type __P((int, char *));
+bas_type *find_type __P((char *));
+/*
+ * rpc_cout routines
+ */
+void emit __P((definition *));
+void emit_inline __P((declaration *, int));
+void emit_single_in_line __P((declaration *, int, relation));
+char *upcase __P((char *));
+
+/*
+ * rpc_hout routines
+ */
+
+void print_datadef __P((definition *));
+void print_funcdef __P((definition *));
+void pxdrfuncdecl __P((char *, int));
+void pprocdef __P((proc_list *, version_list *, char *, int, int));
+void pdeclaration __P((char *, declaration *, int, char *));
+
+/*
+ * rpc_svcout routines
+ */
+void write_most __P((char *, int, int));
+void write_netid_register __P((char *));
+void write_nettype_register __P((char *));
+void write_rest __P((void));
+void write_programs __P((char *));
+int nullproc __P((proc_list *));
+void write_svc_aux __P((int));
+void write_msg_out __P((void));
+void write_inetd_register __P((char *));
+
+/*
+ * rpc_clntout routines
+ */
+void write_stubs __P((void));
+void printarglist __P((proc_list *, char *, char *));
+
+
+/*
+ * rpc_tblout routines
+ */
+void write_tables __P((void));
+
+/*
+ * rpc_sample routines
+ */
+void write_sample_svc __P((definition *));
+int write_sample_clnt __P((definition *));
+void add_sample_msg __P((void));
+void write_sample_clnt_main __P((void));
diff --git a/developer_cmds/rpcgen/rpcgen.1 b/developer_cmds/rpcgen/rpcgen.1
new file mode 100644
index 0000000..a5764a6
--- /dev/null
+++ b/developer_cmds/rpcgen/rpcgen.1
@@ -0,0 +1,452 @@
+.\" $NetBSD: rpcgen.1,v 1.8 1998/04/28 07:19:29 fair Exp $
+.\" from: @(#)rpcgen.new.1 1.1 90/11/09 TIRPC 1.0; from 40.10 of 10/10/89
+.\" Copyright (c) 1988,1990 Sun Microsystems, Inc. - All Rights Reserved.
+.Dd June 11, 1995
+.Dt RPCGEN 1
+.Sh NAME
+.Nm rpcgen
+.Nd Remote Procedure Call (RPC) protocol compiler
+.Sh SYNOPSIS
+.Nm
+.Ar infile
+.Nm
+.Op Fl D Op Ar name=value
+.Op Fl A
+.Op Fl M
+.Op Fl T
+.Op Fl K Ar secs
+.Ar infile
+.Nm
+.Op Fl L
+.Fl c Li |
+.Fl h Li |
+.Fl l Li |
+.Fl m Li |
+.Fl t Li |
+.Fl S\&c Li |
+.Fl S\&s Li |
+.Op Fl o Ar outfile
+.Op Ar infile
+.Nm
+.Fl c Li |
+.Ar nettype
+.Op Fl o Ar outfile
+.Op Ar infile
+.Nm
+.Fl s Li |
+.Ar netid
+.Op Fl o Ar outfile
+.Op Ar infile
+.Sh DESCRIPTION
+.Nm
+is a tool that generates C code to implement an
+.Tn RPC
+protocol.
+The input to
+.Nm
+is a language similar to C known as
+.Tn RPC
+Language (Remote Procedure Call Language).
+.Nm
+is normally used as in the first synopsis where
+it takes an input file and generates up to four output files.
+If the
+.Ar infile
+is named
+.Pa proto.x ,
+then
+.Nm
+will generate a header file in
+.Pa proto.h ,
+.Tn XDR
+routines in
+.Pa proto_xdr.c ,
+server-side stubs in
+.Pa proto_svc.c ,
+and client-side stubs in
+.Pa proto_clnt.c .
+With the
+.Fl T
+option,
+it will also generate the
+.Tn RPC
+dispatch table in
+.Pa proto_tbl.i .
+With the
+.Fl S\&c
+option,
+it will also generate sample code which would illustrate how to use the
+remote procedures on the client side. This code would be created in
+.Pa proto_client.c .
+With the
+.Fl S\&s
+option,
+it will also generate a sample server code which would illustrate how to write
+the remote procedures. This code would be created in
+.Pa proto_server.c .
+.Pp
+The server created can be started both by the port monitors
+(for example,
+.Em inetd
+or
+.Em listen )
+or by itself.
+When it is started by a port monitor,
+it creates servers only for the transport for which
+the file descriptor 0 was passed.
+The name of the transport must be specified
+by setting up the environmental variable
+.Ev PM_TRANSPORT .
+When the server generated by
+.Nm
+is executed,
+it creates server handles for all the transports
+specified in
+.Ev NETPATH
+environment variable,
+or if it is unset,
+it creates server handles for all the visible transports from
+.Pa /etc/netconfig
+file.
+.Pp
+.Em Note:
+the transports are chosen at run time and not at compile time.
+When the server is self-started,
+it backgrounds itself by default.
+A special define symbol
+.Dv RPC_SVC_FG
+can be used to run the server process in foreground.
+.P
+The second synopsis provides special features which allow
+for the creation of more sophisticated
+.Tn RPC
+servers.
+These features include support for user provided
+.Li #defines
+and
+.Tn RPC
+dispatch tables.
+The entries in the
+.Tn RPC
+dispatch table contain:
+.Pp
+.Bl -inset -offset indent -compact
+.It +
+pointers to the service routine corresponding to that procedure,
+.It +
+a pointer to the input and output arguments,
+.It +
+the size of these routines
+.El
+.Pp
+A server can use the dispatch table to check authorization
+and then to execute the service routine;
+a client library may use it to deal with the details of storage
+management and
+.Tn XDR
+data conversion.
+.Pp
+The other three synopses shown above are used when
+one does not want to generate all the output files,
+but only a particular one.
+Some examples of their usage is described in the
+EXAMPLE
+section below.
+When
+.Nm
+is executed with the
+.Fl s
+option,
+it creates servers for that particular class of transports.
+When
+executed with the
+.Fl n
+option,
+it creates a server for the transport specified by
+.Em netid .
+If
+.Ar infile
+is not specified,
+.Nm
+accepts the standard input.
+.Pp
+The C preprocessor,
+.Xr cpp 1
+is run on the input file before it is actually interpreted by
+.Nm
+For each type of output file,
+.Nm
+defines a special preprocessor symbol for use by the
+.Nm
+programmer:
+.Bl -tag -width RPC_CLNT
+.It Dv RPC_HDR
+defined when compiling into header files
+.It Dv RPC_XDR
+defined when compiling into
+.Tn XDR
+routines
+.It Dv RPC_SVC
+defined when compiling into server-side stubs
+.It Dv RPC_CLNT
+defined when compiling into client-side stubs
+.It Dv RPC_TBL
+defined when compiling into
+.Tn RPC
+dispatch tables
+.El
+.Pp
+Any line beginning with
+.Sq %
+is passed directly into the output file,
+uninterpreted by
+.Nm .
+.Pp
+For every data type referred to in
+.Ar infile
+.Nm
+assumes that there exists a
+routine with the string
+.Dq xdr_
+prepended to the name of the data type.
+If this routine does not exist in the
+.Tn RPC/XDR
+library, it must be provided.
+Providing an undefined data type
+allows customization of
+.Tn XDR
+routines.
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl a
+Generate all the files including sample code for client and server side.
+.It Fl b
+This generates code for the
+.Tn "SunOS 4.1"
+style of
+.Tn RPC .
+This is the default.
+.It Fl C
+Generate code in
+.Tn ANSI
+C.
+This option also generates code that could be compiled with the
+C++ compiler.
+.It Fl c
+Compile into
+.Tn XDR
+routines.
+.It Fl D Ar name Ns Op Ar =value
+Define a symbol
+.Dv name .
+Equivalent to the
+.Dv #define
+directive in the source.
+If no
+.Dv value
+is given,
+.Dv value
+is defined as 1.
+This option may be specified more than once.
+.It Fl h
+Compile into C data-definitions (a header file).
+The
+.Fl T
+option can be used in conjunction to produce a
+header file which supports
+.Tn RPC
+dispatch tables.
+.It Fl K Ar secs
+By default, services created using
+.Nm
+wait 120 seconds
+after servicing a request before exiting.
+That interval can be changed using the
+.Fl K
+flag.
+To create a server that exits immediately upon servicing a request,
+.Dq Fl K No 0
+can be used.
+To create a server that never exits, the appropriate argument is
+.Dq Fl K No -1 .
+.Pp
+When monitoring for a server,
+some port monitors, like the
+.At V.4
+utility
+.Xr listen 1 ,
+.Em always
+spawn a new process in response to a service request.
+If it is known that a server will be used with such a monitor, the
+server should exit immediately on completion.
+For such servers,
+.Nm
+should be used with
+.Dq Fl K No -1 .
+.It Fl L
+Server errors will be sent to syslog instead of stderr.
+.It Fl l
+Compile into client-side stubs.
+.It Fl m
+Compile into server-side stubs,
+but do not generate a
+.Fn main
+routine.
+This option is useful for doing callback-routines
+and for users who need to write their own
+.Fn main
+routine to do initialization.
+.It Fl N
+Use the newstyle of
+.Nm .
+This allows procedures to have multiple arguments.
+It also uses the style of parameter passing that closely resembles C.
+So, when passing an argument to a remote procedure you do not have
+to pass a pointer to the argument but the argument itself.
+This behaviour is different from the oldstyle
+of
+.Nm
+generated code.
+The newstyle is not the default case because of backward compatibility.
+.It Fl n Ar netid
+Compile into server-side stubs for the transport
+specified by
+.Ar netid.
+There should be an entry for
+.Ar netid
+in the
+netconfig database.
+This option may be specified more than once,
+so as to compile a server that serves multiple transports.
+.It Fl o Ar outfile
+Specify the name of the output file.
+If none is specified,
+standard output is used
+.Po
+.Fl c Fl h Fl l
+.Fl m Fl n Fl s
+modes only
+.Pc
+.It Fl S\&c
+Generate sample code to show the use of remote procedure and how to bind
+to the server before calling the client side stubs generated by
+.Nm .
+.It Fl S\&s
+Generate skeleton code for the remote procedures on the server side. You would need
+to fill in the actual code for the remote procedures.
+.It Fl s Ar nettype
+Compile into server-side stubs for all the
+transports belonging to the class
+.Ar nettype .
+The supported classes are
+.Em netpath,
+.Em visible,
+.Em circuit_n,
+.Em circuit_v,
+.Em datagram_n,
+.Em datagram_v,
+.Em tcp,
+and
+.Em udp
+[see
+.Xr rpc 3
+for the meanings associated with these classes.
+.Em Note:
+.Bx
+currently supports only the
+.Em tcp
+and
+.Em udp
+classes].
+This option may be specified more than once.
+.Em Note:
+the transports are chosen at run time and not at compile time.
+.It Fl T
+Generate the code to support
+.Tn RPC
+dispatch tables.
+.It Fl t
+Compile into
+.Tn RPC
+dispatch table.
+.El
+.Pp
+The options
+.Fl c ,
+.Fl h ,
+.Fl l ,
+.Fl m ,
+.Fl s ,
+and
+.Fl t
+are used exclusively to generate a particular type of file,
+while the options
+.Fl D
+and
+.Fl T
+are global and can be used with the other options.
+.Sh NOTES
+The
+.Tn RPC
+Language does not support nesting of structures.
+As a work-around,
+structures can be declared at the top-level,
+and their name used inside other structures in
+order to achieve the same effect.
+.Pp
+Name clashes can occur when using program definitions,
+since the apparent scoping does not really apply.
+Most of these can be avoided by giving
+unique names for programs,
+versions,
+procedures and types.
+.Pp
+The server code generated with
+.Fl n
+option refers to the transport indicated by
+.Em netid
+and hence is very site specific.
+.Sh EXAMPLE
+.Pp
+The command
+.Pp
+.Bd -literal -offset indent
+$ rpcgen -T prot.x
+.Ed
+.Pp
+generates the five files:
+.Pa prot.h ,
+.Pa prot_clnt.c ,
+.Pa prot_svc.c ,
+.Pa prot_xdr.c
+and
+.Pa prot_tbl.i .
+.Pp
+The following example sends the C data-definitions (header file)
+to standard output.
+.Pp
+.Bd -literal -offset indent
+$ rpcgen -h prot.x
+.Ed
+.Pp
+To send the test version of the
+.Dv -DTEST ,
+server side stubs for
+all the transport belonging to the class
+.Em datagram_n
+to standard output, use:
+.Pp
+.Bd -literal -offset indent
+$ rpcgen -s datagram_n -DTEST prot.x
+.Ed
+.Pp
+To create the server side stubs for the transport indicated by
+.Em netid
+.Em tcp ,
+use:
+.Pp
+.Bd -literal -offset indent
+$ rpcgen -n tcp -o prot_svc.c prot.x
+.Ed
+.Sh SEE ALSO
+.Xr cpp 1
diff --git a/developer_cmds/unifdef/unifdef.1 b/developer_cmds/unifdef/unifdef.1
new file mode 100644
index 0000000..292ee67
--- /dev/null
+++ b/developer_cmds/unifdef/unifdef.1
@@ -0,0 +1,415 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\" Copyright (c) 2002 - 2010 Tony Finch <dot@dotat.at>. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Dave Yost. It was rewritten to support ANSI C by Tony Finch.
+.\"
+.\" 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 University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/unifdef/unifdef.1,v 1.30 2010/08/01 09:10:09 joel Exp $
+.\"
+.Dd March 11, 2010
+.Dt UNIFDEF 1
+.Os
+.Sh NAME
+.Nm unifdef , unifdefall
+.Nd remove preprocessor conditionals from code
+.Sh SYNOPSIS
+.Nm
+.Op Fl bBcdeKknsStV
+.Op Fl I Ns Ar path
+.Op Fl D Ns Ar sym Ns Op = Ns Ar val
+.Op Fl U Ns Ar sym
+.Op Fl iD Ns Ar sym Ns Op = Ns Ar val
+.Op Fl iU Ns Ar sym
+.Ar ...
+.Op Fl o Ar outfile
+.Op Ar infile
+.Nm unifdefall
+.Op Fl I Ns Ar path
+.Ar ...
+.Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility selectively processes conditional
+.Xr cpp 1
+directives.
+It removes from a file
+both the directives
+and any additional text that they specify should be removed,
+while otherwise leaving the file alone.
+.Pp
+The
+.Nm
+utility acts on
+.Ic #if , #ifdef , #ifndef , #elif , #else ,
+and
+.Ic #endif
+lines.
+A directive is only processed
+if the symbols specified on the command line are sufficient to allow
+.Nm
+to get a definite value for its control expression.
+If the result is false,
+the directive and the following lines under its control are removed.
+If the result is true,
+only the directive is removed.
+An
+.Ic #ifdef
+or
+.Ic #ifndef
+directive is passed through unchanged
+if its controlling symbol is not specified on the command line.
+Any
+.Ic #if
+or
+.Ic #elif
+control expression that has an unknown value or that
+.Nm
+cannot parse is passed through unchanged.
+By default,
+.Nm
+ignores
+.Ic #if
+and
+.Ic #elif
+lines with constant expressions;
+it can be told to process them by specifying the
+.Fl k
+flag on the command line.
+.Pp
+It understands a commonly-used subset
+of the expression syntax for
+.Ic #if
+and
+.Ic #elif
+lines:
+integer constants,
+integer values of symbols defined on the command line,
+the
+.Fn defined
+operator,
+the operators
+.Ic \&! , < , > , <= , >= , == , != , && , || ,
+and parenthesized expressions.
+A kind of
+.Dq "short circuit"
+evaluation is used for the
+.Ic &&
+operator:
+if either operand is definitely false then the result is false,
+even if the value of the other operand is unknown.
+Similarly,
+if either operand of
+.Ic ||
+is definitely true then the result is true.
+.Pp
+In most cases, the
+.Nm
+utility does not distinguish between object-like macros
+(without arguments) and function-like arguments (with arguments).
+If a macro is not explicitly defined, or is defined with the
+.Fl D
+flag on the command-line, its arguments are ignored.
+If a macro is explicitly undefined on the command line with the
+.Fl U
+flag, it may not have any arguments since this leads to a syntax error.
+.Pp
+The
+.Nm
+utility understands just enough about C
+to know when one of the directives is inactive
+because it is inside
+a comment,
+or affected by a backslash-continued line.
+It spots unusually-formatted preprocessor directives
+and knows when the layout is too odd for it to handle.
+.Pp
+A script called
+.Nm unifdefall
+can be used to remove all conditional
+.Xr cpp 1
+directives from a file.
+It uses
+.Nm Fl s
+and
+.Nm cpp Fl dM
+to get lists of all the controlling symbols
+and their definitions (or lack thereof),
+then invokes
+.Nm
+with appropriate arguments to process the file.
+.Sh OPTIONS
+.Pp
+.Bl -tag -width indent -compact
+.It Fl D Ns Ar sym Ns = Ns Ar val
+Specify that a symbol is defined to a given value
+which is used when evaluating
+.Ic #if
+and
+.Ic #elif
+control expressions.
+.Pp
+.It Fl D Ns Ar sym
+Specify that a symbol is defined to the value 1.
+.Pp
+.It Fl U Ns Ar sym
+Specify that a symbol is undefined.
+If the same symbol appears in more than one argument,
+the last occurrence dominates.
+.Pp
+.It Fl b
+Replace removed lines with blank lines
+instead of deleting them.
+Mutually exclusive with the
+.Fl B
+option.
+.Pp
+.It Fl B
+Compress blank lines around a deleted section.
+Mutually exclusive with the
+.Fl b
+option.
+.Pp
+.It Fl c
+If the
+.Fl c
+flag is specified,
+then the operation of
+.Nm
+is complemented,
+i.e., the lines that would have been removed or blanked
+are retained and vice versa.
+.Pp
+.It Fl d
+Turn on printing of debugging messages.
+.Pp
+.It Fl e
+Because
+.Nm
+processes its input one line at a time,
+it cannot remove preprocessor directives that span more than one line.
+The most common example of this is a directive with a multi-line
+comment hanging off its right hand end.
+By default,
+if
+.Nm
+has to process such a directive,
+it will complain that the line is too obfuscated.
+The
+.Fl e
+option changes the behaviour so that,
+where possible,
+such lines are left unprocessed instead of reporting an error.
+.Pp
+.It Fl K
+Always treat the result of
+.Ic &&
+and
+.Ic ||
+operators as unknown if either operand is unknown,
+instead of short-circuiting when unknown operands can't affect the result.
+This option is for compatibility with older versions of
+.Nm .
+.Pp
+.It Fl k
+Process
+.Ic #if
+and
+.Ic #elif
+lines with constant expressions.
+By default, sections controlled by such lines are passed through unchanged
+because they typically start
+.Dq Li "#if 0"
+and are used as a kind of comment to sketch out future or past development.
+It would be rude to strip them out, just as it would be for normal comments.
+.Pp
+.It Fl n
+Add
+.Li #line
+directives to the output following any deleted lines,
+so that errors produced when compiling the output file correspond to
+line numbers in the input file.
+.Pp
+.It Fl o Ar outfile
+Write output to the file
+.Ar outfile
+instead of the standard output.
+If
+.Ar outfile
+is the same as the input file,
+the output is written to a temporary file
+which is renamed into place when
+.Nm
+completes successfully.
+.Pp
+.It Fl s
+Instead of processing the input file as usual,
+this option causes
+.Nm
+to produce a list of symbols that appear in expressions
+that
+.Nm
+understands.
+It is useful in conjunction with the
+.Fl dM
+option of
+.Xr cpp 1
+for creating
+.Nm
+command lines.
+.Pp
+.It Fl S
+Like the
+.Fl s
+option, but the nesting depth of each symbol is also printed.
+This is useful for working out the number of possible combinations
+of interdependent defined/undefined symbols.
+.Pp
+.It Fl t
+Disables parsing for C comments
+and line continuations,
+which is useful
+for plain text.
+.Pp
+.It Fl iD Ns Ar sym Ns Op = Ns Ar val
+.It Fl iU Ns Ar sym
+Ignore
+.Ic #ifdef Ns s .
+If your C code uses
+.Ic #ifdef Ns s
+to delimit non-C lines,
+such as comments
+or code which is under construction,
+then you must tell
+.Nm
+which symbols are used for that purpose so that it will not try to parse
+comments
+and line continuations
+inside those
+.Ic #ifdef Ns s .
+You can specify ignored symbols with
+.Fl iD Ns Ar sym Ns Oo = Ns Ar val Oc
+and
+.Fl iU Ns Ar sym
+similar to
+.Fl D Ns Ar sym Ns Op = Ns Ar val
+and
+.Fl U Ns Ar sym
+above.
+.Pp
+.It Fl I Ns Ar path
+Specifies to
+.Nm unifdefall
+an additional place to look for
+.Ic #include
+files.
+This option is ignored by
+.Nm
+for compatibility with
+.Xr cpp 1
+and to simplify the implementation of
+.Nm unifdefall .
+.Pp
+.It Fl V
+Print version details.
+.El
+.Pp
+The
+.Nm
+utility copies its output to
+.Em stdout
+and will take its input from
+.Em stdin
+if no
+.Ar file
+argument is given.
+.Pp
+The
+.Nm
+utility works nicely with the
+.Fl D Ns Ar sym
+option of
+.Xr diff 1 .
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 if the output is an exact copy of the input,
+1 if not, and 2 if in trouble.
+.Sh DIAGNOSTICS
+.Bl -item
+.It
+Too many levels of nesting.
+.It
+Inappropriate
+.Ic #elif ,
+.Ic #else
+or
+.Ic #endif .
+.It
+Obfuscated preprocessor control line.
+.It
+Premature
+.Tn EOF
+(with the line number of the most recent unterminated
+.Ic #if ) .
+.It
+.Tn EOF
+in comment.
+.El
+.Sh SEE ALSO
+.Xr cpp 1 ,
+.Xr diff 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 2.9 .
+.Tn ANSI\~C
+support was added in
+.Fx 4.7 .
+.Sh AUTHORS
+The original implementation was written by
+.An Dave Yost Aq Dave@Yost.com .
+.An Tony Finch Aq dot@dotat.at
+rewrote it to support
+.Tn ANSI\~C .
+.Sh BUGS
+Expression evaluation is very limited.
+.Pp
+Preprocessor control lines split across more than one physical line
+(because of comments or backslash-newline)
+cannot be handled in every situation.
+.Pp
+Trigraphs are not recognized.
+.Pp
+There is no support for symbols with different definitions at
+different points in the source file.
+.Pp
+The text-mode and ignore functionality does not correspond to modern
+.Xr cpp 1
+behaviour.
diff --git a/developer_cmds/unifdef/unifdef.c b/developer_cmds/unifdef/unifdef.c
new file mode 100644
index 0000000..8c54e6e
--- /dev/null
+++ b/developer_cmds/unifdef/unifdef.c
@@ -0,0 +1,1235 @@
+/*
+ * Copyright (c) 2002 - 2011 Tony Finch <dot@dotat.at>
+ *
+ * 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.
+ */
+
+/*
+ * unifdef - remove ifdef'ed lines
+ *
+ * This code was derived from software contributed to Berkeley by Dave Yost.
+ * It was rewritten to support ANSI C by Tony Finch. The original version
+ * of unifdef carried the 4-clause BSD copyright licence. None of its code
+ * remains in this version (though some of the names remain) so it now
+ * carries a more liberal licence.
+ *
+ * Wishlist:
+ * provide an option which will append the name of the
+ * appropriate symbol after #else's and #endif's
+ * provide an option which will check symbols after
+ * #else's and #endif's to see that they match their
+ * corresponding #ifdef or #ifndef
+ *
+ * These require better buffer handling, which would also make
+ * it possible to handle all "dodgy" directives correctly.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+const char copyright[] =
+ "@(#) $Version: unifdef-2.5.6.21f1388 $\n"
+ "@(#) $FreeBSD: src/usr.bin/unifdef/unifdef.c,v 1.31 2011/01/21 18:10:11 fanf Exp $\n"
+ "@(#) $Author: Tony Finch (dot@dotat.at) $\n"
+ "@(#) $URL: http://dotat.at/prog/unifdef $\n"
+;
+
+/* types of input lines: */
+typedef enum {
+ LT_TRUEI, /* a true #if with ignore flag */
+ LT_FALSEI, /* a false #if with ignore flag */
+ LT_IF, /* an unknown #if */
+ LT_TRUE, /* a true #if */
+ LT_FALSE, /* a false #if */
+ LT_ELIF, /* an unknown #elif */
+ LT_ELTRUE, /* a true #elif */
+ LT_ELFALSE, /* a false #elif */
+ LT_ELSE, /* #else */
+ LT_ENDIF, /* #endif */
+ LT_DODGY, /* flag: directive is not on one line */
+ LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
+ LT_PLAIN, /* ordinary line */
+ LT_EOF, /* end of file */
+ LT_ERROR, /* unevaluable #if */
+ LT_COUNT
+} Linetype;
+
+static char const * const linetype_name[] = {
+ "TRUEI", "FALSEI", "IF", "TRUE", "FALSE",
+ "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF",
+ "DODGY TRUEI", "DODGY FALSEI",
+ "DODGY IF", "DODGY TRUE", "DODGY FALSE",
+ "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
+ "DODGY ELSE", "DODGY ENDIF",
+ "PLAIN", "EOF", "ERROR"
+};
+
+/* state of #if processing */
+typedef enum {
+ IS_OUTSIDE,
+ IS_FALSE_PREFIX, /* false #if followed by false #elifs */
+ IS_TRUE_PREFIX, /* first non-false #(el)if is true */
+ IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */
+ IS_FALSE_MIDDLE, /* a false #elif after a pass state */
+ IS_TRUE_MIDDLE, /* a true #elif after a pass state */
+ IS_PASS_ELSE, /* an else after a pass state */
+ IS_FALSE_ELSE, /* an else after a true state */
+ IS_TRUE_ELSE, /* an else after only false states */
+ IS_FALSE_TRAILER, /* #elifs after a true are false */
+ IS_COUNT
+} Ifstate;
+
+static char const * const ifstate_name[] = {
+ "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX",
+ "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE",
+ "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE",
+ "FALSE_TRAILER"
+};
+
+/* state of comment parser */
+typedef enum {
+ NO_COMMENT = false, /* outside a comment */
+ C_COMMENT, /* in a comment like this one */
+ CXX_COMMENT, /* between // and end of line */
+ STARTING_COMMENT, /* just after slash-backslash-newline */
+ FINISHING_COMMENT, /* star-backslash-newline in a C comment */
+ CHAR_LITERAL, /* inside '' */
+ STRING_LITERAL /* inside "" */
+} Comment_state;
+
+static char const * const comment_name[] = {
+ "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING"
+};
+
+/* state of preprocessor line parser */
+typedef enum {
+ LS_START, /* only space and comments on this line */
+ LS_HASH, /* only space, comments, and a hash */
+ LS_DIRTY /* this line can't be a preprocessor line */
+} Line_state;
+
+static char const * const linestate_name[] = {
+ "START", "HASH", "DIRTY"
+};
+
+/*
+ * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1
+ */
+#define MAXDEPTH 64 /* maximum #if nesting */
+#define MAXLINE 4096 /* maximum length of line */
+#define MAXSYMS 4096 /* maximum number of symbols */
+
+/*
+ * Sometimes when editing a keyword the replacement text is longer, so
+ * we leave some space at the end of the tline buffer to accommodate this.
+ */
+#define EDITSLOP 10
+
+/*
+ * For temporary filenames
+ */
+#define TEMPLATE "unifdef.XXXXXX"
+
+/*
+ * Globals.
+ */
+
+static bool compblank; /* -B: compress blank lines */
+static bool lnblank; /* -b: blank deleted lines */
+static bool complement; /* -c: do the complement */
+static bool debugging; /* -d: debugging reports */
+static bool iocccok; /* -e: fewer IOCCC errors */
+static bool strictlogic; /* -K: keep ambiguous #ifs */
+static bool killconsts; /* -k: eval constant #ifs */
+static bool lnnum; /* -n: add #line directives */
+static bool symlist; /* -s: output symbol list */
+static bool symdepth; /* -S: output symbol depth */
+static bool text; /* -t: this is a text file */
+
+static const char *symname[MAXSYMS]; /* symbol name */
+static const char *value[MAXSYMS]; /* -Dsym=value */
+static bool ignore[MAXSYMS]; /* -iDsym or -iUsym */
+static int nsyms; /* number of symbols */
+
+static FILE *input; /* input file pointer */
+static const char *filename; /* input file name */
+static int linenum; /* current line number */
+static FILE *output; /* output file pointer */
+static const char *ofilename; /* output file name */
+static bool overwriting; /* output overwrites input */
+static char tempname[FILENAME_MAX]; /* used when overwriting */
+
+static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */
+static char *keyword; /* used for editing #elif's */
+
+static const char *newline; /* input file format */
+static const char newline_unix[] = "\n";
+static const char newline_crlf[] = "\r\n";
+
+static Comment_state incomment; /* comment parser state */
+static Line_state linestate; /* #if line parser state */
+static Ifstate ifstate[MAXDEPTH]; /* #if processor state */
+static bool ignoring[MAXDEPTH]; /* ignore comments state */
+static int stifline[MAXDEPTH]; /* start of current #if */
+static int depth; /* current #if nesting */
+static int delcount; /* count of deleted lines */
+static unsigned blankcount; /* count of blank lines */
+static unsigned blankmax; /* maximum recent blankcount */
+static bool constexpr; /* constant #if expression */
+static bool zerosyms = true; /* to format symdepth output */
+static bool firstsym; /* ditto */
+
+static int exitstat; /* program exit status */
+
+static void addsym(bool, bool, char *);
+static void closeout(void);
+static void debug(const char *, ...);
+static void done(void);
+static void error(const char *);
+static int findsym(const char *);
+static void flushline(bool);
+static Linetype parseline(void);
+static Linetype ifeval(const char **);
+static void ignoreoff(void);
+static void ignoreon(void);
+static void keywordedit(const char *);
+static void nest(void);
+static void process(void);
+static const char *skipargs(const char *);
+static const char *skipcomment(const char *);
+static const char *skipsym(const char *);
+static void state(Ifstate);
+static int strlcmp(const char *, const char *, size_t);
+static void unnest(void);
+static void usage(void);
+static void version(void);
+
+#define endsym(c) (!isalnum((unsigned char)c) && c != '_')
+
+/*
+ * The main program.
+ */
+int
+main(int argc, char *argv[])
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "i:D:U:I:o:bBcdeKklnsStV")) != -1)
+ switch (opt) {
+ case 'i': /* treat stuff controlled by these symbols as text */
+ /*
+ * For strict backwards-compatibility the U or D
+ * should be immediately after the -i but it doesn't
+ * matter much if we relax that requirement.
+ */
+ opt = *optarg++;
+ if (opt == 'D')
+ addsym(true, true, optarg);
+ else if (opt == 'U')
+ addsym(true, false, optarg);
+ else
+ usage();
+ break;
+ case 'D': /* define a symbol */
+ addsym(false, true, optarg);
+ break;
+ case 'U': /* undef a symbol */
+ addsym(false, false, optarg);
+ break;
+ case 'I': /* no-op for compatibility with cpp */
+ break;
+ case 'b': /* blank deleted lines instead of omitting them */
+ case 'l': /* backwards compatibility */
+ lnblank = true;
+ break;
+ case 'B': /* compress blank lines around removed section */
+ compblank = true;
+ break;
+ case 'c': /* treat -D as -U and vice versa */
+ complement = true;
+ break;
+ case 'd':
+ debugging = true;
+ break;
+ case 'e': /* fewer errors from dodgy lines */
+ iocccok = true;
+ break;
+ case 'K': /* keep ambiguous #ifs */
+ strictlogic = true;
+ break;
+ case 'k': /* process constant #ifs */
+ killconsts = true;
+ break;
+ case 'n': /* add #line directive after deleted lines */
+ lnnum = true;
+ break;
+ case 'o': /* output to a file */
+ ofilename = optarg;
+ break;
+ case 's': /* only output list of symbols that control #ifs */
+ symlist = true;
+ break;
+ case 'S': /* list symbols with their nesting depth */
+ symlist = symdepth = true;
+ break;
+ case 't': /* don't parse C comments */
+ text = true;
+ break;
+ case 'V': /* print version */
+ version();
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+ if (compblank && lnblank)
+ errx(2, "-B and -b are mutually exclusive");
+ if (argc > 1) {
+ errx(2, "can only do one file");
+ } else if (argc == 1 && strcmp(*argv, "-") != 0) {
+ filename = *argv;
+ input = fopen(filename, "rb");
+ if (input == NULL)
+ err(2, "can't open %s", filename);
+ } else {
+ filename = "[stdin]";
+ input = stdin;
+ }
+ if (ofilename == NULL) {
+ ofilename = "[stdout]";
+ output = stdout;
+ } else {
+ struct stat ist, ost;
+ if (stat(ofilename, &ost) == 0 &&
+ fstat(fileno(input), &ist) == 0)
+ overwriting = (ist.st_dev == ost.st_dev
+ && ist.st_ino == ost.st_ino);
+ if (overwriting) {
+ const char *dirsep;
+ int ofd;
+
+ dirsep = strrchr(ofilename, '/');
+ if (dirsep != NULL)
+ snprintf(tempname, sizeof(tempname),
+ "%.*s/" TEMPLATE,
+ (int)(dirsep - ofilename), ofilename);
+ else
+ snprintf(tempname, sizeof(tempname),
+ TEMPLATE);
+ ofd = mkstemp(tempname);
+ if (ofd != -1)
+ output = fdopen(ofd, "wb+");
+ if (output == NULL)
+ err(2, "can't create temporary file");
+ fchmod(ofd, ist.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
+ } else {
+ output = fopen(ofilename, "wb");
+ if (output == NULL)
+ err(2, "can't open %s", ofilename);
+ }
+ }
+ process();
+ abort(); /* bug */
+}
+
+static void
+version(void)
+{
+ const char *c = copyright;
+ for (;;) {
+ while (*++c != '$')
+ if (*c == '\0')
+ exit(0);
+ while (*++c != '$')
+ putc(*c, stderr);
+ putc('\n', stderr);
+ }
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: unifdef [-bBcdeKknsStV] [-Ipath]"
+ " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
+ exit(2);
+}
+
+/*
+ * A state transition function alters the global #if processing state
+ * in a particular way. The table below is indexed by the current
+ * processing state and the type of the current line.
+ *
+ * Nesting is handled by keeping a stack of states; some transition
+ * functions increase or decrease the depth. They also maintain the
+ * ignore state on a stack. In some complicated cases they have to
+ * alter the preprocessor directive, as follows.
+ *
+ * When we have processed a group that starts off with a known-false
+ * #if/#elif sequence (which has therefore been deleted) followed by a
+ * #elif that we don't understand and therefore must keep, we edit the
+ * latter into a #if to keep the nesting correct. We use strncpy() to
+ * overwrite the 4 byte token "elif" with "if " without a '\0' byte.
+ *
+ * When we find a true #elif in a group, the following block will
+ * always be kept and the rest of the sequence after the next #elif or
+ * #else will be discarded. We edit the #elif into a #else and the
+ * following directive to #endif since this has the desired behaviour.
+ *
+ * "Dodgy" directives are split across multiple lines, the most common
+ * example being a multi-line comment hanging off the right of the
+ * directive. We can handle them correctly only if there is no change
+ * from printing to dropping (or vice versa) caused by that directive.
+ * If the directive is the first of a group we have a choice between
+ * failing with an error, or passing it through unchanged instead of
+ * evaluating it. The latter is not the default to avoid questions from
+ * users about unifdef unexpectedly leaving behind preprocessor directives.
+ */
+typedef void state_fn(void);
+
+/* report an error */
+static void Eelif (void) { error("Inappropriate #elif"); }
+static void Eelse (void) { error("Inappropriate #else"); }
+static void Eendif(void) { error("Inappropriate #endif"); }
+static void Eeof (void) { error("Premature EOF"); }
+static void Eioccc(void) { error("Obfuscated preprocessor control line"); }
+/* plain line handling */
+static void print (void) { flushline(true); }
+static void drop (void) { flushline(false); }
+/* output lacks group's start line */
+static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); }
+static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); }
+static void Selse (void) { drop(); state(IS_TRUE_ELSE); }
+/* print/pass this block */
+static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); }
+static void Pelse (void) { print(); state(IS_PASS_ELSE); }
+static void Pendif(void) { print(); unnest(); }
+/* discard this block */
+static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); }
+static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); }
+static void Delse (void) { drop(); state(IS_FALSE_ELSE); }
+static void Dendif(void) { drop(); unnest(); }
+/* first line of group */
+static void Fdrop (void) { nest(); Dfalse(); }
+static void Fpass (void) { nest(); Pelif(); }
+static void Ftrue (void) { nest(); Strue(); }
+static void Ffalse(void) { nest(); Sfalse(); }
+/* variable pedantry for obfuscated lines */
+static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); }
+static void Oif (void) { if (!iocccok) Eioccc(); Fpass(); }
+static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); }
+/* ignore comments in this block */
+static void Idrop (void) { Fdrop(); ignoreon(); }
+static void Itrue (void) { Ftrue(); ignoreon(); }
+static void Ifalse(void) { Ffalse(); ignoreon(); }
+/* modify this line */
+static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); }
+static void Mtrue (void) { keywordedit("else"); state(IS_TRUE_MIDDLE); }
+static void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); }
+static void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); }
+
+static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
+/* IS_OUTSIDE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif,
+ print, done, abort },
+/* IS_FALSE_PREFIX */
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
+ drop, Eeof, abort },
+/* IS_TRUE_PREFIX */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
+ print, Eeof, abort },
+/* IS_PASS_MIDDLE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif,
+ print, Eeof, abort },
+/* IS_FALSE_MIDDLE */
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
+ drop, Eeof, abort },
+/* IS_TRUE_MIDDLE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
+ print, Eeof, abort },
+/* IS_PASS_ELSE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif,
+ print, Eeof, abort },
+/* IS_FALSE_ELSE */
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
+ drop, Eeof, abort },
+/* IS_TRUE_ELSE */
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc,
+ print, Eeof, abort },
+/* IS_FALSE_TRAILER */
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
+ drop, Eeof, abort }
+/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF
+ TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY)
+ PLAIN EOF ERROR */
+};
+
+/*
+ * State machine utility functions
+ */
+static void
+ignoreoff(void)
+{
+ if (depth == 0)
+ abort(); /* bug */
+ ignoring[depth] = ignoring[depth-1];
+}
+static void
+ignoreon(void)
+{
+ ignoring[depth] = true;
+}
+static void
+keywordedit(const char *replacement)
+{
+ snprintf(keyword, tline + sizeof(tline) - keyword,
+ "%s%s", replacement, newline);
+ print();
+}
+static void
+nest(void)
+{
+ if (depth > MAXDEPTH-1)
+ abort(); /* bug */
+ if (depth == MAXDEPTH-1)
+ error("Too many levels of nesting");
+ depth += 1;
+ stifline[depth] = linenum;
+}
+static void
+unnest(void)
+{
+ if (depth == 0)
+ abort(); /* bug */
+ depth -= 1;
+}
+static void
+state(Ifstate is)
+{
+ ifstate[depth] = is;
+}
+
+/*
+ * Write a line to the output or not, according to command line options.
+ * If writing fails, closeout() will print the error and exit.
+ */
+static void
+flushline(bool keep)
+{
+ if (symlist)
+ return;
+ if (keep ^ complement) {
+ bool blankline = tline[strspn(tline, " \t\r\n")] == '\0';
+ if (blankline && compblank && blankcount != blankmax) {
+ delcount += 1;
+ blankcount += 1;
+ } else {
+ if (lnnum && delcount > 0 &&
+ fprintf(output, "#line %d%s", linenum, newline) < 0)
+ closeout();
+ if (fputs(tline, output) == EOF)
+ closeout();
+ delcount = 0;
+ blankmax = blankcount = blankline ? blankcount + 1 : 0;
+ }
+ } else {
+ if (lnblank && fputs(newline, output) == EOF)
+ closeout();
+ exitstat = 1;
+ delcount += 1;
+ blankcount = 0;
+ }
+ if (debugging && fflush(output) == EOF)
+ closeout();
+}
+
+/*
+ * The driver for the state machine.
+ */
+static void
+process(void)
+{
+ /* When compressing blank lines, act as if the file
+ is preceded by a large number of blank lines. */
+ blankmax = blankcount = 1000;
+ for (;;) {
+ Linetype lineval = parseline();
+ trans_table[ifstate[depth]][lineval]();
+ debug("process line %d %s -> %s depth %d",
+ linenum, linetype_name[lineval],
+ ifstate_name[ifstate[depth]], depth);
+ }
+}
+
+/*
+ * Flush the output and handle errors.
+ */
+static void
+closeout(void)
+{
+ if (symdepth && !zerosyms)
+ printf("\n");
+ if (ferror(output) || fclose(output) == EOF) {
+ if (overwriting) {
+ warn("couldn't write to temporary file");
+ unlink(tempname);
+ errx(2, "%s unchanged", ofilename);
+ } else {
+ err(2, "couldn't write to %s", ofilename);
+ }
+ }
+}
+
+/*
+ * Clean up and exit.
+ */
+static void
+done(void)
+{
+ if (incomment)
+ error("EOF in comment");
+ closeout();
+ if (overwriting && rename(tempname, ofilename) == -1) {
+ warn("couldn't rename temporary file");
+ unlink(tempname);
+ errx(2, "%s unchanged", ofilename);
+ }
+ exit(exitstat);
+}
+
+/*
+ * Parse a line and determine its type. We keep the preprocessor line
+ * parser state between calls in the global variable linestate, with
+ * help from skipcomment().
+ */
+static Linetype
+parseline(void)
+{
+ const char *cp;
+ int cursym;
+ int kwlen;
+ Linetype retval;
+ Comment_state wascomment;
+
+ linenum++;
+ if (fgets(tline, MAXLINE, input) == NULL) {
+ if (ferror(input))
+ error(strerror(errno));
+ else
+ return (LT_EOF);
+ }
+ if (newline == NULL) {
+ if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1)
+ newline = newline_crlf;
+ else
+ newline = newline_unix;
+ }
+ retval = LT_PLAIN;
+ wascomment = incomment;
+ cp = skipcomment(tline);
+ if (linestate == LS_START) {
+ if (*cp == '#') {
+ linestate = LS_HASH;
+ firstsym = true;
+ cp = skipcomment(cp + 1);
+ } else if (*cp != '\0')
+ linestate = LS_DIRTY;
+ }
+ if (!incomment && linestate == LS_HASH) {
+ keyword = tline + (cp - tline);
+ cp = skipsym(cp);
+ kwlen = cp - keyword;
+ /* no way can we deal with a continuation inside a keyword */
+ if (strncmp(cp, "\\\r\n", 3) == 0 ||
+ strncmp(cp, "\\\n", 2) == 0)
+ Eioccc();
+ if (strlcmp("ifdef", keyword, kwlen) == 0 ||
+ strlcmp("ifndef", keyword, kwlen) == 0) {
+ cp = skipcomment(cp);
+ if ((cursym = findsym(cp)) < 0)
+ retval = LT_IF;
+ else {
+ retval = (keyword[2] == 'n')
+ ? LT_FALSE : LT_TRUE;
+ if (value[cursym] == NULL)
+ retval = (retval == LT_TRUE)
+ ? LT_FALSE : LT_TRUE;
+ if (ignore[cursym])
+ retval = (retval == LT_TRUE)
+ ? LT_TRUEI : LT_FALSEI;
+ }
+ cp = skipsym(cp);
+ } else if (strlcmp("if", keyword, kwlen) == 0)
+ retval = ifeval(&cp);
+ else if (strlcmp("elif", keyword, kwlen) == 0)
+ retval = ifeval(&cp) - LT_IF + LT_ELIF;
+ else if (strlcmp("else", keyword, kwlen) == 0)
+ retval = LT_ELSE;
+ else if (strlcmp("endif", keyword, kwlen) == 0)
+ retval = LT_ENDIF;
+ else {
+ linestate = LS_DIRTY;
+ retval = LT_PLAIN;
+ }
+ cp = skipcomment(cp);
+ if (*cp != '\0') {
+ linestate = LS_DIRTY;
+ if (retval == LT_TRUE || retval == LT_FALSE ||
+ retval == LT_TRUEI || retval == LT_FALSEI)
+ retval = LT_IF;
+ if (retval == LT_ELTRUE || retval == LT_ELFALSE)
+ retval = LT_ELIF;
+ }
+ if (retval != LT_PLAIN && (wascomment || incomment)) {
+ retval += LT_DODGY;
+ if (incomment)
+ linestate = LS_DIRTY;
+ }
+ /* skipcomment normally changes the state, except
+ if the last line of the file lacks a newline, or
+ if there is too much whitespace in a directive */
+ if (linestate == LS_HASH) {
+ size_t len = cp - tline;
+ if (fgets(tline + len, MAXLINE - len, input) == NULL) {
+ if (ferror(input))
+ error(strerror(errno));
+ /* append the missing newline at eof */
+ strcpy(tline + len, newline);
+ cp += strlen(newline);
+ linestate = LS_START;
+ } else {
+ linestate = LS_DIRTY;
+ }
+ }
+ }
+ if (linestate == LS_DIRTY) {
+ while (*cp != '\0')
+ cp = skipcomment(cp + 1);
+ }
+ debug("parser line %d state %s comment %s line", linenum,
+ comment_name[incomment], linestate_name[linestate]);
+ return (retval);
+}
+
+/*
+ * These are the binary operators that are supported by the expression
+ * evaluator.
+ */
+static Linetype op_strict(int *p, int v, Linetype at, Linetype bt) {
+ if(at == LT_IF || bt == LT_IF) return (LT_IF);
+ return (*p = v, v ? LT_TRUE : LT_FALSE);
+}
+static Linetype op_lt(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a < b, at, bt);
+}
+static Linetype op_gt(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a > b, at, bt);
+}
+static Linetype op_le(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a <= b, at, bt);
+}
+static Linetype op_ge(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a >= b, at, bt);
+}
+static Linetype op_eq(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a == b, at, bt);
+}
+static Linetype op_ne(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a != b, at, bt);
+}
+static Linetype op_or(int *p, Linetype at, int a, Linetype bt, int b) {
+ if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE))
+ return (*p = 1, LT_TRUE);
+ return op_strict(p, a || b, at, bt);
+}
+static Linetype op_and(int *p, Linetype at, int a, Linetype bt, int b) {
+ if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE))
+ return (*p = 0, LT_FALSE);
+ return op_strict(p, a && b, at, bt);
+}
+
+/*
+ * An evaluation function takes three arguments, as follows: (1) a pointer to
+ * an element of the precedence table which lists the operators at the current
+ * level of precedence; (2) a pointer to an integer which will receive the
+ * value of the expression; and (3) a pointer to a char* that points to the
+ * expression to be evaluated and that is updated to the end of the expression
+ * when evaluation is complete. The function returns LT_FALSE if the value of
+ * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression
+ * depends on an unknown symbol, or LT_ERROR if there is a parse failure.
+ */
+struct ops;
+
+typedef Linetype eval_fn(const struct ops *, int *, const char **);
+
+static eval_fn eval_table, eval_unary;
+
+/*
+ * The precedence table. Expressions involving binary operators are evaluated
+ * in a table-driven way by eval_table. When it evaluates a subexpression it
+ * calls the inner function with its first argument pointing to the next
+ * element of the table. Innermost expressions have special non-table-driven
+ * handling.
+ */
+static const struct ops {
+ eval_fn *inner;
+ struct op {
+ const char *str;
+ Linetype (*fn)(int *, Linetype, int, Linetype, int);
+ } op[5];
+} eval_ops[] = {
+ { eval_table, { { "||", op_or } } },
+ { eval_table, { { "&&", op_and } } },
+ { eval_table, { { "==", op_eq },
+ { "!=", op_ne } } },
+ { eval_unary, { { "<=", op_le },
+ { ">=", op_ge },
+ { "<", op_lt },
+ { ">", op_gt } } }
+};
+
+/*
+ * Function for evaluating the innermost parts of expressions,
+ * viz. !expr (expr) number defined(symbol) symbol
+ * We reset the constexpr flag in the last two cases.
+ */
+static Linetype
+eval_unary(const struct ops *ops, int *valp, const char **cpp)
+{
+ const char *cp;
+ char *ep;
+ int sym;
+ bool defparen;
+ Linetype lt;
+
+ cp = skipcomment(*cpp);
+ if (*cp == '!') {
+ debug("eval%d !", ops - eval_ops);
+ cp++;
+ lt = eval_unary(ops, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ if (lt != LT_IF) {
+ *valp = !*valp;
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ }
+ } else if (*cp == '(') {
+ cp++;
+ debug("eval%d (", ops - eval_ops);
+ lt = eval_table(eval_ops, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ cp = skipcomment(cp);
+ if (*cp++ != ')')
+ return (LT_ERROR);
+ } else if (isdigit((unsigned char)*cp)) {
+ debug("eval%d number", ops - eval_ops);
+ *valp = strtol(cp, &ep, 0);
+ if (ep == cp)
+ return (LT_ERROR);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ cp = skipsym(cp);
+ } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
+ cp = skipcomment(cp+7);
+ debug("eval%d defined", ops - eval_ops);
+ if (*cp == '(') {
+ cp = skipcomment(cp+1);
+ defparen = true;
+ } else {
+ defparen = false;
+ }
+ sym = findsym(cp);
+ if (sym < 0) {
+ lt = LT_IF;
+ } else {
+ *valp = (value[sym] != NULL);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ }
+ cp = skipsym(cp);
+ cp = skipcomment(cp);
+ if (defparen && *cp++ != ')')
+ return (LT_ERROR);
+ constexpr = false;
+ } else if (!endsym(*cp)) {
+ debug("eval%d symbol", ops - eval_ops);
+ sym = findsym(cp);
+ cp = skipsym(cp);
+ if (sym < 0) {
+ lt = LT_IF;
+ cp = skipargs(cp);
+ } else if (value[sym] == NULL) {
+ *valp = 0;
+ lt = LT_FALSE;
+ } else {
+ *valp = strtol(value[sym], &ep, 0);
+ if (*ep != '\0' || ep == value[sym])
+ return (LT_ERROR);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ cp = skipargs(cp);
+ }
+ constexpr = false;
+ } else {
+ debug("eval%d bad expr", ops - eval_ops);
+ return (LT_ERROR);
+ }
+
+ *cpp = cp;
+ debug("eval%d = %d", ops - eval_ops, *valp);
+ return (lt);
+}
+
+/*
+ * Table-driven evaluation of binary operators.
+ */
+static Linetype
+eval_table(const struct ops *ops, int *valp, const char **cpp)
+{
+ const struct op *op;
+ const char *cp;
+ int val;
+ Linetype lt, rt;
+
+ debug("eval%d", ops - eval_ops);
+ cp = *cpp;
+ lt = ops->inner(ops+1, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ for (;;) {
+ cp = skipcomment(cp);
+ for (op = ops->op; op->str != NULL; op++)
+ if (strncmp(cp, op->str, strlen(op->str)) == 0)
+ break;
+ if (op->str == NULL)
+ break;
+ cp += strlen(op->str);
+ debug("eval%d %s", ops - eval_ops, op->str);
+ rt = ops->inner(ops+1, &val, &cp);
+ if (rt == LT_ERROR)
+ return (LT_ERROR);
+ lt = op->fn(valp, lt, *valp, rt, val);
+ }
+
+ *cpp = cp;
+ debug("eval%d = %d", ops - eval_ops, *valp);
+ debug("eval%d lt = %s", ops - eval_ops, linetype_name[lt]);
+ return (lt);
+}
+
+/*
+ * Evaluate the expression on a #if or #elif line. If we can work out
+ * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we
+ * return just a generic LT_IF.
+ */
+static Linetype
+ifeval(const char **cpp)
+{
+ int ret;
+ int val = 0;
+
+ debug("eval %s", *cpp);
+ constexpr = killconsts ? false : true;
+ ret = eval_table(eval_ops, &val, cpp);
+ debug("eval = %d", val);
+ return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret);
+}
+
+/*
+ * Skip over comments, strings, and character literals and stop at the
+ * next character position that is not whitespace. Between calls we keep
+ * the comment state in the global variable incomment, and we also adjust
+ * the global variable linestate when we see a newline.
+ * XXX: doesn't cope with the buffer splitting inside a state transition.
+ */
+static const char *
+skipcomment(const char *cp)
+{
+ if (text || ignoring[depth]) {
+ for (; isspace((unsigned char)*cp); cp++)
+ if (*cp == '\n')
+ linestate = LS_START;
+ return (cp);
+ }
+ while (*cp != '\0')
+ /* don't reset to LS_START after a line continuation */
+ if (strncmp(cp, "\\\r\n", 3) == 0)
+ cp += 3;
+ else if (strncmp(cp, "\\\n", 2) == 0)
+ cp += 2;
+ else switch (incomment) {
+ case NO_COMMENT:
+ if (strncmp(cp, "/\\\r\n", 4) == 0) {
+ incomment = STARTING_COMMENT;
+ cp += 4;
+ } else if (strncmp(cp, "/\\\n", 3) == 0) {
+ incomment = STARTING_COMMENT;
+ cp += 3;
+ } else if (strncmp(cp, "/*", 2) == 0) {
+ incomment = C_COMMENT;
+ cp += 2;
+ } else if (strncmp(cp, "//", 2) == 0) {
+ incomment = CXX_COMMENT;
+ cp += 2;
+ } else if (strncmp(cp, "\'", 1) == 0) {
+ incomment = CHAR_LITERAL;
+ linestate = LS_DIRTY;
+ cp += 1;
+ } else if (strncmp(cp, "\"", 1) == 0) {
+ incomment = STRING_LITERAL;
+ linestate = LS_DIRTY;
+ cp += 1;
+ } else if (strncmp(cp, "\n", 1) == 0) {
+ linestate = LS_START;
+ cp += 1;
+ } else if (strchr(" \r\t", *cp) != NULL) {
+ cp += 1;
+ } else
+ return (cp);
+ continue;
+ case CXX_COMMENT:
+ if (strncmp(cp, "\n", 1) == 0) {
+ incomment = NO_COMMENT;
+ linestate = LS_START;
+ }
+ cp += 1;
+ continue;
+ case CHAR_LITERAL:
+ case STRING_LITERAL:
+ if ((incomment == CHAR_LITERAL && cp[0] == '\'') ||
+ (incomment == STRING_LITERAL && cp[0] == '\"')) {
+ incomment = NO_COMMENT;
+ cp += 1;
+ } else if (cp[0] == '\\') {
+ if (cp[1] == '\0')
+ cp += 1;
+ else
+ cp += 2;
+ } else if (strncmp(cp, "\n", 1) == 0) {
+ if (incomment == CHAR_LITERAL)
+ error("unterminated char literal");
+ else
+ error("unterminated string literal");
+ } else
+ cp += 1;
+ continue;
+ case C_COMMENT:
+ if (strncmp(cp, "*\\\r\n", 4) == 0) {
+ incomment = FINISHING_COMMENT;
+ cp += 4;
+ } else if (strncmp(cp, "*\\\n", 3) == 0) {
+ incomment = FINISHING_COMMENT;
+ cp += 3;
+ } else if (strncmp(cp, "*/", 2) == 0) {
+ incomment = NO_COMMENT;
+ cp += 2;
+ } else
+ cp += 1;
+ continue;
+ case STARTING_COMMENT:
+ if (*cp == '*') {
+ incomment = C_COMMENT;
+ cp += 1;
+ } else if (*cp == '/') {
+ incomment = CXX_COMMENT;
+ cp += 1;
+ } else {
+ incomment = NO_COMMENT;
+ linestate = LS_DIRTY;
+ }
+ continue;
+ case FINISHING_COMMENT:
+ if (*cp == '/') {
+ incomment = NO_COMMENT;
+ cp += 1;
+ } else
+ incomment = C_COMMENT;
+ continue;
+ default:
+ abort(); /* bug */
+ }
+ return (cp);
+}
+
+/*
+ * Skip macro arguments.
+ */
+static const char *
+skipargs(const char *cp)
+{
+ const char *ocp = cp;
+ int level = 0;
+ cp = skipcomment(cp);
+ if (*cp != '(')
+ return (cp);
+ do {
+ if (*cp == '(')
+ level++;
+ if (*cp == ')')
+ level--;
+ cp = skipcomment(cp+1);
+ } while (level != 0 && *cp != '\0');
+ if (level == 0)
+ return (cp);
+ else
+ /* Rewind and re-detect the syntax error later. */
+ return (ocp);
+}
+
+/*
+ * Skip over an identifier.
+ */
+static const char *
+skipsym(const char *cp)
+{
+ while (!endsym(*cp))
+ ++cp;
+ return (cp);
+}
+
+/*
+ * Look for the symbol in the symbol table. If it is found, we return
+ * the symbol table index, else we return -1.
+ */
+static int
+findsym(const char *str)
+{
+ const char *cp;
+ int symind;
+
+ cp = skipsym(str);
+ if (cp == str)
+ return (-1);
+ if (symlist) {
+ if (symdepth && firstsym)
+ printf("%s%3d", zerosyms ? "" : "\n", depth);
+ firstsym = zerosyms = false;
+ printf("%s%.*s%s",
+ symdepth ? " " : "",
+ (int)(cp-str), str,
+ symdepth ? "" : "\n");
+ /* we don't care about the value of the symbol */
+ return (0);
+ }
+ for (symind = 0; symind < nsyms; ++symind) {
+ if (strlcmp(symname[symind], str, cp-str) == 0) {
+ debug("findsym %s %s", symname[symind],
+ value[symind] ? value[symind] : "");
+ return (symind);
+ }
+ }
+ return (-1);
+}
+
+/*
+ * Add a symbol to the symbol table.
+ */
+static void
+addsym(bool ignorethis, bool definethis, char *sym)
+{
+ int symind;
+ char *val;
+
+ symind = findsym(sym);
+ if (symind < 0) {
+ if (nsyms >= MAXSYMS)
+ errx(2, "too many symbols");
+ symind = nsyms++;
+ }
+ symname[symind] = sym;
+ ignore[symind] = ignorethis;
+ val = sym + (skipsym(sym) - sym);
+ if (definethis) {
+ if (*val == '=') {
+ value[symind] = val+1;
+ *val = '\0';
+ } else if (*val == '\0')
+ value[symind] = "1";
+ else
+ usage();
+ } else {
+ if (*val != '\0')
+ usage();
+ value[symind] = NULL;
+ }
+ debug("addsym %s=%s", symname[symind],
+ value[symind] ? value[symind] : "undef");
+}
+
+/*
+ * Compare s with n characters of t.
+ * The same as strncmp() except that it checks that s[n] == '\0'.
+ */
+static int
+strlcmp(const char *s, const char *t, size_t n)
+{
+ while (n-- && *t != '\0')
+ if (*s != *t)
+ return ((unsigned char)*s - (unsigned char)*t);
+ else
+ ++s, ++t;
+ return ((unsigned char)*s);
+}
+
+/*
+ * Diagnostics.
+ */
+static void
+debug(const char *msg, ...)
+{
+ va_list ap;
+
+ if (debugging) {
+ va_start(ap, msg);
+ vwarnx(msg, ap);
+ va_end(ap);
+ }
+}
+
+static void
+error(const char *msg)
+{
+ if (depth == 0)
+ warnx("%s: %d: %s", filename, linenum, msg);
+ else
+ warnx("%s: %d: %s (#if line %d depth %d)",
+ filename, linenum, msg, stifline[depth], depth);
+ closeout();
+ errx(2, "output may be truncated");
+}
diff --git a/developer_cmds/unifdef/unifdefall.sh b/developer_cmds/unifdef/unifdefall.sh
new file mode 100644
index 0000000..6d6165a
--- /dev/null
+++ b/developer_cmds/unifdef/unifdefall.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+#
+# unifdefall: remove all the #if's from a source file
+#
+# Copyright (c) 2002 - 2010 Tony Finch <dot@dotat.at>
+# Copyright (c) 2009 - 2010 Jonathan Nieder <jrnieder@gmail.com>
+#
+# 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 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD: src/usr.bin/unifdef/unifdefall.sh,v 1.7 2010/03/12 17:55:29 fanf Exp $
+
+set -e
+
+unifdef="$(dirname "$0")/unifdef"
+if [ ! -e "$unifdef" ]
+then
+ unifdef=unifdef
+fi
+
+case "$@" in
+"-d "*) echo DEBUGGING 1>&2
+ debug=-d
+ shift
+esac
+
+basename=$(basename "$0")
+tmp=$(mktemp -d "${TMPDIR:-/tmp}/$basename.XXXXXXXXXX") || exit 2
+trap 'rm -r "$tmp" || exit 2' EXIT
+
+export LC_ALL=C
+
+# list of all controlling macros
+"$unifdef" $debug -s "$@" | sort | uniq >"$tmp/ctrl"
+# list of all macro definitions
+cpp -dM "$@" | sort | sed 's/^#define //' >"$tmp/hashdefs"
+# list of defined macro names
+sed 's/[^A-Za-z0-9_].*$//' <"$tmp/hashdefs" >"$tmp/alldef"
+# list of undefined and defined controlling macros
+comm -23 "$tmp/ctrl" "$tmp/alldef" >"$tmp/undef"
+comm -12 "$tmp/ctrl" "$tmp/alldef" >"$tmp/def"
+# create a sed script that extracts the controlling macro definitions
+# and converts them to unifdef command-line arguments
+sed 's|.*|s/^&\\(([^)]*)\\)\\{0,1\\} /-D&=/p|' <"$tmp/def" >"$tmp/script"
+# create the final unifdef command
+{ echo "$unifdef" $debug -k '\'
+ # convert the controlling undefined macros to -U arguments
+ sed 's/.*/-U& \\/' <"$tmp/undef"
+ # convert the controlling defined macros to quoted -D arguments
+ sed -nf "$tmp/script" <"$tmp/hashdefs" |
+ sed "s/'/'\\\\''/g;s/.*/'&' \\\\/"
+ echo '"$@"'
+} >"$tmp/cmd"
+case $debug in
+-d) for i in ctrl hashdefs alldef undef def script cmd
+ do echo ==== $i
+ cat "$tmp/$i"
+ done 1>&2
+esac
+# run the command we just created
+sh "$tmp/cmd" "$@"
diff --git a/developer_cmds/xcodescripts/install-lorder.sh b/developer_cmds/xcodescripts/install-lorder.sh
new file mode 100644
index 0000000..8da52b7
--- /dev/null
+++ b/developer_cmds/xcodescripts/install-lorder.sh
@@ -0,0 +1,7 @@
+set -ex
+
+BINDIR="$DSTROOT"/"$DT_TOOLCHAIN_DIR"/usr/bin
+
+install -c -o root -g wheel -m 0755 \
+ "$PROJECT_DIR"/lorder/lorder.sh \
+ "$BINDIR"/lorder
diff --git a/developer_cmds/xcodescripts/install-unifdefall.sh b/developer_cmds/xcodescripts/install-unifdefall.sh
new file mode 100644
index 0000000..7424b3f
--- /dev/null
+++ b/developer_cmds/xcodescripts/install-unifdefall.sh
@@ -0,0 +1,9 @@
+set -e -x
+
+BINDIR="$DSTROOT"/"$DT_TOOLCHAIN_DIR"/usr/bin
+MANDIR="$DSTROOT"/"$DT_TOOLCHAIN_DIR"/usr/share/man/man1
+
+ln -f "$MANDIR"/unifdef.1 "$MANDIR"/unifdefall.1
+install -c -o root -g wheel -m 0755 \
+ "$PROJECT_DIR"/unifdef/unifdefall.sh \
+ "$BINDIR"/unifdefall
diff --git a/diskdev_cmds/APPLE_LICENSE b/diskdev_cmds/APPLE_LICENSE
new file mode 100644
index 0000000..fe81a60
--- /dev/null
+++ b/diskdev_cmds/APPLE_LICENSE
@@ -0,0 +1,367 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 2.0 - August 6, 2003
+
+Please read this License carefully before downloading this software.
+By downloading or using this software, you are agreeing to be bound by
+the terms of this License. If you do not or cannot agree to the terms
+of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+work which Apple Computer, Inc. ("Apple") makes publicly available and
+which contains a notice placed by Apple identifying such program or
+work as "Original Code" and stating that it is subject to the terms of
+this Apple Public Source License version 2.0 ("License"). As used in
+this License:
+
+1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is
+the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to Apple and (ii) that cover subject
+matter contained in the Original Code, but only to the extent
+necessary to use, reproduce and/or distribute the Original Code
+without infringement; and (b) in the case where You are the grantor of
+rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to You and (ii) that cover subject matter in Your
+Modifications, taken alone or in combination with Original Code.
+
+1.2 "Contributor" means any person or entity that creates or
+contributes to the creation of Modifications.
+
+1.3 "Covered Code" means the Original Code, Modifications, the
+combination of Original Code and any Modifications, and/or any
+respective portions thereof.
+
+1.4 "Externally Deploy" means: (a) to sublicense, distribute or
+otherwise make Covered Code available, directly or indirectly, to
+anyone other than You; and/or (b) to use Covered Code, alone or as
+part of a Larger Work, in any way to provide a service, including but
+not limited to delivery of content, through electronic communication
+with a client other than You.
+
+1.5 "Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6 "Modifications" mean any addition to, deletion from, and/or change
+to, the substance and/or structure of the Original Code, any previous
+Modifications, the combination of Original Code and any previous
+Modifications, and/or any respective portions thereof. When code is
+released as a series of files, a Modification is: (a) any addition to
+or deletion from the contents of a file containing Covered Code;
+and/or (b) any new file or other representation of computer program
+statements that contains any part of Covered Code.
+
+1.7 "Original Code" means (a) the Source Code of a program or other
+work as originally made available by Apple under this License,
+including the Source Code of any updates or upgrades to such programs
+or works made available by Apple under this License, and that has been
+expressly identified by Apple as such in the header file(s) of such
+work; and (b) the object code compiled from such Source Code and
+originally made available by Apple under this License.
+
+1.8 "Source Code" means the human readable form of a program or other
+work that is suitable for making modifications to it, including all
+modules it contains, plus any associated interface definition files,
+scripts used to control compilation and installation of an executable
+(object code).
+
+1.9 "You" or "Your" means an individual or a legal entity exercising
+rights under this License. For legal entities, "You" or "Your"
+includes any entity which controls, is controlled by, or is under
+common control with, You, where "control" means (a) the power, direct
+or indirect, to cause the direction or management of such entity,
+whether by contract or otherwise, or (b) ownership of fifty percent
+(50%) or more of the outstanding shares or beneficial ownership of
+such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+and conditions of this License, Apple hereby grants You, effective on
+the date You accept this License and download the Original Code, a
+world-wide, royalty-free, non-exclusive license, to the extent of
+Apple's Applicable Patent Rights and copyrights covering the Original
+Code, to do the following:
+
+2.1 Unmodified Code. You may use, reproduce, display, perform,
+internally distribute within Your organization, and Externally Deploy
+verbatim, unmodified copies of the Original Code, for commercial or
+non-commercial purposes, provided that in each instance:
+
+(a) You must retain and reproduce in all copies of Original Code the
+copyright and other proprietary notices and disclaimers of Apple as
+they appear in the Original Code, and keep intact all notices in the
+Original Code that refer to this License; and
+
+(b) You must include a copy of this License with every copy of Source
+Code of Covered Code and documentation You distribute or Externally
+Deploy, and You may not offer or impose any terms on such Source Code
+that alter or restrict this License or the recipients' rights
+hereunder, except as permitted under Section 6.
+
+2.2 Modified Code. You may modify Covered Code and use, reproduce,
+display, perform, internally distribute within Your organization, and
+Externally Deploy Your Modifications and Covered Code, for commercial
+or non-commercial purposes, provided that in each instance You also
+meet all of these conditions:
+
+(a) You must satisfy all the conditions of Section 2.1 with respect to
+the Source Code of the Covered Code;
+
+(b) You must duplicate, to the extent it does not already exist, the
+notice in Exhibit A in each file of the Source Code of all Your
+Modifications, and cause the modified files to carry prominent notices
+stating that You changed the files and the date of any change; and
+
+(c) If You Externally Deploy Your Modifications, You must make
+Source Code of all Your Externally Deployed Modifications either
+available to those to whom You have Externally Deployed Your
+Modifications, or publicly available. Source Code of Your Externally
+Deployed Modifications must be released under the terms set forth in
+this License, including the license grants set forth in Section 3
+below, for as long as you Externally Deploy the Covered Code or twelve
+(12) months from the date of initial External Deployment, whichever is
+longer. You should preferably distribute the Source Code of Your
+Externally Deployed Modifications electronically (e.g. download from a
+web site).
+
+2.3 Distribution of Executable Versions. In addition, if You
+Externally Deploy Covered Code (Original Code and/or Modifications) in
+object code, executable form only, You must include a prominent
+notice, in the code itself as well as in related documentation,
+stating that Source Code of the Covered Code is available under the
+terms of this License with information on how and where to obtain such
+Source Code.
+
+2.4 Third Party Rights. You expressly acknowledge and agree that
+although Apple and each Contributor grants the licenses to their
+respective portions of the Covered Code set forth herein, no
+assurances are provided by Apple or any Contributor that the Covered
+Code does not infringe the patent or other intellectual property
+rights of any other entity. Apple and each Contributor disclaim any
+liability to You for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a
+condition to exercising the rights and licenses granted hereunder, You
+hereby assume sole responsibility to secure any other intellectual
+property rights needed, if any. For example, if a third party patent
+license is required to allow You to distribute the Covered Code, it is
+Your responsibility to acquire that license before distributing the
+Covered Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+licenses granted to You under this License, You hereby grant to any
+person or entity receiving or distributing Covered Code under this
+License a non-exclusive, royalty-free, perpetual, irrevocable license,
+under Your Applicable Patent Rights and other intellectual property
+rights (other than patent) owned or controlled by You, to use,
+reproduce, display, perform, modify, sublicense, distribute and
+Externally Deploy Your Modifications of the same scope and extent as
+Apple's licenses under Sections 2.1 and 2.2 above.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+Code with other code not governed by the terms of this License and
+distribute the Larger Work as a single product. In each such instance,
+You must make sure the requirements of this License are fulfilled for
+the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+Section 2, no other patent rights, express or implied, are granted by
+Apple herein. Modifications and/or Larger Works may require additional
+patent licenses from Apple which Apple may grant in its sole
+discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee for,
+warranty, support, indemnity or liability obligations and/or other
+rights consistent with the scope of the license granted herein
+("Additional Terms") to one or more recipients of Covered Code.
+However, You may do so only on Your own behalf and as Your sole
+responsibility, and not on behalf of Apple or any Contributor. You
+must obtain the recipient's agreement that any such Additional Terms
+are offered by You alone, and You hereby agree to indemnify, defend
+and hold Apple and every Contributor harmless for any liability
+incurred by or claims asserted against Apple or such Contributor by
+reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+versions of this License from time to time. Each version will be given
+a distinguishing version number. Once Original Code has been published
+under a particular version of this License, You may continue to use it
+under the terms of that version. You may also choose to use such
+Original Code under the terms of any subsequent version of this
+License published by Apple. No one other than Apple has the right to
+modify the terms applicable to Covered Code created under this
+License.
+
+8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in
+part pre-release, untested, or not fully tested works. The Covered
+Code may contain errors that could cause failures or loss of data, and
+may be incomplete or contain inaccuracies. You expressly acknowledge
+and agree that use of the Covered Code, or any portion thereof, is at
+Your sole and entire risk. THE COVERED CODE IS PROVIDED "AS IS" AND
+WITHOUT WARRANTY, UPGRADES OR SUPPORT OF ANY KIND AND APPLE AND
+APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" FOR THE
+PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
+ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF
+MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR
+PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD
+PARTY RIGHTS. APPLE AND EACH CONTRIBUTOR DOES NOT WARRANT AGAINST
+INTERFERENCE WITH YOUR ENJOYMENT OF THE COVERED CODE, THAT THE
+FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR REQUIREMENTS,
+THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
+ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO
+ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE
+AUTHORIZED REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.
+You acknowledge that the Covered Code is not intended for use in the
+operation of nuclear facilities, aircraft navigation, communication
+systems, or air traffic control machines in which case the failure of
+the Covered Code could lead to death, personal injury, or severe
+physical or environmental damage.
+
+9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
+EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL,
+SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING
+TO THIS LICENSE OR YOUR USE OR INABILITY TO USE THE COVERED CODE, OR
+ANY PORTION THEREOF, WHETHER UNDER A THEORY OF CONTRACT, WARRANTY,
+TORT (INCLUDING NEGLIGENCE), PRODUCTS LIABILITY OR OTHERWISE, EVEN IF
+APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL PURPOSE OF ANY
+REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF LIABILITY OF
+INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT APPLY
+TO YOU. In no event shall Apple's total liability to You for all
+damages (other than as may be required by applicable law) under this
+License exceed the amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+trademarks or trade names "Apple", "Apple Computer", "Mac", "Mac OS",
+"QuickTime", "QuickTime Streaming Server" or any other trademarks,
+service marks, logos or trade names belonging to Apple (collectively
+"Apple Marks") or to any trademark, service mark, logo or trade name
+belonging to any Contributor. You agree not to use any Apple Marks in
+or as part of the name of products derived from the Original Code or
+to endorse or promote products derived from the Original Code other
+than as expressly permitted by and in strict compliance at all times
+with Apple's third party trademark usage guidelines which are posted
+at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Subject to the licenses granted under this License,
+each Contributor retains all rights, title and interest in and to any
+Modifications made by such Contributor. Apple retains all rights,
+title and interest in and to the Original Code and any Modifications
+made by or on behalf of Apple ("Apple Modifications"), and such Apple
+Modifications will not be automatically subject to this License. Apple
+may, at its sole discretion, choose to license such Apple
+Modifications under this License, or on different terms from those
+contained in this License or may choose not to license them at all.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach;
+
+(b) immediately in the event of the circumstances described in Section
+13.5(b); or
+
+(c) automatically without notice from Apple if You, at any time during
+the term of this License, commence an action for patent infringement
+against Apple; provided that Apple did not first commence
+an action for patent infringement against You in that instance.
+
+12.2 Effect of Termination. Upon termination, You agree to immediately
+stop any further use, reproduction, modification, sublicensing and
+distribution of the Covered Code. All sublicenses to the Covered Code
+which have been properly granted prior to termination shall survive
+any termination of this License. Provisions which, by their nature,
+should remain in effect beyond the termination of this License shall
+survive, including but not limited to Sections 3, 5, 8, 9, 10, 11,
+12.2 and 13. No party will be liable to any other for compensation,
+indemnity or damages of any sort solely as a result of terminating
+this License in accordance with its terms, and termination of this
+License will be without prejudice to any other right or remedy of
+any party.
+
+13. Miscellaneous.
+
+13.1 Government End Users. The Covered Code is a "commercial item" as
+defined in FAR 2.101. Government software and technical data rights in
+the Covered Code include only those rights customarily provided to the
+public as defined in this License. This customary commercial license
+in technical data and software is provided in accordance with FAR
+12.211 (Technical Data) and 12.212 (Computer Software) and, for
+Department of Defense purchases, DFAR 252.227-7015 (Technical Data --
+Commercial Items) and 227.7202-3 (Rights in Commercial Computer
+Software or Computer Software Documentation). Accordingly, all U.S.
+Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2 Relationship of Parties. This License will not be construed as
+creating an agency, partnership, joint venture or any other form of
+legal association between or among You, Apple or any Contributor, and
+You will not represent to the contrary, whether expressly, by
+implication, appearance or otherwise.
+
+13.3 Independent Development. Nothing in this License will impair
+Apple's right to acquire, license, develop, have others develop for
+it, market and/or distribute technology or products that perform the
+same or similar functions as, or otherwise compete with,
+Modifications, Larger Works, technology or products that You may
+develop, produce, market or distribute.
+
+13.4 Waiver; Construction. Failure by Apple or any Contributor to
+enforce any provision of this License will not be deemed a waiver of
+future enforcement of that or any other provision. Any law or
+regulation which provides that the language of a contract shall be
+construed against the drafter will not apply to this License.
+
+13.5 Severability. (a) If for any reason a court of competent
+jurisdiction finds any provision of this License, or portion thereof,
+to be unenforceable, that provision of the License will be enforced to
+the maximum extent permissible so as to effect the economic benefits
+and intent of the parties, and the remainder of this License will
+continue in full force and effect. (b) Notwithstanding the foregoing,
+if applicable law prohibits or restricts You from fully and/or
+specifically complying with Sections 2 and/or 3 or prevents the
+enforceability of either of those Sections, this License will
+immediately terminate and You must immediately discontinue any use of
+the Covered Code and destroy all copies of it that are in your
+possession or control.
+
+13.6 Dispute Resolution. Any litigation or other dispute resolution
+between You and Apple relating to this License shall take place in the
+Northern District of California, and You and Apple hereby consent to
+the personal jurisdiction of, and venue in, the state and federal
+courts within that District with respect to this License. The
+application of the United Nations Convention on Contracts for the
+International Sale of Goods is expressly excluded.
+
+13.7 Entire Agreement; Governing Law. This License constitutes the
+entire agreement between the parties with respect to the subject
+matter hereof. This License shall be governed by the laws of the
+United States and the State of California, except that body of
+California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999-2003 Apple Computer, Inc. All Rights
+Reserved.
+
+This file contains Original Code and/or Modifications of Original Code
+as defined in and that are subject to the Apple Public Source License
+Version 2.0 (the 'License'). You may not use this file except in
+compliance with the License. Please obtain a copy of the License at
+http://www.opensource.apple.com/apsl/ and read it before using this
+file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+Please see the License for the specific language governing rights and
+limitations under the License."
diff --git a/diskdev_cmds/dev_mkdb.tproj/dev_mkdb.8 b/diskdev_cmds/dev_mkdb.tproj/dev_mkdb.8
new file mode 100644
index 0000000..9369b2b
--- /dev/null
+++ b/diskdev_cmds/dev_mkdb.tproj/dev_mkdb.8
@@ -0,0 +1,81 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)dev_mkdb.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Os
+.Dt DEV_MKDB 8
+.Sh NAME
+.Nm dev_mkdb
+.Nd create
+.Pa /dev
+database
+.Sh SYNOPSIS
+.Nm dev_mkdb
+.Sh DESCRIPTION
+The
+.Nm dev_mkdb
+command creates a
+.Xr db 3
+hash access method database in
+.Dq Pa /var/run/dev.db
+which contains the names of all of the character and block special
+files in the
+.Dq Pa /dev
+directory, using the file type and the
+.Fa st_rdev
+field as the key.
+.Pp
+Keys are a structure containing a mode_t followed by a dev_t,
+with any padding zero'd out.
+The former is the type of the file (st_mode & S_IFMT),
+the latter is the st_rdev field.
+.Sh FILES
+.Bl -tag -width /var/run/dev.db -compact
+.It Pa /dev
+Device directory.
+.It Pa /var/run/dev.db
+Database file.
+.El
+.Sh SEE ALSO
+.Xr ps 1 ,
+.Xr stat 2 ,
+.Xr db 3 ,
+.Xr devname 3 ,
+.Xr kvm_nlist 3 ,
+.Xr ttyname 3 ,
+.Xr kvm_mkdb 8
+.Sh HISTORY
+The
+.Nm dev_mkdb
+command appeared in
+.Bx 4.4 .
diff --git a/diskdev_cmds/dev_mkdb.tproj/dev_mkdb.c b/diskdev_cmds/dev_mkdb.tproj/dev_mkdb.c
new file mode 100644
index 0000000..82c7429
--- /dev/null
+++ b/diskdev_cmds/dev_mkdb.tproj/dev_mkdb.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/******
+static char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+******/
+
+/******
+static char sccsid[] = "@(#)dev_mkdb.c 8.1 (Berkeley) 6/6/93";
+******/
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#undef DIRBLKSIZ
+#include <dirent.h>
+#include <nlist.h>
+#include <db.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+
+void err __P((const char *, ...));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register DIR *dirp;
+ register struct dirent *dp;
+ struct stat sb;
+ struct {
+ mode_t type;
+ dev_t dev;
+ } bkey;
+ DB *db;
+ DBT data, key;
+ int ch;
+ u_char buf[MAXNAMLEN + 1];
+ char dbtmp[MAXPATHLEN + 1], dbname[MAXPATHLEN + 1];
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch((char)ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ usage();
+
+ if (chdir(_PATH_DEV))
+ err("%s: %s", _PATH_DEV, strerror(errno));
+
+ dirp = opendir(".");
+
+ (void)snprintf(dbtmp, sizeof(dbtmp), "%sdev.tmp", _PATH_VARRUN);
+ (void)snprintf(dbname, sizeof(dbtmp), "%sdev.db", _PATH_VARRUN);
+ db = dbopen(dbtmp, O_CREAT|O_EXLOCK|O_RDWR|O_TRUNC,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, DB_HASH, NULL);
+ if (db == NULL)
+ err("%s: %s", dbtmp, strerror(errno));
+
+ /*
+ * Keys are a mode_t followed by a dev_t. The former is the type of
+ * the file (mode & S_IFMT), the latter is the st_rdev field. Note
+ * that the structure may contain padding, so we have to clear it
+ * out here.
+ */
+ bzero(&bkey, sizeof(bkey));
+ key.data = &bkey;
+ key.size = sizeof(bkey);
+ data.data = buf;
+ while ((dp = readdir(dirp))) {
+ if (lstat(dp->d_name, &sb)) {
+ (void)fprintf(stderr,
+ "dev_mkdb: %s: %s\n", dp->d_name, strerror(errno));
+ continue;
+ }
+
+ /* Create the key. */
+ if (S_ISCHR(sb.st_mode))
+ bkey.type = S_IFCHR;
+ else if (S_ISBLK(sb.st_mode))
+ bkey.type = S_IFBLK;
+ else
+ continue;
+ bkey.dev = sb.st_rdev;
+
+ /*
+ * Create the data; nul terminate the name so caller doesn't
+ * have to.
+ */
+ bcopy(dp->d_name, buf, dp->d_namlen);
+ buf[dp->d_namlen] = '\0';
+ data.size = dp->d_namlen + 1;
+ if ((db->put)(db, &key, &data, 0))
+ err("dbput %s: %s\n", dbtmp, strerror(errno));
+ }
+ (void)(db->close)(db);
+ if (rename(dbtmp, dbname))
+ err("rename %s to %s: %s", dbtmp, dbname, strerror(errno));
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: dev_mkdb\n");
+ exit(1);
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(const char *fmt, ...)
+#else
+err(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)fprintf(stderr, "dev_mkdb: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/project.pbxproj b/diskdev_cmds/diskdev_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..ff896ee
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,2411 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 4D55934F153CE4CC009F2584 /* Common */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 4D559350153CE4CC009F2584 /* Build configuration list for PBXAggregateTarget "Common" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 4D559357153CE4EA009F2584 /* PBXTargetDependency */,
+ 4D559472153DC87B009F2584 /* PBXTargetDependency */,
+ 4D559359153CE4EC009F2584 /* PBXTargetDependency */,
+ 4D55935B153CE4ED009F2584 /* PBXTargetDependency */,
+ 4D559498153DC9E8009F2584 /* PBXTargetDependency */,
+ 4D5594A7153DCA04009F2584 /* PBXTargetDependency */,
+ 4D5594B9153DCA5E009F2584 /* PBXTargetDependency */,
+ 4D5594DF153DCC73009F2584 /* PBXTargetDependency */,
+ 4D559373153CE5F8009F2584 /* PBXTargetDependency */,
+ 4D559426153DC38F009F2584 /* PBXTargetDependency */,
+ 4D55943A153DC4C0009F2584 /* PBXTargetDependency */,
+ 4D55939C153CE83A009F2584 /* PBXTargetDependency */,
+ 4D559415153DC282009F2584 /* PBXTargetDependency */,
+ 071077D92488A09C003B97C7 /* PBXTargetDependency */,
+ );
+ name = Common;
+ productName = All;
+ };
+ 4D559440153DC57D009F2584 /* All_MacOSX */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 4D559441153DC57D009F2584 /* Build configuration list for PBXAggregateTarget "All_MacOSX" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 4D559447153DC597009F2584 /* PBXTargetDependency */,
+ B12C9C9222A7CDE300B9F497 /* PBXTargetDependency */,
+ B12C9C9422A7CDE300B9F497 /* PBXTargetDependency */,
+ B12C9C9622A7CDE300B9F497 /* PBXTargetDependency */,
+ B12C9C9822A7CDE300B9F497 /* PBXTargetDependency */,
+ B12C9C9A22A7CDE300B9F497 /* PBXTargetDependency */,
+ B12C9C9C22A7CDE300B9F497 /* PBXTargetDependency */,
+ 07747AA21DA8511D00ACE020 /* PBXTargetDependency */,
+ 4D55945C153DC665009F2584 /* PBXTargetDependency */,
+ );
+ name = All_MacOSX;
+ productName = All_MacOSX;
+ };
+ 4D559443153DC587009F2584 /* All_iOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 4D559444153DC587009F2584 /* Build configuration list for PBXAggregateTarget "All_iOS" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 4D559449153DC599009F2584 /* PBXTargetDependency */,
+ );
+ name = All_iOS;
+ productName = All_iOS;
+ };
+ 4D559514153DE116009F2584 /* quotaoff */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 4D559515153DE116009F2584 /* Build configuration list for PBXAggregateTarget "quotaoff" */;
+ buildPhases = (
+ 4D55951B153DE1EF009F2584 /* ShellScript */,
+ );
+ dependencies = (
+ 4D55951A153DE1CB009F2584 /* PBXTargetDependency */,
+ );
+ name = quotaoff;
+ productName = quotaoff;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 072AAAA62167CE8F004ED4E2 /* mount_flags.c in Sources */ = {isa = PBXBuildFile; fileRef = 072AAAA42167CE8E004ED4E2 /* mount_flags.c */; };
+ 078B970D2190682600674625 /* mount_flags.c in Sources */ = {isa = PBXBuildFile; fileRef = 072AAAA42167CE8E004ED4E2 /* mount_flags.c */; };
+ 07CE4C1821906BB800BF11C0 /* mount.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55936C153CE58E009F2584 /* mount.c */; };
+ 1A9041022091EE830061D05A /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041012091EE830061D05A /* IOKit.framework */; };
+ 1A9041042091EE910061D05A /* APFS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041032091EE910061D05A /* APFS.framework */; };
+ 1A9041062091EE980061D05A /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041052091EE980061D05A /* CoreFoundation.framework */; };
+ 4D07DD57153CA9DC002B57CB /* dkcksum.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D07DD4D153CA9DC002B57CB /* dkcksum.c */; };
+ 4D07DD58153CA9DC002B57CB /* dkdisklabel.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D07DD4E153CA9DC002B57CB /* dkdisklabel.c */; };
+ 4D07DD59153CA9DC002B57CB /* dkopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D07DD4F153CA9DC002B57CB /* dkopen.c */; };
+ 4D07DD5A153CA9DC002B57CB /* dkopen.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D07DD50153CA9DC002B57CB /* dkopen.h */; };
+ 4D07DD5B153CA9DC002B57CB /* dksecsize.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D07DD51153CA9DC002B57CB /* dksecsize.c */; };
+ 4D07DD5E153CA9DC002B57CB /* pathnames.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D07DD54153CA9DC002B57CB /* pathnames.h */; };
+ 4D07DD5F153CA9DC002B57CB /* preen.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D07DD55153CA9DC002B57CB /* preen.c */; };
+ 4D07DD60153CA9DC002B57CB /* vfslist.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D07DD56153CA9DC002B57CB /* vfslist.c */; };
+ 4D559332153CE1D9009F2584 /* auto.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55931E153CE1D9009F2584 /* auto.c */; };
+ 4D559333153CE1D9009F2584 /* cmd.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559320153CE1D9009F2584 /* cmd.c */; };
+ 4D559334153CE1D9009F2584 /* disk.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559322153CE1D9009F2584 /* disk.c */; };
+ 4D559335153CE1D9009F2584 /* fdisk.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559325153CE1D9009F2584 /* fdisk.c */; };
+ 4D559336153CE1D9009F2584 /* getrawpartition.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559326153CE1D9009F2584 /* getrawpartition.c */; };
+ 4D559337153CE1D9009F2584 /* mbr.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559327153CE1D9009F2584 /* mbr.c */; };
+ 4D559338153CE1D9009F2584 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55932A153CE1D9009F2584 /* misc.c */; };
+ 4D559339153CE1D9009F2584 /* opendev.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55932C153CE1D9009F2584 /* opendev.c */; };
+ 4D55933A153CE1D9009F2584 /* part.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55932D153CE1D9009F2584 /* part.c */; };
+ 4D55933B153CE1D9009F2584 /* user.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55932F153CE1D9009F2584 /* user.c */; };
+ 4D55933C153CE242009F2584 /* fdisk.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D559324153CE1D9009F2584 /* fdisk.8 */; };
+ 4D55934D153CE44E009F2584 /* fsck.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55934B153CE44E009F2584 /* fsck.c */; };
+ 4D55934E153CE4B1009F2584 /* fsck.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D55934A153CE44E009F2584 /* fsck.8 */; };
+ 4D55936F153CE5D6009F2584 /* fstab.5 in Copy man5 */ = {isa = PBXBuildFile; fileRef = 4D559369153CE58E009F2584 /* fstab.5 */; };
+ 4D559371153CE5EA009F2584 /* mount.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D55936B153CE58E009F2584 /* mount.8 */; };
+ 4D559389153CE794009F2584 /* libdisk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D07DD49153CA9A0002B57CB /* libdisk.a */; };
+ 4D559399153CE826009F2584 /* umount.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559398153CE826009F2584 /* umount.c */; };
+ 4D55939A153CE82E009F2584 /* umount.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D559397153CE826009F2584 /* umount.8 */; };
+ 4D55939D153CE8AF009F2584 /* libdisk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D07DD49153CA9A0002B57CB /* libdisk.a */; };
+ 4D5593B2153CEABD009F2584 /* edquota.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D5593B0153CEABD009F2584 /* edquota.c */; };
+ 4D5593C4153CEB9A009F2584 /* quota.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D5593C3153CEB9A009F2584 /* quota.c */; };
+ 4D5593C5153CEBB4009F2584 /* edquota.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D5593AF153CEABD009F2584 /* edquota.8 */; };
+ 4D5593C6153CEBC3009F2584 /* quota.1 in Copy man1 */ = {isa = PBXBuildFile; fileRef = 4D5593C2153CEB9A009F2584 /* quota.1 */; };
+ 4D5593DC153CED51009F2584 /* hfs_quotacheck.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D5593D8153CED51009F2584 /* hfs_quotacheck.c */; };
+ 4D5593DD153CED51009F2584 /* quotacheck.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D5593DA153CED51009F2584 /* quotacheck.c */; };
+ 4D5593DE153CED6A009F2584 /* quotacheck.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D5593D9153CED51009F2584 /* quotacheck.8 */; };
+ 4D5593DF153CED8D009F2584 /* libdisk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D07DD49153CA9A0002B57CB /* libdisk.a */; };
+ 4D5593EF153CEE66009F2584 /* quotaon.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D5593EE153CEE66009F2584 /* quotaon.c */; };
+ 4D5593F0153CEE74009F2584 /* quotaon.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D5593ED153CEE66009F2584 /* quotaon.8 */; };
+ 4D559403153DC13D009F2584 /* repquota.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559402153DC13D009F2584 /* repquota.c */; };
+ 4D559404153DC150009F2584 /* repquota.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D559401153DC13D009F2584 /* repquota.8 */; };
+ 4D559417153DC2AB009F2584 /* vndevice.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559416153DC2AB009F2584 /* vndevice.c */; };
+ 4D559428153DC3A6009F2584 /* mount_devfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559427153DC3A6009F2584 /* mount_devfs.c */; };
+ 4D55942B153DC427009F2584 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D55942A153DC420009F2584 /* libutil.dylib */; };
+ 4D55943D153DC4DE009F2584 /* mount_fdesc.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55943C153DC4DE009F2584 /* mount_fdesc.c */; };
+ 4D55943E153DC4E9009F2584 /* mount_fdesc.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D55943B153DC4DE009F2584 /* mount_fdesc.8 */; };
+ 4D55943F153DC534009F2584 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D55942A153DC420009F2584 /* libutil.dylib */; };
+ 4D55945A153DC650009F2584 /* vsdbutil_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559458153DC650009F2584 /* vsdbutil_main.c */; };
+ 4D55945D153DC728009F2584 /* vsdbutil.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D559459153DC650009F2584 /* vsdbutil.8 */; };
+ 4D55945F153DC735009F2584 /* com.apple.vsdbutil.plist in Copy com.apple.vsdbutil.plist */ = {isa = PBXBuildFile; fileRef = 4D559457153DC650009F2584 /* com.apple.vsdbutil.plist */; };
+ 4D55946F153DC839009F2584 /* dev_mkdb.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D55946E153DC839009F2584 /* dev_mkdb.c */; };
+ 4D559470153DC84E009F2584 /* dev_mkdb.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D55946D153DC839009F2584 /* dev_mkdb.8 */; };
+ 4D559482153DC912009F2584 /* fstyp.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559481153DC912009F2584 /* fstyp.c */; };
+ 4D559483153DC92D009F2584 /* fstyp.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D559480153DC912009F2584 /* fstyp.8 */; };
+ 4D559495153DC9AE009F2584 /* fstyp_msdos.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D559494153DC9AE009F2584 /* fstyp_msdos.c */; };
+ 4D559496153DC9BC009F2584 /* fstyp_msdos.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D559493153DC9AE009F2584 /* fstyp_msdos.8 */; };
+ 4D5594AA153DCA19009F2584 /* fstyp_ntfs.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D5594A9153DCA19009F2584 /* fstyp_ntfs.c */; };
+ 4D5594BC153DCA74009F2584 /* fstyp_udf.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D5594BB153DCA74009F2584 /* fstyp_udf.c */; };
+ 4D5594BD153DCA85009F2584 /* fstyp_udf.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D5594BA153DCA74009F2584 /* fstyp_udf.8 */; };
+ 4D5594CD153DCB72009F2584 /* setclass.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D5594CC153DCB72009F2584 /* setclass.c */; };
+ 4D5594CE153DCB82009F2584 /* setclass.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D5594CB153DCB72009F2584 /* setclass.8 */; };
+ 4D5594E2153DCCAC009F2584 /* fuser.1 in Copy man1 */ = {isa = PBXBuildFile; fileRef = 4D5594E0153DCC92009F2584 /* fuser.1 */; };
+ 4D5594E6153DCFFB009F2584 /* fstyp_ntfs.8 in Copy man8 */ = {isa = PBXBuildFile; fileRef = 4D5594A8153DCA19009F2584 /* fstyp_ntfs.8 */; };
+ 785314FF227120BD00B25661 /* MediaKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 785314FE227120BD00B25661 /* MediaKit.framework */; };
+ B19B239C21C8DF660001F35C /* edt_fstab.c in Sources */ = {isa = PBXBuildFile; fileRef = B19B239A21C8DEF90001F35C /* edt_fstab.c */; };
+ B19B239D21C8DF6E0001F35C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041012091EE830061D05A /* IOKit.framework */; };
+ B19B239E21C8DF740001F35C /* APFS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041032091EE910061D05A /* APFS.framework */; };
+ B19B239F21C8DF7B0001F35C /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041052091EE980061D05A /* CoreFoundation.framework */; };
+ B19B23A021C8DFA40001F35C /* edt_fstab.c in Sources */ = {isa = PBXBuildFile; fileRef = B19B239A21C8DEF90001F35C /* edt_fstab.c */; };
+ B19B23A221C8DFC30001F35C /* edt_fstab.c in Sources */ = {isa = PBXBuildFile; fileRef = B19B239A21C8DEF90001F35C /* edt_fstab.c */; };
+ B19B23A321C8DFCF0001F35C /* APFS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041032091EE910061D05A /* APFS.framework */; };
+ B19B23A421C8DFD50001F35C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041012091EE830061D05A /* IOKit.framework */; };
+ B19B23A521C8DFE10001F35C /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A9041052091EE980061D05A /* CoreFoundation.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 071077D82488A09C003B97C7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5594C1153DCAFC009F2584;
+ remoteInfo = setclass;
+ };
+ 07747AA11DA8511D00ACE020 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D559476153DC8FC009F2584;
+ remoteInfo = fstyp;
+ };
+ 4D559356153CE4EA009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D07DD48153CA9A0002B57CB;
+ remoteInfo = libdisk;
+ };
+ 4D559358153CE4EC009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D559314153CE198009F2584;
+ remoteInfo = fdisk;
+ };
+ 4D55935A153CE4ED009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D559340153CE41E009F2584;
+ remoteInfo = fsck;
+ };
+ 4D559372153CE5F8009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55935F153CE561009F2584;
+ remoteInfo = mount;
+ };
+ 4D55939B153CE83A009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55938D153CE7FD009F2584;
+ remoteInfo = umount;
+ };
+ 4D55939E153CE8B6009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D07DD48153CA9A0002B57CB;
+ remoteInfo = libdisk;
+ };
+ 4D5593A0153CE8BC009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D07DD48153CA9A0002B57CB;
+ remoteInfo = libdisk;
+ };
+ 4D559414153DC282009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55940A153DC27A009F2584;
+ remoteInfo = vndevice;
+ };
+ 4D559425153DC38F009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55941B153DC383009F2584;
+ remoteInfo = mount_devfs;
+ };
+ 4D559439153DC4C0009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55942F153DC49A009F2584;
+ remoteInfo = mount_fdesc;
+ };
+ 4D559446153DC597009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55934F153CE4CC009F2584;
+ remoteInfo = Common;
+ };
+ 4D559448153DC599009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55934F153CE4CC009F2584;
+ remoteInfo = Common;
+ };
+ 4D55945B153DC665009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55944D153DC634009F2584;
+ remoteInfo = vsdbutil;
+ };
+ 4D559471153DC87B009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D559463153DC808009F2584;
+ remoteInfo = dev_mkdb;
+ };
+ 4D559497153DC9E8009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D559489153DC98D009F2584;
+ remoteInfo = fstyp_msdos;
+ };
+ 4D5594A6153DCA04009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D55949C153DC9FB009F2584;
+ remoteInfo = fstyp_ntfs;
+ };
+ 4D5594B8153DCA5E009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5594AE153DCA53009F2584;
+ remoteInfo = fstyp_udf;
+ };
+ 4D5594DE153DCC73009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5594D4153DCC66009F2584;
+ remoteInfo = fuser;
+ };
+ 4D559519153DE1CB009F2584 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5593E3153CEE4A009F2584;
+ remoteInfo = quotaon;
+ };
+ B12C9C9122A7CDE300B9F497 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5593A5153CEA90009F2584;
+ remoteInfo = edquota;
+ };
+ B12C9C9322A7CDE300B9F497 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5593B8153CEB7E009F2584;
+ remoteInfo = quota;
+ };
+ B12C9C9522A7CDE300B9F497 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5593CC153CED29009F2584;
+ remoteInfo = quotacheck;
+ };
+ B12C9C9722A7CDE300B9F497 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5593E3153CEE4A009F2584;
+ remoteInfo = quotaon;
+ };
+ B12C9C9922A7CDE300B9F497 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D559514153DE116009F2584;
+ remoteInfo = quotaoff;
+ };
+ B12C9C9B22A7CDE300B9F497 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 4D07DD2B153CA616002B57CB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D5593F7153DC0DE009F2584;
+ remoteInfo = repquota;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 4D559313153CE198009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D55933C153CE242009F2584 /* fdisk.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D55933F153CE41E009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D55934E153CE4B1009F2584 /* fsck.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D55935E153CE561009F2584 /* Copy man5 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man5/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D55936F153CE5D6009F2584 /* fstab.5 in Copy man5 */,
+ );
+ name = "Copy man5";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D559370153CE5DC009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D559371153CE5EA009F2584 /* mount.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D55938C153CE7FD009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D55939A153CE82E009F2584 /* umount.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D5593A4153CEA90009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D5593C5153CEBB4009F2584 /* edquota.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D5593B7153CEB7E009F2584 /* Copy man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D5593C6153CEBC3009F2584 /* quota.1 in Copy man1 */,
+ );
+ name = "Copy man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D5593CB153CED29009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D5593DE153CED6A009F2584 /* quotacheck.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D5593E2153CEE4A009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D5593F0153CEE74009F2584 /* quotaon.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D5593F6153DC0DE009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D559404153DC150009F2584 /* repquota.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D559409153DC27A009F2584 /* Copy man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ name = "Copy man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D55941A153DC383009F2584 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D55942E153DC49A009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D55943E153DC4E9009F2584 /* mount_fdesc.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D55944C153DC634009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D55945D153DC728009F2584 /* vsdbutil.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D55945E153DC730009F2584 /* Copy com.apple.vsdbutil.plist */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D55945F153DC735009F2584 /* com.apple.vsdbutil.plist in Copy com.apple.vsdbutil.plist */,
+ );
+ name = "Copy com.apple.vsdbutil.plist";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D559462153DC808009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D559470153DC84E009F2584 /* dev_mkdb.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D559475153DC8FC009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D559483153DC92D009F2584 /* fstyp.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D559488153DC98D009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D559496153DC9BC009F2584 /* fstyp_msdos.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D55949B153DC9FB009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D5594E6153DCFFB009F2584 /* fstyp_ntfs.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D5594AD153DCA53009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D5594BD153DCA85009F2584 /* fstyp_udf.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D5594C0153DCAFC009F2584 /* Copy man8 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D5594CE153DCB82009F2584 /* setclass.8 in Copy man8 */,
+ );
+ name = "Copy man8";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 4D5594D3153DCC66009F2584 /* Copy man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 4D5594E2153DCCAC009F2584 /* fuser.1 in Copy man1 */,
+ );
+ name = "Copy man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 072AAAA42167CE8E004ED4E2 /* mount_flags.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mount_flags.c; sourceTree = "<group>"; };
+ 072AAAA52167CE8E004ED4E2 /* mount_flags.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mount_flags.h; sourceTree = "<group>"; };
+ 07AF95B12323281D001E9266 /* System.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = System.framework; path = System/Library/Frameworks/System.framework; sourceTree = SDKROOT; };
+ 07AF95B323232837001E9266 /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = System/Library/Frameworks/Kernel.framework; sourceTree = SDKROOT; };
+ 1A9041012091EE830061D05A /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
+ 1A9041032091EE910061D05A /* APFS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = APFS.framework; path = System/Library/PrivateFrameworks/APFS.framework; sourceTree = SDKROOT; };
+ 1A9041052091EE980061D05A /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+ 4D07DD49153CA9A0002B57CB /* libdisk.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdisk.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D07DD4D153CA9DC002B57CB /* dkcksum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dkcksum.c; path = disklib/dkcksum.c; sourceTree = "<group>"; };
+ 4D07DD4E153CA9DC002B57CB /* dkdisklabel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dkdisklabel.c; path = disklib/dkdisklabel.c; sourceTree = "<group>"; };
+ 4D07DD4F153CA9DC002B57CB /* dkopen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dkopen.c; path = disklib/dkopen.c; sourceTree = "<group>"; };
+ 4D07DD50153CA9DC002B57CB /* dkopen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dkopen.h; path = disklib/dkopen.h; sourceTree = "<group>"; };
+ 4D07DD51153CA9DC002B57CB /* dksecsize.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dksecsize.c; path = disklib/dksecsize.c; sourceTree = "<group>"; };
+ 4D07DD54153CA9DC002B57CB /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pathnames.h; path = disklib/pathnames.h; sourceTree = "<group>"; };
+ 4D07DD55153CA9DC002B57CB /* preen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = preen.c; path = disklib/preen.c; sourceTree = "<group>"; };
+ 4D07DD56153CA9DC002B57CB /* vfslist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vfslist.c; path = disklib/vfslist.c; sourceTree = "<group>"; };
+ 4D559315153CE198009F2584 /* fdisk */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fdisk; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D55931E153CE1D9009F2584 /* auto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auto.c; path = fdisk.tproj/auto.c; sourceTree = SOURCE_ROOT; };
+ 4D55931F153CE1D9009F2584 /* auto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = auto.h; path = fdisk.tproj/auto.h; sourceTree = SOURCE_ROOT; };
+ 4D559320153CE1D9009F2584 /* cmd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cmd.c; path = fdisk.tproj/cmd.c; sourceTree = SOURCE_ROOT; };
+ 4D559321153CE1D9009F2584 /* cmd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cmd.h; path = fdisk.tproj/cmd.h; sourceTree = SOURCE_ROOT; };
+ 4D559322153CE1D9009F2584 /* disk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = disk.c; path = fdisk.tproj/disk.c; sourceTree = SOURCE_ROOT; };
+ 4D559323153CE1D9009F2584 /* disk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = disk.h; path = fdisk.tproj/disk.h; sourceTree = SOURCE_ROOT; };
+ 4D559324153CE1D9009F2584 /* fdisk.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fdisk.8; path = fdisk.tproj/fdisk.8; sourceTree = SOURCE_ROOT; };
+ 4D559325153CE1D9009F2584 /* fdisk.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fdisk.c; path = fdisk.tproj/fdisk.c; sourceTree = SOURCE_ROOT; };
+ 4D559326153CE1D9009F2584 /* getrawpartition.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = getrawpartition.c; path = fdisk.tproj/getrawpartition.c; sourceTree = SOURCE_ROOT; };
+ 4D559327153CE1D9009F2584 /* mbr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mbr.c; path = fdisk.tproj/mbr.c; sourceTree = SOURCE_ROOT; };
+ 4D559328153CE1D9009F2584 /* mbr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mbr.h; path = fdisk.tproj/mbr.h; sourceTree = SOURCE_ROOT; };
+ 4D559329153CE1D9009F2584 /* mbrcode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mbrcode.h; path = fdisk.tproj/mbrcode.h; sourceTree = SOURCE_ROOT; };
+ 4D55932A153CE1D9009F2584 /* misc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = misc.c; path = fdisk.tproj/misc.c; sourceTree = SOURCE_ROOT; };
+ 4D55932B153CE1D9009F2584 /* misc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = misc.h; path = fdisk.tproj/misc.h; sourceTree = SOURCE_ROOT; };
+ 4D55932C153CE1D9009F2584 /* opendev.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = opendev.c; path = fdisk.tproj/opendev.c; sourceTree = SOURCE_ROOT; };
+ 4D55932D153CE1D9009F2584 /* part.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = part.c; path = fdisk.tproj/part.c; sourceTree = SOURCE_ROOT; };
+ 4D55932E153CE1D9009F2584 /* part.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = part.h; path = fdisk.tproj/part.h; sourceTree = SOURCE_ROOT; };
+ 4D55932F153CE1D9009F2584 /* user.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = user.c; path = fdisk.tproj/user.c; sourceTree = SOURCE_ROOT; };
+ 4D559330153CE1D9009F2584 /* user.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = user.h; path = fdisk.tproj/user.h; sourceTree = SOURCE_ROOT; };
+ 4D559331153CE1D9009F2584 /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = util.h; path = fdisk.tproj/util.h; sourceTree = SOURCE_ROOT; };
+ 4D559341153CE41E009F2584 /* fsck */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fsck; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D55934A153CE44E009F2584 /* fsck.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fsck.8; path = fsck.tproj/fsck.8; sourceTree = SOURCE_ROOT; };
+ 4D55934B153CE44E009F2584 /* fsck.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fsck.c; path = fsck.tproj/fsck.c; sourceTree = SOURCE_ROOT; };
+ 4D55934C153CE44E009F2584 /* fsck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fsck.h; path = fsck.tproj/fsck.h; sourceTree = SOURCE_ROOT; };
+ 4D559360153CE561009F2584 /* mount */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mount; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D559369153CE58E009F2584 /* fstab.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fstab.5; path = mount.tproj/fstab.5; sourceTree = SOURCE_ROOT; };
+ 4D55936B153CE58E009F2584 /* mount.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mount.8; path = mount.tproj/mount.8; sourceTree = SOURCE_ROOT; };
+ 4D55936C153CE58E009F2584 /* mount.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mount.c; path = mount.tproj/mount.c; sourceTree = SOURCE_ROOT; };
+ 4D55936D153CE58E009F2584 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pathnames.h; path = mount.tproj/pathnames.h; sourceTree = SOURCE_ROOT; };
+ 4D55938E153CE7FD009F2584 /* umount */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = umount; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D559397153CE826009F2584 /* umount.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = umount.8; path = umount.tproj/umount.8; sourceTree = SOURCE_ROOT; };
+ 4D559398153CE826009F2584 /* umount.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = umount.c; path = umount.tproj/umount.c; sourceTree = SOURCE_ROOT; };
+ 4D5593A6153CEA90009F2584 /* edquota */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = edquota; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D5593AF153CEABD009F2584 /* edquota.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = edquota.8; path = edquota.tproj/edquota.8; sourceTree = SOURCE_ROOT; };
+ 4D5593B0153CEABD009F2584 /* edquota.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = edquota.c; path = edquota.tproj/edquota.c; sourceTree = SOURCE_ROOT; };
+ 4D5593B1153CEABD009F2584 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pathnames.h; path = edquota.tproj/pathnames.h; sourceTree = SOURCE_ROOT; };
+ 4D5593B9153CEB7E009F2584 /* quota */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = quota; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D5593C2153CEB9A009F2584 /* quota.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = quota.1; path = quota.tproj/quota.1; sourceTree = SOURCE_ROOT; };
+ 4D5593C3153CEB9A009F2584 /* quota.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quota.c; path = quota.tproj/quota.c; sourceTree = SOURCE_ROOT; };
+ 4D5593CD153CED29009F2584 /* quotacheck */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = quotacheck; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D5593D8153CED51009F2584 /* hfs_quotacheck.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = hfs_quotacheck.c; path = quotacheck.tproj/hfs_quotacheck.c; sourceTree = SOURCE_ROOT; };
+ 4D5593D9153CED51009F2584 /* quotacheck.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = quotacheck.8; path = quotacheck.tproj/quotacheck.8; sourceTree = SOURCE_ROOT; };
+ 4D5593DA153CED51009F2584 /* quotacheck.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quotacheck.c; path = quotacheck.tproj/quotacheck.c; sourceTree = SOURCE_ROOT; };
+ 4D5593DB153CED51009F2584 /* quotacheck.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = quotacheck.h; path = quotacheck.tproj/quotacheck.h; sourceTree = SOURCE_ROOT; };
+ 4D5593E4153CEE4A009F2584 /* quotaon */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = quotaon; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D5593ED153CEE66009F2584 /* quotaon.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = quotaon.8; path = quotaon.tproj/quotaon.8; sourceTree = SOURCE_ROOT; };
+ 4D5593EE153CEE66009F2584 /* quotaon.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = quotaon.c; path = quotaon.tproj/quotaon.c; sourceTree = SOURCE_ROOT; };
+ 4D5593F8153DC0DE009F2584 /* repquota */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = repquota; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D559401153DC13D009F2584 /* repquota.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = repquota.8; path = repquota.tproj/repquota.8; sourceTree = SOURCE_ROOT; };
+ 4D559402153DC13D009F2584 /* repquota.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = repquota.c; path = repquota.tproj/repquota.c; sourceTree = SOURCE_ROOT; };
+ 4D55940B153DC27A009F2584 /* vndevice */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vndevice; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D559416153DC2AB009F2584 /* vndevice.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vndevice.c; path = vndevice.tproj/vndevice.c; sourceTree = SOURCE_ROOT; };
+ 4D55941C153DC383009F2584 /* mount_devfs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mount_devfs; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D559427153DC3A6009F2584 /* mount_devfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mount_devfs.c; path = mount_devfs.tproj/mount_devfs.c; sourceTree = SOURCE_ROOT; };
+ 4D55942A153DC420009F2584 /* libutil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libutil.dylib; path = usr/lib/libutil.dylib; sourceTree = SDKROOT; };
+ 4D559430153DC49A009F2584 /* mount_fdesc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mount_fdesc; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D55943B153DC4DE009F2584 /* mount_fdesc.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mount_fdesc.8; path = mount_fdesc.tproj/mount_fdesc.8; sourceTree = SOURCE_ROOT; };
+ 4D55943C153DC4DE009F2584 /* mount_fdesc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mount_fdesc.c; path = mount_fdesc.tproj/mount_fdesc.c; sourceTree = SOURCE_ROOT; };
+ 4D55944E153DC634009F2584 /* vsdbutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vsdbutil; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D559457153DC650009F2584 /* com.apple.vsdbutil.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = com.apple.vsdbutil.plist; path = vsdbutil.tproj/com.apple.vsdbutil.plist; sourceTree = SOURCE_ROOT; };
+ 4D559458153DC650009F2584 /* vsdbutil_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vsdbutil_main.c; path = vsdbutil.tproj/vsdbutil_main.c; sourceTree = SOURCE_ROOT; };
+ 4D559459153DC650009F2584 /* vsdbutil.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = vsdbutil.8; path = vsdbutil.tproj/vsdbutil.8; sourceTree = SOURCE_ROOT; };
+ 4D559464153DC808009F2584 /* dev_mkdb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dev_mkdb; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D55946D153DC839009F2584 /* dev_mkdb.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = dev_mkdb.8; path = dev_mkdb.tproj/dev_mkdb.8; sourceTree = SOURCE_ROOT; };
+ 4D55946E153DC839009F2584 /* dev_mkdb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dev_mkdb.c; path = dev_mkdb.tproj/dev_mkdb.c; sourceTree = SOURCE_ROOT; };
+ 4D559477153DC8FC009F2584 /* fstyp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fstyp; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D559480153DC912009F2584 /* fstyp.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fstyp.8; path = fstyp.tproj/fstyp.8; sourceTree = SOURCE_ROOT; };
+ 4D559481153DC912009F2584 /* fstyp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fstyp.c; path = fstyp.tproj/fstyp.c; sourceTree = SOURCE_ROOT; };
+ 4D55948A153DC98D009F2584 /* fstyp_msdos */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fstyp_msdos; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D559493153DC9AE009F2584 /* fstyp_msdos.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fstyp_msdos.8; path = fstyp.tproj/fstyp_msdos.8; sourceTree = SOURCE_ROOT; };
+ 4D559494153DC9AE009F2584 /* fstyp_msdos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fstyp_msdos.c; path = fstyp.tproj/fstyp_msdos.c; sourceTree = SOURCE_ROOT; };
+ 4D55949D153DC9FB009F2584 /* fstyp_ntfs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fstyp_ntfs; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D5594A8153DCA19009F2584 /* fstyp_ntfs.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fstyp_ntfs.8; path = fstyp.tproj/fstyp_ntfs.8; sourceTree = SOURCE_ROOT; };
+ 4D5594A9153DCA19009F2584 /* fstyp_ntfs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fstyp_ntfs.c; path = fstyp.tproj/fstyp_ntfs.c; sourceTree = SOURCE_ROOT; };
+ 4D5594AF153DCA53009F2584 /* fstyp_udf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fstyp_udf; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D5594BA153DCA74009F2584 /* fstyp_udf.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fstyp_udf.8; path = fstyp.tproj/fstyp_udf.8; sourceTree = SOURCE_ROOT; };
+ 4D5594BB153DCA74009F2584 /* fstyp_udf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = fstyp_udf.c; path = fstyp.tproj/fstyp_udf.c; sourceTree = SOURCE_ROOT; };
+ 4D5594C2153DCAFC009F2584 /* setclass */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = setclass; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D5594CB153DCB72009F2584 /* setclass.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = setclass.8; path = setclass.tproj/setclass.8; sourceTree = SOURCE_ROOT; };
+ 4D5594CC153DCB72009F2584 /* setclass.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = setclass.c; path = setclass.tproj/setclass.c; sourceTree = SOURCE_ROOT; };
+ 4D5594D5153DCC66009F2584 /* fuser */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fuser; sourceTree = BUILT_PRODUCTS_DIR; };
+ 4D5594E0153DCC92009F2584 /* fuser.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = fuser.1; path = fuser.tproj/fuser.1; sourceTree = SOURCE_ROOT; };
+ 4D5594E1153DCC92009F2584 /* fuser.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; name = fuser.pl; path = fuser.tproj/fuser.pl; sourceTree = SOURCE_ROOT; };
+ 785314FE227120BD00B25661 /* MediaKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaKit.framework; path = System/Library/PrivateFrameworks/MediaKit.framework; sourceTree = SDKROOT; };
+ 785315012277BEA700B25661 /* mount.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = mount.entitlements; path = mount.tproj/mount.entitlements; sourceTree = SOURCE_ROOT; };
+ B19B239A21C8DEF90001F35C /* edt_fstab.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = edt_fstab.c; sourceTree = "<group>"; };
+ B19B239B21C8DEFA0001F35C /* edt_fstab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = edt_fstab.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 4D07DD46153CA9A0002B57CB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559312153CE198009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55933E153CE41E009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B19B239F21C8DF7B0001F35C /* CoreFoundation.framework in Frameworks */,
+ B19B239E21C8DF740001F35C /* APFS.framework in Frameworks */,
+ B19B239D21C8DF6E0001F35C /* IOKit.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55935D153CE561009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 785314FF227120BD00B25661 /* MediaKit.framework in Frameworks */,
+ 1A9041062091EE980061D05A /* CoreFoundation.framework in Frameworks */,
+ 1A9041042091EE910061D05A /* APFS.framework in Frameworks */,
+ 1A9041022091EE830061D05A /* IOKit.framework in Frameworks */,
+ 4D559389153CE794009F2584 /* libdisk.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55938B153CE7FD009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B19B23A521C8DFE10001F35C /* CoreFoundation.framework in Frameworks */,
+ B19B23A421C8DFD50001F35C /* IOKit.framework in Frameworks */,
+ B19B23A321C8DFCF0001F35C /* APFS.framework in Frameworks */,
+ 4D55939D153CE8AF009F2584 /* libdisk.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593A3153CEA90009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593B6153CEB7E009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593CA153CED29009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D5593DF153CED8D009F2584 /* libdisk.a in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593E1153CEE4A009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593F5153DC0DE009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559408153DC27A009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559419153DC383009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D55942B153DC427009F2584 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55942D153DC49A009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D55943F153DC534009F2584 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55944B153DC634009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559461153DC808009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559474153DC8FC009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559487153DC98D009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55949A153DC9FB009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5594AC153DCA53009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5594BF153DCAFC009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5594D2153DCC66009F2584 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 072AAAA32167CD68004ED4E2 /* mount_flags_dir */ = {
+ isa = PBXGroup;
+ children = (
+ 072AAAA42167CE8E004ED4E2 /* mount_flags.c */,
+ 072AAAA52167CE8E004ED4E2 /* mount_flags.h */,
+ );
+ path = mount_flags_dir;
+ sourceTree = "<group>";
+ };
+ 1A9041002091EE820061D05A /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 07AF95B323232837001E9266 /* Kernel.framework */,
+ 07AF95B12323281D001E9266 /* System.framework */,
+ 785314FE227120BD00B25661 /* MediaKit.framework */,
+ 1A9041052091EE980061D05A /* CoreFoundation.framework */,
+ 1A9041032091EE910061D05A /* APFS.framework */,
+ 1A9041012091EE830061D05A /* IOKit.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 4D07DD29153CA616002B57CB = {
+ isa = PBXGroup;
+ children = (
+ B1DF3D3D21C27FE00099F594 /* edt_fstab */,
+ 072AAAA32167CD68004ED4E2 /* mount_flags_dir */,
+ 4D559466153DC808009F2584 /* dev_mkdb */,
+ 4D07DD4C153CA9C4002B57CB /* disklib */,
+ 4D5593A8153CEA90009F2584 /* edquota */,
+ 4D559317153CE199009F2584 /* fdisk */,
+ 4D559343153CE41E009F2584 /* fsck */,
+ 4D559479153DC8FC009F2584 /* fstyp */,
+ 4D55948C153DC98D009F2584 /* fstyp_msdos */,
+ 4D55949F153DC9FB009F2584 /* fstyp_ntfs */,
+ 4D5594B1153DCA53009F2584 /* fstyp_udf */,
+ 4D5594D7153DCC66009F2584 /* fuser */,
+ 4D559362153CE561009F2584 /* mount */,
+ 4D55941E153DC384009F2584 /* mount_devfs */,
+ 4D559432153DC49A009F2584 /* mount_fdesc */,
+ 4D5593BB153CEB7E009F2584 /* quota */,
+ 4D5593CF153CED29009F2584 /* quotacheck */,
+ 4D5593E6153CEE4A009F2584 /* quotaon */,
+ 4D5593FA153DC0DE009F2584 /* repquota */,
+ 4D5594C4153DCAFC009F2584 /* setclass */,
+ 4D559390153CE7FD009F2584 /* umount */,
+ 4D55940D153DC27A009F2584 /* vndevice */,
+ 4D559450153DC634009F2584 /* vsdbutil */,
+ 4D559429153DC3F3009F2584 /* Libraries */,
+ 4D07DD35153CA616002B57CB /* Products */,
+ 1A9041002091EE820061D05A /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 4D07DD35153CA616002B57CB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 4D07DD49153CA9A0002B57CB /* libdisk.a */,
+ 4D559315153CE198009F2584 /* fdisk */,
+ 4D559341153CE41E009F2584 /* fsck */,
+ 4D559360153CE561009F2584 /* mount */,
+ 4D55938E153CE7FD009F2584 /* umount */,
+ 4D5593A6153CEA90009F2584 /* edquota */,
+ 4D5593B9153CEB7E009F2584 /* quota */,
+ 4D5593CD153CED29009F2584 /* quotacheck */,
+ 4D5593E4153CEE4A009F2584 /* quotaon */,
+ 4D5593F8153DC0DE009F2584 /* repquota */,
+ 4D55940B153DC27A009F2584 /* vndevice */,
+ 4D55941C153DC383009F2584 /* mount_devfs */,
+ 4D559430153DC49A009F2584 /* mount_fdesc */,
+ 4D55944E153DC634009F2584 /* vsdbutil */,
+ 4D559464153DC808009F2584 /* dev_mkdb */,
+ 4D559477153DC8FC009F2584 /* fstyp */,
+ 4D55948A153DC98D009F2584 /* fstyp_msdos */,
+ 4D55949D153DC9FB009F2584 /* fstyp_ntfs */,
+ 4D5594AF153DCA53009F2584 /* fstyp_udf */,
+ 4D5594C2153DCAFC009F2584 /* setclass */,
+ 4D5594D5153DCC66009F2584 /* fuser */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 4D07DD4C153CA9C4002B57CB /* disklib */ = {
+ isa = PBXGroup;
+ children = (
+ 4D07DD50153CA9DC002B57CB /* dkopen.h */,
+ 4D07DD54153CA9DC002B57CB /* pathnames.h */,
+ 4D07DD4D153CA9DC002B57CB /* dkcksum.c */,
+ 4D07DD4E153CA9DC002B57CB /* dkdisklabel.c */,
+ 4D07DD4F153CA9DC002B57CB /* dkopen.c */,
+ 4D07DD51153CA9DC002B57CB /* dksecsize.c */,
+ 4D07DD55153CA9DC002B57CB /* preen.c */,
+ 4D07DD56153CA9DC002B57CB /* vfslist.c */,
+ );
+ name = disklib;
+ sourceTree = "<group>";
+ };
+ 4D559317153CE199009F2584 /* fdisk */ = {
+ isa = PBXGroup;
+ children = (
+ 4D55931F153CE1D9009F2584 /* auto.h */,
+ 4D559321153CE1D9009F2584 /* cmd.h */,
+ 4D559323153CE1D9009F2584 /* disk.h */,
+ 4D559328153CE1D9009F2584 /* mbr.h */,
+ 4D559329153CE1D9009F2584 /* mbrcode.h */,
+ 4D55932B153CE1D9009F2584 /* misc.h */,
+ 4D55932E153CE1D9009F2584 /* part.h */,
+ 4D559330153CE1D9009F2584 /* user.h */,
+ 4D559331153CE1D9009F2584 /* util.h */,
+ 4D55931E153CE1D9009F2584 /* auto.c */,
+ 4D559320153CE1D9009F2584 /* cmd.c */,
+ 4D559322153CE1D9009F2584 /* disk.c */,
+ 4D559325153CE1D9009F2584 /* fdisk.c */,
+ 4D559326153CE1D9009F2584 /* getrawpartition.c */,
+ 4D559327153CE1D9009F2584 /* mbr.c */,
+ 4D55932A153CE1D9009F2584 /* misc.c */,
+ 4D55932C153CE1D9009F2584 /* opendev.c */,
+ 4D55932D153CE1D9009F2584 /* part.c */,
+ 4D55932F153CE1D9009F2584 /* user.c */,
+ 4D559324153CE1D9009F2584 /* fdisk.8 */,
+ );
+ path = fdisk;
+ sourceTree = "<group>";
+ };
+ 4D559343153CE41E009F2584 /* fsck */ = {
+ isa = PBXGroup;
+ children = (
+ 4D55934C153CE44E009F2584 /* fsck.h */,
+ 4D55934B153CE44E009F2584 /* fsck.c */,
+ 4D55934A153CE44E009F2584 /* fsck.8 */,
+ );
+ path = fsck;
+ sourceTree = "<group>";
+ };
+ 4D559362153CE561009F2584 /* mount */ = {
+ isa = PBXGroup;
+ children = (
+ 4D55936D153CE58E009F2584 /* pathnames.h */,
+ 4D55936C153CE58E009F2584 /* mount.c */,
+ 4D55936B153CE58E009F2584 /* mount.8 */,
+ 4D559369153CE58E009F2584 /* fstab.5 */,
+ 785315012277BEA700B25661 /* mount.entitlements */,
+ );
+ path = mount;
+ sourceTree = "<group>";
+ };
+ 4D559390153CE7FD009F2584 /* umount */ = {
+ isa = PBXGroup;
+ children = (
+ 4D559398153CE826009F2584 /* umount.c */,
+ 4D559397153CE826009F2584 /* umount.8 */,
+ );
+ path = umount;
+ sourceTree = "<group>";
+ };
+ 4D5593A8153CEA90009F2584 /* edquota */ = {
+ isa = PBXGroup;
+ children = (
+ 4D5593B1153CEABD009F2584 /* pathnames.h */,
+ 4D5593B0153CEABD009F2584 /* edquota.c */,
+ 4D5593AF153CEABD009F2584 /* edquota.8 */,
+ );
+ path = edquota;
+ sourceTree = "<group>";
+ };
+ 4D5593BB153CEB7E009F2584 /* quota */ = {
+ isa = PBXGroup;
+ children = (
+ 4D5593C2153CEB9A009F2584 /* quota.1 */,
+ 4D5593C3153CEB9A009F2584 /* quota.c */,
+ );
+ path = quota;
+ sourceTree = "<group>";
+ };
+ 4D5593CF153CED29009F2584 /* quotacheck */ = {
+ isa = PBXGroup;
+ children = (
+ 4D5593DB153CED51009F2584 /* quotacheck.h */,
+ 4D5593D8153CED51009F2584 /* hfs_quotacheck.c */,
+ 4D5593DA153CED51009F2584 /* quotacheck.c */,
+ 4D5593D9153CED51009F2584 /* quotacheck.8 */,
+ );
+ path = quotacheck;
+ sourceTree = "<group>";
+ };
+ 4D5593E6153CEE4A009F2584 /* quotaon */ = {
+ isa = PBXGroup;
+ children = (
+ 4D5593EE153CEE66009F2584 /* quotaon.c */,
+ 4D5593ED153CEE66009F2584 /* quotaon.8 */,
+ );
+ path = quotaon;
+ sourceTree = "<group>";
+ };
+ 4D5593FA153DC0DE009F2584 /* repquota */ = {
+ isa = PBXGroup;
+ children = (
+ 4D559402153DC13D009F2584 /* repquota.c */,
+ 4D559401153DC13D009F2584 /* repquota.8 */,
+ );
+ path = repquota;
+ sourceTree = "<group>";
+ };
+ 4D55940D153DC27A009F2584 /* vndevice */ = {
+ isa = PBXGroup;
+ children = (
+ 4D559416153DC2AB009F2584 /* vndevice.c */,
+ );
+ path = vndevice;
+ sourceTree = "<group>";
+ };
+ 4D55941E153DC384009F2584 /* mount_devfs */ = {
+ isa = PBXGroup;
+ children = (
+ 4D559427153DC3A6009F2584 /* mount_devfs.c */,
+ );
+ path = mount_devfs;
+ sourceTree = "<group>";
+ };
+ 4D559429153DC3F3009F2584 /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 4D55942A153DC420009F2584 /* libutil.dylib */,
+ );
+ name = Libraries;
+ sourceTree = "<group>";
+ };
+ 4D559432153DC49A009F2584 /* mount_fdesc */ = {
+ isa = PBXGroup;
+ children = (
+ 4D55943B153DC4DE009F2584 /* mount_fdesc.8 */,
+ 4D55943C153DC4DE009F2584 /* mount_fdesc.c */,
+ );
+ path = mount_fdesc;
+ sourceTree = "<group>";
+ };
+ 4D559450153DC634009F2584 /* vsdbutil */ = {
+ isa = PBXGroup;
+ children = (
+ 4D559458153DC650009F2584 /* vsdbutil_main.c */,
+ 4D559457153DC650009F2584 /* com.apple.vsdbutil.plist */,
+ 4D559459153DC650009F2584 /* vsdbutil.8 */,
+ );
+ path = vsdbutil;
+ sourceTree = "<group>";
+ };
+ 4D559466153DC808009F2584 /* dev_mkdb */ = {
+ isa = PBXGroup;
+ children = (
+ 4D55946D153DC839009F2584 /* dev_mkdb.8 */,
+ 4D55946E153DC839009F2584 /* dev_mkdb.c */,
+ );
+ path = dev_mkdb;
+ sourceTree = "<group>";
+ };
+ 4D559479153DC8FC009F2584 /* fstyp */ = {
+ isa = PBXGroup;
+ children = (
+ 4D559480153DC912009F2584 /* fstyp.8 */,
+ 4D559481153DC912009F2584 /* fstyp.c */,
+ );
+ path = fstyp;
+ sourceTree = "<group>";
+ };
+ 4D55948C153DC98D009F2584 /* fstyp_msdos */ = {
+ isa = PBXGroup;
+ children = (
+ 4D559493153DC9AE009F2584 /* fstyp_msdos.8 */,
+ 4D559494153DC9AE009F2584 /* fstyp_msdos.c */,
+ );
+ path = fstyp_msdos;
+ sourceTree = "<group>";
+ };
+ 4D55949F153DC9FB009F2584 /* fstyp_ntfs */ = {
+ isa = PBXGroup;
+ children = (
+ 4D5594A8153DCA19009F2584 /* fstyp_ntfs.8 */,
+ 4D5594A9153DCA19009F2584 /* fstyp_ntfs.c */,
+ );
+ path = fstyp_ntfs;
+ sourceTree = "<group>";
+ };
+ 4D5594B1153DCA53009F2584 /* fstyp_udf */ = {
+ isa = PBXGroup;
+ children = (
+ 4D5594BA153DCA74009F2584 /* fstyp_udf.8 */,
+ 4D5594BB153DCA74009F2584 /* fstyp_udf.c */,
+ );
+ path = fstyp_udf;
+ sourceTree = "<group>";
+ };
+ 4D5594C4153DCAFC009F2584 /* setclass */ = {
+ isa = PBXGroup;
+ children = (
+ 4D5594CB153DCB72009F2584 /* setclass.8 */,
+ 4D5594CC153DCB72009F2584 /* setclass.c */,
+ );
+ path = setclass;
+ sourceTree = "<group>";
+ };
+ 4D5594D7153DCC66009F2584 /* fuser */ = {
+ isa = PBXGroup;
+ children = (
+ 4D5594E0153DCC92009F2584 /* fuser.1 */,
+ 4D5594E1153DCC92009F2584 /* fuser.pl */,
+ );
+ path = fuser;
+ sourceTree = "<group>";
+ };
+ B1DF3D3D21C27FE00099F594 /* edt_fstab */ = {
+ isa = PBXGroup;
+ children = (
+ B19B239A21C8DEF90001F35C /* edt_fstab.c */,
+ B19B239B21C8DEFA0001F35C /* edt_fstab.h */,
+ );
+ path = edt_fstab;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 4D07DD47153CA9A0002B57CB /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D07DD5A153CA9DC002B57CB /* dkopen.h in Headers */,
+ 4D07DD5E153CA9DC002B57CB /* pathnames.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 4D07DD48153CA9A0002B57CB /* libdisk */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D07DD4A153CA9A0002B57CB /* Build configuration list for PBXNativeTarget "libdisk" */;
+ buildPhases = (
+ 4D07DD45153CA9A0002B57CB /* Sources */,
+ 4D07DD46153CA9A0002B57CB /* Frameworks */,
+ 4D07DD47153CA9A0002B57CB /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libdisk;
+ productName = disklib;
+ productReference = 4D07DD49153CA9A0002B57CB /* libdisk.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ 4D559314153CE198009F2584 /* fdisk */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D55931C153CE199009F2584 /* Build configuration list for PBXNativeTarget "fdisk" */;
+ buildPhases = (
+ 4D559311153CE198009F2584 /* Sources */,
+ 4D559312153CE198009F2584 /* Frameworks */,
+ 4D559313153CE198009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fdisk;
+ productName = fdisk;
+ productReference = 4D559315153CE198009F2584 /* fdisk */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D559340153CE41E009F2584 /* fsck */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D559348153CE41E009F2584 /* Build configuration list for PBXNativeTarget "fsck" */;
+ buildPhases = (
+ 4D55933D153CE41E009F2584 /* Sources */,
+ 4D55933E153CE41E009F2584 /* Frameworks */,
+ 4D55933F153CE41E009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fsck;
+ productName = fsck;
+ productReference = 4D559341153CE41E009F2584 /* fsck */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D55935F153CE561009F2584 /* mount */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D559367153CE561009F2584 /* Build configuration list for PBXNativeTarget "mount" */;
+ buildPhases = (
+ 4D55935C153CE561009F2584 /* Sources */,
+ 4D55935D153CE561009F2584 /* Frameworks */,
+ 4D55935E153CE561009F2584 /* Copy man5 */,
+ 4D559370153CE5DC009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 4D5593A1153CE8BC009F2584 /* PBXTargetDependency */,
+ );
+ name = mount;
+ productName = mount;
+ productReference = 4D559360153CE561009F2584 /* mount */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D55938D153CE7FD009F2584 /* umount */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D559395153CE7FE009F2584 /* Build configuration list for PBXNativeTarget "umount" */;
+ buildPhases = (
+ 4D55938A153CE7FD009F2584 /* Sources */,
+ 4D55938B153CE7FD009F2584 /* Frameworks */,
+ 4D55938C153CE7FD009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 4D55939F153CE8B6009F2584 /* PBXTargetDependency */,
+ );
+ name = umount;
+ productName = umount;
+ productReference = 4D55938E153CE7FD009F2584 /* umount */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D5593A5153CEA90009F2584 /* edquota */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5593AD153CEA90009F2584 /* Build configuration list for PBXNativeTarget "edquota" */;
+ buildPhases = (
+ 4D5593A2153CEA90009F2584 /* Sources */,
+ 4D5593A3153CEA90009F2584 /* Frameworks */,
+ 4D5593A4153CEA90009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = edquota;
+ productName = edquota;
+ productReference = 4D5593A6153CEA90009F2584 /* edquota */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D5593B8153CEB7E009F2584 /* quota */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5593C0153CEB7E009F2584 /* Build configuration list for PBXNativeTarget "quota" */;
+ buildPhases = (
+ 4D5593B5153CEB7E009F2584 /* Sources */,
+ 4D5593B6153CEB7E009F2584 /* Frameworks */,
+ 4D5593B7153CEB7E009F2584 /* Copy man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = quota;
+ productName = quota;
+ productReference = 4D5593B9153CEB7E009F2584 /* quota */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D5593CC153CED29009F2584 /* quotacheck */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5593D4153CED29009F2584 /* Build configuration list for PBXNativeTarget "quotacheck" */;
+ buildPhases = (
+ 4D5593C9153CED29009F2584 /* Sources */,
+ 4D5593CA153CED29009F2584 /* Frameworks */,
+ 4D5593CB153CED29009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = quotacheck;
+ productName = quotacheck;
+ productReference = 4D5593CD153CED29009F2584 /* quotacheck */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D5593E3153CEE4A009F2584 /* quotaon */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5593EB153CEE4A009F2584 /* Build configuration list for PBXNativeTarget "quotaon" */;
+ buildPhases = (
+ 4D5593E0153CEE4A009F2584 /* Sources */,
+ 4D5593E1153CEE4A009F2584 /* Frameworks */,
+ 4D5593E2153CEE4A009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = quotaon;
+ productName = quotaon;
+ productReference = 4D5593E4153CEE4A009F2584 /* quotaon */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D5593F7153DC0DE009F2584 /* repquota */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5593FF153DC0DE009F2584 /* Build configuration list for PBXNativeTarget "repquota" */;
+ buildPhases = (
+ 4D5593F4153DC0DE009F2584 /* Sources */,
+ 4D5593F5153DC0DE009F2584 /* Frameworks */,
+ 4D5593F6153DC0DE009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = repquota;
+ productName = repquota;
+ productReference = 4D5593F8153DC0DE009F2584 /* repquota */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D55940A153DC27A009F2584 /* vndevice */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D559412153DC27A009F2584 /* Build configuration list for PBXNativeTarget "vndevice" */;
+ buildPhases = (
+ 4D559407153DC27A009F2584 /* Sources */,
+ 4D559408153DC27A009F2584 /* Frameworks */,
+ 4D559409153DC27A009F2584 /* Copy man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vndevice;
+ productName = vndevice;
+ productReference = 4D55940B153DC27A009F2584 /* vndevice */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D55941B153DC383009F2584 /* mount_devfs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D559423153DC384009F2584 /* Build configuration list for PBXNativeTarget "mount_devfs" */;
+ buildPhases = (
+ 4D559418153DC383009F2584 /* Sources */,
+ 4D559419153DC383009F2584 /* Frameworks */,
+ 4D55941A153DC383009F2584 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mount_devfs;
+ productName = mount_devfs;
+ productReference = 4D55941C153DC383009F2584 /* mount_devfs */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D55942F153DC49A009F2584 /* mount_fdesc */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D559437153DC49A009F2584 /* Build configuration list for PBXNativeTarget "mount_fdesc" */;
+ buildPhases = (
+ 4D55942C153DC49A009F2584 /* Sources */,
+ 4D55942D153DC49A009F2584 /* Frameworks */,
+ 4D55942E153DC49A009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mount_fdesc;
+ productName = mount_fdesc;
+ productReference = 4D559430153DC49A009F2584 /* mount_fdesc */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D55944D153DC634009F2584 /* vsdbutil */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D559455153DC634009F2584 /* Build configuration list for PBXNativeTarget "vsdbutil" */;
+ buildPhases = (
+ 4D55944A153DC634009F2584 /* Sources */,
+ 4D55944B153DC634009F2584 /* Frameworks */,
+ 4D55944C153DC634009F2584 /* Copy man8 */,
+ 4D55945E153DC730009F2584 /* Copy com.apple.vsdbutil.plist */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vsdbutil;
+ productName = vsdbutil;
+ productReference = 4D55944E153DC634009F2584 /* vsdbutil */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D559463153DC808009F2584 /* dev_mkdb */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D55946B153DC808009F2584 /* Build configuration list for PBXNativeTarget "dev_mkdb" */;
+ buildPhases = (
+ 4D559460153DC808009F2584 /* Sources */,
+ 4D559461153DC808009F2584 /* Frameworks */,
+ 4D559462153DC808009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dev_mkdb;
+ productName = dev_mkdb;
+ productReference = 4D559464153DC808009F2584 /* dev_mkdb */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D559476153DC8FC009F2584 /* fstyp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D55947E153DC8FC009F2584 /* Build configuration list for PBXNativeTarget "fstyp" */;
+ buildPhases = (
+ 4D559473153DC8FC009F2584 /* Sources */,
+ 4D559474153DC8FC009F2584 /* Frameworks */,
+ 4D559475153DC8FC009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fstyp;
+ productName = fstyp;
+ productReference = 4D559477153DC8FC009F2584 /* fstyp */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D559489153DC98D009F2584 /* fstyp_msdos */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D559491153DC98D009F2584 /* Build configuration list for PBXNativeTarget "fstyp_msdos" */;
+ buildPhases = (
+ 4D559486153DC98D009F2584 /* Sources */,
+ 4D559487153DC98D009F2584 /* Frameworks */,
+ 4D559488153DC98D009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fstyp_msdos;
+ productName = fstyp_msdos;
+ productReference = 4D55948A153DC98D009F2584 /* fstyp_msdos */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D55949C153DC9FB009F2584 /* fstyp_ntfs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5594A4153DC9FB009F2584 /* Build configuration list for PBXNativeTarget "fstyp_ntfs" */;
+ buildPhases = (
+ 4D559499153DC9FB009F2584 /* Sources */,
+ 4D55949A153DC9FB009F2584 /* Frameworks */,
+ 4D55949B153DC9FB009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fstyp_ntfs;
+ productName = fstyp_ntfs;
+ productReference = 4D55949D153DC9FB009F2584 /* fstyp_ntfs */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D5594AE153DCA53009F2584 /* fstyp_udf */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5594B6153DCA53009F2584 /* Build configuration list for PBXNativeTarget "fstyp_udf" */;
+ buildPhases = (
+ 4D5594AB153DCA53009F2584 /* Sources */,
+ 4D5594AC153DCA53009F2584 /* Frameworks */,
+ 4D5594AD153DCA53009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fstyp_udf;
+ productName = fstyp_udf;
+ productReference = 4D5594AF153DCA53009F2584 /* fstyp_udf */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D5594C1153DCAFC009F2584 /* setclass */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5594C9153DCAFC009F2584 /* Build configuration list for PBXNativeTarget "setclass" */;
+ buildPhases = (
+ 4D5594BE153DCAFC009F2584 /* Sources */,
+ 4D5594BF153DCAFC009F2584 /* Frameworks */,
+ 4D5594C0153DCAFC009F2584 /* Copy man8 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = setclass;
+ productName = setclass;
+ productReference = 4D5594C2153DCAFC009F2584 /* setclass */;
+ productType = "com.apple.product-type.tool";
+ };
+ 4D5594D4153DCC66009F2584 /* fuser */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D5594DC153DCC66009F2584 /* Build configuration list for PBXNativeTarget "fuser" */;
+ buildPhases = (
+ 4D5594D1153DCC66009F2584 /* Sources */,
+ 4D5594D2153DCC66009F2584 /* Frameworks */,
+ 4D5594E4153DCCD3009F2584 /* Copy fuser */,
+ 4D5594D3153DCC66009F2584 /* Copy man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fuser;
+ productName = fuser;
+ productReference = 4D5594D5153DCC66009F2584 /* fuser */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 4D07DD2B153CA616002B57CB /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0440;
+ ORGANIZATIONNAME = "Apple Inc.";
+ };
+ buildConfigurationList = 4D07DD2E153CA616002B57CB /* Build configuration list for PBXProject "diskdev_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ en,
+ );
+ mainGroup = 4D07DD29153CA616002B57CB;
+ productRefGroup = 4D07DD35153CA616002B57CB /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 4D559440153DC57D009F2584 /* All_MacOSX */,
+ 4D559443153DC587009F2584 /* All_iOS */,
+ 4D55934F153CE4CC009F2584 /* Common */,
+ 4D07DD48153CA9A0002B57CB /* libdisk */,
+ 4D559463153DC808009F2584 /* dev_mkdb */,
+ 4D5593A5153CEA90009F2584 /* edquota */,
+ 4D559314153CE198009F2584 /* fdisk */,
+ 4D559340153CE41E009F2584 /* fsck */,
+ 4D559476153DC8FC009F2584 /* fstyp */,
+ 4D559489153DC98D009F2584 /* fstyp_msdos */,
+ 4D55949C153DC9FB009F2584 /* fstyp_ntfs */,
+ 4D5594AE153DCA53009F2584 /* fstyp_udf */,
+ 4D5594D4153DCC66009F2584 /* fuser */,
+ 4D55935F153CE561009F2584 /* mount */,
+ 4D55941B153DC383009F2584 /* mount_devfs */,
+ 4D55942F153DC49A009F2584 /* mount_fdesc */,
+ 4D5593B8153CEB7E009F2584 /* quota */,
+ 4D5593CC153CED29009F2584 /* quotacheck */,
+ 4D5593E3153CEE4A009F2584 /* quotaon */,
+ 4D559514153DE116009F2584 /* quotaoff */,
+ 4D5593F7153DC0DE009F2584 /* repquota */,
+ 4D5594C1153DCAFC009F2584 /* setclass */,
+ 4D55938D153CE7FD009F2584 /* umount */,
+ 4D55940A153DC27A009F2584 /* vndevice */,
+ 4D55944D153DC634009F2584 /* vsdbutil */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 4D5594E4153DCCD3009F2584 /* Copy fuser */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/fuser.tproj/fuser.pl",
+ );
+ name = "Copy fuser";
+ outputPaths = (
+ "$(DSTROOT)$(INSTALL_PATH)/fuser",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\ncp ${SCRIPT_INPUT_FILE_0} ${SCRIPT_OUTPUT_FILE_0}\nchmod 555 ${SCRIPT_OUTPUT_FILE_0}\n";
+ showEnvVarsInLog = 0;
+ };
+ 4D55951B153DE1EF009F2584 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/sbin/quotaon",
+ "$(DSTROOT)/usr/share/man/man8/quotaon.8",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/sbin/quotaoff",
+ "$(DSTROOT)/usr/share/man/man8/quotaoff.8",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man8\"\nln -fhv \"${SCRIPT_INPUT_FILE_1}\" \"${SCRIPT_OUTPUT_FILE_1}\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 4D07DD45153CA9A0002B57CB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D07DD57153CA9DC002B57CB /* dkcksum.c in Sources */,
+ 4D07DD5B153CA9DC002B57CB /* dksecsize.c in Sources */,
+ 4D07DD5F153CA9DC002B57CB /* preen.c in Sources */,
+ 4D07DD60153CA9DC002B57CB /* vfslist.c in Sources */,
+ 4D07DD58153CA9DC002B57CB /* dkdisklabel.c in Sources */,
+ 4D07DD59153CA9DC002B57CB /* dkopen.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559311153CE198009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D559333153CE1D9009F2584 /* cmd.c in Sources */,
+ 4D559334153CE1D9009F2584 /* disk.c in Sources */,
+ 4D559335153CE1D9009F2584 /* fdisk.c in Sources */,
+ 4D559336153CE1D9009F2584 /* getrawpartition.c in Sources */,
+ 4D559337153CE1D9009F2584 /* mbr.c in Sources */,
+ 4D559338153CE1D9009F2584 /* misc.c in Sources */,
+ 4D559339153CE1D9009F2584 /* opendev.c in Sources */,
+ 4D55933A153CE1D9009F2584 /* part.c in Sources */,
+ 4D55933B153CE1D9009F2584 /* user.c in Sources */,
+ 4D559332153CE1D9009F2584 /* auto.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55933D153CE41E009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B19B239C21C8DF660001F35C /* edt_fstab.c in Sources */,
+ 4D55934D153CE44E009F2584 /* fsck.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55935C153CE561009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B19B23A021C8DFA40001F35C /* edt_fstab.c in Sources */,
+ 07CE4C1821906BB800BF11C0 /* mount.c in Sources */,
+ 072AAAA62167CE8F004ED4E2 /* mount_flags.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55938A153CE7FD009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B19B23A221C8DFC30001F35C /* edt_fstab.c in Sources */,
+ 4D559399153CE826009F2584 /* umount.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593A2153CEA90009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D5593B2153CEABD009F2584 /* edquota.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593B5153CEB7E009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D5593C4153CEB9A009F2584 /* quota.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593C9153CED29009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D5593DD153CED51009F2584 /* quotacheck.c in Sources */,
+ 4D5593DC153CED51009F2584 /* hfs_quotacheck.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593E0153CEE4A009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D5593EF153CEE66009F2584 /* quotaon.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5593F4153DC0DE009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D559403153DC13D009F2584 /* repquota.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559407153DC27A009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D559417153DC2AB009F2584 /* vndevice.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559418153DC383009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D559428153DC3A6009F2584 /* mount_devfs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55942C153DC49A009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D55943D153DC4DE009F2584 /* mount_fdesc.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D55944A153DC634009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 078B970D2190682600674625 /* mount_flags.c in Sources */,
+ 4D55945A153DC650009F2584 /* vsdbutil_main.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559460153DC808009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D55946F153DC839009F2584 /* dev_mkdb.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559473153DC8FC009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D559482153DC912009F2584 /* fstyp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559486153DC98D009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D559495153DC9AE009F2584 /* fstyp_msdos.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D559499153DC9FB009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D5594AA153DCA19009F2584 /* fstyp_ntfs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5594AB153DCA53009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D5594BC153DCA74009F2584 /* fstyp_udf.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5594BE153DCAFC009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D5594CD153DCB72009F2584 /* setclass.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 4D5594D1153DCC66009F2584 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 071077D92488A09C003B97C7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5594C1153DCAFC009F2584 /* setclass */;
+ targetProxy = 071077D82488A09C003B97C7 /* PBXContainerItemProxy */;
+ };
+ 07747AA21DA8511D00ACE020 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D559476153DC8FC009F2584 /* fstyp */;
+ targetProxy = 07747AA11DA8511D00ACE020 /* PBXContainerItemProxy */;
+ };
+ 4D559357153CE4EA009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D07DD48153CA9A0002B57CB /* libdisk */;
+ targetProxy = 4D559356153CE4EA009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D559359153CE4EC009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D559314153CE198009F2584 /* fdisk */;
+ targetProxy = 4D559358153CE4EC009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D55935B153CE4ED009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D559340153CE41E009F2584 /* fsck */;
+ targetProxy = 4D55935A153CE4ED009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D559373153CE5F8009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55935F153CE561009F2584 /* mount */;
+ targetProxy = 4D559372153CE5F8009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D55939C153CE83A009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55938D153CE7FD009F2584 /* umount */;
+ targetProxy = 4D55939B153CE83A009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D55939F153CE8B6009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D07DD48153CA9A0002B57CB /* libdisk */;
+ targetProxy = 4D55939E153CE8B6009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D5593A1153CE8BC009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D07DD48153CA9A0002B57CB /* libdisk */;
+ targetProxy = 4D5593A0153CE8BC009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D559415153DC282009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55940A153DC27A009F2584 /* vndevice */;
+ targetProxy = 4D559414153DC282009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D559426153DC38F009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55941B153DC383009F2584 /* mount_devfs */;
+ targetProxy = 4D559425153DC38F009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D55943A153DC4C0009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55942F153DC49A009F2584 /* mount_fdesc */;
+ targetProxy = 4D559439153DC4C0009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D559447153DC597009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55934F153CE4CC009F2584 /* Common */;
+ targetProxy = 4D559446153DC597009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D559449153DC599009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55934F153CE4CC009F2584 /* Common */;
+ targetProxy = 4D559448153DC599009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D55945C153DC665009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55944D153DC634009F2584 /* vsdbutil */;
+ targetProxy = 4D55945B153DC665009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D559472153DC87B009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D559463153DC808009F2584 /* dev_mkdb */;
+ targetProxy = 4D559471153DC87B009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D559498153DC9E8009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D559489153DC98D009F2584 /* fstyp_msdos */;
+ targetProxy = 4D559497153DC9E8009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D5594A7153DCA04009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D55949C153DC9FB009F2584 /* fstyp_ntfs */;
+ targetProxy = 4D5594A6153DCA04009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D5594B9153DCA5E009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5594AE153DCA53009F2584 /* fstyp_udf */;
+ targetProxy = 4D5594B8153DCA5E009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D5594DF153DCC73009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5594D4153DCC66009F2584 /* fuser */;
+ targetProxy = 4D5594DE153DCC73009F2584 /* PBXContainerItemProxy */;
+ };
+ 4D55951A153DE1CB009F2584 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5593E3153CEE4A009F2584 /* quotaon */;
+ targetProxy = 4D559519153DE1CB009F2584 /* PBXContainerItemProxy */;
+ };
+ B12C9C9222A7CDE300B9F497 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5593A5153CEA90009F2584 /* edquota */;
+ targetProxy = B12C9C9122A7CDE300B9F497 /* PBXContainerItemProxy */;
+ };
+ B12C9C9422A7CDE300B9F497 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5593B8153CEB7E009F2584 /* quota */;
+ targetProxy = B12C9C9322A7CDE300B9F497 /* PBXContainerItemProxy */;
+ };
+ B12C9C9622A7CDE300B9F497 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5593CC153CED29009F2584 /* quotacheck */;
+ targetProxy = B12C9C9522A7CDE300B9F497 /* PBXContainerItemProxy */;
+ };
+ B12C9C9822A7CDE300B9F497 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5593E3153CEE4A009F2584 /* quotaon */;
+ targetProxy = B12C9C9722A7CDE300B9F497 /* PBXContainerItemProxy */;
+ };
+ B12C9C9A22A7CDE300B9F497 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D559514153DE116009F2584 /* quotaoff */;
+ targetProxy = B12C9C9922A7CDE300B9F497 /* PBXContainerItemProxy */;
+ };
+ B12C9C9C22A7CDE300B9F497 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D5593F7153DC0DE009F2584 /* repquota */;
+ targetProxy = B12C9C9B22A7CDE300B9F497 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 4D07DD3D153CA616002B57CB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_64_BIT)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ INSTALL_MODE_FLAG = "ugo-w,a+rX";
+ OTHER_CFLAGS = "";
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = Release;
+ };
+ 4D07DD4B153CA9A0002B57CB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ EXECUTABLE_PREFIX = lib;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ PRODUCT_NAME = disk;
+ SKIP_INSTALL = YES;
+ };
+ name = Release;
+ };
+ 4D55931D153CE199009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559349153CE41E009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(inherited) $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+ };
+ name = Release;
+ };
+ 4D559351153CE4CC009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559368153CE561009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = mount.tproj/mount.entitlements;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(inherited) $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks";
+ };
+ name = Release;
+ };
+ 4D559396153CE7FE009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(inherited) $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+ };
+ name = Release;
+ };
+ 4D5593AE153CEA90009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D5593C1153CEB7E009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D5593D5153CED29009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D5593EC153CEE4A009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559400153DC0DE009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559413153DC27A009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559424153DC384009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559438153DC49A009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559442153DC57D009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ OTHER_CFLAGS = "";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559445153DC587009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559456153DC634009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D55946C153DC808009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D55947F153DC8FC009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559492153DC98D009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D5594A5153DC9FB009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D5594B7153DCA53009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D5594CA153DCAFC009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D5594DD153DCC66009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 4D559516153DE116009F2584 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 4D07DD2E153CA616002B57CB /* Build configuration list for PBXProject "diskdev_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D07DD3D153CA616002B57CB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D07DD4A153CA9A0002B57CB /* Build configuration list for PBXNativeTarget "libdisk" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D07DD4B153CA9A0002B57CB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D55931C153CE199009F2584 /* Build configuration list for PBXNativeTarget "fdisk" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D55931D153CE199009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559348153CE41E009F2584 /* Build configuration list for PBXNativeTarget "fsck" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559349153CE41E009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559350153CE4CC009F2584 /* Build configuration list for PBXAggregateTarget "Common" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559351153CE4CC009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559367153CE561009F2584 /* Build configuration list for PBXNativeTarget "mount" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559368153CE561009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559395153CE7FE009F2584 /* Build configuration list for PBXNativeTarget "umount" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559396153CE7FE009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5593AD153CEA90009F2584 /* Build configuration list for PBXNativeTarget "edquota" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D5593AE153CEA90009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5593C0153CEB7E009F2584 /* Build configuration list for PBXNativeTarget "quota" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D5593C1153CEB7E009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5593D4153CED29009F2584 /* Build configuration list for PBXNativeTarget "quotacheck" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D5593D5153CED29009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5593EB153CEE4A009F2584 /* Build configuration list for PBXNativeTarget "quotaon" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D5593EC153CEE4A009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5593FF153DC0DE009F2584 /* Build configuration list for PBXNativeTarget "repquota" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559400153DC0DE009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559412153DC27A009F2584 /* Build configuration list for PBXNativeTarget "vndevice" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559413153DC27A009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559423153DC384009F2584 /* Build configuration list for PBXNativeTarget "mount_devfs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559424153DC384009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559437153DC49A009F2584 /* Build configuration list for PBXNativeTarget "mount_fdesc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559438153DC49A009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559441153DC57D009F2584 /* Build configuration list for PBXAggregateTarget "All_MacOSX" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559442153DC57D009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559444153DC587009F2584 /* Build configuration list for PBXAggregateTarget "All_iOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559445153DC587009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559455153DC634009F2584 /* Build configuration list for PBXNativeTarget "vsdbutil" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559456153DC634009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D55946B153DC808009F2584 /* Build configuration list for PBXNativeTarget "dev_mkdb" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D55946C153DC808009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D55947E153DC8FC009F2584 /* Build configuration list for PBXNativeTarget "fstyp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D55947F153DC8FC009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559491153DC98D009F2584 /* Build configuration list for PBXNativeTarget "fstyp_msdos" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559492153DC98D009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5594A4153DC9FB009F2584 /* Build configuration list for PBXNativeTarget "fstyp_ntfs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D5594A5153DC9FB009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5594B6153DCA53009F2584 /* Build configuration list for PBXNativeTarget "fstyp_udf" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D5594B7153DCA53009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5594C9153DCAFC009F2584 /* Build configuration list for PBXNativeTarget "setclass" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D5594CA153DCAFC009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D5594DC153DCC66009F2584 /* Build configuration list for PBXNativeTarget "fuser" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D5594DD153DCC66009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 4D559515153DE116009F2584 /* Build configuration list for PBXAggregateTarget "quotaoff" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D559516153DE116009F2584 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 4D07DD2B153CA616002B57CB /* Project object */;
+}
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/diskdev_cmds/diskdev_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..e0c148d
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:diskdev_cmds.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/diskdev_cmds/diskdev_cmds.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..08de0be
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
+ <false/>
+</dict>
+</plist>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/All_MacOSX.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/All_MacOSX.xcscheme
new file mode 100644
index 0000000..844c24e
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/All_MacOSX.xcscheme
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559440153DC57D009F2584"
+ BuildableName = "All_MacOSX"
+ BlueprintName = "All_MacOSX"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/All_iOS.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/All_iOS.xcscheme
new file mode 100644
index 0000000..1b41173
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/All_iOS.xcscheme
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559443153DC587009F2584"
+ BuildableName = "All_iOS"
+ BlueprintName = "All_iOS"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/Common.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/Common.xcscheme
new file mode 100644
index 0000000..d077a0a
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/Common.xcscheme
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55934F153CE4CC009F2584"
+ BuildableName = "Common"
+ BlueprintName = "Common"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/dev_mkdb.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/dev_mkdb.xcscheme
new file mode 100644
index 0000000..da3f116
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/dev_mkdb.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559463153DC808009F2584"
+ BuildableName = "dev_mkdb"
+ BlueprintName = "dev_mkdb"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559463153DC808009F2584"
+ BuildableName = "dev_mkdb"
+ BlueprintName = "dev_mkdb"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559463153DC808009F2584"
+ BuildableName = "dev_mkdb"
+ BlueprintName = "dev_mkdb"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559463153DC808009F2584"
+ BuildableName = "dev_mkdb"
+ BlueprintName = "dev_mkdb"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/edquota.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/edquota.xcscheme
new file mode 100644
index 0000000..aac4a1c
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/edquota.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593A5153CEA90009F2584"
+ BuildableName = "edquota"
+ BlueprintName = "edquota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593A5153CEA90009F2584"
+ BuildableName = "edquota"
+ BlueprintName = "edquota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593A5153CEA90009F2584"
+ BuildableName = "edquota"
+ BlueprintName = "edquota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593A5153CEA90009F2584"
+ BuildableName = "edquota"
+ BlueprintName = "edquota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fdisk.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fdisk.xcscheme
new file mode 100644
index 0000000..23af6d2
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fdisk.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559314153CE198009F2584"
+ BuildableName = "fdisk"
+ BlueprintName = "fdisk"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559314153CE198009F2584"
+ BuildableName = "fdisk"
+ BlueprintName = "fdisk"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559314153CE198009F2584"
+ BuildableName = "fdisk"
+ BlueprintName = "fdisk"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559314153CE198009F2584"
+ BuildableName = "fdisk"
+ BlueprintName = "fdisk"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fsck.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fsck.xcscheme
new file mode 100644
index 0000000..5405e97
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fsck.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559340153CE41E009F2584"
+ BuildableName = "fsck"
+ BlueprintName = "fsck"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559340153CE41E009F2584"
+ BuildableName = "fsck"
+ BlueprintName = "fsck"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559340153CE41E009F2584"
+ BuildableName = "fsck"
+ BlueprintName = "fsck"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559340153CE41E009F2584"
+ BuildableName = "fsck"
+ BlueprintName = "fsck"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp.xcscheme
new file mode 100644
index 0000000..7e5ae37
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559476153DC8FC009F2584"
+ BuildableName = "fstyp"
+ BlueprintName = "fstyp"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559476153DC8FC009F2584"
+ BuildableName = "fstyp"
+ BlueprintName = "fstyp"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559476153DC8FC009F2584"
+ BuildableName = "fstyp"
+ BlueprintName = "fstyp"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559476153DC8FC009F2584"
+ BuildableName = "fstyp"
+ BlueprintName = "fstyp"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_msdos.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_msdos.xcscheme
new file mode 100644
index 0000000..7135b78
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_msdos.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559489153DC98D009F2584"
+ BuildableName = "fstyp_msdos"
+ BlueprintName = "fstyp_msdos"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559489153DC98D009F2584"
+ BuildableName = "fstyp_msdos"
+ BlueprintName = "fstyp_msdos"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559489153DC98D009F2584"
+ BuildableName = "fstyp_msdos"
+ BlueprintName = "fstyp_msdos"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D559489153DC98D009F2584"
+ BuildableName = "fstyp_msdos"
+ BlueprintName = "fstyp_msdos"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_ntfs.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_ntfs.xcscheme
new file mode 100644
index 0000000..144c15c
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_ntfs.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55949C153DC9FB009F2584"
+ BuildableName = "fstyp_ntfs"
+ BlueprintName = "fstyp_ntfs"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55949C153DC9FB009F2584"
+ BuildableName = "fstyp_ntfs"
+ BlueprintName = "fstyp_ntfs"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55949C153DC9FB009F2584"
+ BuildableName = "fstyp_ntfs"
+ BlueprintName = "fstyp_ntfs"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55949C153DC9FB009F2584"
+ BuildableName = "fstyp_ntfs"
+ BlueprintName = "fstyp_ntfs"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_udf.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_udf.xcscheme
new file mode 100644
index 0000000..8cb1245
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fstyp_udf.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594AE153DCA53009F2584"
+ BuildableName = "fstyp_udf"
+ BlueprintName = "fstyp_udf"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594AE153DCA53009F2584"
+ BuildableName = "fstyp_udf"
+ BlueprintName = "fstyp_udf"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594AE153DCA53009F2584"
+ BuildableName = "fstyp_udf"
+ BlueprintName = "fstyp_udf"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594AE153DCA53009F2584"
+ BuildableName = "fstyp_udf"
+ BlueprintName = "fstyp_udf"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fuser.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fuser.xcscheme
new file mode 100644
index 0000000..db85539
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/fuser.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594D4153DCC66009F2584"
+ BuildableName = "fuser"
+ BlueprintName = "fuser"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594D4153DCC66009F2584"
+ BuildableName = "fuser"
+ BlueprintName = "fuser"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594D4153DCC66009F2584"
+ BuildableName = "fuser"
+ BlueprintName = "fuser"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594D4153DCC66009F2584"
+ BuildableName = "fuser"
+ BlueprintName = "fuser"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/libdisk.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/libdisk.xcscheme
new file mode 100644
index 0000000..0f60716
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/libdisk.xcscheme
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D07DD48153CA9A0002B57CB"
+ BuildableName = "libdisk.a"
+ BlueprintName = "libdisk"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount.xcscheme
new file mode 100644
index 0000000..6a53cec
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55935F153CE561009F2584"
+ BuildableName = "mount"
+ BlueprintName = "mount"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55935F153CE561009F2584"
+ BuildableName = "mount"
+ BlueprintName = "mount"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55935F153CE561009F2584"
+ BuildableName = "mount"
+ BlueprintName = "mount"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55935F153CE561009F2584"
+ BuildableName = "mount"
+ BlueprintName = "mount"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount_devfs.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount_devfs.xcscheme
new file mode 100644
index 0000000..246cbba
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount_devfs.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55941B153DC383009F2584"
+ BuildableName = "mount_devfs"
+ BlueprintName = "mount_devfs"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55941B153DC383009F2584"
+ BuildableName = "mount_devfs"
+ BlueprintName = "mount_devfs"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55941B153DC383009F2584"
+ BuildableName = "mount_devfs"
+ BlueprintName = "mount_devfs"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55941B153DC383009F2584"
+ BuildableName = "mount_devfs"
+ BlueprintName = "mount_devfs"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount_fdesc.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount_fdesc.xcscheme
new file mode 100644
index 0000000..dad5f9a
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/mount_fdesc.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55942F153DC49A009F2584"
+ BuildableName = "mount_fdesc"
+ BlueprintName = "mount_fdesc"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55942F153DC49A009F2584"
+ BuildableName = "mount_fdesc"
+ BlueprintName = "mount_fdesc"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55942F153DC49A009F2584"
+ BuildableName = "mount_fdesc"
+ BlueprintName = "mount_fdesc"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55942F153DC49A009F2584"
+ BuildableName = "mount_fdesc"
+ BlueprintName = "mount_fdesc"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quota.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quota.xcscheme
new file mode 100644
index 0000000..df303b9
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quota.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593B8153CEB7E009F2584"
+ BuildableName = "quota"
+ BlueprintName = "quota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593B8153CEB7E009F2584"
+ BuildableName = "quota"
+ BlueprintName = "quota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593B8153CEB7E009F2584"
+ BuildableName = "quota"
+ BlueprintName = "quota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593B8153CEB7E009F2584"
+ BuildableName = "quota"
+ BlueprintName = "quota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quotacheck.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quotacheck.xcscheme
new file mode 100644
index 0000000..48bf0e6
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quotacheck.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593CC153CED29009F2584"
+ BuildableName = "quotacheck"
+ BlueprintName = "quotacheck"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593CC153CED29009F2584"
+ BuildableName = "quotacheck"
+ BlueprintName = "quotacheck"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593CC153CED29009F2584"
+ BuildableName = "quotacheck"
+ BlueprintName = "quotacheck"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593CC153CED29009F2584"
+ BuildableName = "quotacheck"
+ BlueprintName = "quotacheck"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quotaon.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quotaon.xcscheme
new file mode 100644
index 0000000..1a5fcda
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/quotaon.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593E3153CEE4A009F2584"
+ BuildableName = "quotaon"
+ BlueprintName = "quotaon"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593E3153CEE4A009F2584"
+ BuildableName = "quotaon"
+ BlueprintName = "quotaon"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593E3153CEE4A009F2584"
+ BuildableName = "quotaon"
+ BlueprintName = "quotaon"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593E3153CEE4A009F2584"
+ BuildableName = "quotaon"
+ BlueprintName = "quotaon"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/repquota.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/repquota.xcscheme
new file mode 100644
index 0000000..75149cf
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/repquota.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593F7153DC0DE009F2584"
+ BuildableName = "repquota"
+ BlueprintName = "repquota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593F7153DC0DE009F2584"
+ BuildableName = "repquota"
+ BlueprintName = "repquota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593F7153DC0DE009F2584"
+ BuildableName = "repquota"
+ BlueprintName = "repquota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5593F7153DC0DE009F2584"
+ BuildableName = "repquota"
+ BlueprintName = "repquota"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/setclass.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/setclass.xcscheme
new file mode 100644
index 0000000..b249cf1
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/setclass.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594C1153DCAFC009F2584"
+ BuildableName = "setclass"
+ BlueprintName = "setclass"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594C1153DCAFC009F2584"
+ BuildableName = "setclass"
+ BlueprintName = "setclass"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594C1153DCAFC009F2584"
+ BuildableName = "setclass"
+ BlueprintName = "setclass"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D5594C1153DCAFC009F2584"
+ BuildableName = "setclass"
+ BlueprintName = "setclass"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/umount.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/umount.xcscheme
new file mode 100644
index 0000000..51ffb5d
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/umount.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55938D153CE7FD009F2584"
+ BuildableName = "umount"
+ BlueprintName = "umount"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55938D153CE7FD009F2584"
+ BuildableName = "umount"
+ BlueprintName = "umount"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55938D153CE7FD009F2584"
+ BuildableName = "umount"
+ BlueprintName = "umount"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55938D153CE7FD009F2584"
+ BuildableName = "umount"
+ BlueprintName = "umount"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/vndevice.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/vndevice.xcscheme
new file mode 100644
index 0000000..5bb5059
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/vndevice.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55940A153DC27A009F2584"
+ BuildableName = "vndevice"
+ BlueprintName = "vndevice"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55940A153DC27A009F2584"
+ BuildableName = "vndevice"
+ BlueprintName = "vndevice"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55940A153DC27A009F2584"
+ BuildableName = "vndevice"
+ BlueprintName = "vndevice"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55940A153DC27A009F2584"
+ BuildableName = "vndevice"
+ BlueprintName = "vndevice"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/vsdbutil.xcscheme b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/vsdbutil.xcscheme
new file mode 100644
index 0000000..6e7d1c4
--- /dev/null
+++ b/diskdev_cmds/diskdev_cmds.xcodeproj/xcshareddata/xcschemes/vsdbutil.xcscheme
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "YES">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55944D153DC634009F2584"
+ BuildableName = "vsdbutil"
+ BlueprintName = "vsdbutil"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ buildConfiguration = "Release">
+ <Testables>
+ </Testables>
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55944D153DC634009F2584"
+ BuildableName = "vsdbutil"
+ BlueprintName = "vsdbutil"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </TestAction>
+ <LaunchAction
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ allowLocationSimulation = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55944D153DC634009F2584"
+ BuildableName = "vsdbutil"
+ BlueprintName = "vsdbutil"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ buildConfiguration = "Release"
+ debugDocumentVersioning = "YES">
+ <BuildableProductRunnable>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "4D55944D153DC634009F2584"
+ BuildableName = "vsdbutil"
+ BlueprintName = "vsdbutil"
+ ReferencedContainer = "container:diskdev_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildableProductRunnable>
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release">
+ </InstallAction>
+</Scheme>
diff --git a/diskdev_cmds/disklib/dkcksum.c b/diskdev_cmds/disklib/dkcksum.c
new file mode 100644
index 0000000..e275cb2
--- /dev/null
+++ b/diskdev_cmds/disklib/dkcksum.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/types.h>
+
+#if defined (linux) && defined (__powerpc__)
+#define __ppc__
+#endif
+
+#include <sys/disklabel.h>
+
+u_short
+dkcksum(lp)
+ register struct disklabel *lp;
+{
+ register u_short *start, *end;
+ register u_short sum = 0;
+
+ start = (u_short *)lp;
+ end = (u_short *)&lp->d_partitions[lp->d_npartitions];
+ while (start < end)
+ sum ^= *start++;
+ return (sum);
+}
diff --git a/diskdev_cmds/disklib/dkdisklabel.c b/diskdev_cmds/disklib/dkdisklabel.c
new file mode 100644
index 0000000..3fffce5
--- /dev/null
+++ b/diskdev_cmds/disklib/dkdisklabel.c
@@ -0,0 +1,193 @@
+/* Copyright 1999 Apple Computer, Inc.
+ *
+ * Generate a bsd disk label routine.
+ * Input: open file descriptor to the device node, and
+ * pointer to a disk label structure to fill in
+ * Return: errno status
+ *
+ * HISTORY
+ *
+ * 24 Feb 1999 D. Markarian at Apple
+ * Created.
+ */
+
+#include <string.h> /* memset */
+#include <sys/types.h> /* sys/disklabel.h */
+#include <sys/param.h> /* NBPG */
+
+#include <sys/disk.h> /* DKIOCGETBLOCKSIZE ioctl */
+
+#include <sys/disklabel.h> /* struct disklabel */
+
+u_short dkcksum __P((register struct disklabel *lp));
+int dkdisklabelregenerate __P((int fd, struct disklabel * lp, int newblksize));
+
+/*
+ * The following two constants set the default block and fragment sizes.
+ * Both constants must be a power of 2 and meet the following constraints:
+ * MINBSIZE <= GENBLKSIZE <= MAXBSIZE
+ * sectorsize <= GENFRAGSIZE <= GENBLKSIZE
+ * GENBLKSIZE / GENFRAGSIZE <= 8
+ */
+#define GENFRAGSIZE 1024
+#define GENBLKSIZE NBPG /* 4096 */
+
+/*
+ * Cylinder groups may have up to many cylinders. The actual
+ * number used depends upon how much information can be stored
+ * on a single cylinder. The default is to use 16 cylinders
+ * per group.
+ */
+#define GENCPG 16
+
+/*
+ * Interleave is physical sector interleave, set up by the
+ * formatter or controller when formatting. When interleaving is
+ * in use, logically adjacent sectors are not physically
+ * contiguous, but instead are separated by some number of
+ * sectors. It is specified as the ratio of physical sectors
+ * traversed per logical sector. Thus an interleave of 1:1
+ * implies contiguous layout, while 2:1 implies that logical
+ * sector 0 is separated by one sector from logical sector 1.
+ */
+#define GENINTERLEAVE 1
+
+/*
+ * Rotational speed; # of data sectors per track.
+ */
+#define GENRPM 3600
+#define GENNSECTORS 32
+
+int dkdisklabel(int fd, struct disklabel * lp)
+{
+ return dkdisklabelregenerate(fd, lp, 0);
+}
+
+int dkdisklabelregenerate(int fd, struct disklabel * lp, int newblksize)
+{
+ /*
+ * Generate a bsd-style disk label for the specified device node.
+ */
+
+ int blksize;
+ int error;
+ int index;
+ int64_t numblks;
+
+ /* obtain the size of the media (in blocks) */
+ if ( (error = ioctl(fd, DKIOCGETBLOCKCOUNT, &numblks)) < 0 )
+ return(error);
+
+ /* obtain the block size of the media */
+ if ( (error = ioctl(fd, DKIOCGETBLOCKSIZE, &blksize)) < 0 )
+ return(error);
+
+ /* adjust the size of the media with newblksize should it be specified */
+ if (newblksize)
+ {
+ numblks = ((numblks * blksize) / newblksize);
+ blksize = newblksize;
+ }
+
+ /*
+ * clear the disk label structure and then fill in the appropriate fields;
+ * we comment out lines that are initializations to zero with //, since it
+ * is redundant work
+ */
+ memset(lp, 0, sizeof(struct disklabel));
+
+ lp->d_magic = DISKMAGIC; /* the magic number */
+// lp->d_type = 0; /* drive type */
+// lp->d_subtype = 0; /* controller/d_type specific */
+// lp->d_typename[0] = 0; /* type name, e.g. "eagle" */
+ /*
+ * d_packname contains the pack identifier and is returned when
+ * the disklabel is read off the disk or in-core copy.
+ * d_boot0 and d_boot1 are the (optional) names of the
+ * primary (block 0) and secondary (block 1-15) bootstraps
+ * as found in /usr/mdec. These are returned when using
+ * getdiskbyname(3) to retrieve the values from /etc/disktab.
+ */
+// lp->d_packname[0] = 0; /* pack identifier */
+
+ /* disk geometry: */
+ lp->d_secsize = blksize; /* # of bytes per sector */
+ lp->d_nsectors = GENNSECTORS; /* # of data sectors per track */
+ /* # of tracks per cylinder */
+ if (numblks < 8*32*1024) /* <=528.4 MB */
+ lp->d_ntracks = 16;
+ else if (numblks < 16*32*1024) /* <=1.057 GB */
+ lp->d_ntracks = 32;
+ else if (numblks < 32*32*1024) /* <=2.114 GB */
+ lp->d_ntracks = 54;
+ else if (numblks < 64*32*1024) /* <=4.228 GB */
+ lp->d_ntracks = 128;
+ else /* > 4.228 GB */
+ lp->d_ntracks = 255;
+ /* # of data cylinders per unit */
+ lp->d_ncylinders = numblks / lp->d_ntracks / lp->d_nsectors;
+ /* # of data sectors per cylinder */
+ lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
+ lp->d_secperunit = numblks; /* # of data sectors per unit */
+ /*
+ * Spares (bad sector replacements) below are not counted in
+ * d_nsectors or d_secpercyl. Spare sectors are assumed to
+ * be physical sectors which occupy space at the end of each
+ * track and/or cylinder.
+ */
+// lp->d_sparespertrack = 0; /* # of spare sectors per track */
+// lp->d_sparespercyl = 0; /* # of data sectors per unit */
+ /*
+ * Alternate cylinders include maintenance, replacement, configuration
+ * description areas, etc.
+ */
+// lp->d_acylinders = 0; /* # of alt. cylinders per unit */
+
+ /* hardware characteristics: */
+ /*
+ * d_interleave, d_trackskew and d_cylskew describe perturbations
+ * in the media format used to compensate for a slow controller.
+ * Interleave is physical sector interleave, set up by the
+ * formatter or controller when formatting. When interleaving is
+ * in use, logically adjacent sectors are not physically
+ * contiguous, but instead are separated by some number of
+ * sectors. It is specified as the ratio of physical sectors
+ * traversed per logical sector. Thus an interleave of 1:1
+ * implies contiguous layout, while 2:1 implies that logical
+ * sector 0 is separated by one sector from logical sector 1.
+ * d_trackskew is the offset of sector 0 on track N relative to
+ * sector 0 on track N-1 on the same cylinder. Finally, d_cylskew
+ * is the offset of sector 0 on cylinder N relative to sector 0
+ * on cylinder N-1.
+ */
+ lp->d_rpm = GENRPM; /* rotational speed */
+ lp->d_interleave = GENINTERLEAVE; /* hardware sector interleave */
+// lp->d_trackskew = 0; /* sector 0 skew, per track */
+// lp->d_cylskew = 0; /* sector 0 skew, per cylinder */
+// lp->d_headswitch = 0; /* head switch time, usec */
+// lp->d_trkseek = 0; /* track-to-track seek, usec */
+// lp->d_flags = 0; /* generic flags */
+// lp->d_drivedata[0-4] = 0; /* drive-type specific information */
+// lp->d_spare[0-4] = 0; /* reserved for future use */
+ lp->d_magic2 = DISKMAGIC; /* the magic number (again) */
+// lp->d_checksum = 0; /* xor of data incl. partitions */
+
+ /* filesystem and partition information: */
+ lp->d_npartitions = MAXPARTITIONS; /* number of partitions */
+
+ for (index = 0; index < MAXPARTITIONS; index++)
+ {
+ struct partition * pp = &(lp->d_partitions[index]);
+ pp->p_size = numblks; /* number of sectors */
+// pp->p_offset = 0; /* starting sector */
+ pp->p_fsize = MAX(GENFRAGSIZE, blksize); /* fs fragment size */
+ pp->p_fstype = FS_BSDFFS; /* fs type */
+ pp->p_frag = MIN(8, GENBLKSIZE / pp->p_fsize);/* fs fragments/block */
+ pp->p_cpg = GENCPG; /* fs cylinders/group */
+ }
+
+ /* compute a checksum on the resulting structure */
+ lp->d_checksum = dkcksum(lp);
+
+ return 0; /* success */
+}
diff --git a/diskdev_cmds/disklib/dkopen.c b/diskdev_cmds/disklib/dkopen.c
new file mode 100644
index 0000000..7a94561
--- /dev/null
+++ b/diskdev_cmds/disklib/dkopen.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "dkopen.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int dkopen (const char *path, int flags, int mode)
+{
+#if defined (linux)
+ return (open64 (path, flags, mode));
+#elif defined (__APPLE__)
+ return (open (path, flags, mode));
+#endif
+}
+
+int dkclose (int filedes)
+{
+#if defined (linux)
+ return (close (filedes));
+#elif defined (__APPLE__)
+ return (close (filedes));
+#endif
+}
+
+off64_t dklseek (int filedes, off64_t offset, int whence)
+{
+#if defined (linux)
+ return (lseek64 (filedes, offset, whence));
+#elif defined (__APPLE__)
+ return (lseek (filedes, offset, whence));
+#endif
+}
+
diff --git a/diskdev_cmds/disklib/dkopen.h b/diskdev_cmds/disklib/dkopen.h
new file mode 100644
index 0000000..eb0bdeb
--- /dev/null
+++ b/diskdev_cmds/disklib/dkopen.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * File I/O stubs
+ *
+ * Linux and other OSs may use open64, lseek64 instead of defaulting off_t to
+ * 64-bits like OSX does. This file provides cover functions to always perform
+ * 64-bit file I/O.
+ */
+
+#ifndef _DKOPEN_H_
+#define _DKOPEN_H_
+
+/* Must predefine the large file flags before including sys/types.h */
+#if defined (linux)
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+#elif defined (__APPLE__)
+#else
+#error Platform not recognized
+#endif
+
+#include <sys/types.h>
+
+/* Typedef off64_t for platforms that don't have it declared */
+#if defined (__APPLE__) && !defined (linux)
+typedef u_int64_t off64_t;
+#endif
+
+int dkopen (const char *path, int flags, int mode);
+int dkclose (int filedes);
+
+off64_t dklseek (int fileds, off64_t offset, int whence);
+
+#endif
diff --git a/diskdev_cmds/disklib/dksecsize.c b/diskdev_cmds/disklib/dksecsize.c
new file mode 100644
index 0000000..0cfad82
--- /dev/null
+++ b/diskdev_cmds/disklib/dksecsize.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* Copyright 1998 Apple Computer, Inc.
+ *
+ * Get disk label's sector size routine.
+ * Input: pointer to a block device string ie: "/dev/disk1s1"
+ * Return: sector size from the disk label
+ *
+ * HISTORY
+ *
+ * 27 May 1998 K. Crippes at Apple
+ * Rhapsody version created.
+ * 18 Feb 1999 D. Markarian at Apple
+ * DKIOCGLABEL deprecated; using DKIOCBLKSIZE instead, which now returns
+ * the appropriate size for ufs partitions created with wierd block sizes.
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/disk.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+char *blockcheck __P((char *));
+
+long dksecsize (dev)
+ char *dev;
+{
+ int fd; /* file descriptor for reading device label */
+ char *cdev;
+ int devblklen;
+ extern int errno;
+
+ /* Convert block device into a character device string */
+ if ((cdev = blockcheck(dev))) {
+ if ((fd = open(cdev, O_RDONLY)) < 0) {
+ fprintf(stderr, "Can't open %s, %s\n", cdev, strerror(errno));
+ return (0);
+ }
+ }
+ else
+ return (0);
+
+ if (ioctl(fd, DKIOCGETBLOCKSIZE, &devblklen) < 0) {
+ (void)close(fd);
+ return (0);
+ }
+ else {
+ (void)close(fd);
+ return (devblklen);
+ }
+}
+
diff --git a/diskdev_cmds/disklib/pathnames.h b/diskdev_cmds/disklib/pathnames.h
new file mode 100644
index 0000000..59cd945
--- /dev/null
+++ b/diskdev_cmds/disklib/pathnames.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/5/93
+ */
+
+#include <paths.h>
+
+#define _PATH_DTMP "/etc/dtmp"
+#define _PATH_DUMPDATES "/etc/dumpdates"
+#define _PATH_LOCK "/tmp/dumplockXXXXXX"
+#define _PATH_RMT "rmt"
diff --git a/diskdev_cmds/disklib/preen.c b/diskdev_cmds/disklib/preen.c
new file mode 100644
index 0000000..f7128e0
--- /dev/null
+++ b/diskdev_cmds/disklib/preen.c
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <fstab.h>
+#include <string.h>
+#include <TargetConditionals.h>
+
+#if TARGET_OS_OSX
+struct part {
+ struct part *next; /* forward link of partitions on disk */
+ char *name; /* device name */
+ char *fsname; /* mounted filesystem name */
+ long auxdata; /* auxillary data for application */
+} *badlist, **badnext = &badlist;
+
+struct disk {
+ char *name; /* disk base name */
+ struct disk *next; /* forward link for list of disks */
+ struct part *part; /* head of list of partitions on disk */
+ int pid; /* If != 0, pid of proc working on */
+} *disks;
+
+int nrun, ndisks;
+char hotroot;
+
+static void addpart (char *name, char *fsname, long auxdata);
+static struct disk *finddisk (char *name);
+static char *rawname (char *name);
+static int startdisk (struct disk *dk,
+ int (*checkit)(char *, char *, long, int));
+static char *unrawname (char *name);
+char* blockcheck (char *name);
+
+int
+checkfstab(preen, maxrun, docheck, chkit)
+ int preen;
+ int maxrun;
+ int (*docheck)(struct fstab *);
+ int (*chkit)(char *, char *, long, int);
+{
+ register struct fstab *fsp;
+ register struct disk *dk, *nextdisk;
+ register struct part *pt;
+ int ret, pid, retcode, passno, sumstatus, status;
+ long auxdata;
+ char *name;
+
+ sumstatus = 0;
+ for (passno = 1; passno <= 2; passno++) {
+ if (setfsent() == 0) {
+ fprintf(stderr, "Can't open checklist file: %s\n",
+ _PATH_FSTAB);
+ return (8);
+ }
+ while ((fsp = getfsent()) != 0) {
+ if ((auxdata = (*docheck)(fsp)) == 0)
+ continue;
+ if (preen == 0 ||
+ (passno == 1 && fsp->fs_passno == 1)) {
+ if ((name = blockcheck(fsp->fs_spec)) != 0) {
+ if ((sumstatus = (*chkit)(name,
+ fsp->fs_file, auxdata, 0)) != 0)
+ return (sumstatus);
+ } else if (preen)
+ return (8);
+ } else if (passno == 2 && fsp->fs_passno > 1) {
+ if ((name = blockcheck(fsp->fs_spec)) == NULL) {
+ fprintf(stderr, "BAD DISK NAME %s\n",
+ fsp->fs_spec);
+ sumstatus |= 8;
+ continue;
+ }
+ addpart(name, fsp->fs_file, auxdata);
+ }
+ }
+ if (preen == 0)
+ return (0);
+ }
+ if (preen) {
+ if (maxrun == 0)
+ maxrun = ndisks;
+ if (maxrun > ndisks)
+ maxrun = ndisks;
+ nextdisk = disks;
+ for (passno = 0; passno < maxrun; ++passno) {
+ while ((ret = startdisk(nextdisk, chkit)) && nrun > 0)
+ sleep(10);
+ if (ret)
+ return (ret);
+ nextdisk = nextdisk->next;
+ }
+ while ((pid = wait(&status)) != -1) {
+ for (dk = disks; dk; dk = dk->next)
+ if (dk->pid == pid)
+ break;
+ if (dk == 0) {
+ printf("Unknown pid %d\n", pid);
+ continue;
+ }
+ if (WIFEXITED(status))
+ retcode = WEXITSTATUS(status);
+ else
+ retcode = 0;
+ if (WIFSIGNALED(status)) {
+ printf("%s (%s): EXITED WITH SIGNAL %d\n",
+ dk->part->name, dk->part->fsname,
+ WTERMSIG(status));
+ retcode = 8;
+ }
+ if (retcode != 0) {
+ sumstatus |= retcode;
+ *badnext = dk->part;
+ badnext = &dk->part->next;
+ dk->part = dk->part->next;
+ *badnext = NULL;
+ } else
+ dk->part = dk->part->next;
+ dk->pid = 0;
+ nrun--;
+ if (dk->part == NULL)
+ ndisks--;
+
+ if (nextdisk == NULL) {
+ if (dk->part) {
+ while ((ret = startdisk(dk, chkit)) &&
+ nrun > 0)
+ sleep(10);
+ if (ret)
+ return (ret);
+ }
+ } else if (nrun < maxrun && nrun < ndisks) {
+ for ( ;; ) {
+ if ((nextdisk = nextdisk->next) == NULL)
+ nextdisk = disks;
+ if (nextdisk->part != NULL &&
+ nextdisk->pid == 0)
+ break;
+ }
+ while ((ret = startdisk(nextdisk, chkit)) &&
+ nrun > 0)
+ sleep(10);
+ if (ret)
+ return (ret);
+ }
+ }
+ }
+ if (sumstatus) {
+ if (badlist == 0)
+ return (sumstatus);
+ fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
+ badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
+ for (pt = badlist; pt; pt = pt->next)
+ fprintf(stderr, "%s (%s)%s", pt->name, pt->fsname,
+ pt->next ? ", " : "\n");
+ return (sumstatus);
+ }
+ (void)endfsent();
+ return (0);
+}
+
+static struct disk *
+finddisk(name)
+ char *name;
+{
+ register struct disk *dk, **dkp;
+ register char *p;
+ size_t len;
+
+ for (len = strlen(name), p = name + len - 1; p >= name; --p)
+ if (isdigit(*p)) {
+ len = p - name + 1;
+ break;
+ }
+
+ for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
+ if (strncmp(dk->name, name, len) == 0 &&
+ dk->name[len] == 0)
+ return (dk);
+ }
+ if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ dk = *dkp;
+ if ((dk->name = malloc(len + 1)) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ (void)strncpy(dk->name, name, len);
+ dk->name[len] = '\0';
+ dk->part = NULL;
+ dk->next = NULL;
+ dk->pid = 0;
+ ndisks++;
+ return (dk);
+}
+
+static void
+addpart(name, fsname, auxdata)
+ char *name, *fsname;
+ long auxdata;
+{
+ struct disk *dk = finddisk(name);
+ register struct part *pt, **ppt = &dk->part;
+
+ for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
+ if (strcmp(pt->name, name) == 0) {
+ printf("%s in fstab more than once!\n", name);
+ return;
+ }
+ if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ pt = *ppt;
+ if ((pt->name = strdup(name)) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ if ((pt->fsname = strdup(fsname)) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ pt->next = NULL;
+ pt->auxdata = auxdata;
+}
+
+static int
+startdisk(dk, checkit)
+ register struct disk *dk;
+ int (*checkit)(char *, char *, long, int);
+{
+ register struct part *pt = dk->part;
+
+ dk->pid = fork();
+ if (dk->pid < 0) {
+ perror("fork");
+ return (8);
+ }
+ if (dk->pid == 0)
+ exit((*checkit)(pt->name, pt->fsname, pt->auxdata, 1));
+ nrun++;
+ return (0);
+}
+
+char *
+blockcheck(char* origname) {
+ struct stat stslash, stblock, stchar;
+ char *newname, *raw;
+ int retried = 0;
+
+ hotroot = 0;
+ if (stat("/", &stslash) < 0) {
+ perror("/");
+ printf("Can't stat root\n");
+ return (origname);
+ }
+ newname = origname;
+retry:
+ if (stat(newname, &stblock) < 0) {
+ perror(newname);
+ printf("Can't stat %s\n", newname);
+ return (origname);
+ }
+ if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
+ if (stslash.st_dev == stblock.st_rdev)
+ hotroot++;
+ raw = rawname(newname);
+ if (stat(raw, &stchar) < 0) {
+ perror(raw);
+ printf("Can't stat %s\n", raw);
+ return (origname);
+ }
+ if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
+ return (raw);
+ } else {
+ printf("%s is not a character device\n", raw);
+ return (origname);
+ }
+ } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
+ newname = unrawname(newname);
+ retried++;
+ goto retry;
+ }
+ /*
+ * Not a block or character device, just return name and
+ * let the user decide whether to use it.
+ */
+ return (origname);
+}
+
+static char *
+unrawname(name)
+ char *name;
+{
+ char *dp;
+ struct stat stb;
+ size_t dp_len;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (name);
+ if (stat(name, &stb) < 0)
+ return (name);
+ if ((stb.st_mode & S_IFMT) != S_IFCHR)
+ return (name);
+ if (dp[1] != 'r')
+ return (name);
+ dp_len = strlen(&dp[2]) + 1;
+ (void)memmove(&dp[1], &dp[2], dp_len);
+ return (name);
+}
+
+static char *
+rawname(name)
+ char *name;
+{
+ static char rawbuf[32];
+ char *dp;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (0);
+ *dp = 0;
+ (void)strncpy(rawbuf, name, sizeof(rawbuf));
+ *dp = '/';
+ (void)strlcat(rawbuf, "/r", sizeof(rawbuf));
+ (void)strlcat(rawbuf, &dp[1], sizeof(rawbuf));
+ return (rawbuf);
+}
+
+#endif /* TARGET_OS_OSX */
+
diff --git a/diskdev_cmds/disklib/vfslist.c b/diskdev_cmds/disklib/vfslist.c
new file mode 100644
index 0000000..6ecafcd
--- /dev/null
+++ b/diskdev_cmds/disklib/vfslist.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+
+int checkvfsname __P((const char *, const char **));
+const char **makevfslist __P((char *));
+static int skipvfs;
+
+int
+checkvfsname(vfsname, vfslist)
+ const char *vfsname;
+ const char **vfslist;
+{
+
+ if (vfslist == NULL)
+ return (0);
+ while (*vfslist != NULL) {
+ if (strcmp(vfsname, *vfslist) == 0)
+ return (skipvfs);
+ ++vfslist;
+ }
+ return (!skipvfs);
+}
+
+const char **
+makevfslist(fslist)
+ char *fslist;
+{
+ const char **av;
+ int i;
+ char *nextcp;
+
+ if (fslist == NULL)
+ return (NULL);
+ if (fslist[0] == 'n' && fslist[1] == 'o') {
+ fslist += 2;
+ skipvfs = 1;
+ }
+ for (i = 0, nextcp = fslist; *nextcp; nextcp++)
+ if (*nextcp == ',')
+ i++;
+ if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) {
+ warn(NULL);
+ return (NULL);
+ }
+ nextcp = fslist;
+ i = 0;
+ av[i++] = nextcp;
+ while ((nextcp = strchr(nextcp, ',')) != NULL) {
+ *nextcp++ = '\0';
+ av[i++] = nextcp;
+ }
+ av[i++] = NULL;
+ return (av);
+}
diff --git a/diskdev_cmds/edquota.tproj/edquota.8 b/diskdev_cmds/edquota.tproj/edquota.8
new file mode 100644
index 0000000..fd52b56
--- /dev/null
+++ b/diskdev_cmds/edquota.tproj/edquota.8
@@ -0,0 +1,184 @@
+.\" Copyright (c) 1983, 1990, 1993, 2002
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)edquota.8 8.2 (Berkeley) 4/27/95
+.\"
+.Dd "March 28, 2002"
+.Dt EDQUOTA 8
+.Os
+.Sh NAME
+.Nm edquota
+.Nd edit user quotas
+.Sh SYNOPSIS
+.Nm edquota
+.Op Fl u
+.Op Fl p Ar proto-username
+.Ar username ...
+.Nm edquota
+.Fl g
+.Op Fl p Ar proto-groupname
+.Ar groupname ...
+.Nm edquota
+.Fl t
+.Op Fl u
+.Nm edquota
+.Fl t
+.Fl g
+.Sh DESCRIPTION
+.Nm Edquota
+is a quota editor.
+By default, or if the
+.Fl u
+flag is specified,
+one or more users may be specified on the command line.
+For each user a temporary file is created
+with an ASCII representation of the current
+disk quotas for that user.
+The list of filesystems with user quotas is determined by
+scanning the mounted filesystems for a
+.Pa .quota.ops.user
+file located at its root.
+An editor is invoked on the ASCII file.
+The editor invoked is
+.Xr vi 1
+unless the environment variable
+.Ev EDITOR
+specifies otherwise.
+.Pp
+The quotas may then be modified, new quotas added, etc.
+Setting a quota to zero indicates that no quota should be imposed.
+Setting a hard limit to one indicates that no allocations should
+be permitted.
+Setting a soft limit to one with a hard limit of zero
+indicates that allocations should be permitted on
+only a temporary basis (see
+.Fl t
+below).
+The current usage information in the file is for informational purposes;
+only the hard and soft limits can be changed.
+.Pp
+On leaving the editor,
+.Nm edquota
+reads the temporary file and modifies the binary
+quota files to reflect the changes made.
+The binary quota file,
+.Pa .quota.user
+is stored at the root of the filesystem.
+The default filename and root location for the user
+quotas cannot be overridden.
+.Pp
+If the
+.Fl p
+flag is specified,
+.Nm edquota
+will duplicate the quotas of the prototypical user
+specified for each user specified.
+This is the normal mechanism used to
+initialize quotas for groups of users.
+.Pp
+If the
+.Fl g
+flag is specified,
+.Nm edquota
+is invoked to edit the quotas of
+one or more groups specified on the command line.
+The list of filesystems with group quotas is determined by
+scanning the mounted filesystems for a
+.Pa .quota.ops.group
+file located at its root.
+Similarly, the binary quota file,
+.Pa .quota.group
+is stored at the root of the filesystem.
+The default filename and root location for group
+quotas cannot be overridden.
+The
+.Fl p
+flag can be specified in conjunction with
+the
+.Fl g
+flag to specify a prototypical group
+to be duplicated among the listed set of groups.
+.Pp
+Users are permitted to exceed their soft limits
+for a grace period that may be specified per filesystem.
+Once the grace period has expired,
+the soft limit is enforced as a hard limit.
+The default grace period for a filesystem is specified in
+.Pa /usr/include/sys/quota.h .
+The
+.Fl t
+flag can be used to change the grace period.
+By default, or when invoked with the
+.Fl u
+flag, the grace period is set for each filesystem with a
+.Pa .quota.ops.user
+file located at its root.
+When invoked with the
+.Fl g
+flag, the grace period is
+set for each filesystem with a
+.Pa .quota.ops.group
+file located at its root.
+The grace period may be specified in days, hours, minutes, or seconds.
+Setting a grace period to zero indicates that the default
+grace period should be imposed.
+Setting a grace period to one second indicates that no
+grace period should be granted.
+.Pp
+Only the super-user may edit quotas.
+.Sh FILES
+Each of the following quota files is located at the root of the
+mounted filesystem. The mount option files are empty files
+whose existence indicates that quotas are to be enabled
+for that filesystem. The binary data files will be
+created by edquota, if they don't already exist.
+.Pp
+.Bl -tag -width .quota.ops.group -compact
+.It Pa .quota.user
+data file containing user quotas
+.It Pa .quota.group
+data file containing group quotas
+.It Pa .quota.ops.user
+mount option file used to enable user quotas
+.It Pa .quota.ops.group
+mount option file used to enable group quotas
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr quotactl 2 ,
+.Xr quotacheck 8 ,
+.Xr quotaon 8 ,
+.Xr repquota 8
+.Sh DIAGNOSTICS
+Various messages about inaccessible files; self-explanatory.
diff --git a/diskdev_cmds/edquota.tproj/edquota.c b/diskdev_cmds/edquota.tproj/edquota.c
new file mode 100644
index 0000000..6dad1cb
--- /dev/null
+++ b/diskdev_cmds/edquota.tproj/edquota.c
@@ -0,0 +1,1228 @@
+/*
+ * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1980, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+__unused static char sccsid[] = "@(#)edquota.c 8.3 (Berkeley) 4/27/95";
+#endif /* not lint */
+
+/*
+ * Disk quota editor.
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#ifdef __APPLE__
+#include <sys/mount.h>
+#endif /* __APPLE__ */
+#include <sys/wait.h>
+#include <sys/queue.h>
+#include <sys/quota.h>
+#include <errno.h>
+#include <fstab.h>
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include "pathnames.h"
+
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#endif /* __APPLE__ */
+
+char *qfname = QUOTAFILENAME;
+char *qfextension[] = INITQFNAMES;
+char *quotagroup = QUOTAGROUP;
+char tmpfil[] = _PATH_TMP;
+
+#ifdef __APPLE__
+u_int32_t quotamagic[MAXQUOTAS] = INITQMAGICS;
+#endif /* __APPLE__ */
+
+struct quotause {
+ struct quotause *next;
+ long flags;
+ struct dqblk dqblk;
+ char fsname[MAXPATHLEN + 1];
+ char qfname[1]; /* actually longer */
+} *getprivs();
+#define FOUND 0x01
+
+int alldigits __P((char *));
+int cvtatos __P((time_t, char *, time_t *));
+int editit __P((char *));
+void freeprivs __P((struct quotause *));
+int getentry __P((char *, int));
+int hasquota __P((struct statfs *, int, char **));
+void putprivs __P((uid_t, int, struct quotause *));
+int readprivs __P((struct quotause *, int));
+int readtimes __P((struct quotause *, int));
+void usage __P((void));
+int writeprivs __P((struct quotause *, int, char *, int));
+int writetimes __P((struct quotause *, int, int));
+
+#ifdef __APPLE__
+int qfinit(int, struct statfs *, int);
+int qflookup(int, uid_t, int, struct dqblk *);
+int qfupdate(int, uid_t, int, struct dqblk *);
+#endif /* __APPLE__ */
+
+
+int
+main(argc, argv)
+ register char **argv;
+ int argc;
+{
+ register struct quotause *qup, *protoprivs, *curprivs;
+ extern char *optarg;
+ extern int optind;
+ register uid_t id, protoid;
+ register int quotatype, tmpfd;
+ char *protoname = NULL, ch;
+ int tflag = 0, pflag = 0;
+
+ if (argc < 2)
+ usage();
+ if (getuid()) {
+ fprintf(stderr, "edquota: permission denied\n");
+ exit(1);
+ }
+ quotatype = USRQUOTA;
+
+ while ((ch = getopt(argc, argv, "ugtp:")) != EOF) {
+ switch(ch) {
+ case 'p':
+ protoname = optarg;
+ pflag++;
+ break;
+ case 'g':
+ quotatype = GRPQUOTA;
+ break;
+ case 'u':
+ quotatype = USRQUOTA;
+ break;
+ case 't':
+ tflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (pflag) {
+ if ((protoid = getentry(protoname, quotatype)) == -1)
+ exit(1);
+ protoprivs = getprivs(protoid, quotatype);
+#ifdef __APPLE__
+ if (protoprivs == (struct quotause *) NULL)
+ exit(0);
+#endif /* __APPLE__ */
+ for (qup = protoprivs; qup; qup = qup->next) {
+ qup->dqblk.dqb_btime = 0;
+ qup->dqblk.dqb_itime = 0;
+ }
+ while (argc-- > 0) {
+ if ((id = getentry(*argv++, quotatype)) == -1)
+ continue;
+ /*
+ * Set the ID in each disk quota block to match
+ * the ID it's supposed to go with.
+ */
+ for (qup = protoprivs; qup; qup = qup->next) {
+ qup->dqblk.dqb_id = id;
+ }
+ putprivs(id, quotatype, protoprivs);
+ }
+ exit(0);
+ }
+ tmpfd = mkstemp(tmpfil);
+ fchown(tmpfd, getuid(), getgid());
+ if (tflag) {
+ protoprivs = getprivs(0, quotatype);
+#ifdef __APPLE__
+ if (protoprivs == (struct quotause *) NULL)
+ exit(0);
+#endif /* __APPLE__ */
+ if (writetimes(protoprivs, tmpfd, quotatype) == 0)
+ exit(1);
+ if (editit(tmpfil)) {
+ /*
+ * Re-open tmpfil to be editor independent.
+ */
+ close(tmpfd);
+ tmpfd = open(tmpfil, O_RDWR, 0);
+ if (tmpfd < 0) {
+ freeprivs(protoprivs);
+ unlink(tmpfil);
+ exit(1);
+ }
+ if (readtimes(protoprivs, tmpfd))
+ putprivs(0, quotatype, protoprivs);
+ }
+ freeprivs(protoprivs);
+ exit(0);
+ }
+ for ( ; argc > 0; argc--, argv++) {
+ if ((id = getentry(*argv, quotatype)) == -1)
+ continue;
+ curprivs = getprivs(id, quotatype);
+#ifdef __APPLE__
+ if (curprivs == (struct quotause *) NULL)
+ exit(0);
+#endif /* __APPLE__ */
+
+
+ if (writeprivs(curprivs, tmpfd, *argv, quotatype) == 0) {
+ freeprivs(curprivs);
+ continue;
+ }
+ if (editit(tmpfil)) {
+ /*
+ * Re-open tmpfil to be editor independent.
+ */
+ close(tmpfd);
+ tmpfd = open(tmpfil, O_RDWR, 0);
+ if (tmpfd < 0) {
+ freeprivs(curprivs);
+ unlink(tmpfil);
+ exit(1);
+ }
+ if (readprivs(curprivs, tmpfd))
+ putprivs(id, quotatype, curprivs);
+ }
+ freeprivs(curprivs);
+ }
+ close(tmpfd);
+ unlink(tmpfil);
+ exit(0);
+}
+
+void
+usage()
+{
+ fprintf(stderr, "%s%s%s%s",
+ "Usage: edquota [-u] [-p username] username ...\n",
+ "\tedquota -g [-p groupname] groupname ...\n",
+ "\tedquota [-u] -t\n", "\tedquota -g -t\n");
+#ifdef __APPLE__
+ fprintf(stderr, "\nQuota file editing triggers only on filesystems with a\n");
+ fprintf(stderr, "%s.%s or %s.%s file located at its root.\n",
+ QUOTAOPSNAME, qfextension[USRQUOTA],
+ QUOTAOPSNAME, qfextension[GRPQUOTA]);
+#endif /* __APPLE__ */
+ exit(1);
+}
+
+/*
+ * This routine converts a name for a particular quota type to
+ * an identifier. This routine must agree with the kernel routine
+ * getinoquota as to the interpretation of quota types.
+ */
+int
+getentry(name, quotatype)
+ char *name;
+ int quotatype;
+{
+ struct passwd *pw;
+ struct group *gr;
+
+ if (alldigits(name))
+ return (atoi(name));
+ switch(quotatype) {
+ case USRQUOTA:
+ if ((pw = getpwnam(name)) != NULL)
+ return (pw->pw_uid);
+ fprintf(stderr, "%s: no such user\n", name);
+ break;
+ case GRPQUOTA:
+ if ((gr = getgrnam(name)))
+ return (gr->gr_gid);
+ fprintf(stderr, "%s: no such group\n", name);
+ break;
+ default:
+ fprintf(stderr, "%d: unknown quota type\n", quotatype);
+ break;
+ }
+ sleep(1);
+ return (-1);
+}
+
+/*
+ * Collect the requested quota information.
+ */
+#ifdef __APPLE__
+struct quotause *
+getprivs(id, quotatype)
+ register uid_t id;
+ int quotatype;
+{
+ struct statfs *fst;
+ register struct quotause *qup, *quptail;
+ struct quotause *quphead;
+ int qcmd, fd;
+ size_t qupsize;
+ char *qfpathname;
+ size_t qfpathname_len;
+ static int warned = 0;
+ int nfst, i;
+ extern int errno;
+
+
+ quptail = quphead = (struct quotause *)0;
+ qcmd = QCMD(Q_GETQUOTA, quotatype);
+
+ nfst = getmntinfo(&fst, MNT_WAIT);
+ if (nfst==0) {
+ fprintf(stderr, "edquota: no mounted filesystems\n");
+ exit(1);
+ }
+
+ for (i=0; i<nfst; i++) {
+ if (strcmp(fst[i].f_fstypename, "hfs")) {
+ continue;
+ }
+ if (!hasquota(&fst[i], quotatype, &qfpathname))
+ continue;
+ qfpathname_len = strlen(qfpathname);
+ qupsize = sizeof(*qup) + qfpathname_len;
+ if ((qup = (struct quotause *)malloc(qupsize)) == NULL) {
+ fprintf(stderr, "edquota: out of memory\n");
+ exit(2);
+ }
+ if (quotactl(fst[i].f_mntonname, qcmd, id, (char *)&qup->dqblk) != 0) {
+ if (errno == ENOTSUP && !warned) {
+ warned++;
+ fprintf(stderr, "Warning: %s\n",
+ "Quotas are not compiled into this kernel");
+ sleep(3);
+ }
+ if ((fd = open(qfpathname, O_RDONLY)) < 0) {
+ fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
+ if (fd < 0 && errno != ENOENT) {
+ perror(qfpathname);
+ free(qup);
+ continue;
+ }
+ fprintf(stderr, "Creating quota file %s\n",
+ qfpathname);
+ sleep(3);
+ (void) fchown(fd, getuid(),
+ getentry(quotagroup, GRPQUOTA));
+ (void) fchmod(fd, 0640);
+ if (qfinit(fd, &fst[i], quotatype)) {
+ perror(qfpathname);
+ close(fd);
+ free(qup);
+ continue;
+ }
+ }
+ if (qflookup(fd, id, quotatype, &qup->dqblk) != 0) {
+ fprintf(stderr, "edquota: lookup error in ");
+ perror(qfpathname);
+ close(fd);
+ free(qup);
+ continue;
+ }
+ close(fd);
+ }
+ strlcpy(qup->qfname, qfpathname, qfpathname_len); // malloc'd size is correct for this
+ strlcpy(qup->fsname, fst[i].f_mntonname, sizeof(qup->fsname));
+
+ if (quphead == NULL)
+ quphead = qup;
+ else
+ quptail->next = qup;
+ quptail = qup;
+ qup->next = 0;
+ }
+ return (quphead);
+}
+#else
+struct quotause *
+getprivs(id, quotatype)
+ register long id;
+ int quotatype;
+{
+ register struct fstab *fs;
+ register struct quotause *qup, *quptail;
+ struct quotause *quphead;
+ int qcmd, fd;
+ size_t qupsize;
+ char *qfpathname;
+ size_t qfpathname_len;
+ static int warned = 0;
+ extern int errno;
+
+ setfsent();
+ quphead = (struct quotause *)0;
+ qcmd = QCMD(Q_GETQUOTA, quotatype);
+ while (fs = getfsent()) {
+ if (!hasquota(fs, quotatype, &qfpathname))
+ continue;
+ qfpathname_len = strlen(qfpathname);
+ qupsize = sizeof(*qup) + qfpathname_len;
+ if ((qup = (struct quotause *)malloc(qupsize)) == NULL) {
+ fprintf(stderr, "edquota: out of memory\n");
+ exit(2);
+ }
+ if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
+ if (errno == ENOTSUP && !warned) {
+ warned++;
+ fprintf(stderr, "Warning: %s\n",
+ "Quotas are not compiled into this kernel");
+ sleep(3);
+ }
+ if ((fd = open(qfpathname, O_RDONLY)) < 0) {
+ fd = open(qfpathname, O_RDWR|O_CREAT, 0640);
+ if (fd < 0 && errno != ENOENT) {
+ perror(qfpathname);
+ free(qup);
+ continue;
+ }
+ fprintf(stderr, "Creating quota file %s\n",
+ qfpathname);
+ sleep(3);
+ (void) fchown(fd, getuid(),
+ getentry(quotagroup, GRPQUOTA));
+ (void) fchmod(fd, 0640);
+ }
+ lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET);
+ switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
+ case 0: /* EOF */
+ /*
+ * Convert implicit 0 quota (EOF)
+ * into an explicit one (zero'ed dqblk)
+ */
+ bzero((caddr_t)&qup->dqblk,
+ sizeof(struct dqblk));
+ break;
+
+ case sizeof(struct dqblk): /* OK */
+ break;
+
+ default: /* ERROR */
+ fprintf(stderr, "edquota: read error in ");
+ perror(qfpathname);
+ close(fd);
+ free(qup);
+ continue;
+ }
+ close(fd);
+ }
+ strlcpy(qup->qfname, qfpathname, qfpathname_len); // malloc'd size is correct for this
+ strlcpy(qup->fsname, fs->fs_file, sizeof(qup->fsname));
+
+ if (quphead == NULL)
+ quphead = qup;
+ else
+ quptail->next = qup;
+ quptail = qup;
+ qup->next = 0;
+ }
+ endfsent();
+ return (quphead);
+}
+#endif /* __APPLE */
+
+#ifdef __APPLE__
+#define ONEGIGABYTE (1024*1024*1024)
+/*
+ * Initialize a new quota file.
+ */
+int
+qfinit(fd, fst, type)
+ int fd;
+ struct statfs *fst;
+ int type;
+{
+ struct dqfilehdr dqhdr = {0};
+ u_int64_t fs_size;
+ int64_t max = 0;
+
+ /*
+ * Calculate the size of the hash table from the size of
+ * the file system. Note that the open addressing hashing
+ * used by the quota file assumes that this table will not
+ * be more than 90% full.
+ */
+ fs_size = (u_int64_t)fst->f_blocks * (u_int64_t)fst->f_bsize;
+
+ if (type == USRQUOTA) {
+ max = QF_USERS_PER_GB * (fs_size / ONEGIGABYTE);
+
+ if (max < QF_MIN_USERS)
+ max = QF_MIN_USERS;
+ else if (max > QF_MAX_USERS)
+ max = QF_MAX_USERS;
+ } else if (type == GRPQUOTA) {
+ max = QF_GROUPS_PER_GB * (fs_size / ONEGIGABYTE);
+
+ if (max < QF_MIN_GROUPS)
+ max = QF_MIN_GROUPS;
+ else if (max > QF_MAX_GROUPS)
+ max = QF_MAX_GROUPS;
+ }
+ /* Round up to a power of 2 */
+ if (max && !powerof2(max)) {
+ int64_t x = max;
+ max = 4;
+ while (x>>1 != 1) {
+ x = x >> 1;
+ max = max << 1;
+ }
+ }
+
+ (void) ftruncate(fd, (off_t)((max + 1) * sizeof(struct dqblk)));
+ dqhdr.dqh_magic = OSSwapHostToBigInt32(quotamagic[type]);
+ dqhdr.dqh_version = OSSwapHostToBigConstInt32(QF_VERSION);
+ dqhdr.dqh_maxentries = OSSwapHostToBigInt32((int32_t)max);
+ dqhdr.dqh_btime = OSSwapHostToBigConstInt32(MAX_DQ_TIME);
+ dqhdr.dqh_itime = OSSwapHostToBigConstInt32(MAX_IQ_TIME);
+ memmove(dqhdr.dqh_string, QF_STRING_TAG, strlen(QF_STRING_TAG));
+ (void) lseek(fd, 0, L_SET);
+ (void) write(fd, &dqhdr, sizeof(dqhdr));
+
+ return (0);
+}
+
+/*
+ * Lookup an entry in a quota file.
+ */
+int
+qflookup(fd, id, type, dqbp)
+ int fd;
+ uid_t id;
+ int type;
+ struct dqblk *dqbp;
+{
+ struct dqfilehdr dqhdr;
+ int i, skip, last, m;
+ int mask;
+
+ bzero(dqbp, sizeof(struct dqblk));
+
+ if (id == 0)
+ return (0);
+
+ lseek(fd, 0, L_SET);
+ if (read(fd, &dqhdr, sizeof(struct dqfilehdr)) != sizeof(struct dqfilehdr))
+ return (-1);
+
+ /* Sanity check the quota file header. */
+ if ((OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type]) ||
+ (OSSwapBigToHostInt32(dqhdr.dqh_version) > 1) ||
+ (!powerof2(OSSwapBigToHostInt32(dqhdr.dqh_maxentries)))) {
+ fprintf(stderr, "quota: invalid quota file header\n");
+ return (-1);
+ }
+
+ m = OSSwapBigToHostInt32(dqhdr.dqh_maxentries);
+ mask = m - 1;
+ i = dqhash1(id, dqhashshift(m), mask);
+ skip = dqhash2(id, mask);
+
+ for (last = (i + (m-1) * skip) & mask;
+ i != last;
+ i = (i + skip) & mask) {
+ lseek(fd, dqoffset(i), L_SET);
+ if (read(fd, dqbp, sizeof(struct dqblk)) < sizeof(struct dqblk))
+ return (-1);
+ /*
+ * Stop when an empty entry is found
+ * or we encounter a matching id.
+ */
+ if (dqbp->dqb_id == 0 || OSSwapBigToHostInt32(dqbp->dqb_id) == id)
+ break;
+ }
+ /* Put data in host native byte order. */
+ dqbp->dqb_bhardlimit = OSSwapBigToHostInt64(dqbp->dqb_bhardlimit);
+ dqbp->dqb_bsoftlimit = OSSwapBigToHostInt64(dqbp->dqb_bsoftlimit);
+ dqbp->dqb_curbytes = OSSwapBigToHostInt64(dqbp->dqb_curbytes);
+ dqbp->dqb_ihardlimit = OSSwapBigToHostInt32(dqbp->dqb_ihardlimit);
+ dqbp->dqb_isoftlimit = OSSwapBigToHostInt32(dqbp->dqb_isoftlimit);
+ dqbp->dqb_curinodes = OSSwapBigToHostInt32(dqbp->dqb_curinodes);
+ dqbp->dqb_btime = OSSwapBigToHostInt32(dqbp->dqb_btime);
+ dqbp->dqb_itime = OSSwapBigToHostInt32(dqbp->dqb_itime);
+ dqbp->dqb_id = OSSwapBigToHostInt32(dqbp->dqb_id);
+
+ return (0);
+}
+#endif /* __APPLE */
+
+
+/*
+ * Store the requested quota information.
+ */
+void
+putprivs(id, quotatype, quplist)
+ uid_t id;
+ int quotatype;
+ struct quotause *quplist;
+{
+ register struct quotause *qup;
+ int qcmd, fd;
+
+ qcmd = QCMD(Q_SETQUOTA, quotatype);
+ for (qup = quplist; qup; qup = qup->next) {
+ if (quotactl(qup->fsname, qcmd, id, (char *)&qup->dqblk) == 0)
+ continue;
+#ifdef __APPLE__
+ if ((fd = open(qup->qfname, O_RDWR)) < 0) {
+ perror(qup->qfname);
+ } else {
+ if (qfupdate(fd, id, quotatype, &qup->dqblk) != 0) {
+ fprintf(stderr, "edquota: ");
+ perror(qup->qfname);
+ }
+#else
+ if ((fd = open(qup->qfname, O_WRONLY)) < 0) {
+ perror(qup->qfname);
+ } else {
+ lseek(fd,
+ (off_t)(id * (long)sizeof (struct dqblk)), L_SET);
+ if (write(fd, &qup->dqblk, sizeof (struct dqblk)) !=
+ sizeof (struct dqblk)) {
+ fprintf(stderr, "edquota: ");
+ perror(qup->qfname);
+ }
+#endif /* __APPLE */
+ close(fd);
+ }
+ }
+}
+
+#ifdef __APPLE__
+/*
+ * Update an entry in a quota file.
+ */
+int
+qfupdate(fd, id, type, dqbp)
+ int fd;
+ uid_t id;
+ int type;
+ struct dqblk *dqbp;
+{
+ struct dqblk dqbuf;
+ struct dqfilehdr dqhdr;
+ int i, skip, last, m;
+ unsigned int mask;
+
+ if (id == 0)
+ return (0);
+
+ lseek(fd, 0, L_SET);
+ if (read(fd, &dqhdr, sizeof(struct dqfilehdr)) != sizeof(struct dqfilehdr))
+ return (-1);
+
+ /* Sanity check the quota file header. */
+ if ((OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type]) ||
+ (OSSwapBigToHostInt32(dqhdr.dqh_version) > QF_VERSION) ||
+ (!powerof2(OSSwapBigToHostInt32(dqhdr.dqh_maxentries)))) {
+ fprintf(stderr, "quota: invalid quota file header\n");
+ return (EINVAL);
+ }
+
+ m = OSSwapBigToHostInt32(dqhdr.dqh_maxentries);
+ mask = m - 1;
+ i = dqhash1(id, dqhashshift(m), mask);
+ skip = dqhash2(id, mask);
+
+ for (last = (i + (m-1) * skip) & mask;
+ i != last;
+ i = (i + skip) & mask) {
+ lseek(fd, dqoffset(i), L_SET);
+ if (read(fd, &dqbuf, sizeof(struct dqblk)) < sizeof(struct dqblk))
+ return (-1);
+ /*
+ * Stop when an empty entry is found
+ * or we encounter a matching id.
+ */
+ if (dqbuf.dqb_id == 0 || OSSwapBigToHostInt32(dqbuf.dqb_id) == id) {
+ /* Convert buffer to big endian before writing. */
+ struct dqblk tblk;
+
+ tblk.dqb_bhardlimit = OSSwapHostToBigInt64(dqbp->dqb_bhardlimit);
+ tblk.dqb_bsoftlimit = OSSwapHostToBigInt64(dqbp->dqb_bsoftlimit);
+ tblk.dqb_curbytes = OSSwapHostToBigInt64(dqbp->dqb_curbytes);
+ tblk.dqb_ihardlimit = OSSwapHostToBigInt32(dqbp->dqb_ihardlimit);
+ tblk.dqb_isoftlimit = OSSwapHostToBigInt32(dqbp->dqb_isoftlimit);
+ tblk.dqb_curinodes = OSSwapHostToBigInt32(dqbp->dqb_curinodes);
+ tblk.dqb_btime = OSSwapHostToBigInt32((int)dqbp->dqb_btime);
+ tblk.dqb_itime = OSSwapHostToBigInt32((int)dqbp->dqb_itime);
+ tblk.dqb_id = OSSwapHostToBigInt32(id);
+
+ lseek(fd, dqoffset(i), L_SET);
+ if (write(fd, &tblk, sizeof (struct dqblk)) !=
+ sizeof (struct dqblk)) {
+ return (-1);
+ }
+ return (0);
+ }
+ }
+ errno = ENOSPC;
+ return (-1);
+}
+#endif /* __APPLE__ */
+
+/*
+ * Take a list of priviledges and get it edited.
+ */
+int
+editit(tmpfile)
+ char *tmpfile;
+{
+ int omask;
+ int pid, stat;
+ extern char *getenv();
+
+ omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
+ top:
+ if ((pid = fork()) < 0) {
+ extern int errno;
+
+ if (errno == EPROCLIM) {
+ fprintf(stderr, "You have too many processes\n");
+ return(0);
+ }
+ if (errno == EAGAIN) {
+ sleep(1);
+ goto top;
+ }
+ perror("fork");
+ return (0);
+ }
+ if (pid == 0) {
+ register char *ed;
+ struct passwd *pwd = getpwuid(getuid());
+ gid_t newgid = getgid();
+
+ setgid(newgid);
+ if (pwd) initgroups(pwd->pw_name, newgid);
+ setuid(getuid());
+ sigsetmask(omask);
+
+ if ((ed = getenv("EDITOR")) == (char *)0)
+ ed = _PATH_VI;
+ execlp(ed, ed, tmpfile, NULL);
+ perror(ed);
+ exit(1);
+ }
+ waitpid(pid, &stat, 0);
+ sigsetmask(omask);
+ if (!WIFEXITED(stat) || WEXITSTATUS(stat) != 0)
+ return (0);
+ return (1);
+}
+
+/*
+ * Convert a quotause list to an ASCII file.
+ */
+int
+writeprivs(quplist, outfd, name, quotatype)
+ struct quotause *quplist;
+ int outfd;
+ char *name;
+ int quotatype;
+{
+ register struct quotause *qup;
+ FILE *fd;
+
+ ftruncate(outfd, 0);
+ lseek(outfd, 0, L_SET);
+ if ((fd = fdopen(dup(outfd), "w")) == NULL) {
+ fprintf(stderr, "edquota: ");
+ perror(tmpfil);
+ exit(1);
+ }
+ fprintf(fd, "Quotas for %s %s:\n", qfextension[quotatype], name);
+ for (qup = quplist; qup; qup = qup->next) {
+#ifdef __APPLE__
+ fprintf(fd, "%s: %s %qd, limits (soft = %qd, hard = %qd)\n",
+ qup->fsname, "1K blocks in use:",
+ qup->dqblk.dqb_curbytes / 1024,
+ qup->dqblk.dqb_bsoftlimit / 1024,
+ qup->dqblk.dqb_bhardlimit / 1024);
+#else
+ fprintf(fd, "%s: %s %d, limits (soft = %d, hard = %d)\n",
+ qup->fsname, "blocks in use:",
+ dbtob(qup->dqblk.dqb_curblocks) / 1024,
+ dbtob(qup->dqblk.dqb_bsoftlimit) / 1024,
+ dbtob(qup->dqblk.dqb_bhardlimit) / 1024);
+#endif /* __APPLE__ */
+
+ fprintf(fd, "%s %d, limits (soft = %d, hard = %d)\n",
+ "\tinodes in use:", qup->dqblk.dqb_curinodes,
+ qup->dqblk.dqb_isoftlimit, qup->dqblk.dqb_ihardlimit);
+ }
+ fclose(fd);
+ return (1);
+}
+
+/*
+ * Merge changes to an ASCII file into a quotause list.
+ */
+int
+readprivs(quplist, infd)
+ struct quotause *quplist;
+ int infd;
+{
+ register struct quotause *qup;
+ FILE *fd;
+ int cnt;
+ register char *cp;
+ struct dqblk dqblk;
+ char fsp[BUFSIZ], line1[BUFSIZ], line2[BUFSIZ];
+
+ lseek(infd, 0, L_SET);
+ fd = fdopen(dup(infd), "r");
+ if (fd == NULL) {
+ fprintf(stderr, "Can't re-read temp file!!\n");
+ return (0);
+ }
+ /*
+ * Discard title line, then read pairs of lines to process.
+ */
+ (void) fgets(line1, sizeof (line1), fd);
+ while (fgets(line1, sizeof (line1), fd) != NULL &&
+ fgets(line2, sizeof (line2), fd) != NULL) {
+ cp = strstr(line1, ": 1K blocks in use:");
+ if (cp == NULL) {
+ fprintf(stderr, "%s: bad format for line\n", line1);
+ return 0;
+ }
+ /* Copy up to the template text */
+ strlcpy(fsp, line1, cp - line1 + 1);
+ /* And point cp right after it. */
+ cp = line1 + strlen(fsp) + 1;
+#ifdef __APPLE__
+ /* We expect input to be in 1K blocks */
+ cnt = sscanf(cp,
+ " 1K blocks in use: %qd, limits (soft = %qd, hard = %qd)",
+ &dqblk.dqb_curbytes, &dqblk.dqb_bsoftlimit,
+ &dqblk.dqb_bhardlimit);
+ if (cnt != 3) {
+ fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
+ return (0);
+ }
+
+ /* convert default 1K blocks to byte count */
+ dqblk.dqb_curbytes = dqblk.dqb_curbytes * 1024;
+ dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit * 1024;
+ dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit * 1024;
+#else
+ cnt = sscanf(cp,
+ " blocks in use: %d, limits (soft = %d, hard = %d)",
+ &dqblk.dqb_curblocks, &dqblk.dqb_bsoftlimit,
+ &dqblk.dqb_bhardlimit);
+ if (cnt != 3) {
+ fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
+ return (0);
+ }
+ dqblk.dqb_curblocks = btodb(dqblk.dqb_curblocks * 1024);
+ dqblk.dqb_bsoftlimit = btodb(dqblk.dqb_bsoftlimit * 1024);
+ dqblk.dqb_bhardlimit = btodb(dqblk.dqb_bhardlimit * 1024);
+#endif /* __APPLE__ */
+
+ if ((cp = strtok(line2, "\n")) == NULL) {
+ fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
+ return (0);
+ }
+ cnt = sscanf(cp,
+ "\tinodes in use: %d, limits (soft = %d, hard = %d)",
+ &dqblk.dqb_curinodes, &dqblk.dqb_isoftlimit,
+ &dqblk.dqb_ihardlimit);
+ if (cnt != 3) {
+ fprintf(stderr, "%s: %s: bad format\n", fsp, line2);
+ return (0);
+ }
+ for (qup = quplist; qup; qup = qup->next) {
+ if (strcmp(fsp, qup->fsname))
+ continue;
+ /*
+ * Cause time limit to be reset when the quota
+ * is next used if previously had no soft limit
+ * or were under it, but now have a soft limit
+ * and are over it.
+ */
+#ifdef __APPLE__
+ if (dqblk.dqb_bsoftlimit &&
+ qup->dqblk.dqb_curbytes >= dqblk.dqb_bsoftlimit &&
+ (qup->dqblk.dqb_bsoftlimit == 0 ||
+ qup->dqblk.dqb_curbytes <
+ qup->dqblk.dqb_bsoftlimit))
+ qup->dqblk.dqb_btime = 0;
+#else
+ if (dqblk.dqb_bsoftlimit &&
+ qup->dqblk.dqb_curblocks >= dqblk.dqb_bsoftlimit &&
+ (qup->dqblk.dqb_bsoftlimit == 0 ||
+ qup->dqblk.dqb_curblocks <
+ qup->dqblk.dqb_bsoftlimit))
+ qup->dqblk.dqb_btime = 0;
+#endif /* __APPLE__ */
+ if (dqblk.dqb_isoftlimit &&
+ qup->dqblk.dqb_curinodes >= dqblk.dqb_isoftlimit &&
+ (qup->dqblk.dqb_isoftlimit == 0 ||
+ qup->dqblk.dqb_curinodes <
+ qup->dqblk.dqb_isoftlimit))
+ qup->dqblk.dqb_itime = 0;
+ qup->dqblk.dqb_bsoftlimit = dqblk.dqb_bsoftlimit;
+ qup->dqblk.dqb_bhardlimit = dqblk.dqb_bhardlimit;
+ qup->dqblk.dqb_isoftlimit = dqblk.dqb_isoftlimit;
+ qup->dqblk.dqb_ihardlimit = dqblk.dqb_ihardlimit;
+ qup->flags |= FOUND;
+#ifdef __APPLE__
+ if (dqblk.dqb_curbytes == qup->dqblk.dqb_curbytes &&
+ dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
+ break;
+#else
+ if (dqblk.dqb_curblocks == qup->dqblk.dqb_curblocks &&
+ dqblk.dqb_curinodes == qup->dqblk.dqb_curinodes)
+ break;
+#endif /* __APPLE__ */
+ fprintf(stderr,
+ "%s: cannot change current allocation\n", fsp);
+ break;
+ }
+ }
+ fclose(fd);
+ /*
+ * Disable quotas for any filesystems that have not been found.
+ */
+ for (qup = quplist; qup; qup = qup->next) {
+ if (qup->flags & FOUND) {
+ qup->flags &= ~FOUND;
+ continue;
+ }
+ qup->dqblk.dqb_bsoftlimit = 0;
+ qup->dqblk.dqb_bhardlimit = 0;
+ qup->dqblk.dqb_isoftlimit = 0;
+ qup->dqblk.dqb_ihardlimit = 0;
+ }
+ return (1);
+}
+
+/*
+ * Convert a quotause list to an ASCII file of grace times.
+ */
+int
+writetimes(quplist, outfd, quotatype)
+ struct quotause *quplist;
+ int outfd;
+ int quotatype;
+{
+ register struct quotause *qup;
+ char *cvtstoa();
+ FILE *fd;
+
+ ftruncate(outfd, 0);
+ lseek(outfd, 0, L_SET);
+ if ((fd = fdopen(dup(outfd), "w")) == NULL) {
+ fprintf(stderr, "edquota: ");
+ perror(tmpfil);
+ exit(1);
+ }
+ fprintf(fd, "Time units may be: days, hours, minutes, or seconds\n");
+ fprintf(fd, "Grace period before enforcing soft limits for %ss:\n",
+ qfextension[quotatype]);
+ for (qup = quplist; qup; qup = qup->next) {
+ fprintf(fd, "%s: block grace period: %s, ",
+ qup->fsname, cvtstoa(qup->dqblk.dqb_btime));
+ fprintf(fd, "file grace period: %s\n",
+ cvtstoa(qup->dqblk.dqb_itime));
+ }
+ fclose(fd);
+ return (1);
+}
+
+/*
+ * Merge changes of grace times in an ASCII file into a quotause list.
+ */
+int
+readtimes(quplist, infd)
+ struct quotause *quplist;
+ int infd;
+{
+ register struct quotause *qup;
+ FILE *fd;
+ int cnt;
+ register char *cp;
+ time_t itime, btime, iseconds, bseconds;
+ char *fsp, bunits[10], iunits[10], line1[BUFSIZ];
+
+ lseek(infd, 0, L_SET);
+ fd = fdopen(dup(infd), "r");
+ if (fd == NULL) {
+ fprintf(stderr, "Can't re-read temp file!!\n");
+ return (0);
+ }
+ /*
+ * Discard two title lines, then read lines to process.
+ */
+ (void) fgets(line1, sizeof (line1), fd);
+ (void) fgets(line1, sizeof (line1), fd);
+ while (fgets(line1, sizeof (line1), fd) != NULL) {
+ if ((fsp = strtok(line1, " \t:")) == NULL) {
+ fprintf(stderr, "%s: bad format\n", line1);
+ return (0);
+ }
+ if ((cp = strtok((char *)0, "\n")) == NULL) {
+ fprintf(stderr, "%s: %s: bad format\n", fsp,
+ &fsp[strlen(fsp) + 1]);
+ return (0);
+ }
+ cnt = sscanf(cp,
+ " block grace period: %ld %s file grace period: %ld %s",
+ &btime, bunits, &itime, iunits);
+ if (cnt != 4) {
+ fprintf(stderr, "%s:%s: bad format\n", fsp, cp);
+ return (0);
+ }
+ if (cvtatos(btime, bunits, &bseconds) == 0)
+ return (0);
+ if (cvtatos(itime, iunits, &iseconds) == 0)
+ return (0);
+ for (qup = quplist; qup; qup = qup->next) {
+ if (strcmp(fsp, qup->fsname))
+ continue;
+ qup->dqblk.dqb_btime = (uint32_t) bseconds;
+ qup->dqblk.dqb_itime = (uint32_t) iseconds;
+ qup->flags |= FOUND;
+ break;
+ }
+ }
+ fclose(fd);
+ /*
+ * reset default grace periods for any filesystems
+ * that have not been found.
+ */
+ for (qup = quplist; qup; qup = qup->next) {
+ if (qup->flags & FOUND) {
+ qup->flags &= ~FOUND;
+ continue;
+ }
+ qup->dqblk.dqb_btime = 0;
+ qup->dqblk.dqb_itime = 0;
+ }
+ return (1);
+}
+
+/*
+ * Convert seconds to ASCII times.
+ */
+char *
+cvtstoa(time)
+ time_t time;
+{
+ static char buf[20];
+
+ if (time % (24 * 60 * 60) == 0) {
+ time /= 24 * 60 * 60;
+ snprintf(buf, sizeof(buf), "%d day%s", (int)time, time == 1 ? "" : "s");
+ } else if (time % (60 * 60) == 0) {
+ time /= 60 * 60;
+ snprintf(buf, sizeof(buf), "%d hour%s", (int)time, time == 1 ? "" : "s");
+ } else if (time % 60 == 0) {
+ time /= 60;
+ snprintf(buf, sizeof(buf), "%d minute%s", (int)time, time == 1 ? "" : "s");
+ } else
+ snprintf(buf, sizeof(buf), "%d second%s", (int)time, time == 1 ? "" : "s");
+ return (buf);
+}
+
+/*
+ * Convert ASCII input times to seconds.
+ */
+int
+cvtatos(time, units, seconds)
+ time_t time;
+ char *units;
+ time_t *seconds;
+{
+
+ if (bcmp(units, "second", 6) == 0)
+ *seconds = time;
+ else if (bcmp(units, "minute", 6) == 0)
+ *seconds = time * 60;
+ else if (bcmp(units, "hour", 4) == 0)
+ *seconds = time * 60 * 60;
+ else if (bcmp(units, "day", 3) == 0)
+ *seconds = time * 24 * 60 * 60;
+ else {
+ printf("%s: bad units, specify %s\n", units,
+ "days, hours, minutes, or seconds");
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Free a list of quotause structures.
+ */
+void
+freeprivs(quplist)
+ struct quotause *quplist;
+{
+ register struct quotause *qup, *nextqup;
+
+ for (qup = quplist; qup; qup = nextqup) {
+ nextqup = qup->next;
+ free(qup);
+ }
+}
+
+/*
+ * Check whether a string is completely composed of digits.
+ */
+int
+alldigits(s)
+ register char *s;
+{
+ register int c;
+
+ c = *s++;
+ do {
+ if (!isdigit(c))
+ return (0);
+ } while ((c = *s++));
+ return (1);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+#ifdef __APPLE__
+int
+hasquota(fst, type, qfnamep)
+ register struct statfs *fst;
+ int type;
+ char **qfnamep;
+{
+ struct stat sb;
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
+ snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+
+ /*
+ We only support the default path to the
+ on disk quota files.
+ */
+
+ (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname,
+ QUOTAOPSNAME, qfextension[type] );
+ if (stat(buf, &sb) != 0) {
+ /* There appears to be no mount option file */
+ return(0);
+ }
+
+ (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+#else
+hasquota(fs, type, qfnamep)
+ register struct fstab *fs;
+ int type;
+ char **qfnamep;
+{
+ register char *opt;
+ char *cp, *index(), *strtok();
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
+ snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ strlcpy(buf, fs->fs_mntops, sizeof(buf));
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if (cp = index(opt, '='))
+ *cp++ = '\0';
+ if (type == USRQUOTA && strcmp(opt, usrname) == 0)
+ break;
+ if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+#endif /* __APPLE */
diff --git a/diskdev_cmds/edquota.tproj/pathnames.h b/diskdev_cmds/edquota.tproj/pathnames.h
new file mode 100644
index 0000000..f1aef1c
--- /dev/null
+++ b/diskdev_cmds/edquota.tproj/pathnames.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+#undef _PATH_TMP
+#define _PATH_TMP "/tmp/EdP.aXXXXX"
diff --git a/diskdev_cmds/edt_fstab/edt_fstab.c b/diskdev_cmds/edt_fstab/edt_fstab.c
new file mode 100644
index 0000000..42a53fe
--- /dev/null
+++ b/diskdev_cmds/edt_fstab/edt_fstab.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2018-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+// edt_fstab.c
+//
+// Created on 12/11/2018.
+//
+
+#include <sys/types.h>
+
+#include "edt_fstab.h"
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+
+/* Some APFS specific goop */
+#include <APFS/APFS.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <os/bsd.h>
+#include <sys/stat.h>
+#include <paths.h>
+
+char boot_container[EDTVolumePropertySize] = {};
+char data_volume[EDTVolumePropertySize] = {};
+
+static uint32_t edt_os_environment = EDT_OS_ENV_MAIN;
+
+const char *
+get_boot_container(uint32_t *os_envp)
+{
+ kern_return_t err;
+ CFMutableDictionaryRef fs_info = NULL;
+ CFStringRef container = NULL;
+ CFDataRef os_env = NULL;
+
+ // already got the boot container
+ if (strnlen(boot_container, sizeof(boot_container)) > 0) {
+ *os_envp = edt_os_environment;
+ return boot_container;
+ }
+
+ fs_info = IORegistryEntryFromPath(kIOMasterPortDefault, kEDTFilesystemEntry);
+ if (fs_info == IO_OBJECT_NULL) {
+ fprintf(stderr, "failed to get filesystem info\n");
+ return NULL;
+ }
+
+ // lookup the OS environment being booted, assumes main OS upon failure
+ os_env = IORegistryEntryCreateCFProperty(fs_info, kEDTOSEnvironment, kCFAllocatorDefault, 0);
+ if (os_env) {
+ CFDataGetBytes(os_env, CFRangeMake(0, CFDataGetLength(os_env)), (UInt8*)(&edt_os_environment));
+ CFRelease(os_env);
+ }
+ IOObjectRelease(fs_info);
+ *os_envp = edt_os_environment;
+
+ // lookup the boot container
+ err = APFSContainerGetBootDevice(&container);
+ if (!err) {
+ strcpy(boot_container, _PATH_DEV);
+ CFStringGetCString(container,
+ boot_container + strlen(_PATH_DEV),
+ EDTVolumePropertySize - strlen(_PATH_DEV),
+ kCFStringEncodingUTF8);
+ CFRelease(container);
+ return boot_container;
+ } else {
+ // just a warning if not booting the main OS (rdar://48693021)
+ fprintf(stderr, "%sfailed to get boot device - %s\n",
+ (edt_os_environment == EDT_OS_ENV_MAIN) ? "" : "warning: ",
+ strerror(err_get_code(err)));
+ return NULL;
+ }
+}
+
+const char *
+get_data_volume(void)
+{
+ const char *container = NULL;
+ CFMutableArrayRef matches = NULL;
+ OSStatus status;
+
+ // already got the data volume
+ if (strnlen(data_volume, sizeof(data_volume)) > 0) {
+ return data_volume;
+ }
+
+ // get the boot container
+ if (strlen(boot_container) > 0) {
+ container = boot_container;
+ } else {
+ uint32_t os_env;
+ container = get_boot_container(&os_env);
+ }
+ if (!container) {
+ return NULL;
+ }
+
+ // lookup the data volume
+ status = APFSVolumeRoleFind(container, APFS_VOL_ROLE_DATA, &matches);
+ if (status) {
+ // just a warning if not booting the main OS
+ fprintf(stderr, "%sfailed to lookup data volume - %s\n",
+ (edt_os_environment == EDT_OS_ENV_MAIN) ? "" : "warning: ",
+ strerror(err_get_code(status)));
+ return NULL;
+ } else if (CFArrayGetCount(matches) > 1) {
+ fprintf(stderr, "found multiple data volumes\n");
+ CFRelease(matches);
+ return NULL;
+ } else {
+ CFStringGetCString(CFArrayGetValueAtIndex(matches, 0),
+ data_volume,
+ EDTVolumePropertySize,
+ kCFStringEncodingUTF8);
+ CFRelease(matches);
+ return data_volume;
+ }
+}
+
+int
+get_boot_manifest_hash(char *boot_manifest_hash, size_t boot_manifest_hash_len)
+{
+ kern_return_t err = 0;
+ io_registry_entry_t chosen;
+ CFDataRef bm_hash = NULL;
+ size_t bm_hash_size;
+ uint8_t bm_hash_buf[EDTVolumePropertyMaxSize] = {};
+ const char *hexmap = "0123456789ABCDEF";
+
+ chosen = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/chosen");
+ if (chosen == IO_OBJECT_NULL) {
+ fprintf(stderr, "failed to get chosen info\n");
+ return ENOENT;
+ }
+
+ bm_hash = IORegistryEntryCreateCFProperty(chosen, CFSTR("boot-manifest-hash"), kCFAllocatorDefault, 0);
+ if (!bm_hash) {
+ fprintf(stderr, "failed to get boot-manifest-hash\n");
+ IOObjectRelease(chosen);
+ return ENOENT;
+ } else {
+ bm_hash_size = CFDataGetLength(bm_hash);
+ CFDataGetBytes(bm_hash, CFRangeMake(0, bm_hash_size), bm_hash_buf);
+
+ if (boot_manifest_hash_len < (bm_hash_size * 2 + 1)) {
+ err = EINVAL;
+ } else {
+ // hexdump the hash into input buffer
+ for (size_t i = 0; i < (2 * bm_hash_size); i++)
+ *boot_manifest_hash++ = hexmap[(bm_hash_buf[i / 2] >> ((i % 2) ? 0 : 4)) & 0xf];
+ *boot_manifest_hash = '\0';
+ }
+ CFRelease(bm_hash);
+ IOObjectRelease(chosen);
+ }
+
+ return err;
+}
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
diff --git a/diskdev_cmds/edt_fstab/edt_fstab.h b/diskdev_cmds/edt_fstab/edt_fstab.h
new file mode 100644
index 0000000..1fd4926
--- /dev/null
+++ b/diskdev_cmds/edt_fstab/edt_fstab.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+// edt_fstab.h
+//
+// Created on 12/11/2018.
+//
+
+#ifndef edt_fstab_h
+#define edt_fstab_h
+
+#include <TargetConditionals.h>
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#define RAMDISK_FS_SPEC "ramdisk"
+
+/*
+ * get_boot_container, get_data_volume - return the bsd name of the requested
+ * device upon success. Null otherwise.
+ */
+const char *get_boot_container(uint32_t *os_env);
+const char *get_data_volume(void);
+
+int get_boot_manifest_hash(char *boot_manifest_hash, size_t boot_manifest_hash_len);
+#endif
+
+#endif /* edt_fstab_h */
diff --git a/diskdev_cmds/fdisk.tproj/auto.c b/diskdev_cmds/fdisk.tproj/auto.c
new file mode 100644
index 0000000..155f7ab
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/auto.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Auto partitioning code.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+#include "disk.h"
+#include "mbr.h"
+#include "auto.h"
+
+int AUTO_boothfs __P((disk_t *, mbr_t *));
+int AUTO_hfs __P((disk_t *, mbr_t *));
+int AUTO_dos __P((disk_t *, mbr_t *));
+int AUTO_raid __P((disk_t *, mbr_t *));
+
+/* The default style is the first one in the list */
+struct _auto_style {
+ char *style_name;
+ int (*style_fn)(disk_t *, mbr_t *);
+ char *description;
+} style_fns[] = {
+ {"boothfs", AUTO_boothfs, "8Mb boot plus HFS+ root partition"},
+ {"hfs", AUTO_hfs, "Entire disk as one HFS+ partition"},
+ {"dos", AUTO_dos, "Entire disk as one DOS partition"},
+ {"raid", AUTO_raid, "Entire disk as one 0xAC partition"},
+ {0,0}
+};
+
+void
+AUTO_print_styles(FILE *f)
+{
+ struct _auto_style *fp;
+ int i;
+
+ for (i=0, fp = &style_fns[0]; fp->style_name != NULL; i++, fp++) {
+ fprintf(f, " %-10s %s%s\n", fp->style_name, fp->description, (i==0) ? " (default)" : "");
+ }
+}
+
+
+int
+AUTO_init(disk_t *disk, char *style, mbr_t *mbr)
+{
+ struct _auto_style *fp;
+
+ for (fp = &style_fns[0]; fp->style_name != NULL; fp++) {
+ /* If style is NULL, use the first (default) style */
+ if (style == NULL || strcasecmp(style, fp->style_name) == 0) {
+ return (*fp->style_fn)(disk, mbr);
+ }
+ }
+ warnx("No such auto-partition style %s", style);
+ return AUTO_ERR;
+}
+
+
+static int
+use_whole_disk(disk_t *disk, unsigned char id, mbr_t *mbr)
+{
+ MBR_clear(mbr);
+ mbr->part[0].id = id;
+ mbr->part[0].bs = 63;
+ mbr->part[0].ns = disk->real->size - 63;
+ PRT_fix_CHS(disk, &mbr->part[0], 0);
+ return AUTO_OK;
+}
+
+/* DOS style: one partition for the whole disk */
+int
+AUTO_dos(disk_t *disk, mbr_t *mbr)
+{
+ int cc;
+ cc = use_whole_disk(disk, 0x0C, mbr);
+ if (cc == AUTO_OK) {
+ mbr->part[0].flag = DOSACTIVE;
+ }
+ return cc;
+}
+
+/* HFS style: one partition for the whole disk */
+int
+AUTO_hfs(disk_t *disk, mbr_t *mbr)
+{
+ int cc;
+ cc = use_whole_disk(disk, 0xAF, mbr);
+ if (cc == AUTO_OK) {
+ mbr->part[0].flag = DOSACTIVE;
+ }
+ return cc;
+}
+
+/* One boot partition, one HFS+ root partition */
+int
+AUTO_boothfs (disk_t *disk, mbr_t *mbr)
+{
+ /* Check disk size. */
+ if (disk->real->size < 16 * 2048) {
+ errx(1, "Disk size must be greater than 16Mb");
+ return AUTO_ERR;
+ }
+
+ MBR_clear(mbr);
+
+ /* 8MB boot partition */
+ mbr->part[0].id = 0xAB;
+ mbr->part[0].bs = 63;
+ mbr->part[0].ns = 8 * 1024 * 2;
+ mbr->part[0].flag = DOSACTIVE;
+ PRT_fix_CHS(disk, &mbr->part[0], 0);
+
+ /* Rest of the disk for rooting */
+ mbr->part[1].id = 0xAF;
+ mbr->part[1].bs = (mbr->part[0].bs + mbr->part[0].ns);
+ mbr->part[1].ns = disk->real->size - mbr->part[0].ns - 63;
+ PRT_fix_CHS(disk, &mbr->part[1], 1);
+
+ return AUTO_OK;
+}
+
+
+
+/* RAID style: one 0xAC partition for the whole disk */
+int
+AUTO_raid(disk_t *disk, mbr_t *mbr)
+{
+ return use_whole_disk(disk, 0xAC, mbr);
+}
+
diff --git a/diskdev_cmds/fdisk.tproj/auto.h b/diskdev_cmds/fdisk.tproj/auto.h
new file mode 100644
index 0000000..c9259d4
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/auto.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "mbr.h"
+
+/* Prototypes */
+void AUTO_print_styles __P((FILE *));
+int AUTO_init __P((disk_t *, char *, mbr_t *));
+
+#define AUTO_OK 0
+#define AUTO_ERR -1
diff --git a/diskdev_cmds/fdisk.tproj/cmd.c b/diskdev_cmds/fdisk.tproj/cmd.c
new file mode 100644
index 0000000..41cee77
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/cmd.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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 <stdio.h>
+#include <ctype.h>
+#include <memory.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/fcntl.h>
+#include "disk.h"
+#include "misc.h"
+#include "user.h"
+#include "part.h"
+#include "cmd.h"
+#include "auto.h"
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+
+int
+Xerase(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ bzero(mbr->part, sizeof(mbr->part));
+ mbr->signature = MBR_SIGNATURE;
+ return (CMD_DIRTY);
+}
+
+int
+Xreinit(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ /* Copy template MBR */
+ MBR_make(tt);
+ MBR_parse(disk, offset, 0, mbr);
+
+ MBR_init(disk, mbr);
+
+ /* Tell em we did something */
+ printf("In memory copy is initialized to:\n");
+ printf("Offset: %d\t", offset);
+ MBR_print(mbr);
+ printf("Use 'write' to update disk.\n");
+
+ return (CMD_DIRTY);
+}
+
+int
+Xauto(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ if (cmd->args[0] == '\0') {
+ printf("usage: auto <style>\n");
+ printf(" where style is one of:\n");
+ AUTO_print_styles(stdout);
+ return (CMD_CONT);
+ }
+
+ if (AUTO_init(disk, cmd->args, mbr) != AUTO_OK) {
+ return (CMD_CONT);
+ }
+ MBR_make(mbr);
+ return (CMD_DIRTY);
+}
+
+int
+Xdisk(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ int maxcyl = 1024;
+ int maxhead = 256;
+ int maxsec = 63;
+
+ /* Print out disk info */
+ DISK_printmetrics(disk);
+
+#if defined (__powerpc__) || defined (__mips__)
+ maxcyl = 9999999;
+ maxhead = 9999999;
+ maxsec = 9999999;
+#endif
+
+ /* Ask for new info */
+ if (ask_yn("Change disk geometry?", 0)) {
+ disk->real->cylinders = ask_num("BIOS Cylinders", ASK_DEC,
+ disk->real->cylinders, 1, maxcyl, NULL);
+ disk->real->heads = ask_num("BIOS Heads", ASK_DEC,
+ disk->real->heads, 1, maxhead, NULL);
+ disk->real->sectors = ask_num("BIOS Sectors", ASK_DEC,
+ disk->real->sectors, 1, maxsec, NULL);
+
+ disk->real->size = disk->real->cylinders * disk->real->heads
+ * disk->real->sectors;
+ }
+
+ return (CMD_CONT);
+}
+
+int
+Xedit(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ int pn, num, ret;
+ prt_t *pp;
+
+ ret = CMD_CONT;
+
+ if (!isdigit(cmd->args[0])) {
+ printf("Invalid argument: %s <partition number>\n", cmd->cmd);
+ return (ret);
+ }
+ pn = atoi(cmd->args) - 1;
+
+ if (pn < 0 || pn > 3) {
+ printf("Invalid partition number.\n");
+ return (ret);
+ }
+
+ /* Print out current table entry */
+ pp = &mbr->part[pn];
+ PRT_print(0, NULL);
+ PRT_print(pn, pp);
+
+#define EDIT(p, f, v, n, m, h) \
+ if ((num = ask_num(p, f, v, n, m, h)) != v) \
+ ret = CMD_DIRTY; \
+ v = num;
+
+ /* Ask for partition type */
+ EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
+
+ /* Unused, so just zero out */
+ if (pp->id == DOSPTYP_UNUSED) {
+ memset(pp, 0, sizeof(*pp));
+ printf("Partition %d is disabled.\n", pn + 1);
+ return (ret);
+ }
+
+ /* Change table entry */
+ if (ask_yn("Do you wish to edit in CHS mode?", 0)) {
+ int maxcyl, maxhead, maxsect;
+
+ /* Shorter */
+ maxcyl = disk->real->cylinders - 1;
+ maxhead = disk->real->heads - 1;
+ maxsect = disk->real->sectors;
+
+ /* Get data */
+ EDIT("BIOS Starting cylinder", ASK_DEC, pp->scyl, 0, maxcyl, NULL);
+ EDIT("BIOS Starting head", ASK_DEC, pp->shead, 0, maxhead, NULL);
+ EDIT("BIOS Starting sector", ASK_DEC, pp->ssect, 1, maxsect, NULL);
+ EDIT("BIOS Ending cylinder", ASK_DEC, pp->ecyl, 0, maxcyl, NULL);
+ EDIT("BIOS Ending head", ASK_DEC, pp->ehead, 0, maxhead, NULL);
+ EDIT("BIOS Ending sector", ASK_DEC, pp->esect, 1, maxsect, NULL);
+ /* Fix up off/size values */
+ PRT_fix_BN(disk, pp, pn);
+ /* Fix up CHS values for LBA */
+ PRT_fix_CHS(disk, pp, pn);
+ } else {
+ u_int m;
+
+ if (pn == 0) {
+ pp->bs = 63 + offset;
+ } else {
+ if (mbr->part[pn-1].id != 0) {
+ pp->bs = mbr->part[pn-1].bs + mbr->part[pn-1].ns;
+ }
+ }
+ /* Get data */
+ EDIT("Partition offset", ASK_DEC, pp->bs, 0,
+ disk->real->size, NULL);
+ m = MAX(pp->ns, disk->real->size - pp->bs);
+ if ( m > disk->real->size - pp->bs) {
+ /* dont have default value extend beyond end of disk */
+ m = disk->real->size - pp->bs;
+ }
+ pp->ns = m;
+ EDIT("Partition size", ASK_DEC, pp->ns, 1,
+ m, NULL);
+
+ /* Fix up CHS values */
+ PRT_fix_CHS(disk, pp, pn);
+ }
+#undef EDIT
+ return (ret);
+}
+
+int
+Xsetpid(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ int pn, num, ret;
+ prt_t *pp;
+
+ ret = CMD_CONT;
+
+ if (!isdigit(cmd->args[0])) {
+ printf("Invalid argument: %s <partition number>\n", cmd->cmd);
+ return (ret);
+ }
+ pn = atoi(cmd->args) - 1;
+
+ if (pn < 0 || pn > 3) {
+ printf("Invalid partition number.\n");
+ return (ret);
+ }
+
+ /* Print out current table entry */
+ pp = &mbr->part[pn];
+ PRT_print(0, NULL);
+ PRT_print(pn, pp);
+
+#define EDIT(p, f, v, n, m, h) \
+ if ((num = ask_num(p, f, v, n, m, h)) != v) \
+ ret = CMD_DIRTY; \
+ v = num;
+
+ /* Ask for partition type */
+ EDIT("Partition id ('0' to disable) ", ASK_HEX, pp->id, 0, 0xFF, PRT_printall);
+
+#undef EDIT
+ return (ret);
+}
+int
+Xselect(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ static int firstoff = 0;
+ int off;
+ int pn;
+
+ if (!isdigit(cmd->args[0])) {
+ printf("Invalid argument: %s <partition number>\n", cmd->cmd);
+ return (CMD_CONT);
+ }
+
+ pn = atoi(cmd->args) - 1;
+ if (pn < 0 || pn > 3) {
+ printf("Invalid partition number.\n");
+ return (CMD_CONT);
+ }
+
+ off = mbr->part[pn].bs;
+
+ /* Sanity checks */
+ if ((mbr->part[pn].id != DOSPTYP_EXTEND) &&
+ (mbr->part[pn].id != DOSPTYP_EXTENDL)) {
+ printf("Partition %d is not an extended partition.\n", pn + 1);
+ return (CMD_CONT);
+ }
+
+ if (firstoff == 0)
+ firstoff = off;
+
+ if (!off) {
+ printf("Loop to offset 0! Not selected.\n");
+ return (CMD_CONT);
+ } else {
+ printf("Selected extended partition %d\n", pn + 1);
+ printf("New MBR at offset %d.\n", off);
+ }
+
+ /* Recursion is beautifull! */
+ USER_modify(disk, tt, off, firstoff);
+ return (CMD_CONT);
+}
+
+int
+Xprint(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+
+ DISK_printmetrics(disk);
+ printf("Offset: %d\t", offset);
+ MBR_print(mbr);
+
+ return (CMD_CONT);
+}
+
+int
+Xwrite(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ int fd;
+ int shared = 0;
+
+ fd = DISK_openshared(disk->name, O_RDWR, &shared);
+ if(shared) {
+ if(!ask_yn("Device could not be accessed exclusively.\nA reboot will be needed for changes to take effect. OK?", 0)) {
+ close(fd);
+ printf("MBR unchanged\n");
+ return (CMD_CONT);
+ }
+ }
+
+ printf("Writing MBR at offset %d.\n", offset);
+
+ MBR_make(mbr);
+ MBR_write(disk, fd, mbr);
+ close(fd);
+ return (CMD_CLEAN);
+}
+
+int
+Xquit(cmd, disk, r, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *r;
+ mbr_t *tt;
+ int offset;
+{
+
+ /* Nothing to do here */
+ return (CMD_SAVE);
+}
+
+int
+Xabort(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ exit(0);
+
+ /* NOTREACHED */
+ return (CMD_CONT);
+}
+
+
+int
+Xexit(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+
+ /* Nothing to do here */
+ return (CMD_EXIT);
+}
+
+int
+Xhelp(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ cmd_table_t *cmd_table = cmd->table;
+ int i;
+
+ /* Hmm, print out cmd_table here... */
+ for (i = 0; cmd_table[i].cmd != NULL; i++)
+ printf("\t%s\t\t%s\n", cmd_table[i].cmd, cmd_table[i].help);
+ return (CMD_CONT);
+}
+
+int
+Xupdate(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ extern char *mbr_binary;
+ /* Update code */
+ memcpy(mbr->code, mbr_binary, MBR_CODE_SIZE);
+ printf("Machine code updated.\n");
+ return (CMD_DIRTY);
+}
+
+int
+Xflag(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ int i, pn = -1;
+
+ /* Parse partition table entry number */
+ if (!isdigit(cmd->args[0])) {
+ printf("Invalid argument: %s <partition number>\n", cmd->cmd);
+ return (CMD_CONT);
+ }
+ pn = atoi(cmd->args) - 1;
+
+ if (pn < 0 || pn > 3) {
+ printf("Invalid partition number.\n");
+ return (CMD_CONT);
+ }
+
+ /* Set active flag */
+ for (i = 0; i < 4; i++) {
+ if (i == pn)
+ mbr->part[i].flag = DOSACTIVE;
+ else
+ mbr->part[i].flag = 0x00;
+ }
+
+ printf("Partition %d marked active.\n", pn + 1);
+ return (CMD_DIRTY);
+}
+
+int
+Xmanual(cmd, disk, mbr, tt, offset)
+ cmd_t *cmd;
+ disk_t *disk;
+ mbr_t *mbr;
+ mbr_t *tt;
+ int offset;
+{
+ system("man 8 fdisk");
+ return (CMD_CONT);
+}
diff --git a/diskdev_cmds/fdisk.tproj/cmd.h b/diskdev_cmds/fdisk.tproj/cmd.h
new file mode 100644
index 0000000..0c2b727
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/cmd.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#ifndef _CMD_H
+#define _CMD_H
+
+/* Includes */
+#include "disk.h"
+#include "mbr.h"
+
+
+/* Constants (returned by cmd funs) */
+#define CMD_EXIT 0x0000
+#define CMD_SAVE 0x0001
+#define CMD_CONT 0x0002
+#define CMD_CLEAN 0x0003
+#define CMD_DIRTY 0x0004
+
+
+/* Data types */
+struct _cmd_table_t;
+typedef struct _cmd_t {
+ struct _cmd_table_t *table;
+ char cmd[10];
+ char args[100];
+} cmd_t;
+
+typedef struct _cmd_table_t {
+ char *cmd;
+ int (*fcn)(cmd_t *, disk_t *, mbr_t *, mbr_t *, int);
+ char *help;
+} cmd_table_t;
+
+
+/* Prototypes */
+int Xerase __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xreinit __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xauto __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xdisk __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xmanual __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xedit __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xsetpid __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xselect __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xprint __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xwrite __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xexit __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xquit __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xabort __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xhelp __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xflag __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+int Xupdate __P((cmd_t *, disk_t *, mbr_t *, mbr_t *, int));
+
+#endif /* _CMD_H */
+
+
diff --git a/diskdev_cmds/fdisk.tproj/disk.c b/diskdev_cmds/fdisk.tproj/disk.c
new file mode 100644
index 0000000..2d04113
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/disk.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2002, 2012 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997, 2001 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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 <err.h>
+#include <util.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/reboot.h>
+#include <sys/disk.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#ifdef __i386__
+#include <pexpert/i386/boot.h>
+#endif
+#include "disk.h"
+
+int
+DISK_open(disk, mode)
+ char *disk;
+ int mode;
+{
+ int fd;
+ struct stat st;
+
+ fd = open(disk, mode);
+ if (fd == -1)
+ err(1, "%s", disk);
+ if (fstat(fd, &st) == -1)
+ err(1, "%s", disk);
+ /* Don't be so picky about needing a character device */
+ if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode))
+ errx(1, "%s is not a character device or a regular file", disk);
+ return (fd);
+}
+
+int
+DISK_openshared(disk, mode, shared)
+ char *disk;
+ int mode;
+ int *shared;
+{
+ int fd;
+ struct stat st;
+ *shared = 0;
+
+ fd = open(disk, mode|O_EXLOCK);
+ if (fd == -1) {
+ // if we can't have exclusive access, attempt
+ // to gracefully degrade to shared access
+ fd = open(disk, mode|O_SHLOCK);
+ if(fd == -1)
+ err(1, "%s", disk);
+
+ *shared = 1;
+ }
+
+ if (fstat(fd, &st) == -1)
+ err(1, "%s", disk);
+ /* Don't be so picky about needing a character device */
+ if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode) && !S_ISREG(st.st_mode))
+ errx(1, "%s is not a character device or a regular file", disk);
+ return (fd);
+}
+
+int
+DISK_close(fd)
+ int fd;
+{
+
+ return (close(fd));
+}
+
+/* Given a size in the metrics,
+ * fake up a CHS geometry.
+ */
+void
+DISK_fake_CHS(DISK_metrics *lm)
+{
+ int heads = 4;
+ int spt = 63;
+ int cylinders = (lm->size / heads / spt);
+
+ while (cylinders > 1024 && heads < 256) {
+ heads *= 2;
+ cylinders /= 2;
+ }
+ if (heads == 256) {
+ heads = 255;
+ cylinders = (lm->size / heads / spt);
+ }
+ lm->cylinders = cylinders;
+ lm->heads = heads;
+ lm->sectors = spt;
+}
+
+/* Routine to go after the disklabel for geometry
+ * information. This should work everywhere, but
+ * in the land of PC, things are not always what
+ * they seem.
+ */
+DISK_metrics *
+DISK_getlabelmetrics(name)
+ char *name;
+{
+ DISK_metrics *lm = NULL;
+ long long size;
+ uint32_t sector_size;
+ int fd;
+ struct stat st;
+
+ /* Get label metrics */
+ if ((fd = DISK_open(name, O_RDONLY)) != -1) {
+ lm = malloc(sizeof(DISK_metrics));
+
+ if (fstat(fd, &st) == -1)
+ err(1, "%s", name);
+ if (!S_ISREG(st.st_mode) || S_ISBLK(st.st_mode)) {
+ if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size) == -1) {
+ err(1, "Could not get disk block count");
+ free(lm);
+ return NULL;
+ }
+ if (ioctl(fd, DKIOCGETBLOCKSIZE, &sector_size) == -1) {
+ err(1, "Could not get disk block size");
+ free(lm);
+ return NULL;
+ }
+ } else {
+ sector_size = 512;
+ size = st.st_size / sector_size;
+ }
+
+ lm->sector_size = sector_size;
+ lm->size = size;
+ DISK_fake_CHS(lm);
+ DISK_close(fd);
+ }
+
+ return (lm);
+}
+
+/*
+ * Don't try to get BIOS disk metrics.
+ */
+DISK_metrics *
+DISK_getbiosmetrics(name)
+ char *name;
+{
+ return (NULL);
+}
+
+/* This is ugly, and convoluted. All the magic
+ * for disk geo/size happens here. Basically,
+ * the real size is the one we will use in the
+ * rest of the program, the label size is what we
+ * got from the disklabel. If the disklabel fails,
+ * we assume we are working with a normal file,
+ * and should request the user to specify the
+ * geometry he/she wishes to use.
+ */
+int
+DISK_getmetrics(disk, user)
+ disk_t *disk;
+ DISK_metrics *user;
+{
+
+ disk->label = DISK_getlabelmetrics(disk->name);
+ disk->bios = DISK_getbiosmetrics(disk->name);
+
+ /* If user supplied, use that */
+ if (user) {
+ disk->real = user;
+ return (0);
+ }
+
+ /* Fixup bios metrics to include cylinders past 1023 boundary */
+ if(disk->label && disk->bios){
+ int cyls, secs;
+
+ cyls = disk->label->size / (disk->bios->heads * disk->bios->sectors);
+ secs = cyls * (disk->bios->heads * disk->bios->sectors);
+ if (disk->label->size < secs) {
+ errx(1, "BIOS fixup botch (%u sectors)", disk->label->size - secs);
+ }
+ disk->bios->cylinders = cyls;
+ disk->bios->size = secs;
+ }
+
+ /* If we have a (fixed) BIOS geometry, use that */
+ if (disk->bios) {
+ disk->real = disk->bios;
+ return (0);
+ }
+
+ /* If we have a label, use that */
+ if (disk->label) {
+ disk->real = disk->label;
+ return (0);
+ }
+
+ /* Can not get geometry, punt */
+ disk->real = NULL;
+ return (1);
+}
+
+/* Get the disk's native sector size, updating the metrics' sector_size field.
+ */
+ int
+DISK_get_sector_size(disk, user)
+ disk_t *disk;
+ DISK_metrics *user;
+{
+ int ret;
+ int fd;
+ uint32_t sector_size;
+
+ /* Default to 512 bytes per sector, in case of failure. */
+ user->sector_size = 512;
+ ret = 1;
+
+ fd = DISK_open(disk->name, O_RDONLY);
+ if (fd == -1) {
+ err(1, "Could not open %s", disk->name);
+ } else {
+ if (ioctl(fd, DKIOCGETBLOCKSIZE, &sector_size) == -1) {
+ err(1, "Could not get disk block size");
+ } else {
+ user->sector_size = sector_size;
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+int
+DISK_printmetrics(disk)
+ disk_t *disk;
+{
+
+ printf("Disk: %s\t", disk->name);
+ if (disk->real) {
+ printf("geometry: %u/%u/%u [%u sectors]\n", disk->real->cylinders,
+ disk->real->heads, disk->real->sectors, disk->real->size);
+ if (disk->real->sector_size != 512)
+ printf("Sector size: %u bytes\n", disk->real->sector_size);
+ } else {
+ printf("geometry: <none>\n");
+ }
+
+ return (0);
+}
+
diff --git a/diskdev_cmds/fdisk.tproj/disk.h b/diskdev_cmds/fdisk.tproj/disk.h
new file mode 100644
index 0000000..a8a97ef
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/disk.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2002,2012 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#ifndef _DISK_H
+#define _DISK_H
+
+/* Data types */
+typedef struct _DISK_metrics {
+ unsigned int cylinders;
+ unsigned int heads;
+ unsigned int sectors;
+ unsigned int size; /* Number of sectors in disk */
+ unsigned int sector_size; /* Bytes per sector */
+} DISK_metrics;
+
+typedef struct _disk_t {
+ char *name;
+ DISK_metrics *bios; /* Metrics as reported by BIOS (always NULL) */
+ DISK_metrics *label; /* As reported by device ioctls */
+ DISK_metrics *real; /* Metrics we're using (BIOS, ioctls, user-supplied) */
+} disk_t;
+
+/* Prototypes */
+int DISK_open __P((char *, int));
+int DISK_openshared __P((char *, int, int *));
+int DISK_close __P((int));
+int DISK_getmetrics __P((disk_t *, DISK_metrics *));
+int DISK_get_sector_size __P((disk_t *, DISK_metrics *));
+int DISK_printmetrics __P((disk_t *));
+void DISK_fake_CHS __P((DISK_metrics *));
+
+#endif /* _DISK_H */
+
diff --git a/diskdev_cmds/fdisk.tproj/fdisk.8 b/diskdev_cmds/fdisk.tproj/fdisk.8
new file mode 100644
index 0000000..c74c091
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/fdisk.8
@@ -0,0 +1,377 @@
+.\" $OpenBSD: fdisk.8,v 1.38 2002/01/04 21:20:56 kjell Exp $
+.\"
+.\" Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+.\"
+.\" "Portions Copyright (c) 2002 Apple Computer, Inc. All Rights
+.\" Reserved. This file contains Original Code and/or Modifications of
+.\" Original Code as defined in and that are subject to the Apple Public
+.\" Source License Version 1.2 (the 'License'). You may not use this file
+.\" except in compliance with the License. Please obtain a copy of the
+.\" License at http://www.apple.com/publicsource and read it before using
+.\" this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License."
+.\"
+.\" Copyright (c) 1997 Tobias Weingartner
+.\" 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 Tobias Weingartner.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" 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.
+.\"
+.Dd January 3, 2002
+.Dt FDISK 8
+.Os
+.Sh NAME
+.Nm fdisk
+.Nd DOS partition maintenance program
+.Sh SYNOPSIS
+.Nm fdisk
+.Op Fl ieu
+.Op Fl f Ar mbrname
+.Op Fl c Ar cylinders
+.Op Fl h Ar heads
+.Op Fl s Ar sectors
+.Op Fl S Ar size
+.Op Fl b Ar size
+.Ar device
+.Sh DESCRIPTION
+In order for the BIOS to boot the kernel, certain conventions must be
+adhered to.
+Sector 0 of a bootable hard disk must contain boot code,
+an MBR partition table, and a magic number (0xAA55).
+These MBR partitions (also
+known as BIOS partitions) can be used to break the disk up into several
+pieces.
+.Pp
+The BIOS loads sector 0 of the boot disk into memory, verifies
+the magic number, and begins executing the code at the first byte.
+The normal DOS MBR boot code searches the MBR partition table for an
+.Dq active
+partition (indicated by a
+.Ql \&*
+in the first column), and if one
+is found, the boot block from that partition is loaded and executed in
+place of the original (MBR) boot block.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl i
+Initialize the MBR sector.
+.It Fl a Ar style
+Specify an automatic partitioning style.
+.It Fl e
+Edit existing MBR sectors.
+.It Fl f Ar mbrname
+Specifies an alternate MBR template file.
+.It Fl u
+Update MBR code, preserving existing partition table.
+.It Fl y
+Do not ask for confirmation before writing.
+.It Fl d
+Dump partition table in a format readable by the -r option.
+.It Fl r
+Read a partition table from the standard input.
+.It Fl t
+Test if the disk is partitioned.
+.It Xo Fl c Ar cylinders ,
+.Fl h Ar heads ,
+.Fl s Ar sectors
+.Xc
+Specifies an alternate BIOS geometry for
+.Nm
+to use.
+.It Fl S Ar size
+Specify the disk size in blocks.
+.It Fl b Ar size
+Specify the number of bytes per disk block.
+.El
+.Pp
+The DOS
+.Nm
+program can be used to divide space on the disk into partitions and set
+one active.
+This
+.Nm
+program serves a similar purpose to the DOS program.
+When called with no special flags, it prints the MBR partition
+table of the specified device, i.e.,
+.Bd -literal
+ # fdisk fd0
+ Disk: fd0 geometry: 80/2/18 [2880 sectors]
+ Offset: 0 Signature: 0xAA55
+ Starting Ending
+ #: id cyl hd sec - cyl hd sec [ start - size]
+ ----------------------------------------------------------------------
+ *1: A6 0 0 1 - 79 1 18 [ 0 - 2880] OpenBSD
+ 2: 00 0 0 0 - 0 0 0 [ 0 - 0] unused
+ 3: A7 0 0 2 - 79 1 18 [ 1 - 2879] NEXTSTEP
+ 4: 00 0 0 0 - 0 0 0 [ 0 - 0] unused
+.Ed
+.Pp
+The geometry displayed is a synthetic geometry unless another geometry
+has been selected using the
+.Fl c ,
+.Fl h ,
+.Fl s ,
+.Fl S ,
+and
+.Fl b
+options.
+In the future,
+.Nm
+will read the BIOS geometry from the IOKit registry.
+.Pp
+In this example,
+the disk is divided into two partitions that happen to fill the disk.
+The first partition overlaps the third partition.
+(Used for debugging purposes.)
+.Bl -tag -width "start/size"
+.It Em "#"
+Number of partition table entry.
+A
+.Dq \&*
+denotes the bootable partition.
+.It Em "id"
+System identifier.
+.Ox
+reserves the
+magic number 166 decimal (A6 in hex).
+If no 166 partition is found, it will use an older
+.Fx
+partition (with a magic number of 165 or A5 in hex).
+.It Em "cyl/hd/sec"
+These fields provide the starting and ending address of the partition
+in BIOS geometry
+.It Em "start/size"
+These fields provide the starting sector and size in sectors of the
+partition in linear block addresses.
+.El
+.Pp
+.Em NOTE :
+The sectors field is
+.Dq 1 based ,
+and the start field is
+.Dq 0 based .
+The CHS values may need to be in the BIOS's geometry
+for older systems to be able to boot and use the drive correctly;
+most modern systems prefer the starting sector and size
+in preference to the CHS values.
+.Pp
+The
+.Fl i
+flag is used to indicate that the partition data is to be initialized.
+In this mode,
+.Nm
+will completely overwrite the primary MBR and partition table, either
+using the default MBR template, or the one specified by the
+.Fl f
+flag.
+.Pp
+In the default template, partition number 1 will be configured as a
+Darwin boot
+partition spanning from cylinder 0, head 1, sector 1, and extending
+for 8 megabytes.
+Partition number 2 will be configured as a
+Darwin HFS
+partition spanning the rest of the disk.
+This mode is designed to initialize an MBR the very first time,
+or when it has been corrupted beyond repair.
+.Pp
+You can specify other default partition styles with the
+.Fl a
+flag. The available styles are:
+.Bl -tag -width "start/size"
+.It Em "boothfs"
+Creates an 8Mb boot partition (type AB hex)
+and makes the rest of the disk
+a Darwin HFS partition (type AF hex).
+.It Em "hfs"
+Makes the entire disk one HFS+ partition (type AF hex).
+.It Em "dos"
+Makes the entire disk one DOS partition (type 0C hex).
+.It Em "raid"
+Makes the entire disk one type AC hex partition.
+.El
+.Pp
+The
+.Fl u
+flag is used to update the MBR code on a given drive.
+The MBR code extends from offset 0x000 to the start of the partition table
+at offset 0x1BE.
+It is similar to the
+.Fl i
+flag, except the existing partition table is preserved. This
+is useful for writing new MBR code onto an existing drive, and is
+equivalent to the DOS command
+.Dq FDISK /MBR .
+Note that this option will overwrite the NT disk signature, if present.
+The
+.Fl u
+and
+.Fl i
+flags may not be specified together.
+.Pp
+The flag
+.Fl e
+is used to modify a partition table using a interactive edit mode of the
+.Nm
+program.
+This mode is designed to allow you to change any partition on the
+drive you choose, including extended partitions.
+It is a very powerful mode,
+but is safe as long as you do not execute the
+.Em write
+command, or answer in the negative (the default) when
+.Nm
+asks you about writing out changes.
+.Sh COMMAND MODE
+When you first enter this mode, you are presented with a prompt, that looks
+like so:
+.Em "fdisk: 0>" .
+This prompt has two important pieces of information for you.
+It will tell
+you if the in-memory copy of the boot block has been modified or not.
+If it has been modified, the prompt will change to look like:
+.Em "fdisk:*0>" .
+The second piece of information pertains to the number given in the prompt.
+This number specifies the disk offset of the currently selected boot block
+you are editing.
+This number could be something different that zero when
+you are editing extended partitions.
+The list of commands and their explanations are given below.
+.Bl -tag -width "update"
+.It Em help
+Display a list of commands that
+.Nm
+understands in the interactive edit mode.
+.It Em manual
+Display this manual page.
+.It Em reinit
+Initialize the currently selected, in-memory copy of the
+boot block.
+.It Em auto
+Partition the disk with one of the automatic partition styles.
+.It Em disk
+Display the current drive geometry that
+.Nm
+has
+probed.
+You are given a chance to edit it if you wish.
+.It Em edit
+Edit a given table entry in the memory copy of
+the current boot block.
+You may edit either in BIOS geometry mode,
+or in sector offsets and sizes.
+.It Em setpid
+Change the partition
+identifier of the given partition table entry.
+This command is particularly useful for reassigning
+an existing partition to OpenBSD.
+.It Em flag
+Make the given partition table entry bootable.
+Only one entry can be marked bootable.
+If you wish to boot from an extended
+partition, you will need to mark the partition table entry for the
+extended partition as bootable.
+.It Em update
+Update the machine code in the memory copy of the currently selected
+boot block.
+Note that this option will overwrite the NT disk
+signature, if present.
+.It Em select
+Select and load into memory the boot block pointed
+to by the extended partition table entry in the current boot block.
+.It Em print
+Print the currently selected in-memory copy of the boot
+block and its MBR table to the terminal.
+.It Em write
+Write the in-memory copy of the boot block to disk.
+You will be asked to confirm this operation.
+.It Em exit
+Exit the current level of
+.Nm fdisk ,
+either returning to the
+previously selected in-memory copy of a boot block, or exiting the
+program if there is none.
+.It Em quit
+Exit the current level of
+.Nm fdisk ,
+either returning to the
+previously selected in-memory copy of a boot block, or exiting the
+program if there is none.
+Unlike
+.Em exit
+it does write the modified block out.
+.It Em abort
+Quit program without saving current changes.
+.El
+.Sh NOTES
+The automatic calculation of starting cylinder etc. uses
+a set of figures that represent what the BIOS thinks is the
+geometry of the drive.
+These figures are by default taken from the in-core disklabel, or
+values that
+.Em /boot
+has passed to the kernel, but
+.Nm
+gives you an opportunity to change them if there is a need to.
+This allows the user to create a bootblock that can work with drives
+that use geometry translation under a potentially different BIOS.
+.Pp
+If you hand craft your disk layout,
+please make sure that the
+.Ox
+partition starts on a cylinder boundary.
+(This restriction may be changed in the future.)
+.Pp
+Editing an existing partition is risky, and may cause you to
+lose all the data in that partition.
+.Pp
+You should run this program interactively once or twice to see how it works.
+This is completely safe as long as you answer the
+.Dq write
+questions in the
+negative.
+.Sh FILES
+.Bl -tag -width /usr/mdec/mbr -compact
+.It Pa /usr/mdec/mbr
+default MBR template
+.El
+.Sh SEE ALSO
+.Xr gpt 8 ,
+.Xr pdisk 8
+.Sh BUGS
+There are subtleties
+.Nm
+detects that are not explained in this manual page.
+As well, chances are that some of the subtleties it should detect are being
+steamrolled.
+Caveat Emptor.
diff --git a/diskdev_cmds/fdisk.tproj/fdisk.c b/diskdev_cmds/fdisk.tproj/fdisk.c
new file mode 100644
index 0000000..e7b45cb
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/fdisk.c
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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 <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <paths.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include "disk.h"
+#include "user.h"
+#include "auto.h"
+
+#define _PATH_MBR "/usr/standalone/i386/boot0"
+
+void
+usage()
+{
+ extern char * __progname;
+ fprintf(stderr, "usage: %s "
+ "[-ieu] [-f mbrboot] [-c cyl -h head -s sect] [-S size] [-r] [-a style] disk\n"
+ "\t-i: initialize disk with new MBR\n"
+ "\t-u: update MBR code, preserve partition table\n"
+ "\t-e: edit MBRs on disk interactively\n"
+ "\t-f: specify non-standard MBR template\n"
+ "\t-chs: specify disk geometry\n"
+ "\t-S: specify disk size\n"
+ "\t-r: read partition specs from stdin (implies -i)\n"
+ "\t-a: auto-partition with the given style\n"
+ "\t-d: dump partition table\n"
+ "\t-y: don't ask any questions\n"
+ "\t-t: test if disk is partitioned\n"
+ "`disk' is of the form /dev/rdisk0.\n",
+ __progname);
+ fprintf(stderr, "auto-partition styles:\n");
+ AUTO_print_styles(stderr);
+ exit(1);
+}
+
+char *mbr_binary = NULL;
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch, fd;
+ int i_flag = 0, m_flag = 0, u_flag = 0, r_flag = 0, d_flag = 0, y_flag = 0, t_flag = 0;
+ int c_arg = 0, h_arg = 0, s_arg = 0;
+ int size_arg = 0;
+ int block_size_arg = 0;
+ disk_t disk;
+ DISK_metrics *usermetrics;
+ char *mbrfile = _PATH_MBR;
+ mbr_t *mp;
+ char *auto_style = NULL;
+
+ while ((ch = getopt(argc, argv, "ieuf:c:h:s:b:S:ra:dyt")) != -1) {
+ switch(ch) {
+ case 'i':
+ i_flag = 1;
+ break;
+ case 'u':
+ u_flag = 1;
+ break;
+ case 'e':
+ m_flag = 1;
+ break;
+ case 'f':
+ mbrfile = optarg;
+ break;
+ case 'c':
+ c_arg = atoi(optarg);
+ if (c_arg < 1 || c_arg > 262144)
+ errx(1, "Cylinder argument out of range.");
+ break;
+ case 'h':
+ h_arg = atoi(optarg);
+ if (h_arg < 1 || h_arg > 256)
+ errx(1, "Head argument out of range.");
+ break;
+ case 's':
+ s_arg = atoi(optarg);
+ if (s_arg < 1 || s_arg > 63)
+ errx(1, "Sector argument out of range.");
+ break;
+ case 'b':
+ block_size_arg = atoi(optarg);
+ if (block_size_arg & (block_size_arg - 1))
+ errx(1, "Block size argument not a power of two.");
+ if (block_size_arg < 512 || block_size_arg > 4096)
+ errx(1, "Block size argument out of range 512..4096.");
+ break;
+ case 'S':
+ size_arg = atoi(optarg);
+ break;
+ case 'r':
+ r_flag = 1;
+ break;
+ case 'a':
+ auto_style = optarg;
+ break;
+ case 'd':
+ d_flag = 1;
+ break;
+ case 'y':
+ y_flag = 1;
+ break;
+ case 't':
+ t_flag = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Argument checking */
+ if (argc != 1)
+ usage();
+ else
+ disk.name = argv[0];
+
+ if (i_flag && u_flag) errx(1, "-i and -u cannot be specified simultaneously");
+
+ /* Put in supplied geometry if there */
+ if (c_arg | h_arg | s_arg | size_arg | block_size_arg) {
+ usermetrics = malloc(sizeof(DISK_metrics));
+ if (usermetrics != NULL) {
+ if (c_arg && h_arg && s_arg) {
+ usermetrics->cylinders = c_arg;
+ usermetrics->heads = h_arg;
+ usermetrics->sectors = s_arg;
+ if (size_arg) {
+ usermetrics->size = size_arg;
+ } else {
+ usermetrics->size = c_arg * h_arg * s_arg;
+ }
+ } else {
+ if (size_arg) {
+ usermetrics->size = size_arg;
+ DISK_fake_CHS(usermetrics);
+ } else {
+ errx(1, "Please specify a full geometry with [-chs].");
+ }
+ }
+ if (block_size_arg) {
+ usermetrics->sector_size = block_size_arg;
+ } else {
+ DISK_get_sector_size(&disk, usermetrics);
+ }
+ }
+ } else {
+ usermetrics = NULL;
+ }
+
+ /* Get the geometry */
+ disk.real = NULL;
+ if (DISK_getmetrics(&disk, usermetrics))
+ errx(1, "Can't get disk geometry, please use [-chs] to specify.");
+
+ /* If only testing, read MBR and silently exit */
+ if (t_flag) {
+ mbr_t *mbr;
+
+ mp = mbr = MBR_read_all(&disk);
+ while (mp) {
+ if (mp->signature != MBR_SIGNATURE) {
+ MBR_free(mbr);
+ exit(1);
+ }
+ mp = mp->next;
+ }
+ MBR_free(mbr);
+ exit(0);
+ }
+
+ /* If not editing the disk, print out current MBRs on disk */
+ if ((i_flag + r_flag + u_flag + m_flag) == 0) {
+ exit(USER_print_disk(&disk, d_flag));
+ }
+
+ /* Parse mbr template or read partition specs, to pass on later */
+ if (auto_style && r_flag) {
+ errx(1, "Can't specify both -r and -a");
+ }
+
+ mbr_binary = (char *)malloc(MBR_CODE_SIZE);
+ if ((fd = open(mbrfile, O_RDONLY)) == -1) {
+ warn("could not open MBR file %s", mbrfile);
+ bzero(mbr_binary, MBR_CODE_SIZE);
+ } else {
+ int cc;
+ cc = read(fd, mbr_binary, MBR_CODE_SIZE);
+ if (cc < MBR_CODE_SIZE) {
+ err(1, "could not read MBR code");
+ }
+ close(fd);
+ }
+
+ if (u_flag) {
+ /* Don't hose the partition table; just write the boot code */
+ mp = MBR_read_all(&disk);
+ bcopy(mbr_binary, mp->code, MBR_CODE_SIZE);
+ MBR_make(mp);
+ } else if (i_flag) {
+ /* If they didn't specify -a, they'll get the default auto style */
+ mp = MBR_alloc(NULL);
+ if (AUTO_init(&disk, auto_style, mp) != AUTO_OK) {
+ errx(1, "error initializing disk");
+ }
+ bcopy(mbr_binary, mp->code, MBR_CODE_SIZE);
+ MBR_make(mp);
+ } else if (r_flag) {
+ mp = MBR_parse_spec(stdin, &disk);
+ bcopy(mbr_binary, mp->code, MBR_CODE_SIZE);
+ MBR_make(mp);
+ } else {
+ /* Use what's on the disk. */
+ mp = MBR_read_all(&disk);
+ }
+
+ /* Now do what we are supposed to */
+ if (i_flag || r_flag || u_flag) {
+ USER_write(&disk, mp, u_flag, y_flag);
+ }
+
+ if (m_flag) {
+ USER_modify(&disk, mp, 0, 0);
+ }
+
+ if (mbr_binary)
+ free(mbr_binary);
+
+ return (0);
+}
diff --git a/diskdev_cmds/fdisk.tproj/getrawpartition.c b/diskdev_cmds/fdisk.tproj/getrawpartition.c
new file mode 100644
index 0000000..9cfcb35
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/getrawpartition.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*-
+ * Copyright (c) 1996 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+#include <sys/cdefs.h>
+#if defined(LIBC_SCCS) && !defined(lint)
+__RCSID("$NetBSD: getrawpartition.c,v 1.4 1999/07/02 15:49:12 simonb Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <util.h>
+
+int
+getrawpartition()
+{
+#if 0
+ int rawpart, mib[2];
+ size_t varlen;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_RAWPARTITION;
+ varlen = sizeof(rawpart);
+ if (sysctl(mib, 2, &rawpart, &varlen, NULL, 0) < 0)
+ return (-1);
+
+ return (rawpart);
+#else
+ return 0 - 'a';
+#endif
+}
diff --git a/diskdev_cmds/fdisk.tproj/mbr.c b/diskdev_cmds/fdisk.tproj/mbr.c
new file mode 100644
index 0000000..90c8809
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/mbr.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2002, 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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 <err.h>
+#include <util.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <memory.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if 0
+#include <sys/dkio.h>
+#endif
+#include <machine/param.h>
+#include "disk.h"
+#include "misc.h"
+#include "mbr.h"
+#include "part.h"
+
+
+void
+MBR_init(disk, mbr)
+ disk_t *disk;
+ mbr_t *mbr;
+{
+ /* Fix up given mbr for this disk */
+ mbr->part[0].flag = 0;
+ mbr->part[1].flag = 0;
+ mbr->part[2].flag = 0;
+#if !defined(DOSPTYP_OPENBSD)
+ mbr->part[3].flag = 0;
+ mbr->signature = MBR_SIGNATURE;
+#else
+
+ mbr->part[3].flag = DOSACTIVE;
+ mbr->signature = DOSMBR_SIGNATURE;
+
+ /* Use whole disk, save for first head, on first cyl. */
+ mbr->part[3].id = DOSPTYP_OPENBSD;
+ mbr->part[3].scyl = 0;
+ mbr->part[3].shead = 1;
+ mbr->part[3].ssect = 1;
+
+ /* Go right to the end */
+ mbr->part[3].ecyl = disk->real->cylinders - 1;
+ mbr->part[3].ehead = disk->real->heads - 1;
+ mbr->part[3].esect = disk->real->sectors;
+
+ /* Fix up start/length fields */
+ PRT_fix_BN(disk, &mbr->part[3], 3);
+
+#if defined(__powerpc__) || defined(__mips__)
+ /* Now fix up for the MS-DOS boot partition on PowerPC. */
+ mbr->part[0].flag = DOSACTIVE; /* Boot from dos part */
+ mbr->part[3].flag = 0;
+ mbr->part[3].ns += mbr->part[3].bs;
+ mbr->part[3].bs = mbr->part[0].bs + mbr->part[0].ns;
+ mbr->part[3].ns -= mbr->part[3].bs;
+ PRT_fix_CHS(disk, &mbr->part[3], 3);
+ if ((mbr->part[3].shead != 1) || (mbr->part[3].ssect != 1)) {
+ /* align the partition on a cylinder boundary */
+ mbr->part[3].shead = 0;
+ mbr->part[3].ssect = 1;
+ mbr->part[3].scyl += 1;
+ }
+ /* Fix up start/length fields */
+ PRT_fix_BN(disk, &mbr->part[3], 3);
+#endif
+#endif
+}
+
+void
+MBR_parse(disk, offset, reloff, mbr)
+ disk_t *disk;
+ off_t offset;
+ off_t reloff;
+ mbr_t *mbr;
+{
+ int i;
+ unsigned char *mbr_buf = mbr->buf;
+
+ memcpy(mbr->code, mbr_buf, MBR_CODE_SIZE);
+ mbr->offset = offset;
+ mbr->reloffset = reloff;
+ mbr->signature = getshort(&mbr_buf[MBR_SIG_OFF]);
+
+ for (i = 0; i < NDOSPART; i++)
+ PRT_parse(disk, &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i],
+ offset, reloff, &mbr->part[i], i);
+}
+
+void
+MBR_make(mbr)
+ mbr_t *mbr;
+{
+ int i;
+ unsigned char *mbr_buf = mbr->buf;
+
+ memcpy(mbr_buf, mbr->code, MBR_CODE_SIZE);
+ putshort(&mbr_buf[MBR_SIG_OFF], mbr->signature);
+
+ for (i = 0; i < NDOSPART; i++)
+ PRT_make(&mbr->part[i], mbr->offset, mbr->reloffset,
+ &mbr_buf[MBR_PART_OFF + MBR_PART_SIZE * i]);
+}
+
+void
+MBR_print(mbr)
+ mbr_t *mbr;
+{
+ int i;
+
+ /* Header */
+ printf("Signature: 0x%X\n",
+ (int)mbr->signature);
+ PRT_print(0, NULL);
+
+ /* Entries */
+ for (i = 0; i < NDOSPART; i++)
+ PRT_print(i, &mbr->part[i]);
+}
+
+int
+MBR_read(disk, fd, where, mbr)
+ disk_t *disk;
+ int fd;
+ off_t where;
+ mbr_t *mbr;
+{
+ off_t off;
+ int len;
+ int size;
+ unsigned char *buf = mbr->buf;
+
+ size = disk->real->sector_size;
+ where *= size;
+ off = lseek(fd, where, SEEK_SET);
+ if (off != where)
+ return (off);
+ len = read(fd, buf, size);
+ if (len != size)
+ return (len);
+ return (0);
+}
+
+int
+MBR_write(disk, fd, mbr)
+ disk_t *disk;
+ int fd;
+ mbr_t *mbr;
+{
+ off_t off;
+ int len;
+ int size;
+ unsigned char *buf = mbr->buf;
+ off_t where;
+
+ size = disk->real->sector_size;
+ where = mbr->offset * size;
+ off = lseek(fd, where, SEEK_SET);
+ if (off != where)
+ return (off);
+ len = write(fd, buf, size);
+ if (len != size)
+ return (len);
+#if defined(DIOCRLDINFO)
+ (void) ioctl(fd, DIOCRLDINFO, 0);
+#endif
+ return (0);
+}
+
+void
+MBR_pcopy(disk, mbr)
+ disk_t *disk;
+ mbr_t *mbr;
+{
+ /*
+ * Copy partition table from the disk indicated
+ * to the supplied mbr structure
+ */
+
+ int i, fd, offset = 0, reloff = 0;
+ mbr_t *mbrd;
+
+ mbrd = MBR_alloc(NULL);
+ fd = DISK_open(disk->name, O_RDONLY);
+ MBR_read(disk, fd, offset, mbrd);
+ DISK_close(fd);
+ MBR_parse(disk, offset, reloff, mbrd);
+ for (i = 0; i < NDOSPART; i++) {
+ PRT_parse(disk, &mbrd->buf[MBR_PART_OFF +
+ MBR_PART_SIZE * i],
+ offset, reloff, &mbr->part[i], i);
+ PRT_print(i, &mbr->part[i]);
+ }
+ MBR_free(mbrd);
+}
+
+
+static int
+parse_number(char *str, int default_val, int base) {
+ if (str != NULL && *str != '\0') {
+ default_val = strtol(str, NULL, base);
+ }
+ return default_val;
+}
+
+static inline int
+null_arg(char *arg) {
+ if (arg == NULL || *arg == 0)
+ return 1;
+ else
+ return 0;
+}
+
+/* Parse a partition spec into a partition structure.
+ * Spec is of the form:
+ * <start>,<size>,<id>,<bootable>[,<c,h,s>,<c,h,s>]
+ * We require passing in the disk and mbr so we can
+ * set reasonable defaults for values, e.g. "the whole disk"
+ * or "starting after the last partition."
+ */
+#define N_ARGS 10
+static int
+MBR_parse_one_spec(char *line, disk_t *disk, mbr_t *mbr, int pn)
+{
+ int i;
+ char *args[N_ARGS];
+ prt_t *part = &mbr->part[pn];
+ int next_start, next_size;
+
+ /* There are up to 10 arguments. */
+ for (i=0; i<N_ARGS; i++) {
+ char *arg;
+ while (isspace(*line))
+ line++;
+ arg = strsep(&line, ",\n");
+ if (arg == NULL || line == NULL) {
+ break;
+ }
+ args[i] = arg;
+ }
+ for (; i<N_ARGS; i++) {
+ args[i] = NULL;
+ }
+ /* Set reasonable defaults. */
+ if (pn == 0) {
+ next_start = 0;
+ } else {
+ next_start = mbr->part[pn-1].bs + mbr->part[pn-1].ns;
+ }
+ next_size = disk->real->size;
+ for(i=0; i<pn; i++) {
+ next_size -= mbr->part[i].ns;
+ }
+
+ part->id = parse_number(args[2], 0xA8, 16);
+ if (!null_arg(args[3]) && *args[3] == '*') {
+ part->flag = 0x80;
+ } else {
+ part->flag = 0;
+ }
+ /* If you specify the start or end sector,
+ you have to give both. */
+ if ((null_arg(args[0]) && !null_arg(args[1])) ||
+ (!null_arg(args[0]) && null_arg(args[1]))) {
+ errx(1, "You must specify both start and size, or neither");
+ return -1;
+ }
+
+ /* If you specify one of the CHS args,
+ you have to give them all. */
+ if (!null_arg(args[4])) {
+ for (i=5; i<10; i++) {
+ if (null_arg(args[i])) {
+ errx(1, "Either all CHS arguments must be specified, or none");
+ return -1;
+ }
+ }
+
+ part->scyl = parse_number(args[4], 0, 10);
+ part->shead = parse_number(args[5], 0, 10);
+ part->ssect = parse_number(args[6], 0, 10);
+ part->scyl = parse_number(args[7], 0, 10);
+ part->shead = parse_number(args[8], 0, 10);
+ part->ssect = parse_number(args[9], 0, 10);
+ if (null_arg(args[0])) {
+ PRT_fix_BN(disk, part, pn);
+ }
+ } else {
+ /* See if they gave no CHS and no start/end */
+ if (null_arg(args[0])) {
+ errx(1, "You must specify either start sector and size or CHS");
+ return -1;
+ }
+ }
+ if (!null_arg(args[0])) {
+ part->bs = parse_number(args[0], next_start, 10);
+ part->ns = parse_number(args[1], next_size, 10);
+ PRT_fix_CHS(disk, part, pn);
+ }
+ return 0;
+}
+
+
+typedef struct _mbr_chain {
+ mbr_t mbr;
+ struct _mbr_chain *next;
+} mbr_chain_t;
+
+/* Parse some number of MBR spec lines.
+ * Spec is of the form:
+ * <start>,<size>,<id>,<bootable>[,<c,h,s>,<c,h,s>]
+ *
+ */
+mbr_t *
+MBR_parse_spec(FILE *f, disk_t *disk)
+{
+ int lineno;
+ int offset, firstoffset;
+ mbr_t *mbr, *head, *prev_mbr;
+
+ head = mbr = prev_mbr = NULL;
+ firstoffset = 0;
+ do {
+
+ offset = 0;
+ for (lineno = 0; lineno < NDOSPART && !feof(f); lineno++) {
+ char line[256];
+ char *str;
+ prt_t *part;
+
+ do {
+ str = fgets(line, 256, f);
+ } while ((str != NULL) && (*str == '\0'));
+ if (str == NULL) {
+ break;
+ }
+
+ if (mbr == NULL) {
+ mbr = MBR_alloc(prev_mbr);
+ if (head == NULL)
+ head = mbr;
+ }
+
+ if (MBR_parse_one_spec(line, disk, mbr, lineno)) {
+ /* MBR_parse_one_spec printed the error message. */
+ return NULL;
+ }
+ part = &mbr->part[lineno];
+ if ((part->id == DOSPTYP_EXTEND) || (part->id == DOSPTYP_EXTENDL)) {
+ offset = part->bs;
+ if (firstoffset == 0) firstoffset = offset;
+ }
+ }
+ /* If fewer lines than partitions, zero out the rest of the partitions */
+ if (mbr != NULL) {
+ for (; lineno < NDOSPART; lineno++) {
+ bzero(&mbr->part[lineno], sizeof(prt_t));
+ }
+ }
+ prev_mbr = mbr;
+ mbr = NULL;
+ } while (offset >= 0 && !feof(f));
+
+ return head;
+}
+
+void
+MBR_dump(mbr_t *mbr)
+{
+ int i;
+ prt_t *part;
+
+ for (i=0; i<NDOSPART; i++) {
+ part = &mbr->part[i];
+ printf("%d,%d,0x%02X,%c,%u,%u,%u,%u,%u,%u\n",
+ part->bs,
+ part->ns,
+ part->id,
+ (part->flag == 0x80) ? '*' : '-',
+ part->scyl,
+ part->shead,
+ part->ssect,
+ part->ecyl,
+ part->ehead,
+ part->esect);
+ }
+}
+
+mbr_t *
+MBR_alloc(mbr_t *parent)
+{
+ mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));
+ bzero(mbr, sizeof(mbr_t));
+ if (parent) {
+ parent->next = mbr;
+ }
+ mbr->signature = MBR_SIGNATURE;
+ return mbr;
+}
+
+void
+MBR_free(mbr_t *mbr)
+{
+ mbr_t *tmp;
+ while (mbr) {
+ tmp = mbr->next;
+ free(mbr);
+ mbr = tmp;
+ }
+}
+
+/* Read and parse all the partition tables on the disk,
+ * including extended partitions.
+ */
+mbr_t *
+MBR_read_all(disk_t *disk)
+{
+ mbr_t *mbr = NULL, *head = NULL;
+ int i, fd, offset, firstoff;
+
+ fd = DISK_open(disk->name, O_RDONLY);
+ firstoff = offset = 0;
+ do {
+ mbr = MBR_alloc(mbr);
+ if (head == NULL) {
+ head = mbr;
+ }
+ MBR_read(disk, fd, offset, mbr);
+ MBR_parse(disk, offset, firstoff, mbr);
+ if (mbr->signature != MBR_SIGNATURE) {
+ /* The MBR signature is invalid. */
+ break;
+ }
+ offset = 0;
+ for (i=0; i<NDOSPART; i++) {
+ prt_t *part = &mbr->part[i];
+ if ((part->id == DOSPTYP_EXTEND) || (part->id == DOSPTYP_EXTENDL)) {
+ offset = part->bs;
+ if (firstoff == 0) {
+ firstoff = offset;
+ }
+ }
+ }
+ } while (offset > 0);
+ DISK_close(fd);
+
+ return head;
+}
+
+
+int
+MBR_write_all(disk_t *disk, mbr_t *mbr)
+{
+ int result = 0;
+ int fd;
+
+ fd = DISK_open(disk->name, O_RDWR);
+ while (mbr) {
+ MBR_make(mbr);
+ result = MBR_write(disk, fd, mbr);
+ if (result)
+ break;
+ mbr = mbr->next;
+ }
+ DISK_close(fd);
+ return result;
+}
+
+void
+MBR_print_all(mbr_t *mbr) {
+ while (mbr) {
+ MBR_print(mbr);
+ mbr = mbr->next;
+ }
+}
+
+void
+MBR_dump_all(mbr_t *mbr) {
+ while (mbr) {
+ MBR_dump(mbr);
+ mbr = mbr->next;
+ }
+}
+
+void
+MBR_clear(mbr_t *mbr) {
+ int i;
+ if (mbr->next) {
+ MBR_free(mbr->next);
+ mbr->next = NULL;
+ }
+ for (i=0; i<4; i++) {
+ bzero(&mbr->part[i], sizeof(mbr->part[i]));
+ }
+ bzero(&mbr->buf, sizeof(mbr->buf));
+}
+
diff --git a/diskdev_cmds/fdisk.tproj/mbr.h b/diskdev_cmds/fdisk.tproj/mbr.h
new file mode 100644
index 0000000..52247ee
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/mbr.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#ifndef _MBR_H
+#define _MBR_H
+
+#include "part.h"
+
+#ifndef NDOSPART
+#define NDOSPART 4
+#define DOSPTYP_UNUSED 0
+#define DOSPTYP_EXTEND 5
+#define DOSPTYP_EXTENDL 15
+#define DOSACTIVE 128
+#endif
+
+/* Various constants */
+#define MBR_CODE_SIZE 0x1BE
+#define MBR_PART_SIZE 0x10
+#define MBR_PART_OFF 0x1BE
+#define MBR_SIG_OFF 0x1FE
+/* MBR_BUF_SIZE is the largest sector size we support */
+#define MBR_BUF_SIZE 4096
+
+#define MBR_SIGNATURE 0xAA55
+
+/* MBR type */
+typedef struct _mbr_t {
+ off_t reloffset; /* the offset of the first extended partition that contains all the rest */
+ off_t offset; /* the absolute offset of this partition */
+ struct _mbr_t *next; /* pointer to the next MBR in an extended partition chain */
+ unsigned char code[MBR_CODE_SIZE];
+ unsigned short signature;
+ prt_t part[NDOSPART];
+ unsigned char buf[MBR_BUF_SIZE];
+} mbr_t;
+
+/* Prototypes */
+void MBR_print_disk __P((char *));
+void MBR_print __P((mbr_t *));
+void MBR_print_all __P((mbr_t *));
+void MBR_parse __P((disk_t *, off_t, off_t, mbr_t *));
+void MBR_make __P((mbr_t *));
+void MBR_init __P((disk_t *, mbr_t *));
+int MBR_read __P((disk_t *,int, off_t, mbr_t *));
+int MBR_write __P((disk_t *,int, mbr_t *));
+void MBR_pcopy __P((disk_t *, mbr_t *));
+mbr_t * MBR_parse_spec __P((FILE *, disk_t *));
+void MBR_dump __P((mbr_t *));
+void MBR_dump_all __P((mbr_t *));
+mbr_t *MBR_alloc __P((mbr_t *));
+void MBR_free __P((mbr_t *));
+mbr_t * MBR_read_all __P((disk_t *));
+int MBR_write_all __P((disk_t *, mbr_t *));
+void MBR_clear __P((mbr_t *));
+
+/* Sanity check */
+#include <machine/param.h>
+#if (DEV_BSIZE != 512)
+#error "DEV_BSIZE != 512, somebody better fix me!"
+#endif
+
+#endif /* _MBR_H */
+
diff --git a/diskdev_cmds/fdisk.tproj/mbrcode.h b/diskdev_cmds/fdisk.tproj/mbrcode.h
new file mode 100644
index 0000000..2b8182e
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/mbrcode.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 2000 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+/* Largely generated by:
+ * hexdump -ve '8/1 "0x%02x, " "\n"' /usr/mdec/mbr
+ */
+0xfa, 0xea, 0x06, 0x00, 0xc0, 0x07, 0x8c, 0xc8,
+0x8e, 0xd8, 0x8e, 0xd0, 0xbc, 0xfc, 0xff, 0xfb,
+0xb0, 0x53, 0xe8, 0xe2, 0x00, 0xb8, 0xa0, 0x07,
+0x8e, 0xc0, 0x31, 0xf6, 0x31, 0xff, 0xb9, 0x00,
+0x02, 0xfc, 0xf2, 0xa4, 0xea, 0x29, 0x00, 0xa0,
+0x07, 0xb0, 0x52, 0xe8, 0xc9, 0x00, 0x1e, 0x07,
+0x0e, 0x1f, 0xf6, 0xc2, 0x80, 0x75, 0x0b, 0x66,
+0xbe, 0x13, 0x01, 0x00, 0x00, 0xe8, 0xab, 0x00,
+0xb2, 0x80, 0x66, 0xbe, 0xbe, 0x01, 0x00, 0x00,
+0x66, 0xb9, 0x04, 0x00, 0x00, 0x00, 0xb0, 0x4c,
+0xe8, 0xa4, 0x00, 0x8a, 0x44, 0x00, 0x3c, 0x80,
+0x74, 0x18, 0x66, 0x83, 0xc6, 0x10, 0xe2, 0xee,
+0x66, 0xbe, 0x3c, 0x01, 0x00, 0x00, 0xe8, 0x82,
+0x00, 0xfa, 0xf4, 0xb0, 0x2e, 0xe8, 0x87, 0x00,
+0xeb, 0xf7, 0xb0, 0x42, 0xe8, 0x80, 0x00, 0x8b,
+0x14, 0x8b, 0x4c, 0x02, 0x66, 0xb8, 0x01, 0x02,
+0x00, 0x00, 0x31, 0xdb, 0xcd, 0x13, 0x73, 0x13,
+0x80, 0xfa, 0x80, 0x75, 0xaa, 0x66, 0xbe, 0x2f,
+0x01, 0x00, 0x00, 0xe8, 0x55, 0x00, 0xe8, 0x33,
+0x00, 0xeb, 0xce, 0xb0, 0x43, 0xe8, 0x57, 0x00,
+0x66, 0x31, 0xc0, 0x66, 0xbb, 0xfe, 0x01, 0x00,
+0x00, 0x67, 0x8b, 0x03, 0x66, 0x3d, 0x55, 0xaa,
+0x00, 0x00, 0x74, 0x0b, 0x66, 0xbe, 0x52, 0x01,
+0x00, 0x00, 0xe8, 0x2e, 0x00, 0xeb, 0xaa, 0xb0,
+0x47, 0xe8, 0x33, 0x00, 0x66, 0xea, 0x00, 0x7c,
+0x00, 0x00, 0x00, 0x00, 0x50, 0x53, 0x66, 0xbb,
+0x03, 0x01, 0x00, 0x00, 0x50, 0x88, 0xe0, 0x66,
+0x83, 0xe0, 0x0f, 0xd7, 0xe8, 0x18, 0x00, 0x58,
+0x66, 0x83, 0xe0, 0x0f, 0xd7, 0xe8, 0x0f, 0x00,
+0x5b, 0x58, 0xc3, 0x50, 0xfc, 0xac, 0x84, 0xc0,
+0x74, 0x0f, 0xe8, 0x02, 0x00, 0xeb, 0xf6, 0x50,
+0x53, 0xb4, 0x0e, 0x31, 0xdb, 0x43, 0xcd, 0x10,
+0x5b, 0x58, 0xc3, 0x30, 0x31, 0x32, 0x33, 0x34,
+0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43,
+0x44, 0x45, 0x46, 0x4d, 0x42, 0x52, 0x20, 0x6f,
+0x6e, 0x20, 0x66, 0x6c, 0x6f, 0x70, 0x70, 0x79,
+0x20, 0x6f, 0x72, 0x20, 0x6f, 0x6c, 0x64, 0x20,
+0x42, 0x49, 0x4f, 0x53, 0x0d, 0x0a, 0x00, 0x52,
+0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72, 0x6f,
+0x72, 0x0d, 0x0a, 0x00, 0x4e, 0x6f, 0x20, 0x61,
+0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x70, 0x61,
+0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x0d,
+0x0a, 0x00, 0x49, 0x6e, 0x76, 0x61, 0x6c, 0x69,
+0x64, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x74,
+0x75, 0x72, 0x65, 0x0d, 0x0a, 0x00, 0x90, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+0x01, 0x00, 0xa6, 0xff, 0xff, 0xff, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x55, 0xaa,
diff --git a/diskdev_cmds/fdisk.tproj/misc.c b/diskdev_cmds/fdisk.tproj/misc.c
new file mode 100644
index 0000000..a477001
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/misc.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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 <err.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include "misc.h"
+
+
+int
+ask_cmd(cmd_t *cmd)
+{
+ char lbuf[100], *cp, *buf;
+
+ /* Get input */
+ if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
+ errx(1, "eof");
+ lbuf[strlen(lbuf)-1] = '\0';
+
+ /* Parse input */
+ buf = lbuf;
+ buf = &buf[strspn(buf, " \t")];
+ cp = &buf[strcspn(buf, " \t")];
+ *cp++ = '\0';
+ strncpy(cmd->cmd, buf, 10);
+ buf = &cp[strspn(cp, " \t")];
+ strncpy(cmd->args, buf, 100);
+
+ return (0);
+}
+
+int
+ask_num(const char *str, int flags, unsigned int dflt, unsigned int low, unsigned int high, void (*help) __P((void)))
+{
+ char lbuf[100], *cp;
+ unsigned int num;
+
+ do {
+again:
+ num = dflt;
+ if (flags == ASK_HEX)
+ printf("%s [%X - %X]: [%X] ", str, low, high, num);
+ else
+ printf("%s [%u - %u]: [%u] ", str, low, high, num);
+ if (help)
+ printf("(? for help) ");
+
+ if (fgets(lbuf, sizeof lbuf, stdin) == NULL)
+ errx(1, "eof");
+ lbuf[strlen(lbuf)-1] = '\0';
+
+ if (help && lbuf[0] == '?') {
+ (*help)();
+ goto again;
+ }
+
+ /* Convert */
+ cp = lbuf;
+ num = strtoul(lbuf, &cp, ((flags==ASK_HEX)?16:10));
+
+ /* Make sure only number present */
+ if (cp == lbuf)
+ num = dflt;
+ if (*cp != '\0') {
+ printf("'%s' is not a valid number.\n", lbuf);
+ num = low - 1;
+ } else if (num < low || num > high) {
+ printf("'%u' is out of range.\n", num);
+ }
+ } while (num < low || num > high);
+
+ return (num);
+}
+
+int
+ask_yn(const char *str, int default_answer)
+{
+ int ch, first;
+
+ printf("%s [%c] ", str, default_answer ? 'y' : 'n');
+ fflush(stdout);
+
+ first = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+
+ if (ch == EOF || first == EOF)
+ errx(1, "eof");
+
+ if (first == '\n')
+ return default_answer;
+
+ return (first == 'y' || first == 'Y');
+}
+
+u_int16_t
+getshort(void *p)
+{
+ unsigned char *cp = p;
+
+ return (cp[0] | (cp[1] << 8));
+}
+
+void
+putshort(void *p, u_int16_t l)
+{
+ unsigned char *cp = p;
+
+ *cp++ = l;
+ *cp++ = l >> 8;
+}
+
+u_int32_t
+getlong(void *p)
+{
+ unsigned char *cp = p;
+
+ return (cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24));
+}
+
+void
+putlong(void *p, u_int32_t l)
+{
+ unsigned char *cp = p;
+
+ *cp++ = l;
+ *cp++ = l >> 8;
+ *cp++ = l >> 16;
+ *cp++ = l >> 24;
+}
diff --git a/diskdev_cmds/fdisk.tproj/misc.h b/diskdev_cmds/fdisk.tproj/misc.h
new file mode 100644
index 0000000..d3fa6ae
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/misc.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#ifndef _MISC_H
+#define _MISC_H
+
+#include <sys/types.h>
+#include "cmd.h"
+
+/* Constants */
+#define ASK_HEX 0x01
+#define ASK_DEC 0x02
+
+/* Prototypes */
+int ask_cmd __P((cmd_t *));
+int ask_num __P((const char *, int, unsigned int, unsigned int, unsigned int, void (*help) __P((void))));
+int ask_yn __P((const char *, int));
+u_int16_t getshort __P((void *));
+u_int32_t getlong __P((void *));
+void putshort __P((void *, u_int16_t));
+void putlong __P((void *, u_int32_t));
+
+#endif /* _MISC_H */
+
diff --git a/diskdev_cmds/fdisk.tproj/opendev.c b/diskdev_cmds/fdisk.tproj/opendev.c
new file mode 100644
index 0000000..538e4e6
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/opendev.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * Copyright (c) 2000, Todd C. Miller. All rights reserved.
+ * Copyright (c) 1996, Jason Downs. 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(S) ``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(S) 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 <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "util.h"
+/*
+ * This routine is a generic rewrite of the original code found in
+ * disklabel(8).
+ */
+
+int
+opendev(path, oflags, dflags, realpath)
+ char *path;
+ int oflags;
+ int dflags;
+ char **realpath;
+{
+ int fd;
+ char *slash, *prefix;
+ static char namebuf[PATH_MAX];
+
+ /* Initial state */
+ if (realpath)
+ *realpath = path;
+ fd = -1;
+ errno = ENOENT;
+
+ if (dflags & OPENDEV_BLCK)
+ prefix = ""; /* block device */
+ else
+ prefix = "r"; /* character device */
+
+ if ((slash = strchr(path, '/')))
+ fd = open(path, oflags);
+ else if (dflags & OPENDEV_PART) {
+ /*
+ * First try raw partition (for removable drives)
+ */
+ if (snprintf(namebuf, sizeof(namebuf), "%s%s%s%c",
+ _PATH_DEV, prefix, path, 'a' + getrawpartition())
+ < sizeof(namebuf)) {
+ fd = open(namebuf, oflags);
+ if (realpath)
+ *realpath = namebuf;
+ } else
+ errno = ENAMETOOLONG;
+ }
+ if (!slash && fd == -1 && errno == ENOENT) {
+ if (snprintf(namebuf, sizeof(namebuf), "%s%s%s",
+ _PATH_DEV, prefix, path) < sizeof(namebuf)) {
+ fd = open(namebuf, oflags);
+ if (realpath)
+ *realpath = namebuf;
+ } else
+ errno = ENAMETOOLONG;
+ }
+ return (fd);
+}
diff --git a/diskdev_cmds/fdisk.tproj/part.c b/diskdev_cmds/fdisk.tproj/part.c
new file mode 100644
index 0000000..7191442
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/part.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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 <err.h>
+#include <util.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <machine/param.h>
+#include "disk.h"
+#include "misc.h"
+#include "mbr.h"
+
+
+static const struct part_type {
+ int type;
+ char sname[14];
+ char *lname;
+} part_types[] = {
+ { 0x00, "unused ", "unused"},
+ { 0x01, "DOS FAT-12 ", "Primary DOS with 12 bit FAT"},
+ { 0x02, "XENIX / ", "XENIX / filesystem"},
+ { 0x03, "XENIX /usr ", "XENIX /usr filesystem"},
+ { 0x04, "DOS FAT-16 ", "Primary DOS with 16 bit FAT"},
+ { 0x05, "Extended DOS", "Extended DOS"},
+ { 0x06, "DOS > 32MB ", "Primary 'big' DOS (> 32MB)"},
+ { 0x07, "HPFS/QNX/AUX", "OS/2 HPFS, QNX-2 or Advanced UNIX"},
+ { 0x08, "AIX fs ", "AIX filesystem"},
+ { 0x09, "AIX/Coherent", "AIX boot partition or Coherent"},
+ { 0x0A, "OS/2 Bootmgr", "OS/2 Boot Manager or OPUS"},
+ { 0x0B, "Win95 FAT-32", "Primary Win95 w/ 32-bit FAT"},
+ { 0x0C, "Win95 FAT32L", "Primary Win95 w/ 32-bit FAT LBA-mapped"},
+ { 0x0E, "DOS FAT-16 ", "Primary DOS w/ 16-bit FAT, CHS-mapped"},
+ { 0x0F, "Extended LBA", "Extended DOS LBA-mapped"},
+ { 0x10, "OPUS ", "OPUS"},
+ { 0x11, "OS/2 hidden ", "OS/2 BM: hidden DOS 12-bit FAT"},
+ { 0x12, "Compaq Diag.", "Compaq Diagnostics"},
+ { 0x14, "OS/2 hidden ", "OS/2 BM: hidden DOS 16-bit FAT <32M or Novell DOS 7.0 bug"},
+ { 0x16, "OS/2 hidden ", "OS/2 BM: hidden DOS 16-bit FAT >=32M"},
+ { 0x17, "OS/2 hidden ", "OS/2 BM: hidden IFS"},
+ { 0x18, "AST swap ", "AST Windows swapfile"},
+ { 0x19, "Willowtech ", "Willowtech Photon coS"},
+ { 0x20, "Willowsoft ", "Willowsoft OFS1"},
+ { 0x24, "NEC DOS ", "NEC DOS"},
+ { 0x38, "Theos ", "Theos"},
+ { 0x39, "Plan 9 ", "Plan 9"},
+ { 0x40, "VENIX 286 ", "VENIX 286 or LynxOS"},
+ { 0x41, "Lin/Minux DR", "Linux/MINIX (sharing disk with DRDOS) or Personal RISC boot"},
+ { 0x42, "LinuxSwap DR", "SFS or Linux swap (sharing disk with DRDOS)"},
+ { 0x43, "Linux DR ", "Linux native (sharing disk with DRDOS)"},
+ { 0x4D, "QNX 4.2 Pri ", "QNX 4.2 Primary"},
+ { 0x4E, "QNX 4.2 Sec ", "QNX 4.2 Secondary"},
+ { 0x4F, "QNX 4.2 Ter ", "QNX 4.2 Tertiary"},
+ { 0x50, "DM ", "DM (disk manager)"},
+ { 0x51, "DM ", "DM6 Aux1 (or Novell)"},
+ { 0x52, "CP/M or SysV", "CP/M or Microport SysV/AT"},
+ { 0x53, "DM ", "DM6 Aux3"},
+ { 0x54, "Ontrack ", "Ontrack"},
+ { 0x55, "EZ-Drive ", "EZ-Drive (disk manager)"},
+ { 0x56, "Golden Bow ", "Golden Bow (disk manager)"},
+ { 0x5C, "Priam ", "Priam Edisk (disk manager)"},
+ { 0x61, "SpeedStor ", "SpeedStor"},
+ { 0x63, "ISC, HURD, *", "ISC, System V/386, GNU HURD or Mach"},
+ { 0x64, "Netware 2.xx", "Novell Netware 2.xx"},
+ { 0x65, "Netware 3.xx", "Novell Netware 3.xx"},
+ { 0x66, "Netware 386 ", "Novell 386 Netware"},
+ { 0x67, "Novell ", "Novell"},
+ { 0x68, "Novell ", "Novell"},
+ { 0x69, "Novell ", "Novell"},
+ { 0x70, "DiskSecure ", "DiskSecure Multi-Boot"},
+ { 0x75, "PCIX ", "PCIX"},
+ { 0x80, "Minix (old) ", "Minix 1.1 ... 1.4a"},
+ { 0x81, "Minix (new) ", "Minix 1.4b ... 1.5.10"},
+ { 0x82, "Linux swap ", "Linux swap"},
+ { 0x83, "Linux files*", "Linux filesystem"},
+ { 0x93, "Amoeba file*", "Amoeba filesystem"},
+ { 0x94, "Amoeba BBT ", "Amoeba bad block table"},
+ { 0x84, "OS/2 hidden ", "OS/2 hidden C: drive"},
+ { 0x85, "Linux ext. ", "Linux extended"},
+ { 0x86, "NT FAT VS ", "NT FAT volume set"},
+ { 0x87, "NTFS VS ", "NTFS volume set or HPFS mirrored"},
+ { 0x93, "Amoeba FS ", "Amoeba filesystem"},
+ { 0x94, "Amoeba BBT ", "Amoeba bad block table"},
+ { 0x99, "Mylex ", "Mylex EISA SCSI"},
+ { 0x9F, "BSDI ", "BSDI BSD/OS"},
+ { 0xA0, "NotebookSave", "Phoenix NoteBIOS save-to-disk"},
+ { 0xA5, "FreeBSD ", "FreeBSD"},
+ { 0xA6, "OpenBSD ", "OpenBSD"},
+ { 0xA7, "NEXTSTEP ", "NEXTSTEP"},
+ { 0xA8, "Darwin UFS ", "Darwin UFS partition"},
+ { 0xA9, "NetBSD ", "NetBSD"},
+ { 0xAB, "Darwin Boot ", "Darwin boot partition"},
+ { 0xAF, "HFS+ ", "Darwin HFS+ partition"},
+ { 0xB7, "BSDI filesy*", "BSDI BSD/386 filesystem"},
+ { 0xB8, "BSDI swap ", "BSDI BSD/386 swap"},
+ { 0xC0, "CTOS ", "CTOS"},
+ { 0xC1, "DRDOSs FAT12", "DRDOS/sec (FAT-12)"},
+ { 0xC4, "DRDOSs < 32M", "DRDOS/sec (FAT-16, < 32M)"},
+ { 0xC6, "DRDOSs >=32M", "DRDOS/sec (FAT-16, >= 32M)"},
+ { 0xC7, "HPFS Disbled", "Syrinx (Cyrnix?) or HPFS disabled"},
+ { 0xDB, "CPM/C.DOS/C*", "Concurrent CPM or C.DOS or CTOS"},
+ { 0xE1, "SpeedStor ", "DOS access or SpeedStor 12-bit FAT extended partition"},
+ { 0xE3, "SpeedStor ", "DOS R/O or SpeedStor or Storage Dimensions"},
+ { 0xE4, "SpeedStor ", "SpeedStor 16-bit FAT extended partition < 1024 cyl."},
+ { 0xEB, "BeOS/i386 ", "BeOS for Intel"},
+ { 0xF1, "SpeedStor ", "SpeedStor or Storage Dimensions"},
+ { 0xF2, "DOS 3.3+ Sec", "DOS 3.3+ Secondary"},
+ { 0xF4, "SpeedStor ", "SpeedStor >1024 cyl. or LANstep or IBM PS/2 IML"},
+ { 0xFF, "Xenix BBT ", "Xenix Bad Block Table"},
+};
+
+void
+PRT_printall()
+{
+ int i, idrows;
+
+ idrows = ((sizeof(part_types)/sizeof(struct part_type))+3)/4;
+
+ printf("Choose from the following Partition id values:\n");
+ for (i = 0; i < idrows; i++) {
+ printf("%02X %s %02X %s %02X %s"
+ , part_types[i ].type, part_types[i ].sname
+ , part_types[i+idrows ].type, part_types[i+idrows ].sname
+ , part_types[i+idrows*2].type, part_types[i+idrows*2].sname
+ );
+ if ((i+idrows*3) < (sizeof(part_types)/sizeof(struct part_type))) {
+ printf(" %02X %s\n"
+ , part_types[i+idrows*3].type, part_types[i+idrows*3].sname );
+ }
+ else
+ printf( "\n" );
+ }
+}
+
+const char *
+PRT_ascii_id(id)
+ int id;
+{
+ static char unknown[] = "<Unknown ID>";
+ int i;
+
+ for (i = 0; i < sizeof(part_types)/sizeof(struct part_type); i++) {
+ if (part_types[i].type == id)
+ return (part_types[i].sname);
+ }
+
+ return (unknown);
+}
+
+void
+PRT_parse(disk, prt, offset, reloff, partn, pn)
+ disk_t *disk;
+ void *prt;
+ off_t offset;
+ off_t reloff;
+ prt_t *partn;
+ int pn;
+{
+ unsigned char *p = prt;
+ off_t off;
+
+ partn->flag = *p++;
+ partn->shead = *p++;
+
+ partn->ssect = (*p) & 0x3F;
+ partn->scyl = ((*p << 2) & 0xFF00) | (*(p+1));
+ p += 2;
+
+ partn->id = *p++;
+ partn->ehead = *p++;
+ partn->esect = (*p) & 0x3F;
+ partn->ecyl = ((*p << 2) & 0xFF00) | (*(p+1));
+ p += 2;
+
+ if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL))
+ off = reloff;
+ else
+ off = offset;
+
+ partn->bs = getlong(p) + off;
+ partn->ns = getlong(p+4);
+
+
+ /* Zero out entry if not used */
+ if (partn->id == DOSPTYP_UNUSED ) {
+ memset(partn, 0, sizeof(*partn));
+ }
+}
+
+int
+PRT_check_chs(partn)
+ prt_t *partn;
+{
+ if ( (partn->shead > 255) ||
+ (partn->ssect >63) ||
+ (partn->scyl > 1023) ||
+ (partn->ehead >255) ||
+ (partn->esect >63) ||
+ (partn->ecyl > 1023) )
+ {
+ return 0;
+ }
+ return 1;
+}
+void
+PRT_make(partn, offset, reloff, prt)
+ prt_t *partn;
+ off_t offset;
+ off_t reloff;
+ void *prt;
+{
+ unsigned char *p = prt;
+ prt_t tmp;
+ off_t off;
+
+ tmp.shead = partn->shead;
+ tmp.ssect = partn->ssect;
+ tmp.scyl = (partn->scyl > 1023)? 1023: partn->scyl;
+ tmp.ehead = partn->ehead;
+ tmp.esect = partn->esect;
+ tmp.ecyl = (partn->ecyl > 1023)? 1023: partn->ecyl;
+ if (!PRT_check_chs(partn) && PRT_check_chs(&tmp)) {
+ partn->shead = tmp.shead;
+ partn->ssect = tmp.ssect;
+ partn->scyl = tmp.scyl;
+ partn->ehead = tmp.ehead;
+ partn->esect = tmp.esect;
+ partn->ecyl = tmp.ecyl;
+ printf("Cylinder values are modified to fit in CHS.\n");
+ }
+ if ((partn->id == DOSPTYP_EXTEND) || (partn->id == DOSPTYP_EXTENDL))
+ off = reloff;
+ else
+ off = offset;
+
+ if (PRT_check_chs(partn)) {
+ *p++ = partn->flag & 0xFF;
+
+ *p++ = partn->shead & 0xFF;
+ *p++ = (partn->ssect & 0x3F) | ((partn->scyl & 0x300) >> 2);
+ *p++ = partn->scyl & 0xFF;
+
+ *p++ = partn->id & 0xFF;
+
+ *p++ = partn->ehead & 0xFF;
+ *p++ = (partn->esect & 0x3F) | ((partn->ecyl & 0x300) >> 2);
+ *p++ = partn->ecyl & 0xFF;
+ } else {
+ /* should this really keep flag, id and set others to 0xff? */
+ *p++ = partn->flag & 0xFF;
+ *p++ = 0xFF;
+ *p++ = 0xFF;
+ *p++ = 0xFF;
+ *p++ = partn->id & 0xFF;
+ *p++ = 0xFF;
+ *p++ = 0xFF;
+ *p++ = 0xFF;
+ printf("Warning CHS values out of bounds only saving LBA values\n");
+ }
+
+ putlong(p, partn->bs - off);
+ putlong(p+4, partn->ns);
+}
+
+void
+PRT_print(num, partn)
+ int num;
+ prt_t *partn;
+{
+
+ if (partn == NULL) {
+ printf(" Starting Ending\n");
+ printf(" #: id cyl hd sec - cyl hd sec [ start - size]\n");
+ printf("------------------------------------------------------------------------\n");
+ } else {
+ printf("%c%1d: %.2X %4u %3u %3u - %4u %3u %3u [%10u - %10u] %s\n",
+ (partn->flag == 0x80)?'*':' ',
+ num + 1, partn->id,
+ partn->scyl, partn->shead, partn->ssect,
+ partn->ecyl, partn->ehead, partn->esect,
+ partn->bs, partn->ns,
+ PRT_ascii_id(partn->id));
+ }
+}
+
+void
+PRT_fix_BN(disk, part, pn)
+ disk_t *disk;
+ prt_t *part;
+ int pn;
+{
+ int spt, tpc, spc;
+ int start = 0;
+ int end = 0;
+
+ /* Zero out entry if not used */
+ if (part->id == DOSPTYP_UNUSED ) {
+ memset(part, 0, sizeof(*part));
+ return;
+ }
+
+ /* Disk metrics */
+ spt = disk->real->sectors;
+ tpc = disk->real->heads;
+ spc = spt * tpc;
+
+ start += part->scyl * spc;
+ start += part->shead * spt;
+ start += part->ssect - 1;
+
+ end += part->ecyl * spc;
+ end += part->ehead * spt;
+ end += part->esect - 1;
+
+ /* XXX - Should handle this... */
+ if (start > end)
+ warn("Start of partition #%d after end!", pn);
+
+ part->bs = start;
+ part->ns = (end - start) + 1;
+}
+
+void
+PRT_fix_CHS(disk, part, pn)
+ disk_t *disk;
+ prt_t *part;
+ int pn;
+{
+ int spt, tpc, spc;
+ int start;
+ int cyl, head, sect;
+
+ /* Zero out entry if not used */
+ if (part->id == DOSPTYP_UNUSED ) {
+ memset(part, 0, sizeof(*part));
+ return;
+ }
+
+ /* Disk metrics */
+ spt = disk->real->sectors;
+ tpc = disk->real->heads;
+ spc = spt * tpc;
+
+ start = part->bs;
+
+ if(start <= spt) {
+ /* Figure out "real" starting CHS values */
+ cyl = (start / spc); start -= (cyl * spc);
+ head = (start / spt); start -= (head * spt);
+ sect = (start + 1);
+ } else {
+ cyl = 1023;
+ head = 254;
+ sect = 63;
+ }
+
+ part->scyl = cyl;
+ part->shead = head;
+ part->ssect = sect;
+
+ /* use fake geometry to trigger LBA mode */
+
+ cyl = 1023;
+ head = 254;
+ sect = 63;
+
+ part->ecyl = cyl;
+ part->ehead = head;
+ part->esect = sect;
+}
+
diff --git a/diskdev_cmds/fdisk.tproj/part.h b/diskdev_cmds/fdisk.tproj/part.h
new file mode 100644
index 0000000..049cf2c
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/part.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#ifndef _PART_H
+#define _PART_H
+
+/* Partition type */
+typedef struct _prt_t {
+ int shead, scyl, ssect;
+ int ehead, ecyl, esect;
+ int bs;
+ int ns;
+ unsigned char flag;
+ unsigned char id;
+} prt_t;
+
+/* Prototypes */
+void PRT_printall __P((void));
+const char *PRT_ascii_id __P((int));
+void PRT_parse __P((disk_t *, void *, off_t, off_t, prt_t *, int));
+void PRT_make __P((prt_t *, off_t, off_t, void *));
+void PRT_print __P((int, prt_t *));
+
+/* This does CHS -> bs/ns */
+void PRT_fix_BN __P((disk_t *, prt_t *, int));
+
+/* This does bs/ns -> CHS */
+void PRT_fix_CHS __P((disk_t *, prt_t *, int));
+#endif /* _PART_H */
+
diff --git a/diskdev_cmds/fdisk.tproj/user.c b/diskdev_cmds/fdisk.tproj/user.c
new file mode 100644
index 0000000..d44434e
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/user.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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 <err.h>
+#include <util.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <machine/param.h>
+#include "user.h"
+#include "disk.h"
+#include "misc.h"
+#include "mbr.h"
+#include "cmd.h"
+
+
+/* Our command table */
+static cmd_table_t cmd_table[] = {
+ {"help", Xhelp, "Command help list"},
+ {"manual", Xmanual, "Show entire man page for fdisk"},
+ {"reinit", Xreinit, "Re-initialize loaded MBR (to defaults)"},
+ {"auto", Xauto, "Auto-partition the disk with a partition style"},
+ {"setpid", Xsetpid, "Set the identifier of a given table entry"},
+ {"disk", Xdisk, "Edit current drive stats"},
+ {"edit", Xedit, "Edit given table entry"},
+ {"erase", Xerase, "Erase current MBR"},
+ {"flag", Xflag, "Flag given table entry as bootable"},
+ {"update", Xupdate, "Update machine code in loaded MBR"},
+ {"select", Xselect, "Select extended partition table entry MBR"},
+ {"print", Xprint, "Print loaded MBR partition table"},
+ {"write", Xwrite, "Write loaded MBR to disk"},
+ {"exit", Xexit, "Exit edit of current MBR, without saving changes"},
+ {"quit", Xquit, "Quit edit of current MBR, saving current changes"},
+ {"abort", Xabort, "Abort program without saving current changes"},
+ {NULL, NULL, NULL}
+};
+
+
+int
+USER_write(disk, tt, preserve, force)
+ disk_t *disk;
+ mbr_t *tt; /* Template MBR to write */
+ int preserve; /* Preserve partition table and just write boot code */
+ int force; /* Don't ask any questions */
+{
+ int fd, yn;
+ char *msgp = "\nDo you wish to write new MBR?";
+ char *msgk = "\nDo you wish to write new MBR and partition table?";
+
+ /* Write sector 0 */
+ if (force) {
+ yn = 1;
+ } else {
+ printf("\a\n"
+ "\t-----------------------------------------------------\n"
+ "\t------ ATTENTION - UPDATING MASTER BOOT RECORD ------\n"
+ "\t-----------------------------------------------------\n");
+ if (preserve)
+ yn = ask_yn(msgp, 0);
+ else
+ yn = ask_yn(msgk, 0);
+ }
+
+ if (yn) {
+ if (preserve) {
+ int shared;
+ /* Only write the first one, if there's more than one in an extended partition chain */
+ /* Since we're updating boot code, we don't require exclusive access */
+ fd = DISK_openshared(disk->name, O_RDWR, &shared);
+ MBR_make(tt);
+ MBR_write(disk, fd, tt);
+ DISK_close(fd);
+ } else {
+ MBR_write_all(disk, tt);
+ }
+ } else {
+ printf("MBR is unchanged\n");
+ }
+
+ return (0);
+}
+
+
+int
+USER_modify(disk, tt, offset, reloff)
+ disk_t *disk;
+ mbr_t *tt;
+ off_t offset;
+ off_t reloff;
+{
+ static int editlevel;
+ mbr_t *mbr;
+ cmd_t cmd;
+ int i, st, fd;
+ int modified = 0;
+
+ /* One level deeper */
+ editlevel += 1;
+
+ /* Set up command table pointer */
+ cmd.table = cmd_table;
+
+ /* Read MBR & partition */
+ mbr = MBR_alloc(NULL);
+ fd = DISK_open(disk->name, O_RDONLY);
+ MBR_read(disk, fd, offset, mbr);
+ DISK_close(fd);
+
+ /* Parse the sucker */
+ MBR_parse(disk, offset, reloff, mbr);
+
+ if (mbr->signature != MBR_SIGNATURE) {
+ int yn = ask_yn("The signature for this MBR is invalid.\nWould you like to initialize the partition table?", 1);
+ if (yn) {
+ strlcpy(cmd.cmd, "erase", sizeof(cmd.cmd));
+ cmd.args[0] = '\0';
+ st = Xerase(&cmd, disk, mbr, tt, offset);
+ modified = 1;
+ }
+ }
+
+ printf("Enter 'help' for information\n");
+
+ /* Edit cycle */
+ do {
+again:
+ printf("fdisk:%c%d> ", (modified)?'*':' ', editlevel);
+ fflush(stdout);
+ ask_cmd(&cmd);
+
+ if (cmd.cmd[0] == '\0')
+ goto again;
+ for (i = 0; cmd_table[i].cmd != NULL; i++)
+ if (strstr(cmd_table[i].cmd, cmd.cmd)==cmd_table[i].cmd)
+ break;
+
+ /* Quick hack to put in '?' == 'help' */
+ if (!strcmp(cmd.cmd, "?"))
+ i = 0;
+
+ /* Check for valid command */
+ if (cmd_table[i].cmd == NULL) {
+ printf("Invalid command '%s'. Try 'help'.\n", cmd.cmd);
+ continue;
+ } else
+ strlcpy(cmd.cmd, cmd_table[i].cmd, sizeof(cmd.cmd));
+
+ /* Call function */
+ st = cmd_table[i].fcn(&cmd, disk, mbr, tt, offset);
+
+ /* Update status */
+ if (st == CMD_EXIT)
+ break;
+ if (st == CMD_SAVE)
+ break;
+ if (st == CMD_CLEAN)
+ modified = 0;
+ if (st == CMD_DIRTY)
+ modified = 1;
+ } while (1);
+
+ /* Write out MBR */
+ if (modified) {
+ if (st == CMD_SAVE) {
+ int shared = 0;
+ printf("Writing current MBR to disk.\n");
+ fd = DISK_openshared(disk->name, O_RDWR, &shared);
+ if(shared) {
+ if(!ask_yn("Device could not be accessed exclusively.\nA reboot will be needed for changes to take effect. OK?", 0)) {
+ close(fd);
+ goto again;
+ }
+ }
+
+ MBR_make(mbr);
+ MBR_write(disk, fd, mbr);
+ close(fd);
+ } else {
+ int yn = ask_yn("MBR was modified; really quit without saving?", 0);
+ if (yn) {
+ printf("Aborting changes to current MBR.\n");
+ } else {
+ goto again;
+ }
+ }
+ }
+
+ /* One level less */
+ editlevel -= 1;
+
+ MBR_free(mbr);
+
+ return (0);
+}
+
+int
+USER_print_disk(disk, do_dump)
+ disk_t *disk;
+ int do_dump;
+{
+ int fd, offset, firstoff;
+ mbr_t *mbr;
+
+ fd = DISK_open(disk->name, O_RDONLY);
+ offset = firstoff = 0;
+
+ if (!do_dump)
+ DISK_printmetrics(disk);
+
+ mbr = MBR_read_all(disk);
+ if (do_dump)
+ MBR_dump_all(mbr);
+ else
+ MBR_print_all(mbr);
+ MBR_free(mbr);
+
+ return (DISK_close(fd));
+}
+
+
+
diff --git a/diskdev_cmds/fdisk.tproj/user.h b/diskdev_cmds/fdisk.tproj/user.h
new file mode 100644
index 0000000..7234c98
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/user.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Tobias Weingartner
+ * 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 Tobias Weingartner.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#ifndef _USER_H
+#define _USER_H
+
+#include "disk.h"
+#include "mbr.h"
+
+/* Prototypes */
+int USER_write __P((disk_t *, mbr_t *, int, int));
+int USER_modify __P((disk_t *, mbr_t *, off_t, off_t));
+int USER_print_disk __P((disk_t *, int));
+#endif /* _USER_H */
+
diff --git a/diskdev_cmds/fdisk.tproj/util.h b/diskdev_cmds/fdisk.tproj/util.h
new file mode 100644
index 0000000..4e1600d
--- /dev/null
+++ b/diskdev_cmds/fdisk.tproj/util.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1996, Jason Downs. 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/*
+ * fparseln() specific operation flags.
+ */
+#define FPARSELN_UNESCESC 0x01
+#define FPARSELN_UNESCCONT 0x02
+#define FPARSELN_UNESCCOMM 0x04
+#define FPARSELN_UNESCREST 0x08
+#define FPARSELN_UNESCALL 0x0f
+
+/*
+ * opendev() specific operation flags.
+ */
+#define OPENDEV_PART 0x01 /* Try to open the raw partition. */
+#define OPENDEV_DRCT 0x02 /* Obsolete (now default behavior). */
+#define OPENDEV_BLCK 0x04 /* Open block, not character device. */
+
+/*
+ * uucplock(3) specific flags.
+ */
+#define UU_LOCK_INUSE (1)
+#define UU_LOCK_OK (0)
+#define UU_LOCK_OPEN_ERR (-1)
+#define UU_LOCK_READ_ERR (-2)
+#define UU_LOCK_CREAT_ERR (-3)
+#define UU_LOCK_WRITE_ERR (-4)
+#define UU_LOCK_LINK_ERR (-5)
+#define UU_LOCK_TRY_ERR (-6)
+#define UU_LOCK_OWNER_ERR (-7)
+
+/*
+ * stub struct definitions.
+ */
+struct __sFILE;
+struct login_cap;
+struct passwd;
+struct termios;
+struct winsize;
+
+__BEGIN_DECLS
+char *fparseln __P((struct __sFILE *, size_t *, size_t *, const char[3], int));
+int login_tty __P((int));
+int logout __P((const char *));
+void logwtmp __P((const char *, const char *, const char *));
+int opendev __P((char *, int, int, char **));
+int pidfile __P((const char *));
+void pw_setdir __P((const char *));
+char *pw_file __P((const char *));
+int pw_lock __P((int retries));
+int pw_mkdb __P((char *, int));
+int pw_abort __P((void));
+void pw_init __P((void));
+void pw_edit __P((int, const char *));
+void pw_prompt __P((void));
+void pw_copy __P((int, int, struct passwd *));
+void pw_getconf __P((char *, size_t, const char *, const char *));
+int pw_scan __P((char *, struct passwd *, int *));
+void pw_error __P((const char *, int, int));
+int openpty __P((int *, int *, char *, struct termios *,
+ struct winsize *));
+int opendisk __P((const char *path, int flags, char *buf, size_t buflen,
+ int iscooked));
+pid_t forkpty __P((int *, char *, struct termios *, struct winsize *));
+int getmaxpartitions __P((void));
+int getrawpartition __P((void));
+void login_fbtab __P((char *, uid_t, gid_t));
+int login_check_expire __P((struct __sFILE *, struct passwd *, char *, int));
+char *readlabelfs __P((char *, int));
+const char *uu_lockerr __P((int _uu_lockresult));
+int uu_lock __P((const char *_ttyname));
+int uu_lock_txfr __P((const char *_ttyname, pid_t _pid));
+int uu_unlock __P((const char *_ttyname));
+__END_DECLS
+
+#endif /* !_UTIL_H_ */
diff --git a/diskdev_cmds/fsck.tproj/fsck.8 b/diskdev_cmds/fsck.tproj/fsck.8
new file mode 100644
index 0000000..11cf28f
--- /dev/null
+++ b/diskdev_cmds/fsck.tproj/fsck.8
@@ -0,0 +1,176 @@
+.\" Copyright (c) 1980, 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fsck.8 8.4 (Berkeley) 5/9/95
+.\"
+.Dd May 18, 2010
+.Dt FSCK 8
+.Os BSD 4
+.Sh NAME
+.Nm fsck
+.Nd filesystem consistency check and interactive repair
+.Sh SYNOPSIS
+.Nm fsck
+.Fl p
+.Op Fl f
+.Nm fsck
+.Op Fl l Ar maxparallel
+.Op Fl q
+.Op Fl y
+.Op Fl n
+.Op Fl d
+.Sh DESCRIPTION
+The first form of
+.Nm fsck
+preens a standard set of filesystems or the specified filesystems.
+It is normally used in the script
+.Pa /etc/rc
+during automatic reboot.
+Here
+.Nm fsck
+reads the filesystem descriptor table (using
+.Xr getfsent 3 )
+to determine which filesystems to check.
+Only partitions that have ``rw,'' ``rq'' or ``ro'' as options,
+and that have non-zero pass number are checked.
+Filesystems with pass number 1 (normally just the root filesystem)
+are checked one at a time.
+When pass 1 completes, all remaining filesystems are checked,
+running one process per disk drive.
+The disk drive containing each filesystem is inferred from the shortest prefix
+of the device name that ends in one or more digits; the remaining characters
+are assumed to be the partition designator.
+In preening mode,
+filesystems that are marked clean are skipped.
+Filesystems are marked clean when they are unmounted,
+when they have been mounted read-only, or when
+.Nm fsck
+runs on them successfully.
+.Pp
+It should be noted that
+.Nm fsck
+is now essentially a wrapper that invokes other
+.Pa fsck_XXX
+utilities as needed. Currently,
+.Nm fsck
+can invoke
+.Pa fsck_hfs ,
+.Pa fsck_apfs ,
+.Pa fsck_msdos ,
+.Pa fsck_exfat ,
+and
+.Pa fsck_udf .
+If this underlying process that
+.Nm fsck
+invokes encounters serious inconsistencies or the filesystem type is not one
+of the above, it exits
+with an abnormal return status and an automatic reboot will then fail.
+For each corrected inconsistency one or more lines will be printed
+identifying the filesystem on which the correction will take place,
+and the nature of the correction.
+.Pp
+If sent a
+.Dv QUIT
+signal,
+.Nm fsck
+will finish the filesystem checks, then exit with an abnormal
+return status that causes an automatic reboot to fail.
+This is useful when you want to finish the filesystem checks during an
+automatic reboot,
+but do not want the machine to come up multiuser after the checks complete.
+.Pp
+Without the
+.Fl p
+option,
+.Nm fsck
+audits and interactively repairs inconsistent conditions for filesystems.
+It should be noted that some of the corrective actions which are not
+correctable under the
+.Fl p
+option will result in some loss of data.
+The amount and severity of data lost may be determined from the diagnostic
+output.
+If the operator does not have write permission on the filesystem
+.Nm fsck
+will default to a
+.Fl n
+action.
+.Pp
+The following flags are interpreted by
+.Nm fsck
+and passed along to the underlying tool that it spawns.
+.Bl -tag
+.It Fl f
+Force fsck to check `clean' filesystems when preening.
+.It Fl l
+Limit the number of parallel checks to the number specified in the following
+argument.
+By default, the limit is the number of disks, running one process per disk.
+If a smaller limit is given, the disks are checked round-robin, one filesystem
+at a time.
+.It Fl R
+Specify a particular passno number for which fsck is to check. You may only specify 1 or 2.
+Only those filesystems matching that particular passno entry (if using fstab) will be checked.
+For more information on the passno field, see
+.Xr fstab 5 .
+.It Fl p
+"Preen" mode, described above.
+.It Fl q
+Do a quick check to determine if the filesystem was unmounted cleanly.
+.It Fl y
+Assume a yes response to all questions asked by
+.Nm fsck ;
+this should be used with great caution as this is a free license
+to continue after essentially unlimited trouble has been encountered.
+.It Fl n
+Assume a no response to all questions asked by
+.Nm fsck
+except for
+.Ql CONTINUE? ,
+which is assumed to be affirmative;
+do not open the filesystem for writing.
+.El
+.Pp
+If no filesystems are given to
+.Nm fsck
+then a default list of filesystems is read using
+.Xr getfsent 3 .
+.Pp
+Because of inconsistencies between the block device and the buffer cache,
+the raw device should always be used.
+.Sh SEE ALSO
+.Xr fs 5 ,
+.Xr fsck_hfs 8 ,
+.Xr fsck_apfs 8 ,
+.Xr fsck_msdos 8 ,
+.Xr getfsent 3 ,
+.Xr fstab 5,
+.Xr reboot 8
diff --git a/diskdev_cmds/fsck.tproj/fsck.c b/diskdev_cmds/fsck.tproj/fsck.c
new file mode 100644
index 0000000..dc44e77
--- /dev/null
+++ b/diskdev_cmds/fsck.tproj/fsck.c
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (c) 2010-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1980, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <fstab.h>
+#include <err.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <signal.h>
+
+#include <TargetConditionals.h>
+
+#include "fsck.h"
+#include "../edt_fstab/edt_fstab.h"
+
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#include <os/bsd.h>
+#define AUTO_BOOT "auto-boot"
+#endif
+
+/* Local Static Functions */
+static int argtoi(int flag, char *req, char *str, int base);
+static void usage();
+static int startdiskcheck(disk_t* disk);
+
+
+/* Global Variables */
+int preen = 0; /* We're checking all fs'es in 'preen' mode */
+int returntosingle = 0; /* Return a non-zero status to prevent multi-user start up */
+int hotroot= 0; /* We're checking / (slash or root) */
+int fscks_running = 0; /* Number of currently running fs checks */
+int ndisks = 0; /* Total number of disks observed */
+int debug = 0; /* Output Debugging info */
+int force_fsck = 0; /* Force an fsck even if the underlying FS is clean */
+int maximum_running = 0; /* Maximum number of sub-processes we'll allow to be spawned */
+int quick_check = 0; /* Do a quick check. Quick check returns clean, dirty, or fail */
+int live_check = 0; /* Do a live check. This allows fsck to run on a partition which is mounted RW */
+int requested_passno = 0; /* only check the filesystems with the specified passno */
+/*
+ * The two following globals are mutually exclusive; you cannot assume "yes" and "no."
+ * The last one observed will be the one that is honored. e.g. fsck -fdnyny will result
+ * in assume_yes == 1, and assume_no == 0;
+ */
+int assume_no = 0; /* If set, assume a "no" response to repair requests */
+int assume_yes = 0; /* If set, assume a "yes" response to repair requests. */
+
+disk_t *disklist = NULL; /* Disk struct with embedded list to enum. all disks */
+part_t *badlist = NULL; /* List of partitions which may have had errors */
+
+static int argtoi(int flag, char *req, char *str, int base) {
+ char *cp;
+ int ret;
+
+ ret = (int)strtol(str, &cp, base);
+ if (cp == str || *cp)
+ errx(EEXIT, "-%c flag requires a %s", flag, req);
+ return (ret);
+}
+
+static void usage(void) {
+ fprintf(stderr, "fsck usage: fsck [-fdnypqL] [-l number]\n");
+}
+
+#if DEBUG
+void debug_args (void);
+void dump_part (part_t* part);
+void dump_disk (disk_t* disk);
+void dump_fsp (struct fstab *fsp);
+
+void debug_args (void) {
+ if (debug) {
+ printf("debug %d\n", debug);
+ }
+
+ if (force_fsck) {
+ printf("force_fsck %d\n", force_fsck);
+ }
+
+ if (assume_no) {
+ printf("assume_no: %d\n", assume_no);
+ }
+
+ if (assume_yes) {
+ printf("assume_yes: %d\n", assume_yes);
+ }
+
+ if (preen) {
+ printf("preen: %d\n", preen);
+ }
+
+ if (quick_check) {
+ printf("quick check %d\n", quick_check);
+ }
+
+ printf("maximum_running %d\n", maximum_running);
+}
+
+void dump_fsp (struct fstab *fsp) {
+ fprintf (stderr, "**********dumping fstab entry %p**********\n", fsp);
+ fprintf (stderr, "fstab->fs_spec: %s\n", fsp->fs_spec);
+ fprintf (stderr, "fstab->fs_file: %s\n", fsp->fs_file);
+ fprintf (stderr, "fstab->fs_vfstype: %s\n", fsp->fs_vfstype);
+ fprintf (stderr, "fstab->fs_mntops: %s\n", fsp->fs_mntops);
+ fprintf (stderr, "fstab->fs_type: %s\n", fsp->fs_type);
+ fprintf (stderr, "fstab->fs_freq: %d\n", fsp->fs_freq);
+ fprintf (stderr, "fstab->fs_passno: %d\n", fsp->fs_passno);
+ fprintf (stderr, "********** finished dumping fstab entry %p**********\n\n\n", fsp);
+
+}
+
+void dump_disk (disk_t* disk) {
+ part_t *part;
+ fprintf (stderr, "**********dumping disk entry %p**********\n", disk);
+ fprintf (stderr, "disk->name: %s\n", disk->name);
+ fprintf (stderr, "disk->next: %p\n", disk->next);
+ fprintf (stderr, "disk->part: %p\n", disk->part);
+ fprintf (stderr, "disk->pid: %d\n\n", disk->pid);
+
+ part = disk->part;
+ if (part) {
+ fprintf(stderr, "dumping partition entries now... \n");
+ }
+ while (part) {
+ dump_part (part);
+ part = part->next;
+ }
+ fprintf (stderr, "**********done dumping disk entry %p**********\n\n\n", disk);
+
+}
+
+void dump_part (part_t* part) {
+ fprintf (stderr, "**********dumping partition entry %p**********\n", part);
+ fprintf (stderr, "part->next: %p\n", part->next);
+ fprintf (stderr, "part->name: %s\n", part->name);
+ fprintf (stderr, "part->fsname: %s\n", part->fsname);
+ fprintf (stderr, "part->vfstype: %s\n\n", part->vfstype);
+ fprintf (stderr, "**********done dumping partition entry %p**********\n\n\n", part);
+}
+
+#endif
+
+
+
+int main (int argc, char** argv) {
+ /* for getopt */
+ extern char *optarg;
+ extern int optind;
+
+ int ch;
+ int ret;
+
+
+ sync();
+ while ((ch = getopt(argc, argv, "dfpR:qnNyYl:L")) != EOF) {
+ switch (ch) {
+ case 'd':
+ debug++;
+ break;
+
+ case 'l':
+ maximum_running = argtoi('l', "number", optarg, 10);
+ break;
+
+ case 'f':
+ force_fsck++;
+ break;
+
+ case 'R':
+ requested_passno = argtoi('R', "number", optarg, 10);
+ /* only allowed to specify 1 or 2 as argument here */
+ if ((requested_passno < ROOT_PASSNO) || (requested_passno > NONROOT_PASSNO)) {
+ usage();
+ exit(EINVAL);
+ }
+ break;
+
+ case 'N':
+ case 'n':
+ assume_no = 1;
+ assume_yes = 0;
+ break;
+
+ case 'p':
+ preen++;
+ break;
+
+ case 'q':
+ quick_check = 1;
+ break;
+
+ case 'Y':
+ case 'y':
+ assume_yes = 1;
+ assume_no = 0;
+ break;
+
+ case 'L':
+ live_check = 1;
+ break;
+
+ default:
+ errx(EEXIT, "%c option?", ch);
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Install our signal handlers */
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
+ (void)signal(SIGINT, catchsig);
+ }
+
+ if (preen) {
+ (void)signal(SIGQUIT, catchquit);
+ }
+
+ if (argc) {
+ /* We do not support any extra arguments at this time */
+ ret = EINVAL;
+ usage();
+ exit(ret);
+ }
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ char arg_val[16];
+ if (os_parse_boot_arg_string(AUTO_BOOT, arg_val, sizeof(arg_val))) {
+ if (strcmp(arg_val, "false")) {
+ fprintf(stderr, "warning: auto-boot is set to %s\n", arg_val);
+ }
+ }
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+
+ /*
+ * checkfstab does the bulk of work for fsck. It will scan through the
+ * fstab and iterate through the devices, as needed
+ */
+ ret = checkfstab();
+ /* Return a non-zero return status so that we'll stay in single-user */
+ if (returntosingle) {
+ exit(2);
+ }
+ /* Return the error value obtained from checking all filesystems in checkfstab */
+ exit(ret);
+
+}
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#include <APFS/APFSConstants.h> // EDT_OS_ENV_MAIN
+
+static int check_boot_container(void)
+{
+ int error = 0;
+ uint32_t os_env = 0;
+ const char *boot_container = get_boot_container(&os_env);
+ char *rcontainer = NULL;
+ char *container = NULL;
+
+ if ((os_env != EDT_OS_ENV_MAIN) &&
+ (os_env != EDT_OS_ENV_DIAGS)) {
+ fprintf(stdout, "fsck: not booting main or diagnostic OS. Skipping fsck on OS container\n");
+ return (0);
+ }
+
+ if (!boot_container) {
+ fprintf(stderr, "fsck: failed to get boot container\n");
+ return (EEXIT);
+ }
+
+ /* get a non-const copy */
+ container = strdup(boot_container);
+ if (!container) {
+ fprintf(stderr, "fsck: failed to copy boot container\n");
+ return (EEXIT);
+ }
+
+ /* Take the special device name, and do some cursory checks */
+ if ((rcontainer = blockcheck(container)) != 0) {
+ /* Construct a temporary disk_t for checkfilesys */
+ disk_t disk;
+ part_t part;
+
+ disk.name = NULL;
+ disk.next = NULL;
+ disk.part = &part;
+ disk.pid = 0;
+
+ part.next = NULL;
+ part.name = rcontainer;
+ part.vfstype = "apfs";
+
+ /* Run the filesystem check against the filesystem in question */
+ error = checkfilesys(&disk, 0);
+ }
+
+ free(container);
+
+ return (error);
+}
+#endif
+
+/*
+ * This is now the guts of fsck.
+ *
+ * This function will iterate over all of the elements in the fstab and run
+ * fsck-like binaries on all of the filesystems in question if able. The root filesystem
+ * is checked first, and then non-root filesystems are checked in order.
+ */
+int checkfstab(void) {
+ int running_status = 0;
+ int ret;
+
+ /*
+ * fsck boot-task (fsck -q):
+ * iOS - fsck_apfs -q will quick-check the container and volumes.
+ * So no need to obtain and check the fstab entries from EDT,
+ * just check the container.
+ * OSX - See comment in build_disklist(). In short - during early boot
+ * getfsent() will only return a synthetic entry for the root volume ("/")
+ * and additional fstab entries. An invalid entry will fail boot.
+ * To avoid this we require passing the "-R 1" flag to only check
+ * the root volume, which per fsck_apfs behaviour will quick-check the container and
+ * the root volume. We dont need to check the other volumes for boot
+ * (except perhaps for the VM and Data volumes but those are mounted earlier anyway).
+ */
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (quick_check && (requested_passno == 0)) {
+ return check_boot_container();
+ }
+#endif
+
+ ret = build_disklist ();
+ /*
+ * If we encountered any errors or if 'preen' was off,
+ * then we must have scanned everything. Either way, return.
+ */
+ if ((ret) || (preen == 0)) {
+ return ret;
+ }
+
+ if (preen) {
+ /* Otherwise, see if we need to do a cursory fsck against the FS. */
+ ret = do_diskchecks();
+ running_status |= ret;
+ }
+
+
+ if (running_status) {
+ part_t *part = NULL;
+
+ if (badlist == NULL) {
+ /* If there were no disk problems, then return the status */
+ return (running_status);
+ }
+ fprintf(stderr, "THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
+ badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
+ for (part = badlist; part; part = part->next) {
+ fprintf(stderr, "%s (%s)%s", part->name, part->fsname, part->next ? ", " : "\n");
+ }
+ return (running_status);
+ }
+
+ endfsent();
+ return (0);
+
+}
+
+/*
+ * This function builds up the list of disks that fsck will need to
+ * process and check.
+ *
+ * If we're not in 'preen' mode, then we'll go ahead and do the full
+ * check on all of them now.
+ *
+ * If we ARE in 'preen' mode, then we'll just check the root fs, and log
+ * all of the other ones that we encounter by scanning through the fstab
+ * for checking a bit later on. See notes below for checking '/' at boot.
+ */
+int build_disklist(void) {
+
+ struct fstab *fsp = NULL;
+ int passno = 0;
+ char *name;
+ int retval;
+ int running_status = 0;
+
+ int starting_passno = ROOT_PASSNO; //1
+ int ending_passno = NONROOT_PASSNO; //2
+
+ if (requested_passno) {
+ if (requested_passno == NONROOT_PASSNO) {
+ starting_passno = NONROOT_PASSNO;
+ }
+ else if (requested_passno == ROOT_PASSNO) {
+ ending_passno = ROOT_PASSNO;
+ }
+ }
+
+ /*
+ * We may need to iterate over the elements in the fstab in non-sequential order.
+ * Thus, we take up to two passes to check all fstab fsck-eligible FSes. The first
+ * pass should focus on the root filesystem, which can be inferred from the fsp->fs_passno
+ * field. The library code used to fill in the fsp structure will specify an
+ * fsp->fs_passno == 1 for the root. All other filesystems should get fsp->fs_passno == 2.
+ * (See fstab manpage for more info.)
+ *
+ * However, note that with the addition of the -R argument to this utility, we might "skip"
+ * one of these two passes. By passing in -R 1 or -R 2, the executor of this utility is
+ * specifying that they only want 'fsck' to run on either the root filesystem (passno == 1)
+ * or the non-root filesystems (passno == 2).
+ */
+#if DEBUG
+ fprintf(stderr, "fsck: iterating fstab - starting passno %d, ending passno %d\n",
+ starting_passno, ending_passno);
+#endif
+
+ for (passno = starting_passno; passno <= ending_passno; passno++) {
+ /* Open or reset the fstab entry */
+ if (setfsent() == 0) {
+ fprintf(stderr, "Can't get filesystem checklist: %s\n", strerror(errno));
+ return EEXIT;
+ }
+ /* Iterate through the fs entries returned from fstab */
+ while ((fsp = getfsent()) != 0) {
+ /*
+ * Determine if the filesystem is worth checking. Ignore it if it
+ * is not checkable.
+ */
+ if (fs_checkable(fsp) == 0) {
+ continue;
+ }
+ /*
+ * 'preen' mode is a holdover from the BSD days of long ago. It is semi-
+ * equivalent to a fsck -q, except that it skips filesystems who say that they
+ * are cleanly unmounted and fsck -q will actually call into fsck_hfs to do a
+ * journaling check.
+ *
+ * If preen is off, then we will wind up checking everything in order, so
+ * go ahead and just check this item now. However, if requested_passno is set, then
+ * the caller is asking us to explicitly only check partitions with a certain passno
+ * identifier.
+ *
+ * Otherwise, only work on the root filesystem in the first pass. We can
+ * tell that the fsp represents the root filesystem if fsp->fs_passno == 1.
+ *
+ * NOTE: On Mac OSX, LibInfo, part of Libsystem is in charge of vending us a valid
+ * fstab entry when we're running 'fsck -q' in early boot to ensure the validity of the
+ * boot disk. Since it's before the volume is mounted read-write, getfsent() will probe
+ * the Mach port for directory services. Since it's not up yet, it will determine the
+ * underlying /dev/disk entry for '/' and mechanically construct a fstab entry for / here.
+ * It correctly fills in the passno field below, which will allow us to fork/exec in order
+ * to call fsck_XXX as necessary.
+ *
+ * Once we're booted to multi-user, this block of code shouldn't ever really check anything
+ * unless it's a valid fstab entry because the synthesized fstab entries don't supply a passno
+ * field. Also, they would have to be valid /dev/disk fstab entries as opposed to
+ * UUID or LABEL ones.
+ *
+ * on iOS the above is not true; we rely on the EDT for all fstab entries.
+ */
+ if ((preen == 0) || (passno == 1 && fsp->fs_passno == 1)) {
+
+ /*
+ * If the caller specified a -R argument for us to examine only a certain
+ * range of passno fields AND that value does not match our current passno,
+ * then let the loop march on.
+ */
+ if (requested_passno && (fsp->fs_passno != requested_passno)) {
+ continue; //skip to the next fsent entry.
+ }
+
+ /* Take the special device name, and do some cursory checks. */
+ if ((name = blockcheck(fsp->fs_spec)) != 0) {
+#if TARGET_OS_IPHONE
+ if (!strcmp(name, RAMDISK_FS_SPEC)) {
+ fprintf(stdout, "Encountered ramdisk definition for location %s - will be created during mount.\n", fsp->fs_file);
+ continue;
+ }
+#endif // TARGET_OS_IPHONE
+
+ /* Construct a temporary disk_t for checkfilesys */
+ disk_t disk;
+ part_t part;
+
+ disk.name = NULL;
+ disk.next = NULL;
+ disk.part = &part;
+ disk.pid = 0;
+
+ part.next = NULL;
+ part.name = name;
+ part.vfstype = fsp->fs_vfstype;
+
+ /* Run the filesystem check against the filesystem in question */
+ if ((retval = checkfilesys(&disk, 0)) != 0) {
+ return (retval);
+ }
+ }
+ else {
+ fprintf(stderr, "BAD DISK NAME %s\n", fsp->fs_spec);
+ /*
+ * If we get here, then blockcheck failed (returned NULL).
+ * Presumably, we couldn't stat the disk device. In this case,
+ * just bail out because we couldn't even find all of the
+ * entries in the fstab.
+ */
+ return EEXIT;
+ }
+ }
+ /*
+ * If we get here, then preen must be ON and we're checking a
+ * non-root filesystem. So we must be on the 2nd pass, and
+ * the passno of the element returned from fstab will be > 1.
+ */
+ else if (passno == 2 && fsp->fs_passno > 1) {
+ /*
+ * If the block device checks tell us the name is bad, mark it in the status
+ * field and continue
+ */
+ if ((name = blockcheck(fsp->fs_spec)) == NULL) {
+ fprintf(stderr, "BAD DISK NAME %s\n", fsp->fs_spec);
+ running_status |= 8;
+ continue;
+ }
+ /*
+ * Since we haven't actually done anything yet, add this partition
+ * to the list of devices to check later on.
+ */
+ addpart(name, fsp->fs_file, fsp->fs_vfstype);
+ }
+ }
+ /* If we're not in preen mode, then we scanned everything already. Just bail out */
+ if (preen == 0) {
+ break;
+ }
+ }
+
+ return running_status;
+
+}
+
+/*
+ * This function only runs if we're operating in 'preen' mode. If so,
+ * then iterate over our list of non-root filesystems and fork/exec 'fsck_XXX'
+ * on them to actually do the checking. Spawn up to 'maximum_running' processes.
+ * If 'maximum_running' was not set, then default to the number of disk devices
+ * that we encounter.
+ */
+int do_diskchecks(void) {
+
+ int fsckno = 0;
+ int pid = 0;
+ int exitstatus = 0;
+ int retval = 0;
+ int running_status = 0;
+ disk_t *disk = NULL;
+ disk_t *nextdisk = NULL;
+
+ /*
+ * If we were not specified a maximum number of FS's to check at once,
+ * or the max exceeded the number of disks we observed, then clip it to
+ * the maximum number of disks.
+ */
+ if ((maximum_running == 0) || (maximum_running > ndisks)) {
+ maximum_running = ndisks;
+ }
+ nextdisk = disklist;
+
+ /* Start as many fscks as we will allow */
+ for (fsckno = 0; fsckno < maximum_running; ++fsckno) {
+ /*
+ * Run the disk check against the disk devices we have seen.
+ * 'fscks_running' is increased for each disk we actually visit.
+ * If we hit an error then sleep for 10 seconds and just try again.
+ */
+ while ((retval = startdiskcheck(nextdisk)) && fscks_running > 0) {
+ sleep(10);
+ }
+ if (retval) {
+ return (retval);
+ }
+ nextdisk = nextdisk->next;
+ }
+
+ /*
+ * Once we get limited by 'maximum_running' as to the maximum
+ * number of processes we can spawn at a time, wait until one of our
+ * child processes exits before spawning another one.
+ */
+ while ((pid = wait(&exitstatus)) != -1) {
+ for (disk = disklist; disk; disk = disk->next) {
+ if (disk->pid == pid) {
+ break;
+ }
+ }
+ if (disk == 0) {
+ /* Couldn't find a new disk to check */
+ printf("Unknown pid %d\n", pid);
+ continue;
+ }
+ /* Check the WIFEXITED macros */
+ if (WIFEXITED(exitstatus)) {
+ retval = WEXITSTATUS(exitstatus);
+ }
+ else {
+ retval = 0;
+ }
+ if (WIFSIGNALED(exitstatus)) {
+ printf("%s (%s): EXITED WITH SIGNAL %d\n",
+ disk->part->name, disk->part->fsname,
+ WTERMSIG(exitstatus));
+ retval = 8;
+ }
+ /* If it hit an error, OR in the value into our running total */
+ if (retval != 0) {
+ part_t *temp_part = badlist;
+
+ /* Add the bad partition to the bad partition list */
+ running_status |= retval;
+ badlist = disk->part;
+ disk->part = disk->part->next;
+ if (temp_part) {
+ badlist->next = temp_part;
+ }
+ } else {
+ /* Just move to the next partition */
+ part_t *temp_part = disk->part;
+ disk->part = disk->part->next;
+ destroy_part (temp_part);
+ }
+ /*
+ * Reset the pid to 0 since this partition was checked.
+ * Decrease the number of running processes. Decrease the
+ * number of disks if we finish one off.
+ */
+ disk->pid = 0;
+ fscks_running--;
+
+ if (disk->part == NULL) {
+ ndisks--;
+ }
+
+ if (nextdisk == NULL) {
+ if (disk->part) {
+ /* Start the next partition up */
+ while ((retval = startdiskcheck(disk)) && fscks_running > 0) {
+ sleep(10);
+ }
+ if (retval) {
+ return (retval);
+ }
+ }
+ }
+ else if (fscks_running < maximum_running && fscks_running < ndisks) {
+ /* If there's more room to go, then find the next valid disk */
+ for ( ;; ) {
+ if ((nextdisk = nextdisk->next) == NULL) {
+ nextdisk = disklist;
+ }
+ if (nextdisk->part != NULL && nextdisk->pid == 0) {
+ break;
+ }
+ }
+
+ while ((retval = startdiskcheck(nextdisk)) && fscks_running > 0) {
+ sleep(10);
+ }
+ if (retval) {
+ return (retval);
+ }
+ }
+ }
+ return running_status;
+
+}
+
+/*
+ * fork/exec in order to spawn a process that will eventually
+ * wait4() on the fsck_XXX process.
+ *
+ * Note: The number of forks/execs here is slightly complicated.
+ * We call fork twice, and exec once. The reason we need three total
+ * processes is that the first will continue on as the main line of execution.
+ * This first fork() will create the second process which calls checkfilesys().
+ * In checkfilesys() we will call fork again, followed by an exec. Observe that
+ * the second process created here will *immediately* call wait4 on the third
+ * process, fsck_XXX. This is so that we can track error dialogs and exit statuses
+ * and tie them to the specific instance of fsck_XXX that created them. Otherwise,
+ * if we just called fork a bunch of times and waited on the first one to finish,
+ * it would be difficult to tell which process exited first, and whether or not the
+ * exit status is meaningful.
+ *
+ * Also note that after we get our result from checkfilesys(), we immediately exit,
+ * so that this process doesn't linger and accidentally continue on.
+ */
+static
+int startdiskcheck(disk_t* disk) {
+
+ /*
+ * Split this process into the one that will go
+ * call fsck_XX and the one that won't
+ */
+ disk->pid = fork();
+ if (disk->pid < 0) {
+ perror("fork");
+ return (8);
+ }
+ if (disk->pid == 0) {
+ /*
+ * Call checkfilesys. Note the exit() call. Also note that
+ * we pass 1 to checkfilesys since we are a child process
+ */
+ exit(checkfilesys(disk, 1));
+ }
+ else {
+ fscks_running++;
+ }
+ return (0);
+}
+
+
+
+
+/*
+ * Call fork/exec in order to spawn instance of fsck_XXX for the filesystem
+ * of the specified vfstype. This will actually spawn the process that does the
+ * checking of the filesystem in question.
+ */
+int checkfilesys(disk_t *disk, int child) {
+#define ARGC_MAX 4 /* cmd-name, options, device, NULL-termination */
+ part_t *part = disk->part;
+ const char *argv[ARGC_MAX];
+ int argc;
+ int error = 0;
+ struct stat buf;
+ pid_t pid;
+ int status = 0;
+ char options[] = "-pdfnyql"; /* constant strings are not on the stack */
+ char progname[NAME_MAX];
+ char execname[MAXPATHLEN + 1];
+ char* filesys = part->name;
+ char* vfstype = part->vfstype;
+
+ if (preen && child) {
+ (void)signal(SIGQUIT, ignore_single_quit);
+ }
+
+#if TARGET_OS_IPHONE
+ if (!strcmp(filesys, RAMDISK_FS_SPEC)) {
+ fprintf(stdout, "No need to check filesys for ramdisk, does not exist yet.\n");
+ return 0;
+ }
+#endif // TARGET_OS_IPHONE
+
+ /*
+ * If there was a vfstype specified, then we can go ahead and fork/exec
+ * the child fsck process if the fsck_XXX binary exists.
+ */
+ if (vfstype) {
+ int exitstatus;
+
+ /*
+ * Not all options are currently supported by all 5 fsck_* binaries.
+ * Specifically:
+ * udf does not support debug, quick or live
+ * msdos does not support quick or live
+ * exfat does not support live
+ * apfs does not support preen
+ * When the System invokes fsck it is during boot (one of launchd's boot-tasks).
+ * This task is run with the quick and live options.
+ * On iOS we can assume all partitions are APFS or HFS.
+ * On OSX we run this only against the System volume which will always be HFS or APFS
+ */
+ bzero(options, sizeof(options));
+ snprintf(options, sizeof(options), "-%s%s%s%s%s%s%s",
+ (preen) ? "p" : "",
+ (debug) ? "d" : "",
+ (force_fsck) ? "f" : "",
+ (assume_no) ? "n" : "",
+ (assume_yes) ? "y" : "",
+ (quick_check) ? "q" : "",
+ (live_check) ? "l" : ""
+ );
+
+ argc = 0;
+ snprintf(progname, sizeof(progname), "fsck_%s", vfstype);
+ argv[argc++] = progname;
+ if (strlen(options) > 1) {
+ argv[argc++] = options;
+ }
+ argv[argc++] = filesys;
+ argv[argc] = NULL;
+
+ /* Create the string to the fsck binary */
+ (void)snprintf(execname, sizeof(execname), "%s/fsck_%s", _PATH_SBIN, vfstype);
+
+ /* Check that the binary exists */
+ error = stat (execname, &buf);
+ if (error != 0) {
+ fprintf(stderr, "Filesystem cannot be checked \n");
+ return EEXIT;
+ }
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ /* The fork failed. */
+ fprintf(stderr, "fork failed for %s \n", filesys);
+ if (preen) {
+ fprintf(stderr, "\n%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
+ filesys);
+ exit(EEXIT);
+ }
+
+ status = EEXIT;
+ break;
+
+ case 0:
+ /* The child */
+ if (preen) {
+ (void)signal(SIGQUIT, ignore_single_quit);
+ }
+#if DEBUG
+ printf("exec: %s", execname);
+ for (int i = 1; i < argc; i++) {
+ printf(" %s", argv[i]);
+ }
+ printf("\n");
+ exit(0);
+#endif
+ execv(execname, (char * const *)argv);
+ fprintf(stderr, "error attempting to exec %s\n", execname);
+ _exit(8);
+ break;
+
+ default:
+ /* The parent; child is process "pid" */
+ waitpid(pid, &exitstatus, 0);
+ if (WIFEXITED(exitstatus)) {
+ status = WEXITSTATUS(exitstatus);
+ }
+ else {
+ status = 0;
+ }
+ if (WIFSIGNALED(exitstatus)) {
+ printf("%s (%s) EXITED WITH SIGNAL %d\n", filesys, vfstype, WTERMSIG(exitstatus));
+ status = 8;
+ }
+ break;
+ }
+
+ return status;
+ }
+ else {
+ fprintf(stderr, "Filesystem cannot be checked \n");
+ return EEXIT;
+ }
+}
+
+/*
+ * When preening, allow a single quit to signal
+ * a special exit after filesystem checks complete
+ * so that reboot sequence may be interrupted.
+ */
+void catchquit(int sig) {
+ extern int returntosingle;
+
+ printf("returning to single-user after filesystem check\n");
+ returntosingle = 1;
+ (void)signal(SIGQUIT, SIG_DFL);
+}
+
+/* Quit if we catch a signal here. Emit 12 */
+void catchsig(int sig) {
+ exit (12);
+}
+
+
+/*
+ * Determine whether a filesystem should be checked.
+ *
+ * Zero indicates that no check should be performed.
+ */
+int fs_checkable(struct fstab *fsp) {
+
+ /*
+ * APFS, HFS, MSDOS, exfat, and UDF are allowed for now.
+ */
+ if (strcmp(fsp->fs_vfstype, "apfs") &&
+ strcmp(fsp->fs_vfstype, "hfs") &&
+ strcmp(fsp->fs_vfstype, "msdos") &&
+ strcmp(fsp->fs_vfstype, "exfat") &&
+ strcmp(fsp->fs_vfstype, "udf")) {
+ return 0;
+ }
+
+ /* if not RW and not RO (SW or XX?), ignore it */
+ if ((strcmp(fsp->fs_type, FSTAB_RW) && strcmp(fsp->fs_type, FSTAB_RO)) ||
+ fsp->fs_passno == 0) {
+ return 0;
+ }
+
+#define DISKARB_LABEL "LABEL="
+#define DISKARB_UUID "UUID="
+ /* If LABEL or UUID specified, ignore it */
+ if ((strncmp(fsp->fs_spec, DISKARB_LABEL, strlen(DISKARB_LABEL)) == 0)
+ || (strncmp(fsp->fs_spec, DISKARB_UUID, strlen(DISKARB_UUID)) == 0)) {
+ return 0;
+ }
+
+ /* Otherwise, it looks fine. Go ahead and check! */
+ return 1;
+}
+
+/*
+ * Do some cursory checks on the pathname provided to ensure that it's really a block
+ * device. If it is, then generate the raw device name and vend it out.
+ */
+char *blockcheck (char *origname) {
+ struct stat stslash;
+ struct stat stblock;
+ struct stat stchar;
+
+ char *newname;
+ char *raw;
+ int retried = 0;
+ int error = 0;
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ /* Variables for setting up the kqueue listener*/
+#define TIMEOUT_SEC 30l
+ struct kevent kev;
+ struct kevent results;
+ struct timespec ts;
+ int slashdev_fd;
+ int kq = -1;
+ int ct;
+ time_t end;
+ time_t now;
+#endif // (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+
+ hotroot = 0;
+ /* Try to get device info for '/' */
+ if (stat("/", &stslash) < 0) {
+ perror("/");
+ /* If we can't get any info on root, then bail out */
+ printf("Can't stat root\n");
+ return (origname);
+ }
+ newname = origname;
+#if TARGET_OS_IPHONE
+ if (!strcmp(newname, RAMDISK_FS_SPEC)) {
+ // Keyword ramdisk
+ fprintf(stdout, "Encountered ramdisk definition. Do not stat\n");
+ return (newname);
+ }
+#endif // TARGET_OS_IPHONE
+
+retry:
+ /* Poke the block device argument */
+ error = stat(newname, &stblock);
+ if (error < 0) {
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ /*
+ * If the device node is not present, set up
+ * a kqueue and wait for up to 30 seconds for it to be
+ * published.
+ */
+ kq = kqueue();
+ if (kq < 0) {
+ printf("kqueue: could not create kqueue: %d\n", errno);
+ printf("Can't stat %s\n", newname);
+ return NULL;
+ }
+ slashdev_fd = open(_PATH_DEV, O_RDONLY);
+
+ EV_SET(&kev, slashdev_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, NOTE_WRITE, 0, NULL);
+ ct = kevent(kq, &kev, 1, NULL, 0, NULL);
+ if (ct != 0) {
+ printf("kevent() failed to register: %d\n", errno);
+ printf("Can't stat %s\n", newname);
+ /* If we can't register the kqueue, bail out */
+ close (kq);
+ kq = -1;
+ return NULL;
+ }
+ now = time(NULL);
+ end = now + TIMEOUT_SEC;
+
+ ts.tv_nsec = 0;
+ while ((now = time(NULL)) < end) {
+ ts.tv_sec = end - now;
+ ct = kevent(kq, NULL, 0, &results, 1, &ts);
+ if (results.flags & EV_ERROR) {
+ /* If we register any errors, bail out */
+ printf("kevent: registered errors.\n");
+ error = -1;
+ close (kq);
+ kq = -1;
+ break;
+ }
+ error = stat (newname, &stblock);
+ if (error == 0) {
+ /* found the item. continue on */
+ if (kq >= 0) {
+ close (kq);
+ }
+ break;
+ }
+ }
+ if (error != 0) {
+ /* Time out. bail out */
+ if (kq >= 0) {
+ close(kq);
+ }
+ printf("fsck timed out. Can't stat %s\n", newname);
+ return NULL;
+ }
+
+#else //(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ perror(newname);
+ printf("Can't stat %s\n", newname);
+ return (NULL);
+#endif // (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ }
+
+ if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
+ /*
+ * If the block device we're checking is the same as '/' then
+ * update hotroot global for debugging.
+ */
+ if (stslash.st_dev == stblock.st_rdev) {
+ hotroot++;
+ }
+ raw = rawname(newname);
+ if (stat(raw, &stchar) < 0) {
+ perror(raw);
+ printf("Can't stat %s\n", raw);
+ return (origname);
+ }
+ if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
+ return (raw);
+ } else {
+ printf("%s is not a character device\n", raw);
+ return (origname);
+ }
+ } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
+ newname = unrawname(newname);
+ retried++;
+ goto retry;
+ }
+ /*
+ * Not a block or character device, return NULL and
+ * let the user decide what to do.
+ */
+ return (NULL);
+}
+
+
+/*
+ * Generate a raw disk device pathname from a normal one.
+ *
+ * For input /dev/disk1s2, generate /dev/rdisk1s2
+ */
+char *rawname(char *name) {
+ static char rawbuf[32];
+ char *dp;
+
+ /*
+ * Search for the last '/' in the pathname.
+ * If it's not there, then bail out
+ */
+ if ((dp = strrchr(name, '/')) == 0) {
+ return (0);
+ }
+ /*
+ * Insert a NULL in the place of the final '/' so that we can
+ * copy everything BEFORE that last '/' into a separate buffer.
+ */
+ *dp = 0;
+ (void)strlcpy(rawbuf, name, sizeof(rawbuf));
+ *dp = '/';
+ /* Now add an /r to our buffer, then copy everything after the final / */
+ (void)strlcat(rawbuf, "/r", sizeof(rawbuf));
+ (void)strlcat(rawbuf, &dp[1], sizeof(rawbuf));
+ return (rawbuf);
+}
+
+/*
+ * Generate a regular disk device name from a raw one.
+ *
+ * For input /dev/rdisk1s2, generate /dev/disk1s2
+ */
+char *unrawname(char *name) {
+ char *dp;
+ struct stat stb;
+ size_t length;
+
+ /* Find the last '/' in the pathname */
+ if ((dp = strrchr(name, '/')) == 0) {
+ return (name);
+ }
+
+ /* Stat the disk device argument */
+ if (stat(name, &stb) < 0) {
+ return (name);
+ }
+
+ /* If it's not a character device, error out */
+ if ((stb.st_mode & S_IFMT) != S_IFCHR) {
+ return (name);
+ }
+
+ /* If it's not a real raw name, then error out */
+ if (dp[1] != 'r') {
+ return (name);
+ }
+ length = strlen(&dp[2]);
+ length++; /* to account for trailing NULL */
+
+ memmove(&dp[1], &dp[2], length);
+ return (name);
+}
+
+/*
+ * Given a pathname to a disk device, generate the relevant disk_t for that
+ * disk device. It is assumed that this function will be called for each item in the
+ * fstab that needs to get checked.
+ */
+disk_t *finddisk (char *pathname) {
+ disk_t *disk;
+ disk_t **dkp;
+ char *tmp;
+ size_t len;
+
+ /*
+ * Find the disk name. It is assumed that the disk name ends with the
+ * first run of digit(s) in the last component of the path.
+ */
+ tmp = strrchr(pathname, '/'); /* Find the last component of the path */
+ if (tmp == NULL) {
+ tmp = pathname;
+ }
+ else {
+ tmp++;
+ }
+ for (; *tmp && !isdigit(*tmp); tmp++) { /* Skip non-digits */
+ continue;
+ }
+
+ for (; *tmp && isdigit(*tmp); tmp++){ /* Skip to end of consecutive digits */
+ continue;
+ }
+
+ len = tmp - pathname;
+ if (len == 0) {
+ len = strlen(pathname);
+ }
+
+ /* Iterate through all known disks to see if this item was already seen before */
+ for (disk = disklist, dkp = &disklist; disk; dkp = &disk->next, disk = disk->next) {
+ if ((strncmp(disk->name, pathname, len) == 0) &&
+ (disk->name[len] == 0)) {
+ return (disk);
+ }
+ }
+ /* If not, then allocate a new structure and add it to the end of the list */
+ if ((*dkp = (disk_t*)malloc(sizeof(disk_t))) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ /* Make 'disk' point to the newly allocated structure */
+ disk = *dkp;
+ if ((disk->name = malloc(len + 1)) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ /* copy the name into place */
+ (void)strncpy(disk->name, pathname, len);
+ disk->name[len] = '\0';
+ /* Initialize 'part' and 'next' to NULL for now */
+ disk->part = NULL;
+ disk->next = NULL;
+ disk->pid = 0;
+ /* Increase total number of disks observed */
+ ndisks++;
+
+ /* Bubble out either the newly created disk_t or the one we found */
+ return (disk);
+}
+
+
+/*
+ * Add this partition to the list of devices to check.
+ */
+void addpart(char *name, char *fsname, char *vfstype) {
+ disk_t *disk;
+ part_t *part;
+ part_t **ppt;
+
+ /* Find the disk_t that corresponds to our element */
+ disk = finddisk(name);
+ ppt = &(disk->part);
+
+ /*
+ * Now iterate through all of the partitions of that disk.
+ * If we see our partition name already in there, then it means the entry
+ * was in the fstab more than once, which is bad.
+ */
+ for (part = disk->part; part; ppt = &part->next, part = part->next) {
+ if (strcmp(part->name, name) == 0) {
+ printf("%s in fstab more than once!\n", name);
+ return;
+ }
+ }
+
+ /* Hopefully we get here. Allocate a new partition structure for the disk */
+ if ((*ppt = (part_t*)malloc(sizeof(part_t))) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ part = *ppt;
+ if ((part->name = strdup(name)) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+
+ /* Add the name & vfs info to the partition struct */
+ if ((part->fsname = strdup(fsname)) == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+ part->next = NULL;
+ part->vfstype = strdup(vfstype);
+ if (part->vfstype == NULL) {
+ fprintf(stderr, "out of memory");
+ exit (8);
+ }
+}
+
+/*
+ * Free the partition and its fields.
+ */
+void destroy_part (part_t *part) {
+ if (part->name) {
+ free (part->name);
+ }
+
+ if (part->fsname) {
+ free (part->fsname);
+ }
+
+ if (part->vfstype) {
+ free (part->vfstype);
+ }
+
+ free (part);
+}
+
+
+/*
+ * Ignore a single quit signal; wait and flush just in case.
+ * Used by child processes in preen mode.
+ */
+void
+ignore_single_quit(int sig) {
+
+ sleep(1);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_DFL);
+}
+
+
+
diff --git a/diskdev_cmds/fsck.tproj/fsck.h b/diskdev_cmds/fsck.tproj/fsck.h
new file mode 100644
index 0000000..d602029
--- /dev/null
+++ b/diskdev_cmds/fsck.tproj/fsck.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1980, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __FSCK_H__
+#define __FSCK_H__
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fstab.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <string.h>
+
+/* Typedef Structures */
+
+/*
+ * Describes the current partition and
+ * contains a link to the next one if avail.
+ */
+typedef struct part {
+ struct part *next; /* forward link of partitions on disk */
+ char *name; /* device name */
+ char *fsname; /* mounted filesystem name */
+ char *vfstype; /* file system type (eg., "hfs" or "msdos") */
+} part_t;
+
+/*
+ * Disk structure that describes the device and contains the list
+ * of partitions available to the disk.
+ */
+typedef struct disk {
+ char *name; /* disk base name */
+ struct disk *next; /* forward link for list of disks */
+ struct part *part; /* head of list of partitions on disk */
+ int pid; /* If != 0, pid of proc working on */
+} disk_t;
+
+
+#define EEXIT 8 /* Standard Error exit code for fsck */
+#define _PATH_SBIN "/sbin" /* Path prefix used for fork/exec */
+
+#define ROOT_PASSNO 1 /* passno field for root FSes */
+#define NONROOT_PASSNO 2 /* passno field for non-root FSes */
+
+
+/* Function prototypes */
+int checkfstab(void);
+void catchquit(int sig);
+void catchsig(int sig);
+int fs_checkable (struct fstab *fsp);
+char *blockcheck(char *origname);
+char *rawname(char *name);
+char *unrawname(char *name);
+void addpart(char *name, char *fsname, char *vfstype);
+void destroy_part (part_t* part);
+disk_t *finddisk (char *name);
+int checkfilesys(disk_t *disk, int child);
+int check_fs(char *vfstype, char *filesys);
+void ignore_single_quit (int sig);
+int build_disklist(void);
+int do_diskchecks(void);
+
+
+#endif
+
+
+
diff --git a/diskdev_cmds/fstyp.tproj/fstyp.8 b/diskdev_cmds/fstyp.tproj/fstyp.8
new file mode 100644
index 0000000..fdc6ca2
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp.8
@@ -0,0 +1,41 @@
+.\"
+.\" (c) 2005 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd August 15, 2005
+.Dt FSTYP 8
+.Os
+.Sh NAME
+.Nm fstyp
+.Nd identify a file system
+.Sh SYNOPSIS
+.Nm
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility attempts to determine what sort of volume is present on the given
+device.
+It operates by iterating over directories that are typically part of the path,
+searching for files matching the pattern fstyp_* and running them.
+If it finds a match, it will print out the file system type name and exit with
+a return value of 1.
+If it does not find a match, it will not print out anything, and the return
+value will be 0.
diff --git a/diskdev_cmds/fstyp.tproj/fstyp.c b/diskdev_cmds/fstyp.tproj/fstyp.c
new file mode 100644
index 0000000..840c4aa
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#define FSTYP_PREFIX "fstyp_"
+#define MAX_PATH_LEN 80
+#define MAX_CMD_LEN (MAX_PATH_LEN * 2)
+#define NULL_REDIRECTION ">/dev/null 2>&1"
+
+void usage(void);
+int select_fstyp(const struct dirent * dp);
+int test(const char *dir, const struct dirent * dp, const char *dev);
+void dealloc(struct dirent ** dpp, int numElems);
+
+char *progname;
+
+/*
+ * The fstyp command iterates through the binary directories to look for
+ * commands of the form fstyp_* and runs them, trying to find one that
+ * matches the given device. Once one of the returns success, fstyp
+ * prints out that file system type name and terminates. 1 is returned
+ * if any match is found, and 0 is returned if no match is found.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ /* NULL-terminated list of directories to search for fstyp_* commands */
+ const char *DIRS[] = { "/bin/",
+ "/sbin/",
+ "/usr/bin/",
+ "/usr/sbin/",
+ "/usr/local/bin/",
+ "/usr/local/sbin/",
+ NULL};
+
+ int numMatches, i, j, found;
+ struct stat sb;
+ struct dirent **dpp;
+
+ numMatches = 0;
+ i = 0;
+ j = 0;
+ found = 0;
+
+ if ((progname = strrchr(*argv, '/')))
+ ++progname;
+ else
+ progname = *argv;
+
+ if (argc != 2) {
+ usage();
+ return EX_USAGE;
+ }
+ if (0 == stat(argv[1], &sb)) {
+ for (i = 0; (!found && (NULL != DIRS[i])); i++) {
+ /*
+ * scan DIRS[i] for files that start with
+ * "fstyp_"
+ */
+ numMatches = scandir(DIRS[i], &dpp, select_fstyp, NULL);
+
+ if (numMatches >= 0) {
+ for (j = 0; (!found && (j < numMatches)); j++) {
+ if (test(DIRS[i], dpp[j], argv[1]) == 1) {
+ puts(dpp[j]->d_name + 6);
+
+ found = 1;
+ }
+ }
+
+ dealloc(dpp, numMatches);
+ dpp = NULL;
+ }
+ }
+ }
+ return found;
+}
+
+int
+select_fstyp(const struct dirent * dp)
+{
+ return ((dp != NULL) &&
+ ((dp->d_type == DT_REG) || (dp->d_type == DT_LNK)) &&
+ (dp->d_namlen > strlen(FSTYP_PREFIX)) &&
+ (!strncmp(FSTYP_PREFIX, dp->d_name, strlen(FSTYP_PREFIX))));
+}
+
+/* return dp if successful, else return NULL */
+int
+test(const char *dir, const struct dirent * dp, const char *dev)
+{
+ char cmd[MAX_CMD_LEN + 1] = {0};
+ int status;
+ FILE *fileptr;
+
+ status = 0;
+
+ /* + 1 for white space */
+ if ((strlen(dir) + dp->d_namlen + 1 + strlen(dev) +
+ strlen(NULL_REDIRECTION)) > MAX_CMD_LEN) {
+ return 0;
+ }
+ snprintf(cmd, sizeof(cmd), "%s%s %s", dir, dp->d_name, dev);
+
+ if ((fileptr = popen(cmd, "r")) != NULL) {
+ status = pclose(fileptr);
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 1) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+void
+dealloc(struct dirent ** dpp, int numElems)
+{
+ int i;
+
+ for (i = 0; i < numElems; i++) {
+ free(dpp[i]);
+ dpp[i] = NULL;
+ }
+
+ free(dpp);
+
+ return;
+}
+
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s device\n", progname);
+ return;
+}
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_msdos.8 b/diskdev_cmds/fstyp.tproj/fstyp_msdos.8
new file mode 100644
index 0000000..940bc78
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_msdos.8
@@ -0,0 +1,41 @@
+.\"
+.\" (c) 2005 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd August 15, 2005
+.Dt FSTYP_MSDOS 8
+.Os
+.Sh NAME
+.Nm fstyp_msdos
+.Nd check for an MSDOS FAT volume
+.Sh SYNOPSIS
+.Nm
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility is not intended to be run directly, but rather called by
+.Xr fstyp 8
+while it is trying to determine which file system type is present on the
+given device.
+It returns 1 if it thinks the device contains an MSDOS FAT volume, and 0
+otherwise.
+.Sh SEE ALSO
+.Xr fstyp 8
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_msdos.c b/diskdev_cmds/fstyp.tproj/fstyp_msdos.c
new file mode 100644
index 0000000..edf4551
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_msdos.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/disk.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/* copied from diskdev_cmds/fsck_msdos/dosfs.h */
+#define DOSBOOTBLOCKSIZE 512
+#define MAX_SECTOR_SIZE 4096
+
+#define E_OPENDEV -1
+#define E_READ -5
+
+void usage(void);
+char *rawname(char *name);
+char *unrawname(char *name);
+int checkVolHdr(const unsigned char *volhdr);
+char *blockcheck(char *origname);
+
+char *progname;
+
+/*
+ * prefer to use raw device. TODO: suppose block device is valid but
+ * the corresponding raw device is not valid, then we fail. this is
+ * probably no the desired behavior.
+ */
+
+int
+main(int argc, char **argv)
+{
+ unsigned char volhdr[MAX_SECTOR_SIZE] = {0};
+ int fd, retval;
+ char *devname;
+
+ fd = -1;
+ retval = 0;
+
+ if ((progname = strrchr(*argv, '/')))
+ ++progname;
+ else
+ progname = *argv;
+
+ if (argc != 2) {
+ usage();
+ } else {
+ devname = blockcheck(argv[1]);
+
+ if (devname != NULL) {
+ if ((fd = open(devname, O_RDONLY, 0)) < 0) {
+ retval = E_OPENDEV;
+ } else if (read(fd, volhdr, MAX_SECTOR_SIZE) != MAX_SECTOR_SIZE) {
+ retval = E_READ;
+ } else {
+ retval = checkVolHdr(volhdr);
+ }
+
+ if (-1 != fd) {
+ close(fd);
+ fd = -1;
+ }
+ }
+ }
+
+ return retval;
+}
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s device\n", progname);
+ return;
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+rawname(char *name)
+{
+ static char rawbuf[32];
+ char *dp;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (0);
+ *dp = 0;
+ (void) strlcpy(rawbuf, name, sizeof(rawbuf));
+ *dp = '/';
+ (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
+ (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
+
+ return (rawbuf);
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+unrawname(char *name)
+{
+ char *dp;
+ struct stat stb;
+ size_t dp_len;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (name);
+ if (stat(name, &stb) < 0)
+ return (name);
+ if ((stb.st_mode & S_IFMT) != S_IFCHR)
+ return (name);
+ if (dp[1] != 'r')
+ return (name);
+ dp_len = strlen(&dp[2]) + 1;
+ (void)memmove(&dp[1], &dp[2], dp_len);
+
+ return (name);
+}
+
+/*
+ * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
+ * 1) remove "hotroot"
+ * 2) if error, return NULL
+ * 3) if not a char device, return NULL (effectively, this is treated
+ * as error even if accessing the block device might have been OK)
+ */
+char *
+blockcheck(char *origname)
+{
+ struct stat stblock, stchar;
+ char *newname, *raw;
+ int retried;
+
+ retried = 0;
+ newname = origname;
+retry:
+ if (stat(newname, &stblock) < 0) {
+ perror(newname);
+ fprintf(stderr, "Can't stat %s\n", newname);
+ return NULL;
+ }
+ if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
+ raw = rawname(newname);
+ if (stat(raw, &stchar) < 0) {
+ perror(raw);
+ fprintf(stderr, "Can't stat %s\n", raw);
+ return NULL;
+ }
+ if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
+ return (raw);
+ } else {
+ fprintf(stderr, "%s is not a character device\n", raw);
+ return NULL;
+ }
+ } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
+ newname = unrawname(newname);
+ retried++;
+ goto retry;
+ }
+ /* not a block or character device */
+ return NULL;
+}
+
+/*
+ * (sanity) check the volume header in volhdr
+ *
+ * return 1 if volhdr is a FAT volhdr, 0 otherwise
+ */
+int
+checkVolHdr(const unsigned char *volhdr)
+{
+ /* NTFS volumes have an OEMid of NTFS followed by four spaces. */
+ const char *ntfs_oemid = "NTFS ";
+ int retval;
+
+ retval = 1;
+
+ /* copied from diskdev_cmds/fsck_msdos/boot.c */
+
+ /*
+ * [2699033]
+ *
+ * The first three bytes are an Intel x86 jump instruction. It should
+ * be one of the following forms: 0xE9 0x?? 0x?? 0xEC 0x?? 0x90 where
+ * 0x?? means any byte value is OK.
+ */
+ if (volhdr[0] != 0xE9 && (volhdr[0] != 0xEB || volhdr[2] != 0x90)) {
+ retval = 0;
+ }
+ if (!memcmp(ntfs_oemid, volhdr + 3, 8))
+ retval = 0;
+ return retval;
+}
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_ntfs.8 b/diskdev_cmds/fstyp.tproj/fstyp_ntfs.8
new file mode 100644
index 0000000..e5efa90
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_ntfs.8
@@ -0,0 +1,41 @@
+.\"
+.\" (c) 2006 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd September 30, 2006
+.Dt FSTYP_NTFS 8
+.Os
+.Sh NAME
+.Nm fstyp_ntfs
+.Nd check for a Windows NT File System (NTFS) volume
+.Sh SYNOPSIS
+.Nm
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility is not intended to be run directly, but rather called by
+.Xr fstyp 8
+while it is trying to determine which file system type is present on the
+given device.
+It returns 1 if it thinks the device contains a Windows NT File System (NTFS)
+volume, and 0 otherwise.
+.Sh SEE ALSO
+.Xr fstyp 8
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_ntfs.c b/diskdev_cmds/fstyp.tproj/fstyp_ntfs.c
new file mode 100644
index 0000000..88e7568
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_ntfs.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/disk.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+/* copied from diskdev_cmds/fsck_msdos/dosfs.h */
+#define DOSBOOTBLOCKSIZE 512
+#define MAX_SECTOR_SIZE 4096
+
+#define E_OPENDEV -1
+#define E_READ -5
+
+void usage(void);
+char *rawname(char *name);
+char *unrawname(char *name);
+int checkVolHdr(const unsigned char *volhdr);
+char *blockcheck(char *origname);
+
+char *progname;
+
+/*
+ * prefer to use raw device. TODO: suppose block device is valid but
+ * the corresponding raw device is not valid, then we fail. this is
+ * probably no the desired behavior.
+ */
+
+int
+main(int argc, char **argv)
+{
+ unsigned char volhdr[MAX_SECTOR_SIZE] = {0};
+ int fd, retval;
+ char *devname;
+
+ fd = -1;
+ retval = 0;
+
+ if ((progname = strrchr(*argv, '/')))
+ ++progname;
+ else
+ progname = *argv;
+
+ if (argc != 2) {
+ usage();
+ } else {
+ devname = blockcheck(argv[1]);
+
+ if (devname != NULL) {
+ if ((fd = open(devname, O_RDONLY, 0)) < 0) {
+ retval = E_OPENDEV;
+ } else if (read(fd, volhdr, MAX_SECTOR_SIZE) != MAX_SECTOR_SIZE) {
+ retval = E_READ;
+ } else {
+ retval = checkVolHdr(volhdr);
+ }
+
+ if (-1 != fd) {
+ close(fd);
+ fd = -1;
+ }
+ }
+ }
+
+ return retval;
+}
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s device\n", progname);
+ return;
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+rawname(char *name)
+{
+ static char rawbuf[32];
+ char *dp;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (0);
+ *dp = 0;
+ (void) strlcpy(rawbuf, name, sizeof(rawbuf));
+ *dp = '/';
+ (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
+ (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
+
+ return (rawbuf);
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+unrawname(char *name)
+{
+ char *dp;
+ struct stat stb;
+ size_t dp_len;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (name);
+ if (stat(name, &stb) < 0)
+ return (name);
+ if ((stb.st_mode & S_IFMT) != S_IFCHR)
+ return (name);
+ if (dp[1] != 'r')
+ return (name);
+ dp_len = strlen(&dp[2]) + 1;
+ (void)memmove(&dp[1], &dp[2], dp_len);
+
+ return (name);
+}
+
+/*
+ * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
+ * 1) remove "hotroot"
+ * 2) if error, return NULL
+ * 3) if not a char device, return NULL (effectively, this is treated
+ * as error even if accessing the block device might have been OK)
+ */
+char *
+blockcheck(char *origname)
+{
+ struct stat stblock, stchar;
+ char *newname, *raw;
+ int retried;
+
+ retried = 0;
+ newname = origname;
+retry:
+ if (stat(newname, &stblock) < 0) {
+ perror(newname);
+ fprintf(stderr, "Can't stat %s\n", newname);
+ return NULL;
+ }
+ if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
+ raw = rawname(newname);
+ if (stat(raw, &stchar) < 0) {
+ perror(raw);
+ fprintf(stderr, "Can't stat %s\n", raw);
+ return NULL;
+ }
+ if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
+ return (raw);
+ } else {
+ fprintf(stderr, "%s is not a character device\n", raw);
+ return NULL;
+ }
+ } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
+ newname = unrawname(newname);
+ retried++;
+ goto retry;
+ }
+ /* not a block or character device */
+ return NULL;
+}
+
+/*
+ * (sanity) check the volume header in volhdr
+ *
+ * return 1 if volhdr is a NTFS volhdr, 0 otherwise
+ */
+int
+checkVolHdr(const unsigned char *volhdr)
+{
+ /* NTFS volumes have an OEMid of NTFS followed by four spaces. */
+ const char *ntfs_oemid = "NTFS ";
+ int retval;
+
+ retval = 1;
+
+ /*
+ * Only check the OEMid. This should be sufficiently specific so it
+ * does not match anything else. If it ever does it would be easy to
+ * check more bootsector fields for validity...
+ */
+ if (memcmp(ntfs_oemid, volhdr + 3, 8))
+ retval = 0;
+ return retval;
+}
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_udf.8 b/diskdev_cmds/fstyp.tproj/fstyp_udf.8
new file mode 100644
index 0000000..00efe55
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_udf.8
@@ -0,0 +1,40 @@
+.\"
+.\" (c) 2005 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd August 15, 2005
+.Dt FSTYP_UDF 8
+.Os
+.Sh NAME
+.Nm fstyp_udf
+.Nd check for a UDF volume
+.Sh SYNOPSIS
+.Nm
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility is not intended to be run directly, but rather called by
+.Xr fstyp 8
+while it is trying to determine which file system type is present on the
+given device.
+It returns 1 if it thinks the device contains a UDF volume, and 0 otherwise.
+.Sh SEE ALSO
+.Xr fstyp 8
diff --git a/diskdev_cmds/fstyp.tproj/fstyp_udf.c b/diskdev_cmds/fstyp.tproj/fstyp_udf.c
new file mode 100644
index 0000000..7526524
--- /dev/null
+++ b/diskdev_cmds/fstyp.tproj/fstyp_udf.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/disk.h>
+
+#define E_OPENDEV -1
+#define E_READ -5
+
+/*
+ * We don't have a (non-C++) standard header for UDF (yet?), so
+ * let's define the basic structures and constants we'll be using.
+ */
+
+typedef struct UDFVolumeSequenceDescriptor {
+ unsigned char type;
+ unsigned char id[5];
+ unsigned char version;
+ unsigned char data[2041];
+} udfVSD;
+
+#define UDFSTART (32*1024) /* First 32k is unused */
+
+void usage(void);
+char *rawname(char *name);
+char *unrawname(char *name);
+int CheckUDF(int, int);
+char *blockcheck(char *origname);
+
+char *progname;
+
+/*
+ * prefer to use raw device. TODO: suppose block device is valid but
+ * the corresponding raw device is not valid, then we fail. this is
+ * probably no the desired behavior.
+ */
+
+int
+main(int argc, char **argv)
+{
+ char *devname = NULL;
+ int fd, retval;
+
+ retval = 0;
+ fd = -1;
+
+ if ((progname = strrchr(*argv, '/')))
+ ++progname;
+ else
+ progname = *argv;
+
+ if (argc != 2) {
+ usage();
+ } else {
+ devname = blockcheck(argv[1]);
+ if (devname != NULL) {
+ if ((fd = open(devname, O_RDONLY, 0)) < 0) {
+ retval = E_OPENDEV;
+ } else {
+ int bsize;
+ if (ioctl(fd, DKIOCGETBLOCKSIZE, (char*)&bsize) == -1) {
+#ifdef DEBUG
+ warn("DKIOCGETBLOCKSIZE ioctl failed for %s", devname);
+#endif
+ bsize = 2048; /* A standard default size */
+ }
+ retval = CheckUDF(fd, bsize) == 1;
+ if (retval == 0 && bsize != 2048) {
+ retval = CheckUDF(fd, 2048) == 1;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+static int
+IsVSD(udfVSD *vsd) {
+ int retval = memcmp(vsd->id, "BEA01", 5)==0 ||
+ memcmp(vsd->id, "BOOT2", 5)==0 ||
+ memcmp(vsd->id, "NSR02", 5)==0 ||
+ memcmp(vsd->id, "NSR03", 5)==0 ||
+ memcmp(vsd->id, "TEA01", 5)==0 ||
+ memcmp(vsd->id, "CDW02", 5)==0 ||
+ memcmp(vsd->id, "CD001", 5)==0;
+#ifdef DEBUG
+ fprintf(stderr, "IsVSD: Returning %d\n", retval);
+#endif
+ return retval;
+}
+
+/*
+ * This is inspired by the udf25 kext code.
+ * It concludes that a device has a UDF filesystem
+ * if:
+ * 1) It has a Volume Sequence Descriptor;
+ * 2) That VSD has a "BEA01" in it;
+ * 3) That VSD has an "NSR02" or "NSR03" in it before the terminating one.
+ *
+ * It may be necessary to check the AVDP(s), as well.
+ */
+
+int
+CheckUDF(int fd, int blockSize) {
+ ssize_t err;
+ char buf[blockSize];
+ off_t curr, max;
+ char found = 0;
+
+ curr = UDFSTART;
+ max = curr + (512 * blockSize);
+ if (lseek(fd, curr, SEEK_SET) == -1) {
+ warn("Cannot seek to %llu", curr);
+ return -1;
+ }
+
+ while (curr < max) {
+ udfVSD *vsd;
+ err = read(fd, buf, sizeof(buf));
+ if (err != sizeof(buf)) {
+ if (err == -1) {
+ warn("Cannot read %zu bytes", sizeof(buf));
+ } else {
+ warn("Cannot read %zd bytes, only read %zd", sizeof(buf), err);
+ }
+ return -1;
+ }
+ vsd = (udfVSD*)buf;
+ if (!IsVSD(vsd)) {
+ break;
+ }
+ if (vsd->type == 0 &&
+ memcmp(vsd->id, "BEA01", 5) == 0 &&
+ vsd->version == 1) {
+ found = 1;
+ break;
+ }
+ curr += blockSize;
+ }
+ if (found == 0)
+ return 0;
+
+ found = 0;
+
+ while (curr < max) {
+ udfVSD *vsd;
+ err = read(fd, buf, sizeof(buf));
+ if (err != sizeof(buf)) {
+ if (err == -1) {
+ warn("Cannot read %zu bytes", sizeof(buf));
+ } else {
+ warn("Cannot read %zu bytes, only read %zd", sizeof(buf), err);
+ }
+ return -1;
+ }
+ vsd = (udfVSD*)buf;
+ if (!IsVSD(vsd)) {
+ break;
+ }
+ if (vsd->type == 0 &&
+ memcmp(vsd->id, "TEA01", 5) == 0 &&
+ vsd->version == 1) {
+ /* we're at the end */
+ break;
+ } else if (memcmp(vsd->id, "NSR02", 5) == 0 ||
+ memcmp(vsd->id, "NSR03", 5) == 0) {
+ found = 1;
+ break;
+ }
+ curr += blockSize;
+ }
+
+ return found;
+}
+
+void
+usage(void)
+{
+ fprintf(stdout, "usage: %s device\n", progname);
+ return;
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+rawname(char *name)
+{
+ static char rawbuf[32];
+ char *dp;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (0);
+ *dp = 0;
+ (void) strlcpy(rawbuf, name, sizeof(rawbuf));
+ *dp = '/';
+ (void) strlcat(rawbuf, "/r", sizeof(rawbuf));
+ (void) strlcat(rawbuf, &dp[1], sizeof(rawbuf));
+
+ return (rawbuf);
+}
+
+/* copied from diskdev_cmds/fsck_hfs/utilities.c */
+char *
+unrawname(char *name)
+{
+ char *dp;
+ struct stat stb;
+ size_t dp_len;
+
+ if ((dp = strrchr(name, '/')) == 0)
+ return (name);
+ if (stat(name, &stb) < 0)
+ return (name);
+ if ((stb.st_mode & S_IFMT) != S_IFCHR)
+ return (name);
+ if (dp[1] != 'r')
+ return (name);
+ dp_len = strlen(&dp[2]) + 1;
+ (void)memmove(&dp[1], &dp[2], dp_len);
+
+ return (name);
+}
+
+/*
+ * copied from diskdev_cmds/fsck_hfs/utilities.c, and modified:
+ * 1) remove "hotroot"
+ * 2) if error, return NULL
+ * 3) if not a char device, return NULL (effectively, this is treated
+ * as error even if accessing the block device might have been OK)
+ */
+char *
+blockcheck(char *origname)
+{
+ struct stat stblock, stchar;
+ char *newname, *raw;
+ int retried = 0;
+
+ newname = origname;
+retry:
+ if (stat(newname, &stblock) < 0) {
+ perror(newname);
+ fprintf(stderr, "Can't stat %s\n", newname);
+ return NULL;
+ }
+ if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
+ raw = rawname(newname);
+ if (stat(raw, &stchar) < 0) {
+ perror(raw);
+ fprintf(stderr, "Can't stat %s\n", raw);
+ return NULL;
+ }
+ if ((stchar.st_mode & S_IFMT) == S_IFCHR) {
+ return (raw);
+ } else {
+ fprintf(stderr, "%s is not a character device\n", raw);
+ return NULL;
+ }
+ } else if ((stblock.st_mode & S_IFMT) == S_IFCHR && !retried) {
+ newname = unrawname(newname);
+ retried++;
+ goto retry;
+ }
+#ifdef DEBUG
+ else if ((stblock.st_mode & S_IFMT) == S_IFREG) {
+ return strdup(origname);
+ }
+#endif
+ /* not a block or character device */
+ return NULL;
+}
+
+
diff --git a/diskdev_cmds/fuser.tproj/fuser.1 b/diskdev_cmds/fuser.tproj/fuser.1
new file mode 100644
index 0000000..fcaf5a2
--- /dev/null
+++ b/diskdev_cmds/fuser.tproj/fuser.1
@@ -0,0 +1,200 @@
+.\" Copyright (c) 2001-2003 The Open Group, All Rights Reserved
+.TH "FUSER" P 2003 "IEEE/The Open Group" "POSIX Programmer's Manual"
+.\" fuser
+.SH NAME
+fuser \- list process IDs of all processes that have one or more files
+open
+.SH SYNOPSIS
+.LP
+\fBfuser\fP \fB[\fP \fB-cfu\fP \fB]\fP \fIfile\fP \fB... \fP
+.SH DESCRIPTION
+.LP
+The \fIfuser\fP utility shall write to standard output the process
+IDs of processes running on the local system that have one
+or more named files open. For block special devices, all processes
+using any file on that device are listed.
+.LP
+The \fIfuser\fP utility shall write to standard error additional information
+about the named files indicating how the file is
+being used.
+.LP
+Any output for processes running on remote systems that have a named
+file open is unspecified.
+.LP
+A user may need appropriate privilege to invoke the \fIfuser\fP utility.
+.SH OPTIONS
+.LP
+The \fIfuser\fP utility shall conform to the Base Definitions volume
+of IEEE\ Std\ 1003.1-2001, Section 12.2, Utility Syntax Guidelines.
+.LP
+The following options shall be supported:
+.TP 7
+\fB-c\fP
+The file is treated as a mount point and the utility shall report
+on any files open in the file system.
+.TP 7
+\fB-f\fP
+The report shall be only for the named files.
+.TP 7
+\fB-u\fP
+The user name, in parentheses, associated with each process ID written
+to standard output shall be written to standard
+error.
+.sp
+.SH OPERANDS
+.LP
+The following operand shall be supported:
+.TP 7
+\fIfile\fP
+A pathname on which the file or file system is to be reported.
+.sp
+.SH STDIN
+.LP
+Not used.
+.SH INPUT FILES
+.LP
+The user database.
+.SH ENVIRONMENT VARIABLES
+.LP
+The following environment variables shall affect the execution of
+\fIfuser\fP:
+.TP 7
+\fILANG\fP
+Provide a default value for the internationalization variables that
+are unset or null. (See the Base Definitions volume of
+IEEE\ Std\ 1003.1-2001, Section 8.2, Internationalization Variables
+for
+the precedence of internationalization variables used to determine
+the values of locale categories.)
+.TP 7
+\fILC_ALL\fP
+If set to a non-empty string value, override the values of all the
+other internationalization variables.
+.TP 7
+\fILC_CTYPE\fP
+Determine the locale for the interpretation of sequences of bytes
+of text data as characters (for example, single-byte as
+opposed to multi-byte characters in arguments).
+.TP 7
+\fILC_MESSAGES\fP
+Determine the locale that should be used to affect the format and
+contents of diagnostic messages written to standard
+error.
+.TP 7
+\fINLSPATH\fP
+Determine the location of message catalogs for the processing of \fILC_MESSAGES
+\&.\fP
+.sp
+.SH ASYNCHRONOUS EVENTS
+.LP
+Default.
+.SH STDOUT
+.LP
+The \fIfuser\fP utility shall write the process ID for each process
+using each file given as an operand to standard output in
+the following format:
+.sp
+.RS
+.nf
+
+\fB"%d", <\fP\fIprocess_id\fP\fB>
+\fP
+.fi
+.RE
+.SH STDERR
+.LP
+The \fIfuser\fP utility shall write diagnostic messages to standard
+error.
+.LP
+The \fIfuser\fP utility also shall write the following to standard
+error:
+.IP " *" 3
+The pathname of each named file is written followed immediately by
+a colon.
+.LP
+.IP " *" 3
+For each process ID written to standard output, the character \fB'c'\fP
+shall be written to standard error if the process is
+using the file as its current directory and the character \fB'r'\fP
+shall be written to standard error if the process is using
+the file as its root directory. Implementations may write other alphabetic
+characters to indicate other uses of files.
+.LP
+.IP " *" 3
+When the \fB-u\fP option is specified, characters indicating the use
+of the file shall be followed immediately by the user
+name, in parentheses, corresponding to the process' real user ID.
+If the user name cannot be resolved from the process' real user
+ID, the process' real user ID shall be written instead of the user
+name.
+.LP
+.LP
+When standard output and standard error are directed to the same file,
+the output shall be interleaved so that the filename
+appears at the start of each line, followed by the process ID and
+characters indicating the use of the file. Then, if the \fB-u\fP
+option is specified, the user name or user ID for each process using
+that file shall be written.
+.LP
+A <newline> shall be written to standard error after the last output
+described above for each \fIfile\fP operand.
+.SH OUTPUT FILES
+.LP
+None.
+.SH EXTENDED DESCRIPTION
+.LP
+None.
+.SH EXIT STATUS
+.LP
+The following exit values shall be returned:
+.TP 7
+\ 0
+Successful completion.
+.TP 7
+>0
+An error occurred.
+.sp
+.SH CONSEQUENCES OF ERRORS
+.LP
+Default.
+.LP
+\fIThe following sections are informative.\fP
+.SH APPLICATION USAGE
+.LP
+None.
+.SH EXAMPLES
+.LP
+The command:
+.sp
+.RS
+.nf
+
+\fBfuser -fu .
+\fP
+.fi
+.RE
+.LP
+writes to standard output the process IDs of processes that are using
+the current directory and writes to standard error an
+indication of how those processes are using the directory and the
+user names associated with the processes that are using the
+current directory.
+.SH RATIONALE
+.LP
+The definition of the \fIfuser\fP utility follows existing practice.
+.SH FUTURE DIRECTIONS
+.LP
+None.
+.SH SEE ALSO
+.LP
+None.
+.SH COPYRIGHT
+Portions of this text are reprinted and reproduced in electronic form
+from IEEE Std 1003.1, 2003 Edition, Standard for Information Technology
+-- Portable Operating System Interface (POSIX), The Open Group Base
+Specifications Issue 6, Copyright (C) 2001-2003 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/diskdev_cmds/fuser.tproj/fuser.pl b/diskdev_cmds/fuser.tproj/fuser.pl
new file mode 100755
index 0000000..0784bfb
--- /dev/null
+++ b/diskdev_cmds/fuser.tproj/fuser.pl
@@ -0,0 +1,92 @@
+#!/usr/bin/perl -w
+##
+# Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+#
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+#
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+#
+# @APPLE_LICENSE_HEADER_END@
+##
+
+use strict;
+use Getopt::Long qw(GetOptions);
+
+sub usage {
+ print "fuser: [-cfu] file ...\n",
+ "\t-c\tfile is treated as mount point\n",
+ "\t-f\tthe report is only for the named files\n",
+ "\t-u\tprint username of pid in parenthesis\n";
+}
+
+Getopt::Long::config('bundling');
+my %o;
+unless (GetOptions(\%o, qw(c f u)) && scalar (@ARGV) > 0) {
+ usage();
+ exit(1);
+}
+
+use IO::Handle;
+STDERR->autoflush(1);
+STDOUT->autoflush(1);
+
+my $exit_value = 0;
+
+my $space = "";
+while (scalar (@ARGV)) {
+ my $file = shift @ARGV;
+ if (-e $file) {
+ my @command;
+ push(@command, q(/usr/sbin/lsof));
+ push(@command, q(-F));
+ if ($o{u}) { # Add user name
+ push(@command, q(pfL));
+ } else {
+ push(@command, q(pf));
+ }
+ push(@command, q(-f)) if ($o{f});
+ push(@command, q(--));
+ push(@command, $file);
+ # This cryptic statement will cause exec(@command) to run in the child,
+ # with the output set up correctl and LSOF's input set up correctly.
+ open (LSOF, "-|") or exec(@command);
+ my @results = <LSOF>;
+ chomp(@results);
+ # fuser man page is very explicit about stdout/stderr output
+ print STDERR $file, qq(: );
+ my $username = "";
+ foreach (@results) {
+ if (/^p(\d+)$/) {
+ if ($username) {
+ print STDERR $username;
+ $username = "";
+ }
+ print $space, $1;
+ $space = q( );
+ }
+ if (/^f(c|r)[wt]d$/) {
+ print STDERR "$1" . $username;
+ $username = "";
+ }
+ $username = "(" . $1 . ")" if (/^L(.+)$/);
+ }
+ print STDERR $username . qq(\n);
+ } else {
+ print STDERR "$0: '$file' does not exist\n";
+ $exit_value = 1;
+ }
+}
+exit($exit_value);
diff --git a/diskdev_cmds/mount.tproj/fstab.5 b/diskdev_cmds/mount.tproj/fstab.5
new file mode 100644
index 0000000..0ba6dc7
--- /dev/null
+++ b/diskdev_cmds/mount.tproj/fstab.5
@@ -0,0 +1,222 @@
+.\" $NetBSD: fstab.5,v 1.5.2.1 1995/11/16 20:11:11 pk Exp $
+.\"
+.\" Copyright (c) 1980, 1989, 1991, 1993, 2002
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fstab.5 8.1 (Berkeley) 6/5/93
+.\"
+.Dd March 28, 2002
+.Dt FSTAB 5
+.Os Darwin
+.Sh NAME
+.Nm fstab
+.Nd static information about the filesystems
+.Sh SYNOPSIS
+.Fd #include <fstab.h>
+.Sh DESCRIPTION
+The file
+.Nm fstab
+contains descriptive information about the various file
+systems.
+.Nm fstab
+is only read by programs, and not written;
+it is the duty of the system administrator to properly create
+and maintain this file, using the
+.Xr vifs 8
+command.
+Each filesystem is described on a separate line;
+fields on each line are separated by tabs or spaces.
+The order of records in
+.Nm fstab
+is important because
+.Xr diskarbitrationd 8 ,
+.Xr fsck 8 ,
+.Xr mount 8 ,
+and
+.Xr umount 8
+sequentially iterate through
+.Nm fstab
+doing their thing.
+.Pp
+The first field,
+.Pq Fa fs_spec ,
+describes the block special device, the local filesystem, or
+the remote filesystem to be mounted. The
+.Xr diskarbitrationd
+program supports the identification of a local filesystem uniquely by its
+UUID or by its volume name, irrespective of hardware configuration and of
+hardware parallelism, using the constructs ``UUID'' and ``LABEL''.
+For APFS volumes, this field should never be the block special device as it is
+not constant. Only the constructs ``UUID'' and ``LABEL'' should be used.
+.Pp
+The second field,
+.Pq Fa fs_file ,
+describes the mount point for the filesystem.
+For swap partitions, this field should be specified as ``none''.
+.Pp
+The third field,
+.Pq Fa fs_vfstype ,
+describes the type of the filesystem.
+The system currently supports different filesystem types, including the following:
+.Bl -tag -width indent -offset indent
+.It Em apfs
+APFS is the Mac OS X default filesystem since version 10.13 (High Sierra).
+.It Em hfs
+HFS+ is the previous Mac OS X default filesystem.
+.It Em nfs
+a Sun Microsystems compatible ``Network File System''
+.It Em msdos
+a DOS compatible filesystem
+.It Em cd9660
+a CD-ROM filesystem (as per ISO 9660)
+.It Em fdesc
+an implementation of /dev/fd
+.It Em union
+a translucent filesystem
+.El
+.Pp
+The fourth field,
+.Pq Fa fs_mntops ,
+describes the mount options associated with the filesystem.
+It is formatted as a comma separated list of options.
+It contains at least the type of mount (see
+.Fa fs_type
+below) plus any additional options
+appropriate to the filesystem type.
+.Pp
+The option ``auto'' can be used in the ``noauto'' form to cause
+a file system not to be mounted automatically (with ``mount -a'',
+or system boot time).
+.Pp
+The type of the mount is extracted from the
+.Fa fs_mntops
+field and stored separately in the
+.Fa fs_type
+field (it is not deleted from the
+.Fa fs_mntops
+field).
+If
+.Fa fs_type
+is ``rw'' or ``ro'' then the filesystem whose name is given in the
+.Fa fs_file
+field is normally mounted read-write or read-only on the
+specified special file.
+If
+.Fa fs_type
+is ``sw'' then the special file is made available as a piece of swap
+space by the
+.Xr swapon 8
+command at the end of the system reboot procedure.
+The fields other than
+.Fa fs_spec
+and
+.Fa fs_type
+are unused.
+If
+.Fa fs_type
+is specified as ``xx'' the entry is ignored.
+This is useful to show disk partitions which are currently unused.
+.Pp
+The fifth field,
+.Pq Fa fs_freq ,
+is used for these filesystems by the
+.Xr dump 8
+command to determine which filesystems need to be dumped.
+If the fifth field is not present, a value of zero is returned and
+.Xr dump
+will assume that the filesystem does not need to be dumped.
+.Pp
+The sixth field,
+.Pq Fa fs_passno ,
+is used by the
+.Xr fsck 8
+program to determine the order in which filesystem checks are done
+at reboot time.
+The root filesystem should be specified with a
+.Fa fs_passno
+of 1, and other filesystems should have a
+.Fa fs_passno
+of 2.
+Filesystems within a drive will be checked sequentially,
+but filesystems on different drives will be checked at the
+same time to utilize parallelism available in the hardware.
+If the sixth field is not present or zero,
+a value of zero is returned and
+.Xr fsck
+will assume that the filesystem does not need to be checked.
+.Bd -literal
+#define FSTAB_RW "rw" /* read-write device */
+#define FSTAB_RO "ro" /* read-only device */
+#define FSTAB_SW "sw" /* swap device */
+#define FSTAB_XX "xx" /* ignore totally */
+
+struct fstab {
+ char *fs_spec; /* block special device name */
+ char *fs_file; /* filesystem path prefix */
+ char *fs_vfstype; /* type of filesystem */
+ char *fs_mntops; /* comma separated mount options */
+ char *fs_type; /* rw, ro, sw, or xx */
+ int fs_freq; /* dump frequency, in days */
+ int fs_passno; /* pass number on parallel fsck */
+};
+.Ed
+.Pp
+The proper way to read records from
+.Pa fstab
+is to use the routines
+.Xr getfsent 3 ,
+.Xr getfsspec 3 ,
+.Xr getfstype 3 ,
+and
+.Xr getfsfile 3 .
+.Sh EXAMPLES
+.Bd -literal
+UUID=2A1B02AD-467D-403A-8CCD-B87E50AD3DA2 none apfs rw
+UUID=DF000C7E-AE0C-3B15-B730-DFD2EF15CB91 /export apfs ro
+UUID=FAB060E9-79F7-33FF-BE85-E1D3ABD3EDEA none hfs rw,noauto
+LABEL=The\\040Volume\\040Name\\040Is\\040This none msdos ro
+.Ed
+.Sh FILES
+.Bl -tag -width /etc/fstab -compact
+.It Pa /etc/fstab
+The file
+.Nm fstab
+resides in
+.Pa /etc .
+.El
+.Sh SEE ALSO
+.Xr getfsent 3 ,
+.Xr diskarbitrationd 8
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.0 .
diff --git a/diskdev_cmds/mount.tproj/mount.8 b/diskdev_cmds/mount.tproj/mount.8
new file mode 100644
index 0000000..d07ff8d
--- /dev/null
+++ b/diskdev_cmds/mount.tproj/mount.8
@@ -0,0 +1,293 @@
+.\" Copyright (c) 1980, 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mount.8 8.8 (Berkeley) 6/16/94
+.\"
+.Dd June 16, 1994
+.Dt MOUNT 8
+.Os BSD 4
+.Sh NAME
+.Nm mount
+.Nd mount file systems
+.Sh SYNOPSIS
+.Nm mount
+.Op Fl adfruvw
+.Op Fl t Ar lfs | external_type
+.Nm mount
+.Op Fl dfruvw
+.Ar special | mount_point
+.Nm mount
+.Op Fl dfruvw
+.Op Fl o Ar options
+.Op Fl t Ar lfs | external_type
+.Ar special mount_point
+.Sh DESCRIPTION
+The
+.Nm mount
+command
+calls the
+.Xr mount 2
+system call to prepare and graft a
+.Ar "special device"
+or the remote node (rhost:path) on to the file system tree at the point
+.Ar mount_point ,
+which must be a directory. If either
+.Ar special
+or
+.Ar mount_point
+are not provided, the appropriate information is obtained via the
+.Xr getfsent 3
+library routines.
+.Pp
+The system maintains a list of currently mounted file systems.
+If no arguments are given to
+.Nm mount,
+this list is printed.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a
+All the filesystems listed via
+.Xr getfsent 3
+are mounted.
+Exceptions are those marked as ``noauto;'' excluded by the
+.Fl t
+flag (see below); entries that are neither ``ro,'' ``rw,'' or
+``rq;'' ``nfs'' entries that also have ``net'' as an option; and
+already-mounted ``nfs'' entries.
+.It Fl d
+Causes everything to be done except for the actual system call.
+This option is useful in conjunction with the
+.Fl v
+flag to
+determine what the
+.Nm mount
+command is trying to do.
+.It Fl f
+Forces the revocation of write access when trying to downgrade
+a filesystem mount status from read-write to read-only.
+.It Fl o
+Options are specified with a
+.Fl o
+flag followed by a comma separated string of options.
+The following options are available:
+.Bl -tag -width indent
+.It async
+All
+.Tn I/O
+to the file system should be done asynchronously.
+This can be somewhat dangerous with respect to losing data when faced with
+system crashes and power outages.
+This is also the default.
+It can be avoided with the
+.Em noasync
+option.
+.It force
+The same as
+.Fl f ;
+forces the revocation of write access when trying to downgrade
+a filesystem mount status from read-write to read-only.
+.It noasync
+This filesystem should not force all
+.Tn I/O
+to be written asynchronously.
+.It noauto
+This filesystem should be skipped when mount is run with the
+.Fl a
+flag.
+.It nodev
+Do not interpret character or block special devices on the file system.
+This option is useful for a server that has file systems containing
+special devices for architectures other than its own.
+.It noexec
+Do not allow execution of any binaries on the mounted file system.
+This option is useful for a server that has file systems containing
+binaries for architectures other than its own.
+.It noowners
+Ignore the ownership field for the entire volume.
+This causes all objects to appear as owned by user ID 99 and group ID 99.
+User ID 99 is interpreted as the current effective user ID, while group ID 99
+is used directly and translates to ``unknown''.
+.It nosuid
+Do not allow set-user-identifier or set-group-identifier bits to take effect.
+.It rdonly
+The same as
+.Fl r ;
+mount the file system read-only (even the super-user may not write it).
+.It sync
+All
+.Tn I/O
+to the file system should be done synchronously.
+.It update
+The same as
+.Fl u ;
+indicate that the status of an already mounted file system should be changed.
+.It union
+Causes the namespace to appear as the union of directories
+of the mounted filesystem with corresponding directories in the
+underlying filesystem.
+Lookups will be done in the mounted filesystem first.
+If those operations fail due to a non-existent file the underlying
+directory is then accessed.
+.It noatime
+Do not update the file access time when reading from a file.
+This option is useful on file systems where there are large numbers of files
+and performance is more critical than updating the file access time (which
+is rarely ever important).
+.It strictatime
+Always update the file access time when reading from a file. Without this option the
+filesystem may default to a less strict update mode, where some access time updates
+are skipped for performance reasons. This option could be ignored if it is not supported
+by the filesystem.
+.It nobrowse
+This option indicates that the mount point should not be visible
+via the GUI (i.e., appear on the Desktop as a separate volume).
+.El
+.Pp
+Any additional options specific to a filesystem type that is not
+one of the internally known types (see the
+.Fl t
+option) may be passed as a comma separated list; these options are
+distinguished by a leading
+.Dq \&-
+(dash).
+Options that take a value are specified using the syntax -option=value.
+For example, the mount command:
+.Bd -literal -offset indent
+mount -t hfs -o nosuid,-w,-m=755 /dev/disk2s9 /tmp
+.Ed
+.Pp
+causes
+.Nm mount
+to execute the equivalent of:
+.Bd -literal -offset indent
+/sbin/mount_hfs -o nosuid -w -m 755 /dev/disk2s9 /tmp
+.Ed
+.It Fl r
+Mount the file system read-only (even the super-user may not write it).
+The same as the
+.Dq rdonly
+argument to the
+.Fl o
+option.
+.It Fl t Ar "lfs \\*(Ba external type"
+The argument following the
+.Fl t
+is used to indicate the file system type.
+There is no default local file system for use with mount. A type must
+be specified in order to mount a non-NFS filesystem.
+The \fI-t\fP option can be used
+to indicate that the actions should only be taken on
+filesystems of the specified type.
+More than one type may be specified in a comma separated list.
+The list of filesystem types can be prefixed with
+.Dq no
+to specify the filesystem types for which action should
+.Em not
+be taken.
+For example, the
+.Nm mount
+command:
+.Bd -literal -offset indent
+mount -a -t nonfs,hfs
+.Ed
+.Pp
+mounts all filesystems except those of type
+.Tn NFS
+and
+.Tn HFS .
+.Pp
+If the type is not one of the internally known types,
+mount will attempt to execute a program in
+.Pa /sbin/mount_ Ns Em XXX
+where
+.Em XXX
+is replaced by the type name.
+For example, nfs filesystems are mounted by the program
+.Pa /sbin/mount_nfs .
+.It Fl u
+The
+.Fl u
+flag indicates that the status of an already mounted file
+system should be changed.
+Any of the options discussed above (the
+.Fl o
+option)
+may be changed;
+also a file system can be changed from read-only to read-write
+or vice versa.
+An attempt to change from read-write to read-only will fail if any
+files on the filesystem are currently open for writing unless the
+.Fl f
+flag is also specified.
+The set of options is determined by first extracting the options
+for the file system from the
+filesystem table (see
+.Xr getfsent 3 )
+then applying any options specified by the
+.Fl o
+argument,
+and finally applying the
+.Fl r
+or
+.Fl w
+option.
+.It Fl v
+Verbose mode.
+.It Fl w
+Mount the file system read-write.
+.Pp
+The options specific to NFS filesystems are described in the
+.Xr mount_nfs 8
+manual page.
+.El
+.Sh SEE ALSO
+.Xr mount 2 ,
+.Xr getfsent 3 ,
+.Xr mount_afp 8 ,
+.Xr mount_cd9660 8 ,
+.Xr mount_cddafs 8 ,
+.Xr mount_fdesc 8 ,
+.Xr mount_hfs 8 ,
+.Xr mount_apfs 8 ,
+.Xr mount_msdos 8 ,
+.Xr mount_nfs 8 ,
+.Xr mount_smbfs 8 ,
+.Xr mount_udf 8 ,
+.Xr mount_webdav 8 ,
+.Xr umount 8
+.Sh BUGS
+It is possible for a corrupted file system to cause a crash.
+.Sh HISTORY
+A
+.Nm mount
+command appeared in
+.At v6 .
diff --git a/diskdev_cmds/mount.tproj/mount.c b/diskdev_cmds/mount.tproj/mount.c
new file mode 100644
index 0000000..ace7cbe
--- /dev/null
+++ b/diskdev_cmds/mount.tproj/mount.c
@@ -0,0 +1,1696 @@
+/*
+ * Copyright (c) 1999-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1980, 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <System/sys/reason.h>
+#include <err.h>
+#include <os/errno.h>
+#include <os/bsd.h>
+#include <os/variant_private.h>
+#include <fstab.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <TargetConditionals.h>
+#include <sysexits.h>
+#include <sys/sysctl.h>
+#include <APFS/APFS.h>
+#include <APFS/APFSConstants.h>
+#include <pthread.h>
+#include <spawn.h>
+#include <crt_externs.h>
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#include <paths.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/cdefs.h>
+
+/* Some APFS specific goop */
+#include <copyfile.h>
+#include <MediaKit/MKMedia.h>
+#include <MediaKit/MKMediaAccess.h>
+#include <MediaKit/GPTTypes.h>
+#endif
+
+#if TARGET_OS_OSX
+// To unmount the BaseSystem disk image.
+#include <paths.h>
+#include <IOKit/IOBSD.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOMedia.h>
+#endif
+
+#include "mount_flags.h"
+#include "edt_fstab.h"
+#include "pathnames.h"
+#include "fsck.h"
+
+#if TARGET_OS_OSX
+#define APFS_BOOT_UTIL_PATH "/System/Library/Filesystems/apfs.fs/Contents/Resources/apfs_boot_util"
+#define PLATFORM_DATA_VOLUME_MOUNT_POINT "/System/Volumes/Data"
+#define BASE_SYSTEM_PATH "/System/Volumes/BaseSystem"
+#define RECOVERY_PATH "/System/Volumes/Recovery"
+#else
+#define APFS_BOOT_UTIL_PATH "/System/Library/Filesystems/apfs.fs/apfs_boot_util"
+#define PLATFORM_DATA_VOLUME_MOUNT_POINT "/private/var"
+#endif
+
+#define environ (*_NSGetEnviron())
+#define COMMAND_OUTPUT_MAX 1024
+
+int debug;
+int verbose;
+int bootstrap_macos = 0;
+int passno = 0;
+
+int checkvfsname __P((const char *, const char **));
+char *catopt __P((char *, const char *));
+struct statfs *getmntpt __P((const char *));
+int hasopt __P((const char *, const char *));
+const char
+ **makevfslist __P((char *));
+void mangle __P((char *, int *, const char **));
+void prmount __P((struct statfs *));
+void usage __P((void));
+
+int run_command(char **command_argv, char *output, int *rc, int *signal_no);
+void print_mount(const char **vfslist);
+int ismounted(const char *fs_spec, const char *fs_file, long *flags);
+int mountfs(const char *vfstype, const char *fs_spec, const char *fs_file, int flags, const char *options, const char *mntopts);
+int unmount_location(char *mount_point);
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+
+char* parse_parameter_for_token(char * opts, char * search_string);
+int verify_executable_file_existence (char *path);
+int verify_file_existence (char *path);
+int _verify_file_flags (char *path, int flags);
+int preflight_create_mount_ramdisk (char *mnt_opts, size_t *ramdisk_size, char *template);
+char* split_ramdisk_params(char *opts);
+int create_mount_ramdisk(struct fstab *fs, int init_flags, char *options);
+int construct_apfs_volume(char *mounted_device_name);
+int create_partition_table(size_t partition_size, char *device);
+int attach_device(size_t device_size , char* deviceOut);
+void truncate_whitespace(char* str);
+
+#define RAMDISK_BLCK_OFFSET 34
+#define RAMDISK_TMP_MOUNT "/mnt2"
+#define RAMDISK_BCK_MOUNT "/.mb"
+#define RAMDISK_SIZE_TOK "size="
+#define RAMDISK_TPLT_TOK "template="
+#define HDIK_PATH "/usr/sbin/hdik"
+
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+
+//pull in the optnames array from the mount_flags.c file
+extern mountopt_t optnames[];
+#if TARGET_OS_OSX
+static int booted_rosv(void);
+static int booted_apfs(void);
+#endif /* TARGET_OS_OSX */
+static int upgrade_mount(const char *mountpt, int init_flags, char *options);
+
+/*
+ * Map a POSIX error code to a representative sysexits(3) code. Can be disabled
+ * to exit with errno error code by passing -e as a command line argument to mount
+ */
+static int ret_errno = 0;
+static inline int
+errno_or_sysexit(int err, int sysexit)
+{
+ if (sysexit == -1) {
+ sysexit = sysexit_np(err);
+ }
+ return (ret_errno ? err : sysexit);
+}
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#define BINDFS_MOUNT_TYPE "bindfs"
+#define PREBOOT_VOL_MOUNTPOINT "/private/preboot"
+#define HARDWARE_VOL_MOUNTPOINT "/private/var/hardware"
+
+#define BOOT_MANIFEST_HASH_LEN 256
+
+typedef struct bind_mount {
+ char *bm_mnt_prefix;
+ char *bm_mnt_to;
+ bool bm_mandatory;
+} bind_mount_t;
+
+static void
+do_bindfs_mount(char *from, const char *to, bool required)
+{
+ struct statfs sfs;
+ uint32_t mnt_flags = MNT_RDONLY | MNT_NODEV | MNT_NOSUID | MNT_DONTBROWSE;
+ int err = 0;
+
+ if (debug) {
+ printf("call: mount %s %s %x %s", BINDFS_MOUNT_TYPE, to, mnt_flags, from);
+ return;
+ }
+
+ if ((statfs(from, &sfs) == 0) &&
+ (strncmp(sfs.f_fstypename, BINDFS_MOUNT_TYPE, sizeof(BINDFS_MOUNT_TYPE)) == 0)) {
+ return;
+ }
+
+ err = mount(BINDFS_MOUNT_TYPE, to, mnt_flags, from);
+ if (err) {
+ if ((errno == ENOENT) && !required) {
+ err = 0;
+ } else {
+ errx(errno_or_sysexit(errno, -1), "failed to mount %s -> %s - %s(%d)",
+ from, to, strerror(errno), errno);
+ }
+ }
+}
+
+static void
+setup_preboot_mounts(int pass)
+{
+ int err = 0;
+ const char *mnt_to;
+ char mnt_from[MAXPATHLEN], boot_manifest_hash[BOOT_MANIFEST_HASH_LEN];
+
+ err = get_boot_manifest_hash(boot_manifest_hash, sizeof(boot_manifest_hash));
+ if (err) {
+ errx(errno_or_sysexit(err, -1), "failed to get boot manifest hash - %s",
+ strerror(err));
+ }
+
+ const bind_mount_t preboot_mnts[] = {
+ {.bm_mnt_prefix = PREBOOT_VOL_MOUNTPOINT,
+ .bm_mnt_to = "/usr/standalone/firmware",
+ .bm_mandatory = true},
+ {.bm_mnt_prefix = PREBOOT_VOL_MOUNTPOINT,
+ .bm_mnt_to = "/usr/local/standalone/firmware",
+ .bm_mandatory = false}
+ };
+
+ const bind_mount_t hw_mnts[] = {
+ {.bm_mnt_prefix = HARDWARE_VOL_MOUNTPOINT "/Pearl",
+ .bm_mnt_to = "/System/Library/Pearl/ReferenceFrames",
+ .bm_mandatory = false},
+ {.bm_mnt_prefix = HARDWARE_VOL_MOUNTPOINT "/FactoryData",
+ .bm_mnt_to = "/System/Library/Caches/com.apple.factorydata",
+ .bm_mandatory = true}
+ };
+
+ if (pass == ROOT_PASSNO) {
+ for (int i = 0; i < (sizeof(preboot_mnts) / sizeof(preboot_mnts[0])); i++) {
+ mnt_to = preboot_mnts[i].bm_mnt_to;
+ snprintf(mnt_from, sizeof(mnt_from), "%s/%s%s",
+ preboot_mnts[i].bm_mnt_prefix, boot_manifest_hash, mnt_to);
+
+ do_bindfs_mount(mnt_from, mnt_to, preboot_mnts[i].bm_mandatory);
+ }
+ } else {
+ for (int i = 0; i < (sizeof(hw_mnts) / sizeof(hw_mnts[0])); i++) {
+ mnt_to = hw_mnts[i].bm_mnt_to;
+ snprintf(mnt_from, sizeof(mnt_from), "%s%s",
+ hw_mnts[i].bm_mnt_prefix, mnt_to);
+
+ do_bindfs_mount(mnt_from, mnt_to, hw_mnts[i].bm_mandatory);
+ }
+ }
+}
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+
+/*
+ * mount phases to be used during boot to perform the following operations:
+ * first phase:
+ * TARGET_OS_OSX: (call `apfs_boot_util 1`
+ * TARGET_OS_IPHONE: mount System, Preboot and xART volumes (if present)
+ *
+ * second phase:
+ * TARGET_OS_OSX: unmount base system DMG if needed, upgrade System
+ * volume to RW, and call `apfs_boot_util 2` (on ROSV config)
+ * TARGET_OS_IPHONE: mount remaining volumes
+ *
+ * For more info on mount phases, see apfs_boot_util.
+ */
+#define MOUNT_PHASE_1 1 /* first phase */
+#define MOUNT_PHASE_2 2 /* second phase */
+
+#define NONFS "nonfs"
+
+static void
+bootstrap_apfs(int phase)
+{
+ char * const apfs_util_argv[] = {
+ APFS_BOOT_UTIL_PATH,
+ ((phase == MOUNT_PHASE_1) ? "1" : ((phase == MOUNT_PHASE_2) ? "2" : NULL)),
+ NULL,
+ };
+ execv(APFS_BOOT_UTIL_PATH, apfs_util_argv);
+ errx(errno_or_sysexit(errno, -1), "apfs_boot_util exec failed");
+}
+
+int
+main(argc, argv)
+ int argc;
+ char * const argv[];
+{
+ const char **vfslist, *vfstype;
+ struct fstab *fs;
+ struct statfs *mntbuf;
+ int all, ch, init_flags, rval;
+ char *options, *ep;
+ int mount_phase = 0;
+
+ all = init_flags = 0;
+ options = NULL;
+ vfslist = NULL;
+ vfstype = NULL;
+
+ while ((ch = getopt(argc, argv, "headfo:rwt:uvP:")) != EOF)
+ switch (ch) {
+ case 'a':
+ all = 1;
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case 'f':
+ init_flags |= MNT_FORCE;
+ break;
+ case 'o':
+ if (*optarg) {
+ options = catopt(options, optarg);
+ if (strstr(optarg, "union"))
+ init_flags |= MNT_UNION;
+ }
+ break;
+ case 'r':
+ init_flags |= MNT_RDONLY;
+ break;
+ case 't':
+ if (vfslist != NULL)
+ errx(errno_or_sysexit(EINVAL, EX_USAGE),
+ "only one -t option may be specified.");
+ vfslist = makevfslist(optarg);
+ vfstype = optarg;
+ break;
+ case 'u':
+ init_flags |= MNT_UPDATE;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'w':
+ init_flags &= ~MNT_RDONLY;
+ break;
+ case 'e':
+ ret_errno = 1;
+ break;
+ case 'P':
+ /* only allowed to specify 1 or 2 as argument here */
+ mount_phase = (int)strtol(optarg, &ep, 10);
+ if ((ep == optarg) || (*ep) ||
+ (mount_phase < MOUNT_PHASE_1) ||
+ (mount_phase > MOUNT_PHASE_2)) {
+ errx(errno_or_sysexit(EINVAL, EX_USAGE),
+ "-P flag requires a valid mount phase number");
+ }
+ break;
+ case 'h':
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ argc -= optind;
+ argv += optind;
+
+#define BADTYPE(type) \
+ (strcmp(type, FSTAB_RO) && \
+ strcmp(type, FSTAB_RW) && strcmp(type, FSTAB_RQ))
+
+// mount boot tasks
+ if (mount_phase != 0) {
+#if TARGET_OS_OSX
+ bootstrap_macos = 1;
+#else /* !TARGET_OS_OSX */
+ if (mount_phase == MOUNT_PHASE_1) {
+ /* mount -vat -nonfs -P 1 */
+ passno = ROOT_PASSNO;
+ } else if (mount_phase == MOUNT_PHASE_2) {
+ /* mount -vat -nonfs -R 2 */
+ passno = NONROOT_PASSNO;
+ }
+ verbose = 1;
+ all = 1;
+ vfslist = makevfslist(NONFS);
+ vfstype = NONFS;
+#endif /* !TARGET_OS_OSX */
+ }
+
+ rval = 0;
+ switch (argc) {
+ case 0:
+ /*
+ * Note - mount should never be called with "-a" on OSX
+ * as per fstab(5) - you may insert entries with UUID=,LABEL=
+ * and mount(8) has no knowledge of these entries
+ */
+ if (all) {
+ int err = 0;
+ long fs_flags = 0;
+
+ if ((setfsent() == 0)) {
+ errx(errno_or_sysexit(errno ? errno : ENXIO, -1),
+ "mount: can't get filesystem checklist");
+ }
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ uint32_t os_env;
+ const char *container_dev = get_boot_container(&os_env);
+ const char *data_vol_dev = get_data_volume();
+ /*
+ * It is a given that the boot container must be present
+ * in order to locate the data volume.
+ *
+ * The data volume is required if it is present in the EDT.
+ * This is always the case when booting the main OS (EDT_OS_ENV_MAIN),
+ * however there are some exceptions.
+ *
+ * When the data volume is required,
+ * we defer checking it is present until the second mount-phase,
+ * when the data volume is actually mounted, in order to allow
+ * MobileObliteration the opportunity to fix the container or fail gracefully.
+ */
+ if (data_vol_dev) {
+ fprintf(stdout, "mount: found boot container: %s, data volume: %s env: %u\n",
+ container_dev, data_vol_dev, os_env);
+ } else if ((os_env == EDT_OS_ENV_MAIN) &&
+ (passno == MOUNT_PHASE_2)) {
+ errx(errno_or_sysexit(errno ? errno : ENXIO, -1),
+ "mount: missing data volume");
+ } else {
+ fprintf(stdout, "mount: data volume missing, but not required in env: %u\n",
+ os_env);
+ }
+#endif
+
+ while ((fs = getfsent()) != NULL) {
+ int ro_mount = !strcmp(fs->fs_type, FSTAB_RO);
+
+ if (BADTYPE(fs->fs_type))
+ continue;
+ if (checkvfsname(fs->fs_vfstype, vfslist))
+ continue;
+ if (hasopt(fs->fs_mntops, "noauto"))
+ continue;
+ if (!strcmp(fs->fs_vfstype, "nfs")) {
+ if (hasopt(fs->fs_mntops, "net"))
+ continue;
+ /* check if already mounted */
+ if (fs->fs_spec == NULL ||
+ fs->fs_file == NULL ||
+ ismounted(fs->fs_spec, fs->fs_file, NULL))
+ continue;
+ }
+
+ /* If this volume is not needed for this pass, skip it. */
+ if (passno && fs->fs_passno != passno)
+ continue;
+
+ /*
+ * Check if already mounted:
+ * 1) If mounted RW this is either an attempt to
+ * downgrade (RW -> RO) or someone else already
+ * mounted this volume as RW.
+ * 2) If mounted RO and not upgrading to RW nothing
+ * nothing need to be done so we should skip this entry.
+ * Skip this entry in both cases (basically only keep going
+ * if this is an acctual mount RW upgrade).
+ */
+ if (ismounted(fs->fs_spec, fs->fs_file, &fs_flags) &&
+ (!(fs_flags & MNT_RDONLY) || ro_mount))
+ continue;
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (!strcmp(fs->fs_spec, RAMDISK_FS_SPEC)) {
+ if (verbose) {
+ fprintf(stdout, "mount: encountered ramdisk\n");
+ }
+ rval = create_mount_ramdisk(fs, init_flags, options);
+ continue;
+ } else if (fs->fs_passno > ROOT_PASSNO &&
+ !strcmp(fs->fs_vfstype, EDTVolumeFSType) &&
+ !strcmp(fs->fs_type, FSTAB_RW)) {
+
+ /*
+ * Perform media keys migration if this is the data volume
+ * of the main OS environment
+ */
+ if (!debug && data_vol_dev &&
+ (os_env == EDT_OS_ENV_MAIN) &&
+ (strcmp(data_vol_dev, fs->fs_spec) == 0)) {
+ kern_return_t mig_err = APFSContainerMigrateMediaKeys(container_dev);
+ if (mig_err) {
+ fprintf(stderr, "mount: failed to migrate Media Keys, error = %x\n", mig_err);
+ } else {
+ fprintf(stdout, "mount: successfully migrated Media Keys\n");
+ }
+ }
+ }
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+
+ if ((err = mountfs(fs->fs_vfstype, fs->fs_spec,
+ fs->fs_file, init_flags, options,
+ fs->fs_mntops)))
+ rval = err;
+ }
+ endfsent();
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ /* Setup bindfs mounts */
+ if (os_env != EDT_OS_ENV_OTHER) {
+ setup_preboot_mounts(passno);
+ }
+ /* Hand the rest of the process over to apfs_boot_util */
+ if (os_variant_has_internal_content(APFS_BUNDLE_ID) &&
+ (mount_phase == MOUNT_PHASE_2)) {
+ bootstrap_apfs(MOUNT_PHASE_2);
+ }
+#endif
+ }
+ else if (bootstrap_macos) {
+#if TARGET_OS_OSX
+ if (mount_phase == MOUNT_PHASE_1) {
+ if (booted_apfs()) {
+ bootstrap_apfs(MOUNT_PHASE_1);
+ } else {
+ fprintf(stdout, "Not booted from APFS, skipping apfs_boot_util\n");
+ exit(0);
+ }
+ } else if (mount_phase == MOUNT_PHASE_2) {
+ /*
+ * We centralize the logic for dealing with a read-only system (ROSV) volume here.
+ * If it is not set up, then default to the old logic of a `mount -uw /`
+ *
+ * Note: We can safely do this boot-task even if we are
+ * already mounted RW (e.g. boot from single user mode).
+ * In that case this will effectively be a no-op.
+ */
+ if (booted_rosv()) {
+ /* Hand the rest of the process over to apfs_boot_util */
+ bootstrap_apfs(MOUNT_PHASE_2);
+ } else {
+ /* upgrade mount "/" read-write */
+ rval = upgrade_mount("/", MNT_UPDATE, options);
+ }
+ }
+#endif /* TARGET_OS_OSX */
+ } else {
+ print_mount(vfslist);
+ }
+ exit(rval);
+ case 1:
+ if (vfslist != NULL)
+ usage();
+
+ if (init_flags & MNT_UPDATE) {
+
+ rval = upgrade_mount (*argv, init_flags, options);
+
+ break;
+ }
+
+ if ((fs = getfsfile(*argv)) == NULL &&
+ (fs = getfsspec(*argv)) == NULL)
+ errx(errno_or_sysexit(errno , -1),
+ "%s: unknown special file or file system.",
+ *argv);
+ if (BADTYPE(fs->fs_type))
+ errx(errno_or_sysexit(EINVAL, EX_DATAERR),
+ "%s has unknown file system type.",
+ *argv);
+ if (!strcmp(fs->fs_vfstype, "nfs")) {
+ if (hasopt(fs->fs_mntops, "net"))
+ errx(errno_or_sysexit(EINVAL, EX_DATAERR),
+ "%s is owned by the automounter.",
+ *argv);
+ if (ismounted(fs->fs_spec, fs->fs_file, NULL))
+ errx(errno_or_sysexit(EALREADY, EX_CONFIG),
+ "%s is already mounted at %s.",
+ fs->fs_spec, fs->fs_file);
+ }
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (!strcmp(fs->fs_spec, RAMDISK_FS_SPEC)) {
+ if (verbose) {
+ fprintf(stdout, "Found a ramdisk entry\n");
+ }
+ rval = create_mount_ramdisk(fs, init_flags, options);
+ break;
+ }
+#endif
+ rval = mountfs(fs->fs_vfstype, fs->fs_spec, fs->fs_file,
+ init_flags, options, fs->fs_mntops);
+ break;
+ case 2:
+ /*
+ * If -t flag has not been specified, and spec contains a ':'
+ * then assume that an NFS filesystem is being specified.
+ */
+ if (vfslist == NULL && strchr(argv[0], ':') != NULL) {
+ vfstype = "nfs";
+ /* check if already mounted */
+ if (ismounted(argv[0], argv[1], NULL))
+ errx(errno_or_sysexit(EALREADY, EX_CONFIG),
+ "%s is already mounted at %s.",
+ argv[0], argv[1]);
+ }
+
+ /* If we have both a devnode and a pathname, and an update mount was requested,
+ * then figure out where the devnode is mounted. We will need to run
+ * an update mount on its path. It wouldn't make sense to do an
+ * update mount on a path other than the one it's already using.
+ *
+ * XXX: Should we implement the same workaround for updating the
+ * root file system at boot time?
+ */
+ if (init_flags & MNT_UPDATE) {
+ if ((mntbuf = getmntpt(*argv)) == NULL)
+ errx(errno_or_sysexit(errno ? errno : ENOENT, -1),
+ "unknown special file or file system %s.",
+ *argv);
+ rval = mountfs(mntbuf->f_fstypename, mntbuf->f_mntfromname,
+ mntbuf->f_mntonname, init_flags, options, 0);
+ }
+ else {
+ /*
+ * If update mount not requested, then go with the vfstype and arguments
+ * specified. If no vfstype specified, then error out.
+ */
+ if (vfstype == NULL) {
+ errx (errno_or_sysexit(EINVAL, EX_USAGE),
+ "You must specify a filesystem type with -t.");
+ }
+ rval = mountfs(vfstype,
+ argv[0], argv[1], init_flags, options, NULL);
+ }
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ exit(rval);
+}
+
+static int
+upgrade_mount (const char *mountpt, int init_flags, char *options) {
+
+ struct statfs *mntbuf = NULL;
+ const char *mntfromname = NULL;
+ struct fstab *fs = NULL;
+
+ if ((mntbuf = getmntpt(mountpt)) == NULL) {
+ errx(errno_or_sysexit(errno, -1),
+ "unknown special file or file system %s.",
+ mountpt);
+ }
+
+ /*
+ * Handle the special case of upgrading the root file
+ * system from read-only to read/write. The root file
+ * system was originally mounted with a "mount from" name
+ * of "root_device". The getfsfile("/") returns non-
+ * NULL at this point, with fs_spec set to the true
+ * path to the root device (regardless of what either the real
+ * or synthesized /etc/fstab contained).
+ */
+ mntfromname = mntbuf->f_mntfromname;
+ if (strchr(mntfromname, '/') == NULL) {
+ fs = getfsfile(mntbuf->f_mntonname);
+ if (fs != NULL)
+ mntfromname = fs->fs_spec;
+ }
+
+ /*
+ * Handle the special case of upgrading a content protected
+ * file system from read-only to read/write. While our caller
+ * is nominally required to pass the protect option to maintain
+ * content protection, the kernel requires it anyway, so just add it
+ * in.
+ */
+ if (mntbuf->f_flags & MNT_CPROTECT) {
+ init_flags |= MNT_CPROTECT;
+ }
+
+
+ /* Do the update mount */
+ return mountfs(mntbuf->f_fstypename, mntfromname,
+ mntbuf->f_mntonname, init_flags, options, 0);
+
+}
+
+int
+hasopt(mntopts, option)
+ const char *mntopts, *option;
+{
+ int negative, found;
+ char *opt, *optbuf;
+
+ if (option[0] == 'n' && option[1] == 'o') {
+ negative = 1;
+ option += 2;
+ } else
+ negative = 0;
+ optbuf = strdup(mntopts);
+ found = 0;
+ for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
+ if (opt[0] == 'n' && opt[1] == 'o') {
+ if (!strcasecmp(opt + 2, option))
+ found = negative;
+ } else if (!strcasecmp(opt, option))
+ found = !negative;
+ }
+ free(optbuf);
+ return (found);
+}
+
+int
+ismounted(const char *fs_spec, const char *fs_file, long *flags)
+{
+ int i, mntsize;
+ struct statfs *mntbuf;
+
+ if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0)
+ err(errno_or_sysexit(errno , -1), "getmntinfo");
+ for (i = 0; i < mntsize; i++) {
+ if (strcmp(mntbuf[i].f_mntfromname, fs_spec))
+ continue;
+ if (strcmp(mntbuf[i].f_mntonname, fs_file))
+ continue;
+ if (flags)
+ *flags = mntbuf[i].f_flags;
+ return 1;
+ }
+ return 0;
+}
+
+#if TARGET_OS_OSX
+static int
+booted_apfs(void) {
+ struct statfs *mntbuf;
+
+ if ((mntbuf = getmntpt("/")) == NULL) {
+ errx(errno_or_sysexit(errno, -1),
+ "failed to lookup root file system");
+ }
+
+ return (strcmp(mntbuf->f_fstypename, "apfs") == 0);
+}
+
+static int
+booted_rosv(void) {
+ /* use sysctl to query kernel */
+ uint32_t is_rosp = 0;
+ size_t rospsize = sizeof(is_rosp);
+ int err = sysctlbyname ("vfs.generic.apfs.rosp", &is_rosp, &rospsize, NULL, NULL);
+
+ if (!err && is_rosp) {
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* TARGET_OS_OSX */
+
+// prints currently mounted filesystems
+void
+print_mount(const char **vfslist)
+{
+ struct statfs *mntbuf;
+ int mntsize;
+
+ if ( (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0 )
+ err(errno_or_sysexit(errno , -1), "getmntinfo");
+ for (int i = 0; i < mntsize; i++) {
+ if ( checkvfsname(mntbuf[i].f_fstypename, vfslist) )
+ continue;
+ prmount(&mntbuf[i]);
+ }
+}
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+int
+verify_executable_file_existence (char *path)
+{
+ return _verify_file_flags(path, F_OK | X_OK);
+}
+
+int
+verify_file_existence (char *path)
+{
+ return _verify_file_flags(path, F_OK);
+}
+
+int
+_verify_file_flags (char *path, int flags)
+{
+
+ if ( access(path, flags) ) {
+ fprintf(stderr, "Failed access check for %s with issue %s\n", path, strerror(errno));
+ return errno;
+ }
+ return 0;
+}
+
+int
+preflight_create_mount_ramdisk (char *mnt_opts, size_t *ramdisk_size, char *template)
+{
+ char *special_ramdisk_params;
+
+ if ( mnt_opts == NULL ) {
+ fprintf(stderr, "No mnt_opts provided to ramdisk preflight.\n");
+ return EINVAL;
+ }
+
+ if ( verify_executable_file_existence(HDIK_PATH) != 0 ) {
+ fprintf(stderr, "Failed to find executable hdik at location %s \n", HDIK_PATH);
+ return ENOENT;
+ }
+
+ special_ramdisk_params = split_ramdisk_params(mnt_opts);
+ if ( special_ramdisk_params == NULL ) {
+ fprintf(stderr, "Ramdisk fstab not in expected format.\n");
+ return EINVAL;
+ }
+
+ if ( ramdisk_size ) {
+ char *ramdisk_size_str = parse_parameter_for_token(special_ramdisk_params, RAMDISK_SIZE_TOK);
+
+ if ( ramdisk_size_str != NULL ) {
+ *ramdisk_size = atoi(ramdisk_size_str);
+ free(ramdisk_size_str);
+ }
+
+ if ( *ramdisk_size == 0 ) {
+ fprintf(stderr, "Unexpected ramdisk size %zu\n", *ramdisk_size);
+ return EINVAL;
+ }
+ }
+
+ if ( template ) {
+ char *template_str = parse_parameter_for_token(special_ramdisk_params, RAMDISK_TPLT_TOK);
+ if (template_str != NULL) {
+ strlcpy(template, template_str, PATH_MAX);
+ free(template_str);
+ }
+
+ if ( template == NULL ) {
+ fprintf(stderr, "Ramdisk template path not found\n");
+ return EINVAL;
+ }
+
+ }
+
+ return 0;
+}
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+
+/*
+ * Helper function that posix_spawn a child process
+ * as defined by command_argv[0].
+ * If `output` is non-null, then the command's stdout will be read
+ * into that buffer.
+ * If `rc` is non-null, then the command's return code will be set
+ * there.
+ * If `signal_no` is non-null, then if the command is signaled, the
+ * signal number will be set there.
+ *
+ *
+ * This function returns
+ * -1, if there's an internal error. errno will be set
+ * 0, if command exit normally with 0 as return code
+ * 1, if command exit abnormally or with a non-zero return code
+ */
+int
+run_command(char **command_argv, char *output, int *rc, int *signal_no)
+{
+ int error = -1;
+ int faulting_errno = 0;
+ int status = -1;
+ int internal_result = -1;
+ pid_t pid;
+ posix_spawn_file_actions_t actions = NULL;
+ int output_pipe[2] = {-1, -1};
+ char *command_out = NULL;
+ FILE *stream = NULL;
+
+ if ( !command_argv ) {
+ fprintf(stderr, "command_argv is NULL\n");
+ errno = EINVAL;
+ goto done;
+ }
+
+ if ( pipe(output_pipe) ) {
+ fprintf(stderr, "Failed to create pipe for command output: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ if ( (internal_result = posix_spawn_file_actions_init(&actions)) != 0 ) {
+ errno = internal_result;
+ fprintf(stderr, "posix_spawn_file_actions_init failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ if ( (internal_result = posix_spawn_file_actions_addclose(&actions, output_pipe[0])) != 0 ) {
+ errno = internal_result;
+ fprintf(stderr, "posix_spawn_file_actions_addclose output_pipe[0] failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ if ( (internal_result = posix_spawn_file_actions_adddup2(&actions, output_pipe[1], STDOUT_FILENO)) != 0 ) {
+ errno = internal_result;
+ fprintf(stderr, "posix_spawn_file_actions_adddup2 output_pipe[1] failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ if ( (internal_result = posix_spawn_file_actions_addclose(&actions, output_pipe[1])) != 0 ) {
+ errno = internal_result;
+ fprintf(stderr, "posix_spawn_file_actions_addclose output_pipe[1] failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ if ( verbose ) {
+ fprintf(stdout, "Executing command: ");
+ for (char **command_segment = command_argv; *command_segment; command_segment++) {
+ fprintf(stdout, "%s ", *command_segment);
+ }
+ fprintf(stdout, "\n");
+ }
+
+ if ( (internal_result = posix_spawn(&pid, command_argv[0], &actions, NULL, command_argv, environ)) != 0 ) {
+ errno = internal_result;
+ fprintf(stderr, "posix_spawn failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ // Close out our side of the pipe
+ close(output_pipe[1]);
+ output_pipe[1] = -1;
+
+ // If caller specified the output buffer, we'll use that
+ // Otherwise allocate a buffer and capture the output ourselves for verbose logging
+ if ( output != NULL ) {
+ command_out = output;
+ } else {
+ command_out = calloc(COMMAND_OUTPUT_MAX, sizeof(char));
+ if (!command_out) {
+ fprintf(stderr, "calloc failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+ }
+
+ stream = fdopen(output_pipe[0], "r");
+ if ( !stream ) {
+ fprintf(stderr, "fdopen failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ size_t length;
+ size_t count = 0;
+ char *line;
+ while ( (line = fgetln(stream, &length)) && (count < COMMAND_OUTPUT_MAX - length - 1) ) {
+ strncat(command_out, line, length);
+ count += length;
+ }
+
+ if ( ferror(stream) ) {
+ fprintf(stderr, "fgetln failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ if ( fclose(stream) ) {
+ fprintf(stderr, "fclose failed: %d (%s)\n", errno, strerror(errno));
+ stream = NULL;
+ goto done;
+ }
+ stream = NULL;
+ close(output_pipe[0]);
+ output_pipe[0] = -1;
+
+ while ( waitpid(pid, &status, 0) < 0 ) {
+ if (errno == EINTR) {
+ continue;
+ }
+ fprintf(stderr, "waitpid failed: %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ if ( verbose ) {
+ fprintf(stdout, "Command output:\n%s\n", command_out);
+ }
+
+ if ( WIFEXITED(status) ) {
+ int exit_status = WEXITSTATUS(status);
+ if (rc) *rc = exit_status;
+ if (signal_no) *signal_no = 0;
+
+ if (exit_status != 0) {
+ error = 1;
+ fprintf(stderr, "Command failed: %d\n", exit_status);
+ goto done;
+ }
+ }
+
+ if ( WIFSIGNALED(status) ) {
+ if (rc) *rc = 0;
+ if (signal_no) *signal_no = WTERMSIG(status);
+
+ error = 1;
+ fprintf(stderr, "Command signaled: %d\n", WTERMSIG(status));
+ goto done;
+ }
+
+ error = 0;
+done:
+ // we don't care much about the errno set by the clean up routine
+ // so save the errno here and return to caller
+ faulting_errno = errno;
+
+ if ( actions ) {
+ posix_spawn_file_actions_destroy(&actions);
+ }
+
+ if ( stream ) {
+ fclose(stream);
+ }
+
+ if ( output_pipe[0] >= 0 ) {
+ close(output_pipe[0]);
+ }
+
+ if ( output_pipe[1] >= 0 ) {
+ close(output_pipe[1]);
+ }
+
+ if ( !output && command_out ) {
+ free(command_out);
+ }
+
+ errno = faulting_errno;
+ return error;
+}
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+// Helper function that truncates whitespaces
+void
+truncate_whitespace(char* str)
+{
+ size_t idx = strcspn(str, " \n");
+ if ( idx != 0 ) {
+ str[idx] = '\0';
+ }
+}
+
+// Creates a new unmounted ramdisk of size device_size
+int
+attach_device(size_t device_size , char* deviceOut)
+{
+ int return_val = -1;
+ char ram_define [PATH_MAX];
+ snprintf(ram_define, sizeof(ram_define), "ram://%zu", device_size);
+
+ char *command[4] = { HDIK_PATH, "-nomount", ram_define, NULL };
+
+ int status = run_command(command, deviceOut, &return_val, NULL);
+ if ( status == 1 ) {
+ fprintf(stderr, "Failed to create ramdisk. HDIK returned %d.\n", return_val);
+ exit(errno_or_sysexit(errno, -1));
+ } else if (status != 0) {
+ fprintf(stderr, "Failed to execute command %s\n", command[0]);
+ exit(errno_or_sysexit(errno, -1));
+ }
+
+ truncate_whitespace(deviceOut);
+ return return_val;
+}
+
+// Creates the partition table directly through MediaKit.
+int
+create_partition_table(size_t partition_size, char *device)
+{
+
+ MKStatus err = -1;
+ MKMediaRef gpt_ref = NULL;
+ CFMutableArrayRef schemes = NULL;
+ CFMutableArrayRef partitionArray = NULL;
+ CFDictionaryRef partition = NULL;
+ CFMutableDictionaryRef options = NULL;
+ CFMutableDictionaryRef layout = NULL;
+ CFMutableDictionaryRef media = NULL;
+ CFMutableDictionaryRef map = NULL;
+
+ layout = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ options = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+ if (!layout || !options) {
+ fprintf(stderr, "Failed to create necessary CFDictionaries\n");
+ err = errno;
+ goto done;
+ }
+
+ CFDictionarySetValue(options, kMKMediaPropertyWritableKey, kCFBooleanTrue);
+
+ gpt_ref = MKMediaCreateWithPath(kCFAllocatorDefault, device, options, &err);
+ CFRelease(options);
+
+ if (gpt_ref) {
+ MKStatus mediaErr = 0;
+ partition = MKCFBuildPartition(PMGPTTYPE, apple_apfs, CFSTR(EDTVolumeFSType), CFSTR(RAMDISK_FS_SPEC), 0, RAMDISK_BLCK_OFFSET, &mediaErr, NULL);
+
+ if (!partition) {
+ fprintf(stderr, "Failed to create partition with err %d\n", mediaErr);
+ err = mediaErr;
+ goto done;
+ }
+
+ partitionArray = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ if (!partitionArray) {
+ fprintf(stderr, "Failed to create partitionArray\n");
+ err = errno;
+ CFRelease(partition);
+ goto done;
+ }
+
+ CFArrayAppendValue(partitionArray, partition);
+ CFRelease(partition);
+
+ CFDictionaryAddValue(layout, CFSTR(MK_PARTITIONS_KEY), partitionArray);
+ CFRelease(partitionArray);
+
+
+ media = MKCFCreateMedia(&schemes, &mediaErr);
+
+ if (!media) {
+ fprintf(stderr, "Failed to create Schemes with error %d\n", mediaErr);
+ err = mediaErr;
+ goto done;
+ }
+
+ map = MKCFCreateMap(PMGPTTYPE, schemes, layout, NULL, NULL, NULL, NULL, NULL, gpt_ref, &mediaErr);
+ if (!map) {
+ fprintf(stderr, "Failed to create map with error %d\n", mediaErr);
+ err = mediaErr;
+ goto done;
+ }
+
+ err = MKCFWriteMedia(media, layout, NULL, NULL, gpt_ref);
+ if (err) {
+ fprintf(stderr, "Failed to WriteMedia with error %d\n", err);
+ goto done;
+ }
+
+ } else {
+ fprintf(stderr, "Failed to create gpt_ref with error %d\n", err);
+ goto done;
+ }
+
+ if (verbose) {
+ fprintf(stderr, "Releasing MediaKit objects\n");
+ }
+ err = 0;
+
+done:
+ if (media) {
+ MKCFDisposeMedia(media);
+ }
+
+ if (layout) {
+ CFRelease(layout);
+ }
+
+ if (gpt_ref) {
+ CFRelease(gpt_ref);
+ }
+
+ return err;
+}
+
+// Triggers newfs_apfs for the target device
+int
+construct_apfs_volume(char *mounted_device_name)
+{
+ int return_val = -1;
+ int status = -1;
+ char *command[5] = { "/sbin/newfs_apfs", "-v", "Var", mounted_device_name, NULL };
+
+ status = run_command(command, NULL, &return_val, NULL);
+ if ( status >= 0 ) {
+ return return_val;
+ } else {
+ fprintf(stderr, "Failed to execute command %s\n", command[0]);
+ errno_or_sysexit(errno, -1);
+ }
+
+ // shouldn't reach here. This is to satisfy the compiler
+ return -1;
+}
+
+// unmounts device at location
+int
+unmount_location(char *mount_point)
+{
+ int return_val = -1;
+ int status = -1;
+ char *command[4] = { "/sbin/umount", "-f", mount_point, NULL };
+
+ status = run_command(command, NULL, &return_val, NULL);
+ if ( status >= 0 ) {
+ return return_val;
+ } else {
+ fprintf(stderr, "Failed to execute command %s\n", command[0]);
+ return errno_or_sysexit(errno, -1);
+ }
+}
+
+// The mnt_opts for fstab are standard across the different
+// mount_fs implementations. To create and mount an ephemeral
+// filesystem, it is necessary to provide additional non-standard
+// values in filesystem definition - mainly size and location of
+// the seed files.
+// The fstab definition for a ramdisk fs requires two new parameters:
+// 'size=%zu' and 'template=%s'. To keep the fstab structure
+// consistent with that of other filesystem types, these
+// parameters are appended at the end of the mnt_opts string.
+// It is necessary to split the mnt_opts into two strings, the
+// standard mountfs parameters that are used in the fs-specifnc mount
+// and the ramdisk definition parameters.
+char*
+split_ramdisk_params(char *opts)
+{
+ char* opt = NULL;
+ char* target_str = NULL;
+ char* size_tok = RAMDISK_SIZE_TOK;
+ char* tplt_tok = RAMDISK_TPLT_TOK;
+ char* optbuf = NULL;
+ size_t size_tok_len = strlen(size_tok);
+ size_t tplt_tok_len = strlen(tplt_tok);
+
+ optbuf = strdup(opts);
+ for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
+ size_t opt_len = strlen(opt);
+ if ( (opt_len > size_tok_len && !strncmp(size_tok, opt, size_tok_len) ) ||
+ (opt_len > tplt_tok_len && !strncmp(tplt_tok, opt, tplt_tok_len) ) ) {
+ size_t start_index = opt - optbuf;
+ target_str = opts + start_index;
+ opts[start_index - 1 ] = '\0'; // Break original into two strings.
+ break;
+ }
+ }
+ free(optbuf);
+ return target_str;
+}
+
+// returns string for the parameter after the '=' in the search_string
+// part of the special ramdisk parameters
+char*
+parse_parameter_for_token(char * opts, char * search_string)
+{
+ char *return_str = NULL;
+ char *tmp_str = NULL;
+ char *target_str = strstr(opts, search_string);
+ size_t len = strlen(search_string);
+
+ if ( target_str && strlen(target_str) > len ) {
+ tmp_str = target_str + len;
+ size_t idx = strcspn(tmp_str, ",\0");
+ if ( idx != 0 && (idx < MAXPATHLEN) ) {
+ return_str = calloc(1, idx+1); //for null terminator
+ strncpy(return_str, tmp_str, idx);
+ }
+ }
+ return return_str;
+}
+
+
+static int _copyfile_status(int what, int stage, copyfile_state_t state, const char * src, const char * dst, void * ctx) {
+
+ if (verbose && stage == COPYFILE_START) {
+ if (what == COPYFILE_RECURSE_FILE) {
+ fprintf(stderr, "Copying %s -> %s\n", src, dst);
+ } else if (what == COPYFILE_RECURSE_DIR) {
+ fprintf(stderr, "Creating %s/\n", dst);
+ }
+ }
+
+ return COPYFILE_CONTINUE;
+}
+
+
+// returns 0 upon success and a valid sysexit or errno code upon failure
+int
+create_mount_ramdisk(struct fstab *fs, int init_flags, char *options)
+{
+ int default_flags = init_flags;
+ int mount_return = 0;
+ char ramdisk_partition [PATH_MAX] = { 0 };
+ char ramdisk_volume [PATH_MAX] = { 0 };
+ char ramdisk_container [PATH_MAX] = { 0 };
+ char seed_location [PATH_MAX] = { 0 };
+ char *mnt_point = RAMDISK_TMP_MOUNT; // intermediate
+ char *target_dir = fs->fs_file; // target
+ size_t ram_size = 0;
+
+ if ( verify_file_existence(mnt_point) != 0 ) {
+ if (verbose) {
+ fprintf(stderr, "Default mount %s is not available. Using backup %s.\n", mnt_point, RAMDISK_BCK_MOUNT);
+ }
+ mnt_point = RAMDISK_BCK_MOUNT;
+ if ( verify_file_existence(mnt_point) != 0 ) {
+ fprintf(stderr, "Mountpoints not available. Exiting.\n");
+ return ENOENT;
+ }
+ }
+
+ if ( preflight_create_mount_ramdisk(fs->fs_mntops, &ram_size, seed_location) != 0 ) {
+ fprintf(stderr, "Failed ramdisk preflight. Exiting.\n");
+ return EINVAL;
+ }
+
+ if ( verbose ) {
+ fprintf(stdout, "Attaching device of size %zu\n", ram_size);
+ }
+
+ if( attach_device(ram_size, ramdisk_partition) != 0 ){
+ fprintf(stderr, "Failed to attach the ramdisk.\n");
+ exit(errno_or_sysexit(ECHILD, -1));
+ }
+
+ if ( verbose ) {
+ fprintf(stdout, "Creating partition table for device %s \n", ramdisk_partition);
+ }
+
+ if ( create_partition_table(ram_size, ramdisk_partition) !=0 ) {
+ fprintf(stderr, "Failed to create partition table.\n");
+ exit(errno_or_sysexit(ECHILD, -1));
+ }
+
+ snprintf(ramdisk_container, sizeof(ramdisk_container), "%ss1", ramdisk_partition);
+
+ if ( verbose ) {
+ fprintf(stdout, "Creating apfs volume on partition %s\n", ramdisk_container);
+ }
+
+ if ( construct_apfs_volume(ramdisk_container) != 0 ) {
+ fprintf(stderr, "Failed to construct the apfs volume on the ramdisk.\n");
+ exit(errno_or_sysexit(ECHILD, -1));
+ }
+
+ snprintf(ramdisk_volume, sizeof(ramdisk_volume), "%ss1", ramdisk_container);
+
+ if ( verify_file_existence(ramdisk_volume) != 0 ) {
+ fprintf(stderr, "Failed to verify %s with issue %s\n", ramdisk_volume, strerror(errno));
+ exit(errno_or_sysexit(errno, -1));
+ }
+
+ // Mount volume to RAMDISK_TMP_MOUNT
+ if ( verbose ) {
+ fprintf(stdout, "Mounting to tmp location %s\n", mnt_point);
+ }
+
+ mount_return = mountfs(EDTVolumeFSType, ramdisk_volume, mnt_point, default_flags, NULL, fs->fs_mntops);
+ if ( mount_return > 0 ) {
+ fprintf(stderr, "Initial mount to %s failed with %d\n", mnt_point, mount_return);
+ exit(errno_or_sysexit(errno, -1));
+ }
+
+ // ditto contents of RAMDISK_TMP_MOUNT to /private/var
+ copyfile_state_t state = copyfile_state_alloc();
+ copyfile_state_set(state, COPYFILE_STATE_STATUS_CB, _copyfile_status);
+ if( copyfile(seed_location, mnt_point, state, COPYFILE_ALL | COPYFILE_RECURSIVE) < 0 ) {
+ fprintf(stderr, "Failed to copy contents from %s to %s with error: %s\n", seed_location, mnt_point, strerror(errno));
+ exit(errno_or_sysexit(errno, -1));
+ }
+ copyfile_state_free(state);
+
+ // unount RAMDISK_TMP_MOUNT
+ if( unmount_location(mnt_point) != 0 ){
+ fprintf(stderr, "Failed to unmount device mounted at %s.\n", mnt_point);
+ exit(errno_or_sysexit(ECHILD, -1));
+ }
+
+ if( verbose ) {
+ fprintf(stdout, "Mounting apfs volume %s to %s\n", ramdisk_volume, target_dir);
+ }
+
+ mount_return = mountfs(EDTVolumeFSType, ramdisk_volume, target_dir, default_flags, options, fs->fs_mntops);
+ if ( mount_return > 0 ) {
+ fprintf(stderr, "Followup mount to %s failed with %d\n", target_dir, mount_return);
+ exit(errno_or_sysexit(errno, -1));
+ }
+
+ // Verify contents in stdout
+ if ( verbose ) {
+ print_mount(NULL);
+ }
+
+ return mount_return;
+}
+#endif // (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+
+// returns 0 upon success and a valid sysexit or errno code upon failure
+int
+mountfs(const char *vfstype, const char *fs_spec, const char *fs_file, int flags,
+ const char *options, const char *mntopts)
+{
+ /* List of directories containing mount_xxx subcommands. */
+ static const char *edirs[] = {
+ _PATH_SBIN,
+ _PATH_USRSBIN,
+ NULL
+ };
+ static const char *bdirs[] = {
+ _PATH_FSBNDL,
+ _PATH_USRFSBNDL,
+ NULL
+ };
+ const char *argv[100], **edir, **bdir;
+ struct statfs sf;
+ pid_t pid;
+ int argc, i, status;
+ char *optbuf, execname[MAXPATHLEN + 1], mntpath[MAXPATHLEN];
+
+ if (realpath(fs_file, mntpath) == NULL) {
+ /* Attempt to create missing mountpoints on Data volume */
+ if ((passno == NONROOT_PASSNO) &&
+ (!strncmp(mntpath, PLATFORM_DATA_VOLUME_MOUNT_POINT,
+ MIN(strlen(mntpath), strlen(PLATFORM_DATA_VOLUME_MOUNT_POINT))))) {
+ if (mkdir(mntpath, S_IRWXU)) {
+ warn("mkdir %s", mntpath);
+ return (errno_or_sysexit(errno , -1));
+ }
+ } else {
+ warn("realpath %s", mntpath);
+ return (errno_or_sysexit(errno , -1));
+ }
+ }
+
+ fs_file = mntpath;
+
+ if (mntopts == NULL)
+ mntopts = "";
+ if (options == NULL) {
+ if (*mntopts == '\0') {
+ options = "";
+ } else {
+ options = mntopts;
+ mntopts = "";
+ }
+ }
+ optbuf = catopt(strdup(mntopts), options);
+
+ if ((strcmp(fs_file, "/") == 0) && !(flags & MNT_UNION))
+ flags |= MNT_UPDATE;
+ if (flags & MNT_FORCE)
+ optbuf = catopt(optbuf, "force");
+ if (flags & MNT_RDONLY)
+ optbuf = catopt(optbuf, "ro");
+ if (flags & MNT_UPDATE)
+ optbuf = catopt(optbuf, "update");
+ if (flags & MNT_DONTBROWSE)
+ optbuf = catopt(optbuf, "nobrowse");
+ if (flags & MNT_CPROTECT)
+ optbuf = catopt(optbuf, "protect");
+
+
+ argc = 0;
+ argv[argc++] = vfstype;
+ mangle(optbuf, &argc, argv);
+ argv[argc++] = fs_spec;
+ argv[argc++] = fs_file;
+ argv[argc] = NULL;
+
+ if (debug) {
+ (void)printf("exec: mount_%s", vfstype);
+ for (i = 1; i < argc; i++)
+ (void)printf(" %s", argv[i]);
+ (void)printf("\n");
+ return (0);
+ }
+
+ switch (pid = fork()) {
+ case -1: /* Error. */
+ warn("fork");
+ free(optbuf);
+ return (errno_or_sysexit(errno, EX_OSERR));
+ case 0: /* Child. */
+ /* Go find an executable. */
+ edir = edirs;
+ do {
+ (void)snprintf(execname, sizeof(execname),
+ "%s/mount_%s", *edir, vfstype);
+
+ argv[0] = execname;
+ execv(execname, (char * const *)argv);
+ if (errno != ENOENT)
+ warn("exec %s for %s", execname, fs_file);
+ } while (*++edir != NULL);
+
+ bdir = bdirs;
+ do {
+ /* Special case file system bundle executable path */
+ (void)snprintf(execname, sizeof(execname),
+ "%s/%s.fs/%s/mount_%s", *bdir,
+ vfstype, _PATH_FSBNDLBIN, vfstype);
+
+ argv[0] = execname;
+ execv(execname, (char * const *)argv);
+ if (errno != ENOENT)
+ warn("exec %s for %s", execname, fs_file);
+ } while (*++bdir != NULL);
+
+ if (errno == ENOENT) {
+ warn("exec %s for %s", execname, fs_file);
+ return (errno_or_sysexit(errno, EX_OSFILE));
+ }
+ exit(errno_or_sysexit(errno , -1));
+ /* NOTREACHED */
+ default: /* Parent. */
+ free(optbuf);
+
+ if (waitpid(pid, &status, 0) < 0) {
+ warn("waitpid");
+ return (errno_or_sysexit(errno , -1));
+ }
+
+ if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) != 0) {
+ warnx("%s failed with %d", fs_file, WEXITSTATUS(status));
+ return (errno_or_sysexit(EINTR, WEXITSTATUS(status)));
+ }
+ } else if (WIFSIGNALED(status)) {
+ warnx("%s: %s", fs_file, sys_siglist[WTERMSIG(status)]);
+ return (errno_or_sysexit(EINTR, EX_UNAVAILABLE));
+ }
+
+ if (verbose) {
+ if (statfs(fs_file, &sf) < 0) {
+ warn("statfs %s", fs_file);
+ return (errno_or_sysexit(errno , -1));
+ }
+ prmount(&sf);
+ }
+ break;
+ }
+
+ return (EX_OK);
+}
+
+static bool
+is_sealed(const char *mntpt)
+{
+ struct vol_attr {
+ uint32_t len;
+ vol_capabilities_attr_t vol_cap;
+ } vol_attrs = {};
+
+ struct attrlist vol_attr_list = {
+ .bitmapcount = ATTR_BIT_MAP_COUNT,
+ .volattr = ATTR_VOL_CAPABILITIES
+ };
+
+ if (!getattrlist(mntpt, &vol_attr_list, &vol_attrs, sizeof(vol_attrs), 0) &&
+ vol_attrs.vol_cap.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_SEALED) {
+ return (vol_attrs.vol_cap.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_SEALED);
+ }
+ return false;
+}
+
+void
+prmount(sfp)
+ struct statfs *sfp;
+{
+ int flags;
+ mountopt_t *o;
+ struct passwd *pw;
+
+ (void)printf("%s on %s (%s", sfp->f_mntfromname, sfp->f_mntonname,
+ sfp->f_fstypename);
+
+ if (is_sealed(sfp->f_mntonname))
+ (void)printf(", sealed");
+ flags = sfp->f_flags & MNT_VISFLAGMASK;
+ for (o = optnames; flags && o->o_opt; o++)
+ if (flags & o->o_opt) {
+ (void)printf(", %s", o->o_name);
+ flags &= ~o->o_opt;
+ }
+ if (sfp->f_owner) {
+ (void)printf(", mounted by ");
+ if ((pw = getpwuid(sfp->f_owner)) != NULL)
+ (void)printf("%s", pw->pw_name);
+ else
+ (void)printf("%d", sfp->f_owner);
+ }
+ (void)printf(")\n");
+}
+
+struct statfs *
+getmntpt(name)
+ const char *name;
+{
+ struct statfs *mntbuf;
+ int i, mntsize;
+
+ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+ for (i = 0; i < mntsize; i++) {
+ if (strcmp(mntbuf[i].f_mntfromname, name) == 0 ||
+ strcmp(mntbuf[i].f_mntonname, name) == 0)
+ return (&mntbuf[i]);
+ }
+ return (NULL);
+}
+
+char *
+catopt(s0, s1)
+ char *s0;
+ const char *s1;
+{
+ size_t i;
+ char *cp;
+
+ if (s0 && *s0) {
+ i = strlen(s0) + strlen(s1) + 1 + 1;
+ if ((cp = malloc(i)) == NULL)
+ err(errno_or_sysexit(errno, EX_TEMPFAIL),
+ "failed to allocate memory for arguments");
+ (void)snprintf(cp, i, "%s,%s", s0, s1);
+ } else
+ cp = strdup(s1);
+
+ if (s0)
+ free(s0);
+ return (cp);
+}
+
+void
+mangle(options, argcp, argv)
+ char *options;
+ int *argcp;
+ const char **argv;
+{
+ char *p, *s;
+ int argc;
+
+ argc = *argcp;
+ for (s = options; (p = strsep(&s, ",")) != NULL;)
+ if (*p != '\0') {
+ if (*p == '-') {
+ argv[argc++] = p;
+ p = strchr(p, '=');
+ if (p) {
+ *p = '\0';
+ argv[argc++] = p+1;
+ }
+ } else {
+ argv[argc++] = "-o";
+ argv[argc++] = p;
+ }
+ }
+
+ *argcp = argc;
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr,
+ "usage: mount %s %s\n mount %s\n mount %s\n",
+ "[-dfruvw] [-o options] [-t external_type]",
+ "special mount_point",
+ "[-adfruvw] [-t external_type]",
+ "[-dfruvw] special | mount_point");
+ exit(errno_or_sysexit(EINVAL, EX_USAGE));
+}
diff --git a/diskdev_cmds/mount.tproj/mount.entitlements b/diskdev_cmds/mount.tproj/mount.entitlements
new file mode 100644
index 0000000..c56a334
--- /dev/null
+++ b/diskdev_cmds/mount.tproj/mount.entitlements
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.private.bindfs-allow</key>
+ <true/>
+ <key>com.apple.private.security.disk-device-access</key>
+ <true/>
+ <key>com.apple.security.iokit-user-client-class</key>
+ <string>AppleAPFSUserClient</string>
+</dict>
+</plist>
diff --git a/diskdev_cmds/mount.tproj/pathnames.h b/diskdev_cmds/mount.tproj/pathnames.h
new file mode 100644
index 0000000..009be31
--- /dev/null
+++ b/diskdev_cmds/mount.tproj/pathnames.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.2 (Berkeley) 3/27/94
+ */
+
+#define _PATH_SBIN "/sbin"
+#define _PATH_USRSBIN "/usr/sbin"
+#define _PATH_FSBNDL "/System/Library/Filesystems"
+#define _PATH_USRFSBNDL "/Library/Filesystems"
+#define _PATH_FSBNDLBIN "Contents/Resources"
+#define _PATH_MOUNTDPID "/var/run/mountd.pid"
diff --git a/diskdev_cmds/mount_devfs.tproj/mount_devfs.c b/diskdev_cmds/mount_devfs.tproj/mount_devfs.c
new file mode 100644
index 0000000..f0285b2
--- /dev/null
+++ b/diskdev_cmds/mount_devfs.tproj/mount_devfs.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1990, 1992 Jan-Simon Pendry
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mntopts.h>
+
+struct mntopt mopts[] = {
+ MOPT_STDOPTS,
+ { NULL }
+};
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch, mntflags;
+ char dir[MAXPATHLEN];
+
+ mntflags = 0;
+ while ((ch = getopt(argc, argv, "o:")) != EOF)
+ switch (ch) {
+ case 'o':
+ getmntopts(optarg, mopts, &mntflags, 0);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ if (realpath(argv[1], dir) == NULL)
+ err(1, "realpath %s", dir);
+
+ if (mount("devfs", dir, mntflags, NULL))
+ err(1, NULL);
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: mount_devfs [-o options] devfs mount_point\n");
+ exit(1);
+}
diff --git a/diskdev_cmds/mount_fdesc.tproj/mount_fdesc.8 b/diskdev_cmds/mount_fdesc.tproj/mount_fdesc.8
new file mode 100644
index 0000000..a61c952
--- /dev/null
+++ b/diskdev_cmds/mount_fdesc.tproj/mount_fdesc.8
@@ -0,0 +1,171 @@
+.\"
+.\" Copyright (c) 1992, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software donated to Berkeley by
+.\" Jan-Simon Pendry.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mount_fdesc.8 8.2 (Berkeley) 3/27/94
+.\"
+.\"
+.Dd March 27, 1994
+.Dt MOUNT_FDESC 8
+.Os BSD 4.4
+.Sh NAME
+.Nm mount_fdesc
+.Nd mount the file-descriptor file system
+.Sh SYNOPSIS
+.Nm mount_fdesc
+.Op Fl o Ar options
+.Ar fdesc
+.Ar mount_point
+.Sh DESCRIPTION
+The
+.Nm mount_fdesc
+command attaches an instance of the per-process file descriptor
+namespace to the global filesystem namespace.
+The conventional mount point is
+.Pa /dev
+and the filesystem should be union mounted in order to augment,
+rather than replace, the existing entries in
+.Pa /dev .
+This command is normally executed by
+.Xr mount 8
+at boot time.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl o
+Options are specified with a
+.Fl o
+flag followed by a comma separated string of options.
+See the
+.Xr mount 8
+man page for possible options and their meanings.
+.El
+.Pp
+The contents of the mount point are
+.Pa fd ,
+.Pa stderr ,
+.Pa stdin ,
+.Pa stdout
+and
+.Pa tty .
+.Pp
+.Pa fd
+is a directory whose contents
+appear as a list of numbered files
+which correspond to the open files of the process reading the
+directory.
+The files
+.Pa /dev/fd/0
+through
+.Pa /dev/fd/#
+refer to file descriptors which can be accessed through the file
+system.
+If the file descriptor is open and the mode the file is being opened
+with is a subset of the mode of the existing descriptor, the call:
+.Bd -literal -offset indent
+fd = open("/dev/fd/0", mode);
+.Ed
+.Pp
+and the call:
+.Bd -literal -offset indent
+fd = fcntl(0, F_DUPFD, 0);
+.Ed
+.Pp
+are equivalent.
+.Pp
+The files
+.Pa /dev/stdin ,
+.Pa /dev/stdout
+and
+.Pa /dev/stderr
+appear as symlinks to the relevant entry in the
+.Pa /dev/fd
+sub-directory.
+Opening them is equivalent to the following calls:
+.Bd -literal -offset indent
+fd = fcntl(STDIN_FILENO, F_DUPFD, 0);
+fd = fcntl(STDOUT_FILENO, F_DUPFD, 0);
+fd = fcntl(STDERR_FILENO, F_DUPFD, 0);
+.Ed
+.Pp
+Flags to the
+.Xr open 2
+call other than
+.Dv O_RDONLY ,
+.Dv O_WRONLY
+and
+.Dv O_RDWR
+are ignored.
+.Pp
+The
+.Pa /dev/tty
+entry is an indirect reference to the current process's controlling terminal.
+It appears as a named pipe (FIFO) but behaves in exactly the same way as
+the real controlling terminal device.
+.Sh FILES
+.Bl -tag -width /dev/stderr -compact
+.It Pa /dev/fd/#
+.It Pa /dev/stdin
+.It Pa /dev/stdout
+.It Pa /dev/stderr
+.It Pa /dev/tty
+.El
+.Sh SEE ALSO
+.Xr mount 2 ,
+.Xr unmount 2 ,
+.Xr tty 4 ,
+.Xr fstab 5 ,
+.Xr mount 8
+.Sh CAVEATS
+No
+.Pa .
+and
+.Pa ..
+entries appear when listing the contents of the
+.Pa /dev/fd
+directory.
+This makes sense in the context of this filesystem, but is inconsistent
+with usual filesystem conventions.
+However, it is still possible to refer to both
+.Pa .
+and
+.Pa ..
+in a pathname.
+.Pp
+This filesystem may not be NFS-exported.
+.Sh HISTORY
+The
+.Nm mount_fdesc
+utility first appeared in 4.4BSD.
diff --git a/diskdev_cmds/mount_fdesc.tproj/mount_fdesc.c b/diskdev_cmds/mount_fdesc.tproj/mount_fdesc.c
new file mode 100644
index 0000000..f49df63
--- /dev/null
+++ b/diskdev_cmds/mount_fdesc.tproj/mount_fdesc.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1990, 1992 Jan-Simon Pendry
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <mntopts.h>
+
+struct mntopt mopts[] = {
+ MOPT_STDOPTS,
+ { NULL }
+};
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch, mntflags;
+ char dir[MAXPATHLEN];
+ struct statfs fs;
+
+ mntflags = 0;
+ while ((ch = getopt(argc, argv, "o:")) != EOF)
+ switch (ch) {
+ case 'o':
+ getmntopts(optarg, mopts, &mntflags, 0);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2)
+ usage();
+
+ if (realpath(argv[1], dir) == NULL)
+ err(1, "realpath %s", dir);
+
+ /*
+ * fdesc mount happens automatically now, so no need to do anything.
+ * Just return indicating success.
+ */
+ if (statfs(dir, &fs) == -1) {
+ err(1, "mount point %s", dir);
+ }
+ if (strcmp(fs.f_fstypename, "devfs") != 0) {
+ errx(1, "%s is not devfs", dir);
+ }
+ return 0;
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: mount_fdesc [-o options] fdesc mount_point\n");
+ exit(1);
+}
diff --git a/diskdev_cmds/mount_flags_dir/mount_flags.c b/diskdev_cmds/mount_flags_dir/mount_flags.c
new file mode 100644
index 0000000..3707290
--- /dev/null
+++ b/diskdev_cmds/mount_flags_dir/mount_flags.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1980, 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/mount.h>
+#include <sys/param.h>
+#include "mount_flags.h"
+
+/*
+ * This file is intended to be compiled into whichever projects need
+ * to access the MNT_* bit => string mappings. It could be made into a
+ * library but that's unnecessary at present.
+ */
+
+const mountopt_t optnames[] = {
+ { MNT_ASYNC, "asynchronous", "async", },
+ { MNT_EXPORTED, "NFS exported", NULL, },
+ { MNT_LOCAL, "local", NULL, },
+ { MNT_NODEV, "nodev", "nodev", },
+ { MNT_NOEXEC, "noexec", "noexec", },
+ { MNT_NOSUID, "nosuid", "nosuid", },
+ { MNT_QUOTA, "with quotas", NULL, },
+ { MNT_RDONLY, "read-only", "rdonly", },
+ { MNT_SYNCHRONOUS, "synchronous", "sync", },
+ { MNT_UNION, "union", "union", },
+ { MNT_AUTOMOUNTED, "automounted", NULL, },
+ { MNT_JOURNALED, "journaled", NULL, },
+ { MNT_DEFWRITE, "defwrite", NULL, },
+ { MNT_IGNORE_OWNERSHIP, "noowners", "noowners", },
+ { MNT_NOATIME, "noatime", "noatime", },
+ { MNT_STRICTATIME, "strictatime", "strictatime", },
+ { MNT_QUARANTINE, "quarantine", "quarantine", },
+ { MNT_DONTBROWSE, "nobrowse", "nobrowse", },
+ { MNT_CPROTECT, "protect", "protect", },
+ { 0, NULL, NULL, }, // must be last
+};
+
diff --git a/diskdev_cmds/mount_flags_dir/mount_flags.h b/diskdev_cmds/mount_flags_dir/mount_flags.h
new file mode 100644
index 0000000..cf8b190
--- /dev/null
+++ b/diskdev_cmds/mount_flags_dir/mount_flags.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1980, 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __MOUNT_FLAGS__
+#define __MOUNT_FLAGS__
+
+typedef struct mountopt {
+ int o_opt;
+ const char *o_name;
+ const char *o_cmd;
+} mountopt_t;
+
+#endif
+
diff --git a/diskdev_cmds/quota.tproj/quota.1 b/diskdev_cmds/quota.tproj/quota.1
new file mode 100644
index 0000000..57243c9
--- /dev/null
+++ b/diskdev_cmds/quota.tproj/quota.1
@@ -0,0 +1,137 @@
+.\" Copyright (c) 1983, 1990, 1993, 2002
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)quota.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd March 28, 2002
+.Dt QUOTA 1
+.Os BSD 4.2
+.Sh NAME
+.Nm quota
+.Nd display disk usage and limits
+.Sh SYNOPSIS
+.Nm quota
+.Op Fl g
+.Op Fl u
+.Op Fl v | Fl q
+.Nm quota
+.Op Fl u
+.Op Fl v | Fl q
+.Ar user
+.Nm quota
+.Op Fl g
+.Op Fl v | Fl q
+.Ar group
+.Sh DESCRIPTION
+.Nm Quota
+displays users' disk usage and limits.
+By default only the user quotas are printed.
+.Pp
+Options:
+.Pp
+.Bl -tag -width Ds
+.It Fl g
+Print group quotas for the group
+of which the user is a member.
+The optional
+.Fl u
+flag is equivalent to the default.
+.It Fl v
+.Nm quota
+will display quotas on filesystems
+where no storage is allocated.
+.It Fl q
+Print a more terse message,
+containing only information
+on filesystems where usage is over quota.
+.El
+.Pp
+Specifying both
+.Fl g
+and
+.Fl u
+displays both the user quotas and the group quotas (for
+the user).
+.Pp
+Only the super-user may use the
+.Fl u
+flag and the optional
+.Ar user
+argument to view the limits of other users.
+Non-super-users can use the
+.Fl g
+flag and optional
+.Ar group
+argument to view only the limits of groups of which they are members.
+.Pp
+The
+.Fl q
+flag takes precedence over the
+.Fl v
+flag.
+.Pp
+.Nm Quota
+reports the quotas of all the filesystems that have
+a mount option file located at its root.
+If
+.Nm quota
+exits with a non-zero status, then one or more filesystems
+are over quota.
+.Sh FILES
+Each of the following quota files is located at the root of the
+mounted filesystem. The mount option files are empty files
+whose existence indicates that quotas are to be enabled
+for that filesystem.
+.Pp
+.Bl -tag -width .quota.ops.group -compact
+.It Pa .quota.user
+data file containing user quotas
+.It Pa .quota.group
+data file containing group quotas
+.It Pa .quota.ops.user
+mount option file used to enable user quotas
+.It Pa .quota.ops.group
+mount option file used to enable group quotas
+.El
+.Sh HISTORY
+The
+.Nm quota
+command appeared in
+.Bx 4.2 .
+.Sh SEE ALSO
+.Xr quotactl 2 ,
+.Xr edquota 8 ,
+.Xr quotacheck 8 ,
+.Xr quotaon 8 ,
+.Xr repquota 8
diff --git a/diskdev_cmds/quota.tproj/quota.c b/diskdev_cmds/quota.tproj/quota.c
new file mode 100644
index 0000000..87cb531
--- /dev/null
+++ b/diskdev_cmds/quota.tproj/quota.c
@@ -0,0 +1,858 @@
+/*
+ * Copyright (c) 2002-2007 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+/*
+ * Disk quota reporting program.
+ */
+#include <sys/param.h>
+#include <sys/file.h>
+#ifdef __APPLE__
+#include <sys/mount.h>
+#endif /* __APPLE */
+#include <sys/stat.h>
+#include <sys/queue.h>
+
+#include <sys/quota.h>
+#include <libkern/OSByteOrder.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fstab.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *qfname = QUOTAFILENAME;
+char *qfextension[] = INITQFNAMES;
+
+#ifdef __APPLE__
+u_int32_t quotamagic[MAXQUOTAS] = INITQMAGICS;
+#endif /* __APPLE__ */
+
+struct quotause {
+ struct quotause *next;
+ long flags;
+ struct dqblk dqblk;
+ char fsname[MAXPATHLEN + 1];
+} *getprivs();
+#define FOUND 0x01
+
+int qflag;
+int vflag;
+
+int alldigits __P((char *));
+int hasquota __P((struct statfs *, int, char **));
+void heading __P((int, u_long, char *, char *));
+void showgid __P((u_long));
+void showuid __P((u_long));
+void showgrpname __P((char *));
+void showquotas __P((int, u_long, char *));
+void showusrname __P((char *));
+void usage __P((void));
+
+#ifdef __APPLE__
+int qflookup(int, u_long, int, struct dqblk *);
+#endif /* __APPLE__ */
+
+int
+main(argc, argv)
+ char *argv[];
+{
+ int ngroups;
+ gid_t gidset[NGROUPS];
+ int i, gflag = 0, uflag = 0;
+ char ch;
+
+#if 0
+ if (quotactl("/", 0, 0, (caddr_t)0) < 0 && errno == ENOTSUP) {
+ fprintf(stderr, "There are no quotas on this system\n");
+ exit(0);
+ }
+#endif
+
+ while ((ch = getopt(argc, argv, "ugvq")) != EOF) {
+ switch(ch) {
+ case 'g':
+ gflag++;
+ break;
+ case 'u':
+ uflag++;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'q':
+ qflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (!uflag && !gflag)
+ uflag++;
+ if (argc == 0) {
+ if (uflag)
+ showuid(getuid());
+ if (gflag) {
+ ngroups = getgroups(NGROUPS, gidset);
+ if (ngroups < 0) {
+ perror("quota: getgroups");
+ exit(1);
+ }
+ for (i = 1; i < ngroups; i++)
+ showgid(gidset[i]);
+ }
+ exit(0);
+ }
+ if (uflag && gflag)
+ usage();
+ if (uflag) {
+ for (; argc > 0; argc--, argv++) {
+ if (alldigits(*argv))
+ showuid(atoi(*argv));
+ else
+ showusrname(*argv);
+ }
+ exit(0);
+ }
+ if (gflag) {
+ for (; argc > 0; argc--, argv++) {
+ if (alldigits(*argv))
+ showgid(atoi(*argv));
+ else
+ showgrpname(*argv);
+ }
+ exit(0);
+ }
+ exit(0);
+}
+
+void
+usage()
+{
+
+ fprintf(stderr, "%s\n%s\n%s\n",
+ "Usage: quota [-guqv]",
+ "\tquota [-qv] -u username ...",
+ "\tquota [-qv] -g groupname ...");
+ exit(1);
+}
+
+/*
+ * Print out quotas for a specified user identifier.
+ */
+void
+showuid(uid)
+ u_long uid;
+{
+ struct passwd *pwd = getpwuid(uid);
+ u_long myuid;
+ char *name;
+
+ if (pwd == NULL)
+ name = "(no account)";
+ else
+ name = pwd->pw_name;
+ myuid = getuid();
+ if (uid != myuid && myuid != 0) {
+ printf("quota: %s (uid %ld): permission denied\n", name, uid);
+ return;
+ }
+ showquotas(USRQUOTA, uid, name);
+}
+
+/*
+ * Print out quotas for a specifed user name.
+ */
+void
+showusrname(name)
+ char *name;
+{
+ struct passwd *pwd = getpwnam(name);
+ u_long myuid;
+
+ if (pwd == NULL) {
+ fprintf(stderr, "quota: %s: unknown user\n", name);
+ return;
+ }
+ myuid = getuid();
+ if (pwd->pw_uid != myuid && myuid != 0) {
+ fprintf(stderr, "quota: %s (uid %d): permission denied\n",
+ name, pwd->pw_uid);
+ return;
+ }
+ showquotas(USRQUOTA, pwd->pw_uid, name);
+}
+
+/*
+ * Print out quotas for a specified group identifier.
+ */
+void
+showgid(gid)
+ u_long gid;
+{
+ struct group *grp = getgrgid(gid);
+ int ngroups;
+ gid_t gidset[NGROUPS];
+ register int i;
+ char *name;
+
+ if (grp == NULL)
+ name = "(no entry)";
+ else
+ name = grp->gr_name;
+ ngroups = getgroups(NGROUPS, gidset);
+ if (ngroups < 0) {
+ perror("quota: getgroups");
+ return;
+ }
+ for (i = 1; i < ngroups; i++)
+ if (gid == gidset[i])
+ break;
+ if (i >= ngroups && getuid() != 0) {
+ fprintf(stderr, "quota: %s (gid %ld): permission denied\n",
+ name, gid);
+ return;
+ }
+ showquotas(GRPQUOTA, gid, name);
+}
+
+/*
+ * Print out quotas for a specifed group name.
+ */
+void
+showgrpname(name)
+ char *name;
+{
+ struct group *grp = getgrnam(name);
+ int ngroups;
+ gid_t gidset[NGROUPS];
+ register int i;
+
+ if (grp == NULL) {
+ fprintf(stderr, "quota: %s: unknown group\n", name);
+ return;
+ }
+ ngroups = getgroups(NGROUPS, gidset);
+ if (ngroups < 0) {
+ perror("quota: getgroups");
+ return;
+ }
+ for (i = 1; i < ngroups; i++)
+ if (grp->gr_gid == gidset[i])
+ break;
+ if (i >= ngroups && getuid() != 0) {
+ fprintf(stderr, "quota: %s (gid %d): permission denied\n",
+ name, grp->gr_gid);
+ return;
+ }
+ showquotas(GRPQUOTA, grp->gr_gid, name);
+}
+
+void
+showquotas(type, id, name)
+ int type;
+ u_long id;
+ char *name;
+{
+ register struct quotause *qup;
+ struct quotause *quplist, *getprivs();
+ char *msgi, *msgb, *timeprt();
+ int lines = 0;
+ static time_t now;
+
+ if (now == 0)
+ time(&now);
+ quplist = getprivs(id, type);
+ for (qup = quplist; qup; qup = qup->next) {
+ if (!vflag &&
+ qup->dqblk.dqb_isoftlimit == 0 &&
+ qup->dqblk.dqb_ihardlimit == 0 &&
+ qup->dqblk.dqb_bsoftlimit == 0 &&
+ qup->dqblk.dqb_bhardlimit == 0)
+ continue;
+ msgi = (char *)0;
+ if (qup->dqblk.dqb_ihardlimit &&
+ qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_ihardlimit) {
+ msgi = "File limit reached on";
+ } else if (qup->dqblk.dqb_isoftlimit &&
+ qup->dqblk.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) {
+ if (qup->dqblk.dqb_itime > now) {
+ msgi = "In file grace period on";
+ } else {
+ msgi = "Over file quota on";
+ }
+ }
+ msgb = (char *)0;
+#ifdef __APPLE__
+ if (qup->dqblk.dqb_bhardlimit &&
+ qup->dqblk.dqb_curbytes >= qup->dqblk.dqb_bhardlimit) {
+ msgb = "Block limit reached on";
+ } else if (qup->dqblk.dqb_bsoftlimit &&
+ qup->dqblk.dqb_curbytes >= qup->dqblk.dqb_bsoftlimit) {
+ if (qup->dqblk.dqb_btime > now) {
+ msgb = "In block grace period on";
+ } else {
+ msgb = "Over block quota on";
+ }
+ }
+#else
+ if (qup->dqblk.dqb_bhardlimit &&
+ qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bhardlimit) {
+ msgb = "Block limit reached on";
+ } else if (qup->dqblk.dqb_bsoftlimit &&
+ qup->dqblk.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) {
+ if (qup->dqblk.dqb_btime > now) {
+ msgb = "In block grace period on";
+ } else {
+ msgb = "Over block quota on";
+ }
+ }
+#endif /* __APPLE__ */
+
+ if (qflag) {
+ if ((msgi != (char *)0 || msgb != (char *)0) &&
+ lines++ == 0)
+ heading(type, id, name, "");
+ if (msgi != (char *)0)
+ printf("\t%s %s\n", msgi, qup->fsname);
+ if (msgb != (char *)0)
+ printf("\t%s %s\n", msgb, qup->fsname);
+ continue;
+ }
+#ifdef __APPLE__
+ if (vflag ||
+ qup->dqblk.dqb_curbytes ||
+ qup->dqblk.dqb_curinodes) {
+ if (lines++ == 0)
+ heading(type, id, name, "");
+
+ printf("%15s %12qd%c %12qd %12qd %8s"
+ , qup->fsname
+ , qup->dqblk.dqb_curbytes / 1024
+ , (msgb == (char *)0) ? ' ' : '*'
+ , qup->dqblk.dqb_bsoftlimit / 1024
+ , qup->dqblk.dqb_bhardlimit / 1024
+ , (msgb == (char *)0) ? ""
+ : timeprt(qup->dqblk.dqb_btime));
+#else
+ if (vflag ||
+ qup->dqblk.dqb_curblocks ||
+ qup->dqblk.dqb_curinodes) {
+ if (lines++ == 0)
+ heading(type, id, name, "");
+
+ printf("%15s%8d%c%7d%8d%8s"
+ , qup->fsname
+ , dbtob(qup->dqblk.dqb_curblocks) / 1024
+ , (msgb == (char *)0) ? ' ' : '*'
+ , dbtob(qup->dqblk.dqb_bsoftlimit) / 1024
+ , dbtob(qup->dqblk.dqb_bhardlimit) / 1024
+ , (msgb == (char *)0) ? ""
+ : timeprt(qup->dqblk.dqb_btime));
+#endif /* __APPLE__ */
+ printf("%8d%c%7d%8d%8s\n"
+ , qup->dqblk.dqb_curinodes
+ , (msgi == (char *)0) ? ' ' : '*'
+ , qup->dqblk.dqb_isoftlimit
+ , qup->dqblk.dqb_ihardlimit
+ , (msgi == (char *)0) ? ""
+ : timeprt(qup->dqblk.dqb_itime)
+ );
+ continue;
+ }
+ }
+ if (!qflag && lines == 0)
+ heading(type, id, name, "none");
+}
+
+void
+heading(type, id, name, tag)
+ int type;
+ u_long id;
+ char *name, *tag;
+{
+
+ printf("Disk quotas for %s %s (%cid %ld): %s\n", qfextension[type],
+ name, *qfextension[type], id, tag);
+ if (!qflag && tag[0] == '\0') {
+#ifdef __APPLE__
+ printf("%15s %12s %12s %12s %8s%8s %7s%8s%8s\n"
+ , "Filesystem"
+ , "1K blocks"
+#else
+ printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n"
+ , "Filesystem"
+ , "blocks"
+#endif /* __APPLE __*/
+ , "quota"
+ , "limit"
+ , "grace"
+ , "files"
+ , "quota"
+ , "limit"
+ , "grace"
+ );
+ }
+}
+
+/*
+ * Calculate the grace period and return a printable string for it.
+ */
+char *
+timeprt(seconds)
+ time_t seconds;
+{
+ time_t hours, minutes;
+ static char buf[20];
+ static time_t now;
+
+ if (now == 0)
+ time(&now);
+ if (now > seconds)
+ return ("none");
+ seconds -= now;
+ minutes = (seconds + 30) / 60;
+ hours = (minutes + 30) / 60;
+ if (hours >= 36) {
+ snprintf(buf, sizeof(buf), "%ddays", (int)((hours + 12) / 24));
+ return (buf);
+ }
+ if (minutes >= 60) {
+ snprintf(buf, sizeof(buf), "%2d:%d", (int)(minutes / 60), (int)(minutes % 60));
+ return (buf);
+ }
+ snprintf(buf, sizeof(buf), "%2d", (int)minutes);
+ return (buf);
+}
+
+typedef struct {
+ int alloced;
+ int nels;
+ char **strings;
+} mount_list_t;
+
+static void *
+init_list(int max)
+{
+ mount_list_t *retval = NULL;
+ retval = malloc(sizeof(*retval));
+ if (retval) {
+ retval->strings = malloc(sizeof(char*) * max);
+ if (retval->strings) {
+ retval->alloced = max;
+ } else {
+ retval->alloced = 0;
+ }
+ retval->nels = 0;
+ }
+ return retval;
+}
+static void
+free_list(void *list)
+{
+ mount_list_t *tmp = list;
+ int i;
+
+ if (tmp == NULL)
+ return;
+ for (i = 0; i < tmp->nels; i++) {
+ free(tmp->strings[i]);
+ }
+ free(tmp);
+ return;
+}
+
+static int
+hasseen(void *tmp, const char *mp)
+{
+ int retval = 0;
+ mount_list_t *list = tmp;
+ int i;
+
+ if (tmp == NULL || mp == NULL)
+ goto done;
+
+ /*
+ * This could also be a binary search, but then we'd have to sort
+ * after each addition. We may want to change the behaviour based
+ * on the number of elements in the array.
+ */
+
+ for (i = 0; i < list->nels; i++) {
+ if (strcmp(list->strings[i], mp) == 0) {
+ retval = 1;
+ goto done;
+ }
+ }
+ if (list->nels <= list->alloced) {
+ char **a = realloc(list->strings, (list->alloced + 10) * sizeof(char*));
+ if (a) {
+ list->alloced = list->alloced + 10;
+ list->strings = a;
+ } else {
+ goto done;
+ }
+ }
+ list->strings[list->nels++] = strdup(mp);
+
+done:
+ return retval;
+}
+
+/*
+ * Collect the requested quota information.
+ */
+#ifdef __APPLE__
+struct quotause *
+getprivs(id, quotatype)
+ register long id;
+ int quotatype;
+{
+ struct statfs *fst;
+ register struct quotause *qup, *quptail;
+ struct quotause *quphead;
+ struct dqblk dqb;
+ char *qfpathname;
+ int qcmd, fd;
+ int nfst, i;
+ int error;
+ void *cache;
+
+ quptail = quphead = (struct quotause *)0;
+ qcmd = QCMD(Q_GETQUOTA, quotatype);
+
+ nfst = getmntinfo(&fst, MNT_WAIT);
+ if (nfst==0) {
+ fprintf(stderr, "quota: no mounted filesystems\n");
+ exit(1);
+ }
+
+ cache = init_list(nfst);
+
+ for (i=0; i<nfst; i++) {
+ if (hasseen(cache, fst[i].f_mntonname))
+ continue;
+ error = quotactl(fst[i].f_mntonname, qcmd, id, (char *)&dqb);
+ if (error) {
+ if (strcmp(fst[i].f_fstypename, "hfs"))
+ continue;
+ if (!hasquota(&fst[i], quotatype, &qfpathname))
+ continue;
+ }
+ if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) {
+ fprintf(stderr, "quota: out of memory\n");
+ exit(2);
+ }
+ if (!error) {
+ bcopy(&dqb, &qup->dqblk, sizeof(dqb));
+ } else {
+ if ((fd = open(qfpathname, O_RDONLY)) < 0) {
+ perror(qfpathname);
+ free(qup);
+ continue;
+ }
+ if ((error = qflookup(fd, id, quotatype, &qup->dqblk))) {
+ perror(qfpathname);
+ close(fd);
+ free(qup);
+ continue;
+ }
+ close(fd);
+ }
+ strlcpy(qup->fsname, fst[i].f_mntonname, sizeof(qup->fsname));
+ if (quphead == NULL)
+ quphead = qup;
+ else
+ quptail->next = qup;
+ quptail = qup;
+ qup->next = 0;
+ }
+ free_list(cache);
+
+ return (quphead);
+}
+#else
+struct quotause *
+getprivs(id, quotatype)
+ register long id;
+ int quotatype;
+{
+ register struct fstab *fs;
+ register struct quotause *qup, *quptail;
+ struct quotause *quphead;
+ char *qfpathname;
+ int qcmd, fd;
+
+ setfsent();
+ quphead = (struct quotause *)0;
+ qcmd = QCMD(Q_GETQUOTA, quotatype);
+ while (fs = getfsent()) {
+ if (strcmp(fs->fs_vfstype, "ufs"))
+ continue;
+ if (!hasquota(fs, quotatype, &qfpathname))
+ continue;
+ if ((qup = (struct quotause *)malloc(sizeof *qup)) == NULL) {
+ fprintf(stderr, "quota: out of memory\n");
+ exit(2);
+ }
+ if (quotactl(fs->fs_file, qcmd, id, &qup->dqblk) != 0) {
+ if ((fd = open(qfpathname, O_RDONLY)) < 0) {
+ perror(qfpathname);
+ free(qup);
+ continue;
+ }
+ lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET);
+ switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
+ case 0: /* EOF */
+ /*
+ * Convert implicit 0 quota (EOF)
+ * into an explicit one (zero'ed dqblk)
+ */
+ bzero((caddr_t)&qup->dqblk,
+ sizeof(struct dqblk));
+ break;
+
+ case sizeof(struct dqblk): /* OK */
+ break;
+
+ default: /* ERROR */
+ fprintf(stderr, "quota: read error");
+ perror(qfpathname);
+ close(fd);
+ free(qup);
+ continue;
+ }
+ close(fd);
+ }
+ strlcpy(qup->fsname, fs->fs_file, sizeof(qup->fsname));
+
+ if (quphead == NULL)
+ quphead = qup;
+ else
+ quptail->next = qup;
+ quptail = qup;
+ qup->next = 0;
+ }
+ endfsent();
+ return (quphead);
+}
+#endif /* __APPLE__ */
+
+
+#ifdef __APPLE__
+/*
+ * Lookup an entry in the quota file.
+ */
+int
+qflookup(fd, id, type, dqbp)
+ int fd;
+ u_long id;
+ int type;
+ struct dqblk *dqbp;
+{
+ struct dqfilehdr dqhdr;
+ int i, skip, last, m;
+ u_long mask;
+
+ bzero(dqbp, sizeof(struct dqblk));
+
+ if (id == 0)
+ return (0);
+
+ lseek(fd, 0, L_SET);
+ if (read(fd, &dqhdr, sizeof(struct dqfilehdr)) != sizeof(struct dqfilehdr)) {
+ fprintf(stderr, "quota: read error\n");
+ return (errno);
+ }
+
+ /* Sanity check the quota file header. */
+ if ((OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type]) ||
+ (OSSwapBigToHostInt32(dqhdr.dqh_version) > QF_VERSION) ||
+ (!powerof2(OSSwapBigToHostInt32(dqhdr.dqh_maxentries)))) {
+ fprintf(stderr, "quota: invalid quota file header\n");
+ return (EINVAL);
+ }
+
+ m = OSSwapBigToHostInt32(dqhdr.dqh_maxentries);
+ mask = m - 1;
+ i = dqhash1(id, dqhashshift(m), mask);
+ skip = dqhash2(id, mask);
+
+ for (last = (i + (m-1) * skip) & mask;
+ i != last;
+ i = (i + skip) & mask) {
+ lseek(fd, dqoffset(i), L_SET);
+ if (read(fd, dqbp, sizeof(struct dqblk)) < sizeof(struct dqblk)) {
+ fprintf(stderr, "quota: read error at index %d\n", i);
+ return (errno);
+ }
+ /*
+ * Stop when an empty entry is found
+ * or we encounter a matching id.
+ */
+ if (dqbp->dqb_id == 0 || OSSwapBigToHostInt32(dqbp->dqb_id) == id)
+ break;
+ }
+ /* Put data in host native byte order. */
+ dqbp->dqb_bhardlimit = OSSwapBigToHostInt64(dqbp->dqb_bhardlimit);
+ dqbp->dqb_bsoftlimit = OSSwapBigToHostInt64(dqbp->dqb_bsoftlimit);
+ dqbp->dqb_curbytes = OSSwapBigToHostInt64(dqbp->dqb_curbytes);
+ dqbp->dqb_ihardlimit = OSSwapBigToHostInt32(dqbp->dqb_ihardlimit);
+ dqbp->dqb_isoftlimit = OSSwapBigToHostInt32(dqbp->dqb_isoftlimit);
+ dqbp->dqb_curinodes = OSSwapBigToHostInt32(dqbp->dqb_curinodes);
+ dqbp->dqb_btime = OSSwapBigToHostInt32(dqbp->dqb_btime);
+ dqbp->dqb_itime = OSSwapBigToHostInt32(dqbp->dqb_itime);
+ dqbp->dqb_id = OSSwapBigToHostInt32(dqbp->dqb_id);
+
+ return (0);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+#ifdef __APPLE__
+int
+hasquota(fst, type, qfnamep)
+ register struct statfs *fst;
+ int type;
+ char **qfnamep;
+{
+ struct stat sb;
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
+ snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ /*
+ We only support the default path to the
+ on disk quota files.
+ */
+
+ (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname,
+ QUOTAOPSNAME, qfextension[type] );
+ if (stat(buf, &sb) != 0) {
+ /* There appears to be no mount option file */
+ return(0);
+ }
+
+ (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+#else
+hasquota(fs, type, qfnamep)
+ register struct fstab *fs;
+ int type;
+ char **qfnamep;
+{
+ register char *opt;
+ char *cp, *index(), *strtok();
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
+ snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ strlcpy(buf, fs->fs_mntops, sizeof(buf));
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if (cp = index(opt, '='))
+ *cp++ = '\0';
+ if (type == USRQUOTA && strcmp(opt, usrname) == 0)
+ break;
+ if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+#endif /* __APPLE__ */
+
+int
+alldigits(s)
+ register char *s;
+{
+ register int c;
+
+ c = *s++;
+ do {
+ if (!isdigit(c))
+ return (0);
+ } while ((c = *s++));
+ return (1);
+}
diff --git a/diskdev_cmds/quotacheck.tproj/hfs_quotacheck.c b/diskdev_cmds/quotacheck.tproj/hfs_quotacheck.c
new file mode 100644
index 0000000..31bb0f5
--- /dev/null
+++ b/diskdev_cmds/quotacheck.tproj/hfs_quotacheck.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/param.h>
+#include <sys/attr.h>
+#include <sys/quota.h>
+#include <sys/vnode.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "quotacheck.h"
+
+
+/*
+ * Query is based on uid
+ */
+#define QQ_COMMON (ATTR_CMN_OWNERID)
+
+struct quota_query {
+ u_int32_t qq_len;
+ uid_t qq_uid;
+};
+
+/*
+ * Desired atttributes for quota checking
+ */
+#define QA_COMMON (ATTR_CMN_OBJTYPE | ATTR_CMN_OWNERID | ATTR_CMN_GRPID)
+#define QA_FILE (ATTR_FILE_ALLOCSIZE)
+#define QA_DIR (0)
+
+struct quota_attr {
+ u_int32_t qa_attrlen;
+ fsobj_type_t qa_type;
+ uid_t qa_uid;
+ gid_t qa_gid;
+ off_t qa_bytes;
+};
+
+#define ITEMS_PER_SEARCH 2500
+
+void collectdata(const char*, struct quotaname *);
+
+
+/*
+ * Scan an HFS filesystem to check quota(s) present on it.
+ */
+int
+chkquota_hfs(fsname, mntpt, qnp)
+ char *fsname, *mntpt;
+ register struct quotaname *qnp;
+{
+ int errs = 0;
+
+ sync();
+
+ collectdata(mntpt, qnp);
+
+ if (qnp->flags & HASUSR)
+ errs = update(mntpt, qnp->usrqfname, USRQUOTA);
+ if (qnp->flags & HASGRP)
+ errs = update(mntpt, qnp->grpqfname, GRPQUOTA);
+
+ return (errs);
+}
+
+
+void
+collectdata(const char* path, struct quotaname *qnp)
+{
+ struct fssearchblock searchblk = {0};
+ struct attrlist attrlist = {0};
+ struct searchstate state;
+ struct quota_attr *qap;
+ struct quota_query query;
+ u_long nummatches;
+ u_int options;
+
+ int i;
+ int result;
+ int vntype;
+ off_t filebytes;
+ register struct fileusage *fup;
+
+ qap = malloc(ITEMS_PER_SEARCH * sizeof(struct quota_attr));
+ if (qap == NULL)
+ err(1, "%s", strerror(errno));
+
+ options = SRCHFS_START |SRCHFS_MATCHDIRS | SRCHFS_MATCHFILES;
+
+ /* Search for items with uid != 0 */
+ query.qq_len = sizeof(struct quota_query);
+ query.qq_uid = 0;
+ options |= SRCHFS_NEGATEPARAMS | SRCHFS_SKIPLINKS;
+ searchblk.searchattrs.bitmapcount = ATTR_BIT_MAP_COUNT;
+ searchblk.searchattrs.commonattr = QQ_COMMON;
+ searchblk.searchparams1 = &query;
+ searchblk.searchparams2 = &query;
+ searchblk.sizeofsearchparams1 = sizeof(query);
+ searchblk.sizeofsearchparams2 = sizeof(query);
+
+ /* Ask for type, uid, gid and file bytes */
+ searchblk.returnattrs = &attrlist;
+ attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
+ attrlist.commonattr = QA_COMMON;
+ attrlist.dirattr = QA_DIR;
+ attrlist.fileattr = QA_FILE;
+
+ /* Collect 2,500 items at a time (~60K) */
+ searchblk.returnbuffer = qap;
+ searchblk.returnbuffersize = ITEMS_PER_SEARCH * sizeof(struct quota_attr);
+ searchblk.maxmatches = ITEMS_PER_SEARCH;
+
+ for (;;) {
+ nummatches = 0;
+ result = searchfs(path, &searchblk, &nummatches, 0, options, &state);
+ if (result && errno != EAGAIN && errno != EBUSY) {
+ fprintf(stderr, "%d \n", errno);
+ err(1, "searchfs %s", strerror(errno));
+ }
+ if (result == 0 && nummatches == 0)
+ break; /* all done */
+ options &= ~SRCHFS_START;
+
+ for (i = 0; i < nummatches; ++i) {
+ vntype = qap[i].qa_type;
+ filebytes = (vntype == VDIR) ? 0 : qap[i].qa_bytes;
+
+ if (qnp->flags & HASGRP) {
+ fup = addid(qap[i].qa_gid, GRPQUOTA);
+ fup->fu_curinodes++;
+ if (vntype == VREG || vntype == VDIR || vntype == VLNK)
+ fup->fu_curbytes += filebytes;
+ }
+ if (qnp->flags & HASUSR) {
+ fup = addid(qap[i].qa_uid, USRQUOTA);
+ fup->fu_curinodes++;
+ if (vntype == VREG || vntype == VDIR || vntype == VLNK)
+ fup->fu_curbytes += filebytes;
+ }
+ }
+ }
+
+ free(qap);
+}
diff --git a/diskdev_cmds/quotacheck.tproj/quotacheck.8 b/diskdev_cmds/quotacheck.tproj/quotacheck.8
new file mode 100644
index 0000000..92e547e
--- /dev/null
+++ b/diskdev_cmds/quotacheck.tproj/quotacheck.8
@@ -0,0 +1,156 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993, 2002
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)quotacheck.8 8.1 (Berkeley) 6/5/93
+.\"
+.Dd October 17, 2002
+.Dt QUOTACHECK 8
+.Os BSD 4.2
+.Sh NAME
+.Nm quotacheck
+.Nd filesystem quota consistency checker
+.Sh SYNOPSIS
+.Nm quotacheck
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Ar filesystem Ar ...
+.Nm quotacheck
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Fl a
+.Sh DESCRIPTION
+.Nm Quotacheck
+examines each filesystem,
+builds a table of current disk usage,
+and compares this table against that recorded
+in the disk quota file for the filesystem.
+If any inconsistencies are detected, both the
+quota file and the current system copy of the
+incorrect quotas are updated (the latter only
+occurs if an active filesystem is checked).
+By default both user and group quotas are checked.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl a
+If the
+.Fl a
+flag is supplied in place of any filesystem names,
+.Nm quotacheck
+will check all the read-write filesystems with an existing
+mount option file at its root.
+The mount option file specifies the types of quotas that
+are to be checked.
+.It Fl g
+Only group quotas are checked. The mount option file,
+.Pa .quota.ops.group ,
+must exist at the root of the filesystem.
+.It Fl u
+Only user quotas are checked. The mount option file,
+.Pa .quota.ops.user ,
+must exist at the root of the filesystem.
+.It Fl v
+.Nm quotacheck
+reports discrepancies between the
+calculated and recorded disk quotas.
+.El
+.Pp
+Specifying both
+.Fl g
+and
+.Fl u
+is equivalent to the default.
+Parallel passes are run on the filesystems required,
+in an identical fashion to
+.Xr fsck 8 .
+.Pp
+Normally
+.Nm quotacheck
+operates silently.
+.Pp
+.Nm Quotacheck
+expects each filesystem being checked to have
+quota data files named
+.Pa .quota.user
+and/or
+.Pa .quota.group
+located at the filesystem root.
+If a binary data file is not present,
+.Nm quotacheck
+will create it.
+The default filename and root location cannot be overridden.
+.Pp
+.Nm Quotacheck
+is normally run at
+.Pa fsck
+time.
+.Pp
+.Nm Quotacheck
+accesses the raw device in calculating the actual
+disk usage for each user.
+Thus, the filesystems
+checked should be quiescent while
+.Nm quotacheck
+is running.
+.Sh FILES
+Each of the following quota files is located at the root of the
+mounted filesystem. The mount option files are empty files
+whose existence indicates that quotas are to be enabled
+for that filesystem. The binary data files will be created by
+quotacheck, if they don't already exist.
+.Pp
+.Bl -tag -width .quota.ops.group -compact
+.It Pa .quota.user
+data file containing user quotas
+.It Pa .quota.group
+data file containing group quotas
+.It Pa .quota.ops.user
+mount option file used to enable user quotas
+.It Pa .quota.ops.group
+mount option file used to enable group quotas
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr quotactl 2 ,
+.Xr edquota 8 ,
+.Xr fsck 8 ,
+.Xr quotaon 8 ,
+.Xr repquota 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/diskdev_cmds/quotacheck.tproj/quotacheck.c b/diskdev_cmds/quotacheck.tproj/quotacheck.c
new file mode 100644
index 0000000..20b5dde
--- /dev/null
+++ b/diskdev_cmds/quotacheck.tproj/quotacheck.c
@@ -0,0 +1,972 @@
+/*
+ * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+/*
+ * Fix up / report on disk quotas & usage
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#ifdef __APPLE__
+#include <sys/mount.h>
+#endif /* __APPLE__ */
+
+#include <sys/quota.h>
+
+#include <fcntl.h>
+#include <fstab.h>
+#include <pwd.h>
+#include <grp.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#endif /* __APPLE__ */
+
+#include "quotacheck.h"
+
+char *qfname = QUOTAFILENAME;
+char *qfextension[] = INITQFNAMES;
+char *quotagroup = QUOTAGROUP;
+
+#ifdef __APPLE__
+u_int32_t quotamagic[MAXQUOTAS] = INITQMAGICS;
+#endif /* __APPLE__ */
+
+
+#define FUHASH 1024 /* must be power of two */
+struct fileusage *fuhead[MAXQUOTAS][FUHASH];
+
+int aflag; /* all file systems */
+int gflag; /* check group quotas */
+int uflag; /* check user quotas */
+int vflag; /* verbose */
+
+#ifdef __APPLE__
+int maxentries; /* maximum entries in disk quota file */
+#else
+u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
+#endif /* __APPLE__ */
+
+
+#ifdef __APPLE__
+char * blockcheck(char *);
+int chkquota(char *, char *, char *, struct quotaname *);
+int getquotagid(void);
+int hasquota(struct statfs *, int, char **);
+struct fileusage *
+ lookup(u_long, int);
+void * needchk(struct statfs *);
+int oneof(char *, char*[], int);
+int qfinsert(FILE *, struct dqblk *, int, int);
+int qfmaxentries(char *, int);
+void usage(void);
+void dqbuftohost(struct dqblk *dqbp);
+
+#else
+struct fileusage *
+ addid __P((uid_t, int, char *));
+char *blockcheck __P((char *));
+int chkquota __P((char *, char *, struct quotaname *));
+int getquotagid __P((void));
+int hasquota __P((struct fstab *, int, char **));
+struct fileusage *
+ lookup __P((u_long, int));
+void *needchk __P((struct fstab *));
+int oneof __P((char *, char*[], int));
+int update __P((char *, char *, int));
+void usage __P((void));
+#endif /* __APPLE__ */
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+#ifndef __APPLE__
+ register struct fstab *fs;
+ register struct passwd *pw;
+ register struct group *gr;
+#endif /* !__APPLE__ */
+ struct quotaname *auxdata;
+ int i, argnum, maxrun, errs;
+ long done = 0;
+ char ch, *name;
+
+#ifdef __APPLE__
+ int nfst;
+ struct statfs *fst;
+#endif /* __APPLE__ */
+
+ errs = maxrun = 0;
+ while ((ch = getopt(argc, argv, "aguvl:")) != EOF) {
+ switch(ch) {
+ case 'a':
+ aflag++;
+ break;
+ case 'g':
+ gflag++;
+ break;
+ case 'u':
+ uflag++;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'l':
+ maxrun = atoi(optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if ((argc == 0 && !aflag) || (argc > 0 && aflag))
+ usage();
+ if (!gflag && !uflag) {
+ gflag++;
+ uflag++;
+ }
+
+#ifdef __APPLE__
+ nfst = getmntinfo(&fst, MNT_WAIT);
+ if (nfst==0) {
+ fprintf(stderr, "quotacheck: no mounted filesystems\n");
+ exit(1);
+ }
+
+ for (i=0; i<nfst; i++) {
+ if(strcmp(fst[i].f_fstypename, "hfs")) {
+ continue;
+ }
+
+ if (aflag) {
+ if ((auxdata = needchk(&fst[i])) &&
+ (name = blockcheck(fst[i].f_mntfromname))) {
+ errs += chkquota(fst[i].f_fstypename, name, fst[i].f_mntonname, auxdata);
+ }
+
+ if (i+1 == nfst)
+ exit (errs);
+ else
+ continue;
+ }
+
+ if (((argnum = oneof(fst[i].f_mntonname, argv, argc)) >= 0 ||
+ (argnum = oneof(fst[i].f_mntfromname, argv, argc)) >= 0) &&
+ (auxdata = needchk(&fst[i])) &&
+ (name = blockcheck(fst[i].f_mntfromname))) {
+ done |= 1 << argnum;
+ errs += chkquota(fst[i].f_fstypename, name, fst[i].f_mntonname, auxdata);
+ }
+ } /* end for loop */
+
+ for (i = 0; i < argc; i++)
+ if ((done & (1 << i)) == 0)
+ fprintf(stderr, "%s not identified as a quota filesystem\n",
+ argv[i]);
+
+ exit(errs);
+#else
+ if (gflag) {
+ setgrent();
+ while ((gr = getgrent()) != 0)
+ (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
+ endgrent();
+ }
+ if (uflag) {
+ setpwent();
+ while ((pw = getpwent()) != 0)
+ (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
+ endpwent();
+ }
+ if (aflag)
+ exit(checkfstab(1, maxrun, needchk, chkquota));
+ if (setfsent() == 0)
+ err(1, "%s: can't open", FSTAB);
+ while ((fs = getfsent()) != NULL) {
+ if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
+ (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) &&
+ (auxdata = needchk(fs)) &&
+ (name = blockcheck(fs->fs_spec))) {
+ done |= 1 << argnum;
+ errs += chkquota(name, fs->fs_file, auxdata);
+ }
+ }
+ endfsent();
+ for (i = 0; i < argc; i++)
+ if ((done & (1 << i)) == 0)
+ fprintf(stderr, "%s not found in %s\n",
+ argv[i], FSTAB);
+ exit(errs);
+#endif /* __APPLE__ */
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage:\t%s\n\t%s\n",
+ "quotacheck -a [-guv]",
+ "quotacheck [-guv] filesys ...");
+ exit(1);
+}
+
+#ifdef __APPLE__
+void *
+needchk(fst)
+ struct statfs *fst;
+{
+ register struct quotaname *qnp;
+ char *qfnp;
+
+ if(strcmp(fst->f_fstypename, "hfs")) {
+ return(NULL);
+ }
+ if(fst->f_flags & MNT_RDONLY)
+ return (NULL);
+ if ((qnp = malloc(sizeof(*qnp))) == NULL)
+ err(1, "%s", strerror(errno));
+ qnp->flags = 0;
+ if (gflag && hasquota(fst, GRPQUOTA, &qfnp)) {
+ strlcpy(qnp->grpqfname, qfnp, sizeof(qnp->grpqfname));
+ qnp->flags |= HASGRP;
+ }
+ if (uflag && hasquota(fst, USRQUOTA, &qfnp)) {
+ strlcpy(qnp->usrqfname, qfnp, sizeof(qnp->usrqfname));
+ qnp->flags |= HASUSR;
+ }
+ if (qnp->flags)
+ return (qnp);
+ free(qnp);
+ return (NULL);
+}
+#else
+void *
+needchk(fs)
+ register struct fstab *fs;
+{
+ register struct quotaname *qnp;
+ char *qfnp;
+
+ if (strcmp(fs->fs_type, FSTAB_RW))
+ return (NULL);
+
+ if ((qnp = malloc(sizeof(*qnp))) == NULL)
+ err(1, "%s", strerror(errno));
+ qnp->flags = 0;
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) {
+ strlcpy(qnp->grpqfname, qfnp, sizeof(qnp->grpqfname));
+ qnp->flags |= HASGRP;
+ }
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp)) {
+ strlcpy(qnp->usrqfname, qfnp, sizeof(qnp->usrqfname));
+ qnp->flags |= HASUSR;
+ }
+ if (qnp->flags)
+ return (qnp);
+ free(qnp);
+ return (NULL);
+}
+#endif /* __APPLE__ */
+
+/*
+ * Scan the specified filesystem to check quota(s) present on it.
+ */
+int
+chkquota(fstype, fsname, mntpt, qnp)
+ char *fstype, *fsname, *mntpt;
+ register struct quotaname *qnp;
+{
+ int errs = 1;
+
+ if (vflag) {
+ fprintf(stdout, "*** Checking ");
+ if (qnp->flags & HASUSR)
+ fprintf(stdout, "%s%s", qfextension[USRQUOTA],
+ (qnp->flags & HASGRP) ? " and " : "");
+ if (qnp->flags & HASGRP)
+ fprintf(stdout, "%s", qfextension[GRPQUOTA]);
+ fprintf(stdout, " quotas for %s (%s)\n", fsname, mntpt);
+ }
+
+ if(strcmp(fstype, "hfs") == 0)
+ errs = chkquota_hfs(fsname, mntpt, qnp);
+
+ return (errs);
+}
+
+/*
+ * Update a specified quota file.
+ */
+#ifdef __APPLE__
+int
+update(fsname, quotafile, type)
+ char *fsname, *quotafile;
+ register int type;
+{
+ register struct fileusage *fup;
+ register FILE *qfi, *qfo;
+ register u_long i;
+ struct dqblk dqbuf;
+ struct dqfilehdr dqhdr = {0};
+ int m, shift;
+ int idcnt = 0;
+ static int warned = 0;
+ static struct dqblk zerodqbuf;
+ static struct fileusage zerofileusage;
+
+ if ((qfo = fopen(quotafile, "r+")) == NULL) {
+ if (errno == ENOENT)
+ qfo = fopen(quotafile, "w+");
+ if (qfo) {
+ fprintf(stderr,
+ "quotacheck: creating quota file %s\n", quotafile);
+#define MODE (S_IRUSR|S_IWUSR|S_IRGRP)
+ (void) fchown(fileno(qfo), getuid(), getquotagid());
+ (void) fchmod(fileno(qfo), MODE);
+ } else {
+ fprintf(stderr,
+ "quotacheck: %s: %s\n", quotafile, strerror(errno));
+ return (1);
+ }
+ }
+ if ((qfi = fopen(quotafile, "r")) == NULL) {
+ fprintf(stderr,
+ "quotacheck: %s: %s\n", quotafile, strerror(errno));
+ (void) fclose(qfo);
+ return (1);
+ }
+ if (quotactl(fsname, QCMD(Q_SYNC, type), 0, 0) < 0 &&
+ errno == ENOTSUP && !warned && vflag) {
+ warned++;
+ fprintf(stdout, "*** Warning: %s\n",
+ "Quotas are not compiled into this kernel");
+ }
+
+ /* Read in the quota file header. */
+ if (fread((char *)&dqhdr, sizeof(struct dqfilehdr), 1, qfi) > 0) {
+ /* Check for reverse endian file. */
+ if (OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type] &&
+ OSSwapInt32(dqhdr.dqh_magic) == quotamagic[type]) {
+ fprintf(stderr,
+ "quotacheck: %s: not in big endian byte order\n",
+ quotafile);
+ (void) fclose(qfo);
+ (void) fclose(qfi);
+ return (1);
+ }
+ /* Sanity check the quota file header. */
+ if ((OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type]) ||
+ (OSSwapBigToHostInt32(dqhdr.dqh_version) > QF_VERSION) ||
+ (!powerof2(OSSwapBigToHostInt32(dqhdr.dqh_maxentries)))) {
+ fprintf(stderr,
+ "quotacheck: %s: not a valid quota file\n",
+ quotafile);
+ (void) fclose(qfo);
+ (void) fclose(qfi);
+ return (1);
+ }
+ m = OSSwapBigToHostInt32(dqhdr.dqh_maxentries);
+ } else /* empty file */ {
+ if (maxentries)
+ m = maxentries;
+ else
+ m = qfmaxentries(fsname, type);
+
+ ftruncate(fileno(qfo), (off_t)((m + 1) * sizeof(struct dqblk)));
+
+ /* Initialize file header in big endian. */
+ dqhdr.dqh_magic = OSSwapHostToBigInt32(quotamagic[type]);
+ dqhdr.dqh_version = OSSwapHostToBigConstInt32(QF_VERSION);
+ dqhdr.dqh_maxentries = OSSwapHostToBigInt32(m);
+ dqhdr.dqh_btime = OSSwapHostToBigConstInt32(MAX_DQ_TIME);
+ dqhdr.dqh_itime = OSSwapHostToBigConstInt32(MAX_IQ_TIME);
+ memmove(dqhdr.dqh_string, QF_STRING_TAG, strlen(QF_STRING_TAG));
+ goto orphans; /* just insert all new records */
+ }
+
+ /* Examine all the entries in the quota file. */
+ for (i = 0; i < m; i++) {
+ if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0) {
+ fprintf(stderr,
+ "quotacheck: problem reading at index %ld\n", i);
+ continue;
+ }
+ if (dqbuf.dqb_id == 0)
+ continue;
+
+ ++idcnt;
+ if ((fup = lookup(OSSwapBigToHostInt32(dqbuf.dqb_id), type)) == 0)
+ fup = &zerofileusage;
+ else
+ fup->fu_checked = 1;
+
+ if (OSSwapBigToHostInt32(dqbuf.dqb_curinodes) == fup->fu_curinodes &&
+ OSSwapBigToHostInt64(dqbuf.dqb_curbytes) == fup->fu_curbytes) {
+ fup->fu_curinodes = 0;
+ fup->fu_curbytes = 0;
+ continue;
+ }
+ if (vflag) {
+ if (aflag)
+ fprintf(stdout, "%s: ", fsname);
+ fprintf(stdout, "%-12s fixed:", fup->fu_name);
+ if (OSSwapBigToHostInt32(dqbuf.dqb_curinodes) != fup->fu_curinodes)
+ fprintf(stdout, "\tinodes %u -> %u",
+ OSSwapBigToHostInt32(dqbuf.dqb_curinodes), fup->fu_curinodes);
+ if (OSSwapBigToHostInt64(dqbuf.dqb_curbytes) != fup->fu_curbytes)
+ fprintf(stdout, "\t1K blocks %qd -> %qd",
+ (OSSwapBigToHostInt64(dqbuf.dqb_curbytes)/1024), (fup->fu_curbytes/1024));
+ fprintf(stdout, "\n");
+ }
+ /*
+ * Reset time limit if have a soft limit and were
+ * previously under it, but are now over it.
+ */
+ if (dqbuf.dqb_bsoftlimit != 0 &&
+ OSSwapBigToHostInt64(dqbuf.dqb_curbytes) < OSSwapBigToHostInt64(dqbuf.dqb_bsoftlimit) &&
+ fup->fu_curbytes >= OSSwapBigToHostInt64(dqbuf.dqb_bsoftlimit))
+ dqbuf.dqb_btime = 0;
+ if (dqbuf.dqb_isoftlimit != 0 &&
+ OSSwapBigToHostInt32(dqbuf.dqb_curinodes) < OSSwapBigToHostInt32(dqbuf.dqb_isoftlimit) &&
+ fup->fu_curinodes >= OSSwapBigToHostInt32(dqbuf.dqb_isoftlimit))
+ dqbuf.dqb_itime = 0;
+ dqbuf.dqb_curinodes = OSSwapHostToBigInt32(fup->fu_curinodes);
+ dqbuf.dqb_curbytes = OSSwapHostToBigInt64(fup->fu_curbytes);
+
+ /* Write dqblk in big endian. */
+ fseek(qfo, dqoffset(i), SEEK_SET);
+ fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo);
+
+ dqbuftohost(&dqbuf);
+ (void) quotactl(fsname, QCMD(Q_SETUSE, type), dqbuf.dqb_id,
+ (caddr_t)&dqbuf);
+ fup->fu_curinodes = 0;
+ fup->fu_curbytes = 0;
+ }
+orphans:
+ /* Look for any fileusage orphans */
+
+ shift = dqhashshift(m);
+ for (i = 0; i < FUHASH; ++i) {
+ for (fup = fuhead[type][i]; fup != 0; fup = fup->fu_next) {
+ if (fup->fu_checked || fup->fu_id == 0)
+ continue;
+ if (vflag) {
+ if (aflag)
+ fprintf(stdout, "%s: ", fsname);
+ fprintf(stdout,
+ "%-12s added:\tinodes %u\t1K blocks %qd\n",
+ fup->fu_name, fup->fu_curinodes,
+ (fup->fu_curbytes/1024));
+ }
+ /* Initialize dqbuf in big endian. */
+ dqbuf = zerodqbuf;
+ dqbuf.dqb_id = OSSwapHostToBigInt32(fup->fu_id);
+ dqbuf.dqb_curinodes = OSSwapHostToBigInt32(fup->fu_curinodes);
+ dqbuf.dqb_curbytes = OSSwapHostToBigInt64(fup->fu_curbytes);
+ /* insert this dqb */
+ if (qfinsert(qfo, &dqbuf, m, shift)) {
+ i = FUHASH;
+ break;
+ }
+
+ dqbuftohost(&dqbuf);
+ (void) quotactl(fsname, QCMD(Q_SETUSE, type),
+ dqbuf.dqb_id, (caddr_t)&dqbuf);
+ ++idcnt;
+ }
+ }
+
+ /* Write the quota file header */
+ dqhdr.dqh_entrycnt = OSSwapHostToBigInt32(idcnt);
+ fseek(qfo, (long)0, SEEK_SET);
+ fwrite((char *)&dqhdr, sizeof(struct dqfilehdr), 1, qfo);
+
+ fclose(qfi);
+ fflush(qfo);
+ fclose(qfo);
+ return (0);
+}
+
+/* Convert a dqblk to host native byte order. */
+void
+dqbuftohost(struct dqblk *dqbp)
+{
+ dqbp->dqb_bhardlimit = OSSwapBigToHostInt64(dqbp->dqb_bhardlimit);
+ dqbp->dqb_bsoftlimit = OSSwapBigToHostInt64(dqbp->dqb_bsoftlimit);
+ dqbp->dqb_curbytes = OSSwapBigToHostInt64(dqbp->dqb_curbytes);
+ dqbp->dqb_ihardlimit = OSSwapBigToHostInt32(dqbp->dqb_ihardlimit);
+ dqbp->dqb_isoftlimit = OSSwapBigToHostInt32(dqbp->dqb_isoftlimit);
+ dqbp->dqb_curinodes = OSSwapBigToHostInt32(dqbp->dqb_curinodes);
+ dqbp->dqb_btime = OSSwapBigToHostInt32(dqbp->dqb_btime);
+ dqbp->dqb_itime = OSSwapBigToHostInt32(dqbp->dqb_itime);
+ dqbp->dqb_id = OSSwapBigToHostInt32(dqbp->dqb_id);
+}
+
+#else
+int
+update(fsname, quotafile, type)
+ char *fsname, *quotafile;
+ register int type;
+{
+ register struct fileusage *fup;
+ register FILE *qfi, *qfo;
+ register u_long id, lastid;
+ struct dqblk dqbuf;
+ static int warned = 0;
+ static struct dqblk zerodqbuf;
+ static struct fileusage zerofileusage;
+
+ if ((qfo = fopen(quotafile, "r+")) == NULL) {
+ if (errno == ENOENT)
+ qfo = fopen(quotafile, "w+");
+ if (qfo) {
+ (void) fprintf(stderr,
+ "quotacheck: creating quota file %s\n", quotafile);
+#define MODE (S_IRUSR|S_IWUSR|S_IRGRP)
+ (void) fchown(fileno(qfo), getuid(), getquotagid());
+ (void) fchmod(fileno(qfo), MODE);
+ } else {
+ (void) fprintf(stderr,
+ "quotacheck: %s: %s\n", quotafile, strerror(errno));
+ return (1);
+ }
+ }
+ if ((qfi = fopen(quotafile, "r")) == NULL) {
+ (void) fprintf(stderr,
+ "quotacheck: %s: %s\n", quotafile, strerror(errno));
+ (void) fclose(qfo);
+ return (1);
+ }
+ if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 &&
+ errno == ENOTSUP && !warned && vflag) {
+ warned++;
+ (void)printf("*** Warning: %s\n",
+ "Quotas are not compiled into this kernel");
+ }
+ for (lastid = highid[type], id = 0; id <= lastid; id++) {
+ if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0)
+ dqbuf = zerodqbuf;
+ if ((fup = lookup(id, type)) == 0)
+ fup = &zerofileusage;
+ if (dqbuf.dqb_curinodes == fup->fu_curinodes &&
+ dqbuf.dqb_curblocks == fup->fu_curblocks) {
+ fup->fu_curinodes = 0;
+ fup->fu_curblocks = 0;
+ fseek(qfo, (long)sizeof(struct dqblk), 1);
+ continue;
+ }
+ if (vflag) {
+ if (aflag)
+ printf("%s: ", fsname);
+ printf("%-8s fixed:", fup->fu_name);
+ if (dqbuf.dqb_curinodes != fup->fu_curinodes)
+ (void)printf("\tinodes %d -> %d",
+ dqbuf.dqb_curinodes, fup->fu_curinodes);
+ if (dqbuf.dqb_curblocks != fup->fu_curblocks)
+ (void)printf("\tblocks %d -> %d",
+ dqbuf.dqb_curblocks, fup->fu_curblocks);
+ (void)printf("\n");
+ }
+ /*
+ * Reset time limit if have a soft limit and were
+ * previously under it, but are now over it.
+ */
+ if (dqbuf.dqb_bsoftlimit &&
+ dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
+ fup->fu_curblocks >= dqbuf.dqb_bsoftlimit)
+ dqbuf.dqb_btime = 0;
+ if (dqbuf.dqb_isoftlimit &&
+ dqbuf.dqb_curblocks < dqbuf.dqb_isoftlimit &&
+ fup->fu_curblocks >= dqbuf.dqb_isoftlimit)
+ dqbuf.dqb_itime = 0;
+ dqbuf.dqb_curinodes = fup->fu_curinodes;
+ dqbuf.dqb_curblocks = fup->fu_curblocks;
+ fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo);
+ (void) quotactl(fsname, QCMD(Q_SETUSE, type), id,
+ (caddr_t)&dqbuf);
+ fup->fu_curinodes = 0;
+ fup->fu_curblocks = 0;
+ }
+ fclose(qfi);
+ fflush(qfo);
+ ftruncate(fileno(qfo),
+ (off_t)((highid[type] + 1) * sizeof(struct dqblk)));
+ fclose(qfo);
+ return (0);
+}
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+/*
+ * Insert an entry into a quota file.
+ *
+ * The dqblk pointed to by dqbp is in big endian.
+ */
+int
+qfinsert(file, dqbp, maxentries, shift)
+ FILE *file;
+ struct dqblk *dqbp;
+ int maxentries, shift;
+{
+ struct dqblk dqbuf;
+ int i, skip, last;
+ u_int32_t mask;
+ u_int32_t id;
+ off_t offset;
+
+ id = OSSwapBigToHostInt32(dqbp->dqb_id);
+ if (id == 0)
+ return (0);
+ mask = maxentries - 1;
+ i = dqhash1(id, dqhashshift(maxentries), mask);
+ skip = dqhash2(id, mask);
+
+ for (last = (i + (maxentries-1) * skip) & mask;
+ i != last;
+ i = (i + skip) & mask) {
+ offset = dqoffset(i);
+ fseek(file, (long)offset, SEEK_SET);
+ if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, file) == 0) {
+ fprintf(stderr, "quotacheck: read error at index %d\n", i);
+ return (EIO);
+ }
+ /*
+ * Stop when an empty entry is found
+ * or we encounter a matching id.
+ */
+ if (dqbuf.dqb_id == 0 || dqbuf.dqb_id == dqbp->dqb_id) {
+ dqbuf = *dqbp;
+ fseek(file, (long)offset, SEEK_SET);
+ fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, file);
+ return (0);
+ }
+ }
+ fprintf(stderr, "quotacheck: exceeded maximum entries (%d)\n", maxentries);
+ return (ENOSPC);
+}
+
+#define ONEGIGABYTE (1024*1024*1024)
+
+/*
+ * Calculate the size of the hash table from the size of
+ * the file system. The open addressing hashing used on
+ * the quota file assumes that this table will never be
+ * more than 90% full.
+ */
+int
+qfmaxentries(mntpt, type)
+ char *mntpt;
+ int type;
+{
+ struct statfs fs_stat;
+ u_int64_t fs_size;
+ int max = 0;
+
+ if (statfs(mntpt, &fs_stat)) {
+ fprintf(stderr, "quotacheck: %s: %s\n",
+ mntpt, strerror(errno));
+ return (0);
+ }
+ fs_size = (u_int64_t)fs_stat.f_blocks * (u_int64_t)fs_stat.f_bsize;
+
+ if (type == USRQUOTA) {
+ max = QF_USERS_PER_GB * (fs_size / ONEGIGABYTE);
+
+ if (max < QF_MIN_USERS)
+ max = QF_MIN_USERS;
+ else if (max > QF_MAX_USERS)
+ max = QF_MAX_USERS;
+ } else if (type == GRPQUOTA) {
+ max = QF_GROUPS_PER_GB * (fs_size / ONEGIGABYTE);
+
+ if (max < QF_MIN_GROUPS)
+ max = QF_MIN_GROUPS;
+ else if (max > QF_MAX_GROUPS)
+ max = QF_MAX_GROUPS;
+ }
+ /* Round up to a power of 2 */
+ if (max && !powerof2(max)) {
+ int x = max;
+ max = 4;
+ while (x>>1 != 1) {
+ x = x >> 1;
+ max = max << 1;
+ }
+ }
+ return (max);
+}
+#endif /* __APPLE__ */
+
+/*
+ * Check to see if target appears in list of size cnt.
+ */
+int
+oneof(target, list, cnt)
+ register char *target, *list[];
+ int cnt;
+{
+ register int i;
+
+ for (i = 0; i < cnt; i++)
+ if (strcmp(target, list[i]) == 0)
+ return (i);
+ return (-1);
+}
+
+/*
+ * Determine the group identifier for quota files.
+ */
+int
+getquotagid()
+{
+ struct group *gr;
+
+ if ((gr = getgrnam(quotagroup)))
+ return (gr->gr_gid);
+ return (-1);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+#ifdef __APPLE__
+int
+hasquota(fst, type, qfnamep)
+ struct statfs *fst;
+ int type;
+ char **qfnamep;
+{
+ struct stat sb;
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ (void)snprintf(usrname, sizeof(usrname),
+ "%s%s", qfextension[USRQUOTA], qfname);
+ (void)snprintf(grpname, sizeof(grpname),
+ "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+
+ /*
+ We only support the default path to the
+ on disk quota files.
+ */
+
+ (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname,
+ QUOTAOPSNAME, qfextension[type] );
+ if (stat(buf, &sb) != 0) {
+ /* There appears to be no mount option file */
+ return(0);
+ }
+
+ (void)snprintf(buf, sizeof(buf),
+ "%s/%s.%s", fst->f_mntonname, qfname, qfextension[type]);
+ *qfnamep = buf;
+
+ return (1);
+}
+#else
+int
+hasquota(fs, type, qfnamep)
+ register struct fstab *fs;
+ int type;
+ char **qfnamep;
+{
+ register char *opt;
+ char *cp;
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ (void)snprintf(usrname, sizeof(usrname),
+ "%s%s", qfextension[USRQUOTA], qfname);
+ (void)snprintf(grpname, sizeof(grpname),
+ "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ strlcpy(buf, fs->fs_mntops, sizeof(buf));
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if (cp = strchr(opt, '='))
+ *cp++ = '\0';
+ if (type == USRQUOTA && strcmp(opt, usrname) == 0)
+ break;
+ if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp)
+ *qfnamep = cp;
+ else {
+ (void)snprintf(buf, sizeof(buf),
+ "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
+ *qfnamep = buf;
+ }
+ return (1);
+}
+#endif /* __APPLE__ */
+
+/*
+ * Routines to manage the file usage table.
+ *
+ * Lookup an id of a specific type.
+ */
+struct fileusage *
+lookup(id, type)
+ u_long id;
+ int type;
+{
+ register struct fileusage *fup;
+
+ for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
+ if (fup->fu_id == id)
+ return (fup);
+ return (NULL);
+}
+
+/*
+ * Add a new file usage id if it does not already exist.
+ */
+#ifdef __APPLE__
+struct fileusage *
+addid(id, type)
+ uid_t id;
+ int type;
+{
+ struct fileusage *fup, **fhp;
+ struct passwd *pw;
+ struct group *gr;
+ char *name;
+ size_t len;
+
+ if ((fup = lookup(id, type)))
+ return (fup);
+
+ name = NULL;
+ len = 10;
+ switch (type) {
+ case USRQUOTA:
+ if ((pw = getpwuid(id)) != 0) {
+ name = pw->pw_name;
+ len = strlen(name);
+ }
+ break;
+ case GRPQUOTA:
+ if ((gr = getgrgid(id)) != 0) {
+ name = gr->gr_name;
+ len = strlen(name);
+ }
+ break;
+ }
+
+ if ((fup = calloc(1, sizeof(*fup) + len)) == NULL)
+ err(1, "%s", strerror(errno));
+ fhp = &fuhead[type][id & (FUHASH - 1)];
+ fup->fu_next = *fhp;
+ *fhp = fup;
+ fup->fu_id = id;
+ if (name)
+ memmove(fup->fu_name, name, len + 1);
+ else
+ (void)snprintf(fup->fu_name, len + 1, "%u", (unsigned int)id);
+
+ return (fup);
+}
+#else
+struct fileusage *
+addid(id, type, name)
+ u_long id;
+ int type;
+ char *name;
+{
+ struct fileusage *fup, **fhp;
+ int len;
+
+ if (fup = lookup(id, type))
+ return (fup);
+ if (name)
+ len = strlen(name);
+ else
+ len = 10;
+ if ((fup = calloc(1, sizeof(*fup) + len)) == NULL)
+ err(1, "%s", strerror(errno));
+ fhp = &fuhead[type][id & (FUHASH - 1)];
+ fup->fu_next = *fhp;
+ *fhp = fup;
+ fup->fu_id = id;
+ if (id > highid[type])
+ highid[type] = id;
+ if (name)
+ memmove(fup->fu_name, name, len + 1);
+ else
+ (void)snprintf(fup->fu_name, len + 1, "%u", id);
+ return (fup);
+}
+#endif /* __APPLE__ */
+
diff --git a/diskdev_cmds/quotacheck.tproj/quotacheck.h b/diskdev_cmds/quotacheck.tproj/quotacheck.h
new file mode 100644
index 0000000..da1bbdc
--- /dev/null
+++ b/diskdev_cmds/quotacheck.tproj/quotacheck.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+struct fileusage {
+ struct fileusage *fu_next;
+ u_int32_t fu_curinodes;
+ u_int64_t fu_curbytes;
+ u_int32_t fu_id;
+ char fu_checked;
+ char fu_name[1];
+ /* actually bigger */
+};
+
+
+extern int vflag; /* verbose mode */
+
+
+struct quotaname {
+ long flags;
+ char grpqfname[MAXPATHLEN + 1];
+ char usrqfname[MAXPATHLEN + 1];
+};
+#define HASUSR 1
+#define HASGRP 2
+
+
+extern struct fileusage *
+ addid(uid_t, int);
+extern int update(char *, char *, int);
+
+extern int chkquota_hfs(char *, char *, struct quotaname *);
diff --git a/diskdev_cmds/quotaon.tproj/quotaon.8 b/diskdev_cmds/quotaon.tproj/quotaon.8
new file mode 100644
index 0000000..a3bafe6
--- /dev/null
+++ b/diskdev_cmds/quotaon.tproj/quotaon.8
@@ -0,0 +1,159 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993, 2002
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)quotaon.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd October 17, 2002
+.Dt QUOTAON 8
+.Os BSD 4.2
+.Sh NAME
+.Nm quotaon ,
+.Nm quotaoff
+.Nd turn filesystem quotas on and off
+.Sh SYNOPSIS
+.Nm quotaon
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Ar filesystem Ar ...
+.Nm quotaon
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Fl a
+.Nm quotaoff
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Ar filesystem Ar ...
+.Nm quotaoff
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Fl a
+.Sh DESCRIPTION
+.Nm Quotaon
+announces to the system that disk quotas should be enabled on one or more
+filesystems.
+.Nm Quotaoff
+announces to the system that the specified
+filesystems should have disk quotas
+turned off.
+The filesystem must be mounted and it
+must have the
+appropriate mount option file located at its root, the
+.Pa .quota.ops.user
+file for user quota configuration, and the
+.Pa .quota.ops.group
+file for group quota configuration.
+.Nm Quotaon
+also expects each filesystem to have the appropriate
+quota data files located at its root, the
+.Pa .quota.user
+file for user data, and the
+.Pa .quota.group
+file for group data.
+These filenames and their root location cannot be overridden.
+By default,
+.Nm quotaon
+will attempt to enable both
+user and group quotas.
+By default,
+.Nm quotaoff
+will disable both
+user and group quotas.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl a
+If the
+.Fl a
+flag is supplied in place of any filesystem names,
+.Nm quotaon Ns / Ns Nm quotaoff
+will enable/disable any filesystems with an existing
+mount option file at its root. The mount option file
+specifies the types of quotas that are to be configured.
+.It Fl g
+Only group quotas will be enabled/disabled.
+The mount option file,
+.Pa .quota.ops.group ,
+must exist at the root of the filesystem.
+.It Fl u
+Only user quotas will be enabled/disabled.
+The mount option file,
+.Pa .quota.ops.user ,
+must exist at the root of the filesystem.
+.It Fl v
+Causes
+.Nm quotaon
+and
+.Nm quotaoff
+to print a message for each filesystem where quotas are turned on or off.
+.El
+.Pp
+Specifying both
+.Fl g
+and
+.Fl u
+is equivalent to the default.
+.Pp
+Quotas for both users and groups will automatically be turned
+on at filesystem mount if the appropriate mount option file
+and binary data file is in place at its root.
+.Sh FILES
+Each of the following quota files is located at the root of the
+mounted filesystem. The mount option files are empty files
+whose existence indicates that quotas are to be enabled
+for that filesystem.
+.Pp
+.Bl -tag -width .quota.ops.group -compact
+.It Pa .quota.user
+data file containing user quotas
+.It Pa .quota.group
+data file containing group quotas
+.It Pa .quota.ops.user
+mount option file used to enable user quotas
+.It Pa .quota.ops.group
+mount option file used to enable group quotas
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr quotactl 2 ,
+.Xr edquota 8 ,
+.Xr quotacheck 8 ,
+.Xr repquota 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/diskdev_cmds/quotaon.tproj/quotaon.c b/diskdev_cmds/quotaon.tproj/quotaon.c
new file mode 100644
index 0000000..a94be7b
--- /dev/null
+++ b/diskdev_cmds/quotaon.tproj/quotaon.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (c) 1999, 2002, 2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1980, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+__unused static char sccsid[] = "@(#)quotaon.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Turn quota on/off for a filesystem.
+ */
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/mount.h>
+#ifdef __APPLE__
+#include <sys/stat.h>
+#endif /* __APPLE__ */
+#include <sys/appleapiopts.h>
+#include <sys/quota.h>
+#include <stdio.h>
+#include <fstab.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Internal functions */
+void usage(char *whoami);
+
+char *qfname = QUOTAFILENAME;
+char *qfextension[] = INITQFNAMES;
+
+int aflag; /* all file systems */
+int gflag; /* operate on group quotas */
+int uflag; /* operate on user quotas */
+int vflag; /* verbose */
+
+/* Function prototypes */
+#ifdef __APPLE__
+int hasquota(register struct statfs *, int, char **);
+int quotaonoff(register struct statfs *, int, int, char *);
+#else
+int hasquota(register struct fstab *, int, char **);
+int quotaonoff(register struct fstab *, int, int, char *);
+#endif /* __APPLE__ */
+
+int oneof(register char *, register char **, int);
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char ch, *qfnp, *whoami, *rindex();
+ long argnum, done = 0;
+ int i, offmode = 0, errs = 0;
+#ifdef __APPLE__
+ int nfst;
+ struct statfs *fst;
+#endif /* __APPLE__ */
+
+ whoami = rindex(*argv, '/') + 1;
+ if (whoami == (char *)1)
+ whoami = *argv;
+ if (strcmp(whoami, "quotaoff") == 0)
+ offmode++;
+ else if (strcmp(whoami, "quotaon") != 0) {
+ fprintf(stderr, "Name must be quotaon or quotaoff not %s\n",
+ whoami);
+ exit(1);
+ }
+ while ((ch = getopt(argc, argv, "avug")) != EOF) {
+ switch(ch) {
+ case 'a':
+ aflag++;
+ break;
+ case 'g':
+ gflag++;
+ break;
+ case 'u':
+ uflag++;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage(whoami);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc <= 0 && !aflag)
+ usage(whoami);
+ if (!gflag && !uflag) {
+ gflag++;
+ uflag++;
+ }
+
+#ifdef __APPLE__
+ nfst = getmntinfo(&fst, MNT_WAIT);
+ if (nfst==0) {
+ fprintf(stderr, "no filesystems mounted");
+ return(1);
+ }
+
+ for (i=0; i<nfst; i++) {
+ if(strcmp(fst[i].f_fstypename, "hfs")) {
+ continue;
+ }
+ if(fst[i].f_flags & MNT_RDONLY) {
+ errs++;
+ continue;
+ }
+
+ if (aflag) {
+ if (gflag && hasquota(&fst[i], GRPQUOTA, &qfnp))
+ errs += quotaonoff(&fst[i], offmode, GRPQUOTA, qfnp);
+ if (uflag && hasquota(&fst[i], USRQUOTA, &qfnp))
+ errs += quotaonoff(&fst[i], offmode, USRQUOTA, qfnp);
+ continue;
+ }
+ if ((argnum = oneof(fst[i].f_mntonname, argv, argc)) >= 0 ||
+ (argnum = oneof(fst[i].f_mntfromname, argv, argc)) >= 0) {
+ done |= 1 << argnum;
+ if (gflag && hasquota(&fst[i], GRPQUOTA, &qfnp))
+ errs += quotaonoff(&fst[i], offmode, GRPQUOTA, qfnp);
+ if (uflag && hasquota(&fst[i], USRQUOTA, &qfnp))
+ errs += quotaonoff(&fst[i], offmode, USRQUOTA, qfnp);
+ }
+ }
+#else
+ register struct fstab *fs;
+ setfsent();
+ while ((fs = getfsent()) != NULL) {
+ if (strcmp(fs->fs_vfstype, "ufs") ||
+ strcmp(fs->fs_type, FSTAB_RW))
+ continue;
+ if (aflag) {
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
+ errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp))
+ errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
+ continue;
+ }
+ if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
+ (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
+ done |= 1 << argnum;
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
+ errs += quotaonoff(fs, offmode, GRPQUOTA, qfnp);
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp))
+ errs += quotaonoff(fs, offmode, USRQUOTA, qfnp);
+ }
+ }
+ endfsent();
+#endif /* __APPLE__ */
+ for (i = 0; i < argc; i++)
+ if ((done & (1 << i)) == 0)
+ fprintf(stderr, "%s not found in fstab\n",
+ argv[i]);
+ exit(errs);
+}
+
+void usage(whoami)
+ char *whoami;
+{
+
+ fprintf(stderr, "Usage:\n\t%s [-g] [-u] [-v] -a\n", whoami);
+ fprintf(stderr, "\t%s [-g] [-u] [-v] filesys ...\n", whoami);
+ exit(1);
+}
+
+#ifdef __APPLE__
+int quotaonoff(fst, offmode, type, qfpathname)
+ register struct statfs *fst;
+ int offmode, type;
+ char *qfpathname;
+{
+ if (strcmp(fst->f_mntonname, "/") && (fst->f_flags & MNT_RDONLY))
+ return (1);
+ if (offmode) {
+ if (quotactl(fst->f_mntonname, QCMD(Q_QUOTAOFF, type), 0, 0) < 0) {
+ fprintf(stderr, "quotaoff: ");
+ perror(fst->f_mntonname);
+ return (1);
+ }
+ if (vflag)
+ printf("%s: %s quotas turned off\n", fst->f_mntonname,
+ qfextension[type]);
+ return (0);
+ }
+ if (quotactl(fst->f_mntonname, QCMD(Q_QUOTAON, type), 0, qfpathname) < 0) {
+ fprintf(stderr, "quotaon: using %s on ", qfpathname);
+ perror(fst->f_mntonname);
+ return (1);
+ }
+ if (vflag)
+ printf("%s: %s quotas turned on\n", fst->f_mntonname,
+ qfextension[type]);
+ return (0);
+}
+#else
+int quotaonoff(fs, offmode, type, qfpathname)
+ register struct fstab *fs;
+ int offmode, type;
+ char *qfpathname;
+{
+
+ if (strcmp(fs->fs_file, "/") && readonly(fs))
+ return (1);
+ if (offmode) {
+ if (quotactl(fs->fs_file, QCMD(Q_QUOTAOFF, type), 0, 0) < 0) {
+ fprintf(stderr, "quotaoff: ");
+ perror(fs->fs_file);
+ return (1);
+ }
+ if (vflag)
+ printf("%s: quotas turned off\n", fs->fs_file);
+ return (0);
+ }
+ if (quotactl(fs->fs_file, QCMD(Q_QUOTAON, type), 0, qfpathname) < 0) {
+ fprintf(stderr, "quotaon: using %s on", qfpathname);
+ perror(fs->fs_file);
+ return (1);
+ }
+ if (vflag)
+ printf("%s: %s quotas turned on\n", fs->fs_file,
+ qfextension[type]);
+ return (0);
+}
+#endif /* __APPLE__ */
+
+/*
+ * Check to see if target appears in list of size cnt.
+ */
+int oneof(target, list, cnt)
+ register char *target, *list[];
+ int cnt;
+{
+ register int i;
+
+ for (i = 0; i < cnt; i++)
+ if (strcmp(target, list[i]) == 0)
+ return (i);
+ return (-1);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+#ifdef __APPLE__
+int hasquota(fst, type, qfnamep)
+ register struct statfs *fst;
+ int type;
+ char **qfnamep;
+{
+ struct stat sb;
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
+ snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+
+ /*
+ We only support the default path to the
+ on disk quota files.
+ */
+
+ (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname,
+ QUOTAOPSNAME, qfextension[type] );
+ if (stat(buf, &sb) != 0) {
+ /* There appears to be no mount option file */
+ return(0);
+ }
+
+
+ (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+#else
+int hasquota(fs, type, qfnamep)
+ register struct fstab *fs;
+ int type;
+ char **qfnamep;
+{
+ register char *opt;
+ char *cp, *index(), *strtok();
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
+ snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ strlcpy(buf, fs->fs_mntops, sizeof(buf));
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if (cp = index(opt, '='))
+ *cp++ = '\0';
+ if (type == USRQUOTA && strcmp(opt, usrname) == 0)
+ break;
+ if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+#endif /* __APPLE__ */
+
+
+/*
+ * Verify file system is mounted and not readonly.
+ */
+int readonly(fs)
+ register struct fstab *fs;
+{
+ struct statfs fsbuf;
+
+ if (statfs(fs->fs_file, &fsbuf) < 0 ||
+ strcmp(fsbuf.f_mntonname, fs->fs_file) ||
+ strcmp(fsbuf.f_mntfromname, fs->fs_spec)) {
+ printf("%s: not mounted\n", fs->fs_file);
+ return (1);
+ }
+ if (fsbuf.f_flags & MNT_RDONLY) {
+ printf("%s: mounted read-only\n", fs->fs_file);
+ return (1);
+ }
+ return (0);
+}
diff --git a/diskdev_cmds/repquota.tproj/repquota.8 b/diskdev_cmds/repquota.tproj/repquota.8
new file mode 100644
index 0000000..9b8a7b9
--- /dev/null
+++ b/diskdev_cmds/repquota.tproj/repquota.8
@@ -0,0 +1,109 @@
+.\" Copyright (c) 1983, 1990, 1991, 1993, 2002
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Robert Elz at The University of Melbourne.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)repquota.8 8.1 (Berkeley) 6/2/93
+.\"
+.Dd March 28, 2002
+.Dt REPQUOTA 8
+.Os BSD 4.2
+.Sh NAME
+.Nm repquota
+.Nd summarize quotas for a file system
+.Sh SYNOPSIS
+.Nm repquota
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Ar filesystem Ar ...
+.Nm repquota
+.Op Fl g
+.Op Fl u
+.Op Fl v
+.Fl a
+.Sh DESCRIPTION
+.Nm Repquota
+prints a summary of the disk usage and quotas for the
+specified file systems.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl a
+Print the quotas of all the filesystems configured with
+a quota mount option file at its root.
+.It Fl g
+Print only group quotas (the default is to print both
+group and user quotas if they exist).
+.It Fl u
+Print only user quotas (the default is to print both
+group and user quotas if they exist).
+.It Fl v
+Print a header line before printing each filesystem quotas.
+.El
+.Pp
+For each user or group, the current
+number of files and amount of space (in kilobytes) is
+printed, along with any quotas created with
+.Xr edquota 8 .
+.Pp
+Only members of the operator group or the super-user may
+use this command.
+.Sh FILES
+Each of the following quota files is located at the root of the
+mounted filesystem. The mount option files are empty files
+whose existence indicates that quotas are to be enabled
+for that filesystem.
+.Pp
+.Bl -tag -width .quota.ops.group -compact
+.It Pa .quota.user
+data file containing user quotas
+.It Pa .quota.group
+data file containing group quotas
+.It Pa .quota.ops.user
+mount option file used to enable user quotas
+.It Pa .quota.ops.group
+mount option file used to enable group quotas
+.El
+.Sh SEE ALSO
+.Xr quota 1 ,
+.Xr quotactl 2 ,
+.Xr edquota 8 ,
+.Xr quotacheck 8 ,
+.Xr quotaon 8
+.Sh DIAGNOSTICS
+Various messages about inaccessible files; self-explanatory.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/diskdev_cmds/repquota.tproj/repquota.c b/diskdev_cmds/repquota.tproj/repquota.c
new file mode 100644
index 0000000..87c1d8c
--- /dev/null
+++ b/diskdev_cmds/repquota.tproj/repquota.c
@@ -0,0 +1,630 @@
+/*
+ * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1980, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Robert Elz at The University of Melbourne.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1980, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+__unused static char sccsid[] = "@(#)repquota.c 8.2 (Berkeley) 11/22/94";
+#endif /* not lint */
+
+/*
+ * Quota report
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <sys/quota.h>
+
+#ifdef __APPLE__
+#include <sys/mount.h>
+#endif /* __APPLE__ */
+#include <errno.h>
+#include <fstab.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#endif /* __APPLE__ */
+
+char *qfname = QUOTAFILENAME;
+char *qfextension[] = INITQFNAMES;
+#ifdef __APPLE__
+u_int32_t quotamagic[MAXQUOTAS] = INITQMAGICS;
+#endif /* __APPLE__ */
+
+#ifndef __APPLE__
+struct fileusage {
+ struct fileusage *fu_next;
+ struct dqblk fu_dqblk;
+ u_long fu_id;
+ char fu_name[1];
+ /* actually bigger */
+};
+struct fileusage * addid(u_long, int);
+struct fileusage * lookup(u_long, int);
+
+#define FUHASH 1024 /* must be power of two */
+struct fileusage *fuhead[MAXQUOTAS][FUHASH];
+u_long highid[MAXQUOTAS]; /* highest addid()'ed identifier per type */
+#endif /* NOT __APPLE__ */
+
+int vflag; /* verbose */
+int aflag; /* all file systems */
+
+int hasquota(struct statfs *, int, char **);
+int repquota(struct statfs *, int, char *);
+int oneof(char *, char **, int);
+void usage(void);
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+#ifndef __APPLE__
+ register struct fstab *fs;
+ register struct passwd *pw;
+ register struct group *gr;
+#endif /* __APPLE__ */
+ int gflag = 0, uflag = 0, errs = 0;
+ long i, argnum, done = 0;
+#ifdef __APPLE__
+ int nfst;
+ struct statfs *fst;
+#endif /* __APPLE__ */
+ char ch, *qfnp;
+
+ while ((ch = getopt(argc, argv, "aguv")) != EOF) {
+ switch(ch) {
+ case 'a':
+ aflag++;
+ break;
+ case 'g':
+ gflag++;
+ break;
+ case 'u':
+ uflag++;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc == 0 && !aflag)
+ usage();
+ if (!gflag && !uflag) {
+ if (aflag)
+ gflag++;
+ uflag++;
+ }
+
+#ifdef __APPLE__
+ nfst = getmntinfo(&fst, MNT_WAIT);
+ if (nfst==0) {
+ fprintf(stderr, "repquota: no filesystems mounted");
+ return(1);
+ }
+
+ for (i=0; i<nfst; i++) {
+ if(strcmp(fst[i].f_fstypename, "hfs")) {
+ continue;
+ }
+ if (aflag) {
+ if (gflag && hasquota(&fst[i], GRPQUOTA, &qfnp))
+ errs += repquota(&fst[i], GRPQUOTA, qfnp);
+ if (uflag && hasquota(&fst[i], USRQUOTA, &qfnp))
+ errs += repquota(&fst[i], USRQUOTA, qfnp);
+ continue;
+ }
+ if ((argnum = oneof(fst[i].f_mntonname, argv, argc)) >= 0 ||
+ (argnum = oneof(fst[i].f_mntfromname, argv, argc)) >= 0) {
+ done |= 1 << argnum;
+ if (gflag && hasquota(&fst[i], GRPQUOTA, &qfnp))
+ errs += repquota(&fst[i], GRPQUOTA, qfnp);
+ if (uflag && hasquota(&fst[i], USRQUOTA, &qfnp))
+ errs += repquota(&fst[i], USRQUOTA, qfnp);
+ }
+ }
+#else
+ if (gflag) {
+ setgrent();
+ while ((gr = getgrent()) != 0)
+ (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name);
+ endgrent();
+ }
+ if (uflag) {
+ setpwent();
+ while ((pw = getpwent()) != 0)
+ (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name);
+ endpwent();
+ }
+
+ setfsent();
+ while ((fs = getfsent()) != NULL) {
+ if (strcmp(fs->fs_vfstype, "ufs"))
+ continue;
+ if (aflag) {
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
+ errs += repquota(fs, GRPQUOTA, qfnp);
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp))
+ errs += repquota(fs, USRQUOTA, qfnp);
+ continue;
+ }
+ if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
+ (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) {
+ done |= 1 << argnum;
+ if (gflag && hasquota(fs, GRPQUOTA, &qfnp))
+ errs += repquota(fs, GRPQUOTA, qfnp);
+ if (uflag && hasquota(fs, USRQUOTA, &qfnp))
+ errs += repquota(fs, USRQUOTA, qfnp);
+ }
+ }
+ endfsent();
+#endif /* __APPLE */
+ for (i = 0; i < argc; i++)
+ if ((done & (1 << i)) == 0)
+ fprintf(stderr, "%s not found in fstab\n", argv[i]);
+ exit(errs);
+}
+
+void
+usage()
+{
+ fprintf(stderr, "Usage:\n\t%s\n\t%s\n",
+ "repquota [-v] [-g] [-u] -a",
+ "repquota [-v] [-g] [-u] filesys ...");
+ exit(1);
+}
+
+#ifdef __APPLE__
+int
+repquota(fst, type, qfpathname)
+ struct statfs *fst;
+ int type;
+ char *qfpathname;
+{
+ FILE *qf;
+ uid_t id;
+ struct dqblk dqbuf;
+ char *timeprt();
+ char *name;
+ struct dqfilehdr dqhdr;
+ static int warned = 0;
+ static int multiple = 0;
+ extern int errno;
+ int i;
+ struct passwd *pw;
+ struct group *gr;
+ int maxentries;
+ u_int64_t bsoftlimit;
+ u_int32_t isoftlimit;
+ u_int64_t curbytes;
+ u_int32_t curinodes;
+
+
+ if (quotactl(fst->f_mntonname, QCMD(Q_SYNC, type), 0, 0) < 0 &&
+ errno == ENOTSUP && !warned && vflag) {
+ warned++;
+ fprintf(stdout,
+ "*** Warning: Quotas are not compiled into this kernel\n");
+ }
+ if (multiple++)
+ printf("\n");
+ if (vflag)
+ fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
+ qfextension[type], fst->f_mntonname, fst->f_mntfromname);
+ if ((qf = fopen(qfpathname, "r")) == NULL) {
+ perror(qfpathname);
+ return (1);
+ }
+
+ /* Read in the quota file header. */
+ if (fread((char *)&dqhdr, sizeof(struct dqfilehdr), 1, qf) > 0) {
+ /* Check for non big endian file. */
+ if (OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type] &&
+ OSSwapInt32(dqhdr.dqh_magic) == quotamagic[type]) {
+ (void) fprintf(stderr,
+ "*** Error: %s: not in big endian byte order\n", qfpathname);
+ (void) fclose(qf);
+ return (1);
+ }
+ /* Sanity check the quota file header. */
+ if ((OSSwapBigToHostInt32(dqhdr.dqh_magic) != quotamagic[type]) ||
+ (OSSwapBigToHostInt32(dqhdr.dqh_version) > QF_VERSION) ||
+ (!powerof2(OSSwapBigToHostInt32(dqhdr.dqh_maxentries)))) {
+ (void) fprintf(stderr,
+ "repquota: %s: not a valid quota file\n", qfpathname);
+ (void) fclose(qf);
+ return (1);
+ }
+ }
+
+ printf(" 1K Block limits File limits\n");
+ printf("User used soft hard grace used soft hard grace\n");
+
+ maxentries = OSSwapBigToHostInt32(dqhdr.dqh_maxentries);
+
+ /* Read the entries in the quota file. */
+ for (i = 0; i < maxentries; i++) {
+ if (fread(&dqbuf, sizeof(struct dqblk), 1, qf) == 0 && feof(qf))
+ break;
+ id = OSSwapBigToHostInt32(dqbuf.dqb_id);
+ if (id == 0)
+ continue;
+ if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curbytes == 0LL)
+ continue;
+ name = NULL;
+ switch (type) {
+ case USRQUOTA:
+ if ((pw = getpwuid(id)) != 0)
+ name = pw->pw_name;
+ break;
+ case GRPQUOTA:
+ if ((gr = getgrgid(id)) != 0)
+ name = gr->gr_name;
+ break;
+ }
+ if (name)
+ printf("%-10s", name);
+ else
+ printf("%-10u", (unsigned int)id);
+
+ bsoftlimit = OSSwapBigToHostInt64( dqbuf.dqb_bsoftlimit );
+ isoftlimit = OSSwapBigToHostInt32( dqbuf.dqb_isoftlimit );
+ curbytes = OSSwapBigToHostInt64( dqbuf.dqb_curbytes );
+ curinodes = OSSwapBigToHostInt32( dqbuf.dqb_curinodes );
+
+ printf("%c%c%12qd%12qd%12qd%7s",
+ bsoftlimit &&
+ curbytes >=
+ bsoftlimit ? '+' : '-',
+ isoftlimit &&
+ curinodes >=
+ isoftlimit ? '+' : '-',
+ curbytes / 1024,
+ bsoftlimit / 1024,
+ OSSwapBigToHostInt64( dqbuf.dqb_bhardlimit ) / 1024,
+ bsoftlimit &&
+ curbytes >=
+ bsoftlimit ?
+ timeprt(OSSwapBigToHostInt32(dqbuf.dqb_btime)) : "");
+ printf(" %6d%6d%6d%7s\n",
+ curinodes,
+ isoftlimit,
+ OSSwapBigToHostInt32( dqbuf.dqb_ihardlimit ),
+ isoftlimit &&
+ curinodes >=
+ isoftlimit ?
+ timeprt(OSSwapBigToHostInt32(dqbuf.dqb_itime)) : "");
+ }
+ fclose(qf);
+
+ return (0);
+}
+#else
+repquota(fs, type, qfpathname)
+ register struct fstab *fs;
+ int type;
+ char *qfpathname;
+{
+ register struct fileusage *fup;
+ FILE *qf;
+ u_long id;
+ struct dqblk dqbuf;
+ char *timeprt();
+ static struct dqblk zerodqblk;
+ static int warned = 0;
+ static int multiple = 0;
+ extern int errno;
+
+ if (quotactl(fs->fs_file, QCMD(Q_SYNC, type), 0, 0) < 0 &&
+ errno == ENOTSUP && !warned && vflag) {
+ warned++;
+ fprintf(stdout,
+ "*** Warning: Quotas are not compiled into this kernel\n");
+ }
+ if (multiple++)
+ printf("\n");
+ if (vflag)
+ fprintf(stdout, "*** Report for %s quotas on %s (%s)\n",
+ qfextension[type], fs->fs_file, fs->fs_spec);
+ if ((qf = fopen(qfpathname, "r")) == NULL) {
+ perror(qfpathname);
+ return (1);
+ }
+ for (id = 0; ; id++) {
+ fread(&dqbuf, sizeof(struct dqblk), 1, qf);
+ if (feof(qf))
+ break;
+ if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0)
+ continue;
+ if ((fup = lookup(id, type)) == 0)
+ fup = addid(id, type, (char *)0);
+ fup->fu_dqblk = dqbuf;
+ }
+ fclose(qf);
+ printf(" Block limits File limits\n");
+ printf("User used soft hard grace used soft hard grace\n");
+
+ for (id = 0; id <= highid[type]; id++) {
+ fup = lookup(id, type);
+ if (fup == 0)
+ continue;
+ if (fup->fu_dqblk.dqb_curinodes == 0 &&
+ fup->fu_dqblk.dqb_curblocks == 0)
+ continue;
+ printf("%-10s", fup->fu_name);
+ printf("%c%c%8d%8d%8d%7s",
+ fup->fu_dqblk.dqb_bsoftlimit &&
+ fup->fu_dqblk.dqb_curblocks >=
+ fup->fu_dqblk.dqb_bsoftlimit ? '+' : '-',
+ fup->fu_dqblk.dqb_isoftlimit &&
+ fup->fu_dqblk.dqb_curinodes >=
+ fup->fu_dqblk.dqb_isoftlimit ? '+' : '-',
+ dbtob(fup->fu_dqblk.dqb_curblocks) / 1024,
+ dbtob(fup->fu_dqblk.dqb_bsoftlimit) / 1024,
+ dbtob(fup->fu_dqblk.dqb_bhardlimit) / 1024,
+ fup->fu_dqblk.dqb_bsoftlimit &&
+ fup->fu_dqblk.dqb_curblocks >=
+ fup->fu_dqblk.dqb_bsoftlimit ?
+ timeprt(fup->fu_dqblk.dqb_btime) : "");
+ printf(" %6d%6d%6d%7s\n",
+ fup->fu_dqblk.dqb_curinodes,
+ fup->fu_dqblk.dqb_isoftlimit,
+ fup->fu_dqblk.dqb_ihardlimit,
+ fup->fu_dqblk.dqb_isoftlimit &&
+ fup->fu_dqblk.dqb_curinodes >=
+ fup->fu_dqblk.dqb_isoftlimit ?
+ timeprt(fup->fu_dqblk.dqb_itime) : "");
+ fup->fu_dqblk = zerodqblk;
+ }
+ return (0);
+}
+#endif /* __APPLE */
+
+/*
+ * Check to see if target appears in list of size cnt.
+ */
+int
+oneof(target, list, cnt)
+ register char *target, **list;
+ int cnt;
+{
+ register int i;
+
+ for (i = 0; i < cnt; i++)
+ if (strcmp(target, list[i]) == 0)
+ return (i);
+ return (-1);
+}
+
+/*
+ * Check to see if a particular quota is to be enabled.
+ */
+#ifdef __APPLE__
+int
+hasquota(fst, type, qfnamep)
+ register struct statfs *fst;
+ int type;
+ char **qfnamep;
+{
+ struct stat sb;
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ snprintf(usrname, sizeof(usrname), "%s%s", qfextension[USRQUOTA], qfname);
+ snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+
+ /*
+ We only support the default path to the
+ on disk quota files.
+ */
+
+ (void)snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname,
+ QUOTAOPSNAME, qfextension[type] );
+ if (stat(buf, &sb) != 0) {
+ /* There appears to be no mount option file */
+ return(0);
+ }
+
+ (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fst->f_mntonname, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+#else
+hasquota(fs, type, qfnamep)
+ register struct fstab *fs;
+ int type;
+ char **qfnamep;
+{
+ register char *opt;
+ char *cp, *index(), *strtok();
+ static char initname, usrname[100], grpname[100];
+ static char buf[BUFSIZ];
+
+ if (!initname) {
+ snprintf(usrname, sizoef(usrname), "%s%s", qfextension[USRQUOTA], qfname);
+ snprintf(grpname, sizeof(grpname), "%s%s", qfextension[GRPQUOTA], qfname);
+ initname = 1;
+ }
+ strlcpy(buf, fs->fs_mntops, sizeof(buf));
+ for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
+ if (cp = index(opt, '='))
+ *cp++ = '\0';
+ if (type == USRQUOTA && strcmp(opt, usrname) == 0)
+ break;
+ if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
+ break;
+ }
+ if (!opt)
+ return (0);
+ if (cp) {
+ *qfnamep = cp;
+ return (1);
+ }
+ (void) snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file, qfname, qfextension[type]);
+ *qfnamep = buf;
+ return (1);
+}
+#endif /* __APPLE__ */
+
+
+#ifndef __APPLE__
+
+/*
+ * Routines to manage the file usage table.
+ *
+ * Lookup an id of a specific type.
+ */
+struct fileusage *
+lookup(id, type)
+ u_long id;
+ int type;
+{
+ register struct fileusage *fup;
+
+ for (fup = fuhead[type][id & (FUHASH-1)]; fup != 0; fup = fup->fu_next)
+ if (fup->fu_id == id)
+ return (fup);
+ return ((struct fileusage *)0);
+}
+
+/*
+ * Add a new file usage id if it does not already exist.
+ */
+struct fileusage *
+addid(id, type, name)
+ u_long id;
+ int type;
+ char *name;
+{
+ struct fileusage *fup, **fhp;
+ int len;
+ extern char *calloc();
+
+ if (fup = lookup(id, type))
+ return (fup);
+ if (name)
+ len = strlen(name);
+ else
+ len = 10;
+ if ((fup = (struct fileusage *)calloc(1, sizeof(*fup) + len)) == NULL) {
+ fprintf(stderr, "out of memory for fileusage structures\n");
+ exit(1);
+ }
+ fhp = &fuhead[type][id & (FUHASH - 1)];
+ fup->fu_next = *fhp;
+ *fhp = fup;
+ fup->fu_id = id;
+ if (id > highid[type])
+ highid[type] = id;
+ if (name) {
+ bcopy(name, fup->fu_name, len + 1);
+ } else {
+ snprintf(fup->fu_name, len + 1, "%u", id);
+ }
+ return (fup);
+}
+#endif /* !__APPLE__ */
+
+/*
+ * Calculate the grace period and return a printable string for it.
+ */
+char *
+timeprt(seconds)
+ time_t seconds;
+{
+ time_t hours, minutes;
+ static char buf[20];
+ static time_t now;
+
+ if (now == 0)
+ time(&now);
+ if (now > seconds)
+ return ("none");
+ seconds -= now;
+ minutes = (seconds + 30) / 60;
+ hours = (minutes + 30) / 60;
+ if (hours >= 36) {
+ snprintf(buf, sizeof(buf), "%lddays", (hours + 12) / 24);
+ return (buf);
+ }
+ if (minutes >= 60) {
+ snprintf(buf, sizeof(buf), "%2ld:%ld", minutes / 60, minutes % 60);
+ return (buf);
+ }
+ snprintf(buf, sizeof(buf), "%2ld", minutes);
+ return (buf);
+}
diff --git a/diskdev_cmds/setclass.tproj/setclass.8 b/diskdev_cmds/setclass.tproj/setclass.8
new file mode 100644
index 0000000..90d0c80
--- /dev/null
+++ b/diskdev_cmds/setclass.tproj/setclass.8
@@ -0,0 +1,46 @@
+.\" Copyright (c) 2010-2012 Apple Inc. All rights reserved.
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @(#)setclass.8
+.Dd June 20, 2012
+.Dt SETCLASS 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm setclass
+.Nd content protection utility
+.Sh SYNOPSIS
+.Nm setclass
+.Ar file
+.Op A-E
+.Sh DESCRIPTION
+.Pp
+The
+.Nm
+utility sets and gets the content protection class of a given file.
+.Pp
+If a class from A to E is specified,
+.Nm
+will attempt to set
+.Ar file
+to that class.
+If no class is given,
+.Nm
+will report the current protection class of
+.Ar file.
+.Pp
+Note that the ability to change the content protection class of a file is restricted by the
+runtime status of the device in question. If the device is locked with a PIN code, then
+you may not be able to modify the protection class, even as root.
diff --git a/diskdev_cmds/setclass.tproj/setclass.c b/diskdev_cmds/setclass.tproj/setclass.c
new file mode 100644
index 0000000..306547b
--- /dev/null
+++ b/diskdev_cmds/setclass.tproj/setclass.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2010-2020 Apple Inc. All rights reserved.
+ */
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/attr.h>
+
+/* from sys/cprotect.h */
+
+#define PROTECTION_CLASS_A 1
+#define PROTECTION_CLASS_B 2
+#define PROTECTION_CLASS_C 3
+#define PROTECTION_CLASS_D 4
+#define PROTECTION_CLASS_E 5
+#define PROTECTION_CLASS_F 6
+
+void
+usage(void)
+{
+ printf("usage: setclass <path> [A-F]\n");
+ printf("\tsets <path> to a protection class from A to F.\n");
+ printf("\tIf no class is specified, reports the current class for <path>.\n");
+ exit(0);
+}
+
+int
+chartoclass(char c)
+{
+ switch (c) {
+ /* directory 'unset' operation */
+ case '0':
+ return 0;
+ case 'A':
+ case 'a':
+ return PROTECTION_CLASS_A;
+ case 'B':
+ case 'b':
+ return PROTECTION_CLASS_B;
+ case 'C':
+ case 'c':
+ return PROTECTION_CLASS_C;
+ case 'D':
+ case 'd':
+ return PROTECTION_CLASS_D;
+ case 'E':
+ case 'e':
+ return PROTECTION_CLASS_E;
+ case 'F':
+ case 'f':
+ return PROTECTION_CLASS_F;
+ default:
+ usage();
+ exit(0);
+ }
+ return 0;
+}
+
+char
+classtochar(int class)
+{
+ if (class < 0) {
+ /* negative classes are invalid */
+ return -1;
+ }
+
+ /* otherwise, it must be >= 0... */
+ if (class == 0) {
+ /* Directories are allowed to be "unset" */
+ return 0;
+ }
+ return 'A' + (class - 1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int error = 0, class = 0, do_set = 0;
+ static struct attrlist req = {
+ .bitmapcount = ATTR_BIT_MAP_COUNT,
+ .commonattr = ATTR_CMN_DATA_PROTECT_FLAGS
+ };
+
+ if ((argc < 2) || (argc > 3))
+ usage();
+
+ if (argv[2]) {
+ do_set = 1;
+ class = chartoclass(*argv[2]);
+ }
+
+ /*
+ * setclass and getclass for `argv[1]` using setattrlist(2) and
+ * getattrlist(2) respectively.
+ */
+ if (do_set) {
+ struct {
+ uint32_t prot_class;
+ } __attribute__((packed, aligned(4))) attrs = {
+ .prot_class = class
+ };
+
+ error = setattrlist(argv[1], (void *)&req, &attrs, sizeof(attrs),
+ FSOPT_NOFOLLOW);
+ if (error) {
+ char new_class = classtochar(class);
+ if (new_class == 0) {
+ warn("could not set protection class of %s to (directory none)",
+ argv[1]);
+ }
+ else {
+ warn("could not set protection class of %s to %c", argv[1],
+ new_class);
+ }
+ }
+ }
+ else {
+ req.commonattr |= ATTR_CMN_RETURNED_ATTRS;
+
+ struct {
+ uint32_t len;
+ attribute_set_t returned;
+ uint32_t prot_class;
+ } __attribute__((packed, aligned(4))) attrs;
+
+ error = getattrlist(argv[1], (void *)&req, &attrs, sizeof(attrs),
+ FSOPT_NOFOLLOW);
+ if (error == -1 || attrs.len != sizeof(attrs) ||
+ attrs.returned.commonattr != req.commonattr) {
+ if (error == -1) {
+ error = errno;
+ }
+ else {
+ error = EINVAL;
+ }
+ err(error, "could not get protection class");
+ }
+ else {
+ class = attrs.prot_class;
+ char new_class = classtochar(class);
+ if (new_class == 0) {
+ printf("%s is in protection class (directory none) \n", argv[1]);
+ }
+ else {
+ printf("%s is in protection class %c\n", argv[1], new_class);
+ }
+ }
+ }
+
+ return error;
+}
diff --git a/diskdev_cmds/umount.tproj/umount.8 b/diskdev_cmds/umount.tproj/umount.8
new file mode 100644
index 0000000..b914134
--- /dev/null
+++ b/diskdev_cmds/umount.tproj/umount.8
@@ -0,0 +1,133 @@
+.\" Copyright (c) 1980, 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)umount.8 8.2 (Berkeley) 5/8/95
+.\"
+.Dd May 8, 1995
+.Dt UMOUNT 8
+.Os BSD 4
+.Sh NAME
+.Nm umount
+.Nd unmount filesystems
+.Sh SYNOPSIS
+.Nm umount
+.Op Fl fv
+.Ar special | node
+.Nm umount
+.Fl a | A
+.Op Fl fv
+.Op Fl h Ar host
+.Op Fl t Ar type
+.Sh DESCRIPTION
+The
+.Nm umount
+command
+calls the
+.Xr unmount 2
+system call to remove a
+.Ar "special device"
+or the remote node (rhost:path) from the filesystem tree at the point
+.Ar node .
+If either
+.Ar special
+or
+.Ar node
+are not provided, the appropriate information is taken from the
+list of filesystems provided by
+.Xr getfsent 3 .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a
+All the filesystems described via
+.Xr getfsent 3
+are unmounted.
+.It Fl A
+All the currently mounted filesystems except
+the root are unmounted.
+.It Fl f
+The filesystem is forcibly unmounted.
+Active special devices continue to work,
+but all other files return errors if further accesses are attempted.
+The root filesystem cannot be forcibly unmounted.
+.It Fl h Ar host
+Only filesystems mounted from the specified host will be
+unmounted.
+This option implies the
+.Fl A
+option and, unless otherwise specified with the
+.Fl t
+option, will only unmount NFS filesystems.
+.It Fl t Ar type
+Is used to indicate the actions should only be taken on
+filesystems of the specified type.
+More than one type may be specified in a comma separated list.
+The list of filesystem types can be prefixed with
+.Dq no
+to specify the filesystem types for which action should
+.Em not
+be taken.
+For example, the
+.Nm umount
+command:
+.Bd -literal -offset indent
+umount -A -t nfs,hfs
+.Ed
+.Pp
+umounts all currently-mounted filesystems of the type
+.Tn NFS
+and
+.Tn HFS .
+(The
+.Fl a
+option only unmounts entries in the
+.Pa /etc/fstab
+list.)
+.It Fl v
+Verbose, additional information is printed out as each filesystem
+is unmounted.
+.El
+.Sh NOTES
+Due to the complex and interwoven nature of Mac OS X,
+.Nm umount
+may fail often. It is recommended that
+.Xr diskutil 1
+(as in, ``diskutil unmount /mnt'') be used instead.
+.Sh SEE ALSO
+.Xr unmount 2 ,
+.Xr getfsent 3 ,
+.Xr mount 8 ,
+.Xr diskutil 1
+.Sh HISTORY
+A
+.Nm umount
+command appeared in
+.At v6 .
diff --git a/diskdev_cmds/umount.tproj/umount.c b/diskdev_cmds/umount.tproj/umount.c
new file mode 100644
index 0000000..26e9ba4
--- /dev/null
+++ b/diskdev_cmds/umount.tproj/umount.c
@@ -0,0 +1,655 @@
+#ifndef _DARWIN_USE_64_BIT_INODE
+# define _DARWIN_USE_64_BIT_INODE 1
+#endif
+/*
+ * Copyright (c) 1999-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1980, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <System/sys/fsctl.h>
+
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <fstab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <pthread.h>
+
+#include "../edt_fstab/edt_fstab.h"
+
+struct syncarg {
+ const char *mntname;
+ int wakeup_flag;
+ pthread_cond_t *wakeup_cond;
+ pthread_mutex_t *wakeup_lock;
+};
+
+typedef enum { MNTON, MNTFROM } mntwhat;
+
+int fake, fflag, vflag;
+char *nfshost;
+
+int checkvfsname(const char *, char **);
+char *getmntname(const char *, mntwhat, char **);
+int getmntfsid(const char *, fsid_t *);
+int sysctl_fsid(int, fsid_t *, void *, size_t *, void *, size_t);
+int unmount_by_fsid(const char *mntpt, int flag);
+char **makevfslist(char *);
+int selected(int);
+int namematch(struct hostent *);
+int umountall(char **);
+int umountfs(char *, char **);
+void usage(void);
+
+static void*
+syncit(void *vap) {
+ int rv;
+ pthread_mutex_t *lock;
+ int full_sync = FSCTL_SYNC_WAIT;
+ struct syncarg *args = vap;
+
+ rv = fsctl(args->mntname, FSIOC_SYNC_VOLUME, &full_sync, 0);
+ if (rv == -1) {
+#ifdef DEBUG
+ warn("fsctl %s", args->mntname);
+#endif
+ }
+
+ lock = args->wakeup_lock;
+ (void)pthread_mutex_lock(lock);
+ args->wakeup_flag = 1;
+ pthread_cond_signal(args->wakeup_cond);
+ (void)pthread_mutex_unlock(lock);
+
+ return NULL;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int all, ch, errs, mnts;
+ char **typelist = NULL;
+ struct statfs *mntbuf;
+
+ /*
+ * We used to call sync(2) here, but this should be unneccessary
+ * given that a sync occurs at a more proper level (VFS_SYNC()
+ * in dounmount() in the non-forced unmount case).
+ *
+ * We add the sync() back in for the -f case below to cover the
+ * situation where the filesystem was mounted RW and force
+ * unmounted when it really didn't have to be.
+ *
+ * See 5328558 for some context.
+ */
+
+ all = 0;
+ while ((ch = getopt(argc, argv, "AaFfh:t:v")) != EOF)
+ switch (ch) {
+ case 'A':
+ all = 2;
+ break;
+ case 'a':
+ all = 1;
+ break;
+ case 'F':
+ fake = 1;
+ break;
+ case 'f':
+ fflag = MNT_FORCE;
+ break;
+ case 'h': /* -h implies -A. */
+ all = 2;
+ nfshost = optarg;
+ break;
+ case 't':
+ if (typelist != NULL)
+ errx(1, "only one -t option may be specified.");
+ typelist = makevfslist(optarg);
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ((argc == 0 && !all) || (argc != 0 && all))
+ usage();
+
+ /* -h implies "-t nfs" if no -t flag. */
+ if ((nfshost != NULL) && (typelist == NULL))
+ typelist = makevfslist("nfs");
+
+ if (fflag & MNT_FORCE) {
+ /*
+ * If we really mean business, we don't want to get hung up on
+ * any remote file systems. So, we set the "noremotehang" flag.
+ */
+ pid_t pid;
+ pid = getpid();
+ errs = sysctlbyname("vfs.generic.noremotehang", NULL, NULL, &pid, sizeof(pid));
+ if ((errs != 0) && vflag)
+ warn("sysctl vfs.generic.noremotehang");
+ }
+
+ errs = EXIT_SUCCESS;
+ switch (all) {
+ case 2:
+ if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
+ warn("getmntinfo");
+ errs = 1;
+ break;
+ }
+ for (errs = 0, mnts--; mnts > 0; mnts--) {
+ if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
+ continue;
+ if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
+ errs = 1;
+ }
+ break;
+ case 1:
+ if ((setfsent() == 0)) {
+ fprintf(stderr, "Can't get filesystem checklist: %s\n", strerror(errno));
+ exit(1);
+ }
+ errs = umountall(typelist);
+ break;
+ case 0:
+ for (errs = 0; *argv != NULL; ++argv)
+ if (umountfs(*argv, typelist) != 0)
+ errs = 1;
+ break;
+ }
+ exit(errs);
+}
+
+int
+umountall(char **typelist)
+{
+ struct fstab *fs;
+ int rval;
+ size_t cp_len;
+ char *cp;
+
+ while ((fs = getfsent()) != NULL) {
+ /* Ignore the root. */
+ if (strcmp(fs->fs_file, "/") == 0)
+ continue;
+ /*
+ * !!!
+ * Historic practice: ignore unknown FSTAB_* fields.
+ */
+ if (strcmp(fs->fs_type, FSTAB_RW) &&
+ strcmp(fs->fs_type, FSTAB_RO) &&
+ strcmp(fs->fs_type, FSTAB_RQ))
+ continue;
+#if 0
+ /* If an unknown file system type, complain. */
+ if (getvfsbyname(fs->fs_vfstype, &vfc) < 0) {
+ warnx("%s: unknown mount type `%s'", fs->fs_spec, fs->fs_vfstype);
+ continue;
+ }
+ if (checkvfsname(fs->fs_vfstype, typelist))
+ continue;
+#endif
+
+ /*
+ * We want to unmount the file systems in the reverse order
+ * that they were mounted. So, we save off the file name
+ * in some allocated memory, and then call recursively.
+ */
+ cp_len = (size_t)strlen(fs->fs_file) + 1;
+ if ((cp = malloc(cp_len)) == NULL)
+ err(1, NULL);
+ (void)strlcpy(cp, fs->fs_file, cp_len);
+ rval = umountall(typelist);
+ rval = umountfs(cp, typelist) || rval;
+ free(cp);
+ return (rval);
+ }
+ return (0);
+}
+
+int
+umountfs(char *name, char **typelist)
+{
+ struct hostent *hp, *hp6;
+ struct stat sb;
+ int isftpfs, errnum;
+ char *type, *delimp, *hostname, *mntpt, rname[MAXPATHLEN], *tname;
+ char *pname = name; /* save the name parameter */
+
+ /*
+ * First directly check the
+ * current mount list for a match. If we find it,
+ * we skip the realpath()/stat() below.
+ */
+ tname = name;
+ /* check if name is a non-device "mount from" name */
+ if ((mntpt = getmntname(tname, MNTON, &type)) == NULL) {
+ /* or if name is a mounted-on directory */
+ mntpt = tname;
+ tname = getmntname(mntpt, MNTFROM, &type);
+ }
+ if (mntpt && tname) {
+ if (fflag & MNT_FORCE) {
+ /*
+ * The bulk of this block is to try to do a sync on the filesystem
+ * being unmounted. We want to do this in another thread, so we
+ * can avoid blocking for a hardware or network reason. We will
+ * wait 10 seconds for the sync to finish; after that, we just
+ * ignore it and go ahead with the unmounting.
+ *
+ * We only want to do this in the event of a forced unmount.
+ */
+ int rv;
+ pthread_t tid;
+ pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+ pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+ struct syncarg args;
+ struct timespec timeout;
+
+ /* we found a match */
+ name = tname;
+
+ args.mntname = mntpt;
+ args.wakeup_flag = 0;
+ args.wakeup_cond = &cond;
+ args.wakeup_lock = &lock;
+
+ timeout.tv_sec = time(NULL) + 10; /* Wait 10 seconds */
+ timeout.tv_nsec = 0;
+
+ rv = pthread_create(&tid, NULL, &syncit, &args);
+ if (rv == 0 && pthread_mutex_lock(&lock) == 0) {
+ while (args.wakeup_flag == 0 && rv == 0)
+ rv = pthread_cond_timedwait(&cond, &lock, &timeout);
+
+ /* If this fails, not much we can do at this point... */
+ (void)pthread_mutex_unlock(&lock);
+ if (rv != 0) {
+ errno = rv;
+ warn("pthread_cond_timeout failed; continuing with unmount");
+ }
+ }
+ }
+ goto got_mount_point;
+ }
+
+ /*
+ * Note: in the face of path resolution errors (realpath/stat),
+ * we just try using the name passed in as is.
+ */
+ /* even if path resolution succeeds, but can't find mountpoint
+ * with the resolved path, we still want to try using the name
+ * as passed in.
+ */
+
+ if (realpath(name, rname) == NULL) {
+ if (vflag)
+ warn("realpath(%s)", rname);
+ } else {
+ name = rname;
+ }
+
+ /* we could just try MNTON and MNTFROM on name and again (if
+ * name is not the passed in param) MNTON and MNTFROM on
+ * pname.
+ *
+ * but we stat(name) here to avoid umounting the wrong thing
+ * if the mount table has an entry with the MNTFROM that is
+ * the same as the MNTON in another entry.
+ */
+
+ if (stat(name, &sb) < 0) {
+ if (vflag)
+ warn("stat(%s)", name);
+ /* maybe name is a non-device "mount from" name? */
+ if ((mntpt = getmntname(name, MNTON, &type)))
+ goto got_mount_point;
+ mntpt = name;
+ /* or name is a directory we simply can't reach? */
+ if ((name = getmntname(mntpt, MNTFROM, &type)))
+ goto got_mount_point;
+ } else if (S_ISBLK(sb.st_mode)) {
+ if ((mntpt = getmntname(name, MNTON, &type)))
+ goto got_mount_point;
+ } else if (S_ISDIR(sb.st_mode)) {
+ mntpt = name;
+ if ((name = getmntname(mntpt, MNTFROM, &type)))
+ goto got_mount_point;
+ } else {
+ warnx("%s: not a directory or special device", name);
+ }
+
+ /* haven't found mountpoint.
+ *
+ * if we were not using the name as passed in, then try using it.
+ */
+ if ((NULL == name) || (strcmp(name, pname) != 0)) {
+ name = pname;
+
+ if ((mntpt = getmntname(name, MNTON, &type)))
+ goto got_mount_point;
+ mntpt = name;
+ if ((name = getmntname(mntpt, MNTFROM, &type)))
+ goto got_mount_point;
+ }
+
+ warnx("%s: not currently mounted", pname);
+ return (1);
+
+got_mount_point:
+
+ if (checkvfsname(type, typelist))
+ return (1);
+
+ if (!strncmp("ftp://", name, 6))
+ isftpfs = 1;
+ else
+ isftpfs = 0;
+
+ hp = hp6 = NULL;
+ delimp = NULL;
+ if (nfshost && !strcmp(type, "nfs") && !isftpfs) {
+ /*
+ * Parse the NFS host out of the name.
+ *
+ * If it starts with '[' then skip IPv6 literal characters
+ * until we find ']'. If we find other characters (or the
+ * closing ']' isn't followed by a ':', then don't consider
+ * it to be an IPv6 literal address.
+ *
+ * Scan the name string to find ":/" (or just ":"). The name
+ * is the portion of the string preceding the first ":/" (or ":").
+ */
+ char *p, *colon, *colonslash, c;
+ hostname = colon = colonslash = NULL;
+ p = name;
+ if (*p == '[') { /* Looks like an IPv6 literal address */
+ p++;
+ while (isxdigit(*p) || (*p == ':')) {
+ if (*p == ':') {
+ if (!colon)
+ colon = p;
+ if (!colonslash && (*(p+1) == '/'))
+ colonslash = p;
+ }
+ p++;
+ }
+ if ((*p == ']') && (*(p+1) == ':')) {
+ /* Found "[IPv6]:", double check that it's acceptable and use it. */
+ struct sockaddr_in6 sin6;
+ c = *p;
+ *p = '\0';
+ if (inet_pton(AF_INET6, name+1, &sin6))
+ hostname = name + 1;
+ *p = c;
+ }
+ }
+ /* if hostname not found yet, search for ":/" and ":" */
+ while (!hostname && *p && (!colon || !colonslash)) {
+ if (*p == ':') {
+ if (!colon)
+ colon = p;
+ if (!colonslash && (*(p+1) == '/'))
+ colonslash = p;
+ }
+ p++;
+ }
+ if (!hostname && (colonslash || colon)) {
+ /* host name is the string preceding the colon(slash) */
+ hostname = name;
+ if (colonslash)
+ p = colonslash;
+ else if (colon)
+ p = colon;
+ }
+ if (hostname) {
+ c = *p;
+ *p = '\0';
+ /* we just want all the names/aliases */
+ hp = getipnodebyname(hostname, AF_INET, 0, &errnum);
+ hp6 = getipnodebyname(hostname, AF_INET6, 0, &errnum);
+ *p = c;
+ }
+ }
+
+ if (nfshost && (hp || hp6)) {
+ int match = (namematch(hp) || namematch(hp6));
+ if (hp)
+ freehostent(hp);
+ if (hp6)
+ freehostent(hp6);
+ if (!match)
+ return (1);
+ }
+
+ if (vflag)
+ (void)printf("%s unmount from %s\n", name, mntpt);
+ if (fake)
+ return (0);
+
+ if (unmount(mntpt, fflag) < 0) {
+ /*
+ * If we're root and it looks like the error is that the
+ * mounted on directory is just not reachable or if we really
+ * want this filesystem unmounted (MNT_FORCE), then try doing
+ * the unmount by fsid. (Note: the sysctl only works for root)
+ */
+ if ((getuid() == 0) &&
+ ((errno == ESTALE) || (errno == ENOENT) || (fflag & MNT_FORCE))) {
+ if (vflag)
+ warn("unmount(%s)", mntpt);
+ if (unmount_by_fsid(mntpt, fflag) < 0) {
+ warn("unmount(%s)", mntpt);
+ return (1);
+ }
+ } else if (errno == EBUSY) {
+ fprintf(stderr, "umount(%s): %s -- try 'diskutil unmount'\n", mntpt, strerror(errno));
+ return (1);
+ } else {
+ warn("unmount(%s)", mntpt);
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+static struct statfs *mntbuf;
+static int mntsize;
+
+char *
+getmntname(const char *name, mntwhat what, char **type)
+{
+ int i;
+
+ if (mntbuf == NULL &&
+ (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
+ warn("getmntinfo");
+ return (NULL);
+ }
+ for (i = mntsize-1; i >= 0; i--) {
+ if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
+ if (type)
+ *type = mntbuf[i].f_fstypename;
+ return (mntbuf[i].f_mntonname);
+ }
+ if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
+ if (type)
+ *type = mntbuf[i].f_fstypename;
+ return (mntbuf[i].f_mntfromname);
+ }
+ }
+ return (NULL);
+}
+
+int
+getmntfsid(const char *name, fsid_t *fsid)
+{
+ int i;
+
+ if (mntbuf == NULL &&
+ (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
+ warn("getmntinfo");
+ return (-1);
+ }
+ for (i = mntsize-1; i >= 0; i--) {
+ if (!strcmp(mntbuf[i].f_mntonname, name)) {
+ *fsid = mntbuf[i].f_fsid;
+ return (0);
+ }
+ }
+ return (-1);
+}
+
+int
+namematch(struct hostent *hp)
+{
+ char *cp, **np;
+
+ if (nfshost == NULL)
+ return (1);
+
+ if (hp == NULL)
+ return (0);
+
+ if (strcasecmp(nfshost, hp->h_name) == 0)
+ return (1);
+
+ if ((cp = strchr(hp->h_name, '.')) != NULL) {
+ *cp = '\0';
+ if (strcasecmp(nfshost, hp->h_name) == 0)
+ return (1);
+ }
+ for (np = hp->h_aliases; *np; np++) {
+ if (strcasecmp(nfshost, *np) == 0)
+ return (1);
+ if ((cp = strchr(*np, '.')) != NULL) {
+ *cp = '\0';
+ if (strcasecmp(nfshost, *np) == 0)
+ return (1);
+ }
+ }
+ return (0);
+}
+
+
+int
+sysctl_fsid(
+ int op,
+ fsid_t *fsid,
+ void *oldp,
+ size_t *oldlenp,
+ void *newp,
+ size_t newlen)
+{
+ int ctlname[CTL_MAXNAME+2];
+ size_t ctllen;
+ const char *sysstr = "vfs.generic.ctlbyfsid";
+ struct vfsidctl vc;
+
+ ctllen = CTL_MAXNAME+2;
+ if (sysctlnametomib(sysstr, ctlname, &ctllen) == -1) {
+ warn("sysctlnametomib(%s)", sysstr);
+ return (-1);
+ };
+ ctlname[ctllen] = op;
+
+ bzero(&vc, sizeof(vc));
+ vc.vc_vers = VFS_CTL_VERS1;
+ vc.vc_fsid = *fsid;
+ vc.vc_ptr = newp;
+ vc.vc_len = newlen;
+ return (sysctl(ctlname, (uint32_t)(ctllen + 1), oldp, oldlenp, &vc, sizeof(vc)));
+}
+
+
+int
+unmount_by_fsid(const char *mntpt, int flag)
+{
+ fsid_t fsid;
+ if (getmntfsid(mntpt, &fsid) < 0)
+ return (-1);
+ if (vflag)
+ printf("attempting to unmount %s by fsid\n", mntpt);
+ return sysctl_fsid(VFS_CTL_UMOUNT, &fsid, NULL, 0, &flag, sizeof(flag));
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: %s\n %s\n",
+ "umount [-fv] [-t fstypelist] special | node",
+ "umount -a[fv] [-h host] [-t fstypelist]");
+ exit(1);
+}
diff --git a/diskdev_cmds/vndevice.tproj/vndevice.c b/diskdev_cmds/vndevice.tproj/vndevice.c
new file mode 100644
index 0000000..9610ddf
--- /dev/null
+++ b/diskdev_cmds/vndevice.tproj/vndevice.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * History:
+ * March 25, 2002 Dieter Siegmund (dieter@apple.com)
+ * - created
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioccom.h>
+#include <sys/vnioctl.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <mach/boolean.h>
+#include <sys/disk.h>
+
+void
+usage()
+{
+ fprintf(stderr, "usage: vncontrol <command> <args>\n"
+ "vncontrol attach <dev_node> <image_file>\n"
+ "vncontrol shadow <dev_node> <shadow_file>\n"
+ "vncontrol detach <dev_node>\n");
+ exit(1);
+}
+
+enum {
+ kAttach,
+ kDetach,
+ kShadow,
+};
+
+int
+main(int argc, char * argv[])
+{
+ int fd;
+ struct vn_ioctl vn;
+ int op = kAttach;
+ struct stat sb;
+
+ if (argc < 2) {
+ usage();
+ }
+ if (strcmp(argv[1], "attach") == 0) {
+ if (argc < 4) {
+ usage();
+ }
+ op = kAttach;
+ }
+ else if (strcmp(argv[1], "detach") == 0) {
+ if (argc < 3) {
+ usage();
+ }
+ op = kDetach;
+ }
+ else if (strcmp(argv[1], "shadow") == 0) {
+ if (argc < 4) {
+ usage();
+ }
+ op = kShadow;
+ }
+ else {
+ usage();
+ }
+ fd = open(argv[2], O_RDONLY, 0);
+ if (fd < 0) {
+ perror(argv[2]);
+ exit(2);
+ }
+ switch (op) {
+ case kAttach:
+ case kShadow:
+ if (stat(argv[3], &sb) < 0) {
+ perror(argv[3]);
+ exit(2);
+ }
+ break;
+ default:
+ break;
+ }
+ bzero(&vn, sizeof(vn));
+ switch (op) {
+ case kAttach:
+ vn.vn_file = argv[3];
+ vn.vn_control = vncontrol_readwrite_io_e;
+
+ if (ioctl(fd, VNIOCATTACH, &vn) < 0) {
+ perror("VNIOCATTACH");
+ exit(2);
+ }
+ break;
+ case kDetach:
+ if (ioctl(fd, VNIOCDETACH, &vn) < 0) {
+ perror("VNIOCDETACH");
+ exit(2);
+ }
+ break;
+ case kShadow:
+ vn.vn_file = argv[3];
+ if (ioctl(fd, VNIOCSHADOW, &vn) < 0) {
+ perror("VNIOCSHADOW");
+ exit(2);
+ }
+ break;
+ }
+ close(fd);
+ exit(0);
+ return (0);
+}
diff --git a/diskdev_cmds/vsdbutil.tproj/com.apple.vsdbutil.plist b/diskdev_cmds/vsdbutil.tproj/com.apple.vsdbutil.plist
new file mode 100644
index 0000000..18bf10e
--- /dev/null
+++ b/diskdev_cmds/vsdbutil.tproj/com.apple.vsdbutil.plist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.vsdbutil</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/sbin/vsdbutil</string>
+ <string>-i</string>
+ </array>
+ <key>KeepAlive</key>
+ <dict>
+ <key>PathState</key>
+ <dict>
+ <key>/var/db/volinfo.database</key>
+ <false/>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/diskdev_cmds/vsdbutil.tproj/vsdbutil.8 b/diskdev_cmds/vsdbutil.tproj/vsdbutil.8
new file mode 100644
index 0000000..1be7d10
--- /dev/null
+++ b/diskdev_cmds/vsdbutil.tproj/vsdbutil.8
@@ -0,0 +1,49 @@
+.Dd December 19, 2001
+.Dt VSDBUTIL 8
+.Os Darwin
+.Sh NAME
+.Nm vsdbutil
+.Nd manipulates the volume status DB.
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar path
+.Pp
+.Nm
+.Op Fl c Ar path
+.Op Fl d Ar path
+.Op Fl i
+.Pp
+.Nm
+.Op Fl h
+.Sh DESCRIPTION
+.Nm
+manipulates the volume status DB.
+The following options are available:
+.Bl -tag -width -indent
+.It Fl a
+adopts (activates) on-disk ownership on the specified path
+.It Fl c
+checks the status of the ownership usage on the specified path
+.It Fl d
+disowns (deactivates) the on-disk ownership on the specified path
+.It Fl i
+initializes the ownership database to include all mounted HFS+ and APFS volumes
+.It Fl h
+prints out a simple help message
+.El
+.Pp
+The
+.Nm
+command is deprecated; using a volume UUID in
+.Xr fstab 5
+is preferred.
+.Sh FILES
+.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
+.It Pa /var/db/volinfo.database
+Database of volumes managed via
+.Nm .
+.El
+.Sh SEE ALSO
+.Xr diskutil 8 ,
+.Xr mount 8 ,
+.Xr fstab 5
diff --git a/diskdev_cmds/vsdbutil.tproj/vsdbutil_main.c b/diskdev_cmds/vsdbutil.tproj/vsdbutil_main.c
new file mode 100644
index 0000000..c9647fe
--- /dev/null
+++ b/diskdev_cmds/vsdbutil.tproj/vsdbutil_main.c
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (c) 2000-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ About vsdbutil.c:
+ Contains code to manipulate the volume status DB (/var/db/volinfo.database).
+
+ Change History:
+ 18-Apr-2000 Pat Dirks New Today.
+
+ */
+
+
+/* ************************************** I N C L U D E S ***************************************** */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/ucred.h>
+#include <sys/resource.h>
+#include <sys/vmmeter.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <err.h>
+#include <errno.h>
+#include <dirent.h>
+#include <strings.h>
+
+#include <sys/attr.h>
+#include <uuid/uuid.h>
+#include <System/uuid/namespace.h>
+
+// This flags array is shared with the mount(8) tool.
+#include "../mount_flags_dir/mount_flags.h"
+
+//from mount_flags_dir/mount_flags.c
+extern mountopt_t optnames[];
+
+
+/*
+ * CommonCrypto is meant to be a more stable API than OpenSSL.
+ * Defining COMMON_DIGEST_FOR_OPENSSL gives API-compatibility
+ * with OpenSSL, so we don't have to change the code.
+ */
+#define COMMON_DIGEST_FOR_OPENSSL
+#include <CommonCrypto/CommonDigest.h>
+#include <libkern/OSByteOrder.h>
+
+static char usage[] = "Usage: %s [-a path] | [-c path ] [-d path] [-i]\n";
+
+static char gHFSTypeName[] = "hfs";
+static char gAPFSTypeName[] = "apfs";
+
+/*****************************************************************************
+ *
+ * The following should really be in some system header file:
+ *
+ *****************************************************************************/
+
+typedef struct VolumeUUID {
+ uuid_t uuid;
+} VolumeUUID;
+
+#define VOLUMEUUID64LENGTH 16
+
+#define VOLUME_USEPERMISSIONS 0x00000001
+#define VOLUME_VALIDSTATUSBITS ( VOLUME_USEPERMISSIONS )
+
+typedef void *VolumeStatusDBHandle;
+
+void ConvertVolumeUUIDString64ToUUID(const char *UUIDString64, VolumeUUID *volumeID);
+
+int OpenVolumeStatusDB(VolumeStatusDBHandle *DBHandlePtr);
+int ConvertVolumeStatusDB(VolumeStatusDBHandle DBHandle);
+int GetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID, u_int32_t *VolumeStatus);
+int SetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID, u_int32_t VolumeStatus);
+int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID);
+int CloseVolumeStatusDB(VolumeStatusDBHandle DBHandle);
+
+/*****************************************************************************
+ *
+ * Internal function prototypes:
+ *
+ *****************************************************************************/
+
+static void check_uid(void);
+static int GetVolumeUUID(const char *path, VolumeUUID *volumeUUIDPtr);
+static int AdoptAllLocalVolumes(void);
+static int AdoptVolume(const char *path);
+static int DisownVolume(const char *path);
+static int ClearVolumeUUID(const char *path);
+static int DisplayVolumeStatus(const char *path);
+static int UpdateMountStatus(const char *path, u_int32_t volstatus);
+
+
+static int isVolumeHFS(const char*path);
+
+int main (int argc, const char *argv[])
+{
+ int arg;
+ char option;
+ int result = 0;
+
+ if (argc < 2) {
+ fprintf(stderr, usage, argv[0]);
+ exit(1);
+ };
+
+ for (arg = 1; arg < argc; ++arg) {
+ if ((argv[arg][0] == '-') &&
+ ((option = argv[arg][1]) != (char)0) &&
+ (argv[arg][2] == (char)0)) {
+ switch (option) {
+ case 'a':
+ case 'A':
+ /* Pick out the pathname argument: */
+ if (++arg >= argc) {
+ fprintf(stderr, usage, argv[0]);
+ exit(1);
+ }
+
+ check_uid();
+ result = AdoptVolume(argv[arg]);
+ break;
+
+ case 'c':
+ case 'C':
+ /* Pick out the pathname argument: */
+ if (++arg >= argc) {
+ fprintf(stderr, usage, argv[0]);
+ exit(1);
+ };
+
+ result = DisplayVolumeStatus(argv[arg]);
+ break;
+
+ case 'd':
+ case 'D':
+ /* Pick out the pathname argument: */
+ if (++arg >= argc) {
+ fprintf(stderr, usage, argv[0]);
+ exit(1);
+ };
+
+ check_uid();
+ result = DisownVolume(argv[arg]);
+ break;
+
+ case 'h':
+ case 'H':
+ printf(usage, argv[0]);
+ printf("where\n");
+ printf("\t-a adopts (activates) on-disk permissions on the specified path,\n");
+ printf("\t-c checks the status of the permissions usage on the specified path\n");
+ printf("\t-d disowns (deactivates) the on-disk permissions on the specified path\n");
+ printf("\t-i initializes the permissions database to include all mounted HFS/HFS+ volumes\n");
+ break;
+
+ case 'i':
+ case 'I':
+ check_uid();
+ result = AdoptAllLocalVolumes();
+ break;
+
+ case 'x':
+ case 'X':
+ /* Pick out the pathname argument: */
+ if (++arg >= argc) {
+ fprintf(stderr, usage, argv[0]);
+ exit(1);
+ };
+
+ check_uid();
+ result = ClearVolumeUUID(argv[arg]);
+ break;
+
+ default:
+ fprintf(stderr, usage, argv[0]);
+ exit(1);
+ }
+ }
+ }
+
+ if (result < 0) result = 1; // Make sure only positive exit status codes are generated
+
+ exit(result); // ensure the process exit status is returned
+ return result; // ...and make main fit the ANSI spec.
+}
+
+
+
+static void check_uid(void) {
+ if (geteuid() != 0) {
+ fprintf(stderr, "###\n");
+ fprintf(stderr, "### You must be root to perform this operation.\n");
+ fprintf(stderr, "###\n");
+ exit(1);
+ };
+}
+
+
+
+/*
+ -- UpdateMountStatus
+ --
+ -- Returns: error code (0 if successful).
+ */
+static int
+UpdateMountStatus(const char *path, u_int32_t volstatus) {
+ struct statfs mntstat;
+ int result;
+ union wait status;
+ int pid;
+
+ /*
+ * selectors to determine whether or not certain features
+ * should be re-enabled via mount -u
+ */
+#ifndef MAXMOUNTLEN
+#define MAXMOUNTLEN 255
+#endif
+
+ char mountline[MAXMOUNTLEN];
+ char mountstring[MAXMOUNTLEN];
+
+ mountopt_t* opt = NULL;
+ uint64_t flags;
+ uint64_t flags_mask = (MNT_NOSUID | MNT_NODEV |
+ MNT_NOEXEC | MNT_RDONLY |
+ MNT_CPROTECT | MNT_QUARANTINE |
+ MNT_UNION | MNT_DONTBROWSE);
+
+ result = statfs(path, &mntstat);
+ if (result != 0) {
+ warn("couldn't look up mount status for '%s'", path);
+ return errno;
+ }
+
+ bzero (mountline, MAXMOUNTLEN);
+ bzero (mountstring, MAXMOUNTLEN);
+
+ /* first, check for permissions */
+ if (volstatus & VOLUME_USEPERMISSIONS) {
+ strlcpy(mountline, "perm", MAXMOUNTLEN);
+ }
+ else {
+ strlcpy(mountline, "noperm", MAXMOUNTLEN);
+ }
+
+ /* check the flags */
+ flags = (mntstat.f_flags & flags_mask);
+
+ /*
+ * now iterate over all of the strings in the optname array and
+ * add them into the "mount" string if the flag they represent is set.
+ * The optnames array is extern'd (at the top of this file), and is defined
+ * in a .c file within the mount_flags directory
+ */
+ for (opt = optnames; flags && opt->o_opt; opt++) {
+ if ((flags & opt->o_opt) && opt->o_cmd) {
+ snprintf(mountstring, sizeof(mountstring), ",%s", opt->o_cmd);
+ result = strlcat(mountline, mountstring, MAXMOUNTLEN);
+ if (result >= MAXMOUNTLEN) {
+ // bail out, string is too long.
+ return EINVAL;
+ }
+ flags &= ~opt->o_opt;
+ bzero (mountstring, MAXMOUNTLEN);
+ }
+ }
+
+#ifdef MAXMOUNTLEN
+#undef MAXMOUNTLEN
+#endif
+
+ pid = fork();
+ if (pid == 0) {
+ result = execl("/sbin/mount", "mount",
+ "-t", mntstat.f_fstypename,
+ "-u","-o", mountline,
+ mntstat.f_mntfromname, mntstat.f_mntonname, NULL);
+ /* IF WE ARE HERE, WE WERE UNSUCCESFULL */
+ return (1);
+ }
+
+ if (pid == -1) {
+ warn("couldn't fork to execute mount command");
+ return errno;
+ };
+
+ /* Success! */
+ if ((wait4(pid, (int *)&status, 0, NULL) == pid) && (WIFEXITED(status))) {
+ result = status.w_retcode;
+ } else {
+ result = -1;
+ };
+
+ return result;
+}
+
+
+
+/*
+ -- AdoptAllLocalVolumes
+ --
+ -- Returns: error code (0 if successful).
+ */
+static int
+AdoptAllLocalVolumes(void) {
+ struct statfs *mntstatptr;
+ int fscount;
+
+ fscount = getmntinfo(&mntstatptr, MNT_WAIT);
+ if (fscount == 0) {
+ warn("couldn't get information on mounted volumes");
+ return errno;
+ };
+
+ while (fscount > 0) {
+ if ((strncmp(mntstatptr->f_fstypename, gHFSTypeName, MFSNAMELEN) == 0) ||
+ (strncmp(mntstatptr->f_fstypename, gAPFSTypeName, MFSNAMELEN) == 0)) {
+ (void)AdoptVolume(mntstatptr->f_mntonname);
+ };
+
+ ++mntstatptr;
+ --fscount;
+ };
+
+ return 0;
+}
+
+
+
+/*
+ -- AdoptVolume
+ --
+ -- Returns: error code (0 if successful).
+ */
+static int
+AdoptVolume(const char *path) {
+ VolumeUUID targetuuid;
+ VolumeStatusDBHandle vsdb;
+ u_int32_t volstatus;
+ int result = 0;
+
+ /* Look up the target volume UUID: */
+ result = GetVolumeUUID(path, &targetuuid);
+ if (result != 0) {
+ warnx("no valid volume UUID found on '%s': %s", path, strerror(result));
+ return result;
+ };
+
+ if (uuid_is_null(targetuuid.uuid)) {
+ warnx("internal error: incomplete UUID generated.");
+ return EINVAL;
+ };
+
+ /* Open the volume status DB to look up the entry for the volume in question: */
+ if ((result = OpenVolumeStatusDB(&vsdb)) != 0) {
+ warnx("couldn't access volume status database: %s", strerror(result));
+ return result;
+ };
+
+ /* Check to see if an entry exists. If not, prepare a default initial status value: */
+ if ((result = GetVolumeStatusDBEntry(vsdb, &targetuuid, &volstatus)) != 0) {
+ volstatus = 0;
+ };
+
+ /* Enable permissions on the specified volume: */
+ volstatus = (volstatus & VOLUME_VALIDSTATUSBITS) | VOLUME_USEPERMISSIONS;
+
+ /* Update the entry in the volume status database: */
+ if ((result = SetVolumeStatusDBEntry(vsdb, &targetuuid, volstatus)) != 0) {
+ warnx("couldn't update volume status database: %s", strerror(result));
+ return result;
+ };
+
+ (void)CloseVolumeStatusDB(vsdb);
+
+ if ((result = UpdateMountStatus(path, volstatus)) != 0) {
+ warnx("couldn't update mount status of '%s': %s", path, strerror(result));
+ return result;
+ };
+
+ return 0;
+}
+
+
+
+/*
+ -- DisownVolume
+ --
+ -- Returns: error code (0 if successful).
+ */
+static int
+DisownVolume(const char *path) {
+ VolumeUUID targetuuid;
+ VolumeStatusDBHandle vsdb;
+ u_int32_t volstatus;
+ int result = 0;
+
+ /* Look up the target volume UUID: */
+ result = GetVolumeUUID(path, &targetuuid);
+ if (result != 0) {
+ warnx("no valid volume UUID found on '%s': %s", path, strerror(result));
+ return result;
+ };
+
+ volstatus = 0;
+ if (!uuid_is_null(targetuuid.uuid)) {
+ /* Open the volume status DB to look up the entry for the volume in question: */
+ if ((result = OpenVolumeStatusDB(&vsdb)) != 0) {
+ warnx("couldn't access volume status database: %s", strerror(result));
+ return result;
+ };
+
+ /* Check to see if an entry exists. If not, prepare a default initial status value: */
+ if ((result = GetVolumeStatusDBEntry(vsdb, &targetuuid, &volstatus)) != 0) {
+ volstatus = 0;
+ };
+
+ /* Disable permissions on the specified volume: */
+ volstatus = (volstatus & VOLUME_VALIDSTATUSBITS) & ~VOLUME_USEPERMISSIONS;
+
+ /* Update the entry in the volume status database: */
+ if ((result = SetVolumeStatusDBEntry(vsdb, &targetuuid, volstatus)) != 0) {
+ warnx("couldn't update volume status database: %s", strerror(result));
+ return result;
+ };
+
+ (void)CloseVolumeStatusDB(vsdb);
+
+ };
+
+ if ((result = UpdateMountStatus(path, volstatus)) != 0) {
+ warnx("couldn't update mount status of '%s': %s", path, strerror(result));
+ return result;
+ };
+
+ return result;
+};
+
+
+
+/*
+ -- ClearVolumeUUID
+ --
+ -- Returns: error code (0 if successful).
+ */
+static int
+ClearVolumeUUID(const char *path) {
+ VolumeUUID targetuuid;
+ VolumeStatusDBHandle vsdb;
+ u_int32_t volstatus;
+ int result = 0;
+
+ /* Check to see whether the target volume has an assigned UUID: */
+ result = GetVolumeUUID(path, &targetuuid);
+ if (result != 0) {
+ warnx("couldn't read volume UUID on '%s': %s", path, strerror(result));
+ return result;
+ };
+
+ if (uuid_is_null(targetuuid.uuid) == 0) {
+ /* Open the volume status DB to look up the entry for the volume in question: */
+ if ((result = OpenVolumeStatusDB(&vsdb)) != 0) {
+ warnx("couldn't access volume status database: %s", strerror(result));
+ return result;
+ };
+
+ /* Check to see if an entry exists: */
+ if (GetVolumeStatusDBEntry(vsdb, &targetuuid, &volstatus) == 0) {
+ /* Remove the entry from the volume status database: */
+ if ((result = DeleteVolumeStatusDBEntry(vsdb, &targetuuid)) != 0) {
+ warnx("couldn't update volume status database: %s", strerror(result));
+ return result;
+ };
+ };
+
+ (void)CloseVolumeStatusDB(vsdb);
+
+ if ((result = UpdateMountStatus(path, 0)) != 0) {
+ warnx("couldn't update mount status of '%s': %s", path, strerror(result));
+ return result;
+ };
+
+ };
+
+ return result;
+};
+
+
+
+/*
+ -- DisplayVolumeStatus
+ --
+ -- Returns: error code (0 if successful).
+ */
+static int
+DisplayVolumeStatus(const char *path) {
+ VolumeUUID targetuuid;
+ VolumeStatusDBHandle vsdb;
+ u_int32_t volstatus;
+ int result = 0;
+
+ /* Look up the target volume UUID, exactly as stored on disk: */
+ result = GetVolumeUUID(path, &targetuuid);
+ if (result != 0) {
+ warnx("couldn't read volume UUID on '%s': %s", path, strerror(result));
+ return result;
+ };
+
+ if (uuid_is_null(targetuuid.uuid)) {
+ warnx("no valid volume UUID found on '%s': permissions are disabled.", path);
+ return 0;
+ };
+
+ /* Open the volume status DB to look up the entry for the volume in question: */
+ if ((result = OpenVolumeStatusDB(&vsdb)) != 0) {
+ warnx("couldn't access volume status database: %s", strerror(result));
+ return result;
+ };
+
+ if ((result = GetVolumeStatusDBEntry(vsdb, &targetuuid, &volstatus)) != 0) {
+ printf("No entry found for '%s'.\n", path);
+ goto Std_Exit;
+ };
+
+ if (volstatus & VOLUME_USEPERMISSIONS) {
+ printf("Permissions on '%s' are enabled.\n", path);
+ } else {
+ printf("Permissions on '%s' are disabled.\n", path);
+ };
+
+Std_Exit:
+ (void)CloseVolumeStatusDB(vsdb);
+
+ return result;
+}
+
+static int isVolumeHFS (const char* path) {
+
+ /* default to no */
+ int result = 0;
+ int isHFS = 0;
+
+ struct statfs statfs_buf;
+
+ result = statfs (path, &statfs_buf);
+ if (result == 0) {
+ if (!strncmp(statfs_buf.f_fstypename, gHFSTypeName, 3)) {
+ isHFS = 1;
+ }
+ }
+
+ return isHFS;
+}
+
+
+
+//struct definition for calling getattrlist for finderinfos
+typedef struct FinderInfoBuf {
+ uint32_t info_length;
+ uint32_t finderinfo[8];
+} FinderInfoBuf_t;
+
+typedef struct hfsUUID {
+ uint32_t high;
+ uint32_t low;
+} hfsUUID_t;
+
+/*
+ -- GetVolumeUUID
+ --
+ -- Returns: error code (0 if successful).
+ */
+
+static int
+GetVolumeUUID(const char *path, VolumeUUID *volumeUUIDPtr) {
+ struct attrlist alist;
+ struct { uint32_t size; uuid_t uuid; } volUUID;
+
+ FinderInfoBuf_t finfo;
+
+ int result;
+
+ /*
+ * For a bit more definition on why we have to do this, check out
+ * hfs.util source. The gist is that IFF the volume is HFS, then
+ * we must check the finderinfo UUID FIRST before querying the
+ * fs for its full UUID via the getattrlist volume call.
+ */
+
+ if (isVolumeHFS(path)) {
+ /* then go get the finderinfo, first... */
+ memset (&alist, 0, sizeof(alist));
+ alist.bitmapcount = ATTR_BIT_MAP_COUNT;
+ alist.reserved = 0;
+ alist.commonattr = ATTR_CMN_FNDRINFO;
+ alist.volattr = ATTR_VOL_INFO;
+ alist.dirattr = 0;
+ alist.fileattr = 0;
+ alist.forkattr = 0;
+
+ result = getattrlist (path, &alist, &finfo, sizeof(finfo), 0);
+ if (result) {
+ warn ("failed to getattrlist finderinfo for %s", path);
+ result = errno;
+ goto Err_Exit;
+ }
+
+ hfsUUID_t* hfs_finfo_uuid = (hfsUUID_t*)(&finfo.finderinfo[6]);
+
+ /*
+ * Note: this is a bit of HFS-specific chicanery. When HFS+ generates
+ * the volume UUID, the formula it uses to generate the 8 bytes of internal
+ * UUID is re-looped/restarted if either high or low is zero. Thus, if we
+ * see either word as '0' then that means we should treat it as an uninitialized
+ * UUID.
+ *
+ * As a result, if we see either word as zero, then clear out the caller's buffer
+ * and return the NULL UUID. Otherwise, we'd get the 8 bytes which potentially include
+ * one or more zeroes run through HFS+'s MD5 algorithm which is not what we want.
+ */
+ //technically should endian-swap this but not necessary here
+ if ((hfs_finfo_uuid->high == 0) || (hfs_finfo_uuid->low == 0)) {
+ uuid_clear (volumeUUIDPtr->uuid);
+ return 0;
+ }
+ }
+
+
+ /* Set up the attrlist structure to get the volume's UUID: */
+ alist.bitmapcount = ATTR_BIT_MAP_COUNT;
+ alist.reserved = 0;
+ alist.commonattr = 0;
+ alist.volattr = (ATTR_VOL_INFO | ATTR_VOL_UUID);
+ alist.dirattr = 0;
+ alist.fileattr = 0;
+ alist.forkattr = 0;
+
+ result = getattrlist(path, &alist, &volUUID, sizeof(volUUID), 0);
+ if (result) {
+ warn("Couldn't get volume information for '%s'", path);
+ result = errno;
+ goto Err_Exit;
+ }
+
+ uuid_copy(volumeUUIDPtr->uuid, volUUID.uuid);
+ result = 0;
+
+Err_Exit:
+ return result;
+};
+
+
+
+
+
+/******************************************************************************
+ *
+ * V O L U M E S T A T U S D A T A B A S E R O U T I N E S
+ *
+ *****************************************************************************/
+
+#define DBHANDLESIGNATURE 0x75917737
+
+/* Flag values for operation options: */
+#define DBMARKPOSITION 1
+
+static char gVSDBPath[] = "/var/db/volinfo.database";
+
+#define MAXIOMALLOC 16384
+
+/* Database layout: */
+
+struct VSDBKey {
+ char uuidString[36];
+};
+
+struct VSDBRecord {
+ char statusFlags[8];
+};
+
+struct VSDBEntry {
+ struct VSDBKey key;
+ char keySeparator;
+ char space;
+ struct VSDBRecord record;
+ char terminator;
+};
+
+struct VSDBKey64 {
+ char uuid[16];
+};
+
+struct VSDBEntry64 {
+ struct VSDBKey64 key;
+ char keySeparator;
+ char space;
+ struct VSDBRecord record;
+ char terminator;
+};
+
+#define DBKEYSEPARATOR ':'
+#define DBBLANKSPACE ' '
+#define DBRECORDTERMINATOR '\n'
+
+/* In-memory data structures: */
+
+struct VSDBState {
+ u_int32_t signature;
+ int dbfile;
+ int dbmode;
+ off_t recordPosition;
+};
+
+typedef struct VSDBState *VSDBStatePtr;
+
+
+
+/* Internal function prototypes: */
+static int LockDB(VSDBStatePtr dbstateptr, int lockmode);
+static int UnlockDB(VSDBStatePtr dbstateptr);
+
+static int FindVolumeRecordByUUID(VSDBStatePtr dbstateptr, VolumeUUID *volumeID, struct VSDBEntry *dbentry, u_int32_t options);
+static int AddVolumeRecord(VSDBStatePtr dbstateptr, struct VSDBEntry *dbentry);
+static int UpdateVolumeRecord(VSDBStatePtr dbstateptr, struct VSDBEntry *dbentry);
+static int GetVSDBEntry(VSDBStatePtr dbstateptr, struct VSDBEntry *dbentry);
+static int CompareVSDBKeys(struct VSDBKey *key1, struct VSDBKey *key2);
+
+static void FormatULong(u_int32_t u, char *s);
+static void FormatDBKey(VolumeUUID *volumeID, struct VSDBKey *dbkey);
+static void FormatDBRecord(u_int32_t volumeStatusFlags, struct VSDBRecord *dbrecord);
+static void FormatDBEntry(VolumeUUID *volumeID, u_int32_t volumeStatusFlags, struct VSDBEntry *dbentry);
+static u_int32_t ConvertHexStringToULong(const char *hs, long maxdigits);
+
+
+
+/******************************************************************************
+ *
+ * P U B L I S H E D I N T E R F A C E R O U T I N E S
+ *
+ *****************************************************************************/
+
+void ConvertVolumeUUIDString64ToUUID(const char *UUIDString64, VolumeUUID *volumeID) {
+ int i;
+ char c;
+ u_int32_t nextdigit;
+ u_int32_t high = 0;
+ u_int32_t low = 0;
+ u_int32_t carry;
+ MD5_CTX ctx;
+
+ for (i = 0; (i < VOLUMEUUID64LENGTH) && ((c = UUIDString64[i]) != (char)0) ; ++i) {
+ if ((c >= '0') && (c <= '9')) {
+ nextdigit = c - '0';
+ } else if ((c >= 'A') && (c <= 'F')) {
+ nextdigit = c - 'A' + 10;
+ } else if ((c >= 'a') && (c <= 'f')) {
+ nextdigit = c - 'a' + 10;
+ } else {
+ nextdigit = 0;
+ };
+ carry = ((low & 0xF0000000) >> 28) & 0x0000000F;
+ high = (high << 4) | carry;
+ low = (low << 4) | nextdigit;
+ };
+
+ high = OSSwapHostToBigInt32(high);
+ low = OSSwapHostToBigInt32(low);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, kFSUUIDNamespaceSHA1, sizeof(uuid_t));
+ MD5_Update(&ctx, &high, sizeof(high));
+ MD5_Update(&ctx, &low, sizeof(low));
+ MD5_Final(volumeID->uuid, &ctx);
+
+ volumeID->uuid[6] = (volumeID->uuid[6] & 0x0F) | 0x30;
+ volumeID->uuid[8] = (volumeID->uuid[8] & 0x3F) | 0x80;
+}
+
+
+
+int OpenVolumeStatusDB(VolumeStatusDBHandle *DBHandlePtr) {
+ VSDBStatePtr dbstateptr;
+
+ *DBHandlePtr = NULL;
+
+ dbstateptr = (VSDBStatePtr)malloc(sizeof(*dbstateptr));
+ if (dbstateptr == NULL) {
+ return ENOMEM;
+ };
+
+ dbstateptr->dbmode = O_RDWR;
+ dbstateptr->dbfile = open(gVSDBPath, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ if (dbstateptr->dbfile == -1) {
+ /*
+ The file couldn't be opened for read/write access:
+ try read-only access before giving up altogether.
+ */
+ dbstateptr->dbmode = O_RDONLY;
+ dbstateptr->dbfile = open(gVSDBPath, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ if (dbstateptr->dbfile == -1) {
+ return errno;
+ };
+ };
+
+ dbstateptr->signature = DBHANDLESIGNATURE;
+ *DBHandlePtr = (VolumeStatusDBHandle)dbstateptr;
+ ConvertVolumeStatusDB(*DBHandlePtr);
+ return 0;
+}
+
+
+
+int ConvertVolumeStatusDB(VolumeStatusDBHandle DBHandle) {
+ VSDBStatePtr dbstateptr = (VSDBStatePtr)DBHandle;
+ struct VSDBEntry64 entry64;
+ struct stat dbinfo;
+ int result;
+ u_int32_t iobuffersize;
+ void *iobuffer = NULL;
+ int i;
+
+ if (dbstateptr->signature != DBHANDLESIGNATURE) return EINVAL;
+
+ if ((result = LockDB(dbstateptr, LOCK_EX)) != 0) return result;
+
+ lseek(dbstateptr->dbfile, 0, SEEK_SET);
+ result = read(dbstateptr->dbfile, &entry64, sizeof(entry64));
+ if ((result != sizeof(entry64)) ||
+ (entry64.keySeparator != DBKEYSEPARATOR) ||
+ (entry64.space != DBBLANKSPACE) ||
+ (entry64.terminator != DBRECORDTERMINATOR)) {
+ result = 0;
+ goto ErrExit;
+ } else {
+ if ((result = stat(gVSDBPath, &dbinfo)) != 0) goto ErrExit;
+ iobuffersize = dbinfo.st_size;
+ iobuffer = malloc(iobuffersize);
+ if (iobuffer == NULL) {
+ result = ENOMEM;
+ goto ErrExit;
+ };
+
+ lseek(dbstateptr->dbfile, 0, SEEK_SET);
+ result = read(dbstateptr->dbfile, iobuffer, iobuffersize);
+ if (result != iobuffersize) {
+ result = errno;
+ goto ErrExit;
+ };
+ if ((result = ftruncate(dbstateptr->dbfile, 0)) != 0) {
+ goto ErrExit;
+ };
+
+ for (i = 0; i < iobuffersize / sizeof(entry64); i++) {
+ VolumeUUID volumeID;
+ u_int32_t VolumeStatus;
+ struct VSDBEntry dbentry;
+
+ entry64 = *(((struct VSDBEntry64 *)iobuffer) + i);
+ if ((entry64.keySeparator != DBKEYSEPARATOR) ||
+ (entry64.space != DBBLANKSPACE) ||
+ (entry64.terminator != DBRECORDTERMINATOR)) {
+ continue;
+ }
+
+ ConvertVolumeUUIDString64ToUUID(entry64.key.uuid, &volumeID);
+ VolumeStatus = ConvertHexStringToULong(entry64.record.statusFlags, sizeof(entry64.record.statusFlags));
+
+ FormatDBEntry(&volumeID, VolumeStatus, &dbentry);
+ if ((result = AddVolumeRecord(dbstateptr, &dbentry)) != sizeof(dbentry)) {
+ warnx("couldn't convert volume status database: %s", strerror(result));
+ goto ErrExit;
+ };
+ };
+
+ fsync(dbstateptr->dbfile);
+
+ result = 0;
+ };
+
+ErrExit:
+ if (iobuffer) free(iobuffer);
+ UnlockDB(dbstateptr);
+ return result;
+}
+
+
+
+int GetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID, u_int32_t *VolumeStatus) {
+ VSDBStatePtr dbstateptr = (VSDBStatePtr)DBHandle;
+ struct VSDBEntry dbentry;
+ int result;
+
+ if (dbstateptr->signature != DBHANDLESIGNATURE) return EINVAL;
+
+ if ((result = LockDB(dbstateptr, LOCK_SH)) != 0) return result;
+
+ if ((result = FindVolumeRecordByUUID(dbstateptr, volumeID, &dbentry, 0)) != 0) {
+ goto ErrExit;
+ };
+ *VolumeStatus = ConvertHexStringToULong(dbentry.record.statusFlags, sizeof(dbentry.record.statusFlags));
+
+ result = 0;
+
+ErrExit:
+ UnlockDB(dbstateptr);
+ return result;
+}
+
+
+
+int SetVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID, u_int32_t VolumeStatus) {
+ VSDBStatePtr dbstateptr = (VSDBStatePtr)DBHandle;
+ struct VSDBEntry dbentry;
+ int result;
+
+ if (dbstateptr->signature != DBHANDLESIGNATURE) return EINVAL;
+ if (VolumeStatus & ~VOLUME_VALIDSTATUSBITS) return EINVAL;
+
+ if ((result = LockDB(dbstateptr, LOCK_EX)) != 0) return result;
+
+ FormatDBEntry(volumeID, VolumeStatus, &dbentry);
+ if ((result = FindVolumeRecordByUUID(dbstateptr, volumeID, NULL, DBMARKPOSITION)) == 0) {
+ result = UpdateVolumeRecord(dbstateptr, &dbentry);
+ } else if (result == -1) {
+ result = AddVolumeRecord(dbstateptr, &dbentry);
+ } else {
+ goto ErrExit;
+ };
+
+ fsync(dbstateptr->dbfile);
+
+ result = 0;
+
+ErrExit:
+ UnlockDB(dbstateptr);
+ return result;
+}
+
+
+
+int DeleteVolumeStatusDBEntry(VolumeStatusDBHandle DBHandle, VolumeUUID *volumeID) {
+ VSDBStatePtr dbstateptr = (VSDBStatePtr)DBHandle;
+ struct stat dbinfo;
+ int result;
+ u_int32_t iobuffersize;
+ void *iobuffer = NULL;
+ off_t dataoffset;
+ u_int32_t iotransfersize;
+ u_int32_t bytestransferred;
+
+ if (dbstateptr->signature != DBHANDLESIGNATURE) return EINVAL;
+
+ if ((result = LockDB(dbstateptr, LOCK_EX)) != 0) return result;
+
+ if ((result = FindVolumeRecordByUUID(dbstateptr, volumeID, NULL, DBMARKPOSITION)) != 0) {
+ if (result == -1) result = 0; /* Entry wasn't in the database to begin with? */
+ goto StdEdit;
+ } else {
+ if ((result = stat(gVSDBPath, &dbinfo)) != 0) goto ErrExit;
+ if ((dbinfo.st_size - dbstateptr->recordPosition - sizeof(struct VSDBEntry)) <= MAXIOMALLOC) {
+ iobuffersize = dbinfo.st_size - dbstateptr->recordPosition - sizeof(struct VSDBEntry);
+ } else {
+ iobuffersize = MAXIOMALLOC;
+ };
+ if (iobuffersize > 0) {
+ iobuffer = malloc(iobuffersize);
+ if (iobuffer == NULL) {
+ result = ENOMEM;
+ goto ErrExit;
+ };
+
+ dataoffset = dbstateptr->recordPosition + sizeof(struct VSDBEntry);
+ do {
+ iotransfersize = dbinfo.st_size - dataoffset;
+ if (iotransfersize > 0) {
+ if (iotransfersize > iobuffersize) iotransfersize = iobuffersize;
+
+ lseek(dbstateptr->dbfile, dataoffset, SEEK_SET);
+ bytestransferred = read(dbstateptr->dbfile, iobuffer, iotransfersize);
+ if (bytestransferred != iotransfersize) {
+ result = errno;
+ goto ErrExit;
+ };
+
+ lseek(dbstateptr->dbfile, dataoffset - (off_t)sizeof(struct VSDBEntry), SEEK_SET);
+ bytestransferred = write(dbstateptr->dbfile, iobuffer, iotransfersize);
+ if (bytestransferred != iotransfersize) {
+ result = errno;
+ goto ErrExit;
+ };
+
+ dataoffset += (off_t)iotransfersize;
+ };
+ } while (iotransfersize > 0);
+ };
+ if ((result = ftruncate(dbstateptr->dbfile, dbinfo.st_size - (off_t)(sizeof(struct VSDBEntry)))) != 0) {
+ goto ErrExit;
+ };
+
+ fsync(dbstateptr->dbfile);
+
+ result = 0;
+ };
+
+ErrExit:
+ if (iobuffer) free(iobuffer);
+ UnlockDB(dbstateptr);
+
+StdEdit:
+ return result;
+}
+
+
+
+int CloseVolumeStatusDB(VolumeStatusDBHandle DBHandle) {
+ VSDBStatePtr dbstateptr = (VSDBStatePtr)DBHandle;
+
+ if (dbstateptr->signature != DBHANDLESIGNATURE) return EINVAL;
+
+ dbstateptr->signature = 0;
+
+ close(dbstateptr->dbfile); /* Nothing we can do about any errors... */
+ dbstateptr->dbfile = 0;
+
+ free(dbstateptr);
+
+ return 0;
+}
+
+
+
+/******************************************************************************
+ *
+ * I N T E R N A L O N L Y D A T A B A S E R O U T I N E S
+ *
+ *****************************************************************************/
+
+static int LockDB(VSDBStatePtr dbstateptr, int lockmode) {
+ return flock(dbstateptr->dbfile, lockmode);
+}
+
+
+
+static int UnlockDB(VSDBStatePtr dbstateptr) {
+ return flock(dbstateptr->dbfile, LOCK_UN);
+}
+
+
+
+static int FindVolumeRecordByUUID(VSDBStatePtr dbstateptr, VolumeUUID *volumeID, struct VSDBEntry *targetEntry, u_int32_t options) {
+ struct VSDBKey searchkey;
+ struct VSDBEntry dbentry;
+ int result;
+
+ FormatDBKey(volumeID, &searchkey);
+ lseek(dbstateptr->dbfile, 0, SEEK_SET);
+
+ do {
+ result = GetVSDBEntry(dbstateptr, &dbentry);
+ if ((result == 0) && (CompareVSDBKeys(&dbentry.key, &searchkey) == 0)) {
+ if (targetEntry != NULL) {
+ memcpy(targetEntry, &dbentry, sizeof(*targetEntry));
+ };
+ return 0;
+ };
+ } while (result == 0);
+
+ return -1;
+}
+
+
+
+static int AddVolumeRecord(VSDBStatePtr dbstateptr , struct VSDBEntry *dbentry) {
+ lseek(dbstateptr->dbfile, 0, SEEK_END);
+ return write(dbstateptr->dbfile, dbentry, sizeof(struct VSDBEntry));
+}
+
+
+
+
+static int UpdateVolumeRecord(VSDBStatePtr dbstateptr, struct VSDBEntry *dbentry) {
+ lseek(dbstateptr->dbfile, dbstateptr->recordPosition, SEEK_SET);
+ return write(dbstateptr->dbfile, dbentry, sizeof(*dbentry));
+}
+
+
+
+static int GetVSDBEntry(VSDBStatePtr dbstateptr, struct VSDBEntry *dbentry) {
+ struct VSDBEntry entry;
+ int result;
+
+ dbstateptr->recordPosition = lseek(dbstateptr->dbfile, 0, SEEK_CUR);
+ result = read(dbstateptr->dbfile, &entry, sizeof(entry));
+ if ((result != sizeof(entry)) ||
+ (entry.keySeparator != DBKEYSEPARATOR) ||
+ (entry.space != DBBLANKSPACE) ||
+ (entry.terminator != DBRECORDTERMINATOR)) {
+ return -1;
+ };
+
+ memcpy(dbentry, &entry, sizeof(*dbentry));
+ return 0;
+};
+
+
+
+static int CompareVSDBKeys(struct VSDBKey *key1, struct VSDBKey *key2) {
+ return memcmp(key1->uuidString, key2->uuidString, sizeof(key1->uuidString));
+}
+
+
+
+/******************************************************************************
+ *
+ * F O R M A T T I N G A N D C O N V E R S I O N R O U T I N E S
+ *
+ *****************************************************************************/
+
+static void FormatULong(u_int32_t u, char *s) {
+ u_int32_t d;
+ int i;
+ char *digitptr = s;
+
+ for (i = 0; i < 8; ++i) {
+ d = ((u & 0xF0000000) >> 28) & 0x0000000F;
+ if (d < 10) {
+ *digitptr++ = (char)(d + '0');
+ } else {
+ *digitptr++ = (char)(d - 10 + 'A');
+ };
+ u = u << 4;
+ };
+}
+
+
+
+static void FormatDBKey(VolumeUUID *volumeID, struct VSDBKey *dbkey) {
+ uuid_string_t uuid_str;
+
+ uuid_unparse(volumeID->uuid, uuid_str);
+ memcpy(dbkey->uuidString, uuid_str, sizeof(dbkey->uuidString));
+}
+
+
+
+static void FormatDBRecord(u_int32_t volumeStatusFlags, struct VSDBRecord *dbrecord) {
+ FormatULong(volumeStatusFlags, dbrecord->statusFlags);
+}
+
+
+
+static void FormatDBEntry(VolumeUUID *volumeID, u_int32_t volumeStatusFlags, struct VSDBEntry *dbentry) {
+ FormatDBKey(volumeID, &dbentry->key);
+ dbentry->keySeparator = DBKEYSEPARATOR;
+ dbentry->space = DBBLANKSPACE;
+ FormatDBRecord(volumeStatusFlags, &dbentry->record);
+ dbentry->terminator = DBRECORDTERMINATOR;
+}
+
+
+
+static u_int32_t ConvertHexStringToULong(const char *hs, long maxdigits) {
+ int i;
+ char c;
+ u_int32_t nextdigit;
+ u_int32_t n;
+
+ n = 0;
+ for (i = 0; (i < 8) && ((c = hs[i]) != (char)0) ; ++i) {
+ if ((c >= '0') && (c <= '9')) {
+ nextdigit = c - '0';
+ } else if ((c >= 'A') && (c <= 'F')) {
+ nextdigit = c - 'A' + 10;
+ } else if ((c >= 'a') && (c <= 'f')) {
+ nextdigit = c - 'a' + 10;
+ } else {
+ nextdigit = 0;
+ };
+ n = (n << 4) + nextdigit;
+ };
+
+ return n;
+}
diff --git a/doc_cmds/checknr/checknr.1 b/doc_cmds/checknr/checknr.1
new file mode 100644
index 0000000..871730e
--- /dev/null
+++ b/doc_cmds/checknr/checknr.1
@@ -0,0 +1,163 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)checknr.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/checknr/checknr.1,v 1.10 2004/07/02 22:22:23 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt CHECKNR 1
+.Os
+.Sh NAME
+.Nm checknr
+.Nd check nroff/troff files
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ns Ar \&.x1.y1.x2.y2. ... \&.xn.yn
+.Op Fl c Ns Ar \&.x1.x2.x3 ... \&.xn
+.Op Fl s
+.Op Fl f
+.Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility checks a list of
+.Xr nroff 1
+or
+.Xr troff 1
+input files for certain kinds of errors
+involving mismatched opening and closing delimiters
+and unknown commands.
+If no files are specified,
+.Nm
+checks the standard input.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+Add additional pairs of macros to the list of known macros.
+This must be followed by groups of six characters, each group defining
+a pair of macros.
+The six characters are
+a period,
+the first macro name,
+another period,
+and the second macro name.
+For example, to define a pair .BS and .ES, use
+.Sq Li \-a.BS.ES
+.It Fl c
+Define commands which would otherwise be complained about
+as undefined.
+.It Fl f
+Request
+.Nm
+to ignore
+.Ql \ef
+font changes.
+.It Fl s
+Ignore
+.Ql \es
+size changes.
+.El
+.Pp
+Delimiters checked are:
+.Bl -enum
+.It
+Font changes using \efx ...\& \efP.
+.It
+Size changes using \esx ...\& \es0.
+.It
+Macros that come in open ...\& close forms, for example,
+the .TS and .TE macros which must always come in pairs.
+.El
+.Pp
+The
+.Nm
+utility is intended for use on documents that are prepared with
+.Nm
+in mind, much the same as
+.Xr lint 1 .
+It expects a certain document writing style for
+.Ql \ef
+and
+.Ql \es
+commands,
+in that each
+.Ql \efx
+must be terminated with
+.Ql \efP
+and
+each
+.Ql \esx
+must be terminated with
+.Ql \es0 .
+While it will work to directly go into the next font or explicitly
+specify the original font or point size,
+and many existing documents actually do this,
+such a practice will produce complaints from
+.Nm .
+Since it is probably better to use the
+.Ql \efP
+and
+.Ql \es0
+forms anyway,
+you should think of this as a contribution to your document
+preparation style.
+.Pp
+The
+.Nm
+utility knows about the
+.Xr ms 7
+and
+.Xr me 7
+macro packages.
+.Sh SEE ALSO
+.Xr nroff 1 ,
+.Xr troff 1 ,
+.Xr me 7 ,
+.Xr ms 7
+.\" .Xr checkeq 1 ,
+.Sh DIAGNOSTICS
+.Bd -ragged -compact
+Complaints about unmatched delimiters.
+Complaints about unrecognized commands.
+Various complaints about the syntax of commands.
+.Ed
+.Sh BUGS
+There is no way to define a 1 character macro name using
+.Fl a .
+.Pp
+Does not correctly recognize certain reasonable constructs,
+such as conditionals.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/doc_cmds/checknr/checknr.c b/doc_cmds/checknr/checknr.c
new file mode 100644
index 0000000..ae1f847
--- /dev/null
+++ b/doc_cmds/checknr/checknr.c
@@ -0,0 +1,607 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)checknr.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/checknr/checknr.c,v 1.9 2004/07/15 04:42:47 tjr Exp $");
+
+/*
+ * checknr: check an nroff/troff input file for matching macro calls.
+ * we also attempt to match size and font changes, but only the embedded
+ * kind. These must end in \s0 and \fP resp. Maybe more sophistication
+ * later but for now think of these restrictions as contributions to
+ * structured typesetting.
+ */
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define MAXSTK 100 /* Stack size */
+#define MAXBR 100 /* Max number of bracket pairs known */
+#define MAXCMDS 500 /* Max number of commands known */
+
+void addcmd(char *);
+void addmac(const char *);
+int binsrch(const char *);
+void checkknown(const char *);
+void chkcmd(const char *, const char *);
+void complain(int);
+int eq(const char *, const char *);
+void nomatch(const char *);
+void pe(int);
+void process(FILE *);
+void prop(int);
+static void usage(void);
+
+/*
+ * The stack on which we remember what we've seen so far.
+ */
+struct stkstr {
+ int opno; /* number of opening bracket */
+ int pl; /* '+', '-', ' ' for \s, 1 for \f, 0 for .ft */
+ int parm; /* parm to size, font, etc */
+ int lno; /* line number the thing came in in */
+} stk[MAXSTK];
+int stktop;
+
+/*
+ * The kinds of opening and closing brackets.
+ */
+struct brstr {
+ const char *opbr;
+ const char *clbr;
+} br[MAXBR] = {
+ /* A few bare bones troff commands */
+#define SZ 0
+ {"sz", "sz"}, /* also \s */
+#define FT 1
+ {"ft", "ft"}, /* also \f */
+ /* the -mm package */
+ {"AL", "LE"},
+ {"AS", "AE"},
+ {"BL", "LE"},
+ {"BS", "BE"},
+ {"DF", "DE"},
+ {"DL", "LE"},
+ {"DS", "DE"},
+ {"FS", "FE"},
+ {"ML", "LE"},
+ {"NS", "NE"},
+ {"RL", "LE"},
+ {"VL", "LE"},
+ /* the -ms package */
+ {"AB", "AE"},
+ {"BD", "DE"},
+ {"CD", "DE"},
+ {"DS", "DE"},
+ {"FS", "FE"},
+ {"ID", "DE"},
+ {"KF", "KE"},
+ {"KS", "KE"},
+ {"LD", "DE"},
+ {"LG", "NL"},
+ {"QS", "QE"},
+ {"RS", "RE"},
+ {"SM", "NL"},
+ {"XA", "XE"},
+ {"XS", "XE"},
+ /* The -me package */
+ {"(b", ")b"},
+ {"(c", ")c"},
+ {"(d", ")d"},
+ {"(f", ")f"},
+ {"(l", ")l"},
+ {"(q", ")q"},
+ {"(x", ")x"},
+ {"(z", ")z"},
+ /* Things needed by preprocessors */
+ {"EQ", "EN"},
+ {"TS", "TE"},
+ /* Refer */
+ {"[", "]"},
+ {0, 0}
+};
+
+/*
+ * All commands known to nroff, plus macro packages.
+ * Used so we can complain about unrecognized commands.
+ */
+const char *knowncmds[MAXCMDS] = {
+"$c", "$f", "$h", "$p", "$s", "(b", "(c", "(d", "(f", "(l", "(q", "(t",
+"(x", "(z", ")b", ")c", ")d", ")f", ")l", ")q", ")t", ")x", ")z", "++",
+"+c", "1C", "1c", "2C", "2c", "@(", "@)", "@C", "@D", "@F", "@I", "@M",
+"@c", "@e", "@f", "@h", "@m", "@n", "@o", "@p", "@r", "@t", "@z", "AB",
+"AE", "AF", "AI", "AL", "AM", "AS", "AT", "AU", "AX", "B", "B1", "B2",
+"BD", "BE", "BG", "BL", "BS", "BT", "BX", "C1", "C2", "CD", "CM", "CT",
+"D", "DA", "DE", "DF", "DL", "DS", "DT", "EC", "EF", "EG", "EH", "EM",
+"EN", "EQ", "EX", "FA", "FD", "FE", "FG", "FJ", "FK", "FL", "FN", "FO",
+"FQ", "FS", "FV", "FX", "H", "HC", "HD", "HM", "HO", "HU", "I", "ID",
+"IE", "IH", "IM", "IP", "IX", "IZ", "KD", "KE", "KF", "KQ", "KS", "LB",
+"LC", "LD", "LE", "LG", "LI", "LP", "MC", "ME", "MF", "MH", "ML", "MR",
+"MT", "ND", "NE", "NH", "NL", "NP", "NS", "OF", "OH", "OK", "OP", "P",
+"P1", "PF", "PH", "PP", "PT", "PX", "PY", "QE", "QP", "QS", "R", "RA",
+"RC", "RE", "RL", "RP", "RQ", "RS", "RT", "S", "S0", "S2", "S3", "SA",
+"SG", "SH", "SK", "SM", "SP", "SY", "T&", "TA", "TB", "TC", "TD", "TE",
+"TH", "TL", "TM", "TP", "TQ", "TR", "TS", "TX", "UL", "US", "UX", "VL",
+"WC", "WH", "XA", "XD", "XE", "XF", "XK", "XP", "XS", "[", "[-", "[0",
+"[1", "[2", "[3", "[4", "[5", "[<", "[>", "[]", "]", "]-", "]<", "]>",
+"][", "ab", "ac", "ad", "af", "am", "ar", "as", "b", "ba", "bc", "bd",
+"bi", "bl", "bp", "br", "bx", "c.", "c2", "cc", "ce", "cf", "ch", "cs",
+"ct", "cu", "da", "de", "di", "dl", "dn", "ds", "dt", "dw", "dy", "ec",
+"ef", "eh", "el", "em", "eo", "ep", "ev", "ex", "fc", "fi", "fl", "fo",
+"fp", "ft", "fz", "hc", "he", "hl", "hp", "ht", "hw", "hx", "hy", "i",
+"ie", "if", "ig", "in", "ip", "it", "ix", "lc", "lg", "li", "ll", "ln",
+"lo", "lp", "ls", "lt", "m1", "m2", "m3", "m4", "mc", "mk", "mo", "n1",
+"n2", "na", "ne", "nf", "nh", "nl", "nm", "nn", "np", "nr", "ns", "nx",
+"of", "oh", "os", "pa", "pc", "pi", "pl", "pm", "pn", "po", "pp", "ps",
+"q", "r", "rb", "rd", "re", "rm", "rn", "ro", "rr", "rs", "rt", "sb",
+"sc", "sh", "sk", "so", "sp", "ss", "st", "sv", "sz", "ta", "tc", "th",
+"ti", "tl", "tm", "tp", "tr", "u", "uf", "uh", "ul", "vs", "wh", "xp",
+"yr", 0
+};
+
+int lineno; /* current line number in input file */
+const char *cfilename; /* name of current file */
+int nfiles; /* number of files to process */
+int fflag; /* -f: ignore \f */
+int sflag; /* -s: ignore \s */
+int ncmds; /* size of knowncmds */
+int slot; /* slot in knowncmds found by binsrch */
+
+int
+main(int argc, char **argv)
+{
+ FILE *f;
+ int i;
+ char *cp;
+ char b1[4];
+
+ /* Figure out how many known commands there are */
+ while (knowncmds[ncmds])
+ ncmds++;
+ while (argc > 1 && argv[1][0] == '-') {
+ switch(argv[1][1]) {
+
+ /* -a: add pairs of macros */
+ case 'a':
+ i = strlen(argv[1]) - 2;
+ if (i % 6 != 0)
+ usage();
+ /* look for empty macro slots */
+ for (i=0; br[i].opbr; i++)
+ ;
+ for (cp=argv[1]+3; cp[-1]; cp += 6) {
+ br[i].opbr = strncpy(malloc(3), cp, 2);
+ br[i].clbr = strncpy(malloc(3), cp+3, 2);
+ addmac(br[i].opbr); /* knows pairs are also known cmds */
+ addmac(br[i].clbr);
+ i++;
+ }
+ break;
+
+ /* -c: add known commands */
+ case 'c':
+ i = strlen(argv[1]) - 2;
+ if (i % 3 != 0)
+ usage();
+ for (cp=argv[1]+3; cp[-1]; cp += 3) {
+ if (cp[2] && cp[2] != '.')
+ usage();
+ strncpy(b1, cp, 2);
+ b1[2] = '\0';
+ addmac(b1);
+ }
+ break;
+
+ /* -f: ignore font changes */
+ case 'f':
+ fflag = 1;
+ break;
+
+ /* -s: ignore size changes */
+ case 's':
+ sflag = 1;
+ break;
+ default:
+ usage();
+ }
+ argc--; argv++;
+ }
+
+ nfiles = argc - 1;
+
+ if (nfiles > 0) {
+ for (i=1; i<argc; i++) {
+ cfilename = argv[i];
+ f = fopen(cfilename, "r");
+ if (f == NULL)
+ warn("%s", cfilename);
+ else {
+ process(f);
+ fclose(f);
+ }
+ }
+ } else {
+ cfilename = "stdin";
+ process(stdin);
+ }
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: checknr [-a.xx.yy.xx.yy...] [-c.xx.xx.xx...] [-s] [-f] file\n");
+ exit(1);
+}
+
+void
+process(FILE *f)
+{
+ int i, n;
+ char mac[5]; /* The current macro or nroff command */
+ int pl;
+ static char line[256]; /* the current line */
+
+ stktop = -1;
+ for (lineno = 1; fgets(line, sizeof line, f); lineno++) {
+ if (line[0] == '.') {
+ /*
+ * find and isolate the macro/command name.
+ */
+ strncpy(mac, line+1, 4);
+ if (isspace(mac[0])) {
+ pe(lineno);
+ printf("Empty command\n");
+ } else if (isspace(mac[1])) {
+ mac[1] = 0;
+ } else if (isspace(mac[2])) {
+ mac[2] = 0;
+ } else if (mac[0] != '\\' || mac[1] != '\"') {
+ pe(lineno);
+ printf("Command too long\n");
+ }
+
+ /*
+ * Is it a known command?
+ */
+ checkknown(mac);
+
+ /*
+ * Should we add it?
+ */
+ if (eq(mac, "de"))
+ addcmd(line);
+
+ chkcmd(line, mac);
+ }
+
+ /*
+ * At this point we process the line looking
+ * for \s and \f.
+ */
+ for (i=0; line[i]; i++)
+ if (line[i]=='\\' && (i==0 || line[i-1]!='\\')) {
+ if (!sflag && line[++i]=='s') {
+ pl = line[++i];
+ if (isdigit(pl)) {
+ n = pl - '0';
+ pl = ' ';
+ } else
+ n = 0;
+ while (isdigit(line[++i]))
+ n = 10 * n + line[i] - '0';
+ i--;
+ if (n == 0) {
+ if (stk[stktop].opno == SZ) {
+ stktop--;
+ } else {
+ pe(lineno);
+ printf("unmatched \\s0\n");
+ }
+ } else {
+ stk[++stktop].opno = SZ;
+ stk[stktop].pl = pl;
+ stk[stktop].parm = n;
+ stk[stktop].lno = lineno;
+ }
+ } else if (!fflag && line[i]=='f') {
+ n = line[++i];
+ if (n == 'P') {
+ if (stk[stktop].opno == FT) {
+ stktop--;
+ } else {
+ pe(lineno);
+ printf("unmatched \\fP\n");
+ }
+ } else {
+ stk[++stktop].opno = FT;
+ stk[stktop].pl = 1;
+ stk[stktop].parm = n;
+ stk[stktop].lno = lineno;
+ }
+ }
+ }
+ }
+ /*
+ * We've hit the end and look at all this stuff that hasn't been
+ * matched yet! Complain, complain.
+ */
+ for (i=stktop; i>=0; i--) {
+ complain(i);
+ }
+}
+
+void
+complain(int i)
+{
+ pe(stk[i].lno);
+ printf("Unmatched ");
+ prop(i);
+ printf("\n");
+}
+
+void
+prop(int i)
+{
+ if (stk[i].pl == 0)
+ printf(".%s", br[stk[i].opno].opbr);
+ else switch(stk[i].opno) {
+ case SZ:
+ printf("\\s%c%d", stk[i].pl, stk[i].parm);
+ break;
+ case FT:
+ printf("\\f%c", stk[i].parm);
+ break;
+ default:
+ printf("Bug: stk[%d].opno = %d = .%s, .%s",
+ i, stk[i].opno, br[stk[i].opno].opbr, br[stk[i].opno].clbr);
+ }
+}
+
+void
+chkcmd(const char *line __unused, const char *mac)
+{
+ int i;
+
+ /*
+ * Check to see if it matches top of stack.
+ */
+ if (stktop >= 0 && eq(mac, br[stk[stktop].opno].clbr))
+ stktop--; /* OK. Pop & forget */
+ else {
+ /* No. Maybe it's an opener */
+ for (i=0; br[i].opbr; i++) {
+ if (eq(mac, br[i].opbr)) {
+ /* Found. Push it. */
+ stktop++;
+ stk[stktop].opno = i;
+ stk[stktop].pl = 0;
+ stk[stktop].parm = 0;
+ stk[stktop].lno = lineno;
+ break;
+ }
+ /*
+ * Maybe it's an unmatched closer.
+ * NOTE: this depends on the fact
+ * that none of the closers can be
+ * openers too.
+ */
+ if (eq(mac, br[i].clbr)) {
+ nomatch(mac);
+ break;
+ }
+ }
+ }
+}
+
+void
+nomatch(const char *mac)
+{
+ int i, j;
+
+ /*
+ * Look for a match further down on stack
+ * If we find one, it suggests that the stuff in
+ * between is supposed to match itself.
+ */
+ for (j=stktop; j>=0; j--)
+ if (eq(mac,br[stk[j].opno].clbr)) {
+ /* Found. Make a good diagnostic. */
+ if (j == stktop-2) {
+ /*
+ * Check for special case \fx..\fR and don't
+ * complain.
+ */
+ if (stk[j+1].opno==FT && stk[j+1].parm!='R'
+ && stk[j+2].opno==FT && stk[j+2].parm=='R') {
+ stktop = j -1;
+ return;
+ }
+ /*
+ * We have two unmatched frobs. Chances are
+ * they were intended to match, so we mention
+ * them together.
+ */
+ pe(stk[j+1].lno);
+ prop(j+1);
+ printf(" does not match %d: ", stk[j+2].lno);
+ prop(j+2);
+ printf("\n");
+ } else for (i=j+1; i <= stktop; i++) {
+ complain(i);
+ }
+ stktop = j-1;
+ return;
+ }
+ /* Didn't find one. Throw this away. */
+ pe(lineno);
+ printf("Unmatched .%s\n", mac);
+}
+
+/* eq: are two strings equal? */
+int
+eq(const char *s1, const char *s2)
+{
+ return (strcmp(s1, s2) == 0);
+}
+
+/* print the first part of an error message, given the line number */
+void
+pe(int linen)
+{
+ if (nfiles > 1)
+ printf("%s: ", cfilename);
+ printf("%d: ", linen);
+}
+
+void
+checkknown(const char *mac)
+{
+
+ if (eq(mac, "."))
+ return;
+ if (binsrch(mac) >= 0)
+ return;
+ if (mac[0] == '\\' && mac[1] == '"') /* comments */
+ return;
+
+ pe(lineno);
+ printf("Unknown command: .%s\n", mac);
+}
+
+/*
+ * We have a .de xx line in "line". Add xx to the list of known commands.
+ */
+void
+addcmd(char *line)
+{
+ char *mac;
+
+ /* grab the macro being defined */
+ mac = line+4;
+ while (isspace(*mac))
+ mac++;
+ if (*mac == 0) {
+ pe(lineno);
+ printf("illegal define: %s\n", line);
+ return;
+ }
+ mac[2] = 0;
+ if (isspace(mac[1]) || mac[1] == '\\')
+ mac[1] = 0;
+ if (ncmds >= MAXCMDS) {
+ printf("Only %d known commands allowed\n", MAXCMDS);
+ exit(1);
+ }
+ addmac(mac);
+}
+
+/*
+ * Add mac to the list. We should really have some kind of tree
+ * structure here but this is a quick-and-dirty job and I just don't
+ * have time to mess with it. (I wonder if this will come back to haunt
+ * me someday?) Anyway, I claim that .de is fairly rare in user
+ * nroff programs, and the register loop below is pretty fast.
+ */
+void
+addmac(const char *mac)
+{
+ const char **src, **dest, **loc;
+
+ if (binsrch(mac) >= 0){ /* it's OK to redefine something */
+#ifdef DEBUG
+ printf("binsrch(%s) -> already in table\n", mac);
+#endif
+ return;
+ }
+ /* binsrch sets slot as a side effect */
+#ifdef DEBUG
+printf("binsrch(%s) -> %d\n", mac, slot);
+#endif
+ loc = &knowncmds[slot];
+ src = &knowncmds[ncmds-1];
+ dest = src+1;
+ while (dest > loc)
+ *dest-- = *src--;
+ *loc = strcpy(malloc(3), mac);
+ ncmds++;
+#ifdef DEBUG
+printf("after: %s %s %s %s %s, %d cmds\n", knowncmds[slot-2], knowncmds[slot-1], knowncmds[slot], knowncmds[slot+1], knowncmds[slot+2], ncmds);
+#endif
+}
+
+/*
+ * Do a binary search in knowncmds for mac.
+ * If found, return the index. If not, return -1.
+ */
+int
+binsrch(const char *mac)
+{
+ const char *p; /* pointer to current cmd in list */
+ int d; /* difference if any */
+ int mid; /* mid point in binary search */
+ int top, bot; /* boundaries of bin search, inclusive */
+
+ top = ncmds-1;
+ bot = 0;
+ while (top >= bot) {
+ mid = (top+bot)/2;
+ p = knowncmds[mid];
+ d = p[0] - mac[0];
+ if (d == 0)
+ d = p[1] - mac[1];
+ if (d == 0)
+ return mid;
+ if (d < 0)
+ bot = mid + 1;
+ else
+ top = mid - 1;
+ }
+ slot = bot; /* place it would have gone */
+ return -1;
+}
diff --git a/doc_cmds/colcrt/colcrt.1 b/doc_cmds/colcrt/colcrt.1
new file mode 100644
index 0000000..cc2df02
--- /dev/null
+++ b/doc_cmds/colcrt/colcrt.1
@@ -0,0 +1,124 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)colcrt.1 8.1 (Berkeley) 6/30/93
+.\" $FreeBSD: src/usr.bin/colcrt/colcrt.1,v 1.13 2004/07/31 06:22:01 tjr Exp $
+.\"
+.Dd July 31, 2004
+.Dt COLCRT 1
+.Os
+.Sh NAME
+.Nm colcrt
+.Nd filter nroff output for CRT previewing
+.Sh SYNOPSIS
+.Nm
+.Op Fl
+.Op Fl \&2
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility provides virtual half-line and reverse line feed sequences
+for terminals without such capability, and on which overstriking
+is destructive.
+Half-line characters and underlining (changed to dashing `\-')
+are placed on new lines in between the normal output lines.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl
+Suppress all underlining.
+This option is especially useful for previewing
+.Em allboxed
+tables from
+.Xr tbl 1 .
+.It Fl 2
+Cause all half-lines to be printed, effectively double spacing the output.
+Normally, a minimal space output format is used which will suppress empty
+lines.
+The program never suppresses two consecutive empty lines, however.
+The
+.Fl 2
+option is useful for sending output to the line printer when the output
+contains superscripts and subscripts which would otherwise be invisible.
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXAMPLES
+A typical use of
+.Nm
+would be
+.Bd -literal
+tbl exum2.n \&| nroff \-ms \&| colcrt \- \&| more
+.Ed
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr col 1 ,
+.Xr more 1 ,
+.Xr nroff 1 ,
+.Xr troff 1 ,
+.Xr ul 1
+.Sh BUGS
+Should fold underlines onto blanks even with the
+.Sq Fl
+option so that
+a true underline character would show.
+.Pp
+Can't back up more than 102 lines.
+.Pp
+General overstriking is lost;
+as a special case
+.Ql \&|
+overstruck with
+.Ql \-
+or underline becomes
+.Ql \&+ .
+.Pp
+Lines are trimmed to 132 characters.
+.Pp
+Some provision should be made for processing superscripts and subscripts
+in documents which are already double-spaced.
+.Pp
+Characters that take up more than one column position may not be
+underlined correctly.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/doc_cmds/colcrt/colcrt.c b/doc_cmds/colcrt/colcrt.c
new file mode 100644
index 0000000..2e5570b
--- /dev/null
+++ b/doc_cmds/colcrt/colcrt.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)colcrt.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/colcrt/colcrt.c,v 1.18 2004/07/31 06:22:57 tjr Exp $");
+
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+/*
+ * colcrt - replaces col for crts with new nroff esp. when using tbl.
+ * Bill Joy UCB July 14, 1977
+ *
+ * This filter uses a screen buffer, 267 half-lines by 132 columns.
+ * It interprets the up and down sequences generated by the new
+ * nroff when used with tbl and by \u \d and \r.
+ * General overstriking doesn't work correctly.
+ * Underlining is split onto multiple lines, etc.
+ *
+ * Option - suppresses all underlining.
+ * Option -2 forces printing of all half lines.
+ */
+
+wchar_t page[267][132];
+
+int outline = 1;
+int outcol;
+
+char suppresul;
+char printall;
+
+static void move(int, int);
+static void pflush(int);
+static int plus(wchar_t, wchar_t);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ wint_t c;
+ wchar_t *cp, *dp;
+ int ch, i, w;
+
+ setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "-2")) != -1)
+ switch (ch) {
+ case '-':
+ suppresul = 1;
+ break;
+ case '2':
+ printall = 1;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ do {
+ if (argc > 0) {
+ if (freopen(argv[0], "r", stdin) == NULL) {
+ fflush(stdout);
+ err(1, "%s", argv[0]);
+ }
+ argc--;
+ argv++;
+ }
+ for (;;) {
+ c = getwc(stdin);
+ if (c == WEOF) {
+ pflush(outline);
+ fflush(stdout);
+ break;
+ }
+ switch (c) {
+ case '\n':
+ if (outline >= 265)
+ pflush(62);
+ outline += 2;
+ outcol = 0;
+ continue;
+ case '\016':
+ case '\017':
+ continue;
+ case 033:
+ c = getwc(stdin);
+ switch (c) {
+ case '9':
+ if (outline >= 266)
+ pflush(62);
+ outline++;
+ continue;
+ case '8':
+ if (outline >= 1)
+ outline--;
+ continue;
+ case '7':
+ outline -= 2;
+ if (outline < 0)
+ outline = 0;
+ continue;
+ default:
+ continue;
+ }
+ case '\b':
+ if (outcol)
+ outcol--;
+ continue;
+ case '\t':
+ outcol += 8;
+ outcol &= ~7;
+ outcol--;
+ c = ' ';
+ default:
+ if ((w = wcwidth(c)) <= 0)
+ w = 1; /* XXX */
+ if (outcol + w > 132) {
+ outcol += w;
+ continue;
+ }
+ cp = &page[outline][outcol];
+ outcol += w;
+ if (c == '_') {
+ if (suppresul)
+ continue;
+ cp += 132;
+ c = '-';
+ }
+ if (*cp == 0) {
+ for (i = 0; i < w; i++)
+ cp[i] = c;
+ dp = cp - (outcol - w);
+ for (cp--; cp >= dp && *cp == 0; cp--)
+ *cp = ' ';
+ } else {
+ if (plus(c, *cp) || plus(*cp, c))
+ *cp = '+';
+ else if (*cp == ' ' || *cp == 0) {
+ for (i = 1; i < w; i++)
+ if (cp[i] != ' ' &&
+ cp[i] != 0)
+ goto cont;
+ for (i = 0; i < w; i++)
+ cp[i] = c;
+ }
+ }
+cont:
+ continue;
+ }
+ }
+ if (ferror(stdin))
+ err(1, NULL);
+ } while (argc > 0);
+ fflush(stdout);
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: colcrt [-] [-2] [file ...]\n");
+ exit(1);
+}
+
+static int
+plus(wchar_t c, wchar_t d)
+{
+
+ return ((c == '|' && d == '-') || d == '_');
+}
+
+static void
+pflush(int ol)
+{
+ static int first;
+ int i;
+ wchar_t *cp;
+ char lastomit;
+ int l, w;
+
+ l = ol;
+ lastomit = 0;
+ if (l > 266)
+ l = 266;
+ else
+ l |= 1;
+ for (i = first | 1; i < l; i++) {
+ move(i, i - 1);
+ move(i, i + 1);
+ }
+ for (i = first; i < l; i++) {
+ cp = page[i];
+ if (printall == 0 && lastomit == 0 && *cp == 0) {
+ lastomit = 1;
+ continue;
+ }
+ lastomit = 0;
+ while (*cp != L'\0') {
+ if ((w = wcwidth(*cp)) > 0) {
+ putwchar(*cp);
+ cp += w;
+ } else
+ cp++;
+ }
+ putwchar(L'\n');
+ }
+ wmemcpy(page[0], page[ol], (267 - ol) * 132);
+ wmemset(page[267- ol], L'\0', ol * 132);
+ outline -= ol;
+ outcol = 0;
+ first = 1;
+}
+
+static void
+move(int l, int m)
+{
+ wchar_t *cp, *dp;
+
+ for (cp = page[l], dp = page[m]; *cp; cp++, dp++) {
+ switch (*cp) {
+ case '|':
+ if (*dp != ' ' && *dp != '|' && *dp != 0)
+ return;
+ break;
+ case ' ':
+ break;
+ default:
+ return;
+ }
+ }
+ if (*cp == 0) {
+ for (cp = page[l], dp = page[m]; *cp; cp++, dp++)
+ if (*cp == '|')
+ *dp = '|';
+ else if (*dp == 0)
+ *dp = ' ';
+ page[l][0] = 0;
+ }
+}
diff --git a/doc_cmds/doc_cmds.plist b/doc_cmds/doc_cmds.plist
new file mode 100644
index 0000000..a9ea197
--- /dev/null
+++ b/doc_cmds/doc_cmds.plist
@@ -0,0 +1,72 @@
+<plist version="1.0">
+<array>
+<dict>
+ <key>OpenSourceProject</key>
+ <string>checknr</string>
+ <key>OpenSourceVersion</key>
+ <string>2004-09-18</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/checknr/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co checknr</string>
+ <key>OpenSourceImportDate</key>
+ <string>2004-09-18</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>doc_cmds.txt</string>
+</dict>
+<dict>
+ <key>OpenSourceProject</key>
+ <string>colcrt</string>
+ <key>OpenSourceVersion</key>
+ <string>2004-09-18</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/colcrt/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co colcrt</string>
+ <key>OpenSourceImportDate</key>
+ <string>2004-09-18</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>doc_cmds.txt</string>
+</dict>
+<dict>
+ <key>OpenSourceProject</key>
+ <string>getNAME</string>
+ <key>OpenSourceVersion</key>
+ <string>2004-09-18</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/libexec/getNAME/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co getNAME</string>
+ <key>OpenSourceImportDate</key>
+ <string>2004-09-18</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>doc_cmds.txt</string>
+</dict>
+<dict>
+ <key>OpenSourceProject</key>
+ <string>makewhatis</string>
+ <key>OpenSourceVersion</key>
+ <string>2004-09-18</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/makewhatis/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co makewhatis</string>
+ <key>OpenSourceImportDate</key>
+ <string>2004-09-18</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>3806865</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>doc_cmds.txt</string>
+</dict>
+</array>
+</plist>
diff --git a/doc_cmds/doc_cmds.txt b/doc_cmds/doc_cmds.txt
new file mode 100644
index 0000000..873a785
--- /dev/null
+++ b/doc_cmds/doc_cmds.txt
@@ -0,0 +1,134 @@
+checknr:
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+colcrt:
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+getNAME:
+
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+makewhatis:
+
+/*-
+ * Copyright (c) 2002 John Rochester
+ * 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.
+ */
diff --git a/doc_cmds/doc_cmds.xcodeproj/project.pbxproj b/doc_cmds/doc_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..ec9533d
--- /dev/null
+++ b/doc_cmds/doc_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,538 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FD91BA470FC2319F00643D04 /* Build All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FD91BA500FC231AB00643D04 /* Build configuration list for PBXAggregateTarget "Build All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FD91BA6B0FC231C500643D04 /* PBXTargetDependency */,
+ FD91BA690FC231C500643D04 /* PBXTargetDependency */,
+ FD91BA650FC231C500643D04 /* PBXTargetDependency */,
+ FD91BA930FC2330000643D04 /* PBXTargetDependency */,
+ );
+ name = "Build All";
+ productName = "Build All";
+ };
+ FD91BA900FC232FB00643D04 /* Other Files */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FD91BAA00FC2331400643D04 /* Build configuration list for PBXAggregateTarget "Other Files" */;
+ buildPhases = (
+ FD91BA8F0FC232FB00643D04 /* man1 */,
+ FD91BAA60FC2338D00643D04 /* OpenSourceVersions */,
+ FD91BAA70FC2338D00643D04 /* OpenSourceLicenses */,
+ );
+ dependencies = (
+ );
+ name = "Other Files";
+ productName = Other;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ FD91BA6C0FC231D500643D04 /* checknr.c in Sources */ = {isa = PBXBuildFile; fileRef = FD91BA270FC2311E00643D04 /* checknr.c */; };
+ FD91BA6D0FC231DA00643D04 /* colcrt.c in Sources */ = {isa = PBXBuildFile; fileRef = FD91BA2C0FC2311E00643D04 /* colcrt.c */; };
+ FD91BA6F0FC231EA00643D04 /* makewhatis.c in Sources */ = {isa = PBXBuildFile; fileRef = FD91BA3E0FC2311E00643D04 /* makewhatis.c */; };
+ FD91BA830FC2328800643D04 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FD91BA820FC2328800643D04 /* libz.dylib */; };
+ FD91BAA10FC2332800643D04 /* intro.1 in man1 */ = {isa = PBXBuildFile; fileRef = FD91BA440FC2316200643D04 /* intro.1 */; };
+ FD91BAA30FC2335800643D04 /* doc_cmds.plist in OpenSourceVersions */ = {isa = PBXBuildFile; fileRef = FD91BA2F0FC2311E00643D04 /* doc_cmds.plist */; };
+ FD91BAA50FC2336F00643D04 /* doc_cmds.txt in OpenSourceLicenses */ = {isa = PBXBuildFile; fileRef = FD91BA300FC2311E00643D04 /* doc_cmds.txt */; };
+ FD91BAAD0FC233BB00643D04 /* checknr.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD91BA260FC2311E00643D04 /* checknr.1 */; };
+ FD91BAB00FC233DD00643D04 /* colcrt.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD91BA2B0FC2311E00643D04 /* colcrt.1 */; };
+ FD91BAB60FC2346F00643D04 /* makewhatis.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD91BA3D0FC2311E00643D04 /* makewhatis.8 */; };
+ FD91BAB70FC2346F00643D04 /* makewhatis.local.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD91BA3F0FC2311E00643D04 /* makewhatis.local.8 */; };
+ FDB4EC3B0FC32F8D00F23EE6 /* makewhatis.local.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD91BA400FC2311E00643D04 /* makewhatis.local.sh */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ FD91BA640FC231C500643D04 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FD91BA090FC2310A00643D04 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD91BA600FC231BE00643D04;
+ remoteInfo = makewhatis;
+ };
+ FD91BA680FC231C500643D04 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FD91BA090FC2310A00643D04 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD91BA540FC231B200643D04;
+ remoteInfo = colcrt;
+ };
+ FD91BA6A0FC231C500643D04 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FD91BA090FC2310A00643D04 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD91BA4B0FC231AB00643D04;
+ remoteInfo = checknr;
+ };
+ FD91BA920FC2330000643D04 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FD91BA090FC2310A00643D04 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD91BA900FC232FB00643D04;
+ remoteInfo = Other;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ FD91BA8F0FC232FB00643D04 /* man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FD91BAA10FC2332800643D04 /* intro.1 in man1 */,
+ );
+ name = man1;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD91BAA60FC2338D00643D04 /* OpenSourceVersions */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/OpenSourceVersions;
+ dstSubfolderSpec = 0;
+ files = (
+ FD91BAA30FC2335800643D04 /* doc_cmds.plist in OpenSourceVersions */,
+ );
+ name = OpenSourceVersions;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD91BAA70FC2338D00643D04 /* OpenSourceLicenses */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/OpenSourceLicenses;
+ dstSubfolderSpec = 0;
+ files = (
+ FD91BAA50FC2336F00643D04 /* doc_cmds.txt in OpenSourceLicenses */,
+ );
+ name = OpenSourceLicenses;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD91BAAC0FC233B600643D04 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FD91BAAD0FC233BB00643D04 /* checknr.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD91BAAF0FC233D600643D04 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FD91BAB00FC233DD00643D04 /* colcrt.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD91BAB50FC2346000643D04 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ FD91BAB60FC2346F00643D04 /* makewhatis.8 in CopyFiles */,
+ FD91BAB70FC2346F00643D04 /* makewhatis.local.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDB4EC3D0FC32FA700F23EE6 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/libexec;
+ dstSubfolderSpec = 0;
+ files = (
+ FDB4EC3B0FC32F8D00F23EE6 /* makewhatis.local.sh in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ FD91BA260FC2311E00643D04 /* checknr.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = checknr.1; sourceTree = "<group>"; };
+ FD91BA270FC2311E00643D04 /* checknr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = checknr.c; sourceTree = "<group>"; };
+ FD91BA2B0FC2311E00643D04 /* colcrt.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = colcrt.1; sourceTree = "<group>"; };
+ FD91BA2C0FC2311E00643D04 /* colcrt.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = colcrt.c; sourceTree = "<group>"; };
+ FD91BA2F0FC2311E00643D04 /* doc_cmds.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = doc_cmds.plist; sourceTree = "<group>"; };
+ FD91BA300FC2311E00643D04 /* doc_cmds.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = doc_cmds.txt; sourceTree = "<group>"; };
+ FD91BA3D0FC2311E00643D04 /* makewhatis.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = makewhatis.8; sourceTree = "<group>"; };
+ FD91BA3E0FC2311E00643D04 /* makewhatis.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = makewhatis.c; sourceTree = "<group>"; };
+ FD91BA3F0FC2311E00643D04 /* makewhatis.local.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = makewhatis.local.8; sourceTree = "<group>"; };
+ FD91BA400FC2311E00643D04 /* makewhatis.local.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = makewhatis.local.sh; sourceTree = "<group>"; };
+ FD91BA440FC2316200643D04 /* intro.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = intro.1; sourceTree = "<group>"; };
+ FD91BA4C0FC231AB00643D04 /* checknr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = checknr; sourceTree = BUILT_PRODUCTS_DIR; };
+ FD91BA550FC231B200643D04 /* colcrt */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = colcrt; sourceTree = BUILT_PRODUCTS_DIR; };
+ FD91BA610FC231BE00643D04 /* makewhatis */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = makewhatis; sourceTree = BUILT_PRODUCTS_DIR; };
+ FD91BA820FC2328800643D04 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = /usr/lib/libz.dylib; sourceTree = "<absolute>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FD91BA4A0FC231AB00643D04 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD91BA530FC231B200643D04 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD91BA5F0FC231BE00643D04 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD91BA830FC2328800643D04 /* libz.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ FD91BA070FC2310A00643D04 = {
+ isa = PBXGroup;
+ children = (
+ FD91BA150FC2311E00643D04 /* Source */,
+ FD91BA4D0FC231AB00643D04 /* Products */,
+ FD91BA820FC2328800643D04 /* libz.dylib */,
+ );
+ sourceTree = "<group>";
+ };
+ FD91BA150FC2311E00643D04 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ FD91BA250FC2311E00643D04 /* checknr */,
+ FD91BA2A0FC2311E00643D04 /* colcrt */,
+ FD91BA3A0FC2311E00643D04 /* makewhatis */,
+ FD91BA2F0FC2311E00643D04 /* doc_cmds.plist */,
+ FD91BA300FC2311E00643D04 /* doc_cmds.txt */,
+ FD91BA440FC2316200643D04 /* intro.1 */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ FD91BA250FC2311E00643D04 /* checknr */ = {
+ isa = PBXGroup;
+ children = (
+ FD91BA260FC2311E00643D04 /* checknr.1 */,
+ FD91BA270FC2311E00643D04 /* checknr.c */,
+ );
+ path = checknr;
+ sourceTree = "<group>";
+ };
+ FD91BA2A0FC2311E00643D04 /* colcrt */ = {
+ isa = PBXGroup;
+ children = (
+ FD91BA2B0FC2311E00643D04 /* colcrt.1 */,
+ FD91BA2C0FC2311E00643D04 /* colcrt.c */,
+ );
+ path = colcrt;
+ sourceTree = "<group>";
+ };
+ FD91BA3A0FC2311E00643D04 /* makewhatis */ = {
+ isa = PBXGroup;
+ children = (
+ FD91BA3D0FC2311E00643D04 /* makewhatis.8 */,
+ FD91BA3E0FC2311E00643D04 /* makewhatis.c */,
+ FD91BA3F0FC2311E00643D04 /* makewhatis.local.8 */,
+ FD91BA400FC2311E00643D04 /* makewhatis.local.sh */,
+ );
+ path = makewhatis;
+ sourceTree = "<group>";
+ };
+ FD91BA4D0FC231AB00643D04 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FD91BA4C0FC231AB00643D04 /* checknr */,
+ FD91BA550FC231B200643D04 /* colcrt */,
+ FD91BA610FC231BE00643D04 /* makewhatis */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ FD91BA4B0FC231AB00643D04 /* checknr */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD91BA510FC231AB00643D04 /* Build configuration list for PBXNativeTarget "checknr" */;
+ buildPhases = (
+ FD91BA490FC231AB00643D04 /* Sources */,
+ FD91BA4A0FC231AB00643D04 /* Frameworks */,
+ FD91BAAC0FC233B600643D04 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = checknr;
+ productName = checknr;
+ productReference = FD91BA4C0FC231AB00643D04 /* checknr */;
+ productType = "com.apple.product-type.tool";
+ };
+ FD91BA540FC231B200643D04 /* colcrt */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD91BA720FC2320800643D04 /* Build configuration list for PBXNativeTarget "colcrt" */;
+ buildPhases = (
+ FD91BA520FC231B200643D04 /* Sources */,
+ FD91BA530FC231B200643D04 /* Frameworks */,
+ FD91BAAF0FC233D600643D04 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = colcrt;
+ productName = colcrt;
+ productReference = FD91BA550FC231B200643D04 /* colcrt */;
+ productType = "com.apple.product-type.tool";
+ };
+ FD91BA600FC231BE00643D04 /* makewhatis */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD91BA740FC2320800643D04 /* Build configuration list for PBXNativeTarget "makewhatis" */;
+ buildPhases = (
+ FD91BA5E0FC231BE00643D04 /* Sources */,
+ FD91BA5F0FC231BE00643D04 /* Frameworks */,
+ FDB4EC3D0FC32FA700F23EE6 /* CopyFiles */,
+ FD91BAC90FC2359F00643D04 /* ShellScript */,
+ FD91BAB50FC2346000643D04 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = makewhatis;
+ productName = makewhatis;
+ productReference = FD91BA610FC231BE00643D04 /* makewhatis */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FD91BA090FC2310A00643D04 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = FD91BA0C0FC2310A00643D04 /* Build configuration list for PBXProject "doc_cmds" */;
+ compatibilityVersion = "Xcode 3.1";
+ hasScannedForEncodings = 0;
+ mainGroup = FD91BA070FC2310A00643D04;
+ productRefGroup = FD91BA4D0FC231AB00643D04 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FD91BA470FC2319F00643D04 /* Build All */,
+ FD91BA4B0FC231AB00643D04 /* checknr */,
+ FD91BA540FC231B200643D04 /* colcrt */,
+ FD91BA600FC231BE00643D04 /* makewhatis */,
+ FD91BA900FC232FB00643D04 /* Other Files */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FD91BAC90FC2359F00643D04 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/libexec/makewhatis.local.sh",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/libexec/makewhatis.local",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\n/bin/mv ${SCRIPT_INPUT_FILE_0} ${SCRIPT_OUTPUT_FILE_0}\n/bin/chmod +x ${SCRIPT_OUTPUT_FILE_0}";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FD91BA490FC231AB00643D04 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD91BA6C0FC231D500643D04 /* checknr.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD91BA520FC231B200643D04 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD91BA6D0FC231DA00643D04 /* colcrt.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD91BA5E0FC231BE00643D04 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD91BA6F0FC231EA00643D04 /* makewhatis.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ FD91BA650FC231C500643D04 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD91BA600FC231BE00643D04 /* makewhatis */;
+ targetProxy = FD91BA640FC231C500643D04 /* PBXContainerItemProxy */;
+ };
+ FD91BA690FC231C500643D04 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD91BA540FC231B200643D04 /* colcrt */;
+ targetProxy = FD91BA680FC231C500643D04 /* PBXContainerItemProxy */;
+ };
+ FD91BA6B0FC231C500643D04 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD91BA4B0FC231AB00643D04 /* checknr */;
+ targetProxy = FD91BA6A0FC231C500643D04 /* PBXContainerItemProxy */;
+ };
+ FD91BA930FC2330000643D04 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD91BA900FC232FB00643D04 /* Other Files */;
+ targetProxy = FD91BA920FC2330000643D04 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ FD91BA0B0FC2310A00643D04 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD)";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = "";
+ PREBINDING = NO;
+ USE_HEADERMAP = NO;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = __;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ FD91BA480FC2319F00643D04 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = "Build All";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ FD91BA4F0FC231AB00643D04 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = checknr;
+ };
+ name = Release;
+ };
+ FD91BA570FC231B200643D04 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = colcrt;
+ };
+ name = Release;
+ };
+ FD91BA630FC231BF00643D04 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = makewhatis;
+ };
+ name = Release;
+ };
+ FD91BA910FC232FB00643D04 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = Other;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ FD91BA0C0FC2310A00643D04 /* Build configuration list for PBXProject "doc_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD91BA0B0FC2310A00643D04 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD91BA500FC231AB00643D04 /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD91BA480FC2319F00643D04 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD91BA510FC231AB00643D04 /* Build configuration list for PBXNativeTarget "checknr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD91BA4F0FC231AB00643D04 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD91BA720FC2320800643D04 /* Build configuration list for PBXNativeTarget "colcrt" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD91BA570FC231B200643D04 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD91BA740FC2320800643D04 /* Build configuration list for PBXNativeTarget "makewhatis" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD91BA630FC231BF00643D04 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD91BAA00FC2331400643D04 /* Build configuration list for PBXAggregateTarget "Other Files" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD91BA910FC232FB00643D04 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FD91BA090FC2310A00643D04 /* Project object */;
+}
diff --git a/doc_cmds/intro.1 b/doc_cmds/intro.1
new file mode 100644
index 0000000..98c603c
--- /dev/null
+++ b/doc_cmds/intro.1
@@ -0,0 +1,74 @@
+.\" $NetBSD: intro.1,v 1.4 1994/11/30 08:35:00 jtc Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)intro.1 8.2 (Berkeley) 12/30/93
+.\"
+.Dd December 30, 1993
+.Dt INTRO 1
+.Os
+.Sh NAME
+.Nm intro
+.Nd introduction to general commands (tools and utilities)
+.Sh DESCRIPTION
+Section one of the manual contains most of the commands
+which comprise the
+.Bx
+user environment.
+Some of the commands included in section one are
+text editors, command shell interpreters,
+searching and sorting tools,
+file manipulation commands
+system status commands,
+remote file copy commands, mail commands,
+compilers and compiler tools,
+formatted output tools,
+and line printer commands.
+.Pp
+All commands set a status value upon exit which may be tested
+to see if the command completed normally.
+The exit values and their meanings are explained in the individual
+manuals. Traditionally, the value 0 signifies successful
+completion of the command.
+.Sh SEE ALSO
+.Xr man 1 ,
+.Xr intro 2 ,
+.Xr intro 4 ,
+.Xr intro 8 ,
+.Pp
+Tutorials in the
+.%T "UNIX User's Manual Supplementary Documents" .
+.Sh HISTORY
+A
+.Nm intro
+manual appeared in
+.At v6 .
diff --git a/doc_cmds/makewhatis/makewhatis.8 b/doc_cmds/makewhatis/makewhatis.8
new file mode 100644
index 0000000..5c59b96
--- /dev/null
+++ b/doc_cmds/makewhatis/makewhatis.8
@@ -0,0 +1,133 @@
+.\" Copyright (c) 2002 John Rochester
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/makewhatis/makewhatis.1,v 1.3 2002/05/18 15:39:56 ru Exp $
+.\"
+.Dd May 12, 2002
+.Dt MAKEWHATIS 8
+.Os
+.Sh NAME
+.Nm makewhatis
+.Nd "create whatis database"
+.Sh SYNOPSIS
+.Nm
+.Op Fl a
+.Op Fl i Ar column
+.Op Fl n Ar name
+.Op Fl o Ar file
+.Op Fl v
+.Op Fl L
+.Op Ar directories ...
+.Sh DESCRIPTION
+The
+.Nm
+utility collects the names and short descriptions from all the unformatted
+man pages in the
+.Ar directories
+and puts them into a file used by the
+.Xr whatis 1
+and
+.Xr apropos 1
+commands.
+Directories may be separated by colons instead of spaces.
+If no
+.Ar directories
+are specified, the contents of the
+.Ev MANPATH
+environment variable will be used, or if that is not set, the default directory
+.Pa /usr/share/man
+will be processed.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl i Ar column"
+.It Fl a
+Appends to the output file(s) instead of replacing them.
+The output
+will be sorted with duplicate lines removed, but may have obsolete
+entries.
+.It Fl i Ar column
+Indents the description by
+.Ar column
+characters.
+The default value is 24.
+.It Fl n Ar name
+Uses
+.Ar name
+instead of
+.Pa whatis .
+.It Fl o Ar file
+Outputs all lines to the
+.Ar file
+instead of
+.Pa */man/whatis .
+.It Fl v
+Makes
+.Nm
+more verbose about what it is doing.
+.It Fl L
+Process only localized subdirectories corresponding to the locale specified
+in the standard environment variables.
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev MANPATH"
+.It Ev LC_ALL , LC_CTYPE , LANG
+These variables control what subdirectories will be processed if the
+.Fl L
+option is used.
+.It Ev MACHINE
+If set, its value is used to override the current
+machine type when searching machine specific subdirectories.
+.It Ev MANPATH
+Determines the set of directories to be processed if none are given on
+the command line.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /usr/share/man" -compact
+.It Pa /usr/share/man
+Default directory to process if the
+.Ev MANPATH
+environment variable is not set.
+.It Pa */man/whatis
+The default output file.
+.El
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr apropos 1 ,
+.Xr whatis 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 2.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+program was originally written in Perl and was contributed by
+.An Wolfram Schneider .
+The current version of
+.Nm
+was rewritten in C by
+.An John Rochester .
diff --git a/doc_cmds/makewhatis/makewhatis.c b/doc_cmds/makewhatis/makewhatis.c
new file mode 100644
index 0000000..1a98842
--- /dev/null
+++ b/doc_cmds/makewhatis/makewhatis.c
@@ -0,0 +1,1094 @@
+/*-
+ * Copyright (c) 2002 John Rochester
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/makewhatis/makewhatis.c,v 1.9 2002/09/04 23:29:04 dwmalone Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+
+/* Workaround for missing #define in sys/queue.h (3806865) */
+#ifndef SLIST_HEAD_INITIALIZER
+#define SLIST_HEAD_INITIALIZER(head) { NULL }
+#endif
+
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stringlist.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#define DEFAULT_MANPATH "/usr/share/man"
+#define LINE_ALLOC 4096
+
+static char blank[] = "";
+
+/*
+ * Information collected about each man page in a section.
+ */
+struct page_info {
+ char * filename;
+ char * name;
+ char * suffix;
+ int gzipped;
+ ino_t inode;
+};
+
+/*
+ * An entry kept for each visited directory.
+ */
+struct visited_dir {
+ dev_t device;
+ ino_t inode;
+ SLIST_ENTRY(visited_dir) next;
+};
+
+/*
+ * an expanding string
+ */
+struct sbuf {
+ char * content; /* the start of the buffer */
+ char * end; /* just past the end of the content */
+ char * last; /* the last allocated character */
+};
+
+/*
+ * Removes the last amount characters from the sbuf.
+ */
+#define sbuf_retract(sbuf, amount) \
+ ((sbuf)->end -= (amount))
+/*
+ * Returns the length of the sbuf content.
+ */
+#define sbuf_length(sbuf) \
+ ((sbuf)->end - (sbuf)->content)
+
+typedef char *edited_copy(char *from, char *to, int length);
+
+static int append; /* -a flag: append to existing whatis */
+static int verbose; /* -v flag: be verbose with warnings */
+static int indent = 24; /* -i option: description indentation */
+static const char *whatis_name="whatis";/* -n option: the name */
+static char *common_output; /* -o option: the single output file */
+static char *locale; /* user's locale if -L is used */
+static char *lang_locale; /* short form of locale */
+#ifndef __APPLE__
+static const char *machine;
+#endif /* !__APPLE__ */
+
+static int exit_code; /* exit code to use when finished */
+static SLIST_HEAD(, visited_dir) visited_dirs =
+ SLIST_HEAD_INITIALIZER(visited_dirs);
+
+/*
+ * While the whatis line is being formed, it is stored in whatis_proto.
+ * When finished, it is reformatted into whatis_final and then appended
+ * to whatis_lines.
+ */
+static struct sbuf *whatis_proto;
+static struct sbuf *whatis_final;
+static StringList *whatis_lines; /* collected output lines */
+
+static char tmp_file[MAXPATHLEN]; /* path of temporary file, if any */
+static char tmp_rel_file[MAXPATHLEN];
+
+/* A set of possible names for the NAME man page section */
+static const char *name_section_titles[] = {
+ "NAME", "Name", "NAMN", "BEZEICHNUNG", "\xcc\xbe\xbe\xce",
+ "\xee\xe1\xfa\xf7\xe1\xee\xe9\xe5", NULL
+};
+
+/* A subset of the mdoc(7) commands to ignore */
+static char mdoc_commands[] = "ArDvErEvFlLiNmPa";
+
+/*
+ * Frees a struct page_info and its content.
+ */
+static void
+free_page_info(struct page_info *info)
+{
+ free(info->filename);
+ free(info->name);
+ free(info->suffix);
+ free(info);
+}
+
+/*
+ * Allocates and fills in a new struct page_info given the
+ * name of the man section directory and the dirent of the file.
+ * If the file is not a man page, returns NULL.
+ */
+static struct page_info *
+new_page_info(char *dir, struct dirent *dirent)
+{
+ struct page_info *info;
+ int basename_length;
+ char *suffix;
+ struct stat st;
+
+ info = (struct page_info *) malloc(sizeof(struct page_info));
+ if (info == NULL)
+ err(1, "malloc");
+ basename_length = strlen(dirent->d_name);
+ suffix = &dirent->d_name[basename_length];
+ asprintf(&info->filename, "%s/%s", dir, dirent->d_name);
+ if ((info->gzipped = basename_length >= 4 && strcmp(&dirent->d_name[basename_length - 3], ".gz") == 0)) {
+ suffix -= 3;
+ *suffix = '\0';
+ }
+ for (;;) {
+ if (--suffix == dirent->d_name || !isalnum(*suffix)) {
+ if (*suffix == '.')
+ break;
+ if (verbose)
+ warnx("%s: invalid man page name", info->filename);
+ free(info->filename);
+ free(info);
+ return NULL;
+ }
+ }
+ *suffix++ = '\0';
+ info->name = strdup(dirent->d_name);
+ info->suffix = strdup(suffix);
+ if (stat(info->filename, &st) < 0) {
+ warn("%s", info->filename);
+ free_page_info(info);
+ return NULL;
+ }
+ if (!S_ISREG(st.st_mode)) {
+ if (verbose && !S_ISDIR(st.st_mode))
+ warnx("%s: not a regular file", info->filename);
+ free_page_info(info);
+ return NULL;
+ }
+ info->inode = st.st_ino;
+ return info;
+}
+
+/*
+ * Reset an sbuf's length to 0.
+ */
+static void
+sbuf_clear(struct sbuf *sbuf)
+{
+ sbuf->end = sbuf->content;
+}
+
+/*
+ * Allocate a new sbuf.
+ */
+static struct sbuf *
+new_sbuf(void)
+{
+ struct sbuf *sbuf = (struct sbuf *) malloc(sizeof(struct sbuf));
+ sbuf->content = (char *) malloc(LINE_ALLOC);
+ sbuf->last = sbuf->content + LINE_ALLOC - 1;
+ sbuf_clear(sbuf);
+ return sbuf;
+}
+
+/*
+ * Ensure that there is enough room in the sbuf for nchars more characters.
+ */
+static void
+sbuf_need(struct sbuf *sbuf, int nchars)
+{
+ char *new_content;
+ size_t size, cntsize;
+
+ /* double the size of the allocation until the buffer is big enough */
+ while (sbuf->end + nchars > sbuf->last) {
+ size = sbuf->last + 1 - sbuf->content;
+ size *= 2;
+ cntsize = sbuf->end - sbuf->content;
+
+ new_content = (char *)malloc(size);
+ memcpy(new_content, sbuf->content, cntsize);
+ free(sbuf->content);
+ sbuf->content = new_content;
+ sbuf->end = new_content + cntsize;
+ sbuf->last = new_content + size - 1;
+ }
+}
+
+/*
+ * Appends a string of a given length to the sbuf.
+ */
+static void
+sbuf_append(struct sbuf *sbuf, const char *text, int length)
+{
+ if (length > 0) {
+ sbuf_need(sbuf, length);
+ memcpy(sbuf->end, text, length);
+ sbuf->end += length;
+ }
+}
+
+/*
+ * Appends a null-terminated string to the sbuf.
+ */
+static void
+sbuf_append_str(struct sbuf *sbuf, char *text)
+{
+ sbuf_append(sbuf, text, strlen(text));
+}
+
+/*
+ * Appends an edited null-terminated string to the sbuf.
+ */
+static void
+sbuf_append_edited(struct sbuf *sbuf, char *text, edited_copy copy)
+{
+ int length = strlen(text);
+ if (length > 0) {
+ sbuf_need(sbuf, length);
+ sbuf->end = copy(text, sbuf->end, length);
+ }
+}
+
+/*
+ * Strips any of a set of chars from the end of the sbuf.
+ */
+static void
+sbuf_strip(struct sbuf *sbuf, const char *set)
+{
+ while (sbuf->end > sbuf->content && strchr(set, sbuf->end[-1]) != NULL)
+ sbuf->end--;
+}
+
+/*
+ * Returns the null-terminated string built by the sbuf.
+ */
+static char *
+sbuf_content(struct sbuf *sbuf)
+{
+ *sbuf->end = '\0';
+ return sbuf->content;
+}
+
+/*
+ * Returns true if no man page exists in the directory with
+ * any of the names in the StringList.
+ */
+static int
+no_page_exists(char *dir, StringList *names, char *suffix)
+{
+ char path[MAXPATHLEN];
+ size_t i;
+
+ for (i = 0; i < names->sl_cur; i++) {
+ snprintf(path, sizeof path, "%s/%s.%s.gz", dir, names->sl_str[i], suffix);
+ if (access(path, F_OK) < 0) {
+ path[strlen(path) - 3] = '\0';
+ if (access(path, F_OK) < 0)
+ continue;
+ }
+ return 0;
+ }
+ return 1;
+}
+
+static void
+trap_signal(int sig __unused)
+{
+ if (tmp_file[0] != '\0')
+ unlink(tmp_file);
+ exit(1);
+}
+
+/*
+ * Attempts to open an output file. Returns NULL if unsuccessful.
+ */
+static FILE *
+open_output(char *name, int dir_fd, char *rel_name)
+{
+ FILE *output;
+ int output_fd;
+ struct stat statbuf;
+
+ whatis_lines = sl_init();
+ if (append) {
+ char line[LINE_ALLOC];
+
+ output_fd = openat(dir_fd, rel_name, O_RDONLY);
+ if (output_fd == -1) {
+ warn("%s", name);
+ exit_code = 1;
+ return NULL;
+ }
+ output = fdopen(output_fd, "r");
+ if (output == NULL) {
+ warn("%s", name);
+ exit_code = 1;
+ return NULL;
+ }
+ while (fgets(line, sizeof line, output) != NULL) {
+ line[strlen(line) - 1] = '\0';
+ sl_add(whatis_lines, strdup(line));
+ }
+ fclose(output);
+ }
+ if (common_output == NULL) {
+ snprintf(tmp_file, sizeof tmp_file, "%s.tmp", name);
+ snprintf(tmp_rel_file, sizeof tmp_rel_file, "%s.tmp", rel_name);
+ name = tmp_file;
+ rel_name = tmp_rel_file;
+ }
+ /* Bail out if the file is actually a symlink or has another link.
+ * This script can run as root and we don't want to risk writing
+ * into a random location.
+ * See rdar://problem/55280616
+ */
+ output_fd = openat(dir_fd, rel_name, O_WRONLY | O_NOFOLLOW | O_CREAT | O_TRUNC, 0644);
+ if (output_fd == -1) {
+ warn("%s", name);
+ exit_code = 1;
+ return NULL;
+ }
+ if (fstat(output_fd, &statbuf) == -1) {
+ warn("%s: unable to stat", name);
+ close(output_fd);
+ exit_code = 1;
+ return NULL;
+ }
+ if (statbuf.st_nlink > 1) {
+ warnx("%s: is a hardlink", name);
+ close(output_fd);
+ exit_code = 1;
+ return NULL;
+ }
+ output = fdopen(output_fd, "w");
+ if (output == NULL) {
+ warn("%s", name);
+ exit_code = 1;
+ return NULL;
+ }
+ return output;
+}
+
+static int
+linesort(const void *a, const void *b)
+{
+ return strcmp((*(const char * const *)a), (*(const char * const *)b));
+}
+
+/*
+ * Writes the unique sorted lines to the output file.
+ */
+static void
+finish_output(FILE *output, char *name, int dir_fd, char *rel_name)
+{
+ size_t i;
+ char *prev = NULL;
+
+ qsort(whatis_lines->sl_str, whatis_lines->sl_cur, sizeof(char *), linesort);
+ for (i = 0; i < whatis_lines->sl_cur; i++) {
+ char *line = whatis_lines->sl_str[i];
+ if (i > 0 && strcmp(line, prev) == 0)
+ continue;
+ prev = line;
+ fputs(line, output);
+ putc('\n', output);
+ }
+ fclose(output);
+ sl_free(whatis_lines, 1);
+ if (common_output == NULL) {
+ renameat(dir_fd, tmp_rel_file, dir_fd, rel_name);
+ unlinkat(dir_fd, tmp_rel_file, 0);
+ }
+}
+
+static FILE *
+open_whatis(char *mandir, int mandir_fd)
+{
+ char filename[MAXPATHLEN];
+
+ snprintf(filename, sizeof filename, "%s/%s", mandir, whatis_name);
+ return open_output(filename, mandir_fd, whatis_name);
+}
+
+static void
+finish_whatis(FILE *output, char *mandir, int mandir_fd)
+{
+ char filename[MAXPATHLEN];
+
+ snprintf(filename, sizeof filename, "%s/%s", mandir, whatis_name);
+ finish_output(output, filename, mandir_fd, whatis_name);
+}
+
+/*
+ * Tests to see if the given directory has already been visited.
+ */
+static int
+already_visited(char *dir)
+{
+ struct stat st;
+ struct visited_dir *visit;
+
+ if (stat(dir, &st) < 0) {
+ warn("%s", dir);
+ exit_code = 1;
+ return 1;
+ }
+ SLIST_FOREACH(visit, &visited_dirs, next) {
+ if (visit->inode == st.st_ino &&
+ visit->device == st.st_dev) {
+ warnx("already visited %s", dir);
+ return 1;
+ }
+ }
+ visit = (struct visited_dir *) malloc(sizeof(struct visited_dir));
+ visit->device = st.st_dev;
+ visit->inode = st.st_ino;
+ SLIST_INSERT_HEAD(&visited_dirs, visit, next);
+ return 0;
+}
+
+/*
+ * Removes trailing spaces from a string, returning a pointer to just
+ * beyond the new last character.
+ */
+static char *
+trim_rhs(char *str)
+{
+ char *rhs = &str[strlen(str)];
+ while (--rhs > str && isspace(*rhs))
+ ;
+ *++rhs = '\0';
+ return rhs;
+}
+
+/*
+ * Returns a pointer to the next non-space character in the string.
+ */
+static char *
+skip_spaces(char *s)
+{
+ while (*s != '\0' && isspace(*s))
+ s++;
+ return s;
+}
+
+/*
+ * Returns whether the string contains only digits.
+ */
+static int
+only_digits(char *line)
+{
+ if (!isdigit(*line++))
+ return 0;
+ while (isdigit(*line))
+ line++;
+ return *line == '\0';
+}
+
+/*
+ * Returns whether the line is of one of the forms:
+ * .Sh NAME
+ * .Sh "NAME"
+ * etc.
+ * assuming that section_start is ".Sh".
+ */
+static int
+name_section_line(char *line, const char *section_start)
+{
+ char *rhs;
+ const char **title;
+
+ if (strncmp(line, section_start, 3) != 0)
+ return 0;
+ line = skip_spaces(line + 3);
+ rhs = trim_rhs(line);
+ if (*line == '"') {
+ line++;
+ if (*--rhs == '"')
+ *rhs = '\0';
+ }
+ for (title = name_section_titles; *title != NULL; title++)
+ if (strcmp(*title, line) == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * Copies characters while removing the most common nroff/troff
+ * markup:
+ * \(em, \(mi, \s[+-N], \&
+ * \fF, \f(fo, \f[font]
+ * \*s, \*(st, \*[stringvar]
+ */
+static char *
+de_nroff_copy(char *from, char *to, int fromlen)
+{
+ char *from_end = &from[fromlen];
+ while (from < from_end) {
+ switch (*from) {
+ case '\\':
+ switch (*++from) {
+ case '(':
+ if (strncmp(&from[1], "em", 2) == 0 ||
+ strncmp(&from[1], "mi", 2) == 0) {
+ from += 3;
+ continue;
+ }
+ break;
+ case 's':
+ if (*++from == '-')
+ from++;
+ while (isdigit(*from))
+ from++;
+ continue;
+ case 'f':
+ case '*':
+ if (*++from == '(')
+ from += 3;
+ else if (*from == '[') {
+ while (*++from != ']' && from < from_end);
+ from++;
+ } else
+ from++;
+ continue;
+ case '&':
+ from++;
+ continue;
+ }
+ break;
+ }
+ *to++ = *from++;
+ }
+ return to;
+}
+
+/*
+ * Appends a string with the nroff formatting removed.
+ */
+static void
+add_nroff(char *text)
+{
+ sbuf_append_edited(whatis_proto, text, de_nroff_copy);
+}
+
+/*
+ * Appends "name(suffix), " to whatis_final.
+ */
+static void
+add_whatis_name(char *name, char *suffix)
+{
+ if (*name != '\0') {
+ sbuf_append_str(whatis_final, name);
+ sbuf_append(whatis_final, "(", 1);
+ sbuf_append_str(whatis_final, suffix);
+ sbuf_append(whatis_final, "), ", 3);
+ }
+}
+
+/*
+ * Processes an old-style man(7) line. This ignores commands with only
+ * a single number argument.
+ */
+static void
+process_man_line(char *line)
+{
+ if (*line == '.') {
+ while (isalpha(*++line))
+ ;
+ line = skip_spaces(line);
+ if (only_digits(line))
+ return;
+ } else
+ line = skip_spaces(line);
+#ifdef __APPLE__
+ /* 4454557 */
+ if (*line == '"')
+ ++line;
+#endif /* __APPLE__ */
+ if (*line != '\0') {
+ add_nroff(line);
+ sbuf_append(whatis_proto, " ", 1);
+ }
+}
+
+/*
+ * Processes a new-style mdoc(7) line.
+ */
+static void
+process_mdoc_line(char *line)
+{
+ int xref;
+ int arg = 0;
+ char *line_end = &line[strlen(line)];
+ int orig_length = sbuf_length(whatis_proto);
+ char *next;
+
+ if (*line == '\0')
+ return;
+ if (line[0] != '.' || !isupper(line[1]) || !islower(line[2])) {
+ add_nroff(skip_spaces(line));
+ sbuf_append(whatis_proto, " ", 1);
+ return;
+ }
+ xref = strncmp(line, ".Xr", 3) == 0;
+ line += 3;
+ while ((line = skip_spaces(line)) < line_end) {
+ if (*line == '"') {
+ next = ++line;
+ for (;;) {
+ next = strchr(next, '"');
+ if (next == NULL)
+ break;
+ memmove(next, next + 1, strlen(next));
+ line_end--;
+ if (*next != '"')
+ break;
+ next++;
+ }
+ } else
+ next = strpbrk(line, " \t");
+ if (next != NULL)
+ *next++ = '\0';
+ else
+ next = line_end;
+ if (isupper(*line) && islower(line[1]) && line[2] == '\0') {
+ if (strcmp(line, "Ns") == 0) {
+ arg = 0;
+ line = next;
+ continue;
+ }
+ if (strstr(mdoc_commands, line) != NULL) {
+ line = next;
+ continue;
+ }
+ }
+ if (arg > 0 && strchr(",.:;?!)]", *line) == 0) {
+ if (xref) {
+ sbuf_append(whatis_proto, "(", 1);
+ add_nroff(line);
+ sbuf_append(whatis_proto, ")", 1);
+ xref = 0;
+ line = blank;
+ } else
+ sbuf_append(whatis_proto, " ", 1);
+ }
+ add_nroff(line);
+ arg++;
+ line = next;
+ }
+ if (sbuf_length(whatis_proto) > orig_length)
+ sbuf_append(whatis_proto, " ", 1);
+}
+
+/*
+ * Collects a list of comma-separated names from the text.
+ */
+static void
+collect_names(StringList *names, char *text)
+{
+ char *arg;
+
+ for (;;) {
+ arg = text;
+ text = strchr(text, ',');
+ if (text != NULL)
+ *text++ = '\0';
+ sl_add(names, arg);
+ if (text == NULL)
+ return;
+ if (*text == ' ')
+ text++;
+ }
+}
+
+enum { STATE_UNKNOWN, STATE_MANSTYLE, STATE_MDOCNAME, STATE_MDOCDESC };
+
+/*
+ * Processes a man page source into a single whatis line and adds it
+ * to whatis_lines.
+ */
+static void
+process_page(struct page_info *page, char *section_dir)
+{
+ gzFile *in;
+ char buffer[4096];
+ char *line;
+ StringList *names;
+ char *descr;
+ int state = STATE_UNKNOWN;
+ size_t i;
+
+ sbuf_clear(whatis_proto);
+ if ((in = gzopen(page->filename, "r")) == NULL) {
+ warn("%s", page->filename);
+ exit_code = 1;
+ return;
+ }
+ while (gzgets(in, buffer, sizeof buffer) != NULL) {
+ line = buffer;
+ if (strncmp(line, ".\\\"", 3) == 0) /* ignore comments */
+ continue;
+ switch (state) {
+ /*
+ * haven't reached the NAME section yet.
+ */
+ case STATE_UNKNOWN:
+ if (name_section_line(line, ".SH"))
+ state = STATE_MANSTYLE;
+ else if (name_section_line(line, ".Sh"))
+ state = STATE_MDOCNAME;
+ continue;
+ /*
+ * Inside an old-style .SH NAME section.
+ */
+ case STATE_MANSTYLE:
+ if ((strncmp(line, ".SH", 3) == 0) || (strncmp(line, ".SS", 3) == 0))
+ break;
+ trim_rhs(line);
+ if (strcmp(line, ".") == 0)
+ continue;
+ if (strncmp(line, ".IX", 3) == 0) {
+ line += 3;
+ line = skip_spaces(line);
+ }
+ process_man_line(line);
+ continue;
+ /*
+ * Inside a new-style .Sh NAME section (the .Nm part).
+ */
+ case STATE_MDOCNAME:
+ trim_rhs(line);
+ if (strncmp(line, ".Nm", 3) == 0) {
+ process_mdoc_line(line);
+ continue;
+ } else {
+ if (strcmp(line, ".") == 0)
+ continue;
+ sbuf_append(whatis_proto, "- ", 2);
+ state = STATE_MDOCDESC;
+ }
+ /* fall through */
+ /*
+ * Inside a new-style .Sh NAME section (after the .Nm-s).
+ */
+ case STATE_MDOCDESC:
+ if (strncmp(line, ".Sh", 3) == 0)
+ break;
+ trim_rhs(line);
+ if (strcmp(line, ".") == 0)
+ continue;
+ process_mdoc_line(line);
+ continue;
+ }
+ break;
+ }
+ gzclose(in);
+ sbuf_strip(whatis_proto, " \t.-");
+ line = sbuf_content(whatis_proto);
+ /*
+ * line now contains the appropriate data, but without
+ * the proper indentation or the section appended to each name.
+ */
+ descr = strstr(line, " - ");
+ if (descr == NULL) {
+ descr = strchr(line, ' ');
+ if (descr == NULL) {
+ if (verbose)
+ fprintf(stderr, " ignoring junk description \"%s\"\n", line);
+ return;
+ }
+ *descr++ = '\0';
+ } else {
+ *descr = '\0';
+ descr += 3;
+ }
+ names = sl_init();
+ collect_names(names, line);
+ sbuf_clear(whatis_final);
+ if (!sl_find(names, page->name) && no_page_exists(section_dir, names, page->suffix)) {
+ /*
+ * Add the page name since that's the only thing that
+ * man(1) will find.
+ */
+ add_whatis_name(page->name, page->suffix);
+ }
+ for (i = 0; i < names->sl_cur; i++)
+ add_whatis_name(names->sl_str[i], page->suffix);
+ sl_free(names, 0);
+ sbuf_retract(whatis_final, 2); /* remove last ", " */
+ while (sbuf_length(whatis_final) < indent)
+ sbuf_append(whatis_final, " ", 1);
+ sbuf_append(whatis_final, " - ", 3);
+ sbuf_append_str(whatis_final, skip_spaces(descr));
+ sl_add(whatis_lines, strdup(sbuf_content(whatis_final)));
+}
+
+/*
+ * Sorts pages first by inode number, then by name.
+ */
+static int
+pagesort(const void *a, const void *b)
+{
+ const struct page_info *p1 = *(struct page_info * const *) a;
+ const struct page_info *p2 = *(struct page_info * const *) b;
+ if (p1->inode == p2->inode)
+ return strcmp(p1->name, p2->name);
+ return p1->inode - p2->inode;
+}
+
+/*
+ * Processes a single man section.
+ */
+static void
+process_section(char *section_dir)
+{
+ struct dirent **entries;
+ int nentries;
+ struct page_info **pages;
+ int npages = 0;
+ int i;
+ ino_t prev_inode = 0;
+
+ if (verbose)
+ fprintf(stderr, " %s\n", section_dir);
+
+ /*
+ * scan the man section directory for pages
+ */
+ nentries = scandir(section_dir, &entries, NULL, alphasort);
+ if (nentries < 0) {
+ warn("%s", section_dir);
+ exit_code = 1;
+ return;
+ }
+ /*
+ * collect information about man pages
+ */
+ pages = (struct page_info **) calloc(nentries, sizeof(struct page_info *));
+ for (i = 0; i < nentries; i++) {
+ struct page_info *info = new_page_info(section_dir, entries[i]);
+ if (info != NULL)
+ pages[npages++] = info;
+ free(entries[i]);
+ }
+ free(entries);
+ qsort(pages, npages, sizeof(struct page_info *), pagesort);
+ /*
+ * process each unique page
+ */
+ for (i = 0; i < npages; i++) {
+ struct page_info *page = pages[i];
+ if (page->inode != prev_inode) {
+ prev_inode = page->inode;
+ if (verbose)
+ fprintf(stderr, " reading %s\n", page->filename);
+ process_page(page, section_dir);
+ } else if (verbose)
+ fprintf(stderr, " skipping %s, duplicate\n", page->filename);
+ free_page_info(page);
+ }
+ free(pages);
+}
+
+/*
+ * Returns whether the directory entry is a man page section.
+ */
+static int
+select_sections(struct dirent *entry)
+{
+ char *p = &entry->d_name[3];
+
+ if (strncmp(entry->d_name, "man", 3) != 0)
+ return 0;
+ while (*p != '\0') {
+ if (!isalnum(*p++))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Processes a single top-level man directory by finding all the
+ * sub-directories named man* and processing each one in turn.
+ */
+static void
+process_mandir(char *dir_name)
+{
+ int dir_fd;
+ DIR *dir;
+ FILE *fp = NULL;
+ struct dirent *entry;
+ struct stat st;
+
+ if (already_visited(dir_name))
+ return;
+ if (verbose)
+ fprintf(stderr, "man directory %s\n", dir_name);
+
+ dir_fd = open(dir_name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
+ if (dir_fd == -1) {
+ warn("%s", dir_name);
+ exit_code = 1;
+ return;
+ }
+ dir = fdopendir(dir_fd);
+ if (dir == NULL) {
+ warn("%s", dir_name);
+ close(dir_fd);
+ exit_code = 1;
+ return;
+ }
+ if (common_output == NULL && (fp = open_whatis(dir_name, dir_fd)) == NULL) {
+ closedir(dir);
+ return;
+ }
+ while ((entry = readdir(dir)) != NULL) {
+ char section_dir[MAXPATHLEN];
+ if (select_sections(entry) == 0)
+ continue;
+ snprintf(section_dir, sizeof section_dir, "%s/%s", dir_name, entry->d_name);
+ process_section(section_dir);
+#ifndef __APPLE__
+ snprintf(section_dir, sizeof section_dir, "%s/%s/%s", dir_name,
+ entry->d_name, machine);
+ if (stat(section_dir, &st) == 0 && S_ISDIR(st.st_mode))
+ process_section(section_dir);
+#endif /* !__APPLE__ */
+ }
+ if (common_output == NULL)
+ finish_whatis(fp, dir_name, dir_fd);
+ closedir(dir);
+}
+
+/*
+ * Processes one argument, which may be a colon-separated list of
+ * directories.
+ */
+static void
+process_argument(const char *arg)
+{
+ char *dir;
+ char *mandir;
+ char *parg;
+
+ parg = strdup(arg);
+ if (parg == NULL)
+ err(1, "out of memory");
+ while ((dir = strsep(&parg, ":")) != NULL) {
+ if (locale != NULL) {
+ asprintf(&mandir, "%s/%s", dir, locale);
+ process_mandir(mandir);
+ free(mandir);
+ if (lang_locale != NULL) {
+ asprintf(&mandir, "%s/%s", dir, lang_locale);
+ process_mandir(mandir);
+ free(mandir);
+ }
+ } else {
+ process_mandir(dir);
+ }
+ }
+ free(parg);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ int opt;
+ FILE *fp = NULL;
+
+ while ((opt = getopt(argc, argv, "ai:n:o:vL")) != -1) {
+ switch (opt) {
+ case 'a':
+ append++;
+ break;
+ case 'i':
+ indent = atoi(optarg);
+ break;
+ case 'n':
+ whatis_name = optarg;
+ break;
+ case 'o':
+ common_output = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'L':
+ locale = getenv("LC_ALL");
+ if (locale == NULL)
+ locale = getenv("LC_CTYPE");
+ if (locale == NULL)
+ locale = getenv("LANG");
+ if (locale != NULL) {
+ char *sep = strchr(locale, '_');
+ if (sep != NULL && isupper(sep[1]) &&
+ isupper(sep[2])) {
+ asprintf(&lang_locale, "%.*s%s", sep - locale, locale, &sep[3]);
+ }
+ }
+ break;
+ default:
+ fprintf(stderr, "usage: %s [-a] [-i indent] [-n name] [-o output_file] [-v] [-L] [directories...]\n", argv[0]);
+ exit(1);
+ }
+ }
+
+ signal(SIGINT, trap_signal);
+ signal(SIGHUP, trap_signal);
+ signal(SIGQUIT, trap_signal);
+ signal(SIGTERM, trap_signal);
+ SLIST_INIT(&visited_dirs);
+ whatis_proto = new_sbuf();
+ whatis_final = new_sbuf();
+
+#ifndef __APPLE__
+ if ((machine = getenv("MACHINE")) == NULL)
+ machine = MACHINE;
+#endif /* !__APPLE__ */
+
+ if (common_output != NULL && (fp = open_output(common_output, AT_FDCWD, common_output)) == NULL)
+ err(1, "%s", common_output);
+ if (optind == argc) {
+ const char *manpath = getenv("MANPATH");
+ if (manpath == NULL)
+ manpath = DEFAULT_MANPATH;
+ process_argument(manpath);
+ } else {
+ while (optind < argc)
+ process_argument(argv[optind++]);
+ }
+ if (common_output != NULL)
+ finish_output(fp, common_output, AT_FDCWD, common_output);
+ exit(exit_code);
+}
diff --git a/doc_cmds/makewhatis/makewhatis.local.8 b/doc_cmds/makewhatis/makewhatis.local.8
new file mode 100644
index 0000000..597d78b
--- /dev/null
+++ b/doc_cmds/makewhatis/makewhatis.local.8
@@ -0,0 +1,69 @@
+.\" Copyright (c) April 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/makewhatis/makewhatis.local.8,v 1.15 2004/07/02 22:22:28 ru Exp $
+.Dd April 26, 1996
+.Dt MAKEWHATIS.LOCAL 8
+.Os
+.Sh NAME
+.Nm makewhatis.local
+.Nd start makewhatis for local file systems
+.Sh SYNOPSIS
+.Nm /usr/libexec/makewhatis.local
+.Op options
+.Ar directories ...
+.Sh DESCRIPTION
+The
+.Nm
+utility starts
+.Xr makewhatis 8
+only for file systems physically mounted on the system
+where the
+.Nm
+is being executed.
+Running makewhatis
+by
+.Pa periodic weekly
+for rw nfs-mounted /usr may kill
+your NFS server -- all NFS clients start makewhatis at the same time!
+So use this wrapper for
+.Xr cron 8
+instead of calling makewhatis directly.
+.Sh FILES
+.Bl -tag -width /etc/periodic/weekly/320.whatis.XXX -compact
+.It Pa /etc/periodic/weekly/320.whatis
+run
+.Nm
+every week
+.El
+.Sh SEE ALSO
+.Xr find 1 ,
+.Xr makewhatis 8 ,
+.Xr cron 8 ,
+.Xr periodic 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Fx 2.2 .
diff --git a/doc_cmds/makewhatis/makewhatis.local.sh b/doc_cmds/makewhatis/makewhatis.local.sh
new file mode 100644
index 0000000..6baedcb
--- /dev/null
+++ b/doc_cmds/makewhatis/makewhatis.local.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# Copyright (c) April 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# 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.
+#
+# makewhatis.local - start makewhatis(1) only for file systems
+# physically mounted on the system
+#
+# Running makewhatis from /etc/periodic/weekly/320.whatis for rw nfs-mounted
+# /usr may kill your NFS server -- all clients start makewhatis at the same
+# time! So use this wrapper instead calling makewhatis directly.
+#
+# PS: this wrapper works also for catman(1)
+#
+# $FreeBSD: src/usr.bin/makewhatis/makewhatis.local.sh,v 1.7 1999/08/27 23:36:10 peter Exp $
+PATH=/bin:/usr/bin:/usr/libexec:$PATH; export PATH
+opt= dirs= localdirs= stdout=
+
+for arg
+do
+ case "$arg" in
+ "-o /dev/fd/1")
+ opt="$opt $arg"
+ stdout=1;;
+ -*) opt="$opt $arg";;
+ *) dirs="$dirs $arg";;
+ esac
+done
+
+if [[ -z "$stdout" ]]; then
+ dirs=`echo $dirs | awk -F: '{ for (i = 1; i <= NF; i++) { if ($i !~ "\\.app/" && $i !~ "/CommandLineTools/") { printf $i " " } } printf "\n" }'`
+else
+ dirs=`echo $dirs | sed 's/:/ /g'`
+fi
+case X"$dirs" in X) echo "usage: $0 [options] directories ..."; exit 1;; esac
+
+localdirs=`find -H $dirs -fstype local -type d -prune -print`
+
+case X"$localdirs" in
+ X) echo "$0: no local-mounted manual directories found: $dirs"
+ exit 1;;
+ *) exec `basename $0 .local` $opt $localdirs;;
+esac
diff --git a/file_cmds/.upstream_base_commits b/file_cmds/.upstream_base_commits
new file mode 100644
index 0000000..9423598
--- /dev/null
+++ b/file_cmds/.upstream_base_commits
@@ -0,0 +1,2 @@
+#freebsd = https://github.com/freebsd/freebsd.git
+chmod/chmod.1 freebsd bin/chmod/chmod.1 14889ebf5bdeaead21c00f70044d9acbb923f6b0
diff --git a/file_cmds/chflags/chflags.1 b/file_cmds/chflags/chflags.1
new file mode 100644
index 0000000..cb0281f
--- /dev/null
+++ b/file_cmds/chflags/chflags.1
@@ -0,0 +1,185 @@
+.\"-
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chflags.1 8.4 (Berkeley) 5/2/95
+.\" $FreeBSD: src/bin/chflags/chflags.1,v 1.30.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $
+.\"
+.Dd March 3, 2006
+.Dt CHFLAGS 1
+.Os
+.Sh NAME
+.Nm chflags
+.Nd change file flags
+.Sh SYNOPSIS
+.Nm
+.Op Fl fhv
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Ar flags
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility modifies the file flags of the listed files
+as specified by the
+.Ar flags
+operand.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl f
+Do not display a diagnostic message if
+.Nm
+could not modify the flags for
+.Va file ,
+nor modify the exit status to reflect such failures.
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl h
+If the
+.Ar file
+is a symbolic link,
+change the file flags of the link itself rather than the file to which it points.
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+This is the default.
+.It Fl R
+Change the file flags for the file hierarchies rooted
+in the files instead of just the files themselves.
+.It Fl v
+Cause
+.Nm
+to be verbose, showing filenames as the flags are modified.
+If the
+.Fl v
+option is specified more than once, the old and new flags of the file
+will also be printed, in octal notation.
+.El
+.Pp
+The flags are specified as an octal number or a comma separated list
+of keywords.
+The following keywords are currently defined:
+.Pp
+.Bl -tag -offset indent -width ".Cm opaque"
+.It Cm arch , archived
+set the archived flag (super-user only)
+.It Cm opaque
+set the opaque flag (owner or super-user only).
+[Directory is opaque when viewed through a union mount]
+.It Cm nodump
+set the nodump flag (owner or super-user only)
+.It Cm sappnd , sappend
+set the system append-only flag (super-user only)
+.It Cm schg , schange , simmutable
+set the system immutable flag (super-user only)
+.It Cm uappnd , uappend
+set the user append-only flag (owner or super-user only)
+.It Cm uchg , uchange , uimmutable
+set the user immutable flag (owner or super-user only)
+.It Cm hidden
+set the hidden flag
+[Hide item from GUI]
+.El
+.Pp
+Putting the letters
+.Dq Ar no
+before or removing the letters
+.Dq Ar no
+from a keyword causes the flag to be cleared.
+For example:
+.Pp
+.Bl -tag -offset indent -width "nouchg" -compact
+.It Ar nouchg
+clear the user immutable flag (owner or super-user only)
+.It Ar dump
+clear the nodump flag (owner or super-user only)
+.El
+.Pp
+Unless the
+.Fl H
+or
+.Fl L
+options are given,
+.Nm
+on a symbolic link always succeeds and has no effect.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+You can use "ls -lO" to see the flags of existing files.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr ls 1 ,
+.Xr chflags 2 ,
+.Xr stat 2 ,
+.Xr fts 3 ,
+.Xr symlink 7
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Bx 4.4 .
+.Sh BUGS
+Only a limited number of utilities are
+.Nm
+aware.
+Some of these tools include
+.Xr ls 1 ,
+.Xr cp 1 ,
+.Xr find 1 ,
+.Xr install 1 ,
+.Xr dump 8 ,
+and
+.Xr restore 8 .
+In particular a tool which is not currently
+.Nm
+aware is the
+.Xr pax 1
+utility.
diff --git a/file_cmds/chflags/chflags.c b/file_cmds/chflags/chflags.c
new file mode 100644
index 0000000..76c8027
--- /dev/null
+++ b/file_cmds/chflags/chflags.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static char sccsid[] = "@(#)chflags.c 8.5 (Berkeley) 4/1/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/chflags/chflags.c,v 1.26.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ FTS *ftsp;
+ FTSENT *p;
+ u_long clear, newflags, set;
+ long val;
+ int Hflag, Lflag, Rflag, fflag, hflag, vflag;
+ int ch, fts_options, oct, rval;
+ char *flags, *ep;
+ int (*change_flags)(const char *, u_int);
+
+ Hflag = Lflag = Rflag = fflag = hflag = vflag = 0;
+ while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = 0;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc < 2)
+ usage();
+
+ if (Rflag) {
+ fts_options = FTS_PHYSICAL;
+ if (hflag)
+ errx(1, "the -R and -h options "
+ "may not be specified together");
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ if (Lflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ } else
+ fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+
+ if (hflag)
+ change_flags = lchflags;
+ else
+ change_flags = chflags;
+
+ flags = *argv;
+ if (*flags >= '0' && *flags <= '7') {
+ errno = 0;
+ val = strtol(flags, &ep, 8);
+ if (val < 0)
+ errno = ERANGE;
+ if (errno)
+ err(1, "invalid flags: %s", flags);
+ if (*ep)
+ errx(1, "invalid flags: %s", flags);
+ set = val;
+ oct = 1;
+ } else {
+ if (strtofflags(&flags, &set, &clear))
+ errx(1, "invalid flag: %s", flags);
+ clear = ~clear;
+ oct = 0;
+ }
+
+ if ((ftsp = fts_open(++argv, fts_options , 0)) == NULL)
+ err(1, NULL);
+
+ for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ switch (p->fts_info) {
+ case FTS_D: /* Change it at FTS_DP if we're recursive. */
+ if (!Rflag)
+ fts_set(ftsp, p, FTS_SKIP);
+ continue;
+ case FTS_DNR: /* Warn, chflag, continue. */
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ case FTS_ERR: /* Warn, continue. */
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ continue;
+ case FTS_SL: /* Ignore. */
+ case FTS_SLNONE:
+ /*
+ * The only symlinks that end up here are ones that
+ * don't point to anything and ones that we found
+ * doing a physical walk.
+ */
+ if (!hflag)
+ continue;
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ if (oct)
+ newflags = set;
+ else
+ newflags = (p->fts_statp->st_flags | set) & clear;
+ if (newflags == p->fts_statp->st_flags)
+ continue;
+ if ((*change_flags)(p->fts_accpath, (u_int)newflags) && !fflag) {
+ warn("%s", p->fts_path);
+ rval = 1;
+ } else if (vflag) {
+ (void)printf("%s", p->fts_path);
+ if (vflag > 1)
+ (void)printf(": 0%lo -> 0%lo",
+ (u_long)p->fts_statp->st_flags,
+ newflags);
+ (void)printf("\n");
+ }
+ }
+ if (errno)
+ err(1, "fts_read");
+ exit(rval);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: chflags [-fhv] [-R [-H | -L | -P]] flags file ...\n");
+ exit(1);
+}
diff --git a/file_cmds/chmod/chmod.1 b/file_cmds/chmod/chmod.1
new file mode 100644
index 0000000..0e89f26
--- /dev/null
+++ b/file_cmds/chmod/chmod.1
@@ -0,0 +1,604 @@
+.\"-
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chmod.1 8.4 (Berkeley) 3/31/94
+.\" $FreeBSD$
+.\"
+.Dd January 7, 2017
+.Dt CHMOD 1
+.Os
+.Sh NAME
+.Nm chmod
+.Nd change file modes or Access Control Lists
+.Sh SYNOPSIS
+.Nm chmod
+.Op Fl fv
+.Op Fl R Op Fl H | L | P
+.Ar mode
+.Ar
+.Nm chmod
+.Op Fl fv
+.Op Fl R Op Fl H | L | P
+.Op -a | +a | =a
+.Ar ACE
+.Ar
+.Nm chmod
+.Op Fl fhv
+.Op Fl R Op Fl H | L | P
+.Op Fl E
+.Ar
+.Nm chmod
+.Op Fl fhv
+.Op Fl R Op Fl H | L | P
+.Op Fl C
+.Ar
+.Nm chmod
+.Op Fl fhv
+.Op Fl R Op Fl H | L | P
+.Op Fl N
+.Ar
+.Sh DESCRIPTION
+The
+.Nm chmod
+utility modifies the file mode bits of the listed files
+as specified by the
+.Ar mode
+operand. It may also be used to modify the Access Control
+Lists (ACLs) associated with the listed files.
+.Pp
+The generic options are as follows:
+.Bl -tag -width indent
+.It Fl f
+Do not display a diagnostic message if
+.Nm chmod
+could not modify the mode for
+.Va file ,
+nor modify the exit status to reflect such failures.
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed
+and hence unaffected by the command.
+(Symbolic links encountered during tree traversal are not followed.)
+.It Fl h
+If the file is a symbolic link, change the mode of the link itself
+rather than the file that the link points to.
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+This is the default.
+.It Fl R
+Change the modes of the file hierarchies rooted in the files,
+instead of just the files themselves.
+Beware of unintentionally matching the
+.Dq Pa ".."
+hard link to the parent directory when using wildcards like
+.Dq Li ".*" .
+.It Fl v
+Cause
+.Nm chmod
+to be verbose, showing filenames as the mode is modified.
+If the
+.Fl v
+flag is specified more than once, the old and new modes of the file
+will also be printed, in both octal and symbolic notation.
+.El
+.Pp
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+If
+.Nm chmod
+receives a
+.Dv SIGINFO
+signal (see the
+.Cm status
+argument for
+.Xr stty 1 ) ,
+then the current filename as well as the old and new modes are displayed.
+.Pp
+Only the owner of a file or the super-user is permitted to change
+the mode of a file.
+.Sh EXIT STATUS
+.Ex -std
+.Sh MODES
+Modes may be absolute or symbolic.
+An absolute mode is an octal number constructed from the sum of
+one or more of the following values:
+.Pp
+.Bl -tag -width 6n -compact -offset indent
+.It Li 4000
+(the setuid bit).
+Executable files with this bit set
+will run with effective uid set to the uid of the file owner.
+Directories with this bit set will force all files and
+sub-directories created in them to be owned by the directory owner
+and not by the uid of the creating process, if the underlying file
+system supports this feature: see
+.Xr chmod 2
+and the
+.Cm suiddir
+option to
+.Xr mount 8 .
+.It Li 2000
+(the setgid bit).
+Executable files with this bit set
+will run with effective gid set to the gid of the file owner.
+.It Li 1000
+(the sticky bit).
+See
+.Xr chmod 2
+and
+.Xr sticky 7 .
+.It Li 0400
+Allow read by owner.
+.It Li 0200
+Allow write by owner.
+.It Li 0100
+For files, allow execution by owner.
+For directories, allow the owner to
+search in the directory.
+.It Li 0040
+Allow read by group members.
+.It Li 0020
+Allow write by group members.
+.It Li 0010
+For files, allow execution by group members.
+For directories, allow
+group members to search in the directory.
+.It Li 0004
+Allow read by others.
+.It Li 0002
+Allow write by others.
+.It Li 0001
+For files, allow execution by others.
+For directories allow others to
+search in the directory.
+.El
+.Pp
+For example, the absolute mode that permits read, write and execute by
+the owner, read and execute by group members, read and execute by
+others, and no set-uid or set-gid behaviour is 755
+(400+200+100+040+010+004+001).
+.Pp
+The symbolic mode is described by the following grammar:
+.Bd -literal -offset indent
+mode ::= clause [, clause ...]
+clause ::= [who ...] [action ...] action
+action ::= op [perm ...]
+who ::= a | u | g | o
+op ::= + | \- | =
+perm ::= r | s | t | w | x | X | u | g | o
+.Ed
+.Pp
+The
+.Ar who
+symbols ``u'', ``g'', and ``o'' specify the user, group, and other parts
+of the mode bits, respectively.
+The
+.Ar who
+symbol ``a'' is equivalent to ``ugo''.
+.Pp
+The
+.Ar perm
+symbols represent the portions of the mode bits as follows:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It r
+The read bits.
+.It s
+The set-user-ID-on-execution and set-group-ID-on-execution bits.
+.It t
+The sticky bit.
+.It w
+The write bits.
+.It x
+The execute/search bits.
+.It X
+The execute/search bits if the file is a directory or any of the
+execute/search bits are set in the original (unmodified) mode.
+Operations with the
+.Ar perm
+symbol ``X'' are only meaningful in conjunction with the
+.Ar op
+symbol ``+'', and are ignored in all other cases.
+.It u
+The user permission bits in the original mode of the file.
+.It g
+The group permission bits in the original mode of the file.
+.It o
+The other permission bits in the original mode of the file.
+.El
+.Pp
+The
+.Ar op
+symbols represent the operation performed, as follows:
+.Bl -tag -width 4n
+.It +
+If no value is supplied for
+.Ar perm ,
+the ``+'' operation has no effect.
+If no value is supplied for
+.Ar who ,
+each permission bit specified in
+.Ar perm ,
+for which the corresponding bit in the file mode creation mask
+(see
+.Xr umask 2 )
+is clear, is set.
+Otherwise, the mode bits represented by the specified
+.Ar who
+and
+.Ar perm
+values are set.
+.It \&\-
+If no value is supplied for
+.Ar perm ,
+the ``\-'' operation has no effect.
+If no value is supplied for
+.Ar who ,
+each permission bit specified in
+.Ar perm ,
+for which the corresponding bit in the file mode creation mask
+is set, is cleared.
+Otherwise, the mode bits represented by the specified
+.Ar who
+and
+.Ar perm
+values are cleared.
+.It =
+The mode bits specified by the
+.Ar who
+value are cleared, or, if no
+.Ar who
+value is specified, the owner, group
+and other mode bits are cleared.
+Then, if no value is supplied for
+.Ar who ,
+each permission bit specified in
+.Ar perm ,
+for which the corresponding bit in the file mode creation mask
+is clear, is set.
+Otherwise, the mode bits represented by the specified
+.Ar who
+and
+.Ar perm
+values are set.
+.El
+.Pp
+Each
+.Ar clause
+specifies one or more operations to be performed on the mode
+bits, and each operation is applied to the mode bits in the
+order specified.
+.Pp
+Operations upon the other permissions only (specified by the symbol
+``o'' by itself), in combination with the
+.Ar perm
+symbols ``s'' or ``t'', are ignored.
+.Pp
+The ``w'' permission on directories will permit file creation, relocation,
+and copy into that directory.
+Files created within the directory itself will inherit its group ID.
+.Sh EXAMPLES OF VALID MODES
+.Bl -tag -width "u=rwx,go=u-w" -compact
+.It Li 644
+make a file readable by anyone and writable by the owner only.
+.Pp
+.It Li go-w
+deny write permission to group and others.
+.Pp
+.It Li =rw,+X
+set the read and write permissions to the usual defaults, but
+retain any execute permissions that are currently set.
+.Pp
+.It Li +X
+make a directory or file searchable/executable by everyone if it is
+already searchable/executable by anyone.
+.Pp
+.It Li 755
+.It Li u=rwx,go=rx
+.It Li u=rwx,go=u-w
+make a file readable/executable by everyone and writable by the owner only.
+.Pp
+.It Li go=
+clear all mode bits for group and others.
+.Pp
+.It Li g=u-w
+set the group bits equal to the user bits, but clear the group write bit.
+.El
+.Sh ACL MANIPULATION OPTIONS
+ACLs are manipulated using extensions to the symbolic mode
+grammar. Each file has one ACL, containing an ordered list of entries.
+Each entry refers to a user or group, and grants or denies a set of
+permissions.
+In cases where a user and a group exist with the same name, the
+user/group name can be prefixed with "user:" or "group:" in order to
+specify the type of name.
+.Pp
+If the user or group name contains spaces you can use ':' as the delimiter
+between name and permission.
+.Pp
+The following permissions are applicable to all filesystem objects:
+.Bl -tag -width 6n -compact -offset indent
+.It delete
+Delete the item. Deletion may be granted by either this permission
+on an object or the delete_child right on the containing directory.
+.It readattr
+Read an object's basic attributes. This is implicitly granted if
+the object can be looked up and not explicitly denied.
+.It writeattr
+Write an object's basic attributes.
+.It readextattr
+Read extended attributes.
+.It writeextattr
+Write extended attributes.
+.It readsecurity
+Read an object's extended security information (ACL).
+.It writesecurity
+Write an object's security information (ownership, mode, ACL).
+.It chown
+Change an object's ownership.
+.El
+.Pp
+The following permissions are applicable to directories:
+.Bl -tag -width 6n -compact -offset indent
+.It list
+List entries.
+.It search
+Look up files by name.
+.It add_file
+Add a file.
+.It add_subdirectory
+Add a subdirectory.
+.It delete_child
+Delete a contained object. See the file delete permission above.
+.El
+.Pp
+The following permissions are applicable to non-directory filesystem objects:
+.Bl -tag -width 6n -compact -offset indent
+.It read
+Open for reading.
+.It write
+Open for writing.
+.It append
+Open for writing, but in a fashion that only allows writes into areas of
+the file not previously written.
+.It execute
+Execute the file as a script or program.
+.El
+.Pp
+ACL inheritance is controlled with the following permissions words, which
+may only be applied to directories:
+.Bl -tag -width 6n -compact -offset indent
+.It file_inherit
+Inherit to files.
+.It directory_inherit
+Inherit to directories.
+.It limit_inherit
+This flag is only relevant to entries inherited by subdirectories; it
+causes the directory_inherit flag to be cleared in the entry that is
+inherited, preventing further nested subdirectories from also
+inheriting the entry.
+.It only_inherit
+The entry is inherited by created items but not considered when processing
+the ACL.
+.El
+.Pp
+The ACL manipulation options are as follows:
+.Bl -tag -width Ds
+.It \fB+a\fR
+The +a mode parses a new ACL entry from the next argument on
+the commandline and inserts it into the canonical location in the
+ACL. If the supplied entry refers to an identity already listed, the
+two entries are combined.
+.Pp
+\fBExamples\fR
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ # chmod +a "admin allow write" file1
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: admin allow write
+ # chmod +a "guest deny read" file1
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: guest deny read
+ 2: admin allow write
+ # chmod +a "admin allow delete" file1
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: guest deny read
+ 2: admin allow write,delete
+ # chmod +a "User 1:allow:read" file
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: guest deny read
+ 2: User 1 allow read
+ 3: admin allow write,delete
+.Pp
+The +a mode strives to maintain correct canonical form for the ACL.
+ local deny
+ local allow
+ inherited deny
+ inherited allow
+.Pp
+By default, chmod adds entries to the top of the local deny and local
+allow lists. Inherited entries are added by using the +ai mode.
+.Pp
+\fBExamples\fR
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: guest deny read
+ 2: admin allow write,delete
+ 3: juser inherited deny delete
+ 4: admin inherited allow delete
+ 5: backup inherited deny read
+ 6: admin inherited allow write-security
+ # chmod +ai "others allow read" file1
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: guest deny read
+ 2: admin allow write,delete
+ 3: juser inherited deny delete
+ 4: others inherited allow read
+ 5: admin inherited allow delete
+ 6: backup inherited deny read
+ 7: admin inherited allow write-security
+.It \fB+a#\fR
+When a specific ordering is required, the exact location at which an
+entry will be inserted is specified with the +a# mode.
+.Pp
+\fBExamples\fR
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: guest deny read
+ 2: admin allow write
+ # chmod +a# 2 "others deny read" file1
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: guest deny read
+ 2: others deny read
+ 3: admin allow write
+.Pp
+The +ai# mode may be used to insert inherited entries at a specific
+location. Note that these modes allow non-canonical ACL ordering to
+be constructed.
+.It Fl a
+The -a mode is used to delete ACL entries. All entries exactly
+matching the supplied entry will be deleted. If the entry lists a
+subset of rights granted by an entry, only the rights listed are
+removed. Entries may also be deleted by index using the -a# mode.
+.Pp
+\fBExamples\fR
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: guest deny read
+ 2: admin allow write,delete
+ # chmod -a# 1 file1
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: admin allow write,delete
+ # chmod -a "admin allow write" file1
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: admin allow delete
+.Pp
+Inheritance is not considered when processing the -a mode; rights and
+entries will be removed regardless of their inherited state.
+.Pp
+If the user or group name contains spaces you can use ':' as the delimiter
+.Pp
+\fBExample\fR
+ # chmod +a "User 1:allow:read" file
+.It \fB=a#\fR
+Individual entries are rewritten using the =a# mode.
+.Pp
+\fBExamples\fR
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: admin allow delete
+ # chmod =a# 1 "admin allow write,chown"
+ # ls -le
+ -rw-r--r--+ 1 juser wheel 0 Apr 28 14:06 file1
+ owner: juser
+ 1: admin allow write,chown
+.Pp
+This mode may not be used to add new entries.
+.It Fl E
+Reads the ACL information from stdin, as a sequential list
+of ACEs, separated by newlines. If the information parses correctly,
+the existing information is replaced.
+.It Fl C
+Returns false if any of the named files have ACLs in non-canonical order.
+.It Fl i
+Removes the 'inherited' bit from all entries in the named file(s) ACLs.
+.It Fl I
+Removes all inherited entries from the named file(s) ACL(s).
+.It Fl N
+Removes the ACL from the named file(s).
+.El
+.Sh COMPATIBILITY
+The
+.Fl v
+option is non-standard and its use in scripts is not recommended.
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr install 1 ,
+.Xr chmod 2 ,
+.Xr stat 2 ,
+.Xr umask 2 ,
+.Xr fts 3 ,
+.Xr setmode 3 ,
+.Xr sticky 7 ,
+.Xr symlink 7 ,
+.Xr chown 8 ,
+.Xr mount 8
+.Sh STANDARDS
+The
+.Nm chmod
+utility is expected to be
+.St -p1003.2
+compatible with the exception of the
+.Ar perm
+symbol
+.Dq t
+which is not included in that standard.
+.Sh HISTORY
+A
+.Nm chmod
+command appeared in
+.At v1 .
diff --git a/file_cmds/chmod/chmod.c b/file_cmds/chmod/chmod.c
new file mode 100644
index 0000000..442815d
--- /dev/null
+++ b/file_cmds/chmod/chmod.c
@@ -0,0 +1,458 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static char const copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)chmod.c 8.8 (Berkeley) 4/1/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/chmod/chmod.c,v 1.27 2002/08/04 05:29:13 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include "chmod_acl.h"
+
+#endif /*__APPLE__*/
+
+int fflag = 0;
+
+int main(int, char *[]);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ FTS *ftsp = NULL;
+ FTSENT *p = NULL;
+ mode_t *set = NULL;
+ long val = 0;
+ int oct = 0;
+ int Hflag, Lflag, Pflag, Rflag, ch, fts_options, hflag, rval;
+ int vflag;
+ char *ep, *mode;
+ mode_t newmode, omode;
+#ifdef __APPLE__
+ unsigned int acloptflags = 0;
+ long aclpos = -1;
+ int inheritance_level = 0;
+ int index = 0;
+ size_t acloptlen = 0;
+ int ace_arg_not_required = 0;
+ acl_t acl_input = NULL;
+#endif /* __APPLE__*/
+ int (*change_mode)(const char *, mode_t);
+
+ set = NULL;
+ omode = 0;
+ Hflag = Lflag = Pflag = Rflag = fflag = hflag = vflag = 0;
+#ifndef __APPLE__
+ while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "ACEHILNPRVXafghinorstuvwx")) != -1)
+#endif
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = 0;
+ Pflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = 0;
+ Pflag = 0;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ Pflag = 1;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ /*
+ * In System V (and probably POSIX.2) the -h option
+ * causes chmod to change the mode of the symbolic
+ * link. 4.4BSD's symbolic links didn't have modes,
+ * so it was an undocumented noop. In FreeBSD 3.0,
+ * lchmod(2) is introduced and this option does real
+ * work.
+ */
+ hflag = 1;
+ break;
+#ifdef __APPLE__
+ case 'a':
+ if (argv[optind - 1][0] == '-' &&
+ argv[optind - 1][1] == ch)
+ --optind;
+ goto done;
+ case 'A':
+// acloptflags |= ACL_FLAG | ACL_TO_STDOUT;
+// ace_arg_not_required = 1;
+ errx(1, "-A not implemented");
+ goto done;
+ case 'E':
+ acloptflags |= ACL_FLAG | ACL_FROM_STDIN;
+ goto done;
+ case 'C':
+ acloptflags |= ACL_FLAG | ACL_CHECK_CANONICITY;
+ ace_arg_not_required = 1;
+ goto done;
+ case 'i':
+ acloptflags |= ACL_FLAG | ACL_REMOVE_INHERIT_FLAG;
+ ace_arg_not_required = 1;
+ goto done;
+ case 'I':
+ acloptflags |= ACL_FLAG | ACL_REMOVE_INHERITED_ENTRIES;
+ ace_arg_not_required = 1;
+ goto done;
+ case 'n':
+ acloptflags |= ACL_FLAG | ACL_NO_TRANSLATE;
+ break;
+ case 'N':
+ acloptflags |= ACL_FLAG | ACL_CLEAR_FLAG;
+ ace_arg_not_required = 1;
+ goto done;
+ case 'V':
+// acloptflags |= ACL_FLAG | ACL_INVOKE_EDITOR;
+// ace_arg_not_required = 1;
+ errx(1, "-V not implemented");
+ goto done;
+#endif /* __APPLE__ */
+ /*
+ * XXX
+ * "-[rwx]" are valid mode commands. If they are the entire
+ * argument, getopt has moved past them, so decrement optind.
+ * Regardless, we're done argument processing.
+ */
+ case 'g': case 'o': case 'r': case 's':
+ case 't': case 'u': case 'w': case 'X': case 'x':
+ if (argv[optind - 1][0] == '-' &&
+ argv[optind - 1][1] == ch &&
+ argv[optind - 1][2] == '\0')
+ --optind;
+ goto done;
+ case 'v':
+ vflag++;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+done: argv += optind;
+ argc -= optind;
+
+#ifdef __APPLE__
+ if (argc < ((acloptflags & ACL_FLAG) ? 1 : 2))
+ usage();
+ if (!Rflag && (Hflag || Lflag || Pflag))
+ warnx("options -H, -L, -P only useful with -R");
+#else /* !__APPLE__ */
+ if (argc < 2)
+ usage();
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+ if (!(acloptflags & ACL_FLAG) && ((acloptlen = strlen(argv[0])) > 1) && (argv[0][1] == 'a')) {
+ acloptflags |= ACL_FLAG;
+ switch (argv[0][0]) {
+ case '+':
+ acloptflags |= ACL_SET_FLAG;
+ break;
+ case '-':
+ acloptflags |= ACL_DELETE_FLAG;
+ break;
+ case '=':
+ acloptflags |= ACL_REWRITE_FLAG;
+ break;
+ default:
+ acloptflags &= ~ACL_FLAG;
+ goto apnoacl;
+ }
+
+ if (argc < 3)
+ usage();
+
+ if (acloptlen > 2) {
+ for (index = 2; index < acloptlen; index++) {
+ switch (argv[0][index]) {
+ case '#':
+ acloptflags |= ACL_ORDER_FLAG;
+
+ if (argc < ((acloptflags & ACL_DELETE_FLAG)
+ ? 3 : 4))
+ usage();
+ argv++;
+ argc--;
+ errno = 0;
+ aclpos = strtol(argv[0], &ep, 0);
+
+ if (aclpos > ACL_MAX_ENTRIES
+ || aclpos < 0)
+ errno = ERANGE;
+ if (errno || *ep)
+ errx(1, "Invalid ACL entry number: %ld", aclpos);
+ if (acloptflags & ACL_DELETE_FLAG)
+ ace_arg_not_required = 1;
+
+ goto apdone;
+ case 'i':
+ acloptflags |= ACL_INHERIT_FLAG;
+ /* The +aii.. syntax to specify
+ * inheritance level is rather unwieldy,
+ * find an alternative.
+ */
+ inheritance_level++;
+ if (inheritance_level > 1)
+ warnx("Inheritance across more than one generation is not currently supported");
+ if (inheritance_level >= MAX_INHERITANCE_LEVEL)
+ goto apdone;
+ break;
+ default:
+ errno = EINVAL;
+ usage();
+ }
+ }
+ }
+apdone:
+ argv++;
+ argc--;
+ }
+apnoacl:
+#endif /*__APPLE__*/
+
+ if (Rflag) {
+ fts_options = FTS_PHYSICAL;
+ if (hflag)
+ errx(1,
+ "the -R and -h options may not be specified together.");
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ if (Lflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ } else
+ fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+
+ if (hflag)
+ change_mode = lchmod;
+ else
+ change_mode = chmod;
+#ifdef __APPLE__
+ if (acloptflags & ACL_FROM_STDIN) {
+ ssize_t readval = 0;
+ size_t readtotal = 0;
+
+ mode = (char *) malloc(MAX_ACL_TEXT_SIZE);
+
+ if (mode == NULL)
+ err(1, "Unable to allocate mode string");
+ /* Read the ACEs from STDIN */
+ do {
+ readtotal += readval;
+ readval = read(STDIN_FILENO, mode + readtotal,
+ MAX_ACL_TEXT_SIZE);
+ } while ((readval > 0) && (readtotal <= MAX_ACL_TEXT_SIZE));
+
+ if (0 == readtotal)
+ errx(1, "-E specified, but read from STDIN failed");
+ else
+ mode[readtotal - 1] = '\0';
+ --argv;
+ }
+ else
+#endif /* __APPLE */
+ mode = *argv;
+
+#ifdef __APPLE__
+ if ((acloptflags & ACL_FLAG)) {
+
+ /* Are we deleting by entry number, verifying
+ * canonicity or performing some other operation that
+ * does not require an input entry? If so, there's no
+ * entry to convert.
+ */
+ if (ace_arg_not_required) {
+ --argv;
+ }
+ else {
+ /* Parse the text into an ACL*/
+ acl_input = parse_acl_entries(mode);
+ if (acl_input == NULL) {
+ errx(1, "Invalid ACL specification: %s", mode);
+ }
+ }
+ }
+ else {
+#endif /* __APPLE__*/
+ if (*mode >= '0' && *mode <= '7') {
+ errno = 0;
+ val = strtol(mode, &ep, 8);
+ if (val > USHRT_MAX || val < 0)
+ errno = ERANGE;
+ if (errno)
+ err(1, "Invalid file mode: %s", mode);
+ if (*ep)
+ errx(1, "Invalid file mode: %s", mode);
+ omode = (mode_t)val;
+ oct = 1;
+ } else {
+ if ((set = setmode(mode)) == NULL)
+ errx(1, "Invalid file mode: %s", mode);
+ oct = 0;
+ }
+#ifdef __APPLE__
+ }
+#endif /* __APPLE__*/
+ if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
+ err(1, "fts_open");
+ for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ switch (p->fts_info) {
+ case FTS_D:
+ if (!Rflag)
+ (void)fts_set(ftsp, p, FTS_SKIP);
+ break;
+ case FTS_DNR: /* Warn, chmod, continue. */
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ case FTS_DP: /* Already changed at FTS_D. */
+ continue;
+ case FTS_NS:
+ if (acloptflags & ACL_FLAG) /* don't need stat for -N */
+ break;
+ case FTS_ERR: /* Warn, continue. */
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ continue;
+ case FTS_SL: /* Ignore. */
+ case FTS_SLNONE:
+ /*
+ * The only symlinks that end up here are ones that
+ * don't point to anything and ones that we found
+ * doing a physical walk.
+ */
+ if (!hflag)
+ continue;
+ /* else */
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+#ifdef __APPLE__
+/* If an ACL manipulation option was specified, manipulate */
+ if (acloptflags & ACL_FLAG) {
+ if (0 != modify_file_acl(acloptflags, p->fts_accpath, acl_input, (int)aclpos, inheritance_level, !hflag))
+ rval = 1;
+ }
+ else {
+#endif /* __APPLE__ */
+ newmode = oct ? omode : getmode(set, p->fts_statp->st_mode);
+ if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS))
+ continue;
+ if ((*change_mode)(p->fts_accpath, newmode) && !fflag) {
+ warn("Unable to change file mode on %s", p->fts_path);
+ rval = 1;
+ } else {
+ if (vflag) {
+ (void)printf("%s", p->fts_accpath);
+
+ if (vflag > 1) {
+ char m1[12], m2[12];
+
+ strmode(p->fts_statp->st_mode, m1);
+ strmode((p->fts_statp->st_mode &
+ S_IFMT) | newmode, m2);
+
+ (void)printf(": 0%o [%s] -> 0%o [%s]",
+ p->fts_statp->st_mode, m1,
+ (p->fts_statp->st_mode & S_IFMT) |
+ newmode, m2);
+ }
+ (void)printf("\n");
+ }
+
+ }
+#ifdef __APPLE__
+ }
+#endif /* __APPLE__*/
+ }
+ if (errno)
+ err(1, "fts_read");
+#ifdef __APPLE__
+ if (acl_input)
+ acl_free(acl_input);
+ if (mode && (acloptflags & ACL_FROM_STDIN))
+ free(mode);
+
+#endif /* __APPLE__ */
+ if (set)
+ free(set);
+ exit(rval);
+}
+
+void
+usage(void)
+{
+#ifdef __APPLE__
+ (void)fprintf(stderr,
+ "usage:\tchmod [-fhv] [-R [-H | -L | -P]] [-a | +a | =a [i][# [ n]]] mode|entry file ...\n"
+ "\tchmod [-fhv] [-R [-H | -L | -P]] [-E | -C | -N | -i | -I] file ...\n"); /* add -A and -V when implemented */
+#else
+ (void)fprintf(stderr,
+ "usage: chmod [-fhv] [-R [-H | -L | -P]] mode file ...\n");
+#endif /* __APPLE__ */
+ exit(1);
+}
diff --git a/file_cmds/chmod/chmod_acl.c b/file_cmds/chmod/chmod_acl.c
new file mode 100644
index 0000000..5ac4c17
--- /dev/null
+++ b/file_cmds/chmod/chmod_acl.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <membership.h>
+#include "chmod_acl.h"
+
+extern void usage(void);
+
+#ifdef __APPLE__
+static struct {
+ acl_perm_t perm;
+ char *name;
+ int flags;
+#define ACL_PERM_DIR (1<<0)
+#define ACL_PERM_FILE (1<<1)
+} acl_perms[] = {
+ {ACL_READ_DATA, "read", ACL_PERM_FILE},
+ {ACL_LIST_DIRECTORY, "list", ACL_PERM_DIR},
+ {ACL_WRITE_DATA, "write", ACL_PERM_FILE},
+ {ACL_ADD_FILE, "add_file", ACL_PERM_DIR},
+ {ACL_EXECUTE, "execute", ACL_PERM_FILE},
+ {ACL_SEARCH, "search", ACL_PERM_DIR},
+ {ACL_DELETE, "delete", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_APPEND_DATA, "append", ACL_PERM_FILE},
+ {ACL_ADD_SUBDIRECTORY, "add_subdirectory", ACL_PERM_DIR},
+ {ACL_DELETE_CHILD, "delete_child", ACL_PERM_DIR},
+ {ACL_READ_ATTRIBUTES, "readattr", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_WRITE_ATTRIBUTES, "writeattr", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_READ_EXTATTRIBUTES, "readextattr", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_WRITE_EXTATTRIBUTES, "writeextattr", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_READ_SECURITY, "readsecurity", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_WRITE_SECURITY, "writesecurity", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_CHANGE_OWNER, "chown", ACL_PERM_FILE | ACL_PERM_DIR},
+ {0, NULL, 0}
+};
+
+static struct {
+ acl_flag_t flag;
+ char *name;
+ int flags;
+} acl_flags[] = {
+ {ACL_ENTRY_INHERITED, "inherited", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_ENTRY_FILE_INHERIT, "file_inherit", ACL_PERM_DIR},
+ {ACL_ENTRY_DIRECTORY_INHERIT, "directory_inherit", ACL_PERM_DIR},
+ {ACL_ENTRY_LIMIT_INHERIT, "limit_inherit", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_ENTRY_ONLY_INHERIT, "only_inherit", ACL_PERM_DIR},
+ {0, NULL, 0}
+};
+
+/* TBD - Many of these routines could potentially be considered for
+ * inclusion in a library. If that is done, either avoid use of "err"
+ * and implement a better fall-through strategy in case of errors,
+ * or use err_set_exit() and make various structures globals.
+ */
+
+#define NAME_USER (1)
+#define NAME_GROUP (2)
+#define NAME_EITHER (NAME_USER | NAME_GROUP)
+
+/* Perform a name to uuid mapping - calls through to memberd */
+
+uuid_t *
+name_to_uuid(char *tok, int nametype) {
+ uuid_t *entryg = NULL;
+ size_t len = strlen(tok);
+
+ if ((entryg = (uuid_t *) calloc(1, sizeof(uuid_t))) == NULL) {
+ errx(1, "Unable to allocate a uuid");
+ }
+
+ if ((nametype & NAME_USER) && mbr_identifier_to_uuid(ID_TYPE_USERNAME, tok, len, *entryg) == 0) {
+ return entryg;
+ }
+
+ if ((nametype & NAME_GROUP) && mbr_identifier_to_uuid(ID_TYPE_GROUPNAME, tok, len, *entryg) == 0) {
+ return entryg;
+ }
+
+ errx(1, "Unable to translate '%s' to a UUID", tok);
+}
+
+/* Convert an acl entry in string form to an acl_entry_t */
+int
+parse_entry(char *entrybuf, acl_entry_t newent) {
+ char *tok;
+ char *pebuf;
+ uuid_t *entryg;
+
+ acl_tag_t tag;
+ acl_permset_t perms;
+ acl_flagset_t flags;
+ unsigned permcount = 0;
+ unsigned pindex = 0;
+ char *delimiter = " ";
+ int nametype = NAME_EITHER;
+
+ acl_get_permset(newent, &perms);
+ acl_get_flagset_np(newent, &flags);
+
+ pebuf = entrybuf;
+
+ if (0 == strncmp(entrybuf, "user:", 5)) {
+ nametype = NAME_USER;
+ pebuf += 5;
+ } else if (0 == strncmp(entrybuf, "group:", 6)) {
+ nametype = NAME_GROUP;
+ pebuf += 6;
+ }
+
+ if (strchr(pebuf, ':')) /* User/Group names can have spaces */
+ delimiter = ":";
+ tok = strsep(&pebuf, delimiter);
+
+ if ((tok == NULL) || *tok == '\0') {
+ errx(1, "Invalid entry format -- expected user or group name");
+ }
+
+ /* parse the name into a qualifier */
+ entryg = name_to_uuid(tok, nametype);
+
+ tok = strsep(&pebuf, ": "); /* Stick with delimiter? */
+ if ((tok == NULL) || *tok == '\0') {
+ errx(1, "Invalid entry format -- expected allow or deny");
+ }
+
+ /* is the verb 'allow' or 'deny'? */
+ if (!strcmp(tok, "allow")) {
+ tag = ACL_EXTENDED_ALLOW;
+ } else if (!strcmp(tok, "deny")) {
+ tag = ACL_EXTENDED_DENY;
+ } else {
+ errx(1, "Unknown tag type '%s'", tok);
+ }
+
+ /* parse permissions */
+ for (; (tok = strsep(&pebuf, ",")) != NULL;) {
+ if (*tok != '\0') {
+ /* is it a permission? */
+ for (pindex = 0; acl_perms[pindex].name != NULL; pindex++) {
+ if (!strcmp(acl_perms[pindex].name, tok)) {
+ /* got one */
+ acl_add_perm(perms, acl_perms[pindex].perm);
+ permcount++;
+ goto found;
+ }
+ }
+ /* is it a flag? */
+ for (pindex = 0; acl_flags[pindex].name != NULL; pindex++) {
+ if (!strcmp(acl_flags[pindex].name, tok)) {
+ /* got one */
+ acl_add_flag_np(flags, acl_flags[pindex].flag);
+ permcount++;
+ goto found;
+ }
+ }
+ errx(1,"Invalid permission type '%s'", tok);
+ found:
+ continue;
+ }
+ }
+ if (0 == permcount) {
+ errx(1, "No permissions specified");
+ }
+ acl_set_tag_type(newent, tag);
+ acl_set_qualifier(newent, entryg);
+ acl_set_permset(newent, perms);
+ acl_set_flagset_np(newent, flags);
+ free(entryg);
+
+ return(0);
+}
+
+/* Convert one or more acl entries in string form to an acl_t */
+acl_t
+parse_acl_entries(const char *input) {
+ acl_t acl_input;
+ acl_entry_t newent;
+ char *inbuf;
+ char *oinbuf;
+
+ char **bufp, *entryv[ACL_MAX_ENTRIES];
+#if 0
+/* XXX acl_from_text(), when implemented, will presumably use the canonical
+ * text representation format, which is what chmod should be using
+ * We may need to add an entry number to the input
+ */
+ /* Translate the user supplied ACL entry */
+ /* acl_input = acl_from_text(input); */
+#else
+ inbuf = malloc(MAX_ACL_TEXT_SIZE);
+
+ if (inbuf == NULL)
+ err(1, "malloc() failed");
+ strncpy(inbuf, input, MAX_ACL_TEXT_SIZE);
+ inbuf[MAX_ACL_TEXT_SIZE - 1] = '\0';
+
+ if ((acl_input = acl_init(1)) == NULL)
+ err(1, "acl_init() failed");
+
+ oinbuf = inbuf;
+
+ for (bufp = entryv; (*bufp = strsep(&oinbuf, "\n")) != NULL;)
+ if (**bufp != '\0') {
+ if (0 != acl_create_entry(&acl_input, &newent))
+ err(1, "acl_create_entry() failed");
+ if (0 != parse_entry(*bufp, newent)) {
+ errx(1, "Failed parsing entry '%s'", *bufp);
+ }
+ if (++bufp >= &entryv[ACL_MAX_ENTRIES - 1]) {
+ errx(1, "Too many entries");
+ }
+ }
+
+ free(inbuf);
+ return acl_input;
+#endif /* #if 0 */
+}
+
+/* XXX No Libc support for inherited entries and generation determination yet */
+unsigned
+get_inheritance_level(acl_entry_t entry) {
+/* XXX to be implemented */
+ return 1;
+}
+
+/* Determine a "score" for an acl entry. The entry scores higher if it's
+ * tagged ACL_EXTENDED_DENY, and non-inherited entries are ranked higher
+ * than inherited entries.
+ */
+
+int
+score_acl_entry(acl_entry_t entry) {
+
+ acl_tag_t tag;
+ acl_flagset_t flags;
+ acl_permset_t perms;
+
+ int score = 0;
+
+ if (entry == NULL)
+ return (MINIMUM_TIER);
+
+ if (acl_get_tag_type(entry, &tag) != 0) {
+ err(1, "Malformed ACL entry, no tag present");
+ }
+ if (acl_get_flagset_np(entry, &flags) != 0){
+ err(1, "Unable to obtain flagset");
+ }
+ if (acl_get_permset(entry, &perms) != 0)
+ err(1, "Malformed ACL entry, no permset present");
+
+ switch(tag) {
+ case ACL_EXTENDED_ALLOW:
+ break;
+ case ACL_EXTENDED_DENY:
+ score++;
+ break;
+ default:
+ errx(1, "Unknown tag type %d present in ACL entry", tag);
+ /* NOTREACHED */
+ }
+
+ if (acl_get_flag_np(flags, ACL_ENTRY_INHERITED))
+ score += get_inheritance_level(entry) * INHERITANCE_TIER;
+
+ return score;
+}
+
+int
+compare_acl_qualifiers(uuid_t *qa, uuid_t *qb) {
+ return bcmp(qa, qb, sizeof(uuid_t));
+}
+
+/* Compare two ACL permsets.
+ * Returns :
+ * MATCH_SUBSET if bperms is a subset of aperms
+ * MATCH_SUPERSET if bperms is a superset of aperms
+ * MATCH_PARTIAL if the two permsets have a common subset
+ * MATCH_EXACT if the two permsets are identical
+ * MATCH_NONE if they are disjoint
+ */
+
+int
+compare_acl_permsets(acl_permset_t aperms, acl_permset_t bperms)
+{
+ int i;
+/* TBD Implement other match levels as needed */
+ for (i = 0; acl_perms[i].name != NULL; i++) {
+ if (acl_get_perm_np(aperms, acl_perms[i].perm) !=
+ acl_get_perm_np(bperms, acl_perms[i].perm))
+ return MATCH_NONE;
+ }
+ return MATCH_EXACT;
+}
+
+static int
+compare_acl_flagsets(acl_flagset_t aflags, acl_flagset_t bflags)
+{
+ int i;
+/* TBD Implement other match levels as needed */
+ for (i = 0; acl_flags[i].name != NULL; i++) {
+ if (acl_get_flag_np(aflags, acl_flags[i].flag) !=
+ acl_get_flag_np(bflags, acl_flags[i].flag))
+ return MATCH_NONE;
+ }
+ return MATCH_EXACT;
+}
+
+/* Compares two ACL entries for equality */
+int
+compare_acl_entries(acl_entry_t a, acl_entry_t b)
+{
+ acl_tag_t atag, btag;
+ acl_permset_t aperms, bperms;
+ acl_flagset_t aflags, bflags;
+ int pcmp = 0, fcmp = 0;
+ void *aqual, *bqual;
+
+ aqual = acl_get_qualifier(a);
+ bqual = acl_get_qualifier(b);
+
+ int compare = compare_acl_qualifiers(aqual, bqual);
+ acl_free(aqual);
+ acl_free(bqual);
+
+ if (compare != 0)
+ return MATCH_NONE;
+
+ if (0 != acl_get_tag_type(a, &atag))
+ err(1, "No tag type present in entry");
+ if (0!= acl_get_tag_type(b, &btag))
+ err(1, "No tag type present in entry");
+
+ if (atag != btag)
+ return MATCH_NONE;
+
+ if ((acl_get_permset(a, &aperms) != 0) ||
+ (acl_get_flagset_np(a, &aflags) != 0) ||
+ (acl_get_permset(b, &bperms) != 0) ||
+ (acl_get_flagset_np(b, &bflags) != 0))
+ err(1, "error fetching permissions");
+
+ pcmp = compare_acl_permsets(aperms, bperms);
+ fcmp = compare_acl_flagsets(aflags, bflags);
+
+ if ((pcmp == MATCH_NONE) || (fcmp == MATCH_NONE))
+ return(MATCH_PARTIAL);
+ else
+ return(MATCH_EXACT);
+}
+
+/* Verify that an ACL is in canonical order. Currently, the canonical
+ * form is:
+ * local deny
+ * local allow
+ * inherited deny (parent)
+ * inherited allow (parent)
+ * inherited deny (grandparent)
+ * inherited allow (grandparent)
+ * ...
+ */
+unsigned int
+is_canonical(acl_t acl) {
+
+ unsigned aindex;
+ acl_entry_t entry;
+ int score = 0, next_score = 0;
+
+/* XXX - is a zero entry ACL in canonical form? */
+ if (0 != acl_get_entry(acl, ACL_FIRST_ENTRY, &entry))
+ return 1;
+
+ score = score_acl_entry(entry);
+
+ for (aindex = 0; acl_get_entry(acl, ACL_NEXT_ENTRY, &entry) == 0;
+ aindex++) {
+ if (score < (next_score = score_acl_entry(entry)))
+ return 0;
+ score = next_score;
+ }
+ return 1;
+}
+
+
+/* Iterate through an ACL, and find the canonical position for the
+ * specified entry
+ */
+unsigned int
+find_canonical_position(acl_t acl, acl_entry_t modifier) {
+
+ acl_entry_t entry;
+ int mscore = 0;
+ unsigned mpos = 0;
+
+ /* Check if there's an entry with the same qualifier
+ * and tag type; if not, find the appropriate slot
+ * for the score.
+ */
+
+ if (0 != acl_get_entry(acl, ACL_FIRST_ENTRY, &entry))
+ return 0;
+
+ mscore = score_acl_entry(modifier);
+
+ while (mscore < score_acl_entry(entry)) {
+
+ mpos++;
+
+ if (0 != acl_get_entry(acl, ACL_NEXT_ENTRY, &entry))
+ break;
+
+ }
+ return mpos;
+}
+
+int canonicalize_acl_entries(acl_t acl);
+
+/* For a given acl_entry_t "modifier", find the first exact or
+ * partially matching entry from the specified acl_t acl
+ */
+
+int
+find_matching_entry (acl_t acl, acl_entry_t modifier, acl_entry_t *rentryp,
+ unsigned match_inherited) {
+
+ acl_entry_t entry = NULL;
+
+ unsigned aindex;
+ int cmp, fcmp = MATCH_NONE;
+
+ for (aindex = 0;
+ acl_get_entry(acl, entry == NULL ? ACL_FIRST_ENTRY :
+ ACL_NEXT_ENTRY, &entry) == 0;
+ aindex++) {
+ cmp = compare_acl_entries(entry, modifier);
+ if ((cmp == MATCH_EXACT) || (cmp == MATCH_PARTIAL)) {
+ if (match_inherited) {
+ acl_flagset_t eflags, mflags;
+
+ if (0 != acl_get_flagset_np(modifier, &mflags))
+ err(1, "Unable to get flagset");
+
+ if (0 != acl_get_flagset_np(entry, &eflags))
+ err(1, "Unable to get flagset");
+
+ if (compare_acl_flagsets(mflags, eflags) == MATCH_EXACT) {
+ *rentryp = entry;
+ fcmp = cmp;
+ }
+ }
+ else {
+ *rentryp = entry;
+ fcmp = cmp;
+ }
+ }
+ if (fcmp == MATCH_EXACT)
+ break;
+ }
+ return fcmp;
+}
+
+/* Remove all perms specified in modifier from rentry*/
+int
+subtract_from_entry(acl_entry_t rentry, acl_entry_t modifier, int* valid_perms)
+{
+ acl_permset_t rperms, mperms;
+ acl_flagset_t rflags, mflags;
+ if (valid_perms)
+ *valid_perms = 0;
+ int i;
+
+ if ((acl_get_permset(rentry, &rperms) != 0) ||
+ (acl_get_flagset_np(rentry, &rflags) != 0) ||
+ (acl_get_permset(modifier, &mperms) != 0) ||
+ (acl_get_flagset_np(modifier, &mflags) != 0))
+ err(1, "error computing ACL modification");
+
+ for (i = 0; acl_perms[i].name != NULL; i++) {
+ if (acl_get_perm_np(mperms, acl_perms[i].perm))
+ acl_delete_perm(rperms, acl_perms[i].perm);
+ else if (valid_perms && acl_get_perm_np(rperms, acl_perms[i].perm))
+ (*valid_perms)++;
+ }
+ for (i = 0; acl_flags[i].name != NULL; i++) {
+ if (acl_get_flag_np(mflags, acl_flags[i].flag))
+ acl_delete_flag_np(rflags, acl_flags[i].flag);
+ }
+ acl_set_permset(rentry, rperms);
+ acl_set_flagset_np(rentry, rflags);
+ return 0;
+}
+/* Add the perms specified in modifier to rentry */
+static int
+merge_entry_perms(acl_entry_t rentry, acl_entry_t modifier)
+{
+ acl_permset_t rperms, mperms;
+ acl_flagset_t rflags, mflags;
+ int i;
+
+ if ((acl_get_permset(rentry, &rperms) != 0) ||
+ (acl_get_flagset_np(rentry, &rflags) != 0) ||
+ (acl_get_permset(modifier, &mperms) != 0) ||
+ (acl_get_flagset_np(modifier, &mflags) != 0))
+ err(1, "error computing ACL modification");
+
+ for (i = 0; acl_perms[i].name != NULL; i++) {
+ if (acl_get_perm_np(mperms, acl_perms[i].perm))
+ acl_add_perm(rperms, acl_perms[i].perm);
+ }
+ for (i = 0; acl_flags[i].name != NULL; i++) {
+ if (acl_get_flag_np(mflags, acl_flags[i].flag))
+ acl_add_flag_np(rflags, acl_flags[i].flag);
+ }
+ acl_set_permset(rentry, rperms);
+ acl_set_flagset_np(rentry, rflags);
+ return 0;
+}
+
+int
+modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags,
+ int position, int inheritance_level,
+ unsigned flag_new_acl, const char* path) {
+
+ unsigned cpos = 0;
+ acl_entry_t newent = NULL;
+ int dmatch = 0;
+ acl_entry_t rentry = NULL;
+ unsigned retval = 0;
+ acl_t oacl = *oaclp;
+
+/* Add the inherited flag if requested by the user*/
+ if (modifier && (optflags & ACL_INHERIT_FLAG)) {
+ acl_flagset_t mflags;
+
+ acl_get_flagset_np(modifier, &mflags);
+ acl_add_flag_np(mflags, ACL_ENTRY_INHERITED);
+ acl_set_flagset_np(modifier, mflags);
+ }
+
+ if (optflags & ACL_SET_FLAG) {
+ if (position != -1) {
+ if (0 != acl_create_entry_np(&oacl, &newent, position))
+ err(1, "acl_create_entry() failed");
+ acl_copy_entry(newent, modifier);
+ } else {
+/* If an entry exists, add the new permissions to it, else add an
+ * entry in the canonical position.
+ */
+
+/* First, check for a matching entry - if one exists, merge flags */
+ dmatch = find_matching_entry(oacl, modifier, &rentry, 1);
+
+ if (dmatch != MATCH_NONE) {
+ if (dmatch == MATCH_EXACT)
+/* Nothing to be done */
+ goto ma_exit;
+
+ if (dmatch == MATCH_PARTIAL) {
+ merge_entry_perms(rentry, modifier);
+ goto ma_exit;
+ }
+ }
+/* Insert the entry in canonical order */
+ cpos = find_canonical_position(oacl, modifier);
+ if (0!= acl_create_entry_np(&oacl, &newent, cpos))
+ err(1, "acl_create_entry() failed");
+ acl_copy_entry(newent, modifier);
+ }
+ } else if (optflags & ACL_DELETE_FLAG) {
+ if (flag_new_acl) {
+ warnx("No ACL present '%s'", path);
+ retval = 1;
+ } else if (position != -1 ) {
+ if (0 != acl_get_entry(oacl, position, &rentry)) {
+ warnx("Invalid entry number '%s'", path);
+ retval = 1;
+ } else {
+ acl_delete_entry(oacl, rentry);
+ }
+ } else {
+ unsigned match_found = 0, aindex;
+ for (aindex = 0;
+ acl_get_entry(oacl, rentry == NULL ?
+ ACL_FIRST_ENTRY :
+ ACL_NEXT_ENTRY, &rentry) == 0;
+ aindex++) {
+ unsigned cmp;
+ cmp = compare_acl_entries(rentry, modifier);
+ if ((cmp == MATCH_EXACT) ||
+ (cmp == MATCH_PARTIAL)) {
+ match_found++;
+ if (cmp == MATCH_EXACT)
+ acl_delete_entry(oacl, rentry);
+ else {
+ int valid_perms;
+/* In the event of a partial match, remove the specified perms from the
+ * entry */
+ subtract_from_entry(rentry, modifier, &valid_perms);
+ /* if no perms survived then delete the entry */
+ if (valid_perms == 0)
+ acl_delete_entry(oacl, rentry);
+ }
+ }
+ }
+ if (0 == match_found) {
+ warnx("Entry not found when attempting delete '%s'",path);
+ retval = 1;
+ }
+ }
+ } else if (optflags & ACL_REWRITE_FLAG) {
+ acl_entry_t rentry;
+
+ if (-1 == position) {
+ usage();
+ }
+ if (0 == flag_new_acl) {
+ if (0 != acl_get_entry(oacl, position,
+ &rentry))
+ err(1, "Invalid entry number '%s'", path);
+
+ if (0 != acl_delete_entry(oacl, rentry))
+ err(1, "Unable to delete entry '%s'", path);
+ }
+ if (0!= acl_create_entry_np(&oacl, &newent, position))
+ err(1, "acl_create_entry() failed");
+ acl_copy_entry(newent, modifier);
+ }
+ma_exit:
+ *oaclp = oacl;
+ return retval;
+}
+
+int
+modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow) {
+
+ acl_t oacl = NULL;
+ unsigned aindex = 0, flag_new_acl = 0;
+ acl_entry_t newent = NULL;
+ acl_entry_t entry = NULL;
+ unsigned retval = 0;
+
+ extern int fflag;
+
+/* XXX acl_get_file() returns a zero entry ACL if an ACL was previously
+ * associated with the file, and has had its entries removed.
+ * However, POSIX 1003.1e states that a zero entry ACL should be
+ * returned if the caller asks for ACL_TYPE_DEFAULT, and no ACL is
+ * associated with the path; it
+ * does not specifically state that a request for ACL_TYPE_EXTENDED
+ * should not return a zero entry ACL, however.
+ */
+
+/* Determine if we've been given a zero entry ACL, or create an ACL if
+ * none exists. There are some issues to consider here: Should we create
+ * a zero-entry ACL for a delete or check canonicity operation?
+ */
+
+ if (path == NULL)
+ usage();
+
+ if (optflags & ACL_CLEAR_FLAG) {
+ filesec_t fsec = filesec_init();
+ if (fsec == NULL) {
+ err(1, "filesec_init() failed");
+ }
+ if (filesec_set_property(fsec, FILESEC_ACL, _FILESEC_REMOVE_ACL) != 0) {
+ err(1, "filesec_set_property() failed");
+ }
+ if (follow) {
+ if (chmodx_np(path, fsec) != 0) {
+ if (!fflag) {
+ warn("Failed to clear ACL on file %s", path);
+ }
+ retval = 1;
+ }
+ } else {
+ int fd = open(path, O_SYMLINK);
+ if (fd != -1) {
+ if (fchmodx_np(fd, fsec) != 0) {
+ if (!fflag) {
+ warn("Failed to clear ACL on file %s", path);
+ }
+ retval = 1;
+ }
+ close(fd);
+ } else {
+ if (!fflag) {
+ warn("Failed to open file %s", path);
+ }
+ retval = 1;
+ }
+ }
+ filesec_free(fsec);
+ return (retval);
+ }
+
+ if (optflags & ACL_FROM_STDIN) {
+ oacl = acl_dup(modifier);
+ } else {
+ if (follow) {
+ oacl = acl_get_file(path, ACL_TYPE_EXTENDED);
+ } else {
+ int fd = open(path, O_SYMLINK);
+ if (fd != -1) {
+ oacl = acl_get_fd_np(fd, ACL_TYPE_EXTENDED);
+ close(fd);
+ }
+ }
+ if ((oacl == NULL) ||
+ (acl_get_entry(oacl,ACL_FIRST_ENTRY, &newent) != 0)) {
+ if ((oacl = acl_init(1)) == NULL)
+ err(1, "acl_init() failed");
+ flag_new_acl = 1;
+ position = 0;
+ }
+
+ if ((0 == flag_new_acl) && (optflags & (ACL_REMOVE_INHERIT_FLAG |
+ ACL_REMOVE_INHERITED_ENTRIES))) {
+ acl_t facl = NULL;
+ if ((facl = acl_init(1)) == NULL)
+ err(1, "acl_init() failed");
+ for (aindex = 0;
+ acl_get_entry(oacl,
+ (entry == NULL ? ACL_FIRST_ENTRY :
+ ACL_NEXT_ENTRY), &entry) == 0;
+ aindex++) {
+ acl_flagset_t eflags;
+ acl_entry_t fent = NULL;
+ if (acl_get_flagset_np(entry, &eflags) != 0) {
+ err(1, "Unable to obtain flagset");
+ }
+
+ if (acl_get_flag_np(eflags, ACL_ENTRY_INHERITED)) {
+ if (optflags & ACL_REMOVE_INHERIT_FLAG) {
+ acl_delete_flag_np(eflags, ACL_ENTRY_INHERITED);
+ acl_set_flagset_np(entry, eflags);
+ acl_create_entry(&facl, &fent);
+ acl_copy_entry(fent, entry);
+ }
+ }
+ else {
+ acl_create_entry(&facl, &fent);
+ acl_copy_entry(fent, entry);
+ }
+ }
+ if (oacl)
+ acl_free(oacl);
+ oacl = facl;
+ } else if (optflags & ACL_TO_STDOUT) {
+ ssize_t len; /* need to get printacl() from ls(1) */
+ char *text = acl_to_text(oacl, &len);
+ puts(text);
+ acl_free(text);
+ } else if (optflags & ACL_CHECK_CANONICITY) {
+ if (flag_new_acl) {
+ warnx("No ACL currently associated with file '%s'", path);
+ }
+ retval = is_canonical(oacl);
+ } else if ((optflags & ACL_SET_FLAG) && (position == -1) &&
+ (!is_canonical(oacl))) {
+ warnx("The specified file '%s' does not have an ACL in canonical order, please specify a position with +a# ", path);
+ retval = 1;
+ } else if (((optflags & ACL_DELETE_FLAG) && (position != -1))
+ || (optflags & ACL_CHECK_CANONICITY)) {
+ retval = modify_acl(&oacl, NULL, optflags, position,
+ inheritance_level, flag_new_acl, path);
+ } else if ((optflags & (ACL_REMOVE_INHERIT_FLAG|ACL_REMOVE_INHERITED_ENTRIES)) && flag_new_acl) {
+ warnx("No ACL currently associated with file '%s'", path);
+ retval = 1;
+ } else {
+ if (!modifier) { /* avoid bus error in acl_get_entry */
+ errx(1, "Internal error: modifier should not be NULL");
+ }
+ for (aindex = 0;
+ acl_get_entry(modifier,
+ (entry == NULL ? ACL_FIRST_ENTRY :
+ ACL_NEXT_ENTRY), &entry) == 0;
+ aindex++) {
+
+ retval += modify_acl(&oacl, entry, optflags,
+ position, inheritance_level,
+ flag_new_acl, path);
+ }
+ }
+ }
+
+/* XXX Potential race here, since someone else could've modified or
+ * read the ACL on this file (with the intention of modifying it) in
+ * the interval from acl_get_file() to acl_set_file(); we can
+ * minimize one aspect of this window by comparing the original acl
+ * to a fresh one from acl_get_file() but we could consider a
+ * "changeset" mechanism, common locking strategy, or kernel
+ * supplied reservation mechanism to prevent this race.
+ */
+ if (!(optflags & (ACL_TO_STDOUT|ACL_CHECK_CANONICITY))) {
+ int status = -1;
+ if (follow) {
+ status = acl_set_file(path, ACL_TYPE_EXTENDED, oacl);
+ } else {
+ int fd = open(path, O_SYMLINK);
+ if (fd != -1) {
+ status = acl_set_fd_np(fd, oacl,
+ ACL_TYPE_EXTENDED);
+ close(fd);
+ }
+ }
+ if (status != 0) {
+ if (!fflag)
+ warn("Failed to set ACL on file '%s'", path);
+ retval = 1;
+ }
+ }
+
+ if (oacl)
+ acl_free(oacl);
+
+ return retval;
+}
+
+#endif /*__APPLE__*/
diff --git a/file_cmds/chmod/chmod_acl.h b/file_cmds/chmod/chmod_acl.h
new file mode 100644
index 0000000..b4667e9
--- /dev/null
+++ b/file_cmds/chmod/chmod_acl.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _CHMOD_ACL_H_
+#define _CHMOD_ACL_H_
+
+#ifdef __APPLE__
+#include <pwd.h>
+#include <grp.h>
+#include <ctype.h>
+#include <sys/acl.h>
+#include <sys/kauth.h>
+#include <uuid/uuid.h>
+
+#define ACL_FLAG (1<<0)
+#define ACL_SET_FLAG (1<<1)
+#define ACL_DELETE_FLAG (1<<2)
+#define ACL_REWRITE_FLAG (1<<3)
+#define ACL_ORDER_FLAG (1<<4)
+#define ACL_INHERIT_FLAG (1<<5)
+#define ACL_FOLLOW_LINK (1<<6)
+#define ACL_FROM_STDIN (1<<7)
+#define ACL_CHECK_CANONICITY (1<<8)
+#define ACL_REMOVE_INHERIT_FLAG (1<<9)
+#define ACL_REMOVE_INHERITED_ENTRIES (1<<10)
+#define ACL_NO_TRANSLATE (1<<11)
+#define ACL_INVOKE_EDITOR (1<<12)
+#define ACL_TO_STDOUT (1<<13)
+#define ACL_CLEAR_FLAG (1<<14)
+
+#define INHERITANCE_TIER (-5)
+#define MINIMUM_TIER (-1000)
+
+#define MATCH_EXACT (2)
+#define MATCH_PARTIAL (1)
+#define MATCH_NONE (-1)
+#define MATCH_SUBSET (-2)
+#define MATCH_SUPERSET (-3)
+
+#define MAX_ACL_TEXT_SIZE 4096
+#define MAX_INHERITANCE_LEVEL 1024
+
+extern int search_acl_block(char *tok);
+extern int parse_entry(char *entrybuf, acl_entry_t newent);
+extern acl_t parse_acl_entries(const char *input);
+extern int score_acl_entry(acl_entry_t entry);
+extern unsigned get_inheritance_level(acl_entry_t entry);
+extern int compare_acl_qualifiers(uuid_t *qa, uuid_t *qb);
+extern int compare_acl_permsets(acl_permset_t aperms, acl_permset_t bperms);
+extern int compare_acl_entries(acl_entry_t a, acl_entry_t b);
+extern unsigned is_canonical(acl_t acl);
+extern int find_matching_entry (acl_t acl, acl_entry_t modifier, acl_entry_t *rentry, unsigned match_inherited);
+extern unsigned find_canonical_position(acl_t acl, acl_entry_t modifier);
+extern int subtract_from_entry(acl_entry_t rentry, acl_entry_t modifier, int *valid_perms);
+extern int modify_acl(acl_t *oaclp, acl_entry_t modifier, unsigned int optflags, int position, int inheritance_level, unsigned flag_new_acl, const char* path);
+extern int modify_file_acl(unsigned int optflags, const char *path, acl_t modifier, int position, int inheritance_level, int follow);
+extern uuid_t *name_to_uuid(char *tok, int nametype);
+#endif /* __APPLE__*/
+
+#endif /* _CHMOD_ACL_H_ */
diff --git a/file_cmds/chown/chgrp.1 b/file_cmds/chown/chgrp.1
new file mode 100644
index 0000000..593c609
--- /dev/null
+++ b/file_cmds/chown/chgrp.1
@@ -0,0 +1,144 @@
+.\" Copyright (c) 1983, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chgrp.1 8.3 (Berkeley) 3/31/94
+.\" $FreeBSD: src/usr.sbin/chown/chgrp.1,v 1.13 2001/08/15 09:09:46 ru Exp $
+.\"
+.Dd March 31, 1994
+.Dt CHGRP 1
+.Os
+.Sh NAME
+.Nm chgrp
+.Nd change group
+.Sh SYNOPSIS
+.Nm chgrp
+.Op Fl fhnv
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Ar group
+.Ar
+.Sh DESCRIPTION
+The
+.Nm chgrp
+utility sets the group ID of the file named by each
+.Ar file
+operand to the
+.Ar group
+ID specified by the group operand.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl f
+The force option ignores errors, except for usage errors and doesn't
+query about strange modes (unless the user does not have proper permissions).
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed).
+.It Fl h
+If the file is a symbolic link, the group ID of the link itself is changed
+rather than the file that is pointed to.
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+This is the default. Use
+.Fl h
+to change the group ID of a symbolic link.
+.It Fl R
+Change the group ID for the file hierarchies rooted
+in the files instead of just the files themselves.
+.It Fl n
+Interpret the group ID as numeric, avoiding the name lookup.
+.It Fl v
+Cause
+.Nm chgrp
+to be verbose, showing files as the group is modified.
+.El
+.Pp
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+The
+.Ar group
+operand can be either a group name from the group database,
+or a numeric group ID.
+If a group name is also a numeric group ID, the operand is used as a
+group name.
+.Pp
+The user invoking
+.Nm chgrp
+must belong to the specified group and be the owner of the file,
+or be the super-user.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh COMPATIBILITY
+In previous versions of this system, symbolic links did not have groups.
+.Pp
+The
+.Fl v
+option is non-standard and its use in scripts is not recommended.
+.Sh FILES
+.Bl -tag -width /etc/group -compact
+.It Pa /etc/group
+group ID file
+.El
+.Sh SEE ALSO
+.Xr chown 2 ,
+.Xr fts 3 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr symlink 7 ,
+.Xr chown 8
+.Sh STANDARDS
+The
+.Nm chgrp
+utility is expected to be
+.St -p1003.2
+compatible.
diff --git a/file_cmds/chown/chown.8 b/file_cmds/chown/chown.8
new file mode 100644
index 0000000..3455497
--- /dev/null
+++ b/file_cmds/chown/chown.8
@@ -0,0 +1,177 @@
+.\" Copyright (c) 1990, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)chown.8 8.3 (Berkeley) 3/31/94
+.\" $FreeBSD: src/usr.sbin/chown/chown.8,v 1.20 2002/07/14 14:42:43 charnier Exp $
+.\"
+.Dd March 31, 1994
+.Dt CHOWN 8
+.Os
+.Sh NAME
+.Nm chown
+.Nd change file owner and group
+.Sh SYNOPSIS
+.Nm chown
+.Op Fl fhnv
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Ar owner Ns Op : Ns Ar group
+.Ar
+.Nm chown
+.Op Fl fhnv
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.No : Ns Ar group
+.Ar
+.Sh DESCRIPTION
+The
+.Nm chown
+utility changes the user ID and/or the group ID of the specified files.
+Symbolic links named by arguments are silently left unchanged unless
+.Fl h
+is used.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f
+Don't report any failure to change file owner or group, nor modify
+the exit status to reflect such failures.
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl h
+If the file is a symbolic link, change the user ID and/or the
+group ID of the link itself.
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+Instead, the user and/or group ID of the link itself are modified.
+This is the default. Use
+.Fl h
+to change the user ID and/or the group of symbolic links.
+.It Fl R
+Change the user ID and/or the group ID for the file hierarchies rooted
+in the files instead of just the files themselves.
+.It Fl n
+Interpret user ID and group ID as numeric, avoiding name lookups.
+.It Fl v
+Cause
+.Nm chown
+to be verbose, showing files as the owner is modified.
+.El
+.Pp
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+The
+.Ar owner
+and
+.Ar group
+operands are both optional;
+however, at least one must be specified.
+If the
+.Ar group
+operand is specified, it must be preceded by a colon (``:'') character.
+.Pp
+The
+.Ar owner
+may be either a numeric user ID or a user name.
+If a user name is also a numeric user ID, the operand is used as a
+user name.
+The
+.Ar group
+may be either a numeric group ID or a group name.
+If a group name is also a numeric group ID, the operand is used as a
+group name.
+.Pp
+For obvious security reasons,
+the ownership of a file may only be altered by a super-user.
+Similarly, only a member of a group can change a file's group ID
+to that group.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh COMPATIBILITY
+Previous versions of the
+.Nm chown
+utility used the dot (``.'') character to distinguish the group name.
+This has been changed to be a colon (``:'') character,
+so that user and group names may contain the dot character.
+.Pp
+On previous versions of this system,
+symbolic links did not have owners.
+.Pp
+The
+.Fl v
+option is non-standard and its use in scripts is not recommended.
+.Sh LEGACY DESCRIPTION
+In legacy mode, the
+.Fl R
+and
+.Fl RP
+options do not change the user ID
+or the group ID of symbolic links.
+.Sh SEE ALSO
+.Xr chgrp 1 ,
+.Xr find 1 ,
+.Xr chown 2 ,
+.Xr fts 3 ,
+.Xr compat 5 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm chown
+utility is expected to be
+.St -p1003.2
+compliant.
+.Sh HISTORY
+A
+.Nm chown
+utility appeared in
+.At v1 .
diff --git a/file_cmds/chown/chown.c b/file_cmds/chown/chown.c
new file mode 100644
index 0000000..708a6c5
--- /dev/null
+++ b/file_cmds/chown/chown.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.sbin/chown/chown.c,v 1.24 2002/07/17 16:22:24 dwmalone Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+void a_gid(const char *);
+void a_uid(const char *);
+void chownerr(const char *);
+static uid_t id(const char *, const char *);
+void usage(void);
+
+uid_t uid;
+gid_t gid;
+int ischown;
+#ifdef __APPLE__
+int isnumeric = 0;
+#endif
+const char *gname;
+
+int
+main(int argc, char **argv)
+{
+ FTS *ftsp;
+ FTSENT *p;
+ int Hflag, Lflag, Pflag, Rflag, fflag, hflag, vflag;
+ int ch, fts_options, rval;
+ char *cp;
+ int unix2003_compat = 0;
+ int symlink_found = 0;
+
+ if (argc < 1)
+ usage();
+ cp = strrchr(argv[0], '/');
+ cp = (cp != NULL) ? cp + 1 : argv[0];
+ ischown = (strcmp(cp, "chown") == 0);
+
+ Hflag = Lflag = Pflag = Rflag = fflag = hflag = vflag = 0;
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "HLPRfhnv")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "HLPRfhv")) != -1)
+#endif
+ switch (ch) {
+ case 'H':
+ Hflag = 1;
+ Lflag = Pflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = Pflag = 0;
+ break;
+ case 'P':
+ Pflag = 1;
+ Hflag = Lflag = 0;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+#ifdef __APPLE__
+ case 'n':
+ isnumeric = 1;
+ break;
+#endif
+ case 'v':
+ vflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc < 2)
+ usage();
+ if (!Rflag && (Hflag || Lflag || Pflag))
+ warnx("options -H, -L, -P only useful with -R");
+
+ if (Rflag) {
+ fts_options = FTS_PHYSICAL;
+ if (hflag && (Hflag || Lflag))
+ errx(1, "the -R%c and -h options may not be "
+ "specified together", Hflag ? 'H' : 'L');
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ else if (Lflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ } else
+ fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL;
+
+ uid = (uid_t)-1;
+ gid = (gid_t)-1;
+ if (ischown) {
+ unix2003_compat = COMPAT_MODE("bin/chown", "Unix2003");
+ if ((cp = strchr(*argv, ':')) != NULL) {
+ *cp++ = '\0';
+ a_gid(cp);
+ }
+#ifdef SUPPORT_DOT
+ else if ((cp = strchr(*argv, '.')) != NULL) {
+ warnx("separation of user and group with a period is deprecated");
+ *cp++ = '\0';
+ a_gid(cp);
+ }
+#endif
+ a_uid(*argv);
+ } else {
+ unix2003_compat = COMPAT_MODE("bin/chgrp", "Unix2003");
+ a_gid(*argv);
+ }
+
+ if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL)
+ err(1, NULL);
+
+ for (rval = 0; (p = fts_read(ftsp)) != NULL;) {
+ symlink_found = 0;
+ switch (p->fts_info) {
+ case FTS_D: /* Change it at FTS_DP. */
+ if (!Rflag)
+ fts_set(ftsp, p, FTS_SKIP);
+ continue;
+ case FTS_DNR: /* Warn, chown. */
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ case FTS_ERR: /* Warn, continue. */
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ continue;
+ case FTS_SL:
+ case FTS_SLNONE:
+ /*
+ * The only symlinks that end up here are ones that
+ * don't point to anything and ones that we found
+ * doing a physical walk.
+ */
+ if (hflag)
+ break;
+ else {
+ symlink_found = 1;
+ if (unix2003_compat) {
+ if (Hflag || Lflag) { /* -H or -L was specified */
+ if (p->fts_errno) {
+ warnx("%s: %s", p->fts_name, strerror(p->fts_errno));
+ rval = 1;
+ continue;
+ }
+ }
+ break; /* Otherwise symlinks keep going */
+ }
+ continue;
+ }
+ default:
+ break;
+ }
+ if (unix2003_compat) {
+ /* Can only avoid updating times if both uid and gid are -1 */
+ if ((uid == (uid_t)-1) && (gid == (gid_t)-1))
+ continue;
+ } else {
+ if ((uid == (uid_t)-1 || uid == p->fts_statp->st_uid) &&
+ (gid == (gid_t)-1 || gid == p->fts_statp->st_gid))
+ continue;
+ }
+ if (((hflag || symlink_found) ? lchown : chown)(p->fts_accpath, uid, gid) == -1) {
+ if (!fflag) {
+ chownerr(p->fts_path);
+ rval = 1;
+ }
+ } else {
+ if (vflag)
+ printf("%s\n", p->fts_path);
+ }
+ }
+ if (errno)
+ err(1, "fts_read");
+ exit(rval);
+}
+
+void
+a_gid(const char *s)
+{
+ struct group *gr;
+
+ if (*s == '\0') /* Argument was "uid[:.]". */
+ return;
+ gname = s;
+#ifdef __APPLE__
+ gid = (!isnumeric && ((gr = getgrnam(s)) != NULL)) ? gr->gr_gid : id(s, "group");
+#else
+ gid = ((gr = getgrnam(s)) != NULL) ? gr->gr_gid : id(s, "group");
+#endif
+}
+
+void
+a_uid(const char *s)
+{
+ struct passwd *pw;
+
+ if (*s == '\0') /* Argument was "[:.]gid". */
+ return;
+#ifdef __APPLE__
+ uid = (!isnumeric && ((pw = getpwnam(s)) != NULL)) ? pw->pw_uid : id(s, "user");
+#else
+ uid = ((pw = getpwnam(s)) != NULL) ? pw->pw_uid : id(s, "user");
+#endif
+}
+
+static uid_t
+id(const char *name, const char *type)
+{
+ unsigned long val;
+ char *ep;
+
+ errno = 0;
+ val = strtoul(name, &ep, 10);
+ if (errno || *ep != '\0' || val > UID_MAX)
+ errx(1, "%s: illegal %s name", name, type);
+ return (uid_t)val;
+}
+
+void
+chownerr(const char *file)
+{
+ static uid_t euid = -1;
+ static int ngroups = -1;
+ gid_t groups[NGROUPS_MAX];
+
+ /* Check for chown without being root. */
+ if (errno != EPERM || (uid != (uid_t)-1 &&
+ euid == (uid_t)-1 && (euid = geteuid()) != 0)) {
+ warn("%s", file);
+ return;
+ }
+
+ /* Check group membership; kernel just returns EPERM. */
+ if (gid != (gid_t)-1 && ngroups == -1 &&
+ euid == (uid_t)-1 && (euid = geteuid()) != 0) {
+ ngroups = getgroups(NGROUPS_MAX, groups);
+ while (--ngroups >= 0 && gid != groups[ngroups]);
+ if (ngroups < 0) {
+ warnx("you are not a member of group %s", gname);
+ return;
+ }
+ }
+ warn("%s", file);
+}
+
+void
+usage(void)
+{
+
+ if (ischown)
+ (void)fprintf(stderr, "%s\n%s\n",
+#ifdef __APPLE__
+ "usage: chown [-fhnv] [-R [-H | -L | -P]] owner[:group]"
+ " file ...",
+ " chown [-fhnv] [-R [-H | -L | -P]] :group file ...");
+#else
+ "usage: chown [-fhv] [-R [-H | -L | -P]] owner[:group]"
+ " file ...",
+ " chown [-fhv] [-R [-H | -L | -P]] :group file ...");
+#endif
+ else
+ (void)fprintf(stderr, "%s\n",
+#ifdef __APPLE__
+ "usage: chgrp [-fhnv] [-R [-H | -L | -P]] group file ...");
+#else
+ "usage: chgrp [-fhv] [-R [-H | -L | -P]] group file ...");
+#endif
+ exit(1);
+}
diff --git a/file_cmds/cksum/cksum.1 b/file_cmds/cksum/cksum.1
new file mode 100644
index 0000000..b4161fe
--- /dev/null
+++ b/file_cmds/cksum/cksum.1
@@ -0,0 +1,182 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)cksum.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/usr.bin/cksum/cksum.1,v 1.19 2005/01/17 07:44:13 ru Exp $
+.\"
+.Dd April 28, 1995
+.Dt CKSUM 1
+.Os
+.Sh NAME
+.Nm cksum ,
+.Nm sum
+.Nd display file checksums and block counts
+.Sh SYNOPSIS
+.Nm
+.Op Fl o Ar 1 | 2 | 3
+.Op Ar
+.Nm sum
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility writes to the standard output three whitespace separated
+fields for each input file.
+These fields are a checksum
+.Tn CRC ,
+the total number of octets in the file and the file name.
+If no file name is specified, the standard input is used and no file name
+is written.
+.Pp
+The
+.Nm sum
+utility is identical to the
+.Nm
+utility, except that it defaults to using historic algorithm 1, as
+described below.
+It is provided for compatibility only.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl o
+Use historic algorithms instead of the (superior) default one.
+.Pp
+Algorithm 1 is the algorithm used by historic
+.Bx
+systems as the
+.Xr sum 1
+algorithm and by historic
+.At V
+systems as the
+.Xr sum 1
+algorithm when using the
+.Fl r
+option.
+This is a 16-bit checksum, with a right rotation before each addition;
+overflow is discarded.
+.Pp
+Algorithm 2 is the algorithm used by historic
+.At V
+systems as the
+default
+.Xr sum 1
+algorithm.
+This is a 32-bit checksum, and is defined as follows:
+.Bd -unfilled -offset indent
+s = sum of all bytes;
+r = s % 2^16 + (s % 2^32) / 2^16;
+cksum = (r % 2^16) + r / 2^16;
+.Ed
+.Pp
+Algorithm 3 is what is commonly called the
+.Ql 32bit CRC
+algorithm.
+This is a 32-bit checksum.
+.Pp
+Both algorithm 1 and 2 write to the standard output the same fields as
+the default algorithm except that the size of the file in bytes is
+replaced with the size of the file in blocks.
+For historic reasons, the block size is 1024 for algorithm 1 and 512
+for algorithm 2.
+Partial blocks are rounded up.
+.El
+.Pp
+The default
+.Tn CRC
+used is based on the polynomial used for
+.Tn CRC
+error checking
+in the networking standard
+.St -iso8802-3 .
+The
+.Tn CRC
+checksum encoding is defined by the generating polynomial:
+.Pp
+.Bd -unfilled -offset indent
+G(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 +
+ x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
+.Ed
+.Pp
+Mathematically, the
+.Tn CRC
+value corresponding to a given file is defined by
+the following procedure:
+.Bd -ragged -offset indent
+The
+.Ar n
+bits to be evaluated are considered to be the coefficients of a mod 2
+polynomial M(x) of degree
+.Ar n Ns \-1 .
+These
+.Ar n
+bits are the bits from the file, with the most significant bit being the most
+significant bit of the first octet of the file and the last bit being the least
+significant bit of the last octet, padded with zero bits (if necessary) to
+achieve an integral number of octets, followed by one or more octets
+representing the length of the file as a binary value, least significant octet
+first.
+The smallest number of octets capable of representing this integer are used.
+.Pp
+M(x) is multiplied by x^32 (i.e., shifted left 32 bits) and divided by
+G(x) using mod 2 division, producing a remainder R(x) of degree <= 31.
+.Pp
+The coefficients of R(x) are considered to be a 32-bit sequence.
+.Pp
+The bit sequence is complemented and the result is the CRC.
+.Ed
+.Sh EXIT STATUS
+.Ex -std cksum sum
+.Sh SEE ALSO
+.Xr md5 1
+.Pp
+The default calculation is identical to that given in pseudo-code
+in the following
+.Tn ACM
+article.
+.Rs
+.%T "Computation of Cyclic Redundancy Checks Via Table Lookup"
+.%A Dilip V. Sarwate
+.%J "Communications of the" Tn ACM
+.%D "August 1988"
+.Re
+.Sh STANDARDS
+The
+.Nm
+utility is expected to conform to
+.St -p1003.2-92 .
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.4 .
diff --git a/file_cmds/cksum/cksum.c b/file_cmds/cksum/cksum.c
new file mode 100644
index 0000000..ae6a7ed
--- /dev/null
+++ b/file_cmds/cksum/cksum.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James W. Williams of NASA Goddard Space Flight Center.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cksum.c 8.2 (Berkeley) 4/28/95";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/cksum.c,v 1.17 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ uint32_t val;
+ int ch, fd, rval;
+ off_t len;
+ char *fn, *p;
+ int (*cfncn)(int, uint32_t *, off_t *);
+ void (*pfncn)(char *, u_int32_t, off_t);
+
+ cfncn=NULL;
+
+ if(*argv) {
+ if ((p = rindex(argv[0], '/')) == NULL)
+ p = argv[0];
+ else
+ ++p;
+ if (!strcmp(p, "sum")) {
+ cfncn = csum1;
+ pfncn = psum1;
+ ++argv;
+ }
+ }
+
+ if(!cfncn) {
+ cfncn = crc;
+ pfncn = pcrc;
+
+ while ((ch = getopt(argc, argv, "o:")) != -1)
+ switch (ch) {
+ case 'o':
+ if (!strcmp(optarg, "1")) {
+ cfncn = csum1;
+ pfncn = psum1;
+ } else if (!strcmp(optarg, "2")) {
+ cfncn = csum2;
+ pfncn = psum2;
+ } else if (!strcmp(optarg, "3")) {
+ cfncn = crc32;
+ pfncn = pcrc;
+ } else {
+ warnx("illegal argument to -o option");
+ usage();
+ }
+ break;
+ case '?':
+ default:
+ usage();
+ }
+// argc -= optind;
+ argv += optind;
+ }
+
+ fd = STDIN_FILENO;
+ fn = NULL;
+ rval = 0;
+ do {
+ if (*argv) {
+ fn = *argv++;
+ if ((fd = open(fn, O_RDONLY, 0)) < 0) {
+ warn("%s", fn);
+ rval = 1;
+ continue;
+ }
+ }
+ if (cfncn(fd, &val, &len)) {
+ warn("%s", fn ? fn : "stdin");
+ rval = 1;
+ } else
+ pfncn(fn, val, len);
+ (void)close(fd);
+ } while (*argv);
+ exit(rval);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: cksum [-o 1 | 2 | 3] [file ...]\n");
+ (void)fprintf(stderr, " sum [file ...]\n");
+ exit(1);
+}
diff --git a/file_cmds/cksum/crc.c b/file_cmds/cksum/crc.c
new file mode 100644
index 0000000..57179d5
--- /dev/null
+++ b/file_cmds/cksum/crc.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James W. Williams of NASA Goddard Space Flight Center.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)crc.c 8.1 (Berkeley) 6/17/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/crc.c,v 1.8 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+static const uint32_t crctab[] = {
+ 0x0,
+ 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6,
+ 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
+ 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac,
+ 0x5bd4b01b, 0x569796c2, 0x52568b75, 0x6a1936c8, 0x6ed82b7f,
+ 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a,
+ 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58,
+ 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033,
+ 0xa4ad16ea, 0xa06c0b5d, 0xd4326d90, 0xd0f37027, 0xddb056fe,
+ 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
+ 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4,
+ 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5,
+ 0x2ac12072, 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
+ 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, 0x7897ab07,
+ 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c,
+ 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1,
+ 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b,
+ 0xbb60adfc, 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698,
+ 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d,
+ 0x94ea7b2a, 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
+ 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, 0xc6bcf05f,
+ 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80,
+ 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
+ 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a,
+ 0x58c1663d, 0x558240e4, 0x51435d53, 0x251d3b9e, 0x21dc2629,
+ 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c,
+ 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e,
+ 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65,
+ 0xeba91bbc, 0xef68060b, 0xd727bbb6, 0xd3e6a601, 0xdea580d8,
+ 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
+ 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2,
+ 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74,
+ 0x857130c3, 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
+ 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, 0x7b827d21,
+ 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a,
+ 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, 0x18197087,
+ 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d,
+ 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce,
+ 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb,
+ 0xdbee767c, 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
+ 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, 0x89b8fd09,
+ 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf,
+ 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+/*
+ * Compute a POSIX 1003.2 checksum. This routine has been broken out so that
+ * other programs can use it. It takes a file descriptor to read from and
+ * locations to store the crc and the number of bytes read. It returns 0 on
+ * success and 1 on failure. Errno is set on failure.
+ */
+uint32_t crc_total = ~0; /* The crc over a number of files. */
+
+int
+crc(int fd, uint32_t *cval, off_t *clen)
+{
+ uint32_t lcrc;
+ ssize_t nr;
+ off_t len;
+ u_char *p;
+ u_char buf[16 * 1024];
+
+#define COMPUTE(var, ch) (var) = (var) << 8 ^ crctab[(var) >> 24 ^ (ch)]
+
+ lcrc = 0;
+ len = 0;
+ crc_total = ~crc_total;
+ while ((nr = read(fd, buf, sizeof(buf))) > 0)
+ for (len += nr, p = buf; nr--; ++p) {
+ COMPUTE(lcrc, *p);
+ COMPUTE(crc_total, *p);
+ }
+ if (nr < 0)
+ return (1);
+
+ *clen = len;
+
+ /* Include the length of the file. */
+ for (; len != 0; len >>= 8) {
+ COMPUTE(lcrc, len & 0xff);
+ COMPUTE(crc_total, len & 0xff);
+ }
+
+ *cval = ~lcrc;
+ crc_total = ~crc_total;
+ return (0);
+}
diff --git a/file_cmds/cksum/crc32.c b/file_cmds/cksum/crc32.c
new file mode 100644
index 0000000..ff17565
--- /dev/null
+++ b/file_cmds/cksum/crc32.c
@@ -0,0 +1,122 @@
+/*
+ * This code implements the AUTODIN II polynomial used by Ethernet,
+ * and can be used to calculate multicast address hash indices.
+ * It assumes that the low order bits will be transmitted first,
+ * and consequently the low byte should be sent first when
+ * the crc computation is finished. The crc should be complemented
+ * before transmission.
+ * The variable corresponding to the macro argument "crc" should
+ * be an unsigned long and should be preset to all ones for Ethernet
+ * use. An error-free packet will leave 0xDEBB20E3 in the crc.
+ * Spencer Garrett <srg@quick.com>
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/crc32.c,v 1.9 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
+
+/* generated using the AUTODIN II polynomial
+ * x^32 + x^26 + x^23 + x^22 + x^16 +
+ * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+ */
+static const uint32_t crctab[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+};
+
+uint32_t crc32_total = 0;
+
+int
+crc32(int fd, uint32_t *cval, off_t *clen)
+{
+ uint32_t lcrc = ~0;
+ ssize_t nr;
+ off_t len ;
+ char buf[BUFSIZ], *p ;
+
+ len = 0 ;
+ crc32_total = ~crc32_total ;
+ while ((nr = read(fd, buf, sizeof(buf))) > 0)
+ for (len += nr, p = buf; nr--; ++p) {
+ CRC(lcrc, *p) ;
+ CRC(crc32_total, *p) ;
+ }
+ if (nr < 0)
+ return 1 ;
+
+ *clen = len ;
+ *cval = ~lcrc ;
+ crc32_total = ~crc32_total ;
+ return 0 ;
+}
diff --git a/file_cmds/cksum/extern.h b/file_cmds/cksum/extern.h
new file mode 100644
index 0000000..3e9c8c6
--- /dev/null
+++ b/file_cmds/cksum/extern.h
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/cksum/extern.h,v 1.6 2003/03/13 23:32:28 robert Exp $
+ */
+
+#ifndef _CKSUM_EXTERN_H_
+#define _CKSUM_EXTERN_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+int crc(int, uint32_t *, off_t *);
+void pcrc(char *, uint32_t, off_t);
+void psum1(char *, uint32_t, off_t);
+void psum2(char *, uint32_t, off_t);
+int csum1(int, uint32_t *, off_t *);
+int csum2(int, uint32_t *, off_t *);
+int crc32(int, uint32_t *, off_t *);
+__END_DECLS
+
+#endif /* _CKSUM_EXTERN_H_ */
diff --git a/file_cmds/cksum/print.c b/file_cmds/cksum/print.c
new file mode 100644
index 0000000..4d732d9
--- /dev/null
+++ b/file_cmds/cksum/print.c
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/print.c,v 1.7 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdint.h>
+
+#include "extern.h"
+
+void
+pcrc(char *fn, uint32_t val, off_t len)
+{
+ (void)printf("%lu %jd", (u_long)val, (intmax_t)len);
+ if (fn != NULL)
+ (void)printf(" %s", fn);
+ (void)printf("\n");
+}
+
+void
+psum1(char *fn, uint32_t val, off_t len)
+{
+ (void)printf("%lu %jd", (u_long)val, (intmax_t)(len + 1023) / 1024);
+ if (fn != NULL)
+ (void)printf(" %s", fn);
+ (void)printf("\n");
+}
+
+void
+psum2(char *fn, uint32_t val, off_t len)
+{
+ (void)printf("%lu %jd", (u_long)val, (intmax_t)(len + 511) / 512);
+ if (fn != NULL)
+ (void)printf(" %s", fn);
+ (void)printf("\n");
+}
diff --git a/file_cmds/cksum/sum.1 b/file_cmds/cksum/sum.1
new file mode 100644
index 0000000..db04800
--- /dev/null
+++ b/file_cmds/cksum/sum.1
@@ -0,0 +1 @@
+.so man1/cksum.1
diff --git a/file_cmds/cksum/sum1.c b/file_cmds/cksum/sum1.c
new file mode 100644
index 0000000..fa016ce
--- /dev/null
+++ b/file_cmds/cksum/sum1.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)sum1.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/sum1.c,v 1.8 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdint.h>
+
+#include "extern.h"
+
+int
+csum1(int fd, uint32_t *cval, off_t *clen)
+{
+ ssize_t nr;
+ u_int lcrc;
+ off_t total;
+ u_char *p;
+ u_char buf[8192];
+
+ /*
+ * 16-bit checksum, rotating right before each addition;
+ * overflow is discarded.
+ */
+ lcrc = 0;
+ total = 0;
+ while ((nr = read(fd, buf, sizeof(buf))) > 0)
+ for (total += nr, p = buf; nr--; ++p) {
+ if (lcrc & 1)
+ lcrc |= 0x10000;
+ lcrc = ((lcrc >> 1) + *p) & 0xffff;
+ }
+ if (nr < 0)
+ return (1);
+
+ *cval = lcrc;
+ *clen = total;
+ return (0);
+}
diff --git a/file_cmds/cksum/sum2.c b/file_cmds/cksum/sum2.c
new file mode 100644
index 0000000..126b428
--- /dev/null
+++ b/file_cmds/cksum/sum2.c
@@ -0,0 +1,79 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)sum2.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cksum/sum2.c,v 1.8 2003/03/13 23:32:28 robert Exp $");
+
+#include <sys/types.h>
+
+#include <unistd.h>
+#include <stdint.h>
+
+#include "extern.h"
+
+int
+csum2(int fd, uint32_t *cval, off_t *clen)
+{
+ uint32_t lcrc;
+ ssize_t nr;
+ off_t total;
+ u_char *p;
+ u_char buf[8192];
+
+ /*
+ * Draft 8 POSIX 1003.2:
+ *
+ * s = sum of all bytes
+ * r = s % 2^16 + (s % 2^32) / 2^16
+ * lcrc = (r % 2^16) + r / 2^16
+ */
+ lcrc = 0;
+ total = 0;
+ while ((nr = read(fd, buf, sizeof(buf))) > 0)
+ for (total += nr, p = buf; nr--; ++p)
+ lcrc += *p;
+ if (nr < 0)
+ return (1);
+
+ lcrc = (lcrc & 0xffff) + (lcrc >> 16);
+ lcrc = (lcrc & 0xffff) + (lcrc >> 16);
+
+ *cval = lcrc;
+ *clen = total;
+ return (0);
+}
diff --git a/file_cmds/compress/compress.1 b/file_cmds/compress/compress.1
new file mode 100644
index 0000000..963cd7a
--- /dev/null
+++ b/file_cmds/compress/compress.1
@@ -0,0 +1,253 @@
+.\" Copyright (c) 1986, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" James A. Woods, derived from original work by Spencer Thomas
+.\" and Joseph Orost.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)compress.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/compress/compress.1,v 1.23 2010/12/11 08:32:16 joel Exp $
+.\"
+.Dd May 17, 2002
+.Dt COMPRESS 1
+.Os
+.Sh NAME
+.Nm compress ,
+.Nm uncompress
+.Nd compress and expand data
+.Sh SYNOPSIS
+.Nm
+.Op Fl fv
+.Op Fl b Ar bits
+.Op Ar
+.Nm
+.Fl c
+.Op Fl b Ar bits
+.Op Ar
+.Nm uncompress
+.Op Fl fv
+.Op Ar
+.Nm uncompress
+.Fl c
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility reduces the size of files using adaptive Lempel-Ziv coding.
+Each
+.Ar file
+is renamed to the same name plus the extension
+.Pa .Z .
+A
+.Ar file
+argument with a
+.Pa .Z
+extension will be ignored except it will cause an
+error exit after other arguments are processed.
+If compression would not reduce the size of a
+.Ar file ,
+the file is ignored.
+.Pp
+The
+.Nm uncompress
+utility restores compressed files to their original form, renaming the
+files by deleting the
+.Pa .Z
+extensions.
+A file specification need not include the file's
+.Pa .Z
+extension.
+If a file's name in its file system does not have a
+.Pa .Z
+extension, it will not be uncompressed and it will cause
+an error exit after other arguments are processed.
+.Pp
+If renaming the files would cause files to be overwritten and the standard
+input device is a terminal, the user is prompted (on the standard error
+output) for confirmation.
+If prompting is not possible or confirmation is not received, the files
+are not overwritten.
+.Pp
+As many of the modification time, access time, file flags, file mode,
+user ID, and group ID as allowed by permissions are retained in the
+new file.
+.Pp
+If no files are specified or a
+.Ar file
+argument is a single dash
+.Pq Sq Fl ,
+the standard input is compressed or uncompressed to the standard output.
+If either the input and output files are not regular files, the checks for
+reduction in size and file overwriting are not performed, the input file is
+not removed, and the attributes of the input file are not retained
+in the output file.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl b Ar bits"
+.It Fl b Ar bits
+The code size (see below) is limited to
+.Ar bits ,
+which must be in the range 9..16.
+The default is 16.
+.It Fl c
+Compressed or uncompressed output is written to the standard output.
+No files are modified.
+The
+.Fl v
+option is ignored.
+Compression is attempted even if the results will be larger than the
+original.
+.It Fl f
+Files are overwritten without prompting for confirmation.
+Also, for
+.Nm compress ,
+files are compressed even if they are not actually reduced in size.
+.It Fl v
+Print the percentage reduction of each file.
+Ignored by
+.Nm uncompress
+or if the
+.Fl c
+option is also used.
+.El
+.Pp
+The
+.Nm
+utility uses a modified Lempel-Ziv algorithm.
+Common substrings in the file are first replaced by 9-bit codes 257 and up.
+When code 512 is reached, the algorithm switches to 10-bit codes and
+continues to use more bits until the
+limit specified by the
+.Fl b
+option or its default is reached.
+.Pp
+After the limit is reached,
+.Nm
+periodically checks the compression ratio.
+If it is increasing,
+.Nm
+continues to use the existing code dictionary.
+However, if the compression ratio decreases,
+.Nm
+discards the table of substrings and rebuilds it from scratch.
+This allows
+the algorithm to adapt to the next "block" of the file.
+.Pp
+The
+.Fl b
+option is unavailable for
+.Nm uncompress
+since the
+.Ar bits
+parameter specified during compression
+is encoded within the output, along with
+a magic number to ensure that neither decompression of random data nor
+recompression of compressed data is attempted.
+.Pp
+The amount of compression obtained depends on the size of the
+input, the number of
+.Ar bits
+per code, and the distribution of common substrings.
+Typically, text such as source code or English is reduced by 50\-60%.
+Compression is generally much better than that achieved by Huffman
+coding (as used in the historical command pack), or adaptive Huffman
+coding (as used in the historical command compact), and takes less
+time to compute.
+.Sh EXIT STATUS
+.Ex -std compress uncompress
+.Pp
+The
+.Nm compress
+utility exits 2 if attempting to compress a file would not reduce its size
+and the
+.Fl f
+option was not specified and if no other error occurs.
+.Sh SEE ALSO
+.Xr gunzip 1 ,
+.Xr gzexe 1 ,
+.Xr gzip 1 ,
+.Xr zcat 1 ,
+.Xr zmore 1 ,
+.Xr znew 1
+.Rs
+.%A Welch, Terry A.
+.%D June, 1984
+.%T "A Technique for High Performance Data Compression"
+.%J "IEEE Computer"
+.%V 17:6
+.%P pp. 8-19
+.Re
+.Sh STANDARDS
+The
+.Nm compress
+and
+.Nm uncompress
+utilities conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
+.Sh BUGS
+Some of these might be considered otherwise-undocumented features.
+.Pp
+.Nm compress :
+If the utility does not compress a file because doing so would not
+reduce its size, and a file of the same name except with an
+.Pa .Z
+extension exists, the named file is not really ignored as stated above;
+it causes a prompt to confirm the overwriting of the file with the extension.
+If the operation is confirmed, that file is deleted.
+.Pp
+.Nm uncompress :
+If an empty file is compressed (using
+.Fl f ) ,
+the resulting
+.Pa .Z
+file is also empty.
+That seems right, but if
+.Nm uncompress
+is then used on that file, an error will occur.
+.Pp
+Both utilities: If a
+.Sq Fl
+argument is used and the utility prompts the user, the standard input
+is taken as the user's reply to the prompt.
+.Pp
+Both utilities:
+If the specified file does not exist, but a similarly-named one with (for
+.Nm compress )
+or without (for
+.Nm uncompress )
+a
+.Pa .Z
+extension does exist, the utility will waste the user's time by not
+immediately emitting an error message about the missing file and
+continuing.
+Instead, it first asks for confirmation to overwrite
+the existing file and then does not overwrite it.
diff --git a/file_cmds/compress/compress.c b/file_cmds/compress/compress.c
new file mode 100644
index 0000000..26da7fa
--- /dev/null
+++ b/file_cmds/compress/compress.c
@@ -0,0 +1,467 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)compress.c 8.2 (Berkeley) 1/7/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/compress/compress.c,v 1.23 2010/12/11 08:32:16 joel Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include "zopen.h"
+
+void compress(const char *, const char *, int);
+void cwarn(const char *, ...) __printflike(1, 2);
+void cwarnx(const char *, ...) __printflike(1, 2);
+void decompress(const char *, const char *, int);
+int permission(const char *);
+void setfile(const char *, struct stat *);
+void usage(int);
+
+int eval, force, verbose, cat;
+
+int
+main(int argc, char *argv[])
+{
+ enum {COMPRESS, DECOMPRESS} style;
+ size_t len;
+ int bits, ch;
+ char *p, newname[MAXPATHLEN];
+
+ if (argc < 1)
+ usage(1);
+ cat = 0;
+ if ((p = rindex(argv[0], '/')) == NULL)
+ p = argv[0];
+ else
+ ++p;
+ if (!strcmp(p, "uncompress"))
+ style = DECOMPRESS;
+ else if (!strcmp(p, "compress"))
+ style = COMPRESS;
+ else if (!strcmp(p, "zcat")) {
+ cat = 1;
+ style = DECOMPRESS;
+ } else
+ errx(1, "unknown program name");
+
+ bits = 0;
+ while ((ch = getopt(argc, argv, "b:cdfv")) != -1)
+ switch(ch) {
+ case 'b':
+ bits = strtol(optarg, &p, 10);
+ if (*p)
+ errx(1, "illegal bit count -- %s", optarg);
+ break;
+ case 'c':
+ cat = 1;
+ break;
+ case 'd': /* Backward compatible. */
+ style = DECOMPRESS;
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ usage(style == COMPRESS);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ cat = 1;
+ switch(style) {
+ case COMPRESS:
+ (void)compress("/dev/stdin", "/dev/stdout", bits);
+ break;
+ case DECOMPRESS:
+ (void)decompress("/dev/stdin", "/dev/stdout", bits);
+ break;
+ }
+ exit (eval);
+ }
+
+ /*
+ * The UNIX standard requires that `uncompress -c` be able to have multiple file parameters given.
+ */
+
+ for (; *argv; ++argv)
+ switch(style) {
+ case COMPRESS:
+ if (strcmp(*argv, "-") == 0) {
+ cat = 1;
+ compress("/dev/stdin", "/dev/stdout", bits);
+ break;
+ } else if (cat) {
+ compress(*argv, "/dev/stdout", bits);
+ break;
+ }
+ if ((p = rindex(*argv, '.')) != NULL &&
+ !strcmp(p, ".Z")) {
+ cwarnx("%s: name already has trailing .Z",
+ *argv);
+ break;
+ }
+ len = strlen(*argv);
+ if (len > sizeof(newname) - 3) {
+ cwarnx("%s: name too long", *argv);
+ break;
+ }
+ memmove(newname, *argv, len);
+ newname[len] = '.';
+ newname[len + 1] = 'Z';
+ newname[len + 2] = '\0';
+ compress(*argv, newname, bits);
+ break;
+ case DECOMPRESS:
+ if (strcmp(*argv, "-") == 0) {
+ cat = 1;
+ decompress("/dev/stdin", "/dev/stdout", bits);
+ break;
+ }
+ len = strlen(*argv);
+ if ((p = rindex(*argv, '.')) == NULL ||
+ strcmp(p, ".Z")) {
+ if (len > sizeof(newname) - 3) {
+ cwarnx("%s: name too long", *argv);
+ break;
+ }
+ memmove(newname, *argv, len);
+ newname[len] = '.';
+ newname[len + 1] = 'Z';
+ newname[len + 2] = '\0';
+ decompress(newname,
+ cat ? "/dev/stdout" : *argv, bits);
+ } else {
+ if (len - 2 > sizeof(newname) - 1) {
+ cwarnx("%s: name too long", *argv);
+ break;
+ }
+ memmove(newname, *argv, len - 2);
+ newname[len - 2] = '\0';
+ decompress(*argv,
+ cat ? "/dev/stdout" : newname, bits);
+ }
+ break;
+ }
+ exit (eval);
+}
+
+void
+compress(const char *in, const char *out, int bits)
+{
+ size_t nr;
+ struct stat isb, sb;
+ FILE *ifp = NULL, *ofp = NULL;
+ int exists, isreg, oreg;
+ u_char buf[1024];
+
+ exists = !stat(out, &sb);
+ if (!force && exists && S_ISREG(sb.st_mode) && !cat && !permission(out)) {
+ cwarnx("%s already exists", out);
+ return;
+ }
+ isreg = oreg = !exists || S_ISREG(sb.st_mode);
+
+ if ((ifp = fopen(in, "r")) == NULL) {
+ cwarn("%s", in);
+ return;
+ }
+ if (stat(in, &isb)) { /* DON'T FSTAT! */
+ cwarn("%s", in);
+ goto err;
+ }
+ if (!S_ISREG(isb.st_mode))
+ isreg = 0;
+
+ if ((ofp = zopen(out, "w", bits)) == NULL) {
+ cwarn("%s", out);
+ goto err;
+ }
+ while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
+ if (fwrite(buf, 1, nr, ofp) != nr) {
+ cwarn("%s", out);
+ goto err;
+ }
+
+ if (ferror(ifp) || fclose(ifp)) {
+ cwarn("%s", in);
+ goto err;
+ }
+ ifp = NULL;
+
+ if (fclose(ofp)) {
+ cwarn("%s", out);
+ goto err;
+ }
+ ofp = NULL;
+
+ if (!cat && isreg) {
+ if (stat(out, &sb)) {
+ cwarn("%s", out);
+ goto err;
+ }
+
+ if (!force && sb.st_size >= isb.st_size) {
+ if (verbose)
+ (void)fprintf(stderr, "%s: file would grow; left unmodified\n",
+ in);
+ eval = 2;
+ if (unlink(out))
+ cwarn("%s", out);
+ goto err;
+ }
+
+ setfile(out, &isb);
+
+ if (unlink(in))
+ cwarn("%s", in);
+
+ if (verbose) {
+ (void)fprintf(stderr, "%s: ", out);
+ if (isb.st_size > sb.st_size)
+ (void)fprintf(stderr, "%.0f%% compression\n",
+ ((float)sb.st_size / isb.st_size) * 100.0);
+ else
+ (void)fprintf(stderr, "%.0f%% expansion\n",
+ ((float)isb.st_size / sb.st_size) * 100.0);
+ }
+ }
+ return;
+
+err: if (ofp) {
+ if (!cat && oreg)
+ (void)unlink(out);
+ (void)fclose(ofp);
+ }
+ if (ifp)
+ (void)fclose(ifp);
+}
+
+void
+decompress(const char *in, const char *out, int bits)
+{
+ size_t nr;
+ struct stat sb;
+ FILE *ifp, *ofp;
+ int exists, isreg, oreg;
+ u_char buf[1024];
+
+ exists = !stat(out, &sb);
+ if (!force && exists && S_ISREG(sb.st_mode) && !cat && !permission(out)) {
+ cwarnx("%s already exists", out);
+ return;
+ }
+ isreg = oreg = !exists || S_ISREG(sb.st_mode);
+
+ ofp = NULL;
+ if ((ifp = zopen(in, "r", bits)) == NULL) {
+ cwarn("%s", in);
+ return;
+ }
+ if (stat(in, &sb)) {
+ cwarn("%s", in);
+ goto err;
+ }
+ if (!S_ISREG(sb.st_mode))
+ isreg = 0;
+
+ /*
+ * Try to read the first few uncompressed bytes from the input file
+ * before blindly truncating the output file.
+ */
+ if ((nr = fread(buf, 1, sizeof(buf), ifp)) == 0) {
+ cwarn("%s", in);
+ (void)fclose(ifp);
+ return;
+ }
+ if ((ofp = fopen(out, "w")) == NULL ||
+ (nr != 0 && fwrite(buf, 1, nr, ofp) != nr)) {
+ cwarn("%s", out);
+ (void)fclose(ifp);
+ return;
+ }
+
+ while ((nr = fread(buf, 1, sizeof(buf), ifp)) != 0)
+ if (fwrite(buf, 1, nr, ofp) != nr) {
+ cwarn("%s", out);
+ goto err;
+ }
+
+ if (ferror(ifp) || fclose(ifp)) {
+ cwarn("%s", in);
+ goto err;
+ }
+ ifp = NULL;
+
+ if (fclose(ofp)) {
+ cwarn("%s", out);
+ goto err;
+ }
+
+ if (!cat && isreg) {
+ setfile(out, &sb);
+
+ if (unlink(in))
+ cwarn("%s", in);
+ if (verbose) {
+ struct stat isb = sb;
+ stat(out, &sb);
+ (void)fprintf(stderr, "%s: ", out);
+ if (isb.st_size > sb.st_size)
+ (void)fprintf(stderr, "%.0f%% compression\n",
+ ((float)sb.st_size / isb.st_size) * 100.0);
+ else
+ (void)fprintf(stderr, "%.0f%% expansion\n",
+ ((float)isb.st_size / sb.st_size) * 100.0);
+ }
+ }
+ return;
+
+err: if (ofp) {
+ if (!cat && oreg)
+ (void)unlink(out);
+ (void)fclose(ofp);
+ }
+ if (ifp)
+ (void)fclose(ifp);
+}
+
+void
+setfile(const char *name, struct stat *fs)
+{
+ static struct timeval tv[2];
+
+ fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
+
+ TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
+ TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
+ if (utimes(name, tv))
+ cwarn("utimes: %s", name);
+
+ /*
+ * Changing the ownership probably won't succeed, unless we're root
+ * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
+ * the mode; current BSD behavior is to remove all setuid bits on
+ * chown. If chown fails, lose setuid/setgid bits.
+ */
+ if (chown(name, fs->st_uid, fs->st_gid)) {
+ if (errno != EPERM)
+ cwarn("chown: %s", name);
+ fs->st_mode &= ~(S_ISUID|S_ISGID);
+ }
+ if (chmod(name, fs->st_mode) && errno != ENOTSUP)
+ cwarn("chmod: %s", name);
+
+ if (chflags(name, fs->st_flags) && errno != ENOTSUP)
+ cwarn("chflags: %s", name);
+}
+
+int
+permission(const char *fname)
+{
+ int ch, first;
+ char resp[] = {'\0', '\0'};
+
+ if (!isatty(fileno(stderr)))
+ return (0);
+ (void)fprintf(stderr, "overwrite %s? ", fname);
+
+ /* Load user specified locale */
+ setlocale(LC_MESSAGES, "");
+
+ first = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+
+ /* only care about first character */
+ resp[0] = first;
+
+ return (rpmatch(resp) == 1);
+}
+
+void
+usage(int iscompress)
+{
+ if (iscompress)
+ (void)fprintf(stderr,
+ "usage: compress [-cfv] [-b bits] [file ...]\n");
+ else
+ (void)fprintf(stderr,
+ "usage: uncompress [-cfv] [file ...]\n");
+ exit(1);
+}
+
+void
+cwarnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+ eval = 1;
+}
+
+void
+cwarn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vwarn(fmt, ap);
+ va_end(ap);
+ eval = 1;
+}
diff --git a/file_cmds/compress/doc/NOTES b/file_cmds/compress/doc/NOTES
new file mode 100644
index 0000000..4ced689
--- /dev/null
+++ b/file_cmds/compress/doc/NOTES
@@ -0,0 +1,142 @@
+
+ $FreeBSD: src/usr.bin/compress/doc/NOTES,v 1.3 2011/10/16 14:30:28 eadler Exp $
+
+From: James A. Woods <jaw@eos.arc.nasa.gov>
+
+>From vn Fri Dec 2 18:05:27 1988
+Subject: Re: Looking for C source for RSA
+Newsgroups: sci.crypt
+
+# Illegitimi noncarborundum
+
+Patents are a tar pit.
+
+A good case can be made that most are just a license to sue, and nothing
+is illegal until a patent is upheld in court.
+
+For example, if you receive netnews by means other than 'nntp',
+these very words are being modulated by 'compress',
+a variation on the patented Lempel-Ziv-Welch algorithm.
+
+Original Ziv-Lempel is patent number 4,464,650, and the more powerful
+LZW method is #4,558,302. Yet despite any similarities between 'compress'
+and LZW (the public-domain 'compress' code was designed and given to the
+world before the ink on the Welch patent was dry), no attorneys from Sperry
+(the assignee) have asked you to unplug your Usenet connection.
+
+Why? I can't speak for them, but it is possible the claims are too broad,
+or, just as bad, not broad enough. ('compress' does things not mentioned
+in the Welch patent.) Maybe they realize that they can commercialize
+LZW better by selling hardware implementations rather than by licensing
+software. Again, the LZW software delineated in the patent is *not*
+the same as that of 'compress'.
+
+At any rate, court-tested software patents are a different animal;
+corporate patents in a portfolio are usually traded like baseball cards
+to shut out small fry rather than actually be defended before
+non-technical juries. Perhaps RSA will undergo this test successfully,
+although the grant to "exclude others from making, using, or selling"
+the invention would then only apply to the U.S. (witness the
+Genentech patent of the TPA molecule in the U.S. but struck down
+in Great Britain as too broad.)
+
+The concept is still exotic for those who learned in school the rule of thumb
+that one may patent "apparatus" but not an "idea".
+Apparently this all changed in Diamond v. Diehr (1981) when the U. S. Supreme
+Court reversed itself.
+
+Scholars should consult the excellent article in the Washington and Lee
+Law Review (fall 1984, vol. 41, no. 4) by Anthony and Colwell for a
+comprehensive survey of an area which will remain murky for some time.
+
+Until the dust clears, how you approach ideas which are patented depends
+on how paranoid you are of a legal onslaught. Arbitrary? Yes. But
+the patent bar the CCPA (Court of Customs and Patent Appeals)
+thanks you for any uncertainty as they, at least, stand to gain
+from any trouble.
+
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+From: James A. Woods <jaw@eos.arc.nasa.gov>
+Subject: Re: Looking for C source for RSA (actually 'compress' patents)
+
+ In article <2042@eos.UUCP> you write:
+ >The concept is still exotic for those who learned in school the rule of thumb
+ >that one may patent "apparatus" but not an "idea".
+
+A rule of thumb that has never been completely valid, as any chemical
+engineer can tell you. (Chemical processes were among the earliest patents,
+as I recall.)
+
+ ah yes -- i date myself when relaying out-of-date advice from elderly
+ attorneys who don't even specialize in patents. one other interesting
+ class of patents include the output of optical lens design programs,
+ which yield formulae which can then fairly directly can be molded
+ into glass. although there are restrictions on patenting equations,
+ the "embedded systems" seem to fly past the legal gauntlets.
+
+ anyway, I'm still learning about intellectual property law after
+ several conversations from a Unisys (nee sperry) lawyer re 'compress'.
+
+ it's more complicated than this, but they're letting (oral
+ communication only) software versions of 'compress' slide
+ as far as licensing fees go. this includes 'arc', 'stuffit',
+ and other commercial wrappers for 'compress'. yet they are
+ signing up licensees for hardware chips. Hewlett-Packard
+ supposedly has an active vlsi project, and Unisys has
+ board-level LZW-based tape controllers. (to build LZW into
+ a disk controller would be strange, as you'd have to build
+ in a filesystem too!)
+
+ it's byzantine
+ that Unisys is in a tiff with HP regarding the patents,
+ after discovering some sort of "compress" button on some
+ HP terminal product. why? well, professor Abraham Lempel jumped
+ from being department chairman of computer science at technion in
+ Israel to sperry (where he got the first patent), but then to work
+ at Hewlett-Packard on sabbatical. the second Welch patent
+ is only weakly derivative of the first, so they want chip
+ licenses and HP relented. however, everyone agrees something
+ like the current Unix implementation is the way to go with
+ software, so HP (and UCB) long ago asked spencer Thomas and i to sign
+ off on copyright permission (although they didn't need to, it being pd).
+ Lempel, HP, and Unisys grumbles they can't make money off the
+ software since a good free implementation (not the best --
+ i have more ideas!) escaped via Usenet. (Lempel's own pascal
+ code was apparently horribly slow.)
+ i don't follow the IBM 'arc' legal bickering; my impression
+ is that the pc folks are making money off the archiver/wrapper
+ look/feel of the thing [if ms-dos can be said to have a look and feel].
+
+ now where is telebit with the compress firmware? in a limbo
+ netherworld, probably, with sperry still welcoming outfits
+ to sign patent licenses, a common tactic to bring other small fry
+ into the fold. the guy who crammed 12-bit compress into the modem
+ there left. also what is transpiring with 'compress' and sys 5 rel 4?
+ beats me, but if sperry got a hold of them on these issues,
+ at&t would likely re-implement another algorithm if they
+ thought 'compress' infringes. needful to say, i don't think
+ it does after the above mentioned legal conversation.
+ my own beliefs on whether algorithms should be patentable at all
+ change with the weather. if the courts finally nail down
+ patent protection for algorithms, academic publication in
+ textbooks will be somewhat at odds with the engineering world,
+ where the textbook codes will simply be a big tease to get
+ money into the patent holder coffers...
+
+ oh, if you implement LZW from the patent, you won't get
+ good rates because it doesn't mention adaptive table reset,
+ lack thereof being *the* serious deficiency of Thomas' first version.
+
+ now i know that patent law generally protects against independent
+ re-invention (like the 'xor' hash function pleasantly mentioned
+ in the patent [but not the paper]).
+ but the upshot is that if anyone ever wanted to sue us,
+ we're partially covered with
+ independently-developed twists, plus the fact that some of us work
+ in a bureaucratic morass (as contractor to a public agency in my case).
+
+ quite a mess, huh? I've wanted to tell someone this stuff
+ for a long time, for posterity if nothing else.
+
+james
+
diff --git a/file_cmds/compress/doc/README b/file_cmds/compress/doc/README
new file mode 100644
index 0000000..0828cdf
--- /dev/null
+++ b/file_cmds/compress/doc/README
@@ -0,0 +1,284 @@
+
+ @(#)README 8.1 (Berkeley) 6/9/93
+ $FreeBSD: src/usr.bin/compress/doc/README,v 1.3 2002/12/30 21:18:11 schweikh Exp $
+
+Compress version 4.0 improvements over 3.0:
+ o compress() speedup (10-50%) by changing division hash to xor
+ o decompress() speedup (5-10%)
+ o Memory requirements reduced (3-30%)
+ o Stack requirements reduced to less than 4kb
+ o Removed 'Big+Fast' compress code (FBITS) because of compress speedup
+ o Portability mods for Z8000 and PC/XT (but not zeus 3.2)
+ o Default to 'quiet' mode
+ o Unification of 'force' flags
+ o Manual page overhaul
+ o Portability enhancement for M_XENIX
+ o Removed text on #else and #endif
+ o Added "-V" switch to print version and options
+ o Added #defines for SIGNED_COMPARE_SLOW
+ o Added Makefile and "usermem" program
+ o Removed all floating point computations
+ o New programs: [deleted]
+
+The "usermem" script attempts to determine the maximum process size. Some
+editing of the script may be necessary (see the comments). [It should work
+fine on 4.3 BSD.] If you can't get it to work at all, just create file
+"USERMEM" containing the maximum process size in decimal.
+
+The following preprocessor symbols control the compilation of "compress.c":
+
+ o USERMEM Maximum process memory on the system
+ o SACREDMEM Amount to reserve for other processes
+ o SIGNED_COMPARE_SLOW Unsigned compare instructions are faster
+ o NO_UCHAR Don't use "unsigned char" types
+ o BITS Overrules default set by USERMEM-SACREDMEM
+ o vax Generate inline assembler
+ o interdata Defines SIGNED_COMPARE_SLOW
+ o M_XENIX Makes arrays < 65536 bytes each
+ o pdp11 BITS=12, NO_UCHAR
+ o z8000 BITS=12
+ o pcxt BITS=12
+ o BSD4_2 Allow long filenames ( > 14 characters) &
+ Call setlinebuf(stderr)
+
+The difference "usermem-sacredmem" determines the maximum BITS that can be
+specified with the "-b" flag.
+
+memory: at least BITS
+------ -- ----- ----
+ 433,484 16
+ 229,600 15
+ 127,536 14
+ 73,464 13
+ 0 12
+
+The default is BITS=16.
+
+The maximum bits can be overruled by specifying "-DBITS=bits" at
+compilation time.
+
+WARNING: files compressed on a large machine with more bits than allowed by
+a version of compress on a smaller machine cannot be decompressed! Use the
+"-b12" flag to generate a file on a large machine that can be uncompressed
+on a 16-bit machine.
+
+The output of compress 4.0 is fully compatible with that of compress 3.0.
+In other words, the output of compress 4.0 may be fed into uncompress 3.0 or
+the output of compress 3.0 may be fed into uncompress 4.0.
+
+The output of compress 4.0 not compatible with that of
+compress 2.0. However, compress 4.0 still accepts the output of
+compress 2.0. To generate output that is compatible with compress
+2.0, use the undocumented "-C" flag.
+
+ -from mod.sources, submitted by vax135!petsd!joe (Joe Orost), 8/1/85
+--------------------------------
+
+Enclosed is compress version 3.0 with the following changes:
+
+1. "Block" compression is performed. After the BITS run out, the
+ compression ratio is checked every so often. If it is decreasing,
+ the table is cleared and a new set of substrings are generated.
+
+ This makes the output of compress 3.0 not compatible with that of
+ compress 2.0. However, compress 3.0 still accepts the output of
+ compress 2.0. To generate output that is compatible with compress
+ 2.0, use the undocumented "-C" flag.
+
+2. A quiet "-q" flag has been added for use by the news system.
+
+3. The character chaining has been deleted and the program now uses
+ hashing. This improves the speed of the program, especially
+ during decompression. Other speed improvements have been made,
+ such as using putc() instead of fwrite().
+
+4. A large table is used on large machines when a relatively small
+ number of bits is specified. This saves much time when compressing
+ for a 16-bit machine on a 32-bit virtual machine. Note that the
+ speed improvement only occurs when the input file is > 30000
+ characters, and the -b BITS is less than or equal to the cutoff
+ described below.
+
+Most of these changes were made by James A. Woods (ames!jaw). Thank you
+James!
+
+To compile compress:
+
+ cc -O -DUSERMEM=usermem -o compress compress.c
+
+Where "usermem" is the amount of physical user memory available (in bytes).
+If any physical memory is to be reserved for other processes, put in
+"-DSACREDMEM sacredmem", where "sacredmem" is the amount to be reserved.
+
+The difference "usermem-sacredmem" determines the maximum BITS that can be
+specified, and the cutoff bits where the large+fast table is used.
+
+memory: at least BITS cutoff
+------ -- ----- ---- ------
+ 4,718,592 16 13
+ 2,621,440 16 12
+ 1,572,864 16 11
+ 1,048,576 16 10
+ 631,808 16 --
+ 329,728 15 --
+ 178,176 14 --
+ 99,328 13 --
+ 0 12 --
+
+The default memory size is 750,000 which gives a maximum BITS=16 and no
+large+fast table.
+
+The maximum bits can be overruled by specifying "-DBITS=bits" at
+compilation time.
+
+If your machine doesn't support unsigned characters, define "NO_UCHAR"
+when compiling.
+
+If your machine has "int" as 16-bits, define "SHORT_INT" when compiling.
+
+After compilation, move "compress" to a standard executable location, such
+as /usr/local. Then:
+ cd /usr/local
+ ln compress uncompress
+ ln compress zcat
+
+On machines that have a fixed stack size (such as Perkin-Elmer), set the
+stack to at least 12kb. ("setstack compress 12" on Perkin-Elmer).
+
+Next, install the manual (compress.l).
+ cp compress.l /usr/man/manl
+ cd /usr/man/manl
+ ln compress.l uncompress.l
+ ln compress.l zcat.l
+
+ - or -
+
+ cp compress.l /usr/man/man1/compress.1
+ cd /usr/man/man1
+ ln compress.1 uncompress.1
+ ln compress.1 zcat.1
+
+ regards,
+ petsd!joe
+
+Here is a note from the net:
+
+>From hplabs!pesnta!amd!turtlevax!ken Sat Jan 5 03:35:20 1985
+Path: ames!hplabs!pesnta!amd!turtlevax!ken
+From: ken@turtlevax.UUCP (Ken Turkowski)
+Newsgroups: net.sources
+Subject: Re: Compress release 3.0 : sample Makefile
+Organization: CADLINC, Inc. @ Menlo Park, CA
+
+In the compress 3.0 source recently posted to mod.sources, there is a
+#define variable which can be set for optimum performance on a machine
+with a large amount of memory. A program (usermem) to calculate the
+usable amount of physical user memory is enclosed, as well as a sample
+4.2BSD Vax Makefile for compress.
+
+Here is the README file from the previous version of compress (2.0):
+
+>Enclosed is compress.c version 2.0 with the following bugs fixed:
+>
+>1. The packed files produced by compress are different on different
+> machines and dependent on the vax sysgen option.
+> The bug was in the different byte/bit ordering on the
+> various machines. This has been fixed.
+>
+> This version is NOT compatible with the original vax posting
+> unless the '-DCOMPATIBLE' option is specified to the C
+> compiler. The original posting has a bug which I fixed,
+> causing incompatible files. I recommend you NOT to use this
+> option unless you already have a lot of packed files from
+> the original posting by Thomas.
+>2. The exit status is not well defined (on some machines) causing the
+> scripts to fail.
+> The exit status is now 0,1 or 2 and is documented in
+> compress.l.
+>3. The function getopt() is not available in all C libraries.
+> The function getopt() is no longer referenced by the
+> program.
+>4. Error status is not being checked on the fwrite() and fflush() calls.
+> Fixed.
+>
+>The following enhancements have been made:
+>
+>1. Added facilities of "compact" into the compress program. "Pack",
+> "Unpack", and "Pcat" are no longer required (no longer supplied).
+>2. Installed work around for C compiler bug with "-O".
+>3. Added a magic number header (\037\235). Put the bits specified
+> in the file.
+>4. Added "-f" flag to force overwrite of output file.
+>5. Added "-c" flag and "zcat" program. 'ln compress zcat' after you
+> compile.
+>6. The 'uncompress' script has been deleted; simply
+> 'ln compress uncompress' after you compile and it will work.
+>7. Removed extra bit masking for machines that support unsigned
+> characters. If your machine doesn't support unsigned characters,
+> define "NO_UCHAR" when compiling.
+>
+>Compile "compress.c" with "-O -o compress" flags. Move "compress" to a
+>standard executable location, such as /usr/local. Then:
+> cd /usr/local
+> ln compress uncompress
+> ln compress zcat
+>
+>On machines that have a fixed stack size (such as Perkin-Elmer), set the
+>stack to at least 12kb. ("setstack compress 12" on Perkin-Elmer).
+>
+>Next, install the manual (compress.l).
+> cp compress.l /usr/man/manl - or -
+> cp compress.l /usr/man/man1/compress.1
+>
+>Here is the README that I sent with my first posting:
+>
+>>Enclosed is a modified version of compress.c, along with scripts to make it
+>>run identically to pack(1), unpack(1), and pcat(1). Here is what I
+>>(petsd!joe) and a colleague (petsd!peora!srd) did:
+>>
+>>1. Removed VAX dependencies.
+>>2. Changed the struct to separate arrays; saves mucho memory.
+>>3. Did comparisons in unsigned, where possible. (Faster on Perkin-Elmer.)
+>>4. Sorted the character next chain and changed the search to stop
+>>prematurely. This saves a lot on the execution time when compressing.
+>>
+>>This version is totally compatible with the original version. Even though
+>>lint(1) -p has no complaints about compress.c, it won't run on a 16-bit
+>>machine, due to the size of the arrays.
+>>
+>>Here is the README file from the original author:
+>>
+>>>Well, with all this discussion about file compression (for news batching
+>>>in particular) going around, I decided to implement the text compression
+>>>algorithm described in the June Computer magazine. The author claimed
+>>>blinding speed and good compression ratios. It's certainly faster than
+>>>compact (but, then, what wouldn't be), but it's also the same speed as
+>>>pack, and gets better compression than both of them. On 350K bytes of
+>>>Unix-wizards, compact took about 8 minutes of CPU, pack took about 80
+>>>seconds, and compress (herein) also took 80 seconds. But, compact and
+>>>pack got about 30% compression, whereas compress got over 50%. So, I
+>>>decided I had something, and that others might be interested, too.
+>>>
+>>>As is probably true of compact and pack (although I haven't checked),
+>>>the byte order within a word is probably relevant here, but as long as
+>>>you stay on a single machine type, you should be ok. (Can anybody
+>>>elucidate on this?) There are a couple of asm's in the code (extv and
+>>>insv instructions), so anyone porting it to another machine will have to
+>>>deal with this anyway (and could probably make it compatible with Vax
+>>>byte order at the same time). Anyway, I've linted the code (both with
+>>>and without -p), so it should run elsewhere. Note the longs in the
+>>>code, you can take these out if you reduce BITS to <= 15.
+>>>
+>>>Have fun, and as always, if you make good enhancements, or bug fixes,
+>>>I'd like to see them.
+>>>
+>>>=Spencer (thomas@utah-20, {harpo,hplabs,arizona}!utah-cs!thomas)
+>>
+>> regards,
+>> joe
+>>
+>>--
+>>Full-Name: Joseph M. Orost
+>>UUCP: ..!{decvax,ucbvax,ihnp4}!vax135!petsd!joe
+>>US Mail: MS 313; Perkin-Elmer; 106 Apple St; Tinton Falls, NJ 07724
+>>Phone: (201) 870-5844
diff --git a/file_cmds/compress/doc/revision.log b/file_cmds/compress/doc/revision.log
new file mode 100644
index 0000000..04c96e6
--- /dev/null
+++ b/file_cmds/compress/doc/revision.log
@@ -0,0 +1,118 @@
+/* $FreeBSD: src/usr.bin/compress/doc/revision.log,v 1.5 2011/03/31 14:35:33 emaste Exp $ */
+
+/*
+ * $Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $
+ *
+ * Revision 4.0 85/07/30 12:50:00 joe
+ * Removed ferror() calls in output routine on every output except first.
+ * Prepared for release to the world.
+ *
+ * Revision 3.6 85/07/04 01:22:21 joe
+ * Remove much wasted storage by overlaying hash table with the tables
+ * used by decompress: tab_suffix[1<<BITS], stack[8000]. Updated USERMEM
+ * computations. Fixed dump_tab() DEBUG routine.
+ *
+ * Revision 3.5 85/06/30 20:47:21 jaw
+ * Change hash function to use exclusive-or. Rip out hash cache. These
+ * speedups render the megamemory version defunct, for now. Make decoder
+ * stack global. Parts of the RCS trunks 2.7, 2.6, and 2.1 no longer apply.
+ *
+ * Revision 3.4 85/06/27 12:00:00 ken
+ * Get rid of all floating-point calculations by doing all compression ratio
+ * calculations in fixed point.
+ *
+ * Revision 3.3 85/06/24 21:53:24 joe
+ * Incorporate portability suggestion for M_XENIX. Got rid of text on #else
+ * and #endif lines. Cleaned up #ifdefs for vax and interdata.
+ *
+ * Revision 3.2 85/06/06 21:53:24 jaw
+ * Incorporate portability suggestions for Z8000, IBM PC/XT from mailing list.
+ * Default to "quiet" output (no compression statistics).
+ *
+ * Revision 3.1 85/05/12 18:56:13 jaw
+ * Integrate decompress() stack speedups (from early pointer mods by McKie).
+ * Repair multi-file USERMEM gaffe. Unify 'force' flags to mimic semantics
+ * of SVR2 'pack'. Streamline block-compress table clear logic. Increase
+ * output byte count by magic number size.
+ *
+ * Revision 3.0 84/11/27 11:50:00 petsd!joe
+ * Set HSIZE depending on BITS. Set BITS depending on USERMEM. Unrolled
+ * loops in clear routines. Added "-C" flag for 2.0 compatibility. Used
+ * unsigned compares on Perkin-Elmer. Fixed foreground check.
+ *
+ * Revision 2.7 84/11/16 19:35:39 ames!jaw
+ * Cache common hash codes based on input statistics; this improves
+ * performance for low-density raster images. Pass on #ifdef bundle
+ * from Turkowski.
+ *
+ * Revision 2.6 84/11/05 19:18:21 ames!jaw
+ * Vary size of hash tables to reduce time for small files.
+ * Tune PDP-11 hash function.
+ *
+ * Revision 2.5 84/10/30 20:15:14 ames!jaw
+ * Junk chaining; replace with the simpler (and, on the VAX, faster)
+ * double hashing, discussed within. Make block compression standard.
+ *
+ * Revision 2.4 84/10/16 11:11:11 ames!jaw
+ * Introduce adaptive reset for block compression, to boost the rate
+ * another several percent. (See mailing list notes.)
+ *
+ * Revision 2.3 84/09/22 22:00:00 petsd!joe
+ * Implemented "-B" block compress. Implemented REVERSE sorting of tab_next.
+ * Bug fix for last bits. Changed fwrite to putchar loop everywhere.
+ *
+ * Revision 2.2 84/09/18 14:12:21 ames!jaw
+ * Fold in news changes, small machine typedef from thomas,
+ * #ifdef interdata from joe.
+ *
+ * Revision 2.1 84/09/10 12:34:56 ames!jaw
+ * Configured fast table lookup for 32-bit machines.
+ * This cuts user time in half for b <= FBITS, and is useful for news batching
+ * from VAX to PDP sites. Also sped up decompress() [fwrite->putc] and
+ * added signal catcher [plus beef in writeerr()] to delete effluvia.
+ *
+ * Revision 2.0 84/08/28 22:00:00 petsd!joe
+ * Add check for foreground before prompting user. Insert maxbits into
+ * compressed file. Force file being uncompressed to end with ".Z".
+ * Added "-c" flag and "zcat". Prepared for release.
+ *
+ * Revision 1.10 84/08/24 18:28:00 turtlevax!ken
+ * Will only compress regular files (no directories), added a magic number
+ * header (plus an undocumented -n flag to handle old files without headers),
+ * added -f flag to force overwriting of possibly existing destination file,
+ * otherwise the user is prompted for a response. Will tack on a .Z to a
+ * filename if it doesn't have one when decompressing. Will only replace
+ * file if it was compressed.
+ *
+ * Revision 1.9 84/08/16 17:28:00 turtlevax!ken
+ * Removed scanargs(), getopt(), added .Z extension and unlimited number of
+ * filenames to compress. Flags may be clustered (-Ddvb12) or separated
+ * (-D -d -v -b 12), or combination thereof. Modes and other status is
+ * copied with copystat(). -O bug for 4.2 seems to have disappeared with
+ * 1.8.
+ *
+ * Revision 1.8 84/08/09 23:15:00 joe
+ * Made it compatible with vax version, installed jim's fixes/enhancements
+ *
+ * Revision 1.6 84/08/01 22:08:00 joe
+ * Sped up algorithm significantly by sorting the compress chain.
+ *
+ * Revision 1.5 84/07/13 13:11:00 srd
+ * Added C version of vax asm routines. Changed structure to arrays to
+ * save much memory. Do unsigned compares where possible (faster on
+ * Perkin-Elmer)
+ *
+ * Revision 1.4 84/07/05 03:11:11 thomas
+ * Clean up the code a little and lint it. (Lint complains about all
+ * the regs used in the asm, but I'm not going to "fix" this.)
+ *
+ * Revision 1.3 84/07/05 02:06:54 thomas
+ * Minor fixes.
+ *
+ * Revision 1.2 84/07/05 00:27:27 thomas
+ * Add variable bit length output.
+ *
+ */
+
+static char rcs_ident[] =
+ "$Header: compress.c,v 4.0 85/07/30 12:50:00 joe Release $";
diff --git a/file_cmds/compress/uncompress.1 b/file_cmds/compress/uncompress.1
new file mode 100644
index 0000000..208c3ce
--- /dev/null
+++ b/file_cmds/compress/uncompress.1
@@ -0,0 +1 @@
+.so man1/compress.1 \ No newline at end of file
diff --git a/file_cmds/compress/zcat.sh b/file_cmds/compress/zcat.sh
new file mode 100644
index 0000000..6799f46
--- /dev/null
+++ b/file_cmds/compress/zcat.sh
@@ -0,0 +1,38 @@
+#!/bin/sh -
+# $NetBSD: zcat.sh,v 1.4 1995/03/26 19:54:37 glass Exp $
+#
+# Copyright (c) 1992, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)zcat.sh 8.1 (Berkeley) 6/6/93
+#
+
+uncompress -c $*
diff --git a/file_cmds/compress/zopen.3 b/file_cmds/compress/zopen.3
new file mode 100644
index 0000000..f6c7f34
--- /dev/null
+++ b/file_cmds/compress/zopen.3
@@ -0,0 +1,137 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)zopen.3 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD: src/usr.bin/compress/zopen.3,v 1.9 2010/12/11 08:32:16 joel Exp $
+.\"
+.Dd June 9, 1993
+.Dt ZOPEN 3
+.Os
+.Sh NAME
+.Nm zopen
+.Nd compressed stream open function
+.Sh SYNOPSIS
+.Fd #include \&"zopen.h\&"
+.Ft FILE *
+.Fn zopen "const char *path" "const char *mode" "int bits"
+.Sh DESCRIPTION
+The
+.Fn zopen
+function
+opens the compressed file whose name is the string pointed to by
+.Fa path
+and associates a stream with it.
+.Pp
+The argument
+.Fa mode
+points to one of the following one-character strings:
+.Bl -tag -width indent
+.It Dq Li r
+Open compressed file for reading.
+The stream is positioned at the beginning of the file.
+.It Dq Li w
+Truncate file to zero length or create compressed file for writing.
+The stream is positioned at the beginning of the file.
+.El
+.Pp
+Any created files will have mode
+.Pf \\*q Dv S_IRUSR
+\&|
+.Dv S_IWUSR
+\&|
+.Dv S_IRGRP
+\&|
+.Dv S_IWGRP
+\&|
+.Dv S_IROTH
+\&|
+.Dv S_IWOTH Ns \\*q
+.Pq Li 0666 ,
+as modified by the process'
+umask value (see
+.Xr umask 2 ) .
+.Pp
+Files may only be read or written.
+Seek operations are not allowed.
+.Pp
+The
+.Fa bits
+argument, if non-zero, is set to the bits code limit.
+If zero, the default is 16.
+See
+.Xr compress 1
+for more information.
+.Sh RETURN VALUES
+Upon successful completion
+.Fn zopen
+returns a
+.Tn FILE
+pointer.
+Otherwise,
+.Dv NULL
+is returned and the global variable
+.Va errno
+is set to indicate the error.
+.Sh ERRORS
+.Bl -tag -width [EINVAL]
+.It Bq Er EINVAL
+The
+.Fa mode
+or
+.Fa bits
+arguments specified to
+.Fn zopen
+were invalid.
+.It Bq Er EFTYPE
+The compressed file starts with an invalid header, or the compressed
+file is compressed with more bits than can be handled.
+.El
+.Pp
+The
+.Fn zopen
+function may also fail and set
+.Va errno
+for any of the errors specified for the routines
+.Xr fopen 3
+or
+.Xr funopen 3 .
+.Sh SEE ALSO
+.Xr compress 1 ,
+.Xr fopen 3 ,
+.Xr funopen 3
+.Sh HISTORY
+The
+.Nm
+function
+first appeared in
+.Bx 4.4 .
+.Sh BUGS
+The
+.Fn zopen
+function
+may not be portable to systems other than
+.Bx .
diff --git a/file_cmds/compress/zopen.c b/file_cmds/compress/zopen.c
new file mode 100644
index 0000000..589ce52
--- /dev/null
+++ b/file_cmds/compress/zopen.c
@@ -0,0 +1,738 @@
+/*-
+ * Copyright (c) 1985, 1986, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis and James A. Woods, derived from original
+ * work by Spencer Thomas and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)zopen.c 8.1 (Berkeley) 6/27/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/compress/zopen.c,v 1.17 2011/09/28 08:47:17 bz Exp $");
+
+/*-
+ * fcompress.c - File compression ala IEEE Computer, June 1984.
+ *
+ * Compress authors:
+ * Spencer W. Thomas (decvax!utah-cs!thomas)
+ * Jim McKie (decvax!mcvax!jim)
+ * Steve Davies (decvax!vax135!petsd!peora!srd)
+ * Ken Turkowski (decvax!decwrl!turtlevax!ken)
+ * James A. Woods (decvax!ihnp4!ames!jaw)
+ * Joe Orost (decvax!vax135!petsd!joe)
+ *
+ * Cleaned up and converted to library returning I/O streams by
+ * Diomidis Spinellis <dds@doc.ic.ac.uk>.
+ *
+ * zopen(filename, mode, bits)
+ * Returns a FILE * that can be used for read or write. The modes
+ * supported are only "r" and "w". Seeking is not allowed. On
+ * reading the file is decompressed, on writing it is compressed.
+ * The output is compatible with compress(1) with 16 bit tables.
+ * Any file produced by compress(1) can be read.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "zopen.h"
+
+#define BITS 16 /* Default bits. */
+#define HSIZE 69001 /* 95% occupancy */
+
+/* A code_int must be able to hold 2**BITS values of type int, and also -1. */
+typedef long code_int;
+typedef long count_int;
+
+typedef u_char char_type;
+static char_type magic_header[] =
+ {'\037', '\235'}; /* 1F 9D */
+
+#define BIT_MASK 0x1f /* Defines for third byte of header. */
+#define BLOCK_MASK 0x80
+
+/*
+ * Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
+ * a fourth header byte (for expansion).
+ */
+#define INIT_BITS 9 /* Initial number of bits/code. */
+
+#define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
+
+struct s_zstate {
+ FILE *zs_fp; /* File stream for I/O */
+ char zs_mode; /* r or w */
+ enum {
+ S_START, S_MIDDLE, S_EOF
+ } zs_state; /* State of computation */
+ u_int zs_n_bits; /* Number of bits/code. */
+ u_int zs_maxbits; /* User settable max # bits/code. */
+ code_int zs_maxcode; /* Maximum code, given n_bits. */
+ code_int zs_maxmaxcode; /* Should NEVER generate this code. */
+ count_int zs_htab [HSIZE];
+ u_short zs_codetab [HSIZE];
+ code_int zs_hsize; /* For dynamic table sizing. */
+ code_int zs_free_ent; /* First unused entry. */
+ /*
+ * Block compression parameters -- after all codes are used up,
+ * and compression rate changes, start over.
+ */
+ int zs_block_compress;
+ int zs_clear_flg;
+ long zs_ratio;
+ count_int zs_checkpoint;
+ u_int zs_offset;
+ long zs_in_count; /* Length of input. */
+ long zs_bytes_out; /* Length of compressed output. */
+ long zs_out_count; /* # of codes output (for debugging). */
+ char_type zs_buf[BITS];
+ union {
+ struct {
+ long zs_fcode;
+ code_int zs_ent;
+ code_int zs_hsize_reg;
+ int zs_hshift;
+ } w; /* Write parameters */
+ struct {
+ char_type *zs_stackp;
+ int zs_finchar;
+ code_int zs_code, zs_oldcode, zs_incode;
+ int zs_roffset, zs_size;
+ char_type zs_gbuf[BITS];
+ } r; /* Read parameters */
+ } u;
+};
+
+/* Definitions to retain old variable names */
+#define fp zs->zs_fp
+#define zmode zs->zs_mode
+#define state zs->zs_state
+#define n_bits zs->zs_n_bits
+#define maxbits zs->zs_maxbits
+#define maxcode zs->zs_maxcode
+#define maxmaxcode zs->zs_maxmaxcode
+#define htab zs->zs_htab
+#define codetab zs->zs_codetab
+#define hsize zs->zs_hsize
+#define free_ent zs->zs_free_ent
+#define block_compress zs->zs_block_compress
+#define clear_flg zs->zs_clear_flg
+#define ratio zs->zs_ratio
+#define checkpoint zs->zs_checkpoint
+#define offset zs->zs_offset
+#define in_count zs->zs_in_count
+#define bytes_out zs->zs_bytes_out
+#define out_count zs->zs_out_count
+#define buf zs->zs_buf
+#define fcode zs->u.w.zs_fcode
+#define hsize_reg zs->u.w.zs_hsize_reg
+#define ent zs->u.w.zs_ent
+#define hshift zs->u.w.zs_hshift
+#define stackp zs->u.r.zs_stackp
+#define finchar zs->u.r.zs_finchar
+#define code zs->u.r.zs_code
+#define oldcode zs->u.r.zs_oldcode
+#define incode zs->u.r.zs_incode
+#define roffset zs->u.r.zs_roffset
+#define size zs->u.r.zs_size
+#define gbuf zs->u.r.zs_gbuf
+
+/*
+ * To save much memory, we overlay the table used by compress() with those
+ * used by decompress(). The tab_prefix table is the same size and type as
+ * the codetab. The tab_suffix table needs 2**BITS characters. We get this
+ * from the beginning of htab. The output stack uses the rest of htab, and
+ * contains characters. There is plenty of room for any possible stack
+ * (stack used to be 8000 characters).
+ */
+
+#define htabof(i) htab[i]
+#define codetabof(i) codetab[i]
+
+#define tab_prefixof(i) codetabof(i)
+#define tab_suffixof(i) ((char_type *)(htab))[i]
+#define de_stack ((char_type *)&tab_suffixof(1 << BITS))
+
+#define CHECK_GAP 10000 /* Ratio check interval. */
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define FIRST 257 /* First free entry. */
+#define CLEAR 256 /* Table clear output code. */
+
+static int cl_block(struct s_zstate *);
+static void cl_hash(struct s_zstate *, count_int);
+static code_int getcode(struct s_zstate *);
+static int output(struct s_zstate *, code_int);
+static int zclose(void *);
+static int zread(void *, char *, int);
+static int zwrite(void *, const char *, int);
+
+/*-
+ * Algorithm from "A Technique for High Performance Data Compression",
+ * Terry A. Welch, IEEE Computer Vol 17, No 6 (June 1984), pp 8-19.
+ *
+ * Algorithm:
+ * Modified Lempel-Ziv method (LZW). Basically finds common
+ * substrings and replaces them with a variable size code. This is
+ * deterministic, and can be done on the fly. Thus, the decompression
+ * procedure needs no input table, but tracks the way the table was built.
+ */
+
+/*-
+ * compress write
+ *
+ * Algorithm: use open addressing double hashing (no chaining) on the
+ * prefix code / next character combination. We do a variant of Knuth's
+ * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
+ * secondary probe. Here, the modular division first probe is gives way
+ * to a faster exclusive-or manipulation. Also do block compression with
+ * an adaptive reset, whereby the code table is cleared when the compression
+ * ratio decreases, but after the table fills. The variable-length output
+ * codes are re-sized at this point, and a special CLEAR code is generated
+ * for the decompressor. Late addition: construct the table according to
+ * file size for noticeable speed improvement on small files. Please direct
+ * questions about this implementation to ames!jaw.
+ */
+static int
+zwrite(void *cookie, const char *wbp, int num)
+{
+ code_int i;
+ int c, disp;
+ struct s_zstate *zs;
+ const u_char *bp;
+ u_char tmp;
+ int count;
+
+ if (num == 0)
+ return (0);
+
+ zs = cookie;
+ count = num;
+ bp = (const u_char *)wbp;
+ if (state == S_MIDDLE)
+ goto middle;
+ state = S_MIDDLE;
+
+ maxmaxcode = 1L << maxbits;
+ if (fwrite(magic_header,
+ sizeof(char), sizeof(magic_header), fp) != sizeof(magic_header))
+ return (-1);
+ tmp = (u_char)((maxbits) | block_compress);
+ if (fwrite(&tmp, sizeof(char), sizeof(tmp), fp) != sizeof(tmp))
+ return (-1);
+
+ offset = 0;
+ bytes_out = 3; /* Includes 3-byte header mojo. */
+ out_count = 0;
+ clear_flg = 0;
+ ratio = 0;
+ in_count = 1;
+ checkpoint = CHECK_GAP;
+ maxcode = MAXCODE(n_bits = INIT_BITS);
+ free_ent = ((block_compress) ? FIRST : 256);
+
+ ent = *bp++;
+ --count;
+
+ hshift = 0;
+ for (fcode = (long)hsize; fcode < 65536L; fcode *= 2L)
+ hshift++;
+ hshift = 8 - hshift; /* Set hash code range bound. */
+
+ hsize_reg = hsize;
+ cl_hash(zs, (count_int)hsize_reg); /* Clear hash table. */
+
+middle: for (; count--;) {
+ c = *bp++;
+ in_count++;
+ fcode = (long)(((long)c << maxbits) + ent);
+ i = ((c << hshift) ^ ent); /* Xor hashing. */
+
+ if (htabof(i) == fcode) {
+ ent = codetabof(i);
+ continue;
+ } else if ((long)htabof(i) < 0) /* Empty slot. */
+ goto nomatch;
+ disp = hsize_reg - i; /* Secondary hash (after G. Knott). */
+ if (i == 0)
+ disp = 1;
+probe: if ((i -= disp) < 0)
+ i += hsize_reg;
+
+ if (htabof(i) == fcode) {
+ ent = codetabof(i);
+ continue;
+ }
+ if ((long)htabof(i) >= 0)
+ goto probe;
+nomatch: if (output(zs, (code_int) ent) == -1)
+ return (-1);
+ out_count++;
+ ent = c;
+ if (free_ent < maxmaxcode) {
+ codetabof(i) = free_ent++; /* code -> hashtable */
+ htabof(i) = fcode;
+ } else if ((count_int)in_count >=
+ checkpoint && block_compress) {
+ if (cl_block(zs) == -1)
+ return (-1);
+ }
+ }
+ return (num);
+}
+
+static int
+zclose(void *cookie)
+{
+ struct s_zstate *zs;
+ int rval;
+
+ zs = cookie;
+ if (zmode == 'w') { /* Put out the final code. */
+ if (output(zs, (code_int) ent) == -1) {
+ (void)fclose(fp);
+ free(zs);
+ return (-1);
+ }
+ out_count++;
+ if (output(zs, (code_int) - 1) == -1) {
+ (void)fclose(fp);
+ free(zs);
+ return (-1);
+ }
+ }
+ rval = fclose(fp) == EOF ? -1 : 0;
+ free(zs);
+ return (rval);
+}
+
+/*-
+ * Output the given code.
+ * Inputs:
+ * code: A n_bits-bit integer. If == -1, then EOF. This assumes
+ * that n_bits =< (long)wordsize - 1.
+ * Outputs:
+ * Outputs code to the file.
+ * Assumptions:
+ * Chars are 8 bits long.
+ * Algorithm:
+ * Maintain a BITS character long buffer (so that 8 codes will
+ * fit in it exactly). Use the VAX insv instruction to insert each
+ * code in turn. When the buffer fills up empty it and start over.
+ */
+
+static char_type lmask[9] =
+ {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00};
+static char_type rmask[9] =
+ {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
+
+static int
+output(struct s_zstate *zs, code_int ocode)
+{
+ int r_off;
+ u_int bits;
+ char_type *bp;
+
+ r_off = offset;
+ bits = n_bits;
+ bp = buf;
+ if (ocode >= 0) {
+ /* Get to the first byte. */
+ bp += (r_off >> 3);
+ r_off &= 7;
+ /*
+ * Since ocode is always >= 8 bits, only need to mask the first
+ * hunk on the left.
+ */
+ *bp = (*bp & rmask[r_off]) | ((ocode << r_off) & lmask[r_off]);
+ bp++;
+ bits -= (8 - r_off);
+ ocode >>= 8 - r_off;
+ /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
+ if (bits >= 8) {
+ *bp++ = ocode;
+ ocode >>= 8;
+ bits -= 8;
+ }
+ /* Last bits. */
+ if (bits)
+ *bp = ocode;
+ offset += n_bits;
+ if (offset == (n_bits << 3)) {
+ bp = buf;
+ bits = n_bits;
+ bytes_out += bits;
+ if (fwrite(bp, sizeof(char), bits, fp) != bits)
+ return (-1);
+// bp += bits;
+// bits = 0;
+ offset = 0;
+ }
+ /*
+ * If the next entry is going to be too big for the ocode size,
+ * then increase it, if possible.
+ */
+ if (free_ent > maxcode || (clear_flg > 0)) {
+ /*
+ * Write the whole buffer, because the input side won't
+ * discover the size increase until after it has read it.
+ */
+ if (offset > 0) {
+ if (fwrite(buf, 1, n_bits, fp) != n_bits)
+ return (-1);
+ bytes_out += n_bits;
+ }
+ offset = 0;
+
+ if (clear_flg) {
+ maxcode = MAXCODE(n_bits = INIT_BITS);
+ clear_flg = 0;
+ } else {
+ n_bits++;
+ if (n_bits == maxbits)
+ maxcode = maxmaxcode;
+ else
+ maxcode = MAXCODE(n_bits);
+ }
+ }
+ } else {
+ /* At EOF, write the rest of the buffer. */
+ if (offset > 0) {
+ offset = (offset + 7) / 8;
+ if (fwrite(buf, 1, offset, fp) != offset)
+ return (-1);
+ bytes_out += offset;
+ }
+ offset = 0;
+ }
+ return (0);
+}
+
+/*
+ * Decompress read. This routine adapts to the codes in the file building
+ * the "string" table on-the-fly; requiring no table to be stored in the
+ * compressed file. The tables used herein are shared with those of the
+ * compress() routine. See the definitions above.
+ */
+static int
+zread(void *cookie, char *rbp, int num)
+{
+ u_int count;
+ struct s_zstate *zs;
+ u_char *bp, header[3];
+
+ if (num == 0)
+ return (0);
+
+ zs = cookie;
+ count = num;
+ bp = (u_char *)rbp;
+ switch (state) {
+ case S_START:
+ state = S_MIDDLE;
+ break;
+ case S_MIDDLE:
+ goto middle;
+ case S_EOF:
+ goto eof;
+ }
+
+ /* Check the magic number */
+ if (fread(header,
+ sizeof(char), sizeof(header), fp) != sizeof(header) ||
+ memcmp(header, magic_header, sizeof(magic_header)) != 0) {
+ errno = EFTYPE;
+ return (-1);
+ }
+ maxbits = header[2]; /* Set -b from file. */
+ block_compress = maxbits & BLOCK_MASK;
+ maxbits &= BIT_MASK;
+ maxmaxcode = 1L << maxbits;
+ if (maxbits > BITS || maxbits < 12) {
+ errno = EFTYPE;
+ return (-1);
+ }
+ /* As above, initialize the first 256 entries in the table. */
+ maxcode = MAXCODE(n_bits = INIT_BITS);
+ for (code = 255; code >= 0; code--) {
+ tab_prefixof(code) = 0;
+ tab_suffixof(code) = (char_type) code;
+ }
+ free_ent = block_compress ? FIRST : 256;
+
+ finchar = oldcode = getcode(zs);
+ if (oldcode == -1) /* EOF already? */
+ return (0); /* Get out of here */
+
+ /* First code must be 8 bits = char. */
+ *bp++ = (u_char)finchar;
+ count--;
+ stackp = de_stack;
+
+ while ((code = getcode(zs)) > -1) {
+
+ if ((code == CLEAR) && block_compress) {
+ for (code = 255; code >= 0; code--)
+ tab_prefixof(code) = 0;
+ clear_flg = 1;
+ free_ent = FIRST;
+ oldcode = -1;
+ continue;
+ }
+ incode = code;
+
+ /* Special case for kWkWk string. */
+ if (code >= free_ent) {
+ if (code > free_ent || oldcode == -1) {
+ /* Bad stream. */
+ errno = EINVAL;
+ return (-1);
+ }
+ *stackp++ = finchar;
+ code = oldcode;
+ }
+ /*
+ * The above condition ensures that code < free_ent.
+ * The construction of tab_prefixof in turn guarantees that
+ * each iteration decreases code and therefore stack usage is
+ * bound by 1 << BITS - 256.
+ */
+
+ /* Generate output characters in reverse order. */
+ while (code >= 256) {
+ *stackp++ = tab_suffixof(code);
+ code = tab_prefixof(code);
+ }
+ *stackp++ = finchar = tab_suffixof(code);
+
+ /* And put them out in forward order. */
+middle: do {
+ if (count-- == 0)
+ return (num);
+ *bp++ = *--stackp;
+ } while (stackp > de_stack);
+
+ /* Generate the new entry. */
+ if ((code = free_ent) < maxmaxcode && oldcode != -1) {
+ tab_prefixof(code) = (u_short) oldcode;
+ tab_suffixof(code) = finchar;
+ free_ent = code + 1;
+ }
+
+ /* Remember previous code. */
+ oldcode = incode;
+ }
+ state = S_EOF;
+eof: return (num - count);
+}
+
+/*-
+ * Read one code from the standard input. If EOF, return -1.
+ * Inputs:
+ * stdin
+ * Outputs:
+ * code or -1 is returned.
+ */
+static code_int
+getcode(struct s_zstate *zs)
+{
+ code_int gcode;
+ int r_off, bits;
+ char_type *bp;
+
+ bp = gbuf;
+ if (clear_flg > 0 || roffset >= size || free_ent > maxcode) {
+ /*
+ * If the next entry will be too big for the current gcode
+ * size, then we must increase the size. This implies reading
+ * a new buffer full, too.
+ */
+ if (free_ent > maxcode) {
+ n_bits++;
+ if (n_bits == maxbits) /* Won't get any bigger now. */
+ maxcode = maxmaxcode;
+ else
+ maxcode = MAXCODE(n_bits);
+ }
+ if (clear_flg > 0) {
+ maxcode = MAXCODE(n_bits = INIT_BITS);
+ clear_flg = 0;
+ }
+ size = fread(gbuf, 1, n_bits, fp);
+ if (size <= 0) /* End of file. */
+ return (-1);
+ roffset = 0;
+ /* Round size down to integral number of codes. */
+ size = (size << 3) - (n_bits - 1);
+ }
+ r_off = roffset;
+ bits = n_bits;
+
+ /* Get to the first byte. */
+ bp += (r_off >> 3);
+ r_off &= 7;
+
+ /* Get first part (low order bits). */
+ gcode = (*bp++ >> r_off);
+ bits -= (8 - r_off);
+ r_off = 8 - r_off; /* Now, roffset into gcode word. */
+
+ /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
+ if (bits >= 8) {
+ gcode |= *bp++ << r_off;
+ r_off += 8;
+ bits -= 8;
+ }
+
+ /* High order bits. */
+ gcode |= (*bp & rmask[bits]) << r_off;
+ roffset += n_bits;
+
+ return (gcode);
+}
+
+static int
+cl_block(struct s_zstate *zs) /* Table clear for block compress. */
+{
+ long rat;
+
+ checkpoint = in_count + CHECK_GAP;
+
+ if (in_count > 0x007fffff) { /* Shift will overflow. */
+ rat = bytes_out >> 8;
+ if (rat == 0) /* Don't divide by zero. */
+ rat = 0x7fffffff;
+ else
+ rat = in_count / rat;
+ } else
+ rat = (in_count << 8) / bytes_out; /* 8 fractional bits. */
+ if (rat > ratio)
+ ratio = rat;
+ else {
+ ratio = 0;
+ cl_hash(zs, (count_int) hsize);
+ free_ent = FIRST;
+ clear_flg = 1;
+ if (output(zs, (code_int) CLEAR) == -1)
+ return (-1);
+ }
+ return (0);
+}
+
+static void
+cl_hash(struct s_zstate *zs, count_int cl_hsize) /* Reset code table. */
+{
+ count_int *htab_p;
+ long i, m1;
+
+ m1 = -1;
+ htab_p = htab + cl_hsize;
+ i = cl_hsize - 16;
+ do { /* Might use Sys V memset(3) here. */
+ *(htab_p - 16) = m1;
+ *(htab_p - 15) = m1;
+ *(htab_p - 14) = m1;
+ *(htab_p - 13) = m1;
+ *(htab_p - 12) = m1;
+ *(htab_p - 11) = m1;
+ *(htab_p - 10) = m1;
+ *(htab_p - 9) = m1;
+ *(htab_p - 8) = m1;
+ *(htab_p - 7) = m1;
+ *(htab_p - 6) = m1;
+ *(htab_p - 5) = m1;
+ *(htab_p - 4) = m1;
+ *(htab_p - 3) = m1;
+ *(htab_p - 2) = m1;
+ *(htab_p - 1) = m1;
+ htab_p -= 16;
+ } while ((i -= 16) >= 0);
+ for (i += 16; i > 0; i--)
+ *--htab_p = m1;
+}
+
+FILE *
+zopen(const char *fname, const char *mode, int bits)
+{
+ struct s_zstate *zs;
+
+ if ((mode[0] != 'r' && mode[0] != 'w') || mode[1] != '\0' ||
+ bits < 0 || bits > BITS) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((zs = calloc(1, sizeof(struct s_zstate))) == NULL)
+ return (NULL);
+
+ maxbits = bits ? bits : BITS; /* User settable max # bits/code. */
+ maxmaxcode = 1L << maxbits; /* Should NEVER generate this code. */
+ hsize = HSIZE; /* For dynamic table sizing. */
+ free_ent = 0; /* First unused entry. */
+ block_compress = BLOCK_MASK;
+ clear_flg = 0;
+ ratio = 0;
+ checkpoint = CHECK_GAP;
+ in_count = 1; /* Length of input. */
+ out_count = 0; /* # of codes output (for debugging). */
+ state = S_START;
+ roffset = 0;
+ size = 0;
+
+ /*
+ * Layering compress on top of stdio in order to provide buffering,
+ * and ensure that reads and write work with the data specified.
+ */
+ if ((fp = fopen(fname, mode)) == NULL) {
+ free(zs);
+ return (NULL);
+ }
+ switch (*mode) {
+ case 'r':
+ zmode = 'r';
+ return (funopen(zs, zread, NULL, NULL, zclose));
+ case 'w':
+ zmode = 'w';
+ return (funopen(zs, NULL, zwrite, NULL, zclose));
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
diff --git a/file_cmds/compress/zopen.h b/file_cmds/compress/zopen.h
new file mode 100644
index 0000000..8ad5691
--- /dev/null
+++ b/file_cmds/compress/zopen.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 1996
+ * FreeBSD 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 FreeBSD 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 [your name] OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/compress/zopen.h,v 1.5 2002/03/22 01:19:31 imp Exp $
+ */
+
+#ifndef _ZOPEN_H_
+#define _ZOPEN_H_
+
+FILE *zopen(const char *, const char *, int);
+
+#endif /* _ZOPEN_H_ */
diff --git a/file_cmds/cp/cp.1 b/file_cmds/cp/cp.1
new file mode 100644
index 0000000..8c346c7
--- /dev/null
+++ b/file_cmds/cp/cp.1
@@ -0,0 +1,311 @@
+.\"-
+.\" Copyright (c) 1989, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)cp.1 8.3 (Berkeley) 4/18/94
+.\" $FreeBSD: src/bin/cp/cp.1,v 1.33 2005/02/25 00:40:46 trhodes Exp $
+.\"
+.Dd February 23, 2005
+.Dt CP 1
+.Os
+.Sh NAME
+.Nm cp
+.Nd copy files
+.Sh SYNOPSIS
+.Nm cp
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl fi | n
+.Op Fl apvX
+.Ar source_file target_file
+.Nm cp
+.Oo
+.Fl R
+.Op Fl H | Fl L | Fl P
+.Oc
+.Op Fl fi | n
+.Op Fl apvX
+.Ar source_file ... target_directory
+.Sh DESCRIPTION
+In the first synopsis form, the
+.Nm cp
+utility copies the contents of the
+.Ar source_file
+to the
+.Ar target_file .
+In the second synopsis form,
+the contents of each named
+.Ar source_file
+is copied to the destination
+.Ar target_directory .
+The names of the files themselves are not changed.
+If
+.Nm cp
+detects an attempt to copy a file to itself, the copy will fail.
+.Pp
+The following options are available:
+.Bl -tag -width flag
+.It Fl a
+Same as
+.Fl pPR
+options. Preserves structure and attributes of files
+but not directory structure.
+.It Fl f
+.\"For each existing destination pathname, remove it and
+If the destination file cannot be opened, remove it and
+create a new file, without prompting for confirmation
+regardless of its permissions.
+(The
+.Fl f
+option overrides any previous
+.Fl n
+option.)
+.Pp
+The target file is not unlinked before the copy.
+Thus, any existing access rights will be retained.
+.It Fl H
+If the
+.Fl R
+option is specified, symbolic links on the command line are followed.
+(Symbolic links encountered in the tree traversal are not followed.)
+.It Fl i
+Cause
+.Nm cp
+to write a prompt to the standard error output before copying a file
+that would overwrite an existing file.
+If the response from the standard input begins with the character
+.Sq Li y
+or
+.Sq Li Y ,
+the file copy is attempted.
+(The
+.Fl i
+option overrides any previous
+.Fl n
+option.)
+.It Fl L
+If the
+.Fl R
+option is specified, all symbolic links are followed.
+.It Fl n
+Do not overwrite an existing file.
+(The
+.Fl n
+option overrides any previous
+.Fl f
+or
+.Fl i
+options.)
+.It Fl P
+If the
+.Fl R
+option is specified, no symbolic links are followed.
+This is the default.
+.It Fl p
+Cause
+.Nm cp
+to preserve the following attributes of each source
+file in the copy: modification time, access time,
+file flags, file mode, user ID, and group ID, as allowed by permissions.
+Access Control Lists (ACLs) and Extended Attributes (EAs),
+including resource forks, will also be preserved.
+.Pp
+If the user ID and group ID cannot be preserved, no error message
+is displayed and the exit value is not altered.
+.Pp
+If the source file has its set-user-ID bit on and the user ID cannot
+be preserved, the set-user-ID bit is not preserved
+in the copy's permissions.
+If the source file has its set-group-ID bit on and the group ID cannot
+be preserved, the set-group-ID bit is not preserved
+in the copy's permissions.
+If the source file has both its set-user-ID and set-group-ID bits on,
+and either the user ID or group ID cannot be preserved, neither
+the set-user-ID nor set-group-ID bits are preserved in the copy's
+permissions.
+.It Fl R
+If
+.Ar source_file
+designates a directory,
+.Nm cp
+copies the directory and the entire subtree connected at that point.
+If the
+.Ar source_file
+ends in a
+.Pa / ,
+the contents of the directory are copied rather than the
+directory itself.
+This option also causes symbolic links to be copied, rather than
+indirected through, and for
+.Nm cp
+to create special files rather than copying them as normal files.
+Created directories have the same mode as the corresponding source
+directory, unmodified by the process' umask.
+.Pp
+In
+.Fl R
+mode,
+.Nm cp
+will continue copying even if errors are detected.
+.Pp
+Note that
+.Nm cp
+copies hard-linked files as separate files.
+If you need to preserve hard links, consider using
+.Xr tar 1 ,
+.Xr cpio 1 ,
+or
+.Xr pax 1
+instead.
+.It Fl v
+Cause
+.Nm cp
+to be verbose, showing files as they are copied.
+.It Fl X
+Do not copy Extended Attributes (EAs) or resource forks.
+.It Fl c
+copy files using clonefile(2)
+.El
+.Pp
+For each destination file that already exists, its contents are
+overwritten if permissions allow.
+Its mode, user ID, and group
+ID are unchanged unless the
+.Fl p
+option was specified.
+.Pp
+In the second synopsis form,
+.Ar target_directory
+must exist unless there is only one named
+.Ar source_file
+which is a directory and the
+.Fl R
+flag is specified.
+.Pp
+If the destination file does not exist, the mode of the source file is
+used as modified by the file mode creation mask
+.Pf ( Ic umask ,
+see
+.Xr csh 1 ) .
+If the source file has its set-user-ID bit on, that bit is removed
+unless both the source file and the destination file are owned by the
+same user.
+If the source file has its set-group-ID bit on, that bit is removed
+unless both the source file and the destination file are in the same
+group and the user is a member of that group.
+If both the set-user-ID and set-group-ID bits are set, all of the above
+conditions must be fulfilled or both bits are removed.
+.Pp
+Appropriate permissions are required for file creation or overwriting.
+.Pp
+Symbolic links are always followed unless the
+.Fl R
+flag is set, in which case symbolic links are not followed, by default.
+The
+.Fl H
+or
+.Fl L
+flags (in conjunction with the
+.Fl R
+flag) cause symbolic links to be followed as described above.
+The
+.Fl H ,
+.Fl L
+and
+.Fl P
+options are ignored unless the
+.Fl R
+option is specified.
+In addition, these options override each other and the
+command's actions are determined by the last one specified.
+.Pp
+If
+.Nm cp
+receives a
+.Dv SIGINFO
+(see the
+.Cm status
+argument for
+.Xr stty 1 )
+signal, the current input and output file and the percentage complete
+will be written to the standard output.
+.Sh EXIT STATUS
+.Ex -std
+.Sh COMPATIBILITY
+Historic versions of the
+.Nm cp
+utility had a
+.Fl r
+option.
+This implementation supports that option;
+however, its use is strongly discouraged,
+as it does not correctly copy special files, symbolic links, or fifo's.
+.Pp
+The
+.Fl v
+and
+.Fl n
+options are non-standard and their use in scripts is not recommended.
+.Sh LEGACY DESCRIPTION
+In legacy mode,
+.Fl f
+will override
+.Fl i .
+Also, under the
+.Fl f
+option, the target file is always unlinked before the copy.
+Thus, new access rights will always be set.
+.Pp
+In
+.Fl R
+mode, copying will terminate if an error is encountered.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr mv 1 ,
+.Xr rcp 1 ,
+.Xr umask 2 ,
+.Xr fts 3 ,
+.Xr compat 5 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm cp
+command is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm cp
+command appeared in
+.At v1 .
diff --git a/file_cmds/cp/cp.c b/file_cmds/cp/cp.c
new file mode 100644
index 0000000..c856fd9
--- /dev/null
+++ b/file_cmds/cp/cp.c
@@ -0,0 +1,571 @@
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * David Hitz of Auspex Systems Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/cp/cp.c,v 1.52 2005/09/05 04:36:08 csjp Exp $");
+
+/*
+ * Cp copies source files to target files.
+ *
+ * The global PATH_T structure "to" always contains the path to the
+ * current target file. Since fts(3) does not change directories,
+ * this path can be either absolute or dot-relative.
+ *
+ * The basic algorithm is to initialize "to" and use fts(3) to traverse
+ * the file hierarchy rooted in the argument list. A trivial case is the
+ * case of 'cp file1 file2'. The more interesting case is the case of
+ * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
+ * path (relative to the root of the traversal) is appended to dir (stored
+ * in "to") to form the final target path.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <copyfile.h>
+#include <get_compat.h>
+#else /* !__APPLE__ */
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+#include "extern.h"
+
+#define STRIP_TRAILING_SLASH(p) { \
+ while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \
+ *--(p).p_end = 0; \
+}
+
+static char emptystring[] = "";
+
+PATH_T to = { to.p_path, emptystring, "" };
+
+int fflag, iflag, nflag, pflag, vflag;
+#ifdef __APPLE__
+int Xflag;
+#endif /* __APPLE__ */
+static int Rflag, rflag;
+ int cflag = 0;
+volatile sig_atomic_t info;
+
+enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
+
+static int copy(char *[], enum op, int);
+static void siginfo(int __unused);
+
+int
+main(int argc, char *argv[])
+{
+ struct stat to_stat, tmp_stat;
+ enum op type;
+ int Hflag, Lflag, Pflag, ch, fts_options, r, have_trailing_slash;
+ char *target;
+
+ Hflag = Lflag = Pflag = 0;
+ while ((ch = getopt(argc, argv, "cHLPRXafinprv")) != -1)
+ switch (ch) {
+ case 'c':
+ cflag = 1;
+ break;
+ case 'H':
+ Hflag = 1;
+ Lflag = Pflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = Pflag = 0;
+ break;
+ case 'P':
+ Pflag = 1;
+ Hflag = Lflag = 0;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'X':
+ Xflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ /* Determine if the STD is SUSv3 or Legacy */
+ if (COMPAT_MODE("bin/cp", "unix2003"))
+ nflag = 0; /* reset nflag, but not iflag */
+ else
+ iflag = nflag = 0; /* reset both */
+ break;
+ case 'i':
+ iflag = 1;
+ if (COMPAT_MODE("bin/cp", "unix2003"))
+ nflag = 0; /* reset nflag, but not fflag */
+ else
+ fflag = nflag = 0;
+ break;
+ case 'n':
+ nflag = 1;
+ fflag = iflag = 0;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case 'a':
+ pflag = 1;
+ Pflag = 1;
+ Rflag = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ usage();
+
+ if (cflag && Xflag) {
+ errx(1, "the -c and -X options may not be specified together");
+ }
+
+ fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
+ if (rflag) {
+ if (Rflag)
+ errx(1,
+ "the -R and -r options may not be specified together.");
+ if (Hflag || Lflag || Pflag)
+ errx(1,
+ "the -H, -L, and -P options may not be specified with the -r option.");
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ if (Rflag) {
+ if (Hflag)
+ fts_options |= FTS_COMFOLLOW;
+ if (Lflag) {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ }
+ } else {
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL | FTS_COMFOLLOW;
+ }
+ (void)signal(SIGINFO, siginfo);
+
+ /* Save the target base in "to". */
+ target = argv[--argc];
+ if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path))
+ errx(1, "%s: name too long", target);
+ to.p_end = to.p_path + strlen(to.p_path);
+ if (to.p_path == to.p_end) {
+ *to.p_end++ = '.';
+ *to.p_end = 0;
+ }
+ have_trailing_slash = (to.p_end[-1] == '/');
+ if (have_trailing_slash)
+ STRIP_TRAILING_SLASH(to);
+ to.target_end = to.p_end;
+
+ /* Set end of argument list for fts(3). */
+ argv[argc] = NULL;
+
+ /*
+ * Cp has two distinct cases:
+ *
+ * cp [-R] source target
+ * cp [-R] source1 ... sourceN directory
+ *
+ * In both cases, source can be either a file or a directory.
+ *
+ * In (1), the target becomes a copy of the source. That is, if the
+ * source is a file, the target will be a file, and likewise for
+ * directories.
+ *
+ * In (2), the real target is not directory, but "directory/source".
+ */
+ r = stat(to.p_path, &to_stat);
+ if (r == -1 && errno != ENOENT)
+ err(1, "%s", to.p_path);
+ if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
+ /*
+ * Case (1). Target is not a directory.
+ */
+ if (argc > 1) {
+ usage();
+ exit(1);
+ }
+ /*
+ * Need to detect the case:
+ * cp -R dir foo
+ * Where dir is a directory and foo does not exist, where
+ * we want pathname concatenations turned on but not for
+ * the initial mkdir().
+ */
+ if (r == -1) {
+ if (rflag || (Rflag && (Lflag || Hflag)))
+ stat(*argv, &tmp_stat);
+ else
+ lstat(*argv, &tmp_stat);
+
+ if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
+ type = DIR_TO_DNE;
+ else
+ type = FILE_TO_FILE;
+ } else
+ type = FILE_TO_FILE;
+
+ if (have_trailing_slash && type == FILE_TO_FILE) {
+ if (r == -1)
+ errx(1, "directory %s does not exist",
+ to.p_path);
+ else
+ errx(1, "%s is not a directory", to.p_path);
+ }
+ } else
+ /*
+ * Case (2). Target is a directory.
+ */
+ type = FILE_TO_DIR;
+
+ exit (copy(argv, type, fts_options));
+}
+
+static int
+copy(char *argv[], enum op type, int fts_options)
+{
+ struct stat to_stat;
+ FTS *ftsp;
+ FTSENT *curr;
+ int base = 0, dne, badcp, rval;
+ size_t nlen;
+ char *p, *target_mid;
+ mode_t mask, mode;
+
+ /*
+ * Keep an inverted copy of the umask, for use in correcting
+ * permissions on created directories when not using -p.
+ */
+ mask = ~umask(0777);
+ umask(~mask);
+
+ if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL)
+ err(1, "fts_open");
+ for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) {
+ switch (curr->fts_info) {
+ case FTS_NS:
+ case FTS_DNR:
+ case FTS_ERR:
+ warnx("%s: %s",
+ curr->fts_path, strerror(curr->fts_errno));
+ rval = 1;
+ continue;
+ case FTS_DC: /* Warn, continue. */
+ warnx("%s: directory causes a cycle", curr->fts_path);
+ rval = 1;
+ continue;
+ default:
+ ;
+ }
+#ifdef __APPLE__
+
+#ifdef __clang__
+#pragma clang diagnostic push
+/* clang doesn't like fts_name[1], but we know better... */
+#pragma clang diagnostic ignored "-Warray-bounds"
+#endif
+ /* Skip ._<file> when using copyfile and <file> exists */
+ if ((pflag || !Xflag) && (curr->fts_level != FTS_ROOTLEVEL) &&
+ (curr->fts_namelen > 2) && /* ._\0 is not AppleDouble */
+ (curr->fts_name[0] == '.') && (curr->fts_name[1] == '_')) {
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+ struct stat statbuf;
+ char path[PATH_MAX];
+ char *p = strrchr(curr->fts_path, '/');
+ if (p) {
+ size_t s = p + 2 - curr->fts_path;
+ if (s > sizeof(path)) s = sizeof(path);
+ strlcpy(path, curr->fts_path, s);
+ strlcat(path, curr->fts_name+2, sizeof(path));
+ } else {
+ strlcpy(path, curr->fts_name+2, sizeof(path));
+ }
+ if (!lstat(path, &statbuf)) {
+ continue;
+ }
+ }
+#endif /* __APPLE__ */
+ /*
+ * If we are in case (2) or (3) above, we need to append the
+ * source name to the target name.
+ */
+ if (type != FILE_TO_FILE) {
+ /*
+ * Need to remember the roots of traversals to create
+ * correct pathnames. If there's a directory being
+ * copied to a non-existent directory, e.g.
+ * cp -R a/dir noexist
+ * the resulting path name should be noexist/foo, not
+ * noexist/dir/foo (where foo is a file in dir), which
+ * is the case where the target exists.
+ *
+ * Also, check for "..". This is for correct path
+ * concatenation for paths ending in "..", e.g.
+ * cp -R .. /tmp
+ * Paths ending in ".." are changed to ".". This is
+ * tricky, but seems the easiest way to fix the problem.
+ *
+ * XXX
+ * Since the first level MUST be FTS_ROOTLEVEL, base
+ * is always initialized.
+ */
+ if (curr->fts_level == FTS_ROOTLEVEL) {
+ if (type != DIR_TO_DNE) {
+ p = strrchr(curr->fts_path, '/');
+ base = (p == NULL) ? 0 :
+ (int)(p - curr->fts_path + 1);
+
+ if (!strcmp(&curr->fts_path[base],
+ ".."))
+ base += 1;
+ } else
+ base = curr->fts_pathlen;
+ }
+
+ p = &curr->fts_path[base];
+ nlen = curr->fts_pathlen - base;
+ target_mid = to.target_end;
+ if (*p != '/' && target_mid[-1] != '/')
+ *target_mid++ = '/';
+ *target_mid = 0;
+ if (target_mid - to.p_path + nlen >= PATH_MAX) {
+ warnx("%s%s: name too long (not copied)",
+ to.p_path, p);
+ rval = 1;
+ continue;
+ }
+ (void)strncat(target_mid, p, nlen);
+ to.p_end = target_mid + nlen;
+ *to.p_end = 0;
+ STRIP_TRAILING_SLASH(to);
+ }
+
+ if (curr->fts_info == FTS_DP) {
+ /*
+ * We are nearly finished with this directory. If we
+ * didn't actually copy it, or otherwise don't need to
+ * change its attributes, then we are done.
+ */
+ if (!curr->fts_number)
+ continue;
+ /*
+ * If -p is in effect, set all the attributes.
+ * Otherwise, set the correct permissions, limited
+ * by the umask. Optimise by avoiding a chmod()
+ * if possible (which is usually the case if we
+ * made the directory). Note that mkdir() does not
+ * honour setuid, setgid and sticky bits, but we
+ * normally want to preserve them on directories.
+ */
+ if (pflag) {
+ if (setfile(curr->fts_statp, -1))
+ rval = 1;
+#ifdef __APPLE__
+ /* setfile will fail if writeattr is denied */
+ if (copyfile(curr->fts_path, to.p_path, NULL, COPYFILE_ACL)<0)
+ warn("%s: unable to copy ACL to %s", curr->fts_path, to.p_path);
+#else /* !__APPLE__ */
+ if (preserve_dir_acls(curr->fts_statp,
+ curr->fts_accpath, to.p_path) != 0)
+ rval = 1;
+#endif /* __APPLE__ */
+ } else {
+ mode = curr->fts_statp->st_mode;
+ if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) ||
+ ((mode | S_IRWXU) & mask) != (mode & mask))
+ if (chmod(to.p_path, mode & mask) != 0){
+ warn("chmod: %s", to.p_path);
+ rval = 1;
+ }
+ }
+ continue;
+ }
+
+ /* Not an error but need to remember it happened */
+ if (stat(to.p_path, &to_stat) == -1)
+ dne = 1;
+ else {
+ if (to_stat.st_dev == curr->fts_statp->st_dev &&
+ to_stat.st_ino == curr->fts_statp->st_ino) {
+ warnx("%s and %s are identical (not copied).",
+ to.p_path, curr->fts_path);
+ rval = 1;
+ if (S_ISDIR(curr->fts_statp->st_mode))
+ (void)fts_set(ftsp, curr, FTS_SKIP);
+ continue;
+ }
+ if (!S_ISDIR(curr->fts_statp->st_mode) &&
+ S_ISDIR(to_stat.st_mode)) {
+ warnx("cannot overwrite directory %s with "
+ "non-directory %s",
+ to.p_path, curr->fts_path);
+ rval = 1;
+ continue;
+ }
+ dne = 0;
+ }
+
+ switch (curr->fts_statp->st_mode & S_IFMT) {
+ case S_IFLNK:
+ /* Catch special case of a non-dangling symlink */
+ if ((fts_options & FTS_LOGICAL) ||
+ ((fts_options & FTS_COMFOLLOW) &&
+ curr->fts_level == 0)) {
+ if (copy_file(curr, dne))
+ badcp = rval = 1;
+ } else {
+ if (copy_link(curr, !dne))
+ badcp = rval = 1;
+ }
+ break;
+ case S_IFDIR:
+ if (!Rflag && !rflag) {
+ warnx("%s is a directory (not copied).",
+ curr->fts_path);
+ (void)fts_set(ftsp, curr, FTS_SKIP);
+ badcp = rval = 1;
+ break;
+ }
+ /*
+ * If the directory doesn't exist, create the new
+ * one with the from file mode plus owner RWX bits,
+ * modified by the umask. Trade-off between being
+ * able to write the directory (if from directory is
+ * 555) and not causing a permissions race. If the
+ * umask blocks owner writes, we fail..
+ */
+ if (dne) {
+ if (mkdir(to.p_path,
+ curr->fts_statp->st_mode | S_IRWXU) < 0) {
+ if (COMPAT_MODE("bin/cp", "unix2003")) {
+ warn("%s", to.p_path);
+ } else {
+ err(1, "%s", to.p_path);
+ }
+ }
+ } else if (!S_ISDIR(to_stat.st_mode)) {
+ errno = ENOTDIR;
+ if (COMPAT_MODE("bin/cp", "unix2003")) {
+ warn("%s", to.p_path);
+ } else {
+ err(1, "%s", to.p_path);
+ }
+ }
+ /*
+ * Arrange to correct directory attributes later
+ * (in the post-order phase) if this is a new
+ * directory, or if the -p flag is in effect.
+ */
+ curr->fts_number = pflag || dne;
+#ifdef __APPLE__
+ if (!Xflag) {
+ if (copyfile(curr->fts_path, to.p_path, NULL, COPYFILE_XATTR) < 0)
+ warn("%s: unable to copy extended attributes to %s", curr->fts_path, to.p_path);
+ /* ACL and mtime set in postorder traversal */
+ }
+#endif /* __APPLE__ */
+ break;
+ case S_IFBLK:
+ case S_IFCHR:
+ if (Rflag) {
+ if (copy_special(curr->fts_statp, !dne))
+ badcp = rval = 1;
+ } else {
+ if (copy_file(curr, dne))
+ badcp = rval = 1;
+ }
+ break;
+ case S_IFIFO:
+ if (Rflag) {
+ if (copy_fifo(curr->fts_statp, !dne))
+ badcp = rval = 1;
+ } else {
+ if (copy_file(curr, dne))
+ badcp = rval = 1;
+ }
+ break;
+ default:
+ if (copy_file(curr, dne))
+ badcp = rval = 1;
+ break;
+ }
+ if (vflag && !badcp)
+ (void)printf("%s -> %s\n", curr->fts_path, to.p_path);
+ }
+ if (errno)
+ err(1, "fts_read");
+ fts_close(ftsp);
+ return (rval);
+}
+
+static void
+siginfo(int sig __unused)
+{
+
+ info = 1;
+}
diff --git a/file_cmds/cp/extern.h b/file_cmds/cp/extern.h
new file mode 100644
index 0000000..521091d
--- /dev/null
+++ b/file_cmds/cp/extern.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/1/94
+ * $FreeBSD: src/bin/cp/extern.h,v 1.20 2005/09/05 04:36:08 csjp Exp $
+ */
+
+#ifndef _CP_EXTERN_H_
+#define _CP_EXTERN_H_
+
+typedef struct {
+ char *p_end; /* pointer to NULL at end of path */
+ char *target_end; /* pointer to end of target base */
+ char p_path[PATH_MAX]; /* pointer to the start of a path */
+} PATH_T;
+
+extern PATH_T to;
+extern int fflag, iflag, nflag, pflag, vflag;
+#ifdef __APPLE__
+extern int Xflag;
+#endif /* __APPLE__ */
+extern int cflag;
+extern volatile sig_atomic_t info;
+
+__BEGIN_DECLS
+int copy_fifo(struct stat *, int);
+int copy_file(const FTSENT *, int);
+int copy_link(const FTSENT *, int);
+int copy_special(struct stat *, int);
+int setfile(struct stat *, int);
+int preserve_dir_acls(struct stat *, char *, char *);
+int preserve_fd_acls(int, int);
+void usage(void);
+__END_DECLS
+
+#endif /* _CP_EXTERN_H_ */
diff --git a/file_cmds/cp/utils.c b/file_cmds/cp/utils.c
new file mode 100644
index 0000000..af05cc3
--- /dev/null
+++ b/file_cmds/cp/utils.c
@@ -0,0 +1,541 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/cp/utils.c,v 1.46 2005/09/05 04:36:08 csjp Exp $");
+
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
+#include <sys/mman.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <locale.h>
+
+#ifdef __APPLE__
+#include <sys/time.h>
+#include <copyfile.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <get_compat.h>
+#include <sys/attr.h>
+#include <sys/clonefile.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+#include "extern.h"
+#define cp_pct(x,y) (int)(100.0 * (double)(x) / (double)(y))
+
+int
+copy_file(const FTSENT *entp, int dne)
+{
+ static char buf[MAXBSIZE];
+ struct stat *fs;
+ int ch, checkch, from_fd, rval, to_fd;
+ ssize_t rcount;
+ ssize_t wcount;
+ size_t wresid;
+ off_t wtotal;
+ char *bufp;
+ char resp[] = {'\0', '\0'};
+#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
+ char *p;
+#endif
+ mode_t mode = 0;
+ struct stat to_stat;
+
+ if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) {
+ warn("%s", entp->fts_path);
+ return (1);
+ }
+
+ fs = entp->fts_statp;
+
+ /*
+ * If the file exists and we're interactive, verify with the user.
+ * If the file DNE, set the mode to be the from file, minus setuid
+ * bits, modified by the umask; arguably wrong, but it makes copying
+ * executables work right and it's been that way forever. (The
+ * other choice is 666 or'ed with the execute bits on the from file
+ * modified by the umask.)
+ */
+ if (!dne) {
+#define YESNO "(y/n [n]) "
+ if (nflag) {
+ if (vflag)
+ printf("%s not overwritten\n", to.p_path);
+ (void)close(from_fd);
+ return (1);
+ } else if (iflag) {
+ (void)fprintf(stderr, "overwrite %s? %s",
+ to.p_path, YESNO);
+
+ /* Load user specified locale */
+ setlocale(LC_MESSAGES, "");
+
+ checkch = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+
+ /* only care about the first character */
+ resp[0] = checkch;
+
+ if (rpmatch(resp) != 1) {
+ (void)close(from_fd);
+ (void)fprintf(stderr, "not overwritten\n");
+ return (1);
+ }
+ }
+
+ if (cflag) {
+ (void)unlink(to.p_path);
+ int error = clonefile(entp->fts_path, to.p_path, 0);
+ if (error)
+ warn("%s: clonefile failed", to.p_path);
+ (void)close(from_fd);
+ return error == 0 ? 0 : 1;
+ }
+
+ if (COMPAT_MODE("bin/cp", "unix2003")) {
+ /* first try to overwrite existing destination file name */
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+ if (to_fd == -1) {
+ if (fflag) {
+ /* Only if it fails remove file and create a new one */
+ (void)unlink(to.p_path);
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+ }
+ }
+ } else {
+ if (fflag) {
+ /* remove existing destination file name,
+ * create a new file */
+ (void)unlink(to.p_path);
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+ } else
+ /* overwrite existing destination file name */
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
+ }
+ } else {
+
+ if (cflag) {
+ int error = clonefile(entp->fts_path, to.p_path, 0);
+ if (error)
+ warn("%s: clonefile failed", to.p_path);
+ (void)close(from_fd);
+ return error == 0 ? 0 : 1;
+ }
+
+ to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
+ fs->st_mode & ~(S_ISUID | S_ISGID));
+ }
+
+ if (to_fd == -1) {
+ warn("%s", to.p_path);
+ (void)close(from_fd);
+ return (1);
+ }
+
+ rval = 0;
+
+#ifdef __APPLE__
+ if (S_ISREG(fs->st_mode)) {
+ struct statfs sfs;
+
+ /*
+ * Pre-allocate blocks for the destination file if it
+ * resides on Xsan.
+ */
+ if (fstatfs(to_fd, &sfs) == 0 &&
+ strcmp(sfs.f_fstypename, "acfs") == 0) {
+ fstore_t fst;
+
+ fst.fst_flags = 0;
+ fst.fst_posmode = F_PEOFPOSMODE;
+ fst.fst_offset = 0;
+ fst.fst_length = fs->st_size;
+
+ (void) fcntl(to_fd, F_PREALLOCATE, &fst);
+ }
+ }
+#endif /* __APPLE__ */
+
+ if (fstat(to_fd, &to_stat) != -1) {
+ mode = to_stat.st_mode;
+ if ((mode & (S_IRWXG|S_IRWXO))
+ && fchmod(to_fd, mode & ~(S_IRWXG|S_IRWXO))) {
+ if (errno != EPERM) /* we have write access but do not own the file */
+ warn("%s: fchmod failed", to.p_path);
+ mode = 0;
+ }
+ } else {
+ warn("%s", to.p_path);
+ }
+ /*
+ * Mmap and write if less than 8M (the limit is so we don't totally
+ * trash memory on big files. This is really a minor hack, but it
+ * wins some CPU back.
+ */
+#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
+ if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
+ fs->st_size <= 8 * 1048576) {
+ if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
+ MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
+ warn("%s", entp->fts_path);
+ rval = 1;
+ } else {
+ wtotal = 0;
+ for (bufp = p, wresid = fs->st_size; ;
+ bufp += wcount, wresid -= (size_t)wcount) {
+ wcount = write(to_fd, bufp, wresid);
+ wtotal += wcount;
+ if (info) {
+ info = 0;
+ (void)fprintf(stderr,
+ "%s -> %s %3d%%\n",
+ entp->fts_path, to.p_path,
+ cp_pct(wtotal, fs->st_size));
+
+ }
+ if (wcount >= (ssize_t)wresid || wcount <= 0)
+ break;
+ }
+ if (wcount != (ssize_t)wresid) {
+ warn("%s", to.p_path);
+ rval = 1;
+ }
+ /* Some systems don't unmap on close(2). */
+ if (munmap(p, fs->st_size) < 0) {
+ warn("%s", entp->fts_path);
+ rval = 1;
+ }
+ }
+ } else
+#endif
+ {
+ wtotal = 0;
+ while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ for (bufp = buf, wresid = rcount; ;
+ bufp += wcount, wresid -= wcount) {
+ wcount = write(to_fd, bufp, wresid);
+ wtotal += wcount;
+ if (info) {
+ info = 0;
+ (void)fprintf(stderr,
+ "%s -> %s %3d%%\n",
+ entp->fts_path, to.p_path,
+ cp_pct(wtotal, fs->st_size));
+
+ }
+ if (wcount >= (ssize_t)wresid || wcount <= 0)
+ break;
+ }
+ if (wcount != (ssize_t)wresid) {
+ warn("%s", to.p_path);
+ rval = 1;
+ break;
+ }
+ }
+ if (rcount < 0) {
+ warn("%s", entp->fts_path);
+ rval = 1;
+ }
+ }
+
+ /*
+ * Don't remove the target even after an error. The target might
+ * not be a regular file, or its attributes might be important,
+ * or its contents might be irreplaceable. It would only be safe
+ * to remove it if we created it and its length is 0.
+ */
+ if (mode != 0)
+ if (fchmod(to_fd, mode))
+ warn("%s: fchmod failed", to.p_path);
+#ifdef __APPLE__
+ /* do these before setfile in case copyfile changes mtime */
+ if (!Xflag && S_ISREG(fs->st_mode)) { /* skip devices, etc */
+ if (fcopyfile(from_fd, to_fd, NULL, COPYFILE_XATTR) < 0)
+ warn("%s: could not copy extended attributes to %s", entp->fts_path, to.p_path);
+ }
+ if (pflag && setfile(fs, to_fd))
+ rval = 1;
+ if (pflag) {
+ /* If this ACL denies writeattr then setfile will fail... */
+ if (fcopyfile(from_fd, to_fd, NULL, COPYFILE_ACL) < 0)
+ warn("%s: could not copy ACL to %s", entp->fts_path, to.p_path);
+ }
+#else /* !__APPLE__ */
+ if (pflag && setfile(fs, to_fd))
+ rval = 1;
+ if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
+ rval = 1;
+#endif /* __APPLE__ */
+ (void)close(from_fd);
+ if (close(to_fd)) {
+ warn("%s", to.p_path);
+ rval = 1;
+ }
+ return (rval);
+}
+
+int
+copy_link(const FTSENT *p, int exists)
+{
+ ssize_t len;
+ char llink[PATH_MAX];
+
+ if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) {
+ warn("readlink: %s", p->fts_path);
+ return (1);
+ }
+ llink[len] = '\0';
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (symlink(llink, to.p_path)) {
+ warn("symlink: %s", llink);
+ return (1);
+ }
+#ifdef __APPLE__
+ if (!Xflag)
+ if (copyfile(p->fts_path, to.p_path, NULL, COPYFILE_XATTR | COPYFILE_NOFOLLOW_SRC) <0)
+ warn("%s: could not copy extended attributes to %s",
+ p->fts_path, to.p_path);
+#endif
+ return (pflag ? setfile(p->fts_statp, -1) : 0);
+}
+
+int
+copy_fifo(struct stat *from_stat, int exists)
+{
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (mkfifo(to.p_path, from_stat->st_mode)) {
+ warn("mkfifo: %s", to.p_path);
+ return (1);
+ }
+ return (pflag ? setfile(from_stat, -1) : 0);
+}
+
+int
+copy_special(struct stat *from_stat, int exists)
+{
+ if (exists && unlink(to.p_path)) {
+ warn("unlink: %s", to.p_path);
+ return (1);
+ }
+ if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
+ warn("mknod: %s", to.p_path);
+ return (1);
+ }
+ return (pflag ? setfile(from_stat, -1) : 0);
+}
+
+int
+setfile(struct stat *fs, int fd)
+{
+ static struct timeval tv[2];
+ struct stat ts;
+ int rval, gotstat, islink, fdval;
+
+ rval = 0;
+ fdval = fd != -1;
+ islink = !fdval && S_ISLNK(fs->st_mode);
+ fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO;
+
+ TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
+ TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
+ if (fdval ? futimes(fd, tv) : (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv))) {
+ warn("%sutimes: %s", fdval ? "f" : (islink ? "l" : ""), to.p_path);
+ rval = 1;
+ }
+ if (fdval ? fstat(fd, &ts) : (islink ? lstat(to.p_path, &ts) :
+ stat(to.p_path, &ts))) {
+ gotstat = 0;
+ } else {
+ gotstat = 1;
+ ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO;
+ }
+ /*
+ * Changing the ownership probably won't succeed, unless we're root
+ * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
+ * the mode; current BSD behavior is to remove all setuid bits on
+ * chown. If chown fails, lose setuid/setgid bits.
+ */
+ if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) {
+ if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) : (islink ?
+ lchown(to.p_path, fs->st_uid, fs->st_gid) :
+ chown(to.p_path, fs->st_uid, fs->st_gid))) {
+ if (errno != EPERM) {
+ warn("%schown: %s", fdval ? "f" : (islink ? "l" : ""), to.p_path);
+ rval = 1;
+ }
+ fs->st_mode &= ~(S_ISUID | S_ISGID);
+ }
+ }
+
+ if (!gotstat || fs->st_mode != ts.st_mode) {
+ if (fdval ? fchmod(fd, fs->st_mode) : (islink ?
+ lchmod(to.p_path, fs->st_mode) :
+ chmod(to.p_path, fs->st_mode))) {
+ warn("%schmod: %s", fdval ? "f" : (islink ? "l" : ""), to.p_path);
+ rval = 1;
+ }
+ }
+
+ if (!gotstat || fs->st_flags != ts.st_flags) {
+ if (fdval ? fchflags(fd, fs->st_flags) : (islink ?
+ lchflags(to.p_path, fs->st_flags) :
+ chflags(to.p_path, fs->st_flags))) {
+ if (errno != EPERM) {
+ warn("%schflags: %s", fdval ? "f" : (islink ? "l" : ""), to.p_path);
+ rval = 1;
+ }
+ }
+ }
+ return (rval);
+}
+
+#ifndef __APPLE__
+int
+preserve_fd_acls(int source_fd, int dest_fd)
+{
+ struct acl *aclp;
+ acl_t acl;
+
+ if (fpathconf(source_fd, _PC_ACL_EXTENDED) != 1 ||
+ fpathconf(dest_fd, _PC_ACL_EXTENDED) != 1)
+ return (0);
+ acl = acl_get_fd(source_fd);
+ if (acl == NULL) {
+ warn("failed to get acl entries while setting %s", to.p_path);
+ return (1);
+ }
+ aclp = &acl->ats_acl;
+ if (aclp->acl_cnt == 3)
+ return (0);
+ if (acl_set_fd(dest_fd, acl) < 0) {
+ warn("failed to set acl entries for %s", to.p_path);
+ return (1);
+ }
+ return (0);
+}
+
+int
+preserve_dir_acls(struct stat *fs, char *source_dir, char *dest_dir)
+{
+ acl_t (*aclgetf)(const char *, acl_type_t);
+ int (*aclsetf)(const char *, acl_type_t, acl_t);
+ struct acl *aclp;
+ acl_t acl;
+
+ if (pathconf(source_dir, _PC_ACL_EXTENDED) != 1 ||
+ pathconf(dest_dir, _PC_ACL_EXTENDED) != 1)
+ return (0);
+ /*
+ * If the file is a link we will not follow it
+ */
+ if (S_ISLNK(fs->st_mode)) {
+ aclgetf = acl_get_link_np;
+ aclsetf = acl_set_link_np;
+ } else {
+ aclgetf = acl_get_file;
+ aclsetf = acl_set_file;
+ }
+ /*
+ * Even if there is no ACL_TYPE_DEFAULT entry here, a zero
+ * size ACL will be returned. So it is not safe to simply
+ * check the pointer to see if the default ACL is present.
+ */
+ acl = aclgetf(source_dir, ACL_TYPE_DEFAULT);
+ if (acl == NULL) {
+ warn("failed to get default acl entries on %s",
+ source_dir);
+ return (1);
+ }
+ aclp = &acl->ats_acl;
+ if (aclp->acl_cnt != 0 && aclsetf(dest_dir,
+ ACL_TYPE_DEFAULT, acl) < 0) {
+ warn("failed to set default acl entries on %s",
+ dest_dir);
+ return (1);
+ }
+ acl = aclgetf(source_dir, ACL_TYPE_ACCESS);
+ if (acl == NULL) {
+ warn("failed to get acl entries on %s", source_dir);
+ return (1);
+ }
+ aclp = &acl->ats_acl;
+ if (aclsetf(dest_dir, ACL_TYPE_ACCESS, acl) < 0) {
+ warn("failed to set acl entries on %s", dest_dir);
+ return (1);
+ }
+ return (0);
+}
+#endif /* !__APPLE__ */
+
+void
+usage(void)
+{
+
+ if (COMPAT_MODE("bin/cp", "unix2003")) {
+ (void)fprintf(stderr, "%s\n%s\n",
+"usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file target_file",
+" cp [-R [-H | -L | -P]] [-fi | -n] [-apvXc] source_file ... "
+"target_directory");
+ } else {
+ (void)fprintf(stderr, "%s\n%s\n",
+"usage: cp [-R [-H | -L | -P]] [-f | -i | -n] [-apvXc] source_file target_file",
+" cp [-R [-H | -L | -P]] [-f | -i | -n] [-apvXc] source_file ... "
+"target_directory");
+ }
+ exit(EX_USAGE);
+}
diff --git a/file_cmds/csh/strpct.c b/file_cmds/csh/strpct.c
new file mode 100644
index 0000000..ac3b32d
--- /dev/null
+++ b/file_cmds/csh/strpct.c
@@ -0,0 +1,99 @@
+/* $NetBSD: strpct.c,v 1.2 1998/05/08 18:43:54 fair Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Erik E. Fair
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+/*
+ * Calculate a percentage without resorting to floating point
+ * and return a pointer to a string
+ *
+ * "digits" is the number of digits past the decimal place you want
+ * (zero being the straight percentage with no decimals)
+ *
+ * Erik E. Fair <fair@clock.org>, May 8, 1997
+ */
+
+#include <sys/types.h>
+#include <machine/limits.h>
+
+#include <stdio.h>
+
+char * strpct __P((u_long, u_long, u_int));
+
+char *
+strpct(numerator, denominator, digits)
+ u_long numerator, denominator;
+ u_int digits;
+{
+ int i;
+ u_long result, factor;
+ static char percent[32];
+
+ /* I should check for digit overflow here, too XXX */
+ factor = 100L;
+ for(i = 0; i < digits; i++) {
+ factor *= 10;
+ }
+
+ /* watch out for overflow! */
+ if (numerator < (ULONG_MAX / factor)) {
+ numerator *= factor;
+ } else {
+ /* toss some of the bits of lesser significance */
+ denominator /= factor;
+ }
+
+ if (denominator == 0L)
+ denominator = 1L;
+
+ result = numerator / denominator;
+
+ if (digits == 0) {
+ (void) snprintf(percent, sizeof(percent), "%lu%%", result);
+ } else {
+ char fmt[32];
+
+ /* indirection to produce the right output format */
+ (void) snprintf(fmt, sizeof(fmt), "%%lu.%%0%ulu%%%%", digits);
+
+ factor /= 100L; /* undo initialization */
+
+ (void) snprintf(percent, sizeof(percent),
+ fmt, result / factor, result % factor);
+ }
+
+ return(percent);
+}
diff --git a/file_cmds/dd/args.c b/file_cmds/dd/args.c
new file mode 100644
index 0000000..463bd46
--- /dev/null
+++ b/file_cmds/dd/args.c
@@ -0,0 +1,421 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)args.c 8.3 (Berkeley) 4/2/94";
+#endif
+__used static const char rcsid[] =
+ "$FreeBSD: src/bin/dd/args.c,v 1.31 2002/02/22 20:51:00 markm Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dd.h"
+#include "extern.h"
+
+static int c_arg(const void *, const void *);
+static int c_conv(const void *, const void *);
+static void f_bs(char *);
+static void f_cbs(char *);
+static void f_conv(char *);
+static void f_count(char *);
+static void f_files(char *);
+static void f_ibs(char *);
+static void f_if(char *);
+static void f_obs(char *);
+static void f_of(char *);
+static void f_seek(char *);
+static void f_skip(char *);
+static quad_t get_num(char *);
+static off_t get_offset(char *);
+
+static const struct arg {
+ const char *name;
+ void (*f)(char *);
+ u_int set, noset;
+} args[] = {
+ { "bs", f_bs, C_BS, C_BS|C_OSYNC },
+ { "cbs", f_cbs, C_CBS, C_CBS },
+ { "conv", f_conv, 0, 0 },
+ { "count", f_count, C_COUNT, C_COUNT },
+ { "files", f_files, C_FILES, C_FILES },
+ { "ibs", f_ibs, C_IBS, C_IBS },
+ { "if", f_if, C_IF, C_IF },
+ { "iseek", f_skip, C_SKIP, C_SKIP },
+ { "obs", f_obs, C_OBS, C_OBS },
+ { "of", f_of, C_OF, C_OF },
+ { "oseek", f_seek, C_SEEK, C_SEEK },
+ { "seek", f_seek, C_SEEK, C_SEEK },
+ { "skip", f_skip, C_SKIP, C_SKIP },
+};
+
+static char *oper;
+
+/*
+ * args -- parse JCL syntax of dd.
+ */
+void
+jcl(char **argv)
+{
+ struct arg *ap, tmp;
+ char *arg;
+
+ in.dbsz = out.dbsz = 512;
+
+ if (argv[1] && !strcmp(argv[1], "--")) /* skip delimiter before operands */
+ argv++;
+ while ((oper = *++argv) != NULL) {
+ if ((oper = strdup(oper)) == NULL)
+ errx(1, "unable to allocate space for the argument \"%s\"", *argv);
+ if ((arg = strchr(oper, '=')) == NULL)
+ errx(1, "unknown operand %s", oper);
+ *arg++ = '\0';
+ if (!*arg)
+ errx(1, "no value specified for %s", oper);
+ tmp.name = oper;
+ if (!(ap = (struct arg *)bsearch(&tmp, args,
+ sizeof(args)/sizeof(struct arg), sizeof(struct arg),
+ c_arg)))
+ errx(1, "unknown operand %s", tmp.name);
+ if (ddflags & ap->noset)
+ errx(1, "%s: illegal argument combination or already set",
+ tmp.name);
+ ddflags |= ap->set;
+ ap->f(arg);
+ }
+
+ /* Final sanity checks. */
+
+ if (ddflags & C_BS) {
+ /*
+ * Bs is turned off by any conversion -- we assume the user
+ * just wanted to set both the input and output block sizes
+ * and didn't want the bs semantics, so we don't warn.
+ */
+ if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
+ C_UNBLOCK))
+ ddflags &= ~C_BS;
+
+ /* Bs supersedes ibs and obs. */
+ if (ddflags & C_BS && ddflags & (C_IBS | C_OBS))
+ warnx("bs supersedes ibs and obs");
+ }
+
+ /*
+ * Ascii/ebcdic and cbs implies block/unblock.
+ * Block/unblock requires cbs and vice-versa.
+ */
+ if (ddflags & (C_BLOCK | C_UNBLOCK)) {
+ if (!(ddflags & C_CBS))
+ errx(1, "record operations require cbs");
+ if (cbsz == 0)
+ errx(1, "cbs cannot be zero");
+ cfunc = ddflags & C_BLOCK ? block : unblock;
+ } else if (ddflags & C_CBS) {
+ if (ddflags & (C_ASCII | C_EBCDIC)) {
+ if (ddflags & C_ASCII) {
+ ddflags |= C_UNBLOCK;
+ cfunc = unblock;
+ } else {
+ ddflags |= C_BLOCK;
+ cfunc = block;
+ }
+ } else
+ errx(1, "cbs meaningless if not doing record operations");
+ } else
+ cfunc = def;
+
+ /*
+ * Bail out if the calculation of a file offset would overflow.
+ */
+ if (in.offset > QUAD_MAX / in.dbsz || out.offset > QUAD_MAX / out.dbsz)
+ errx(1, "seek offsets cannot be larger than %qd", QUAD_MAX);
+}
+
+static int
+c_arg(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct arg *)a)->name,
+ ((const struct arg *)b)->name));
+}
+
+static void
+f_bs(char *arg)
+{
+ quad_t res;
+
+ res = get_num(arg);
+ if (res < 1 || res > SSIZE_MAX)
+ errx(1, "bs must be between 1 and %ld", SSIZE_MAX);
+ in.dbsz = out.dbsz = (size_t)res;
+}
+
+static void
+f_cbs(char *arg)
+{
+ quad_t res;
+
+ res = get_num(arg);
+ if (res < 1 || res > SSIZE_MAX)
+ errx(1, "cbs must be between 1 and %ld", SSIZE_MAX);
+ cbsz = (size_t)res;
+}
+
+static void
+f_count(char *arg)
+{
+
+ cpy_cnt = get_num(arg);
+ if (cpy_cnt < 0)
+ errx(1, "count cannot be negative");
+ if (cpy_cnt == 0)
+ cpy_cnt = -1;
+}
+
+static void
+f_files(char *arg)
+{
+
+ files_cnt = get_num(arg);
+ if (files_cnt < 1)
+ errx(1, "files must be between 1 and %qd", QUAD_MAX);
+}
+
+static void
+f_ibs(char *arg)
+{
+ quad_t res;
+
+ if (!(ddflags & C_BS)) {
+ res = get_num(arg);
+ if (res < 1 || res > SSIZE_MAX)
+ errx(1, "ibs must be between 1 and %ld", SSIZE_MAX);
+ in.dbsz = (size_t)res;
+ }
+}
+
+static void
+f_if(char *arg)
+{
+
+ in.name = arg;
+}
+
+static void
+f_obs(char *arg)
+{
+ quad_t res;
+
+ if (!(ddflags & C_BS)) {
+ res = get_num(arg);
+ if (res < 1 || res > SSIZE_MAX)
+ errx(1, "obs must be between 1 and %ld", SSIZE_MAX);
+ out.dbsz = (size_t)res;
+ }
+}
+
+static void
+f_of(char *arg)
+{
+
+ out.name = arg;
+}
+
+static void
+f_seek(char *arg)
+{
+
+ out.offset = get_offset(arg);
+}
+
+static void
+f_skip(char *arg)
+{
+
+ in.offset = get_offset(arg);
+}
+
+static const struct conv {
+ const char *name;
+ u_int set, noset;
+ const u_char *ctab;
+} clist[] = {
+ { "ascii", C_ASCII, C_EBCDIC, e2a_POSIX },
+ { "block", C_BLOCK, C_UNBLOCK, NULL },
+ { "ebcdic", C_EBCDIC, C_ASCII, a2e_POSIX },
+ { "ibm", C_EBCDIC, C_ASCII, a2ibm_POSIX },
+ { "lcase", C_LCASE, C_UCASE, NULL },
+ { "noerror", C_NOERROR, 0, NULL },
+ { "notrunc", C_NOTRUNC, 0, NULL },
+ { "oldascii", C_ASCII, C_EBCDIC, e2a_32V },
+ { "oldebcdic", C_EBCDIC, C_ASCII, a2e_32V },
+ { "oldibm", C_EBCDIC, C_ASCII, a2ibm_32V },
+ { "osync", C_OSYNC, C_BS, NULL },
+ { "sparse", C_SPARSE, 0, NULL },
+ { "swab", C_SWAB, 0, NULL },
+ { "sync", C_SYNC, 0, NULL },
+ { "ucase", C_UCASE, C_LCASE, NULL },
+ { "unblock", C_UNBLOCK, C_BLOCK, NULL },
+};
+
+static void
+f_conv(char *arg)
+{
+ struct conv *cp, tmp;
+
+ while (arg != NULL) {
+ tmp.name = strsep(&arg, ",");
+ cp = bsearch(&tmp, clist, sizeof(clist) / sizeof(struct conv),
+ sizeof(struct conv), c_conv);
+ if (cp == NULL)
+ errx(1, "unknown conversion %s", tmp.name);
+ if (ddflags & cp->noset)
+ errx(1, "%s: illegal conversion combination", tmp.name);
+ ddflags |= cp->set;
+ if (cp->ctab)
+ ctab = cp->ctab;
+ }
+}
+
+static int
+c_conv(const void *a, const void *b)
+{
+
+ return (strcmp(((const struct conv *)a)->name,
+ ((const struct conv *)b)->name));
+}
+
+/*
+ * Convert an expression of the following forms to a quad_t.
+ * 1) A positive decimal number.
+ * 2) A positive decimal number followed by a b (mult by 512).
+ * 3) A positive decimal number followed by a k (mult by 1 << 10).
+ * 4) A positive decimal number followed by a m (mult by 1 << 20).
+ * 5) A positive decimal number followed by a g (mult by 1 << 30).
+ * 5) A positive decimal number followed by a w (mult by sizeof int).
+ * 6) Two or more positive decimal numbers (with/without [bkmgw])
+ * separated by x (also * for backwards compatibility), specifying
+ * the product of the indicated values.
+ */
+static quad_t
+get_num(char *val)
+{
+ quad_t num, t;
+ char *expr;
+
+ errno = 0;
+ num = strtoq(val, &expr, 0);
+ if (errno != 0) /* Overflow or underflow. */
+ err(1, "%s", oper);
+
+ if (expr == val) /* No valid digits. */
+ errx(1, "%s: illegal numeric value", oper);
+
+ switch (*expr) {
+ case 'b':
+ t = num;
+ num *= 512;
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 'k':
+ t = num;
+ num *= 1 << 10;
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 'm':
+ t = num;
+ num *= 1 << 20;
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 'g':
+ t = num;
+ num *= 1 << 30;
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ case 'w':
+ t = num;
+ num *= sizeof(int);
+ if (t > num)
+ goto erange;
+ ++expr;
+ break;
+ }
+
+ switch (*expr) {
+ case '\0':
+ break;
+ case '*': /* Backward compatible. */
+ case 'x':
+ t = num;
+ num *= get_num(expr + 1);
+ if (t <= num)
+ break;
+erange:
+ errx(1, "%s: %s", oper, strerror(ERANGE));
+ default:
+ errx(1, "%s: illegal numeric value", oper);
+ }
+ return (num);
+}
+
+static off_t
+get_offset(char *val)
+{
+ quad_t num;
+
+ num = get_num(val);
+ if (num > QUAD_MAX) /* XXX can't happen && quad_t != off_t */
+ errx(1, "%s: illegal offset", oper); /* Too big. */
+ return ((off_t)num);
+}
diff --git a/file_cmds/dd/conv.c b/file_cmds/dd/conv.c
new file mode 100644
index 0000000..59c7b01
--- /dev/null
+++ b/file_cmds/dd/conv.c
@@ -0,0 +1,273 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)conv.c 8.3 (Berkeley) 4/2/94";
+#endif
+__used static const char rcsid[] =
+ "$FreeBSD: src/bin/dd/conv.c,v 1.16 2002/02/02 06:24:12 imp Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <string.h>
+
+#include "dd.h"
+#include "extern.h"
+
+/*
+ * def --
+ * Copy input to output. Input is buffered until reaches obs, and then
+ * output until less than obs remains. Only a single buffer is used.
+ * Worst case buffer calculation is (ibs + obs - 1).
+ */
+void
+def(void)
+{
+ u_char *inp;
+ const u_char *t;
+ size_t cnt;
+
+ if ((t = ctab) != NULL)
+ for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
+ *inp = t[*inp];
+
+ /* Make the output buffer look right. */
+ out.dbp = in.dbp;
+ out.dbcnt = in.dbcnt;
+
+ if (in.dbcnt >= out.dbsz) {
+ /* If the output buffer is full, write it. */
+ dd_out(0);
+
+ /*
+ * Ddout copies the leftover output to the beginning of
+ * the buffer and resets the output buffer. Reset the
+ * input buffer to match it.
+ */
+ in.dbp = out.dbp;
+ in.dbcnt = out.dbcnt;
+ }
+}
+
+void
+def_close(void)
+{
+ /* Just update the count, everything is already in the buffer. */
+ if (in.dbcnt)
+ out.dbcnt = in.dbcnt;
+}
+
+/*
+ * Copy variable length newline terminated records with a max size cbsz
+ * bytes to output. Records less than cbs are padded with spaces.
+ *
+ * max in buffer: MAX(ibs, cbsz)
+ * max out buffer: obs + cbsz
+ */
+void
+block(void)
+{
+ u_char *inp, *outp;
+ const u_char *t;
+ size_t cnt, maxlen;
+ static int intrunc;
+ int ch;
+
+ /*
+ * Record truncation can cross block boundaries. If currently in a
+ * truncation state, keep tossing characters until reach a newline.
+ * Start at the beginning of the buffer, as the input buffer is always
+ * left empty.
+ */
+ if (intrunc) {
+ for (inp = in.db, cnt = in.dbrcnt; cnt && *inp++ != '\n'; --cnt)
+ ;
+ if (!cnt) {
+ in.dbcnt = 0;
+ in.dbp = in.db;
+ return;
+ }
+ intrunc = 0;
+ /* Adjust the input buffer numbers. */
+ in.dbcnt = cnt - 1;
+ in.dbp = inp + cnt - 1;
+ }
+
+ /*
+ * Copy records (max cbsz size chunks) into the output buffer. The
+ * translation is done as we copy into the output buffer.
+ */
+ ch = 0;
+ for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
+ maxlen = MIN(cbsz, in.dbcnt);
+ if ((t = ctab) != NULL)
+ for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n';
+ ++cnt)
+ *outp++ = t[ch];
+ else
+ for (cnt = 0; cnt < maxlen && (ch = *inp++) != '\n';
+ ++cnt)
+ *outp++ = ch;
+ /*
+ * Check for short record without a newline. Reassemble the
+ * input block.
+ */
+ if (ch != '\n' && in.dbcnt < cbsz) {
+ (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+ break;
+ }
+
+ /* Adjust the input buffer numbers. */
+ in.dbcnt -= cnt;
+ if (ch == '\n')
+ --in.dbcnt;
+
+ /* Pad short records with spaces. */
+ if (cnt < cbsz)
+ (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
+ else {
+ /*
+ * If the next character wouldn't have ended the
+ * block, it's a truncation.
+ */
+ if (!in.dbcnt || *inp != '\n')
+ ++st.trunc;
+
+ /* Toss characters to a newline. */
+ for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
+ if (!in.dbcnt)
+ intrunc = 1;
+ else
+ --in.dbcnt;
+ }
+
+ /* Adjust output buffer numbers. */
+ out.dbp += cbsz;
+ if ((out.dbcnt += cbsz) >= out.dbsz)
+ dd_out(0);
+ outp = out.dbp;
+ }
+ in.dbp = in.db + in.dbcnt;
+}
+
+void
+block_close(void)
+{
+ /*
+ * Copy any remaining data into the output buffer and pad to a record.
+ * Don't worry about truncation or translation, the input buffer is
+ * always empty when truncating, and no characters have been added for
+ * translation. The bottom line is that anything left in the input
+ * buffer is a truncated record. Anything left in the output buffer
+ * just wasn't big enough.
+ */
+ if (in.dbcnt) {
+ ++st.trunc;
+ (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
+ (void)memset(out.dbp + in.dbcnt, ctab ? ctab[' '] : ' ',
+ cbsz - in.dbcnt);
+ out.dbcnt += cbsz;
+ }
+}
+
+/*
+ * Convert fixed length (cbsz) records to variable length. Deletes any
+ * trailing blanks and appends a newline.
+ *
+ * max in buffer: MAX(ibs, cbsz) + cbsz
+ * max out buffer: obs + cbsz
+ */
+void
+unblock(void)
+{
+ u_char *inp;
+ const u_char *t;
+ size_t cnt;
+
+ /* Translation and case conversion. */
+ if ((t = ctab) != NULL)
+ for (cnt = in.dbrcnt, inp = in.dbp; cnt--;) {
+ *inp = t[*inp];
+ --inp;
+ }
+ /*
+ * Copy records (max cbsz size chunks) into the output buffer. The
+ * translation has to already be done or we might not recognize the
+ * spaces.
+ */
+ for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
+ for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t)
+ ;
+ if (t >= inp) {
+ cnt = t - inp + 1;
+ (void)memmove(out.dbp, inp, cnt);
+ out.dbp += cnt;
+ out.dbcnt += cnt;
+ }
+ *out.dbp++ = '\n';
+ if (++out.dbcnt >= out.dbsz)
+ dd_out(0);
+ }
+ if (in.dbcnt)
+ (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
+ in.dbp = in.db + in.dbcnt;
+}
+
+void
+unblock_close(void)
+{
+ u_char *t;
+ size_t cnt;
+
+ if (in.dbcnt) {
+ warnx("%s: short input record", in.name);
+ for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t)
+ ;
+ if (t >= in.db) {
+ cnt = t - in.db + 1;
+ (void)memmove(out.dbp, in.db, cnt);
+ out.dbp += cnt;
+ out.dbcnt += cnt;
+ }
+ ++out.dbcnt;
+ *out.dbp++ = '\n';
+ }
+}
diff --git a/file_cmds/dd/conv_tab.c b/file_cmds/dd/conv_tab.c
new file mode 100644
index 0000000..a9f091e
--- /dev/null
+++ b/file_cmds/dd/conv_tab.c
@@ -0,0 +1,289 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)conv_tab.c 8.1 (Berkeley) 5/31/93";
+#endif
+__used static const char rcsid[] =
+ "$FreeBSD: src/bin/dd/conv_tab.c,v 1.10 1999/09/12 16:51:53 green Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+/*
+ * There are currently six tables:
+ *
+ * ebcdic -> ascii 32V conv=oldascii
+ * ascii -> ebcdic 32V conv=oldebcdic
+ * ascii -> ibm ebcdic 32V conv=oldibm
+ *
+ * ebcdic -> ascii POSIX/S5 conv=ascii
+ * ascii -> ebcdic POSIX/S5 conv=ebcdic
+ * ascii -> ibm ebcdic POSIX/S5 conv=ibm
+ *
+ * Other tables are built from these if multiple conversions are being
+ * done.
+ *
+ * Tables used for conversions to/from IBM and EBCDIC to support an extension
+ * to POSIX P1003.2/D11. The tables referencing POSIX contain data extracted
+ * from tables 4-3 and 4-4 in P1003.2/Draft 11. The historic tables were
+ * constructed by running against a file with all possible byte values.
+ *
+ * More information can be obtained in "Correspondences of 8-Bit and Hollerith
+ * Codes for Computer Environments-A USASI Tutorial", Communications of the
+ * ACM, Volume 11, Number 11, November 1968, pp. 783-789.
+ */
+
+u_char casetab[256];
+
+/* EBCDIC to ASCII -- 32V compatible. */
+const u_char e2a_32V[] = {
+ 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, /* 0000 */
+ 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, /* 0010 */
+ 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, /* 0020 */
+ 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, /* 0030 */
+ 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, /* 0040 */
+ 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, /* 0050 */
+ 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, /* 0060 */
+ 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, /* 0070 */
+ 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, /* 0100 */
+ 0247, 0250, 0133, 0056, 0074, 0050, 0053, 0041, /* 0110 */
+ 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, /* 0120 */
+ 0260, 0261, 0135, 0044, 0052, 0051, 0073, 0136, /* 0130 */
+ 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, /* 0140 */
+ 0270, 0271, 0174, 0054, 0045, 0137, 0076, 0077, /* 0150 */
+ 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, /* 0160 */
+ 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, /* 0170 */
+ 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, /* 0200 */
+ 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, /* 0210 */
+ 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, /* 0220 */
+ 0161, 0162, 0313, 0314, 0315, 0316, 0317, 0320, /* 0230 */
+ 0321, 0176, 0163, 0164, 0165, 0166, 0167, 0170, /* 0240 */
+ 0171, 0172, 0322, 0323, 0324, 0325, 0326, 0327, /* 0250 */
+ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, /* 0260 */
+ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347, /* 0270 */
+ 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, /* 0300 */
+ 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, /* 0310 */
+ 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, /* 0320 */
+ 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, /* 0330 */
+ 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, /* 0340 */
+ 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, /* 0350 */
+ 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, /* 0360 */
+ 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */
+};
+
+/* ASCII to EBCDIC -- 32V compatible. */
+const u_char a2e_32V[] = {
+ 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */
+ 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */
+ 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */
+ 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */
+ 0100, 0117, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */
+ 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */
+ 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */
+ 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */
+ 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */
+ 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */
+ 0347, 0350, 0351, 0112, 0340, 0132, 0137, 0155, /* 0130 */
+ 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */
+ 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */
+ 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */
+ 0247, 0250, 0251, 0300, 0152, 0320, 0241, 0007, /* 0170 */
+ 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */
+ 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */
+ 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */
+ 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */
+ 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */
+ 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */
+ 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */
+ 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */
+ 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */
+ 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */
+ 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */
+ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */
+ 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */
+ 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */
+ 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */
+};
+
+/* ASCII to IBM EBCDIC -- 32V compatible. */
+const u_char a2ibm_32V[] = {
+ 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */
+ 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */
+ 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */
+ 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */
+ 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */
+ 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */
+ 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */
+ 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */
+ 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */
+ 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */
+ 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, /* 0130 */
+ 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */
+ 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */
+ 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */
+ 0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007, /* 0170 */
+ 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */
+ 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */
+ 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */
+ 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */
+ 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */
+ 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */
+ 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */
+ 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */
+ 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */
+ 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */
+ 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */
+ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */
+ 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */
+ 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */
+ 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */
+};
+
+/* EBCDIC to ASCII -- POSIX and System V compatible. */
+const u_char e2a_POSIX[] = {
+ 0000, 0001, 0002, 0003, 0234, 0011, 0206, 0177, /* 0000 */
+ 0227, 0215, 0216, 0013, 0014, 0015, 0016, 0017, /* 0010 */
+ 0020, 0021, 0022, 0023, 0235, 0205, 0010, 0207, /* 0020 */
+ 0030, 0031, 0222, 0217, 0034, 0035, 0036, 0037, /* 0030 */
+ 0200, 0201, 0202, 0203, 0204, 0012, 0027, 0033, /* 0040 */
+ 0210, 0211, 0212, 0213, 0214, 0005, 0006, 0007, /* 0050 */
+ 0220, 0221, 0026, 0223, 0224, 0225, 0226, 0004, /* 0060 */
+ 0230, 0231, 0232, 0233, 0024, 0025, 0236, 0032, /* 0070 */
+ 0040, 0240, 0241, 0242, 0243, 0244, 0245, 0246, /* 0100 */
+ 0247, 0250, 0325, 0056, 0074, 0050, 0053, 0174, /* 0110 */
+ 0046, 0251, 0252, 0253, 0254, 0255, 0256, 0257, /* 0120 */
+ 0260, 0261, 0041, 0044, 0052, 0051, 0073, 0176, /* 0130 */
+ 0055, 0057, 0262, 0263, 0264, 0265, 0266, 0267, /* 0140 */
+ 0270, 0271, 0313, 0054, 0045, 0137, 0076, 0077, /* 0150 */
+ 0272, 0273, 0274, 0275, 0276, 0277, 0300, 0301, /* 0160 */
+ 0302, 0140, 0072, 0043, 0100, 0047, 0075, 0042, /* 0170 */
+ 0303, 0141, 0142, 0143, 0144, 0145, 0146, 0147, /* 0200 */
+ 0150, 0151, 0304, 0305, 0306, 0307, 0310, 0311, /* 0210 */
+ 0312, 0152, 0153, 0154, 0155, 0156, 0157, 0160, /* 0220 */
+ 0161, 0162, 0136, 0314, 0315, 0316, 0317, 0320, /* 0230 */
+ 0321, 0345, 0163, 0164, 0165, 0166, 0167, 0170, /* 0240 */
+ 0171, 0172, 0322, 0323, 0324, 0133, 0326, 0327, /* 0250 */
+ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337, /* 0260 */
+ 0340, 0341, 0342, 0343, 0344, 0135, 0346, 0347, /* 0270 */
+ 0173, 0101, 0102, 0103, 0104, 0105, 0106, 0107, /* 0300 */
+ 0110, 0111, 0350, 0351, 0352, 0353, 0354, 0355, /* 0310 */
+ 0175, 0112, 0113, 0114, 0115, 0116, 0117, 0120, /* 0320 */
+ 0121, 0122, 0356, 0357, 0360, 0361, 0362, 0363, /* 0330 */
+ 0134, 0237, 0123, 0124, 0125, 0126, 0127, 0130, /* 0340 */
+ 0131, 0132, 0364, 0365, 0366, 0367, 0370, 0371, /* 0350 */
+ 0060, 0061, 0062, 0063, 0064, 0065, 0066, 0067, /* 0360 */
+ 0070, 0071, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */
+};
+
+/* ASCII to EBCDIC -- POSIX and System V compatible. */
+const u_char a2e_POSIX[] = {
+ 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */
+ 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */
+ 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */
+ 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */
+ 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */
+ 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */
+ 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */
+ 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */
+ 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */
+ 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */
+ 0347, 0350, 0351, 0255, 0340, 0275, 0232, 0155, /* 0130 */
+ 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */
+ 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */
+ 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */
+ 0247, 0250, 0251, 0300, 0117, 0320, 0137, 0007, /* 0170 */
+ 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */
+ 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */
+ 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */
+ 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */
+ 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */
+ 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */
+ 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */
+ 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */
+ 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */
+ 0216, 0217, 0220, 0152, 0233, 0234, 0235, 0236, /* 0310 */
+ 0237, 0240, 0252, 0253, 0254, 0112, 0256, 0257, /* 0320 */
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */
+ 0270, 0271, 0272, 0273, 0274, 0241, 0276, 0277, /* 0340 */
+ 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */
+ 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */
+ 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */
+};
+
+/* ASCII to IBM EBCDIC -- POSIX and System V compatible. */
+const u_char a2ibm_POSIX[] = {
+ 0000, 0001, 0002, 0003, 0067, 0055, 0056, 0057, /* 0000 */
+ 0026, 0005, 0045, 0013, 0014, 0015, 0016, 0017, /* 0010 */
+ 0020, 0021, 0022, 0023, 0074, 0075, 0062, 0046, /* 0020 */
+ 0030, 0031, 0077, 0047, 0034, 0035, 0036, 0037, /* 0030 */
+ 0100, 0132, 0177, 0173, 0133, 0154, 0120, 0175, /* 0040 */
+ 0115, 0135, 0134, 0116, 0153, 0140, 0113, 0141, /* 0050 */
+ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367, /* 0060 */
+ 0370, 0371, 0172, 0136, 0114, 0176, 0156, 0157, /* 0070 */
+ 0174, 0301, 0302, 0303, 0304, 0305, 0306, 0307, /* 0100 */
+ 0310, 0311, 0321, 0322, 0323, 0324, 0325, 0326, /* 0110 */
+ 0327, 0330, 0331, 0342, 0343, 0344, 0345, 0346, /* 0120 */
+ 0347, 0350, 0351, 0255, 0340, 0275, 0137, 0155, /* 0130 */
+ 0171, 0201, 0202, 0203, 0204, 0205, 0206, 0207, /* 0140 */
+ 0210, 0211, 0221, 0222, 0223, 0224, 0225, 0226, /* 0150 */
+ 0227, 0230, 0231, 0242, 0243, 0244, 0245, 0246, /* 0160 */
+ 0247, 0250, 0251, 0300, 0117, 0320, 0241, 0007, /* 0170 */
+ 0040, 0041, 0042, 0043, 0044, 0025, 0006, 0027, /* 0200 */
+ 0050, 0051, 0052, 0053, 0054, 0011, 0012, 0033, /* 0210 */
+ 0060, 0061, 0032, 0063, 0064, 0065, 0066, 0010, /* 0220 */
+ 0070, 0071, 0072, 0073, 0004, 0024, 0076, 0341, /* 0230 */
+ 0101, 0102, 0103, 0104, 0105, 0106, 0107, 0110, /* 0240 */
+ 0111, 0121, 0122, 0123, 0124, 0125, 0126, 0127, /* 0250 */
+ 0130, 0131, 0142, 0143, 0144, 0145, 0146, 0147, /* 0260 */
+ 0150, 0151, 0160, 0161, 0162, 0163, 0164, 0165, /* 0270 */
+ 0166, 0167, 0170, 0200, 0212, 0213, 0214, 0215, /* 0300 */
+ 0216, 0217, 0220, 0232, 0233, 0234, 0235, 0236, /* 0310 */
+ 0237, 0240, 0252, 0253, 0254, 0255, 0256, 0257, /* 0320 */
+ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267, /* 0330 */
+ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277, /* 0340 */
+ 0312, 0313, 0314, 0315, 0316, 0317, 0332, 0333, /* 0350 */
+ 0334, 0335, 0336, 0337, 0352, 0353, 0354, 0355, /* 0360 */
+ 0356, 0357, 0372, 0373, 0374, 0375, 0376, 0377, /* 0370 */
+};
diff --git a/file_cmds/dd/dd.1 b/file_cmds/dd/dd.1
new file mode 100644
index 0000000..8460813
--- /dev/null
+++ b/file_cmds/dd/dd.1
@@ -0,0 +1,382 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Keith Muller of the University of California, San Diego.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)dd.1 8.2 (Berkeley) 1/13/94
+.\" $FreeBSD: src/bin/dd/dd.1,v 1.19 2002/03/31 20:49:37 keramida Exp $
+.\"
+.Dd January 13, 1994
+.Dt DD 1
+.Os
+.Sh NAME
+.Nm dd
+.Nd convert and copy a file
+.Sh SYNOPSIS
+.Nm
+.Op Ar operands ...
+.Sh DESCRIPTION
+The
+.Nm
+utility copies the standard input to the standard output.
+Input data is read and written in 512-byte blocks.
+If input reads are short, input from multiple reads are aggregated
+to form the output block.
+When finished,
+.Nm
+displays the number of complete and partial input and output blocks
+and truncated input records to the standard error output.
+.Pp
+The following operands are available:
+.\" XXX
+.Bl -tag -width of=file
+.It Cm bs Ns = Ns Ar n
+Set both input and output block size to
+.Ar n
+bytes, superseding the
+.Cm ibs
+and
+.Cm obs
+operands.
+If no conversion values other than
+.Cm noerror ,
+.Cm notrunc
+or
+.Cm sync
+are specified, then each input block is copied to the output as a
+single block without any aggregation of short blocks.
+.It Cm cbs Ns = Ns Ar n
+Set the conversion record size to
+.Ar n
+bytes.
+The conversion record size is required by the record oriented conversion
+values.
+.It Cm count Ns = Ns Ar n
+Copy only
+.Ar n
+input blocks.
+.It Cm files Ns = Ns Ar n
+Copy
+.Ar n
+input files before terminating.
+This operand is only applicable when the input device is a tape.
+.It Cm ibs Ns = Ns Ar n
+Set the input block size to
+.Ar n
+bytes instead of the default 512.
+.It Cm if Ns = Ns Ar file
+Read input from
+.Ar file
+instead of the standard input.
+.It Cm iseek Ns = Ns Ar n
+Seek on the input file
+.Ar n
+blocks.
+This is synonymous with
+.Cm skip Ns = Ns Ar n .
+.It Cm obs Ns = Ns Ar n
+Set the output block size to
+.Ar n
+bytes instead of the default 512.
+.It Cm of Ns = Ns Ar file
+Write output to
+.Ar file
+instead of the standard output.
+Any regular output file is truncated unless the
+.Cm notrunc
+conversion value is specified.
+If an initial portion of the output file is seeked past (see the
+.Cm oseek
+operand),
+the output file is truncated at that point.
+.It Cm oseek Ns = Ns Ar n
+Seek on the output file
+.Ar n
+blocks.
+This is synonymous with
+.Cm seek Ns = Ns Ar n .
+.It Cm seek Ns = Ns Ar n
+Seek
+.Ar n
+blocks from the beginning of the output before copying.
+On non-tape devices, an
+.Xr lseek 2
+operation is used.
+Otherwise, existing blocks are read and the data discarded.
+If the user does not have read permission for the tape, it is positioned
+using the tape
+.Xr ioctl 2
+function calls.
+If the seek operation is past the end of file, space from the current
+end of file to the specified offset is filled with blocks of
+.Dv NUL
+bytes.
+.It Cm skip Ns = Ns Ar n
+Skip
+.Ar n
+blocks from the beginning of the input before copying.
+On input which supports seeks, an
+.Xr lseek 2
+operation is used.
+Otherwise, input data is read and discarded.
+For pipes, the correct number of bytes is read.
+For all other devices, the correct number of blocks is read without
+distinguishing between a partial or complete block being read.
+.It Cm conv Ns = Ns Ar value Ns Op , Ns Ar value ...
+Where
+.Cm value
+is one of the symbols from the following list.
+.Bl -tag -width ".Cm unblock"
+.It Cm ascii , oldascii
+The same as the
+.Cm unblock
+value except that characters are translated from
+.Tn EBCDIC
+to
+.Tn ASCII
+before the
+records are converted.
+(These values imply
+.Cm unblock
+if the operand
+.Cm cbs
+is also specified.)
+There are two conversion maps for
+.Tn ASCII .
+The value
+.Cm ascii
+specifies the recommended one which is compatible with
+.At V .
+The value
+.Cm oldascii
+specifies the one used in historic
+.At
+and
+.No pre- Ns Bx 4.3 reno
+systems.
+.It Cm block
+Treats the input as a sequence of newline or end-of-file terminated variable
+length records independent of input and output block boundaries.
+Any trailing newline character is discarded.
+Each input record is converted to a fixed length output record where the
+length is specified by the
+.Cm cbs
+operand.
+Input records shorter than the conversion record size are padded with spaces.
+Input records longer than the conversion record size are truncated.
+The number of truncated input records, if any, are reported to the standard
+error output at the completion of the copy.
+.It Cm ebcdic , ibm , oldebcdic , oldibm
+The same as the
+.Cm block
+value except that characters are translated from
+.Tn ASCII
+to
+.Tn EBCDIC
+after the
+records are converted.
+(These values imply
+.Cm block
+if the operand
+.Cm cbs
+is also specified.)
+There are four conversion maps for
+.Tn EBCDIC .
+The value
+.Cm ebcdic
+specifies the recommended one which is compatible with
+.At V .
+The value
+.Cm ibm
+is a slightly different mapping, which is compatible with the
+.At V
+.Cm ibm
+value.
+The values
+.Cm oldebcdic
+and
+.Cm oldibm
+are maps used in historic
+.At
+and
+.No pre- Ns Bx 4.3 reno
+systems.
+.It Cm lcase
+Transform uppercase characters into lowercase characters.
+.It Cm noerror
+Do not stop processing on an input error.
+When an input error occurs, a diagnostic message followed by the current
+input and output block counts will be written to the standard error output
+in the same format as the standard completion message.
+If the
+.Cm sync
+conversion is also specified, any missing input data will be replaced
+with
+.Dv NUL
+bytes (or with spaces if a block oriented conversion value was
+specified) and processed as a normal input buffer.
+If the
+.Cm sync
+conversion is not specified, the input block is omitted from the output.
+On input files which are not tapes or pipes, the file offset
+will be positioned past the block in which the error occurred using
+.Xr lseek 2 .
+.It Cm notrunc
+Do not truncate the output file.
+This will preserve any blocks in the output file not explicitly written
+by
+.Nm .
+The
+.Cm notrunc
+value is not supported for tapes.
+.It Cm osync
+Pad the final output block to the full output block size.
+If the input file is not a multiple of the output block size
+after conversion, this conversion forces the final output block
+to be the same size as preceding blocks for use on devices that require
+regularly sized blocks to be written.
+This option is incompatible with use of the
+.Cm bs Ns = Ns Ar n
+block size specification.
+.It Cm sparse
+If one or more output blocks would consist solely of
+.Dv NUL
+bytes, try to seek the output file by the required space instead of
+filling them with
+.Dv NUL Ns s ,
+resulting in a sparse file.
+.It Cm swab
+Swap every pair of input bytes.
+If an input buffer has an odd number of bytes, the last byte will be
+ignored during swapping.
+.It Cm sync
+Pad every input block to the input buffer size.
+Spaces are used for pad bytes if a block oriented conversion value is
+specified, otherwise
+.Dv NUL
+bytes are used.
+.It Cm ucase
+Transform lowercase characters into uppercase characters.
+.It Cm unblock
+Treats the input as a sequence of fixed length records independent of input
+and output block boundaries.
+The length of the input records is specified by the
+.Cm cbs
+operand.
+Any trailing space characters are discarded and a newline character is
+appended.
+.El
+.El
+.Pp
+Where sizes are specified, a decimal, octal, or hexadecimal number of
+bytes is expected.
+If the number ends with a
+.Dq Li b ,
+.Dq Li k ,
+.Dq Li m ,
+.Dq Li g ,
+or
+.Dq Li w ,
+the
+number is multiplied by 512, 1024 (1K), 1048576 (1M), 1073741824 (1G)
+or the number of bytes in an integer, respectively.
+Two or more numbers may be separated by an
+.Dq Li x
+to indicate a product.
+.Pp
+When finished,
+.Nm
+displays the number of complete and partial input and output blocks,
+truncated input records and odd-length byte-swapping blocks to the
+standard error output.
+A partial input block is one where less than the input block size
+was read.
+A partial output block is one where less than the output block size
+was written.
+Partial output blocks to tape devices are considered fatal errors.
+Otherwise, the rest of the block will be written.
+Partial output blocks to character devices will produce a warning message.
+A truncated input block is one where a variable length record oriented
+conversion value was specified and the input line was too long to
+fit in the conversion record or was not newline terminated.
+.Pp
+Normally, data resulting from input or conversion or both are aggregated
+into output blocks of the specified size.
+After the end of input is reached, any remaining output is written as
+a block.
+This means that the final output block may be shorter than the output
+block size.
+.Pp
+If
+.Nm
+receives a
+.Dv SIGINFO
+(see the
+.Cm status
+argument for
+.Xr stty 1 )
+signal, the current input and output block counts will
+be written to the standard error output
+in the same format as the standard completion message.
+If
+.Nm
+receives a
+.Dv SIGINT
+signal, the current input and output block counts will
+be written to the standard error output
+in the same format as the standard completion message and
+.Nm
+will exit.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr cp 1 ,
+.Xr tr 1
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2
+standard.
+The
+.Cm files
+operand and the
+.Cm ascii ,
+.Cm ebcdic ,
+.Cm ibm ,
+.Cm oldascii ,
+.Cm oldebcdic
+and
+.Cm oldibm
+values are extensions to the
+\*[Px]
+standard.
diff --git a/file_cmds/dd/dd.c b/file_cmds/dd/dd.c
new file mode 100644
index 0000000..5731186
--- /dev/null
+++ b/file_cmds/dd/dd.c
@@ -0,0 +1,481 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
+#endif
+__used static const char rcsid[] =
+ "$FreeBSD: src/bin/dd/dd.c,v 1.36 2002/03/07 14:00:33 markm Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/conf.h>
+#include <sys/filio.h>
+#include <sys/time.h>
+
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#else
+#include <sys/disklabel.h>
+#endif
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+static void dd_close(void);
+static void dd_in(void);
+static void getfdtype(IO *);
+static void setup(void);
+
+IO in, out; /* input/output state */
+STAT st; /* statistics */
+void (*cfunc)(void); /* conversion function */
+quad_t cpy_cnt; /* # of blocks to copy */
+off_t pending = 0; /* pending seek if sparse */
+u_int ddflags; /* conversion options */
+size_t cbsz; /* conversion block size */
+quad_t files_cnt = 1; /* # of files to copy */
+const u_char *ctab; /* conversion table */
+
+int
+main(int argc, char *argv[])
+{
+ (void)setlocale(LC_CTYPE, "");
+ jcl(argv);
+ setup();
+
+ (void)signal(SIGINFO, summaryx);
+ (void)signal(SIGINT, terminate);
+
+ atexit(summary);
+
+ while (files_cnt--)
+ dd_in();
+
+ dd_close();
+ exit(0);
+}
+
+static void
+setup(void)
+{
+ u_int cnt;
+ struct timeval tv;
+
+ if (in.name == NULL) {
+ in.name = "stdin";
+ in.fd = STDIN_FILENO;
+ } else {
+ in.fd = open(in.name, O_RDONLY, 0);
+ if (in.fd == -1)
+ err(1, "%s", in.name);
+ }
+
+ getfdtype(&in);
+
+ if (files_cnt > 1 && !(in.flags & ISTAPE))
+ errx(1, "files is not supported for non-tape devices");
+
+ if (out.name == NULL) {
+ /* No way to check for read access here. */
+ out.fd = STDOUT_FILENO;
+ out.name = "stdout";
+ } else {
+#define OFLAGS \
+ (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
+ out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
+ /*
+ * May not have read access, so try again with write only.
+ * Without read we may have a problem if output also does
+ * not support seeks.
+ */
+ if (out.fd == -1) {
+ out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
+ out.flags |= NOREAD;
+ }
+ if (out.fd == -1)
+ err(1, "%s", out.name);
+ }
+
+ getfdtype(&out);
+
+ /*
+ * Allocate space for the input and output buffers. If not doing
+ * record oriented I/O, only need a single buffer.
+ */
+ if (!(ddflags & (C_BLOCK | C_UNBLOCK))) {
+ if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
+ err(1, "input buffer");
+ out.db = in.db;
+ } else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL ||
+ (out.db = malloc(out.dbsz + cbsz)) == NULL)
+ err(1, "output buffer");
+ in.dbp = in.db;
+ out.dbp = out.db;
+
+ /* Position the input/output streams. */
+ if (in.offset)
+ pos_in();
+ if (out.offset)
+ pos_out();
+
+ /*
+ * Truncate the output file. If it fails on a type of output file
+ * that it should _not_ fail on, error out.
+ */
+ if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) &&
+ out.flags & ISTRUNC)
+ if (ftruncate(out.fd, out.offset * out.dbsz) == -1)
+ err(1, "truncating %s", out.name);
+
+ /*
+ * If converting case at the same time as another conversion, build a
+ * table that does both at once. If just converting case, use the
+ * built-in tables.
+ */
+ if (ddflags & (C_LCASE | C_UCASE)) {
+ if (ddflags & (C_ASCII | C_EBCDIC)) {
+ if (ddflags & C_LCASE) {
+ for (cnt = 0; cnt <= 0377; ++cnt)
+ casetab[cnt] = tolower(ctab[cnt]);
+ } else {
+ for (cnt = 0; cnt <= 0377; ++cnt)
+ casetab[cnt] = toupper(ctab[cnt]);
+ }
+ } else {
+ if (ddflags & C_LCASE) {
+ for (cnt = 0; cnt <= 0377; ++cnt)
+ casetab[cnt] = tolower((int)cnt);
+ } else {
+ for (cnt = 0; cnt <= 0377; ++cnt)
+ casetab[cnt] = toupper((int)cnt);
+ }
+ }
+ ctab = casetab;
+ }
+
+ (void)gettimeofday(&tv, (struct timezone *)NULL);
+ st.start = tv.tv_sec + tv.tv_usec * 1e-6;
+}
+
+static void
+getfdtype(IO *io)
+{
+ struct stat sb;
+ int type;
+
+ if (fstat(io->fd, &sb) == -1)
+ err(1, "%s", io->name);
+ if (S_ISREG(sb.st_mode))
+ io->flags |= ISTRUNC;
+ if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
+ if (ioctl(io->fd, FIODTYPE, &type) == -1) {
+ err(1, "%s", io->name);
+ } else {
+#ifdef __APPLE__ /* MacOSX uses enumeration for type not a bitmask */
+ if (type == D_TAPE)
+ io->flags |= ISTAPE;
+ else if (type == D_DISK || type == D_TTY) {
+#else /* !__APPLE__ */
+ if (type & D_TAPE)
+ io->flags |= ISTAPE;
+ else if (type & (D_DISK | D_MEM)) {
+ if (type & D_DISK) {
+ const int one = 1;
+
+ (void)ioctl(io->fd, DIOCWLABEL, &one);
+ }
+#endif /* __APPLE__ */
+ io->flags |= ISSEEK;
+ }
+#ifdef __APPLE__
+ if (S_ISCHR(sb.st_mode) && (type != D_TAPE))
+#else /* !__APPLE__ */
+ if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0)
+#endif /* __APPLE__ */
+ io->flags |= ISCHR;
+ }
+ return;
+ }
+ errno = 0;
+ if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
+ io->flags |= ISPIPE;
+ else
+ io->flags |= ISSEEK;
+}
+
+static void
+dd_in(void)
+{
+ ssize_t n;
+
+ for (;;) {
+ switch (cpy_cnt) {
+ case -1: /* count=0 was specified */
+ return;
+ case 0:
+ break;
+ default:
+ if (st.in_full + st.in_part >= (u_quad_t)cpy_cnt)
+ return;
+ break;
+ }
+
+ /*
+ * Zero the buffer first if sync; if doing block operations,
+ * use spaces.
+ */
+ if (ddflags & C_SYNC) {
+ if (ddflags & (C_BLOCK | C_UNBLOCK))
+ memset(in.dbp, ' ', in.dbsz);
+ else
+ memset(in.dbp, 0, in.dbsz);
+ }
+
+ n = read(in.fd, in.dbp, in.dbsz);
+ if (n == 0) {
+ in.dbrcnt = 0;
+ return;
+ }
+
+ /* Read error. */
+ if (n == -1) {
+ /*
+ * If noerror not specified, die. POSIX requires that
+ * the warning message be followed by an I/O display.
+ */
+ if (!(ddflags & C_NOERROR))
+ err(1, "%s", in.name);
+ warn("%s", in.name);
+ summary();
+
+ /*
+ * If it's a seekable file descriptor, seek past the
+ * error. If your OS doesn't do the right thing for
+ * raw disks this section should be modified to re-read
+ * in sector size chunks.
+ */
+ if (in.flags & ISSEEK &&
+ lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
+ warn("%s", in.name);
+
+ /* If sync not specified, omit block and continue. */
+ if (!(ddflags & C_SYNC))
+ continue;
+
+ /* Read errors count as full blocks. */
+ in.dbcnt += in.dbrcnt = in.dbsz;
+ ++st.in_full;
+
+ /* Handle full input blocks. */
+ } else if ((size_t)n == in.dbsz) {
+ in.dbcnt += in.dbrcnt = n;
+ ++st.in_full;
+
+ /* Handle partial input blocks. */
+ } else {
+ /* If sync, use the entire block. */
+ if (ddflags & C_SYNC)
+ in.dbcnt += in.dbrcnt = in.dbsz;
+ else
+ in.dbcnt += in.dbrcnt = n;
+ ++st.in_part;
+ }
+
+ /*
+ * POSIX states that if bs is set and no other conversions
+ * than noerror, notrunc or sync are specified, the block
+ * is output without buffering as it is read.
+ */
+ if (ddflags & C_BS) {
+ out.dbcnt = in.dbcnt;
+ dd_out(1);
+ in.dbcnt = 0;
+ continue;
+ }
+
+ if (ddflags & C_SWAB) {
+ if ((n = in.dbrcnt) & 1) {
+ ++st.swab;
+ --n;
+ }
+ swab(in.dbp, in.dbp, (size_t)n);
+ }
+
+ in.dbp += in.dbrcnt;
+ (*cfunc)();
+ }
+}
+
+/*
+ * Clean up any remaining I/O and flush output. If necessary, the output file
+ * is truncated.
+ */
+static void
+dd_close(void)
+{
+ if (cfunc == def)
+ def_close();
+ else if (cfunc == block)
+ block_close();
+ else if (cfunc == unblock)
+ unblock_close();
+ if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) {
+ if (ddflags & (C_BLOCK | C_UNBLOCK))
+ memset(out.dbp, ' ', out.dbsz - out.dbcnt);
+ else
+ memset(out.dbp, 0, out.dbsz - out.dbcnt);
+ out.dbcnt = out.dbsz;
+ }
+ if (out.dbcnt || pending)
+ dd_out(1);
+}
+
+void
+dd_out(int force)
+{
+ u_char *outp;
+ size_t cnt, i, n;
+ ssize_t nw;
+ static int warned;
+ int sparse;
+
+ /*
+ * Write one or more blocks out. The common case is writing a full
+ * output block in a single write; increment the full block stats.
+ * Otherwise, we're into partial block writes. If a partial write,
+ * and it's a character device, just warn. If a tape device, quit.
+ *
+ * The partial writes represent two cases. 1: Where the input block
+ * was less than expected so the output block was less than expected.
+ * 2: Where the input block was the right size but we were forced to
+ * write the block in multiple chunks. The original versions of dd(1)
+ * never wrote a block in more than a single write, so the latter case
+ * never happened.
+ *
+ * One special case is if we're forced to do the write -- in that case
+ * we play games with the buffer size, and it's usually a partial write.
+ */
+ outp = out.db;
+ for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
+ for (cnt = n;; cnt -= nw) {
+ sparse = 0;
+ if (ddflags & C_SPARSE) {
+ sparse = 1; /* Is buffer sparse? */
+ for (i = 0; i < cnt; i++)
+ if (outp[i] != 0) {
+ sparse = 0;
+ break;
+ }
+ }
+ if (sparse && !force) {
+ pending += cnt;
+ nw = cnt;
+ } else {
+ if (pending != 0) {
+ if (force)
+ pending--;
+ if (lseek(out.fd, pending, SEEK_CUR) ==
+ -1)
+ err(2, "%s: seek error creating sparse file",
+ out.name);
+ if (force)
+ write(out.fd, outp, 1);
+ pending = 0;
+ }
+ if (cnt)
+ nw = write(out.fd, outp, cnt);
+ else
+ return;
+ }
+
+ if (nw <= 0) {
+ if (nw == 0)
+ errx(1, "%s: end of device", out.name);
+ if (errno != EINTR)
+ err(1, "%s", out.name);
+ nw = 0;
+ }
+ outp += nw;
+ st.bytes += nw;
+ if ((size_t)nw == n) {
+ if (n != out.dbsz)
+ ++st.out_part;
+ else
+ ++st.out_full;
+ break;
+ }
+ ++st.out_part;
+ if ((size_t)nw == cnt)
+ break;
+ if (out.flags & ISTAPE)
+ errx(1, "%s: short write on tape device",
+ out.name);
+ if (out.flags & ISCHR && !warned) {
+ warned = 1;
+ warnx("%s: short write on character device",
+ out.name);
+ }
+ }
+ if ((out.dbcnt -= n) < out.dbsz)
+ break;
+ }
+
+ /* Reassemble the output block. */
+ if (out.dbcnt)
+ (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
+ out.dbp = out.db + out.dbcnt;
+}
diff --git a/file_cmds/dd/dd.entitlements b/file_cmds/dd/dd.entitlements
new file mode 100644
index 0000000..abb8bc5
--- /dev/null
+++ b/file_cmds/dd/dd.entitlements
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.private.security.disk-device-access</key>
+ <true/>
+</dict>
+</plist>
+
diff --git a/file_cmds/dd/dd.h b/file_cmds/dd/dd.h
new file mode 100644
index 0000000..c516ad2
--- /dev/null
+++ b/file_cmds/dd/dd.h
@@ -0,0 +1,102 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dd.h 8.3 (Berkeley) 4/2/94
+ * $FreeBSD: src/bin/dd/dd.h,v 1.17 2002/02/22 20:51:00 markm Exp $
+ */
+
+#ifndef _DD_H_
+#define _DD_H_
+
+/* Input/output stream state. */
+typedef struct {
+ u_char *db; /* buffer address */
+ u_char *dbp; /* current buffer I/O address */
+ /* XXX ssize_t? */
+ size_t dbcnt; /* current buffer byte count */
+ size_t dbrcnt; /* last read byte count */
+ size_t dbsz; /* buffer size */
+
+#define ISCHR 0x01 /* character device (warn on short) */
+#define ISPIPE 0x02 /* pipe-like (see position.c) */
+#define ISTAPE 0x04 /* tape */
+#define ISSEEK 0x08 /* valid to seek on */
+#define NOREAD 0x10 /* not readable */
+#define ISTRUNC 0x20 /* valid to ftruncate() */
+ u_int flags;
+
+ const char *name; /* name */
+ int fd; /* file descriptor */
+ off_t offset; /* # of blocks to skip */
+
+} IO;
+
+typedef struct {
+ u_quad_t in_full; /* # of full input blocks */
+ u_quad_t in_part; /* # of partial input blocks */
+ u_quad_t out_full; /* # of full output blocks */
+ u_quad_t out_part; /* # of partial output blocks */
+ u_quad_t trunc; /* # of truncated records */
+ u_quad_t swab; /* # of odd-length swab blocks */
+ u_quad_t bytes; /* # of bytes written */
+ double start; /* start time of dd */
+} STAT;
+
+/* Flags (in ddflags). */
+#define C_ASCII 0x00001
+#define C_BLOCK 0x00002
+#define C_BS 0x00004
+#define C_CBS 0x00008
+#define C_COUNT 0x00010
+#define C_EBCDIC 0x00020
+#define C_FILES 0x00040
+#define C_IBS 0x00080
+#define C_IF 0x00100
+#define C_LCASE 0x00200
+#define C_NOERROR 0x00400
+#define C_NOTRUNC 0x00800
+#define C_OBS 0x01000
+#define C_OF 0x02000
+#define C_SEEK 0x04000
+#define C_SKIP 0x08000
+#define C_SWAB 0x10000
+#define C_SYNC 0x20000
+#define C_UCASE 0x40000
+#define C_UNBLOCK 0x80000
+#define C_OSYNC 0x100000
+#define C_SPARSE 0x200000
+
+#endif /* _DD_H_ */
diff --git a/file_cmds/dd/extern.h b/file_cmds/dd/extern.h
new file mode 100644
index 0000000..0ae6330
--- /dev/null
+++ b/file_cmds/dd/extern.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.3 (Berkeley) 4/2/94
+ * $FreeBSD: src/bin/dd/extern.h,v 1.12 2002/02/02 06:24:12 imp Exp $
+ */
+
+#ifndef _DD_EXTERN_H_
+#define _DD_EXTERN_H_
+
+#include <sys/cdefs.h>
+
+void block(void);
+void block_close(void);
+void dd_out(int);
+void def(void);
+void def_close(void);
+void jcl(char **);
+void pos_in(void);
+void pos_out(void);
+void summary(void);
+void summaryx(int);
+void terminate(int);
+void unblock(void);
+void unblock_close(void);
+
+extern IO in, out;
+extern STAT st;
+extern void (*cfunc)(void);
+extern quad_t cpy_cnt;
+extern size_t cbsz;
+extern u_int ddflags;
+extern quad_t files_cnt;
+extern const u_char *ctab;
+extern const u_char a2e_32V[], a2e_POSIX[];
+extern const u_char e2a_32V[], e2a_POSIX[];
+extern const u_char a2ibm_32V[], a2ibm_POSIX[];
+extern u_char casetab[];
+
+#endif /* _DD_EXTERN_H_ */
diff --git a/file_cmds/dd/install_symlink.sh b/file_cmds/dd/install_symlink.sh
new file mode 100644
index 0000000..7e8665f
--- /dev/null
+++ b/file_cmds/dd/install_symlink.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -e
+set -x
+
+case "$PLATFORM_NAME" in
+iphoneos|appletvos|watchos|bridgeos)
+ ln -hfs /usr/local/bin/dd "$DSTROOT"/bin/dd
+ ;;
+macosx)
+ ;;
+*)
+ echo "Unsupported platform: $PLATFORM_NAME"
+ exit 1
+ ;;
+esac
+
diff --git a/file_cmds/dd/misc.c b/file_cmds/dd/misc.c
new file mode 100644
index 0000000..b220334
--- /dev/null
+++ b/file_cmds/dd/misc.c
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94";
+#endif
+__used static const char rcsid[] =
+ "$FreeBSD: src/bin/dd/misc.c,v 1.23 2002/02/02 06:24:12 imp Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+void
+summary(void)
+{
+ struct timeval tv;
+ double secs;
+ char buf[100];
+
+ (void)gettimeofday(&tv, (struct timezone *)NULL);
+ secs = tv.tv_sec + tv.tv_usec * 1e-6 - st.start;
+ if (secs < 1e-6)
+ secs = 1e-6;
+ /* Use snprintf(3) so that we don't reenter stdio(3). */
+ (void)snprintf(buf, sizeof(buf),
+ "%qu+%qu records in\n%qu+%qu records out\n",
+ st.in_full, st.in_part, st.out_full, st.out_part);
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ if (st.swab) {
+ (void)snprintf(buf, sizeof(buf), "%qu odd length swab %s\n",
+ st.swab, (st.swab == 1) ? "block" : "blocks");
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ }
+ if (st.trunc) {
+ (void)snprintf(buf, sizeof(buf), "%qu truncated %s\n",
+ st.trunc, (st.trunc == 1) ? "record" : "records");
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+ }
+ (void)snprintf(buf, sizeof(buf),
+ "%qu bytes transferred in %.6f secs (%.0f bytes/sec)\n",
+ st.bytes, secs, st.bytes / secs);
+ (void)write(STDERR_FILENO, buf, strlen(buf));
+}
+
+/* ARGSUSED */
+void
+summaryx(int notused)
+{
+ int save_errno = errno;
+
+ summary();
+ errno = save_errno;
+}
+
+/* ARGSUSED */
+void
+terminate(int sig)
+{
+
+ summary();
+ _exit(sig == 0 ? 0 : 1);
+}
diff --git a/file_cmds/dd/position.c b/file_cmds/dd/position.c
new file mode 100644
index 0000000..c110cd3
--- /dev/null
+++ b/file_cmds/dd/position.c
@@ -0,0 +1,169 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego and Lance
+ * Visser of Convex Computer Corporation.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)position.c 8.3 (Berkeley) 4/2/94";
+#endif
+__used static const char rcsid[] =
+ "$FreeBSD: src/bin/dd/position.c,v 1.20 2002/02/02 06:24:12 imp Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include "dd.h"
+#include "extern.h"
+
+/*
+ * Position input/output data streams before starting the copy. Device type
+ * dependent. Seekable devices use lseek, and the rest position by reading.
+ * Seeking past the end of file can cause null blocks to be written to the
+ * output.
+ */
+void
+pos_in(void)
+{
+ off_t cnt;
+ int warned;
+ ssize_t nr;
+ size_t bcnt;
+
+ /* If known to be seekable, try to seek on it. */
+ if (in.flags & ISSEEK) {
+ errno = 0;
+ if (lseek(in.fd, in.offset * in.dbsz, SEEK_CUR) == -1 &&
+ errno != 0)
+ err(1, "%s", in.name);
+ return;
+ }
+
+ /* Don't try to read a really weird amount (like negative). */
+ if (in.offset < 0)
+ errx(1, "%s: illegal offset", "iseek/skip");
+
+ /*
+ * Read the data. If a pipe, read until satisfy the number of bytes
+ * being skipped. No differentiation for reading complete and partial
+ * blocks for other devices.
+ */
+ for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
+ if ((nr = read(in.fd, in.db, bcnt)) > 0) {
+ if (in.flags & ISPIPE) {
+ if (!(bcnt -= nr)) {
+ bcnt = in.dbsz;
+ --cnt;
+ }
+ } else
+ --cnt;
+ continue;
+ }
+
+ if (nr == 0) {
+ if (files_cnt > 1) {
+ --files_cnt;
+ continue;
+ }
+ errx(1, "skip reached end of input");
+ }
+
+ /*
+ * Input error -- either EOF with no more files, or I/O error.
+ * If noerror not set die. POSIX requires that the warning
+ * message be followed by an I/O display.
+ */
+ if (ddflags & C_NOERROR) {
+ if (!warned) {
+ warn("%s", in.name);
+ warned = 1;
+ summary();
+ }
+ continue;
+ }
+ err(1, "%s", in.name);
+ }
+}
+
+void
+pos_out(void)
+{
+ off_t cnt;
+ ssize_t n;
+
+ /*
+ * If not a tape, try seeking on the file. Seeking on a pipe is
+ * going to fail, but don't protect the user -- they shouldn't
+ * have specified the seek operand.
+ */
+ if (out.flags & (ISSEEK | ISPIPE)) {
+ errno = 0;
+ if (lseek(out.fd, out.offset * out.dbsz, SEEK_CUR) == -1 &&
+ errno != 0)
+ err(1, "%s", out.name);
+ return;
+ }
+
+ /* Don't try to read a really weird amount (like negative). */
+ if (out.offset < 0)
+ errx(1, "%s: illegal offset", "oseek/seek");
+
+ /* Read it. */
+ for (cnt = 0; cnt < out.offset; ++cnt) {
+ if ((n = read(out.fd, out.db, out.dbsz)) > 0)
+ continue;
+
+ if (n == -1)
+ err(1, "%s", out.name);
+
+ while (cnt++ < out.offset) {
+ n = write(out.fd, out.db, out.dbsz);
+ if (n == -1)
+ err(1, "%s", out.name);
+ if ((size_t)n != out.dbsz)
+ errx(1, "%s: write failure", out.name);
+ }
+ break;
+ }
+}
diff --git a/file_cmds/df/df.1 b/file_cmds/df/df.1
new file mode 100644
index 0000000..4560ab9
--- /dev/null
+++ b/file_cmds/df/df.1
@@ -0,0 +1,217 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)df.1 8.3 (Berkeley) 5/8/95
+.\" $FreeBSD: src/bin/df/df.1,v 1.18.2.7 2002/04/22 22:17:36 keramida Exp $
+.\"
+.Dd May 8, 1995
+.Dt DF 1
+.Os
+.Sh NAME
+.Nm df
+.Nd display free disk space
+.Sh SYNOPSIS
+.Nm df
+.Oo
+.Fl b | h | H | k |
+.Fl m | g | P
+.Oc
+.Op Fl ailn
+.Op Fl t
+.Op Fl T Ar type
+.Op Ar file | filesystem ...
+.Sh LEGACY SYNOPSIS
+.Nm df
+.Oo
+.Fl b | h | H | k |
+.Fl m | P
+.Oc
+.Op Fl ailn
+.Op Fl t Ar type
+.Op Fl T Ar type
+.Op Ar file | filesystem ...
+.Sh DESCRIPTION
+The
+.Nm df
+utility
+displays statistics about the amount of free disk space on the specified
+.Ar filesystem
+or on the filesystem of which
+.Ar file
+is a part.
+Values are displayed in 512-byte per block counts.
+If neither a file or a filesystem operand is specified,
+statistics for all mounted filesystems are displayed
+(subject to the
+.Fl t
+option below).
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl a
+Show all mount points, including those that were mounted with the MNT_IGNORE
+flag.
+.It Fl b
+Use (the default) 512-byte blocks.
+This is only useful as a way to override an
+.Ev BLOCKSIZE
+specification from the environment.
+.It Fl g
+Use 1073741824-byte (1-Gbyte) blocks rather than the default.
+Note that this overrides the
+.Ev BLOCKSIZE
+specification from the environment.
+.It Fl H
+"Human-readable" output. Use unit suffixes: Byte, Kilobyte, Megabyte,
+Gigabyte, Terabyte and Petabyte in order to reduce the number of
+digits to three or less using base 10 for sizes.
+.It Fl h
+"Human-readable" output. Use unit suffixes: Byte, Kilobyte, Megabyte,
+Gigabyte, Terabyte and Petabyte in order to reduce the number of
+digits to three or less using base 2 for sizes.
+.It Fl i
+Include statistics on the number of free inodes. This option is now the default to conform to
+.St -susv3
+Use
+.Fl P
+to suppress this output.
+.It Fl k
+Use 1024-byte (1-Kbyte) blocks, rather than the default.
+Note that this overrides the
+.Ev BLOCKSIZE
+specification from the environment.
+.It Fl l
+Only display information about locally-mounted filesystems.
+.It Fl m
+Use 1048576-byte (1-Mbyte) blocks rather than the default. Note that
+this overrides the
+.Ev BLOCKSIZE
+specification from the environment.
+.It Fl n
+Print out the previously obtained statistics from the filesystems.
+This option should be used if it is possible that one or more
+filesystems are in a state such that they will not be able to provide
+statistics without a long delay.
+When this option is specified,
+.Nm df
+will not request new statistics from the filesystems, but will respond
+with the possibly stale statistics that were previously obtained.
+.It Fl P
+Use (the default) 512-byte blocks.
+This is only useful as a way to override an
+.Ev BLOCKSIZE
+specification from the environment.
+.It Fl T
+Only print out statistics for filesystems of the specified types.
+More than one type may be specified in a comma separated list.
+The list of filesystem types can be prefixed with
+.Dq no
+to specify the filesystem types for which action should
+.Em not
+be taken.
+For example, the
+.Nm df
+command:
+.Bd -literal -offset indent
+df -T nonfs,mfs
+.Ed
+.Pp
+lists all filesystems except those of type
+.Tn NFS
+and
+.Tn MFS .
+The
+.Xr lsvfs 1
+command can be used to find out the types of filesystems
+that are available on the system.
+.It Fl t
+If used with no arguments,
+this option is a no-op
+(Mac OS X already prints the total allocated-space figures).
+If used with an argument, it acts like
+.Fl T ,
+but this usage is deprecated and should not be relied upon.
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environment variable
+.Ev BLOCKSIZE
+is set, the block counts will be displayed in units of that size block.
+.El
+.Sh BUGS
+The
+.Fl n
+and
+.Fl t
+flags are ignored if a file or filesystem is specified.
+.Sh LEGACY DESCRIPTION
+The "capacity" percentage is normally rounded up to the next higher integer.
+In legacy mode, it is rounded down to the next lower integer.
+.Pp
+When the
+.Fl P
+option and the
+.Fl k
+option are used together,
+sizes are reported in 1024-blocks.
+In legacy mode, when the
+.Fl P
+option and
+.Fl k
+option are used together,
+the last option specified dictates the reported block size.
+.Pp
+The
+.Fl t
+option is normally a no-op
+(Mac OS X already prints the total allocated-space figures).
+In legacy mode, it is equivalent to
+.Fl T .
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr lsvfs 1 ,
+.Xr quota 1 ,
+.Xr fstatfs 2 ,
+.Xr getfsstat 2 ,
+.Xr statfs 2 ,
+.Xr getmntinfo 3 ,
+.Xr compat 5 ,
+.Xr fstab 5 ,
+.Xr mount 8 ,
+.Xr quot 8
+.Sh HISTORY
+A
+.Nm df
+command appeared in
+.At v1 .
diff --git a/file_cmds/df/df.c b/file_cmds/df/df.c
new file mode 100644
index 0000000..7e576d7
--- /dev/null
+++ b/file_cmds/df/df.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 1980, 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1980, 1990, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)df.c 8.9 (Berkeley) 5/8/95";
+#else
+__used static const char rcsid[] =
+ "$FreeBSD: src/bin/df/df.c,v 1.23.2.9 2002/07/01 00:14:24 iedowse Exp $";
+#endif
+#endif /* not lint */
+
+#ifdef __APPLE__
+#define MNT_IGNORE 0
+#endif
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/sysctl.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <libutil.h>
+
+#ifdef __APPLE__
+#include "get_compat.h"
+#else
+#define COMPAT_MODE(func, mode) 1
+#endif
+
+#define UNITS_SI 1
+#define UNITS_2 2
+
+#define KILO_SZ(n) (n)
+#define MEGA_SZ(n) ((n) * (n))
+#define GIGA_SZ(n) ((n) * (n) * (n))
+#define TERA_SZ(n) ((n) * (n) * (n) * (n))
+#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
+
+#define KILO_2_SZ (KILO_SZ(1024ULL))
+#define MEGA_2_SZ (MEGA_SZ(1024ULL))
+#define GIGA_2_SZ (GIGA_SZ(1024ULL))
+#define TERA_2_SZ (TERA_SZ(1024ULL))
+#define PETA_2_SZ (PETA_SZ(1024ULL))
+
+#define KILO_SI_SZ (KILO_SZ(1000ULL))
+#define MEGA_SI_SZ (MEGA_SZ(1000ULL))
+#define GIGA_SI_SZ (GIGA_SZ(1000ULL))
+#define TERA_SI_SZ (TERA_SZ(1000ULL))
+#define PETA_SI_SZ (PETA_SZ(1000ULL))
+
+/* Maximum widths of various fields. */
+struct maxwidths {
+ int mntfrom;
+ int total;
+ int used;
+ int avail;
+ int iused;
+ int ifree;
+};
+
+unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ};
+unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
+unsigned long long *valp;
+
+typedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t;
+
+unit_t unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA };
+
+int bread(off_t, void *, int);
+int checkvfsname(const char *, char **);
+char *getmntpt(char *);
+int int64width(int64_t);
+char *makenetvfslist(void);
+char **makevfslist(const char *);
+void prthuman(struct statfs *, uint64_t);
+void prthumanval(int64_t);
+void prtstat(struct statfs *, struct maxwidths *);
+long regetmntinfo(struct statfs **, long, char **);
+unit_t unit_adjust(double *);
+void update_maxwidths(struct maxwidths *, struct statfs *);
+void usage(void);
+
+int aflag = 0, hflag, iflag, nflag;
+
+static __inline int imax(int a, int b)
+{
+ return (a > b ? a : b);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct stat stbuf;
+ struct statfs statfsbuf, *mntbuf;
+ struct maxwidths maxwidths;
+ char *mntpt, **vfslist;
+ long mntsize;
+ int ch, i, rv, tflag = 0, kludge_tflag = 0;
+ int kflag = 0;
+ const char *options = "abgHhiklmnPt:T:";
+ if (COMPAT_MODE("bin/df", "unix2003")) {
+ /* Unix2003 requires -t be "include total capacity". which df
+ already does, but it conflicts with the old -t so we need to
+ *not* expect a string after -t (we provide -T in both cases
+ to cover the old use of -t) */
+ options = "abgHhiklmnPtT:";
+ iflag = 1;
+ }
+
+ vfslist = NULL;
+ while ((ch = getopt(argc, argv, options)) != -1)
+ switch (ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'b':
+ /* FALLTHROUGH */
+ case 'P':
+ if (COMPAT_MODE("bin/df", "unix2003")) {
+ if (!kflag) {
+ /* -k overrides -P */
+ putenv("BLOCKSIZE=512");
+ }
+ iflag = 0;
+ } else {
+ putenv("BLOCKSIZE=512");
+ }
+ hflag = 0;
+ break;
+ case 'g':
+ putenv("BLOCKSIZE=1g");
+ hflag = 0;
+ break;
+ case 'H':
+ hflag = UNITS_SI;
+ valp = vals_si;
+ break;
+ case 'h':
+ hflag = UNITS_2;
+ valp = vals_base2;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'k':
+ if (COMPAT_MODE("bin/df", "unix2003")) {
+ putenv("BLOCKSIZE=1024");
+ } else {
+ putenv("BLOCKSIZE=1k");
+ }
+ kflag = 1;
+ hflag = 0;
+ break;
+ case 'l':
+ if (tflag)
+ errx(1, "-l and -T are mutually exclusive.");
+ if (vfslist != NULL)
+ break;
+ vfslist = makevfslist(makenetvfslist());
+ break;
+ case 'm':
+ putenv("BLOCKSIZE=1m");
+ hflag = 0;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 't':
+ /* Unix2003 uses -t for something we do by default */
+ if (COMPAT_MODE("bin/df", "unix2003")) {
+ kludge_tflag = 1;
+ break;
+ }
+ case 'T':
+ if (vfslist != NULL) {
+ if (tflag)
+ errx(1, "only one -%c option may be specified", ch);
+ else
+ errx(1, "-l and -%c are mutually exclusive.", ch);
+ }
+ tflag++;
+ vfslist = makevfslist(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* If we are in unix2003 mode, have seen a -t but no -T and the first
+ non switch arg isn't a file, let's pretend they used -T on it.
+ This makes the Lexmark printer installer happy (PR-3918471) */
+ if (tflag == 0 && kludge_tflag && *argv && stat(*argv, &stbuf) < 0
+ && errno == ENOENT) {
+ vfslist = makevfslist(*argv++);
+ }
+
+ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+ bzero(&maxwidths, sizeof(maxwidths));
+ for (i = 0; i < mntsize; i++)
+ update_maxwidths(&maxwidths, &mntbuf[i]);
+
+ rv = 0;
+ if (!*argv) {
+ mntsize = regetmntinfo(&mntbuf, mntsize, vfslist);
+ bzero(&maxwidths, sizeof(maxwidths));
+ for (i = 0; i < mntsize; i++)
+ update_maxwidths(&maxwidths, &mntbuf[i]);
+ for (i = 0; i < mntsize; i++) {
+ if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
+ prtstat(&mntbuf[i], &maxwidths);
+ }
+ exit(rv);
+ }
+
+ for (; *argv; argv++) {
+ if (stat(*argv, &stbuf) < 0) {
+ if ((mntpt = getmntpt(*argv)) == 0) {
+ warn("%s", *argv);
+ rv = 1;
+ continue;
+ }
+ } else if (S_ISCHR(stbuf.st_mode) || S_ISBLK(stbuf.st_mode)) {
+ warnx("%s: Raw devices not supported", *argv);
+ rv = 1;
+ continue;
+ } else
+ mntpt = *argv;
+ /*
+ * Statfs does not take a `wait' flag, so we cannot
+ * implement nflag here.
+ */
+ if (statfs(mntpt, &statfsbuf) < 0) {
+ warn("%s", mntpt);
+ rv = 1;
+ continue;
+ }
+ /* Check to make sure the arguments we've been
+ * given are satisfied. Return an error if we
+ * have been asked to list a mount point that does
+ * not match the other args we've been given (-l, -t, etc.)
+ */
+ if (checkvfsname(statfsbuf.f_fstypename, vfslist)) {
+ rv++;
+ continue;
+ }
+
+ if (argc == 1) {
+ bzero(&maxwidths, sizeof(maxwidths));
+ update_maxwidths(&maxwidths, &statfsbuf);
+ }
+ prtstat(&statfsbuf, &maxwidths);
+ }
+ return (rv);
+}
+
+char *
+getmntpt(char *name)
+{
+ long mntsize, i;
+ struct statfs *mntbuf;
+
+ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+ for (i = 0; i < mntsize; i++) {
+ if (!strcmp(mntbuf[i].f_mntfromname, name))
+ return (mntbuf[i].f_mntonname);
+ }
+ return (0);
+}
+
+/*
+ * Make a pass over the filesystem info in ``mntbuf'' filtering out
+ * filesystem types not in vfslist and possibly re-stating to get
+ * current (not cached) info. Returns the new count of valid statfs bufs.
+ */
+long
+regetmntinfo(struct statfs **mntbufp, long mntsize, char **vfslist)
+{
+ int i, j;
+ struct statfs *mntbuf;
+
+ if (vfslist == NULL)
+ return (nflag ? mntsize : getmntinfo(mntbufp, MNT_WAIT));
+
+ mntbuf = *mntbufp;
+ for (j = 0, i = 0; i < mntsize; i++) {
+ if (checkvfsname(mntbuf[i].f_fstypename, vfslist))
+ continue;
+ if (!nflag)
+ (void)statfs(mntbuf[i].f_mntonname,&mntbuf[j]);
+ else if (i != j)
+ mntbuf[j] = mntbuf[i];
+ j++;
+ }
+ return (j);
+}
+
+/*
+ * Output in "human-readable" format. Uses 3 digits max and puts
+ * unit suffixes at the end. Makes output compact and easy to read,
+ * especially on huge disks.
+ *
+ */
+unit_t
+unit_adjust(double *val)
+{
+ double abval;
+ unit_t unit;
+ unsigned int unit_sz;
+
+ abval = fabs(*val);
+
+ unit_sz = abval ? ilogb(abval) / 10 : 0;
+
+ if (unit_sz >= UNIT_MAX) {
+ unit = NONE;
+ } else {
+ unit = unitp[unit_sz];
+ *val /= (double)valp[unit_sz];
+ }
+
+ return (unit);
+}
+
+void
+prthuman(struct statfs *sfsp, uint64_t used)
+{
+ int64_t value;
+
+ value = sfsp->f_blocks;
+ value *= sfsp->f_bsize;
+ prthumanval(value);
+ value = used;
+ value *= sfsp->f_bsize;
+ prthumanval(value);
+ value = sfsp->f_bavail;
+ value *= sfsp->f_bsize;
+ prthumanval(value);
+}
+
+void
+prthumanval(int64_t bytes)
+{
+ char buf[6];
+ int flags;
+
+ flags = HN_B | HN_NOSPACE | HN_DECIMAL;
+ if (hflag == UNITS_SI)
+ flags |= HN_DIVISOR_1000;
+
+ humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
+ bytes, "", HN_AUTOSCALE, flags);
+
+ if (hflag == UNITS_SI)
+ (void)printf(" %6s", buf);
+ else
+ (void)printf("%6si", buf);
+
+}
+
+/*
+ * Convert statfs returned filesystem size into BLOCKSIZE units.
+ * Attempts to avoid overflow for large filesystems.
+ */
+static intmax_t fsbtoblk(int64_t num, uint64_t fsbs, u_long bs, char *fs)
+{
+ if (num < 0) {
+ warnx("negative filesystem block count/size from fs %s", fs);
+ return 0;
+ } else if ((fsbs != 0) && (fsbs < bs)) {
+ return (num / (intmax_t) (bs / fsbs));
+ } else {
+ return (num * (intmax_t) (fsbs / bs));
+ }
+}
+
+/*
+ * Print out status about a filesystem.
+ */
+void
+prtstat(struct statfs *sfsp, struct maxwidths *mwp)
+{
+ static long blocksize;
+ static int headerlen, timesthrough;
+ static const char *header;
+ uint64_t used, availblks, inodes;
+ char * avail_str;
+
+ if (++timesthrough == 1) {
+ mwp->mntfrom = imax(mwp->mntfrom, (int)strlen("Filesystem"));
+ if (hflag) {
+ header = " Size";
+ mwp->total = mwp->used = mwp->avail = (int)strlen(header);
+ } else {
+ header = getbsize(&headerlen, &blocksize);
+ mwp->total = imax(mwp->total, headerlen);
+ }
+ mwp->used = imax(mwp->used, (int)strlen("Used"));
+ if (COMPAT_MODE("bin/df", "unix2003") && !hflag) {
+ avail_str = "Available";
+ } else {
+ avail_str = "Avail";
+ }
+ mwp->avail = imax(mwp->avail, (int)strlen(avail_str));
+
+ (void)printf("%-*s %*s %*s %*s Capacity", mwp->mntfrom,
+ "Filesystem", mwp->total, header, mwp->used, "Used",
+ mwp->avail, avail_str);
+ if (iflag) {
+ mwp->iused = imax(mwp->iused, (int)strlen(" iused"));
+ mwp->ifree = imax(mwp->ifree, (int)strlen("ifree"));
+ (void)printf(" %*s %*s %%iused", mwp->iused - 2,
+ "iused", mwp->ifree, "ifree");
+ }
+ (void)printf(" Mounted on\n");
+ }
+
+ (void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname);
+ if (sfsp->f_blocks > sfsp->f_bfree)
+ used = sfsp->f_blocks - sfsp->f_bfree;
+ else
+ used = 0;
+ availblks = sfsp->f_bavail + used;
+ if (hflag) {
+ prthuman(sfsp, used);
+ } else {
+ (void)printf(" %*jd %*jd %*jd", mwp->total,
+ fsbtoblk(sfsp->f_blocks, sfsp->f_bsize, blocksize, sfsp->f_mntonname),
+ mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize, sfsp->f_mntonname),
+ mwp->avail, fsbtoblk(sfsp->f_bavail, sfsp->f_bsize, blocksize, sfsp->f_mntonname));
+ }
+ if (COMPAT_MODE("bin/df", "unix2003")) {
+ /* Standard says percentage must be rounded UP to next
+ integer value, not truncated */
+ double value;
+ if (availblks == 0)
+ value = 100.0;
+ else {
+ value = (double)used / (double)availblks * 100.0;
+ if ((value-(int)value) > 0.0) value = value + 1.0;
+ }
+ (void)printf(" %5.0f%%", trunc(value));
+ } else {
+ (void)printf(" %5.0f%%",
+ availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
+ }
+ if (iflag) {
+ inodes = sfsp->f_files;
+ used = inodes - sfsp->f_ffree;
+ (void)printf(" %*llu %*llu %4.0f%% ", mwp->iused, used,
+ mwp->ifree, sfsp->f_ffree, inodes == 0 ? 100.0 :
+ (double)used / (double)inodes * 100.0);
+ } else
+ (void)printf(" ");
+ (void)printf(" %s\n", sfsp->f_mntonname);
+}
+
+/*
+ * Update the maximum field-width information in `mwp' based on
+ * the filesystem specified by `sfsp'.
+ */
+void
+update_maxwidths(struct maxwidths *mwp, struct statfs *sfsp)
+{
+ static long blocksize;
+ int dummy;
+
+ if (blocksize == 0)
+ getbsize(&dummy, &blocksize);
+
+ mwp->mntfrom = imax(mwp->mntfrom, (int)strlen(sfsp->f_mntfromname));
+ mwp->total = imax(mwp->total, int64width(fsbtoblk(sfsp->f_blocks,
+ sfsp->f_bsize, blocksize, sfsp->f_mntonname)));
+ if (sfsp->f_blocks >= sfsp->f_bfree)
+ mwp->used = imax(mwp->used, int64width(fsbtoblk(sfsp->f_blocks -
+ sfsp->f_bfree, sfsp->f_bsize, blocksize, sfsp->f_mntonname)));
+ mwp->avail = imax(mwp->avail, int64width(fsbtoblk(sfsp->f_bavail,
+ sfsp->f_bsize, blocksize, sfsp->f_mntonname)));
+ mwp->iused = imax(mwp->iused, int64width(sfsp->f_files - sfsp->f_ffree));
+ mwp->ifree = imax(mwp->ifree, int64width(sfsp->f_ffree));
+}
+
+/* Return the width in characters of the specified long. */
+int
+int64width(int64_t val)
+{
+ int len;
+
+ len = 0;
+ /* Negative or zero values require one extra digit. */
+ if (val <= 0) {
+ val = -val;
+ len++;
+ }
+ while (val > 0) {
+ len++;
+ val /= 10;
+ }
+
+ return (len);
+}
+
+void
+usage(void)
+{
+
+ char *t_flag = COMPAT_MODE("bin/df", "unix2003") ? "[-t]" : "[-t type]";
+ (void)fprintf(stderr,
+ "usage: df [-b | -H | -h | -k | -m | -g | -P] [-ailn] [-T type] %s [filesystem ...]\n", t_flag);
+ exit(EX_USAGE);
+}
+
+char *
+makenetvfslist(void)
+{
+ char *str, *strptr, **listptr;
+#ifndef __APPLE__
+ int mib[3], maxvfsconf, cnt=0, i;
+ size_t miblen;
+ struct ovfsconf *ptr;
+#else
+ int mib[4], maxvfsconf, cnt=0, i;
+ size_t miblen;
+ struct vfsconf vfc;
+#endif
+
+ mib[0] = CTL_VFS; mib[1] = VFS_GENERIC; mib[2] = VFS_MAXTYPENUM;
+ miblen=sizeof(maxvfsconf);
+ if (sysctl(mib, 3,
+ &maxvfsconf, &miblen, NULL, 0)) {
+ warn("sysctl failed");
+ return (NULL);
+ }
+
+ if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) {
+ warnx("malloc failed");
+ return (NULL);
+ }
+
+#ifndef __APPLE__
+ for (ptr = getvfsent(); ptr; ptr = getvfsent())
+ if (ptr->vfc_flags & VFCF_NETWORK) {
+ listptr[cnt++] = strdup(ptr->vfc_name);
+ if (listptr[cnt-1] == NULL) {
+ warnx("malloc failed");
+ return (NULL);
+ }
+ }
+#else
+ miblen = sizeof (struct vfsconf);
+ mib[2] = VFS_CONF;
+ for (i = 0; i < maxvfsconf; i++) {
+ mib[3] = i;
+ if (sysctl(mib, 4, &vfc, &miblen, NULL, 0) == 0) {
+ if (!(vfc.vfc_flags & MNT_LOCAL)) {
+ listptr[cnt++] = strdup(vfc.vfc_name);
+ if (listptr[cnt-1] == NULL) {
+ free(listptr);
+ warnx("malloc failed");
+ return (NULL);
+ }
+ }
+ }
+ }
+#endif
+
+ if (cnt == 0 ||
+ (str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) {
+ if (cnt > 0)
+ warnx("malloc failed");
+ free(listptr);
+ return (NULL);
+ }
+
+ *str = 'n'; *(str + 1) = 'o';
+ for (i = 0, strptr = str + 2; i < cnt; i++, strptr++) {
+ strncpy(strptr, listptr[i], 32);
+ strptr += strlen(listptr[i]);
+ *strptr = ',';
+ free(listptr[i]);
+ }
+ *(--strptr) = '\0';
+
+ free(listptr);
+ return (str);
+}
diff --git a/file_cmds/df/vfslist.c b/file_cmds/df/vfslist.c
new file mode 100644
index 0000000..36b789b
--- /dev/null
+++ b/file_cmds/df/vfslist.c
@@ -0,0 +1,103 @@
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)vfslist.c 8.1 (Berkeley) 5/8/95";
+#endif
+__used static const char rcsid[] =
+ "$FreeBSD: src/sbin/mount/vfslist.c,v 1.4 1999/08/28 00:13:27 peter Exp $";
+#endif /* not lint */
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef __APPLE__
+#include "extern.h"
+#endif
+
+static int skipvfs;
+
+int checkvfsname(const char *, const char **);
+const char **makevfslist(const char *);
+
+int
+checkvfsname(vfsname, vfslist)
+ const char *vfsname;
+ const char **vfslist;
+{
+
+ if (vfslist == NULL)
+ return (0);
+ while (*vfslist != NULL) {
+ if (strcmp(vfsname, *vfslist) == 0)
+ return (skipvfs);
+ ++vfslist;
+ }
+ return (!skipvfs);
+}
+
+const char **
+makevfslist(fslist)
+ const char *fslist;
+{
+ const char **av;
+ int i;
+ const char *cnextcp;
+ char *nextcp;
+
+ if (fslist == NULL)
+ return (NULL);
+ if (fslist[0] == 'n' && fslist[1] == 'o') {
+ fslist += 2;
+ skipvfs = 1;
+ }
+ for (i = 0, cnextcp = fslist; *cnextcp; cnextcp++)
+ if (*cnextcp == ',')
+ i++;
+ if ((av = malloc((size_t)(i + 2) * sizeof(char *))) == NULL) {
+ warnx("malloc failed");
+ return (NULL);
+ }
+ nextcp = strdup(fslist);
+ i = 0;
+ av[i++] = nextcp;
+ while ((nextcp = strchr(nextcp, ',')) != NULL) {
+ *nextcp++ = '\0';
+ av[i++] = nextcp;
+ }
+ av[i++] = NULL;
+ return (av);
+}
diff --git a/file_cmds/du/du.1 b/file_cmds/du/du.1
new file mode 100644
index 0000000..1bc6b2b
--- /dev/null
+++ b/file_cmds/du/du.1
@@ -0,0 +1,172 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)du.1 8.2 (Berkeley) 4/1/94
+.\" $FreeBSD: src/usr.bin/du/du.1,v 1.30 2005/05/21 09:55:05 ru Exp $
+.\"
+.Dd June 2, 2004
+.Dt DU 1
+.Os
+.Sh NAME
+.Nm du
+.Nd display disk usage statistics
+.Sh SYNOPSIS
+.Nm du
+.Op Fl H | L | P
+.Op Fl a | s | d Ar depth
+.Op Fl c
+.Op Fl h | k | m | g
+.Op Fl x
+.Op Fl I Ar mask
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm du
+utility displays the file system block usage for each file argument
+and for each directory in the file hierarchy rooted in each directory
+argument.
+If no file is specified, the block usage of the hierarchy rooted in
+the current directory is displayed.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl a
+Display an entry for each file in a file hierarchy.
+.It Fl c
+Display a grand total.
+.It Fl d Ar depth
+Display an entry for all files and directories
+.Ar depth
+directories deep.
+.It Fl H
+Symbolic links on the command line are followed, symbolic links in file
+hierarchies are not followed.
+.It Fl h
+"Human-readable" output.
+Use unit suffixes: Byte, Kilobyte, Megabyte,
+Gigabyte, Terabyte and Petabyte.
+.It Fl I Ar mask
+Ignore files and directories matching the specified
+.Ar mask .
+.It Fl g
+Display block counts in 1073741824-byte (1-Gbyte) blocks.
+.It Fl k
+Display block counts in 1024-byte (1-Kbyte) blocks.
+.It Fl L
+Symbolic links on the command line and in file hierarchies are followed.
+.It Fl m
+Display block counts in 1048576-byte (1-Mbyte) blocks.
+.It Fl P
+No symbolic links are followed.
+This is the default.
+.It Fl r
+Generate messages about directories that cannot be read, files
+that cannot be opened, and so on.
+This is the default case.
+This option exists solely for conformance with
+.St -xpg4 .
+.It Fl s
+Display an entry for each specified file.
+(Equivalent to
+.Fl d Li 0 )
+.It Fl x
+File system mount points are not traversed.
+.El
+.Pp
+The
+.Nm du
+utility counts the storage used by symbolic links and not the files they
+reference unless the
+.Fl H
+or
+.Fl L
+option is specified.
+If either the
+.Fl H
+or
+.Fl L
+options are specified, storage used by any symbolic links which are
+followed is not counted or displayed.
+If more than one of the
+.Fl H ,
+.Fl L ,
+and
+.Fl P
+options is specified, the last one given is used.
+.Pp
+Files having multiple hard links are counted (and displayed) a single
+time per
+.Nm du
+execution.
+Directories having multiple hard links (typically Time Machine backups) are
+counted a single time per
+.Nm du
+execution.
+.Sh ENVIRONMENT
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environment variable
+.Ev BLOCKSIZE
+is set, and the
+.Fl k
+option is not specified, the block counts will be displayed in units of that
+size block.
+If
+.Ev BLOCKSIZE
+is not set, and the
+.Fl k
+option is not specified, the block counts will be displayed in 512-byte blocks.
+.El
+.Sh LEGACY DESCRIPTION
+In legacy mode, only one of the
+.Fl H ,
+.Fl L ,
+or
+.Fl P
+options may be specified.
+.Pp
+The command will detect and report a SYMLOOP error
+(loop involving symbolic links).
+In legacy mode, this is not the case.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr df 1 ,
+.Xr fts 3 ,
+.Xr compat 5 ,
+.Xr symlink 7 ,
+.Xr quot 8
+.Sh HISTORY
+A
+.Nm du
+command appeared in
+.At v1 .
diff --git a/file_cmds/du/du.c b/file_cmds/du/du.c
new file mode 100644
index 0000000..9aea790
--- /dev/null
+++ b/file_cmds/du/du.c
@@ -0,0 +1,730 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Newcomb.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/du/du.c,v 1.38 2005/04/09 14:31:40 stefanf Exp $");
+
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/stat.h>
+#include <sys/attr.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <locale.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#include <sys/sysctl.h>
+#else
+#define COMPAT_MODE(func, mode) (1)
+#endif
+
+#define KILO_SZ(n) (n)
+#define MEGA_SZ(n) ((n) * (n))
+#define GIGA_SZ(n) ((n) * (n) * (n))
+#define TERA_SZ(n) ((n) * (n) * (n) * (n))
+#define PETA_SZ(n) ((n) * (n) * (n) * (n) * (n))
+
+#define KILO_2_SZ (KILO_SZ(1024ULL))
+#define MEGA_2_SZ (MEGA_SZ(1024ULL))
+#define GIGA_2_SZ (GIGA_SZ(1024ULL))
+#define TERA_2_SZ (TERA_SZ(1024ULL))
+#define PETA_2_SZ (PETA_SZ(1024ULL))
+
+#define KILO_SI_SZ (KILO_SZ(1000ULL))
+#define MEGA_SI_SZ (MEGA_SZ(1000ULL))
+#define GIGA_SI_SZ (GIGA_SZ(1000ULL))
+#define TERA_SI_SZ (TERA_SZ(1000ULL))
+#define PETA_SI_SZ (PETA_SZ(1000ULL))
+
+unsigned long long vals_si [] = {1, KILO_SI_SZ, MEGA_SI_SZ, GIGA_SI_SZ, TERA_SI_SZ, PETA_SI_SZ};
+unsigned long long vals_base2[] = {1, KILO_2_SZ, MEGA_2_SZ, GIGA_2_SZ, TERA_2_SZ, PETA_2_SZ};
+unsigned long long *valp;
+
+typedef enum { NONE, KILO, MEGA, GIGA, TERA, PETA, UNIT_MAX } unit_t;
+
+int unitp [] = { NONE, KILO, MEGA, GIGA, TERA, PETA };
+
+SLIST_HEAD(ignhead, ignentry) ignores;
+struct ignentry {
+ char *mask;
+ SLIST_ENTRY(ignentry) next;
+};
+
+static int linkchk(FTSENT *);
+static int dirlinkchk(FTSENT *);
+static void usage(void);
+void prthumanval(double);
+unit_t unit_adjust(double *);
+void ignoreadd(const char *);
+void ignoreclean(void);
+int ignorep(FTSENT *);
+
+int
+main(int argc, char *argv[])
+{
+ FTS *fts;
+ FTSENT *p;
+ off_t savednumber = 0;
+ long blocksize;
+ int ftsoptions;
+ int listall;
+ int depth;
+ int Hflag, Lflag, Pflag, aflag, sflag, dflag, cflag, hflag, ch, notused, rval;
+ char **save;
+ static char dot[] = ".";
+ off_t *ftsnum, *ftsparnum;
+
+ setlocale(LC_ALL, "");
+
+ Hflag = Lflag = Pflag = aflag = sflag = dflag = cflag = hflag = 0;
+
+ save = argv;
+ ftsoptions = FTS_NOCHDIR;
+ depth = INT_MAX;
+ SLIST_INIT(&ignores);
+
+ while ((ch = getopt(argc, argv, "HI:LPasd:cghkmrx")) != -1)
+ switch (ch) {
+ case 'H':
+ Lflag = Pflag = 0;
+ Hflag = 1;
+ break;
+ case 'I':
+ ignoreadd(optarg);
+ break;
+ case 'L':
+ Hflag = Pflag = 0;
+ Lflag = 1;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ Pflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ errno = 0;
+ depth = atoi(optarg);
+ if (errno == ERANGE || depth < 0) {
+ warnx("invalid argument to option d: %s", optarg);
+ usage();
+ }
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'h':
+ putenv("BLOCKSIZE=512");
+ hflag = 1;
+ valp = vals_base2;
+ break;
+ case 'k':
+ hflag = 0;
+ putenv("BLOCKSIZE=1024");
+ break;
+ case 'm':
+ hflag = 0;
+ putenv("BLOCKSIZE=1048576");
+ break;
+ case 'g':
+ hflag = 0;
+ putenv("BLOCKSIZE=1g");
+ break;
+ case 'r': /* Compatibility. */
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+// argc -= optind;
+ argv += optind;
+
+ /*
+ * XXX
+ * Because of the way that fts(3) works, logical walks will not count
+ * the blocks actually used by symbolic links. We rationalize this by
+ * noting that users computing logical sizes are likely to do logical
+ * copies, so not counting the links is correct. The real reason is
+ * that we'd have to re-implement the kernel's symbolic link traversing
+ * algorithm to get this right. If, for example, you have relative
+ * symbolic links referencing other relative symbolic links, it gets
+ * very nasty, very fast. The bottom line is that it's documented in
+ * the man page, so it's a feature.
+ */
+
+ if (Hflag + Lflag + Pflag > 1)
+ usage();
+
+ if (Hflag + Lflag + Pflag == 0)
+ Pflag = 1; /* -P (physical) is default */
+
+ if (Hflag)
+ ftsoptions |= FTS_COMFOLLOW;
+
+ if (Lflag)
+ ftsoptions |= FTS_LOGICAL;
+
+ if (Pflag)
+ ftsoptions |= FTS_PHYSICAL;
+
+ listall = 0;
+
+ if (aflag) {
+ if (sflag || dflag)
+ usage();
+ listall = 1;
+ } else if (sflag) {
+ if (dflag)
+ usage();
+ depth = 0;
+ }
+
+ if (!*argv) {
+ argv = save;
+ argv[0] = dot;
+ argv[1] = NULL;
+ }
+
+ (void) getbsize(&notused, &blocksize);
+ blocksize /= 512;
+
+#ifdef __APPLE__
+ // "du" should not have any side effect on disk usage,
+ // so prevent materializing dataless directories upon traversal
+ rval = 1;
+ (void) sysctlbyname("vfs.nspace.prevent_materialization", NULL, NULL, &rval, sizeof(rval));
+#endif /* __APPLE__ */
+
+ rval = 0;
+
+ if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
+ err(1, "fts_open");
+
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_D:
+ if (ignorep(p) || dirlinkchk(p))
+ fts_set(fts, p, FTS_SKIP);
+ break;
+ case FTS_DP:
+ if (ignorep(p))
+ break;
+
+ ftsparnum = (off_t *)&p->fts_parent->fts_number;
+ ftsnum = (off_t *)&p->fts_number;
+ ftsparnum[0] += ftsnum[0] += p->fts_statp->st_blocks;
+
+ if (p->fts_level <= depth) {
+ if (hflag) {
+ (void) prthumanval(howmany(*ftsnum, blocksize));
+ (void) printf("\t%s\n", p->fts_path);
+ } else {
+ (void) printf("%jd\t%s\n",
+ (intmax_t)howmany(*ftsnum, blocksize),
+ p->fts_path);
+ }
+ }
+ break;
+ case FTS_DC: /* Ignore. */
+ if (COMPAT_MODE("bin/du", "unix2003")) {
+ errx(1, "Can't follow symlink cycle from %s to %s", p->fts_path, p->fts_cycle->fts_path);
+ }
+ break;
+ case FTS_DNR: /* Warn, continue. */
+ case FTS_ERR:
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ case FTS_SLNONE:
+ if (COMPAT_MODE("bin/du", "unix2003")) {
+ struct stat sb;
+ int rc = stat(p->fts_path, &sb);
+ if (rc < 0 && errno == ELOOP) {
+ errx(1, "Too many symlinks at %s", p->fts_path);
+ }
+ }
+ default:
+ if (ignorep(p))
+ break;
+
+ if (p->fts_statp->st_nlink > 1 && linkchk(p))
+ break;
+
+ if (listall || p->fts_level == 0) {
+ if (hflag) {
+ (void) prthumanval(howmany(p->fts_statp->st_blocks,
+ blocksize));
+ (void) printf("\t%s\n", p->fts_path);
+ } else {
+ (void) printf("%jd\t%s\n",
+ (intmax_t)howmany(p->fts_statp->st_blocks, blocksize),
+ p->fts_path);
+ }
+ }
+
+ ftsparnum = (off_t *)&p->fts_parent->fts_number;
+ ftsparnum[0] += p->fts_statp->st_blocks;
+ }
+ savednumber = ((off_t *)&p->fts_parent->fts_number)[0];
+ }
+
+ if (errno)
+ err(1, "fts_read");
+
+ if (cflag) {
+ if (hflag) {
+ (void) prthumanval(howmany(savednumber, blocksize));
+ (void) printf("\ttotal\n");
+ } else {
+ (void) printf("%jd\ttotal\n", (intmax_t)howmany(savednumber, blocksize));
+ }
+ }
+
+ ignoreclean();
+ exit(rval);
+}
+
+static int
+linkchk(FTSENT *p)
+{
+ struct links_entry {
+ struct links_entry *next;
+ struct links_entry *previous;
+ int links;
+ dev_t dev;
+ ino_t ino;
+ };
+ static const size_t links_hash_initial_size = 8192;
+ static struct links_entry **buckets;
+ static struct links_entry *free_list;
+ static size_t number_buckets;
+ static unsigned long number_entries;
+ static char stop_allocating;
+ struct links_entry *le, **new_buckets;
+ struct stat *st;
+ size_t i, new_size;
+ int hash;
+
+ st = p->fts_statp;
+
+ /* If necessary, initialize the hash table. */
+ if (buckets == NULL) {
+ number_buckets = links_hash_initial_size;
+ buckets = malloc(number_buckets * sizeof(buckets[0]));
+ if (buckets == NULL)
+ errx(1, "No memory for hardlink detection");
+ for (i = 0; i < number_buckets; i++)
+ buckets[i] = NULL;
+ }
+
+ /* If the hash table is getting too full, enlarge it. */
+ if (number_entries > number_buckets * 10 && !stop_allocating) {
+ new_size = number_buckets * 2;
+ new_buckets = malloc(new_size * sizeof(struct links_entry *));
+
+ /* Try releasing the free list to see if that helps. */
+ if (new_buckets == NULL && free_list != NULL) {
+ while (free_list != NULL) {
+ le = free_list;
+ free_list = le->next;
+ free(le);
+ }
+ new_buckets = malloc(new_size * sizeof(new_buckets[0]));
+ }
+
+ if (new_buckets == NULL) {
+ stop_allocating = 1;
+ warnx("No more memory for tracking hard links");
+ } else {
+ memset(new_buckets, 0,
+ new_size * sizeof(struct links_entry *));
+ for (i = 0; i < number_buckets; i++) {
+ while (buckets[i] != NULL) {
+ /* Remove entry from old bucket. */
+ le = buckets[i];
+ buckets[i] = le->next;
+
+ /* Add entry to new bucket. */
+ hash = (le->dev ^ le->ino) % new_size;
+
+ if (new_buckets[hash] != NULL)
+ new_buckets[hash]->previous =
+ le;
+ le->next = new_buckets[hash];
+ le->previous = NULL;
+ new_buckets[hash] = le;
+ }
+ }
+ free(buckets);
+ buckets = new_buckets;
+ number_buckets = new_size;
+ }
+ }
+
+ /* Try to locate this entry in the hash table. */
+ hash = ( st->st_dev ^ st->st_ino ) % number_buckets;
+ for (le = buckets[hash]; le != NULL; le = le->next) {
+ if (le->dev == st->st_dev && le->ino == st->st_ino) {
+ /*
+ * Save memory by releasing an entry when we've seen
+ * all of it's links.
+ */
+ if (--le->links <= 0) {
+ if (le->previous != NULL)
+ le->previous->next = le->next;
+ if (le->next != NULL)
+ le->next->previous = le->previous;
+ if (buckets[hash] == le)
+ buckets[hash] = le->next;
+ number_entries--;
+ /* Recycle this node through the free list */
+ if (stop_allocating) {
+ free(le);
+ } else {
+ le->next = free_list;
+ free_list = le;
+ }
+ }
+ return (1);
+ }
+ }
+
+ if (stop_allocating)
+ return (0);
+
+ /* Add this entry to the links cache. */
+ if (free_list != NULL) {
+ /* Pull a node from the free list if we can. */
+ le = free_list;
+ free_list = le->next;
+ } else
+ /* Malloc one if we have to. */
+ le = malloc(sizeof(struct links_entry));
+ if (le == NULL) {
+ stop_allocating = 1;
+ warnx("No more memory for tracking hard links");
+ return (0);
+ }
+ le->dev = st->st_dev;
+ le->ino = st->st_ino;
+ le->links = st->st_nlink - 1;
+ number_entries++;
+ le->next = buckets[hash];
+ le->previous = NULL;
+ if (buckets[hash] != NULL)
+ buckets[hash]->previous = le;
+ buckets[hash] = le;
+ return (0);
+}
+
+static int
+dirlinkchk(FTSENT *p)
+{
+ struct links_entry {
+ struct links_entry *next;
+ struct links_entry *previous;
+ int links;
+ dev_t dev;
+ ino_t ino;
+ };
+ static const size_t links_hash_initial_size = 8192;
+ static struct links_entry **buckets;
+ static struct links_entry *free_list;
+ static size_t number_buckets;
+ static unsigned long number_entries;
+ static char stop_allocating;
+ struct links_entry *le, **new_buckets;
+ struct stat *st;
+ size_t i, new_size;
+ int hash;
+ struct attrbuf {
+ int size;
+ int linkcount;
+ } buf;
+ struct attrlist attrList;
+
+ memset(&attrList, 0, sizeof(attrList));
+ attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
+ attrList.dirattr = ATTR_DIR_LINKCOUNT;
+ if (-1 == getattrlist(p->fts_path, &attrList, &buf, sizeof(buf), 0))
+ return 0;
+ if (buf.linkcount == 1)
+ return 0;
+ st = p->fts_statp;
+
+ /* If necessary, initialize the hash table. */
+ if (buckets == NULL) {
+ number_buckets = links_hash_initial_size;
+ buckets = malloc(number_buckets * sizeof(buckets[0]));
+ if (buckets == NULL)
+ errx(1, "No memory for directory hardlink detection");
+ for (i = 0; i < number_buckets; i++)
+ buckets[i] = NULL;
+ }
+
+ /* If the hash table is getting too full, enlarge it. */
+ if (number_entries > number_buckets * 10 && !stop_allocating) {
+ new_size = number_buckets * 2;
+ new_buckets = malloc(new_size * sizeof(struct links_entry *));
+
+ /* Try releasing the free list to see if that helps. */
+ if (new_buckets == NULL && free_list != NULL) {
+ while (free_list != NULL) {
+ le = free_list;
+ free_list = le->next;
+ free(le);
+ }
+ new_buckets = malloc(new_size * sizeof(new_buckets[0]));
+ }
+
+ if (new_buckets == NULL) {
+ stop_allocating = 1;
+ warnx("No more memory for tracking directory hard links");
+ } else {
+ memset(new_buckets, 0,
+ new_size * sizeof(struct links_entry *));
+ for (i = 0; i < number_buckets; i++) {
+ while (buckets[i] != NULL) {
+ /* Remove entry from old bucket. */
+ le = buckets[i];
+ buckets[i] = le->next;
+
+ /* Add entry to new bucket. */
+ hash = (le->dev ^ le->ino) % new_size;
+
+ if (new_buckets[hash] != NULL)
+ new_buckets[hash]->previous =
+ le;
+ le->next = new_buckets[hash];
+ le->previous = NULL;
+ new_buckets[hash] = le;
+ }
+ }
+ free(buckets);
+ buckets = new_buckets;
+ number_buckets = new_size;
+ }
+ }
+
+ /* Try to locate this entry in the hash table. */
+ hash = ( st->st_dev ^ st->st_ino ) % number_buckets;
+ for (le = buckets[hash]; le != NULL; le = le->next) {
+ if (le->dev == st->st_dev && le->ino == st->st_ino) {
+ /*
+ * Save memory by releasing an entry when we've seen
+ * all of it's links.
+ */
+ if (--le->links <= 0) {
+ if (le->previous != NULL)
+ le->previous->next = le->next;
+ if (le->next != NULL)
+ le->next->previous = le->previous;
+ if (buckets[hash] == le)
+ buckets[hash] = le->next;
+ number_entries--;
+ /* Recycle this node through the free list */
+ if (stop_allocating) {
+ free(le);
+ } else {
+ le->next = free_list;
+ free_list = le;
+ }
+ }
+ return (1);
+ }
+ }
+
+ if (stop_allocating)
+ return (0);
+ /* Add this entry to the links cache. */
+ if (free_list != NULL) {
+ /* Pull a node from the free list if we can. */
+ le = free_list;
+ free_list = le->next;
+ } else
+ /* Malloc one if we have to. */
+ le = malloc(sizeof(struct links_entry));
+ if (le == NULL) {
+ stop_allocating = 1;
+ warnx("No more memory for tracking hard links");
+ return (0);
+ }
+ le->dev = st->st_dev;
+ le->ino = st->st_ino;
+ le->links = buf.linkcount - 1;
+ number_entries++;
+ le->next = buckets[hash];
+ le->previous = NULL;
+ if (buckets[hash] != NULL)
+ buckets[hash]->previous = le;
+ buckets[hash] = le;
+ return (0);
+}
+
+/*
+ * Output in "human-readable" format. Uses 3 digits max and puts
+ * unit suffixes at the end. Makes output compact and easy to read,
+ * especially on huge disks.
+ *
+ */
+unit_t
+unit_adjust(double *val)
+{
+ double abval;
+ unit_t unit;
+ unsigned int unit_sz;
+
+ abval = fabs(*val);
+
+ unit_sz = abval ? ilogb(abval) / 10 : 0;
+
+ if (unit_sz >= UNIT_MAX) {
+ unit = NONE;
+ } else {
+ unit = unitp[unit_sz];
+ *val /= (double)valp[unit_sz];
+ }
+
+ return (unit);
+}
+
+void
+prthumanval(double bytes)
+{
+ unit_t unit;
+
+ bytes *= 512;
+ unit = unit_adjust(&bytes);
+
+ if (bytes == 0)
+ (void)printf(" 0B");
+ else if (bytes > 10)
+ (void)printf("%3.0f%c", bytes, "BKMGTPE"[unit]);
+ else
+ (void)printf("%3.1f%c", bytes, "BKMGTPE"[unit]);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: du [-H | -L | -P] [-a | -s | -d depth] [-c] [-h | -k | -m | -g] [-x] [-I mask] [file ...]\n");
+ exit(EX_USAGE);
+}
+
+void
+ignoreadd(const char *mask)
+{
+ struct ignentry *ign;
+
+ ign = calloc(1, sizeof(*ign));
+ if (ign == NULL)
+ errx(1, "cannot allocate memory");
+ ign->mask = strdup(mask);
+ if (ign->mask == NULL)
+ errx(1, "cannot allocate memory");
+ SLIST_INSERT_HEAD(&ignores, ign, next);
+}
+
+void
+ignoreclean(void)
+{
+ struct ignentry *ign;
+
+ while (!SLIST_EMPTY(&ignores)) {
+ ign = SLIST_FIRST(&ignores);
+ SLIST_REMOVE_HEAD(&ignores, next);
+ free(ign->mask);
+ free(ign);
+ }
+}
+
+int
+ignorep(FTSENT *ent)
+{
+ struct ignentry *ign;
+
+#ifdef __APPLE__
+ if (S_ISDIR(ent->fts_statp->st_mode) && !strcmp("fd", ent->fts_name)) {
+ struct statfs sfsb;
+ int rc = statfs(ent->fts_accpath, &sfsb);
+ if (rc >= 0 && !strcmp("devfs", sfsb.f_fstypename)) {
+ /* Don't cd into /dev/fd/N since one of those is likely to be
+ the cwd as of the start of du which causes all manner of
+ unpleasant surprises */
+ return 1;
+ }
+ }
+#endif /* __APPLE__ */
+ SLIST_FOREACH(ign, &ignores, next)
+ if (fnmatch(ign->mask, ent->fts_name, 0) != FNM_NOMATCH)
+ return 1;
+ return 0;
+}
diff --git a/file_cmds/file_cmds.xcodeproj/project.pbxproj b/file_cmds/file_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..e4e94ec
--- /dev/null
+++ b/file_cmds/file_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,3984 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 3E966CE71FB2211F0019F7A1 /* tests */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 3E966CE91FB2211F0019F7A1 /* Build configuration list for PBXAggregateTarget "tests" */;
+ buildPhases = (
+ 3E966CED1FB2215C0019F7A1 /* CopyFiles */,
+ 3E966CEF1FB221740019F7A1 /* CopyFiles */,
+ );
+ dependencies = (
+ );
+ name = tests;
+ productName = tests;
+ };
+ 729D07252347EC4D000716E5 /* macos_host_tools */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 729D07682347EC4D000716E5 /* Build configuration list for PBXAggregateTarget "macos_host_tools" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 729D074E2347EC4D000716E5 /* PBXTargetDependency */,
+ );
+ name = macos_host_tools;
+ productName = macos_host_tools;
+ };
+ FC8A8C3C14B64A9D001B97AD /* shar */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC8A8C3D14B64A9D001B97AD /* Build configuration list for PBXAggregateTarget "shar" */;
+ buildPhases = (
+ FC8A8CC714B65CEB001B97AD /* ShellScript */,
+ FC8A8C3F14B64AA8001B97AD /* CopyFiles */,
+ );
+ dependencies = (
+ );
+ name = shar;
+ productName = shar;
+ };
+ FC8A8C4614B64DCD001B97AD /* readlink */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC8A8C4714B64DCE001B97AD /* Build configuration list for PBXAggregateTarget "readlink" */;
+ buildPhases = (
+ FC8A8C4B14B64DEA001B97AD /* Copy Files */,
+ FC8A8C4C14B64DF9001B97AD /* ShellScript */,
+ );
+ dependencies = (
+ FC8A8C4A14B64DE1001B97AD /* PBXTargetDependency */,
+ );
+ name = readlink;
+ productName = readlink;
+ };
+ FC8A8C5014B650CF001B97AD /* unlink */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC8A8C5614B650CF001B97AD /* Build configuration list for PBXAggregateTarget "unlink" */;
+ buildPhases = (
+ FC8A8C5314B650CF001B97AD /* CopyFiles */,
+ FC8A8C5514B650CF001B97AD /* ShellScript */,
+ );
+ dependencies = (
+ FC8A8C5914B65238001B97AD /* PBXTargetDependency */,
+ );
+ name = unlink;
+ productName = readlink;
+ };
+ FC8A8C5B14B652E1001B97AD /* chgrp */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC8A8C6114B652E1001B97AD /* Build configuration list for PBXAggregateTarget "chgrp" */;
+ buildPhases = (
+ FC8A8C5E14B652E1001B97AD /* CopyFiles */,
+ FC8A8C6014B652E1001B97AD /* ShellScript */,
+ );
+ dependencies = (
+ FC8A8C6414B652FA001B97AD /* PBXTargetDependency */,
+ );
+ name = chgrp;
+ productName = readlink;
+ };
+ FC8A8C6714B6536D001B97AD /* sum */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC8A8C6D14B6536D001B97AD /* Build configuration list for PBXAggregateTarget "sum" */;
+ buildPhases = (
+ FC8A8C6A14B6536D001B97AD /* CopyFiles */,
+ FC8A8C6C14B6536D001B97AD /* ShellScript */,
+ );
+ dependencies = (
+ FC8A8C7014B6537C001B97AD /* PBXTargetDependency */,
+ );
+ name = sum;
+ productName = readlink;
+ };
+ FC8A8C7314B6554E001B97AD /* link */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC8A8C7914B6554E001B97AD /* Build configuration list for PBXAggregateTarget "link" */;
+ buildPhases = (
+ FC8A8C7614B6554E001B97AD /* CopyFiles */,
+ FC8A8C7814B6554E001B97AD /* ShellScript */,
+ );
+ dependencies = (
+ FC8A8C7C14B65562001B97AD /* PBXTargetDependency */,
+ );
+ name = link;
+ productName = readlink;
+ };
+ FC8A8C8014B655ED001B97AD /* executables */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC8A8C8114B655ED001B97AD /* Build configuration list for PBXAggregateTarget "executables" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FC8A8C8414B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C8614B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C8814B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C8A14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C8C14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C8E14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C9014B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C9214B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C9414B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C9614B655FD001B97AD /* PBXTargetDependency */,
+ FDAD94AA1808BDAA00B4D5A0 /* PBXTargetDependency */,
+ FC8A8C9814B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C9A14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C9C14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8C9E14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CA014B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CA214B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CA414B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CA614B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CA814B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CAA14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CAC14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CAE14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CB014B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CB214B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CB414B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CB614B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CB814B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CBA14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CBC14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CBE14B655FD001B97AD /* PBXTargetDependency */,
+ FC8A8CD314B67BFD001B97AD /* PBXTargetDependency */,
+ FC8A8CC014B655FD001B97AD /* PBXTargetDependency */,
+ );
+ name = executables;
+ productName = executables;
+ };
+ FC8A8CC814B65F92001B97AD /* uncompress */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC8A8CCE14B65F92001B97AD /* Build configuration list for PBXAggregateTarget "uncompress" */;
+ buildPhases = (
+ FC8A8CCB14B65F92001B97AD /* CopyFiles */,
+ FC8A8CCD14B65F92001B97AD /* ShellScript */,
+ );
+ dependencies = (
+ FC8A8CC914B65F92001B97AD /* PBXTargetDependency */,
+ );
+ name = uncompress;
+ productName = readlink;
+ };
+ FDFF0C501811BA2F00BFC477 /* eOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDFF0C931811BA2F00BFC477 /* Build configuration list for PBXAggregateTarget "eOS" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FDFF0C511811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C531811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C551811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C571811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C591811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C5B1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C5D1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C5F1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C611811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C631811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C671811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C691811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C6B1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C6D1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C6F1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C711811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C731811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C751811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C771811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C791811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C7B1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C7D1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C7F1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C811811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C831811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C851811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C871811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C891811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C8B1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C8D1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C8F1811BA2F00BFC477 /* PBXTargetDependency */,
+ FDFF0C911811BA2F00BFC477 /* PBXTargetDependency */,
+ );
+ name = eOS;
+ productName = executables;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 3E59B9311D4A767600D3128C /* futimens.c in Sources */ = {isa = PBXBuildFile; fileRef = 3E59B9301D4A767600D3128C /* futimens.c */; };
+ 3E966CEE1FB2216F0019F7A1 /* file_cmds.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */; };
+ 3E966CF01FB2218A0019F7A1 /* chgrp.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = 3E966CEB1FB2214F0019F7A1 /* chgrp.sh */; };
+ 729D06D8230B5E42000716E5 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 729D06D7230B5E42000716E5 /* CoreFoundation.framework */; };
+ 7D0A20EA2499364700F0F6D7 /* metrics.c in Sources */ = {isa = PBXBuildFile; fileRef = 7D0A20E92499364700F0F6D7 /* metrics.c */; };
+ FC8A8A2814B6486E001B97AD /* chflags.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDCC14B6460C0070FACB /* chflags.c */; };
+ FC8A8BE414B6494B001B97AD /* chflags.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDCB14B6460C0070FACB /* chflags.1 */; };
+ FC8A8BE514B64958001B97AD /* chmod.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDD014B6460C0070FACB /* chmod.c */; };
+ FC8A8BE614B6495B001B97AD /* chmod_acl.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDD114B6460C0070FACB /* chmod_acl.c */; };
+ FC8A8BE714B6495D001B97AD /* chmod.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDCF14B6460C0070FACB /* chmod.1 */; };
+ FC8A8BE814B64962001B97AD /* chown.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDD714B6460C0070FACB /* chown.c */; };
+ FC8A8BEA14B6496E001B97AD /* cksum.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDDA14B6460C0070FACB /* cksum.1 */; };
+ FC8A8BEB14B64970001B97AD /* cksum.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDDB14B6460C0070FACB /* cksum.c */; };
+ FC8A8BEC14B64972001B97AD /* crc.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDDC14B6460C0070FACB /* crc.c */; };
+ FC8A8BED14B64975001B97AD /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDDD14B6460C0070FACB /* crc32.c */; };
+ FC8A8BEE14B64977001B97AD /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDE014B6460C0070FACB /* print.c */; };
+ FC8A8BEF14B6497A001B97AD /* sum1.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDE114B6460C0070FACB /* sum1.c */; };
+ FC8A8BF014B6497D001B97AD /* sum2.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDE214B6460C0070FACB /* sum2.c */; };
+ FC8A8BF114B64982001B97AD /* compress.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDE414B6460C0070FACB /* compress.1 */; };
+ FC8A8BF314B64988001B97AD /* compress.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDE514B6460C0070FACB /* compress.c */; };
+ FC8A8BF414B6498A001B97AD /* zopen.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDEE14B6460C0070FACB /* zopen.c */; };
+ FC8A8BF514B64995001B97AD /* cp.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDF214B6460C0070FACB /* cp.c */; };
+ FC8A8BF614B64998001B97AD /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDF514B6460C0070FACB /* utils.c */; };
+ FC8A8BF714B6499A001B97AD /* cp.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDF114B6460C0070FACB /* cp.1 */; };
+ FC8A8BF814B649A4001B97AD /* args.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDF914B6460C0070FACB /* args.c */; };
+ FC8A8BF914B649A5001B97AD /* conv.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDFA14B6460C0070FACB /* conv.c */; };
+ FC8A8BFA14B649A7001B97AD /* conv_tab.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDFB14B6460C0070FACB /* conv_tab.c */; };
+ FC8A8BFB14B649A9001B97AD /* dd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDFC14B6460C0070FACB /* dd.1 */; };
+ FC8A8BFC14B649AC001B97AD /* dd.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDFD14B6460C0070FACB /* dd.c */; };
+ FC8A8BFD14B649AE001B97AD /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE0114B6460C0070FACB /* misc.c */; };
+ FC8A8BFE14B649B1001B97AD /* position.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE0214B6460C0070FACB /* position.c */; };
+ FC8A8BFF14B649B4001B97AD /* df.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE0414B6460C0070FACB /* df.1 */; };
+ FC8A8C0114B649D1001B97AD /* df.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE0514B6460C0070FACB /* df.c */; };
+ FC8A8C0214B649D4001B97AD /* du.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE0A14B6460C0070FACB /* du.c */; };
+ FC8A8C0314B649D8001B97AD /* du.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE0914B6460C0070FACB /* du.1 */; };
+ FC8A8C0414B649DD001B97AD /* xinstall.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE1014B6460C0070FACB /* xinstall.c */; };
+ FC8A8C0514B649DF001B97AD /* install.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE0D14B6460C0070FACB /* install.1 */; };
+ FC8A8C0614B649E2001B97AD /* ipcrm.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE1214B6460C0070FACB /* ipcrm.1 */; };
+ FC8A8C0714B649E3001B97AD /* ipcrm.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE1314B6460C0070FACB /* ipcrm.c */; };
+ FC8A8C0814B649E8001B97AD /* ipcs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE1714B6460C0070FACB /* ipcs.c */; };
+ FC8A8C0914B649EA001B97AD /* ipcs.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE1614B6460C0070FACB /* ipcs.1 */; };
+ FC8A8C0A14B649ED001B97AD /* ln.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE1A14B6460C0070FACB /* ln.1 */; };
+ FC8A8C0B14B649EF001B97AD /* ln.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE1B14B6460C0070FACB /* ln.c */; };
+ FC8A8C0C14B649F5001B97AD /* ls.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE2114B6460C0070FACB /* ls.1 */; };
+ FC8A8C0D14B649F7001B97AD /* cmp.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE1F14B6460C0070FACB /* cmp.c */; };
+ FC8A8C0E14B649F9001B97AD /* ls.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE2214B6460C0070FACB /* ls.c */; };
+ FC8A8C0F14B649FC001B97AD /* print.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE2514B6460C0070FACB /* print.c */; };
+ FC8A8C1014B649FE001B97AD /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE2614B6460C0070FACB /* util.c */; };
+ FC8A8C1114B64A04001B97AD /* mkdir.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE2B14B6460C0070FACB /* mkdir.c */; };
+ FC8A8C1214B64A06001B97AD /* mkdir.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE2A14B6460C0070FACB /* mkdir.1 */; };
+ FC8A8C1314B64A09001B97AD /* mkfifo.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE2E14B6460C0070FACB /* mkfifo.1 */; };
+ FC8A8C1414B64A0A001B97AD /* mkfifo.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE2F14B6460C0070FACB /* mkfifo.c */; };
+ FC8A8C1514B64A0D001B97AD /* mknod.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE3214B6460C0070FACB /* mknod.8 */; };
+ FC8A8C1614B64A0F001B97AD /* mknod.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE3314B6460C0070FACB /* mknod.c */; };
+ FC8A8C1714B64A14001B97AD /* commoncrypto.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE3514B6460C0070FACB /* commoncrypto.c */; };
+ FC8A8C1814B64A17001B97AD /* compare.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE3714B6460C0070FACB /* compare.c */; };
+ FC8A8C1914B64A1A001B97AD /* create.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE3814B6460C0070FACB /* create.c */; };
+ FC8A8C1A14B64A22001B97AD /* excludes.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE3914B6460C0070FACB /* excludes.c */; };
+ FC8A8C1B14B64A27001B97AD /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE3C14B6460C0070FACB /* misc.c */; };
+ FC8A8C1C14B64A2D001B97AD /* mtree.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE3E14B6460C0070FACB /* mtree.c */; };
+ FC8A8C1D14B64A31001B97AD /* spec.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE4014B6460C0070FACB /* spec.c */; };
+ FC8A8C1E14B64A34001B97AD /* specspec.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE4114B6460C0070FACB /* specspec.c */; };
+ FC8A8C1F14B64A38001B97AD /* verify.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE4814B6460C0070FACB /* verify.c */; };
+ FC8A8C2014B64A40001B97AD /* mtree.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE3D14B6460C0070FACB /* mtree.8 */; };
+ FC8A8C2114B64A49001B97AD /* mv.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE4B14B6460C0070FACB /* mv.1 */; };
+ FC8A8C2214B64A4B001B97AD /* mv.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE4C14B6460C0070FACB /* mv.c */; };
+ FC8A8C2314B64A4F001B97AD /* pathchk.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE5014B6460C0070FACB /* pathchk.1 */; };
+ FC8A8C2414B64A53001B97AD /* pathchk.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5114B6460C0070FACB /* pathchk.c */; };
+ FC8A8C2514B64A59001B97AD /* pax.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE6614B6460C0070FACB /* pax.1 */; };
+ FC8A8C2714B64A73001B97AD /* ar_io.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5314B6460C0070FACB /* ar_io.c */; };
+ FC8A8C2814B64A73001B97AD /* ar_subs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5414B6460C0070FACB /* ar_subs.c */; };
+ FC8A8C2914B64A73001B97AD /* buf_subs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5514B6460C0070FACB /* buf_subs.c */; };
+ FC8A8C2A14B64A73001B97AD /* cache.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5614B6460C0070FACB /* cache.c */; };
+ FC8A8C2B14B64A73001B97AD /* cpio.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5914B6460C0070FACB /* cpio.c */; };
+ FC8A8C2C14B64A73001B97AD /* file_subs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5C14B6460C0070FACB /* file_subs.c */; };
+ FC8A8C2D14B64A73001B97AD /* ftree.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5D14B6460C0070FACB /* ftree.c */; };
+ FC8A8C2E14B64A73001B97AD /* gen_subs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE5F14B6460C0070FACB /* gen_subs.c */; };
+ FC8A8C2F14B64A73001B97AD /* getoldopt.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE6014B6460C0070FACB /* getoldopt.c */; };
+ FC8A8C3014B64A73001B97AD /* options.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE6214B6460C0070FACB /* options.c */; };
+ FC8A8C3114B64A73001B97AD /* pat_rep.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE6414B6460C0070FACB /* pat_rep.c */; };
+ FC8A8C3214B64A73001B97AD /* pax.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE6714B6460C0070FACB /* pax.c */; };
+ FC8A8C3314B64A73001B97AD /* pax_format.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE6914B6460C0070FACB /* pax_format.c */; };
+ FC8A8C3414B64A73001B97AD /* sel_subs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE6B14B6460C0070FACB /* sel_subs.c */; };
+ FC8A8C3514B64A73001B97AD /* tables.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE6D14B6460C0070FACB /* tables.c */; };
+ FC8A8C3614B64A73001B97AD /* tar.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE6F14B6460C0070FACB /* tar.c */; };
+ FC8A8C3714B64A73001B97AD /* tty_subs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE7114B6460C0070FACB /* tty_subs.c */; };
+ FC8A8C3814B64A7C001B97AD /* rm.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE7414B6460C0070FACB /* rm.1 */; };
+ FC8A8C3914B64A7E001B97AD /* rm.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE7514B6460C0070FACB /* rm.c */; };
+ FC8A8C3A14B64A85001B97AD /* rmdir.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE7814B6460C0070FACB /* rmdir.1 */; };
+ FC8A8C3B14B64A88001B97AD /* rmdir.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE7914B6460C0070FACB /* rmdir.c */; };
+ FC8A8C4014B64AAB001B97AD /* shar.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE8014B6460C0070FACB /* shar.1 */; };
+ FC8A8C4114B64AC0001B97AD /* stat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE8414B6460C0070FACB /* stat.1 */; };
+ FC8A8C4214B64AC3001B97AD /* stat.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE8514B6460C0070FACB /* stat.c */; };
+ FC8A8C4314B64AC7001B97AD /* touch.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE8914B6460C0070FACB /* touch.c */; };
+ FC8A8C4514B64AD7001B97AD /* touch.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE8814B6460C0070FACB /* touch.1 */; };
+ FC8A8C4E14B64EAE001B97AD /* readlink.1 in Copy Files */ = {isa = PBXBuildFile; fileRef = FC8A8C4D14B64EA8001B97AD /* readlink.1 */; };
+ FC8A8C5A14B6525A001B97AD /* unlink.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC8A8C4F14B650C3001B97AD /* unlink.1 */; };
+ FC8A8C6514B65307001B97AD /* chgrp.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDD514B6460C0070FACB /* chgrp.1 */; };
+ FC8A8C7114B65389001B97AD /* sum.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC8A8C6614B6535B001B97AD /* sum.1 */; };
+ FC8A8C7D14B65575001B97AD /* link.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC8A8C7214B65547001B97AD /* link.1 */; };
+ FC8A8C7F14B65586001B97AD /* symlink.7 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BE1D14B6460C0070FACB /* symlink.7 */; };
+ FC8A8CC214B658D7001B97AD /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8A8CC114B658D6001B97AD /* libutil.dylib */; };
+ FC8A8CC314B6598F001B97AD /* vfslist.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BE0714B6460C0070FACB /* vfslist.c */; };
+ FC8A8CC514B65C3D001B97AD /* libcurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8A8CC414B65C3D001B97AD /* libcurses.dylib */; };
+ FC8A8CC614B65C46001B97AD /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FC8A8CC114B658D6001B97AD /* libutil.dylib */; };
+ FC8A8CD014B65F9B001B97AD /* uncompress.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDEB14B6460C0070FACB /* uncompress.1 */; };
+ FC8A8CD114B66E10001B97AD /* crc.c in Sources */ = {isa = PBXBuildFile; fileRef = FCB1BDDC14B6460C0070FACB /* crc.c */; };
+ FC8A8CD414B67D60001B97AD /* chown.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCB1BDD614B6460C0070FACB /* chown.8 */; };
+ FDAD949F1808BBB900B4D5A0 /* gzip.c in Sources */ = {isa = PBXBuildFile; fileRef = FDAD94831808BB3A00B4D5A0 /* gzip.c */; };
+ FDAD94A21808BC9100B4D5A0 /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDAD94A11808BC9100B4D5A0 /* libbz2.dylib */; };
+ FDAD94A41808BC9700B4D5A0 /* liblzma.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDAD94A31808BC9700B4D5A0 /* liblzma.dylib */; };
+ FDAD94A61808BC9B00B4D5A0 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FDAD94A51808BC9B00B4D5A0 /* libz.dylib */; };
+ FDAD94A81808BD0600B4D5A0 /* gzip.1 in Install Man Page */ = {isa = PBXBuildFile; fileRef = FDAD94821808BB3A00B4D5A0 /* gzip.1 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 729D074F2347EC4D000716E5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B8C14B648ED001B97AD;
+ remoteInfo = mtree;
+ };
+ FC8A8C4914B64DE1001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BC414B648EF001B97AD;
+ remoteInfo = stat;
+ };
+ FC8A8C5814B65238001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BAC14B648EF001B97AD;
+ remoteInfo = rm;
+ };
+ FC8A8C6314B652FA001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B1414B648E0001B97AD;
+ remoteInfo = chown;
+ };
+ FC8A8C6F14B6537C001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B1C14B648E3001B97AD;
+ remoteInfo = cksum;
+ };
+ FC8A8C7B14B65562001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B6414B648EC001B97AD;
+ remoteInfo = ln;
+ };
+ FC8A8C8314B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCB1BDB714B645D10070FACB;
+ remoteInfo = chflags;
+ };
+ FC8A8C8514B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C5B14B652E1001B97AD;
+ remoteInfo = chgrp;
+ };
+ FC8A8C8714B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B0B14B648D7001B97AD;
+ remoteInfo = chmod;
+ };
+ FC8A8C8914B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B1414B648E0001B97AD;
+ remoteInfo = chown;
+ };
+ FC8A8C8B14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B1C14B648E3001B97AD;
+ remoteInfo = cksum;
+ };
+ FC8A8C8D14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B2414B648E5001B97AD;
+ remoteInfo = compress;
+ };
+ FC8A8C8F14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B2C14B648E7001B97AD;
+ remoteInfo = cp;
+ };
+ FC8A8C9114B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B3414B648EA001B97AD;
+ remoteInfo = dd;
+ };
+ FC8A8C9314B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B3C14B648EA001B97AD;
+ remoteInfo = df;
+ };
+ FC8A8C9514B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B4414B648EB001B97AD;
+ remoteInfo = du;
+ };
+ FC8A8C9714B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B4C14B648EB001B97AD;
+ remoteInfo = install;
+ };
+ FC8A8C9914B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B5414B648EB001B97AD;
+ remoteInfo = ipcrm;
+ };
+ FC8A8C9B14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B5C14B648EC001B97AD;
+ remoteInfo = ipcs;
+ };
+ FC8A8C9D14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C7314B6554E001B97AD;
+ remoteInfo = link;
+ };
+ FC8A8C9F14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B6414B648EC001B97AD;
+ remoteInfo = ln;
+ };
+ FC8A8CA114B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B6C14B648ED001B97AD;
+ remoteInfo = ls;
+ };
+ FC8A8CA314B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B7414B648ED001B97AD;
+ remoteInfo = mkdir;
+ };
+ FC8A8CA514B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B7C14B648ED001B97AD;
+ remoteInfo = mkfifo;
+ };
+ FC8A8CA714B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B8414B648ED001B97AD;
+ remoteInfo = mknod;
+ };
+ FC8A8CA914B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B8C14B648ED001B97AD;
+ remoteInfo = mtree;
+ };
+ FC8A8CAB14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B9414B648EE001B97AD;
+ remoteInfo = mv;
+ };
+ FC8A8CAD14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B9C14B648EE001B97AD;
+ remoteInfo = pathchk;
+ };
+ FC8A8CAF14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BA414B648EE001B97AD;
+ remoteInfo = pax;
+ };
+ FC8A8CB114B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C4614B64DCD001B97AD;
+ remoteInfo = readlink;
+ };
+ FC8A8CB314B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BAC14B648EF001B97AD;
+ remoteInfo = rm;
+ };
+ FC8A8CB514B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BB414B648EF001B97AD;
+ remoteInfo = rmdir;
+ };
+ FC8A8CB714B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C3C14B64A9D001B97AD;
+ remoteInfo = shar;
+ };
+ FC8A8CB914B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BC414B648EF001B97AD;
+ remoteInfo = stat;
+ };
+ FC8A8CBB14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C6714B6536D001B97AD;
+ remoteInfo = sum;
+ };
+ FC8A8CBD14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BCC14B648F0001B97AD;
+ remoteInfo = touch;
+ };
+ FC8A8CBF14B655FD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C5014B650CF001B97AD;
+ remoteInfo = unlink;
+ };
+ FC8A8CCA14B65F92001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BAC14B648EF001B97AD;
+ remoteInfo = rm;
+ };
+ FC8A8CD214B67BFD001B97AD /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8CC814B65F92001B97AD;
+ remoteInfo = uncompress;
+ };
+ FDAD94A91808BDAA00B4D5A0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDAD94961808BB6D00B4D5A0;
+ remoteInfo = gzip;
+ };
+ FDFF0C521811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCB1BDB714B645D10070FACB;
+ remoteInfo = chflags;
+ };
+ FDFF0C541811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C5B14B652E1001B97AD;
+ remoteInfo = chgrp;
+ };
+ FDFF0C561811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B0B14B648D7001B97AD;
+ remoteInfo = chmod;
+ };
+ FDFF0C581811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B1414B648E0001B97AD;
+ remoteInfo = chown;
+ };
+ FDFF0C5A1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B1C14B648E3001B97AD;
+ remoteInfo = cksum;
+ };
+ FDFF0C5C1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B2414B648E5001B97AD;
+ remoteInfo = compress;
+ };
+ FDFF0C5E1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B2C14B648E7001B97AD;
+ remoteInfo = cp;
+ };
+ FDFF0C601811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B3414B648EA001B97AD;
+ remoteInfo = dd;
+ };
+ FDFF0C621811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B3C14B648EA001B97AD;
+ remoteInfo = df;
+ };
+ FDFF0C641811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B4414B648EB001B97AD;
+ remoteInfo = du;
+ };
+ FDFF0C681811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B4C14B648EB001B97AD;
+ remoteInfo = install;
+ };
+ FDFF0C6A1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B5414B648EB001B97AD;
+ remoteInfo = ipcrm;
+ };
+ FDFF0C6C1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B5C14B648EC001B97AD;
+ remoteInfo = ipcs;
+ };
+ FDFF0C6E1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C7314B6554E001B97AD;
+ remoteInfo = link;
+ };
+ FDFF0C701811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B6414B648EC001B97AD;
+ remoteInfo = ln;
+ };
+ FDFF0C721811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B6C14B648ED001B97AD;
+ remoteInfo = ls;
+ };
+ FDFF0C741811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B7414B648ED001B97AD;
+ remoteInfo = mkdir;
+ };
+ FDFF0C761811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B7C14B648ED001B97AD;
+ remoteInfo = mkfifo;
+ };
+ FDFF0C781811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B8414B648ED001B97AD;
+ remoteInfo = mknod;
+ };
+ FDFF0C7A1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B8C14B648ED001B97AD;
+ remoteInfo = mtree;
+ };
+ FDFF0C7C1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B9414B648EE001B97AD;
+ remoteInfo = mv;
+ };
+ FDFF0C7E1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8B9C14B648EE001B97AD;
+ remoteInfo = pathchk;
+ };
+ FDFF0C801811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BA414B648EE001B97AD;
+ remoteInfo = pax;
+ };
+ FDFF0C821811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C4614B64DCD001B97AD;
+ remoteInfo = readlink;
+ };
+ FDFF0C841811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BAC14B648EF001B97AD;
+ remoteInfo = rm;
+ };
+ FDFF0C861811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BB414B648EF001B97AD;
+ remoteInfo = rmdir;
+ };
+ FDFF0C881811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C3C14B64A9D001B97AD;
+ remoteInfo = shar;
+ };
+ FDFF0C8A1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BC414B648EF001B97AD;
+ remoteInfo = stat;
+ };
+ FDFF0C8C1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C6714B6536D001B97AD;
+ remoteInfo = sum;
+ };
+ FDFF0C8E1811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8BCC14B648F0001B97AD;
+ remoteInfo = touch;
+ };
+ FDFF0C901811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8CC814B65F92001B97AD;
+ remoteInfo = uncompress;
+ };
+ FDFF0C921811BA2F00BFC477 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FCB1BDAF14B645D00070FACB /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC8A8C5014B650CF001B97AD;
+ remoteInfo = unlink;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 3E966CED1FB2215C0019F7A1 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /AppleInternal/CoreOS/BATS/unit_tests;
+ dstSubfolderSpec = 0;
+ files = (
+ 3E966CEE1FB2216F0019F7A1 /* file_cmds.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 3E966CEF1FB221740019F7A1 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /AppleInternal/Tests/file_cmds;
+ dstSubfolderSpec = 0;
+ files = (
+ 3E966CF01FB2218A0019F7A1 /* chgrp.sh in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B0F14B648D7001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8BE714B6495D001B97AD /* chmod.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B1714B648E0001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8CD414B67D60001B97AD /* chown.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B1F14B648E3001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8BEA14B6496E001B97AD /* cksum.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B2714B648E5001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8BF114B64982001B97AD /* compress.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B2F14B648E7001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8BF714B6499A001B97AD /* cp.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B3714B648EA001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8BFB14B649A9001B97AD /* dd.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B3F14B648EA001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8BFF14B649B4001B97AD /* df.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B4714B648EB001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C0314B649D8001B97AD /* du.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B4F14B648EB001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C0514B649DF001B97AD /* install.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B5714B648EB001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C0614B649E2001B97AD /* ipcrm.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B5F14B648EC001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C0914B649EA001B97AD /* ipcs.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B6714B648EC001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C0A14B649ED001B97AD /* ln.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B6F14B648ED001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C0C14B649F5001B97AD /* ls.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B7714B648ED001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C1214B64A06001B97AD /* mkdir.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B7F14B648ED001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C1314B64A09001B97AD /* mkfifo.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B8714B648ED001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C1514B64A0D001B97AD /* mknod.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B8F14B648ED001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C2014B64A40001B97AD /* mtree.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B9714B648EE001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C2114B64A49001B97AD /* mv.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8B9F14B648EE001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C2314B64A4F001B97AD /* pathchk.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8BA714B648EE001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C2514B64A59001B97AD /* pax.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8BAF14B648EF001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C3814B64A7C001B97AD /* rm.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8BB714B648EF001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C3A14B64A85001B97AD /* rmdir.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8BC714B648EF001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C4114B64AC0001B97AD /* stat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8BCF14B648F0001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C4514B64AD7001B97AD /* touch.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8C3F14B64AA8001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C4014B64AAB001B97AD /* shar.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8C4B14B64DEA001B97AD /* Copy Files */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C4E14B64EAE001B97AD /* readlink.1 in Copy Files */,
+ );
+ name = "Copy Files";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8C5314B650CF001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C5A14B6525A001B97AD /* unlink.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8C5E14B652E1001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C6514B65307001B97AD /* chgrp.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8C6A14B6536D001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C7114B65389001B97AD /* sum.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8C7614B6554E001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C7D14B65575001B97AD /* link.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8C7E14B6557E001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man7/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8C7F14B65586001B97AD /* symlink.7 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC8A8CCB14B65F92001B97AD /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8CD014B65F9B001B97AD /* uncompress.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCB1BDB614B645D10070FACB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC8A8BE414B6494B001B97AD /* chflags.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDAD94951808BB6D00B4D5A0 /* Install Man Page */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "$(GZIP_PREFIX)/share/man/man1";
+ dstSubfolderSpec = 0;
+ files = (
+ FDAD94A81808BD0600B4D5A0 /* gzip.1 in Install Man Page */,
+ );
+ name = "Install Man Page";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 0773099A1A3A4DFE00E9B4EA /* dd.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = dd.entitlements; sourceTree = "<group>"; };
+ 3E59B9301D4A767600D3128C /* futimens.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = futimens.c; sourceTree = "<group>"; };
+ 3E966CEB1FB2214F0019F7A1 /* chgrp.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = chgrp.sh; sourceTree = "<group>"; };
+ 3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = file_cmds.plist; sourceTree = "<group>"; };
+ 729D06D7230B5E42000716E5 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+ 7D0A20E82499364700F0F6D7 /* metrics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = metrics.h; sourceTree = "<group>"; };
+ 7D0A20E92499364700F0F6D7 /* metrics.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = metrics.c; sourceTree = "<group>"; };
+ FC8A8B1214B648D7001B97AD /* chmod */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chmod; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B1A14B648E0001B97AD /* chown */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chown; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B2214B648E3001B97AD /* cksum */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cksum; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B2A14B648E5001B97AD /* compress */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = compress; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B3214B648E7001B97AD /* cp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cp; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B3A14B648EA001B97AD /* dd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dd; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B4214B648EA001B97AD /* df */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = df; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B4A14B648EB001B97AD /* du */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = du; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B5214B648EB001B97AD /* install */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = install; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B5A14B648EB001B97AD /* ipcrm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ipcrm; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B6214B648EC001B97AD /* ipcs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ipcs; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B6A14B648EC001B97AD /* ln */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ln; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B7214B648ED001B97AD /* ls */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ls; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B7A14B648ED001B97AD /* mkdir */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mkdir; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B8214B648ED001B97AD /* mkfifo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mkfifo; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B8A14B648ED001B97AD /* mknod */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mknod; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B9214B648ED001B97AD /* mtree */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mtree; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8B9A14B648EE001B97AD /* mv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mv; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8BA214B648EE001B97AD /* pathchk */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pathchk; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8BAA14B648EE001B97AD /* pax */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pax; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8BB214B648EF001B97AD /* rm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rm; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8BBA14B648EF001B97AD /* rmdir */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rmdir; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8BCA14B648EF001B97AD /* stat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stat; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8BD214B648F0001B97AD /* touch */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = touch; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC8A8C4D14B64EA8001B97AD /* readlink.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = readlink.1; sourceTree = "<group>"; };
+ FC8A8C4F14B650C3001B97AD /* unlink.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = unlink.1; sourceTree = "<group>"; };
+ FC8A8C6614B6535B001B97AD /* sum.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = sum.1; sourceTree = "<group>"; };
+ FC8A8C7214B65547001B97AD /* link.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = link.1; sourceTree = "<group>"; };
+ FC8A8CC114B658D6001B97AD /* libutil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libutil.dylib; path = /usr/lib/libutil.dylib; sourceTree = "<absolute>"; };
+ FC8A8CC414B65C3D001B97AD /* libcurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcurses.dylib; path = /usr/lib/libcurses.dylib; sourceTree = "<absolute>"; };
+ FCB1BDB814B645D10070FACB /* chflags */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chflags; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCB1BDCB14B6460C0070FACB /* chflags.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = chflags.1; sourceTree = "<group>"; };
+ FCB1BDCC14B6460C0070FACB /* chflags.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chflags.c; sourceTree = "<group>"; };
+ FCB1BDCF14B6460C0070FACB /* chmod.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = chmod.1; sourceTree = "<group>"; };
+ FCB1BDD014B6460C0070FACB /* chmod.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chmod.c; sourceTree = "<group>"; };
+ FCB1BDD114B6460C0070FACB /* chmod_acl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chmod_acl.c; sourceTree = "<group>"; };
+ FCB1BDD214B6460C0070FACB /* chmod_acl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = chmod_acl.h; sourceTree = "<group>"; };
+ FCB1BDD514B6460C0070FACB /* chgrp.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = chgrp.1; sourceTree = "<group>"; };
+ FCB1BDD614B6460C0070FACB /* chown.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = chown.8; sourceTree = "<group>"; };
+ FCB1BDD714B6460C0070FACB /* chown.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chown.c; sourceTree = "<group>"; };
+ FCB1BDDA14B6460C0070FACB /* cksum.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = cksum.1; sourceTree = "<group>"; };
+ FCB1BDDB14B6460C0070FACB /* cksum.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cksum.c; sourceTree = "<group>"; };
+ FCB1BDDC14B6460C0070FACB /* crc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = crc.c; sourceTree = "<group>"; };
+ FCB1BDDD14B6460C0070FACB /* crc32.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = crc32.c; sourceTree = "<group>"; };
+ FCB1BDDE14B6460C0070FACB /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCB1BDE014B6460C0070FACB /* print.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; };
+ FCB1BDE114B6460C0070FACB /* sum1.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sum1.c; sourceTree = "<group>"; };
+ FCB1BDE214B6460C0070FACB /* sum2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sum2.c; sourceTree = "<group>"; usesTabs = 1; };
+ FCB1BDE414B6460C0070FACB /* compress.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = compress.1; sourceTree = "<group>"; };
+ FCB1BDE514B6460C0070FACB /* compress.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = compress.c; sourceTree = "<group>"; };
+ FCB1BDE714B6460C0070FACB /* NOTES */ = {isa = PBXFileReference; lastKnownFileType = text; path = NOTES; sourceTree = "<group>"; };
+ FCB1BDE814B6460C0070FACB /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ FCB1BDE914B6460C0070FACB /* revision.log */ = {isa = PBXFileReference; lastKnownFileType = text; path = revision.log; sourceTree = "<group>"; };
+ FCB1BDEB14B6460C0070FACB /* uncompress.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = uncompress.1; sourceTree = "<group>"; };
+ FCB1BDEC14B6460C0070FACB /* zcat.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = zcat.sh; sourceTree = "<group>"; };
+ FCB1BDED14B6460C0070FACB /* zopen.3 */ = {isa = PBXFileReference; lastKnownFileType = text; path = zopen.3; sourceTree = "<group>"; };
+ FCB1BDEE14B6460C0070FACB /* zopen.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zopen.c; sourceTree = "<group>"; };
+ FCB1BDEF14B6460C0070FACB /* zopen.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = zopen.h; sourceTree = "<group>"; };
+ FCB1BDF114B6460C0070FACB /* cp.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = cp.1; sourceTree = "<group>"; };
+ FCB1BDF214B6460C0070FACB /* cp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cp.c; sourceTree = "<group>"; };
+ FCB1BDF314B6460C0070FACB /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCB1BDF514B6460C0070FACB /* utils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = "<group>"; };
+ FCB1BDF714B6460C0070FACB /* strpct.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = strpct.c; sourceTree = "<group>"; };
+ FCB1BDF914B6460C0070FACB /* args.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = args.c; sourceTree = "<group>"; };
+ FCB1BDFA14B6460C0070FACB /* conv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = conv.c; sourceTree = "<group>"; };
+ FCB1BDFB14B6460C0070FACB /* conv_tab.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = conv_tab.c; sourceTree = "<group>"; };
+ FCB1BDFC14B6460C0070FACB /* dd.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = dd.1; sourceTree = "<group>"; };
+ FCB1BDFD14B6460C0070FACB /* dd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dd.c; sourceTree = "<group>"; };
+ FCB1BDFE14B6460C0070FACB /* dd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dd.h; sourceTree = "<group>"; };
+ FCB1BDFF14B6460C0070FACB /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCB1BE0114B6460C0070FACB /* misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+ FCB1BE0214B6460C0070FACB /* position.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = position.c; sourceTree = "<group>"; };
+ FCB1BE0414B6460C0070FACB /* df.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = df.1; sourceTree = "<group>"; };
+ FCB1BE0514B6460C0070FACB /* df.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = df.c; sourceTree = "<group>"; };
+ FCB1BE0714B6460C0070FACB /* vfslist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vfslist.c; sourceTree = "<group>"; };
+ FCB1BE0914B6460C0070FACB /* du.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = du.1; sourceTree = "<group>"; };
+ FCB1BE0A14B6460C0070FACB /* du.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = du.c; sourceTree = "<group>"; };
+ FCB1BE0D14B6460C0070FACB /* install.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = install.1; sourceTree = "<group>"; };
+ FCB1BE0F14B6460C0070FACB /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FCB1BE1014B6460C0070FACB /* xinstall.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xinstall.c; sourceTree = "<group>"; };
+ FCB1BE1214B6460C0070FACB /* ipcrm.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = ipcrm.1; sourceTree = "<group>"; };
+ FCB1BE1314B6460C0070FACB /* ipcrm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ipcrm.c; sourceTree = "<group>"; };
+ FCB1BE1614B6460C0070FACB /* ipcs.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = ipcs.1; sourceTree = "<group>"; };
+ FCB1BE1714B6460C0070FACB /* ipcs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ipcs.c; sourceTree = "<group>"; };
+ FCB1BE1A14B6460C0070FACB /* ln.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = ln.1; sourceTree = "<group>"; };
+ FCB1BE1B14B6460C0070FACB /* ln.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ln.c; sourceTree = "<group>"; };
+ FCB1BE1D14B6460C0070FACB /* symlink.7 */ = {isa = PBXFileReference; lastKnownFileType = text; path = symlink.7; sourceTree = "<group>"; };
+ FCB1BE1F14B6460C0070FACB /* cmp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cmp.c; sourceTree = "<group>"; };
+ FCB1BE2014B6460C0070FACB /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCB1BE2114B6460C0070FACB /* ls.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; lineEnding = 0; path = ls.1; sourceTree = "<group>"; };
+ FCB1BE2214B6460C0070FACB /* ls.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ls.c; sourceTree = "<group>"; };
+ FCB1BE2314B6460C0070FACB /* ls.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ls.h; sourceTree = "<group>"; };
+ FCB1BE2514B6460C0070FACB /* print.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = print.c; sourceTree = "<group>"; };
+ FCB1BE2614B6460C0070FACB /* util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FCB1BE2A14B6460C0070FACB /* mkdir.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = mkdir.1; sourceTree = "<group>"; };
+ FCB1BE2B14B6460C0070FACB /* mkdir.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mkdir.c; sourceTree = "<group>"; };
+ FCB1BE2E14B6460C0070FACB /* mkfifo.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = mkfifo.1; sourceTree = "<group>"; };
+ FCB1BE2F14B6460C0070FACB /* mkfifo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mkfifo.c; sourceTree = "<group>"; };
+ FCB1BE3214B6460C0070FACB /* mknod.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = mknod.8; sourceTree = "<group>"; };
+ FCB1BE3314B6460C0070FACB /* mknod.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mknod.c; sourceTree = "<group>"; };
+ FCB1BE3514B6460C0070FACB /* commoncrypto.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = commoncrypto.c; sourceTree = "<group>"; };
+ FCB1BE3614B6460C0070FACB /* commoncrypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = commoncrypto.h; sourceTree = "<group>"; };
+ FCB1BE3714B6460C0070FACB /* compare.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = compare.c; sourceTree = "<group>"; };
+ FCB1BE3814B6460C0070FACB /* create.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = create.c; sourceTree = "<group>"; };
+ FCB1BE3914B6460C0070FACB /* excludes.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = excludes.c; sourceTree = "<group>"; };
+ FCB1BE3A14B6460C0070FACB /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCB1BE3C14B6460C0070FACB /* misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+ FCB1BE3D14B6460C0070FACB /* mtree.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = mtree.8; sourceTree = "<group>"; };
+ FCB1BE3E14B6460C0070FACB /* mtree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mtree.c; sourceTree = "<group>"; };
+ FCB1BE3F14B6460C0070FACB /* mtree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mtree.h; sourceTree = "<group>"; };
+ FCB1BE4014B6460C0070FACB /* spec.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = spec.c; sourceTree = "<group>"; };
+ FCB1BE4114B6460C0070FACB /* specspec.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = specspec.c; sourceTree = "<group>"; };
+ FCB1BE4314B6460C0070FACB /* test00.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = test00.sh; sourceTree = "<group>"; };
+ FCB1BE4414B6460C0070FACB /* test01.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = test01.sh; sourceTree = "<group>"; };
+ FCB1BE4514B6460C0070FACB /* test02.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = test02.sh; sourceTree = "<group>"; };
+ FCB1BE4614B6460C0070FACB /* test03.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = test03.sh; sourceTree = "<group>"; };
+ FCB1BE4714B6460C0070FACB /* test04.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = test04.sh; sourceTree = "<group>"; };
+ FCB1BE4814B6460C0070FACB /* verify.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = verify.c; sourceTree = "<group>"; };
+ FCB1BE4B14B6460C0070FACB /* mv.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = mv.1; sourceTree = "<group>"; };
+ FCB1BE4C14B6460C0070FACB /* mv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mv.c; sourceTree = "<group>"; };
+ FCB1BE4D14B6460C0070FACB /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FCB1BE5014B6460C0070FACB /* pathchk.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = pathchk.1; sourceTree = "<group>"; };
+ FCB1BE5114B6460C0070FACB /* pathchk.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pathchk.c; sourceTree = "<group>"; };
+ FCB1BE5314B6460C0070FACB /* ar_io.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ar_io.c; sourceTree = "<group>"; };
+ FCB1BE5414B6460C0070FACB /* ar_subs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ar_subs.c; sourceTree = "<group>"; };
+ FCB1BE5514B6460C0070FACB /* buf_subs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = buf_subs.c; sourceTree = "<group>"; };
+ FCB1BE5614B6460C0070FACB /* cache.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cache.c; sourceTree = "<group>"; };
+ FCB1BE5714B6460C0070FACB /* cache.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cache.h; sourceTree = "<group>"; };
+ FCB1BE5814B6460C0070FACB /* cpio.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = cpio.1; sourceTree = "<group>"; };
+ FCB1BE5914B6460C0070FACB /* cpio.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cpio.c; sourceTree = "<group>"; };
+ FCB1BE5A14B6460C0070FACB /* cpio.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cpio.h; sourceTree = "<group>"; };
+ FCB1BE5B14B6460C0070FACB /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCB1BE5C14B6460C0070FACB /* file_subs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = file_subs.c; sourceTree = "<group>"; };
+ FCB1BE5D14B6460C0070FACB /* ftree.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ftree.c; sourceTree = "<group>"; };
+ FCB1BE5E14B6460C0070FACB /* ftree.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ftree.h; sourceTree = "<group>"; };
+ FCB1BE5F14B6460C0070FACB /* gen_subs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gen_subs.c; sourceTree = "<group>"; };
+ FCB1BE6014B6460C0070FACB /* getoldopt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = getoldopt.c; sourceTree = "<group>"; };
+ FCB1BE6214B6460C0070FACB /* options.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = options.c; sourceTree = "<group>"; };
+ FCB1BE6314B6460C0070FACB /* options.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = options.h; sourceTree = "<group>"; };
+ FCB1BE6414B6460C0070FACB /* pat_rep.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pat_rep.c; sourceTree = "<group>"; };
+ FCB1BE6514B6460C0070FACB /* pat_rep.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pat_rep.h; sourceTree = "<group>"; };
+ FCB1BE6614B6460C0070FACB /* pax.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = pax.1; sourceTree = "<group>"; };
+ FCB1BE6714B6460C0070FACB /* pax.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pax.c; sourceTree = "<group>"; };
+ FCB1BE6814B6460C0070FACB /* pax.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pax.h; sourceTree = "<group>"; };
+ FCB1BE6914B6460C0070FACB /* pax_format.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pax_format.c; sourceTree = "<group>"; };
+ FCB1BE6A14B6460C0070FACB /* pax_format.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pax_format.h; sourceTree = "<group>"; };
+ FCB1BE6B14B6460C0070FACB /* sel_subs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sel_subs.c; sourceTree = "<group>"; };
+ FCB1BE6C14B6460C0070FACB /* sel_subs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sel_subs.h; sourceTree = "<group>"; };
+ FCB1BE6D14B6460C0070FACB /* tables.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tables.c; sourceTree = "<group>"; };
+ FCB1BE6E14B6460C0070FACB /* tables.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tables.h; sourceTree = "<group>"; };
+ FCB1BE6F14B6460C0070FACB /* tar.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tar.c; sourceTree = "<group>"; };
+ FCB1BE7014B6460C0070FACB /* tar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tar.h; sourceTree = "<group>"; };
+ FCB1BE7114B6460C0070FACB /* tty_subs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tty_subs.c; sourceTree = "<group>"; };
+ FCB1BE7414B6460C0070FACB /* rm.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = rm.1; sourceTree = "<group>"; };
+ FCB1BE7514B6460C0070FACB /* rm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rm.c; sourceTree = "<group>"; };
+ FCB1BE7814B6460C0070FACB /* rmdir.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = rmdir.1; sourceTree = "<group>"; };
+ FCB1BE7914B6460C0070FACB /* rmdir.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rmdir.c; sourceTree = "<group>"; };
+ FCB1BE7C14B6460C0070FACB /* rmt.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = rmt.8; sourceTree = "<group>"; };
+ FCB1BE7D14B6460C0070FACB /* rmt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rmt.c; sourceTree = "<group>"; };
+ FCB1BE8014B6460C0070FACB /* shar.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = shar.1; sourceTree = "<group>"; };
+ FCB1BE8114B6460C0070FACB /* shar.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = shar.sh; sourceTree = "<group>"; };
+ FCB1BE8414B6460C0070FACB /* stat.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = stat.1; sourceTree = "<group>"; };
+ FCB1BE8514B6460C0070FACB /* stat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = stat.c; sourceTree = "<group>"; };
+ FCB1BE8814B6460C0070FACB /* touch.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = touch.1; sourceTree = "<group>"; };
+ FCB1BE8914B6460C0070FACB /* touch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = touch.c; sourceTree = "<group>"; };
+ FDAD94801808BB3A00B4D5A0 /* gzexe */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = gzexe; sourceTree = "<group>"; };
+ FDAD94811808BB3A00B4D5A0 /* gzexe.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = gzexe.1; sourceTree = "<group>"; };
+ FDAD94821808BB3A00B4D5A0 /* gzip.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = gzip.1; sourceTree = "<group>"; };
+ FDAD94831808BB3A00B4D5A0 /* gzip.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gzip.c; sourceTree = "<group>"; };
+ FDAD94841808BB3A00B4D5A0 /* gzip.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = gzip.plist; sourceTree = "<group>"; };
+ FDAD94851808BB3A00B4D5A0 /* gzip.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = gzip.xcconfig; sourceTree = "<group>"; };
+ FDAD94861808BB3A00B4D5A0 /* install_scripts.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = install_scripts.sh; sourceTree = "<group>"; };
+ FDAD94871808BB3A00B4D5A0 /* unbzip2.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = unbzip2.c; sourceTree = "<group>"; };
+ FDAD94881808BB3A00B4D5A0 /* unpack.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = unpack.c; sourceTree = "<group>"; };
+ FDAD94891808BB3A00B4D5A0 /* unxz.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = unxz.c; sourceTree = "<group>"; };
+ FDAD948A1808BB3A00B4D5A0 /* zdiff */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = zdiff; sourceTree = "<group>"; };
+ FDAD948B1808BB3A00B4D5A0 /* zdiff.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = zdiff.1; sourceTree = "<group>"; };
+ FDAD948C1808BB3A00B4D5A0 /* zforce */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = zforce; sourceTree = "<group>"; };
+ FDAD948D1808BB3A00B4D5A0 /* zforce.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = zforce.1; sourceTree = "<group>"; };
+ FDAD948E1808BB3A00B4D5A0 /* zmore */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = zmore; sourceTree = "<group>"; };
+ FDAD948F1808BB3A00B4D5A0 /* zmore.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = zmore.1; sourceTree = "<group>"; };
+ FDAD94901808BB3A00B4D5A0 /* znew */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = znew; sourceTree = "<group>"; };
+ FDAD94911808BB3A00B4D5A0 /* znew.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = znew.1; sourceTree = "<group>"; };
+ FDAD94921808BB3A00B4D5A0 /* zuncompress.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zuncompress.c; sourceTree = "<group>"; };
+ FDAD94971808BB6D00B4D5A0 /* gzip */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gzip; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDAD94A11808BC9100B4D5A0 /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; };
+ FDAD94A31808BC9700B4D5A0 /* liblzma.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = liblzma.dylib; path = usr/lib/liblzma.dylib; sourceTree = SDKROOT; };
+ FDAD94A51808BC9B00B4D5A0 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FC8A8B0E14B648D7001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B1614B648E0001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B1E14B648E3001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B2614B648E5001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B2E14B648E7001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B3614B648EA001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B3E14B648EA001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8CC214B658D7001B97AD /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B4614B648EB001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B4E14B648EB001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B5614B648EB001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B5E14B648EC001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B6614B648EC001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B6E14B648ED001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8CC614B65C46001B97AD /* libutil.dylib in Frameworks */,
+ FC8A8CC514B65C3D001B97AD /* libcurses.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B7614B648ED001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B7E14B648ED001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B8614B648ED001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B8E14B648ED001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 729D06D8230B5E42000716E5 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B9614B648EE001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B9E14B648EE001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BA614B648EE001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BAE14B648EF001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BB614B648EF001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BC614B648EF001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BCE14B648F0001B97AD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCB1BDB514B645D10070FACB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDAD94941808BB6D00B4D5A0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDAD94A21808BC9100B4D5A0 /* libbz2.dylib in Frameworks */,
+ FDAD94A41808BC9700B4D5A0 /* liblzma.dylib in Frameworks */,
+ FDAD94A61808BC9B00B4D5A0 /* libz.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 3E966CEA1FB221330019F7A1 /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ 3E966CEB1FB2214F0019F7A1 /* chgrp.sh */,
+ 3E966CEC1FB2214F0019F7A1 /* file_cmds.plist */,
+ );
+ path = tests;
+ sourceTree = "<group>";
+ };
+ 729D06D6230B5E42000716E5 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 729D06D7230B5E42000716E5 /* CoreFoundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ FCB1BDAD14B645D00070FACB = {
+ isa = PBXGroup;
+ children = (
+ 3E966CEA1FB221330019F7A1 /* tests */,
+ FCB1BDCA14B6460C0070FACB /* chflags */,
+ FCB1BDCE14B6460C0070FACB /* chmod */,
+ FCB1BDD414B6460C0070FACB /* chown */,
+ FCB1BDD914B6460C0070FACB /* cksum */,
+ FCB1BDE314B6460C0070FACB /* compress */,
+ FCB1BDF014B6460C0070FACB /* cp */,
+ FCB1BDF614B6460C0070FACB /* csh */,
+ FCB1BDF814B6460C0070FACB /* dd */,
+ FCB1BE0314B6460C0070FACB /* df */,
+ FCB1BE0814B6460C0070FACB /* du */,
+ FDAD947F1808BB3A00B4D5A0 /* gzip */,
+ FCB1BE0C14B6460C0070FACB /* install */,
+ FCB1BE1114B6460C0070FACB /* ipcrm */,
+ FCB1BE1514B6460C0070FACB /* ipcs */,
+ FCB1BE1914B6460C0070FACB /* ln */,
+ FCB1BE1E14B6460C0070FACB /* ls */,
+ FCB1BE2814B6460C0070FACB /* mkdir */,
+ FCB1BE2C14B6460C0070FACB /* mkfifo */,
+ FCB1BE3014B6460C0070FACB /* mknod */,
+ FCB1BE3414B6460C0070FACB /* mtree */,
+ FCB1BE4914B6460C0070FACB /* mv */,
+ FCB1BE4E14B6460C0070FACB /* pathchk */,
+ FCB1BE5214B6460C0070FACB /* pax */,
+ FCB1BE7214B6460C0070FACB /* rm */,
+ FCB1BE7614B6460C0070FACB /* rmdir */,
+ FCB1BE7A14B6460C0070FACB /* rmt */,
+ FCB1BE7E14B6460C0070FACB /* shar */,
+ FCB1BE8214B6460C0070FACB /* stat */,
+ FCB1BE8614B6460C0070FACB /* touch */,
+ FDAD94A71808BCB700B4D5A0 /* Libraries */,
+ FCB1BDB914B645D10070FACB /* Products */,
+ 729D06D6230B5E42000716E5 /* Frameworks */,
+ );
+ indentWidth = 8;
+ sourceTree = "<group>";
+ tabWidth = 8;
+ usesTabs = 1;
+ };
+ FCB1BDB914B645D10070FACB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BDB814B645D10070FACB /* chflags */,
+ FC8A8B1214B648D7001B97AD /* chmod */,
+ FC8A8B1A14B648E0001B97AD /* chown */,
+ FC8A8B2214B648E3001B97AD /* cksum */,
+ FC8A8B2A14B648E5001B97AD /* compress */,
+ FC8A8B3214B648E7001B97AD /* cp */,
+ FC8A8B3A14B648EA001B97AD /* dd */,
+ FC8A8B4214B648EA001B97AD /* df */,
+ FC8A8B4A14B648EB001B97AD /* du */,
+ FC8A8B5214B648EB001B97AD /* install */,
+ FC8A8B5A14B648EB001B97AD /* ipcrm */,
+ FC8A8B6214B648EC001B97AD /* ipcs */,
+ FC8A8B6A14B648EC001B97AD /* ln */,
+ FC8A8B7214B648ED001B97AD /* ls */,
+ FC8A8B7A14B648ED001B97AD /* mkdir */,
+ FC8A8B8214B648ED001B97AD /* mkfifo */,
+ FC8A8B8A14B648ED001B97AD /* mknod */,
+ FC8A8B9214B648ED001B97AD /* mtree */,
+ FC8A8B9A14B648EE001B97AD /* mv */,
+ FC8A8BA214B648EE001B97AD /* pathchk */,
+ FC8A8BAA14B648EE001B97AD /* pax */,
+ FC8A8BB214B648EF001B97AD /* rm */,
+ FC8A8BBA14B648EF001B97AD /* rmdir */,
+ FC8A8BCA14B648EF001B97AD /* stat */,
+ FC8A8BD214B648F0001B97AD /* touch */,
+ FDAD94971808BB6D00B4D5A0 /* gzip */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FCB1BDCA14B6460C0070FACB /* chflags */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BDCB14B6460C0070FACB /* chflags.1 */,
+ FCB1BDCC14B6460C0070FACB /* chflags.c */,
+ );
+ path = chflags;
+ sourceTree = "<group>";
+ };
+ FCB1BDCE14B6460C0070FACB /* chmod */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BDCF14B6460C0070FACB /* chmod.1 */,
+ FCB1BDD014B6460C0070FACB /* chmod.c */,
+ FCB1BDD114B6460C0070FACB /* chmod_acl.c */,
+ FCB1BDD214B6460C0070FACB /* chmod_acl.h */,
+ );
+ path = chmod;
+ sourceTree = "<group>";
+ };
+ FCB1BDD414B6460C0070FACB /* chown */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BDD514B6460C0070FACB /* chgrp.1 */,
+ FCB1BDD614B6460C0070FACB /* chown.8 */,
+ FCB1BDD714B6460C0070FACB /* chown.c */,
+ );
+ path = chown;
+ sourceTree = "<group>";
+ };
+ FCB1BDD914B6460C0070FACB /* cksum */ = {
+ isa = PBXGroup;
+ children = (
+ FC8A8C6614B6535B001B97AD /* sum.1 */,
+ FCB1BDDA14B6460C0070FACB /* cksum.1 */,
+ FCB1BDDB14B6460C0070FACB /* cksum.c */,
+ FCB1BDDC14B6460C0070FACB /* crc.c */,
+ FCB1BDDD14B6460C0070FACB /* crc32.c */,
+ FCB1BDDE14B6460C0070FACB /* extern.h */,
+ FCB1BDE014B6460C0070FACB /* print.c */,
+ FCB1BDE114B6460C0070FACB /* sum1.c */,
+ FCB1BDE214B6460C0070FACB /* sum2.c */,
+ );
+ path = cksum;
+ sourceTree = "<group>";
+ };
+ FCB1BDE314B6460C0070FACB /* compress */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BDE414B6460C0070FACB /* compress.1 */,
+ FCB1BDE514B6460C0070FACB /* compress.c */,
+ FCB1BDE614B6460C0070FACB /* doc */,
+ FCB1BDEB14B6460C0070FACB /* uncompress.1 */,
+ FCB1BDEC14B6460C0070FACB /* zcat.sh */,
+ FCB1BDED14B6460C0070FACB /* zopen.3 */,
+ FCB1BDEE14B6460C0070FACB /* zopen.c */,
+ FCB1BDEF14B6460C0070FACB /* zopen.h */,
+ );
+ path = compress;
+ sourceTree = "<group>";
+ };
+ FCB1BDE614B6460C0070FACB /* doc */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BDE714B6460C0070FACB /* NOTES */,
+ FCB1BDE814B6460C0070FACB /* README */,
+ FCB1BDE914B6460C0070FACB /* revision.log */,
+ );
+ path = doc;
+ sourceTree = "<group>";
+ };
+ FCB1BDF014B6460C0070FACB /* cp */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BDF114B6460C0070FACB /* cp.1 */,
+ FCB1BDF214B6460C0070FACB /* cp.c */,
+ FCB1BDF314B6460C0070FACB /* extern.h */,
+ FCB1BDF514B6460C0070FACB /* utils.c */,
+ );
+ path = cp;
+ sourceTree = "<group>";
+ };
+ FCB1BDF614B6460C0070FACB /* csh */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BDF714B6460C0070FACB /* strpct.c */,
+ );
+ path = csh;
+ sourceTree = "<group>";
+ };
+ FCB1BDF814B6460C0070FACB /* dd */ = {
+ isa = PBXGroup;
+ children = (
+ 0773099A1A3A4DFE00E9B4EA /* dd.entitlements */,
+ FCB1BDF914B6460C0070FACB /* args.c */,
+ FCB1BDFA14B6460C0070FACB /* conv.c */,
+ FCB1BDFB14B6460C0070FACB /* conv_tab.c */,
+ FCB1BDFC14B6460C0070FACB /* dd.1 */,
+ FCB1BDFD14B6460C0070FACB /* dd.c */,
+ FCB1BDFE14B6460C0070FACB /* dd.h */,
+ FCB1BDFF14B6460C0070FACB /* extern.h */,
+ FCB1BE0114B6460C0070FACB /* misc.c */,
+ FCB1BE0214B6460C0070FACB /* position.c */,
+ );
+ path = dd;
+ sourceTree = "<group>";
+ };
+ FCB1BE0314B6460C0070FACB /* df */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE0414B6460C0070FACB /* df.1 */,
+ FCB1BE0514B6460C0070FACB /* df.c */,
+ FCB1BE0714B6460C0070FACB /* vfslist.c */,
+ );
+ path = df;
+ sourceTree = "<group>";
+ };
+ FCB1BE0814B6460C0070FACB /* du */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE0914B6460C0070FACB /* du.1 */,
+ FCB1BE0A14B6460C0070FACB /* du.c */,
+ );
+ path = du;
+ sourceTree = "<group>";
+ };
+ FCB1BE0C14B6460C0070FACB /* install */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE0D14B6460C0070FACB /* install.1 */,
+ FCB1BE0F14B6460C0070FACB /* pathnames.h */,
+ FCB1BE1014B6460C0070FACB /* xinstall.c */,
+ );
+ path = install;
+ sourceTree = "<group>";
+ };
+ FCB1BE1114B6460C0070FACB /* ipcrm */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE1214B6460C0070FACB /* ipcrm.1 */,
+ FCB1BE1314B6460C0070FACB /* ipcrm.c */,
+ );
+ path = ipcrm;
+ sourceTree = "<group>";
+ };
+ FCB1BE1514B6460C0070FACB /* ipcs */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE1614B6460C0070FACB /* ipcs.1 */,
+ FCB1BE1714B6460C0070FACB /* ipcs.c */,
+ );
+ path = ipcs;
+ sourceTree = "<group>";
+ };
+ FCB1BE1914B6460C0070FACB /* ln */ = {
+ isa = PBXGroup;
+ children = (
+ FC8A8C7214B65547001B97AD /* link.1 */,
+ FCB1BE1A14B6460C0070FACB /* ln.1 */,
+ FCB1BE1B14B6460C0070FACB /* ln.c */,
+ FCB1BE1D14B6460C0070FACB /* symlink.7 */,
+ );
+ path = ln;
+ sourceTree = "<group>";
+ };
+ FCB1BE1E14B6460C0070FACB /* ls */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE1F14B6460C0070FACB /* cmp.c */,
+ FCB1BE2014B6460C0070FACB /* extern.h */,
+ FCB1BE2114B6460C0070FACB /* ls.1 */,
+ FCB1BE2214B6460C0070FACB /* ls.c */,
+ FCB1BE2314B6460C0070FACB /* ls.h */,
+ FCB1BE2514B6460C0070FACB /* print.c */,
+ FCB1BE2614B6460C0070FACB /* util.c */,
+ FC8A8CC414B65C3D001B97AD /* libcurses.dylib */,
+ FC8A8CC114B658D6001B97AD /* libutil.dylib */,
+ );
+ path = ls;
+ sourceTree = "<group>";
+ };
+ FCB1BE2814B6460C0070FACB /* mkdir */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE2A14B6460C0070FACB /* mkdir.1 */,
+ FCB1BE2B14B6460C0070FACB /* mkdir.c */,
+ );
+ path = mkdir;
+ sourceTree = "<group>";
+ };
+ FCB1BE2C14B6460C0070FACB /* mkfifo */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE2E14B6460C0070FACB /* mkfifo.1 */,
+ FCB1BE2F14B6460C0070FACB /* mkfifo.c */,
+ );
+ path = mkfifo;
+ sourceTree = "<group>";
+ };
+ FCB1BE3014B6460C0070FACB /* mknod */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE3214B6460C0070FACB /* mknod.8 */,
+ FCB1BE3314B6460C0070FACB /* mknod.c */,
+ );
+ path = mknod;
+ sourceTree = "<group>";
+ };
+ FCB1BE3414B6460C0070FACB /* mtree */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE3514B6460C0070FACB /* commoncrypto.c */,
+ FCB1BE3614B6460C0070FACB /* commoncrypto.h */,
+ FCB1BE3714B6460C0070FACB /* compare.c */,
+ FCB1BE3814B6460C0070FACB /* create.c */,
+ FCB1BE3914B6460C0070FACB /* excludes.c */,
+ FCB1BE3A14B6460C0070FACB /* extern.h */,
+ FCB1BE3C14B6460C0070FACB /* misc.c */,
+ FCB1BE3D14B6460C0070FACB /* mtree.8 */,
+ FCB1BE3E14B6460C0070FACB /* mtree.c */,
+ FCB1BE3F14B6460C0070FACB /* mtree.h */,
+ FCB1BE4014B6460C0070FACB /* spec.c */,
+ FCB1BE4114B6460C0070FACB /* specspec.c */,
+ FCB1BE4214B6460C0070FACB /* test */,
+ FCB1BE4814B6460C0070FACB /* verify.c */,
+ 7D0A20E82499364700F0F6D7 /* metrics.h */,
+ 7D0A20E92499364700F0F6D7 /* metrics.c */,
+ );
+ path = mtree;
+ sourceTree = "<group>";
+ };
+ FCB1BE4214B6460C0070FACB /* test */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE4314B6460C0070FACB /* test00.sh */,
+ FCB1BE4414B6460C0070FACB /* test01.sh */,
+ FCB1BE4514B6460C0070FACB /* test02.sh */,
+ FCB1BE4614B6460C0070FACB /* test03.sh */,
+ FCB1BE4714B6460C0070FACB /* test04.sh */,
+ );
+ path = test;
+ sourceTree = "<group>";
+ };
+ FCB1BE4914B6460C0070FACB /* mv */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE4B14B6460C0070FACB /* mv.1 */,
+ FCB1BE4C14B6460C0070FACB /* mv.c */,
+ FCB1BE4D14B6460C0070FACB /* pathnames.h */,
+ );
+ path = mv;
+ sourceTree = "<group>";
+ };
+ FCB1BE4E14B6460C0070FACB /* pathchk */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE5014B6460C0070FACB /* pathchk.1 */,
+ FCB1BE5114B6460C0070FACB /* pathchk.c */,
+ );
+ path = pathchk;
+ sourceTree = "<group>";
+ };
+ FCB1BE5214B6460C0070FACB /* pax */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE5314B6460C0070FACB /* ar_io.c */,
+ FCB1BE5414B6460C0070FACB /* ar_subs.c */,
+ FCB1BE5514B6460C0070FACB /* buf_subs.c */,
+ FCB1BE5614B6460C0070FACB /* cache.c */,
+ FCB1BE5714B6460C0070FACB /* cache.h */,
+ FCB1BE5814B6460C0070FACB /* cpio.1 */,
+ FCB1BE5914B6460C0070FACB /* cpio.c */,
+ FCB1BE5A14B6460C0070FACB /* cpio.h */,
+ FCB1BE5B14B6460C0070FACB /* extern.h */,
+ FCB1BE5C14B6460C0070FACB /* file_subs.c */,
+ FCB1BE5D14B6460C0070FACB /* ftree.c */,
+ FCB1BE5E14B6460C0070FACB /* ftree.h */,
+ FCB1BE5F14B6460C0070FACB /* gen_subs.c */,
+ FCB1BE6014B6460C0070FACB /* getoldopt.c */,
+ FCB1BE6214B6460C0070FACB /* options.c */,
+ FCB1BE6314B6460C0070FACB /* options.h */,
+ FCB1BE6414B6460C0070FACB /* pat_rep.c */,
+ FCB1BE6514B6460C0070FACB /* pat_rep.h */,
+ FCB1BE6614B6460C0070FACB /* pax.1 */,
+ FCB1BE6714B6460C0070FACB /* pax.c */,
+ FCB1BE6814B6460C0070FACB /* pax.h */,
+ FCB1BE6914B6460C0070FACB /* pax_format.c */,
+ FCB1BE6A14B6460C0070FACB /* pax_format.h */,
+ FCB1BE6B14B6460C0070FACB /* sel_subs.c */,
+ FCB1BE6C14B6460C0070FACB /* sel_subs.h */,
+ FCB1BE6D14B6460C0070FACB /* tables.c */,
+ FCB1BE6E14B6460C0070FACB /* tables.h */,
+ FCB1BE6F14B6460C0070FACB /* tar.c */,
+ FCB1BE7014B6460C0070FACB /* tar.h */,
+ FCB1BE7114B6460C0070FACB /* tty_subs.c */,
+ );
+ path = pax;
+ sourceTree = "<group>";
+ };
+ FCB1BE7214B6460C0070FACB /* rm */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE7414B6460C0070FACB /* rm.1 */,
+ FCB1BE7514B6460C0070FACB /* rm.c */,
+ FC8A8C4F14B650C3001B97AD /* unlink.1 */,
+ );
+ path = rm;
+ sourceTree = "<group>";
+ };
+ FCB1BE7614B6460C0070FACB /* rmdir */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE7814B6460C0070FACB /* rmdir.1 */,
+ FCB1BE7914B6460C0070FACB /* rmdir.c */,
+ );
+ path = rmdir;
+ sourceTree = "<group>";
+ };
+ FCB1BE7A14B6460C0070FACB /* rmt */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE7C14B6460C0070FACB /* rmt.8 */,
+ FCB1BE7D14B6460C0070FACB /* rmt.c */,
+ );
+ path = rmt;
+ sourceTree = "<group>";
+ };
+ FCB1BE7E14B6460C0070FACB /* shar */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE8014B6460C0070FACB /* shar.1 */,
+ FCB1BE8114B6460C0070FACB /* shar.sh */,
+ );
+ path = shar;
+ sourceTree = "<group>";
+ };
+ FCB1BE8214B6460C0070FACB /* stat */ = {
+ isa = PBXGroup;
+ children = (
+ FC8A8C4D14B64EA8001B97AD /* readlink.1 */,
+ FCB1BE8414B6460C0070FACB /* stat.1 */,
+ FCB1BE8514B6460C0070FACB /* stat.c */,
+ );
+ path = stat;
+ sourceTree = "<group>";
+ };
+ FCB1BE8614B6460C0070FACB /* touch */ = {
+ isa = PBXGroup;
+ children = (
+ FCB1BE8814B6460C0070FACB /* touch.1 */,
+ FCB1BE8914B6460C0070FACB /* touch.c */,
+ );
+ path = touch;
+ sourceTree = "<group>";
+ };
+ FDAD947F1808BB3A00B4D5A0 /* gzip */ = {
+ isa = PBXGroup;
+ children = (
+ 3E59B9301D4A767600D3128C /* futimens.c */,
+ FDAD94801808BB3A00B4D5A0 /* gzexe */,
+ FDAD94811808BB3A00B4D5A0 /* gzexe.1 */,
+ FDAD94821808BB3A00B4D5A0 /* gzip.1 */,
+ FDAD94831808BB3A00B4D5A0 /* gzip.c */,
+ FDAD94841808BB3A00B4D5A0 /* gzip.plist */,
+ FDAD94851808BB3A00B4D5A0 /* gzip.xcconfig */,
+ FDAD94861808BB3A00B4D5A0 /* install_scripts.sh */,
+ FDAD94871808BB3A00B4D5A0 /* unbzip2.c */,
+ FDAD94881808BB3A00B4D5A0 /* unpack.c */,
+ FDAD94891808BB3A00B4D5A0 /* unxz.c */,
+ FDAD948A1808BB3A00B4D5A0 /* zdiff */,
+ FDAD948B1808BB3A00B4D5A0 /* zdiff.1 */,
+ FDAD948C1808BB3A00B4D5A0 /* zforce */,
+ FDAD948D1808BB3A00B4D5A0 /* zforce.1 */,
+ FDAD948E1808BB3A00B4D5A0 /* zmore */,
+ FDAD948F1808BB3A00B4D5A0 /* zmore.1 */,
+ FDAD94901808BB3A00B4D5A0 /* znew */,
+ FDAD94911808BB3A00B4D5A0 /* znew.1 */,
+ FDAD94921808BB3A00B4D5A0 /* zuncompress.c */,
+ );
+ path = gzip;
+ sourceTree = "<group>";
+ };
+ FDAD94A71808BCB700B4D5A0 /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ FDAD94A11808BC9100B4D5A0 /* libbz2.dylib */,
+ FDAD94A31808BC9700B4D5A0 /* liblzma.dylib */,
+ FDAD94A51808BC9B00B4D5A0 /* libz.dylib */,
+ );
+ name = Libraries;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ FC8A8B0B14B648D7001B97AD /* chmod */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B1014B648D7001B97AD /* Build configuration list for PBXNativeTarget "chmod" */;
+ buildPhases = (
+ FC8A8B0C14B648D7001B97AD /* Sources */,
+ FC8A8B0E14B648D7001B97AD /* Frameworks */,
+ FC8A8B0F14B648D7001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chmod;
+ productName = file_cmds;
+ productReference = FC8A8B1214B648D7001B97AD /* chmod */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B1414B648E0001B97AD /* chown */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B1814B648E0001B97AD /* Build configuration list for PBXNativeTarget "chown" */;
+ buildPhases = (
+ FC8A8B1514B648E0001B97AD /* Sources */,
+ FC8A8B1614B648E0001B97AD /* Frameworks */,
+ FC8A8B1714B648E0001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chown;
+ productName = file_cmds;
+ productReference = FC8A8B1A14B648E0001B97AD /* chown */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B1C14B648E3001B97AD /* cksum */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B2014B648E3001B97AD /* Build configuration list for PBXNativeTarget "cksum" */;
+ buildPhases = (
+ FC8A8B1D14B648E3001B97AD /* Sources */,
+ FC8A8B1E14B648E3001B97AD /* Frameworks */,
+ FC8A8B1F14B648E3001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cksum;
+ productName = file_cmds;
+ productReference = FC8A8B2214B648E3001B97AD /* cksum */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B2414B648E5001B97AD /* compress */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B2814B648E5001B97AD /* Build configuration list for PBXNativeTarget "compress" */;
+ buildPhases = (
+ FC8A8B2514B648E5001B97AD /* Sources */,
+ FC8A8B2614B648E5001B97AD /* Frameworks */,
+ FC8A8B2714B648E5001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = compress;
+ productName = file_cmds;
+ productReference = FC8A8B2A14B648E5001B97AD /* compress */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B2C14B648E7001B97AD /* cp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B3014B648E7001B97AD /* Build configuration list for PBXNativeTarget "cp" */;
+ buildPhases = (
+ FC8A8B2D14B648E7001B97AD /* Sources */,
+ FC8A8B2E14B648E7001B97AD /* Frameworks */,
+ FC8A8B2F14B648E7001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cp;
+ productName = file_cmds;
+ productReference = FC8A8B3214B648E7001B97AD /* cp */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B3414B648EA001B97AD /* dd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B3814B648EA001B97AD /* Build configuration list for PBXNativeTarget "dd" */;
+ buildPhases = (
+ FC8A8B3514B648EA001B97AD /* Sources */,
+ FC8A8B3614B648EA001B97AD /* Frameworks */,
+ FC8A8B3714B648EA001B97AD /* CopyFiles */,
+ 72E62BA81A3A62960015FC8E /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dd;
+ productName = file_cmds;
+ productReference = FC8A8B3A14B648EA001B97AD /* dd */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B3C14B648EA001B97AD /* df */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B4014B648EA001B97AD /* Build configuration list for PBXNativeTarget "df" */;
+ buildPhases = (
+ FC8A8B3D14B648EA001B97AD /* Sources */,
+ FC8A8B3E14B648EA001B97AD /* Frameworks */,
+ FC8A8B3F14B648EA001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = df;
+ productName = file_cmds;
+ productReference = FC8A8B4214B648EA001B97AD /* df */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B4414B648EB001B97AD /* du */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B4814B648EB001B97AD /* Build configuration list for PBXNativeTarget "du" */;
+ buildPhases = (
+ FC8A8B4514B648EB001B97AD /* Sources */,
+ FC8A8B4614B648EB001B97AD /* Frameworks */,
+ FC8A8B4714B648EB001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = du;
+ productName = file_cmds;
+ productReference = FC8A8B4A14B648EB001B97AD /* du */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B4C14B648EB001B97AD /* install */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B5014B648EB001B97AD /* Build configuration list for PBXNativeTarget "install" */;
+ buildPhases = (
+ FC8A8B4D14B648EB001B97AD /* Sources */,
+ FC8A8B4E14B648EB001B97AD /* Frameworks */,
+ FC8A8B4F14B648EB001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = install;
+ productName = file_cmds;
+ productReference = FC8A8B5214B648EB001B97AD /* install */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B5414B648EB001B97AD /* ipcrm */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B5814B648EB001B97AD /* Build configuration list for PBXNativeTarget "ipcrm" */;
+ buildPhases = (
+ FC8A8B5514B648EB001B97AD /* Sources */,
+ FC8A8B5614B648EB001B97AD /* Frameworks */,
+ FC8A8B5714B648EB001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ipcrm;
+ productName = file_cmds;
+ productReference = FC8A8B5A14B648EB001B97AD /* ipcrm */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B5C14B648EC001B97AD /* ipcs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B6014B648EC001B97AD /* Build configuration list for PBXNativeTarget "ipcs" */;
+ buildPhases = (
+ FC8A8B5D14B648EC001B97AD /* Sources */,
+ FC8A8B5E14B648EC001B97AD /* Frameworks */,
+ FC8A8B5F14B648EC001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ipcs;
+ productName = file_cmds;
+ productReference = FC8A8B6214B648EC001B97AD /* ipcs */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B6414B648EC001B97AD /* ln */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B6814B648EC001B97AD /* Build configuration list for PBXNativeTarget "ln" */;
+ buildPhases = (
+ FC8A8B6514B648EC001B97AD /* Sources */,
+ FC8A8B6614B648EC001B97AD /* Frameworks */,
+ FC8A8B6714B648EC001B97AD /* CopyFiles */,
+ FC8A8C7E14B6557E001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ln;
+ productName = file_cmds;
+ productReference = FC8A8B6A14B648EC001B97AD /* ln */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B6C14B648ED001B97AD /* ls */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B7014B648ED001B97AD /* Build configuration list for PBXNativeTarget "ls" */;
+ buildPhases = (
+ FC8A8B6D14B648ED001B97AD /* Sources */,
+ FC8A8B6E14B648ED001B97AD /* Frameworks */,
+ FC8A8B6F14B648ED001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ls;
+ productName = file_cmds;
+ productReference = FC8A8B7214B648ED001B97AD /* ls */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B7414B648ED001B97AD /* mkdir */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B7814B648ED001B97AD /* Build configuration list for PBXNativeTarget "mkdir" */;
+ buildPhases = (
+ FC8A8B7514B648ED001B97AD /* Sources */,
+ FC8A8B7614B648ED001B97AD /* Frameworks */,
+ FC8A8B7714B648ED001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mkdir;
+ productName = file_cmds;
+ productReference = FC8A8B7A14B648ED001B97AD /* mkdir */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B7C14B648ED001B97AD /* mkfifo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B8014B648ED001B97AD /* Build configuration list for PBXNativeTarget "mkfifo" */;
+ buildPhases = (
+ FC8A8B7D14B648ED001B97AD /* Sources */,
+ FC8A8B7E14B648ED001B97AD /* Frameworks */,
+ FC8A8B7F14B648ED001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mkfifo;
+ productName = file_cmds;
+ productReference = FC8A8B8214B648ED001B97AD /* mkfifo */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B8414B648ED001B97AD /* mknod */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B8814B648ED001B97AD /* Build configuration list for PBXNativeTarget "mknod" */;
+ buildPhases = (
+ FC8A8B8514B648ED001B97AD /* Sources */,
+ FC8A8B8614B648ED001B97AD /* Frameworks */,
+ FC8A8B8714B648ED001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mknod;
+ productName = file_cmds;
+ productReference = FC8A8B8A14B648ED001B97AD /* mknod */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B8C14B648ED001B97AD /* mtree */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B9014B648ED001B97AD /* Build configuration list for PBXNativeTarget "mtree" */;
+ buildPhases = (
+ FC8A8B8D14B648ED001B97AD /* Sources */,
+ FC8A8B8E14B648ED001B97AD /* Frameworks */,
+ FC8A8B8F14B648ED001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mtree;
+ productName = file_cmds;
+ productReference = FC8A8B9214B648ED001B97AD /* mtree */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B9414B648EE001B97AD /* mv */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8B9814B648EE001B97AD /* Build configuration list for PBXNativeTarget "mv" */;
+ buildPhases = (
+ FC8A8B9514B648EE001B97AD /* Sources */,
+ FC8A8B9614B648EE001B97AD /* Frameworks */,
+ FC8A8B9714B648EE001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mv;
+ productName = file_cmds;
+ productReference = FC8A8B9A14B648EE001B97AD /* mv */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8B9C14B648EE001B97AD /* pathchk */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8BA014B648EE001B97AD /* Build configuration list for PBXNativeTarget "pathchk" */;
+ buildPhases = (
+ FC8A8B9D14B648EE001B97AD /* Sources */,
+ FC8A8B9E14B648EE001B97AD /* Frameworks */,
+ FC8A8B9F14B648EE001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pathchk;
+ productName = file_cmds;
+ productReference = FC8A8BA214B648EE001B97AD /* pathchk */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8BA414B648EE001B97AD /* pax */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8BA814B648EE001B97AD /* Build configuration list for PBXNativeTarget "pax" */;
+ buildPhases = (
+ FC8A8BA514B648EE001B97AD /* Sources */,
+ FC8A8BA614B648EE001B97AD /* Frameworks */,
+ FC8A8BA714B648EE001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pax;
+ productName = file_cmds;
+ productReference = FC8A8BAA14B648EE001B97AD /* pax */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8BAC14B648EF001B97AD /* rm */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8BB014B648EF001B97AD /* Build configuration list for PBXNativeTarget "rm" */;
+ buildPhases = (
+ FC8A8BAD14B648EF001B97AD /* Sources */,
+ FC8A8BAE14B648EF001B97AD /* Frameworks */,
+ FC8A8BAF14B648EF001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rm;
+ productName = file_cmds;
+ productReference = FC8A8BB214B648EF001B97AD /* rm */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8BB414B648EF001B97AD /* rmdir */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8BB814B648EF001B97AD /* Build configuration list for PBXNativeTarget "rmdir" */;
+ buildPhases = (
+ FC8A8BB514B648EF001B97AD /* Sources */,
+ FC8A8BB614B648EF001B97AD /* Frameworks */,
+ FC8A8BB714B648EF001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rmdir;
+ productName = file_cmds;
+ productReference = FC8A8BBA14B648EF001B97AD /* rmdir */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8BC414B648EF001B97AD /* stat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8BC814B648EF001B97AD /* Build configuration list for PBXNativeTarget "stat" */;
+ buildPhases = (
+ FC8A8BC514B648EF001B97AD /* Sources */,
+ FC8A8BC614B648EF001B97AD /* Frameworks */,
+ FC8A8BC714B648EF001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = stat;
+ productName = file_cmds;
+ productReference = FC8A8BCA14B648EF001B97AD /* stat */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC8A8BCC14B648F0001B97AD /* touch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC8A8BD014B648F0001B97AD /* Build configuration list for PBXNativeTarget "touch" */;
+ buildPhases = (
+ FC8A8BCD14B648F0001B97AD /* Sources */,
+ FC8A8BCE14B648F0001B97AD /* Frameworks */,
+ FC8A8BCF14B648F0001B97AD /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = touch;
+ productName = file_cmds;
+ productReference = FC8A8BD214B648F0001B97AD /* touch */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCB1BDB714B645D10070FACB /* chflags */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCB1BDC214B645D10070FACB /* Build configuration list for PBXNativeTarget "chflags" */;
+ buildPhases = (
+ FCB1BDB414B645D10070FACB /* Sources */,
+ FCB1BDB514B645D10070FACB /* Frameworks */,
+ 590112FE18284E58006881A1 /* ShellScript */,
+ FCB1BDB614B645D10070FACB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chflags;
+ productName = file_cmds;
+ productReference = FCB1BDB814B645D10070FACB /* chflags */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDAD94961808BB6D00B4D5A0 /* gzip */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDAD949D1808BB6D00B4D5A0 /* Build configuration list for PBXNativeTarget "gzip" */;
+ buildPhases = (
+ FDAD94931808BB6D00B4D5A0 /* Sources */,
+ FDAD94941808BB6D00B4D5A0 /* Frameworks */,
+ FDAD94951808BB6D00B4D5A0 /* Install Man Page */,
+ FDAD94A01808BBF100B4D5A0 /* Install Scripts */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = gzip;
+ productName = gzip;
+ productReference = FDAD94971808BB6D00B4D5A0 /* gzip */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FCB1BDAF14B645D00070FACB /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = "Apple Inc.";
+ TargetAttributes = {
+ 3E966CE71FB2211F0019F7A1 = {
+ CreatedOnToolsVersion = 9.2;
+ ProvisioningStyle = Automatic;
+ };
+ };
+ };
+ buildConfigurationList = FCB1BDB214B645D00070FACB /* Build configuration list for PBXProject "file_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ en,
+ );
+ mainGroup = FCB1BDAD14B645D00070FACB;
+ productRefGroup = FCB1BDB914B645D10070FACB /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FC8A8C8014B655ED001B97AD /* executables */,
+ FDFF0C501811BA2F00BFC477 /* eOS */,
+ FCB1BDB714B645D10070FACB /* chflags */,
+ FC8A8C5B14B652E1001B97AD /* chgrp */,
+ FC8A8B0B14B648D7001B97AD /* chmod */,
+ FC8A8B1414B648E0001B97AD /* chown */,
+ FC8A8B1C14B648E3001B97AD /* cksum */,
+ FC8A8B2414B648E5001B97AD /* compress */,
+ FC8A8B2C14B648E7001B97AD /* cp */,
+ FC8A8B3414B648EA001B97AD /* dd */,
+ FC8A8B3C14B648EA001B97AD /* df */,
+ FC8A8B4414B648EB001B97AD /* du */,
+ FDAD94961808BB6D00B4D5A0 /* gzip */,
+ FC8A8B4C14B648EB001B97AD /* install */,
+ FC8A8B5414B648EB001B97AD /* ipcrm */,
+ FC8A8B5C14B648EC001B97AD /* ipcs */,
+ FC8A8C7314B6554E001B97AD /* link */,
+ FC8A8B6414B648EC001B97AD /* ln */,
+ FC8A8B6C14B648ED001B97AD /* ls */,
+ FC8A8B7414B648ED001B97AD /* mkdir */,
+ FC8A8B7C14B648ED001B97AD /* mkfifo */,
+ FC8A8B8414B648ED001B97AD /* mknod */,
+ FC8A8B8C14B648ED001B97AD /* mtree */,
+ FC8A8B9414B648EE001B97AD /* mv */,
+ FC8A8B9C14B648EE001B97AD /* pathchk */,
+ FC8A8BA414B648EE001B97AD /* pax */,
+ FC8A8C4614B64DCD001B97AD /* readlink */,
+ FC8A8BAC14B648EF001B97AD /* rm */,
+ FC8A8BB414B648EF001B97AD /* rmdir */,
+ FC8A8C3C14B64A9D001B97AD /* shar */,
+ FC8A8BC414B648EF001B97AD /* stat */,
+ FC8A8C6714B6536D001B97AD /* sum */,
+ FC8A8BCC14B648F0001B97AD /* touch */,
+ FC8A8CC814B65F92001B97AD /* uncompress */,
+ FC8A8C5014B650CF001B97AD /* unlink */,
+ 3E966CE71FB2211F0019F7A1 /* tests */,
+ 729D07252347EC4D000716E5 /* macos_host_tools */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 590112FE18284E58006881A1 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = "/bin/sh -ex";
+ shellScript = "install -d -g ${GROUP} -o ${USER} -m 0755 ${INSTALL_DIR}\ninstall -d -g ${GROUP} -o ${USER} -m 0755 ${DSTROOT}/usr/share\ninstall -d -g ${GROUP} -o ${USER} -m 0755 ${DSTROOT}/usr/share/man\ninstall -d -g ${GROUP} -o ${USER} -m 0755 ${DSTROOT}/usr/share/man/man{1,7,8}";
+ showEnvVarsInLog = 0;
+ };
+ 72E62BA81A3A62960015FC8E /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". ${SRCROOT}/dd/install_symlink.sh";
+ showEnvVarsInLog = 0;
+ };
+ FC8A8C4C14B64DF9001B97AD /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/stat",
+ );
+ outputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/$(PRODUCT_NAME)",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/hardlink.sh";
+ showEnvVarsInLog = 0;
+ };
+ FC8A8C5514B650CF001B97AD /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/rm",
+ );
+ outputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/$(PRODUCT_NAME)",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/hardlink.sh";
+ showEnvVarsInLog = 0;
+ };
+ FC8A8C6014B652E1001B97AD /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/sbin/chown",
+ );
+ outputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/$(PRODUCT_NAME)",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/hardlink.sh";
+ showEnvVarsInLog = 0;
+ };
+ FC8A8C6C14B6536D001B97AD /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/cksum",
+ );
+ outputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/$(PRODUCT_NAME)",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/hardlink.sh";
+ showEnvVarsInLog = 0;
+ };
+ FC8A8C7814B6554E001B97AD /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/ln",
+ );
+ outputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/$(PRODUCT_NAME)",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/hardlink.sh";
+ showEnvVarsInLog = 0;
+ };
+ FC8A8CC714B65CEB001B97AD /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "install -d -o root -g wheel -m 0755 \"$DSTROOT\"/usr/bin\ninstall -c -o root -g wheel -m 0755 \"$PROJECT_DIR\"/shar/shar.sh \"$DSTROOT\"/usr/bin/shar";
+ showEnvVarsInLog = 0;
+ };
+ FC8A8CCD14B65F92001B97AD /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/compress",
+ );
+ outputPaths = (
+ "$(DSTROOT)/$(INSTALL_PATH)/$(PRODUCT_NAME)",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/hardlink.sh";
+ showEnvVarsInLog = 0;
+ };
+ FDAD94A01808BBF100B4D5A0 /* Install Scripts */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Install Scripts";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". ${SRCROOT}/gzip/install_scripts.sh";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FC8A8B0C14B648D7001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8BE614B6495B001B97AD /* chmod_acl.c in Sources */,
+ FC8A8BE514B64958001B97AD /* chmod.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B1514B648E0001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8BE814B64962001B97AD /* chown.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B1D14B648E3001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8BF014B6497D001B97AD /* sum2.c in Sources */,
+ FC8A8BEF14B6497A001B97AD /* sum1.c in Sources */,
+ FC8A8BEE14B64977001B97AD /* print.c in Sources */,
+ FC8A8BED14B64975001B97AD /* crc32.c in Sources */,
+ FC8A8BEC14B64972001B97AD /* crc.c in Sources */,
+ FC8A8BEB14B64970001B97AD /* cksum.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B2514B648E5001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8BF414B6498A001B97AD /* zopen.c in Sources */,
+ FC8A8BF314B64988001B97AD /* compress.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B2D14B648E7001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8BF614B64998001B97AD /* utils.c in Sources */,
+ FC8A8BF514B64995001B97AD /* cp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B3514B648EA001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8BFE14B649B1001B97AD /* position.c in Sources */,
+ FC8A8BFD14B649AE001B97AD /* misc.c in Sources */,
+ FC8A8BFC14B649AC001B97AD /* dd.c in Sources */,
+ FC8A8BFA14B649A7001B97AD /* conv_tab.c in Sources */,
+ FC8A8BF914B649A5001B97AD /* conv.c in Sources */,
+ FC8A8BF814B649A4001B97AD /* args.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B3D14B648EA001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C0114B649D1001B97AD /* df.c in Sources */,
+ FC8A8CC314B6598F001B97AD /* vfslist.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B4514B648EB001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C0214B649D4001B97AD /* du.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B4D14B648EB001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C0414B649DD001B97AD /* xinstall.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B5514B648EB001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C0714B649E3001B97AD /* ipcrm.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B5D14B648EC001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C0814B649E8001B97AD /* ipcs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B6514B648EC001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C0B14B649EF001B97AD /* ln.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B6D14B648ED001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C0D14B649F7001B97AD /* cmp.c in Sources */,
+ FC8A8C0E14B649F9001B97AD /* ls.c in Sources */,
+ FC8A8C0F14B649FC001B97AD /* print.c in Sources */,
+ FC8A8C1014B649FE001B97AD /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B7514B648ED001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C1114B64A04001B97AD /* mkdir.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B7D14B648ED001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C1414B64A0A001B97AD /* mkfifo.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B8514B648ED001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C1614B64A0F001B97AD /* mknod.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B8D14B648ED001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8CD114B66E10001B97AD /* crc.c in Sources */,
+ FC8A8C1714B64A14001B97AD /* commoncrypto.c in Sources */,
+ FC8A8C1814B64A17001B97AD /* compare.c in Sources */,
+ FC8A8C1914B64A1A001B97AD /* create.c in Sources */,
+ FC8A8C1A14B64A22001B97AD /* excludes.c in Sources */,
+ FC8A8C1B14B64A27001B97AD /* misc.c in Sources */,
+ 7D0A20EA2499364700F0F6D7 /* metrics.c in Sources */,
+ FC8A8C1C14B64A2D001B97AD /* mtree.c in Sources */,
+ FC8A8C1D14B64A31001B97AD /* spec.c in Sources */,
+ FC8A8C1E14B64A34001B97AD /* specspec.c in Sources */,
+ FC8A8C1F14B64A38001B97AD /* verify.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B9514B648EE001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C2214B64A4B001B97AD /* mv.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8B9D14B648EE001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C2414B64A53001B97AD /* pathchk.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BA514B648EE001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C2714B64A73001B97AD /* ar_io.c in Sources */,
+ FC8A8C2814B64A73001B97AD /* ar_subs.c in Sources */,
+ FC8A8C2914B64A73001B97AD /* buf_subs.c in Sources */,
+ FC8A8C2A14B64A73001B97AD /* cache.c in Sources */,
+ FC8A8C2B14B64A73001B97AD /* cpio.c in Sources */,
+ FC8A8C2C14B64A73001B97AD /* file_subs.c in Sources */,
+ FC8A8C2D14B64A73001B97AD /* ftree.c in Sources */,
+ FC8A8C2E14B64A73001B97AD /* gen_subs.c in Sources */,
+ FC8A8C2F14B64A73001B97AD /* getoldopt.c in Sources */,
+ FC8A8C3014B64A73001B97AD /* options.c in Sources */,
+ FC8A8C3114B64A73001B97AD /* pat_rep.c in Sources */,
+ FC8A8C3214B64A73001B97AD /* pax.c in Sources */,
+ FC8A8C3314B64A73001B97AD /* pax_format.c in Sources */,
+ FC8A8C3414B64A73001B97AD /* sel_subs.c in Sources */,
+ FC8A8C3514B64A73001B97AD /* tables.c in Sources */,
+ FC8A8C3614B64A73001B97AD /* tar.c in Sources */,
+ FC8A8C3714B64A73001B97AD /* tty_subs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BAD14B648EF001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C3914B64A7E001B97AD /* rm.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BB514B648EF001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C3B14B64A88001B97AD /* rmdir.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BC514B648EF001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C4214B64AC3001B97AD /* stat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC8A8BCD14B648F0001B97AD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8C4314B64AC7001B97AD /* touch.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCB1BDB414B645D10070FACB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC8A8A2814B6486E001B97AD /* chflags.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDAD94931808BB6D00B4D5A0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3E59B9311D4A767600D3128C /* futimens.c in Sources */,
+ FDAD949F1808BBB900B4D5A0 /* gzip.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 729D074E2347EC4D000716E5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B8C14B648ED001B97AD /* mtree */;
+ targetProxy = 729D074F2347EC4D000716E5 /* PBXContainerItemProxy */;
+ };
+ FC8A8C4A14B64DE1001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BC414B648EF001B97AD /* stat */;
+ targetProxy = FC8A8C4914B64DE1001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C5914B65238001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BAC14B648EF001B97AD /* rm */;
+ targetProxy = FC8A8C5814B65238001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C6414B652FA001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B1414B648E0001B97AD /* chown */;
+ targetProxy = FC8A8C6314B652FA001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C7014B6537C001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B1C14B648E3001B97AD /* cksum */;
+ targetProxy = FC8A8C6F14B6537C001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C7C14B65562001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B6414B648EC001B97AD /* ln */;
+ targetProxy = FC8A8C7B14B65562001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C8414B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCB1BDB714B645D10070FACB /* chflags */;
+ targetProxy = FC8A8C8314B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C8614B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C5B14B652E1001B97AD /* chgrp */;
+ targetProxy = FC8A8C8514B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C8814B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B0B14B648D7001B97AD /* chmod */;
+ targetProxy = FC8A8C8714B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C8A14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B1414B648E0001B97AD /* chown */;
+ targetProxy = FC8A8C8914B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C8C14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B1C14B648E3001B97AD /* cksum */;
+ targetProxy = FC8A8C8B14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C8E14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B2414B648E5001B97AD /* compress */;
+ targetProxy = FC8A8C8D14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C9014B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B2C14B648E7001B97AD /* cp */;
+ targetProxy = FC8A8C8F14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C9214B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B3414B648EA001B97AD /* dd */;
+ targetProxy = FC8A8C9114B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C9414B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B3C14B648EA001B97AD /* df */;
+ targetProxy = FC8A8C9314B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C9614B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B4414B648EB001B97AD /* du */;
+ targetProxy = FC8A8C9514B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C9814B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B4C14B648EB001B97AD /* install */;
+ targetProxy = FC8A8C9714B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C9A14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B5414B648EB001B97AD /* ipcrm */;
+ targetProxy = FC8A8C9914B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C9C14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B5C14B648EC001B97AD /* ipcs */;
+ targetProxy = FC8A8C9B14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8C9E14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C7314B6554E001B97AD /* link */;
+ targetProxy = FC8A8C9D14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CA014B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B6414B648EC001B97AD /* ln */;
+ targetProxy = FC8A8C9F14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CA214B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B6C14B648ED001B97AD /* ls */;
+ targetProxy = FC8A8CA114B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CA414B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B7414B648ED001B97AD /* mkdir */;
+ targetProxy = FC8A8CA314B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CA614B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B7C14B648ED001B97AD /* mkfifo */;
+ targetProxy = FC8A8CA514B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CA814B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B8414B648ED001B97AD /* mknod */;
+ targetProxy = FC8A8CA714B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CAA14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B8C14B648ED001B97AD /* mtree */;
+ targetProxy = FC8A8CA914B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CAC14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B9414B648EE001B97AD /* mv */;
+ targetProxy = FC8A8CAB14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CAE14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B9C14B648EE001B97AD /* pathchk */;
+ targetProxy = FC8A8CAD14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CB014B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BA414B648EE001B97AD /* pax */;
+ targetProxy = FC8A8CAF14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CB214B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C4614B64DCD001B97AD /* readlink */;
+ targetProxy = FC8A8CB114B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CB414B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BAC14B648EF001B97AD /* rm */;
+ targetProxy = FC8A8CB314B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CB614B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BB414B648EF001B97AD /* rmdir */;
+ targetProxy = FC8A8CB514B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CB814B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C3C14B64A9D001B97AD /* shar */;
+ targetProxy = FC8A8CB714B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CBA14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BC414B648EF001B97AD /* stat */;
+ targetProxy = FC8A8CB914B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CBC14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C6714B6536D001B97AD /* sum */;
+ targetProxy = FC8A8CBB14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CBE14B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BCC14B648F0001B97AD /* touch */;
+ targetProxy = FC8A8CBD14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CC014B655FD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C5014B650CF001B97AD /* unlink */;
+ targetProxy = FC8A8CBF14B655FD001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CC914B65F92001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BAC14B648EF001B97AD /* rm */;
+ targetProxy = FC8A8CCA14B65F92001B97AD /* PBXContainerItemProxy */;
+ };
+ FC8A8CD314B67BFD001B97AD /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8CC814B65F92001B97AD /* uncompress */;
+ targetProxy = FC8A8CD214B67BFD001B97AD /* PBXContainerItemProxy */;
+ };
+ FDAD94AA1808BDAA00B4D5A0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDAD94961808BB6D00B4D5A0 /* gzip */;
+ targetProxy = FDAD94A91808BDAA00B4D5A0 /* PBXContainerItemProxy */;
+ };
+ FDFF0C511811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCB1BDB714B645D10070FACB /* chflags */;
+ targetProxy = FDFF0C521811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C531811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C5B14B652E1001B97AD /* chgrp */;
+ targetProxy = FDFF0C541811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C551811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B0B14B648D7001B97AD /* chmod */;
+ targetProxy = FDFF0C561811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C571811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B1414B648E0001B97AD /* chown */;
+ targetProxy = FDFF0C581811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C591811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B1C14B648E3001B97AD /* cksum */;
+ targetProxy = FDFF0C5A1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C5B1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B2414B648E5001B97AD /* compress */;
+ targetProxy = FDFF0C5C1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C5D1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B2C14B648E7001B97AD /* cp */;
+ targetProxy = FDFF0C5E1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C5F1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B3414B648EA001B97AD /* dd */;
+ targetProxy = FDFF0C601811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C611811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B3C14B648EA001B97AD /* df */;
+ targetProxy = FDFF0C621811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C631811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B4414B648EB001B97AD /* du */;
+ targetProxy = FDFF0C641811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C671811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B4C14B648EB001B97AD /* install */;
+ targetProxy = FDFF0C681811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C691811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B5414B648EB001B97AD /* ipcrm */;
+ targetProxy = FDFF0C6A1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C6B1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B5C14B648EC001B97AD /* ipcs */;
+ targetProxy = FDFF0C6C1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C6D1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C7314B6554E001B97AD /* link */;
+ targetProxy = FDFF0C6E1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C6F1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B6414B648EC001B97AD /* ln */;
+ targetProxy = FDFF0C701811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C711811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B6C14B648ED001B97AD /* ls */;
+ targetProxy = FDFF0C721811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C731811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B7414B648ED001B97AD /* mkdir */;
+ targetProxy = FDFF0C741811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C751811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B7C14B648ED001B97AD /* mkfifo */;
+ targetProxy = FDFF0C761811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C771811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B8414B648ED001B97AD /* mknod */;
+ targetProxy = FDFF0C781811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C791811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B8C14B648ED001B97AD /* mtree */;
+ targetProxy = FDFF0C7A1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C7B1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B9414B648EE001B97AD /* mv */;
+ targetProxy = FDFF0C7C1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C7D1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8B9C14B648EE001B97AD /* pathchk */;
+ targetProxy = FDFF0C7E1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C7F1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BA414B648EE001B97AD /* pax */;
+ targetProxy = FDFF0C801811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C811811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C4614B64DCD001B97AD /* readlink */;
+ targetProxy = FDFF0C821811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C831811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BAC14B648EF001B97AD /* rm */;
+ targetProxy = FDFF0C841811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C851811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BB414B648EF001B97AD /* rmdir */;
+ targetProxy = FDFF0C861811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C871811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C3C14B64A9D001B97AD /* shar */;
+ targetProxy = FDFF0C881811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C891811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BC414B648EF001B97AD /* stat */;
+ targetProxy = FDFF0C8A1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C8B1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C6714B6536D001B97AD /* sum */;
+ targetProxy = FDFF0C8C1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C8D1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8BCC14B648F0001B97AD /* touch */;
+ targetProxy = FDFF0C8E1811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C8F1811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8CC814B65F92001B97AD /* uncompress */;
+ targetProxy = FDFF0C901811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+ FDFF0C911811BA2F00BFC477 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC8A8C5014B650CF001B97AD /* unlink */;
+ targetProxy = FDFF0C921811BA2F00BFC477 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 3E966CE81FB2211F0019F7A1 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 729D07692347EC4D000716E5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC8A8B1114B648D7001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8B1914B648E0001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ };
+ name = Release;
+ };
+ FC8A8B2114B648E3001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8B2914B648E5001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ };
+ name = Release;
+ };
+ FC8A8B3114B648E7001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8B3914B648EA001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = dd/dd.entitlements;
+ "CODE_SIGN_ENTITLEMENTS[sdk=macosx*]" = "";
+ CODE_SIGN_IDENTITY = "-";
+ INSTALL_PATH = /bin;
+ "INSTALL_PATH[sdk=appletvos]" = /usr/local/bin;
+ "INSTALL_PATH[sdk=iphoneos*]" = /usr/local/bin;
+ };
+ name = Release;
+ };
+ FC8A8B4114B648EA001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8B4914B648EB001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ };
+ name = Release;
+ };
+ FC8A8B5114B648EB001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ };
+ name = Release;
+ };
+ FC8A8B5914B648EB001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8B6114B648EC001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ OTHER_CFLAGS = (
+ "-iquote",
+ "$(SDKROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders",
+ "-iquote",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ );
+ WARNING_CFLAGS = "";
+ };
+ name = Release;
+ };
+ FC8A8B6914B648EC001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8B7114B648ED001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ _DARWIN_USE_64_BIT_INODE,
+ COLORLS,
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8B7914B648ED001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8B8114B648ED001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8B8914B648ED001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ };
+ name = Release;
+ };
+ FC8A8B9114B648ED001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ _DARWIN_USE_64_BIT_INODE,
+ ENABLE_MD5,
+ ENABLE_RMD160,
+ ENABLE_SHA1,
+ ENABLE_SHA256,
+ );
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
+ INSTALL_PATH = /usr/sbin;
+ "OTHER_LDFLAGS[sdk=macosx*]" = "-lCrashReporterClient";
+ };
+ name = Release;
+ };
+ FC8A8B9914B648EE001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8BA114B648EE001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8BA914B648EE001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8BB114B648EF001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8BB914B648EF001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8BC914B648EF001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "HAVE_CONFIG_H=0",
+ );
+ };
+ name = Release;
+ };
+ FC8A8BD114B648F0001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8C3E14B64A9D001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8C4814B64DCE001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8C5714B650CF001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8C6214B652E1001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8C6E14B6536D001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8C7A14B6554E001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ };
+ name = Release;
+ };
+ FC8A8C8214B655ED001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC8A8CCF14B65F92001B97AD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FCB1BDC114B645D10070FACB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ _DARWIN_USE_64_BIT_INODE,
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ VERSIONING_SYSTEM = "apple-generic";
+ WARNING_CFLAGS = (
+ "-Wall",
+ "-Werror",
+ "-Wundef",
+ );
+ };
+ name = Release;
+ };
+ FCB1BDC414B645D10070FACB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FDAD949E1808BB6D00B4D5A0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FDAD94851808BB3A00B4D5A0 /* gzip.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FDFF0C941811BA2F00BFC477 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 3E966CE91FB2211F0019F7A1 /* Build configuration list for PBXAggregateTarget "tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 3E966CE81FB2211F0019F7A1 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 729D07682347EC4D000716E5 /* Build configuration list for PBXAggregateTarget "macos_host_tools" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 729D07692347EC4D000716E5 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B1014B648D7001B97AD /* Build configuration list for PBXNativeTarget "chmod" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B1114B648D7001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B1814B648E0001B97AD /* Build configuration list for PBXNativeTarget "chown" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B1914B648E0001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B2014B648E3001B97AD /* Build configuration list for PBXNativeTarget "cksum" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B2114B648E3001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B2814B648E5001B97AD /* Build configuration list for PBXNativeTarget "compress" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B2914B648E5001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B3014B648E7001B97AD /* Build configuration list for PBXNativeTarget "cp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B3114B648E7001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B3814B648EA001B97AD /* Build configuration list for PBXNativeTarget "dd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B3914B648EA001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B4014B648EA001B97AD /* Build configuration list for PBXNativeTarget "df" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B4114B648EA001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B4814B648EB001B97AD /* Build configuration list for PBXNativeTarget "du" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B4914B648EB001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B5014B648EB001B97AD /* Build configuration list for PBXNativeTarget "install" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B5114B648EB001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B5814B648EB001B97AD /* Build configuration list for PBXNativeTarget "ipcrm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B5914B648EB001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B6014B648EC001B97AD /* Build configuration list for PBXNativeTarget "ipcs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B6114B648EC001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B6814B648EC001B97AD /* Build configuration list for PBXNativeTarget "ln" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B6914B648EC001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B7014B648ED001B97AD /* Build configuration list for PBXNativeTarget "ls" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B7114B648ED001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B7814B648ED001B97AD /* Build configuration list for PBXNativeTarget "mkdir" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B7914B648ED001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B8014B648ED001B97AD /* Build configuration list for PBXNativeTarget "mkfifo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B8114B648ED001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B8814B648ED001B97AD /* Build configuration list for PBXNativeTarget "mknod" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B8914B648ED001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B9014B648ED001B97AD /* Build configuration list for PBXNativeTarget "mtree" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B9114B648ED001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8B9814B648EE001B97AD /* Build configuration list for PBXNativeTarget "mv" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8B9914B648EE001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8BA014B648EE001B97AD /* Build configuration list for PBXNativeTarget "pathchk" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8BA114B648EE001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8BA814B648EE001B97AD /* Build configuration list for PBXNativeTarget "pax" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8BA914B648EE001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8BB014B648EF001B97AD /* Build configuration list for PBXNativeTarget "rm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8BB114B648EF001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8BB814B648EF001B97AD /* Build configuration list for PBXNativeTarget "rmdir" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8BB914B648EF001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8BC814B648EF001B97AD /* Build configuration list for PBXNativeTarget "stat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8BC914B648EF001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8BD014B648F0001B97AD /* Build configuration list for PBXNativeTarget "touch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8BD114B648F0001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8C3D14B64A9D001B97AD /* Build configuration list for PBXAggregateTarget "shar" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8C3E14B64A9D001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8C4714B64DCE001B97AD /* Build configuration list for PBXAggregateTarget "readlink" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8C4814B64DCE001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8C5614B650CF001B97AD /* Build configuration list for PBXAggregateTarget "unlink" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8C5714B650CF001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8C6114B652E1001B97AD /* Build configuration list for PBXAggregateTarget "chgrp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8C6214B652E1001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8C6D14B6536D001B97AD /* Build configuration list for PBXAggregateTarget "sum" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8C6E14B6536D001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8C7914B6554E001B97AD /* Build configuration list for PBXAggregateTarget "link" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8C7A14B6554E001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8C8114B655ED001B97AD /* Build configuration list for PBXAggregateTarget "executables" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8C8214B655ED001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC8A8CCE14B65F92001B97AD /* Build configuration list for PBXAggregateTarget "uncompress" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC8A8CCF14B65F92001B97AD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCB1BDB214B645D00070FACB /* Build configuration list for PBXProject "file_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCB1BDC114B645D10070FACB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCB1BDC214B645D10070FACB /* Build configuration list for PBXNativeTarget "chflags" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCB1BDC414B645D10070FACB /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDAD949D1808BB6D00B4D5A0 /* Build configuration list for PBXNativeTarget "gzip" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDAD949E1808BB6D00B4D5A0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDFF0C931811BA2F00BFC477 /* Build configuration list for PBXAggregateTarget "eOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDFF0C941811BA2F00BFC477 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FCB1BDAF14B645D00070FACB /* Project object */;
+}
diff --git a/file_cmds/gzip/futimens.c b/file_cmds/gzip/futimens.c
new file mode 100644
index 0000000..08345c3
--- /dev/null
+++ b/file_cmds/gzip/futimens.c
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2015 Jilles Tjoelker
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/time.h>
+
+#ifndef UTIME_NOW
+#define UTIME_NOW -1
+#endif
+
+#ifndef UTIME_OMIT
+#define UTIME_OMIT -2
+#endif
+int futimens(int fd, const struct timespec times[2]);
+
+int
+futimens(int fd, const struct timespec times[2])
+{
+ struct timeval now, tv[2], *tvp;
+ struct stat sb;
+
+ if (times == NULL || (times[0].tv_nsec == UTIME_NOW &&
+ times[1].tv_nsec == UTIME_NOW))
+ tvp = NULL;
+ else if (times[0].tv_nsec == UTIME_OMIT &&
+ times[1].tv_nsec == UTIME_OMIT)
+ return (0);
+ else {
+ if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) &&
+ times[0].tv_nsec != UTIME_NOW &&
+ times[0].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) &&
+ times[1].tv_nsec != UTIME_NOW &&
+ times[1].tv_nsec != UTIME_OMIT) {
+ errno = EINVAL;
+ return (-1);
+ }
+ tv[0].tv_sec = times[0].tv_sec;
+ tv[0].tv_usec = times[0].tv_nsec / 1000;
+ tv[1].tv_sec = times[1].tv_sec;
+ tv[1].tv_usec = times[1].tv_nsec / 1000;
+ tvp = tv;
+ if (times[0].tv_nsec == UTIME_OMIT ||
+ times[1].tv_nsec == UTIME_OMIT) {
+ if (fstat(fd, &sb) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_OMIT) {
+ tv[0].tv_sec = sb.st_atimespec.tv_sec;
+ tv[0].tv_usec = sb.st_atimespec.tv_nsec / 1000;
+ }
+ if (times[1].tv_nsec == UTIME_OMIT) {
+ tv[1].tv_sec = sb.st_mtimespec.tv_sec;
+ tv[1].tv_usec = sb.st_mtimespec.tv_nsec / 1000;
+ }
+ }
+ if (times[0].tv_nsec == UTIME_NOW ||
+ times[1].tv_nsec == UTIME_NOW) {
+ if (gettimeofday(&now, NULL) == -1)
+ return (-1);
+ if (times[0].tv_nsec == UTIME_NOW)
+ tv[0] = now;
+ if (times[1].tv_nsec == UTIME_NOW)
+ tv[1] = now;
+ }
+ }
+ return (futimes(fd, tvp));
+}
diff --git a/file_cmds/gzip/gzexe b/file_cmds/gzip/gzexe
new file mode 100644
index 0000000..5809133
--- /dev/null
+++ b/file_cmds/gzip/gzexe
@@ -0,0 +1,179 @@
+#!/bin/sh -
+#
+# $NetBSD: gzexe,v 1.3 2004/05/01 08:22:41 wiz Exp $
+# $OpenBSD: gzexe,v 1.3 2003/08/05 18:22:17 deraadt Exp $
+#
+#-
+# Copyright (c) 2003 Otto Moerbeek <otto@drijf.net>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# $FreeBSD: src/usr.bin/gzip/gzexe,v 1.1 2007/01/26 10:19:07 delphij Exp $
+
+# The number of lines plus one in the on-the-fly decompression script
+lines=19
+
+# A simple string to recognize already compressed files
+magic="# compressed by gzexe"
+
+# Write the decompression script to stdout
+header () {
+ # first section needs variable expansion, second not
+ cat <<- EOF
+ #!/bin/sh -
+ $magic
+ lines=$lines
+ EOF
+ cat <<- 'EOF'
+ prog=`/usr/bin/basename "$0"`
+ tmp=`/usr/bin/mktemp -d /tmp/gzexeXXXXXXXXXX` || {
+ /bin/echo "$prog: cannot create tmp dir"; exit 1
+ }
+ trap '/bin/rm -rf "$tmp"' 0
+ if /usr/bin/tail +$lines "$0" |
+ /usr/bin/gzip -dc > "$tmp/$prog" 2> /dev/null; then
+ /bin/chmod u+x "$tmp/$prog"
+ "$tmp/$prog" ${1+"$@"}
+ ret=$?
+ else
+ /bin/echo "$prog: cannot decompress $0"
+ ret=1
+ fi
+ exit $ret
+ EOF
+}
+
+# Test if a file is compressed by checking the magic line
+compressed () {
+ test "X`sed -n 2p "$1" 2> /dev/null`" = "X$magic"
+}
+
+# Decompress a file
+decompress () {
+ tmp=`mktemp /tmp/gzexeXXXXXXXXXX` || {
+ echo "$prog: cannot create tmp file"
+ return 1
+ }
+ if ! cp "$1" "$tmp"; then
+ echo "$prog: cannot copy $1 to $tmp"
+ rm -f "$tmp"
+ return 1
+ fi
+ if ! tail +$lines "$tmp" | gzip -vdc > "$1"; then
+ echo "$prog: cannot decompress $1"
+ cp "$tmp" "$1"
+ rm -f "$tmp"
+ return 1
+ fi
+}
+
+# Perform some sanity checks on the file
+check () {
+ if test ! -e "$1"; then
+ echo "$prog: cannot compress non-existing file $1"
+ return 1
+ fi
+
+ if test ! -f "$1"; then
+ echo "$prog: cannot compress non-regular file $1"
+ return 1
+ fi
+
+ case `basename "$1"` in
+ sh | mktemp | rm | echo | tail | gzip | chmod)
+ echo "$prog: cannot compress $1, I depend on it"
+ return 1
+ esac
+
+ if test ! -x "$1"; then
+ echo "$prog: cannot compress $1, it is not executable"
+ return 1
+ fi
+
+ if test -u "$1" -o -g "$1"; then
+ echo "$prog: cannot compress $1, it has an s bit set"
+ return 1
+ fi
+}
+
+# Compress a file
+compress () {
+ tmp=`mktemp /tmp/gzexeXXXXXXXXXX` || {
+ echo "$prog: cannot create tmp file"
+ return 1
+ }
+ if ! cp "$1" "$tmp"; then
+ echo "$prog: cannot copy $1 to $tmp"
+ rm -f "$tmp"
+ return 1
+ fi
+ if ! cp "$1" "$1"~; then
+ echo "$prog: cannot create backup copy $1~"
+ rm -f "$1"~ "$tmp"
+ return 1
+ fi
+
+ # Use cp to overwrite the existing file preserving mode and owner
+ # if possible. If the file is not writable, this will produce an
+ # error.
+
+ if header "$1" > "$tmp" && gzip -vc "$1" >> "$tmp"; then
+ if ! cp "$tmp" "$1"; then
+ echo "$prog: cannot copy $tmp to $1"
+ rm -f "$tmp"
+ return 1
+ fi
+ else
+ echo "$prog: cannot compress $1"
+ rm -f "$1"~ "$tmp"
+ return 1
+ fi
+}
+
+# Is the -d flag specified?
+dflag=
+
+# Return value
+rc=0
+
+if test "X$1" = X-d; then
+ dflag=1
+ shift
+fi
+
+prog=`basename "$0"`
+USAGE="usage: $prog [-d] file ..."
+if test $# -eq 0; then
+ echo $USAGE
+ exit 1
+fi
+
+while test $# -ne 0; do
+ if test $dflag; then
+ if ! compressed "$1"; then
+ echo "$prog: $1 is not compressed"
+ rc=1;
+ elif ! decompress "$1"; then
+ rc=$?
+ fi
+ else
+ if compressed "$1"; then
+ echo "$prog: $1 is already compressed"
+ rc=1;
+ elif ! check "$1" || ! compress "$1"; then
+ rc=$?
+ fi
+ fi
+ shift
+done
+exit $rc
diff --git a/file_cmds/gzip/gzexe.1 b/file_cmds/gzip/gzexe.1
new file mode 100644
index 0000000..0c514c4
--- /dev/null
+++ b/file_cmds/gzip/gzexe.1
@@ -0,0 +1,73 @@
+.\" $NetBSD: gzexe.1,v 1.3 2003/12/28 12:49:41 wiz Exp $
+.\" $OpenBSD: gzexe.1,v 1.1 2003/07/31 07:32:47 otto Exp $
+.\"
+.\" Copyright (c) 2003 Otto Moerbeek <otto@drijf.net>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD: src/usr.bin/gzip/gzexe.1,v 1.1 2007/01/26 10:19:07 delphij Exp $
+.Dd January 26, 2007
+.Dt GZEXE 1
+.Os
+.Sh NAME
+.Nm gzexe
+.Nd create auto-decompressing executables
+.Sh SYNOPSIS
+.Nm gzexe
+.Op Fl d
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility uses
+.Xr gzip 1
+to compress executables, producing executables that decompress on-the-fly
+when executed.
+This saves disk space, at the cost of slower execution times.
+The original executables are saved by copying each of them to a file with
+the same name with a
+.Sq ~
+suffix appended.
+After verifying that the compressed executables work as expected, the backup
+files can be removed.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d
+Decompress executables previously compressed by
+.Nm .
+.El
+.Pp
+The
+.Nm
+program refuses to compress non-regular or non-executable files,
+files with a setuid or setgid bit set, files that are already
+compressed using
+.Nm
+or programs it needs to perform on-the-fly decompression:
+.Xr sh 1 ,
+.Xr mktemp 1 ,
+.Xr rm 1 ,
+.Xr echo 1 ,
+.Xr tail 1 ,
+.Xr gzip 1 ,
+and
+.Xr chmod 1 .
+.Sh SEE ALSO
+.Xr gzip 1
+.Sh CAVEATS
+The
+.Nm
+utility replaces files by overwriting them with the generated
+compressed executable.
+To be able to do this, it is required that the original files are writable.
diff --git a/file_cmds/gzip/gzip.1 b/file_cmds/gzip/gzip.1
new file mode 100644
index 0000000..98e0ea2
--- /dev/null
+++ b/file_cmds/gzip/gzip.1
@@ -0,0 +1,234 @@
+.\" $NetBSD: gzip.1,v 1.26 2015/10/27 07:36:18 mrg Exp $
+.\"
+.\" Copyright (c) 1997, 2003, 2004 Matthew R. Green
+.\" 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 ``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.
+.\"
+.\" $FreeBSD: head/usr.bin/gzip/gzip.1 290073 2015-10-27 21:26:05Z delphij $
+.Dd October 26, 2015
+.Dt GZIP 1
+.Os
+.Sh NAME
+.Nm gzip
+.Nd compression/decompression tool using Lempel-Ziv coding (LZ77)
+.Sh SYNOPSIS
+.Nm
+.Op Fl cdfhkLlNnqrtVv
+.Op Fl S Ar suffix
+.Ar file
+.Oo
+.Ar file Oo ...
+.Oc
+.Oc
+.Nm gunzip
+.Op Fl cfhkLNqrtVv
+.Op Fl S Ar suffix
+.Ar file
+.Oo
+.Ar file Oo ...
+.Oc
+.Oc
+.Nm zcat
+.Op Fl fhV
+.Ar file
+.Oo
+.Ar file Oo ...
+.Oc
+.Oc
+.Sh DESCRIPTION
+The
+.Nm
+program compresses and decompresses files using Lempel-Ziv coding
+(LZ77).
+If no
+.Ar files
+are specified,
+.Nm
+will compress from standard input, or decompress to standard output.
+When in compression mode, each
+.Ar file
+will be replaced with another file with the suffix, set by the
+.Fl S Ar suffix
+option, added, if possible.
+.Pp
+In decompression mode, each
+.Ar file
+will be checked for existence, as will the file with the suffix
+added.
+Each
+.Ar file
+argument must contain a separate complete archive;
+when multiple
+.Ar files
+are indicated, each is decompressed in turn.
+.Pp
+In the case of
+.Nm gzcat
+the resulting data is then concatenated in the manner of
+.Xr cat 1 .
+.Pp
+If invoked as
+.Nm gunzip
+then the
+.Fl d
+option is enabled.
+If invoked as
+.Nm zcat
+or
+.Nm gzcat
+then both the
+.Fl c
+and
+.Fl d
+options are enabled.
+.Pp
+This version of
+.Nm
+is also capable of decompressing files compressed using
+.Xr compress 1 ,
+.Xr bzip2 1 ,
+or
+.Xr xz 1 .
+.Sh OPTIONS
+The following options are available:
+.Bl -tag -width XXrXXXrecursiveX
+.It Fl 1 , -fast
+.It Fl 2 , 3 , 4 , 5 , 6 , 7 , 8
+.It Fl 9 , -best
+These options change the compression level used, with the
+.Fl 1
+option being the fastest, with less compression, and the
+.Fl 9
+option being the slowest, with optimal compression.
+The default compression level is 6.
+.It Fl c , -stdout , -to-stdout
+This option specifies that output will go to the standard output
+stream, leaving files intact.
+.It Fl d , -decompress , -uncompress
+This option selects decompression rather than compression.
+.It Fl f , -force
+This option turns on force mode.
+This allows files with multiple links, symbolic links to regular files,
+overwriting of pre-existing files, reading from or writing to a terminal,
+and when combined with the
+.Fl c
+option, allowing non-compressed data to pass through unchanged.
+.It Fl h , -help
+This option prints a usage summary and exits.
+.It Fl k , -keep
+Keep (do not delete) input files during compression
+or decompression.
+.It Fl L , -license
+This option prints
+.Nm
+license.
+.It Fl l , -list
+This option displays information about the file's compressed and
+uncompressed size, ratio, uncompressed name.
+With the
+.Fl v
+option, it also displays the compression method, CRC, date and time
+embedded in the file.
+.It Fl N , -name
+This option causes the stored filename in the input file to be used
+as the output file.
+.It Fl n , -no-name
+This option stops the filename and timestamp from being stored in
+the output file.
+.It Fl q , -quiet
+With this option, no warnings or errors are printed.
+.It Fl r , -recursive
+This option is used to
+.Nm
+the files in a directory tree individually, using the
+.Xr fts 3
+library.
+.It Fl S Ar suffix , Fl -suffix Ar suffix
+This option changes the default suffix from .gz to
+.Ar suffix .
+.It Fl t , -test
+This option will test compressed files for integrity.
+.It Fl V , -version
+This option prints the version of the
+.Nm
+program.
+.It Fl v , -verbose
+This option turns on verbose mode, which prints the compression
+ratio for each file compressed.
+.El
+.Sh ENVIRONMENT
+If the environment variable
+.Ev GZIP
+is set, it is parsed as a white-space separated list of options
+handled before any options on the command line.
+Options on the command line will override anything in
+.Ev GZIP .
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 on success,
+1 on errors,
+and 2 if a warning occurs.
+.Sh SEE ALSO
+.Xr bzip2 1 ,
+.Xr compress 1 ,
+.Xr xz 1 ,
+.Xr fts 3 ,
+.Xr zlib 3
+.Sh HISTORY
+The
+.Nm
+program was originally written by Jean-loup Gailly, licensed under
+the GNU Public Licence.
+Matthew R. Green wrote a simple front end for
+.Nx 1.3
+distribution media, based on the freely re-distributable zlib library.
+It was enhanced to be mostly feature-compatible with the original
+GNU
+.Nm
+program for
+.Nx 2.0 .
+.Pp
+This implementation of
+.Nm
+was ported based on the
+.Nx
+.Nm ,
+and first appeared in
+.Fx 7.0 .
+.Sh AUTHORS
+.An -nosplit
+This implementation of
+.Nm
+was written by
+.An Matthew R. Green Aq Mt mrg@eterna.com.au
+with unpack support written by
+.An Xin LI Aq Mt delphij@FreeBSD.org .
+.Sh BUGS
+According to RFC 1952, the recorded file size is stored in a 32-bit
+integer, therefore, it cannot represent files larger than 4GB.
+This limitation also applies to
+.Fl l
+option of
+.Nm
+utility.
diff --git a/file_cmds/gzip/gzip.c b/file_cmds/gzip/gzip.c
new file mode 100644
index 0000000..3d27266
--- /dev/null
+++ b/file_cmds/gzip/gzip.c
@@ -0,0 +1,2256 @@
+/* $NetBSD: gzip.c,v 1.109 2015/10/27 07:36:18 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green
+ * 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 ``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/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1997, 1998, 2003, 2004, 2006\
+ Matthew R. Green. All rights reserved.");
+__FBSDID("$FreeBSD: head/usr.bin/gzip/gzip.c 290073 2015-10-27 21:26:05Z delphij $");
+#endif /* not lint */
+
+/*
+ * gzip.c -- GPL free gzip using zlib.
+ *
+ * RFC 1950 covers the zlib format
+ * RFC 1951 covers the deflate format
+ * RFC 1952 covers the gzip format
+ *
+ * TODO:
+ * - use mmap where possible
+ * - make bzip2/compress -v/-t/-l support work as well as possible
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <inttypes.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <zlib.h>
+#include <fts.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <time.h>
+
+#ifdef __APPLE__
+#include <sys/attr.h>
+#include <copyfile.h>
+#include <get_compat.h>
+int futimens(int fd, const struct timespec times[2]);
+#endif /* __APPLE__ */
+
+/* what type of file are we dealing with */
+enum filetype {
+ FT_GZIP,
+#ifndef NO_BZIP2_SUPPORT
+ FT_BZIP2,
+#endif
+#ifndef NO_COMPRESS_SUPPORT
+ FT_Z,
+#endif
+#ifndef NO_PACK_SUPPORT
+ FT_PACK,
+#endif
+#ifndef NO_XZ_SUPPORT
+ FT_XZ,
+#endif
+ FT_LAST,
+ FT_UNKNOWN
+};
+
+#ifndef NO_BZIP2_SUPPORT
+#include <bzlib.h>
+
+#define BZ2_SUFFIX ".bz2"
+#define BZIP2_MAGIC "\102\132\150"
+#endif
+
+#ifndef NO_COMPRESS_SUPPORT
+#define Z_SUFFIX ".Z"
+#define Z_MAGIC "\037\235"
+#endif
+
+#ifndef NO_PACK_SUPPORT
+#define PACK_MAGIC "\037\036"
+#endif
+
+#ifndef NO_XZ_SUPPORT
+#include <lzma.h>
+#define XZ_SUFFIX ".xz"
+#define XZ_MAGIC "\3757zXZ"
+#endif
+
+#define GZ_SUFFIX ".gz"
+
+#define BUFLEN (64 * 1024)
+
+#define GZIP_MAGIC0 0x1F
+#define GZIP_MAGIC1 0x8B
+#define GZIP_OMAGIC1 0x9E
+
+#define GZIP_TIMESTAMP (off_t)4
+#define GZIP_ORIGNAME (off_t)10
+
+#define HEAD_CRC 0x02
+#define EXTRA_FIELD 0x04
+#define ORIG_NAME 0x08
+#define COMMENT 0x10
+
+#define OS_CODE 3 /* Unix */
+
+typedef struct {
+ const char *zipped;
+ int ziplen;
+ const char *normal; /* for unzip - must not be longer than zipped */
+} suffixes_t;
+static suffixes_t suffixes[] = {
+#define SUFFIX(Z, N) {Z, sizeof Z - 1, N}
+ SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S .xxx */
+#ifndef SMALL
+ SUFFIX(GZ_SUFFIX, ""),
+ SUFFIX(".z", ""),
+ SUFFIX("-gz", ""),
+ SUFFIX("-z", ""),
+ SUFFIX("_z", ""),
+ SUFFIX(".taz", ".tar"),
+ SUFFIX(".tgz", ".tar"),
+#ifndef NO_BZIP2_SUPPORT
+ SUFFIX(BZ2_SUFFIX, ""),
+ SUFFIX(".tbz", ".tar"),
+ SUFFIX(".tbz2", ".tar"),
+#endif
+#ifndef NO_COMPRESS_SUPPORT
+ SUFFIX(Z_SUFFIX, ""),
+#endif
+#ifndef NO_XZ_SUPPORT
+ SUFFIX(XZ_SUFFIX, ""),
+#endif
+ SUFFIX(GZ_SUFFIX, ""), /* Overwritten by -S "" */
+#endif /* SMALL */
+#undef SUFFIX
+};
+#define NUM_SUFFIXES (sizeof suffixes / sizeof suffixes[0])
+#define SUFFIX_MAXLEN 30
+
+#ifdef __APPLE__
+static const char gzip_version[] = "Apple gzip " GZIP_APPLE_VERSION;
+#else
+static const char gzip_version[] = "FreeBSD gzip 20150413";
+#endif
+
+#ifndef SMALL
+static const char gzip_copyright[] = \
+" Copyright (c) 1997, 1998, 2003, 2004, 2006 Matthew R. Green\n"
+" All rights reserved.\n"
+"\n"
+" Redistribution and use in source and binary forms, with or without\n"
+" modification, are permitted provided that the following conditions\n"
+" are met:\n"
+" 1. Redistributions of source code must retain the above copyright\n"
+" notice, this list of conditions and the following disclaimer.\n"
+" 2. Redistributions in binary form must reproduce the above copyright\n"
+" notice, this list of conditions and the following disclaimer in the\n"
+" documentation and/or other materials provided with the distribution.\n"
+"\n"
+" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
+" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"
+" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"
+" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n"
+" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n"
+" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"
+" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED\n"
+" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n"
+" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n"
+" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n"
+" SUCH DAMAGE.";
+#endif
+
+static int cflag; /* stdout mode */
+static int dflag; /* decompress mode */
+static int lflag; /* list mode */
+static int numflag = 6; /* gzip -1..-9 value */
+
+#ifndef SMALL
+static int fflag; /* force mode */
+static int kflag; /* don't delete input files */
+static int nflag; /* don't save name/timestamp */
+static int Nflag; /* don't restore name/timestamp */
+static int qflag; /* quiet mode */
+static int rflag; /* recursive mode */
+static int tflag; /* test */
+static int vflag; /* verbose mode */
+static const char *remove_file = NULL; /* file to be removed upon SIGINT */
+#else
+#define qflag 0
+#define tflag 0
+#endif
+
+static int exit_value = 0; /* exit value */
+
+static char *infile; /* name of file coming in */
+
+#ifdef __APPLE__
+static bool zcat;
+#endif
+
+static void maybe_err(const char *fmt, ...) __printflike(1, 2) __dead2;
+#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \
+ !defined(NO_XZ_SUPPORT)
+static void maybe_errx(const char *fmt, ...) __printflike(1, 2) __dead2;
+#endif
+static void maybe_warn(const char *fmt, ...) __printflike(1, 2);
+static void maybe_warnx(const char *fmt, ...) __printflike(1, 2);
+static enum filetype file_gettype(u_char *);
+#ifdef SMALL
+#define gz_compress(if, of, sz, fn, tm) gz_compress(if, of, sz)
+#endif
+static off_t gz_compress(int, int, off_t *, const char *, uint32_t);
+static off_t gz_uncompress(int, int, char *, size_t, off_t *, const char *);
+static off_t file_compress(char *, char *, size_t);
+static off_t file_uncompress(char *, char *, size_t);
+static void handle_pathname(char *);
+static void handle_file(char *, struct stat *);
+static void handle_stdin(void);
+static void handle_stdout(void);
+static void print_ratio(off_t, off_t, FILE *);
+static void print_list(int fd, off_t, const char *, time_t);
+static void usage(void) __dead2;
+static void display_version(void) __dead2;
+#ifndef SMALL
+static void display_license(void);
+static void sigint_handler(int);
+#endif
+static const suffixes_t *check_suffix(char *, int);
+static ssize_t read_retry(int, void *, size_t);
+
+#ifdef SMALL
+#define unlink_input(f, sb) unlink(f)
+#else
+static off_t cat_fd(unsigned char *, size_t, off_t *, int fd);
+static void prepend_gzip(char *, int *, char ***);
+static void handle_dir(char *);
+static void print_verbage(const char *, const char *, off_t, off_t);
+static void print_test(const char *, int);
+static void copymodes(int fd, const struct stat *, const char *file);
+static int check_outfile(const char *outfile);
+#endif
+
+#ifndef NO_BZIP2_SUPPORT
+static off_t unbzip2(int, int, char *, size_t, off_t *);
+#endif
+
+#ifndef NO_COMPRESS_SUPPORT
+static FILE *zdopen(int);
+static off_t zuncompress(FILE *, FILE *, char *, size_t, off_t *);
+#endif
+
+#ifndef NO_PACK_SUPPORT
+static off_t unpack(int, int, char *, size_t, off_t *);
+#endif
+
+#ifndef NO_XZ_SUPPORT
+static off_t unxz(int, int, char *, size_t, off_t *);
+#endif
+
+#ifdef SMALL
+#define getopt_long(a,b,c,d,e) getopt(a,b,c)
+#else
+static const struct option longopts[] = {
+ { "stdout", no_argument, 0, 'c' },
+ { "to-stdout", no_argument, 0, 'c' },
+ { "decompress", no_argument, 0, 'd' },
+ { "uncompress", no_argument, 0, 'd' },
+ { "force", no_argument, 0, 'f' },
+ { "help", no_argument, 0, 'h' },
+ { "keep", no_argument, 0, 'k' },
+ { "list", no_argument, 0, 'l' },
+ { "no-name", no_argument, 0, 'n' },
+ { "name", no_argument, 0, 'N' },
+ { "quiet", no_argument, 0, 'q' },
+ { "recursive", no_argument, 0, 'r' },
+ { "suffix", required_argument, 0, 'S' },
+ { "test", no_argument, 0, 't' },
+ { "verbose", no_argument, 0, 'v' },
+ { "version", no_argument, 0, 'V' },
+ { "fast", no_argument, 0, '1' },
+ { "best", no_argument, 0, '9' },
+ { "ascii", no_argument, 0, 'a' },
+ { "license", no_argument, 0, 'L' },
+ { NULL, no_argument, 0, 0 },
+};
+#endif
+
+int
+main(int argc, char **argv)
+{
+ const char *progname = getprogname();
+#ifndef SMALL
+ char *gzip;
+ int len;
+#endif
+ int ch;
+
+#ifndef SMALL
+ if ((gzip = getenv("GZIP")) != NULL)
+ prepend_gzip(gzip, &argc, &argv);
+ signal(SIGINT, sigint_handler);
+#endif
+
+ /*
+ * XXX
+ * handle being called `gunzip', `zcat' and `gzcat'
+ */
+ if (strcmp(progname, "gunzip") == 0)
+ dflag = 1;
+ else if (strcmp(progname, "zcat") == 0 ||
+ strcmp(progname, "gzcat") == 0)
+ dflag = cflag = 1;
+
+#ifdef __APPLE__
+ if (strcmp(progname, "zcat") == 0) {
+ zcat = true;
+ }
+#endif
+
+#ifdef SMALL
+#define OPT_LIST "123456789cdhlV"
+#else
+#define OPT_LIST "123456789acdfhklLNnqrS:tVv"
+#endif
+
+ while ((ch = getopt_long(argc, argv, OPT_LIST, longopts, NULL)) != -1) {
+ switch (ch) {
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ numflag = ch - '0';
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ dflag = 1;
+ break;
+ case 'V':
+ display_version();
+ /* NOTREACHED */
+#ifndef SMALL
+ case 'a':
+ fprintf(stderr, "%s: option --ascii ignored on this system\n", progname);
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'k':
+ kflag = 1;
+ break;
+ case 'L':
+ display_license();
+ /* NOT REACHED */
+ case 'N':
+ nflag = 0;
+ Nflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ Nflag = 0;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 'S':
+ len = strlen(optarg);
+ if (len != 0) {
+ if (len > SUFFIX_MAXLEN)
+ errx(1, "incorrect suffix: '%s': too long", optarg);
+ suffixes[0].zipped = optarg;
+ suffixes[0].ziplen = len;
+ } else {
+ suffixes[NUM_SUFFIXES - 1].zipped = "";
+ suffixes[NUM_SUFFIXES - 1].ziplen = 0;
+ }
+ break;
+ case 't':
+ cflag = 1;
+ tflag = 1;
+ dflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+#endif
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (argc == 0) {
+ if (dflag) /* stdin mode */
+ handle_stdin();
+ else /* stdout mode */
+ handle_stdout();
+ } else {
+ do {
+ handle_pathname(argv[0]);
+ } while (*++argv);
+ }
+#ifndef SMALL
+ if (qflag == 0 && lflag && argc > 1)
+ print_list(-1, 0, "(totals)", 0);
+#endif
+ exit(exit_value);
+}
+
+/* maybe print a warning */
+void
+maybe_warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (qflag == 0) {
+ va_start(ap, fmt);
+ vwarn(fmt, ap);
+ va_end(ap);
+ }
+ if (exit_value == 0)
+ exit_value = 1;
+}
+
+/* ... without an errno. */
+void
+maybe_warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (qflag == 0) {
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+ }
+ if (exit_value == 0)
+ exit_value = 1;
+}
+
+/* maybe print an error */
+void
+maybe_err(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (qflag == 0) {
+ va_start(ap, fmt);
+ vwarn(fmt, ap);
+ va_end(ap);
+ }
+ exit(2);
+}
+
+#if !defined(NO_BZIP2_SUPPORT) || !defined(NO_PACK_SUPPORT) || \
+ !defined(NO_XZ_SUPPORT)
+/* ... without an errno. */
+void
+maybe_errx(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (qflag == 0) {
+ va_start(ap, fmt);
+ vwarnx(fmt, ap);
+ va_end(ap);
+ }
+ exit(2);
+}
+#endif
+
+#ifndef SMALL
+/* split up $GZIP and prepend it to the argument list */
+static void
+prepend_gzip(char *gzip, int *argc, char ***argv)
+{
+ char *s, **nargv, **ac;
+ int nenvarg = 0, i;
+
+ /* scan how many arguments there are */
+ for (s = gzip;;) {
+ while (*s == ' ' || *s == '\t')
+ s++;
+ if (*s == 0)
+ goto count_done;
+ nenvarg++;
+ while (*s != ' ' && *s != '\t')
+ if (*s++ == 0)
+ goto count_done;
+ }
+count_done:
+ /* punt early */
+ if (nenvarg == 0)
+ return;
+
+ *argc += nenvarg;
+ ac = *argv;
+
+ nargv = (char **)malloc((*argc + 1) * sizeof(char *));
+ if (nargv == NULL)
+ maybe_err("malloc");
+
+ /* stash this away */
+ *argv = nargv;
+
+ /* copy the program name first */
+ i = 0;
+ nargv[i++] = *(ac++);
+
+ s = gzip;
+ for (;;) {
+ /* Skip whitespaces. */
+ while (*s == ' ' || *s == '\t')
+ s++;
+ if (*s == 0) {
+ goto copy_done;
+ }
+ nargv[i++] = s;
+ /* Find the end of this argument. */
+ while (*s != ' ' && *s != '\t')
+ if (*s++ == 0)
+ /* Argument followed by NUL. */
+ goto copy_done;
+ /* copy any unterminated args */
+ nargv[i-1] = strndup(nargv[i-1], s-nargv[i-1]);
+ if (nargv[i-1] == NULL)
+ maybe_err("strndup");
+ s++;
+ }
+copy_done:
+
+ /* copy the original arguments and a NULL */
+ while (*ac)
+ nargv[i++] = *(ac++);
+ nargv[i] = NULL;
+}
+#endif
+
+/* compress input to output. Return bytes read, -1 on error */
+static off_t
+gz_compress(int in, int out, off_t *gsizep, const char *origname, uint32_t mtime)
+{
+ z_stream z;
+ char *outbufp, *inbufp;
+ off_t in_tot = 0, out_tot = 0;
+ ssize_t in_size;
+ int i, error;
+ uLong crc;
+#ifdef SMALL
+ static char header[] = { GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED, 0,
+ 0, 0, 0, 0,
+ 0, OS_CODE };
+#endif
+
+ outbufp = malloc(BUFLEN);
+ inbufp = malloc(BUFLEN);
+ if (outbufp == NULL || inbufp == NULL) {
+ maybe_err("malloc failed");
+ goto out;
+ }
+
+ memset(&z, 0, sizeof z);
+ z.zalloc = Z_NULL;
+ z.zfree = Z_NULL;
+ z.opaque = 0;
+
+#ifdef SMALL
+ memcpy(outbufp, header, sizeof header);
+ i = sizeof header;
+#else
+ if (nflag != 0) {
+ mtime = 0;
+ origname = "";
+ }
+
+ i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c%c%c%s",
+ GZIP_MAGIC0, GZIP_MAGIC1, Z_DEFLATED,
+ *origname ? ORIG_NAME : 0,
+ mtime & 0xff,
+ (mtime >> 8) & 0xff,
+ (mtime >> 16) & 0xff,
+ (mtime >> 24) & 0xff,
+ numflag == 1 ? 4 : numflag == 9 ? 2 : 0,
+ OS_CODE, origname);
+ if (i >= BUFLEN)
+ /* this need PATH_MAX > BUFLEN ... */
+ maybe_err("snprintf");
+ if (*origname)
+ i++;
+#endif
+
+ z.next_out = (unsigned char *)outbufp + i;
+ z.avail_out = BUFLEN - i;
+
+ error = deflateInit2(&z, numflag, Z_DEFLATED,
+ (-MAX_WBITS), 8, Z_DEFAULT_STRATEGY);
+ if (error != Z_OK) {
+ maybe_warnx("deflateInit2 failed");
+ in_tot = -1;
+ goto out;
+ }
+
+ crc = crc32(0L, Z_NULL, 0);
+ for (;;) {
+ if (z.avail_out == 0) {
+ if (write(out, outbufp, BUFLEN) != BUFLEN) {
+ maybe_warn("write");
+ out_tot = -1;
+ goto out;
+ }
+
+ out_tot += BUFLEN;
+ z.next_out = (unsigned char *)outbufp;
+ z.avail_out = BUFLEN;
+ }
+
+ if (z.avail_in == 0) {
+ in_size = read(in, inbufp, BUFLEN);
+ if (in_size < 0) {
+ maybe_warn("read");
+ in_tot = -1;
+ goto out;
+ }
+ if (in_size == 0)
+ break;
+
+ crc = crc32(crc, (const Bytef *)inbufp, (unsigned)in_size);
+ in_tot += in_size;
+ z.next_in = (unsigned char *)inbufp;
+ z.avail_in = in_size;
+ }
+
+ error = deflate(&z, Z_NO_FLUSH);
+ if (error != Z_OK && error != Z_STREAM_END) {
+ maybe_warnx("deflate failed");
+ in_tot = -1;
+ goto out;
+ }
+ }
+
+ /* clean up */
+ for (;;) {
+ size_t len;
+ ssize_t w;
+
+ error = deflate(&z, Z_FINISH);
+ if (error != Z_OK && error != Z_STREAM_END) {
+ maybe_warnx("deflate failed");
+ in_tot = -1;
+ goto out;
+ }
+
+ len = (char *)z.next_out - outbufp;
+
+ w = write(out, outbufp, len);
+ if (w == -1 || (size_t)w != len) {
+ maybe_warn("write");
+ out_tot = -1;
+ goto out;
+ }
+ out_tot += len;
+ z.next_out = (unsigned char *)outbufp;
+ z.avail_out = BUFLEN;
+
+ if (error == Z_STREAM_END)
+ break;
+ }
+
+ if (deflateEnd(&z) != Z_OK) {
+ maybe_warnx("deflateEnd failed");
+ in_tot = -1;
+ goto out;
+ }
+
+ i = snprintf(outbufp, BUFLEN, "%c%c%c%c%c%c%c%c",
+ (int)crc & 0xff,
+ (int)(crc >> 8) & 0xff,
+ (int)(crc >> 16) & 0xff,
+ (int)(crc >> 24) & 0xff,
+ (int)in_tot & 0xff,
+ (int)(in_tot >> 8) & 0xff,
+ (int)(in_tot >> 16) & 0xff,
+ (int)(in_tot >> 24) & 0xff);
+ if (i != 8)
+ maybe_err("snprintf");
+ if (write(out, outbufp, i) != i) {
+ maybe_warn("write");
+ in_tot = -1;
+ } else
+ out_tot += i;
+
+out:
+ if (inbufp != NULL)
+ free(inbufp);
+ if (outbufp != NULL)
+ free(outbufp);
+ if (gsizep)
+ *gsizep = out_tot;
+ return in_tot;
+}
+
+/*
+ * uncompress input to output then close the input. return the
+ * uncompressed size written, and put the compressed sized read
+ * into `*gsizep'.
+ */
+static off_t
+gz_uncompress(int in, int out, char *pre, size_t prelen, off_t *gsizep,
+ const char *filename)
+{
+ z_stream z;
+ char *outbufp, *inbufp;
+ off_t out_tot = -1, in_tot = 0;
+ uint32_t out_sub_tot = 0;
+ enum {
+ GZSTATE_MAGIC0,
+ GZSTATE_MAGIC1,
+ GZSTATE_METHOD,
+ GZSTATE_FLAGS,
+ GZSTATE_SKIPPING,
+ GZSTATE_EXTRA,
+ GZSTATE_EXTRA2,
+ GZSTATE_EXTRA3,
+ GZSTATE_ORIGNAME,
+ GZSTATE_COMMENT,
+ GZSTATE_HEAD_CRC1,
+ GZSTATE_HEAD_CRC2,
+ GZSTATE_INIT,
+ GZSTATE_READ,
+ GZSTATE_CRC,
+ GZSTATE_LEN,
+ } state = GZSTATE_MAGIC0;
+ int flags = 0, skip_count = 0;
+ int error = Z_STREAM_ERROR, done_reading = 0;
+ uLong crc = 0;
+ ssize_t wr;
+ int needmore = 0;
+
+#define ADVANCE() { z.next_in++; z.avail_in--; }
+
+ if ((outbufp = malloc(BUFLEN)) == NULL) {
+ maybe_err("malloc failed");
+ goto out2;
+ }
+ if ((inbufp = malloc(BUFLEN)) == NULL) {
+ maybe_err("malloc failed");
+ goto out1;
+ }
+
+ memset(&z, 0, sizeof z);
+ z.avail_in = prelen;
+ z.next_in = (unsigned char *)pre;
+ z.avail_out = BUFLEN;
+ z.next_out = (unsigned char *)outbufp;
+ z.zalloc = NULL;
+ z.zfree = NULL;
+ z.opaque = 0;
+
+ in_tot = prelen;
+ out_tot = 0;
+
+ for (;;) {
+ if ((z.avail_in == 0 || needmore) && done_reading == 0) {
+ ssize_t in_size;
+
+ if (z.avail_in > 0) {
+ memmove(inbufp, z.next_in, z.avail_in);
+ }
+ z.next_in = (unsigned char *)inbufp;
+ in_size = read(in, z.next_in + z.avail_in,
+ BUFLEN - z.avail_in);
+
+ if (in_size == -1) {
+ maybe_warn("failed to read stdin");
+ goto stop_and_fail;
+ } else if (in_size == 0) {
+ done_reading = 1;
+ }
+
+ z.avail_in += in_size;
+ needmore = 0;
+
+ in_tot += in_size;
+ }
+ if (z.avail_in == 0) {
+ if (done_reading && state != GZSTATE_MAGIC0) {
+ maybe_warnx("%s: unexpected end of file",
+ filename);
+ goto stop_and_fail;
+ }
+ goto stop;
+ }
+ switch (state) {
+ case GZSTATE_MAGIC0:
+ if (*z.next_in != GZIP_MAGIC0) {
+ if (in_tot > 0) {
+ maybe_warnx("%s: trailing garbage "
+ "ignored", filename);
+ exit_value = 2;
+ goto stop;
+ }
+ maybe_warnx("input not gziped (MAGIC0)");
+ goto stop_and_fail;
+ }
+ ADVANCE();
+ state++;
+ out_sub_tot = 0;
+ crc = crc32(0L, Z_NULL, 0);
+ break;
+
+ case GZSTATE_MAGIC1:
+ if (*z.next_in != GZIP_MAGIC1 &&
+ *z.next_in != GZIP_OMAGIC1) {
+ maybe_warnx("input not gziped (MAGIC1)");
+ goto stop_and_fail;
+ }
+ ADVANCE();
+ state++;
+ break;
+
+ case GZSTATE_METHOD:
+ if (*z.next_in != Z_DEFLATED) {
+ maybe_warnx("unknown compression method");
+ goto stop_and_fail;
+ }
+ ADVANCE();
+ state++;
+ break;
+
+ case GZSTATE_FLAGS:
+ flags = *z.next_in;
+ ADVANCE();
+ skip_count = 6;
+ state++;
+ break;
+
+ case GZSTATE_SKIPPING:
+ if (skip_count > 0) {
+ skip_count--;
+ ADVANCE();
+ } else
+ state++;
+ break;
+
+ case GZSTATE_EXTRA:
+ if ((flags & EXTRA_FIELD) == 0) {
+ state = GZSTATE_ORIGNAME;
+ break;
+ }
+ skip_count = *z.next_in;
+ ADVANCE();
+ state++;
+ break;
+
+ case GZSTATE_EXTRA2:
+ skip_count |= ((*z.next_in) << 8);
+ ADVANCE();
+ state++;
+ break;
+
+ case GZSTATE_EXTRA3:
+ if (skip_count > 0) {
+ skip_count--;
+ ADVANCE();
+ } else
+ state++;
+ break;
+
+ case GZSTATE_ORIGNAME:
+ if ((flags & ORIG_NAME) == 0) {
+ state++;
+ break;
+ }
+ if (*z.next_in == 0)
+ state++;
+ ADVANCE();
+ break;
+
+ case GZSTATE_COMMENT:
+ if ((flags & COMMENT) == 0) {
+ state++;
+ break;
+ }
+ if (*z.next_in == 0)
+ state++;
+ ADVANCE();
+ break;
+
+ case GZSTATE_HEAD_CRC1:
+ if (flags & HEAD_CRC)
+ skip_count = 2;
+ else
+ skip_count = 0;
+ state++;
+ break;
+
+ case GZSTATE_HEAD_CRC2:
+ if (skip_count > 0) {
+ skip_count--;
+ ADVANCE();
+ } else
+ state++;
+ break;
+
+ case GZSTATE_INIT:
+ if (inflateInit2(&z, -MAX_WBITS) != Z_OK) {
+ maybe_warnx("failed to inflateInit");
+ goto stop_and_fail;
+ }
+ state++;
+ break;
+
+ case GZSTATE_READ:
+ error = inflate(&z, Z_FINISH);
+ switch (error) {
+ /* Z_BUF_ERROR goes with Z_FINISH... */
+ case Z_BUF_ERROR:
+ if (z.avail_out > 0 && !done_reading)
+ continue;
+
+ case Z_STREAM_END:
+ case Z_OK:
+ break;
+
+ case Z_NEED_DICT:
+ maybe_warnx("Z_NEED_DICT error");
+ goto stop_and_fail;
+ case Z_DATA_ERROR:
+ maybe_warnx("data stream error");
+ goto stop_and_fail;
+ case Z_STREAM_ERROR:
+ maybe_warnx("internal stream error");
+ goto stop_and_fail;
+ case Z_MEM_ERROR:
+ maybe_warnx("memory allocation error");
+ goto stop_and_fail;
+
+ default:
+ maybe_warn("unknown error from inflate(): %d",
+ error);
+ }
+ wr = BUFLEN - z.avail_out;
+
+ if (wr != 0) {
+ crc = crc32(crc, (const Bytef *)outbufp, (unsigned)wr);
+ if (
+#ifndef SMALL
+ /* don't write anything with -t */
+ tflag == 0 &&
+#endif
+ write(out, outbufp, wr) != wr) {
+ maybe_warn("error writing to output");
+ goto stop_and_fail;
+ }
+
+ out_tot += wr;
+ out_sub_tot += wr;
+ }
+
+ if (error == Z_STREAM_END) {
+ inflateEnd(&z);
+ state++;
+ }
+
+ z.next_out = (unsigned char *)outbufp;
+ z.avail_out = BUFLEN;
+
+ break;
+ case GZSTATE_CRC:
+ {
+ uLong origcrc;
+
+ if (z.avail_in < 4) {
+ if (!done_reading) {
+ needmore = 1;
+ continue;
+ }
+ maybe_warnx("truncated input");
+ goto stop_and_fail;
+ }
+ origcrc = ((unsigned)z.next_in[0] & 0xff) |
+ ((unsigned)z.next_in[1] & 0xff) << 8 |
+ ((unsigned)z.next_in[2] & 0xff) << 16 |
+ ((unsigned)z.next_in[3] & 0xff) << 24;
+ if (origcrc != crc) {
+ maybe_warnx("invalid compressed"
+ " data--crc error");
+ goto stop_and_fail;
+ }
+ }
+
+ z.avail_in -= 4;
+ z.next_in += 4;
+
+ if (!z.avail_in && done_reading) {
+ goto stop;
+ }
+ state++;
+ break;
+ case GZSTATE_LEN:
+ {
+ uLong origlen;
+
+ if (z.avail_in < 4) {
+ if (!done_reading) {
+ needmore = 1;
+ continue;
+ }
+ maybe_warnx("truncated input");
+ goto stop_and_fail;
+ }
+ origlen = ((unsigned)z.next_in[0] & 0xff) |
+ ((unsigned)z.next_in[1] & 0xff) << 8 |
+ ((unsigned)z.next_in[2] & 0xff) << 16 |
+ ((unsigned)z.next_in[3] & 0xff) << 24;
+
+ if (origlen != out_sub_tot) {
+ maybe_warnx("invalid compressed"
+ " data--length error");
+ goto stop_and_fail;
+ }
+ }
+
+ z.avail_in -= 4;
+ z.next_in += 4;
+
+ if (error < 0) {
+ maybe_warnx("decompression error");
+ goto stop_and_fail;
+ }
+ state = GZSTATE_MAGIC0;
+ break;
+ }
+ continue;
+stop_and_fail:
+ out_tot = -1;
+stop:
+ break;
+ }
+ if (state > GZSTATE_INIT)
+ inflateEnd(&z);
+
+ free(inbufp);
+out1:
+ free(outbufp);
+out2:
+ if (gsizep)
+ *gsizep = in_tot;
+ return (out_tot);
+}
+
+#ifndef SMALL
+/*
+ * set the owner, mode, flags & utimes using the given file descriptor.
+ * file is only used in possible warning messages.
+ */
+static void
+copymodes(int fd, const struct stat *sbp, const char *file)
+{
+ struct timespec times[2];
+ struct stat sb;
+
+ /*
+ * If we have no info on the input, give this file some
+ * default values and return..
+ */
+ if (sbp == NULL) {
+ mode_t mask = umask(022);
+
+ (void)fchmod(fd, DEFFILEMODE & ~mask);
+ (void)umask(mask);
+ return;
+ }
+ sb = *sbp;
+
+ /* if the chown fails, remove set-id bits as-per compress(1) */
+ if (fchown(fd, sb.st_uid, sb.st_gid) < 0) {
+ if (errno != EPERM)
+ maybe_warn("couldn't fchown: %s", file);
+ sb.st_mode &= ~(S_ISUID|S_ISGID);
+ }
+
+ /* we only allow set-id and the 9 normal permission bits */
+ sb.st_mode &= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+ if (fchmod(fd, sb.st_mode) < 0)
+ maybe_warn("couldn't fchmod: %s", file);
+
+#ifdef __APPLE__
+ times[0] = sb.st_atimespec;
+ times[1] = sb.st_mtimespec;
+#else
+ times[0] = sb.st_atim;
+ times[1] = sb.st_mtim;
+#endif
+ if (futimens(fd, times) < 0)
+ maybe_warn("couldn't futimens: %s", file);
+
+ /* only try flags if they exist already */
+ if (sb.st_flags != 0 && fchflags(fd, sb.st_flags) < 0)
+ maybe_warn("couldn't fchflags: %s", file);
+}
+#endif
+
+/* what sort of file is this? */
+static enum filetype
+file_gettype(u_char *buf)
+{
+
+ if (buf[0] == GZIP_MAGIC0 &&
+ (buf[1] == GZIP_MAGIC1 || buf[1] == GZIP_OMAGIC1))
+ return FT_GZIP;
+ else
+#ifndef NO_BZIP2_SUPPORT
+ if (memcmp(buf, BZIP2_MAGIC, 3) == 0 &&
+ buf[3] >= '0' && buf[3] <= '9')
+ return FT_BZIP2;
+ else
+#endif
+#ifndef NO_COMPRESS_SUPPORT
+ if (memcmp(buf, Z_MAGIC, 2) == 0)
+ return FT_Z;
+ else
+#endif
+#ifndef NO_PACK_SUPPORT
+ if (memcmp(buf, PACK_MAGIC, 2) == 0)
+ return FT_PACK;
+ else
+#endif
+#ifndef NO_XZ_SUPPORT
+ if (memcmp(buf, XZ_MAGIC, 4) == 0) /* XXX: We only have 4 bytes */
+ return FT_XZ;
+ else
+#endif
+ return FT_UNKNOWN;
+}
+
+#ifndef SMALL
+/* check the outfile is OK. */
+static int
+check_outfile(const char *outfile)
+{
+ struct stat sb;
+ int ok = 1;
+
+ if (lflag == 0 && stat(outfile, &sb) == 0) {
+ if (fflag)
+ unlink(outfile);
+ else if (isatty(STDIN_FILENO)) {
+ char ans[10] = { 'n', '\0' }; /* default */
+
+ fprintf(stderr, "%s already exists -- do you wish to "
+ "overwrite (y or n)? " , outfile);
+ (void)fgets(ans, sizeof(ans) - 1, stdin);
+ if (ans[0] != 'y' && ans[0] != 'Y') {
+ fprintf(stderr, "\tnot overwriting\n");
+ ok = 0;
+ } else
+ unlink(outfile);
+ } else {
+ maybe_warnx("%s already exists -- skipping", outfile);
+ ok = 0;
+ }
+ }
+ return ok;
+}
+
+static void
+unlink_input(const char *file, const struct stat *sb)
+{
+ struct stat nsb;
+
+ if (kflag)
+ return;
+ bzero(&nsb, sizeof(nsb));
+ if (stat(file, &nsb) != 0)
+ /* Must be gone already */
+ return;
+ if (nsb.st_dev != sb->st_dev || nsb.st_ino != sb->st_ino)
+ /* Definitely a different file */
+ return;
+ unlink(file);
+}
+
+static void
+sigint_handler(int signo __unused)
+{
+
+ if (remove_file != NULL)
+ unlink(remove_file);
+ _exit(2);
+}
+#endif
+
+static const suffixes_t *
+check_suffix(char *file, int xlate)
+{
+ const suffixes_t *s;
+ int len = strlen(file);
+ char *sp;
+
+ for (s = suffixes; s != suffixes + NUM_SUFFIXES; s++) {
+ /* if it doesn't fit in "a.suf", don't bother */
+ if (s->ziplen >= len)
+ continue;
+ sp = file + len - s->ziplen;
+ if (strcmp(s->zipped, sp) != 0)
+ continue;
+ if (xlate)
+ strcpy(sp, s->normal);
+ return s;
+ }
+ return NULL;
+}
+
+#ifdef __APPLE__
+static void
+clear_type_and_creator(int fd)
+{
+ struct attrlist alist;
+ struct {
+ u_int32_t length;
+ char info[32];
+ } abuf;
+
+ memset(&alist, 0, sizeof(alist));
+ alist.bitmapcount = ATTR_BIT_MAP_COUNT;
+ alist.commonattr = ATTR_CMN_FNDRINFO;
+
+ if (!fgetattrlist(fd, &alist, &abuf, sizeof(abuf), 0) && abuf.length == sizeof(abuf)) {
+ memset(abuf.info, 0, 8);
+ fsetattrlist(fd, &alist, abuf.info, sizeof(abuf.info), 0);
+ }
+}
+#endif /* __APPLE__ */
+
+/*
+ * compress the given file: create a corresponding .gz file and remove the
+ * original.
+ */
+static off_t
+file_compress(char *file, char *outfile, size_t outsize)
+{
+ int in;
+ int out;
+ off_t size, insize;
+#ifndef SMALL
+ struct stat isb, osb;
+ const suffixes_t *suff;
+#endif
+
+ in = open(file, O_RDONLY);
+ if (in == -1) {
+ maybe_warn("can't open %s", file);
+ return (-1);
+ }
+
+#ifndef SMALL
+ bzero(&isb, sizeof(isb));
+ if (fstat(in, &isb) != 0) {
+ maybe_warn("couldn't stat: %s", file);
+ close(in);
+ return (-1);
+ }
+#endif
+
+ if (cflag == 0) {
+#ifndef SMALL
+ if (isb.st_nlink > 1 && fflag == 0) {
+ maybe_warnx("%s has %d other link%s -- skipping",
+ file, isb.st_nlink - 1,
+ (isb.st_nlink - 1) == 1 ? "" : "s");
+ close(in);
+ return (-1);
+ }
+
+ if (fflag == 0 && (suff = check_suffix(file, 0)) &&
+ suff->zipped[0] != 0) {
+ maybe_warnx("%s already has %s suffix -- unchanged",
+ file, suff->zipped);
+ close(in);
+ return (-1);
+ }
+#endif
+
+ /* Add (usually) .gz to filename */
+ if ((size_t)snprintf(outfile, outsize, "%s%s",
+ file, suffixes[0].zipped) >= outsize)
+ memcpy(outfile + outsize - suffixes[0].ziplen - 1,
+ suffixes[0].zipped, suffixes[0].ziplen + 1);
+
+#ifndef SMALL
+ if (check_outfile(outfile) == 0) {
+ close(in);
+ return (-1);
+ }
+#endif
+ }
+
+ if (cflag == 0) {
+ out = open(outfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
+ if (out == -1) {
+ maybe_warn("could not create output: %s", outfile);
+ fclose(stdin);
+ return (-1);
+ }
+#ifndef SMALL
+ remove_file = outfile;
+#endif
+ } else
+ out = STDOUT_FILENO;
+
+ insize = gz_compress(in, out, &size, basename(file), (uint32_t)isb.st_mtime);
+
+#ifndef __APPLE__
+ (void)close(in);
+#endif /* !__APPLE__ */
+
+ /*
+ * If there was an error, insize will be -1.
+ * If we compressed to stdout, just return the size.
+ * Otherwise stat the file and check it is the correct size.
+ * We only blow away the file if we can stat the output and it
+ * has the expected size.
+ */
+ if (cflag != 0)
+ return (insize == -1 ? -1 : size);
+
+#ifndef SMALL
+ if (fstat(out, &osb) != 0) {
+ maybe_warn("couldn't stat: %s", outfile);
+ goto bad_outfile;
+ }
+
+ if (osb.st_size != size) {
+ maybe_warnx("output file: %s wrong size (%ju != %ju), deleting",
+ outfile, (uintmax_t)osb.st_size, (uintmax_t)size);
+ goto bad_outfile;
+ }
+
+#ifdef __APPLE__
+ fcopyfile(in, out, 0, COPYFILE_ACL | COPYFILE_XATTR);
+ clear_type_and_creator(out);
+#endif /* __APPLE__ */
+ copymodes(out, &isb, outfile);
+ remove_file = NULL;
+#endif
+#ifdef __APPLE__
+ (void)close(in);
+#endif /* __APPLE__ */
+ if (close(out) == -1)
+ maybe_warn("couldn't close output");
+
+ /* output is good, ok to delete input */
+ unlink_input(file, &isb);
+ return (size);
+
+#ifndef SMALL
+ bad_outfile:
+ if (close(out) == -1)
+ maybe_warn("couldn't close output");
+
+ maybe_warnx("leaving original %s", file);
+ unlink(outfile);
+ return (size);
+#endif
+}
+
+/* uncompress the given file and remove the original */
+static off_t
+file_uncompress(char *file, char *outfile, size_t outsize)
+{
+ struct stat isb, osb;
+ off_t size;
+ ssize_t rbytes;
+ unsigned char header1[4];
+ enum filetype method;
+ int fd, ofd, zfd = -1;
+#ifndef SMALL
+ ssize_t rv;
+ time_t timestamp = 0;
+ char name[PATH_MAX + 1];
+#endif
+
+ /* gather the old name info */
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0) {
+ maybe_warn("can't open %s", file);
+ goto lose;
+ }
+
+ strlcpy(outfile, file, outsize);
+ if (check_suffix(outfile, 1) == NULL && !(cflag || lflag)) {
+ maybe_warnx("%s: unknown suffix -- ignored", file);
+ goto lose;
+ }
+
+ rbytes = read(fd, header1, sizeof header1);
+ if (rbytes != sizeof header1) {
+ /* we don't want to fail here. */
+#ifndef SMALL
+ if (fflag)
+ goto lose;
+#endif
+ if (rbytes == -1)
+ maybe_warn("can't read %s", file);
+ else
+ goto unexpected_EOF;
+ goto lose;
+ }
+
+ method = file_gettype(header1);
+#ifndef SMALL
+ if (fflag == 0 && method == FT_UNKNOWN) {
+ maybe_warnx("%s: not in gzip format", file);
+ goto lose;
+ }
+
+#endif
+
+#ifndef SMALL
+ if (method == FT_GZIP && Nflag) {
+ unsigned char ts[4]; /* timestamp */
+
+ rv = pread(fd, ts, sizeof ts, GZIP_TIMESTAMP);
+ if (rv >= 0 && rv < (ssize_t)(sizeof ts))
+ goto unexpected_EOF;
+ if (rv == -1) {
+ if (!fflag)
+ maybe_warn("can't read %s", file);
+ goto lose;
+ }
+ timestamp = ts[3] << 24 | ts[2] << 16 | ts[1] << 8 | ts[0];
+
+ if (header1[3] & ORIG_NAME) {
+ rbytes = pread(fd, name, sizeof(name) - 1, GZIP_ORIGNAME);
+ if (rbytes < 0) {
+ maybe_warn("can't read %s", file);
+ goto lose;
+ }
+ if (name[0] != '\0') {
+ char *dp, *nf;
+
+ /* Make sure that name is NUL-terminated */
+ name[rbytes] = '\0';
+
+ /* strip saved directory name */
+ nf = strrchr(name, '/');
+ if (nf == NULL)
+ nf = name;
+ else
+ nf++;
+
+ /* preserve original directory name */
+ dp = strrchr(file, '/');
+ if (dp == NULL)
+ dp = file;
+ else
+ dp++;
+ snprintf(outfile, outsize, "%.*s%.*s",
+ (int) (dp - file),
+ file, (int) rbytes, nf);
+ }
+ }
+ }
+#endif
+ lseek(fd, 0, SEEK_SET);
+ bzero(&isb, sizeof(isb));
+ if (cflag == 0 || lflag) {
+ if (fstat(fd, &isb) != 0)
+ goto lose;
+#ifndef SMALL
+ if (isb.st_nlink > 1 && lflag == 0 && fflag == 0) {
+ maybe_warnx("%s has %d other links -- skipping",
+ file, isb.st_nlink - 1);
+ goto lose;
+ }
+ if (nflag == 0 && timestamp)
+ isb.st_mtime = timestamp;
+ if (check_outfile(outfile) == 0)
+ goto lose;
+#endif
+ }
+
+ if (cflag == 0 && lflag == 0) {
+ zfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0600);
+ if (zfd == STDOUT_FILENO) {
+ /* We won't close STDOUT_FILENO later... */
+ zfd = dup(zfd);
+ close(STDOUT_FILENO);
+ }
+ if (zfd == -1) {
+ maybe_warn("can't open %s", outfile);
+ goto lose;
+ }
+#ifndef SMALL
+ remove_file = outfile;
+#endif
+ } else
+ zfd = STDOUT_FILENO;
+
+ switch (method) {
+#ifndef NO_BZIP2_SUPPORT
+ case FT_BZIP2:
+ /* XXX */
+ if (lflag) {
+ maybe_warnx("no -l with bzip2 files");
+ goto lose;
+ }
+
+ size = unbzip2(fd, zfd, NULL, 0, NULL);
+ break;
+#endif
+
+#ifndef NO_COMPRESS_SUPPORT
+ case FT_Z: {
+ FILE *in, *out;
+
+ /* XXX */
+ if (lflag) {
+ maybe_warnx("no -l with Lempel-Ziv files");
+ goto lose;
+ }
+
+ if ((in = zdopen(fd)) == NULL) {
+ maybe_warn("zdopen for read: %s", file);
+ goto lose;
+ }
+
+ out = fdopen(dup(zfd), "w");
+ if (out == NULL) {
+ maybe_warn("fdopen for write: %s", outfile);
+ fclose(in);
+ goto lose;
+ }
+
+ size = zuncompress(in, out, NULL, 0, NULL);
+ /* need to fclose() if ferror() is true... */
+ if (ferror(in) | fclose(in)) {
+ maybe_warn("failed infile fclose");
+ unlink(outfile);
+ (void)fclose(out);
+ }
+ if (fclose(out) != 0) {
+ maybe_warn("failed outfile fclose");
+ unlink(outfile);
+ goto lose;
+ }
+ break;
+ }
+#endif
+
+#ifndef NO_PACK_SUPPORT
+ case FT_PACK:
+ if (lflag) {
+ maybe_warnx("no -l with packed files");
+ goto lose;
+ }
+
+ size = unpack(fd, zfd, NULL, 0, NULL);
+ break;
+#endif
+
+#ifndef NO_XZ_SUPPORT
+ case FT_XZ:
+ if (lflag) {
+ maybe_warnx("no -l with xz files");
+ goto lose;
+ }
+
+ size = unxz(fd, zfd, NULL, 0, NULL);
+ break;
+#endif
+
+#ifndef SMALL
+ case FT_UNKNOWN:
+ if (lflag) {
+ maybe_warnx("no -l for unknown filetypes");
+ goto lose;
+ }
+ size = cat_fd(NULL, 0, NULL, fd);
+ break;
+#endif
+ default:
+ if (lflag) {
+ print_list(fd, isb.st_size, outfile, isb.st_mtime);
+ close(fd);
+ return -1; /* XXX */
+ }
+
+ size = gz_uncompress(fd, zfd, NULL, 0, NULL, file);
+ break;
+ }
+
+ if (close(fd) != 0)
+ maybe_warn("couldn't close input");
+ if (zfd != STDOUT_FILENO && close(zfd) != 0)
+ maybe_warn("couldn't close output");
+
+ if (size == -1) {
+ if (cflag == 0)
+ unlink(outfile);
+ maybe_warnx("%s: uncompress failed", file);
+ return -1;
+ }
+
+ /* if testing, or we uncompressed to stdout, this is all we need */
+#ifndef SMALL
+ if (tflag)
+ return size;
+#endif
+ /* if we are uncompressing to stdin, don't remove the file. */
+ if (cflag)
+ return size;
+
+ /*
+ * if we create a file...
+ */
+ /*
+ * if we can't stat the file don't remove the file.
+ */
+
+ ofd = open(outfile, O_RDWR, 0);
+ if (ofd == -1) {
+ maybe_warn("couldn't open (leaving original): %s",
+ outfile);
+ return -1;
+ }
+ if (fstat(ofd, &osb) != 0) {
+ maybe_warn("couldn't stat (leaving original): %s",
+ outfile);
+ close(ofd);
+ return -1;
+ }
+ if (osb.st_size != size) {
+ maybe_warnx("stat gave different size: %ju != %ju (leaving original)",
+ (uintmax_t)size, (uintmax_t)osb.st_size);
+ close(ofd);
+ unlink(outfile);
+ return -1;
+ }
+#ifndef SMALL
+ copymodes(ofd, &isb, outfile);
+ remove_file = NULL;
+#endif
+ close(ofd);
+ unlink_input(file, &isb);
+ return size;
+
+ unexpected_EOF:
+ maybe_warnx("%s: unexpected end of file", file);
+ lose:
+ if (fd != -1)
+ close(fd);
+ if (zfd != -1 && zfd != STDOUT_FILENO)
+ close(fd);
+ return -1;
+}
+
+#ifndef SMALL
+static off_t
+cat_fd(unsigned char * prepend, size_t count, off_t *gsizep, int fd)
+{
+ char buf[BUFLEN];
+ off_t in_tot;
+ ssize_t w;
+
+ in_tot = count;
+ w = write(STDOUT_FILENO, prepend, count);
+ if (w == -1 || (size_t)w != count) {
+ maybe_warn("write to stdout");
+ return -1;
+ }
+ for (;;) {
+ ssize_t rv;
+
+ rv = read(fd, buf, sizeof buf);
+ if (rv == 0)
+ break;
+ if (rv < 0) {
+ maybe_warn("read from fd %d", fd);
+ break;
+ }
+
+ if (write(STDOUT_FILENO, buf, rv) != rv) {
+ maybe_warn("write to stdout");
+ break;
+ }
+ in_tot += rv;
+ }
+
+ if (gsizep)
+ *gsizep = in_tot;
+ return (in_tot);
+}
+#endif
+
+static void
+handle_stdin(void)
+{
+ unsigned char header1[4];
+ off_t usize, gsize;
+ enum filetype method;
+ ssize_t bytes_read;
+#ifndef NO_COMPRESS_SUPPORT
+ FILE *in;
+#endif
+
+#ifndef SMALL
+ if (fflag == 0 && lflag == 0 && isatty(STDIN_FILENO)) {
+ maybe_warnx("standard input is a terminal -- ignoring");
+ return;
+ }
+#endif
+
+ if (lflag) {
+ struct stat isb;
+
+ /* XXX could read the whole file, etc. */
+ if (fstat(STDIN_FILENO, &isb) < 0) {
+ maybe_warn("fstat");
+ return;
+ }
+ print_list(STDIN_FILENO, isb.st_size, "stdout", isb.st_mtime);
+ return;
+ }
+
+ bytes_read = read_retry(STDIN_FILENO, header1, sizeof header1);
+ if (bytes_read == -1) {
+ maybe_warn("can't read stdin");
+ return;
+ } else if (bytes_read != sizeof(header1)) {
+ maybe_warnx("(stdin): unexpected end of file");
+ return;
+ }
+
+ method = file_gettype(header1);
+ switch (method) {
+ default:
+#ifndef SMALL
+ if (fflag == 0) {
+ maybe_warnx("unknown compression format");
+ return;
+ }
+ usize = cat_fd(header1, sizeof header1, &gsize, STDIN_FILENO);
+ break;
+#endif
+ case FT_GZIP:
+ usize = gz_uncompress(STDIN_FILENO, STDOUT_FILENO,
+ (char *)header1, sizeof header1, &gsize, "(stdin)");
+ break;
+#ifndef NO_BZIP2_SUPPORT
+ case FT_BZIP2:
+ usize = unbzip2(STDIN_FILENO, STDOUT_FILENO,
+ (char *)header1, sizeof header1, &gsize);
+ break;
+#endif
+#ifndef NO_COMPRESS_SUPPORT
+ case FT_Z:
+ if ((in = zdopen(STDIN_FILENO)) == NULL) {
+ maybe_warnx("zopen of stdin");
+ return;
+ }
+
+ usize = zuncompress(in, stdout, (char *)header1,
+ sizeof header1, &gsize);
+ fclose(in);
+ break;
+#endif
+#ifndef NO_PACK_SUPPORT
+ case FT_PACK:
+ usize = unpack(STDIN_FILENO, STDOUT_FILENO,
+ (char *)header1, sizeof header1, &gsize);
+ break;
+#endif
+#ifndef NO_XZ_SUPPORT
+ case FT_XZ:
+ usize = unxz(STDIN_FILENO, STDOUT_FILENO,
+ (char *)header1, sizeof header1, &gsize);
+ break;
+#endif
+ }
+
+#ifndef SMALL
+ if (vflag && !tflag && usize != -1 && gsize != -1)
+ print_verbage(NULL, NULL, usize, gsize);
+ if (vflag && tflag)
+ print_test("(stdin)", usize != -1);
+#endif
+
+}
+
+static void
+handle_stdout(void)
+{
+ off_t gsize, usize;
+ struct stat sb;
+ time_t systime;
+ uint32_t mtime;
+ int ret;
+
+#ifndef SMALL
+ if (fflag == 0 && isatty(STDOUT_FILENO)) {
+ maybe_warnx("standard output is a terminal -- ignoring");
+ return;
+ }
+#endif
+ /* If stdin is a file use its mtime, otherwise use current time */
+ ret = fstat(STDIN_FILENO, &sb);
+
+#ifndef SMALL
+ if (ret < 0) {
+ maybe_warn("Can't stat stdin");
+ return;
+ }
+#endif
+
+ if (S_ISREG(sb.st_mode))
+ mtime = (uint32_t)sb.st_mtime;
+ else {
+ systime = time(NULL);
+#ifndef SMALL
+ if (systime == -1) {
+ maybe_warn("time");
+ return;
+ }
+#endif
+ mtime = (uint32_t)systime;
+ }
+
+ usize = gz_compress(STDIN_FILENO, STDOUT_FILENO, &gsize, "", mtime);
+#ifndef SMALL
+ if (vflag && !tflag && usize != -1 && gsize != -1)
+ print_verbage(NULL, NULL, usize, gsize);
+#endif
+}
+
+/* do what is asked for, for the path name */
+static void
+handle_pathname(char *path)
+{
+ char *opath = path, *s = NULL;
+ ssize_t len;
+ int slen;
+ struct stat sb;
+
+ /* check for stdout/stdin */
+ if (path[0] == '-' && path[1] == '\0') {
+ if (dflag)
+ handle_stdin();
+ else
+ handle_stdout();
+ return;
+ }
+
+#ifdef __APPLE__
+ if (zcat && COMPAT_MODE("bin/zcat", "Unix2003")) {
+ char *suffix = strrchr(path, '.');
+ if (suffix == NULL || strcmp(suffix, Z_SUFFIX) != 0) {
+ len = strlen(path);
+ slen = sizeof(Z_SUFFIX) - 1;
+ s = malloc(len + slen + 1);
+ memcpy(s, path, len);
+ memcpy(s + len, Z_SUFFIX, slen + 1);
+ path = s;
+ }
+ }
+#endif
+
+retry:
+ if (stat(path, &sb) != 0 || (fflag == 0 && cflag == 0 &&
+ lstat(path, &sb) != 0)) {
+ /* lets try <path>.gz if we're decompressing */
+ if (dflag && s == NULL && errno == ENOENT) {
+ len = strlen(path);
+ slen = suffixes[0].ziplen;
+ s = malloc(len + slen + 1);
+ if (s == NULL)
+ maybe_err("malloc");
+ memcpy(s, path, len);
+ memcpy(s + len, suffixes[0].zipped, slen + 1);
+ path = s;
+ goto retry;
+ }
+#ifdef __APPLE__
+ /* Include actual path for clarity. */
+ maybe_warn("can't stat: %s (%s)", opath, path);
+#else
+ maybe_warn("can't stat: %s", opath);
+#endif
+ goto out;
+ }
+
+ if (S_ISDIR(sb.st_mode)) {
+#ifndef SMALL
+ if (rflag)
+ handle_dir(path);
+ else
+#endif
+ maybe_warnx("%s is a directory", path);
+ goto out;
+ }
+
+ if (S_ISREG(sb.st_mode))
+ handle_file(path, &sb);
+ else
+ maybe_warnx("%s is not a regular file", path);
+
+out:
+ if (s)
+ free(s);
+}
+
+/* compress/decompress a file */
+static void
+handle_file(char *file, struct stat *sbp)
+{
+ off_t usize, gsize;
+ char outfile[PATH_MAX];
+
+ infile = file;
+ if (dflag) {
+ usize = file_uncompress(file, outfile, sizeof(outfile));
+#ifndef SMALL
+ if (vflag && tflag)
+ print_test(file, usize != -1);
+#endif
+ if (usize == -1)
+ return;
+ gsize = sbp->st_size;
+ } else {
+ gsize = file_compress(file, outfile, sizeof(outfile));
+ if (gsize == -1)
+ return;
+ usize = sbp->st_size;
+ }
+
+
+#ifndef SMALL
+ if (vflag && !tflag)
+ print_verbage(file, (cflag) ? NULL : outfile, usize, gsize);
+#endif
+}
+
+#ifndef SMALL
+/* this is used with -r to recursively descend directories */
+static void
+handle_dir(char *dir)
+{
+ char *path_argv[2];
+ FTS *fts;
+ FTSENT *entry;
+
+ path_argv[0] = dir;
+ path_argv[1] = 0;
+ fts = fts_open(path_argv, FTS_PHYSICAL | FTS_NOCHDIR, NULL);
+ if (fts == NULL) {
+ warn("couldn't fts_open %s", dir);
+ return;
+ }
+
+ while ((entry = fts_read(fts))) {
+ switch(entry->fts_info) {
+ case FTS_D:
+ case FTS_DP:
+ continue;
+
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ maybe_warn("%s", entry->fts_path);
+ continue;
+ case FTS_F:
+ handle_file(entry->fts_path, entry->fts_statp);
+ }
+ }
+ (void)fts_close(fts);
+}
+#endif
+
+/* print a ratio - size reduction as a fraction of uncompressed size */
+static void
+print_ratio(off_t in, off_t out, FILE *where)
+{
+ int percent10; /* 10 * percent */
+ off_t diff;
+ char buff[8];
+ int len;
+
+ diff = in - out/2;
+ if (diff <= 0)
+ /*
+ * Output is more than double size of input! print -99.9%
+ * Quite possibly we've failed to get the original size.
+ */
+ percent10 = -999;
+ else {
+ /*
+ * We only need 12 bits of result from the final division,
+ * so reduce the values until a 32bit division will suffice.
+ */
+ while (in > 0x100000) {
+ diff >>= 1;
+ in >>= 1;
+ }
+ if (in != 0)
+ percent10 = ((u_int)diff * 2000) / (u_int)in - 1000;
+ else
+ percent10 = 0;
+ }
+
+ len = snprintf(buff, sizeof buff, "%2.2d.", percent10);
+ /* Move the '.' to before the last digit */
+ buff[len - 1] = buff[len - 2];
+ buff[len - 2] = '.';
+ fprintf(where, "%5s%%", buff);
+}
+
+#ifndef SMALL
+/* print compression statistics, and the new name (if there is one!) */
+static void
+print_verbage(const char *file, const char *nfile, off_t usize, off_t gsize)
+{
+ if (file)
+ fprintf(stderr, "%s:%s ", file,
+ strlen(file) < 7 ? "\t\t" : "\t");
+ print_ratio(usize, gsize, stderr);
+ if (nfile)
+ fprintf(stderr, " -- replaced with %s", nfile);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+
+/* print test results */
+static void
+print_test(const char *file, int ok)
+{
+
+ if (exit_value == 0 && ok == 0)
+ exit_value = 1;
+ fprintf(stderr, "%s:%s %s\n", file,
+ strlen(file) < 7 ? "\t\t" : "\t", ok ? "OK" : "NOT OK");
+ fflush(stderr);
+}
+#endif
+
+/* print a file's info ala --list */
+/* eg:
+ compressed uncompressed ratio uncompressed_name
+ 354841 1679360 78.8% /usr/pkgsrc/distfiles/libglade-2.0.1.tar
+*/
+static void
+print_list(int fd, off_t out, const char *outfile, time_t ts)
+{
+ static int first = 1;
+#ifndef SMALL
+ static off_t in_tot, out_tot;
+ uint32_t crc = 0;
+#endif
+ off_t in = 0, rv;
+
+ if (first) {
+#ifndef SMALL
+ if (vflag)
+ printf("method crc date time ");
+#endif
+ if (qflag == 0)
+ printf(" compressed uncompressed "
+ "ratio uncompressed_name\n");
+ }
+ first = 0;
+
+ /* print totals? */
+#ifndef SMALL
+ if (fd == -1) {
+ in = in_tot;
+ out = out_tot;
+ } else
+#endif
+ {
+ /* read the last 4 bytes - this is the uncompressed size */
+ rv = lseek(fd, (off_t)(-8), SEEK_END);
+ if (rv != -1) {
+ unsigned char buf[8];
+ uint32_t usize;
+
+ rv = read(fd, (char *)buf, sizeof(buf));
+ if (rv == -1)
+ maybe_warn("read of uncompressed size");
+ else if (rv != sizeof(buf))
+ maybe_warnx("read of uncompressed size");
+
+ else {
+ usize = buf[4] | buf[5] << 8 |
+ buf[6] << 16 | buf[7] << 24;
+ in = (off_t)usize;
+#ifndef SMALL
+ crc = buf[0] | buf[1] << 8 |
+ buf[2] << 16 | buf[3] << 24;
+#endif
+ }
+ }
+ }
+
+#ifndef SMALL
+ if (vflag && fd == -1)
+ printf(" ");
+ else if (vflag) {
+ char *date = ctime(&ts);
+
+ /* skip the day, 1/100th second, and year */
+ date += 4;
+ date[12] = 0;
+ printf("%5s %08x %11s ", "defla"/*XXX*/, crc, date);
+ }
+ in_tot += in;
+ out_tot += out;
+#else
+ (void)&ts; /* XXX */
+#endif
+ printf("%12llu %12llu ", (unsigned long long)out, (unsigned long long)in);
+ print_ratio(in, out, stdout);
+ printf(" %s\n", outfile);
+}
+
+/* display the usage of NetBSD gzip */
+static void
+usage(void)
+{
+
+ fprintf(stderr, "%s\n", gzip_version);
+ fprintf(stderr,
+#ifdef SMALL
+ "usage: %s [-" OPT_LIST "] [<file> [<file> ...]]\n",
+#else
+ "usage: %s [-123456789acdfhklLNnqrtVv] [-S .suffix] [<file> [<file> ...]]\n"
+ " -1 --fast fastest (worst) compression\n"
+ " -2 .. -8 set compression level\n"
+ " -9 --best best (slowest) compression\n"
+ " -c --stdout write to stdout, keep original files\n"
+ " --to-stdout\n"
+ " -d --decompress uncompress files\n"
+ " --uncompress\n"
+ " -f --force force overwriting & compress links\n"
+ " -h --help display this help\n"
+ " -k --keep don't delete input files during operation\n"
+ " -l --list list compressed file contents\n"
+ " -N --name save or restore original file name and time stamp\n"
+ " -n --no-name don't save original file name or time stamp\n"
+ " -q --quiet output no warnings\n"
+ " -r --recursive recursively compress files in directories\n"
+ " -S .suf use suffix .suf instead of .gz\n"
+ " --suffix .suf\n"
+ " -t --test test compressed file\n"
+ " -V --version display program version\n"
+ " -v --verbose print extra statistics\n",
+#endif
+ getprogname());
+ exit(0);
+}
+
+#ifndef SMALL
+/* display the license information of FreeBSD gzip */
+static void
+display_license(void)
+{
+
+#ifdef __APPLE__
+ fprintf(stderr, "%s (based on FreeBSD gzip 20150113)\n", gzip_version);
+#else
+ fprintf(stderr, "%s (based on NetBSD gzip 20150113)\n", gzip_version);
+#endif
+ fprintf(stderr, "%s\n", gzip_copyright);
+ exit(0);
+}
+#endif
+
+/* display the version of NetBSD gzip */
+static void
+display_version(void)
+{
+
+ fprintf(stderr, "%s\n", gzip_version);
+ exit(0);
+}
+
+#ifndef NO_BZIP2_SUPPORT
+#include "unbzip2.c"
+#endif
+#ifndef NO_COMPRESS_SUPPORT
+#include "zuncompress.c"
+#endif
+#ifndef NO_PACK_SUPPORT
+#include "unpack.c"
+#endif
+#ifndef NO_XZ_SUPPORT
+#include "unxz.c"
+#endif
+
+static ssize_t
+read_retry(int fd, void *buf, size_t sz)
+{
+ char *cp = buf;
+ size_t left = MIN(sz, (size_t) SSIZE_MAX);
+
+ while (left > 0) {
+ ssize_t ret;
+
+ ret = read(fd, cp, left);
+ if (ret == -1) {
+ return ret;
+ } else if (ret == 0) {
+ break; /* EOF */
+ }
+ cp += ret;
+ left -= ret;
+ }
+
+ return sz - left;
+}
diff --git a/file_cmds/gzip/gzip.plist b/file_cmds/gzip/gzip.plist
new file mode 100644
index 0000000..a0190fd
--- /dev/null
+++ b/file_cmds/gzip/gzip.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>OpenSourceImportDate</key>
+ <string>2012-10-25</string>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>gzip.txt</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>gzip.c: adjust --version output</string>
+ <string>gzip.c: timespec portability fixes</string>
+ <string>gzip.c: preserve ACLs/EAs (3753276)</string>
+ <string>gzip.c: clear type/creator (4123341)</string>
+ <string>gzip.c, gzip.1: zcat conformance (3675040)</string>
+ <string>zmore: work as zless or zmore</string>
+ </array>
+ <key>OpenSourceProject</key>
+ <string>gzip</string>
+ <key>OpenSourceSCM</key>
+ <string>cvs -d :pserver:anoncvs@anoncvs.fr.FreeBSD.org:/home/ncvs co src/usr.bin/gzip</string>
+ <key>OpenSourceVersion</key>
+ <string>2012-10-19</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/usr.bin/gzip/</string>
+</dict>
+</plist>
diff --git a/file_cmds/gzip/gzip.xcconfig b/file_cmds/gzip/gzip.xcconfig
new file mode 100644
index 0000000..382cbbf
--- /dev/null
+++ b/file_cmds/gzip/gzip.xcconfig
@@ -0,0 +1,49 @@
+PRODUCT_NAME = $(TARGET_NAME)
+GZIP_PREFIX = /usr/local
+GZIP_PREFIX[sdk=macosx*] = /usr
+INSTALL_PATH = $(GZIP_PREFIX)/bin
+
+GCC_PREPROCESSOR_DEFINITIONS = GZIP_APPLE_VERSION=\"$(RC_ProjectSourceVersion)\"
+
+// Make it build in the GUI
+SUPPORTED_PLATFORMS = iphoneos macosx
+ARCHS[sdk=macosx*] = x86_64
+RUN_CLANG_STATIC_ANALYZER = YES
+
+// Versioning
+CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion)
+VERSIONING_SYSTEM = apple-generic
+VERSION_INFO_PREFIX = __
+
+// Other Stuff
+ALWAYS_SEARCH_USER_PATHS = NO
+APPLY_RULES_IN_COPY_FILES = YES
+CODE_SIGN_IDENTITY = -
+DEAD_CODE_STRIPPING = YES
+DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
+STRIP_INSTALLED_PRODUCT = YES
+USE_HEADERMAP = NO
+
+// Warnings
+//CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES
+//CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
+GCC_TREAT_WARNINGS_AS_ERRORS = YES
+//GCC_WARN_64_TO_32_BIT_CONVERSION = YES
+GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES
+GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
+GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
+GCC_WARN_SHADOW = YES
+GCC_WARN_SIGN_COMPARE = YES
+GCC_WARN_UNINITIALIZED_AUTOS = YES
+GCC_WARN_UNKNOWN_PRAGMAS = YES
+GCC_WARN_UNUSED_FUNCTION = YES
+GCC_WARN_UNUSED_LABEL = YES
+GCC_WARN_UNUSED_PARAMETER = YES
+GCC_WARN_UNUSED_VARIABLE = YES
+
+// Used by install_scripts.sh
+GZIP_SCRIPTS = gzexe zdiff zforce zmore znew
+GZIP_LINKS = gzip gunzip gzip gzcat gzip zcat zdiff zcmp zmore zless
diff --git a/file_cmds/gzip/install_scripts.sh b/file_cmds/gzip/install_scripts.sh
new file mode 100644
index 0000000..6e8e550
--- /dev/null
+++ b/file_cmds/gzip/install_scripts.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+set -e
+
+INSTALL_MAN1_DIR=${INSTALL_ROOT}${GZIP_PREFIX}/share/man/man1
+
+install -d -m 0755 "${INSTALL_MAN1_DIR}"
+for script in ${GZIP_SCRIPTS}; do
+ printf "Installing ${script} ...\n"
+ install -m 0755 ${SRCROOT}/gzip/${script} ${INSTALL_DIR}/${script}
+ install -m 0644 ${SRCROOT}/gzip/${script}.1 ${INSTALL_MAN1_DIR}/${script}.1
+done
+
+set ${GZIP_LINKS}
+while [ $# -ge 2 ]; do
+ l=$1
+ shift
+ t=$1
+ shift
+ printf "Creating link: ${t} -> ${l} ...\n"
+ ln -f ${INSTALL_DIR}/${l} ${INSTALL_DIR}/${t}
+ ln -f ${INSTALL_MAN1_DIR}/${l}.1 ${INSTALL_MAN1_DIR}/${t}.1
+done
diff --git a/file_cmds/gzip/unbzip2.c b/file_cmds/gzip/unbzip2.c
new file mode 100644
index 0000000..4192e9b
--- /dev/null
+++ b/file_cmds/gzip/unbzip2.c
@@ -0,0 +1,141 @@
+/* $NetBSD: unbzip2.c,v 1.13 2009/12/05 03:23:37 mrg Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Simon Burge.
+ *
+ * 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.
+ *
+ * $FreeBSD: src/usr.bin/gzip/unbzip2.c,v 1.5 2010/04/07 22:54:53 delphij Exp $
+ */
+
+/* This file is #included by gzip.c */
+
+static off_t
+unbzip2(int in, int out, char *pre, size_t prelen, off_t *bytes_in)
+{
+ int ret, end_of_file, cold = 0;
+ off_t bytes_out = 0;
+ bz_stream bzs;
+ static char *inbuf, *outbuf;
+
+ if (inbuf == NULL)
+ inbuf = malloc(BUFLEN);
+ if (outbuf == NULL)
+ outbuf = malloc(BUFLEN);
+ if (inbuf == NULL || outbuf == NULL)
+ maybe_err("malloc");
+
+ bzs.bzalloc = NULL;
+ bzs.bzfree = NULL;
+ bzs.opaque = NULL;
+
+ end_of_file = 0;
+ ret = BZ2_bzDecompressInit(&bzs, 0, 0);
+ if (ret != BZ_OK)
+ maybe_errx("bzip2 init");
+
+ /* Prepend. */
+ bzs.avail_in = prelen;
+ bzs.next_in = pre;
+
+ if (bytes_in)
+ *bytes_in = prelen;
+
+ while (ret == BZ_OK) {
+ if (bzs.avail_in == 0 && !end_of_file) {
+ ssize_t n;
+
+ n = read(in, inbuf, BUFLEN);
+ if (n < 0)
+ maybe_err("read");
+ if (n == 0)
+ end_of_file = 1;
+ bzs.next_in = inbuf;
+ bzs.avail_in = n;
+ if (bytes_in)
+ *bytes_in += n;
+ }
+
+ bzs.next_out = outbuf;
+ bzs.avail_out = BUFLEN;
+ ret = BZ2_bzDecompress(&bzs);
+
+ switch (ret) {
+ case BZ_STREAM_END:
+ case BZ_OK:
+ if (ret == BZ_OK && end_of_file) {
+ /*
+ * If we hit this after a stream end, consider
+ * it as the end of the whole file and don't
+ * bail out.
+ */
+ if (cold == 1)
+ ret = BZ_STREAM_END;
+ else
+ maybe_errx("truncated file");
+ }
+ cold = 0;
+ if (!tflag && bzs.avail_out != BUFLEN) {
+ ssize_t n;
+
+ n = write(out, outbuf, BUFLEN - bzs.avail_out);
+ if (n < 0)
+ maybe_err("write");
+ bytes_out += n;
+ }
+ if (ret == BZ_STREAM_END && !end_of_file) {
+ if (BZ2_bzDecompressEnd(&bzs) != BZ_OK ||
+ BZ2_bzDecompressInit(&bzs, 0, 0) != BZ_OK)
+ maybe_errx("bzip2 re-init");
+ cold = 1;
+ ret = BZ_OK;
+ }
+ break;
+
+ case BZ_DATA_ERROR:
+ maybe_warnx("bzip2 data integrity error");
+ break;
+
+ case BZ_DATA_ERROR_MAGIC:
+ maybe_warnx("bzip2 magic number error");
+ break;
+
+ case BZ_MEM_ERROR:
+ maybe_warnx("bzip2 out of memory");
+ break;
+
+ default:
+ maybe_warnx("unknown bzip2 error: %d", ret);
+ break;
+ }
+ }
+
+ if (ret != BZ_STREAM_END || BZ2_bzDecompressEnd(&bzs) != BZ_OK)
+ return (-1);
+
+ return (bytes_out);
+}
+
diff --git a/file_cmds/gzip/unpack.c b/file_cmds/gzip/unpack.c
new file mode 100644
index 0000000..dbad588
--- /dev/null
+++ b/file_cmds/gzip/unpack.c
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 2009 Xin LI <delphij@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/gzip/unpack.c,v 1.3 2010/10/16 15:24:04 bcr Exp $
+ */
+
+/* This file is #included by gzip.c */
+
+/*
+ * pack(1) file format:
+ *
+ * The first 7 bytes is the header:
+ * 00, 01 - Signature (US, RS), we already validated it earlier.
+ * 02..05 - Uncompressed size
+ * 06 - Level for the huffman tree (<=24)
+ *
+ * pack(1) will then store symbols (leaf) nodes count in each huffman
+ * tree levels, each level would consume 1 byte (See [1]).
+ *
+ * After the symbol count table, there is the symbol table, storing
+ * symbols represented by corresponding leaf node. EOB is not being
+ * explicitly transmitted (not necessary anyway) in the symbol table.
+ *
+ * Compressed data goes after the symbol table.
+ *
+ * NOTES
+ *
+ * [1] If we count EOB into the symbols, that would mean that we will
+ * have at most 256 symbols in the huffman tree. pack(1) rejects empty
+ * file and files that just repeats one character, which means that we
+ * will have at least 2 symbols. Therefore, pack(1) would reduce the
+ * last level symbol count by 2 which makes it a number in
+ * range [0..254], so all levels' symbol count would fit into 1 byte.
+ */
+
+#define PACK_HEADER_LENGTH 7
+#define HTREE_MAXLEVEL 24
+
+/*
+ * unpack descriptor
+ *
+ * Represent the huffman tree in a similar way that pack(1) would
+ * store in a packed file. We store all symbols in a linear table,
+ * and store pointers to each level's first symbol. In addition to
+ * that, maintain two counts for each level: inner nodes count and
+ * leaf nodes count.
+ */
+typedef struct {
+ int symbol_size; /* Size of the symbol table */
+ int treelevels; /* Levels for the huffman tree */
+
+ int *symbolsin; /* Table of leaf symbols count in
+ each level */
+ int *inodesin; /* Table of internal nodes count in
+ each level */
+
+ char *symbol; /* The symbol table */
+ char *symbol_eob; /* Pointer to the EOB symbol */
+ char **tree; /* Decoding huffman tree (pointers to
+ first symbol of each tree level */
+
+ off_t uncompressed_size; /* Uncompressed size */
+ FILE *fpIn; /* Input stream */
+ FILE *fpOut; /* Output stream */
+} unpack_descriptor_t;
+
+/*
+ * Release resource allocated to an unpack descriptor.
+ *
+ * Caller is responsible to make sure that all of these pointers are
+ * initialized (in our case, they all point to valid memory block).
+ * We don't zero out pointers here because nobody else would ever
+ * reference the memory block without scrubbing them.
+ */
+static void
+unpack_descriptor_fini(unpack_descriptor_t *unpackd)
+{
+
+ free(unpackd->symbolsin);
+ free(unpackd->inodesin);
+ free(unpackd->symbol);
+ free(unpackd->tree);
+
+ fclose(unpackd->fpIn);
+ fclose(unpackd->fpOut);
+}
+
+/*
+ * Recursively fill the internal node count table
+ */
+static void
+unpackd_fill_inodesin(const unpack_descriptor_t *unpackd, int level)
+{
+
+ /*
+ * The internal nodes would be 1/2 of total internal nodes and
+ * leaf nodes in the next level. For the last level there
+ * would be no internal node by definition.
+ */
+ if (level < unpackd->treelevels) {
+ unpackd_fill_inodesin(unpackd, level + 1);
+ unpackd->inodesin[level] = (unpackd->inodesin[level + 1] +
+ unpackd->symbolsin[level + 1]) / 2;
+ } else
+ unpackd->inodesin[level] = 0;
+}
+
+/*
+ * Update counter for accepted bytes
+ */
+static void
+accepted_bytes(off_t *bytes_in, off_t newbytes)
+{
+
+ if (bytes_in != NULL)
+ (*bytes_in) += newbytes;
+}
+
+/*
+ * Read file header and construct the tree. Also, prepare the buffered I/O
+ * for decode routine.
+ *
+ * Return value is uncompressed size.
+ */
+static void
+unpack_parse_header(int in, int out, char *pre, size_t prelen, off_t *bytes_in,
+ unpack_descriptor_t *unpackd)
+{
+ unsigned char hdr[PACK_HEADER_LENGTH]; /* buffer for header */
+ ssize_t bytesread; /* Bytes read from the file */
+ int i, j, thisbyte;
+
+ /* Prepend the header buffer if we already read some data */
+ if (prelen != 0)
+ memcpy(hdr, pre, prelen);
+
+ /* Read in and fill the rest bytes of header */
+ bytesread = read(in, hdr + prelen, PACK_HEADER_LENGTH - prelen);
+ if (bytesread < 0)
+ maybe_err("Error reading pack header");
+
+ accepted_bytes(bytes_in, PACK_HEADER_LENGTH);
+
+ /* Obtain uncompressed length (bytes 2,3,4,5)*/
+ unpackd->uncompressed_size = 0;
+ for (i = 2; i <= 5; i++) {
+ unpackd->uncompressed_size <<= 8;
+ unpackd->uncompressed_size |= hdr[i];
+ }
+
+ /* Get the levels of the tree */
+ unpackd->treelevels = hdr[6];
+ if (unpackd->treelevels > HTREE_MAXLEVEL || unpackd->treelevels < 1)
+ maybe_errx("Huffman tree has insane levels");
+
+ /* Let libc take care for buffering from now on */
+ if ((unpackd->fpIn = fdopen(in, "r")) == NULL)
+ maybe_err("Can not fdopen() input stream");
+ if ((unpackd->fpOut = fdopen(out, "w")) == NULL)
+ maybe_err("Can not fdopen() output stream");
+
+ /* Allocate for the tables of bounds and the tree itself */
+ unpackd->inodesin =
+ calloc(unpackd->treelevels, sizeof(*(unpackd->inodesin)));
+ unpackd->symbolsin =
+ calloc(unpackd->treelevels, sizeof(*(unpackd->symbolsin)));
+ unpackd->tree =
+ calloc(unpackd->treelevels, (sizeof (*(unpackd->tree))));
+ if (unpackd->inodesin == NULL || unpackd->symbolsin == NULL ||
+ unpackd->tree == NULL)
+ maybe_err("calloc");
+
+ /* We count from 0 so adjust to match array upper bound */
+ unpackd->treelevels--;
+
+ /* Read the levels symbol count table and calculate total */
+ unpackd->symbol_size = 1; /* EOB */
+ for (i = 0; i <= unpackd->treelevels; i++) {
+ if ((thisbyte = fgetc(unpackd->fpIn)) == EOF)
+ maybe_err("File appears to be truncated");
+ unpackd->symbolsin[i] = (unsigned char)thisbyte;
+ unpackd->symbol_size += unpackd->symbolsin[i];
+ }
+ accepted_bytes(bytes_in, unpackd->treelevels);
+ if (unpackd->symbol_size > 256)
+ maybe_errx("Bad symbol table");
+
+ /* Allocate for the symbol table, point symbol_eob at the beginning */
+ unpackd->symbol_eob = unpackd->symbol = calloc(1, unpackd->symbol_size);
+ if (unpackd->symbol == NULL)
+ maybe_err("calloc");
+
+ /*
+ * Read in the symbol table, which contain [2, 256] symbols.
+ * In order to fit the count in one byte, pack(1) would offset
+ * it by reducing 2 from the actual number from the last level.
+ *
+ * We adjust the last level's symbol count by 1 here, because
+ * the EOB symbol is not being transmitted explicitly. Another
+ * adjustment would be done later afterward.
+ */
+ unpackd->symbolsin[unpackd->treelevels]++;
+ for (i = 0; i <= unpackd->treelevels; i++) {
+ unpackd->tree[i] = unpackd->symbol_eob;
+ for (j = 0; j < unpackd->symbolsin[i]; j++) {
+ if ((thisbyte = fgetc(unpackd->fpIn)) == EOF)
+ maybe_errx("Symbol table truncated");
+ *unpackd->symbol_eob++ = (char)thisbyte;
+ }
+ accepted_bytes(bytes_in, unpackd->symbolsin[i]);
+ }
+
+ /* Now, take account for the EOB symbol as well */
+ unpackd->symbolsin[unpackd->treelevels]++;
+
+ /*
+ * The symbolsin table has been constructed now.
+ * Calculate the internal nodes count table based on it.
+ */
+ unpackd_fill_inodesin(unpackd, 0);
+}
+
+/*
+ * Decode huffman stream, based on the huffman tree.
+ */
+static void
+unpack_decode(const unpack_descriptor_t *unpackd, off_t *bytes_in)
+{
+ int thislevel, thiscode, thisbyte, inlevelindex;
+ int i;
+ off_t bytes_out = 0;
+ const char *thissymbol; /* The symbol pointer decoded from stream */
+
+ /*
+ * Decode huffman. Fetch every bytes from the file, get it
+ * into 'thiscode' bit-by-bit, then output the symbol we got
+ * when one has been found.
+ *
+ * Assumption: sizeof(int) > ((max tree levels + 1) / 8).
+ * bad things could happen if not.
+ */
+ thislevel = 0;
+ thiscode = thisbyte = 0;
+
+ while ((thisbyte = fgetc(unpackd->fpIn)) != EOF) {
+ accepted_bytes(bytes_in, 1);
+
+ /*
+ * Split one bit from thisbyte, from highest to lowest,
+ * feed the bit into thiscode, until we got a symbol from
+ * the tree.
+ */
+ for (i = 7; i >= 0; i--) {
+ thiscode = (thiscode << 1) | ((thisbyte >> i) & 1);
+
+ /* Did we got a symbol? (referencing leaf node) */
+ if (thiscode >= unpackd->inodesin[thislevel]) {
+ inlevelindex =
+ thiscode - unpackd->inodesin[thislevel];
+ if (inlevelindex > unpackd->symbolsin[thislevel])
+ maybe_errx("File corrupt");
+
+ thissymbol =
+ &(unpackd->tree[thislevel][inlevelindex]);
+ if ((thissymbol == unpackd->symbol_eob) &&
+ (bytes_out == unpackd->uncompressed_size))
+ goto finished;
+
+ fputc((*thissymbol), unpackd->fpOut);
+ bytes_out++;
+
+ /* Prepare for next input */
+ thislevel = 0; thiscode = 0;
+ } else {
+ thislevel++;
+ if (thislevel > unpackd->treelevels)
+ maybe_errx("File corrupt");
+ }
+ }
+ }
+
+finished:
+ if (bytes_out != unpackd->uncompressed_size)
+ maybe_errx("Premature EOF");
+}
+
+/* Handler for pack(1)'ed file */
+static off_t
+unpack(int in, int out, char *pre, size_t prelen, off_t *bytes_in)
+{
+ unpack_descriptor_t unpackd;
+
+ in = dup(in);
+ if (in == -1)
+ maybe_err("dup");
+ out = dup(out);
+ if (out == -1)
+ maybe_err("dup");
+
+ unpack_parse_header(in, out, pre, prelen, bytes_in, &unpackd);
+ unpack_decode(&unpackd, bytes_in);
+ unpack_descriptor_fini(&unpackd);
+
+ /* If we reached here, the unpack was successful */
+ return (unpackd.uncompressed_size);
+}
+
diff --git a/file_cmds/gzip/unxz.c b/file_cmds/gzip/unxz.c
new file mode 100644
index 0000000..df48ae3
--- /dev/null
+++ b/file_cmds/gzip/unxz.c
@@ -0,0 +1,153 @@
+/* $NetBSD: unxz.c,v 1.5 2011/09/30 01:32:21 christos Exp $ */
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/gzip/unxz.c,v 1.2 2011/10/16 07:35:26 delphij Exp $");
+
+#include <stdarg.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <lzma.h>
+
+static off_t
+unxz(int i, int o, char *pre, size_t prelen, off_t *bytes_in)
+{
+ lzma_stream strm = LZMA_STREAM_INIT;
+ static const int flags = LZMA_TELL_UNSUPPORTED_CHECK|LZMA_CONCATENATED;
+ lzma_ret ret;
+ lzma_action action = LZMA_RUN;
+ off_t bytes_out, bp;
+ uint8_t ibuf[BUFSIZ];
+ uint8_t obuf[BUFSIZ];
+
+ if (bytes_in == NULL)
+ bytes_in = &bp;
+
+ strm.next_in = ibuf;
+ memcpy(ibuf, pre, prelen);
+ strm.avail_in = read(i, ibuf + prelen, sizeof(ibuf) - prelen);
+ if (strm.avail_in == (size_t)-1)
+ maybe_err("read failed");
+ strm.avail_in += prelen;
+ *bytes_in = strm.avail_in;
+
+ if ((ret = lzma_stream_decoder(&strm, UINT64_MAX, flags)) != LZMA_OK)
+ maybe_errx("Can't initialize decoder (%d)", ret);
+
+ strm.next_out = NULL;
+ strm.avail_out = 0;
+ if ((ret = lzma_code(&strm, LZMA_RUN)) != LZMA_OK)
+ maybe_errx("Can't read headers (%d)", ret);
+
+ bytes_out = 0;
+ strm.next_out = obuf;
+ strm.avail_out = sizeof(obuf);
+
+ for (;;) {
+ if (strm.avail_in == 0) {
+ strm.next_in = ibuf;
+ strm.avail_in = read(i, ibuf, sizeof(ibuf));
+ switch (strm.avail_in) {
+ case (size_t)-1:
+ maybe_err("read failed");
+ /*NOTREACHED*/
+ case 0:
+ action = LZMA_FINISH;
+ break;
+ default:
+ *bytes_in += strm.avail_in;
+ break;
+ }
+ }
+
+ ret = lzma_code(&strm, action);
+
+ // Write and check write error before checking decoder error.
+ // This way as much data as possible gets written to output
+ // even if decoder detected an error.
+ if (strm.avail_out == 0 || ret != LZMA_OK) {
+ const size_t write_size = sizeof(obuf) - strm.avail_out;
+
+ if (write(o, obuf, write_size) != (ssize_t)write_size)
+ maybe_err("write failed");
+
+ strm.next_out = obuf;
+ strm.avail_out = sizeof(obuf);
+ bytes_out += write_size;
+ }
+
+ if (ret != LZMA_OK) {
+ if (ret == LZMA_STREAM_END) {
+ // Check that there's no trailing garbage.
+ if (strm.avail_in != 0 || read(i, ibuf, 1))
+ ret = LZMA_DATA_ERROR;
+ else {
+ lzma_end(&strm);
+ return bytes_out;
+ }
+ }
+
+ const char *msg;
+ switch (ret) {
+ case LZMA_MEM_ERROR:
+ msg = strerror(ENOMEM);
+ break;
+
+ case LZMA_FORMAT_ERROR:
+ msg = "File format not recognized";
+ break;
+
+ case LZMA_OPTIONS_ERROR:
+ // FIXME: Better message?
+ msg = "Unsupported compression options";
+ break;
+
+ case LZMA_DATA_ERROR:
+ msg = "File is corrupt";
+ break;
+
+ case LZMA_BUF_ERROR:
+ msg = "Unexpected end of input";
+ break;
+
+ case LZMA_MEMLIMIT_ERROR:
+ msg = "Reached memory limit";
+ break;
+
+ default:
+ maybe_errx("Unknown error (%d)", ret);
+ break;
+ }
+ maybe_errx("%s", msg);
+
+ }
+ }
+}
diff --git a/file_cmds/gzip/zdiff b/file_cmds/gzip/zdiff
new file mode 100644
index 0000000..87863c0
--- /dev/null
+++ b/file_cmds/gzip/zdiff
@@ -0,0 +1,142 @@
+#!/bin/sh -
+#
+# $NetBSD: zdiff,v 1.5 2010/04/14 20:30:28 joerg Exp $
+#
+# $OpenBSD: zdiff,v 1.2 2003/07/29 07:42:44 otto Exp $
+#
+#-
+# Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+# Copyright (c) 2010 Joerg Sonnenberger <joerg@NetBSD.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Sponsored in part by the Defense Advanced Research Projects
+# Agency (DARPA) and Air Force Research Laboratory, Air Force
+# Materiel Command, USAF, under agreement number F39502-99-1-0512.
+#
+# $FreeBSD: src/usr.bin/gzip/zdiff,v 1.2 2011/05/23 09:02:44 delphij Exp $
+
+# Set $prog based on $0
+case $0 in
+ *cmp) prog=cmp
+ ;;
+ *) prog=diff
+ ;;
+esac
+USAGE="usage: $0 [options] file1 [file2]"
+
+check_suffix() {
+ case "$1" in
+ *[._-][Zz])
+ setvar $2 "${1%??}"
+ setvar $3 "gzip -cdqf"
+ ;;
+ *[._-]bz)
+ setvar $2 "${1%???}"
+ setvar $3 "bzip2 -cdqf"
+ ;;
+ *[._-]gz)
+ setvar $2 "${1%???}"
+ setvar $3 "gzip -cdqf"
+ ;;
+ *[._-]xz)
+ setvar $2 "${1%???}"
+ setvar $3 "xz -cdqf"
+ ;;
+ *[._-]bz2)
+ setvar $2 "${1%????}"
+ setvar $3 "bzip2 -cdqf"
+ ;;
+ *[._-]lzma)
+ setvar $2 "${1%?????}"
+ setvar $3 "xz -cdqf"
+ ;;
+ *.t[ag]z)
+ setvar $2 "${1%??}"ar
+ setvar $3 "gzip -cdqf"
+ ;;
+ *.tbz)
+ setvar $2 "${1%??}"ar
+ setvar $3 "bzip2 -cdqf"
+ ;;
+ *.tbz2)
+ setvar $2 "${1%???}"ar
+ setvar $3 "bzip2 -cdqf"
+ ;;
+ *.t[lx]z)
+ setvar $2 "${1%??}"ar
+ setvar $3 "xz -cdqf"
+ ;;
+ *)
+ setvar $2 "$1"
+ setvar $3 ""
+ ;;
+ esac
+}
+
+
+# Pull out any command line flags so we can pass them to diff/cmp
+# XXX - assumes there is no optarg
+flags=
+while test $# -ne 0; do
+ case "$1" in
+ --)
+ shift
+ break
+ ;;
+ -)
+ break
+ ;;
+ -*)
+ flags="$flags $1"
+ shift
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+if [ $# -eq 1 ]; then
+ # One file given, compare compressed to uncompressed
+ files="$1"
+ check_suffix "$1" files filt
+ if [ -z "$filt" ]; then
+ echo "z$prog: unknown suffix" 1>&2
+ exit 1
+ fi
+ $filt -- "$1" | $prog $flags -- - "$files"
+ status=$?
+elif [ $# -eq 2 ]; then
+ # Two files given, compare the two uncompressing as needed
+ check_suffix "$1" files filt
+ check_suffix "$2" files2 filt2
+ if [ -z "$filt" -a -z "$filt2" ]; then
+ $prog $flags -- "$1" "$2"
+ elif [ -z "$filt" -a -n "$filt2" -a "$1" != "-" ]; then
+ $filt2 -- "$2" | $prog $flags -- "$1" -
+ elif [ -n "$filt" -a -z "$filt2" -a "$2" != "-" ]; then
+ $filt -- "$1" | $prog $flags -- - "$2"
+ else
+ tmp=`mktemp -t z$prog.XXXXXXXXXX` || exit 1
+ trap "rm -f $tmp" 0 1 2 3 13 15
+ ${filt2:-cat} -- "$2" > $tmp || exit $?
+ ${filt:-cat} -- "$1" | $prog $flags -- - "$tmp"
+ fi
+ status=$?
+else
+ echo "$USAGE" 1>&2
+ exit 1
+fi
+
+exit $status
diff --git a/file_cmds/gzip/zdiff.1 b/file_cmds/gzip/zdiff.1
new file mode 100644
index 0000000..2e0ebea
--- /dev/null
+++ b/file_cmds/gzip/zdiff.1
@@ -0,0 +1,142 @@
+.\" $NetBSD: zdiff.1,v 1.5 2010/04/14 19:52:05 wiz Exp $
+.\" $OpenBSD: zdiff.1,v 1.2 2003/07/13 17:39:14 millert Exp $
+.\"
+.\" Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+.\" Copyright (c) 2010 Joerg Sonnenberger <joerg@NetBSD.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.\" $FreeBSD: src/usr.bin/gzip/zdiff.1,v 1.2 2011/05/23 09:02:44 delphij Exp $
+.Dd May 23, 2011
+.Dt ZDIFF 1
+.Os
+.Sh NAME
+.Nm zcmp ,
+.Nm zdiff
+.Nd compare compressed files
+.Sh SYNOPSIS
+.Nm zcmp
+.Op Ar options
+.Ar file
+.Op Ar file2
+.Nm zdiff
+.Op Ar options
+.Ar file
+.Op Ar file2
+.Sh DESCRIPTION
+.Nm zcmp
+and
+.Nm zdiff
+are filters that invoke
+.Xr cmp 1
+or
+.Xr diff 1
+respectively to compare compressed files.
+Any
+.Ar options
+that are specified are passed to
+.Xr cmp 1
+or
+.Xr diff 1 .
+.Pp
+If only
+.Ar file1
+is specified, it is compared against a file with the same name, but
+with the extension removed.
+When both
+.Ar file1
+or
+.Ar file2
+are specified, either file may be compressed.
+.Pp
+Extensions handled by
+.Xr gzip 1 :
+.Bl -bullet -compact
+.It
+z, Z,
+.It
+gz,
+.It
+taz,
+.It
+tgz.
+.El
+.Pp
+Extensions handled by
+.Xr bzip2 1 :
+.Bl -bullet -compact
+.It
+bz,
+.It
+bz2,
+.It
+tbz,
+.It
+tbz2.
+.El
+.Pp
+Extensions handled by
+.Xr xz 1 :
+.Bl -bullet -compact
+.It
+lzma,
+.It
+xz,
+.It
+tlz,
+.It
+txz.
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width "TMPDIR"
+.It Ev TMPDIR
+Directory in which to place temporary files.
+If unset,
+.Pa /tmp
+is used.
+.El
+.Sh FILES
+.Bl -tag -width "/tmp/zdiff.XXXXXXXXXX" -compact
+.It Pa /tmp/zcmp.XXXXXXXXXX
+Temporary file for
+.Nm zcmp .
+.It Pa /tmp/zdiff.XXXXXXXXXX
+Temporary file for
+.Nm zdiff .
+.El
+.Sh SEE ALSO
+.Xr bzip2 1 ,
+.Xr cmp 1 ,
+.Xr diff 1 ,
+.Xr gzip 1 ,
+.Xr xz 1
+.Sh CAVEATS
+.Nm zcmp
+and
+.Nm zdiff
+rely solely on the file extension to determine what is, or is not,
+a compressed file.
+Consequently, the following are not supported as arguments:
+.Bl -dash
+.It
+directories
+.It
+device special files
+.It
+filenames indicating the standard input
+.Pq Dq \-
+.El
diff --git a/file_cmds/gzip/zforce b/file_cmds/gzip/zforce
new file mode 100644
index 0000000..243cbdf
--- /dev/null
+++ b/file_cmds/gzip/zforce
@@ -0,0 +1,55 @@
+#!/bin/sh -
+#
+# $NetBSD: zforce,v 1.2 2003/12/28 12:43:43 wiz Exp $
+# $OpenBSD: zforce,v 1.2 2003/08/05 18:22:17 deraadt Exp $
+#
+#-
+# Copyright (c) 2003 Otto Moerbeek <otto@drijf.net>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# $FreeBSD: src/usr.bin/gzip/zforce,v 1.1 2007/01/26 10:19:07 delphij Exp $
+prog=`basename $0`
+USAGE="usage: $prog file ..."
+if test $# -eq 0; then
+ echo $USAGE
+ exit 1
+fi
+
+ret=0
+
+while test $# -ne 0; do
+ case "$1" in
+ *[._-]gz)
+ shift
+ ;;
+ *.t[ag]z)
+ shift
+ ;;
+ *)
+ if file "$1" |
+ grep -q "gzip compressed data" 2> /dev/null
+ then
+ n="$1".gz
+ if mv "$1" "$n" 2> /dev/null; then
+ echo "$1" -- renamed to "$n"
+ else
+ ret=1
+ echo $prog: cannot rename "$1" to "$n"
+ fi
+ fi
+ shift
+ ;;
+ esac
+done
+exit $ret
diff --git a/file_cmds/gzip/zforce.1 b/file_cmds/gzip/zforce.1
new file mode 100644
index 0000000..933d681
--- /dev/null
+++ b/file_cmds/gzip/zforce.1
@@ -0,0 +1,53 @@
+.\" $NetBSD: zforce.1,v 1.2 2003/12/28 12:43:43 wiz Exp $
+.\" $OpenBSD: zforce.1,v 1.1 2003/07/29 11:50:09 otto Exp $
+.\"
+.\" Copyright (c) 2003 Otto Moerbeek <otto@drijf.net>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD: src/usr.bin/gzip/zforce.1,v 1.1 2007/01/26 10:19:07 delphij Exp $
+.Dd January 26, 2007
+.Dt ZFORCE 1
+.Os
+.Sh NAME
+.Nm zforce
+.Nd force gzip files to have a .gz suffix
+.Sh SYNOPSIS
+.Nm zforce
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility renames
+.Xr gzip 1
+files to have a
+.Sq .gz
+suffix, so that
+.Xr gzip 1
+will not compress them twice.
+This can be useful if file names were truncated during a file transfer.
+Files that have an existing
+.Sq .gz ,
+.Sq -gz ,
+.Sq _gz ,
+.Sq .tgz
+or
+.Sq .taz
+suffix, or that have not been compressed by
+.Xr gzip 1 ,
+are ignored.
+.Sh SEE ALSO
+.Xr gzip 1
+.Sh CAVEATS
+.Nm
+overwrites existing files without warning.
diff --git a/file_cmds/gzip/zmore b/file_cmds/gzip/zmore
new file mode 100644
index 0000000..dbdbd3f
--- /dev/null
+++ b/file_cmds/gzip/zmore
@@ -0,0 +1,82 @@
+#!/bin/sh -
+#
+# $NetBSD: zmore,v 1.5 2013/12/06 13:33:15 pettai Exp $
+#
+# $OpenBSD: zmore,v 1.6 2008/08/20 09:22:02 mpf Exp $
+#
+#-
+# Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# Sponsored in part by the Defense Advanced Research Projects
+# Agency (DARPA) and Air Force Research Laboratory, Air Force
+# Materiel Command, USAF, under agreement number F39502-99-1-0512.
+#
+# $FreeBSD: head/usr.bin/gzip/zmore 273507 2014-10-23 01:22:29Z delphij $
+
+# Pull out any command line flags so we can pass them to more/less
+flags=
+while test $# -ne 0; do
+ case "$1" in
+ --)
+ shift
+ break
+ ;;
+ -*)
+ flags="$flags $1"
+ shift
+ ;;
+ *)
+ break
+ ;;
+ esac
+done
+
+if [ `basename $0` = "zless" ] ; then
+ pager=${PAGER-less}
+else
+ pager=${PAGER-more}
+fi
+
+# No files means read from stdin
+if [ $# -eq 0 ]; then
+ gzip -cdfq 2>&1 | $pager $flags
+ exit 0
+fi
+
+oterm=`stty -g 2>/dev/null`
+while test $# -ne 0; do
+ gzip -cdfq "$1" 2>&1 | $pager $flags
+ prev="$1"
+ shift
+ if tty -s && test -n "$oterm" -a $# -gt 0; then
+ #echo -n "--More--(Next file: $1)"
+ echo -n "$prev (END) - Next: $1 "
+ trap "stty $oterm 2>/dev/null" 0 1 2 3 13 15
+ stty cbreak -echo 2>/dev/null
+ REPLY=`dd bs=1 count=1 2>/dev/null`
+ stty $oterm 2>/dev/null
+ trap - 0 1 2 3 13 15
+ echo
+ case "$REPLY" in
+ s)
+ shift
+ ;;
+ e|q)
+ break
+ ;;
+ esac
+ fi
+done
+exit 0
diff --git a/file_cmds/gzip/zmore.1 b/file_cmds/gzip/zmore.1
new file mode 100644
index 0000000..4723f22
--- /dev/null
+++ b/file_cmds/gzip/zmore.1
@@ -0,0 +1,110 @@
+.\" $NetBSD: zmore.1,v 1.4 2013/11/12 21:58:37 pettai Exp $
+.\" $OpenBSD: zmore.1,v 1.10 2009/08/16 09:41:08 sobrado Exp $
+.\"
+.\" Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" Sponsored in part by the Defense Advanced Research Projects
+.\" Agency (DARPA) and Air Force Research Laboratory, Air Force
+.\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
+.\"
+.\" $FreeBSD: head/usr.bin/gzip/zmore.1 273507 2014-10-23 01:22:29Z delphij $
+.Dd October 22, 2014
+.Dt ZMORE 1
+.Os
+.Sh NAME
+.Nm zmore ,
+.Nm zless
+.Nd view compressed files
+.Sh SYNOPSIS
+.Nm zmore
+.Op Ar flags
+.Op Ar
+.Nm zless
+.Op Ar flags
+.Op Ar
+.Sh DESCRIPTION
+.Nm
+is a filter that allows the viewing of files compressed with Lempel-Ziv
+encoding.
+Such files generally have a
+.Dq Z
+or
+.Dq gz
+extension (both the
+.Xr compress 1
+and
+.Xr gzip 1
+formats are supported).
+Any
+.Ar flags
+that are specified are passed to the user's preferred
+.Ev PAGER
+(which is
+.Pa /usr/bin/more
+by default).
+.Pp
+.Nm zless
+is equivalent to
+.Nm zmore
+but uses
+.Xr less 1
+as a pager instead of
+.Xr more 1 .
+.Pp
+When multiple files are specified,
+.Nm
+will pause at the end of each file and present the following prompt to the user:
+.Bd -literal -offset indent
+prev_file (END) - Next: next_file
+.Ed
+.Pp
+Where
+.Sy prev_file
+is the file that was just displayed and
+.Sy next_file
+is the next file to be displayed.
+The following keys are recognized at the prompt:
+.Bl -tag -width "e or q" -offset indent
+.It Ic e No or Ic q
+quit
+.Nm zmore .
+.It Ic s
+skip the next file (or exit if the next file is the last).
+.El
+.Pp
+If no files are specified,
+.Nm
+will read from the standard input.
+In this mode
+.Nm
+will assume
+.Xr gzip 1
+style compression since there is no suffix on which to make a decision.
+.Sh ENVIRONMENT
+.Bl -tag -width "PAGER"
+.It Ev PAGER
+Program used to display files.
+If unset,
+.Pa /usr/bin/more
+is used
+.Pq Nm zmore
+or
+.Pa /usr/bin/less
+.Pq Nm zless .
+.El
+.Sh SEE ALSO
+.Xr compress 1 ,
+.Xr less 1 ,
+.Xr more 1
diff --git a/file_cmds/gzip/znew b/file_cmds/gzip/znew
new file mode 100644
index 0000000..4a84f58
--- /dev/null
+++ b/file_cmds/gzip/znew
@@ -0,0 +1,137 @@
+#!/bin/sh -
+#
+# $NetBSD: znew,v 1.3 2008/04/27 09:07:13 nakayama Exp $
+# $OpenBSD: znew,v 1.2 2003/08/05 18:22:17 deraadt Exp $
+#
+#-
+# Copyright (c) 2003 Otto Moerbeek <otto@drijf.net>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+# $FreeBSD: src/usr.bin/gzip/znew,v 1.3 2008/06/30 23:53:15 delphij Exp $
+
+# Return 0 if the first arg file size is smaller than the second, 1 otherwise.
+smaller () {
+ a=`du -k "$1" | awk '{ print $1 }'`
+ b=`du -k "$2" | awk '{ print $1 }'`
+ test $a -lt $b
+}
+
+# Check gzip integrity if the -t flag is specified
+checkfile () {
+ if test $tflag -eq 1; then
+ gzip -qt < "$1"
+ fi
+}
+
+# Decompress a file and then gzip it
+process () {
+ prefix="${1%.Z}"
+ filez="$prefix".Z
+ filegz="$prefix".gz
+
+ if test ! -e "$filez"; then
+ echo "$prog: $filez does not exist"
+ return 1
+ fi
+ if test ! -f "$filez"; then
+ echo "$prog: $filez is not a regular file"
+ return 1
+ fi
+ if test -e "$filegz" -a $fflag -eq 0; then
+ echo "$prog: $filegz already exists"
+ return 1
+ fi
+
+ tmp=`mktemp /tmp/znewXXXXXXXXXX` || {
+ echo "$prog: cannot create tmp file"
+ return 1
+ }
+ trap 'rm -f "$tmp"; exit 1' HUP INT QUIT PIPE TERM
+
+ # Do the actual work, producing a file "$tmp"
+ if uncompress -f -c < "$filez" | gzip -f -c $gzipflags > "$tmp"; then
+ if test $kflag -eq 1 && smaller "$filez" "$tmp"; then
+ echo -n "$prog: $filez is smaller than $filegz"
+ echo "; keeping it"
+ rm -f "$tmp"
+ return 0
+ fi
+ if ! checkfile "$tmp"; then
+ echo "$prog: integrity check of $tmp failed"
+ rm -f "$tmp"
+ return 1;
+ fi
+
+ # Try to keep the mode of the original file
+ if ! cp -fp "$filez" "$filegz"; then
+ echo "$prog: warning: could not keep mode of $filez"
+ fi
+ if ! cp "$tmp" "$filegz" 2> /dev/null; then
+ echo "$prog: warning: could not keep mode of $filez"
+ if ! cp -f "$tmp" "$filegz" 2> /dev/null; then
+ echo "$prog: could not copy $tmp to $filegz"
+ rm -f "$filegz" "$tmp"
+ return 1
+ fi
+ fi
+ if ! touch -fr "$filez" "$filegz"; then
+ echo -n "$prog: warning: could not keep timestamp of "
+ echo "$filez"
+ fi
+ rm -f "$filez" "$tmp"
+ else
+ echo "$prog: failed to process $filez"
+ rm -f "$tmp"
+ return 1
+ fi
+}
+
+prog=`basename "$0"`
+usage="usage: $prog [-ftv9K] file ..."
+
+fflag=0
+tflag=0
+kflag=0
+gzipflags=
+
+# -P flag is recognized to maintain compatibility, but ignored. Pipe mode is
+# always used
+while getopts :ftv9PK i; do
+ case $i in
+ f) fflag=1;;
+ t) tflag=1;;
+ v) gzipflags="-v $gzipflags";;
+ 9) gzipflags="-9 $gzipflags";;
+ P) ;;
+ K) kflag=1;;
+ \?) echo "$usage"; exit 1;;
+ esac
+done
+
+shift $((OPTIND - 1))
+
+if test $# -eq 0; then
+ echo "$usage"
+ exit 1
+fi
+
+rc=0
+
+while test $# -ne 0; do
+ if ! process "$1"; then
+ rc=$?
+ fi
+ shift
+done
+exit $rc
diff --git a/file_cmds/gzip/znew.1 b/file_cmds/gzip/znew.1
new file mode 100644
index 0000000..61060ca
--- /dev/null
+++ b/file_cmds/gzip/znew.1
@@ -0,0 +1,71 @@
+.\" $NetBSD: znew.1,v 1.2 2003/12/28 12:43:43 wiz Exp $
+.\" $OpenBSD: znew.1,v 1.1 2003/08/02 20:52:50 otto Exp $
+.\"
+.\" Copyright (c) 2003 Otto Moerbeek <otto@drijf.net>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD: src/usr.bin/gzip/znew.1,v 1.1 2007/01/26 10:19:07 delphij Exp $
+.Dd January 26, 2007
+.Dt ZNEW 1
+.Os
+.Sh NAME
+.Nm znew
+.Nd convert compressed files to gzipped files
+.Sh SYNOPSIS
+.Nm
+.Op Fl ftv9K
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility uncompresses files compressed by
+.Xr compress 1
+and recompresses them with
+.Xr gzip 1 .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f
+Overwrite existing
+.Sq .gz
+files.
+Unless this option is specified,
+.Nm
+refuses to overwrite existing files.
+.It Fl t
+Test integrity of the gzipped file before deleting the original file.
+If the integrity check fails, the original
+.Sq .Z
+file is not removed.
+.It Fl v
+Print a report specifying the achieved compression ratios.
+.It Fl 9
+Use the -9 mode of
+.Xr gzip 1 ,
+achieving better compression at the cost of slower execution.
+.It Fl K
+Keep the original
+.Sq .Z
+file if it uses less disk blocks than the gzipped one.
+A disk block is 1024 bytes.
+.El
+.Sh SEE ALSO
+.Xr gzip 1
+.Sh CAVEATS
+The
+.Nm
+utility tries to maintain the file mode of the original file.
+If the original file is not writable, it is not able to do that and
+.Nm
+will print a warning.
diff --git a/file_cmds/gzip/zuncompress.c b/file_cmds/gzip/zuncompress.c
new file mode 100644
index 0000000..06df597
--- /dev/null
+++ b/file_cmds/gzip/zuncompress.c
@@ -0,0 +1,396 @@
+/* $NetBSD: zuncompress.c,v 1.11 2011/08/16 13:55:02 joerg Exp $ */
+
+/*-
+ * Copyright (c) 1985, 1986, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis and James A. Woods, derived from original
+ * work by Spencer Thomas and Joseph Orost.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: NetBSD: zopen.c,v 1.8 2003/08/07 11:13:29 agc Exp
+ * $FreeBSD: src/usr.bin/gzip/zuncompress.c,v 1.7 2012/10/19 14:49:42 ed Exp $
+ */
+
+/* This file is #included by gzip.c */
+
+static int zread(void *, char *, int);
+
+#define tab_prefixof(i) (zs->zs_codetab[i])
+#define tab_suffixof(i) ((char_type *)(zs->zs_htab))[i]
+#define de_stack ((char_type *)&tab_suffixof(1 << BITS))
+
+#define BITS 16 /* Default bits. */
+#define HSIZE 69001 /* 95% occupancy */ /* XXX may not need HSIZE */
+#define BIT_MASK 0x1f /* Defines for third byte of header. */
+#define BLOCK_MASK 0x80
+#define CHECK_GAP 10000 /* Ratio check interval. */
+#define BUFSIZE (64 * 1024)
+
+/*
+ * Masks 0x40 and 0x20 are free. I think 0x20 should mean that there is
+ * a fourth header byte (for expansion).
+ */
+#define INIT_BITS 9 /* Initial number of bits/code. */
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define FIRST 257 /* First free entry. */
+#define CLEAR 256 /* Table clear output code. */
+
+
+#define MAXCODE(n_bits) ((1 << (n_bits)) - 1)
+
+typedef long code_int;
+typedef long count_int;
+typedef u_char char_type;
+
+static char_type magic_header[] =
+ {'\037', '\235'}; /* 1F 9D */
+
+static char_type rmask[9] =
+ {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff};
+
+static off_t total_compressed_bytes;
+static size_t compressed_prelen;
+static char *compressed_pre;
+
+struct s_zstate {
+ FILE *zs_fp; /* File stream for I/O */
+ char zs_mode; /* r or w */
+ enum {
+ S_START, S_MIDDLE, S_EOF
+ } zs_state; /* State of computation */
+ int zs_n_bits; /* Number of bits/code. */
+ int zs_maxbits; /* User settable max # bits/code. */
+ code_int zs_maxcode; /* Maximum code, given n_bits. */
+ code_int zs_maxmaxcode; /* Should NEVER generate this code. */
+ count_int zs_htab [HSIZE];
+ u_short zs_codetab [HSIZE];
+ code_int zs_hsize; /* For dynamic table sizing. */
+ code_int zs_free_ent; /* First unused entry. */
+ /*
+ * Block compression parameters -- after all codes are used up,
+ * and compression rate changes, start over.
+ */
+ int zs_block_compress;
+ int zs_clear_flg;
+ long zs_ratio;
+ count_int zs_checkpoint;
+ int zs_offset;
+ long zs_in_count; /* Length of input. */
+ long zs_bytes_out; /* Length of compressed output. */
+ long zs_out_count; /* # of codes output (for debugging). */
+ char_type zs_buf[BITS];
+ union {
+ struct {
+ long zs_fcode;
+ code_int zs_ent;
+ code_int zs_hsize_reg;
+ int zs_hshift;
+ } w; /* Write parameters */
+ struct {
+ char_type *zs_stackp;
+ int zs_finchar;
+ code_int zs_code, zs_oldcode, zs_incode;
+ int zs_roffset, zs_size;
+ char_type zs_gbuf[BITS];
+ } r; /* Read parameters */
+ } u;
+};
+
+static code_int getcode(struct s_zstate *zs);
+
+static off_t
+zuncompress(FILE *in, FILE *out, char *pre, size_t prelen,
+ off_t *compressed_bytes)
+{
+ off_t bin, bout = 0;
+ char *buf;
+
+ buf = malloc(BUFSIZE);
+ if (buf == NULL)
+ return -1;
+
+ /* XXX */
+ compressed_prelen = prelen;
+ if (prelen != 0)
+ compressed_pre = pre;
+ else
+ compressed_pre = NULL;
+
+ while ((bin = fread(buf, 1, BUFSIZE, in)) != 0) {
+ if (tflag == 0 && (off_t)fwrite(buf, 1, bin, out) != bin) {
+ free(buf);
+ return -1;
+ }
+ bout += bin;
+ }
+
+ if (compressed_bytes)
+ *compressed_bytes = total_compressed_bytes;
+
+ free(buf);
+ return bout;
+}
+
+static int
+zclose(void *zs)
+{
+ free(zs);
+ /* We leave the caller to close the fd passed to zdopen() */
+ return 0;
+}
+
+FILE *
+zdopen(int fd)
+{
+ struct s_zstate *zs;
+
+ if ((zs = calloc(1, sizeof(struct s_zstate))) == NULL)
+ return (NULL);
+
+ zs->zs_state = S_START;
+
+ /* XXX we can get rid of some of these */
+ zs->zs_hsize = HSIZE; /* For dynamic table sizing. */
+ zs->zs_free_ent = 0; /* First unused entry. */
+ zs->zs_block_compress = BLOCK_MASK;
+ zs->zs_clear_flg = 0; /* XXX we calloc()'d this structure why = 0? */
+ zs->zs_ratio = 0;
+ zs->zs_checkpoint = CHECK_GAP;
+ zs->zs_in_count = 1; /* Length of input. */
+ zs->zs_out_count = 0; /* # of codes output (for debugging). */
+ zs->u.r.zs_roffset = 0;
+ zs->u.r.zs_size = 0;
+
+ /*
+ * Layering compress on top of stdio in order to provide buffering,
+ * and ensure that reads and write work with the data specified.
+ */
+ if ((zs->zs_fp = fdopen(fd, "r")) == NULL) {
+ free(zs);
+ return NULL;
+ }
+
+ return funopen(zs, zread, NULL, NULL, zclose);
+}
+
+/*
+ * Decompress read. This routine adapts to the codes in the file building
+ * the "string" table on-the-fly; requiring no table to be stored in the
+ * compressed file. The tables used herein are shared with those of the
+ * compress() routine. See the definitions above.
+ */
+static int
+zread(void *cookie, char *rbp, int num)
+{
+ u_int count, i;
+ struct s_zstate *zs;
+ u_char *bp, header[3];
+
+ if (num == 0)
+ return (0);
+
+ zs = cookie;
+ count = num;
+ bp = (u_char *)rbp;
+ switch (zs->zs_state) {
+ case S_START:
+ zs->zs_state = S_MIDDLE;
+ break;
+ case S_MIDDLE:
+ goto middle;
+ case S_EOF:
+ goto eof;
+ }
+
+ /* Check the magic number */
+ for (i = 0; i < 3 && compressed_prelen; i++, compressed_prelen--)
+ header[i] = *compressed_pre++;
+
+ if (fread(header + i, 1, sizeof(header) - i, zs->zs_fp) !=
+ sizeof(header) - i ||
+ memcmp(header, magic_header, sizeof(magic_header)) != 0) {
+ errno = EFTYPE;
+ return (-1);
+ }
+ total_compressed_bytes = 0;
+ zs->zs_maxbits = header[2]; /* Set -b from file. */
+ zs->zs_block_compress = zs->zs_maxbits & BLOCK_MASK;
+ zs->zs_maxbits &= BIT_MASK;
+ zs->zs_maxmaxcode = 1L << zs->zs_maxbits;
+ if (zs->zs_maxbits > BITS || zs->zs_maxbits < 12) {
+ errno = EFTYPE;
+ return (-1);
+ }
+ /* As above, initialize the first 256 entries in the table. */
+ zs->zs_maxcode = MAXCODE(zs->zs_n_bits = INIT_BITS);
+ for (zs->u.r.zs_code = 255; zs->u.r.zs_code >= 0; zs->u.r.zs_code--) {
+ tab_prefixof(zs->u.r.zs_code) = 0;
+ tab_suffixof(zs->u.r.zs_code) = (char_type) zs->u.r.zs_code;
+ }
+ zs->zs_free_ent = zs->zs_block_compress ? FIRST : 256;
+
+ zs->u.r.zs_oldcode = -1;
+ zs->u.r.zs_stackp = de_stack;
+
+ while ((zs->u.r.zs_code = getcode(zs)) > -1) {
+
+ if ((zs->u.r.zs_code == CLEAR) && zs->zs_block_compress) {
+ for (zs->u.r.zs_code = 255; zs->u.r.zs_code >= 0;
+ zs->u.r.zs_code--)
+ tab_prefixof(zs->u.r.zs_code) = 0;
+ zs->zs_clear_flg = 1;
+ zs->zs_free_ent = FIRST;
+ zs->u.r.zs_oldcode = -1;
+ continue;
+ }
+ zs->u.r.zs_incode = zs->u.r.zs_code;
+
+ /* Special case for KwKwK string. */
+ if (zs->u.r.zs_code >= zs->zs_free_ent) {
+ if (zs->u.r.zs_code > zs->zs_free_ent ||
+ zs->u.r.zs_oldcode == -1) {
+ /* Bad stream. */
+ errno = EINVAL;
+ return (-1);
+ }
+ *zs->u.r.zs_stackp++ = zs->u.r.zs_finchar;
+ zs->u.r.zs_code = zs->u.r.zs_oldcode;
+ }
+ /*
+ * The above condition ensures that code < free_ent.
+ * The construction of tab_prefixof in turn guarantees that
+ * each iteration decreases code and therefore stack usage is
+ * bound by 1 << BITS - 256.
+ */
+
+ /* Generate output characters in reverse order. */
+ while (zs->u.r.zs_code >= 256) {
+ *zs->u.r.zs_stackp++ = tab_suffixof(zs->u.r.zs_code);
+ zs->u.r.zs_code = tab_prefixof(zs->u.r.zs_code);
+ }
+ *zs->u.r.zs_stackp++ = zs->u.r.zs_finchar = tab_suffixof(zs->u.r.zs_code);
+
+ /* And put them out in forward order. */
+middle: do {
+ if (count-- == 0)
+ return (num);
+ *bp++ = *--zs->u.r.zs_stackp;
+ } while (zs->u.r.zs_stackp > de_stack);
+
+ /* Generate the new entry. */
+ if ((zs->u.r.zs_code = zs->zs_free_ent) < zs->zs_maxmaxcode &&
+ zs->u.r.zs_oldcode != -1) {
+ tab_prefixof(zs->u.r.zs_code) = (u_short) zs->u.r.zs_oldcode;
+ tab_suffixof(zs->u.r.zs_code) = zs->u.r.zs_finchar;
+ zs->zs_free_ent = zs->u.r.zs_code + 1;
+ }
+
+ /* Remember previous code. */
+ zs->u.r.zs_oldcode = zs->u.r.zs_incode;
+ }
+ zs->zs_state = S_EOF;
+eof: return (num - count);
+}
+
+/*-
+ * Read one code from the standard input. If EOF, return -1.
+ * Inputs:
+ * stdin
+ * Outputs:
+ * code or -1 is returned.
+ */
+static code_int
+getcode(struct s_zstate *zs)
+{
+ code_int gcode;
+ int r_off, bits, i;
+ char_type *bp;
+
+ bp = zs->u.r.zs_gbuf;
+ if (zs->zs_clear_flg > 0 || zs->u.r.zs_roffset >= zs->u.r.zs_size ||
+ zs->zs_free_ent > zs->zs_maxcode) {
+ /*
+ * If the next entry will be too big for the current gcode
+ * size, then we must increase the size. This implies reading
+ * a new buffer full, too.
+ */
+ if (zs->zs_free_ent > zs->zs_maxcode) {
+ zs->zs_n_bits++;
+ if (zs->zs_n_bits == zs->zs_maxbits) /* Won't get any bigger now. */
+ zs->zs_maxcode = zs->zs_maxmaxcode;
+ else
+ zs->zs_maxcode = MAXCODE(zs->zs_n_bits);
+ }
+ if (zs->zs_clear_flg > 0) {
+ zs->zs_maxcode = MAXCODE(zs->zs_n_bits = INIT_BITS);
+ zs->zs_clear_flg = 0;
+ }
+ /* XXX */
+ for (i = 0; i < zs->zs_n_bits && compressed_prelen; i++, compressed_prelen--)
+ zs->u.r.zs_gbuf[i] = *compressed_pre++;
+ zs->u.r.zs_size = fread(zs->u.r.zs_gbuf + i, 1, zs->zs_n_bits - i, zs->zs_fp);
+ zs->u.r.zs_size += i;
+ if (zs->u.r.zs_size <= 0) /* End of file. */
+ return (-1);
+ zs->u.r.zs_roffset = 0;
+
+ total_compressed_bytes += zs->u.r.zs_size;
+
+ /* Round size down to integral number of codes. */
+ zs->u.r.zs_size = (zs->u.r.zs_size << 3) - (zs->zs_n_bits - 1);
+ }
+ r_off = zs->u.r.zs_roffset;
+ bits = zs->zs_n_bits;
+
+ /* Get to the first byte. */
+ bp += (r_off >> 3);
+ r_off &= 7;
+
+ /* Get first part (low order bits). */
+ gcode = (*bp++ >> r_off);
+ bits -= (8 - r_off);
+ r_off = 8 - r_off; /* Now, roffset into gcode word. */
+
+ /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */
+ if (bits >= 8) {
+ gcode |= *bp++ << r_off;
+ r_off += 8;
+ bits -= 8;
+ }
+
+ /* High order bits. */
+ gcode |= (*bp & rmask[bits]) << r_off;
+ zs->u.r.zs_roffset += zs->zs_n_bits;
+
+ return (gcode);
+}
+
diff --git a/file_cmds/install/install.1 b/file_cmds/install/install.1
new file mode 100644
index 0000000..76f3697
--- /dev/null
+++ b/file_cmds/install/install.1
@@ -0,0 +1,253 @@
+.\" Copyright (c) 1987, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)install.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/xinstall/install.1,v 1.21 2001/05/30 09:45:47 ru Exp $
+.\"
+.Dd May 7, 2001
+.Dt INSTALL 1
+.Os
+.Sh NAME
+.Nm install
+.Nd install binaries
+.Sh SYNOPSIS
+.Nm install
+.Op Fl bCcMpSsv
+.Op Fl B Ar suffix
+.Op Fl f Ar flags
+.Op Fl g Ar group
+.Op Fl m Ar mode
+.Op Fl o Ar owner
+.Ar file1 file2
+.Nm install
+.Op Fl bCcMpSsv
+.Op Fl B Ar suffix
+.Op Fl f Ar flags
+.Op Fl g Ar group
+.Op Fl m Ar mode
+.Op Fl o Ar owner
+.Ar file1 ... fileN directory
+.Nm install
+.Fl d
+.Op Fl v
+.Op Fl g Ar group
+.Op Fl m Ar mode
+.Op Fl o Ar owner
+.Ar directory ...
+.Sh DESCRIPTION
+The file(s) are copied
+to the target file or directory.
+If the destination is a directory, then the
+.Ar file
+is copied into
+.Ar directory
+with its original filename.
+If the target file already exists, it is
+either renamed to
+.Ar file Ns Pa .old
+if the
+.Fl b
+option is given
+or overwritten
+if permissions allow.
+An alternate backup suffix may be specified via the
+.Fl B
+option's argument.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.\" ==========
+.It Fl B Ar suffix
+Use
+.Ar suffix
+as the backup suffix if
+.Fl b
+is given.
+.\" ==========
+.It Fl b
+Back up any existing files before overwriting them by renaming
+them to
+.Ar file Ns Pa .old .
+See
+.Fl B
+for specifying a different backup suffix.
+.\" ==========
+.It Fl C
+Copy the file.
+If the target file already exists and the files are the same,
+then don't change the modification time of the target.
+.\" ==========
+.It Fl c
+Copy the file.
+This is actually the default.
+The
+.Fl c
+option is only included for backwards compatibility.
+.\" ==========
+.It Fl d
+Create directories.
+Missing parent directories are created as required.
+.\" ==========
+.It Fl f
+Specify the target's file flags; see
+.Xr chflags 1
+for a list of possible flags and their meanings.
+.\" ==========
+.It Fl g
+Specify a group.
+A numeric GID is allowed.
+.\" ==========
+.It Fl M
+Disable all use of
+.Xr mmap 2 .
+.\" ==========
+.It Fl m
+Specify an alternate mode.
+The default mode is set to rwxr-xr-x (0755).
+The specified mode may be either an octal or symbolic value; see
+.Xr chmod 1
+for a description of possible mode values.
+.\" ==========
+.It Fl o
+Specify an owner.
+A numeric UID is allowed.
+.\" ==========
+.It Fl p
+Preserve the modification time.
+Copy the file, as if the
+.Fl C
+(compare and copy) option is specified,
+except if the target file doesn't already exist or is different,
+then preserve the modification time of the file.
+.\" ==========
+.It Fl S
+Safe copy.
+Normally,
+.Nm install
+unlinks an existing target before installing the new file.
+With the
+.Fl S
+flag a temporary file is used and then renamed to be
+the target.
+The reason this is safer is that if the copy or
+rename fails, the existing target is left untouched.
+.\" ==========
+.It Fl s
+.Nm install
+exec's the command
+.Xr strip 1
+to strip binaries so that
+.Nm install
+can be portable over a large
+number of systems and binary types.
+.\" ==========
+.It Fl v
+Causes
+.Nm install
+to show when
+.Fl C
+actually installs something.
+.El
+.Pp
+By default,
+.Nm install
+preserves all file flags, with the exception of the
+.Dq nodump
+flag.
+.Pp
+The
+.Nm install
+utility attempts to prevent moving a file onto itself.
+.Pp
+Installing
+.Pa /dev/null
+creates an empty file.
+.Sh DIAGNOSTICS
+The
+.Nm install
+utility exits 0 on success, and 1 otherwise.
+.Sh FILES
+.Bl -tag -width INS@XXXX -compact
+.It Pa INS@XXXX
+If either
+.Fl S
+option is specified, or the
+.Fl C
+or
+.Fl p
+option is used in conjuction with the
+.Fl s
+option, temporary files named
+.Pa INS@XXXX ,
+where
+.Pa XXXX
+is decided by
+.Xr mkstemp 3 ,
+are created in the target directory.
+.El
+.Sh COMPATIBILITY
+Historically
+.Nm install
+moved files by default.
+The default was changed to copy in
+.Fx 4.4 .
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chgrp 1 ,
+.Xr chmod 1 ,
+.Xr cp 1 ,
+.Xr mv 1 ,
+.Xr strip 1 ,
+.Xr mmap 2 ,
+.Xr chown 8
+.Sh HISTORY
+The
+.Nm install
+utility appeared in
+.Bx 4.2 .
+.Sh BUGS
+Temporary files may be left in the target directory if
+.Nm install
+exits abnormally.
+.Pp
+File flags cannot be set by
+.Xr fchflags 2
+over a NFS file system. Other file systems do not have a concept of flags.
+.Nm install
+will only warn when flags could not be set on a file system
+that does not support them.
+.Pp
+.Nm install
+with
+.Fl v
+falsely says a file is copied when
+.Fl C
+snaps hard links.
diff --git a/file_cmds/install/pathnames.h b/file_cmds/install/pathnames.h
new file mode 100644
index 0000000..5099eb0
--- /dev/null
+++ b/file_cmds/install/pathnames.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#ifndef _INSTALL_PATHNAMES_H_
+#define _INSTALL_PATHNAMES_H_
+
+#define _PATH_STRIP "/usr/bin/strip"
+
+#endif /* _INSTALL_PATHNAMES_H_ */
diff --git a/file_cmds/install/xinstall.c b/file_cmds/install/xinstall.c
new file mode 100644
index 0000000..5e6bcec
--- /dev/null
+++ b/file_cmds/install/xinstall.c
@@ -0,0 +1,816 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "From: @(#)xinstall.c 8.1 (Berkeley) 7/21/93";
+#endif
+__used static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/xinstall/xinstall.c,v 1.43 2001/05/30 07:08:49 ru Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <utime.h>
+#include <spawn.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#include <copyfile.h>
+#endif /* __APPLE__ */
+
+#include "pathnames.h"
+
+/* Bootstrap aid - this doesn't exist in most older releases */
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1) /* from <sys/mman.h> */
+#endif
+
+#define DIRECTORY 0x01 /* Tell install it's a directory. */
+#define SETFLAGS 0x02 /* Tell install to set flags. */
+#define NOCHANGEBITS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
+#define BACKUP_SUFFIX ".old"
+
+struct passwd *pp;
+struct group *gp;
+gid_t gid;
+uid_t uid;
+int dobackup, docompare, dodir, dopreserve, dostrip, nommap, safecopy, verbose;
+mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+char *suffix = BACKUP_SUFFIX;
+
+void copy __P((int, char *, int, char *, off_t));
+int compare __P((int, const char *, size_t, int, const char *, size_t));
+int create_newfile __P((char *, int, struct stat *));
+int create_tempfile __P((char *, char *, size_t));
+void install __P((char *, char *, u_long, u_int));
+void install_dir __P((char *));
+u_long numeric_id __P((char *, char *));
+void strip __P((char *));
+int trymmap __P((int));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct stat from_sb, to_sb;
+ mode_t *set;
+ u_long fset = 0;
+ int ch, no_target;
+ u_int iflags;
+ char *flags, *group, *owner, *to_name;
+
+ iflags = 0;
+ group = owner = NULL;
+ while ((ch = getopt(argc, argv, "B:bCcdf:g:Mm:o:pSsv")) != -1)
+ switch((char)ch) {
+ case 'B':
+ suffix = optarg;
+ /* FALLTHROUGH */
+ case 'b':
+ dobackup = 1;
+ break;
+ case 'C':
+ docompare = 1;
+ break;
+ case 'c':
+ /* For backwards compatibility. */
+ break;
+ case 'd':
+ dodir = 1;
+ break;
+ case 'f':
+ flags = optarg;
+ if (strtofflags(&flags, &fset, NULL))
+ errx(EX_USAGE, "%s: invalid flag", flags);
+ iflags |= SETFLAGS;
+ break;
+ case 'g':
+ group = optarg;
+ break;
+ case 'M':
+ nommap = 1;
+ break;
+ case 'm':
+ if (!(set = setmode(optarg)))
+ errx(EX_USAGE, "invalid file mode: %s",
+ optarg);
+ mode = getmode(set, 0);
+ free(set);
+ break;
+ case 'o':
+ owner = optarg;
+ break;
+ case 'p':
+ docompare = dopreserve = 1;
+ break;
+ case 'S':
+ safecopy = 1;
+ break;
+ case 's':
+ dostrip = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* some options make no sense when creating directories */
+ if ((safecopy || dostrip) && dodir)
+ usage();
+
+ /*
+ * Older versions allowed -d -C combo. Issue a warning
+ * for now, but turn this into an error before 4.5-RELEASE.
+ */
+ if (docompare && dodir)
+ warnx("the -d and -C options may not be specified together");
+
+ /* must have at least two arguments, except when creating directories */
+ if (argc < 2 && !dodir)
+ usage();
+
+ /* need to make a temp copy so we can compare stripped version */
+ if (docompare && dostrip)
+ safecopy = 1;
+
+ /* get group and owner id's */
+ if (group != NULL) {
+ if ((gp = getgrnam(group)) != NULL)
+ gid = gp->gr_gid;
+ else
+ gid = (uid_t)numeric_id(group, "group");
+ } else
+ gid = (gid_t)-1;
+
+ if (owner != NULL) {
+ if ((pp = getpwnam(owner)) != NULL)
+ uid = pp->pw_uid;
+ else
+ uid = (uid_t)numeric_id(owner, "user");
+ } else
+ uid = (uid_t)-1;
+
+ if (dodir) {
+ for (; *argv != NULL; ++argv)
+ install_dir(*argv);
+ exit(EX_OK);
+ /* NOTREACHED */
+ }
+
+ no_target = stat(to_name = argv[argc - 1], &to_sb);
+ if (!no_target && S_ISDIR(to_sb.st_mode)) {
+ for (; *argv != to_name; ++argv)
+ install(*argv, to_name, fset, iflags | DIRECTORY);
+ exit(EX_OK);
+ /* NOTREACHED */
+ }
+
+ /* can't do file1 file2 directory/file */
+ if (argc != 2)
+ usage();
+
+ if (!no_target) {
+ if (stat(*argv, &from_sb))
+ err(EX_OSERR, "%s", *argv);
+ if (!S_ISREG(to_sb.st_mode)) {
+ errno = EFTYPE;
+ err(EX_OSERR, "%s", to_name);
+ }
+ if (to_sb.st_dev == from_sb.st_dev &&
+ to_sb.st_ino == from_sb.st_ino)
+ errx(EX_USAGE,
+ "%s and %s are the same file", *argv, to_name);
+ }
+ install(*argv, to_name, fset, iflags);
+ exit(EX_OK);
+ /* NOTREACHED */
+}
+
+u_long
+numeric_id(name, type)
+ char *name, *type;
+{
+ u_long val;
+ char *ep;
+
+ /*
+ * XXX
+ * We know that uid_t's and gid_t's are unsigned longs.
+ */
+ errno = 0;
+ val = strtoul(name, &ep, 10);
+ if (errno)
+ err(EX_NOUSER, "%s", name);
+ if (*ep != '\0')
+ errx(EX_NOUSER, "unknown %s %s", type, name);
+ return (val);
+}
+
+/*
+ * install --
+ * build a path name and install the file
+ */
+void
+install(from_name, to_name, fset, flags)
+ char *from_name, *to_name;
+ u_long fset;
+ u_int flags;
+{
+ struct stat from_sb, temp_sb, to_sb;
+ struct utimbuf utb;
+ int devnull, files_match, from_fd=0, serrno, target;
+ int tempcopy, temp_fd, to_fd=0;
+ char backup[MAXPATHLEN], *p, pathbuf[MAXPATHLEN], tempfile[MAXPATHLEN];
+
+ files_match = 0;
+
+ /* If try to install NULL file to a directory, fails. */
+ if (flags & DIRECTORY || strcmp(from_name, _PATH_DEVNULL)) {
+ if (stat(from_name, &from_sb))
+ err(EX_OSERR, "%s", from_name);
+ if (!S_ISREG(from_sb.st_mode)) {
+ errno = EFTYPE;
+ err(EX_OSERR, "%s", from_name);
+ }
+ /* Build the target path. */
+ if (flags & DIRECTORY) {
+ (void)snprintf(pathbuf, sizeof(pathbuf), "%s/%s",
+ to_name,
+ (p = strrchr(from_name, '/')) ? ++p : from_name);
+ to_name = pathbuf;
+ }
+ devnull = 0;
+ } else {
+ devnull = 1;
+ }
+
+ target = stat(to_name, &to_sb) == 0;
+
+ /* Only install to regular files. */
+ if (target && !S_ISREG(to_sb.st_mode)) {
+ errno = EFTYPE;
+ warn("%s", to_name);
+ return;
+ }
+
+ /* Only copy safe if the target exists. */
+ tempcopy = safecopy && target;
+
+ if (!devnull && (from_fd = open(from_name, O_RDONLY, 0)) < 0)
+ err(EX_OSERR, "%s", from_name);
+
+ /* If we don't strip, we can compare first. */
+ if (docompare && !dostrip && target) {
+ if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
+ err(EX_OSERR, "%s", to_name);
+ if (devnull)
+ files_match = to_sb.st_size == 0;
+ else
+ files_match = !(compare(from_fd, from_name,
+ (size_t)from_sb.st_size, to_fd,
+ to_name, (size_t)to_sb.st_size));
+
+ /* Close "to" file unless we match. */
+ if (!files_match)
+ (void)close(to_fd);
+ }
+
+ if (!files_match) {
+ if (tempcopy) {
+ to_fd = create_tempfile(to_name, tempfile,
+ sizeof(tempfile));
+ if (to_fd < 0)
+ err(EX_OSERR, "%s", tempfile);
+ } else {
+ if ((to_fd = create_newfile(to_name, target,
+ &to_sb)) < 0)
+ err(EX_OSERR, "%s", to_name);
+ if (verbose)
+ (void)printf("install: %s -> %s\n",
+ from_name, to_name);
+ }
+ if (!devnull)
+ copy(from_fd, from_name, to_fd,
+ tempcopy ? tempfile : to_name, from_sb.st_size);
+ }
+
+ if (dostrip) {
+ strip(tempcopy ? tempfile : to_name);
+
+ /*
+ * Re-open our fd on the target, in case we used a strip
+ * that does not work in-place -- like GNU binutils strip.
+ */
+ close(to_fd);
+ to_fd = open(tempcopy ? tempfile : to_name, O_RDONLY, 0);
+ if (to_fd < 0)
+ err(EX_OSERR, "stripping %s", to_name);
+ }
+
+ /*
+ * Compare the stripped temp file with the target.
+ */
+ if (docompare && dostrip && target) {
+ temp_fd = to_fd;
+
+ /* Re-open to_fd using the real target name. */
+ if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
+ err(EX_OSERR, "%s", to_name);
+
+ if (fstat(temp_fd, &temp_sb)) {
+ serrno = errno;
+ (void)unlink(tempfile);
+ errno = serrno;
+ err(EX_OSERR, "%s", tempfile);
+ }
+
+ if (compare(temp_fd, tempfile, (size_t)temp_sb.st_size, to_fd,
+ to_name, (size_t)to_sb.st_size) == 0) {
+ /*
+ * If target has more than one link we need to
+ * replace it in order to snap the extra links.
+ * Need to preserve target file times, though.
+ */
+ if (to_sb.st_nlink != 1) {
+ utb.actime = to_sb.st_atime;
+ utb.modtime = to_sb.st_mtime;
+ (void)utime(tempfile, &utb);
+ } else {
+ files_match = 1;
+ (void)unlink(tempfile);
+ }
+ (void) close(temp_fd);
+ }
+ }
+
+ /*
+ * Move the new file into place if doing a safe copy
+ * and the files are different (or just not compared).
+ */
+ if (tempcopy && !files_match) {
+ /* Try to turn off the immutable bits. */
+ if (to_sb.st_flags & NOCHANGEBITS)
+ (void)chflags(to_name, to_sb.st_flags & ~NOCHANGEBITS);
+ if (dobackup) {
+ if (snprintf(backup, MAXPATHLEN, "%s%s", to_name,
+ suffix) != strlen(to_name) + strlen(suffix)) {
+ unlink(tempfile);
+ errx(EX_OSERR, "%s: backup filename too long",
+ to_name);
+ }
+ if (verbose)
+ (void)printf("install: %s -> %s\n", to_name, backup);
+ if (rename(to_name, backup) < 0) {
+ serrno = errno;
+ unlink(tempfile);
+ errno = serrno;
+ err(EX_OSERR, "rename: %s to %s", to_name,
+ backup);
+ }
+ }
+ if (verbose)
+ (void)printf("install: %s -> %s\n", from_name, to_name);
+ if (rename(tempfile, to_name) < 0) {
+ serrno = errno;
+ unlink(tempfile);
+ errno = serrno;
+ err(EX_OSERR, "rename: %s to %s",
+ tempfile, to_name);
+ }
+
+ /* Re-open to_fd so we aren't hosed by the rename(2). */
+ (void) close(to_fd);
+ if ((to_fd = open(to_name, O_RDONLY, 0)) < 0)
+ err(EX_OSERR, "%s", to_name);
+ }
+
+#ifdef __APPLE__
+ /* in case mtime is modified */
+ if (!devnull && (S_ISLNK(from_sb.st_mode) || S_ISREG(from_sb.st_mode)) &&
+ fcopyfile(from_fd, to_fd, NULL, COPYFILE_XATTR) < 0) {
+ warn("%s: unable to copy extended attributes from %s", to_name, from_name);
+ }
+#endif /* __APPLE__ */
+ /*
+ * Preserve the timestamp of the source file if necessary.
+ */
+ if (dopreserve && !files_match && !devnull) {
+ utb.actime = from_sb.st_atime;
+ utb.modtime = from_sb.st_mtime;
+ (void)utime(to_name, &utb);
+ }
+
+ if (fstat(to_fd, &to_sb) == -1) {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = serrno;
+ err(EX_OSERR, "%s", to_name);
+ }
+
+ /*
+ * Set owner, group, mode for target; do the chown first,
+ * chown may lose the setuid bits.
+ */
+ if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||
+ (uid != (uid_t)-1 && uid != to_sb.st_uid) ||
+ (mode != to_sb.st_mode)) {
+ /* Try to turn off the immutable bits. */
+ if (to_sb.st_flags & NOCHANGEBITS)
+ (void)fchflags(to_fd, to_sb.st_flags & ~NOCHANGEBITS);
+ }
+
+ if ((gid != (gid_t)-1 && gid != to_sb.st_gid) ||
+ (uid != (uid_t)-1 && uid != to_sb.st_uid))
+ if (fchown(to_fd, uid, gid) == -1) {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = serrno;
+ err(EX_OSERR,"%s: chown/chgrp", to_name);
+ }
+
+ if (mode != to_sb.st_mode)
+ if (fchmod(to_fd, mode)) {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = serrno;
+ err(EX_OSERR, "%s: chmod", to_name);
+ }
+
+ /*
+ * If provided a set of flags, set them, otherwise, preserve the
+ * flags, except for the dump flag.
+ * NFS does not support flags. Ignore ENOTSUP flags if we're just
+ * trying to turn off UF_NODUMP. If we're trying to set real flags,
+ * then warn if the the fs doesn't support it, otherwise fail.
+ */
+ if (!devnull && fchflags(to_fd,
+ flags & SETFLAGS ? fset : from_sb.st_flags & ~UF_NODUMP)) {
+ if (flags & SETFLAGS) {
+ if (errno == ENOTSUP)
+ warn("%s: chflags", to_name);
+ else {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = serrno;
+ err(EX_OSERR, "%s: chflags", to_name);
+ }
+ }
+ }
+#ifdef __APPLE__
+ /* the ACL could prevent credential/permission system calls later on... */
+ if (!devnull && (S_ISLNK(from_sb.st_mode) || S_ISREG(from_sb.st_mode)) &&
+ (fcopyfile(from_fd, to_fd, NULL, COPYFILE_ACL) < 0)) {
+ warn("%s: unable to copy ACL from %s", to_name, from_name);
+ }
+#endif /* __APPLE__ */
+
+ (void)close(to_fd);
+ if (!devnull)
+ (void)close(from_fd);
+}
+
+/*
+ * compare --
+ * compare two files; non-zero means files differ
+ */
+int
+compare(int from_fd, const char *from_name, size_t from_len,
+ int to_fd, const char *to_name, size_t to_len)
+{
+ char *p, *q;
+ int rv;
+ int done_compare;
+
+ rv = 0;
+ if (from_len != to_len)
+ return 1;
+
+ if (from_len <= 8 * 1024 * 1024) {
+ done_compare = 0;
+ if (trymmap(from_fd) && trymmap(to_fd)) {
+ p = mmap(NULL, from_len, PROT_READ, MAP_SHARED, from_fd, (off_t)0);
+ if (p == (char *)MAP_FAILED)
+ goto out;
+ q = mmap(NULL, from_len, PROT_READ, MAP_SHARED, to_fd, (off_t)0);
+ if (q == (char *)MAP_FAILED) {
+ munmap(p, from_len);
+ goto out;
+ }
+
+ rv = memcmp(p, q, from_len);
+ munmap(p, from_len);
+ munmap(q, from_len);
+ done_compare = 1;
+ }
+ out:
+ if (!done_compare) {
+ char buf1[MAXBSIZE];
+ char buf2[MAXBSIZE];
+ int n1, n2;
+
+ rv = 0;
+ lseek(from_fd, 0, SEEK_SET);
+ lseek(to_fd, 0, SEEK_SET);
+ while (rv == 0) {
+ n1 = read(from_fd, buf1, sizeof(buf1));
+ if (n1 == 0)
+ break; /* EOF */
+ else if (n1 > 0) {
+ n2 = read(to_fd, buf2, n1);
+ if (n2 == n1)
+ rv = memcmp(buf1, buf2, n1);
+ else
+ rv = 1; /* out of sync */
+ } else
+ rv = 1; /* read failure */
+ }
+ lseek(from_fd, 0, SEEK_SET);
+ lseek(to_fd, 0, SEEK_SET);
+ }
+ } else
+ rv = 1; /* don't bother in this case */
+
+ return rv;
+}
+
+/*
+ * create_tempfile --
+ * create a temporary file based on path and open it
+ */
+int
+create_tempfile(path, temp, tsize)
+ char *path;
+ char *temp;
+ size_t tsize;
+{
+ char *p;
+
+ (void)strncpy(temp, path, tsize);
+ temp[tsize - 1] = '\0';
+ if ((p = strrchr(temp, '/')) != NULL)
+ p++;
+ else
+ p = temp;
+ (void)strncpy(p, "INS@XXXX", &temp[tsize - 1] - p);
+ temp[tsize - 1] = '\0';
+ return (mkstemp(temp));
+}
+
+/*
+ * create_newfile --
+ * create a new file, overwriting an existing one if necessary
+ */
+int
+create_newfile(path, target, sbp)
+ char *path;
+ int target;
+ struct stat *sbp;
+{
+ char backup[MAXPATHLEN];
+
+ if (target) {
+ /*
+ * Unlink now... avoid ETXTBSY errors later. Try to turn
+ * off the append/immutable bits -- if we fail, go ahead,
+ * it might work.
+ */
+ if (sbp->st_flags & NOCHANGEBITS)
+ (void)chflags(path, sbp->st_flags & ~NOCHANGEBITS);
+
+ if (dobackup) {
+ if (snprintf(backup, MAXPATHLEN, "%s%s",
+ path, suffix) != strlen(path) + strlen(suffix))
+ errx(EX_OSERR, "%s: backup filename too long",
+ path);
+ (void)snprintf(backup, MAXPATHLEN, "%s%s",
+ path, suffix);
+ if (verbose)
+ (void)printf("install: %s -> %s\n",
+ path, backup);
+ if (rename(path, backup) < 0)
+ err(EX_OSERR, "rename: %s to %s", path, backup);
+ } else
+ (void)unlink(path);
+ }
+
+ return (open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR));
+}
+
+/*
+ * copy --
+ * copy from one file to another
+ */
+void
+copy(from_fd, from_name, to_fd, to_name, size)
+ register int from_fd, to_fd;
+ char *from_name, *to_name;
+ off_t size;
+{
+ register int nr, nw;
+ int serrno;
+ char *p;
+ char buf[MAXBSIZE];
+ int done_copy;
+
+ /* Rewind file descriptors. */
+ if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1)
+ err(EX_OSERR, "lseek: %s", from_name);
+ if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
+ err(EX_OSERR, "lseek: %s", to_name);
+
+ /*
+ * Mmap and write if less than 8M (the limit is so we don't totally
+ * trash memory on big files. This is really a minor hack, but it
+ * wins some CPU back.
+ */
+ done_copy = 0;
+ if (size <= 8 * 1048576 && trymmap(from_fd) &&
+ (p = mmap(NULL, (size_t)size, PROT_READ, MAP_SHARED,
+ from_fd, (off_t)0)) != (char *)MAP_FAILED) {
+ if ((nw = write(to_fd, p, size)) != size) {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = nw > 0 ? EIO : serrno;
+ err(EX_OSERR, "%s", to_name);
+ }
+ done_copy = 1;
+ }
+ if (!done_copy) {
+ while ((nr = read(from_fd, buf, sizeof(buf))) > 0)
+ if ((nw = write(to_fd, buf, nr)) != nr) {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = nw > 0 ? EIO : serrno;
+ err(EX_OSERR, "%s", to_name);
+ }
+ if (nr != 0) {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = serrno;
+ err(EX_OSERR, "%s", from_name);
+ }
+ }
+}
+
+/*
+ * strip --
+ * use strip(1) to strip the target file
+ */
+void
+strip(to_name)
+ char *to_name;
+{
+ pid_t pid;
+ int error;
+ extern char** environ;
+ char *const argv[] = { "xcrun", "strip", "-", to_name, NULL };
+
+ if (0 == (error = posix_spawnp(&pid, "xcrun", NULL, NULL, argv, environ))) {
+ int status = 0;
+ pid_t child = waitpid(pid, &status, 0);
+ if ((child == -1) || status) {
+ unlink(to_name);
+ errx(EX_SOFTWARE, "child process failed: xcrun strip - %s", to_name);
+ }
+ } else {
+ errno = error;
+ err(EX_OSERR, "xcrun strip - %s", to_name);
+ }
+}
+
+/*
+ * install_dir --
+ * build directory heirarchy
+ */
+void
+install_dir(path)
+ char *path;
+{
+ register char *p;
+ struct stat sb;
+ int ch;
+
+ for (p = path;; ++p)
+ if (!*p || (p != path && *p == '/')) {
+ ch = *p;
+ *p = '\0';
+ if (stat(path, &sb)) {
+ if (errno != ENOENT || mkdir(path, 0755) < 0) {
+ err(EX_OSERR, "mkdir %s", path);
+ /* NOTREACHED */
+ } else if (verbose)
+ (void)printf("install: mkdir %s\n",
+ path);
+ } else if (!S_ISDIR(sb.st_mode))
+ errx(EX_OSERR, "%s exists but is not a directory", path);
+ if (!(*p = ch))
+ break;
+ }
+
+ if ((gid != (gid_t)-1 || uid != (uid_t)-1) && chown(path, uid, gid))
+ warn("chown %u:%u %s", uid, gid, path);
+ if (chmod(path, mode))
+ warn("chmod %o %s", mode, path);
+}
+
+/*
+ * usage --
+ * print a usage message and die
+ */
+void
+usage()
+{
+ (void)fprintf(stderr, "\
+usage: install [-bCcpSsv] [-B suffix] [-f flags] [-g group] [-m mode]\n\
+ [-o owner] file1 file2\n\
+ install [-bCcpSsv] [-B suffix] [-f flags] [-g group] [-m mode]\n\
+ [-o owner] file1 ... fileN directory\n\
+ install -d [-v] [-g group] [-m mode] [-o owner] directory ...\n");
+ exit(EX_USAGE);
+ /* NOTREACHED */
+}
+
+/*
+ * trymmap --
+ * return true (1) if mmap should be tried, false (0) if not.
+ */
+int
+trymmap(fd)
+ int fd;
+{
+/*
+ * The ifdef is for bootstrapping - f_fstypename doesn't exist in
+ * pre-Lite2-merge systems.
+ */
+#ifdef MFSNAMELEN
+ struct statfs stfs;
+
+ if (nommap || fstatfs(fd, &stfs) != 0)
+ return (0);
+ if (strcmp(stfs.f_fstypename, "ufs") == 0 ||
+ strcmp(stfs.f_fstypename, "cd9660") == 0)
+ return (1);
+#endif
+ return (0);
+}
diff --git a/file_cmds/ipcrm/ipcrm.1 b/file_cmds/ipcrm/ipcrm.1
new file mode 100644
index 0000000..55ff23c
--- /dev/null
+++ b/file_cmds/ipcrm/ipcrm.1
@@ -0,0 +1,84 @@
+.\" Copyright (c) 1994 Adam Glass
+.\" 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. 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 Adam Glass ``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 Adam Glass 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: ipcrm.1,v 1.3 2005/04/12 23:51:24 nicolai Exp $
+.\""
+.Dd August 8, 1994
+.Dt ipcrm 1
+.Os
+.Sh NAME
+.Nm ipcrm
+.Nd remove the specified message queues, semaphore sets, and shared memory
+segments
+.Sh SYNOPSIS
+.Nm ipcrm
+.Op Fl M Ar shmkey
+.Op Fl m Ar shmid
+.Op Fl Q Ar msgkey
+.Op Fl q Ar msqid
+.Op Fl S Ar semkey
+.Op Fl s Ar semid
+.Ar ...
+.Sh DESCRIPTION
+.Nm Ipcrm
+removes the specified message queues, semaphores and shared memory
+segments. These System V IPC objects can be specified by their
+creation id or any associated key.
+.Pp
+The following options are used to specify which IPC objects will be removed.
+Any number and combination of these options can be used:
+.Bl -tag -width indent
+.It Fl M Ar shmkey
+Mark the shared memory segment associated with key
+.Nm shmkey
+for removal.
+This marked segment will be destroyed after the last detach.
+.It Fl m Ar shmid
+Mark the shared memory segment associated with id
+.Nm shmid
+for removal.
+This marked segment will be destroyed after the last detach.
+.It Fl Q Ar msgkey
+Remove the message queue associated with key
+.Nm msgkey
+from the system.
+.It Fl q Ar msqid
+Remove the message queue associated with the id
+.Nm msqid
+from the system.
+.It Fl S Ar semkey
+Remove the semaphore set associated with key
+.Nm semkey
+from the system.
+.It Fl s Ar semid
+Removes the semaphore set associated with id
+.Nm semid
+from the system.
+.El
+.Pp
+The identifiers and keys associated with these System V IPC objects can be
+determined by using
+.Xr ipcs 1
+.
+.Sh SEE ALSO
+.Xr ipcs 1
diff --git a/file_cmds/ipcrm/ipcrm.c b/file_cmds/ipcrm/ipcrm.c
new file mode 100644
index 0000000..e90aaa1
--- /dev/null
+++ b/file_cmds/ipcrm/ipcrm.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1994 Adam Glass
+ * 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 Adam Glass.
+ * 4. The name of the Author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Adam Glass ``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 Adam Glass BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char rcsid[] =
+ "$Id: ipcrm.c,v 1.3 2005/02/03 07:31:33 josborne Exp $";
+#endif /* not lint */
+
+#include <ctype.h>
+#include <err.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <sys/shm.h>
+
+#define IPC_TO_STR(x) (x == 'Q' ? "msq" : (x == 'M' ? "shm" : "sem"))
+#define IPC_TO_STRING(x) (x == 'Q' ? "message queue" : \
+ (x == 'M' ? "shared memory segment" : "semaphore"))
+
+int signaled;
+
+static void usage(void)
+{
+ fprintf(stderr, "%s\n%s\n",
+ "usage: ipcrm [-q msqid] [-m shmid] [-s semid]",
+ " [-Q msgkey] [-M shmkey] [-S semkey] ...");
+ exit(1);
+}
+
+static int msgrm(key_t key, int id)
+{
+ if (key) {
+ id = msgget(key, 0);
+ if (id == -1)
+ return -1;
+ }
+ return msgctl(id, IPC_RMID, NULL);
+}
+
+static int shmrm(key_t key, int id)
+{
+ if (key) {
+ id = shmget(key, 0, 0);
+ if (id == -1)
+ return -1;
+ }
+ return shmctl(id, IPC_RMID, NULL);
+}
+
+static int semrm(key_t key, int id)
+{
+ if (key) {
+ id = semget(key, 0, 0);
+ if (id == -1)
+ return -1;
+ }
+ return semctl(id, 0, IPC_RMID);
+}
+
+static void not_configured(__unused int unused)
+{
+ signaled++;
+}
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+
+{
+ int c, result, errflg, target_id;
+ key_t target_key;
+ char *en;
+
+ errflg = 0;
+ signal(SIGSYS, not_configured);
+ while ((c = getopt(argc, argv, ":q:m:s:Q:M:S:")) != -1) {
+
+ signaled = 0;
+ switch (c) {
+ case 'q':
+ case 'm':
+ case 's':
+ target_id = (int)strtol(optarg, &en, 0);
+ if (*en) {
+ warnx("%s: '%s' is not a number",
+ IPC_TO_STRING(toupper(c)), optarg);
+ continue;
+ }
+ if (c == 'q')
+ result = msgrm(0, target_id);
+ else if (c == 'm')
+ result = shmrm(0, target_id);
+ else
+ result = semrm(0, target_id);
+ if (result < 0) {
+ errflg++;
+ if (!signaled)
+ warn("%sid(%d): ", IPC_TO_STR(toupper(c)), target_id);
+ else
+ warnx("%ss are not configured in the running kernel",
+ IPC_TO_STRING(toupper(c)));
+ }
+ break;
+ case 'Q':
+ case 'M':
+ case 'S':
+ target_key = (key_t)strtol(optarg, &en, 0);
+ if (*en) {
+ warnx("%s: '%s' is not a number", IPC_TO_STRING(c), optarg);
+ continue;
+ }
+ if (target_key == IPC_PRIVATE) {
+ warnx("can't remove private %ss", IPC_TO_STRING(c));
+ continue;
+ }
+ if (c == 'Q')
+ result = msgrm(target_key, 0);
+ else if (c == 'M')
+ result = shmrm(target_key, 0);
+ else
+ result = semrm(target_key, 0);
+ if (result < 0) {
+ errflg++;
+ if (!signaled)
+ warn("%s key(%d): ", IPC_TO_STRING(c), target_key);
+ else
+ warnx("%ss are not configured in the running kernel",
+ IPC_TO_STRING(c));
+ }
+ break;
+ case ':':
+ fprintf(stderr, "option -%c requires an argument\n", optopt);
+ usage();
+ case '?':
+ fprintf(stderr, "unrecognized option: -%c\n", optopt);
+ usage();
+ }
+ }
+
+ if (optind != argc) {
+ fprintf(stderr, "unknown argument: %s\n", argv[optind]);
+ usage();
+ }
+ exit(errflg);
+}
diff --git a/file_cmds/ipcs/ipcs.1 b/file_cmds/ipcs/ipcs.1
new file mode 100644
index 0000000..f0a6df4
--- /dev/null
+++ b/file_cmds/ipcs/ipcs.1
@@ -0,0 +1,132 @@
+.\"
+.\" Copyright (c) 1994 SigmaSoft, Th. Lockert
+.\" 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 SigmaSoft, Th. Lockert.
+.\" 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.
+.\"
+.\" $FreeBSD: src/usr.bin/ipcs/ipcs.1,v 1.16 2003/05/21 21:07:28 ru Exp $
+.\"
+.Dd June 18, 1994
+.Dt "IPCS" 1
+.Os
+.Sh NAME
+.Nm ipcs
+.Nd report System V interprocess communication facilities status
+.Sh SYNOPSIS
+.Nm ipcs
+.Op Fl abcMmopQqSsTt
+.Sh DESCRIPTION
+The
+.Nm ipcs
+utility provides information on System V interprocess communication
+(IPC) facilities on the system.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Show the maximum amount of information possible when
+displaying active semaphores, message queues,
+and shared memory segments.
+(This is shorthand for specifying the
+.Fl b ,
+.Fl c ,
+.Fl o ,
+.Fl p ,
+and
+.Fl t
+options.)
+.It Fl b
+Show the maximum allowed sizes for active semaphores, message queues,
+and shared memory segments. The
+.Dq maximum allowed size
+is the maximum number of bytes in a message on a message queue,
+the size of a shared memory segment,
+or the number of semaphores in a set of semaphores.
+.It Fl c
+Show the creator's name and group for active semaphores, message queues,
+and shared memory segments.
+.It Fl M
+Display system information about shared memory.
+.It Fl m
+Display information about active shared memory segments.
+.It Fl o
+Show outstanding usage for active message queues,
+and shared memory segments. The
+.Dq outstanding usage
+is the number of messages in a message queue, or the number
+of processes attached to a shared memory segment.
+.It Fl p
+Show the process ID information for active semaphores, message queues,
+and shared memory segments. The
+.Dq process ID information
+is the last process to send a message to or receive a message from
+a message queue,
+the process that created a semaphore, or the last process to attach
+or detach a shared memory segment.
+.It Fl Q
+Display system information about messages queues.
+.It Fl q
+Display information about active message queues.
+.It Fl S
+Display system information about semaphores.
+.It Fl s
+Display information about active semaphores.
+.It Fl T
+Display system information about shared memory, message queues
+and semaphores.
+.It Fl t
+Show access times for active semaphores, message queues,
+and shared memory segments. The access times is the time
+of the last control operation on an IPC object,
+the last send or receive of a message,
+the last attach or detach of a shared memory segment,
+or the last operation on a semaphore.
+.El
+.Pp
+If none of the
+.Fl M ,
+.Fl m ,
+.Fl Q ,
+.Fl q ,
+.Fl S ,
+or
+.Fl s
+options are specified, information about all active IPC facilities is
+listed.
+.Sh RESTRICTIONS
+System data structures may change while
+.Nm ipcs
+is running; the output of
+.Nm ipcs
+is not guaranteed to be consistent.
+.Sh BUGS
+This manual page is woefully incomplete, because it does not
+at all attempt to explain the information printed by
+.Nm ipcs .
+.Sh SEE ALSO
+.Xr ipcrm 1
+.Sh AUTHORS
+.An Thorsten Lockert Aq tholo@sigmasoft.com
diff --git a/file_cmds/ipcs/ipcs.c b/file_cmds/ipcs/ipcs.c
new file mode 100644
index 0000000..986b229
--- /dev/null
+++ b/file_cmds/ipcs/ipcs.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.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.
+ * 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 ``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/cdefs.h>
+
+#include <assert.h>
+#include <err.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <nlist.h>
+#include <limits.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#include "sys/types.h"
+#include <sys/ucred.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <errno.h>
+#include "sys/ipcs.h"
+#define KERNEL 1 /* To get new ipc_perm and __(sem|shm|msg)ds_new */
+#include "sys/ipc.h"
+#include "sys/sem_internal.h"
+#include "sys/shm_internal.h"
+#include "sys/msg.h"
+
+
+/* The following is a kludge, until the problem of multiple inclusions
+ of ipc.h is taken care of. */
+#ifndef IXSEQ_TO_IPCID
+#define IXSEQ_TO_IPCID(ix,perm) (((perm._seq) << 16L) | (ix & 0xffff))
+#endif
+
+static char *
+fmt_perm(u_short mode, char write_char)
+{
+ static char buffer[100];
+
+ buffer[0] = '-';
+ buffer[1] = '-';
+ buffer[2] = ((mode & 0400) ? 'r' : '-');
+ buffer[3] = ((mode & 0200) ? write_char : '-');
+ buffer[4] = '-';
+ buffer[5] = ((mode & 0040) ? 'r' : '-');
+ buffer[6] = ((mode & 0020) ? write_char : '-');
+ buffer[7] = '-';
+ buffer[8] = ((mode & 0004) ? 'r' : '-');
+ buffer[9] = ((mode & 0002) ? write_char : '-');
+ buffer[10] = '-';
+ buffer[11] = '\0';
+ return (&buffer[0]);
+}
+
+static void
+cvt_time(time_t t, char *buf)
+{
+ struct tm *tm;
+
+ if (t == 0) {
+ strcpy(buf, "no-entry");
+ } else {
+ tm = localtime(&t);
+ if (tm != NULL) {
+ sprintf(buf, "%2d:%02d:%02d",
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ }
+ }
+}
+#define SHMINFO 1
+#define SHMTOTAL 2
+#define MSGINFO 4
+#define MSGTOTAL 8
+#define SEMINFO 16
+#define SEMTOTAL 32
+
+#define BIGGEST 1
+#define CREATOR 2
+#define OUTSTANDING 4
+#define PID 8
+#define TIME 16
+
+static void
+usage(void)
+{
+ errx(EX_USAGE, "%s","usage: ipcs [-abcmopqstMQST]\n");
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int display = 0;
+ int option = 0;
+ int exit_val = 0;
+ time_t now;
+ char datestring[100];
+ int i;
+
+ while ((i = getopt(argc, argv, "MmQqSsabcoptT")) != -1)
+ switch (i) {
+ case 'M':
+ display = SHMTOTAL;
+ break;
+ case 'm':
+ display |= SHMINFO;
+ break;
+ case 'Q':
+ display = MSGTOTAL;
+ break;
+ case 'q':
+ display |= MSGINFO;
+ break;
+ case 'S':
+ display = SEMTOTAL;
+ break;
+ case 's':
+ display |= SEMINFO;
+ break;
+ case 'T':
+ display = SHMTOTAL | MSGTOTAL | SEMTOTAL;
+ break;
+ case 'a':
+ option |= BIGGEST | CREATOR | OUTSTANDING | PID | TIME;
+ break;
+ case 'b':
+ option |= BIGGEST;
+ break;
+ case 'c':
+ option |= CREATOR;
+ break;
+ case 'o':
+ option |= OUTSTANDING;
+ break;
+ case 'p':
+ option |= PID;
+ break;
+ case 't':
+ option |= TIME;
+ break;
+ default:
+ usage();
+ }
+ if (display == 0)
+ display = SHMINFO | MSGINFO | SEMINFO;
+ now = time(0);
+ struct tm* tm = localtime(&now);
+ if (tm == NULL) {
+ now = 0;
+ tm = localtime(&now);
+ }
+ if (0 == strftime(datestring, sizeof(datestring), "%a %b %e %H:%M:%S %Z %Y", tm))
+ errx(1, "strftime failed\n");
+ printf("IPC status from <running system> as of %s\n", datestring);
+ if ((display & (MSGINFO | MSGTOTAL))) {
+ if (display & MSGTOTAL) {
+ struct IPCS_command ic;
+ struct msginfo msginfo;
+ size_t ic_size = sizeof(ic);
+
+ ic.ipcs_magic = IPCS_MAGIC;
+ ic.ipcs_op = IPCS_MSG_CONF;
+ ic.ipcs_cursor = 0; /* 0 for fw. compat. */
+ ic.ipcs_data = &msginfo;
+ ic.ipcs_datalen = sizeof(msginfo);
+
+ if (sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size)) {
+ if (errno != EPERM) {
+ char buffer[1024];
+ snprintf(buffer, 1024, "sysctlbyname(IPCS_MSG_SYSCTL, op=CONF, &ic, &%ld) datalen=%d",
+ sizeof(ic), ic.ipcs_datalen);
+ perror(buffer);
+ } else
+ perror("sysctlbyname IPCS_MSG_SYSCTL");
+ }
+
+ printf("msginfo:\n");
+ printf("\tmsgmax: %6d\t(max characters in a message)\n",
+ msginfo.msgmax);
+ printf("\tmsgmni: %6d\t(# of message queues)\n",
+ msginfo.msgmni);
+ printf("\tmsgmnb: %6d\t(max characters in a message queue)\n",
+ msginfo.msgmnb);
+ printf("\tmsgtql: %6d\t(max # of messages in system)\n",
+ msginfo.msgtql);
+ printf("\tmsgssz: %6d\t(size of a message segment)\n",
+ msginfo.msgssz);
+ printf("\tmsgseg: %6d\t(# of message segments in system)\n\n",
+ msginfo.msgseg);
+ }
+ if (display & MSGINFO) {
+ struct IPCS_command ic;
+ struct __msqid_ds_new ds;
+ struct __msqid_ds_new *msqptr = &ds;
+ size_t ic_size = sizeof(ic);
+
+ printf("T ID KEY MODE OWNER GROUP");
+ if (option & CREATOR)
+ printf(" CREATOR CGROUP");
+ if (option & OUTSTANDING)
+ printf(" CBYTES QNUM");
+ if (option & BIGGEST)
+ printf(" QBYTES");
+ if (option & PID)
+ printf(" LSPID LRPID");
+ if (option & TIME)
+ printf(" STIME RTIME CTIME");
+ printf("\nMessage Queues:\n");
+
+ ic.ipcs_magic = IPCS_MAGIC;
+ ic.ipcs_op = IPCS_MSG_ITER;
+ ic.ipcs_cursor = 0; /* start */
+ ic.ipcs_datalen = sizeof(*msqptr);
+ ic.ipcs_data = msqptr;
+
+ memset(msqptr, 0, sizeof(*msqptr));
+
+ while(!(sysctlbyname(IPCS_MSG_SYSCTL, &ic, &ic_size, &ic, ic_size))) {
+ ic.ipcs_data = msqptr;
+
+ if (msqptr->msg_qbytes != 0) {
+ char stime_buf[100], rtime_buf[100],
+ ctime_buf[100];
+
+ cvt_time(msqptr->msg_stime, stime_buf);
+ cvt_time(msqptr->msg_rtime, rtime_buf);
+ cvt_time(msqptr->msg_ctime, ctime_buf);
+
+ printf("q %6d 0x%08x %s %8s %8s",
+ IXSEQ_TO_IPCID((ic.ipcs_cursor-1), msqptr->msg_perm),
+ (int)msqptr->msg_perm._key,
+ fmt_perm(msqptr->msg_perm.mode, 'w'),
+ user_from_uid(msqptr->msg_perm.uid, 0),
+ group_from_gid(msqptr->msg_perm.gid, 0));
+
+ if (option & CREATOR)
+ printf(" %8s %8s",
+ user_from_uid(msqptr->msg_perm.cuid, 0),
+ group_from_gid(msqptr->msg_perm.cgid, 0));
+
+ if (option & OUTSTANDING)
+ printf(" %6lu %6lu",
+ msqptr->msg_cbytes,
+ msqptr->msg_qnum);
+
+ if (option & BIGGEST)
+ printf(" %6lu",
+ msqptr->msg_qbytes);
+
+ if (option & PID)
+ printf(" %6d %6d",
+ msqptr->msg_lspid,
+ msqptr->msg_lrpid);
+
+ if (option & TIME)
+ printf(" %s %s %s",
+ stime_buf,
+ rtime_buf,
+ ctime_buf);
+
+ printf("\n");
+ }
+ memset(msqptr, 0, sizeof(*msqptr));
+ errno = 0;
+ }
+
+ if (errno != ENOENT && errno != ERANGE) {
+ if (errno != EPERM) {
+ errx(1, "sysctlbyname(IPCS_MSG_SYSCTL, op=ITER, &ic, &%ld) datalen=%d failed:%s\n",
+ sizeof(ic), ic.ipcs_datalen, strerror(errno));
+ } else
+ errx(1, "sysctlbyname IPCS_MSG_SYSCTL: %s", strerror(errno));
+ }
+ printf("\n");
+ }
+ } else
+ if (display & (MSGINFO | MSGTOTAL)) {
+ errx(1, "%s", "SVID messages facility not configured in the system\n");
+ }
+
+ if ((display & (SHMINFO | SHMTOTAL))) {
+ if (display & SHMTOTAL) {
+ struct IPCS_command ic;
+ struct shminfo shminfo;
+ size_t ic_size = sizeof(ic);
+
+ ic.ipcs_magic = IPCS_MAGIC;
+ ic.ipcs_op = IPCS_SHM_CONF;
+ ic.ipcs_cursor = 0; /* 0 for fw. compat. */
+ ic.ipcs_data = &shminfo;
+ ic.ipcs_datalen = sizeof(shminfo);
+
+ if (sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size)) {
+ if (errno != EPERM) {
+ errx(1, "sysctlbyname(IPCS_SHM_SYSCTL, op=CONF, &ic, &%ld) datalen=%d failed: %s\n",
+ sizeof(ic), ic.ipcs_datalen, strerror(errno));
+ } else
+ errx(1, "sysctlbyname: %s", strerror(errno));
+ }
+ printf("shminfo:\n");
+ printf("\tshmmax: %7lld\t(max shared memory segment size)\n",
+ shminfo.shmmax);
+ printf("\tshmmin: %7lld\t(min shared memory segment size)\n",
+ shminfo.shmmin);
+ printf("\tshmmni: %7lld\t(max number of shared memory identifiers)\n",
+ shminfo.shmmni);
+ printf("\tshmseg: %7lld\t(max shared memory segments per process)\n",
+ shminfo.shmseg);
+ printf("\tshmall: %7lld\t(max amount of shared memory in pages)\n\n",
+ shminfo.shmall);
+ }
+ if (display & SHMINFO) {
+ struct IPCS_command ic;
+ struct __shmid_ds_new ds;
+ struct __shmid_ds_new *shmptr = &ds;
+ size_t ic_size = sizeof(ic);
+
+ printf("T ID KEY MODE OWNER GROUP");
+ if (option & CREATOR)
+ printf(" CREATOR CGROUP");
+ if (option & OUTSTANDING)
+ printf(" NATTCH");
+ if (option & BIGGEST)
+ printf(" SEGSZ");
+ if (option & PID)
+ printf(" CPID LPID");
+ if (option & TIME)
+ printf(" ATIME DTIME CTIME");
+ printf("\nShared Memory:\n");
+ { /* XXX */
+
+ ic.ipcs_magic = IPCS_MAGIC;
+ ic.ipcs_op = IPCS_SHM_ITER;
+ ic.ipcs_cursor = 0; /* start */
+ ic.ipcs_datalen = sizeof(*shmptr);
+ ic.ipcs_data = shmptr;
+ memset(shmptr, 0, sizeof(*shmptr));
+
+ while(!(sysctlbyname(IPCS_SHM_SYSCTL, &ic, &ic_size, &ic, ic_size))) {
+ ic.ipcs_data = shmptr; /* xnu workaround */
+
+ if (shmptr->shm_perm.mode & 0x0800) {
+ char atime_buf[100], dtime_buf[100],
+ ctime_buf[100];
+
+ cvt_time(shmptr->shm_atime, atime_buf);
+ cvt_time(shmptr->shm_dtime, dtime_buf);
+ cvt_time(shmptr->shm_ctime, ctime_buf);
+
+ printf("m %6d 0x%08x %s %8s %8s",
+ IXSEQ_TO_IPCID((ic.ipcs_cursor-1), shmptr->shm_perm),
+ (int)shmptr->shm_perm._key,
+ fmt_perm(shmptr->shm_perm.mode, 'w'),
+ user_from_uid(shmptr->shm_perm.uid, 0),
+ group_from_gid(shmptr->shm_perm.gid, 0));
+
+ if (option & CREATOR)
+ printf(" %8s %8s",
+ user_from_uid(shmptr->shm_perm.cuid, 0),
+ group_from_gid(shmptr->shm_perm.cgid, 0));
+
+ if (option & OUTSTANDING)
+ printf(" %6d",
+ shmptr->shm_nattch);
+
+ if (option & BIGGEST)
+ printf(" %6ld",
+ shmptr->shm_segsz);
+
+ if (option & PID)
+ printf(" %6d %6d",
+ shmptr->shm_cpid,
+ shmptr->shm_lpid);
+
+ if (option & TIME)
+ printf(" %s %s %s",
+ atime_buf,
+ dtime_buf,
+ ctime_buf);
+
+ printf("\n");
+ }
+ memset(shmptr, 0, sizeof(*shmptr));
+ errno = 0;
+ }
+
+ if (errno != ENOENT && errno != ERANGE) {
+ if (errno != EPERM) {
+ errx(1, "sysctlbyname(IPCS_SHM_SYSCTL, op=ITER, &ic, &%ld) datalen=%d failed:%s\n",
+ sizeof(ic), ic.ipcs_datalen, strerror(errno));
+ } else
+ errx(1, "sysctlbyname: %s", strerror(errno));
+ }
+ } /* XXX */
+ printf("\n");
+ }
+ }
+else
+ if (display & (SHMINFO | SHMTOTAL)) {
+ errx(1, "%s", "SVID shared memory facility not configured in the system\n");
+ }
+
+ if ((display & (SEMINFO | SEMTOTAL))) {
+ if (display & SEMTOTAL) {
+ struct IPCS_command ic;
+ struct seminfo seminfo;
+ size_t ic_size = sizeof(ic);
+
+ ic.ipcs_magic = IPCS_MAGIC;
+ ic.ipcs_op = IPCS_SEM_CONF;
+ ic.ipcs_cursor = 0; /* 0 for fw. compat. */
+ ic.ipcs_data = &seminfo;
+ ic.ipcs_datalen = sizeof(seminfo);
+
+ if (sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size)) {
+ if (errno != EPERM) {
+ char buffer[1024];
+ snprintf(buffer, 1024, "sysctlbyname(IPCS_SEM_SYSCTL, op=CONF, &ic, &%ld) datalen=%d",
+ sizeof(ic), ic.ipcs_datalen);
+ perror(buffer);
+ } else
+ perror("sysctlbyname IPCS_SEM_SYSCTL/SEM_CONF");
+ }
+
+ printf("seminfo:\n");
+ printf("\tsemmap: %6d\t(# of entries in semaphore map)\n",
+ seminfo.semmap);
+ printf("\tsemmni: %6d\t(# of semaphore identifiers)\n",
+ seminfo.semmni);
+ printf("\tsemmns: %6d\t(# of semaphores in system)\n",
+ seminfo.semmns);
+ printf("\tsemmnu: %6d\t(# of undo structures in system)\n",
+ seminfo.semmnu);
+ printf("\tsemmsl: %6d\t(max # of semaphores per id)\n",
+ seminfo.semmsl);
+ printf("\tsemopm: %6d\t(max # of operations per semop call)\n",
+ seminfo.semopm);
+ printf("\tsemume: %6d\t(max # of undo entries per process)\n",
+ seminfo.semume);
+ printf("\tsemusz: %6d\t(size in bytes of undo structure)\n",
+ seminfo.semusz);
+ printf("\tsemvmx: %6d\t(semaphore maximum value)\n",
+ seminfo.semvmx);
+ printf("\tsemaem: %6d\t(adjust on exit max value)\n\n",
+ seminfo.semaem);
+ }
+ if (display & SEMINFO) {
+ struct IPCS_command ic;
+ struct __semid_ds_new ds;
+ struct __semid_ds_new *semaptr = &ds;
+ size_t ic_size = sizeof(ic);
+
+ printf("T ID KEY MODE OWNER GROUP");
+ if (option & CREATOR)
+ printf(" CREATOR CGROUP");
+ if (option & BIGGEST)
+ printf(" NSEMS");
+ if (option & TIME)
+ printf(" OTIME CTIME");
+ printf("\nSemaphores:\n");
+
+ ic.ipcs_magic = IPCS_MAGIC;
+ ic.ipcs_op = IPCS_SEM_ITER;
+ ic.ipcs_cursor = 0; /* start */
+ ic.ipcs_datalen = sizeof(*semaptr);
+ ic.ipcs_data = semaptr;
+
+ memset(semaptr, 0, sizeof(*semaptr));
+
+ while(!(sysctlbyname(IPCS_SEM_SYSCTL, &ic, &ic_size, &ic, ic_size))) {
+ ic.ipcs_data = semaptr; /* xnu workaround */
+
+ if ((semaptr->sem_perm.mode & SEM_ALLOC) != 0) {
+ char ctime_buf[100], otime_buf[100];
+
+ cvt_time(semaptr->sem_otime, otime_buf);
+ cvt_time(semaptr->sem_ctime, ctime_buf);
+
+ printf("s %6d 0x%08x %s %8s %8s",
+ IXSEQ_TO_IPCID((ic.ipcs_cursor-1), semaptr->sem_perm),
+ (int)semaptr->sem_perm._key,
+ fmt_perm(semaptr->sem_perm.mode, 'a'),
+ user_from_uid(semaptr->sem_perm.uid, 0),
+ group_from_gid(semaptr->sem_perm.gid, 0));
+
+ if (option & CREATOR)
+ printf(" %8s %8s",
+ user_from_uid(semaptr->sem_perm.cuid, 0),
+ group_from_gid(semaptr->sem_perm.cgid, 0));
+
+ if (option & BIGGEST)
+ printf(" %6d",
+ semaptr->sem_nsems);
+
+ if (option & TIME)
+ printf(" %s %s",
+ otime_buf,
+ ctime_buf);
+
+ printf("\n");
+ }
+ memset(semaptr, 0, sizeof(*semaptr));
+ errno = 0;
+ }
+
+ if (errno != ENOENT && errno != ERANGE) {
+ if (errno != EPERM) {
+ errx(1, "sysctlbyname(IPCS_SEM_SYSCTL/ITER, op=ITER, &ic, &%ld) datalen=%d failed: %s\n",
+ sizeof(ic), ic.ipcs_datalen, strerror(errno));
+ } else
+ errx(1, "sysctlbyname: IPCS_SEM_SYSCTL %s", strerror(errno));
+ }
+ printf("\n");
+ }
+ } else
+ if (display & (SEMINFO | SEMTOTAL)) {
+ errx(1, "%s", "SVID semaphores facility not configured in the system\n");
+ }
+
+ exit(exit_val);
+}
diff --git a/file_cmds/ln/link.1 b/file_cmds/ln/link.1
new file mode 100644
index 0000000..bfb5b6e
--- /dev/null
+++ b/file_cmds/ln/link.1
@@ -0,0 +1 @@
+.so man1/ln.1
diff --git a/file_cmds/ln/ln.1 b/file_cmds/ln/ln.1
new file mode 100644
index 0000000..d9edf00
--- /dev/null
+++ b/file_cmds/ln/ln.1
@@ -0,0 +1,233 @@
+.\"-
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ln.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD: src/bin/ln/ln.1,v 1.31 2006/02/14 11:08:05 glebius Exp $
+.\"
+.Dd July 12, 2019
+.Dt LN 1
+.Os
+.Sh NAME
+.Nm link ,
+.Nm ln
+.Nd make links
+.Sh SYNOPSIS
+.Nm ln
+.Op Fl Ffhinsv
+.Ar source_file
+.Op Ar link_name
+.Nm ln
+.Op Fl Ffhinsv
+.Ar source_file ...
+.Ar link_dirname
+.Nm link
+.Ar source_file Ar link_name
+.Sh DESCRIPTION
+The
+.Nm ln
+utility creates a new directory entry (linked file) which has the
+same modes as the original file.
+It is useful for maintaining multiple copies of a file in many places
+at once without using up storage for the
+.Dq copies ;
+instead, a link
+.Dq points
+to the original copy.
+There are two types of links; hard links and symbolic links.
+How a link
+.Dq points
+to a file is one of the differences between a hard and symbolic link.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.\" ==========
+.It Fl F
+If the proposed link (link_name) already exists and is a directory, then remove it
+so that the link may occur.
+The
+.Fl F
+option should be used with either
+.Fl f
+or
+.Fl i
+options.
+If none is specified,
+.Fl f
+is implied.
+The
+.Fl F
+option is a no-op unless
+.Fl s
+option is specified.
+.It Fl h
+If the
+.Ar link_name
+or
+.Ar link_dirname
+is a symbolic link, do not follow it.
+This is most useful with the
+.Fl f
+option, to replace a symlink which may point to a directory.
+.\" ==========
+.It Fl f
+If the proposed link (link_name) already exists,
+then unlink it so that the link may occur.
+(The
+.Fl f
+option overrides any previous
+.Fl i
+options.)
+.\" ==========
+.It Fl i
+Cause
+.Nm ln
+to write a prompt to standard error if the proposed link exists.
+If the response from the standard input begins with the character
+.Sq Li y
+or
+.Sq Li Y ,
+then unlink the proposed link so that the link may occur.
+Otherwise, do not attempt the link.
+(The
+.Fl i
+option overrides any previous
+.Fl f
+options.)
+.\" ==========
+.It Fl n
+Same as
+.Fl h ,
+for compatibility with other
+.Nm ln
+implementations.
+.\" ==========
+.It Fl s
+Create a symbolic link.
+.\" ==========
+.It Fl v
+Cause
+.Nm ln
+to be verbose, showing files as they are processed.
+.El
+.Pp
+By default,
+.Nm ln
+makes
+.Em hard
+links.
+A hard link to a file is indistinguishable from the original directory entry;
+any changes to a file are effectively independent of the name used to reference
+the file.
+Hard links may not normally refer to directories and may not span file systems.
+.Pp
+A symbolic link contains the name of the file to
+which it is linked.
+The referenced file is used when an
+.Xr open 2
+operation is performed on the link.
+A
+.Xr stat 2
+on a symbolic link will return the linked-to file; an
+.Xr lstat 2
+must be done to obtain information about the link.
+The
+.Xr readlink 2
+call may be used to read the contents of a symbolic link.
+Symbolic links may span file systems and may refer to directories.
+.Pp
+Given one or two arguments,
+.Nm ln
+creates a link to an existing file
+.Ar source_file .
+If
+.Ar link_name
+is given, the link has that name;
+.Ar link_name
+may also be a directory in which to place the link;
+otherwise it is placed in the current directory.
+If only the directory is specified, the link will be made
+to the last component of
+.Ar source_file .
+.Pp
+Given more than two arguments,
+.Nm ln
+makes links in
+.Ar link_dirname
+to all the named source files.
+The links made will have the same name as the files being linked to.
+.Pp
+When the utility is called as
+.Nm link ,
+exactly two arguments must be supplied,
+neither of which may specify a directory.
+No options may be supplied in this simple mode of operation,
+which performs a
+.Xr link 2
+operation using the two passed arguments.
+.Sh COMPATIBILITY
+The
+.Fl h ,
+.Fl i ,
+.Fl n
+and
+.Fl v
+options are non-standard and their use in scripts is not recommended.
+They are provided solely for compatibility with other
+.Nm ln
+implementations.
+.Pp
+The
+.Fl F
+option is
+.Fx
+extention and should not be used in portable scripts.
+.Sh SEE ALSO
+.Xr link 2 ,
+.Xr lstat 2 ,
+.Xr readlink 2 ,
+.Xr stat 2 ,
+.Xr symlink 2 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm ln
+utility conforms to
+.St -p1003.2-92 .
+.Pp
+The simplified
+.Nm link
+command conforms to
+.St -susv2 .
+.Sh HISTORY
+An
+.Nm ln
+command appeared in
+.At v1 .
diff --git a/file_cmds/ln/ln.c b/file_cmds/ln/ln.c
new file mode 100644
index 0000000..0455dce
--- /dev/null
+++ b/file_cmds/ln/ln.c
@@ -0,0 +1,272 @@
+/*-
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1987, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)ln.c 8.2 (Berkeley) 3/31/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ln/ln.c,v 1.34 2006/02/14 11:08:05 glebius Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int fflag; /* Unlink existing files. */
+int Fflag; /* Remove empty directories also. */
+int hflag; /* Check new name for symlink first. */
+int iflag; /* Interactive mode. */
+int sflag; /* Symbolic, not hard, link. */
+int vflag; /* Verbose output. */
+ /* System link call. */
+int (*linkf)(const char *, const char *);
+char linkch;
+
+int linkit(const char *, const char *, int);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ char *p, *sourcedir;
+ int ch, exitval;
+
+ if (argc < 1)
+ usage();
+ /*
+ * Test for the special case where the utility is called as
+ * "link", for which the functionality provided is greatly
+ * simplified.
+ */
+ if ((p = rindex(argv[0], '/')) == NULL)
+ p = argv[0];
+ else
+ ++p;
+ if (strcmp(p, "link") == 0) {
+ while (getopt(argc, argv, "") != -1)
+ usage();
+ argc -= optind;
+ argv += optind;
+ if (argc != 2)
+ usage();
+ linkf = link;
+ /* UNIX conformance requires that both operands be NOT a dir */
+ for (int i = 0; i < 2; i++) {
+ if (stat(argv[i], &sb) == 0 && S_ISDIR(sb.st_mode)){
+ errno = EISDIR;
+ warn("%s", argv[0]);
+ return 1;
+ }
+ }
+
+ exit(linkit(argv[0], argv[1], 0));
+ }
+
+ while ((ch = getopt(argc, argv, "Ffhinsv")) != -1)
+ switch (ch) {
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ iflag = 0;
+ break;
+ case 'h':
+ case 'n':
+ hflag = 1;
+ break;
+ case 'i':
+ iflag = 1;
+ fflag = 0;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ linkf = sflag ? symlink : link;
+ linkch = sflag ? '-' : '=';
+ if (sflag == 0)
+ Fflag = 0;
+ if (Fflag == 1 && iflag == 0)
+ fflag = 1;
+
+ switch(argc) {
+ case 0:
+ usage();
+ /* NOTREACHED */
+ case 1: /* ln target */
+ exit(linkit(argv[0], ".", 1));
+ case 2: /* ln target source */
+ exit(linkit(argv[0], argv[1], 0));
+ default:
+ ;
+ }
+ /* ln target1 target2 directory */
+ sourcedir = argv[argc - 1];
+ if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) {
+ /*
+ * We were asked not to follow symlinks, but found one at
+ * the target--simulate "not a directory" error
+ */
+ errno = ENOTDIR;
+ err(1, "%s", sourcedir);
+ }
+ if (stat(sourcedir, &sb))
+ err(1, "%s", sourcedir);
+ if (!S_ISDIR(sb.st_mode))
+ usage();
+ for (exitval = 0; *argv != sourcedir; ++argv)
+ exitval |= linkit(*argv, sourcedir, 1);
+ exit(exitval);
+}
+
+int
+linkit(const char *target, const char *source, int isdir)
+{
+ struct stat sb;
+ const char *p;
+ int ch, exists, first;
+ char path[PATH_MAX];
+ char bbuf[PATH_MAX];
+
+ if (!sflag) {
+ /* If target doesn't exist, quit now. */
+ if (stat(target, &sb)) {
+ warn("%s", target);
+ return (1);
+ }
+ /* Only symbolic links to directories. */
+ if (S_ISDIR(sb.st_mode)) {
+ errno = EISDIR;
+ warn("%s", target);
+ return (1);
+ }
+ }
+
+ /*
+ * If the source is a directory (and not a symlink if hflag),
+ * append the target's name.
+ */
+ if (isdir ||
+ (lstat(source, &sb) == 0 && S_ISDIR(sb.st_mode)) ||
+ (!hflag && stat(source, &sb) == 0 && S_ISDIR(sb.st_mode))) {
+ if (strlcpy(bbuf, target, sizeof(bbuf)) >= sizeof(bbuf) ||
+ (p = basename(bbuf)) == NULL ||
+ snprintf(path, sizeof(path), "%s/%s", source, p) >=
+ (ssize_t)sizeof(path)) {
+ errno = ENAMETOOLONG;
+ warn("%s", target);
+ return (1);
+ }
+ source = path;
+ }
+
+ exists = !lstat(source, &sb);
+ /*
+ * If the file exists, then unlink it forcibly if -f was specified
+ * and interactively if -i was specified.
+ */
+ if (fflag && exists) {
+ if (Fflag && S_ISDIR(sb.st_mode)) {
+ if (rmdir(source)) {
+ warn("%s", source);
+ return (1);
+ }
+ } else if (unlink(source)) {
+ warn("%s", source);
+ return (1);
+ }
+ } else if (iflag && exists) {
+ fflush(stdout);
+ fprintf(stderr, "replace %s? ", source);
+
+ first = ch = getchar();
+ while(ch != '\n' && ch != EOF)
+ ch = getchar();
+ if (first != 'y' && first != 'Y') {
+ fprintf(stderr, "not replaced\n");
+ return (1);
+ }
+
+ if (Fflag && S_ISDIR(sb.st_mode)) {
+ if (rmdir(source)) {
+ warn("%s", source);
+ return (1);
+ }
+ } else if (unlink(source)) {
+ warn("%s", source);
+ return (1);
+ }
+ }
+
+ /* Attempt the link. */
+ if ((*linkf)(target, source)) {
+ warn("%s", source);
+ return (1);
+ }
+ if (vflag)
+ (void)printf("%s %c> %s\n", source, linkch, target);
+ return (0);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n%s\n",
+ "usage: ln [-Ffhinsv] source_file [link_name]",
+ " ln [-Ffhinsv] source_file ... linkname_dir",
+ " link source_file link_name");
+ exit(1);
+}
diff --git a/file_cmds/ln/symlink.7 b/file_cmds/ln/symlink.7
new file mode 100644
index 0000000..7c6c757
--- /dev/null
+++ b/file_cmds/ln/symlink.7
@@ -0,0 +1,457 @@
+.\"-
+.\" Copyright (c) 1992, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)symlink.7 8.3 (Berkeley) 3/31/94
+.\" $FreeBSD: src/bin/ln/symlink.7,v 1.30 2005/02/13 22:25:09 ru Exp $
+.\"
+.Dd March 31, 1994
+.Dt SYMLINK 7
+.Os
+.Sh NAME
+.Nm symlink
+.Nd symbolic link handling
+.Sh SYMBOLIC LINK HANDLING
+Symbolic links are files that act as pointers to other files.
+To understand their behavior, you must first understand how hard links
+work.
+A hard link to a file is indistinguishable from the original file because
+it is a reference to the object underlying the original file name.
+Changes to a file are independent of the name used to reference the
+file.
+Hard links may not refer to directories and may not reference files
+on different file systems.
+A symbolic link contains the name of the file to which it is linked,
+i.e., it is a pointer to another name, and not to an underlying object.
+For this reason, symbolic links may reference directories and may span
+file systems.
+.Pp
+Because a symbolic link and its referenced object coexist in the file system
+name space, confusion can arise in distinguishing between the link itself
+and the referenced object.
+Historically, commands and system calls have adopted their own link
+following conventions in a somewhat ad-hoc fashion.
+Rules for more a uniform approach, as they are implemented in this system,
+are outlined here.
+It is important that local applications conform to these rules, too,
+so that the user interface can be as consistent as possible.
+.Pp
+Symbolic links are handled either by operating on the link itself,
+or by operating on the object referenced by the link.
+In the latter case,
+an application or system call is said to
+.Dq follow
+the link.
+Symbolic links may reference other symbolic links,
+in which case the links are dereferenced until an object that is
+not a symbolic link is found,
+a symbolic link which references a file which does not exist is found,
+or a loop is detected.
+(Loop detection is done by placing an upper limit on the number of
+links that may be followed, and an error results if this limit is
+exceeded.)
+.Pp
+There are three separate areas that need to be discussed.
+They are as follows:
+.Pp
+.Bl -enum -compact -offset indent
+.It
+Symbolic links used as file name arguments for system calls.
+.It
+Symbolic links specified as command line arguments to utilities that
+are not traversing a file tree.
+.It
+Symbolic links encountered by utilities that are traversing a file tree
+(either specified on the command line or encountered as part of the
+file hierarchy walk).
+.El
+.Ss System calls.
+The first area is symbolic links used as file name arguments for
+system calls.
+.Pp
+Except as noted below, all system calls follow symbolic links.
+For example, if there were a symbolic link
+.Dq Li slink
+which pointed to a file named
+.Dq Li afile ,
+the system call
+.Dq Li open("slink" ...\&)
+would return a file descriptor to the file
+.Dq afile .
+.Pp
+There are nine system calls that do not follow links, and which operate
+on the symbolic link itself.
+They are:
+.Xr lchflags 2 ,
+.Xr lchmod 2 ,
+.Xr lchown 2 ,
+.Xr lstat 2 ,
+.Xr lutimes 3 ,
+.Xr readlink 2 ,
+.Xr rename 2 ,
+.Xr rmdir 2 ,
+and
+.Xr unlink 2 .
+Because
+.Xr remove 3
+is an alias for
+.Xr unlink 2 ,
+it also does not follow symbolic links.
+When
+.Xr rmdir 2
+is applied to a symbolic link, it fails with the error
+.Er ENOTDIR .
+.Pp
+The owner and group of an existing symbolic link can be changed by
+means of the
+.Xr lchown 2
+system call.
+The flags, access permissions, owner/group and modification time of
+an existing symbolic link can be changed by means of the
+.Xr lchflags 2 ,
+.Xr lchmod 2 ,
+.Xr lchown 2 ,
+and
+.Xr lutimes 3
+system calls, respectively.
+Of these, only the flags are used by the system;
+the access permissions and ownership are ignored.
+.Pp
+The
+.Bx 4.4
+system differs from historical
+.Bx 4
+systems in that the system call
+.Xr chown 2
+has been changed to follow symbolic links.
+The
+.Xr lchown 2
+system call was added later when the limitations of the new
+.Xr chown 2
+became apparent.
+.Ss Commands not traversing a file tree.
+The second area is symbolic links, specified as command line file
+name arguments, to commands which are not traversing a file tree.
+.Pp
+Except as noted below, commands follow symbolic links named as command
+line arguments.
+For example, if there were a symbolic link
+.Dq Li slink
+which pointed to a file named
+.Dq Li afile ,
+the command
+.Dq Li cat slink
+would display the contents of the file
+.Dq Li afile .
+.Pp
+It is important to realize that this rule includes commands which may
+optionally traverse file trees, e.g.\& the command
+.Dq Li "chown file"
+is included in this rule, while the command
+.Dq Li "chown -R file"
+is not.
+(The latter is described in the third area, below.)
+.Pp
+If it is explicitly intended that the command operate on the symbolic
+link instead of following the symbolic link, e.g., it is desired that
+.Dq Li "chown slink"
+change the ownership of the file that
+.Dq Li slink
+is, whether it is a symbolic link or not, the
+.Fl h
+option should be used.
+In the above example,
+.Dq Li "chown root slink"
+would change the ownership of the file referenced by
+.Dq Li slink ,
+while
+.Dq Li "chown -h root slink"
+would change the ownership of
+.Dq Li slink
+itself.
+.Pp
+There are four exceptions to this rule.
+The
+.Xr mv 1
+and
+.Xr rm 1
+commands do not follow symbolic links named as arguments,
+but respectively attempt to rename and delete them.
+(Note, if the symbolic link references a file via a relative path,
+moving it to another directory may very well cause it to stop working,
+since the path may no longer be correct.)
+.Pp
+The
+.Xr ls 1
+command is also an exception to this rule.
+For compatibility with historic systems (when
+.Nm ls
+is not doing a tree walk, i.e., the
+.Fl R
+option is not specified),
+the
+.Nm ls
+command follows symbolic links named as arguments if the
+.Fl H
+or
+.Fl L
+option is specified,
+or if the
+.Fl F ,
+.Fl d
+or
+.Fl l
+options are not specified.
+(The
+.Nm ls
+command is the only command where the
+.Fl H
+and
+.Fl L
+options affect its behavior even though it is not doing a walk of
+a file tree.)
+.Pp
+The
+.Xr file 1
+command is also an exception to this rule.
+The
+.Xr file 1
+command does not follow symbolic links named as argument by default.
+The
+.Xr file 1
+command does follow symbolic links named as argument if
+.Fl L
+option is specified.
+.Pp
+The
+.Bx 4.4
+system differs from historical
+.Bx 4
+systems in that the
+.Nm chown
+and
+.Nm chgrp
+commands follow symbolic links specified on the command line.
+.Ss Commands traversing a file tree.
+The following commands either optionally or always traverse file trees:
+.Xr chflags 1 ,
+.Xr chgrp 1 ,
+.Xr chmod 1 ,
+.Xr cp 1 ,
+.Xr du 1 ,
+.Xr find 1 ,
+.Xr ls 1 ,
+.Xr pax 1 ,
+.Xr rm 1 ,
+.Xr tar 1
+and
+.Xr chown 8 .
+.Pp
+It is important to realize that the following rules apply equally to
+symbolic links encountered during the file tree traversal and symbolic
+links listed as command line arguments.
+.Pp
+The first rule applies to symbolic links that reference files that are
+not of type directory.
+Operations that apply to symbolic links are performed on the links
+themselves, but otherwise the links are ignored.
+.Pp
+The command
+.Dq Li "rm -r slink directory"
+will remove
+.Dq Li slink ,
+as well as any symbolic links encountered in the tree traversal of
+.Dq Li directory ,
+because symbolic links may be removed.
+In no case will
+.Nm rm
+affect the file which
+.Dq Li slink
+references in any way.
+.Pp
+The second rule applies to symbolic links that reference files of type
+directory.
+Symbolic links which reference files of type directory are never
+.Dq followed
+by default.
+This is often referred to as a
+.Dq physical
+walk, as opposed to a
+.Dq logical
+walk (where symbolic links referencing directories are followed).
+.Pp
+As consistently as possible, you can make commands doing a file tree
+walk follow any symbolic links named on the command line, regardless
+of the type of file they reference, by specifying the
+.Fl H
+(for
+.Dq half\-logical )
+flag.
+This flag is intended to make the command line name space look
+like the logical name space.
+(Note, for commands that do not always do file tree traversals, the
+.Fl H
+flag will be ignored if the
+.Fl R
+flag is not also specified.)
+.Pp
+For example, the command
+.Dq Li "chown -HR user slink"
+will traverse the file hierarchy rooted in the file pointed to by
+.Dq Li slink .
+Note, the
+.Fl H
+is not the same as the previously discussed
+.Fl h
+flag.
+The
+.Fl H
+flag causes symbolic links specified on the command line to be
+dereferenced both for the purposes of the action to be performed
+and the tree walk, and it is as if the user had specified the
+name of the file to which the symbolic link pointed.
+.Pp
+As consistently as possible, you can make commands doing a file tree
+walk follow any symbolic links named on the command line, as well as
+any symbolic links encountered during the traversal, regardless of
+the type of file they reference, by specifying the
+.Fl L
+(for
+.Dq logical )
+flag.
+This flag is intended to make the entire name space look like
+the logical name space.
+(Note, for commands that do not always do file tree traversals, the
+.Fl L
+flag will be ignored if the
+.Fl R
+flag is not also specified.)
+.Pp
+For example, the command
+.Dq Li "chown -LR user slink"
+will change the owner of the file referenced by
+.Dq Li slink .
+If
+.Dq Li slink
+references a directory,
+.Nm chown
+will traverse the file hierarchy rooted in the directory that it
+references.
+In addition, if any symbolic links are encountered in any file tree that
+.Nm chown
+traverses, they will be treated in the same fashion as
+.Dq Li slink .
+.Pp
+As consistently as possible, you can specify the default behavior by
+specifying the
+.Fl P
+(for
+.Dq physical )
+flag.
+This flag is intended to make the entire name space look like the
+physical name space.
+.Pp
+For commands that do not by default do file tree traversals, the
+.Fl H ,
+.Fl L
+and
+.Fl P
+flags are ignored if the
+.Fl R
+flag is not also specified.
+In addition, you may specify the
+.Fl H ,
+.Fl L
+and
+.Fl P
+options more than once; the last one specified determines the
+command's behavior.
+This is intended to permit you to alias commands to behave one way
+or the other, and then override that behavior on the command line.
+.Pp
+The
+.Xr ls 1
+and
+.Xr rm 1
+commands have exceptions to these rules.
+The
+.Nm rm
+command operates on the symbolic link, and not the file it references,
+and therefore never follows a symbolic link.
+The
+.Nm rm
+command does not support the
+.Fl H ,
+.Fl L
+or
+.Fl P
+options.
+.Pp
+To maintain compatibility with historic systems,
+the
+.Nm ls
+command acts a little differently.
+If you do not specify the
+.Fl F ,
+.Fl d
+or
+.Fl l
+options,
+.Nm ls
+will follow symbolic links specified on the command line.
+If the
+.Fl L
+flag is specified,
+.Nm ls
+follows all symbolic links,
+regardless of their type,
+whether specified on the command line or encountered in the tree walk.
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chgrp 1 ,
+.Xr chmod 1 ,
+.Xr cp 1 ,
+.Xr du 1 ,
+.Xr find 1 ,
+.Xr ln 1 ,
+.Xr ls 1 ,
+.Xr mv 1 ,
+.Xr pax 1 ,
+.Xr rm 1 ,
+.Xr tar 1 ,
+.Xr lchflags 2 ,
+.Xr lchmod 2 ,
+.Xr lchown 2 ,
+.Xr lstat 2 ,
+.Xr lutimes 3 ,
+.Xr readlink 2 ,
+.Xr rename 2 ,
+.Xr symlink 2 ,
+.Xr unlink 2 ,
+.Xr fts 3 ,
+.Xr remove 3 ,
+.Xr chown 8
diff --git a/file_cmds/ls/cmp.c b/file_cmds/ls/cmp.c
new file mode 100644
index 0000000..2ad5edd
--- /dev/null
+++ b/file_cmds/ls/cmp.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)cmp.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/ls/cmp.c,v 1.12 2002/06/30 05:13:54 obrien Exp $");
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fts.h>
+#include <string.h>
+
+#include "ls.h"
+#include "extern.h"
+
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || \
+ defined(_XOPEN_SOURCE) || defined(__NetBSD__)
+#define ATIMENSEC_CMP(x, op, y) ((x)->st_atimensec op (y)->st_atimensec)
+#define CTIMENSEC_CMP(x, op, y) ((x)->st_ctimensec op (y)->st_ctimensec)
+#define MTIMENSEC_CMP(x, op, y) ((x)->st_mtimensec op (y)->st_mtimensec)
+#define BTIMENSEC_CMP(x, op, y) ((x)->st_birthtimensec op (y)->st_birthtimensec)
+#else
+#define ATIMENSEC_CMP(x, op, y) \
+ ((x)->st_atimespec.tv_nsec op (y)->st_atimespec.tv_nsec)
+#define CTIMENSEC_CMP(x, op, y) \
+ ((x)->st_ctimespec.tv_nsec op (y)->st_ctimespec.tv_nsec)
+#define MTIMENSEC_CMP(x, op, y) \
+ ((x)->st_mtimespec.tv_nsec op (y)->st_mtimespec.tv_nsec)
+#define BTIMENSEC_CMP(x, op, y) \
+ ((x)->st_birthtimespec.tv_nsec op (y)->st_birthtimespec.tv_nsec)
+#endif
+
+int
+namecmp(const FTSENT *a, const FTSENT *b)
+{
+ return (strcoll(a->fts_name, b->fts_name));
+}
+
+int
+revnamecmp(const FTSENT *a, const FTSENT *b)
+{
+ return (strcoll(b->fts_name, a->fts_name));
+}
+
+int
+modcmp(const FTSENT *a, const FTSENT *b)
+{
+ if (b->fts_statp->st_mtime > a->fts_statp->st_mtime)
+ return (1);
+ else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime)
+ return (-1);
+ else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+ return (1);
+ else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+ return (-1);
+ else
+ return (namecmp(a, b));
+}
+
+int
+revmodcmp(const FTSENT *a, const FTSENT *b)
+{
+ if (b->fts_statp->st_mtime > a->fts_statp->st_mtime)
+ return (-1);
+ else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime)
+ return (1);
+ else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+ return (-1);
+ else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+ return (1);
+ else
+ return (revnamecmp(a, b));
+}
+
+int
+acccmp(const FTSENT *a, const FTSENT *b)
+{
+ if (b->fts_statp->st_atime > a->fts_statp->st_atime)
+ return (1);
+ else if (b->fts_statp->st_atime < a->fts_statp->st_atime)
+ return (-1);
+ else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+ return (1);
+ else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+ return (-1);
+ else
+ return (namecmp(a, b));
+}
+
+int
+revacccmp(const FTSENT *a, const FTSENT *b)
+{
+ if (b->fts_statp->st_atime > a->fts_statp->st_atime)
+ return (-1);
+ else if (b->fts_statp->st_atime < a->fts_statp->st_atime)
+ return (1);
+ else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+ return (-1);
+ else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+ return (1);
+ else
+ return (revnamecmp(a, b));
+}
+
+int
+statcmp(const FTSENT *a, const FTSENT *b)
+{
+ if (b->fts_statp->st_ctime > a->fts_statp->st_ctime)
+ return (1);
+ else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime)
+ return (-1);
+ else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+ return (1);
+ else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+ return (-1);
+ else
+ return (namecmp(a, b));
+}
+
+int
+revstatcmp(const FTSENT *a, const FTSENT *b)
+{
+ if (b->fts_statp->st_ctime > a->fts_statp->st_ctime)
+ return (-1);
+ else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime)
+ return (1);
+ else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+ return (-1);
+ else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+ return (1);
+ else
+ return (revnamecmp(a, b));
+}
+
+int
+sizecmp(a, b)
+ const FTSENT *a, *b;
+{
+ if (b->fts_statp->st_size > a->fts_statp->st_size)
+ return (1);
+ if (b->fts_statp->st_size < a->fts_statp->st_size)
+ return (-1);
+ else
+ return (namecmp(a, b));
+}
+
+int
+revsizecmp(a, b)
+ const FTSENT *a, *b;
+{
+ if (b->fts_statp->st_size > a->fts_statp->st_size)
+ return (-1);
+ if (b->fts_statp->st_size < a->fts_statp->st_size)
+ return (1);
+ else
+ return (revnamecmp(a, b));
+}
+
+int
+birthcmp(const FTSENT *a, const FTSENT *b)
+{
+ if (b->fts_statp->st_birthtime > a->fts_statp->st_birthtime)
+ return (1);
+ else if (b->fts_statp->st_birthtime < a->fts_statp->st_birthtime)
+ return (-1);
+ else if (BTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+ return (1);
+ else if (BTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+ return (-1);
+ else
+ return (namecmp(a, b));
+}
+
+int
+revbirthcmp(const FTSENT *a, const FTSENT *b)
+{
+ if (b->fts_statp->st_birthtime > a->fts_statp->st_birthtime)
+ return (-1);
+ else if (b->fts_statp->st_birthtime < a->fts_statp->st_birthtime)
+ return (1);
+ else if (BTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+ return (-1);
+ else if (BTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+ return (1);
+ else
+ return (revnamecmp(a, b));
+}
diff --git a/file_cmds/ls/extern.h b/file_cmds/ls/extern.h
new file mode 100644
index 0000000..a33bd97
--- /dev/null
+++ b/file_cmds/ls/extern.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)extern.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: src/bin/ls/extern.h,v 1.19 2002/05/19 02:51:36 tjr Exp $
+ */
+
+#ifndef _LS_EXTERN_H_
+#define _LS_EXTERN_H_
+
+int acccmp(const FTSENT *, const FTSENT *);
+int revacccmp(const FTSENT *, const FTSENT *);
+int modcmp(const FTSENT *, const FTSENT *);
+int revmodcmp(const FTSENT *, const FTSENT *);
+int namecmp(const FTSENT *, const FTSENT *);
+int revnamecmp(const FTSENT *, const FTSENT *);
+int statcmp(const FTSENT *, const FTSENT *);
+int revstatcmp(const FTSENT *, const FTSENT *);
+int sizecmp (const FTSENT *, const FTSENT *);
+int revsizecmp (const FTSENT *, const FTSENT *);
+int birthcmp(const FTSENT *, const FTSENT *);
+int revbirthcmp(const FTSENT *, const FTSENT *);
+
+void printcol(DISPLAY *);
+void printlong(DISPLAY *);
+void printscol(DISPLAY *);
+void printstream(DISPLAY *);
+void usage(void);
+int prn_normal(const char *);
+size_t len_octal(const char *, int);
+int prn_octal(const char *);
+int prn_printable(const char *);
+#ifdef COLORLS
+void parsecolors(const char *cs);
+void colorquit(int);
+
+extern char *ansi_fgcol;
+extern char *ansi_bgcol;
+extern char *ansi_coloff;
+extern char *attrs_off;
+extern char *enter_bold;
+#endif
+
+#endif /* _LS_EXTERN_H_ */
diff --git a/file_cmds/ls/ls.1 b/file_cmds/ls/ls.1
new file mode 100644
index 0000000..b75c1ae
--- /dev/null
+++ b/file_cmds/ls/ls.1
@@ -0,0 +1,715 @@
+.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 acknowledgment:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ls.1 8.7 (Berkeley) 7/29/94
+.\" $FreeBSD: src/bin/ls/ls.1,v 1.69 2002/08/21 17:32:34 trhodes Exp $
+.\"
+.Dd May 19, 2002
+.Dt LS 1
+.Os
+.Sh NAME
+.Nm ls
+.Nd list directory contents
+.Sh SYNOPSIS
+.Nm ls
+.Op Fl ABCFGHLOPRSTUW@abcdefghiklmnopqrstuwx1%
+.Op Ar
+.Sh DESCRIPTION
+For each operand that names a
+.Ar file
+of a type other than
+directory,
+.Nm ls
+displays its name as well as any requested,
+associated information.
+For each operand that names a
+.Ar file
+of type directory,
+.Nm ls
+displays the names of files contained
+within that directory, as well as any requested, associated
+information.
+.Pp
+If no operands are given, the contents of the current
+directory are displayed.
+If more than one operand is given,
+non-directory operands are displayed first; directory
+and non-directory operands are sorted separately and in
+lexicographical order.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl @
+Display extended attribute keys and sizes in long
+.Pq Fl l
+output.
+.It Fl 1
+(The numeric digit
+.Dq one . )
+Force output to be
+one entry per line.
+This is the default when
+output is not to a terminal.
+.It Fl A
+List all entries except for
+.Pa \&.
+and
+.Pa .. .
+Always set for the super-user.
+.It Fl a
+Include directory entries whose names begin with a
+dot
+.Pq Pa \&. .
+.It Fl B
+Force printing of non-printable characters (as defined by
+.Xr ctype 3
+and current locale settings) in file names as
+.Li \e Ns Va xxx ,
+where
+.Va xxx
+is the numeric value of the character in octal.
+.It Fl b
+As
+.Fl B ,
+but use
+.Tn C
+escape codes whenever possible.
+.It Fl C
+Force multi-column output; this is the default when output is to a terminal.
+.It Fl c
+Use time when file status was last changed for sorting
+.Pq Fl t
+or long printing
+.Pq Fl l .
+.It Fl d
+Directories are listed as plain files (not searched recursively).
+.It Fl e
+Print the Access Control List (ACL) associated with the file, if present, in long
+.Pq Fl l
+output.
+.It Fl F
+Display a slash
+.Pq Ql /
+immediately after each pathname that is a directory,
+an asterisk
+.Pq Ql *
+after each that is executable,
+an at sign
+.Pq Ql @
+after each symbolic link,
+an equals sign
+.Pq Ql =
+after each socket,
+a percent sign
+.Pq Ql %
+after each whiteout,
+and a vertical bar
+.Pq Ql \&|
+after each that is a
+.Tn FIFO .
+.It Fl f
+Output is not sorted.
+This option turns on the
+.Fl a
+option.
+.It Fl G
+Enable colorized output.
+This option is equivalent to defining
+.Ev CLICOLOR
+in the environment.
+(See below.)
+.It Fl g
+This option is only available for compatibility with POSIX;
+it is used to display the group name in the long
+.Pq Fl l
+format output (the owner name is suppressed).
+.It Fl H
+Symbolic links on the command line are followed.
+This option is assumed if
+none of the
+.Fl F , d ,
+or
+.Fl l
+options are specified.
+.It Fl h
+When used with the
+.Fl l
+option, use unit suffixes: Byte, Kilobyte, Megabyte, Gigabyte, Terabyte
+and Petabyte in order to reduce the number of digits to three or less
+using base 2 for sizes.
+.It Fl i
+For each file, print the file's file serial number (inode number).
+.It Fl k
+If the
+.Fl s
+option is specified, print the file size allocation in kilobytes,
+not blocks.
+This option overrides the environment variable
+.Ev BLOCKSIZE .
+.It Fl L
+Follow all symbolic links to final target and list the file or directory the link references
+rather than the link itself.
+This option cancels the
+.Fl P
+option.
+.It Fl l
+(The lowercase letter
+.Dq ell . )
+List in long format.
+(See below.)
+A total sum for all the file
+sizes is output on a line before the long listing.
+.It Fl m
+Stream output format; list files across the page, separated by commas.
+.It Fl n
+Display user and group IDs numerically,
+rather than converting to a user or group name in a long
+.Pq Fl l
+output.
+This option turns on the
+.Fl l
+option.
+.It Fl O
+Include the file flags in a long
+.Pq Fl l
+output.
+.It Fl o
+List in long format, but omit the group id.
+.It Fl P
+If argument is a symbolic link, list the link itself rather than the
+object the link references.
+This option cancels the
+.Fl H
+and
+.Fl L
+options.
+.It Fl p
+Write a slash
+.Pq Ql /
+after each filename if that file is a directory.
+.It Fl q
+Force printing of non-graphic characters in file names as
+the character
+.Ql \&? ;
+this is the default when output is to a terminal.
+.It Fl R
+Recursively list subdirectories encountered.
+.It Fl r
+Reverse the order of the sort to get reverse
+lexicographical order or the oldest entries first (or largest files
+last, if combined with sort by size
+.It Fl S
+Sort files by size
+.It Fl s
+Display the number of file system blocks actually used by each file, in units
+of 512 bytes, where partial units are rounded up to the next integer value.
+If the output is to a terminal, a total sum for all the file
+sizes is output on a line before the listing.
+The environment variable
+.Ev BLOCKSIZE
+overrides the unit size of 512 bytes.
+.It Fl T
+When used with the
+.Fl l
+(lowercase letter
+.Dq ell )
+option, display complete time information for the file, including
+month, day, hour, minute, second, and year.
+.It Fl t
+Sort by time modified (most recently modified
+first) before sorting the operands by lexicographical
+order.
+.It Fl u
+Use time of last access,
+instead of last modification
+of the file for sorting
+.Pq Fl t
+or long printing
+.Pq Fl l .
+.It Fl U
+Use time of file creation, instead of last modification for sorting
+.Pq Fl t
+or long output
+.Pq Fl l .
+.It Fl v
+Force unedited printing of non-graphic characters; this is the default when
+output is not to a terminal.
+.It Fl W
+Display whiteouts when scanning directories.
+.Pq Fl S
+flag).
+.It Fl w
+Force raw printing of non-printable characters.
+This is the default
+when output is not to a terminal.
+.It Fl x
+The same as
+.Fl C ,
+except that the multi-column output is produced with entries sorted
+across, rather than down, the columns.
+.It Fl %
+Distinguish dataless files and directories with a '%' character in long
+.Pq Fl l
+output, and don't materialize dataless directories when listing them.
+.El
+.Pp
+The
+.Fl 1 , C , x ,
+and
+.Fl l
+options all override each other;
+the last one specified determines the format used.
+.Pp
+The
+.Fl c
+and
+.Fl u
+options override each other; the last one specified determines
+the file time used.
+.Pp
+The
+.Fl B , b , w ,
+and
+.Fl q
+options all override each other;
+the last one specified determines the format used
+for non-printable characters.
+.Pp
+The
+.Fl H , L
+and
+.Fl P
+options all override each other (either partially or fully); they
+are applied in the order specified.
+.Pp
+By default,
+.Nm ls
+lists one entry per line to standard
+output; the exceptions are to terminals or when the
+.Fl C
+or
+.Fl x
+options are specified.
+.Pp
+File information is displayed with one or more
+.Ao blank Ac Ns s
+separating the information associated with the
+.Fl i , s ,
+and
+.Fl l
+options.
+.Ss The Long Format
+If the
+.Fl l
+option is given, the following information
+is displayed for each file:
+file mode,
+number of links, owner name, group name,
+number of bytes in the file, abbreviated
+month, day-of-month file was last modified,
+hour file last modified, minute file last
+modified, and the pathname.
+In addition, for each directory whose contents are displayed,
+the total number of 512-byte blocks used by the files in the directory
+is displayed on a line by itself,
+immediately before the information for the files in the directory.
+If the file or directory has extended attributes,
+the permissions field printed by the
+.Fl l
+option is followed by a '@' character.
+Otherwise, if the file or directory has extended security information
+(such as an access control list),
+the permissions field printed by the
+.Fl l
+option is followed by a '+' character.
+If the
+.Fl %
+option is given, a '%' character follows the permissions field
+for dataless files and directories,
+possibly replacing the '@' or '+' character.
+.Pp
+If the modification time of the file
+is more than 6 months in the past or future,
+then the year of the last modification
+is displayed in place of the hour and minute fields.
+.Pp
+If the owner or group names are not a known user or group name,
+or the
+.Fl n
+option is given,
+the numeric ID's are displayed.
+.Pp
+If the file is a character special or block special file,
+the major and minor device numbers for the file are displayed
+in the size field.
+If the file is a symbolic link,
+the pathname of the linked-to file is preceded by
+.Dq Li -> .
+.Pp
+The file mode printed under the
+.Fl l
+option consists of the
+entry type, owner permissions, and group permissions.
+The entry type character describes the type of file,
+as follows:
+.Pp
+.Bl -tag -width 4n -offset indent -compact
+.It Sy b
+Block special file.
+.It Sy c
+Character special file.
+.It Sy d
+Directory.
+.It Sy l
+Symbolic link.
+.It Sy s
+Socket link.
+.It Sy p
+.Tn FIFO .
+.It Sy \-
+Regular file.
+.El
+.Pp
+The next three fields
+are three characters each:
+owner permissions,
+group permissions, and
+other permissions.
+Each field has three character positions:
+.Bl -enum -offset indent
+.It
+If
+.Sy r ,
+the file is readable; if
+.Sy \- ,
+it is not readable.
+.It
+If
+.Sy w ,
+the file is writable; if
+.Sy \- ,
+it is not writable.
+.It
+The first of the following that applies:
+.Bl -tag -width 4n -offset indent
+.It Sy S
+If in the owner permissions, the file is not executable and
+set-user-ID mode is set.
+If in the group permissions, the file is not executable
+and set-group-ID mode is set.
+.It Sy s
+If in the owner permissions, the file is executable
+and set-user-ID mode is set.
+If in the group permissions, the file is executable
+and setgroup-ID mode is set.
+.It Sy x
+The file is executable or the directory is
+searchable.
+.It Sy \-
+The file is neither readable, writable, executable,
+nor set-user-ID nor set-group-ID mode, nor sticky.
+(See below.)
+.El
+.Pp
+These next two apply only to the third character in the last group
+(other permissions).
+.Bl -tag -width 4n -offset indent
+.It Sy T
+The sticky bit is set
+(mode
+.Li 1000 ) ,
+but not execute or search permission.
+(See
+.Xr chmod 1
+or
+.Xr sticky 8 . )
+.It Sy t
+The sticky bit is set (mode
+.Li 1000 ) ,
+and is searchable or executable.
+(See
+.Xr chmod 1
+or
+.Xr sticky 8 . )
+.El
+.El
+.Sh EXAMPLES
+The following is how to do an
+.Nm ls
+listing sorted by increasing size
+.Pp
+.Dl "ls -lrS"
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm ls :
+.Bl -tag -width ".Ev CLICOLOR_FORCE"
+.It Ev BLOCKSIZE
+If the environment variable
+.Ev BLOCKSIZE
+is set, the block counts
+(see
+.Fl s )
+will be displayed in units of that size block.
+.It Ev CLICOLOR
+Use
+\*[Ai]
+color sequences to distinguish file types.
+See
+.Ev LSCOLORS
+below.
+In addition to the file types mentioned in the
+.Fl F
+option some extra attributes (setuid bit set, etc.) are also displayed.
+The colorization is dependent on a terminal type with the proper
+.Xr termcap 5
+capabilities.
+The default
+.Dq Li cons25
+console has the proper capabilities,
+but to display the colors in an
+.Xr xterm 1 ,
+for example,
+the
+.Ev TERM
+variable must be set to
+.Dq Li xterm-color .
+Other terminal types may require similar adjustments.
+Colorization
+is silently disabled if the output isn't directed to a terminal
+unless the
+.Ev CLICOLOR_FORCE
+variable is defined.
+.It Ev CLICOLOR_FORCE
+Color sequences are normally disabled if the output isn't directed to
+a terminal.
+This can be overridden by setting this flag.
+The
+.Ev TERM
+variable still needs to reference a color capable terminal however
+otherwise it is not possible to determine which color sequences to
+use.
+.It Ev COLUMNS
+If this variable contains a string representing a
+decimal integer, it is used as the
+column position width for displaying
+multiple-text-column output.
+The
+.Nm ls
+utility calculates how
+many pathname text columns to display
+based on the width provided.
+(See
+.Fl C
+and
+.Fl x . )
+.It Ev LANG
+The locale to use when determining the order of day and month in the long
+.Fl l
+format output.
+See
+.Xr environ 7
+for more information.
+.It Ev LSCOLORS
+The value of this variable describes what color to use for which
+attribute when colors are enabled with
+.Ev CLICOLOR .
+This string is a concatenation of pairs of the format
+.Ar f Ns Ar b ,
+where
+.Ar f
+is the foreground color and
+.Ar b
+is the background color.
+.Pp
+The color designators are as follows:
+.Pp
+.Bl -tag -width 4n -offset indent -compact
+.It Sy a
+black
+.It Sy b
+red
+.It Sy c
+green
+.It Sy d
+brown
+.It Sy e
+blue
+.It Sy f
+magenta
+.It Sy g
+cyan
+.It Sy h
+light grey
+.It Sy A
+bold black, usually shows up as dark grey
+.It Sy B
+bold red
+.It Sy C
+bold green
+.It Sy D
+bold brown, usually shows up as yellow
+.It Sy E
+bold blue
+.It Sy F
+bold magenta
+.It Sy G
+bold cyan
+.It Sy H
+bold light grey; looks like bright white
+.It Sy x
+default foreground or background
+.El
+.Pp
+Note that the above are standard
+\*[Ai]
+colors.
+The actual display may differ
+depending on the color capabilities of the terminal in use.
+.Pp
+The order of the attributes are as follows:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+directory
+.It
+symbolic link
+.It
+socket
+.It
+pipe
+.It
+executable
+.It
+block special
+.It
+character special
+.It
+executable with setuid bit set
+.It
+executable with setgid bit set
+.It
+directory writable to others, with sticky bit
+.It
+directory writable to others, without sticky bit
+.El
+.Pp
+The default is
+.Qq "exfxcxdxbxegedabagacad" ,
+i.e. blue foreground and
+default background for regular directories, black foreground and red
+background for setuid executables, etc.
+.It Ev LS_COLWIDTHS
+If this variable is set, it is considered to be a
+colon-delimited list of minimum column widths.
+Unreasonable
+and insufficient widths are ignored (thus zero signifies
+a dynamically sized column).
+Not all columns have changeable widths.
+The fields are,
+in order: inode, block count, number of links, user name,
+group name, flags, file size, file name.
+.It Ev TERM
+The
+.Ev CLICOLOR
+functionality depends on a terminal type with color capabilities.
+.It Ev TZ
+The timezone to use when displaying dates.
+See
+.Xr environ 7
+for more information.
+.El
+.Sh COMPATIBILITY
+The group field is now automatically included in the long listing for
+files in order to be compatible with the
+.St -p1003.2
+specification.
+.Sh LEGACY DESCRIPTION
+In legacy mode, the
+.Fl f
+option does not turn on the
+.Fl a
+option and the
+.Fl g ,
+.Fl n ,
+and
+.Fl o
+options do not turn on the
+.Fl l
+option.
+.Pp
+Also, the
+.Fl o
+option causes the file flags to be included in a long (-l) output;
+there is no
+.Fl O
+option.
+.Pp
+When
+.Fl H
+is specified (and not overridden by
+.Fl L
+or
+.Fl P )
+and a file argument is a symlink
+that resolves to a non-directory file,
+the output will reflect the nature of the link,
+rather than that of the file.
+In legacy operation, the output will describe the file.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chmod 1 ,
+.Xr sort 1 ,
+.Xr xterm 1 ,
+.Xr compat 5 ,
+.Xr termcap 5 ,
+.Xr symlink 7 ,
+.Xr sticky 8
+.Sh STANDARDS
+The
+.Nm ls
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+An
+.Nm ls
+command appeared in
+.At v1 .
+.Sh BUGS
+To maintain backward compatibility, the relationships between the many
+options are quite complex.
diff --git a/file_cmds/ls/ls.c b/file_cmds/ls/ls.c
new file mode 100644
index 0000000..e079333
--- /dev/null
+++ b/file_cmds/ls/ls.c
@@ -0,0 +1,977 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)ls.c 8.5 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/ls/ls.c,v 1.66 2002/09/21 01:28:36 wollman Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <limits.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef COLORLS
+#include <termcap.h>
+#include <signal.h>
+#endif
+#ifdef __APPLE__
+#include <sys/acl.h>
+#include <sys/xattr.h>
+#include <sys/param.h>
+#include <get_compat.h>
+#include <sys/sysctl.h>
+#include <System/sys/fsctl.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+#include "ls.h"
+#include "extern.h"
+
+/*
+ * Upward approximation of the maximum number of characters needed to
+ * represent a value of integral type t as a string, excluding the
+ * NUL terminator, with provision for a sign.
+ */
+#define STRBUF_SIZEOF(t) (1 + CHAR_BIT * sizeof(t) / 3 + 1)
+
+#define IS_DATALESS(sp) (f_dataless && (sp) && ((sp)->st_flags & SF_DATALESS))
+
+static void display(FTSENT *, FTSENT *);
+static u_quad_t makenines(u_quad_t);
+static int mastercmp(const FTSENT **, const FTSENT **);
+static void traverse(int, char **, int);
+
+static void (*printfcn)(DISPLAY *);
+static int (*sortfcn)(const FTSENT *, const FTSENT *);
+
+long blocksize; /* block size units */
+int termwidth = 80; /* default terminal width */
+
+/* flags */
+ int f_accesstime; /* use time of last access */
+ int f_birthtime; /* use time of file birth */
+ int f_flags; /* show flags associated with a file */
+ int f_humanval; /* show human-readable file sizes */
+ int f_inode; /* print inode */
+static int f_kblocks; /* print size in kilobytes */
+static int f_listdir; /* list actual directory, not contents */
+static int f_listdot; /* list files beginning with . */
+ int f_longform; /* long listing format */
+ int f_nonprint; /* show unprintables as ? */
+static int f_nosort; /* don't sort output */
+ int f_notabs; /* don't use tab-separated multi-col output */
+ int f_numericonly; /* don't convert uid/gid to name */
+ int f_octal; /* show unprintables as \xxx */
+ int f_octal_escape; /* like f_octal but use C escapes if possible */
+static int f_recursive; /* ls subdirectories also */
+static int f_reversesort; /* reverse whatever sort is used */
+ int f_sectime; /* print the real time for all files */
+static int f_singlecol; /* use single column output */
+ int f_size; /* list size in short listing */
+ int f_slash; /* similar to f_type, but only for dirs */
+ int f_sortacross; /* sort across rows, not down columns */
+ int f_statustime; /* use time of last mode change */
+ int f_stream; /* stream the output, separate with commas */
+static int f_timesort; /* sort by time vice name */
+static int f_sizesort; /* sort by size */
+ int f_type; /* add type character for non-regular files */
+static int f_whiteout; /* show whiteout entries */
+ int f_acl; /* show ACLs in long listing */
+ int f_xattr; /* show extended attributes in long listing */
+ int f_group; /* show group */
+ int f_owner; /* show owner */
+ int f_dataless; /* distinguish dataless files in long listing,
+ and don't materialize dataless directories. */
+#ifdef COLORLS
+ int f_color; /* add type in color for non-regular files */
+
+char *ansi_bgcol; /* ANSI sequence to set background colour */
+char *ansi_fgcol; /* ANSI sequence to set foreground colour */
+char *ansi_coloff; /* ANSI sequence to reset colours */
+char *attrs_off; /* ANSI sequence to turn off attributes */
+char *enter_bold; /* ANSI sequence to set color to bold mode */
+#endif
+
+static int rval;
+
+int
+main(int argc, char *argv[])
+{
+ static char dot[] = ".", *dotav[] = {dot, NULL};
+ struct winsize win;
+ int ch, fts_options, notused;
+ char *p;
+#ifdef COLORLS
+ char termcapbuf[1024]; /* termcap definition buffer */
+ char tcapbuf[512]; /* capability buffer */
+ char *bp = tcapbuf;
+#endif
+
+ if (argc < 1)
+ usage();
+ (void)setlocale(LC_ALL, "");
+
+ /* Terminal defaults to -Cq, non-terminal defaults to -1. */
+ if (isatty(STDOUT_FILENO)) {
+ termwidth = 80;
+ if ((p = getenv("COLUMNS")) != NULL && *p != '\0')
+ termwidth = atoi(p);
+ else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) != -1 &&
+ win.ws_col > 0)
+ termwidth = win.ws_col;
+ f_nonprint = 1;
+ } else {
+ f_singlecol = 1;
+ /* retrieve environment variable, in case of explicit -C */
+ p = getenv("COLUMNS");
+ if (p)
+ termwidth = atoi(p);
+ }
+
+ /* Root is -A automatically. */
+ if (!getuid())
+ f_listdot = 1;
+
+ fts_options = FTS_PHYSICAL;
+ while ((ch = getopt(argc, argv, "1@ABCFGHLOPRSTUWabcdefghiklmnopqrstuvwx%"))
+ != -1) {
+ switch (ch) {
+ /*
+ * The -1, -C, -x and -l options all override each other so
+ * shell aliasing works right.
+ */
+ case '1':
+ f_singlecol = 1;
+ f_longform = 0;
+ f_stream = 0;
+ break;
+ case 'B':
+ f_nonprint = 0;
+ f_octal = 1;
+ f_octal_escape = 0;
+ break;
+ case 'C':
+ f_sortacross = f_longform = f_singlecol = 0;
+ break;
+ case 'l':
+ f_longform = 1;
+ f_singlecol = 0;
+ f_stream = 0;
+ break;
+ case 'x':
+ f_sortacross = 1;
+ f_longform = 0;
+ f_singlecol = 0;
+ break;
+ /* The -c and -u options override each other. */
+ case 'c':
+ f_statustime = 1;
+ f_accesstime = f_birthtime = 0;
+ break;
+ case 'u':
+ f_accesstime = 1;
+ f_statustime = f_birthtime = 0;
+ break;
+ case 'U':
+ f_birthtime = 1;
+ f_statustime = f_accesstime = 0;
+ break;
+ case 'F':
+ f_type = 1;
+ f_slash = 0;
+ break;
+ case 'H':
+ if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ fts_options &= ~FTS_LOGICAL;
+ fts_options |= FTS_PHYSICAL;
+ fts_options |= FTS_COMFOLLOWDIR;
+ } else
+ fts_options |= FTS_COMFOLLOW;
+ break;
+ case 'G':
+ setenv("CLICOLOR", "", 1);
+ break;
+ case 'L':
+ fts_options &= ~FTS_PHYSICAL;
+ fts_options |= FTS_LOGICAL;
+ if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ fts_options &= ~(FTS_COMFOLLOW|FTS_COMFOLLOWDIR);
+ }
+ break;
+ case 'P':
+ fts_options &= ~(FTS_COMFOLLOW|FTS_COMFOLLOWDIR);
+ fts_options &= ~FTS_LOGICAL;
+ fts_options |= FTS_PHYSICAL;
+ break;
+ case 'R':
+ f_recursive = 1;
+ break;
+ case 'a':
+ fts_options |= FTS_SEEDOT;
+ /* FALLTHROUGH */
+ case 'A':
+ f_listdot = 1;
+ break;
+ /* The -d option turns off the -R option. */
+ case 'd':
+ f_listdir = 1;
+ f_recursive = 0;
+ break;
+ case 'f':
+ f_nosort = 1;
+ if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ fts_options |= FTS_SEEDOT;
+ f_listdot = 1;
+ }
+ break;
+ case 'g': /* Compatibility with Unix03 */
+ if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ f_group = 1;
+ f_longform = 1;
+ f_singlecol = 0;
+ f_stream = 0;
+ }
+ break;
+ case 'h':
+ f_humanval = 1;
+ break;
+ case 'i':
+ f_inode = 1;
+ break;
+ case 'k':
+ f_kblocks = 1;
+ break;
+ case 'm':
+ f_stream = 1;
+ f_singlecol = 0;
+ f_longform = 0;
+ break;
+ case 'n':
+ f_numericonly = 1;
+ if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ f_longform = 1;
+ f_singlecol = 0;
+ f_stream = 0;
+ }
+ break;
+ case 'o':
+ if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ f_owner = 1;
+ f_longform = 1;
+ f_singlecol = 0;
+ f_stream = 0;
+ } else {
+ f_flags = 1;
+ }
+ break;
+ case 'p':
+ f_slash = 1;
+ f_type = 1;
+ break;
+ case 'q':
+ f_nonprint = 1;
+ f_octal = 0;
+ f_octal_escape = 0;
+ break;
+ case 'r':
+ f_reversesort = 1;
+ break;
+ case 'S':
+ /* Darwin 1.4.1 compatibility */
+ f_sizesort = 1;
+ break;
+ case 's':
+ f_size = 1;
+ break;
+ case 'T':
+ f_sectime = 1;
+ break;
+ case 't':
+ f_timesort = 1;
+ break;
+ case 'W':
+ f_whiteout = 1;
+ break;
+ case 'v':
+ /* Darwin 1.4.1 compatibility */
+ f_nonprint = 0;
+ break;
+ case 'b':
+ f_nonprint = 0;
+ f_octal = 0;
+ f_octal_escape = 1;
+ break;
+ case 'w':
+ f_nonprint = 0;
+ f_octal = 0;
+ f_octal_escape = 0;
+ break;
+ case 'e':
+ f_acl = 1;
+ break;
+ case '@':
+ f_xattr = 1;
+ break;
+ case 'O':
+ f_flags = 1;
+ break;
+ case '%':
+ f_dataless = 1;
+ break;
+ default:
+ case '?':
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Enabling of colours is conditional on the environment. */
+ if (getenv("CLICOLOR") &&
+ (isatty(STDOUT_FILENO) || getenv("CLICOLOR_FORCE")))
+#ifdef COLORLS
+ if (tgetent(termcapbuf, getenv("TERM")) == 1) {
+ ansi_fgcol = tgetstr("AF", &bp);
+ ansi_bgcol = tgetstr("AB", &bp);
+ attrs_off = tgetstr("me", &bp);
+ enter_bold = tgetstr("md", &bp);
+
+ /* To switch colours off use 'op' if
+ * available, otherwise use 'oc', or
+ * don't do colours at all. */
+ ansi_coloff = tgetstr("op", &bp);
+ if (!ansi_coloff)
+ ansi_coloff = tgetstr("oc", &bp);
+ if (ansi_fgcol && ansi_bgcol && ansi_coloff)
+ f_color = 1;
+ }
+#else
+ (void)fprintf(stderr, "Color support not compiled in.\n");
+#endif /*COLORLS*/
+
+#ifdef COLORLS
+ if (f_color) {
+ /*
+ * We can't put tabs and color sequences together:
+ * column number will be incremented incorrectly
+ * for "stty oxtabs" mode.
+ */
+ f_notabs = 1;
+ (void)signal(SIGINT, colorquit);
+ (void)signal(SIGQUIT, colorquit);
+ parsecolors(getenv("LSCOLORS"));
+ }
+#endif
+
+ /*
+ * If not -F, -i, -l, -s, -t or -% options, don't require stat
+ * information, unless in color mode in which case we do
+ * need this to determine which colors to display.
+ */
+ if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type && !f_sizesort && !f_dataless
+#ifdef COLORLS
+ && !f_color
+#endif
+ )
+ fts_options |= FTS_NOSTAT;
+
+ /*
+ * If not -F, -d or -l options, follow any symbolic links listed on
+ * the command line.
+ */
+ if (!f_longform && !f_listdir && !f_type && !f_inode)
+ fts_options |= FTS_COMFOLLOW;
+
+ /*
+ * If -W, show whiteout entries
+ */
+#ifdef FTS_WHITEOUT
+ if (f_whiteout)
+ fts_options |= FTS_WHITEOUT;
+#endif
+
+ /* If -l or -s, figure out block size. */
+ if (f_longform || f_size) {
+ if (f_kblocks)
+ blocksize = 2;
+ else {
+ (void)getbsize(&notused, &blocksize);
+ blocksize /= 512;
+ }
+ }
+ /* Select a sort function. */
+ if (f_reversesort) {
+ if (f_sizesort)
+ sortfcn = revsizecmp;
+ else if (!f_timesort)
+ sortfcn = revnamecmp;
+ else if (f_accesstime)
+ sortfcn = revacccmp;
+ else if (f_statustime)
+ sortfcn = revstatcmp;
+ else if (f_birthtime)
+ sortfcn = revbirthcmp;
+ else /* Use modification time. */
+ sortfcn = revmodcmp;
+ } else {
+ if (f_sizesort)
+ sortfcn = sizecmp;
+ else if (!f_timesort)
+ sortfcn = namecmp;
+ else if (f_accesstime)
+ sortfcn = acccmp;
+ else if (f_statustime)
+ sortfcn = statcmp;
+ else if (f_birthtime)
+ sortfcn = birthcmp;
+ else /* Use modification time. */
+ sortfcn = modcmp;
+ }
+
+ /* Select a print function. */
+ if (f_singlecol)
+ printfcn = printscol;
+ else if (f_longform)
+ printfcn = printlong;
+ else if (f_stream)
+ printfcn = printstream;
+ else
+ printfcn = printcol;
+
+#ifdef __APPLE__
+ if (f_dataless) {
+ // don't materialize dataless directories from the cloud
+ // (particularly usefull when listing recursively)
+ int state = 1;
+ if (sysctlbyname("vfs.nspace.prevent_materialization", NULL, NULL, &state, sizeof(state)) < 0) {
+ err(1, "prevent_materialization");
+ }
+ }
+#endif /* __APPLE__ */
+
+ if (argc)
+ traverse(argc, argv, fts_options);
+ else
+ traverse(1, dotav, fts_options);
+ exit(rval);
+}
+
+static int output; /* If anything output. */
+
+/*
+ * Traverse() walks the logical directory structure specified by the argv list
+ * in the order specified by the mastercmp() comparison function. During the
+ * traversal it passes linked lists of structures to display() which represent
+ * a superset (may be exact set) of the files to be displayed.
+ */
+static void
+traverse(int argc, char *argv[], int options)
+{
+ FTS *ftsp;
+ FTSENT *p, *chp;
+ int ch_options, error;
+
+ if ((ftsp =
+ fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
+ err(1, "fts_open");
+
+ display(NULL, fts_children(ftsp, 0));
+ if (f_listdir) {
+ fts_close(ftsp);
+ return;
+ }
+
+ /*
+ * If not recursing down this tree and don't need stat info, just get
+ * the names.
+ */
+ ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0;
+
+ while ((p = fts_read(ftsp)) != NULL)
+ switch (p->fts_info) {
+ case FTS_DC:
+ warnx("%s: directory causes a cycle", p->fts_name);
+ if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ rval = 1;
+ }
+ break;
+ case FTS_DNR:
+ case FTS_ERR:
+ warnx("%s: %s", p->fts_name, strerror(p->fts_errno));
+ rval = 1;
+ break;
+ case FTS_D:
+ if (p->fts_level != FTS_ROOTLEVEL &&
+ p->fts_name[0] == '.' && !f_listdot) {
+ fts_set(ftsp, p, FTS_SKIP);
+ break;
+ }
+
+ if (IS_DATALESS(p->fts_statp)) {
+ fts_set(ftsp, p, FTS_SKIP);
+ break;
+ }
+
+ /*
+ * If already output something, put out a newline as
+ * a separator. If multiple arguments, precede each
+ * directory with its name.
+ */
+ if (output)
+ (void)printf("\n%s:\n", p->fts_path);
+ else if (argc > 1) {
+ (void)printf("%s:\n", p->fts_path);
+ output = 1;
+ }
+ chp = fts_children(ftsp, ch_options);
+ if (COMPAT_MODE("bin/ls", "Unix2003") && ((options & FTS_LOGICAL)!=0)) {
+ FTSENT *curr;
+ for (curr = chp; curr; curr = curr->fts_link) {
+ if (curr->fts_info == FTS_SLNONE)
+ curr->fts_number = NO_PRINT;
+ }
+ }
+ display(p, chp);
+
+ if (!f_recursive && chp != NULL)
+ (void)fts_set(ftsp, p, FTS_SKIP);
+ break;
+ case FTS_SLNONE: /* Same as default unless Unix conformance */
+ if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ if ((options & FTS_LOGICAL)!=0) { /* -L was specified */
+ warnx("%s: %s", p->fts_name, strerror(p->fts_errno ?: ENOENT));
+ rval = 1;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ error = errno;
+ fts_close(ftsp);
+ errno = error;
+
+ if (errno)
+ err(1, "fts_read");
+}
+
+/*
+ * Display() takes a linked list of FTSENT structures and passes the list
+ * along with any other necessary information to the print function. P
+ * points to the parent directory of the display list.
+ */
+static void
+display(FTSENT *p, FTSENT *list)
+{
+ struct stat *sp;
+ DISPLAY d;
+ FTSENT *cur;
+ NAMES *np;
+ off_t maxsize;
+ u_int64_t btotal, maxblock;
+ u_long lattrlen, maxlen, maxnlink, maxlattr;
+ ino_t maxinode;
+ int bcfile, maxflags;
+ gid_t maxgroup;
+ uid_t maxuser;
+ size_t flen, ulen, glen;
+ char *initmax;
+ int entries, needstats;
+ const char *user, *group;
+ char *flags, *lattr = NULL;
+ char buf[STRBUF_SIZEOF(u_quad_t) + 1];
+ char ngroup[STRBUF_SIZEOF(uid_t) + 1];
+ char nuser[STRBUF_SIZEOF(gid_t) + 1];
+#ifdef __APPLE__
+ acl_entry_t dummy;
+ ssize_t xattr_size;
+ char *filename;
+ char path[MAXPATHLEN+1];
+#endif // __APPLE__
+ /*
+ * If list is NULL there are two possibilities: that the parent
+ * directory p has no children, or that fts_children() returned an
+ * error. We ignore the error case since it will be replicated
+ * on the next call to fts_read() on the post-order visit to the
+ * directory p, and will be signaled in traverse().
+ */
+ if (list == NULL)
+ return;
+
+ needstats = f_inode || f_longform || f_size;
+ btotal = 0;
+ initmax = getenv("LS_COLWIDTHS");
+ /* Fields match -lios order. New ones should be added at the end. */
+ maxlattr = maxblock = maxinode = maxlen = maxnlink =
+ maxuser = maxgroup = maxflags = maxsize = 0;
+ if (initmax != NULL && *initmax != '\0') {
+ char *initmax2, *jinitmax;
+ int ninitmax;
+
+ /* Fill-in "::" as "0:0:0" for the sake of scanf. */
+ jinitmax = initmax2 = malloc(strlen(initmax) * 2 + 2);
+ if (jinitmax == NULL)
+ err(1, "malloc");
+ if (*initmax == ':')
+ strcpy(initmax2, "0:"), initmax2 += 2;
+ else
+ *initmax2++ = *initmax, *initmax2 = '\0';
+ for (initmax++; *initmax != '\0'; initmax++) {
+ if (initmax[-1] == ':' && initmax[0] == ':') {
+ *initmax2++ = '0';
+ *initmax2++ = initmax[0];
+ initmax2[1] = '\0';
+ } else {
+ *initmax2++ = initmax[0];
+ initmax2[1] = '\0';
+ }
+ }
+ if (initmax2[-1] == ':')
+ strcpy(initmax2, "0");
+
+ ninitmax = sscanf(jinitmax,
+#if _DARWIN_FEATURE_64_BIT_INODE
+ " %llu : %qu : %lu : %i : %i : %i : %qu : %lu : %lu ",
+#else
+ " %lu : %qu : %lu : %i : %i : %i : %qu : %lu : %lu ",
+#endif
+ &maxinode, &maxblock, &maxnlink, &maxuser,
+ &maxgroup, &maxflags, &maxsize, &maxlen, &maxlattr);
+ f_notabs = 1;
+ switch (ninitmax) {
+ case 0:
+ maxinode = 0;
+ /* FALLTHROUGH */
+ case 1:
+ maxblock = 0;
+ /* FALLTHROUGH */
+ case 2:
+ maxnlink = 0;
+ /* FALLTHROUGH */
+ case 3:
+ maxuser = 0;
+ /* FALLTHROUGH */
+ case 4:
+ maxgroup = 0;
+ /* FALLTHROUGH */
+ case 5:
+ maxflags = 0;
+ /* FALLTHROUGH */
+ case 6:
+ maxsize = 0;
+ /* FALLTHROUGH */
+ case 7:
+ maxlen = 0;
+ /* FALLTHROUGH */
+ case 8:
+ maxlattr = 0;
+ /* FALLTHROUGH */
+#ifdef COLORLS
+ if (!f_color)
+#endif
+ f_notabs = 0;
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ maxinode = makenines(maxinode);
+ maxblock = makenines(maxblock);
+ maxnlink = makenines(maxnlink);
+ maxsize = makenines(maxsize);
+ }
+ bcfile = 0;
+ flags = NULL;
+ for (cur = list, entries = 0; cur; cur = cur->fts_link) {
+ if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
+ warnx("%s: %s",
+ cur->fts_name, strerror(cur->fts_errno));
+ cur->fts_number = NO_PRINT;
+ rval = 1;
+ continue;
+ }
+ /*
+ * P is NULL if list is the argv list, to which different rules
+ * apply.
+ */
+ if (p == NULL) {
+ /* Directories will be displayed later. */
+ if (cur->fts_info == FTS_D && !f_listdir) {
+ cur->fts_number = NO_PRINT;
+ continue;
+ }
+ } else {
+ /* Only display dot file if -a/-A set. */
+ if (cur->fts_name[0] == '.' && !f_listdot) {
+ cur->fts_number = NO_PRINT;
+ continue;
+ }
+ }
+ if (cur->fts_namelen > maxlen)
+ maxlen = cur->fts_namelen;
+ if (f_octal || f_octal_escape) {
+ u_long t = len_octal(cur->fts_name, cur->fts_namelen);
+
+ if (t > maxlen)
+ maxlen = t;
+ }
+ if (needstats) {
+ sp = cur->fts_statp;
+ if (sp->st_blocks > maxblock)
+ maxblock = sp->st_blocks;
+ if (sp->st_ino > maxinode)
+ maxinode = sp->st_ino;
+ if (sp->st_nlink > maxnlink)
+ maxnlink = sp->st_nlink;
+ if (sp->st_size > maxsize)
+ maxsize = sp->st_size;
+
+ btotal += sp->st_blocks;
+ if (f_longform) {
+ if (f_numericonly) {
+ (void)snprintf(nuser, sizeof(nuser),
+ "%u", sp->st_uid);
+ (void)snprintf(ngroup, sizeof(ngroup),
+ "%u", sp->st_gid);
+ user = nuser;
+ group = ngroup;
+ } else {
+ user = user_from_uid(sp->st_uid, 0);
+ group = group_from_gid(sp->st_gid, 0);
+ }
+ if ((ulen = strlen(user)) > maxuser)
+ maxuser = ulen;
+ if ((glen = strlen(group)) > maxgroup)
+ maxgroup = glen;
+ if (f_flags) {
+ flags = fflagstostr(sp->st_flags);
+ if (flags != NULL && *flags == '\0') {
+ free(flags);
+ flags = strdup("-");
+ }
+ if (flags == NULL)
+ err(1, "fflagstostr");
+ flen = strlen(flags);
+ if (flen > (size_t)maxflags)
+ maxflags = flen;
+ } else
+ flen = 0;
+ lattr = NULL;
+ lattrlen = 0;
+
+ if ((np = calloc(1, sizeof(NAMES) + lattrlen +
+ ulen + glen + flen + 4)) == NULL)
+ err(1, "malloc");
+
+ np->user = &np->data[0];
+ (void)strcpy(np->user, user);
+ np->group = &np->data[ulen + 1];
+ (void)strcpy(np->group, group);
+#ifdef __APPLE__
+ if (cur->fts_level == FTS_ROOTLEVEL) {
+ filename = cur->fts_name;
+ } else {
+ snprintf(path, sizeof(path), "%s/%s", cur->fts_parent->fts_accpath, cur->fts_name);
+ filename = path;
+ }
+ xattr_size = listxattr(filename, NULL, 0, XATTR_NOFOLLOW);
+ if (xattr_size < 0) {
+ xattr_size = 0;
+ }
+ if ((xattr_size > 0) && f_xattr) {
+ /* collect sizes */
+ np->xattr_names = malloc(xattr_size);
+ listxattr(filename, np->xattr_names, xattr_size, XATTR_NOFOLLOW);
+ for (char *name = np->xattr_names; name < np->xattr_names + xattr_size;
+ name += strlen(name)+1) {
+ np->xattr_sizes = reallocf(np->xattr_sizes, (np->xattr_count+1) * sizeof(np->xattr_sizes[0]));
+ np->xattr_sizes[np->xattr_count] = getxattr(filename, name, 0, 0, 0, XATTR_NOFOLLOW);
+ np->xattr_count++;
+ }
+ }
+ /* symlinks can not have ACLs */
+ np->acl = acl_get_link_np(filename, ACL_TYPE_EXTENDED);
+ if (np->acl) {
+ if (acl_get_entry(np->acl, ACL_FIRST_ENTRY, &dummy) == -1) {
+ acl_free(np->acl);
+ np->acl = NULL;
+ }
+ }
+ if (xattr_size > 0) {
+ np->mode_suffix = '@';
+ } else if (np->acl) {
+ np->mode_suffix = '+';
+ } else {
+ np->mode_suffix = ' ';
+ }
+ if (IS_DATALESS(sp)) {
+ np->mode_suffix = '%';
+ }
+ if (!f_acl) {
+ acl_free(np->acl);
+ np->acl = NULL;
+ }
+#endif // __APPLE__
+ if (S_ISCHR(sp->st_mode) ||
+ S_ISBLK(sp->st_mode))
+ bcfile = 1;
+
+ if (f_flags) {
+ np->flags = &np->data[ulen + glen + 2];
+ (void)strcpy(np->flags, flags);
+ free(flags);
+ }
+ cur->fts_pointer = np;
+ }
+ }
+ ++entries;
+ }
+
+ if (!entries)
+ return;
+
+ d.list = list;
+ d.entries = entries;
+ d.maxlen = maxlen;
+ if (needstats) {
+ d.bcfile = bcfile;
+ d.btotal = btotal;
+ (void)snprintf(buf, sizeof(buf), "%qu", (u_int64_t)maxblock);
+ d.s_block = strlen(buf);
+ d.s_flags = maxflags;
+ d.s_lattr = maxlattr;
+ d.s_group = maxgroup;
+#if _DARWIN_FEATURE_64_BIT_INODE
+ (void)snprintf(buf, sizeof(buf), "%llu", maxinode);
+#else
+ (void)snprintf(buf, sizeof(buf), "%lu", maxinode);
+#endif
+ d.s_inode = strlen(buf);
+ (void)snprintf(buf, sizeof(buf), "%lu", maxnlink);
+ d.s_nlink = strlen(buf);
+ (void)snprintf(buf, sizeof(buf), "%qu", (u_int64_t)maxsize);
+ d.s_size = strlen(buf);
+ d.s_user = maxuser;
+ }
+ printfcn(&d);
+ output = 1;
+
+ if (f_longform) {
+ for (cur = list; cur; cur = cur->fts_link) {
+ np = cur->fts_pointer;
+ if (np) {
+ if (np->acl) {
+ acl_free(np->acl);
+ }
+ free(np->xattr_names);
+ free(np->xattr_sizes);
+ free(np);
+ cur->fts_pointer = NULL;
+ }
+ }
+ }
+}
+
+/*
+ * Ordering for mastercmp:
+ * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories
+ * as larger than directories. Within either group, use the sort function.
+ * All other levels use the sort function. Error entries remain unsorted.
+ */
+static int
+mastercmp(const FTSENT **a, const FTSENT **b)
+{
+ int a_info, b_info;
+
+ a_info = (*a)->fts_info;
+ if (a_info == FTS_ERR)
+ return (0);
+ b_info = (*b)->fts_info;
+ if (b_info == FTS_ERR)
+ return (0);
+
+ if (a_info == FTS_NS || b_info == FTS_NS)
+ return (namecmp(*a, *b));
+
+ if (a_info != b_info &&
+ (*a)->fts_level == FTS_ROOTLEVEL && !f_listdir) {
+ if (a_info == FTS_D)
+ return (1);
+ if (b_info == FTS_D)
+ return (-1);
+ }
+ return (sortfcn(*a, *b));
+}
+
+/*
+ * Makenines() returns (10**n)-1. This is useful for converting a width
+ * into a number that wide in decimal.
+ */
+static u_quad_t
+makenines(u_quad_t n)
+{
+ u_long i;
+ u_quad_t reg;
+
+ reg = 1;
+ /* Use a loop instead of pow(), since all values of n are small. */
+ for (i = 0; i < n; i++)
+ reg *= 10;
+ reg--;
+
+ return reg;
+}
diff --git a/file_cmds/ls/ls.h b/file_cmds/ls/ls.h
new file mode 100644
index 0000000..d1ef037
--- /dev/null
+++ b/file_cmds/ls/ls.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)ls.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: src/bin/ls/ls.h,v 1.18 2002/05/19 02:51:36 tjr Exp $
+ */
+
+#ifndef _LS_H_
+#define _LS_H_
+
+#define NO_PRINT 1
+
+extern long blocksize; /* block size units */
+
+extern int f_accesstime; /* use time of last access */
+extern int f_birthtime; /* use time of file birth */
+extern int f_flags; /* show flags associated with a file */
+extern int f_humanval; /* show human-readable file sizes */
+extern int f_inode; /* print inode */
+extern int f_longform; /* long listing format */
+extern int f_octal; /* print unprintables in octal */
+extern int f_octal_escape; /* like f_octal but use C escapes if possible */
+extern int f_nonprint; /* show unprintables as ? */
+extern int f_sectime; /* print the real time for all files */
+extern int f_size; /* list size in short listing */
+extern int f_slash; /* append a '/' if the file is a directory */
+extern int f_sortacross; /* sort across rows, not down columns */
+extern int f_statustime; /* use time of last mode change */
+extern int f_notabs; /* don't use tab-separated multi-col output */
+extern int f_type; /* add type character for non-regular files */
+extern int f_acl; /* print ACLs in long format */
+extern int f_xattr; /* print extended attributes in long format */
+extern int f_group; /* list group without owner */
+extern int f_owner; /* list owner without group */
+#ifdef COLORLS
+extern int f_color; /* add type in color for non-regular files */
+#endif
+extern int f_numericonly; /* don't convert uid/gid to name */
+
+#ifdef __APPLE__
+#include <sys/acl.h>
+#endif // __APPLE__
+
+typedef struct {
+ FTSENT *list;
+ u_int64_t btotal;
+ int bcfile;
+ int entries;
+ int maxlen;
+ u_int s_block;
+ u_int s_flags;
+ u_int s_lattr;
+ u_int s_group;
+ u_int s_inode;
+ u_int s_nlink;
+ u_int s_size;
+ u_int s_user;
+} DISPLAY;
+
+typedef struct {
+ char *user;
+ char *group;
+ char *flags;
+#ifndef __APPLE__
+ char *lattr;
+#else
+ char *xattr_names; /* f_xattr */
+ int *xattr_sizes;
+ acl_t acl; /* f_acl */
+ int xattr_count;
+ char mode_suffix; /* @ | + | % | <space> */
+#endif /* __APPLE__ */
+ char data[1];
+} NAMES;
+
+#endif /* _LS_H_ */
diff --git a/file_cmds/ls/print.c b/file_cmds/ls/print.c
new file mode 100644
index 0000000..de04bf3
--- /dev/null
+++ b/file_cmds/ls/print.c
@@ -0,0 +1,837 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)print.c 8.4 (Berkeley) 4/17/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/ls/print.c,v 1.57 2002/08/29 14:29:09 keramida Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef __APPLE__
+#include <sys/acl.h>
+#include <sys/xattr.h>
+#include <sys/types.h>
+#include <grp.h>
+#include <pwd.h>
+#include <TargetConditionals.h>
+#include <membership.h>
+#include <membershipPriv.h>
+#include <uuid/uuid.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <math.h>
+#include <langinfo.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef COLORLS
+#include <ctype.h>
+#include <termcap.h>
+#include <signal.h>
+#endif
+#include <stdint.h> /* intmax_t */
+#include <assert.h>
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+#include "ls.h"
+#include "extern.h"
+
+static int printaname(FTSENT *, u_long, u_long);
+static void printlink(FTSENT *);
+static void printtime(time_t);
+static int printtype(u_int);
+static void printsize(size_t, off_t);
+#ifdef COLORLS
+static void endcolor(int);
+static int colortype(mode_t);
+#endif
+
+#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
+
+#ifdef COLORLS
+/* Most of these are taken from <sys/stat.h> */
+typedef enum Colors {
+ C_DIR, /* directory */
+ C_LNK, /* symbolic link */
+ C_SOCK, /* socket */
+ C_FIFO, /* pipe */
+ C_EXEC, /* executable */
+ C_BLK, /* block special */
+ C_CHR, /* character special */
+ C_SUID, /* setuid executable */
+ C_SGID, /* setgid executable */
+ C_WSDIR, /* directory writeble to others, with sticky
+ * bit */
+ C_WDIR, /* directory writeble to others, without
+ * sticky bit */
+ C_NUMCOLORS /* just a place-holder */
+} Colors;
+
+static const char *defcolors = "exfxcxdxbxegedabagacad";
+
+/* colors for file types */
+static struct {
+ int num[2];
+ int bold;
+} colors[C_NUMCOLORS];
+#endif
+
+void
+printscol(DISPLAY *dp)
+{
+ FTSENT *p;
+
+ assert(dp);
+ if (COMPAT_MODE("bin/ls", "Unix2003") && (dp->list != NULL)) {
+ if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+ (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize));
+ }
+
+ for (p = dp->list; p; p = p->fts_link) {
+ if (IS_NOPRINT(p))
+ continue;
+ (void)printaname(p, dp->s_inode, dp->s_block);
+ (void)putchar('\n');
+ }
+}
+
+/*
+ * print name in current style
+ */
+static int
+printname(const char *name)
+{
+ if (f_octal || f_octal_escape)
+ return prn_octal(name);
+ else if (f_nonprint)
+ return prn_printable(name);
+ else
+ return prn_normal(name);
+}
+
+/*
+ * print access control list
+ */
+static struct {
+ acl_perm_t perm;
+ char *name;
+ int flags;
+#define ACL_PERM_DIR (1<<0)
+#define ACL_PERM_FILE (1<<1)
+} acl_perms[] = {
+ {ACL_READ_DATA, "read", ACL_PERM_FILE},
+ {ACL_LIST_DIRECTORY, "list", ACL_PERM_DIR},
+ {ACL_WRITE_DATA, "write", ACL_PERM_FILE},
+ {ACL_ADD_FILE, "add_file", ACL_PERM_DIR},
+ {ACL_EXECUTE, "execute", ACL_PERM_FILE},
+ {ACL_SEARCH, "search", ACL_PERM_DIR},
+ {ACL_DELETE, "delete", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_APPEND_DATA, "append", ACL_PERM_FILE},
+ {ACL_ADD_SUBDIRECTORY, "add_subdirectory", ACL_PERM_DIR},
+ {ACL_DELETE_CHILD, "delete_child", ACL_PERM_DIR},
+ {ACL_READ_ATTRIBUTES, "readattr", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_WRITE_ATTRIBUTES, "writeattr", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_READ_EXTATTRIBUTES, "readextattr", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_WRITE_EXTATTRIBUTES, "writeextattr", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_READ_SECURITY, "readsecurity", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_WRITE_SECURITY, "writesecurity", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_CHANGE_OWNER, "chown", ACL_PERM_FILE | ACL_PERM_DIR},
+ {0, NULL, 0}
+};
+
+static struct {
+ acl_flag_t flag;
+ char *name;
+ int flags;
+} acl_flags[] = {
+ {ACL_ENTRY_FILE_INHERIT, "file_inherit", ACL_PERM_DIR},
+ {ACL_ENTRY_DIRECTORY_INHERIT, "directory_inherit", ACL_PERM_DIR},
+ {ACL_ENTRY_LIMIT_INHERIT, "limit_inherit", ACL_PERM_FILE | ACL_PERM_DIR},
+ {ACL_ENTRY_ONLY_INHERIT, "only_inherit", ACL_PERM_DIR},
+ {0, NULL, 0}
+};
+
+static char *
+uuid_to_name(uuid_t *uu)
+{
+ int type;
+ char *name = NULL;
+ char *recname = NULL;
+
+#define MAXNAMETAG (MAXLOGNAME + 6) /* + strlen("group:") */
+ name = (char *) malloc(MAXNAMETAG);
+
+ if (NULL == name) {
+ err(1, "malloc");
+ }
+
+ if (f_numericonly) {
+ goto errout;
+ }
+
+ if (mbr_identifier_translate(ID_TYPE_UUID, *uu, sizeof(*uu), ID_TYPE_NAME, (void **) &recname, &type)) {
+ goto errout;
+ }
+
+ snprintf(name, MAXNAMETAG, "%s:%s", (type == MBR_REC_TYPE_USER ? "user" : "group"), recname);
+ free(recname);
+
+ return name;
+errout:
+ uuid_unparse_upper(*uu, name);
+
+ return name;
+}
+
+static void
+printxattr(DISPLAY *dp, int count, char *buf, int sizes[])
+{
+ for (int i = 0; i < count; i++) {
+ putchar('\t');
+ printname(buf);
+ putchar('\t');
+ printsize(dp->s_size, sizes[i]);
+ putchar('\n');
+ buf += strlen(buf) + 1;
+ }
+}
+
+static void
+printacl(acl_t acl, int isdir)
+{
+ acl_entry_t entry = NULL;
+ int index;
+ uuid_t *applicable;
+ char *name = NULL;
+ acl_tag_t tag;
+ acl_flagset_t flags;
+ acl_permset_t perms;
+ char *type;
+ int i, first;
+
+
+ for (index = 0;
+ acl_get_entry(acl, entry == NULL ? ACL_FIRST_ENTRY : ACL_NEXT_ENTRY, &entry) == 0;
+ index++) {
+ if (acl_get_tag_type(entry, &tag) != 0)
+ continue;
+ if (acl_get_flagset_np(entry, &flags) != 0)
+ continue;
+ if (acl_get_permset(entry, &perms) != 0)
+ continue;
+ if ((applicable = (uuid_t *) acl_get_qualifier(entry)) == NULL)
+ continue;
+ name = uuid_to_name(applicable);
+ acl_free(applicable);
+ switch(tag) {
+ case ACL_EXTENDED_ALLOW:
+ type = "allow";
+ break;
+ case ACL_EXTENDED_DENY:
+ type = "deny";
+ break;
+ default:
+ type = "unknown";
+ }
+
+ (void)printf(" %d: %s%s %s ",
+ index,
+ name,
+ acl_get_flag_np(flags, ACL_ENTRY_INHERITED) ? " inherited" : "",
+ type);
+
+ if (name)
+ free(name);
+
+ for (i = 0, first = 0; acl_perms[i].name != NULL; i++) {
+ if (acl_get_perm_np(perms, acl_perms[i].perm) == 0)
+ continue;
+ if (!(acl_perms[i].flags & (isdir ? ACL_PERM_DIR : ACL_PERM_FILE)))
+ continue;
+ (void)printf("%s%s", first++ ? "," : "", acl_perms[i].name);
+ }
+ for (i = 0; acl_flags[i].name != NULL; i++) {
+ if (acl_get_flag_np(flags, acl_flags[i].flag) == 0)
+ continue;
+ if (!(acl_flags[i].flags & (isdir ? ACL_PERM_DIR : ACL_PERM_FILE)))
+ continue;
+ (void)printf("%s%s", first++ ? "," : "", acl_flags[i].name);
+ }
+
+ (void)putchar('\n');
+ }
+
+}
+
+void
+printlong(DISPLAY *dp)
+{
+ struct stat *sp;
+ FTSENT *p;
+ NAMES *np;
+ char buf[20];
+#ifdef COLORLS
+ int color_printed = 0;
+#endif
+
+ if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+ (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize));
+
+ for (p = dp->list; p; p = p->fts_link) {
+ if (IS_NOPRINT(p))
+ continue;
+ sp = p->fts_statp;
+ if (f_inode)
+#if _DARWIN_FEATURE_64_BIT_INODE
+ (void)printf("%*llu ", dp->s_inode, (u_quad_t)sp->st_ino);
+#else
+ (void)printf("%*lu ", dp->s_inode, (u_long)sp->st_ino);
+#endif
+ if (f_size)
+ (void)printf("%*qu ",
+ dp->s_block, (u_int64_t)howmany(sp->st_blocks, blocksize));
+ strmode(sp->st_mode, buf);
+ np = p->fts_pointer;
+#ifdef __APPLE__
+ buf[10] = '\0'; /* make +/@ abut the mode */
+ char str[2] = { np->mode_suffix, '\0' };
+#endif /* __APPLE__ */
+ if (f_group && f_owner) { /* means print neither */
+#ifdef __APPLE__
+ (void)printf("%s%s %*u ", buf, str, dp->s_nlink,
+ sp->st_nlink);
+#else /* ! __APPLE__ */
+ (void)printf("%s %*u ", buf, dp->s_nlink,
+ sp->st_nlink);
+#endif /* __APPLE__ */
+ }
+ else if (f_group) {
+#ifdef __APPLE__
+ (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink,
+ sp->st_nlink, dp->s_group, np->group);
+#else /* ! __APPLE__ */
+ (void)printf("%s %*u %-*s ", buf, dp->s_nlink,
+ sp->st_nlink, dp->s_group, np->group);
+#endif /* __APPLE__ */
+ }
+ else if (f_owner) {
+#ifdef __APPLE__
+ (void)printf("%s%s %*u %-*s ", buf, str, dp->s_nlink,
+ sp->st_nlink, dp->s_user, np->user);
+#else /* ! __APPLE__ */
+ (void)printf("%s %*u %-*s ", buf, dp->s_nlink,
+ sp->st_nlink, dp->s_user, np->user);
+#endif /* __APPLE__ */
+ }
+ else {
+#ifdef __APPLE__
+ (void)printf("%s%s %*u %-*s %-*s ", buf, str, dp->s_nlink,
+ sp->st_nlink, dp->s_user, np->user, dp->s_group,
+ np->group);
+#else /* ! __APPLE__ */
+ (void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink,
+ sp->st_nlink, dp->s_user, np->user, dp->s_group,
+ np->group);
+#endif /* ! __APPLE__ */
+ }
+ if (f_flags)
+ (void)printf("%-*s ", dp->s_flags, np->flags);
+ if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
+ if (minor(sp->st_rdev) > 255 || minor(sp->st_rdev) < 0)
+ (void)printf("%3d, 0x%08x ",
+ major(sp->st_rdev),
+ (u_int)minor(sp->st_rdev));
+ else
+ (void)printf("%3d, %3d ",
+ major(sp->st_rdev), minor(sp->st_rdev));
+ else if (dp->bcfile)
+ (void)printf("%*s%*qu ",
+ 8 - dp->s_size, "", dp->s_size, (u_int64_t)sp->st_size);
+ else
+ printsize(dp->s_size, sp->st_size);
+ if (f_accesstime)
+ printtime(sp->st_atime);
+ else if (f_statustime)
+ printtime(sp->st_ctime);
+ else if (f_birthtime)
+ printtime(sp->st_birthtime);
+ else
+ printtime(sp->st_mtime);
+#ifdef COLORLS
+ if (f_color)
+ color_printed = colortype(sp->st_mode);
+#endif
+ (void)printname(p->fts_name);
+#ifdef COLORLS
+ if (f_color && color_printed)
+ endcolor(0);
+#endif
+ if (f_type)
+ (void)printtype(sp->st_mode);
+ if (S_ISLNK(sp->st_mode))
+ printlink(p);
+ (void)putchar('\n');
+#ifdef __APPLE__
+ if (np->xattr_count && f_xattr) {
+ printxattr(dp, np->xattr_count, np->xattr_names, np->xattr_sizes);
+ }
+ if (np->acl != NULL && f_acl) {
+ printacl(np->acl, S_ISDIR(sp->st_mode));
+ }
+#endif /* __APPLE__ */
+ }
+}
+
+void
+printstream(DISPLAY *dp)
+{
+ FTSENT *p;
+ extern int termwidth;
+ int chcnt;
+
+ for (p = dp->list, chcnt = 0; p; p = p->fts_link) {
+ if (p->fts_number == NO_PRINT)
+ continue;
+ if (strlen(p->fts_name) + chcnt +
+ (p->fts_link ? 2 : 0) >= (unsigned)termwidth) {
+ putchar('\n');
+ chcnt = 0;
+ }
+ chcnt += printaname(p, dp->s_inode, dp->s_block);
+ if (p->fts_link) {
+ printf(", ");
+ chcnt += 2;
+ }
+ }
+ if (chcnt)
+ putchar('\n');
+}
+
+void
+printcol(DISPLAY *dp)
+{
+ extern int termwidth;
+ static FTSENT **array;
+ static int lastentries = -1;
+ FTSENT *p;
+ int base;
+ int chcnt;
+ int cnt;
+ int col;
+ int colwidth;
+ int endcol;
+ int num;
+ int numcols;
+ int numrows;
+ int row;
+ int tabwidth;
+
+ if (f_notabs)
+ tabwidth = 1;
+ else
+ tabwidth = 8;
+
+ /*
+ * Have to do random access in the linked list -- build a table
+ * of pointers.
+ */
+ if ((lastentries == -1) || (dp->entries > lastentries)) {
+ lastentries = dp->entries;
+ if ((array = realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
+ warn(NULL);
+ printscol(dp);
+ return;
+ }
+ }
+ memset(array, 0, dp->entries * sizeof(FTSENT *));
+ for (p = dp->list, num = 0; p; p = p->fts_link)
+ if (p->fts_number != NO_PRINT)
+ array[num++] = p;
+
+ colwidth = dp->maxlen;
+ if (f_inode)
+ colwidth += dp->s_inode + 1;
+ if (f_size)
+ colwidth += dp->s_block + 1;
+ if (f_type)
+ colwidth += 1;
+
+ colwidth = (colwidth + tabwidth) & ~(tabwidth - 1);
+ if (termwidth < 2 * colwidth) {
+ printscol(dp);
+ return;
+ }
+ numcols = termwidth / colwidth;
+ numrows = num / numcols;
+ if (num % numcols)
+ ++numrows;
+
+ assert(dp->list);
+ if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+ (void)printf("total %qu\n", (u_int64_t)howmany(dp->btotal, blocksize));
+
+ base = 0;
+ for (row = 0; row < numrows; ++row) {
+ endcol = colwidth;
+ if (!f_sortacross)
+ base = row;
+ for (col = 0, chcnt = 0; col < numcols; ++col) {
+ assert(base < dp->entries);
+ chcnt += printaname(array[base], dp->s_inode, dp->s_block);
+ if (f_sortacross)
+ base++;
+ else
+ base += numrows;
+ if (base >= num)
+ break;
+ while ((cnt = ((chcnt + tabwidth) & ~(tabwidth - 1)))
+ <= endcol) {
+ if (f_sortacross && col + 1 >= numcols)
+ break;
+ (void)putchar(f_notabs ? ' ' : '\t');
+ chcnt = cnt;
+ }
+ endcol += colwidth;
+ }
+ (void)putchar('\n');
+ }
+}
+
+/*
+ * print [inode] [size] name
+ * return # of characters printed, no trailing characters.
+ */
+static int
+printaname(FTSENT *p, u_long inodefield, u_long sizefield)
+{
+ struct stat *sp;
+ int chcnt;
+#ifdef COLORLS
+ int color_printed = 0;
+#endif
+
+ sp = p->fts_statp;
+ chcnt = 0;
+ if (f_inode)
+#if _DARWIN_FEATURE_64_BIT_INODE
+ chcnt += printf("%*llu ", (int)inodefield, (u_quad_t)sp->st_ino);
+#else
+ chcnt += printf("%*lu ", (int)inodefield, (u_long)sp->st_ino);
+#endif
+ if (f_size)
+ chcnt += printf("%*qu ",
+ (int)sizefield, (u_int64_t)howmany(sp->st_blocks, blocksize));
+#ifdef COLORLS
+ if (f_color)
+ color_printed = colortype(sp->st_mode);
+#endif
+ chcnt += printname(p->fts_name);
+#ifdef COLORLS
+ if (f_color && color_printed)
+ endcolor(0);
+#endif
+ if (f_type)
+ chcnt += printtype(sp->st_mode);
+ return (chcnt);
+}
+
+static void
+printtime(time_t ftime)
+{
+ char longstring[80];
+ static time_t now;
+ const char *format;
+ static int d_first = -1;
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ if (now == 0)
+ now = time(NULL);
+
+#define SIXMONTHS ((365 / 2) * 86400)
+ if (f_sectime)
+ /* mmm dd hh:mm:ss yyyy || dd mmm hh:mm:ss yyyy */
+ format = d_first ? "%e %b %T %Y " : "%b %e %T %Y ";
+ else if (COMPAT_MODE("bin/ls", "Unix2003")) {
+ if (ftime + SIXMONTHS > now && ftime <= now)
+ /* mmm dd hh:mm || dd mmm hh:mm */
+ format = d_first ? "%e %b %R " : "%b %e %R ";
+ else
+ /* mmm dd yyyy || dd mmm yyyy */
+ format = d_first ? "%e %b %Y " : "%b %e %Y ";
+ }
+ else if (ftime + SIXMONTHS > now && ftime < now + SIXMONTHS)
+ /* mmm dd hh:mm || dd mmm hh:mm */
+ format = d_first ? "%e %b %R " : "%b %e %R ";
+ else
+ /* mmm dd yyyy || dd mmm yyyy */
+ format = d_first ? "%e %b %Y " : "%b %e %Y ";
+ strftime(longstring, sizeof(longstring), format, localtime(&ftime));
+ fputs(longstring, stdout);
+}
+
+static int
+printtype(u_int mode)
+{
+
+ if (f_slash) {
+ if ((mode & S_IFMT) == S_IFDIR) {
+ (void)putchar('/');
+ return (1);
+ }
+ return (0);
+ }
+
+ switch (mode & S_IFMT) {
+ case S_IFDIR:
+ (void)putchar('/');
+ return (1);
+ case S_IFIFO:
+ (void)putchar('|');
+ return (1);
+ case S_IFLNK:
+ (void)putchar('@');
+ return (1);
+ case S_IFSOCK:
+ (void)putchar('=');
+ return (1);
+ case S_IFWHT:
+ (void)putchar('%');
+ return (1);
+ default:
+ break;
+ }
+ if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+ (void)putchar('*');
+ return (1);
+ }
+ return (0);
+}
+
+#ifdef COLORLS
+static int
+putch(int c)
+{
+ (void)putchar(c);
+ return 0;
+}
+
+static int
+writech(int c)
+{
+ char tmp = c;
+
+ (void)write(STDOUT_FILENO, &tmp, 1);
+ return 0;
+}
+
+static void
+printcolor(Colors c)
+{
+ char *ansiseq;
+
+ if (colors[c].bold)
+ tputs(enter_bold, 1, putch);
+
+ if (colors[c].num[0] != -1) {
+ ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
+ if (ansiseq)
+ tputs(ansiseq, 1, putch);
+ }
+ if (colors[c].num[1] != -1) {
+ ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
+ if (ansiseq)
+ tputs(ansiseq, 1, putch);
+ }
+}
+
+static void
+endcolor(int sig)
+{
+ tputs(ansi_coloff, 1, sig ? writech : putch);
+ tputs(attrs_off, 1, sig ? writech : putch);
+}
+
+static int
+colortype(mode_t mode)
+{
+ switch (mode & S_IFMT) {
+ case S_IFDIR:
+ if (mode & S_IWOTH)
+ if (mode & S_ISTXT)
+ printcolor(C_WSDIR);
+ else
+ printcolor(C_WDIR);
+ else
+ printcolor(C_DIR);
+ return (1);
+ case S_IFLNK:
+ printcolor(C_LNK);
+ return (1);
+ case S_IFSOCK:
+ printcolor(C_SOCK);
+ return (1);
+ case S_IFIFO:
+ printcolor(C_FIFO);
+ return (1);
+ case S_IFBLK:
+ printcolor(C_BLK);
+ return (1);
+ case S_IFCHR:
+ printcolor(C_CHR);
+ return (1);
+ }
+ if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+ if (mode & S_ISUID)
+ printcolor(C_SUID);
+ else if (mode & S_ISGID)
+ printcolor(C_SGID);
+ else
+ printcolor(C_EXEC);
+ return (1);
+ }
+ return (0);
+}
+
+void
+parsecolors(const char *cs)
+{
+ int i;
+ int j;
+ int len;
+ char c[2];
+ short legacy_warn = 0;
+
+ if (cs == NULL)
+ cs = ""; /* LSCOLORS not set */
+ len = strlen(cs);
+ for (i = 0; i < C_NUMCOLORS; i++) {
+ colors[i].bold = 0;
+
+ if (len <= 2 * i) {
+ c[0] = defcolors[2 * i];
+ c[1] = defcolors[2 * i + 1];
+ } else {
+ c[0] = cs[2 * i];
+ c[1] = cs[2 * i + 1];
+ }
+ for (j = 0; j < 2; j++) {
+ /* Legacy colours used 0-7 */
+ if (c[j] >= '0' && c[j] <= '7') {
+ colors[i].num[j] = c[j] - '0';
+ if (!legacy_warn) {
+ fprintf(stderr,
+ "warn: LSCOLORS should use "
+ "characters a-h instead of 0-9 ("
+ "see the manual page)\n");
+ }
+ legacy_warn = 1;
+ } else if (c[j] >= 'a' && c[j] <= 'h')
+ colors[i].num[j] = c[j] - 'a';
+ else if (c[j] >= 'A' && c[j] <= 'H') {
+ colors[i].num[j] = c[j] - 'A';
+ colors[i].bold = 1;
+ } else if (tolower((unsigned char)c[j] == 'x'))
+ colors[i].num[j] = -1;
+ else {
+ fprintf(stderr,
+ "error: invalid character '%c' in LSCOLORS"
+ " env var\n", c[j]);
+ colors[i].num[j] = -1;
+ }
+ }
+ }
+}
+
+void
+colorquit(int sig)
+{
+ endcolor(sig);
+
+ (void)signal(sig, SIG_DFL);
+ (void)kill(getpid(), sig);
+}
+
+#endif /* COLORLS */
+
+static void
+printlink(FTSENT *p)
+{
+ int lnklen;
+ char name[MAXPATHLEN + 1];
+ char path[MAXPATHLEN + 1];
+
+ if (p->fts_level == FTS_ROOTLEVEL)
+ (void)snprintf(name, sizeof(name), "%s", p->fts_name);
+ else
+ (void)snprintf(name, sizeof(name),
+ "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
+ if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
+ (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
+ return;
+ }
+ path[lnklen] = '\0';
+ (void)printf(" -> ");
+ (void)printname(path);
+}
+
+static void
+printsize(size_t width, off_t bytes)
+{
+
+ if (f_humanval) {
+ char buf[5];
+
+ humanize_number(buf, sizeof(buf), (int64_t)bytes, "",
+ HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+ (void)printf("%5s ", buf);
+ } else
+ (void)printf("%*jd ", (u_int)width, (intmax_t)bytes);
+}
diff --git a/file_cmds/ls/util.c b/file_cmds/ls/util.c
new file mode 100644
index 0000000..1aae3f1
--- /dev/null
+++ b/file_cmds/ls/util.c
@@ -0,0 +1,231 @@
+/*-
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ls/util.c,v 1.38 2005/06/03 11:05:58 dd Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fts.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "ls.h"
+#include "extern.h"
+
+int
+prn_normal(const char *s)
+{
+ mbstate_t mbs;
+ wchar_t wc;
+ int i, n;
+ size_t clen;
+
+ memset(&mbs, 0, sizeof(mbs));
+ n = 0;
+ while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
+ if (clen == (size_t)-2) {
+ n += printf("%s", s);
+ break;
+ }
+ if (clen == (size_t)-1) {
+ memset(&mbs, 0, sizeof(mbs));
+ putchar((unsigned char)*s);
+ s++;
+ n++;
+ continue;
+ }
+ for (i = 0; i < (int)clen; i++)
+ putchar((unsigned char)s[i]);
+ s += clen;
+ if (iswprint(wc))
+ n += wcwidth(wc);
+ }
+ return (n);
+}
+
+int
+prn_printable(const char *s)
+{
+ mbstate_t mbs;
+ wchar_t wc;
+ int i, n;
+ size_t clen;
+
+ memset(&mbs, 0, sizeof(mbs));
+ n = 0;
+ while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
+ if (clen == (size_t)-1) {
+ putchar('?');
+ s++;
+ n++;
+ memset(&mbs, 0, sizeof(mbs));
+ continue;
+ }
+ if (clen == (size_t)-2) {
+ putchar('?');
+ n++;
+ break;
+ }
+ if (!iswprint(wc)) {
+ putchar('?');
+ s += clen;
+ n++;
+ continue;
+ }
+ for (i = 0; i < (int)clen; i++)
+ putchar((unsigned char)s[i]);
+ s += clen;
+ n += wcwidth(wc);
+ }
+ return (n);
+}
+
+/*
+ * The fts system makes it difficult to replace fts_name with a different-
+ * sized string, so we just calculate the real length here and do the
+ * conversion in prn_octal()
+ *
+ * XXX when using f_octal_escape (-b) rather than f_octal (-B), the
+ * length computed by len_octal may be too big. I just can't be buggered
+ * to fix this as an efficient fix would involve a lookup table. Same goes
+ * for the rather inelegant code in prn_octal.
+ *
+ * DES 1998/04/23
+ */
+
+size_t
+len_octal(const char *s, int len)
+{
+ mbstate_t mbs;
+ wchar_t wc;
+ size_t clen, r;
+
+ memset(&mbs, 0, sizeof(mbs));
+ r = 0;
+ while (len != 0 && (clen = mbrtowc(&wc, s, len, &mbs)) != 0) {
+ if (clen == (size_t)-1) {
+ r += 4;
+ s++;
+ len--;
+ memset(&mbs, 0, sizeof(mbs));
+ continue;
+ }
+ if (clen == (size_t)-2) {
+ r += 4 * len;
+ break;
+ }
+ if (iswprint(wc))
+ r++;
+ else
+ r += 4 * clen;
+ s += clen;
+ }
+ return (r);
+}
+
+int
+prn_octal(const char *s)
+{
+ static const char esc[] = "\\\\\"\"\aa\bb\ff\nn\rr\tt\vv";
+ const char *p;
+ mbstate_t mbs;
+ wchar_t wc;
+ size_t clen;
+ unsigned char ch;
+ int goodchar, i, len, prtlen;
+
+ memset(&mbs, 0, sizeof(mbs));
+ len = 0;
+ while ((clen = mbrtowc(&wc, s, MB_LEN_MAX, &mbs)) != 0) {
+ goodchar = clen != (size_t)-1 && clen != (size_t)-2;
+ if (goodchar && iswprint(wc) && wc != L'\"' && wc != L'\\') {
+ for (i = 0; i < (int)clen; i++)
+ putchar((unsigned char)s[i]);
+ len += wcwidth(wc);
+ } else if (goodchar && f_octal_escape && wc >= 0 &&
+ wc <= (wchar_t)UCHAR_MAX &&
+ (p = strchr(esc, (char)wc)) != NULL) {
+ putchar('\\');
+ putchar(p[1]);
+ len += 2;
+ } else {
+ if (goodchar)
+ prtlen = clen;
+ else if (clen == (size_t)-1)
+ prtlen = 1;
+ else
+ prtlen = strlen(s);
+ for (i = 0; i < prtlen; i++) {
+ ch = (unsigned char)s[i];
+ putchar('\\');
+ putchar('0' + (ch >> 6));
+ putchar('0' + ((ch >> 3) & 7));
+ putchar('0' + (ch & 7));
+ len += 4;
+ }
+ }
+ if (clen == (size_t)-2)
+ break;
+ if (clen == (size_t)-1) {
+ memset(&mbs, 0, sizeof(mbs));
+ s++;
+ } else
+ s += clen;
+ }
+ return (len);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr,
+#ifdef COLORLS
+ "usage: ls [-@ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1%%]"
+#else
+ "usage: ls [-@ABCFHLOPRSTUWabcdefghiklmnopqrstuwx1%%]"
+#endif
+ " [file ...]\n");
+ exit(1);
+}
diff --git a/file_cmds/mkdir/mkdir.1 b/file_cmds/mkdir/mkdir.1
new file mode 100644
index 0000000..2903a00
--- /dev/null
+++ b/file_cmds/mkdir/mkdir.1
@@ -0,0 +1,108 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mkdir.1 8.2 (Berkeley) 1/25/94
+.\" $FreeBSD: src/bin/mkdir/mkdir.1,v 1.17 2002/06/30 06:50:16 tjr Exp $
+.\"
+.Dd January 25, 1994
+.Dt MKDIR 1
+.Os
+.Sh NAME
+.Nm mkdir
+.Nd make directories
+.Sh SYNOPSIS
+.Nm
+.Op Fl pv
+.Op Fl m Ar mode
+.Ar directory_name ...
+.Sh DESCRIPTION
+The
+.Nm
+utility creates the directories named as operands, in the order specified,
+using mode
+.Li rwxrwxrwx (\&0777)
+as modified by the current
+.Xr umask 2 .
+.Pp
+The options are as follows:
+.Pp
+.Bl -tag -width indent
+.It Fl m Ar mode
+Set the file permission bits of the final created directory to
+the specified mode.
+The
+.Ar mode
+argument can be in any of the formats specified to the
+.Xr chmod 1
+command.
+If a symbolic mode is specified, the operation characters
+.Dq +
+and
+.Dq -
+are interpreted relative to an initial mode of
+.Dq a=rwx .
+.It Fl p
+Create intermediate directories as required.
+If this option is not specified, the full path prefix of each
+operand must already exist.
+On the other hand, with this option specified, no error will
+be reported if a directory given as an operand already exists.
+Intermediate directories are created with permission bits of
+.Li rwxrwxrwx (\&0777)
+as modified by the current umask, plus write and search
+permission for the owner.
+.It Fl v
+Be verbose when creating directories, listing them as they are created.
+.El
+.Pp
+The user must have write permission in the parent directory.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr rmdir 1
+.Sh COMPATIBILITY
+The
+.Fl v
+option is non-standard and its use in scripts is not recommended.
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/file_cmds/mkdir/mkdir.c b/file_cmds/mkdir/mkdir.c
new file mode 100644
index 0000000..8aede86
--- /dev/null
+++ b/file_cmds/mkdir/mkdir.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1983, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static char const copyright[] =
+"@(#) Copyright (c) 1983, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mkdir.c 8.2 (Berkeley) 1/25/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/mkdir/mkdir.c,v 1.26 2002/06/30 05:13:54 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int vflag;
+
+int
+main(int argc, char *argv[])
+{
+ int ch, exitval, success, pflag;
+ mode_t omode, *set = (mode_t *)NULL;
+ char *mode;
+
+ pflag = 0;
+ mode = NULL;
+ while ((ch = getopt(argc, argv, "m:pv")) != -1)
+ switch(ch) {
+ case 'm':
+ mode = optarg;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+// argc -= optind;
+ argv += optind;
+ if (argv[0] == NULL)
+ usage();
+
+ if (mode == NULL) {
+ omode = S_IRWXU | S_IRWXG | S_IRWXO;
+ } else {
+ if ((set = setmode(mode)) == NULL)
+ errx(1, "invalid file mode: %s", mode);
+ omode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
+ free(set);
+ }
+
+ for (exitval = 0; *argv != NULL; ++argv) {
+ success = 1;
+ if (pflag) {
+ int status = mkpath_np(*argv, omode);
+ if (status && status != EEXIST) {
+ warnc(status, "%s", *argv);
+ success = 0;
+ }
+ } else if (mkdir(*argv, omode) < 0) {
+ if (errno == ENOTDIR || errno == ENOENT)
+ warn("%s", dirname(*argv));
+ else
+ warn("%s", *argv);
+ success = 0;
+ } else if (vflag)
+ (void)printf("mkdir: created directory '%s'\n", *argv);
+
+ if (!success)
+ exitval = 1;
+ /*
+ * The mkdir() and umask() calls both honor only the low
+ * nine bits, so if you try to set a mode including the
+ * sticky, setuid, setgid bits you lose them. Don't do
+ * this unless the user has specifically requested a mode,
+ * as chmod will (obviously) ignore the umask.
+ */
+ if (success && mode != NULL && chmod(*argv, omode) == -1) {
+ warn("%s", *argv);
+ exitval = 1;
+ }
+ }
+ exit(exitval);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: mkdir [-pv] [-m mode] directory ...\n");
+ exit (EX_USAGE);
+}
diff --git a/file_cmds/mkfifo/mkfifo.1 b/file_cmds/mkfifo/mkfifo.1
new file mode 100644
index 0000000..39ca982
--- /dev/null
+++ b/file_cmds/mkfifo/mkfifo.1
@@ -0,0 +1,103 @@
+.\" $NetBSD: mkfifo.1,v 1.6 1997/10/19 05:11:52 lukem Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mkfifo.1 8.2 (Berkeley) 1/5/94
+.\"
+.Dd January 5, 1994
+.Dt MKFIFO 1
+.Os BSD 4.4
+.Sh NAME
+.Nm mkfifo
+.Nd make fifos
+.Sh SYNOPSIS
+.Nm mkfifo
+.Op Fl m Ar mode
+.Ar fifo_name ...
+.Sh DESCRIPTION
+.Nm mkfifo
+creates the fifos requested, in the order specified.
+By default,
+the resulting fifos have mode
+.Li \&0666
+(rw-rw-rw-), limited by the current
+.Xr umask 2 .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl m
+Set the file permission bits of newly-created fifos to
+.Ar mode ,
+without respect to the current umask.
+.Pp
+The mode is specified as in
+.Xr chmod 1 .
+In symbolic mode strings, the
+.Dq +
+and
+.Dq -
+operators are interpreted relative to an assumed initial mode of
+.Dq a=rw
+.El
+.Pp
+.Nm mkfifo
+requires write permission in the parent directory.
+.Pp
+.Nm mkfifo
+exits with 0 if successful, and with >0 if an error occurred.
+.Sh LEGACY DESCRIPTION
+In legacy mode, the fifo's file permission bits
+are always limited by the current umask.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr mkdir 1 ,
+.Xr rm 1 ,
+.Xr umask 1 ,
+.Xr mkfifo 2 ,
+.Xr umask 2 ,
+.Xr compat 5 ,
+.Xr mknod 8
+.Sh STANDARDS
+The
+.Nm mkfifo
+utility is expected to be
+.St -p1003.2-92
+compliant.
+.Sh HISTORY
+.Nm mkfifo
+command appeared in
+.Bx 4.4 .
diff --git a/file_cmds/mkfifo/mkfifo.c b/file_cmds/mkfifo/mkfifo.c
new file mode 100644
index 0000000..c06fc5a
--- /dev/null
+++ b/file_cmds/mkfifo/mkfifo.c
@@ -0,0 +1,128 @@
+/* $NetBSD: mkfifo.c,v 1.8 1997/10/19 05:11:54 lukem Exp $ */
+
+/*
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mkfifo.c 8.2 (Berkeley) 1/5/94";
+#endif
+__RCSID("$NetBSD: mkfifo.c,v 1.8 1997/10/19 05:11:54 lukem Exp $");
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <err.h>
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+int main __P((int, char **));
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch, exitval;
+ void * set;
+ mode_t mode = 0;
+ int m_used = 0;
+
+ setlocale (LC_ALL, "");
+
+ /* The default mode is the value of the bitwise inclusive or of
+ S_IRUSR, S_IWUSR, S_IRGRP, S_IWGRP, S_IROTH, and S_IWOTH
+ modified by the file creation mask */
+ if (!COMPAT_MODE("bin/mkfifo", "Unix2003")) {
+ mode = 0666 & ~umask(0);
+ }
+
+ while ((ch = getopt(argc, argv, "m:")) != -1)
+ switch(ch) {
+ case 'm':
+ m_used = 1;
+ if (!(set = setmode(optarg))) {
+ errx(1, "invalid file mode.");
+ /* NOTREACHED */
+ }
+ /* In symbolic mode strings, the + and - operators are
+ interpreted relative to an assumed initial mode of
+ a=rw. */
+ mode = getmode (set, 0666);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+// argc -= optind;
+ argv += optind;
+ if (argv[0] == NULL)
+ usage();
+
+ if (COMPAT_MODE("bin/mkfifo", "Unix2003")) {
+ mode_t maskbits = umask(0); /* now must disable umask so -m mode won't be masked again */
+ if (!m_used)
+ mode = 0666 & ~maskbits;
+ }
+
+ for (exitval = 0; *argv; ++argv) {
+ if (mkfifo(*argv, mode) < 0) {
+ warn("%s", *argv);
+ exitval = 1;
+ }
+ }
+ exit(exitval);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: mkfifo [-m mode] fifoname ...\n");
+ exit(1);
+}
diff --git a/file_cmds/mknod/mknod.8 b/file_cmds/mknod/mknod.8
new file mode 100644
index 0000000..eb4f292
--- /dev/null
+++ b/file_cmds/mknod/mknod.8
@@ -0,0 +1,137 @@
+.\" $NetBSD: mknod.8,v 1.15 1998/09/11 07:20:48 mycroft Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mknod.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd September 11, 1998
+.Dt MKNOD 8
+.Os NetBSD 1.4
+.Sh NAME
+.Nm mknod
+.Nd make device special file
+.Sh SYNOPSIS
+.Nm
+.Op Fl F Ar format
+.Ar name
+.Op Cm c | Cm b
+.Ar major minor
+.Nm
+.Op Fl F Ar format
+.Ar name
+.Op Cm c | Cm b
+.Ar major unit subunit
+.Nm
+.Ar name
+.Op Cm c | Cm b
+.Ar number
+.Nm
+.Ar name
+.Ar w
+.Sh DESCRIPTION
+The
+.Nm
+command creates device special files.
+.Pp
+To make nodes manually, the required arguments are:
+.Pp
+.Bl -tag -width majorx
+.It Ar name
+Device name, for example
+.Dq sd
+for a SCSI disk on an HP300 or a
+.Dq pty
+for pseudo-devices.
+.It Cm b | Cm c | Cm w
+Type of device. If the
+device is a block type device such as a tape or disk drive which needs
+both cooked and raw special files,
+the type is
+.Cm b .
+Whiteout nodes are type
+.Cm w .
+All other devices are character type devices, such as terminal
+and pseudo devices, and are type
+.Cm c .
+.It Ar major
+The major device number is an integer number which tells the kernel
+which device driver entry point to use.
+.It Ar minor
+The minor device number tells the kernel which one of several similar
+devices the node corresponds to; for example, it may be a specific serial
+port or pty.
+.It Ar unit and subunit
+The unit and subunit numbers select a subset of a device; for example, the
+unit may specify a particular SCSI disk, and the subunit a partition on
+that disk. (Currently this form of specification is only supported by the
+.Ar bsdos
+format, for compatibility with the
+.Bsx
+.Xr mknod 8 . )
+.El
+.Pp
+Device numbers for different operating systems may be packed in a different
+format. To create device nodes that may be used by such an operating system
+(e.g. in an exported file system used for netbooting), the
+.Fl F
+option is used. The following formats are recognized:
+native,
+386bsd,
+4bsd,
+bsdos,
+freebsd,
+hpux,
+isc,
+linux,
+netbsd,
+osf1,
+sco,
+solaris,
+sunos,
+svr3,
+svr4 and
+ultrix.
+.Pp
+Alternatively, a single opaque device number may be specified.
+.Sh SEE ALSO
+.Xr mkfifo 1 ,
+.Xr mkfifo 2 ,
+.Xr mknod 2
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v6 .
+The
+.Fl F
+option appeared in
+.Nx 1.4 .
diff --git a/file_cmds/mknod/mknod.c b/file_cmds/mknod/mknod.c
new file mode 100644
index 0000000..c4848af
--- /dev/null
+++ b/file_cmds/mknod/mknod.c
@@ -0,0 +1,405 @@
+/* $NetBSD: mknod.c,v 1.15 1998/09/11 07:22:13 mycroft Exp $ */
+
+/*-
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1998 The NetBSD Foundation, Inc. All rights reserved.\n");
+__RCSID("$NetBSD: mknod.c,v 1.15 1998/09/11 07:22:13 mycroft Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+int main __P((int, char *[]));
+static void usage __P((void));
+typedef dev_t pack_t __P((int, u_long []));
+
+
+pack_t pack_native;
+
+dev_t
+pack_native(n, numbers)
+ int n;
+ u_long numbers[];
+{
+ dev_t dev=0; /* Quiet -Wall */
+
+ if (n == 2) {
+ dev = makedev(numbers[0], numbers[1]);
+ if (major(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (minor(dev) != numbers[1])
+ errx(1, "invalid minor number");
+ } else
+ errx(1, "too many fields for format");
+ return (dev);
+}
+
+
+#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8)))
+#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \
+ (((x) & 0x000000ff) >> 0)))
+#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \
+ (((y) << 12) & 0xfff00000) | \
+ (((y) << 0) & 0x000000ff)))
+
+pack_t pack_netbsd;
+
+dev_t
+pack_netbsd(n, numbers)
+ int n;
+ u_long numbers[];
+{
+ dev_t dev=0; /* Quiet -Wall */
+
+ if (n == 2) {
+ dev = makedev_netbsd(numbers[0], numbers[1]);
+ if (major_netbsd(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (minor_netbsd(dev) != numbers[1])
+ errx(1, "invalid minor number");
+ } else
+ errx(1, "too many fields for format");
+ return (dev);
+}
+
+
+#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
+#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0))
+#define makedev_freebsd(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \
+ (((y) << 0) & 0xffff00ff)))
+
+pack_t pack_freebsd;
+
+dev_t
+pack_freebsd(n, numbers)
+ int n;
+ u_long numbers[];
+{
+ dev_t dev=0; /* Quiet -Wall */
+
+ if (n == 2) {
+ dev = makedev_freebsd(numbers[0], numbers[1]);
+ if (major_freebsd(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (minor_freebsd(dev) != numbers[1])
+ errx(1, "invalid minor number");
+ } else
+ errx(1, "too many fields for format");
+ return (dev);
+}
+
+
+#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
+#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
+#define makedev_8_8(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \
+ (((y) << 0) & 0x000000ff)))
+
+pack_t pack_8_8;
+
+dev_t
+pack_8_8(n, numbers)
+ int n;
+ u_long numbers[];
+{
+ dev_t dev=0; /* Quiet -Wall */
+
+ if (n == 2) {
+ dev = makedev_8_8(numbers[0], numbers[1]);
+ if (major_8_8(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (minor_8_8(dev) != numbers[1])
+ errx(1, "invalid minor number");
+ } else
+ errx(1, "too many fields for format");
+ return (dev);
+}
+
+
+#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20))
+#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0))
+#define makedev_12_20(x,y) ((dev_t)((((x) << 20) & 0xfff00000) | \
+ (((y) << 0) & 0x000fffff)))
+
+pack_t pack_12_20;
+
+dev_t
+pack_12_20(n, numbers)
+ int n;
+ u_long numbers[];
+{
+ dev_t dev=0; /* Quiet -Wall */
+
+ if (n == 2) {
+ dev = makedev_12_20(numbers[0], numbers[1]);
+ if (major_12_20(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (minor_12_20(dev) != numbers[1])
+ errx(1, "invalid minor number");
+ } else
+ errx(1, "too many fields for format");
+ return (dev);
+}
+
+
+#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18))
+#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0))
+#define makedev_14_18(x,y) ((dev_t)((((x) << 18) & 0xfffc0000) | \
+ (((y) << 0) & 0x0003ffff)))
+
+pack_t pack_14_18;
+
+dev_t
+pack_14_18(n, numbers)
+ int n;
+ u_long numbers[];
+{
+ dev_t dev=0; /* Quiet -Wall */
+
+ if (n == 2) {
+ dev = makedev_14_18(numbers[0], numbers[1]);
+ if (major_14_18(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (minor_14_18(dev) != numbers[1])
+ errx(1, "invalid minor number");
+ } else
+ errx(1, "too many fields for format");
+ return (dev);
+}
+
+
+#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24))
+#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0))
+#define makedev_8_24(x,y) ((dev_t)((((x) << 24) & 0xff000000) | \
+ (((y) << 0) & 0x00ffffff)))
+
+pack_t pack_8_24;
+
+dev_t
+pack_8_24(n, numbers)
+ int n;
+ u_long numbers[];
+{
+ dev_t dev=0; /* Quiet -Wall */
+
+ if (n == 2) {
+ dev = makedev_8_24(numbers[0], numbers[1]);
+ if (major_8_24(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (minor_8_24(dev) != numbers[1])
+ errx(1, "invalid minor number");
+ } else
+ errx(1, "too many fields for format");
+ return (dev);
+}
+
+
+#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20))
+#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8))
+#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
+#define makedev_12_12_8(x,y,z) ((dev_t)((((x) << 20) & 0xfff00000) | \
+ (((y) << 8) & 0x000fff00) | \
+ (((z) << 0) & 0x000000ff)))
+
+pack_t pack_bsdos;
+
+dev_t
+pack_bsdos(n, numbers)
+ int n;
+ u_long numbers[];
+{
+ dev_t dev=0; /* Quiet -Wall */
+
+ if (n == 2) {
+ dev = makedev_12_20(numbers[0], numbers[1]);
+ if (major_12_20(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (minor_12_20(dev) != numbers[1])
+ errx(1, "invalid minor number");
+ } else if (n == 3) {
+ dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]);
+ if (major_12_12_8(dev) != numbers[0])
+ errx(1, "invalid major number");
+ if (unit_12_12_8(dev) != numbers[1])
+ errx(1, "invalid unit number");
+ if (subunit_12_12_8(dev) != numbers[2])
+ errx(1, "invalid subunit number");
+ } else
+ errx(1, "too many fields for format");
+ return (dev);
+}
+
+
+struct format {
+ char *name;
+ pack_t *pack;
+} formats[] = {
+ {"386bsd", pack_8_8},
+ {"4bsd", pack_8_8},
+ {"bsdos", pack_bsdos},
+ {"freebsd", pack_freebsd},
+ {"hpux", pack_8_24},
+ {"isc", pack_8_8},
+ {"linux", pack_8_8},
+ {"native", pack_native},
+ {"netbsd", pack_netbsd},
+ {"osf1", pack_12_20},
+ {"sco", pack_8_8},
+ {"solaris", pack_14_18},
+ {"sunos", pack_8_8},
+ {"svr3", pack_8_8},
+ {"svr4", pack_14_18},
+ {"ultrix", pack_8_8},
+};
+
+int compare_format __P((const void *, const void *));
+
+int
+compare_format(key, element)
+ const void *key;
+ const void *element;
+{
+ const char *name;
+ const struct format *format;
+
+ name = key;
+ format = element;
+
+ return (strcmp(name, format->name));
+}
+
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *name;
+ mode_t mode;
+ dev_t dev;
+ pack_t *pack;
+ u_long numbers[8];
+ struct format *format;
+ char *p;
+ int n;
+ int ch;
+
+ pack = pack_native;
+
+ while ((ch = getopt(argc, argv, "F:")) != -1) {
+ switch (ch) {
+ case 'F':
+ format = bsearch(optarg, formats,
+ sizeof(formats)/sizeof(formats[0]),
+ sizeof(formats[0]), compare_format);
+ if (format == 0)
+ errx(1, "invalid format: %s", optarg);
+ pack = format->pack;
+ break;
+
+ default:
+ case '?':
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2 || argc > 10)
+ usage();
+
+ name = *argv;
+ argc--;
+ argv++;
+
+ mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
+ if (*argv[0] == 'c')
+ mode |= S_IFCHR;
+ else if (*argv[0] == 'b')
+ mode |= S_IFBLK;
+ else if (*argv[0] == 'w')
+ mode |= S_IFWHT;
+ else
+ errx(1, "node type must be 'b' or 'c' or 'w'.");
+ argc--;
+ argv++;
+
+ for (n = 0; n < argc; n++) {
+ if (S_ISWHT(mode)) {
+ errx(1, "whiteout nodes have no device numbers.");
+ }
+ numbers[n] = strtoul(argv[n], &p, 0);
+ if ((p && *p != '\0') || (numbers[n] == ULONG_MAX && errno == ERANGE))
+ errx(1, "invalid number: %s", argv[n]);
+ }
+
+ if (S_ISWHT(mode))
+ dev = 0;
+ else if (argc == 1)
+ dev = (dev_t)numbers[0];
+ else
+ dev = (*pack)(argc, numbers);
+
+#if 0
+ printf("name: %s\nmode: %05o\ndev: %08x\n", name, mode, dev);
+#else
+ if (mknod(name, mode, dev) < 0)
+ err(1, "%s", name);
+#endif
+
+ exit(0);
+}
+
+void
+usage()
+{
+
+ fprintf(stderr, "usage: mknod [-F format] name [b | c] major minor\n");
+ fprintf(stderr, " mknod [-F format] name [b | c] major unit subunit\n");
+ fprintf(stderr, " mknod name [b | c] number\n");
+ fprintf(stderr, " mknod name w\n");
+ exit(1);
+}
diff --git a/file_cmds/mtree/commoncrypto.c b/file_cmds/mtree/commoncrypto.c
new file mode 100644
index 0000000..11e97ce
--- /dev/null
+++ b/file_cmds/mtree/commoncrypto.c
@@ -0,0 +1,378 @@
+#include <dispatch/dispatch.h>
+#include <os/assumes.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/xattr.h>
+#include <stdbool.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/attr.h>
+#include <unistd.h>
+#include <sys/xattr.h>
+#include <sys/mount.h>
+#include <apfs/apfs_fsctl.h>
+
+#include "commoncrypto.h"
+#include "extern.h"
+#include "metrics.h"
+
+const int kSHA256NullTerminatedBuffLen = 65;
+static const char hex[] = "0123456789abcdef";
+
+/* Functions for SHA256_File_XATTRs */
+#define SHA256_Data(d, s, b) Digest_Data(kCCDigestSHA256, d, s, b)
+char *Digest_Data(CCDigestAlg algorithm, void *data, size_t size, char *buf);
+void Quicksort(char **array, int num);
+
+/* Generic version of libmd's *_File() functions. */
+char *
+Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
+{
+ int fd;
+ __block CCDigestCtx ctx;
+ dispatch_queue_t queue;
+ dispatch_semaphore_t sema;
+ dispatch_io_t io;
+ __block int s_error = 0;
+ uint8_t digest[32]; // SHA256 is the biggest
+ size_t i, length;
+
+ /* dispatch_io_create_with_path requires an absolute path */
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ (void)fcntl(fd, F_NOCACHE, 1);
+
+ (void)os_assumes_zero(CCDigestInit(algorithm, &ctx));
+
+ queue = dispatch_queue_create("com.apple.mtree.io", NULL);
+ os_assert(queue);
+ sema = dispatch_semaphore_create(0);
+ os_assert(sema);
+
+ io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
+ if (error != 0) {
+ s_error = error;
+ RECORD_FAILURE(27440, s_error);
+ }
+ (void)close(fd);
+ (void)dispatch_semaphore_signal(sema);
+ });
+ os_assert(io);
+ dispatch_io_read(io, 0, SIZE_MAX, queue, ^(__unused bool done, dispatch_data_t data, int error) {
+ if (data != NULL) {
+ (void)dispatch_data_apply(data, ^(__unused dispatch_data_t region, __unused size_t offset, const void *buffer, size_t size) {
+ (void)os_assumes_zero(CCDigestUpdate(&ctx, buffer, size));
+ return (bool)true;
+ });
+ }
+
+ if (error != 0) {
+ s_error = error;
+ RECORD_FAILURE(27441, s_error);
+ }
+ });
+ dispatch_release(io); // it will close on its own
+
+ (void)dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+
+ dispatch_release(queue);
+ dispatch_release(sema);
+
+ if (s_error != 0) {
+ errno = s_error;
+ return NULL;
+ }
+
+ /* Finalize and convert to hex. */
+ (void)os_assumes_zero(CCDigestFinal(&ctx, digest));
+ length = CCDigestOutputSize(&ctx);
+ os_assert(length <= sizeof(digest));
+ for (i = 0; i < length; i++) {
+ buf[i+i] = hex[digest[i] >> 4];
+ buf[i+i+1] = hex[digest[i] & 0x0f];
+ }
+ buf[i+i] = '\0';
+
+ return buf;
+}
+
+xattr_info *
+SHA256_Path_XATTRs(char *path, char *buf) {
+ xattr_info *ai = NULL;
+
+ if (mflag) {
+ ai = get_xdstream_privateid(path, buf);
+ } else {
+ ai = calculate_SHA256_XATTRs(path, buf);
+ }
+
+ return ai;
+}
+
+
+xattr_info *
+calculate_SHA256_XATTRs(char *path, char *buf)
+{
+ errno_t error = 0;
+ char *xattrsSummary = NULL;
+ int options = XATTR_SHOWCOMPRESSION | XATTR_NOFOLLOW;
+ ssize_t nameBufSize = listxattr(path, NULL, 0, options);
+ uint64_t xd_obj_id = 0;
+ if (nameBufSize > 0) {
+ char *nameBuf = malloc(nameBufSize);
+
+ listxattr(path, nameBuf, nameBufSize, options);
+
+ size_t xattrsLen = 1;
+ size_t xattrIndex = 0;
+ char **xattrs = malloc(xattrsLen * sizeof(char *));
+ char *nextName = nameBuf;
+ while (nextName < nameBuf + nameBufSize)
+ {
+ char *name = nextName;
+ if (xattrIndex == xattrsLen) {
+ xattrsLen *= 2;
+ xattrs = realloc(xattrs, xattrsLen * sizeof(char *));
+ }
+ xattrs[xattrIndex++] = name;
+ nextName += strlen(name) + 1;
+ }
+
+ // sort the xattr array as they're not guaranteed to come in the same order
+ qsort_b(xattrs, xattrIndex, sizeof(char *), ^(const void *l, const void *r) {
+ char *left = *(char **)l;
+ char *right = *(char **)r;
+ return strcmp(left, right);
+ });
+
+ // gather the data for the xattrs
+ bool didAddXATTR = false;
+ int xattrBufLen = kSHA256NullTerminatedBuffLen;
+ void *xattrBuf = malloc(xattrBufLen); // resized if necessary
+ char *digest;
+ ssize_t result = 0;
+ char *oldSummary = NULL;
+ //XXX Make xattr_info an array of structs if necessary
+ xattr_info *ai = (xattr_info *) malloc(sizeof(xattr_info));
+ for (int i = 0; i < xattrIndex; i++) {
+ char *name = xattrs[i];
+ ssize_t xlen = getxattr(path, name, NULL, 0, 0, options);
+ if (xlen > xattrBufLen) {
+ xattrBufLen = xlen;
+ xattrBuf = realloc(xattrBuf, xattrBufLen);
+ }
+ bzero(xattrBuf, xattrBufLen);
+ result = getxattr(path, name, xattrBuf, xattrBufLen, 0, options);
+ if (result < 0) {
+ error = errno;
+ RECORD_FAILURE(27442, error);
+ errc(1, error, "SHA256_Path_XATTRs getxattr of \"%s\" at path \"%s\" failed with error", name, path);
+ }
+
+ digest = SHA256_Data(xattrBuf, xattrBufLen, buf);
+ if (!digest)
+ err(1, "%s", xattrsSummary);
+ if (!didAddXATTR)
+ {
+ didAddXATTR = true;
+ asprintf(&xattrsSummary, "%s:%s", name, digest);
+ } else {
+ oldSummary = xattrsSummary;
+ asprintf(&xattrsSummary, "%s, %s:%s", oldSummary, name, digest);
+ free(oldSummary);
+ }
+#ifdef APFSIOC_XDSTREAM_OBJ_ID
+ // System volume has stream based xattrs only in form of resource forks
+ if (!strncmp(name, XATTR_RESOURCEFORK_NAME, XATTR_MAXNAMELEN)) {
+ struct xdstream_obj_id x_obj;
+ x_obj.xdi_name = name;
+ x_obj.xdi_xdtream_obj_id = 0;
+
+ result = fsctl(path, APFSIOC_XDSTREAM_OBJ_ID, &x_obj, 0);
+ if (!result) {
+ xd_obj_id = x_obj.xdi_xdtream_obj_id;
+ } else if (errno == ENOTTY) {
+ // Not an apfs filesystem, return zero.
+ xd_obj_id = 0;
+ } else {
+ error = errno;
+ RECORD_FAILURE(27444, error);
+ errc(1, error, "%s - SHA256_Path_XATTRs APFSIOC_XDSTREAM_OBJ_ID failed with %d", path, error);
+ }
+ }
+#endif
+ ai->xdstream_priv_id = xd_obj_id;
+ }
+
+ free(xattrBuf);
+ free(nameBuf);
+ free(xattrs);
+
+ digest = SHA256_Data(xattrsSummary, strlen(xattrsSummary) * sizeof(char), buf);
+ if (!digest)
+ err(1, "%s", xattrsSummary);
+
+ ai->digest = digest;
+
+ free(xattrsSummary);
+ return ai;
+ }
+ return NULL;
+}
+
+xattr_info *
+get_xdstream_privateid(char *path, char *buf) {
+ errno_t error = 0;
+ int options = XATTR_SHOWCOMPRESSION | XATTR_NOFOLLOW;
+ ssize_t nameBufSize = listxattr(path, NULL, 0, options);
+ uint64_t xd_obj_id = 0;
+
+ if (nameBufSize > 0) {
+ //XXX Make xattr_info an array of structs if necessary
+ xattr_info *ai = (xattr_info *) malloc(sizeof(xattr_info));
+ char *nameBuf = malloc(nameBufSize);
+ int result = 0;
+
+ listxattr(path, nameBuf, nameBufSize, options);
+
+ size_t xattrsLen = 1;
+ size_t xattrIndex = 0;
+ char **xattrs = malloc(xattrsLen * sizeof(char *));
+ char *nextName = nameBuf;
+ while (nextName < nameBuf + nameBufSize)
+ {
+ char *name = nextName;
+ if (xattrIndex == xattrsLen) {
+ xattrsLen *= 2;
+ xattrs = realloc(xattrs, xattrsLen * sizeof(char *));
+ }
+ xattrs[xattrIndex++] = name;
+ nextName += strlen(name) + 1;
+ }
+
+ for (int i = 0; i < xattrIndex; i++) {
+ char *name = xattrs[i];
+ // System volume has stream based xattrs only in form of resource forks
+ if (!strncmp(name, XATTR_RESOURCEFORK_NAME, XATTR_MAXNAMELEN)) {
+ struct xdstream_obj_id x_obj;
+ x_obj.xdi_name = name;
+ x_obj.xdi_xdtream_obj_id = 0;
+
+ result = fsctl(path, APFSIOC_XDSTREAM_OBJ_ID, &x_obj, 0);
+ if (!result && x_obj.xdi_xdtream_obj_id != 0) {
+ xd_obj_id = x_obj.xdi_xdtream_obj_id;
+ } else if (errno == ENOTTY) {
+ // Not an apfs filesystem, return zero.
+ xd_obj_id = 0;
+ } else {
+ error = errno;
+ RECORD_FAILURE(29983, error);
+ errc(1, error, "%s - SHA256_Path_XATTRs APFSIOC_XDSTREAM_OBJ_ID failed with %d", path, error);
+ }
+ }
+ }
+
+ ai->xdstream_priv_id = xd_obj_id;
+ // insert a dummy value as digest is not used in presence of mflag
+ ai->digest = "authapfs";
+
+ free(nameBuf);
+ free(xattrs);
+ return ai;
+ }
+
+ return NULL;
+}
+
+char *SHA256_Path_ACL(char *path, char *buf)
+{
+ errno_t error = 0;
+ int result = 0;
+ char *data = NULL;
+ char *digest = NULL;
+
+ struct attrlist list = {
+ .bitmapcount = ATTR_BIT_MAP_COUNT,
+ .commonattr = ATTR_CMN_RETURNED_ATTRS | ATTR_CMN_EXTENDED_SECURITY,
+ };
+
+ struct ACLBuf {
+ uint32_t len;
+ attribute_set_t returned_attrs;
+ attrreference_t acl;
+ char buf[8192]; // current acls are up to 3116 bytes, but they may increase in the future
+ } __attribute__((aligned(4), packed));
+
+ struct ACLBuf aclBuf;
+
+ result = getattrlist(path, &list, &aclBuf, sizeof(aclBuf), FSOPT_NOFOLLOW);
+
+ if (result) {
+ error = errno;
+ RECORD_FAILURE(27445, error);
+ errc(1, error, "SHA256_Path_ACL: getattrlist");
+ }
+
+ // if the path does not have an acl, return none
+ if ( ( ! ( aclBuf.returned_attrs.commonattr & ATTR_CMN_EXTENDED_SECURITY ) )
+ || ( aclBuf.acl.attr_length == 0 ) ) {
+ return kNone;
+ }
+
+ data = ((char*)&aclBuf.acl) + aclBuf.acl.attr_dataoffset;
+
+ digest = SHA256_Data(data, aclBuf.acl.attr_length, buf);
+ if (!digest)
+ err(1, "SHA256_Path_ACL: SHA256_Data");
+
+ return digest;
+}
+
+/* Functions for Digest_Path_* */
+char *
+Digest_Data(CCDigestAlg algorithm, void *data, size_t size, char *buf) {
+
+ uint8_t digest[32]; // SHA256 is the biggest
+ CCDigestCtx ctx;
+ size_t i, length;
+
+ (void)os_assumes_zero(CCDigestInit(algorithm, &ctx));
+ (void)os_assumes_zero(CCDigestUpdate(&ctx, data, size));
+
+ /* Finalize and convert to hex. */
+ (void)os_assumes_zero(CCDigestFinal(&ctx, digest));
+ length = CCDigestOutputSize(&ctx);
+ os_assert(length <= sizeof(digest));
+ for (i = 0; i < length; i++) {
+ buf[i+i] = hex[digest[i] >> 4];
+ buf[i+i+1] = hex[digest[i] & 0x0f];
+ }
+ buf[i+i] = '\0';
+
+ return buf;
+}
+
+uint64_t
+get_sibling_id(const char *path)
+{
+ struct attrlist attr_list = {0};
+ struct attrbuf attr_buf = {0};
+ errno_t error = 0;
+
+ attr_list.bitmapcount = ATTR_BIT_MAP_COUNT;
+ attr_list.forkattr = ATTR_CMNEXT_LINKID;
+
+ error = getattrlist(path, &attr_list, &attr_buf, sizeof(attr_buf), FSOPT_ATTR_CMN_EXTENDED | FSOPT_NOFOLLOW);
+ if (error) {
+ error = errno;
+ RECORD_FAILURE(27447, error);
+ errc(1, error, "get_sibling_id: getattrlist failed for %s\n", path);
+ }
+
+ return attr_buf.sibling_id;
+}
diff --git a/file_cmds/mtree/commoncrypto.h b/file_cmds/mtree/commoncrypto.h
new file mode 100644
index 0000000..c547035
--- /dev/null
+++ b/file_cmds/mtree/commoncrypto.h
@@ -0,0 +1,36 @@
+
+#ifndef _COMMON_CRYPTO_H_
+#define _COMMON_CRYPTO_H_
+
+#include <CommonCrypto/CommonDigestSPI.h>
+
+#define kNone "none"
+
+extern const int kSHA256NullTerminatedBuffLen;
+
+#define MD5File(f, b) Digest_File(kCCDigestMD5, f, b)
+#define SHA1_File(f, b) Digest_File(kCCDigestSHA1, f, b)
+#define RIPEMD160_File(f, b) Digest_File(kCCDigestRMD160, f, b)
+#define SHA256_File(f, b) Digest_File(kCCDigestSHA256, f, b)
+
+typedef struct {
+ char *digest;
+ uint64_t xdstream_priv_id;
+} xattr_info;
+
+struct attrbuf {
+ uint32_t info_length;
+ uint64_t sibling_id;
+} __attribute__((aligned, packed));
+
+typedef struct attrbuf attrbuf_t;
+
+char *Digest_File(CCDigestAlg algorithm, const char *filename, char *buf);
+
+xattr_info *calculate_SHA256_XATTRs(char *path, char *buf);
+xattr_info *SHA256_Path_XATTRs(char *path, char *buf);
+xattr_info *get_xdstream_privateid(char *path, char *buf);
+char *SHA256_Path_ACL(char *path, char *buf);
+uint64_t get_sibling_id(const char *path);
+
+#endif /* _COMMON_CRYPTO_H_ */
diff --git a/file_cmds/mtree/compare.c b/file_cmds/mtree/compare.c
new file mode 100644
index 0000000..e585928
--- /dev/null
+++ b/file_cmds/mtree/compare.c
@@ -0,0 +1,688 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/compare.c,v 1.34 2005/03/29 11:44:17 tobez Exp $");
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#ifndef __APPLE__
+#ifdef ENABLE_MD5
+#include <md5.h>
+#endif
+#ifdef ENABLE_RMD160
+#include <ripemd.h>
+#endif
+#ifdef ENABLE_SHA1
+#include <sha.h>
+#endif
+#ifdef ENABLE_SHA256
+#include <sha256.h>
+#endif
+#endif /* !__APPLE__ */
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <vis.h>
+
+#include "metrics.h"
+#include "mtree.h"
+#include "extern.h"
+
+#ifdef __APPLE__
+#include "commoncrypto.h"
+#endif /* __APPLE__ */
+
+#define INDENTNAMELEN 8
+#define LABEL \
+ if (!label++) { \
+ len = printf("%s changed\n", RP(p)); \
+ tab = "\t"; \
+ }
+
+extern CFMutableDictionaryRef dict;
+
+// max/min times apfs can store on disk
+#define APFS_MAX_TIME 0x7fffffffffffffffLL
+#define APFS_MIN_TIME (-0x7fffffffffffffffLL-1)
+
+static uint64_t
+timespec_to_apfs_timestamp(struct timespec *ts)
+{
+ int64_t total;
+ int64_t seconds;
+
+ // `tv_nsec' can be > one billion, so we split it into two components:
+ // seconds and actual nanoseconds
+ // this allows us to detect overflow on the *total* number of nanoseconds
+ // e.g. if (MAX_SECONDS+2, -2billion) is passed in, we return MAX_SECONDS
+ seconds = ((int64_t)ts->tv_nsec / (int64_t)NSEC_PER_SEC);
+
+ // compute total nanoseconds, checking for overflow:
+ // seconds = sec + (ns/10e9)
+ // total = seconds*10e9 + ns%10e9
+ if (__builtin_saddll_overflow(ts->tv_sec, seconds, &seconds) ||
+ __builtin_smulll_overflow(seconds, NSEC_PER_SEC, &total) ||
+ __builtin_saddll_overflow(((int64_t)ts->tv_nsec % (int64_t)NSEC_PER_SEC), total, &total)) {
+ // checking the sign of "seconds" tells us whether to cap the value at
+ // the max or min time
+ total = (ts->tv_sec > 0) ? APFS_MAX_TIME : APFS_MIN_TIME;
+ }
+
+ return (uint64_t)total;
+}
+
+static void
+set_key_value_pair(void *in_key, uint64_t *in_val, bool is_string)
+{
+ CFStringRef key;
+ CFNumberRef val;
+
+ if (is_string) {
+ key = CFStringCreateWithCString(NULL, (const char*)in_key, kCFStringEncodingUTF8);
+
+ } else {
+ key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%llu"), *(uint64_t*)in_key);
+ }
+
+ val = CFNumberCreate(NULL, kCFNumberSInt64Type, in_val);
+
+ // we always expect the key to be not present
+ if (key && val) {
+ CFDictionaryAddValue(dict, key, val);
+ } else {
+ if (key) {
+ CFRelease(key);
+ }
+ if (val) {
+ CFRelease(val);
+ }
+ RECORD_FAILURE(1, EINVAL);
+ errx(1, "set_key_value_pair: key/value is null");
+ }
+
+ if (key) {
+ CFRelease(key);
+ }
+ if (val) {
+ CFRelease(val);
+ }
+}
+
+int
+compare(char *name __unused, NODE *s, FTSENT *p)
+{
+ int error = 0;
+ struct timeval tv[2];
+ uint32_t val;
+ int fd, label;
+ off_t len;
+ char *cp;
+ const char *tab = "";
+ char *fflags, *badflags;
+ u_long flags;
+
+ label = 0;
+ switch(s->type) {
+ case F_BLOCK:
+ if (!S_ISBLK(p->fts_statp->st_mode)) {
+ RECORD_FAILURE(2, EINVAL);
+ goto typeerr;
+ }
+ break;
+ case F_CHAR:
+ if (!S_ISCHR(p->fts_statp->st_mode)) {
+ RECORD_FAILURE(3, EINVAL);
+ goto typeerr;
+ }
+ break;
+ case F_DIR:
+ if (!S_ISDIR(p->fts_statp->st_mode)) {
+ RECORD_FAILURE(4, EINVAL);
+ goto typeerr;
+ }
+ break;
+ case F_FIFO:
+ if (!S_ISFIFO(p->fts_statp->st_mode)) {
+ RECORD_FAILURE(5, EINVAL);
+ goto typeerr;
+ }
+ break;
+ case F_FILE:
+ if (!S_ISREG(p->fts_statp->st_mode)) {
+ RECORD_FAILURE(6, EINVAL);
+ goto typeerr;
+ }
+ break;
+ case F_LINK:
+ if (!S_ISLNK(p->fts_statp->st_mode)) {
+ RECORD_FAILURE(7, EINVAL);
+ goto typeerr;
+ }
+ break;
+ case F_SOCK:
+ if (!S_ISSOCK(p->fts_statp->st_mode)) {
+ RECORD_FAILURE(8, EINVAL);
+typeerr: LABEL;
+ (void)printf("\ttype expected %s found %s\n",
+ ftype(s->type), inotype(p->fts_statp->st_mode));
+ return (label);
+ }
+ break;
+ }
+ /* Set the uid/gid first, then set the mode. */
+ if (s->flags & (F_UID | F_UNAME) && s->st_uid != p->fts_statp->st_uid) {
+ LABEL;
+ (void)printf("%suser expected %lu found %lu",
+ tab, (u_long)s->st_uid, (u_long)p->fts_statp->st_uid);
+ if (uflag) {
+ if (chown(p->fts_accpath, s->st_uid, -1)) {
+ error = errno;
+ RECORD_FAILURE(9, error);
+ (void)printf(" not modified: %s\n",
+ strerror(error));
+ } else {
+ (void)printf(" modified\n");
+ }
+ } else {
+ (void)printf("\n");
+ }
+ tab = "\t";
+ }
+ if (s->flags & (F_GID | F_GNAME) && s->st_gid != p->fts_statp->st_gid) {
+ LABEL;
+ (void)printf("%sgid expected %lu found %lu",
+ tab, (u_long)s->st_gid, (u_long)p->fts_statp->st_gid);
+ if (uflag) {
+ if (chown(p->fts_accpath, -1, s->st_gid)) {
+ error = errno;
+ RECORD_FAILURE(10, error);
+ (void)printf(" not modified: %s\n",
+ strerror(error));
+ } else {
+ (void)printf(" modified\n");
+ }
+ } else {
+ (void)printf("\n");
+ }
+ tab = "\t";
+ }
+ if (s->flags & F_MODE &&
+ !S_ISLNK(p->fts_statp->st_mode) &&
+ s->st_mode != (p->fts_statp->st_mode & MBITS)) {
+ LABEL;
+ (void)printf("%spermissions expected %#o found %#o",
+ tab, s->st_mode, p->fts_statp->st_mode & MBITS);
+ if (uflag) {
+ if (chmod(p->fts_accpath, s->st_mode)) {
+ error = errno;
+ RECORD_FAILURE(11, error);
+ (void)printf(" not modified: %s\n",
+ strerror(error));
+ } else {
+ (void)printf(" modified\n");
+ }
+ } else {
+ (void)printf("\n");
+ }
+ tab = "\t";
+ }
+ if (s->flags & F_NLINK && s->type != F_DIR &&
+ s->st_nlink != p->fts_statp->st_nlink) {
+ LABEL;
+ (void)printf("%slink_count expected %u found %u\n",
+ tab, s->st_nlink, p->fts_statp->st_nlink);
+ tab = "\t";
+ }
+ if (s->flags & F_SIZE && s->st_size != p->fts_statp->st_size &&
+ !S_ISDIR(p->fts_statp->st_mode)) {
+ LABEL;
+ (void)printf("%ssize expected %jd found %jd\n", tab,
+ (intmax_t)s->st_size, (intmax_t)p->fts_statp->st_size);
+ tab = "\t";
+ }
+ if ((s->flags & F_TIME) &&
+ ((s->st_mtimespec.tv_sec != p->fts_statp->st_mtimespec.tv_sec) ||
+ (s->st_mtimespec.tv_nsec != p->fts_statp->st_mtimespec.tv_nsec))) {
+ if (!mflag) {
+ LABEL;
+ (void)printf("%smodification time expected %.24s.%09ld ",
+ tab, ctime(&s->st_mtimespec.tv_sec), s->st_mtimespec.tv_nsec);
+ (void)printf("found %.24s.%09ld",
+ ctime(&p->fts_statp->st_mtimespec.tv_sec), p->fts_statp->st_mtimespec.tv_nsec);
+ if (uflag) {
+ tv[0].tv_sec = s->st_mtimespec.tv_sec;
+ tv[0].tv_usec = s->st_mtimespec.tv_nsec / 1000;
+ tv[1] = tv[0];
+ if (utimes(p->fts_accpath, tv)) {
+ error = errno;
+ RECORD_FAILURE(12, error);
+ (void)printf(" not modified: %s\n",
+ strerror(error));
+ } else {
+ (void)printf(" modified\n");
+ }
+ } else {
+ (void)printf("\n");
+ }
+ tab = "\t";
+ }
+ if (!insert_mod && mflag) {
+ uint64_t s_mod_time = timespec_to_apfs_timestamp(&s->st_mtimespec);
+ char *mod_string = "MODIFICATION";
+ set_key_value_pair(mod_string, &s_mod_time, true);
+ insert_mod = 1;
+ }
+ }
+ if (s->flags & F_CKSUM) {
+ if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0) {
+ LABEL;
+ error = errno;
+ RECORD_FAILURE(13, error);
+ (void)printf("%scksum: %s: %s\n",
+ tab, p->fts_accpath, strerror(error));
+ tab = "\t";
+ } else if (crc(fd, &val, &len)) {
+ (void)close(fd);
+ LABEL;
+ error = errno;
+ RECORD_FAILURE(14, error);
+ (void)printf("%scksum: %s: %s\n",
+ tab, p->fts_accpath, strerror(error));
+ tab = "\t";
+ } else {
+ (void)close(fd);
+ if (s->cksum != val) {
+ LABEL;
+ (void)printf("%scksum expected %lu found %lu\n",
+ tab, s->cksum, (unsigned long)val);
+ tab = "\t";
+ }
+ }
+ }
+ if (s->flags & F_FLAGS) {
+ // There are unpublished flags that should not fail comparison
+ // we convert to string and back to filter them out
+ fflags = badflags = flags_to_string(p->fts_statp->st_flags);
+ if (strcmp("none", fflags) == 0) {
+ flags = 0;
+ } else if (strtofflags(&badflags, &flags, NULL) != 0)
+ errx(1, "invalid flag %s", badflags);
+ free(fflags);
+ if (s->st_flags != flags) {
+ LABEL;
+ fflags = flags_to_string(s->st_flags);
+ (void)printf("%sflags expected \"%s\"", tab, fflags);
+ free(fflags);
+
+ fflags = flags_to_string(flags);
+ (void)printf(" found \"%s\"", fflags);
+ free(fflags);
+
+ if (uflag) {
+ if (chflags(p->fts_accpath, (u_int)s->st_flags)) {
+ error = errno;
+ RECORD_FAILURE(15, error);
+ (void)printf(" not modified: %s\n",
+ strerror(error));
+ } else {
+ (void)printf(" modified\n");
+ }
+ } else {
+ (void)printf("\n");
+ }
+ tab = "\t";
+ }
+ }
+#ifdef ENABLE_MD5
+ if (s->flags & F_MD5) {
+ char *new_digest, buf[33];
+#ifdef __clang__
+/* clang doesn't like MD5 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ new_digest = MD5File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
+ if (!new_digest) {
+ LABEL;
+ error = errno;
+ RECORD_FAILURE(16, error);
+ printf("%sMD5: %s: %s\n", tab, p->fts_accpath,
+ strerror(error));
+ tab = "\t";
+ } else if (strcmp(new_digest, s->md5digest)) {
+ LABEL;
+ printf("%sMD5 expected %s found %s\n", tab, s->md5digest,
+ new_digest);
+ tab = "\t";
+ }
+ }
+#endif /* ENABLE_MD5 */
+#ifdef ENABLE_SHA1
+ if (s->flags & F_SHA1) {
+ char *new_digest, buf[41];
+#ifdef __clang__
+/* clang doesn't like SHA1 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ new_digest = SHA1_File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
+ if (!new_digest) {
+ LABEL;
+ error = errno;
+ RECORD_FAILURE(17, error);
+ printf("%sSHA-1: %s: %s\n", tab, p->fts_accpath,
+ strerror(error));
+ tab = "\t";
+ } else if (strcmp(new_digest, s->sha1digest)) {
+ LABEL;
+ printf("%sSHA-1 expected %s found %s\n",
+ tab, s->sha1digest, new_digest);
+ tab = "\t";
+ }
+ }
+#endif /* ENABLE_SHA1 */
+#ifdef ENABLE_RMD160
+ if (s->flags & F_RMD160) {
+ char *new_digest, buf[41];
+#ifdef __clang__
+/* clang doesn't like RIPEMD160 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ new_digest = RIPEMD160_File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
+ if (!new_digest) {
+ LABEL;
+ error = errno;
+ RECORD_FAILURE(18, error);
+ printf("%sRIPEMD160: %s: %s\n", tab,
+ p->fts_accpath, strerror(error));
+ tab = "\t";
+ } else if (strcmp(new_digest, s->rmd160digest)) {
+ LABEL;
+ printf("%sRIPEMD160 expected %s found %s\n",
+ tab, s->rmd160digest, new_digest);
+ tab = "\t";
+ }
+ }
+#endif /* ENABLE_RMD160 */
+#ifdef ENABLE_SHA256
+ if (s->flags & F_SHA256) {
+ char *new_digest, buf[kSHA256NullTerminatedBuffLen];
+
+ new_digest = SHA256_File(p->fts_accpath, buf);
+ if (!new_digest) {
+ LABEL;
+ error = errno;
+ RECORD_FAILURE(19, error);
+ printf("%sSHA-256: %s: %s\n", tab, p->fts_accpath,
+ strerror(error));
+ tab = "\t";
+ } else if (strcmp(new_digest, s->sha256digest)) {
+ LABEL;
+ printf("%sSHA-256 expected %s found %s\n",
+ tab, s->sha256digest, new_digest);
+ tab = "\t";
+ }
+ }
+#endif /* ENABLE_SHA256 */
+
+ if (s->flags & F_SLINK &&
+ strcmp(cp = rlink(p->fts_accpath), s->slink)) {
+ LABEL;
+ (void)printf("%slink_ref expected %s found %s\n",
+ tab, s->slink, cp);
+ }
+ if ((s->flags & F_BTIME) &&
+ ((s->st_birthtimespec.tv_sec != p->fts_statp->st_birthtimespec.tv_sec) ||
+ (s->st_birthtimespec.tv_nsec != p->fts_statp->st_birthtimespec.tv_nsec))) {
+ if (!mflag) {
+ LABEL;
+ (void)printf("%sbirth time expected %.24s.%09ld ",
+ tab, ctime(&s->st_birthtimespec.tv_sec), s->st_birthtimespec.tv_nsec);
+ (void)printf("found %.24s.%09ld\n",
+ ctime(&p->fts_statp->st_birthtimespec.tv_sec), p->fts_statp->st_birthtimespec.tv_nsec);
+ tab = "\t";
+ }
+ if (!insert_birth && mflag) {
+ uint64_t s_create_time = timespec_to_apfs_timestamp(&s->st_birthtimespec);
+ char *birth_string = "BIRTH";
+ set_key_value_pair(birth_string, &s_create_time, true);
+ insert_birth = 1;
+ }
+ }
+ if ((s->flags & F_ATIME) &&
+ ((s->st_atimespec.tv_sec != p->fts_statp->st_atimespec.tv_sec) ||
+ (s->st_atimespec.tv_nsec != p->fts_statp->st_atimespec.tv_nsec))) {
+ if (!mflag) {
+ LABEL;
+ (void)printf("%saccess time expected %.24s.%09ld ",
+ tab, ctime(&s->st_atimespec.tv_sec), s->st_atimespec.tv_nsec);
+ (void)printf("found %.24s.%09ld\n",
+ ctime(&p->fts_statp->st_atimespec.tv_sec), p->fts_statp->st_atimespec.tv_nsec);
+ tab = "\t";
+ }
+ if (!insert_access && mflag) {
+ uint64_t s_access_time = timespec_to_apfs_timestamp(&s->st_atimespec);
+ char *access_string = "ACCESS";
+ set_key_value_pair(access_string, &s_access_time, true);
+ insert_access = 1;
+
+ }
+ }
+ if ((s->flags & F_CTIME) &&
+ ((s->st_ctimespec.tv_sec != p->fts_statp->st_ctimespec.tv_sec) ||
+ (s->st_ctimespec.tv_nsec != p->fts_statp->st_ctimespec.tv_nsec))) {
+ if (!mflag) {
+ LABEL;
+ (void)printf("%smetadata modification time expected %.24s.%09ld ",
+ tab, ctime(&s->st_ctimespec.tv_sec), s->st_ctimespec.tv_nsec);
+ (void)printf("found %.24s.%09ld\n",
+ ctime(&p->fts_statp->st_ctimespec.tv_sec), p->fts_statp->st_ctimespec.tv_nsec);
+ tab = "\t";
+ }
+ if (!insert_change && mflag) {
+ uint64_t s_mod_time = timespec_to_apfs_timestamp(&s->st_ctimespec);
+ char *change_string = "CHANGE";
+ set_key_value_pair(change_string, &s_mod_time, true);
+ insert_change = 1;
+ }
+ }
+ if (s->flags & F_PTIME) {
+ int supported;
+ struct timespec ptimespec = ptime(p->fts_accpath, &supported);
+ if (!supported) {
+ LABEL;
+ (void)printf("%stime added to parent folder expected %.24s.%09ld found that it is not supported\n",
+ tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
+ tab = "\t";
+ } else if (supported && ((s->st_ptimespec.tv_sec != ptimespec.tv_sec) ||
+ (s->st_ptimespec.tv_nsec != ptimespec.tv_nsec))) {
+ if (!mflag) {
+ LABEL;
+ (void)printf("%stime added to parent folder expected %.24s.%09ld ",
+ tab, ctime(&s->st_ptimespec.tv_sec), s->st_ptimespec.tv_nsec);
+ (void)printf("found %.24s.%09ld\n",
+ ctime(&ptimespec.tv_sec), ptimespec.tv_nsec);
+ tab = "\t";
+ } else if (!insert_parent && mflag) {
+ uint64_t s_added_time = timespec_to_apfs_timestamp(&s->st_ptimespec);
+ char *added_string = "DATEADDED";
+ set_key_value_pair(added_string, &s_added_time, true);
+ insert_parent = 1;
+ }
+ }
+ }
+ if (s->flags & F_XATTRS) {
+ char buf[kSHA256NullTerminatedBuffLen];
+ xattr_info *ai;
+ ai = SHA256_Path_XATTRs(p->fts_accpath, buf);
+ if (!mflag) {
+ if (ai && !ai->digest) {
+ LABEL;
+ printf("%sxattrsdigest missing, expected: %s\n", tab, s->xattrsdigest);
+ tab = "\t";
+ } else if (ai && strcmp(ai->digest, s->xattrsdigest)) {
+ LABEL;
+ printf("%sxattrsdigest expected %s found %s\n",
+ tab, s->xattrsdigest, ai->digest);
+ tab = "\t";
+ }
+ }
+ if (mflag) {
+ if (ai && ai->xdstream_priv_id != s->xdstream_priv_id) {
+ set_key_value_pair((void*)&ai->xdstream_priv_id, &s->xdstream_priv_id, false);
+ }
+ }
+ free(ai);
+ }
+ if ((s->flags & F_INODE) &&
+ (p->fts_statp->st_ino != s->st_ino)) {
+ if (!mflag) {
+ LABEL;
+ (void)printf("%sinode expected %llu found %llu\n",
+ tab, s->st_ino, p->fts_statp->st_ino);
+ tab = "\t";
+ }
+ if (mflag) {
+ set_key_value_pair((void*)&p->fts_statp->st_ino, &s->st_ino, false);
+ }
+ }
+ if (s->flags & F_ACL) {
+ char *new_digest, buf[kSHA256NullTerminatedBuffLen];
+ new_digest = SHA256_Path_ACL(p->fts_accpath, buf);
+ if (!new_digest) {
+ LABEL;
+ printf("%sacldigest missing, expected: %s\n", tab, s->acldigest);
+ tab = "\t";
+ } else if (strcmp(new_digest, s->acldigest)) {
+ LABEL;
+ printf("%sacldigest expected %s found %s\n",
+ tab, s->acldigest, new_digest);
+ tab = "\t";
+ }
+ }
+ if (s->flags & F_SIBLINGID) {
+ uint64_t new_sibling_id = get_sibling_id(p->fts_accpath);
+ new_sibling_id = (new_sibling_id != p->fts_statp->st_ino) ? new_sibling_id : 0;
+ if (new_sibling_id != s->sibling_id) {
+ if (!mflag) {
+ LABEL;
+ (void)printf("%ssibling id expected %llu found %llu\n",
+ tab, s->sibling_id, new_sibling_id);
+ tab = "\t";
+ }
+ if (mflag) {
+ set_key_value_pair((void*)&new_sibling_id, &s->sibling_id, false);
+ }
+ }
+ }
+
+ return (label);
+}
+
+const char *
+inotype(u_int type)
+{
+ switch(type & S_IFMT) {
+ case S_IFBLK:
+ return ("block");
+ case S_IFCHR:
+ return ("char");
+ case S_IFDIR:
+ return ("dir");
+ case S_IFIFO:
+ return ("fifo");
+ case S_IFREG:
+ return ("file");
+ case S_IFLNK:
+ return ("link");
+ case S_IFSOCK:
+ return ("socket");
+ default:
+ return ("unknown");
+ }
+ /* NOTREACHED */
+}
+
+const char *
+ftype(u_int type)
+{
+ switch(type) {
+ case F_BLOCK:
+ return ("block");
+ case F_CHAR:
+ return ("char");
+ case F_DIR:
+ return ("dir");
+ case F_FIFO:
+ return ("fifo");
+ case F_FILE:
+ return ("file");
+ case F_LINK:
+ return ("link");
+ case F_SOCK:
+ return ("socket");
+ default:
+ return ("unknown");
+ }
+ /* NOTREACHED */
+}
+
+char *
+rlink(char *name)
+{
+ int error = 0;
+ static char lbuf[MAXPATHLEN];
+ ssize_t len;
+
+ if ((len = readlink(name, lbuf, sizeof(lbuf) - 1)) == -1) {
+ error = errno;
+ RECORD_FAILURE(20, error);
+ errc(1, error, "line %d: %s", lineno, name);
+ }
+ lbuf[len] = '\0';
+ return (lbuf);
+}
diff --git a/file_cmds/mtree/create.c b/file_cmds/mtree/create.c
new file mode 100644
index 0000000..9300eaa
--- /dev/null
+++ b/file_cmds/mtree/create.c
@@ -0,0 +1,611 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/create.c,v 1.37 2005/03/29 11:44:17 tobez Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <grp.h>
+#ifndef __APPLE__
+#ifdef ENABLE_MD5
+#include <md5.h>
+#endif
+#ifdef ENABLE_SHA1
+#include <sha.h>
+#endif
+#ifdef ENABLE_RMD160
+#include <ripemd.h>
+#endif
+#ifdef ENABLE_SHA256
+#include <sha256.h>
+#endif
+#endif /* !__APPLE__ */
+#include <pwd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <vis.h>
+#include "metrics.h"
+#include "mtree.h"
+#include "extern.h"
+
+#ifdef __APPLE__
+#include "commoncrypto.h"
+#endif /* __APPLE__ */
+
+#define INDENTNAMELEN 15
+#define MAXLINELEN 80
+
+static gid_t gid;
+static uid_t uid;
+static mode_t mode;
+static u_long flags = 0xffffffff;
+static char *xattrs = kNone;
+static char *acl = kNone;
+static u_quad_t xdstream_id;
+
+static int dsort(const FTSENT **, const FTSENT **);
+static void output(int, int *, const char *, ...) __printflike(3, 4);
+static int statd(FTS *, FTSENT *, uid_t *, gid_t *, mode_t *, u_long *, char **, char **, u_quad_t *);
+static void statf(int, FTSENT *);
+
+void
+cwalk(void)
+{
+ int error = 0;
+ FTS *t;
+ FTSENT *p;
+ time_t cl;
+ char *argv[2], host[MAXHOSTNAMELEN];
+ char dot[] = ".";
+ int indent = 0;
+ char *path;
+
+ if (!nflag) {
+ (void)time(&cl);
+ (void)gethostname(host, sizeof(host));
+ (void)printf(
+ "#\t user: %s\n#\tmachine: %s\n",
+ getlogin(), host);
+ (void)printf(
+ "#\t tree: %s\n#\t date: %s",
+ fullpath, ctime(&cl));
+ }
+
+ argv[0] = dot;
+ argv[1] = NULL;
+ if ((t = fts_open(argv, ftsoptions, dsort)) == NULL) {
+ error = errno;
+ RECORD_FAILURE(76, error);
+ errc(1, error, "fts_open()");
+ }
+ while ((p = fts_read(t))) {
+ if (iflag)
+ indent = p->fts_level * 4;
+ if (check_excludes(p->fts_name, p->fts_path)) {
+ fts_set(t, p, FTS_SKIP);
+ continue;
+ }
+ switch(p->fts_info) {
+ case FTS_D:
+ if (!dflag)
+ (void)printf("\n");
+ if (!nflag) {
+ path = escape_path(p->fts_path);
+ (void)printf("# %s\n", path);
+ free(path);
+ }
+ statd(t, p, &uid, &gid, &mode, &flags, &xattrs, &acl, &xdstream_id);
+ statf(indent, p);
+ break;
+ case FTS_DP:
+ if (!nflag && (p->fts_level > 0)) {
+ path = escape_path(p->fts_path);
+ (void)printf("%*s# %s\n", indent, "", path);
+ free(path);
+ }
+ (void)printf("%*s..\n", indent, "");
+ if (!dflag)
+ (void)printf("\n");
+ break;
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ break;
+ default:
+ if (!dflag)
+ statf(indent, p);
+ break;
+
+ }
+ }
+ (void)fts_close(t);
+ if (sflag && keys & F_CKSUM) {
+ RECORD_FAILURE(77, WARN_CHECKSUM);
+ warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
+ }
+}
+
+static void
+statf(int indent, FTSENT *p)
+{
+ int error = 0;
+ struct group *gr;
+ struct passwd *pw;
+ uint32_t val;
+ off_t len;
+ int fd, offset;
+ char *fflags;
+ char *escaped_name;
+
+ escaped_name = calloc(1, p->fts_namelen * 4 + 1);
+ if (escaped_name == NULL) {
+ RECORD_FAILURE(78, ENOMEM);
+ errx(1, "statf(): calloc() failed");
+ }
+ strvis(escaped_name, p->fts_name, VIS_WHITE | VIS_OCTAL | VIS_GLOB);
+
+ if (iflag || S_ISDIR(p->fts_statp->st_mode))
+ offset = printf("%*s%s", indent, "", escaped_name);
+ else
+ offset = printf("%*s %s", indent, "", escaped_name);
+
+ free(escaped_name);
+
+ if (offset > (INDENTNAMELEN + indent))
+ offset = MAXLINELEN;
+ else
+ offset += printf("%*s", (INDENTNAMELEN + indent) - offset, "");
+
+ if (!S_ISREG(p->fts_statp->st_mode) && !dflag)
+ output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode));
+ if (p->fts_statp->st_uid != uid) {
+ if (keys & F_UNAME) {
+ pw = getpwuid(p->fts_statp->st_uid);
+ if (pw != NULL) {
+ output(indent, &offset, "uname=%s", pw->pw_name);
+ } else if (wflag) {
+ RECORD_FAILURE(27448, WARN_UNAME);
+ warnx("Could not get uname for uid=%u",
+ p->fts_statp->st_uid);
+ } else {
+ RECORD_FAILURE(79, EINVAL);
+ errx(1,
+ "Could not get uname for uid=%u",
+ p->fts_statp->st_uid);
+ }
+ }
+ if (keys & F_UID)
+ output(indent, &offset, "uid=%u", p->fts_statp->st_uid);
+ }
+ if (p->fts_statp->st_gid != gid) {
+ if (keys & F_GNAME) {
+ gr = getgrgid(p->fts_statp->st_gid);
+ if (gr != NULL) {
+ output(indent, &offset, "gname=%s", gr->gr_name);
+ } else if (wflag) {
+ RECORD_FAILURE(27449, WARN_UNAME);
+ warnx("Could not get gname for gid=%u",
+ p->fts_statp->st_gid);
+ } else {
+ RECORD_FAILURE(80, EINVAL);
+ errx(1,
+ "Could not get gname for gid=%u",
+ p->fts_statp->st_gid);
+ }
+ }
+ if (keys & F_GID)
+ output(indent, &offset, "gid=%u", p->fts_statp->st_gid);
+ }
+ if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
+ output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS);
+ if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
+ output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink);
+ if (keys & F_SIZE)
+ output(indent, &offset, "size=%jd",
+ (intmax_t)p->fts_statp->st_size);
+ if (keys & F_TIME) {
+ if (tflag && !insert_mod) {
+ output(indent, &offset, "time=%ld.%09ld",
+ (long)ts.tv_sec, ts.tv_nsec);
+ insert_mod = 1;
+ }
+ if (!tflag) {
+ output(indent, &offset, "time=%ld.%09ld",
+ (long)p->fts_statp->st_mtimespec.tv_sec,
+ p->fts_statp->st_mtimespec.tv_nsec);
+ }
+ }
+ if (keys & F_CKSUM && S_ISREG(p->fts_statp->st_mode)) {
+ if ((fd = open(p->fts_accpath, O_RDONLY, 0)) < 0 ||
+ crc(fd, &val, &len)) {
+ error = errno;
+ RECORD_FAILURE(27450, error);
+ errc(1, error, "%s", p->fts_accpath);
+ }
+ (void)close(fd);
+ output(indent, &offset, "cksum=%lu", (unsigned long)val);
+ }
+#ifdef ENABLE_MD5
+ if (keys & F_MD5 && S_ISREG(p->fts_statp->st_mode)) {
+ char *digest, buf[33];
+#ifdef __clang__
+/* clang doesn't like MD5 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ digest = MD5File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
+ if (!digest) {
+ error = errno;
+ RECORD_FAILURE(81, error);
+ errc(1, error, "%s", p->fts_accpath);
+ }
+ output(indent, &offset, "md5digest=%s", digest);
+ }
+#endif /* ENABLE_MD5 */
+#ifdef ENABLE_SHA1
+ if (keys & F_SHA1 && S_ISREG(p->fts_statp->st_mode)) {
+ char *digest, buf[41];
+#ifdef __clang__
+/* clang doesn't like SHA1 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ digest = SHA1_File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
+ if (!digest) {
+ error = errno;
+ RECORD_FAILURE(82, error);
+ errc(1, error, "%s", p->fts_accpath);
+ }
+ output(indent, &offset, "sha1digest=%s", digest);
+ }
+#endif /* ENABLE_SHA1 */
+#ifdef ENABLE_RMD160
+ if (keys & F_RMD160 && S_ISREG(p->fts_statp->st_mode)) {
+ char *digest, buf[41];
+#ifdef __clang__
+/* clang doesn't like RIPEMD160 due to security concerns, but it's used for file data/metadata integrity.. */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ digest = RIPEMD160_File(p->fts_accpath, buf);
+#pragma clang diagnostic pop
+#endif
+ if (!digest) {
+ error = errno;
+ RECORD_FAILURE(83, error);
+ errc(1, error, "%s", p->fts_accpath);
+ }
+ output(indent, &offset, "ripemd160digest=%s", digest);
+ }
+#endif /* ENABLE_RMD160 */
+#ifdef ENABLE_SHA256
+ if (keys & F_SHA256 && S_ISREG(p->fts_statp->st_mode)) {
+ char *digest, buf[kSHA256NullTerminatedBuffLen];
+
+ digest = SHA256_File(p->fts_accpath, buf);
+ if (!digest) {
+ error = errno;
+ RECORD_FAILURE(84, error);
+ errc(1, error, "%s", p->fts_accpath);
+ }
+ output(indent, &offset, "sha256digest=%s", digest);
+ }
+#endif /* ENABLE_SHA256 */
+ if (keys & F_SLINK &&
+ (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+ char visbuf[MAXPATHLEN * 4];
+ char *s = rlink(p->fts_accpath);
+ strvis(visbuf, s, VIS_WHITE | VIS_OCTAL);
+ output(indent, &offset, "link=%s", visbuf);
+ }
+ if (keys & F_FLAGS && p->fts_statp->st_flags != flags) {
+ fflags = flags_to_string(p->fts_statp->st_flags);
+ output(indent, &offset, "flags=%s", fflags);
+ free(fflags);
+ }
+ if (keys & F_BTIME) {
+ if (tflag && !insert_birth) {
+ output(indent, &offset, "btime=%ld.%09ld",
+ ts.tv_sec, ts.tv_nsec);
+ insert_birth = 1;
+ }
+ if (!tflag) {
+ output(indent, &offset, "btime=%ld.%09ld",
+ p->fts_statp->st_birthtimespec.tv_sec,
+ p->fts_statp->st_birthtimespec.tv_nsec);
+ }
+ }
+ // only check access time on regular files, as traversing a folder will update its access time
+ if (keys & F_ATIME && S_ISREG(p->fts_statp->st_mode)) {
+ if (tflag && !insert_access) {
+ output(indent, &offset, "atime=%ld.%09ld",
+ ts.tv_sec, ts.tv_nsec);
+ insert_access = 1;
+ }
+ if (!tflag) {
+ output(indent, &offset, "atime=%ld.%09ld",
+ p->fts_statp->st_atimespec.tv_sec,
+ p->fts_statp->st_atimespec.tv_nsec);
+ }
+ }
+ if (keys & F_CTIME) {
+ if (tflag && !insert_change) {
+ output(indent, &offset, "ctime=%ld.%09ld",
+ ts.tv_sec, ts.tv_nsec);
+ insert_change = 1;
+ }
+ if (!tflag) {
+ output(indent, &offset, "ctime=%ld.%09ld",
+ p->fts_statp->st_ctimespec.tv_sec,
+ p->fts_statp->st_ctimespec.tv_nsec);
+ }
+ }
+ // date added to parent folder is only supported for files and directories
+ if (keys & F_PTIME && (S_ISREG(p->fts_statp->st_mode) ||
+ S_ISDIR(p->fts_statp->st_mode))) {
+ int supported;
+ struct timespec ptimespec = ptime(p->fts_accpath, &supported);
+ if (tflag && !insert_parent) {
+ output(indent, &offset, "ptime=%ld.%09ld",
+ ts.tv_sec, ts.tv_nsec);
+ insert_parent = 1;
+ }
+ if (!tflag && supported) {
+ output(indent, &offset, "ptime=%ld.%09ld",
+ ptimespec.tv_sec,
+ ptimespec.tv_nsec);
+ }
+ }
+ if (keys & F_XATTRS) {
+ char buf[kSHA256NullTerminatedBuffLen];
+ xattr_info *ai;
+
+ ai = SHA256_Path_XATTRs(p->fts_accpath, buf);
+ if (ai && ai->digest) {
+ if ((strcmp(ai->digest, xattrs) != 0) || (ai->xdstream_priv_id != xdstream_id)) {
+ output(indent, &offset, "xattrsdigest=%s.%llu", ai->digest, ai->xdstream_priv_id);
+ }
+ free(ai);
+ ai = NULL;
+ }
+ }
+ if (keys & F_INODE) {
+ output(indent, &offset, "inode=%llu", p->fts_statp->st_ino);
+ }
+ if (keys & F_ACL) {
+ char *digest, buf[kSHA256NullTerminatedBuffLen];
+
+ digest = SHA256_Path_ACL(p->fts_accpath, buf);
+ if (digest && (strcmp(digest, acl) != 0)) {
+ output(indent, &offset, "acldigest=%s", digest);
+ }
+ }
+ if (keys & F_SIBLINGID) {
+ uint64_t sibling_id = get_sibling_id(p->fts_accpath);
+ sibling_id = (sibling_id != p->fts_statp->st_ino) ? sibling_id : 0;
+ output(indent, &offset, "siblingid=%llu", sibling_id);
+ }
+
+ (void)putchar('\n');
+}
+
+#define MAXGID 5000
+#define MAXUID 5000
+#define MAXMODE MBITS + 1
+#define MAXFLAGS 256
+#define MAXS 16
+
+static int
+statd(FTS *t, FTSENT *parent, uid_t *puid, gid_t *pgid, mode_t *pmode, u_long *pflags, char **pxattrs, char **pacl, u_quad_t *xdstream_id)
+{
+ int error = 0;
+ FTSENT *p;
+ gid_t sgid;
+ uid_t suid;
+ mode_t smode;
+ u_long sflags;
+ struct group *gr;
+ struct passwd *pw;
+ gid_t savegid = *pgid;
+ uid_t saveuid = *puid;
+ mode_t savemode = *pmode;
+ u_long saveflags = *pflags;
+ char *savexattrs = *pxattrs;
+ char *saveacl = *pacl;
+ u_quad_t savexdstream_id = *xdstream_id;
+ u_short maxgid, maxuid, maxmode, maxflags;
+ u_short g[MAXGID], u[MAXUID], m[MAXMODE], f[MAXFLAGS];
+ char *fflags;
+ static int first = 1;
+
+ if ((p = fts_children(t, 0)) == NULL) {
+ error = errno;
+ if (error) {
+ RECORD_FAILURE(85, error);
+ errc(1, error, "%s", RP(parent));
+ }
+ return (1);
+ }
+
+ bzero(g, sizeof(g));
+ bzero(u, sizeof(u));
+ bzero(m, sizeof(m));
+ bzero(f, sizeof(f));
+
+ maxuid = maxgid = maxmode = maxflags = 0;
+ for (; p; p = p->fts_link) {
+ if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) {
+ smode = p->fts_statp->st_mode & MBITS;
+ if (smode < MAXMODE && ++m[smode] > maxmode) {
+ savemode = smode;
+ maxmode = m[smode];
+ }
+ sgid = p->fts_statp->st_gid;
+ if (sgid < MAXGID && ++g[sgid] > maxgid) {
+ savegid = sgid;
+ maxgid = g[sgid];
+ }
+ suid = p->fts_statp->st_uid;
+ if (suid < MAXUID && ++u[suid] > maxuid) {
+ saveuid = suid;
+ maxuid = u[suid];
+ }
+
+ /*
+ * XXX
+ * note that we don't count the most common xattr/acl digest
+ * so set will always the default value (none)
+ */
+
+ /*
+ * XXX
+ * note that the below will break when file flags
+ * are extended beyond the first 4 bytes of each
+ * half word of the flags
+ */
+#define FLAGS2IDX(f) ((f & 0xf) | ((f >> 12) & 0xf0))
+ sflags = p->fts_statp->st_flags;
+ if (FLAGS2IDX(sflags) < MAXFLAGS &&
+ ++f[FLAGS2IDX(sflags)] > maxflags) {
+ saveflags = sflags;
+ maxflags = f[FLAGS2IDX(sflags)];
+ }
+ }
+ }
+ /*
+ * If the /set record is the same as the last one we do not need to output
+ * a new one. So first we check to see if anything changed. Note that we
+ * always output a /set record for the first directory.
+ */
+ if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) ||
+ (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) ||
+ ((keys & F_MODE) && (*pmode != savemode)) ||
+ ((keys & F_FLAGS) && (*pflags != saveflags)) ||
+ (first)) {
+ first = 0;
+ if (dflag)
+ (void)printf("/set type=dir");
+ else
+ (void)printf("/set type=file");
+ if (keys & F_UNAME) {
+ pw = getpwuid(saveuid);
+ if (pw != NULL) {
+ (void)printf(" uname=%s", pw->pw_name);
+ } else if (wflag) {
+ RECORD_FAILURE(27451, WARN_UNAME);
+ warnx( "Could not get uname for uid=%u", saveuid);
+ } else {
+ RECORD_FAILURE(86, EINVAL);
+ errx(1, "Could not get uname for uid=%u", saveuid);
+ }
+ }
+ if (keys & F_UID)
+ (void)printf(" uid=%lu", (u_long)saveuid);
+ if (keys & F_GNAME) {
+ gr = getgrgid(savegid);
+ if (gr != NULL) {
+ (void)printf(" gname=%s", gr->gr_name);
+ } else if (wflag) {
+ RECORD_FAILURE(27452, WARN_UNAME);
+ warnx("Could not get gname for gid=%u", savegid);
+ } else {
+ RECORD_FAILURE(87, EINVAL);
+ errx(1, "Could not get gname for gid=%u", savegid);
+ }
+ }
+ if (keys & F_GID)
+ (void)printf(" gid=%lu", (u_long)savegid);
+ if (keys & F_MODE)
+ (void)printf(" mode=%#o", savemode);
+ if (keys & F_NLINK)
+ (void)printf(" nlink=1");
+ if (keys & F_FLAGS) {
+ fflags = flags_to_string(saveflags);
+ (void)printf(" flags=%s", fflags);
+ free(fflags);
+ }
+ if (keys & F_XATTRS)
+ (void)printf(" xattrsdigest=%s.%llu", savexattrs, savexdstream_id);
+ if (keys & F_ACL)
+ (void)printf(" acldigest=%s", saveacl);
+ (void)printf("\n");
+ *puid = saveuid;
+ *pgid = savegid;
+ *pmode = savemode;
+ *pflags = saveflags;
+ *pxattrs = savexattrs;
+ *pacl = saveacl;
+ *xdstream_id = savexdstream_id;
+ }
+ return (0);
+}
+
+static int
+dsort(const FTSENT **a, const FTSENT **b)
+{
+ if (S_ISDIR((*a)->fts_statp->st_mode)) {
+ if (!S_ISDIR((*b)->fts_statp->st_mode))
+ return (1);
+ } else if (S_ISDIR((*b)->fts_statp->st_mode))
+ return (-1);
+ return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
+
+#include <stdarg.h>
+
+void
+output(int indent, int *offset, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[1024];
+ va_start(ap, fmt);
+ (void)vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ if (*offset + strlen(buf) > MAXLINELEN - 3) {
+ (void)printf(" \\\n%*s", INDENTNAMELEN + indent, "");
+ *offset = INDENTNAMELEN + indent;
+ }
+ *offset += printf(" %s", buf) + 1;
+}
diff --git a/file_cmds/mtree/excludes.c b/file_cmds/mtree/excludes.c
new file mode 100644
index 0000000..cb432bf
--- /dev/null
+++ b/file_cmds/mtree/excludes.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2000 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/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/excludes.c,v 1.8 2003/10/21 08:27:05 phk Exp $");
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include "metrics.h"
+#include "extern.h"
+
+/*
+ * We're assuming that there won't be a whole lot of excludes,
+ * so it's OK to use a stupid algorithm.
+ */
+struct exclude {
+ LIST_ENTRY(exclude) link;
+ const char *glob;
+ int pathname;
+};
+static LIST_HEAD(, exclude) excludes;
+
+void
+init_excludes(void)
+{
+ LIST_INIT(&excludes);
+}
+
+void
+read_excludes_file(const char *name)
+{
+ FILE *fp;
+ char *line, *str;
+ struct exclude *e;
+ size_t len;
+
+ fp = fopen(name, "r");
+ if (fp == 0)
+ err(1, "%s", name);
+
+ while ((line = fgetln(fp, &len)) != 0) {
+ if (line[len - 1] == '\n')
+ len--;
+ if (len == 0)
+ continue;
+
+ str = malloc(len + 1);
+ e = malloc(sizeof *e);
+ if (str == 0 || e == 0) {
+ RECORD_FAILURE(59, ENOMEM);
+ errx(1, "memory allocation error");
+ }
+ e->glob = str;
+ memcpy(str, line, len);
+ str[len] = '\0';
+ if (strchr(str, '/'))
+ e->pathname = 1;
+ else
+ e->pathname = 0;
+ LIST_INSERT_HEAD(&excludes, e, link);
+ }
+ fclose(fp);
+}
+
+int
+check_excludes(const char *fname, const char *path)
+{
+ struct exclude *e;
+
+ /* fnmatch(3) has a funny return value convention... */
+#define MATCH(g, n) (fnmatch((g), (n), FNM_PATHNAME) == 0)
+
+ LIST_FOREACH(e, &excludes, link) {
+ if ((e->pathname && MATCH(e->glob, path))
+ || MATCH(e->glob, fname))
+ return 1;
+ }
+ return 0;
+}
diff --git a/file_cmds/mtree/extern.h b/file_cmds/mtree/extern.h
new file mode 100644
index 0000000..47533c2
--- /dev/null
+++ b/file_cmds/mtree/extern.h
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.sbin/mtree/extern.h,v 1.13 2004/01/11 19:38:48 phk Exp $
+ */
+
+#ifndef _EXTERN_H_
+#define _EXTERN_H_
+
+#include "mtree.h"
+
+extern uint32_t crc_total;
+
+#ifdef _FTS_H_
+int compare(char *, NODE *, FTSENT *);
+#endif
+int crc(int, uint32_t *, off_t *);
+void cwalk(void);
+char *flags_to_string(u_long);
+char *escape_path(char *string);
+struct timespec ptime(char *path, int *supported);
+
+const char *inotype(u_int);
+u_int parsekey(char *, int *);
+char *rlink(char *);
+NODE *mtree_readspec(FILE *fi);
+int mtree_verifyspec(FILE *fi);
+int mtree_specspec(FILE *fi, FILE *fj);
+
+int check_excludes(const char *, const char *);
+void init_excludes(void);
+void read_excludes_file(const char *);
+const char * ftype(u_int type);
+
+extern int ftsoptions;
+extern u_int keys;
+extern int lineno;
+extern int dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, wflag, mflag, tflag;
+extern int insert_mod, insert_birth, insert_access, insert_change, insert_parent;
+extern struct timespec ts;
+#ifdef MAXPATHLEN
+extern char fullpath[MAXPATHLEN];
+#endif
+
+#endif /* _EXTERN_H_ */
diff --git a/file_cmds/mtree/fix_failure_locations.py b/file_cmds/mtree/fix_failure_locations.py
new file mode 100755
index 0000000..a49906e
--- /dev/null
+++ b/file_cmds/mtree/fix_failure_locations.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python
+
+#
+# This script is used to automatically fix up the location numbers in
+# calls to RECORD_FAILURE(). When adding a new call to RECORD_FAILURE,
+# write it like:
+# RECORD_FAILURE(0, ...);
+# Don't put any white space between the open parenthesis, zero and comma.
+# Once you have added the new calls to RECORD_FAILURE, then run this script,
+# passing it the path to the directory, like this:
+# python3 mtree/fix_failure_locations.py mtree/
+#
+# This script will edit the files, changing the "0" to the next available
+# location number. It will also detect and complain if you have duplicate
+# location numbers.
+#
+# DO NOT reuse location numbers! It is best if locations are consistent across
+# all versions that have that RECORD_FAILURE call.
+#
+
+import sys
+import os
+import re
+from collections import defaultdict
+from datetime import datetime,timezone
+
+class LocationUpdater(object):
+ epoch = datetime(2020, 6, 17, 23, 22, 46, 562458, tzinfo=timezone.utc)
+ location_base = int((datetime.now(timezone.utc) - epoch).total_seconds() / 60)
+ # Match the number in "RECORD_FAILURE(<number>,"
+ fail_re = (re.compile('(?<=\\bRECORD_FAILURE\\()\\d+(?=,)'),re.compile('(?<=\\bRECORD_FAILURE_MSG\\()\\d+(?=,)'))
+
+ def __init__(self, path):
+ self.location = self.location_base
+ self.path = path
+ # Counters for how often each location number was found
+ self.counts = defaultdict(int)
+ self.locations_changed = 0
+
+ # Replace the "0" in "RECORD_FAILURE(0," with next location number, in *.c
+ def fixLocations(self):
+ def replace_loc(match):
+ location = int(match.group(0))
+ if location == 0:
+ # Replace location 0 with the next available location
+ self.location += 1
+ self.locations_changed += 1
+ location = self.location
+ # Count the number of times this location number was used
+ self.counts[location] += 1
+ # Return the (possibly updated) location number
+ return str(location)
+ rootpath = self.path
+ for dirpath, dirnames, filenames in os.walk(rootpath):
+ for filename in filenames:
+ if filename.endswith(".c") or filename.endswith(".cpp"):
+ path = os.path.join(dirpath, filename)
+ content = open(path, "r").read()
+ for fail_re in self.fail_re:
+ if fail_re.search(content):
+ locations_changed_before = self.locations_changed
+ content = fail_re.sub(replace_loc, content)
+ if self.locations_changed != locations_changed_before:
+ # We updated a location number, so write the changed file
+ print("Updating file {}".format(path))
+ open(path,"w").write(content)
+
+ def duplicates(self):
+ # Return the list of keys whose count is greater than 1
+ return [k for (k,v) in iter(self.counts.items()) if v > 1]
+
+updater = LocationUpdater(sys.argv[1])
+updater.fixLocations()
+dups = updater.duplicates()
+if len(dups):
+ print("WARNING! Duplicate location numbers: {}".format(dups))
+ sys.exit(1)
diff --git a/file_cmds/mtree/metrics.c b/file_cmds/mtree/metrics.c
new file mode 100644
index 0000000..01a9fe2
--- /dev/null
+++ b/file_cmds/mtree/metrics.c
@@ -0,0 +1,155 @@
+/*
+* Copyright (c) 2020 Apple Inc. All rights reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "metrics.h"
+
+#define MAX_WARNINGS_LOGGED 5
+#define MAX_ERRORS_LOGGED 5
+#define WARN_FIRST -1
+
+#ifndef ROUNDUP
+#define ROUNDUP(COUNT, MULTIPLE) ((((COUNT) + (MULTIPLE) - 1) / (MULTIPLE)) * (MULTIPLE))
+#endif
+
+typedef struct failure_info {
+ int location;
+ int code;
+} failure_info_t;
+
+typedef struct metrics {
+ FILE *file;
+ time_t start_time;
+ int warning_count;
+ failure_info_t warnings[MAX_WARNINGS_LOGGED];
+ int error_count;
+ failure_info_t errors[MAX_ERRORS_LOGGED];
+ int last_error_location;
+ char *path;
+ int result;
+} metrics_t;
+metrics_t metrics = {};
+
+void
+set_metrics_file(FILE *file)
+{
+ metrics.file = file;
+}
+
+void
+set_metric_start_time(time_t time)
+{
+ metrics.start_time = time;
+}
+
+void
+set_metric_path(char *path)
+{
+ metrics.path = strdup(path);
+}
+
+void
+mtree_record_failure(int location, int code)
+{
+ if (code <= WARN_FIRST) {
+ if (metrics.warning_count < MAX_WARNINGS_LOGGED) {
+ metrics.warning_count++;
+ } else {
+ // Shift up the warnings to make space for the latest one.
+ for (int index = 0; index < MAX_ERRORS_LOGGED - 1; index++) {
+ metrics.warnings[index] = metrics.warnings[index + 1];
+ }
+ }
+ metrics.warnings[metrics.warning_count - 1].location = location;
+ metrics.warnings[metrics.warning_count - 1].code = code;
+ } else {
+ int error_index = -1;
+ if (metrics.error_count <= MAX_ERRORS_LOGGED) {
+ if (metrics.error_count > 0) {
+ // Log all but the last error which occured in the location and
+ // code arrays. The last (location, error) is logged in
+ // (metrics.last_error_location, metrics.error)
+ error_index = metrics.error_count - 1;
+ }
+ metrics.error_count++;
+ } else {
+ // Shift up the errors to make space for the latest one.
+ for (int index = 0; index < MAX_ERRORS_LOGGED - 1; index++) {
+ metrics.errors[index] = metrics.errors[index + 1];
+ }
+ error_index = MAX_ERRORS_LOGGED - 1;
+ }
+ if (error_index >= 0) {
+ metrics.errors[error_index].location = metrics.last_error_location;
+ metrics.errors[error_index].code = metrics.result;
+ }
+ metrics.last_error_location = location;
+ metrics.result = code;
+ }
+}
+/*
+ * Note on format of metric string
+ * 1) dev points to the path
+ * 2) result is the overall result code from mtree
+ * 3) warnings and errors (upto 5 each) are printed in the format :
+ * w:(location1:code1),(location2:code2).... and
+ * e:(location1:code1),(location2:code2).... respectively.
+ * 4) fl is the last failure location of the run which is 0 if there is no failure
+ * 5) time is the total time taken for the run
+ */
+void
+print_metrics_to_file(void)
+{
+ if (metrics.file == NULL) {
+ return;
+ }
+
+ fprintf(metrics.file, "dev=%s result=%d ",
+ metrics.path ? metrics.path : "", metrics.result);
+ if (metrics.warning_count) {
+ fprintf(metrics.file, "w:");
+ for (int index = 0; index < metrics.warning_count; index++) {
+ fprintf(metrics.file, "(%d:%d)",
+ metrics.warnings[index].location, metrics.warnings[index].code);
+ }
+ fprintf(metrics.file, " ");
+ }
+ if (metrics.error_count > 1) {
+ fprintf(metrics.file, "e:");
+ for (int index = 0; index < metrics.error_count - 1; index++) {
+ fprintf(metrics.file, "(%d:%d)",
+ metrics.errors[index].location, metrics.errors[index].code);
+ }
+ fprintf(metrics.file, " ");
+ }
+ fprintf(metrics.file, "fl=%d time=%ld\n",
+ metrics.last_error_location, ROUNDUP((time(NULL) - metrics.start_time), 60) / 60);
+
+ fclose(metrics.file);
+ if (metrics.path) {
+ free(metrics.path);
+ metrics.path = NULL;
+ }
+}
diff --git a/file_cmds/mtree/metrics.h b/file_cmds/mtree/metrics.h
new file mode 100644
index 0000000..35dca43
--- /dev/null
+++ b/file_cmds/mtree/metrics.h
@@ -0,0 +1,48 @@
+/*
+* Copyright (c) 2020 Apple Inc. All rights reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+#ifndef _METRICS_H_
+#define _METRICS_H_
+
+#include <sys/time.h>
+#include <stdio.h>
+
+// mtree error logging
+enum mtree_result {
+ SUCCESS = 0,
+ WARN_TIME = -1,
+ WARN_USAGE = -2,
+ WARN_CHECKSUM = -3,
+ WARN_MISMATCH = -4,
+ WARN_UNAME = -5,
+ /* Could also be a POSIX errno value */
+};
+
+void set_metrics_file(FILE *file);
+void set_metric_start_time(time_t time);
+void set_metric_path(char *path);
+#define RECORD_FAILURE(location, error) mtree_record_failure(location, error)
+void mtree_record_failure(int location, int code);
+void print_metrics_to_file(void);
+
+#endif /* _METRICS_H_ */
diff --git a/file_cmds/mtree/misc.c b/file_cmds/mtree/misc.c
new file mode 100644
index 0000000..66e566e
--- /dev/null
+++ b/file_cmds/mtree/misc.c
@@ -0,0 +1,189 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
+#endif /*not lint */
+#endif
+#include <sys/cdefs.h>
+#include <errno.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/misc.c,v 1.16 2005/03/29 11:44:17 tobez Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <fts.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "metrics.h"
+#include "mtree.h"
+#include "extern.h"
+#import <sys/attr.h>
+#include <vis.h>
+
+typedef struct _key {
+ const char *name; /* key name */
+ u_int val; /* value */
+
+#define NEEDVALUE 0x01
+ u_int flags;
+} KEY;
+
+/* NB: the following table must be sorted lexically. */
+static KEY keylist[] = {
+ {"acldigest", F_ACL, NEEDVALUE},
+ {"atime", F_ATIME, NEEDVALUE},
+ {"btime", F_BTIME, NEEDVALUE},
+ {"cksum", F_CKSUM, NEEDVALUE},
+ {"ctime", F_CTIME, NEEDVALUE},
+ {"flags", F_FLAGS, NEEDVALUE},
+ {"gid", F_GID, NEEDVALUE},
+ {"gname", F_GNAME, NEEDVALUE},
+ {"ignore", F_IGN, 0},
+ {"inode", F_INODE, NEEDVALUE},
+ {"link", F_SLINK, NEEDVALUE},
+#ifdef ENABLE_MD5
+ {"md5digest", F_MD5, NEEDVALUE},
+#endif
+ {"mode", F_MODE, NEEDVALUE},
+ {"nlink", F_NLINK, NEEDVALUE},
+ {"nochange", F_NOCHANGE, 0},
+ {"ptime", F_PTIME, NEEDVALUE},
+#ifdef ENABLE_RMD160
+ {"ripemd160digest", F_RMD160, NEEDVALUE},
+#endif
+#ifdef ENABLE_SHA1
+ {"sha1digest", F_SHA1, NEEDVALUE},
+#endif
+#ifdef ENABLE_SHA256
+ {"sha256digest", F_SHA256, NEEDVALUE},
+#endif
+ {"siblingid", F_SIBLINGID, NEEDVALUE},
+ {"size", F_SIZE, NEEDVALUE},
+ {"time", F_TIME, NEEDVALUE},
+ {"type", F_TYPE, NEEDVALUE},
+ {"uid", F_UID, NEEDVALUE},
+ {"uname", F_UNAME, NEEDVALUE},
+ {"xattrsdigest", F_XATTRS, NEEDVALUE},
+};
+
+int keycompare(const void *, const void *);
+
+u_int
+parsekey(char *name, int *needvaluep)
+{
+ KEY *k, tmp;
+
+ tmp.name = name;
+ k = (KEY *)bsearch(&tmp, keylist, sizeof(keylist) / sizeof(KEY),
+ sizeof(KEY), keycompare);
+ if (k == NULL) {
+ RECORD_FAILURE(107, EINVAL);
+ errx(1, "line %d: unknown keyword %s", lineno, name);
+ }
+
+ if (needvaluep)
+ *needvaluep = k->flags & NEEDVALUE ? 1 : 0;
+ return (k->val);
+}
+
+int
+keycompare(const void *a, const void *b)
+{
+ return (strcmp(((const KEY *)a)->name, ((const KEY *)b)->name));
+}
+
+char *
+flags_to_string(u_long fflags)
+{
+ int error = 0;
+ char *string;
+
+ string = fflagstostr(fflags);
+ if (string != NULL && *string == '\0') {
+ free(string);
+ string = strdup("none");
+ }
+ if (string == NULL) {
+ error = errno;
+ RECORD_FAILURE(108, error);
+ errc(1, error, NULL);
+ }
+
+ return string;
+}
+
+// escape path and always return a new string so it can be freed
+char *
+escape_path(char *string)
+{
+ char *escapedPath = calloc(1, strlen(string) * 4 + 1);
+ if (escapedPath == NULL) {
+ RECORD_FAILURE(109, ENOMEM);
+ errx(1, "escape_path(): calloc() failed");
+ }
+ strvis(escapedPath, string, VIS_NL | VIS_CSTYLE | VIS_OCTAL);
+
+ return escapedPath;
+}
+
+struct ptimebuf {
+ uint32_t length;
+ attribute_set_t returned_attrs;
+ struct timespec st_ptimespec;
+} __attribute__((aligned(4), packed));
+
+// ptime is not supported on root filesystems or HFS filesystems older than the feature being introduced
+struct timespec
+ptime(char *path, int *supported) {
+
+ int error = 0;
+ int ret = 0;
+ struct ptimebuf buf;
+ struct attrlist list = {
+ .bitmapcount = ATTR_BIT_MAP_COUNT,
+ .commonattr = ATTR_CMN_RETURNED_ATTRS | ATTR_CMN_ADDEDTIME,
+ };
+ ret = getattrlist(path, &list, &buf, sizeof(buf), FSOPT_NOFOLLOW);
+ if (ret) {
+ error = errno;
+ RECORD_FAILURE(110, error);
+ errc(1, error, "ptime: getattrlist");
+ }
+
+ *supported = 0;
+ if (buf.returned_attrs.commonattr & ATTR_CMN_ADDEDTIME) {
+ *supported = 1;
+ }
+
+ return buf.st_ptimespec;
+
+}
diff --git a/file_cmds/mtree/mtree.8 b/file_cmds/mtree/mtree.8
new file mode 100644
index 0000000..1aa529a
--- /dev/null
+++ b/file_cmds/mtree/mtree.8
@@ -0,0 +1,393 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)mtree.8 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD: src/usr.sbin/mtree/mtree.8,v 1.53 2005/07/31 03:30:47 keramida Exp $
+.\"
+.Dd March 29, 2005
+.Dt MTREE 8
+.Os
+.Sh NAME
+.Nm mtree
+.Nd map a directory hierarchy
+.Sh SYNOPSIS
+.Nm mtree
+.Op Fl LPUcdeinqruxw
+.Bk -words
+.Op Fl f Ar spec
+.Ek
+.Bk -words
+.Op Fl f Ar spec
+.Ek
+.Bk -words
+.Op Fl K Ar keywords
+.Ek
+.Bk -words
+.Op Fl k Ar keywords
+.Ek
+.Bk -words
+.Op Fl p Ar path
+.Ek
+.Bk -words
+.Op Fl s Ar seed
+.Ek
+.Bk -words
+.Op Fl X Ar exclude-list
+.Ek
+.Sh DESCRIPTION
+The
+.Nm mtree
+utility compares the file hierarchy rooted in the current directory against a
+specification read from the standard input.
+Messages are written to the standard output for any files whose
+characteristics do not match the specifications, or which are
+missing from either the file hierarchy or the specification.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.\" ==========
+.It Fl c
+Print a specification for the file hierarchy to the standard output.
+.\" ==========
+.It Fl d
+Ignore everything except directory type files.
+.\" ==========
+.It Fl e
+Do not complain about files that are in the file hierarchy, but not in the
+specification.
+.\" ==========
+.It Fl f Ar file
+Read the specification from
+.Ar file ,
+instead of from the standard input.
+.Pp
+If this option is specified twice,
+the two specifications are compared with each other,
+rather than to the file hierarchy.
+The specifications be sorted like output generated using
+.Fl c .
+The output format in this case is somewhat remniscent of
+.Xr comm 1 ,
+having "in first spec only", "in second spec only", and "different"
+columns, prefixed by zero, one and two TAB characters respectively.
+Each entry in the "different" column occupies two lines,
+one from each specification.
+.\" ==========
+.It Fl i
+Indent the output 4 spaces each time a directory level is descended when
+create a specification with the
+.Fl c
+option.
+This does not affect either the /set statements or the comment before each
+directory.
+It does however affect the comment before the close of each directory.
+.\" ==========
+.It Fl K Ar keywords
+Add the specified (whitespace or comma separated)
+.Ar keywords
+to the current set of keywords.
+.\" ==========
+.It Fl k Ar keywords
+Use the ``type'' keyword plus the specified (whitespace or comma separated)
+.Ar keywords
+instead of the current set of keywords.
+.\" ==========
+.It Fl L
+Follow all symbolic links in the file hierarchy.
+.\" ==========
+.It Fl n
+Do not emit pathname comments when creating a specification.
+Normally
+a comment is emitted before each directory and before the close of that
+directory when using the
+.Fl c
+option.
+.\" ==========
+.It Fl P
+Do not follow symbolic links in the file hierarchy, instead consider
+the symbolic link itself in any comparisons.
+This is the default.
+.\" ==========
+.It Fl p Ar path
+Use the file hierarchy rooted in
+.Ar path ,
+instead of the current directory.
+.\" ==========
+.It Fl q
+Quiet mode.
+Do not complain when a
+.Dq missing
+directory cannot be created because it already exists.
+This occurs when the directory is a symbolic link.
+.\" ==========
+.It Fl r
+Remove any files in the file hierarchy that are not described in the
+specification.
+.\" ==========
+.It Fl s Ar seed
+Display a single checksum to the standard error output that represents all
+of the files for which the keyword
+.Cm cksum
+was specified.
+The checksum is seeded with the specified value.
+.\" ==========
+.It Fl U
+Modify the owner, group, permissions, and modification time of existing
+files to match the specification and create any missing directories or
+symbolic links.
+User, group and permissions must all be specified for missing directories
+to be created.
+Corrected mismatches are not considered errors.
+.\" ==========
+.It Fl u
+Same as
+.Fl U
+except a status of 2 is returned if the file hierarchy did not match
+the specification.
+.\" ==========
+.It Fl w
+Make some error conditions non-fatal warnings.
+.\" ==========
+.It Fl X Ar exclude-list
+The specified file contains
+.Xr fnmatch 3
+patterns matching files to be excluded from
+the specification, one to a line.
+If the pattern contains a
+.Ql \&/
+character, it will be matched against entire pathnames (relative to
+the starting directory); otherwise,
+it will be matched against basenames only.
+No comments are allowed in
+the
+.Ar exclude-list
+file.
+.\" ==========
+.It Fl x
+Do not descend below mount points in the file hierarchy.
+.El
+.Pp
+Specifications are mostly composed of ``keywords'', i.e., strings
+that specify values relating to files.
+No keywords have default values, and if a keyword has no value set, no
+checks based on it are performed.
+.Pp
+Currently supported keywords are as follows:
+.Bl -tag -width Cm
+.It Cm cksum
+The checksum of the file using the default algorithm specified by
+the
+.Xr cksum 1
+utility.
+.It Cm flags
+The file flags as a symbolic name.
+See
+.Xr chflags 1
+for information on these names.
+If no flags are to be set the string
+.Dq none
+may be used to override the current default.
+.It Cm ignore
+Ignore any file hierarchy below this file.
+.It Cm gid
+The file group as a numeric value.
+.It Cm gname
+The file group as a symbolic name.
+.It Cm md5digest
+The MD5 message digest of the file.
+.It Cm sha1digest
+The
+.Tn FIPS
+160-1
+.Pq Dq Tn SHA-1
+message digest of the file.
+.It Cm ripemd160digest
+The
+.Tn RIPEMD160
+message digest of the file.
+.It Cm mode
+The current file's permissions as a numeric (octal) or symbolic
+value.
+.It Cm nlink
+The number of hard links the file is expected to have.
+.It Cm nochange
+Make sure this file or directory exists but otherwise ignore all attributes.
+.It Cm uid
+The file owner as a numeric value.
+.It Cm uname
+The file owner as a symbolic name.
+.It Cm size
+The size, in bytes, of the file.
+.It Cm link
+The file the symbolic link is expected to reference.
+.It Cm time
+The last modification time of the file.
+.It Cm btime
+The creation (birth) time of the file.
+.It Cm atime
+The last access time of the file.
+.It Cm ctime
+The last metadata modification time of the file.
+.It Cm ptime
+The time the file was added to its parent folder.
+.It Cm inode
+The inode number of the file.
+.It Cm xattrsdigest
+Digest of the extended attributes of the file.
+.It Cm acldigest
+Digest of the access control list of the file.
+.It Cm type
+The type of the file; may be set to any one of the following:
+.Pp
+.Bl -tag -width Cm -compact
+.It Cm block
+block special device
+.It Cm char
+character special device
+.It Cm dir
+directory
+.It Cm fifo
+fifo
+.It Cm file
+regular file
+.It Cm link
+symbolic link
+.It Cm socket
+socket
+.El
+.El
+.Pp
+The default set of keywords are
+.Cm flags ,
+.Cm gid ,
+.Cm mode ,
+.Cm nlink ,
+.Cm size ,
+.Cm link ,
+.Cm time ,
+and
+.Cm uid .
+.Pp
+There are four types of lines in a specification.
+.Pp
+The first type of line sets a global value for a keyword, and consists of
+the string ``/set'' followed by whitespace, followed by sets of keyword/value
+pairs, separated by whitespace.
+Keyword/value pairs consist of a keyword, followed by an equals sign
+(``=''), followed by a value, without whitespace characters.
+Once a keyword has been set, its value remains unchanged until either
+reset or unset.
+.Pp
+The second type of line unsets keywords and consists of the string
+``/unset'', followed by whitespace, followed by one or more keywords,
+separated by whitespace.
+.Pp
+The third type of line is a file specification and consists of a file
+name, followed by whitespace, followed by zero or more whitespace
+separated keyword/value pairs.
+The file name may be preceded by whitespace characters.
+The file name may contain any of the standard file name matching
+characters (``['', ``]'', ``?'' or ``*''), in which case files
+in the hierarchy will be associated with the first pattern that
+they match.
+.Pp
+Each of the keyword/value pairs consist of a keyword, followed by an
+equals sign (``=''), followed by the keyword's value, without
+whitespace characters.
+These values override, without changing, the global value of the
+corresponding keyword.
+.Pp
+All paths are relative.
+Specifying a directory will cause subsequent files to be searched
+for in that directory hierarchy.
+Which brings us to the last type of line in a specification: a line
+containing only the string
+.Dq Pa ..\&
+causes the current directory
+path to ascend one level.
+.Pp
+Empty lines and lines whose first non-whitespace character is a hash
+mark (``#'') are ignored.
+.Pp
+The
+.Nm mtree
+utility exits with a status of 0 on success, 1 if any error occurred,
+and 2 if the file hierarchy did not match the specification.
+A status of 2 is converted to a status of 0 if the
+.Fl U
+option is used.
+.Sh FILES
+.Bl -tag -width /etc/mtree -compact
+.It Pa /etc/mtree
+system specification directory
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The
+.Fl d
+and
+.Fl u
+options can be used in combination to create directory hierarchies
+for distributions and other such things; the files in
+.Pa /etc/mtree
+were used to create almost all directories in this
+.Fx
+distribution.
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chgrp 1 ,
+.Xr chmod 1 ,
+.Xr cksum 1 ,
+.Xr md5 1 ,
+.Xr stat 2 ,
+.Xr fts 3 ,
+.Xr md5 3 ,
+.Xr chown 8
+.Sh HISTORY
+The
+.Nm mtree
+utility appeared in
+.Bx 4.3 Reno .
+The
+.Tn MD5
+digest capability was added in
+.Fx 2.1 ,
+in response to the widespread use of programs which can spoof
+.Xr cksum 1 .
+The
+.Tn SHA-1
+and
+.Tn RIPEMD160
+digests were added in
+.Fx 4.0 ,
+as new attacks have demonstrated weaknesses in
+.Tn MD5 .
+Support for file flags was added in
+.Fx 4.0 ,
+and mostly comes from
+.Nx .
diff --git a/file_cmds/mtree/mtree.c b/file_cmds/mtree/mtree.c
new file mode 100644
index 0000000..edf0cce
--- /dev/null
+++ b/file_cmds/mtree/mtree.c
@@ -0,0 +1,358 @@
+/*-
+ * Copyright (c) 1989, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/mtree.c,v 1.29 2004/06/04 19:29:28 ru Exp $");
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include "metrics.h"
+#include "mtree.h"
+#include "extern.h"
+
+#define SECONDS_IN_A_DAY (60 * 60 * 24)
+
+int ftsoptions = FTS_PHYSICAL;
+int cflag, dflag, eflag, iflag, nflag, qflag, rflag, sflag, uflag, Uflag, wflag, mflag, tflag;
+int insert_mod, insert_birth, insert_access, insert_change, insert_parent;
+struct timespec ts;
+u_int keys;
+char fullpath[MAXPATHLEN];
+CFMutableDictionaryRef dict;
+char *filepath;
+
+static void usage(void);
+static bool write_plist_to_file(void);
+
+static void
+do_cleanup(void) {
+
+ if (mflag) {
+ if (dict)
+ CFRelease(dict);
+ if (filepath)
+ free(filepath);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int error = 0;
+ int ch;
+ char *dir, *p;
+ int status;
+ FILE *spec1, *spec2;
+ char *timestamp = NULL;
+ char *timeformat = "%FT%T";
+ FILE *file = NULL;
+
+ dir = NULL;
+ keys = KEYDEFAULT;
+ init_excludes();
+ spec1 = stdin;
+ spec2 = NULL;
+ set_metric_start_time(time(NULL));
+
+ atexit(do_cleanup);
+ atexit(print_metrics_to_file);
+
+ while ((ch = getopt(argc, argv, "cdef:iK:k:LnPp:qrs:UuwxX:m:F:t:E:")) != -1)
+ switch((char)ch) {
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ break;
+ case 'f':
+ if (spec1 == stdin) {
+ spec1 = fopen(optarg, "r");
+ if (spec1 == NULL) {
+ error = errno;
+ RECORD_FAILURE(88, error);
+ errc(1, error, "%s", optarg);
+ }
+ } else if (spec2 == NULL) {
+ spec2 = fopen(optarg, "r");
+ if (spec2 == NULL) {
+ error = errno;
+ RECORD_FAILURE(89, error);
+ errc(1, error, "%s", optarg);
+ }
+ } else {
+ RECORD_FAILURE(90, WARN_USAGE);
+ usage();
+ }
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'K':
+ while ((p = strsep(&optarg, " \t,")) != NULL)
+ if (*p != '\0')
+ keys |= parsekey(p, NULL);
+ break;
+ case 'k':
+ keys = F_TYPE;
+ while ((p = strsep(&optarg, " \t,")) != NULL)
+ if (*p != '\0')
+ keys |= parsekey(p, NULL);
+ break;
+ case 'L':
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'P':
+ ftsoptions &= ~FTS_LOGICAL;
+ ftsoptions |= FTS_PHYSICAL;
+ break;
+ case 'p':
+ dir = optarg;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ crc_total = (uint32_t)~strtoul(optarg, &p, 0);
+ if (*p) {
+ RECORD_FAILURE(91, WARN_USAGE);
+ errx(1, "illegal seed value -- %s", optarg);
+ }
+ break;
+ case 'U':
+ Uflag = 1;
+ uflag = 1;
+ break;
+ case 'u':
+ uflag = 1;
+ break;
+ case 'w':
+ wflag = 1;
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case 'X':
+ read_excludes_file(optarg);
+ break;
+ case 'm':
+ mflag = 1;
+ filepath = strdup(optarg);
+ dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ insert_access = insert_mod = insert_birth = insert_change = 0;
+ break;
+ case 'F':
+ timeformat = optarg;
+ break;
+ case 't':
+ timestamp = optarg;
+ tflag = 1;
+ break;
+ case 'E':
+ if (!strcmp(optarg, "-")) {
+ file = stdout;
+ } else {
+ file = fopen(optarg, "w");
+ }
+ if (file == NULL) {
+ warnx("Could not open metrics log file %s", optarg);
+ } else {
+ set_metrics_file(file);
+ }
+ break;
+
+ case '?':
+ default:
+ RECORD_FAILURE(92, WARN_USAGE);
+ usage();
+ }
+ argc -= optind;
+// argv += optind;
+
+ if (argc) {
+ RECORD_FAILURE(93, WARN_USAGE);
+ usage();
+ }
+
+ if (timestamp) {
+ struct tm t = {};
+ char *r = strptime(timestamp, timeformat, &t);
+ if (r && r[0] == '\0') {
+ ts.tv_sec = mktime(&t);
+ if ((ts.tv_sec - time(NULL)) > 30 * SECONDS_IN_A_DAY) {
+ RECORD_FAILURE(94, WARN_TIME);
+ errx(1, "Time is more then 30 days in the future");
+ } else if (ts.tv_sec < 0) {
+ RECORD_FAILURE(95, WARN_TIME);
+ errx(1, "Time is too far in the past");
+ }
+ } else {
+ RECORD_FAILURE(96, WARN_TIME);
+ errx(1,"Cannot parse timestamp '%s' using format \"%s\"\n", timestamp, timeformat);
+ }
+ }
+
+ if (dir && chdir(dir)) {
+ error = errno;
+ RECORD_FAILURE(97, error);
+ errc(1, error, "%s", dir);
+ }
+
+ if ((cflag || sflag) && !getwd(fullpath)) {
+ RECORD_FAILURE(98, errno);
+ errx(1, "%s", fullpath);
+ }
+
+ if (dir) {
+ set_metric_path(dir);
+ }
+
+ if (cflag) {
+ cwalk();
+ exit(0);
+ }
+ if (spec2 != NULL) {
+ status = mtree_specspec(spec1, spec2);
+ if (Uflag & (status == MISMATCHEXIT)) {
+ status = 0;
+ } else {
+ RECORD_FAILURE(99, status);
+ }
+ } else {
+ status = mtree_verifyspec(spec1);
+ if (Uflag & (status == MISMATCHEXIT)) {
+ status = 0;
+ } else {
+ RECORD_FAILURE(100, status);
+ }
+ if (mflag && CFDictionaryGetCount(dict)) {
+ if (!write_plist_to_file()) {
+ RECORD_FAILURE(101, EIO);
+ errx(1, "could not write manifest to the file\n");
+ }
+ }
+ }
+ exit(status);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+"usage: mtree [-LPUcdeinqruxw] [-f spec] [-f spec] [-K key] [-k key] [-p path] [-s seed]\n"
+"\t[-X excludes]\n");
+ exit(1);
+}
+
+static bool
+write_plist_to_file(void)
+{
+ if (!dict || !filepath) {
+ RECORD_FAILURE(102, EINVAL);
+ return false;
+ }
+
+ CFIndex bytes_written = 0;
+ bool status = true;
+
+ CFStringRef file_path_str = CFStringCreateWithCString(kCFAllocatorDefault, (const char *)filepath, kCFStringEncodingUTF8);
+
+ // Create a URL specifying the file to hold the XML data.
+ CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
+ file_path_str, // file path name
+ kCFURLPOSIXPathStyle, // interpret as POSIX path
+ false); // is it a directory?
+
+ if (!fileURL) {
+ CFRelease(file_path_str);
+ RECORD_FAILURE(103, EINVAL);
+ return false;
+ }
+
+ CFWriteStreamRef output_stream = CFWriteStreamCreateWithFile(kCFAllocatorDefault, fileURL);
+
+ if (!output_stream) {
+ CFRelease(file_path_str);
+ CFRelease(fileURL);
+ RECORD_FAILURE(104, EIO);
+ return false;
+ }
+
+ if ((status = CFWriteStreamOpen(output_stream))) {
+ bytes_written = CFPropertyListWrite((CFPropertyListRef)dict, output_stream, kCFPropertyListXMLFormat_v1_0, 0, NULL);
+ CFWriteStreamClose(output_stream);
+ } else {
+ status = false;
+ RECORD_FAILURE(105, EIO);
+ goto out;
+ }
+
+ if (!bytes_written) {
+ status = false;
+ RECORD_FAILURE(106, EIO);
+ }
+
+out:
+ CFRelease(output_stream);
+ CFRelease(fileURL);
+ CFRelease(file_path_str);
+
+ return status;
+}
diff --git a/file_cmds/mtree/mtree.h b/file_cmds/mtree/mtree.h
new file mode 100644
index 0000000..16c927b
--- /dev/null
+++ b/file_cmds/mtree/mtree.h
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)mtree.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.sbin/mtree/mtree.h,v 1.7 2005/03/29 11:44:17 tobez Exp $
+ */
+
+#ifndef _MTREE_H_
+#define _MTREE_H_
+
+#include <sys/time.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define KEYDEFAULT \
+ (F_GID | F_MODE | F_NLINK | F_SIZE | F_SLINK | F_TIME | F_UID | F_FLAGS)
+
+#define MISMATCHEXIT 2
+
+typedef struct _node {
+ struct _node *parent, *child; /* up, down */
+ struct _node *prev, *next; /* left, right */
+ off_t st_size; /* size */
+ struct timespec st_mtimespec; /* last modification time */
+ u_long cksum; /* check sum */
+ char *md5digest; /* MD5 digest */
+ char *sha1digest; /* SHA-1 digest */
+ char *sha256digest; /* SHA-256 digest */
+ char *rmd160digest; /* RIPEMD160 digest */
+ char *slink; /* symbolic link reference */
+ uid_t st_uid; /* uid */
+ gid_t st_gid; /* gid */
+#define MBITS (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
+ mode_t st_mode; /* mode */
+ u_long st_flags; /* flags */
+ nlink_t st_nlink; /* link count */
+ struct timespec st_birthtimespec; /* birth time (creation time) */
+ struct timespec st_atimespec; /* access time */
+ struct timespec st_ctimespec; /* metadata modification time */
+ struct timespec st_ptimespec; /* time added to parent folder */
+ char *xattrsdigest; /* digest of extended attributes */
+ u_quad_t xdstream_priv_id; /* private id of the xattr data stream */
+ ino_t st_ino; /* inode */
+ char *acldigest; /* digest of access control list */
+ u_quad_t sibling_id; /* sibling id */
+
+#define F_CKSUM 0x00000001 /* check sum */
+#define F_DONE 0x00000002 /* directory done */
+#define F_GID 0x00000004 /* gid */
+#define F_GNAME 0x00000008 /* group name */
+#define F_IGN 0x00000010 /* ignore */
+#define F_MAGIC 0x00000020 /* name has magic chars */
+#define F_MODE 0x00000040 /* mode */
+#define F_NLINK 0x00000080 /* number of links */
+#define F_SIZE 0x00000100 /* size */
+#define F_SLINK 0x00000200 /* The file the symbolic link is expected to reference */
+#define F_TIME 0x00000400 /* modification time (mtime) */
+#define F_TYPE 0x00000800 /* file type */
+#define F_UID 0x00001000 /* uid */
+#define F_UNAME 0x00002000 /* user name */
+#define F_VISIT 0x00004000 /* file visited */
+#define F_MD5 0x00008000 /* MD5 digest */
+#define F_NOCHANGE 0x00010000 /* If owner/mode "wrong", do */
+ /* not change */
+#define F_SHA1 0x00020000 /* SHA-1 digest */
+#define F_RMD160 0x00040000 /* RIPEMD160 digest */
+#define F_FLAGS 0x00080000 /* file flags */
+#define F_SHA256 0x00100000 /* SHA-256 digest */
+#define F_BTIME 0x00200000 /* creation time */
+#define F_ATIME 0x00400000 /* access time */
+#define F_CTIME 0x00800000 /* metadata modification time (ctime) */
+#define F_PTIME 0x01000000 /* time added to parent folder */
+#define F_XATTRS 0x02000000 /* digest of extended attributes */
+#define F_INODE 0x04000000 /* inode */
+#define F_ACL 0x08000000 /* digest of access control list */
+#define F_SIBLINGID 0x10000000 /* sibling id */
+ u_int flags; /* items set */
+
+#define F_BLOCK 0x001 /* block special */
+#define F_CHAR 0x002 /* char special */
+#define F_DIR 0x004 /* directory */
+#define F_FIFO 0x008 /* fifo */
+#define F_FILE 0x010 /* regular file */
+#define F_LINK 0x020 /* symbolic link */
+#define F_SOCK 0x040 /* socket */
+ u_char type; /* file type */
+
+ char name[1]; /* file name (must be last) */
+} NODE;
+
+#define RP(p) \
+ ((p)->fts_path[0] == '.' && (p)->fts_path[1] == '/' ? \
+ (p)->fts_path + 2 : (p)->fts_path)
+
+#endif /* _MTREE_H_ */
diff --git a/file_cmds/mtree/spec.c b/file_cmds/mtree/spec.c
new file mode 100644
index 0000000..f15d857
--- /dev/null
+++ b/file_cmds/mtree/spec.c
@@ -0,0 +1,470 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/spec.c,v 1.22 2005/03/29 11:44:17 tobez Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <vis.h>
+#include "metrics.h"
+#include "mtree.h"
+#include "extern.h"
+
+int lineno; /* Current spec line number. */
+
+static void set(char *, NODE *);
+static void unset(char *, NODE *);
+
+NODE *
+mtree_readspec(FILE *fi)
+{
+ NODE *centry, *last;
+ char *p;
+ NODE ginfo, *root;
+ int c_cur, c_next;
+ char buf[2048];
+
+ centry = last = root = NULL;
+ bzero(&ginfo, sizeof(ginfo));
+ c_cur = c_next = 0;
+ for (lineno = 1; fgets(buf, sizeof(buf), fi);
+ ++lineno, c_cur = c_next, c_next = 0) {
+ /* Skip empty lines. */
+ if (buf[0] == '\n')
+ continue;
+
+ /* Find end of line. */
+ if ((p = index(buf, '\n')) == NULL) {
+ RECORD_FAILURE(21, ERANGE);
+ errx(1, "line %d too long", lineno);
+ }
+
+ /* See if next line is continuation line. */
+ if (p[-1] == '\\') {
+ --p;
+ c_next = 1;
+ }
+
+ /* Null-terminate the line. */
+ *p = '\0';
+
+ /* Skip leading whitespace. */
+ for (p = buf; *p && isspace(*p); ++p);
+
+ /* If nothing but whitespace or comment char, continue. */
+ if (!*p || *p == '#')
+ continue;
+
+#ifdef DEBUG
+ (void)fprintf(stderr, "line %d: {%s}\n", lineno, p);
+#endif
+ if (c_cur) {
+ set(p, centry);
+ continue;
+ }
+
+ /* Grab file name, "$", "set", or "unset". */
+ if ((p = strtok(p, "\n\t ")) == NULL) {
+ RECORD_FAILURE(22, EINVAL);
+ errx(1, "line %d: missing field", lineno);
+ }
+
+ if (p[0] == '/')
+ switch(p[1]) {
+ case 's':
+ if (strcmp(p + 1, "set"))
+ break;
+ set(NULL, &ginfo);
+ continue;
+ case 'u':
+ if (strcmp(p + 1, "unset"))
+ break;
+ unset(NULL, &ginfo);
+ continue;
+ }
+
+ if (index(p, '/')) {
+ RECORD_FAILURE(23, EINVAL);
+ errx(1, "line %d: slash character in file name",
+ lineno);
+ }
+
+ if (!strcmp(p, "..")) {
+ /* Don't go up, if haven't gone down. */
+ if (!root)
+ goto noparent;
+ if (last->type != F_DIR || last->flags & F_DONE) {
+ if (last == root)
+ goto noparent;
+ last = last->parent;
+ }
+ last->flags |= F_DONE;
+ continue;
+
+noparent: RECORD_FAILURE(24, EINVAL);
+ errx(1, "line %d: no parent node", lineno);
+ }
+
+ if ((centry = calloc(1, sizeof(NODE) + strlen(p))) == NULL) {
+ RECORD_FAILURE(25, ENOMEM);
+ errx(1, "calloc");
+ }
+ *centry = ginfo;
+#define MAGIC "?*["
+ if (strpbrk(p, MAGIC))
+ centry->flags |= F_MAGIC;
+ if (strunvis(centry->name, p) == -1) {
+ RECORD_FAILURE(26, EILSEQ);
+ errx(1, "filename %s is ill-encoded", p);
+ }
+ set(NULL, centry);
+
+ if (!root) {
+ last = root = centry;
+ root->parent = root;
+ } else if (last->type == F_DIR && !(last->flags & F_DONE)) {
+ centry->parent = last;
+ last = last->child = centry;
+ } else {
+ centry->parent = last->parent;
+ centry->prev = last;
+ last = last->next = centry;
+ }
+ }
+ return (root);
+}
+
+static void
+set(char *t, NODE *ip)
+{
+ int error = 0;
+ int type;
+ char *kw, *val = NULL;
+ struct group *gr;
+ struct passwd *pw;
+ mode_t *m;
+ int value;
+ char *ep;
+
+ for (; (kw = strtok(t, "= \t\n")); t = NULL) {
+ ip->flags |= type = parsekey(kw, &value);
+ if ((value == 0) || (val = strtok(NULL, " \t\n")) == NULL) {
+ RECORD_FAILURE(27, EINVAL);
+ errx(1, "line %d: missing value", lineno);
+ }
+ switch(type) {
+ case F_CKSUM:
+ ip->cksum = strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(28, EINVAL);
+ errx(1, "line %d: invalid checksum %s",
+ lineno, val);
+ }
+ break;
+ case F_MD5:
+ ip->md5digest = strdup(val);
+ if (!ip->md5digest) {
+ RECORD_FAILURE(29, ENOMEM);
+ errx(1, "strdup");
+ }
+ break;
+ case F_SHA1:
+ ip->sha1digest = strdup(val);
+ if (!ip->sha1digest) {
+ RECORD_FAILURE(30, ENOMEM);
+ errx(1, "strdup");
+ }
+ break;
+ case F_SHA256:
+ ip->sha256digest = strdup(val);
+ if (!ip->sha256digest) {
+ RECORD_FAILURE(31, ENOMEM);
+ errx(1, "strdup");
+ }
+ break;
+ case F_RMD160:
+ ip->rmd160digest = strdup(val);
+ if (!ip->rmd160digest) {
+ RECORD_FAILURE(32, ENOMEM);
+ errx(1, "strdup");
+ }
+ break;
+ case F_FLAGS:
+ if (strcmp("none", val) == 0) {
+ ip->st_flags = 0;
+ } else if (strtofflags(&val, &ip->st_flags, NULL) != 0) {
+ RECORD_FAILURE(33, EINVAL);
+ errx(1, "line %d: invalid flag %s",lineno, val);
+ }
+ break;
+ case F_GID:
+ ip->st_gid = (gid_t)strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(34, EINVAL);
+ errx(1, "line %d: invalid gid %s", lineno, val);
+ }
+ break;
+ case F_GNAME:
+ if ((gr = getgrnam(val)) == NULL) {
+ RECORD_FAILURE(35, EINVAL);
+ errx(1, "line %d: unknown group %s", lineno, val);
+ }
+ ip->st_gid = gr->gr_gid;
+ break;
+ case F_IGN:
+ /* just set flag bit */
+ break;
+ case F_MODE:
+ if ((m = setmode(val)) == NULL) {
+ RECORD_FAILURE(36, EINVAL);
+ errx(1, "line %d: invalid file mode %s",
+ lineno, val);
+ }
+ ip->st_mode = getmode(m, 0);
+ free(m);
+ break;
+ case F_NLINK:
+ ip->st_nlink = strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(37, EINVAL);
+ errx(1, "line %d: invalid link count %s",
+ lineno, val);
+ }
+ break;
+ case F_SIZE:
+ ip->st_size = strtoq(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(38, EINVAL);
+ errx(1, "line %d: invalid size %s",
+ lineno, val);
+ }
+ break;
+ case F_SLINK:
+ ip->slink = malloc(strlen(val) + 1);
+ if (ip->slink == NULL) {
+ RECORD_FAILURE(39, ENOMEM);
+ errx(1, "malloc");
+ }
+ if (strunvis(ip->slink, val) == -1) {
+ RECORD_FAILURE(40, EILSEQ);
+ errx(1, "symlink %s is ill-encoded", val);
+ }
+ break;
+ case F_TIME:
+ ip->st_mtimespec.tv_sec = strtoul(val, &ep, 10);
+ if (*ep != '.') {
+ RECORD_FAILURE(41, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ val = ep + 1;
+ ip->st_mtimespec.tv_nsec = strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(42, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ break;
+ case F_TYPE:
+ switch(*val) {
+ case 'b':
+ if (!strcmp(val, "block"))
+ ip->type = F_BLOCK;
+ break;
+ case 'c':
+ if (!strcmp(val, "char"))
+ ip->type = F_CHAR;
+ break;
+ case 'd':
+ if (!strcmp(val, "dir"))
+ ip->type = F_DIR;
+ break;
+ case 'f':
+ if (!strcmp(val, "file"))
+ ip->type = F_FILE;
+ if (!strcmp(val, "fifo"))
+ ip->type = F_FIFO;
+ break;
+ case 'l':
+ if (!strcmp(val, "link"))
+ ip->type = F_LINK;
+ break;
+ case 's':
+ if (!strcmp(val, "socket"))
+ ip->type = F_SOCK;
+ break;
+ default:
+ RECORD_FAILURE(43, EINVAL);
+ errx(1, "line %d: unknown file type %s",
+ lineno, val);
+ }
+ break;
+ case F_UID:
+ ip->st_uid = (uid_t)strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(44, EINVAL);
+ errx(1, "line %d: invalid uid %s", lineno, val);
+ }
+ break;
+ case F_UNAME:
+ if ((pw = getpwnam(val)) == NULL) {
+ RECORD_FAILURE(45, EINVAL);
+ errx(1, "line %d: unknown user %s", lineno, val);
+ }
+ ip->st_uid = pw->pw_uid;
+ break;
+ case F_BTIME:
+ ip->st_birthtimespec.tv_sec = strtoul(val, &ep, 10);
+ if (*ep != '.') {
+ RECORD_FAILURE(46, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ val = ep + 1;
+ ip->st_birthtimespec.tv_nsec = strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(47, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ break;
+ case F_ATIME:
+ ip->st_atimespec.tv_sec = strtoul(val, &ep, 10);
+ if (*ep != '.') {
+ RECORD_FAILURE(48, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ val = ep + 1;
+ ip->st_atimespec.tv_nsec = strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(49, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ break;
+ case F_CTIME:
+ ip->st_ctimespec.tv_sec = strtoul(val, &ep, 10);
+ if (*ep != '.') {
+ RECORD_FAILURE(50, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ val = ep + 1;
+ ip->st_ctimespec.tv_nsec = strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(51, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ break;
+ case F_PTIME:
+ ip->st_ptimespec.tv_sec = strtoul(val, &ep, 10);
+ if (*ep != '.') {
+ RECORD_FAILURE(52, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ val = ep + 1;
+ ip->st_ptimespec.tv_nsec = strtoul(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(53, EINVAL);
+ errx(1, "line %d: invalid time %s",
+ lineno, val);
+ }
+ break;
+ case F_XATTRS:
+ ep = strtok(val,".");
+ ip->xattrsdigest = strdup(ep);
+ if (!ip->xattrsdigest) {
+ error = errno;
+ RECORD_FAILURE(54, error);
+ errc(1, error, "strdup");
+ }
+ val = strtok(NULL,".");
+ if (val) {
+ ip->xdstream_priv_id = strtoull(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(55, EINVAL);
+ errx(1, "line %d: invalid private id %s",
+ lineno, val);
+ }
+ } else {
+ ip->xdstream_priv_id = 0;
+ }
+ break;
+ case F_INODE:
+ ip->st_ino = (ino_t)strtoull(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(56, EINVAL);
+ errx(1, "line %d: invalid inode %s",
+ lineno, val);
+ }
+ break;
+ case F_ACL:
+ ip->acldigest = strdup(val);
+ if (!ip->acldigest) {
+ error = errno;
+ RECORD_FAILURE(57, error);
+ errc(1, error, "strdup");
+ }
+ break;
+ case F_SIBLINGID:
+ ip->sibling_id = (quad_t)strtoull(val, &ep, 10);
+ if (*ep) {
+ RECORD_FAILURE(58, EINVAL);
+ errx(1, "line %d: invalid sibling id %s", lineno, val);
+ }
+ }
+ }
+}
+
+static void
+unset(char *t, NODE *ip)
+{
+ char *p;
+
+ while ((p = strtok(t, "\n\t ")))
+ ip->flags &= ~parsekey(p, NULL);
+}
diff --git a/file_cmds/mtree/specspec.c b/file_cmds/mtree/specspec.c
new file mode 100644
index 0000000..cb08384
--- /dev/null
+++ b/file_cmds/mtree/specspec.c
@@ -0,0 +1,327 @@
+/*-
+ * Copyright (c) 2003 Poul-Henning Kamp
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/specspec.c,v 1.6 2005/03/29 11:44:17 tobez Exp $");
+
+#include <sys/param.h>
+#include <err.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include "metrics.h"
+#include "mtree.h"
+#include "extern.h"
+
+#define FF(a, b, c, d) \
+ (((a)->flags & (c)) && ((b)->flags & (c)) && ((a)->d) != ((b)->d))
+#define FS(a, b, c, d) \
+ (((a)->flags & (c)) && ((b)->flags & (c)) && strcmp((a)->d,(b)->d))
+#define FM(a, b, c, d) \
+ (((a)->flags & (c)) && ((b)->flags & (c)) && memcmp(&(a)->d,&(b)->d, sizeof (a)->d))
+
+static void
+shownode(NODE *n, int f, char const *path)
+{
+ struct group *gr;
+ struct passwd *pw;
+
+ printf("%s%s %s", path, n->name, ftype(n->type));
+ if (f & F_CKSUM)
+ printf(" cksum=%lu", n->cksum);
+ if (f & F_GID)
+ printf(" gid=%d", n->st_gid);
+ if (f & F_GNAME) {
+ gr = getgrgid(n->st_gid);
+ if (gr == NULL)
+ printf(" gid=%d", n->st_gid);
+ else
+ printf(" gname=%s", gr->gr_name);
+ }
+ if (f & F_MODE)
+ printf(" mode=%o", n->st_mode);
+ if (f & F_NLINK)
+ printf(" nlink=%d", n->st_nlink);
+ if (f & F_SIZE)
+ printf(" size=%jd", (intmax_t)n->st_size);
+ if (f & F_TIME)
+ printf(" time=%ld.%09ld", n->st_mtimespec.tv_sec, n->st_mtimespec.tv_nsec);
+ if (f & F_UID)
+ printf(" uid=%d", n->st_uid);
+ if (f & F_UNAME) {
+ pw = getpwuid(n->st_uid);
+ if (pw == NULL)
+ printf(" uid=%d", n->st_uid);
+ else
+ printf(" uname=%s", pw->pw_name);
+ }
+ if (f & F_MD5)
+ printf(" md5digest=%s", n->md5digest);
+ if (f & F_SHA1)
+ printf(" sha1digest=%s", n->sha1digest);
+ if (f & F_RMD160)
+ printf(" rmd160digest=%s", n->rmd160digest);
+ if (f & F_SHA256)
+ printf(" sha256digest=%s", n->sha256digest);
+ if (f & F_FLAGS)
+ printf(" flags=%s", flags_to_string(n->st_flags));
+ if (f & F_BTIME)
+ printf(" btime=%ld.%09ld", n->st_birthtimespec.tv_sec, n->st_birthtimespec.tv_nsec);
+ if (f & F_ATIME)
+ printf(" atime=%ld.%09ld", n->st_atimespec.tv_sec, n->st_atimespec.tv_nsec);
+ if (f & F_CTIME)
+ printf(" ctime=%ld.%09ld", n->st_ctimespec.tv_sec, n->st_ctimespec.tv_nsec);
+ if (f & F_PTIME)
+ printf(" ptime=%ld.%09ld", n->st_ptimespec.tv_sec, n->st_ptimespec.tv_nsec);
+ if (f & F_XATTRS)
+ printf(" xattrsdigest=%s.%llu", n->xattrsdigest, n->xdstream_priv_id);
+ if (f & F_INODE)
+ printf(" inode=%llu", n->st_ino);
+ if (f & F_ACL)
+ printf(" acldigest=%s", n->acldigest);
+ if (f & F_SIBLINGID)
+ printf(" siblingid=%llu", n->sibling_id);
+
+ printf("\n");
+}
+
+static int
+mismatch(NODE *n1, NODE *n2, int differ, char const *path)
+{
+
+ if (n2 == NULL) {
+ shownode(n1, differ, path);
+ return (1);
+ }
+ if (n1 == NULL) {
+ printf("\t");
+ shownode(n2, differ, path);
+ return (1);
+ }
+ if (!(differ & keys))
+ return(0);
+ printf("\t\t");
+ shownode(n1, differ, path);
+ printf("\t\t");
+ shownode(n2, differ, path);
+ return (1);
+}
+
+static int
+compare_nodes(NODE *n1, NODE *n2, char const *path)
+{
+ int differs;
+
+ if (n1 != NULL && n1->type == F_LINK)
+ n1->flags &= ~F_MODE;
+ if (n2 != NULL && n2->type == F_LINK)
+ n2->flags &= ~F_MODE;
+ differs = 0;
+ if ((n1 == NULL) && (n2 == NULL)) {
+ return 0;
+ } else if (n1 == NULL) {
+ differs = n2->flags;
+ RECORD_FAILURE(111, WARN_MISMATCH);
+ mismatch(n1, n2, differs, path);
+ return (1);
+ } else if (n2 == NULL) {
+ differs = n1->flags;
+ RECORD_FAILURE(112, WARN_MISMATCH);
+ mismatch(n1, n2, differs, path);
+ return (1);
+ } else if (n1->type != n2->type) {
+ differs = 0;
+ RECORD_FAILURE(113, WARN_MISMATCH);
+ mismatch(n1, n2, differs, path);
+ return (1);
+ }
+ if (FF(n1, n2, F_CKSUM, cksum))
+ differs |= F_CKSUM;
+ if (FF(n1, n2, F_GID, st_gid))
+ differs |= F_GID;
+ if (FF(n1, n2, F_GNAME, st_gid))
+ differs |= F_GNAME;
+ if (FF(n1, n2, F_MODE, st_mode))
+ differs |= F_MODE;
+ if (FF(n1, n2, F_NLINK, st_nlink))
+ differs |= F_NLINK;
+ if (FF(n1, n2, F_SIZE, st_size))
+ differs |= F_SIZE;
+ if (FS(n1, n2, F_SLINK, slink))
+ differs |= F_SLINK;
+ if (FM(n1, n2, F_TIME, st_mtimespec))
+ differs |= F_TIME;
+ if (FF(n1, n2, F_UID, st_uid))
+ differs |= F_UID;
+ if (FF(n1, n2, F_UNAME, st_uid))
+ differs |= F_UNAME;
+ if (FS(n1, n2, F_MD5, md5digest))
+ differs |= F_MD5;
+ if (FS(n1, n2, F_SHA1, sha1digest))
+ differs |= F_SHA1;
+ if (FS(n1, n2, F_RMD160, rmd160digest))
+ differs |= F_RMD160;
+ if (FS(n1, n2, F_SHA256, sha256digest))
+ differs |= F_SHA256;
+ if (FF(n1, n2, F_FLAGS, st_flags))
+ differs |= F_FLAGS;
+ if (FM(n1, n2, F_BTIME, st_birthtimespec))
+ differs |= F_BTIME;
+ if (FM(n1, n2, F_ATIME, st_atimespec))
+ differs |= F_ATIME;
+ if (FM(n1, n2, F_CTIME, st_ctimespec))
+ differs |= F_CTIME;
+ if (FM(n1, n2, F_PTIME, st_ptimespec))
+ differs |= F_PTIME;
+ if (FS(n1, n2, F_XATTRS, xattrsdigest))
+ differs |= F_XATTRS;
+ if (FF(n1, n2, F_INODE, st_ino))
+ differs |= F_INODE;
+ if (FS(n1, n2, F_ACL, acldigest))
+ differs |= F_ACL;
+ if (FF(n1, n2, F_SIBLINGID, sibling_id))
+ differs |= F_SIBLINGID;
+
+ if (differs) {
+ RECORD_FAILURE(114, WARN_MISMATCH);
+ mismatch(n1, n2, differs, path);
+ return (1);
+ }
+ return (0);
+}
+static int
+walk_in_the_forest(NODE *t1, NODE *t2, char const *path)
+{
+ int r, i, c;
+ NODE *c1, *c2, *n1, *n2;
+ char *np;
+
+ r = 0;
+
+ if (t1 != NULL)
+ c1 = t1->child;
+ else
+ c1 = NULL;
+ if (t2 != NULL)
+ c2 = t2->child;
+ else
+ c2 = NULL;
+ while (c1 != NULL || c2 != NULL) {
+ n1 = n2 = NULL;
+ if (c1 != NULL)
+ n1 = c1->next;
+ if (c2 != NULL)
+ n2 = c2->next;
+ if (c1 != NULL && c2 != NULL) {
+ if (c1->type != F_DIR && c2->type == F_DIR) {
+ n2 = c2;
+ c2 = NULL;
+ } else if (c1->type == F_DIR && c2->type != F_DIR) {
+ n1 = c1;
+ c1 = NULL;
+ } else {
+ i = strcmp(c1->name, c2->name);
+ if (i > 0) {
+ n1 = c1;
+ c1 = NULL;
+ } else if (i < 0) {
+ n2 = c2;
+ c2 = NULL;
+ }
+ }
+ }
+ if (c1 == NULL && c2->type == F_DIR) {
+ asprintf(&np, "%s%s/", path, c2->name);
+ i = walk_in_the_forest(c1, c2, np);
+ if (i) {
+ RECORD_FAILURE(115, WARN_MISMATCH);
+ }
+ free(np);
+ c = compare_nodes(c1, c2, path);
+ if (c) {
+ RECORD_FAILURE(116, WARN_MISMATCH);
+ }
+ i += c;
+ } else if (c2 == NULL && c1->type == F_DIR) {
+ asprintf(&np, "%s%s/", path, c1->name);
+ i = walk_in_the_forest(c1, c2, np);
+ if (i) {
+ RECORD_FAILURE(117, WARN_MISMATCH);
+ }
+ free(np);
+ c = compare_nodes(c1, c2, path);
+ if (c) {
+ RECORD_FAILURE(118, WARN_MISMATCH);
+ }
+ i += c;
+ } else if (c1 == NULL || c2 == NULL) {
+ i = compare_nodes(c1, c2, path);
+ if (i) {
+ RECORD_FAILURE(119, WARN_MISMATCH);
+ }
+ } else if (c1->type == F_DIR && c2->type == F_DIR) {
+ asprintf(&np, "%s%s/", path, c1->name);
+ i = walk_in_the_forest(c1, c2, np);
+ if (i) {
+ RECORD_FAILURE(120, WARN_MISMATCH);
+ }
+ free(np);
+ c = compare_nodes(c1, c2, path);
+ if (c) {
+ RECORD_FAILURE(121, WARN_MISMATCH);
+ }
+ i += c;
+ } else {
+ i = compare_nodes(c1, c2, path);
+ if (i) {
+ RECORD_FAILURE(122, WARN_MISMATCH);
+ }
+ }
+ r += i;
+ c1 = n1;
+ c2 = n2;
+ }
+ return (r);
+}
+
+int
+mtree_specspec(FILE *fi, FILE *fj)
+{
+ int rval;
+ NODE *root1, *root2;
+
+ root1 = mtree_readspec(fi);
+ root2 = mtree_readspec(fj);
+ rval = walk_in_the_forest(root1, root2, "");
+ rval += compare_nodes(root1, root2, "");
+ if (rval > 0) {
+ RECORD_FAILURE(123, WARN_MISMATCH);
+ return (MISMATCHEXIT);
+ }
+ return (0);
+}
diff --git a/file_cmds/mtree/test/test00.sh b/file_cmds/mtree/test/test00.sh
new file mode 100644
index 0000000..a2e4b28
--- /dev/null
+++ b/file_cmds/mtree/test/test00.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+#
+# Copyright (c) 2003 Poul-Henning Kamp
+# All rights reserved.
+#
+# Please see src/share/examples/etc/bsd-style-copyright.
+#
+# $FreeBSD: src/usr.sbin/mtree/test/test00.sh,v 1.3 2003/11/05 22:26:08 phk Exp $
+#
+
+set -e
+
+TMP=/tmp/mtree.$$
+
+rm -rf ${TMP}
+mkdir -p ${TMP} ${TMP}/mr ${TMP}/mt
+
+
+mkdir ${TMP}/mt/foo
+mkdir ${TMP}/mr/\*
+mtree -c -p ${TMP}/mr | mtree -U -r -p ${TMP}/mt > /dev/null 2>&1
+if [ -d ${TMP}/mt/foo ] ; then
+ echo "ERROR Mtree create fell for filename with '*' char" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+rmdir ${TMP}/mr/\*
+
+mkdir -p ${TMP}/mt/foo
+mkdir ${TMP}/mr/\[f\]oo
+mtree -c -p ${TMP}/mr | mtree -U -r -p ${TMP}/mt > /dev/null 2>&1
+if [ -d ${TMP}/mt/foo ] ; then
+ echo "ERROR Mtree create fell for filename with '[' char" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+rmdir ${TMP}/mr/\[f\]oo
+
+mkdir -p ${TMP}/mt/foo
+mkdir ${TMP}/mr/\?oo
+mtree -c -p ${TMP}/mr | mtree -U -r -p ${TMP}/mt > /dev/null 2>&1
+if [ -d ${TMP}/mt/foo ] ; then
+ echo "ERROR Mtree create fell for filename with '?' char" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+rmdir ${TMP}/mr/\?oo
+
+mkdir ${TMP}/mr/\#
+mtree -c -p ${TMP}/mr > ${TMP}/_
+if mtree -U -r -p ${TMP}/mt < ${TMP}/_ > /dev/null 2>&1 ; then
+ true
+else
+ echo "ERROR Mtree create fell for filename with '#' char" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+
+if [ ! -d ${TMP}/mt/\# ] ; then
+ echo "ERROR Mtree update failed to create name with '#' char" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+rmdir ${TMP}/mr/\#
+
+rm -rf ${TMP}
+exit 0
diff --git a/file_cmds/mtree/test/test01.sh b/file_cmds/mtree/test/test01.sh
new file mode 100644
index 0000000..d056b91
--- /dev/null
+++ b/file_cmds/mtree/test/test01.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+# Copyright (c) 2003 Poul-Henning Kamp
+# All rights reserved.
+#
+# Please see src/share/examples/etc/bsd-style-copyright.
+#
+# $FreeBSD: src/usr.sbin/mtree/test/test01.sh,v 1.1 2003/10/30 12:01:32 phk Exp $
+#
+
+set -e
+
+TMP=/tmp/mtree.$$
+
+rm -rf ${TMP}
+mkdir -p ${TMP} ${TMP}/mr ${TMP}/mt
+
+
+ln -s "xx this=is=wrong" ${TMP}/mr/foo
+mtree -c -p ${TMP}/mr > ${TMP}/_
+
+if mtree -U -r -p ${TMP}/mt < ${TMP}/_ > /dev/null 2>&1 ; then
+ true
+else
+ echo "ERROR Mtree failed on symlink with space char" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+
+x=x`(cd ${TMP}/mr ; ls -l foo 2>&1) || true`
+y=x`(cd ${TMP}/mt ; ls -l foo 2>&1) || true`
+
+if [ "$x" != "$y" ] ; then
+ echo "ERROR Recreation of spaced symlink failed" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+
+rm -rf ${TMP}
+exit 0
diff --git a/file_cmds/mtree/test/test02.sh b/file_cmds/mtree/test/test02.sh
new file mode 100644
index 0000000..450ebb3
--- /dev/null
+++ b/file_cmds/mtree/test/test02.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Copyright (c) 2003 Dan Nelson
+# All rights reserved.
+#
+# Please see src/share/examples/etc/bsd-style-copyright.
+#
+# $FreeBSD: src/usr.sbin/mtree/test/test02.sh,v 1.1 2003/10/31 13:39:19 phk Exp $
+#
+
+set -e
+
+TMP=/tmp/mtree.$$
+
+rm -rf ${TMP}
+mkdir -p ${TMP} ${TMP}/mr ${TMP}/mt
+
+touch -t 199901020304 ${TMP}/mr/oldfile
+touch ${TMP}/mt/oldfile
+
+mtree -c -p ${TMP}/mr > ${TMP}/_
+
+mtree -U -r -p ${TMP}/mt < ${TMP}/_ > /dev/null
+
+x=x`(cd ${TMP}/mr ; ls -l 2>&1) || true`
+y=x`(cd ${TMP}/mt ; ls -l 2>&1) || true`
+
+if [ "$x" != "$y" ] ; then
+ echo "ERROR Update of mtime failed" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+
+rm -rf ${TMP}
+exit 0
+
diff --git a/file_cmds/mtree/test/test03.sh b/file_cmds/mtree/test/test03.sh
new file mode 100644
index 0000000..52e08c3
--- /dev/null
+++ b/file_cmds/mtree/test/test03.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+#
+# Copyright (c) 2003 Poul-Henning Kamp
+# All rights reserved.
+#
+# Please see src/share/examples/etc/bsd-style-copyright.
+#
+# $FreeBSD: src/usr.sbin/mtree/test/test03.sh,v 1.2 2005/03/29 11:44:17 tobez Exp $
+#
+
+set -e
+
+TMP=/tmp/mtree.$$
+
+rm -rf ${TMP}
+mkdir -p ${TMP}
+
+K=uid,uname,gid,gname,flags,md5digest,size,ripemd160digest,sha1digest,sha256digest,cksum
+
+rm -rf _FOO
+mkdir _FOO
+touch _FOO/_uid
+touch _FOO/_size
+touch _FOO/zztype
+
+touch _FOO/_bar
+mtree -c -K $K -p .. > ${TMP}/_r
+mtree -c -K $K -p .. > ${TMP}/_r2
+rm -rf _FOO/_bar
+
+rm -rf _FOO/zztype
+mkdir _FOO/zztype
+
+date > _FOO/_size
+
+chown nobody _FOO/_uid
+
+touch _FOO/_foo
+mtree -c -K $K -p .. > ${TMP}/_t
+
+rm -fr _FOO
+
+if mtree -f ${TMP}/_r -f ${TMP}/_r2 ; then
+ true
+else
+ echo "ERROR Compare identical failed" 1>&2
+ exit 1
+fi
+
+if mtree -f ${TMP}/_r -f ${TMP}/_t > ${TMP}/_ ; then
+ echo "ERROR Compare different succeeded" 1>&2
+ exit 1
+fi
+
+if [ `wc -l < ${TMP}/_` -ne 10 ] ; then
+ echo "ERROR wrong number of lines: `wc -l ${TMP}/_`" 1>&2
+ exit 1
+fi
+
+exit 0
diff --git a/file_cmds/mtree/test/test04.sh b/file_cmds/mtree/test/test04.sh
new file mode 100644
index 0000000..453d146
--- /dev/null
+++ b/file_cmds/mtree/test/test04.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+#
+# Copyright (c) 2003 Dan Nelson
+# All rights reserved.
+#
+# Please see src/share/examples/etc/bsd-style-copyright.
+#
+# $FreeBSD: src/usr.sbin/mtree/test/test04.sh,v 1.1 2003/11/13 11:02:57 phk Exp $
+#
+
+set -e
+
+TMP=/tmp/mtree.$$
+
+rm -rf ${TMP}
+mkdir -p ${TMP} ${TMP}/mr ${TMP}/mt
+
+mkdir ${TMP}/mr/a
+mkdir ${TMP}/mr/b
+mkdir ${TMP}/mt/a
+mkdir ${TMP}/mt/b
+touch ${TMP}/mt/z
+
+mtree -c -p ${TMP}/mr > ${TMP}/_r
+mtree -c -p ${TMP}/mt > ${TMP}/_t
+
+if mtree -f ${TMP}/_r -f ${TMP}/_t > ${TMP}/_ ; then
+ echo "ERROR wrong exit on difference" 1>&2
+ exit 1
+fi
+
+if [ `wc -l < ${TMP}/_` -ne 1 ] ; then
+ echo "ERROR spec/spec compare generated wrong output" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+
+if mtree -f ${TMP}/_t -f ${TMP}/_r > ${TMP}/_ ; then
+ echo "ERROR wrong exit on difference" 1>&2
+ exit 1
+fi
+
+if [ `wc -l < ${TMP}/_` -ne 1 ] ; then
+ echo "ERROR spec/spec compare generated wrong output" 1>&2
+ rm -rf ${TMP}
+ exit 1
+fi
+
+rm -rf ${TMP}
+exit 0
+
diff --git a/file_cmds/mtree/verify.c b/file_cmds/mtree/verify.c
new file mode 100644
index 0000000..7471652
--- /dev/null
+++ b/file_cmds/mtree/verify.c
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/mtree/verify.c,v 1.24 2005/08/11 15:43:55 brian Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <removefile.h>
+#include "metrics.h"
+#include "mtree.h"
+#include "extern.h"
+
+static NODE *root;
+static char path[MAXPATHLEN];
+
+static int miss(NODE *, char *, size_t path_length);
+static int vwalk(void);
+
+int
+mtree_verifyspec(FILE *fi)
+{
+ int rval, mval;
+ size_t path_length = 0;
+
+ root = mtree_readspec(fi);
+ rval = vwalk();
+ mval = miss(root, path, path_length);
+
+ if (rval != 0) {
+ RECORD_FAILURE(60, WARN_MISMATCH);
+ return rval;
+ } else {
+ RECORD_FAILURE(61, WARN_MISMATCH);
+ return mval;
+ }
+}
+
+static int
+vwalk(void)
+{
+ int error = 0;
+ FTS *t;
+ FTSENT *p;
+ NODE *ep, *level;
+ int specdepth, rval;
+ char *argv[2];
+ char dot[] = ".";
+
+ argv[0] = dot;
+ argv[1] = NULL;
+ if ((t = fts_open(argv, ftsoptions, NULL)) == NULL) {
+ error = errno;
+ RECORD_FAILURE(62, error);
+ errc(1, error, "line %d: fts_open", lineno);
+ }
+ level = root;
+ specdepth = rval = 0;
+ while ((p = fts_read(t))) {
+ if (check_excludes(p->fts_name, p->fts_path)) {
+ fts_set(t, p, FTS_SKIP);
+ continue;
+ }
+ switch(p->fts_info) {
+ case FTS_D:
+ case FTS_SL:
+ break;
+ case FTS_DP:
+ if (level == NULL) {
+ RECORD_FAILURE(63, EINVAL);
+ errx(1 , "invalid root in vwalk");
+ }
+ if (specdepth > p->fts_level) {
+ for (level = level->parent; level->prev;
+ level = level->prev);
+ --specdepth;
+ }
+ continue;
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ warnx("%s: %s", RP(p), strerror(p->fts_errno));
+ continue;
+ default:
+ if (dflag)
+ continue;
+ }
+
+ if (specdepth != p->fts_level)
+ goto extra;
+ for (ep = level; ep; ep = ep->next)
+ if ((ep->flags & F_MAGIC &&
+ !fnmatch(ep->name, p->fts_name, FNM_PATHNAME)) ||
+ !strcmp(ep->name, p->fts_name)) {
+ ep->flags |= F_VISIT;
+ if ((ep->flags & F_NOCHANGE) == 0 &&
+ compare(ep->name, ep, p)) {
+ RECORD_FAILURE(64, WARN_MISMATCH);
+ rval = MISMATCHEXIT;
+ }
+ if (ep->flags & F_IGN)
+ (void)fts_set(t, p, FTS_SKIP);
+ else if (ep->child && ep->type == F_DIR &&
+ p->fts_info == FTS_D) {
+ level = ep->child;
+ ++specdepth;
+ }
+ break;
+ }
+
+ if (ep)
+ continue;
+extra:
+ if (!eflag) {
+ (void)printf("%s extra", RP(p));
+
+ if (rflag) {
+ /* rflag implies: delete stuff if "extra" is observed" */
+ if (mflag) {
+ /* -mflag is used for sealing & verification -- use removefile for recursive behavior */
+ removefile_state_t rmstate;
+ rmstate = removefile_state_alloc();
+ if (removefile(p->fts_accpath, rmstate, (REMOVEFILE_RECURSIVE))) {
+ error = errno;
+ RECORD_FAILURE(65, error);
+ errx (1, "\n error deleting item (or descendant) at path %s (%s)", RP(p), strerror(error));
+ }
+ else {
+ /* removefile success */
+ (void) printf(", removed");
+ }
+ removefile_state_free(rmstate);
+
+ }
+ else {
+ /* legacy: use rmdir/unlink if "-m" not specified */
+ int syserr = 0;
+
+ if (S_ISDIR(p->fts_statp->st_mode)){
+ syserr = rmdir(p->fts_accpath);
+ }
+ else {
+ syserr = unlink(p->fts_accpath);
+ }
+
+ /* log failures */
+ if (syserr) {
+ error = errno;
+ RECORD_FAILURE(66, error);
+ (void) printf(", not removed :%s", strerror(error));
+ }
+ }
+ } else if (mflag) {
+ RECORD_FAILURE(68956, WARN_MISMATCH);
+ errx(1, "cannot generate the XML dictionary");
+ }
+ (void)putchar('\n');
+ }
+ (void)fts_set(t, p, FTS_SKIP);
+ }
+ (void)fts_close(t);
+ if (sflag) {
+ RECORD_FAILURE(67, WARN_CHECKSUM);
+ warnx("%s checksum: %lu", fullpath, (unsigned long)crc_total);
+ }
+ return (rval);
+}
+
+static int
+miss(NODE *p, char *tail, size_t path_length)
+{
+ int create;
+ char *tp;
+ const char *type, *what;
+ int serr;
+ int rval = 0;
+ int rrval = 0;
+ size_t file_name_length = 0;
+
+ for (; p; p = p->next) {
+ if (p->type != F_DIR && (dflag || p->flags & F_VISIT))
+ continue;
+ file_name_length = strnlen(p->name, MAXPATHLEN);
+ path_length += file_name_length;
+ if (path_length >= MAXPATHLEN) {
+ RECORD_FAILURE(61971, ENAMETOOLONG);
+ continue;
+ }
+ (void)strcpy(tail, p->name);
+ if (!(p->flags & F_VISIT)) {
+ /* Don't print missing message if file exists as a
+ symbolic link and the -q flag is set. */
+ struct stat statbuf;
+
+ if (qflag && stat(path, &statbuf) == 0) {
+ p->flags |= F_VISIT;
+ } else {
+ (void)printf("%s missing", path);
+ RECORD_FAILURE(68, WARN_MISMATCH);
+ rval = MISMATCHEXIT;
+ }
+ }
+ if (p->type != F_DIR && p->type != F_LINK) {
+ putchar('\n');
+ continue;
+ }
+
+ create = 0;
+ if (p->type == F_LINK)
+ type = "symlink";
+ else
+ type = "directory";
+ if (!(p->flags & F_VISIT) && uflag) {
+ if (!(p->flags & (F_UID | F_UNAME))) {
+ (void)printf(" (%s not created: user not specified)", type);
+ } else if (!(p->flags & (F_GID | F_GNAME))) {
+ (void)printf(" (%s not created: group not specified)", type);
+ } else if (p->type == F_LINK) {
+ if (symlink(p->slink, path)) {
+ serr = errno;
+ RECORD_FAILURE(69, serr);
+ (void)printf(" (symlink not created: %s)\n",
+ strerror(serr));
+ } else {
+ (void)printf(" (created)\n");
+ }
+ if (lchown(path, p->st_uid, p->st_gid) == -1) {
+ serr = errno;
+ if (p->st_uid == (uid_t)-1)
+ what = "group";
+ else if (lchown(path, (uid_t)-1,
+ p->st_gid) == -1)
+ what = "user & group";
+ else {
+ what = "user";
+ errno = serr;
+ }
+ serr = errno;
+ RECORD_FAILURE(70, serr);
+ (void)printf("%s: %s not modified: %s"
+ "\n", path, what, strerror(serr));
+ }
+ continue;
+ } else if (!(p->flags & F_MODE)) {
+ (void)printf(" (directory not created: mode not specified)");
+ } else if (mkdir(path, S_IRWXU)) {
+ serr = errno;
+ RECORD_FAILURE(71, serr);
+ (void)printf(" (directory not created: %s)",
+ strerror(serr));
+ } else {
+ create = 1;
+ (void)printf(" (created)");
+ }
+ }
+ if (!(p->flags & F_VISIT))
+ (void)putchar('\n');
+
+ for (tp = tail; *tp; ++tp);
+ *tp = '/';
+ ++path_length;
+ rrval = miss(p->child, tp + 1, path_length);
+ if (rrval != 0) {
+ RECORD_FAILURE(72, WARN_MISMATCH);
+ rval = rrval;
+ }
+ path_length -= (file_name_length + 1);
+ *tp = '\0';
+
+ if (!create)
+ continue;
+ if (chown(path, p->st_uid, p->st_gid) == -1) {
+ serr = errno;
+ if (p->st_uid == (uid_t)-1)
+ what = "group";
+ else if (chown(path, (uid_t)-1, p->st_gid) == -1)
+ what = "user & group";
+ else {
+ what = "user";
+ errno = serr;
+ }
+ serr = errno;
+ RECORD_FAILURE(73, serr);
+ (void)printf("%s: %s not modified: %s\n",
+ path, what, strerror(serr));
+ }
+ if (chmod(path, p->st_mode)) {
+ serr = errno;
+ RECORD_FAILURE(74, serr);
+ (void)printf("%s: permissions not set: %s\n",
+ path, strerror(serr));
+ }
+ if ((p->flags & F_FLAGS) && p->st_flags &&
+ chflags(path, (u_int)p->st_flags)) {
+ serr = errno;
+ RECORD_FAILURE(75, serr);
+ (void)printf("%s: file flags not set: %s\n",
+ path, strerror(serr));
+ }
+ }
+ return rval;
+}
diff --git a/file_cmds/mv/mv.1 b/file_cmds/mv/mv.1
new file mode 100644
index 0000000..569e5c5
--- /dev/null
+++ b/file_cmds/mv/mv.1
@@ -0,0 +1,184 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mv.1 8.1 (Berkeley) 5/31/93
+.\" $FreeBSD: src/bin/mv/mv.1,v 1.25 2002/08/26 06:16:51 keramida Exp $
+.\"
+.Dd July 9, 2002
+.Dt MV 1
+.Os
+.Sh NAME
+.Nm mv
+.Nd move files
+.Sh SYNOPSIS
+.Nm mv
+.Op Fl f | i | n
+.Op Fl v
+.Ar source target
+.Nm mv
+.Op Fl f | i | n
+.Op Fl v
+.Ar source ... directory
+.Sh DESCRIPTION
+In its first form, the
+.Nm mv
+utility renames the file named by the
+.Ar source
+operand to the destination path named by the
+.Ar target
+operand.
+This form is assumed when the last operand does not name an already
+existing directory.
+.Pp
+In its second form,
+.Nm mv
+moves each file named by a
+.Ar source
+operand to a destination file in the existing directory named by the
+.Ar directory
+operand.
+The destination path for each operand is the pathname produced by the
+concatenation of the last operand, a slash, and the final pathname
+component of the named file.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl f
+Do not prompt for confirmation before overwriting the destination
+path.
+(The
+.Fl f
+option overrides any previous
+.Fl i
+or
+.Fl n
+options.)
+.It Fl i
+Cause
+.Nm mv
+to write a prompt to standard error before moving a file that would
+overwrite an existing file.
+If the response from the standard input begins with the character
+.Ql y
+or
+.Ql Y ,
+the move is attempted.
+(The
+.Fl i
+option overrides any previous
+.Fl f
+or
+.Fl n
+options.)
+.It Fl n
+Do not overwrite an existing file.
+(The
+.Fl n
+option overrides any previous
+.Fl f
+or
+.Fl i
+options.)
+.It Fl v
+Cause
+.Nm mv
+to be verbose, showing files after they are moved.
+.El
+.Pp
+It is an error for either the
+.Ar source
+operand or the destination path to specify a directory unless both do.
+.Pp
+If the destination path does not have a mode which permits writing,
+.Nm mv
+prompts the user for confirmation as specified for the
+.Fl i
+option.
+.Pp
+As the
+.Xr rename 2
+call does not work across file systems,
+.Nm mv
+uses
+.Xr cp 1
+and
+.Xr rm 1
+to accomplish the move.
+The effect is equivalent to:
+.Bd -literal -offset indent
+rm -f destination_path && \e
+cp -pRP source_file destination && \e
+rm -rf source_file
+.Ed
+.Sh DIAGNOSTICS
+.Ex -std
+.Pp
+The command "mv dir/afile dir" will abort with an error message.
+.Sh LEGACY DIAGNOSTICS
+In legacy mode, the command "mv dir/afile dir" will fail silently,
+returning an exit code of 0.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr cp 1 ,
+.Xr rm 1 ,
+.Xr symlink 7
+.Sh COMPATIBILITY
+The
+.Fl n
+and
+.Fl v
+options are non-standard and their use in scripts is not recommended.
+.Pp
+The
+.Nm mv
+utility now supports HFS+ Finder and Extended Attributes and resource forks.
+The
+.Nm mv
+utility will no longer strip resource forks off of HFS files.
+For an alternative method,
+refer to
+.Xr cp 1 .
+.Sh STANDARDS
+The
+.Nm mv
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm mv
+command appeared in
+.At v1 .
diff --git a/file_cmds/mv/mv.c b/file_cmds/mv/mv.c
new file mode 100644
index 0000000..52a2938
--- /dev/null
+++ b/file_cmds/mv/mv.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Ken Smith of The State University of New York at Buffalo.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static char const copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/mv/mv.c,v 1.39 2002/07/09 17:45:13 johan Exp $");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <locale.h>
+
+#ifdef __APPLE__
+#include <copyfile.h>
+#include <sys/mount.h>
+#endif
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+#include "pathnames.h"
+
+int fflg, iflg, nflg, vflg;
+
+int copy(char *, char *);
+int do_move(char *, char *);
+int fastcopy(char *, char *, struct stat *);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ size_t baselen, len;
+ int rval;
+ char *p, *endp;
+ struct stat sb;
+#ifdef __APPLE__
+ struct stat fsb, tsb;
+#endif /* __APPLE__ */
+ int ch;
+ char path[PATH_MAX];
+
+ while ((ch = getopt(argc, argv, "finv")) != -1)
+ switch (ch) {
+ case 'i':
+ iflg = 1;
+ fflg = nflg = 0;
+ break;
+ case 'f':
+ fflg = 1;
+ iflg = nflg = 0;
+ break;
+ case 'n':
+ nflg = 1;
+ fflg = iflg = 0;
+ break;
+ case 'v':
+ vflg = 1;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ usage();
+
+ /*
+ * If the stat on the target fails or the target isn't a directory,
+ * try the move. More than 2 arguments is an error in this case.
+ */
+ if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
+ if (argc > 2)
+ usage();
+ exit(do_move(argv[0], argv[1]));
+ }
+
+#ifdef __APPLE__
+ if (argc == 2 && !lstat(argv[0], &fsb) && !lstat(argv[1], &tsb) &&
+ fsb.st_ino == tsb.st_ino && fsb.st_dev == tsb.st_dev &&
+ fsb.st_gen == tsb.st_gen) {
+ /*
+ * We appear to be trying to move a directory into itself,
+ * but it may be that the filesystem is case insensitive and
+ * we are trying to rename the directory to a case-variant.
+ * Ignoring trailing slashes, we look for any difference in
+ * the directory names. If there is a difference we do
+ * the rename, otherwise we fall-thru to the traditional
+ * error. Note the lstat calls above (rather than stat)
+ * permit the renaming of symlinks to case-variants.
+ */
+ char *q;
+
+ for (p = argv[0] + strlen(argv[0]); p != argv[0]; ) {
+ p--;
+ if (*p != '/')
+ break;
+ }
+ for (q = argv[1] + strlen(argv[1]); q != argv[1]; ) {
+ q--;
+ if (*q != '/')
+ break;
+ }
+ for ( ; ; p--, q--) {
+ if (*p != *q)
+ exit(do_move(argv[0], argv[1]));
+ if (*p == '/')
+ break;
+ if (p == argv[0]) {
+ if (q == argv[1] || *(q-1) == '/')
+ break;
+ exit(do_move(argv[0], argv[1]));
+ }
+ if (q == argv[1]) {
+ if (p == argv[0] || *(p-1) == '/')
+ break;
+ exit(do_move(argv[0], argv[1]));
+ }
+ }
+ }
+#endif /* __APPLE__ */
+
+ /* It's a directory, move each file into it. */
+ if (strlen(argv[argc - 1]) > sizeof(path) - 1)
+ errx(1, "%s: destination pathname too long", *argv);
+ (void)strcpy(path, argv[argc - 1]);
+ baselen = strlen(path);
+ endp = &path[baselen];
+ if (!baselen || *(endp - 1) != '/') {
+ *endp++ = '/';
+ ++baselen;
+ }
+ for (rval = 0; --argc; ++argv) {
+ /*
+ * Find the last component of the source pathname. It
+ * may have trailing slashes.
+ */
+ p = *argv + strlen(*argv);
+ while (p != *argv && p[-1] == '/')
+ --p;
+ while (p != *argv && p[-1] != '/')
+ --p;
+
+ if ((baselen + (len = strlen(p))) >= PATH_MAX) {
+ warnx("%s: destination pathname too long", *argv);
+ rval = 1;
+ } else {
+ memmove(endp, p, (size_t)len + 1);
+ if (COMPAT_MODE("bin/mv", "unix2003")) {
+ /*
+ * For Unix 2003 compatibility, check if old and new are
+ * same file, and produce an error * (like on Sun) that
+ * conformance test 66 in mv.ex expects.
+ */
+ if (!stat(*argv, &fsb) && !stat(path, &tsb) &&
+ fsb.st_ino == tsb.st_ino &&
+ fsb.st_dev == tsb.st_dev &&
+ fsb.st_gen == tsb.st_gen) {
+ (void)fprintf(stderr, "mv: %s and %s are identical\n",
+ *argv, path);
+ rval = 2; /* Like the Sun */
+ } else {
+ if (do_move(*argv, path))
+ rval = 1;
+ }
+ } else {
+ if (do_move(*argv, path))
+ rval = 1;
+ }
+ }
+ }
+ exit(rval);
+}
+
+int
+do_move(char *from, char *to)
+{
+ struct stat sb;
+ int ask, ch, first;
+ char modep[15];
+ char resp[] = {'\0', '\0'};
+
+ /*
+ * Check access. If interactive and file exists, ask user if it
+ * should be replaced. Otherwise if file exists but isn't writable
+ * make sure the user wants to clobber it.
+ */
+ if (!fflg && !access(to, F_OK)) {
+
+ /* prompt only if source exist */
+ if (lstat(from, &sb) == -1) {
+ warn("%s", from);
+ return (1);
+ }
+
+#define YESNO "(y/n [n]) "
+ ask = 0;
+ if (nflg) {
+ if (vflg)
+ printf("%s not overwritten\n", to);
+ return (0);
+ } else if (iflg) {
+ (void)fprintf(stderr, "overwrite %s? %s", to, YESNO);
+ ask = 1;
+ } else if (access(to, W_OK) && !stat(to, &sb)) {
+ strmode(sb.st_mode, modep);
+ (void)fprintf(stderr, "override %s%s%s/%s for %s? %s",
+ modep + 1, modep[9] == ' ' ? "" : " ",
+ user_from_uid(sb.st_uid, 0),
+ group_from_gid(sb.st_gid, 0), to, YESNO);
+ ask = 1;
+ }
+ if (ask) {
+ /* Load user specified locale */
+ setlocale(LC_MESSAGES, "");
+
+ first = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+
+ /* only care about the first character */
+ resp[0] = first;
+
+ if (rpmatch(resp) != 1) {
+ (void)fprintf(stderr, "not overwritten\n");
+ return (0);
+ }
+ }
+ }
+ if (!rename(from, to)) {
+ if (vflg)
+ printf("%s -> %s\n", from, to);
+ return (0);
+ }
+
+ if (errno == EXDEV) {
+ struct statfs sfs;
+ char path[PATH_MAX];
+
+ /* Can't mv(1) a mount point. */
+ if (realpath(from, path) == NULL) {
+ warnx("cannot resolve %s: %s", from, path);
+ return (1);
+ }
+ if (!statfs(path, &sfs) && !strcmp(path, sfs.f_mntonname)) {
+ warnx("cannot rename a mount point");
+ return (1);
+ }
+ } else {
+ warn("rename %s to %s", from, to);
+ return (1);
+ }
+
+ /*
+ * If rename fails because we're trying to cross devices, and
+ * it's a regular file, do the copy internally; otherwise, use
+ * cp and rm.
+ */
+ if (lstat(from, &sb)) {
+ warn("%s", from);
+ return (1);
+ }
+ return (S_ISREG(sb.st_mode) ?
+ fastcopy(from, to, &sb) : copy(from, to));
+}
+
+int
+fastcopy(char *from, char *to, struct stat *sbp)
+{
+ struct timeval tval[2];
+ static u_int blen;
+ static char *bp;
+ mode_t oldmode;
+ ssize_t nread;
+ int from_fd, to_fd;
+
+ if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
+ warn("%s", from);
+ return (1);
+ }
+ if (blen < sbp->st_blksize) {
+ if (bp != NULL)
+ free(bp);
+ if ((bp = malloc((size_t)sbp->st_blksize)) == NULL) {
+ blen = 0;
+ warnx("malloc failed");
+ return (1);
+ }
+ blen = sbp->st_blksize;
+ }
+ while ((to_fd =
+ open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) {
+ if (errno == EEXIST && unlink(to) == 0)
+ continue;
+ warn("%s", to);
+ (void)close(from_fd);
+ return (1);
+ }
+#ifdef __APPLE__
+ {
+ struct statfs sfs;
+
+ /*
+ * Pre-allocate blocks for the destination file if it
+ * resides on Xsan.
+ */
+ if (fstatfs(to_fd, &sfs) == 0 &&
+ strcmp(sfs.f_fstypename, "acfs") == 0) {
+ fstore_t fst;
+
+ fst.fst_flags = 0;
+ fst.fst_posmode = F_PEOFPOSMODE;
+ fst.fst_offset = 0;
+ fst.fst_length = sbp->st_size;
+
+ (void) fcntl(to_fd, F_PREALLOCATE, &fst);
+ }
+ }
+#endif /* __APPLE__ */
+ while ((nread = read(from_fd, bp, (size_t)blen)) > 0)
+ if (write(to_fd, bp, (size_t)nread) != nread) {
+ warn("%s", to);
+ goto err;
+ }
+ if (nread < 0) {
+ warn("%s", from);
+err: if (unlink(to))
+ warn("%s: remove", to);
+ (void)close(from_fd);
+ (void)close(to_fd);
+ return (1);
+ }
+#ifdef __APPLE__
+ /* XATTR can fail if to_fd has mode 000 */
+ if (fcopyfile(from_fd, to_fd, NULL, COPYFILE_ACL | COPYFILE_XATTR) < 0) {
+ warn("%s: unable to move extended attributes and ACL from %s",
+ to, from);
+ }
+#endif
+ (void)close(from_fd);
+
+ oldmode = sbp->st_mode & ALLPERMS;
+ if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
+ warn("%s: set owner/group (was: %lu/%lu)", to,
+ (u_long)sbp->st_uid, (u_long)sbp->st_gid);
+ if (oldmode & (S_ISUID | S_ISGID)) {
+ warnx(
+"%s: owner/group changed; clearing suid/sgid (mode was 0%03o)",
+ to, oldmode);
+ sbp->st_mode &= ~(S_ISUID | S_ISGID);
+ }
+ }
+ if (fchmod(to_fd, sbp->st_mode))
+ warn("%s: set mode (was: 0%03o)", to, oldmode);
+ /*
+ * XXX
+ * NFS doesn't support chflags; ignore errors unless there's reason
+ * to believe we're losing bits. (Note, this still won't be right
+ * if the server supports flags and we were trying to *remove* flags
+ * on a file that we copied, i.e., that we didn't create.)
+ */
+ errno = 0;
+ if (fchflags(to_fd, (u_int)sbp->st_flags))
+ if (errno != ENOTSUP || sbp->st_flags != 0)
+ warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);
+
+ tval[0].tv_sec = sbp->st_atime;
+ tval[1].tv_sec = sbp->st_mtime;
+ tval[0].tv_usec = tval[1].tv_usec = 0;
+ if (utimes(to, tval))
+ warn("%s: set times", to);
+
+ if (close(to_fd)) {
+ warn("%s", to);
+ return (1);
+ }
+
+ if (unlink(from)) {
+ warn("%s: remove", from);
+ return (1);
+ }
+ if (vflg)
+ printf("%s -> %s\n", from, to);
+ return (0);
+}
+
+int
+copy(char *from, char *to)
+{
+ int pid, status;
+
+ /* posix_spawn cp from to && rm from */
+
+ if ((pid = fork()) == 0) {
+ execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to,
+ (char *)NULL);
+ warn("%s", _PATH_CP);
+ _exit(1);
+ }
+ if (waitpid(pid, &status, 0) == -1) {
+ warn("%s: waitpid", _PATH_CP);
+ return (1);
+ }
+ if (!WIFEXITED(status)) {
+ warnx("%s: did not terminate normally", _PATH_CP);
+ return (1);
+ }
+ if (WEXITSTATUS(status)) {
+ warnx("%s: terminated with %d (non-zero) status",
+ _PATH_CP, WEXITSTATUS(status));
+ return (1);
+ }
+ if (!(pid = vfork())) {
+ execl(_PATH_RM, "mv", "-rf", "--", from, (char *)NULL);
+ warn("%s", _PATH_RM);
+ _exit(1);
+ }
+ if (waitpid(pid, &status, 0) == -1) {
+ warn("%s: waitpid", _PATH_RM);
+ return (1);
+ }
+ if (!WIFEXITED(status)) {
+ warnx("%s: did not terminate normally", _PATH_RM);
+ return (1);
+ }
+ if (WEXITSTATUS(status)) {
+ warnx("%s: terminated with %d (non-zero) status",
+ _PATH_RM, WEXITSTATUS(status));
+ return (1);
+ }
+ return (0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "%s\n%s\n",
+ "usage: mv [-f | -i | -n] [-v] source target",
+ " mv [-f | -i | -n] [-v] source ... directory");
+ exit(EX_USAGE);
+}
diff --git a/file_cmds/mv/pathnames.h b/file_cmds/mv/pathnames.h
new file mode 100644
index 0000000..fe1d6cd
--- /dev/null
+++ b/file_cmds/mv/pathnames.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD: src/bin/mv/pathnames.h,v 1.6 2002/05/17 11:38:48 jmallett Exp $
+ */
+
+#ifndef _MV_PATHNAMES_H_
+#define _MV_PATHNAMES_H_
+
+#define _PATH_RM "/bin/rm"
+#ifdef __APPLE__
+#define _PATH_CP "/bin/cp"
+#endif /* __APPLE__ */
+
+#endif /* _MV_PATHNAMES_H_ */
diff --git a/file_cmds/pathchk/pathchk.1 b/file_cmds/pathchk/pathchk.1
new file mode 100644
index 0000000..efe2a05
--- /dev/null
+++ b/file_cmds/pathchk/pathchk.1
@@ -0,0 +1,121 @@
+.\" Copyright (c) 2001, 2002 Chuck Rouillard
+.\" 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. 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.
+.\"
+.\" $FreeBSD: src/usr.bin/pathchk/pathchk.1,v 1.3 2002/12/12 17:26:01 ru Exp $
+.\"
+.Dd May 21, 2002
+.Dt PATHCHK 1
+.Os
+.Sh NAME
+.Nm pathchk
+.Nd check pathnames
+.Sh SYNOPSIS
+.Nm
+.Op Fl p
+.Ar pathname ...
+.Sh DESCRIPTION
+The
+.Nm
+utility checks whether each of the specified
+.Ar pathname
+arguments is valid or portable.
+.Pp
+A diagnostic message is written for each argument that:
+.Bl -bullet
+.It
+Is longer than
+.Dv PATH_MAX
+bytes.
+.It
+Contains any component longer than
+.Dv NAME_MAX
+bytes.
+(The value of
+.Dv NAME_MAX
+depends on the underlying file system.)
+.It
+Contains a directory component that is not searchable.
+.El
+.Pp
+It is not considered an error if a
+.Ar pathname
+argument contains a nonexistent component as long as a component by that
+name could be created.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl p
+Perform portability checks on the specified
+.Ar pathname
+arguments.
+Diagnostic messages will be written for each argument that:
+.Bl -bullet
+.It
+Is longer than
+.Dv _POSIX_PATH_MAX
+.Pq 255
+bytes.
+.It
+Contains a component longer than
+.Dv _POSIX_NAME_MAX
+.Pq 14
+bytes.
+.It
+Contains any character not in the portable filename character set (that is,
+alphanumeric characters,
+.Ql \&. ,
+.Ql \&-
+and
+.Ql _ ) .
+No component may start with the hyphen
+.Pq Ql \&-
+character.
+.El
+.El
+.Sh EXAMPLES
+Check whether the names of files in the current directory are portable to
+other
+.Tn POSIX
+systems:
+.Pp
+.Dl "find . -print | xargs pathchk -p"
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr getconf 1 ,
+.Xr pathconf 2 ,
+.Xr stat 2
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.Fx 5.0 .
diff --git a/file_cmds/pathchk/pathchk.c b/file_cmds/pathchk/pathchk.c
new file mode 100644
index 0000000..233a6d0
--- /dev/null
+++ b/file_cmds/pathchk/pathchk.c
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * 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.
+ */
+
+/*
+ * pathchk -- check pathnames
+ *
+ * Check whether files could be created with the names specified on the
+ * command line. If -p is specified, check whether the pathname is portable
+ * to all POSIX systems.
+ */
+
+#include <sys/cdefs.h>
+
+/* Commenting __FBSDID, as it is not needed n OSX ......
+__FBSDID("$FreeBSD: src/usr.bin/pathchk/pathchk.c,v 1.4 2002/12/15 00:40:47 tjr Exp $");
+*/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int check(const char *);
+static int portable(const char *);
+static void usage(void);
+
+static int pflag; /* Perform portability checks */
+
+int
+main(int argc, char *argv[])
+{
+ int ch, rval;
+ const char *arg;
+
+ while ((ch = getopt(argc, argv, "p")) > 0) {
+ switch (ch) {
+ case 'p':
+ pflag = 1;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ rval = 0;
+ while ((arg = *argv++) != NULL)
+ rval |= check(arg);
+
+ exit(rval);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: pathchk [-p] pathname...\n");
+ exit(1);
+}
+
+static int
+check(const char *path)
+{
+ struct stat sb;
+ long complen, namemax, pathmax, svnamemax;
+ int badch, last;
+ char *end, *p, *pathd;
+
+ if ((pathd = strdup(path)) == NULL)
+ err(1, "strdup");
+
+ p = pathd;
+
+ if (!pflag) {
+ errno = 0;
+ namemax = pathconf(*p == '/' ? "/" : ".", _PC_NAME_MAX);
+ if (namemax == -1 && errno != 0)
+ namemax = NAME_MAX;
+ } else
+ namemax = _POSIX_NAME_MAX;
+
+ for (;;) {
+ p += strspn(p, "/");
+ complen = (long)strcspn(p, "/");
+ end = p + complen;
+ last = *end == '\0';
+ *end = '\0';
+
+ if (namemax != -1 && complen > namemax) {
+ warnx("%s: %s: component too long (limit %ld)", path,
+ p, namemax);
+ goto bad;
+ }
+
+ if (!pflag && stat(pathd, &sb) == -1 && errno != ENOENT) {
+ warn("%s: %.*s", path, (int)(strlen(pathd) -
+ complen - 1), pathd);
+ goto bad;
+ }
+
+ if (pflag && (badch = portable(p)) >= 0) {
+ warnx("%s: %s: component contains non-portable "
+ "character `%c'", path, p, badch);
+ goto bad;
+ }
+
+ if (last)
+ break;
+
+ if (!pflag) {
+ errno = 0;
+ svnamemax = namemax;
+ namemax = pathconf(pathd, _PC_NAME_MAX);
+ if (namemax == -1 && errno != 0)
+ namemax = svnamemax;
+ }
+
+ *end = '/';
+ p = end + 1;
+ }
+
+ if (!pflag) {
+ errno = 0;
+ pathmax = pathconf(path, _PC_PATH_MAX);
+ if (pathmax == -1 && errno != 0)
+ pathmax = PATH_MAX;
+ } else
+ pathmax = _POSIX_PATH_MAX;
+ if (pathmax != -1 && strlen(path) >= (size_t)pathmax) {
+ warnx("%s: path too long (limit %ld)", path, pathmax - 1);
+ goto bad;
+ }
+
+ free(pathd);
+ return (0);
+
+bad: free(pathd);
+ return (1);
+}
+
+/*
+ * Check whether a path component contains only portable characters. Return
+ * the first non-portable character found.
+ */
+static int
+portable(const char *path)
+{
+ static const char charset[] =
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "0123456789._-";
+ long s;
+
+ if (*path == '-')
+ return (*path);
+
+ s = strspn(path, charset);
+ if (path[s] != '\0')
+ return (path[s]);
+
+ return (-1);
+}
diff --git a/file_cmds/pax/ar_io.c b/file_cmds/pax/ar_io.c
new file mode 100644
index 0000000..1c4b943
--- /dev/null
+++ b/file_cmds/pax/ar_io.c
@@ -0,0 +1,1318 @@
+/* $OpenBSD: ar_io.c,v 1.38 2008/06/11 00:49:08 pvalchev Exp $ */
+/* $NetBSD: ar_io.c,v 1.5 1996/03/26 23:54:13 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)ar_io.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: ar_io.c,v 1.38 2008/06/11 00:49:08 pvalchev Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#ifndef __APPLE__
+#include <sys/mtio.h>
+#endif /* !__APPLE__ */
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <err.h>
+#include <stdint.h>
+#include "pax.h"
+#include "options.h"
+#include "extern.h"
+
+/*
+ * Routines which deal directly with the archive I/O device/file.
+ */
+
+#define DMOD 0666 /* default mode of created archives */
+#define EXT_MODE O_RDONLY /* open mode for list/extract */
+#define AR_MODE (O_WRONLY | O_CREAT | O_TRUNC) /* mode for archive */
+#define APP_MODE O_RDWR /* mode for append */
+#define STDO "<STDOUT>" /* pseudo name for stdout */
+#define STDN "<STDIN>" /* pseudo name for stdin */
+#define _NONE "<NONE>" /* pseudo name for no files */
+static int arfd = -1; /* archive file descriptor */
+static int artyp = ISREG; /* archive type: file/FIFO/tape */
+static int arvol = 1; /* archive volume number */
+static int lstrval = -1; /* return value from last i/o */
+static int io_ok; /* i/o worked on volume after resync */
+static int did_io; /* did i/o ever occur on volume? */
+static int done; /* set via tty termination */
+static struct stat arsb; /* stat of archive device at open */
+static int invld_rec; /* tape has out of spec record size */
+static int wr_trail = 1; /* trailer was rewritten in append */
+static int can_unlnk = 0; /* do we unlink null archives? */
+const char *arcname; /* printable name of archive */
+const char *gzip_program; /* name of gzip program */
+static pid_t zpid = -1; /* pid of child process */
+int force_one_volume; /* 1 if we ignore volume changes */
+
+#ifndef __APPLE__
+static int get_phys(void);
+#endif /* __APPLE__ */
+extern sigset_t s_mask;
+static void ar_start_gzip(int, const char *, int);
+
+/*
+ * ar_open()
+ * Opens the next archive volume. Determines the type of the device and
+ * sets up block sizes as required by the archive device and the format.
+ * Note: we may be called with name == NULL on the first open only.
+ * Return:
+ * -1 on failure, 0 otherwise
+ */
+
+int
+ar_open(const char *name)
+{
+#ifndef __APPLE__
+ struct mtget mb;
+#endif /* __APPLE__ */
+ if (arfd != -1)
+ (void)close(arfd);
+ arfd = -1;
+ can_unlnk = did_io = io_ok = invld_rec = 0;
+ artyp = ISREG;
+ flcnt = 0;
+
+ /*
+ * open based on overall operation mode
+ */
+ switch (act) {
+ case LIST:
+ case EXTRACT:
+ if (name == NULL) {
+ arfd = STDIN_FILENO;
+ arcname = STDN;
+ } else if ((arfd = open(name, EXT_MODE, DMOD)) < 0)
+ syswarn(1, errno, "Failed open to read on %s", name);
+ if (arfd != -1 && gzip_program != NULL)
+ ar_start_gzip(arfd, gzip_program, 0);
+ break;
+ case ARCHIVE:
+ if (name == NULL) {
+ arfd = STDOUT_FILENO;
+ arcname = STDO;
+ } else if ((arfd = open(name, AR_MODE, DMOD)) < 0)
+ syswarn(1, errno, "Failed open to write on %s", name);
+ else
+ can_unlnk = 1;
+ if (arfd != -1 && gzip_program != NULL)
+ ar_start_gzip(arfd, gzip_program, 1);
+ break;
+ case APPND:
+ if (name == NULL) {
+ arfd = STDOUT_FILENO;
+ arcname = STDO;
+ } else if ((arfd = open(name, APP_MODE, DMOD)) < 0)
+ syswarn(1, errno, "Failed open to read/write on %s",
+ name);
+ break;
+ case COPY:
+ /*
+ * arfd not used in COPY mode
+ */
+ arcname = _NONE;
+ lstrval = 1;
+ return(0);
+ }
+ if (arfd < 0)
+ return(-1);
+
+ if (chdname != NULL)
+ if (dochdir(chdname) == -1) {
+ return(-1);
+ }
+ /*
+ * set up is based on device type
+ */
+ if (fstat(arfd, &arsb) < 0) {
+ syswarn(0, errno, "Failed stat on %s", arcname);
+ (void)close(arfd);
+ arfd = -1;
+ can_unlnk = 0;
+ return(-1);
+ }
+ if (S_ISDIR(arsb.st_mode)) {
+ paxwarn(0, "Cannot write an archive on top of a directory %s",
+ arcname);
+ (void)close(arfd);
+ arfd = -1;
+ can_unlnk = 0;
+ return(-1);
+ }
+
+#ifndef __APPLE__
+ if (S_ISCHR(arsb.st_mode))
+ artyp = ioctl(arfd, MTIOCGET, &mb) ? ISCHR : ISTAPE;
+ else
+#endif /* !__APPLE__ */
+ if (S_ISBLK(arsb.st_mode))
+ artyp = ISBLK;
+ else if ((lseek(arfd, (off_t)0L, SEEK_CUR) == -1) && (errno == ESPIPE))
+ artyp = ISPIPE;
+ else
+ artyp = ISREG;
+
+ /*
+ * make sure we beyond any doubt that we only can unlink regular files
+ * we created
+ */
+ if (artyp != ISREG)
+ can_unlnk = 0;
+ /*
+ * if we are writing, we are done
+ */
+ if (act == ARCHIVE) {
+ blksz = rdblksz = wrblksz;
+ lstrval = 1;
+ return(0);
+ }
+
+ /*
+ * set default blksz on read. APPNDs writes rdblksz on the last volume
+ * On all new archive volumes, we shift to wrblksz (if the user
+ * specified one, otherwise we will continue to use rdblksz). We
+ * must set blocksize based on what kind of device the archive is
+ * stored.
+ */
+ switch (artyp) {
+ case ISTAPE:
+ /*
+ * Tape drives come in at least two flavors. Those that support
+ * variable sized records and those that have fixed sized
+ * records. They must be treated differently. For tape drives
+ * that support variable sized records, we must make large
+ * reads to make sure we get the entire record, otherwise we
+ * will just get the first part of the record (up to size we
+ * asked). Tapes with fixed sized records may or may not return
+ * multiple records in a single read. We really do not care
+ * what the physical record size is UNLESS we are going to
+ * append. (We will need the physical block size to rewrite
+ * the trailer). Only when we are appending do we go to the
+ * effort to figure out the true PHYSICAL record size.
+ */
+ blksz = rdblksz = MAXBLK;
+ break;
+ case ISPIPE:
+ case ISBLK:
+ case ISCHR:
+ /*
+ * Blocksize is not a major issue with these devices (but must
+ * be kept a multiple of 512). If the user specified a write
+ * block size, we use that to read. Under append, we must
+ * always keep blksz == rdblksz. Otherwise we go ahead and use
+ * the device optimal blocksize as (and if) returned by stat
+ * and if it is within pax specs.
+ */
+ if ((act == APPND) && wrblksz) {
+ blksz = rdblksz = wrblksz;
+ break;
+ }
+
+ if ((arsb.st_blksize > 0) && (arsb.st_blksize < MAXBLK) &&
+ ((arsb.st_blksize % BLKMULT) == 0))
+ rdblksz = arsb.st_blksize;
+ else
+ rdblksz = DEVBLK;
+ /*
+ * For performance go for large reads when we can without harm
+ */
+ if ((act == APPND) || (artyp == ISCHR))
+ blksz = rdblksz;
+ else
+ blksz = MAXBLK;
+ break;
+ case ISREG:
+ /*
+ * if the user specified wrblksz works, use it. Under appends
+ * we must always keep blksz == rdblksz
+ */
+ if ((act == APPND) && wrblksz && ((arsb.st_size%wrblksz)==0)){
+ blksz = rdblksz = wrblksz;
+ break;
+ }
+ /*
+ * See if we can find the blocking factor from the file size
+ */
+ for (rdblksz = MAXBLK; rdblksz > 0; rdblksz -= BLKMULT)
+ if ((arsb.st_size % rdblksz) == 0)
+ break;
+ /*
+ * When we cannot find a match, we may have a flawed archive.
+ */
+ if (rdblksz <= 0)
+ rdblksz = FILEBLK;
+ /*
+ * for performance go for large reads when we can
+ */
+ if (act == APPND)
+ blksz = rdblksz;
+ else
+ blksz = MAXBLK;
+ break;
+ default:
+ /*
+ * should never happen, worst case, slow...
+ */
+ blksz = rdblksz = BLKMULT;
+ break;
+ }
+ lstrval = 1;
+ return(0);
+}
+
+/*
+ * ar_close()
+ * closes archive device, increments volume number, and prints i/o summary
+ */
+void
+ar_close(void)
+{
+ int status;
+
+ if (arfd < 0) {
+ did_io = io_ok = flcnt = 0;
+ return;
+ }
+
+ /*
+ * Close archive file. This may take a LONG while on tapes (we may be
+ * forced to wait for the rewind to complete) so tell the user what is
+ * going on (this avoids the user hitting control-c thinking pax is
+ * broken).
+ */
+ if (vflag && (artyp == ISTAPE)) {
+ if (vfpart)
+ (void)putc('\n', listf);
+ (void)fprintf(listf,
+ "%s: Waiting for tape drive close to complete...",
+ argv0);
+ (void)fflush(listf);
+ }
+
+ /*
+ * if nothing was written to the archive (and we created it), we remove
+ * it
+ */
+ if (can_unlnk && (fstat(arfd, &arsb) == 0) && (S_ISREG(arsb.st_mode)) &&
+ (arsb.st_size == 0)) {
+ (void)unlink(arcname);
+ can_unlnk = 0;
+ }
+
+ /*
+ * for a quick extract/list, pax frequently exits before the child
+ * process is done
+ */
+ if ((act == LIST || act == EXTRACT) && nflag && zpid > 0)
+ kill(zpid, SIGINT);
+
+ (void)close(arfd);
+
+ /* Do not exit before child to ensure data integrity */
+ if (zpid > 0)
+ waitpid(zpid, &status, 0);
+
+ if (vflag && (artyp == ISTAPE)) {
+ (void)fputs("done.\n", listf);
+ vfpart = 0;
+ (void)fflush(listf);
+ }
+ arfd = -1;
+
+ if (!io_ok && !did_io) {
+ flcnt = 0;
+ return;
+ }
+ did_io = io_ok = 0;
+
+ /*
+ * The volume number is only increased when the last device has data
+ * and we have already determined the archive format.
+ */
+ if (frmt != NULL)
+ ++arvol;
+
+ if (!vflag) {
+ flcnt = 0;
+ return;
+ }
+
+ /*
+ * Print out a summary of I/O for this archive volume.
+ */
+ if (vfpart) {
+ (void)putc('\n', listf);
+ vfpart = 0;
+ }
+
+ /*
+ * If we have not determined the format yet, we just say how many bytes
+ * we have skipped over looking for a header to id. there is no way we
+ * could have written anything yet.
+ */
+ if (frmt == NULL) {
+# ifdef LONG_OFF_T
+ (void)fprintf(listf, "%s: unknown format, %lu bytes skipped.\n",
+# else
+ (void)fprintf(listf, "%s: unknown format, %qu bytes skipped.\n",
+# endif
+ argv0, rdcnt);
+ (void)fflush(listf);
+ flcnt = 0;
+ return;
+ }
+
+ if (strcmp(NM_CPIO, argv0) == 0)
+ (void)fprintf(listf, "%qu blocks\n", (rdcnt ? rdcnt : wrcnt) / 5120);
+ else if (strcmp(NM_TAR, argv0) != 0 && strcmp(NM_PAX, argv0) != 0)
+ (void)fprintf(listf,
+# ifdef LONG_OFF_T
+ "%s: %s vol %d, %lu files, %lu bytes read, %lu bytes written.\n",
+ argv0, frmt->name, arvol-1, flcnt, rdcnt, wrcnt);
+# else
+ "%s: %s vol %d, %lu files, %ju bytes read, %ju bytes written.\n",
+ argv0, frmt->name, arvol-1, flcnt, (uintmax_t)rdcnt, (uintmax_t)wrcnt);
+# endif
+ (void)fflush(listf);
+ flcnt = 0;
+}
+
+/*
+ * ar_drain()
+ * drain any archive format independent padding from an archive read
+ * from a socket or a pipe. This is to prevent the process on the
+ * other side of the pipe from getting a SIGPIPE (pax will stop
+ * reading an archive once a format dependent trailer is detected).
+ */
+void
+ar_drain(void)
+{
+ int res;
+ char drbuf[MAXBLK];
+
+ /*
+ * we only drain from a pipe/socket. Other devices can be closed
+ * without reading up to end of file. We sure hope that pipe is closed
+ * on the other side so we will get an EOF.
+ */
+ if ((artyp != ISPIPE) || (lstrval <= 0))
+ return;
+
+ /*
+ * keep reading until pipe is drained
+ */
+ while ((res = read(arfd, drbuf, sizeof(drbuf))) > 0)
+ ;
+ lstrval = res;
+}
+
+/*
+ * ar_set_wr()
+ * Set up device right before switching from read to write in an append.
+ * device dependent code (if required) to do this should be added here.
+ * For all archive devices we are already positioned at the place we want
+ * to start writing when this routine is called.
+ * Return:
+ * 0 if all ready to write, -1 otherwise
+ */
+
+int
+ar_set_wr(void)
+{
+ off_t cpos;
+
+ /*
+ * we must make sure the trailer is rewritten on append, ar_next()
+ * will stop us if the archive containing the trailer was not written
+ */
+ wr_trail = 0;
+
+ /*
+ * Add any device dependent code as required here
+ */
+ if (artyp != ISREG)
+ return(0);
+ /*
+ * Ok we have an archive in a regular file. If we were rewriting a
+ * file, we must get rid of all the stuff after the current offset
+ * (it was not written by pax).
+ */
+ if (((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) ||
+ (ftruncate(arfd, cpos) < 0)) {
+ syswarn(1, errno, "Unable to truncate archive file");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * ar_app_ok()
+ * check if the last volume in the archive allows appends. We cannot check
+ * this until we are ready to write since there is no spec that says all
+ * volumes in a single archive have to be of the same type...
+ * Return:
+ * 0 if we can append, -1 otherwise.
+ */
+
+int
+ar_app_ok(void)
+{
+ if (artyp == ISPIPE) {
+ paxwarn(1, "Cannot append to an archive obtained from a pipe.");
+ return(-1);
+ }
+
+ if (!invld_rec)
+ return(0);
+ paxwarn(1,"Cannot append, device record size %d does not support %s spec",
+ rdblksz, argv0);
+ return(-1);
+}
+
+/*
+ * ar_read()
+ * read up to a specified number of bytes from the archive into the
+ * supplied buffer. When dealing with tapes we may not always be able to
+ * read what we want.
+ * Return:
+ * Number of bytes in buffer. 0 for end of file, -1 for a read error.
+ */
+
+int
+ar_read(char *buf, int cnt)
+{
+ int res = 0;
+
+ /*
+ * if last i/o was in error, no more reads until reset or new volume
+ */
+ if (lstrval <= 0)
+ return(lstrval);
+
+ /*
+ * how we read must be based on device type
+ */
+ switch (artyp) {
+ case ISTAPE:
+ if ((res = read(arfd, buf, cnt)) > 0) {
+ /*
+ * CAUTION: tape systems may not always return the same
+ * sized records so we leave blksz == MAXBLK. The
+ * physical record size that a tape drive supports is
+ * very hard to determine in a uniform and portable
+ * manner.
+ */
+ io_ok = 1;
+ if (res != rdblksz) {
+ /*
+ * Record size changed. If this happens on
+ * any record after the first, we probably have
+ * a tape drive which has a fixed record size
+ * (we are getting multiple records in a single
+ * read). Watch out for record blocking that
+ * violates pax spec (must be a multiple of
+ * BLKMULT).
+ */
+ rdblksz = res;
+ if (rdblksz % BLKMULT)
+ invld_rec = 1;
+ }
+ return(res);
+ }
+ break;
+ case ISREG:
+ case ISBLK:
+ case ISCHR:
+ case ISPIPE:
+ default:
+ /*
+ * Files are so easy to deal with. These other things cannot
+ * be trusted at all. So when we are dealing with character
+ * devices and pipes we just take what they have ready for us
+ * and return. Trying to do anything else with them runs the
+ * risk of failure.
+ */
+ if ((res = read(arfd, buf, cnt)) > 0) {
+ io_ok = 1;
+ return(res);
+ }
+ break;
+ }
+
+ /*
+ * We are in trouble at this point, something is broken...
+ */
+ lstrval = res;
+ if (res < 0)
+ syswarn(1, errno, "Failed read on archive volume %d", arvol);
+ else
+ paxwarn(0, "End of archive volume %d reached", arvol);
+ return(res);
+}
+
+/*
+ * ar_write()
+ * Write a specified number of bytes in supplied buffer to the archive
+ * device so it appears as a single "block". Deals with errors and tries
+ * to recover when faced with short writes.
+ * Return:
+ * Number of bytes written. 0 indicates end of volume reached and with no
+ * flaws (as best that can be detected). A -1 indicates an unrecoverable
+ * error in the archive occurred.
+ */
+
+int
+ar_write(char *buf, int bsz)
+{
+ int res;
+ off_t cpos;
+
+ /*
+ * do not allow pax to create a "bad" archive. Once a write fails on
+ * an archive volume prevent further writes to it.
+ */
+ if (lstrval <= 0)
+ return(lstrval);
+
+ if ((res = write(arfd, buf, bsz)) == bsz) {
+ wr_trail = 1;
+ io_ok = 1;
+ return(bsz);
+ } else if (res < 0 && artyp == ISPIPE && errno == EPIPE) { /* ignore it */
+ wr_trail = 1;
+ io_ok = 1;
+ errno = 0;
+ arfd = open("/dev/null", AR_MODE, DMOD);
+ artyp = ISREG;
+ return bsz;
+ }
+
+ /*
+ * write broke, see what we can do with it. We try to send any partial
+ * writes that may violate pax spec to the next archive volume.
+ */
+ if (res < 0)
+ lstrval = res;
+ else
+ lstrval = 0;
+
+ switch (artyp) {
+ case ISREG:
+ if ((res > 0) && (res % BLKMULT)) {
+ /*
+ * try to fix up partial writes which are not BLKMULT
+ * in size by forcing the runt record to next archive
+ * volume
+ */
+ if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0)
+ break;
+ cpos -= (off_t)res;
+ if (ftruncate(arfd, cpos) < 0)
+ break;
+ res = lstrval = 0;
+ break;
+ }
+ if (res >= 0)
+ break;
+ /*
+ * if file is out of space, handle it like a return of 0
+ */
+ if ((errno == ENOSPC) || (errno == EFBIG) || (errno == EDQUOT))
+ res = lstrval = 0;
+ break;
+ case ISTAPE:
+ case ISCHR:
+ case ISBLK:
+ if (res >= 0)
+ break;
+ if (errno == EACCES) {
+ paxwarn(0, "Write failed, archive is write protected.");
+ lstrval = 0;
+ return(0);
+ }
+ /*
+ * see if we reached the end of media, if so force a change to
+ * the next volume
+ */
+ if ((errno == ENOSPC) || (errno == EIO) || (errno == ENXIO))
+ res = lstrval = 0;
+ break;
+ case ISPIPE:
+ default:
+ /*
+ * we cannot fix errors to these devices
+ */
+ break;
+ }
+
+ /*
+ * Better tell the user the bad news...
+ * if this is a block aligned archive format, we may have a bad archive
+ * if the format wants the header to start at a BLKMULT boundary.. While
+ * we can deal with the mis-aligned data, it violates spec and other
+ * archive readers will likely fail. if the format is not block
+ * aligned, the user may be lucky (and the archive is ok).
+ */
+ if (res >= 0) {
+ if (res > 0)
+ wr_trail = 1;
+ io_ok = 1;
+ }
+
+ /*
+ * If we were trying to rewrite the trailer and it didn't work, we
+ * must quit right away.
+ */
+ if (!wr_trail && (res <= 0)) {
+ paxwarn(1,"Unable to append, trailer re-write failed. Quitting.");
+ return(res);
+ }
+
+ if (res == 0)
+ paxwarn(0, "End of archive volume %d reached", arvol);
+ else if (res < 0)
+ syswarn(1, errno, "Failed write to archive volume: %d", arvol);
+ else if (!frmt->blkalgn || ((res % frmt->blkalgn) == 0))
+ paxwarn(0,"WARNING: partial archive write. Archive MAY BE FLAWED");
+ else
+ paxwarn(1,"WARNING: partial archive write. Archive IS FLAWED");
+ return(res);
+}
+
+/*
+ * ar_rdsync()
+ * Try to move past a bad spot on a flawed archive as needed to continue
+ * I/O. Clears error flags to allow I/O to continue.
+ * Return:
+ * 0 when ok to try i/o again, -1 otherwise.
+ */
+
+int
+ar_rdsync(void)
+{
+ long fsbz;
+ off_t cpos;
+ off_t mpos;
+#ifndef __APPLE__
+ struct mtop mb;
+#endif /* !__APPLE__ */
+
+ /*
+ * Fail resync attempts at user request (done) or if this is going to be
+ * an update/append to a existing archive. if last i/o hit media end,
+ * we need to go to the next volume not try a resync
+ */
+ if ((done > 0) || (lstrval == 0))
+ return(-1);
+
+ if ((act == APPND) || (act == ARCHIVE)) {
+ paxwarn(1, "Cannot allow updates to an archive with flaws.");
+ return(-1);
+ }
+ if (io_ok)
+ did_io = 1;
+
+ switch (artyp) {
+#ifndef __APPLE__
+ case ISTAPE:
+ /*
+ * if the last i/o was a successful data transfer, we assume
+ * the fault is just a bad record on the tape that we are now
+ * past. If we did not get any data since the last resync try
+ * to move the tape forward one PHYSICAL record past any
+ * damaged tape section. Some tape drives are stubborn and need
+ * to be pushed.
+ */
+ if (io_ok) {
+ io_ok = 0;
+ lstrval = 1;
+ break;
+ }
+ mb.mt_op = MTFSR;
+ mb.mt_count = 1;
+ if (ioctl(arfd, MTIOCTOP, &mb) < 0)
+ break;
+ lstrval = 1;
+ break;
+#endif /* !__APPLE__ */
+ case ISREG:
+ case ISCHR:
+ case ISBLK:
+ /*
+ * try to step over the bad part of the device.
+ */
+ io_ok = 0;
+ if (((fsbz = arsb.st_blksize) <= 0) || (artyp != ISREG))
+ fsbz = BLKMULT;
+ if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0)
+ break;
+ mpos = fsbz - (cpos % (off_t)fsbz);
+ if (lseek(arfd, mpos, SEEK_CUR) < 0)
+ break;
+ lstrval = 1;
+ break;
+ case ISPIPE:
+ default:
+ /*
+ * cannot recover on these archive device types
+ */
+ io_ok = 0;
+ break;
+ }
+ if (lstrval <= 0) {
+ paxwarn(1, "Unable to recover from an archive read failure.");
+ return(-1);
+ }
+ paxwarn(0, "Attempting to recover from an archive read failure.");
+ return(0);
+}
+
+/*
+ * ar_fow()
+ * Move the I/O position within the archive forward the specified number of
+ * bytes as supported by the device. If we cannot move the requested
+ * number of bytes, return the actual number of bytes moved in skipped.
+ * Return:
+ * 0 if moved the requested distance, -1 on complete failure, 1 on
+ * partial move (the amount moved is in skipped)
+ */
+
+int
+ar_fow(off_t sksz, off_t *skipped)
+{
+ off_t cpos;
+ off_t mpos;
+
+ *skipped = 0;
+ if (sksz <= 0)
+ return(0);
+
+ /*
+ * we cannot move forward at EOF or error
+ */
+ if (lstrval <= 0)
+ return(lstrval);
+
+ /*
+ * Safer to read forward on devices where it is hard to find the end of
+ * the media without reading to it. With tapes we cannot be sure of the
+ * number of physical blocks to skip (we do not know physical block
+ * size at this point), so we must only read forward on tapes!
+ */
+ if (artyp != ISREG)
+ return(0);
+
+ /*
+ * figure out where we are in the archive
+ */
+ if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) >= 0) {
+ /*
+ * we can be asked to move farther than there are bytes in this
+ * volume, if so, just go to file end and let normal buf_fill()
+ * deal with the end of file (it will go to next volume by
+ * itself)
+ */
+ if ((mpos = cpos + sksz) > arsb.st_size) {
+ *skipped = arsb.st_size - cpos;
+ mpos = arsb.st_size;
+ } else
+ *skipped = sksz;
+ if (lseek(arfd, mpos, SEEK_SET) >= 0)
+ return(0);
+ }
+ syswarn(1, errno, "Forward positioning operation on archive failed");
+ lstrval = -1;
+ return(-1);
+}
+
+/*
+ * ar_rev()
+ * move the i/o position within the archive backwards the specified byte
+ * count as supported by the device. With tapes drives we RESET rdblksz to
+ * the PHYSICAL blocksize.
+ * NOTE: We should only be called to move backwards so we can rewrite the
+ * last records (the trailer) of an archive (APPEND).
+ * Return:
+ * 0 if moved the requested distance, -1 on complete failure
+ */
+
+int
+ar_rev(off_t sksz)
+{
+ off_t cpos;
+#ifndef __APPLE__
+ struct mtop mb;
+ int phyblk;
+#endif /* __APPLE__ */
+
+ /*
+ * make sure we do not have try to reverse on a flawed archive
+ */
+ if (lstrval < 0)
+ return(lstrval);
+
+ switch (artyp) {
+ case ISPIPE:
+ if (sksz <= 0)
+ break;
+ /*
+ * cannot go backwards on these critters
+ */
+ paxwarn(1, "Reverse positioning on pipes is not supported.");
+ lstrval = -1;
+ return(-1);
+ case ISREG:
+ case ISBLK:
+ case ISCHR:
+ default:
+ if (sksz <= 0)
+ break;
+
+ /*
+ * For things other than files, backwards movement has a very
+ * high probability of failure as we really do not know the
+ * true attributes of the device we are talking to (the device
+ * may not even have the ability to lseek() in any direction).
+ * First we figure out where we are in the archive.
+ */
+ if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) {
+ syswarn(1, errno,
+ "Unable to obtain current archive byte offset");
+ lstrval = -1;
+ return(-1);
+ }
+
+ /*
+ * we may try to go backwards past the start when the archive
+ * is only a single record. If this happens and we are on a
+ * multi-volume archive, we need to go to the end of the
+ * previous volume and continue our movement backwards from
+ * there.
+ */
+ if ((cpos -= sksz) < (off_t)0L) {
+ if (arvol > 1) {
+ /*
+ * this should never happen
+ */
+ paxwarn(1,"Reverse position on previous volume.");
+ lstrval = -1;
+ return(-1);
+ }
+ cpos = (off_t)0L;
+ }
+ if (lseek(arfd, cpos, SEEK_SET) < 0) {
+ syswarn(1, errno, "Unable to seek archive backwards");
+ lstrval = -1;
+ return(-1);
+ }
+ break;
+#ifndef __APPLE__
+ case ISTAPE:
+ /*
+ * Calculate and move the proper number of PHYSICAL tape
+ * blocks. If the sksz is not an even multiple of the physical
+ * tape size, we cannot do the move (this should never happen).
+ * (We also cannot handle trailers spread over two vols.)
+ * get_phys() also makes sure we are in front of the filemark.
+ */
+ if ((phyblk = get_phys()) <= 0) {
+ lstrval = -1;
+ return(-1);
+ }
+
+ /*
+ * make sure future tape reads only go by physical tape block
+ * size (set rdblksz to the real size).
+ */
+ rdblksz = phyblk;
+
+ /*
+ * if no movement is required, just return (we must be after
+ * get_phys() so the physical blocksize is properly set)
+ */
+ if (sksz <= 0)
+ break;
+
+ /*
+ * ok we have to move. Make sure the tape drive can do it.
+ */
+ if (sksz % phyblk) {
+ paxwarn(1,
+ "Tape drive unable to backspace requested amount");
+ lstrval = -1;
+ return(-1);
+ }
+
+ /*
+ * move backwards the requested number of bytes
+ */
+ mb.mt_op = MTBSR;
+ mb.mt_count = sksz/phyblk;
+ if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+ syswarn(1,errno, "Unable to backspace tape %d blocks.",
+ mb.mt_count);
+ lstrval = -1;
+ return(-1);
+ }
+ break;
+#endif /* !__APPLE__ */
+ }
+ lstrval = 1;
+ return(0);
+}
+#ifndef __APPLE__
+/*
+ * get_phys()
+ * Determine the physical block size on a tape drive. We need the physical
+ * block size so we know how many bytes we skip over when we move with
+ * mtio commands. We also make sure we are BEFORE THE TAPE FILEMARK when
+ * return.
+ * This is one really SLOW routine...
+ * Return:
+ * physical block size if ok (ok > 0), -1 otherwise
+ */
+
+static int
+get_phys(void)
+{
+ int padsz = 0;
+ int res;
+ int phyblk;
+ struct mtop mb;
+ char scbuf[MAXBLK];
+
+ /*
+ * move to the file mark, and then back up one record and read it.
+ * this should tell us the physical record size the tape is using.
+ */
+ if (lstrval == 1) {
+ /*
+ * we know we are at file mark when we get back a 0 from
+ * read()
+ */
+ while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0)
+ padsz += res;
+ if (res < 0) {
+ syswarn(1, errno, "Unable to locate tape filemark.");
+ return(-1);
+ }
+ }
+
+ /*
+ * move backwards over the file mark so we are at the end of the
+ * last record.
+ */
+ mb.mt_op = MTBSF;
+ mb.mt_count = 1;
+ if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+ syswarn(1, errno, "Unable to backspace over tape filemark.");
+ return(-1);
+ }
+
+ /*
+ * move backwards so we are in front of the last record and read it to
+ * get physical tape blocksize.
+ */
+ mb.mt_op = MTBSR;
+ mb.mt_count = 1;
+ if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+ syswarn(1, errno, "Unable to backspace over last tape block.");
+ return(-1);
+ }
+ if ((phyblk = read(arfd, scbuf, sizeof(scbuf))) <= 0) {
+ syswarn(1, errno, "Cannot determine archive tape blocksize.");
+ return(-1);
+ }
+
+ /*
+ * read forward to the file mark, then back up in front of the filemark
+ * (this is a bit paranoid, but should be safe to do).
+ */
+ while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0)
+ ;
+ if (res < 0) {
+ syswarn(1, errno, "Unable to locate tape filemark.");
+ return(-1);
+ }
+ mb.mt_op = MTBSF;
+ mb.mt_count = 1;
+ if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+ syswarn(1, errno, "Unable to backspace over tape filemark.");
+ return(-1);
+ }
+
+ /*
+ * set lstrval so we know that the filemark has not been seen
+ */
+ lstrval = 1;
+
+ /*
+ * return if there was no padding
+ */
+ if (padsz == 0)
+ return(phyblk);
+
+ /*
+ * make sure we can move backwards over the padding. (this should
+ * never fail).
+ */
+ if (padsz % phyblk) {
+ paxwarn(1, "Tape drive unable to backspace requested amount");
+ return(-1);
+ }
+
+ /*
+ * move backwards over the padding so the head is where it was when
+ * we were first called (if required).
+ */
+ mb.mt_op = MTBSR;
+ mb.mt_count = padsz/phyblk;
+ if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
+ syswarn(1,errno,"Unable to backspace tape over %d pad blocks",
+ mb.mt_count);
+ return(-1);
+ }
+ return(phyblk);
+}
+#endif /* !__APPLE__ */
+/*
+ * ar_next()
+ * prompts the user for the next volume in this archive. For some devices
+ * we may allow the media to be changed. Otherwise a new archive is
+ * prompted for. By pax spec, if there is no controlling tty or an eof is
+ * read on tty input, we must quit pax.
+ * Return:
+ * 0 when ready to continue, -1 when all done
+ */
+
+int
+ar_next(void)
+{
+ char buf[PAXPATHLEN+2];
+ static int freeit = 0;
+ sigset_t o_mask;
+
+ /*
+ * WE MUST CLOSE THE DEVICE. A lot of devices must see last close, (so
+ * things like writing EOF etc will be done) (Watch out ar_close() can
+ * also be called via a signal handler, so we must prevent a race.
+ */
+ if (sigprocmask(SIG_BLOCK, &s_mask, &o_mask) < 0)
+ syswarn(0, errno, "Unable to set signal mask");
+ ar_close();
+ if (sigprocmask(SIG_SETMASK, &o_mask, NULL) < 0)
+ syswarn(0, errno, "Unable to restore signal mask");
+
+ if (frmt == NULL || done || !wr_trail || force_one_volume || strcmp(NM_TAR, argv0) == 0 ||
+ strcmp(NM_PAX, argv0) == 0)
+ return(-1);
+
+ tty_prnt("\nATTENTION! %s archive volume change required.\n", argv0);
+
+ /*
+ * if i/o is on stdin or stdout, we cannot reopen it (we do not know
+ * the name), the user will be forced to type it in.
+ */
+ if (strcmp(arcname, STDO) && strcmp(arcname, STDN) && (artyp != ISREG)
+ && (artyp != ISPIPE)) {
+ if (artyp == ISTAPE) {
+ tty_prnt("%s ready for archive tape volume: %d\n",
+ arcname, arvol);
+ tty_prnt("Load the NEXT TAPE on the tape drive");
+ } else {
+ tty_prnt("%s ready for archive volume: %d\n",
+ arcname, arvol);
+ tty_prnt("Load the NEXT STORAGE MEDIA (if required)");
+ }
+
+ if ((act == ARCHIVE) || (act == APPND))
+ tty_prnt(" and make sure it is WRITE ENABLED.\n");
+ else
+ tty_prnt("\n");
+
+ for (;;) {
+ tty_prnt("Type \"y\" to continue, \".\" to quit %s,",
+ argv0);
+ tty_prnt(" or \"s\" to switch to new device.\nIf you");
+ tty_prnt(" cannot change storage media, type \"s\"\n");
+ tty_prnt("Is the device ready and online? > ");
+
+ if ((tty_read(buf,sizeof(buf))<0) || !strcmp(buf,".")){
+ done = 1;
+ lstrval = -1;
+ tty_prnt("Quitting %s!\n", argv0);
+ vfpart = 0;
+ return(-1);
+ }
+
+ if ((buf[0] == '\0') || (buf[1] != '\0')) {
+ tty_prnt("%s unknown command, try again\n",buf);
+ continue;
+ }
+
+ switch (buf[0]) {
+ case 'y':
+ case 'Y':
+ /*
+ * we are to continue with the same device
+ */
+ if (ar_open(arcname) >= 0)
+ return(0);
+ tty_prnt("Cannot re-open %s, try again\n",
+ arcname);
+ continue;
+ case 's':
+ case 'S':
+ /*
+ * user wants to open a different device
+ */
+ tty_prnt("Switching to a different archive\n");
+ break;
+ default:
+ tty_prnt("%s unknown command, try again\n",buf);
+ continue;
+ }
+ break;
+ }
+ } else
+ tty_prnt("Ready for archive volume: %d\n", arvol);
+
+ /*
+ * have to go to a different archive
+ */
+ for (;;) {
+ tty_prnt("Input archive name or \".\" to quit %s.\n", argv0);
+ tty_prnt("Archive name > ");
+
+ if ((tty_read(buf, sizeof(buf)) < 0) || !strcmp(buf, ".")) {
+ done = 1;
+ lstrval = -1;
+ tty_prnt("Quitting %s!\n", argv0);
+ vfpart = 0;
+ return(-1);
+ }
+ if (buf[0] == '\0') {
+ tty_prnt("Empty file name, try again\n");
+ continue;
+ }
+ if (!strcmp(buf, "..")) {
+ tty_prnt("Illegal file name: .. try again\n");
+ continue;
+ }
+ if (strlen(buf) > PAXPATHLEN) {
+ tty_prnt("File name too long, try again\n");
+ continue;
+ }
+
+ /*
+ * try to open new archive
+ */
+ if (ar_open(buf) >= 0) {
+ if (freeit) {
+ (void)free((char *)arcname);
+ freeit = 0;
+ }
+ if ((arcname = strdup(buf)) == NULL) {
+ done = 1;
+ lstrval = -1;
+ paxwarn(0, "Cannot save archive name.");
+ return(-1);
+ }
+ freeit = 1;
+ break;
+ }
+ tty_prnt("Cannot open %s, try again\n", buf);
+ continue;
+ }
+ return(0);
+}
+
+/*
+ * ar_start_gzip()
+ * starts the gzip compression/decompression process as a child, using magic
+ * to keep the fd the same in the calling function (parent).
+ */
+void
+ar_start_gzip(int fd, const char *gzip_program, int wr)
+{
+ int fds[2];
+ const char *gzip_flags = NULL;
+
+ if (pipe(fds) < 0)
+ err(1, "could not pipe");
+ zpid = fork();
+ if (zpid < 0)
+ err(1, "could not fork");
+
+ /* parent */
+ if (zpid) {
+ if (wr)
+ dup2(fds[1], fd);
+ else
+ dup2(fds[0], fd);
+ close(fds[0]);
+ close(fds[1]);
+ } else {
+ if (wr) {
+ dup2(fds[0], STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ gzip_flags = "-c";
+ } else {
+ dup2(fds[1], STDOUT_FILENO);
+ dup2(fd, STDIN_FILENO);
+ gzip_flags = "-dc";
+ }
+ close(fds[0]);
+ close(fds[1]);
+ if (execlp(gzip_program, gzip_program, gzip_flags, (char *)NULL) < 0)
+ err(1, "could not exec %s", gzip_program);
+ /* NOTREACHED */
+ }
+}
diff --git a/file_cmds/pax/ar_subs.c b/file_cmds/pax/ar_subs.c
new file mode 100644
index 0000000..b4896ea
--- /dev/null
+++ b/file_cmds/pax/ar_subs.c
@@ -0,0 +1,1517 @@
+/* $OpenBSD: ar_subs.c,v 1.32 2008/05/06 06:54:28 henning Exp $ */
+/* $NetBSD: ar_subs.c,v 1.5 1995/03/21 09:07:06 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)ar_subs.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: ar_subs.c,v 1.32 2008/05/06 06:54:28 henning Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifdef __APPLE__
+#include <sys/param.h>
+#include <copyfile.h>
+#include <libgen.h>
+#include <sys/queue.h>
+#endif
+#include "pax.h"
+#include "options.h"
+#include "extern.h"
+
+static int path_check(ARCHD *, int);
+static void wr_archive(ARCHD *, int is_app);
+static int get_arc(void);
+static int next_head(ARCHD *);
+extern sigset_t s_mask;
+
+/*
+ * Routines which control the overall operation modes of pax as specified by
+ * the user: list, append, read ...
+ */
+
+static char hdbuf[BLKMULT]; /* space for archive header on read */
+u_long flcnt; /* number of files processed */
+
+static char cwdpath[MAXPATHLEN]; /* current working directory path */
+static size_t cwdpathlen; /* current working directory path len */
+
+int
+updatepath(void)
+{
+ if (getcwd(cwdpath, sizeof(cwdpath)) == NULL) {
+ syswarn(1, errno, "Cannot get working directory");
+ return -1;
+ }
+ cwdpathlen = strlen(cwdpath);
+ return 0;
+}
+
+int
+fdochdir(int fcwd)
+{
+ if (fchdir(fcwd) == -1) {
+ syswarn(1, errno, "Cannot chdir to `.'");
+ return -1;
+ }
+ return updatepath();
+}
+
+int
+dochdir(const char *name)
+{
+ if (chdir(name) == -1)
+ syswarn(1, errno, "Cannot chdir to `%s'", name);
+ return updatepath();
+}
+
+static int
+path_check(ARCHD *arcn, int level)
+{
+ char buf[MAXPATHLEN];
+ char *p;
+
+ if ((p = strrchr(arcn->name, '/')) == NULL)
+ return 0;
+ *p = '\0';
+
+ if (realpath(arcn->name, buf) == NULL) {
+ int error;
+ error = path_check(arcn, level + 1);
+ *p = '/';
+ if (error == 0)
+ return 0;
+ if (level == 0)
+ syswarn(1, 0, "Cannot resolve `%s'", arcn->name);
+ return -1;
+ }
+ if (cwdpathlen == 1) { /* We're in the root */
+ *p = '/';
+ return 0;
+ }
+ if ((strncmp(buf, cwdpath, cwdpathlen) != 0) || (buf[cwdpathlen] != '\0' && buf[cwdpathlen] != '/')) {
+ *p = '/';
+ syswarn(1, 0, "Attempt to write file `%s' that resolves into "
+ "`%s/%s' outside current working directory `%s' ignored",
+ arcn->name, buf, p + 1, cwdpath);
+ return -1;
+ }
+ *p = '/';
+ return 0;
+}
+
+/*
+ * list()
+ * list the contents of an archive which match user supplied pattern(s)
+ * (no pattern matches all).
+ */
+
+void
+list(void)
+{
+ ARCHD *arcn;
+ int res;
+ ARCHD archd;
+ time_t now;
+
+ arcn = &archd;
+ /*
+ * figure out archive type; pass any format specific options to the
+ * archive option processing routine; call the format init routine. We
+ * also save current time for ls_list() so we do not make a system
+ * call for each file we need to print. If verbose (vflag) start up
+ * the name and group caches.
+ */
+ if ((get_arc() < 0) || ((*frmt->options)() < 0) ||
+ ((*frmt->st_rd)() < 0))
+ return;
+
+ if (vflag && ((uidtb_start() < 0) || (gidtb_start() < 0)))
+ return;
+
+ now = time(NULL);
+
+ /*
+ * step through the archive until the format says it is done
+ */
+ while (next_head(arcn) == 0) {
+ if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) {
+ /*
+ * we need to read, to get the real filename
+ */
+ off_t cnt;
+ if (!(*frmt->rd_data)(arcn, arcn->type == PAX_GLF
+ ? -1 : -2, &cnt))
+ (void)rd_skip(cnt + arcn->pad);
+ continue;
+ }
+
+ /*
+ * check for pattern, and user specified options match.
+ * When all patterns are matched we are done.
+ */
+ if ((res = pat_match(arcn)) < 0)
+ break;
+
+ if ((res == 0) && (sel_chk(arcn) == 0)) {
+ /*
+ * pattern resulted in a selected file
+ */
+ if (pat_sel(arcn) < 0)
+ break;
+
+ /*
+ * modify the name as requested by the user if name
+ * survives modification, do a listing of the file
+ */
+ if ((res = mod_name(arcn)) < 0)
+ break;
+ if (res == 0)
+ ls_list(arcn, now, stdout);
+ }
+
+ /*
+ * skip to next archive format header using values calculated
+ * by the format header read routine
+ */
+ if (rd_skip(arcn->skip + arcn->pad) == 1)
+ break;
+ }
+
+ /*
+ * all done, let format have a chance to cleanup, and make sure that
+ * the patterns supplied by the user were all matched
+ */
+ (void)(*frmt->end_rd)();
+ (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
+ ar_close();
+ pat_chk();
+}
+
+/*
+ * extract()
+ * extract the member(s) of an archive as specified by user supplied
+ * pattern(s) (no patterns extracts all members)
+ */
+
+void
+extract(void)
+{
+ ARCHD *arcn;
+ int res;
+ off_t cnt;
+ ARCHD archd;
+ struct stat sb;
+ int fd;
+ time_t now;
+
+#ifdef __APPLE__
+ int copyfile_disable = (getenv(COPYFILE_DISABLE_VAR) != NULL);
+ LIST_HEAD(copyfile_list_t, copyfile_list_entry_t) copyfile_list;
+ struct copyfile_list_entry_t {
+ char *src;
+ char *dst;
+ LIST_ENTRY(copyfile_list_entry_t) link;
+ } *cle;
+
+ LIST_INIT(&copyfile_list);
+#endif
+
+ arcn = &archd;
+ /*
+ * figure out archive type; pass any format specific options to the
+ * archive option processing routine; call the format init routine;
+ * start up the directory modification time and access mode database
+ */
+ if ((get_arc() < 0) || ((*frmt->options)() < 0) ||
+ ((*frmt->st_rd)() < 0) || (dir_start() < 0))
+ return;
+
+ /*
+ * When we are doing interactive rename, we store the mapping of names
+ * so we can fix up hard links files later in the archive.
+ */
+ if (iflag && (name_start() < 0))
+ return;
+
+ now = time(NULL);
+
+ /*
+ * step through each entry on the archive until the format read routine
+ * says it is done
+ */
+ while (next_head(arcn) == 0) {
+ if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) {
+ /*
+ * we need to read, to get the real filename
+ */
+ if (!(*frmt->rd_data)(arcn, arcn->type == PAX_GLF
+ ? -1 : -2, &cnt))
+ (void)rd_skip(cnt + arcn->pad);
+ continue;
+ }
+
+ /*
+ * check for pattern, and user specified options match. When
+ * all the patterns are matched we are done
+ */
+ if ((res = pat_match(arcn)) < 0)
+ break;
+
+ if ((res > 0) || (sel_chk(arcn) != 0)) {
+ /*
+ * file is not selected. skip past any file data and
+ * padding and go back for the next archive member
+ */
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+
+ /*
+ * with -u or -D only extract when the archive member is newer
+ * than the file with the same name in the file system (no
+ * test of being the same type is required).
+ * NOTE: this test is done BEFORE name modifications as
+ * specified by pax. this operation can be confusing to the
+ * user who might expect the test to be done on an existing
+ * file AFTER the name mod. In honesty the pax spec is probably
+ * flawed in this respect.
+ */
+ if ((uflag || Dflag) && ((lstat(arcn->name, &sb) == 0))) {
+ if (uflag && Dflag) {
+ if ((arcn->sb.st_mtime <= sb.st_mtime) &&
+ (arcn->sb.st_ctime <= sb.st_ctime)) {
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+ } else if (Dflag) {
+ if (arcn->sb.st_ctime <= sb.st_ctime) {
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+ } else if (arcn->sb.st_mtime <= sb.st_mtime) {
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+ }
+
+ /*
+ * this archive member is now been selected. modify the name.
+ */
+ if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn)) < 0))
+ break;
+ if (res > 0) {
+ /*
+ * a bad name mod, skip and purge name from link table
+ */
+ purg_lnk(arcn);
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+
+ /*
+ * Non standard -Y and -Z flag. When the existing file is
+ * same age or newer skip
+ */
+ if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
+ if (Yflag && Zflag) {
+ if ((arcn->sb.st_mtime <= sb.st_mtime) &&
+ (arcn->sb.st_ctime <= sb.st_ctime)) {
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+ } else if (Yflag) {
+ if (arcn->sb.st_ctime <= sb.st_ctime) {
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+ } else if (arcn->sb.st_mtime <= sb.st_mtime) {
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+ }
+
+ if (vflag) {
+ if (vflag > 1)
+ ls_list(arcn, now, listf);
+ else {
+ (void)safe_print(arcn->name, listf);
+ vfpart = 1;
+ }
+ }
+
+ /*
+ * if required, chdir around.
+ */
+ if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL))
+ dochdir(arcn->pat->chdname);
+
+ if (secure && path_check(arcn, 0) != 0) {
+ (void)rd_skip(arcn->skip + arcn->pad);
+ continue;
+ }
+
+ /*
+ * all ok, extract this member based on type
+ */
+ if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
+ /*
+ * process archive members that are not regular files.
+ * throw out padding and any data that might follow the
+ * header (as determined by the format).
+ */
+ if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
+ res = lnk_creat(arcn);
+ else
+ res = node_creat(arcn);
+
+ (void)rd_skip(arcn->skip + arcn->pad);
+ if (res < 0)
+ purg_lnk(arcn);
+
+ if (vflag && vfpart) {
+ (void)putc('\n', listf);
+ vfpart = 0;
+ }
+ continue;
+ }
+ /*
+ * we have a file with data here. If we can not create it, skip
+ * over the data and purge the name from hard link table
+ */
+ if ((fd = file_creat(arcn)) < 0) {
+ (void)rd_skip(arcn->skip + arcn->pad);
+ purg_lnk(arcn);
+ continue;
+ }
+ /*
+ * extract the file from the archive and skip over padding and
+ * any unprocessed data
+ */
+ res = (*frmt->rd_data)(arcn, fd, &cnt);
+ file_close(arcn, fd);
+ if (vflag && vfpart) {
+ (void)putc('\n', listf);
+ vfpart = 0;
+ }
+ if (!res)
+ (void)rd_skip(cnt + arcn->pad);
+
+#ifdef __APPLE__
+ if (!strncmp(basename(arcn->name), "._", 2)) {
+ cle = alloca(sizeof(struct copyfile_list_entry_t));
+ cle->src = strdup(arcn->name);
+
+ if (asprintf(&cle->dst, "%s/%s",
+ dirname(arcn->name), basename(arcn->name) + 2) != -1) {
+ LIST_INSERT_HEAD(&copyfile_list, cle, link);
+ } else {
+ free(cle->src);
+ }
+ }
+#endif
+ /*
+ * if required, chdir around.
+ */
+ if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL))
+ fdochdir(cwdfd);
+ }
+#ifdef __APPLE__
+ LIST_FOREACH(cle, &copyfile_list, link)
+ {
+ if(copyfile_disable || copyfile(cle->src, cle->dst, NULL,
+ COPYFILE_UNPACK | COPYFILE_XATTR | COPYFILE_ACL)) {
+ if (!copyfile_disable) {
+ syswarn(1, errno, "Unable to set metadata on %s", cle->dst);
+ }
+ } else {
+ unlink(cle->src);
+ }
+ free(cle->dst);
+ free(cle->src);
+ }
+#endif
+
+ /*
+ * all done, restore directory modes and times as required; make sure
+ * all patterns supplied by the user were matched; block off signals
+ * to avoid chance for multiple entry into the cleanup code.
+ */
+ (void)(*frmt->end_rd)();
+ (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
+ ar_close();
+ proc_dir();
+ pat_chk();
+}
+
+/*
+ * wr_archive()
+ * Write an archive. used in both creating a new archive and appends on
+ * previously written archive.
+ */
+
+static void
+wr_archive(ARCHD *arcn, int is_app)
+{
+ int res;
+ int hlk;
+ int wr_one;
+ off_t cnt;
+ int (*wrf)(ARCHD *);
+ int fd = -1;
+ time_t now;
+
+#ifdef __APPLE__
+ int metadata = 0;
+ char *md_fname = NULL;
+ ARCHD arcn_copy;
+ char arcn_copy_name[PAXPATHLEN+1];
+#endif
+
+ /*
+ * if this format supports hard link storage, start up the database
+ * that detects them.
+ */
+ if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0))
+ return;
+
+ if (hlk && want_linkdata) hlk=0; /* Treat hard links as individual files */
+
+ /*
+ * start up the file traversal code and format specific write
+ */
+ if ((ftree_start() < 0) || ((*frmt->st_wr)() < 0))
+ return;
+ wrf = frmt->wr;
+
+ /*
+ * When we are doing interactive rename, we store the mapping of names
+ * so we can fix up hard links files later in the archive.
+ */
+ if (iflag && (name_start() < 0))
+ return;
+
+ /*
+ * if this is not append, and there are no files, we do not write a
+ * trailer
+ */
+ wr_one = is_app;
+
+ now = time(NULL);
+
+ /*
+ * while there are files to archive, process them one at at time
+ */
+ while (next_file(arcn) == 0) {
+ /*
+ * check if this file meets user specified options match.
+ */
+ if (sel_chk(arcn) != 0) {
+ ftree_notsel();
+ continue;
+ }
+ fd = -1;
+ if (uflag) {
+ /*
+ * only archive if this file is newer than a file with
+ * the same name that is already stored on the archive
+ */
+ if ((res = chk_ftime(arcn)) < 0)
+ break;
+ if (res > 0)
+ continue;
+ }
+
+#ifdef __APPLE__
+ /*
+ * synthesize ._ files for each node we encounter
+ */
+ if (getenv(COPYFILE_DISABLE_VAR) == NULL
+ && copyfile(arcn->name, NULL, NULL,
+ COPYFILE_CHECK | COPYFILE_XATTR | COPYFILE_ACL)
+ && arcn->nlen + 2 < sizeof(arcn->name)) {
+ char *tmpdir = P_tmpdir, *TMPDIR;
+ int fd_src, fd_dst;
+
+ if (!issetugid() && (TMPDIR = getenv("TMPDIR"))) {
+ tmpdir = TMPDIR;
+ }
+ asprintf(&md_fname, "%s%s", tmpdir, "/pax-md-XXXXXX");
+ if (!md_fname) {
+ syswarn(1, errno, "Unable to create temporary file name");
+ return;
+ }
+ memcpy(&arcn_copy, arcn, sizeof(ARCHD));
+ strncpy(arcn_copy_name, arcn->name, PAXPATHLEN+1);
+
+ arcn->skip = 0;
+ arcn->pad = 0;
+ arcn->ln_nlen = 0;
+ arcn->ln_name[0] = '\0';
+ arcn->type = PAX_REG;
+ fd_dst = mkstemp(md_fname);
+ if (fd_dst >= 0) {
+ fd_src = open(arcn->name, O_RDONLY, 0);
+ if (fd_src < 0) {
+ syswarn(1, errno, "Unable to open %s for reading", arcn->name);
+ close(fd_dst);
+ unlink(md_fname);
+ free(md_fname);
+ md_fname = NULL;
+ goto next;
+ }
+ if(fcopyfile(fd_src, fd_dst, NULL,
+ COPYFILE_PACK | COPYFILE_XATTR | COPYFILE_ACL) < 0) {
+ syswarn(1, errno,
+ "Unable to preserve metadata on %s", arcn->name);
+ close(fd_src);
+ close(fd_dst);
+ unlink(md_fname);
+ free(md_fname);
+ md_fname = NULL;
+ goto next;
+ }
+ close(fd_src);
+ fstat(fd_dst, &arcn->sb);
+ close(fd_dst);
+ } else {
+ syswarn(1, errno, "Unable to create temporary file %s", md_fname);
+ free(md_fname);
+ goto next;
+ }
+ arcn->skip = arcn->sb.st_size;
+
+ if (!strncmp(dirname(arcn->name), ".", 2)) {
+ snprintf(arcn->name, sizeof(arcn->name),
+ "._%s", basename(arcn->name));
+ } else {
+ snprintf(arcn->name, sizeof(arcn->name),
+ "%s/._%s",
+ dirname(arcn->name), basename(arcn->name));
+ }
+ arcn->nlen = strlen(arcn->name);
+ arcn->org_name = arcn->name;
+ metadata = 1;
+ } else if (metadata) {
+next:
+ metadata = 0;
+ memcpy(arcn, &arcn_copy, sizeof(ARCHD));
+ strncpy(arcn->name, arcn_copy_name, PAXPATHLEN+1);
+ }
+#endif /* __APPLE__ */
+
+ fd = -1;
+
+ /*
+ * this file is considered selected now. see if this is a hard
+ * link to a file already stored
+ */
+ ftree_sel(arcn);
+ if (hlk && (chk_lnk(arcn) < 0)) {
+ if (md_fname) {
+ unlink(md_fname);
+ free(md_fname);
+ md_fname = NULL;
+ }
+ break;
+ }
+
+ if ((arcn->type == PAX_REG) || (arcn->type == PAX_HRG) ||
+ (arcn->type == PAX_CTG)) {
+ /*
+ * we will have to read this file. by opening it now we
+ * can avoid writing a header to the archive for a file
+ * we were later unable to read (we also purge it from
+ * the link table).
+ */
+#ifdef __APPLE__
+ if (metadata) {
+ fd = open(md_fname, O_RDONLY, 0);
+ unlink(md_fname);
+ free(md_fname);
+ md_fname = NULL;
+ } else
+ fd = open(arcn->org_name, O_RDONLY, 0);
+ if (fd < 0) {
+#else /* !__APPLE__ */
+ if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) {
+#endif /* __APPLE__ */
+ syswarn(1,errno, "Unable to open %s to read",
+ arcn->org_name);
+ purg_lnk(arcn);
+ continue;
+ }
+ }
+
+ /*
+ * Now modify the name as requested by the user
+ */
+ if ((res = mod_name(arcn)) < 0) {
+ /*
+ * name modification says to skip this file, close the
+ * file and purge link table entry
+ */
+ rdfile_close(arcn, &fd);
+ purg_lnk(arcn);
+ break;
+ }
+
+ if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) {
+ /*
+ * unable to obtain the crc we need, close the file,
+ * purge link table entry
+ */
+ rdfile_close(arcn, &fd);
+ purg_lnk(arcn);
+ continue;
+ }
+
+ if (vflag) {
+ if (vflag > 1)
+ ls_list(arcn, now, listf);
+ else {
+ (void)safe_print(arcn->name, listf);
+ vfpart = 1;
+ }
+ }
+ ++flcnt;
+
+ /*
+ * looks safe to store the file, have the format specific
+ * routine write routine store the file header on the archive
+ */
+ if ((res = (*wrf)(arcn)) < 0) {
+ rdfile_close(arcn, &fd);
+ break;
+ }
+ wr_one = 1;
+ if (res > 0) {
+ /*
+ * format write says no file data needs to be stored
+ * so we are done messing with this file
+ */
+ if (vflag && vfpart) {
+ (void)putc('\n', listf);
+ vfpart = 0;
+ }
+ rdfile_close(arcn, &fd);
+ continue;
+ }
+
+ /*
+ * Add file data to the archive, quit on write error. if we
+ * cannot write the entire file contents to the archive we
+ * must pad the archive to replace the missing file data
+ * (otherwise during an extract the file header for the file
+ * which FOLLOWS this one will not be where we expect it to
+ * be).
+ */
+ res = (*frmt->wr_data)(arcn, fd, &cnt);
+ rdfile_close(arcn, &fd);
+ if (vflag && vfpart) {
+ (void)putc('\n', listf);
+ vfpart = 0;
+ }
+ if (res < 0)
+ break;
+
+ /*
+ * pad as required, cnt is number of bytes not written
+ */
+ if (((cnt > 0) && (wr_skip(cnt) < 0)) ||
+ ((arcn->pad > 0) && (wr_skip(arcn->pad) < 0)))
+ break;
+#ifdef __APPLE__
+ if (metadata)
+ goto next;
+#endif /* __APPLE__ */
+ }
+
+ /*
+ * tell format to write trailer; pad to block boundary; reset directory
+ * mode/access times, and check if all patterns supplied by the user
+ * were matched. block off signals to avoid chance for multiple entry
+ * into the cleanup code
+ */
+ if (wr_one) {
+ (*frmt->end_wr)();
+ wr_fin();
+ }
+ (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
+ ar_close();
+ if (tflag)
+ proc_dir();
+ ftree_chk();
+}
+
+/*
+ * append()
+ * Add file to previously written archive. Archive format specified by the
+ * user must agree with archive. The archive is read first to collect
+ * modification times (if -u) and locate the archive trailer. The archive
+ * is positioned in front of the record with the trailer and wr_archive()
+ * is called to add the new members.
+ * PAX IMPLEMENTATION DETAIL NOTE:
+ * -u is implemented by adding the new members to the end of the archive.
+ * Care is taken so that these do not end up as links to the older
+ * version of the same file already stored in the archive. It is expected
+ * when extraction occurs these newer versions will over-write the older
+ * ones stored "earlier" in the archive (this may be a bad assumption as
+ * it depends on the implementation of the program doing the extraction).
+ * It is really difficult to splice in members without either re-writing
+ * the entire archive (from the point were the old version was), or having
+ * assistance of the format specification in terms of a special update
+ * header that invalidates a previous archive record. The POSIX spec left
+ * the method used to implement -u unspecified. This pax is able to
+ * over write existing files that it creates.
+ */
+
+void
+append(void)
+{
+ ARCHD *arcn;
+ int res;
+ ARCHD archd;
+ const FSUB *orgfrmt;
+ int udev;
+ off_t tlen;
+
+ arcn = &archd;
+ orgfrmt = frmt;
+
+ /*
+ * Do not allow an append operation if the actual archive is of a
+ * different format than the user specified format.
+ */
+ if (get_arc() < 0)
+ return;
+ if ((orgfrmt != NULL) && (orgfrmt != frmt)) {
+ paxwarn(1, "Cannot mix current archive format %s with %s",
+ frmt->name, orgfrmt->name);
+ return;
+ }
+
+ /*
+ * pass the format any options and start up format
+ */
+ if (((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0))
+ return;
+
+ /*
+ * if we only are adding members that are newer, we need to save the
+ * mod times for all files we see.
+ */
+ if (uflag && (ftime_start() < 0))
+ return;
+
+ /*
+ * some archive formats encode hard links by recording the device and
+ * file serial number (inode) but copy the file anyway (multiple times)
+ * to the archive. When we append, we run the risk that newly added
+ * files may have the same device and inode numbers as those recorded
+ * on the archive but during a previous run. If this happens, when the
+ * archive is extracted we get INCORRECT hard links. We avoid this by
+ * remapping the device numbers so that newly added files will never
+ * use the same device number as one found on the archive. remapping
+ * allows new members to safely have links among themselves. remapping
+ * also avoids problems with file inode (serial number) truncations
+ * when the inode number is larger than storage space in the archive
+ * header. See the remap routines for more details.
+ */
+ if ((udev = frmt->udev) && (dev_start() < 0))
+ return;
+
+ /*
+ * reading the archive may take a long time. If verbose tell the user
+ */
+ if (vflag) {
+ (void)fprintf(listf,
+ "%s: Reading archive to position at the end...", argv0);
+ vfpart = 1;
+ }
+
+ /*
+ * step through the archive until the format says it is done
+ */
+ while (next_head(arcn) == 0) {
+ /*
+ * check if this file meets user specified options.
+ */
+ if (sel_chk(arcn) != 0) {
+ if (rd_skip(arcn->skip + arcn->pad) == 1)
+ break;
+ continue;
+ }
+
+ if (uflag) {
+ /*
+ * see if this is the newest version of this file has
+ * already been seen, if so skip.
+ */
+ if ((res = chk_ftime(arcn)) < 0)
+ break;
+ if (res > 0) {
+ if (rd_skip(arcn->skip + arcn->pad) == 1)
+ break;
+ continue;
+ }
+ }
+
+ /*
+ * Store this device number. Device numbers seen during the
+ * read phase of append will cause newly appended files with a
+ * device number seen in the old part of the archive to be
+ * remapped to an unused device number.
+ */
+ if ((udev && (add_dev(arcn) < 0)) ||
+ (rd_skip(arcn->skip + arcn->pad) == 1))
+ break;
+ }
+
+ /*
+ * done, finish up read and get the number of bytes to back up so we
+ * can add new members. The format might have used the hard link table,
+ * purge it.
+ */
+ tlen = (*frmt->end_rd)();
+ lnk_end();
+
+ /*
+ * try to position for write, if this fails quit. if any error occurs,
+ * we will refuse to write
+ */
+ if (appnd_start(tlen) < 0)
+ return;
+
+ /*
+ * tell the user we are done reading.
+ */
+ if (vflag && vfpart) {
+ (void)fputs("done.\n", listf);
+ vfpart = 0;
+ }
+
+ /*
+ * go to the writing phase to add the new members
+ */
+ wr_archive(arcn, 1);
+}
+
+/*
+ * archive()
+ * write a new archive
+ */
+
+void
+archive(void)
+{
+ ARCHD archd;
+
+ /*
+ * if we only are adding members that are newer, we need to save the
+ * mod times for all files; set up for writing; pass the format any
+ * options write the archive
+ */
+ if ((uflag && (ftime_start() < 0)) || (wr_start() < 0))
+ return;
+ if ((*frmt->options)() < 0)
+ return;
+
+ wr_archive(&archd, 0);
+}
+
+/*
+ * copy()
+ * copy files from one part of the file system to another. this does not
+ * use any archive storage. The EFFECT OF THE COPY IS THE SAME as if an
+ * archive was written and then extracted in the destination directory
+ * (except the files are forced to be under the destination directory).
+ */
+
+void
+copy(void)
+{
+ ARCHD *arcn;
+ int res;
+ int fddest;
+ char *dest_pt;
+ int dlen;
+ int drem;
+ int fdsrc = -1;
+ struct stat sb;
+ ARCHD archd;
+ char dirbuf[PAXPATHLEN+1];
+
+ arcn = &archd;
+ if (frmt && strcmp(frmt->name, NM_PAX)==0) {
+ /* Copy using pax format: must check if any -o options */
+ if ((*frmt->options)() < 0)
+ return;
+ if (pax_invalid_action==0)
+ pax_invalid_action = PAX_INVALID_ACTION_BYPASS;
+ }
+ /*
+ * set up the destination dir path and make sure it is a directory. We
+ * make sure we have a trailing / on the destination
+ */
+ dlen = strlcpy(dirbuf, dirptr, sizeof(dirbuf));
+ if (dlen >= sizeof(dirbuf) ||
+ (dlen == sizeof(dirbuf) - 1 && dirbuf[dlen - 1] != '/')) {
+ paxwarn(1, "directory name is too long %s", dirptr);
+ return;
+ }
+ dest_pt = dirbuf + dlen;
+ if (*(dest_pt-1) != '/') {
+ *dest_pt++ = '/';
+ *dest_pt = '\0';
+ ++dlen;
+ }
+ drem = PAXPATHLEN - dlen;
+
+ if (stat(dirptr, &sb) < 0) {
+ syswarn(1, errno, "Cannot access destination directory %s",
+ dirptr);
+ return;
+ }
+ if (!S_ISDIR(sb.st_mode)) {
+ paxwarn(1, "Destination is not a directory %s", dirptr);
+ return;
+ }
+
+ /*
+ * start up the hard link table; file traversal routines and the
+ * modification time and access mode database
+ */
+ if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0))
+ return;
+
+ /*
+ * When we are doing interactive rename, we store the mapping of names
+ * so we can fix up hard links files later in the archive.
+ */
+ if (iflag && (name_start() < 0))
+ return;
+
+ /*
+ * set up to cp file trees
+ */
+ cp_start();
+
+ /*
+ * while there are files to archive, process them
+ */
+ while (next_file(arcn) == 0) {
+ fdsrc = -1;
+
+ /*
+ * Fill in arcn from any pax options
+ */
+ adjust_copy_for_pax_options(arcn);
+
+ /*
+ * check if this file meets user specified options
+ */
+ if (sel_chk(arcn) != 0) {
+ ftree_notsel();
+ continue;
+ }
+
+ /*
+ * if there is already a file in the destination directory with
+ * the same name and it is newer, skip the one stored on the
+ * archive.
+ * NOTE: this test is done BEFORE name modifications as
+ * specified by pax. this can be confusing to the user who
+ * might expect the test to be done on an existing file AFTER
+ * the name mod. In honesty the pax spec is probably flawed in
+ * this respect
+ */
+ if (uflag || Dflag) {
+ /*
+ * create the destination name
+ */
+ if (strlcpy(dest_pt, arcn->name + (*arcn->name == '/'),
+ drem + 1) > drem) {
+ paxwarn(1, "Destination pathname too long %s",
+ arcn->name);
+ continue;
+ }
+
+ /*
+ * if existing file is same age or newer skip
+ */
+ res = lstat(dirbuf, &sb);
+ *dest_pt = '\0';
+
+ if (res == 0) {
+ if (uflag && Dflag) {
+ if ((arcn->sb.st_mtime<=sb.st_mtime) &&
+ (arcn->sb.st_ctime<=sb.st_ctime))
+ continue;
+ } else if (Dflag) {
+ if (arcn->sb.st_ctime <= sb.st_ctime)
+ continue;
+ } else if (arcn->sb.st_mtime <= sb.st_mtime)
+ continue;
+ }
+ }
+
+ /*
+ * this file is considered selected. See if this is a hard link
+ * to a previous file; modify the name as requested by the
+ * user; set the final destination.
+ */
+ ftree_sel(arcn);
+ if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn)) < 0))
+ break;
+ if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) {
+ /*
+ * skip file, purge from link table
+ */
+ purg_lnk(arcn);
+ continue;
+ }
+
+ /*
+ * Non standard -Y and -Z flag. When the existing file is
+ * same age or newer skip
+ */
+ if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
+ if (Yflag && Zflag) {
+ if ((arcn->sb.st_mtime <= sb.st_mtime) &&
+ (arcn->sb.st_ctime <= sb.st_ctime))
+ continue;
+ } else if (Yflag) {
+ if (arcn->sb.st_ctime <= sb.st_ctime)
+ continue;
+ } else if (arcn->sb.st_mtime <= sb.st_mtime)
+ continue;
+ }
+
+ if (vflag) {
+ (void)safe_print(arcn->name, listf);
+ vfpart = 1;
+ }
+ ++flcnt;
+
+ /*
+ * try to create a hard link to the src file if requested
+ * but make sure we are not trying to overwrite ourselves.
+ */
+ if (lflag)
+ res = cross_lnk(arcn);
+ else
+ res = chk_same(arcn);
+ if (res <= 0) {
+ if (vflag && vfpart) {
+ (void)putc('\n', listf);
+ vfpart = 0;
+ }
+ continue;
+ }
+
+ /*
+ * have to create a new file
+ */
+ if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
+ /*
+ * create a link or special file
+ */
+ if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
+ res = lnk_creat(arcn);
+ else
+ res = node_creat(arcn);
+ if (res < 0)
+ purg_lnk(arcn);
+#ifdef __APPLE__
+ if (res >= 0 &&
+ arcn->type == PAX_DIR &&
+ copyfile(arcn->org_name, arcn->name, NULL, COPYFILE_ACL | COPYFILE_XATTR) < 0)
+ paxwarn(1, "Directory %s had metadata that could not be copied: %s", arcn->org_name, strerror(errno));
+#endif /* __APPLE__ */
+ if (vflag && vfpart) {
+ (void)putc('\n', listf);
+ vfpart = 0;
+ }
+ continue;
+ }
+
+ /*
+ * have to copy a regular file to the destination directory.
+ * first open source file and then create the destination file
+ */
+ if ((fdsrc = open(arcn->org_name, O_RDONLY, 0)) < 0) {
+ syswarn(1, errno, "Unable to open %s to read",
+ arcn->org_name);
+ purg_lnk(arcn);
+ continue;
+ }
+ if ((fddest = file_creat(arcn)) < 0) {
+ rdfile_close(arcn, &fdsrc);
+ purg_lnk(arcn);
+ continue;
+ }
+
+ /*
+ * copy source file data to the destination file
+ */
+ cp_file(arcn, fdsrc, fddest);
+#ifdef __APPLE__
+ /* do this before file close so that mtimes are correct regardless */
+ if (getenv(COPYFILE_DISABLE_VAR) == NULL) {
+ if (fcopyfile(fdsrc, fddest, NULL, COPYFILE_ACL | COPYFILE_XATTR) < 0)
+ paxwarn(1, "File %s had metadata that could not be copied: %s", arcn->org_name,
+ strerror(errno));
+ }
+#endif
+ file_close(arcn, fddest);
+ rdfile_close(arcn, &fdsrc);
+
+ if (vflag && vfpart) {
+ (void)putc('\n', listf);
+ vfpart = 0;
+ }
+ }
+
+ /*
+ * restore directory modes and times as required; make sure all
+ * patterns were selected block off signals to avoid chance for
+ * multiple entry into the cleanup code.
+ */
+ (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
+ ar_close();
+ proc_dir();
+ ftree_chk();
+}
+
+/*
+ * next_head()
+ * try to find a valid header in the archive. Uses format specific
+ * routines to extract the header and id the trailer. Trailers may be
+ * located within a valid header or in an invalid header (the location
+ * is format specific. The inhead field from the option table tells us
+ * where to look for the trailer).
+ * We keep reading (and resyncing) until we get enough contiguous data
+ * to check for a header. If we cannot find one, we shift by a byte
+ * add a new byte from the archive to the end of the buffer and try again.
+ * If we get a read error, we throw out what we have (as we must have
+ * contiguous data) and start over again.
+ * ASSUMED: headers fit within a BLKMULT header.
+ * Return:
+ * 0 if we got a header, -1 if we are unable to ever find another one
+ * (we reached the end of input, or we reached the limit on retries. see
+ * the specs for rd_wrbuf() for more details)
+ */
+
+static int
+next_head(ARCHD *arcn)
+{
+ int ret;
+ char *hdend;
+ int res;
+ int shftsz;
+ int hsz;
+ int in_resync = 0; /* set when we are in resync mode */
+ int cnt = 0; /* counter for trailer function */
+ int first = 1; /* on 1st read, EOF isn't premature. */
+
+ /*
+ * set up initial conditions, we want a whole frmt->hsz block as we
+ * have no data yet.
+ */
+ res = hsz = frmt->hsz;
+ hdend = hdbuf;
+ shftsz = hsz - 1;
+ for (;;) {
+ /*
+ * keep looping until we get a contiguous FULL buffer
+ * (frmt->hsz is the proper size)
+ */
+ for (;;) {
+ if ((ret = rd_wrbuf(hdend, res)) == res)
+ break;
+
+ /*
+ * If we read 0 bytes (EOF) from an archive when we
+ * expect to find a header, we have stepped upon
+ * an archive without the customary block of zeroes
+ * end marker. It's just stupid to error out on
+ * them, so exit gracefully.
+ */
+ if (first && ret == 0)
+ return(-1);
+ first = 0;
+
+ /*
+ * some kind of archive read problem, try to resync the
+ * storage device, better give the user the bad news.
+ */
+ if ((ret == 0) || (rd_sync() < 0)) {
+ paxwarn(1,"Premature end of file on archive read");
+ return(-1);
+ }
+ if (!in_resync) {
+ if (act == APPND) {
+ paxwarn(1,
+ "Archive I/O error, cannot continue");
+ return(-1);
+ }
+ paxwarn(1,"Archive I/O error. Trying to recover.");
+ ++in_resync;
+ }
+
+ /*
+ * oh well, throw it all out and start over
+ */
+ res = hsz;
+ hdend = hdbuf;
+ }
+
+ /*
+ * ok we have a contiguous buffer of the right size. Call the
+ * format read routine. If this was not a valid header and this
+ * format stores trailers outside of the header, call the
+ * format specific trailer routine to check for a trailer. We
+ * have to watch out that we do not mis-identify file data or
+ * block padding as a header or trailer. Format specific
+ * trailer functions must NOT check for the trailer while we
+ * are running in resync mode. Some trailer functions may tell
+ * us that this block cannot contain a valid header either, so
+ * we then throw out the entire block and start over.
+ */
+ if ((*frmt->rd)(arcn, hdbuf) == 0)
+ break;
+
+ if (!frmt->inhead) {
+ /*
+ * this format has trailers outside of valid headers
+ */
+ if ((ret = (*frmt->trail)(arcn,hdbuf,in_resync,&cnt)) == 0){
+ /*
+ * valid trailer found, drain input as required
+ */
+ ar_drain();
+ return(-1);
+ }
+
+ if (ret == 1) {
+ /*
+ * we are in resync and we were told to throw
+ * the whole block out because none of the
+ * bytes in this block can be used to form a
+ * valid header
+ */
+ res = hsz;
+ hdend = hdbuf;
+ continue;
+ }
+ }
+
+ /*
+ * Brute force section.
+ * not a valid header. We may be able to find a header yet. So
+ * we shift over by one byte, and set up to read one byte at a
+ * time from the archive and place it at the end of the buffer.
+ * We will keep moving byte at a time until we find a header or
+ * get a read error and have to start over.
+ */
+ if (!in_resync) {
+ if (act == APPND) {
+ paxwarn(1,"Unable to append, archive header flaw");
+ return(-1);
+ }
+ paxwarn(1,"Invalid header, starting valid header search.");
+ ++in_resync;
+ }
+ memmove(hdbuf, hdbuf+1, shftsz);
+ res = 1;
+ hdend = hdbuf + shftsz;
+ }
+
+ /*
+ * ok got a valid header, check for trailer if format encodes it in the
+ * the header. NOTE: the parameters are different than trailer routines
+ * which encode trailers outside of the header!
+ */
+ if (frmt->inhead && ((*frmt->trail)(arcn,NULL,0,NULL) == 0)) {
+ /*
+ * valid trailer found, drain input as required
+ */
+ ar_drain();
+ return(-1);
+ }
+
+ ++flcnt;
+ return(0);
+}
+
+/*
+ * get_arc()
+ * Figure out what format an archive is. Handles archive with flaws by
+ * brute force searches for a legal header in any supported format. The
+ * format id routines have to be careful to NOT mis-identify a format.
+ * ASSUMED: headers fit within a BLKMULT header.
+ * Return:
+ * 0 if archive found -1 otherwise
+ */
+
+static int
+get_arc(void)
+{
+ int i;
+ int hdsz = 0;
+ int res;
+ int minhd = BLKMULT;
+ char *hdend;
+ int notice = 0;
+
+ /*
+ * find the smallest header size in all archive formats and then set up
+ * to read the archive.
+ */
+ for (i = 0; ford[i] >= 0; ++i) {
+ if (fsub[ford[i]].hsz < minhd)
+ minhd = fsub[ford[i]].hsz;
+ }
+ if (rd_start() < 0)
+ return(-1);
+ res = BLKMULT;
+ hdsz = 0;
+ hdend = hdbuf;
+ for (;;) {
+ for (;;) {
+ /*
+ * fill the buffer with at least the smallest header
+ */
+ i = rd_wrbuf(hdend, res);
+ if (i > 0)
+ hdsz += i;
+ if (hdsz >= minhd)
+ break;
+
+ /*
+ * if we cannot recover from a read error quit
+ */
+ if ((i == 0) || (rd_sync() < 0))
+ goto out;
+
+ /*
+ * when we get an error none of the data we already
+ * have can be used to create a legal header (we just
+ * got an error in the middle), so we throw it all out
+ * and refill the buffer with fresh data.
+ */
+ res = BLKMULT;
+ hdsz = 0;
+ hdend = hdbuf;
+ if (!notice) {
+ if (act == APPND)
+ return(-1);
+ paxwarn(1,"Cannot identify format. Searching...");
+ ++notice;
+ }
+ }
+
+ /*
+ * we have at least the size of the smallest header in any
+ * archive format. Look to see if we have a match. The array
+ * ford[] is used to specify the header id order to reduce the
+ * chance of incorrectly id'ing a valid header (some formats
+ * may be subsets of each other and the order would then be
+ * important).
+ */
+ for (i = 0; ford[i] >= 0; ++i) {
+ if ((*fsub[ford[i]].id)(hdbuf, hdsz) < 0)
+ continue;
+ frmt = &(fsub[ford[i]]);
+ /*
+ * yuck, to avoid slow special case code in the extract
+ * routines, just push this header back as if it was
+ * not seen. We have left extra space at start of the
+ * buffer for this purpose. This is a bit ugly, but
+ * adding all the special case code is far worse.
+ */
+ pback(hdbuf, hdsz);
+ return(0);
+ }
+
+ /*
+ * We have a flawed archive, no match. we start searching, but
+ * we never allow additions to flawed archives
+ */
+ if (!notice) {
+ if (act == APPND)
+ return(-1);
+ paxwarn(1, "Cannot identify format. Searching...");
+ ++notice;
+ }
+
+ /*
+ * brute force search for a header that we can id.
+ * we shift through byte at a time. this is slow, but we cannot
+ * determine the nature of the flaw in the archive in a
+ * portable manner
+ */
+ if (--hdsz > 0) {
+ memmove(hdbuf, hdbuf+1, hdsz);
+ res = BLKMULT - hdsz;
+ hdend = hdbuf + hdsz;
+ } else {
+ res = BLKMULT;
+ hdend = hdbuf;
+ hdsz = 0;
+ }
+ }
+
+ out:
+ /*
+ * we cannot find a header, bow, apologize and quit
+ */
+ paxwarn(1, "Sorry, unable to determine archive format.");
+ return(-1);
+}
diff --git a/file_cmds/pax/buf_subs.c b/file_cmds/pax/buf_subs.c
new file mode 100644
index 0000000..e56e822
--- /dev/null
+++ b/file_cmds/pax/buf_subs.c
@@ -0,0 +1,994 @@
+/* $OpenBSD: buf_subs.c,v 1.21 2005/11/09 19:59:06 otto Exp $ */
+/* $NetBSD: buf_subs.c,v 1.5 1995/03/21 09:07:08 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)buf_subs.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: buf_subs.c,v 1.21 2005/11/09 19:59:06 otto Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pax.h"
+#include "extern.h"
+
+/*
+ * routines which implement archive and file buffering
+ */
+
+#define MINFBSZ 512 /* default block size for hole detect */
+#define MAXFLT 10 /* default media read error limit */
+
+/*
+ * Need to change bufmem to dynamic allocation when the upper
+ * limit on blocking size is removed (though that will violate pax spec)
+ * MAXBLK define and tests will also need to be updated.
+ */
+static char bufmem[MAXBLK+BLKMULT]; /* i/o buffer + pushback id space */
+static char *buf; /* normal start of i/o buffer */
+static char *bufend; /* end or last char in i/o buffer */
+static char *bufpt; /* read/write point in i/o buffer */
+int blksz = MAXBLK; /* block input/output size in bytes */
+int wrblksz; /* user spec output size in bytes */
+int maxflt = MAXFLT; /* MAX consecutive media errors */
+int rdblksz; /* first read blksize (tapes only) */
+off_t wrlimit; /* # of bytes written per archive vol */
+off_t wrcnt; /* # of bytes written on current vol */
+off_t rdcnt; /* # of bytes read on current vol */
+
+/*
+ * wr_start()
+ * set up the buffering system to operate in a write mode
+ * Return:
+ * 0 if ok, -1 if the user specified write block size violates pax spec
+ */
+
+int
+wr_start(void)
+{
+ buf = &(bufmem[BLKMULT]);
+ /*
+ * Check to make sure the write block size meets pax specs. If the user
+ * does not specify a blocksize, we use the format default blocksize.
+ * We must be picky on writes, so we do not allow the user to create an
+ * archive that might be hard to read elsewhere. If all ok, we then
+ * open the first archive volume
+ */
+ if (!wrblksz)
+ wrblksz = frmt->bsz;
+ if (wrblksz > MAXBLK) {
+ paxwarn(1, "Write block size of %d too large, maximium is: %d",
+ wrblksz, MAXBLK);
+ return(-1);
+ }
+ if (wrblksz % BLKMULT) {
+ paxwarn(1, "Write block size of %d is not a %d byte multiple",
+ wrblksz, BLKMULT);
+ return(-1);
+ }
+ if (wrblksz > MAXBLK_POSIX) {
+ paxwarn(0, "Write block size of %d larger than POSIX max %d, archive may not be portable",
+ wrblksz, MAXBLK_POSIX);
+ return(-1);
+ }
+
+ /*
+ * we only allow wrblksz to be used with all archive operations
+ */
+ blksz = rdblksz = wrblksz;
+ if ((ar_open(arcname) < 0) && (ar_next() < 0))
+ return(-1);
+ wrcnt = 0;
+ bufend = buf + wrblksz;
+ bufpt = buf;
+ return(0);
+}
+
+/*
+ * rd_start()
+ * set up buffering system to read an archive
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+rd_start(void)
+{
+ /*
+ * leave space for the header pushback (see get_arc()). If we are
+ * going to append and user specified a write block size, check it
+ * right away
+ */
+ buf = &(bufmem[BLKMULT]);
+ if ((act == APPND) && wrblksz) {
+ if (wrblksz > MAXBLK) {
+ paxwarn(1,"Write block size %d too large, maximium is: %d",
+ wrblksz, MAXBLK);
+ return(-1);
+ }
+ if (wrblksz % BLKMULT) {
+ paxwarn(1, "Write block size %d is not a %d byte multiple",
+ wrblksz, BLKMULT);
+ return(-1);
+ }
+ }
+
+ /*
+ * open the archive
+ */
+ if ((ar_open(arcname) < 0) && (ar_next() < 0))
+ return(-1);
+ bufend = buf + rdblksz;
+ bufpt = bufend;
+ rdcnt = 0;
+ return(0);
+}
+
+/*
+ * cp_start()
+ * set up buffer system for copying within the file system
+ */
+
+void
+cp_start(void)
+{
+ buf = &(bufmem[BLKMULT]);
+ rdblksz = blksz = MAXBLK;
+}
+
+/*
+ * appnd_start()
+ * Set up the buffering system to append new members to an archive that
+ * was just read. The last block(s) of an archive may contain a format
+ * specific trailer. To append a new member, this trailer has to be
+ * removed from the archive. The first byte of the trailer is replaced by
+ * the start of the header of the first file added to the archive. The
+ * format specific end read function tells us how many bytes to move
+ * backwards in the archive to be positioned BEFORE the trailer. Two
+ * different position have to be adjusted, the O.S. file offset (e.g. the
+ * position of the tape head) and the write point within the data we have
+ * stored in the read (soon to become write) buffer. We may have to move
+ * back several records (the number depends on the size of the archive
+ * record and the size of the format trailer) to read up the record where
+ * the first byte of the trailer is recorded. Trailers may span (and
+ * overlap) record boundaries.
+ * We first calculate which record has the first byte of the trailer. We
+ * move the OS file offset back to the start of this record and read it
+ * up. We set the buffer write pointer to be at this byte (the byte where
+ * the trailer starts). We then move the OS file pointer back to the
+ * start of this record so a flush of this buffer will replace the record
+ * in the archive.
+ * A major problem is rewriting this last record. For archives stored
+ * on disk files, this is trivial. However, many devices are really picky
+ * about the conditions under which they will allow a write to occur.
+ * Often devices restrict the conditions where writes can be made,
+ * so it may not be feasible to append archives stored on all types of
+ * devices.
+ * Return:
+ * 0 for success, -1 for failure
+ */
+
+int
+appnd_start(off_t skcnt)
+{
+ int res;
+ off_t cnt;
+
+ if (exit_val != 0) {
+ paxwarn(0, "Cannot append to an archive that may have flaws.");
+ return(-1);
+ }
+ /*
+ * if the user did not specify a write blocksize, inherit the size used
+ * in the last archive volume read. (If a is set we still use rdblksz
+ * until next volume, cannot shift sizes within a single volume).
+ */
+ if (!wrblksz)
+ wrblksz = blksz = rdblksz;
+ else
+ blksz = rdblksz;
+
+ /*
+ * make sure that this volume allows appends
+ */
+ if (ar_app_ok() < 0)
+ return(-1);
+
+ /*
+ * Calculate bytes to move back and move in front of record where we
+ * need to start writing from. Remember we have to add in any padding
+ * that might be in the buffer after the trailer in the last block. We
+ * travel skcnt + padding ROUNDED UP to blksize.
+ */
+ skcnt += bufend - bufpt;
+ if ((cnt = (skcnt/blksz) * blksz) < skcnt)
+ cnt += blksz;
+ if (ar_rev((off_t)cnt) < 0)
+ goto out;
+
+ /*
+ * We may have gone too far if there is valid data in the block we are
+ * now in front of, read up the block and position the pointer after
+ * the valid data.
+ */
+ if ((cnt -= skcnt) > 0) {
+ /*
+ * watch out for stupid tape drives. ar_rev() will set rdblksz
+ * to be real physical blocksize so we must loop until we get
+ * the old rdblksz (now in blksz). If ar_rev() fouls up the
+ * determination of the physical block size, we will fail.
+ */
+ bufpt = buf;
+ bufend = buf + blksz;
+ while (bufpt < bufend) {
+ if ((res = ar_read(bufpt, rdblksz)) <= 0)
+ goto out;
+ bufpt += res;
+ }
+ if (ar_rev((off_t)(bufpt - buf)) < 0)
+ goto out;
+ bufpt = buf + cnt;
+ bufend = buf + blksz;
+ } else {
+ /*
+ * buffer is empty
+ */
+ bufend = buf + blksz;
+ bufpt = buf;
+ }
+ rdblksz = blksz;
+ rdcnt -= skcnt;
+ wrcnt = 0;
+
+ /*
+ * At this point we are ready to write. If the device requires special
+ * handling to write at a point were previously recorded data resides,
+ * that is handled in ar_set_wr(). From now on we operate under normal
+ * ARCHIVE mode (write) conditions
+ */
+ if (ar_set_wr() < 0)
+ return(-1);
+ act = ARCHIVE;
+ return(0);
+
+ out:
+ paxwarn(1, "Unable to rewrite archive trailer, cannot append.");
+ return(-1);
+}
+
+/*
+ * rd_sync()
+ * A read error occurred on this archive volume. Resync the buffer and
+ * try to reset the device (if possible) so we can continue to read. Keep
+ * trying to do this until we get a valid read, or we reach the limit on
+ * consecutive read faults (at which point we give up). The user can
+ * adjust the read error limit through a command line option.
+ * Returns:
+ * 0 on success, and -1 on failure
+ */
+
+int
+rd_sync(void)
+{
+ int errcnt = 0;
+ int res;
+
+ /*
+ * if the user says bail out on first fault, we are out of here...
+ */
+ if (maxflt == 0)
+ return(-1);
+ if (act == APPND) {
+ paxwarn(1, "Unable to append when there are archive read errors.");
+ return(-1);
+ }
+
+ /*
+ * poke at device and try to get past media error
+ */
+ if (ar_rdsync() < 0) {
+ if (ar_next() < 0)
+ return(-1);
+ else
+ rdcnt = 0;
+ }
+
+ for (;;) {
+ if ((res = ar_read(buf, blksz)) > 0) {
+ /*
+ * All right! got some data, fill that buffer
+ */
+ bufpt = buf;
+ bufend = buf + res;
+ rdcnt += res;
+ return(0);
+ }
+
+ /*
+ * Oh well, yet another failed read...
+ * if error limit reached, ditch. o.w. poke device to move past
+ * bad media and try again. if media is badly damaged, we ask
+ * the poor (and upset user at this point) for the next archive
+ * volume. remember the goal on reads is to get the most we
+ * can extract out of the archive.
+ */
+ if ((maxflt > 0) && (++errcnt > maxflt))
+ paxwarn(0,"Archive read error limit (%d) reached",maxflt);
+ else if (ar_rdsync() == 0)
+ continue;
+ if (ar_next() < 0)
+ break;
+ rdcnt = 0;
+ errcnt = 0;
+ }
+ return(-1);
+}
+
+/*
+ * pback()
+ * push the data used during the archive id phase back into the I/O
+ * buffer. This is required as we cannot be sure that the header does NOT
+ * overlap a block boundary (as in the case we are trying to recover a
+ * flawed archived). This was not designed to be used for any other
+ * purpose. (What software engineering, HA!)
+ * WARNING: do not even THINK of pback greater than BLKMULT, unless the
+ * pback space is increased.
+ */
+
+void
+pback(char *pt, int cnt)
+{
+ bufpt -= cnt;
+ memcpy(bufpt, pt, cnt);
+ return;
+}
+
+/*
+ * rd_skip()
+ * skip forward in the archive during a archive read. Used to get quickly
+ * past file data and padding for files the user did NOT select.
+ * Return:
+ * 0 if ok, -1 failure, and 1 when EOF on the archive volume was detected.
+ */
+
+int
+rd_skip(off_t skcnt)
+{
+ off_t res;
+ off_t cnt;
+ off_t skipped = 0;
+
+ /*
+ * consume what data we have in the buffer. If we have to move forward
+ * whole records, we call the low level skip function to see if we can
+ * move within the archive without doing the expensive reads on data we
+ * do not want.
+ */
+ if (skcnt == 0)
+ return(0);
+ res = MIN((bufend - bufpt), skcnt);
+ bufpt += res;
+ skcnt -= res;
+
+ /*
+ * if skcnt is now 0, then no additional i/o is needed
+ */
+ if (skcnt == 0)
+ return(0);
+
+ /*
+ * We have to read more, calculate complete and partial record reads
+ * based on rdblksz. we skip over "cnt" complete records
+ */
+ res = skcnt%rdblksz;
+ cnt = (skcnt/rdblksz) * rdblksz;
+
+ /*
+ * if the skip fails, we will have to resync. ar_fow will tell us
+ * how much it can skip over. We will have to read the rest.
+ */
+ if (ar_fow(cnt, &skipped) < 0)
+ return(-1);
+ res += cnt - skipped;
+ rdcnt += skipped;
+
+ /*
+ * what is left we have to read (which may be the whole thing if
+ * ar_fow() told us the device can only read to skip records);
+ */
+ while (res > 0L) {
+ cnt = bufend - bufpt;
+ /*
+ * if the read fails, we will have to resync
+ */
+ if ((cnt <= 0) && ((cnt = buf_fill()) < 0))
+ return(-1);
+ if (cnt == 0)
+ return(1);
+ cnt = MIN(cnt, res);
+ bufpt += cnt;
+ res -= cnt;
+ }
+ return(0);
+}
+
+/*
+ * wr_fin()
+ * flush out any data (and pad if required) the last block. We always pad
+ * with zero (even though we do not have to). Padding with 0 makes it a
+ * lot easier to recover if the archive is damaged. zero padding SHOULD
+ * BE a requirement....
+ */
+
+void
+wr_fin(void)
+{
+ if (bufpt > buf) {
+ memset(bufpt, 0, bufend - bufpt);
+ bufpt = bufend;
+ (void)buf_flush(blksz);
+ }
+}
+
+/*
+ * wr_rdbuf()
+ * fill the write buffer from data passed to it in a buffer (usually used
+ * by format specific write routines to pass a file header). On failure we
+ * punt. We do not allow the user to continue to write flawed archives.
+ * We assume these headers are not very large (the memory copy we use is
+ * a bit expensive).
+ * Return:
+ * 0 if buffer was filled ok, -1 o.w. (buffer flush failure)
+ */
+
+int
+wr_rdbuf(char *out, int outcnt)
+{
+ int cnt;
+
+ /*
+ * while there is data to copy copy into the write buffer. when the
+ * write buffer fills, flush it to the archive and continue
+ */
+ while (outcnt > 0) {
+ cnt = bufend - bufpt;
+ if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0))
+ return(-1);
+ /*
+ * only move what we have space for
+ */
+ cnt = MIN(cnt, outcnt);
+ memcpy(bufpt, out, cnt);
+ bufpt += cnt;
+ out += cnt;
+ outcnt -= cnt;
+ }
+ return(0);
+}
+
+/*
+ * rd_wrbuf()
+ * copy from the read buffer into a supplied buffer a specified number of
+ * bytes. If the read buffer is empty fill it and continue to copy.
+ * usually used to obtain a file header for processing by a format
+ * specific read routine.
+ * Return
+ * number of bytes copied to the buffer, 0 indicates EOF on archive volume,
+ * -1 is a read error
+ */
+
+int
+rd_wrbuf(char *in, int cpcnt)
+{
+ int res;
+ int cnt;
+ int incnt = cpcnt;
+
+ /*
+ * loop until we fill the buffer with the requested number of bytes
+ */
+ while (incnt > 0) {
+ cnt = bufend - bufpt;
+ if ((cnt <= 0) && ((cnt = buf_fill()) <= 0)) {
+ /*
+ * read error, return what we got (or the error if
+ * no data was copied). The caller must know that an
+ * error occurred and has the best knowledge what to
+ * do with it
+ */
+ if ((res = cpcnt - incnt) > 0)
+ return(res);
+ return(cnt);
+ }
+
+ /*
+ * calculate how much data to copy based on whats left and
+ * state of buffer
+ */
+ cnt = MIN(cnt, incnt);
+ memcpy(in, bufpt, cnt);
+ bufpt += cnt;
+ incnt -= cnt;
+ in += cnt;
+ }
+ return(cpcnt);
+}
+
+/*
+ * wr_skip()
+ * skip forward during a write. In other words add padding to the file.
+ * we add zero filled padding as it makes flawed archives much easier to
+ * recover from. the caller tells us how many bytes of padding to add
+ * This routine was not designed to add HUGE amount of padding, just small
+ * amounts (a few 512 byte blocks at most)
+ * Return:
+ * 0 if ok, -1 if there was a buf_flush failure
+ */
+
+int
+wr_skip(off_t skcnt)
+{
+ int cnt;
+
+ /*
+ * loop while there is more padding to add
+ */
+ while (skcnt > 0L) {
+ cnt = bufend - bufpt;
+ if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0))
+ return(-1);
+ cnt = MIN(cnt, skcnt);
+ memset(bufpt, 0, cnt);
+ bufpt += cnt;
+ skcnt -= cnt;
+ }
+ return(0);
+}
+
+/*
+ * wr_rdfile()
+ * fill write buffer with the contents of a file. We are passed an open
+ * file descriptor to the file an the archive structure that describes the
+ * file we are storing. The variable "left" is modified to contain the
+ * number of bytes of the file we were NOT able to write to the archive.
+ * it is important that we always write EXACTLY the number of bytes that
+ * the format specific write routine told us to. The file can also get
+ * bigger, so reading to the end of file would create an improper archive,
+ * we just detect this case and warn the user. We never create a bad
+ * archive if we can avoid it. Of course trying to archive files that are
+ * active is asking for trouble. It we fail, we pass back how much we
+ * could NOT copy and let the caller deal with it.
+ * Return:
+ * 0 ok, -1 if archive write failure. a short read of the file returns a
+ * 0, but "left" is set to be greater than zero.
+ */
+
+int
+wr_rdfile(ARCHD *arcn, int ifd, off_t *left)
+{
+ int cnt;
+ int res = 0;
+ off_t size = arcn->sb.st_size;
+ struct stat sb;
+
+ /*
+ * while there are more bytes to write
+ */
+ while (size > 0L) {
+ cnt = bufend - bufpt;
+ if ((cnt <= 0) && ((cnt = buf_flush(blksz)) < 0)) {
+ *left = size;
+ return(-1);
+ }
+ cnt = MIN(cnt, size);
+ if ((res = read(ifd, bufpt, cnt)) <= 0)
+ break;
+ size -= res;
+ bufpt += res;
+ }
+
+ /*
+ * better check the file did not change during this operation
+ * or the file read failed.
+ */
+ if (res < 0)
+ syswarn(1, errno, "Read fault on %s", arcn->org_name);
+ else if (size != 0L)
+ paxwarn(1, "File changed size during read %s", arcn->org_name);
+ else if (fstat(ifd, &sb) < 0)
+ syswarn(1, errno, "Failed stat on %s", arcn->org_name);
+ else if (arcn->sb.st_mtime != sb.st_mtime)
+ paxwarn(1, "File %s was modified during copy to archive",
+ arcn->org_name);
+ *left = size;
+ return(0);
+}
+
+/*
+ * rd_wrfile()
+ * extract the contents of a file from the archive. If we are unable to
+ * extract the entire file (due to failure to write the file) we return
+ * the numbers of bytes we did NOT process. This way the caller knows how
+ * many bytes to skip past to find the next archive header. If the failure
+ * was due to an archive read, we will catch that when we try to skip. If
+ * the format supplies a file data crc value, we calculate the actual crc
+ * so that it can be compared to the value stored in the header
+ * NOTE:
+ * We call a special function to write the file. This function attempts to
+ * restore file holes (blocks of zeros) into the file. When files are
+ * sparse this saves space, and is a LOT faster. For non sparse files
+ * the performance hit is small. As of this writing, no archive supports
+ * information on where the file holes are.
+ * Return:
+ * 0 ok, -1 if archive read failure. if we cannot write the entire file,
+ * we return a 0 but "left" is set to be the amount unwritten
+ */
+
+int
+rd_wrfile(ARCHD *arcn, int ofd, off_t *left)
+{
+ int cnt = 0;
+ off_t size = arcn->sb.st_size;
+ int res = 0;
+ char *fnm = arcn->name;
+ int isem = 1;
+ int rem;
+ int sz = MINFBSZ;
+ struct stat sb;
+ u_int32_t crc = 0;
+
+ /*
+ * pass the blocksize of the file being written to the write routine,
+ * if the size is zero, use the default MINFBSZ
+ */
+ if (ofd < 0)
+ sz = PAXPATHLEN + 1; /* GNU tar long link/file */
+ else if (fstat(ofd, &sb) == 0) {
+ if (sb.st_blksize > 0)
+ sz = (int)sb.st_blksize;
+ } else
+ syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
+ rem = sz;
+ *left = 0L;
+
+ /*
+ * Copy the archive to the file the number of bytes specified. We have
+ * to assume that we want to recover file holes as none of the archive
+ * formats can record the location of file holes.
+ */
+ while (size > 0L) {
+ cnt = bufend - bufpt;
+ /*
+ * if we get a read error, we do not want to skip, as we may
+ * miss a header, so we do not set left, but if we get a write
+ * error, we do want to skip over the unprocessed data.
+ */
+ if ((cnt <= 0) && ((cnt = buf_fill()) <= 0))
+ break;
+ cnt = MIN(cnt, size);
+ if ((res = file_write(ofd,bufpt,cnt,&rem,&isem,sz,fnm)) <= 0) {
+ *left = size;
+ break;
+ }
+
+ if (docrc) {
+ /*
+ * update the actual crc value
+ */
+ cnt = res;
+ while (--cnt >= 0)
+ crc += *bufpt++ & 0xff;
+ } else
+ bufpt += res;
+ size -= res;
+ }
+
+ /*
+ * if the last block has a file hole (all zero), we must make sure this
+ * gets updated in the file. We force the last block of zeros to be
+ * written. just closing with the file offset moved forward may not put
+ * a hole at the end of the file.
+ */
+ if (isem && (arcn->sb.st_size > 0L))
+ file_flush(ofd, fnm, isem);
+
+ /*
+ * if we failed from archive read, we do not want to skip
+ */
+ if ((size > 0L) && (*left == 0L))
+ return(-1);
+
+ /*
+ * some formats record a crc on file data. If so, then we compare the
+ * calculated crc to the crc stored in the archive
+ */
+ if (docrc && (size == 0L) && (arcn->crc != crc))
+ paxwarn(1,"Actual crc does not match expected crc %s",arcn->name);
+ return(0);
+}
+
+/*
+ * cp_file()
+ * copy the contents of one file to another. used during -rw phase of pax
+ * just as in rd_wrfile() we use a special write function to write the
+ * destination file so we can properly copy files with holes.
+ */
+
+void
+cp_file(ARCHD *arcn, int fd1, int fd2)
+{
+ int cnt;
+ off_t cpcnt = 0L;
+ int res = 0;
+ char *fnm = arcn->name;
+ int no_hole = 0;
+ int isem = 1;
+ int rem;
+ int sz = MINFBSZ;
+ struct stat sb;
+
+ /*
+ * check for holes in the source file. If none, we will use regular
+ * write instead of file write.
+ */
+ if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size)
+ ++no_hole;
+
+ /*
+ * pass the blocksize of the file being written to the write routine,
+ * if the size is zero, use the default MINFBSZ
+ */
+ if (fstat(fd2, &sb) == 0) {
+ if (sb.st_blksize > 0)
+ sz = sb.st_blksize;
+ } else
+ syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
+ rem = sz;
+
+ /*
+ * read the source file and copy to destination file until EOF
+ */
+ for (;;) {
+ if ((cnt = read(fd1, buf, blksz)) <= 0)
+ break;
+ if (no_hole)
+ res = write(fd2, buf, cnt);
+ else
+ res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm);
+ if (res != cnt)
+ break;
+ cpcnt += cnt;
+ }
+
+ /*
+ * check to make sure the copy is valid.
+ */
+ if (res < 0)
+ syswarn(1, errno, "Failed write during copy of %s to %s",
+ arcn->org_name, arcn->name);
+ else if (cpcnt != arcn->sb.st_size)
+ paxwarn(1, "File %s changed size during copy to %s",
+ arcn->org_name, arcn->name);
+ else if (fstat(fd1, &sb) < 0)
+ syswarn(1, errno, "Failed stat of %s", arcn->org_name);
+ else if (arcn->sb.st_mtime != sb.st_mtime)
+ paxwarn(1, "File %s was modified during copy to %s",
+ arcn->org_name, arcn->name);
+
+ /*
+ * if the last block has a file hole (all zero), we must make sure this
+ * gets updated in the file. We force the last block of zeros to be
+ * written. just closing with the file offset moved forward may not put
+ * a hole at the end of the file.
+ */
+ if (!no_hole && isem && (arcn->sb.st_size > 0L))
+ file_flush(fd2, fnm, isem);
+ return;
+}
+
+/*
+ * buf_fill()
+ * fill the read buffer with the next record (or what we can get) from
+ * the archive volume.
+ * Return:
+ * Number of bytes of data in the read buffer, -1 for read error, and
+ * 0 when finished (user specified termination in ar_next()).
+ */
+
+int
+buf_fill(void)
+{
+ int cnt;
+ static int fini = 0;
+
+ if (fini)
+ return(0);
+
+ for (;;) {
+ /*
+ * try to fill the buffer. on error the next archive volume is
+ * opened and we try again.
+ */
+ if ((cnt = ar_read(buf, blksz)) > 0) {
+ bufpt = buf;
+ bufend = buf + cnt;
+ rdcnt += cnt;
+ return(cnt);
+ }
+
+ /*
+ * errors require resync, EOF goes to next archive
+ */
+ if (cnt < 0)
+ break;
+ if (ar_next() < 0) {
+ fini = 1;
+ return(0);
+ }
+ rdcnt = 0;
+ }
+ exit_val = 1;
+ return(-1);
+}
+
+/*
+ * buf_flush()
+ * force the write buffer to the archive. We are passed the number of
+ * bytes in the buffer at the point of the flush. When we change archives
+ * the record size might change. (either larger or smaller).
+ * Return:
+ * 0 if all is ok, -1 when a write error occurs.
+ */
+
+int
+buf_flush(int bufcnt)
+{
+ int cnt;
+ int push = 0;
+ int totcnt = 0;
+
+ /*
+ * if we have reached the user specified byte count for each archive
+ * volume, prompt for the next volume. (The non-standard -R flag).
+ * NOTE: If the wrlimit is smaller than wrcnt, we will always write
+ * at least one record. We always round limit UP to next blocksize.
+ */
+ if ((wrlimit > 0) && (wrcnt > wrlimit)) {
+ paxwarn(0, "User specified archive volume byte limit reached.");
+ if (ar_next() < 0) {
+ wrcnt = 0;
+ exit_val = 1;
+ return(-1);
+ }
+ wrcnt = 0;
+
+ /*
+ * The new archive volume might have changed the size of the
+ * write blocksize. if so we figure out if we need to write
+ * (one or more times), or if there is now free space left in
+ * the buffer (it is no longer full). bufcnt has the number of
+ * bytes in the buffer, (the blocksize, at the point we were
+ * CALLED). Push has the amount of "extra" data in the buffer
+ * if the block size has shrunk from a volume change.
+ */
+ bufend = buf + blksz;
+ if (blksz > bufcnt)
+ return(0);
+ if (blksz < bufcnt)
+ push = bufcnt - blksz;
+ }
+
+ /*
+ * We have enough data to write at least one archive block
+ */
+ for (;;) {
+ /*
+ * write a block and check if it all went out ok
+ */
+ cnt = ar_write(buf, blksz);
+ if (cnt == blksz) {
+ /*
+ * the write went ok
+ */
+ wrcnt += cnt;
+ totcnt += cnt;
+ if (push > 0) {
+ /* we have extra data to push to the front.
+ * check for more than 1 block of push, and if
+ * so we loop back to write again
+ */
+ memcpy(buf, bufend, push);
+ bufpt = buf + push;
+ if (push >= blksz) {
+ push -= blksz;
+ continue;
+ }
+ } else
+ bufpt = buf;
+ return(totcnt);
+ } else if (cnt > 0) {
+ /*
+ * Oh drat we got a partial write!
+ * if format doesnt care about alignment let it go,
+ * we warned the user in ar_write().... but this means
+ * the last record on this volume violates pax spec....
+ */
+ totcnt += cnt;
+ wrcnt += cnt;
+ bufpt = buf + cnt;
+ cnt = bufcnt - cnt;
+ memcpy(buf, bufpt, cnt);
+ bufpt = buf + cnt;
+ if (!frmt->blkalgn || ((cnt % frmt->blkalgn) == 0))
+ return(totcnt);
+ break;
+ }
+
+ /*
+ * All done, go to next archive
+ */
+ wrcnt = 0;
+ if (ar_next() < 0)
+ break;
+
+ /*
+ * The new archive volume might also have changed the block
+ * size. if so, figure out if we have too much or too little
+ * data for using the new block size
+ */
+ bufend = buf + blksz;
+ if (blksz > bufcnt)
+ return(0);
+ if (blksz < bufcnt)
+ push = bufcnt - blksz;
+ }
+
+ /*
+ * write failed, stop pax. we must not create a bad archive!
+ */
+ exit_val = 1;
+ return(-1);
+}
diff --git a/file_cmds/pax/cache.c b/file_cmds/pax/cache.c
new file mode 100644
index 0000000..e5c4996
--- /dev/null
+++ b/file_cmds/pax/cache.c
@@ -0,0 +1,426 @@
+/* $OpenBSD: cache.c,v 1.17 2004/03/16 03:28:34 tedu Exp $ */
+/* $NetBSD: cache.c,v 1.4 1995/03/21 09:07:10 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)cache.c 8.1 (Berkeley) 5/31/93";
+#else
+__used static const char rcsid[] = "$OpenBSD: cache.c,v 1.17 2004/03/16 03:28:34 tedu Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdio.h>
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "cache.h"
+#include "extern.h"
+
+/*
+ * routines that control user, group, uid and gid caches (for the archive
+ * member print routine).
+ * IMPORTANT:
+ * these routines cache BOTH hits and misses, a major performance improvement
+ */
+
+static int pwopn = 0; /* is password file open */
+static int gropn = 0; /* is group file open */
+static UIDC **uidtb = NULL; /* uid to name cache */
+static GIDC **gidtb = NULL; /* gid to name cache */
+static UIDC **usrtb = NULL; /* user name to uid cache */
+static GIDC **grptb = NULL; /* group name to gid cache */
+
+/*
+ * uidtb_start
+ * creates an empty uidtb
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+uidtb_start(void)
+{
+ static int fail = 0;
+
+ if (uidtb != NULL)
+ return(0);
+ if (fail)
+ return(-1);
+ if ((uidtb = (UIDC **)calloc(UID_SZ, sizeof(UIDC *))) == NULL) {
+ ++fail;
+ paxwarn(1, "Unable to allocate memory for user id cache table");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * gidtb_start
+ * creates an empty gidtb
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+gidtb_start(void)
+{
+ static int fail = 0;
+
+ if (gidtb != NULL)
+ return(0);
+ if (fail)
+ return(-1);
+ if ((gidtb = (GIDC **)calloc(GID_SZ, sizeof(GIDC *))) == NULL) {
+ ++fail;
+ paxwarn(1, "Unable to allocate memory for group id cache table");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * usrtb_start
+ * creates an empty usrtb
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+usrtb_start(void)
+{
+ static int fail = 0;
+
+ if (usrtb != NULL)
+ return(0);
+ if (fail)
+ return(-1);
+ if ((usrtb = (UIDC **)calloc(UNM_SZ, sizeof(UIDC *))) == NULL) {
+ ++fail;
+ paxwarn(1, "Unable to allocate memory for user name cache table");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * grptb_start
+ * creates an empty grptb
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+grptb_start(void)
+{
+ static int fail = 0;
+
+ if (grptb != NULL)
+ return(0);
+ if (fail)
+ return(-1);
+ if ((grptb = (GIDC **)calloc(GNM_SZ, sizeof(GIDC *))) == NULL) {
+ ++fail;
+ paxwarn(1,"Unable to allocate memory for group name cache table");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * name_uid()
+ * caches the name (if any) for the uid. If frc set, we always return the
+ * the stored name (if valid or invalid match). We use a simple hash table.
+ * Return
+ * Pointer to stored name (or a empty string)
+ */
+
+char *
+name_uid(uid_t uid, int frc)
+{
+ struct passwd *pw;
+ UIDC *ptr;
+
+ if ((uidtb == NULL) && (uidtb_start() < 0))
+ return("");
+
+ /*
+ * see if we have this uid cached
+ */
+ ptr = uidtb[uid % UID_SZ];
+ if ((ptr != NULL) && (ptr->valid > 0) && (ptr->uid == uid)) {
+ /*
+ * have an entry for this uid
+ */
+ if (frc || (ptr->valid == VALID))
+ return(ptr->name);
+ return("");
+ }
+
+ /*
+ * No entry for this uid, we will add it
+ */
+ if (!pwopn) {
+ setpassent(1);
+ ++pwopn;
+ }
+ if (ptr == NULL)
+ ptr = uidtb[uid % UID_SZ] = malloc(sizeof(UIDC));
+
+ if ((pw = getpwuid(uid)) == NULL) {
+ /*
+ * no match for this uid in the local password file
+ * a string that is the uid in numeric format
+ */
+ if (ptr == NULL)
+ return("");
+ ptr->uid = uid;
+ ptr->valid = INVALID;
+ (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
+ (unsigned long)uid);
+ if (frc == 0)
+ return("");
+ } else {
+ /*
+ * there is an entry for this uid in the password file
+ */
+ if (ptr == NULL)
+ return(pw->pw_name);
+ ptr->uid = uid;
+ (void)strlcpy(ptr->name, pw->pw_name, sizeof(ptr->name));
+ ptr->valid = VALID;
+ }
+ return(ptr->name);
+}
+
+/*
+ * name_gid()
+ * caches the name (if any) for the gid. If frc set, we always return the
+ * the stored name (if valid or invalid match). We use a simple hash table.
+ * Return
+ * Pointer to stored name (or a empty string)
+ */
+
+char *
+name_gid(gid_t gid, int frc)
+{
+ struct group *gr;
+ GIDC *ptr;
+
+ if ((gidtb == NULL) && (gidtb_start() < 0))
+ return("");
+
+ /*
+ * see if we have this gid cached
+ */
+ ptr = gidtb[gid % GID_SZ];
+ if ((ptr != NULL) && (ptr->valid > 0) && (ptr->gid == gid)) {
+ /*
+ * have an entry for this gid
+ */
+ if (frc || (ptr->valid == VALID))
+ return(ptr->name);
+ return("");
+ }
+
+ /*
+ * No entry for this gid, we will add it
+ */
+ if (!gropn) {
+ setgroupent(1);
+ ++gropn;
+ }
+ if (ptr == NULL)
+ ptr = gidtb[gid % GID_SZ] = malloc(sizeof(GIDC));
+
+ if ((gr = getgrgid(gid)) == NULL) {
+ /*
+ * no match for this gid in the local group file, put in
+ * a string that is the gid in numberic format
+ */
+ if (ptr == NULL)
+ return("");
+ ptr->gid = gid;
+ ptr->valid = INVALID;
+ (void)snprintf(ptr->name, sizeof(ptr->name), "%lu",
+ (unsigned long)gid);
+ if (frc == 0)
+ return("");
+ } else {
+ /*
+ * there is an entry for this group in the group file
+ */
+ if (ptr == NULL)
+ return(gr->gr_name);
+ ptr->gid = gid;
+ (void)strlcpy(ptr->name, gr->gr_name, sizeof(ptr->name));
+ ptr->valid = VALID;
+ }
+ return(ptr->name);
+}
+
+/*
+ * uid_name()
+ * caches the uid for a given user name. We use a simple hash table.
+ * Return
+ * the uid (if any) for a user name, or a -1 if no match can be found
+ */
+
+int
+uid_name(char *name, uid_t *uid)
+{
+ struct passwd *pw;
+ UIDC *ptr;
+ int namelen;
+
+ /*
+ * return -1 for mangled names
+ */
+ if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
+ return(-1);
+ if ((usrtb == NULL) && (usrtb_start() < 0))
+ return(-1);
+
+ /*
+ * look up in hash table, if found and valid return the uid,
+ * if found and invalid, return a -1
+ */
+ ptr = usrtb[st_hash(name, namelen, UNM_SZ)];
+ if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
+ if (ptr->valid == INVALID)
+ return(-1);
+ *uid = ptr->uid;
+ return(0);
+ }
+
+ if (!pwopn) {
+ setpassent(1);
+ ++pwopn;
+ }
+
+ if (ptr == NULL)
+ ptr = usrtb[st_hash(name, namelen, UNM_SZ)] =
+ (UIDC *)malloc(sizeof(UIDC));
+
+ /*
+ * no match, look it up, if no match store it as an invalid entry,
+ * or store the matching uid
+ */
+ if (ptr == NULL) {
+ if ((pw = getpwnam(name)) == NULL)
+ return(-1);
+ *uid = pw->pw_uid;
+ return(0);
+ }
+ (void)strlcpy(ptr->name, name, sizeof(ptr->name));
+ if ((pw = getpwnam(name)) == NULL) {
+ ptr->valid = INVALID;
+ return(-1);
+ }
+ ptr->valid = VALID;
+ *uid = ptr->uid = pw->pw_uid;
+ return(0);
+}
+
+/*
+ * gid_name()
+ * caches the gid for a given group name. We use a simple hash table.
+ * Return
+ * the gid (if any) for a group name, or a -1 if no match can be found
+ */
+
+int
+gid_name(char *name, gid_t *gid)
+{
+ struct group *gr;
+ GIDC *ptr;
+ int namelen;
+
+ /*
+ * return -1 for mangled names
+ */
+ if (((namelen = strlen(name)) == 0) || (name[0] == '\0'))
+ return(-1);
+ if ((grptb == NULL) && (grptb_start() < 0))
+ return(-1);
+
+ /*
+ * look up in hash table, if found and valid return the uid,
+ * if found and invalid, return a -1
+ */
+ ptr = grptb[st_hash(name, namelen, GID_SZ)];
+ if ((ptr != NULL) && (ptr->valid > 0) && !strcmp(name, ptr->name)) {
+ if (ptr->valid == INVALID)
+ return(-1);
+ *gid = ptr->gid;
+ return(0);
+ }
+
+ if (!gropn) {
+ setgroupent(1);
+ ++gropn;
+ }
+ if (ptr == NULL)
+ ptr = grptb[st_hash(name, namelen, GID_SZ)] =
+ (GIDC *)malloc(sizeof(GIDC));
+
+ /*
+ * no match, look it up, if no match store it as an invalid entry,
+ * or store the matching gid
+ */
+ if (ptr == NULL) {
+ if ((gr = getgrnam(name)) == NULL)
+ return(-1);
+ *gid = gr->gr_gid;
+ return(0);
+ }
+
+ (void)strlcpy(ptr->name, name, sizeof(ptr->name));
+ if ((gr = getgrnam(name)) == NULL) {
+ ptr->valid = INVALID;
+ return(-1);
+ }
+ ptr->valid = VALID;
+ *gid = ptr->gid = gr->gr_gid;
+ return(0);
+}
diff --git a/file_cmds/pax/cache.h b/file_cmds/pax/cache.h
new file mode 100644
index 0000000..1a269d4
--- /dev/null
+++ b/file_cmds/pax/cache.h
@@ -0,0 +1,78 @@
+/* $OpenBSD: cache.h,v 1.4 2003/10/20 06:22:27 jmc Exp $ */
+/* $NetBSD: cache.h,v 1.3 1995/03/21 09:07:12 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cache.h 8.1 (Berkeley) 5/31/93
+ */
+
+#ifndef _CACHE_H_
+#define _CACHE_H_
+
+/*
+ * Constants and data structures used to implement group and password file
+ * caches. Traditional passwd/group cache routines perform quite poorly with
+ * archives. The chances of hitting a valid lookup with an archive is quite a
+ * bit worse than with files already resident on the file system. These misses
+ * create a MAJOR performance cost. To address this problem, these routines
+ * cache both hits and misses.
+ *
+ * NOTE: name lengths must be as large as those stored in ANY PROTOCOL and
+ * as stored in the passwd and group files. CACHE SIZES MUST BE PRIME
+ */
+#define UNMLEN 32 /* >= user name found in any protocol */
+#define GNMLEN 32 /* >= group name found in any protocol */
+#define UID_SZ 317 /* size of user_name/uid cache */
+#define UNM_SZ 317 /* size of user_name/uid cache */
+#define GID_SZ 251 /* size of gid cache */
+#define GNM_SZ 317 /* size of group name cache */
+#define VALID 1 /* entry and name are valid */
+#define INVALID 2 /* entry valid, name NOT valid */
+
+/*
+ * Node structures used in the user, group, uid, and gid caches.
+ */
+
+typedef struct uidc {
+ int valid; /* is this a valid or a miss entry */
+ char name[UNMLEN]; /* uid name */
+ uid_t uid; /* cached uid */
+} UIDC;
+
+typedef struct gidc {
+ int valid; /* is this a valid or a miss entry */
+ char name[GNMLEN]; /* gid name */
+ gid_t gid; /* cached gid */
+} GIDC;
+
+#endif /* _CACHE_H_ */
diff --git a/file_cmds/pax/cpio.1 b/file_cmds/pax/cpio.1
new file mode 100644
index 0000000..b518a02
--- /dev/null
+++ b/file_cmds/pax/cpio.1
@@ -0,0 +1,304 @@
+.\"-
+.\" Copyright (c) 1997 SigmaSoft, Th. Lockert
+.\" 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 ``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.
+.\"
+.\" $OpenBSD: cpio.1,v 1.16 2001/05/01 17:58:01 aaron Exp $
+.\" $FreeBSD: src/bin/pax/cpio.1,v 1.6 2005/02/09 18:02:29 ru Exp $
+.\"
+.Dd February 16, 1997
+.Dt CPIO 1
+.Os
+.Sh NAME
+.Nm cpio
+.Nd copy file archives in and out
+.Sh SYNOPSIS
+.Nm cpio
+.Fl o
+.Op Fl aABcLvzZ
+.Op Fl C Ar bytes
+.Op Fl F Ar archive
+.Op Fl H Ar format
+.Op Fl O Ar archive
+.Ar "< name-list"
+.Op Ar "> archive"
+.Nm cpio
+.Fl i
+.Op Fl bBcdfmrsStuvzZ6
+.Op Fl C Ar bytes
+.Op Fl E Ar file
+.Op Fl F Ar archive
+.Op Fl H Ar format
+.Op Fl I Ar archive
+.Op Ar "pattern ..."
+.Op Ar "< archive"
+.Nm cpio
+.Fl p
+.Op Fl adlLmuv
+.Ar destination-directory
+.No < Ar name-list
+.Sh DESCRIPTION
+The
+.Nm cpio
+command copies files to and from a
+.Nm cpio
+archive.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl o
+Create an archive.
+Reads the list of files to store in the
+archive from standard input, and writes the archive on standard
+output.
+.Bl -tag -width Ds
+.It Fl A
+Append to the specified archive.
+.It Fl a
+Reset the access times on files that have been copied to the
+archive.
+.It Fl B
+Set block size of output to 5120 bytes.
+.It Fl C Ar bytes
+Set the block size of output to
+.Ar bytes .
+.It Fl c
+Use ASCII format for
+.Nm cpio
+header for portability.
+.It Fl F Ar archive
+Use the specified file name as the archive to write to.
+.It Fl H Ar format
+Write the archive in the specified format.
+Recognized formats are:
+.Pp
+.Bl -tag -width sv4cpio -compact
+.It Ar bcpio
+Old binary
+.Nm cpio
+format.
+.It Ar cpio
+Old octal character
+.Nm cpio
+format.
+.It Ar sv4cpio
+SVR4 hex
+.Nm cpio
+format.
+.It Ar tar
+Old tar format.
+.It Cm ustar
+.Tn POSIX
+ustar format.
+.El
+.It Fl L
+Follow symbolic links.
+.It Fl O Ar archive
+Use the specified file name as the archive to write to.
+.It Fl v
+Be verbose about operations.
+List filenames as they are written to the archive.
+.It Fl Z
+Compress archive using
+.Xr compress 1
+format.
+.It Fl z
+Compress archive using
+.Xr gzip 1
+format.
+.El
+.It Fl i
+Restore files from an archive.
+Reads the archive file from
+standard input and extracts files matching the
+.Ar patterns
+that were specified on the command line.
+.Bl -tag -width Ds
+.It Fl 6
+Process old-style
+.Nm cpio
+format archives.
+.It Fl B
+Set the block size of the archive being read to 5120 bytes.
+.It Fl b
+Do byte and word swapping after reading in data from the
+archive, for restoring archives created on systems with
+a different byte order.
+.It Fl C Ar bytes
+Read archive written with a block size of
+.Ar bytes .
+.It Fl c
+Expect the archive headers to be in ASCII format.
+.It Fl d
+Create any intermediate directories as needed during
+restore.
+.It Fl E Ar file
+Read list of file name patterns to extract or list from
+.Ar file .
+.It Fl F Ar archive
+Use the specified file as the input for the archive.
+.It Fl f
+Restore all files except those matching the
+.Ar patterns
+given on the command line.
+.It Fl H Ar format
+Read an archive of the specified format.
+Recognized formats are:
+.Pp
+.Bl -tag -width sv4cpio -compact
+.It Ar bcpio
+Old binary
+.Nm cpio
+format.
+.It Ar cpio
+Old octal character
+.Nm cpio
+format.
+.It Ar sv4cpio
+SVR4 hex
+.Nm cpio
+format.
+.It Ar tar
+Old tar format.
+.It Cm ustar
+.Tn POSIX
+ustar format.
+.El
+.It Fl I Ar archive
+Use the specified file as the input for the archive.
+.It Fl m
+Restore modification times on files.
+.It Fl r
+Rename restored files interactively.
+.It Fl S
+Swap words after reading data from the archive.
+.It Fl s
+Swap bytes after reading data from the archive.
+.It Fl t
+Only list the contents of the archive, no files or
+directories will be created.
+.It Fl u
+Overwrite files even when the file in the archive is
+older than the one that will be overwritten.
+.It Fl v
+Be verbose about operations.
+List filenames as they are copied in from the archive.
+.It Fl Z
+Uncompress archive using
+.Xr compress 1
+format.
+.It Fl z
+Uncompress archive using
+.Xr gzip 1
+format.
+.It Fl Z
+Uncompress archive using
+.Xr compress 1
+format.
+.It Fl 6
+Process old-style
+.Nm
+format archives.
+.El
+.It Fl p
+Copy files from one location to another in a single pass.
+The list of files to copy are read from standard input and
+written out to a directory relative to the specified
+.Ar directory
+argument.
+By default, an older file will not replace a newer file with the same name.
+.Bl -tag -width Ds
+.It Fl a
+Reset the access times on files that have been copied.
+.It Fl d
+Create any intermediate directories as needed to write
+the files at the new location.
+.It Fl L
+Follow symbolic links.
+.It Fl l
+When possible, link files rather than creating an
+extra copy.
+.It Fl m
+Restore modification times on files.
+.It Fl u
+Overwrite files even when the original file being copied is
+older than the one that will be overwritten.
+.It Fl v
+Be verbose about operations.
+List filenames as they are copied.
+.El
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev TMPDIR
+Path in which to store temporary files.
+.El
+.Sh ERRORS
+.Nm cpio
+will exit with one of the following values:
+.Bl -tag -width 2n
+.It 0
+All files were processed successfully.
+.It 1
+An error occurred.
+.El
+.Pp
+Whenever
+.Nm cpio
+cannot create a file or a link when extracting an archive or cannot
+find a file while writing an archive, or cannot preserve the user
+ID, group ID, file mode, or access and modification times when the
+.Fl p
+option is specified, a diagnostic message is written to standard
+error and a non-zero exit value will be returned, but processing
+will continue.
+In the case where
+.Nm cpio
+cannot create a link to a file,
+.Nm cpio
+will not create a second copy of the file.
+.Pp
+If the extraction of a file from an archive is prematurely terminated
+by a signal or error,
+.Nm cpio
+may have only partially extracted the file the user wanted.
+Additionally, the file modes of extracted files and directories may
+have incorrect file bits, and the modification and access times may
+be wrong.
+.Pp
+If the creation of an archive is prematurely terminated by a signal
+or error,
+.Nm cpio
+may have only partially created the archive, which may violate the
+specific archive format specification.
+.Sh SEE ALSO
+.Xr pax 1 ,
+.Xr tar 1
+.Sh AUTHORS
+.An Keith Muller
+at the University of California, San Diego.
+.Sh BUGS
+The
+.Fl s
+and
+.Fl S
+options are currently not implemented.
diff --git a/file_cmds/pax/cpio.c b/file_cmds/pax/cpio.c
new file mode 100644
index 0000000..cb9f969
--- /dev/null
+++ b/file_cmds/pax/cpio.c
@@ -0,0 +1,1149 @@
+/* $OpenBSD: cpio.c,v 1.18 2008/01/01 16:22:44 tobias Exp $ */
+/* $NetBSD: cpio.c,v 1.5 1995/03/21 09:07:13 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)cpio.c 8.1 (Berkeley) 5/31/93";
+#else
+__used static const char rcsid[] = "$OpenBSD: cpio.c,v 1.18 2008/01/01 16:22:44 tobias Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "cpio.h"
+#include "extern.h"
+
+static int rd_nm(ARCHD *, int);
+static int rd_ln_nm(ARCHD *);
+static int com_rd(ARCHD *);
+
+/*
+ * Routines which support the different cpio versions
+ */
+
+static int swp_head; /* binary cpio header byte swap */
+
+/*
+ * Routines common to all versions of cpio
+ */
+
+/*
+ * cpio_strd()
+ * Fire up the hard link detection code
+ * Return:
+ * 0 if ok -1 otherwise (the return values of lnk_start())
+ */
+
+int
+cpio_strd(void)
+{
+ return(lnk_start());
+}
+
+/*
+ * cpio_trail()
+ * Called to determine if a header block is a valid trailer. We are
+ * passed the block, the in_sync flag (which tells us we are in resync
+ * mode; looking for a valid header), and cnt (which starts at zero)
+ * which is used to count the number of empty blocks we have seen so far.
+ * Return:
+ * 0 if a valid trailer, -1 if not a valid trailer,
+ */
+
+int
+cpio_trail(ARCHD *arcn, char *notused, int notused2, int *notused3)
+{
+ /*
+ * look for trailer id in file we are about to process
+ */
+ if ((strcmp(arcn->name, TRAILER) == 0) && (arcn->sb.st_size == 0))
+ return(0);
+ return(-1);
+}
+
+/*
+ * com_rd()
+ * operations common to all cpio read functions.
+ * Return:
+ * 0
+ */
+
+static int
+com_rd(ARCHD *arcn)
+{
+ arcn->skip = 0;
+ arcn->pat = NULL;
+ arcn->org_name = arcn->name;
+ switch (arcn->sb.st_mode & C_IFMT) {
+ case C_ISFIFO:
+ arcn->type = PAX_FIF;
+ break;
+ case C_ISDIR:
+ arcn->type = PAX_DIR;
+ break;
+ case C_ISBLK:
+ arcn->type = PAX_BLK;
+ break;
+ case C_ISCHR:
+ arcn->type = PAX_CHR;
+ break;
+ case C_ISLNK:
+ arcn->type = PAX_SLK;
+ break;
+ case C_ISOCK:
+ arcn->type = PAX_SCK;
+ break;
+ case C_ISCTG:
+ case C_ISREG:
+ default:
+ /*
+ * we have file data, set up skip (pad is set in the format
+ * specific sections)
+ */
+ arcn->sb.st_mode = (arcn->sb.st_mode & 0xfff) | C_ISREG;
+ arcn->type = PAX_REG;
+ arcn->skip = arcn->sb.st_size;
+ break;
+ }
+ if (chk_lnk(arcn) < 0)
+ return(-1);
+ return(0);
+}
+
+/*
+ * cpio_endwr()
+ * write the special file with the name trailer in the proper format
+ * Return:
+ * result of the write of the trailer from the cpio specific write func
+ */
+
+int
+cpio_endwr(void)
+{
+ ARCHD last;
+
+ /*
+ * create a trailer request and call the proper format write function
+ */
+ memset(&last, 0, sizeof(last));
+ last.nlen = sizeof(TRAILER) - 1;
+ last.type = PAX_REG;
+ last.sb.st_nlink = 1;
+ (void)strlcpy(last.name, TRAILER, sizeof(last.name));
+ return((*frmt->wr)(&last));
+}
+
+/*
+ * rd_nam()
+ * read in the file name which follows the cpio header
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+static int
+rd_nm(ARCHD *arcn, int nsz)
+{
+ /*
+ * do not even try bogus values
+ */
+ if ((nsz == 0) || (nsz > sizeof(arcn->name))) {
+ paxwarn(1, "Cpio file name length %d is out of range", nsz);
+ return(-1);
+ }
+
+ /*
+ * read the name and make sure it is not empty and is \0 terminated
+ */
+ if ((rd_wrbuf(arcn->name,nsz) != nsz) || (arcn->name[nsz-1] != '\0') ||
+ (arcn->name[0] == '\0')) {
+ paxwarn(1, "Cpio file name in header is corrupted");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * rd_ln_nm()
+ * read in the link name for a file with links. The link name is stored
+ * like file data (and is NOT \0 terminated!)
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+static int
+rd_ln_nm(ARCHD *arcn)
+{
+ /*
+ * check the length specified for bogus values
+ */
+ if ((arcn->sb.st_size == 0) ||
+ (arcn->sb.st_size >= sizeof(arcn->ln_name))) {
+# ifdef LONG_OFF_T
+ paxwarn(1, "Cpio link name length is invalid: %lu",
+ arcn->sb.st_size);
+# else
+ paxwarn(1, "Cpio link name length is invalid: %qu",
+ arcn->sb.st_size);
+# endif
+ return(-1);
+ }
+
+ /*
+ * read in the link name and \0 terminate it
+ */
+ if (rd_wrbuf(arcn->ln_name, (int)arcn->sb.st_size) !=
+ (int)arcn->sb.st_size) {
+ paxwarn(1, "Cpio link name read error");
+ return(-1);
+ }
+ arcn->ln_nlen = (int)arcn->sb.st_size;
+ arcn->ln_name[arcn->ln_nlen] = '\0';
+
+ /*
+ * watch out for those empty link names
+ */
+ if (arcn->ln_name[0] == '\0') {
+ paxwarn(1, "Cpio link name is corrupt");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * Routines common to the extended byte oriented cpio format
+ */
+
+/*
+ * cpio_id()
+ * determine if a block given to us is a valid extended byte oriented
+ * cpio header
+ * Return:
+ * 0 if a valid header, -1 otherwise
+ */
+
+int
+cpio_id(char *blk, int size)
+{
+ if ((size < sizeof(HD_CPIO)) ||
+ (strncmp(blk, AMAGIC, sizeof(AMAGIC) - 1) != 0))
+ return(-1);
+ return(0);
+}
+
+/*
+ * cpio_rd()
+ * determine if a buffer is a byte oriented extended cpio archive entry.
+ * convert and store the values in the ARCHD parameter.
+ * Return:
+ * 0 if a valid header, -1 otherwise.
+ */
+
+int
+cpio_rd(ARCHD *arcn, char *buf)
+{
+ int nsz;
+ HD_CPIO *hd;
+
+ /*
+ * check that this is a valid header, if not return -1
+ */
+ if (cpio_id(buf, sizeof(HD_CPIO)) < 0)
+ return(-1);
+ hd = (HD_CPIO *)buf;
+
+ /*
+ * byte oriented cpio (posix) does not have padding! extract the octal
+ * ascii fields from the header
+ */
+ arcn->pad = 0L;
+ arcn->sb.st_dev = (dev_t)asc_ul(hd->c_dev, sizeof(hd->c_dev), OCT);
+ arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), OCT);
+ arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), OCT);
+ arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), OCT);
+ arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), OCT);
+ arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
+ OCT);
+ arcn->sb.st_rdev = (dev_t)asc_ul(hd->c_rdev, sizeof(hd->c_rdev), OCT);
+ arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime, sizeof(hd->c_mtime),
+ OCT);
+ arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+# ifdef LONG_OFF_T
+ arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,sizeof(hd->c_filesize),
+ OCT);
+# else
+ arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,sizeof(hd->c_filesize),
+ OCT);
+# endif
+
+ /*
+ * check name size and if valid, read in the name of this entry (name
+ * follows header in the archive)
+ */
+ if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),OCT)) < 2)
+ return(-1);
+ arcn->nlen = nsz - 1;
+ if (rd_nm(arcn, nsz) < 0)
+ return(-1);
+
+ if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
+ /*
+ * no link name to read for this file
+ */
+ arcn->ln_nlen = 0;
+ arcn->ln_name[0] = '\0';
+ return(com_rd(arcn));
+ }
+
+ /*
+ * check link name size and read in the link name. Link names are
+ * stored like file data.
+ */
+ if (rd_ln_nm(arcn) < 0)
+ return(-1);
+
+ /*
+ * we have a valid header (with a link)
+ */
+ return(com_rd(arcn));
+}
+
+/*
+ * cpio_endrd()
+ * no cleanup needed here, just return size of the trailer (for append)
+ * Return:
+ * size of trailer header in this format
+ */
+
+off_t
+cpio_endrd(void)
+{
+ return((off_t)(sizeof(HD_CPIO) + sizeof(TRAILER)));
+}
+
+/*
+ * cpio_stwr()
+ * start up the device mapping table
+ * Return:
+ * 0 if ok, -1 otherwise (what dev_start() returns)
+ */
+
+int
+cpio_stwr(void)
+{
+ return(dev_start());
+}
+
+/*
+ * cpio_wr()
+ * copy the data in the ARCHD to buffer in extended byte oriented cpio
+ * format.
+ * Return
+ * 0 if file has data to be written after the header, 1 if file has NO
+ * data to write after the header, -1 if archive write failed
+ */
+
+int
+cpio_wr(ARCHD *arcn)
+{
+ HD_CPIO *hd;
+ int nsz;
+ char hdblk[sizeof(HD_CPIO)];
+
+ /*
+ * check and repair truncated device and inode fields in the header
+ */
+ if (map_dev(arcn, (u_long)CPIO_MASK, (u_long)CPIO_MASK) < 0)
+ return(-1);
+
+ arcn->pad = 0L;
+ nsz = arcn->nlen + 1;
+ hd = (HD_CPIO *)hdblk;
+ if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
+ arcn->sb.st_rdev = 0;
+
+ switch (arcn->type) {
+ case PAX_CTG:
+ case PAX_REG:
+ case PAX_HRG:
+ /*
+ * set data size for file data
+ */
+# ifdef LONG_OFF_T
+ if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
+ sizeof(hd->c_filesize), OCT)) {
+# else
+ if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
+ sizeof(hd->c_filesize), OCT)) {
+# endif
+ paxwarn(1,"File is too large for cpio format %s",
+ arcn->org_name);
+ return(1);
+ }
+ break;
+ case PAX_SLK:
+ /*
+ * set data size to hold link name
+ */
+ if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
+ sizeof(hd->c_filesize), OCT))
+ goto out;
+ break;
+ default:
+ /*
+ * all other file types have no file data
+ */
+ if (ul_asc((u_long)0, hd->c_filesize, sizeof(hd->c_filesize),
+ OCT))
+ goto out;
+ break;
+ }
+
+ /*
+ * copy the values to the header using octal ascii
+ */
+ if (ul_asc((u_long)MAGIC, hd->c_magic, sizeof(hd->c_magic), OCT) ||
+ ul_asc((u_long)arcn->sb.st_dev, hd->c_dev, sizeof(hd->c_dev),
+ OCT) ||
+ ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
+ OCT) ||
+ ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
+ OCT) ||
+ ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
+ OCT) ||
+ ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
+ OCT) ||
+ ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
+ OCT) ||
+ ul_asc((u_long)arcn->sb.st_rdev, hd->c_rdev, sizeof(hd->c_rdev),
+ OCT) ||
+ ul_asc((u_long)arcn->sb.st_mtime,hd->c_mtime,sizeof(hd->c_mtime),
+ OCT) ||
+ ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), OCT))
+ goto out;
+
+ /*
+ * write the file name to the archive
+ */
+ if ((wr_rdbuf(hdblk, (int)sizeof(HD_CPIO)) < 0) ||
+ (wr_rdbuf(arcn->name, nsz) < 0)) {
+ paxwarn(1, "Unable to write cpio header for %s", arcn->org_name);
+ return(-1);
+ }
+
+ /*
+ * if this file has data, we are done. The caller will write the file
+ * data, if we are link tell caller we are done, go to next file
+ */
+ if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
+ (arcn->type == PAX_HRG))
+ return(0);
+ if (arcn->type != PAX_SLK)
+ return(1);
+
+ /*
+ * write the link name to the archive, tell the caller to go to the
+ * next file as we are done.
+ */
+ if (wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) {
+ paxwarn(1,"Unable to write cpio link name for %s",arcn->org_name);
+ return(-1);
+ }
+ return(1);
+
+ out:
+ /*
+ * header field is out of range
+ */
+ paxwarn(1, "Cpio header field is too small to store file %s",
+ arcn->org_name);
+ return(1);
+}
+
+/*
+ * Routines common to the system VR4 version of cpio (with/without file CRC)
+ */
+
+/*
+ * vcpio_id()
+ * determine if a block given to us is a valid system VR4 cpio header
+ * WITHOUT crc. WATCH it the magic cookies are in OCTAL, the header
+ * uses HEX
+ * Return:
+ * 0 if a valid header, -1 otherwise
+ */
+
+int
+vcpio_id(char *blk, int size)
+{
+ if ((size < sizeof(HD_VCPIO)) ||
+ (strncmp(blk, AVMAGIC, sizeof(AVMAGIC) - 1) != 0))
+ return(-1);
+ return(0);
+}
+
+/*
+ * crc_id()
+ * determine if a block given to us is a valid system VR4 cpio header
+ * WITH crc. WATCH it the magic cookies are in OCTAL the header uses HEX
+ * Return:
+ * 0 if a valid header, -1 otherwise
+ */
+
+int
+crc_id(char *blk, int size)
+{
+ if ((size < sizeof(HD_VCPIO)) ||
+ (strncmp(blk, AVCMAGIC, sizeof(AVCMAGIC) - 1) != 0))
+ return(-1);
+ return(0);
+}
+
+/*
+ * crc_strd()
+ w set file data CRC calculations. Fire up the hard link detection code
+ * Return:
+ * 0 if ok -1 otherwise (the return values of lnk_start())
+ */
+
+int
+crc_strd(void)
+{
+ docrc = 1;
+ return(lnk_start());
+}
+
+/*
+ * vcpio_rd()
+ * determine if a buffer is a system VR4 archive entry. (with/without CRC)
+ * convert and store the values in the ARCHD parameter.
+ * Return:
+ * 0 if a valid header, -1 otherwise.
+ */
+
+int
+vcpio_rd(ARCHD *arcn, char *buf)
+{
+ HD_VCPIO *hd;
+ dev_t devminor;
+ dev_t devmajor;
+ int nsz;
+
+ /*
+ * during the id phase it was determined if we were using CRC, use the
+ * proper id routine.
+ */
+ if (docrc) {
+ if (crc_id(buf, sizeof(HD_VCPIO)) < 0)
+ return(-1);
+ } else {
+ if (vcpio_id(buf, sizeof(HD_VCPIO)) < 0)
+ return(-1);
+ }
+
+ hd = (HD_VCPIO *)buf;
+ arcn->pad = 0L;
+
+ /*
+ * extract the hex ascii fields from the header
+ */
+ arcn->sb.st_ino = (ino_t)asc_ul(hd->c_ino, sizeof(hd->c_ino), HEX);
+ arcn->sb.st_mode = (mode_t)asc_ul(hd->c_mode, sizeof(hd->c_mode), HEX);
+ arcn->sb.st_uid = (uid_t)asc_ul(hd->c_uid, sizeof(hd->c_uid), HEX);
+ arcn->sb.st_gid = (gid_t)asc_ul(hd->c_gid, sizeof(hd->c_gid), HEX);
+ arcn->sb.st_mtime = (time_t)asc_ul(hd->c_mtime,sizeof(hd->c_mtime),HEX);
+ arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+# ifdef LONG_OFF_T
+ arcn->sb.st_size = (off_t)asc_ul(hd->c_filesize,
+ sizeof(hd->c_filesize), HEX);
+# else
+ arcn->sb.st_size = (off_t)asc_uqd(hd->c_filesize,
+ sizeof(hd->c_filesize), HEX);
+# endif
+ arcn->sb.st_nlink = (nlink_t)asc_ul(hd->c_nlink, sizeof(hd->c_nlink),
+ HEX);
+ devmajor = (dev_t)asc_ul(hd->c_maj, sizeof(hd->c_maj), HEX);
+ devminor = (dev_t)asc_ul(hd->c_min, sizeof(hd->c_min), HEX);
+ arcn->sb.st_dev = TODEV(devmajor, devminor);
+ devmajor = (dev_t)asc_ul(hd->c_rmaj, sizeof(hd->c_maj), HEX);
+ devminor = (dev_t)asc_ul(hd->c_rmin, sizeof(hd->c_min), HEX);
+ arcn->sb.st_rdev = TODEV(devmajor, devminor);
+ arcn->crc = asc_ul(hd->c_chksum, sizeof(hd->c_chksum), HEX);
+
+ /*
+ * check the length of the file name, if ok read it in, return -1 if
+ * bogus
+ */
+ if ((nsz = (int)asc_ul(hd->c_namesize,sizeof(hd->c_namesize),HEX)) < 2)
+ return(-1);
+ arcn->nlen = nsz - 1;
+ if (rd_nm(arcn, nsz) < 0)
+ return(-1);
+
+ /*
+ * skip padding. header + filename is aligned to 4 byte boundaries
+ */
+ if (rd_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)
+ return(-1);
+
+ /*
+ * if not a link (or a file with no data), calculate pad size (for
+ * padding which follows the file data), clear the link name and return
+ */
+ if (((arcn->sb.st_mode&C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)) {
+ /*
+ * we have a valid header (not a link)
+ */
+ arcn->ln_nlen = 0;
+ arcn->ln_name[0] = '\0';
+ arcn->pad = VCPIO_PAD(arcn->sb.st_size);
+ return(com_rd(arcn));
+ }
+
+ /*
+ * read in the link name and skip over the padding
+ */
+ if ((rd_ln_nm(arcn) < 0) ||
+ (rd_skip((off_t)(VCPIO_PAD(arcn->sb.st_size))) < 0))
+ return(-1);
+
+ /*
+ * we have a valid header (with a link)
+ */
+ return(com_rd(arcn));
+}
+
+/*
+ * vcpio_endrd()
+ * no cleanup needed here, just return size of the trailer (for append)
+ * Return:
+ * size of trailer header in this format
+ */
+
+off_t
+vcpio_endrd(void)
+{
+ return((off_t)(sizeof(HD_VCPIO) + sizeof(TRAILER) +
+ (VCPIO_PAD(sizeof(HD_VCPIO) + sizeof(TRAILER)))));
+}
+
+/*
+ * crc_stwr()
+ * start up the device mapping table, enable crc file calculation
+ * Return:
+ * 0 if ok, -1 otherwise (what dev_start() returns)
+ */
+
+int
+crc_stwr(void)
+{
+ docrc = 1;
+ return(dev_start());
+}
+
+/*
+ * vcpio_wr()
+ * copy the data in the ARCHD to buffer in system VR4 cpio
+ * (with/without crc) format.
+ * Return
+ * 0 if file has data to be written after the header, 1 if file has
+ * NO data to write after the header, -1 if archive write failed
+ */
+
+int
+vcpio_wr(ARCHD *arcn)
+{
+ HD_VCPIO *hd;
+ unsigned int nsz;
+ char hdblk[sizeof(HD_VCPIO)];
+
+ /*
+ * check and repair truncated device and inode fields in the cpio
+ * header
+ */
+ if (map_dev(arcn, (u_long)VCPIO_MASK, (u_long)VCPIO_MASK) < 0)
+ return(-1);
+ nsz = arcn->nlen + 1;
+ hd = (HD_VCPIO *)hdblk;
+ if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
+ arcn->sb.st_rdev = 0;
+
+ /*
+ * add the proper magic value depending whether we were asked for
+ * file data crc's, and the crc if needed.
+ */
+ if (docrc) {
+ if (ul_asc((u_long)VCMAGIC, hd->c_magic, sizeof(hd->c_magic),
+ OCT) ||
+ ul_asc((u_long)arcn->crc,hd->c_chksum,sizeof(hd->c_chksum),
+ HEX))
+ goto out;
+ } else {
+ if (ul_asc((u_long)VMAGIC, hd->c_magic, sizeof(hd->c_magic),
+ OCT) ||
+ ul_asc((u_long)0L, hd->c_chksum, sizeof(hd->c_chksum),HEX))
+ goto out;
+ }
+
+ switch (arcn->type) {
+ case PAX_CTG:
+ case PAX_REG:
+ case PAX_HRG:
+ /*
+ * caller will copy file data to the archive. tell him how
+ * much to pad.
+ */
+ arcn->pad = VCPIO_PAD(arcn->sb.st_size);
+# ifdef LONG_OFF_T
+ if (ul_asc((u_long)arcn->sb.st_size, hd->c_filesize,
+ sizeof(hd->c_filesize), HEX)) {
+# else
+ if (uqd_asc((u_quad_t)arcn->sb.st_size, hd->c_filesize,
+ sizeof(hd->c_filesize), HEX)) {
+# endif
+ paxwarn(1,"File is too large for sv4cpio format %s",
+ arcn->org_name);
+ return(1);
+ }
+ break;
+ case PAX_SLK:
+ /*
+ * no file data for the caller to process, the file data has
+ * the size of the link
+ */
+ arcn->pad = 0L;
+ if (ul_asc((u_long)arcn->ln_nlen, hd->c_filesize,
+ sizeof(hd->c_filesize), HEX))
+ goto out;
+ break;
+ default:
+ /*
+ * no file data for the caller to process
+ */
+ arcn->pad = 0L;
+ if (ul_asc((u_long)0L, hd->c_filesize, sizeof(hd->c_filesize),
+ HEX))
+ goto out;
+ break;
+ }
+
+ /*
+ * set the other fields in the header
+ */
+ if (ul_asc((u_long)arcn->sb.st_ino, hd->c_ino, sizeof(hd->c_ino),
+ HEX) ||
+ ul_asc((u_long)arcn->sb.st_mode, hd->c_mode, sizeof(hd->c_mode),
+ HEX) ||
+ ul_asc((u_long)arcn->sb.st_uid, hd->c_uid, sizeof(hd->c_uid),
+ HEX) ||
+ ul_asc((u_long)arcn->sb.st_gid, hd->c_gid, sizeof(hd->c_gid),
+ HEX) ||
+ ul_asc((u_long)arcn->sb.st_mtime, hd->c_mtime, sizeof(hd->c_mtime),
+ HEX) ||
+ ul_asc((u_long)arcn->sb.st_nlink, hd->c_nlink, sizeof(hd->c_nlink),
+ HEX) ||
+ ul_asc((u_long)MAJOR(arcn->sb.st_dev),hd->c_maj, sizeof(hd->c_maj),
+ HEX) ||
+ ul_asc((u_long)MINOR(arcn->sb.st_dev),hd->c_min, sizeof(hd->c_min),
+ HEX) ||
+ ul_asc((u_long)MAJOR(arcn->sb.st_rdev),hd->c_rmaj,sizeof(hd->c_maj),
+ HEX) ||
+ ul_asc((u_long)MINOR(arcn->sb.st_rdev),hd->c_rmin,sizeof(hd->c_min),
+ HEX) ||
+ ul_asc((u_long)nsz, hd->c_namesize, sizeof(hd->c_namesize), HEX))
+ goto out;
+
+ /*
+ * write the header, the file name and padding as required.
+ */
+ if ((wr_rdbuf(hdblk, (int)sizeof(HD_VCPIO)) < 0) ||
+ (wr_rdbuf(arcn->name, (int)nsz) < 0) ||
+ (wr_skip((off_t)(VCPIO_PAD(sizeof(HD_VCPIO) + nsz))) < 0)) {
+ paxwarn(1,"Could not write sv4cpio header for %s",arcn->org_name);
+ return(-1);
+ }
+
+ /*
+ * if we have file data, tell the caller we are done, copy the file
+ */
+ if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
+ (arcn->type == PAX_HRG))
+ return(0);
+
+ /*
+ * if we are not a link, tell the caller we are done, go to next file
+ */
+ if (arcn->type != PAX_SLK)
+ return(1);
+
+ /*
+ * write the link name, tell the caller we are done.
+ */
+ if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
+ (wr_skip((off_t)(VCPIO_PAD(arcn->ln_nlen))) < 0)) {
+ paxwarn(1,"Could not write sv4cpio link name for %s",
+ arcn->org_name);
+ return(-1);
+ }
+ return(1);
+
+ out:
+ /*
+ * header field is out of range
+ */
+ paxwarn(1,"Sv4cpio header field is too small for file %s",arcn->org_name);
+ return(1);
+}
+
+/*
+ * Routines common to the old binary header cpio
+ */
+
+/*
+ * bcpio_id()
+ * determine if a block given to us is a old binary cpio header
+ * (with/without header byte swapping)
+ * Return:
+ * 0 if a valid header, -1 otherwise
+ */
+
+int
+bcpio_id(char *blk, int size)
+{
+ if (size < sizeof(HD_BCPIO))
+ return(-1);
+
+ /*
+ * check both normal and byte swapped magic cookies
+ */
+ if (((u_short)SHRT_EXT(blk)) == MAGIC)
+ return(0);
+ if (((u_short)RSHRT_EXT(blk)) == MAGIC) {
+ if (!swp_head)
+ ++swp_head;
+ return(0);
+ }
+ return(-1);
+}
+
+/*
+ * bcpio_rd()
+ * determine if a buffer is a old binary archive entry. (it may have byte
+ * swapped header) convert and store the values in the ARCHD parameter.
+ * This is a very old header format and should not really be used.
+ * Return:
+ * 0 if a valid header, -1 otherwise.
+ */
+
+int
+bcpio_rd(ARCHD *arcn, char *buf)
+{
+ HD_BCPIO *hd;
+ int nsz;
+
+ /*
+ * check the header
+ */
+ if (bcpio_id(buf, sizeof(HD_BCPIO)) < 0)
+ return(-1);
+
+ arcn->pad = 0L;
+ hd = (HD_BCPIO *)buf;
+ if (swp_head) {
+ /*
+ * header has swapped bytes on 16 bit boundaries
+ */
+ arcn->sb.st_dev = (dev_t)(RSHRT_EXT(hd->h_dev));
+ arcn->sb.st_ino = (ino_t)(RSHRT_EXT(hd->h_ino));
+ arcn->sb.st_mode = (mode_t)(RSHRT_EXT(hd->h_mode));
+ arcn->sb.st_uid = (uid_t)(RSHRT_EXT(hd->h_uid));
+ arcn->sb.st_gid = (gid_t)(RSHRT_EXT(hd->h_gid));
+ arcn->sb.st_nlink = (nlink_t)(RSHRT_EXT(hd->h_nlink));
+ arcn->sb.st_rdev = (dev_t)(RSHRT_EXT(hd->h_rdev));
+ arcn->sb.st_mtime = (time_t)(RSHRT_EXT(hd->h_mtime_1));
+ arcn->sb.st_mtime = (arcn->sb.st_mtime << 16) |
+ ((time_t)(RSHRT_EXT(hd->h_mtime_2)));
+ arcn->sb.st_size = (off_t)(RSHRT_EXT(hd->h_filesize_1));
+ arcn->sb.st_size = (arcn->sb.st_size << 16) |
+ ((off_t)(RSHRT_EXT(hd->h_filesize_2)));
+ nsz = (int)(RSHRT_EXT(hd->h_namesize));
+ } else {
+ arcn->sb.st_dev = (dev_t)(SHRT_EXT(hd->h_dev));
+ arcn->sb.st_ino = (ino_t)(SHRT_EXT(hd->h_ino));
+ arcn->sb.st_mode = (mode_t)(SHRT_EXT(hd->h_mode));
+ arcn->sb.st_uid = (uid_t)(SHRT_EXT(hd->h_uid));
+ arcn->sb.st_gid = (gid_t)(SHRT_EXT(hd->h_gid));
+ arcn->sb.st_nlink = (nlink_t)(SHRT_EXT(hd->h_nlink));
+ arcn->sb.st_rdev = (dev_t)(SHRT_EXT(hd->h_rdev));
+ arcn->sb.st_mtime = (time_t)(SHRT_EXT(hd->h_mtime_1));
+ arcn->sb.st_mtime = (arcn->sb.st_mtime << 16) |
+ ((time_t)(SHRT_EXT(hd->h_mtime_2)));
+ arcn->sb.st_size = (off_t)(SHRT_EXT(hd->h_filesize_1));
+ arcn->sb.st_size = (arcn->sb.st_size << 16) |
+ ((off_t)(SHRT_EXT(hd->h_filesize_2)));
+ nsz = (int)(SHRT_EXT(hd->h_namesize));
+ }
+ arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+
+ /*
+ * check the file name size, if bogus give up. otherwise read the file
+ * name
+ */
+ if (nsz < 2)
+ return(-1);
+ arcn->nlen = nsz - 1;
+ if (rd_nm(arcn, nsz) < 0)
+ return(-1);
+
+ /*
+ * header + file name are aligned to 2 byte boundaries, skip if needed
+ */
+ if (rd_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)
+ return(-1);
+
+ /*
+ * if not a link (or a file with no data), calculate pad size (for
+ * padding which follows the file data), clear the link name and return
+ */
+ if (((arcn->sb.st_mode & C_IFMT) != C_ISLNK)||(arcn->sb.st_size == 0)){
+ /*
+ * we have a valid header (not a link)
+ */
+ arcn->ln_nlen = 0;
+ arcn->ln_name[0] = '\0';
+ arcn->pad = BCPIO_PAD(arcn->sb.st_size);
+ return(com_rd(arcn));
+ }
+
+ if ((rd_ln_nm(arcn) < 0) ||
+ (rd_skip((off_t)(BCPIO_PAD(arcn->sb.st_size))) < 0))
+ return(-1);
+
+ /*
+ * we have a valid header (with a link)
+ */
+ return(com_rd(arcn));
+}
+
+/*
+ * bcpio_endrd()
+ * no cleanup needed here, just return size of the trailer (for append)
+ * Return:
+ * size of trailer header in this format
+ */
+
+off_t
+bcpio_endrd(void)
+{
+ return((off_t)(sizeof(HD_BCPIO) + sizeof(TRAILER) +
+ (BCPIO_PAD(sizeof(HD_BCPIO) + sizeof(TRAILER)))));
+}
+
+/*
+ * bcpio_wr()
+ * copy the data in the ARCHD to buffer in old binary cpio format
+ * There is a real chance of field overflow with this critter. So we
+ * always check the conversion is ok. nobody in their right mind
+ * should write an archive in this format...
+ * Return
+ * 0 if file has data to be written after the header, 1 if file has NO
+ * data to write after the header, -1 if archive write failed
+ */
+
+int
+bcpio_wr(ARCHD *arcn)
+{
+ HD_BCPIO *hd;
+ int nsz;
+ char hdblk[sizeof(HD_BCPIO)];
+ off_t t_offt;
+ int t_int;
+ time_t t_timet;
+
+ /*
+ * check and repair truncated device and inode fields in the cpio
+ * header
+ */
+ if (map_dev(arcn, (u_long)BCPIO_MASK, (u_long)BCPIO_MASK) < 0)
+ return(-1);
+
+ if ((arcn->type != PAX_BLK) && (arcn->type != PAX_CHR))
+ arcn->sb.st_rdev = 0;
+ hd = (HD_BCPIO *)hdblk;
+
+ switch (arcn->type) {
+ case PAX_CTG:
+ case PAX_REG:
+ case PAX_HRG:
+ /*
+ * caller will copy file data to the archive. tell him how
+ * much to pad.
+ */
+ arcn->pad = BCPIO_PAD(arcn->sb.st_size);
+ hd->h_filesize_1[0] = CHR_WR_0(arcn->sb.st_size);
+ hd->h_filesize_1[1] = CHR_WR_1(arcn->sb.st_size);
+ hd->h_filesize_2[0] = CHR_WR_2(arcn->sb.st_size);
+ hd->h_filesize_2[1] = CHR_WR_3(arcn->sb.st_size);
+ t_offt = (off_t)(SHRT_EXT(hd->h_filesize_1));
+ t_offt = (t_offt<<16) | ((off_t)(SHRT_EXT(hd->h_filesize_2)));
+ if (arcn->sb.st_size != t_offt) {
+ paxwarn(1,"File is too large for bcpio format %s",
+ arcn->org_name);
+ return(1);
+ }
+ break;
+ case PAX_SLK:
+ /*
+ * no file data for the caller to process, the file data has
+ * the size of the link
+ */
+ arcn->pad = 0L;
+ hd->h_filesize_1[0] = CHR_WR_0(arcn->ln_nlen);
+ hd->h_filesize_1[1] = CHR_WR_1(arcn->ln_nlen);
+ hd->h_filesize_2[0] = CHR_WR_2(arcn->ln_nlen);
+ hd->h_filesize_2[1] = CHR_WR_3(arcn->ln_nlen);
+ t_int = (int)(SHRT_EXT(hd->h_filesize_1));
+ t_int = (t_int << 16) | ((int)(SHRT_EXT(hd->h_filesize_2)));
+ if (arcn->ln_nlen != t_int)
+ goto out;
+ break;
+ default:
+ /*
+ * no file data for the caller to process
+ */
+ arcn->pad = 0L;
+ hd->h_filesize_1[0] = (char)0;
+ hd->h_filesize_1[1] = (char)0;
+ hd->h_filesize_2[0] = (char)0;
+ hd->h_filesize_2[1] = (char)0;
+ break;
+ }
+
+ /*
+ * build up the rest of the fields
+ */
+ hd->h_magic[0] = CHR_WR_2(MAGIC);
+ hd->h_magic[1] = CHR_WR_3(MAGIC);
+ hd->h_dev[0] = CHR_WR_2(arcn->sb.st_dev);
+ hd->h_dev[1] = CHR_WR_3(arcn->sb.st_dev);
+ if (arcn->sb.st_dev != (dev_t)(SHRT_EXT(hd->h_dev)))
+ goto out;
+ hd->h_ino[0] = CHR_WR_2(arcn->sb.st_ino);
+ hd->h_ino[1] = CHR_WR_3(arcn->sb.st_ino);
+ if (arcn->sb.st_ino != (ino_t)(SHRT_EXT(hd->h_ino)))
+ goto out;
+ hd->h_mode[0] = CHR_WR_2(arcn->sb.st_mode);
+ hd->h_mode[1] = CHR_WR_3(arcn->sb.st_mode);
+ if (arcn->sb.st_mode != (mode_t)(SHRT_EXT(hd->h_mode)))
+ goto out;
+ hd->h_uid[0] = CHR_WR_2(arcn->sb.st_uid);
+ hd->h_uid[1] = CHR_WR_3(arcn->sb.st_uid);
+ if (arcn->sb.st_uid != (uid_t)(SHRT_EXT(hd->h_uid)))
+ goto out;
+ hd->h_gid[0] = CHR_WR_2(arcn->sb.st_gid);
+ hd->h_gid[1] = CHR_WR_3(arcn->sb.st_gid);
+ if (arcn->sb.st_gid != (gid_t)(SHRT_EXT(hd->h_gid)))
+ goto out;
+ hd->h_nlink[0] = CHR_WR_2(arcn->sb.st_nlink);
+ hd->h_nlink[1] = CHR_WR_3(arcn->sb.st_nlink);
+ if (arcn->sb.st_nlink != (nlink_t)(SHRT_EXT(hd->h_nlink)))
+ goto out;
+ hd->h_rdev[0] = CHR_WR_2(arcn->sb.st_rdev);
+ hd->h_rdev[1] = CHR_WR_3(arcn->sb.st_rdev);
+ if (arcn->sb.st_rdev != (dev_t)(SHRT_EXT(hd->h_rdev)))
+ goto out;
+ hd->h_mtime_1[0] = CHR_WR_0(arcn->sb.st_mtime);
+ hd->h_mtime_1[1] = CHR_WR_1(arcn->sb.st_mtime);
+ hd->h_mtime_2[0] = CHR_WR_2(arcn->sb.st_mtime);
+ hd->h_mtime_2[1] = CHR_WR_3(arcn->sb.st_mtime);
+ t_timet = (time_t)(SHRT_EXT(hd->h_mtime_1));
+ t_timet = (t_timet << 16) | ((time_t)(SHRT_EXT(hd->h_mtime_2)));
+ if (arcn->sb.st_mtime != t_timet)
+ goto out;
+ nsz = arcn->nlen + 1;
+ hd->h_namesize[0] = CHR_WR_2(nsz);
+ hd->h_namesize[1] = CHR_WR_3(nsz);
+ if (nsz != (int)(SHRT_EXT(hd->h_namesize)))
+ goto out;
+
+ /*
+ * write the header, the file name and padding as required.
+ */
+ if ((wr_rdbuf(hdblk, (int)sizeof(HD_BCPIO)) < 0) ||
+ (wr_rdbuf(arcn->name, nsz) < 0) ||
+ (wr_skip((off_t)(BCPIO_PAD(sizeof(HD_BCPIO) + nsz))) < 0)) {
+ paxwarn(1, "Could not write bcpio header for %s", arcn->org_name);
+ return(-1);
+ }
+
+ /*
+ * if we have file data, tell the caller we are done
+ */
+ if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG) ||
+ (arcn->type == PAX_HRG))
+ return(0);
+
+ /*
+ * if we are not a link, tell the caller we are done, go to next file
+ */
+ if (arcn->type != PAX_SLK)
+ return(1);
+
+ /*
+ * write the link name, tell the caller we are done.
+ */
+ if ((wr_rdbuf(arcn->ln_name, arcn->ln_nlen) < 0) ||
+ (wr_skip((off_t)(BCPIO_PAD(arcn->ln_nlen))) < 0)) {
+ paxwarn(1,"Could not write bcpio link name for %s",arcn->org_name);
+ return(-1);
+ }
+ return(1);
+
+ out:
+ /*
+ * header field is out of range
+ */
+ paxwarn(1,"Bcpio header field is too small for file %s", arcn->org_name);
+ return(1);
+}
diff --git a/file_cmds/pax/cpio.h b/file_cmds/pax/cpio.h
new file mode 100644
index 0000000..93617b4
--- /dev/null
+++ b/file_cmds/pax/cpio.h
@@ -0,0 +1,155 @@
+/* $OpenBSD: cpio.h,v 1.4 2003/06/02 23:32:08 millert Exp $ */
+/* $NetBSD: cpio.h,v 1.3 1995/03/21 09:07:15 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)cpio.h 8.1 (Berkeley) 5/31/93
+ */
+
+#ifndef _CPIO_H_
+#define _CPIO_H_
+
+/*
+ * Defines common to all versions of cpio
+ */
+#define TRAILER "TRAILER!!!" /* name in last archive record */
+
+/*
+ * Header encoding of the different file types
+ */
+#define C_ISDIR 040000 /* Directory */
+#define C_ISFIFO 010000 /* FIFO */
+#define C_ISREG 0100000 /* Regular file */
+#define C_ISBLK 060000 /* Block special file */
+#define C_ISCHR 020000 /* Character special file */
+#define C_ISCTG 0110000 /* Reserved for contiguous files */
+#define C_ISLNK 0120000 /* Reserved for symbolic links */
+#define C_ISOCK 0140000 /* Reserved for sockets */
+#define C_IFMT 0170000 /* type of file */
+
+/*
+ * Data Interchange Format - Extended cpio header format - POSIX 1003.1-1990
+ */
+typedef struct {
+ char c_magic[6]; /* magic cookie */
+ char c_dev[6]; /* device number */
+ char c_ino[6]; /* inode number */
+ char c_mode[6]; /* file type/access */
+ char c_uid[6]; /* owners uid */
+ char c_gid[6]; /* owners gid */
+ char c_nlink[6]; /* # of links at archive creation */
+ char c_rdev[6]; /* block/char major/minor # */
+ char c_mtime[11]; /* modification time */
+ char c_namesize[6]; /* length of pathname */
+ char c_filesize[11]; /* length of file in bytes */
+} HD_CPIO;
+
+#define MAGIC 070707 /* transportable archive id */
+
+#ifdef _PAX_
+#define AMAGIC "070707" /* ascii equivalent string of MAGIC */
+#define CPIO_MASK 0x3ffff /* bits valid in the dev/ino fields */
+ /* used for dev/inode remaps */
+#endif /* _PAX_ */
+
+/*
+ * Binary cpio header structure
+ *
+ * CAUTION! CAUTION! CAUTION!
+ * Each field really represents a 16 bit short (NOT ASCII). Described as
+ * an array of chars in an attempt to improve portability!!
+ */
+typedef struct {
+ u_char h_magic[2];
+ u_char h_dev[2];
+ u_char h_ino[2];
+ u_char h_mode[2];
+ u_char h_uid[2];
+ u_char h_gid[2];
+ u_char h_nlink[2];
+ u_char h_rdev[2];
+ u_char h_mtime_1[2];
+ u_char h_mtime_2[2];
+ u_char h_namesize[2];
+ u_char h_filesize_1[2];
+ u_char h_filesize_2[2];
+} HD_BCPIO;
+
+#ifdef _PAX_
+/*
+ * extraction and creation macros for binary cpio
+ */
+#define SHRT_EXT(ch) ((((unsigned)(ch)[0])<<8) | (((unsigned)(ch)[1])&0xff))
+#define RSHRT_EXT(ch) ((((unsigned)(ch)[1])<<8) | (((unsigned)(ch)[0])&0xff))
+#define CHR_WR_0(val) ((char)(((val) >> 24) & 0xff))
+#define CHR_WR_1(val) ((char)(((val) >> 16) & 0xff))
+#define CHR_WR_2(val) ((char)(((val) >> 8) & 0xff))
+#define CHR_WR_3(val) ((char)((val) & 0xff))
+
+/*
+ * binary cpio masks and pads
+ */
+#define BCPIO_PAD(x) ((2 - ((x) & 1)) & 1) /* pad to next 2 byte word */
+#define BCPIO_MASK 0xffff /* mask for dev/ino fields */
+#endif /* _PAX_ */
+
+/*
+ * System VR4 cpio header structure (with/without file data crc)
+ */
+typedef struct {
+ char c_magic[6]; /* magic cookie */
+ char c_ino[8]; /* inode number */
+ char c_mode[8]; /* file type/access */
+ char c_uid[8]; /* owners uid */
+ char c_gid[8]; /* owners gid */
+ char c_nlink[8]; /* # of links at archive creation */
+ char c_mtime[8]; /* modification time */
+ char c_filesize[8]; /* length of file in bytes */
+ char c_maj[8]; /* block/char major # */
+ char c_min[8]; /* block/char minor # */
+ char c_rmaj[8]; /* special file major # */
+ char c_rmin[8]; /* special file minor # */
+ char c_namesize[8]; /* length of pathname */
+ char c_chksum[8]; /* 0 OR CRC of bytes of FILE data */
+} HD_VCPIO;
+
+#define VMAGIC 070701 /* sVr4 new portable archive id */
+#define VCMAGIC 070702 /* sVr4 new portable archive id CRC */
+#ifdef _PAX_
+#define AVMAGIC "070701" /* ascii string of above */
+#define AVCMAGIC "070702" /* ascii string of above */
+#define VCPIO_PAD(x) ((4 - ((x) & 3)) & 3) /* pad to next 4 byte word */
+#define VCPIO_MASK 0xffffffff /* mask for dev/ino fields */
+#endif /* _PAX_ */
+
+#endif /* _CPIO_H_ */
diff --git a/file_cmds/pax/extern.h b/file_cmds/pax/extern.h
new file mode 100644
index 0000000..16d3195
--- /dev/null
+++ b/file_cmds/pax/extern.h
@@ -0,0 +1,347 @@
+/* $OpenBSD: extern.h,v 1.33 2008/05/06 06:54:28 henning Exp $ */
+/* $NetBSD: extern.h,v 1.5 1996/03/26 23:54:16 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/18/94
+ */
+
+#ifndef _PAX_EXTERN_H_
+#define _PAX_EXTERN_H_
+
+/*
+ * External references from each source file
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * ar_io.c
+ */
+extern const char *arcname;
+extern const char *gzip_program;
+extern int force_one_volume;
+int ar_open(const char *);
+void ar_close(void);
+void ar_drain(void);
+int ar_set_wr(void);
+int ar_app_ok(void);
+int ar_read(char *, int);
+int ar_write(char *, int);
+int ar_rdsync(void);
+int ar_fow(off_t, off_t *);
+int ar_rev(off_t );
+int ar_next(void);
+
+/*
+ * ar_subs.c
+ */
+extern u_long flcnt;
+int updatepath(void);
+int dochdir(const char *);
+int fdochdir(int);
+void list(void);
+void extract(void);
+void append(void);
+void archive(void);
+void copy(void);
+
+/*
+ * buf_subs.c
+ */
+extern int blksz;
+extern int wrblksz;
+extern int maxflt;
+extern int rdblksz;
+extern off_t wrlimit;
+extern off_t rdcnt;
+extern off_t wrcnt;
+int wr_start(void);
+int rd_start(void);
+void cp_start(void);
+int appnd_start(off_t);
+int rd_sync(void);
+void pback(char *, int);
+int rd_skip(off_t);
+void wr_fin(void);
+int wr_rdbuf(char *, int);
+int rd_wrbuf(char *, int);
+int wr_skip(off_t);
+int wr_rdfile(ARCHD *, int, off_t *);
+int rd_wrfile(ARCHD *, int, off_t *);
+void cp_file(ARCHD *, int, int);
+int buf_fill(void);
+int buf_flush(int);
+
+/*
+ * cache.c
+ */
+int uidtb_start(void);
+int gidtb_start(void);
+int usrtb_start(void);
+int grptb_start(void);
+char * name_uid(uid_t, int);
+char * name_gid(gid_t, int);
+int uid_name(char *, uid_t *);
+int gid_name(char *, gid_t *);
+
+/*
+ * cpio.c
+ */
+int cpio_strd(void);
+int cpio_trail(ARCHD *, char *, int, int *);
+int cpio_endwr(void);
+int cpio_id(char *, int);
+int cpio_rd(ARCHD *, char *);
+off_t cpio_endrd(void);
+int cpio_stwr(void);
+int cpio_wr(ARCHD *);
+int vcpio_id(char *, int);
+int crc_id(char *, int);
+int crc_strd(void);
+int vcpio_rd(ARCHD *, char *);
+off_t vcpio_endrd(void);
+int crc_stwr(void);
+int vcpio_wr(ARCHD *);
+int bcpio_id(char *, int);
+int bcpio_rd(ARCHD *, char *);
+off_t bcpio_endrd(void);
+int bcpio_wr(ARCHD *);
+
+/*
+ * file_subs.c
+ */
+extern char *gnu_name_string, *gnu_link_string;
+int file_creat(ARCHD *);
+void file_close(ARCHD *, int);
+int lnk_creat(ARCHD *);
+int cross_lnk(ARCHD *);
+int chk_same(ARCHD *);
+int node_creat(ARCHD *);
+int unlnk_exist(char *, int);
+int chk_path(char *, uid_t, gid_t, char **);
+void set_ftime(char *fnm, time_t mtime, time_t atime, int frc);
+void fset_ftime(char *fnm, int, time_t mtime, time_t atime, int frc);
+int set_ids(char *, uid_t, gid_t);
+int fset_ids(char *, int, uid_t, gid_t);
+int set_lids(char *, uid_t, gid_t);
+void set_pmode(char *, mode_t);
+void fset_pmode(char *, int, mode_t);
+int file_write(int, char *, int, int *, int *, int, char *);
+void file_flush(int, char *, int);
+void rdfile_close(ARCHD *, int *);
+int set_crc(ARCHD *, int);
+
+/*
+ * ftree.c
+ */
+int ftree_start(void);
+int ftree_add(char *, int);
+void ftree_sel(ARCHD *);
+void ftree_notsel(void);
+void ftree_skipped_newer(ARCHD *);
+void ftree_chk(void);
+int next_file(ARCHD *);
+
+/*
+ * gen_subs.c
+ */
+void ls_list(ARCHD *, time_t, FILE *);
+void ls_tty(ARCHD *);
+void safe_print(const char *, FILE *);
+u_long asc_ul(char *, int, int);
+int ul_asc(u_long, char *, int, int);
+#ifndef LONG_OFF_T
+u_quad_t asc_uqd(char *, int, int);
+int uqd_asc(u_quad_t, char *, int, int);
+#endif
+size_t fieldcpy(char *, size_t, const char *, size_t);
+
+/*
+ * getoldopt.c
+ */
+int getoldopt(int, char **, const char *);
+
+/*
+ * options.c
+ */
+extern const FSUB fsub[];
+extern int ford[];
+void options(int, char **);
+OPLIST * opt_next(void);
+int opt_add(const char *);
+int bad_opt(void);
+int pax_format_opt_add(char *);
+int pax_opt(void);
+char *chdname;
+
+/*
+ * pat_rep.c
+ */
+int rep_add(char *);
+int pat_add(char *, char *);
+void pat_chk(void);
+int pat_sel(ARCHD *);
+int pat_match(ARCHD *);
+int mod_name(ARCHD *);
+int set_dest(ARCHD *, char *, int);
+
+/*
+ * pax.c
+ */
+extern int act;
+extern const FSUB *frmt;
+extern int cflag;
+extern int cwdfd;
+extern int dflag;
+extern int iflag;
+extern int kflag;
+extern int lflag;
+extern int nflag;
+extern int tflag;
+extern int uflag;
+extern int vflag;
+extern int Dflag;
+extern int Hflag;
+extern int Lflag;
+extern int Xflag;
+extern int Yflag;
+extern int Zflag;
+extern int zeroflag;
+extern int vfpart;
+extern int patime;
+extern int pmtime;
+extern int nodirs;
+extern int pmode;
+extern int pids;
+extern int rmleadslash;
+extern int secure;
+extern int exit_val;
+extern int docrc;
+extern char *dirptr;
+extern char *ltmfrmt;
+extern char *argv0;
+extern FILE *listf;
+extern char *tempfile;
+extern char *tempbase;
+extern int havechd;
+
+int main(int, char **);
+void sig_cleanup(int);
+
+/*
+ * sel_subs.c
+ */
+int sel_chk(ARCHD *);
+int grp_add(char *);
+int usr_add(char *);
+int trng_add(char *);
+
+/*
+ * tables.c
+ */
+int lnk_start(void);
+int chk_lnk(ARCHD *);
+void purg_lnk(ARCHD *);
+void lnk_end(void);
+int ftime_start(void);
+int chk_ftime(ARCHD *);
+int name_start(void);
+int add_name(char *, int, char *);
+void sub_name(char *, int *, size_t);
+int dev_start(void);
+int add_dev(ARCHD *);
+int map_dev(ARCHD *, u_long, u_long);
+int atdir_start(void);
+void atdir_end(void);
+void add_atdir(char *, dev_t, ino_t, time_t, time_t);
+int get_atdir(dev_t, ino_t, time_t *, time_t *);
+int dir_start(void);
+void add_dir(char *, size_t, struct stat *, int);
+void proc_dir(void);
+u_int st_hash(char *, int, int);
+
+/*
+ * tar.c
+ */
+extern char *gnu_hack_string;
+int tar_endwr(void);
+off_t tar_endrd(void);
+int tar_trail(ARCHD *, char *, int, int *);
+int tar_id(char *, int);
+int tar_opt(void);
+int tar_rd(ARCHD *, char *);
+int tar_wr(ARCHD *);
+int ustar_strd(void);
+int ustar_stwr(void);
+int ustar_id(char *, int);
+int ustar_rd(ARCHD *, char *);
+int ustar_wr(ARCHD *);
+
+/*
+ * pax_format.c
+ */
+extern char *header_name_g;
+extern int pax_read_or_list_mode;
+#define PAX_INVALID_ACTION_BYPASS 1
+#define PAX_INVALID_ACTION_RENAME 2
+#define PAX_INVALID_ACTION_UTF8 3
+#define PAX_INVALID_ACTION_WRITE 4
+extern int want_linkdata;
+extern int pax_invalid_action;
+extern char * pax_list_opt_format;
+extern char * pax_invalid_action_write_path;
+extern char * pax_invalid_action_write_cwd;
+void pax_format_list_output(ARCHD *, time_t, FILE *, int);
+void cleanup_pax_invalid_action(void);
+void record_pax_invalid_action_results(ARCHD *, char *);
+int perform_pax_invalid_action(ARCHD *, int);
+void adjust_copy_for_pax_options(ARCHD *);
+/*
+int pax_strd(void);
+int pax_stwr(void);
+*/
+int pax_id(char *, int);
+int pax_rd(ARCHD *, char *);
+int pax_wr(ARCHD *);
+
+/*
+ * tty_subs.c
+ */
+int tty_init(void);
+void tty_prnt(const char *, ...);
+int tty_read(char *, int);
+void paxwarn(int, const char *, ...);
+void syswarn(int, int, const char *, ...);
+
+#endif /* _PAX_EXTERN_H_ */
diff --git a/file_cmds/pax/file_subs.c b/file_cmds/pax/file_subs.c
new file mode 100644
index 0000000..e78ba2b
--- /dev/null
+++ b/file_cmds/pax/file_subs.c
@@ -0,0 +1,1180 @@
+/* $OpenBSD: file_subs.c,v 1.30 2005/11/09 19:59:06 otto Exp $ */
+/* $NetBSD: file_subs.c,v 1.4 1995/03/21 09:07:18 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)file_subs.c 8.1 (Berkeley) 5/31/93";
+#else
+__used static const char rcsid[] = "$OpenBSD: file_subs.c,v 1.30 2005/11/09 19:59:06 otto Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "pax.h"
+#include "options.h"
+#include "extern.h"
+
+static int
+mk_link(char *, struct stat *, char *, int);
+
+/*
+ * routines that deal with file operations such as: creating, removing;
+ * and setting access modes, uid/gid and times of files
+ */
+
+#define FILEBITS (S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
+#define SETBITS (S_ISUID | S_ISGID)
+#define ABITS (FILEBITS | SETBITS)
+
+/*
+ * file_creat()
+ * Create and open a file.
+ * Return:
+ * file descriptor or -1 for failure
+ */
+
+int
+file_creat(ARCHD *arcn)
+{
+ int fd = -1;
+ mode_t file_mode;
+ int oerrno;
+ int rc = 0;
+ char *path_to_open;
+ char *new_path;
+ char *cwd;
+ char cwd_buff[MAXPATHLEN];
+
+ /*
+ * Assume file doesn't exist, so just try to create it, most times this
+ * works. We have to take special handling when the file does exist. To
+ * detect this, we use O_EXCL. For example when trying to create a
+ * file and a character device or fifo exists with the same name, we
+ * can accidently open the device by mistake (or block waiting to open).
+ * If we find that the open has failed, then spend the effort to
+ * figure out why. This strategy was found to have better average
+ * performance in common use than checking the file (and the path)
+ * first with lstat.
+ */
+ file_mode = arcn->sb.st_mode & FILEBITS;
+ if ((fd = open(arcn->name, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL,
+ file_mode)) >= 0)
+ return(fd);
+
+ /*
+ * the file seems to exist. First we try to get rid of it (found to be
+ * the second most common failure when traced). If this fails, only
+ * then we go to the expense to check and create the path to the file
+ */
+ if (unlnk_exist(arcn->name, arcn->type) != 0)
+ return(-1);
+
+ path_to_open = arcn->name;
+ new_path = arcn->name;
+ cwd = getcwd(cwd_buff,sizeof(cwd_buff));
+ if (cwd==NULL) return -1;
+ for (;;) {
+ /*
+ * try to open it again, if this fails, check all the nodes in
+ * the path and give it a final try. if chk_path() finds that
+ * it cannot fix anything, we will skip the last attempt
+ */
+ if ((fd = open(path_to_open, O_WRONLY | O_CREAT | O_TRUNC,
+ file_mode)) >= 0) {
+ /* clean up the invalid_action */
+ if (pax_invalid_action>0) {
+ record_pax_invalid_action_results(arcn, path_to_open);
+ }
+ break;
+ }
+ oerrno = errno;
+ if (pax_invalid_action>0) {
+ rc = perform_pax_invalid_action(arcn, oerrno);
+ if (rc == 0) continue;
+ if (rc == 1) {
+ fd = -1;
+ break;
+ }
+ }
+ /* rc == 2 reserved for -o invalid_action=write */
+ if (nodirs || chk_path(path_to_open,arcn->sb.st_uid,arcn->sb.st_gid,
+ (rc==2) ? &new_path: NULL) < 0) {
+ syswarn((pax_invalid_action==0), oerrno, "Unable to create %s", arcn->name);
+ fd = -1;
+ break;
+ }
+ if (new_path) path_to_open = new_path; /* try again */
+ }
+ if (new_path && strcmp(new_path, arcn->name)!=0) {
+ dochdir(cwd); /* go back to original directory */
+ }
+ return(fd);
+}
+
+/*
+ * file_close()
+ * Close file descriptor to a file just created by pax. Sets modes,
+ * ownership and times as required.
+ * Return:
+ * 0 for success, -1 for failure
+ */
+
+void
+file_close(ARCHD *arcn, int fd)
+{
+ int res = 0;
+
+ if (fd < 0)
+ return;
+
+ if (close(fd) < 0)
+ syswarn(0, errno, "Unable to close file descriptor on %s",
+ arcn->name);
+
+ /*
+ * set owner/groups first as this may strip off mode bits we want
+ * then set file permission modes. Then set file access and
+ * modification times.
+ */
+ if (pids)
+ res = set_ids(arcn->name, arcn->sb.st_uid,
+ arcn->sb.st_gid);
+ else
+ res = 1; /* without pids, pax should NOT set s bits */
+
+ /*
+ * IMPORTANT SECURITY NOTE:
+ * if not preserving mode or we cannot set uid/gid, then PROHIBIT
+ * set uid/gid bits
+ */
+ if (!pmode || res)
+ arcn->sb.st_mode &= ~(SETBITS);
+ if (pmode)
+ set_pmode(arcn->name, arcn->sb.st_mode);
+ if (patime || pmtime)
+ set_ftime(arcn->name, arcn->sb.st_mtime, arcn->sb.st_atime, 0);
+}
+
+/*
+ * lnk_creat()
+ * Create a hard link to arcn->ln_name from arcn->name. arcn->ln_name
+ * must exist;
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+lnk_creat(ARCHD *arcn)
+{
+ struct stat sb;
+
+ /*
+ * we may be running as root, so we have to be sure that link target
+ * is not a directory, so we lstat and check
+ */
+ if (lstat(arcn->ln_name, &sb) < 0) {
+ syswarn(1,errno,"Unable to link to %s from %s", arcn->ln_name,
+ arcn->name);
+ return(-1);
+ }
+
+ if (S_ISDIR(sb.st_mode)) {
+ paxwarn(1, "A hard link to the directory %s is not allowed",
+ arcn->ln_name);
+ return(-1);
+ }
+
+ if (S_ISLNK(sb.st_mode)) {
+ int res;
+ char buff[PATH_MAX+1];
+ /*
+ * Conformance: cannot make hard link to symlink - just make a
+ * symlink to the target of the symlink
+ */
+ if ((res = readlink(arcn->ln_name, buff, sizeof(buff)-1)) < 0) {
+ syswarn(1,errno,"Unable to symlink to %s from %s", arcn->ln_name,
+ arcn->name);
+ return(-1);
+ }
+ buff[res] = 0;
+ res = symlink(buff, arcn->name);
+ return res;
+ }
+
+ return(mk_link(arcn->ln_name, &sb, arcn->name, 0));
+}
+
+/*
+ * cross_lnk()
+ * Create a hard link to arcn->org_name from arcn->name. Only used in copy
+ * with the -l flag. No warning or error if this does not succeed (we will
+ * then just create the file)
+ * Return:
+ * 1 if copy() should try to create this file node
+ * 0 if cross_lnk() ok, -1 for fatal flaw (like linking to self).
+ */
+
+int
+cross_lnk(ARCHD *arcn)
+{
+ /*
+ * try to make a link to original file (-l flag in copy mode). make
+ * sure we do not try to link to directories in case we are running as
+ * root (and it might succeed).
+ */
+ if (arcn->type == PAX_DIR)
+ return(1);
+ if (arcn->type == PAX_SLK) { /* for Unix 03 conformance tests 202,203 */
+ if (!Lflag)
+ return(1);
+ }
+ return(mk_link(arcn->org_name, &(arcn->sb), arcn->name, 1));
+}
+
+/*
+ * chk_same()
+ * In copy mode if we are not trying to make hard links between the src
+ * and destinations, make sure we are not going to overwrite ourselves by
+ * accident. This slows things down a little, but we have to protect all
+ * those people who make typing errors.
+ * Return:
+ * 1 the target does not exist, go ahead and copy
+ * 0 skip it file exists (-k) or may be the same as source file
+ */
+
+int
+chk_same(ARCHD *arcn)
+{
+ struct stat sb;
+
+ /*
+ * if file does not exist, return. if file exists and -k, skip it
+ * quietly
+ */
+ if (lstat(arcn->name, &sb) < 0)
+ return(1);
+ if (kflag)
+ return(0);
+
+ /*
+ * better make sure the user does not have src == dest by mistake
+ */
+ if ((arcn->sb.st_dev == sb.st_dev) && (arcn->sb.st_ino == sb.st_ino)) {
+ paxwarn(1, "Unable to copy %s, file would overwrite itself",
+ arcn->name);
+ return(0);
+ }
+ return(1);
+}
+
+/*
+ * mk_link()
+ * try to make a hard link between two files. if ign set, we do not
+ * complain.
+ * Return:
+ * 0 if successful (or we are done with this file but no error, such as
+ * finding the from file exists and the user has set -k).
+ * 1 when ign was set to indicates we could not make the link but we
+ * should try to copy/extract the file as that might work (and is an
+ * allowed option). -1 an error occurred.
+ */
+
+static int
+mk_link(char *to, struct stat *to_sb, char *from, int ign)
+{
+ struct stat sb;
+ int oerrno;
+
+ /*
+ * if from file exists, it has to be unlinked to make the link. If the
+ * file exists and -k is set, skip it quietly
+ */
+ if (lstat(from, &sb) == 0) {
+ if (kflag)
+ return(0);
+
+ /*
+ * make sure it is not the same file, protect the user
+ */
+ if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) {
+ paxwarn(1, "Unable to link file %s to itself", to);
+ return(-1);
+ }
+
+ /*
+ * try to get rid of the file, based on the type
+ */
+ if (S_ISDIR(sb.st_mode)) {
+ if (rmdir(from) < 0) {
+ syswarn(1, errno, "Unable to remove %s", from);
+ return(-1);
+ }
+ } else if (unlink(from) < 0) {
+ if (!ign) {
+ syswarn(1, errno, "Unable to remove %s", from);
+ return(-1);
+ }
+ return(1);
+ }
+ }
+
+ /*
+ * from file is gone (or did not exist), try to make the hard link.
+ * if it fails, check the path and try it again (if chk_path() says to
+ * try again)
+ */
+ for (;;) {
+ if (link(to, from) == 0)
+ break;
+ oerrno = errno;
+ if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid, NULL) == 0)
+ continue;
+ if (!ign) {
+ syswarn(1, oerrno, "Could not link to %s from %s", to,
+ from);
+ return(-1);
+ }
+ return(1);
+ }
+
+ /*
+ * all right the link was made
+ */
+ return(0);
+}
+
+/*
+ * node_creat()
+ * create an entry in the file system (other than a file or hard link).
+ * If successful, sets uid/gid modes and times as required.
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+node_creat(ARCHD *arcn)
+{
+ int res;
+ int ign = 0;
+ int oerrno;
+ int pass = 0;
+ mode_t file_mode;
+ struct stat sb;
+ char target[MAXPATHLEN];
+ char *nm = arcn->name;
+ int nmlen = arcn->nlen;
+ int len;
+
+ /*
+ * create node based on type, if that fails try to unlink the node and
+ * try again. finally check the path and try again. As noted in the
+ * file and link creation routines, this method seems to exhibit the
+ * best performance in general use workloads.
+ */
+ file_mode = arcn->sb.st_mode & FILEBITS;
+
+ for (;;) {
+ switch (arcn->type) {
+ case PAX_DIR:
+ /*
+ * If -h (or -L) was given in tar-mode, follow the
+ * potential symlink chain before trying to create the
+ * directory.
+ */
+ if (strcmp(NM_TAR, argv0) == 0 && Lflag) {
+ while (lstat(nm, &sb) == 0 &&
+ S_ISLNK(sb.st_mode)) {
+ len = readlink(nm, target,
+ sizeof target - 1);
+ if (len == -1) {
+ syswarn(0, errno,
+ "cannot follow symlink %s in chain for %s",
+ nm, arcn->name);
+ res = -1;
+ goto badlink;
+ }
+ target[len] = '\0';
+ nm = target;
+ nmlen = len;
+ }
+ }
+ res = mkdir(nm, file_mode);
+
+badlink:
+ if (ign)
+ res = 0;
+ break;
+ case PAX_CHR:
+ file_mode |= S_IFCHR;
+ res = mknod(nm, file_mode, arcn->sb.st_rdev);
+ break;
+ case PAX_BLK:
+ file_mode |= S_IFBLK;
+ res = mknod(nm, file_mode, arcn->sb.st_rdev);
+ break;
+ case PAX_FIF:
+ res = mkfifo(nm, file_mode);
+ break;
+ case PAX_SCK:
+ /*
+ * Skip sockets, operation has no meaning under BSD
+ */
+ paxwarn(0,
+ "%s skipped. Sockets cannot be copied or extracted",
+ nm);
+ return(-1);
+ case PAX_SLK:
+ res = symlink(arcn->ln_name, nm);
+ break;
+ case PAX_CTG:
+ case PAX_HLK:
+ case PAX_HRG:
+ case PAX_REG:
+ default:
+ /*
+ * we should never get here
+ */
+ paxwarn(0, "%s has an unknown file type, skipping",
+ nm);
+ return(-1);
+ }
+
+ /*
+ * if we were able to create the node break out of the loop,
+ * otherwise try to unlink the node and try again. if that
+ * fails check the full path and try a final time.
+ */
+ if (res == 0)
+ break;
+
+ /*
+ * we failed to make the node
+ */
+ oerrno = errno;
+ if ((ign = unlnk_exist(nm, arcn->type)) < 0)
+ return(-1);
+
+ if (++pass <= 1)
+ continue;
+
+ if (nodirs || chk_path(nm,arcn->sb.st_uid,arcn->sb.st_gid, NULL) < 0) {
+ syswarn(1, oerrno, "Could not create: %s", nm);
+ return(-1);
+ }
+ }
+
+ /*
+ * we were able to create the node. set uid/gid, modes and times
+ */
+ if (pids)
+ res = ((arcn->type == PAX_SLK) ?
+#if defined(__APPLE__)
+ /* Mac OS X doesn't have lchown, so don't bother */
+ 0 :
+#else
+ set_lids(nm, arcn->sb.st_uid, arcn->sb.st_gid) :
+#endif
+ set_ids(nm, arcn->sb.st_uid, arcn->sb.st_gid));
+ else
+ res = 1; /* without pids, pax should NOT set s bits */
+
+ /*
+ * symlinks are done now.
+ */
+ if (arcn->type == PAX_SLK)
+ return(0);
+
+ /*
+ * IMPORTANT SECURITY NOTE:
+ * if not preserving mode or we cannot set uid/gid, then PROHIBIT any
+ * set uid/gid bits
+ */
+ if (!pmode || res)
+ arcn->sb.st_mode &= ~(SETBITS);
+ if (pmode)
+ set_pmode(nm, arcn->sb.st_mode);
+
+ if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) {
+ /*
+ * Dirs must be processed again at end of extract to set times
+ * and modes to agree with those stored in the archive. However
+ * to allow extract to continue, we may have to also set owner
+ * rights. This allows nodes in the archive that are children
+ * of this directory to be extracted without failure. Both time
+ * and modes will be fixed after the entire archive is read and
+ * before pax exits.
+ */
+ if (access(nm, R_OK | W_OK | X_OK) < 0) {
+ if (lstat(nm, &sb) < 0) {
+ syswarn(0, errno,"Could not access %s (stat)",
+ arcn->name);
+ set_pmode(nm,file_mode | S_IRWXU);
+ } else {
+ /*
+ * We have to add rights to the dir, so we make
+ * sure to restore the mode. The mode must be
+ * restored AS CREATED and not as stored if
+ * pmode is not set.
+ */
+ set_pmode(nm,
+ ((sb.st_mode & FILEBITS) | S_IRWXU));
+ if (!pmode)
+ arcn->sb.st_mode = sb.st_mode;
+ }
+
+ /*
+ * we have to force the mode to what was set here,
+ * since we changed it from the default as created.
+ */
+ add_dir(nm, nmlen, &(arcn->sb), 1);
+ } else if (pmode || patime || pmtime)
+ add_dir(nm, nmlen, &(arcn->sb), 0);
+ }
+
+ if (patime || pmtime)
+ set_ftime(nm, arcn->sb.st_mtime, arcn->sb.st_atime, 0);
+ return(0);
+}
+
+/*
+ * unlnk_exist()
+ * Remove node from file system with the specified name. We pass the type
+ * of the node that is going to replace it. When we try to create a
+ * directory and find that it already exists, we allow processing to
+ * continue as proper modes etc will always be set for it later on.
+ * Return:
+ * 0 is ok to proceed, no file with the specified name exists
+ * -1 we were unable to remove the node, or we should not remove it (-k)
+ * 1 we found a directory and we were going to create a directory.
+ */
+
+int
+unlnk_exist(char *name, int type)
+{
+ struct stat sb;
+
+ /*
+ * the file does not exist, or -k we are done
+ */
+ if (lstat(name, &sb) < 0)
+ return(0);
+ if (kflag)
+ return(-1);
+
+ if(strstr(name, "._") != NULL) /* remove when stat works properly */
+ return(0);
+
+ if (S_ISDIR(sb.st_mode)) {
+ /*
+ * try to remove a directory, if it fails and we were going to
+ * create a directory anyway, tell the caller (return a 1)
+ */
+ if (rmdir(name) < 0) {
+ if (type == PAX_DIR)
+ return(1);
+ syswarn(1,errno,"Unable to remove directory %s", name);
+ return(-1);
+ }
+ return(0);
+ }
+
+ /*
+ * try to get rid of all non-directory type nodes
+ */
+ if (unlink(name) < 0) {
+ syswarn(1, errno, "Could not unlink %s", name);
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * chk_path()
+ * We were trying to create some kind of node in the file system and it
+ * failed. chk_path() makes sure the path up to the node exists and is
+ * writeable. When we have to create a directory that is missing along the
+ * path somewhere, the directory we create will be set to the same
+ * uid/gid as the file has (when uid and gid are being preserved).
+ * NOTE: this routine is a real performance loss. It is only used as a
+ * last resort when trying to create entries in the file system.
+ * Return:
+ * -1 when it could find nothing it is allowed to fix.
+ * 0 otherwise
+ */
+
+int
+chk_path(char *name, uid_t st_uid, gid_t st_gid, char ** new_name)
+{
+ char *spt = name;
+ int namelen = strlen(name);
+ struct stat sb;
+ int retval = -1;
+
+ /*
+ * watch out for paths with nodes stored directly in / (e.g. /bozo)
+ */
+ if (*spt == '/')
+ ++spt;
+
+ for (;;) {
+ /*
+ * work forward from the first / and check each part of the path
+ */
+ spt = strchr(spt, '/');
+ if (spt == NULL)
+ break;
+ *spt = '\0';
+
+ /*
+ * if it exists we assume it is a directory, it is not within
+ * the spec (at least it seems to read that way) to alter the
+ * file system for nodes NOT EXPLICITLY stored on the archive.
+ * If that assumption is changed, you would test the node here
+ * and figure out how to get rid of it (probably like some
+ * recursive unlink()) or fix up the directory permissions if
+ * required (do an access()).
+ */
+ if (lstat(name, &sb) == 0) {
+ *(spt++) = '/';
+ if (new_name==NULL) continue;
+ retval = 0; /* accept it one directory at a time */
+ break;
+ }
+
+ /*
+ * the path fails at this point, see if we can create the
+ * needed directory and continue on
+ */
+ if (mkdir(name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
+ *spt = '/';
+ retval = -1;
+ break;
+ }
+
+ /*
+ * we were able to create the directory. We will tell the
+ * caller that we found something to fix, and it is ok to try
+ * and create the node again.
+ */
+ retval = 0;
+ if (pids)
+ (void)set_ids(name, st_uid, st_gid);
+
+ /*
+ * make sure the user doesn't have some strange umask that
+ * causes this newly created directory to be unusable. We fix
+ * the modes and restore them back to the creation default at
+ * the end of pax
+ */
+ if ((access(name, R_OK | W_OK | X_OK) < 0) &&
+ (lstat(name, &sb) == 0)) {
+ set_pmode(name, ((sb.st_mode & FILEBITS) | S_IRWXU));
+ add_dir(name, namelen, &sb, 1);
+ }
+ *(spt++) = '/';
+ if (new_name==NULL) continue;
+ break;
+ }
+ if ((new_name != NULL) && retval==0) {
+ /* save the new path */
+ *(--spt) = '\0';
+ /*
+ printf ("chdir to %s\n", name);
+ */
+ if(0==chdir(name)) {
+ *spt++ = '/';
+ /*
+ printf ("remaining path: %s\n",spt);
+ */
+ *new_name = spt;
+ } else
+ *spt = '/';
+ }
+ return(retval);
+}
+
+/*
+ * set_ftime()
+ * Set the access time and modification time for a named file. If frc
+ * is non-zero we force these times to be set even if the user did not
+ * request access and/or modification time preservation (this is also
+ * used by -t to reset access times).
+ * When frc is zero, only those times the user has asked for are set, the
+ * other ones are left alone. We do not assume the un-documented feature
+ * of many utimes() implementations that consider a 0 time value as a do
+ * not set request.
+ */
+
+void
+set_ftime(char *fnm, time_t mtime, time_t atime, int frc)
+{
+ static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}};
+ struct stat sb;
+
+ tv[0].tv_sec = (long)atime;
+ tv[1].tv_sec = (long)mtime;
+ if (!frc && (!patime || !pmtime)) {
+ /*
+ * if we are not forcing, only set those times the user wants
+ * set. We get the current values of the times if we need them.
+ */
+ if (lstat(fnm, &sb) == 0) {
+ if (!patime)
+ tv[0].tv_sec = (long)sb.st_atime;
+ if (!pmtime)
+ tv[1].tv_sec = (long)sb.st_mtime;
+ } else
+ syswarn(0,errno,"Unable to obtain file stats %s", fnm);
+ }
+
+ /*
+ * set the times
+ */
+ if (pax_invalid_action_write_cwd) {
+ char cwd_buff[MAXPATHLEN];
+ char * cwd;
+ cwd = getcwd(&cwd_buff[0],MAXPATHLEN);
+ chdir(pax_invalid_action_write_cwd);
+ if (utimes(pax_invalid_action_write_path, tv) < 0)
+ syswarn(1, errno, "Access/modification time set failed on: %s",
+ pax_invalid_action_write_path);
+ chdir(cwd);
+ cleanup_pax_invalid_action();
+ } else {
+ if (utimes(fnm, tv) < 0)
+ syswarn(1, errno, "Access/modification time set failed on: %s",
+ fnm);
+ }
+ return;
+}
+
+void
+fset_ftime(char *fnm, int fd, time_t mtime, time_t atime, int frc)
+{
+ static struct timeval tv[2] = {{0L, 0L}, {0L, 0L}};
+ struct stat sb;
+
+ tv[0].tv_sec = (long)atime;
+ tv[1].tv_sec = (long)mtime;
+ if (!frc && (!patime || !pmtime)) {
+ /*
+ * if we are not forcing, only set those times the user wants
+ * set. We get the current values of the times if we need them.
+ */
+ if (fstat(fd, &sb) == 0) {
+ if (!patime)
+ tv[0].tv_sec = (long)sb.st_atime;
+ if (!pmtime)
+ tv[1].tv_sec = (long)sb.st_mtime;
+ } else
+ syswarn(0,errno,"Unable to obtain file stats %s", fnm);
+ }
+ /*
+ * set the times
+ */
+ if (futimes(fd, tv) < 0)
+ syswarn(1, errno, "Access/modification time set failed on: %s",
+ fnm);
+ return;
+}
+
+/*
+ * set_ids()
+ * set the uid and gid of a file system node
+ * Return:
+ * 0 when set, -1 on failure
+ */
+
+int
+set_ids(char *fnm, uid_t uid, gid_t gid)
+{
+ if (chown(fnm, uid, gid) < 0) {
+ /*
+ * ignore EPERM unless in verbose mode or being run by root.
+ * if running as pax, POSIX requires a warning.
+ */
+ if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
+ geteuid() == 0)
+ syswarn(1, errno, "Unable to set file uid/gid of %s",
+ fnm);
+ return(-1);
+ }
+ return(0);
+}
+
+int
+fset_ids(char *fnm, int fd, uid_t uid, gid_t gid)
+{
+ if (fchown(fd, uid, gid) < 0) {
+ /*
+ * ignore EPERM unless in verbose mode or being run by root.
+ * if running as pax, POSIX requires a warning.
+ */
+ if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
+ geteuid() == 0)
+ syswarn(1, errno, "Unable to set file uid/gid of %s",
+ fnm);
+ return(-1);
+ }
+ return(0);
+}
+
+#if !defined(__APPLE__)
+/*
+ * set_lids()
+ * set the uid and gid of a file system node
+ * Return:
+ * 0 when set, -1 on failure
+ */
+
+int
+set_lids(char *fnm, uid_t uid, gid_t gid)
+{
+ if (lchown(fnm, uid, gid) < 0) {
+ /*
+ * ignore EPERM unless in verbose mode or being run by root.
+ * if running as pax, POSIX requires a warning.
+ */
+ if (strcmp(NM_PAX, argv0) == 0 || errno != EPERM || vflag ||
+ geteuid() == 0)
+ syswarn(1, errno, "Unable to set file uid/gid of %s",
+ fnm);
+ return(-1);
+ }
+ return(0);
+}
+#endif /* !__APPLE__ */
+
+/*
+ * set_pmode()
+ * Set file access mode
+ */
+
+void
+set_pmode(char *fnm, mode_t mode)
+{
+ mode &= ABITS;
+ if (chmod(fnm, mode) < 0)
+ syswarn(1, errno, "Could not set permissions on %s", fnm);
+ return;
+}
+
+void
+fset_pmode(char *fnm, int fd, mode_t mode)
+{
+ mode &= ABITS;
+ if (fchmod(fd, mode) < 0)
+ syswarn(1, errno, "Could not set permissions on %s", fnm);
+ return;
+}
+
+/*
+ * file_write()
+ * Write/copy a file (during copy or archive extract). This routine knows
+ * how to copy files with lseek holes in it. (Which are read as file
+ * blocks containing all 0's but do not have any file blocks associated
+ * with the data). Typical examples of these are files created by dbm
+ * variants (.pag files). While the file size of these files are huge, the
+ * actual storage is quite small (the files are sparse). The problem is
+ * the holes read as all zeros so are probably stored on the archive that
+ * way (there is no way to determine if the file block is really a hole,
+ * we only know that a file block of all zero's can be a hole).
+ * At this writing, no major archive format knows how to archive files
+ * with holes. However, on extraction (or during copy, -rw) we have to
+ * deal with these files. Without detecting the holes, the files can
+ * consume a lot of file space if just written to disk. This replacement
+ * for write when passed the basic allocation size of a file system block,
+ * uses lseek whenever it detects the input data is all 0 within that
+ * file block. In more detail, the strategy is as follows:
+ * While the input is all zero keep doing an lseek. Keep track of when we
+ * pass over file block boundaries. Only write when we hit a non zero
+ * input. once we have written a file block, we continue to write it to
+ * the end (we stop looking at the input). When we reach the start of the
+ * next file block, start checking for zero blocks again. Working on file
+ * block boundaries significantly reduces the overhead when copying files
+ * that are NOT very sparse. This overhead (when compared to a write) is
+ * almost below the measurement resolution on many systems. Without it,
+ * files with holes cannot be safely copied. It does has a side effect as
+ * it can put holes into files that did not have them before, but that is
+ * not a problem since the file contents are unchanged (in fact it saves
+ * file space). (Except on paging files for diskless clients. But since we
+ * cannot determine one of those file from here, we ignore them). If this
+ * ever ends up on a system where CTG files are supported and the holes
+ * are not desired, just do a conditional test in those routines that
+ * call file_write() and have it call write() instead. BEFORE CLOSING THE
+ * FILE, make sure to call file_flush() when the last write finishes with
+ * an empty block. A lot of file systems will not create an lseek hole at
+ * the end. In this case we drop a single 0 at the end to force the
+ * trailing 0's in the file.
+ * ---Parameters---
+ * rem: how many bytes left in this file system block
+ * isempt: have we written to the file block yet (is it empty)
+ * sz: basic file block allocation size
+ * cnt: number of bytes on this write
+ * str: buffer to write
+ * Return:
+ * number of bytes written, -1 on write (or lseek) error.
+ */
+
+int
+file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz,
+ char *name)
+{
+ char *pt;
+ char *end;
+ int wcnt;
+ char *st = str;
+ char **strp;
+
+ /*
+ * while we have data to process
+ */
+ while (cnt) {
+ if (!*rem) {
+ /*
+ * We are now at the start of file system block again
+ * (or what we think one is...). start looking for
+ * empty blocks again
+ */
+ *isempt = 1;
+ *rem = sz;
+ }
+
+ /*
+ * only examine up to the end of the current file block or
+ * remaining characters to write, whatever is smaller
+ */
+ wcnt = MIN(cnt, *rem);
+ cnt -= wcnt;
+ *rem -= wcnt;
+ if (*isempt) {
+ /*
+ * have not written to this block yet, so we keep
+ * looking for zero's
+ */
+ pt = st;
+ end = st + wcnt;
+
+ /*
+ * look for a zero filled buffer
+ */
+ while ((pt < end) && (*pt == '\0'))
+ ++pt;
+
+ if (pt == end) {
+ /*
+ * skip, buf is empty so far
+ */
+ if (fd > -1 &&
+ lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) {
+ syswarn(1,errno,"File seek on %s",
+ name);
+ return(-1);
+ }
+ st = pt;
+ continue;
+ }
+ /*
+ * drat, the buf is not zero filled
+ */
+ *isempt = 0;
+ }
+
+ /*
+ * have non-zero data in this file system block, have to write
+ */
+ switch (fd) {
+ case -1:
+ strp = &gnu_name_string;
+ break;
+ case -2:
+ strp = &gnu_link_string;
+ break;
+ default:
+ strp = NULL;
+ break;
+ }
+ if (strp) {
+ if (*strp)
+ err(1, "WARNING! Major Internal Error! GNU hack Failing!");
+ *strp = malloc(wcnt + 1);
+ if (*strp == NULL) {
+ paxwarn(1, "Out of memory");
+ return(-1);
+ }
+ memcpy(*strp, st, wcnt);
+ (*strp)[wcnt] = '\0';
+ break;
+ } else if (write(fd, st, wcnt) != wcnt) {
+ syswarn(1, errno, "Failed write to file %s", name);
+ return(-1);
+ }
+ st += wcnt;
+ }
+ return(st - str);
+}
+
+/*
+ * file_flush()
+ * when the last file block in a file is zero, many file systems will not
+ * let us create a hole at the end. To get the last block with zeros, we
+ * write the last BYTE with a zero (back up one byte and write a zero).
+ */
+
+void
+file_flush(int fd, char *fname, int isempt)
+{
+ static char blnk[] = "\0";
+
+ /*
+ * silly test, but make sure we are only called when the last block is
+ * filled with all zeros.
+ */
+ if (!isempt)
+ return;
+
+ /*
+ * move back one byte and write a zero
+ */
+ if (lseek(fd, (off_t)-1, SEEK_CUR) < 0) {
+ syswarn(1, errno, "Failed seek on file %s", fname);
+ return;
+ }
+
+ if (write(fd, blnk, 1) < 0)
+ syswarn(1, errno, "Failed write to file %s", fname);
+ return;
+}
+
+/*
+ * rdfile_close()
+ * close a file we have beed reading (to copy or archive). If we have to
+ * reset access time (tflag) do so (the times are stored in arcn).
+ */
+
+void
+rdfile_close(ARCHD *arcn, int *fd)
+{
+ /*
+ * make sure the file is open
+ */
+ if (*fd < 0)
+ return;
+
+ (void)close(*fd);
+ *fd = -1;
+ if (!tflag)
+ return;
+
+ /*
+ * user wants last access time reset
+ */
+ set_ftime(arcn->org_name, arcn->sb.st_mtime, arcn->sb.st_atime, 1);
+ return;
+}
+
+/*
+ * set_crc()
+ * read a file to calculate its crc. This is a real drag. Archive formats
+ * that have this, end up reading the file twice (we have to write the
+ * header WITH the crc before writing the file contents. Oh well...
+ * Return:
+ * 0 if was able to calculate the crc, -1 otherwise
+ */
+
+int
+set_crc(ARCHD *arcn, int fd)
+{
+ int i;
+ int res;
+ off_t cpcnt = 0L;
+ u_long size;
+ u_int32_t crc = 0;
+ char tbuf[FILEBLK];
+ struct stat sb;
+
+ if (fd < 0) {
+ /*
+ * hmm, no fd, should never happen. well no crc then.
+ */
+ arcn->crc = 0L;
+ return(0);
+ }
+
+ if ((size = (u_long)arcn->sb.st_blksize) > (u_long)sizeof(tbuf))
+ size = (u_long)sizeof(tbuf);
+
+ /*
+ * read all the bytes we think that there are in the file. If the user
+ * is trying to archive an active file, forget this file.
+ */
+ for (;;) {
+ if ((res = read(fd, tbuf, size)) <= 0)
+ break;
+ cpcnt += res;
+ for (i = 0; i < res; ++i)
+ crc += (tbuf[i] & 0xff);
+ }
+
+ /*
+ * safety check. we want to avoid archiving files that are active as
+ * they can create inconsistent archive copies.
+ */
+ if (cpcnt != arcn->sb.st_size)
+ paxwarn(1, "File changed size %s", arcn->org_name);
+ else if (fstat(fd, &sb) < 0)
+ syswarn(1, errno, "Failed stat on %s", arcn->org_name);
+ else if (arcn->sb.st_mtime != sb.st_mtime)
+ paxwarn(1, "File %s was modified during read", arcn->org_name);
+ else if (lseek(fd, (off_t)0L, SEEK_SET) < 0)
+ syswarn(1, errno, "File rewind failed on: %s", arcn->org_name);
+ else {
+ arcn->crc = crc;
+ return(0);
+ }
+ return(-1);
+}
diff --git a/file_cmds/pax/ftree.c b/file_cmds/pax/ftree.c
new file mode 100644
index 0000000..f274241
--- /dev/null
+++ b/file_cmds/pax/ftree.c
@@ -0,0 +1,585 @@
+/* $OpenBSD: ftree.c,v 1.28 2008/05/06 06:54:28 henning Exp $ */
+/* $NetBSD: ftree.c,v 1.4 1995/03/21 09:07:21 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)ftree.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: ftree.c,v 1.28 2008/05/06 06:54:28 henning Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fts.h>
+#include "pax.h"
+#include "ftree.h"
+#include "extern.h"
+
+/*
+ * routines to interface with the fts library function.
+ *
+ * file args supplied to pax are stored on a single linked list (of type FTREE)
+ * and given to fts to be processed one at a time. pax "selects" files from
+ * the expansion of each arg into the corresponding file tree (if the arg is a
+ * directory, otherwise the node itself is just passed to pax). The selection
+ * is modified by the -n and -u flags. The user is informed when a specific
+ * file arg does not generate any selected files. -n keeps expanding the file
+ * tree arg until one of its files is selected, then skips to the next file
+ * arg. when the user does not supply the file trees as command line args to
+ * pax, they are read from stdin
+ */
+
+static FTS *ftsp = NULL; /* current FTS handle */
+static int ftsopts; /* options to be used on fts_open */
+static char *farray[2]; /* array for passing each arg to fts */
+static FTREE *fthead = NULL; /* head of linked list of file args */
+static FTREE *fttail = NULL; /* tail of linked list of file args */
+static FTREE *ftcur = NULL; /* current file arg being processed */
+static FTSENT *ftent = NULL; /* current file tree entry */
+static int ftree_skip; /* when set skip to next file arg */
+
+static int ftree_arg(void);
+static char *getpathname(char *, int);
+
+/*
+ * ftree_start()
+ * initialize the options passed to fts_open() during this run of pax
+ * options are based on the selection of pax options by the user
+ * fts_start() also calls fts_arg() to open the first valid file arg. We
+ * also attempt to reset directory access times when -t (tflag) is set.
+ * Return:
+ * 0 if there is at least one valid file arg to process, -1 otherwise
+ */
+
+int
+ftree_start(void)
+{
+ /*
+ * set up the operation mode of fts, open the first file arg. We must
+ * use FTS_NOCHDIR, as the user may have to open multiple archives and
+ * if fts did a chdir off into the boondocks, we may create an archive
+ * volume in an place where the user did not expect to.
+ */
+ ftsopts = FTS_NOCHDIR;
+
+ /*
+ * optional user flags that effect file traversal
+ * -H command line symlink follow only (half follow)
+ * -L follow sylinks (logical)
+ * -P do not follow sylinks (physical). This is the default.
+ * -X do not cross over mount points
+ * -t preserve access times on files read.
+ * -n select only the first member of a file tree when a match is found
+ * -d do not extract subtrees rooted at a directory arg.
+ */
+ if (Lflag)
+ ftsopts |= FTS_LOGICAL;
+ else
+ ftsopts |= FTS_PHYSICAL;
+ if (Hflag)
+ ftsopts |= FTS_COMFOLLOW;
+ if (Xflag)
+ ftsopts |= FTS_XDEV;
+
+ if ((fthead == NULL) && ((farray[0] = malloc(PAXPATHLEN+2)) == NULL)) {
+ paxwarn(1, "Unable to allocate memory for file name buffer");
+ return(-1);
+ }
+
+ if (ftree_arg() < 0)
+ return(-1);
+ if (tflag && (atdir_start() < 0))
+ return(-1);
+ return(0);
+}
+
+/*
+ * ftree_add()
+ * add the arg to the linked list of files to process. Each will be
+ * processed by fts one at a time
+ * Return:
+ * 0 if added to the linked list, -1 if failed
+ */
+
+int
+ftree_add(char *str, int chflg)
+{
+ FTREE *ft;
+ int len;
+
+ /*
+ * simple check for bad args
+ */
+ if ((str == NULL) || (*str == '\0')) {
+ paxwarn(0, "Invalid file name argument");
+ return(-1);
+ }
+
+ /*
+ * allocate FTREE node and add to the end of the linked list (args are
+ * processed in the same order they were passed to pax). Get rid of any
+ * trailing / the user may pass us. (watch out for / by itself).
+ */
+ if ((ft = (FTREE *)malloc(sizeof(FTREE))) == NULL) {
+ paxwarn(0, "Unable to allocate memory for filename");
+ return(-1);
+ }
+
+ if (((len = strlen(str) - 1) > 0) && (str[len] == '/'))
+ str[len] = '\0';
+ ft->fname = str;
+ ft->refcnt = 0;
+ ft->newercnt = 0;
+ ft->chflg = chflg;
+ ft->fow = NULL;
+ if (fthead == NULL) {
+ fttail = fthead = ft;
+ return(0);
+ }
+ fttail->fow = ft;
+ fttail = ft;
+ return(0);
+}
+
+/*
+ * ftree_sel()
+ * this entry has been selected by pax. bump up reference count and handle
+ * -n and -d processing.
+ */
+
+void
+ftree_sel(ARCHD *arcn)
+{
+ /*
+ * set reference bit for this pattern. This linked list is only used
+ * when file trees are supplied pax as args. The list is not used when
+ * the trees are read from stdin.
+ */
+ if (ftcur != NULL)
+ ftcur->refcnt = 1;
+
+ /*
+ * if -n we are done with this arg, force a skip to the next arg when
+ * pax asks for the next file in next_file().
+ * if -d we tell fts only to match the directory (if the arg is a dir)
+ * and not the entire file tree rooted at that point.
+ */
+ if (nflag)
+ ftree_skip = 1;
+
+ if (!dflag || (arcn->type != PAX_DIR))
+ return;
+
+ if (ftent != NULL)
+ (void)fts_set(ftsp, ftent, FTS_SKIP);
+}
+
+/*
+ * ftree_notsel()
+ * this entry has not been selected by pax.
+ */
+
+void
+ftree_notsel()
+{
+ if (ftent != NULL)
+ (void)fts_set(ftsp, ftent, FTS_SKIP);
+}
+
+/*
+ * ftree_skipped_newer()
+ * file has been skipped because a newer file exists and -u/-D given
+ */
+
+void
+ftree_skipped_newer(ARCHD *arcn)
+{
+ /* skipped due to -u/-D, mark accordingly */
+ if (ftcur != NULL)
+ ftcur->newercnt = 1;
+}
+
+/*
+ * ftree_chk()
+ * called at end on pax execution. Prints all those file args that did not
+ * have a selected member (reference count still 0)
+ */
+
+void
+ftree_chk(void)
+{
+ FTREE *ft;
+ int wban = 0;
+
+ /*
+ * make sure all dir access times were reset.
+ */
+ if (tflag)
+ atdir_end();
+
+ /*
+ * walk down list and check reference count. Print out those members
+ * that never had a match
+ */
+ for (ft = fthead; ft != NULL; ft = ft->fow) {
+ if ((ft->refcnt > 0) || ft->newercnt > 0 || ft->chflg)
+ continue;
+ if (wban == 0) {
+ paxwarn(1,"WARNING! These file names were not selected:");
+ ++wban;
+ }
+ (void)fprintf(stderr, "%s\n", ft->fname);
+ }
+}
+
+/*
+ * ftree_arg()
+ * Get the next file arg for fts to process. Can be from either the linked
+ * list or read from stdin when the user did not them as args to pax. Each
+ * arg is processed until the first successful fts_open().
+ * Return:
+ * 0 when the next arg is ready to go, -1 if out of file args (or EOF on
+ * stdin).
+ */
+
+static int
+ftree_arg(void)
+{
+
+ /*
+ * close off the current file tree
+ */
+ if (ftsp != NULL) {
+ (void)fts_close(ftsp);
+ ftsp = NULL;
+ }
+
+ /*
+ * keep looping until we get a valid file tree to process. Stop when we
+ * reach the end of the list (or get an eof on stdin)
+ */
+ for (;;) {
+ if (fthead == NULL) {
+ /*
+ * the user didn't supply any args, get the file trees
+ * to process from stdin;
+ */
+ if (getpathname(farray[0], PAXPATHLEN+1) == NULL)
+ return(-1);
+ } else {
+ /*
+ * the user supplied the file args as arguments to pax
+ */
+ if (ftcur == NULL)
+ ftcur = fthead;
+ else if ((ftcur = ftcur->fow) == NULL)
+ return(-1);
+ if (ftcur->chflg) {
+ /* First fchdir() back... */
+ if (fdochdir(cwdfd) < 0) {
+ syswarn(1, errno,
+ "Can't fchdir to starting directory");
+ return(-1);
+ }
+ if (dochdir(ftcur->fname) < 0) {
+ syswarn(1, errno, "Can't chdir to %s",
+ ftcur->fname);
+ return(-1);
+ }
+ continue;
+ } else
+ farray[0] = ftcur->fname;
+ }
+
+ /*
+ * watch it, fts wants the file arg stored in a array of char
+ * ptrs, with the last one a null. we use a two element array
+ * and set farray[0] to point at the buffer with the file name
+ * in it. We cannot pass all the file args to fts at one shot
+ * as we need to keep a handle on which file arg generates what
+ * files (the -n and -d flags need this). If the open is
+ * successful, return a 0.
+ */
+ if ((ftsp = fts_open(farray, ftsopts, NULL)) != NULL)
+ break;
+ }
+ return(0);
+}
+
+/*
+ * next_file()
+ * supplies the next file to process in the supplied archd structure.
+ * Return:
+ * 0 when contents of arcn have been set with the next file, -1 when done.
+ */
+
+int
+next_file(ARCHD *arcn)
+{
+ int cnt;
+ time_t atime;
+ time_t mtime;
+
+ /*
+ * ftree_sel() might have set the ftree_skip flag if the user has the
+ * -n option and a file was selected from this file arg tree. (-n says
+ * only one member is matched for each pattern) ftree_skip being 1
+ * forces us to go to the next arg now.
+ */
+ if (ftree_skip) {
+ /*
+ * clear and go to next arg
+ */
+ ftree_skip = 0;
+ if (ftree_arg() < 0)
+ return(-1);
+ }
+
+ /*
+ * loop until we get a valid file to process
+ */
+ for (;;) {
+ if ((ftent = fts_read(ftsp)) == NULL) {
+ if (errno)
+ syswarn(1, errno, "next_file");
+ /*
+ * out of files in this tree, go to next arg, if none
+ * we are done
+ */
+ if (ftree_arg() < 0)
+ return(-1);
+ continue;
+ }
+
+ /*
+ * handle each type of fts_read() flag
+ */
+ switch (ftent->fts_info) {
+ case FTS_D:
+ case FTS_DEFAULT:
+ case FTS_F:
+ case FTS_SL:
+ /*
+ * these are all ok
+ */
+ break;
+ case FTS_SLNONE: /* was same as above cases except Unix
+ conformance requires this error check */
+ if (Hflag || Lflag) { /* -H or -L was specified */
+ if (ftent->fts_errno)
+ paxwarn(1, "%s: %s",
+ ftent->fts_name, strerror(ftent->fts_errno));
+ }
+ break;
+ case FTS_DP:
+ /*
+ * already saw this directory. If the user wants file
+ * access times reset, we use this to restore the
+ * access time for this directory since this is the
+ * last time we will see it in this file subtree
+ * remember to force the time (this is -t on a read
+ * directory, not a created directory).
+ */
+ if (!tflag || (get_atdir(ftent->fts_statp->st_dev,
+ ftent->fts_statp->st_ino, &mtime, &atime) < 0))
+ continue;
+ set_ftime(ftent->fts_path, mtime, atime, 1);
+ continue;
+ case FTS_DC:
+ /*
+ * fts claims a file system cycle
+ */
+ paxwarn(1,"File system cycle found at %s",ftent->fts_path);
+ continue;
+ case FTS_DNR:
+ syswarn(1, ftent->fts_errno,
+ "Unable to read directory %s", ftent->fts_path);
+ continue;
+ case FTS_ERR:
+ syswarn(1, ftent->fts_errno,
+ "File system traversal error");
+ continue;
+ case FTS_NS:
+ case FTS_NSOK:
+ syswarn(1, ftent->fts_errno,
+ "Unable to access %s", ftent->fts_path);
+ continue;
+ }
+
+ /*
+ * ok got a file tree node to process. copy info into arcn
+ * structure (initialize as required)
+ */
+ arcn->skip = 0;
+ arcn->pad = 0;
+ arcn->ln_nlen = 0;
+ arcn->ln_name[0] = '\0';
+ memcpy(&arcn->sb, ftent->fts_statp, sizeof(arcn->sb));
+
+ /*
+ * file type based set up and copy into the arcn struct
+ * SIDE NOTE:
+ * we try to reset the access time on all files and directories
+ * we may read when the -t flag is specified. files are reset
+ * when we close them after copying. we reset the directories
+ * when we are done with their file tree (we also clean up at
+ * end in case we cut short a file tree traversal). However
+ * there is no way to reset access times on symlinks.
+ */
+ switch (S_IFMT & arcn->sb.st_mode) {
+ case S_IFDIR:
+ arcn->type = PAX_DIR;
+ if (!tflag)
+ break;
+ add_atdir(ftent->fts_path, arcn->sb.st_dev,
+ arcn->sb.st_ino, arcn->sb.st_mtime,
+ arcn->sb.st_atime);
+ break;
+ case S_IFCHR:
+ arcn->type = PAX_CHR;
+ break;
+ case S_IFBLK:
+ arcn->type = PAX_BLK;
+ break;
+ case S_IFREG:
+ /*
+ * only regular files with have data to store on the
+ * archive. all others will store a zero length skip.
+ * the skip field is used by pax for actual data it has
+ * to read (or skip over).
+ */
+ arcn->type = PAX_REG;
+ arcn->skip = arcn->sb.st_size;
+ break;
+ case S_IFLNK:
+ arcn->type = PAX_SLK;
+ /*
+ * have to read the symlink path from the file
+ */
+ if ((cnt = readlink(ftent->fts_path, arcn->ln_name,
+ PAXPATHLEN)) < 0) {
+ syswarn(1, errno, "Unable to read symlink %s",
+ ftent->fts_path);
+ continue;
+ }
+ /*
+ * set link name length, watch out readlink does not
+ * always NUL terminate the link path
+ */
+ arcn->ln_name[cnt] = '\0';
+ arcn->ln_nlen = cnt;
+ break;
+ case S_IFSOCK:
+ /*
+ * under BSD storing a socket is senseless but we will
+ * let the format specific write function make the
+ * decision of what to do with it.
+ */
+ arcn->type = PAX_SCK;
+ break;
+ case S_IFIFO:
+ arcn->type = PAX_FIF;
+ break;
+ }
+ break;
+ }
+
+ /*
+ * copy file name, set file name length
+ */
+ arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name));
+ if (arcn->nlen >= sizeof(arcn->name))
+ arcn->nlen = sizeof(arcn->name) - 1; /* XXX truncate? */
+ arcn->org_name = ftent->fts_path;
+ return(0);
+}
+
+/*
+ * getpathname()
+ * Reads a pathname from stdin, handling NUL- or newline-termination.
+ * Return:
+ * NULL at end of file, otherwise the NUL-terminated buffer.
+ */
+
+static char *
+getpathname(char *buf, int buflen)
+{
+ char *bp, *ep;
+ int ch, term;
+
+ if (zeroflag) {
+ /*
+ * Read a NUL-terminated pathname, being especially
+ * paranoid about proper termination and pathname length.
+ */
+ for (bp = buf, ep = buf + buflen; bp < ep; bp++) {
+ if ((ch = getchar()) == EOF) {
+ if (bp != buf)
+ paxwarn(1, "Ignoring unterminated "
+ "pathname at EOF");
+ return(NULL);
+ }
+ if ((*bp = ch) == '\0')
+ return(buf);
+ }
+ /* Too long - skip this path */
+ *--bp = '\0';
+ term = '\0';
+ } else {
+ if (fgets(buf, buflen, stdin) == NULL)
+ return(NULL);
+ if ((bp = strchr(buf, '\n')) != NULL || feof(stdin)) {
+ if (bp != NULL)
+ *bp = '\0';
+ return(buf);
+ }
+ /* Too long - skip this path */
+ term = '\n';
+ }
+ while ((ch = getchar()) != term && ch != EOF)
+ ;
+ paxwarn(1, "Ignoring too-long pathname: %s", buf);
+ return(NULL);
+}
diff --git a/file_cmds/pax/ftree.h b/file_cmds/pax/ftree.h
new file mode 100644
index 0000000..0203815
--- /dev/null
+++ b/file_cmds/pax/ftree.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: ftree.h,v 1.5 2008/05/06 06:54:28 henning Exp $ */
+/* $NetBSD: ftree.h,v 1.3 1995/03/21 09:07:23 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ftree.h 8.1 (Berkeley) 5/31/93
+ */
+
+#ifndef _FTREE_H_
+#define _FTREE_H_
+
+/*
+ * Data structure used by the ftree.c routines to store the file args to be
+ * handed to fts(). It keeps a reference count of which args generated a
+ * "selected" member
+ */
+
+typedef struct ftree {
+ char *fname; /* file tree name */
+ int refcnt; /* has tree had a selected file? */
+ int newercnt; /* skipped due to -u/-D */
+ int chflg; /* change directory flag */
+ struct ftree *fow; /* pointer to next entry on list */
+} FTREE;
+
+#endif /* _FTREE_H_ */
diff --git a/file_cmds/pax/gen_subs.c b/file_cmds/pax/gen_subs.c
new file mode 100644
index 0000000..cf821fb
--- /dev/null
+++ b/file_cmds/pax/gen_subs.c
@@ -0,0 +1,458 @@
+/* $OpenBSD: gen_subs.c,v 1.19 2007/04/04 21:55:10 millert Exp $ */
+/* $NetBSD: gen_subs.c,v 1.5 1995/03/21 09:07:26 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)gen_subs.c 8.1 (Berkeley) 5/31/93";
+#else
+__used static const char rcsid[] = "$OpenBSD: gen_subs.c,v 1.19 2007/04/04 21:55:10 millert Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vis.h>
+#include <langinfo.h>
+#include "pax.h"
+#include "extern.h"
+
+/*
+ * a collection of general purpose subroutines used by pax
+ */
+
+/*
+ * constants used by ls_list() when printing out archive members
+ */
+#define MODELEN 20
+#define DATELEN 64
+#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
+#define CURFRMTM "%b %e %H:%M"
+#define OLDFRMTM "%b %e %Y"
+#define CURFRMTD "%e %b %H:%M"
+#define OLDFRMTD "%e %b %Y"
+#define NAME_WIDTH 8
+
+static int d_first = -1;
+
+/*
+ * ls_list()
+ * list the members of an archive in ls format
+ */
+
+void
+ls_list(ARCHD *arcn, time_t now, FILE *fp)
+{
+ struct stat *sbp;
+ char f_mode[MODELEN];
+ char f_date[DATELEN];
+ const char *timefrmt;
+ int term;
+
+ term = zeroflag ? '\0' : '\n'; /* path termination character */
+
+ /*
+ * if not verbose, just print the file name
+ */
+ if (!vflag) {
+ if (zeroflag)
+ (void)fputs(arcn->name, fp);
+ else
+ safe_print(arcn->name, fp);
+ (void)putc(term, fp);
+ (void)fflush(fp);
+ return;
+ }
+
+ if (pax_list_opt_format) {
+ pax_format_list_output(arcn, now, fp, term);
+ return;
+ }
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ /*
+ * user wants long mode
+ */
+ sbp = &(arcn->sb);
+ strmode(sbp->st_mode, f_mode);
+
+ /*
+ * time format based on age compared to the time pax was started.
+ */
+ if ((sbp->st_mtime + SIXMONTHS) <= now ||
+ sbp->st_mtime > now)
+ timefrmt = d_first ? OLDFRMTD : OLDFRMTM;
+ else
+ timefrmt = d_first ? CURFRMTD : CURFRMTM;
+
+ /*
+ * print file mode, link count, uid, gid and time
+ */
+ if (strftime(f_date,DATELEN,timefrmt,localtime(&(sbp->st_mtime))) == 0)
+ f_date[0] = '\0';
+#define UT_NAMESIZE 8
+ (void)fprintf(fp, "%s%2u %-*.*s %-*.*s ", f_mode, sbp->st_nlink,
+ NAME_WIDTH, UT_NAMESIZE, name_uid(sbp->st_uid, 1),
+ NAME_WIDTH, UT_NAMESIZE, name_gid(sbp->st_gid, 1));
+
+ /*
+ * print device id's for devices, or sizes for other nodes
+ */
+ if ((arcn->type == PAX_CHR) || (arcn->type == PAX_BLK))
+# ifdef LONG_OFF_T
+ (void)fprintf(fp, "%4u,%4u ", MAJOR(sbp->st_rdev),
+# else
+ (void)fprintf(fp, "%4lu,%4lu ", (unsigned long)MAJOR(sbp->st_rdev),
+# endif
+ (unsigned long)MINOR(sbp->st_rdev));
+ else {
+ /*
+ * UNIX compliance fix: printing filename length for soft links
+ * from arcn->ln_nlen instead of sbp->st_size, which is 0.
+ */
+ off_t nlen;
+ if (arcn->type == PAX_SLK) {
+ nlen = arcn->ln_nlen;
+ } else {
+ nlen = sbp->st_size;
+ }
+# ifdef LONG_OFF_T
+ (void)fprintf(fp, "%9lu ", nlen);
+# else
+ (void)fprintf(fp, "%9qu ", nlen);
+# endif
+ }
+
+ /*
+ * print name and link info for hard and soft links
+ */
+ (void)fputs(f_date, fp);
+ (void)putc(' ', fp);
+ safe_print(arcn->name, fp);
+ if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
+ fputs(" == ", fp);
+ safe_print(arcn->ln_name, fp);
+ } else if (arcn->type == PAX_SLK) {
+ fputs(" -> ", fp);
+ safe_print(arcn->ln_name, fp);
+ }
+ (void)putc(term, fp);
+ (void)fflush(fp);
+ return;
+}
+
+/*
+ * tty_ls()
+ * print a short summary of file to tty.
+ */
+
+void
+ls_tty(ARCHD *arcn)
+{
+ char f_date[DATELEN];
+ char f_mode[MODELEN];
+ const char *timefrmt;
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+
+ if ((arcn->sb.st_mtime + SIXMONTHS) <= time(NULL))
+ timefrmt = d_first ? OLDFRMTD : OLDFRMTM;
+ else
+ timefrmt = d_first ? CURFRMTD : CURFRMTM;
+
+ /*
+ * convert time to string, and print
+ */
+ if (strftime(f_date, DATELEN, timefrmt,
+ localtime(&(arcn->sb.st_mtime))) == 0)
+ f_date[0] = '\0';
+ strmode(arcn->sb.st_mode, f_mode);
+ tty_prnt("%s%s %s\n", f_mode, f_date, arcn->name);
+ return;
+}
+
+void
+safe_print(const char *str, FILE *fp)
+{
+ /*
+ * if printing to a tty, use strvis(3) to print special characters.
+ */
+ if (isatty(fileno(fp))) {
+ /*
+ * The size of visbuf must be four times the number
+ * of bytes encoded from str (plus one for the NUL).
+ */
+ char *visbuf = (char *) malloc(sizeof(char) * (4 * strlen(str) + 1));
+ if (visbuf == NULL) {
+ paxwarn(1, "Out of memory");
+ return;
+ }
+ /*
+ * using strvis(3) instead of vis(3) to account for multibyte
+ * characters
+ */
+ (void)strvis(visbuf, str, VIS_CSTYLE);
+ (void)fputs(visbuf, fp);
+ free(visbuf);
+ } else {
+ (void)fputs(str, fp);
+ }
+}
+
+/*
+ * asc_ul()
+ * convert hex/octal character string into a u_long. We do not have to
+ * check for overflow! (the headers in all supported formats are not large
+ * enough to create an overflow).
+ * NOTE: strings passed to us are NOT TERMINATED.
+ * Return:
+ * unsigned long value
+ */
+
+u_long
+asc_ul(char *str, int len, int base)
+{
+ char *stop;
+ u_long tval = 0;
+
+ stop = str + len;
+
+ /*
+ * skip over leading blanks and zeros
+ */
+ while ((str < stop) && ((*str == ' ') || (*str == '0')))
+ ++str;
+
+ /*
+ * for each valid digit, shift running value (tval) over to next digit
+ * and add next digit
+ */
+ if (base == HEX) {
+ while (str < stop) {
+ if ((*str >= '0') && (*str <= '9'))
+ tval = (tval << 4) + (*str++ - '0');
+ else if ((*str >= 'A') && (*str <= 'F'))
+ tval = (tval << 4) + 10 + (*str++ - 'A');
+ else if ((*str >= 'a') && (*str <= 'f'))
+ tval = (tval << 4) + 10 + (*str++ - 'a');
+ else
+ break;
+ }
+ } else {
+ while ((str < stop) && (*str >= '0') && (*str <= '7'))
+ tval = (tval << 3) + (*str++ - '0');
+ }
+ return(tval);
+}
+
+/*
+ * ul_asc()
+ * convert an unsigned long into an hex/oct ascii string. pads with LEADING
+ * ascii 0's to fill string completely
+ * NOTE: the string created is NOT TERMINATED.
+ */
+
+int
+ul_asc(u_long val, char *str, int len, int base)
+{
+ char *pt;
+ u_long digit;
+
+ /*
+ * WARNING str is not '\0' terminated by this routine
+ */
+ pt = str + len - 1;
+
+ /*
+ * do a tailwise conversion (start at right most end of string to place
+ * least significant digit). Keep shifting until conversion value goes
+ * to zero (all digits were converted)
+ */
+ if (base == HEX) {
+ while (pt >= str) {
+ if ((digit = (val & 0xf)) < 10)
+ *pt-- = '0' + (char)digit;
+ else
+ *pt-- = 'a' + (char)(digit - 10);
+ if ((val = (val >> 4)) == (u_long)0)
+ break;
+ }
+ } else {
+ while (pt >= str) {
+ *pt-- = '0' + (char)(val & 0x7);
+ if ((val = (val >> 3)) == (u_long)0)
+ break;
+ }
+ }
+
+ /*
+ * pad with leading ascii ZEROS. We return -1 if we ran out of space.
+ */
+ while (pt >= str)
+ *pt-- = '0';
+ if (val != (u_long)0)
+ return(-1);
+ return(0);
+}
+
+#ifndef LONG_OFF_T
+/*
+ * asc_uqd()
+ * convert hex/octal character string into a u_quad_t. We do not have to
+ * check for overflow! (the headers in all supported formats are not large
+ * enough to create an overflow).
+ * NOTE: strings passed to us are NOT TERMINATED.
+ * Return:
+ * u_quad_t value
+ */
+
+u_quad_t
+asc_uqd(char *str, int len, int base)
+{
+ char *stop;
+ u_quad_t tval = 0;
+
+ stop = str + len;
+
+ /*
+ * skip over leading blanks and zeros
+ */
+ while ((str < stop) && ((*str == ' ') || (*str == '0')))
+ ++str;
+
+ /*
+ * for each valid digit, shift running value (tval) over to next digit
+ * and add next digit
+ */
+ if (base == HEX) {
+ while (str < stop) {
+ if ((*str >= '0') && (*str <= '9'))
+ tval = (tval << 4) + (*str++ - '0');
+ else if ((*str >= 'A') && (*str <= 'F'))
+ tval = (tval << 4) + 10 + (*str++ - 'A');
+ else if ((*str >= 'a') && (*str <= 'f'))
+ tval = (tval << 4) + 10 + (*str++ - 'a');
+ else
+ break;
+ }
+ } else {
+ while ((str < stop) && (*str >= '0') && (*str <= '7'))
+ tval = (tval << 3) + (*str++ - '0');
+ }
+ return(tval);
+}
+
+/*
+ * uqd_asc()
+ * convert an u_quad_t into a hex/oct ascii string. pads with LEADING
+ * ascii 0's to fill string completely
+ * NOTE: the string created is NOT TERMINATED.
+ */
+
+int
+uqd_asc(u_quad_t val, char *str, int len, int base)
+{
+ char *pt;
+ u_quad_t digit;
+
+ /*
+ * WARNING str is not '\0' terminated by this routine
+ */
+ pt = str + len - 1;
+
+ /*
+ * do a tailwise conversion (start at right most end of string to place
+ * least significant digit). Keep shifting until conversion value goes
+ * to zero (all digits were converted)
+ */
+ if (base == HEX) {
+ while (pt >= str) {
+ if ((digit = (val & 0xf)) < 10)
+ *pt-- = '0' + (char)digit;
+ else
+ *pt-- = 'a' + (char)(digit - 10);
+ if ((val = (val >> 4)) == (u_quad_t)0)
+ break;
+ }
+ } else {
+ while (pt >= str) {
+ *pt-- = '0' + (char)(val & 0x7);
+ if ((val = (val >> 3)) == (u_quad_t)0)
+ break;
+ }
+ }
+
+ /*
+ * pad with leading ascii ZEROS. We return -1 if we ran out of space.
+ */
+ while (pt >= str)
+ *pt-- = '0';
+ if (val != (u_quad_t)0)
+ return(-1);
+ return(0);
+}
+#endif
+
+/*
+ * Copy at max min(bufz, fieldsz) chars from field to buf, stopping
+ * at the first NUL char. NUL terminate buf if there is room left.
+ */
+size_t
+fieldcpy(char *buf, size_t bufsz, const char *field, size_t fieldsz)
+{
+ char *p = buf;
+ const char *q = field;
+ size_t i = 0;
+
+ if (fieldsz > bufsz)
+ fieldsz = bufsz;
+ while (i < fieldsz && *q != '\0') {
+ *p++ = *q++;
+ i++;
+ }
+ if (i < bufsz)
+ *p = '\0';
+ return(i);
+}
diff --git a/file_cmds/pax/getoldopt.c b/file_cmds/pax/getoldopt.c
new file mode 100644
index 0000000..3133f62
--- /dev/null
+++ b/file_cmds/pax/getoldopt.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: getoldopt.c,v 1.8 2003/07/02 21:19:33 deraadt Exp $ */
+/* $NetBSD: getoldopt.c,v 1.3 1995/03/21 09:07:28 cgd Exp $ */
+
+/*
+ * Plug-compatible replacement for getopt() for parsing tar-like
+ * arguments. If the first argument begins with "-", it uses getopt;
+ * otherwise, it uses the old rules used by tar, dump, and ps.
+ *
+ * Written 25 August 1985 by John Gilmore (ihnp4!hoptoad!gnu) and placed
+ * in the Public Domain for your edification and enjoyment.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char rcsid[] = "$OpenBSD: getoldopt.c,v 1.8 2003/07/02 21:19:33 deraadt Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "pax.h"
+#include "extern.h"
+
+int
+getoldopt(int argc, char **argv, const char *optstring)
+{
+ static char *key; /* Points to next keyletter */
+ static char use_getopt; /* !=0 if argv[1][0] was '-' */
+ char c;
+ char *place;
+
+ optarg = NULL;
+
+ if (key == NULL) { /* First time */
+ if (argc < 2)
+ return (-1);
+ key = argv[1];
+ if (*key == '-')
+ use_getopt++;
+ else
+ optind = 2;
+ }
+
+ if (use_getopt)
+ return (getopt(argc, argv, optstring));
+
+ c = *key++;
+ if (c == '\0') {
+ key--;
+ return (-1);
+ }
+ place = strchr(optstring, c);
+
+ if (place == NULL || c == ':') {
+ fprintf(stderr, "%s: unknown option %c\n", argv[0], c);
+ return ('?');
+ }
+
+ place++;
+ if (*place == ':') {
+ if (optind < argc) {
+ optarg = argv[optind];
+ optind++;
+ } else {
+ fprintf(stderr, "%s: %c argument missing\n",
+ argv[0], c);
+ return ('?');
+ }
+ }
+
+ return (c);
+}
diff --git a/file_cmds/pax/options.c b/file_cmds/pax/options.c
new file mode 100644
index 0000000..0544e5e
--- /dev/null
+++ b/file_cmds/pax/options.c
@@ -0,0 +1,1747 @@
+/* $OpenBSD: options.c,v 1.70 2008/06/11 00:49:08 pvalchev Exp $ */
+/* $NetBSD: options.c,v 1.6 1996/03/26 23:54:18 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)options.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: options.c,v 1.70 2008/06/11 00:49:08 pvalchev Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <search.h>
+#ifndef __APPLE__
+#include <sys/mtio.h>
+#endif /* __APPLE__ */
+#include <sys/param.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <paths.h>
+#include <getopt.h>
+#include "pax.h"
+#include "options.h"
+#include "cpio.h"
+#include "tar.h"
+#include "extern.h"
+
+/*
+ * Routines which handle command line options
+ */
+
+static char flgch[] = FLGCH; /* list of all possible flags */
+static OPLIST *ophead = NULL; /* head for format specific options -x */
+static OPLIST *optail = NULL; /* option tail */
+
+static int no_op(void);
+static void printflg(unsigned int);
+static int c_frmt(const void *, const void *);
+static off_t str_offt(char *);
+static char *pax_getline(FILE *fp);
+static void pax_options(int, char **);
+void pax_usage(void);
+static void tar_options(int, char **);
+static void tar_usage(void);
+static void cpio_options(int, char **);
+static void cpio_usage(void);
+
+/* errors from getline */
+#define GETLINE_FILE_CORRUPT 1
+#define GETLINE_OUT_OF_MEM 2
+static int getline_error;
+
+
+#define GZIP_CMD "gzip" /* command to run as gzip */
+#define COMPRESS_CMD "compress" /* command to run as compress */
+#define BZIP2_CMD "bzip2" /* command to run as bzip2 */
+
+/*
+ * Format specific routine table - MUST BE IN SORTED ORDER BY NAME
+ * (see pax.h for description of each function)
+ *
+ * name, blksz, hdsz, udev, hlk, blkagn, inhead, id, st_read,
+ * read, end_read, st_write, write, end_write, trail,
+ * rd_data, wr_data, options
+ */
+
+const FSUB fsub[] = {
+/* OLD BINARY CPIO */
+ {"bcpio", 5120, sizeof(HD_BCPIO), 1, 0, 0, 1, bcpio_id, cpio_strd,
+ bcpio_rd, bcpio_endrd, cpio_stwr, bcpio_wr, cpio_endwr, cpio_trail,
+ rd_wrfile, wr_rdfile, bad_opt},
+
+/* OLD OCTAL CHARACTER CPIO */
+ {"cpio", 5120, sizeof(HD_CPIO), 1, 0, 0, 1, cpio_id, cpio_strd,
+ cpio_rd, cpio_endrd, cpio_stwr, cpio_wr, cpio_endwr, cpio_trail,
+ rd_wrfile, wr_rdfile, bad_opt},
+
+/* POSIX 3 PAX */
+ {"pax", 5120, BLKMULT, 0, 1, BLKMULT, 0, pax_id, ustar_strd,
+ pax_rd, tar_endrd, ustar_stwr, pax_wr, tar_endwr, tar_trail,
+ rd_wrfile, wr_rdfile, pax_opt},
+
+/* SVR4 HEX CPIO */
+ {"sv4cpio", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, vcpio_id, cpio_strd,
+ vcpio_rd, vcpio_endrd, cpio_stwr, vcpio_wr, cpio_endwr, cpio_trail,
+ rd_wrfile, wr_rdfile, bad_opt},
+
+/* SVR4 HEX CPIO WITH CRC */
+ {"sv4crc", 5120, sizeof(HD_VCPIO), 1, 0, 0, 1, crc_id, crc_strd,
+ vcpio_rd, vcpio_endrd, crc_stwr, vcpio_wr, cpio_endwr, cpio_trail,
+ rd_wrfile, wr_rdfile, bad_opt},
+
+/* OLD TAR */
+ {"tar", 10240, BLKMULT, 0, 1, BLKMULT, 0, tar_id, no_op,
+ tar_rd, tar_endrd, no_op, tar_wr, tar_endwr, tar_trail,
+ rd_wrfile, wr_rdfile, tar_opt},
+
+/* POSIX USTAR */
+ {"ustar", 10240, BLKMULT, 0, 1, BLKMULT, 0, ustar_id, ustar_strd,
+ ustar_rd, tar_endrd, ustar_stwr, ustar_wr, tar_endwr, tar_trail,
+ rd_wrfile, wr_rdfile, bad_opt},
+};
+#define F_OCPIO 0 /* format when called as cpio -6 */
+#define F_ACPIO 1 /* format when called as cpio -c */
+#define F_PAX 2 /* -x pax */
+#define F_SCPIO 3 /* -x sv4cpio */
+#define F_CPIO 4 /* format when called as cpio */
+#define F_OTAR 5 /* format when called as tar -o */
+#define F_TAR 6 /* format when called as tar */
+#define DEFLT F_TAR /* default write format from list above */
+
+/*
+ * ford is the archive search order used by get_arc() to determine what kind
+ * of archive we are dealing with. This helps to properly id archive formats
+ * some formats may be subsets of others....
+ */
+int ford[] = {F_PAX, F_TAR, F_OTAR, F_CPIO, F_SCPIO, F_ACPIO, F_OCPIO, -1 };
+
+/*
+ * Do we have -C anywhere?
+ */
+int havechd = 0;
+
+/*
+ * options()
+ * figure out if we are pax, tar or cpio. Call the appropriate options
+ * parser
+ */
+
+void
+options(int argc, char **argv)
+{
+
+ /*
+ * Are we acting like pax, tar or cpio (based on argv[0])
+ */
+ if ((argv0 = strrchr(argv[0], '/')) != NULL)
+ argv0++;
+ else
+ argv0 = argv[0];
+
+ if (strcmp(NM_TAR, argv0) == 0) {
+ tar_options(argc, argv);
+ return;
+ } else if (strcmp(NM_CPIO, argv0) == 0) {
+ cpio_options(argc, argv);
+ return;
+ }
+ /*
+ * assume pax as the default
+ */
+ argv0 = NM_PAX;
+ pax_options(argc, argv);
+}
+
+#define OPT_INSECURE 1
+struct option pax_longopts[] = {
+ { "insecure", no_argument, 0, OPT_INSECURE },
+ { 0, 0, 0, 0 },
+};
+
+/*
+ * pax_options()
+ * look at the user specified flags. set globals as required and check if
+ * the user specified a legal set of flags. If not, complain and exit
+ */
+
+static void
+pax_options(int argc, char **argv)
+{
+ int c;
+ size_t i;
+ unsigned int flg = 0;
+ unsigned int bflg = 0;
+ char *pt;
+ FSUB tmp;
+ size_t n_fsub;
+ char * tmp_name;
+
+ listf = stderr;
+ /*
+ * process option flags
+ */
+ while ((c=getopt_long(argc,argv,"0ab:cdf:ijklno:p:rs:tuvwx:zB:DE:G:HLOPT:U:XYZ", pax_longopts, NULL)) != -1) {
+ switch (c) {
+ case '0':
+ /*
+ * Use \0 as pathname terminator.
+ * (For use with the -print0 option of find(1).)
+ */
+ zeroflag = 1;
+ flg |= C0F;
+ break;
+ case 'a':
+ /*
+ * append
+ */
+ flg |= AF;
+ break;
+ case 'b':
+ /*
+ * specify blocksize
+ */
+ flg |= BF;
+ if ((wrblksz = (int)str_offt(optarg)) <= 0) {
+ paxwarn(1, "Invalid block size %s", optarg);
+ pax_usage();
+ }
+ break;
+ case 'c':
+ /*
+ * inverse match on patterns
+ */
+ cflag = 1;
+ flg |= CF;
+ break;
+ case 'd':
+ /*
+ * match only dir on extract, not the subtree at dir
+ */
+ dflag = 1;
+ flg |= DF;
+ break;
+ case 'f':
+ /*
+ * filename where the archive is stored
+ */
+ if ((optarg[0] == '-') && (optarg[1]== '\0')) {
+ /*
+ * treat a - as stdin (like tar)
+ */
+ arcname = NULL;
+ break;
+ }
+ arcname = optarg;
+ flg |= FF;
+ break;
+ case 'i':
+ /*
+ * interactive file rename
+ */
+ iflag = 1;
+ flg |= IF;
+ break;
+ case 'j':
+ /*
+ * use bzip2. Non standard option.
+ */
+ gzip_program = BZIP2_CMD;
+ break;
+ case 'k':
+ /*
+ * do not clobber files that exist
+ */
+ kflag = 1;
+ flg |= KF;
+ break;
+ case 'l':
+ /*
+ * try to link src to dest with copy (-rw)
+ */
+ lflag = 1;
+ flg |= LF;
+ break;
+ case 'n':
+ /*
+ * select first match for a pattern only
+ */
+ nflag = 1;
+ flg |= NF;
+ break;
+ case 'o':
+ /*
+ * pass format specific options
+ */
+ flg |= OF;
+ if (pax_format_opt_add(optarg) < 0)
+ pax_usage();
+ break;
+ case 'p':
+ /*
+ * specify file characteristic options
+ */
+ for (pt = optarg; *pt != '\0'; ++pt) {
+ switch (*pt) {
+ case 'a':
+ /*
+ * do not preserve access time
+ */
+ patime = 0;
+ break;
+ case 'e':
+ /*
+ * preserve user id, group id, file
+ * mode, access/modification times
+ */
+ pids = 1;
+ pmode = 1;
+ patime = 1;
+ pmtime = 1;
+ break;
+ case 'm':
+ /*
+ * do not preserve modification time
+ */
+ pmtime = 0;
+ break;
+ case 'o':
+ /*
+ * preserve uid/gid
+ */
+ pids = 1;
+ break;
+ case 'p':
+ /*
+ * preserve file mode bits
+ */
+ pmode = 1;
+ break;
+ default:
+ paxwarn(1, "Invalid -p string: %c", *pt);
+ pax_usage();
+ break;
+ }
+ }
+ flg |= PF;
+ break;
+ case 'r':
+ /*
+ * read the archive
+ */
+ pax_read_or_list_mode=1;
+ flg |= RF;
+ break;
+ case 's':
+ /*
+ * file name substitution name pattern
+ */
+ if (rep_add(optarg) < 0) {
+ pax_usage();
+ break;
+ }
+ flg |= SF;
+ break;
+ case 't':
+ /*
+ * preserve access time on filesystem nodes we read
+ */
+ tflag = 1;
+ flg |= TF;
+ break;
+ case 'u':
+ /*
+ * ignore those older files
+ */
+ uflag = 1;
+ flg |= UF;
+ break;
+ case 'v':
+ /*
+ * verbose operation mode
+ */
+ vflag = 1;
+ flg |= VF;
+ break;
+ case 'w':
+ /*
+ * write an archive
+ */
+ flg |= WF;
+ break;
+ case 'x':
+ /*
+ * specify an archive format on write
+ */
+ tmp.name = optarg;
+ n_fsub = sizeof(fsub)/sizeof(FSUB);
+ if ((frmt = (FSUB *)bsearch(&tmp, fsub, n_fsub, sizeof(FSUB),
+ c_frmt)) != NULL) {
+ flg |= XF;
+ break;
+ }
+ paxwarn(1, "Unknown -x format: %s", optarg);
+ (void)fputs("pax: Known -x formats are:", stderr);
+ for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
+ (void)fprintf(stderr, " %s", fsub[i].name);
+ (void)fputs("\n\n", stderr);
+ pax_usage();
+ break;
+ case 'z':
+ /*
+ * use gzip. Non standard option.
+ */
+ gzip_program = GZIP_CMD;
+ break;
+ case 'B':
+ /*
+ * non-standard option on number of bytes written on a
+ * single archive volume.
+ */
+ if ((wrlimit = str_offt(optarg)) <= 0) {
+ paxwarn(1, "Invalid write limit %s", optarg);
+ pax_usage();
+ }
+ if (wrlimit % BLKMULT) {
+ paxwarn(1, "Write limit is not a %d byte multiple",
+ BLKMULT);
+ pax_usage();
+ }
+ flg |= CBF;
+ break;
+ case 'D':
+ /*
+ * On extraction check file inode change time before the
+ * modification of the file name. Non standard option.
+ */
+ Dflag = 1;
+ flg |= CDF;
+ break;
+ case 'E':
+ /*
+ * non-standard limit on read faults
+ * 0 indicates stop after first error, values
+ * indicate a limit, "NONE" try forever
+ */
+ flg |= CEF;
+ if (strcmp(NONE, optarg) == 0)
+ maxflt = -1;
+ else if ((maxflt = atoi(optarg)) < 0) {
+ paxwarn(1, "Error count value must be positive");
+ pax_usage();
+ }
+ break;
+ case 'G':
+ /*
+ * non-standard option for selecting files within an
+ * archive by group (gid or name)
+ */
+ if (grp_add(optarg) < 0) {
+ pax_usage();
+ break;
+ }
+ flg |= CGF;
+ break;
+ case 'H':
+ /*
+ * follow command line symlinks only
+ */
+ Hflag = 1;
+ flg |= CHF;
+ Lflag = 0; /* -H and -L are mutually exclusive */
+ flg &= ~CLF; /* only use the last one seen */
+ break;
+ case 'L':
+ /*
+ * follow symlinks
+ */
+ Lflag = 1;
+ flg |= CLF;
+ Hflag = 0; /* -H and -L are mutually exclusive */
+ flg &= ~CHF; /* only use the last one seen */
+ break;
+ case 'O':
+ /*
+ * Force one volume. Non standard option.
+ */
+ force_one_volume = 1;
+ break;
+ case 'P':
+ /*
+ * do NOT follow symlinks (default)
+ */
+ Lflag = 0;
+ flg |= CPF;
+ break;
+ case 'T':
+ /*
+ * non-standard option for selecting files within an
+ * archive by modification time range (lower,upper)
+ */
+ if (trng_add(optarg) < 0) {
+ pax_usage();
+ break;
+ }
+ flg |= CTF;
+ break;
+ case 'U':
+ /*
+ * non-standard option for selecting files within an
+ * archive by user (uid or name)
+ */
+ if (usr_add(optarg) < 0) {
+ pax_usage();
+ break;
+ }
+ flg |= CUF;
+ break;
+ case 'X':
+ /*
+ * do not pass over mount points in the file system
+ */
+ Xflag = 1;
+ flg |= CXF;
+ break;
+ case 'Y':
+ /*
+ * On extraction check file inode change time after the
+ * modification of the file name. Non standard option.
+ */
+ Yflag = 1;
+ flg |= CYF;
+ break;
+ case 'Z':
+ /*
+ * On extraction check modification time after the
+ * modification of the file name. Non standard option.
+ */
+ Zflag = 1;
+ flg |= CZF;
+ break;
+ case OPT_INSECURE:
+ secure = 0;
+ break;
+ default:
+ pax_usage();
+ break;
+ }
+ }
+
+ /*
+ * Fix for POSIX.cmd/pax/pax.ex test 132: force -wu options to look
+ * like -wua options were specified.
+ */
+ if (uflag && (flg & WF) && !(flg & RF)) { /* -w but not -r -w */
+ flg |= AF;
+ }
+
+ /*
+ * figure out the operation mode of pax read,write,extract,copy,append
+ * or list. check that we have not been given a bogus set of flags
+ * for the operation mode.
+ */
+ if (ISLIST(flg)) {
+ act = LIST;
+ pax_read_or_list_mode=1;
+ listf = stdout;
+ bflg = flg & BDLIST;
+ } else if (ISEXTRACT(flg)) {
+ act = EXTRACT;
+ bflg = flg & BDEXTR;
+ } else if (ISARCHIVE(flg)) {
+ act = ARCHIVE;
+ bflg = flg & BDARCH;
+ } else if (ISAPPND(flg)) {
+ act = APPND;
+ bflg = flg & BDARCH;
+ } else if (ISCOPY(flg)) {
+ act = COPY;
+ bflg = flg & BDCOPY;
+ } else
+ pax_usage();
+ if (bflg) {
+ printflg(flg);
+ pax_usage();
+ }
+
+ /*
+ * if we are writing (ARCHIVE) we use the default format if the user
+ * did not specify a format. when we write during an APPEND, we will
+ * adopt the format of the existing archive if none was supplied.
+ */
+ if (!(flg & XF) && (act == ARCHIVE))
+ frmt = &(fsub[DEFLT]);
+
+ /*
+ * if copying (-r and -w) and there is no -x specified, we act as
+ * if -x pax was specified.
+ */
+ if (!(flg & XF) && (act == COPY))
+ frmt = &(fsub[F_PAX]);
+
+ /*
+ * Initialize the global extended header template.
+ */
+ tmp_name = getenv("TMPDIR");
+ if (tmp_name) {
+ asprintf(&header_name_g, "%s%s", tmp_name, "/GlobalHead.%p.%n");
+ } else {
+ header_name_g = "/tmp/GlobalHead.%p.%n";
+ }
+
+ /*
+ * process the args as they are interpreted by the operation mode
+ */
+ switch (act) {
+ case LIST:
+ case EXTRACT:
+ for (; optind < argc; optind++)
+ if (pat_add(argv[optind], NULL) < 0)
+ pax_usage();
+ break;
+ case COPY:
+ if (optind >= argc) {
+ paxwarn(0, "Destination directory was not supplied");
+ pax_usage();
+ }
+ --argc;
+ dirptr = argv[argc];
+ /* FALL THROUGH */
+ case ARCHIVE:
+ case APPND:
+ for (; optind < argc; optind++)
+ if (ftree_add(argv[optind], 0) < 0)
+ pax_usage();
+ /*
+ * no read errors allowed on updates/append operation!
+ */
+ maxflt = 0;
+ break;
+ }
+}
+
+
+/*
+ * tar_options()
+ * look at the user specified flags. set globals as required and check if
+ * the user specified a legal set of flags. If not, complain and exit
+ */
+
+static void
+tar_options(int argc, char **argv)
+{
+ int c;
+ int fstdin = 0;
+ int Oflag = 0;
+ int nincfiles = 0;
+ int incfiles_max = 0;
+ struct incfile {
+ char *file;
+ char *dir;
+ };
+ struct incfile *incfiles = NULL;
+
+ /*
+ * Set default values.
+ */
+ rmleadslash = 1;
+
+ /*
+ * process option flags
+ */
+ while ((c = getoldopt(argc, argv,
+ "b:cef:hjmopqruts:vwxzBC:HI:LOPXZ014578")) != -1) {
+ switch (c) {
+ case 'b':
+ /*
+ * specify blocksize in 512-byte blocks
+ */
+ if ((wrblksz = (int)str_offt(optarg)) <= 0) {
+ paxwarn(1, "Invalid block size %s", optarg);
+ tar_usage();
+ }
+ wrblksz *= 512; /* XXX - check for int oflow */
+ break;
+ case 'c':
+ /*
+ * create an archive
+ */
+ act = ARCHIVE;
+ break;
+ case 'e':
+ /*
+ * stop after first error
+ */
+ maxflt = 0;
+ break;
+ case 'f':
+ /*
+ * filename where the archive is stored
+ */
+ if ((optarg[0] == '-') && (optarg[1]== '\0')) {
+ /*
+ * treat a - as stdin
+ */
+ fstdin = 1;
+ arcname = NULL;
+ break;
+ }
+ fstdin = 0;
+ arcname = optarg;
+ break;
+ case 'h':
+ /*
+ * follow symlinks
+ */
+ Lflag = 1;
+ break;
+ case 'j':
+ /*
+ * use bzip2. Non standard option.
+ */
+ gzip_program = BZIP2_CMD;
+ break;
+ case 'm':
+ /*
+ * do not preserve modification time
+ */
+ pmtime = 0;
+ break;
+ case 'O':
+ Oflag = 1;
+ break;
+ case 'o':
+ Oflag = 2;
+ break;
+ case 'p':
+ /*
+ * preserve uid/gid and file mode, regardless of umask
+ */
+ pmode = 1;
+ pids = 1;
+ break;
+ case 'q':
+ /*
+ * select first match for a pattern only
+ */
+ nflag = 1;
+ break;
+ case 'r':
+ case 'u':
+ /*
+ * append to the archive
+ */
+ act = APPND;
+ break;
+ case 's':
+ /*
+ * file name substitution name pattern
+ */
+ if (rep_add(optarg) < 0) {
+ tar_usage();
+ break;
+ }
+ break;
+ case 't':
+ /*
+ * list contents of the tape
+ */
+ act = LIST;
+ break;
+ case 'v':
+ /*
+ * verbose operation mode
+ */
+ vflag++;
+ break;
+ case 'w':
+ /*
+ * interactive file rename
+ */
+ iflag = 1;
+ break;
+ case 'x':
+ /*
+ * extract an archive, preserving mode,
+ * and mtime if possible.
+ */
+ act = EXTRACT;
+ pmtime = 1;
+ break;
+ case 'z':
+ /*
+ * use gzip. Non standard option.
+ */
+ gzip_program = GZIP_CMD;
+ break;
+ case 'B':
+ /*
+ * Nothing to do here, this is pax default
+ */
+ break;
+ case 'C':
+ havechd++;
+ chdname = optarg;
+ break;
+ case 'H':
+ /*
+ * follow command line symlinks only
+ */
+ Hflag = 1;
+ break;
+ case 'I':
+ if (++nincfiles > incfiles_max) {
+ incfiles_max = nincfiles + 3;
+ incfiles = realloc(incfiles,
+ sizeof(*incfiles) * incfiles_max);
+ if (incfiles == NULL) {
+ paxwarn(0, "Unable to allocate space "
+ "for option list");
+ exit(1);
+ }
+ }
+ incfiles[nincfiles - 1].file = optarg;
+ incfiles[nincfiles - 1].dir = chdname;
+ break;
+ case 'L':
+ /*
+ * follow symlinks
+ */
+ Lflag = 1;
+ break;
+ case 'P':
+ /*
+ * do not remove leading '/' from pathnames
+ */
+ rmleadslash = 0;
+ break;
+ case 'X':
+ /*
+ * do not pass over mount points in the file system
+ */
+ Xflag = 1;
+ break;
+ case 'Z':
+ /*
+ * use compress.
+ */
+ gzip_program = COMPRESS_CMD;
+ break;
+ case '0':
+ arcname = DEV_0;
+ break;
+ case '1':
+ arcname = DEV_1;
+ break;
+ case '4':
+ arcname = DEV_4;
+ break;
+ case '5':
+ arcname = DEV_5;
+ break;
+ case '7':
+ arcname = DEV_7;
+ break;
+ case '8':
+ arcname = DEV_8;
+ break;
+ default:
+ tar_usage();
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Traditional tar behaviour (pax uses stderr unless in list mode) */
+ if (fstdin == 1 && act == ARCHIVE)
+ listf = stderr;
+ else
+ listf = stdout;
+
+ /* Traditional tar behaviour (pax wants to read file list from stdin) */
+ if ((act == ARCHIVE || act == APPND) && argc == 0 && nincfiles == 0)
+ exit(0);
+
+ /*
+ * process the args as they are interpreted by the operation mode
+ */
+ switch (act) {
+ case LIST:
+ case EXTRACT:
+ default:
+ {
+ int sawpat = 0;
+ char *file, *dir = NULL;
+
+ while (nincfiles || *argv != NULL) {
+ /*
+ * If we queued up any include files,
+ * pull them in now. Otherwise, check
+ * for -I and -C positional flags.
+ * Anything else must be a file to
+ * extract.
+ */
+ if (nincfiles) {
+ file = incfiles->file;
+ dir = incfiles->dir;
+ incfiles++;
+ nincfiles--;
+ } else if (strcmp(*argv, "-I") == 0) {
+ if (*++argv == NULL)
+ break;
+ file = *argv++;
+ dir = chdname;
+ } else
+ file = NULL;
+ if (file != NULL) {
+ FILE *fp;
+ char *str;
+
+ if (strcmp(file, "-") == 0)
+ fp = stdin;
+ else if ((fp = fopen(file, "r")) == NULL) {
+ paxwarn(1, "Unable to open file '%s' for read", file);
+ tar_usage();
+ }
+ while ((str = pax_getline(fp)) != NULL) {
+ if (pat_add(str, dir) < 0)
+ tar_usage();
+ sawpat = 1;
+ }
+ if (strcmp(file, "-") != 0)
+ fclose(fp);
+ if (getline_error) {
+ paxwarn(1, "Problem with file '%s'", file);
+ tar_usage();
+ }
+ } else if (strcmp(*argv, "-C") == 0) {
+ if (*++argv == NULL)
+ break;
+ chdname = *argv++;
+ havechd++;
+ } else if (pat_add(*argv++, chdname) < 0)
+ tar_usage();
+ else
+ sawpat = 1;
+ }
+ /*
+ * if patterns were added, we are doing chdir()
+ * on a file-by-file basis, else, just one
+ * global chdir (if any) after opening input.
+ */
+ if (sawpat > 0)
+ chdname = NULL;
+ }
+ break;
+ case ARCHIVE:
+ case APPND:
+ frmt = &(fsub[Oflag ? F_OTAR : F_TAR]);
+
+ if (Oflag == 2 && opt_add("write_opt=nodir") < 0)
+ tar_usage();
+
+ if (chdname != NULL) { /* initial chdir() */
+ if (ftree_add(chdname, 1) < 0)
+ tar_usage();
+ }
+
+ while (nincfiles || *argv != NULL) {
+ char *file, *dir = NULL;
+
+ /*
+ * If we queued up any include files, pull them in
+ * now. Otherwise, check for -I and -C positional
+ * flags. Anything else must be a file to include
+ * in the archive.
+ */
+ if (nincfiles) {
+ file = incfiles->file;
+ dir = incfiles->dir;
+ incfiles++;
+ nincfiles--;
+ } else if (strcmp(*argv, "-I") == 0) {
+ if (*++argv == NULL)
+ break;
+ file = *argv++;
+ dir = NULL;
+ } else
+ file = NULL;
+ if (file != NULL) {
+ FILE *fp;
+ char *str;
+
+ /* Set directory if needed */
+ if (dir) {
+ if (ftree_add(dir, 1) < 0)
+ tar_usage();
+ }
+
+ if (strcmp(file, "-") == 0)
+ fp = stdin;
+ else if ((fp = fopen(file, "r")) == NULL) {
+ paxwarn(1, "Unable to open file '%s' for read", file);
+ tar_usage();
+ }
+ while ((str = pax_getline(fp)) != NULL) {
+ if (ftree_add(str, 0) < 0)
+ tar_usage();
+ }
+ if (strcmp(file, "-") != 0)
+ fclose(fp);
+ if (getline_error) {
+ paxwarn(1, "Problem with file '%s'",
+ file);
+ tar_usage();
+ }
+ } else if (strcmp(*argv, "-C") == 0) {
+ if (*++argv == NULL)
+ break;
+ if (ftree_add(*argv++, 1) < 0)
+ tar_usage();
+ havechd++;
+ } else if (ftree_add(*argv++, 0) < 0)
+ tar_usage();
+ }
+ /*
+ * no read errors allowed on updates/append operation!
+ */
+ maxflt = 0;
+ break;
+ }
+ if (!fstdin && ((arcname == NULL) || (*arcname == '\0'))) {
+ arcname = getenv("TAPE");
+ if ((arcname == NULL) || (*arcname == '\0'))
+ arcname = _PATH_DEFTAPE;
+ }
+}
+
+int mkpath(char *);
+
+int
+mkpath(path)
+ char *path;
+{
+ struct stat sb;
+ char *slash;
+ int done = 0;
+
+ slash = path;
+
+ while (!done) {
+ slash += strspn(slash, "/");
+ slash += strcspn(slash, "/");
+
+ done = (*slash == '\0');
+ *slash = '\0';
+
+ if (stat(path, &sb)) {
+ if (errno != ENOENT || mkdir(path, 0777)) {
+ paxwarn(1, "%s", path);
+ return (-1);
+ }
+ } else if (!S_ISDIR(sb.st_mode)) {
+ syswarn(1, ENOTDIR, "%s", path);
+ return (-1);
+ }
+
+ if (!done)
+ *slash = '/';
+ }
+
+ return (0);
+}
+/*
+ * cpio_options()
+ * look at the user specified flags. set globals as required and check if
+ * the user specified a legal set of flags. If not, complain and exit
+ */
+
+static void
+cpio_options(int argc, char **argv)
+{
+ int c, i;
+ char *str;
+ FSUB tmp;
+ FILE *fp;
+ size_t n_fsub;
+
+ kflag = 1;
+ pids = 1;
+ pmode = 1;
+ pmtime = 0;
+ arcname = NULL;
+ dflag = 1;
+ act = -1;
+ nodirs = 1;
+ while ((c=getopt(argc,argv,"abcdfijklmoprstuvzABC:E:F:H:I:LO:SZ6")) != -1)
+ switch (c) {
+ case 'a':
+ /*
+ * preserve access time on files read
+ */
+ tflag = 1;
+ break;
+ case 'b':
+ /*
+ * swap bytes and half-words when reading data
+ */
+ break;
+ case 'c':
+ /*
+ * ASCII cpio header
+ */
+ frmt = &(fsub[F_ACPIO]);
+ break;
+ case 'd':
+ /*
+ * create directories as needed
+ */
+ nodirs = 0;
+ break;
+ case 'f':
+ /*
+ * invert meaning of pattern list
+ */
+ cflag = 1;
+ break;
+ case 'i':
+ /*
+ * restore an archive
+ */
+ act = EXTRACT;
+ break;
+ case 'j':
+ /*
+ * use bzip2. Non standard option.
+ */
+ gzip_program = BZIP2_CMD;
+ break;
+ case 'k':
+ break;
+ case 'l':
+ /*
+ * use links instead of copies when possible
+ */
+ lflag = 1;
+ break;
+ case 'm':
+ /*
+ * preserve modification time
+ */
+ pmtime = 1;
+ break;
+ case 'o':
+ /*
+ * create an archive
+ */
+ act = ARCHIVE;
+ frmt = &(fsub[F_CPIO]);
+ break;
+ case 'p':
+ /*
+ * copy-pass mode
+ */
+ act = COPY;
+ break;
+ case 'r':
+ /*
+ * interactively rename files
+ */
+ iflag = 1;
+ break;
+ case 's':
+ /*
+ * swap bytes after reading data
+ */
+ break;
+ case 't':
+ /*
+ * list contents of archive
+ */
+ act = LIST;
+ listf = stdout;
+ break;
+ case 'u':
+ /*
+ * replace newer files
+ */
+ kflag = 0;
+ break;
+ case 'v':
+ /*
+ * verbose operation mode
+ */
+ vflag = 1;
+ break;
+ case 'z':
+ /*
+ * use gzip. Non standard option.
+ */
+ gzip_program = GZIP_CMD;
+ break;
+ case 'A':
+ /*
+ * append mode
+ */
+ act = APPND;
+ break;
+ case 'B':
+ /*
+ * Use 5120 byte block size
+ */
+ wrblksz = 5120;
+ break;
+ case 'C':
+ /*
+ * set block size in bytes
+ */
+ wrblksz = atoi(optarg);
+ break;
+ case 'E':
+ /*
+ * file with patterns to extract or list
+ */
+ if ((fp = fopen(optarg, "r")) == NULL) {
+ paxwarn(1, "Unable to open file '%s' for read", optarg);
+ cpio_usage();
+ }
+ while ((str = pax_getline(fp)) != NULL) {
+ pat_add(str, NULL);
+ }
+ fclose(fp);
+ if (getline_error) {
+ paxwarn(1, "Problem with file '%s'", optarg);
+ cpio_usage();
+ }
+ break;
+ case 'F':
+ case 'I':
+ case 'O':
+ /*
+ * filename where the archive is stored
+ */
+ if ((optarg[0] == '-') && (optarg[1]== '\0')) {
+ /*
+ * treat a - as stdin
+ */
+ arcname = NULL;
+ break;
+ }
+ arcname = optarg;
+ break;
+ case 'H':
+ /*
+ * specify an archive format on write
+ */
+ tmp.name = optarg;
+ n_fsub = sizeof(fsub)/sizeof(FSUB);
+ if ((frmt = (FSUB *)bsearch((void *)&tmp, (void *)fsub,
+ n_fsub, sizeof(FSUB), c_frmt)) != NULL)
+ break;
+ paxwarn(1, "Unknown -H format: %s", optarg);
+ (void)fputs("cpio: Known -H formats are:", stderr);
+ for (i = 0; i < (sizeof(fsub)/sizeof(FSUB)); ++i)
+ (void)fprintf(stderr, " %s", fsub[i].name);
+ (void)fputs("\n\n", stderr);
+ cpio_usage();
+ break;
+ case 'L':
+ /*
+ * follow symbolic links
+ */
+ Lflag = 1;
+ break;
+ case 'S':
+ /*
+ * swap halfwords after reading data
+ */
+ break;
+ case 'Z':
+ /*
+ * use compress. Non standard option.
+ */
+ gzip_program = COMPRESS_CMD;
+ break;
+ case '6':
+ /*
+ * process Version 6 cpio format
+ */
+ frmt = &(fsub[F_OCPIO]);
+ break;
+ case '?':
+ default:
+ cpio_usage();
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * process the args as they are interpreted by the operation mode
+ */
+ switch (act) {
+ case LIST:
+ case EXTRACT:
+ while (*argv != NULL)
+ if (pat_add(*argv++, NULL) < 0)
+ cpio_usage();
+ break;
+ case COPY:
+ if (*argv == NULL) {
+ paxwarn(0, "Destination directory was not supplied");
+ cpio_usage();
+ }
+ dirptr = *argv;
+ if (mkpath(dirptr) < 0)
+ cpio_usage();
+ --argc;
+ ++argv;
+ /* FALL THROUGH */
+ case ARCHIVE:
+ case APPND:
+ if (*argv != NULL)
+ cpio_usage();
+ /*
+ * no read errors allowed on updates/append operation!
+ */
+ maxflt = 0;
+ while ((str = pax_getline(stdin)) != NULL) {
+ ftree_add(str, 0);
+ }
+ if (getline_error) {
+ paxwarn(1, "Problem while reading stdin");
+ cpio_usage();
+ }
+ break;
+ default:
+ cpio_usage();
+ break;
+ }
+}
+
+/*
+ * printflg()
+ * print out those invalid flag sets found to the user
+ */
+
+static void
+printflg(unsigned int flg)
+{
+ int nxt;
+ int pos = 0;
+
+ (void)fprintf(stderr,"%s: Invalid combination of options:", argv0);
+ while ((nxt = ffs(flg)) != 0) {
+ flg = flg >> nxt;
+ pos += nxt;
+ (void)fprintf(stderr, " -%c", flgch[pos-1]);
+ }
+ (void)putc('\n', stderr);
+}
+
+/*
+ * c_frmt()
+ * comparison routine used by bsearch to find the format specified
+ * by the user
+ */
+
+static int
+c_frmt(const void *a, const void *b)
+{
+ return(strcmp(((const FSUB *)a)->name, ((const FSUB *)b)->name));
+}
+
+/*
+ * opt_next()
+ * called by format specific options routines to get each format specific
+ * flag and value specified with -o
+ * Return:
+ * pointer to next OPLIST entry or NULL (end of list).
+ */
+
+OPLIST *
+opt_next(void)
+{
+ OPLIST *opt;
+
+ if ((opt = ophead) != NULL)
+ ophead = ophead->fow;
+ return(opt);
+}
+
+/*
+ * bad_opt()
+ * generic routine used to complain about a format specific options
+ * when the format does not support options.
+ */
+
+int
+bad_opt(void)
+{
+ OPLIST *opt;
+
+ if (ophead == NULL)
+ return(0);
+ /*
+ * print all we were given
+ */
+ paxwarn(1,"These format options are not supported");
+ while ((opt = opt_next()) != NULL) {
+ if (opt->separator == SEP_EQ) {
+ (void)fprintf(stderr, "\t%s = %s\n", opt->name, opt->value);
+ } else if (opt->separator == SEP_COLONEQ ) {
+ (void)fprintf(stderr, "\t%s := %s\n", opt->name, opt->value);
+ } else { /* SEP_NONE */
+ (void)fprintf(stderr, "\t%s\n", opt->name);
+ }
+ }
+ pax_usage();
+ return(0);
+}
+
+/*
+ * opt_add()
+ * breaks the value supplied to -o into an option name and value. Options
+ * are given to -o in the form -o name-value,name=value
+ * multiple -o may be specified.
+ * Return:
+ * 0 if format in name=value format, -1 if -o is passed junk.
+ */
+
+int
+opt_add(const char *str)
+{
+ OPLIST *opt;
+ char *frpt;
+ char *pt;
+ char *dstr;
+ char *endpt;
+
+ if ((str == NULL) || (*str == '\0')) {
+ paxwarn(0, "Invalid option name");
+ return(-1);
+ }
+ if ((dstr = strdup(str)) == NULL) {
+ paxwarn(0, "Unable to allocate space for option list");
+ return(-1);
+ }
+ frpt = dstr;
+
+ /*
+ * break into name and values pieces and stuff each one into a
+ * OPLIST structure. When we know the format, the format specific
+ * option function will go through this list
+ */
+ while ((frpt != NULL) && (*frpt != '\0')) {
+ if ((endpt = strchr(frpt, ',')) != NULL)
+ *endpt = '\0';
+ if ((pt = strchr(frpt, '=')) == NULL) {
+ paxwarn(0, "Invalid options format");
+ free(dstr);
+ return(-1);
+ }
+ if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
+ paxwarn(0, "Unable to allocate space for option list");
+ free(dstr);
+ return(-1);
+ }
+ *pt++ = '\0';
+ opt->name = frpt;
+ opt->value = pt;
+ opt->separator = SEP_EQ;
+ opt->fow = NULL;
+ if (endpt != NULL)
+ frpt = endpt + 1;
+ else
+ frpt = NULL;
+ if (ophead == NULL) {
+ optail = ophead = opt;
+ continue;
+ }
+ optail->fow = opt;
+ optail = opt;
+ }
+ return(0);
+}
+
+/*
+ * pax_format_opt_add()
+ * breaks the value supplied to -o into a option name and value. options
+ * are given to -o in the form -o name-value,name=value
+ * multiple -o may be specified.
+ * Return:
+ * 0 if format in name=value format, -1 if -o is passed junk
+ */
+
+int
+pax_format_opt_add(register char *str)
+{
+ register OPLIST *opt;
+ register char *frpt;
+ register char *pt;
+ register char *endpt;
+ register int separator;
+
+ if ((str == NULL) || (*str == '\0')) {
+ paxwarn(0, "Invalid option name");
+ return(-1);
+ }
+ if ((str = strdup(str)) == NULL) {
+ paxwarn(0, "Unable to allocate space for option list");
+ return(-1);
+ }
+ frpt = str;
+
+ /*
+ * break into name and values pieces and stuff each one into a
+ * OPLIST structure. When we know the format, the format specific
+ * option function will go through this list
+ */
+ while ((frpt != NULL) && (*frpt != '\0')) {
+ if ((endpt = strchr(frpt, ',')) != NULL)
+ *endpt = '\0';
+ if ((pt = strstr(frpt, ":=")) != NULL) {
+ *pt++ = '\0';
+ pt++; /* beyond the := */
+ separator = SEP_COLONEQ;
+ } else if ((pt = strchr(frpt, '=')) != NULL) {
+ *pt++ = '\0';
+ separator = SEP_EQ;
+ } else {
+ /* keyword with no value */
+ separator = SEP_NONE;
+ }
+ if ((opt = (OPLIST *)malloc(sizeof(OPLIST))) == NULL) {
+ paxwarn(0, "Unable to allocate space for option list");
+ free(str);
+ return(-1);
+ }
+ opt->name = frpt;
+ opt->value = pt;
+ opt->separator = separator;
+ opt->fow = NULL;
+ if (endpt != NULL)
+ frpt = endpt + 1;
+ else
+ frpt = NULL;
+ if (ophead == NULL) {
+ optail = ophead = opt;
+ continue;
+ }
+ optail->fow = opt;
+ optail = opt;
+ }
+ return(0);
+}
+
+/*
+ * str_offt()
+ * Convert an expression of the following forms to an off_t > 0.
+ * 1) A positive decimal number.
+ * 2) A positive decimal number followed by a b (mult by 512).
+ * 3) A positive decimal number followed by a k (mult by 1024).
+ * 4) A positive decimal number followed by a m (mult by 512).
+ * 5) A positive decimal number followed by a w (mult by sizeof int)
+ * 6) Two or more positive decimal numbers (with/without k,b or w).
+ * separated by x (also * for backwards compatibility), specifying
+ * the product of the indicated values.
+ * Return:
+ * 0 for an error, a positive value o.w.
+ */
+
+static off_t
+str_offt(char *val)
+{
+ char *expr;
+ off_t num, t;
+
+# ifdef LONG_OFF_T
+ num = strtol(val, &expr, 0);
+ if ((num == LONG_MAX) || (num <= 0) || (expr == val))
+# else
+ num = strtoq(val, &expr, 0);
+ if ((num == QUAD_MAX) || (num <= 0) || (expr == val))
+# endif
+ return(0);
+
+ switch (*expr) {
+ case 'b':
+ t = num;
+ num *= 512;
+ if (t > num)
+ return(0);
+ ++expr;
+ break;
+ case 'k':
+ t = num;
+ num *= 1024;
+ if (t > num)
+ return(0);
+ ++expr;
+ break;
+ case 'm':
+ t = num;
+ num *= 1048576;
+ if (t > num)
+ return(0);
+ ++expr;
+ break;
+ case 'w':
+ t = num;
+ num *= sizeof(int);
+ if (t > num)
+ return(0);
+ ++expr;
+ break;
+ }
+
+ switch (*expr) {
+ case '\0':
+ break;
+ case '*':
+ case 'x':
+ t = num;
+ num *= str_offt(expr + 1);
+ if (t > num)
+ return(0);
+ break;
+ default:
+ return(0);
+ }
+ return(num);
+}
+
+char *
+pax_getline(FILE *f)
+{
+ char *name, *temp;
+ size_t len;
+
+ name = fgetln(f, &len);
+ if (!name) {
+ getline_error = ferror(f) ? GETLINE_FILE_CORRUPT : 0;
+ return(0);
+ }
+ if (name[len-1] != '\n')
+ len++;
+ temp = malloc(len);
+ if (!temp) {
+ getline_error = GETLINE_OUT_OF_MEM;
+ return(0);
+ }
+ memcpy(temp, name, len-1);
+ temp[len-1] = 0;
+ return(temp);
+}
+
+/*
+ * no_op()
+ * for those option functions where the archive format has nothing to do.
+ * Return:
+ * 0
+ */
+
+static int
+no_op(void)
+{
+ return(0);
+}
+
+/*
+ * pax_usage()
+ * print the usage summary to the user
+ */
+
+void
+pax_usage(void)
+{
+ (void)fputs(
+ "usage: pax [-0cdjnOvz] [-E limit] [-f archive] [-G group] [-s replstr]\n"
+ " [-T range] [-U user] [--insecure] [pattern ...]\n"
+ " pax -r [-0cDdijknOuvYZz] [-E limit] [-f archive] [-G group] [-o options]\n"
+ " [-p string] [-s replstr] [-T range] [-U user] [--insecure] [pattern ...]\n"
+ " pax -w [-0adHijLOPtuvXz] [-B bytes] [-b blocksize] [-f archive]\n"
+ " [-G group] [-o options] [-s replstr] [-T range] [-U user]\n"
+ " [-x format] [--insecure] [file ...]\n"
+ " pax -rw [-0DdHikLlnOPtuvXYZ] [-G group] [-p string] [-s replstr]\n"
+ " [-T range] [-U user] [--insecure] [file ...] directory\n",
+ stderr);
+ exit(1);
+}
+
+/*
+ * tar_usage()
+ * print the usage summary to the user
+ */
+
+void
+tar_usage(void)
+{
+ (void)fputs(
+ "usage: tar {crtux}[014578befHhjLmOoPpqsvwXZz]\n"
+ " [blocking-factor | archive | replstr] [-C directory] [-I file]\n"
+ " [file ...]\n"
+ " tar {-crtux} [-014578eHhjLmOoPpqvwXZz] [-b blocking-factor]\n"
+ " [-C directory] [-f archive] [-I file] [-s replstr] [file ...]\n",
+ stderr);
+ exit(1);
+}
+
+/*
+ * cpio_usage()
+ * print the usage summary to the user
+ */
+
+void
+cpio_usage(void)
+{
+ (void)fputs(
+ "usage: cpio -o [-AaBcjLvZz] [-C bytes] [-F archive] [-H format]\n"
+ " [-O archive] < name-list [> archive]\n"
+ " cpio -i [-6BbcdfjmrSstuvZz] [-C bytes] [-E file] [-F archive] [-H format]\n"
+ " [-I archive] [pattern ...] [< archive]\n"
+ " cpio -p [-adLlmuv] destination-directory < name-list\n",
+ stderr);
+ exit(1);
+}
diff --git a/file_cmds/pax/options.h b/file_cmds/pax/options.h
new file mode 100644
index 0000000..89eeaa5
--- /dev/null
+++ b/file_cmds/pax/options.h
@@ -0,0 +1,118 @@
+/* $OpenBSD: options.h,v 1.4 2003/06/13 17:51:14 millert Exp $ */
+/* $NetBSD: options.h,v 1.3 1995/03/21 09:07:32 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)options.h 8.2 (Berkeley) 4/18/94
+ */
+
+#ifndef _OPTIONS_H_
+#define _OPTIONS_H_
+
+/*
+ * argv[0] names. Used for tar and cpio emulation
+ */
+
+#define NM_TAR "tar"
+#define NM_CPIO "cpio"
+#define NM_PAX "pax"
+
+/*
+ * Constants used to specify the legal sets of flags in pax. For each major
+ * operation mode of pax, a set of illegal flags is defined. If any one of
+ * those illegal flags are found set, we scream and exit
+ */
+#define NONE "none"
+
+/*
+ * flags (one for each option).
+ */
+#define AF 0x00000001
+#define BF 0x00000002
+#define CF 0x00000004
+#define DF 0x00000008
+#define FF 0x00000010
+#define IF 0x00000020
+#define KF 0x00000040
+#define LF 0x00000080
+#define NF 0x00000100
+#define OF 0x00000200
+#define PF 0x00000400
+#define RF 0x00000800
+#define SF 0x00001000
+#define TF 0x00002000
+#define UF 0x00004000
+#define VF 0x00008000
+#define WF 0x00010000
+#define XF 0x00020000
+#define CBF 0x00040000 /* nonstandard extension */
+#define CDF 0x00080000 /* nonstandard extension */
+#define CEF 0x00100000 /* nonstandard extension */
+#define CGF 0x00200000 /* nonstandard extension */
+#define CHF 0x00400000 /* nonstandard extension */
+#define CLF 0x00800000 /* nonstandard extension */
+#define CPF 0x01000000 /* nonstandard extension */
+#define CTF 0x02000000 /* nonstandard extension */
+#define CUF 0x04000000 /* nonstandard extension */
+#define CXF 0x08000000
+#define CYF 0x10000000 /* nonstandard extension */
+#define CZF 0x20000000 /* nonstandard extension */
+#define C0F 0x40000000 /* nonstandard extension */
+
+/*
+ * ascii string indexed by bit position above (alter the above and you must
+ * alter this string) used to tell the user what flags caused us to complain
+ */
+#define FLGCH "abcdfiklnoprstuvwxBDEGHLPTUXYZ0"
+
+/*
+ * legal pax operation bit patterns
+ */
+
+#define ISLIST(x) (((x) & (RF|WF)) == 0)
+#define ISEXTRACT(x) (((x) & (RF|WF)) == RF)
+#define ISARCHIVE(x) (((x) & (AF|RF|WF)) == WF)
+#define ISAPPND(x) (((x) & (AF|RF|WF)) == (AF|WF))
+#define ISCOPY(x) (((x) & (RF|WF)) == (RF|WF))
+#define ISWRITE(x) (((x) & (RF|WF)) == WF)
+
+/*
+ * Illegal option flag subsets based on pax operation
+ */
+
+#define BDEXTR (AF|BF|LF|TF|WF|XF|CBF|CHF|CLF|CPF|CXF)
+#define BDARCH (CF|KF|LF|NF|PF|RF|CDF|CEF|CYF|CZF)
+#define BDCOPY (AF|BF|FF|CBF|CEF)
+#define BDLIST (AF|BF|IF|KF|LF|PF|RF|TF|UF|WF|XF|CBF|CDF|CHF|CLF|CPF|CXF|CYF|CZF)
+
+#endif /* _OPTIONS_H_ */
diff --git a/file_cmds/pax/pat_rep.c b/file_cmds/pax/pat_rep.c
new file mode 100644
index 0000000..fa778b9
--- /dev/null
+++ b/file_cmds/pax/pat_rep.c
@@ -0,0 +1,1211 @@
+/* $OpenBSD: pat_rep.c,v 1.30 2005/08/05 08:30:10 djm Exp $ */
+/* $NetBSD: pat_rep.c,v 1.4 1995/03/21 09:07:33 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)pat_rep.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: pat_rep.c,v 1.30 2005/08/05 08:30:10 djm Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <regex.h>
+#include "pax.h"
+#include "pat_rep.h"
+#include "extern.h"
+
+/*
+ * routines to handle pattern matching, name modification (regular expression
+ * substitution and interactive renames), and destination name modification for
+ * copy (-rw). Both file name and link names are adjusted as required in these
+ * routines.
+ */
+
+#define MAXSUBEXP 10 /* max subexpressions, DO NOT CHANGE */
+static PATTERN *pathead = NULL; /* file pattern match list head */
+static PATTERN *pattail = NULL; /* file pattern match list tail */
+static REPLACE *rephead = NULL; /* replacement string list head */
+static REPLACE *reptail = NULL; /* replacement string list tail */
+
+static int rep_name(char *, size_t, int *, int);
+int tty_rename(ARCHD *);
+static int fix_path(char *, int *, char *, int);
+static int fn_match(char *, char *, char **);
+#ifdef _HAVE_REGCOMP_
+static char* extract_equiv_pat(char *, char **);
+static int regex_match(char *, char *, char **);
+#endif
+static char * range_match(char *, int);
+static int resub(regex_t *, regmatch_t *, char *, char *, char *, char *);
+
+/*
+ * rep_add()
+ * parses the -s replacement string; compiles the regular expression
+ * and stores the compiled value and it's replacement string together in
+ * replacement string list. Input to this function is of the form:
+ * /old/new/pg
+ * The first char in the string specifies the delimiter used by this
+ * replacement string. "Old" is a regular expression in "ed" format which
+ * is compiled by regcomp() and is applied to filenames. "new" is the
+ * substitution string; p and g are options flags for printing and global
+ * replacement (over the single filename)
+ * Return:
+ * 0 if a proper replacement string and regular expression was added to
+ * the list of replacement patterns; -1 otherwise.
+ */
+
+int
+rep_add(char *str)
+{
+ char *pt1;
+ char *pt2;
+ REPLACE *rep;
+ int res;
+ char rebuf[BUFSIZ];
+
+ /*
+ * throw out the bad parameters
+ */
+ if ((str == NULL) || (*str == '\0')) {
+ paxwarn(1, "Empty replacement string");
+ return(-1);
+ }
+
+ /*
+ * first character in the string specifies what the delimiter is for
+ * this expression
+ */
+ for (pt1 = str+1; *pt1; pt1++) {
+ if (*pt1 == '\\') {
+ pt1++;
+ continue;
+ }
+ if (*pt1 == *str)
+ break;
+ }
+ if (*pt1 == '\0') {
+ paxwarn(1, "Invalid replacement string %s", str);
+ return(-1);
+ }
+
+ /*
+ * allocate space for the node that handles this replacement pattern
+ * and split out the regular expression and try to compile it
+ */
+ if ((rep = (REPLACE *)malloc(sizeof(REPLACE))) == NULL) {
+ paxwarn(1, "Unable to allocate memory for replacement string");
+ return(-1);
+ }
+
+ *pt1 = '\0';
+ if ((res = regcomp(&(rep->rcmp), str+1, 0)) != 0) {
+ regerror(res, &(rep->rcmp), rebuf, sizeof(rebuf));
+ paxwarn(1, "%s while compiling regular expression %s", rebuf, str);
+ (void)free((char *)rep);
+ return(-1);
+ }
+
+ /*
+ * put the delimiter back in case we need an error message and
+ * locate the delimiter at the end of the replacement string
+ * we then point the node at the new substitution string
+ */
+ *pt1++ = *str;
+ for (pt2 = pt1; *pt2; pt2++) {
+ if (*pt2 == '\\') {
+ pt2++;
+ continue;
+ }
+ if (*pt2 == *str)
+ break;
+ }
+ if (*pt2 == '\0') {
+ regfree(&(rep->rcmp));
+ (void)free((char *)rep);
+ paxwarn(1, "Invalid replacement string %s", str);
+ return(-1);
+ }
+
+ *pt2 = '\0';
+ rep->nstr = pt1;
+ pt1 = pt2++;
+ rep->flgs = 0;
+
+ /*
+ * set the options if any
+ */
+ while (*pt2 != '\0') {
+ switch (*pt2) {
+ case 'g':
+ case 'G':
+ rep->flgs |= GLOB;
+ break;
+ case 'p':
+ case 'P':
+ rep->flgs |= PRNT;
+ break;
+ default:
+ regfree(&(rep->rcmp));
+ (void)free((char *)rep);
+ *pt1 = *str;
+ paxwarn(1, "Invalid replacement string option %s", str);
+ return(-1);
+ }
+ ++pt2;
+ }
+
+ /*
+ * all done, link it in at the end
+ */
+ rep->fow = NULL;
+ if (rephead == NULL) {
+ reptail = rephead = rep;
+ return(0);
+ }
+ reptail->fow = rep;
+ reptail = rep;
+ return(0);
+}
+
+/*
+ * pat_add()
+ * add a pattern match to the pattern match list. Pattern matches are used
+ * to select which archive members are extracted. (They appear as
+ * arguments to pax in the list and read modes). If no patterns are
+ * supplied to pax, all members in the archive will be selected (and the
+ * pattern match list is empty).
+ * Return:
+ * 0 if the pattern was added to the list, -1 otherwise
+ */
+
+int
+pat_add(char *str, char *chdname)
+{
+ PATTERN *pt;
+
+ /*
+ * throw out the junk
+ */
+ if ((str == NULL) || (*str == '\0')) {
+ paxwarn(1, "Empty pattern string");
+ return(-1);
+ }
+
+ /*
+ * allocate space for the pattern and store the pattern. the pattern is
+ * part of argv so do not bother to copy it, just point at it. Add the
+ * node to the end of the pattern list
+ */
+ if ((pt = (PATTERN *)malloc(sizeof(PATTERN))) == NULL) {
+ paxwarn(1, "Unable to allocate memory for pattern string");
+ return(-1);
+ }
+
+ pt->pstr = str;
+ pt->pend = NULL;
+ pt->plen = strlen(str);
+ pt->fow = NULL;
+ pt->flgs = 0;
+ pt->chdname = chdname;
+
+ if (pathead == NULL) {
+ pattail = pathead = pt;
+ return(0);
+ }
+ pattail->fow = pt;
+ pattail = pt;
+ return(0);
+}
+
+/*
+ * pat_chk()
+ * complain if any the user supplied pattern did not result in a match to
+ * a selected archive member.
+ */
+
+void
+pat_chk(void)
+{
+ PATTERN *pt;
+ int wban = 0;
+
+ /*
+ * walk down the list checking the flags to make sure MTCH was set,
+ * if not complain
+ */
+ for (pt = pathead; pt != NULL; pt = pt->fow) {
+ if (pt->flgs & MTCH)
+ continue;
+ if (!wban) {
+ paxwarn(1, "WARNING! These patterns were not matched:");
+ ++wban;
+ }
+ (void)fprintf(stderr, "%s\n", pt->pstr);
+ }
+}
+
+/*
+ * pat_sel()
+ * the archive member which matches a pattern was selected. Mark the
+ * pattern as having selected an archive member. arcn->pat points at the
+ * pattern that was matched. arcn->pat is set in pat_match()
+ *
+ * NOTE: When the -c option is used, we are called when there was no match
+ * by pat_match() (that means we did match before the inverted sense of
+ * the logic). Now this seems really strange at first, but with -c we
+ * need to keep track of those patterns that cause an archive member to NOT
+ * be selected (it found an archive member with a specified pattern)
+ * Return:
+ * 0 if the pattern pointed at by arcn->pat was tagged as creating a
+ * match, -1 otherwise.
+ */
+
+int
+pat_sel(ARCHD *arcn)
+{
+ PATTERN *pt;
+ PATTERN **ppt;
+ int len;
+
+ /*
+ * if no patterns just return
+ */
+ if ((pathead == NULL) || ((pt = arcn->pat) == NULL))
+ return(0);
+
+ /*
+ * when we are NOT limited to a single match per pattern mark the
+ * pattern and return
+ */
+ if (!nflag) {
+ pt->flgs |= MTCH;
+ return(0);
+ }
+
+ /*
+ * we reach this point only when we allow a single selected match per
+ * pattern, if the pattern matches a directory and we do not have -d
+ * (dflag) we are done with this pattern. We may also be handed a file
+ * in the subtree of a directory. in that case when we are operating
+ * with -d, this pattern was already selected and we are done
+ */
+ if (pt->flgs & DIR_MTCH)
+ return(0);
+
+ if (!dflag && ((pt->pend != NULL) || (arcn->type == PAX_DIR))) {
+ /*
+ * ok we matched a directory and we are allowing
+ * subtree matches but because of the -n only its children will
+ * match. This is tagged as a DIR_MTCH type.
+ * WATCH IT, the code assumes that pt->pend points
+ * into arcn->name and arcn->name has not been modified.
+ * If not we will have a big mess. Yup this is another kludge
+ */
+
+ /*
+ * if this was a prefix match, remove trailing part of path
+ * so we can copy it. Future matches will be exact prefix match
+ */
+ if (pt->pend != NULL)
+ *pt->pend = '\0';
+
+ if ((pt->pstr = strdup(arcn->name)) == NULL) {
+ paxwarn(1, "Pattern select out of memory");
+ if (pt->pend != NULL)
+ *pt->pend = '/';
+ pt->pend = NULL;
+ return(-1);
+ }
+
+ /*
+ * put the trailing / back in the source string
+ */
+ if (pt->pend != NULL) {
+ *pt->pend = '/';
+ pt->pend = NULL;
+ }
+ pt->plen = strlen(pt->pstr);
+
+ /*
+ * strip off any trailing /, this should really never happen
+ */
+ len = pt->plen - 1;
+ if (*(pt->pstr + len) == '/') {
+ *(pt->pstr + len) = '\0';
+ pt->plen = len;
+ }
+ pt->flgs = DIR_MTCH | MTCH;
+ arcn->pat = pt;
+ return(0);
+ }
+
+ /*
+ * we are then done with this pattern, so we delete it from the list
+ * because it can never be used for another match.
+ * Seems kind of strange to do for a -c, but the pax spec is really
+ * vague on the interaction of -c, -n and -d. We assume that when -c
+ * and the pattern rejects a member (i.e. it matched it) it is done.
+ * In effect we place the order of the flags as having -c last.
+ */
+ pt = pathead;
+ ppt = &pathead;
+ while ((pt != NULL) && (pt != arcn->pat)) {
+ ppt = &(pt->fow);
+ pt = pt->fow;
+ }
+
+ if (pt == NULL) {
+ /*
+ * should never happen....
+ */
+ paxwarn(1, "Pattern list inconsistent");
+ return(-1);
+ }
+ *ppt = pt->fow;
+ (void)free((char *)pt);
+ arcn->pat = NULL;
+ return(0);
+}
+
+/*
+ * pat_match()
+ * see if this archive member matches any supplied pattern, if a match
+ * is found, arcn->pat is set to point at the potential pattern. Later if
+ * this archive member is "selected" we process and mark the pattern as
+ * one which matched a selected archive member (see pat_sel())
+ * Return:
+ * 0 if this archive member should be processed, 1 if it should be
+ * skipped and -1 if we are done with all patterns (and pax should quit
+ * looking for more members)
+ */
+
+int
+pat_match(ARCHD *arcn)
+{
+ PATTERN *pt;
+
+ arcn->pat = NULL;
+
+ /*
+ * if there are no more patterns and we have -n (and not -c) we are
+ * done. otherwise with no patterns to match, matches all
+ */
+ if (pathead == NULL) {
+ if (nflag && !cflag)
+ return(-1);
+ return(0);
+ }
+
+ /*
+ * have to search down the list one at a time looking for a match.
+ */
+ pt = pathead;
+ while (pt != NULL) {
+ /*
+ * check for a file name match unless we have DIR_MTCH set in
+ * this pattern then we want a prefix match
+ */
+ if (pt->flgs & DIR_MTCH) {
+ /*
+ * this pattern was matched before to a directory
+ * as we must have -n set for this (but not -d). We can
+ * only match CHILDREN of that directory so we must use
+ * an exact prefix match (no wildcards).
+ */
+ if ((arcn->name[pt->plen] == '/') &&
+ (strncmp(pt->pstr, arcn->name, pt->plen) == 0))
+ break;
+ } else if (fn_match(pt->pstr, arcn->name, &pt->pend) == 0)
+ break;
+ pt = pt->fow;
+ }
+
+ /*
+ * return the result, remember that cflag (-c) inverts the sense of a
+ * match
+ */
+ if (pt == NULL)
+ return(cflag ? 0 : 1);
+
+ /*
+ * we had a match, now when we invert the sense (-c) we reject this
+ * member. However we have to tag the pattern a being successful, (in a
+ * match, not in selecting an archive member) so we call pat_sel() here.
+ */
+ arcn->pat = pt;
+ if (!cflag)
+ return(0);
+
+ if (pat_sel(arcn) < 0)
+ return(-1);
+ arcn->pat = NULL;
+ return(1);
+}
+
+/*
+ * fn_match()
+ * Return:
+ * 0 if this archive member should be processed, 1 if it should be
+ * skipped and -1 if we are done with all patterns (and pax should quit
+ * looking for more members)
+ * Note: *pend may be changed to show where the prefix ends.
+ */
+
+static int
+fn_match(char *pattern, char *string, char **pend)
+{
+ char c;
+ char test;
+#ifdef _HAVE_REGCOMP_
+ char *equiv_pat;
+ char *pat_pend = NULL;
+#endif
+
+ *pend = NULL;
+ for (;;) {
+ switch (c = *pattern++) {
+ case '\0':
+ /*
+ * Ok we found an exact match
+ */
+ if (*string == '\0')
+ return(0);
+
+ /*
+ * Check if it is a prefix match
+ */
+ if ((dflag == 1) || (*string != '/'))
+ return(-1);
+
+ /*
+ * It is a prefix match, remember where the trailing
+ * / is located
+ */
+ *pend = string;
+ return(0);
+ case '?':
+ if ((*string++) == '\0')
+ return (-1);
+ break;
+ case '*':
+ c = *pattern;
+ /*
+ * Collapse multiple *'s.
+ */
+ while (c == '*')
+ c = *++pattern;
+
+ /*
+ * Optimized hack for pattern with a * at the end
+ */
+ if (c == '\0')
+ return (0);
+
+ /*
+ * General case, use recursion.
+ */
+ while ((*string) != '\0') {
+ if (!fn_match(pattern, string, pend))
+ return (0);
+ ++string;
+ }
+ return (-1);
+ case '[':
+ /*
+ * range match
+ */
+#ifdef _HAVE_REGCOMP_
+ /*
+ * Check for equivalence class and use regex_match to
+ * handle this case. Note pattern should include the
+ * opening bracket '['
+ */
+ equiv_pat = extract_equiv_pat(pattern-1, &pat_pend);
+ if (equiv_pat) {
+ if (regex_match(equiv_pat, string, &string) == -1) {
+ free (equiv_pat);
+ return (-1);
+ }
+
+ free(equiv_pat);
+
+ /*
+ * Update the pattern string
+ */
+ pattern = pat_pend;
+ break;
+ }
+#endif
+ if (((test = *string++) == '\0') ||
+ ((pattern = range_match(pattern, test)) == NULL))
+ return (-1);
+ break;
+
+ case '\\':
+ default:
+ if (c != *string++)
+ return (-1);
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
+
+#ifdef _HAVE_REGCOMP_
+static char*
+extract_equiv_pat(char *pattern, char **pend)
+{
+ int pat_len = 2;
+ int found = 0;
+ int is_double_bracket = 0;
+ char* equiv_pat = NULL;
+
+ if (*pattern == '\0' || pattern[1] == '\0' || pattern[2] == '\0')
+ return NULL;
+
+ /*
+ * check if the pattern is
+ * "[= =]", "[[= =][= =]]", "[: :]", or "[[: :][: :]]"
+ * note that the full "pattern" string needs to be passed in
+ */
+ is_double_bracket = (*pattern == '[' && pattern[1] == '[');
+ if (!(*pattern == '[') && !is_double_bracket) {
+ return NULL;
+ }
+
+ pattern ++;
+
+ if (is_double_bracket) {
+ pattern ++;
+ pat_len ++;
+ }
+
+ if (!(*pattern == ':') && !(*pattern == '=')) {
+ return NULL;
+ }
+
+ pattern ++;
+
+
+ for(; *pattern != '\0'; pat_len++, pattern++) {
+ if (!is_double_bracket) {
+ if ((*pattern == '=' || *pattern == ':')
+ && pattern[1] == ']') {
+ found = 1;
+ pattern += 2;
+ pat_len += 2;
+ break;
+ }
+
+ } else {
+ if ((*pattern == '=' || *pattern == ':')
+ && pattern[1] == ']' && pattern[2] == ']') {
+ found = 1;
+ pattern += 3;
+ pat_len += 3;
+ break;
+ }
+
+ }
+ }
+
+ if (!found) {
+ return NULL;
+ }
+
+ equiv_pat = strndup(pattern-pat_len, pat_len);
+
+ if (equiv_pat == NULL) {
+ paxwarn(1, "Out of memory");
+ return NULL;
+ }
+
+ /*
+ * set pend to the remaining pattern to be matched
+ */
+ if (pend != NULL) {
+ *pend = pattern;
+ }
+
+ return equiv_pat;
+}
+
+static int
+regex_match(char *pattern, char *string, char **pend)
+{
+ int res;
+ regex_t preg;
+ regmatch_t pmatch;
+ char rebuf[BUFSIZ];
+
+ if ((res = regcomp(&(preg), pattern, REG_EXTENDED)) != 0) {
+ regerror(res, &(preg), rebuf, sizeof(rebuf));
+ paxwarn(1, "%s while compiling pattern %s", rebuf, pattern);
+ return(-1);
+ }
+
+ if (regexec(&(preg), string, 1, &(pmatch), 0) != 0) {
+ regfree(&(preg));
+ return(-1);
+ }
+
+ regfree(&(preg));
+
+ /*
+ * starting position of the match must be 0
+ */
+ if (pmatch.rm_so != 0) {
+ return(-1);
+ }
+
+ /*
+ * set pend to the remaining string to be matched
+ */
+ if (pend != NULL) {
+ *pend = string + pmatch.rm_eo;
+ }
+
+ return(0);
+}
+#endif
+
+static char *
+range_match(char *pattern, int test)
+{
+ char c;
+ char c2;
+ int negate;
+ int ok = 0;
+
+ if ((negate = (*pattern == '!')) != 0)
+ ++pattern;
+
+ while ((c = *pattern++) != ']') {
+ /*
+ * Illegal pattern
+ */
+ if (c == '\0')
+ return (NULL);
+
+ if ((*pattern == '-') && ((c2 = pattern[1]) != '\0') &&
+ (c2 != ']')) {
+ if ((c <= test) && (test <= c2))
+ ok = 1;
+ pattern += 2;
+ } else if (c == test)
+ ok = 1;
+ }
+ return (ok == negate ? NULL : pattern);
+}
+
+/*
+ * mod_name()
+ * modify a selected file name. first attempt to apply replacement string
+ * expressions, then apply interactive file rename. We apply replacement
+ * string expressions to both filenames and file links (if we didn't the
+ * links would point to the wrong place, and we could never be able to
+ * move an archive that has a file link in it). When we rename files
+ * interactively, we store that mapping (old name to user input name) so
+ * if we spot any file links to the old file name in the future, we will
+ * know exactly how to fix the file link.
+ * Return:
+ * 0 continue to process file, 1 skip this file, -1 pax is finished
+ */
+
+int
+mod_name(ARCHD *arcn)
+{
+ int res = 0;
+
+ /*
+ * Strip off leading '/' if appropriate.
+ * Currently, this option is only set for the tar format.
+ */
+ while (rmleadslash && arcn->name[0] == '/') {
+ if (arcn->name[1] == '\0') {
+ arcn->name[0] = '.';
+ } else {
+ (void)memmove(arcn->name, &arcn->name[1],
+ strlen(arcn->name));
+ arcn->nlen--;
+ }
+ if (rmleadslash < 2) {
+ rmleadslash = 2;
+ paxwarn(0, "Removing leading / from absolute path names in the archive");
+ }
+ }
+ while (rmleadslash && arcn->ln_name[0] == '/' &&
+ (arcn->type == PAX_HLK || arcn->type == PAX_HRG)) {
+ if (arcn->ln_name[1] == '\0') {
+ arcn->ln_name[0] = '.';
+ } else {
+ (void)memmove(arcn->ln_name, &arcn->ln_name[1],
+ strlen(arcn->ln_name));
+ arcn->ln_nlen--;
+ }
+ if (rmleadslash < 2) {
+ rmleadslash = 2;
+ paxwarn(0, "Removing leading / from absolute path names in the archive");
+ }
+ }
+
+ /*
+ * IMPORTANT: We have a problem. what do we do with symlinks?
+ * Modifying a hard link name makes sense, as we know the file it
+ * points at should have been seen already in the archive (and if it
+ * wasn't seen because of a read error or a bad archive, we lose
+ * anyway). But there are no such requirements for symlinks. On one
+ * hand the symlink that refers to a file in the archive will have to
+ * be modified to so it will still work at its new location in the
+ * file system. On the other hand a symlink that points elsewhere (and
+ * should continue to do so) should not be modified. There is clearly
+ * no perfect solution here. So we handle them like hardlinks. Clearly
+ * a replacement made by the interactive rename mapping is very likely
+ * to be correct since it applies to a single file and is an exact
+ * match. The regular expression replacements are a little harder to
+ * justify though. We claim that the symlink name is only likely
+ * to be replaced when it points within the file tree being moved and
+ * in that case it should be modified. what we really need to do is to
+ * call an oracle here. :)
+ */
+ if (rephead != NULL) {
+ /*
+ * we have replacement strings, modify the name and the link
+ * name if any.
+ */
+ if ((res = rep_name(arcn->name, sizeof(arcn->name), &(arcn->nlen), 1)) != 0)
+ return(res);
+
+ if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
+ (arcn->type == PAX_HRG)) &&
+ ((res = rep_name(arcn->ln_name, sizeof(arcn->ln_name), &(arcn->ln_nlen), 0)) != 0))
+ return(res);
+ }
+
+ if (iflag) {
+ /*
+ * perform interactive file rename, then map the link if any
+ */
+ if ((res = tty_rename(arcn)) != 0)
+ return(res);
+ if ((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
+ (arcn->type == PAX_HRG))
+ sub_name(arcn->ln_name, &(arcn->ln_nlen), sizeof(arcn->ln_name));
+ }
+ return(res);
+}
+
+/*
+ * tty_rename()
+ * Prompt the user for a replacement file name. A "." keeps the old name,
+ * a empty line skips the file, and an EOF on reading the tty, will cause
+ * pax to stop processing and exit. Otherwise the file name input, replaces
+ * the old one.
+ * Return:
+ * 0 process this file, 1 skip this file, -1 we need to exit pax
+ */
+
+int
+tty_rename(ARCHD *arcn)
+{
+ char tmpname[PAXPATHLEN+2];
+ int res;
+
+ /*
+ * prompt user for the replacement name for a file, keep trying until
+ * we get some reasonable input. Archives may have more than one file
+ * on them with the same name (from updates etc). We print verbose info
+ * on the file so the user knows what is up.
+ */
+ tty_prnt("\nATTENTION: %s interactive file rename operation.\n", argv0);
+
+ for (;;) {
+ ls_tty(arcn);
+ tty_prnt("Input new name, or a \".\" to keep the old name, ");
+ tty_prnt("or a \"return\" to skip this file.\n");
+ tty_prnt("Input > ");
+ if (tty_read(tmpname, sizeof(tmpname)) < 0)
+ return(-1);
+ if (strcmp(tmpname, "..") == 0) {
+ tty_prnt("Try again, illegal file name: ..\n");
+ continue;
+ }
+ if (strlen(tmpname) > PAXPATHLEN) {
+ tty_prnt("Try again, file name too long\n");
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * empty file name, skips this file. a "." leaves it alone
+ */
+ if (tmpname[0] == '\0') {
+ tty_prnt("Skipping file.\n");
+ return(1);
+ }
+ if ((tmpname[0] == '.') && (tmpname[1] == '\0')) {
+ tty_prnt("Processing continues, name unchanged.\n");
+ return(0);
+ }
+
+ /*
+ * ok the name changed. We may run into links that point at this
+ * file later. we have to remember where the user sent the file
+ * in order to repair any links.
+ */
+ tty_prnt("Processing continues, name changed to: %s\n", tmpname);
+ res = add_name(arcn->name, arcn->nlen, tmpname);
+ arcn->nlen = strlcpy(arcn->name, tmpname, sizeof(arcn->name));
+ if (arcn->nlen >= sizeof(arcn->name))
+ arcn->nlen = sizeof(arcn->name) - 1; /* XXX truncate? */
+ if (res < 0)
+ return(-1);
+ return(0);
+}
+
+/*
+ * set_dest()
+ * fix up the file name and the link name (if any) so this file will land
+ * in the destination directory (used during copy() -rw).
+ * Return:
+ * 0 if ok, -1 if failure (name too long)
+ */
+
+int
+set_dest(ARCHD *arcn, char *dest_dir, int dir_len)
+{
+ if (fix_path(arcn->name, &(arcn->nlen), dest_dir, dir_len) < 0)
+ return(-1);
+
+ /*
+ * It is really hard to deal with symlinks here, we cannot be sure
+ * if the name they point was moved (or will be moved). It is best to
+ * leave them alone.
+ */
+ if ((arcn->type != PAX_HLK) && (arcn->type != PAX_HRG))
+ return(0);
+
+ if (fix_path(arcn->ln_name, &(arcn->ln_nlen), dest_dir, dir_len) < 0)
+ return(-1);
+ return(0);
+}
+
+/*
+ * fix_path
+ * concatenate dir_name and or_name and store the result in or_name (if
+ * it fits). This is one ugly function.
+ * Return:
+ * 0 if ok, -1 if the final name is too long
+ */
+
+static int
+fix_path(char *or_name, int *or_len, char *dir_name, int dir_len)
+{
+ char *src;
+ char *dest;
+ char *start;
+ int len;
+
+ /*
+ * we shift the or_name to the right enough to tack in the dir_name
+ * at the front. We make sure we have enough space for it all before
+ * we start. since dest always ends in a slash, we skip of or_name
+ * if it also starts with one.
+ */
+ start = or_name;
+ src = start + *or_len;
+ dest = src + dir_len;
+ if (*start == '/') {
+ ++start;
+ --dest;
+ }
+ if ((len = dest - or_name) > PAXPATHLEN) {
+ paxwarn(1, "File name %s/%s, too long", dir_name, start);
+ return(-1);
+ }
+ *or_len = len;
+
+ /*
+ * enough space, shift
+ */
+ while (src >= start)
+ *dest-- = *src--;
+ src = dir_name + dir_len - 1;
+
+ /*
+ * splice in the destination directory name
+ */
+ while (src >= dir_name)
+ *dest-- = *src--;
+
+ *(or_name + len) = '\0';
+ return(0);
+}
+
+/*
+ * rep_name()
+ * walk down the list of replacement strings applying each one in order.
+ * when we find one with a successful substitution, we modify the name
+ * as specified. if required, we print the results. if the resulting name
+ * is empty, we will skip this archive member. We use the regexp(3)
+ * routines (regexp() ought to win a prize as having the most cryptic
+ * library function manual page).
+ * --Parameters--
+ * name is the file name we are going to apply the regular expressions to
+ * (and may be modified)
+ * nsize is the size of the name buffer.
+ * nlen is the length of this name (and is modified to hold the length of
+ * the final string).
+ * prnt is a flag that says whether to print the final result.
+ * Return:
+ * 0 if substitution was successful, 1 if we are to skip the file (the name
+ * ended up empty)
+ */
+
+static int
+rep_name(char *name, size_t nsize, int *nlen, int prnt)
+{
+ REPLACE *pt;
+ char *inpt;
+ char *outpt;
+ char *endpt;
+ char *rpt;
+ int found = 0;
+ int res;
+ regmatch_t pm[MAXSUBEXP];
+ char nname[PAXPATHLEN+1]; /* final result of all replacements */
+ char buf1[PAXPATHLEN+1]; /* where we work on the name */
+
+ /*
+ * copy the name into buf1, where we will work on it. We need to keep
+ * the orig string around so we can print out the result of the final
+ * replacement. We build up the final result in nname. inpt points at
+ * the string we apply the regular expression to. prnt is used to
+ * suppress printing when we handle replacements on the link field
+ * (the user already saw that substitution go by)
+ */
+ pt = rephead;
+ (void)strlcpy(buf1, name, sizeof(buf1));
+ inpt = buf1;
+ outpt = nname;
+ endpt = outpt + PAXPATHLEN;
+
+ /*
+ * try each replacement string in order
+ */
+ while (pt != NULL) {
+ do {
+ char *oinpt = inpt;
+ /*
+ * check for a successful substitution, if not go to
+ * the next pattern, or cleanup if we were global
+ */
+ if (regexec(&(pt->rcmp), inpt, MAXSUBEXP, pm, 0) != 0)
+ break;
+
+ /*
+ * ok we found one. We have three parts, the prefix
+ * which did not match, the section that did and the
+ * tail (that also did not match). Copy the prefix to
+ * the final output buffer (watching to make sure we
+ * do not create a string too long).
+ */
+ found = 1;
+ rpt = inpt + pm[0].rm_so;
+
+ while ((inpt < rpt) && (outpt < endpt))
+ *outpt++ = *inpt++;
+ if (outpt == endpt)
+ break;
+
+ /*
+ * for the second part (which matched the regular
+ * expression) apply the substitution using the
+ * replacement string and place it the prefix in the
+ * final output. If we have problems, skip it.
+ */
+ if ((res = resub(&(pt->rcmp),pm,pt->nstr,oinpt,outpt,endpt))
+ < 0) {
+ if (prnt)
+ paxwarn(1, "Replacement name error %s",
+ name);
+ return(1);
+ }
+ outpt += res;
+
+ /*
+ * we set up to look again starting at the first
+ * character in the tail (of the input string right
+ * after the last character matched by the regular
+ * expression (inpt always points at the first char in
+ * the string to process). If we are not doing a global
+ * substitution, we will use inpt to copy the tail to
+ * the final result. Make sure we do not overrun the
+ * output buffer
+ */
+ inpt += pm[0].rm_eo - pm[0].rm_so;
+
+ if ((outpt == endpt) || (*inpt == '\0'))
+ break;
+
+ /*
+ * if the user wants global we keep trying to
+ * substitute until it fails, then we are done.
+ */
+ } while (pt->flgs & GLOB);
+
+ if (found)
+ break;
+
+ /*
+ * a successful substitution did NOT occur, try the next one
+ */
+ pt = pt->fow;
+ }
+
+ if (found) {
+ /*
+ * we had a substitution, copy the last tail piece (if there is
+ * room) to the final result
+ */
+ while ((outpt < endpt) && (*inpt != '\0'))
+ *outpt++ = *inpt++;
+
+ *outpt = '\0';
+ if ((outpt == endpt) && (*inpt != '\0')) {
+ if (prnt)
+ paxwarn(1,"Replacement name too long %s >> %s",
+ name, nname);
+ return(1);
+ }
+
+ /*
+ * inform the user of the result if wanted
+ */
+ if (prnt && (pt->flgs & PRNT)) {
+ if (*nname == '\0')
+ (void)fprintf(stderr,"%s >> <empty string>\n",
+ name);
+ else
+ (void)fprintf(stderr,"%s >> %s\n", name, nname);
+ }
+
+ /*
+ * if empty inform the caller this file is to be skipped
+ * otherwise copy the new name over the orig name and return
+ */
+ if (*nname == '\0')
+ return(1);
+ *nlen = strlcpy(name, nname, nsize);
+ }
+ return(0);
+}
+
+/*
+ * resub()
+ * apply the replacement to the matched expression. expand out the old
+ * style ed(1) subexpression expansion.
+ * Return:
+ * -1 if error, or the number of characters added to the destination.
+ */
+
+static int
+resub(regex_t *rp, regmatch_t *pm, char *src, char *inpt, char *dest,
+ char *destend)
+{
+ char *spt;
+ char *dpt;
+ char c;
+ regmatch_t *pmpt;
+ int len;
+ int subexcnt;
+
+ spt = src;
+ dpt = dest;
+ subexcnt = rp->re_nsub;
+ while ((dpt < destend) && ((c = *spt++) != '\0')) {
+ /*
+ * see if we just have an ordinary replacement character
+ * or we refer to a subexpression.
+ */
+ if (c == '&') {
+ pmpt = pm;
+ } else if ((c == '\\') && (*spt >= '0') && (*spt <= '9')) {
+ /*
+ * make sure there is a subexpression as specified
+ */
+ if ((len = *spt++ - '0') > subexcnt)
+ return(-1);
+ pmpt = pm + len;
+ } else {
+ /*
+ * Ordinary character, just copy it
+ */
+ if ((c == '\\') && (*spt != '\0'))
+ c = *spt++;
+ *dpt++ = c;
+ continue;
+ }
+
+ /*
+ * continue if the subexpression is bogus
+ */
+ if ((pmpt->rm_so < 0) || (pmpt->rm_eo < 0) ||
+ ((len = (int)(pmpt->rm_eo - pmpt->rm_so)) <= 0))
+ continue;
+
+ /*
+ * copy the subexpression to the destination.
+ * fail if we run out of space or the match string is damaged
+ */
+ if (len > (destend - dpt))
+ len = destend - dpt;
+ strncpy(dpt, inpt + pmpt->rm_so, len);
+ dpt += len;
+ }
+ return(dpt - dest);
+}
diff --git a/file_cmds/pax/pat_rep.h b/file_cmds/pax/pat_rep.h
new file mode 100644
index 0000000..4d65a8e
--- /dev/null
+++ b/file_cmds/pax/pat_rep.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: pat_rep.h,v 1.4 2003/06/02 23:32:08 millert Exp $ */
+/* $NetBSD: pat_rep.h,v 1.3 1995/03/21 09:07:35 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pat_rep.h 8.1 (Berkeley) 5/31/93
+ */
+
+#ifndef _PAT_REP_H_
+#define _PAT_REP_H_
+
+/*
+ * data structure for storing user supplied replacement strings (-s)
+ */
+typedef struct replace {
+ char *nstr; /* the new string we will substitute with */
+ regex_t rcmp; /* compiled regular expression used to match */
+ int flgs; /* print conversions? global in operation? */
+#define PRNT 0x1
+#define GLOB 0x2
+ struct replace *fow; /* pointer to next pattern */
+} REPLACE;
+
+int tty_rename(ARCHD *); /* used for -o invalid=rename recovery */
+
+#endif /* _PAT_REP_H_ */
diff --git a/file_cmds/pax/pax.1 b/file_cmds/pax/pax.1
new file mode 100644
index 0000000..e79cc4b
--- /dev/null
+++ b/file_cmds/pax/pax.1
@@ -0,0 +1,1185 @@
+.\" $OpenBSD: pax.1,v 1.54 2008/06/11 07:42:50 jmc Exp $
+.\" $NetBSD: pax.1,v 1.3 1995/03/21 09:07:37 cgd Exp $
+.\"
+.\" Copyright (c) 1992 Keith Muller.
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Keith Muller of the University of California, San Diego.
+.\"
+.\" 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 University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pax.1 8.4 (Berkeley) 4/18/94
+.\"
+.Dd $Mdocdate: June 11 2008 $
+.Dt PAX 1
+.Os
+.Sh NAME
+.Nm pax
+.Nd read and write file archives and copy directory hierarchies
+.Sh SYNOPSIS
+.Bk -words
+.Nm pax
+.Op Fl 0cdjnOvz
+.Op Fl E Ar limit
+.Op Fl f Ar archive
+.Op Fl G Ar group
+.Op Fl s Ar replstr
+.Op Fl T Ar range
+.Op Fl U Ar user
+.Op Ar pattern ...
+.Nm pax
+.Fl r
+.Op Fl 0cDdijknOuvYZz
+.Op Fl E Ar limit
+.Op Fl f Ar archive
+.Op Fl G Ar group
+.Op Fl o Ar options
+.Op Fl p Ar string
+.Op Fl s Ar replstr
+.Op Fl T Ar range
+.Op Fl U Ar user
+.Op Ar pattern ...
+.Nm pax
+.Fl w
+.Op Fl 0adHijLOPtuvXz
+.Op Fl B Ar bytes
+.Op Fl b Ar blocksize
+.Op Fl f Ar archive
+.Op Fl G Ar group
+.Op Fl o Ar options
+.Op Fl s Ar replstr
+.Op Fl T Ar range
+.Op Fl U Ar user
+.Op Fl x Ar format
+.Op Ar file ...
+.Nm pax
+.Fl rw
+.Op Fl 0DdHijkLlnOPtuvXYZ
+.Op Fl G Ar group
+.Op Fl p Ar string
+.Op Fl s Ar replstr
+.Op Fl T Ar range
+.Op Fl U Ar user
+.Op Ar file ...
+.Ar directory
+.Ek
+.Sh DESCRIPTION
+.Nm
+will read, write, and list the members of an archive file
+and will copy directory hierarchies.
+.Nm
+operation is independent of the specific archive format
+and supports a wide variety of different archive formats.
+A list of supported archive formats can be found under the description of the
+.Fl x
+option.
+.Pp
+The presence of the
+.Fl r
+and the
+.Fl w
+options specifies which of the following functional modes
+.Nm
+will operate under:
+.Em list , read , write ,
+and
+.Em copy .
+.Bl -tag -width 6n
+.It \*(Ltnone\*(Gt
+.Em List .
+.Nm
+will write to standard output
+a table of contents of the members of the archive file read from
+standard input, whose pathnames match the specified
+.Ar pattern
+arguments.
+The table of contents contains one filename per line
+and is written using single line buffering.
+.It Fl r
+.Em Read .
+.Nm
+extracts the members of the archive file read from the standard input,
+with pathnames matching the specified
+.Ar pattern
+arguments.
+The archive format and blocking is automatically determined on input.
+When an extracted file is a directory, the entire file hierarchy
+rooted at that directory is extracted.
+Extracted files are created either at absolute paths (those that begin
+with a / character) or relative to the current file hierarchy unless the
+.Fl s
+option is used to remove leading slashes or add a relative path prefix.
+Files being extracted to absolute paths may overwrite
+files outside of the current working directory,
+so care should be taken when extracting untrusted archives.
+The setting of ownership, access and modification times, and file mode of
+the extracted files are discussed in more detail under the
+.Fl p
+option.
+.It Fl w
+.Em Write .
+.Nm
+writes an archive containing the
+.Ar file
+operands to standard output
+using the specified archive format.
+When no
+.Ar file
+operands are specified, a list of files to copy with one per line is read from
+standard input.
+When a
+.Ar file
+operand is also a directory, the entire file hierarchy rooted
+at that directory will be included.
+.It Fl rw
+.Em Copy .
+.Nm
+copies the
+.Ar file
+operands to the destination
+.Ar directory .
+When no
+.Ar file
+operands are specified, a list of files to copy with one per line is read from
+the standard input.
+When a
+.Ar file
+operand is also a directory the entire file
+hierarchy rooted at that directory will be included.
+The effect of the
+.Em copy
+is as if the copied files were written to an archive file and then
+subsequently extracted, except that there may be hard links between
+the original and the copied files (see the
+.Fl l
+option below).
+.Pp
+.Sy Warning :
+The destination
+.Ar directory
+must not be one of the
+.Ar file
+operands or a member of a file hierarchy rooted at one of the
+.Ar file
+operands.
+The result of a
+.Em copy
+under these conditions is unpredictable.
+.El
+.Pp
+While processing a damaged archive during a
+.Em read
+or
+.Em list
+operation,
+.Nm
+will attempt to recover from media defects and will search through the archive
+to locate and process the largest number of archive members possible (see the
+.Fl E
+option for more details on error handling).
+.Pp
+The
+.Ar directory
+operand specifies a destination directory pathname.
+If the
+.Ar directory
+operand does not exist, or it is not writable by the user,
+or it is not of type directory,
+.Nm
+will exit with a non-zero exit status.
+.Pp
+The
+.Ar pattern
+operand is used to select one or more pathnames of archive members.
+Archive members are selected using the pattern matching notation described
+by
+.Xr glob 3 .
+When the
+.Ar pattern
+operand is not supplied, all members of the archive will be selected.
+When a
+.Ar pattern
+matches a directory, the entire file hierarchy rooted at that directory will
+be selected.
+When a
+.Ar pattern
+operand does not select at least one archive member,
+.Nm
+will write these
+.Ar pattern
+operands in a diagnostic message to standard error
+and then exit with a non-zero exit status.
+.Pp
+The
+.Ar file
+operand specifies the pathname of a file to be copied or archived.
+When a
+.Ar file
+operand does not select at least one archive member,
+.Nm
+will write these
+.Ar file
+operand pathnames in a diagnostic message to standard error
+and then exit with a non-zero exit status.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl 0
+Use the NUL
+.Pq Ql \e0
+character as a pathname terminator, instead of newline
+.Pq Ql \en .
+This applies only to the pathnames read from standard input in
+the write and copy modes,
+and to the pathnames written to standard output in list mode.
+This option is expected to be used in concert with the
+.Fl print0
+function in
+.Xr find 1
+or the
+.Fl 0
+flag in
+.Xr xargs 1 .
+.It Fl a
+Append the given
+.Ar file
+operands
+to the end of an archive that was previously written.
+If an archive format is not specified with a
+.Fl x
+option, the format currently being used in the archive will be selected.
+Any attempt to append to an archive in a format different from the
+format already used in the archive will cause
+.Nm
+to exit immediately
+with a non-zero exit status.
+The blocking size used in the archive volume where writing starts
+will continue to be used for the remainder of that archive volume.
+.Pp
+.Sy Warning :
+Many storage devices are not able to support the operations necessary
+to perform an append operation.
+Any attempt to append to an archive stored on such a device may damage the
+archive or have other unpredictable results.
+Tape drives in particular are more likely to not support an append operation.
+An archive stored in a regular file system file or on a disk device will
+usually support an append operation.
+.It Fl B Ar bytes
+Limit the number of bytes written to a single archive volume to
+.Ar bytes .
+The
+.Ar bytes
+limit can end with
+.Sq Li m ,
+.Sq Li k ,
+or
+.Sq Li b
+to specify multiplication by 1048576 (1M), 1024 (1K) or 512, respectively.
+A pair of
+.Ar bytes
+limits can be separated by
+.Sq Li x
+to indicate a product.
+.Pp
+.Em Warning :
+Only use this option when writing an archive to a device which supports
+an end of file read condition based on last (or largest) write offset
+(such as a regular file or a tape drive).
+The use of this option with a floppy or hard disk is not recommended.
+.It Fl b Ar blocksize
+When
+.Em writing
+an archive,
+block the output at a positive decimal integer number of
+bytes per write to the archive file.
+The
+.Ar blocksize
+must be a multiple of 512 bytes with a maximum of 64512 bytes.
+Archive block sizes larger than 32256 bytes violate the
+.Tn POSIX
+standard and will not be portable to all systems.
+A
+.Ar blocksize
+can end with
+.Sq Li k
+or
+.Sq Li b
+to specify multiplication by 1024 (1K) or 512, respectively.
+A pair of
+.Ar blocksizes
+can be separated by
+.Sq Li x
+to indicate a product.
+A specific archive device may impose additional restrictions on the size
+of blocking it will support.
+When blocking is not specified, the default
+.Ar blocksize
+is dependent on the specific archive format being used (see the
+.Fl x
+option).
+.It Fl c
+Match all file or archive members
+.Em except
+those specified by the
+.Ar pattern
+and
+.Ar file
+operands.
+.It Fl D
+This option is the same as the
+.Fl u
+option, except that the file inode change time is checked instead of the
+file modification time.
+The file inode change time can be used to select files whose inode information
+(e.g., UID, GID, etc.) is newer than a copy of the file in the destination
+.Ar directory .
+.It Fl d
+Cause files of type directory being copied or archived, or archive members of
+type directory being extracted, to match only the directory file or archive
+member and not the file hierarchy rooted at the directory.
+.It Fl E Ar limit
+Limit the number of consecutive read faults while trying to read a flawed
+archive to
+.Ar limit .
+With a positive
+.Ar limit ,
+.Nm
+will attempt to recover from an archive read error and will
+continue processing starting with the next file stored in the archive.
+A
+.Ar limit
+of 0 will cause
+.Nm
+to stop operation after the first read error is detected on an archive volume.
+A
+.Ar limit
+of
+.Li NONE
+will cause
+.Nm
+to attempt to recover from read errors forever.
+The default
+.Ar limit
+is a small positive number of retries.
+.Pp
+.Em Warning :
+Using this option with
+.Li NONE
+should be used with extreme caution as
+.Nm
+may get stuck in an infinite loop on a very badly flawed archive.
+.It Fl f Ar archive
+Specify
+.Ar archive
+as the pathname of the input or output archive, overriding the default
+standard input (for
+.Em list
+and
+.Em read )
+or standard output
+(for
+.Em write ) .
+A single archive may span multiple files and different archive devices.
+When required,
+.Nm
+will prompt for the pathname of the file or device of the next volume in the
+archive.
+.It Fl G Ar group
+Select a file based on its
+.Ar group
+name, or when starting with a
+.Cm # ,
+a numeric GID.
+A
+.Ql \e
+can be used to escape the
+.Cm # .
+Multiple
+.Fl G
+options may be supplied and checking stops with the first match.
+.It Fl H
+Follow only command-line symbolic links while performing a physical file
+system traversal.
+.It Fl i
+Interactively rename files or archive members.
+For each archive member matching a
+.Ar pattern
+operand or each file matching a
+.Ar file
+operand,
+.Nm
+will prompt to
+.Pa /dev/tty
+giving the name of the file, its file mode, and its modification time.
+.Nm
+will then read a line from
+.Pa /dev/tty .
+If this line is blank, the file or archive member is skipped.
+If this line consists of a single period, the
+file or archive member is processed with no modification to its name.
+Otherwise, its name is replaced with the contents of the line.
+.Nm
+will immediately exit with a non-zero exit status if
+.Dv EOF
+is encountered when reading a response or if
+.Pa /dev/tty
+cannot be opened for reading and writing.
+.It Fl j
+Use bzip2 to compress (decompress) the archive while writing (reading).
+The bzip2 utility must be installed separately.
+Incompatible with
+.Fl a .
+.It Fl k
+Do not overwrite existing files.
+.It Fl L
+Follow all symbolic links to perform a logical file system traversal.
+.It Fl l
+(The lowercase letter
+.Dq ell . )
+Link files.
+In the
+.Em copy
+mode
+.Pq Fl r Fl w ,
+hard links are made between the source and destination file hierarchies
+whenever possible.
+.It Fl n
+Select the first archive member that matches each
+.Ar pattern
+operand.
+No more than one archive member is matched for each
+.Ar pattern .
+When members of type directory are matched, the file hierarchy rooted at that
+directory is also matched (unless
+.Fl d
+is also specified).
+.It Fl O
+Force the archive to be one volume.
+If a volume ends prematurely,
+.Nm
+will not prompt for a new volume.
+This option can be useful for
+automated tasks where error recovery cannot be performed by a human.
+.It Fl o Ar options
+Information to modify the algorithm for extracting or writing archive files
+which is specific to the archive format specified by
+.Fl x .
+In general,
+.Ar options
+take the form:
+.Ar name Ns = Ns Ar value .
+.Pp
+The following options are available for the old
+.Bx
+.Em tar
+format:
+.Pp
+.Bl -tag -width Ds -compact
+.It Cm nodir
+.It Cm write_opt=nodir
+When writing archives, omit the storage of directories.
+.El
+.It Fl P
+Do not follow symbolic links, perform a physical file system traversal.
+This is the default mode.
+.It Fl p Ar string
+Specify one or more file characteristic options (privileges).
+The
+.Ar string
+option-argument is a string specifying file characteristics to be retained or
+discarded on extraction.
+The string consists of the specification characters
+.Cm a , e , m , o ,
+and
+.Cm p .
+Multiple characteristics can be concatenated within the same string
+and multiple
+.Fl p
+options can be specified.
+The meanings of the specification characters are as follows:
+.Bl -tag -width 2n
+.It Cm a
+Do not preserve file access times.
+By default, file access times are preserved whenever possible.
+.It Cm e
+.Dq Preserve everything ,
+the user ID, group ID, file mode bits,
+file access time, and file modification time.
+This is intended to be used by
+.Em root ,
+someone with all the appropriate privileges, in order to preserve all
+aspects of the files as they are recorded in the archive.
+The
+.Cm e
+flag is the sum of the
+.Cm o
+and
+.Cm p
+flags.
+.It Cm m
+Do not preserve file modification times.
+By default, file modification times are preserved whenever possible.
+.It Cm o
+Preserve the user ID and group ID.
+.It Cm p
+.Dq Preserve
+the file mode bits.
+This is intended to be used by a
+.Em user
+with regular privileges who wants to preserve all aspects of the file other
+than the ownership.
+The file times are preserved by default, but two other flags are offered to
+disable this and use the time of extraction instead.
+.El
+.Pp
+In the preceding list,
+.Sq preserve
+indicates that an attribute stored in the archive is given to the
+extracted file, subject to the permissions of the invoking
+process.
+Otherwise the attribute of the extracted file is determined as
+part of the normal file creation action.
+If neither the
+.Cm e
+nor the
+.Cm o
+specification character is specified, or the user ID and group ID are not
+preserved for any reason,
+.Nm
+will not set the
+.Dv S_ISUID
+.Em ( setuid )
+and
+.Dv S_ISGID
+.Em ( setgid )
+bits of the file mode.
+If the preservation of any of these items fails for any reason,
+.Nm
+will write a diagnostic message to standard error.
+Failure to preserve these items will affect the final exit status,
+but will not cause the extracted file to be deleted.
+If the file characteristic letters in any of the string option-arguments are
+duplicated or conflict with each other, the one(s) given last will take
+precedence.
+For example, if
+.Fl p Ar eme
+is specified, file modification times are still preserved.
+.It Fl r
+Read an archive file from standard input
+and extract the specified
+.Ar file
+operands.
+If any intermediate directories are needed in order to extract an archive
+member, these directories will be created as if
+.Xr mkdir 2
+was called with the bitwise inclusive
+.Tn OR
+of
+.Dv S_IRWXU , S_IRWXG ,
+and
+.Dv S_IRWXO
+as the mode argument.
+When the selected archive format supports the specification of linked
+files and these files cannot be linked while the archive is being extracted,
+.Nm
+will write a diagnostic message to standard error
+and exit with a non-zero exit status at the completion of operation.
+.It Fl s Ar replstr
+Modify the archive member names according to the substitution expression
+.Ar replstr ,
+using the syntax of the
+.Xr ed 1
+utility regular expressions.
+.Ar file
+or
+.Ar pattern
+arguments may be given to restrict the list of archive members to those
+specified.
+.Pp
+The format of these regular expressions is:
+.Pp
+.Dl /old/new/[gp]
+.Pp
+As in
+.Xr ed 1 ,
+.Ar old
+is a basic regular expression (see
+.Xr re_format 7 )
+and
+.Ar new
+can contain an ampersand
+.Pq Ql & ,
+.Ql \e Ns Em n
+(where
+.Em n
+is a digit) back-references,
+or subexpression matching.
+The
+.Ar old
+string may also contain newline characters.
+Any non-null character can be used as a delimiter
+.Po
+.Ql /
+is shown here
+.Pc .
+Multiple
+.Fl s
+expressions can be specified.
+The expressions are applied in the order they are specified on the
+command line, terminating with the first successful substitution.
+.Pp
+The optional trailing
+.Cm g
+continues to apply the substitution expression to the pathname substring,
+which starts with the first character following the end of the last successful
+substitution.
+The first unsuccessful substitution stops the operation of the
+.Cm g
+option.
+The optional trailing
+.Cm p
+will cause the final result of a successful substitution to be written to
+standard error in the following format:
+.Pp
+.D1 Em original-pathname No \*(Gt\*(Gt Em new-pathname
+.Pp
+File or archive member names that substitute to the empty string
+are not selected and will be skipped.
+.It Fl T Ar range
+Allow files to be selected based on a file modification or inode change
+time falling within the specified time range.
+The range has the format:
+.Sm off
+.Bd -filled -offset indent
+.Oo Ar from_date Oc Oo ,
+.Ar to_date Oc Oo /
+.Oo Cm c Oc Op Cm m Oc
+.Ed
+.Sm on
+.Pp
+The dates specified by
+.Ar from_date
+to
+.Ar to_date
+are inclusive.
+If only a
+.Ar from_date
+is supplied, all files with a modification or inode change time
+equal to or younger are selected.
+If only a
+.Ar to_date
+is supplied, all files with a modification or inode change time
+equal to or older will be selected.
+When the
+.Ar from_date
+is equal to the
+.Ar to_date ,
+only files with a modification or inode change time of exactly that
+time will be selected.
+.Pp
+When
+.Nm
+is in the
+.Em write
+or
+.Em copy
+mode, the optional trailing field
+.Oo Cm c Oc Op Cm m
+can be used to determine which file time (inode change, file modification or
+both) are used in the comparison.
+If neither is specified, the default is to use file modification time only.
+The
+.Cm m
+specifies the comparison of file modification time (the time when
+the file was last written).
+The
+.Cm c
+specifies the comparison of inode change time (the time when the file
+inode was last changed; e.g., a change of owner, group, mode, etc).
+When
+.Cm c
+and
+.Cm m
+are both specified, then the modification and inode change times are
+both compared.
+.Pp
+The inode change time comparison is useful in selecting files whose
+attributes were recently changed or selecting files which were recently
+created and had their modification time reset to an older time (as what
+happens when a file is extracted from an archive and the modification time
+is preserved).
+Time comparisons using both file times is useful when
+.Nm
+is used to create a time based incremental archive (only files that were
+changed during a specified time range will be archived).
+.Pp
+A time range is made up of six different fields and each field must contain two
+digits.
+The format is:
+.Pp
+.Dl [[[[[cc]yy]mm]dd]HH]MM[.SS]
+.Pp
+Where
+.Ar cc
+is the first two digits of the year (the century),
+.Ar yy
+is the last two digits of the year,
+the first
+.Ar mm
+is the month (from 01 to 12),
+.Ar dd
+is the day of the month (from 01 to 31),
+.Ar HH
+is the hour of the day (from 00 to 23),
+.Ar MM
+is the minute (from 00 to 59),
+and
+.Ar SS
+is the seconds (from 00 to 59).
+The minute field
+.Ar MM
+is required, while the other fields are optional and must be added in the
+following order:
+.Ar HH , dd , mm ,
+.Ar yy , cc .
+.Pp
+The
+.Ar SS
+field may be added independently of the other fields.
+Time ranges are relative to the current time, so
+.Ic -T 1234/cm
+would select all files with a modification or inode change time
+of 12:34 PM today or later.
+Multiple
+.Fl T
+time range can be supplied and checking stops with the first match.
+.It Fl t
+Reset the access times of any file or directory read or accessed by
+.Nm
+to be the same as they were before being read or accessed by
+.Nm pax .
+.It Fl U Ar user
+Select a file based on its
+.Ar user
+name, or when starting with a
+.Cm # ,
+a numeric UID.
+A
+.Ql \e
+can be used to escape the
+.Cm # .
+Multiple
+.Fl U
+options may be supplied and checking stops with the first match.
+.It Fl u
+Ignore files that are older (having a less recent file modification time)
+than a pre-existing file or archive member with the same name.
+During
+.Em read ,
+an archive member with the same name as a file in the file system will be
+extracted if the archive member is newer than the file.
+During
+.Em write ,
+a file system member with the same name as an archive member will be
+written to the archive if it is newer than the archive member.
+During
+.Em copy ,
+the file in the destination hierarchy is replaced by the file in the source
+hierarchy or by a link to the file in the source hierarchy if the file in
+the source hierarchy is newer.
+.It Fl v
+During a
+.Em list
+operation, produce a verbose table of contents using the format of the
+.Xr ls 1
+utility with the
+.Fl l
+option.
+For pathnames representing a hard link to a previous member of the archive,
+the output has the format:
+.Pp
+.Dl Em ls -l listing Li == Em link-name
+.Pp
+For pathnames representing a symbolic link, the output has the format:
+.Pp
+.Dl Em ls -l listing Li =\*(Gt Em link-name
+.Pp
+Where
+.Em ls -l listing
+is the output format specified by the
+.Xr ls 1
+utility when used with the
+.Fl l
+option.
+Otherwise for all the other operational modes
+.Po Em read , write , No and Em copy
+.Pc ,
+pathnames are written and flushed to standard error
+without a trailing newline
+as soon as processing begins on that file or
+archive member.
+The trailing newline
+is not buffered and is written only after the file has been read or written.
+.It Fl w
+Write files to the standard output
+in the specified archive format.
+When no
+.Ar file
+operands are specified, standard input
+is read for a list of pathnames with one per line without any leading or
+trailing
+.Aq blanks .
+.It Fl X
+When traversing the file hierarchy specified by a pathname,
+do not descend into directories that have a different device ID.
+See the
+.Li st_dev
+field as described in
+.Xr stat 2
+for more information about device IDs.
+.It Fl x Ar format
+Specify the output archive format, with the default format being
+.Cm ustar .
+.Nm
+currently supports the following formats:
+.Bl -tag -width "sv4cpio"
+.It Cm bcpio
+The old binary cpio format.
+The default blocksize for this format is 5120 bytes.
+This format is not very portable and should not be used when other formats
+are available.
+Inode and device information about a file (used for detecting file hard links
+by this format), which may be truncated by this format, is detected by
+.Nm
+and is repaired.
+.It Cm cpio
+The extended cpio interchange format specified in the
+.St -p1003.2
+standard.
+The default blocksize for this format is 5120 bytes.
+Inode and device information about a file (used for detecting file hard links
+by this format), which may be truncated by this format, is detected by
+.Nm
+and is repaired.
+.It Cm sv4cpio
+The System V release 4 cpio.
+The default blocksize for this format is 5120 bytes.
+Inode and device information about a file (used for detecting file hard links
+by this format), which may be truncated by this format, is detected by
+.Nm
+and is repaired.
+.It Cm sv4crc
+The System V release 4 cpio with file CRC checksums.
+The default blocksize for this format is 5120 bytes.
+Inode and device information about a file (used for detecting file hard links
+by this format), which may be truncated by this format, is detected by
+.Nm
+and is repaired.
+.It Cm tar
+The old
+.Bx
+tar format as found in
+.Bx 4.3 .
+The default blocksize for this format is 10240 bytes.
+Pathnames stored by this format must be 100 characters or less in length.
+Only
+.Em regular
+files,
+.Em hard links , soft links ,
+and
+.Em directories
+will be archived (other file system types are not supported).
+For backwards compatibility with even older tar formats, a
+.Fl o
+option can be used when writing an archive to omit the storage of directories.
+This option takes the form:
+.Pp
+.Dl Fl o Cm write_opt=nodir
+.It Cm ustar
+The extended tar interchange format specified in the
+.St -p1003.2
+standard.
+The default blocksize for this format is 10240 bytes.
+Filenames stored by this format must be 100 characters or less in length;
+the total pathname must be 255 characters or less.
+.El
+.Pp
+.Nm
+will detect and report any file that it is unable to store or extract
+as the result of any specific archive format restrictions.
+The individual archive formats may impose additional restrictions on use.
+Typical archive format restrictions include (but are not limited to):
+file pathname length, file size, link pathname length, and the type of the
+file.
+.It Fl Y
+This option is the same as the
+.Fl D
+option, except that the inode change time is checked using the
+pathname created after all the file name modifications have completed.
+.It Fl Z
+This option is the same as the
+.Fl u
+option, except that the modification time is checked using the
+pathname created after all the file name modifications have completed.
+.It Fl z
+Use
+.Xr gzip 1
+to compress (decompress) the archive while writing (reading).
+Incompatible with
+.Fl a .
+.It Fl -insecure
+Normally
+.Nm
+ignores filenames or symbolic links that contain
+.Dq ..
+as a path component.
+With this option,
+files that contain
+.Dq ..
+can be processed.
+.El
+.Pp
+The options that operate on the names of files or archive members
+.Po Fl c ,
+.Fl i ,
+.Fl j ,
+.Fl n ,
+.Fl s ,
+.Fl u ,
+.Fl v ,
+.Fl D ,
+.Fl G ,
+.Fl T ,
+.Fl U ,
+.Fl Y ,
+and
+.Fl Z
+.Pc
+interact as follows.
+.Pp
+When extracting files during a
+.Em read
+operation, archive members are
+.Sq selected ,
+based only on the user specified pattern operands as modified by the
+.Fl c ,
+.Fl n ,
+.Fl u ,
+.Fl D ,
+.Fl G ,
+.Fl T ,
+.Fl U
+options.
+Then any
+.Fl s
+and
+.Fl i
+options will modify in that order, the names of these selected files.
+Then the
+.Fl Y
+and
+.Fl Z
+options will be applied based on the final pathname.
+Finally, the
+.Fl v
+option will write the names resulting from these modifications.
+.Pp
+When archiving files during a
+.Em write
+operation, or copying files during a
+.Em copy
+operation, archive members are
+.Sq selected ,
+based only on the user specified pathnames as modified by the
+.Fl n ,
+.Fl u ,
+.Fl D ,
+.Fl G ,
+.Fl T ,
+and
+.Fl U
+options (the
+.Fl D
+option only applies during a copy operation).
+Then any
+.Fl s
+and
+.Fl i
+options will modify in that order, the names of these selected files.
+Then during a
+.Em copy
+operation the
+.Fl Y
+and the
+.Fl Z
+options will be applied based on the final pathname.
+Finally, the
+.Fl v
+option will write the names resulting from these modifications.
+.Pp
+When one or both of the
+.Fl u
+or
+.Fl D
+options are specified along with the
+.Fl n
+option, a file is not considered selected unless it is newer
+than the file to which it is compared.
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev TMPDIR
+Path in which to store temporary files.
+.El
+.Sh EXAMPLES
+Copy the contents of the current directory to the device
+.Pa /dev/rst0 :
+.Pp
+.Dl $ pax -w -f /dev/rst0 \&.
+.Pp
+Give the verbose table of contents for an archive stored in
+.Pa filename :
+.Pp
+.Dl $ pax -v -f filename
+.Pp
+This sequence of commands will copy the entire
+.Pa olddir
+directory hierarchy to
+.Pa newdir :
+.Bd -literal -offset indent
+$ mkdir newdir
+$ cd olddir
+$ pax -rw . ../newdir
+.Ed
+.Pp
+Extract files from the archive
+.Pa a.pax .
+Files rooted in
+.Pa /usr
+are extracted relative to the current working directory;
+all other files are extracted to their unmodified path.
+.Pp
+.Dl $ pax -r -s ',^/usr/,,' -f a.pax
+.Pp
+This can be used to interactively select the files to copy from the
+current directory to
+.Pa dest_dir :
+.Pp
+.Dl $ pax -rw -i \&. dest_dir
+.Pp
+Extract all files from the archive
+.Pa a.pax
+which are owned by
+.Em root
+with group
+.Em bin
+and preserve all file permissions:
+.Pp
+.Dl "$ pax -r -pe -U root -G bin -f a.pax"
+.Pp
+Update (and list) only those files in the destination directory
+.Pa /backup
+which are older (less recent inode change or file modification times) than
+files with the same name found in the source file tree
+.Pa home :
+.Pp
+.Dl "$ pax -r -w -v -Y -Z home /backup"
+.Sh DIAGNOSTICS
+.Nm
+will exit with one of the following values:
+.Bl -tag -width 2n -offset indent
+.It 0
+All files were processed successfully.
+.It 1
+An error occurred.
+.El
+.Pp
+Whenever
+.Nm
+cannot create a file or a link when reading an archive or cannot
+find a file when writing an archive, or cannot preserve the user ID,
+group ID, or file mode when the
+.Fl p
+option is specified, a diagnostic message is written to standard error
+and a non-zero exit status will be returned, but processing will continue.
+In the case where
+.Nm
+cannot create a link to a file,
+.Nm
+will not create a second copy of the file.
+.Pp
+If the extraction of a file from an archive is prematurely terminated by
+a signal or error,
+.Nm
+may have only partially extracted a file the user wanted.
+Additionally, the file modes of extracted files and directories
+may have incorrect file bits, and the modification and access times may be
+wrong.
+.Pp
+If the creation of an archive is prematurely terminated by a signal or error,
+.Nm
+may have only partially created the archive, which may violate the specific
+archive format specification.
+.Pp
+If while doing a
+.Em copy ,
+.Nm
+detects a file is about to overwrite itself, the file is not copied,
+a diagnostic message is written to standard error
+and when
+.Nm
+completes it will exit with a non-zero exit status.
+.Sh SEE ALSO
+.Xr cpio 1 ,
+.Xr tar 1
+.Pp
+"Archiving with Pax", Dru Lavigne, ONLamp.com BSD DevCenter,
+http://www.onlamp.com/pub/a/bsd/2002/08/22/FreeBSD_Basics.html
+.Pp
+pax(1) manual page,
+http://heirloom.sourceforge.net/man/pax.1.html
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -p1003.1-2004
+specification.
+.Pp
+The flags
+.Op Fl 0BDEGHjLOPTUYZz ,
+the archive formats
+.Em bcpio ,
+.Em sv4cpio ,
+.Em sv4crc ,
+.Em tar ,
+and the flawed archive handling during
+.Em list
+and
+.Em read
+operations
+are extensions to that specification.
+.Sh AUTHORS
+Keith Muller at the University of California, San Diego.
diff --git a/file_cmds/pax/pax.c b/file_cmds/pax/pax.c
new file mode 100644
index 0000000..ec180b7
--- /dev/null
+++ b/file_cmds/pax/pax.c
@@ -0,0 +1,446 @@
+/* $OpenBSD: pax.c,v 1.28 2005/08/04 10:02:44 mpf Exp $ */
+/* $NetBSD: pax.c,v 1.5 1996/03/26 23:54:20 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)pax.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: pax.c,v 1.28 2005/08/04 10:02:44 mpf Exp $";
+#endif
+#endif /* not lint */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <locale.h>
+#include "pax.h"
+#include "extern.h"
+static int gen_init(void);
+
+/*
+ * PAX main routines, general globals and some simple start up routines
+ */
+
+/*
+ * Variables that can be accessed by any routine within pax
+ */
+int act = DEFOP; /* read/write/append/copy */
+const FSUB *frmt = NULL; /* archive format type */
+int cflag; /* match all EXCEPT pattern/file */
+int cwdfd; /* starting cwd */
+int dflag; /* directory member match only */
+int iflag; /* interactive file/archive rename */
+int kflag; /* do not overwrite existing files */
+int lflag; /* use hard links when possible */
+int nflag; /* select first archive member match */
+int tflag; /* restore access time after read */
+int uflag; /* ignore older modification time files */
+int vflag; /* produce verbose output */
+int Dflag; /* same as uflag except inode change time */
+int Hflag; /* follow command line symlinks (write only) */
+int Lflag; /* follow symlinks when writing */
+int Xflag; /* archive files with same device id only */
+int Yflag; /* same as Dflag except after name mode */
+int Zflag; /* same as uflag except after name mode */
+int zeroflag; /* use \0 as pathname terminator */
+int vfpart; /* is partial verbose output in progress */
+int patime = 1; /* preserve file access time */
+int pmtime = 1; /* preserve file modification times */
+int nodirs; /* do not create directories as needed */
+int pmode; /* preserve file mode bits */
+int pids; /* preserve file uid/gid */
+int rmleadslash = 0; /* remove leading '/' from pathnames */
+int secure = 1; /* don't extract names that contain .. */
+int exit_val; /* exit value */
+int docrc; /* check/create file crc */
+char *dirptr; /* destination dir in a copy */
+char *ltmfrmt; /* -v locale time format (if any) */
+char *argv0; /* root of argv[0] */
+sigset_t s_mask; /* signal mask for cleanup critical sect */
+FILE *listf; /* file pointer to print file list to */
+char *tempfile; /* tempfile to use for mkstemp(3) */
+char *tempbase; /* basename of tempfile to use for mkstemp(3) */
+
+/*
+ * PAX - Portable Archive Interchange
+ *
+ * A utility to read, write, and write lists of the members of archive
+ * files and copy directory hierarchies. A variety of archive formats
+ * are supported (some are described in POSIX 1003.1 10.1):
+ *
+ * ustar - 10.1.1 extended tar interchange format
+ * cpio - 10.1.2 extended cpio interchange format
+ * tar - old BSD 4.3 tar format
+ * binary cpio - old cpio with binary header format
+ * sysVR4 cpio - with and without CRC
+ *
+ * This version is a superset of IEEE Std 1003.2b-d3
+ *
+ * Summary of Extensions to the IEEE Standard:
+ *
+ * 1 READ ENHANCEMENTS
+ * 1.1 Operations which read archives will continue to operate even when
+ * processing archives which may be damaged, truncated, or fail to meet
+ * format specs in several different ways. Damaged sections of archives
+ * are detected and avoided if possible. Attempts will be made to resync
+ * archive read operations even with badly damaged media.
+ * 1.2 Blocksize requirements are not strictly enforced on archive read.
+ * Tapes which have variable sized records can be read without errors.
+ * 1.3 The user can specify via the non-standard option flag -E if error
+ * resync operation should stop on a media error, try a specified number
+ * of times to correct, or try to correct forever.
+ * 1.4 Sparse files (lseek holes) stored on the archive (but stored with blocks
+ * of all zeros will be restored with holes appropriate for the target
+ * filesystem
+ * 1.5 The user is notified whenever something is found during archive
+ * read operations which violates spec (but the read will continue).
+ * 1.6 Multiple archive volumes can be read and may span over different
+ * archive devices
+ * 1.7 Rigidly restores all file attributes exactly as they are stored on the
+ * archive.
+ * 1.8 Modification change time ranges can be specified via multiple -T
+ * options. These allow a user to select files whose modification time
+ * lies within a specific time range.
+ * 1.9 Files can be selected based on owner (user name or uid) via one or more
+ * -U options.
+ * 1.10 Files can be selected based on group (group name or gid) via one o
+ * more -G options.
+ * 1.11 File modification time can be checked against existing file after
+ * name modification (-Z)
+ *
+ * 2 WRITE ENHANCEMENTS
+ * 2.1 Write operation will stop instead of allowing a user to create a flawed
+ * flawed archive (due to any problem).
+ * 2.2 Archives written by pax are forced to strictly conform to both the
+ * archive and pax the specific format specifications.
+ * 2.3 Blocking size and format is rigidly enforced on writes.
+ * 2.4 Formats which may exhibit header overflow problems (they have fields
+ * too small for large file systems, such as inode number storage), use
+ * routines designed to repair this problem. These techniques still
+ * conform to both pax and format specifications, but no longer truncate
+ * these fields. This removes any restrictions on using these archive
+ * formats on large file systems.
+ * 2.5 Multiple archive volumes can be written and may span over different
+ * archive devices
+ * 2.6 A archive volume record limit allows the user to specify the number
+ * of bytes stored on an archive volume. When reached the user is
+ * prompted for the next archive volume. This is specified with the
+ * non-standard -B flag. The limit is rounded up to the next blocksize.
+ * 2.7 All archive padding during write use zero filled sections. This makes
+ * it much easier to pull data out of flawed archive during read
+ * operations.
+ * 2.8 Access time reset with the -t applies to all file nodes (including
+ * directories).
+ * 2.9 Symbolic links can be followed with -L (optional in the spec).
+ * 2.10 Modification or inode change time ranges can be specified via
+ * multiple -T options. These allow a user to select files whose
+ * modification or inode change time lies within a specific time range.
+ * 2.11 Files can be selected based on owner (user name or uid) via one or more
+ * -U options.
+ * 2.12 Files can be selected based on group (group name or gid) via one o
+ * more -G options.
+ * 2.13 Symlinks which appear on the command line can be followed (without
+ * following other symlinks; -H flag)
+ *
+ * 3 COPY ENHANCEMENTS
+ * 3.1 Sparse files (lseek holes) can be copied without expanding the holes
+ * into zero filled blocks. The file copy is created with holes which are
+ * appropriate for the target filesystem
+ * 3.2 Access time as well as modification time on copied file trees can be
+ * preserved with the appropriate -p options.
+ * 3.3 Access time reset with the -t applies to all file nodes (including
+ * directories).
+ * 3.4 Symbolic links can be followed with -L (optional in the spec).
+ * 3.5 Modification or inode change time ranges can be specified via
+ * multiple -T options. These allow a user to select files whose
+ * modification or inode change time lies within a specific time range.
+ * 3.6 Files can be selected based on owner (user name or uid) via one or more
+ * -U options.
+ * 3.7 Files can be selected based on group (group name or gid) via one o
+ * more -G options.
+ * 3.8 Symlinks which appear on the command line can be followed (without
+ * following other symlinks; -H flag)
+ * 3.9 File inode change time can be checked against existing file before
+ * name modification (-D)
+ * 3.10 File inode change time can be checked against existing file after
+ * name modification (-Y)
+ * 3.11 File modification time can be checked against existing file after
+ * name modification (-Z)
+ *
+ * 4 GENERAL ENHANCEMENTS
+ * 4.1 Internal structure is designed to isolate format dependent and
+ * independent functions. Formats are selected via a format driver table.
+ * This encourages the addition of new archive formats by only having to
+ * write those routines which id, read and write the archive header.
+ */
+
+/*
+ * main()
+ * parse options, set up and operate as specified by the user.
+ * any operational flaw will set exit_val to non-zero
+ * Return: 0 if ok, 1 otherwise
+ */
+
+int
+main(int argc, char **argv)
+{
+ char *tmpdir;
+ size_t tdlen;
+#ifdef _HAVE_REGCOMP_
+ setlocale(LC_CTYPE, "");
+ setlocale(LC_COLLATE, "");
+#endif
+
+ listf = stderr;
+ /*
+ * Keep a reference to cwd, so we can always come back home.
+ */
+ cwdfd = open(".", O_RDONLY);
+ if (cwdfd < 0) {
+ syswarn(1, errno, "Can't open current working directory.");
+ return(exit_val);
+ }
+
+ if (updatepath() == -1)
+ return exit_val;
+ /*
+ * Where should we put temporary files?
+ */
+ if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
+ tmpdir = _PATH_TMP;
+ tdlen = strlen(tmpdir);
+ while (tdlen > 0 && tmpdir[tdlen - 1] == '/')
+ tdlen--;
+ tempfile = malloc(tdlen + 1 + sizeof(_TFILE_BASE));
+ if (tempfile == NULL) {
+ paxwarn(1, "Cannot allocate memory for temp file name.");
+ return(exit_val);
+ }
+ if (tdlen)
+ memcpy(tempfile, tmpdir, tdlen);
+ tempbase = tempfile + tdlen;
+ *tempbase++ = '/';
+
+ /*
+ * parse options, determine operational mode, general init
+ */
+ options(argc, argv);
+ if ((gen_init() < 0) || (tty_init() < 0))
+ return(exit_val);
+
+ /*
+ * select a primary operation mode
+ */
+ switch (act) {
+ case EXTRACT:
+ extract();
+ break;
+ case ARCHIVE:
+ archive();
+ break;
+ case APPND:
+ if (gzip_program != NULL)
+ errx(1, "can not gzip while appending");
+ append();
+ break;
+ case COPY:
+ copy();
+ break;
+ default:
+ case LIST:
+ list();
+ break;
+ }
+ return(exit_val);
+}
+
+/*
+ * sig_cleanup()
+ * when interrupted we try to do whatever delayed processing we can.
+ * This is not critical, but we really ought to limit our damage when we
+ * are aborted by the user.
+ * Return:
+ * never....
+ */
+
+void
+sig_cleanup(int which_sig)
+{
+ /* XXX signal races */
+
+ /*
+ * restore modes and times for any dirs we may have created
+ * or any dirs we may have read. Set vflag and vfpart so the user
+ * will clearly see the message on a line by itself.
+ */
+ vflag = vfpart = 1;
+ if (which_sig == SIGXCPU)
+ paxwarn(0, "Cpu time limit reached, cleaning up.");
+ else
+ paxwarn(0, "Signal caught, cleaning up.");
+
+ ar_close();
+ proc_dir();
+ if (tflag)
+ atdir_end();
+ exit(1);
+}
+
+/*
+ * gen_init()
+ * general setup routines. Not all are required, but they really help
+ * when dealing with a medium to large sized archives.
+ */
+
+static int
+gen_init(void)
+{
+ struct rlimit reslimit;
+ struct sigaction n_hand;
+ struct sigaction o_hand;
+
+ /*
+ * Really needed to handle large archives. We can run out of memory for
+ * internal tables really fast when we have a whole lot of files...
+ */
+ if (getrlimit(RLIMIT_DATA , &reslimit) == 0){
+ reslimit.rlim_cur = reslimit.rlim_max;
+ (void)setrlimit(RLIMIT_DATA , &reslimit);
+ }
+
+ /*
+ * should file size limits be waived? if the os limits us, this is
+ * needed if we want to write a large archive
+ */
+ if (getrlimit(RLIMIT_FSIZE , &reslimit) == 0){
+ reslimit.rlim_cur = reslimit.rlim_max;
+ (void)setrlimit(RLIMIT_FSIZE , &reslimit);
+ }
+
+ /*
+ * increase the size the stack can grow to
+ */
+ if (getrlimit(RLIMIT_STACK , &reslimit) == 0){
+ reslimit.rlim_cur = reslimit.rlim_max;
+ (void)setrlimit(RLIMIT_STACK , &reslimit);
+ }
+
+ /*
+ * not really needed, but doesn't hurt
+ */
+ if (getrlimit(RLIMIT_RSS , &reslimit) == 0){
+ reslimit.rlim_cur = reslimit.rlim_max;
+ (void)setrlimit(RLIMIT_RSS , &reslimit);
+ }
+
+ /*
+ * Handle posix locale
+ *
+ * set user defines time printing format for -v option
+ */
+ ltmfrmt = getenv("LC_TIME");
+
+ /*
+ * signal handling to reset stored directory times and modes. Since
+ * we deal with broken pipes via failed writes we ignore it. We also
+ * deal with any file size limit through failed writes. Cpu time
+ * limits are caught and a cleanup is forced.
+ */
+ if ((sigemptyset(&s_mask) < 0) || (sigaddset(&s_mask, SIGTERM) < 0) ||
+ (sigaddset(&s_mask,SIGINT) < 0)||(sigaddset(&s_mask,SIGHUP) < 0) ||
+ (sigaddset(&s_mask,SIGPIPE) < 0)||(sigaddset(&s_mask,SIGQUIT)<0) ||
+ (sigaddset(&s_mask,SIGXCPU) < 0)||(sigaddset(&s_mask,SIGXFSZ)<0)) {
+ paxwarn(1, "Unable to set up signal mask");
+ return(-1);
+ }
+ memset(&n_hand, 0, sizeof n_hand);
+ n_hand.sa_mask = s_mask;
+ n_hand.sa_flags = 0;
+ n_hand.sa_handler = sig_cleanup;
+
+ if ((sigaction(SIGHUP, &n_hand, &o_hand) < 0) &&
+ (o_hand.sa_handler == SIG_IGN) &&
+ (sigaction(SIGHUP, &o_hand, &o_hand) < 0))
+ goto out;
+
+ if ((sigaction(SIGTERM, &n_hand, &o_hand) < 0) &&
+ (o_hand.sa_handler == SIG_IGN) &&
+ (sigaction(SIGTERM, &o_hand, &o_hand) < 0))
+ goto out;
+
+ if ((sigaction(SIGINT, &n_hand, &o_hand) < 0) &&
+ (o_hand.sa_handler == SIG_IGN) &&
+ (sigaction(SIGINT, &o_hand, &o_hand) < 0))
+ goto out;
+
+ if ((sigaction(SIGQUIT, &n_hand, &o_hand) < 0) &&
+ (o_hand.sa_handler == SIG_IGN) &&
+ (sigaction(SIGQUIT, &o_hand, &o_hand) < 0))
+ goto out;
+
+ if ((sigaction(SIGXCPU, &n_hand, &o_hand) < 0) &&
+ (o_hand.sa_handler == SIG_IGN) &&
+ (sigaction(SIGXCPU, &o_hand, &o_hand) < 0))
+ goto out;
+
+ n_hand.sa_handler = SIG_IGN;
+ if ((sigaction(SIGPIPE, &n_hand, &o_hand) < 0) ||
+ (sigaction(SIGXFSZ, &n_hand, &o_hand) < 0))
+ goto out;
+ return(0);
+
+ out:
+ syswarn(1, errno, "Unable to set up signal handler");
+ return(-1);
+}
diff --git a/file_cmds/pax/pax.h b/file_cmds/pax/pax.h
new file mode 100644
index 0000000..1caff0c
--- /dev/null
+++ b/file_cmds/pax/pax.h
@@ -0,0 +1,255 @@
+/* $OpenBSD: pax.h,v 1.17 2005/11/09 19:59:06 otto Exp $ */
+/* $NetBSD: pax.h,v 1.3 1995/03/21 09:07:41 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pax.h 8.2 (Berkeley) 4/18/94
+ */
+
+#ifndef _PAX_H_
+#define _PAX_H_
+
+/*
+ * BSD PAX global data structures and constants.
+ */
+
+#define MAXBLK 64512 /* MAX blocksize supported (posix SPEC) */
+ /* WARNING: increasing MAXBLK past 32256 */
+ /* will violate posix spec. */
+#define MAXBLK_POSIX 32256 /* MAX blocksize supported as per POSIX */
+#define BLKMULT 512 /* blocksize must be even mult of 512 bytes */
+ /* Don't even think of changing this */
+#define DEVBLK 8192 /* default read blksize for devices */
+#define FILEBLK 10240 /* default read blksize for files */
+#define PAXPATHLEN 3072 /* maximum path length for pax. MUST be */
+ /* longer than the system MAXPATHLEN */
+
+/*
+ * Pax modes of operation
+ */
+#define LIST 0 /* List the file in an archive */
+#define EXTRACT 1 /* extract the files in an archive */
+#define ARCHIVE 2 /* write a new archive */
+#define APPND 3 /* append to the end of an archive */
+#define COPY 4 /* copy files to destination dir */
+#define DEFOP LIST /* if no flags default is to LIST */
+
+/*
+ * Device type of the current archive volume
+ */
+#define ISREG 0 /* regular file */
+#define ISCHR 1 /* character device */
+#define ISBLK 2 /* block device */
+#define ISTAPE 3 /* tape drive */
+#define ISPIPE 4 /* pipe/socket */
+
+/*
+ * Pattern matching structure
+ *
+ * Used to store command line patterns
+ */
+typedef struct pattern {
+ char *pstr; /* pattern to match, user supplied */
+ char *pend; /* end of a prefix match */
+ char *chdname; /* the dir to change to if not NULL. */
+ int plen; /* length of pstr */
+ int flgs; /* processing/state flags */
+#define MTCH 0x1 /* pattern has been matched */
+#define DIR_MTCH 0x2 /* pattern matched a directory */
+ struct pattern *fow; /* next pattern */
+} PATTERN;
+
+/*
+ * General Archive Structure (used internal to pax)
+ *
+ * This structure is used to pass information about archive members between
+ * the format independent routines and the format specific routines. When
+ * new archive formats are added, they must accept requests and supply info
+ * encoded in a structure of this type. The name fields are declared statically
+ * here, as there is only ONE of these floating around, size is not a major
+ * consideration. Eventually converting the name fields to a dynamic length
+ * may be required if and when the supporting operating system removes all
+ * restrictions on the length of pathnames it will resolve.
+ */
+typedef struct {
+ int nlen; /* file name length */
+ char name[PAXPATHLEN+1]; /* file name */
+ int ln_nlen; /* link name length */
+ char ln_name[PAXPATHLEN+1]; /* name to link to (if any) */
+ char *org_name; /* orig name in file system */
+ PATTERN *pat; /* ptr to pattern match (if any) */
+ struct stat sb; /* stat buffer see stat(2) */
+ off_t pad; /* bytes of padding after file xfer */
+ off_t skip; /* bytes of real data after header */
+ /* IMPORTANT. The st_size field does */
+ /* not always indicate the amount of */
+ /* data following the header. */
+ u_int32_t crc; /* file crc */
+ int type; /* type of file node */
+#define PAX_DIR 1 /* directory */
+#define PAX_CHR 2 /* character device */
+#define PAX_BLK 3 /* block device */
+#define PAX_REG 4 /* regular file */
+#define PAX_SLK 5 /* symbolic link */
+#define PAX_SCK 6 /* socket */
+#define PAX_FIF 7 /* fifo */
+#define PAX_HLK 8 /* hard link */
+#define PAX_HRG 9 /* hard link to a regular file */
+#define PAX_CTG 10 /* high performance file */
+#define PAX_GLL 11 /* GNU long symlink */
+#define PAX_GLF 12 /* GNU long file */
+} ARCHD;
+
+/*
+ * Format Specific Routine Table
+ *
+ * The format specific routine table allows new archive formats to be quickly
+ * added. Overall pax operation is independent of the actual format used to
+ * form the archive. Only those routines which deal directly with the archive
+ * are tailored to the oddities of the specific format. All other routines are
+ * independent of the archive format. Data flow in and out of the format
+ * dependent routines pass pointers to ARCHD structure (described below).
+ */
+typedef struct {
+ char *name; /* name of format, this is the name the user */
+ /* gives to -x option to select it. */
+ int bsz; /* default block size. used when the user */
+ /* does not specify a blocksize for writing */
+ /* Appends continue to with the blocksize */
+ /* the archive is currently using. */
+ int hsz; /* Header size in bytes. this is the size of */
+ /* the smallest header this format supports. */
+ /* Headers are assumed to fit in a BLKMULT. */
+ /* If they are bigger, get_head() and */
+ /* get_arc() must be adjusted */
+ int udev; /* does append require unique dev/ino? some */
+ /* formats use the device and inode fields */
+ /* to specify hard links. when members in */
+ /* the archive have the same inode/dev they */
+ /* are assumed to be hard links. During */
+ /* append we may have to generate unique ids */
+ /* to avoid creating incorrect hard links */
+ int hlk; /* does archive store hard links info? if */
+ /* not, we do not bother to look for them */
+ /* during archive write operations */
+ int blkalgn; /* writes must be aligned to blkalgn boundary */
+ int inhead; /* is the trailer encoded in a valid header? */
+ /* if not, trailers are assumed to be found */
+ /* in invalid headers (i.e like tar) */
+ int (*id)(char *, /* checks if a buffer is a valid header */
+ int); /* returns 1 if it is, o.w. returns a 0 */
+ int (*st_rd)(void); /* initialize routine for read. so format */
+ /* can set up tables etc before it starts */
+ /* reading an archive */
+ int (*rd)(ARCHD *, /* read header routine. passed a pointer to */
+ char *); /* ARCHD. It must extract the info from the */
+ /* format and store it in the ARCHD struct. */
+ /* This routine is expected to fill all the */
+ /* fields in the ARCHD (including stat buf) */
+ /* 0 is returned when a valid header is */
+ /* found. -1 when not valid. This routine */
+ /* set the skip and pad fields so the format */
+ /* independent routines know the amount of */
+ /* padding and the number of bytes of data */
+ /* which follow the header. This info is */
+ /* used skip to the next file header */
+ off_t (*end_rd)(void); /* read cleanup. Allows format to clean up */
+ /* and MUST RETURN THE LENGTH OF THE TRAILER */
+ /* RECORD (so append knows how many bytes */
+ /* to move back to rewrite the trailer) */
+ int (*st_wr)(void); /* initialize routine for write operations */
+ int (*wr)(ARCHD *); /* write archive header. Passed an ARCHD */
+ /* filled with the specs on the next file to */
+ /* archived. Returns a 1 if no file data is */
+ /* is to be stored; 0 if file data is to be */
+ /* added. A -1 is returned if a write */
+ /* operation to the archive failed. this */
+ /* function sets the skip and pad fields so */
+ /* the proper padding can be added after */
+ /* file data. This routine must NEVER write */
+ /* a flawed archive header. */
+ int (*end_wr)(void); /* end write. write the trailer and do any */
+ /* other format specific functions needed */
+ /* at the end of an archive write */
+ int (*trail)(ARCHD *, /* returns 0 if a valid trailer, -1 if not */
+ char *, int, /* For formats which encode the trailer */
+ int *); /* outside of a valid header, a return value */
+ /* of 1 indicates that the block passed to */
+ /* it can never contain a valid header (skip */
+ /* this block, no point in looking at it) */
+ /* CAUTION: parameters to this function are */
+ /* different for trailers inside or outside */
+ /* of headers. See get_head() for details */
+ int (*rd_data)(ARCHD *, /* read/process file data from the archive */
+ int, off_t *);
+ int (*wr_data)(ARCHD *, /* write/process file data to the archive */
+ int, off_t *);
+ int (*options)(void); /* process format specific options (-o) */
+} FSUB;
+
+/*
+ * Format Specific Options List
+ *
+ * Used to pass format options to the format options handler
+ */
+typedef struct oplist {
+ char *name; /* option variable name e.g. name= */
+ char *value; /* value for option variable */
+ struct oplist *fow; /* next option */
+ int separator; /* 2 means := separator; 1 means = separator
+ 0 means no separator */
+} OPLIST;
+#define SEP_COLONEQ 2
+#define SEP_EQ 1
+#define SEP_NONE 0
+
+/*
+ * General Macros
+ */
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+#define MAJOR(x) major(x)
+#define MINOR(x) minor(x)
+#define TODEV(x, y) makedev((x), (y))
+
+/*
+ * General Defines
+ */
+#define HEX 16
+#define OCT 8
+#define _PAX_ 1
+#define _HAVE_REGCOMP_ 1
+#define _TFILE_BASE "paxXXXXXXXXXX"
+
+#endif /* _PAX_H_ */
diff --git a/file_cmds/pax/pax_format.c b/file_cmds/pax/pax_format.c
new file mode 100644
index 0000000..fbacdff
--- /dev/null
+++ b/file_cmds/pax/pax_format.c
@@ -0,0 +1,1624 @@
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94";
+#else
+static const char rcsid[] __attribute__((__unused__)) = "$OpenBSD: tar.c,v 1.34 2004/10/23 19:34:14 otto Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "extern.h"
+#include "tar.h"
+#include <fnmatch.h>
+#include <regex.h>
+#include "pat_rep.h"
+#include <errno.h>
+
+/*
+ * This file implements the -x pax format support; it is incomplete.
+ * Known missing features include:
+ * many -o options for "copy" mode are not implemented (only path=)
+ * many format specifiers for -o listopt are not implemented
+ * -o listopt option should work for all archive formats, not just -x pax
+ * This file was originally derived from the file tar.c. You should
+ * 'diff' it to that file to see how much of the -x pax format has been implemented.
+ */
+
+char pax_eh_datablk[4*1024];
+int pax_read_or_list_mode = 0;
+int want_a_m_time_headers = 0;
+int want_linkdata = 0;
+
+int pax_invalid_action = 0;
+char * pax_invalid_action_write_path = NULL;
+char * pax_invalid_action_write_cwd = NULL;
+
+char
+ *path_g, *path_x, *path_g_current, *path_x_current,
+ *uname_g, *uname_x, *uname_g_current, *uname_x_current,
+ *gname_g, *gname_x, *gname_g_current, *gname_x_current,
+ *comment_g, *comment_x, *comment_g_current, *comment_x_current,
+ *charset_g, *charset_x, *charset_g_current, *charset_x_current,
+ *atime_g, *atime_x, *atime_g_current, *atime_x_current,
+ *gid_g, *gid_x, *gid_g_current, *gid_x_current,
+ *linkpath_g, *linkpath_x, *linkpath_g_current, *linkpath_x_current,
+ *mtime_g, *mtime_x, *mtime_g_current, *mtime_x_current,
+ *size_g, *size_x, *size_g_current, *size_x_current,
+ *uid_g, *uid_x, *uid_g_current, *uid_x_current;
+
+char *header_name_g_requested = NULL,
+ *header_name_x_requested = NULL;
+
+char *header_name_g = "/tmp/GlobalHead.%p.%n",
+ *header_name_x = "%d/PaxHeaders.%p/%f";
+
+int nglobal_headers = 0;
+char *pax_list_opt_format;
+
+#define O_OPTION_ACTION_NOTIMPL 0
+#define O_OPTION_ACTION_INVALID 1
+#define O_OPTION_ACTION_DELETE 2
+#define O_OPTION_ACTION_STORE_HEADER 3
+#define O_OPTION_ACTION_TIMES 4
+#define O_OPTION_ACTION_HEADER_NAME 5
+#define O_OPTION_ACTION_LISTOPT 6
+#define O_OPTION_ACTION_LINKDATA 7
+
+#define O_OPTION_ACTION_IGNORE 8
+#define O_OPTION_ACTION_ERROR 9
+#define O_OPTION_ACTION_STORE_HEADER2 10
+
+#define ATTRSRC_FROM_NOWHERE 0
+#define ATTRSRC_FROM_X_O_OPTION 1
+#define ATTRSRC_FROM_G_O_OPTION 2
+#define ATTRSRC_FROM_X_HEADER 3
+#define ATTRSRC_FROM_G_HEADER 4
+
+#define KW_PATH_CASE 0
+#define KW_SKIP_CASE -1
+#define KW_ATIME_CASE -2
+
+typedef struct {
+ char * name;
+ int len;
+ int active; /* 1 means active, 0 means deleted via -o delete= */
+ int cmdline_action;
+ int header_action;
+ /* next 2 entries only used by store_header actions */
+ char ** g_value; /* -o keyword= value */
+ char ** x_value; /* -o keyword:= value */
+ char ** g_value_current; /* keyword= value found in Global extended header */
+ char ** x_value_current; /* keyword= value found in extended header */
+ int header_inx; /* starting index of header field this keyword represents */
+ int header_len; /* length of header field this keyword represents */
+ /* If negative, special cases line path= */
+} O_OPTION_TYPE;
+
+O_OPTION_TYPE o_option_table[] = {
+ { "atime", 5, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
+ &atime_g, &atime_x, &atime_g_current, &atime_x_current, 0, KW_ATIME_CASE },
+ { "charset", 7, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_IGNORE,
+ &charset_g, &charset_x, &charset_g_current, &charset_x_current, 0, KW_SKIP_CASE },
+ { "comment", 7, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_IGNORE,
+ &comment_g, &comment_x, &comment_g_current, &comment_x_current, 0, KW_SKIP_CASE },
+ { "gid", 3, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2,
+ &gid_g, &gid_x, &gid_g_current, &gid_x_current , 116, 8 },
+ { "gname", 5, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2,
+ &gname_g, &gname_x, &gname_g_current, &gname_x_current, 297, 32 },
+ { "linkpath", 8, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
+ &linkpath_g, &linkpath_x, &linkpath_g_current, &linkpath_x_current, 0, KW_SKIP_CASE },
+ { "mtime", 5, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
+ &mtime_g, &mtime_x, &mtime_g_current, &mtime_x_current, 136, KW_SKIP_CASE },
+ { "path", 4, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
+ &path_g, &path_x, &path_g_current, &path_x_current, 0, KW_PATH_CASE },
+ { "size", 4, 1, O_OPTION_ACTION_STORE_HEADER, O_OPTION_ACTION_STORE_HEADER,
+ &size_g, &size_x, &size_g_current, &size_x_current, 124, KW_SKIP_CASE },
+ { "uid", 3, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2,
+ &uid_g, &uid_x, &uid_g_current, &uid_x_current, 108, 8 },
+ { "uname", 5, 1, O_OPTION_ACTION_STORE_HEADER2, O_OPTION_ACTION_STORE_HEADER2,
+ &uname_g, &uname_x, &uname_g_current, &uname_x_current, 265, 32 },
+
+ { "exthdr.name", 11, 1, O_OPTION_ACTION_HEADER_NAME, O_OPTION_ACTION_ERROR,
+ &header_name_x, &header_name_x_requested, NULL, NULL, 0, KW_SKIP_CASE },
+ { "globexthdr.name", 15, 1, O_OPTION_ACTION_HEADER_NAME, O_OPTION_ACTION_ERROR,
+ &header_name_g, &header_name_g_requested, NULL, NULL, 0, KW_SKIP_CASE },
+
+ { "delete", 6, 1, O_OPTION_ACTION_DELETE, O_OPTION_ACTION_ERROR,
+ NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE },
+ { "invalid", 7, 1, O_OPTION_ACTION_INVALID, O_OPTION_ACTION_ERROR,
+ NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE },
+ { "linkdata", 8, 1, O_OPTION_ACTION_LINKDATA, O_OPTION_ACTION_ERROR,
+ NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE }, /* Test 241 */
+ { "listopt", 7, 1, O_OPTION_ACTION_LISTOPT, O_OPTION_ACTION_ERROR,
+ &pax_list_opt_format, NULL, NULL, NULL, 0, KW_SKIP_CASE }, /* Test 242 */
+ /* Note: listopt is supposed to apply for all formats, not just -x pax only */
+ { "times", 5, 1, O_OPTION_ACTION_TIMES, O_OPTION_ACTION_ERROR,
+ NULL, NULL, NULL, NULL, 0, KW_SKIP_CASE },
+};
+
+int ext_header_inx,
+ global_ext_header_inx;
+
+/* Make these tables big enough to handle lots of -o options, not just one per table entry */
+int ext_header_entry [4*sizeof(o_option_table)/sizeof(O_OPTION_TYPE)],
+ global_ext_header_entry[4*sizeof(o_option_table)/sizeof(O_OPTION_TYPE)];
+
+/*
+ * Routines for reading, writing and header identify of various versions of pax
+ */
+
+static size_t expandname(char *, size_t, char **, const char *, size_t);
+static u_long pax_chksm(char *, int);
+static char *name_split(char *, int);
+static int ul_oct(u_long, char *, int, int);
+#ifndef LONG_OFF_T
+static int uqd_oct(u_quad_t, char *, int, int);
+#endif
+
+static uid_t uid_nobody;
+static uid_t uid_warn;
+static gid_t gid_nobody;
+static gid_t gid_warn;
+
+/*
+ * Routines common to all versions of pax
+ */
+
+/*
+ * ul_oct()
+ * convert an unsigned long to an octal string. many oddball field
+ * termination characters are used by the various versions of tar in the
+ * different fields. term selects which kind to use. str is '0' padded
+ * at the front to len. we are unable to use only one format as many old
+ * tar readers are very cranky about this.
+ * Return:
+ * 0 if the number fit into the string, -1 otherwise
+ */
+
+static int
+ul_oct(u_long val, char *str, int len, int term)
+{
+ char *pt;
+
+ /*
+ * term selects the appropriate character(s) for the end of the string
+ */
+ pt = str + len - 1;
+ switch (term) {
+ case 3:
+ *pt-- = '\0';
+ break;
+ case 2:
+ *pt-- = ' ';
+ *pt-- = '\0';
+ break;
+ case 1:
+ *pt-- = ' ';
+ break;
+ case 0:
+ default:
+ *pt-- = '\0';
+ *pt-- = ' ';
+ break;
+ }
+
+ /*
+ * convert and blank pad if there is space
+ */
+ while (pt >= str) {
+ *pt-- = '0' + (char)(val & 0x7);
+ if ((val = val >> 3) == (u_long)0)
+ break;
+ }
+
+ while (pt >= str)
+ *pt-- = '0';
+ if (val != (u_long)0)
+ return(-1);
+ return(0);
+}
+
+#ifndef LONG_OFF_T
+/*
+ * uqd_oct()
+ * convert an u_quad_t to an octal string. one of many oddball field
+ * termination characters are used by the various versions of tar in the
+ * different fields. term selects which kind to use. str is '0' padded
+ * at the front to len. we are unable to use only one format as many old
+ * tar readers are very cranky about this.
+ * Return:
+ * 0 if the number fit into the string, -1 otherwise
+ */
+
+static int
+uqd_oct(u_quad_t val, char *str, int len, int term)
+{
+ char *pt;
+
+ /*
+ * term selects the appropriate character(s) for the end of the string
+ */
+ pt = str + len - 1;
+ switch (term) {
+ case 3:
+ *pt-- = '\0';
+ break;
+ case 2:
+ *pt-- = ' ';
+ *pt-- = '\0';
+ break;
+ case 1:
+ *pt-- = ' ';
+ break;
+ case 0:
+ default:
+ *pt-- = '\0';
+ *pt-- = ' ';
+ break;
+ }
+
+ /*
+ * convert and blank pad if there is space
+ */
+ while (pt >= str) {
+ *pt-- = '0' + (char)(val & 0x7);
+ if ((val = val >> 3) == 0)
+ break;
+ }
+
+ while (pt >= str)
+ *pt-- = '0';
+ if (val != (u_quad_t)0)
+ return(-1);
+ return(0);
+}
+#endif
+
+/*
+ * pax_chksm()
+ * calculate the checksum for a pax block counting the checksum field as
+ * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).
+ * NOTE: we use len to short circuit summing 0's on write since we ALWAYS
+ * pad headers with 0.
+ * Return:
+ * unsigned long checksum
+ */
+
+static u_long
+pax_chksm(char *blk, int len)
+{
+ char *stop;
+ char *pt;
+ u_long chksm = BLNKSUM; /* initial value is checksum field sum */
+
+ /*
+ * add the part of the block before the checksum field
+ */
+ pt = blk;
+ stop = blk + CHK_OFFSET;
+ while (pt < stop)
+ chksm += (u_long)(*pt++ & 0xff);
+ /*
+ * move past the checksum field and keep going, spec counts the
+ * checksum field as the sum of 8 blanks (which is pre-computed as
+ * BLNKSUM).
+ * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
+ * starts, no point in summing zero's)
+ */
+ pt += CHK_LEN;
+ stop = blk + len;
+ while (pt < stop)
+ chksm += (u_long)(*pt++ & 0xff);
+ return(chksm);
+}
+
+void
+pax_format_list_output(ARCHD *arcn, time_t now, FILE *fp, int term)
+{
+ /* parse specified listopt format */
+ char *nextpercent, *nextchar;
+ char buf[4*1024];
+ int pos, cpylen;
+ char *fname;
+
+ nextpercent = strchr(pax_list_opt_format,'%');
+ if (nextpercent==NULL) {
+ /* Strange case: no specifiers? */
+ safe_print(pax_list_opt_format, fp);
+ (void)putc(term, fp);
+ (void)fflush(fp);
+ return;
+ }
+ pos = nextpercent-pax_list_opt_format;
+ memcpy(buf,pax_list_opt_format, pos);
+ while (nextpercent++) {
+ switch (*nextpercent) {
+ case 'F':
+ fname = arcn->name;
+ cpylen = strlen(fname);
+ memcpy(&buf[pos],fname,cpylen);
+ pos+= cpylen;
+ break;
+ case 'D':
+ case 'T':
+ case 'M':
+ case 'L':
+ default:
+ paxwarn(1, "Unimplemented listopt format: %c",*nextpercent);
+ break;
+ }
+ nextpercent++;
+ if (*nextpercent=='\0') {
+ break;
+ }
+ nextchar = nextpercent;
+ nextpercent = strchr(nextpercent,'%');
+ if (nextpercent==NULL) {
+ cpylen = strlen(nextchar);
+ } else {
+ cpylen = nextpercent - nextchar;
+ }
+ memcpy(&buf[pos],nextchar, cpylen);
+ pos += cpylen;
+ }
+ buf[pos]='\0';
+ safe_print(&buf[0], fp);
+ (void)putc(term, fp);
+ (void)fflush(fp);
+ return;
+}
+
+void
+cleanup_pax_invalid_action()
+{
+ switch (pax_invalid_action) {
+ case PAX_INVALID_ACTION_BYPASS:
+ case PAX_INVALID_ACTION_RENAME:
+ break;
+ case PAX_INVALID_ACTION_WRITE:
+ pax_invalid_action_write_path = NULL;
+ if (pax_invalid_action_write_cwd) {
+ free(pax_invalid_action_write_cwd);
+ pax_invalid_action_write_cwd = NULL;
+ }
+ break;
+ case PAX_INVALID_ACTION_UTF8:
+ default:
+ paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action);
+ }
+}
+
+void
+record_pax_invalid_action_results(ARCHD * arcn, char * fixed_path)
+{
+ switch (pax_invalid_action) {
+ case PAX_INVALID_ACTION_BYPASS:
+ case PAX_INVALID_ACTION_RENAME:
+ break;
+ case PAX_INVALID_ACTION_WRITE:
+ pax_invalid_action_write_path = fixed_path;
+ pax_invalid_action_write_cwd = strdup(arcn->name);
+ pax_invalid_action_write_cwd[fixed_path-arcn->name-1] = '\0';
+ break;
+ case PAX_INVALID_ACTION_UTF8:
+ default:
+ paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action);
+ }
+}
+
+int
+perform_pax_invalid_action(ARCHD * arcn, int err)
+{
+ int rc = 0;
+ switch (pax_invalid_action) {
+ case PAX_INVALID_ACTION_BYPASS:
+ rc = -1;
+ break;
+ case PAX_INVALID_ACTION_RENAME:
+ rc = tty_rename(arcn);
+ break;
+ case PAX_INVALID_ACTION_WRITE:
+ pax_invalid_action_write_path = NULL;
+ pax_invalid_action_write_cwd = NULL;
+ rc = 2;
+ break;
+ case PAX_INVALID_ACTION_UTF8:
+ default:
+ paxwarn(1, "pax_invalid_action not implemented:%d", pax_invalid_action);
+ rc = -1; /* do nothing? */
+ }
+ return rc;
+}
+
+static void
+delete_keywords(char * pattern)
+{
+ int i;
+ /* loop over all keywords, marking any matched as deleted */
+ for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
+ if (fnmatch(pattern, o_option_table[i].name, 0) == 0) {
+ /* Found option: mark deleted */
+ o_option_table[i].active = 0;
+ }
+ }
+}
+
+/*
+ * pax_opt()
+ * handle pax format specific -o options
+ * Return:
+ * 0 if ok -1 otherwise
+ */
+
+int
+pax_opt(void)
+{
+ OPLIST *opt;
+ int got_option = 0;
+
+ while ((opt = opt_next()) != NULL) {
+ int i;
+ got_option = -1;
+ pax_invalid_action = PAX_INVALID_ACTION_BYPASS; /* Default for pax format */
+ /* look up opt->name */
+ for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
+ if (strncasecmp(opt->name, o_option_table[i].name, o_option_table[i].len) == 0) {
+ /* Found option: see if already set */
+ /* Save it away */
+ got_option = 1;
+ switch (o_option_table[i].cmdline_action) {
+ case O_OPTION_ACTION_INVALID:
+ if (opt->separator != SEP_EQ) {
+ paxwarn(1,"-o %s= option requires '=' separator: option ignored",
+ opt->name);
+ break;
+ }
+ if (opt->value) {
+ if (strncasecmp(opt->value,"bypass",6) == 0) {
+ pax_invalid_action = PAX_INVALID_ACTION_BYPASS;
+ } else if (strncasecmp(opt->value,"rename",6) == 0) {
+ pax_invalid_action = PAX_INVALID_ACTION_RENAME;
+ } else if (strncasecmp(opt->value,"UTF-8",5) == 0) {
+ pax_invalid_action = PAX_INVALID_ACTION_UTF8;
+ } else if (strncasecmp(opt->value,"write",5) == 0) {
+ pax_invalid_action = PAX_INVALID_ACTION_WRITE;
+ } else {
+ paxwarn(1,"Invalid action %s not recognized: option ignored",
+ opt->value);
+ }
+ } else {
+ paxwarn(1,"Invalid action RHS not specified: option ignored");
+ }
+ break;
+ case O_OPTION_ACTION_DELETE:
+ if (opt->separator != SEP_EQ) {
+ paxwarn(1,"-o %s= option requires '=' separator: option ignored",
+ opt->name);
+ break;
+ }
+ /* Mark all matches as deleted */
+ /* can have multiple -o delete= patterns */
+ delete_keywords(opt->value);
+ break;
+ case O_OPTION_ACTION_STORE_HEADER2:
+ if(pax_read_or_list_mode) pids = 1; /* Force -p o for these options */
+ case O_OPTION_ACTION_STORE_HEADER:
+ if (o_option_table[i].g_value == NULL ||
+ o_option_table[i].x_value == NULL ) {
+ paxwarn(1,"-o option not implemented: %s=%s",
+ opt->name, opt->value);
+ } else {
+ if (opt->separator == SEP_EQ) {
+ *(o_option_table[i].g_value) = opt->value;
+ global_ext_header_entry[global_ext_header_inx++] = i;
+ } else if (opt->separator == SEP_COLONEQ ) {
+ *(o_option_table[i].x_value) = opt->value;
+ ext_header_entry [ext_header_inx++] = i;
+ } else { /* SEP_NONE */
+ paxwarn(1,"-o %s option is missing value", opt->name);
+ }
+ }
+ break;
+ case O_OPTION_ACTION_TIMES:
+ if (opt->separator != SEP_NONE) {
+ paxwarn(1,"-o %s option takes no value: option ignored", opt->name);
+ break;
+ }
+ want_a_m_time_headers = 1;
+ break;
+ case O_OPTION_ACTION_LINKDATA:
+ if (opt->separator != SEP_NONE) {
+ paxwarn(1,"-o %s option takes no value: option ignored", opt->name);
+ break;
+ }
+ want_linkdata = 1;
+ break;
+ case O_OPTION_ACTION_HEADER_NAME:
+ if (opt->separator != SEP_EQ) {
+ paxwarn(1,"-o %s= option requires '=' separator: option ignored",
+ opt->name);
+ break;
+ }
+ *(o_option_table[i].g_value) = opt->value;
+ *(o_option_table[i].x_value) = "YES";
+ break;
+ case O_OPTION_ACTION_LISTOPT:
+ if (opt->separator != SEP_EQ) {
+ paxwarn(1,"-o %s= option requires '=' separator: option ignored",
+ opt->name);
+ break;
+ }
+ *(o_option_table[i].g_value) = opt->value;
+ break;
+ case O_OPTION_ACTION_NOTIMPL:
+ default:
+ paxwarn(1,"pax format -o option not yet implemented: %s=%s",
+ opt->name, opt->value);
+ break;
+ }
+ break;
+ }
+ }
+ if (got_option == -1) {
+ paxwarn(1,"pax format -o option not recognized: %s=%s",
+ opt->name, opt->value);
+ }
+ }
+ return(0);
+}
+
+static int
+expand_extended_headers(ARCHD *arcn, HD_USTAR *hd)
+{
+ char mybuf[BLKMULT];
+ HD_USTAR *myhd;
+ char * current_value;
+ int path_replaced = 0;
+ int i, len;
+
+ myhd = hd;
+ while (myhd->typeflag == PAXGTYPE || myhd->typeflag == PAXXTYPE) {
+ char *name, *str;
+ int size, nbytes, inx;
+ size = asc_ul(myhd->size, sizeof(myhd->size), OCT);
+ if (size > sizeof(mybuf)) {
+ paxwarn(1,"extended header buffer overflow");
+ exit(1);
+ }
+ nbytes = rd_wrbuf(mybuf, size);
+ if (nbytes != size) {
+ paxwarn(1,"extended header data read failure: nbytes=%d, size=%d\n",
+ nbytes, size);
+ exit(1);
+ }
+ /*
+ printf("Read 1 extended header: type=%c, size=%d\n",
+ myhd->typeflag, size);
+ */
+ inx=0;
+ /* loop over buffer collecting attributes */
+ while (nbytes > 0) {
+ int got_option = -1;
+ int nentries = sscanf(&mybuf[inx],"%d ", &len);
+ if (nentries != 1) {
+ paxwarn(1,"Extended header failure: length");
+ exit(1);
+ }
+ if (len < 0 || (inx+len-1 >= sizeof(mybuf))) {
+ paxwarn(1, "Extended header failure: invalid length (%d)", len);
+ exit(1);
+ }
+ if (mybuf[inx+len-1] != '\n') {
+ paxwarn(1,"Extended header failure: missed newline");
+ exit(1);
+ } else
+ mybuf[inx+len-1] = '\0';
+ name = strchr(&mybuf[inx],' ');
+ if (name) name++;
+ else {
+ paxwarn(1,"Extended header failure: missing space");
+ exit(1);
+ }
+ str = strchr(name,'=');
+ if (str) {
+ *str++='\0'; /* end of name */
+ } else {
+ paxwarn(1,"Extended header failure: missing RHS string");
+ exit(1);
+ }
+ for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
+ if (strncasecmp(name, o_option_table[i].name, o_option_table[i].len) == 0) {
+ /* Found option: see if already set TBD */
+ /* Save it away */
+ got_option = i;
+ break;
+ }
+ }
+ if (got_option == -1) {
+ paxwarn(1,"Unrecognized header keyword: %s",name);
+ } else {
+ /* Determine precedence of -o and header attributes */
+ int found_value = ATTRSRC_FROM_NOWHERE;
+ current_value = NULL;
+ if (myhd->typeflag == PAXXTYPE) {
+ if (*o_option_table[got_option].x_value) {
+ current_value = *o_option_table[got_option].x_value;
+ found_value = ATTRSRC_FROM_X_O_OPTION;
+ } else {
+ current_value = str;
+ found_value = ATTRSRC_FROM_X_HEADER;
+ }
+ } else if (myhd->typeflag == PAXGTYPE) {
+ if (*o_option_table[got_option].g_value) {
+ current_value = *o_option_table[got_option].g_value;
+ found_value = ATTRSRC_FROM_G_O_OPTION;
+ } else {
+ current_value = str;
+ found_value = ATTRSRC_FROM_G_HEADER;
+ }
+ } else {
+ paxwarn(1,"Unsupported header type:%c",myhd->typeflag);
+ }
+ if (current_value) {
+ /* Save this attribute value for use later */
+ switch (o_option_table[got_option].header_action) {
+ case O_OPTION_ACTION_IGNORE:
+ paxwarn(1,"ignoring header keyword: %s",name);
+ break;
+ case O_OPTION_ACTION_STORE_HEADER2:
+ case O_OPTION_ACTION_STORE_HEADER:
+ switch (found_value) {
+ case ATTRSRC_FROM_NOWHERE: /* shouldn't happen */
+ paxwarn(1, "internal error: value from nowhere");
+ break;
+ case ATTRSRC_FROM_X_O_OPTION:
+ case ATTRSRC_FROM_G_O_OPTION:
+ break;
+ case ATTRSRC_FROM_X_HEADER:
+ current_value = strdup(current_value);
+ if(*o_option_table[got_option].x_value_current)
+ free(*o_option_table[got_option].x_value_current);
+ *o_option_table[got_option].x_value_current = current_value;
+ break;
+ case ATTRSRC_FROM_G_HEADER:
+ current_value = strdup(current_value);
+ if(*o_option_table[got_option].g_value_current)
+ free(*o_option_table[got_option].g_value_current);
+ *o_option_table[got_option].g_value_current = current_value;
+ break;
+ }
+ break;
+ case O_OPTION_ACTION_ERROR:
+ default:
+ paxwarn(1,"Unsupported extended header attribute: %s=%s",
+ name, str);
+ }
+ }
+ }
+ inx+=len;
+ nbytes -= len;
+ }
+
+ /* position file at next header */
+ (void)rd_skip(TAR_PAD(size));
+
+ /* read next header */
+ nbytes = rd_wrbuf(mybuf, frmt->hsz);
+ if (nbytes != frmt->hsz) {
+ paxwarn(1,"extended header read failure: nbytes=%d, size=%d\n",
+ nbytes, frmt->hsz);
+ }
+ myhd = ((HD_USTAR *)mybuf);
+ /* repeat until no more extended headers */
+ }
+
+ /* The header about to be returned must now be updated using all the extended
+ header values collected and any command line options */
+ /* Acceleration: check during command option processing. If there are no -o
+ options, and no changes from any header, do not need to run through this loop. */
+
+ for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
+ int header_len, free_it;
+ if (!o_option_table[i].active) {
+ continue; /* deleted keywords */
+ }
+ header_len = o_option_table[i].header_len;
+ if (header_len == KW_SKIP_CASE) {
+ continue;
+ }
+ free_it = 0;
+ /* Calculate values for all non-skip keywords */
+ current_value = NULL;
+ if (o_option_table[i].x_value) {
+ current_value = *o_option_table[i].x_value;
+ }
+ if (!current_value) { /* No -o := */
+ if (o_option_table[i].x_value_current) {
+ current_value = *o_option_table[i].x_value_current;
+ }
+ if (current_value) {
+ /* Must remove it: x header values not valid beyond this header */
+ *o_option_table[i].x_value_current = NULL;
+ free_it = 1;
+ } else { /* No x values, try globals */
+ current_value = *o_option_table[i].g_value;
+ if (!current_value) {
+ current_value = *o_option_table[i].g_value_current;
+ }
+ }
+ }
+ if (current_value) {
+ /* Update current header with this value */
+ /*
+ printf ("Found current_value:%s for %s, pids=%d\n",
+ current_value, o_option_table[i].name, pids);
+ */
+ len = strlen(current_value);
+ if (header_len == KW_ATIME_CASE) {
+ time_t asecs = strtoul(current_value, NULL, 10);
+ arcn->sb.st_atimespec.tv_sec = asecs;
+ } else if (header_len == KW_PATH_CASE) { /* Special case for path keyword */
+ path_replaced = 1;
+ arcn->nlen = len;
+ strlcpy(arcn->name,current_value,sizeof(arcn->name));
+ } else if (header_len >= 0) { // Skip negative values
+ if (len > header_len) {
+ paxwarn(1," length of string from extended header bigger than header field:"
+ " THAT won't work!\n");
+ } else {
+ char * p = (char *) myhd;
+ memcpy(&p[o_option_table[i].header_inx],
+ current_value, len);
+ if (len != header_len) {
+ /* pad with ? */
+ p[o_option_table[i].header_inx+len] = '\0';
+ }
+ }
+ }
+ if (free_it) {
+ free(current_value);
+ }
+ }
+ }
+
+ if (myhd==hd) return(path_replaced);
+
+ /* must put new header into memory of original */
+ memcpy(hd, myhd, sizeof(HD_USTAR));
+
+ return(path_replaced);
+}
+
+/*
+ * pax_id()
+ * determine if a block given to us is a valid pax header. We have to
+ * be on the lookout for those pesky blocks of all zero's
+ * Return:
+ * 0 if a ustar header, -1 otherwise
+ */
+
+int
+pax_id(char *blk, int size)
+{
+ HD_USTAR *hd;
+
+ if (size < BLKMULT)
+ return(-1);
+ hd = (HD_USTAR *)blk;
+
+ /*
+ * check for block of zero's first, a simple and fast test then check
+ * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
+ * programs are fouled up and create archives missing the \0. Last we
+ * check the checksum. If ok we have to assume it is a valid header.
+ */
+ if (hd->name[0] == '\0')
+ return(-1);
+ if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
+ return(-1);
+ if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != pax_chksm(blk,BLKMULT))
+ return(-1);
+ if ((hd->typeflag != PAXXTYPE) && (hd->typeflag != PAXGTYPE)) {
+ /* Not explicitly pax format, but at least ustar */
+ if (act==LIST || act==EXTRACT) {
+ /* Although insufficient evidence, call it pax format */
+ return(0);
+ }
+ return(-1);
+ }
+ pax_invalid_action = PAX_INVALID_ACTION_BYPASS; /* Default for pax format */
+ return(0);
+}
+
+/*
+ * pax_rd()
+ * extract the values out of block already determined to be a pax header.
+ * store the values in the ARCHD parameter.
+ * Return:
+ * 0
+ */
+
+int
+pax_rd(ARCHD *arcn, char *buf)
+{
+ HD_USTAR *hd;
+ int cnt = 0;
+ int check_path;
+ dev_t devmajor;
+ dev_t devminor;
+
+ /*
+ * we only get proper sized buffers
+ */
+ if (pax_id(buf, BLKMULT) < 0)
+ return(-1);
+
+ memset(arcn, 0, sizeof(*arcn));
+ arcn->org_name = arcn->name;
+ arcn->sb.st_nlink = 1;
+ hd = (HD_USTAR *)buf;
+
+ check_path = expand_extended_headers(arcn, hd);
+
+ if (check_path) {
+ /*
+ * pathname derived from extended head or -o option;
+ * full name is in one string, but length may exceed
+ * max path so be careful.
+ */
+ if (arcn->nlen > sizeof(arcn->name)) {
+ paxwarn(1,"pathname from extended header info doesn't fit! (len=%d)\n",
+ arcn->nlen);
+ }
+ } else {
+ /*
+ * see if the filename is split into two parts. if so, join the parts.
+ * we copy the prefix first and add a / between the prefix and name.
+ */
+ char *dest = arcn->name;
+ if (*(hd->prefix) != '\0') {
+ cnt = strlcpy(dest, hd->prefix, sizeof(arcn->name) - 1);
+ dest += cnt;
+ *dest++ = '/';
+ cnt++;
+ } else {
+ cnt = 0;
+ }
+
+ if (hd->typeflag != LONGLINKTYPE && hd->typeflag != LONGNAMETYPE) {
+ arcn->nlen = cnt + expandname(dest, sizeof(arcn->name) - cnt,
+ &gnu_name_string, hd->name, sizeof(hd->name));
+ arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name),
+ &gnu_link_string, hd->linkname, sizeof(hd->linkname));
+ }
+ }
+
+ /*
+ * follow the spec to the letter. we should only have mode bits, strip
+ * off all other crud we may be passed.
+ */
+ arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
+ 0xfff);
+#ifdef LONG_OFF_T
+ arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
+#else
+ arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
+ /* When we have extended header for size, prefer it over hd->size */
+ if (size_x_current) {
+ sscanf(size_x_current, "%lld", &arcn->sb.st_size);
+ }
+#endif
+ arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
+ if (arcn->sb.st_atimespec.tv_sec == 0) { // Can be set from header
+ arcn->sb.st_atime = arcn->sb.st_mtime;
+ }
+ arcn->sb.st_ctime = arcn->sb.st_mtime;
+
+ /*
+ * If we can find the ascii names for gname and uname in the password
+ * and group files we will use the uid's and gid they bind. Otherwise
+ * we use the uid and gid values stored in the header. (This is what
+ * the posix spec wants).
+ */
+ hd->gname[sizeof(hd->gname) - 1] = '\0';
+ if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
+ arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
+ hd->uname[sizeof(hd->uname) - 1] = '\0';
+ if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
+ arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
+
+ /*
+ * set the defaults, these may be changed depending on the file type
+ */
+ arcn->pad = 0;
+ arcn->skip = 0;
+ arcn->sb.st_rdev = (dev_t)0;
+
+ /*
+ * set the mode and PAX type according to the typeflag in the header
+ */
+ switch (hd->typeflag) {
+ case FIFOTYPE:
+ arcn->type = PAX_FIF;
+ arcn->sb.st_mode |= S_IFIFO;
+ break;
+ case DIRTYPE:
+ arcn->type = PAX_DIR;
+ arcn->sb.st_mode |= S_IFDIR;
+ arcn->sb.st_nlink = 2;
+
+ /*
+ * Some programs that create pax archives append a '/'
+ * to the pathname for directories. This clearly violates
+ * pax specs, but we will silently strip it off anyway.
+ */
+ if (arcn->name[arcn->nlen - 1] == '/')
+ arcn->name[--arcn->nlen] = '\0';
+ break;
+ case BLKTYPE:
+ case CHRTYPE:
+ /*
+ * this type requires the rdev field to be set.
+ */
+ if (hd->typeflag == BLKTYPE) {
+ arcn->type = PAX_BLK;
+ arcn->sb.st_mode |= S_IFBLK;
+ } else {
+ arcn->type = PAX_CHR;
+ arcn->sb.st_mode |= S_IFCHR;
+ }
+ devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
+ devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
+ arcn->sb.st_rdev = TODEV(devmajor, devminor);
+ break;
+ case SYMTYPE:
+ case LNKTYPE:
+ if (hd->typeflag == SYMTYPE) {
+ arcn->type = PAX_SLK;
+ arcn->sb.st_mode |= S_IFLNK;
+ } else {
+ arcn->type = PAX_HLK;
+ /*
+ * so printing looks better
+ */
+ arcn->sb.st_mode |= S_IFREG;
+ arcn->sb.st_nlink = 2;
+ }
+ break;
+ case LONGLINKTYPE:
+ case LONGNAMETYPE:
+ /*
+ * GNU long link/file; we tag these here and let the
+ * pax internals deal with it -- too ugly otherwise.
+ */
+ arcn->type =
+ hd->typeflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF;
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+ arcn->skip = arcn->sb.st_size;
+ break;
+ case CONTTYPE:
+ case AREGTYPE:
+ case REGTYPE:
+ default:
+ /*
+ * these types have file data that follows. Set the skip and
+ * pad fields.
+ */
+ arcn->type = PAX_REG;
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+ arcn->skip = arcn->sb.st_size;
+ arcn->sb.st_mode |= S_IFREG;
+ break;
+ }
+ return(0);
+}
+
+void
+adjust_copy_for_pax_options(ARCHD * arcn)
+{
+ /* Because ext_header options take precedence over global_header options, apply
+ global options first, then override with any extended header options */
+ int i;
+ if (global_ext_header_inx) {
+ for (i=0; i < global_ext_header_inx; i++) {
+ if (!o_option_table[global_ext_header_entry[i]].active) continue; /* deleted keywords */
+ if (strcmp(o_option_table[global_ext_header_entry[i]].name, "path")==0) {
+ strlcpy(arcn->name,*(o_option_table[global_ext_header_entry[i]].g_value),
+ sizeof(arcn->name));
+ arcn->nlen = strlen(*(o_option_table[global_ext_header_entry[i]].g_value));
+ } else { /* only handle path for now: others TBD */
+ paxwarn(1, "adjust arcn for global extended header options not implemented:%d", i);
+ }
+ }
+ }
+ if (ext_header_inx) {
+ for (i=0; i < ext_header_inx; i++) {
+ if (!o_option_table[ext_header_entry[i]].active) continue; /* deleted keywords */
+ if (strcmp(o_option_table[ext_header_entry[i]].name, "path")==0) {
+ strlcpy(arcn->name,*(o_option_table[ext_header_entry[i]].x_value),
+ sizeof(arcn->name));
+ arcn->nlen = strlen(*(o_option_table[ext_header_entry[i]].x_value));
+ } else { /* only handle path for now: others TBD */
+ paxwarn(1, "adjust arcn for extended header options not implemented:%d", i);
+ }
+ }
+ }
+ if (want_a_m_time_headers) {
+ /* TBD */
+ }
+}
+
+static int
+emit_extended_header_record(int len, int total_len, int head_type,
+ char * name, char * value)
+{
+ if (total_len + len > sizeof(pax_eh_datablk)) {
+ paxwarn(1,"extended header buffer overflow for header type '%c': %d",
+ head_type, total_len+len);
+ } else {
+ sprintf(&pax_eh_datablk[total_len],"%d %s=%s\n", len, name, value);
+ total_len += len;
+ }
+ return (total_len);
+}
+
+__attribute__((__malloc__))
+static char *
+substitute_percent(char * header, char * filename)
+{
+ char *nextpercent, *nextchar;
+ char buf[4*1024];
+ int pos, cpylen;
+ char *dname, *fname;
+
+ nextpercent = strchr(header,'%');
+ if (nextpercent==NULL) return strdup(header);
+ pos = nextpercent-header;
+ memcpy(buf,header, pos);
+ while (nextpercent++) {
+ switch (*nextpercent) {
+ case '%':
+ buf[pos++]='%'; /* just skip it */
+ break;
+ case 'd':
+ dname = strrchr(filename,'/');
+ if (dname==NULL) {
+ cpylen = 1;
+ dname = ".";
+ } else {
+ cpylen = dname-filename;
+ dname = filename;
+ }
+ memcpy(&buf[pos],dname,cpylen);
+ pos+= cpylen;
+ break;
+ case 'f':
+ fname = strrchr(filename,'/');
+ if (fname==NULL) {
+ fname = filename;
+ } else {
+ fname++;
+ }
+ cpylen = strlen(fname);
+ memcpy(&buf[pos],fname,cpylen);
+ pos+= cpylen;
+ break;
+ case 'n':
+ pos += sprintf (&buf[pos],"%d",nglobal_headers);
+ break;
+ case 'p':
+ pos += sprintf (&buf[pos],"%d",getpid());
+ break;
+ default:
+ paxwarn(1,"header format substitution failed: '%c'", *nextpercent);
+ return strdup(header);
+ }
+ nextpercent++;
+ if (*nextpercent=='\0') {
+ break;
+ }
+ nextchar = nextpercent;
+ nextpercent = strchr(nextpercent,'%');
+ if (nextpercent==NULL) {
+ cpylen = strlen(nextchar);
+ } else {
+ cpylen = nextpercent - nextchar;
+ }
+ memcpy(&buf[pos],nextchar, cpylen);
+ pos += cpylen;
+ }
+ buf[pos]='\0';
+ return (strdup(&buf[0]));
+}
+
+static int
+generate_pax_ext_header_and_data(ARCHD *arcn, int nfields, int *table,
+ char header_type, char * header_name, char * header_name_requested)
+{
+ HD_USTAR *hd;
+ char hdblk[sizeof(HD_USTAR)];
+ u_long records_size;
+ int term_char, i, len, total_len;
+ char * str, *name;
+
+ if (nfields == 0 && (header_name_requested == NULL)) {
+ if (header_type==PAXXTYPE) {
+ if (!want_a_m_time_headers) return (0);
+ } else
+ return (0);
+ }
+
+ /* There might be no fields but a header with a specific name or
+ times might be wanted */
+
+ term_char = 1;
+ memset(hdblk, 0, sizeof(hdblk));
+ hd = (HD_USTAR *)hdblk;
+ memset(pax_eh_datablk, 0, sizeof(pax_eh_datablk));
+
+ /* generate header */
+ hd->typeflag = header_type;
+
+ /* These fields appear to be necessary to be able to treat extended headers
+ like files in older versions of pax */
+ ul_oct((u_long)0444, hd->mode, sizeof(hd->mode), term_char);
+ strncpy(hd->magic, TMAGIC, TMAGLEN);
+ strncpy(hd->version, TVERSION, TVERSLEN);
+ ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),term_char);
+
+ /* compute size of data */
+ total_len = 0;
+ for (i=0; i < nfields; i++) {
+ if (!o_option_table[table[i]].active) continue; /* deleted keywords */
+ name = o_option_table[table[i]].name;
+ if (header_type == PAXXTYPE) {
+ str = *(o_option_table[table[i]].x_value);
+ } else {
+ str = *(o_option_table[table[i]].g_value);
+ }
+ if (str==NULL) {
+ paxwarn(1,"Missing option value for %s", name);
+ continue;
+ }
+ len = strlen(str) + o_option_table[table[i]].len + 3;
+ if (len < 9) len++;
+ else if (len < 98) len = len + 2;
+ else if (len < 997) len = len + 3;
+ else if (len < 9996) len = len + 4;
+ else {
+ paxwarn(1,"extended header data too long for header type '%c': %d",
+ header_type, len);
+ }
+ total_len = emit_extended_header_record(len, total_len,
+ header_type, name, str);
+ }
+
+ if ((header_type == PAXXTYPE) && want_a_m_time_headers) {
+ char time_buffer[12];
+ memset(time_buffer,0,sizeof(time_buffer));
+ sprintf(&time_buffer[0],"%d",(int)arcn->sb.st_atime);
+ /* 3 chars + strlen("atime") + time + # chars in len */
+ len = 3 + 5 + strlen(&time_buffer[0]) + 2;
+ total_len = emit_extended_header_record(len, total_len,
+ header_type, "atime", &time_buffer[0]);
+ memset(time_buffer,0,sizeof(time_buffer));
+ sprintf(&time_buffer[0],"%d",(int)arcn->sb.st_mtime);
+ /* 3 chars + strlen("mtime") + time + # chars in len */
+ len = 3 + 5 + strlen(&time_buffer[0]) + 2;
+ total_len = emit_extended_header_record(len, total_len,
+ header_type, "mtime", &time_buffer[0]);
+ }
+
+ /* Check if all fields were deleted: might not need to generate anything */
+ if ((total_len==0) && (header_name_requested == NULL)) return (0);
+
+ if (header_type == PAXGTYPE) nglobal_headers++;
+ /* substitution of fields in header_name */
+ header_name = substitute_percent(header_name, arcn->name);
+ if (strlen(header_name) == sizeof(hd->name)) { /* must account for name just fits in buffer */
+ strncpy(hd->name, header_name, sizeof(hd->name));
+ } else {
+ strlcpy(hd->name, header_name, sizeof(hd->name));
+ }
+
+ free(header_name);
+ header_name = NULL;
+ records_size = (u_long)total_len;
+ if (ul_oct(records_size, hd->size, sizeof(hd->size), term_char)) {
+ paxwarn(1,"extended header data too long for header type '%c'", header_type);
+ return(1);
+ }
+
+ if (ul_oct(pax_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum, sizeof(hd->chksum), term_char)) {
+ paxwarn(1,"extended header data checksum failed: header type '%c'", header_type);
+ return(1);
+ }
+
+ /* write out header */
+ if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
+ return(-1);
+ if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
+ return(-1);
+ /* write out header data */
+ if (total_len > 0) {
+ if (wr_rdbuf(pax_eh_datablk, total_len) < 0)
+ return(-1);
+ if (wr_skip((off_t)(BLKMULT - total_len)) < 0)
+ return(-1);
+ /*
+ printf("data written:\n%s",&pax_eh_datablk[0]);
+ */
+ }
+
+ /*
+ paxwarn(0,"extended header and data written: header type '%c', #items: %d, %d characters",
+ header_type, nfields, records_size);
+ */
+ return (0);
+}
+
+/*
+ * pax_wr()
+ * write a pax header for the file specified in the ARCHD to the archive
+ * Have to check for file types that cannot be stored and file names that
+ * are too long. Be careful of the term (last arg) to ul_oct, we only use
+ * '\0' for the termination character (this is different than picky tar)
+ * ASSUMED: space after header in header block is zero filled
+ * Return:
+ * 0 if file has data to be written after the header, 1 if file has NO
+ * data to write after the header, -1 if archive write failed
+ */
+
+int
+pax_wr(ARCHD *arcn)
+{
+ HD_USTAR *hd;
+ char *pt;
+ char hdblk[sizeof(HD_USTAR)];
+ mode_t mode12only;
+ int term_char=3; /* orignal setting */
+ term_char=1; /* To pass conformance tests 274, 301 */
+ const char *size_header_name = "size";
+ char size_value[100];
+ bzero(size_value, sizeof(size_value));
+
+ /*
+ * check for those file system types pax cannot store
+ */
+ if (arcn->type == PAX_SCK) {
+ paxwarn(1, "Pax cannot archive a socket %s", arcn->org_name);
+ return(1);
+ }
+
+ /*
+ * check the length of the linkname
+ */
+ if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
+ (arcn->type == PAX_HRG)) && (arcn->ln_nlen > sizeof(hd->linkname))){
+ paxwarn(1, "Link name too long for pax %s", arcn->ln_name);
+ /*
+ * Conformance: test pax:285 wants error code to be non-zero, and
+ * test tar:12 wants error code from pax to be 0
+ */
+ return(1);
+ }
+
+ /*
+ * split the path name into prefix and name fields (if needed). if
+ * pt != arcn->name, the name has to be split
+ */
+ if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
+ paxwarn(1, "File name too long for pax %s", arcn->name);
+ return(1);
+ }
+
+ generate_pax_ext_header_and_data(arcn, global_ext_header_inx, &global_ext_header_entry[0],
+ PAXGTYPE, header_name_g, header_name_g_requested);
+ generate_pax_ext_header_and_data(arcn, ext_header_inx, &ext_header_entry[0],
+ PAXXTYPE, header_name_x, header_name_x_requested);
+
+ /*
+ * zero out the header so we don't have to worry about zero fill below
+ */
+ memset(hdblk, 0, sizeof(hdblk));
+ hd = (HD_USTAR *)hdblk;
+ arcn->pad = 0L;
+ /* To pass conformance tests 274/301, always set these fields to "zero" */
+ ul_oct(0, hd->devmajor, sizeof(hd->devmajor), term_char);
+ ul_oct(0, hd->devminor, sizeof(hd->devminor), term_char);
+
+ /*
+ * split the name, or zero out the prefix
+ */
+ if (pt != arcn->name) {
+ /*
+ * name was split, pt points at the / where the split is to
+ * occur, we remove the / and copy the first part to the prefix
+ */
+ *pt = '\0';
+ strlcpy(hd->prefix, arcn->name, sizeof(hd->prefix));
+ *pt++ = '/';
+ }
+
+ /*
+ * copy the name part. this may be the whole path or the part after
+ * the prefix
+ */
+ if (strlen(pt) == sizeof(hd->name)) { /* must account for name just fits in buffer */
+ strncpy(hd->name, pt, sizeof(hd->name));
+ } else {
+ strlcpy(hd->name, pt, sizeof(hd->name));
+ }
+
+ /*
+ * set the fields in the header that are type dependent
+ */
+ switch (arcn->type) {
+ case PAX_DIR:
+ hd->typeflag = DIRTYPE;
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
+ goto out;
+ break;
+ case PAX_CHR:
+ case PAX_BLK:
+ if (arcn->type == PAX_CHR)
+ hd->typeflag = CHRTYPE;
+ else
+ hd->typeflag = BLKTYPE;
+ if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
+ sizeof(hd->devmajor), term_char) ||
+ ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
+ sizeof(hd->devminor), term_char) ||
+ ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
+ goto out;
+ break;
+ case PAX_FIF:
+ hd->typeflag = FIFOTYPE;
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
+ goto out;
+ break;
+ case PAX_SLK:
+ case PAX_HLK:
+ case PAX_HRG:
+ if (arcn->type == PAX_SLK)
+ hd->typeflag = SYMTYPE;
+ else
+ hd->typeflag = LNKTYPE;
+ if (strlen(arcn->ln_name) == sizeof(hd->linkname)) { /* must account for name just fits in buffer */
+ strncpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname));
+ } else {
+ strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname));
+ }
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
+ goto out;
+ break;
+ case PAX_REG:
+ case PAX_CTG:
+ default:
+ /*
+ * file data with this type, set the padding
+ */
+ if (arcn->type == PAX_CTG)
+ hd->typeflag = CONTTYPE;
+ else
+ hd->typeflag = REGTYPE;
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+# ifdef LONG_OFF_T
+ if (ul_oct((u_long)arcn->sb.st_size, hd->size,
+ sizeof(hd->size), term_char)) {
+# else
+ if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
+ sizeof(hd->size), term_char)) {
+# endif
+ /*
+ * Insert an extended header for size=<arcn->sb.st_size> since
+ * octal range of 12 byte string cannot fit > 8GiB files in header.
+ * This fixes Conformance test pax.343
+ */
+ int i;
+ snprintf(size_value, sizeof(size_value), "%lld", arcn->sb.st_size);
+ for (i = 0; i < sizeof(o_option_table)/sizeof(O_OPTION_TYPE); i++) {
+ if (strncasecmp(size_header_name, o_option_table[i].name, o_option_table[i].len) == 0) {
+ size_x = size_value;
+ ext_header_entry[ext_header_inx++] = i;
+ }
+ }
+ generate_pax_ext_header_and_data(arcn, ext_header_inx, &ext_header_entry[0],
+ PAXXTYPE, header_name_x, header_name_x_requested);
+ }
+ break;
+ }
+
+ strncpy(hd->magic, TMAGIC, TMAGLEN);
+ strncpy(hd->version, TVERSION, TVERSLEN);
+
+ /*
+ * set the remaining fields. Some versions want all 16 bits of mode
+ * we better humor them (they really do not meet spec though)....
+ */
+ if (ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), term_char)) {
+ if (uid_nobody == 0) {
+ if (uid_name("nobody", &uid_nobody) == -1)
+ goto out;
+ }
+ if (uid_warn != arcn->sb.st_uid) {
+ uid_warn = arcn->sb.st_uid;
+ paxwarn(1,
+ "Pax header field is too small for uid %lu, "
+ "using nobody", (u_long)arcn->sb.st_uid);
+ }
+ if (ul_oct((u_long)uid_nobody, hd->uid, sizeof(hd->uid), term_char))
+ goto out;
+ }
+ if (ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), term_char)) {
+ if (gid_nobody == 0) {
+ if (gid_name("nobody", &gid_nobody) == -1)
+ goto out;
+ }
+ if (gid_warn != arcn->sb.st_gid) {
+ gid_warn = arcn->sb.st_gid;
+ paxwarn(1,
+ "Pax header field is too small for gid %lu, "
+ "using nobody", (u_long)arcn->sb.st_gid);
+ }
+ if (ul_oct((u_long)gid_nobody, hd->gid, sizeof(hd->gid), term_char))
+ goto out;
+ }
+ /* However, Unix conformance tests do not like MORE than 12 mode bits:
+ remove all beyond (see definition of stat.st_mode structure) */
+ mode12only = ((u_long)arcn->sb.st_mode) & 0x00000fff;
+ if (ul_oct((u_long)mode12only, hd->mode, sizeof(hd->mode), term_char) ||
+ ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),term_char))
+ goto out;
+ strncpy(hd->uname, name_uid(arcn->sb.st_uid, 0), sizeof(hd->uname));
+ strncpy(hd->gname, name_gid(arcn->sb.st_gid, 0), sizeof(hd->gname));
+
+ /*
+ * calculate and store the checksum write the header to the archive
+ * return 0 tells the caller to now write the file data, 1 says no data
+ * needs to be written
+ */
+ if (ul_oct(pax_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
+ sizeof(hd->chksum), term_char))
+ goto out;
+ if (wr_rdbuf(hdblk, sizeof(HD_USTAR)) < 0)
+ return(-1);
+ if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
+ return(-1);
+ if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
+ return(0);
+ return(1);
+
+ out:
+ /*
+ * header field is out of range
+ */
+ paxwarn(1, "Pax header field is too small for %s", arcn->org_name);
+ return(1);
+}
+
+/*
+ * name_split()
+ * see if the name has to be split for storage in a ustar header. We try
+ * to fit the entire name in the name field without splitting if we can.
+ * The split point is always at a /
+ * Return
+ * character pointer to split point (always the / that is to be removed
+ * if the split is not needed, the points is set to the start of the file
+ * name (it would violate the spec to split there). A NULL is returned if
+ * the file name is too long
+ */
+
+static char *
+name_split(char *name, int len)
+{
+ char *start;
+
+ /*
+ * check to see if the file name is small enough to fit in the name
+ * field. if so just return a pointer to the name.
+ */
+ if (len <= TNMSZ)
+ return(name);
+ if (len > (TPFSZ + TNMSZ))
+ return(NULL);
+
+ /*
+ * we start looking at the biggest sized piece that fits in the name
+ * field. We walk forward looking for a slash to split at. The idea is
+ * to find the biggest piece to fit in the name field (or the smallest
+ * prefix we can find)
+ */
+ start = name + len - TNMSZ -1;
+ if ((*start == '/') && (start == name))
+ ++start; /* 101 byte paths with leading '/' are dinged otherwise */
+ while ((*start != '\0') && (*start != '/'))
+ ++start;
+
+ /*
+ * if we hit the end of the string, this name cannot be split, so we
+ * cannot store this file.
+ */
+ if (*start == '\0')
+ return(NULL);
+ len = start - name;
+
+ /*
+ * NOTE: /str where the length of str == TNMSZ can not be stored under
+ * the p1003.1-1990 spec for ustar. We could force a prefix of / and
+ * the file would then expand on extract to //str. The len == 0 below
+ * makes this special case follow the spec to the letter.
+ */
+ if ((len >= TPFSZ) || (len == 0))
+ return(NULL);
+
+ /*
+ * ok have a split point, return it to the caller
+ */
+ return(start);
+}
+
+static size_t
+expandname(char *buf, size_t len, char **gnu_name, const char *name, size_t name_len)
+{
+ size_t nlen;
+
+ if (*gnu_name) {
+ if ((nlen = strlcpy(buf, *gnu_name, len)) >= len)
+ nlen = len - 1;
+ free(*gnu_name);
+ *gnu_name = NULL;
+ } else {
+ if (name_len < len) {
+ /* name may not be null terminated: it might be as big as the
+ field, so copy is limited to the max size of the header field */
+ if ((nlen = strlcpy(buf, name, name_len+1)) >= name_len+1)
+ nlen = name_len;
+ } else {
+ if ((nlen = strlcpy(buf, name, len)) >= len)
+ nlen = len - 1;
+ }
+ }
+ return(nlen);
+}
diff --git a/file_cmds/pax/pax_format.h b/file_cmds/pax/pax_format.h
new file mode 100644
index 0000000..4ac4094
--- /dev/null
+++ b/file_cmds/pax/pax_format.h
@@ -0,0 +1,158 @@
+/* $OpenBSD: tar.h,v 1.7 2003/06/02 23:32:09 millert Exp $ */
+/* $NetBSD: tar.h,v 1.3 1995/03/21 09:07:51 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tar.h 8.2 (Berkeley) 4/18/94
+ */
+
+#ifndef _PAX_FORMAT_H_
+#define _PAX_FORMAT_H_
+
+/*
+ * defines and data structures common to all tar formats
+ */
+#define CHK_LEN 8 /* length of checksum field */
+#define TNMSZ 100 /* size of name field */
+#ifdef _PAX_
+#define NULLCNT 2 /* number of null blocks in trailer */
+#define CHK_OFFSET 148 /* start of chksum field */
+#define BLNKSUM 256L /* sum of checksum field using ' ' */
+#endif /* _PAX_ */
+
+/*
+ * Values used in typeflag field in all tar formats
+ * (only REGTYPE, LNKTYPE and SYMTYPE are used in old bsd tar headers)
+ */
+#define REGTYPE '0' /* Regular File */
+#define AREGTYPE '\0' /* Regular File */
+#define LNKTYPE '1' /* Link */
+#define SYMTYPE '2' /* Symlink */
+#define CHRTYPE '3' /* Character Special File */
+#define BLKTYPE '4' /* Block Special File */
+#define DIRTYPE '5' /* Directory */
+#define FIFOTYPE '6' /* FIFO */
+#define CONTTYPE '7' /* high perf file */
+
+/*
+ * GNU tar compatibility;
+ */
+#define LONGLINKTYPE 'K' /* Long Symlink */
+#define LONGNAMETYPE 'L' /* Long File */
+
+/*
+ * Mode field encoding of the different file types - values in octal
+ */
+#define TSUID 04000 /* Set UID on execution */
+#define TSGID 02000 /* Set GID on execution */
+#define TSVTX 01000 /* Reserved */
+#define TUREAD 00400 /* Read by owner */
+#define TUWRITE 00200 /* Write by owner */
+#define TUEXEC 00100 /* Execute/Search by owner */
+#define TGREAD 00040 /* Read by group */
+#define TGWRITE 00020 /* Write by group */
+#define TGEXEC 00010 /* Execute/Search by group */
+#define TOREAD 00004 /* Read by other */
+#define TOWRITE 00002 /* Write by other */
+#define TOEXEC 00001 /* Execute/Search by other */
+
+#ifdef _PAX_
+/*
+ * Pad with a bit mask, much faster than doing a mod but only works on powers
+ * of 2. Macro below is for block of 512 bytes.
+ */
+#define TAR_PAD(x) ((512 - ((x) & 511)) & 511)
+#endif /* _PAX_ */
+
+/*
+ * structure of an old tar header as it appeared in BSD releases
+ */
+typedef struct {
+ char name[TNMSZ]; /* name of entry */
+ char mode[8]; /* mode */
+ char uid[8]; /* uid */
+ char gid[8]; /* gid */
+ char size[12]; /* size */
+ char mtime[12]; /* modification time */
+ char chksum[CHK_LEN]; /* checksum */
+ char linkflag; /* norm, hard, or sym. */
+ char linkname[TNMSZ]; /* linked to name */
+} HD_TAR;
+
+#ifdef _PAX_
+/*
+ * -o options for BSD tar to not write directories to the archive
+ */
+#define TAR_NODIR "nodir"
+#define TAR_OPTION "write_opt"
+
+/*
+ * default device names
+ */
+#define DEV_0 "/dev/rst0"
+#define DEV_1 "/dev/rst1"
+#define DEV_4 "/dev/rst4"
+#define DEV_5 "/dev/rst5"
+#define DEV_7 "/dev/rst7"
+#define DEV_8 "/dev/rst8"
+#endif /* _PAX_ */
+
+/*
+ * Data Interchange Format - Extended tar header format - POSIX 1003.1-1990
+ */
+#define TPFSZ 155
+#define TMAGIC "ustar" /* ustar and a null */
+#define TMAGLEN 6
+#define TVERSION "00" /* 00 and no null */
+#define TVERSLEN 2
+
+typedef struct {
+ char name[TNMSZ]; /* name of entry */
+ char mode[8]; /* mode */
+ char uid[8]; /* uid */
+ char gid[8]; /* gid */
+ char size[12]; /* size */
+ char mtime[12]; /* modification time */
+ char chksum[CHK_LEN]; /* checksum */
+ char typeflag; /* type of file. */
+ char linkname[TNMSZ]; /* linked to name */
+ char magic[TMAGLEN]; /* magic cookie */
+ char version[TVERSLEN]; /* version */
+ char uname[32]; /* ascii owner name */
+ char gname[32]; /* ascii group name */
+ char devmajor[8]; /* major device number */
+ char devminor[8]; /* minor device number */
+ char prefix[TPFSZ]; /* linked to name */
+} HD_USTAR;
+
+#endif /* _PAX_FORMAT_H_ */
diff --git a/file_cmds/pax/sel_subs.c b/file_cmds/pax/sel_subs.c
new file mode 100644
index 0000000..008479b
--- /dev/null
+++ b/file_cmds/pax/sel_subs.c
@@ -0,0 +1,614 @@
+/* $OpenBSD: sel_subs.c,v 1.18 2004/04/16 22:50:23 deraadt Exp $ */
+/* $NetBSD: sel_subs.c,v 1.5 1995/03/21 09:07:42 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)sel_subs.c 8.1 (Berkeley) 5/31/93";
+#else
+__used static const char rcsid[] = "$OpenBSD: sel_subs.c,v 1.18 2004/04/16 22:50:23 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include "pax.h"
+#include "sel_subs.h"
+#include "extern.h"
+
+static int str_sec(const char *, time_t *);
+static int usr_match(ARCHD *);
+static int grp_match(ARCHD *);
+static int trng_match(ARCHD *);
+
+static TIME_RNG *trhead = NULL; /* time range list head */
+static TIME_RNG *trtail = NULL; /* time range list tail */
+static USRT **usrtb = NULL; /* user selection table */
+static GRPT **grptb = NULL; /* group selection table */
+
+/*
+ * Routines for selection of archive members
+ */
+
+/*
+ * sel_chk()
+ * check if this file matches a specified uid, gid or time range
+ * Return:
+ * 0 if this archive member should be processed, 1 if it should be skipped
+ */
+
+int
+sel_chk(ARCHD *arcn)
+{
+ if (((usrtb != NULL) && usr_match(arcn)) ||
+ ((grptb != NULL) && grp_match(arcn)) ||
+ ((trhead != NULL) && trng_match(arcn)))
+ return(1);
+ return(0);
+}
+
+/*
+ * User/group selection routines
+ *
+ * Routines to handle user selection of files based on the file uid/gid. To
+ * add an entry, the user supplies either the name or the uid/gid starting with
+ * a # on the command line. A \# will escape the #.
+ */
+
+/*
+ * usr_add()
+ * add a user match to the user match hash table
+ * Return:
+ * 0 if added ok, -1 otherwise;
+ */
+
+int
+usr_add(char *str)
+{
+ u_int indx;
+ USRT *pt;
+ struct passwd *pw;
+ uid_t uid;
+
+ /*
+ * create the table if it doesn't exist
+ */
+ if ((str == NULL) || (*str == '\0'))
+ return(-1);
+ if ((usrtb == NULL) &&
+ ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) {
+ paxwarn(1, "Unable to allocate memory for user selection table");
+ return(-1);
+ }
+
+ /*
+ * figure out user spec
+ */
+ if (str[0] != '#') {
+ /*
+ * it is a user name, \# escapes # as first char in user name
+ */
+ if ((str[0] == '\\') && (str[1] == '#'))
+ ++str;
+ if ((pw = getpwnam(str)) == NULL) {
+ paxwarn(1, "Unable to find uid for user: %s", str);
+ return(-1);
+ }
+ uid = (uid_t)pw->pw_uid;
+ } else
+ uid = (uid_t)strtoul(str+1, NULL, 10);
+ endpwent();
+
+ /*
+ * hash it and go down the hash chain (if any) looking for it
+ */
+ indx = ((unsigned)uid) % USR_TB_SZ;
+ if ((pt = usrtb[indx]) != NULL) {
+ while (pt != NULL) {
+ if (pt->uid == uid)
+ return(0);
+ pt = pt->fow;
+ }
+ }
+
+ /*
+ * uid is not yet in the table, add it to the front of the chain
+ */
+ if ((pt = (USRT *)malloc(sizeof(USRT))) != NULL) {
+ pt->uid = uid;
+ pt->fow = usrtb[indx];
+ usrtb[indx] = pt;
+ return(0);
+ }
+ paxwarn(1, "User selection table out of memory");
+ return(-1);
+}
+
+/*
+ * usr_match()
+ * check if this files uid matches a selected uid.
+ * Return:
+ * 0 if this archive member should be processed, 1 if it should be skipped
+ */
+
+static int
+usr_match(ARCHD *arcn)
+{
+ USRT *pt;
+
+ /*
+ * hash and look for it in the table
+ */
+ pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ];
+ while (pt != NULL) {
+ if (pt->uid == arcn->sb.st_uid)
+ return(0);
+ pt = pt->fow;
+ }
+
+ /*
+ * not found
+ */
+ return(1);
+}
+
+/*
+ * grp_add()
+ * add a group match to the group match hash table
+ * Return:
+ * 0 if added ok, -1 otherwise;
+ */
+
+int
+grp_add(char *str)
+{
+ u_int indx;
+ GRPT *pt;
+ struct group *gr;
+ gid_t gid;
+
+ /*
+ * create the table if it doesn't exist
+ */
+ if ((str == NULL) || (*str == '\0'))
+ return(-1);
+ if ((grptb == NULL) &&
+ ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) {
+ paxwarn(1, "Unable to allocate memory fo group selection table");
+ return(-1);
+ }
+
+ /*
+ * figure out user spec
+ */
+ if (str[0] != '#') {
+ /*
+ * it is a group name, \# escapes # as first char in group name
+ */
+ if ((str[0] == '\\') && (str[1] == '#'))
+ ++str;
+ if ((gr = getgrnam(str)) == NULL) {
+ paxwarn(1,"Cannot determine gid for group name: %s", str);
+ return(-1);
+ }
+ gid = (gid_t)gr->gr_gid;
+ } else
+ gid = (gid_t)strtoul(str+1, NULL, 10);
+ endgrent();
+
+ /*
+ * hash it and go down the hash chain (if any) looking for it
+ */
+ indx = ((unsigned)gid) % GRP_TB_SZ;
+ if ((pt = grptb[indx]) != NULL) {
+ while (pt != NULL) {
+ if (pt->gid == gid)
+ return(0);
+ pt = pt->fow;
+ }
+ }
+
+ /*
+ * gid not in the table, add it to the front of the chain
+ */
+ if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) {
+ pt->gid = gid;
+ pt->fow = grptb[indx];
+ grptb[indx] = pt;
+ return(0);
+ }
+ paxwarn(1, "Group selection table out of memory");
+ return(-1);
+}
+
+/*
+ * grp_match()
+ * check if this files gid matches a selected gid.
+ * Return:
+ * 0 if this archive member should be processed, 1 if it should be skipped
+ */
+
+static int
+grp_match(ARCHD *arcn)
+{
+ GRPT *pt;
+
+ /*
+ * hash and look for it in the table
+ */
+ pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ];
+ while (pt != NULL) {
+ if (pt->gid == arcn->sb.st_gid)
+ return(0);
+ pt = pt->fow;
+ }
+
+ /*
+ * not found
+ */
+ return(1);
+}
+
+/*
+ * Time range selection routines
+ *
+ * Routines to handle user selection of files based on the modification and/or
+ * inode change time falling within a specified time range (the non-standard
+ * -T flag). The user may specify any number of different file time ranges.
+ * Time ranges are checked one at a time until a match is found (if at all).
+ * If the file has a mtime (and/or ctime) which lies within one of the time
+ * ranges, the file is selected. Time ranges may have a lower and/or a upper
+ * value. These ranges are inclusive. When no time ranges are supplied to pax
+ * with the -T option, all members in the archive will be selected by the time
+ * range routines. When only a lower range is supplied, only files with a
+ * mtime (and/or ctime) equal to or younger are selected. When only a upper
+ * range is supplied, only files with a mtime (and/or ctime) equal to or older
+ * are selected. When the lower time range is equal to the upper time range,
+ * only files with a mtime (or ctime) of exactly that time are selected.
+ */
+
+/*
+ * trng_add()
+ * add a time range match to the time range list.
+ * This is a non-standard pax option. Lower and upper ranges are in the
+ * format: [[[[[cc]yy]mm]dd]HH]MM[.SS] and are comma separated.
+ * Time ranges are based on current time, so 1234 would specify a time of
+ * 12:34 today.
+ * Return:
+ * 0 if the time range was added to the list, -1 otherwise
+ */
+
+int
+trng_add(char *str)
+{
+ TIME_RNG *pt;
+ char *up_pt = NULL;
+ char *stpt;
+ char *flgpt;
+ int dot = 0;
+
+ /*
+ * throw out the badly formed time ranges
+ */
+ if ((str == NULL) || (*str == '\0')) {
+ paxwarn(1, "Empty time range string");
+ return(-1);
+ }
+
+ /*
+ * locate optional flags suffix /{cm}.
+ */
+ if ((flgpt = strrchr(str, '/')) != NULL)
+ *flgpt++ = '\0';
+
+ for (stpt = str; *stpt != '\0'; ++stpt) {
+ if ((*stpt >= '0') && (*stpt <= '9'))
+ continue;
+ if ((*stpt == ',') && (up_pt == NULL)) {
+ *stpt = '\0';
+ up_pt = stpt + 1;
+ dot = 0;
+ continue;
+ }
+
+ /*
+ * allow only one dot per range (secs)
+ */
+ if ((*stpt == '.') && (!dot)) {
+ ++dot;
+ continue;
+ }
+ paxwarn(1, "Improperly specified time range: %s", str);
+ goto out;
+ }
+
+ /*
+ * allocate space for the time range and store the limits
+ */
+ if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) {
+ paxwarn(1, "Unable to allocate memory for time range");
+ return(-1);
+ }
+
+ /*
+ * by default we only will check file mtime, but user can specify
+ * mtime, ctime (inode change time) or both.
+ */
+ if ((flgpt == NULL) || (*flgpt == '\0'))
+ pt->flgs = CMPMTME;
+ else {
+ pt->flgs = 0;
+ while (*flgpt != '\0') {
+ switch (*flgpt) {
+ case 'M':
+ case 'm':
+ pt->flgs |= CMPMTME;
+ break;
+ case 'C':
+ case 'c':
+ pt->flgs |= CMPCTME;
+ break;
+ default:
+ paxwarn(1, "Bad option %c with time range %s",
+ *flgpt, str);
+ free(pt);
+ goto out;
+ }
+ ++flgpt;
+ }
+ }
+
+ /*
+ * start off with the current time
+ */
+ pt->low_time = pt->high_time = time(NULL);
+ if (*str != '\0') {
+ /*
+ * add lower limit
+ */
+ if (str_sec(str, &(pt->low_time)) < 0) {
+ paxwarn(1, "Illegal lower time range %s", str);
+ (void)free((char *)pt);
+ goto out;
+ }
+ pt->flgs |= HASLOW;
+ }
+
+ if ((up_pt != NULL) && (*up_pt != '\0')) {
+ /*
+ * add upper limit
+ */
+ if (str_sec(up_pt, &(pt->high_time)) < 0) {
+ paxwarn(1, "Illegal upper time range %s", up_pt);
+ (void)free((char *)pt);
+ goto out;
+ }
+ pt->flgs |= HASHIGH;
+
+ /*
+ * check that the upper and lower do not overlap
+ */
+ if (pt->flgs & HASLOW) {
+ if (pt->low_time > pt->high_time) {
+ paxwarn(1, "Upper %s and lower %s time overlap",
+ up_pt, str);
+ (void)free((char *)pt);
+ return(-1);
+ }
+ }
+ }
+
+ pt->fow = NULL;
+ if (trhead == NULL) {
+ trtail = trhead = pt;
+ return(0);
+ }
+ trtail->fow = pt;
+ trtail = pt;
+ return(0);
+
+ out:
+ paxwarn(1, "Time range format is: [[[[[cc]yy]mm]dd]HH]MM[.SS][/[c][m]]");
+ return(-1);
+}
+
+/*
+ * trng_match()
+ * check if this files mtime/ctime falls within any supplied time range.
+ * Return:
+ * 0 if this archive member should be processed, 1 if it should be skipped
+ */
+
+static int
+trng_match(ARCHD *arcn)
+{
+ TIME_RNG *pt;
+
+ /*
+ * have to search down the list one at a time looking for a match.
+ * remember time range limits are inclusive.
+ */
+ pt = trhead;
+ while (pt != NULL) {
+ switch (pt->flgs & CMPBOTH) {
+ case CMPBOTH:
+ /*
+ * user wants both mtime and ctime checked for this
+ * time range
+ */
+ if (((pt->flgs & HASLOW) &&
+ (arcn->sb.st_mtime < pt->low_time) &&
+ (arcn->sb.st_ctime < pt->low_time)) ||
+ ((pt->flgs & HASHIGH) &&
+ (arcn->sb.st_mtime > pt->high_time) &&
+ (arcn->sb.st_ctime > pt->high_time))) {
+ pt = pt->fow;
+ continue;
+ }
+ break;
+ case CMPCTME:
+ /*
+ * user wants only ctime checked for this time range
+ */
+ if (((pt->flgs & HASLOW) &&
+ (arcn->sb.st_ctime < pt->low_time)) ||
+ ((pt->flgs & HASHIGH) &&
+ (arcn->sb.st_ctime > pt->high_time))) {
+ pt = pt->fow;
+ continue;
+ }
+ break;
+ case CMPMTME:
+ default:
+ /*
+ * user wants only mtime checked for this time range
+ */
+ if (((pt->flgs & HASLOW) &&
+ (arcn->sb.st_mtime < pt->low_time)) ||
+ ((pt->flgs & HASHIGH) &&
+ (arcn->sb.st_mtime > pt->high_time))) {
+ pt = pt->fow;
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+
+ if (pt == NULL)
+ return(1);
+ return(0);
+}
+
+/*
+ * str_sec()
+ * Convert a time string in the format of [[[[[cc]yy]mm]dd]HH]MM[.SS] to
+ * seconds UTC. Tval already has current time loaded into it at entry.
+ * Return:
+ * 0 if converted ok, -1 otherwise
+ */
+
+static int
+str_sec(const char *p, time_t *tval)
+{
+ struct tm *lt;
+ const char *dot, *t;
+ size_t len;
+ int bigyear;
+ int yearset;
+
+ yearset = 0;
+ len = strlen(p);
+
+ for (t = p, dot = NULL; *t; ++t) {
+ if (isdigit(*t))
+ continue;
+ if (*t == '.' && dot == NULL) {
+ dot = t;
+ continue;
+ }
+ return(-1);
+ }
+
+ lt = localtime(tval);
+
+ if (dot != NULL) { /* .SS */
+ if (strlen(++dot) != 2)
+ return(-1);
+ lt->tm_sec = ATOI2(dot);
+ if (lt->tm_sec > 61)
+ return(-1);
+ len -= 3;
+ } else
+ lt->tm_sec = 0;
+
+ switch (len) {
+ case 12: /* cc */
+ bigyear = ATOI2(p);
+ lt->tm_year = (bigyear * 100) - TM_YEAR_BASE;
+ yearset = 1;
+ /* FALLTHROUGH */
+ case 10: /* yy */
+ if (yearset) {
+ lt->tm_year += ATOI2(p);
+ } else {
+ lt->tm_year = ATOI2(p);
+ if (lt->tm_year < 69) /* hack for 2000 ;-} */
+ lt->tm_year += (2000 - TM_YEAR_BASE);
+ else
+ lt->tm_year += (1900 - TM_YEAR_BASE);
+ }
+ /* FALLTHROUGH */
+ case 8: /* mm */
+ lt->tm_mon = ATOI2(p);
+ if ((lt->tm_mon > 12) || !lt->tm_mon)
+ return(-1);
+ --lt->tm_mon; /* time struct is 0 - 11 */
+ /* FALLTHROUGH */
+ case 6: /* dd */
+ lt->tm_mday = ATOI2(p);
+ if ((lt->tm_mday > 31) || !lt->tm_mday)
+ return(-1);
+ /* FALLTHROUGH */
+ case 4: /* HH */
+ lt->tm_hour = ATOI2(p);
+ if (lt->tm_hour > 23)
+ return(-1);
+ /* FALLTHROUGH */
+ case 2: /* MM */
+ lt->tm_min = ATOI2(p);
+ if (lt->tm_min > 59)
+ return(-1);
+ break;
+ default:
+ return(-1);
+ }
+
+ /* convert broken-down time to UTC clock time seconds */
+ if ((*tval = mktime(lt)) == -1)
+ return(-1);
+ return(0);
+}
diff --git a/file_cmds/pax/sel_subs.h b/file_cmds/pax/sel_subs.h
new file mode 100644
index 0000000..4516545
--- /dev/null
+++ b/file_cmds/pax/sel_subs.h
@@ -0,0 +1,77 @@
+/* $OpenBSD: sel_subs.h,v 1.4 2003/06/02 23:32:09 millert Exp $ */
+/* $NetBSD: sel_subs.h,v 1.3 1995/03/21 09:07:44 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sel_subs.h 8.1 (Berkeley) 5/31/93
+ */
+
+#ifndef _SEL_SUBS_H_
+#define _SEL_SUBS_H_
+
+/*
+ * data structure for storing uid/grp selects (-U, -G non standard options)
+ */
+
+#define USR_TB_SZ 317 /* user selection table size */
+#define GRP_TB_SZ 317 /* user selection table size */
+
+typedef struct usrt {
+ uid_t uid;
+ struct usrt *fow; /* next uid */
+} USRT;
+
+typedef struct grpt {
+ gid_t gid;
+ struct grpt *fow; /* next gid */
+} GRPT;
+
+/*
+ * data structure for storing user supplied time ranges (-T option)
+ */
+
+#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+
+typedef struct time_rng {
+ time_t low_time; /* lower inclusive time limit */
+ time_t high_time; /* higher inclusive time limit */
+ int flgs; /* option flags */
+#define HASLOW 0x01 /* has lower time limit */
+#define HASHIGH 0x02 /* has higher time limit */
+#define CMPMTME 0x04 /* compare file modification time */
+#define CMPCTME 0x08 /* compare inode change time */
+#define CMPBOTH (CMPMTME|CMPCTME) /* compare inode and mod time */
+ struct time_rng *fow; /* next pattern */
+} TIME_RNG;
+
+#endif /* _SEL_SUBS_H_ */
diff --git a/file_cmds/pax/tables.c b/file_cmds/pax/tables.c
new file mode 100644
index 0000000..f45d291
--- /dev/null
+++ b/file_cmds/pax/tables.c
@@ -0,0 +1,1278 @@
+/* $OpenBSD: tables.c,v 1.25 2007/09/02 15:19:08 deraadt Exp $ */
+/* $NetBSD: tables.c,v 1.4 1995/03/21 09:07:45 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 5/31/93";
+#else
+__used static const char rcsid[] = "$OpenBSD: tables.c,v 1.25 2007/09/02 15:19:08 deraadt Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "tables.h"
+#include "extern.h"
+
+/*
+ * Routines for controlling the contents of all the different databases pax
+ * keeps. Tables are dynamically created only when they are needed. The
+ * goal was speed and the ability to work with HUGE archives. The databases
+ * were kept simple, but do have complex rules for when the contents change.
+ * As of this writing, the posix library functions were more complex than
+ * needed for this application (pax databases have very short lifetimes and
+ * do not survive after pax is finished). Pax is required to handle very
+ * large archives. These database routines carefully combine memory usage and
+ * temporary file storage in ways which will not significantly impact runtime
+ * performance while allowing the largest possible archives to be handled.
+ * Trying to force the fit to the posix database routines was not considered
+ * time well spent.
+ */
+
+static HRDLNK **ltab = NULL; /* hard link table for detecting hard links */
+static FTM **ftab = NULL; /* file time table for updating arch */
+static NAMT **ntab = NULL; /* interactive rename storage table */
+static DEVT **dtab = NULL; /* device/inode mapping tables */
+static ATDIR **atab = NULL; /* file tree directory time reset table */
+static DIRDATA *dirp = NULL; /* storage for setting created dir time/mode */
+static size_t dirsize; /* size of dirp table */
+static long dircnt = 0; /* entries in dir time/mode storage */
+static int ffd = -1; /* tmp file for file time table name storage */
+
+static DEVT *chk_dev(dev_t, int);
+
+/*
+ * hard link table routines
+ *
+ * The hard link table tries to detect hard links to files using the device and
+ * inode values. We do this when writing an archive, so we can tell the format
+ * write routine that this file is a hard link to another file. The format
+ * write routine then can store this file in whatever way it wants (as a hard
+ * link if the format supports that like tar, or ignore this info like cpio).
+ * (Actually a field in the format driver table tells us if the format wants
+ * hard link info. if not, we do not waste time looking for them). We also use
+ * the same table when reading an archive. In that situation, this table is
+ * used by the format read routine to detect hard links from stored dev and
+ * inode numbers (like cpio). This will allow pax to create a link when one
+ * can be detected by the archive format.
+ */
+
+/*
+ * lnk_start
+ * Creates the hard link table.
+ * Return:
+ * 0 if created, -1 if failure
+ */
+
+int
+lnk_start(void)
+{
+ if (ltab != NULL)
+ return(0);
+ if ((ltab = (HRDLNK **)calloc(L_TAB_SZ, sizeof(HRDLNK *))) == NULL) {
+ paxwarn(1, "Cannot allocate memory for hard link table");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * chk_lnk()
+ * Looks up entry in hard link hash table. If found, it copies the name
+ * of the file it is linked to (we already saw that file) into ln_name.
+ * lnkcnt is decremented and if goes to 1 the node is deleted from the
+ * database. (We have seen all the links to this file). If not found,
+ * we add the file to the database if it has the potential for having
+ * hard links to other files we may process (it has a link count > 1)
+ * Return:
+ * if found returns 1; if not found returns 0; -1 on error
+ */
+
+int
+chk_lnk(ARCHD *arcn)
+{
+ HRDLNK *pt;
+ HRDLNK **ppt;
+ u_int indx;
+
+ if (ltab == NULL)
+ return(-1);
+ /*
+ * ignore those nodes that cannot have hard links
+ */
+ if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1))
+ return(0);
+
+ /*
+ * hash inode number and look for this file
+ */
+ indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
+ if ((pt = ltab[indx]) != NULL) {
+ /*
+ * its hash chain in not empty, walk down looking for it
+ */
+ ppt = &(ltab[indx]);
+ while (pt != NULL) {
+ if ((pt->ino == arcn->sb.st_ino) &&
+ (pt->dev == arcn->sb.st_dev))
+ break;
+ ppt = &(pt->fow);
+ pt = pt->fow;
+ }
+
+ if (pt != NULL) {
+ /*
+ * found a link. set the node type and copy in the
+ * name of the file it is to link to. we need to
+ * handle hardlinks to regular files differently than
+ * other links.
+ */
+ arcn->ln_nlen = strlcpy(arcn->ln_name, pt->name,
+ sizeof(arcn->ln_name));
+ /* XXX truncate? */
+ if (arcn->nlen >= sizeof(arcn->name))
+ arcn->nlen = sizeof(arcn->name) - 1;
+ if (arcn->type == PAX_REG)
+ arcn->type = PAX_HRG;
+ else
+ arcn->type = PAX_HLK;
+
+ /*
+ * if we have found all the links to this file, remove
+ * it from the database
+ */
+ if (--pt->nlink <= 1) {
+ *ppt = pt->fow;
+ (void)free((char *)pt->name);
+ (void)free((char *)pt);
+ }
+ return(1);
+ }
+ }
+
+ /*
+ * we never saw this file before. It has links so we add it to the
+ * front of this hash chain
+ */
+ if ((pt = (HRDLNK *)malloc(sizeof(HRDLNK))) != NULL) {
+ if ((pt->name = strdup(arcn->name)) != NULL) {
+ pt->dev = arcn->sb.st_dev;
+ pt->ino = arcn->sb.st_ino;
+ pt->nlink = arcn->sb.st_nlink;
+ pt->fow = ltab[indx];
+ ltab[indx] = pt;
+ return(0);
+ }
+ (void)free((char *)pt);
+ }
+
+ paxwarn(1, "Hard link table out of memory");
+ return(-1);
+}
+
+/*
+ * purg_lnk
+ * remove reference for a file that we may have added to the data base as
+ * a potential source for hard links. We ended up not using the file, so
+ * we do not want to accidently point another file at it later on.
+ */
+
+void
+purg_lnk(ARCHD *arcn)
+{
+ HRDLNK *pt;
+ HRDLNK **ppt;
+ u_int indx;
+
+ if (ltab == NULL)
+ return;
+ /*
+ * do not bother to look if it could not be in the database
+ */
+ if ((arcn->sb.st_nlink <= 1) || (arcn->type == PAX_DIR) ||
+ (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
+ return;
+
+ /*
+ * find the hash chain for this inode value, if empty return
+ */
+ indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
+ if ((pt = ltab[indx]) == NULL)
+ return;
+
+ /*
+ * walk down the list looking for the inode/dev pair, unlink and
+ * free if found
+ */
+ ppt = &(ltab[indx]);
+ while (pt != NULL) {
+ if ((pt->ino == arcn->sb.st_ino) &&
+ (pt->dev == arcn->sb.st_dev))
+ break;
+ ppt = &(pt->fow);
+ pt = pt->fow;
+ }
+ if (pt == NULL)
+ return;
+
+ /*
+ * remove and free it
+ */
+ *ppt = pt->fow;
+ (void)free((char *)pt->name);
+ (void)free((char *)pt);
+}
+
+/*
+ * lnk_end()
+ * pull apart a existing link table so we can reuse it. We do this between
+ * read and write phases of append with update. (The format may have
+ * used the link table, and we need to start with a fresh table for the
+ * write phase
+ */
+
+void
+lnk_end(void)
+{
+ int i;
+ HRDLNK *pt;
+ HRDLNK *ppt;
+
+ if (ltab == NULL)
+ return;
+
+ for (i = 0; i < L_TAB_SZ; ++i) {
+ if (ltab[i] == NULL)
+ continue;
+ pt = ltab[i];
+ ltab[i] = NULL;
+
+ /*
+ * free up each entry on this chain
+ */
+ while (pt != NULL) {
+ ppt = pt;
+ pt = ppt->fow;
+ (void)free((char *)ppt->name);
+ (void)free((char *)ppt);
+ }
+ }
+ return;
+}
+
+/*
+ * modification time table routines
+ *
+ * The modification time table keeps track of last modification times for all
+ * files stored in an archive during a write phase when -u is set. We only
+ * add a file to the archive if it is newer than a file with the same name
+ * already stored on the archive (if there is no other file with the same
+ * name on the archive it is added). This applies to writes and appends.
+ * An append with an -u must read the archive and store the modification time
+ * for every file on that archive before starting the write phase. It is clear
+ * that this is one HUGE database. To save memory space, the actual file names
+ * are stored in a scratch file and indexed by an in-memory hash table. The
+ * hash table is indexed by hashing the file path. The nodes in the table store
+ * the length of the filename and the lseek offset within the scratch file
+ * where the actual name is stored. Since there are never any deletions from
+ * this table, fragmentation of the scratch file is never a issue. Lookups
+ * seem to not exhibit any locality at all (files in the database are rarely
+ * looked up more than once...), so caching is just a waste of memory. The
+ * only limitation is the amount of scratch file space available to store the
+ * path names.
+ */
+
+/*
+ * ftime_start()
+ * create the file time hash table and open for read/write the scratch
+ * file. (after created it is unlinked, so when we exit we leave
+ * no witnesses).
+ * Return:
+ * 0 if the table and file was created ok, -1 otherwise
+ */
+
+int
+ftime_start(void)
+{
+
+ if (ftab != NULL)
+ return(0);
+ if ((ftab = (FTM **)calloc(F_TAB_SZ, sizeof(FTM *))) == NULL) {
+ paxwarn(1, "Cannot allocate memory for file time table");
+ return(-1);
+ }
+
+ /*
+ * get random name and create temporary scratch file, unlink name
+ * so it will get removed on exit
+ */
+ memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE));
+ if ((ffd = mkstemp(tempfile)) < 0) {
+ syswarn(1, errno, "Unable to create temporary file: %s",
+ tempfile);
+ return(-1);
+ }
+ (void)unlink(tempfile);
+
+ return(0);
+}
+
+/*
+ * chk_ftime()
+ * looks up entry in file time hash table. If not found, the file is
+ * added to the hash table and the file named stored in the scratch file.
+ * If a file with the same name is found, the file times are compared and
+ * the most recent file time is retained. If the new file was younger (or
+ * was not in the database) the new file is selected for storage.
+ * Return:
+ * 0 if file should be added to the archive, 1 if it should be skipped,
+ * -1 on error
+ */
+
+int
+chk_ftime(ARCHD *arcn)
+{
+ FTM *pt;
+ int namelen;
+ u_int indx;
+ char ckname[PAXPATHLEN+1];
+
+ /*
+ * no info, go ahead and add to archive
+ */
+ if (ftab == NULL)
+ return(0);
+
+ /*
+ * hash the pathname and look up in table
+ */
+ namelen = arcn->nlen;
+ indx = st_hash(arcn->name, namelen, F_TAB_SZ);
+ if ((pt = ftab[indx]) != NULL) {
+ /*
+ * the hash chain is not empty, walk down looking for match
+ * only read up the path names if the lengths match, speeds
+ * up the search a lot
+ */
+ while (pt != NULL) {
+ if (pt->namelen == namelen) {
+ /*
+ * potential match, have to read the name
+ * from the scratch file.
+ */
+ if (lseek(ffd,pt->seek,SEEK_SET) != pt->seek) {
+ syswarn(1, errno,
+ "Failed ftime table seek");
+ return(-1);
+ }
+ if (read(ffd, ckname, namelen) != namelen) {
+ syswarn(1, errno,
+ "Failed ftime table read");
+ return(-1);
+ }
+
+ /*
+ * if the names match, we are done
+ */
+ if (!strncmp(ckname, arcn->name, namelen))
+ break;
+ }
+
+ /*
+ * try the next entry on the chain
+ */
+ pt = pt->fow;
+ }
+
+ if (pt != NULL) {
+ /*
+ * found the file, compare the times, save the newer
+ */
+ if (arcn->sb.st_mtime > pt->mtime) {
+ /*
+ * file is newer
+ */
+ pt->mtime = arcn->sb.st_mtime;
+ return(0);
+ }
+ /*
+ * file is older
+ */
+ return(1);
+ }
+ }
+
+ /*
+ * not in table, add it
+ */
+ if ((pt = (FTM *)malloc(sizeof(FTM))) != NULL) {
+ /*
+ * add the name at the end of the scratch file, saving the
+ * offset. add the file to the head of the hash chain
+ */
+ if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) {
+ if (write(ffd, arcn->name, namelen) == namelen) {
+ pt->mtime = arcn->sb.st_mtime;
+ pt->namelen = namelen;
+ pt->fow = ftab[indx];
+ ftab[indx] = pt;
+ return(0);
+ }
+ syswarn(1, errno, "Failed write to file time table");
+ } else
+ syswarn(1, errno, "Failed seek on file time table");
+ } else
+ paxwarn(1, "File time table ran out of memory");
+
+ if (pt != NULL)
+ (void)free((char *)pt);
+ return(-1);
+}
+
+/*
+ * Interactive rename table routines
+ *
+ * The interactive rename table keeps track of the new names that the user
+ * assigns to files from tty input. Since this map is unique for each file
+ * we must store it in case there is a reference to the file later in archive
+ * (a link). Otherwise we will be unable to find the file we know was
+ * extracted. The remapping of these files is stored in a memory based hash
+ * table (it is assumed since input must come from /dev/tty, it is unlikely to
+ * be a very large table).
+ */
+
+/*
+ * name_start()
+ * create the interactive rename table
+ * Return:
+ * 0 if successful, -1 otherwise
+ */
+
+int
+name_start(void)
+{
+ if (ntab != NULL)
+ return(0);
+ if ((ntab = (NAMT **)calloc(N_TAB_SZ, sizeof(NAMT *))) == NULL) {
+ paxwarn(1, "Cannot allocate memory for interactive rename table");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * add_name()
+ * add the new name to old name mapping just created by the user.
+ * If an old name mapping is found (there may be duplicate names on an
+ * archive) only the most recent is kept.
+ * Return:
+ * 0 if added, -1 otherwise
+ */
+
+int
+add_name(char *oname, int onamelen, char *nname)
+{
+ NAMT *pt;
+ u_int indx;
+
+ if (ntab == NULL) {
+ /*
+ * should never happen
+ */
+ paxwarn(0, "No interactive rename table, links may fail");
+ return(0);
+ }
+
+ /*
+ * look to see if we have already mapped this file, if so we
+ * will update it
+ */
+ indx = st_hash(oname, onamelen, N_TAB_SZ);
+ if ((pt = ntab[indx]) != NULL) {
+ /*
+ * look down the has chain for the file
+ */
+ while ((pt != NULL) && (strcmp(oname, pt->oname) != 0))
+ pt = pt->fow;
+
+ if (pt != NULL) {
+ /*
+ * found an old mapping, replace it with the new one
+ * the user just input (if it is different)
+ */
+ if (strcmp(nname, pt->nname) == 0)
+ return(0);
+
+ (void)free((char *)pt->nname);
+ if ((pt->nname = strdup(nname)) == NULL) {
+ paxwarn(1, "Cannot update rename table");
+ return(-1);
+ }
+ return(0);
+ }
+ }
+
+ /*
+ * this is a new mapping, add it to the table
+ */
+ if ((pt = (NAMT *)malloc(sizeof(NAMT))) != NULL) {
+ if ((pt->oname = strdup(oname)) != NULL) {
+ if ((pt->nname = strdup(nname)) != NULL) {
+ pt->fow = ntab[indx];
+ ntab[indx] = pt;
+ return(0);
+ }
+ (void)free((char *)pt->oname);
+ }
+ (void)free((char *)pt);
+ }
+ paxwarn(1, "Interactive rename table out of memory");
+ return(-1);
+}
+
+/*
+ * sub_name()
+ * look up a link name to see if it points at a file that has been
+ * remapped by the user. If found, the link is adjusted to contain the
+ * new name (oname is the link to name)
+ */
+
+void
+sub_name(char *oname, int *onamelen, size_t onamesize)
+{
+ NAMT *pt;
+ u_int indx;
+
+ if (ntab == NULL)
+ return;
+ /*
+ * look the name up in the hash table
+ */
+ indx = st_hash(oname, *onamelen, N_TAB_SZ);
+ if ((pt = ntab[indx]) == NULL)
+ return;
+
+ while (pt != NULL) {
+ /*
+ * walk down the hash chain looking for a match
+ */
+ if (strcmp(oname, pt->oname) == 0) {
+ /*
+ * found it, replace it with the new name
+ * and return (we know that oname has enough space)
+ */
+ *onamelen = strlcpy(oname, pt->nname, onamesize);
+ if (*onamelen >= onamesize)
+ *onamelen = onamesize - 1; /* XXX truncate? */
+ return;
+ }
+ pt = pt->fow;
+ }
+
+ /*
+ * no match, just return
+ */
+ return;
+}
+
+/*
+ * device/inode mapping table routines
+ * (used with formats that store device and inodes fields)
+ *
+ * device/inode mapping tables remap the device field in a archive header. The
+ * device/inode fields are used to determine when files are hard links to each
+ * other. However these values have very little meaning outside of that. This
+ * database is used to solve one of two different problems.
+ *
+ * 1) when files are appended to an archive, while the new files may have hard
+ * links to each other, you cannot determine if they have hard links to any
+ * file already stored on the archive from a prior run of pax. We must assume
+ * that these inode/device pairs are unique only within a SINGLE run of pax
+ * (which adds a set of files to an archive). So we have to make sure the
+ * inode/dev pairs we add each time are always unique. We do this by observing
+ * while the inode field is very dense, the use of the dev field is fairly
+ * sparse. Within each run of pax, we remap any device number of a new archive
+ * member that has a device number used in a prior run and already stored in a
+ * file on the archive. During the read phase of the append, we store the
+ * device numbers used and mark them to not be used by any file during the
+ * write phase. If during write we go to use one of those old device numbers,
+ * we remap it to a new value.
+ *
+ * 2) Often the fields in the archive header used to store these values are
+ * too small to store the entire value. The result is an inode or device value
+ * which can be truncated. This really can foul up an archive. With truncation
+ * we end up creating links between files that are really not links (after
+ * truncation the inodes are the same value). We address that by detecting
+ * truncation and forcing a remap of the device field to split truncated
+ * inodes away from each other. Each truncation creates a pattern of bits that
+ * are removed. We use this pattern of truncated bits to partition the inodes
+ * on a single device to many different devices (each one represented by the
+ * truncated bit pattern). All inodes on the same device that have the same
+ * truncation pattern are mapped to the same new device. Two inodes that
+ * truncate to the same value clearly will always have different truncation
+ * bit patterns, so they will be split from away each other. When we spot
+ * device truncation we remap the device number to a non truncated value.
+ * (for more info see table.h for the data structures involved).
+ */
+
+/*
+ * dev_start()
+ * create the device mapping table
+ * Return:
+ * 0 if successful, -1 otherwise
+ */
+
+int
+dev_start(void)
+{
+ if (dtab != NULL)
+ return(0);
+ if ((dtab = (DEVT **)calloc(D_TAB_SZ, sizeof(DEVT *))) == NULL) {
+ paxwarn(1, "Cannot allocate memory for device mapping table");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * add_dev()
+ * add a device number to the table. this will force the device to be
+ * remapped to a new value if it be used during a write phase. This
+ * function is called during the read phase of an append to prohibit the
+ * use of any device number already in the archive.
+ * Return:
+ * 0 if added ok, -1 otherwise
+ */
+
+int
+add_dev(ARCHD *arcn)
+{
+ if (chk_dev(arcn->sb.st_dev, 1) == NULL)
+ return(-1);
+ return(0);
+}
+
+/*
+ * chk_dev()
+ * check for a device value in the device table. If not found and the add
+ * flag is set, it is added. This does NOT assign any mapping values, just
+ * adds the device number as one that need to be remapped. If this device
+ * is already mapped, just return with a pointer to that entry.
+ * Return:
+ * pointer to the entry for this device in the device map table. Null
+ * if the add flag is not set and the device is not in the table (it is
+ * not been seen yet). If add is set and the device cannot be added, null
+ * is returned (indicates an error).
+ */
+
+static DEVT *
+chk_dev(dev_t dev, int add)
+{
+ DEVT *pt;
+ u_int indx;
+
+ if (dtab == NULL)
+ return(NULL);
+ /*
+ * look to see if this device is already in the table
+ */
+ indx = ((unsigned)dev) % D_TAB_SZ;
+ if ((pt = dtab[indx]) != NULL) {
+ while ((pt != NULL) && (pt->dev != dev))
+ pt = pt->fow;
+
+ /*
+ * found it, return a pointer to it
+ */
+ if (pt != NULL)
+ return(pt);
+ }
+
+ /*
+ * not in table, we add it only if told to as this may just be a check
+ * to see if a device number is being used.
+ */
+ if (add == 0)
+ return(NULL);
+
+ /*
+ * allocate a node for this device and add it to the front of the hash
+ * chain. Note we do not assign remaps values here, so the pt->list
+ * list must be NULL.
+ */
+ if ((pt = (DEVT *)malloc(sizeof(DEVT))) == NULL) {
+ paxwarn(1, "Device map table out of memory");
+ return(NULL);
+ }
+ pt->dev = dev;
+ pt->list = NULL;
+ pt->fow = dtab[indx];
+ dtab[indx] = pt;
+ return(pt);
+}
+/*
+ * map_dev()
+ * given an inode and device storage mask (the mask has a 1 for each bit
+ * the archive format is able to store in a header), we check for inode
+ * and device truncation and remap the device as required. Device mapping
+ * can also occur when during the read phase of append a device number was
+ * seen (and was marked as do not use during the write phase). WE ASSUME
+ * that unsigned longs are the same size or bigger than the fields used
+ * for ino_t and dev_t. If not the types will have to be changed.
+ * Return:
+ * 0 if all ok, -1 otherwise.
+ */
+
+int
+map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask)
+{
+ DEVT *pt;
+ DLIST *dpt;
+ static dev_t lastdev = 0; /* next device number to try */
+ int trc_ino = 0;
+ int trc_dev = 0;
+ ino_t trunc_bits = 0;
+ ino_t nino;
+
+ if (dtab == NULL)
+ return(0);
+ /*
+ * check for device and inode truncation, and extract the truncated
+ * bit pattern.
+ */
+ if ((arcn->sb.st_dev & (dev_t)dev_mask) != arcn->sb.st_dev)
+ ++trc_dev;
+ if ((nino = arcn->sb.st_ino & (ino_t)ino_mask) != arcn->sb.st_ino) {
+ ++trc_ino;
+ trunc_bits = arcn->sb.st_ino & (ino_t)(~ino_mask);
+ }
+
+ /*
+ * see if this device is already being mapped, look up the device
+ * then find the truncation bit pattern which applies
+ */
+ if ((pt = chk_dev(arcn->sb.st_dev, 0)) != NULL) {
+ /*
+ * this device is already marked to be remapped
+ */
+ for (dpt = pt->list; dpt != NULL; dpt = dpt->fow)
+ if (dpt->trunc_bits == trunc_bits)
+ break;
+
+ if (dpt != NULL) {
+ /*
+ * we are being remapped for this device and pattern
+ * change the device number to be stored and return
+ */
+ arcn->sb.st_dev = dpt->dev;
+ arcn->sb.st_ino = nino;
+ return(0);
+ }
+ } else {
+ /*
+ * this device is not being remapped YET. if we do not have any
+ * form of truncation, we do not need a remap
+ */
+ if (!trc_ino && !trc_dev)
+ return(0);
+
+ /*
+ * we have truncation, have to add this as a device to remap
+ */
+ if ((pt = chk_dev(arcn->sb.st_dev, 1)) == NULL)
+ goto bad;
+
+ /*
+ * if we just have a truncated inode, we have to make sure that
+ * all future inodes that do not truncate (they have the
+ * truncation pattern of all 0's) continue to map to the same
+ * device number. We probably have already written inodes with
+ * this device number to the archive with the truncation
+ * pattern of all 0's. So we add the mapping for all 0's to the
+ * same device number.
+ */
+ if (!trc_dev && (trunc_bits != 0)) {
+ if ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL)
+ goto bad;
+ dpt->trunc_bits = 0;
+ dpt->dev = arcn->sb.st_dev;
+ dpt->fow = pt->list;
+ pt->list = dpt;
+ }
+ }
+
+ /*
+ * look for a device number not being used. We must watch for wrap
+ * around on lastdev (so we do not get stuck looking forever!)
+ */
+ while (++lastdev > 0) {
+ if (chk_dev(lastdev, 0) != NULL)
+ continue;
+ /*
+ * found an unused value. If we have reached truncation point
+ * for this format we are hosed, so we give up. Otherwise we
+ * mark it as being used.
+ */
+ if (((lastdev & ((dev_t)dev_mask)) != lastdev) ||
+ (chk_dev(lastdev, 1) == NULL))
+ goto bad;
+ break;
+ }
+
+ if ((lastdev <= 0) || ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL))
+ goto bad;
+
+ /*
+ * got a new device number, store it under this truncation pattern.
+ * change the device number this file is being stored with.
+ */
+ dpt->trunc_bits = trunc_bits;
+ dpt->dev = lastdev;
+ dpt->fow = pt->list;
+ pt->list = dpt;
+ arcn->sb.st_dev = lastdev;
+ arcn->sb.st_ino = nino;
+ return(0);
+
+ bad:
+ paxwarn(1, "Unable to fix truncated inode/device field when storing %s",
+ arcn->name);
+ paxwarn(0, "Archive may create improper hard links when extracted");
+ return(0);
+}
+
+/*
+ * directory access/mod time reset table routines (for directories READ by pax)
+ *
+ * The pax -t flag requires that access times of archive files be the same
+ * before being read by pax. For regular files, access time is restored after
+ * the file has been copied. This database provides the same functionality for
+ * directories read during file tree traversal. Restoring directory access time
+ * is more complex than files since directories may be read several times until
+ * all the descendants in their subtree are visited by fts. Directory access
+ * and modification times are stored during the fts pre-order visit (done
+ * before any descendants in the subtree are visited) and restored after the
+ * fts post-order visit (after all the descendants have been visited). In the
+ * case of premature exit from a subtree (like from the effects of -n), any
+ * directory entries left in this database are reset during final cleanup
+ * operations of pax. Entries are hashed by inode number for fast lookup.
+ */
+
+/*
+ * atdir_start()
+ * create the directory access time database for directories READ by pax.
+ * Return:
+ * 0 is created ok, -1 otherwise.
+ */
+
+int
+atdir_start(void)
+{
+ if (atab != NULL)
+ return(0);
+ if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) {
+ paxwarn(1,"Cannot allocate space for directory access time table");
+ return(-1);
+ }
+ return(0);
+}
+
+
+/*
+ * atdir_end()
+ * walk through the directory access time table and reset the access time
+ * of any directory who still has an entry left in the database. These
+ * entries are for directories READ by pax
+ */
+
+void
+atdir_end(void)
+{
+ ATDIR *pt;
+ int i;
+
+ if (atab == NULL)
+ return;
+ /*
+ * for each non-empty hash table entry reset all the directories
+ * chained there.
+ */
+ for (i = 0; i < A_TAB_SZ; ++i) {
+ if ((pt = atab[i]) == NULL)
+ continue;
+ /*
+ * remember to force the times, set_ftime() looks at pmtime
+ * and patime, which only applies to things CREATED by pax,
+ * not read by pax. Read time reset is controlled by -t.
+ */
+ for (; pt != NULL; pt = pt->fow)
+ set_ftime(pt->name, pt->mtime, pt->atime, 1);
+ }
+}
+
+/*
+ * add_atdir()
+ * add a directory to the directory access time table. Table is hashed
+ * and chained by inode number. This is for directories READ by pax
+ */
+
+void
+add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime)
+{
+ ATDIR *pt;
+ u_int indx;
+
+ if (atab == NULL)
+ return;
+
+ /*
+ * make sure this directory is not already in the table, if so just
+ * return (the older entry always has the correct time). The only
+ * way this will happen is when the same subtree can be traversed by
+ * different args to pax and the -n option is aborting fts out of a
+ * subtree before all the post-order visits have been made.
+ */
+ indx = ((unsigned)ino) % A_TAB_SZ;
+ if ((pt = atab[indx]) != NULL) {
+ while (pt != NULL) {
+ if ((pt->ino == ino) && (pt->dev == dev))
+ break;
+ pt = pt->fow;
+ }
+
+ /*
+ * oops, already there. Leave it alone.
+ */
+ if (pt != NULL)
+ return;
+ }
+
+ /*
+ * add it to the front of the hash chain
+ */
+ if ((pt = (ATDIR *)malloc(sizeof(ATDIR))) != NULL) {
+ if ((pt->name = strdup(fname)) != NULL) {
+ pt->dev = dev;
+ pt->ino = ino;
+ pt->mtime = mtime;
+ pt->atime = atime;
+ pt->fow = atab[indx];
+ atab[indx] = pt;
+ return;
+ }
+ (void)free((char *)pt);
+ }
+
+ paxwarn(1, "Directory access time reset table ran out of memory");
+ return;
+}
+
+/*
+ * get_atdir()
+ * look up a directory by inode and device number to obtain the access
+ * and modification time you want to set to. If found, the modification
+ * and access time parameters are set and the entry is removed from the
+ * table (as it is no longer needed). These are for directories READ by
+ * pax
+ * Return:
+ * 0 if found, -1 if not found.
+ */
+
+int
+get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime)
+{
+ ATDIR *pt;
+ ATDIR **ppt;
+ u_int indx;
+
+ if (atab == NULL)
+ return(-1);
+ /*
+ * hash by inode and search the chain for an inode and device match
+ */
+ indx = ((unsigned)ino) % A_TAB_SZ;
+ if ((pt = atab[indx]) == NULL)
+ return(-1);
+
+ ppt = &(atab[indx]);
+ while (pt != NULL) {
+ if ((pt->ino == ino) && (pt->dev == dev))
+ break;
+ /*
+ * no match, go to next one
+ */
+ ppt = &(pt->fow);
+ pt = pt->fow;
+ }
+
+ /*
+ * return if we did not find it.
+ */
+ if (pt == NULL)
+ return(-1);
+
+ /*
+ * found it. return the times and remove the entry from the table.
+ */
+ *ppt = pt->fow;
+ *mtime = pt->mtime;
+ *atime = pt->atime;
+ (void)free((char *)pt->name);
+ (void)free((char *)pt);
+ return(0);
+}
+
+/*
+ * directory access mode and time storage routines (for directories CREATED
+ * by pax).
+ *
+ * Pax requires that extracted directories, by default, have their access/mod
+ * times and permissions set to the values specified in the archive. During the
+ * actions of extracting (and creating the destination subtree during -rw copy)
+ * directories extracted may be modified after being created. Even worse is
+ * that these directories may have been created with file permissions which
+ * prohibits any descendants of these directories from being extracted. When
+ * directories are created by pax, access rights may be added to permit the
+ * creation of files in their subtree. Every time pax creates a directory, the
+ * times and file permissions specified by the archive are stored. After all
+ * files have been extracted (or copied), these directories have their times
+ * and file modes reset to the stored values. The directory info is restored in
+ * reverse order as entries were added to the data file from root to leaf. To
+ * restore atime properly, we must go backwards. The data file consists of
+ * records with two parts, the file name followed by a DIRDATA trailer. The
+ * fixed sized trailer contains the size of the name plus the off_t location in
+ * the file. To restore we work backwards through the file reading the trailer
+ * then the file name.
+ */
+
+/*
+ * dir_start()
+ * set up the directory time and file mode storage for directories CREATED
+ * by pax.
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+dir_start(void)
+{
+ if (dirp != NULL)
+ return(0);
+
+ dirsize = DIRP_SIZE;
+ if ((dirp = calloc(dirsize, sizeof(DIRDATA))) == NULL) {
+ paxwarn(1, "Unable to allocate memory for directory times");
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * add_dir()
+ * add the mode and times for a newly CREATED directory
+ * name is name of the directory, psb the stat buffer with the data in it,
+ * frc_mode is a flag that says whether to force the setting of the mode
+ * (ignoring the user set values for preserving file mode). Frc_mode is
+ * for the case where we created a file and found that the resulting
+ * directory was not writeable and the user asked for file modes to NOT
+ * be preserved. (we have to preserve what was created by default, so we
+ * have to force the setting at the end. this is stated explicitly in the
+ * pax spec)
+ */
+
+void
+add_dir(char *name, size_t nlen, struct stat *psb, int frc_mode)
+{
+ DIRDATA *dblk;
+ char realname[MAXPATHLEN], *rp;
+
+ if (dirp == NULL)
+ return;
+
+ if (havechd && *name != '/') {
+ if ((rp = realpath(name, realname)) == NULL) {
+ paxwarn(1, "Cannot canonicalize %s", name);
+ return;
+ }
+ name = rp;
+ }
+ if (dircnt == dirsize) {
+ dblk = realloc(dirp, 2 * dirsize * sizeof(DIRDATA));
+ if (dblk == NULL) {
+ paxwarn(1, "Unable to store mode and times for created"
+ " directory: %s", name);
+ return;
+ }
+ dirp = dblk;
+ dirsize *= 2;
+ }
+ dblk = &dirp[dircnt];
+ if ((dblk->name = strdup(name)) == NULL) {
+ paxwarn(1, "Unable to store mode and times for created"
+ " directory: %s", name);
+ return;
+ }
+ dblk->mode = psb->st_mode & 0xffff;
+ dblk->mtime = psb->st_mtime;
+ dblk->atime = psb->st_atime;
+ dblk->frc_mode = frc_mode;
+ ++dircnt;
+}
+
+/*
+ * proc_dir()
+ * process all file modes and times stored for directories CREATED
+ * by pax
+ */
+
+void
+proc_dir(void)
+{
+ DIRDATA *dblk;
+ long cnt;
+
+ if (dirp == NULL)
+ return;
+ /*
+ * read backwards through the file and process each directory
+ */
+ cnt = dircnt;
+ while (--cnt >= 0) {
+ /*
+ * frc_mode set, make sure we set the file modes even if
+ * the user didn't ask for it (see file_subs.c for more info)
+ */
+ dblk = &dirp[cnt];
+ if (pmode || dblk->frc_mode)
+ set_pmode(dblk->name, dblk->mode);
+ if (patime || pmtime)
+ set_ftime(dblk->name, dblk->mtime, dblk->atime, 0);
+ free(dblk->name);
+ }
+
+ free(dirp);
+ dirp = NULL;
+ dircnt = 0;
+}
+
+/*
+ * database independent routines
+ */
+
+/*
+ * st_hash()
+ * hashes filenames to a u_int for hashing into a table. Looks at the tail
+ * end of file, as this provides far better distribution than any other
+ * part of the name. For performance reasons we only care about the last
+ * MAXKEYLEN chars (should be at LEAST large enough to pick off the file
+ * name). Was tested on 500,000 name file tree traversal from the root
+ * and gave almost a perfectly uniform distribution of keys when used with
+ * prime sized tables (MAXKEYLEN was 128 in test). Hashes (sizeof int)
+ * chars at a time and pads with 0 for last addition.
+ * Return:
+ * the hash value of the string MOD (%) the table size.
+ */
+
+u_int
+st_hash(char *name, int len, int tabsz)
+{
+ char *pt;
+ char *dest;
+ char *end;
+ int i;
+ u_int key = 0;
+ int steps;
+ int res;
+ u_int val = 0;
+
+ /*
+ * only look at the tail up to MAXKEYLEN, we do not need to waste
+ * time here (remember these are pathnames, the tail is what will
+ * spread out the keys)
+ */
+ if (len > MAXKEYLEN) {
+ pt = &(name[len - MAXKEYLEN]);
+ len = MAXKEYLEN;
+ } else
+ pt = name;
+
+ /*
+ * calculate the number of u_int size steps in the string and if
+ * there is a runt to deal with
+ */
+ steps = len/sizeof(u_int);
+ res = len % sizeof(u_int);
+
+ /*
+ * add up the value of the string in unsigned integer sized pieces
+ * too bad we cannot have unsigned int aligned strings, then we
+ * could avoid the expensive copy.
+ */
+ for (i = 0; i < steps; ++i) {
+ end = pt + sizeof(u_int);
+ dest = (char *)&val;
+ while (pt < end)
+ *dest++ = *pt++;
+ key += val;
+ }
+
+ /*
+ * add in the runt padded with zero to the right
+ */
+ if (res) {
+ val = 0;
+ end = pt + res;
+ dest = (char *)&val;
+ while (pt < end)
+ *dest++ = *pt++;
+ key += val;
+ }
+
+ /*
+ * return the result mod the table size
+ */
+ return(key % tabsz);
+}
diff --git a/file_cmds/pax/tables.h b/file_cmds/pax/tables.h
new file mode 100644
index 0000000..3b1970f
--- /dev/null
+++ b/file_cmds/pax/tables.h
@@ -0,0 +1,175 @@
+/* $OpenBSD: tables.h,v 1.8 2006/08/05 23:05:13 ray Exp $ */
+/* $NetBSD: tables.h,v 1.3 1995/03/21 09:07:47 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tables.h 8.1 (Berkeley) 5/31/93
+ */
+
+#ifndef _TABLES_H_
+#define _TABLES_H_
+
+/*
+ * data structures and constants used by the different databases kept by pax
+ */
+
+/*
+ * Hash Table Sizes MUST BE PRIME, if set too small performance suffers.
+ * Probably safe to expect 500000 inodes per tape. Assuming good key
+ * distribution (inodes) chains of under 50 long (worst case) is ok.
+ */
+#define L_TAB_SZ 2503 /* hard link hash table size */
+#define F_TAB_SZ 50503 /* file time hash table size */
+#define N_TAB_SZ 541 /* interactive rename hash table */
+#define D_TAB_SZ 317 /* unique device mapping table */
+#define A_TAB_SZ 317 /* ftree dir access time reset table */
+#define MAXKEYLEN 64 /* max number of chars for hash */
+#define DIRP_SIZE 64 /* initial size of created dir table */
+
+/*
+ * file hard link structure (hashed by dev/ino and chained) used to find the
+ * hard links in a file system or with some archive formats (cpio)
+ */
+typedef struct hrdlnk {
+ char *name; /* name of first file seen with this ino/dev */
+ dev_t dev; /* files device number */
+ ino_t ino; /* files inode number */
+ u_long nlink; /* expected link count */
+ struct hrdlnk *fow;
+} HRDLNK;
+
+/*
+ * Archive write update file time table (the -u, -C flag), hashed by filename.
+ * Filenames are stored in a scratch file at seek offset into the file. The
+ * file time (mod time) and the file name length (for a quick check) are
+ * stored in a hash table node. We were forced to use a scratch file because
+ * with -u, the mtime for every node in the archive must always be available
+ * to compare against (and this data can get REALLY large with big archives).
+ * By being careful to read only when we have a good chance of a match, the
+ * performance loss is not measurable (and the size of the archive we can
+ * handle is greatly increased).
+ */
+typedef struct ftm {
+ int namelen; /* file name length */
+ time_t mtime; /* files last modification time */
+ off_t seek; /* location in scratch file */
+ struct ftm *fow;
+} FTM;
+
+/*
+ * Interactive rename table (-i flag), hashed by orig filename.
+ * We assume this will not be a large table as this mapping data can only be
+ * obtained through interactive input by the user. Nobody is going to type in
+ * changes for 500000 files? We use chaining to resolve collisions.
+ */
+
+typedef struct namt {
+ char *oname; /* old name */
+ char *nname; /* new name typed in by the user */
+ struct namt *fow;
+} NAMT;
+
+/*
+ * Unique device mapping tables. Some protocols (e.g. cpio) require that the
+ * <c_dev,c_ino> pair will uniquely identify a file in an archive unless they
+ * are links to the same file. Appending to archives can break this. For those
+ * protocols that have this requirement we map c_dev to a unique value not seen
+ * in the archive when we append. We also try to handle inode truncation with
+ * this table. (When the inode field in the archive header are too small, we
+ * remap the dev on writes to remove accidental collisions).
+ *
+ * The list is hashed by device number using chain collision resolution. Off of
+ * each DEVT are linked the various remaps for this device based on those bits
+ * in the inode which were truncated. For example if we are just remapping to
+ * avoid a device number during an update append, off the DEVT we would have
+ * only a single DLIST that has a truncation id of 0 (no inode bits were
+ * stripped for this device so far). When we spot inode truncation we create
+ * a new mapping based on the set of bits in the inode which were stripped off.
+ * so if the top four bits of the inode are stripped and they have a pattern of
+ * 0110...... (where . are those bits not truncated) we would have a mapping
+ * assigned for all inodes that has the same 0110.... pattern (with this dev
+ * number of course). This keeps the mapping sparse and should be able to store
+ * close to the limit of files which can be represented by the optimal
+ * combination of dev and inode bits, and without creating a fouled up archive.
+ * Note we also remap truncated devs in the same way (an exercise for the
+ * dedicated reader; always wanted to say that...:)
+ */
+
+typedef struct devt {
+ dev_t dev; /* the orig device number we now have to map */
+ struct devt *fow; /* new device map list */
+ struct dlist *list; /* map list based on inode truncation bits */
+} DEVT;
+
+typedef struct dlist {
+ ino_t trunc_bits; /* truncation pattern for a specific map */
+ dev_t dev; /* the new device id we use */
+ struct dlist *fow;
+} DLIST;
+
+/*
+ * ftree directory access time reset table. When we are done with a
+ * subtree we reset the access and mod time of the directory when the tflag is
+ * set. Not really explicitly specified in the pax spec, but easy and fast to
+ * do (and this may have even been intended in the spec, it is not clear).
+ * table is hashed by inode with chaining.
+ */
+
+typedef struct atdir {
+ char *name; /* name of directory to reset */
+ dev_t dev; /* dev and inode for fast lookup */
+ ino_t ino;
+ time_t mtime; /* access and mod time to reset to */
+ time_t atime;
+ struct atdir *fow;
+} ATDIR;
+
+/*
+ * created directory time and mode storage entry. After pax is finished during
+ * extraction or copy, we must reset directory access modes and times that
+ * may have been modified after creation (they no longer have the specified
+ * times and/or modes). We must reset time in the reverse order of creation,
+ * because entries are added from the top of the file tree to the bottom.
+ * We MUST reset times from leaf to root (it will not work the other
+ * direction).
+ */
+
+typedef struct dirdata {
+ char *name; /* file name */
+ time_t mtime; /* mtime to set */
+ time_t atime; /* atime to set */
+ u_int16_t mode; /* file mode to restore */
+ u_int16_t frc_mode; /* do we force mode settings? */
+} DIRDATA;
+
+#endif /* _TABLES_H_ */
diff --git a/file_cmds/pax/tar.c b/file_cmds/pax/tar.c
new file mode 100644
index 0000000..360541f
--- /dev/null
+++ b/file_cmds/pax/tar.c
@@ -0,0 +1,1206 @@
+/* $OpenBSD: tar.c,v 1.41 2006/03/04 20:24:55 otto Exp $ */
+/* $NetBSD: tar.c,v 1.5 1995/03/21 09:07:49 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)tar.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: tar.c,v 1.41 2006/03/04 20:24:55 otto Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pax.h"
+#include "extern.h"
+#include "tar.h"
+
+/*
+ * Routines for reading, writing and header identify of various versions of tar
+ */
+
+static size_t expandname(char *, size_t, char **, const char *, size_t);
+static u_long tar_chksm(char *, int);
+static char *name_split(char *, int);
+static int ul_oct(u_long, char *, int, int);
+#ifndef LONG_OFF_T
+static int uqd_oct(u_quad_t, char *, int, int);
+#endif
+
+static uid_t uid_nobody;
+static uid_t uid_warn;
+static gid_t gid_nobody;
+static gid_t gid_warn;
+
+/*
+ * Routines common to all versions of tar
+ */
+
+static int tar_nodir; /* do not write dirs under old tar */
+char *gnu_name_string; /* GNU ././@LongLink hackery name */
+char *gnu_link_string; /* GNU ././@LongLink hackery link */
+
+/*
+ * tar_endwr()
+ * add the tar trailer of two null blocks
+ * Return:
+ * 0 if ok, -1 otherwise (what wr_skip returns)
+ */
+
+int
+tar_endwr(void)
+{
+ return(wr_skip((off_t)(NULLCNT*BLKMULT)));
+}
+
+/*
+ * tar_endrd()
+ * no cleanup needed here, just return size of trailer (for append)
+ * Return:
+ * size of trailer (2 * BLKMULT)
+ */
+
+off_t
+tar_endrd(void)
+{
+ return((off_t)(NULLCNT*BLKMULT));
+}
+
+/*
+ * tar_trail()
+ * Called to determine if a header block is a valid trailer. We are passed
+ * the block, the in_sync flag (which tells us we are in resync mode;
+ * looking for a valid header), and cnt (which starts at zero) which is
+ * used to count the number of empty blocks we have seen so far.
+ * Return:
+ * 0 if a valid trailer, -1 if not a valid trailer, or 1 if the block
+ * could never contain a header.
+ */
+
+int
+tar_trail(ARCHD *ignore, char *buf, int in_resync, int *cnt)
+{
+ int i;
+
+ /*
+ * look for all zero, trailer is two consecutive blocks of zero
+ */
+ for (i = 0; i < BLKMULT; ++i) {
+ if (buf[i] != '\0')
+ break;
+ }
+
+ /*
+ * if not all zero it is not a trailer, but MIGHT be a header.
+ */
+ if (i != BLKMULT)
+ return(-1);
+
+ /*
+ * When given a zero block, we must be careful!
+ * If we are not in resync mode, check for the trailer. Have to watch
+ * out that we do not mis-identify file data as the trailer, so we do
+ * NOT try to id a trailer during resync mode. During resync mode we
+ * might as well throw this block out since a valid header can NEVER be
+ * a block of all 0 (we must have a valid file name).
+ */
+ if (!in_resync && (++*cnt >= NULLCNT))
+ return(0);
+ return(1);
+}
+
+/*
+ * ul_oct()
+ * convert an unsigned long to an octal string. many oddball field
+ * termination characters are used by the various versions of tar in the
+ * different fields. term selects which kind to use. str is '0' padded
+ * at the front to len. we are unable to use only one format as many old
+ * tar readers are very cranky about this.
+ * Return:
+ * 0 if the number fit into the string, -1 otherwise
+ */
+
+static int
+ul_oct(u_long val, char *str, int len, int term)
+{
+ char *pt;
+
+ /*
+ * term selects the appropriate character(s) for the end of the string
+ */
+ pt = str + len - 1;
+ switch (term) {
+ case 3:
+ *pt-- = '\0';
+ break;
+ case 2:
+ *pt-- = ' ';
+ *pt-- = '\0';
+ break;
+ case 1:
+ *pt-- = ' ';
+ break;
+ case 0:
+ default:
+ *pt-- = '\0';
+ *pt-- = ' ';
+ break;
+ }
+
+ /*
+ * convert and blank pad if there is space
+ */
+ while (pt >= str) {
+ *pt-- = '0' + (char)(val & 0x7);
+ if ((val = val >> 3) == (u_long)0)
+ break;
+ }
+
+ while (pt >= str)
+ *pt-- = '0';
+ if (val != (u_long)0)
+ return(-1);
+ return(0);
+}
+
+#ifndef LONG_OFF_T
+/*
+ * uqd_oct()
+ * convert an u_quad_t to an octal string. one of many oddball field
+ * termination characters are used by the various versions of tar in the
+ * different fields. term selects which kind to use. str is '0' padded
+ * at the front to len. we are unable to use only one format as many old
+ * tar readers are very cranky about this.
+ * Return:
+ * 0 if the number fit into the string, -1 otherwise
+ */
+
+static int
+uqd_oct(u_quad_t val, char *str, int len, int term)
+{
+ char *pt;
+
+ /*
+ * term selects the appropriate character(s) for the end of the string
+ */
+ pt = str + len - 1;
+ switch (term) {
+ case 3:
+ *pt-- = '\0';
+ break;
+ case 2:
+ *pt-- = ' ';
+ *pt-- = '\0';
+ break;
+ case 1:
+ *pt-- = ' ';
+ break;
+ case 0:
+ default:
+ *pt-- = '\0';
+ *pt-- = ' ';
+ break;
+ }
+
+ /*
+ * convert and blank pad if there is space
+ */
+ while (pt >= str) {
+ *pt-- = '0' + (char)(val & 0x7);
+ if ((val = val >> 3) == 0)
+ break;
+ }
+
+ while (pt >= str)
+ *pt-- = '0';
+ if (val != (u_quad_t)0)
+ return(-1);
+ return(0);
+}
+#endif
+
+/*
+ * tar_chksm()
+ * calculate the checksum for a tar block counting the checksum field as
+ * all blanks (BLNKSUM is that value pre-calculated, the sum of 8 blanks).
+ * NOTE: we use len to short circuit summing 0's on write since we ALWAYS
+ * pad headers with 0.
+ * Return:
+ * unsigned long checksum
+ */
+
+static u_long
+tar_chksm(char *blk, int len)
+{
+ char *stop;
+ char *pt;
+ u_long chksm = BLNKSUM; /* initial value is checksum field sum */
+
+ /*
+ * add the part of the block before the checksum field
+ */
+ pt = blk;
+ stop = blk + CHK_OFFSET;
+ while (pt < stop)
+ chksm += (u_long)(*pt++ & 0xff);
+ /*
+ * move past the checksum field and keep going, spec counts the
+ * checksum field as the sum of 8 blanks (which is pre-computed as
+ * BLNKSUM).
+ * ASSUMED: len is greater than CHK_OFFSET. (len is where our 0 padding
+ * starts, no point in summing zero's)
+ */
+ pt += CHK_LEN;
+ stop = blk + len;
+ while (pt < stop)
+ chksm += (u_long)(*pt++ & 0xff);
+ return(chksm);
+}
+
+/*
+ * Routines for old BSD style tar (also made portable to sysV tar)
+ */
+
+/*
+ * tar_id()
+ * determine if a block given to us is a valid tar header (and not a USTAR
+ * header). We have to be on the lookout for those pesky blocks of all
+ * zero's.
+ * Return:
+ * 0 if a tar header, -1 otherwise
+ */
+
+int
+tar_id(char *blk, int size)
+{
+ HD_TAR *hd;
+ HD_USTAR *uhd;
+
+ if (size < BLKMULT)
+ return(-1);
+ hd = (HD_TAR *)blk;
+ uhd = (HD_USTAR *)blk;
+
+ /*
+ * check for block of zero's first, a simple and fast test, then make
+ * sure this is not a ustar header by looking for the ustar magic
+ * cookie. We should use TMAGLEN, but some USTAR archive programs are
+ * wrong and create archives missing the \0. Last we check the
+ * checksum. If this is ok we have to assume it is a valid header.
+ */
+ if (hd->name[0] == '\0')
+ return(-1);
+ if (strncmp(uhd->magic, TMAGIC, TMAGLEN - 1) == 0)
+ return(-1);
+ if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
+ return(-1);
+ force_one_volume = 1;
+ return(0);
+}
+
+/*
+ * tar_opt()
+ * handle tar format specific -o options
+ * Return:
+ * 0 if ok -1 otherwise
+ */
+
+int
+tar_opt(void)
+{
+ OPLIST *opt;
+
+ while ((opt = opt_next()) != NULL) {
+ if (strcmp(opt->name, TAR_OPTION) ||
+ strcmp(opt->value, TAR_NODIR)) {
+ paxwarn(1, "Unknown tar format -o option/value pair %s=%s",
+ opt->name, opt->value);
+ paxwarn(1,"%s=%s is the only supported tar format option",
+ TAR_OPTION, TAR_NODIR);
+ return(-1);
+ }
+
+ /*
+ * we only support one option, and only when writing
+ */
+ if ((act != APPND) && (act != ARCHIVE)) {
+ paxwarn(1, "%s=%s is only supported when writing.",
+ opt->name, opt->value);
+ return(-1);
+ }
+ tar_nodir = 1;
+ }
+ return(0);
+}
+
+
+/*
+ * tar_rd()
+ * extract the values out of block already determined to be a tar header.
+ * store the values in the ARCHD parameter.
+ * Return:
+ * 0
+ */
+
+int
+tar_rd(ARCHD *arcn, char *buf)
+{
+ HD_TAR *hd;
+ char *pt;
+
+ /*
+ * we only get proper sized buffers passed to us
+ */
+ if (tar_id(buf, BLKMULT) < 0)
+ return(-1);
+ memset(arcn, 0, sizeof(*arcn));
+ arcn->org_name = arcn->name;
+ arcn->sb.st_nlink = 1;
+
+ /*
+ * copy out the name and values in the stat buffer
+ */
+ hd = (HD_TAR *)buf;
+ if (hd->linkflag != LONGLINKTYPE && hd->linkflag != LONGNAMETYPE) {
+ arcn->nlen = expandname(arcn->name, sizeof(arcn->name),
+ &gnu_name_string, hd->name, sizeof(hd->name));
+ arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name),
+ &gnu_link_string, hd->linkname, sizeof(hd->linkname));
+ }
+ arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode,sizeof(hd->mode),OCT) &
+ 0xfff);
+ arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
+ arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
+#ifdef LONG_OFF_T
+ arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
+#else
+ arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
+#endif
+ arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
+ arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+
+ /*
+ * have to look at the last character, it may be a '/' and that is used
+ * to encode this as a directory
+ */
+ pt = &(arcn->name[arcn->nlen - 1]);
+ arcn->pad = 0;
+ arcn->skip = 0;
+ switch (hd->linkflag) {
+ case SYMTYPE:
+ /*
+ * symbolic link, need to get the link name and set the type in
+ * the st_mode so -v printing will look correct.
+ */
+ arcn->type = PAX_SLK;
+ arcn->sb.st_mode |= S_IFLNK;
+ arcn->ln_nlen = strlcpy(arcn->ln_name, hd->linkname, sizeof(arcn->ln_name));
+ break;
+ case LNKTYPE:
+ /*
+ * hard link, need to get the link name, set the type in the
+ * st_mode and st_nlink so -v printing will look better.
+ */
+ arcn->type = PAX_HLK;
+ arcn->sb.st_nlink = 2;
+ arcn->ln_nlen = strlcpy(arcn->ln_name, hd->linkname, sizeof(arcn->ln_name));
+
+ /*
+ * no idea of what type this thing really points at, but
+ * we set something for printing only.
+ */
+ arcn->sb.st_mode |= S_IFREG;
+ break;
+ case LONGLINKTYPE:
+ case LONGNAMETYPE:
+ /*
+ * GNU long link/file; we tag these here and let the
+ * pax internals deal with it -- too ugly otherwise.
+ */
+ arcn->type =
+ hd->linkflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF;
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+ arcn->skip = arcn->sb.st_size;
+ break;
+ case DIRTYPE:
+ /*
+ * It is a directory, set the mode for -v printing
+ */
+ arcn->type = PAX_DIR;
+ arcn->sb.st_mode |= S_IFDIR;
+ arcn->sb.st_nlink = 2;
+ break;
+ case AREGTYPE:
+ case REGTYPE:
+ default:
+ /*
+ * If we have a trailing / this is a directory and NOT a file.
+ */
+ arcn->ln_name[0] = '\0';
+ arcn->ln_nlen = 0;
+ if (*pt == '/') {
+ /*
+ * it is a directory, set the mode for -v printing
+ */
+ arcn->type = PAX_DIR;
+ arcn->sb.st_mode |= S_IFDIR;
+ arcn->sb.st_nlink = 2;
+ } else {
+ /*
+ * have a file that will be followed by data. Set the
+ * skip value to the size field and calculate the size
+ * of the padding.
+ */
+ arcn->type = PAX_REG;
+ arcn->sb.st_mode |= S_IFREG;
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+ arcn->skip = arcn->sb.st_size;
+ }
+ break;
+ }
+
+ /*
+ * strip off any trailing slash.
+ */
+ if (*pt == '/') {
+ *pt = '\0';
+ --arcn->nlen;
+ }
+ return(0);
+}
+
+/*
+ * tar_wr()
+ * write a tar header for the file specified in the ARCHD to the archive.
+ * Have to check for file types that cannot be stored and file names that
+ * are too long. Be careful of the term (last arg) to ul_oct, each field
+ * of tar has it own spec for the termination character(s).
+ * ASSUMED: space after header in header block is zero filled
+ * Return:
+ * 0 if file has data to be written after the header, 1 if file has NO
+ * data to write after the header, -1 if archive write failed
+ */
+
+int
+tar_wr(ARCHD *arcn)
+{
+ HD_TAR *hd;
+ int len;
+ HD_TAR hdblk;
+
+ /*
+ * check for those file system types which tar cannot store
+ */
+ switch (arcn->type) {
+ case PAX_DIR:
+ /*
+ * user asked that dirs not be written to the archive
+ */
+ if (tar_nodir)
+ return(1);
+ break;
+ case PAX_CHR:
+ paxwarn(1, "Tar cannot archive a character device %s",
+ arcn->org_name);
+ return(1);
+ case PAX_BLK:
+ paxwarn(1, "Tar cannot archive a block device %s", arcn->org_name);
+ return(1);
+ case PAX_SCK:
+ paxwarn(1, "Tar cannot archive a socket %s", arcn->org_name);
+ return(1);
+ case PAX_FIF:
+ paxwarn(1, "Tar cannot archive a fifo %s", arcn->org_name);
+ return(1);
+ case PAX_SLK:
+ case PAX_HLK:
+ case PAX_HRG:
+ if (arcn->ln_nlen >= sizeof(hd->linkname)) {
+ paxwarn(1, "Link name too long for tar %s",
+ arcn->ln_name);
+ return(1);
+ }
+ break;
+ case PAX_REG:
+ case PAX_CTG:
+ default:
+ break;
+ }
+
+ /*
+ * check file name len, remember extra char for dirs (the / at the end)
+ */
+ len = arcn->nlen;
+ if (arcn->type == PAX_DIR)
+ ++len;
+ if (len >= sizeof(hd->name)) {
+ paxwarn(1, "File name too long for tar %s", arcn->name);
+ return(1);
+ }
+
+ /*
+ * Copy the data out of the ARCHD into the tar header based on the type
+ * of the file. Remember, many tar readers want all fields to be
+ * padded with zero so we zero the header first. We then set the
+ * linkflag field (type), the linkname, the size, and set the padding
+ * (if any) to be added after the file data (0 for all other types,
+ * as they only have a header).
+ */
+ memset(&hdblk, 0, sizeof(hdblk));
+ hd = (HD_TAR *)&hdblk;
+ strlcpy(hd->name, arcn->name, sizeof(hd->name));
+ arcn->pad = 0;
+
+ if (arcn->type == PAX_DIR) {
+ /*
+ * directories are the same as files, except have a filename
+ * that ends with a /, we add the slash here. No data follows
+ * dirs, so no pad.
+ */
+ hd->linkflag = AREGTYPE;
+ hd->name[len-1] = '/';
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
+ goto out;
+ } else if (arcn->type == PAX_SLK) {
+ /*
+ * no data follows this file, so no pad
+ */
+ hd->linkflag = SYMTYPE;
+ strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname));
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
+ goto out;
+ } else if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) {
+ /*
+ * no data follows this file, so no pad
+ */
+ hd->linkflag = LNKTYPE;
+ strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname));
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), 1))
+ goto out;
+ } else {
+ /*
+ * data follows this file, so set the pad
+ */
+ hd->linkflag = AREGTYPE;
+# ifdef LONG_OFF_T
+ if (ul_oct((u_long)arcn->sb.st_size, hd->size,
+ sizeof(hd->size), 1)) {
+# else
+ if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
+ sizeof(hd->size), 1)) {
+# endif
+ paxwarn(1,"File is too large for tar %s", arcn->org_name);
+ return(1);
+ }
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+ }
+
+ /*
+ * copy those fields that are independent of the type
+ */
+ if (ul_oct((u_long)arcn->sb.st_mode, hd->mode, sizeof(hd->mode), 0) ||
+ ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), 0) ||
+ ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), 0) ||
+ ul_oct((u_long)arcn->sb.st_mtime, hd->mtime, sizeof(hd->mtime), 1))
+ goto out;
+
+ /*
+ * calculate and add the checksum, then write the header. A return of
+ * 0 tells the caller to now write the file data, 1 says no data needs
+ * to be written
+ */
+ if (ul_oct(tar_chksm((char *)&hdblk, sizeof(HD_TAR)), hd->chksum,
+ sizeof(hd->chksum), 3))
+ goto out;
+ if (wr_rdbuf((char *)&hdblk, sizeof(HD_TAR)) < 0)
+ return(-1);
+ if (wr_skip((off_t)(BLKMULT - sizeof(HD_TAR))) < 0)
+ return(-1);
+ if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
+ return(0);
+ return(1);
+
+ out:
+ /*
+ * header field is out of range
+ */
+ paxwarn(1, "Tar header field is too small for %s", arcn->org_name);
+ return(1);
+}
+
+/*
+ * Routines for POSIX ustar
+ */
+
+/*
+ * ustar_strd()
+ * initialization for ustar read
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+ustar_strd(void)
+{
+ if ((usrtb_start() < 0) || (grptb_start() < 0))
+ return(-1);
+ return(0);
+}
+
+/*
+ * ustar_stwr()
+ * initialization for ustar write
+ * Return:
+ * 0 if ok, -1 otherwise
+ */
+
+int
+ustar_stwr(void)
+{
+ if ((uidtb_start() < 0) || (gidtb_start() < 0))
+ return(-1);
+ return(0);
+}
+
+/*
+ * ustar_id()
+ * determine if a block given to us is a valid ustar header. We have to
+ * be on the lookout for those pesky blocks of all zero's
+ * Return:
+ * 0 if a ustar header, -1 otherwise
+ */
+
+int
+ustar_id(char *blk, int size)
+{
+ HD_USTAR *hd;
+
+ if (size < BLKMULT)
+ return(-1);
+ hd = (HD_USTAR *)blk;
+
+ /*
+ * check for block of zero's first, a simple and fast test then check
+ * ustar magic cookie. We should use TMAGLEN, but some USTAR archive
+ * programs are fouled up and create archives missing the \0. Last we
+ * check the checksum. If ok we have to assume it is a valid header.
+ */
+ if (hd->name[0] == '\0')
+ return(-1);
+ if (strncmp(hd->magic, TMAGIC, TMAGLEN - 1) != 0)
+ return(-1);
+ if (asc_ul(hd->chksum,sizeof(hd->chksum),OCT) != tar_chksm(blk,BLKMULT))
+ return(-1);
+ return(0);
+}
+
+/*
+ * ustar_rd()
+ * extract the values out of block already determined to be a ustar header.
+ * store the values in the ARCHD parameter.
+ * Return:
+ * 0
+ */
+
+int
+ustar_rd(ARCHD *arcn, char *buf)
+{
+ HD_USTAR *hd;
+ char *dest;
+ int cnt = 0;
+ dev_t devmajor;
+ dev_t devminor;
+
+ /*
+ * we only get proper sized buffers
+ */
+ if (ustar_id(buf, BLKMULT) < 0)
+ return(-1);
+ memset(arcn, 0, sizeof(*arcn));
+ arcn->org_name = arcn->name;
+ arcn->sb.st_nlink = 1;
+ hd = (HD_USTAR *)buf;
+
+ /*
+ * see if the filename is split into two parts. if, so joint the parts.
+ * we copy the prefix first and add a / between the prefix and name.
+ */
+ dest = arcn->name;
+ if (*(hd->prefix) != '\0') {
+ cnt = strlcpy(dest, hd->prefix, sizeof(arcn->name) - 1);
+ dest += cnt;
+ *dest++ = '/';
+ cnt++;
+ } else {
+ cnt = 0;
+ }
+
+ if (hd->typeflag != LONGLINKTYPE && hd->typeflag != LONGNAMETYPE) {
+ arcn->nlen = cnt + expandname(dest, sizeof(arcn->name) - cnt,
+ &gnu_name_string, hd->name, sizeof(hd->name));
+ arcn->ln_nlen = expandname(arcn->ln_name, sizeof(arcn->ln_name),
+ &gnu_link_string, hd->linkname, sizeof(hd->linkname));
+ }
+
+ /*
+ * follow the spec to the letter. we should only have mode bits, strip
+ * off all other crud we may be passed.
+ */
+ arcn->sb.st_mode = (mode_t)(asc_ul(hd->mode, sizeof(hd->mode), OCT) &
+ 0xfff);
+#ifdef LONG_OFF_T
+ arcn->sb.st_size = (off_t)asc_ul(hd->size, sizeof(hd->size), OCT);
+#else
+ arcn->sb.st_size = (off_t)asc_uqd(hd->size, sizeof(hd->size), OCT);
+#endif
+ arcn->sb.st_mtime = (time_t)asc_ul(hd->mtime, sizeof(hd->mtime), OCT);
+ arcn->sb.st_ctime = arcn->sb.st_atime = arcn->sb.st_mtime;
+
+ /*
+ * If we can find the ascii names for gname and uname in the password
+ * and group files we will use the uid's and gid they bind. Otherwise
+ * we use the uid and gid values stored in the header. (This is what
+ * the POSIX spec wants).
+ */
+ hd->gname[sizeof(hd->gname) - 1] = '\0';
+ if (gid_name(hd->gname, &(arcn->sb.st_gid)) < 0)
+ arcn->sb.st_gid = (gid_t)asc_ul(hd->gid, sizeof(hd->gid), OCT);
+ hd->uname[sizeof(hd->uname) - 1] = '\0';
+ if (uid_name(hd->uname, &(arcn->sb.st_uid)) < 0)
+ arcn->sb.st_uid = (uid_t)asc_ul(hd->uid, sizeof(hd->uid), OCT);
+
+ /*
+ * set the defaults, these may be changed depending on the file type
+ */
+ arcn->pad = 0;
+ arcn->skip = 0;
+ arcn->sb.st_rdev = (dev_t)0;
+
+ /*
+ * set the mode and PAX type according to the typeflag in the header
+ */
+ switch (hd->typeflag) {
+ case FIFOTYPE:
+ arcn->type = PAX_FIF;
+ arcn->sb.st_mode |= S_IFIFO;
+ break;
+ case DIRTYPE:
+ arcn->type = PAX_DIR;
+ arcn->sb.st_mode |= S_IFDIR;
+ arcn->sb.st_nlink = 2;
+
+ /*
+ * Some programs that create ustar archives append a '/'
+ * to the pathname for directories. This clearly violates
+ * ustar specs, but we will silently strip it off anyway.
+ */
+ if (arcn->name[arcn->nlen - 1] == '/')
+ arcn->name[--arcn->nlen] = '\0';
+ break;
+ case BLKTYPE:
+ case CHRTYPE:
+ /*
+ * this type requires the rdev field to be set.
+ */
+ if (hd->typeflag == BLKTYPE) {
+ arcn->type = PAX_BLK;
+ arcn->sb.st_mode |= S_IFBLK;
+ } else {
+ arcn->type = PAX_CHR;
+ arcn->sb.st_mode |= S_IFCHR;
+ }
+ devmajor = (dev_t)asc_ul(hd->devmajor,sizeof(hd->devmajor),OCT);
+ devminor = (dev_t)asc_ul(hd->devminor,sizeof(hd->devminor),OCT);
+ arcn->sb.st_rdev = TODEV(devmajor, devminor);
+ break;
+ case SYMTYPE:
+ case LNKTYPE:
+ if (hd->typeflag == SYMTYPE) {
+ arcn->type = PAX_SLK;
+ arcn->sb.st_mode |= S_IFLNK;
+ } else {
+ arcn->type = PAX_HLK;
+ /*
+ * so printing looks better
+ */
+ arcn->sb.st_mode |= S_IFREG;
+ arcn->sb.st_nlink = 2;
+ }
+ break;
+ case LONGLINKTYPE:
+ case LONGNAMETYPE:
+ /*
+ * GNU long link/file; we tag these here and let the
+ * pax internals deal with it -- too ugly otherwise.
+ */
+ arcn->type =
+ hd->typeflag == LONGLINKTYPE ? PAX_GLL : PAX_GLF;
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+ arcn->skip = arcn->sb.st_size;
+ break;
+ case CONTTYPE:
+ case AREGTYPE:
+ case REGTYPE:
+ default:
+ /*
+ * these types have file data that follows. Set the skip and
+ * pad fields.
+ */
+ arcn->type = PAX_REG;
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+ arcn->skip = arcn->sb.st_size;
+ arcn->sb.st_mode |= S_IFREG;
+ break;
+ }
+ return(0);
+}
+
+/*
+ * ustar_wr()
+ * write a ustar header for the file specified in the ARCHD to the archive
+ * Have to check for file types that cannot be stored and file names that
+ * are too long. Be careful of the term (last arg) to ul_oct, we only use
+ * '\0' for the termination character (this is different than picky tar)
+ * ASSUMED: space after header in header block is zero filled
+ * Return:
+ * 0 if file has data to be written after the header, 1 if file has NO
+ * data to write after the header, -1 if archive write failed
+ */
+
+int
+ustar_wr(ARCHD *arcn)
+{
+ HD_USTAR *hd;
+ char *pt;
+ char hdblk[sizeof(HD_USTAR)];
+ mode_t mode12only;
+ int term_char=3; /* orignal setting */
+ term_char=1; /* To pass conformance tests 274, 301 */
+
+ /*
+ * check for those file system types ustar cannot store
+ */
+ if (arcn->type == PAX_SCK) {
+ paxwarn(1, "Ustar cannot archive a socket %s", arcn->org_name);
+ return(1);
+ }
+
+ /*
+ * check the length of the linkname
+ */
+ if (((arcn->type == PAX_SLK) || (arcn->type == PAX_HLK) ||
+ (arcn->type == PAX_HRG)) && (arcn->ln_nlen > sizeof(hd->linkname))){
+ paxwarn(1, "Link name too long for ustar %s", arcn->ln_name);
+ /*
+ * Conformance: test pax:285 wants error code to be non-zero, and
+ * test tar:12 wants error code from pax to be 0
+ */
+ return(1);
+ }
+
+ /*
+ * split the path name into prefix and name fields (if needed). if
+ * pt != arcn->name, the name has to be split
+ */
+ if ((pt = name_split(arcn->name, arcn->nlen)) == NULL) {
+ paxwarn(1, "File name too long for ustar %s", arcn->name);
+ return(1);
+ }
+
+ /*
+ * zero out the header so we don't have to worry about zero fill below
+ */
+ memset(hdblk, 0, sizeof(hdblk));
+ hd = (HD_USTAR *)hdblk;
+ arcn->pad = 0L;
+
+ /* To pass conformance tests 274/301, always set these fields to "zero" */
+ ul_oct(0, hd->devmajor, sizeof(hd->devmajor), term_char);
+ ul_oct(0, hd->devminor, sizeof(hd->devminor), term_char);
+
+ /*
+ * split the name, or zero out the prefix
+ */
+ if (pt != arcn->name) {
+ /*
+ * name was split, pt points at the / where the split is to
+ * occur, we remove the / and copy the first part to the prefix
+ */
+ *pt = '\0';
+ strlcpy(hd->prefix, arcn->name, sizeof(hd->prefix));
+ *pt++ = '/';
+ }
+
+ /*
+ * copy the name part. this may be the whole path or the part after
+ * the prefix. both the name and prefix may fill the entire field.
+ */
+ if (strlen(pt) == sizeof(hd->name)) { /* must account for name just fits in buffer */
+ strncpy(hd->name, pt, sizeof(hd->name));
+ } else {
+ strlcpy(hd->name, pt, sizeof(hd->name));
+ }
+
+ /*
+ * set the fields in the header that are type dependent
+ */
+ switch (arcn->type) {
+ case PAX_DIR:
+ hd->typeflag = DIRTYPE;
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
+ goto out;
+ break;
+ case PAX_CHR:
+ case PAX_BLK:
+ if (arcn->type == PAX_CHR)
+ hd->typeflag = CHRTYPE;
+ else
+ hd->typeflag = BLKTYPE;
+ if (ul_oct((u_long)MAJOR(arcn->sb.st_rdev), hd->devmajor,
+ sizeof(hd->devmajor), term_char) ||
+ ul_oct((u_long)MINOR(arcn->sb.st_rdev), hd->devminor,
+ sizeof(hd->devminor), term_char) ||
+ ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
+ goto out;
+ break;
+ case PAX_FIF:
+ hd->typeflag = FIFOTYPE;
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
+ goto out;
+ break;
+ case PAX_SLK:
+ case PAX_HLK:
+ case PAX_HRG:
+ if (arcn->type == PAX_SLK)
+ hd->typeflag = SYMTYPE;
+ else
+ hd->typeflag = LNKTYPE;
+ if (strlen(arcn->ln_name) == sizeof(hd->linkname)) { /* must account for name just fits in buffer */
+ strncpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname));
+ } else {
+ strlcpy(hd->linkname, arcn->ln_name, sizeof(hd->linkname));
+ }
+ if (ul_oct((u_long)0L, hd->size, sizeof(hd->size), term_char))
+ goto out;
+ break;
+ case PAX_REG:
+ case PAX_CTG:
+ default:
+ /*
+ * file data with this type, set the padding
+ */
+ if (arcn->type == PAX_CTG)
+ hd->typeflag = CONTTYPE;
+ else
+ hd->typeflag = REGTYPE;
+ arcn->pad = TAR_PAD(arcn->sb.st_size);
+# ifdef LONG_OFF_T
+ if (ul_oct((u_long)arcn->sb.st_size, hd->size,
+ sizeof(hd->size), term_char)) {
+# else
+ if (uqd_oct((u_quad_t)arcn->sb.st_size, hd->size,
+ sizeof(hd->size), term_char)) {
+# endif
+ paxwarn(1,"File is too long for ustar %s",arcn->org_name);
+ return(1);
+ }
+ break;
+ }
+
+ strncpy(hd->magic, TMAGIC, TMAGLEN);
+ strncpy(hd->version, TVERSION, TVERSLEN);
+
+ /*
+ * set the remaining fields. Some versions want all 16 bits of mode
+ * we better humor them (they really do not meet spec though)....
+ */
+ if (ul_oct((u_long)arcn->sb.st_uid, hd->uid, sizeof(hd->uid), term_char)) {
+ if (uid_nobody == 0) {
+ if (uid_name("nobody", &uid_nobody) == -1)
+ goto out;
+ }
+ if (uid_warn != arcn->sb.st_uid) {
+ uid_warn = arcn->sb.st_uid;
+ paxwarn(1,
+ "Ustar header field is too small for uid %lu, "
+ "using nobody", (u_long)arcn->sb.st_uid);
+ }
+ if (ul_oct((u_long)uid_nobody, hd->uid, sizeof(hd->uid), term_char))
+ goto out;
+ }
+ if (ul_oct((u_long)arcn->sb.st_gid, hd->gid, sizeof(hd->gid), term_char)) {
+ if (gid_nobody == 0) {
+ if (gid_name("nobody", &gid_nobody) == -1)
+ goto out;
+ }
+ if (gid_warn != arcn->sb.st_gid) {
+ gid_warn = arcn->sb.st_gid;
+ paxwarn(1,
+ "Ustar header field is too small for gid %lu, "
+ "using nobody", (u_long)arcn->sb.st_gid);
+ }
+ if (ul_oct((u_long)gid_nobody, hd->gid, sizeof(hd->gid), term_char))
+ goto out;
+ }
+ /* However, Unix conformance tests do not like MORE than 12 mode bits:
+ remove all beyond (see definition of stat.st_mode structure) */
+ mode12only = ((u_long)arcn->sb.st_mode) & 0x00000fff;
+ if (ul_oct((u_long)mode12only, hd->mode, sizeof(hd->mode), term_char) ||
+ ul_oct((u_long)arcn->sb.st_mtime,hd->mtime,sizeof(hd->mtime),term_char))
+ goto out;
+ strncpy(hd->uname, name_uid(arcn->sb.st_uid, 0), sizeof(hd->uname));
+ strncpy(hd->gname, name_gid(arcn->sb.st_gid, 0), sizeof(hd->gname));
+
+ /*
+ * calculate and store the checksum write the header to the archive
+ * return 0 tells the caller to now write the file data, 1 says no data
+ * needs to be written
+ */
+ if (ul_oct(tar_chksm(hdblk, sizeof(HD_USTAR)), hd->chksum,
+ sizeof(hd->chksum), term_char))
+ goto out;
+ if (wr_rdbuf((char *)&hdblk, sizeof(HD_USTAR)) < 0)
+ return(-1);
+ if (wr_skip((off_t)(BLKMULT - sizeof(HD_USTAR))) < 0)
+ return(-1);
+ if ((arcn->type == PAX_CTG) || (arcn->type == PAX_REG))
+ return(0);
+ return(1);
+
+ out:
+ /*
+ * header field is out of range
+ */
+ paxwarn(1, "Ustar header field is too small for %s", arcn->org_name);
+ return(1);
+}
+
+/*
+ * name_split()
+ * see if the name has to be split for storage in a ustar header. We try
+ * to fit the entire name in the name field without splitting if we can.
+ * The split point is always at a /
+ * Return
+ * character pointer to split point (always the / that is to be removed
+ * if the split is not needed, the points is set to the start of the file
+ * name (it would violate the spec to split there). A NULL is returned if
+ * the file name is too long
+ */
+
+static char *
+name_split(char *name, int len)
+{
+ char *start;
+
+ /*
+ * check to see if the file name is small enough to fit in the name
+ * field. if so just return a pointer to the name.
+ * The strings can fill the complete name and prefix fields
+ * without a NUL terminator.
+ */
+ if (len <= TNMSZ)
+ return(name);
+ if (len > (TPFSZ + TNMSZ + 1))
+ return(NULL);
+
+ /*
+ * we start looking at the biggest sized piece that fits in the name
+ * field. We walk forward looking for a slash to split at. The idea is
+ * to find the biggest piece to fit in the name field (or the smallest
+ * prefix we can find) (the -1 is correct the biggest piece would
+ * include the slash between the two parts that gets thrown away)
+ */
+ start = name + len - TNMSZ - 1;
+ if ((*start == '/') && (start == name))
+ ++start; /* 101 byte paths with leading '/' are dinged otherwise */
+ while ((*start != '\0') && (*start != '/'))
+ ++start;
+
+ /*
+ * if we hit the end of the string, this name cannot be split, so we
+ * cannot store this file.
+ */
+ if (*start == '\0')
+ return(NULL);
+ len = start - name;
+
+ /*
+ * NOTE: /str where the length of str == TNMSZ can not be stored under
+ * the p1003.1-1990 spec for ustar. We could force a prefix of / and
+ * the file would then expand on extract to //str. The len == 0 below
+ * makes this special case follow the spec to the letter.
+ */
+ if ((len > TPFSZ) || (len == 0))
+ return(NULL);
+
+ /*
+ * ok have a split point, return it to the caller
+ */
+ return(start);
+}
+
+static size_t
+expandname(char *buf, size_t len, char **gnu_name, const char *name,
+ size_t name_len)
+{
+ size_t nlen;
+
+ if (*gnu_name) {
+ /* *gnu_name is NUL terminated */
+ if ((nlen = strlcpy(buf, *gnu_name, len)) >= len)
+ nlen = len - 1;
+ free(*gnu_name);
+ *gnu_name = NULL;
+ } else {
+ if (name_len < len) {
+ /* name may not be null terminated: it might be as big as the
+ field, so copy is limited to the max size of the header field */
+ if ((nlen = strlcpy(buf, name, name_len+1)) >= name_len+1)
+ nlen = name_len;
+ } else {
+ if ((nlen = strlcpy(buf, name, len)) >= len)
+ nlen = len - 1;
+ }
+ }
+ return(nlen);
+}
diff --git a/file_cmds/pax/tar.h b/file_cmds/pax/tar.h
new file mode 100644
index 0000000..a78813c
--- /dev/null
+++ b/file_cmds/pax/tar.h
@@ -0,0 +1,161 @@
+/* $OpenBSD: tar.h,v 1.7 2003/06/02 23:32:09 millert Exp $ */
+/* $NetBSD: tar.h,v 1.3 1995/03/21 09:07:51 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tar.h 8.2 (Berkeley) 4/18/94
+ */
+
+#ifndef _TAR_H_
+#define _TAR_H_
+
+/*
+ * defines and data structures common to all tar formats
+ */
+#define CHK_LEN 8 /* length of checksum field */
+#define TNMSZ 100 /* size of name field */
+#ifdef _PAX_
+#define NULLCNT 2 /* number of null blocks in trailer */
+#define CHK_OFFSET 148 /* start of chksum field */
+#define BLNKSUM 256L /* sum of checksum field using ' ' */
+#endif /* _PAX_ */
+
+/*
+ * Values used in typeflag field in all tar formats
+ * (only REGTYPE, LNKTYPE and SYMTYPE are used in old bsd tar headers)
+ */
+#define REGTYPE '0' /* Regular File */
+#define AREGTYPE '\0' /* Regular File */
+#define LNKTYPE '1' /* Link */
+#define SYMTYPE '2' /* Symlink */
+#define CHRTYPE '3' /* Character Special File */
+#define BLKTYPE '4' /* Block Special File */
+#define DIRTYPE '5' /* Directory */
+#define FIFOTYPE '6' /* FIFO */
+#define CONTTYPE '7' /* high perf file */
+
+#define PAXXTYPE 'x' /* pax format extended header */
+#define PAXGTYPE 'g' /* pax format global extended header */
+
+/*
+ * GNU tar compatibility;
+ */
+#define LONGLINKTYPE 'K' /* Long Symlink */
+#define LONGNAMETYPE 'L' /* Long File */
+
+/*
+ * Mode field encoding of the different file types - values in octal
+ */
+#define TSUID 04000 /* Set UID on execution */
+#define TSGID 02000 /* Set GID on execution */
+#define TSVTX 01000 /* Reserved */
+#define TUREAD 00400 /* Read by owner */
+#define TUWRITE 00200 /* Write by owner */
+#define TUEXEC 00100 /* Execute/Search by owner */
+#define TGREAD 00040 /* Read by group */
+#define TGWRITE 00020 /* Write by group */
+#define TGEXEC 00010 /* Execute/Search by group */
+#define TOREAD 00004 /* Read by other */
+#define TOWRITE 00002 /* Write by other */
+#define TOEXEC 00001 /* Execute/Search by other */
+
+#ifdef _PAX_
+/*
+ * Pad with a bit mask, much faster than doing a mod but only works on powers
+ * of 2. Macro below is for block of 512 bytes.
+ */
+#define TAR_PAD(x) ((512 - ((x) & 511)) & 511)
+#endif /* _PAX_ */
+
+/*
+ * structure of an old tar header as it appeared in BSD releases
+ */
+typedef struct {
+ char name[TNMSZ]; /* name of entry */
+ char mode[8]; /* mode */
+ char uid[8]; /* uid */
+ char gid[8]; /* gid */
+ char size[12]; /* size */
+ char mtime[12]; /* modification time */
+ char chksum[CHK_LEN]; /* checksum */
+ char linkflag; /* norm, hard, or sym. */
+ char linkname[TNMSZ]; /* linked to name */
+} HD_TAR;
+
+#ifdef _PAX_
+/*
+ * -o options for BSD tar to not write directories to the archive
+ */
+#define TAR_NODIR "nodir"
+#define TAR_OPTION "write_opt"
+
+/*
+ * default device names
+ */
+#define DEV_0 "/dev/rst0"
+#define DEV_1 "/dev/rst1"
+#define DEV_4 "/dev/rst4"
+#define DEV_5 "/dev/rst5"
+#define DEV_7 "/dev/rst7"
+#define DEV_8 "/dev/rst8"
+#endif /* _PAX_ */
+
+/*
+ * Data Interchange Format - Extended tar header format - POSIX 1003.1-1990
+ */
+#define TPFSZ 155
+#define TMAGIC "ustar" /* ustar and a null */
+#define TMAGLEN 6
+#define TVERSION "00" /* 00 and no null */
+#define TVERSLEN 2
+
+typedef struct {
+ char name[TNMSZ]; /* name of entry */
+ char mode[8]; /* mode */
+ char uid[8]; /* uid */
+ char gid[8]; /* gid */
+ char size[12]; /* size */
+ char mtime[12]; /* modification time */
+ char chksum[CHK_LEN]; /* checksum */
+ char typeflag; /* type of file. */
+ char linkname[TNMSZ]; /* linked to name */
+ char magic[TMAGLEN]; /* magic cookie */
+ char version[TVERSLEN]; /* version */
+ char uname[32]; /* ascii owner name */
+ char gname[32]; /* ascii group name */
+ char devmajor[8]; /* major device number */
+ char devminor[8]; /* minor device number */
+ char prefix[TPFSZ]; /* linked to name */
+} HD_USTAR;
+
+#endif /* _TAR_H_ */
diff --git a/file_cmds/pax/tty_subs.c b/file_cmds/pax/tty_subs.c
new file mode 100644
index 0000000..74065c6
--- /dev/null
+++ b/file_cmds/pax/tty_subs.c
@@ -0,0 +1,200 @@
+/* $OpenBSD: tty_subs.c,v 1.12 2003/06/02 23:32:09 millert Exp $ */
+/* $NetBSD: tty_subs.c,v 1.5 1995/03/21 09:07:52 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1992 Keith Muller.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)tty_subs.c 8.2 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] = "$OpenBSD: tty_subs.c,v 1.12 2003/06/02 23:32:09 millert Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pax.h"
+#include "extern.h"
+#include <stdarg.h>
+
+/*
+ * routines that deal with I/O to and from the user
+ */
+
+#define DEVTTY "/dev/tty" /* device for interactive i/o */
+static FILE *ttyoutf = NULL; /* output pointing at control tty */
+static FILE *ttyinf = NULL; /* input pointing at control tty */
+
+/*
+ * tty_init()
+ * try to open the controlling terminal (if any) for this process. if the
+ * open fails, future ops that require user input will get an EOF
+ */
+
+int
+tty_init(void)
+{
+ int ttyfd;
+
+ if ((ttyfd = open(DEVTTY, O_RDWR)) >= 0) {
+ if ((ttyoutf = fdopen(ttyfd, "w")) != NULL) {
+ if ((ttyinf = fdopen(ttyfd, "r")) != NULL)
+ return(0);
+ (void)fclose(ttyoutf);
+ }
+ (void)close(ttyfd);
+ }
+
+ if (iflag) {
+ paxwarn(1, "Fatal error, cannot open %s", DEVTTY);
+ return(-1);
+ }
+ return(0);
+}
+
+/*
+ * tty_prnt()
+ * print a message using the specified format to the controlling tty
+ * if there is no controlling terminal, just return.
+ */
+
+void
+tty_prnt(const char *fmt, ...)
+{
+ va_list ap;
+ if (ttyoutf == NULL)
+ return;
+ va_start(ap, fmt);
+ (void)vfprintf(ttyoutf, fmt, ap);
+ va_end(ap);
+ (void)fflush(ttyoutf);
+}
+
+/*
+ * tty_read()
+ * read a string from the controlling terminal if it is open into the
+ * supplied buffer
+ * Return:
+ * 0 if data was read, -1 otherwise.
+ */
+
+int
+tty_read(char *str, int len)
+{
+ char *pt;
+
+ if ((--len <= 0) || (ttyinf == NULL) || (fgets(str,len,ttyinf) == NULL))
+ return(-1);
+ *(str + len) = '\0';
+
+ /*
+ * strip off that trailing newline
+ */
+ if ((pt = strchr(str, '\n')) != NULL)
+ *pt = '\0';
+ return(0);
+}
+
+/*
+ * paxwarn()
+ * write a warning message to stderr. if "set" the exit value of pax
+ * will be non-zero.
+ */
+
+void
+paxwarn(int set, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (set && (pax_invalid_action==0))
+ exit_val = 1;
+ /*
+ * when vflag we better ship out an extra \n to get this message on a
+ * line by itself
+ */
+ if (vflag && vfpart) {
+ (void)fflush(listf);
+ (void)fputc('\n', stderr);
+ vfpart = 0;
+ }
+ (void)fprintf(stderr, "%s: ", argv0);
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fputc('\n', stderr);
+}
+
+/*
+ * syswarn()
+ * write a warning message to stderr. if "set" the exit value of pax
+ * will be non-zero.
+ */
+
+void
+syswarn(int set, int errnum, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (set)
+ exit_val = 1;
+ /*
+ * when vflag we better ship out an extra \n to get this message on a
+ * line by itself
+ */
+ if (vflag && vfpart) {
+ (void)fflush(listf);
+ (void)fputc('\n', stderr);
+ vfpart = 0;
+ }
+ (void)fprintf(stderr, "%s: ", argv0);
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ /*
+ * format and print the errno
+ */
+ if (errnum > 0)
+ (void)fprintf(stderr, " <%s>", strerror(errnum));
+ (void)fputc('\n', stderr);
+}
diff --git a/file_cmds/rm/rm.1 b/file_cmds/rm/rm.1
new file mode 100644
index 0000000..c40f8a7
--- /dev/null
+++ b/file_cmds/rm/rm.1
@@ -0,0 +1,216 @@
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rm.1 8.5 (Berkeley) 12/5/94
+.\" $FreeBSD: src/bin/rm/rm.1,v 1.23 2001/07/15 07:49:05 dd Exp $
+.\"
+.Dd January 28, 1999
+.Dt RM 1
+.Os
+.Sh NAME
+.Nm rm ,
+.Nm unlink
+.Nd remove directory entries
+.Sh SYNOPSIS
+.Nm
+.Op Fl dfiPRrvW
+.Ar
+.Nm unlink
+.Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility attempts to remove the non-directory type files specified on the
+command line.
+If the permissions of the file do not permit writing, and the standard
+input device is a terminal, the user is prompted (on the standard error
+output) for confirmation.
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl d
+Attempt to remove directories as well as other types of files.
+.It Fl f
+Attempt to remove the files without prompting for confirmation,
+regardless of the file's permissions.
+If the file does not exist, do not display a diagnostic message or modify
+the exit status to reflect an error.
+The
+.Fl f
+option overrides any previous
+.Fl i
+options.
+.It Fl i
+Request confirmation before attempting to remove each file, regardless of
+the file's permissions, or whether or not the standard input device is a
+terminal.
+The
+.Fl i
+option overrides any previous
+.Fl f
+options.
+.It Fl P
+Overwrite regular files before deleting them.
+Files are overwritten three times, first with the byte pattern 0xff,
+then 0x00, and then 0xff again, before they are deleted.
+.It Fl R
+Attempt to remove the file hierarchy rooted in each file argument.
+The
+.Fl R
+option implies the
+.Fl d
+option.
+If the
+.Fl i
+option is specified, the user is prompted for confirmation before
+each directory's contents are processed (as well as before the attempt
+is made to remove the directory).
+If the user does not respond affirmatively, the file hierarchy rooted in
+that directory is skipped.
+.Pp
+.It Fl r
+Equivalent to
+.Fl R .
+.It Fl v
+Be verbose when deleting files, showing them as they are removed.
+.It Fl W
+Attempt to undelete the named files.
+Currently, this option can only be used to recover
+files covered by whiteouts.
+.El
+.Pp
+The
+.Nm
+utility removes symbolic links, not the files referenced by the links.
+.Pp
+It is an error to attempt to remove the files
+.Dq .\&
+or
+.Dq .. .
+.Pp
+When the utility is called as
+.Nm unlink ,
+only one argument,
+which must not be a directory,
+may be supplied.
+No options may be supplied in this simple mode of operation,
+which performs an
+.Xr unlink 2
+operation on the passed argument.
+.Pp
+The
+.Nm
+utility exits 0 if all of the named files or file hierarchies were removed,
+or if the
+.Fl f
+option was specified and all of the existing files or file hierarchies were
+removed.
+If an error occurs,
+.Nm
+exits with a value >0.
+.Sh NOTE
+The
+.Nm
+command uses
+.Xr getopt 3
+to parse its arguments, which allows it to accept
+the
+.Sq Li --
+option which will cause it to stop processing flag options at that
+point. This will allow the removal of file names that begin
+with a dash
+.Pq Sq - .
+For example:
+.Dl rm -- -filename
+The same behavior can be obtained by using an absolute or relative
+path reference. For example:
+.Dl rm /home/user/-filename
+.Dl rm ./-filename
+.Sh SEE ALSO
+.Xr rmdir 1 ,
+.Xr undelete 2 ,
+.Xr unlink 2 ,
+.Xr fts 3 ,
+.Xr getopt 3 ,
+.Xr symlink 7
+.Sh BUGS
+The
+.Fl P
+option assumes that the underlying file system is a fixed-block file
+system. In addition, only regular files are overwritten, other types of files
+are not.
+.Sh COMPATIBILITY
+The
+.Nm
+utility differs from historical implementations in that the
+.Fl f
+option only masks attempts to remove non-existent files instead of
+masking a large variety of errors.
+The
+.Fl v
+option is non-standard and its use in scripts is not recommended.
+.Pp
+Also, historical
+.Bx
+implementations prompted on the standard output,
+not the standard error output.
+.Sh STANDARDS
+The
+.Nm
+command is almost
+.St -p1003.2
+compatible, except that
+.Tn POSIX
+requires
+.Nm
+to act like
+.Xr rmdir 1
+when the
+.Ar file
+specified is a directory. This implementation requires the
+.Fl d
+option if such behavior is desired. This follows the historical
+behavior of
+.Nm
+with respect to directories.
+.Pp
+The simplified
+.Nm unlink
+command conforms to
+.St -susv2 .
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/file_cmds/rm/rm.c b/file_cmds/rm/rm.c
new file mode 100644
index 0000000..ef457c5
--- /dev/null
+++ b/file_cmds/rm/rm.c
@@ -0,0 +1,601 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rm.c 8.5 (Berkeley) 4/18/94";
+#else
+__used static const char rcsid[] =
+ "$FreeBSD: src/bin/rm/rm.c,v 1.33 2001/06/13 15:01:25 ru Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <locale.h>
+
+#ifdef __APPLE__
+#include <removefile.h>
+#include <pwd.h>
+#include <grp.h>
+#include "get_compat.h"
+
+#ifndef AT_REMOVEDIR_DATALESS
+#define AT_REMOVEDIR_DATALESS 0x0100 /* Remove a dataless directory without materializing first */
+#endif
+#else
+#define COMPAT_MODE(func, mode) 1
+#endif
+
+int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
+uid_t uid;
+
+int check __P((char *, char *, struct stat *));
+int checkdir __P((char *));
+int yes_or_no __P((void));
+void checkdot __P((char **));
+void rm_file __P((char **));
+void rm_overwrite __P((char *, struct stat *));
+void rm_tree __P((char **));
+void usage __P((void));
+
+/*
+ * rm --
+ * This rm is different from historic rm's, but is expected to match
+ * POSIX 1003.2 behavior. The most visible difference is that -f
+ * has two specific effects now, ignore non-existent files and force
+ * file removal.
+ */
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch, rflag;
+ char *p;
+
+ if (argc < 1)
+ usage();
+
+ /*
+ * Test for the special case where the utility is called as
+ * "unlink", for which the functionality provided is greatly
+ * simplified.
+ */
+ if ((p = rindex(argv[0], '/')) == NULL)
+ p = argv[0];
+ else
+ ++p;
+ uid = geteuid();
+ if (strcmp(p, "unlink") == 0) {
+ if (argc == 2) {
+ rm_file(&argv[1]);
+ exit(eval);
+ } else
+ usage();
+ }
+
+ Pflag = rflag = 0;
+ while ((ch = getopt(argc, argv, "dfiPRrvW")) != -1)
+ switch(ch) {
+ case 'd':
+ dflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ iflag = 0;
+ break;
+ case 'i':
+ fflag = 0;
+ iflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ break;
+ case 'R':
+ case 'r': /* Compatibility. */
+ rflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case 'W':
+ Wflag = 1;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ if (fflag)
+ return 0;
+ usage();
+ }
+
+ checkdot(argv);
+
+ if (*argv) {
+ stdin_ok = isatty(STDIN_FILENO);
+
+ if (rflag)
+ rm_tree(argv);
+ else
+ rm_file(argv);
+ }
+
+ exit (eval);
+}
+
+void
+rm_tree(argv)
+ char **argv;
+{
+ FTS *fts;
+ FTSENT *p;
+ int needstat;
+ int flags;
+ int rval;
+ int wantConformance = COMPAT_MODE("bin/rm", "unix2003");
+ /*
+ * Remove a file hierarchy. If forcing removal (-f), or interactive
+ * (-i) or can't ask anyway (stdin_ok), don't stat the file.
+ */
+ needstat = !uid || (!fflag && !iflag && stdin_ok);
+
+ /*
+ * If the -i option is specified, the user can skip on the pre-order
+ * visit. The fts_number field flags skipped directories.
+ */
+#define SKIPPED 1
+
+ flags = FTS_PHYSICAL;
+ if (!needstat)
+ flags |= FTS_NOSTAT;
+ if (Wflag)
+ flags |= FTS_WHITEOUT;
+ if (!(fts = fts_open(argv, flags, NULL))) {
+ if (fflag && errno == ENOENT)
+ return;
+ err(1, NULL);
+ }
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_DNR:
+ if (!fflag || p->fts_errno != ENOENT) {
+ warnx("%s: %s",
+ p->fts_path, strerror(p->fts_errno));
+ eval = 1;
+ }
+ continue;
+ case FTS_ERR:
+ errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
+ case FTS_NS:
+ /*
+ * FTS_NS: assume that if can't stat the file, it
+ * can't be unlinked.
+ */
+ if (!needstat)
+ break;
+ if (!fflag || p->fts_errno != ENOENT) {
+ warnx("%s: %s",
+ p->fts_path, strerror(p->fts_errno));
+ eval = 1;
+ }
+ continue;
+ case FTS_D:
+ /* Pre-order: give user chance to skip. */
+ /* In conformance mode the user is prompted to skip processing the contents.
+ * Then the option to delete the dir is presented post-order */
+ if (!fflag &&
+ ( (wantConformance && !checkdir(p->fts_path)) ||
+ (!wantConformance && !check(p->fts_path, p->fts_accpath, p->fts_statp))
+ )
+ ){
+ (void)fts_set(fts, p, FTS_SKIP);
+ p->fts_number = SKIPPED;
+ }
+ else if (!uid &&
+ (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
+ !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
+ chflags(p->fts_accpath,
+ p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE)) < 0)
+ goto err;
+ continue;
+ case FTS_DP:
+ /* Post-order: see if user skipped. */
+ if(p->fts_number == SKIPPED)/*in legacy mode, the user was prompted pre-order */
+ continue;
+ else if(wantConformance)
+ {
+ /* delete directory if force is on, or if user answers Y to prompt */
+ if(fflag || check(p->fts_path, p->fts_accpath, p->fts_statp))
+ break;
+ else
+ continue;
+ }
+ break;
+ default:
+ if (!fflag &&
+ !check(p->fts_path, p->fts_accpath, p->fts_statp))
+ continue;
+ }
+
+ rval = 0;
+ if (!uid &&
+ (p->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
+ !(p->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)))
+ rval = chflags(p->fts_accpath,
+ p->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
+ if (rval == 0) {
+ /*
+ * If we can't read or search the directory, may still be
+ * able to remove it. Don't print out the un{read,search}able
+ * message unless the remove fails.
+ */
+ switch (p->fts_info) {
+ case FTS_DP:
+ case FTS_DNR:
+#if __APPLE__
+ rval = unlinkat(AT_FDCWD, p->fts_accpath, AT_REMOVEDIR_DATALESS);
+ if (rval == -1 && errno == EINVAL) {
+ /*
+ * Kernel rejected AT_REMOVEDIR_DATALESS?
+ * I guess we fall back on the painful
+ * route (but it's better than failing).
+ */
+ rval = rmdir(p->fts_accpath);
+ }
+#else
+ rval = rmdir(p->fts_accpath);
+#endif
+ if (rval == 0 || (fflag && errno == ENOENT)) {
+ if (rval == 0 && vflag)
+ (void)printf("%s\n",
+ p->fts_path);
+ continue;
+ }
+ break;
+
+ case FTS_W:
+ rval = undelete(p->fts_accpath);
+ if (rval == 0 && (fflag && errno == ENOENT)) {
+ if (vflag)
+ (void)printf("%s\n",
+ p->fts_path);
+ continue;
+ }
+ break;
+
+ default:
+#ifdef __APPLE__
+ if (Pflag) {
+ if (removefile(p->fts_accpath, NULL, REMOVEFILE_SECURE_7_PASS)) /* overwrites and unlinks */
+ eval = rval = 1;
+ } else
+ rval = unlink(p->fts_accpath);
+#else /* !__APPLE_ */
+ if (Pflag)
+ rm_overwrite(p->fts_accpath, NULL);
+ rval = unlink(p->fts_accpath);
+#endif /* __APPLE__ */
+ if (rval == 0 || (fflag && errno == ENOENT)) {
+ if (rval == 0 && vflag)
+ (void)printf("%s\n",
+ p->fts_path);
+ continue;
+ }
+ }
+ }
+err:
+ warn("%s", p->fts_path);
+ eval = 1;
+ }
+ if (errno)
+ err(1, "fts_read");
+ fts_close(fts);
+}
+
+void
+rm_file(argv)
+ char **argv;
+{
+ struct stat sb;
+ int rval;
+ char *f;
+
+ /*
+ * Remove a file. POSIX 1003.2 states that, by default, attempting
+ * to remove a directory is an error, so must always stat the file.
+ */
+ while ((f = *argv++) != NULL) {
+ /* Assume if can't stat the file, can't unlink it. */
+ if (lstat(f, &sb)) {
+ if (Wflag) {
+ sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
+ } else {
+ if (!fflag || errno != ENOENT) {
+ warn("%s", f);
+ eval = 1;
+ }
+ continue;
+ }
+ } else if (Wflag) {
+ warnx("%s: %s", f, strerror(EEXIST));
+ eval = 1;
+ continue;
+ }
+
+ if (S_ISDIR(sb.st_mode) && !dflag) {
+ warnx("%s: is a directory", f);
+ eval = 1;
+ continue;
+ }
+ if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
+ continue;
+ rval = 0;
+ if (!uid &&
+ (sb.st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
+ !(sb.st_flags & (SF_APPEND|SF_IMMUTABLE)))
+ rval = chflags(f, sb.st_flags & ~(UF_APPEND|UF_IMMUTABLE));
+ if (rval == 0) {
+ if (S_ISWHT(sb.st_mode))
+ rval = undelete(f);
+ else if (S_ISDIR(sb.st_mode))
+ rval = rmdir(f);
+ else {
+#ifdef __APPLE__
+ if (Pflag) {
+ if (removefile(f, NULL, REMOVEFILE_SECURE_7_PASS)) /* overwrites and unlinks */
+ eval = rval = 1;
+ } else
+ rval = unlink(f);
+#else /* !__APPLE__ */
+ if (Pflag)
+ rm_overwrite(f, &sb);
+ rval = unlink(f);
+#endif /* __APPLE__ */
+ }
+ }
+ if (rval && (!fflag || errno != ENOENT)) {
+ warn("%s", f);
+ eval = 1;
+ }
+ if (vflag && rval == 0)
+ (void)printf("%s\n", f);
+ }
+}
+
+/*
+ * rm_overwrite --
+ * Overwrite the file 3 times with varying bit patterns.
+ *
+ * XXX
+ * This is a cheap way to *really* delete files. Note that only regular
+ * files are deleted, directories (and therefore names) will remain.
+ * Also, this assumes a fixed-block file system (like FFS, or a V7 or a
+ * System V file system). In a logging file system, you'll have to have
+ * kernel support.
+ */
+void
+rm_overwrite(file, sbp)
+ char *file;
+ struct stat *sbp;
+{
+ struct stat sb;
+ struct statfs fsb;
+ off_t len;
+ int bsize, fd, wlen;
+ char *buf = NULL;
+
+ if (sbp == NULL) {
+ if (lstat(file, &sb))
+ goto err;
+ sbp = &sb;
+ }
+ if (!S_ISREG(sbp->st_mode))
+ return;
+ if ((fd = open(file, O_WRONLY, 0)) == -1)
+ goto err;
+ if (fstatfs(fd, &fsb) == -1)
+ goto err;
+ bsize = MAX(fsb.f_iosize, 1024);
+ if ((buf = malloc(bsize)) == NULL)
+ err(1, "malloc");
+
+#define PASS(byte) { \
+ memset(buf, byte, bsize); \
+ for (len = sbp->st_size; len > 0; len -= wlen) { \
+ wlen = len < bsize ? (int)len : bsize; \
+ if (write(fd, buf, wlen) != wlen) \
+ goto err; \
+ } \
+}
+ PASS(0xff);
+ if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
+ goto err;
+ PASS(0x00);
+ if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
+ goto err;
+ PASS(0xff);
+ if (!fsync(fd) && !close(fd)) {
+ free(buf);
+ return;
+ }
+
+err: eval = 1;
+ if (buf)
+ free(buf);
+ warn("%s", file);
+}
+
+int
+yes_or_no()
+{
+ int ch, first;
+ char resp[] = {'\0', '\0'};
+
+ (void)fflush(stderr);
+
+ /* Load user specified locale */
+ setlocale(LC_MESSAGES, "");
+
+ first = ch = getchar();
+ while (ch != '\n' && ch != EOF)
+ ch = getchar();
+
+ /* only care about the first character */
+ resp[0] = first;
+
+ return (rpmatch(resp) == 1);
+}
+
+int
+checkdir(path)
+ char *path;
+{
+ if(!iflag)
+ return 1; //if not interactive, process directory's contents
+ (void)fprintf(stderr, "examine files in directory %s? ", path);
+ return yes_or_no();
+}
+
+int
+check(path, name, sp)
+ char *path, *name;
+ struct stat *sp;
+{
+ char modep[15], *flagsp;
+
+ /* Check -i first. */
+ if (iflag)
+ (void)fprintf(stderr, "remove %s? ", path);
+ else {
+ /*
+ * If it's not a symbolic link and it's unwritable and we're
+ * talking to a terminal, ask. Symbolic links are excluded
+ * because their permissions are meaningless. Check stdin_ok
+ * first because we may not have stat'ed the file.
+ */
+ if (!stdin_ok || S_ISLNK(sp->st_mode) ||
+ (!access(name, W_OK) &&
+ !(sp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
+ (!(sp->st_flags & (UF_APPEND|UF_IMMUTABLE)) || !uid)))
+ return (1);
+ strmode(sp->st_mode, modep);
+ if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
+ err(1, NULL);
+ (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
+ modep + 1, modep[9] == ' ' ? "" : " ",
+ user_from_uid(sp->st_uid, 0),
+ group_from_gid(sp->st_gid, 0),
+ *flagsp ? flagsp : "", *flagsp ? " " : "",
+ path);
+ free(flagsp);
+ }
+ return yes_or_no();
+}
+
+
+#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || ((a)[1] == '.' && !(a)[2])))
+void
+checkdot(argv)
+ char **argv;
+{
+ char *p, **save, **t;
+ int complained;
+
+ complained = 0;
+ for (t = argv; *t;) {
+ size_t len = strlen(*t);
+ char truncated[len];
+
+ if ((p = strrchr(*t, '/')) != NULL) {
+ if (p[1] == '\0') { // one or more trailing / -- treat as if not present
+ for (; (p > *t) && (p[-1] == '/');) {
+ len--;
+ p--;
+ }
+ strlcpy(truncated, *t, len);
+ p = strrchr(truncated, '/');
+ if (p) {
+ ++p;
+ } else {
+ p = truncated;
+ }
+ } else {
+ ++p;
+ }
+ } else {
+ p = *t;
+ }
+ if (ISDOT(p)) {
+ if (!complained++)
+ warnx("\".\" and \"..\" may not be removed");
+ eval = 1;
+ for (save = t; (t[0] = t[1]) != NULL; ++t)
+ continue;
+ t = save;
+ } else
+ ++t;
+ }
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "%s\n%s\n",
+ "usage: rm [-f | -i] [-dPRrvW] file ...",
+ " unlink file");
+ exit(EX_USAGE);
+}
diff --git a/file_cmds/rm/unlink.1 b/file_cmds/rm/unlink.1
new file mode 100644
index 0000000..6764e6d
--- /dev/null
+++ b/file_cmds/rm/unlink.1
@@ -0,0 +1 @@
+.so man1/rm.1
diff --git a/file_cmds/rmdir/rmdir.1 b/file_cmds/rmdir/rmdir.1
new file mode 100644
index 0000000..577637a
--- /dev/null
+++ b/file_cmds/rmdir/rmdir.1
@@ -0,0 +1,100 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rmdir.1 8.1 (Berkeley) 5/31/93
+.\" $FreeBSD: src/bin/rmdir/rmdir.1,v 1.9 2000/11/20 11:39:40 ru Exp $
+.\"
+.Dd May 31, 1993
+.Dt RMDIR 1
+.Os
+.Sh NAME
+.Nm rmdir
+.Nd remove directories
+.Sh SYNOPSIS
+.Nm
+.Op Fl p
+.Ar directory ...
+.Sh DESCRIPTION
+The
+.Nm
+utility removes the directory entry specified by
+each
+.Ar directory
+argument, provided it is empty.
+.Pp
+Arguments are processed in the order given.
+In order to remove both a parent directory and a subdirectory
+of that parent, the subdirectory
+must be specified first so the parent directory
+is empty when
+.Nm
+tries to remove it.
+.Pp
+The following option is available:
+.Bl -tag -width indent
+.It Fl p
+Each
+.Ar directory
+argument is treated as a pathname of which all
+components will be removed, if they are empty,
+starting with the last most component.
+(See
+.Xr rm 1
+for fully non-discriminant recursive removal.)
+.El
+.Pp
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It Li \&0
+Each directory entry specified by a dir operand
+referred to an empty directory and was removed
+successfully.
+.It Li \&>\&0
+An error occurred.
+.El
+.Sh SEE ALSO
+.Xr rm 1
+.Sh STANDARDS
+The
+.Nm
+command is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/file_cmds/rmdir/rmdir.c b/file_cmds/rmdir/rmdir.c
new file mode 100644
index 0000000..32969bc
--- /dev/null
+++ b/file_cmds/rmdir/rmdir.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__used static char const copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rmdir.c 8.3 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/bin/rmdir/rmdir.c,v 1.13 2002/06/30 05:15:03 obrien Exp $");
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int rm_path(char *);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, errors;
+ int pflag;
+
+ pflag = 0;
+ while ((ch = getopt(argc, argv, "p")) != -1)
+ switch(ch) {
+ case 'p':
+ pflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ for (errors = 0; *argv; argv++) {
+ if (rmdir(*argv) < 0) {
+ warn("%s", *argv);
+ errors = 1;
+ } else if (pflag)
+ errors |= rm_path(*argv);
+ }
+
+ exit(errors);
+}
+
+int
+rm_path(char *path)
+{
+ char *p;
+
+ p = path + strlen(path);
+ while (--p > path && *p == '/')
+ ;
+ *++p = '\0';
+ while ((p = strrchr(path, '/')) != NULL) {
+ /* Delete trailing slashes. */
+ while (--p > path && *p == '/')
+ ;
+ *++p = '\0';
+
+ if (rmdir(path) < 0) {
+ warn("%s", path);
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: rmdir [-p] directory ...\n");
+ exit(1);
+}
diff --git a/file_cmds/rmt/rmt.8 b/file_cmds/rmt/rmt.8
new file mode 100644
index 0000000..77a9074
--- /dev/null
+++ b/file_cmds/rmt/rmt.8
@@ -0,0 +1,220 @@
+.\" $NetBSD: rmt.8,v 1.6 1997/10/17 13:03:15 lukem Exp $
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rmt.8 8.3 (Berkeley) 6/1/94
+.\"
+.Dd June 1, 1994
+.Dt RMT 8
+.Os BSD 4.2
+.Sh NAME
+.Nm rmt
+.Nd remote magtape protocol module
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+is a program used by the remote dump and restore programs
+in manipulating a magnetic tape drive through an interprocess
+communication connection.
+.Nm
+is normally started up with an
+.Xr rexec 3
+or
+.Xr rcmd 3
+call.
+.Pp
+The
+.Nm
+program accepts requests specific to the manipulation of
+magnetic tapes, performs the commands, then responds with
+a status indication. All responses are in
+.Tn ASCII
+and in
+one of two forms.
+Successful commands have responses of:
+.Bd -filled -offset indent
+.Sm off
+.Sy A Ar number No \en
+.Sm on
+.Ed
+.Pp
+.Ar Number
+is an
+.Tn ASCII
+representation of a decimal number.
+Unsuccessful commands are responded to with:
+.Bd -filled -offset indent
+.Sm off
+.Xo Sy E Ar error-number
+.No \en Ar error-message
+.No \en
+.Xc
+.Sm on
+.Ed
+.Pp
+.Ar Error-number
+is one of the possible error
+numbers described in
+.Xr intro 2
+and
+.Ar error-message
+is the corresponding error string as printed
+from a call to
+.Xr perror 3 .
+The protocol is comprised of the
+following commands, which are sent as indicated - no spaces are supplied
+between the command and its arguments, or between its arguments, and
+.Ql \en
+indicates that a newline should be supplied:
+.Bl -tag -width Ds
+.Sm off
+.It Xo Sy \&O Ar device
+.No \en Ar mode No \en
+.Xc
+Open the specified
+.Ar device
+using the indicated
+.Ar mode .
+.Ar Device
+is a full pathname and
+.Ar mode
+is an
+.Tn ASCII
+representation of a decimal
+number suitable for passing to
+.Xr open 2 .
+If a device had already been opened, it is
+closed before a new open is performed.
+.It Xo Sy C Ar device No \en
+.Xc
+Close the currently open device. The
+.Ar device
+specified is ignored.
+.It Xo Sy L
+.Ar offset No \en
+.Ar whence No \en
+.Xc
+.Sm on
+Perform an
+.Xr lseek 2
+operation using the specified parameters.
+The response value is that returned from the
+.Xr lseek
+call.
+.Sm off
+.It Sy W Ar count No \en
+.Sm on
+Write data onto the open device.
+.Nm
+reads
+.Ar count
+bytes from the connection, aborting if
+a premature end-of-file is encountered.
+The response value is that returned from
+the
+.Xr write 2
+call.
+.Sm off
+.It Sy R Ar count No \en
+.Sm on
+Read
+.Ar count
+bytes of data from the open device.
+If
+.Ar count
+exceeds the size of the data buffer (10 kilobytes), it is
+truncated to the data buffer size.
+.Nm
+then performs the requested
+.Xr read 2
+and responds with
+.Sm off
+.Sy A Ar count-read No \en
+.Sm on
+if the read was
+successful; otherwise an error in the
+standard format is returned. If the read
+was successful, the data read is then sent.
+.Sm off
+.It Xo Sy I Ar operation
+.No \en Ar count No \en
+.Xc
+.Sm on
+Perform a
+.Dv MTIOCOP
+.Xr ioctl 2
+command using the specified parameters.
+The parameters are interpreted as the
+.Tn ASCII
+representations of the decimal values
+to place in the
+.Ar mt_op
+and
+.Ar mt_count
+fields of the structure used in the
+.Xr ioctl
+call. The return value is the
+.Ar count
+parameter when the operation is successful.
+.ne 1i
+.It Sy S
+Return the status of the open device, as
+obtained with a
+.Dv MTIOCGET
+.Xr ioctl
+call. If the operation was successful,
+an ``ack'' is sent with the size of the
+status buffer, then the status buffer is
+sent (in binary).
+.El
+.Sm on
+.Pp
+Any other command causes
+.Nm
+to exit.
+.Sh DIAGNOSTICS
+All responses are of the form described above.
+.Sh SEE ALSO
+.Xr rcmd 3 ,
+.Xr rexec 3 ,
+.Xr mtio 4 ,
+.Xr rdump 8 ,
+.Xr rrestore 8
+.Sh BUGS
+People should be discouraged from using this for a remote
+file access protocol.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/file_cmds/rmt/rmt.c b/file_cmds/rmt/rmt.c
new file mode 100644
index 0000000..bfb4d37
--- /dev/null
+++ b/file_cmds/rmt/rmt.c
@@ -0,0 +1,259 @@
+/* $NetBSD: rmt.c,v 1.9 1997/10/17 13:03:25 lukem Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)rmt.c 8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: rmt.c,v 1.9 1997/10/17 13:03:25 lukem Exp $");
+#endif
+#endif /* not lint */
+
+/*
+ * rmt
+ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int tape = -1;
+
+char *record;
+int maxrecsize = -1;
+
+#define SSIZE 64
+char device[SSIZE];
+char count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
+
+char resp[BUFSIZ];
+
+FILE *debug;
+#define DEBUG(f) if (debug) fprintf(debug, f)
+#define DEBUG1(f,a) if (debug) fprintf(debug, f, a)
+#define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2)
+
+char *checkbuf __P((char *, int));
+void error __P((int));
+int main __P((int, char **));
+void getstring __P((char *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int rval;
+ char c;
+ int n, i, cc;
+
+ argc--, argv++;
+ if (argc > 0) {
+ debug = fopen(*argv, "w");
+ if (debug == 0)
+ exit(1);
+ (void)setbuf(debug, (char *)0);
+ }
+top:
+ errno = 0;
+ rval = 0;
+ if (read(STDIN_FILENO, &c, 1) != 1)
+ exit(0);
+ switch (c) {
+
+ case 'O':
+ if (tape >= 0)
+ (void) close(tape);
+ getstring(device);
+ getstring(mode);
+ DEBUG2("rmtd: O %s %s\n", device, mode);
+ tape = open(device, atoi(mode),
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ if (tape < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'C':
+ DEBUG("rmtd: C\n");
+ getstring(device); /* discard */
+ if (close(tape) < 0)
+ goto ioerror;
+ tape = -1;
+ goto respond;
+
+ case 'L':
+ getstring(count);
+ getstring(pos);
+ DEBUG2("rmtd: L %s %s\n", count, pos);
+ rval = lseek(tape, (off_t)strtoq(count, NULL, 10), atoi(pos));
+ if (rval < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'W':
+ getstring(count);
+ n = atoi(count);
+ DEBUG1("rmtd: W %s\n", count);
+ record = checkbuf(record, n);
+ for (i = 0; i < n; i += cc) {
+ cc = read(STDIN_FILENO, &record[i], n - i);
+ if (cc <= 0) {
+ DEBUG("rmtd: premature eof\n");
+ exit(2);
+ }
+ }
+ rval = write(tape, record, n);
+ if (rval < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'R':
+ getstring(count);
+ DEBUG1("rmtd: R %s\n", count);
+ n = atoi(count);
+ record = checkbuf(record, n);
+ rval = read(tape, record, n);
+ if (rval < 0)
+ goto ioerror;
+ (void)sprintf(resp, "A%d\n", rval);
+ (void)write(STDOUT_FILENO, resp, strlen(resp));
+ (void)write(STDOUT_FILENO, record, rval);
+ goto top;
+
+ case 'I':
+ getstring(op);
+ getstring(count);
+ DEBUG2("rmtd: I %s %s\n", op, count);
+ {
+ struct mtop mtop;
+
+ mtop.mt_op = atoi(op);
+ mtop.mt_count = atoi(count);
+ if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
+ goto ioerror;
+ rval = mtop.mt_count;
+ }
+ goto respond;
+
+ case 'S': /* status */
+ DEBUG("rmtd: S\n");
+ {
+ struct mtget mtget;
+
+ if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
+ goto ioerror;
+ rval = sizeof (mtget);
+ (void)sprintf(resp, "A%d\n", rval);
+ (void)write(STDOUT_FILENO, resp, strlen(resp));
+ (void)write(STDOUT_FILENO, (char *)&mtget,
+ sizeof (mtget));
+ goto top;
+ }
+
+ default:
+ DEBUG1("rmtd: garbage command %c\n", c);
+ exit(3);
+ }
+respond:
+ DEBUG1("rmtd: A %d\n", rval);
+ (void)sprintf(resp, "A%d\n", rval);
+ (void)write(STDOUT_FILENO, resp, strlen(resp));
+ goto top;
+ioerror:
+ error(errno);
+ goto top;
+}
+
+void
+getstring(bp)
+ char *bp;
+{
+ int i;
+ char *cp = bp;
+
+ for (i = 0; i < SSIZE - 1; i++) {
+ if (read(STDIN_FILENO, cp+i, 1) != 1)
+ exit(0);
+ if (cp[i] == '\n')
+ break;
+ }
+ cp[i] = '\0';
+}
+
+char *
+checkbuf(record, size)
+ char *record;
+ int size;
+{
+
+ if (size <= maxrecsize)
+ return (record);
+ if (record != 0)
+ free(record);
+ record = malloc(size);
+ if (record == 0) {
+ DEBUG("rmtd: cannot allocate buffer space\n");
+ exit(4);
+ }
+ maxrecsize = size;
+ while (size > 1024 &&
+ setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
+ size -= 1024;
+ return (record);
+}
+
+void
+error(num)
+ int num;
+{
+
+ DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
+ (void)sprintf(resp, "E%d\n%s\n", num, strerror(num));
+ (void)write(STDOUT_FILENO, resp, strlen(resp));
+}
diff --git a/file_cmds/shar/shar.1 b/file_cmds/shar/shar.1
new file mode 100644
index 0000000..3f9dac9
--- /dev/null
+++ b/file_cmds/shar/shar.1
@@ -0,0 +1,105 @@
+.\" $NetBSD: shar.1,v 1.6 1998/06/08 12:41:44 lukem Exp $
+.\"
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)shar.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt SHAR 1
+.Os BSD 4.4
+.Sh NAME
+.Nm shar
+.Nd create a shell archive of files
+.Sh SYNOPSIS
+.Nm
+.Ar
+.Sh DESCRIPTION
+.Nm
+writes an
+.Xr sh 1
+shell script to the standard output which will recreate the file
+hierarchy specified by the command line operands.
+Directories will be recreated and must be specified before the
+files they contain (the
+.Xr find 1
+utility does this correctly).
+.Pp
+.Nm
+is normally used for distributing files by
+.Xr ftp 1
+or
+.Xr mail 1 .
+.Sh SEE ALSO
+.Xr compress 1 ,
+.Xr mail 1 ,
+.Xr tar 1 ,
+.Xr uuencode 1
+.Sh BUGS
+.Nm
+makes no provisions for special types of files or files containing
+magic characters.
+.Sh EXAMPLES
+To create a shell archive of the program
+.Xr ls 1
+and mail it to Rick:
+.Bd -literal -offset indent
+cd ls
+shar `find . -print` \&| mail -s "ls source" rick
+.Ed
+.Pp
+To recreate the program directory:
+.Bd -literal -offset indent
+mkdir ls
+cd ls
+\&...
+<delete header lines and examine mailed archive>
+\&...
+sh archive
+.Ed
+.Sh HISTORY
+The
+.Nm
+command appears in
+.Bx 4.4 .
+.Sh SECURITY CONSIDERATIONS
+It is easy to insert trojan horses into
+.Nm
+files.
+It is strongly recommended that all shell archive files be examined
+before running them through
+.Xr sh 1 .
+Archives produced using this implementation of
+.Nm
+may be easily examined with the command:
+.Bd -literal -offset indent
+egrep -v '^[X#]' shar.file
+.Ed
diff --git a/file_cmds/shar/shar.sh b/file_cmds/shar/shar.sh
new file mode 100644
index 0000000..7048b44
--- /dev/null
+++ b/file_cmds/shar/shar.sh
@@ -0,0 +1,76 @@
+#!/bin/sh -
+#
+# $NetBSD: shar.sh,v 1.2 1994/12/21 08:42:04 jtc Exp $
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)shar.sh 8.1 (Berkeley) 6/6/93
+#
+
+if [ $# -eq 0 ]; then
+ echo 'usage: shar file ...'
+ exit 1
+fi
+
+cat << EOF
+# This is a shell archive. Save it in a file, remove anything before
+# this line, and then unpack it by entering "sh file". Note, it may
+# create directories; files and directories will be owned by you and
+# have default permissions.
+#
+# This archive contains:
+#
+EOF
+
+for i
+do
+ echo "# $i"
+done
+
+echo "#"
+
+for i
+do
+ if [ -d $i ]; then
+ echo "echo c - $i"
+ echo "mkdir -p $i > /dev/null 2>&1"
+ else
+ echo "echo x - $i"
+ echo "sed 's/^X//' >$i << 'END-of-$i'"
+ sed 's/^/X/' $i
+ echo "END-of-$i"
+ fi
+done
+echo exit
+echo ""
+
+exit 0
diff --git a/file_cmds/stat/readlink.1 b/file_cmds/stat/readlink.1
new file mode 100644
index 0000000..968704b
--- /dev/null
+++ b/file_cmds/stat/readlink.1
@@ -0,0 +1 @@
+.so man1/stat.1
diff --git a/file_cmds/stat/stat.1 b/file_cmds/stat/stat.1
new file mode 100644
index 0000000..79c774f
--- /dev/null
+++ b/file_cmds/stat/stat.1
@@ -0,0 +1,534 @@
+.\" $NetBSD: stat.1,v 1.11 2003/05/08 13:07:10 wiz Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Andrew Brown and Jan Schaumann.
+.\"
+.\" 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 the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation 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 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.
+.\"
+.\" $FreeBSD: src/usr.bin/stat/stat.1,v 1.8 2005/06/14 11:50:53 ru Exp $
+.\"
+.Dd May 8, 2003
+.Dt STAT 1
+.Os
+.Sh NAME
+.Nm readlink ,
+.Nm stat
+.Nd display file status
+.Sh SYNOPSIS
+.Nm stat
+.Op Fl FLnq
+.Op Fl f Ar format | Fl l | r | s | x
+.Op Fl t Ar timefmt
+.Op Ar
+.Nm readlink
+.Op Fl n
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm stat
+utility displays information about the file pointed to by
+.Ar file .
+Read, write or execute permissions of the named file are not required, but
+all directories listed in the path name leading to the file must be
+searchable.
+If no argument is given,
+.Nm stat
+displays information about the file descriptor for standard input.
+.Pp
+When invoked as
+.Nm readlink ,
+only the target of the symbolic link is printed.
+If the given argument is not a symbolic link,
+.Nm readlink
+will print nothing and exit with an error.
+.Pp
+The information displayed is obtained by calling
+.Xr lstat 2
+with the given argument and evaluating the returned structure.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.\" ==========
+.It Fl F
+As in
+.Xr ls 1 ,
+display a slash
+.Pq Ql /
+immediately after each pathname that is a directory,
+an asterisk
+.Pq Ql *
+after each that is executable,
+an at sign
+.Pq Ql @
+after each symbolic link,
+a percent sign
+.Pq Ql %
+after each whiteout,
+an equal sign
+.Pq Ql =
+after each socket,
+and a vertical bar
+.Pq Ql |
+after each that is a FIFO.
+The use of
+.Fl F
+implies
+.Fl l .
+.\" ==========
+.It Fl f Ar format
+Display information using the specified format.
+See the
+.Sx FORMATS
+section for a description of valid formats.
+.\" ==========
+.It Fl L
+Use
+.Xr stat 2
+instead of
+.Xr lstat 2 .
+The information reported by
+.Nm stat
+will refer to the target of
+.Ar file ,
+if file is a symbolic link, and not to
+.Ar file
+itself.
+.\" ==========
+.It Fl l
+Display output in
+.Nm ls Fl lT
+format.
+.\" ==========
+.It Fl n
+Do not force a newline to appear at the end of each piece of output.
+.\" ==========
+.It Fl q
+Suppress failure messages if calls to
+.Xr stat 2
+or
+.Xr lstat 2
+fail.
+When run as
+.Nm readlink ,
+error messages are automatically suppressed.
+.\" ==========
+.It Fl r
+Display raw information.
+That is, for all the fields in the
+.Vt stat
+structure,
+display the raw, numerical value (for example, times in seconds since the
+epoch, etc.).
+.\" ==========
+.It Fl s
+Display information in
+.Dq "shell output" ,
+suitable for initializing variables.
+.\" ==========
+.It Fl t Ar timefmt
+Display timestamps using the specified format.
+This format is
+passed directly to
+.Xr strftime 3 .
+.\" ==========
+.It Fl x
+Display information in a more verbose way as known from some
+.Tn Linux
+distributions.
+.El
+.Ss Formats
+Format strings are similar to
+.Xr printf 3
+formats in that they start with
+.Cm % ,
+are then followed by a sequence of formatting characters, and end in
+a character that selects the field of the
+.Vt "struct stat"
+which is to be formatted.
+If the
+.Cm %
+is immediately followed by one of
+.Cm n , t , % ,
+or
+.Cm @ ,
+then a newline character, a tab character, a percent character,
+or the current file number is printed, otherwise the string is
+examined for the following:
+.Pp
+Any of the following optional flags:
+.Bl -tag -width indent
+.It Cm #
+Selects an alternate output form for octal and hexadecimal output.
+Non-zero octal output will have a leading zero, and non-zero
+hexadecimal output will have
+.Dq Li 0x
+prepended to it.
+.It Cm +
+Asserts that a sign indicating whether a number is positive or negative
+should always be printed.
+Non-negative numbers are not usually printed
+with a sign.
+.It Cm -
+Aligns string output to the left of the field, instead of to the right.
+.It Cm 0
+Sets the fill character for left padding to the
+.Ql 0
+character, instead of a space.
+.It space
+Reserves a space at the front of non-negative signed output fields.
+A
+.Sq Cm +
+overrides a space if both are used.
+.El
+.Pp
+Then the following fields:
+.Bl -tag -width indent
+.It Ar size
+An optional decimal digit string specifying the minimum field width.
+.It Ar prec
+An optional precision composed of a decimal point
+.Sq Cm \&.
+and a decimal digit string that indicates the maximum string length,
+the number of digits to appear after the decimal point in floating point
+output, or the minimum number of digits to appear in numeric output.
+.It Ar fmt
+An optional output format specifier which is one of
+.Cm D , O , U , X , F ,
+or
+.Cm S .
+These represent signed decimal output, octal output, unsigned decimal
+output, hexadecimal output, floating point output, and string output,
+respectively.
+Some output formats do not apply to all fields.
+Floating point output only applies to
+.Vt timespec
+fields (the
+.Cm a , m ,
+and
+.Cm c
+fields).
+.Pp
+The special output specifier
+.Cm S
+may be used to indicate that the output, if
+applicable, should be in string format.
+May be used in combination with:
+.Bl -tag -width indent
+.It Cm amc
+Display date in
+.Xr strftime 3
+format.
+.It Cm dr
+Display actual device name.
+.It Cm gu
+Display group or user name.
+.It Cm p
+Display the mode of
+.Ar file
+as in
+.Nm ls Fl lTd .
+.It Cm N
+Displays the name of
+.Ar file .
+.It Cm T
+Displays the type of
+.Ar file .
+.It Cm Y
+Insert a
+.Dq Li " -\*[Gt] "
+into the output.
+Note that the default output format
+for
+.Cm Y
+is a string, but if specified explicitly, these four characters are
+prepended.
+.El
+.It Ar sub
+An optional sub field specifier (high, middle, low).
+Only applies to
+the
+.Cm p , d , r ,
+and
+.Cm T
+output formats.
+It can be one of the following:
+.Bl -tag -width indent
+.It Cm H
+.Dq High
+\[em]
+specifies the major number for devices from
+.Cm r
+or
+.Cm d ,
+the
+.Dq user
+bits for permissions from the string form of
+.Cm p ,
+the file
+.Dq type
+bits from the numeric forms of
+.Cm p ,
+and the long output form of
+.Cm T .
+.It Cm L
+.Dq Low
+\[em]
+specifies the minor number for devices from
+.Cm r
+or
+.Cm d ,
+the
+.Dq other
+bits for permissions from the string form of
+.Cm p ,
+the
+.Dq user ,
+.Dq group ,
+and
+.Dq other
+bits from the numeric forms of
+.Cm p ,
+and the
+.Nm ls Fl F
+style output character for file type when used with
+.Cm T
+(the use of
+.Cm L
+for this is optional).
+.It Cm M
+.Dq Middle
+\[em]
+specifies the
+.Dq group
+bits for permissions from the
+string output form of
+.Cm p ,
+or the
+.Dq suid ,
+.Dq sgid ,
+and
+.Dq sticky
+bits for the numeric forms of
+.Cm p .
+.El
+.It Ar datum
+A required field specifier, being one of the following:
+.Bl -tag -width indent
+.It Cm d
+Device upon which
+.Ar file
+resides.
+.It Cm i
+.Ar file Ns 's
+inode number.
+.It Cm p
+File type and permissions.
+.It Cm l
+Number of hard links to
+.Ar file .
+.It Cm u , g
+User ID and group ID of
+.Ar file Ns 's
+owner.
+.It Cm r
+Device number for character and block device special files.
+.It Cm a , m , c , B
+The time
+.Ar file
+was last accessed or modified, of when the inode was last changed, or
+the birth time of the inode.
+.It Cm z
+The size of
+.Ar file
+in bytes.
+.It Cm b
+Number of blocks allocated for
+.Ar file .
+.It Cm k
+Optimal file system I/O operation block size.
+.It Cm f
+User defined flags for
+.Ar file .
+.It Cm v
+Inode generation number.
+.El
+.Pp
+The following four field specifiers are not drawn directly from the
+data in
+.Vt "struct stat" ,
+but are:
+.Bl -tag -width indent
+.It Cm N
+The name of the file.
+.It Cm T
+The file type, either as in
+.Nm ls Fl F
+or in a more descriptive form if the
+.Ar sub
+field specifier
+.Cm H
+is given.
+.It Cm Y
+The target of a symbolic link.
+.It Cm Z
+Expands to
+.Dq major,minor
+from the
+.Va rdev
+field for character or block
+special devices and gives size output for all others.
+.El
+.El
+.Pp
+Only the
+.Cm %
+and the field specifier are required.
+Most field specifiers default to
+.Cm U
+as an output form, with the
+exception of
+.Cm p
+which defaults to
+.Cm O ,
+.Cm a , m ,
+and
+.Cm c
+which default to
+.Cm D ,
+and
+.Cm Y , T ,
+and
+.Cm N
+which default to
+.Cm S .
+.Sh EXIT STATUS
+.Ex -std stat readlink
+.Sh EXAMPLES
+Given a symbolic link
+.Pa foo
+that points from
+.Pa /tmp/foo
+to
+.Pa / ,
+you would use
+.Nm stat
+as follows:
+.Bd -literal -offset indent
+\*[Gt] stat -F /tmp/foo
+lrwxrwxrwx 1 jschauma cs 1 Apr 24 16:37:28 2002 /tmp/foo@ -\*[Gt] /
+
+\*[Gt] stat -LF /tmp/foo
+drwxr-xr-x 16 root wheel 512 Apr 19 10:57:54 2002 /tmp/foo/
+.Ed
+.Pp
+To initialize some shell variables, you could use the
+.Fl s
+flag as follows:
+.Bd -literal -offset indent
+\*[Gt] csh
+% eval set `stat -s .cshrc`
+% echo $st_size $st_mtimespec
+1148 1015432481
+
+\*[Gt] sh
+$ eval $(stat -s .profile)
+$ echo $st_size $st_mtimespec
+1148 1015432481
+.Ed
+.Pp
+In order to get a list of the kind of files including files pointed to if the
+file is a symbolic link, you could use the following format:
+.Bd -literal -offset indent
+$ stat -f "%N: %HT%SY" /tmp/*
+/tmp/bar: Symbolic Link -\*[Gt] /tmp/foo
+/tmp/output25568: Regular File
+/tmp/blah: Directory
+/tmp/foo: Symbolic Link -\*[Gt] /
+.Ed
+.Pp
+In order to get a list of the devices, their types and the major and minor
+device numbers, formatted with tabs and linebreaks, you could use the
+following format:
+.Bd -literal -offset indent
+stat -f "Name: %N%n%tType: %HT%n%tMajor: %Hr%n%tMinor: %Lr%n%n" /dev/*
+[...]
+Name: /dev/wt8
+ Type: Block Device
+ Major: 3
+ Minor: 8
+
+Name: /dev/zero
+ Type: Character Device
+ Major: 2
+ Minor: 12
+.Ed
+.Pp
+In order to determine the permissions set on a file separately, you could use
+the following format:
+.Bd -literal -offset indent
+\*[Gt] stat -f "%Sp -\*[Gt] owner=%SHp group=%SMp other=%SLp" .
+drwxr-xr-x -\*[Gt] owner=rwx group=r-x other=r-x
+.Ed
+.Pp
+In order to determine the three files that have been modified most recently,
+you could use the following format:
+.Bd -literal -offset indent
+\*[Gt] stat -f "%m%t%Sm %N" /tmp/* | sort -rn | head -3 | cut -f2-
+Apr 25 11:47:00 2002 /tmp/blah
+Apr 25 10:36:34 2002 /tmp/bar
+Apr 24 16:47:35 2002 /tmp/foo
+.Ed
+.Sh SEE ALSO
+.Xr file 1 ,
+.Xr ls 1 ,
+.Xr lstat 2 ,
+.Xr readlink 2 ,
+.Xr stat 2 ,
+.Xr printf 3 ,
+.Xr strftime 3
+.Sh HISTORY
+The
+.Nm stat
+utility appeared in
+.Nx 1.6
+and
+.Fx 4.10 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm stat
+utility was written by
+.An Andrew Brown
+.Aq atatat@NetBSD.org .
+This man page was written by
+.An Jan Schaumann
+.Aq jschauma@NetBSD.org .
diff --git a/file_cmds/stat/stat.c b/file_cmds/stat/stat.c
new file mode 100644
index 0000000..610eff9
--- /dev/null
+++ b/file_cmds/stat/stat.c
@@ -0,0 +1,1004 @@
+/*
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Brown.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+#include <sys/cdefs.h>
+#if 0
+#ifndef lint
+__RCSID("$NetBSD: stat.c,v 1.13 2003/07/25 03:21:17 atatat Exp $");
+#endif
+#endif
+
+__FBSDID("$FreeBSD: src/usr.bin/stat/stat.c,v 1.6 2003/10/06 01:55:17 dougb Exp $");
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#else /* HAVE_CONFIG_H */
+#define HAVE_STRUCT_STAT_ST_FLAGS 1
+#define HAVE_STRUCT_STAT_ST_GEN 1
+#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
+#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1
+#define HAVE_STRUCT_STAT_ST_ATIM 0
+#define HAVE_DEVNAME 1
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#if HAVE_STRUCT_STAT_ST_FLAGS
+#define DEF_F "%#Xf "
+#define RAW_F "%f "
+#define SHELL_F " st_flags=%f"
+#else /* HAVE_STRUCT_STAT_ST_FLAGS */
+#define DEF_F
+#define RAW_F
+#define SHELL_F
+#endif /* HAVE_STRUCT_STAT_ST_FLAGS */
+
+#if HAVE_STRUCT_STAT_ST_BIRTHTIME
+#define DEF_B "\"%SB\" "
+#define RAW_B "%B "
+#define SHELL_B "st_birthtime=%B "
+#else /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
+#define DEF_B
+#define RAW_B
+#define SHELL_B
+#endif /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
+
+#if HAVE_STRUCT_STAT_ST_ATIM
+#define st_atimespec st_atim
+#define st_ctimespec st_ctim
+#define st_mtimespec st_mtim
+#endif /* HAVE_STRUCT_STAT_ST_ATIM */
+
+#define DEF_FORMAT \
+ "%d %i %Sp %l %Su %Sg %r %z \"%Sa\" \"%Sm\" \"%Sc\" " DEF_B \
+ "%k %b " DEF_F "%N"
+#define RAW_FORMAT "%d %i %#p %l %u %g %r %z %a %m %c " RAW_B \
+ "%k %b " RAW_F "%N"
+#define LS_FORMAT "%Sp %l %Su %Sg %Z %Sm %N%SY"
+#define LSF_FORMAT "%Sp %l %Su %Sg %Z %Sm %N%T%SY"
+#define SHELL_FORMAT \
+ "st_dev=%d st_ino=%i st_mode=%#p st_nlink=%l " \
+ "st_uid=%u st_gid=%g st_rdev=%r st_size=%z " \
+ "st_atime=%a st_mtime=%m st_ctime=%c " SHELL_B \
+ "st_blksize=%k st_blocks=%b" SHELL_F
+#define LINUX_FORMAT \
+ " File: \"%N\"%n" \
+ " Size: %-11z FileType: %HT%n" \
+ " Mode: (%04OA/%.10Sp) Uid: (%5u/%8Su) Gid: (%5g/%8Sg)%n" \
+ "Device: %Hd,%Ld Inode: %i Links: %l%n" \
+ "Access: %Sa%n" \
+ "Modify: %Sm%n" \
+ "Change: %Sc"
+
+#define TIME_FORMAT "%b %e %T %Y"
+
+#define FLAG_POUND 0x01
+#define FLAG_SPACE 0x02
+#define FLAG_PLUS 0x04
+#define FLAG_ZERO 0x08
+#define FLAG_MINUS 0x10
+
+/*
+ * These format characters must all be unique, except the magic one.
+ */
+#define FMT_MAGIC '%'
+#define FMT_DOT '.'
+
+#define SIMPLE_NEWLINE 'n'
+#define SIMPLE_TAB 't'
+#define SIMPLE_PERCENT '%'
+#define SIMPLE_NUMBER '@'
+
+#define FMT_POUND '#'
+#define FMT_SPACE ' '
+#define FMT_PLUS '+'
+#define FMT_ZERO '0'
+#define FMT_MINUS '-'
+
+#define FMT_DECIMAL 'D'
+#define FMT_OCTAL 'O'
+#define FMT_UNSIGNED 'U'
+#define FMT_HEX 'X'
+#define FMT_FLOAT 'F'
+#define FMT_STRING 'S'
+
+#define FMTF_DECIMAL 0x01
+#define FMTF_OCTAL 0x02
+#define FMTF_UNSIGNED 0x04
+#define FMTF_HEX 0x08
+#define FMTF_FLOAT 0x10
+#define FMTF_STRING 0x20
+
+#define HIGH_PIECE 'H'
+#define MIDDLE_PIECE 'M'
+#define LOW_PIECE 'L'
+
+#define SHOW_st_dev 'd'
+#define SHOW_st_ino 'i'
+#define SHOW_st_mode 'p'
+#define SHOW_st_mode2 'A'
+#define SHOW_st_nlink 'l'
+#define SHOW_st_uid 'u'
+#define SHOW_st_gid 'g'
+#define SHOW_st_rdev 'r'
+#define SHOW_st_atime 'a'
+#define SHOW_st_mtime 'm'
+#define SHOW_st_ctime 'c'
+#define SHOW_st_btime 'B'
+#define SHOW_st_size 'z'
+#define SHOW_st_blocks 'b'
+#define SHOW_st_blksize 'k'
+#define SHOW_st_flags 'f'
+#define SHOW_st_gen 'v'
+#define SHOW_symlink 'Y'
+#define SHOW_filetype 'T'
+#define SHOW_filename 'N'
+#define SHOW_sizerdev 'Z'
+
+void usage(const char *);
+void output(const struct stat *, const char *,
+ const char *, int, int, int);
+int format1(const struct stat *, /* stat info */
+ const char *, /* the file name */
+ const char *, int, /* the format string itself */
+ char *, size_t, /* a place to put the output */
+ int, int, int, int, /* the parsed format */
+ int, int);
+
+char *timefmt;
+int linkfail;
+
+#define addchar(s, c, nl) \
+ do { \
+ (void)fputc((c), (s)); \
+ (*nl) = ((c) == '\n'); \
+ } while (0/*CONSTCOND*/)
+
+int
+main(int argc, char *argv[])
+{
+ struct stat st;
+ int ch, rc, errs, am_readlink;
+ int lsF, fmtchar, usestat, fn, nonl, quiet;
+ char *statfmt, *options, *synopsis;
+
+ am_readlink = 0;
+ lsF = 0;
+ fmtchar = '\0';
+ usestat = 0;
+ nonl = 0;
+ quiet = 0;
+ linkfail = 0;
+ statfmt = NULL;
+ timefmt = NULL;
+
+ if (strcmp(getprogname(), "readlink") == 0) {
+ am_readlink = 1;
+ options = "n";
+ synopsis = "[-n] [file ...]";
+ statfmt = "%Y";
+ fmtchar = 'f';
+ quiet = 1;
+ } else {
+ options = "f:FlLnqrst:x";
+ synopsis = "[-FlLnqrsx] [-f format] [-t timefmt] [file ...]";
+ }
+
+ while ((ch = getopt(argc, argv, options)) != -1)
+ switch (ch) {
+ case 'F':
+ lsF = 1;
+ break;
+ case 'L':
+ usestat = 1;
+ break;
+ case 'n':
+ nonl = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'f':
+ statfmt = optarg;
+ /* FALLTHROUGH */
+ case 'l':
+ case 'r':
+ case 's':
+ case 'x':
+ if (fmtchar != 0)
+ errx(1, "can't use format '%c' with '%c'",
+ fmtchar, ch);
+ fmtchar = ch;
+ break;
+ case 't':
+ timefmt = optarg;
+ break;
+ default:
+ usage(synopsis);
+ }
+
+ argc -= optind;
+ argv += optind;
+ fn = 1;
+
+ if (fmtchar == '\0') {
+ if (lsF)
+ fmtchar = 'l';
+ else {
+ fmtchar = 'f';
+ statfmt = DEF_FORMAT;
+ }
+ }
+
+ if (lsF && fmtchar != 'l')
+ errx(1, "can't use format '%c' with -F", fmtchar);
+
+ switch (fmtchar) {
+ case 'f':
+ /* statfmt already set */
+ break;
+ case 'l':
+ statfmt = lsF ? LSF_FORMAT : LS_FORMAT;
+ break;
+ case 'r':
+ statfmt = RAW_FORMAT;
+ break;
+ case 's':
+ statfmt = SHELL_FORMAT;
+ break;
+ case 'x':
+ statfmt = LINUX_FORMAT;
+ if (timefmt == NULL)
+ timefmt = "%c";
+ break;
+ default:
+ usage(synopsis);
+ /*NOTREACHED*/
+ }
+
+ if (timefmt == NULL)
+ timefmt = TIME_FORMAT;
+
+ errs = 0;
+ do {
+ if (argc == 0)
+ rc = fstat(STDIN_FILENO, &st);
+ else if (usestat)
+ rc = stat(argv[0], &st);
+ else
+ rc = lstat(argv[0], &st);
+
+ if (rc == -1) {
+ errs = 1;
+ linkfail = 1;
+ if (!quiet)
+ warn("%s: stat",
+ argc == 0 ? "(stdin)" : argv[0]);
+ }
+ else
+ output(&st, argv[0], statfmt, fn, nonl, quiet);
+
+ argv++;
+ argc--;
+ fn++;
+ } while (argc > 0);
+
+ return (am_readlink ? linkfail : errs);
+}
+
+void
+usage(const char *synopsis)
+{
+
+ (void)fprintf(stderr, "usage: %s %s\n", getprogname(), synopsis);
+ exit(1);
+}
+
+/*
+ * Parses a format string.
+ */
+void
+output(const struct stat *st, const char *file,
+ const char *statfmt, int fn, int nonl, int quiet)
+{
+ int flags, size, prec, ofmt, hilo, what;
+ char buf[PATH_MAX];
+ const char *subfmt;
+ int nl, t, i;
+
+ nl = 1;
+ while (*statfmt != '\0') {
+
+ /*
+ * Non-format characters go straight out.
+ */
+ if (*statfmt != FMT_MAGIC) {
+ addchar(stdout, *statfmt, &nl);
+ statfmt++;
+ continue;
+ }
+
+ /*
+ * The current format "substring" starts here,
+ * and then we skip the magic.
+ */
+ subfmt = statfmt;
+ statfmt++;
+
+ /*
+ * Some simple one-character "formats".
+ */
+ switch (*statfmt) {
+ case SIMPLE_NEWLINE:
+ addchar(stdout, '\n', &nl);
+ statfmt++;
+ continue;
+ case SIMPLE_TAB:
+ addchar(stdout, '\t', &nl);
+ statfmt++;
+ continue;
+ case SIMPLE_PERCENT:
+ addchar(stdout, '%', &nl);
+ statfmt++;
+ continue;
+ case SIMPLE_NUMBER: {
+ char num[12], *p;
+
+ snprintf(num, sizeof(num), "%d", fn);
+ for (p = &num[0]; *p; p++)
+ addchar(stdout, *p, &nl);
+ statfmt++;
+ continue;
+ }
+ }
+
+ /*
+ * This must be an actual format string. Format strings are
+ * similar to printf(3) formats up to a point, and are of
+ * the form:
+ *
+ * % required start of format
+ * [-# +0] opt. format characters
+ * size opt. field width
+ * . opt. decimal separator, followed by
+ * prec opt. precision
+ * fmt opt. output specifier (string, numeric, etc.)
+ * sub opt. sub field specifier (high, middle, low)
+ * datum required field specifier (size, mode, etc)
+ *
+ * Only the % and the datum selector are required. All data
+ * have reasonable default output forms. The "sub" specifier
+ * only applies to certain data (mode, dev, rdev, filetype).
+ * The symlink output defaults to STRING, yet will only emit
+ * the leading " -> " if STRING is explicitly specified. The
+ * sizerdev datum will generate rdev output for character or
+ * block devices, and size output for all others.
+ */
+ flags = 0;
+ do {
+ if (*statfmt == FMT_POUND)
+ flags |= FLAG_POUND;
+ else if (*statfmt == FMT_SPACE)
+ flags |= FLAG_SPACE;
+ else if (*statfmt == FMT_PLUS)
+ flags |= FLAG_PLUS;
+ else if (*statfmt == FMT_ZERO)
+ flags |= FLAG_ZERO;
+ else if (*statfmt == FMT_MINUS)
+ flags |= FLAG_MINUS;
+ else
+ break;
+ statfmt++;
+ } while (1/*CONSTCOND*/);
+
+ size = -1;
+ if (isdigit((unsigned)*statfmt)) {
+ size = 0;
+ while (isdigit((unsigned)*statfmt)) {
+ size = (size * 10) + (*statfmt - '0');
+ statfmt++;
+ if (size < 0)
+ goto badfmt;
+ }
+ }
+
+ prec = -1;
+ if (*statfmt == FMT_DOT) {
+ statfmt++;
+
+ prec = 0;
+ while (isdigit((unsigned)*statfmt)) {
+ prec = (prec * 10) + (*statfmt - '0');
+ statfmt++;
+ if (prec < 0)
+ goto badfmt;
+ }
+ }
+
+#define fmtcase(x, y) case (y): (x) = (y); statfmt++; break
+#define fmtcasef(x, y, z) case (y): (x) = (z); statfmt++; break
+ switch (*statfmt) {
+ fmtcasef(ofmt, FMT_DECIMAL, FMTF_DECIMAL);
+ fmtcasef(ofmt, FMT_OCTAL, FMTF_OCTAL);
+ fmtcasef(ofmt, FMT_UNSIGNED, FMTF_UNSIGNED);
+ fmtcasef(ofmt, FMT_HEX, FMTF_HEX);
+ fmtcasef(ofmt, FMT_FLOAT, FMTF_FLOAT);
+ fmtcasef(ofmt, FMT_STRING, FMTF_STRING);
+ default:
+ ofmt = 0;
+ break;
+ }
+
+ switch (*statfmt) {
+ fmtcase(hilo, HIGH_PIECE);
+ fmtcase(hilo, MIDDLE_PIECE);
+ fmtcase(hilo, LOW_PIECE);
+ default:
+ hilo = 0;
+ break;
+ }
+
+ switch (*statfmt) {
+ fmtcase(what, SHOW_st_dev);
+ fmtcase(what, SHOW_st_ino);
+ fmtcase(what, SHOW_st_mode);
+ fmtcase(what, SHOW_st_mode2);
+ fmtcase(what, SHOW_st_nlink);
+ fmtcase(what, SHOW_st_uid);
+ fmtcase(what, SHOW_st_gid);
+ fmtcase(what, SHOW_st_rdev);
+ fmtcase(what, SHOW_st_atime);
+ fmtcase(what, SHOW_st_mtime);
+ fmtcase(what, SHOW_st_ctime);
+ fmtcase(what, SHOW_st_btime);
+ fmtcase(what, SHOW_st_size);
+ fmtcase(what, SHOW_st_blocks);
+ fmtcase(what, SHOW_st_blksize);
+ fmtcase(what, SHOW_st_flags);
+ fmtcase(what, SHOW_st_gen);
+ fmtcase(what, SHOW_symlink);
+ fmtcase(what, SHOW_filetype);
+ fmtcase(what, SHOW_filename);
+ fmtcase(what, SHOW_sizerdev);
+ default:
+ goto badfmt;
+ }
+#undef fmtcasef
+#undef fmtcase
+
+ t = format1(st,
+ file,
+ subfmt, statfmt - subfmt,
+ buf, sizeof(buf),
+ flags, size, prec, ofmt, hilo, what);
+
+ for (i = 0; i < t && i < sizeof(buf); i++)
+ addchar(stdout, buf[i], &nl);
+
+ continue;
+
+ badfmt:
+ errx(1, "%.*s: bad format",
+ (int)(statfmt - subfmt + 1), subfmt);
+ }
+
+ if (!nl && !nonl)
+ (void)fputc('\n', stdout);
+ (void)fflush(stdout);
+}
+
+/*
+ * Arranges output according to a single parsed format substring.
+ */
+int
+format1(const struct stat *st,
+ const char *file,
+ const char *fmt, int flen,
+ char *buf, size_t blen,
+ int flags, int size, int prec, int ofmt,
+ int hilo, int what)
+{
+ u_int64_t data;
+ char *sdata, lfmt[24], tmp[20];
+ char smode[12], sid[12], path[PATH_MAX + 4];
+ struct passwd *pw;
+ struct group *gr;
+ const struct timespec *tsp;
+ struct timespec ts = {0,0};
+ struct tm *tm;
+ int l, small, formats;
+
+ tsp = NULL;
+// formats = 0;
+// small = 0;
+
+ /*
+ * First, pick out the data and tweak it based on hilo or
+ * specified output format (symlink output only).
+ */
+ switch (what) {
+ case SHOW_st_dev:
+ case SHOW_st_rdev:
+ small = (sizeof(st->st_dev) == 4);
+ data = (what == SHOW_st_dev) ? st->st_dev : st->st_rdev;
+#if HAVE_DEVNAME
+ sdata = (what == SHOW_st_dev) ?
+ devname(st->st_dev, S_IFBLK) :
+ devname(st->st_rdev,
+ S_ISCHR(st->st_mode) ? S_IFCHR :
+ S_ISBLK(st->st_mode) ? S_IFBLK :
+ 0U);
+ if (sdata == NULL)
+ sdata = "???";
+#endif /* HAVE_DEVNAME */
+ if (hilo == HIGH_PIECE) {
+ data = major(data);
+ hilo = 0;
+ }
+ else if (hilo == LOW_PIECE) {
+ data = minor((unsigned)data);
+ hilo = 0;
+ }
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
+#if HAVE_DEVNAME
+ FMTF_STRING;
+#else /* HAVE_DEVNAME */
+ 0;
+#endif /* HAVE_DEVNAME */
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+ case SHOW_st_ino:
+ small = (sizeof(st->st_ino) == 4);
+ data = st->st_ino;
+ sdata = NULL;
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+ case SHOW_st_mode:
+ case SHOW_st_mode2:
+ small = (sizeof(st->st_mode) == 4);
+ data = st->st_mode;
+ strmode(st->st_mode, smode);
+ sdata = smode;
+ l = strlen(sdata);
+ if (sdata[l - 1] == ' ')
+ sdata[--l] = '\0';
+ if (what == SHOW_st_mode2)
+ data &= 07777;
+ if (hilo == HIGH_PIECE) {
+ data >>= 12;
+ sdata += 1;
+ sdata[3] = '\0';
+ hilo = 0;
+ }
+ else if (hilo == MIDDLE_PIECE) {
+ data = (data >> 9) & 07;
+ sdata += 4;
+ sdata[3] = '\0';
+ hilo = 0;
+ }
+ else if (hilo == LOW_PIECE) {
+ data &= 0777;
+ sdata += 7;
+ sdata[3] = '\0';
+ hilo = 0;
+ }
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
+ FMTF_STRING;
+ if (ofmt == 0)
+ ofmt = FMTF_OCTAL;
+ break;
+ case SHOW_st_nlink:
+ small = (sizeof(st->st_dev) == 4);
+ data = st->st_nlink;
+ sdata = NULL;
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+ case SHOW_st_uid:
+ small = (sizeof(st->st_uid) == 4);
+ data = st->st_uid;
+ if ((pw = getpwuid(st->st_uid)) != NULL)
+ sdata = pw->pw_name;
+ else {
+ snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_uid);
+ sdata = sid;
+ }
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
+ FMTF_STRING;
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+ case SHOW_st_gid:
+ small = (sizeof(st->st_gid) == 4);
+ data = st->st_gid;
+ if ((gr = getgrgid(st->st_gid)) != NULL)
+ sdata = gr->gr_name;
+ else {
+ snprintf(sid, sizeof(sid), "(%ld)", (long)st->st_gid);
+ sdata = sid;
+ }
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
+ FMTF_STRING;
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+ case SHOW_st_atime:
+ tsp = &st->st_atimespec;
+ /* FALLTHROUGH */
+ case SHOW_st_mtime:
+ if (tsp == NULL)
+ tsp = &st->st_mtimespec;
+ /* FALLTHROUGH */
+ case SHOW_st_ctime:
+ if (tsp == NULL)
+ tsp = &st->st_ctimespec;
+ /* FALLTHROUGH */
+#if HAVE_STRUCT_STAT_ST_BIRTHTIME
+ case SHOW_st_btime:
+ if (tsp == NULL)
+ tsp = &st->st_birthtimespec;
+#endif /* HAVE_STRUCT_STAT_ST_BIRTHTIME */
+ ts = *tsp; /* copy so we can muck with it */
+ small = (sizeof(ts.tv_sec) == 4);
+ data = ts.tv_sec;
+ tm = localtime(&ts.tv_sec);
+ if (tm == NULL) {
+ ts.tv_sec = 0;
+ tm = localtime(&ts.tv_sec);
+ }
+ (void)strftime(path, sizeof(path), timefmt, tm);
+ sdata = path;
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
+ FMTF_FLOAT | FMTF_STRING;
+ if (ofmt == 0)
+ ofmt = FMTF_DECIMAL;
+ break;
+ case SHOW_st_size:
+ small = (sizeof(st->st_size) == 4);
+ data = st->st_size;
+ sdata = NULL;
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+ case SHOW_st_blocks:
+ small = (sizeof(st->st_blocks) == 4);
+ data = st->st_blocks;
+ sdata = NULL;
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+ case SHOW_st_blksize:
+ small = (sizeof(st->st_blksize) == 4);
+ data = st->st_blksize;
+ sdata = NULL;
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+#if HAVE_STRUCT_STAT_ST_FLAGS
+ case SHOW_st_flags:
+ small = (sizeof(st->st_flags) == 4);
+ data = st->st_flags;
+ sdata = NULL;
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX |
+ FMTF_STRING;
+ if (ofmt == FMTF_STRING) {
+ small = 0;
+ data = 0;
+ snprintf(path, sizeof(path), "%s", fflagstostr(st->st_flags));
+ sdata = path;
+ }
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+#endif /* HAVE_STRUCT_STAT_ST_FLAGS */
+#if HAVE_STRUCT_STAT_ST_GEN
+ case SHOW_st_gen:
+ small = (sizeof(st->st_gen) == 4);
+ data = st->st_gen;
+ sdata = NULL;
+ formats = FMTF_DECIMAL | FMTF_OCTAL | FMTF_UNSIGNED | FMTF_HEX;
+ if (ofmt == 0)
+ ofmt = FMTF_UNSIGNED;
+ break;
+#endif /* HAVE_STRUCT_STAT_ST_GEN */
+ case SHOW_symlink:
+ small = 0;
+ data = 0;
+ if (S_ISLNK(st->st_mode)) {
+ snprintf(path, sizeof(path), " -> ");
+ l = readlink(file, path + 4, sizeof(path) - 4 - 1);
+ if (l == -1) {
+ linkfail = 1;
+ l = 0;
+ path[0] = '\0';
+ }
+ path[l + 4] = '\0';
+ sdata = path + (ofmt == FMTF_STRING ? 0 : 4);
+ }
+ else {
+ linkfail = 1;
+ sdata = "";
+ }
+ formats = FMTF_STRING;
+ if (ofmt == 0)
+ ofmt = FMTF_STRING;
+ break;
+ case SHOW_filetype:
+ small = 0;
+ data = 0;
+ sdata = smode;
+ sdata[0] = '\0';
+ if (hilo == 0 || hilo == LOW_PIECE) {
+ switch (st->st_mode & S_IFMT) {
+ case S_IFIFO: (void)strcat(sdata, "|"); break;
+ case S_IFDIR: (void)strcat(sdata, "/"); break;
+ case S_IFREG:
+ if (st->st_mode &
+ (S_IXUSR | S_IXGRP | S_IXOTH))
+ (void)strcat(sdata, "*");
+ break;
+ case S_IFLNK: (void)strcat(sdata, "@"); break;
+ case S_IFSOCK: (void)strcat(sdata, "="); break;
+#ifdef S_IFWHT
+ case S_IFWHT: (void)strcat(sdata, "%"); break;
+#endif /* S_IFWHT */
+#ifdef S_IFDOOR
+ case S_IFDOOR: (void)strcat(sdata, ">"); break;
+#endif /* S_IFDOOR */
+ }
+ hilo = 0;
+ }
+ else if (hilo == HIGH_PIECE) {
+ switch (st->st_mode & S_IFMT) {
+ case S_IFIFO: sdata = "Fifo File"; break;
+ case S_IFCHR: sdata = "Character Device"; break;
+ case S_IFDIR: sdata = "Directory"; break;
+ case S_IFBLK: sdata = "Block Device"; break;
+ case S_IFREG: sdata = "Regular File"; break;
+ case S_IFLNK: sdata = "Symbolic Link"; break;
+ case S_IFSOCK: sdata = "Socket"; break;
+#ifdef S_IFWHT
+ case S_IFWHT: sdata = "Whiteout File"; break;
+#endif /* S_IFWHT */
+#ifdef S_IFDOOR
+ case S_IFDOOR: sdata = "Door"; break;
+#endif /* S_IFDOOR */
+ default: sdata = "???"; break;
+ }
+ hilo = 0;
+ }
+ formats = FMTF_STRING;
+ if (ofmt == 0)
+ ofmt = FMTF_STRING;
+ break;
+ case SHOW_filename:
+ small = 0;
+ data = 0;
+ if (file == NULL)
+ (void)strncpy(path, "(stdin)", sizeof(path));
+ else
+ (void)strncpy(path, file, sizeof(path));
+ sdata = path;
+ formats = FMTF_STRING;
+ if (ofmt == 0)
+ ofmt = FMTF_STRING;
+ break;
+ case SHOW_sizerdev:
+ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
+ char majdev[20], mindev[20];
+ int l1, l2;
+
+ l1 = format1(st,
+ file,
+ fmt, flen,
+ majdev, sizeof(majdev),
+ flags, size, prec,
+ ofmt, HIGH_PIECE, SHOW_st_rdev);
+ l2 = format1(st,
+ file,
+ fmt, flen,
+ mindev, sizeof(mindev),
+ flags, size, prec,
+ ofmt, LOW_PIECE, SHOW_st_rdev);
+ return (snprintf(buf, blen, "%.*s,%.*s",
+ l1, majdev, l2, mindev));
+ }
+ else {
+ return (format1(st,
+ file,
+ fmt, flen,
+ buf, blen,
+ flags, size, prec,
+ ofmt, 0, SHOW_st_size));
+ }
+ /*NOTREACHED*/
+ default:
+ errx(1, "%.*s: bad format", (int)flen, fmt);
+ }
+
+ /*
+ * If a subdatum was specified but not supported, or an output
+ * format was selected that is not supported, that's an error.
+ */
+ if (hilo != 0 || (ofmt & formats) == 0)
+ errx(1, "%.*s: bad format", (int)flen, fmt);
+
+ /*
+ * Assemble the format string for passing to printf(3).
+ */
+ lfmt[0] = '\0';
+ (void)strcat(lfmt, "%");
+ if (flags & FLAG_POUND)
+ (void)strcat(lfmt, "#");
+ if (flags & FLAG_SPACE)
+ (void)strcat(lfmt, " ");
+ if (flags & FLAG_PLUS)
+ (void)strcat(lfmt, "+");
+ if (flags & FLAG_MINUS)
+ (void)strcat(lfmt, "-");
+ if (flags & FLAG_ZERO)
+ (void)strcat(lfmt, "0");
+
+ /*
+ * Only the timespecs support the FLOAT output format, and that
+ * requires work that differs from the other formats.
+ */
+ if (ofmt == FMTF_FLOAT) {
+ /*
+ * Nothing after the decimal point, so just print seconds.
+ */
+ if (prec == 0) {
+ if (size != -1) {
+ (void)snprintf(tmp, sizeof(tmp), "%d", size);
+ (void)strcat(lfmt, tmp);
+ }
+ (void)strcat(lfmt, "d");
+ return (snprintf(buf, blen, lfmt, ts.tv_sec));
+ }
+
+ /*
+ * Unspecified precision gets all the precision we have:
+ * 9 digits.
+ */
+ if (prec == -1)
+ prec = 9;
+
+ /*
+ * Adjust the size for the decimal point and the digits
+ * that will follow.
+ */
+ size -= prec + 1;
+
+ /*
+ * Any leftover size that's legitimate will be used.
+ */
+ if (size > 0) {
+ (void)snprintf(tmp, sizeof(tmp), "%d", size);
+ (void)strcat(lfmt, tmp);
+ }
+ (void)strcat(lfmt, "d");
+
+ /*
+ * The stuff after the decimal point always needs zero
+ * filling.
+ */
+ (void)strcat(lfmt, ".%0");
+
+ /*
+ * We can "print" at most nine digits of precision. The
+ * rest we will pad on at the end.
+ */
+ (void)snprintf(tmp, sizeof(tmp), "%dd", prec > 9 ? 9 : prec);
+ (void)strcat(lfmt, tmp);
+
+ /*
+ * For precision of less that nine digits, trim off the
+ * less significant figures.
+ */
+ for (; prec < 9; prec++)
+ ts.tv_nsec /= 10;
+
+ /*
+ * Use the format, and then tack on any zeroes that
+ * might be required to make up the requested precision.
+ */
+ l = snprintf(buf, blen, lfmt, ts.tv_sec, ts.tv_nsec);
+ for (; prec > 9 && l < blen; prec--, l++)
+ (void)strcat(buf, "0");
+ return (l);
+ }
+
+ /*
+ * Add on size and precision, if specified, to the format.
+ */
+ if (size != -1) {
+ (void)snprintf(tmp, sizeof(tmp), "%d", size);
+ (void)strcat(lfmt, tmp);
+ }
+ if (prec != -1) {
+ (void)snprintf(tmp, sizeof(tmp), ".%d", prec);
+ (void)strcat(lfmt, tmp);
+ }
+
+ /*
+ * String output uses the temporary sdata.
+ */
+ if (ofmt == FMTF_STRING) {
+ if (sdata == NULL)
+ errx(1, "%.*s: bad format", (int)flen, fmt);
+ (void)strcat(lfmt, "s");
+ return (snprintf(buf, blen, lfmt, sdata));
+ }
+
+ /*
+ * Ensure that sign extension does not cause bad looking output
+ * for some forms.
+ */
+ if (small && ofmt != FMTF_DECIMAL)
+ data = (u_int32_t)data;
+
+ /*
+ * The four "numeric" output forms.
+ */
+ (void)strcat(lfmt, "ll");
+ switch (ofmt) {
+ case FMTF_DECIMAL: (void)strcat(lfmt, "d"); break;
+ case FMTF_OCTAL: (void)strcat(lfmt, "o"); break;
+ case FMTF_UNSIGNED: (void)strcat(lfmt, "u"); break;
+ case FMTF_HEX: (void)strcat(lfmt, "x"); break;
+ }
+
+ return (snprintf(buf, blen, lfmt, data));
+}
diff --git a/file_cmds/tests/chgrp.sh b/file_cmds/tests/chgrp.sh
new file mode 100644
index 0000000..503fbf1
--- /dev/null
+++ b/file_cmds/tests/chgrp.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+GROUPID=31337
+
+dscl /Local/Default -read /Groups/$GROUPID > /dev/null 2>&1
+if [ $? != "0" ]; then
+ dscl /Local/Default -create /Groups/$GROUPID
+ dscl /Local/Default -create /Groups/$GROUPID PrimaryGroupID 9999
+fi
+
+mkdir /tmp/$$
+chgrp $GROUPID /tmp/$$
+gid=`/usr/bin/stat -f '%g' /tmp/$$`
+if [ "$gid" != "9999" ]; then
+ echo "chgrp $GROUPID, expected group 9999, is $gid"
+ exit 1
+fi
+
+chgrp -n $GROUPID /tmp/$$
+gid=`/usr/bin/stat -f '%g' /tmp/$$`
+if [ "$gid" != "$GROUPID" ]; then
+ echo "chgrp -n $GROUPID, expected group $GROUPID, is $gid"
+ exit 1
+fi
+
+exit 0
diff --git a/file_cmds/tests/file_cmds.plist b/file_cmds/tests/file_cmds.plist
new file mode 100644
index 0000000..4e4d135
--- /dev/null
+++ b/file_cmds/tests/file_cmds.plist
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Project</key>
+ <string>file_cmds</string>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>Tests</key>
+ <array>
+ <dict>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>chgrp.sh</string>
+ </array>
+ <key>AsRoot</key>
+ <true/>
+ <key>TestName</key>
+ <string>chgrp</string>
+ <key>WhenToRun</key>
+ <array>
+ <string>PRESUBMISSION</string>
+ <string>NIGHTLY</string>
+ </array>
+ <key>WorkingDirectory</key>
+ <string>/AppleInternal/Tests/file_cmds</string>
+ </dict>
+ </array>
+ <key>Timeout</key>
+ <integer>30</integer>
+</dict>
+</plist>
diff --git a/file_cmds/touch/touch.1 b/file_cmds/touch/touch.1
new file mode 100644
index 0000000..6e6678b
--- /dev/null
+++ b/file_cmds/touch/touch.1
@@ -0,0 +1,221 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)touch.1 8.3 (Berkeley) 4/28/95
+.\" $FreeBSD: src/usr.bin/touch/touch.1,v 1.16 2007/04/10 07:24:47 grog Exp $
+.\"
+.Dd April 28, 1995
+.Dt TOUCH 1
+.Os
+.Sh NAME
+.Nm touch
+.Nd change file access and modification times
+.Sh SYNOPSIS
+.Nm
+.Op Fl A Ar [-][[hh]mm]SS
+.Op Fl acfhm
+.Op Fl r Ar file
+.Op Fl t Ar [[CC]YY]MMDDhhmm[.SS]
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility sets the modification and access times of files.
+If any file does not exist, it is created with default permissions.
+.Pp
+By default,
+.Nm
+changes both modification and access times. The
+.Fl a
+and
+.Fl m
+flags may be used to select the access time or the modification time
+individually.
+Selecting both is equivalent to the default.
+By default, the timestamps are set to the current time.
+The
+.Fl t
+flag explicitly specifies a different time, and the
+.Fl r
+flag specifies to set the times those of the specified file.
+The
+.Fl A
+flag adjusts the values by a specified amount.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl A
+Adjust the access and modification time stamps for the file by the
+specified value.
+This flag is intended for use in modifying files with incorrectly set
+time stamps.
+.Pp
+The argument is of the form
+.Dq [-][[hh]mm]SS
+where each pair of letters represents the following:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar -
+Make the adjustment negative: the new time stamp is set to be before
+the old one.
+.It Ar hh
+The number of hours, from 00 to 99.
+.It Ar mm
+The number of minutes, from 00 to 59.
+.It Ar SS
+The number of seconds, from 00 to 59.
+.El
+.Pp
+The
+.Fl A
+flag implies the
+.Fl c
+flag: if any file specified does not exist, it will be silently ignored.
+.It Fl a
+Change the access time of the file.
+The modification time of the file is not changed unless the
+.Fl m
+flag is also specified.
+.It Fl c
+Do not create the file if it does not exist.
+The
+.Nm
+utility does not treat this as an error.
+No error messages are displayed and the exit value is not affected.
+.It Fl f
+Attempt to force the update, even if the file permissions do not
+currently permit it.
+.It Fl h
+If the file is a symbolic link, change the times of the link
+itself rather than the file that the link points to.
+Note that
+.Fl h
+implies
+.Fl c
+and thus will not create any new files.
+.It Fl m
+Change the modification time of the file.
+The access time of the file is not changed unless the
+.Fl a
+flag is also specified.
+.It Fl r
+Use the access and modifications times from the specified file
+instead of the current time of day.
+.It Fl t
+Change the access and modification times to the specified time instead
+of the current time of day.
+The argument is of the form
+.Dq [[CC]YY]MMDDhhmm[.SS]
+where each pair of letters represents the following:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar CC
+The first two digits of the year (the century).
+.It Ar YY
+The second two digits of the year.
+If
+.Dq YY
+is specified, but
+.Dq CC
+is not, a value for
+.Dq YY
+between 69 and 99 results in a
+.Dq CC
+value of 19.
+Otherwise, a
+.Dq CC
+value of 20 is used.
+.It Ar MM
+The month of the year, from 01 to 12.
+.It Ar DD
+the day of the month, from 01 to 31.
+.It Ar hh
+The hour of the day, from 00 to 23.
+.It Ar mm
+The minute of the hour, from 00 to 59.
+.It Ar SS
+The second of the minute, from 00 to 61.
+.El
+.Pp
+If the
+.Dq CC
+and
+.Dq YY
+letter pairs are not specified, the values default to the current
+year.
+If the
+.Dq SS
+letter pair is not specified, the value defaults to 0.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh COMPATIBILITY
+The obsolescent form of
+.Nm ,
+where a time format is specified as the first argument, is supported.
+When no
+.Fl r
+or
+.Fl t
+option is specified, there are at least two arguments, and the first
+argument is a string of digits either eight or ten characters in length,
+the first argument is interpreted as a time specification of the form
+.Dq MMDDhhmm[YY] .
+.Pp
+The
+.Dq MM ,
+.Dq DD ,
+.Dq hh
+and
+.Dq mm
+letter pairs are treated as their counterparts specified to the
+.Fl t
+option.
+If the
+.Dq YY
+letter pair is in the range 39 to 99, the year is set to 1939 to 1999,
+otherwise, the year is set in the 21st century.
+.Sh SEE ALSO
+.Xr utimes 2
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2
+specification.
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v7 .
diff --git a/file_cmds/touch/touch.c b/file_cmds/touch/touch.c
new file mode 100644
index 0000000..aca5b90
--- /dev/null
+++ b/file_cmds/touch/touch.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/touch/touch.c,v 1.25 2010/03/28 13:16:08 ed Exp $");
+
+#ifndef lint
+__used static const char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+__used static const char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+int rw(char *, struct stat *, int);
+void stime_arg1(char *, struct timeval *);
+void stime_arg2(char *, int, struct timeval *);
+void stime_file(char *, struct timeval *);
+int timeoffset(char *);
+void usage(char *);
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ struct timeval tv[2];
+ int (*stat_f)(const char *, struct stat *);
+ int (*utimes_f)(const char *, const struct timeval *);
+ int Aflag, aflag, cflag, fflag, mflag, ch, fd, len, rval, timeset;
+ char *p;
+ char *myname;
+
+ myname = basename(argv[0]);
+ Aflag = aflag = cflag = fflag = mflag = timeset = 0;
+ stat_f = stat;
+ utimes_f = utimes;
+ if (gettimeofday(&tv[0], NULL))
+ err(1, "gettimeofday");
+
+ while ((ch = getopt(argc, argv, "A:acfhmr:t:")) != -1)
+ switch(ch) {
+ case 'A':
+ Aflag = timeoffset(optarg);
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ cflag = 1;
+ stat_f = lstat;
+ utimes_f = lutimes;
+ break;
+ case 'm':
+ mflag = 1;
+ break;
+ case 'r':
+ timeset = 1;
+ stime_file(optarg, tv);
+ break;
+ case 't':
+ timeset = 1;
+ stime_arg1(optarg, tv);
+ break;
+ case '?':
+ default:
+ usage(myname);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (aflag == 0 && mflag == 0)
+ aflag = mflag = 1;
+
+ if (timeset) {
+ if (Aflag) {
+ /*
+ * We're setting the time to an offset from a specified
+ * time. God knows why, but it means that we can set
+ * that time once and for all here.
+ */
+ if (aflag)
+ tv[0].tv_sec += Aflag;
+ if (mflag)
+ tv[1].tv_sec += Aflag;
+ Aflag = 0; /* done our job */
+ }
+ } else {
+ /*
+ * If no -r or -t flag, at least two operands, the first of
+ * which is an 8 or 10 digit number, use the obsolete time
+ * specification, otherwise use the current time.
+ */
+ if (argc > 1) {
+ strtol(argv[0], &p, 10);
+ len = p - argv[0];
+ if (*p == '\0' && (len == 8 || len == 10)) {
+ timeset = 1;
+ stime_arg2(*argv++, len == 10, tv);
+ }
+ }
+ /* Both times default to the same. */
+ tv[1] = tv[0];
+ }
+
+ if (*argv == NULL)
+ usage(myname);
+
+ if (Aflag)
+ cflag = 1;
+
+ for (rval = 0; *argv; ++argv) {
+ /* See if the file exists. */
+ if (stat_f(*argv, &sb) != 0) {
+ if (errno != ENOENT) {
+ rval = 1;
+ warn("%s", *argv);
+ continue;
+ }
+ if (!cflag) {
+ /* Create the file. */
+ fd = open(*argv,
+ O_WRONLY | O_CREAT, DEFFILEMODE);
+ if (fd == -1 || fstat(fd, &sb) || close(fd)) {
+ rval = 1;
+ warn("%s", *argv);
+ continue;
+ }
+
+ /* If using the current time, we're done. */
+ if (!timeset)
+ continue;
+ } else
+ continue;
+ }
+
+ if (!aflag)
+ TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec);
+ if (!mflag)
+ TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
+
+ /*
+ * We're adjusting the times based on the file times, not a
+ * specified time (that gets handled above).
+ */
+ if (Aflag) {
+ if (aflag) {
+ TIMESPEC_TO_TIMEVAL(&tv[0], &sb.st_atimespec);
+ tv[0].tv_sec += Aflag;
+ }
+ if (mflag) {
+ TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
+ tv[1].tv_sec += Aflag;
+ }
+ }
+
+ /* Try utimes(2). */
+ if (!utimes_f(*argv, tv))
+ continue;
+
+ /* If the user specified a time, nothing else we can do. */
+ if (timeset || Aflag) {
+ rval = 1;
+ warn("%s", *argv);
+ continue;
+ }
+
+ /*
+ * System V and POSIX 1003.1 require that a NULL argument
+ * set the access/modification times to the current time.
+ * The permission checks are different, too, in that the
+ * ability to write the file is sufficient. Take a shot.
+ */
+ if (!utimes_f(*argv, NULL))
+ continue;
+
+ /* Try reading/writing. */
+ if (!S_ISLNK(sb.st_mode) && !S_ISDIR(sb.st_mode)) {
+ if (rw(*argv, &sb, fflag))
+ rval = 1;
+ } else {
+ rval = 1;
+ warn("%s", *argv);
+ }
+ }
+ exit(rval);
+}
+
+#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+
+void
+stime_arg1(char *arg, struct timeval *tvp)
+{
+ time_t now;
+ struct tm *t;
+ int yearset;
+ char *p;
+ /* Start with the current time. */
+ now = tvp[0].tv_sec;
+ if ((t = localtime(&now)) == NULL)
+ err(1, "localtime");
+ /* [[CC]YY]MMDDhhmm[.SS] */
+ if ((p = strchr(arg, '.')) == NULL)
+ t->tm_sec = 0; /* Seconds defaults to 0. */
+ else {
+ if (strlen(p + 1) != 2)
+ goto terr;
+ *p++ = '\0';
+ t->tm_sec = ATOI2(p);
+ }
+
+ yearset = 0;
+ switch(strlen(arg)) {
+ case 12: /* CCYYMMDDhhmm */
+ t->tm_year = ATOI2(arg);
+ t->tm_year *= 100;
+ yearset = 1;
+ /* FALLTHROUGH */
+ case 10: /* YYMMDDhhmm */
+ if (yearset) {
+ yearset = ATOI2(arg);
+ t->tm_year += yearset;
+ } else {
+ yearset = ATOI2(arg);
+ if (yearset < 69)
+ t->tm_year = yearset + 2000;
+ else
+ t->tm_year = yearset + 1900;
+ }
+ t->tm_year -= 1900; /* Convert to UNIX time. */
+ /* FALLTHROUGH */
+ case 8: /* MMDDhhmm */
+ t->tm_mon = ATOI2(arg);
+ --t->tm_mon; /* Convert from 01-12 to 00-11 */
+ t->tm_mday = ATOI2(arg);
+ t->tm_hour = ATOI2(arg);
+ t->tm_min = ATOI2(arg);
+ break;
+ default:
+ goto terr;
+ }
+
+ t->tm_isdst = -1; /* Figure out DST. */
+ tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
+ if (tvp[0].tv_sec == -1)
+terr: errx(1,
+ "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
+
+ tvp[0].tv_usec = tvp[1].tv_usec = 0;
+}
+
+void
+stime_arg2(char *arg, int year, struct timeval *tvp)
+{
+ time_t now;
+ struct tm *t;
+ /* Start with the current time. */
+ now = tvp[0].tv_sec;
+ if ((t = localtime(&now)) == NULL)
+ err(1, "localtime");
+
+ t->tm_mon = ATOI2(arg); /* MMDDhhmm[yy] */
+ --t->tm_mon; /* Convert from 01-12 to 00-11 */
+ t->tm_mday = ATOI2(arg);
+ t->tm_hour = ATOI2(arg);
+ t->tm_min = ATOI2(arg);
+ if (year) {
+ t->tm_year = ATOI2(arg);
+ if (t->tm_year < 39) /* support 2000-2038 not 1902-1969 */
+ t->tm_year += 100;
+ }
+
+ t->tm_isdst = -1; /* Figure out DST. */
+ tvp[0].tv_sec = tvp[1].tv_sec = mktime(t);
+ if (tvp[0].tv_sec == -1)
+ errx(1,
+ "out of range or illegal time specification: MMDDhhmm[yy]");
+
+ tvp[0].tv_usec = tvp[1].tv_usec = 0;
+}
+
+/* Calculate a time offset in seconds, given an arg of the format [-]HHMMSS. */
+int
+timeoffset(char *arg)
+{
+ int offset;
+ int isneg;
+
+ offset = 0;
+ isneg = *arg == '-';
+ if (isneg)
+ arg++;
+ switch (strlen(arg)) {
+ default: /* invalid */
+ errx(1, "Invalid offset spec, must be [-][[HH]MM]SS");
+
+ case 6: /* HHMMSS */
+ offset = ATOI2(arg);
+ /* FALLTHROUGH */
+ case 4: /* MMSS */
+ offset = offset * 60 + ATOI2(arg);
+ /* FALLTHROUGH */
+ case 2: /* SS */
+ offset = offset * 60 + ATOI2(arg);
+ }
+ if (isneg)
+ return (-offset);
+ else
+ return (offset);
+}
+
+void
+stime_file(char *fname, struct timeval *tvp)
+{
+ struct stat sb;
+
+ if (stat(fname, &sb))
+ err(1, "%s", fname);
+ TIMESPEC_TO_TIMEVAL(tvp, &sb.st_atimespec);
+ TIMESPEC_TO_TIMEVAL(tvp + 1, &sb.st_mtimespec);
+}
+
+int
+rw(char *fname, struct stat *sbp, int force)
+{
+ int fd, needed_chmod, rval;
+ u_char byte;
+
+ /* Try regular files. */
+ if (!S_ISREG(sbp->st_mode)) {
+ warnx("%s: %s", fname, strerror(EFTYPE));
+ return (1);
+ }
+
+ needed_chmod = rval = 0;
+ if ((fd = open(fname, O_RDWR, 0)) == -1) {
+ if (!force || chmod(fname, DEFFILEMODE))
+ goto err;
+ if ((fd = open(fname, O_RDWR, 0)) == -1)
+ goto err;
+ needed_chmod = 1;
+ }
+
+ if (sbp->st_size != 0) {
+ if (read(fd, &byte, sizeof(byte)) != sizeof(byte))
+ goto err;
+ if (lseek(fd, (off_t)0, SEEK_SET) == -1)
+ goto err;
+ if (write(fd, &byte, sizeof(byte)) != sizeof(byte))
+ goto err;
+ } else {
+ if (write(fd, &byte, sizeof(byte)) != sizeof(byte)) {
+err: rval = 1;
+ warn("%s", fname);
+ } else if (ftruncate(fd, (off_t)0)) {
+ rval = 1;
+ warn("%s: file modified", fname);
+ }
+ }
+
+ if (close(fd) && rval != 1) {
+ rval = 1;
+ warn("%s", fname);
+ }
+ if (needed_chmod && chmod(fname, sbp->st_mode) && rval != 1) {
+ rval = 1;
+ warn("%s: permissions modified", fname);
+ }
+ return (rval);
+}
+
+void
+usage(char *myname)
+{
+ fprintf(stderr, "usage:\n" "%s [-A [-][[hh]mm]SS] [-acfhm] [-r file] "
+ "[-t [[CC]YY]MMDDhhmm[.SS]] file ...\n", myname);
+ exit(1);
+}
diff --git a/file_cmds/xcodescripts/hardlink.sh b/file_cmds/xcodescripts/hardlink.sh
new file mode 100644
index 0000000..8659623
--- /dev/null
+++ b/file_cmds/xcodescripts/hardlink.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Link input files to output files (in order).
+
+set -e
+
+if [ "$SCRIPT_INPUT_FILE_COUNT" -ne "$SCRIPT_OUTPUT_FILE_COUNT" ]; then
+ echo input and output file counts differ
+ exit 1
+fi
+
+X=0
+
+while [ "$X" -lt "$SCRIPT_INPUT_FILE_COUNT" ]; do
+ eval ln -fhv \"\$SCRIPT_INPUT_FILE_$X\" \"\$SCRIPT_OUTPUT_FILE_$X\"
+ X=$((X+1))
+done
diff --git a/mail_cmds/Makefile b/mail_cmds/Makefile
new file mode 100644
index 0000000..127d0a7
--- /dev/null
+++ b/mail_cmds/Makefile
@@ -0,0 +1,5 @@
+Project = mail_cmds
+
+SubProjects = biff comsat from mail msgs
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/biff/Makefile b/mail_cmds/biff/Makefile
new file mode 100644
index 0000000..2672505
--- /dev/null
+++ b/mail_cmds/biff/Makefile
@@ -0,0 +1,10 @@
+Project = biff
+Install_Dir = /usr/bin
+
+CFILES = biff.c
+MANPAGES = biff.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/biff/biff.1 b/mail_cmds/biff/biff.1
new file mode 100644
index 0000000..05e8162
--- /dev/null
+++ b/mail_cmds/biff/biff.1
@@ -0,0 +1,127 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)biff.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/biff/biff.1,v 1.19 2002/08/16 03:08:25 johan Exp $
+.\"
+.Dd July 9, 2002
+.Dt BIFF 1
+.Os
+.Sh NAME
+.Nm biff
+.Nd "be notified if mail arrives and who it is from"
+.Sh SYNOPSIS
+.Nm
+.Op Cm n | y | b
+.Sh DESCRIPTION
+The
+.Nm
+utility informs the system whether you want to be notified on your terminal
+when mail arrives.
+.Pp
+Affected is the first terminal associated with the standard input,
+standard output or standard error file descriptor, in that order.
+Thus, it is possible to use the redirection facilities of a shell to
+toggle the notification for other terminals than the one
+.Nm
+runs on.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Cm n
+Disable notification.
+.It Cm y
+Enable header notification.
+.It Cm b
+Enable bell notification.
+.El
+.Pp
+When header notification is enabled, the header and first few lines of
+the message will be printed on your terminal whenever mail arrives.
+A
+.Dq Li biff y
+command is often included in the file
+.Pa \&.login
+or
+.Pa \&.profile
+to be executed at each login.
+.Pp
+When bell notification is enabled, only two bell characters
+.Tn ( ASCII
+\\007)
+will be printed on your terminal whenever mail arrives.
+.Pp
+If no arguments are given,
+.Nm
+displays the present notification status of the terminal to the
+standard output.
+.Pp
+The
+.Nm
+utility operates asynchronously.
+For synchronous notification use the
+.Ev MAIL
+variable of
+.Xr sh 1
+or the
+.Ev mail
+variable of
+.Xr csh 1 .
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width indent
+.It 0
+Notification is enabled.
+.It 1
+Notification is disabled.
+.It >1
+An error occurred.
+.El
+.Sh COMPATIBILITY
+Previous versions of the
+.Nm
+utility affected the terminal attached to standard error without first
+trying the standard input or output devices.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr mail 1 ,
+.Xr sh 1 ,
+.Xr comsat 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
+It was named after the dog of Heidi Stettner.
+He died
+in August 1993, at 15.
diff --git a/mail_cmds/biff/biff.c b/mail_cmds/biff/biff.c
new file mode 100644
index 0000000..444e2c7
--- /dev/null
+++ b/mail_cmds/biff/biff.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)biff.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/biff/biff.c,v 1.18 2002/07/24 18:54:59 robert Exp $");
+
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ int ch;
+ char *name;
+
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ((name = ttyname(STDIN_FILENO)) == NULL &&
+ (name = ttyname(STDOUT_FILENO)) == NULL &&
+ (name = ttyname(STDERR_FILENO)) == NULL)
+ err(2, "unknown tty");
+
+ if (stat(name, &sb))
+ err(2, "stat");
+
+ if (*argv == NULL) {
+ (void)printf("is %s\n",
+ sb.st_mode & S_IXUSR ? "y" :
+ sb.st_mode & S_IXGRP ? "b" : "n");
+ return (sb.st_mode & (S_IXUSR | S_IXGRP) ? 0 : 1);
+
+ }
+
+ switch (argv[0][0]) {
+ case 'n':
+ if (chmod(name, sb.st_mode & ~(S_IXUSR | S_IXGRP)) < 0)
+ err(2, "%s", name);
+ break;
+ case 'y':
+ if (chmod(name, (sb.st_mode & ~(S_IXUSR | S_IXGRP)) | S_IXUSR)
+ < 0)
+ err(2, "%s", name);
+ break;
+ case 'b':
+ if (chmod(name, (sb.st_mode & ~(S_IXUSR | S_IXGRP)) | S_IXGRP)
+ < 0)
+ err(2, "%s", name);
+ break;
+ default:
+ usage();
+ }
+ return (sb.st_mode & (S_IXUSR | S_IXGRP) ? 0 : 1);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: biff [n | y | b]\n");
+ exit(2);
+}
diff --git a/mail_cmds/comsat/Makefile b/mail_cmds/comsat/Makefile
new file mode 100644
index 0000000..fd52e66
--- /dev/null
+++ b/mail_cmds/comsat/Makefile
@@ -0,0 +1,11 @@
+Project = comsat
+Install_Dir = /usr/libexec
+
+CFILES = comsat.c
+MANPAGES = comsat.8
+LAUNCHD_PLISTS = comsat.plist
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/comsat/comsat.8 b/mail_cmds/comsat/comsat.8
new file mode 100644
index 0000000..2f73c78
--- /dev/null
+++ b/mail_cmds/comsat/comsat.8
@@ -0,0 +1,115 @@
+.\" $NetBSD: comsat.8,v 1.6 1998/07/04 19:38:39 mrg Exp $
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)comsat.8 8.1 (Berkeley) 6/4/93
+.\"
+.Dd June 4, 1993
+.Dt COMSAT 8
+.Os BSD 4.2
+.Sh NAME
+.Nm comsat
+.Nd biff server
+.Sh SYNOPSIS
+.Nm
+.Op Fl l
+.Sh DESCRIPTION
+.Nm
+is the server process which receives reports of incoming mail
+and notifies users if they have requested this service.
+.Nm
+receives messages on a datagram port associated with the
+.Dq biff
+service
+specification (see
+.Xr services 5
+and
+.Xr inetd 8 ) .
+The one line messages are of the form:
+.Pp
+.Dl user@mailbox-offset
+.Pp
+If the
+.Em user
+specified is logged in to the system and the associated terminal has
+the owner execute bit turned on (by a
+.Dq Li biff y ) ,
+the
+.Em offset
+is used as a seek offset into the appropriate mailbox file and
+the first 7 lines or 560 characters of the message are printed
+on the user's terminal. Lines which appear to be part of
+the message header other than the
+.Dq From ,
+.Dq \&To ,
+.Dq Date ,
+or
+.Dq Subject
+lines are not included in the displayed message.
+.Sh OPTIONS
+The
+.Nm
+program supports this option:
+.Bl -tag -width 12345
+.It Fl l
+The
+.Fl l
+option turns on
+.Xr syslogd 8
+log messages.
+.El
+.Sh FILES
+.Bl -tag -width /var/run/utmpx -compact
+.It Pa /var/run/utmpx
+to find out who's logged on and on what terminals
+.El
+.Sh SEE ALSO
+.Xr biff 1 ,
+.Xr inetd 8 ,
+.Xr syslogd 8 .
+.Sh BUGS
+The message header filtering is prone to error.
+The density of the information presented is near the theoretical minimum.
+.Pp
+Users should be notified of mail which arrives on other
+machines than the one to which they are currently logged in.
+.Pp
+The notification should appear in a separate window so it
+does not mess up the screen.
+.Pp
+.Nm
+runs as root so that it can open the users maildrop.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/mail_cmds/comsat/comsat.c b/mail_cmds/comsat/comsat.c
new file mode 100644
index 0000000..62ac5d5
--- /dev/null
+++ b/mail_cmds/comsat/comsat.c
@@ -0,0 +1,314 @@
+/* $NetBSD: comsat.c,v 1.14 1998/07/06 06:47:38 mrg Exp $ */
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#if 0
+static char sccsid[] = "from: @(#)comsat.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: comsat.c,v 1.14 1998/07/06 06:47:38 mrg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <vis.h>
+#include <unistd.h>
+#include <utmpx.h>
+
+int logging;
+int debug = 0;
+#define dsyslog if (debug) syslog
+
+#define MAXIDLE 120
+
+char hostname[MAXHOSTNAMELEN+1];
+struct utmpx *utmpx = NULL;
+time_t lastmsgtime;
+int nutmpx, uf;
+
+void jkfprintf __P((FILE *, char[], off_t));
+void mailfor __P((char *));
+void notify __P((struct utmpx *, off_t));
+void onalrm __P((int));
+void reapchildren __P((int));
+int main __P((int, char *[]));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in from;
+ int cc, ch;
+ socklen_t fromlen;
+ char msgbuf[100];
+ sigset_t sigset;
+ extern char *__progname;
+
+ /* verify proper invocation */
+ fromlen = sizeof(from);
+ if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ (void)fprintf(stderr,
+ "comsat: getsockname: %s.\n", strerror(errno));
+ exit(1);
+ }
+
+ openlog("comsat", LOG_PID, LOG_DAEMON);
+ while ((ch = getopt(argc, argv, "l")) != -1)
+ switch (ch) {
+ case 'l':
+ logging = 1;
+ break;
+ default:
+ syslog(LOG_ERR, "usage: %s [-l]", __progname);
+ exit(1);
+ }
+ if (chdir(_PATH_MAILDIR)) {
+ syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR);
+ (void)recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
+ exit(1);
+ }
+ if ((uf = open(_PATH_UTMPX, O_RDONLY, 0)) < 0) {
+ syslog(LOG_ERR, "open: %s: %m", _PATH_UTMPX);
+ (void)recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
+ exit(1);
+ }
+ (void)time(&lastmsgtime);
+ (void)gethostname(hostname, sizeof(hostname));
+ hostname[sizeof(hostname) - 1] = '\0';
+ onalrm(0);
+ (void)signal(SIGALRM, onalrm);
+ (void)signal(SIGTTOU, SIG_IGN);
+ (void)signal(SIGCHLD, reapchildren);
+ for (;;) {
+ cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
+ if (cc <= 0) {
+ if (errno != EINTR)
+ sleep(1);
+ errno = 0;
+ continue;
+ }
+ if (!nutmpx) /* no one has logged in yet */
+ continue;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ sigprocmask(SIG_SETMASK, &sigset, NULL);
+ msgbuf[cc] = '\0';
+ (void)time(&lastmsgtime);
+ mailfor(msgbuf);
+ sigemptyset(&sigset);
+ sigprocmask(SIG_SETMASK, &sigset, NULL);
+ }
+}
+
+void
+reapchildren(signo)
+ int signo;
+{
+
+ while (wait3(NULL, WNOHANG, NULL) > 0);
+}
+
+void
+onalrm(signo)
+ int signo;
+{
+ static u_int utmpxsize; /* last malloced size for utmpx */
+ static time_t utmpxmtime; /* last modification time for utmpx */
+ struct stat statbf;
+
+ if (time(NULL) - lastmsgtime >= MAXIDLE)
+ exit(0);
+ (void)alarm((u_int)15);
+ (void)fstat(uf, &statbf);
+ if (statbf.st_mtime > utmpxmtime) {
+ utmpxmtime = statbf.st_mtime;
+ if (statbf.st_size > utmpxsize) {
+ utmpxsize = statbf.st_size + 10 * sizeof(struct utmpx);
+ if ((utmpx = realloc(utmpx, utmpxsize)) == NULL) {
+ syslog(LOG_ERR, "%s", strerror(errno));
+ exit(1);
+ }
+ }
+ /* the first record is just a signature, so it is skipped */
+ (void)lseek(uf, (off_t)sizeof(struct utmpx), SEEK_SET);
+ nutmpx = read(uf, utmpx, statbf.st_size - sizeof(struct utmpx))/sizeof(struct utmpx);
+ }
+}
+
+void
+mailfor(name)
+ char *name;
+{
+ struct utmpx *utp = &utmpx[nutmpx];
+ char *cp;
+ off_t offset;
+
+ if (!(cp = strchr(name, '@')))
+ return;
+ *cp = '\0';
+ offset = atoi(cp + 1);
+ while (--utp >= utmpx)
+ if (utp->ut_type == USER_PROCESS && !strncmp(utp->ut_user, name, sizeof(utp->ut_user)))
+ notify(utp, offset);
+}
+
+static char *cr;
+
+void
+notify(utp, offset)
+ struct utmpx *utp;
+ off_t offset;
+{
+ FILE *tp;
+ struct passwd *p;
+ struct stat stb;
+ struct termios ttybuf;
+ char tty[40], name[sizeof(utp->ut_user) + 1];
+
+ (void)snprintf(tty, sizeof(tty), "%s%.*s",
+ _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line);
+ if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) {
+ /* A slash is an attempt to break security... */
+ /*
+ * XXX but what about something like "/dev/pts/5"
+ * that we may one day "support". ?
+ */
+ syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty);
+ return;
+ }
+ if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) {
+ dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_user, tty);
+ return;
+ }
+ dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_user, tty);
+ if (fork())
+ return;
+ (void)signal(SIGALRM, SIG_DFL);
+ (void)alarm((u_int)30);
+ if ((tp = fopen(tty, "w")) == NULL) {
+ dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno));
+ _exit(-1);
+ }
+ (void)tcgetattr(fileno(tp), &ttybuf);
+ cr = (ttybuf.c_oflag & ONLCR) && (ttybuf.c_oflag & OPOST) ?
+ "\n" : "\n\r";
+ (void)strncpy(name, utp->ut_user, sizeof(utp->ut_user));
+ name[sizeof(name) - 1] = '\0';
+
+ /* Set uid/gid/groups to users in case mail drop is on nfs */
+ if ((p = getpwnam(name)) == NULL ||
+ initgroups(p->pw_name, p->pw_gid) < 0 ||
+ setgid(p->pw_gid) < 0 ||
+ setuid(p->pw_uid) < 0)
+ _exit(-1);
+
+ if (logging)
+ syslog(LOG_INFO, "biff message for %s", name);
+
+ (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s",
+ cr, name, (int)sizeof(hostname), hostname, cr, cr);
+ jkfprintf(tp, name, offset);
+ (void)fclose(tp);
+ _exit(0);
+}
+
+void
+jkfprintf(tp, name, offset)
+ FILE *tp;
+ char name[];
+ off_t offset;
+{
+ FILE *fi;
+ int linecnt, charcnt, inheader;
+ char line[BUFSIZ], visline[BUFSIZ*4];
+
+ if ((fi = fopen(name, "r")) == NULL)
+ return;
+
+ (void)fseek(fi, offset, SEEK_SET);
+ /*
+ * Print the first 7 lines or 560 characters of the new mail
+ * (whichever comes first). Skip header crap other than
+ * From, Subject, To, and Date.
+ */
+ linecnt = 7;
+ charcnt = 560;
+ inheader = 1;
+ while (fgets(line, sizeof(line), fi) != NULL) {
+ if (inheader) {
+ if (line[0] == '\n') {
+ inheader = 0;
+ continue;
+ }
+ if (line[0] == ' ' || line[0] == '\t' ||
+ (strncasecmp(line, "From:", 5) &&
+ strncasecmp(line, "Subject:", 8)))
+ continue;
+ }
+ if (linecnt <= 0 || charcnt <= 0) {
+ (void)fprintf(tp, "...more...%s", cr);
+ (void)fclose(fi);
+ return;
+ }
+ /* strip weird stuff so can't trojan horse stupid terminals */
+ (void)strvis(visline, line, VIS_CSTYLE);
+ fputs(visline, tp);
+ --linecnt;
+ }
+ (void)fprintf(tp, "----%s\n", cr);
+ (void)fclose(fi);
+}
diff --git a/mail_cmds/comsat/comsat.plist b/mail_cmds/comsat/comsat.plist
new file mode 100644
index 0000000..48b772a
--- /dev/null
+++ b/mail_cmds/comsat/comsat.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.comsat</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/comsat</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <true/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>comsat</string>
+ <key>SockType</key>
+ <string>dgram</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/mail_cmds/from/Makefile b/mail_cmds/from/Makefile
new file mode 100644
index 0000000..b0c5bd7
--- /dev/null
+++ b/mail_cmds/from/Makefile
@@ -0,0 +1,10 @@
+Project = from
+Install_Dir = /usr/bin
+
+CFILES = from.c
+MANPAGES = from.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/from/from.1 b/mail_cmds/from/from.1
new file mode 100644
index 0000000..af26bfd
--- /dev/null
+++ b/mail_cmds/from/from.1
@@ -0,0 +1,99 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)from.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD: src/usr.bin/from/from.1,v 1.14 2002/07/15 06:15:38 keramida Exp $
+.\"
+.Dd December 30, 1993
+.Dt FROM 1
+.Os
+.Sh NAME
+.Nm from
+.Nd print names of those who have sent mail
+.Sh SYNOPSIS
+.Nm
+.Op Fl c
+.Op Fl s Ar sender
+.Op Fl f Ar file
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility prints
+out the mail header lines from the invoker's mailbox.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl c
+Just print a count of messages and exit.
+.It Fl f Ar file
+The supplied file
+is examined instead of the invoker's mailbox.
+If the
+.Fl f
+option is used, the
+.Ar user
+argument should not be used.
+Read from standard input if file name
+.Ar -
+is given.
+.It Fl s Ar sender
+Only mail from addresses containing
+the
+supplied string are printed.
+.El
+.Pp
+If
+.Ar user
+is given, the
+.Ar user Ns 's
+mailbox is examined instead of the invoker's own mailbox.
+(Privileges are required.)
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev MAIL
+If set, the location of the invoker's mailbox.
+Otherwise, the default in
+.Pa /var/mail
+is used.
+.El
+.Sh FILES
+.Bl -tag -width /var/mail/* -compact
+.It Pa /var/mail/*
+.El
+.Sh SEE ALSO
+.Xr biff 1 ,
+.Xr mail 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/mail_cmds/from/from.c b/mail_cmds/from/from.c
new file mode 100644
index 0000000..ac85c54
--- /dev/null
+++ b/mail_cmds/from/from.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1980, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/from/from.c,v 1.14 2002/09/04 23:29:00 dwmalone Exp $");
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <paths.h>
+#include <string.h>
+#include <unistd.h>
+
+int match(const char *, const char *);
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ FILE *mbox;
+ struct passwd *pwd;
+ int ch, count, newline;
+ const char *file;
+ char *sender, *p;
+#if MAXPATHLEN > BUFSIZ
+ char buf[MAXPATHLEN];
+#else
+ char buf[BUFSIZ];
+#endif
+
+ file = sender = NULL;
+ count = -1;
+ while ((ch = getopt(argc, argv, "cf:s:")) != -1)
+ switch (ch) {
+ case 'c':
+ count = 0;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case 's':
+ sender = optarg;
+ for (p = sender; *p; ++p)
+ if (isupper(*p))
+ *p = tolower(*p);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (file == NULL) {
+ if (argc) {
+ (void)snprintf(buf, sizeof(buf), "%s/%s", _PATH_MAILDIR, *argv);
+ file = buf;
+ } else {
+ if (!(file = getenv("MAIL"))) {
+ if (!(pwd = getpwuid(getuid())))
+ errx(1, "no password file entry for you");
+ file = pwd->pw_name;
+ (void)snprintf(buf, sizeof(buf),
+ "%s/%s", _PATH_MAILDIR, file);
+ file = buf;
+ }
+ }
+ }
+
+ /* read from stdin */
+ if (strcmp(file, "-") == 0) {
+ mbox = stdin;
+ }
+ else if ((mbox = fopen(file, "r")) == NULL) {
+ errx(1, "can't read %s", file);
+ }
+ for (newline = 1; fgets(buf, sizeof(buf), mbox);) {
+ if (*buf == '\n') {
+ newline = 1;
+ continue;
+ }
+ if (newline && !strncmp(buf, "From ", 5) &&
+ (!sender || match(buf + 5, sender))) {
+ if (count != -1)
+ count++;
+ else
+ printf("%s", buf);
+ }
+ newline = 0;
+ }
+ if (count != -1)
+ printf("There %s %d message%s in your incoming mailbox.\n",
+ count == 1 ? "is" : "are", count, count == 1 ? "" : "s");
+ fclose(mbox);
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: from [-c] [-f file] [-s sender] [user]\n");
+ exit(1);
+}
+
+int
+match(const char *line, const char *sender)
+{
+ char ch, pch, first;
+ const char *p, *t;
+
+ for (first = *sender++;;) {
+ if (isspace(ch = *line))
+ return(0);
+ ++line;
+ if (isupper(ch))
+ ch = tolower(ch);
+ if (ch != first)
+ continue;
+ for (p = sender, t = line;;) {
+ if (!(pch = *p++))
+ return(1);
+ if (isupper(ch = *t++))
+ ch = tolower(ch);
+ if (ch != pch)
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
diff --git a/mail_cmds/mail/Makefile b/mail_cmds/mail/Makefile
new file mode 100644
index 0000000..bd82ec4
--- /dev/null
+++ b/mail_cmds/mail/Makefile
@@ -0,0 +1,24 @@
+Project = mail
+Install_Dir = /usr/bin
+
+CFILES = aux.c cmd1.c cmd2.c cmd3.c cmdtab.c collect.c \
+ edit.c fio.c getname.c head.c lex.c list.c main.c names.c\
+ popen.c quit.c send.c strings.c temp.c tty.c v7.local.c\
+ vars.c version.c
+MANPAGES = mail.1 mailx.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
+
+ETCDIR=$(DSTROOT)/private/etc
+MISCDIR=$(DSTROOT)/usr/share/misc
+
+after_install:
+ $(INSTALL_DIRECTORY) $(MISCDIR)
+ $(INSTALL_FILE) -c misc/mail.help misc/mail.tildehelp $(MISCDIR)
+ $(INSTALL_DIRECTORY) $(ETCDIR)
+ $(INSTALL_FILE) -c -m 644 misc/mail.rc $(ETCDIR)/mail.rc
+ $(LN) -f $(DSTROOT)$(Install_Dir)/mail \
+ $(DSTROOT)$(Install_Dir)/mailx
diff --git a/mail_cmds/mail/USD.doc/Makefile b/mail_cmds/mail/USD.doc/Makefile
new file mode 100644
index 0000000..4c96c7e
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/Makefile
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.3 1997/12/21 15:48:30 christos Exp $
+# from: @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= usd/07.mail
+SRCS= mail0.nr mail1.nr mail2.nr mail3.nr mail4.nr mail5.nr mail6.nr \
+ mail7.nr mail8.nr mail9.nr maila.nr
+MACROS= -me
+
+paper.ps: ${SRCS}
+ ${SOELIM} -I${.CURDIR} ${.ALLSRC} | ${TBL} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/mail_cmds/mail/USD.doc/mail0.nr b/mail_cmds/mail/USD.doc/mail0.nr
new file mode 100644
index 0000000..15955be
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail0.nr
@@ -0,0 +1,71 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail0.nr 8.1 (Berkeley) 6/8/93
+.\"
+.eh 'USD:7-%''Mail Reference Manual'
+.oh 'Mail Reference Manual''USD:7-%'
+.if n \
+.nr fs .5v
+.\".he 'Mail Reference Manual'\n(mo/\n(dy/\n(yr'%'
+.tp
+.sp 1.0i
+.sz 12
+.rb
+.(l C
+MAIL REFERENCE MANUAL
+.)l
+.sz 10
+.sp 2
+.i
+.(l C
+Kurt Shoens
+.)l
+.r
+.(l C
+Revised by
+.)l
+.(l C
+.i
+Craig Leres\ \c
+.r
+and\ \c
+.i
+Mark Andrews
+.)l
+.r
+.(l C
+Version 5.5
+
+
+\*(td
+.)l
+.pn 2
diff --git a/mail_cmds/mail/USD.doc/mail1.nr b/mail_cmds/mail/USD.doc/mail1.nr
new file mode 100644
index 0000000..50e7883
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail1.nr
@@ -0,0 +1,92 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail1.nr 8.1 (Berkeley) 6/8/93
+.\"
+.sh 1 Introduction
+.pp
+.i Mail
+provides a simple and friendly environment for sending and receiving mail.
+It divides incoming mail into
+its constituent messages and allows the user to deal with them
+in any order. In addition, it provides a set of
+.i ed -\c
+like commands for manipulating messages and sending mail.
+.i Mail
+offers the user simple editing capabilities to ease the composition
+of outgoing messages, as well as providing the ability to define and send
+to names which address groups of users. Finally,
+.i Mail
+is able to send and receive messages across such networks as the
+ARPANET, UUCP, and Berkeley network.
+.pp
+This document describes how to use the
+.i Mail
+program to send and receive messages. The reader is not assumed to
+be familiar with other message handling systems, but should be
+familiar with the \s-2UNIX\s0\**
+.(f
+\** \s-1UNIX\s0 is a trademark of Bell Laboratories.
+.)f
+shell, the text editor, and some of the common \s-2UNIX\s0 commands.
+.q "The \s-2UNIX\s0 Programmer's Manual,"
+.q "An Introduction to Csh,"
+and
+.q "Text Editing with Ex and Vi"
+can be consulted for more information on these topics.
+.pp
+Here is how messages are handled:
+the mail system accepts incoming
+.i messages
+for you from other people
+and collects them in a file, called your
+.i "system mailbox" .
+When you login, the system notifies you if there are any messages
+waiting in your system mailbox. If you are a
+.i csh
+user, you will be notified when new mail arrives if you inform
+the shell of the location of your mailbox. On version 7 systems,
+your system mailbox is located in the directory /var/mail
+in a file with your login name. If your login name is
+.q sam,
+then you can make
+.i csh
+notify you of new mail by including the following line in your .cshrc
+file:
+.(l
+set mail=/var/mail/sam
+.)l
+When you read your mail using
+.i Mail ,
+it reads your system mailbox and separates that file into the
+individual messages that have been sent to you. You can then
+read, reply to, delete, or save these messages.
+Each message is marked with its author and the date they sent it.
diff --git a/mail_cmds/mail/USD.doc/mail2.nr b/mail_cmds/mail/USD.doc/mail2.nr
new file mode 100644
index 0000000..0419859
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail2.nr
@@ -0,0 +1,617 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail2.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "Common usage"
+.pp
+The
+.i Mail
+command has two distinct usages, according to whether one
+wants to send or receive mail. Sending mail is simple: to send a
+message to a user whose login name is, say,
+\*(lqroot,\*(rq
+use the shell
+command:
+.(l
+% Mail root
+.)l
+then type your message. When you reach the end of the message, type
+an EOT (control\-d) at the beginning of a line, which will cause
+.i Mail
+to echo \*(lqEOT\*(rq and return you to the Shell. When the user you sent mail
+to next logs in, he will receive the message:
+.(l
+You have mail.
+.)l
+to alert him to the existence of your message.
+.pp
+If, while you are composing the message
+you decide that you do not wish to send it after all, you can
+abort the letter with a \s-2RUBOUT\s0. Typing a single \s-2RUBOUT\s0
+causes
+.i Mail
+to print
+.(l
+(Interrupt -- one more to kill letter)
+.)l
+Typing a second
+\s-2RUBOUT\s0 causes
+.i Mail
+to save your partial letter on the file
+.q dead.letter
+in your home directory and abort the letter.
+Once you have
+sent mail to someone, there is no way to undo the act, so be
+careful.
+.pp
+The message your recipient reads will consist of the message you
+typed, preceded by a line telling who sent the message (your login name)
+and the date and time it
+was sent.
+.pp
+If you want to send the same message to several other people, you can list
+their login names on the command line.
+Thus,
+.(l
+% Mail sam bob john
+Tuition fees are due next Friday. Don't forget!!
+<Control\-d>
+EOT
+%
+.)l
+will send the reminder to sam, bob, and john.
+.pp
+If, when you log in, you see the message,
+.(l
+You have mail.
+.)l
+you can read the mail by typing simply:
+.(l
+% Mail
+.)l
+.i Mail
+will respond by typing its version number and date and then listing
+the messages you have waiting. Then it will type a prompt and await
+your command. The messages are assigned numbers starting with 1 \*- you
+refer to the messages with these numbers.
+.i Mail
+keeps track of which messages are
+.i new
+(have been sent since you last read your mail) and
+.i read
+(have been read by you). New messages have an
+.b N
+next to them in the header listing and old, but unread messages have
+a
+.b U
+next to them.
+.i Mail
+keeps track of new/old and read/unread messages by putting a
+header field called
+.q Status
+into your messages.
+.pp
+To look at a specific message, use the
+.b type
+command, which may be abbreviated to simply
+.b t .
+For example, if you had the following messages:
+.(l
+N 1 root Wed Sep 21 09:21 "Tuition fees"
+N 2 sam Tue Sep 20 22:55
+.)l
+you could examine the first message by giving the command:
+.(l
+type 1
+.)l
+which might cause
+.i Mail
+to respond with, for example:
+.(l
+Message 1:
+From root Wed Sep 21 09:21:45 1978
+Subject: Tuition fees
+Status: R
+
+Tuition fees are due next Wednesday. Don't forget!!
+
+.)l
+Many
+.i Mail
+commands that operate on messages take a message number as an
+argument like the
+.b type
+command. For these commands, there is a notion of a current
+message. When you enter the
+.i Mail
+program, the current message is initially the first one. Thus,
+you can often omit the message number and use, for example,
+.(l
+t
+.)l
+to type the current message. As a further shorthand, you can type a message
+by simply giving its message number. Hence,
+.(l
+1
+.)l
+would type the first message.
+.pp
+Frequently, it is useful to read the messages in your mailbox in order,
+one after another. You can read the next message in
+.i Mail
+by simply typing a newline. As a special case, you can type a newline
+as your first command to
+.i Mail
+to type the first message.
+.pp
+If, after typing a message, you wish to immediately send a reply,
+you can do so with the
+.b reply
+command.
+.b Reply ,
+like
+.b type ,
+takes a message number as an argument.
+.i Mail
+then begins a message addressed to the user who sent you the message.
+You may then type in your letter in reply, followed by a <control-d>
+at the beginning of a line, as before.
+.i Mail
+will type EOT, then type the ampersand prompt to indicate its readiness
+to accept another command. In our example, if, after typing the
+first message, you wished to reply to it, you might give the command:
+.(l
+reply
+.)l
+.i Mail
+responds by typing:
+.(l
+To: root
+Subject: Re: Tuition fees
+.)l
+and waiting for you to enter your letter.
+You are now in the message collection mode described at the beginning
+of this section and
+.i Mail
+will gather up your message up to a control\-d.
+Note that it copies the subject
+header from the original message. This is useful in that correspondence
+about a particular matter will tend to retain the same subject heading,
+making it easy to recognize. If there are other header fields in
+the message, the information found will also be used.
+For example, if the letter had a
+.q "To:"
+header listing several recipients,
+.i Mail
+would arrange to send your replay to the same people as well.
+Similarly, if the original message contained a
+.q "Cc:"
+(carbon copies to) field,
+.i Mail
+would send your reply to
+.i those
+users, too.
+.i Mail
+is careful, though, not too send the message to
+.i you ,
+even if you appear in the
+.q "To:"
+or
+.q "Cc:"
+field, unless you ask to be included explicitly. See section 4 for more
+details.
+.pp
+After typing in your letter, the dialog with
+.i Mail
+might look like the following:
+.(l
+reply
+To: root
+Subject: Tuition fees
+
+Thanks for the reminder
+EOT
+&
+.)l
+.pp
+The
+.b reply
+command is especially useful for sustaining extended conversations
+over the message system, with other
+.q listening
+users receiving copies of the conversation. The
+.b reply
+command can be abbreviated to
+.b r .
+.pp
+Sometimes you will receive a message that has been sent to
+several people and wish to reply
+.i only
+to the person who sent it.
+.b Reply
+with a capital
+.b R
+replies to a message, but sends a copy to the sender only.
+.pp
+If you wish, while reading your mail, to send a message to someone,
+but not as a reply to one of your messages, you can send the message
+directly with the
+.b mail
+command, which takes as arguments the names of the recipients you wish
+to send to. For example, to send a message to
+.q frank,
+you would do:
+.(l
+mail frank
+This is to confirm our meeting next Friday at 4.
+EOT
+&
+.)l
+The
+.b mail
+command can be abbreviated to
+.b m .
+.pp
+Normally, each message you receive is saved in the file
+.i mbox
+in your login directory at the time you leave
+.i Mail .
+Often,
+however, you will not want to save a particular message you
+have received because it is only of passing interest. To avoid
+saving a message in
+.i mbox
+you can delete it using the
+.b delete
+command. In our example,
+.(l
+delete 1
+.)l
+will prevent
+.i Mail
+from saving message 1 (from root) in
+.i mbox .
+In addition to not saving deleted messages,
+.i Mail
+will not let
+you type them, either. The effect is to make the message disappear
+altogether, along with its number. The
+.b delete
+command can be abbreviated to simply
+.b d .
+.pp
+Many features of
+.i Mail
+can be tailored to your liking with the
+.b set
+command. The
+.b set
+command has two forms, depending on whether you are setting
+a
+.i binary
+option or a
+.i valued
+option.
+Binary options are either on or off. For example, the
+.q ask
+option informs
+.i Mail
+that each time you send a message, you want it to prompt you for
+a subject header, to be included in the message.
+To set the
+.q ask
+option, you would type
+.(l
+set ask
+.)l
+.pp
+Another useful
+.i Mail
+option is
+.q hold.
+Unless told otherwise,
+.i Mail
+moves the messages from your system mailbox to the file
+.i mbox
+in your home directory when you leave
+.i Mail .
+If you want
+.i Mail
+to keep your letters in the system mailbox instead, you can set the
+.q hold
+option.
+.pp
+Valued options are values which
+.i Mail
+uses to adapt to your tastes. For example, the
+.q SHELL
+option tells
+.i Mail
+which shell you like to use, and is specified by
+.(l
+set SHELL=/bin/csh
+.)l
+for example. Note that no spaces are allowed in
+.q "SHELL=/bin/csh."
+A complete list of the
+.i Mail
+options appears in section 5.
+.pp
+Another important valued option is
+.q crt.
+If you use a fast video terminal, you will find that when you
+print long messages, they fly by too quickly for you to read them.
+With the
+.q crt
+option, you can make
+.i Mail
+print any message larger than a given number of lines by sending
+it through a paging program. This program is specified by the
+valued option \fBPAGER\fP.
+If \fBPAGER\fP is not set, a default paginator is used.
+For example, most CRT users with 24-line screens should do:
+.(l
+set crt=24
+.)l
+to paginate messages that will not fit on their screens.
+In the default state, \fImore\fP (default paginator) prints a screenful of
+information, then types --More--. Type a space to see the next screenful.
+.pp
+Another adaptation to user needs that
+.i Mail
+provides is that of
+.i aliases .
+An alias is simply a name which stands for one or more
+real user names.
+.i Mail
+sent to an alias is really sent to the list of real users
+associated with it. For example, an alias can be defined for the
+members of a project, so that you can send mail to the whole project
+by sending mail to just a single name. The
+.b alias
+command in
+.i Mail
+defines an alias. Suppose that the users in a project are
+named Sam, Sally, Steve, and Susan. To define an alias called
+.q project
+for them, you would use the
+.i Mail
+command:
+.(l
+alias project sam sally steve susan
+.)l
+The
+.b alias
+command can also be used to provide a convenient name for someone
+whose user name is inconvenient. For example, if a user named
+.q "Bob Anderson"
+had the login name
+.q anderson,"
+you might want to use:
+.(l
+alias bob anderson
+.)l
+so that you could send mail to the shorter name,
+.q bob.
+.pp
+While the
+.b alias
+and
+.b set
+commands allow you to customize
+.i Mail ,
+they have the drawback that they must be retyped each time you enter
+.i Mail .
+To make them more convenient to use,
+.i Mail
+always looks for two files when it is invoked. It first reads
+a system wide file
+.q /etc/mail.rc,
+then a user specific file,
+.q .mailrc,
+which is found in the user's home directory.
+The system wide file
+is maintained by the system administrator and
+contains
+.b set
+commands that are applicable to all users of the system.
+The
+.q .mailrc
+file is usually used by each user to set options the way he likes
+and define individual aliases.
+For example, my .mailrc file looks like this:
+.(l
+set ask nosave SHELL=/bin/csh
+.)l
+As you can see, it is possible to set many options in the
+same
+.b set
+command. The
+.q nosave
+option is described in section 5.
+.pp
+Mail aliasing is implemented
+at the system-wide level
+by the mail delivery
+system
+.i sendmail .
+These aliases are stored in the file /usr/lib/aliases and are
+accessible to all users of the system.
+The lines in /usr/lib/aliases are of
+the form:
+.(l
+alias: name\*<1\*>, name\*<2\*>, name\*<3\*>
+.)l
+where
+.i alias
+is the mailing list name and the
+.i name\*<i\*>
+are the members of the list. Long lists can be continued onto the next
+line by starting the next line with a space or tab. Remember that you
+must execute the shell command
+.i newaliases
+after editing /usr/lib/aliases since the delivery system
+uses an indexed file created by
+.i newaliases .
+.pp
+We have seen that
+.i Mail
+can be invoked with command line arguments which are people
+to send the message to, or with no arguments to read mail.
+Specifying the
+.rb \-f
+flag on the command line causes
+.i Mail
+to read messages from a file other than your system mailbox.
+For example, if you have a collection of messages in
+the file
+.q letters
+you can use
+.i Mail
+to read them with:
+.(l
+% Mail \-f letters
+.)l
+You can use all
+the
+.i Mail
+commands described in this document to examine, modify, or delete
+messages from your
+.q letters
+file, which will be rewritten when you leave
+.i Mail
+with the
+.b quit
+command described below.
+.pp
+Since mail that you read is saved in the file
+.i mbox
+in your home directory by default, you can read
+.i mbox
+in your home directory by using simply
+.(l
+% Mail \-f
+.)l
+.pp
+Normally, messages that you examine using the
+.b type
+command are saved in the file
+.q mbox
+in your home directory if you leave
+.i Mail
+with the
+.b quit
+command described below.
+If you wish to retain a message in your system mailbox
+you can use the
+.b preserve
+command to tell
+.i Mail
+to leave it there.
+The
+.b preserve
+command accepts a list of message numbers, just like
+.b type
+and may be abbreviated to
+.b pre .
+.pp
+Messages in your system mailbox that you do not examine are
+normally retained in your system mailbox automatically.
+If you wish to have such a message saved in
+.i mbox
+without reading it, you may use the
+.b mbox
+command to have them so saved. For example,
+.(l
+mbox 2
+.)l
+in our example would cause the second message (from sam)
+to be saved in
+.i mbox
+when the
+.b quit
+command is executed.
+.b Mbox
+is also the way to direct messages to your
+.i mbox
+file if you have set the
+.q hold
+option described above.
+.b Mbox
+can be abbreviated to
+.b mb .
+.pp
+When you have perused all the messages of interest, you can leave
+.i Mail
+with the
+.b quit
+command, which saves the messages you have typed but not
+deleted in the file
+.i mbox
+in your login directory. Deleted messages are discarded irretrievably,
+and messages left untouched are preserved in your system mailbox so
+that you will see them the next time you type:
+.(l
+% Mail
+.)l
+The
+.b quit
+command can be abbreviated to simply
+.b q .
+.pp
+If you wish for some reason to leave
+.i Mail
+quickly without altering either your system mailbox or
+.i mbox ,
+you can type the
+.b x
+command (short for
+.b exit ),
+which will immediately return you to the Shell without changing anything.
+.pp
+If, instead, you want to execute a Shell command without leaving
+.i Mail ,
+you
+can type the command preceded by an exclamation point, just as in the
+text editor. Thus, for instance:
+.(l
+!date
+.)l
+will print the current date without leaving
+.i Mail .
+.pp
+Finally, the
+.b help
+command is available to print out a brief summary of the
+.i Mail
+commands, using only the single character command abbreviations.
diff --git a/mail_cmds/mail/USD.doc/mail3.nr b/mail_cmds/mail/USD.doc/mail3.nr
new file mode 100644
index 0000000..8b133ef
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail3.nr
@@ -0,0 +1,133 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail3.nr 8.1 (Berkeley) 6/8/93
+.\"
+.sh 1 "Maintaining folders"
+.pp
+.i Mail
+includes a simple facility for maintaining groups of messages together
+in folders. This section describes this facility.
+.pp
+To use the folder facility, you must tell
+.i Mail
+where you wish to keep your folders. Each folder of messages will
+be a single file. For convenience, all of your folders are kept in
+a single directory of your choosing. To tell
+.i Mail
+where your folder directory is, put a line of the form
+.(l
+set folder=letters
+.)l
+in your
+.i .mailrc
+file. If, as in the example above, your folder directory does not
+begin with a `/,'
+.i Mail
+will assume that your folder directory is to be found starting from
+your home directory. Thus, if your home directory is
+.b /home/person
+the above example told
+.i Mail
+to find your folder directory in
+.b /home/person/letters .
+.pp
+Anywhere a file name is expected, you can use a folder name, preceded
+with `+.' For example, to put a message into a folder with the
+.b save
+command, you can use:
+.(l
+save +classwork
+.)l
+to save the current message in the
+.i classwork
+folder. If the
+.i classwork
+folder does not yet exist, it will be created. Note that messages
+which are saved with the
+.b save
+command are automatically removed from your system mailbox.
+.pp
+In order to make a copy of a message in a folder without causing
+that message to be removed from your system mailbox, use the
+.b copy
+command, which is identical in all other respects to the
+.b save
+command. For example,
+.(l
+copy +classwork
+.)l
+copies the current message into the
+.i classwork
+folder and leaves a copy in your system mailbox.
+.pp
+The
+.b folder
+command
+can be used to direct
+.i Mail
+to the contents of a different folder.
+For example,
+.(l
+folder +classwork
+.)l
+directs
+.i Mail
+to read the contents of the
+.i classwork
+folder. All of the commands that you can use on your system
+mailbox are also applicable to folders, including
+.b type ,
+.b delete ,
+and
+.b reply .
+To inquire which folder you are currently editing, use simply:
+.(l
+folder
+.)l
+.pp
+To list your current set of folders, use the
+.b folders
+command.
+.pp
+To start
+.i Mail
+reading one of your folders, you can use the
+.b \-f
+option described in section 2. For example:
+.(l
+% Mail \-f +classwork
+.)l
+will cause
+.i Mail
+to read your
+.i classwork
+folder without looking at your system mailbox.
diff --git a/mail_cmds/mail/USD.doc/mail4.nr b/mail_cmds/mail/USD.doc/mail4.nr
new file mode 100644
index 0000000..1a1e046
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail4.nr
@@ -0,0 +1,437 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail4.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "More about sending mail"
+.sh 2 "Tilde escapes"
+.pp
+While typing in a message to be sent to others, it is often
+useful to be able to invoke the text editor on the partial message,
+print the message, execute a shell command, or do some other
+auxiliary function.
+.i Mail
+provides these capabilities through
+.i "tilde escapes" ,
+which consist of a tilde (~) at the beginning of a line, followed by
+a single character which indicates the function to be performed. For
+example, to print the text of the message so far, use:
+.(l
+~p
+.)l
+which will print a line of dashes, the recipients of your message, and
+the text of the message so far.
+Since
+.i Mail
+requires two consecutive \s-2RUBOUT\s0's to abort a letter, you
+can use a single \s-2RUBOUT\s0 to abort the output of ~p or any other
+~ escape without killing your letter.
+.pp
+If you are dissatisfied with the message as
+it stands, you can invoke the text editor on it using the escape
+.(l
+~e
+.)l
+which causes the message to be copied into a temporary file and an
+instance of the editor to be spawned. After modifying the message to
+your satisfaction, write it out and quit the editor.
+.i Mail
+will respond
+by typing
+.(l
+(continue)
+.)l
+after which you may continue typing text which will be appended to your
+message, or type <control-d> to end the message.
+A standard text editor is provided by
+.i Mail .
+You can override this default by setting the valued option
+.q EDITOR
+to something else. For example, you might prefer:
+.(l
+set EDITOR=/usr/bin/ex
+.)l
+.pp
+Many systems offer a screen editor as an alternative to the standard
+text editor, such as the
+.i vi
+editor from UC Berkeley.
+To use the screen, or
+.i visual
+editor, on your current message, you can use the escape,
+.(l
+~v
+.)l
+~v works like ~e, except that the screen editor is invoked instead.
+A default screen editor is defined by
+.i Mail .
+If it does not suit you, you can set the valued option
+.q VISUAL
+to the path name of a different editor.
+.pp
+It is often useful to be able to include the contents of some
+file in your message; the escape
+.(l
+~r filename
+.)l
+is provided for this purpose, and causes the named file to be appended
+to your current message.
+.i Mail
+complains if the file doesn't exist
+or can't be read. If the read is successful, the number of lines and
+characters appended to your message is printed, after which you may continue
+appending text. The filename may contain shell metacharacters like * and ?
+which are expanded according to the conventions of your shell.
+.pp
+As a special case of ~r, the escape
+.(l
+~d
+.)l
+reads in the file
+.q dead.letter
+in your home directory. This is often useful since
+.i Mail
+copies the text
+of your message there when you abort a message with \s-2RUBOUT\s0.
+.pp
+To save the current text of your message on a file you may use the
+.(l
+~w filename
+.)l
+escape.
+.i Mail
+will print out the number of lines and characters written
+to the file, after which you may continue appending text to your message.
+Shell metacharacters may be used in the filename, as in ~r and are expanded
+with the conventions of your shell.
+.pp
+If you are sending mail from within
+.i Mail's
+command mode
+you can read a message sent to you into the message
+you are constructing with the escape:
+.(l
+~m 4
+.)l
+which will read message 4 into the current message, shifted right by
+one tab stop. You can name any non-deleted message, or list of messages.
+Messages can also be forwarded without shifting by a tab stop with ~f.
+This is the usual way to forward a message.
+.pp
+If, in the process of composing a message, you decide to add additional
+people to the list of message recipients, you can do so with the escape
+.(l
+~t name1 name2 ...
+.)l
+You may name as few or many additional recipients as you wish. Note
+that the users originally on the recipient list will still receive
+the message; you cannot remove someone from the recipient
+list with ~t.
+.pp
+If you wish, you can associate a subject with your message by using the
+escape
+.(l
+~s Arbitrary string of text
+.)l
+which replaces any previous subject with
+.q "Arbitrary string of text."
+The subject, if given, is sent near the
+top of the message prefixed with
+.q "Subject:"
+You can see what the message will look like by using ~p.
+.pp
+For political reasons, one occasionally prefers to list certain
+people as recipients of carbon copies of a message rather than
+direct recipients. The escape
+.(l
+~c name1 name2 ...
+.)l
+adds the named people to the
+.q "Cc:"
+list, similar to ~t.
+Again, you can execute ~p to see what the message will look like.
+.pp
+The escape
+.(l
+~b name1 name2 ...
+.)l
+adds the named people to the
+.q "Cc:"
+list, but does not make the names visible in the
+.q "Cc:"
+line ("blind" carbon copy).
+.pp
+The recipients of the message together constitute the
+.q "To:"
+field, the subject the
+.q "Subject:"
+field, and the carbon copies the
+.q "Cc:"
+field. If you wish to edit these in ways impossible with the ~t, ~s, ~c
+and ~b escapes, you can use the escape
+.(l
+~h
+.)l
+which prints
+.q "To:"
+followed by the current list of recipients and leaves the cursor
+(or printhead) at the end of the line. If you type in ordinary
+characters, they are appended to the end of the current list of
+recipients. You can also use your erase character to erase back into
+the list of recipients, or your kill character to erase them altogether.
+Thus, for example, if your erase and kill characters are the standard
+(on printing terminals) # and @ symbols,
+.(l
+~h
+To: root kurt####bill
+.)l
+would change the initial recipients
+.q "root kurt"
+to
+.q "root bill."
+When you type a newline,
+.i Mail
+advances to the
+.q "Subject:"
+field, where the same rules apply. Another newline brings you to
+the
+.q "Cc:"
+field, which may be edited in the same fashion. Another newline
+brings you to the
+.q "Bcc:"
+("blind" carbon copy) field, which follows the same rules as the "Cc:"
+field. Another newline
+leaves you appending text to the end of your message. You can use
+~p to print the current text of the header fields and the body
+of the message.
+.pp
+To effect a temporary escape to the shell, the escape
+.(l
+~!command
+.)l
+is used, which executes
+.i command
+and returns you to mailing mode without altering the text of
+your message. If you wish, instead, to filter the body of your
+message through a shell command, then you can use
+.(l
+~|command
+.)l
+which pipes your message through the command and uses the output
+as the new text of your message. If the command produces no output,
+.i Mail
+assumes that something is amiss and retains the old version
+of your message. A frequently-used filter is the command
+.i fmt ,
+designed to format outgoing mail.
+.pp
+To effect a temporary escape to
+.i Mail
+command mode instead, you can use the
+.(l
+~:\fIMail command\fP
+.)l
+escape. This is especially useful for retyping the message you are
+replying to, using, for example:
+.(l
+~:t
+.)l
+It is also useful for setting options and modifying aliases.
+.pp
+If you wish abort the current message, you can use the escape
+.(l
+~q
+.)l
+This will terminate the current message and return you to the
+shell (or \fIMail\fP if you were using the \fBmail\fP command).
+If the \fBsave\fP option is set, the message will be copied
+to the file
+.q dead.letter
+in your home directory.
+.pp
+If you wish (for some reason) to send a message that contains
+a line beginning with a tilde, you must double it. Thus, for example,
+.(l
+~~This line begins with a tilde.
+.)l
+sends the line
+.(l
+~This line begins with a tilde.
+.)l
+.pp
+Finally, the escape
+.(l
+~?
+.)l
+prints out a brief summary of the available tilde escapes.
+.pp
+On some terminals (particularly ones with no lower case)
+tilde's are difficult to type.
+.i Mail
+allows you to change the escape character with the
+.q escape
+option. For example, I set
+.(l
+set escape=]
+.)l
+and use a right bracket instead of a tilde. If I ever need to
+send a line beginning with right bracket, I double it, just as for ~.
+Changing the escape character removes the special meaning of ~.
+.sh 2 "Network access"
+.pp
+This section describes how to send mail to people on other machines.
+Recall that sending to a plain login name sends mail to that person
+on your machine. If your machine is directly (or sometimes, even,
+indirectly) connected to the Arpanet, you can send messages to people
+on the Arpanet using a name of the form
+.(l
+name@host.domain
+.)l
+where
+.i name
+is the login name of the person you're trying to reach,
+.i host
+is the name of the machine on the Arpanet,
+and
+.i domain
+is the higher-level scope within which the hostname is known, e.g. EDU (for educational
+institutions), COM (for commercial entities), GOV (for governmental agencies),
+ARPA for many other things, BITNET or CSNET for those networks.
+.pp
+If your recipient logs in on a machine connected to yours by
+UUCP (the Bell Laboratories supplied network that communicates
+over telephone lines), sending mail can be a bit more complicated.
+You must know the list of machines through which your message must
+travel to arrive at his site. So, if his machine is directly connected
+to yours, you can send mail to him using the syntax:
+.(l
+host!name
+.)l
+where, again,
+.i host
+is the name of the machine and
+.i name
+is the login name.
+If your message must go through an intermediary machine first, you
+must use the syntax:
+.(l
+intermediary!host!name
+.)l
+and so on. It is actually a feature of UUCP that the map of all
+the systems in the network is not known anywhere (except where people
+decide to write it down for convenience). Talk to your system administrator
+about good ways to get places; the
+.i uuname
+command will tell you systems whose names are recognized, but not which
+ones are frequently called or well-connected.
+.pp
+When you use the
+.b reply
+command to respond to a letter, there is a problem of figuring out the
+names of the users in the
+.q "To:"
+and
+.q "Cc:"
+lists
+.i "relative to the current machine" .
+If the original letter was sent to you by someone on the local machine,
+then this problem does not exist, but if the message came from a remote
+machine, the problem must be dealt with.
+.i Mail
+uses a heuristic to build the correct name for each user relative
+to the local machine. So, when you
+.b reply
+to remote mail, the names in the
+.q "To:"
+and
+.q "Cc:"
+lists may change somewhat.
+.sh 2 "Special recipients"
+.pp
+As described previously, you can send mail to either user names or
+.b alias
+names. It is also possible to send messages directly to files or to
+programs, using special conventions. If a recipient name has a
+`/' in it or begins with a `+', it is assumed to be the
+path name of a file into which
+to send the message. If the file already exists, the message is
+appended to the end of the file. If you want to name a file in
+your current directory (ie, one for which a `/' would not usually
+be needed) you can precede the name with `./'
+So, to send mail to the file
+.q memo
+in the current directory, you can give the command:
+.(l
+% Mail ./memo
+.)l
+If the name begins with a `+,' it is expanded into the full path name
+of the folder name in your folder directory.
+This ability to send mail to files can be used for a variety of
+purposes, such as maintaining a journal and keeping a record of
+mail sent to a certain group of users. The second example can be
+done automatically by including the full pathname of the record
+file in the
+.b alias
+command for the group. Using our previous
+.b alias
+example, you might give the command:
+.(l
+alias project sam sally steve susan /usr/project/mail_record
+.)l
+Then, all mail sent to "project" would be saved on the file
+.q /usr/project/mail_record
+as well as being sent to the members of the project. This file
+can be examined using
+.i "Mail \-f" .
+.pp
+It is sometimes useful to send mail directly to a program, for
+example one might write a project billboard program and want to access
+it using
+.i Mail .
+To send messages to the billboard program, one can send mail
+to the special name `|billboard' for example.
+.i Mail
+treats recipient names that begin with a `|' as a program to send
+the mail to. An
+.b alias
+can be set up to reference a `|' prefaced name if desired.
+.i Caveats :
+the shell treats `|' specially, so it must be quoted on the command
+line. Also, the `| program' must be presented as a single argument to
+mail. The safest course is to surround the entire name with double
+quotes. This also applies to usage in the
+.b alias
+command. For example, if we wanted to alias `rmsgs' to `rmsgs \-s'
+we would need to say:
+.(l
+alias rmsgs "| rmsgs -s"
+.)l
diff --git a/mail_cmds/mail/USD.doc/mail5.nr b/mail_cmds/mail/USD.doc/mail5.nr
new file mode 100644
index 0000000..0116303
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail5.nr
@@ -0,0 +1,1042 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail5.nr 8.1 (Berkeley) 6/8/93
+.\" $FreeBSD: src/usr.bin/mail/USD.doc/mail5.nr,v 1.4 2000/11/29 10:56:59 ru Exp $
+.\"
+.bp
+.sh 1 "Additional features"
+.pp
+This section describes some additional commands useful for
+reading your mail, setting options, and handling lists of messages.
+.sh 2 "Message lists"
+.pp
+Several
+.i Mail
+commands accept a list of messages as an argument.
+Along with
+.b type
+and
+.b delete ,
+described in section 2,
+there is the
+.b from
+command, which prints the message headers associated with the
+message list passed to it.
+The
+.b from
+command is particularly useful in conjunction with some of the
+message list features described below.
+.pp
+A
+.i "message list"
+consists of a list of message numbers, ranges, and names,
+separated by spaces or tabs. Message numbers may be either
+decimal numbers, which directly specify messages, or one of the
+special characters
+.q \(ua
+.q "."
+or
+.q "$"
+to specify the first relevant, current, or last
+relevant message, respectively.
+.i Relevant
+here means, for most commands
+.q "not deleted"
+and
+.q "deleted"
+for the
+.b undelete
+command.
+.pp
+A range of messages consists of two message numbers (of the form
+described in the previous paragraph) separated by a dash.
+Thus, to print the first four messages, use
+.(l
+type 1\-4
+.)l
+and to print all the messages from the current message to the last
+message, use
+.(l
+type .\-$
+.)l
+.pp
+A
+.i name
+is a user name. The user names given in the message list are
+collected together and each message selected by other means
+is checked to make sure it was sent by one of the named users.
+If the message consists entirely of user names, then every
+message sent by one of those users that is
+.i relevant
+(in the sense described earlier)
+is selected. Thus, to print every message sent to you by
+.q root,
+do
+.(l
+type root
+.)l
+.pp
+As a shorthand notation, you can specify simply
+.q *
+to get every
+.i relevant
+(same sense)
+message. Thus,
+.(l
+type *
+.)l
+prints all undeleted messages,
+.(l
+delete *
+.)l
+deletes all undeleted messages, and
+.(l
+undelete *
+.)l
+undeletes all deleted messages.
+.pp
+You can search for the presence of a word in subject lines with
+.b / .
+For example, to print the headers of all messages that contain the
+word
+.q PASCAL,
+do:
+.(l
+from /pascal
+.)l
+Note that subject searching ignores upper/lower case differences.
+.sh 2 "List of commands"
+.pp
+This section describes all the
+.i Mail
+commands available when
+receiving mail.
+.ip "\fB\-\fP\ \ "
+The
+.rb \-
+command goes to the previous message and prints it. The
+.rb \-
+command may be given a decimal number
+.i n
+as an argument, in which case the
+.i n th
+previous message is gone to and printed.
+.ip "\fB?\fP\ \ "
+Prints a brief summary of commands.
+.ip "\fB!\fP\ \ "
+Used to preface a command to be executed by the shell.
+.ip "\fBPrint\fP\ \ "
+Like
+.b print ,
+but also print out ignored header fields. See also
+\fBprint\fP, \fBignore\fP and \fBretain\fP.
+\fBPrint\fP can be abbreviated to \fBP\fP.
+.ip "\fBReply\fP or \fBRespond\fP\ \ "
+Note the capital \fBR\fP in the name.
+Frame a reply to a one or more messages.
+The reply (or replies if you are using this on multiple messages)
+will be sent ONLY to the person who sent you the message
+(respectively, the set of people who sent the messages you are
+replying to).
+You can
+add people using the \fB~t\fP, \fB~c\fP and \fB~b\fP
+tilde escapes. The subject in your reply is formed by prefacing the
+subject in the original message with
+.q "Re:"
+unless it already began thus.
+If the original message included a
+.q "reply-to"
+header field, the reply will go
+.i only
+to the recipient named by
+.q "reply-to."
+You type in your message using the same conventions available to you
+through the
+.b mail
+command.
+The
+.b Reply
+command is especially useful for replying to messages that were sent
+to enormous distribution groups when you really just want to
+send a message to the originator. Use it often.
+\fBReply\fP (and \fBRespond\fP) can be abbreviated to \fBR\fP.
+.ip "\fBType\fP\ \ "
+Identical to the
+.b Print
+command.
+\fBType\fP can be abbreviated to \fBT\fP.
+.ip "\fBalias\fP\ \ "
+Define a name to stand for a set of other names.
+This is used when you want to send messages to a certain
+group of people and want to avoid retyping their names.
+For example
+.(l
+alias project john sue willie kathryn
+.)l
+creates an alias
+.i project
+which expands to the four people John, Sue, Willie, and Kathryn.
+If no arguments are given, all currently-defined aliases are printed.
+If one argument is given, that alias is printed (if it exists).
+\fBAlias\fP can be abbreviated to \fBa\fP.
+.ip "\fBalternates\fP\ \ "
+If you have accounts on several machines, you may find it convenient
+to use the /usr/lib/aliases on all the machines except one to direct
+your mail to a single account.
+The
+.b alternates
+command is used to inform
+.i Mail
+that each of these other addresses is really
+.i you .
+.i Alternates
+takes a list of user names and remembers that they are all actually you.
+When you
+.b reply
+to messages that were sent to one of these alternate names,
+.i Mail
+will not bother to send a copy of the message to this other address (which
+would simply be directed back to you by the alias mechanism).
+If
+.i alternates
+is given no argument, it lists the current set of alternate names.
+.b Alternates
+is usually used in the .mailrc file.
+\fBAlternates\fP can be abbreviated to \fBalt\fP.
+.ip "\fBchdir\fP\ \ "
+The
+.b chdir
+command allows you to change your current directory.
+.b Chdir
+takes a single argument, which is taken to be the pathname of
+the directory to change to. If no argument is given,
+.b chdir
+changes to your home directory.
+\fBChdir\fP can be abbreviated to \fBc\fP.
+.ip "\fBcopy\fP\ \ "
+The
+.b copy
+command does the same thing that
+.b save
+does, except that it does not mark the messages it is used on
+for deletion when you quit.
+\fBCopy\fP can be abbreviated to \fBco\fP.
+.ip "\fBdelete\fP\ \ "
+Deletes a list of messages. Deleted messages can be reclaimed
+with the
+.b undelete
+command.
+\fBDelete\fP can be abbreviated to \fBd\fP.
+.ip "\fBdp\fP or \fBdt\fP\ \ "
+These
+commands delete the current message and print the next message.
+They are useful for quickly reading and disposing of mail.
+If there is no next message, \fImail\fP says ``at EOF.''
+.ip "\fBedit\fP\ \ "
+To edit individual messages using the text editor, the
+.b edit
+command is provided. The
+.b edit
+command takes a list of messages as described under the
+.b type
+command and processes each by writing it into the file
+Message\c
+.i x
+where
+.i x
+is the message number being edited and executing the text editor on it.
+When you have edited the message to your satisfaction, write the message
+out and quit, upon which
+.i Mail
+will read the message back and remove the file.
+.b Edit
+can be abbreviated to
+.b e .
+.ip "\fBelse\fP\ \ "
+Marks the end of the then-part of an
+.b if
+statement and the beginning of the
+part to take effect if the condition of the
+.b if
+statement is false.
+.ip "\fBendif\fP\ \ "
+Marks the end of an
+.b if
+statement.
+.ip "\fBexit\fP or \fBxit\fP\ \ "
+Leave
+.i Mail
+without updating the system mailbox or the file your were reading.
+Thus, if you accidentally delete several messages, you can use
+.b exit
+to avoid scrambling your mailbox.
+\fBExit\fP can be abbreviated to \fBex\fP or \fBx\fP.
+.ip "\fBfile\fP\ \ "
+The same as
+.b folder .
+\fBFile\fP can be abbreviated to \fBfi\fP.
+.ip "\fBfolders\fP\ \ "
+List the names of the folders in your folder directory.
+.ip "\fBfolder\fP\ \ "
+The
+.b folder
+command switches to a new mail file or folder. With no arguments, it
+tells you which file you are currently reading. If you give
+it an argument, it will write out changes (such as deletions)
+you have made in the current file and read the new file.
+Some special conventions are recognized for the name:
+.(b
+.TS
+center;
+c c
+l a.
+Name Meaning
+_
+# Previous file read
+% Your system mailbox
+%name \fIName\fP's system mailbox
+& Your ~/mbox file
++folder A file in your folder directory
+.TE
+.)b
+\fBFolder\fP can be abbreviated to \fBfo\fP.
+.ip "\fBfrom\fP\ \ "
+The
+.b from
+command takes a list of messages and prints out the header lines for each one;
+hence
+.(l
+from joe
+.)l
+is the easy way to display all the message headers from \*(lqjoe.\*(rq
+\fBFrom\fP can be abbreviated to \fBf\fP.
+.ip "\fBheaders\fP\ \ "
+When you start up
+.i Mail
+to read your mail, it lists the message headers that you have.
+These headers tell you who each message is from, when they were
+received, how many lines and characters each message is, and the
+.q "Subject:"
+header field of each message, if present. In addition,
+.i Mail
+tags the message header of each message that has been the object
+of the
+.b preserve
+command with a
+.q P.
+Messages that have been
+.b saved
+or
+.b written
+are flagged with a
+.q *.
+Finally,
+.b deleted
+messages are not printed at all. If you wish to reprint the current
+list of message headers, you can do so with the
+.b headers
+command. The
+.b headers
+command (and thus the initial header listing)
+only lists the first so many message headers.
+The number of headers listed depends on the speed of your
+terminal.
+This can be overridden by specifying the number of headers you
+want with the
+.i window
+option.
+.i Mail
+maintains a notion of the current
+.q window
+into your messages for the purposes of printing headers.
+Use the
+.b z
+command to move forward and back a window.
+You can move
+.i Mail's
+notion of the current window directly to a particular message by
+using, for example,
+.(l
+headers 40
+.)l
+to move
+.i Mail's
+attention to the messages around message 40.
+If a ``+'' argument is given, then the next screenful of message headers is
+printed, and if a ``\-'' argument is given, the previous screenful of message
+headers is printed.
+\fBHeaders\fP can be abbreviated to \fBh\fP.
+.ip "\fBhelp\fP\ \ "
+Print a brief and usually out of date help message about the commands
+in
+.i Mail .
+The
+.i man
+page for
+.i mail
+is usually more up-to-date than either the help message or this manual.
+It is also a synonym for \fB?\fP.
+.ip "\fBhold\fP\ \ "
+Arrange to hold a list of messages in the system mailbox, instead
+of moving them to the file
+.i mbox
+in your home directory. If you set the binary option
+.i hold ,
+this will happen by default.
+It does not override the \fBdelete\fP command.
+\fBHold\fP can be abbreviated to \fBho\fP.
+.ip "\fBif\fP\ \ "
+Commands in your
+.q .mailrc
+file can be executed conditionally depending on whether you are
+sending or receiving mail with the
+.b if
+command. For example, you can do:
+.(l
+if receive
+ \fIcommands\fP...
+endif
+.)l
+An
+.b else
+form is also available:
+.(l
+if send
+ \fIcommands\fP...
+else
+ \fIcommands\fP...
+endif
+.)l
+Note that the only allowed conditions are
+.b receive
+and
+.b send .
+.ip "\fBignore\fP \ \ "
+.b N.B.:
+.i Ignore
+has been superseded by
+.i retain.
+.br
+Add the list of header fields named to the
+.i "ignore list" .
+Header fields in the ignore list are not printed on your
+terminal when you print a message. This allows you to suppress
+printing of certain machine-generated header fields, such as
+.i Via
+which are not usually of interest. The
+.b Type
+and
+.b Print
+commands can be used to print a message in its entirety, including
+ignored fields.
+If
+.b ignore
+is executed with no arguments, it lists the current set of ignored fields.
+.ip "\fBlist\fP\ \ "
+List the valid
+.i Mail
+commands.
+\fBList\fP can be abbreviated to \fBl\fP.
+.\".ip \fBlocal\fP
+.\"Define a list of local names for this host. This command is useful
+.\"when the host is known by more than one name. Names in the list
+.\"may be qualified be the domain of the host. The first name on the local
+.\"list is the
+.\".i distinguished
+.\"name of the host.
+.\"The names on the local list are used by
+.\".i Mail
+.\"to decide which addresses are local to the host.
+.\"For example:
+.\".(l
+.\"local ucbarpa.BERKELEY.ARPA arpa.BERKELEY.ARPA \\
+.\" arpavax.BERKELEY.ARPA r.BERKELEY.ARPA \\
+.\" ucb-arpa.ARPA
+.\".)l
+.\"From this list we see that
+.\".i "fred@ucbarpa.BERKELEY.ARPA",
+.\".i "harold@arpa.BERKELEY",
+.\"and
+.\".i "larry@r"
+.\"are all addresses of users on the local host.
+.\"The
+.\".b local
+.\"command is usually not used be general users since it is designed for
+.\"local configuration; it is usually found in the file /etc/mail.rc.
+.ip "\fBmail\fP\ \ "
+Send mail to one or more people. If you have the
+.i ask
+option set,
+.i Mail
+will prompt you for a subject to your message. Then you
+can type in your message, using tilde escapes as described in
+section 4 to edit, print, or modify your message. To signal your
+satisfaction with the message and send it, type control-d at the
+beginning of a line, or a . alone on a line if you set the option
+.i dot .
+To abort the message, type two interrupt characters (\s-2RUBOUT\s0
+by default) in a row or use the
+.b ~q
+escape.
+The \fBmail\fP command can be abbreviated to \fBm\fP.
+.ip "\fBmbox\fP\ \ "
+Indicate that a list of messages be sent to
+.i mbox
+in your home directory when you quit. This is the default
+action for messages if you do
+.i not
+have the
+.i hold
+option set.
+.ip "\fBnext\fP or \fB+\fP\ \ "
+The
+.b next
+command goes to the next message and types it. If given a message list,
+.b next
+goes to the first such message and types it. Thus,
+.(l
+next root
+.)l
+goes to the next message sent by
+.q root
+and types it. The
+.b next
+command can be abbreviated to simply a newline, which means that one
+can go to and type a message by simply giving its message number or
+one of the magic characters
+.q "^"
+.q "."
+or
+.q "$".
+Thus,
+.(l
+\&.
+.)l
+prints the current message and
+.(l
+4
+.)l
+prints message 4, as described previously.
+\fBNext\fP can be abbreviated to \fBn\fP.
+.ip "\fBpreserve\fP\ \ "
+Same as
+.b hold .
+Cause a list of messages to be held in your system mailbox when you quit.
+\fBPreserve\fP can be abbreviated to \fBpre\fP.
+.ip "\fBprint\fP\ \ "
+Print the specified messages. If the
+.b crt
+variable is set, messages longer than the number of lines it indicates
+are paged through the command specified by the \fBPAGER\fP variable.
+The \fBprint\fP command can be abbreviated to \fBp\fP.
+.ip "\fBquit\fP\ \ "
+Terminates the session, saving all undeleted, unsaved and unwritten messages
+in the user's \fImbox\fP file in their login directory
+(messages marked as having been read), preserving all
+messages marked with \fBhold\fP or \fBpreserve\fP or never referenced
+in their system mailbox.
+Any messages that were deleted, saved, written or saved to \fImbox\fP are
+removed from their system mailbox.
+If new mail has arrived during the session, the message
+``You have new mail'' is given. If given while editing a mailbox file
+with the \fB\-f\fP flag, then the edit file is rewritten.
+A return to the Shell is effected, unless the rewrite of edit file fails,
+in which case the user can escape with the \fBexit\fP command.
+\fBQuit\fP can be abbreviated to \fBq\fP.
+.ip "\fBreply\fP or \fBrespond\fP\ \ "
+Frame a reply to a single message.
+The reply will be sent to the
+person who sent you the message (to which you are replying), plus all
+the people who received the original message, except you. You can
+add people using the \fB~t\fP, \fB~c\fP and \fB~b\fP
+tilde escapes. The subject in your reply is formed by prefacing the
+subject in the original message with
+.q "Re:"
+unless it already began thus.
+If the original message included a
+.q "reply-to"
+header field, the reply will go
+.i only
+to the recipient named by
+.q "reply-to."
+You type in your message using the same conventions available to you
+through the
+.b mail
+command.
+The \fBreply\fP (and \fBrespond\fP) command can be abbreviated to \fBr\fP.
+.ip "\fBretain\fP\ \ "
+Add the list of header fields named to the \fIretained list\fP.
+Only the header fields in the retain list
+are shown on your terminal when you print a message.
+All other header fields are suppressed.
+The
+.b Type
+and
+.b Print
+commands can be used to print a message in its entirety.
+If
+.b retain
+is executed with no arguments, it lists the current set of
+retained fields.
+.ip "\fBsave\fP\ \ "
+It is often useful to be able to save messages on related topics
+in a file. The
+.b save
+command gives you the ability to do this. The
+.b save
+command takes as an argument a list of message numbers, followed by
+the name of the file in which to save the messages. The messages
+are appended to the named file, thus allowing one to keep several
+messages in the file, stored in the order they were put there.
+The filename in quotes, followed by the line
+count and character count is echoed on the user's terminal.
+An example of the
+.b save
+command relative to our running example is:
+.(l
+s 1 2 tuitionmail
+.)l
+.b Saved
+messages are not automatically saved in
+.i mbox
+at quit time, nor are they selected by the
+.b next
+command described above, unless explicitly specified.
+\fBSave\fP can be abbreviated to \fBs\fP.
+.ip "\fBset\fP\ \ "
+Set an option or give an option a value. Used to customize
+.i Mail .
+Section 5.3 contains a list of the options. Options can be
+.i binary ,
+in which case they are
+.i on
+or
+.i off ,
+or
+.i valued .
+To set a binary option
+.i option
+.i on ,
+do
+.(l
+set option
+.)l
+To give the valued option
+.i option
+the value
+.i value ,
+do
+.(l
+set option=value
+.)l
+There must be no space before or after the ``='' sign.
+If no arguments are given, all variable values are printed.
+Several options can be specified in a single
+.b set
+command.
+\fBSet\fP can be abbreviated to \fBse\fP.
+.ip "\fBshell\fP\ \ "
+The
+.b shell
+command allows you to
+escape to the shell.
+.b Shell
+invokes an interactive shell and allows you to type commands to it.
+When you leave the shell, you will return to
+.i Mail .
+The shell used is a default assumed by
+.i Mail ;
+you can override this default by setting the valued option
+.q SHELL,
+eg:
+.(l
+set SHELL=/bin/csh
+.)l
+\fBShell\fP can be abbreviated to \fBsh\fP.
+.ip "\fBsize\fP\ \ "
+Takes a message list and prints out the size in characters of each
+message.
+.ip "\fBsource\fP\ \ "
+The
+.b source
+command reads
+.i mail
+commands from a file. It is useful when you are trying to fix your
+.q .mailrc
+file and you need to re-read it.
+\fBSource\fP can be abbreviated to \fBso\fP.
+.ip "\fBtop\fP\ \ "
+The
+.b top
+command takes a message list and prints the first five lines
+of each addressed message.
+If you wish, you can change the number of lines that
+.b top
+prints out by setting the valued option
+.q "toplines."
+On a CRT terminal,
+.(l
+set toplines=10
+.)l
+might be preferred.
+\fBTop\fP can be abbreviated to \fBto\fP.
+.ip "\fBtype\fP\ \ "
+Same as \fBprint\fP.
+Takes a message list and types out each message on the terminal.
+The \fBtype\fP command can be abbreviated to \fBt\fP.
+.ip "\fBundelete\fP \ \"
+Takes a message list and marks each message as \fInot\fP
+being deleted.
+\fBUndelete\fP can be abbreviated to \fBu\fP.
+.ip "\fBunread\fP\ \ "
+Takes a message list and marks each message as
+.i not
+having been read.
+\fBUnread\fP can be abbreviated to \fBU\fP.
+.ip "\fBunset\fP\ \ "
+Takes a list of option names and discards their remembered values;
+the inverse of \fBset\fP .
+.ip "\fBvisual\fP\ \ "
+It is often useful to be able to invoke one of two editors,
+based on the type of terminal one is using. To invoke
+a display oriented editor, you can use the
+.b visual
+command. The operation of the
+.b visual
+command is otherwise identical to that of the
+.b edit
+command.
+.ne 2v+\n(psu
+.sp \n(psu
+Both the
+.b edit
+and
+.b visual
+commands assume some default text editors. These default editors
+can be overridden by the valued options
+.q EDITOR
+and
+.q VISUAL
+for the standard and screen editors. You might want to do:
+.(l
+set EDITOR=/usr/bin/ex VISUAL=/usr/bin/vi
+.)l
+\fBVisual\fP can be abbreviated to \fBv\fP.
+.ip "\fBwrite\fP\ \ "
+The
+.b save
+command always writes the entire message, including the headers,
+into the file. If you want to write just the message itself, you
+can use the
+.b write
+command. The
+.b write
+command has the same syntax as the
+.b save
+command, and can be abbreviated to simply
+.b w .
+Thus, we could write the second message by doing:
+.(l
+w 2 file.c
+.)l
+As suggested by this example, the
+.b write
+command is useful for such tasks as sending and receiving
+source program text over the message system.
+The filename in quotes, followed by the line
+count and character count is echoed on the user's terminal.
+.ip "\fBz\fP\ \ "
+.i Mail
+presents message headers in windowfuls as described under
+the
+.b headers
+command.
+You can move
+.i Mail's
+attention forward to the next window by giving the
+.(l
+z+
+.)l
+command. Analogously, you can move to the previous window with:
+.(l
+z\-
+.)l
+.sh 2 "Custom options"
+.pp
+Throughout this manual, we have seen examples of binary and valued options.
+This section describes each of the options in alphabetical order, including
+some that you have not seen yet.
+To avoid confusion, please note that the options are either
+all lower case letters or all upper case letters. When I start a sentence
+such as:
+.q "Ask"
+causes
+.i Mail
+to prompt you for a subject header,
+I am only capitalizing
+.q ask
+as a courtesy to English.
+.ip "\fBEDITOR\fP\ \ "
+The valued option
+.q EDITOR
+defines the pathname of the text editor to be used in the
+.b edit
+command and ~e. If not defined, a standard editor is used.
+.ip "\fBPAGER\fP\ \ "
+Pathname of the program to use for paginating output when
+it exceeds \fIcrt\fP lines.
+A default paginator is used if this option is not defined.
+.ip "\fBSHELL\fP\ \ "
+The valued option
+.q SHELL
+gives the path name of your shell. This shell is used for the
+.b !
+command and ~! escape. In addition, this shell expands
+file names with shell metacharacters like * and ? in them.
+.ip "\fBVISUAL\fP\ \ "
+The valued option
+.q VISUAL
+defines the pathname of the screen editor to be used in the
+.b visual
+command
+and ~v escape. A standard screen editor is used if you do not define one.
+.ip "\fBappend\fP\ \ "
+The
+.q append
+option is binary and
+causes messages saved in
+.i mbox
+to be appended to the end rather than prepended.
+Normally, \fIMail\fP will put messages in \fImbox\fP
+in the same order that the system puts messages in your system mailbox.
+By setting
+.q append,
+you are requesting that
+.i mbox
+be appended to regardless. It is in any event quicker to append.
+.ip "\fBask\fP\ \ "
+.q "Ask"
+is a binary option which
+causes
+.i Mail
+to prompt you for the subject of each message you send.
+If you respond with simply a newline, no subject field will be sent.
+.ip "\fBaskcc\fP\ \ "
+.q Askcc
+is a binary option which
+causes you to be prompted for additional carbon copy recipients at the
+end of each message. Responding with a newline shows your
+satisfaction with the current list.
+.ip "\fBautoprint\fP\ \ "
+.q Autoprint
+is a binary option which
+causes the
+.b delete
+command to behave like
+.b dp
+\*- thus, after deleting a message, the next one will be typed
+automatically. This is useful when quickly scanning and deleting
+messages in your mailbox.
+.ip "\fBcrt\fP \ \ "
+The valued option
+.q crt
+is used as a threshold to determine how long a message must
+be before
+.b PAGER
+is used to read it.
+.ip "\fBdebug\fP \ \ "
+The binary option
+.q debug
+causes debugging information to be displayed. Use of this
+option is the same as using the \fB\-d\fP command line flag.
+.ip "\fBdot\fP\ \ "
+.q Dot
+is a binary option which, if set, causes
+.i Mail
+to interpret a period alone on a line as the terminator
+of the message you are sending.
+.ip "\fBescape\fP\ \ "
+To allow you to change the escape character used when sending
+mail, you can set the valued option
+.q escape.
+Only the first character of the
+.q escape
+option is used, and it must be doubled if it is to appear as
+the first character of a line of your message. If you change your escape
+character, then ~ loses all its special meaning, and need no longer be doubled
+at the beginning of a line.
+.ip "\fBfolder\fP\ \ "
+The name of the directory to use for storing folders of messages.
+If this name begins with a `/'
+.i Mail
+considers it to be an absolute pathname; otherwise, the folder directory
+is found relative to your home directory.
+.ip "\fBhold\fP\ \ "
+The binary option
+.q hold
+causes messages that have been read but not manually dealt with
+to be held in the system mailbox. This prevents such messages from
+being automatically swept into your \fImbox\fP file.
+.ip "\fBignore\fP\ \ "
+The binary option
+.q ignore
+causes \s-2RUBOUT\s0 characters from your terminal to be ignored and echoed
+as @'s while you are sending mail. \s-2RUBOUT\s0 characters retain their
+original meaning in
+.i Mail
+command mode.
+Setting the
+.q ignore
+option is equivalent to supplying the
+.b \-i
+flag on the command line as described in section 6.
+.ip "\fBignoreeof\fP\ \ "
+An option related to
+.q dot
+is
+.q ignoreeof
+which makes
+.i Mail
+refuse to accept a control\-d as the end of a message.
+.q Ignoreeof
+also applies to
+.i Mail
+command mode.
+.ip "\fBkeep\fP\ \ "
+The
+.q keep
+option causes
+.i Mail
+to truncate your system mailbox instead of deleting it when it
+is empty. This is useful if you elect to protect your mailbox, which
+you would do with the shell command:
+.(l
+chmod 600 /var/mail/yourname
+.)l
+where
+.i yourname
+is your login name. If you do not do this, anyone can probably read
+your mail, although people usually don't.
+.ip "\fBkeepsave\fP\ \ "
+When you
+.b save
+a message,
+.i Mail
+usually discards it when you
+.b quit .
+To retain all saved messages, set the
+.q keepsave
+option.
+.ip "\fBmetoo\fP\ \ "
+When sending mail to an alias,
+.i Mail
+makes sure that if you are included in the alias, that mail will not
+be sent to you. This is useful if a single alias is being used by
+all members of the group. If however, you wish to receive a copy of
+all the messages you send to the alias, you can set the binary option
+.q metoo.
+.ip "\fBnoheader\fP\ \ "
+The binary option
+.q noheader
+suppresses the printing of the version and headers when
+.i Mail
+is first invoked. Setting this option is the same as using
+.b \-N
+on the command line.
+.ip "\fBnosave\fP\ \ "
+Normally,
+when you abort a message with two \s-2RUBOUTs\s0,
+.i Mail
+copies the partial letter to the file
+.q dead.letter
+in your home directory. Setting the binary option
+.q nosave
+prevents this.
+.ip "\fBReplyall\fP\ \ "
+Reverses the sense of
+.i reply
+and
+.i Reply
+commands.
+.ip "\fBquiet\fP\ \ "
+The binary option
+.q quiet
+suppresses the printing of the version when
+.i Mail
+is first invoked,
+as well as printing the for example
+.q "Message 4:"
+from the
+.b type
+command.
+.ip "\fBrecord\fP\ \ "
+If you love to keep records, then the
+valued option
+.q record
+can be set to the name of a file to save your outgoing mail.
+Each new message you send is appended to the end of the file.
+.ip "\fBscreen\fP\ \ "
+When
+.i Mail
+initially prints the message headers, it determines the number to
+print by looking at the speed of your terminal. The faster your
+terminal, the more it prints.
+The valued option
+.q screen
+overrides this calculation and
+specifies how many message headers you want printed.
+This number is also used for scrolling with the
+.b z
+command.
+.ip "\fBsendmail\fP\ \ "
+To use an alternate mail delivery system, set the
+.q sendmail
+option to the full pathname of the program to use. Note: this is not
+for everyone! Most people should use the default delivery system.
+.ip "\fBtoplines\fP\ \ "
+The valued option
+.q toplines
+defines the number of lines that the
+.q top
+command will print out instead of the default five lines.
+.ip "\fBverbose\fP\ \ "
+The binary option "verbose" causes
+.i Mail
+to invoke sendmail with the
+.b \-v
+flag, which causes it to go into verbose mode and announce expansion
+of aliases, etc. Setting the "verbose" option is equivalent to
+invoking
+.i Mail
+with the
+.b \-v
+flag as described in section 6.
diff --git a/mail_cmds/mail/USD.doc/mail6.nr b/mail_cmds/mail/USD.doc/mail6.nr
new file mode 100644
index 0000000..0465a94
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail6.nr
@@ -0,0 +1,125 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail6.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "Command line options"
+.pp
+This section describes command line options for
+.i Mail
+and what they are used for.
+.ip \-N
+Suppress the initial printing of headers.
+.ip \-d
+Turn on debugging information. Not of general interest.
+.ip "\-f file\ \ "
+Show the messages in
+.i file
+instead of your system mailbox. If
+.i file
+is omitted,
+.i Mail
+reads
+.i mbox
+in your home directory.
+.ip \-i
+Ignore tty interrupt signals. Useful on noisy phone lines, which
+generate spurious RUBOUT or DELETE characters. It's usually
+more effective to change your interrupt character to control\-c,
+for which see the
+.i stty
+shell command.
+.ip \-n
+Inhibit reading of /etc/mail.rc. Not generally useful, since
+/etc/mail.rc is usually empty.
+.ip "\-s string"
+Used for sending mail.
+.i String
+is used as the subject of the message being composed. If
+.i string
+contains blanks, you must surround it with quote marks.
+.ip "\-u name"
+Read
+.i names's
+mail instead of your own. Unwitting others often neglect to protect
+their mailboxes, but discretion is advised. Essentially,
+.b "\-u user"
+is a shorthand way of doing
+.b "\-f /var/mail/user".
+.ip "\-v"
+Use the
+.b \-v
+flag when invoking sendmail. This feature may also be enabled
+by setting the the option "verbose".
+.pp
+The following command line flags are also recognized, but are
+intended for use by programs invoking
+.i Mail
+and not for people.
+.ip "\-T file"
+Arrange to print on
+.i file
+the contents of the
+.i article-id
+fields of all messages that were either read or deleted.
+.b \-T
+is for the
+.i readnews
+program and should NOT be used for reading your mail.
+.ip "\-h number"
+Pass on hop count information.
+.i Mail
+will take the number, increment it, and pass it with
+.b \-h
+to the mail delivery system.
+.b \-h
+only has effect when sending mail and is used for network mail
+forwarding.
+.ip "\-r name"
+Used for network mail forwarding: interpret
+.i name
+as the sender of the message. The
+.i name
+and
+.b \-r
+are simply sent along to the mail delivery system. Also,
+.i Mail
+will wait for the message to be sent and return the exit status.
+Also restricts formatting of message.
+.pp
+Note that
+.b \-h
+and
+.b \-r ,
+which are for network mail forwarding, are not used in practice
+since mail forwarding is now handled separately. They may
+disappear soon.
diff --git a/mail_cmds/mail/USD.doc/mail7.nr b/mail_cmds/mail/USD.doc/mail7.nr
new file mode 100644
index 0000000..0b2590b
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail7.nr
@@ -0,0 +1,107 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail7.nr 8.1 (Berkeley) 6/8/93
+.\"
+.sh 1 "Format of messages"
+.pp
+This section describes the format of messages.
+Messages begin with a
+.i from
+line, which consists of the word
+.q From
+followed by a user name, followed by anything, followed by
+a date in the format returned by the
+.i ctime
+library routine described in section 3 of the Unix Programmer's
+Manual. A possible
+.i ctime
+format date is:
+.(l
+Tue Dec 1 10:58:23 1981
+.)l
+The
+.i ctime
+date may be optionally followed by a single space and a
+time zone indication, which
+should be three capital letters, such as PDT.
+.pp
+Following the
+.i from
+line are zero or more
+.i "header field"
+lines.
+Each header field line is of the form:
+.(l
+name: information
+.)l
+.i Name
+can be anything, but only certain header fields are recognized as
+having any meaning. The recognized header fields are:
+.i article-id ,
+.i bcc ,
+.i cc ,
+.i from ,
+.i reply-to ,
+.i sender ,
+.i subject ,
+and
+.i to .
+Other header fields are also significant to other systems; see,
+for example, the current Arpanet message standard for much more
+information on this topic.
+A header field can be continued onto following lines by making the
+first character on the following line a space or tab character.
+.pp
+If any headers are present, they must be followed by a blank line.
+The part that follows is called the
+.i body
+of the message, and must be ASCII text, not containing null characters.
+Each line in the message body must be no longer than 512 characters and
+terminated with an ASCII newline character.
+If binary data must be passed through the mail system, it is suggested
+that this data be encoded in a system which encodes six bits into
+a printable character (i.e.: uuencode).
+For example, one could use the upper and lower case letters, the digits,
+and the characters comma and period to make up the 64 characters.
+Then, one can send a 16-bit binary number
+as three characters. These characters should be packed into lines,
+preferably lines about 70 characters long as long lines are transmitted
+more efficiently.
+.pp
+The message delivery system always adds a blank line to the end of
+each message. This blank line must not be deleted.
+.pp
+The UUCP message delivery system sometimes adds a blank line to
+the end of a message each time it is forwarded through a machine.
+.pp
+It should be noted that some network transport protocols enforce
+limits to the lengths of messages.
diff --git a/mail_cmds/mail/USD.doc/mail8.nr b/mail_cmds/mail/USD.doc/mail8.nr
new file mode 100644
index 0000000..b09afbd
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail8.nr
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail8.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "Glossary"
+.pp
+This section contains the definitions of a few phrases
+peculiar to
+.i Mail .
+.ip "\fIalias\fP"
+An alternative name for a person or list of people.
+.ip "\fIflag\fP"
+An option, given on the command line of
+.i Mail ,
+prefaced with a \-. For example,
+.b \-f
+is a flag.
+.ip "\fIheader field\fP"
+At the beginning of a message, a line which contains information
+that is part of the structure of the message. Popular header fields
+include
+.i to ,
+.i cc ,
+and
+.i subject .
+.ip "\fImail\ \ \fP"
+A collection of messages. Often used in the phrase,
+.q "Have you read your mail?"
+.ip "\fImailbox\fP"
+The place where your mail is stored, typically in the directory
+/var/mail.
+.ip "\fImessage\fP"
+A single letter from someone, initially stored in your
+.i mailbox .
+.ip "\fImessage list\fP"
+A string used in
+.i Mail
+command mode to describe a sequence of messages.
+.ip "\fIoption\fP"
+A piece of special purpose information used to tailor
+.i Mail
+to your taste.
+Options are specified with the
+.b set
+command.
diff --git a/mail_cmds/mail/USD.doc/mail9.nr b/mail_cmds/mail/USD.doc/mail9.nr
new file mode 100644
index 0000000..271548e
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail9.nr
@@ -0,0 +1,203 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail9.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "Summary of commands, options, and escapes"
+.pp
+This section gives a quick summary of the
+.i Mail
+commands, binary and valued options, and tilde escapes.
+.pp
+The following table describes the commands:
+.TS
+center ;
+c ci
+lb l.
+Command Description
+_
++ Same as \fBnext\fP
+- Back up to previous message
+? Print brief summary of \fIMail\fP commands
+! Single command escape to shell
+Print Type message with ignored fields
+Reply Reply to author of message only
+Respond Same as \fBReply\fP
+Type Type message with ignored fields
+alias Define an alias as a set of user names
+alternates List other names you are known by
+chdir Change working directory, home by default
+copy Copy a message to a file or folder
+delete Delete a list of messages
+dp Same as \fBdt\fP
+dt Delete current message, type next message
+edit Edit a list of messages
+else Start of else part of conditional; see \fBif\fP
+endif End of conditional statement; see \fBif\fP
+exit Leave mail without changing anything
+file Interrogate/change current mail file
+folder Same as \fBfile\fP
+folders List the folders in your folder directory
+from List headers of a list of messages
+headers List current window of messages
+help Same as \fB?\fP
+hold Same as \fBpreserve\fP
+if Conditional execution of \fIMail\fP commands
+ignore Set/examine list of ignored header fields
+list List valid \fIMail\fP commands
+local List other names for the local host
+mail Send mail to specified names
+mbox Arrange to save a list of messages in \fImbox\fP
+next Go to next message and type it
+preserve Arrange to leave list of messages in system mailbox
+print Print messages
+quit Leave \fIMail\fP; update system mailbox, \fImbox\fP as appropriate
+reply Compose a reply to a message
+respond Same as \fBreply\fP
+retain Supersedes \fBignore\fP
+save Append messages, headers included, on a file
+set Set binary or valued options
+shell Invoke an interactive shell
+size Prints out size of message list
+source Read \fImail\fP commands from a file
+top Print first so many (5 by default) lines of list of messages
+type Same as \fBprint\fP
+undelete Undelete list of messages
+unread Marks list of messages as not been read
+unset Undo the operation of a \fBset\fP
+visual Invoke visual editor on a list of messages
+write Append messages to a file, don't include headers
+xit Same as \fBexit\fP
+z Scroll to next/previous screenful of headers
+.TE
+.bp
+.(b
+.pp
+The following table describes the options. Each option is
+shown as being either a binary or valued option.
+.TS
+center;
+c ci ci
+l ci l.
+Option Type Description
+_
+EDITOR valued Pathname of editor for ~e and \fBedit\fP
+PAGER valued Pathname of paginator for \fBPrint\fP, \fBprint\fP, \fBType\fP and \fBtype\fP
+SHELL valued Pathname of shell for \fBshell\fP, ~! and \fB!\fP
+VISUAL valued Pathname of screen editor for ~v, \fBvisual\fP
+append binary Always append messages to end of \fImbox\fP
+ask binary Prompt user for Subject: field when sending
+askcc binary Prompt user for additional Cc's at end of message
+autoprint binary Print next message after \fBdelete\fP
+crt valued Minimum number of lines before using \fBPAGER\fP
+debug binary Print out debugging information
+dot binary Accept . alone on line to terminate message input
+escape valued Escape character to be used instead of\ \ ~
+folder valued Directory to store folders in
+hold binary Hold messages in system mailbox by default
+ignore binary Ignore \s-2RUBOUT\s0 while sending mail
+ignoreeof binary Don't terminate letters/command input with \fB\(uaD\fP
+keep binary Don't unlink system mailbox when empty
+keepsave binary Don't delete \fBsave\fPd messages by default
+metoo binary Include sending user in aliases
+noheader binary Suppress initial printing of version and headers
+nosave binary Don't save partial letter in \fIdead.letter\fP
+quiet binary Suppress printing of \fIMail\fP version and message numbers
+record valued File to save all outgoing mail in
+screen valued Size of window of message headers for \fBz\fP, etc.
+sendmail valued Choose alternate mail delivery system
+toplines valued Number of lines to print in \fBtop\fP
+verbose binary Invoke sendmail with the \fB\-v\fP flag
+.TE
+.)b
+.(b
+.pp
+The following table summarizes the tilde escapes available
+while sending mail.
+.TS
+center;
+c ci ci
+l li l.
+Escape Arguments Description
+_
+~! command Execute shell command
+~b name ... Add names to "blind" Cc: list
+~c name ... Add names to Cc: field
+~d Read \fIdead.letter\fP into message
+~e Invoke text editor on partial message
+~f messages Read named messages
+~h Edit the header fields
+~m messages Read named messages, right shift by tab
+~p Print message entered so far
+~q Abort entry of letter; like \s-2RUBOUT\s0
+~r filename Read file into message
+~s string Set Subject: field to \fIstring\fP
+~t name ... Add names to To: field
+~v Invoke screen editor on message
+~w filename Write message on file
+~| command Pipe message through \fIcommand\fP
+~: Mail command Execute a \fIMail\fP command
+~~ string Quote a ~ in front of \fIstring\fP
+.TE
+.)b
+.(b
+.pp
+The following table shows the command line flags that
+.i Mail
+accepts:
+.TS
+center;
+c c
+l a.
+Flag Description
+_
+\-N Suppress the initial printing of headers
+\-T \fIfile\fP Article-id's of read/deleted messages to \fIfile\fP
+\-d Turn on debugging
+\-f \fIfile\fP Show messages in \fIfile\fP or \fI~/mbox\fP
+\-h \fInumber\fP Pass on hop count for mail forwarding
+\-i Ignore tty interrupt signals
+\-n Inhibit reading of /etc/mail.rc
+\-r \fIname\fP Pass on \fIname\fP for mail forwarding
+\-s \fIstring\fP Use \fIstring\fP as subject in outgoing mail
+\-u \fIname\fP Read \fIname's\fP mail instead of your own
+\-v Invoke sendmail with the \fB\-v\fP flag
+.TE
+.)b
+.lp
+Notes:
+.b \-T ,
+.b \-d ,
+.b \-h ,
+and
+.b \-r
+are not for human use.
diff --git a/mail_cmds/mail/USD.doc/maila.nr b/mail_cmds/mail/USD.doc/maila.nr
new file mode 100644
index 0000000..84b01fe
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/maila.nr
@@ -0,0 +1,33 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)maila.nr 8.1 (Berkeley) 6/8/93
+.\"
diff --git a/mail_cmds/mail/aux.c b/mail_cmds/mail/aux.c
new file mode 100644
index 0000000..f1a621f
--- /dev/null
+++ b/mail_cmds/mail/aux.c
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/aux.c,v 1.13 2002/08/25 13:22:47 charnier Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <sys/time.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Auxiliary functions.
+ */
+
+static char *save2str(char *, char *);
+
+/*
+ * Return a pointer to a dynamic copy of the argument.
+ */
+char *
+savestr(str)
+ char *str;
+{
+ char *new;
+ int size = strlen(str) + 1;
+
+ if ((new = salloc(size)) != NULL)
+ bcopy(str, new, size);
+ return (new);
+}
+
+/*
+ * Make a copy of new argument incorporating old one.
+ */
+char *
+save2str(str, old)
+ char *str, *old;
+{
+ char *new;
+ int newsize = strlen(str) + 1;
+ int oldsize = old ? strlen(old) + 1 : 0;
+
+ if ((new = salloc(newsize + oldsize)) != NULL) {
+ if (oldsize) {
+ bcopy(old, new, oldsize);
+ new[oldsize - 1] = ' ';
+ }
+ bcopy(str, new + oldsize, newsize);
+ }
+ return (new);
+}
+
+/*
+ * Touch the named message by setting its MTOUCH flag.
+ * Touched messages have the effect of not being sent
+ * back to the system mailbox on exit.
+ */
+void
+touch(mp)
+ struct message *mp;
+{
+
+ mp->m_flag |= MTOUCH;
+ if ((mp->m_flag & MREAD) == 0)
+ mp->m_flag |= MREAD|MSTATUS;
+}
+
+/*
+ * Test to see if the passed file name is a directory.
+ * Return true if it is.
+ */
+int
+isdir(name)
+ char name[];
+{
+ struct stat sbuf;
+
+ if (stat(name, &sbuf) < 0)
+ return (0);
+ return (S_ISDIR(sbuf.st_mode));
+}
+
+/*
+ * Count the number of arguments in the given string raw list.
+ */
+int
+argcount(argv)
+ char **argv;
+{
+ char **ap;
+
+ for (ap = argv; *ap++ != NULL;)
+ ;
+ return (ap - argv - 1);
+}
+
+/*
+ * Return the desired header line from the passed message
+ * pointer (or NULL if the desired header field is not available).
+ */
+char *
+hfield(field, mp)
+ const char *field;
+ struct message *mp;
+{
+ FILE *ibuf;
+ char linebuf[LINESIZE];
+ int lc;
+ char *hfield;
+ char *colon, *oldhfield = NULL;
+
+ ibuf = setinput(mp);
+ if ((lc = mp->m_lines - 1) < 0)
+ return (NULL);
+ if (readline(ibuf, linebuf, LINESIZE) < 0)
+ return (NULL);
+ while (lc > 0) {
+ if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
+ return (oldhfield);
+ if ((hfield = ishfield(linebuf, colon, field)) != NULL)
+ oldhfield = save2str(hfield, oldhfield);
+ }
+ return (oldhfield);
+}
+
+/*
+ * Return the next header field found in the given message.
+ * Return >= 0 if something found, < 0 elsewise.
+ * "colon" is set to point to the colon in the header.
+ * Must deal with \ continuations & other such fraud.
+ */
+int
+gethfield(f, linebuf, rem, colon)
+ FILE *f;
+ char linebuf[];
+ int rem;
+ char **colon;
+{
+ char line2[LINESIZE];
+ char *cp, *cp2;
+ int c;
+
+ for (;;) {
+ if (--rem < 0)
+ return (-1);
+ if ((c = readline(f, linebuf, LINESIZE)) <= 0)
+ return (-1);
+ for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
+ cp++)
+ ;
+ if (*cp != ':' || cp == linebuf)
+ continue;
+ /*
+ * I guess we got a headline.
+ * Handle wraparounding
+ */
+ *colon = cp;
+ cp = linebuf + c;
+ for (;;) {
+ while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
+ ;
+ cp++;
+ if (rem <= 0)
+ break;
+ ungetc(c = getc(f), f);
+ if (c != ' ' && c != '\t')
+ break;
+ if ((c = readline(f, line2, LINESIZE)) < 0)
+ break;
+ rem--;
+ for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
+ ;
+ c -= cp2 - line2;
+ if (cp + c >= linebuf + LINESIZE - 2)
+ break;
+ *cp++ = ' ';
+ bcopy(cp2, cp, c);
+ cp += c;
+ }
+ *cp = 0;
+ return (rem);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Check whether the passed line is a header line of
+ * the desired breed. Return the field body, or 0.
+ */
+
+char*
+ishfield(linebuf, colon, field)
+ char linebuf[];
+ char *colon;
+ const char *field;
+{
+ char *cp = colon;
+
+ *cp = 0;
+ if (strcasecmp(linebuf, field) != 0) {
+ *cp = ':';
+ return (0);
+ }
+ *cp = ':';
+ for (cp++; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ return (cp);
+}
+
+/*
+ * Copy a string and lowercase the result.
+ * dsize: space left in buffer (including space for NULL)
+ */
+void
+istrncpy(dest, src, dsize)
+ char *dest;
+ const char *src;
+ size_t dsize;
+{
+
+ strlcpy(dest, src, dsize);
+ while (*dest) {
+ *dest = tolower((unsigned char)*dest);
+ dest++;
+ }
+}
+
+/*
+ * The following code deals with input stacking to do source
+ * commands. All but the current file pointer are saved on
+ * the stack.
+ */
+
+static int ssp; /* Top of file stack */
+struct sstack {
+ FILE *s_file; /* File we were in. */
+ int s_cond; /* Saved state of conditionals */
+ int s_loading; /* Loading .mailrc, etc. */
+};
+#define SSTACK_SIZE 64 /* XXX was NOFILE. */
+static struct sstack sstack[SSTACK_SIZE];
+
+/*
+ * Pushdown current input file and switch to a new one.
+ * Set the global flag "sourcing" so that others will realize
+ * that they are no longer reading from a tty (in all probability).
+ */
+int
+source(arglist)
+ char **arglist;
+{
+ FILE *fi;
+ char *cp;
+
+ if ((cp = expand(*arglist)) == NULL)
+ return (1);
+ if ((fi = Fopen(cp, "r")) == NULL) {
+ warn("%s", cp);
+ return (1);
+ }
+ if (ssp >= SSTACK_SIZE - 1) {
+ printf("Too much \"sourcing\" going on.\n");
+ (void)Fclose(fi);
+ return (1);
+ }
+ sstack[ssp].s_file = input;
+ sstack[ssp].s_cond = cond;
+ sstack[ssp].s_loading = loading;
+ ssp++;
+ loading = 0;
+ cond = CANY;
+ input = fi;
+ sourcing++;
+ return (0);
+}
+
+/*
+ * Pop the current input back to the previous level.
+ * Update the "sourcing" flag as appropriate.
+ */
+int
+unstack()
+{
+ if (ssp <= 0) {
+ printf("\"Source\" stack over-pop.\n");
+ sourcing = 0;
+ return (1);
+ }
+ (void)Fclose(input);
+ if (cond != CANY)
+ printf("Unmatched \"if\"\n");
+ ssp--;
+ cond = sstack[ssp].s_cond;
+ loading = sstack[ssp].s_loading;
+ input = sstack[ssp].s_file;
+ if (ssp == 0)
+ sourcing = loading;
+ return (0);
+}
+
+/*
+ * Touch the indicated file.
+ * This is nifty for the shell.
+ */
+void
+alter(name)
+ char *name;
+{
+ struct stat sb;
+ struct timeval tv[2];
+
+ if (stat(name, &sb))
+ return;
+ (void)gettimeofday(&tv[0], (struct timezone *)NULL);
+ tv[0].tv_sec++;
+ TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
+ (void)utimes(name, tv);
+}
+
+/*
+ * Get sender's name from this message. If the message has
+ * a bunch of arpanet stuff in it, we may have to skin the name
+ * before returning it.
+ */
+char *
+nameof(mp, reptype)
+ struct message *mp;
+ int reptype;
+{
+ char *cp, *cp2;
+
+ cp = skin(name1(mp, reptype));
+ if (reptype != 0 || charcount(cp, '!') < 2)
+ return (cp);
+ cp2 = strrchr(cp, '!');
+ cp2--;
+ while (cp2 > cp && *cp2 != '!')
+ cp2--;
+ if (*cp2 == '!')
+ return (cp2 + 1);
+ return (cp);
+}
+
+/*
+ * Start of a "comment".
+ * Ignore it.
+ */
+char *
+skip_comment(cp)
+ char *cp;
+{
+ int nesting = 1;
+
+ for (; nesting > 0 && *cp; cp++) {
+ switch (*cp) {
+ case '\\':
+ if (cp[1])
+ cp++;
+ break;
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ nesting--;
+ break;
+ }
+ }
+ return (cp);
+}
+
+/*
+ * Skin an arpa net address according to the RFC 822 interpretation
+ * of "host-phrase."
+ */
+char *
+skin(name)
+ char *name;
+{
+ char *nbuf, *bufend, *cp, *cp2;
+ int c, gotlt, lastsp;
+
+ if (name == NULL)
+ return (NULL);
+ if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
+ && strchr(name, ' ') == NULL)
+ return (name);
+
+ /* We assume that length(input) <= length(output) */
+ if ((nbuf = malloc(strlen(name) + 1)) == NULL)
+ err(1, "Out of memory");
+ gotlt = 0;
+ lastsp = 0;
+ bufend = nbuf;
+ for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
+ switch (c) {
+ case '(':
+ cp = skip_comment(cp);
+ lastsp = 0;
+ break;
+
+ case '"':
+ /*
+ * Start of a "quoted-string".
+ * Copy it in its entirety.
+ */
+ while ((c = *cp) != '\0') {
+ cp++;
+ if (c == '"')
+ break;
+ if (c != '\\')
+ *cp2++ = c;
+ else if ((c = *cp) != '\0') {
+ *cp2++ = c;
+ cp++;
+ }
+ }
+ lastsp = 0;
+ break;
+
+ case ' ':
+ if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
+ cp += 3, *cp2++ = '@';
+ else
+ if (cp[0] == '@' && cp[1] == ' ')
+ cp += 2, *cp2++ = '@';
+ else
+ lastsp = 1;
+ break;
+
+ case '<':
+ cp2 = bufend;
+ gotlt++;
+ lastsp = 0;
+ break;
+
+ case '>':
+ if (gotlt) {
+ gotlt = 0;
+ while ((c = *cp) != '\0' && c != ',') {
+ cp++;
+ if (c == '(')
+ cp = skip_comment(cp);
+ else if (c == '"')
+ while ((c = *cp) != '\0') {
+ cp++;
+ if (c == '"')
+ break;
+ if (c == '\\' && *cp != '\0')
+ cp++;
+ }
+ }
+ lastsp = 0;
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ if (lastsp) {
+ lastsp = 0;
+ *cp2++ = ' ';
+ }
+ *cp2++ = c;
+ if (c == ',' && *cp == ' ' && !gotlt) {
+ *cp2++ = ' ';
+ while (*++cp == ' ')
+ ;
+ lastsp = 0;
+ bufend = cp2;
+ }
+ }
+ }
+ *cp2 = '\0';
+
+ if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL)
+ nbuf = cp;
+ return (nbuf);
+}
+
+/*
+ * Fetch the sender's name from the passed message.
+ * Reptype can be
+ * 0 -- get sender's name for display purposes
+ * 1 -- get sender's name for reply
+ * 2 -- get sender's name for Reply
+ */
+char *
+name1(mp, reptype)
+ struct message *mp;
+ int reptype;
+{
+ char namebuf[LINESIZE];
+ char linebuf[LINESIZE];
+ char *cp, *cp2;
+ FILE *ibuf;
+ int first = 1;
+
+ if ((cp = hfield("from", mp)) != NULL)
+ return (cp);
+ if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
+ return (cp);
+ ibuf = setinput(mp);
+ namebuf[0] = '\0';
+ if (readline(ibuf, linebuf, LINESIZE) < 0)
+ return (savestr(namebuf));
+newname:
+ for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++)
+ ;
+ for (; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ for (cp2 = &namebuf[strlen(namebuf)];
+ *cp != '\0' && *cp != ' ' && *cp != '\t' &&
+ cp2 < namebuf + LINESIZE - 1;)
+ *cp2++ = *cp++;
+ *cp2 = '\0';
+ if (readline(ibuf, linebuf, LINESIZE) < 0)
+ return (savestr(namebuf));
+ if ((cp = strchr(linebuf, 'F')) == NULL)
+ return (savestr(namebuf));
+ if (strncmp(cp, "From", 4) != 0)
+ return (savestr(namebuf));
+ while ((cp = strchr(cp, 'r')) != NULL) {
+ if (strncmp(cp, "remote", 6) == 0) {
+ if ((cp = strchr(cp, 'f')) == NULL)
+ break;
+ if (strncmp(cp, "from", 4) != 0)
+ break;
+ if ((cp = strchr(cp, ' ')) == NULL)
+ break;
+ cp++;
+ if (first) {
+ cp2 = namebuf;
+ first = 0;
+ } else
+ cp2 = strrchr(namebuf, '!') + 1;
+ strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1);
+ strcat(namebuf, "!");
+ goto newname;
+ }
+ cp++;
+ }
+ return (savestr(namebuf));
+}
+
+/*
+ * Count the occurances of c in str
+ */
+int
+charcount(str, c)
+ char *str;
+ int c;
+{
+ char *cp;
+ int i;
+
+ for (i = 0, cp = str; *cp != '\0'; cp++)
+ if (*cp == c)
+ i++;
+ return (i);
+}
+
+/*
+ * See if the given header field is supposed to be ignored.
+ */
+int
+isign(field, ignore)
+ const char *field;
+ struct ignoretab ignore[2];
+{
+ char realfld[LINESIZE];
+
+ if (ignore == ignoreall)
+ return (1);
+ /*
+ * Lower-case the string, so that "Status" and "status"
+ * will hash to the same place.
+ */
+ istrncpy(realfld, field, sizeof(realfld));
+ if (ignore[1].i_count > 0)
+ return (!member(realfld, ignore + 1));
+ else
+ return (member(realfld, ignore));
+}
+
+int
+member(realfield, table)
+ char *realfield;
+ struct ignoretab *table;
+{
+ struct ignore *igp;
+
+ for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link)
+ if (*igp->i_field == *realfield &&
+ equal(igp->i_field, realfield))
+ return (1);
+ return (0);
+}
diff --git a/mail_cmds/mail/cmd1.c b/mail_cmds/mail/cmd1.c
new file mode 100644
index 0000000..a1f9d61
--- /dev/null
+++ b/mail_cmds/mail/cmd1.c
@@ -0,0 +1,487 @@
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/cmd1.c,v 1.7 2002/06/30 05:25:05 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * User commands.
+ */
+
+extern const struct cmd cmdtab[];
+
+/*
+ * Print the current active headings.
+ * Don't change dot if invoker didn't give an argument.
+ */
+
+static int screen;
+
+int
+headers(msgvec)
+ int *msgvec;
+{
+ int n, mesg, flag, size;
+ struct message *mp;
+
+ size = screensize();
+ n = msgvec[0];
+ if (n != 0)
+ screen = (n-1)/size;
+ if (screen < 0)
+ screen = 0;
+ mp = &message[screen * size];
+ if (mp >= &message[msgCount])
+ mp = &message[msgCount - size];
+ if (mp < &message[0])
+ mp = &message[0];
+ flag = 0;
+ mesg = mp - &message[0];
+ if (dot != &message[n-1])
+ dot = mp;
+ for (; mp < &message[msgCount]; mp++) {
+ mesg++;
+ if (mp->m_flag & MDELETED)
+ continue;
+ if (flag++ >= size)
+ break;
+ printhead(mesg);
+ }
+ if (flag == 0) {
+ printf("No more mail.\n");
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Scroll to the next/previous screen
+ */
+int
+scroll(arg)
+ char arg[];
+{
+ int s, size;
+ int cur[1];
+
+ cur[0] = 0;
+ size = screensize();
+ s = screen;
+ switch (*arg) {
+ case 0:
+ case '+':
+ s++;
+ if (s * size >= msgCount) {
+ printf("On last screenful of messages\n");
+ return (0);
+ }
+ screen = s;
+ break;
+
+ case '-':
+ if (--s < 0) {
+ printf("On first screenful of messages\n");
+ return (0);
+ }
+ screen = s;
+ break;
+
+ default:
+ printf("Unrecognized scrolling command \"%s\"\n", arg);
+ return (1);
+ }
+ return (headers(cur));
+}
+
+/*
+ * Compute screen size.
+ */
+int
+screensize()
+{
+ int s;
+ char *cp;
+
+ if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0)
+ return (s);
+ return (screenheight - 4);
+}
+
+/*
+ * Print out the headlines for each message
+ * in the passed message list.
+ */
+int
+from(msgvec)
+ int *msgvec;
+{
+ int *ip;
+
+ for (ip = msgvec; *ip != 0; ip++)
+ printhead(*ip);
+ if (--ip >= msgvec)
+ dot = &message[*ip - 1];
+ return (0);
+}
+
+/*
+ * Print out the header of a specific message.
+ * This is a slight improvement to the standard one.
+ */
+void
+printhead(mesg)
+ int mesg;
+{
+ struct message *mp;
+ char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
+ char pbuf[BUFSIZ];
+ struct headline hl;
+ int subjlen;
+ char *name;
+
+ mp = &message[mesg-1];
+ (void)readline(setinput(mp), headline, LINESIZE);
+ if ((subjline = hfield("subject", mp)) == NULL)
+ subjline = hfield("subj", mp);
+ /*
+ * Bletch!
+ */
+ curind = dot == mp ? '>' : ' ';
+ dispc = ' ';
+ if (mp->m_flag & MSAVED)
+ dispc = '*';
+ if (mp->m_flag & MPRESERVE)
+ dispc = 'P';
+ if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
+ dispc = 'N';
+ if ((mp->m_flag & (MREAD|MNEW)) == 0)
+ dispc = 'U';
+ if (mp->m_flag & MBOX)
+ dispc = 'M';
+ parse(headline, &hl, pbuf);
+ sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size);
+ subjlen = screenwidth - 50 - strlen(wcount);
+ name = value("show-rcpt") != NULL ?
+ skin(hfield("to", mp)) : nameof(mp, 0);
+ if (subjline == NULL || subjlen < 0) /* pretty pathetic */
+ printf("%c%c%3d %-20.20s %16.16s %s\n",
+ curind, dispc, mesg, name, hl.l_date, wcount);
+ else
+ printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
+ curind, dispc, mesg, name, hl.l_date, wcount,
+ subjlen, subjline);
+}
+
+/*
+ * Print out the value of dot.
+ */
+int
+pdot()
+{
+ printf("%ld\n", (uintptr_t)dot - (uintptr_t)&message[0] + 1);
+ return (0);
+}
+
+/*
+ * Print out all the possible commands.
+ */
+int
+pcmdlist()
+{
+ const struct cmd *cp;
+ int cc;
+
+ printf("Commands are:\n");
+ for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
+ cc += strlen(cp->c_name) + 2;
+ if (cc > 72) {
+ printf("\n");
+ cc = strlen(cp->c_name) + 2;
+ }
+ if ((cp+1)->c_name != NULL)
+ printf("%s, ", cp->c_name);
+ else
+ printf("%s\n", cp->c_name);
+ }
+ return (0);
+}
+
+/*
+ * Paginate messages, honor ignored fields.
+ */
+int
+more(msgvec)
+ int *msgvec;
+{
+
+ return (type1(msgvec, 1, 1));
+}
+
+/*
+ * Paginate messages, even printing ignored fields.
+ */
+int
+More(msgvec)
+ int *msgvec;
+{
+
+ return (type1(msgvec, 0, 1));
+}
+
+/*
+ * Type out messages, honor ignored fields.
+ */
+int
+type(msgvec)
+ int *msgvec;
+{
+
+ return (type1(msgvec, 1, 0));
+}
+
+/*
+ * Type out messages, even printing ignored fields.
+ */
+int
+Type(msgvec)
+ int *msgvec;
+{
+
+ return (type1(msgvec, 0, 0));
+}
+
+/*
+ * Type out the messages requested.
+ */
+jmp_buf pipestop;
+int
+type1(msgvec, doign, page)
+ int *msgvec;
+ int doign, page;
+{
+ int nlines, *ip;
+ struct message *mp;
+ char *cp;
+ FILE *obuf;
+
+ obuf = stdout;
+ if (setjmp(pipestop))
+ goto close_pipe;
+ if (value("interactive") != NULL &&
+ (page || (cp = value("crt")) != NULL)) {
+ nlines = 0;
+ if (!page) {
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
+ nlines += message[*ip - 1].m_lines;
+ }
+ if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
+ cp = value("PAGER");
+ if (cp == NULL || *cp == '\0')
+ cp = _PATH_MORE;
+ obuf = Popen(cp, "w");
+ if (obuf == NULL) {
+ warnx("%s", cp);
+ obuf = stdout;
+ } else
+ (void)signal(SIGPIPE, brokpipe);
+ }
+ }
+
+ /*
+ * Send messages to the output.
+ *
+ */
+ for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ dot = mp;
+ if (value("quiet") == NULL)
+ fprintf(obuf, "Message %d:\n", *ip);
+ (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL);
+ }
+
+close_pipe:
+ if (obuf != stdout) {
+ /*
+ * Ignore SIGPIPE so it can't cause a duplicate close.
+ */
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)Pclose(obuf);
+ (void)signal(SIGPIPE, SIG_DFL);
+ }
+ return (0);
+}
+
+/*
+ * Respond to a broken pipe signal --
+ * probably caused by quitting more.
+ */
+/*ARGSUSED*/
+void
+brokpipe(signo)
+ int signo;
+{
+ longjmp(pipestop, 1);
+}
+
+/*
+ * Print the top so many lines of each desired message.
+ * The number of lines is taken from the variable "toplines"
+ * and defaults to 5.
+ */
+int
+top(msgvec)
+ int *msgvec;
+{
+ int *ip;
+ struct message *mp;
+ int c, topl, lines, lineb;
+ char *valtop, linebuf[LINESIZE];
+ FILE *ibuf;
+
+ topl = 5;
+ valtop = value("toplines");
+ if (valtop != NULL) {
+ topl = atoi(valtop);
+ if (topl < 0 || topl > 10000)
+ topl = 5;
+ }
+ lineb = 1;
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ dot = mp;
+ if (value("quiet") == NULL)
+ printf("Message %d:\n", *ip);
+ ibuf = setinput(mp);
+ c = mp->m_lines;
+ if (!lineb)
+ printf("\n");
+ for (lines = 0; lines < c && lines <= topl; lines++) {
+ if (readline(ibuf, linebuf, sizeof(linebuf)) < 0)
+ break;
+ puts(linebuf);
+ lineb = strspn(linebuf, " \t") == strlen(linebuf);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Touch all the given messages so that they will
+ * get mboxed.
+ */
+int
+stouch(msgvec)
+ int msgvec[];
+{
+ int *ip;
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ dot = &message[*ip-1];
+ dot->m_flag |= MTOUCH;
+ dot->m_flag &= ~MPRESERVE;
+ }
+ return (0);
+}
+
+/*
+ * Make sure all passed messages get mboxed.
+ */
+int
+mboxit(msgvec)
+ int msgvec[];
+{
+ int *ip;
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ dot = &message[*ip-1];
+ dot->m_flag |= MTOUCH|MBOX;
+ dot->m_flag &= ~MPRESERVE;
+ }
+ return (0);
+}
+
+/*
+ * List the folders the user currently has.
+ */
+int
+folders()
+{
+ char dirname[PATHSIZE];
+ char *cmd;
+
+ if (getfold(dirname, sizeof(dirname)) < 0) {
+ printf("No value set for \"folder\"\n");
+ return (1);
+ }
+ if ((cmd = value("LISTER")) == NULL)
+ cmd = "ls";
+ (void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL);
+ return (0);
+}
+
+/*
+ * Update the mail file with any new messages that have
+ * come in since we started reading mail.
+ */
+int
+inc(v)
+ void *v;
+{
+ int nmsg, mdot;
+
+ nmsg = incfile();
+
+ if (nmsg == 0)
+ printf("No new mail.\n");
+ else if (nmsg > 0) {
+ mdot = newfileinfo(msgCount - nmsg);
+ dot = &message[mdot - 1];
+ } else
+ printf("\"inc\" command failed...\n");
+
+ return (0);
+}
diff --git a/mail_cmds/mail/cmd2.c b/mail_cmds/mail/cmd2.c
new file mode 100644
index 0000000..7153b13
--- /dev/null
+++ b/mail_cmds/mail/cmd2.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/cmd2.c,v 1.9 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <sys/wait.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * More user commands.
+ */
+
+extern int wait_status;
+
+/*
+ * If any arguments were given, go to the next applicable argument
+ * following dot, otherwise, go to the next applicable message.
+ * If given as first command with no arguments, print first message.
+ */
+int
+next(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ int *ip, *ip2, list[2], mdot;
+
+ if (*msgvec != 0) {
+
+ /*
+ * If some messages were supplied, find the
+ * first applicable one following dot using
+ * wrap around.
+ */
+
+ mdot = dot - &message[0] + 1;
+
+ /*
+ * Find the first message in the supplied
+ * message list which follows dot.
+ */
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ if (!sawcom) /* don't skip current message if first command */
+ break;
+ if (*ip > mdot)
+ break;
+ }
+ if (*ip == 0)
+ ip = msgvec;
+ ip2 = ip;
+ do {
+ mp = &message[*ip2 - 1];
+ if ((mp->m_flag & MDELETED) == 0) {
+ dot = mp;
+ goto hitit;
+ }
+ if (*ip2 != 0)
+ ip2++;
+ if (*ip2 == 0)
+ ip2 = msgvec;
+ } while (ip2 != ip);
+ printf("No messages applicable\n");
+ return (1);
+ }
+
+ /*
+ * If this is the first command, select message 1.
+ * Note that this must exist for us to get here at all.
+ */
+
+ if (!sawcom)
+ goto hitit;
+
+ /*
+ * Just find the next good message after dot, no
+ * wraparound.
+ */
+
+ for (mp = dot+1; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
+ break;
+ if (mp >= &message[msgCount]) {
+ printf("At EOF\n");
+ return (0);
+ }
+ dot = mp;
+hitit:
+ /*
+ * Print dot.
+ */
+
+ list[0] = dot - &message[0] + 1;
+ list[1] = 0;
+ return (type(list));
+}
+
+/*
+ * Save a message in a file. Mark the message as saved
+ * so we can discard when the user quits.
+ */
+int
+save(str)
+ char str[];
+{
+
+ return (save1(str, 1, "save", saveignore));
+}
+
+/*
+ * Save a message list in a file named after author. Mark the message as saved
+ * so we can discard when the user quits.
+ */
+int
+Capsave(str)
+ char str[];
+{
+
+ return (save1(str, 1, "Save", saveignore));
+}
+
+/*
+ * Copy a message to a file without affected its saved-ness
+ */
+int
+copycmd(str)
+ char str[];
+{
+
+ return (save1(str, 0, "copy", saveignore));
+}
+
+/*
+ * Copy a message to a file named after author without affected its saved-ness
+ */
+int
+Capcopycmd(str)
+ char str[];
+{
+
+#if 1
+ printf("Copy command is not yet implemented\n");
+ return (1);
+#else
+ return (save1(str, 0, "Copy", saveignore));
+#endif
+}
+
+/*
+ * Save/copy the indicated messages at the end of the passed file name.
+ * If mark is true, mark the message "saved."
+ */
+int
+save1(str, mark, cmd, ignore)
+ char str[];
+ int mark;
+ const char *cmd;
+ struct ignoretab *ignore;
+{
+ struct message *mp;
+ char *file;
+ const char *disp;
+ int f, *msgvec, *ip;
+ FILE *obuf;
+ int doing_Save = !strcmp(cmd,"Save");
+
+ msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
+ if ((file = snarf(str, &f, doing_Save)) == NULL)
+ return (1);
+ if (!f) {
+ *msgvec = first(0, MMNORM);
+ if (*msgvec == 0) {
+ printf("No messages to %s.\n", cmd);
+ return (1);
+ }
+ msgvec[1] = 0;
+ }
+ if (f && getmsglist(str, msgvec, 0) < 0)
+ return (1);
+ /* Save derives file name from author of first message: */
+ if (doing_Save) {
+ char *rcv;
+ mp = &message[msgvec[0] - 1];
+ touch(mp);
+ if ((rcv = skin(hfield("from", mp))) == NULL)
+ rcv = skin(nameof(mp, 1));
+ rcv = getauthor(rcv);
+ if (rcv == NULL) {
+ printf("Failed to find sender: Save not performed\n");
+ return(1);
+ }
+ file = rcv; /* use it as file name */
+ }
+ if ((file = expand(file)) == NULL)
+ return (1);
+ printf("\"%s\" ", file);
+ (void)fflush(stdout);
+ if (access(file, 0) >= 0)
+ disp = "[Appended]";
+ else
+ disp = "[New file]";
+ if ((obuf = Fopen(file, "a")) == NULL) {
+ warn((char *)NULL);
+ return (1);
+ }
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ if (sendmessage(mp, obuf, ignore, NULL) < 0) {
+ warnx("%s", file);
+ (void)Fclose(obuf);
+ return (1);
+ }
+ if (mark)
+ mp->m_flag |= MSAVED;
+ }
+ (void)fflush(obuf);
+ if (ferror(obuf))
+ warn("%s", file);
+ (void)Fclose(obuf);
+ printf("%s\n", disp);
+ return (0);
+}
+
+/*
+ * Write the indicated messages at the end of the passed
+ * file name, minus header and trailing blank line.
+ */
+int
+swrite(str)
+ char str[];
+{
+
+ return (save1(str, 1, "write", ignoreall));
+}
+
+/*
+ * Snarf the file from the end of the command line and
+ * return a pointer to it. If there is no file attached,
+ * just return NULL. Put a null in front of the file
+ * name so that the message list processing won't see it,
+ * unless the file name is the only thing on the line, in
+ * which case, return 0 in the reference flag variable.
+ */
+
+char *
+snarf(linebuf, flag, doing_Save)
+ char linebuf[];
+ int *flag;
+ int doing_Save;
+{
+ char *cp;
+
+ *flag = 1;
+ cp = strlen(linebuf) + linebuf - 1;
+
+ /*
+ * Strip away trailing blanks.
+ */
+
+ while (cp > linebuf && isspace((unsigned char)*cp))
+ cp--;
+ *++cp = '\0';
+
+ /*
+ * Now search for the beginning of the file name.
+ */
+
+ while (cp > linebuf && !isspace((unsigned char)*cp))
+ cp--;
+ if (*cp == '\0') {
+ if (!doing_Save)
+ printf("No file specified: using MBOX.\n");
+ *flag = 0; /* no message list found either */
+ return ("&");
+ }
+
+ if (isspace((unsigned char)*cp))
+ *cp++ = '\0';
+ else {
+ if (!doing_Save) *flag = 0;
+ }
+ return (cp);
+}
+
+/*
+ * Delete messages.
+ */
+int
+delete(msgvec)
+ int msgvec[];
+{
+
+ delm(msgvec);
+ return (0);
+}
+
+/*
+ * Delete messages, then type the new dot.
+ */
+int
+deltype(msgvec)
+ int msgvec[];
+{
+ int list[2];
+ int lastdot;
+
+ lastdot = dot - &message[0] + 1;
+ if (delm(msgvec) >= 0) {
+ list[0] = dot - &message[0] + 1;
+ if (list[0] > lastdot) {
+ touch(dot);
+ list[1] = 0;
+ return (type(list));
+ }
+ printf("At EOF\n");
+ } else
+ printf("No more messages\n");
+ return (0);
+}
+
+/*
+ * Delete the indicated messages.
+ * Set dot to some nice place afterwards.
+ * Internal interface.
+ */
+int
+delm(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ int *ip, last;
+
+ last = 0;
+ for (ip = msgvec; *ip != 0; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ mp->m_flag |= MDELETED|MTOUCH;
+ mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
+ last = *ip;
+ }
+ if (last != 0) {
+ dot = &message[last-1];
+ last = first(0, MDELETED);
+ if (last != 0) {
+ dot = &message[last-1];
+ return (0);
+ }
+ else {
+ dot = &message[0];
+ return (-1);
+ }
+ }
+
+ /*
+ * Following can't happen -- it keeps lint happy
+ */
+
+ return (-1);
+}
+
+/*
+ * Undelete the indicated messages.
+ */
+int
+undelete_messages(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ int *ip;
+
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ dot = mp;
+ mp->m_flag &= ~MDELETED;
+ }
+ return (0);
+}
+
+/*
+ * Interactively dump core on "core"
+ */
+int
+core()
+{
+ int pid;
+
+ switch (pid = fork()) {
+ case -1:
+ warn("fork");
+ return (1);
+ case 0:
+ abort();
+ _exit(1);
+ }
+ printf("Okie dokie");
+ (void)fflush(stdout);
+ wait_child(pid);
+ if (WIFSIGNALED(wait_status) && WCOREDUMP(wait_status))
+ printf(" -- Core dumped.\n");
+ else
+ printf(" -- Can't dump core.\n");
+ return (0);
+}
+
+/*
+ * Clobber as many bytes of stack as the user requests.
+ */
+int
+clobber(argv)
+ char **argv;
+{
+ int times;
+
+ if (argv[0] == 0)
+ times = 1;
+ else
+ times = (atoi(argv[0]) + 511) / 512;
+ clob1(times);
+ return (0);
+}
+
+/*
+ * Clobber the stack.
+ */
+void
+clob1(n)
+ int n;
+{
+ char buf[512];
+ char *cp;
+
+ if (n <= 0)
+ return;
+ for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
+ ;
+ clob1(n - 1);
+}
+
+/*
+ * Add the given header fields to the retained list.
+ * If no arguments, print the current list of retained fields.
+ */
+int
+retfield(list)
+ char *list[];
+{
+
+ return (ignore1(list, ignore + 1, "retained"));
+}
+
+/*
+ * Add the given header fields to the ignored list.
+ * If no arguments, print the current list of ignored fields.
+ */
+int
+igfield(list)
+ char *list[];
+{
+
+ return (ignore1(list, ignore, "ignored"));
+}
+
+int
+saveretfield(list)
+ char *list[];
+{
+
+ return (ignore1(list, saveignore + 1, "retained"));
+}
+
+int
+saveigfield(list)
+ char *list[];
+{
+
+ return (ignore1(list, saveignore, "ignored"));
+}
+
+int
+ignore1(list, tab, which)
+ char *list[];
+ struct ignoretab *tab;
+ const char *which;
+{
+ char field[LINESIZE];
+ int h;
+ struct ignore *igp;
+ char **ap;
+
+ if (*list == NULL)
+ return (igshow(tab, which));
+ for (ap = list; *ap != 0; ap++) {
+ istrncpy(field, *ap, sizeof(field));
+ if (member(field, tab))
+ continue;
+ h = hash(field);
+ igp = calloc(1, sizeof(struct ignore));
+ igp->i_field = calloc((unsigned)strlen(field) + 1,
+ sizeof(char));
+ strcpy(igp->i_field, field);
+ igp->i_link = tab->i_head[h];
+ tab->i_head[h] = igp;
+ tab->i_count++;
+ }
+ return (0);
+}
+
+/*
+ * Print out all currently retained fields.
+ */
+int
+igshow(tab, which)
+ struct ignoretab *tab;
+ const char *which;
+{
+ int h;
+ struct ignore *igp;
+ char **ap, **ring;
+
+ if (tab->i_count == 0) {
+ printf("No fields currently being %s.\n", which);
+ return (0);
+ }
+ ring = (char **)salloc((tab->i_count + 1) * sizeof(char *));
+ ap = ring;
+ for (h = 0; h < HSHSIZE; h++)
+ for (igp = tab->i_head[h]; igp != NULL; igp = igp->i_link)
+ *ap++ = igp->i_field;
+ *ap = 0;
+ qsort(ring, tab->i_count, sizeof(char *), igcomp);
+ for (ap = ring; *ap != 0; ap++)
+ printf("%s\n", *ap);
+ return (0);
+}
+
+/*
+ * Compare two names for sorting ignored field list.
+ */
+int
+igcomp(l, r)
+ const void *l, *r;
+{
+
+ return (strcmp(*(const char **)l, *(const char **)r));
+}
diff --git a/mail_cmds/mail/cmd3.c b/mail_cmds/mail/cmd3.c
new file mode 100644
index 0000000..67bcd07
--- /dev/null
+++ b/mail_cmds/mail/cmd3.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/cmd3.c,v 1.10 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Still more user commands.
+ */
+
+/*
+ * Process a shell escape by saving signals, ignoring signals,
+ * and forking a sh -c
+ */
+int
+shell(str)
+ char *str;
+{
+ sig_t sigint = signal(SIGINT, SIG_IGN);
+ char *sh;
+ char cmd[BUFSIZ];
+
+ if (strlcpy(cmd, str, sizeof(cmd)) >= sizeof(cmd))
+ return (1);
+ if (bangexp(cmd, sizeof(cmd)) < 0)
+ return (1);
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ (void)run_command(sh, 0, -1, -1, "-c", cmd, NULL);
+ (void)signal(SIGINT, sigint);
+ printf("!\n");
+ return (0);
+}
+
+/*
+ * Fork an interactive shell.
+ */
+/*ARGSUSED*/
+int
+dosh(str)
+ char *str;
+{
+ sig_t sigint = signal(SIGINT, SIG_IGN);
+ char *sh;
+
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ (void)run_command(sh, 0, -1, -1, NULL, NULL, NULL);
+ (void)signal(SIGINT, sigint);
+ printf("\n");
+ return (0);
+}
+
+/*
+ * Expand the shell escape by expanding unescaped !'s into the
+ * last issued command where possible.
+ */
+int
+bangexp(str, strsize)
+ char *str;
+ size_t strsize;
+{
+ char bangbuf[BUFSIZ];
+ static char lastbang[BUFSIZ];
+ char *cp, *cp2;
+ int n, changed = 0;
+
+ if (value("bang") == NULL)
+ return (0);
+ cp = str;
+ cp2 = bangbuf;
+ n = sizeof(bangbuf);
+ while (*cp != '\0') {
+ if (*cp == '!') {
+ if (n < strlen(lastbang)) {
+overf:
+ printf("Command buffer overflow\n");
+ return (-1);
+ }
+ changed++;
+ if (strlcpy(cp2, lastbang, sizeof(bangbuf) - (cp2 - bangbuf))
+ >= sizeof(bangbuf) - (cp2 - bangbuf))
+ goto overf;
+ cp2 += strlen(lastbang);
+ n -= strlen(lastbang);
+ cp++;
+ continue;
+ }
+ if (*cp == '\\' && cp[1] == '!') {
+ if (--n <= 1)
+ goto overf;
+ *cp2++ = '!';
+ cp += 2;
+ changed++;
+ }
+ if (--n <= 1)
+ goto overf;
+ *cp2++ = *cp++;
+ }
+ *cp2 = 0;
+ if (changed) {
+ printf("!%s\n", bangbuf);
+ (void)fflush(stdout);
+ }
+ if (strlcpy(str, bangbuf, strsize) >= strsize)
+ goto overf;
+ if (strlcpy(lastbang, bangbuf, sizeof(lastbang)) >= sizeof(lastbang))
+ goto overf;
+ return (0);
+}
+
+/*
+ * Print out a nice help message from some file or another.
+ */
+
+int
+help()
+{
+ int c;
+ FILE *f;
+
+ if ((f = Fopen(_PATH_HELP, "r")) == NULL) {
+ warn("%s", _PATH_HELP);
+ return (1);
+ }
+ while ((c = getc(f)) != EOF)
+ putchar(c);
+ (void)Fclose(f);
+ return (0);
+}
+
+/*
+ * Change user's working directory.
+ */
+int
+schdir(arglist)
+ char **arglist;
+{
+ char *cp;
+
+ if (*arglist == NULL) {
+ if (homedir == NULL)
+ return (1);
+ cp = homedir;
+ } else
+ if ((cp = expand(*arglist)) == NULL)
+ return (1);
+ if (chdir(cp) < 0) {
+ warn("%s", cp);
+ return (1);
+ }
+ return (0);
+}
+
+char *
+getauthor(str)
+ char * str;
+{
+ char *atsign;
+ if (str == NULL) {
+ return(NULL);
+ }
+ atsign = strchr(str,'@');
+ if (atsign != NULL) {
+ str = savestr(str); /* copy to modify */
+ atsign = strchr(str,'@');
+ *atsign = '\0';
+ }
+/*
+printf("file name=%s\n", str);
+*/
+ return (str);
+}
+
+int
+followup(msgvec)
+ int *msgvec;
+{
+ int res;
+ int reset = 0;
+ if (value("recordrecip") == NULL) {
+ assign("recordrecip", "");
+ reset = 1;
+ }
+ res = respond(msgvec);
+ if (reset) {
+ char *alist[2];
+ alist[0] = "recordrecip";
+ alist[1] = NULL;
+ unset(alist);
+ }
+ return (res);
+}
+
+int
+Capfollowup(msgvec)
+ int *msgvec;
+{
+ int res;
+ int reset = 0;
+ if (value("recordrecip") == NULL) {
+ assign("recordrecip", "");
+ reset = 1;
+ }
+ res = Respond(msgvec);
+ if (reset) {
+ char *alist[2];
+ alist[0] = "recordrecip";
+ alist[1] = NULL;
+ unset(alist);
+ }
+ return (res);
+}
+
+int
+respond(msgvec)
+ int *msgvec;
+{
+ if (value("Replyall") == NULL && value("flipr") == NULL)
+ return (dorespond(msgvec));
+ else
+ return (doRespond(msgvec));
+}
+
+/*
+ * Reply to a list of messages. Extract each name from the
+ * message header and send them off to mail1()
+ */
+int
+dorespond(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ char *cp, *rcv, *replyto;
+ char **ap;
+ struct name *np;
+ struct header head;
+
+ if (msgvec[1] != 0) {
+ printf("Sorry, can't reply to multiple messages at once\n");
+ return (1);
+ }
+ mp = &message[msgvec[0] - 1];
+ touch(mp);
+ dot = mp;
+ if ((rcv = skin(hfield("from", mp))) == NULL)
+ rcv = skin(nameof(mp, 1));
+ if ((replyto = skin(hfield("reply-to", mp))) != NULL)
+ np = extract(replyto, GTO);
+ else if ((cp = skin(hfield("to", mp))) != NULL)
+ np = extract(cp, GTO);
+ else
+ np = NULL;
+ np = elide(np);
+ /*
+ * Delete my name from the reply list,
+ * and with it, all my alternate names.
+ */
+ np = delname(np, myname);
+ if (altnames)
+ for (ap = altnames; *ap != NULL; ap++)
+ np = delname(np, *ap);
+ if (np != NULL && replyto == NULL)
+ np = cat(np, extract(rcv, GTO));
+ else if (np == NULL) {
+ if (replyto != NULL)
+ printf("Empty reply-to field -- replying to author\n");
+ np = extract(rcv, GTO);
+ }
+ head.h_to = np;
+ if ((head.h_subject = hfield("subject", mp)) == NULL)
+ head.h_subject = hfield("subj", mp);
+ head.h_subject = reedit(head.h_subject);
+ if (replyto == NULL && (cp = skin(hfield("cc", mp))) != NULL) {
+ np = elide(extract(cp, GCC));
+ np = delname(np, myname);
+ if (altnames != 0)
+ for (ap = altnames; *ap != NULL; ap++)
+ np = delname(np, *ap);
+ head.h_cc = np;
+ } else
+ head.h_cc = NULL;
+ head.h_bcc = NULL;
+ head.h_smopts = NULL;
+ head.h_replyto = value("REPLYTO");
+ head.h_inreplyto = skin(hfield("message-id", mp));
+ mail1(&head, 1);
+ return (0);
+}
+
+/*
+ * Modify the subject we are replying to to begin with Re: if
+ * it does not already.
+ */
+char *
+reedit(subj)
+ char *subj;
+{
+ char *newsubj;
+
+ if (subj == NULL)
+ return (NULL);
+ if ((subj[0] == 'r' || subj[0] == 'R') &&
+ (subj[1] == 'e' || subj[1] == 'E') &&
+ subj[2] == ':')
+ return (subj);
+ newsubj = salloc(strlen(subj) + 5);
+ sprintf(newsubj, "Re: %s", subj);
+ return (newsubj);
+}
+
+/*
+ * Preserve the named messages, so that they will be sent
+ * back to the system mailbox.
+ */
+int
+preserve(msgvec)
+ int *msgvec;
+{
+ int *ip, mesg;
+ struct message *mp;
+
+ if (edit) {
+ printf("Cannot \"preserve\" in edit mode\n");
+ return (1);
+ }
+ for (ip = msgvec; *ip != 0; ip++) {
+ mesg = *ip;
+ mp = &message[mesg-1];
+ mp->m_flag |= MPRESERVE;
+ mp->m_flag &= ~MBOX;
+ dot = mp;
+ }
+ return (0);
+}
+
+/*
+ * Mark all given messages as unread.
+ */
+int
+unread(msgvec)
+ int msgvec[];
+{
+ int *ip;
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ dot = &message[*ip-1];
+ dot->m_flag &= ~(MREAD|MTOUCH);
+ dot->m_flag |= MSTATUS;
+ }
+ return (0);
+}
+
+/*
+ * Print the size of each message.
+ */
+int
+messize(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ int *ip, mesg;
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ mesg = *ip;
+ mp = &message[mesg-1];
+ printf("%d: %ld/%ld\n", mesg, mp->m_lines, mp->m_size);
+ }
+ return (0);
+}
+
+/*
+ * Quit quickly. If we are sourcing, just pop the input level
+ * by returning an error.
+ */
+int
+rexit(e)
+ int e;
+{
+ if (sourcing)
+ return (1);
+ exit(0);
+ /*NOTREACHED*/
+}
+
+/*
+ * Set or display a variable value. Syntax is similar to that
+ * of csh.
+ */
+int
+set(arglist)
+ char **arglist;
+{
+ struct var *vp;
+ char *cp, *cp2;
+ char varbuf[BUFSIZ], **ap, **p;
+ int errs, h, s;
+ int stringlength;
+
+ if (*arglist == NULL) {
+ char * printval;
+ for (h = 0, s = 1; h < HSHSIZE; h++)
+ for (vp = variables[h]; vp != NULL; vp = vp->v_link)
+ s++;
+ ap = (char **)salloc(s * sizeof(*ap));
+ for (h = 0, p = ap; h < HSHSIZE; h++)
+ for (vp = variables[h]; vp != NULL; vp = vp->v_link)
+ *p++ = vp->v_name;
+ *p = NULL;
+ sort(ap);
+ for (p = ap; *p != NULL; p++) {
+ printf("%s", *p);
+ printval = value(*p);
+ if (printval) {
+ if (printval[0]!='\0') printf("\t\"%s\"", printval);
+ }
+ printf("\n");
+ }
+ return (0);
+ }
+ errs = 0;
+ for (ap = arglist; *ap != NULL; ap++) {
+ cp = *ap;
+ stringlength = strlen(cp);
+ if (stringlength > 2 && cp[0]=='n' && cp[1]=='o') {
+ /* set no<var> means unset <var> */
+ char *alist[2];
+ alist[0] = cp+2;
+ alist[1] = NULL;
+ errs += unset(alist);
+ continue;
+ }
+ if (stringlength == 3 && cp[0]=='a' && cp[1]=='s' && cp[2]=='k') {
+ /* synonym: must convert into "asksub" */
+ cp = "asksub";
+ }
+ cp2 = varbuf;
+ while (cp2 < varbuf + sizeof(varbuf) - 1 && *cp != '=' && *cp != '\0')
+ *cp2++ = *cp++;
+ *cp2 = '\0';
+ if (*cp == '\0')
+ cp = "";
+ else
+ cp++;
+ if (equal(varbuf, "")) {
+ printf("Non-null variable name required\n");
+ errs++;
+ continue;
+ }
+ assign(varbuf, cp);
+ }
+ return (errs);
+}
+
+/*
+ * Unset a bunch of variable values.
+ */
+int
+unset(arglist)
+ char **arglist;
+{
+ struct var *vp, *vp2;
+ int errs, h;
+ char **ap;
+ int stringlength;
+
+ errs = 0;
+ for (ap = arglist; *ap != NULL; ap++) {
+ stringlength = strlen(*ap);
+ if (stringlength > 2 && (*ap)[0]=='n' && (*ap)[1]=='o') {
+ /* no<var> is not in db - only <var> can be in table */
+ printf("\"%s\": variable cannot be unset\n", *ap);
+ errs++;
+ continue;
+ }
+ if (stringlength == 3 && (*ap)[0]=='a' && (*ap)[1]=='s' && (*ap)[2]=='k') {
+ /* synonym: must convert into "asksub" */
+ *ap = "asksub";
+ }
+ if ((vp2 = lookup(*ap)) == NULL) {
+ if (getenv(*ap)) {
+ unsetenv(*ap);
+ if (debug)
+ fprintf(stderr,"WARNING: unsetting environment variable: %s\n", *ap);
+ } else if (!sourcing) {
+ printf("\"%s\": undefined variable\n", *ap);
+ errs++;
+ }
+ continue;
+ }
+ h = hash(*ap);
+ if (vp2 == variables[h]) {
+ variables[h] = variables[h]->v_link;
+ v_free(vp2->v_name);
+ v_free(vp2->v_value);
+ (void)free(vp2);
+ continue;
+ }
+ for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
+ ;
+ vp->v_link = vp2->v_link;
+ v_free(vp2->v_name);
+ v_free(vp2->v_value);
+ (void)free(vp2);
+ }
+ return (errs);
+}
+
+/*
+ * Put add users to a group.
+ */
+int
+group(argv)
+ char **argv;
+{
+ struct grouphead *gh;
+ struct group *gp;
+ char **ap, *gname, **p;
+ int h, s;
+
+ if (*argv == NULL) {
+ for (h = 0, s = 1; h < HSHSIZE; h++)
+ for (gh = groups[h]; gh != NULL; gh = gh->g_link)
+ s++;
+ ap = (char **)salloc(s * sizeof(*ap));
+ for (h = 0, p = ap; h < HSHSIZE; h++)
+ for (gh = groups[h]; gh != NULL; gh = gh->g_link)
+ *p++ = gh->g_name;
+ *p = NULL;
+ sort(ap);
+ for (p = ap; *p != NULL; p++)
+ printgroup(*p);
+ return (0);
+ }
+ if (argv[1] == NULL) {
+ printgroup(*argv);
+ return (0);
+ }
+ gname = *argv;
+ h = hash(gname);
+ if ((gh = findgroup(gname)) == NULL) {
+ gh = calloc(sizeof(*gh), 1);
+ gh->g_name = vcopy(gname);
+ gh->g_list = NULL;
+ gh->g_link = groups[h];
+ groups[h] = gh;
+ }
+
+ /*
+ * Insert names from the command list into the group.
+ * Who cares if there are duplicates? They get tossed
+ * later anyway.
+ */
+
+ for (ap = argv+1; *ap != NULL; ap++) {
+ gp = calloc(sizeof(*gp), 1);
+ gp->ge_name = vcopy(*ap);
+ gp->ge_link = gh->g_list;
+ gh->g_list = gp;
+ }
+ return (0);
+}
+
+/*
+ * Sort the passed string vecotor into ascending dictionary
+ * order.
+ */
+void
+sort(list)
+ char **list;
+{
+ char **ap;
+
+ for (ap = list; *ap != NULL; ap++)
+ ;
+ if (ap-list < 2)
+ return;
+ qsort(list, ap-list, sizeof(*list), diction);
+}
+
+/*
+ * Do a dictionary order comparison of the arguments from
+ * qsort.
+ */
+int
+diction(a, b)
+ const void *a, *b;
+{
+ return (strcmp(*(const char **)a, *(const char **)b));
+}
+
+/*
+ * The do nothing command for comments.
+ */
+
+/*ARGSUSED*/
+int
+null(e)
+ int e;
+{
+ return (0);
+}
+
+/*
+ * Change to another file. With no argument, print information about
+ * the current file.
+ */
+int
+file(argv)
+ char **argv;
+{
+
+ if (argv[0] == NULL) {
+ newfileinfo(0);
+ return (0);
+ }
+ if (setfile(*argv) < 0)
+ return (1);
+ announce();
+ return (0);
+}
+
+/*
+ * Expand file names like echo
+ */
+int
+echo(argv)
+ char **argv;
+{
+ char **ap, *cp;
+
+ for (ap = argv; *ap != NULL; ap++) {
+ cp = *ap;
+ if ((cp = expand(cp)) != NULL) {
+ if (ap != argv)
+ printf(" ");
+ printf("%s", cp);
+ }
+ }
+ printf("\n");
+ return (0);
+}
+
+int
+Respond(msgvec)
+ int *msgvec;
+{
+ if (value("Replyall") == NULL && value("flipr") == NULL)
+ return (doRespond(msgvec));
+ else
+ return (dorespond(msgvec));
+}
+
+/*
+ * Reply to a series of messages by simply mailing to the senders
+ * and not messing around with the To: and Cc: lists as in normal
+ * reply.
+ */
+int
+doRespond(msgvec)
+ int msgvec[];
+{
+ struct header head;
+ struct message *mp;
+ int *ap;
+ char *cp, *mid = NULL;
+
+ head.h_to = NULL;
+ for (ap = msgvec; *ap != 0; ap++) {
+ mp = &message[*ap - 1];
+ touch(mp);
+ dot = mp;
+ if ((cp = skin(hfield("from", mp))) == NULL)
+ cp = skin(nameof(mp, 2));
+ head.h_to = cat(head.h_to, extract(cp, GTO));
+ mid = skin(hfield("message-id", mp));
+ }
+ if (head.h_to == NULL)
+ return (0);
+ mp = &message[msgvec[0] - 1];
+ if ((head.h_subject = hfield("subject", mp)) == NULL)
+ head.h_subject = hfield("subj", mp);
+ head.h_subject = reedit(head.h_subject);
+ head.h_cc = NULL;
+ head.h_bcc = NULL;
+ head.h_smopts = NULL;
+ head.h_replyto = value("REPLYTO");
+ head.h_inreplyto = mid;
+ mail1(&head, 1);
+ return (0);
+}
+
+/*
+ * Conditional commands. These allow one to parameterize one's
+ * .mailrc and do some things if sending, others if receiving.
+ */
+int
+ifcmd(argv)
+ char **argv;
+{
+ char *cp;
+
+ if (cond != CANY) {
+ printf("Illegal nested \"if\"\n");
+ return (1);
+ }
+ cond = CANY;
+ cp = argv[0];
+ switch (*cp) {
+ case 'r': case 'R':
+ cond = CRCV;
+ break;
+
+ case 's': case 'S':
+ cond = CSEND;
+ break;
+
+ default:
+ printf("Unrecognized if-keyword: \"%s\"\n", cp);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Implement 'else'. This is pretty simple -- we just
+ * flip over the conditional flag.
+ */
+int
+elsecmd()
+{
+
+ switch (cond) {
+ case CANY:
+ printf("\"Else\" without matching \"if\"\n");
+ return (1);
+
+ case CSEND:
+ cond = CRCV;
+ break;
+
+ case CRCV:
+ cond = CSEND;
+ break;
+
+ default:
+ printf("Mail's idea of conditions is screwed up\n");
+ cond = CANY;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * End of if statement. Just set cond back to anything.
+ */
+int
+endifcmd()
+{
+
+ if (cond == CANY) {
+ printf("\"Endif\" without matching \"if\"\n");
+ return (1);
+ }
+ cond = CANY;
+ return (0);
+}
+
+/*
+ * Set the list of alternate names.
+ */
+int
+alternates(namelist)
+ char **namelist;
+{
+ int c;
+ char **ap, **ap2, *cp;
+
+ c = argcount(namelist) + 1;
+ if (c == 1) {
+ if (altnames == 0)
+ return (0);
+ for (ap = altnames; *ap != NULL; ap++)
+ printf("%s ", *ap);
+ printf("\n");
+ return (0);
+ }
+ if (altnames != 0)
+ (void)free(altnames);
+ altnames = calloc((unsigned)c, sizeof(char *));
+ for (ap = namelist, ap2 = altnames; *ap != NULL; ap++, ap2++) {
+ cp = calloc((unsigned)strlen(*ap) + 1, sizeof(char));
+ strcpy(cp, *ap);
+ *ap2 = cp;
+ }
+ *ap2 = 0;
+ return (0);
+}
diff --git a/mail_cmds/mail/cmdtab.c b/mail_cmds/mail/cmdtab.c
new file mode 100644
index 0000000..d001ac1
--- /dev/null
+++ b/mail_cmds/mail/cmdtab.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/cmdtab.c,v 1.6 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "def.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Define all of the command names and bindings.
+ */
+
+const struct cmd cmdtab[] = {
+ /* msgmask msgflag */
+ /* command function argtype result & mask */
+ /* ------- -------- ------- ------ ------- */
+ { "next", next, NDMLIST, 0, MMNDEL },
+ { "alias", group, M|RAWLIST, 0, 1000 },
+ { "print", type, MSGLIST, 0, MMNDEL },
+ { "type", type, MSGLIST, 0, MMNDEL },
+ { "Type", Type, MSGLIST, 0, MMNDEL },
+ { "Print", Type, MSGLIST, 0, MMNDEL },
+ { "visual", visual, I|MSGLIST, 0, MMNORM },
+ { "top", top, MSGLIST, 0, MMNDEL },
+ { "touch", stouch, W|MSGLIST, 0, MMNDEL },
+ { "preserve", preserve, W|MSGLIST, 0, MMNDEL },
+ { "delete", delete, W|P|MSGLIST, 0, MMNDEL },
+ { "dp", deltype, W|MSGLIST, 0, MMNDEL },
+ { "dt", deltype, W|MSGLIST, 0, MMNDEL },
+ { "undelete", undelete_messages, P|MSGLIST, MDELETED,MMNDEL },
+ { "unset", unset, M|RAWLIST, 1, 1000 },
+ { "mail", sendmail, R|M|I|STRLIST, 0, 0 },
+ { "mbox", mboxit, W|MSGLIST, 0, 0 },
+ { "more", more, MSGLIST, 0, MMNDEL },
+ { "page", more, MSGLIST, 0, MMNDEL },
+ { "More", More, MSGLIST, 0, MMNDEL },
+ { "Page", More, MSGLIST, 0, MMNDEL },
+ { "unread", unread, MSGLIST, 0, MMNDEL },
+ { "!", shell, I|STRLIST, 0, 0 },
+ { "copy", copycmd, M|STRLIST, 0, 0 },
+ { "Copy", Capcopycmd, MSGLIST, 0, 0 },
+ { "chdir", schdir, M|RAWLIST, 0, 1 },
+ { "cd", schdir, M|RAWLIST, 0, 1 },
+ { "save", save, STRLIST, 0, 0 },
+ { "Save", Capsave, STRLIST, 0, 0 },
+ { "source", source, M|RAWLIST, 1, 1 },
+ { "set", set, M|RAWLIST, 0, 1000 },
+ { "shell", dosh, I|NOLIST, 0, 0 },
+ { "version", pversion, M|NOLIST, 0, 0 },
+ { "group", group, M|RAWLIST, 0, 1000 },
+ { "write", swrite, STRLIST, 0, 0 },
+ { "from", from, MSGLIST, 0, MMNORM },
+ { "file", file, T|M|RAWLIST, 0, 1 },
+ { "followup", followup, MSGLIST, 0, 0 },
+ { "folder", file, T|M|RAWLIST, 0, 1 },
+ { "folders", folders, T|M|NOLIST, 0, 0 },
+ { "Followup", Capfollowup, MSGLIST, 0, 0 },
+ { "|", mailpipe, STRLIST, 0, 0 },
+ { "pipe", mailpipe, STRLIST, 0, 0 },
+ { "?", help, M|NOLIST, 0, 0 },
+ { "z", scroll, M|STRLIST, 0, 0 },
+ { "headers", headers, MSGLIST, 0, MMNDEL },
+ { "help", help, M|NOLIST, 0, 0 },
+ { "=", pdot, NOLIST, 0, 0 },
+ { "Reply", Respond, R|I|MSGLIST, 0, MMNDEL },
+ { "Respond", Respond, R|I|MSGLIST, 0, MMNDEL },
+ { "reply", respond, R|I|MSGLIST, 0, MMNDEL },
+ { "respond", respond, R|I|MSGLIST, 0, MMNDEL },
+ { "edit", editor, I|MSGLIST, 0, MMNORM },
+ { "echo", echo, M|RAWLIST, 0, 1000 },
+ { "quit", quitcmd, NOLIST, 0, 0 },
+ { "list", pcmdlist, M|NOLIST, 0, 0 },
+ { "xit", rexit, M|NOLIST, 0, 0 },
+ { "exit", rexit, M|NOLIST, 0, 0 },
+ { "size", messize, MSGLIST, 0, MMNDEL },
+ { "hold", preserve, W|MSGLIST, 0, MMNDEL },
+ { "if", ifcmd, F|M|RAWLIST, 1, 1 },
+ { "else", elsecmd, F|M|RAWLIST, 0, 0 },
+ { "endif", endifcmd, F|M|RAWLIST, 0, 0 },
+ { "alternates", alternates, M|RAWLIST, 0, 1000 },
+ { "ignore", igfield, M|RAWLIST, 0, 1000 },
+ { "discard", igfield, M|RAWLIST, 0, 1000 },
+ { "retain", retfield, M|RAWLIST, 0, 1000 },
+ { "saveignore", saveigfield, M|RAWLIST, 0, 1000 },
+ { "savediscard",saveigfield, M|RAWLIST, 0, 1000 },
+ { "saveretain", saveretfield, M|RAWLIST, 0, 1000 },
+/* { "Header", Header, STRLIST, 0, 1000 }, */
+ { "core", core, M|NOLIST, 0, 0 },
+ { "#", null, M|NOLIST, 0, 0 },
+ { "clobber", clobber, M|RAWLIST, 0, 1 },
+ { "inc", inc, T|NOLIST, 0, 0 },
+ { 0, 0, 0, 0, 0 }
+};
diff --git a/mail_cmds/mail/collect.c b/mail_cmds/mail/collect.c
new file mode 100644
index 0000000..703f953
--- /dev/null
+++ b/mail_cmds/mail/collect.c
@@ -0,0 +1,998 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/collect.c,v 1.12 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Collect input from standard input, handling
+ * ~ escapes.
+ */
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Read a message from standard output and return a read file to it
+ * or NULL on error.
+ */
+
+/*
+ * The following hokiness with global variables is so that on
+ * receipt of an interrupt signal, the partial message can be salted
+ * away on dead.letter.
+ */
+
+static sig_t saveint; /* Previous SIGINT value */
+static sig_t savehup; /* Previous SIGHUP value */
+static sig_t savetstp; /* Previous SIGTSTP value */
+static sig_t savettou; /* Previous SIGTTOU value */
+static sig_t savettin; /* Previous SIGTTIN value */
+static FILE *collf; /* File for saving away */
+static int hadintr; /* Have seen one SIGINT so far */
+
+static jmp_buf colljmp; /* To get back to work */
+static int colljmp_p; /* whether to long jump */
+static jmp_buf collabort; /* To end collection with error */
+
+static jmp_buf pipejmp; /* To catch the loss of pipe connection */
+
+void
+brokthepipe(signo)
+ int signo;
+{
+ longjmp(pipejmp, 1);
+}
+
+FILE *
+collect(hp, printheaders)
+ struct header *hp;
+ int printheaders;
+{
+ FILE *fbuf;
+ int lc, cc, escape, eofcount, fd, c, t;
+ char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub;
+ sigset_t nset;
+ int longline, lastlong, rc; /* So we don't make 2 or more lines
+ out of a long input line. */
+ int nlines, usepager;
+ char *envptr;
+
+ collf = NULL;
+ /*
+ * Start catching signals from here, but we're still die on interrupts
+ * until we're in the main loop.
+ */
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGINT);
+ (void)sigaddset(&nset, SIGHUP);
+ (void)sigprocmask(SIG_BLOCK, &nset, NULL);
+ if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
+ (void)signal(SIGINT, collint);
+ if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
+ (void)signal(SIGHUP, collhup);
+ savetstp = signal(SIGTSTP, collstop);
+ savettou = signal(SIGTTOU, collstop);
+ savettin = signal(SIGTTIN, collstop);
+ if (setjmp(collabort) || setjmp(colljmp)) {
+ (void)rm(tempname);
+ goto err;
+ }
+ (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+
+ noreset++;
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RsXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (collf = Fdopen(fd, "w+")) == NULL) {
+ warn("%s", tempname);
+ goto err;
+ }
+ (void)rm(tempname);
+
+ /*
+ * If we are going to prompt for a subject,
+ * refrain from printing a newline after
+ * the headers (since some people mind).
+ */
+ t = GTO|GSUBJECT|GCC|GNL;
+ getsub = 0;
+ if (hp->h_subject == NULL && value("interactive") != NULL &&
+ (value("ask") != NULL || value("asksub") != NULL))
+ t &= ~GNL, getsub++;
+ if (printheaders) {
+ puthead(hp, stdout, t);
+ (void)fflush(stdout);
+ }
+ if ((cp = value("escape")) != NULL)
+ escape = *cp;
+ else
+ escape = ESCAPE;
+ eofcount = 0;
+ hadintr = 0;
+ lastlong = 0;
+ longline = 0;
+
+ if (!setjmp(colljmp)) {
+ if (getsub) {
+ if (grabh(hp, GSUBJECT)) {
+ /* grabh was interrupted: must count as first one */
+ /* makes Unix 2003 conformance tests mailx_01.ex{49,57} pass */
+ /* printf("Interrupt from Subject:\n"); */
+ hadintr++;
+ goto cont;
+ }
+ }
+ } else {
+ /*
+ * Come here for printing the after-signal message.
+ * Duplicate messages won't be printed because
+ * the write is aborted if we get a SIGTTOU.
+ */
+cont:
+ if (hadintr) {
+ (void)fflush(stdout);
+ fprintf(stderr,
+ "\n(Interrupt -- one more to kill letter)\n");
+ } else {
+ printf("(continue)\n");
+ (void)fflush(stdout);
+ }
+ }
+ for (;;) {
+ colljmp_p = 1;
+ c = readline(stdin, linebuf, LINESIZE);
+ colljmp_p = 0;
+ if (c < 0) {
+ if (value("interactive") != NULL &&
+ value("ignoreeof") != NULL && ++eofcount < 25) {
+ printf("Use \".\" to terminate letter\n");
+ continue;
+ }
+ break;
+ }
+ lastlong = longline;
+ longline = c == LINESIZE - 1;
+ eofcount = 0;
+ hadintr = 0;
+ if (linebuf[0] == '.' && linebuf[1] == '\0' &&
+ value("interactive") != NULL && !lastlong &&
+ (value("dot") != NULL || value("ignoreeof") != NULL))
+ break;
+ if (linebuf[0] != escape || value("interactive") == NULL ||
+ lastlong) {
+ if (putline(collf, linebuf, !longline) < 0)
+ goto err;
+ continue;
+ }
+ c = linebuf[1];
+ switch (c) {
+ default:
+ /*
+ * On double escape, just send the single one.
+ * Otherwise, it's an error.
+ */
+ if (c == escape) {
+ if (putline(collf, &linebuf[1], !longline) < 0)
+ goto err;
+ else
+ break;
+ }
+ printf("Unknown tilde escape.\n");
+ break;
+ case 'C':
+ /*
+ * Dump core.
+ */
+ core();
+ break;
+ case '!':
+ /*
+ * Shell escape, send the balance of the
+ * line to sh -c.
+ */
+ shell(&linebuf[2]);
+ break;
+ case ':':
+ case '_':
+ /*
+ * Escape to command mode, but be nice!
+ */
+ execute(&linebuf[2], 1);
+ goto cont;
+ case '.':
+ /*
+ * Simulate end of file on input.
+ */
+ goto out;
+ case 'q':
+ /*
+ * Force a quit of sending mail.
+ * Act like an interrupt happened.
+ */
+ hadintr++;
+ collint(SIGINT);
+ exit(1);
+ case 'x':
+ /*
+ * Exit, do not save in dead.letter.
+ */
+ goto err;
+ case 'h':
+ /*
+ * Grab a bunch of headers.
+ */
+ grabh(hp, GTO|GSUBJECT|GCC|GBCC);
+ goto cont;
+ case 't':
+ /*
+ * Add to the To list.
+ */
+ hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO));
+ break;
+ case 's':
+ /*
+ * Set the Subject line.
+ */
+ cp = &linebuf[2];
+ while (isspace((unsigned char)*cp))
+ cp++;
+ hp->h_subject = savestr(cp);
+ break;
+ case 'R':
+ /*
+ * Set the Reply-To line.
+ */
+ cp = &linebuf[2];
+ while (isspace((unsigned char)*cp))
+ cp++;
+ hp->h_replyto = savestr(cp);
+ break;
+ case 'c':
+ /*
+ * Add to the CC list.
+ */
+ hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC));
+ break;
+ case 'b':
+ /*
+ * Add to the BCC list.
+ */
+ hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC));
+ break;
+ case 'i':
+ case 'A':
+ case 'a':
+ /*
+ * Insert named variable in message.
+ */
+ switch(c) {
+ case 'i':
+ cp = &linebuf[2];
+ while(isspace((unsigned char)*cp))
+ cp++;
+ break;
+ case 'a':
+ cp = "sign";
+ break;
+ case 'A':
+ cp = "Sign";
+ break;
+ default:
+ goto err;
+ }
+
+ if(*cp != '\0' && (cp = value(cp)) != NULL) {
+ if (*cp != '\0') {
+ printf("%s\n", cp);
+ if(putline(collf, cp, 1) < 0)
+ goto err;
+ }
+ }
+
+ break;
+ case 'd':
+ /*
+ * Read in the dead letter file.
+ */
+ if (strlcpy(linebuf + 2, getdeadletter(),
+ sizeof(linebuf) - 2)
+ >= sizeof(linebuf) - 2) {
+ printf("Line buffer overflow\n");
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'r':
+ case '<':
+ /*
+ * Invoke a file:
+ * Search for the file name,
+ * then open it and copy the contents to collf.
+ */
+ cp = &linebuf[2];
+ while (isspace((unsigned char)*cp))
+ cp++;
+ if (*cp == '\0') {
+ printf("Interpolate what file?\n");
+ break;
+ }
+ cp = expand(cp);
+ if (cp == NULL)
+ break;
+ if (*cp == '!') {
+ /*
+ * Insert stdout of command.
+ */
+ char *sh;
+ int nullfd, tempfd, rc;
+ char tempname2[PATHSIZE];
+
+ if ((nullfd = open("/dev/null", O_RDONLY, 0))
+ == -1) {
+ warn("/dev/null");
+ break;
+ }
+
+ (void)snprintf(tempname2, sizeof(tempname2),
+ "%s/mail.ReXXXXXXXXXX", tmpdir);
+ if ((tempfd = mkstemp(tempname2)) == -1 ||
+ (fbuf = Fdopen(tempfd, "w+")) == NULL) {
+ warn("%s", tempname2);
+ break;
+ }
+ (void)unlink(tempname2);
+
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+
+ rc = run_command(sh, 0, nullfd, fileno(fbuf),
+ "-c", cp+1, NULL);
+
+ close(nullfd);
+
+ if (rc < 0) {
+ (void)Fclose(fbuf);
+ break;
+ }
+
+ if (fsize(fbuf) == 0) {
+ fprintf(stderr,
+ "No bytes from command \"%s\"\n",
+ cp+1);
+ (void)Fclose(fbuf);
+ break;
+ }
+
+ rewind(fbuf);
+ } else if (isdir(cp)) {
+ printf("%s: Directory\n", cp);
+ break;
+ } else if ((fbuf = Fopen(cp, "r")) == NULL) {
+ warn("%s", cp);
+ break;
+ }
+ printf("\"%s\" ", cp);
+ (void)fflush(stdout);
+ lc = 0;
+ cc = 0;
+ while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) {
+ if (rc != LINESIZE - 1)
+ lc++;
+ if ((t = putline(collf, linebuf,
+ rc != LINESIZE - 1)) < 0) {
+ (void)Fclose(fbuf);
+ goto err;
+ }
+ cc += t;
+ }
+ (void)Fclose(fbuf);
+ printf("%d/%d\n", lc, cc);
+ break;
+ case 'w':
+ /*
+ * Write the message on a file.
+ */
+ cp = &linebuf[2];
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0') {
+ fprintf(stderr, "Write what file!?\n");
+ break;
+ }
+ if ((cp = expand(cp)) == NULL)
+ break;
+ rewind(collf);
+ exwrite(cp, collf, 1);
+ break;
+ case 'm':
+ case 'M':
+ case 'f':
+ case 'F':
+ /*
+ * Interpolate the named messages, if we
+ * are in receiving mail mode. Does the
+ * standard list processing garbage.
+ * If ~f is given, we don't shift over.
+ */
+ if (forward(linebuf + 2, collf, tempname, c) < 0)
+ goto err;
+ goto cont;
+ case '?':
+ if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) {
+ warn("%s", _PATH_TILDE);
+ break;
+ }
+ while ((t = getc(fbuf)) != EOF)
+ (void)putchar(t);
+ (void)Fclose(fbuf);
+ break;
+ case 'p':
+ /*
+ * Print out the current state of the
+ * message without altering anything.
+ */
+ rewind(collf);
+ printf("-------\nMessage contains:\n");
+ puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
+ if ((envptr = value("crt")) != NULL) {
+ nlines = atoi(envptr);
+ } else {
+ nlines = 0;
+ }
+ fbuf = stdout;
+ usepager = 0;
+ if (nlines>0) {
+ /* See if crt < num lines in file */
+ int countlines = 0;
+ while ((t = getc(collf)) != EOF) {
+ if (t=='\n') {
+ countlines++;
+ if (nlines < countlines) {
+ break;
+ }
+ }
+ }
+ rewind(collf);
+ if (nlines < countlines) {
+ /* Must use a paginator: default is "more" */
+ usepager = 1;
+ envptr = value("PAGER");
+ if (envptr == NULL || *envptr == '\0')
+ envptr = _PATH_MORE;
+ if (setjmp(pipejmp))
+ goto close_pipe;
+ fbuf = Popen(envptr, "w");
+ if (fbuf == NULL) {
+ warnx("%s", envptr);
+ fbuf = stdout;
+ } else
+ (void)signal(SIGPIPE, brokthepipe);
+ }
+ }
+ while ((t = getc(collf)) != EOF)
+ (void)putchar(t);
+ if (usepager) {
+ close_pipe:
+ if (fbuf != stdout) {
+ /*
+ * Ignore SIGPIPE so it can't cause a duplicate close.
+ */
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)Pclose(fbuf);
+ (void)signal(SIGPIPE, SIG_DFL);
+ }
+ }
+ goto cont;
+ case '|':
+ /*
+ * Pipe message through command.
+ * Collect output as new message.
+ */
+ rewind(collf);
+ mespipe(collf, &linebuf[2]);
+ goto cont;
+ case 'v':
+ case 'e':
+ /*
+ * Edit the current message.
+ * 'e' means to use EDITOR
+ * 'v' means to use VISUAL
+ */
+ rewind(collf);
+ mesedit(collf, c);
+ goto cont;
+ }
+ }
+ goto out;
+err:
+ senderr++; /* set return code */
+ if (collf != NULL) {
+ (void)Fclose(collf);
+ collf = NULL;
+ }
+out:
+ if (collf != NULL)
+ rewind(collf);
+ noreset--;
+ (void)sigprocmask(SIG_BLOCK, &nset, NULL);
+ (void)signal(SIGINT, saveint);
+ (void)signal(SIGHUP, savehup);
+ (void)signal(SIGTSTP, savetstp);
+ (void)signal(SIGTTOU, savettou);
+ (void)signal(SIGTTIN, savettin);
+ (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+ return (collf);
+}
+
+/*
+ * Write a file, ex-like if f set.
+ */
+int
+exwrite(name, fp, f)
+ char name[];
+ FILE *fp;
+ int f;
+{
+ FILE *of;
+ int c, lc;
+ long cc;
+#if 0
+ struct stat junk;
+#endif
+
+ if (f) {
+ printf("\"%s\" ", name);
+ (void)fflush(stdout);
+ }
+#if 0
+ if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) {
+ if (!f)
+ fprintf(stderr, "%s: ", name);
+ fprintf(stderr, "File exists\n");
+ return (-1);
+ }
+#endif
+ if ((of = Fopen(name, "a")) == NULL) {
+ warn((char *)NULL);
+ return (-1);
+ }
+ lc = 0;
+ cc = 0;
+ while ((c = getc(fp)) != EOF) {
+ cc++;
+ if (c == '\n')
+ lc++;
+ (void)putc(c, of);
+ if (ferror(of)) {
+ warnx("%s", name);
+ (void)Fclose(of);
+ return (-1);
+ }
+ }
+ (void)Fclose(of);
+ printf("%d/%ld\n", lc, cc);
+ (void)fflush(stdout);
+ return (0);
+}
+
+/*
+ * Edit the message being collected on fp.
+ * On return, make the edit file the new temp file.
+ */
+void
+mesedit(fp, c)
+ FILE *fp;
+ int c;
+{
+ sig_t sigint = signal(SIGINT, SIG_IGN);
+ FILE *nf = run_editor(fp, (off_t)-1, c, 0);
+
+ if (nf != NULL) {
+ (void)fseeko(nf, (off_t)0, SEEK_END);
+ collf = nf;
+ (void)Fclose(fp);
+ }
+ (void)signal(SIGINT, sigint);
+}
+
+static char *
+parse_pipe_args(str, msglist)
+ char str[];
+ char **msglist;
+{
+ char *cp;
+ char quoted;
+
+ *msglist = NULL;
+ if (str==NULL) return NULL;
+ if (*str=='\0') return NULL;
+
+ cp = strlen(str) + str - 1;
+
+ /*
+ * Strip away trailing blanks.
+ */
+
+ while (cp > str && isspace((unsigned char)*cp))
+ cp--;
+ *++cp = '\0';
+
+ /*
+ * Now search for the beginning of the command.
+ */
+ quoted = 0;
+ if (cp > str) { /* check for quotes */
+ cp--;
+ if (*cp=='"' || *cp=='\'' ) {
+ quoted=*cp;
+ cp--;
+ }
+ }
+
+/*
+printf("before loop: str=%s,cp=%s\n", str,cp);
+*/
+
+ while (cp > str && (!isspace((unsigned char)*cp) || quoted)) {
+ if (quoted) {
+ if (*cp==quoted) {
+ cp--;
+ if (cp>str) {
+ if (!(*cp=='\\' || *cp==quoted)) {
+ quoted=0;
+ continue;
+ }
+ } else /* done */
+ break;
+ }
+ }
+ cp--;
+ }
+ if (cp == str) {
+ return (cp); /* no msglist */
+ }
+
+ *msglist = str;
+ if (isspace((unsigned char)*cp))
+ *cp++ = '\0';
+ else {
+ printf("malformed arguments:%s\n",str);
+ }
+ return (cp);
+}
+
+int
+mailpipe(str)
+ char str[];
+{
+ struct message *mp;
+ int *msgvec, *ip;
+ char *msglist = NULL;
+ char * cmd;
+ char * sh;
+ char cmdline[4096];
+ int do_pagefeed;
+ FILE *fbuf;
+
+ fbuf = stdout;
+
+ /* parse arguments: [[msglist] command] */
+ cmd = parse_pipe_args(str, &msglist);
+/*
+ printf (" pipe args: msglist=%s, cmd=%s\n", msglist, cmd);
+*/
+ /* get message list for reading */
+ msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
+ if (msglist==NULL) {
+ *msgvec = first(0, MMNORM);
+ if (*msgvec == 0) {
+ printf("No messages to %s.\n", cmd);
+ return (1);
+ }
+ msgvec[1] = 0;
+ } else {
+ if (getmsglist(msglist, msgvec, 0) < 0)
+ return (1);
+ }
+ /* if cmd empty get from cmd= variable */
+ if (cmd==NULL) {
+ cmd = value("cmd");
+ if (cmd==NULL || *cmd == '\0') {
+ printf("No command to pipe.\n");
+ return(1);
+ }
+ }
+
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+
+ /* complete cmd, open a pipe to shell */
+ cmdline[0] = '\0';
+ strlcpy(cmdline, sh, sizeof(cmdline));
+ strlcat(cmdline, " -c ", sizeof(cmdline));
+ if (*cmd!='"' && *cmd!='\'') {
+ /* I know this doesn't handle all the cases, but
+ it is enough to make the conformance tests pass */
+ strlcat(cmdline, "\"", sizeof(cmdline));
+ strlcat(cmdline, cmd, sizeof(cmdline));
+ strlcat(cmdline, "\"", sizeof(cmdline));
+ } else {
+ strlcat(cmdline, cmd, sizeof(cmdline));
+ }
+
+/*
+ printf(" popen cmdline:%s\n", cmdline);
+*/
+ if (setjmp(pipejmp))
+ goto close_pipe;
+
+ fbuf = Popen(cmdline, "w");
+ if (fbuf == NULL) {
+ warnx("%s", cmdline);
+ return(1);
+ } else
+ (void)signal(SIGPIPE, brokthepipe);
+
+ /* paginate if page= set */
+ if (value("page") == NULL) {
+ do_pagefeed = 0;
+ } else {
+ do_pagefeed = 1;
+ }
+
+ /* write all messages to the pipe */
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ dot = mp;
+/* printf (" sending message %d\n", ip-msgvec); */
+ if (sendmessage(mp, fbuf, 0, NULL) < 0) {
+ warnx("%s", cmdline);
+ (void)Fclose(fbuf);
+ return (1);
+ }
+ if (do_pagefeed)
+ fprintf(fbuf,"\f"); /* form feed */
+ }
+ (void)fflush(fbuf);
+close_pipe:
+ if (fbuf != stdout) {
+ /*
+ * Ignore SIGPIPE so it can't cause a duplicate close.
+ */
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)Pclose(fbuf);
+ (void)signal(SIGPIPE, SIG_DFL);
+ }
+ return (0);
+}
+
+/*
+ * Pipe the message through the command.
+ * Old message is on stdin of command;
+ * New message collected from stdout.
+ * Sh -c must return 0 to accept the new message.
+ */
+void
+mespipe(fp, cmd)
+ FILE *fp;
+ char cmd[];
+{
+ FILE *nf;
+ int fd;
+ sig_t sigint = signal(SIGINT, SIG_IGN);
+ char *sh, tempname[PATHSIZE];
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.ReXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (nf = Fdopen(fd, "w+")) == NULL) {
+ warn("%s", tempname);
+ goto out;
+ }
+ (void)rm(tempname);
+ /*
+ * stdin = current message.
+ * stdout = new message.
+ */
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ if (run_command(sh,
+ 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) {
+ (void)Fclose(nf);
+ goto out;
+ }
+ if (fsize(nf) == 0) {
+ fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
+ (void)Fclose(nf);
+ goto out;
+ }
+ /*
+ * Take new files.
+ */
+ (void)fseeko(nf, (off_t)0, SEEK_END);
+ collf = nf;
+ (void)Fclose(fp);
+out:
+ (void)signal(SIGINT, sigint);
+}
+
+/*
+ * Interpolate the named messages into the current
+ * message, preceding each line with a tab.
+ * Return a count of the number of characters now in
+ * the message, or -1 if an error is encountered writing
+ * the message temporary. The flag argument is 'm' if we
+ * should shift over and 'f' if not.
+ */
+int
+forward(ms, fp, fn, f)
+ char ms[];
+ FILE *fp;
+ char *fn;
+ int f;
+{
+ int *msgvec;
+ struct ignoretab *ig;
+ char *tabst;
+
+ msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec));
+ if (msgvec == NULL)
+ return (0);
+ if (getmsglist(ms, msgvec, 0) < 0)
+ return (0);
+ if (*msgvec == 0) {
+ *msgvec = first(0, MMNORM);
+ if (*msgvec == 0) {
+ printf("No appropriate messages\n");
+ return (0);
+ }
+ msgvec[1] = 0;
+ }
+ if (f == 'f' || f == 'F')
+ tabst = NULL;
+ else if ((tabst = value("indentprefix")) == NULL)
+ tabst = "\t";
+ ig = isupper((unsigned char)f) ? NULL : ignore;
+ printf("Interpolating:");
+ for (; *msgvec != 0; msgvec++) {
+ struct message *mp = message + *msgvec - 1;
+
+ touch(mp);
+ printf(" %d", *msgvec);
+ if (sendmessage(mp, fp, ig, tabst) < 0) {
+ warnx("%s", fn);
+ return (-1);
+ }
+ }
+ printf("\n");
+ return (0);
+}
+
+/*
+ * Print (continue) when continued after ^Z.
+ */
+/*ARGSUSED*/
+void
+collstop(s)
+ int s;
+{
+ sig_t old_action = signal(s, SIG_DFL);
+ sigset_t nset;
+
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, s);
+ (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+ (void)kill(0, s);
+ (void)sigprocmask(SIG_BLOCK, &nset, NULL);
+ (void)signal(s, old_action);
+ if (colljmp_p) {
+ colljmp_p = 0;
+ hadintr = 0;
+ longjmp(colljmp, 1);
+ }
+}
+
+/*
+ * On interrupt, come here to save the partial message in ~/dead.letter.
+ * Then jump out of the collection loop.
+ */
+/*ARGSUSED*/
+void
+collint(s)
+ int s;
+{
+ /*
+ * the control flow is subtle, because we can be called from ~q.
+ */
+ if (!hadintr) {
+ if (value("ignore") != NULL) {
+ printf("@");
+ (void)fflush(stdout);
+ clearerr(stdin);
+ return;
+ }
+ hadintr = 1;
+ longjmp(colljmp, 1);
+ }
+ rewind(collf);
+ if (value("save") != NULL)
+ savedeadletter(collf);
+ longjmp(collabort, 1);
+}
+
+/*ARGSUSED*/
+void
+collhup(s)
+ int s;
+{
+ rewind(collf);
+ savedeadletter(collf);
+ /*
+ * Let's pretend nobody else wants to clean up,
+ * a true statement at this time.
+ */
+ exit(1);
+}
+
+void
+savedeadletter(fp)
+ FILE *fp;
+{
+ FILE *dbuf;
+ int c;
+ char *cp;
+
+ if (fsize(fp) == 0)
+ return;
+ cp = getdeadletter();
+ c = umask(077);
+ dbuf = Fopen(cp, "w");
+ (void)umask(c);
+ if (dbuf == NULL)
+ return;
+ while ((c = getc(fp)) != EOF)
+ (void)putc(c, dbuf);
+ (void)Fclose(dbuf);
+ rewind(fp);
+}
diff --git a/mail_cmds/mail/def.h b/mail_cmds/mail/def.h
new file mode 100644
index 0000000..3817a5f
--- /dev/null
+++ b/mail_cmds/mail/def.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)def.h 8.4 (Berkeley) 4/20/95
+ *
+ * $FreeBSD: src/usr.bin/mail/def.h,v 1.8 2001/12/18 20:52:09 mikeh Exp $
+ */
+
+/*
+ * Mail -- a mail program
+ *
+ * Author: Kurt Shoens (UCB) March 25, 1978
+ */
+
+#ifndef DEF_H
+#define DEF_H
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+#define APPEND /* New mail goes to end of mailbox */
+
+#define ESCAPE '~' /* Default escape for sending */
+#define NMLSIZE 1024 /* max names in a message list */
+#define PATHSIZE MAXPATHLEN /* Size of pathnames throughout */
+#define HSHSIZE 59 /* Hash size for aliases and vars */
+#define LINESIZE BUFSIZ /* max readable line width */
+#define STRINGSIZE ((unsigned)128) /* Dynamic allocation units */
+#define MAXARGC 1024 /* Maximum list of raw strings */
+#define MAXEXP 25 /* Maximum expansion of aliases */
+
+#define equal(a, b) (strcmp(a,b)==0)/* A nice function to string compare */
+
+struct message {
+ short m_flag; /* flags, see below */
+ short m_offset; /* offset in block of message */
+ long m_block; /* block number of this message */
+ long m_size; /* Bytes in the message */
+ long m_lines; /* Lines in the message */
+};
+
+/*
+ * flag bits.
+ */
+
+#define MUSED (1<<0) /* entry is used, but this bit isn't */
+#define MDELETED (1<<1) /* entry has been deleted */
+#define MSAVED (1<<2) /* entry has been saved */
+#define MTOUCH (1<<3) /* entry has been noticed */
+#define MPRESERVE (1<<4) /* keep entry in sys mailbox */
+#define MMARK (1<<5) /* message is marked! */
+#define MODIFY (1<<6) /* message has been modified */
+#define MNEW (1<<7) /* message has never been seen */
+#define MREAD (1<<8) /* message has been read sometime. */
+#define MSTATUS (1<<9) /* message status has changed */
+#define MBOX (1<<10) /* Send this to mbox, regardless */
+
+/*
+ * Given a file address, determine the block number it represents.
+ */
+#define blockof(off) ((int)((off) / 4096))
+#define boffsetof(off) ((int)((off) % 4096))
+#define positionof(block, offset) ((off_t)(block) * 4096 + (offset))
+
+/*
+ * Format of the command description table.
+ * The actual table is declared and initialized
+ * in lex.c
+ */
+struct cmd {
+ const char *c_name; /* Name of command */
+ int (*c_func)(); /* Implementor of the command */
+ short c_argtype; /* Type of arglist (see below) */
+ short c_msgflag; /* Required flags of messages */
+ short c_msgmask; /* Relevant flags of messages */
+};
+
+/* Yechh, can't initialize unions */
+
+#define c_minargs c_msgflag /* Minimum argcount for RAWLIST */
+#define c_maxargs c_msgmask /* Max argcount for RAWLIST */
+
+/*
+ * Argument types.
+ */
+
+#define MSGLIST 0 /* Message list type */
+#define STRLIST 1 /* A pure string */
+#define RAWLIST 2 /* Shell string list */
+#define NOLIST 3 /* Just plain 0 */
+#define NDMLIST 4 /* Message list, no defaults */
+
+#define P 040 /* Autoprint dot after command */
+#define I 0100 /* Interactive command bit */
+#define M 0200 /* Legal from send mode bit */
+#define W 0400 /* Illegal when read only bit */
+#define F 01000 /* Is a conditional command */
+#define T 02000 /* Is a transparent command */
+#define R 04000 /* Cannot be called from collect */
+
+/*
+ * Oft-used mask values
+ */
+
+#define MMNORM (MDELETED|MSAVED)/* Look at both save and delete bits */
+#define MMNDEL MDELETED /* Look only at deleted bit */
+
+/*
+ * Structure used to return a break down of a head
+ * line (hats off to Bill Joy!)
+ */
+
+struct headline {
+ char *l_from; /* The name of the sender */
+ char *l_tty; /* His tty string (if any) */
+ char *l_date; /* The entire date string */
+};
+
+#define GTO 1 /* Grab To: line */
+#define GSUBJECT 2 /* Likewise, Subject: line */
+#define GCC 4 /* And the Cc: line */
+#define GBCC 8 /* And also the Bcc: line */
+#define GREPLYTO 0x10 /* And the Reply-To: line */
+#define GINREPLYTO 0x20 /* The In-Reply-To: line */
+#define GMASK (GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO)
+ /* Mask of places from whence */
+
+#define GNL 0x40 /* Print blank line after */
+#define GDEL 0x80 /* Entity removed from list */
+#define GCOMMA 0x100 /* detract puts in commas */
+
+/*
+ * Structure used to pass about the current
+ * state of the user-typed message header.
+ */
+
+struct header {
+ struct name *h_bcc; /* Blind carbon copies */
+ struct name *h_cc; /* Carbon copies string */
+ struct name *h_smopts; /* Sendmail options */
+ struct name *h_to; /* Dynamic "To:" string */
+ char *h_inreplyto; /* Reference */
+ char *h_replyto; /* Reply address */
+ char *h_subject; /* Subject string */
+};
+
+/*
+ * Structure of namelist nodes used in processing
+ * the recipients of mail and aliases and all that
+ * kind of stuff.
+ */
+
+struct name {
+ struct name *n_flink; /* Forward link in list. */
+ struct name *n_blink; /* Backward list link */
+ short n_type; /* From which list it came */
+ char *n_name; /* This fella's name */
+};
+
+/*
+ * Structure of a variable node. All variables are
+ * kept on a singly-linked list of these, rooted by
+ * "variables"
+ */
+
+struct var {
+ struct var *v_link; /* Forward link to next variable */
+ char *v_name; /* The variable's name */
+ char *v_value; /* And it's current value */
+};
+
+struct group {
+ struct group *ge_link; /* Next person in this group */
+ char *ge_name; /* This person's user name */
+};
+
+struct grouphead {
+ struct grouphead *g_link; /* Next grouphead in list */
+ char *g_name; /* Name of this group */
+ struct group *g_list; /* Users in group. */
+};
+
+/*
+ * Structure of the hash table of ignored header fields
+ */
+struct ignoretab {
+ int i_count; /* Number of entries */
+ struct ignore {
+ struct ignore *i_link; /* Next ignored field in bucket */
+ char *i_field; /* This ignored field */
+ } *i_head[HSHSIZE];
+};
+
+/*
+ * Token values returned by the scanner used for argument lists.
+ * Also, sizes of scanner-related things.
+ */
+
+#define TEOL 0 /* End of the command line */
+#define TNUMBER 1 /* A message number */
+#define TDASH 2 /* A simple dash */
+#define TSTRING 3 /* A string (possibly containing -) */
+#define TDOT 4 /* A "." */
+#define TUP 5 /* An "^" */
+#define TDOLLAR 6 /* A "$" */
+#define TSTAR 7 /* A "*" */
+#define TOPEN 8 /* An '(' */
+#define TCLOSE 9 /* A ')' */
+#define TPLUS 10 /* A '+' */
+#define TERROR 11 /* A lexical error */
+
+#define REGDEP 2 /* Maximum regret depth. */
+#define STRINGLEN 1024 /* Maximum length of string token */
+
+/*
+ * Constants for conditional commands. These describe whether
+ * we should be executing stuff or not.
+ */
+
+#define CANY 0 /* Execute in send or receive mode */
+#define CRCV 1 /* Execute in receive mode only */
+#define CSEND 2 /* Execute in send mode only */
+
+/*
+ * Kludges to handle the change from setexit / reset to setjmp / longjmp
+ */
+
+#define setexit() setjmp(srbuf)
+#define reset(x) longjmp(srbuf, x)
+
+/*
+ * Truncate a file to the last character written. This is
+ * useful just before closing an old file that was opened
+ * for read/write.
+ */
+#define trunc(stream) { \
+ (void)fflush(stream); \
+ (void)ftruncate(fileno(stream), (off_t)ftell(stream)); \
+}
+
+#endif /* DEF_H */
diff --git a/mail_cmds/mail/edit.c b/mail_cmds/mail/edit.c
new file mode 100644
index 0000000..d49267a
--- /dev/null
+++ b/mail_cmds/mail/edit.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/edit.c,v 1.9 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Perform message editing functions.
+ */
+
+/*
+ * Edit a message list.
+ */
+int
+editor(msgvec)
+ int *msgvec;
+{
+
+ return (edit1(msgvec, 'e'));
+}
+
+/*
+ * Invoke the visual editor on a message list.
+ */
+int
+visual(msgvec)
+ int *msgvec;
+{
+
+ return (edit1(msgvec, 'v'));
+}
+
+/*
+ * Edit a message by writing the message into a funnily-named file
+ * (which should not exist) and forking an editor on it.
+ * We get the editor from the stuff above.
+ */
+int
+edit1(msgvec, type)
+ int *msgvec;
+ int type;
+{
+ int c, i;
+ FILE *fp;
+ struct message *mp;
+ off_t size;
+
+ /*
+ * Deal with each message to be edited . . .
+ */
+ for (i = 0; msgvec[i] && i < msgCount; i++) {
+ sig_t sigint;
+
+ if (i > 0) {
+ char buf[100];
+ char *p;
+
+ printf("Edit message %d [ynq]? ", msgvec[i]);
+ if (fgets(buf, sizeof(buf), stdin) == 0)
+ break;
+ for (p = buf; *p == ' ' || *p == '\t'; p++)
+ ;
+ if (*p == 'q')
+ break;
+ if (*p == 'n')
+ continue;
+ }
+ dot = mp = &message[msgvec[i] - 1];
+ touch(mp);
+ sigint = signal(SIGINT, SIG_IGN);
+ fp = run_editor(setinput(mp), mp->m_size, type, readonly);
+ if (fp != NULL) {
+ (void)fseeko(otf, (off_t)0, SEEK_END);
+ size = ftello(otf);
+ mp->m_block = blockof(size);
+ mp->m_offset = boffsetof(size);
+ mp->m_size = (long)fsize(fp);
+ mp->m_lines = 0;
+ mp->m_flag |= MODIFY;
+ rewind(fp);
+ while ((c = getc(fp)) != EOF) {
+ if (c == '\n')
+ mp->m_lines++;
+ if (putc(c, otf) == EOF)
+ break;
+ }
+ if (ferror(otf))
+ warnx("/tmp");
+ (void)Fclose(fp);
+ }
+ (void)signal(SIGINT, sigint);
+ }
+ return (0);
+}
+
+/*
+ * Run an editor on the file at "fpp" of "size" bytes,
+ * and return a new file pointer.
+ * Signals must be handled by the caller.
+ * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
+ */
+FILE *
+run_editor(fp, size, type, readonly)
+ FILE *fp;
+ off_t size;
+ int type, readonly;
+{
+ FILE *nf = NULL;
+ int t;
+ time_t modtime;
+ char *edit, tempname[PATHSIZE];
+ struct stat statb;
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.ReXXXXXXXXXX", tmpdir);
+ if ((t = mkstemp(tempname)) == -1 ||
+ (nf = Fdopen(t, "w")) == NULL) {
+ warn("%s", tempname);
+ goto out;
+ }
+ if (readonly && fchmod(t, 0400) == -1) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ goto out;
+ }
+ if (size >= 0)
+ while (--size >= 0 && (t = getc(fp)) != EOF)
+ (void)putc(t, nf);
+ else
+ while ((t = getc(fp)) != EOF)
+ (void)putc(t, nf);
+ (void)fflush(nf);
+ if (fstat(fileno(nf), &statb) < 0)
+ modtime = 0;
+ else
+ modtime = statb.st_mtime;
+ if (ferror(nf)) {
+ (void)Fclose(nf);
+ warnx("%s", tempname);
+ (void)rm(tempname);
+ nf = NULL;
+ goto out;
+ }
+ if (Fclose(nf) < 0) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ nf = NULL;
+ goto out;
+ }
+ nf = NULL;
+ if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL)
+ edit = type == 'e' ? _PATH_EX : _PATH_VI;
+ else {
+ if (*edit=='\0')
+ edit = type == 'e' ? _PATH_EX : _PATH_VI;
+ }
+ if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) {
+ (void)rm(tempname);
+ goto out;
+ }
+ /*
+ * If in read only mode or file unchanged, just remove the editor
+ * temporary and return.
+ */
+ if (readonly) {
+ (void)rm(tempname);
+ goto out;
+ }
+ if (stat(tempname, &statb) < 0) {
+ warn("%s", tempname);
+ goto out;
+ }
+ if (modtime == statb.st_mtime) {
+ (void)rm(tempname);
+ goto out;
+ }
+ /*
+ * Now switch to new file.
+ */
+ if ((nf = Fopen(tempname, "a+")) == NULL) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ goto out;
+ }
+ (void)rm(tempname);
+out:
+ return (nf);
+}
diff --git a/mail_cmds/mail/extern.h b/mail_cmds/mail/extern.h
new file mode 100644
index 0000000..239a8cd
--- /dev/null
+++ b/mail_cmds/mail/extern.h
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/20/95
+ *
+ * $FreeBSD: src/usr.bin/mail/extern.h,v 1.9 2004/02/29 20:44:44 mikeh Exp $
+ */
+
+#ifndef EXTERN_H
+#define EXTERN_H
+
+struct name *cat(struct name *, struct name *);
+struct name *delname(struct name *, char []);
+struct name *elide(struct name *);
+struct name *extract(char [], int);
+struct name *gexpand(struct name *, struct grouphead *, int, int);
+struct name *nalloc(char [], int);
+struct name *outof(struct name *, FILE *, struct header *);
+struct name *put(struct name *, struct name *);
+struct name *tailof(struct name *);
+struct name *usermap(struct name *);
+FILE *Fdopen(int, const char *);
+FILE *Fopen(const char *, const char *);
+FILE *Popen(char *, const char *);
+FILE *collect(struct header *, int);
+char *copyin(char *, char **);
+char *detract(struct name *, int);
+char *expand(char *);
+char *getauthor(char *);
+char *getdeadletter(void);
+char *getname(int);
+char *hfield(const char *, struct message *);
+FILE *infix(struct header *, FILE *);
+char *ishfield(char [], char *, const char *);
+char *name1(struct message *, int);
+char *nameof(struct message *, int);
+char *nextword(char *, char *);
+char *readtty(const char *, char []);
+char *reedit(char *);
+FILE *run_editor(FILE *, off_t, int, int);
+char *salloc(int);
+char *savestr(char *);
+FILE *setinput(struct message *);
+char *skin(char *);
+char *skip_comment(char *);
+char *snarf(char [], int *, int);
+char *username(void);
+char *value(const char *);
+char *vcopy(const char *);
+char *yankword(char *, char []);
+char *yanklogin(char *, char []);
+int Fclose(FILE *);
+int More(int *);
+int Pclose(FILE *);
+int Respond(int *);
+int Type(int *);
+int doRespond(int []);
+int dorespond(int *);
+void alter(char *);
+int alternates(char **);
+void announce(void);
+int append(struct message *, FILE *);
+int argcount(char **);
+void assign(const char *, const char *);
+int bangexp(char *, size_t);
+void brokpipe(int);
+int charcount(char *, int);
+int check(int, int);
+void clob1(int);
+int clobber(char **);
+void close_all_files(void);
+int cmatch(char *, char *);
+void collhup(int);
+void collint(int);
+void collstop(int);
+void commands(void);
+int copycmd(char []);
+int Capcopycmd(char []);
+int core(void);
+int count(struct name *);
+int delete(int []);
+int delm(int []);
+int deltype(int []);
+void demail(void);
+int diction(const void *, const void *);
+int dosh(char *);
+int echo(char **);
+int edit1(int *, int);
+int editor(int *);
+void edstop(void);
+int elsecmd(void);
+int endifcmd(void);
+int evalcol(int);
+int execute(char [], int);
+int exwrite(char [], FILE *, int);
+void fail(const char *, const char *);
+int file(char **);
+struct grouphead *
+ findgroup(char []);
+void findmail(char *, char *, int);
+int first(int, int);
+void fixhead(struct header *, struct name *);
+void fmt(const char *, struct name *, FILE *, int);
+int folders(void);
+int followup(int *);
+int Capfollowup(int *);
+int forward(char [], FILE *, char *, int);
+void free_child(int);
+int from(int *);
+off_t fsize(FILE *);
+int getfold(char *, int);
+int gethfield(FILE *, char [], int, char **);
+int getmsglist(char *, int *, int);
+int getrawlist(char [], char **, int);
+int getuserid(char []);
+int grabh(struct header *, int);
+int group(char **);
+void hangup(int);
+int hash(const char *);
+void hdrstop(int);
+int headers(int *);
+int help(void);
+void holdsigs(void);
+int ifcmd(char **);
+int igcomp(const void *, const void *);
+int igfield(char *[]);
+int ignore1(char *[], struct ignoretab *, const char *);
+int igshow(struct ignoretab *, const char *);
+int inc(void *);
+int incfile(void);
+void intr(int);
+int isdate(char []);
+int isdir(char []);
+int isfileaddr(char *);
+int ishead(char []);
+int isign(const char *, struct ignoretab []);
+int isprefix(const char *, const char *);
+void istrncpy(char *, const char *, size_t);
+__const struct cmd *
+ lex(char []);
+void load(char *);
+struct var *
+ lookup(const char *);
+int mail(struct name *,
+ struct name *, struct name *, struct name *, char *, char *);
+void mail1(struct header *, int);
+int mailpipe(char []);
+void makemessage(FILE *, int);
+void mark(int);
+int markall(char [], int);
+int matchsender(char *, int);
+int matchfield(char *, int);
+int mboxit(int []);
+int member(char *, struct ignoretab *);
+void mesedit(FILE *, int);
+void mespipe(FILE *, char []);
+int messize(int *);
+int metamess(int, int);
+int more(int *);
+int newfileinfo(int);
+int next(int *);
+int null(int);
+void parse(char [], struct headline *, char []);
+int pcmdlist(void);
+int pdot(void);
+void prepare_child(sigset_t *, int, int);
+int preserve(int *);
+void prettyprint(struct name *);
+void printgroup(char []);
+void printhead(int);
+int puthead(struct header *, FILE *, int);
+int putline(FILE *, char *, int);
+int pversion(int);
+void quit(void);
+int quitcmd(void);
+int readline(FILE *, char *, int);
+void register_file(FILE *, int, int);
+void regret(int);
+void relsesigs(void);
+int respond(int *);
+int retfield(char *[]);
+int rexit(int);
+int rm(char *);
+int run_command(char *, sigset_t *, int, int, char *, char *, char *);
+int save(char []);
+int Capsave(char []);
+int save1(char [], int, const char *, struct ignoretab *);
+void savedeadletter(FILE *);
+int saveigfield(char *[]);
+int savemail(char [], FILE *);
+int saveretfield(char *[]);
+int scan(char **);
+void scaninit(void);
+int schdir(char **);
+int screensize(void);
+int scroll(char []);
+int sendmessage(struct message *, FILE *, struct ignoretab *, char *);
+int sendmail(char *);
+int set(char **);
+int setfile(char *);
+void setmsize(int);
+void setptr(FILE *, off_t);
+void setscreensize(void);
+int shell(char *);
+void sigchild(int);
+void sort(char **);
+int source(char **);
+void spreserve(void);
+void sreset(void);
+int start_command(char *, sigset_t *, int, int, char *, char *, char *);
+void statusput(struct message *, FILE *, char *);
+void stop(int);
+int stouch(int []);
+int swrite(char []);
+void tinit(void);
+int top(int *);
+void touch(struct message *);
+void ttyint(int);
+void ttystop(int);
+int type(int *);
+int type1(int *, int, int);
+int undelete_messages(int *);
+void unmark(int);
+char **unpack(struct name *);
+int unread(int []);
+void unregister_file(FILE *);
+int unset(char **);
+int unstack(void);
+void v_free(char *);
+int visual(int *);
+int wait_child(int);
+int wait_command(int);
+int writeback(FILE *);
+
+extern char *__progname;
+extern char *tmpdir;
+
+#endif /* EXTERN_H */
+
diff --git a/mail_cmds/mail/fio.c b/mail_cmds/mail/fio.c
new file mode 100644
index 0000000..6f59372
--- /dev/null
+++ b/mail_cmds/mail/fio.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)fio.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/fio.c,v 1.12 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <sys/file.h>
+#include <sys/wait.h>
+
+#include <unistd.h>
+#include <paths.h>
+#include <errno.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * File I/O.
+ */
+
+extern int wait_status;
+
+/*
+ * Set up the input pointers while copying the mail file into /tmp.
+ */
+void
+setptr(ibuf, offset)
+ FILE *ibuf;
+ off_t offset;
+{
+ int c, count;
+ char *cp, *cp2;
+ struct message this;
+ FILE *mestmp;
+ int maybe, inhead;
+ char linebuf[LINESIZE], pathbuf[PATHSIZE];
+ int omsgCount;
+
+ /* Get temporary file. */
+ (void)snprintf(pathbuf, sizeof(pathbuf), "%s/mail.XXXXXXXXXX", tmpdir);
+ if ((c = mkstemp(pathbuf)) == -1 || (mestmp = Fdopen(c, "r+")) == NULL)
+ err(1, "can't open %s", pathbuf);
+ (void)rm(pathbuf);
+
+ if (offset == 0) {
+ msgCount = 0;
+ } else {
+ /* Seek into the file to get to the new messages */
+ (void)fseeko(ibuf, offset, SEEK_SET);
+ /*
+ * We need to make "offset" a pointer to the end of
+ * the temp file that has the copy of the mail file.
+ * If any messages have been edited, this will be
+ * different from the offset into the mail file.
+ */
+ (void)fseeko(otf, (off_t)0, SEEK_END);
+ offset = ftello(otf);
+ }
+ omsgCount = msgCount;
+ maybe = 1;
+ inhead = 0;
+ this.m_flag = MUSED|MNEW;
+ this.m_size = 0;
+ this.m_lines = 0;
+ this.m_block = 0;
+ this.m_offset = 0;
+ for (;;) {
+ if (fgets(linebuf, sizeof(linebuf), ibuf) == NULL) {
+ if (append(&this, mestmp))
+ errx(1, "temporary file");
+ makemessage(mestmp, omsgCount);
+ return;
+ }
+ count = strlen(linebuf);
+ /*
+ * Transforms lines ending in <CR><LF> to just <LF>.
+ * This allows mail to be able to read Eudora mailboxes.
+ */
+ if (count >= 2 && linebuf[count - 1] == '\n' &&
+ linebuf[count - 2] == '\r') {
+ count--;
+ linebuf[count - 1] = '\n';
+ }
+
+ (void)fwrite(linebuf, sizeof(*linebuf), count, otf);
+ if (ferror(otf))
+ errx(1, "/tmp");
+ if (count)
+ linebuf[count - 1] = '\0';
+ if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
+ msgCount++;
+ if (append(&this, mestmp))
+ errx(1, "temporary file");
+ this.m_flag = MUSED|MNEW;
+ this.m_size = 0;
+ this.m_lines = 0;
+ this.m_block = blockof(offset);
+ this.m_offset = boffsetof(offset);
+ inhead = 1;
+ } else if (linebuf[0] == 0) {
+ inhead = 0;
+ } else if (inhead) {
+ for (cp = linebuf, cp2 = "status";; cp++) {
+ if ((c = *cp2++) == '\0') {
+ while (isspace((unsigned char)*cp++))
+ ;
+ if (cp[-1] != ':')
+ break;
+ while ((c = *cp++) != '\0')
+ if (c == 'R')
+ this.m_flag |= MREAD;
+ else if (c == 'O')
+ this.m_flag &= ~MNEW;
+ inhead = 0;
+ break;
+ }
+ if (*cp != c && *cp != toupper((unsigned char)c))
+ break;
+ }
+ }
+ offset += count;
+ this.m_size += count;
+ this.m_lines++;
+ maybe = linebuf[0] == 0;
+ }
+}
+
+/*
+ * Drop the passed line onto the passed output buffer.
+ * If a write error occurs, return -1, else the count of
+ * characters written, including the newline if requested.
+ */
+int
+putline(obuf, linebuf, outlf)
+ FILE *obuf;
+ char *linebuf;
+ int outlf;
+{
+ int c;
+
+ c = strlen(linebuf);
+ (void)fwrite(linebuf, sizeof(*linebuf), c, obuf);
+ if (outlf) {
+ fprintf(obuf, "\n");
+ c++;
+ }
+ if (ferror(obuf))
+ return (-1);
+ return (c);
+}
+
+/*
+ * Read up a line from the specified input into the line
+ * buffer. Return the number of characters read. Do not
+ * include the newline (or carriage return) at the end.
+ */
+int
+readline(ibuf, linebuf, linesize)
+ FILE *ibuf;
+ char *linebuf;
+ int linesize;
+{
+ int n;
+
+ clearerr(ibuf);
+ if (fgets(linebuf, linesize, ibuf) == NULL)
+ return (-1);
+ n = strlen(linebuf);
+ if (n > 0 && linebuf[n - 1] == '\n')
+ linebuf[--n] = '\0';
+ if (n > 0 && linebuf[n - 1] == '\r')
+ linebuf[--n] = '\0';
+ return (n);
+}
+
+/*
+ * Return a file buffer all ready to read up the
+ * passed message pointer.
+ */
+FILE *
+setinput(mp)
+ struct message *mp;
+{
+
+ (void)fflush(otf);
+ if (fseeko(itf,
+ positionof(mp->m_block, mp->m_offset), SEEK_SET) < 0)
+ err(1, "fseeko");
+ return (itf);
+}
+
+/*
+ * Take the data out of the passed ghost file and toss it into
+ * a dynamically allocated message structure.
+ */
+void
+makemessage(f, omsgCount)
+ FILE *f;
+ int omsgCount;
+{
+ size_t size;
+ struct message *nmessage;
+
+ size = (msgCount + 1) * sizeof(struct message);
+ nmessage = (struct message *)realloc(message, size);
+ if (nmessage == NULL)
+ errx(1, "Insufficient memory for %d messages\n",
+ msgCount);
+ if (omsgCount == 0 || message == NULL)
+ dot = nmessage;
+ else
+ dot = nmessage + (dot - message);
+ message = nmessage;
+ size -= (omsgCount + 1) * sizeof(struct message);
+ (void)fflush(f);
+ (void)lseek(fileno(f), (off_t)sizeof(*message), 0);
+ if (read(fileno(f), (char *)&message[omsgCount], size) != size)
+ errx(1, "Message temporary file corrupted");
+ message[msgCount].m_size = 0;
+ message[msgCount].m_lines = 0;
+ (void)Fclose(f);
+}
+
+/*
+ * Append the passed message descriptor onto the temp file.
+ * If the write fails, return 1, else 0
+ */
+int
+append(mp, f)
+ struct message *mp;
+ FILE *f;
+{
+ return (fwrite((char *)mp, sizeof(*mp), 1, f) != 1);
+}
+
+/*
+ * Delete a file, but only if the file is a plain file.
+ */
+int
+rm(name)
+ char *name;
+{
+ struct stat sb;
+
+ if (stat(name, &sb) < 0)
+ return (-1);
+ if (!S_ISREG(sb.st_mode)) {
+ errno = EISDIR;
+ return (-1);
+ }
+ return (unlink(name));
+}
+
+static int sigdepth; /* depth of holdsigs() */
+static sigset_t nset, oset;
+/*
+ * Hold signals SIGHUP, SIGINT, and SIGQUIT.
+ */
+void
+holdsigs()
+{
+
+ if (sigdepth++ == 0) {
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGHUP);
+ (void)sigaddset(&nset, SIGINT);
+ (void)sigaddset(&nset, SIGQUIT);
+ (void)sigprocmask(SIG_BLOCK, &nset, &oset);
+ }
+}
+
+/*
+ * Release signals SIGHUP, SIGINT, and SIGQUIT.
+ */
+void
+relsesigs()
+{
+
+ if (--sigdepth == 0)
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
+/*
+ * Determine the size of the file possessed by
+ * the passed buffer.
+ */
+off_t
+fsize(iob)
+ FILE *iob;
+{
+ struct stat sbuf;
+
+ if (fstat(fileno(iob), &sbuf) < 0)
+ return (0);
+ return (sbuf.st_size);
+}
+
+/*
+ * Evaluate the string given as a new mailbox name.
+ * Supported meta characters:
+ * % for my system mail box
+ * %user for user's system mail box
+ * # for previous file
+ * & invoker's mbox file
+ * +file file in folder directory
+ * any shell meta character
+ * Return the file name as a dynamic string.
+ */
+char *
+expand(name)
+ char *name;
+{
+ char xname[PATHSIZE];
+ char cmdbuf[PATHSIZE]; /* also used for file names */
+ int pid, l;
+ char *cp, *sh;
+ int pivec[2];
+ struct stat sbuf;
+
+ /*
+ * The order of evaluation is "%" and "#" expand into constants.
+ * "&" can expand into "+". "+" can expand into shell meta characters.
+ * Shell meta characters expand into constants.
+ * This way, we make no recursive expansion.
+ */
+ switch (*name) {
+ case '%':
+ findmail(name[1] ? name + 1 : myname, xname, sizeof(xname));
+ return (savestr(xname));
+ case '#':
+ if (name[1] != 0)
+ break;
+ if (prevfile[0] == 0) {
+ printf("No previous file\n");
+ return (NULL);
+ }
+ return (savestr(prevfile));
+ case '&':
+ if (name[1] == 0 && (name = value("MBOX")) == NULL)
+ name = "~/mbox";
+ /* fall through */
+ }
+ if (name[0] == '+' && getfold(cmdbuf, sizeof(cmdbuf)) >= 0) {
+ (void)snprintf(xname, sizeof(xname), "%s/%s", cmdbuf, name + 1);
+ name = savestr(xname);
+ }
+ /* catch the most common shell meta character */
+ if (name[0] == '~' && homedir != NULL &&
+ (name[1] == '/' || name[1] == '\0')) {
+ (void)snprintf(xname, sizeof(xname), "%s%s", homedir, name + 1);
+ name = savestr(xname);
+ }
+ if (!strpbrk(name, "~{[*?$`'\"\\"))
+ return (name);
+ if (pipe(pivec) < 0) {
+ warn("pipe");
+ return (name);
+ }
+ (void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ pid = start_command(sh, 0, -1, pivec[1], "-c", cmdbuf, NULL);
+ if (pid < 0) {
+ (void)close(pivec[0]);
+ (void)close(pivec[1]);
+ return (NULL);
+ }
+ (void)close(pivec[1]);
+ l = read(pivec[0], xname, BUFSIZ);
+ (void)close(pivec[0]);
+ if (wait_child(pid) < 0 && WIFSIGNALED(wait_status) &&
+ WTERMSIG(wait_status) != SIGPIPE) {
+ fprintf(stderr, "\"%s\": Expansion failed.\n", name);
+ return (NULL);
+ }
+ if (l < 0) {
+ warn("read");
+ return (NULL);
+ }
+ if (l == 0) {
+ fprintf(stderr, "\"%s\": No match.\n", name);
+ return (NULL);
+ }
+ if (l == BUFSIZ) {
+ fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name);
+ return (NULL);
+ }
+ xname[l] = '\0';
+ for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
+ ;
+ cp[1] = '\0';
+ if (strchr(xname, ' ') && stat(xname, &sbuf) < 0) {
+ fprintf(stderr, "\"%s\": Ambiguous.\n", name);
+ return (NULL);
+ }
+ return (savestr(xname));
+}
+
+/*
+ * Determine the current folder directory name.
+ */
+int
+getfold(name, namelen)
+ char *name;
+ int namelen;
+{
+ char *folder;
+ int copylen;
+
+ if ((folder = value("folder")) == NULL)
+ return (-1);
+ if (*folder == '/')
+ copylen = strlcpy(name, folder, namelen);
+ else
+ copylen = snprintf(name, namelen, "%s/%s",
+ homedir ? homedir : ".", folder);
+ return (copylen < 0 || copylen >= namelen ? (-1) : (0));
+}
+
+/*
+ * Return the name of the dead.letter file.
+ */
+char *
+getdeadletter()
+{
+ char *cp;
+
+ if ((cp = value("DEAD")) == NULL || (cp = expand(cp)) == NULL)
+ cp = expand("~/dead.letter");
+ else if (*cp != '/') {
+ char buf[PATHSIZE];
+
+ (void)snprintf(buf, sizeof(buf), "~/%s", cp);
+ cp = expand(buf);
+ }
+ return (cp);
+}
diff --git a/mail_cmds/mail/getname.c b/mail_cmds/mail/getname.c
new file mode 100644
index 0000000..f8e2231
--- /dev/null
+++ b/mail_cmds/mail/getname.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)getname.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/getname.c,v 1.4 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <pwd.h>
+#include "extern.h"
+
+/* Getname / getuserid for those with hashed passwd data base). */
+
+/*
+ * Search the passwd file for a uid. Return name on success, NULL on failure.
+ */
+char *
+getname(uid)
+ int uid;
+{
+ struct passwd *pw;
+
+ if ((pw = getpwuid(uid)) == NULL)
+ return (NULL);
+ return (pw->pw_name);
+}
+
+/*
+ * Convert the passed name to a user id and return it. Return -1
+ * on error.
+ */
+int
+getuserid(name)
+ char name[];
+{
+ struct passwd *pw;
+
+ if ((pw = getpwnam(name)) == NULL)
+ return (-1);
+ return (pw->pw_uid);
+}
diff --git a/mail_cmds/mail/glob.h b/mail_cmds/mail/glob.h
new file mode 100644
index 0000000..dfbc55f
--- /dev/null
+++ b/mail_cmds/mail/glob.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)glob.h 8.1 (Berkeley) 6/6/93
+ *
+ * $FreeBSD: src/usr.bin/mail/glob.h,v 1.2 2001/03/25 04:57:04 mikeh Exp $
+ */
+
+#ifndef GLOB_H
+#define GLOB_H
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+/*
+ * A bunch of global variable declarations lie herein.
+ * def.h must be included first.
+ */
+
+EXTERN int msgCount; /* Count of messages read in */
+EXTERN int rcvmode; /* True if receiving mail */
+EXTERN int sawcom; /* Set after first command */
+EXTERN char *Tflag; /* -T temp file for netnews */
+EXTERN int senderr; /* An error while checking */
+EXTERN int edit; /* Indicates editing a file */
+EXTERN int readonly; /* Will be unable to rewrite file */
+EXTERN int noreset; /* String resets suspended */
+EXTERN int sourcing; /* Currently reading variant file */
+EXTERN int loading; /* Loading user definitions */
+EXTERN int cond; /* Current state of conditional exc. */
+EXTERN FILE *itf; /* Input temp file buffer */
+EXTERN FILE *otf; /* Output temp file buffer */
+EXTERN int image; /* File descriptor for image of msg */
+EXTERN FILE *input; /* Current command input file */
+EXTERN char mailname[PATHSIZE]; /* Name of current file */
+EXTERN char prevfile[PATHSIZE]; /* Name of previous file */
+EXTERN char *homedir; /* Path name of home directory */
+EXTERN char *myname; /* My login name */
+EXTERN off_t mailsize; /* Size of system mailbox */
+EXTERN int lexnumber; /* Number of TNUMBER from scan() */
+EXTERN char lexstring[STRINGLEN]; /* String from TSTRING, scan() */
+EXTERN int regretp; /* Pointer to TOS of regret tokens */
+EXTERN int regretstack[REGDEP]; /* Stack of regretted tokens */
+EXTERN char *string_stack[REGDEP]; /* Stack of regretted strings */
+EXTERN int numberstack[REGDEP]; /* Stack of regretted numbers */
+EXTERN struct message *dot; /* Pointer to current message */
+EXTERN struct message *message; /* The actual message structure */
+EXTERN struct var *variables[HSHSIZE]; /* Pointer to active var list */
+EXTERN struct grouphead *groups[HSHSIZE];/* Pointer to active groups */
+EXTERN struct ignoretab ignore[2]; /* ignored and retained fields
+ 0 is ignore, 1 is retain */
+EXTERN struct ignoretab saveignore[2]; /* ignored and retained fields
+ on save to folder */
+EXTERN struct ignoretab ignoreall[2]; /* special, ignore all headers */
+EXTERN char **altnames; /* List of alternate names for user */
+EXTERN int debug; /* Debug flag set */
+EXTERN int screenwidth; /* Screen width, or best guess */
+EXTERN int screenheight; /* Screen height, or best guess,
+ for "header" command */
+EXTERN int realscreenheight; /* the real screen height */
+
+#include <setjmp.h>
+
+EXTERN jmp_buf srbuf;
+
+
+/*
+ * The pointers for the string allocation routines,
+ * there are NSPACE independent areas.
+ * The first holds STRINGSIZE bytes, the next
+ * twice as much, and so on.
+ */
+
+#define NSPACE 25 /* Total number of string spaces */
+EXTERN struct strings {
+ char *s_topFree; /* Beginning of this area */
+ char *s_nextFree; /* Next alloctable place here */
+ unsigned s_nleft; /* Number of bytes left here */
+} stringdope[NSPACE];
+
+#endif /* GLOB_H */
+
diff --git a/mail_cmds/mail/head.c b/mail_cmds/mail/head.c
new file mode 100644
index 0000000..d747cb0
--- /dev/null
+++ b/mail_cmds/mail/head.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/head.c,v 1.8 2003/01/09 05:08:37 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Routines for processing and detecting headlines.
+ */
+
+/*
+ * See if the passed line buffer is a mail header.
+ * Return true if yes. Note the extreme pains to
+ * accomodate all funny formats.
+ */
+int
+ishead(linebuf)
+ char linebuf[];
+{
+ struct headline hl;
+ char parbuf[BUFSIZ];
+
+ if (strncmp(linebuf, "From ", 5) != 0)
+ return (0);
+ parse(linebuf, &hl, parbuf);
+ if (hl.l_date == NULL) {
+ fail(linebuf, "No date field");
+ return (0);
+ }
+ if (!isdate(hl.l_date)) {
+ fail(linebuf, "Date field not legal date");
+ return (0);
+ }
+ /*
+ * I guess we got it!
+ */
+ return (1);
+}
+
+/*ARGSUSED*/
+void
+fail(linebuf, reason)
+ const char *linebuf, *reason;
+{
+
+ /*
+ if (value("debug") == NULL)
+ return;
+ fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
+ */
+}
+
+/*
+ * Split a headline into its useful components.
+ * Copy the line into dynamic string space, then set
+ * pointers into the copied line in the passed headline
+ * structure. Actually, it scans.
+ */
+void
+parse(line, hl, pbuf)
+ char line[], pbuf[];
+ struct headline *hl;
+{
+ char *cp, *sp;
+ char word[LINESIZE];
+
+ hl->l_from = NULL;
+ hl->l_tty = NULL;
+ hl->l_date = NULL;
+ cp = line;
+ sp = pbuf;
+ /*
+ * Skip over "From" first.
+ */
+ cp = nextword(cp, word);
+ /*
+ * Check for missing return-path.
+ */
+ if (isdate(cp)) {
+ hl->l_date = copyin(cp, &sp);
+ return;
+ }
+ cp = nextword(cp, word);
+ if (strlen(word) > 0)
+ hl->l_from = copyin(word, &sp);
+ if (cp != NULL && strncmp(cp, "tty", 3) == 0) {
+ cp = nextword(cp, word);
+ hl->l_tty = copyin(word, &sp);
+ }
+ if (cp != NULL)
+ hl->l_date = copyin(cp, &sp);
+}
+
+/*
+ * Copy the string on the left into the string on the right
+ * and bump the right (reference) string pointer by the length.
+ * Thus, dynamically allocate space in the right string, copying
+ * the left string into it.
+ */
+char *
+copyin(src, space)
+ char *src;
+ char **space;
+{
+ char *cp, *top;
+
+ top = cp = *space;
+ while ((*cp++ = *src++) != '\0')
+ ;
+ *space = cp;
+ return (top);
+}
+
+/*
+ * Test to see if the passed string is a ctime(3) generated
+ * date string as documented in the manual. The template
+ * below is used as the criterion of correctness.
+ * Also, we check for a possible trailing time zone using
+ * the tmztype template.
+ *
+ * If the mail file is created by Sys V (Solaris), there are
+ * no seconds in the time. If the mail is created by another
+ * program such as imapd, it might have timezone as
+ * <-|+>nnnn (-0800 for instance) at the end.
+ */
+
+/*
+ * 'A' An upper case char
+ * 'a' A lower case char
+ * ' ' A space
+ * '0' A digit
+ * 'O' A digit or space
+ * 'p' A punctuation char
+ * 'P' A punctuation char or space
+ * ':' A colon
+ * 'N' A new line
+ */
+
+static char *date_formats[] = {
+ "Aaa Aaa O0 00:00:00 0000", /* Mon Jan 01 23:59:59 2001 */
+ "Aaa Aaa O0 00:00:00 AAA 0000", /* Mon Jan 01 23:59:59 PST 2001 */
+ "Aaa Aaa O0 00:00:00 0000 p0000", /* Mon Jan 01 23:59:59 2001 -0800 */
+ "Aaa Aaa O0 00:00 0000", /* Mon Jan 01 23:59 2001 */
+ "Aaa Aaa O0 00:00 AAA 0000", /* Mon Jan 01 23:59 PST 2001 */
+ "Aaa Aaa O0 00:00 0000 p0000", /* Mon Jan 01 23:59 2001 -0800 */
+ NULL
+};
+
+int
+isdate(date)
+ char date[];
+{
+ int i;
+
+ for(i = 0; date_formats[i] != NULL; i++) {
+ if (cmatch(date, date_formats[i]))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Match the given string (cp) against the given template (tp).
+ * Return 1 if they match, 0 if they don't
+ */
+int
+cmatch(cp, tp)
+ char *cp, *tp;
+{
+
+ while (*cp != '\0' && *tp != '\0')
+ switch (*tp++) {
+ case 'a':
+ if (!islower((unsigned char)*cp++))
+ return (0);
+ break;
+ case 'A':
+ if (!isupper((unsigned char)*cp++))
+ return (0);
+ break;
+ case ' ':
+ if (*cp++ != ' ')
+ return (0);
+ break;
+ case '0':
+ if (!isdigit((unsigned char)*cp++))
+ return (0);
+ break;
+ case 'O':
+ if (*cp != ' ' && !isdigit((unsigned char)*cp))
+ return (0);
+ cp++;
+ break;
+ case 'p':
+ if (!ispunct((unsigned char)*cp++))
+ return (0);
+ break;
+ case 'P':
+ if (*cp != ' ' && !ispunct((unsigned char)*cp))
+ return (0);
+ cp++;
+ break;
+ case ':':
+ if (*cp++ != ':')
+ return (0);
+ break;
+ case 'N':
+ if (*cp++ != '\n')
+ return (0);
+ break;
+ }
+ if (*cp != '\0' || *tp != '\0')
+ return (0);
+ return (1);
+}
+
+/*
+ * Collect a liberal (space, tab delimited) word into the word buffer
+ * passed. Also, return a pointer to the next word following that,
+ * or NULL if none follow.
+ */
+char *
+nextword(wp, wbuf)
+ char *wp, *wbuf;
+{
+ int c;
+
+ if (wp == NULL) {
+ *wbuf = '\0';
+ return (NULL);
+ }
+ while ((c = *wp++) != '\0' && c != ' ' && c != '\t') {
+ *wbuf++ = c;
+ if (c == '"') {
+ while ((c = *wp++) != '\0' && c != '"')
+ *wbuf++ = c;
+ if (c == '"')
+ *wbuf++ = c;
+ else
+ wp--;
+ }
+ }
+ *wbuf = '\0';
+ for (; c == ' ' || c == '\t'; c = *wp++)
+ ;
+ if (c == '\0')
+ return (NULL);
+ return (wp - 1);
+}
diff --git a/mail_cmds/mail/lex.c b/mail_cmds/mail/lex.c
new file mode 100644
index 0000000..9296b31
--- /dev/null
+++ b/mail_cmds/mail/lex.c
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lex.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/lex.c,v 1.16 2004/03/06 13:27:59 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <errno.h>
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Lexical processing of commands.
+ */
+
+const char *prompt = "? "; /* Unix standard prompt */
+
+extern const struct cmd cmdtab[];
+extern const char *version;
+
+/*
+ * Set up editing on the given file name.
+ * If the first character of name is %, we are considered to be
+ * editing the file, otherwise we are reading our mail which has
+ * signficance for mbox and so forth.
+ *
+ * If the -e option is being passed to mail, this function has a
+ * tri-state return code: -1 on error, 0 on no mail, 1 if there is
+ * mail.
+ */
+int
+setfile(name)
+ char *name;
+{
+ FILE *ibuf;
+ int checkmode, i, fd;
+ struct stat stb;
+ char isedit = *name != '%' || getuserid(myname) != getuid();
+ char *who = name[1] ? name + 1 : myname;
+ char tempname[PATHSIZE];
+ static int shudclob;
+
+ checkmode = value("checkmode") != NULL;
+ if ((name = expand(name)) == NULL)
+ return (-1);
+
+ if ((ibuf = Fopen(name, "r")) == NULL) {
+ if (!isedit && errno == ENOENT)
+ goto nomail;
+ warn("%s", name);
+ return (-1);
+ }
+
+ if (fstat(fileno(ibuf), &stb) < 0) {
+ warn("fstat");
+ (void)Fclose(ibuf);
+ return (-1);
+ }
+
+ if (S_ISDIR(stb.st_mode) || !S_ISREG(stb.st_mode)) {
+ (void)Fclose(ibuf);
+ errno = S_ISDIR(stb.st_mode) ? EISDIR : EINVAL;
+ warn("%s", name);
+ return (-1);
+ }
+
+ /*
+ * Looks like all will be well. We must now relinquish our
+ * hold on the current set of stuff. Must hold signals
+ * while we are reading the new file, else we will ruin
+ * the message[] data structure.
+ */
+
+ holdsigs();
+ if (shudclob)
+ quit();
+
+ /*
+ * Copy the messages into /tmp
+ * and set pointers.
+ */
+
+ readonly = 0;
+ if ((i = open(name, 1)) < 0)
+ readonly++;
+ else
+ (void)close(i);
+ if (shudclob) {
+ (void)fclose(itf);
+ (void)fclose(otf);
+ }
+ shudclob = 1;
+ edit = isedit;
+ strlcpy(prevfile, mailname, sizeof(prevfile));
+ if (name != mailname)
+ strlcpy(mailname, name, sizeof(mailname));
+ mailsize = fsize(ibuf);
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RxXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 || (otf = fdopen(fd, "w")) == NULL)
+ err(1, "%s", tempname);
+ (void)fcntl(fileno(otf), F_SETFD, 1);
+ if ((itf = fopen(tempname, "r")) == NULL)
+ err(1, "%s", tempname);
+ (void)fcntl(fileno(itf), F_SETFD, 1);
+ (void)rm(tempname);
+ setptr(ibuf, 0);
+ setmsize(msgCount);
+ /*
+ * New mail may have arrived while we were reading
+ * the mail file, so reset mailsize to be where
+ * we really are in the file...
+ */
+ mailsize = ftello(ibuf);
+ (void)Fclose(ibuf);
+ relsesigs();
+ sawcom = 0;
+
+ if ((checkmode || !edit) && msgCount == 0) {
+nomail:
+ if (!checkmode) {
+ fprintf(stderr, "No mail for %s\n", who);
+ return (-1);
+ } else
+ return (0);
+ }
+ return (checkmode ? 1 : 0);
+}
+
+/*
+ * Incorporate any new mail that has arrived since we first
+ * started reading mail.
+ */
+int
+incfile()
+{
+ off_t newsize;
+ int omsgCount = msgCount;
+ FILE *ibuf;
+
+ ibuf = Fopen(mailname, "r");
+ if (ibuf == NULL)
+ return (-1);
+ holdsigs();
+ newsize = fsize(ibuf);
+ if (newsize == 0)
+ return (-1); /* mail box is now empty??? */
+ if (newsize < mailsize)
+ return (-1); /* mail box has shrunk??? */
+ if (newsize == mailsize)
+ return (0); /* no new mail */
+ setptr(ibuf, mailsize);
+ setmsize(msgCount);
+ mailsize = ftello(ibuf);
+ (void)Fclose(ibuf);
+ relsesigs();
+ return (msgCount - omsgCount);
+}
+
+int *msgvec;
+int reset_on_stop; /* do a reset() if stopped */
+
+/*
+ * Interpret user commands one by one. If standard input is not a tty,
+ * print no prompt.
+ */
+void
+commands()
+{
+ int n, eofloop = 0;
+ char linebuf[PATHSIZE+LINESIZE]; /* make very large to handle maximum pathname in commands */
+
+ if (!sourcing) {
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ (void)signal(SIGINT, intr);
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ (void)signal(SIGHUP, hangup);
+ (void)signal(SIGTSTP, stop);
+ (void)signal(SIGTTOU, stop);
+ (void)signal(SIGTTIN, stop);
+ }
+ setexit();
+ for (;;) {
+ /*
+ * Print the prompt, if needed. Clear out
+ * string space, and flush the output.
+ */
+ if (!sourcing && value("interactive") != NULL) {
+ char * current_prompt;
+ if ((value("autoinc") != NULL) && (incfile() > 0))
+ printf("New mail has arrived.\n");
+ reset_on_stop = 1;
+ if ((current_prompt = value("prompt")) != NULL) {
+ printf("%s", current_prompt);
+ }
+ }
+ (void)fflush(stdout);
+ sreset();
+ /*
+ * Read a line of commands from the current input
+ * and handle end of file specially.
+ */
+ n = 0;
+ for (;;) {
+ if (readline(input, &linebuf[n], sizeof(linebuf) - n) < 0) {
+ if (n == 0)
+ n = -1;
+ break;
+ }
+ if ((n = strlen(linebuf)) == 0)
+ break;
+ n--;
+ if (linebuf[n] != '\\')
+ break;
+ linebuf[n++] = ' ';
+ }
+ reset_on_stop = 0;
+ if (n < 0) {
+ /* eof */
+ if (loading)
+ break;
+ if (sourcing) {
+ unstack();
+ continue;
+ }
+ if (value("interactive") != NULL &&
+ value("ignoreeof") != NULL &&
+ ++eofloop < 25) {
+ printf("Use \"quit\" to quit.\n");
+ continue;
+ }
+ break;
+ }
+ eofloop = 0;
+ if (execute(linebuf, 0))
+ break;
+ }
+}
+
+/*
+ * Execute a single command.
+ * Command functions return 0 for success, 1 for error, and -1
+ * for abort. A 1 or -1 aborts a load or source. A -1 aborts
+ * the interactive command loop.
+ * Contxt is non-zero if called while composing mail.
+ */
+int
+execute(linebuf, contxt)
+ char linebuf[];
+ int contxt;
+{
+ char word[LINESIZE];
+ char *arglist[MAXARGC];
+ const struct cmd *com;
+ char *cp, *cp2;
+ int c, muvec[2];
+ int e = 1;
+
+ /*
+ * Strip the white space away from the beginning
+ * of the command, then scan out a word, which
+ * consists of anything except digits and white space.
+ *
+ * Handle ! escapes differently to get the correct
+ * lexical conventions.
+ */
+
+ for (cp = linebuf; isspace((unsigned char)*cp); cp++)
+ ;
+ if (*cp == '!') {
+ if (sourcing) {
+ printf("Can't \"!\" while sourcing\n");
+ goto out;
+ }
+ shell(cp+1);
+ return (0);
+ }
+ cp2 = word;
+ while (*cp != '\0' && strchr(" \t0123456789$^.:/-+*'\"", *cp) == NULL)
+ *cp2++ = *cp++;
+ *cp2 = '\0';
+
+ /*
+ * Look up the command; if not found, bitch.
+ * Normally, a blank command would map to the
+ * first command in the table; while sourcing,
+ * however, we ignore blank lines to eliminate
+ * confusion.
+ */
+
+ if (sourcing && *word == '\0')
+ return (0);
+ com = lex(word);
+ if (com == NULL) {
+ printf("Unknown command: \"%s\"\n", word);
+ goto out;
+ }
+
+ if (debug != 1) {
+ if (value("debug") == NULL) {
+ debug = 0;
+ } else {
+ debug = 2;
+ }
+ } /* else ignore debug env var */
+ if (debug)
+ fprintf(stderr, "debug mode: cmd is %s\n", com->c_name);
+
+ /*
+ * See if we should execute the command -- if a conditional
+ * we always execute it, otherwise, check the state of cond.
+ */
+
+ if ((com->c_argtype & F) == 0)
+ if ((cond == CRCV && !rcvmode) || (cond == CSEND && rcvmode))
+ return (0);
+
+ /*
+ * Process the arguments to the command, depending
+ * on the type he expects. Default to an error.
+ * If we are sourcing an interactive command, it's
+ * an error.
+ */
+
+ if (!rcvmode && (com->c_argtype & M) == 0) {
+ printf("May not execute \"%s\" while sending\n",
+ com->c_name);
+ goto out;
+ }
+ if (sourcing && com->c_argtype & I) {
+ printf("May not execute \"%s\" while sourcing\n",
+ com->c_name);
+ goto out;
+ }
+ if (readonly && com->c_argtype & W) {
+ printf("May not execute \"%s\" -- message file is read only\n",
+ com->c_name);
+ goto out;
+ }
+ if (contxt && com->c_argtype & R) {
+ printf("Cannot recursively invoke \"%s\"\n", com->c_name);
+ goto out;
+ }
+ switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
+ case MSGLIST:
+ /*
+ * A message list defaulting to nearest forward
+ * legal message.
+ */
+ if (msgvec == 0) {
+ printf("Illegal use of \"message list\"\n");
+ break;
+ }
+ if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
+ break;
+ if (c == 0) {
+ *msgvec = first(com->c_msgflag, com->c_msgmask);
+ msgvec[1] = 0;
+ }
+ if (*msgvec == 0) {
+ printf("No applicable messages\n");
+ break;
+ }
+ e = (*com->c_func)(msgvec);
+ break;
+
+ case NDMLIST:
+ /*
+ * A message list with no defaults, but no error
+ * if none exist.
+ */
+ if (msgvec == 0) {
+ printf("Illegal use of \"message list\"\n");
+ break;
+ }
+ if (getmsglist(cp, msgvec, com->c_msgflag) < 0)
+ break;
+ e = (*com->c_func)(msgvec);
+ break;
+
+ case STRLIST:
+ /*
+ * Just the straight string, with
+ * leading blanks removed.
+ */
+ while (isspace((unsigned char)*cp))
+ cp++;
+ e = (*com->c_func)(cp);
+ break;
+
+ case RAWLIST:
+ /*
+ * A vector of strings, in shell style.
+ */
+ if ((c = getrawlist(cp, arglist,
+ sizeof(arglist) / sizeof(*arglist))) < 0)
+ break;
+ if (c < com->c_minargs) {
+ printf("%s requires at least %d arg(s)\n",
+ com->c_name, com->c_minargs);
+ break;
+ }
+ if (c > com->c_maxargs) {
+ printf("%s takes no more than %d arg(s)\n",
+ com->c_name, com->c_maxargs);
+ break;
+ }
+ e = (*com->c_func)(arglist);
+ break;
+
+ case NOLIST:
+ /*
+ * Just the constant zero, for exiting,
+ * eg.
+ */
+ e = (*com->c_func)(0);
+ break;
+
+ default:
+ errx(1, "Unknown argtype");
+ }
+
+out:
+ /*
+ * Exit the current source file on
+ * error.
+ */
+ if (e) {
+ if (e < 0)
+ return (1);
+ if (loading)
+ return (1);
+ if (sourcing)
+ unstack();
+ return (0);
+ }
+ if (com == NULL)
+ return (0);
+ if (value("autoprint") != NULL && com->c_argtype & P)
+ if ((dot->m_flag & MDELETED) == 0) {
+ muvec[0] = dot - &message[0] + 1;
+ muvec[1] = 0;
+ type(muvec);
+ }
+ if (!sourcing && (com->c_argtype & T) == 0)
+ sawcom = 1;
+ return (0);
+}
+
+/*
+ * Set the size of the message vector used to construct argument
+ * lists to message list functions.
+ */
+void
+setmsize(sz)
+ int sz;
+{
+
+ if (msgvec != NULL)
+ (void)free(msgvec);
+ msgvec = calloc((unsigned)(sz + 1), sizeof(*msgvec));
+}
+
+/*
+ * Find the correct command in the command table corresponding
+ * to the passed command "word"
+ */
+
+__const struct cmd *
+lex(word)
+ char word[];
+{
+ const struct cmd *cp;
+
+ /*
+ * ignore trailing chars after `#'
+ *
+ * lines with beginning `#' are comments
+ * spaces before `#' are ignored in execute()
+ */
+
+ if (*word == '#')
+ *(word+1) = '\0';
+
+
+ for (cp = &cmdtab[0]; cp->c_name != NULL; cp++)
+ if (isprefix(word, cp->c_name))
+ return (cp);
+ return (NULL);
+}
+
+/*
+ * Determine if as1 is a valid prefix of as2.
+ * Return true if yep.
+ */
+int
+isprefix(as1, as2)
+ const char *as1, *as2;
+{
+ const char *s1, *s2;
+
+ s1 = as1;
+ s2 = as2;
+ while (*s1++ == *s2)
+ if (*s2++ == '\0')
+ return (1);
+ return (*--s1 == '\0');
+}
+
+/*
+ * The following gets called on receipt of an interrupt. This is
+ * to abort printout of a command, mainly.
+ * Dispatching here when command() is inactive crashes rcv.
+ * Close all open files except 0, 1, 2, and the temporary.
+ * Also, unstack all source files.
+ */
+
+int inithdr; /* am printing startup headers */
+
+/*ARGSUSED*/
+void
+intr(s)
+ int s;
+{
+
+ noreset = 0;
+ if (!inithdr)
+ sawcom++;
+ inithdr = 0;
+ while (sourcing)
+ unstack();
+
+ close_all_files();
+
+ if (image >= 0) {
+ (void)close(image);
+ image = -1;
+ }
+ fprintf(stderr, "Interrupt\n");
+ reset(0);
+}
+
+/*
+ * When we wake up after ^Z, reprint the prompt.
+ */
+void
+stop(s)
+ int s;
+{
+ sig_t old_action = signal(s, SIG_DFL);
+ sigset_t nset;
+
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, s);
+ (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+ (void)kill(0, s);
+ (void)sigprocmask(SIG_BLOCK, &nset, NULL);
+ (void)signal(s, old_action);
+ if (reset_on_stop) {
+ reset_on_stop = 0;
+ reset(0);
+ }
+}
+
+/*
+ * Branch here on hangup signal and simulate "exit".
+ */
+/*ARGSUSED*/
+void
+hangup(s)
+ int s;
+{
+
+ /* nothing to do? */
+ exit(1);
+}
+
+/*
+ * Announce the presence of the current Mail version,
+ * give the message count, and print a header listing.
+ */
+void
+announce()
+{
+ int vec[2], mdot;
+
+ mdot = newfileinfo(0);
+ vec[0] = mdot;
+ vec[1] = 0;
+ dot = &message[mdot - 1];
+ if (msgCount > 0 && value("header") != NULL) {
+ inithdr++;
+ headers(vec);
+ inithdr = 0;
+ }
+}
+
+/*
+ * Announce information about the file we are editing.
+ * Return a likely place to set dot.
+ */
+int
+newfileinfo(omsgCount)
+ int omsgCount;
+{
+ struct message *mp;
+ int u, n, mdot, d, s;
+ char fname[PATHSIZE+1], zname[PATHSIZE+1], *ename;
+
+ for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++)
+ if (mp->m_flag & MNEW)
+ break;
+ if (mp >= &message[msgCount])
+ for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag & MREAD) == 0)
+ break;
+ if (mp < &message[msgCount])
+ mdot = mp - &message[0] + 1;
+ else
+ mdot = omsgCount + 1;
+ if (value("header") == NULL) {
+ return (mdot);
+ }
+ s = d = 0;
+ for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) {
+ if (mp->m_flag & MNEW)
+ n++;
+ if ((mp->m_flag & MREAD) == 0)
+ u++;
+ if (mp->m_flag & MDELETED)
+ d++;
+ if (mp->m_flag & MSAVED)
+ s++;
+ }
+ ename = mailname;
+ if (getfold(fname, sizeof(fname) - 1) >= 0) {
+ strcat(fname, "/");
+ if (strncmp(fname, mailname, strlen(fname)) == 0) {
+ (void)snprintf(zname, sizeof(zname), "+%s",
+ mailname + strlen(fname));
+ ename = zname;
+ }
+ }
+ printf("\"%s\": ", ename);
+ if (msgCount == 1)
+ printf("1 message");
+ else
+ printf("%d messages", msgCount);
+ if (n > 0)
+ printf(" %d new", n);
+ if (u-n > 0)
+ printf(" %d unread", u);
+ if (d > 0)
+ printf(" %d deleted", d);
+ if (s > 0)
+ printf(" %d saved", s);
+ if (readonly)
+ printf(" [Read only]");
+ printf("\n");
+ return (mdot);
+}
+
+/*
+ * Print the current version number.
+ */
+
+/*ARGSUSED*/
+int
+pversion(e)
+ int e;
+{
+
+ printf("Version %s\n", version);
+ return (0);
+}
+
+/*
+ * Load a file of user definitions.
+ */
+void
+load(name)
+ char *name;
+{
+ FILE *in, *oldin;
+
+ if ((in = Fopen(name, "r")) == NULL)
+ return;
+ oldin = input;
+ input = in;
+ loading = 1;
+ sourcing = 1;
+ commands();
+ loading = 0;
+ sourcing = 0;
+ input = oldin;
+ (void)Fclose(in);
+}
diff --git a/mail_cmds/mail/list.c b/mail_cmds/mail/list.c
new file mode 100644
index 0000000..1b0a962
--- /dev/null
+++ b/mail_cmds/mail/list.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)list.c 8.4 (Berkeley) 5/1/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/list.c,v 1.9 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <ctype.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Message list handling.
+ */
+
+/*
+ * Convert the user string of message numbers and
+ * store the numbers into vector.
+ *
+ * Returns the count of messages picked up or -1 on error.
+ */
+int
+getmsglist(buf, vector, flags)
+ char *buf;
+ int *vector, flags;
+{
+ int *ip;
+ struct message *mp;
+
+ if (msgCount == 0) {
+ *vector = 0;
+ return (0);
+ }
+ if (markall(buf, flags) < 0)
+ return (-1);
+ ip = vector;
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if (mp->m_flag & MMARK)
+ *ip++ = mp - &message[0] + 1;
+ *ip = 0;
+ return (ip - vector);
+}
+
+/*
+ * Mark all messages that the user wanted from the command
+ * line in the message structure. Return 0 on success, -1
+ * on error.
+ */
+
+/*
+ * Bit values for colon modifiers.
+ */
+
+#define CMNEW 01 /* New messages */
+#define CMOLD 02 /* Old messages */
+#define CMUNREAD 04 /* Unread messages */
+#define CMDELETED 010 /* Deleted messages */
+#define CMREAD 020 /* Read messages */
+
+/*
+ * The following table describes the letters which can follow
+ * the colon and gives the corresponding modifier bit.
+ */
+
+struct coltab {
+ char co_char; /* What to find past : */
+ int co_bit; /* Associated modifier bit */
+ int co_mask; /* m_status bits to mask */
+ int co_equal; /* ... must equal this */
+} coltab[] = {
+ { 'n', CMNEW, MNEW, MNEW },
+ { 'o', CMOLD, MNEW, 0 },
+ { 'u', CMUNREAD, MREAD, 0 },
+ { 'd', CMDELETED, MDELETED, MDELETED},
+ { 'r', CMREAD, MREAD, MREAD },
+ { 0, 0, 0, 0 }
+};
+
+static int lastcolmod;
+
+int
+markall(buf, f)
+ char buf[];
+ int f;
+{
+ char **np;
+ int i;
+ struct message *mp;
+ char *namelist[NMLSIZE], *bufp;
+ int tok, beg, mc, star, other, valdot, colmod, colresult;
+
+ valdot = dot - &message[0] + 1;
+ colmod = 0;
+ for (i = 1; i <= msgCount; i++)
+ unmark(i);
+ bufp = buf;
+ mc = 0;
+ np = &namelist[0];
+ scaninit();
+ tok = scan(&bufp);
+ star = 0;
+ other = 0;
+ beg = 0;
+ while (tok != TEOL) {
+ switch (tok) {
+ case TNUMBER:
+number:
+ if (star) {
+ printf("No numbers mixed with *\n");
+ return (-1);
+ }
+ mc++;
+ other++;
+ if (beg != 0) {
+ if (check(lexnumber, f))
+ return (-1);
+ for (i = beg; i <= lexnumber; i++)
+ if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0)
+ mark(i);
+ beg = 0;
+ break;
+ }
+ beg = lexnumber;
+ if (check(beg, f))
+ return (-1);
+ tok = scan(&bufp);
+ regret(tok);
+ if (tok != TDASH) {
+ mark(beg);
+ beg = 0;
+ }
+ break;
+
+ case TPLUS:
+ if (beg != 0) {
+ printf("Non-numeric second argument\n");
+ return (-1);
+ }
+ i = valdot;
+ do {
+ i++;
+ if (i > msgCount) {
+ printf("Referencing beyond EOF\n");
+ return (-1);
+ }
+ } while ((message[i - 1].m_flag & MDELETED) != f);
+ mark(i);
+ break;
+
+ case TDASH:
+ if (beg == 0) {
+ i = valdot;
+ do {
+ i--;
+ if (i <= 0) {
+ printf("Referencing before 1\n");
+ return (-1);
+ }
+ } while ((message[i - 1].m_flag & MDELETED) != f);
+ mark(i);
+ }
+ break;
+
+ case TSTRING:
+ if (beg != 0) {
+ printf("Non-numeric second argument\n");
+ return (-1);
+ }
+ other++;
+ if (lexstring[0] == ':') {
+ colresult = evalcol(lexstring[1]);
+ if (colresult == 0) {
+ printf("Unknown colon modifier \"%s\"\n",
+ lexstring);
+ return (-1);
+ }
+ colmod |= colresult;
+ }
+ else
+ *np++ = savestr(lexstring);
+ break;
+
+ case TDOLLAR:
+ case TUP:
+ case TDOT:
+ lexnumber = metamess(lexstring[0], f);
+ if (lexnumber == -1)
+ return (-1);
+ goto number;
+
+ case TSTAR:
+ if (other) {
+ printf("Can't mix \"*\" with anything\n");
+ return (-1);
+ }
+ star++;
+ break;
+
+ case TERROR:
+ return (-1);
+ }
+ tok = scan(&bufp);
+ }
+ lastcolmod = colmod;
+ *np = NULL;
+ mc = 0;
+ if (star) {
+ for (i = 0; i < msgCount; i++)
+ if ((message[i].m_flag & MDELETED) == f) {
+ mark(i+1);
+ mc++;
+ }
+ if (mc == 0) {
+ printf("No applicable messages.\n");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * If no numbers were given, mark all of the messages,
+ * so that we can unmark any whose sender was not selected
+ * if any user names were given.
+ */
+
+ if ((np > namelist || colmod != 0) && mc == 0)
+ for (i = 1; i <= msgCount; i++)
+ if ((message[i-1].m_flag & MDELETED) == f)
+ mark(i);
+
+ /*
+ * If any names were given, go through and eliminate any
+ * messages whose senders were not requested.
+ */
+
+ if (np > namelist) {
+ for (i = 1; i <= msgCount; i++) {
+ for (mc = 0, np = &namelist[0]; *np != NULL; np++)
+ if (**np == '/') {
+ if (matchfield(*np, i)) {
+ mc++;
+ break;
+ }
+ }
+ else {
+ if (matchsender(*np, i)) {
+ mc++;
+ break;
+ }
+ }
+ if (mc == 0)
+ unmark(i);
+ }
+
+ /*
+ * Make sure we got some decent messages.
+ */
+
+ mc = 0;
+ for (i = 1; i <= msgCount; i++)
+ if (message[i-1].m_flag & MMARK) {
+ mc++;
+ break;
+ }
+ if (mc == 0) {
+ printf("No applicable messages from {%s",
+ namelist[0]);
+ for (np = &namelist[1]; *np != NULL; np++)
+ printf(", %s", *np);
+ printf("}\n");
+ return (-1);
+ }
+ }
+
+ /*
+ * If any colon modifiers were given, go through and
+ * unmark any messages which do not satisfy the modifiers.
+ */
+
+ if (colmod != 0) {
+ for (i = 1; i <= msgCount; i++) {
+ struct coltab *colp;
+
+ mp = &message[i - 1];
+ for (colp = &coltab[0]; colp->co_char != '\0'; colp++)
+ if (colp->co_bit & colmod)
+ if ((mp->m_flag & colp->co_mask)
+ != colp->co_equal)
+ unmark(i);
+
+ }
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if (mp->m_flag & MMARK)
+ break;
+ if (mp >= &message[msgCount]) {
+ struct coltab *colp;
+
+ printf("No messages satisfy");
+ for (colp = &coltab[0]; colp->co_char != '\0'; colp++)
+ if (colp->co_bit & colmod)
+ printf(" :%c", colp->co_char);
+ printf("\n");
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Turn the character after a colon modifier into a bit
+ * value.
+ */
+int
+evalcol(col)
+ int col;
+{
+ struct coltab *colp;
+
+ if (col == 0)
+ return (lastcolmod);
+ for (colp = &coltab[0]; colp->co_char != '\0'; colp++)
+ if (colp->co_char == col)
+ return (colp->co_bit);
+ return (0);
+}
+
+/*
+ * Check the passed message number for legality and proper flags.
+ * If f is MDELETED, then either kind will do. Otherwise, the message
+ * has to be undeleted.
+ */
+int
+check(mesg, f)
+ int mesg, f;
+{
+ struct message *mp;
+
+ if (mesg < 1 || mesg > msgCount) {
+ printf("%d: Invalid message number\n", mesg);
+ return (-1);
+ }
+ mp = &message[mesg-1];
+ if (f != MDELETED && (mp->m_flag & MDELETED) != 0) {
+ printf("%d: Inappropriate message\n", mesg);
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Scan out the list of string arguments, shell style
+ * for a RAWLIST.
+ */
+int
+getrawlist(line, argv, argc)
+ char line[];
+ char **argv;
+ int argc;
+{
+ char c, *cp, *cp2, quotec;
+ int argn;
+ char *linebuf;
+ size_t linebufsize = BUFSIZ;
+
+ if ((linebuf = malloc(linebufsize)) == NULL)
+ err(1, "Out of memory");
+
+ argn = 0;
+ cp = line;
+ for (;;) {
+ for (; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ if (*cp == '\0')
+ break;
+ if (argn >= argc - 1) {
+ printf(
+ "Too many elements in the list; excess discarded.\n");
+ break;
+ }
+ cp2 = linebuf;
+ quotec = '\0';
+ while ((c = *cp) != '\0') {
+ /* Allocate more space if necessary */
+ if (cp2 - linebuf == linebufsize - 1) {
+ linebufsize += BUFSIZ;
+ if ((linebuf = realloc(linebuf, linebufsize)) == NULL)
+ err(1, "Out of memory");
+ cp2 = linebuf + linebufsize - BUFSIZ - 1;
+ }
+ cp++;
+ if (quotec != '\0') {
+ if (c == quotec)
+ quotec = '\0';
+ else if (c == '\\')
+ switch (c = *cp++) {
+ case '\0':
+ *cp2++ = '\\';
+ cp--;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c -= '0';
+ if (*cp >= '0' && *cp <= '7')
+ c = c * 8 + *cp++ - '0';
+ if (*cp >= '0' && *cp <= '7')
+ c = c * 8 + *cp++ - '0';
+ *cp2++ = c;
+ break;
+ case 'b':
+ *cp2++ = '\b';
+ break;
+ case 'f':
+ *cp2++ = '\f';
+ break;
+ case 'n':
+ *cp2++ = '\n';
+ break;
+ case 'r':
+ *cp2++ = '\r';
+ break;
+ case 't':
+ *cp2++ = '\t';
+ break;
+ case 'v':
+ *cp2++ = '\v';
+ break;
+ default:
+ *cp2++ = c;
+ }
+ else if (c == '^') {
+ c = *cp++;
+ if (c == '?')
+ *cp2++ = '\177';
+ /* null doesn't show up anyway */
+ else if ((c >= 'A' && c <= '_') ||
+ (c >= 'a' && c <= 'z'))
+ *cp2++ = c & 037;
+ else {
+ *cp2++ = '^';
+ cp--;
+ }
+ } else
+ *cp2++ = c;
+ } else if (c == '"' || c == '\'')
+ quotec = c;
+ else if (c == ' ' || c == '\t')
+ break;
+ else
+ *cp2++ = c;
+ }
+ *cp2 = '\0';
+ argv[argn++] = savestr(linebuf);
+ }
+ argv[argn] = NULL;
+ (void)free(linebuf);
+ return (argn);
+}
+
+/*
+ * scan out a single lexical item and return its token number,
+ * updating the string pointer passed **p. Also, store the value
+ * of the number or string scanned in lexnumber or lexstring as
+ * appropriate. In any event, store the scanned `thing' in lexstring.
+ */
+
+struct lex {
+ char l_char;
+ char l_token;
+} singles[] = {
+ { '$', TDOLLAR },
+ { '.', TDOT },
+ { '^', TUP },
+ { '*', TSTAR },
+ { '-', TDASH },
+ { '+', TPLUS },
+ { '(', TOPEN },
+ { ')', TCLOSE },
+ { 0, 0 }
+};
+
+int
+scan(sp)
+ char **sp;
+{
+ char *cp, *cp2;
+ int c;
+ struct lex *lp;
+ int quotec;
+
+ if (regretp >= 0) {
+ strcpy(lexstring, string_stack[regretp]);
+ lexnumber = numberstack[regretp];
+ return (regretstack[regretp--]);
+ }
+ cp = *sp;
+ cp2 = lexstring;
+ c = *cp++;
+
+ /*
+ * strip away leading white space.
+ */
+
+ while (c == ' ' || c == '\t')
+ c = *cp++;
+
+ /*
+ * If no characters remain, we are at end of line,
+ * so report that.
+ */
+
+ if (c == '\0') {
+ *sp = --cp;
+ return (TEOL);
+ }
+
+ /*
+ * If the leading character is a digit, scan
+ * the number and convert it on the fly.
+ * Return TNUMBER when done.
+ */
+
+ if (isdigit((unsigned char)c)) {
+ lexnumber = 0;
+ while (isdigit((unsigned char)c)) {
+ lexnumber = lexnumber*10 + c - '0';
+ *cp2++ = c;
+ c = *cp++;
+ }
+ *cp2 = '\0';
+ *sp = --cp;
+ return (TNUMBER);
+ }
+
+ /*
+ * Check for single character tokens; return such
+ * if found.
+ */
+
+ for (lp = &singles[0]; lp->l_char != '\0'; lp++)
+ if (c == lp->l_char) {
+ lexstring[0] = c;
+ lexstring[1] = '\0';
+ *sp = cp;
+ return (lp->l_token);
+ }
+
+ /*
+ * We've got a string! Copy all the characters
+ * of the string into lexstring, until we see
+ * a null, space, or tab.
+ * If the lead character is a " or ', save it
+ * and scan until you get another.
+ */
+
+ quotec = 0;
+ if (c == '\'' || c == '"') {
+ quotec = c;
+ c = *cp++;
+ }
+ while (c != '\0') {
+ if (c == quotec) {
+ cp++;
+ break;
+ }
+ if (quotec == 0 && (c == ' ' || c == '\t'))
+ break;
+ if (cp2 - lexstring < STRINGLEN-1)
+ *cp2++ = c;
+ c = *cp++;
+ }
+ if (quotec && c == '\0') {
+ fprintf(stderr, "Missing %c\n", quotec);
+ return (TERROR);
+ }
+ *sp = --cp;
+ *cp2 = '\0';
+ return (TSTRING);
+}
+
+/*
+ * Unscan the named token by pushing it onto the regret stack.
+ */
+void
+regret(token)
+ int token;
+{
+ if (++regretp >= REGDEP)
+ errx(1, "Too many regrets");
+ regretstack[regretp] = token;
+ lexstring[STRINGLEN-1] = '\0';
+ string_stack[regretp] = savestr(lexstring);
+ numberstack[regretp] = lexnumber;
+}
+
+/*
+ * Reset all the scanner global variables.
+ */
+void
+scaninit()
+{
+ regretp = -1;
+}
+
+/*
+ * Find the first message whose flags & m == f and return
+ * its message number.
+ */
+int
+first(f, m)
+ int f, m;
+{
+ struct message *mp;
+
+ if (msgCount == 0)
+ return (0);
+ f &= MDELETED;
+ m &= MDELETED;
+ for (mp = dot; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag & m) == f)
+ return (mp - message + 1);
+ for (mp = dot-1; mp >= &message[0]; mp--)
+ if ((mp->m_flag & m) == f)
+ return (mp - message + 1);
+ return (0);
+}
+
+/*
+ * See if the passed name sent the passed message number. Return true
+ * if so.
+ */
+int
+matchsender(str, mesg)
+ char *str;
+ int mesg;
+{
+ char *cp;
+
+ /* null string matches nothing instead of everything */
+ if (*str == '\0')
+ return (0);
+
+ cp = nameof(&message[mesg - 1], 0);
+ return (strcasestr(cp, str) != NULL);
+}
+
+/*
+ * See if the passed name received the passed message number. Return true
+ * if so.
+ */
+
+static char *to_fields[] = { "to", "cc", "bcc", NULL };
+
+int
+matchto(str, mesg)
+ char *str;
+ int mesg;
+{
+ struct message *mp;
+ char *cp, **to;
+
+ str++;
+
+ /* null string matches nothing instead of everything */
+ if (*str == '\0')
+ return (0);
+
+ mp = &message[mesg - 1];
+
+ for (to = to_fields; *to != NULL; to++) {
+ cp = hfield(*to, mp);
+ if (cp != NULL && strcasestr(cp, str) != NULL)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * See if the given substring is contained within the specified field. If
+ * 'searchheaders' is set, then the form '/x:y' will be accepted and matches
+ * any message with the substring 'y' in field 'x'. If 'x' is omitted or
+ * 'searchheaders' is not set, then the search matches any messages
+ * with the substring 'y' in the 'Subject'. The search is case insensitive.
+ *
+ * The form '/to:y' is a special case, and will match all messages
+ * containing the substring 'y' in the 'To', 'Cc', or 'Bcc' header
+ * fields. The search for 'to' is case sensitive, so that '/To:y' can
+ * be used to limit the search to just the 'To' field.
+ */
+
+char lastscan[STRINGLEN];
+int
+matchfield(str, mesg)
+ char *str;
+ int mesg;
+{
+ struct message *mp;
+ char *cp, *cp2;
+
+ str++;
+ if (*str == '\0')
+ str = lastscan;
+ else
+ strlcpy(lastscan, str, sizeof(lastscan));
+ mp = &message[mesg-1];
+
+ /*
+ * Now look, ignoring case, for the word in the string.
+ */
+
+ if (value("searchheaders") && (cp = strchr(str, ':')) != NULL) {
+ /* Check for special case "/to:" */
+ if (strncmp(str, "to:", 3) == 0)
+ return (matchto(cp, mesg));
+ *cp++ = '\0';
+ cp2 = hfield(*str != '\0' ? str : "subject", mp);
+ cp[-1] = ':';
+ str = cp;
+ cp = cp2;
+ } else
+ cp = hfield("subject", mp);
+
+ if (cp == NULL)
+ return (0);
+
+ return (strcasestr(cp, str) != NULL);
+}
+
+/*
+ * Mark the named message by setting its mark bit.
+ */
+void
+mark(mesg)
+ int mesg;
+{
+ int i;
+
+ i = mesg;
+ if (i < 1 || i > msgCount)
+ errx(1, "Bad message number to mark");
+ message[i-1].m_flag |= MMARK;
+}
+
+/*
+ * Unmark the named message.
+ */
+void
+unmark(mesg)
+ int mesg;
+{
+ int i;
+
+ i = mesg;
+ if (i < 1 || i > msgCount)
+ errx(1, "Bad message number to unmark");
+ message[i-1].m_flag &= ~MMARK;
+}
+
+/*
+ * Return the message number corresponding to the passed meta character.
+ */
+int
+metamess(meta, f)
+ int meta, f;
+{
+ int c, m;
+ struct message *mp;
+
+ c = meta;
+ switch (c) {
+ case '^':
+ /*
+ * First 'good' message left.
+ */
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag & MDELETED) == f)
+ return (mp - &message[0] + 1);
+ printf("No applicable messages\n");
+ return (-1);
+
+ case '$':
+ /*
+ * Last 'good message left.
+ */
+ for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
+ if ((mp->m_flag & MDELETED) == f)
+ return (mp - &message[0] + 1);
+ printf("No applicable messages\n");
+ return (-1);
+
+ case '.':
+ /*
+ * Current message.
+ */
+ m = dot - &message[0] + 1;
+ if ((dot->m_flag & MDELETED) != f) {
+ printf("%d: Inappropriate message\n", m);
+ return (-1);
+ }
+ return (m);
+
+ default:
+ printf("Unknown metachar (%c)\n", c);
+ return (-1);
+ }
+}
diff --git a/mail_cmds/mail/mail.1 b/mail_cmds/mail/mail.1
new file mode 100644
index 0000000..18e617e
--- /dev/null
+++ b/mail_cmds/mail/mail.1
@@ -0,0 +1,1272 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail.1 8.8 (Berkeley) 4/28/95
+.\" $FreeBSD: src/usr.bin/mail/mail.1,v 1.45 2004/05/19 09:51:31 ru Exp $
+.\"
+.Dd February 29, 2004
+.Dt MAIL 1
+.Os
+.Sh NAME
+.Nm mail ,
+.Nm mailx
+.Nd send and receive mail
+.Sh SYNOPSIS
+.Nm
+.Op Fl EiInv
+.Op Fl s Ar subject
+.Op Fl c Ar cc-addr
+.Op Fl b Ar bcc-addr
+.Op Fl F
+.Ar to-addr ...
+.Op Fl Ar sendmail-option ...
+.Nm
+.Op Fl EHiInNv
+.Op Fl F
+.Fl f
+.Op Ar name
+.Nm
+.Op Fl EHiInNv
+.Op Fl F
+.Op Fl u Ar user
+.Nm
+.Fl e
+.Op Fl f Ar name
+.Nm
+.Op Fl H
+.Sh INTRODUCTION
+The
+.Nm
+utility is an intelligent mail processing system, which has
+a command syntax reminiscent of
+.Xr ed 1
+with lines replaced by messages.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl v
+Verbose mode.
+The details of
+delivery are displayed on the user's terminal.
+.It Fl e
+Test for the presence of mail in the (by default, system)
+mailbox.
+An exit status of 0 is returned if
+it has mail; otherwise, an exit status
+of 1 is returned.
+.It Fl H
+Write a header summary only.
+.It Fl E
+Do not send messages with an empty body.
+This is useful for piping errors from
+.Xr cron 8
+scripts.
+.It Fl i
+Ignore tty interrupt signals.
+This is
+particularly useful when using
+.Nm
+on noisy phone lines.
+.It Fl I
+Force
+.Nm
+to run in interactive mode even when
+input is not a terminal.
+In particular, the
+.Ql ~
+special
+character when sending mail is only active in interactive mode.
+.It Fl n
+Inhibit reading the system-wide
+.Pa mail.rc
+files upon startup.
+.It Fl N
+Inhibit the initial display of message headers
+when reading mail or editing a mail folder.
+.It Fl s Ar subject
+Specify
+.Ar subject
+on command line.
+(Only the first argument after the
+.Fl s
+flag is used as a subject; be careful to quote subjects
+containing spaces.)
+.It Fl c Ar cc-addr
+Send carbon copies to
+.Ar cc-addr
+list of users.
+The
+.Ar cc-addr
+argument should be a comma-separated list of names.
+.It Fl b Ar bcc-addr
+Send blind carbon copies to
+.Ar bcc-addr
+list of users.
+The
+.Ar bcc-addr
+argument should be a comma-separated list of names.
+.It Fl f Op Ar mbox
+Read in the contents of your
+.Pa mbox
+(or the specified file)
+for processing; when you
+.Ic quit ,
+.Nm
+writes undeleted messages back to this file.
+.It Fl F
+Record the message in a file named after the first
+recipient.
+The name is the login-name portion of the
+address found first on the
+.Dq Li To:
+line in the mail header.
+Overrides the
+.Va record
+variable, if set.
+.It Fl u
+Is equivalent to:
+.Pp
+.Dl "mail -f /var/mail/user"
+.El
+.Ss "Startup Actions"
+At startup time
+.Nm
+will execute commands in the system command files
+.Pa /usr/share/misc/mail.rc ,
+.Pa /usr/local/etc/mail.rc
+and
+.Pa /etc/mail.rc
+in order, unless explicitly told not to by the use of the
+.Fl n
+option.
+Next, the commands in the user's personal command file
+.Pa ~/.mailrc
+are executed.
+The
+.Nm
+utility then examines its command line options to determine whether a
+new message is to be sent, or whether an existing mailbox is to
+be read.
+.Ss "Sending Mail"
+To send a message to one or more people,
+.Nm
+can be invoked with arguments which are the names of people to
+whom the mail will be sent.
+You are then expected to type in
+your message, followed
+by a
+.Aq Li control-D
+at the beginning of a line.
+The section below
+.Sx "Replying To or Originating Mail" ,
+describes some features of
+.Nm
+available to help you compose your letter.
+.Ss "Reading Mail"
+In normal usage
+.Nm
+is given no arguments and checks your mail out of the
+post office, then
+prints out a one line header of each message found.
+The current message is initially the first message (numbered 1)
+and can be printed using the
+.Ic print
+command (which can be abbreviated
+.Ic p ) .
+You can move among the messages much as you move between lines in
+.Xr ed 1 ,
+with the commands
+.Ic +
+and
+.Ic \-
+moving backwards and forwards, and
+simple numbers.
+.Ss "Disposing of Mail"
+After examining a message you can
+.Ic delete
+.Pq Ic d
+the message or
+.Ic reply
+.Pq Ic r
+to it.
+Deletion causes the
+.Nm
+program to forget about the message.
+This is not irreversible; the message can be
+.Ic undeleted
+.Pq Ic u
+by giving its number, or the
+.Nm
+session can be aborted by giving the
+.Ic exit
+.Pq Ic x
+command.
+Deleted messages will, however, usually disappear never to be seen again.
+.Ss "Specifying Messages"
+Commands such as
+.Ic print
+and
+.Ic delete
+can be given a list of message numbers as arguments to apply
+to a number of messages at once.
+Thus
+.Dq Li "delete 1 2"
+deletes messages 1 and 2, while
+.Dq Li "delete 1\-5"
+deletes messages 1 through 5.
+The special name
+.Ql *
+addresses all messages, and
+.Ql $
+addresses
+the last message; thus the command
+.Ic top
+which prints the first few lines of a message could be used in
+.Dq Li "top *"
+to print the first few lines of all messages.
+.Ss "Replying To or Originating Mail"
+You can use the
+.Ic reply
+command to
+set up a response to a message, sending it back to the
+person who it was from.
+Text you then type in, up to an end-of-file,
+defines the contents of the message.
+While you are composing a message,
+.Nm
+treats lines beginning with the character
+.Ql ~
+specially.
+For instance, typing
+.Ic ~m
+(alone on a line) will place a copy
+of the current message into the response right shifting it by a tabstop
+(see
+.Va indentprefix
+variable, below).
+Other escapes will set up subject fields, add and delete recipients
+to the message and allow you to escape to an editor to revise the
+message or to a shell to run some commands.
+(These options
+are given in the summary below.)
+.Ss "Ending a Mail Processing Session"
+You can end a
+.Nm
+session with the
+.Ic quit
+.Pq Ic q
+command.
+Messages which have been examined go to your
+.Pa mbox
+file unless they have been deleted in which case they are discarded.
+Unexamined messages go back to the post office.
+(See the
+.Fl f
+option above).
+.Ss "Personal and System Wide Distribution Lists"
+It is also possible to create a personal distribution lists so that,
+for instance, you can send mail to
+.Dq Li cohorts
+and have it go
+to a group of people.
+Such lists can be defined by placing a line like
+.Pp
+.Dl "alias cohorts bill ozalp jkf mark kridle@ucbcory"
+.Pp
+in the file
+.Pa .mailrc
+in your home directory.
+The current list of such aliases can be displayed with the
+.Ic alias
+command in
+.Nm .
+System wide distribution lists can be created by editing
+.Pa /etc/mail/aliases ,
+see
+.Xr aliases 5
+and
+.Xr sendmail 8 ;
+these are kept in a different syntax.
+In mail you send, personal aliases will be expanded in mail sent
+to others so that they will be able to
+.Ic reply
+to the recipients.
+System wide
+aliases
+are not expanded when the mail is sent,
+but any reply returned to the machine will have the system wide
+alias expanded as all mail goes through
+.Xr sendmail 8 .
+.Ss "Network Mail (ARPA, UUCP, Berknet)"
+See
+.Xr mailaddr 7
+for a description of network addresses.
+.Pp
+The
+.Nm
+utility has a number of options which can be set in the
+.Pa .mailrc
+file to alter its behavior; thus
+.Dq Li "set askcc"
+enables the
+.Va askcc
+feature.
+(These options are summarized below.)
+.Sh SUMMARY
+(Adapted from the
+.%T "Mail Reference Manual" . )
+.Pp
+Each command is typed on a line by itself, and may take arguments
+following the command word.
+The command need not be typed in its
+entirety \(em the first command which matches the typed prefix is used.
+For commands which take message lists as arguments, if no message
+list is given, then the next message forward which satisfies the
+command's requirements is used.
+If there are no messages forward of
+the current message, the search proceeds backwards, and if there are no
+good messages at all,
+.Nm
+types
+.Dq Li "No applicable messages"
+and
+aborts the command.
+.Bl -tag -width indent
+.It Ic \-
+Print out the preceding message.
+If given a numeric
+argument
+.Ar n ,
+goes to the
+.Ar n Ns 'th
+previous message and prints it.
+.It Ic #
+ignore the remainder of the line as a comment.
+.It Ic \&?
+Prints a brief summary of commands.
+.It Ic \&!
+Executes the shell
+(see
+.Xr sh 1
+and
+.Xr csh 1 )
+command which follows.
+.It Ic Print
+.Pq Ic P
+Like
+.Ic print
+but also prints out ignored header fields.
+See also
+.Ic print , ignore
+and
+.Ic retain .
+.It Ic Reply
+.Pq Ic R
+Reply to originator.
+Does not reply to other
+recipients of the original message.
+.It Ic Type
+.Pq Ic T
+Identical to the
+.Ic Print
+command.
+.It Ic alias
+.Pq Ic a
+With no arguments, prints out all currently-defined aliases.
+With one
+argument, prints out that alias.
+With more than one argument, creates
+a new alias or changes an old one.
+.It Ic alternates
+.Pq Ic alt
+The
+.Ic alternates
+command is useful if you have accounts on several machines.
+It can be used to inform
+.Nm
+that the listed addresses are really you.
+When you
+.Ic reply
+to messages,
+.Nm
+will not send a copy of the message to any of the addresses
+listed on the
+.Ic alternates
+list.
+If the
+.Ic alternates
+command is given with no argument, the current set of alternative
+names is displayed.
+.It Ic chdir
+.Pq Ic c
+Changes the user's working directory to that specified, if given.
+If
+no directory is given, then changes to the user's login directory.
+.It Ic copy
+.Pq Ic co
+The
+.Ic copy
+command does the same thing that
+.Ic save
+does, except that it does not mark the messages it
+is used on for deletion when you
+.Ic quit .
+.It Ic delete
+.Pq Ic d
+Takes a list of messages as argument and marks them all as deleted.
+Deleted messages will not be saved in
+.Pa mbox ,
+nor will they be available for most other commands.
+.It Ic dp
+(also
+.Ic dt )
+Deletes the current message and prints the next message.
+If there is no next message,
+.Nm
+says
+.Dq Li "at EOF" .
+.It Ic edit
+.Pq Ic e
+Takes a list of messages and points the text editor at each one in
+turn.
+On return from the editor, the message is read back in.
+.It Ic exit
+.Ic ( ex
+or
+.Ic x )
+Effects an immediate return to the shell without
+modifying the user's system mailbox, his
+.Pa mbox
+file, or his edit file in
+.Fl f .
+.It Ic file
+.Pq Ic fi
+The same as
+.Ic folder .
+.It Ic folders
+List the names of the folders in your folder directory.
+.It Ic folder
+.Pq Ic fo
+The
+.Ic folder
+command switches to a new mail file or folder.
+With no
+arguments, it tells you which file you are currently reading.
+If you give it an argument, it will write out changes (such
+as deletions) you have made in the current file and read in
+the new file.
+Some special conventions are recognized for
+the name.
+.Ql #
+means the previous file,
+.Ql %
+means your system mailbox,
+.Dq Li % Ns Ar user
+means user's system mailbox,
+.Ql &
+means your
+.Pa mbox
+file, and
+.Dq Li + Ns Ar folder
+means a file in your folder
+directory.
+.It Ic from
+.Pq Ic f
+Takes a list of messages and prints their message headers.
+.It Ic headers
+.Pq Ic h
+Lists the current range of headers, which is an 18-message group.
+If
+a
+.Ql +
+argument is given, then the next 18-message group is printed, and if
+a
+.Ql \-
+argument is given, the previous 18-message group is printed.
+.It Ic help
+A synonym for
+.Ic \&? .
+.It Ic hold
+.Ic ( ho ,
+also
+.Ic preserve )
+Takes a message list and marks each
+message therein to be saved in the
+user's system mailbox instead of in
+.Pa mbox .
+Does not override the
+.Ic delete
+command.
+.It Ic ignore
+Add the list of header fields named to the
+.Ar ignored list .
+Header fields in the ignore list are not printed
+on your terminal when you print a message.
+This
+command is very handy for suppression of certain machine-generated
+header fields.
+The
+.Ic Type
+and
+.Ic Print
+commands can be used to print a message in its entirety, including
+ignored fields.
+If
+.Ic ignore
+is executed with no arguments, it lists the current set of
+ignored fields.
+.It Ic inc
+Incorporate any new messages that have arrived while mail
+is being read.
+The new messages are added to the end of the message list,
+and the current message is reset to be the first new mail message.
+This does not renumber the existing message list, nor
+does it cause any changes made so far to be saved.
+.It Ic mail
+.Pq Ic m
+Takes as argument login names and distribution group names and sends
+mail to those people.
+.It Ic mbox
+Indicate that a list of messages be sent to
+.Pa mbox
+in your home directory when you quit.
+This is the default
+action for messages if you do
+.Em not
+have the
+.Ic hold
+option set.
+.It Ic more
+.Pq Ic mo
+Takes a list of messages and invokes the pager on that list.
+.It Ic next
+.Ic ( n ,
+like
+.Ic +
+or
+.Tn CR )
+Goes to the next message in sequence and types it.
+With an argument list, types the next matching message.
+.It Ic preserve
+.Pq Ic pre
+A synonym for
+.Ic hold .
+.It Ic print
+.Pq Ic p
+Takes a message list and types out each message on the user's terminal.
+.It Ic quit
+.Pq Ic q
+Terminates the session, saving all undeleted, unsaved messages in
+the user's
+.Pa mbox
+file in his login directory, preserving all messages marked with
+.Ic hold
+or
+.Ic preserve
+or never referenced
+in his system mailbox, and removing all other messages from his system
+mailbox.
+If new mail has arrived during the session, the message
+.Dq Li "You have new mail"
+is given.
+If given while editing a
+mailbox file with the
+.Fl f
+flag, then the edit file is rewritten.
+A return to the shell is
+effected, unless the rewrite of edit file fails, in which case the user
+can escape with the
+.Ic exit
+command.
+.It Ic reply
+.Pq Ic r
+Takes a message list and sends mail to the sender and all
+recipients of the specified message.
+The default message must not be deleted.
+.It Ic respond
+A synonym for
+.Ic reply .
+.It Ic retain
+Add the list of header fields named to the
+.Em "retained list" .
+Only the header fields in the retained list
+are shown on your terminal when you print a message.
+All other header fields are suppressed.
+The
+.Ic type
+and
+.Ic print
+commands can be used to print a message in its entirety.
+If
+.Ic retain
+is executed with no arguments, it lists the current set of
+retained fields.
+.It Ic save
+.Pq Ic s
+Takes a message list and a filename and appends each message in
+turn to the end of the file.
+The filename in quotes, followed by the line
+count and character count is echoed on the user's terminal.
+.It Ic set
+.Pq Ic se
+With no arguments, prints all variable values.
+Otherwise, sets
+option.
+Arguments are of the form
+.Ar option Ns Li = Ns Ar value
+(no space before or after
+.Ql = )
+or
+.Ar option .
+Quotation marks may be placed around any part of the assignment statement to
+quote blanks or tabs, i.e.\&
+.Dq Li "set indentprefix=\*q->\*q"
+.It Ic saveignore
+.Ic Saveignore
+is to
+.Ic save
+what
+.Ic ignore
+is to
+.Ic print
+and
+.Ic type .
+Header fields thus marked are filtered out when
+saving a message by
+.Ic save
+or when automatically saving to
+.Pa mbox .
+.It Ic saveretain
+.Ic Saveretain
+is to
+.Ic save
+what
+.Ic retain
+is to
+.Ic print
+and
+.Ic type .
+Header fields thus marked are the only ones saved
+with a message when saving by
+.Ic save
+or when automatically saving to
+.Pa mbox .
+.Ic Saveretain
+overrides
+.Ic saveignore .
+.It Ic shell
+.Pq Ic sh
+Invokes an interactive version of the shell.
+.It Ic size
+Takes a message list and prints out the size in characters of each
+message.
+.It Ic source
+The
+.Ic source
+command reads
+commands from a file.
+.It Ic top
+Takes a message list and prints the top few lines of each.
+The number of
+lines printed is controlled by the variable
+.Va toplines
+and defaults to 5.
+.It Ic type
+.Pq Ic t
+A synonym for
+.Ic print .
+.It Ic unalias
+Takes a list of names defined by
+.Ic alias
+commands and discards the remembered groups of users.
+The group names
+no longer have any significance.
+.It Ic undelete
+.Pq Ic u
+Takes a message list and marks each message as
+.Em not
+being deleted.
+.It Ic unread
+.Pq Ic U
+Takes a message list and marks each message as
+.Em not
+having been read.
+.It Ic unset
+Takes a list of option names and discards their remembered values;
+the inverse of
+.Ic set .
+.It Ic visual
+.Pq Ic v
+Takes a message list and invokes the display editor on each message.
+.It Ic write
+.Pq Ic w
+Similar to
+.Ic save ,
+except that
+.Em only
+the message body
+.Em ( without
+the header) is saved.
+Extremely useful for such tasks as sending and receiving source
+program text over the message system.
+.It Ic xit
+.Pq Ic x
+A synonym for
+.Ic exit .
+.It Ic z
+The
+.Nm
+utility presents message headers in windowfuls as described under the
+.Ic headers
+command.
+You can move
+.Nm Ns 's
+attention forward to the next window with the
+.Ic z
+command.
+Also, you can move to the previous window by using
+.Ic z\- .
+.El
+.Ss Tilde/Escapes
+Here is a summary of the tilde escapes,
+which are used when composing messages to perform
+special functions.
+Tilde escapes are only recognized at the beginning
+of lines.
+The name
+.Dq "tilde escape"
+is somewhat of a misnomer since the actual escape character can be set
+by the option
+.Va escape .
+.Bl -tag -width indent
+.It Ic ~a
+Inserts the autograph string from the sign= option into the message.
+.It Ic ~A
+Inserts the autograph string from the Sign= option into the message.
+.It Ic ~b Ar name ...
+Add the given names to the list of carbon copy recipients but do not make
+the names visible in the Cc: line
+.Dq ( blind
+carbon copy).
+.It Ic ~c Ar name ...
+Add the given names to the list of carbon copy recipients.
+.It Ic ~d
+Read the file
+.Pa dead.letter
+from your home directory into the message.
+.It Ic ~e
+Invoke the text editor on the message collected so far.
+After the
+editing session is finished, you may continue appending text to the
+message.
+.It Ic ~f Ar messages
+Read the named messages into the message being sent.
+If no messages are specified, read in the current message.
+Message headers currently being ignored (by the
+.Ic ignore
+or
+.Ic retain
+command) are not included.
+.It Ic ~F Ar messages
+Identical to
+.Ic ~f ,
+except all message headers are included.
+.It Ic ~h
+Edit the message header fields by typing each one in turn and allowing
+the user to append text to the end or modify the field by using the
+current terminal erase and kill characters.
+.It Ic ~i Ar string
+Inserts the value of the named option into the text of the message.
+.It Ic ~m Ar messages
+Read the named messages into the message being sent, indented by a
+tab or by the value of
+.Va indentprefix .
+If no messages are specified,
+read the current message.
+Message headers currently being ignored (by the
+.Ic ignore
+or
+.Ic retain
+command) are not included.
+.It Ic ~M Ar messages
+Identical to
+.Ic ~m ,
+except all message headers are included.
+.It Ic ~p
+Print out the message collected so far, prefaced by the message header
+fields.
+.It Ic ~q
+Abort the message being sent, copying the message to
+.Pa dead.letter
+in your home directory if
+.Va save
+is set.
+.It Ic ~r Ar filename , Ic ~r Li \&! Ns Ar command
+.It Ic ~< Ar filename , Ic ~< Li \&! Ns Ar command
+Read the named file into the message.
+If the argument begins with a
+.Ql \&! ,
+the rest of the string is taken as an arbitrary system command and is
+executed, with the standard output inserted into the message.
+.It Ic ~R Ar string
+Use
+.Ar string
+as the Reply-To field.
+.It Ic ~s Ar string
+Cause the named string to become the current subject field.
+.It Ic ~t Ar name ...
+Add the given names to the direct recipient list.
+.It Ic ~v
+Invoke an alternative editor (defined by the
+.Ev VISUAL
+environment variable) on the
+message collected so far.
+Usually, the alternative editor will be a
+screen editor.
+After you quit the editor, you may resume appending
+text to the end of your message.
+.It Ic ~w Ar filename
+Write the message onto the named file.
+.It Ic ~x
+Exits as with
+.Ic ~q ,
+except the message is not saved in
+.Pa dead.letter .
+.It Ic ~! Ar command
+Execute the indicated shell command, then return to the message.
+.It Ic ~| Ar command , Ic ~^ Ar command
+Pipe the message through the command as a filter.
+If the command gives
+no output or terminates abnormally, retain the original text of the
+message.
+The command
+.Xr fmt 1
+is often used as
+.Ar command
+to rejustify the message.
+.It Ic ~: Ar mail-command , Ic ~_ Ar mail-command
+Execute the given
+.Nm
+command.
+Not all commands, however, are allowed.
+.It Ic ~.
+Simulate end-of-file on input.
+.It Ic ~?
+Print a summary of the available command escapes.
+.It Ic ~~ Ar string
+Insert the string of text in the message prefaced by a single
+.Ql ~ .
+If
+you have changed the escape character, then you should double
+that character in order to send it.
+.El
+.Ss "Mail Options"
+Options can be set with the
+.Ic set
+command
+and can be disabled with the
+.Ic unset
+or
+.Ic set Cm no Ns Ar name
+commands.
+Options may be either binary, in which case it is only
+significant to see whether they are set or not; or string, in which
+case the actual value is of interest.
+If an option is not set,
+.Nm
+will look for an environment variable of the same name.
+The available options include the following:
+.Bl -tag -width indent
+.It Va append
+Causes messages saved in
+.Pa mbox
+to be appended to the end rather than prepended.
+This should always be set (preferably in one of the system-wide
+.Pa mail.rc
+files).
+Default is
+.Va noappend .
+.It Va ask , asksub
+Causes
+.Nm
+to prompt you for the subject of each message you send.
+If
+you respond with simply a newline, no subject field will be sent.
+Default is
+.Va asksub .
+.It Va askbcc
+Causes you to be prompted for additional blind carbon copy recipients at the
+end of each message.
+Responding with a newline indicates your
+satisfaction with the current list.
+Default is
+.Va noaskbcc .
+.It Va askcc
+Causes you to be prompted for additional carbon copy recipients at the
+end of each message.
+Responding with a newline indicates your
+satisfaction with the current list.
+Default is
+.Va noaskcc .
+.It Va autoinc
+Causes new mail to be automatically incorporated when it arrives.
+Setting this is similar to issuing the
+.Ic inc
+command at each prompt, except that the current message is not
+reset when new mail arrives.
+Default is
+.Va noautoinc .
+.It Va autoprint
+Causes the
+.Ic delete
+command to behave like
+.Ic dp ;
+thus, after deleting a message, the next one will be typed
+automatically.
+Default is
+.Va noautoprint .
+.It Va crt
+The valued option
+.Va crt
+is used as a threshold to determine how long a message must
+be before
+.Ev PAGER
+is used to read it.
+If
+.Va crt
+is set without a value,
+then the height of the terminal screen stored in the system
+is used to compute the threshold (see
+.Xr stty 1 ) .
+Default is
+.Va nocrt .
+.It Va debug
+Setting the binary option
+.Va debug
+is the same as specifying
+.Fl d
+on the command line and causes
+.Nm
+to output all sorts of information useful for debugging
+.Nm .
+Default is
+.Va nodebug .
+.It Va dot
+The binary option
+.Va dot
+causes
+.Nm
+to interpret a period alone on a line as the terminator
+of a message you are sending.
+Default is
+.Va nodot .
+.It Va escape
+If defined, the first character of this option gives the character to
+use in place of
+.Ql ~
+to denote escapes.
+.It Va flipr
+Reverses the sense of
+.Ic reply
+and
+.Ic Reply
+commands.
+Default is
+.Va noflipr .
+.It Va folder
+The name of the directory to use for storing folders of
+messages.
+If this name begins with a
+.Ql / ,
+.Nm
+considers it to be an absolute pathname; otherwise, the
+folder directory is found relative to your home directory.
+.It Va header
+If defined, initially display message headers when reading mail or
+editing a mail folder.
+Default is
+.Va header .
+This option can be disabled by giving the
+.Fl N
+flag on the command line.
+.It Va hold
+This option is used to hold messages in the system mailbox
+by default.
+Default is
+.Va nohold .
+.It Va ignore
+Causes interrupt signals from your terminal to be ignored and echoed as
+.Li @ Ns 's.
+Default is
+.Va noignore .
+.It Va ignoreeof
+An option related to
+.Va dot
+is
+.Va ignoreeof
+which makes
+.Nm
+refuse to accept a
+.Aq Li control-D
+as the end of a message.
+.Ar Ignoreeof
+also applies to
+.Nm
+command mode.
+Default is
+.Va noignoreeof .
+.It Va indentprefix
+String used by the
+.Ic ~m
+tilde escape for indenting messages, in place of
+the normal tab character
+.Pq Li ^I .
+Be sure to quote the value if it contains
+spaces or tabs.
+.It Va metoo
+Usually, when a group is expanded that contains the sender, the sender
+is removed from the expansion.
+Setting this option causes the sender
+to be included in the group.
+Default is
+.Va nometoo .
+.It Va quiet
+Suppresses the printing of the version when first invoked.
+Default is
+.Va noquiet .
+.It Va record
+If defined, gives the pathname of the file used to record all outgoing
+mail.
+If not defined, outgoing mail is not saved.
+Default is
+.Va norecord .
+.It Va Replyall
+Reverses the sense of
+.Ic reply
+and
+.Ic Reply
+commands.
+Default is
+.Va noReplyall .
+.It Va save
+If this option is set, and you abort a message with two
+.Tn RUBOUT
+(erase or delete),
+.Nm
+will copy the partial letter to the file
+.Pa dead.letter
+in your home directory.
+Default is
+.Va save .
+.It Va searchheaders
+If this option is set, then a message-list specifier in the form
+.Dq Li / Ns Ar x Ns Li : Ns Ar y
+will expand to all messages containing the substring
+.Ar y
+in the header field
+.Ar x .
+The string search is case insensitive.
+If
+.Ar x
+is omitted, it will default to the
+.Dq Li Subject
+header field.
+The form
+.Dq Li /to: Ns Ar y
+is a special case, and will expand
+to all messages containing the substring
+.Ar y
+in the
+.Dq Li To ,
+.Dq Li Cc
+or
+.Dq Li Bcc
+header fields.
+The check for
+.Qq Li "to"
+is case sensitive, so that
+.Dq Li /To: Ns Ar y
+can be used to limit the search for
+.Ar y
+to just the
+.Dq Li To:
+field.
+Default is
+.Va nosearchheaders .
+.It Va toplines
+If defined, gives the number of lines of a message to be printed out
+with the
+.Ic top
+command; normally, the first five lines are printed.
+.It Va verbose
+Setting the option
+.Va verbose
+is the same as using the
+.Fl v
+flag on the command line.
+When
+.Nm
+runs in verbose mode,
+the actual delivery of messages is displayed on the user's
+terminal.
+Default is
+.Va noverbose .
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev REPLYTO"
+.It Ev DEAD
+Pathname of the file to save partial messages to in case of interrupts
+or delivery errors.
+Default is
+.Pa ~/dead.letter .
+.It Ev EDITOR
+Pathname of the text editor to use in the
+.Ic edit
+command and
+.Ic ~e
+escape.
+If not defined, then a default editor is used.
+.It Ev HOME
+Pathname of the user's home directory.
+.It Ev LISTER
+Pathname of the directory lister to use in the
+.Ic folders
+command.
+Default is
+.Pa /bin/ls .
+.It Ev MAIL
+Location of the user's mailbox.
+Default is
+.Pa /var/mail .
+.It Ev MAILRC
+Pathname of file containing initial
+.Nm
+commands.
+Default is
+.Pa ~/.mailrc .
+.It Ev MBOX
+The name of the mailbox file.
+It can be the name of a folder.
+The default is
+.Pa mbox
+in the user's home directory.
+.It Ev PAGER
+Pathname of the program to use in the
+.Ic more
+command or when
+.Va crt
+variable is set.
+The default paginator
+.Xr more 1
+is used if this option is not defined.
+.It Ev REPLYTO
+If set, will be used to initialize the Reply-To field for outgoing
+messages.
+.It Ev SHELL
+Pathname of the shell to use in the
+.Ic \&!
+command and the
+.Ic ~!
+escape.
+A default shell is used if this option is
+not defined.
+.It Ev VISUAL
+Pathname of the text editor to use in the
+.Ic visual
+command and
+.Ic ~v
+escape.
+.It Ev USER
+Login name of the user executing mail.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /usr/share/misc/mail.*help" -compact
+.It Pa /var/mail/*
+Post office.
+.It Pa ~/mbox
+User's old mail.
+.It Pa ~/.mailrc
+File giving initial
+.Nm
+commands.
+This can be overridden by setting the
+.Ev MAILRC
+environment variable.
+.It Pa /tmp/R*
+Temporary files.
+.It Pa /usr/share/misc/mail.*help
+Help files.
+.Pp
+.It Pa /usr/share/misc/mail.rc
+.It Pa /usr/local/etc/mail.rc
+.It Pa /etc/mail.rc
+System-wide initialization files.
+Each file will be sourced, in order,
+if it exists.
+.El
+.Sh SEE ALSO
+.Xr fmt 1 ,
+.Xr newaliases 1 ,
+.Xr vacation 1 ,
+.Xr aliases 5 ,
+.Xr mailaddr 7 ,
+.Xr sendmail 8
+.Rs
+.%T "The Mail Reference Manual"
+.Re
+.Sh HISTORY
+A
+.Nm
+command
+appeared in
+.At v1 .
+This man page is derived from
+.%T "The Mail Reference Manual"
+originally written by
+.An Kurt Shoens .
+.Sh BUGS
+There are some flags that are not documented here.
+Most are
+not useful to the general user.
+.Pp
+Usually,
+.Nm
+is just a link to
+.Nm Mail
+and
+.Nm mailx ,
+which can be confusing.
+.Pp
+The name of the
+.Ic alternates
+list is incorrect English (it should be
+.Dq alternatives ) ,
+but is retained for compatibility.
diff --git a/mail_cmds/mail/mailx.1 b/mail_cmds/mail/mailx.1
new file mode 100644
index 0000000..6c49b5b
--- /dev/null
+++ b/mail_cmds/mail/mailx.1
@@ -0,0 +1 @@
+.so man1/mail.1
diff --git a/mail_cmds/mail/main.c b/mail_cmds/mail/main.c
new file mode 100644
index 0000000..915a376
--- /dev/null
+++ b/mail_cmds/mail/main.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 4/20/95";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/main.c,v 1.14 2004/02/29 20:44:44 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
+
+#define EXTERN
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Startup -- interface with user.
+ */
+
+jmp_buf hdrjmp;
+
+extern const char *version;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ struct name *to, *cc, *bcc, *smopts;
+ char *subject, *replyto;
+ char *ef, *rc;
+ char nosrc = 0;
+ sig_t prevint;
+
+ /*
+ * Set up a reasonable environment.
+ * Figure out whether we are being run interactively,
+ * start the SIGCHLD catcher, and so forth.
+ */
+ (void)signal(SIGCHLD, sigchild);
+ if (isatty(0))
+ assign("interactive", "");
+ image = -1;
+
+ /* Define defaults for internal variables, based on Unix 2003 standard */
+ /* noallnet allnet off */
+ /* noappend append off */
+ assign("asksub",""); /* asksub on */
+ /* noaskbcc askbcc off */
+ /* noaskcc askcc off */
+ /* noautoprint autoprint off */
+ /* nobang bang off */
+ /* nocmd cmd off */
+ /* nocrt crt off */
+ /* nodebug debug off */
+ /* nodot dot off */
+ /* noflipr flipr off */
+ /* nofolder folder off */
+ assign("header", ""); /* headers on */
+ /* nohold hold off */
+ /* noignore ignore off */
+ /* noignoreeof ignoreeof off */
+ /* nokeep keep off */
+ /* nokeepsave keepsave off */
+ /* nometoo metoo off */
+ /* noonehop onehop off */
+ /* nooutfolder outfolder off */
+ /* nopage page off */
+ assign("prompt", "? ");
+ /* noquiet quiet off */
+ /* norecord record off */
+ assign("save", ""); /* save on */
+ /* nosendwait sendwait off */
+ /* noshowto showto off */
+ /* nosign sign off */
+ /* noSign Sign off */
+
+ /*
+ * Now, determine how we are being used.
+ * We successively pick off - flags.
+ * If there is anything left, it is the base of the list
+ * of users to mail to. Argp will be set to point to the
+ * first of these users.
+ */
+ ef = NULL;
+ to = NULL;
+ cc = NULL;
+ bcc = NULL;
+ smopts = NULL;
+ subject = NULL;
+ while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) {
+ switch (i) {
+ case 'T':
+ /*
+ * Next argument is temp file to write which
+ * articles have been read/deleted for netnews.
+ */
+ Tflag = optarg;
+ if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY,
+ 0600)) < 0)
+ err(1, "%s", Tflag);
+ (void)close(i);
+ break;
+ case 'u':
+ /*
+ * Next argument is person to pretend to be.
+ */
+ myname = optarg;
+ unsetenv("MAIL");
+ break;
+ case 'i':
+ /*
+ * User wants to ignore interrupts.
+ * Set the variable "ignore"
+ */
+ assign("ignore", "");
+ break;
+ case 'd':
+ debug = 1; /* 1 -> set from command line; disables env var [no]debug */
+ break;
+ case 'e':
+ /*
+ * User wants to check mail and exit.
+ */
+ assign("checkmode", "");
+ break;
+ case 'H':
+ /*
+ * User wants a header summary only.
+ */
+ assign("headersummary", "");
+ break;
+ case 'F':
+ /*
+ * User wants to record messages to files
+ * named after first recipient username.
+ */
+ assign("recordrecip", "");
+ break;
+ case 's':
+ /*
+ * Give a subject field for sending from
+ * non terminal
+ */
+ subject = optarg;
+ break;
+ case 'f':
+ /*
+ * User is specifying file to "edit" with Mail,
+ * as opposed to reading system mailbox.
+ * If no argument is given after -f, we read his
+ * mbox file.
+ *
+ * getopt() can't handle optional arguments, so here
+ * is an ugly hack to get around it.
+ */
+ if ((argv[optind] != NULL) && (argv[optind][0] != '-'))
+ ef = argv[optind++];
+ else
+ ef = "&";
+ break;
+ case 'n':
+ /*
+ * User doesn't want to source /usr/lib/Mail.rc
+ */
+ nosrc++;
+ break;
+ case 'N':
+ /*
+ * Avoid initial header printing.
+ */
+ assign("quiet", "");
+ break;
+ case 'v':
+ /*
+ * Send mailer verbose flag
+ */
+ assign("verbose", "");
+ break;
+ case 'I':
+ /*
+ * We're interactive
+ */
+ assign("interactive", "");
+ break;
+ case 'c':
+ /*
+ * Get Carbon Copy Recipient list
+ */
+ cc = cat(cc, nalloc(optarg, GCC));
+ break;
+ case 'b':
+ /*
+ * Get Blind Carbon Copy Recipient list
+ */
+ bcc = cat(bcc, nalloc(optarg, GBCC));
+ break;
+ case 'E':
+ /*
+ * Don't send empty files.
+ */
+ assign("dontsendempty", "");
+ break;
+ case '?':
+ fprintf(stderr, "\
+Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\
+ %*s [- sendmail-options ...]\n\
+ %s [-EHiInNv] [-F] -f [name]\n\
+ %s [-EHiInNv] [-F] [-u user]\n\
+ %s -e [-f name]\n\
+ %s -H\n",__progname, (int)strlen(__progname), "",
+ __progname, __progname, __progname, __progname);
+ exit(1);
+ }
+ }
+ for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
+ to = cat(to, nalloc(argv[i], GTO));
+ for (; argv[i] != NULL; i++)
+ smopts = cat(smopts, nalloc(argv[i], 0));
+ /*
+ * Check for inconsistent arguments.
+ */
+ if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
+ errx(1, "You must specify direct recipients with -s, -c, or -b.");
+ if (ef != NULL && to != NULL)
+ errx(1, "Cannot give -f and people to send to.");
+ tinit();
+ setscreensize();
+ input = stdin;
+ rcvmode = !to;
+ spreserve();
+ if (!nosrc) {
+ char *s, *path_rc;
+
+ if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
+ err(1, "malloc(path_rc) failed");
+
+ strcpy(path_rc, _PATH_MASTER_RC);
+ while ((s = strsep(&path_rc, ":")) != NULL)
+ if (*s != '\0')
+ load(s);
+ }
+ /*
+ * Expand returns a savestr, but load only uses the file name
+ * for fopen, so it's safe to do this.
+ */
+ if ((rc = getenv("MAILRC")) == NULL)
+ rc = "~/.mailrc";
+ load(expand(rc));
+
+ replyto = value("REPLYTO");
+ if (!rcvmode) {
+ mail(to, cc, bcc, smopts, subject, replyto);
+ /*
+ * why wait?
+ */
+ exit(senderr);
+ }
+
+ if(value("checkmode") != NULL) {
+ if (ef == NULL)
+ ef = "%";
+ if (setfile(ef) <= 0)
+ /* Either an error has occured, or no mail */
+ exit(1);
+ else
+ exit(0);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Ok, we are reading mail.
+ * Decide whether we are editing a mailbox or reading
+ * the system mailbox, and open up the right stuff.
+ */
+ if (ef == NULL)
+ ef = "%";
+ if (setfile(ef) < 0)
+ exit(1); /* error already reported */
+ if (setjmp(hdrjmp) == 0) {
+ if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
+ (void)signal(SIGINT, hdrstop);
+ if (value("quiet") == NULL) {
+ printf("Mail version %s. Type ? for help.\n",
+ version);
+ announce();
+ }
+ (void)fflush(stdout);
+ (void)signal(SIGINT, prevint);
+ }
+
+ /* If we were in header summary mode, it's time to exit. */
+ if (value("headersummary") != NULL)
+ exit(0);
+
+ commands();
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ quit();
+ exit(0);
+}
+
+/*
+ * Interrupt printing of the headers.
+ */
+/*ARGSUSED*/
+void
+hdrstop(signo)
+ int signo;
+{
+
+ (void)fflush(stdout);
+ fprintf(stderr, "\nInterrupt\n");
+ longjmp(hdrjmp, 1);
+}
+
+/*
+ * Compute what the screen size for printing headers should be.
+ * We use the following algorithm for the height:
+ * If baud rate < 1200, use 9
+ * If baud rate = 1200, use 14
+ * If baud rate > 1200, use 24 or ws_row
+ * Width is either 80 or ws_col;
+ */
+void
+setscreensize()
+{
+ struct termios tbuf;
+ struct winsize ws;
+ speed_t speed;
+
+ if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
+ ws.ws_col = ws.ws_row = 0;
+ if (tcgetattr(1, &tbuf) < 0)
+ speed = B9600;
+ else
+ speed = cfgetospeed(&tbuf);
+ if (speed < B1200)
+ screenheight = 9;
+ else if (speed == B1200)
+ screenheight = 14;
+ else if (ws.ws_row != 0)
+ screenheight = ws.ws_row;
+ else
+ screenheight = 24;
+ if ((realscreenheight = ws.ws_row) == 0)
+ realscreenheight = 24;
+ if ((screenwidth = ws.ws_col) == 0)
+ screenwidth = 80;
+}
diff --git a/mail_cmds/mail/misc/mail.help b/mail_cmds/mail/misc/mail.help
new file mode 100644
index 0000000..f5c5dd2
--- /dev/null
+++ b/mail_cmds/mail/misc/mail.help
@@ -0,0 +1,23 @@
+ Mail Commands
+t <message list> type messages
+n goto and type next message
+e <message list> edit messages
+f <message list> give head lines of messages
+d <message list> delete messages
+s <message list> file append messages to file
+u <message list> undelete messages
+R <message list> reply to message senders
+r <message list> reply to message senders and all recipients
+pre <message list> make messages go back to /var/mail
+m <user list> mail to specific users
+q quit, saving unresolved messages in mbox
+x quit, do not remove system mailbox
+h print out active message headers
+! shell escape
+cd [directory] chdir to directory or home if none given
+
+A <message list> consists of integers, ranges of same, or user names separated
+by spaces. If omitted, Mail uses the last message typed.
+
+A <user list> consists of user names or aliases separated by spaces.
+Aliases are defined in .mailrc in your home directory.
diff --git a/mail_cmds/mail/misc/mail.rc b/mail_cmds/mail/misc/mail.rc
new file mode 100644
index 0000000..2293b3c
--- /dev/null
+++ b/mail_cmds/mail/misc/mail.rc
@@ -0,0 +1,2 @@
+set append dot save ask crt
+ignore Received Message-Id Resent-Message-Id Status Mail-From Return-Path Via
diff --git a/mail_cmds/mail/misc/mail.tildehelp b/mail_cmds/mail/misc/mail.tildehelp
new file mode 100644
index 0000000..47201d3
--- /dev/null
+++ b/mail_cmds/mail/misc/mail.tildehelp
@@ -0,0 +1,36 @@
+-----------------------------------------------------------
+The following ~ escapes are defined:
+~? Print this message
+~~ Quote a single tilde
+~. Simulate end-of-file on input
+~A Equivalent to: ~i Sign
+~a Equivalent to: ~i sign
+~b users Add users to Bcc list
+~c users Add users to Cc list
+~C Dump core
+~d Read in dead.letter
+~e Edit the message buffer
+~f messages Read in messages
+~F messages Same as ~f, but keep all header lines
+~h Prompt for Subject and To, Cc, and Bcc lists
+~i name Insert the value of the named variable
+~m messages Read in messages, right shifted by a tab
+~M messages Same as ~m, but keep all header lines
+~p Print the message buffer
+~q Quit, save partial message in dead.letter
+~r file Read a file into the message buffer
+~r !command Insert the output of the command
+~< file Same as ~r
+~< !command Same as ~r
+~R address Set Reply-to to address
+~s subject Set Subject to subject
+~t users Add users to the To list
+~v Invoke display editor on message
+~w file Write message onto file
+~x Quit, do not save to dead.letter
+~! command Invoke the shell
+~| command Pipe the message through the command
+~^ command Same as ~|
+~_ mail-cmd Perform the command-level request
+~: mail-cmd Same as ~_
+-----------------------------------------------------------
diff --git a/mail_cmds/mail/names.c b/mail_cmds/mail/names.c
new file mode 100644
index 0000000..19aa411
--- /dev/null
+++ b/mail_cmds/mail/names.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)names.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/names.c,v 1.9 2004/02/29 20:44:44 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Handle name lists.
+ */
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Allocate a single element of a name list,
+ * initialize its name field to the passed
+ * name and return it.
+ */
+struct name *
+nalloc(str, ntype)
+ char str[];
+ int ntype;
+{
+ struct name *np;
+
+ np = (struct name *)salloc(sizeof(*np));
+ np->n_flink = NULL;
+ np->n_blink = NULL;
+ np->n_type = ntype;
+ np->n_name = savestr(str);
+ return (np);
+}
+
+/*
+ * Find the tail of a list and return it.
+ */
+struct name *
+tailof(name)
+ struct name *name;
+{
+ struct name *np;
+
+ np = name;
+ if (np == NULL)
+ return (NULL);
+ while (np->n_flink != NULL)
+ np = np->n_flink;
+ return (np);
+}
+
+/*
+ * Extract a list of names from a line,
+ * and make a list of names from it.
+ * Return the list or NULL if none found.
+ */
+struct name *
+extract(line, ntype)
+ char line[];
+ int ntype;
+{
+ char *cp, *nbuf;
+ struct name *top, *np, *t;
+
+ if (line == NULL || *line == '\0')
+ return (NULL);
+ if ((nbuf = malloc(strlen(line) + 1)) == NULL)
+ err(1, "Out of memory");
+ top = NULL;
+ np = NULL;
+ cp = line;
+ while ((cp = yankword(cp, nbuf)) != NULL) {
+ t = nalloc(nbuf, ntype);
+ if (top == NULL)
+ top = t;
+ else
+ np->n_flink = t;
+ t->n_blink = np;
+ np = t;
+ }
+ (void)free(nbuf);
+ return (top);
+}
+
+/*
+ * Turn a list of names into a string of the same names.
+ */
+char *
+detract(np, ntype)
+ struct name *np;
+ int ntype;
+{
+ int s, comma;
+ char *cp, *top;
+ struct name *p;
+
+ comma = ntype & GCOMMA;
+ if (np == NULL)
+ return (NULL);
+ ntype &= ~GCOMMA;
+ s = 0;
+ if (debug && comma)
+ fprintf(stderr, "detract asked to insert commas\n");
+ for (p = np; p != NULL; p = p->n_flink) {
+ if (ntype && (p->n_type & GMASK) != ntype)
+ continue;
+ s += strlen(p->n_name) + 1;
+ if (comma)
+ s++;
+ }
+ if (s == 0)
+ return (NULL);
+ s += 2;
+ top = salloc(s);
+ cp = top;
+ for (p = np; p != NULL; p = p->n_flink) {
+ if (ntype && (p->n_type & GMASK) != ntype)
+ continue;
+ cp += strlcpy(cp, p->n_name, strlen(p->n_name) + 1);
+ if (comma && p->n_flink != NULL)
+ *cp++ = ',';
+ *cp++ = ' ';
+ }
+ *--cp = '\0';
+ if (comma && *--cp == ',')
+ *cp = '\0';
+ return (top);
+}
+
+/*
+ * Grab a single word (liberal word)
+ * Throw away things between ()'s, and take anything between <>.
+ */
+char *
+yankword(ap, wbuf)
+ char *ap, wbuf[];
+{
+ char *cp, *cp2;
+
+ cp = ap;
+ for (;;) {
+ if (*cp == '\0')
+ return (NULL);
+ if (*cp == '(') {
+ int nesting = 0;
+
+ while (*cp != '\0') {
+ switch (*cp++) {
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ --nesting;
+ break;
+ }
+ if (nesting <= 0)
+ break;
+ }
+ } else if (*cp == ' ' || *cp == '\t' || *cp == ',')
+ cp++;
+ else
+ break;
+ }
+ if (*cp == '<')
+ for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';)
+ ;
+ else
+ for (cp2 = wbuf; *cp != '\0' && strchr(" \t,(", *cp) == NULL;
+ *cp2++ = *cp++)
+ ;
+ *cp2 = '\0';
+ return (cp);
+}
+
+/*
+ * Grab a single login name (liberal word)
+ * Throw away things between ()'s, take anything between <>,
+ * and look for words before metacharacters %, @, !.
+ */
+char *
+yanklogin(ap, wbuf)
+ char *ap, wbuf[];
+{
+ char *cp, *cp2, *cp_temp;
+ int n;
+
+ cp = ap;
+ for (;;) {
+ if (*cp == '\0')
+ return (NULL);
+ if (*cp == '(') {
+ int nesting = 0;
+
+ while (*cp != '\0') {
+ switch (*cp++) {
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ --nesting;
+ break;
+ }
+ if (nesting <= 0)
+ break;
+ }
+ } else if (*cp == ' ' || *cp == '\t' || *cp == ',')
+ cp++;
+ else
+ break;
+ }
+
+ /*
+ * Now, let's go forward till we meet the needed character,
+ * and step one word back.
+ */
+
+ /* First, remember current point. */
+ cp_temp = cp;
+ n = 0;
+
+ /*
+ * Note that we look ahead in a cycle. This is safe, since
+ * non-end of string is checked first.
+ */
+ while(*cp != '\0' && strchr("@%!", *(cp + 1)) == NULL)
+ cp++;
+
+ /*
+ * Now, start stepping back to the first non-word character,
+ * while counting the number of symbols in a word.
+ */
+ while(cp != cp_temp && strchr(" \t,<>", *(cp - 1)) == NULL) {
+ n++;
+ cp--;
+ }
+
+ /* Finally, grab the word forward. */
+ cp2 = wbuf;
+ while(n >= 0) {
+ *cp2++=*cp++;
+ n--;
+ }
+
+ *cp2 = '\0';
+ return (cp);
+}
+
+/*
+ * For each recipient in the passed name list with a /
+ * in the name, append the message to the end of the named file
+ * and remove him from the recipient list.
+ *
+ * Recipients whose name begins with | are piped through the given
+ * program and removed.
+ */
+struct name *
+outof(names, fo, hp)
+ struct name *names;
+ FILE *fo;
+ struct header *hp;
+{
+ int c, ispipe;
+ struct name *np, *top;
+ time_t now;
+ char *date, *fname;
+ FILE *fout, *fin;
+
+ top = names;
+ np = names;
+ (void)time(&now);
+ date = ctime(&now);
+ while (np != NULL) {
+ if (!isfileaddr(np->n_name) && np->n_name[0] != '|') {
+ np = np->n_flink;
+ continue;
+ }
+ ispipe = np->n_name[0] == '|';
+ if (ispipe)
+ fname = np->n_name+1;
+ else
+ fname = expand(np->n_name);
+
+ /*
+ * See if we have copied the complete message out yet.
+ * If not, do so.
+ */
+
+ if (image < 0) {
+ int fd;
+ char tempname[PATHSIZE];
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.ReXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (fout = Fdopen(fd, "a")) == NULL) {
+ warn("%s", tempname);
+ senderr++;
+ goto cant;
+ }
+ image = open(tempname, O_RDWR);
+ (void)rm(tempname);
+ if (image < 0) {
+ warn("%s", tempname);
+ senderr++;
+ (void)Fclose(fout);
+ goto cant;
+ }
+ (void)fcntl(image, F_SETFD, 1);
+ fprintf(fout, "From %s %s", myname, date);
+ puthead(hp, fout,
+ GTO|GSUBJECT|GCC|GREPLYTO|GINREPLYTO|GNL);
+ while ((c = getc(fo)) != EOF)
+ (void)putc(c, fout);
+ rewind(fo);
+ fprintf(fout, "\n");
+ (void)fflush(fout);
+ if (ferror(fout)) {
+ warn("%s", tempname);
+ senderr++;
+ (void)Fclose(fout);
+ goto cant;
+ }
+ (void)Fclose(fout);
+ }
+
+ /*
+ * Now either copy "image" to the desired file
+ * or give it as the standard input to the desired
+ * program as appropriate.
+ */
+
+ if (ispipe) {
+ int pid;
+ char *sh;
+ sigset_t nset;
+
+ /*
+ * XXX
+ * We can't really reuse the same image file,
+ * because multiple piped recipients will
+ * share the same lseek location and trample
+ * on one another.
+ */
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGHUP);
+ (void)sigaddset(&nset, SIGINT);
+ (void)sigaddset(&nset, SIGQUIT);
+ pid = start_command(sh, &nset, image, -1, "-c", fname,
+ NULL);
+ if (pid < 0) {
+ senderr++;
+ goto cant;
+ }
+ free_child(pid);
+ } else {
+ int f;
+ if ((fout = Fopen(fname, "a")) == NULL) {
+ warn("%s", fname);
+ senderr++;
+ goto cant;
+ }
+ if ((f = dup(image)) < 0) {
+ warn("dup");
+ fin = NULL;
+ } else
+ fin = Fdopen(f, "r");
+ if (fin == NULL) {
+ fprintf(stderr, "Can't reopen image\n");
+ (void)Fclose(fout);
+ senderr++;
+ goto cant;
+ }
+ rewind(fin);
+ while ((c = getc(fin)) != EOF)
+ (void)putc(c, fout);
+ if (ferror(fout)) {
+ warnx("%s", fname);
+ senderr++;
+ (void)Fclose(fout);
+ (void)Fclose(fin);
+ goto cant;
+ }
+ (void)Fclose(fout);
+ (void)Fclose(fin);
+ }
+cant:
+ /*
+ * In days of old we removed the entry from the
+ * the list; now for sake of header expansion
+ * we leave it in and mark it as deleted.
+ */
+ np->n_type |= GDEL;
+ np = np->n_flink;
+ }
+ if (image >= 0) {
+ (void)close(image);
+ image = -1;
+ }
+ return (top);
+}
+
+/*
+ * Determine if the passed address is a local "send to file" address.
+ * If any of the network metacharacters precedes any slashes, it can't
+ * be a filename. We cheat with .'s to allow path names like ./...
+ */
+int
+isfileaddr(name)
+ char *name;
+{
+ char *cp;
+
+ if (*name == '+')
+ return (1);
+ for (cp = name; *cp != '\0'; cp++) {
+ if (*cp == '!' || *cp == '%' || *cp == '@')
+ return (0);
+ if (*cp == '/')
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Map all of the aliased users in the invoker's mailrc
+ * file and insert them into the list.
+ * Changed after all these months of service to recursively
+ * expand names (2/14/80).
+ */
+
+struct name *
+usermap(names)
+ struct name *names;
+{
+ struct name *new, *np, *cp;
+ struct grouphead *gh;
+ int metoo;
+
+ new = NULL;
+ np = names;
+ metoo = (value("metoo") != NULL);
+ while (np != NULL) {
+ if (np->n_name[0] == '\\') {
+ cp = np->n_flink;
+ new = put(new, np);
+ np = cp;
+ continue;
+ }
+ gh = findgroup(np->n_name);
+ cp = np->n_flink;
+ if (gh != NULL)
+ new = gexpand(new, gh, metoo, np->n_type);
+ else
+ new = put(new, np);
+ np = cp;
+ }
+ return (new);
+}
+
+/*
+ * Recursively expand a group name. We limit the expansion to some
+ * fixed level to keep things from going haywire.
+ * Direct recursion is not expanded for convenience.
+ */
+
+struct name *
+gexpand(nlist, gh, metoo, ntype)
+ struct name *nlist;
+ struct grouphead *gh;
+ int metoo, ntype;
+{
+ struct group *gp;
+ struct grouphead *ngh;
+ struct name *np;
+ static int depth;
+ char *cp;
+
+ if (depth > MAXEXP) {
+ printf("Expanding alias to depth larger than %d\n", MAXEXP);
+ return (nlist);
+ }
+ depth++;
+ for (gp = gh->g_list; gp != NULL; gp = gp->ge_link) {
+ cp = gp->ge_name;
+ if (*cp == '\\')
+ goto quote;
+ if (strcmp(cp, gh->g_name) == 0)
+ goto quote;
+ if ((ngh = findgroup(cp)) != NULL) {
+ nlist = gexpand(nlist, ngh, metoo, ntype);
+ continue;
+ }
+quote:
+ np = nalloc(cp, ntype);
+ /*
+ * At this point should allow to expand
+ * to self if only person in group
+ */
+ if (gp == gh->g_list && gp->ge_link == NULL)
+ goto skip;
+ if (!metoo && strcmp(cp, myname) == 0)
+ np->n_type |= GDEL;
+skip:
+ nlist = put(nlist, np);
+ }
+ depth--;
+ return (nlist);
+}
+
+/*
+ * Concatenate the two passed name lists, return the result.
+ */
+struct name *
+cat(n1, n2)
+ struct name *n1, *n2;
+{
+ struct name *tail;
+
+ if (n1 == NULL)
+ return (n2);
+ if (n2 == NULL)
+ return (n1);
+ tail = tailof(n1);
+ tail->n_flink = n2;
+ n2->n_blink = tail;
+ return (n1);
+}
+
+/*
+ * Unpack the name list onto a vector of strings.
+ * Return an error if the name list won't fit.
+ */
+char **
+unpack(np)
+ struct name *np;
+{
+ char **ap, **top;
+ struct name *n;
+ int t, extra, metoo, verbose;
+
+ n = np;
+ if ((t = count(n)) == 0)
+ errx(1, "No names to unpack");
+ /*
+ * Compute the number of extra arguments we will need.
+ * We need at least two extra -- one for "mail" and one for
+ * the terminating 0 pointer. Additional spots may be needed
+ * to pass along -f to the host mailer.
+ */
+ extra = 2;
+ extra++;
+ metoo = value("metoo") != NULL;
+ if (metoo)
+ extra++;
+ verbose = value("verbose") != NULL;
+ if (verbose)
+ extra++;
+ top = (char **)salloc((t + extra) * sizeof(*top));
+ ap = top;
+ *ap++ = "send-mail";
+ *ap++ = "-i";
+ if (metoo)
+ *ap++ = "-m";
+ if (verbose)
+ *ap++ = "-v";
+ for (; n != NULL; n = n->n_flink)
+ if ((n->n_type & GDEL) == 0)
+ *ap++ = n->n_name;
+ *ap = NULL;
+ return (top);
+}
+
+/*
+ * Remove all of the duplicates from the passed name list by
+ * insertion sorting them, then checking for dups.
+ * Return the head of the new list.
+ */
+struct name *
+elide(names)
+ struct name *names;
+{
+ struct name *np, *t, *new;
+ struct name *x;
+
+ if (names == NULL)
+ return (NULL);
+ new = names;
+ np = names;
+ np = np->n_flink;
+ if (np != NULL)
+ np->n_blink = NULL;
+ new->n_flink = NULL;
+ while (np != NULL) {
+ t = new;
+ while (strcasecmp(t->n_name, np->n_name) < 0) {
+ if (t->n_flink == NULL)
+ break;
+ t = t->n_flink;
+ }
+
+ /*
+ * If we ran out of t's, put the new entry after
+ * the current value of t.
+ */
+
+ if (strcasecmp(t->n_name, np->n_name) < 0) {
+ t->n_flink = np;
+ np->n_blink = t;
+ t = np;
+ np = np->n_flink;
+ t->n_flink = NULL;
+ continue;
+ }
+
+ /*
+ * Otherwise, put the new entry in front of the
+ * current t. If at the front of the list,
+ * the new guy becomes the new head of the list.
+ */
+
+ if (t == new) {
+ t = np;
+ np = np->n_flink;
+ t->n_flink = new;
+ new->n_blink = t;
+ t->n_blink = NULL;
+ new = t;
+ continue;
+ }
+
+ /*
+ * The normal case -- we are inserting into the
+ * middle of the list.
+ */
+
+ x = np;
+ np = np->n_flink;
+ x->n_flink = t;
+ x->n_blink = t->n_blink;
+ t->n_blink->n_flink = x;
+ t->n_blink = x;
+ }
+
+ /*
+ * Now the list headed up by new is sorted.
+ * Go through it and remove duplicates.
+ */
+
+ np = new;
+ while (np != NULL) {
+ t = np;
+ while (t->n_flink != NULL &&
+ strcasecmp(np->n_name, t->n_flink->n_name) == 0)
+ t = t->n_flink;
+ if (t == np || t == NULL) {
+ np = np->n_flink;
+ continue;
+ }
+
+ /*
+ * Now t points to the last entry with the same name
+ * as np. Make np point beyond t.
+ */
+
+ np->n_flink = t->n_flink;
+ if (t->n_flink != NULL)
+ t->n_flink->n_blink = np;
+ np = np->n_flink;
+ }
+ return (new);
+}
+
+/*
+ * Put another node onto a list of names and return
+ * the list.
+ */
+struct name *
+put(list, node)
+ struct name *list, *node;
+{
+ node->n_flink = list;
+ node->n_blink = NULL;
+ if (list != NULL)
+ list->n_blink = node;
+ return (node);
+}
+
+/*
+ * Determine the number of undeleted elements in
+ * a name list and return it.
+ */
+int
+count(np)
+ struct name *np;
+{
+ int c;
+
+ for (c = 0; np != NULL; np = np->n_flink)
+ if ((np->n_type & GDEL) == 0)
+ c++;
+ return (c);
+}
+
+/*
+ * Delete the given name from a namelist.
+ */
+struct name *
+delname(np, name)
+ struct name *np;
+ char name[];
+{
+ struct name *p;
+
+ for (p = np; p != NULL; p = p->n_flink)
+ if (strcasecmp(p->n_name, name) == 0) {
+ if (p->n_blink == NULL) {
+ if (p->n_flink != NULL)
+ p->n_flink->n_blink = NULL;
+ np = p->n_flink;
+ continue;
+ }
+ if (p->n_flink == NULL) {
+ if (p->n_blink != NULL)
+ p->n_blink->n_flink = NULL;
+ continue;
+ }
+ p->n_blink->n_flink = p->n_flink;
+ p->n_flink->n_blink = p->n_blink;
+ }
+ return (np);
+}
+
+/*
+ * Pretty print a name list
+ * Uncomment it if you need it.
+ */
+
+/*
+void
+prettyprint(name)
+ struct name *name;
+{
+ struct name *np;
+
+ np = name;
+ while (np != NULL) {
+ fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);
+ np = np->n_flink;
+ }
+ fprintf(stderr, "\n");
+}
+*/
diff --git a/mail_cmds/mail/pathnames.h b/mail_cmds/mail/pathnames.h
new file mode 100644
index 0000000..ea67572
--- /dev/null
+++ b/mail_cmds/mail/pathnames.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ *
+ * $FreeBSD: src/usr.bin/mail/pathnames.h,v 1.4 2001/05/27 20:26:22 mikeh Exp $
+ */
+
+#ifndef PATHNAMES_H
+#define PATHNAMES_H
+
+#define _PATH_EX "/usr/bin/ex"
+#define _PATH_HELP "/usr/share/misc/mail.help"
+#define _PATH_TILDE "/usr/share/misc/mail.tildehelp"
+#define _PATH_MASTER_RC "/usr/share/misc/mail.rc:/usr/local/etc/mail.rc:/etc/mail.rc"
+#define _PATH_MORE "/usr/bin/more"
+
+#endif /* PATHNAMES_H */
diff --git a/mail_cmds/mail/popen.c b/mail_cmds/mail/popen.c
new file mode 100644
index 0000000..979a76f
--- /dev/null
+++ b/mail_cmds/mail/popen.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/popen.c,v 1.7 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+#include <sys/cdefs.h>
+
+
+#include "rcv.h"
+#include <sys/wait.h>
+#include <fcntl.h>
+#include "extern.h"
+
+#define READ 0
+#define WRITE 1
+
+struct fp {
+ FILE *fp;
+ int pipe;
+ int pid;
+ struct fp *link;
+};
+static struct fp *fp_head;
+
+struct child {
+ int pid;
+ char done;
+ char free;
+ int status;
+ struct child *link;
+};
+static struct child *child;
+static struct child *findchild(int);
+static void delchild(struct child *);
+static int file_pid(FILE *);
+
+FILE *
+Fopen(path, mode)
+ const char *path, *mode;
+{
+ FILE *fp;
+
+ if ((fp = fopen(path, mode)) != NULL) {
+ register_file(fp, 0, 0);
+ (void)fcntl(fileno(fp), F_SETFD, 1);
+ }
+ return (fp);
+}
+
+FILE *
+Fdopen(fd, mode)
+ int fd;
+ const char *mode;
+{
+ FILE *fp;
+
+ if ((fp = fdopen(fd, mode)) != NULL) {
+ register_file(fp, 0, 0);
+ (void)fcntl(fileno(fp), F_SETFD, 1);
+ }
+ return (fp);
+}
+
+int
+Fclose(fp)
+ FILE *fp;
+{
+ unregister_file(fp);
+ return (fclose(fp));
+}
+
+FILE *
+Popen(cmd, mode)
+ char *cmd;
+ const char *mode;
+{
+ int p[2];
+ int myside, hisside, fd0, fd1;
+ int pid;
+ sigset_t nset;
+ FILE *fp;
+
+ if (pipe(p) < 0)
+ return (NULL);
+ (void)fcntl(p[READ], F_SETFD, 1);
+ (void)fcntl(p[WRITE], F_SETFD, 1);
+ if (*mode == 'r') {
+ myside = p[READ];
+ fd0 = -1;
+ hisside = fd1 = p[WRITE];
+ } else {
+ myside = p[WRITE];
+ hisside = fd0 = p[READ];
+ fd1 = -1;
+ }
+ (void)sigemptyset(&nset);
+ if ((pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL)) < 0) {
+ (void)close(p[READ]);
+ (void)close(p[WRITE]);
+ return (NULL);
+ }
+ (void)close(hisside);
+ if ((fp = fdopen(myside, mode)) != NULL)
+ register_file(fp, 1, pid);
+ return (fp);
+}
+
+int
+Pclose(ptr)
+ FILE *ptr;
+{
+ int i;
+ sigset_t nset, oset;
+
+ i = file_pid(ptr);
+ unregister_file(ptr);
+ (void)fclose(ptr);
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGINT);
+ (void)sigaddset(&nset, SIGHUP);
+ (void)sigprocmask(SIG_BLOCK, &nset, &oset);
+ i = wait_child(i);
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ return (i);
+}
+
+void
+close_all_files()
+{
+
+ while (fp_head != NULL)
+ if (fp_head->pipe)
+ (void)Pclose(fp_head->fp);
+ else
+ (void)Fclose(fp_head->fp);
+}
+
+void
+register_file(fp, pipe, pid)
+ FILE *fp;
+ int pipe, pid;
+{
+ struct fp *fpp;
+
+ if ((fpp = malloc(sizeof(*fpp))) == NULL)
+ err(1, "Out of memory");
+ fpp->fp = fp;
+ fpp->pipe = pipe;
+ fpp->pid = pid;
+ fpp->link = fp_head;
+ fp_head = fpp;
+}
+
+void
+unregister_file(fp)
+ FILE *fp;
+{
+ struct fp **pp, *p;
+
+ for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
+ if (p->fp == fp) {
+ *pp = p->link;
+ (void)free(p);
+ return;
+ }
+ errx(1, "Invalid file pointer");
+ /*NOTREACHED*/
+}
+
+int
+file_pid(fp)
+ FILE *fp;
+{
+ struct fp *p;
+
+ for (p = fp_head; p != NULL; p = p->link)
+ if (p->fp == fp)
+ return (p->pid);
+ errx(1, "Invalid file pointer");
+ /*NOTREACHED*/
+}
+
+/*
+ * Run a command without a shell, with optional arguments and splicing
+ * of stdin and stdout. The command name can be a sequence of words.
+ * Signals must be handled by the caller.
+ * "Mask" contains the signals to ignore in the new process.
+ * SIGINT is enabled unless it's in the mask.
+ */
+/*VARARGS4*/
+int
+run_command(cmd, mask, infd, outfd, a0, a1, a2)
+ char *cmd;
+ sigset_t *mask;
+ int infd, outfd;
+ char *a0, *a1, *a2;
+{
+ int pid;
+
+ if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
+ return (-1);
+ return (wait_command(pid));
+}
+
+/*VARARGS4*/
+int
+start_command(cmd, mask, infd, outfd, a0, a1, a2)
+ char *cmd;
+ sigset_t *mask;
+ int infd, outfd;
+ char *a0, *a1, *a2;
+{
+ int pid;
+
+ if ((pid = fork()) < 0) {
+ warn("fork");
+ return (-1);
+ }
+ if (pid == 0) {
+ char *argv[100];
+ int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv));
+
+ if ((argv[i++] = a0) != NULL &&
+ (argv[i++] = a1) != NULL &&
+ (argv[i++] = a2) != NULL)
+ argv[i] = NULL;
+ prepare_child(mask, infd, outfd);
+ execvp(argv[0], argv);
+ warn("%s", argv[0]);
+ _exit(1);
+ }
+ return (pid);
+}
+
+void
+prepare_child(nset, infd, outfd)
+ sigset_t *nset;
+ int infd, outfd;
+{
+ int i;
+ sigset_t eset;
+
+ /*
+ * All file descriptors other than 0, 1, and 2 are supposed to be
+ * close-on-exec.
+ */
+ if (infd >= 0)
+ dup2(infd, 0);
+ if (outfd >= 0)
+ dup2(outfd, 1);
+ for (i = 1; i < NSIG; i++)
+ if (nset != NULL && sigismember(nset, i))
+ (void)signal(i, SIG_IGN);
+ if (nset == NULL || !sigismember(nset, SIGINT))
+ (void)signal(SIGINT, SIG_DFL);
+ (void)sigemptyset(&eset);
+ (void)sigprocmask(SIG_SETMASK, &eset, NULL);
+}
+
+int
+wait_command(pid)
+ int pid;
+{
+
+ if (wait_child(pid) < 0) {
+ printf("Fatal error in process.\n");
+ return (-1);
+ }
+ return (0);
+}
+
+static struct child *
+findchild(pid)
+ int pid;
+{
+ struct child **cpp;
+
+ for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
+ cpp = &(*cpp)->link)
+ ;
+ if (*cpp == NULL) {
+ *cpp = malloc(sizeof(struct child));
+ if (*cpp == NULL)
+ err(1, "Out of memory");
+ (*cpp)->pid = pid;
+ (*cpp)->done = (*cpp)->free = 0;
+ (*cpp)->link = NULL;
+ }
+ return (*cpp);
+}
+
+static void
+delchild(cp)
+ struct child *cp;
+{
+ struct child **cpp;
+
+ for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
+ ;
+ *cpp = cp->link;
+ (void)free(cp);
+}
+
+/*ARGSUSED*/
+void
+sigchild(signo)
+ int signo;
+{
+ int pid;
+ int status;
+ struct child *cp;
+
+ while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
+ cp = findchild(pid);
+ if (cp->free)
+ delchild(cp);
+ else {
+ cp->done = 1;
+ cp->status = status;
+ }
+ }
+}
+
+int wait_status;
+
+/*
+ * Wait for a specific child to die.
+ */
+int
+wait_child(pid)
+ int pid;
+{
+ sigset_t nset, oset;
+ struct child *cp = findchild(pid);
+
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGCHLD);
+ (void)sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ while (!cp->done)
+ (void)sigsuspend(&oset);
+ wait_status = cp->status;
+ delchild(cp);
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ return ((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0);
+}
+
+/*
+ * Mark a child as don't care.
+ */
+void
+free_child(pid)
+ int pid;
+{
+ sigset_t nset, oset;
+ struct child *cp = findchild(pid);
+
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGCHLD);
+ (void)sigprocmask(SIG_BLOCK, &nset, &oset);
+
+ if (cp->done)
+ delchild(cp);
+ else
+ cp->free = 1;
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+}
diff --git a/mail_cmds/mail/quit.c b/mail_cmds/mail/quit.c
new file mode 100644
index 0000000..69d7db1
--- /dev/null
+++ b/mail_cmds/mail/quit.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)quit.c 8.2 (Berkeley) 4/28/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/quit.c,v 1.7 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Rcv -- receive mail rationally.
+ *
+ * Termination processing.
+ */
+
+/*
+ * The "quit" command.
+ */
+int
+quitcmd()
+{
+ /*
+ * If we are sourcing, then return 1 so execute() can handle it.
+ * Otherwise, return -1 to abort command loop.
+ */
+ if (sourcing)
+ return (1);
+ return (-1);
+}
+
+/*
+ * Save all of the undetermined messages at the top of "mbox"
+ * Save all untouched messages back in the system mailbox.
+ * Remove the system mailbox, if none saved there.
+ */
+void
+quit()
+{
+ int mcount, p, modify, autohold, anystat, holdbit, nohold;
+ FILE *ibuf = NULL, *obuf = NULL, *fbuf, *rbuf, *readstat = NULL, *abuf;
+ struct message *mp;
+ int c, fd;
+ struct stat minfo;
+ char *mbox, tempname[PATHSIZE];
+
+ /*
+ * If we are read only, we can't do anything,
+ * so just return quickly.
+ */
+ if (readonly)
+ return;
+ /*
+ * If editing (not reading system mail box), then do the work
+ * in edstop()
+ */
+ if (edit) {
+ edstop();
+ return;
+ }
+
+ /*
+ * See if there any messages to save in mbox. If no, we
+ * can save copying mbox to /tmp and back.
+ *
+ * Check also to see if any files need to be preserved.
+ * Delete all untouched messages to keep them out of mbox.
+ * If all the messages are to be preserved, just exit with
+ * a message.
+ */
+
+ fbuf = Fopen(mailname, "r");
+ if (fbuf == NULL)
+ goto newmail;
+ (void)flock(fileno(fbuf), LOCK_EX);
+ rbuf = NULL;
+ if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
+ printf("New mail has arrived.\n");
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RqXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (rbuf = Fdopen(fd, "w")) == NULL)
+ goto newmail;
+#ifdef APPEND
+ (void)fseeko(fbuf, mailsize, SEEK_SET);
+ while ((c = getc(fbuf)) != EOF)
+ (void)putc(c, rbuf);
+#else
+ p = minfo.st_size - mailsize;
+ while (p-- > 0) {
+ c = getc(fbuf);
+ if (c == EOF)
+ goto newmail;
+ (void)putc(c, rbuf);
+ }
+#endif
+ (void)Fclose(rbuf);
+ if ((rbuf = Fopen(tempname, "r")) == NULL)
+ goto newmail;
+ (void)rm(tempname);
+ }
+
+ /*
+ * Adjust the message flags in each message.
+ */
+
+ anystat = 0;
+ autohold = value("hold") != NULL;
+ holdbit = autohold ? MPRESERVE : MBOX;
+ nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
+ if (value("keepsave") != NULL)
+ nohold &= ~MSAVED;
+ for (mp = &message[0]; mp < &message[msgCount]; mp++) {
+ if (mp->m_flag & MNEW) {
+ mp->m_flag &= ~MNEW;
+ mp->m_flag |= MSTATUS;
+ }
+ if (mp->m_flag & MSTATUS)
+ anystat++;
+ if ((mp->m_flag & MTOUCH) == 0)
+ mp->m_flag |= MPRESERVE;
+ if ((mp->m_flag & nohold) == 0)
+ mp->m_flag |= holdbit;
+ }
+ modify = 0;
+ if (Tflag != NULL) {
+ if ((readstat = Fopen(Tflag, "w")) == NULL)
+ Tflag = NULL;
+ }
+ for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
+ if (mp->m_flag & MBOX)
+ c++;
+ if (mp->m_flag & MPRESERVE)
+ p++;
+ if (mp->m_flag & MODIFY)
+ modify++;
+ if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
+ char *id;
+
+ if ((id = hfield("article-id", mp)) != NULL)
+ fprintf(readstat, "%s\n", id);
+ }
+ }
+ if (Tflag != NULL)
+ (void)Fclose(readstat);
+ if (p == msgCount && !modify && !anystat) {
+ printf("Held %d message%s in %s\n",
+ p, p == 1 ? "" : "s", mailname);
+ (void)Fclose(fbuf);
+ return;
+ }
+ if (c == 0) {
+ if (p != 0) {
+ writeback(rbuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ goto cream;
+ }
+
+ /*
+ * Create another temporary file and copy user's mbox file
+ * darin. If there is no mbox, copy nothing.
+ * If he has specified "append" don't copy his mailbox,
+ * just copy saveable entries at the end.
+ */
+
+ mbox = expand("&");
+ mcount = c;
+ if (value("append") == NULL) {
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RmXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (obuf = Fdopen(fd, "w")) == NULL) {
+ warn("%s", tempname);
+ (void)Fclose(fbuf);
+ return;
+ }
+ if ((ibuf = Fopen(tempname, "r")) == NULL) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ (void)Fclose(obuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ (void)rm(tempname);
+ if ((abuf = Fopen(mbox, "r")) != NULL) {
+ while ((c = getc(abuf)) != EOF)
+ (void)putc(c, obuf);
+ (void)Fclose(abuf);
+ }
+ if (ferror(obuf)) {
+ warnx("%s", tempname);
+ (void)Fclose(ibuf);
+ (void)Fclose(obuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ (void)Fclose(obuf);
+ (void)close(open(mbox, O_CREAT | O_TRUNC | O_WRONLY, 0600));
+ if ((obuf = Fopen(mbox, "r+")) == NULL) {
+ warn("%s", mbox);
+ (void)Fclose(ibuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ }
+ if (value("append") != NULL) {
+ if ((obuf = Fopen(mbox, "a")) == NULL) {
+ warn("%s", mbox);
+ (void)Fclose(fbuf);
+ return;
+ }
+ (void)fchmod(fileno(obuf), 0600);
+ }
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if (mp->m_flag & MBOX)
+ if (sendmessage(mp, obuf, saveignore, NULL) < 0) {
+ warnx("%s", mbox);
+ (void)Fclose(ibuf);
+ (void)Fclose(obuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+
+ /*
+ * Copy the user's old mbox contents back
+ * to the end of the stuff we just saved.
+ * If we are appending, this is unnecessary.
+ */
+
+ if (value("append") == NULL) {
+ rewind(ibuf);
+ c = getc(ibuf);
+ while (c != EOF) {
+ (void)putc(c, obuf);
+ if (ferror(obuf))
+ break;
+ c = getc(ibuf);
+ }
+ (void)Fclose(ibuf);
+ }
+ (void)fflush(obuf);
+ trunc(obuf);
+ if (ferror(obuf)) {
+ warn("%s", mbox);
+ (void)Fclose(obuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ (void)Fclose(obuf);
+ if (mcount == 1)
+ printf("Saved 1 message in mbox\n");
+ else
+ printf("Saved %d messages in mbox\n", mcount);
+
+ /*
+ * Now we are ready to copy back preserved files to
+ * the system mailbox, if any were requested.
+ */
+
+ if (p != 0) {
+ writeback(rbuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+
+ /*
+ * Finally, remove his /var/mail file.
+ * If new mail has arrived, copy it back.
+ */
+
+cream:
+ if (rbuf != NULL) {
+ abuf = Fopen(mailname, "r+");
+ if (abuf == NULL)
+ goto newmail;
+ while ((c = getc(rbuf)) != EOF)
+ (void)putc(c, abuf);
+ (void)Fclose(rbuf);
+ trunc(abuf);
+ (void)Fclose(abuf);
+ alter(mailname);
+ (void)Fclose(fbuf);
+ return;
+ }
+ demail();
+ (void)Fclose(fbuf);
+ return;
+
+newmail:
+ printf("Thou hast new mail.\n");
+ if (fbuf != NULL)
+ (void)Fclose(fbuf);
+}
+
+/*
+ * Preserve all the appropriate messages back in the system
+ * mailbox, and print a nice message indicated how many were
+ * saved. On any error, just return -1. Else return 0.
+ * Incorporate the any new mail that we found.
+ */
+int
+writeback(res)
+ FILE *res;
+{
+ struct message *mp;
+ int p, c;
+ FILE *obuf;
+
+ p = 0;
+ if ((obuf = Fopen(mailname, "r+")) == NULL) {
+ warn("%s", mailname);
+ return (-1);
+ }
+#ifndef APPEND
+ if (res != NULL)
+ while ((c = getc(res)) != EOF)
+ (void)putc(c, obuf);
+#endif
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
+ p++;
+ if (sendmessage(mp, obuf, NULL, NULL) < 0) {
+ warnx("%s", mailname);
+ (void)Fclose(obuf);
+ return (-1);
+ }
+ }
+#ifdef APPEND
+ if (res != NULL)
+ while ((c = getc(res)) != EOF)
+ (void)putc(c, obuf);
+#endif
+ (void)fflush(obuf);
+ trunc(obuf);
+ if (ferror(obuf)) {
+ warn("%s", mailname);
+ (void)Fclose(obuf);
+ return (-1);
+ }
+ if (res != NULL)
+ (void)Fclose(res);
+ (void)Fclose(obuf);
+ alter(mailname);
+ if (p == 1)
+ printf("Held 1 message in %s\n", mailname);
+ else
+ printf("Held %d messages in %s\n", p, mailname);
+ return (0);
+}
+
+/*
+ * Terminate an editing session by attempting to write out the user's
+ * file from the temporary. Save any new stuff appended to the file.
+ */
+void
+edstop()
+{
+ int gotcha, c;
+ struct message *mp;
+ FILE *obuf, *ibuf, *readstat = NULL;
+ struct stat statb;
+ char tempname[PATHSIZE];
+
+ if (readonly)
+ return;
+ holdsigs();
+ if (Tflag != NULL) {
+ if ((readstat = Fopen(Tflag, "w")) == NULL)
+ Tflag = NULL;
+ }
+ for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
+ if (mp->m_flag & MNEW) {
+ mp->m_flag &= ~MNEW;
+ mp->m_flag |= MSTATUS;
+ }
+ if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
+ gotcha++;
+ if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
+ char *id;
+
+ if ((id = hfield("article-id", mp)) != NULL)
+ fprintf(readstat, "%s\n", id);
+ }
+ }
+ if (Tflag != NULL)
+ (void)Fclose(readstat);
+ if (!gotcha || Tflag != NULL)
+ goto done;
+ ibuf = NULL;
+ if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
+ int fd;
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mbox.XXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (obuf = Fdopen(fd, "w")) == NULL) {
+ warn("%s", tempname);
+ relsesigs();
+ reset(0);
+ }
+ if ((ibuf = Fopen(mailname, "r")) == NULL) {
+ warn("%s", mailname);
+ (void)Fclose(obuf);
+ (void)rm(tempname);
+ relsesigs();
+ reset(0);
+ }
+ (void)fseeko(ibuf, mailsize, SEEK_SET);
+ while ((c = getc(ibuf)) != EOF)
+ (void)putc(c, obuf);
+ (void)Fclose(ibuf);
+ (void)Fclose(obuf);
+ if ((ibuf = Fopen(tempname, "r")) == NULL) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ relsesigs();
+ reset(0);
+ }
+ (void)rm(tempname);
+ }
+ printf("\"%s\" ", mailname);
+ (void)fflush(stdout);
+ if ((obuf = Fopen(mailname, "r+")) == NULL) {
+ warn("%s", mailname);
+ relsesigs();
+ reset(0);
+ }
+ trunc(obuf);
+ c = 0;
+ for (mp = &message[0]; mp < &message[msgCount]; mp++) {
+ if ((mp->m_flag & MDELETED) != 0)
+ continue;
+ c++;
+ if (sendmessage(mp, obuf, NULL, NULL) < 0) {
+ warnx("%s", mailname);
+ relsesigs();
+ reset(0);
+ }
+ }
+ gotcha = (c == 0 && ibuf == NULL);
+ if (ibuf != NULL) {
+ while ((c = getc(ibuf)) != EOF)
+ (void)putc(c, obuf);
+ (void)Fclose(ibuf);
+ }
+ (void)fflush(obuf);
+ if (ferror(obuf)) {
+ warn("%s", mailname);
+ relsesigs();
+ reset(0);
+ }
+ (void)Fclose(obuf);
+ if (gotcha) {
+ if (value("keep") == NULL) {
+ (void)rm(mailname);
+ printf("removed\n");
+ } else { /* leave truncated file there */
+ printf("is empty\n");
+ }
+ } else
+ printf("complete\n");
+ (void)fflush(stdout);
+
+done:
+ relsesigs();
+}
diff --git a/mail_cmds/mail/rcv.h b/mail_cmds/mail/rcv.h
new file mode 100644
index 0000000..b8269b8
--- /dev/null
+++ b/mail_cmds/mail/rcv.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rcv.h 8.1 (Berkeley) 6/6/93
+ *
+ * $FreeBSD: src/usr.bin/mail/rcv.h,v 1.2 2001/03/25 04:57:04 mikeh Exp $
+ */
+
+#ifndef RCV_H
+#define RCV_H
+
+/*
+ * Mail -- a mail program
+ *
+ * This file is included by normal files which want both
+ * globals and declarations.
+ */
+
+#include "def.h"
+#include "glob.h"
+
+#endif /* RCV_H */
+
diff --git a/mail_cmds/mail/send.c b/mail_cmds/mail/send.c
new file mode 100644
index 0000000..466bd65
--- /dev/null
+++ b/mail_cmds/mail/send.c
@@ -0,0 +1,629 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/send.c,v 1.14 2004/02/29 20:44:44 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Mail to others.
+ */
+
+/*
+ * Send message described by the passed pointer to the
+ * passed output buffer. Return -1 on error.
+ * Adjust the status: field if need be.
+ * If doign is given, suppress ignored header fields.
+ * prefix is a string to prepend to each output line.
+ */
+int
+sendmessage(mp, obuf, doign, prefix)
+ struct message *mp;
+ FILE *obuf;
+ struct ignoretab *doign;
+ char *prefix;
+{
+ long count;
+ FILE *ibuf;
+ char *cp, *cp2, line[LINESIZE];
+ int ishead, infld, ignoring = 0, dostat, firstline;
+ int c = 0, length, prefixlen = 0;
+
+ /*
+ * Compute the prefix string, without trailing whitespace
+ */
+ if (prefix != NULL) {
+ cp2 = 0;
+ for (cp = prefix; *cp != '\0'; cp++)
+ if (*cp != ' ' && *cp != '\t')
+ cp2 = cp;
+ prefixlen = cp2 == NULL ? 0 : cp2 - prefix + 1;
+ }
+ ibuf = setinput(mp);
+ count = mp->m_size;
+ ishead = 1;
+ dostat = doign == 0 || !isign("status", doign);
+ infld = 0;
+ firstline = 1;
+ /*
+ * Process headers first
+ */
+ while (count > 0 && ishead) {
+ if (fgets(line, sizeof(line), ibuf) == NULL)
+ break;
+ count -= length = strlen(line);
+ if (firstline) {
+ /*
+ * First line is the From line, so no headers
+ * there to worry about
+ */
+ firstline = 0;
+ ignoring = doign == ignoreall;
+ } else if (line[0] == '\n') {
+ /*
+ * If line is blank, we've reached end of
+ * headers, so force out status: field
+ * and note that we are no longer in header
+ * fields
+ */
+ if (dostat) {
+ statusput(mp, obuf, prefix);
+ dostat = 0;
+ }
+ ishead = 0;
+ ignoring = doign == ignoreall;
+ } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
+ /*
+ * If this line is a continuation (via space or tab)
+ * of a previous header field, just echo it
+ * (unless the field should be ignored).
+ * In other words, nothing to do.
+ */
+ } else {
+ /*
+ * Pick up the header field if we have one.
+ */
+ for (cp = line; (c = *cp++) != '\0' && c != ':' &&
+ !isspace((unsigned char)c);)
+ ;
+ cp2 = --cp;
+ while (isspace((unsigned char)*cp++))
+ ;
+ if (cp[-1] != ':') {
+ /*
+ * Not a header line, force out status:
+ * This happens in uucp style mail where
+ * there are no headers at all.
+ */
+ if (dostat) {
+ statusput(mp, obuf, prefix);
+ dostat = 0;
+ }
+ if (doign != ignoreall)
+ /* add blank line */
+ (void)putc('\n', obuf);
+ ishead = 0;
+ ignoring = 0;
+ } else {
+ /*
+ * If it is an ignored field and
+ * we care about such things, skip it.
+ */
+ *cp2 = '\0'; /* temporarily null terminate */
+ if (doign && isign(line, doign))
+ ignoring = 1;
+ else if ((line[0] == 's' || line[0] == 'S') &&
+ strcasecmp(line, "status") == 0) {
+ /*
+ * If the field is "status," go compute
+ * and print the real Status: field
+ */
+ if (dostat) {
+ statusput(mp, obuf, prefix);
+ dostat = 0;
+ }
+ ignoring = 1;
+ } else {
+ ignoring = 0;
+ *cp2 = c; /* restore */
+ }
+ infld = 1;
+ }
+ }
+ if (!ignoring) {
+ /*
+ * Strip trailing whitespace from prefix
+ * if line is blank.
+ */
+ if (prefix != NULL) {
+ if (length > 1)
+ fputs(prefix, obuf);
+ else
+ (void)fwrite(prefix, sizeof(*prefix),
+ prefixlen, obuf);
+ }
+ (void)fwrite(line, sizeof(*line), length, obuf);
+ if (ferror(obuf))
+ return (-1);
+ }
+ }
+ /*
+ * Copy out message body
+ */
+ if (doign == ignoreall)
+ count--; /* skip final blank line */
+ if (prefix != NULL)
+ while (count > 0) {
+ if (fgets(line, sizeof(line), ibuf) == NULL) {
+ c = 0;
+ break;
+ }
+ count -= c = strlen(line);
+ /*
+ * Strip trailing whitespace from prefix
+ * if line is blank.
+ */
+ if (c > 1)
+ fputs(prefix, obuf);
+ else
+ (void)fwrite(prefix, sizeof(*prefix),
+ prefixlen, obuf);
+ (void)fwrite(line, sizeof(*line), c, obuf);
+ if (ferror(obuf))
+ return (-1);
+ }
+ else
+ while (count > 0) {
+ c = count < LINESIZE ? count : LINESIZE;
+ if ((c = fread(line, sizeof(*line), c, ibuf)) <= 0)
+ break;
+ count -= c;
+ if (fwrite(line, sizeof(*line), c, obuf) != c)
+ return (-1);
+ }
+ if (doign == ignoreall && c > 0 && line[c - 1] != '\n')
+ /* no final blank line */
+ if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Output a reasonable looking status field.
+ */
+void
+statusput(mp, obuf, prefix)
+ struct message *mp;
+ FILE *obuf;
+ char *prefix;
+{
+ char statout[3];
+ char *cp = statout;
+
+ if (mp->m_flag & MREAD)
+ *cp++ = 'R';
+ if ((mp->m_flag & MNEW) == 0)
+ *cp++ = 'O';
+ *cp = '\0';
+ if (statout[0] != '\0')
+ fprintf(obuf, "%sStatus: %s\n",
+ prefix == NULL ? "" : prefix, statout);
+}
+
+/*
+ * Interface between the argument list and the mail1 routine
+ * which does all the dirty work.
+ */
+int
+mail(to, cc, bcc, smopts, subject, replyto)
+ struct name *to, *cc, *bcc, *smopts;
+ char *subject, *replyto;
+{
+ struct header head;
+
+ head.h_to = to;
+ head.h_subject = subject;
+ head.h_cc = cc;
+ head.h_bcc = bcc;
+ head.h_smopts = smopts;
+ head.h_replyto = replyto;
+ head.h_inreplyto = NULL;
+ mail1(&head, 0);
+ return (0);
+}
+
+
+/*
+ * Send mail to a bunch of user names. The interface is through
+ * the mail routine below.
+ */
+int
+sendmail(str)
+ char *str;
+{
+ struct header head;
+
+ head.h_to = extract(str, GTO);
+ head.h_subject = NULL;
+ head.h_cc = NULL;
+ head.h_bcc = NULL;
+ head.h_smopts = NULL;
+ head.h_replyto = value("REPLYTO");
+ head.h_inreplyto = NULL;
+ mail1(&head, 0);
+ return (0);
+}
+
+/*
+ * Mail a message on standard input to the people indicated
+ * in the passed header. (Internal interface).
+ */
+void
+mail1(hp, printheaders)
+ struct header *hp;
+ int printheaders;
+{
+ char *cp;
+ char *nbuf;
+ int pid;
+ char **namelist;
+ struct name *to, *nsto = NULL;
+ FILE *mtf;
+
+ /*
+ * Collect user's mail from standard input.
+ * Get the result as mtf.
+ */
+ if ((mtf = collect(hp, printheaders)) == NULL)
+ return;
+ if (value("interactive") != NULL) {
+ if (value("askcc") != NULL || value("askbcc") != NULL) {
+ if (value("askcc") != NULL)
+ grabh(hp, GCC);
+ if (value("askbcc") != NULL)
+ grabh(hp, GBCC);
+ } else {
+ printf("EOT\n");
+ (void)fflush(stdout);
+ }
+ }
+ if (fsize(mtf) == 0) {
+ if (value("dontsendempty") != NULL)
+ goto out;
+ if (hp->h_subject == NULL)
+ printf("No message, no subject; hope that's ok\n");
+ else
+ printf("Null message body; hope that's ok\n");
+ }
+ /*
+ * Now, take the user names from the combined
+ * to and cc lists and do all the alias
+ * processing.
+ */
+ senderr = 0;
+ to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
+ if (to == NULL) {
+ printf("No recipients specified\n");
+ senderr++;
+ }
+ /*
+ * Look through the recipient list for names with /'s
+ * in them which we write to as files directly.
+ */
+ to = outof(to, mtf, hp);
+ if (senderr)
+ savedeadletter(mtf);
+ to = elide(to);
+ if (count(to) == 0)
+ goto out;
+ if (value("recordrecip") != NULL) {
+ /*
+ * Before fixing the header, save old To:.
+ * We do this because elide above has sorted To: list, and
+ * we would like to save message in a file named by the first
+ * recipient the user has entered, not the one being the first
+ * after sorting happened.
+ */
+ if ((nsto = malloc(sizeof(struct name))) == NULL)
+ err(1, "Out of memory");
+ bcopy(hp->h_to, nsto, sizeof(struct name));
+ }
+ fixhead(hp, to);
+ if ((mtf = infix(hp, mtf)) == NULL) {
+ fprintf(stderr, ". . . message lost, sorry.\n");
+ return;
+ }
+ namelist = unpack(cat(hp->h_smopts, to));
+ if (debug) {
+ char **t;
+
+ printf("Sendmail arguments:");
+ for (t = namelist; *t != NULL; t++)
+ printf(" \"%s\"", *t);
+ printf("\n");
+ goto out;
+ }
+ if (value("recordrecip") != NULL) {
+ /*
+ * Extract first recipient username from saved To: and use it
+ * as a filename.
+ */
+ if ((nbuf = malloc(strlen(detract(nsto, 0)) + 1)) == NULL)
+ err(1, "Out of memory");
+ if ((cp = yanklogin(detract(nsto, 0), nbuf)) != NULL)
+ (void)savemail(expand(nbuf), mtf);
+ free(nbuf);
+ free(nsto);
+ } else if ((cp = value("record")) != NULL) {
+ char * expanded_record_name = expand(cp);
+ char * outfolder = value("outfolder");
+ if ((outfolder != NULL) && (*expanded_record_name != '/')) {
+ char xname[PATHSIZE];
+ if (getfold(xname, sizeof(xname)) >= 0) {
+ if (xname[strlen(xname)-1] != '/')
+ strlcat(xname, "/", sizeof(xname)); /* only when needed */
+ strlcat(xname, expanded_record_name, sizeof(xname));
+ (void)savemail(xname, mtf);
+ } else { /* folder problem? - just save using "record" */
+ (void)savemail(expanded_record_name, mtf);
+ }
+ } else {
+ (void)savemail(expanded_record_name, mtf);
+ }
+ }
+ /*
+ * Fork, set up the temporary mail file as standard
+ * input for "mail", and exec with the user list we generated
+ * far above.
+ */
+ pid = fork();
+ if (pid == -1) {
+ warn("fork");
+ savedeadletter(mtf);
+ goto out;
+ }
+ if (pid == 0) {
+ sigset_t nset;
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGHUP);
+ (void)sigaddset(&nset, SIGINT);
+ (void)sigaddset(&nset, SIGQUIT);
+ (void)sigaddset(&nset, SIGTSTP);
+ (void)sigaddset(&nset, SIGTTIN);
+ (void)sigaddset(&nset, SIGTTOU);
+ prepare_child(&nset, fileno(mtf), -1);
+ if ((cp = value("sendmail")) != NULL)
+ cp = expand(cp);
+ else
+ cp = _PATH_SENDMAIL;
+ execv(cp, namelist);
+ warn("%s", cp);
+ _exit(1);
+ }
+ if (value("verbose") != NULL)
+ (void)wait_child(pid);
+ else
+ free_child(pid);
+out:
+ (void)Fclose(mtf);
+}
+
+/*
+ * Fix the header by glopping all of the expanded names from
+ * the distribution list into the appropriate fields.
+ */
+void
+fixhead(hp, tolist)
+ struct header *hp;
+ struct name *tolist;
+{
+ struct name *np;
+
+ hp->h_to = NULL;
+ hp->h_cc = NULL;
+ hp->h_bcc = NULL;
+ for (np = tolist; np != NULL; np = np->n_flink) {
+ /* Don't copy deleted addresses to the header */
+ if (np->n_type & GDEL)
+ continue;
+ if ((np->n_type & GMASK) == GTO)
+ hp->h_to =
+ cat(hp->h_to, nalloc(np->n_name, np->n_type));
+ else if ((np->n_type & GMASK) == GCC)
+ hp->h_cc =
+ cat(hp->h_cc, nalloc(np->n_name, np->n_type));
+ else if ((np->n_type & GMASK) == GBCC)
+ hp->h_bcc =
+ cat(hp->h_bcc, nalloc(np->n_name, np->n_type));
+ }
+}
+
+/*
+ * Prepend a header in front of the collected stuff
+ * and return the new file.
+ */
+FILE *
+infix(hp, fi)
+ struct header *hp;
+ FILE *fi;
+{
+ FILE *nfo, *nfi;
+ int c, fd;
+ char tempname[PATHSIZE];
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RsXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (nfo = Fdopen(fd, "w")) == NULL) {
+ warn("%s", tempname);
+ return (fi);
+ }
+ if ((nfi = Fopen(tempname, "r")) == NULL) {
+ warn("%s", tempname);
+ (void)Fclose(nfo);
+ (void)rm(tempname);
+ return (fi);
+ }
+ (void)rm(tempname);
+ (void)puthead(hp, nfo,
+ GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO|GNL|GCOMMA);
+ c = getc(fi);
+ while (c != EOF) {
+ (void)putc(c, nfo);
+ c = getc(fi);
+ }
+ if (ferror(fi)) {
+ warnx("read");
+ rewind(fi);
+ return (fi);
+ }
+ (void)fflush(nfo);
+ if (ferror(nfo)) {
+ warn("%s", tempname);
+ (void)Fclose(nfo);
+ (void)Fclose(nfi);
+ rewind(fi);
+ return (fi);
+ }
+ (void)Fclose(nfo);
+ (void)Fclose(fi);
+ rewind(nfi);
+ return (nfi);
+}
+
+/*
+ * Dump the to, subject, cc header on the
+ * passed file buffer.
+ */
+int
+puthead(hp, fo, w)
+ struct header *hp;
+ FILE *fo;
+ int w;
+{
+ int gotcha;
+
+ gotcha = 0;
+ if (hp->h_to != NULL && w & GTO)
+ fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++;
+ if (hp->h_subject != NULL && w & GSUBJECT)
+ fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
+ if (hp->h_cc != NULL && w & GCC)
+ fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++;
+ if (hp->h_bcc != NULL && w & GBCC)
+ fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++;
+ if (hp->h_replyto != NULL && w & GREPLYTO)
+ fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++;
+ if (hp->h_inreplyto != NULL && w & GINREPLYTO)
+ fprintf(fo, "In-Reply-To: <%s>\n", hp->h_inreplyto), gotcha++;
+ if (gotcha && w & GNL)
+ (void)putc('\n', fo);
+ return (0);
+}
+
+/*
+ * Format the given header line to not exceed 72 characters.
+ */
+void
+fmt(str, np, fo, comma)
+ const char *str;
+ struct name *np;
+ FILE *fo;
+ int comma;
+{
+ int col, len;
+
+ comma = comma ? 1 : 0;
+ col = strlen(str);
+ if (col)
+ fputs(str, fo);
+ for (; np != NULL; np = np->n_flink) {
+ if (np->n_flink == NULL)
+ comma = 0;
+ len = strlen(np->n_name);
+ col++; /* for the space */
+ if (col + len + comma > 72 && col > 4) {
+ fprintf(fo, "\n ");
+ col = 4;
+ } else
+ fprintf(fo, " ");
+ fputs(np->n_name, fo);
+ if (comma)
+ fprintf(fo, ",");
+ col += len + comma;
+ }
+ fprintf(fo, "\n");
+}
+
+/*
+ * Save the outgoing mail on the passed file.
+ */
+
+/*ARGSUSED*/
+int
+savemail(name, fi)
+ char name[];
+ FILE *fi;
+{
+ FILE *fo;
+ char buf[BUFSIZ];
+ int i;
+ time_t now;
+
+ if ((fo = Fopen(name, "a")) == NULL) {
+ warn("%s", name);
+ return (-1);
+ }
+ (void)time(&now);
+ fprintf(fo, "From %s %s", myname, ctime(&now));
+ while ((i = fread(buf, 1, sizeof(buf), fi)) > 0)
+ (void)fwrite(buf, 1, i, fo);
+ fprintf(fo, "\n");
+ (void)fflush(fo);
+ if (ferror(fo))
+ warn("%s", name);
+ (void)Fclose(fo);
+ rewind(fi);
+ return (0);
+}
diff --git a/mail_cmds/mail/strings.c b/mail_cmds/mail/strings.c
new file mode 100644
index 0000000..6b4fc6b
--- /dev/null
+++ b/mail_cmds/mail/strings.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)strings.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/strings.c,v 1.5 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * String allocation routines.
+ * Strings handed out here are reclaimed at the top of the command
+ * loop each time, so they need not be freed.
+ */
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Allocate size more bytes of space and return the address of the
+ * first byte to the caller. An even number of bytes are always
+ * allocated so that the space will always be on a word boundary.
+ * The string spaces are of exponentially increasing size, to satisfy
+ * the occasional user with enormous string size requests.
+ */
+
+char *
+salloc(size)
+ int size;
+{
+ char *t;
+ int s, index;
+ struct strings *sp;
+
+ s = size;
+ s += (sizeof(char *) - 1);
+ s &= ~(sizeof(char *) - 1);
+ index = 0;
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) {
+ if (sp->s_topFree == NULL && (STRINGSIZE << index) >= s)
+ break;
+ if (sp->s_nleft >= s)
+ break;
+ index++;
+ }
+ if (sp >= &stringdope[NSPACE])
+ errx(1, "String too large");
+ if (sp->s_topFree == NULL) {
+ index = sp - &stringdope[0];
+ if ((sp->s_topFree = malloc(STRINGSIZE << index)) == NULL)
+ err(1, "No room for space %d", index);
+ sp->s_nextFree = sp->s_topFree;
+ sp->s_nleft = STRINGSIZE << index;
+ }
+ sp->s_nleft -= s;
+ t = sp->s_nextFree;
+ sp->s_nextFree += s;
+ return (t);
+}
+
+/*
+ * Reset the string area to be empty.
+ * Called to free all strings allocated
+ * since last reset.
+ */
+void
+sreset()
+{
+ struct strings *sp;
+ int index;
+
+ if (noreset)
+ return;
+ index = 0;
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) {
+ if (sp->s_topFree == NULL)
+ continue;
+ sp->s_nextFree = sp->s_topFree;
+ sp->s_nleft = STRINGSIZE << index;
+ index++;
+ }
+}
+
+/*
+ * Make the string area permanent.
+ * Meant to be called in main, after initialization.
+ */
+void
+spreserve()
+{
+ struct strings *sp;
+
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++)
+ sp->s_topFree = NULL;
+}
diff --git a/mail_cmds/mail/strlcpy.c b/mail_cmds/mail/strlcpy.c
new file mode 100644
index 0000000..9de9d32
--- /dev/null
+++ b/mail_cmds/mail/strlcpy.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.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.
+ * 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 ``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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/lib/libc/string/strlcpy.c,v 1.2.4.1 2001/07/09 23:30:06 obrien Exp $";
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/mail_cmds/mail/temp.c b/mail_cmds/mail/temp.c
new file mode 100644
index 0000000..8b2195d
--- /dev/null
+++ b/mail_cmds/mail/temp.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)temp.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/temp.c,v 1.9 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Give names to all the temporary files that we will need.
+ */
+
+char *tmpdir;
+
+void
+tinit()
+{
+ char *cp;
+
+ if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
+ tmpdir = _PATH_TMP;
+ if ((tmpdir = strdup(tmpdir)) == NULL)
+ errx(1, "Out of memory");
+ /* Strip trailing '/' if necessary */
+ cp = tmpdir + strlen(tmpdir) - 1;
+ while (cp > tmpdir && *cp == '/') {
+ *cp = '\0';
+ cp--;
+ }
+
+ /*
+ * It's okay to call savestr in here because main will
+ * do a spreserve() after us.
+ */
+ if (myname != NULL) {
+ if (getuserid(myname) < 0)
+ errx(1, "\"%s\" is not a user of this system", myname);
+ } else {
+ if ((cp = username()) == NULL) {
+ myname = "ubluit";
+ if (rcvmode)
+ errx(1, "Who are you!?");
+ } else
+ myname = savestr(cp);
+ }
+ if ((cp = getenv("HOME")) == NULL || *cp == '\0' ||
+ strlen(cp) >= PATHSIZE)
+ homedir = NULL;
+ else
+ homedir = savestr(cp);
+ if (debug)
+ fprintf(stderr, "user = %s, homedir = %s\n", myname,
+ homedir ? homedir : "NONE");
+}
diff --git a/mail_cmds/mail/tty.c b/mail_cmds/mail/tty.c
new file mode 100644
index 0000000..77e9e0d
--- /dev/null
+++ b/mail_cmds/mail/tty.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/tty.c,v 1.6 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Generally useful tty stuff.
+ */
+
+#include "rcv.h"
+#include "extern.h"
+
+static cc_t c_erase; /* Current erase char */
+static cc_t c_kill; /* Current kill char */
+static jmp_buf rewrite; /* Place to go when continued */
+static jmp_buf intjmp; /* Place to go when interrupted */
+#ifndef TIOCSTI
+static int ttyset; /* We must now do erase/kill */
+#endif
+
+/*
+ * Read all relevant header fields.
+ */
+
+int
+grabh(hp, gflags)
+ struct header *hp;
+ int gflags;
+{
+ struct termios ttybuf;
+ sig_t saveint;
+ sig_t savetstp;
+ sig_t savettou;
+ sig_t savettin;
+ int errs;
+#ifndef TIOCSTI
+ sig_t savequit;
+#else
+# ifdef TIOCEXT
+ int extproc, flag;
+# endif /* TIOCEXT */
+#endif /* TIOCSTI */
+
+ savetstp = signal(SIGTSTP, SIG_DFL);
+ savettou = signal(SIGTTOU, SIG_DFL);
+ savettin = signal(SIGTTIN, SIG_DFL);
+ errs = 0;
+#ifndef TIOCSTI
+ ttyset = 0;
+#endif
+ if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
+ warn("tcgetattr(stdin)");
+ return (-1);
+ }
+ c_erase = ttybuf.c_cc[VERASE];
+ c_kill = ttybuf.c_cc[VKILL];
+#ifndef TIOCSTI
+ ttybuf.c_cc[VERASE] = _POSIX_VDISABLE;
+ ttybuf.c_cc[VKILL] = _POSIX_VDISABLE;
+ if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
+ (void)signal(SIGINT, SIG_DFL);
+ if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
+ (void)signal(SIGQUIT, SIG_DFL);
+#else
+# ifdef TIOCEXT
+ extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
+ if (extproc) {
+ flag = 0;
+ if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
+ warn("TIOCEXT: off");
+ }
+# endif /* TIOCEXT */
+ saveint = signal(SIGINT, ttyint);
+ if (setjmp(intjmp)) {
+ /* Interrupt from headers needs to be told to caller */
+ errs++;
+ goto out;
+ }
+#endif
+ if (gflags & GTO) {
+#ifndef TIOCSTI
+ if (!ttyset && hp->h_to != NULL)
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
+#endif
+ hp->h_to =
+ extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
+ }
+ if (gflags & GSUBJECT) {
+#ifndef TIOCSTI
+ if (!ttyset && hp->h_subject != NULL)
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
+#endif
+ hp->h_subject = readtty("Subject: ", hp->h_subject);
+ }
+ if (gflags & GCC) {
+#ifndef TIOCSTI
+ if (!ttyset && hp->h_cc != NULL)
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
+#endif
+ hp->h_cc =
+ extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
+ }
+ if (gflags & GBCC) {
+#ifndef TIOCSTI
+ if (!ttyset && hp->h_bcc != NULL)
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
+#endif
+ hp->h_bcc =
+ extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
+ }
+out:
+ (void)signal(SIGTSTP, savetstp);
+ (void)signal(SIGTTOU, savettou);
+ (void)signal(SIGTTIN, savettin);
+#ifndef TIOCSTI
+ ttybuf.c_cc[VERASE] = c_erase;
+ ttybuf.c_cc[VKILL] = c_kill;
+ if (ttyset)
+ tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
+ (void)signal(SIGQUIT, savequit);
+#else
+# ifdef TIOCEXT
+ if (extproc) {
+ flag = 1;
+ if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
+ warn("TIOCEXT: on");
+ }
+# endif /* TIOCEXT */
+#endif
+ (void)signal(SIGINT, saveint);
+ return (errs);
+}
+
+/*
+ * Read up a header from standard input.
+ * The source string has the preliminary contents to
+ * be read.
+ *
+ */
+
+char *
+readtty(pr, src)
+ const char *pr;
+ char src[];
+{
+ char ch, canonb[BUFSIZ];
+ int c;
+ char *cp, *cp2;
+
+ fputs(pr, stdout);
+ (void)fflush(stdout);
+ if (src != NULL && strlen(src) > BUFSIZ - 2) {
+ printf("too long to edit\n");
+ return (src);
+ }
+#ifndef TIOCSTI
+ if (src != NULL)
+ strlcpy(canonb, src, sizeof(canonb));
+ else
+ *canonb = '\0';
+ fputs(canonb, stdout);
+ (void)fflush(stdout);
+#else
+ cp = src == NULL ? "" : src;
+ while ((c = *cp++) != '\0') {
+ if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
+ (c_kill != _POSIX_VDISABLE && c == c_kill)) {
+ ch = '\\';
+ ioctl(0, TIOCSTI, &ch);
+ }
+ ch = c;
+ ioctl(0, TIOCSTI, &ch);
+ }
+ cp = canonb;
+ *cp = '\0';
+#endif
+ cp2 = cp;
+ while (cp2 < canonb + BUFSIZ)
+ *cp2++ = '\0';
+ cp2 = cp;
+ if (setjmp(rewrite))
+ goto redo;
+ (void)signal(SIGTSTP, ttystop);
+ (void)signal(SIGTTOU, ttystop);
+ (void)signal(SIGTTIN, ttystop);
+ clearerr(stdin);
+ while (cp2 < canonb + BUFSIZ) {
+ c = getc(stdin);
+ if (c == EOF || c == '\n')
+ break;
+ *cp2++ = c;
+ }
+ *cp2 = '\0';
+ (void)signal(SIGTSTP, SIG_DFL);
+ (void)signal(SIGTTOU, SIG_DFL);
+ (void)signal(SIGTTIN, SIG_DFL);
+ if (c == EOF && ferror(stdin)) {
+redo:
+ cp = strlen(canonb) > 0 ? canonb : NULL;
+ clearerr(stdin);
+ return (readtty(pr, cp));
+ }
+#ifndef TIOCSTI
+ if (cp == NULL || *cp == '\0')
+ return (src);
+ cp2 = cp;
+ if (!ttyset)
+ return (strlen(canonb) > 0 ? savestr(canonb) : NULL);
+ while (*cp != '\0') {
+ c = *cp++;
+ if (c_erase != _POSIX_VDISABLE && c == c_erase) {
+ if (cp2 == canonb)
+ continue;
+ if (cp2[-1] == '\\') {
+ cp2[-1] = c;
+ continue;
+ }
+ cp2--;
+ continue;
+ }
+ if (c_kill != _POSIX_VDISABLE && c == c_kill) {
+ if (cp2 == canonb)
+ continue;
+ if (cp2[-1] == '\\') {
+ cp2[-1] = c;
+ continue;
+ }
+ cp2 = canonb;
+ continue;
+ }
+ *cp2++ = c;
+ }
+ *cp2 = '\0';
+#endif
+ if (equal("", canonb))
+ return (NULL);
+ return (savestr(canonb));
+}
+
+/*
+ * Receipt continuation.
+ */
+void
+ttystop(s)
+ int s;
+{
+ sig_t old_action = signal(s, SIG_DFL);
+ sigset_t nset;
+
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, s);
+ (void)sigprocmask(SIG_BLOCK, &nset, NULL);
+ kill(0, s);
+ (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+ (void)signal(s, old_action);
+ longjmp(rewrite, 1);
+}
+
+/*ARGSUSED*/
+void
+ttyint(s)
+ int s;
+{
+ longjmp(intjmp, 1);
+}
diff --git a/mail_cmds/mail/v7.local.c b/mail_cmds/mail/v7.local.c
new file mode 100644
index 0000000..3e43ff2
--- /dev/null
+++ b/mail_cmds/mail/v7.local.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)v7.local.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/v7.local.c,v 1.5 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Version 7
+ *
+ * Local routines that are installation dependent.
+ */
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Locate the user's mailbox file (ie, the place where new, unread
+ * mail is queued).
+ */
+void
+findmail(user, buf, buflen)
+ char *user, *buf;
+ int buflen;
+{
+ char *tmp = getenv("MAIL");
+
+ if (tmp == NULL)
+ (void)snprintf(buf, buflen, "%s/%s", _PATH_MAILDIR, user);
+ else
+ (void)strlcpy(buf, tmp, buflen);
+}
+
+/*
+ * Get rid of the queued mail.
+ */
+void
+demail()
+{
+
+ if (value("keep") != NULL || rm(mailname) < 0)
+ (void)close(open(mailname, O_CREAT | O_TRUNC | O_WRONLY, 0600));
+}
+
+/*
+ * Discover user login name.
+ */
+char *
+username()
+{
+ char *np;
+ uid_t uid;
+
+ if ((np = getenv("USER")) != NULL)
+ return (np);
+ if ((np = getenv("LOGNAME")) != NULL)
+ return (np);
+ if ((np = getname(uid = getuid())) != NULL)
+ return (np);
+ printf("Cannot associate a name with uid %u\n", (unsigned)uid);
+ return (NULL);
+}
diff --git a/mail_cmds/mail/vars.c b/mail_cmds/mail/vars.c
new file mode 100644
index 0000000..419952d
--- /dev/null
+++ b/mail_cmds/mail/vars.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)vars.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/vars.c,v 1.4 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Variable handling stuff.
+ */
+
+/*
+ * Assign a value to a variable.
+ */
+void
+assign(name, value)
+ const char *name, *value;
+{
+ struct var *vp;
+ int h;
+
+ h = hash(name);
+ vp = lookup(name);
+ if (vp == NULL) {
+ vp = calloc(sizeof(*vp), 1);
+ vp->v_name = vcopy(name);
+ vp->v_link = variables[h];
+ variables[h] = vp;
+ }
+ else
+ v_free(vp->v_value);
+ vp->v_value = vcopy(value);
+}
+
+/*
+ * Free up a variable string. We do not bother to allocate
+ * strings whose value is "" since they are expected to be frequent.
+ * Thus, we cannot free same!
+ */
+void
+v_free(cp)
+ char *cp;
+{
+ if (*cp != '\0')
+ (void)free(cp);
+}
+
+/*
+ * Copy a variable value into permanent (ie, not collected after each
+ * command) space. Do not bother to alloc space for ""
+ */
+
+char *
+vcopy(str)
+ const char *str;
+{
+ char *new;
+ unsigned len;
+
+ if (*str == '\0')
+ return ("");
+ len = strlen(str) + 1;
+ if ((new = malloc(len)) == NULL)
+ err(1, "Out of memory");
+ bcopy(str, new, (int)len);
+ return (new);
+}
+
+/*
+ * Get the value of a variable and return it.
+ * Look in the environment if its not available locally.
+ */
+
+char *
+value(name)
+ const char *name;
+{
+ struct var *vp;
+
+ if ((vp = lookup(name)) == NULL)
+ return (getenv(name));
+ return (vp->v_value);
+}
+
+/*
+ * Locate a variable and return its variable
+ * node.
+ */
+
+struct var *
+lookup(name)
+ const char *name;
+{
+ struct var *vp;
+
+ for (vp = variables[hash(name)]; vp != NULL; vp = vp->v_link)
+ if (*vp->v_name == *name && equal(vp->v_name, name))
+ return (vp);
+ return (NULL);
+}
+
+/*
+ * Locate a group name and return it.
+ */
+
+struct grouphead *
+findgroup(name)
+ char name[];
+{
+ struct grouphead *gh;
+
+ for (gh = groups[hash(name)]; gh != NULL; gh = gh->g_link)
+ if (*gh->g_name == *name && equal(gh->g_name, name))
+ return (gh);
+ return (NULL);
+}
+
+/*
+ * Print a group out on stdout
+ */
+void
+printgroup(name)
+ char name[];
+{
+ struct grouphead *gh;
+ struct group *gp;
+
+ if ((gh = findgroup(name)) == NULL) {
+ printf("\"%s\": not a group\n", name);
+ return;
+ }
+ printf("%s\t", gh->g_name);
+ for (gp = gh->g_list; gp != NULL; gp = gp->ge_link)
+ printf(" %s", gp->ge_name);
+ printf("\n");
+}
+
+/*
+ * Hash the passed string and return an index into
+ * the variable or group hash table.
+ */
+int
+hash(name)
+ const char *name;
+{
+ int h = 0;
+
+ while (*name != '\0') {
+ h <<= 2;
+ h += *name++;
+ }
+ if (h < 0 && (h = -h) < 0)
+ h = 0;
+ return (h % HSHSIZE);
+}
diff --git a/mail_cmds/mail/version.c b/mail_cmds/mail/version.c
new file mode 100644
index 0000000..5178acb
--- /dev/null
+++ b/mail_cmds/mail/version.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)version.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/version.c,v 1.4 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Just keep track of the date/sid of this version of Mail.
+ * Load this file first to get a "total" Mail version.
+ */
+const char *version = "8.1 6/6/93";
diff --git a/mail_cmds/msgs/Makefile b/mail_cmds/msgs/Makefile
new file mode 100644
index 0000000..3319b01
--- /dev/null
+++ b/mail_cmds/msgs/Makefile
@@ -0,0 +1,11 @@
+Project = msgs
+Install_Dir = /usr/bin
+
+CFILES = msgs.c
+MANPAGES = msgs.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip \
+ -lcurses
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/msgs/msgs.1 b/mail_cmds/msgs/msgs.1
new file mode 100644
index 0000000..3897861
--- /dev/null
+++ b/mail_cmds/msgs/msgs.1
@@ -0,0 +1,236 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)msgs.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/usr.bin/msgs/msgs.1,v 1.18 2002/07/15 07:16:54 keramida Exp $
+.\"
+.Dd April 28, 1995
+.Dt MSGS 1
+.Os
+.Sh NAME
+.Nm msgs
+.Nd system messages and junk mail program
+.Sh SYNOPSIS
+.Nm
+.Op Fl fhlpq
+.Op Ar number
+.Op Ar \-number
+.Nm
+.Op Fl s
+.Nm
+.Op Fl c
+.Op \-days
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to read system messages.
+These messages are
+sent by mailing to the login `msgs' and should be short
+pieces of information which are suitable to be read once by most users
+of the system.
+.Pp
+The
+.Nm
+utility is normally invoked each time you login, by placing it in the file
+.Pa .login
+(or
+.Pa .profile
+if you use
+.Xr sh 1 ) .
+It will then prompt you with the source and subject of each new message.
+If there is no subject line, the first few non-blank lines of the
+message will be displayed.
+If there is more to the message, you will be told how
+long it is and asked whether you wish to see the rest of the message.
+The possible responses are:
+.Bl -tag -width Fl
+.It Fl y
+Type the rest of the message.
+.It Ic RETURN
+Synonym for y.
+.It Fl n
+Skip this message
+and go on to the next message.
+.It Fl
+Redisplay the last message.
+.It Fl q
+Drop out of
+.Nm ;
+the next time
+.Nm
+will pick up where it last left off.
+.It Fl s
+Append the current message to the file ``Messages'' in the current directory;
+`s\-' will save the previously displayed message.
+A `s' or `s\-' may
+be followed by a space and a file name to receive the message replacing
+the default ``Messages''.
+.It Fl m
+A copy of the specified message is placed in a temporary
+mailbox and
+.Xr mail 1
+is invoked on that mailbox.
+Both `m' and `s' accept a numeric argument in place of the `\-'.
+.El
+.Pp
+The
+.Nm
+utility keeps track of the next message you will see by a number in the file
+.Pa \&.msgsrc
+in your home directory.
+In the directory
+.Pa /var/msgs
+it keeps a set of files whose names are the (sequential) numbers
+of the messages they represent.
+The file
+.Pa /var/msgs/bounds
+shows the low and high number of the messages in the directory
+so that
+.Nm
+can quickly determine if there are no messages for you.
+If the contents of
+.Pa bounds
+is incorrect it can be fixed by removing it;
+.Nm
+will make a new
+.Pa bounds
+file the next time it is run with the
+.Fl s
+option.
+If
+.Nm
+is run with any option other than
+.Fl s ,
+an error will be displayed if
+.Pa /var/msgs/bounds
+does not exist.
+.Pp
+The
+.Fl s
+option is used for setting up the posting of messages.
+The line
+.Pp
+.Dl msgs: \&"\&| /usr/bin/msgs \-s\&"
+.Pp
+should be included in
+.Pa /etc/mail/aliases
+(see
+.Xr newaliases 1 )
+to enable posting of messages.
+.Pp
+The
+.Fl c
+option is used for performing cleanup on
+.Pa /var/msgs .
+A shell script entry to run
+.Nm
+with the
+.Fl c
+option should be placed in
+.Pa /etc/periodic/daily
+(see
+.Xr periodic 8 )
+to run every night.
+This will remove all messages over 21 days old.
+A different expiration may be specified on the command line to override
+the default.
+You must be the superuser to use this option.
+.Pp
+Options when reading messages include:
+.Bl -tag -width Fl
+.It Fl f
+Do not say ``No new messages.''.
+This is useful in a
+.Pa .login
+file since this is often the case here.
+.It Fl q
+Queries whether there are messages, printing
+``There are new messages.'' if there are.
+The command ``msgs \-q'' is often used in login scripts.
+.It Fl h
+Print the first part of messages only.
+.It Fl l
+Cause only locally originated messages to be reported.
+.It Ar num
+A message number can be given
+on the command line, causing
+.Nm
+to start at the specified message rather than at the next message
+indicated by your
+.Pa \&.msgsrc
+file.
+Thus
+.Pp
+.Dl msgs \-h 1
+.Pp
+prints the first part of all messages.
+.It Ar \-number
+Start
+.Ar number
+messages back from the one indicated in the
+.Pa \&.msgsrc
+file, useful for reviews of recent messages.
+.It Fl p
+Pipe long messages through
+.Xr more 1 .
+.El
+.Pp
+Within
+.Nm
+you can also go to any specific message by typing its number when
+.Nm
+requests input as to what to do.
+.Sh ENVIRONMENT
+The
+.Nm
+utility uses the
+.Ev HOME
+and
+.Ev TERM
+environment variables for the default home directory and
+terminal type.
+.Sh FILES
+.Bl -tag -width /var/msgs/* -compact
+.It Pa /var/msgs/*
+database
+.It Pa ~/.msgsrc
+number of next message to be presented
+.El
+.Sh SEE ALSO
+.Xr mail 1 ,
+.Xr more 1 ,
+.Xr aliases 5 ,
+.Xr periodic 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/mail_cmds/msgs/msgs.c b/mail_cmds/msgs/msgs.c
new file mode 100644
index 0000000..a452994
--- /dev/null
+++ b/mail_cmds/msgs/msgs.c
@@ -0,0 +1,923 @@
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+
+__RCSID("$FreeBSD: src/usr.bin/msgs/msgs.c,v 1.24 2002/09/04 23:29:04 dwmalone Exp $");
+
+/*
+ * msgs - a user bulletin board program
+ *
+ * usage:
+ * msgs [fhlopqr] [[-]number] to read messages
+ * msgs -s to place messages
+ * msgs -c [-days] to clean up the bulletin board
+ *
+ * prompt commands are:
+ * y print message
+ * n flush message, go to next message
+ * q flush message, quit
+ * p print message, turn on 'pipe thru more' mode
+ * P print message, turn off 'pipe thru more' mode
+ * - reprint last message
+ * s[-][<num>] [<filename>] save message
+ * m[-][<num>] mail with message in temp mbox
+ * x exit without flushing this message
+ * <num> print message number <num>
+ */
+
+#define V7 /* will look for TERM in the environment */
+#define OBJECT /* will object to messages without Subjects */
+#define REJECT /* will reject messages without Subjects
+ (OBJECT must be defined also) */
+/* #define UNBUFFERED *//* use unbuffered output */
+
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif /* __APPLE__ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <termcap.h>
+#include <termios.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "pathnames.h"
+
+#define CMODE 0644 /* bounds file creation mode */
+#define NO 0
+#define YES 1
+#define SUPERUSER 0 /* superuser uid */
+#define DAEMON 1 /* daemon uid */
+#define NLINES 24 /* default number of lines/crt screen */
+#define NDAYS 21 /* default keep time for messages */
+#define DAYS *24*60*60 /* seconds/day */
+#define MSGSRC ".msgsrc" /* user's rc file */
+#define BOUNDS "bounds" /* message bounds file */
+#define NEXT "Next message? [yq]"
+#define MORE "More? [ynq]"
+#define NOMORE "(No more) [q] ?"
+
+typedef char bool;
+
+FILE *msgsrc;
+FILE *newmsg;
+const char *sep = "-";
+char inbuf[BUFSIZ];
+char fname[MAXPATHLEN];
+char cmdbuf[MAXPATHLEN + MAXPATHLEN];
+char subj[128];
+char from[128];
+char date[128];
+char *ptr;
+char *in;
+bool local;
+bool ruptible;
+bool totty;
+bool seenfrom;
+bool seensubj;
+bool blankline;
+bool printing = NO;
+bool mailing = NO;
+bool quitit = NO;
+bool sending = NO;
+bool intrpflg = NO;
+bool restricted = NO;
+uid_t uid;
+int msg;
+int prevmsg;
+int lct;
+int nlines;
+int Lpp = 0;
+time_t t;
+time_t keep;
+
+/* option initialization */
+bool hdrs = NO;
+bool qopt = NO;
+bool hush = NO;
+bool send_msg = NO;
+bool locomode = NO;
+bool use_pager = NO;
+bool clean = NO;
+bool lastcmd = NO;
+jmp_buf tstpbuf;
+
+void ask(const char *);
+void gfrsub(FILE *);
+int linecnt(FILE *);
+int next(char *);
+char *nxtfld(unsigned char *);
+void onsusp(int);
+void onintr(int);
+void prmesg(int);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ bool newrc, already;
+ int rcfirst = 0; /* first message to print (from .rc) */
+ int rcback = 0; /* amount to back off of rcfirst */
+ int firstmsg = 0, nextmsg = 0, lastmsg = 0;
+ int blast = 0;
+ struct stat buf; /* stat to check access of bounds */
+ FILE *bounds;
+
+#ifdef UNBUFFERED
+ setbuf(stdout, NULL);
+#endif
+ setlocale(LC_ALL, "");
+
+ time(&t);
+ setuid(uid = getuid());
+ ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL);
+ if (ruptible)
+ signal(SIGINT, SIG_DFL);
+
+ argc--, argv++;
+ while (argc > 0) {
+ if (isdigit(argv[0][0])) { /* starting message # */
+ rcfirst = atoi(argv[0]);
+ }
+ else if (isdigit(argv[0][1])) { /* backward offset */
+ rcback = atoi( &( argv[0][1] ) );
+ }
+ else {
+ ptr = *argv;
+ while (*ptr) switch (*ptr++) {
+
+ case '-':
+ break;
+
+ case 'c':
+ if (uid != SUPERUSER && uid != DAEMON)
+ errx(1,
+ "only the super-user can use the c flag");
+ clean = YES;
+ break;
+
+ case 'f': /* silently */
+ hush = YES;
+ break;
+
+ case 'h': /* headers only */
+ hdrs = YES;
+ break;
+
+ case 'l': /* local msgs only */
+ locomode = YES;
+ break;
+
+ case 'o': /* option to save last message */
+ lastcmd = YES;
+ break;
+
+ case 'p': /* pipe thru 'more' during long msgs */
+ use_pager = YES;
+ break;
+
+ case 'q': /* query only */
+ qopt = YES;
+ break;
+
+#ifdef __APPLE__
+ case 'r': /* restricted */
+ restricted = YES;
+ break;
+#endif /* __APPLE__ */
+
+
+ case 's': /* sending TO msgs */
+ send_msg = YES;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc--, argv++;
+ }
+
+ /*
+ * determine current message bounds
+ */
+ snprintf(fname, sizeof(fname), "%s/%s", _PATH_MSGS, BOUNDS);
+
+ /*
+ * Test access rights to the bounds file
+ * This can be a little tricky. if(send_msg), then
+ * we will create it. We assume that if(send_msg),
+ * then you have write permission there.
+ * Else, it better be there, or we bail.
+ */
+ if (send_msg != YES) {
+ if (stat(fname, &buf) < 0) {
+ if (hush != YES) {
+ err(errno, "%s", fname);
+ } else {
+ exit(1);
+ }
+ }
+ }
+ bounds = fopen(fname, "r");
+
+ if (bounds != NULL) {
+ fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg);
+ fclose(bounds);
+ blast = lastmsg; /* save upper bound */
+ }
+
+ if (clean)
+ keep = t - (rcback? rcback : NDAYS) DAYS;
+
+ if (clean || bounds == NULL) { /* relocate message bounds */
+ struct dirent *dp;
+ struct stat stbuf;
+ bool seenany = NO;
+ DIR *dirp;
+
+ dirp = opendir(_PATH_MSGS);
+ if (dirp == NULL)
+ err(errno, "%s", _PATH_MSGS);
+
+ firstmsg = 32767;
+ lastmsg = 0;
+
+ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){
+ char *cp = dp->d_name;
+ int i = 0;
+
+ if (dp->d_ino == 0)
+ continue;
+ if (dp->d_namlen == 0)
+ continue;
+
+ if (clean)
+ snprintf(inbuf, sizeof(inbuf), "%s/%s", _PATH_MSGS, cp);
+
+ while (isdigit(*cp))
+ i = i * 10 + *cp++ - '0';
+ if (*cp)
+ continue; /* not a message! */
+
+ if (clean) {
+ if (stat(inbuf, &stbuf) != 0)
+ continue;
+ if (stbuf.st_mtime < keep
+ && stbuf.st_mode&S_IWRITE) {
+ unlink(inbuf);
+ continue;
+ }
+ }
+
+ if (i > lastmsg)
+ lastmsg = i;
+ if (i < firstmsg)
+ firstmsg = i;
+ seenany = YES;
+ }
+ closedir(dirp);
+
+ if (!seenany) {
+ if (blast != 0) /* never lower the upper bound! */
+ lastmsg = blast;
+ firstmsg = lastmsg + 1;
+ }
+ else if (blast > lastmsg)
+ lastmsg = blast;
+
+ if (!send_msg) {
+ bounds = fopen(fname, "w");
+ if (bounds == NULL)
+ err(errno, "%s", fname);
+ chmod(fname, CMODE);
+ fprintf(bounds, "%d %d\n", firstmsg, lastmsg);
+ fclose(bounds);
+ }
+ }
+
+ if (send_msg) {
+ /*
+ * Send mode - place msgs in _PATH_MSGS
+ */
+ bounds = fopen(fname, "w");
+ if (bounds == NULL)
+ err(errno, "%s", fname);
+
+ nextmsg = lastmsg + 1;
+ snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, nextmsg);
+ newmsg = fopen(fname, "w");
+ if (newmsg == NULL)
+ err(errno, "%s", fname);
+ chmod(fname, CMODE);
+
+ fprintf(bounds, "%d %d\n", firstmsg, nextmsg);
+ fclose(bounds);
+
+ sending = YES;
+ if (ruptible)
+ signal(SIGINT, onintr);
+
+ if (isatty(fileno(stdin))) {
+ ptr = getpwuid(uid)->pw_name;
+ printf("Message %d:\nFrom %s %sSubject: ",
+ nextmsg, ptr, ctime(&t));
+ fflush(stdout);
+ fgets(inbuf, sizeof inbuf, stdin);
+ putchar('\n');
+ fflush(stdout);
+ fprintf(newmsg, "From %s %sSubject: %s\n",
+ ptr, ctime(&t), inbuf);
+ blankline = seensubj = YES;
+ }
+ else
+ blankline = seensubj = NO;
+ for (;;) {
+ fgets(inbuf, sizeof inbuf, stdin);
+ if (feof(stdin) || ferror(stdin))
+ break;
+ blankline = (blankline || (inbuf[0] == '\n'));
+ seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0)));
+ fputs(inbuf, newmsg);
+ }
+#ifdef OBJECT
+ if (!seensubj) {
+ printf("NOTICE: Messages should have a Subject field!\n");
+#ifdef REJECT
+ unlink(fname);
+#endif
+ exit(1);
+ }
+#endif
+ exit(ferror(stdin));
+ }
+ if (clean)
+ exit(0);
+
+ /*
+ * prepare to display messages
+ */
+ totty = (isatty(fileno(stdout)) != 0);
+ use_pager = use_pager && totty;
+
+ snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), MSGSRC);
+ msgsrc = fopen(fname, "r");
+ if (msgsrc) {
+ newrc = NO;
+ fscanf(msgsrc, "%d\n", &nextmsg);
+ fclose(msgsrc);
+ if (nextmsg > lastmsg+1) {
+ printf("Warning: bounds have been reset (%d, %d)\n",
+ firstmsg, lastmsg);
+ truncate(fname, (off_t)0);
+ newrc = YES;
+ }
+ else if (!rcfirst)
+ rcfirst = nextmsg - rcback;
+ }
+ else
+ newrc = YES;
+ msgsrc = fopen(fname, "r+");
+ if (msgsrc == NULL)
+ msgsrc = fopen(fname, "w");
+ if (msgsrc == NULL)
+ err(errno, "%s", fname);
+ if (rcfirst) {
+ if (rcfirst > lastmsg+1) {
+ printf("Warning: the last message is number %d.\n",
+ lastmsg);
+ rcfirst = nextmsg;
+ }
+ if (rcfirst > firstmsg)
+ firstmsg = rcfirst; /* don't set below first msg */
+ }
+ if (newrc) {
+ nextmsg = firstmsg;
+ rewind(msgsrc);
+ fprintf(msgsrc, "%d\n", nextmsg);
+ fflush(msgsrc);
+ }
+
+#ifdef V7
+ if (totty) {
+ struct winsize win;
+ if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1)
+ Lpp = win.ws_row;
+ if (Lpp <= 0) {
+ if (tgetent(inbuf, getenv("TERM")) <= 0
+ || (Lpp = tgetnum("li")) <= 0) {
+ Lpp = NLINES;
+ }
+ }
+ }
+#endif
+ Lpp -= 6; /* for headers, etc. */
+
+ already = NO;
+ prevmsg = firstmsg;
+ printing = YES;
+ if (ruptible)
+ signal(SIGINT, onintr);
+
+ /*
+ * Main program loop
+ */
+ for (msg = firstmsg; msg <= lastmsg; msg++) {
+
+ snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, msg);
+ newmsg = fopen(fname, "r");
+ if (newmsg == NULL)
+ continue;
+
+ gfrsub(newmsg); /* get From and Subject fields */
+ if (locomode && !local) {
+ fclose(newmsg);
+ continue;
+ }
+
+ if (qopt) { /* This has to be located here */
+ printf("There are new messages.\n");
+ exit(0);
+ }
+
+ if (already && !hdrs)
+ putchar('\n');
+
+ /*
+ * Print header
+ */
+ if (totty)
+ signal(SIGTSTP, onsusp);
+ (void) setjmp(tstpbuf);
+ already = YES;
+ nlines = 2;
+ if (seenfrom) {
+ printf("Message %d:\nFrom %s %s", msg, from, date);
+ nlines++;
+ }
+ if (seensubj) {
+ printf("Subject: %s", subj);
+ nlines++;
+ }
+ else {
+ if (seenfrom) {
+ putchar('\n');
+ nlines++;
+ }
+ while (nlines < 6
+ && fgets(inbuf, sizeof inbuf, newmsg)
+ && inbuf[0] != '\n') {
+ fputs(inbuf, stdout);
+ nlines++;
+ }
+ }
+
+ lct = linecnt(newmsg);
+ if (lct)
+ printf("(%d%slines) ", lct, seensubj? " " : " more ");
+
+ if (hdrs) {
+ printf("\n-----\n");
+ fclose(newmsg);
+ continue;
+ }
+
+ /*
+ * Ask user for command
+ */
+ if (totty)
+ ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT));
+ else
+ inbuf[0] = 'y';
+ if (totty)
+ signal(SIGTSTP, SIG_DFL);
+cmnd:
+ in = inbuf;
+ switch (*in) {
+ case 'x':
+ /* FALLTHROUGH */
+ case 'X':
+ exit(0);
+ /* NOTREACHED */
+
+ case 'q':
+ /* FALLTHROUGH */
+ case 'Q':
+ quitit = YES;
+ printf("--Postponed--\n");
+ exit(0);
+ /* NOTREACHED */
+
+ case 'n':
+ /* FALLTHROUGH */
+ case 'N':
+ if (msg >= nextmsg) sep = "Flushed";
+ prevmsg = msg;
+ break;
+
+ case 'p':
+ /* FALLTHROUGH */
+ case 'P':
+ use_pager = (*in++ == 'p');
+ /* FALLTHROUGH */
+ case '\n':
+ /* FALLTHROUGH */
+ case 'y':
+ default:
+ if (*in == '-') {
+ msg = prevmsg-1;
+ sep = "replay";
+ break;
+ }
+ if (isdigit(*in)) {
+ msg = next(in);
+ sep = in;
+ break;
+ }
+
+ prmesg(nlines + lct + (seensubj? 1 : 0));
+ prevmsg = msg;
+
+ }
+
+ printf("--%s--\n", sep);
+ sep = "-";
+ if (msg >= nextmsg) {
+ nextmsg = msg + 1;
+ rewind(msgsrc);
+ fprintf(msgsrc, "%d\n", nextmsg);
+ fflush(msgsrc);
+ }
+ if (newmsg)
+ fclose(newmsg);
+ if (quitit)
+ break;
+ }
+
+ /*
+ * Make sure .rc file gets updated
+ */
+ if (--msg >= nextmsg) {
+ nextmsg = msg + 1;
+ rewind(msgsrc);
+ fprintf(msgsrc, "%d\n", nextmsg);
+ fflush(msgsrc);
+ }
+ if (already && !quitit && lastcmd && totty) {
+ /*
+ * save or reply to last message?
+ */
+ msg = prevmsg;
+ ask(NOMORE);
+ if (inbuf[0] == '-' || isdigit(inbuf[0]))
+ goto cmnd;
+ }
+ if (!(already || hush || qopt))
+ printf("No new messages.\n");
+ exit(0);
+ /* NOTREACHED */
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: msgs [fhlopqr] [[-]number]\n");
+ exit(1);
+}
+
+void
+prmesg(int length)
+{
+ FILE *outf;
+ char *env_pager;
+
+ if (use_pager && length > Lpp) {
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ if ((env_pager = getenv("PAGER")) == NULL) {
+ snprintf(cmdbuf, sizeof(cmdbuf), _PATH_PAGER, Lpp);
+ } else {
+ snprintf(cmdbuf, sizeof(cmdbuf), "%s", env_pager);
+ }
+ outf = popen(cmdbuf, "w");
+ if (!outf)
+ outf = stdout;
+ else
+ setbuf(outf, (char *)NULL);
+ }
+ else
+ outf = stdout;
+
+ if (seensubj)
+ putc('\n', outf);
+
+ while (fgets(inbuf, sizeof inbuf, newmsg)) {
+ fputs(inbuf, outf);
+ if (ferror(outf)) {
+ clearerr(outf);
+ break;
+ }
+ }
+
+ if (outf != stdout) {
+ pclose(outf);
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ }
+ else {
+ fflush(stdout);
+ }
+
+ /* force wait on output */
+ tcdrain(fileno(stdout));
+}
+
+void
+onintr(int unused)
+{
+ signal(SIGINT, onintr);
+ if (mailing)
+ unlink(fname);
+ if (sending) {
+ unlink(fname);
+ puts("--Killed--");
+ exit(1);
+ }
+ if (printing) {
+ putchar('\n');
+ if (hdrs)
+ exit(0);
+ sep = "Interrupt";
+ if (newmsg)
+ fseeko(newmsg, (off_t)0, SEEK_END);
+ intrpflg = YES;
+ }
+}
+
+/*
+ * We have just gotten a susp. Suspend and prepare to resume.
+ */
+void
+onsusp(int unused)
+{
+ signal(SIGTSTP, SIG_DFL);
+ sigsetmask(0);
+ kill(0, SIGTSTP);
+ signal(SIGTSTP, onsusp);
+ if (!mailing)
+ longjmp(tstpbuf, 0);
+}
+
+int
+linecnt(FILE *f)
+{
+ off_t oldpos = ftello(f);
+ int l = 0;
+ char lbuf[BUFSIZ];
+
+ while (fgets(lbuf, sizeof lbuf, f))
+ l++;
+ clearerr(f);
+ fseeko(f, oldpos, SEEK_SET);
+ return (l);
+}
+
+int
+next(char *buf)
+{
+ int i;
+ sscanf(buf, "%d", &i);
+ sprintf(buf, "Goto %d", i);
+ return(--i);
+}
+
+void
+ask(const char *prompt)
+{
+ char inch;
+ int n, cmsg, fd;
+ off_t oldpos;
+ FILE *cpfrom, *cpto;
+
+ printf("%s ", prompt);
+ fflush(stdout);
+ intrpflg = NO;
+ (void) fgets(inbuf, sizeof inbuf, stdin);
+ if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n')
+ inbuf[n - 1] = '\0';
+ if (intrpflg)
+ inbuf[0] = 'x';
+
+ /*
+ * Handle 'mail' and 'save' here.
+ */
+#ifdef __APPLE__
+ if (((inch = inbuf[0]) == 's' || inch == 'm') && !restricted) {
+#else
+ if ((inch = inbuf[0]) == 's' || inch == 'm') {
+#endif /* __APPLE__ */
+ if (inbuf[1] == '-')
+ cmsg = prevmsg;
+ else if (isdigit(inbuf[1]))
+ cmsg = atoi(&inbuf[1]);
+ else
+ cmsg = msg;
+ snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, cmsg);
+
+ oldpos = ftello(newmsg);
+
+ cpfrom = fopen(fname, "r");
+ if (!cpfrom) {
+ printf("Message %d not found\n", cmsg);
+ ask (prompt);
+ return;
+ }
+
+ if (inch == 's') {
+ in = nxtfld((unsigned char *)inbuf);
+ if (*in) {
+ for (n=0; in[n] > ' '; n++) { /* sizeof fname? */
+ fname[n] = in[n];
+ }
+ fname[n] = 0;
+ }
+ else
+ strcpy(fname, "Messages");
+ fd = open(fname, O_RDWR|O_EXCL|O_CREAT|O_APPEND);
+ }
+ else {
+ strcpy(fname, _PATH_TMP);
+ fd = mkstemp(fname);
+ if (fd != -1) {
+ snprintf(cmdbuf, sizeof(cmdbuf), _PATH_MAIL,
+ fname);
+ mailing = YES;
+ }
+ }
+ if (fd == -1 || (cpto = fdopen(fd, "a")) == NULL) {
+ if (fd != -1)
+ close(fd);
+ warn("%s", fname);
+ mailing = NO;
+ fseeko(newmsg, oldpos, SEEK_SET);
+ ask(prompt);
+ return;
+ }
+
+ while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom)))
+ fwrite(inbuf, 1, n, cpto);
+
+ fclose(cpfrom);
+ fclose(cpto);
+ fseeko(newmsg, oldpos, SEEK_SET);/* reposition current message */
+ if (inch == 's')
+ printf("Message %d saved in \"%s\"\n", cmsg, fname);
+ else {
+ system(cmdbuf);
+ unlink(fname);
+ mailing = NO;
+ }
+ ask(prompt);
+ }
+}
+
+void
+gfrsub(FILE *infile)
+{
+ off_t frompos;
+ int count;
+
+ seensubj = seenfrom = NO;
+ local = YES;
+ subj[0] = from[0] = date[0] = 0;
+
+ /*
+ * Is this a normal message?
+ */
+ if (fgets(inbuf, sizeof inbuf, infile)) {
+ if (strncmp(inbuf, "From", 4)==0) {
+ /*
+ * expected form starts with From
+ */
+ seenfrom = YES;
+ frompos = ftello(infile);
+ ptr = from;
+ in = nxtfld((unsigned char *)inbuf);
+ if (*in) {
+ count = sizeof(from) - 1;
+ while (*in && *in > ' ' && count-- > 0) {
+ if (*in == ':' || *in == '@' ||
+ *in == '!')
+ local = NO;
+ *ptr++ = *in++;
+ }
+ }
+ *ptr = 0;
+ if (*(in = nxtfld((unsigned char *)in)))
+ strncpy(date, in, sizeof date);
+ else {
+ date[0] = '\n';
+ date[1] = 0;
+ }
+ }
+ else {
+ /*
+ * not the expected form
+ */
+ rewind(infile);
+ return;
+ }
+ }
+ else
+ /*
+ * empty file ?
+ */
+ return;
+
+ /*
+ * look for Subject line until EOF or a blank line
+ */
+ while (fgets(inbuf, sizeof inbuf, infile)
+ && !(blankline = (inbuf[0] == '\n'))) {
+ /*
+ * extract Subject line
+ */
+ if (!seensubj && strncmp(inbuf, "Subj", 4)==0) {
+ seensubj = YES;
+ frompos = ftello(infile);
+ strncpy(subj, nxtfld((unsigned char *)inbuf), sizeof subj);
+ }
+ }
+ if (!blankline)
+ /*
+ * ran into EOF
+ */
+ fseeko(infile, frompos, SEEK_SET);
+
+ if (!seensubj)
+ /*
+ * for possible use with Mail
+ */
+ strncpy(subj, "(No Subject)\n", sizeof subj);
+}
+
+char *
+nxtfld(unsigned char *s)
+{
+ if (*s) while (*s && !isspace(*s)) s++; /* skip over this field */
+ if (*s) while (*s && isspace(*s)) s++; /* find start of next field */
+ return ((char *)s);
+}
diff --git a/mail_cmds/msgs/pathnames.h b/mail_cmds/msgs/pathnames.h
new file mode 100644
index 0000000..90f23f4
--- /dev/null
+++ b/mail_cmds/msgs/pathnames.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#define _PATH_MSGS "/var/msgs"
+#define _PATH_MAIL "/usr/bin/Mail -f %s"
+#define _PATH_PAGER "/usr/bin/more -%d"
+#undef _PATH_TMP
+#define _PATH_TMP "/tmp/msgXXXXXX"
diff --git a/misc_cmds/calendar/calendar.1 b/misc_cmds/calendar/calendar.1
new file mode 100644
index 0000000..1d82f71
--- /dev/null
+++ b/misc_cmds/calendar/calendar.1
@@ -0,0 +1,265 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)calendar.1 8.1 (Berkeley) 6/29/93
+.\" $FreeBSD: src/usr.bin/calendar/calendar.1,v 1.38 2005/02/13 22:25:20 ru Exp $
+.\"
+.Dd June 13, 2002
+.Dt CALENDAR 1
+.Os
+.Sh NAME
+.Nm calendar
+.Nd reminder service
+.Sh SYNOPSIS
+.Nm
+.Op Fl a
+.Op Fl A Ar num
+.Op Fl B Ar num
+.Op Fl F Ar friday
+.Op Fl f Ar calendarfile
+.Oo
+.Bk -words
+.Fl t Ar dd Ns
+.Sm off
+.Op . Ar mm Op . Ar year
+.Sm on
+.Ek
+.Oc
+.Op Fl W Ar num
+.Sh DESCRIPTION
+The
+.Nm
+utility checks the current directory for a file named
+.Pa calendar
+and displays lines that begin with either today's date
+or tomorrow's.
+On the day before a weekend (normally Friday), events for the next
+three days are displayed.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl A Ar num
+Print lines from today and the next
+.Ar num
+days (forward, future).
+.It Fl a
+Process the ``calendar'' files of all users and mail the results
+to them.
+This requires super-user privileges.
+.It Fl B Ar num
+Print lines from today and the previous
+.Ar num
+days (backward, past).
+.It Fl F Ar friday
+Specify which day of the week is ``Friday'' (the day before the
+weekend begins).
+Default is 5.
+.It Fl f Pa calendarfile
+Use
+.Pa calendarfile
+as the default calendar file.
+.It Xo Fl t
+.Sm off
+.Ar dd
+.Op . Ar mm Op . Ar year
+.Sm on
+.Xc
+For test purposes only: set date directly to argument values.
+.It Fl W Ar num
+Print lines from today and the next
+.Ar num
+days (forward, future).
+Ignore weekends when calculating the number of days.
+.El
+.Pp
+To handle calendars in your national code table you can specify
+.Dq LANG=<locale_name>
+in the calendar file as early as possible.
+To handle national Easter
+names in the calendars
+.Dq Easter=<national_name>
+(for Catholic Easter) or
+.Dq Paskha=<national_name>
+(for Orthodox Easter) can be used.
+.Pp
+Other lines should begin with a month and day.
+They may be entered in almost any format, either numeric or as character
+strings.
+If the proper locale is set, national month and weekday
+names can be used.
+A single asterisk (``*'') matches every month.
+A day without a month matches that day of every week.
+A month without a day matches the first of that month.
+Two numbers default to the month followed by the day.
+Lines with leading tabs default to the last entered date, allowing
+multiple line specifications for a single date.
+.Pp
+``Easter'', is Easter for this year, and may be followed by a positive
+or negative integer.
+.Pp
+``Paskha'', is Orthodox Easter for this year, and may be followed by a
+positive or negative integer.
+.Pp
+Weekdays may be followed by ``-4'' ...\& ``+5'' (aliases for
+last, first, second, third, fourth) for moving events like
+``the last Monday in April''.
+.Pp
+By convention, dates followed by an asterisk are not fixed, i.e., change
+from year to year.
+.Pp
+Day descriptions start after the first <tab> character in the line;
+if the line does not contain a <tab> character, it is not displayed.
+If the first character in the line is a <tab> character, it is treated as
+a continuation of the previous line.
+.Pp
+The ``calendar'' file is preprocessed by
+.Xr cpp 1 ,
+allowing the inclusion of shared files such as lists of company holidays or
+meetings.
+If the shared file is not referenced by a full pathname,
+.Xr cpp 1
+searches in the current (or home) directory first, and then in the
+directory
+.Pa /usr/share/calendar .
+Empty lines and lines protected by the C commenting syntax
+.Pq Li /* ... */
+are ignored.
+.Pp
+Some possible calendar entries (<tab> characters highlighted by
+\fB\et\fR sequence)
+.Bd -unfilled -offset indent
+LANG=C
+Easter=Ostern
+
+#include <calendar.usholiday>
+#include <calendar.birthday>
+
+6/15\fB\et\fRJune 15 (if ambiguous, will default to month/day).
+Jun. 15\fB\et\fRJune 15.
+15 June\fB\et\fRJune 15.
+Thursday\fB\et\fREvery Thursday.
+June\fB\et\fREvery June 1st.
+15 *\fB\et\fR15th of every month.
+
+May Sun+2\fB\et\fRsecond Sunday in May (Muttertag)
+04/SunLast\fB\et\fRlast Sunday in April,
+\fB\et\fRsummer time in Europe
+Easter\fB\et\fREaster
+Ostern-2\fB\et\fRGood Friday (2 days before Easter)
+Paskha\fB\et\fROrthodox Easter
+
+.Ed
+.Sh FILES
+.Bl -tag -width calendar.christian -compact
+.It Pa calendar
+file in current directory
+.It Pa ~/.calendar
+.Pa calendar
+HOME directory.
+A chdir is done into this directory if it exists.
+.It Pa ~/.calendar/calendar
+calendar file to use if no calendar file exists in the current directory.
+.It Pa ~/.calendar/nomail
+do not send mail if this file exists.
+.El
+.Pp
+The following default calendar files are provided:
+.Pp
+.Bl -tag -width calendar.southafrica -compact
+.It Pa calendar.all
+File which includes all the default files.
+.It Pa calendar.australia
+Calendar of events in Australia.
+.It Pa calendar.birthday
+Births and deaths of famous (and not-so-famous) people.
+.It Pa calendar.christian
+Christian holidays.
+This calendar should be updated yearly by the local system administrator
+so that roving holidays are set correctly for the current year.
+.It Pa calendar.computer
+Days of special significance to computer people.
+.It Pa calendar.croatian
+Calendar of events in Croatia.
+.It Pa calendar.freebsd
+Birthdays of
+.Fx
+committers.
+.It Pa calendar.french
+Calendar of events in France.
+.It Pa calendar.german
+Calendar of events in Germany.
+.It Pa calendar.history
+Everything else, mostly U.S.\& historical events.
+.It Pa calendar.holiday
+Other holidays, including the not-well-known, obscure, and
+.Em really
+obscure.
+.It Pa calendar.judaic
+Jewish holidays.
+This calendar should be updated yearly by the local system administrator
+so that roving holidays are set correctly for the current year.
+.It Pa calendar.music
+Musical events, births, and deaths.
+Strongly oriented toward rock 'n' roll.
+.It Pa calendar.newzealand
+Calendar of events in New Zealand.
+.It Pa calendar.russian
+Russian calendar.
+.It Pa calendar.southafrica
+Calendar of events in South Africa.
+.It Pa calendar.usholiday
+U.S.\& holidays.
+This calendar should be updated yearly by the local system administrator
+so that roving holidays are set correctly for the current year.
+.It Pa calendar.world
+Includes all calendar files except for national files.
+.El
+.Sh COMPATIBILITY
+The
+.Nm
+program previously selected lines which had the correct date anywhere
+in the line.
+This is no longer true, the date is only recognized when it occurs
+at the beginning of a line.
+.Sh SEE ALSO
+.Xr at 1 ,
+.Xr cpp 1 ,
+.Xr mail 1 ,
+.Xr cron 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v7 .
+.Sh BUGS
+The
+.Nm
+utility does not handle Jewish holidays and moon phases.
diff --git a/misc_cmds/calendar/calendar.c b/misc_cmds/calendar/calendar.c
new file mode 100644
index 0000000..ae30497
--- /dev/null
+++ b/misc_cmds/calendar/calendar.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/calendar/calendar.c,v 1.19 2007/05/07 11:18:30 dwmalone Exp $");
+
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+#include "calendar.h"
+
+struct passwd *pw;
+int doall = 0;
+time_t f_time = 0;
+
+int f_dayAfter = 1; /* days after current date */
+int f_dayBefore = 0; /* days before current date */
+int Friday = 5; /* day before weekend */
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ (void) setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "-af:t:A:B:F:W:")) != -1)
+ switch (ch) {
+ case '-': /* backward contemptible */
+ case 'a':
+ if (getuid()) {
+ errno = EPERM;
+ err(1, NULL);
+ }
+ doall = 1;
+ break;
+
+
+ case 'f': /* other calendar file */
+ calendarFile = optarg;
+ break;
+
+ case 't': /* other date, undocumented, for tests */
+ f_time = Mktime (optarg);
+ break;
+
+ case 'W': /* we don't need no steenking Fridays */
+ Friday = -1;
+
+ /* FALLTHROUGH */
+ case 'A': /* days after current date */
+ f_dayAfter = atoi(optarg);
+ break;
+
+ case 'B': /* days before current date */
+ f_dayBefore = atoi(optarg);
+ break;
+
+ case 'F':
+ Friday = atoi(optarg);
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc)
+ usage();
+
+ /* use current time */
+ if (f_time <= 0)
+ (void)time(&f_time);
+
+ settime(f_time);
+
+ if (doall)
+ while ((pw = getpwent()) != NULL) {
+ (void)setegid(pw->pw_gid);
+ (void)initgroups(pw->pw_name, pw->pw_gid);
+ (void)seteuid(pw->pw_uid);
+ if (!chdir(pw->pw_dir))
+ cal();
+ (void)seteuid(0);
+ }
+ else
+ cal();
+ exit(0);
+}
+
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n",
+ "usage: calendar [-a] [-A days] [-B days] [-F friday] "
+ "[-f calendarfile]",
+ " [-t dd[.mm[.year]]] [-W days]");
+ exit(1);
+}
+
+
diff --git a/misc_cmds/calendar/calendar.h b/misc_cmds/calendar/calendar.h
new file mode 100644
index 0000000..57e84a1
--- /dev/null
+++ b/misc_cmds/calendar/calendar.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendar.h,v 1.12 2007/06/09 05:54:13 grog Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+extern struct passwd *pw;
+extern int doall;
+extern struct iovec header[];
+extern struct tm *tp;
+extern const char *calendarFile;
+extern int *cumdays;
+extern int yrdays;
+extern struct fixs neaster, npaskha;
+
+void cal(void);
+void closecal(FILE *);
+int getday(char *);
+int getdayvar(char *);
+int getfield(char *, char **, int *);
+int getmonth(char *);
+int geteaster(char *, int);
+int getpaskha(char *, int);
+int easter(int);
+int isnow(char *, int *, int *, int *);
+FILE *opencal(void);
+void settime(time_t);
+time_t Mktime(char *);
+void usage(void);
+void setnnames(void);
+
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+
+/* some flags */
+#define F_ISMONTH 0x01 /* month (Januar ...) */
+#define F_ISDAY 0x02 /* day of week (Sun, Mon, ...) */
+#define F_ISDAYVAR 0x04 /* variables day of week, like SundayLast */
+#define F_EASTER 0x08 /* Easter or easter depending days */
+
+extern int f_dayAfter; /* days after current date */
+extern int f_dayBefore; /* days bevore current date */
+extern int Friday; /* day before weekend */
+
+struct fixs {
+ char *name;
+ int len;
+};
+
+struct event *event_add(struct event *events, int month, int day, char *date,
+ int var, char *txt);
+void event_continue(struct event *events, char *txt);
+void event_print_all(FILE *fp, struct event *events);
+/* Stored calendar event */
+struct event {
+ int month;
+ int day;
+ int var;
+ char *date;
+ char *text;
+ struct event *next;
+};
diff --git a/misc_cmds/calendar/calendars/calendar.all b/misc_cmds/calendar/calendars/calendar.all
new file mode 100644
index 0000000..c7593f6
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.all
@@ -0,0 +1,20 @@
+/*
+ * International and national calendar files
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.all,v 1.10 2007/06/09 05:51:24 grog Exp $
+ */
+
+#ifndef _calendar_all_
+#define _calendar_all_
+
+#include <calendar.world>
+#include <calendar.croatian>
+#include <calendar.dutch>
+#include <calendar.french>
+#include <calendar.german>
+#include <calendar.hungarian>
+#include <calendar.southafrica>
+#include <calendar.russian>
+#include <calendar.usholiday>
+
+#endif /* !_calendar_all_ */
diff --git a/misc_cmds/calendar/calendars/calendar.australia b/misc_cmds/calendar/calendars/calendar.australia
new file mode 100644
index 0000000..32a3900
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.australia
@@ -0,0 +1,58 @@
+/*
+ * Australian holidays
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.australia,v 1.7 2006/10/06 23:20:01 flz Exp $
+ */
+
+#ifndef _calendar_australia_
+#define _calendar_australia_
+
+LANG=en_AU.ISO8859-1
+
+/* Australia */
+Jan 26 Australia Day
+Mar/SunLast Daylight Savings Time ends in ACT, NSW, SA, TAS and VIC.
+Apr 25 Anzac Day
+Jun/MonSecond Queen's Birthday Holiday (Australia, except WA)
+Oct/SunLast Daylight Savings Time starts in ACT, NSW, SA and VIC.
+
+/* ACT, NSW, common */
+Mar 18 Canberra Day (ACT)
+8/MonFirst Bank Holiday (ACT, NSW)
+10/MonFirst Labour Day (ACT, NSW, SA)
+
+/* Victoria */
+3/MonSecond Labour Day (Vic)
+Nov/TueFirst Melbourne Cup (Vic)
+
+/* Tasmania */
+Feb 11 Regatta Day (Tas)
+Feb 27 Launceston Cup (Tas)
+Mar 11 Eight Hours Day (Tas)
+Oct/SunFirst Daylight Savings Time starts in TAS.
+Oct 10 Launceston Show Day (Tas)
+Oct 24 Hobart Show Day (Tas)
+Nov 04 Recreation Day (N Tas)
+
+/* South Australia */
+May/MonThird Adelaide Cup (SA)
+Dec 26 Proclamation Day holiday (SA)
+
+/* Western Australia */
+3/MonFirst Labour Day (WA)
+6/MonFirst Foundation Day (WA)
+Sep 30 Queen's Birthday (WA)
+
+/* Northern Territory */
+5/MonFirst May Day (NT)
+7/FriFirst Alice Springs Show Day (NT)
+7/FriSecond Tennant Creek Show Day (NT)
+7/FriThird Katherine Show Day (NT)
+7/FriLast Darwin Show Day (NT)
+8/MonFirst Picnic Day (NT)
+
+/* Queensland */
+5/MonFirst Labour Day (Qld)
+Aug 14 RNA Show Day (Brisbane metro)
+
+#endif
diff --git a/misc_cmds/calendar/calendars/calendar.birthday b/misc_cmds/calendar/calendars/calendar.birthday
new file mode 100644
index 0000000..5233a0b
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.birthday
@@ -0,0 +1,299 @@
+/*
+ * Birthday
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.birthday,v 1.35 2007/10/14 08:52:29 maxim Exp $
+ */
+
+#ifndef _calendar_birthday_
+#define _calendar_birthday_
+
+01/01 J.D. Salinger born, 1919
+01/01 Paul Revere born in Boston, 1735
+01/02 Isaac Asimov born in Petrovichi, Russian SFSR, 1920
+01/04 George Washington Carver born in Missouri, 1864
+01/04 Jakob Grimm born, 1785
+01/04 Wilhelm Beer born, 1797, first astronomer to map Mars
+01/05 DeWitt B. Brace born, 1859, inventor of spectrophotometer
+01/10 Ethan Allen born, 1738
+01/11 Alexander Hamilton born in Nevis, British West Indies, 1757?
+01/12 "Long" John Baldry is born in London, 1941
+01/13 Horatio Alger born, 1834
+01/13 Sophie Tucker born, 1884
+01/13 Wilhelm Wien born, 1864, Nobel prize for blackbody radiation laws
+01/14 Albert Schweitzer born, 1875
+01/15 Martin Luther King, Jr. born
+01/17 Benjamin Franklin born in Boston, 1706
+01/19 Edgar Allan Poe born in Boston, 1809
+01/19 Robert Edward Lee born in Stratford Estate, Virginia, 1807
+01/20 George Burns born, 1898
+01/21 Lenin died, 1924
+01/21 Thomas Jonathan "Stonewall" Jackson born in Clarksburg, VA, 1824
+01/22 Sir Francis Bacon born, 1561
+01/23 Ernst Abbe born, 1840, formulated diffraction theory
+01/23 Humphrey Bogart born in New York City, 1899
+01/23 John Hancock born, 1737
+01/23 Joseph Hewes born, 1730
+01/23 Samuel Barber died, 1981
+01/24 John Belushi is born in Chicago, 1949
+01/25 Robert Burns born, 1759
+01/25 Virginia Woolf born, 1882
+01/25 W. Somerset Maugham born, 1874
+01/27 Samuel Gompers born, 1850
+01/30 Franklin Delano Roosevelt born in Hyde Park, New York, 1882
+01/31 Jackie Robinson born, 1919
+02/03 Gertrude Stein born, 1874
+02/05 Alex Harvey (SAHB) is born in Glasgow, Scotland, 1935
+02/06 King George VI of UK dies; his daughter becomes Elizabeth II, 1952
+02/07 Sinclair Lewis born, 1885
+02/08 Friedleib F. Runge born, 1795, father of paper chromatography
+02/08 Jules Verne born in Nantes, France, 1828
+02/09 George Hartmann born, 1489, designed astrolabes, timepieces, etc.
+02/10 Charles Lamb born, 1775
+02/10 William Allen White born, 1868
+02/11 Thos. Edison born, 1847
+02/11 William Henry Fox Talbot (photographic pioneer) born, 1800
+02/12 Abraham Lincoln born, 1809
+02/12 Charles Darwin born in Shrewsbury, England, 1809
+02/15 Galileo Galilei born in Pisa, Italy, 1564
+02/15 Susan B. Anthony born, 1820
+02/16 Pierre Bouguer born, 1698, founder of photometry
+02/17 Federick Eugene Ives born, 1856, pioneer of halftone
+02/17 Marion Anderson born, 1902
+02/17 T. J. Watson, Sr. born, 1874
+02/18 Ernst Mach born, 1838, philosopher & optics pioneer
+02/19 Nicolas Copernicus born in Thorn, Poland, 1473
+02/20 Ludwig Boltzmann born, 1838, atomic physics pioneer
+02/21 Alexis De Rochon born, 1838, developed the spyglass
+02/22 George Washington born, 1732
+02/22 Pierre Jules Cesar Janssen born, 1838, found hydrogen in the sun
+02/23 W.E.B. DuBois born, 1868
+02/24 Winslow Homer born, 1836
+02/25 George Harrison born in Liverpool, England, 1943
+02/25 Renoir born, 1841
+02/26 Dominique Francois Jean Arago born, 1786;
+ observed "Poisson's spot" cf June 21
+02/28 Michel de Mantaigne born, 1533
+02/29 Herman Hollerith born, 1860
+03/01 David Niven born, 1910
+03/02 Dr. Seuss born, 1904
+03/04 Casimir Pulaski born, 1747
+03/05 John Belushi dies in Los Angeles, 1982
+03/07 Sir John Frederick William Herschel born, 1792, astronomer
+03/08 Alvan Clark born, 1804, astronomer & lens manufacturer
+03/08 Howard Aiken born, 1900
+03/11 Robert Treat Paine born, 1737
+03/11 Vannevar Bush born, 1890
+03/12 Gustav Robert Kirchhoff born, 1824, physicist
+03/14 Albert Einstein born, 1879
+03/14 Casey Jones born, 1864
+03/14 Giovanni Virginia Schiaparelli born, 1835, astronomer;
+ named Mars "canals"
+03/14 Jean Baptiste Joseph Fourier born, 1768, mathematician & physicist
+03/15 Andrew "Old Hickory" Jackson, 7th President of the United States,
+ born in Waxhaw, South Carolina, 1767
+03/15 J.J. Robert's Birthday in Liberia
+03/16 George Clymer born, 1739
+03/16 James Madison, 4th President of the United States, born in King George
+ County, Virginia, 1751
+03/21 NetBSD project born, 1993
+03/24 Harry Houdini born, 1874
+03/26 Benjamin Thompson born, 1753, Count Rumford; physicist
+03/26 David Packard died, 1996; age of 83
+03/27 Wilhelm Conrad Roentgen born, 1845, discoverer of X-rays
+03/28 Pierre Simon de Laplace born, 1749, mathematician & astronomer
+03/30 Francisco Jose de Goya born, 1746
+03/30 Sean O'Casey born, 1880
+03/30 Vincent Van Gogh born, 1853
+03/31 Rene Descartes born, 1596, mathematician & philosopher
+04/02 Hans Christian Andersen born, 1805, fairy tale author
+04/02 Pope John Paul II (Karol Wojtyla) died in Vatican, 2005
+04/03 Washington Irving born, 1783
+04/05 Thomas Hobbes born, 1588, philosopher
+04/08 Buddha born, 563 BC
+04/08 David Rittenhouse born, 1732, astronomer & mathematician
+04/09 Edward Muybridge born, 1830, motion-picture pioneer
+04/09 J. Presper Eckert born, 1919
+04/10 Commodore Matthew Calbraith Perry born, 1794
+04/10 William Booth born, 1829, founder of the Salvation Army
+04/13 Thomas Jefferson, 3rd President of the United States, born Shadwell
+ Plantation, Albemarle County, Virginia, 1743
+04/14 Christian Huygen born, 1629, physicist & astronomer;
+ discovered Saturn's rings
+04/15 Leonardo da Vinci born, 1452
+04/16 Charles (Charlie) Chaplin (Sir) born in London, 1889
+04/22 Kant born, 1724
+04/27 Louis Victor de Broglie born, 1774, physicist
+04/28 James Monroe, 5th President of the United States, born in Westmoreland
+ County, Viriginia, 1758
+04/29 Jules Henri Poincare born, 1854, founder of topology
+04/29 William Randolph Hearst born in San Francisco, 1863
+04/30 Karl Friedrich Gauss born, 1777, mathematician & astronomer
+05/01 Little Walter (Marion Walter Jacobs) is born in Alexandria,
+ Louisiana, 1930
+05/02 Dr. Benjamin Spock born, 1903
+05/04 Alice Liddell born, 1852, Alice's Adventures in Wonderland
+ & Through the Looking-Glass
+05/09 Pinza died, 1957
+05/10 Fred Astaire (Frederick Austerlitz) born in Omaha, Nebraska, 1899
+05/11 Johnny Appleseed born, 1768
+05/12 Florence Nightingale born in Florence, Italy, 1820
+05/13 Arthur S. Sullivan born, 1842
+05/15 Mike Oldfield is born in Essex, England, 1953
+05/18 Pope John Paul II (Karol Wojtyla) born in Wadowice, Poland, 1920
+05/19 Ho Chi Minh born, 1890
+05/21 Plato (Aristocles) born in Athens(?), 427BC
+05/27 Hubert H. Humphrey born, 1911
+05/28 Dionne quintuplets born, 1934
+05/29 Gilbert Keith Chesterton born, 1874
+05/29 John Fitzgerald Kennedy, 35th President of the United States, born in
+ Brookline, Massachusetts, 1917
+05/29 Patrick Henry born, 1736
+05/30 Mel (Melvin Jerome) Blanc born in San Francisco, 1908
+06/01 Brigham Young born, 1801
+06/01 Marilyn Monroe born, 1928
+06/02 Edward Elgar (Sir) born in Worcester, England, 1857
+06/03 Henry James born, 1811
+06/07 (Eugene Henri) Paul Gaugin born, 1848
+06/07 George Bryan "Beau" Brummel born, 1778
+06/07 Alan Mathison Turing died, 1954
+06/08 Frank Lloyd Wright born in Richland Center, Wisconsin, 1867
+06/13 Alexander the Great dies (323BC)
+06/15 Edward (Edvard Hagerup) Grieg born in Bergen, Norway, 1843
+06/16 Hammurabi the Great dies, Babylon, 1686 BC
+06/18 M.C. Escher born, 1898
+06/19 FreeBSD project born, 1993
+06/22 Carl Hubbell born, 1903
+06/22 Meryl Streep born in Summit, New Jersey, 1949
+06/22 Konrad Zuse born in Berlin, 1919
+06/23 Alan Mathison Turing born, 1912
+06/25 Eric Arthur Blair (a.k.a. George Orwell) born, 1903
+06/27 Helen Keller born, 1880
+07/03 Franz Kafka born, 1883
+07/04 Nathaniel Hawthorne born in Salem, Massachusetts, 1804
+07/04 John Adams and Thomas Jefferson die on same day, 1826
+07/06 (Helen) Beatrix Potter born, 1866
+07/06 John Paul Jones born, 1747
+07/07 P.T. Barnum dies, 1891
+07/08 Count Ferdinand von Zeppelin born, 1838
+07/10 John Calvin born, 1509
+07/11 John Quincy Adams, 6th President of the United States, born in
+ Braintree, Massachusetts, 1767
+07/12 Henry David Thoreau born, 1817
+07/15 Clement Clarke Moore born, 1779, author of "A Visit from
+ Saint Nicholas"
+07/18 Brian Auger is born in London, 1939
+07/25 Steve Goodman is born in Chicago, 1948
+07/29 Mussolini born, 1883
+07/30 Emily Bronte born, 1818
+07/30 Henry Ford born, 1863
+08/01 Herman Melville born, 1819
+08/03 Lenny Bruce dies of a morphine overdose, 1966
+08/06 Jonathan B. Postel is born in Altadena, California, 1943
+08/08 Dustin Hoffman born in Los Angeles, 1937
+08/12 Thomas Mann's Death, 1955
+08/13 Alfred Hitchcock born, 1899
+08/13 Annie Oakley born, 1860
+08/13 Fidel Castro born, 1927
+08/17 Mae West born, 1892
+08/18 Meriwether Lewis born, 1774
+08/20 Leon Trotsky assassinated, 1940
+08/21 Christopher Robin Milne born, 1920
+08/21 Winnie-the-Pooh (Edward Bear) born (given to Christopher Robin
+ Milne), 1921
+08/23 Gene Kelly born, 1912
+08/27 Lyndon B. Johnson born, 1908
+08/29 Oliver Wendell Holmes born, 1809, physician & father of the jurist
+08/30 John W. Mauchly born, 1907
+09/05 King Louis XIV of France born, 1638
+09/05 Raquel Welch born, 1942
+09/06 Word is received that Perry has reached the North Pole and died, 1909
+09/07 James Fenimore Cooper born in Burlington, NJ, 1789
+09/07 Queen Elizabeth I of England born, 1533
+09/08 Richard ``the Lionheart'', king of England born in Oxford, 1157
+09/08 Peter Sellers born in Southsea, England, 1925
+09/09 Chinese Communist Party Chairman Mao Tse-Tung dies at age 82, 1976
+09/09 Dennis Ritchie born, 1941
+09/12 Jesse Owens born, 1913
+09/13 Walter Reed born, 1851
+09/15 Agatha Christie born in Torquay, England, 1890
+09/16 Allen Funt born in Brooklyn, NY, 1914
+09/18 Greta Garbo born, 1905
+09/18 Jimi Hendrix dies from an overdose, 1970
+09/20 Upton (Beall) Sinclair born, 1878
+09/21 H.G. (Herbert George) Wells born in Bromley, England, 1866
+09/21 Louis Joliet born, 1645
+09/22 President Garfield dies of wounds in Baltimore, 1881
+09/23 Augustus (Gaius Octavius) Caesar born in Rome, 63 BC
+09/23 Euripides born in Salamis, Greece, 480 BC
+09/24 F. Scott Fitzgerald born, 1896
+09/26 Johnny Appleseed born, 1774
+09/26 T.S. (Thomas Stearns) Eliot born in St. Louis, 1888
+09/27 Thomas Nast born, 1840
+09/28 Michelangelo Buonarroti born in Caprese, Italy, 1573
+09/28 Pompey (Gnaeus Pompeius Magnus) born in Rome, 106BC
+09/28 Seymour Cray born, 1925
+09/29 Gene Autry born, 1907
+10/01 Jimmy Carter, 39th President of United States, born in Plains, Georgia,
+ 1924
+10/02 Aristotle dies of indigestion, 322 BC
+10/02 Mohandas K. Gandhi born at Porbandar, Kathiawad, India, 1869
+10/04 John V. Atanasoff born, 1903
+10/05 Ray Kroc (founder of McDonald's) born, 1902
+10/13 Lenny Bruce is born in New York City, 1925
+10/13 Virgil (Publius Vergilius Maro) born near Mantua, Italy, 70 BC
+10/14 Dwight David Eisenhower, 34th President of the United States, born in
+ Denison, Texas, 1890
+10/14 William Penn born in London, 1644
+10/15 Pelham Grenville Wodehouse born, 1881
+10/16 Noah Webster born, 1758
+10/16 Oscar (Fingal O'Flahertie Wills) Wilde born in Dublin, 1854
+10/16 Dr. Jonathan B. Postel dies at age 55, 1998
+10/17 Richard Mentor Johnson born, 1780, 9th V.P. of U.S.
+10/21 Alfred Nobel born in Stockholm, 1833
+10/25 Pablo Picasso born in Malaga, Spain, 1881
+10/27 James Cook is born, 1728
+10/27 Theodore (Teddy) Roosevelt, 26th President of the United States, born
+ New York, New York, 1858
+10/27 Gerald M. Weinberg born, 1933
+10/30 John Adams, 2nd President of the United States, born Quincy,
+ Massachusetts 1735.
+10/31 Chiang Kai-Shek born, 1887
+10/31 Dale Evans born, 1912
+11/02 Daniel Boone born near Reading, PA, 1734
+11/04 King William III of Orange born, 1650
+11/05 Roy Rogers born, 1912
+11/09 Carl Sagan born, 1934
+11/10 Martin Luther born in Eisleben, Germany, 1483
+11/10 Soviet President Leonid Brezhnev dies at age 75, 1982
+11/11 Kurt Vonnegut, Jr, born in Indianapolis, 1922
+11/13 Robert Louis Stevenson born, 1850
+11/13 St. Augustine of Hippo born in Numidia, Algeria, 354
+11/18 Imogene Coca born, 1908
+11/18 William S. Gilbert born, 1836
+11/20 Robert Francis Kennedy (RFK) born in Boston, Massachusetts, 1925
+11/26 Charles Schulz born in Minneapolis, 1922
+11/26 Norbert Wiener born in Columbia, Missouri, 1894
+11/29 John Mayall is born in Cheshire, England, 1933
+11/30 Cleopatra died, 30 BC
+11/30 Mark Twain (Samuel Clemmens) born in Florida, Missouri, 1835
+12/01 Woody Allen (Allen Stuart Konigsberg) born in Brooklyn, NY, 1935
+12/04 Tommy Bolin dies of a heroin overdose in Miami, 1976
+12/05 Martin Van Buren, 8th President of the United States, born in
+ Kinderhook, New York, 1837
+12/05 Walt (Walter Elias) Disney born in Chicago, 1901
+12/08 Horace (Quintus Horatius Flaccus) born in Venosa (Italy), 65BC
+12/08 James (Grover) Thurber born in Columbus, Ohio, 1894
+12/10 Emily Dickenson born, 1830
+12/12 E.G. Robinson born, 1893
+12/14 George Washington dies, 1799
+12/17 William Safire (Safir) born, 1929
+12/18 Konrad Zuse died in Hünfeld, 1995
+12/20 Carl Sagan died, 1996
+12/21 Benjamin Disraeli born, 1804
+12/22 Giacomo Puccini born, 1858
+12/23 Joseph Smith born, 1805
+12/25 Isaac Newton (Sir) born in Grantham, England, 1642
+12/26 Chas. Babbage born, 1791
+12/28 John von Neumann born, 1903
+
+#endif /* !_calendar_birthday_ */
diff --git a/misc_cmds/calendar/calendars/calendar.christian b/misc_cmds/calendar/calendars/calendar.christian
new file mode 100644
index 0000000..b04b411
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.christian
@@ -0,0 +1,32 @@
+/*
+ * Christian
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.christian,v 1.10 2006/12/29 06:36:32 ru Exp $
+ */
+
+#ifndef _calendar_christian_
+#define _calendar_christian_
+
+01/05 Last (twelfth) day of Christmastide
+01/06 Epiphany
+Easter-47 Shrove Tuesday / Mardi Gras (day before Ash Wednesday)
+Easter-46 Ash Wednesday (First day of Lent)
+Easter-7 Palm Sunday (7 days before Easter)
+Easter-3 Maundy Thursday (3 days before Easter)
+Easter-2 Good Friday (2 days before Easter)
+Easter Easter Sunday
+Easter+39 Ascension Day (10 days before Pentecost)
+Easter+49 Pentecost (Whitsunday)
+Easter+50 Whitmonday
+Easter+56 Trinity Sunday (7 days after Pentecost)
+Easter+60 Corpus Christi (11 days after Pentecost)
+05/28* Rogation Sunday
+10/18 Feast Day of St. Luke
+11/SunLast First Sunday of Advent (4th Sunday before Christmas)
+12/SunFirst First Sunday of Advent (4th Sunday before Christmas)
+12/06 St. Nicholas' Day
+12/24 Christmas eve
+12/25 Christmastide begins: First day of Christmas
+12/26 Second day of Christmas (Boxing Day)
+
+#endif /* !_calendar_christian_ */
diff --git a/misc_cmds/calendar/calendars/calendar.computer b/misc_cmds/calendar/calendars/calendar.computer
new file mode 100644
index 0000000..6a4e9f0
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.computer
@@ -0,0 +1,76 @@
+/*
+ * Computer
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.computer,v 1.11 2007/09/07 03:23:06 edwin Exp $
+ */
+
+#ifndef _calendar_computer_
+#define _calendar_computer_
+
+01/01 AT&T officially divests its local Bell companies, 1984
+01/01 The Epoch (Time 0 for UNIX systems, Midnight GMT, 1970)
+01/03 Apple Computer founded, 1977
+01/08 American Telephone and Telegraph loses antitrust case, 1982
+01/08 Herman Hollerith patents first data processing computer, 1889
+01/08 Justice Dept. drops IBM suit, 1982
+01/10 First CDC 1604 delivered to Navy, 1960
+01/16 Set uid bit patent issued, to Dennis Ritchie, 1979
+01/17 Justice Dept. begins IBM anti-trust suit, 1969 (drops it, January 8, 1982)
+01/24 DG Nova introduced, 1969
+01/25 First U.S. meeting of ALGOL definition committee, 1958
+01/26 EDVAC demonstrated, 1952
+01/31 Hewlett-Packard founded, 1939
+02/11 Last day of JOSS service at RAND Corp., 1966
+02/14 First micro-on-a-chip patented (TI), 1978
+02/15 ENIAC demonstrated, 1946
+03/01 First NPL (later PL/I) report published, 1964
+03/04 First Cray-1 shipped to Los Alamos
+03/09 "GOTO considered harmful" (E.J. Dijkstra) published in CACM, 1968
+03/14 LISP introduced, 1960
+03/28 DEC announces PDP-11, 1970
+03/31 Eckert-Mauchly Computer Corp. founded, Phila, 1946
+04/01 Yourdon, Inc. founded, 1974 (It figures.)
+04/03 IBM 701 introduced, 1953
+04/04 Tandy Corp. acquires Radio Shack, 1963 (9 stores)
+04/07 IBM announces System/360, 1964
+04/09 ENIAC Project begun, 1943
+04/28 Zilog Z-80 introduced, 1976
+05/06 EDSAC demonstrated, 1949
+05/01 First BASIC program run at Dartmouth, 1964
+05/16 First report on SNOBOL distributed (within BTL), 1963
+05/19 UNIX is 10000 days old, 1997
+05/21 DEC announces PDP-8, 1965
+05/22 Ethernet first described, 1973
+05/27 First joint meeting of U.S. and European ALGOL definition cte., 1958
+05/28 First meeting of COBOL definition cte. (eventually CODASYL), 1959
+05/30 Colossus Mark II, 1944
+06/02 First issue of Computerworld, 1967
+06/07 Alan Mathison Turing died, 1954
+06/10 First Apple II shipped, 1977
+06/15 UNIVAC I delivered to the Census Bureau, 1951
+06/16 First publicized programming error at Census Bureau, 1951
+06/23 IBM unbundles software, 1969
+06/23 Alan Mathison Turing born, 1912
+06/30 First advanced degree on computer related topic: to H. Karamanian,
+ Temple Univ., Phila, 1948, for symbolic differentiation on the ENIAC
+07/08 Bell Telephone Co. formed (predecessor of AT&T), 1877
+07/08 CDC incorporated, 1957
+07/FriLast System Administrator Appreciation Day
+08/14 First Unix-based mallet created, 1954
+08/14 IBM PC announced, 1981
+08/22 CDC 6600 introduced, 1963
+08/23 DEC founded, 1957
+09/15 ACM founded, 1947
+09/20 Harlan Herrick runs first FORTRAN program, 1954
+10/02 First robotics-based CAM, 1939
+10/06 First GPSS manual published, 1961
+10/08 First VisiCalc prototype, 1978
+10/12 Univac gives contract for SIMULA compiler to Nygaard and Dahl, 1962
+10/14 British Computer Society founded, 1957
+10/15 First FORTRAN Programmer's Reference Manual published, 1956
+10/20 Zurich ALGOL report published, 1958
+10/25 DEC announces VAX-11/780
+11/04 UNIVAC I program predicts Eisenhower victory based on 7% of votes, 1952
+12/08 First Ph.D. awarded by Computer Science Dept, Univ. of Penna, 1965
+
+#endif /* !_calendar_computer_ */
diff --git a/misc_cmds/calendar/calendars/calendar.croatian b/misc_cmds/calendar/calendars/calendar.croatian
new file mode 100644
index 0000000..61d7493
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.croatian
@@ -0,0 +1,12 @@
+/*
+ * Croatian calendar files
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.croatian,v 1.5 2001/06/11 04:24:43 ache Exp $
+ */
+
+#ifndef _calendar_croatian_
+#define _calendar_croatian_
+
+#include <hr_HR.ISO8859-2/calendar.all>
+
+#endif /* !_calendar_croatian_ */
diff --git a/misc_cmds/calendar/calendars/calendar.dutch b/misc_cmds/calendar/calendars/calendar.dutch
new file mode 100644
index 0000000..1ce5562
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.dutch
@@ -0,0 +1,78 @@
+/*
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.dutch,v 1.4 2008/02/18 07:09:17 edwin Exp $
+ *
+ * Originally submitted by Edwin Groothuis <edwin@FreeBSD.org>
+ */
+
+LANG=nl_NL.ISO8859-15
+
+/*
+ * Feestdagen
+ */
+01/01 Nieuwjaar
+01/06 Driekoningen
+04/01 Een April
+04/30 Koninginendag
+05/01 Dag van de Arbeid
+05/04 Dodenherdenking
+05/05 Bevrijdingsdag
+10/04 Dierendag
+11/01 Allerheilingen
+11/02 Allerzielen
+11/11 Sint Maarten
+11/11 Elfde-van-de-elfde
+12/05 Sinterklaas avond
+12/15 Koninkrijksdag
+12/24 Kerstavond
+12/25 Eerste kerstdag
+12/26 Tweede kerstdag
+12/28 Feest der Onnozele Kinderen
+12/31 Oudjaar
+
+/*
+ * Pasen gerelateerd
+ */
+Easter-50 Carnaval
+Easter-49 Carnaval
+Easter-48 Carnaval
+Easter-47 Carnaval (Vastenavond)
+Easter-46 Aswoensdag
+Easter-7 Palmzondag
+Easter-3 Witte Donderdag
+Easter-2 Goede vrijdag
+Easter-1 Stille zaterdag
+Easter Eerste paasdag
+Easter+1 Tweede paasdag
+Easter+39 Hemelvaartsdag
+Easter+49 Eerste Pinksterdag
+Easter+50 Tweede Pinksterdag
+Easter+56 Trinitatis
+
+/*
+ * Misc
+ */
+05/SunSecond Moederdag
+06/SunThird Vaderdag
+09/TueThird Prinsjesdag
+
+/*
+ * Het koningshuis
+ */
+01/19 Prinses Margriet (1943)
+01/31 Koningin Beatrix (1938)
+02/17 Prins Willem III (1817 - 1890)
+02/18 Prinses Christina (1947)
+04/10 Prinses Ariane (2007)
+04/19 Prins Hendrik (1876 - 1934)
+04/27 Kroonprins Willem Alexander (1967)
+04/30 Koningin Juliana (1909 - 2004)
+04/30 Mr. Pieter van Vollenhoven (1939)
+05/17 Prinses Maxima (1971)
+06/26 Prinses Alexia (2005)
+06/29 Prins Bernhard (1911 - 2004)
+08/05 Prinses Irene (1939)
+08/31 Prinses Wilhelmina (1880 - 1962)
+09/06 Prins Claus (1925 - 2002)
+09/25 Prins Johan Friso (1968)
+10/11 Prins Constantijn (1969)
+12/07 Prinses Catharina-Amalia (2003)
diff --git a/misc_cmds/calendar/calendars/calendar.freebsd b/misc_cmds/calendar/calendars/calendar.freebsd
new file mode 100644
index 0000000..2cda19b
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.freebsd
@@ -0,0 +1,283 @@
+/*
+ * FreeBSD
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.freebsd,v 1.224 2008/02/05 19:34:54 antoine Exp $
+ */
+
+#ifndef _calendar_freebsd_
+#define _calendar_freebsd_
+
+01/01 Alexander Langer <alex@FreeBSD.org> born in Duesseldorf, Nordrhein-Westfalen, Germany, 1981
+01/02 Ion-Mihai "IOnut" Tetcu <itetcu@FreeBSD.org> born in Bucharest, Romania, 1980
+01/02 Patrick Li <pat@FreeBSD.org> born in Beijing, People's Republic of China, 1985
+01/03 Tetsurou Okazaki <okazaki@FreeBSD.org> born in Mobara, Chiba, Japan, 1972
+01/04 Hiroyuki Hanai <hanai@FreeBSD.org> born in Kagawa pre., Japan, 1969
+01/08 Michael L. Hostbaek <mich@FreeBSD.org> born in Copenhagen, Denmark, 1977
+01/10 Jean-Yves Lefort <jylefort@FreeBSD.org> born in Charleroi, Belgium, 1980
+01/12 Yen-Ming Lee <leeym@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1977
+01/12 Ying-Chieh Liao <ijliao@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1979
+01/16 Ariff Abdullah <ariff@FreeBSD.org> born in Kuala Lumpur, Malaysia, 1978
+01/16 Dmitry Sivachenko <demon@FreeBSD.org> born in Moscow, USSR, 1978
+01/16 Vanilla I. Shu <vanilla@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1978
+01/18 Dejan Lesjak <lesi@FreeBSD.org> born in Ljubljana, Slovenia, Yugoslavia, 1977
+01/19 Marshall Kirk McKusick <mckusick@FreeBSD.org> born in Wilmington, Delaware, United States, 1954
+01/19 Marcelo S. Araujo <araujo@FreeBSD.org> born in Joinville, Santa Catarina, Brazil, 1981
+01/19 Ruslan Ermilov <ru@FreeBSD.org> born in Simferopol, USSR, 1974
+01/20 Poul-Henning Kamp <phk@FreeBSD.org> born in Korsoer, Denmark, 1966
+01/22 Johann Visagie <wjv@FreeBSD.org> born in Cape Town, South Africa, 1970
+01/23 Hideyuki KURASHINA <rushani@FreeBSD.org> born in Niigata, Japan, 1982
+01/24 Matteo Riondato <matteo@FreeBSD.org> born in Padova, Italy, 1986
+01/25 Bernd Walter <ticso@FreeBSD.org> born in Moers, Nordrhein-Westfalen, Germany, 1974
+01/26 Andrew Gallatin <gallatin@FreeBSD.org> born in Buffalo, New York, United States, 1970
+01/27 Nick Sayer <nsayer@FreeBSD.org> born in San Diego, California, United States, 1968
+01/27 Jacques Anthony Vidrine <nectar@FreeBSD.org> born in Baton Rouge, Louisiana, United States, 1971
+01/31 Hidetoshi Shimokawa <simokawa@FreeBSD.org> born in Yokohama, Kanagawa, Japan, 1970
+02/01 Nicola Vitale <nivit@FreeBSD.org> born in Busto Arsizio, Varese, Italy, 1976
+02/01 Paul Saab <ps@FreeBSD.org> born in Champaign-Urbana, Illinois, United States, 1978
+02/01 Martin Wilke <miwi@FreeBSD.org> born in Ludwigsfelde, Brandenburg, Germany, 1980
+02/01 Christian Brueffer <brueffer@FreeBSD.org> born in Gronau, Nordrhein-Westfalen, Germany, 1982
+02/01 Juli Mallett <jmallett@FreeBSD.org> born in Washington, Pennsylvania, United States, 1985
+02/02 Diomidis D. Spinellis <dds@FreeBSD.org> born in Athens, Greece, 1967
+02/02 Yoichi Nakayama <yoichi@FreeBSD.org> born in Tsu, Mie, Japan, 1976
+02/05 Frank Laszlo <laszlof@FreeBSD.org> born in Howell, Michigan, United States, 1983
+02/10 David Greenman <dg@FreeBSD.org> born in Portland, Oregon, United States, 1968
+02/10 Paul Richards <paul@FreeBSD.org> born in Ammanford, Carmarthenshire, United Kingdom, 1968
+02/10 Simon Barner <barner@FreeBSD.org> born in Rosenheim, Bayern, Germany, 1980
+02/13 Jesper Skriver <jesper@FreeBSD.org> born in Aarhus, Denmark, 1975
+02/13 Andrey Slusar <anray@FreeBSD.org> born in Odessa, USSR, 1979
+02/13 David W. Chapman Jr. <dwcjr@FreeBSD.org> born in Bethel, Connecticut, United States, 1981
+02/14 Erwin Lansing <erwin@FreeBSD.org> born in 's-Hertogenbosch, the Netherlands, 1975
+02/14 Martin Blapp <mbr@FreeBSD.org> born in Olten, Switzerland, 1976
+02/19 Murray Stokely <murray@FreeBSD.org> born in Jacksonville, Florida, United States, 1979
+02/20 Anders Nordby <anders@FreeBSD.org> born in Oslo, Norway, 1976
+02/21 Alexey Zelkin <phantom@FreeBSD.org> born in Simferopol, Ukraine, 1978
+02/22 Brooks Davis <brooks@FreeBSD.org> born in Longview, Washington, United States, 1976
+02/22 Jake Burkholder <jake@FreeBSD.org> born in Maynooth, Ontario, Canada, 1979
+02/23 Peter Wemm <peter@FreeBSD.org> born in Perth, Western Australia, Australia, 1971
+02/23 Mathieu Arnold <mat@FreeBSD.org> born in Champigny sur Marne, Val de Marne, France, 1978
+02/24 Johan Karlsson <johan@FreeBSD.org> born in Mariannelund, Sweden, 1974
+02/24 Colin Percival <cperciva@FreeBSD.org> born in Burnaby, Canada, 1981
+02/28 Daichi GOTO <daichi@FreeBSD.org> born in Shimizu Suntou, Shizuoka, Japan, 1980
+03/01 Hye-Shik Chang <perky@FreeBSD.org> born in Daejeon, Republic of Korea, 1980
+03/02 Cy Schubert <cy@FreeBSD.org> born in Edmonton, Alberta, Canada, 1956
+03/03 Sergey Matveychuk <sem@FreeBSD.org> born in Moscow, Russian Federation, 1973
+03/03 Doug White <dwhite@FreeBSD.org> born in Eugene, Oregon, United States, 1977
+03/03 Gordon Tetlow <gordon@FreeBSD.org> born in Reno, Nevada, United States, 1978
+03/05 Philip Paeps <philip@FreeBSD.org> born in Leuven, Belgium, 1983
+03/05 Ulf Lilleengen <lulf@FreeBSD.org> born in Hamar, Norway, 1985
+03/06 Christopher Piazza <cpiazza@FreeBSD.org> born in Kamloops, British Columbia, Canada, 1981
+03/07 Michael P. Pritchard <mpp@FreeBSD.org> born in Los Angeles, California, United States, 1964
+03/07 Giorgos Keramidas <keramida@FreeBSD.org> born in Athens, Greece, 1976
+03/10 Andreas Klemm <andreas@FreeBSD.org> born in Duesseldorf, Nordrhein-Westfalen, Germany, 1963
+03/11 Soeren Straarup <xride@FreeBSD.org> born in Andst, Denmark, 1978
+03/12 Greg Lewis <glewis@FreeBSD.org> born in Adelaide, South Australia, Australia, 1969
+03/13 Alexander Leidinger <netchild@FreeBSD.org> born in Neunkirchen, Saarland, Germany, 1976
+03/13 Will Andrews <will@FreeBSD.org> born in Pontiac, Michigan, United States, 1982
+03/15 Paolo Pisati <piso@FreeBSD.org> born in Lodi, Italy, 1977
+03/15 Brian Fundakowski Feldman <green@FreeBSD.org> born in Alexandria, Virginia, United States, 1983
+03/17 Michael Smith <msmith@FreeBSD.org> born in Bankstown, New South Wales, Australia, 1971
+03/18 Koop Mast <kwm@FreeBSD.org> born in Dokkum, the Netherlands, 1981
+03/19 Mikhail Teterin <mi@FreeBSD.org> born in Kyiv, Ukraine, 1972
+03/20 MANTANI Nobutaka <nobutaka@FreeBSD.org> born in Hiroshima, Japan, 1978
+03/20 Cameron Grant <cg@FreeBSD.org> died in Hemel Hempstead, United Kingdom, 2005
+03/20 Henrik Brix Andersen <brix@FreeBSD.org> born in Aarhus, Denmark, 1978
+03/22 Brad Davis <brd@FreeBSD.org> born in Farmington, New Mexico, United States, 1983
+03/23 Daniel C. Sobral <dcs@FreeBSD.org> born in Brasilia, Distrito Federal, Brazil, 1971
+03/23 Benno Rice <benno@FreeBSD.org> born in Adelaide, South Australia, Australia, 1977
+03/24 Marcel Moolenaar <marcel@FreeBSD.org> born in Hilversum, the Netherlands, 1968
+03/24 Emanuel Haupt <ehaupt@FreeBSD.org> born in Zurich, Switzerland, 1979
+03/25 Andrew R. Reiter <arr@FreeBSD.org> born in Springfield, Massachusetts, United States, 1980
+03/27 Josef El-Rayes <josef@FreeBSD.org> born in Linz, Austria, 1982
+03/28 Sean C. Farley <scf@FreeBSD.org> born in Indianapolis, Indiana, United States, 1970
+03/29 Thierry Thomas <thierry@FreeBSD.org> born in Luxeuil les Bains, France, 1961
+04/01 Matthew Jacob <mjacob@FreeBSD.org> born in San Francisco, California, United States, 1958
+04/01 Bill Fenner <fenner@FreeBSD.org> born in Bellefonte, Pennsylvania, United States, 1971
+04/01 Peter Edwards <peadar@FreeBSD.org> born in Dublin, Ireland, 1973
+04/03 Hellmuth Michaelis <hm@FreeBSD.org> born in Kiel, Schleswig-Holstein, Germany, 1958
+04/03 Tong Liu <nemoliu@FreeBSD.org> born in Beijing, People's Republic of China, 1981
+04/08 Jordan K. Hubbard <jkh@FreeBSD.org> born in Honolulu, Hawaii, United States, 1963
+04/09 Ceri Davies <ceri@FreeBSD.org> born in Haverfordwest, Pembrokeshire, United Kingdom, 1976
+04/11 Bruce A. Mah <bmah@FreeBSD.org> born in Fresno, California, United States, 1969
+04/12 Patrick Gardella <patrick@FreeBSD.org> born in Columbus, Ohio, United States, 1967
+04/13 Oliver Braun <obraun@FreeBSD.org> born in Nuremberg, Bavaria, Germany, 1972
+04/14 Crist J. Clark <cjc@FreeBSD.org> born in Milwaukee, Wisconsin, United States, 1970
+04/15 David Malone <dwmalone@FreeBSD.org> born in Dublin, Ireland, 1973
+04/17 Dryice Liu <dryice@FreeBSD.org> born in Jinan, Shandong, China, 1975
+04/22 Joerg Wunsch <joerg@FreeBSD.org> born in Dresden, Sachsen, Germany, 1962
+04/22 Jun Kuriyama <kuriyama@FreeBSD.org> born in Matsue, Shimane, Japan, 1973
+04/29 Adam Weinberger <adamw@FreeBSD.org> born in Berkeley, California, United States, 1980
+04/29 Eric Anholt <anholt@FreeBSD.org> born in Portland, Oregon, United States, 1983
+05/02 Wojciech A. Koszek <wkoszek@FreeBSD.org> born in Czestochowa, Poland, 1987
+05/03 Brian Dean <bsd@FreeBSD.org> born in Elkins, West Virginia, United States, 1966
+05/03 Robert Nicholas Maxwell Watson <rwatson@FreeBSD.org> born in Harrow, Middlesex, United Kingdom, 1977
+05/04 Denis Peplin <den@FreeBSD.org> born in Nizhniy Novgorod, Russian Federation, 1977
+05/08 Kirill Ponomarew <krion@FreeBSD.org> born in Volgograd, Russian Federation, 1977
+05/08 Sean Kelly <smkelly@FreeBSD.org> born in Walnut Creek, California, United States, 1982
+05/09 Daniel Eischen <deischen@FreeBSD.org> born in Syracuse, New York, United States, 1963
+05/09 Aaron Dalton <aaron@FreeBSD.org> born in Boise, Idaho, United States, 1973
+05/10 Markus Brueffer <markus@FreeBSD.org> born in Gronau, Nordrhein-Westfalen, Germany, 1977
+05/11 Jesus Rodriguez <jesusr@FreeBSD.org> born in Barcelona, Spain, 1972
+05/11 Roman Kurakin <rik@FreeBSD.org> born in Moscow, USSR, 1979
+05/13 Pete Fritchman <petef@FreeBSD.org> born in Lansdale, Pennsylvania, United States, 1983
+05/14 Tatsumi Hosokawa <hosokawa@FreeBSD.org> born in Tokyo, Japan, 1968
+05/14 Shigeyuku Fukushima <shige@FreeBSD.org> born in Osaka, Japan, 1974
+05/16 Johann Kois <jkois@FreeBSD.org> born in Wolfsberg, Austria, 1975
+05/16 Marcus Alves Grando <mnag@FreeBSD.org> born in Florianopolis, Santa Catarina, Brazil, 1979
+05/17 Thomas Abthorpe <tabthorpe@FreeBSD.org> born in Port Arthur, Ontario, Canada, 1968
+05/19 Philippe Charnier <charnier@FreeBSD.org> born in Fontainebleau, France, 1966
+05/19 Ian Dowse <iedowse@FreeBSD.org> born in Dublin, Ireland, 1975
+05/21 Kris Kennaway <kris@FreeBSD.org> born in Winnipeg, Manitoba, Canada, 1978
+05/22 Clive Tong-I Lin <clive@FreeBSD.org> born in Changhua, Taiwan, Republic of China, 1978
+05/22 Michael Bushkov <bushman@FreeBSD.org> born in Rostov-on-Don, Russia, 1985
+05/23 Munechika Sumikawa <sumikawa@FreeBSD.org> born in Osaka, Osaka, Japan, 1972
+05/24 Duncan McLennan Barclay <dmlb@FreeBSD.org> born in London, Middlesex, United Kingdom, 1970
+05/24 Oliver Lehmann <oliver@FreeBSD.org> born in Karlsburg, Germany, 1981
+05/25 Tom Rhodes <trhodes@FreeBSD.org> born in Ellwood City, Pennsylvania, United States, 1981
+05/26 Jim Pirzyk <pirzyk@FreeBSD.org> born in Chicago, Illinois, United States, 1968
+05/27 Ollivier Robert <roberto@FreeBSD.org> born in Paris, France, 1967
+05/29 Wilko Bulte <wilko@FreeBSD.org> born in Arnhem, the Netherlands, 1965
+05/29 Seigo Tanimura <tanimura@FreeBSD.org> born in Kitakyushu, Fukuoka, Japan, 1976
+05/31 Ville Skytta <scop@FreeBSD.org> born in Helsinki, Finland, 1974
+06/02 Jean-Marc Zucconi <jmz@FreeBSD.org> born in Pontarlier, France, 1954
+06/02 Alexander Botero-Lowry <alexbl@FreeBSD.org> born in Austin, TX, USA, 1986
+06/03 CHOI Junho <cjh@FreeBSD.org> born in Seoul, Korea, 1974
+06/04 Julian Elischer <julian@FreeBSD.org> born in Perth, Australia, 1959
+06/04 Jason Evans <jasone@FreeBSD.org> born in Greeley, Colorado, United States, 1973
+06/04 Thomas Moestl <tmm@FreeBSD.org> born in Braunschweig, Niedersachsen, Germany, 1980
+06/06 Sergei Kolobov <sergei@FreeBSD.org> born in Karpinsk, Russian Federation, 1972
+06/06 Alan Eldridge <alane@FreeBSD.org> died in Denver, Colorado, 2003
+06/07 Benjamin Close <benjsc@FreeBSD.org> born in Adelaide, Australia, 1978
+06/07 Jimmy Olgeni <olgeni@FreeBSD.org> born in Milano, Italy, 1976
+06/17 Tilman Linneweh <arved@FreeBSD.org> born in Weinheim, Baden-Wuertemberg, Germany, 1978
+06/18 Li-Wen Hsu <lwhsu@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1984
+06/18 Roman Bogorodskiy <novel@FreeBSD.org> born in Saratov, Russian Federation, 1986
+06/19 Charlie Root <root@FreeBSD.org> born in Portland, Oregon, United States, 1993
+06/21 Niels Heinen <niels@FreeBSD.org> born in Markelo, the Netherlands, 1978
+06/24 Chris Faulhaber <jedgar@FreeBSD.org> born in Springfield, Illinois, United States, 1971
+06/26 Brian Somers <brian@FreeBSD.org> born in Dundrum, Dublin, Ireland, 1967
+06/28 Mark Santcroos <marks@FreeBSD.org> born in Rotterdam, the Netherlands, 1979
+06/28 Xin Li <delphij@FreeBSD.org> born in Beijing, People's Republic of China, 1982
+06/29 Wilfredo Sanchez Vega <wsanchez@FreeBSD.org> born in Majaguez, Puerto Rico, United States, 1972
+06/29 Daniel Harris <dannyboy@FreeBSD.org> born in Lubbock, Texas, United States, 1985
+06/29 Andrew Pantyukhin <sat@FreeBSD.org> born in Moscow, Russian Federation, 1985
+06/30 Guido van Rooij <guido@FreeBSD.org> born in Best, Noord-Brabant, the Netherlands, 1965
+07/01 Matthew Dillon <dillon@apollo.backplane.net> born in San Francisco, California, United States, 1966
+07/02 Mark Christopher Ovens <marko@FreeBSD.org> born in Preston, Lancashire, United Kingdom, 1958
+07/02 Vasil Venelinov Dimov <vd@FreeBSD.org> born in Shumen, Bulgaria, 1982
+07/04 Motoyuki Konno <motoyuki@FreeBSD.org> born in Musashino, Tokyo, Japan, 1969
+07/04 Florent Thoumie <flz@FreeBSD.org> born in Montmorency, Val d'Oise, France, 1982
+07/07 Andrew Thompson <thompsa@FreeBSD.org> born in Lower Hutt, Wellington, New Zealand, 1979
+07/07 Maxime Henrion <mux@FreeBSD.org> born in Metz, France, 1981
+07/07 George Reid <greid@FreeBSD.org> born in Frimley, Hampshire, United Kingdom, 1983
+07/10 Jung-uk Kim <jkim@FreeBSD.org> born in Seoul, Korea, 1971
+07/10 Justin Seger <jseger@FreeBSD.org> born in Harvard, Massachusetts, United States, 1981
+07/10 David Schultz <das@FreeBSD.org> born in Oakland, California, United States, 1982
+07/11 Jesus R. Camou <jcamou@FreeBSD.org> born in Hermosillo, Sonora, Mexico, 1983
+07/15 Gary Jennejohn <gj@FreeBSD.org> born in Rochester, New York, United States, 1950
+07/16 Suleiman Souhlal <ssouhlal@FreeBSD.org> born in Roma, Italy, 1983
+07/17 Michael Chin-Yuan Wu <keichii@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1980
+07/19 Masafumi NAKANE <max@FreeBSD.org> born in Okazaki, Aichi, Japan, 1972
+07/19 Simon L. Nielsen <simon@FreeBSD.org> born in Copenhagen, Denmark, 1980
+07/19 Gleb Smirnoff <glebius@FreeBSD.org> born in Kharkov, USSR, 1981
+07/22 James Housley <jeh@FreeBSD.org> born in Chicago, Illinois, United States, 1965
+07/22 Jens Schweikhardt <schweikh@FreeBSD.org> born in Waiblingen, Baden-Wuerttemberg, Germany, 1967
+07/22 Lukas Ertl <le@FreeBSD.org> born in Weissenbach/Enns, Steiermark, Austria, 1976
+07/23 Sergey A. Osokin <osa@FreeBSD.org> born in Krasnogorsky, Stepnogorsk, Akmolinskaya region, Kazakhstan, 1972
+07/24 Alexander Nedotsukov <bland@FreeBSD.org> born in Ulyanovsk, Russian Federation, 1974
+07/28 Jim Mock <jim@FreeBSD.org> born in Bethlehem, Pennsylvania, United States, 1974
+07/28 Tom Hukins <tom@FreeBSD.org> born in Manchester, United Kingdom, 1976
+07/29 Dirk Meyer <dinoex@FreeBSD.org> born in Kassel, Hessen, Germany, 1965
+08/02 Gabor Kovesdan <gabor@FreeBSD.org> born in Budapest, Hungary, 1987
+08/05 Alfred Perlstein <alfred@FreeBSD.org> born in Brooklyn, New York, United States, 1978
+08/06 Anton Berezin <tobez@FreeBSD.org> born in Dnepropetrovsk, Ukraine, 1970
+08/06 John-Mark Gurney <jmg@FreeBSD.org> born in Detroit, Michigan, United States, 1978
+08/07 Jonathan Mini <mini@FreeBSD.org> born in San Mateo, California, United States, 1979
+08/10 Peter Pentchev <roam@FreeBSD.org> born in Sofia, Bulgaria, 1977
+08/12 Joe Marcus Clarke <marcus@FreeBSD.org> born in Lakeland, Florida, United States, 1976
+08/14 Stefan Esser <se@FreeBSD.org> born in Cologne, Nordrhein-Westfalen, Germany, 1961
+08/17 Olivier Houchard <cognet@FreeBSD.org> born in Nancy, France, 1980
+08/19 Pav Lucistnik <pav@FreeBSD.org> born in Kutna Hora, Czech Republic, 1980
+08/19 Chin-San Huang <chinsan@FreeBSD.org> born in Yi-Lan, Taiwan, Republic of China, 1979
+08/20 Michael Heffner <mikeh@FreeBSD.org> born in Cleona, Pennsylvania, United States, 1981
+08/24 Mark Linimon <linimon@FreeBSD.org> born in Houston, Texas, United States, 1955
+08/25 Jean Milanez Melo <jmelo@FreeBSD.org> born in Divinopolis, Minas Gerais, Brazil, 1982
+08/25 Beech Rintoul <beech@FreeBSD.org> born in Oakland, California, United States, 1952
+08/26 Dima Ruban <dima@FreeBSD.org> born in Nalchik, USSR, 1970
+08/26 Marc Fonvieille <blackend@FreeBSD.org> born in Avignon, France, 1972
+08/26 Herve Quiroz <hq@FreeBSD.org> born in Aix-en-Provence, France, 1977
+08/27 Andrey Chernov <ache@FreeBSD.org> born in Moscow, USSR, 1966
+08/27 Tony Finch <fanf@FreeBSD.org> born in London, United Kingdom, 1974
+08/27 Michael Johnson <ahze@FreeBSD.org> born in Morganton, North Carolina, United States, 1980
+08/28 Norikatsu Shigemura <nork@FreeBSD.org> born in Fujisawa, Kanagawa, Japan, 1974
+08/29 Thomas Gellekum <tg@FreeBSD.org> born in Moenchengladbach, Nordrhein-Westfalen, Germany, 1967
+08/29 Max Laier <mlaier@FreeBSD.org> born in Karlsruhe, Germany, 1981
+09/01 Pyun YongHyeon <yongari@FreeBSD.org> born in Kimcheon, Korea, 1968
+09/03 Max Khon <fjoe@FreeBSD.org> born in Novosibirsk, USSR, 1976
+09/03 Cheng-Lung Sung <clsung@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1977
+09/05 Mark Robert Vaughan Murray <markm@FreeBSD.org> born in Harare, Mashonaland, Zimbabwe, 1961
+09/05 Adrian Harold Chadd <adrian@FreeBSD.org> born in Perth, Western Australia, Australia, 1979
+09/07 Tim Bishop <tdb@FreeBSD.org> born in Cornwall, United Kingdom, 1978
+09/08 Boris Samorodov <bsam@FreeBSD.org> born in Krasnodar, Russian Federation, 1963
+09/09 Yoshio Mita <mita@FreeBSD.org> born in Hiroshima, Japan, 1972
+09/10 Wesley R. Peters <wes@FreeBSD.org> born in Hartford, Alabama, United States, 1961
+09/12 Weongyo Jeong <weongyo@FreeBSD.org> born in Haman, Korea, 1980
+09/12 William C. Fumerola II <billf@FreeBSD.org> born in Detroit, Michigan, United States, 1981
+09/17 Maxim Bolotin <mb@FreeBSD.org> born in Rostov-on-Don, Russian Federation, 1976
+09/20 Kevin Lo <kevlo@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1972
+09/27 Neil Blakey-Milner <nbm@FreeBSD.org> born in Port Elizabeth, South Africa, 1978
+09/27 Renato Botelho <garga@FreeBSD.org> born in Araras, Sao Paulo, Brazil, 1979
+09/28 Greg Lehey <grog@FreeBSD.org> born in Melbourne, Victoria, Australia, 1948
+09/28 Alex Dupre <ale@FreeBSD.org> born in Milano, Italy, 1980
+09/29 Matthew Hunt <mph@FreeBSD.org> born in Johnstown, Pennsylvania, United States, 1976
+09/30 Hiten M. Pandya <hmp@FreeBSD.org> born in Dar-es-Salaam, Tanzania, East Africa, 1986
+10/05 Hiroki Sato <hrs@FreeBSD.org> born in Yamagata, Japan, 1977
+10/05 Chris Costello <chris@FreeBSD.org> born in Houston, Texas, United States, 1985
+10/09 Stefan Walter <stefan@FreeBSD.org> born in Werne, Nordrhein-Westfalen, 1978
+10/12 Pawel Jakub Dawidek <pjd@FreeBSD.org> born in Radzyn Podlaski, Poland, 1980
+10/15 Maxim Konovalov <maxim@FreeBSD.org> born in Khabarovsk, USSR, 1973
+10/16 Remko Lodder <remko@FreeBSD.org> born in Rotterdam, the Netherlands, 1983
+10/17 Maho NAKATA <maho@FreeBSD.org> born in Osaka, Japan, 1974
+10/18 Sheldon Hearn <sheldonh@FreeBSD.org> born in Cape Town, Western Cape, South Africa, 1974
+10/19 Nicholas Souchu <nsouch@FreeBSD.org> born in Suresnes, Hauts-de-Seine, France, 1972
+10/20 Joel Dahl <joel@FreeBSD.org> born in Lidkoping, Sweden, 1983
+10/21 Dan Moschuk <dan@FreeBSD.org> born in Halifax, Nova Scotia, Canada, 1980
+10/21 Ben Smithurst <ben@FreeBSD.org> born in Sheffield, South Yorkshire, United Kingdom, 1981
+10/22 Jean-Sebastien Pedron <dumbbell@FreeBSD.org> born in Redon, Ille-et-Vilaine, France, 1980
+10/23 Mario Sergio Fujikawa Ferreira <lioux@FreeBSD.org> born in Brasilia, Distrito Federal, Brazil, 1976
+10/25 Eric Melville <eric@FreeBSD.org> born in Los Gatos, California, United States, 1980
+10/27 Takanori Watanabe <takawata@FreeBSD.org> born in Numazu, Shizuoka, Japan, 1972
+11/05 M. Warner Losh <imp@FreeBSD.org> born in Kansas City, Kansas, United States, 1966
+11/09 Coleman Kane <cokane@FreeBSD.org> born in Cincinnati, OH, United States, 1980
+11/09 Antoine Brodin <antoine@FreeBSD.org> born in Bagnolet, France, 1981
+11/10 Gregory Neil Shapiro <gshapiro@FreeBSD.org> born in Providence, Rhode Island, United States, 1970
+11/13 John Baldwin <jhb@FreeBSD.org> born in Stuart, Virginia, United States, 1977
+11/15 Lars Engels <lme@FreeBSD.org> born in Hilden, Nordrhein-Westfalen, Germany, 1980
+11/16 Jose Maria Alcaide Salinas <jmas@FreeBSD.org> born in Madrid, Spain, 1962
+11/17 Ralf S. Engelschall <rse@FreeBSD.org> born in Dachau, Bavaria, Germany, 1972
+11/18 Thomas Quinot <thomas@FreeBSD.org> born in Paris, France, 1977
+11/19 Konstantin Belousov <kib@FreeBSD.org> born in Kiev, USSR, 1972
+11/20 Dmitry Morozovsky <marck@FreeBSD.org> born in Moscow, USSR, 1968
+11/23 Josef Lawrence Karthauser <joe@FreeBSD.org> born in Pembury, Kent, United Kingdom, 1972
+11/24 Andrey Zakhvatov <andy@FreeBSD.org> born in Chelyabinsk, Russian Federation, 1974
+11/24 Daniel Gerzo <danger@FreeBSD.org> born in Bratislava, Slovakia, 1986
+11/28 Nik Clayton <nik@FreeBSD.org> born in Peterborough, United Kingdom, 1973
+11/28 Stanislav Sedov <stas@FreeBSD.org> born in Chelyabinsk, USSR, 1985
+12/01 Hajimu Umemoto <ume@FreeBSD.org> born in Nara, Japan, 1961
+12/01 Alexey Dokuchaev <danfe@FreeBSD.org> born in Magadan, USSR, 1980
+12/03 Diane Bruce <db@FreeBSD.org> born in Ottawa, Ontario, Canada, 1952
+12/06 Stefan Farfeleder <stefanf@FreeBSD.org> born in Wien, Austria, 1980
+12/15 James FitzGibbon <jfitz@FreeBSD.org> born in Amersham, Buckinghamshire, United Kingdom, 1974
+12/15 Timur I. Bakeyev <timur@FreeBSD.org> born in Kazan, Republic of Tatarstan, USSR, 1974
+12/18 Chris Timmons <cwt@FreeBSD.org> born in Ellensburg, Washington, United States, 1964
+12/18 Dag-Erling Smorgrav <des@FreeBSD.org> born in Brussels, Belgium, 1977
+12/18 Semen Ustimenko <semenu@FreeBSD.org> born in Novosibirsk, Russian Federation, 1979
+12/21 Rong-En Fan <rafan@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1982
+12/22 Maxim Sobolev <sobomax@FreeBSD.org> born in Dnepropetrovsk, Ukraine, 1976
+12/23 Sean Chittenden <seanc@FreeBSD.org> born in Seattle, Washington, United States, 1979
+12/23 Alejandro Pulver <alepulver@FreeBSD.org> born in Buenos Aires, Argentina, 1989
+12/28 Soren Schmidt <sos@FreeBSD.org> born in Maribo, Denmark, 1960
+12/28 Ade Lovett <ade@FreeBSD.org> born in London, England, 1969
+12/28 Marius Strobl <marius@FreeBSD.org> born in Cham, Bavaria, Germany, 1978
+12/31 Edwin Groothuis <edwin@FreeBSD.org> born in Geldrop, the Netherlands, 1970
+
+#endif /* !_calendar_freebsd_ */
diff --git a/misc_cmds/calendar/calendars/calendar.french b/misc_cmds/calendar/calendars/calendar.french
new file mode 100644
index 0000000..a9af6f1
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.french
@@ -0,0 +1,12 @@
+/*
+ * French calendar file(s)
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.french,v 1.2 2002/04/29 20:57:36 dwmalone Exp $
+ */
+
+#ifndef _calendar_french_
+#define _calendar_french_
+
+#include <fr_FR.ISO8859-1/calendar.all>
+
+#endif /* !_calendar_french_ */
diff --git a/misc_cmds/calendar/calendars/calendar.german b/misc_cmds/calendar/calendars/calendar.german
new file mode 100644
index 0000000..d84e260
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.german
@@ -0,0 +1,12 @@
+/*
+ * German calendar file(s)
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.german,v 1.6 2001/06/11 04:24:43 ache Exp $
+ */
+
+#ifndef _calendar_german_
+#define _calendar_german_
+
+#include <de_DE.ISO8859-1/calendar.all>
+
+#endif /* !_calendar_german_ */
diff --git a/misc_cmds/calendar/calendars/calendar.history b/misc_cmds/calendar/calendars/calendar.history
new file mode 100644
index 0000000..e8abdb7
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.history
@@ -0,0 +1,476 @@
+/*
+ * History
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.history,v 1.35 2006/12/29 06:39:35 ru Exp $
+ */
+
+#ifndef _calendar_history_
+#define _calendar_history_
+
+01/01 Anniversary of the Triumph of the Revolution in Cuba
+01/01 Castro expels Cuban President Batista, 1959
+01/01 Churchill delivers his "Iron Curtain" speech, 1947
+01/01 First Rose Bowl; Michigan 49 - Stanford 0, 1902
+01/04 Quadrantid meteor shower (look north)
+01/05 -50 degrees F, Strawberry UT, 1913
+01/05 The FCC hears the first demonstration of FM radio, 1940
+01/05 Twelfth night
+01/06 Millard Fillmore's birthday (let's party!)
+01/08 Battle of New Orleans
+01/09 Plough Monday
+01/10 First meeting of United Nations General Assembly in London, 1946
+01/10 Thomas Paine's Common Sense published, 1776
+01/11 Anniversary of the Peoples Republic of Albania
+01/11 De Hostos' Birthday in Puerto Rico
+01/11 Milk delivered in bottles for first time, 1878
+01/11 Prithvi Jayanti in Nepal
+01/11 Surgeon General condemned cigarettes, 1964
+01/11 The Whiskey-A-Go-Go opens on Sunset Boulevard in Los Angeles, 1963
+01/14 The first "Be-In" is held in Golden Gate Park, 1967
+01/16 Prohibition begins, 1920
+01/18 Grey whale migration, California
+01/20 St. Agnes Eve (Ah, bitter chill it was...)
+01/24 Eskimo Pie patented by Christian Nelson, 1922
+01/24 Gold discovered in California at Sutter's Mill, 1848
+01/26 Sydney, New South Wales settled, 1788
+01/27 Grissom, White and Chaffe burned to death in Apollo 1, 1967
+01/27 Vietnam War cease-fire signed, 1973
+01/28 First ski tow, Woodstock VT, 1914
+01/28 Space Shuttle Challenger (51-L) explodes 74 seconds after liftoff
+ killing Scobee, Smith, McNair, Resnick, Jarvis, Onizuka and McAuliffe,
+ 1986
+01/30 Mohandas Gandhi assassinated in New Delhi by Hindu fanatic, 1948
+01/30 Tet Offensive, 1968
+01/31 "Ham" the chimpanzee soars into space aboard Mercury-Redstone 2, 1961
+01/31 Explorer I launched, 1958. Van Allen Belt discovered
+01/31 Irving Langmuir, 1881, invented tungsten filament lamp
+02/01 First TV soap: Secret Storm, 1954
+02/01 Forces led by Khomeini take over Iran, 1979
+02/01 Space Shuttle Columbia (STS-107) disintegrates 15 minutes before landing
+ killing Husband, McCool, Chawla, Clark, Ramon, Brown, and Anderson, 2003
+02/04 Cybernet inaugurated, 1969
+02/04 Patricia Hearst kidnapped by Symbionese Liberation Army, 1974
+02/08 1963 Revolution Anniversary in Iraq
+02/09 -51 degrees F, Vanderbilt MI, 1934
+02/12 US President Abraham Lincoln's real birthday
+02/12 Santa Barbara oil leak, 1969
+02/14 Bombing of Dresden, 1945
+02/15 Chicago Seven convicted, 1970
+02/16 Nylon patented, 1937
+02/16 Stephen Decatur burns US frigate in Tripoli, 1804
+02/18 Pluto discovered by Clyde Tombaugh, Lowell Observatory, AZ, 1930
+02/19 US Marines land on Iwo Jima, 1945
+02/20 John Glenn orbits the Earth 3 times, 1962
+02/21 Battle of Verdun begins, 1916 1M casualties
+02/21 First telephone directory, New Haven, Connecticut, 1878
+02/21 Malcom X shot to death in Harlem, 1965
+02/23 Lt. Calley confesses, implicates Cpt. Medina, 1971
+02/24 Impeachment proceedings against Andrew Johnson begin, 1868
+02/28 The "French Connection" drug bust occurs in Marseilles, 1972
+02/29 French and Indian raid on Deerfield MA, 1704
+03/01 Sarah Goode, Sarah Osborne, and Tituba arrested for witchcraft
+ in Salem, Massachusetts, 1692
+03/02 Blackthorn winds (New England) (Does anyone know what this is?)
+03/04 First meeting of Congress, 1789, in N.Y.C.
+03/13 "Striptease" introduced, Paris, 1894
+03/14 Teddy Roosevelt excludes Japanese laborers from continental US, 1907
+03/15 Day of the 1848 revolution in Hungary
+03/15 Buzzards return to Hinckley OH
+03/15 France assumes protectorate over Vietnam, 1874
+03/15 Watts, Los Angeles, riots kill two, injure 25, 1966
+03/15 Ides of March. Gaius Julius Caesar assassinated by senators,
+ including adoptive son Marcus Junius Brutus Caepio, 44BC
+03/16 First liquid-fuel-powered rocket flight, 1926
+03/16 MyLai Massacre; 300 non-combatant villagers killed by US infantrymen
+03/16 Robert Goddard launches first liquid-fueled rocket, Auburn MA, 1926
+03/17 Vanguard I launched, 1958. Earth proved pear-shaped
+03/18 Aleksei Leonov performs first spacewalk, 1965
+03/19 Swallows return to Capistrano
+03/20 Radio Caroline, the original British pirate radio station, sinks, 1980
+03/24 Construction of New York subway system begins, 1900
+03/25 Triangle Shirt Waist Fire, 1911
+03/26 Popeye statue unveiled, Crystal City TX Spinach Festival, 1937
+03/27 Khrushchev becomes Premier of Soviet Union, 1958
+03/28 Three Mile Island releases radioactive gas, 1979
+03/29 Swedish settled Christiana (Wilmington) DE, 1638
+03/30 Alaska purchased from Russia for $7.2 million, 1867
+03/30 Five rings around Uranus discovered, 1977
+03/30 Pencil with eraser patented, 1858
+04/01 People of superb intelligence, savoir-faire, etc. born this day.
+04/04 Martin Luther King assassinated in Memphis, Tennessee, 1968
+04/04 NATO Established, 1949
+04/06 Joseph Smith founds Mormon Church, 1830
+04/07 Albert Hofmann synthesizes LSD in Switzerland, 1943
+04/07 Alewives run, Cape Cod
+04/08 Matthew Flinders and Nicolas Baudin meet in Encounter Bay, 1802
+04/09 Lee surrenders to Grant at Appomattox Courthouse, 1865
+04/12 Confederate troops fire first shots of Civil War at Ft Sumter, 1861
+04/12 Space Shuttle Columbia launched, 1981
+04/12 Yuri Gagarin becomes the first man in space, 1961
+04/13 Laotian New Year (3 days) in Laos
+04/14 US President Abraham Lincoln shot in Ford's Theatre by John Wilkes Booth, 1865
+04/14 Titanic hits iceberg and sinks, 1912
+04/15 US President Abraham Lincoln dies, 1865
+04/15 Ray Kroc opens first McDonalds in Des Plaines, IL, 1955
+04/17 Bay of Pigs invasion crushed by Castro forces, 1961
+04/18 Einstein's Death, 1955
+04/18 First Laundromat opens, Fort Worth Texas, 1934
+04/18 San Francisco earthquake, 1906
+04/19 Landing of the "33" in Uruguay
+04/19 Warsaw Ghetto uprising, 1943
+04/20 Supreme Court unanimously rules in favor of busing, 1971
+04/21 Lyrid meteor shower
+04/22 Vladimir Ilich Ulyanov, called Lenin, Russian political leader, born in Simbirsk, 1870
+04/23 Hank Aaron hits his first home run, 1954
+04/26 William Shakespeare baptized in Stratford-on-Avon, England, 1564,
+ birthdate unknown
+04/27 Magellan killed in Philippines, 1521
+04/29 Zipper patented by Gideon Sindback, 1913
+05/01 Beltaine; Feast of the god Bel, sun god
+05/03 Anti-war protest disrupts business in Washington, 1971
+05/04 Four Kent State students are shot down by the National Guard, 1970
+05/05 John Scopes arrested for teaching evolution, Dayton, TN, 1925
+05/06 Hindenburg explodes and burns upon landing at Lakehurst, NJ, 1937
+05/07 Germany surrenders after WWII, 1945
+05/08 Beginning of ostrich mating season
+05/08 US institutes mining of Haiphong Harbor, 1972
+05/09 94 degrees, New York, 1979
+05/10 Germany invades Low Countries, 1940
+05/10 Nazi bookburning, 1933
+05/14 Beginning of Lewis and Clark Expedition, 1804
+05/14 Nation of Israel proclaimed, 1948
+05/15 Asylum for Inebriates founded, Binghamton NY, 1854
+05/17 24" rain in 11 hours, Pearl River, S. China, 1982
+05/17 Six SLA members killed in televised gun fight, 1974
+05/18 Battle of Las Piedras in Uruguay
+05/18 Napoleon crowned Emperor, 1804
+05/21 Battle of Iquique in Chile
+05/21 US explodes first hydrogen bomb, 1956
+05/22 US Civil War ends, 1865
+05/23 Israeli raid into Argentina to capture Adolf Eichmann, 1960
+05/23 Two Yetis sighted, Mt. Everest, 1953
+05/23 Federal Republic of Germany founded, 1949
+05/24 Battle of Pinchincha in Ecuador
+05/25 Oral Roberts sees 900 foot tall Jesus Christ, Tulsa OK, 1980
+05/25 Successful test of the limelight in Purfleet, England, 1830
+05/26 Congress sets first immigration quotas, 1924
+05/27 Golden Gate Bridge opens, 1937
+05/29 Edmund Hillary and Tenzing Norkay climb Mt. Everest, 1953
+05/29 First food stamps issued, 1961
+05/30 US Marines sent to Nicaragua, 1912
+06/02 Native Americans "granted" citizenship, 1924
+06/04 Roquefort cheese developed, 1070
+06/05 Robert Kennedy assassinated, 1968
+06/05 US leaves the Gold Standard, 1933
+06/06 First drive-in movie, 1933
+06/06 Normandy landing, 1944
+06/10 Death of Alexander the Great, 323 B.C.
+06/10 Denver police tear gas Jethro Tull and 2000 fans at Red Rocks, 1971
+06/11 Greeks seize Troy, 1184BC
+06/13 Pioneer flies past Neptune, and therefore out of the Solar System
+06/14 Sandpaper invented by I. Fischer, Jr., 1834
+06/15 Ben Franklin's kite experiment, 1752
+06/15 Magna Carta signed, 1215
+06/15 Series of photographs by Edward Muggeridge prove to Leland Stanford
+ that all the hooves of a horse are off the ground during the gallop,
+ 1878
+06/16 "The Blues Brothers" premieres in Chicago, 1980
+06/17 China explodes its first Hydrogen bomb, 1967
+06/17 Watergate Democratic National Committee break-in, 1972
+06/19 Julius and Ethel Rosenberg are executed in Sing-Sing prison, 1953
+06/19 Lizzie Bordon acquitted, 1893
+06/20 Victoria crowned, 1837
+06/21 Berlin airlift begins, 1948
+06/21 Sun rises over Heelstone at Stonehenge
+06/22 Civil rights workers disappear in Mississippi, 1964
+06/23 Slavery abolished in England, 1772
+06/24 Senate repeals Gulf of Tonkin resolution, 1970
+06/25 Custer's Last Stand at Little Big Horn, 1876
+06/25 North Korea invades South Korea, 1950
+06/26 Battle of Gettysburg, 1863
+06/26 St. Lawrence Seaway dedicated by Eisenhower & Queen Elizabeth II, 1959
+06/26 Toothbrush invented, 1498
+06/27 100 degrees, Fort Yukon, 1915
+06/27 Bill Graham closes the Fillmore East, 1971
+06/28 Supreme Court decides in favor of Alan Bakke, 1978
+06/30 "That" explosion in Siberia, 1908
+06/30 China and Soviet Union announce split over ideology, 1960
+07/01 Battle of Gettysburg begins, 1863
+07/03 Dog days begin
+07/04 Battles of Vicksburg and Gettysburg won by Union forces, 1863
+07/04 Cloudy, 76 degrees, Philadelphia PA, 1776
+07/04 New York abstains on Declaration of Independence vote, 1776
+07/04 Thoreau enters woods, 1845
+07/06 First `talkie' (talking motion picture) premiere in New York, 1928
+07/06 Lawrence of Arabia captures Aqaba, 1917
+07/07 First radio broadcast of "Dragnet", 1949
+07/07 Terrorists detonate four bombs on London public transport, 2005
+07/08 First public reading of the Declaration of Independence, 1776
+07/08 Liberty Bell cracks while being rung at funeral of John Marshall, 1835
+07/09 10-hour working day set by law, NH, 1847
+07/10 134 degrees in Death Valley, 1913
+07/12 Minimum wages established: 40 cents/hour, 1933
+07/13 Women first compete in Olympic games, 1908
+07/16 Detonation of the first atomic bomb at Alamagordo, NM, 1945
+07/17 Disneyland opens, 1955
+07/18 Ty Cobb gets 4000th base hit, 1927
+07/19 Five Massachusetts women executed for witchcraft, 1692
+07/20 Armstrong and Aldrin land on moon, 1969
+07/21 First Train Robbery, Jesse James gets $3000 near Adair, Iowa, 1873
+07/21 Vietnam divided at 17th parallel, 1954
+07/23 Ice cream cone introduced, St. Louis MO, 1904
+07/24 Scopes Monkey Trial, 1925
+07/30 "In God We Trust" made US motto, 1956
+07/31 Harry S. Truman dedicates N.Y. Int'l Airport @ Idlewild Field, 1948,
+ later JFK
+08/01 Lughnasa; Feast of the god Lugh, a 30 day Celtic feast centers on
+ this day
+08/03 Columbus sets sail for Cathay, 1492
+08/03 USS Nautilus crosses under north polar ice cap, 1958
+08/04 Axe murder of Andrew and Abbey Borden, 1892
+08/04 Bombing of N. Vietnam begins, 1964
+08/04 Britain declares war on Germany starting World War I, 1914
+08/06 Atomic bomb dropped on Hiroshima, 1945
+08/06 Caricom in Barbados
+08/06 Cy Young pitches first game, 1890
+08/08 Montenegro declares war on Germany, 1914
+08/08 Richard Nixon resigns the US presidency, 1974
+08/08 The Great Train Robbery -- $7,368,000, 1963
+08/09 Helter Skelter... the Charles Manson murders take place, 1969
+08/09 Persia defeats Spartan King Leonidas at Thermopylae, 480 BC
+08/09 US/Canada border defined in the Webster-Ashburton Treaty, 1842
+08/09 Atomic bomb dropped on Nagasaki, 1945
+08/09 Singapore secedes from Malaysia, 1965
+08/10 Chicago incorporated as a village of 300 people, 1833
+08/10 US and Panama agree to transfer the canal in the year 2000, 1977
+08/11 Dog days end
+08/11 France Ends War in Indochina, 1954
+08/11 Perseid meteor shower (look north; three days)
+08/12 First test flight of Space Shuttle "Enterprise" from 747, 1977
+08/12 Last US ground troops out of Vietnam, 1972
+08/13 Berlin wall erected, 1961
+08/13 Li'l Abner debut, 1934
+08/14 Social Security begins in US, 1935
+08/15 Gandhi's movement obtains independence for Pakistan and India, 1947
+08/15 Hurricane hits Plymouth Plantation, 1635
+08/16 Roller Coaster patented, 1898
+08/17 First public bath opened in N.Y., 1891
+08/18 Anti-Cigarette League of America formed
+08/19 Air Force cargo plane snares payload from Discoverer 14 spy satellite,
+ marking start of practical military reconnaissance from space, 1960
+08/19 Gail Borden patents condensed milk, 1856
+08/22 Death of King Richard III, 1485, Last of the Plantagenets
+08/22 Joe Walker sets X-15 all time altitude mark (67 miles), 1963
+08/22 St. Columbia reports seeing monster in Loch Ness, 565
+08/23 Sacco and Vanzetti executed, 1927
+08/24 "Alice's Restaurant" premieres in New York and Los Angeles, 1969
+08/24 -126.9 F at Vostok, Antarctica, 1960
+08/24 British troops burn Washington, 1814
+08/25 Gen. De Gaulle leads French forces into Paris, 1944
+08/26 19th amendment of US constitution gives women the vote, 1920
+08/27 "Tarzan of the Apes" published, 1912
+08/27 Krakatoa, Java explodes with a force of 1,300 megatons, 1883
+08/28 Martin Luther King leads over 200,000 in civil rights rally in Washington, DC, 1963
+08/29 Star in Cygnus goes nova and becomes 4th brightest in sky, 1975;
+ Nova Cygni 1975.
+08/30 75 cents a pound tariff set on opium, 1842
+08/30 Japan Stationery Co. sells first felt-tipped pen, 1960
+08/30 St. Rose of Lima in Peru
+08/30 Washington-to-Moscow hot line connected, 1963
+08/31 269 people killed after Korean Airlines 747 shot down by USSR, 1983
+08/31 Mary Anne Nichols becomes Jack the Ripper's first victim, 1888
+08/31 Non-aggression pact signed by USSR and Afghanistan, 1926
+08/31 Federation of Malaya gains independence from Great Britain, 1957
+09/01 Bobby Fischer defeats Boris Spassky in World Chess Match, 1972
+09/01 Joshua A. Norton proclaims himself 'Emperor Norton I', 1859
+09/02 Great Britain adopts Gregorian Calendar, 1752
+09/02 Japan signs unconditional surrender on US battleship `Missouri', 1945
+09/03 Richard ``the Lionheart'' crowned king of England, 1189
+09/03 Anniversary of the Founding of the Republic in San Marino
+09/05 US President Kennedy orders resumption of underground nuclear tests, 1961
+09/05 The first Continental Congress was convened in Philadelphia, 1774
+09/06 149 Pilgrims set forth from England aboard the Mayflower, 1620
+09/06 First Star Trek episode (The Man Trap) aired 1966
+09/06 US President McKinley shot, 1901
+09/06 Somhlolo in Swaziland
+09/08 "Star Trek" debuts on NBC (1966)
+09/08 Jack the Ripper kills again, Annie Chapman is second victim, 1888
+09/08 US President Ford pardons Richard M. Nixon, 1974
+09/09 California becomes the 31st state of the USA, 1850
+09/09 United Colonies is renamed the United States, 1776
+09/10 Mountain Meadows Massacre. Mormons kill Gentile wagon train, 1857
+09/11 CIA-sponsored terrorists overthrow Chilean government, murder President Allende, 1973
+09/11 Terrorists destroy World Trade Center in New York, 2001
+09/12 German paratroopers rescue Mussolini from captivity in Rome, 1943
+09/12 Germany annexes Sudetenland, 1938
+09/13 58° C (136.4° F) measured at el Azizia, Libya, 1922
+09/13 British defeat the French at Abraham near Quebec City, 1788
+09/13 Building of Hadrian's Wall begun, 122
+09/13 Chiang Kai-Shek becomes president of China, 1943
+09/14 Benjamin Franklin is sent to France as an American minister, 1778
+09/14 Salem, Massachusetts, is founded, 1629
+09/14 The US Selective Service Act establishes the first peacetime draft, 1940
+09/15 Soviet Premier Nikita Khrushchev begins his 13 day tour of the US, 1959
+09/15 The US Foreign Affairs Dept. becomes the US State Department, 1789
+09/16 The village of Shawmut, Massachusetts, becomes the city of Boston, 1630
+09/16 Malaya, Sabah, Sarawak and Singapore unite to become Malaysia, 1963
+09/17 Battle of Antietam, 1862
+09/18 Victory of Uprona in Burundi
+09/19 New Zealand women get the right to vote, 1893
+09/20 Equal Rights Party nominates Belva Lockwood for US President, 1884
+09/20 First meeting of the American Association for the Advancement of
+ Science, 1848
+09/20 First meeting of the US National Research Council, 1916
+09/20 Magellan leaves Spain on the first Round the World passage, 1519
+09/20 The Roxy Theater opens in Hollywood, 1973
+09/22 US President Lincoln issues the Emancipation Proclamation, 1862
+09/22 Special prosecutor Leon Jeworski subpoenas US President Nixon, 1974
+09/22 The first Soviet atomic bomb explodes, 1949
+09/23 Philippine President Ferdinand Marcos declares martial law, 1972
+09/23 The New York Knickerbockers becomes the first US Baseball club, 1845
+09/23 US Vice President Nixon denies campaign fund fraud with his "Checkers" speech, 1952
+09/25 Sandra Day O'Connor becomes first woman on US Supreme Court, 1981
+09/27 The first passenger was hauled in a locomotive in England, 1825
+09/28 "Pilgrim's Progress" published, 1678
+09/28 A Greek soldier runs 26+ miles after the Persian defeat at Marathon,
+ 490BC
+09/30 Red Jack kills 2, Elizabeth Stride (#3) and Catherine Eddowes (#4),
+ 1888
+09/30 The first tooth is extracted under anesthesia in Charleston, Mass, 1846
+09/30 The verdicts of the Nuremberg trials are announced, 1946
+10/01 NASA officially begins operations, 1958
+10/02 Thurgood Marshall sworn as the first black Supreme Court Justice, 1967
+10/04 Crimean war begins, 1853
+10/04 First space vehicle, Sputnik I, launched, 1957
+10/06 Antioch College is the first public school to admit men and women, 1853
+10/06 Egyptian President Anwar es-Sadat is assassinated in Cairo, 1981
+10/06 Israel is attacked by the alliance of Egypt and Syria, 1973
+10/07 Foundation of the German Democratic Republic (GDR or DDR), 1949
+10/07 Georgia Tech. beats Cumberland Univ. 222-0, 1916
+10/07 Maryland Governor Marvin Mandel sent to prison on fraud charges, 1977
+10/07 Mother Teresa of Calcutta awarded the Nobel Peace Prize, 1979
+10/07 Police stop Wilbur Mills car, Fanne Fox jumps into water, 1974
+10/08 Great Chicago Fire, 1871
+10/09 First two-way telephone conversation, 1876
+10/10 Beginning of the Wars for Independence in Cuba
+10/10 Foundation of the Workers Party in North Korea
+10/10 Mercury at Superior Conjunction with Sun. Moves into night sky. (1984)
+10/10 Spiro T. Agnew resigns as Vice-President due to income tax fraud, 1973
+10/11 "Saturday Night Live" premiers on NBC-TV, 1975
+10/11 The Gang of Four are arrested in Peking, 1976
+10/11 The first steam powered ferry ran between New York and Hoboken, 1811
+10/11 The second Vatican Ecumenical Council opens in Rome, 1962
+10/11 First broadcast of Saturday Night Live, 1975
+10/12 Bahama Natives discover Columbus of Europe lost on their shores, 1492
+10/12 Khrushchev pounds his desk with shoe during a speech to the UN, 1960
+10/12 Man O'War's last race, 1920
+10/12 Native Americans discover Columbus of Europe lost on their shores, 1492
+10/13 Italy declares war on Germany, 1943
+10/13 US Navy born, 1775, authorized by the Second Continental Congress
+10/14 Battle of Hastings won by William the Conqueror and the Normans, 1066
+10/14 Chuck Yeager breaks sound barrier, 1947
+10/15 First draft card burned, 1965
+10/18 Boston Shoemakers form first US labor org., 1648
+10/18 Soviets announce their probe took photos of the Moon's far side, 1959
+10/19 Mao Tse-tung establishes the People's Republic of China, 1949
+10/19 Napoleon's beaten army begins the long retreat from Moscow, 1812
+10/20 "Saturday Night Massacre", 1973
+10/20 OPEC embargo, 1973
+10/21 Edison makes the first practical incandescent lamp, 1879
+10/21 Guggenheim Museum opens, 1959
+10/23 Battle of Leyte Gulf begins, 1944
+10/23 Day of the 1956 revolution in Hungary
+10/23 Earth created at 6:30 AM, 4004BC.
+10/23 Swallows leave Capistrano
+10/25 The UN removes Taiwan and admits the People's Republic of China, 1971
+10/26 UN's World Health Organization declares smallpox eradicated, 1978
+10/27 New York's Boss Tweed is arrested on fraud charges, 1871
+10/27 The first New York Subway is opened, 1904
+10/28 Columbus discovers Cuba, 1492
+10/28 Constantine's army defeats forces of Maxentius at Mulvian Bridge, 312
+10/28 Harvard was founded in Massachusetts, 1636
+10/28 Statue of Liberty was dedicated on Bedloe's Island, 1886
+10/29 Stock Market Crash, 1929
+10/30 Orson Welles' "War of the Worlds" broadcast, 1938
+10/31 Luther nails 95 Theses to door of Castle Church, Wittenberg, 1517
+11/01 Austria-Hungary become two separate nations, 1918
+11/01 Puerto Rican nationalists try to kill Truman at the Blair House, 1950
+11/02 Luftwaffe completes 57 consecutive nights of bombing of London, 1940
+11/02 Two Frenchmen make the first free hot air balloon flight, 1783
+11/03 Beef rises to 3 cents a pound, IL, 1837
+11/03 Linus Pauling wins Nobel Chemistry Prize, 1954
+11/03 Sputnik II launched, 1957, bearing space dog Laika
+11/04 Iranian militants seize US embassy personnel in Teheran, 1979
+11/04 Soviet forces crush the anti-communist revolt in Hungary, 1956
+11/05 Guy Fawkes' Plot, 1605
+11/07 Abolitionist newspaperman Elijah P. Lovejoy murdered by mob, 1837
+11/07 Lewis and Clark Expedition in sight of the Pacific Ocean, 1805
+11/09 Blackout of New York, New England, and Eastern Canada, 1965
+11/09 Giant panda discovered (?!), China, 1927
+11/09 Jack the Ripper kills fifth and final victim, Jane Kelly, 1888
+11/09 Margaret Sanger forms American Birth Control League, 1921
+11/09 Roosevelt establishes the Civil Works Administration, 1933
+11/10 41 Women arrested in suffragette demonstrations near White House, 1917
+11/10 Cpt. Wirz, commandant of Andersonville Prison hanged, 1865
+11/10 Henry Stanley asks David Livingston, "Dr. Livingston, I presume?", 1871
+11/11 Washington becomes the 42nd state, 1889
+11/12 Dr. Sun Yat-sen's Birthday in Taiwan
+11/12 USA first exports oil to Europe, 1861
+11/14 Quarter Pounder price raised from $0.53 to $0.55 in violation of Nixon
+ price controls (but okayed by Price Commission after formal request
+ from McDonald's), 1971
+11/15 Niagara Falls power plant startup, 1896
+11/16 Opening of the Suez Canal, 1869
+11/17 46,000 meteoroids fall over AZ in 20 minutes, 1966
+11/17 Richard Nixon says "I am not a crook.", 1973
+11/18 First hydrogen bomb blasts Enewetok, 1952
+11/18 Local standard time zones established for US, 1883
+11/19 Gettysburg Address delivered, 1863
+11/21 Announcement of 18 1/2 minute gap on Watergate tape, 1973
+11/22 Kennedy shot in Dallas, Texas by Lee Harvey Oswald, 1963
+11/23 First broadcast of Dr. Who (longest running TV series), 1963
+11/24 Lee Harvey Oswald killed by Jack Ruby, 1963
+11/25 Alfred Nobel invents dynamite, 1867
+11/27 Alfred Nobel establishes Nobel Prize, 1895
+11/27 Friction match invented, England, 1826
+11/27 Hoosac Railroad Tunnel completed, 1873, in NW Massachusetts
+11/29 King Tut's tomb opened, 1922
+12/01 First national corn-husking championship, Alleman IA, 1924
+12/01 Martin Luther King Jr., leads black boycott of Montgomery buses, 1955
+12/01 Rosa Parks refuses to move to back of the bus (Montgomery, AL), 1953
+12/03 First neon light display, Paris, 1910
+12/03 First successful human heart transplant led by Dr. Barnard, 1967
+12/03 The Montreux Casino burns down during a Frank Zappa concert, 1971
+12/04 Washington takes leave of his officers at Fraunce's Tavern, NYC, 1783
+12/05 End of Prohibition, 1933 (at least the alcohol part)
+12/05 Phi Beta Kappa founded, 1776
+12/05 The Eighteenth Amendment repealed, ending Prohibition, 1933
+12/07 Japan bombs Pearl Harbor, 1941
+12/08 Japan enters Second World War with invasion of Pantai Sabak, Kelantan, 1941
+12/09 Ball-bearing roller skates patented, 1884
+12/10 Metric system established in France, 1799
+12/10 Nobel Peace Prize awarded each year
+12/12 First wireless message sent across Atlantic by Marconi, 1901
+12/13 Apollo 17 leaves the moon, with "last" men to walk on moon aboard, 1972
+12/13 Dartmouth College chartered, 1769
+12/13 Geminid meteor shower (look south)
+12/15 Argo Merchant oil spill, 1976
+12/15 Bill of Rights adopted, 1791
+12/15 James Naismith invents basketball, Canada, 1891
+12/15 Sitting Bull shot in head while submitting to arrest, 1890
+12/20 US buys ~1,000,000 sq. miles of Louisiana for ~$20/sq.mi.
+12/21 Phileas Fogg completes his trip around the world in less than 80 days
+12/21 Women gain the right to vote in South Australia, 1894
+12/21 Women gain the right to hold political office in South Australia, 1894
+12/24 KKK formed in Pulaski, Tenn, 1865
+12/26 DPMA founded, 1951
+12/27 APT report published, 1956
+12/27 Ether first used as anesthetic in childbirth, 1845
+12/28 Comet Kohoutek at perihelion, 1973
+12/28 Proclamation of the Province of South Australia, 1836
+12/29 Battle of Wounded knee, 1890
+12/30 First Los Angeles freeway dedicated, 1940
+12/31 St. Sylvester in Switzerland
+12/31 Winterland closes its doors, 1978
+
+#endif /* !_calendar_history_ */
diff --git a/misc_cmds/calendar/calendars/calendar.holiday b/misc_cmds/calendar/calendars/calendar.holiday
new file mode 100644
index 0000000..f3093dd
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.holiday
@@ -0,0 +1,563 @@
+/*
+ * Holiday
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.holiday,v 1.36 2007/09/07 03:23:06 edwin Exp $
+ */
+
+#ifndef _calendar_holiday_
+#define _calendar_holiday_
+
+01/01 Beginning of the Year in Japan
+01/01 Independence Day in Haiti and Sudan
+01/01 Universal Fraternity Day in Mozambique
+01/02 Ancestry Day in Haiti
+01/02 St. Berchtold's Day in Switzerland
+01/03 New Year's Holiday in Scotland
+01/03 Revolution Day in Upper Volta
+01/04 Independence Day in Burma
+01/04 Martyrs Day in Zaire
+01/06 Children's Day in Uruguay
+01/06 Three Kings' Day in Puerto Rico
+01/07 Christmas in Ethiopia
+01/07 Pioneer's Day in Liberia
+01/09 Day of the Martyrs in Panama
+01/11 Armed Forces Day in Liberia
+01/12 Zanzibar Revolution Day in Tanzania
+01/13 National Liberation Day in Togo
+01/15 Arbor Day in Jordan
+01/16 Martyrs Day in Benin
+01/18 Revolution Day in Tunisia
+01/19 Confederate Heroes Day in Texas
+01/19 Ethiopian Epiphany in Ethiopia
+01/19 Nameday of Archbishop Makarios in Cyprus
+01/20 Army Day in Mali
+01/20 National Heroes Day in Guinea-Bissau
+01/21 Our Lady of Altagracia in Dominican Republic
+01/23 Feast of St. Ildefonsus
+01/23 US National Handwriting Day
+01/24 Economic Liberation Day in Togo
+01/26 Republic Day in India
+01/MonSecond Adults Day in Japan
+01/MonThird Lee-Jackson Day in Virginia (3rd Monday)
+01/MonThird Robert E. Lee's Birthday in Alabama & Mississippi (3rd Monday)
+01/MonThird Martin Luther King Day in New York (3rd Monday)
+02/01 Chinese New Year Holiday (3 days) in Taiwan
+02/02 Candlemas
+02/04 Independence Commemoration Day in Sri Lanka
+02/05 Constitution Day in Mexico
+02/06 New Zealand Day
+02/07 Independence Day in Grenada
+02/09 St. Maron's Day in Lebanon
+02/10 Feast of St. Paul's Shipwreck, AD 60
+02/11 National Foundation Day in Japan
+02/12 Pyidaungsa Day in Burma
+02/16 Makha Bucha Day in Thailand
+02/18 Democracy Day in Nepal
+02/18 Independence Day in The Gambia
+02/23 Republic Day in Guyana
+02/24 Gregorian Calendar Day
+02/25 National Day in Kuwait
+02/27 Independence Day in Dominican Republic
+03/01 Samil Independence Movement Day in South Korea
+03/01 St. David's Day - Patron Saint of Wales
+03/02 Peasants Day in Burma
+03/02 Texas Independence day
+03/02 Victory of Adowa in Ethiopia
+03/03 Throne Day in Morocco
+03/03 Independence day (Treaty of San Stefano) in Bulgaria
+03/04 Vermont Admission Day (admitted as 14th US state in 1791)
+03/05 Independence Day in Equatorial Guinea
+03/06 Lantern Day, Bejing
+03/08 First Annual International Women's Day, 1909
+03/08 International Women's Day in former USSR
+03/08 Syrian National Day in Libyan Arab Republic
+03/08 Women's Day in Guinea-Bissau, Taiwan and Yemen Democratic Republic
+03/08 Youth Day in Zambia
+03/09 Decoration Day in Liberia
+03/09 Falgun Purnima Day in Nepal
+03/10 Labor Day in South Korea
+03/11 Johnny Appleseed Day; anniversary of the death of John Chapman
+03/12 Commonwealth Day in Swaziland
+03/12 Independence Day in Mauritius
+03/12 Moshoeshoe's Birthday in Lesotho
+03/12 Renovation Day in Gabon
+03/13 National Day in Grenada
+03/16 Black Press Day; first US Black newspaper founded in 1827
+03/17 Evacuation Day in Suffolk County, Massachusetts
+03/17 St. Patrick's Day - one of the Patron Saints of Ireland
+03/19 St. Joseph's Day, observed in Colombia, Costa Rica, Holy See,
+ Liechtenstein, San Marino, Spain, Venezuela
+03/19 Tree Planting Day in Lestho
+03/20 Independence Day in Tunisia
+03/20 Youth Day in Oklahoma
+03/20* Vernal Equinox in Japan
+03/21 Afghan New Year in Afghanistan
+03/21 Juarez' Birthday in Mexico
+03/21* Vernal Equinox in Japan
+03/22 Abolition Day in Puerto Rico
+03/23 Pakistan Day in Pakistan
+03/25 Greek Independence Day in Cyprus
+03/25 Lady Day (a.k.a. the Feast of the Annunciation)
+03/25 Maryland Day in Maryland
+03/25 National Holiday in Greece
+03/26 Independence Day in Bangladesh
+03/26 Prince Jonah Kuhio Kalanianaole Day in Hawaii
+03/27 Armed Forces Day in Burma
+03/29 Death of President Barthelemy Boganda in Central African Republic
+03/29 Memorial Day in Madagascar
+03/31 National Day in Malta
+03/MonLast Seward's Day in Alaska (last Monday)
+04/01 Youth Day in Benin
+04/02 Malvinas Day in Argentina
+04/02 Pascua Florida Day in Florida
+04/04 Ching Ming Festival in Hong Kong
+04/04 Liberation Day in Hungary
+04/04 National Day in Senegal
+04/05 Arbor Day in South Korea
+04/05 Tomb Sweeping Day in Taiwan
+04/06 Chakri Memorial Day in Thailand
+04/06 Victory Day in Ethiopia
+04/08 Fast and Prayer Day in Liberia
+04/09 Martyrs Day in Tunisia
+04/11 National Heroes Day in Costa Rica
+04/13 National Day in Chad
+04/13 Songkron Day in Thailand
+04/14 Day of the Americas in Honduras
+04/15 Bengali New Year in Bangladesh
+04/16 De Diego's Birthday celebrated in Puerto Rico
+04/16 Holy Week (5 days) in Venezuela
+04/16 Tourist Week (5 days) in Uruguay
+04/17 Burmese New Year in Burma
+04/18 Independence Day in Chile and Zimbabwe
+04/19 Declaration of Independence in Venezuela
+04/19 Republic Day in Sierra Leone
+04/21 San Jacinto Day in Texas
+04/21 Tiradentes in Brazil
+04/22 Arbor Day in Nebraska & Delaware
+04/22 Oklahoma Day in Oklahoma
+04/23 St. George's Day - Patron Saint of England
+04/24 Victory Day in Togo
+04/25 Anniversary of the Revolution in Portugal
+04/25 Anzac Day, observed in Australia, New Zealand, Tonga and Western Samoa
+04/25 Liberation Day in Italy
+04/25 National Flag Day in Swaziland
+04/26 Confederate Memorial Day in Florida & Georgia
+04/26 Union Day in Tanzania
+04/27 Independence Day in Togo
+04/29 Showa Day in Japan
+04/30 Queen's Birthday in the Netherlands, the Netherlands Antilles
+04/30 The Workers Day in Uruguay
+04/MonLast Arbor Day in Wyoming (last Monday)
+04/MonLast Confederate Memorial Day in Alabama & Mississippi (last Monday)
+04/MonThird Patriot's Day in Maine & Massachusetts (3rd Monday)
+05/01 Labor Day in many places in the USA
+05/01 May Day in many places
+05/01 US Law Day (decl. by Eisenhower)
+05/02 King's Birthday in Lesotho
+05/03 Constitution Memorial Day in Japan
+05/04 Greenery Day in Japan
+05/04 Rhode Island Independence Day
+05/05 Battle of Puebla in Mexico
+05/05 Children's Day in Japan and South Korea
+05/05 Coronation Day in Thailand
+05/05 Liberation Day in the Netherlands
+05/06 Bataan Day in Philippines
+05/06* Bank Holiday in UK
+05/07 May Day in United Kingdom
+05/08 Buddha's Birthday in South Korea
+05/08 Elections for the National Assembly in Philippines
+05/08 Truman Day in Missouri
+05/09 VE day, end of Second World War, celebrated in many countries
+05/10 Confederate Memorial Day in South Carolina
+05/10 Mothers Day in Guatemala
+05/11 Minnesota Day in Minnesota
+05/14 Anniversary of the Founding of Guinean Democratic Party in Guinea
+05/14 Buddhist Holiday (Waisak 2528) in Indonesia
+05/14 Independence Day (2 days) in Paraguay
+05/14 Unification Day in Liberia
+05/15 Kamuzu Day in Malawi
+05/15 Vesak Day, observed in Singapore and Malaysia
+05/15 Visakha Bucha Day in Thailand
+05/16 Discovery Day in Cayman Islands
+05/17 Constitution Day in Nauru and Norway
+05/18 Flag Day in Haiti
+05/18 Prayer Day in Denmark
+05/19 Youth and Sports Day in Turkey
+05/20 Mecklenburg Independence Day in North Carolina
+05/20 National Day in Cameroon
+05/20 Victoria Day in Canada
+05/22 National Heroes Day in Sri Lanka
+05/23 Commonwealth Day in Jamaica and Belize
+05/23 National Labor Day in Jamaica
+05/24 Bermuda Day in Bermuda
+05/24 Day of Slav Letters in Bulgaria
+05/25 African Freedom Day in Zimbabwe
+05/25 African Liberation Day in Chad, Mauritania and Zambia
+05/25 Anniversary of the Revolution of 1810 in Argentina
+05/25 Independence Day in Jordan
+05/25 Memorial Day in New Mexico & Puerto Rico
+05/25 Revolution in the Sudan in Libyan Arab Republic
+05/27 Afghanistan attains sovereignty, 1921
+05/27* Bank Holiday in UK
+05/28 Mothers Day in Central African Republic
+05/31 Pya Martyrs Day in Togo
+05/MonThird Memorial Day in Michigan (3rd Monday)
+06/01 Independence Days (3 days) in Western Samoa
+06/01 Madaraka Day in Kenya
+06/01 Victory Day in Tunisia
+06/02 Corpus Christi in Paraguay
+06/03 Confederate Memorial Day in Kentucky & Louisiana
+06/03 Labor Day in Bahamas
+06/03* Bank Holiday in Rep. of Ireland
+06/04 Emancipation Day in Tonga
+06/04 Queen's Birthday in New Zealand
+06/05 Constitution Day in Denmark
+06/05 Liberation Day in Seychelles
+06/06 His Majesty, Yang Di-Pertuan Agong's Birthday in Malaysia
+06/06 Memorial Day in South Korea
+06/09 Senior Citizen's Day in Oklahoma
+06/10 Camoes Day in Portugal
+06/11 King Kamehameha I Day in Hawaii
+06/11 Queen's Birthday
+06/12 Independence Day in Philippines
+06/12 Peace with Bolivia in Paraguay
+06/13 Corrective Movement in Yemen Arab Republic
+06/14 Flag Day, USA
+06/16 Bloomsday - Anniversary of Dublin events, 1904, in "Ulysses"
+06/17 Bunker Hill Day in Suffolk County, Massachusetts
+06/17 Independence Day in Iceland
+06/18 Evacuation Day in Egypt
+06/18 Queen's Birthday in Fiji
+06/19 Artigas Birthday in Uruguay
+06/19 Emancipation Day in Texas
+06/19 Labor Day in Trinidad and Tobago
+06/19 Revolution Day in Algeria
+06/20 Flag Day in Argentina
+06/20 West Virginia Day in West Virginia
+06/22 Corrective Movement in Yemen Democratic Republic
+06/22 Midsummer Eve in Finland, Sweden
+06/22 National Sovereignty Day in Haiti
+06/23 National Holiday in Luxembourg
+06/24 Battle of Carabobob in Venezuela
+06/24 Fisherman's Day in Madagascar, Mozambique and Somalia
+06/24 Kings Day in Spain
+06/24 Peasants Day in Peru
+06/24 St. Jean-Baptiste Day in Quebec
+06/28 Mothers Day in Central African Republic
+06/29 Independence Day in Seychelles
+06/30 Day of the Army in Guatemala
+06/MonFirst Jefferson Davis's Birthday in Alabama & Mississippi (1st Monday)
+06/MonFirst Jefferson Davis's Birthday in Florida, Georgia, & S. Carolina
+07/01 Dominion Day in Canada
+07/01 Freedom Day in Suriname
+07/01 Independence Day in Burundi
+07/01 National Day in Rwanda
+07/01 Republic Day in Ghana
+07/01 Union of the Somalia Republic in Somalia
+07/02 National Day in Kiribati
+07/04 Caribbean Day in Guyana
+07/04 Constitution Day in Cayman Islands
+07/04 Family Day in Lesotho
+07/04 Heroes Day in Zambia
+07/04 Kadooment Day in Barbados
+07/04 Philippine-American Friendship Day in the Philippines
+07/04 Warriors Day (2 days) in Yugoslavia
+07/05 Day of Peace and Unity in Rwanda
+07/05 Independence Day in Algeria and Venezuela
+07/07 Anniversary of the P.U.N. in Equatorial Guinea
+07/07 National Day in Malawi
+07/07 Saba Saba Day in Tanzania
+07/09 Independence Day in Argentina
+07/10 Independence Day in Bahamas
+07/11 National Holiday in the Mongolian People's Republic
+07/12 Battle of Boyne celebrated in Northern Ireland
+07/13 Buddhist Lent in Thailand
+07/14 Anniversary of the Revolution in Iraq
+07/14 French National Festival
+07/14 National Holiday in Monaco
+07/15 St. Swithin's Day
+07/16 Presidents Day in Botswana
+07/17 Constitution Day in South Korea
+07/17 July Revolution in Iraq
+07/17 Munoz Rivera's Birthday (celebrated in Puerto Rico)
+07/17 Public Holiday in Botswana
+07/18 Constitution Day in Uruguay
+07/18 Liberation Day in Nicaragua
+07/19 Martyrs Day in Burma
+07/20 Independence Day in Colombia
+07/21 National Holiday in Belgium
+07/22 King's Birthday in Swaziland
+07/22 National Day in Poland
+07/23 Anniversary of the Revolution in Egypt
+07/23 Egyptian National Day in Syrian Arab Republic
+07/23 Remembrance Day in Papua New Guinea
+07/24 Pioneer Day in Utah
+07/24 Simon Bolivar's Day in Ecuador and Venezuela
+07/25 Constitution Day in Puerto Rico
+07/25 National Rebellion Day (3 days) in Cuba
+07/25 Republic Day in Tunisia
+07/25 St. James, Patron Saint in Spain
+07/26 Independence Day in Liberia
+07/26 National Day in Maldives
+07/27 Barbosa's Birthday (celebrated in Puerto Rico)
+07/28 Independence Days (2 days) in Peru
+07/29 Olsok Eve in Norway to commemorate Norway's Viking King St. Olav
+07/29 Rain Day in Waynesburg, PA
+07/31 Revolution Day in Congo
+07/MonThird Day of Sea in Japan
+08/01 Discovery Day in Trinidad and Tobago
+08/01 Emancipation Day in Granada
+08/01 Founding of Asuncion in Paraguay
+08/01 Freedom Day in Guyana
+08/01 National Day in Switzerland
+08/01 National Holidays (5 days) in El Salvador
+08/01 Parent's Day in Zaire
+08/02 Our Lady of Los Angeles in Costa Rica
+08/03 Independence Day in Jamaica and Niger
+08/03 Massacre of the Pidjiguiti in Buinea-bissau
+08/03 Memorial Day of Archbishop Makarios in Cyprus
+08/04 Freedom Day in Guyana
+08/05* Bank Holiday in Scotland and Northern Ireland
+08/06 Bank Holiday in British Columbia, Fiji, Iceland, Ireland, Ontario
+08/06 Emancipation Day in Bahamas
+08/06 Independence Day in Bolivia
+08/07 Battle of Boyaca in Colombia
+08/09 National Day in Singapore
+08/10 Independence Day in Ecuador
+08/11 Heroes Day (2 days) in Zimbabwe
+08/11 Independence Day in Chad
+08/11 King Hussein's Accession to the Throne in Jordan
+08/12 Queen's Birthday in Thailand
+08/13 Proclamation of Independence in Central African Republic
+08/13 Women's Day in Tunisia
+08/14 Independence Day in Pakistan
+08/14 VJ Day, 1945
+08/14 Waddi Dhahab in Morocco
+08/15 Founding of Ascuncion in Paraguay
+08/15 Independence Day in India
+08/15 Liberation Day in South Korea
+08/15 National Day in Congo
+08/15 Santa Maria in Malta
+08/16 Bennington Battle Day in Vermont
+08/16 Independence Days (3 days) in Gabon
+08/16 Restoration Day in Dominican Republic
+08/17 Anniversary of the Death of General San Martin in Argentina
+08/17 Independence Day in Indonesia
+08/19 Independence Day in Afghanistan
+08/20 Constitution Day in Hungary
+08/24 National Flag Day in Liberia
+08/25 Constitution Day in Paraguay
+08/25 Independence Day in Uruguay
+08/26 Susan B. Anthony Day in Massachusetts
+08/26* Bank Holiday in England and Wales
+08/27 Liberation Day in Hong Kong
+08/28 Heroes Day in Philippines
+08/30 Huey P. Long Day in Louisiana
+08/30 Victory Day in Turkey
+08/31 Independence Day (Merdeka) in Malaysia
+08/31 Independence Day in Trinidad and Tobago
+08/31 Pashtoonian Day in Afghanistan
+08/FriThird Admission Day in Hawaii, 1984 (3rd Friday)
+09/01 Army Day in Chile
+09/03 Independence Day in Qatar
+09/03 Memorial Day in Tunisia
+09/06 Defense of Pakistan Day in Pakistan
+09/06 Unification of Bulgaria
+09/07 Independence Day in Brazil
+09/09 Admission Day in California
+09/09 National Day in North Korea
+09/10 Korean Thanksgiving Day (Chusuk) in South Korea
+09/10 Moon Festival in Taiwan
+09/10 National Day in Belize
+09/11 Anniversary of military coup in Chile
+09/11 Ethiopian New Year in Ethiopia
+09/11 National Holiday in Chile
+09/12 Amilcar Cabral's Birthday in Guinea-Bissau
+09/12 Defender's Day in Maryland
+09/12 Revolution Day in Ethiopia
+09/13 Barry Day commemorates the death of Commodore John Barry, USA
+09/14 Battle of San Jacinto in Nicaragua
+09/15 Foundation of Panama in Panama
+09/16 Cherokee Strip Day in Oklahoma
+09/16 Independence Days in Mexico and Papua New Guinea
+09/17 National Heroes Day in Angola
+09/18 Independence Day in Chile and Zimbabwe
+09/19 Army Day in Chile
+09/21 Independence Day in Belize
+09/22 Independence Day in Mali
+09/22 National Sovereignty Day in Haiti
+09/22* Autumnal Equinox in Japan
+09/23 Grito de Lares in Puerto Rico
+09/23* Autumnal Equinox in Japan
+09/24 Anniversary of the Third Republic in Ghana
+09/24 Independence Day in Guinea-Bissau
+09/24 National Day in Saudi Arabia
+09/24 Our Lady of Mercedes in Dominican Republic
+09/24 Republic Day in Trinidad and Tobago
+09/25 Army Day in Mozambique
+09/25 Referendum Day in Rwanda
+09/26 National Day in Maldives
+09/26 Revolution Anniversary Day in Yemen
+09/27 Feast of Finding the True Cross in Ethiopia
+09/28 Confucius' Day in Taiwan
+09/29 Michaelmas
+09/29 Battle of Boqueron in Paraguay
+09/30 Botswana Day in Botswana
+09/MonThird Respect for the Aged Day in Japan
+10/01 Armed Forces Day in South Korea
+10/01 Independence Day in Nigeria
+10/01 National Liberation Day (2 days) in China
+10/01 Public Holiday in Botswana
+10/02 Anniversary of Guinean Independence in Guinea
+10/03 Chung Yeung Festival in Hong Kong
+10/03 Francisco Morazan's Birthday in Honduras
+10/03 German Reunification Day
+10/03 National Foundation Day in South Korea
+10/03 U.N. Day in Barbados
+10/04 Independence Day in Lesotho
+10/05 Anniversary of Proclamation of the Republic in Portugal
+10/06 National Sports Day in Lesotho
+10/07 National Heroes Day in Jamaica
+10/08 Battle of Agamos in Peru
+10/08 Constitution Day in former USSR
+10/08 Thanksgiving Day in Canada
+10/08* Fiji Day
+10/09 Independence Day in Uganda
+10/09 Independence of Guayaquil in Ecuador
+10/09 Korean Alphabet Day in South Korea
+10/09 Leif Erikson Day commemorates the discovery of North America in AD 1000
+10/09 Republic Day in Khmer Republic
+10/10 National Day in Taiwan
+10/10 Oklahoma Historical Day in Oklahoma
+10/11 Day of the Revolution in Panama
+10/12 Day of the Race in Argentina
+10/12 Discovery Day in Bahamas
+10/12 National Day in Equatorial Guinea and Spain
+10/12 Our Lady Aparecida Day in Brazil
+10/12 Pan American Day in Belize
+10/14 National Day in Yemen Arab Republic
+10/14 Young People's Day in Zaire
+10/14* Thanksgiving Day in Canada
+10/15 Evacuation Day in Tunisia
+10/16 National Boss Day, USA
+10/17 Dessaline's Death Anniversary in Haiti
+10/17 Heroes Day in Jamaica
+10/17 Mother's Day in Malawi
+10/20 Anniversary of the 1944 Revolution in Guatemala
+10/20 Kenyatta Day in Kenya
+10/21 Armed Forces Day in Honduras
+10/21 Revolution Days (2 days) in Somalia
+10/23 Chulalongkron's Day in Thailand
+10/24 Independence Day in Zambia
+10/24 United Nations Day
+10/25 Taiwan Restoration Day in Taiwan
+10/25 St. Crispin's day, patron saint of shoemakers
+10/26 Agam Day in Nauru
+10/26 Armed Forces Day in Benin and Rwanda
+10/26 National Day in Austria
+10/28 National Holiday in Greece
+10/28 OHI Day in Cyprus
+10/28* Bank Holiday in Republic of Ireland
+10/29 Republic Day in Turkey
+10/31 All Hallows Eve ("Halloween")
+10/31 Nevada Day in Nevada
+10/MonFourth Labour Day in New Zealand
+10/MonSecond Health Sports Day in Japan
+11/01 All Saints Day
+11/01 Samhain; Beginning of the Celtic year and most important holiday.
+11/02 All Souls Day
+11/02 Memorial Day in Ecuador
+11/03 Culture Day in Japan
+11/03 Independence from Columbia in Panama
+11/03 Independence of Cuenca in Ecuador
+11/03 Thanksgiving Day in Liberia
+11/04 Flag Day in Panama
+11/04 Will Rogers Day, USA
+11/06 Green March Day in Morocco
+11/07 October Revolution Day in Hungary
+11/08 Her Majesty, the Queen's Birthday in Nepal
+11/10 King's Birthday in Bhutan
+11/11 Angola gains independence from Portugal, 1975
+11/11 Independence Day in Angola
+11/11 Independence of Cartagena in Colombia
+11/11 Remembrance Day in Canada
+11/11 Republic Day in Maldives
+11/14 King Hussein's Birthday in Jordan
+11/15 Dynasty Day in Belgium
+11/15 Proclamation of the Republic in Brazil
+11/15 Thatlouang Festival in Laos
+11/16 Oklahoma Heritage Week in Oklahoma
+11/17 Army Day in Zaire
+11/17 Corrective Movement in Syrian Arab Republic
+11/18 Battle of Viertieres in Haiti
+11/18 Independence Day in Morocco
+11/18 National Days (4 days) in Oman
+11/19 Anniversary of the 1968 Coup by the Army in Mali
+11/19 Discovery Day in Puerto Rico
+11/19 Feast Day of S.A.S. Prince Rainier in Monaco
+11/19 Garifuna Settlement in Belize
+11/20 Revolution Day in Mexico
+11/22 Anniversary of Portuguese Aggression in Guinea
+11/22 Independence Day in Lebanon
+11/23 Labor Thanksgiving Day in Japan
+11/24 Anniversary of the New Regime in Zaire
+11/25 Independence Day in Suriname
+11/28 Independence Day in Albania and Mauritania
+11/28 Independence from Spain in Panama
+11/28 Proclamation of the Republic in Chad
+11/29 Day of the Republic (2 days) in Yugoslavia
+11/29 Goodwill Day in Liberia
+11/29 Liberation Day in Albania
+11/29 National Day in Burma
+11/30 Independence Day in Barbados and Yemen Democratic Republic
+11/30 National Day in Benin
+11/30 National Heroes Day in Philippines
+11/30 St. Andrew's Day - Patron Saint of Scotland
+11/Wed+3 Day of Prayer and Repentance (Buss- und Bettag) in Federal Republic of Germany
+12/01 Anniversary of the Restoration of Independence in Portugal
+12/01 Union Day in Romania
+12/01 Independence Day in Central African Republic
+12/01 World AIDS Day
+12/02 National Holiday in United Arab Emirates
+12/03 National Holiday in Laos
+12/05 King's Birthday in Thailand
+12/06 Independence Day in Finland
+12/07 Delaware Day in Delaware
+12/07 Independence Day in Ivory Coast
+12/07 Independence Day in Panama
+12/08 Blessing of the Water in Uruguay
+12/08 Mother's Day in Panama
+12/08 Our Lady of the Cacupe in Paraguay
+12/09 Independence Day in Tanzania
+12/10 Foundation of Worker's Party in Angola
+12/10 Human Rights Day
+12/10 Thai Constitution Day in Thailand
+12/10 Wyoming Day in Wyoming
+12/11 Independence Day in Upper Volta
+12/12 Independence Day in Kenya
+12/13 Republic Day in Malta
+12/15 Statue Day in the Netherlands Antilles
+12/16 Constitution Day in Nepal
+12/16 National Day in Bahrain
+12/16 Victory Day in Bangladesh
+12/17 National Day in Bhutan
+12/18 Republic Day in Niger
+12/23 Emperor's Birthday in Japan
+12/23 Victory Day in Egypt
+12/25 Birthday of Quaid-i-Azam in Pakistan
+12/25 Children's Day in Congo
+12/26 Boxing Day
+12/26 Feast of Our Theotokos in Greece
+12/26 St. Stephen's Day
+12/26 Bank Holiday in Canada, Rep. of Ireland, and UK
+12/27 Bank Holiday in Cayman Islands
+12/27 Constitution Day in North Korea
+12/27 Public Holiday in Lesotho, Zimbabwe
+12/29 Civic Holidays (3 days) in Costa Rica
+12/29 His Majesty, the King's Birthday in Nepal
+12/30 Anniversary of the Democratic Republic of Madagascar in Madagascar
+12/31 Bank Holiday in El Salvador, Honduras, Pakistan
+12/31 Feed Yourself Day in Benin
+12/31 Proclamation of the Republic in Congo
+
+#endif /* !_calendar_holiday_ */
diff --git a/misc_cmds/calendar/calendars/calendar.hungarian b/misc_cmds/calendar/calendars/calendar.hungarian
new file mode 100644
index 0000000..0fd3dd4
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.hungarian
@@ -0,0 +1,12 @@
+/*
+ * Hungarian calendar file(s)
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.hungarian,v 1.1 2004/08/16 09:31:09 dwmalone Exp $
+ */
+
+#ifndef _calendar_hungarian_
+#define _calendar_hungarian_
+
+#include <hu_HU.ISO8859-2/calendar.all>
+
+#endif /* !_calendar_hungarian_ */
diff --git a/misc_cmds/calendar/calendars/calendar.judaic b/misc_cmds/calendar/calendars/calendar.judaic
new file mode 100644
index 0000000..8247093
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.judaic
@@ -0,0 +1,227 @@
+/*
+ * Judaic Calendar. Maintained by Josef Grosch <jgrosch@mooseriver.com>.
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.judaic,v 1.13 2007/01/14 09:58:39 dwmalone Exp $
+ *
+ */
+
+/*
+ * $Id: calendar.judaic,v 1.45 2007/01/01 22:24:53 jgrosch Exp $
+ */
+
+#ifndef _calendar_judaic_
+#define _calendar_judaic_
+
+/*
+ * Jewish calendar for the CE year 2007
+ * 11 Tevet 5767 - 22 tevet 5768
+ */
+
+
+01/06* Parshas Vayechi
+01/13* Parshas Shemos
+01/20* Parshas Vaera
+01/20* Rosh Chodesh Shevat (Beginning of the month of Shevat)
+01/27* Parshas Bo
+02/03* Parshas Beshalach
+02/03* Shabbos Shira
+02/03* Tu B'Shevat (Feast of Trees)
+02/10* Parshas Yisro
+02/17* Parshas Mishpatim
+02/17* Shabbos Shekalim
+02/18* Rosh Chodesh Adar (Beginning of the month of Adar)
+02/18* Be Happy! It's Adar
+02/19* Rosh Chodesh Adar (Beginning of the month of Adar)
+02/19* Be Happy! It's Adar
+02/24* Parshas Terumah
+03/01* Ta'anis Esther (Fast of Esther, Battle of Purim)
+03/03* Parshas Tetzaveh
+03/03* Shabbos Zachor
+03/04* Purim (Feast of Lots)
+03/05* Shushan Purim
+03/10* Parshas Ki Sisa
+03/10* Shabbos Parah
+03/17* Parshas Vayakhel-Pekudei
+03/17* Shabbos HaChodesh
+03/20* Rosh Chodesh Nissan (Beginning of the month of Nissan)
+03/24* Parshas Vayikra
+03/31* Parshas Tzav
+03/31* Shabbos Haggadol
+04/02* Erev Pesach
+04/02* Ta'anis Bechoros (Fast of the First Born)
+04/02* First Seder night
+04/03* Pesach (First Day of Passover; sabbatical)
+04/03* Second Sedar night
+04/04* Pesach (Second Day of Passover; sabbatical)
+04/04* Sefirat ha-Omer begins (Counting of the Omer)
+04/05* Omer 2nd day
+04/05* Pesach (Third Day of Passover; sabbatical)
+04/05* Hol Hamoed
+04/06* Omer 3rd day
+04/06* Pesach (Fourth Day of Passover)
+04/06* Hol Hamoed
+04/07* Omer 4th day
+04/07* Pesach (Fifth Day of Passover)
+04/07* Hol Hamoed
+04/08* Omer 5th day
+04/08* Pesach (Sixth Day of Passover)
+04/08* Hol Hamoed
+04/09* Omer 6th day
+04/09* Pesach (Seventh Day of Passover)
+04/10* Omer 7th day
+04/10* Pesach (Last Day of Passover; 8th day of Pesach; sabbatical)
+04/10* Yizkor
+04/11* Omer 8th day
+04/12* Omer 9th day
+04/13* Omer 10th day
+04/14* Omer 11th day
+04/14* Parshas Shmini
+04/15* Omer 12th day
+04/15* Yom HaShoah (Holocaust Memorial Day)
+04/16* Omer 13th day
+04/17* Omer 14th day
+04/18* Omer 15th day
+04/18* Rosh Chodesh Iyar (Beginning of the month of Iyar)
+04/19* Omer 16th day
+04/19* Rosh Chodesh Iyar (Beginning of the month of Iyar)
+04/20* Omer 17th day
+04/21* Omer 18th day
+04/21* Parshas Tazria-Metzora
+04/22* Omer 19th day
+04/23* Omer 20th day
+04/23* Yom HaZikaron
+04/24* Omer 21th day
+04/24* Yom HaAtzma'ut (Israel Independence Day)
+04/25* Omer 22th day
+04/26* Omer 23th day
+04/27* Omer 24th day
+04/28* Omer 25th day
+04/28* Parshas Achrei Kedoshim
+04/29* Omer 26th day
+04/30* Omer 27th day
+05/01* Omer 28th day
+05/02* Omer 29th day
+05/03* Omer 30th day
+05/04* Omer 31th day
+05/05* Omer 32th day
+05/05* Parshas Emor
+05/06* Lag B'Omer (Commemoration of the Great Rebellion)
+05/06* Omer 33th day
+05/07* Omer 34th day
+05/08* Omer 35th day
+05/09* Omer 36th day
+05/10* Omer 37th day
+05/11* Omer 38th day
+05/12* Omer 39th day
+05/12* Parshas Behar-Bechukosai
+05/13* Omer 40th day
+05/14* Omer 41th day
+05/15* Omer 42th day
+05/16* Omer 43th day
+05/16* Yom Yerushalayim (Reunification of Jerusalem)
+05/17* Omer 44th day
+05/18* Omer 45th day
+05/18* Rosh Chodesh Sivan (Beginning of the month of Sivan)
+05/19* Omer 46th day
+05/19* Parshas Bamidbar
+05/20* Omer 47th day
+05/21* Omer 48th day
+05/22* Erev Shavuos
+05/22* Omer 49th day
+05/23* Shavuos (Festival of Weeks; sabbatical)
+05/24* Shavuos (Festival of Weeks; sabbatical)
+05/24* Yizkor
+05/26* Parshas Nasso
+06/02* Parshas Beha'aloscha
+06/09* Parshas Shelach Lecha
+06/16* Parshas Korach
+06/16* Rosh Chodesh Tammuz (Beginning of the month of Tammuz)
+06/17* Rosh Chodesh Tammuz (Beginning of the month of Tammuz)
+06/23* Parshas Chukas
+06/30* Parshas Balak
+07/03* Fast of Shiv'a Asar B'Tammuz (Romans breach Wall of Jerusalem; fast day)
+07/03* Tzom Tammuz
+07/07* Parshas Pinchas
+07/14* Parshas Matos-Masei
+07/16* Rosh Chodesh Av (Beginning of the month of Av)
+07/21* Parshas Devarim
+07/21* Shabbos Hazon
+07/24* Fast of Tish'a B'Av (Babylon/Rome destroys Holy Temple; fast day)
+07/28* Parshas Vaeschanan
+07/28* Shabbos Nachamu
+07/30* Tu B'Av
+08/04* Parshas Eikev
+08/11* Parshas Re'eh
+08/14* Rosh Chodesh Elul (Beginning of the month of Elul)
+08/15* Rosh Chodesh Elul (Beginning of the month of Elul)
+08/18* Parshas Shoftim
+08/25* Parshas Ki Tetze
+09/01* Parshas Ki Savo
+09/08* Parshas Nitzavim-Vayeilech
+09/12* Erev Rosh Hashana
+09/13* First Day of Rosh Hashanah (Jewish New Year; 5768; sabbatical)
+09/13* Rosh Chodesh Tishrei (Beginning of the month of Tishrei)
+09/14* Rosh Hashanah (sabbatical)
+09/15* Parshas Ha'Azinu
+09/15* Shabbos Shuvah
+09/16* Fast of Gedalya (Murder of Gedalya and subsequent Exile; fast day)
+09/16* Tzom Gedaliah
+09/21* Erev Yom Kippur
+09/22* Yom Kippur (Day of Atonement; sabbatical, fast day)
+09/22* Yizkor
+09/26* Erev Sukkos
+09/27* Succos (Festival of Tabernacles; sabbatical)
+09/28* Succos (sabbatical)
+09/28* Sukkos (Second day of Sukkos)
+09/29* Sukkos (Third day of Sukkos)
+09/29* Hol Hamoed
+09/30* Sukkos (Fourth day of Sukkos)
+09/30* Hol Hamoed
+10/01* Sukkos (Fifth day of Sukkos)
+10/01* Hol Hamoed
+10/02* Sukkos (Sixth day of Sukkos)
+10/02* Hol Hamoed
+10/03* Hoshanah Rabba (Seventh day of Succos)
+10/03* Sukkos (Seventh day of Sukkos)
+10/04* Shmini Atzeres (8th Day of Gathering; sabbatical)
+10/04* Yizkor
+10/05* Simchas Torah (Rejoicing of the Law; sabbatical)
+10/06* Parshas Bereshis
+10/12* Rosh Chodesh Heshvan (Beginning of the month of Heshvan)
+10/13* Parshas Noach
+10/13* Rosh Chodesh Heshvan (Beginning of the month of Heshvan)
+10/20* Parshas Lech-Lecha
+10/27* Parshas Vayera
+11/03* Parshas Chayei Sara
+11/10* Parshas Toldos
+11/11* Rosh Chodesh Kislev (Beginning of the month of Kislev)
+11/17* Parshas Vayetzei
+11/24* Parshas Vayishlach
+12/01* Parshas Vayeshev
+12/04* Erev Chanukah
+12/04* Light 1st candle
+12/05* Chanukah (First Day)
+12/05* Light 2nd candle
+12/06* Chanukah (Second Day)
+12/06* Light 3rd candle
+12/07* Chanukah (Third Day)
+12/07* Light 4th candle
+12/08* Chanukah (Fourth Day)
+12/08* Parshas Miketz
+12/08* Light 5th candle
+12/09* Chanukah (Fifth Day)
+12/09* Light 6th candle
+12/10* Chanukah (Sixth Day)
+12/10* Rosh Chodesh Tevet (Beginning of the month of Tevet)
+12/10* Light 7th candle
+12/11* Chanukah (Seventh Day)
+12/11* Light 8th candle
+12/12* Chanukah (Eight Day)
+12/15* Parshas Vayigash
+12/19* Asara B'Tevet
+12/19* Fast of Asara B'Tevet (Babylonians put siege on Jerusalem; fast day)
+12/22* Parshas Vayechi
+12/29* Parshas Shemos
+
+
+#endif /* !_calendar_judaic_ */
diff --git a/misc_cmds/calendar/calendars/calendar.lotr b/misc_cmds/calendar/calendars/calendar.lotr
new file mode 100644
index 0000000..9adb342
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.lotr
@@ -0,0 +1,48 @@
+/*
+ * Lord Of The Rings
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.lotr,v 1.2 2003/10/09 00:31:48 grog Exp $
+ */
+
+#ifndef _calendar_lotr_
+#define _calendar_lotr_
+
+01/05 Fellowship enters Moria
+01/09 Fellowship reaches Lorien
+01/17 Passing of Gandalf
+02/07 Fellowship leaves Lorien
+02/17 Death of Boromir
+02/20 Meriadoc & Pippin meet Treebeard
+02/22 Passing of King Elessar
+02/24 Ents destroy Isengard
+02/26 Aragorn takes the Paths of the Dead
+03/05 Frodo & Samwise encounter Shelob
+03/08 Deaths of Denethor & Theoden
+03/18 Destruction of the Ring
+03/29 Flowering of the Mallorn
+04/04 Gandalf visits Bilbo
+04/17 An unexpected party
+04/23 Crowning of King Elessar
+05/19 Arwen leaves Lorien to wed King Elessar
+06/11 Sauron attacks Osgiliath
+06/13 Bilbo returns to Bag End
+06/23 Wedding of Elessar & Arwen
+07/04 Gandalf imprisoned by Saruman
+07/24 The ring comes to Bilbo
+07/26 Bilbo rescued from Wargs by Eagles
+08/03 Funeral of King Theoden
+08/29 Saruman enters the Shire
+09/10 Gandalf escapes from Orthanc
+09/14 Frodo & Bilbo's birthday
+09/15 Black riders enter the Shire
+09/18 Frodo and company rescued by Bombadil
+09/28 Frodo wounded at Weathertop
+10/05 Frodo crosses bridge of Mitheithel
+10/16 Boromir reaches Rivendell
+10/17 Council of Elrond
+10/25 End of War of the Ring
+11/16 Bilbo reaches the Lonely Mountain
+12/05 Death of Smaug
+12/16 Fellowship begins Quest
+
+#endif /* !_calendar_lotr_ */
diff --git a/misc_cmds/calendar/calendars/calendar.music b/misc_cmds/calendar/calendars/calendar.music
new file mode 100644
index 0000000..a2e4292
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.music
@@ -0,0 +1,240 @@
+/*
+ * Music
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.music,v 1.19 2007/01/24 21:21:38 dougb Exp $
+ */
+
+#ifndef _calendar_music_
+#define _calendar_music_
+
+01/01 Country Joe McDonald is born in El Monte, California, 1942
+01/03 Steven Stills is born in Dallas, 1945
+01/04 Jazz great Charlie Mingus dies at 57 in Cuernavaca, Mexico, 1979
+01/08 David Bowie (then David Robert Jones) is born in London, 1947
+01/08 Elvis Presley born, 1935
+01/09 James Patrick Page (Led Zeppelin) is born in Middlesex, England, 1945
+01/10 Blues guitarist Howlin' Wolf dies in Chicago, 1976
+01/10 Jim Croce is born in Philadelphia, 1943
+01/10 Pat Benatar is born in Long Island, 1952
+01/10 Rod Stewart is born in Glasgow, Scotland, 1945
+01/13 Eric Clapton plays the "Rainbow Concert" in London, 1973
+01/17 Led Zeppelin's first album is released, 1969
+01/19 Janis Joplin is born in Port Arthur, Texas, 1943
+01/22 Sam Cooke is born in Chicago, 1935
+01/24 Warren Zevon is born in Chicago, 1947
+01/25 Bob Dylan plays the second "Hurricane" benefit, in the Astrodome, 1978
+01/27 Bobby "Blue" Bland (Robert Calvin Bland) is born in Tennessee, 1930
+01/27 Wolfgang Amadeus Mozart is born in Salzburg, Austria, 1756
+01/28 Jimi Hendrix headlines Madison Square Garden, 1970
+01/30 Lightnin' Hopkins, the most-recorded blues artist ever, dies, 1982
+01/31 Franz Schubert is born in Lichtenthal, Vienna, Austria, 1797
+01/31 The Grateful Dead are busted in New Orleans, 1970
+02/01 RCA Victor unveils the 45 rpm record playing system, 1949
+02/02 Graham Nash is born in Lancashire, England, 1942
+02/03 Felix Mendelssohn Bartholdy is born in Hamburg, Germany, 1809
+02/03 The Day The Music Died; Buddy Holly, Richie Valens, and the Big
+ Bopper are killed in a plane crash outside Mason City, Iowa, 1959
+02/07 Beatles land at JFK airport to begin first U.S. tour, 1964
+02/07 Steven Stills makes the first digitally recorded rock album, 1979
+02/09 Carole King (Carole Klein) is born in Brooklyn, 1941
+02/12 The Beatles play Carnegie Hall in New York City, 1964
+02/13 Richard Wagner dies in Venice, Italy, 1883
+02/17 Jazz great Thelonius Monk dies in Englewood, New Jersey, 1982
+02/18 Yoko Ono Lennon is born in Tokyo, 1933
+02/19 Paul McCartney's "Give Ireland Back to the Irish" is banned in
+ Britain, 1972
+02/19 William "Smokey" Robinson is born in Detroit, 1940
+02/20 J. Geils (J. Geils Band) is born, 1946
+02/20 Yes sells out Madison Square Garden...without advertising, 1974
+02/23 George Friedrich Handel is born in Halle on the Saale, Germany, 1685
+02/23 Johnny Winter is born in Leland, Mississippi, 1944
+02/25 George Harrison born in Liverpool, England, 1943
+02/29 Jimmy Dorsey born, 1904
+03/01 Frederic Chopin is born in Zelazowa Wola, Warsaw, Poland, 1810
+03/01 Jim Morrison is busted for obscenity in Miami, 1969
+03/02 Blues guitarist Rory Gallagher is born in Ballyshannon, Ireland, 1949
+03/03 Buffalo Springfield is formed in Los Angeles, 1966
+03/04 Antonio Vivaldi born in Venice, Italy, 1678
+03/07 Last Gilbert & Sullivan opera produced, 1896
+03/08 Ron "Pigpen" McKernan (Grateful Dead) dies in California, 1973
+03/08 (Louis) Hector Berlioz dies in Paris, 1869
+03/09 Robin Trower is born in London, 1945
+03/13 The Allman Brothers record their live album at the Fillmore East, 1971
+03/15 Sly Stone born, 1944
+03/17 Paul Kantner (Jefferson Airplane) is born in San Francisco, 1942
+03/21 Johann Sebastian Bach is born in Eisenach, Germany, 1685
+03/22 Ten Years After plays their last concert, 1974
+03/25 Aretha Franklin is born in Detroit, 1943
+03/25 Bela Bartok is born in Nagyszentmiklos, Hungary, 1881
+03/26 Emerson, Lake, and Palmer record "Pictures at an Exhibition" live, 1971
+03/26 Ludwig van Beethoven dies in Vienna, Austria, 1827
+03/28 Sergej Rachmaninow dies in Beverley Hills, 1943
+03/29 Carl Orff dies in Munich, Germany, 1982
+03/29 Dr. Hook gets a group picture on the cover of "Rolling Stone", 1973
+03/30 Eric Clapton is born in Surrey, England, 1945
+03/31 Joseph Haydn is born in Rohrau, Austria, 1732
+04/01 Sergej Rachmaninow is born in Oneg, Russia, 1873
+04/02 Marvin Gaye is born in Washington, D.C., 1939
+04/04 Muddy Waters (McKinley Morganfield) is born in Rolling Fork,
+ Mississippi, 1915
+04/09 Paul Robeson born, 1898
+04/10 Paul McCartney announces that he's quitting the Beatles, 1970
+04/14 George Friedrich Handel dies in London, England, 1759
+04/14 Ritchie Blackmore (Deep Purple, Rainbow) is born, 1945
+04/18 Yes breaks up after 13 years, 1981
+04/25 Blues guitarist Albert King is born, 1925
+04/25 Ella Fitzgerald born, 1918
+04/26 Carol Burnett born in San Antonio, Texas, 1933
+04/29 "Hair" premiers on Broadway, 1968
+05/01 Kate Smith born, 1909
+05/01 Antonin Dvorak dies in Prague, 1904
+05/03 Bob Seger is born in Ann Arbor, Michigan, 1945
+05/07 Johannes Brahms is born in Hamburg, Germany, 1833
+05/07 Tchaikowsky born, 1840
+05/10 Dave Mason is born in Worcester, England, 1945
+05/11 Bob Marley dies in his sleep in Miami, 1981
+05/12 Pink Floyd performs the first quadrophonic concert, 1977
+05/18 Gustav Mahler dies in Vienna, Austria, 1911
+05/18 Rick Wakeman is born in West London, England, 1949
+05/19 Pete Townshend is born in London, 1945
+05/20 The Jimi Hendrix Experience is signed by Reprise Records, 1967
+05/22 Richard Wagner is born in Leipzig, Germany, 1813
+05/23 Blues great Elmore James dies, 1963
+05/24 Bob Dylan (Robert Zimmerman) is born in Duluth, 1941
+05/26 Al Jolson born, 1886
+05/31 Joseph Haydn dies in Vienna, Austria, 1809
+05/31 The Who perform the loudest concert ever -- 76,000 watts of PA, 1976
+06/01 The Beatles release "Sgt. Pepper", 1967
+06/03 Georges Bizet dies in Bougival, Paris, France, 1875
+06/05 Carl Maria von Weber dies in London, England, 1826
+06/06 "Rock Around The Clock" makes Billboard's #1 slot, 1955
+06/06 Dee Dee Ramone dies, 2002
+06/07 Blind Faith debuts in concert at London's Hyde Park, 1969
+06/08 Robert Schumann is born in Zwickau, Germany, 1810
+06/09 Les Paul (Lester Polfus) is born in Waukesha, Wisconsin, 1923
+06/10 Howlin' Wolf (Chester Burnett) is born in West Point, Mississippi, 1910
+06/10 Judy Garland born, 1922
+06/11 Richard Strauss is born in Munich, Germany, 1864
+06/15 Edvard Grieg is born in Bergen, Norway, 1843
+06/15 Harry Nilsson is born in Brooklyn, 1941
+06/16 The Monterey Pop festival opens, 1967
+06/18 Paul McCartney born in Liverpool, England, 1942
+06/21 Columbia records announces the first mass production of LP's, 1948
+06/22 Todd Rundgren is born in Upper Darby, Pennsylvania, 1948
+06/24 Jeff Beck is born in Surrey, England, 1944
+06/27 John Entwistle dies in Las Vegas, 2002
+07/02 Felix Pappalardi and Leslie West form Mountain, 1969
+07/03 Jim Morrison dies in Paris, 1971
+07/06 The Jefferson Airplane is formed in San Francisco, 1965
+07/07 Gustav Mahler is born in Kalischt, Bohemia, 1860
+07/07 Ringo Starr (Richard Starkey) born in Liverpool, England, 1940
+07/10 Carl Orff is born in Munich, Germany, 1895
+07/12 Chicago DJ Steve Dahl holds "Disco Demolition" at Kamisky Park, 1979
+07/14 Woodie Guthrie born, 1912
+07/16 Cream forms in the U.K., 1966
+07/16 Harry Chapin dies on Long Island Expressway, 1981
+07/17 "Yellow Submarine" premieres at the London Pavilion, 1968
+07/20 Carlos Santana is born in Autlan, Mexico, 1947
+07/25 Bob Dylan goes electric at the Newport Folk Festival, 1965
+07/25 Crosby, Stills, Nash & Young debut at the Fillmore East, 1969
+07/26 Mick Jagger is born in Kent, England, 1943
+07/28 Antonio Vivaldi dies in Vienna, 1741
+07/28 Johann Sebastian Bach dies in Leipzig, 1750
+07/28 The Watkins Glen "Summer Jam" opens, 1973
+07/29 Robert Schumann dies in Endenich, Bonn, Germany, 1856
+08/01 The Concert for Bangla Desh takes place at Madison Square Garden, 1971
+08/04 John Lennon points out that "the Beatles are more popular than Jesus", 1966
+08/10 Ian Anderson (Jethro Tull) is born in Edinburgh, Scotland, 1947
+08/13 Dan Fogelberg is born in Peoria, Illinois, 1951
+08/15 Beatles replace drummer Pete Best with Richard Starkey, 1962
+08/15 The Beatles play Shea Stadium in New York, 1965
+08/15 Woodstock Festival, Max Yasgur's farm, 1969
+08/16 Elvis Presley dies, 1977
+08/16 Madonna Louise Ciccone born in Bay City, Michigan, 1958
+08/21 Joe Strummer (The Clash), born John Mellor in Ankara, Turkey, 1952
+08/23 Keith Moon is born in London, England, 1946
+08/26 Jimi Hendrix gives his last performance at the Isle of Wight, 1970
+08/26 Jimi Hendrix's Electric Ladyland Studios opens in New York, 1970
+09/04 Edvard Grieg dies in Bergen, Norway, 1907
+09/07 Keith Moon (The Who) dies in London of a drug overdose, 1978
+09/07 Warren Zevon dies in Los Angeles of lung cancer (mesothelioma), 2003
+09/08 Antonin Dvorak born in Nelahozeves, Bohemia, 1841
+09/08 Richard Strauss dies in Garmisch-Partenkirchen, Germany, 1949
+09/08 Ron "Pigpen" McKernan (Grateful Dead) is born in San Bruno, California, 1945
+09/14 Francis Scott Key writes words to "Star Spangled Banner", 1814
+09/16 B.B. King is born in Itta Bena, Mississippi, 1925
+09/18 Dee Dee Ramone (Douglas Colvin) born in Fort Lee, Virginia, 1952
+09/19 Simon & Garfunkel reunite to play New York's Central Park, 1981
+09/20 Jim Croce dies in a plane crash, 1973
+09/23 "Paul is dead" rumors sweep the country, 1969
+09/23 Bruce "The Boss" Springsteen is born in Freehold, New Jersey, 1949
+09/25 John Bonham (Led Zeppelin) dies of alcohol poisoning, 1980
+09/26 Bela Bartok dies in New York, 1945
+09/26 George Gershwin is born in Brooklyn, NY, 1898
+10/04 Janis Joplin dies of a heroin overdose in Hollywood, 1970
+10/05 Steve Miller is born in Dallas, 1943
+10/07 First Bandstand (later, American Bandstand) broadcast, 1957
+10/09 John Entwistle is born in London, England, 1944
+10/09 John Lennon born in Liverpool, England, 1940
+10/10 John Prine is born in Maywood, Illinois, 1946
+10/12 Ray Conniff dies after falling down and hitting his head, 2002
+10/12 The Jimi Hendrix Experience is formed in London, 1966
+10/16 Bob Weir (Grateful Dead) is born in San Francisco, 1947
+10/17 "Hair" opens at New York's Public Theater, 1967
+10/17 Frederic Chopin dies in Paris, France, 1849
+10/18 Chuck Berry is born in San Jose, California, 1926
+10/20 Three members of Lynyrd Skynyrd die in a plane crash, 1977
+10/21 Jesus Christ Super Star debuted on Broadway, 1971
+10/22 Franz Liszt born, 1811
+10/22 Pablo Casals dies in Puerto Rico, 1973
+10/25 Georges Bizet is born in Paris, France, 1838
+10/25 Jon Anderson (Yes) is born in Lancashire, England, 1944
+10/25 The Rolling Stones appear on The Ed Sullivan Show, 1964
+10/29 Duane Allman dies in motorcycle crash near Macon, Georgia, 1971
+10/30 Grace Slick is born in Chicago, 1939
+11/02 Jimi Hendrix's "Electric Ladyland" enters US charts at #1, 1968
+11/02 Keith Emerson is born, 1944
+11/03 James Taylor and Carly Simon are married in Manhattan, 1972
+11/04 Felix Mendelssohn Bartholdy dies in Leipzig, Germany, 1847
+11/06 Ray Conniff born in Attleboro, Massachusetts, 1916
+11/07 Joni Mitchell (Roberta Joan Anderson) is born in Alberta, Canada, 1943
+11/08 Patti Page born, 1927
+11/09 The first issue of "Rolling Stone" is published, 1967
+11/10 Greg Lake is born in Bournemouth, England, 1948
+11/12 Neil Young is born in Toronto, 1945
+11/13 Paul Simon born, 1942
+11/16 Bill Ham first demonstrates his psychedelic "Light Show", 1965
+11/18 Carl Maria von Weber is born in Eutin, Germany, 1786
+11/19 Franz Schubert dies in Vienna, Austria, 1828
+11/20 Duane Allman is born in Nashville, Tennessee, 1946
+11/20 Joe Walsh is born in Cleveland, 1947
+11/22 Saint Cecilia's day (patron saint of music)
+11/24 Scott Joplin born, 1868
+11/25 "The Last Waltz" concert is played by The Band at Winterland, 1976
+11/25 Johann Strauss, Jr., writes `On the Beautiful Blue Danube', 1867
+11/26 Cream performs their farewell concert at Royal Albert Hall, 1968
+11/26 Paul Hindemith is born in Hanau, Germany, 1895
+11/27 Jimi Hendrix (Johnny Allen Hendrix) is born in Seattle, 1942
+11/29 Pau Casals born in Vendrell, 1876
+11/30 George Harrison dies at 13:30 in L.A., 2001
+12/04 Frank Zappa dies in his Laurel Canyon home shortly before 18:00, 1993
+12/05 Wolfgang Amadeus Mozart dies in Vienna, Austria, 1791
+12/06 First sound recording made by Thomas Edison, 1877
+12/06 The Rolling Stones play Altamont Speedway near San Francisco, 1969
+12/07 Harry Chapin is born in New York City, 1942
+12/08 Jim Morrison is born in Melbourne, Florida, 1943
+12/08 John Lennon is shot and killed in New York City, 1980
+12/09 The Who's "Tommy" premieres in London, 1973
+12/11 (Louis) Hector Berlioz born in La-Côte-Saint-André, 1803
+12/13 Ted Nugent, the motor city madman, born in Detroit, 1949
+12/15 Thomas Edison receives patent on the phonograph, 1877
+12/16 Don McLean's "American Pie" is released, 1971
+12/17 Ludwig van Beethoven is christened in Bonn, 1770
+12/21 Frank Zappa is born in Baltimore, 1940
+12/23 First G&S collaboration, Thespis, 1871
+12/23 Joe Strummer (born John Mellor) dies in Broomfield, England, 2002
+12/28 Edgar Winter is born in Beaumont, Texas, 1946
+12/28 Paul Hindemith dies in Frankfurt/Main, Germany, 1963
+12/31 Jimi Hendrix introduces the Band of Gypsies at the Fillmore East, 1969
+
+#endif /* !_calendar_music_ */
diff --git a/misc_cmds/calendar/calendars/calendar.newzealand b/misc_cmds/calendar/calendars/calendar.newzealand
new file mode 100644
index 0000000..3437c83
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.newzealand
@@ -0,0 +1,25 @@
+/*
+ * New Zealand holidays
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.newzealand,v 1.2 2005/01/01 18:58:28 ceri Exp $
+ */
+
+#ifndef _calendar_newzealand_
+#define _calendar_newzealand_
+
+Jan 02 New Year Holiday (NZ)
+Jan 14 Anniversary Day (Southland)
+Jan 21 Anniversary Day (Wellington)
+Jan 28 Anniversary Day (Auckland)
+Feb 06 Waitangi Day (NZ)
+Mar 11 Anniversary Day (Taranaki)
+Mar 25 Anniversary Day (Otago)
+Jun 03 Queen's Birthday (NZ)
+Sep 23 Anniversary Day (South Canterbury)
+Oct 25 Anniversary Day (Hawke's Bay)
+Oct 28 Labour Day (NZ)
+Nov 04 Anniversary Day (Marlborough)
+Nov 15 Anniversary Day (Canterbury)
+Dec 02 Anniversary Day (Chatham Islands)
+
+#endif
diff --git a/misc_cmds/calendar/calendars/calendar.russian b/misc_cmds/calendar/calendars/calendar.russian
new file mode 100644
index 0000000..489d21f
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.russian
@@ -0,0 +1,12 @@
+/*
+ * Russian calendar files
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.russian,v 1.5 2000/05/04 11:35:27 phantom Exp $
+ */
+
+#ifndef _calendar_russian_
+#define _calendar_russian_
+
+#include <ru_RU.KOI8-R/calendar.all>
+
+#endif /* !_calendar_russian_ */
diff --git a/misc_cmds/calendar/calendars/calendar.southafrica b/misc_cmds/calendar/calendars/calendar.southafrica
new file mode 100644
index 0000000..5ff5013
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.southafrica
@@ -0,0 +1,23 @@
+/*
+ * South African holidays
+ * Note: The Public Holidays Act (Act No 36 of 1994) determines whenever
+ * any public holiday falls on a Sunday, the Monday following on it shall
+ * be an unnamed public holiday in addition to the named holiday the day
+ * before. This file format is not complex enough to reflect this, but
+ * if it ever is, the change should be made.
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.southafrica,v 1.1 2002/11/19 00:29:36 grog Exp $
+ */
+
+#ifndef _calendar_southafrica_
+#define _calendar_southafrica_
+
+03/01 Human Rights Day in South Africa
+04/27 Freedom Day in South Africa
+05/01 Workers Day in South Africa
+06/16 Youth Day in South Africa
+08/09 National Women's Day in South Africa
+09/24 Heritage Day in South Africa
+12/16 Day of Reconciliation in South Africa
+12/26 Day of Goodwill in South Africa
+
+#endif
diff --git a/misc_cmds/calendar/calendars/calendar.ukrainian b/misc_cmds/calendar/calendars/calendar.ukrainian
new file mode 100644
index 0000000..0a25db1
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.ukrainian
@@ -0,0 +1,12 @@
+/*
+ * Ukrainian calendar files
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.ukrainian,v 1.1 2005/10/28 21:25:28 ru Exp $
+ */
+
+#ifndef _calendar_ukrainian_
+#define _calendar_ukrainian_
+
+#include <uk_UA.KOI8-U/calendar.all>
+
+#endif /* !_calendar_ukrainian_ */
diff --git a/misc_cmds/calendar/calendars/calendar.usholiday b/misc_cmds/calendar/calendars/calendar.usholiday
new file mode 100644
index 0000000..f64c10b
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.usholiday
@@ -0,0 +1,42 @@
+/*
+ * USA holiday
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.usholiday,v 1.9 2007/04/29 20:03:06 dwmalone Exp $
+ */
+
+#ifndef _calendar_usholiday_
+#define _calendar_usholiday_
+
+01/01 New Year's Day
+01/14 Julian Calendar New Year's Day
+02/02 Groundhog Day
+02/14 St. Valentine's Day
+02/MonThird President's Day (3rd Monday of February)
+03/05 Mother-in-Law Day, USA
+03/SunSecond Daylight Savings Time begins in USA; clocks move forward (2nd Sunday of March)
+03/17 St. Patrick's Day
+03/20* Vernal Equinox
+04/01 April Fool's Day
+04/15 Income Tax Day, USA.
+04/28* Arbor Day, USA (varies from state to state)
+05/SunSecond Mother's Day (2nd Sunday of May)
+05/SatThird Armed Forces in USA Day (3rd Saturday of May)
+05/MonLast Memorial Day in USA (Last Monday of May)
+06/SunThird Father's Day (3rd Sunday of June)
+06/21* Summer Solstice
+07/04 US Independence Day
+09/MonFirst Labor Day in USA (1st Monday of September)
+09/SunSecond Grandparent's Day in USA (2nd Sunday of September; varies from state to state)
+09/22* Autumnal Equinox
+10/MonSecond Columbus Day in USA (2nd Monday of October)
+10/31 All Hallows Eve (Halloween)
+11/05* Election Day in USA (1st Tuesday after 1st Monday for even years)
+11/SunFirst Daylight Savings Time ends in USA; clocks move back (1st Sunday of November)
+11/11 Veterans' Day
+11/ThuFourth Thanksgiving Day (4th Thursday in November)
+12/21* Winter Solstice
+12/24 Christmas Eve
+12/25 Christmas
+12/31 New Year's Eve
+
+#endif /* !_calendar_usholiday_ */
diff --git a/misc_cmds/calendar/calendars/calendar.world b/misc_cmds/calendar/calendars/calendar.world
new file mode 100644
index 0000000..7f6b873
--- /dev/null
+++ b/misc_cmds/calendar/calendars/calendar.world
@@ -0,0 +1,19 @@
+/*
+ * World wide calendar files, except national calendars
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/calendar.world,v 1.5 2003/02/15 10:57:20 seanc Exp $
+ */
+
+#ifndef _calendar_world_
+#define _calendar_world_
+
+#include <calendar.birthday>
+#include <calendar.christian>
+#include <calendar.computer>
+#include <calendar.history>
+#include <calendar.lotr>
+#include <calendar.holiday>
+#include <calendar.judaic>
+#include <calendar.music>
+
+#endif /* !_calendar_world_ */
diff --git a/misc_cmds/calendar/calendars/de_AT.ISO_8859-15/calendar.feiertag b/misc_cmds/calendar/calendars/de_AT.ISO_8859-15/calendar.feiertag
new file mode 100644
index 0000000..ddac0f6
--- /dev/null
+++ b/misc_cmds/calendar/calendars/de_AT.ISO_8859-15/calendar.feiertag
@@ -0,0 +1,62 @@
+/*
+ * Feiertage
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/de_AT.ISO_8859-15/calendar.feiertag,v 1.1 2004/05/23 13:22:01 josef Exp $
+ */
+
+#ifndef _de_AT_ISO8859_15_feiertag_
+#define _de_AT_ISO8859_15_feiertag_
+
+LANG=de_AT.ISO8859-15
+
+/* arbeitsfreie staatliche Feiertage */
+01/01 Neujahr
+05/01 Staatsfeiertag
+10/26 Nationalfeiertag
+
+/* christliche Feiertage, meist irgendwo arbeitsfrei */
+01/06 Heilige 3 Könige
+Easter-2 Karfreitag
+Easter Ostersonntag
+Easter+1 Ostermontag
+Easter+49 Pfingstsonntag
+Easter+50 Pfingstmontag
+Easter+39 Christi Himmelfahrt
+Easter+60 Fronleichnam
+
+08/15 Mariä Himmelfahrt
+
+11/01 Allerheiligen
+11/02 Allerseelen
+
+12/08 Mariä Empfängnis
+12/24 Heiligabend
+12/25 Weihnachten
+12/26 Stephanstag
+12/31 Silvester
+
+/* Gedenktage - nicht arbeitsfreie Feiertage */
+02/14 Valentinstag
+02/WednesdayLast Aschermittwoch
+Easter-7 Palmsonntag
+Nov Sun+3 Totensonntag
+Nov Sun+4 1. Advent
+Dec Sun+1 2. Advent
+12/06 Nikolaus
+Dec Sun+2 3. Advent
+Dec Sun+3 4. Advent
+
+/* Jahreszeiten */
+03/20* Frühlingsanfang
+06/21* Sommeranfang
+09/23* Herbstanfang
+12/21* Winteranfang
+
+/* Sommer- und Winterzeit */
+03/SundayLast Anfang der Sommerzeit
+10/SundayLast Ende der Sommerzeit
+
+/* Blumenverkäufer */
+May Sun+2 Muttertag
+
+#endif /*! _de_AT_ISO8859_15_feiertag_ */
diff --git a/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.all b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.all
new file mode 100644
index 0000000..1274934
--- /dev/null
+++ b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.all
@@ -0,0 +1,17 @@
+/*
+ * deutscher Kalender
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.all,v 1.6 2001/06/11 03:06:13 ache Exp $
+ */
+
+#ifndef _de_DE_ISO8859_1_all_
+#define _de_DE_ISO8859_1_all_
+
+#include <de_DE.ISO8859-1/calendar.feiertag>
+#include <de_DE.ISO8859-1/calendar.geschichte>
+#include <de_DE.ISO8859-1/calendar.kirche>
+#include <de_DE.ISO8859-1/calendar.literatur>
+#include <de_DE.ISO8859-1/calendar.musik>
+#include <de_DE.ISO8859-1/calendar.wissenschaft>
+
+#endif /* !_de_DE.ISO8859-1_all_ */
diff --git a/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag
new file mode 100644
index 0000000..48cfd31
--- /dev/null
+++ b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag
@@ -0,0 +1,56 @@
+/*
+ * Feiertage
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.feiertag,v 1.14 2006/10/01 09:22:05 maxim Exp $
+ */
+
+#ifndef _de_DE_ISO8859_1_feiertag_
+#define _de_DE_ISO8859_1_feiertag_
+
+LANG=de_DE.ISO8859-1
+
+/* arbeitsfreie staatliche Feiertage */
+01/01 Neujahr
+05/01 Maifeiertag
+10/03 Tag der deutschen Einheit
+
+/* christliche Feiertage, meist irgendwo arbeitsfrei */
+Easter-2 Karfreitag
+Easter Ostersonntag
+Easter+1 Ostermontag
+Easter+49 Pfingstsonntag
+Easter+50 Pfingstmontag
+Easter+39 Christi Himmelfahrt
+Easter+60 Fronleichnam
+
+08/08 Friedensfest (Augsburg)
+08/15 Mariä Himmelfahrt
+
+10/31 Reformationstag
+11/01 Allerheiligen
+11/02 Allerseelen
+11/Wed+4 Buß- und Bettag
+
+12/24 Heiligabend
+12/25 Erster Weihnachtstag
+12/26 Zweiter Weihnachtstag
+12/31 Silvester
+
+/* Gedenktage - nicht arbeitsfreie Feiertage :-( */
+06/17 Arbeiteraufstand am 17. Juni 1953
+01/27 Gedenktag für die Opfer des Nationalsozialismus
+
+/* Jahreszeiten */
+03/20* Frühlingsanfang
+06/21* Sommeranfang
+09/23* Herbstanfang
+12/21* Winteranfang
+
+/* Sommer- und Winterzeit */
+03/SundayLast Anfang der Sommerzeit
+10/SundayLast Ende der Sommerzeit
+
+/* Blumenverkäufer */
+May Sun+2 Muttertag
+
+#endif /*! _de_DE_ISO8859_1_feiertag_ */
diff --git a/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte
new file mode 100644
index 0000000..64ccc31
--- /dev/null
+++ b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte
@@ -0,0 +1,198 @@
+/*
+ * deutsche Geschichte
+ *
+ *
+ * Die Angaben wurden überwiegend entnommen aus dem Buch:
+ *
+ * Fragen an die deutsche Geschichte, Ideen, Kräfte, Entscheidungen von
+ * 1800 bis zur Gegenwart; historische Ausstellung im Reichstagsgebäude
+ * in Berlin; Katalog, 16. Auflage, Sonderausgabe - Bonn: Deutscher
+ * Bundestag, Referat Öffentlichkeitsarbeit, 1990
+ *
+ * English Title: Questions on German history
+ *
+ * ISBN 3-924521-59-X
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.geschichte,v 1.13 2005/09/23 11:58:16 krion Exp $
+ */
+
+#ifndef _de_DE_ISO8859_1_geschichte_
+#define _de_DE_ISO8859_1_geschichte_
+
+LANG=de_DE.ISO8859-1
+
+/* 1800-1933 */
+07/11 Gründung des Rheinbundes, 1806
+10/14 Doppelschlacht bei Jena und Auerstedt, 1806
+10/16 Völkerschlacht bei Leipzig, 1813
+06/18 Niederlage Napoleons bei Waterloo, 1815
+10/18 Wartburgfest der Deutschen Burschenschaften, 1817
+01/01 Inkrafttreten des Vertrages über den deutschen Zollverein, 1834
+12/07 Erste deutsche Eisenbahn zwischen Nürnberg und Fürth, 1835
+06 Aufstand der schlesischen Weber, 1844
+12/21 Verabschiedung des Gesetzes über die Grundrechte des deutschen
+ Volkes durch die Frankfurter Nationalversammlung, 1848
+03/27 Annahme der deutschen Reichsverfassung in der Frankfurter
+ Paulskirche, Wahl von Friedrich Wilhelm IV von Preußen zum
+ deutschen Kaiser, 1849
+04/28 Ablehnung der deutschen Kaiserkrone durch den preußischen König, 1849
+07/03 Schlacht von Königgrätz
+07/13 Emser Depesche, 1870
+07/18 Verkündung des Dogmas von der päpstlichen Unfehlbarkeit
+ durch das I. Vatikanische Konzil
+01/18 Proklamation des deutschen Kaiserreiches in Versailles, 1871
+10/18 Verabschiedung des Sozialistengesetzes durch den Reichstag, 1878
+03/20 Entlassung von Bismarck als Reichskanzler und
+ preußischer Ministerpräsident, 1890
+06/21 Eröffnung des Nord-Ostsee-Kanals, 1895
+01/07 Billigung des Bürgerlichen Gesetzbuches (BGB) durch den Reichstag, 1896
+01/01 Bürgerliches Gesetzbuch tritt in Kraft, 1900
+06/28 Ermordung des österreichischen Thronfolgers Erzherzog Franz
+ Ferdinand durch serbische Nationalisten in Sarajewo, 1914
+07/28 Kriegserklärung Österreich-Ungarns an Serbien, 1914
+08/01 Deutsche Mobilmachung und Kriegserklärung an Rußland, 1914
+08/03 Deutsche Kriegserklärung an Frankreich, 1914
+08/04 Kriegserklärung Großbritanniens an Deutschland, 1914
+08/04 Bewilligung der Kriegskredite im Reichstag, 1914
+08/26 Schlacht bei Tannenberg, 1914
+02/21 Schlacht um Verdun, 1916
+03/08 Ausbruch der Revolution in Rußland, Abdankung von Zar Nikolaus II, 1917
+04/06 Kriegserklärung der USA an Deutschland, 1917
+12/15 Waffenstillstand zwisch Rußland und Deutschland, 1917
+03/03 Frieden von Brest-Litowsk, 1918
+11/03 Matrosenaufstand in Kiel, 1918
+11/09 Ausrufung der Republik durch Scheidemann (SPD), 1918
+02/11 Friedrich Ebert wird Reichspräsident, Weimar 1919
+06/28 Unterzeichnung des Versailler Vertrages, 1919
+03/21 Volksabstimmung in Oberschlesien, 1921
+04/16 Vertrag von Rapallo, 1922
+06/24 Ermordung von Reichsaußenminister Rathenau, 1922
+01/11 Besetzung des Ruhrgebietes durch Frankreich und Belgien, 1923
+09/10 Eintritt Deutschlands in den Völkerbund, 1926
+10/25 Schwarzer Freitag in New York, Beginn der Weltwirtschaftskrise, 1929
+
+
+/* II. Weltkrieg */
+10/14 Austritt Deutschlands aus dem Völkerbund, 1933
+03/16 Wiedereinführung der allgemeinen Wehrpflicht in Deutschland, 1935
+10/25 Deutsch-italienischer Vertrag, Achse Berlin-Rom, 1936
+11/25 Antikominternpakt zwischen Deutschland und Japan, 1936
+01/13 Volksabstimmung im Saargebiet über die Rückführung
+ ins deutsche Reich, 1935
+03/12 Einmarsch deutscher Truppen in Österreich, 1938
+09/29 Münchner Abkommen, 1938
+03/15 Einmarsch deutscher Truppen in die Tschechoslowakei, 1939
+03/23 Rückgabe des Memelgebietes an Deutschland, 1939
+08/23 Abschluß des Hitler-Stalin-Paktes, 1939
+09/03 Kriegserklärung Großbritaniens und Frankreichs an Deutschland, 1939
+04/09 Deutsche Besetzung Dänemarks, Invasion in Norwegen, 1940
+05/10 Deutscher Angriff auf Belgien, die Niederlande, Luxemburg
+ und Frankreich, 1940
+06/22 Deutscher Angriff gegen die Sowjetunion, 1941
+12/11 Kriegserklärung Deutschlands an die USA, 1941
+01/14 Konferenz von Casablanca, 1943
+01/31 Kapitulation der 6. deutschen Armee in Stalingrad, 1943
+06/06 Alliierte Landung in Nordwestfrankreich, 1944
+02/04 Konferenz von Jalta, 4.-11.2. 1945
+04/25 Zusammentreffen von amerikanischen und sowjetischen Truppen
+ bei Torgau an der Elbe, 1945
+05/08 Bedingungslose Kapitulation von Deutschland, 1945
+07/01 Rückzug britischer und amerikanischer Truppen aus Sachsen, Thüringen und
+ Mecklenburg, Einmarsch westlicher Truppen in Berlin, 1945
+07/17 Potsdamer Konferenz, 1945
+09/01 Deutscher Überfall auf Polen, Beginn des 2. Weltkrieges, 1939
+10/01 Verkündigung der Urteile im Nürnberger Hauptkriegsverbrecherprozeß, 1946
+02/25 Auflösung der Landes Preußen durch den Kontrollrat, 1947
+08/06 Erster Atombombenabwurf auf Hiroshima, 1945
+08/08 Atombombenabwurf auf Nagasaki, 1945
+04/19 Aufstand im Warschauer Ghetto, 1943
+12/07 Japan bombardiert Pearl Harbor, 1941
+
+/* Deutschland nach dem 2. Weltkrieg */
+04/11 Attentat auf Dutschke, Studentenunruhen, 1968
+04/26 GAU in Tschernobyl, 1986
+05/05 Natobeitritt, Wiederbewaffnung, Souveränität der Bundesrepublik, 1955
+05/06 Rücktritt von Brandt, 1974
+05/16 Wahl von Schmidt (SPD) zum Bundeskanzler, 1974
+05/23 Verkündung des Grundgesetzes, 1949
+05/23 Wahl von Richard von Weizsäcker zum Bundespräsidenten, 1984
+06/05 Marshallplan, 1947
+06/20 Währungsreform in den Westzonen, 1948
+06/24 Beginn der Berliner Blockade, 1948
+07/01 Wahl von Heinrich Lübke zum Bundespräsidenten, 1959
+07/01 Wirtschafts- und Währungsunion, 1990
+08/12 Deutsch-sowjetischer Gewaltverzichtsvertrag, Moskau 1970
+08/14 Wahl zum ersten deutschen Bundestag, 1949
+09/03 Vier-Mächte-Abkommen über Berlin, 1971
+09/05 Entführung und Ermordung von Arbeitgeberpräsident Schleyer,
+ Entführung einer Lufthansa-Maschine nach Mogadischu, 1977
+09/07 DDR-Staatsratsvorsitzender Honecker in der Bundesrepublik, 1987
+09/12 Wahl von Theodor Heuss (FDP) zum Bundespräsidenten, 1949
+09/15 Wahl von Konrad Adenauer (CDU) zum Bundeskanzler, 1949
+09/17 Bruch der Sozialliberalen Koalition, 1982
+09/18 Aufnahme von Bundesrepublik und DDR in die UNO, 1973
+10/01 Ablösung von Bundeskanzler Schmidt durch Kohl, 1982
+10/23 Volksabstimmung im Saargebiet, 1955
+12/02 Washingtoner Abkommen über Bi-Zone, 1946
+12/07 Deutsch-polnischer Vertrag, Warschau 1970
+12/10 Friedensnobelpreis für Brandt, 1971
+12/12 Nachrüstungsbeschluß des NATO-Ministerates, 1979
+12/21 Grundlagenvertrag zwischen DDR und Bundesrepublik, 1972
+
+
+/* Nationalsozialismus */
+11/09 Hitler-Putsch in München/Marsch auf die Feldherrenhalle, 1923
+11/09 Reichskristallnacht, 1938
+09/14 Reichstagswahl: Erdrutsch zugunsten der NSDAP, 1930
+07/31 Reichstagswahl: NSDAP wird stärkste Fraktion, 1932
+11/06 Reichstagswahl: Rückgang der NSDAP, 1932
+01/30 Ernennung von Hitler zum Reichskanzler, 1933
+02/27 Reichstagsbrand, 1933
+03/05 Reichstagswahl: Mehrheit für NSDAP+DNVP, 1933
+03/23 Annahme des Ermächtigungsgesetzes, 1933
+03/31 Erstes Gesetz zur Gleichschaltung der Länder, 1933
+04/01 Organisierter Boykott jüdischer Geschäfte, 1933
+04/07 Zweites Gesetz zur Gleichschaltung der Länder, 1933
+05/02 Auflösung der Gewerkschaften, 1933
+06 Auflösung aller Parteien außer NSDAP, 1933
+07/20 Konkordat zwischen Deutschland und dem Vatikan, 1933
+06/30 Röhm-Putsch, Ausschaltung der SA-Führung, 1934
+09/15 Nürnberger Gesetze, 1935
+01/08 Eröffnung der olympischen Spiele in Berlin, 1936
+01/20 Wannseekonferenz, 1942
+04/30 Selbstmord Hitlers, 1945
+07/29 Mussolini geboren, 1883
+
+/* Sozialismus */
+01/21 Lenin gestorben, 1924
+06 Gründung des Bundes der Kommunisten in London
+ durch Marx und Engels, 1847
+05/23 Gründung des Allgemeinen Deutschen Arbeitervereins in Leipzig
+ unter Führung von Ferdinand Lassalles, 1863
+08/07 Gründung der Sozialdemokratischen Arbeiterpartei in Eisenach
+ unter der Führung von August Bebel und Wilhelm Liebknecht, 1869
+04/06 Gründung der Unabhängigen Sozialdemokratischen Partei, Gotha 1917
+11/07 Oktoberrevolution in Rußland, Putsch der Bolschewisten, 1917
+12/31 Gründung der KPD, 1918
+01/15 Ermordung von Rosa Luxemburg und Karl Liebknecht, 1919
+03/05 Tod Stalins, 1953
+03/18 Erste demokratische Volkskammerwahl, 1990
+04/21 Zwangsvereinigung von KPD und SPD zur SED, 1946
+05/14 Gründung der Warschauer Paktes, 1955
+06/17 Arbeiteraufstand am 17. Juni 1953
+06/25 Begin der Korea-Krieges, 1950
+08/13 Bau der Berliner Mauer, 1961
+08/21 Einmarsch des Warschauer Pakts in die Tschechoslowakei, 1968
+10/03 Offizielles Ende der DDR :-), 1990
+10/07 Gründung der DDR, 1949
+10/09 Massendemonstration in Leipzig, 1989
+10/14 Kuba-Krise, 1962
+10/18 Ablösung von Erich Honecker als SED-Generalsekretär, 1989
+11/09 Fall der Berliner Mauer, 1989
+09/09 Mao Tse-Tung gestorben im Alter von 82 Jahren, 1976
+11/10 Sowjetischer Präsident Leonid Breschnew gestorben, Alter 75, 1982
+03/27 Chruschtschow wird sowjetischer Präsident, 1958
+10/12 Chruschtschow schlägt während einer Rede in der UNO mit den
+ Schuhen auf den Tisch, 1960
+
+#endif /* _de_DE_ISO8859_1_geschichte_ */
diff --git a/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.kirche b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.kirche
new file mode 100644
index 0000000..eba0fe3
--- /dev/null
+++ b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.kirche
@@ -0,0 +1,32 @@
+/*
+ * Kirche in Deutschland
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.kirche,v 1.7 2001/06/11 03:06:13 ache Exp $
+ */
+
+#ifndef _de_DE_ISO8859_1_kirche_
+#define _de_DE_ISO8859_1_kirche_
+
+LANG=de_DE.ISO8859-1
+
+Easter-46 Aschermittwoch
+Easter-48 Rosenmontag
+Easter-7 Palmsonntag
+
+11/Sun-3 Volkstrauertag (maybe)
+11/Sun-2 Volkstrauertag oder Totensonntag
+11/Sun-1 1. Advent oder Totensonntag
+12/Sun+1 1. oder 2. Advent
+12/Sun+2 2. oder 3. Advent
+12/Sun+3 3. oder 4. Advent
+12/Sun+4 4. Advent (maybe)
+
+12/06 Nikolaus
+12/25 1. Weihnachtstag
+12/26 2. Weihnachtstag
+
+/* Evangelische Kirche */
+11/10 Martin Luther geboren in Eisleben, 1483
+10/31 95 Thesen von Luther, Wittenberg, 1517
+
+#endif /* !_de_DE_ISO8859_1_kirche_ */
diff --git a/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.literatur b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.literatur
new file mode 100644
index 0000000..db1f6bd
--- /dev/null
+++ b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.literatur
@@ -0,0 +1,54 @@
+/*
+ * Literatur
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.literatur,v 1.8 2003/10/06 01:17:42 grog Exp $
+ */
+
+#ifndef _de_DE_ISO8859_1_literatur_
+#define _de_DE_ISO8859_1_literatur_
+
+LANG=de_DE.ISO8859-1
+
+/* Schriftsteller
+
+ Fontane
+ Goethe
+ Grass
+ Hegel
+ Heine
+ Schiller
+ */
+
+01/04 Jakob Grimm geboren, 1785
+01/18 Arno Schmidt in Hamburg geboren, 1914
+02/09 Thomas Bernhard in Heerlen geboren, 1931
+02/12 Immanuel Kant in Königsberg gestorben, 1804
+02/12 Thomas Bernhard in Gmunden gestorben, 1989
+02/17 Heinrich Heine in Paris gestorben, 1856
+03/22 Johann Wolfgang von Goethe in Weimar gestorben, 1832
+04/22 Kant geboren, 1724
+05/09 Friedrich von Schiller in Weimar gestorben, 1805
+06/03 Arno Schmidt in Celle gestorben, 1979
+06/03 Franz Kafka in Prag gestorben, 1924
+06/06 Thomas Mann in Lübeck geboren, 1875
+07/03 Franz Kafka geboren, 1883
+08/12 Thomas Mann gestorben, 1955
+08/27 Georg Wilhelm Friedrich Hegel in Stuttgart geboren, 1770
+08/28 Johann Wolfgang von Goethe in Frankfurt am Main geboren, 1749
+09/20 Theodor Fontane in Berlin gestorben, 1898
+10/16 Günter Grass in Danzig geboren, 1927
+11/10 Friedrich von Schiller in Marbach geboren, 1759
+11/14 Georg Wilhelm Friedrich Hegel in Berlin gestorben, 1831
+12/13 Heinrich Heine in Düsseldorf geboren, 1797
+12/30 Theodor Fontane in Neuruppin geboren, 1819
+
+
+/* Verlage */
+03/09 "die tageszeitung" als erste täglich aktualisierte deutsche
+ Tageszeitung im WWW, 1995, Betatest, vollständige Ausgabe
+05/05 Schweriner Volkszeitung als erste deutsche Tageszeitung im WWW, 1995
+05/12 "die tageszeitung" offiziell im WWW, 1995
+08/31 Hitler stellt Frankfurter Zeitung ein, 1943
+11/01 Frankfurter Allgemeine Zeitung in Leben gerufen, 1949
+
+#endif /* !_de_DE_ISO8859_1_literatur_ */
diff --git a/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.musik b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.musik
new file mode 100644
index 0000000..7dd5175
--- /dev/null
+++ b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.musik
@@ -0,0 +1,66 @@
+/*
+ * Musik
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.musik,v 1.13 2006/10/24 23:18:07 grog Exp $
+ */
+
+#ifndef _de_DE_ISO8859_1_musik_
+#define _de_DE_ISO8859_1_musik_
+
+LANG=de_DE.ISO8859-1
+
+/* Barock */
+02/23 Georg Friedrich Händel in Halle an der Saale geboren, 1685
+03/14 Georg Philipp Telemann in Magdeburg geboren, 1681
+03/21 Johann Sebastian Bach in Eisenach geboren, 1685
+04/14 Georg Friedrich Händel in London gestorben, 1759
+06/25 Georg Philipp Telemann in Hamburg gestorben, 1767
+07/17 Diderich Buxtehude in Lübeck gestorben, 1707
+07/28 Johann Sebastian Bach in Leipzig gestorben, 1750
+
+/* Klassik */
+01/27 Wolfgang Amadeus Mozart in Salzburg geboren, 1756
+01/31 Franz Schubert in Lichtenthal bei Wien geboren, 1797
+02/03 Felix Mendelssohn Bartholdy in Hamburg geboren, 1809
+02/13 Richard Wagner in Venedig gestorben, 1883
+03/01 Frederic Chopin in Zelazowa-Wola bei Warschau geboren, 1810
+03/08 (Louis) Hector Berlioz in Paris gestorben, 1869
+03/25 Bela Bartok in Nagyszentmiklos geboren, 1881
+03/26 Ludwig van Beethoven in Wien gestorben, 1827
+03/28 Sergej Rachmaninow in Beverley Hills gestorben, 1943
+03/29 Carl Orff in München gestorben, 1982
+03/31 Joseph Haydn in Rohrau geboren, 1732
+04/01 Sergej Rachmaninow in Oneg geboren, 1873
+04/03 Johannes Brahms in Wien gestorben, 1897
+05/07 Johannes Brahms in Hamburg geboren, 1833
+05/18 Gustav Mahler in Wien gestorben, 1911
+05/22 Richard Wagner in Leipzig geboren, 1813
+05/31 Joseph Haydn in Wien gestorben, 1809
+06/03 Georges Bizet in Bougival bei Paris gestorben, 1875
+06/05 Carl Maria von Weber in London gestorben, 1826
+06/08 Robert Schumann in Zwickau geboren, 1810
+06/11 Richard Strauss in München geboren, 1864
+06/15 Edvard Grieg in Bergen geboren, 1843
+07/07 Gustav Mahler in Kalischt geboren, 1860
+07/10 Carl Orff in München geboren, 1895
+07/29 Robert Schumann in Endenich bei Bonn gestorben, 1856
+07/31 Franz Liszt in Bayreuth gestorben, 1886
+09/04 Edvard Grieg in Bergen gestorben, 1907
+09/08 Richard Strauss in Garmisch-Partenkirchen gestorben, 1949
+09/26 Bela Bartok in New York gestorben, 1945
+10/17 Frederic Chopin in Paris gestorben, 1849
+10/22 Franz Liszt in Raiding (Ungarn) geboren, 1811
+10/25 Georges Bizet in Paris geboren, 1838
+11/04 Felix Mendelssohn Bartholdy in Leipzig gestorben, 1847
+11/18 Carl Maria von Weber in Eutin geboren, 1786
+11/19 Franz Schubert in Wien gestorben, 1828
+11/26 Paul Hindemith in Hanau geboren, 1895
+12/05 Wolfgang Amadeus Mozart in Wien gestorben, 1791
+12/11 (Louis) Hector Berlioz in La-Côte-Saint-André geboren, 1803
+12/17 Ludwig van Beethoven in Bonn getauft, 1770
+12/28 Paul Hindemith in Frankfurt am Main gestorben, 1963
+
+/* Pop */
+09/18 Jimi Hendrix in Paris gestorben, 1970
+
+#endif /* !_de_DE_ISO8859_1_musik_ */
diff --git a/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft
new file mode 100644
index 0000000..444d05b
--- /dev/null
+++ b/misc_cmds/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft
@@ -0,0 +1,19 @@
+/*
+ * Wissenschaft
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/de_DE.ISO8859-1/calendar.wissenschaft,v 1.9 2003/10/15 08:18:59 tg Exp $
+ */
+
+#ifndef _de_DE_ISO8859_1_wissenschaft_
+#define _de_DE_ISO8859_1_wissenschaft_
+
+LANG=de_DE.ISO8859-1
+
+04/12 Erster Mann im All, Juri Gagarin, 1961
+04/18 Einstein gestorben, 1955
+06/22 Konrad Zuse geboren in Berlin, 1919
+10/04 Sputnik 1, erster Satellit im Weltraum, 1957
+12/18 Konrad Zuse gestorben in Hünfeld, 1995
+
+
+#endif /* ! _de_DE_ISO8859_1_wissenschaft_ */
diff --git a/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.all b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.all
new file mode 100644
index 0000000..9a706c0
--- /dev/null
+++ b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.all
@@ -0,0 +1,14 @@
+/*
+ * Calendrier français
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/fr_FR.ISO8859-1/calendar.all,v 1.1 2002/04/29 20:57:36 dwmalone Exp $
+ */
+
+#ifndef _fr_FR_ISO8859_1_all_
+#define _fr_FR_ISO8859_1_all_
+
+#include <fr_FR.ISO8859-1/calendar.jferies>
+#include <fr_FR.ISO8859-1/calendar.fetes>
+#include <fr_FR.ISO8859-1/calendar.proverbes>
+
+#endif /* !_fr_FR.ISO8859-1_all_ */
diff --git a/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.fetes b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.fetes
new file mode 100644
index 0000000..7eb0183
--- /dev/null
+++ b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.fetes
@@ -0,0 +1,630 @@
+/*
+ * Fêtes à souhaiter
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/fr_FR.ISO8859-1/calendar.fetes,v 1.2 2006/04/13 12:14:44 flz Exp $
+ */
+
+#ifndef _fr_FR_ISO8859_1_fetes_
+#define _fr_FR_ISO8859_1_fetes_
+
+LANG=fr_FR.ISO8859-1
+
+/*
+ * N.B.: ceci n'est pas un calendrier liturgique !
+ * Il a seulement été réalisé pour me faire payer à boire
+ * par mes collègues de travail ; on n'y trouve donc que
+ * des prénoms seuls.
+ *
+ * Par ex. « St Antoine de Padoue » se retrouve abrégé en
+ * Antoine, et si Antoine est fêté plusieurs jours par an,
+ * tant mieux pour lui, c'est voulu.
+ */
+
+01/01 Aujourd'hui, c'est la St(e) Almaque.
+01/01 N'oubliez pas les Télémaque !
+01/02 Bonne fête aux Basile !
+01/02 Aujourd'hui, c'est la St(e) Vassili.
+01/02 N'oubliez pas les Grégoire !
+01/03 Bonne fête aux Geneviève !
+01/03 Aujourd'hui, c'est la St(e) Ginette.
+01/04 N'oubliez pas les Odilon !
+01/04 Bonne fête aux Angèle !
+01/04 Aujourd'hui, c'est la St(e) Robert.
+01/05 N'oubliez pas les Édouard !
+01/05 Bonne fête aux Gerlac !
+01/06 Aujourd'hui, c'est la St(e) Mélaine.
+01/06 N'oubliez pas les André !
+01/07 Galette des rois
+01/07 Aujourd'hui, c'est la St(e) Raymond.
+01/07 N'oubliez pas les Raymonde !
+01/07 Bonne fête aux Virginie !
+01/08 Aujourd'hui, c'est la St(e) Lucien.
+01/08 N'oubliez pas les Lucienne !
+01/08 Bonne fête aux Peggy !
+01/08 Aujourd'hui, c'est la St(e) Gudule.
+01/09 N'oubliez pas les Adrien !
+01/09 Bonne fête aux Alix !
+01/10 Aujourd'hui, c'est la St(e) Guillaume.
+01/10 N'oubliez pas les Guillemette !
+01/11 Bonne fête aux Paulin !
+01/11 Aujourd'hui, c'est la St(e) Pauline.
+01/12 N'oubliez pas les Tatiana !
+01/12 Bonne fête aux Alfred !
+01/12 Aujourd'hui, c'est la St(e) Ailred (Aelred, Eilred, Elred).
+01/13 N'oubliez pas les Vivant !
+01/13 Bonne fête aux Vivence !
+01/13 Aujourd'hui, c'est la St(e) Hilaire.
+01/13 N'oubliez pas les Yvette !
+01/14 Bonne fête aux Nina !
+01/14 Aujourd'hui, c'est la St(e) Séraphin.
+01/15 N'oubliez pas les Rémi !
+01/16 Bonne fête aux Marcel !
+01/16 Aujourd'hui, c'est la St(e) Marcelle.
+01/16 N'oubliez pas les Marceau !
+01/16 Bonne fête aux Honorat !
+01/17 Aujourd'hui, c'est la St(e) Roseline.
+01/17 N'oubliez pas les Antoine !
+01/17 Bonne fête aux Anthony !
+01/18 Aujourd'hui, c'est la St(e) Prisca.
+01/18 N'oubliez pas les Libert !
+01/19 Bonne fête aux Marius !
+01/19 Aujourd'hui, c'est la St(e) Canut.
+01/20 N'oubliez pas les Fabienne !
+01/20 Bonne fête aux Sébastien !
+01/20 Aujourd'hui, c'est la St(e) Bastien.
+01/21 N'oubliez pas les Agnès !
+01/21 Bonne fête aux Fructueux !
+01/21 Aujourd'hui, c'est la St(e) Augure.
+01/21 N'oubliez pas les Euloge !
+01/21 Bonne fête aux Avit !
+01/22 Aujourd'hui, c'est la St(e) Vincent.
+01/22 N'oubliez pas les Blésille !
+01/23 Bonne fête aux Barnard !
+01/24 Aujourd'hui, c'est la St(e) François.
+01/25 N'oubliez pas les Morgane !
+01/26 Bonne fête aux Paule !
+01/26 Aujourd'hui, c'est la St(e) Timothée.
+01/26 N'oubliez pas les Tite !
+01/27 Bonne fête aux Angèle !
+01/28 Aujourd'hui, c'est la St(e) Thomas.
+01/29 N'oubliez pas les Gildas !
+01/29 Bonne fête aux Sulpice !
+01/30 Aujourd'hui, c'est la St(e) Martine.
+01/31 N'oubliez pas les Marcelle !
+01/31 Bonne fête aux Jean !
+02/01 Aujourd'hui, c'est la St(e) Ella.
+02/01 N'oubliez pas les Viridiane !
+02/02 Bonne fête aux Théophane !
+02/03 Aujourd'hui, c'est la St(e) Blaise.
+02/03 N'oubliez pas les Anschaire !
+02/04 Bonne fête aux Véronique !
+02/04 Aujourd'hui, c'est la St(e) Jeanne.
+02/04 N'oubliez pas les Gilbert !
+02/05 Bonne fête aux Agathe !
+02/06 Aujourd'hui, c'est la St(e) Gaston.
+02/06 N'oubliez pas les Armand !
+02/07 Bonne fête aux Eugénie !
+02/07 Aujourd'hui, c'est la St(e) Partène.
+02/08 N'oubliez pas les Jacqueline !
+02/08 Bonne fête aux Jérôme !
+02/09 Aujourd'hui, c'est la St(e) Apolline.
+02/09 N'oubliez pas les Appollonie !
+02/10 Bonne fête aux Arnaud !
+02/10 Aujourd'hui, c'est la St(e) Scholastique.
+02/11 N'oubliez pas les Séverin !
+02/11 Bonne fête aux Séverine !
+02/12 Aujourd'hui, c'est la St(e) Félix.
+02/12 N'oubliez pas les Eulalie !
+02/13 Bonne fête aux Béatrice !
+02/13 Aujourd'hui, c'est la St(e) Polyeucte.
+02/14 N'oubliez pas les Valentin !
+02/14 Bonne fête aux Méthode !
+02/14 Aujourd'hui, c'est la St(e) Cyrille.
+02/15 N'oubliez pas les Claude !
+02/15 Bonne fête aux Georgette !
+02/16 Aujourd'hui, c'est la St(e) Julienne.
+02/17 N'oubliez pas les Alexis !
+02/18 Bonne fête aux Bernadette et aux Nadine !
+02/19 Aujourd'hui, c'est la St(e) Gabin.
+02/20 N'oubliez pas les Aimée !
+02/20 Bonne fête aux Aimé !
+02/20 Aujourd'hui, c'est la St(e) Amata.
+02/21 N'oubliez pas les Pierre-Damien !
+02/22 Bonne fête aux Isabelle !
+02/23 Aujourd'hui, c'est la St(e) Lazare.
+02/23 N'oubliez pas les Polycarpe !
+02/24 Bonne fête aux Modeste !
+02/25 Aujourd'hui, c'est la St(e) Roméo.
+02/25 N'oubliez pas les Avertan !
+02/26 Bonne fête aux Nestor !
+02/27 Aujourd'hui, c'est la St(e) Honorine.
+02/27 N'oubliez pas les Gabriel !
+02/28 Bonne fête aux Romain !
+02/28 Aujourd'hui, c'est la St(e) Lupicin.
+02/29 N'oubliez pas les Auguste !
+03/01 Bonne fête aux Aubin !
+03/01 Aujourd'hui, c'est la St(e) Albin.
+03/02 N'oubliez pas les Charles !
+03/03 Bonne fête aux Guénolé (Gwénolé) !
+03/04 Aujourd'hui, c'est la St(e) Casimir.
+03/05 N'oubliez pas les Olive !
+03/05 Bonne fête aux Olivia !
+03/06 Aujourd'hui, c'est la St(e) Colette.
+03/06 N'oubliez pas les Nicole !
+03/07 Bonne fête aux Félicité !
+03/07 Aujourd'hui, c'est la St(e) Félicie.
+03/07 N'oubliez pas les Perpétue !
+03/08 Bonne fête aux Jean !
+03/09 Aujourd'hui, c'est la St(e) Françoise.
+03/10 N'oubliez pas les Vivien !
+03/10 Bonne fête aux Dominique !
+03/11 Aujourd'hui, c'est la St(e) Rosine.
+03/12 N'oubliez pas les Justine !
+03/12 Bonne fête aux Maximilien !
+03/13 Aujourd'hui, c'est la St(e) Rodrigue.
+03/13 N'oubliez pas les Salomon !
+03/13 Bonne fête aux Euphrasie !
+03/14 Aujourd'hui, c'est la St(e) Mathilde.
+03/15 N'oubliez pas les Louise !
+03/16 Bonne fête aux Bénédicte !
+03/16 Aujourd'hui, c'est la St(e) Benoîte.
+03/16 N'oubliez pas les Julien !
+03/17 C'est la St Patrick !
+03/17 Aujourd'hui, c'est la St(e) Patrice.
+03/18 N'oubliez pas les Cyrille !
+03/19 Bonne fête aux Joseph !
+03/20 Aujourd'hui, c'est la St(e) Herbert.
+03/20 N'oubliez pas les Wulfran !
+03/21 Bonne fête aux Clémence !
+03/22 Aujourd'hui, c'est la St(e) Léa.
+03/23 N'oubliez pas les Victorien !
+03/23 Bonne fête aux Turibio !
+03/24 Aujourd'hui, c'est la St(e) Catherine.
+03/24 N'oubliez pas les Karine !
+03/26 Bonne fête aux Lara !
+03/26 Aujourd'hui, c'est la St(e) Ludger.
+03/26 N'oubliez pas les Larissa !
+03/27 Bonne fête aux Habib !
+03/28 Aujourd'hui, c'est la St(e) Gontran.
+03/29 N'oubliez pas les Gwladys !
+03/29 Bonne fête aux Eustase !
+03/30 Aujourd'hui, c'est la St(e) Amédée.
+03/31 N'oubliez pas les Benjamin !
+03/31 Bonne fête aux Benjamine !
+04/01 Votre fichier calendar est corrompu.
+04/01 N'oubliez pas les Hugues !
+04/02 Bonne fête aux Sandrine !
+04/03 Aujourd'hui, c'est la St(e) Richard.
+04/04 N'oubliez pas les Isidore !
+04/04 Bonne fête aux Benoît !
+04/05 Aujourd'hui, c'est la St(e) Irène.
+04/05 N'oubliez pas les Vincent !
+04/06 Bonne fête aux Marcellin !
+04/06 Aujourd'hui, c'est la St(e) Célestin.
+04/06 N'oubliez pas les Guillaume !
+04/07 Bonne fête aux Jean-Baptiste !
+04/07 Aujourd'hui, c'est la St(e) Julienne.
+04/08 N'oubliez pas les Perpet !
+04/08 Bonne fête aux Perpetuus !
+04/09 Aujourd'hui, c'est la St(e) Gautier.
+04/09 N'oubliez pas les Jean !
+04/10 Bonne fête aux Fulbert !
+04/10 Aujourd'hui, c'est la St(e) Michel.
+04/11 N'oubliez pas les Stanislas !
+04/11 Bonne fête aux Gemma !
+04/11 Aujourd'hui, c'est la St(e) Léon.
+04/12 N'oubliez pas les Jules !
+04/12 Bonne fête aux Sabas !
+04/13 Aujourd'hui, c'est la St(e) Ida.
+04/13 N'oubliez pas les Herménégilde !
+04/14 Bonne fête aux Maxime !
+04/14 Aujourd'hui, c'est la St(e) Lydwine.
+04/14 N'oubliez pas les Bénézet !
+04/15 Bonne fête aux Pierre !
+04/16 Aujourd'hui, c'est la St(e) Benoît.
+04/17 N'oubliez pas les Anicet !
+04/17 Bonne fête aux Kateri !
+04/18 Aujourd'hui, c'est la St(e) Parfait.
+04/19 N'oubliez pas les Emma !
+04/19 Bonne fête aux Elphège !
+04/20 Aujourd'hui, c'est la St(e) Odette.
+04/20 N'oubliez pas les Agnès !
+04/21 Bonne fête aux Anselme !
+04/22 Aujourd'hui, c'est la St(e) Alexandre.
+04/22 N'oubliez pas les Soter !
+04/22 Bonne fête aux Caïus !
+04/22 Aujourd'hui, c'est la St(e) Léonide.
+04/23 N'oubliez pas les Georges !
+04/23 Bonne fête aux Pierre !
+04/24 Aujourd'hui, c'est la St(e) Fidèle.
+04/24 N'oubliez pas les Marie-Euphrasie !
+04/25 Bonne fête aux Marc !
+04/26 Aujourd'hui, c'est la St(e) Alida.
+04/27 N'oubliez pas les Zita !
+04/27 Bonne fête aux Pierre !
+04/28 Aujourd'hui, c'est la St(e) Valérie.
+04/28 N'oubliez pas les Louis-Marie !
+04/28 Bonne fête aux Paul !
+04/29 Aujourd'hui, c'est la St(e) Joseph-Benoît.
+04/29 N'oubliez pas les Hugues !
+04/30 Bonne fête aux Robert !
+04/30 Aujourd'hui, c'est la St(e) Catherine.
+05/02 N'oubliez pas les Boris !
+05/03 Bonne fête aux Jacques !
+05/03 Aujourd'hui, c'est la St(e) Philippe.
+05/04 N'oubliez pas les Sylvain !
+05/05 Bonne fête aux Judith !
+05/06 Aujourd'hui, c'est la St(e) Prudence.
+05/07 N'oubliez pas les Gisèle !
+05/09 Bonne fête aux Pacôme !
+05/10 Aujourd'hui, c'est la St(e) Solange.
+05/11 N'oubliez pas les Estelle !
+05/12 Bonne fête aux Achille !
+05/14 Aujourd'hui, c'est la St(e) Matthias.
+05/15 N'oubliez pas les Denise !
+05/16 Bonne fête aux Honoré !
+05/17 Aujourd'hui, c'est la St(e) Pascal.
+05/18 N'oubliez pas les Éric !
+05/19 Bonne fête aux Yves !
+05/19 Aujourd'hui, c'est la St(e) Yvonne.
+05/20 N'oubliez pas les Bernardin !
+05/21 Bonne fête aux Constantin !
+05/22 Aujourd'hui, c'est la St(e) Émile.
+05/23 N'oubliez pas les Didier !
+05/24 Bonne fête aux Donatien !
+05/25 Aujourd'hui, c'est la St(e) Sophie.
+05/26 N'oubliez pas les Bérenger !
+05/28 Bonne fête aux Germain !
+05/29 Aujourd'hui, c'est la St(e) Aymard.
+05/30 N'oubliez pas les Ferdinand !
+06/01 Bonne fête aux Justin !
+06/02 Aujourd'hui, c'est la St(e) Blandine.
+06/03 N'oubliez pas les Kévin !
+06/04 Bonne fête aux Clotilde !
+06/05 Aujourd'hui, c'est la St(e) Igor.
+06/06 N'oubliez pas les Norbert !
+06/07 Bonne fête aux Gilbert !
+06/08 Aujourd'hui, c'est la St(e) Médard.
+06/09 N'oubliez pas les Diane !
+06/11 Bonne fête aux Barnabé !
+06/11 Aujourd'hui, c'est la St(e) Yolande.
+06/12 N'oubliez pas les Guy !
+06/13 Bonne fête aux Antoine !
+06/14 Aujourd'hui, c'est la St(e) Élisée.
+06/15 N'oubliez pas les Germaine !
+06/16 Bonne fête aux Jean-François !
+06/17 Aujourd'hui, c'est la St(e) Hervé.
+06/18 N'oubliez pas les Léonce !
+06/19 Bonne fête aux Romuald !
+06/20 Aujourd'hui, c'est la St(e) Silvère.
+06/21 N'oubliez pas les Rodolphe !
+06/22 Bonne fête aux Alban !
+06/23 Aujourd'hui, c'est la St(e) Audrey.
+06/24 N'oubliez pas les Jean-Baptiste !
+06/25 Bonne fête aux Prosper !
+06/26 Aujourd'hui, c'est la St(e) Anthelme.
+06/27 N'oubliez pas les Fernand !
+06/28 Bonne fête aux Irénée !
+06/29 Aujourd'hui, c'est la St(e) Paul.
+06/29 N'oubliez pas les Pierre !
+06/30 Bonne fête aux Martial !
+07/01 Aujourd'hui, c'est la St(e) Thierry.
+07/02 N'oubliez pas les Martinien !
+07/03 Bonne fête aux Thomas !
+07/04 Aujourd'hui, c'est la St(e) Florent.
+07/05 N'oubliez pas les Antoine !
+07/06 Bonne fête aux Mariette !
+07/07 Aujourd'hui, c'est la St(e) Raoul.
+07/08 N'oubliez pas les Thibaut !
+07/09 Bonne fête aux Amandine !
+07/10 Aujourd'hui, c'est la St(e) Ulrich.
+07/11 N'oubliez pas les Benoît !
+07/12 Bonne fête aux Olivier !
+07/13 Aujourd'hui, c'est la St(e) Henri.
+07/13 N'oubliez pas les Joël !
+07/14 Bonne fête aux Camille !
+07/15 Aujourd'hui, c'est la St(e) Donald.
+07/17 N'oubliez pas les Caroline !
+07/17 Bonne fête aux Charlotte !
+07/18 Aujourd'hui, c'est la St(e) Frédéric.
+07/19 N'oubliez pas les Arsène !
+07/20 Bonne fête aux Marina !
+07/21 Aujourd'hui, c'est la St(e) Victor.
+07/22 N'oubliez pas les Marie-Madeleine !
+07/23 Bonne fête aux Brigitte !
+07/24 Aujourd'hui, c'est la St(e) Christine.
+07/25 N'oubliez pas les Jacques !
+07/26 Bonne fête aux Anne !
+07/26 Aujourd'hui, c'est la St(e) Joachim.
+07/27 N'oubliez pas les Nathalie !
+07/28 Bonne fête aux Samson !
+07/29 Aujourd'hui, c'est la St(e) Marthe.
+07/30 N'oubliez pas les Juliette !
+07/31 Bonne fête aux Ignace !
+08/01 Aujourd'hui, c'est la St(e) Alphonse.
+08/01 N'oubliez pas les Pierre !
+08/02 Bonne fête aux Julien !
+08/03 Aujourd'hui, c'est la St(e) Lydie.
+08/03 N'oubliez pas les Pierre-Julien !
+08/04 Bonne fête aux Jean-Marie !
+08/04 Aujourd'hui, c'est la St(e) Dominique.
+08/05 N'oubliez pas les Abel !
+08/05 Bonne fête aux Oswald !
+08/07 Aujourd'hui, c'est la St(e) Gaëtan.
+08/08 N'oubliez pas les Dominique !
+08/08 Bonne fête aux Cyriaque !
+08/09 Aujourd'hui, c'est la St(e) Amour.
+08/10 N'oubliez pas les Laurent !
+08/11 Bonne fête aux Claire !
+08/11 Aujourd'hui, c'est la St(e) Philomène.
+08/12 N'oubliez pas les Clarisse !
+08/13 Bonne fête aux Hyppolite !
+08/13 Aujourd'hui, c'est la St(e) Radegonde.
+08/14 N'oubliez pas les Évrard !
+08/14 Bonne fête aux Maximilien !
+08/15 Aujourd'hui, c'est la St(e) Marie.
+08/16 N'oubliez pas les Armel !
+08/16 Bonne fête aux Roch !
+08/17 Aujourd'hui, c'est la St(e) Hyacinthe.
+08/18 N'oubliez pas les Hélène !
+08/19 Bonne fête aux Jean-Eudes !
+08/19 Aujourd'hui, c'est la St(e) Louis.
+08/20 N'oubliez pas les Bernard !
+08/21 Bonne fête aux Christophe !
+08/21 Aujourd'hui, c'est la St(e) Jeanne.
+08/22 N'oubliez pas les Fabrice !
+08/22 Bonne fête aux Symphorien !
+08/23 Aujourd'hui, c'est la St(e) Rose.
+08/23 N'oubliez pas les Philippe !
+08/24 Bonne fête aux Barthélémy !
+08/25 Aujourd'hui, c'est la St(e) Louis.
+08/26 N'oubliez pas les Natacha !
+08/26 Bonne fête aux Zéphirin !
+08/26 Aujourd'hui, c'est la St(e) Eulade.
+08/27 N'oubliez pas les Edwige !
+08/27 Bonne fête aux Joseph !
+08/28 Aujourd'hui, c'est la St(e) Augustin.
+08/29 N'oubliez pas les Sabine !
+08/30 Bonne fête aux Fiacre !
+08/30 Aujourd'hui, c'est la St(e) Rose.
+08/31 N'oubliez pas les Aristide !
+08/31 Bonne fête aux Raymond !
+09/01 Aujourd'hui, c'est la St(e) Gilles.
+09/02 N'oubliez pas les Ingrid !
+09/03 Bonne fête aux Grégoire !
+09/04 Aujourd'hui, c'est la St(e) Rosalie.
+09/05 N'oubliez pas les Raïssa !
+09/06 Bonne fête aux Bertrand !
+09/07 Aujourd'hui, c'est la St(e) Reine.
+09/09 N'oubliez pas les Alain !
+09/10 Bonne fête aux Inès !
+09/11 Aujourd'hui, c'est la St(e) Adelphe.
+09/12 N'oubliez pas les Apollinaire !
+09/13 Bonne fête aux Aimé !
+09/15 Aujourd'hui, c'est la St(e) Roland.
+09/16 N'oubliez pas les Édith !
+09/17 Bonne fête aux Renaud !
+09/18 Aujourd'hui, c'est la St(e) Nadège.
+09/19 N'oubliez pas les Émilie !
+09/20 Bonne fête aux Davy !
+09/21 Aujourd'hui, c'est la St(e) Matthieu.
+09/22 N'oubliez pas les Maurice !
+09/23 Bonne fête aux Constant !
+09/24 Aujourd'hui, c'est la St(e) Thècle.
+09/25 N'oubliez pas les Hermann !
+09/26 Bonne fête aux Côme !
+09/26 Aujourd'hui, c'est la St(e) Damien.
+09/27 N'oubliez pas les Vincent !
+09/28 Bonne fête aux Venceslas !
+09/29 Aujourd'hui, c'est la St(e) Michel.
+09/29 N'oubliez pas les Raphaël !
+09/30 Bonne fête aux Jérôme !
+10/01 Aujourd'hui, c'est la St(e) Thérèse.
+10/02 N'oubliez pas les Léger !
+10/03 Bonne fête aux Gérard !
+10/04 Aujourd'hui, c'est la St(e) François.
+10/05 N'oubliez pas les Placide !
+10/05 Bonne fête aux Fleur !
+10/05 Aujourd'hui, c'est la St(e) Flore.
+10/05 N'oubliez pas les Pâquerette !
+10/05 Bonne fête aux Violette !
+10/05 Aujourd'hui, c'est la St(e) Pervenche.
+10/05 N'oubliez pas les Anémone !
+10/05 Bonne fête aux Bluette !
+10/05 Aujourd'hui, c'est la St(e) Capucine.
+10/05 N'oubliez pas les Dahlia !
+10/05 Bonne fête aux Myrtille !
+10/05 Aujourd'hui, c'est la St(e) Hortense.
+10/05 N'oubliez pas les Violaine !
+10/05 Bonne fête aux Anne-Aymone !
+10/05 Aujourd'hui, c'est la St(e) Dalie.
+10/06 N'oubliez pas les Bruno !
+10/06 Bonne fête aux Foy !
+10/07 Aujourd'hui, c'est la St(e) Serge.
+10/08 N'oubliez pas les Pélagie !
+10/26 Bonne fête aux Démétrius !
+10/09 Aujourd'hui, c'est la St(e) Denis.
+10/09 N'oubliez pas les Denys !
+10/10 Bonne fête aux Ghislain !
+10/10 Aujourd'hui, c'est la St(e) Ghislaine.
+10/10 N'oubliez pas les Guislain !
+10/10 Bonne fête aux Guislaine !
+10/11 Aujourd'hui, c'est la St(e) Firmin.
+10/11 N'oubliez pas les Gausbert !
+10/12 Bonne fête aux Wilfried !
+10/12 Aujourd'hui, c'est la St(e) Séraphin.
+10/13 N'oubliez pas les Géraud !
+10/14 Bonne fête aux Juste !
+10/14 Aujourd'hui, c'est la St(e) Calliste.
+10/15 N'oubliez pas les Thérèse !
+10/16 Bonne fête aux Edwige !
+10/16 Aujourd'hui, c'est la St(e) Marie-Marguerite.
+10/17 N'oubliez pas les Baudoin !
+10/17 Bonne fête aux Ignace !
+10/18 Aujourd'hui, c'est la St(e) Luc.
+10/19 N'oubliez pas les René !
+10/20 Bonne fête aux Adeline !
+10/20 Aujourd'hui, c'est la St(e) Aline.
+10/20 N'oubliez pas les Line !
+10/21 Bonne fête aux Céline !
+10/21 Aujourd'hui, c'est la St(e) Hilarion.
+10/22 N'oubliez pas les Élodie !
+10/22 Bonne fête aux Nunillon !
+10/22 Aujourd'hui, c'est la St(e) Salomé.
+10/23 N'oubliez pas les Jean !
+10/24 Bonne fête aux Florentin !
+10/25 Aujourd'hui, c'est la St(e) Crépin.
+10/25 N'oubliez pas les Crépinien !
+10/25 Bonne fête aux Chrysanthe !
+10/25 Aujourd'hui, c'est la St(e) Darie.
+10/25 N'oubliez pas les Enguerran !
+10/26 Bonne fête aux Dimitri !
+10/26 Aujourd'hui, c'est la St(e) Évariste.
+10/27 N'oubliez pas les Émeline !
+10/27 Bonne fête aux Didier !
+10/27 Aujourd'hui, c'est la St(e) Frumence.
+10/28 N'oubliez pas les Jude !
+10/28 Bonne fête aux Judas !
+10/28 Aujourd'hui, c'est la St(e) Thaddée.
+10/28 N'oubliez pas les Simon !
+10/28 Bonne fête aux Simone (Simonne) !
+10/29 Aujourd'hui, c'est la St(e) Narcisse.
+10/30 N'oubliez pas les Bienvenue !
+10/30 Bonne fête aux Dorothée !
+10/31 Aujourd'hui, c'est la St(e) Quentin.
+10/31 N'oubliez pas les Alphonse !
+10/31 Bonne fête aux Wolfgang !
+11/03 Aujourd'hui, c'est la St(e) Hubert.
+11/04 N'oubliez pas les Charles !
+11/04 Bonne fête aux Amans !
+11/05 Aujourd'hui, c'est la St(e) Sylvie.
+11/05 N'oubliez pas les Sylvette !
+11/05 Bonne fête aux Sylviane !
+11/05 Aujourd'hui, c'est la St(e) Zacharie.
+11/05 N'oubliez pas les Élisabeth !
+11/06 Bonne fête aux Bertille !
+11/06 Aujourd'hui, c'est la St(e) Léonard.
+11/06 N'oubliez pas les Winnoc !
+11/07 Bonne fête aux Carine !
+11/07 Aujourd'hui, c'est la St(e) Karine.
+11/07 N'oubliez pas les Ernest !
+11/07 Bonne fête aux Ernst !
+11/07 Aujourd'hui, c'est la St(e) Willibrord.
+11/08 N'oubliez pas les Geoffroy !
+11/09 Bonne fête aux Théodore !
+11/10 Aujourd'hui, c'est la St(e) Léon.
+11/10 N'oubliez pas les Léontine !
+11/10 Bonne fête aux Lionel !
+11/11 Aujourd'hui, c'est la St(e) Martin.
+11/12 N'oubliez pas les Christian !
+11/12 Bonne fête aux Josaphat !
+11/13 Aujourd'hui, c'est la St(e) Brice.
+11/13 N'oubliez pas les Diégo !
+11/13 Bonne fête aux Didace !
+11/14 Aujourd'hui, c'est la St(e) Sidoine.
+11/14 N'oubliez pas les Sidonie !
+11/14 Bonne fête aux Sérapion !
+11/15 Aujourd'hui, c'est la St(e) Albert.
+11/16 N'oubliez pas les Marguerite !
+11/16 Bonne fête aux Gertrude !
+11/17 Aujourd'hui, c'est la St(e) Élisabeth.
+11/17 N'oubliez pas les Élise !
+11/17 Bonne fête aux Lise !
+11/18 Aujourd'hui, c'est la St(e) Aude.
+11/19 N'oubliez pas les Tanguy !
+11/19 Bonne fête aux Tanneguy !
+11/19 Aujourd'hui, c'est la St(e) Mechtilde.
+11/19 N'oubliez pas les Mathilde !
+11/19 Bonne fête aux Patrocle !
+11/20 Aujourd'hui, c'est la St(e) Edmond.
+11/20 N'oubliez pas les Octave !
+11/20 Bonne fête aux Adventor !
+11/20 Aujourd'hui, c'est la St(e) Solutor.
+11/20 N'oubliez pas les Ambroise !
+11/20 Bonne fête aux Rutus !
+11/22 Aujourd'hui, c'est la St(e) Cécile.
+11/22 N'oubliez pas les Célia !
+11/23 Bonne fête aux Clément !
+11/23 Aujourd'hui, c'est la St(e) Clémentine.
+11/23 N'oubliez pas les Colomban !
+11/24 Bonne fête aux Augusta !
+11/24 Aujourd'hui, c'est la St(e) Flora.
+11/25 N'oubliez pas les Catherine !
+11/24 Bonne fête aux Maria !
+11/26 Aujourd'hui, c'est la St(e) Delphine.
+11/26 N'oubliez pas les Elzéar !
+11/27 Bonne fête aux Séverin !
+11/27 Aujourd'hui, c'est la St(e) Séverine.
+11/27 N'oubliez pas les Maxime !
+11/28 Bonne fête aux Jacques !
+11/29 Aujourd'hui, c'est la St(e) Saturnin.
+11/29 N'oubliez pas les Sernin (Cernin) !
+11/29 Bonne fête aux Savourin !
+11/29 Aujourd'hui, c'est la St(e) Sornin.
+11/30 N'oubliez pas les André !
+11/30 Bonne fête aux Andréa !
+12/01 Aujourd'hui, c'est la St(e) Florence.
+12/01 N'oubliez pas les Éloi !
+12/01 Bonne fête aux Airy !
+12/02 Aujourd'hui, c'est la St(e) Viviane.
+12/03 N'oubliez pas les François-Xavier !
+12/03 Bonne fête aux Xavier !
+12/03 Aujourd'hui, c'est la St(e) Eugène.
+12/04 N'oubliez pas les Barbara !
+12/04 Bonne fête aux Barbe !
+12/05 Aujourd'hui, c'est la St(e) Gérald.
+12/05 N'oubliez pas les Géraldine !
+12/05 Bonne fête aux Géraud !
+12/05 Aujourd'hui, c'est la St(e) Sabas.
+12/06 N'oubliez pas les Nicolas !
+12/07 Bonne fête aux Ambroise !
+12/09 Aujourd'hui, c'est la St(e) Pierre.
+12/10 N'oubliez pas les Romaric !
+12/10 Bonne fête aux Eulalie !
+12/10 Aujourd'hui, c'est la St(e) Melchaide.
+12/10 N'oubliez pas les Miltiade !
+12/11 Bonne fête aux Daniel !
+12/11 Aujourd'hui, c'est la St(e) Damase.
+12/12 N'oubliez pas les Chantal !
+12/13 Bonne fête aux Lucie !
+12/13 Aujourd'hui, c'est la St(e) Rolande.
+12/13 N'oubliez pas les Aurore !
+12/14 Bonne fête aux Odile !
+12/15 Aujourd'hui, c'est la St(e) Ninon.
+12/15 N'oubliez pas les Nina !
+12/15 Bonne fête aux Christiane !
+12/15 Aujourd'hui, c'est la St(e) Christina.
+12/16 N'oubliez pas les Alice !
+12/16 Bonne fête aux Adélaïde !
+12/16 Aujourd'hui, c'est la St(e) Évrard.
+12/16 N'oubliez pas les Éberhard !
+12/17 Bonne fête aux Gaël !
+12/17 Aujourd'hui, c'est la St(e) Lazare.
+12/17 N'oubliez pas les Olympe !
+12/17 Bonne fête aux Olympias !
+12/17 Aujourd'hui, c'est la St(e) Judicaël.
+12/18 N'oubliez pas les Gatien !
+12/18 Bonne fête aux Winebald !
+12/19 Aujourd'hui, c'est la St(e) Urbain.
+12/20 N'oubliez pas les Abraham !
+12/20 Bonne fête aux Théophile !
+12/21 Aujourd'hui, c'est la St(e) Pierre.
+12/22 N'oubliez pas les Françoise-Xavière !
+12/22 Bonne fête aux Flavien !
+12/23 Aujourd'hui, c'est la St(e) Armand.
+12/24 N'oubliez pas les Adèle !
+12/24 Bonne fête aux Charbel !
+12/25 Aujourd'hui, c'est la St(e) Emmanuel.
+12/25 N'oubliez pas les Emmanuelle !
+12/25 Bonne fête aux Noël !
+12/26 Aujourd'hui, c'est la St(e) Étienne.
+12/26 N'oubliez pas les Stéphane !
+12/26 Bonne fête aux Stéphanie !
+12/27 Aujourd'hui, c'est la St(e) Jean.
+12/27 N'oubliez pas les Yann !
+12/28 Bonne fête aux Innocents !
+12/29 Aujourd'hui, c'est la St(e) David.
+12/30 N'oubliez pas les Roger !
+12/31 Bonne fête aux Sylvestre !
+
+#endif /*! _fr_FR_ISO8859_1_fetes */
diff --git a/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.french b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.french
new file mode 100644
index 0000000..823aef4
--- /dev/null
+++ b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.french
@@ -0,0 +1,12 @@
+/*
+ * French calendar file(s)
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/fr_FR.ISO8859-1/calendar.french,v 1.1 2002/04/29 20:57:36 dwmalone Exp $
+ */
+
+#ifndef _calendar_french_
+#define _calendar_french_
+
+#include <fr_FR.ISO8859-1/calendar.all>
+
+#endif /* !_calendar_french_ */
diff --git a/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.jferies b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.jferies
new file mode 100644
index 0000000..21d1f0c
--- /dev/null
+++ b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.jferies
@@ -0,0 +1,46 @@
+/*
+ * Jours fériés
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/fr_FR.ISO8859-1/calendar.jferies,v 1.2 2006/04/13 12:14:44 flz Exp $
+ */
+
+#ifndef _fr_FR_ISO8859_1_jferies_
+#define _fr_FR_ISO8859_1_jferies_
+
+LANG=fr_FR.ISO8859-1
+
+/* Jours chômés */
+01/01 Nouvel an
+05/01 Fête du travail
+05/08 Armistice 1945
+07/14 Fête nationale française
+11/11 Armistice 1918
+
+/* Jours fériés religieux */
+Easter Pâques
+Easter+1 Lundi de Pâques
+Easter+39 Ascension
+Easter+49 Pentecôte
+Easter+50 Lundi de Pentecôte
+08/15 Assomption
+11/01 Toussaint
+12/25 Noël
+
+/* Les dates suivantes ne sont malheureusement pas fériées... */
+
+/* Saisons */
+03/21* Printemps
+06/21* Été
+09/21* Automne
+12/21* Hiver
+
+/* Changements d'heure */
+03/SundayLast Passage à l'heure d'été
+10/SundayLast Passage à l'heure d'hiver
+
+/* Divers */
+/* BUG : si Penteco^te = 05/SunLast, fe^te des me`res repousse'e d'une semaine */
+05/SundayLast Fêtes des mères
+June Sun+3 Fêtes des pères
+
+#endif /*! _fr_FR_ISO8859_1_jferies_ */
diff --git a/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.proverbes b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.proverbes
new file mode 100644
index 0000000..40c6414
--- /dev/null
+++ b/misc_cmds/calendar/calendars/fr_FR.ISO8859-1/calendar.proverbes
@@ -0,0 +1,354 @@
+/*
+ * Proverbes liés au calendrier
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/fr_FR.ISO8859-1/calendar.proverbes,v 1.1 2002/04/29 20:57:36 dwmalone Exp $
+ */
+
+#ifndef _fr_FR_ISO8859_1_proverbes_
+#define _fr_FR_ISO8859_1_proverbes_
+
+LANG=fr_FR.ISO8859-1
+
+/* Janvier */
+01/01 Calme et claire nuit de l'an
+ À bonne année donne l'élan.
+01/02 Janvier d'eau chiche
+ Fait le paysan riche.
+01/04 Un mois de janvier sans gelée
+ N'amène jamais une bonne année.
+01/06 Pluie aux Rois,
+ Blé jusqu'au toit.
+01/08 Janvier sec et sage
+ Est un bon présage.
+01/09 Saint Julien brise la glace ;
+ S'il ne la brise, c'est qu'il l'embrasse.
+01/10 Beau temps à la saint Guillaume
+ Donne plus de blé que de chaume.
+01/13 Soleil au jour de saint Hilaire,
+ Fends du bois pour ton hiver.
+01/14 Pingouin dans les champs,
+ Hiver méchant.
+01/15 S'il gèle à la saint Maur,
+ La moitié de l'hiver est dehors.
+01/18 À la saint Pierre,
+ L'hiver s'en va ou se resserre.
+01/20 S'il gèle à la saint Sébastien,
+ L'hiver s'en va ou revient.
+01/22 Pour saint Vincent,
+ L'hiver perd ses dents
+ Ou les retrouve pour longtemps.
+01/24 S'il tonne en janvier,
+ Monte les barriques au grenier.
+01/25 Le jour de saint Paul,
+ L'hiver se rompt le col.
+01/31 Janvier fait le péché,
+ Mars en est accusé.
+
+/* Février */
+02/01 À la saint Ignace,
+ L'eau est de glace.
+02/02 Chandeleur claire, hiver derrière ;
+ Chandeleur trouble, hiver redouble.
+02/03 À la saint Blaise,
+ L'hiver s'apaise,
+ Mais s'il redouble et s'il reprend,
+ Longtemps après on s'en ressent.
+02/05 Pour la sainte Agathe, sème ton oignon,
+ Fût-il dans la glace, il deviendra bon.
+02/09 À la sainte Apolline
+ Bien souvent l'hiver nous quitte.
+02/12 Si le soleil rit à la sainte Eulalie,
+ Pommes et cidre à la folie.
+02/14 À la saint Valentin,
+ Tous les vents sont marins.
+02/16 Pluie de février
+ À la terre vaut du fumier.
+02/18 Février trop doux,
+ Printemps en courroux.
+02/20 La neige de février
+ Brûle le blé.
+02/22 Neige à la sainte Isabelle
+ Fait la fleur plus belle.
+02/24 Saint Mathias
+ Casse la glace ;
+ S'il n'y en a pas,
+ Il en fera.
+02/27 Gelée de la sainte Honorine
+ Rend toute la vallée chagrine.
+02/28 Fleur de février
+ Va mal au pommier.
+
+/* Mars */
+03/01 Taille à la saint Aubin
+ Donnera de gros raisins.
+03/02 Quand mars mouillera,
+ Bien du vin tu auras.
+03/03 Soit au début, soit à la fin,
+ Mars nous montre son venin.
+03/06 À la sainte Colette
+ Commence à chanter l'alouette.
+03/08 Quand en mars il tonne,
+ L'année sera bonne.
+03/10 Mars venteux,
+ Vergers pommeux.
+03/12 À la saint Grégoire,
+ Il faut tailler la vigne pour boire.
+03/13 Poussière de mars
+ Est poussière d'or...
+03/15 Pluie de mars grandit l'herbette
+ Et souvent annonce disette.
+03/17 S'il fait doux à la saint Patrice,
+ De leurs trous sortent les écrevisses.
+03/19 Pour saint Joseph,
+ L'hirondelle va et vient.
+03/21 S'il pleut à la saint Benoît,
+ Il pleut trente-sept jours plus trois.
+03/23 Quand à glace il gèle à la saint Victorien,
+ En pêches et en abricots il n'y a rien.
+03/25 Quand fleurs en mars il y aura,
+ Guère de fruits ne mangeras.
+03/28 À la saint Gontran, si la température est belle,
+ Arrivent les premières hirondelles.
+03/30 Quand mars se déguise en été,
+ Avril prend ses habits fourrés.
+03/31 À la saint Benjamin,
+ Le mauvais temps prend fin.
+
+/* Mobiles */
+Easter-7 Le propre jour des Rameaux
+ Sème oignons et poireaux.
+Easter-3 La gelée du jeudi saint
+ Gèle le sarrasin.
+Easter-2 Gelée du vendredi saint
+ Gèle le pain et le vin.
+Easter S'il pleut à Pâques,
+ Il pleut pendant quarante jours.
+Easter Pâques en mars,
+ Pestes, guerres ou famines.
+Easter+36 Haricots de rogations
+ Rendent à foison.
+Easter+37 Belles rogations,
+ Belles moissons.
+Easter+39 S'il pleut à l'Ascension,
+ Tout va en perdition.
+Easter+49 La Pentecôte
+ Donne les fruits, ou les ôte.
+Easter+56 S'il pleut à la Trinité,
+ Il pleut tous les jours de l'année.
+
+/* Avril */
+04/01 Avril entrant,
+ Coucou chantant,
+ Sonnailles tintant.
+04/05 Avril fait la fleur,
+ Mai en a l'honneur.
+04/10 Il n'est point d'avril si beau
+ Qu'il n'ait de neige à son chapeau.
+04/15 En avril, ne te découvre pas d'un fil ;
+ En mai, fais ce qu'il te plaît ;
+ En juin, de trois habits n'en garde qu'un.
+04/17 Orage en avril,
+ Prépare tes barrils.
+04/19 À la sainte Léonide
+ Chaque blé pousse rapide.
+04/22 Pluie à la sainte Opportune,
+ Ni cerises ni prunes.
+04/23 À la saint Georges,
+ Sème ton orge,
+ À la saint Marc,
+ Il est trop tard.
+04/25 À la saint Marc, s'il tombe de l'eau,
+ Il n'y aura pas de fruits à couteau.
+04/28 Avril pluvieux et mai venteux
+ Ne rendent pas le paysan disetteux.
+04/30 La pluie à la saint Robert
+ De bon vin emplira ton verre.
+
+/* Mai */
+05/03 Les trois saints au sang de navet,
+ Pancrace, Mamert et Servais,
+ Sont bien nommés les saints de glace,
+ Mamert, Servais et Pancrace.
+05/15 À la sainte Denise,
+ Le froid n'en fait plus à sa guise.
+05/16 À la saint Honoré,
+ S'il fait gelée,
+ Le vin diminue de moitié.
+05/18 Bon fermier à sainte Juliette
+ Doit vendre ses poulettes.
+05/22 Beau temps à la sainte Émilie
+ Donne du fruit à la folie.
+05/23 Qui sème haricots à la saint Didier
+ Les arrachera à poignées.
+
+/* Juin */
+06/08 S'il pleut à la saint Médard,
+ Il pleut quarante jours plus tard,
+ À moins que saint Barnabé
+ Ne vienne l'arrêter.
+06/11 À la saint Barnabé,
+ Fauche ton pré.
+06/16 Si le jour de saint Fargeau
+ La lune se fait dans l'eau,
+ Le reste du mois est beau.
+06/19 S'il pleut à la saint Gervais,
+ Il pleut quarante jours après.
+06/20 Pluie d'orage à la saint Sylvère,
+ C'est beaucoup de vin dans le verre.
+06/24 S'il pleut à la saint Jean,
+ Guère de vin ni de pain.
+06/25 Après la saint Jean, si le coucou chante,
+ L'année sera rude et méchante.
+06/29 S'il pleut la veille de la saint Pierre,
+ La vigne est réduite du tiers.
+
+/* Juillet */
+07/02 S'il pleut à la Visitation,
+ Pluie à discrétion.
+07/03 À la saint Anatole,
+ Confiture dans la casserole.
+07/06 Juillet sans orage,
+ Famine au village.
+07/10 Petite pluie de juillet ensoleillé
+ Emplit caves et greniers.
+07/13 Quand reviendra la saint Henri,
+ Tu planteras ton céleri.
+07/16 Qui veut des beaux navets
+ Les sème en juillet.
+07/20 À la sainte Marguerite, pluie
+ Jamais au paysan ne souris ;
+ Mais pluie à la sainte Anne,
+ Pour lui c'est de la manne.
+07/21 S'il pleut à la saint Victor,
+ La récolte n'est pas d'or.
+07/22 S'il pleut à la sainte Madeleine,
+ Il pleuvra durant six semaines.
+07/25 Si saint jacques est serein,
+ L'hiver sera dû et serein.
+07/26 Pour la sainte Anne, s'il pleut,
+ Trente jours seront pluvieux.
+
+/* Août */
+August Sun+2 En août et vendanges, il n'y a ni fêtes ni dimanches.
+08/02 S'il pleut au mois d'août,
+ Les truffes sont au bout.
+08/04 Août donne goût.
+08/06 Soleil rouge en août,
+ C'est de la pluie partout.
+08/10 Qui sème à la saint Laurent
+ Y perd la graine et puis le temps.
+08/13 S'il pleut à la sainte Radegonde,
+ Misère abonde sur le monde.
+08/15 Pluie de l'Assomption,
+ Huit jours de mouillon.
+08/16 De saint Roch la grande chaleur
+ Prépare du vin la couleur.
+08/18 Temps trop beau en août
+ Annonce hiver en courroux.
+08/20 Brumes d'août font passer les châtaignes.
+08/22 Jamais d'août la sécheresse
+ N'amènera la richesse.
+08/24 À la saint Barthélémy,
+ Paie to dû.
+08/28 Fine pluie à la saint Augustin,
+ C'est comme s'il pleuvait du vin.
+08/29 Quand les hirondelles voient la saint Michel,
+ L'hiver ne vient qu'à Noël.
+
+/* Septembre */
+09/01 Pluie de la saint Gilles ruine les glands.
+09/05 Septembre humide,
+ Pas de tonneau vide.
+09/11 Tu peux semer sans crainte
+ Quand arrive la saint Hyacinthe.
+09/15 La rosée de saint Albin
+ est, dit-on, rosée de vin.
+09/19 Qui sème à la saint Janvier
+ De l'an récolte le premier.
+09/21 Si Matthieu pleure au lieu de rire,
+ Le vin en vinaigre vire.
+09/22 Semis de saint Maurice,
+ Récolte à ton caprice.
+09/23 Septembre se nomme
+ Le mai de l'automne.
+09/25 À la saint Firmin
+ L'hiver est en chemin.
+09/29 Pluie de saint Michel sans orage
+ D'un hiver doux est le présage.
+09/30 À la saint Jérôme,
+ Hoche tes pommes.
+
+/* Octobre */
+10/02 À la saint Léger,
+ Faut s'purger !
+10/04 Sème à la saint François,
+ Ton blé aura plus de poids.
+10/09 Beau temps à la saint Denis,
+ Hiver pourri.
+10/13 En octobre, qui ne fume rien
+ Ne récolte rien.
+10/16 Coupe ton chou à la saint Gall,
+ En hiver c'est un régal.
+10/18 À la saint Luc, sème dru,
+ Ou ne sème plus.
+10/23 Gelée d'octobre
+ Rend le vigneron sobre.
+10/25 Pour saint Crépin, mort aux mouches.
+10/28 À la sainte Simone,
+ Il faut avoir rentré ses pommes.
+10/31 Quand octobre prend sa fin,
+ Dans la cave est le vin.
+
+/* Novembre */
+11/01 À la Toussaint commence l'été de la saint Martin.
+11/02 Telle Toussaint, tel Noël,
+ Et Pâques pareil.
+11/04 À la saint Charles,
+ La gelée parle.
+11/08 En novembre, s'il tonne,
+ L'année sera bonne.
+11/11 Si l'hiver va droit son chemin,
+ Vous l'aurez à la saint Martin,
+ Mais s'il trouve quelque encombrée,
+ Vous l'aurez à la saint André.
+11/11 Tue ton cochon à la saint Martin
+ Et invite ton voisin.
+11/19 Sainte Élisabeth nous montre quel bonhomme sera l'hiver.
+11/22 Pour sainte Cécile,
+ Chaque haricot en fait mille.
+11/23 Quand l'hiver vient doucement,
+ Il est là à la saint Clément.
+11/25 Sainte Catherine, toute fille veut la fêter,
+ Mais aucune ne veut la coiffer.
+11/25 Quand sainte Catherine au ciel fait la moue,
+ Il faut patauger longtemps dans la boue.
+11/30 Quand l'hiver n'est pas pressé,
+ Il arrive à la saint André.
+
+/* Décembre */
+12/SundayFirst Tel avent,
+ Tel printemps.
+12/06 Neige de saint Nicolas
+ Donne froid pour trois mois.
+12/07 À la saint Ambroise,
+ Du froid pour huit jours.
+12/10 À la sainte Julie,
+ Le soleil ne quitte pas son lit.
+12/13 À la sainte Luce,
+ Le jour croît du saut d'une puce.
+12/16 Décembre de froid trop chiche
+ Ne fait pas le paysan riche.
+12/21 S'il gèle à la saint Thomas,
+ Il gèlera encore trois mois.
+12/23 Le tonnerre en décembre
+ Annonce pour l'an qui vient
+ Aux bêtes et aux gens
+ Abondance de biens.
+12/25 Noël au balcon,
+ Pâques au tison.
+12/26 À la saint Étienne,
+ Chacun trouve la sienne.
+12/28 Les jours entre Noël et les Rois
+ Indiquent le temps des douze mois.
+
+#endif /*! _fr_FR_ISO8859_1_proverbes_ */
diff --git a/misc_cmds/calendar/calendars/hr_HR.ISO8859-2/calendar.all b/misc_cmds/calendar/calendars/hr_HR.ISO8859-2/calendar.all
new file mode 100644
index 0000000..835ed47
--- /dev/null
+++ b/misc_cmds/calendar/calendars/hr_HR.ISO8859-2/calendar.all
@@ -0,0 +1,12 @@
+/*
+ * hrvatski calendar
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.all,v 1.5 2001/06/11 03:08:46 ache Exp $
+ */
+
+#ifndef _hr_HR_ISO8859_2_all
+#define _hr_HR_ISO8859_2_all
+
+#include <hr_HR.ISO8859-2/calendar.praznici>
+
+#endif /* !_hr_HR_ISO8859_2_all */
diff --git a/misc_cmds/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici b/misc_cmds/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici
new file mode 100644
index 0000000..8b9a56c
--- /dev/null
+++ b/misc_cmds/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici
@@ -0,0 +1,44 @@
+/*
+ * hrvatski praznici
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/hr_HR.ISO8859-2/calendar.praznici,v 1.8 2007/09/21 23:43:03 edwin Exp $
+ */
+
+#ifndef _hr_HR_ISO8859_2_praznici
+#define _hr_HR_ISO8859_2_praznici
+
+LANG=hr_HR.ISO8859-2
+
+/* dr¾avni praznici */
+01/01 Nova godina
+05/01 Praznik rada
+05/30 Tjelovo
+06/22 Dan antifa¹istièke borbe
+06/25 Dan dr¾avnosti
+08/05 Dan domovinske zahvalnosti
+10/08 Dan neovisnosti
+
+/* katolièki blagdani */
+01/06 Sveta tri kralja
+Easter-2 Veliki petak
+Easter Uskrs
+Easter+1 Uskrsni ponedjeljak
+Easter+49 Duhovi
+Easter+50 Duhovni ponedjeljak
+Easter+39 Uza¹a¹æe
+08/15 Velika Gospa
+11/01 Svi sveti
+12/25 Bo¾iæ
+12/26 Stjepandan
+
+/* godi¹nja doba */
+03/21* Poèetak proljeæa
+06/21* Poèetak ljeta
+09/21* Poèetak jesena
+12/21* Poèetak zime
+
+/* ljetno vrijeme */
+03/NedjeljaLast Poèetak ljetnog vremena
+10/NedjeljaLast Kraj ljetnog vremena
+
+#endif /* !_hr_HR_ISO8859_2_praznici */
diff --git a/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.all b/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.all
new file mode 100644
index 0000000..5165ab3
--- /dev/null
+++ b/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.all
@@ -0,0 +1,13 @@
+/*
+ * Magyar kalendárium
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/hu_HU.ISO8859-2/calendar.all,v 1.1 2004/08/16 09:31:09 dwmalone Exp $
+ */
+
+#ifndef _hu_HU_ISO8859_2_all_
+#define _hu_HU_ISO8859_2_all_
+
+#include <hu_HU.ISO8859-2/calendar.unnepek>
+#include <hu_HU.ISO8859-2/calendar.nevnapok>
+
+#endif /* !_hu_HU.ISO8859-2_all_ */
diff --git a/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.nevnapok b/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.nevnapok
new file mode 100644
index 0000000..14f7c57
--- /dev/null
+++ b/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.nevnapok
@@ -0,0 +1,386 @@
+/*
+ * Névnapok
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/hu_HU.ISO8859-2/calendar.nevnapok,v 1.1 2004/08/16 09:31:09 dwmalone Exp $
+ */
+
+#ifndef _hu_HU_ISO8859_2_nevnapok_
+#define _hu_HU_ISO8859_2_nevnapok_
+
+LANG=hu_HU.ISO8859-2
+
+/*
+ * N.B.: A névnapok Magyarországon a szentek napjai alapján szerepelnek
+ * a naptárban. Néhány név többször is szerepel, de mindenki
+ * csak egyszer tart névnapot egy évben. A választott nap
+ * ebben az esetben a hagyományokon és az illetõn múlik.
+ *
+ */
+
+01/01 Fruzsina
+01/02 Ábel, Gergely
+01/03 Genovéva, Benjámin
+01/04 Titusz, Leona
+01/05 Simon
+01/06 Boldizsár, Menyhárt
+01/07 Attila, Ramóna
+01/08 Gyöngyvér
+01/09 Marcell
+01/10 Melánia
+01/11 Ágota, Baltazár
+01/12 Ernõ, Cézár
+01/13 Veronika
+01/14 Bódog, Félix
+01/15 Lóránt, Loránd
+01/16 Gusztáv
+01/17 Antal, Antónia
+01/18 Piroska
+01/19 Sára, Márió
+01/20 Fábián, Sebestyén
+01/21 Ágnes
+01/22 Vince, Artúr
+01/23 Zelma, Rajmund
+01/24 Timót, Xénia
+01/25 Pál
+01/26 Vanda, Paula
+01/27 Angelika, Angéla
+01/28 Károly, Karola
+01/29 Adél
+01/30 Gerda, Martina
+01/31 Marcella
+02/01 Ignác
+02/02 Karolina, Aida
+02/03 Balázs
+02/04 Ráhel, Csenge
+02/05 Ágota, Ingrid
+02/06 Dóra, Dorottya
+02/07 Rómeó, Tódor
+02/08 Aranka
+02/09 Abigél, Alex
+02/10 Elvira
+02/11 Bertold, Marietta
+02/12 Lívia, Lídia
+02/13 Ella, Linda
+02/14 Bálint, Valentin
+02/15 Kolos
+02/16 Julianna, Lilla
+02/17 Donát
+02/18 Bernadett
+02/19 Zsuzsanna
+02/20 Aladár, Álmos
+02/21 Eleonóra
+02/22 Gerzson
+02/23 Alfréd
+02/24 Mátyás
+02/25 Géza
+02/26 Edina
+02/27 Ákos, Bátor
+02/28 Elemér
+03/01 Albin
+03/02 Lujza
+03/03 Kornélia
+03/04 Kázmér
+03/05 Adorján, Adrián
+03/06 Leonóra, Inez
+03/07 Tamás
+03/08 Zoltán
+03/09 Franciska, Fanni
+03/10 Ildikó
+03/11 Szilárd
+03/12 Gergely
+03/13 Krisztián, Ajtony
+03/14 Matild
+03/15 Kristóf
+03/16 Henrietta
+03/17 Gertrúd, Patrik
+03/18 Sándor, Ede
+03/19 József, Bánk
+03/20 Klaudia
+03/21 Benedek
+03/22 Beáta, Izolda
+03/23 Emõke
+03/24 Gábor, Karina
+03/25 Irén, Irisz
+03/26 Emánuel
+03/27 Hajnalka
+03/28 Gedeon, Johanna
+03/29 Aguszta
+03/30 Zalán
+03/31 Árpád
+04/01 Hugó
+04/02 Áron
+04/03 Buda, Richárd
+04/04 Izidor
+04/05 Vince
+04/06 Vilmos, Bíborka
+04/07 Herman
+04/08 Dénes
+04/09 Erhard
+04/10 Zsolt
+04/11 Leó, Szaniszló
+04/12 Gyula
+04/13 Ida
+04/14 Tibor
+04/15 Anasztázia, Tas
+04/16 Csongor
+04/17 Rudolf
+04/18 Andrea, Ilma
+04/19 Emma
+04/20 Tivadar
+04/21 Konrád
+04/22 Csilla, Noémi
+04/23 Béla
+04/24 György
+04/25 Márk
+04/26 Ervin
+04/27 Zita
+04/28 Valéria
+04/29 Péter
+04/30 Katalin, Kitti
+05/01 Fülöp, Jakab
+05/02 Zsigmond
+05/03 Tímea, Irma
+05/04 Mónika, Flórián
+05/05 Györgyi
+05/06 Ivett, Frida
+05/07 Gizella
+05/08 Mihály
+05/09 Gergely
+05/10 Ármin, Pálma
+05/11 Ferenc
+05/12 Pongrác
+05/13 Szervác, Imola
+05/14 Bonifác
+05/15 Zsófia, Szonja
+05/16 Mózes, Botond
+05/17 Paszkál
+05/18 Erik, Alexandra
+05/19 Ivó, Milán
+05/20 Bernát, Felícia
+05/21 Konstantin
+05/22 Júlia, Rita
+05/23 Dezsõ
+05/24 Eszter, Eliza
+05/25 Orbán
+05/26 Fülöp, Evelin
+05/27 Hella
+05/28 Emil, Csanád
+05/29 Magdolna
+05/30 Janka, Zsanett
+05/31 Angéla, Petronella
+06/01 Tünde
+06/02 Kármen, Anita
+06/03 Klotild
+06/04 Bulcsú
+06/05 Fatime
+06/06 Norbert, Cintia
+06/07 Róbert
+06/08 Medárd
+06/09 Félix
+06/10 Margit, Gitta, Gréta
+06/11 Barnabás
+06/12 Villõ
+06/13 Antal, Anett
+06/14 Vazul
+06/15 Jolán, Vid
+06/16 Jusztin
+06/17 Laura, Alida
+06/18 Arnold, Levente
+06/19 Gyárfás
+06/20 Rafael
+06/21 Alajos, Leila
+06/22 Paulina
+06/23 Zoltán, Szidonia
+06/24 Iván
+06/25 Vilmos, Viola
+06/26 János, Pál
+06/27 László
+06/28 Levente, Irén
+06/29 Péter, Pál
+06/30 Pál
+07/01 Annamária, Tihamér
+07/02 Ottó
+07/03 Kornél, Soma
+07/04 Ulrik
+07/05 Emese, Sarolta
+07/06 Csaba
+07/07 Apollónia
+07/08 Ellák
+07/09 Lukrécia
+07/10 Amália
+07/11 Nóra, Lili
+07/12 Izabella, Dalma
+07/13 Jenõ
+07/14 Örs, Stella
+07/15 Henrik, Roland
+07/16 Valter
+07/17 Endre, Elek
+07/18 Frigyes
+07/19 Emília
+07/20 Illés
+07/21 Daniella, Dániel
+07/22 Magdolna
+07/23 Lenke
+07/24 Kinga, Kincsõ
+07/25 Kristóf, Jakab
+07/26 Anna, Anikó
+07/27 Olga, Liliána
+07/28 Szabolcs
+07/29 Márta, Flóra
+07/30 Judit, Xénia
+07/31 Oszkár
+08/01 Boglárka
+08/02 Lehel
+08/03 Hermina
+08/04 Domonkos, Dominika
+08/05 Krisztina
+08/06 Berta, Bettina
+08/07 Ibolya
+08/08 László
+08/09 Emõd
+08/10 Lõrinc
+08/11 Zsuzsanna, Tiborc
+08/12 Klára
+08/13 Ipoly
+08/14 Marcell
+08/15 Mária
+08/16 Ábrahám
+08/17 Jácint
+08/18 Ilona
+08/19 Huba
+08/20 István
+08/21 Sámuel, Hajna
+08/22 Menyhért, Mirjam
+08/23 Bence
+08/24 Bertalan
+08/25 Lajos, Patrícia
+08/26 Izsó
+08/27 Gáspár
+08/28 Ágoston
+08/29 Beatrix, Erna
+08/30 Rózsa
+08/31 Erika, Bella
+09/01 Egyed, Egon
+09/02 Rebeka, Dorina
+09/03 Hilda
+09/04 Rozália
+09/05 Viktor, Lõrinc
+09/06 Zakariás
+09/07 Regina
+09/08 Mária, Adrienn
+09/09 Ádám
+09/10 Nikolett, Hunor
+09/11 Teodóra
+09/12 Mária
+09/13 Kornél
+09/14 Szeréna, Roxána
+09/15 Enikõ, Melitta
+09/16 Edit
+09/17 Zsófia
+09/18 Diána
+09/19 Vilhelmina
+09/20 Friderika
+09/21 Máté, Mirella
+09/22 Móric
+09/23 Tekla
+09/24 Gellért, Mercédesz
+09/25 Eufrozina, Kende
+09/26 Jusztina
+09/27 Adalbert
+09/28 Vencel
+09/29 Mihály
+09/30 Jeromos
+10/01 Malvin
+10/02 Petra
+10/03 Helga
+10/04 Ferenc
+10/05 Aurél
+10/06 Brúnó, Renáta
+10/07 Amália
+10/08 Koppány
+10/09 Dénes
+10/10 Gedeon
+10/11 Brigitta
+10/12 Miksa
+10/13 Kálmán, Ede
+10/14 Helén
+10/15 Teréz
+10/16 Gál
+10/17 Hedvig
+10/18 Lukács
+10/19 Nándor
+10/20 Vendel
+10/21 Orsolya
+10/22 Elõd
+10/23 Gyöngyi
+10/24 Salamon
+10/25 Blanka, Bianka
+10/26 Dömötör
+10/27 Szabina
+10/28 Simon, Szimonetta
+10/29 Nárcisz
+10/30 Alfonz
+10/31 Farkas
+11/01 Marianna
+11/02 Achilles
+11/03 Gyõzõ
+11/04 Károly
+11/05 Imre
+11/06 Lénárd
+11/07 Rezsõ
+11/08 Zsombor
+11/09 Tivadar
+11/10 Réka
+11/11 Márton
+11/12 Jónás, Renátó
+11/13 Szilvia
+11/14 Aliz
+11/15 Albert, Lipót
+11/16 Ödön
+11/17 Hortenzia, Gergõ
+11/18 Jenõ
+11/19 Erzsébet
+11/20 Jolán
+11/21 Olivér
+11/22 Cecília
+11/23 Kelemen, Klementina
+11/24 Emma
+11/25 Katalin
+11/26 Virág
+11/27 Virgil
+11/28 Stefánia
+11/29 Taksony
+11/30 András, Andor
+12/01 Elza
+12/02 Melinda, Vivien
+12/03 Ferenc, Olívia
+12/04 Borbála, Barbara
+12/05 Vilma
+12/06 Miklós
+12/07 Ambrus
+12/08 Mária
+12/09 Natália
+12/10 Judit
+12/11 Árpád
+12/12 Gabriella
+12/13 Luca, Otília
+12/14 Szilárda
+12/15 Valér
+12/16 Etelka, Aletta
+12/17 Lázár, Olimpia
+12/18 Auguszta
+12/19 Viola
+12/20 Teofil
+12/21 Tamás
+12/22 Zénó
+12/23 Viktória
+12/24 Ádám, Éva
+12/25 Eugénia
+12/26 István
+12/27 János
+12/28 Kamilla
+12/29 Tamás, Tamara
+12/30 Dávid
+12/31 Szilveszter
+
+#endif /*! _hu_HU_ISO8859_2_nevnapok_ */
diff --git a/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.unnepek b/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.unnepek
new file mode 100644
index 0000000..41e619f
--- /dev/null
+++ b/misc_cmds/calendar/calendars/hu_HU.ISO8859-2/calendar.unnepek
@@ -0,0 +1,53 @@
+/*
+ * Ünnepnapok
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/hu_HU.ISO8859-2/calendar.unnepek,v 1.1 2004/08/16 09:31:09 dwmalone Exp $
+ */
+
+#ifndef _hu_HU_ISO8859_2_unnepek_
+#define _hu_HU_ISO8859_2_unnepek_
+
+LANG=hu_HU.ISO8859-2
+
+/* Munkaszüneti napok */
+01/01 Újév
+03/15 1848-as szabadságharc és forradalom ünnepe
+05/01 Munka ünnepe
+10/23 1956-os forradalom ünnepe
+
+/* Vallási munkaszüneti napok */
+Easter Húsvét
+Easter+1 Húsvét hétfõ
+Easter+42 Virágvasárnap
+Easter+49 Pünkösd
+Easter+50 Pünkösd hétfõ
+08/20 Szent István nap, Államalapítás ünnepe
+11/01 Halottak napja
+12/25 Karácsony elsõ napja
+12/26 Karácsony második napja
+
+/* Az itt következõ dátumok nem munkaszüneti napok csak ünnepnapok */
+
+/* Csillagászati évszakok */
+03/21* Tavaszi napéjegyenlõség
+06/21* Nyári napforduló
+09/21* Õszi napéjegyenlõség
+12/21* Téli napforduló
+
+/* Téli és nyári idõszámítás közötti váltás */
+03/SundayLast Váltás a nyári idõszámításra
+10/SundayLast Váltás a téli idõszámításra
+
+/* Egyéb vallási ünnepek amelyek nem munkaszüneti napok */
+Easter-2 Nagy péntek ("a harangok Romába mennek")
+
+/* Egyéb ünnepnapok és emléknapok*/
+02/14 Valentin nap - a szerelmesek ünnepe
+03/08 Nõ nap - egy-egy szál virág a nõknek
+May Sun+2 Anyák napja
+10/06 Az 1848-as aradi vértanuk napja
+12/06 Mikulás napja - gyerekek csokit kapnak
+12/24 Karácsony elõestéje
+12/31 Szilveszter napja
+
+#endif /*! _hu_HU_ISO8859_2_unnepek_ */
diff --git a/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.all b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.all
new file mode 100644
index 0000000..fe1ad0b
--- /dev/null
+++ b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.all
@@ -0,0 +1,17 @@
+/*
+ * òÕÓÓËÉÊ ËÁÌÅÎÄÁÒØ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.all,v 1.6 2003/12/15 11:51:26 maxim Exp $
+ */
+
+#ifndef _ru_RU_KOI8_R_all
+#define _ru_RU_KOI8_R_all
+
+#include <ru_RU.KOI8-R/calendar.common>
+#include <ru_RU.KOI8-R/calendar.holiday>
+#include <ru_RU.KOI8-R/calendar.military>
+#include <ru_RU.KOI8-R/calendar.msk>
+#include <ru_RU.KOI8-R/calendar.orthodox>
+#include <ru_RU.KOI8-R/calendar.pagan>
+
+#endif /* !_ru_RU_KOI8_R_all */
diff --git a/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.common b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.common
new file mode 100644
index 0000000..82e40a5
--- /dev/null
+++ b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.common
@@ -0,0 +1,90 @@
+/*
+ * òÏÓÓÉÊÓËÉÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.common,v 1.14 2007/12/17 07:36:39 maxim Exp $
+ */
+
+#ifndef _ru_RU_KOI8_R_common_
+#define _ru_RU_KOI8_R_common_
+
+LANG=ru_RU.KOI8-R
+
+12 ÑÎ× äÅÎØ ÒÁÂÏÔÎÉËÁ ÐÒÏËÕÒÁÔÕÒÙ
+13 ÑÎ× äÅÎØ ÒÏÓÓÉÊÓËÏÊ ÐÅÞÁÔÉ
+14 ÑÎ× óÔÁÒÙÊ îÏ×ÙÊ ÇÏÄ
+21 ÑÎ× äÅÎØ ÉÎÖÅÎÅÒÎÙÈ ×ÏÊÓË
+25 ÑÎ× ôÁÔØÑÎÉÎ ÄÅÎØ. óÔÕÄÅÎÞÅÓËÉÊ ÐÒÁÚÄÎÉË
+ 8 ÆÅ× äÅÎØ ÒÏÓÓÉÊÓËÏÊ ÎÁÕËÉ
+10 ÆÅ× äÅÎØ ÄÉÐÌÏÍÁÔÉÞÅÓËÏÇÏ ÒÁÂÏÔÎÉËÁ
+ 1 ÍÁÒ ÷ÓÅÍÉÒÎÙÊ ÄÅÎØ ÇÒÁÖÄÁÎÓËÏÊ ÏÂÏÒÏÎÙ
+03/SunSecond äÅÎØ ÒÁÂÏÔÎÉËÏ× ÇÅÏÄÅÚÉÉ É ËÁÒÔÏÇÒÁÆÉÉ
+18 ÍÁÒ äÅÎØ ÎÁÌÏÇÏ×ÏÊ ÐÏÌÉÃÉÉ
+03/SunThird äÅÎØ ÒÁÂÏÔÎÉËÏ× ÔÏÒÇÏ×ÌÉ, ÂÙÔÏ×ÏÇÏ ÏÂÓÌÕÖÉ×ÁÎÉÑ ÎÁÓÅÌÅÎÉÑ É ÖÉÌÉÝÎÏ-ËÏÍÍÕÎÁÌØÎÏÇÏ ÈÏÚÑÊÓÔ×Á
+27 ÍÁÒ íÅÖÄÕÎÁÒÏÄÎÙÊ ÄÅÎØ ÔÅÁÔÒÁ
+27 ÍÁÒ äÅÎØ ×ÎÕÔÒÅÎÎÉÈ ×ÏÊÓË
+ 1 ÁÐÒ äÅÎØ ÓÍÅÈÁ
+ 2 ÁÐÒ äÅÎØ ÅÄÉÎÅÎÉÑ ÎÁÒÏÄÏ×
+04/SunFirst äÅÎØ ÇÅÏÌÏÇÁ
+12 ÁÐÒ äÅÎØ ËÏÓÍÏÎÁ×ÔÉËÉ
+04/SunSecond äÅÎØ ×ÏÊÓË ÐÒÏÔÉ×Ï×ÏÚÄÕÛÎÏÊ ÏÂÏÒÏÎÙ
+26 ÁÐÒ äÅÎØ ÐÁÍÑÔÉ ÐÏÇÉÂÛÉÈ × ÒÁÄÉÁÃÉÏÎÎÙÈ Á×ÁÒÉÑÈ É ËÁÔÁÓÔÒÏÆÁÈ
+30 ÁÐÒ äÅÎØ ÐÏÖÁÒÎÏÊ ÏÈÒÁÎÙ
+ 7 ÍÁÊ äÅÎØ ÒÁÄÉÏ
+17 ÍÁÊ íÅÖÄÕÎÁÒÏÄÎÙÊ ÄÅÎØ ÔÅÌÅËÏÍÍÕÎÉËÁÃÉÊ
+18 ÍÁÊ íÅÖÄÕÎÁÒÏÄÎÙÊ ÄÅÎØ ÍÕÚÅÅ×
+24 ÍÁÊ äÅÎØ ÓÌÁ×ÑÎÓËÏÊ ÐÉÓØÍÅÎÎÏÓÔÉ É ËÕÌØÔÕÒÙ
+27 ÍÁÊ ïÂÝÅÒÏÓÓÉÊÓËÉÊ ÄÅÎØ ÂÉÂÌÉÏÔÅË
+28 ÍÁÊ äÅÎØ ÐÏÇÒÁÎÉÞÎÉËÁ
+05/SunLast äÅÎØ ÈÉÍÉËÁ
+ 1 ÉÀÎ äÅÎØ ÚÁÝÉÔÙ ÄÅÔÅÊ
+ 6 ÉÀÎ ðÕÛËÉÎÓËÉÊ ÄÅÎØ
+ 8 ÉÀÎ äÅÎØ ÓÏÃÉÁÌØÎÏÇÏ ÒÁÂÏÔÎÉËÁ
+06/SunSecond äÅÎØ ÒÁÂÏÔÎÉËÏ× ÌÅÇËÏÊ ÐÒÏÍÙÛÌÅÎÎÏÓÔÉ
+06/SunThird äÅÎØ ÍÅÄÉÃÉÎÓËÏÇÏ ÒÁÂÏÔÎÉËÁ
+22 ÉÀÎ äÅÎØ ÐÁÍÑÔÉ É ÓËÏÒÂÉ (îÁÞÁÌÏ ÷ÅÌÉËÏÊ ïÔÅÞÅÓÔ×ÅÎÎÏÊ ÷ÏÊÎÙ, 1941 ÇÏÄ)
+27 ÉÀÎ äÅÎØ ÍÏÌÏÄÅÖÉ
+06/SatLast äÅÎØ ÉÚÏÂÒÅÔÁÔÅÌÑ É ÒÁÃÉÏÎÁÌÉÚÁÔÏÒÁ
+07/SunFirst äÅÎØ ÒÁÂÏÔÎÉËÏ× ÍÏÒÓËÏÇÏ É ÒÅÞÎÏÇÏ ÆÌÏÔÁ
+07/SunSecond äÅÎØ ÒÙÂÁËÁ
+07/SunSecond äÅÎØ ÒÏÓÓÉÊÓËÏÊ ÐÏÞÔÙ
+07/SunThird äÅÎØ ÍÅÔÁÌÌÕÒÇÁ
+07/SunLast äÅÎØ ÷ÏÅÎÎÏ-íÏÒÓËÏÇÏ æÌÏÔÁ
+ 6 Á×Ç äÅÎØ ÖÅÌÅÚÎÏÄÏÒÏÖÎÙÈ ×ÏÊÓË
+08/SunFirst äÅÎØ ÖÅÌÅÚÎÏÄÏÒÏÖÎÉËÁ
+12 Á×Ç äÅÎØ ×ÏÅÎÎÏ-×ÏÚÄÕÛÎÙÈ ÓÉÌ
+08/SunSecond äÅÎØ ÓÔÒÏÉÔÅÌÑ
+08/SunThird äÅÎØ ÷ÏÚÄÕÛÎÏÇÏ æÌÏÔÁ
+22 Á×Ç äÅÎØ ÇÏÓÕÄÁÒÓÔ×ÅÎÎÏÇÏ ÆÌÁÇÁ
+27 Á×Ç äÅÎØ ËÉÎÏ
+08/SunLast äÅÎØ ÛÁÈÔÅÒÁ
+ 1 ÓÅÎ äÅÎØ ÚÎÁÎÉÊ
+ 2 ÓÅÎ äÅÎØ ÒÏÓÓÉÊÓËÏÊ Ç×ÁÒÄÉÉ
+09/SunFirst äÅÎØ ÒÁÂÏÔÎÉËÏ× ÎÅÆÔÑÎÏÊ É ÇÁÚÏ×ÏÊ ÐÒÏÍÙÛÌÅÎÎÏÓÔÉ
+09/SunSecond äÅÎØ ÔÁÎËÉÓÔÁ
+09/SunThird äÅÎØ ÒÁÂÏÔÎÉËÏ× ÌÅÓÁ
+09/SunLast äÅÎØ ÍÁÛÉÎÏÓÔÒÏÉÔÅÌÑ
+ 1 ÏËÔ äÅÎØ ÐÏÖÉÌÙÈ ÌÀÄÅÊ
+ 4 ÏËÔ äÅÎØ ×ÏÅÎÎÏ-ËÏÓÍÉÞÅÓËÉÈ ÓÉÌ
+ 5 ÏËÔ äÅÎØ ÕÞÉÔÅÌÑ
+14 ÏËÔ íÅÖÄÕÎÁÒÏÄÎÙÊ ÄÅÎØ ÓÔÁÎÄÁÒÔÉÚÁÃÉÉ
+10/SunSecond äÅÎØ ÒÁÂÏÔÎÉËÏ× ÓÅÌØÓËÏÇÏ ÈÏÚÑÊÓÔ×Á É ÐÅÒÅÒÁÂÁÔÙ×ÁÀÝÅÊ ÐÒÏÍÙÛÌÅÎÎÏÓÔÉ
+10/SunThird äÅÎØ ÒÁÂÏÔÎÉËÏ× ÄÏÒÏÖÎÏÇÏ ÈÏÚÑÊÓÔ×Á
+24 ÏËÔ íÅÖÄÕÎÁÒÏÄÎÙÊ ÄÅÎØ ïïî
+25 ÏËÔ äÅÎØ ÔÁÍÏÖÅÎÎÉËÁ
+30 ÏËÔ äÅÎØ ÐÁÍÑÔÉ ÖÅÒÔ× ÐÏÌÉÔÉÞÅÓËÉÈ ÒÅÐÒÅÓÓÉÊ
+10/SunLast äÅÎØ ÒÁÂÏÔÎÉËÏ× Á×ÔÏÍÏÂÉÌØÎÏÇÏ ÔÒÁÎÓÐÏÒÔÁ
+ 9 ÎÏÑ ÷ÓÅÍÉÒÎÙÊ ÄÅÎØ ËÁÞÅÓÔ×Á
+10 ÎÏÑ äÅÎØ ÍÉÌÉÃÉÉ
+16 ÎÏÑ äÅÎØ ÍÏÒÓËÏÊ ÐÅÈÏÔÙ
+17 ÎÏÑ íÅÖÄÕÎÁÒÏÄÎÙÊ ÄÅÎØ ÓÔÕÄÅÎÔÏ×
+11/SunThird äÅÎØ ÒÁËÅÔÎÙÈ ×ÏÊÓË É ÁÒÔÉÌÌÅÒÉÉ
+21 ÎÏÑ äÅÎØ ÒÁÂÏÔÎÉËÏ× ÎÁÌÏÇÏ×ÙÈ ÏÒÇÁÎÏ×
+26 ÎÏÑ ÷ÓÅÍÉÒÎÙÊ ÄÅÎØ ÉÎÆÏÒÍÁÃÉÉ
+11/SunLast äÅÎØ ÍÁÔÅÒÉ
+ 1 ÄÅË ÷ÓÅÍÉÒÎÙÊ ÄÅÎØ ÂÏÒØÂÙ ÓÏ óðéäÏÍ
+17 ÄÅË äÅÎØ ÒÁËÅÔÎÙÈ ×ÏÊÓË ÓÔÒÁÔÅÇÉÞÅÓËÏÇÏ ÎÁÚÎÁÞÅÎÉÑ
+20 ÄÅË äÅÎØ ÒÁÂÏÔÎÉËÁ ÏÒÇÁÎÏ× ÂÅÚÏÐÁÓÎÏÓÔÉ
+22 ÄÅË äÅÎØ ÜÎÅÒÇÅÔÉËÁ
+27 ÄÅË äÅÎØ ÓÐÁÓÁÔÅÌÑ
+
+#endif /* !_ru_RU_KOI8_R_common_ */
diff --git a/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.holiday b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.holiday
new file mode 100644
index 0000000..bf2d6ba
--- /dev/null
+++ b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.holiday
@@ -0,0 +1,25 @@
+/*
+ * òÏÓÓÉÊÓËÉÅ ÐÒÁÚÄÎÉËÉ (ÎÅÒÁÂÏÞÉÅ "ËÒÁÓÎÙÅ" ÄÎÉ)
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.holiday,v 1.3 2005/11/02 09:22:28 maxim Exp $
+ */
+
+#ifndef _ru_RU_KOI8_R_holiday_
+#define _ru_RU_KOI8_R_holiday_
+
+LANG=ru_RU.KOI8-R
+
+ 1 ÑÎ× îÏ×ÙÊ ÇÏÄ
+ 2 ÑÎ× îÏ×ÏÇÏÄÎÉÅ ËÁÎÉËÕÌÙ
+ 3 ÑÎ× îÏ×ÏÇÏÄÎÉÅ ËÁÎÉËÕÌÙ
+ 4 ÑÎ× îÏ×ÏÇÏÄÎÉÅ ËÁÎÉËÕÌÙ
+ 5 ÑÎ× îÏ×ÏÇÏÄÎÉÅ ËÁÎÉËÕÌÙ
+ 7 ÑÎ× òÏÖÄÅÓÔ×Ï èÒÉÓÔÏ×Ï
+23 ÆÅ× äÅÎØ ÚÁÝÉÔÎÉËÁ ïÔÅÞÅÓÔ×Á
+ 8 ÍÁÒ íÅÖÄÕÎÁÒÏÄÎÙÊ ÖÅÎÓËÉÊ ÄÅÎØ
+ 1 ÍÁÊ ðÒÁÚÄÎÉË ÷ÅÓÎÙ É ôÒÕÄÁ
+ 9 ÍÁÊ äÅÎØ ðÏÂÅÄÙ
+12 ÉÀÎ äÅÎØ òÏÓÓÉÉ
+ 4 ÎÏÑ äÅÎØ ÎÁÒÏÄÎÏÇÏ ÅÄÉÎÓÔ×Á
+
+#endif /* !_ru_RU_KOI8_R_holiday_ */
diff --git a/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.military b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.military
new file mode 100644
index 0000000..f3a6f33
--- /dev/null
+++ b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.military
@@ -0,0 +1,27 @@
+/*
+ * äÎÉ ×ÏÉÎÓËÏÊ ÓÌÁ×Ù òÏÓÓÉÉ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.military,v 1.2 2003/12/26 13:04:13 maxim Exp $
+ */
+
+#ifndef _ru_RU_KOI8_R_military_
+#define _ru_RU_KOI8_R_military_
+
+LANG=ru_RU.KOI8-R
+
+27 ÑÎ× äÅÎØ ÓÎÑÔÉÑ ÂÌÏËÁÄÙ ÇÏÒÏÄÁ ìÅÎÉÎÇÒÁÄÁ (1944 ÇÏÄ)
+ 2 ÆÅ× äÅÎØ ÒÁÚÇÒÏÍÁ ÓÏ×ÅÔÓËÉÍÉ ×ÏÊÓËÁÍÉ ÎÅÍÅÃËÏ-ÆÁÛÉÓÔÓËÉÈ ×ÏÊÓË × óÔÁÌÉÎÇÒÁÄÓËÏÊ ÂÉÔ×Å (1943 ÇÏÄ)
+23 ÆÅ× äÅÎØ ÐÏÂÅÄÙ ëÒÁÓÎÏÊ áÒÍÉÉ ÎÁÄ ËÁÊÚÅÒÏ×ÓËÉÍÉ ×ÏÊÓËÁÍÉ çÅÒÍÁÎÉÉ (1918 ÇÏÄ)
+18 ÁÐÒ äÅÎØ ÐÏÂÅÄÙ ÒÕÓÓËÉÈ ×ÏÉÎÏ× ËÎÑÚÑ áÌÅËÓÁÎÄÒÁ îÅ×ÓËÏÇÏ ÎÁÄ ÎÅÍÅÃËÉÍÉ ÒÙÃÁÒÑÍÉ ÎÁ þÕÄÓËÏÍ ÏÚÅÒÅ (ìÅÄÏ×ÏÅ ÐÏÂÏÉÝÅ, 1242 ÇÏÄ)
+10 ÉÀÌ äÅÎØ ÐÏÂÅÄÙ ÒÕÓÓËÏÊ ÁÒÍÉÉ ÐÏÄ ËÏÍÁÎÄÏ×ÁÎÉÅÍ ðÅÔÒÁ ðÅÒ×ÏÇÏ ÎÁÄ Û×ÅÄÁÍÉ × ðÏÌÔÁ×ÓËÏÍ ÓÒÁÖÅÎÉÉ (1709 ÇÏÄ)
+ 9 Á×Ç äÅÎØ ÐÅÒ×ÏÊ × ÒÏÓÓÉÊÓËÏÊ ÉÓÔÏÒÉÉ ÍÏÒÓËÏÊ ÐÏÂÅÄÙ ÒÕÓÓËÏÇÏ ÆÌÏÔÁ ÐÏÄ ËÏÍÁÎÄÏ×ÁÎÉÅÍ ðÅÔÒÁ ðÅÒ×ÏÇÏ ÎÁÄ Û×ÅÄÁÍÉ Õ ÍÙÓÁ çÁÎÇÕÔ (1714 ÇÏÄ)
+23 Á×Ç äÅÎØ ÒÁÚÇÒÏÍÁ ÓÏ×ÅÔÓËÉÍÉ ×ÏÊÓËÁÍÉ ÎÅÍÅÃËÏ-ÆÁÛÉÓÔÓËÉÈ ×ÏÊÓË × ëÕÒÓËÏÊ ÂÉÔ×Å (1943 ÇÏÄ)
+ 8 ÓÅÎ äÅÎØ âÏÒÏÄÉÎÓËÏÇÏ ÓÒÁÖÅÎÉÑ ÒÕÓÓËÏÊ ÁÒÍÉÉ ÐÏÄ ËÏÍÁÎÄÏ×ÁÎÉÅÍ í.é. ëÕÔÕÚÏ×Á Ó ÆÒÁÎÃÕÚÓËÏÊ ÁÒÍÉÅÊ (1812 ÇÏÄ)
+11 ÓÅÎ äÅÎØ ÐÏÂÅÄÙ ÒÕÓÓËÏÊ ÜÓËÁÄÒÙ ÐÏÄ ËÏÍÁÎÄÏ×ÁÎÉÅÍ æ.æ. õÛÁËÏ×Á ÎÁÄ ÔÕÒÅÃËÏÊ ÜÓËÁÄÒÏÊ Õ ÍÙÓÁ ôÅÎÄÒÁ (1790 ÇÏÄ)
+21 ÓÅÎ äÅÎØ ÐÏÂÅÄÙ ÒÕÓÓËÉÈ ÐÏÌËÏ× ×Ï ÇÌÁ×Å Ó ×ÅÌÉËÉÍ ËÎÑÚÅÍ äÍÉÔÒÉÅÍ äÏÎÓËÉÍ ÎÁÄ ÍÏÎÇÏÌÏ-ÔÁÔÁÒÓËÉÍÉ ×ÏÊÓËÁÍÉ × ëÕÌÉËÏ×ÓËÏÊ ÂÉÔ×Å (1380 ÇÏÄ)
+ 7 ÎÏÑ äÅÎØ ÏÓ×ÏÂÏÖÄÅÎÉÑ íÏÓË×Ù ÓÉÌÁÍÉ ÎÁÒÏÄÎÏÇÏ ÏÐÏÌÞÅÎÉÑ ÐÏÄ ÒÕËÏ×ÏÄÓÔ×ÏÍ ëÕÚØÍÙ íÉÎÉÎÁ É äÍÉÔÒÉÑ ðÏÖÁÒÓËÏÇÏ ÏÔ ÐÏÌØÓËÉÈ ÉÎÔÅÒ×ÅÎÔÏ× (1612 ÇÏÄ)
+ 1 ÄÅË äÅÎØ ÐÏÂÅÄÙ ÒÕÓÓËÏÊ ÜÓËÁÄÒÙ ÐÏÄ ËÏÍÁÎÄÏ×ÁÎÉÅÍ ð.ó. îÁÈÉÍÏ×Á ÎÁÄ ÔÕÒÅÃËÏÊ ÜÓËÁÄÒÏÊ Õ ÍÙÓÁ óÉÎÏÐ (1853 ÇÏÄ)
+ 5 ÄÅË äÅÎØ ÎÁÞÁÌÁ ËÏÎÔÒÎÁÓÔÕÐÌÅÎÉÑ ÓÏ×ÅÔÓËÉÈ ×ÏÊÓË ÐÒÏÔÉ× ÎÅÍÅÃËÏ-ÆÁÛÉÓÔÓËÉÈ ×ÏÊÓË × ÂÉÔ×Å ÐÏÄ íÏÓË×ÏÊ (1941 ÇÏÄ)
+24 ÄÅË äÅÎØ ×ÚÑÔÉÑ ÔÕÒÅÃËÏÊ ËÒÅÐÏÓÔÉ éÚÍÁÉÌ ÒÕÓÓËÉÍÉ ×ÏÊÓËÁÍÉ ÐÏÄ ËÏÍÁÎÄÏ×ÁÎÉÅÍ á.÷. óÕ×ÏÒÏ×Á (1790 ÇÏÄ)
+
+#endif /* !_ru_RU_KOI8_R_military_ */
diff --git a/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.msk b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.msk
new file mode 100644
index 0000000..c173b65
--- /dev/null
+++ b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.msk
@@ -0,0 +1,16 @@
+/*
+ * ðÅÒÅ×ÏÄ ÞÁÓÏ× ÄÌÑ ÍÏÓËÏ×ÓËÏÊ ×ÒÅÍÅÎÎÏÊ ÚÏÎÙ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.msk,v 1.7 2006/12/29 06:44:24 ru Exp $
+ */
+
+#ifndef _ru_RU_KOI8_R_msk_
+#define _ru_RU_KOI8_R_msk_
+
+LANG=ru_RU.KOI8-R
+
+03/SunLast îÁÞÁÌÏ ÍÏÓËÏ×ÓËÏÇÏ ÌÅÔÎÅÇÏ ×ÒÅÍÅÎÉ; ÞÁÓÙ ÐÅÒÅ×ÏÄÑÔÓÑ ×ÐÅÒÅÄ
+10/SunLast ëÏÎÅà ÍÏÓËÏ×ÓËÏÇÏ ÌÅÔÎÅÇÏ ×ÒÅÍÅÎÉ; ÞÁÓÙ ÐÅÒÅ×ÏÄÑÔÓÑ ÎÁÚÁÄ
+
+#endif /* !_ru_RU_KOI8_R_msk_ */
+
diff --git a/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox
new file mode 100644
index 0000000..da2d0a7
--- /dev/null
+++ b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox
@@ -0,0 +1,34 @@
+/*
+ * ðÒÁ×ÏÓÌÁ×ÎÙÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.orthodox,v 1.5 2000/05/04 11:31:16 phantom Exp $
+ */
+
+#ifndef _ru_RU_KOI8_R_orthodox_
+#define _ru_RU_KOI8_R_orthodox_
+
+LANG=ru_RU.KOI8-R
+Paskha=ðÁÓÈÁ
+
+21 ÓÅÎ òÏÖÄÅÓÔ×Ï ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+28 ÓÅÎ ÷ÏÚÄ×ÉÖÅÎÉÅ ëÒÅÓÔÁ çÏÓÐÏÄÎÑ
+14 ÏËÔ ðÏËÒÏ× ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+ 4 ÄÅË ÷×ÅÄÅÎÉÅ ×Ï ÈÒÁÍ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+ 7 ÑÎ× òÏÖÄÅÓÔ×Ï èÒÉÓÔÏ×Ï
+19 ÑÎ× âÏÇÏÑ×ÌÅÎÉÅ ÉÌÉ ëÒÅÝÅÎÉÅ çÏÓÐÏÄÎÅ
+15 ÆÅ× óÒÅÔÅÎÉÅ çÏÓÐÏÄÎÅ
+ðÁÓÈÁ-46 ÷ÅÌÉËÉÊ ðÏÓÔ
+ðÁÓÈÁ-7 ÷ÅÒÂÎÏÅ ÷ÏÓËÒÅÓÅÎØÅ
+ðÁÓÈÁ-3 ÷ÅÌÉËÉÊ þÅÔ×ÅÒÇ
+ðÁÓÈÁ-2 óÔÒÁÓÔÎÁÑ ðÑÔÎÉÃÁ
+ðÁÓÈÁ ÷ÏÓËÒÅÓÅÎÉÅ èÒÉÓÔÏ×Ï
+ðÁÓÈÁ+39 ÷ÏÚÎÅÓÅÎÉÅ
+ðÁÓÈÁ+49 ðÑÔÉÄÅÓÑÔÎÉÃÁ
+ðÁÓÈÁ+56 ôÒÏÉÃÉÎ äÅÎØ
+ðÁÓÈÁ+60 ðÒÁÚÄÎÉË ôÅÌÁ èÒÉÓÔÏ×Á
+ 7 ÁÐÒ âÌÁÇÏ×ÅÝÅÎÉÅ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+19 Á×Ç ðÒÅÏÂÒÁÖÅÎÉÅ çÏÓÐÏÄÎÅ
+28 Á×Ç õÓÐÅÎÉÅ ðÒÅÓ×ÑÔÏÊ âÏÇÏÒÏÄÉÃÙ
+
+#endif /* !_ru_RU_KOI8_R_orthodox_ */
+
diff --git a/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.pagan b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.pagan
new file mode 100644
index 0000000..7ac2bac
--- /dev/null
+++ b/misc_cmds/calendar/calendars/ru_RU.KOI8-R/calendar.pagan
@@ -0,0 +1,42 @@
+/*
+ * ñÚÙÞÅÓËÉÅ ÐÒÁÚÄÎÉËÉ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/ru_RU.KOI8-R/calendar.pagan,v 1.7 2003/12/31 18:01:31 ache Exp $
+ */
+
+#ifndef _ru_RU_KOI8_R_pagan_
+#define _ru_RU_KOI8_R_pagan_
+
+LANG=ru_RU.KOI8-R
+Paskha=ðÁÓÈÁ
+
+21 ÄÅË* úÉÍÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ
+25 ÄÅË ëÏÌÑÄÁ (ÓÄ×ÉÎÕÔÏÅ ÚÉÍÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ)
+ 6 ÑÎ× äÅÎØ ëÁÝÅÑ É ÷ÅÌÅÓÁ
+24 ÆÅ× äÅÎØ ÷ÅÌÅÓÁ
+29 ÆÅ× äÅÎØ ëÁÝÅÑ
+ 1 ÍÁÒ äÅÎØ íÁÒÅÎÙ
+14 ÍÁÒ îÏ×ÙÊ çÏÄ, ï×ÓÅÎØ ÍÁÌÙÊ
+ðÁÓÈÁ-47 íÁÓÌÅÎÉÃÁ
+ðÁÓÈÁ+7 ëÒÁÓÎÁÑ çÏÒËÁ
+ðÁÓÈÁ+16 òÁÄÕÎÉÃÁ
+20 ÍÁÒ* ÷ÅÓÅÎÎÉÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ
+ 7 ÁÐÒ äÅÎØ íÁÒÅÎÙ (ÓÄ×ÉÎÕÔÏÅ ×ÅÓÅÎÎÅÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ)
+ 6 ÍÁÊ äÅÎØ äÁÖØÂÏÇÁ, ï×ÓÅÎØ ÂÏÌØÛÏÊ
+22 ÍÁÊ ñÒÉÌÉÎ äÅÎØ
+15 ÉÀÎ äÅÎØ ôÒÉÇÌÁ×Á
+21 ÉÀÎ* ìÅÔÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ
+ 1 ÉÀÌ òÕÓÁÌØÎÁÑ îÅÄÅÌÑ
+ 7 ÉÀÌ ëÕÐÁÌÁ (ÓÄ×ÉÎÕÔÏÅ ÌÅÔÎÅÅ ÓÏÌÎÃÅÓÔÏÑÎÉÅ)
+27 ÉÀÌ ïÔÂÏÒ ÖÅÒÔ× ðÅÒÕÎÕ, ÒÕÓÁÌÉÉ
+ 2 Á×Ç ðÅÒÕÎÏ× äÅÎØ
+21 Á×Ç äÅÎØ óÔÒÉÂÏÇÁ
+28 Á×Ç õÓÐÅÎÉÅ úÌÁÔÏÇÏÒËÉ
+14 ÓÅÎ äÅÎØ ÷ÏÌÈÁ úÍÅÅ×ÉÞÁ
+22 ÓÅÎ* ðÏ×ÏÒÏÔ Ë ÚÉÍÅ (ÏÓÅÎÎÅÅ ÒÁ×ÎÏÄÅÎÓÔ×ÉÅ)
+10 ÎÏÑ äÅÎØ íÁËÏÛÉ
+21 ÎÏÑ äÅÎØ ó×ÁÒÏÇÁ É óÅÍÁÒÇÌÁ
+ 9 ÄÅË äÅÎØ äÁÖØÂÏÇÁ É íÁÒÅÎÙ
+
+#endif /* !_ru_RU_KOI8_R_pagan_ */
+
diff --git a/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.all b/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.all
new file mode 100644
index 0000000..dc862bd
--- /dev/null
+++ b/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.all
@@ -0,0 +1,14 @@
+/*
+ * õËÒÁ§ÎÓØËÉÊ ËÁÌÅÎÄÁÒ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/uk_UA.KOI8-U/calendar.all,v 1.1 2005/10/28 21:25:28 ru Exp $
+ */
+
+#ifndef _uk_UA_KOI8_U_all_
+#define _uk_UA_KOI8_U_all_
+
+#include <uk_UA.KOI8-U/calendar.holiday>
+#include <uk_UA.KOI8-U/calendar.orthodox>
+#include <uk_UA.KOI8-U/calendar.misc>
+
+#endif /* !_uk_UA_KOI8_U_all_ */
diff --git a/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.holiday b/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.holiday
new file mode 100644
index 0000000..d127ed9
--- /dev/null
+++ b/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.holiday
@@ -0,0 +1,22 @@
+/*
+ * õËÒÁ§ÎÓØ˦ ÄÅÒÖÁ×Φ Ó×ÑÔÁ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/uk_UA.KOI8-U/calendar.holiday,v 1.1 2005/10/28 21:25:28 ru Exp $
+ */
+
+#ifndef _uk_UA_KOI8_U_holiday_
+#define _uk_UA_KOI8_U_holiday_
+
+LANG=uk_UA.KOI8-U
+Paskha=÷ÅÌÉËÄÅÎØ
+
+ó¦Þ 01 îÏ×ÉÊ ò¦Ë
+ó¦Þ 07 ò¦ÚÄ×Ï èÒÉÓÔÏ×Å
+âÅÒ 08 8 âÅÒÅÚÎÑ - í¦ÖÎÁÒÏÄÎÉÊ ö¦ÎÏÞÉÊ äÅÎØ
+ôÒÁ 01 1 ôÒÁ×ÎÑ - äÅÎØ ðÒÁæ
+ôÒÁ 09 äÅÎØ ðÅÒÅÍÏÇÉ
+÷ÅÌÉËÄÅÎØ+49 ôÒ¦ÊÃÑ
+þÅÒ 28 äÅÎØ ëÏÎÓÔÉÔÕæ§ õËÒÁ§ÎÉ
+óÅÒ 24 äÅÎØ îÅÚÁÌÅÖÎÏÓÔ¦ õËÒÁ§ÎÉ
+
+#endif /* !_uk_UA_KOI8_U_holiday_ */
diff --git a/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.misc b/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.misc
new file mode 100644
index 0000000..ec91264
--- /dev/null
+++ b/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.misc
@@ -0,0 +1,18 @@
+/*
+ * ¶ÎÛ¦ æËÁצ ÄÁÔÉ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/uk_UA.KOI8-U/calendar.misc,v 1.1 2005/10/28 21:25:28 ru Exp $
+ */
+
+#ifndef _uk_UA_KOI8_U_misc_
+#define _uk_UA_KOI8_U_misc_
+
+LANG=uk_UA.KOI8-U
+
+/* ðÏÓÔÁÎÏ×Á ëÁ¦ÎÅÔÕ í¦Î¦ÓÔÒ¦× õËÒÁ§ÎÉ ×¦Ä 13 ÔÒÁ×ÎÑ 1996 Ò. N 509
+ * "ðÒÏ ÐÏÒÑÄÏË ÏÂÞÉÓÌÅÎÎÑ ÞÁÓÕ ÎÁ ÔÅÒÉÔÏÒ¦§ õËÒÁ§ÎÉ"
+ */
+âÅÒ îÄ-1 ðÅÒÅÈ¦Ä ÎÁ ̦ÔÎ¦Ê ÞÁÓ (ÏÓÔÁÎÎÑ ÎÅĦÌÑ ÂÅÒÅÚÎÑ)
+öÏ× îÄ-1 ðÅÒÅÈ¦Ä ÎÁ ÚÉÍÏ×ÉÊ ÞÁÓ (ÏÓÔÁÎÎÑ ÎÅĦÌÑ ÖÏ×ÔÎÑ)
+
+#endif /* !_uk_UA_KOI8_U_misc_ */
diff --git a/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.orthodox b/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.orthodox
new file mode 100644
index 0000000..31f6df3
--- /dev/null
+++ b/misc_cmds/calendar/calendars/uk_UA.KOI8-U/calendar.orthodox
@@ -0,0 +1,35 @@
+/*
+ * ðÒÁ×ÏÓÌÁ×Φ Ó×ÑÔÁ
+ *
+ * $FreeBSD: src/usr.bin/calendar/calendars/uk_UA.KOI8-U/calendar.orthodox,v 1.1 2005/10/28 21:25:28 ru Exp $
+ */
+
+#ifndef _uk_UA_KOI8_U_orthodox_
+#define _uk_UA_KOI8_U_orthodox_
+
+LANG=uk_UA.KOI8-U
+Paskha=÷ÅÌÉËÄÅÎØ
+
+ 7 ó¦Þ ò¦ÚÄ×Ï èÒÉÓÔÏ×Å
+19 ó¦Þ âÏÇÏÑ×ÌÅÎÎÑ ÁÂÏ èÒÅÝÅÎÎÑ çÏÓÐÏÄΤ
+15 ìÀÔ óÔÒ¦ÔÅÎÎÑ çÏÓÐÏÄΤ
+÷ÅÌÉËÄÅÎØ-46 ÷ÅÌÉËÉÊ ð¦ÓÔ
+÷ÅÌÉËÄÅÎØ-7 ÷ÅÒÂÎÁ îÅĦÌÑ
+÷ÅÌÉËÄÅÎØ-3 ÷ÅÌÉËÉÊ þÅÔ×ÅÒ
+÷ÅÌÉËÄÅÎØ-2 óÔÒÁÓÎÁ ð'ÑÔÎÉÃÑ
+÷ÅÌÉËÄÅÎØ ÷ÏÓËÒÅÓ¦ÎÎÑ èÒÉÓÔÏ×Å
+÷ÅÌÉËÄÅÎØ+39 ÷ÏÚÎÅÓ¦ÎÎÑ çÏÓÐÏÄΤ
+÷ÅÌÉËÄÅÎØ+49 äÅÎØ ó×ÑÔϧ ôÒ¦Êæ, ð'ÑÔÉÄÅÓÑÔÎÉÃÑ
+÷ÅÌÉËÄÅÎØ+60 ó×ÑÔÏ Ô¦ÌÁ èÒÉÓÔÏ×ÏÇÏ
+ 7 ëצ âÌÁÇÏצÝÅÎÎÑ ðÒÅÓ×ÑÔϧ ä¦×É íÁÒ¦§
+ 7 ìÉÐ ò¦ÚÄ×Ï Ó×ÑÔÏÇÏ ¶×ÁÎÁ èÒÅÓÔÉÔÅÌÑ
+12 ìÉÐ ó×ÑÔÉÈ ÷ÅÒÈÏ×ÎÉÈ ÁÐÏÓÔÏÌ¦× ðÅÔÒÁ ¦ ðÁ×ÌÁ
+19 óÅÒ ðÒÅÏÂÒÁÖÅÎÎÑ çÏÓÐÏÄΤ
+28 óÅÒ õÓÐÅÎÎÑ ðÒÅÓ×ÑÔϧ âÏÇÏÒÏÄÉæ
+11 ÷ÅÒ õÓ¦ËÎÏ×ÅÎÎÑ ÞÅÓÎϧ ÇÏÌÏ×É Ó×ÑÔÏÇÏ ¶×ÁÎÁ èÒÅÓÔÉÔÅÌÑ
+21 ÷ÅÒ ò¦ÚÄ×Ï ðÒÅÓ×ÑÔϧ âÏÇÏÒÏÄÉæ
+27 ÷ÅÒ ÷ÏÚÄ×ÉÖÅÎÎÑ þÅÓÎÏÇÏ èÒÅÓÔÁ
+14 öÏ× ðÏËÒÏ×Á ðÒÅÓ×ÑÔϧ âÏÇÏÒÏÄÉæ
+ 4 çÒÕ ÷×ÅÄÅÎÎÑ ÄÏ ÈÒÁÍÕ ðÒÅÓ×ÑÔϧ âÏÇÏÒÏÄÉæ
+
+#endif /* !_uk_UA_KOI8_U_orthodox_ */
diff --git a/misc_cmds/calendar/day.c b/misc_cmds/calendar/day.c
new file mode 100644
index 0000000..f41fc2d
--- /dev/null
+++ b/misc_cmds/calendar/day.c
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/calendar/day.c,v 1.27 2007/06/09 05:54:13 grog Exp $");
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <ctype.h>
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "pathnames.h"
+#include "calendar.h"
+
+struct tm *tp;
+static const struct tm tm0;
+int *cumdays, yrdays;
+char dayname[10];
+
+
+/* 1-based month, 0-based days, cumulative */
+int daytab[][14] = {
+ { 0, -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 },
+ { 0, -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+};
+
+static char const *days[] = {
+ "sun", "mon", "tue", "wed", "thu", "fri", "sat", NULL,
+};
+
+static const char *months[] = {
+ "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec", NULL,
+};
+
+static struct fixs fndays[8]; /* full national days names */
+static struct fixs ndays[8]; /* short national days names */
+
+static struct fixs fnmonths[13]; /* full national months names */
+static struct fixs nmonths[13]; /* short national month names */
+
+
+void
+setnnames(void)
+{
+ char buf[80];
+ int i, l;
+ struct tm tm;
+
+ for (i = 0; i < 7; i++) {
+ tm.tm_wday = i;
+ strftime(buf, sizeof(buf), "%a", &tm);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (ndays[i].name != NULL)
+ free(ndays[i].name);
+ if ((ndays[i].name = strdup(buf)) == NULL)
+ errx(1, "cannot allocate memory");
+ ndays[i].len = strlen(buf);
+
+ strftime(buf, sizeof(buf), "%A", &tm);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (fndays[i].name != NULL)
+ free(fndays[i].name);
+ if ((fndays[i].name = strdup(buf)) == NULL)
+ errx(1, "cannot allocate memory");
+ fndays[i].len = strlen(buf);
+ }
+
+ for (i = 0; i < 12; i++) {
+ tm.tm_mon = i;
+ strftime(buf, sizeof(buf), "%b", &tm);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (nmonths[i].name != NULL)
+ free(nmonths[i].name);
+ if ((nmonths[i].name = strdup(buf)) == NULL)
+ errx(1, "cannot allocate memory");
+ nmonths[i].len = strlen(buf);
+
+ strftime(buf, sizeof(buf), "%B", &tm);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (fnmonths[i].name != NULL)
+ free(fnmonths[i].name);
+ if ((fnmonths[i].name = strdup(buf)) == NULL)
+ errx(1, "cannot allocate memory");
+ fnmonths[i].len = strlen(buf);
+ }
+}
+
+void
+settime(time_t now)
+{
+ char *oldl, *lbufp;
+
+ tp = localtime(&now);
+ if ( isleap(tp->tm_year + 1900) ) {
+ yrdays = 366;
+ cumdays = daytab[1];
+ } else {
+ yrdays = 365;
+ cumdays = daytab[0];
+ }
+ /* Friday displays Monday's events */
+ /* -A n ignores weekends */
+ if (f_dayAfter != 0 && Friday != -1) {
+ int weeks = f_dayAfter / 5;
+ int days = f_dayAfter % 5;
+ f_dayAfter += 2 * weeks;
+ if (days &&
+ (tp->tm_wday <= Friday) &&
+ (tp->tm_wday+days > Friday)) {
+ f_dayAfter += 2;
+ }
+ }
+ header[5].iov_base = dayname;
+
+ oldl = NULL;
+ lbufp = setlocale(LC_TIME, NULL);
+ if (lbufp != NULL && (oldl = strdup(lbufp)) == NULL)
+ errx(1, "cannot allocate memory");
+ (void) setlocale(LC_TIME, "C");
+ header[5].iov_len = strftime(dayname, sizeof(dayname), "%A", tp);
+ (void) setlocale(LC_TIME, (oldl != NULL ? oldl : ""));
+ if (oldl != NULL)
+ free(oldl);
+
+ setnnames();
+}
+
+/* convert Day[/Month][/Year] into unix time (since 1970)
+ * Day: two digits, Month: two digits, Year: digits
+ */
+time_t
+Mktime (char *dp)
+{
+ time_t t;
+ int d, m, y;
+ struct tm tm;
+
+ (void)time(&t);
+ tp = localtime(&t);
+
+ tm = tm0;
+ tm.tm_mday = tp->tm_mday;
+ tm.tm_mon = tp->tm_mon;
+ tm.tm_year = tp->tm_year;
+
+ switch (sscanf(dp, "%d.%d.%d", &d, &m, &y)) {
+ case 3:
+ if (y > 1900)
+ y -= 1900;
+ tm.tm_year = y;
+ /* FALLTHROUGH */
+ case 2:
+ tm.tm_mon = m - 1;
+ /* FALLTHROUGH */
+ case 1:
+ tm.tm_mday = d;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Mktime: %d %d %s\n", (int)mktime(&tm), (int)t,
+ asctime(&tm));
+#endif
+ return(mktime(&tm));
+}
+
+/*
+ * Possible date formats include any combination of:
+ * 3-charmonth (January, Jan, Jan)
+ * 3-charweekday (Friday, Monday, mon.)
+ * numeric month or day (1, 2, 04)
+ *
+ * Any character may separate them, or they may not be separated. Any line,
+ * following a line that is matched, that starts with "whitespace", is shown
+ * along with the matched line.
+ */
+int
+isnow(char *endp, int *monthp, int *dayp, int *varp)
+{
+ int day, flags, month = 0, v1, v2;
+
+ /*
+ * CONVENTION
+ *
+ * Month: 1-12
+ * Monthname: Jan .. Dec
+ * Day: 1-31
+ * Weekday: Mon-Sun
+ *
+ */
+
+ flags = 0;
+
+ /* read first field */
+ /* didn't recognize anything, skip it */
+ if (!(v1 = getfield(endp, &endp, &flags)))
+ return (0);
+
+ /* Easter or Easter depending days */
+ if (flags & F_EASTER)
+ day = v1 - 1; /* days since January 1 [0-365] */
+
+ /*
+ * 1. {Weekday,Day} XYZ ...
+ *
+ * where Day is > 12
+ */
+ else if (flags & F_ISDAY || v1 > 12) {
+
+ /* found a day; day: 1-31 or weekday: 1-7 */
+ day = v1;
+
+ /* {Day,Weekday} {Month,Monthname} ... */
+ /* if no recognizable month, assume just a day alone
+ * in other words, find month or use current month */
+ if (!(month = getfield(endp, &endp, &flags)))
+ month = tp->tm_mon + 1;
+ }
+
+ /* 2. {Monthname} XYZ ... */
+ else if (flags & F_ISMONTH) {
+ month = v1;
+
+ /* Monthname {day,weekday} */
+ /* if no recognizable day, assume the first day in month */
+ if (!(day = getfield(endp, &endp, &flags)))
+ day = 1;
+ }
+
+ /* Hm ... */
+ else {
+ v2 = getfield(endp, &endp, &flags);
+
+ /*
+ * {Day} {Monthname} ...
+ * where Day <= 12
+ */
+ if (flags & F_ISMONTH) {
+ day = v1;
+ month = v2;
+ *varp = 0;
+ }
+
+ /* {Month} {Weekday,Day} ... */
+ else {
+ /* F_ISDAY set, v2 > 12, or no way to tell */
+ month = v1;
+ /* if no recognizable day, assume the first */
+ day = v2 ? v2 : 1;
+ *varp = 0;
+ }
+ }
+
+ /* convert Weekday into *next* Day,
+ * e.g.: 'Sunday' -> 22
+ * 'SundayLast' -> ??
+ */
+ if (flags & F_ISDAY) {
+#ifdef DEBUG
+ fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);
+#endif
+
+ *varp = 1;
+ /* variable weekday, SundayLast, MondayFirst ... */
+ if (day < 0 || day >= 10) {
+
+ /* negative offset; last, -4 .. -1 */
+ if (day < 0) {
+ v1 = day/10 - 1; /* offset -4 ... -1 */
+ day = 10 + (day % 10); /* day 1 ... 7 */
+
+ /* day, eg '22nd' */
+ v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
+
+ /* (month length - day) / 7 + 1 */
+ if (cumdays[month+1] - cumdays[month] >= v2
+ && ((int)((cumdays[month+1] -
+ cumdays[month] - v2) / 7) + 1) == -v1)
+ /* bingo ! */
+ day = v2;
+
+ /* set to yesterday */
+ else {
+ day = tp->tm_mday - 1;
+ if (day == 0)
+ return (0);
+ }
+ }
+
+ /* first, second ... +1 ... +5 */
+ else {
+ v1 = day/10; /* offset: +1 (first Sunday) ... */
+ day = day % 10;
+
+ /* day, eg '22th' */
+ v2 = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
+
+ /* Hurrah! matched */
+ if ( ((v2 - 1 + 7) / 7) == v1 )
+ day = v2;
+
+ /* set to yesterday */
+ else {
+ day = tp->tm_mday - 1;
+ if (day == 0)
+ return (0);
+ }
+ }
+ }
+
+ /* wired */
+ else {
+ day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
+ *varp = 1;
+ }
+ }
+
+ if (!(flags & F_EASTER)) {
+ if (day + cumdays[month] > cumdays[month + 1]) { /* off end of month */
+ day -= (cumdays[month + 1] - cumdays[month]); /* adjust */
+ if (++month > 12) /* next year */
+ month = 1;
+ }
+ *monthp = month;
+ *dayp = day;
+ day = cumdays[month] + day;
+ }
+ else {
+ for (v1 = 0; day > cumdays[v1]; v1++)
+ ;
+ *monthp = v1 - 1;
+ *dayp = day - cumdays[v1 - 1];
+ *varp = 1;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "day2: day %d(%d-%d) yday %d\n", *dayp, day,
+ cumdays[month], tp->tm_yday);
+#endif
+
+ /* When days before or days after is specified */
+ /* no year rollover */
+ if (day >= tp->tm_yday - f_dayBefore &&
+ day <= tp->tm_yday + f_dayAfter)
+ return (1);
+
+ /* next year */
+ if (tp->tm_yday + f_dayAfter >= yrdays) {
+ int end = tp->tm_yday + f_dayAfter - yrdays;
+ if (day <= end)
+ return (1);
+ }
+
+ /* previous year */
+ if (tp->tm_yday - f_dayBefore < 0) {
+ int before = yrdays + (tp->tm_yday - f_dayBefore );
+ if (day >= before)
+ return (1);
+ }
+
+ return (0);
+}
+
+
+int
+getmonth(char *s)
+{
+ const char **p;
+ struct fixs *n;
+
+ for (n = fnmonths; n->name; ++n)
+ if (!strncasecmp(s, n->name, n->len))
+ return ((n - fnmonths) + 1);
+ for (n = nmonths; n->name; ++n)
+ if (!strncasecmp(s, n->name, n->len))
+ return ((n - nmonths) + 1);
+ for (p = months; *p; ++p)
+ if (!strncasecmp(s, *p, 3))
+ return ((p - months) + 1);
+ return (0);
+}
+
+
+int
+getday(char *s)
+{
+ const char **p;
+ struct fixs *n;
+
+ for (n = fndays; n->name; ++n)
+ if (!strncasecmp(s, n->name, n->len))
+ return ((n - fndays) + 1);
+ for (n = ndays; n->name; ++n)
+ if (!strncasecmp(s, n->name, n->len))
+ return ((n - ndays) + 1);
+ for (p = days; *p; ++p)
+ if (!strncasecmp(s, *p, 3))
+ return ((p - days) + 1);
+ return (0);
+}
+
+/* return offset for variable weekdays
+ * -1 -> last weekday in month
+ * +1 -> first weekday in month
+ * ... etc ...
+ */
+int
+getdayvar(char *s)
+{
+ int offs;
+
+
+ offs = strlen(s);
+
+
+ /* Sun+1 or Wednesday-2
+ * ^ ^ */
+
+ /* fprintf(stderr, "x: %s %s %d\n", s, s + offs - 2, offs); */
+ switch(*(s + offs - 2)) {
+ case '-':
+ return(-(atoi(s + offs - 1)));
+ case '+':
+ return(atoi(s + offs - 1));
+ }
+
+
+ /*
+ * some aliases: last, first, second, third, fourth
+ */
+
+ /* last */
+ if (offs > 4 && !strcasecmp(s + offs - 4, "last"))
+ return(-1);
+ else if (offs > 5 && !strcasecmp(s + offs - 5, "first"))
+ return(+1);
+ else if (offs > 6 && !strcasecmp(s + offs - 6, "second"))
+ return(+2);
+ else if (offs > 5 && !strcasecmp(s + offs - 5, "third"))
+ return(+3);
+ else if (offs > 6 && !strcasecmp(s + offs - 6, "fourth"))
+ return(+4);
+
+
+ /* no offset detected */
+ return(0);
+}
diff --git a/misc_cmds/calendar/io.c b/misc_cmds/calendar/io.c
new file mode 100644
index 0000000..6c8f4d2
--- /dev/null
+++ b/misc_cmds/calendar/io.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/calendar/io.c,v 1.24 2007/12/30 22:04:04 grog Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+#include "calendar.h"
+
+
+const char *calendarFile = "calendar"; /* default calendar file */
+const char *calendarHomes[] = { ".calendar", _PATH_INCLUDE }; /* HOME */
+const char *calendarNoMail = "nomail"; /* don't sent mail if this file exist */
+
+struct fixs neaster, npaskha;
+
+struct iovec header[] = {
+ {"From: ", 6},
+ {NULL, 0},
+ {" (Reminder Service)\nTo: ", 24},
+ {NULL, 0},
+ {"\nSubject: ", 10},
+ {NULL, 0},
+ {"'s Calendar\nPrecedence: bulk\n\n", 30},
+};
+
+
+void
+cal(void)
+{
+ int printing;
+ char *p;
+ FILE *fp;
+ int ch, l;
+ int month;
+ int day;
+ int var;
+ static int d_first = -1;
+ char buf[2048 + 1];
+ struct event *events = NULL;
+
+ if ((fp = opencal()) == NULL)
+ return;
+ for (printing = 0; fgets(buf, sizeof(buf), stdin) != NULL;) {
+ if ((p = strchr(buf, '\n')) != NULL)
+ *p = '\0';
+ else
+ while ((ch = getchar()) != '\n' && ch != EOF);
+ for (l = strlen(buf);
+ l > 0 && isspace((unsigned char)buf[l - 1]);
+ l--)
+ ;
+ buf[l] = '\0';
+ if (buf[0] == '\0')
+ continue;
+ if (strncmp(buf, "LANG=", 5) == 0) {
+ (void) setlocale(LC_ALL, buf + 5);
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ setnnames();
+ continue;
+ }
+ if (strncasecmp(buf, "Easter=", 7) == 0 && buf[7]) {
+ if (neaster.name != NULL)
+ free(neaster.name);
+ if ((neaster.name = strdup(buf + 7)) == NULL)
+ errx(1, "cannot allocate memory");
+ neaster.len = strlen(buf + 7);
+ continue;
+ }
+ if (strncasecmp(buf, "Paskha=", 7) == 0 && buf[7]) {
+ if (npaskha.name != NULL)
+ free(npaskha.name);
+ if ((npaskha.name = strdup(buf + 7)) == NULL)
+ errx(1, "cannot allocate memory");
+ npaskha.len = strlen(buf + 7);
+ continue;
+ }
+ if (buf[0] != '\t') {
+ printing = isnow(buf, &month, &day, &var) ? 1 : 0;
+ if ((p = strchr(buf, '\t')) == NULL) {
+#if DEBUG
+ fprintf(stderr, "[continue <%s>]\n", buf);
+#endif
+ continue;
+ }
+ if (p > buf && p[-1] == '*')
+ var = 1;
+ if (printing) {
+#if DEBUG
+ fprintf(stderr, "[Add event]\n");
+#endif
+ struct tm tm;
+ char dbuf[80];
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ tm.tm_sec = 0; /* unused */
+ tm.tm_min = 0; /* unused */
+ tm.tm_hour = 0; /* unused */
+ tm.tm_wday = 0; /* unused */
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_year = tp->tm_year; /* unused */
+ (void)strftime(dbuf, sizeof(dbuf),
+ d_first ? "%e %b" : "%b %e",
+ &tm);
+ events = event_add(events, month, day, dbuf, var, p);
+ }
+ }
+ else if (printing)
+ event_continue(events, buf);
+ }
+
+ event_print_all(fp, events);
+ closecal(fp);
+}
+
+/*
+ * Functions to handle buffered calendar events.
+ */
+struct event *
+event_add(struct event *events, int month, int day, char *date, int var, char *txt)
+{
+ struct event *e;
+
+ e = (struct event *)calloc(1, sizeof(struct event));
+ if (e == NULL)
+ errx(1, "event_add: cannot allocate memory");
+ e->month = month;
+ e->day = day;
+ e->var = var;
+ e->date = strdup(date);
+ if (e->date == NULL)
+ errx(1, "event_add: cannot allocate memory");
+ e->text = strdup(txt);
+ if (e->text == NULL)
+ errx(1, "event_add: cannot allocate memory");
+ e->next = events;
+
+ return e;
+}
+
+void
+event_continue(struct event *e, char *txt)
+{
+ char *text;
+
+ text = strdup(e->text);
+ if (text == NULL)
+ errx(1, "event_continue: cannot allocate memory");
+
+ free(e->text);
+ e->text = (char *)malloc(strlen(text) + strlen(txt) + 3);
+ if (e->text == NULL)
+ errx(1, "event_continue: cannot allocate memory");
+ strcpy(e->text, text);
+ strcat(e->text, "\n");
+ strcat(e->text, txt);
+ free(text);
+
+ return;
+}
+
+void
+event_print_all(FILE *fp, struct event *events)
+{
+ struct event *e, *e_next;
+ int daycount = f_dayAfter + f_dayBefore;
+ int daycounter;
+ int day, month;
+
+ for (daycounter = 0; daycounter <= daycount; daycounter++) {
+ day = tp->tm_yday - f_dayBefore + daycounter;
+ if (day < 0) day += yrdays;
+ if (day >= yrdays) day -= yrdays;
+
+ month = 1;
+ while (month <= 12) {
+ if (day <= cumdays[month])
+ break;
+ month++;
+ }
+ month--;
+ day -= cumdays[month];
+
+#ifdef DEBUG
+ fprintf(stderr,"event_print_allmonth: %d, day: %d\n",month,day);
+#endif
+
+ for (e = events; e != NULL; e = e_next ) {
+ e_next = e->next;
+
+ if (month != e->month || day != e->day)
+ continue;
+
+ (void)fprintf(fp, "%s%c%s\n", e->date,
+ e->var ? '*' : ' ', e->text);
+ }
+ }
+}
+
+int
+getfield(char *p, char **endp, int *flags)
+{
+ int val, var;
+ char *start, savech;
+
+ for (; !isdigit((unsigned char)*p) && !isalpha((unsigned char)*p)
+ && *p != '*'; ++p);
+ if (*p == '*') { /* `*' is current month */
+ *flags |= F_ISMONTH;
+ *endp = p+1;
+ return (tp->tm_mon + 1);
+ }
+ if (isdigit((unsigned char)*p)) {
+ val = strtol(p, &p, 10); /* if 0, it's failure */
+ for (; !isdigit((unsigned char)*p)
+ && !isalpha((unsigned char)*p) && *p != '*'; ++p);
+ *endp = p;
+ return (val);
+ }
+ for (start = p; isalpha((unsigned char)*++p););
+
+ /* Sunday-1 */
+ if (*p == '+' || *p == '-')
+ for(; isdigit((unsigned char)*++p););
+
+ savech = *p;
+ *p = '\0';
+
+ /* Month */
+ if ((val = getmonth(start)) != 0)
+ *flags |= F_ISMONTH;
+
+ /* Day */
+ else if ((val = getday(start)) != 0) {
+ *flags |= F_ISDAY;
+
+ /* variable weekday */
+ if ((var = getdayvar(start)) != 0) {
+ if (var <=5 && var >= -4)
+ val += var * 10;
+#ifdef DEBUG
+ printf("var: %d\n", var);
+#endif
+ }
+ }
+
+ /* Easter */
+ else if ((val = geteaster(start, tp->tm_year + 1900)) != 0)
+ *flags |= F_EASTER;
+
+ /* Paskha */
+ else if ((val = getpaskha(start, tp->tm_year + 1900)) != 0)
+ *flags |= F_EASTER;
+
+ /* undefined rest */
+ else {
+ *p = savech;
+ return (0);
+ }
+ for (*p = savech; !isdigit((unsigned char)*p)
+ && !isalpha((unsigned char)*p) && *p != '*'; ++p);
+ *endp = p;
+ return (val);
+}
+
+char path[MAXPATHLEN];
+
+FILE *
+opencal(void)
+{
+ uid_t uid;
+ size_t i;
+ int fd, found, pdes[2];
+ struct stat sbuf;
+
+ /* open up calendar file as stdin */
+ if (!freopen(calendarFile, "r", stdin)) {
+ if (doall) {
+ if (chdir(calendarHomes[0]) != 0)
+ return (NULL);
+ if (stat(calendarNoMail, &sbuf) == 0)
+ return (NULL);
+ if (!freopen(calendarFile, "r", stdin))
+ return (NULL);
+ } else {
+ char *home = getenv("HOME");
+ if (home == NULL || *home == '\0')
+ errx(1, "cannot get home directory");
+ chdir(home);
+ for (found = i = 0; i < sizeof(calendarHomes) /
+ sizeof(calendarHomes[0]); i++)
+ if (chdir(calendarHomes[i]) == 0 &&
+ freopen(calendarFile, "r", stdin)) {
+ found = 1;
+ break;
+ }
+ if (!found)
+ errx(1, "can't open calendar file \"%s\": %s (%d)",
+ calendarFile, strerror(errno), errno);
+ }
+ }
+ if (pipe(pdes) < 0)
+ return (NULL);
+ switch (fork()) {
+ case -1: /* error */
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+ return (NULL);
+ case 0:
+ /* child -- stdin already setup, set stdout to pipe input */
+ if (pdes[1] != STDOUT_FILENO) {
+ (void)dup2(pdes[1], STDOUT_FILENO);
+ (void)close(pdes[1]);
+ }
+ (void)close(pdes[0]);
+ uid = geteuid();
+ if (setuid(getuid()) < 0) {
+ warnx("first setuid failed");
+ _exit(1);
+ };
+ if (setgid(getegid()) < 0) {
+ warnx("setgid failed");
+ _exit(1);
+ }
+ if (setuid(uid) < 0) {
+ warnx("setuid failed");
+ _exit(1);
+ }
+ execl(_PATH_CPP, "cpp", "-w", "-P",
+ "-traditional", "-nostdinc", /* GCC specific opts */
+ "-I.", "-I" _PATH_INCLUDE, (char *)NULL);
+ warn(_PATH_CPP);
+ _exit(1);
+ }
+ /* parent -- set stdin to pipe output */
+ (void)dup2(pdes[0], STDIN_FILENO);
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+
+ /* not reading all calendar files, just set output to stdout */
+ if (!doall)
+ return (stdout);
+
+ /* set output to a temporary file, so if no output don't send mail */
+ (void)snprintf(path, sizeof(path), "%s/_calXXXXXX", _PATH_TMP);
+ if ((fd = mkstemp(path)) < 0)
+ return (NULL);
+ return (fdopen(fd, "w+"));
+}
+
+void
+closecal(FILE *fp)
+{
+ uid_t uid;
+ struct stat sbuf;
+ int nread, pdes[2], status;
+ char buf[1024];
+
+ if (!doall)
+ return;
+
+ (void)rewind(fp);
+ if (fstat(fileno(fp), &sbuf) || !sbuf.st_size)
+ goto done;
+ if (pipe(pdes) < 0)
+ goto done;
+ switch (fork()) {
+ case -1: /* error */
+ (void)close(pdes[0]);
+ (void)close(pdes[1]);
+ goto done;
+ case 0:
+ /* child -- set stdin to pipe output */
+ if (pdes[0] != STDIN_FILENO) {
+ (void)dup2(pdes[0], STDIN_FILENO);
+ (void)close(pdes[0]);
+ }
+ (void)close(pdes[1]);
+ uid = geteuid();
+ if (setuid(getuid()) < 0) {
+ warnx("setuid failed");
+ _exit(1);
+ };
+ if (setgid(getegid()) < 0) {
+ warnx("setgid failed");
+ _exit(1);
+ }
+ if (setuid(uid) < 0) {
+ warnx("setuid failed");
+ _exit(1);
+ }
+ execl(_PATH_SENDMAIL, "sendmail", "-i", "-t", "-F",
+ "\"Reminder Service\"", (char *)NULL);
+ warn(_PATH_SENDMAIL);
+ _exit(1);
+ }
+ /* parent -- write to pipe input */
+ (void)close(pdes[0]);
+
+ header[1].iov_base = header[3].iov_base = pw->pw_name;
+ header[1].iov_len = header[3].iov_len = strlen(pw->pw_name);
+ writev(pdes[1], header, 7);
+ while ((nread = read(fileno(fp), buf, sizeof(buf))) > 0)
+ (void)write(pdes[1], buf, nread);
+ (void)close(pdes[1]);
+done: (void)fclose(fp);
+ (void)unlink(path);
+ while (wait(&status) >= 0);
+}
diff --git a/misc_cmds/calendar/ostern.c b/misc_cmds/calendar/ostern.c
new file mode 100644
index 0000000..0f9d17e
--- /dev/null
+++ b/misc_cmds/calendar/ostern.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/calendar/ostern.c,v 1.12 2007/05/07 11:18:30 dwmalone Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "calendar.h"
+
+/* return year day for Easter */
+
+/*
+ * This code is based on the Calendar FAQ's code for how to calculate
+ * easter is. This is the Gregorian calendar version. They refer to
+ * the Algorithm of Oudin in the "Explanatory Supplement to the
+ * Astronomical Almanac".
+ */
+
+int
+easter(int year) /* 0 ... abcd, NOT since 1900 */
+{
+ int G, /* Golden number - 1 */
+ C, /* Century */
+ H, /* 23 - epact % 30 */
+ I, /* days from 21 March to Paschal full moon */
+ J, /* weekday of full moon */
+ L; /* days from 21 March to Sunday on of before full moon */
+
+ G = year % 19;
+ C = year / 100;
+ H = (C - C/4 - (8*C+13)/25 + 19*G + 15) % 30;
+ I = H - (H/28)*(1 - (H/28)*(29/(H + 1))*((21 - G)/11));
+ J = (year + year/4 + I + 2 - C + C/4) % 7;
+
+ L = I - J;
+
+ if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
+ return 31 + 29 + 21 + L + 7;
+ else
+ return 31 + 28 + 21 + L + 7;
+}
+
+/* return year day for Easter or easter depending days
+ * Match: Easter([+-][0-9]+)?
+ * e.g: Easter-2 is Good Friday (2 days before Easter)
+ */
+
+int
+geteaster(char *s, int year)
+{
+ int offset = 0;
+
+#define EASTER "easter"
+#define EASTERNAMELEN (sizeof(EASTER) - 1)
+
+ if (strncasecmp(s, EASTER, EASTERNAMELEN) == 0)
+ s += EASTERNAMELEN;
+ else if ( neaster.name != NULL
+ && strncasecmp(s, neaster.name, neaster.len) == 0
+ )
+ s += neaster.len;
+ else
+ return(0);
+
+#if DEBUG
+ printf("%s %d %d\n", s, year, EASTERNAMELEN);
+#endif
+
+ /* Easter+1 or Easter-2
+ * ^ ^ */
+
+ switch(*s) {
+
+ case '-':
+ case '+':
+ offset = atoi(s);
+ break;
+
+ default:
+ offset = 0;
+ }
+
+ return (easter(year) + offset);
+}
diff --git a/misc_cmds/calendar/paskha.c b/misc_cmds/calendar/paskha.c
new file mode 100644
index 0000000..8193fb3
--- /dev/null
+++ b/misc_cmds/calendar/paskha.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 1993-1996 by Andrey A. Chernov, Moscow, Russia.
+ * 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 ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/calendar/paskha.c,v 1.8 2007/05/07 11:18:30 dwmalone Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "calendar.h"
+
+#define PASKHA "paskha"
+#define PASKHALEN (sizeof(PASKHA) - 1)
+
+static int paskha (int);
+
+/* return year day for Orthodox Easter using Gauss formula */
+/* (old style result) */
+
+static int
+paskha(int R) /*year*/
+{
+ int a, b, c, d, e;
+ static int x = 15;
+ static int y = 6;
+
+ a = R % 19;
+ b = R % 4;
+ c = R % 7;
+ d = (19*a + x) % 30;
+ e = (2*b + 4*c + 6*d + y) % 7;
+ return (((cumdays[3] + 1) + 22) + (d + e));
+}
+
+/* return year day for Orthodox Easter depending days */
+
+int
+getpaskha(char *s, int year)
+{
+ int offset;
+
+ if (strncasecmp(s, PASKHA, PASKHALEN) == 0)
+ s += PASKHALEN;
+ else if ( npaskha.name != NULL
+ && strncasecmp(s, npaskha.name, npaskha.len) == 0
+ )
+ s += npaskha.len;
+ else
+ return 0;
+
+
+ /* Paskha+1 or Paskha-2
+ * ^ ^ */
+
+ switch(*s) {
+
+ case '-':
+ case '+':
+ offset = atoi(s);
+ break;
+
+ default:
+ offset = 0;
+ break;
+ }
+
+ return (paskha(year) + offset + 13/* new style */);
+}
diff --git a/misc_cmds/calendar/pathnames.h b/misc_cmds/calendar/pathnames.h
new file mode 100644
index 0000000..85913f5
--- /dev/null
+++ b/misc_cmds/calendar/pathnames.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/calendar/pathnames.h,v 1.4 2001/01/13 01:33:59 ache Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_CPP "/usr/bin/cpp"
+#define _PATH_INCLUDE "/usr/share/calendar"
diff --git a/misc_cmds/leave/leave.1 b/misc_cmds/leave/leave.1
new file mode 100644
index 0000000..ada7c3f
--- /dev/null
+++ b/misc_cmds/leave/leave.1
@@ -0,0 +1,100 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)leave.1 8.3 (Berkeley) 4/28/95
+.\" $FreeBSD: src/usr.bin/leave/leave.1,v 1.10 2002/12/23 16:04:51 ru Exp $
+.\"
+.Dd April 28, 1995
+.Dt LEAVE 1
+.Os
+.Sh NAME
+.Nm leave
+.Nd remind you when you have to leave
+.Sh SYNOPSIS
+.Nm
+.Op Oo Cm \&+ Oc Ns Ar hhmm
+.Sh DESCRIPTION
+The
+.Nm
+utility waits until the specified time, then reminds you that you
+have to leave.
+You are reminded 5 minutes and 1 minute before the actual
+time, at the time, and every minute thereafter.
+When you log off,
+.Nm
+exits just before it would have
+printed the next message.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Ar hhmm
+The time of day is in the form
+.Ar hhmm
+where
+.Ar hh
+is a time in
+hours (on a 12 or 24 hour clock), and
+.Ar mm
+are minutes.
+All times are converted to a 12 hour clock, and assumed to
+be in the next 12 hours.
+.It Cm \&+
+If the time is preceded by
+.Sq Cm \&+ ,
+the alarm will go off in hours and minutes
+from the current time.
+.El
+.Pp
+If no argument is given,
+.Nm
+prompts with "When do you
+have to leave?".
+A reply of newline causes
+.Nm
+to exit,
+otherwise the reply is assumed to be a time.
+This form is suitable for inclusion in a
+.Pa .login
+or
+.Pa .profile .
+.Pp
+To get rid of
+.Nm
+you should either log off or use
+.Ql kill \-s KILL
+giving its process id.
+.Sh SEE ALSO
+.Xr calendar 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/misc_cmds/leave/leave.c b/misc_cmds/leave/leave.c
new file mode 100644
index 0000000..c1db136
--- /dev/null
+++ b/misc_cmds/leave/leave.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1980, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)leave.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/leave/leave.c,v 1.12 2002/09/04 23:29:03 dwmalone Exp $");
+
+#include <err.h>
+#include <ctype.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+void doalarm(u_int);
+static void usage(void);
+
+/*
+ * leave [[+]hhmm]
+ *
+ * Reminds you when you have to leave.
+ * Leave prompts for input and goes away if you hit return.
+ * It nags you like a mother hen.
+ */
+int
+main(int argc, char **argv)
+{
+ u_int secs;
+ int hours, minutes;
+ char c, *cp = NULL;
+ struct tm *t;
+ time_t now;
+ int plusnow, t_12_hour;
+ char buf[50];
+
+ if (setlocale(LC_TIME, "") == NULL)
+ warn("setlocale");
+
+ if (argc < 2) {
+#define MSG1 "When do you have to leave? "
+ (void)write(STDOUT_FILENO, MSG1, sizeof(MSG1) - 1);
+ cp = fgets(buf, sizeof(buf), stdin);
+ if (cp == NULL || *cp == '\n')
+ exit(0);
+ } else if (argc > 2)
+ usage();
+ else
+ cp = argv[1];
+
+ if (*cp == '+') {
+ plusnow = 1;
+ ++cp;
+ } else
+ plusnow = 0;
+
+ for (hours = 0; (c = *cp) && c != '\n'; ++cp) {
+ if (!isdigit(c))
+ usage();
+ hours = hours * 10 + (c - '0');
+ }
+ minutes = hours % 100;
+ hours /= 100;
+
+ if (minutes < 0 || minutes > 59)
+ usage();
+ if (plusnow)
+ secs = hours * 60 * 60 + minutes * 60;
+ else {
+ (void)time(&now);
+ t = localtime(&now);
+
+ if (hours > 23)
+ usage();
+
+ /* Convert tol to 12 hr time (0:00...11:59) */
+ if (hours > 11)
+ hours -= 12;
+
+ /* Convert tm to 12 hr time (0:00...11:59) */
+ if (t->tm_hour > 11)
+ t_12_hour = t->tm_hour - 12;
+ else
+ t_12_hour = t->tm_hour;
+
+ if (hours < t_12_hour ||
+ (hours == t_12_hour && minutes <= t->tm_min))
+ /* Leave time is in the past so we add 12 hrs */
+ hours += 12;
+
+ secs = (hours - t_12_hour) * 60 * 60;
+ secs += (minutes - t->tm_min) * 60;
+ secs -= now % 60; /* truncate (now + secs) to min */
+ }
+ doalarm(secs);
+ exit(0);
+}
+
+void
+doalarm(u_int secs)
+{
+ int bother;
+ time_t daytime;
+ char tb[80];
+ int pid;
+
+ if ((pid = fork())) {
+ (void)time(&daytime);
+ daytime += secs;
+ strftime(tb, sizeof(tb), "%+", localtime(&daytime));
+ printf("Alarm set for %s. (pid %d)\n", tb, pid);
+ exit(0);
+ }
+ sleep((u_int)2); /* let parent print set message */
+ if (secs >= 2)
+ secs -= 2;
+
+ /*
+ * if write fails, we've lost the terminal through someone else
+ * causing a vhangup by logging in.
+ */
+#define FIVEMIN (5 * 60)
+#define MSG2 "\07\07You have to leave in 5 minutes.\n"
+ if (secs >= FIVEMIN) {
+ sleep(secs - FIVEMIN);
+ if (write(STDOUT_FILENO, MSG2, sizeof(MSG2) - 1) != sizeof(MSG2) - 1)
+ exit(0);
+ secs = FIVEMIN;
+ }
+
+#define ONEMIN (60)
+#define MSG3 "\07\07Just one more minute!\n"
+ if (secs >= ONEMIN) {
+ sleep(secs - ONEMIN);
+ if (write(STDOUT_FILENO, MSG3, sizeof(MSG3) - 1) != sizeof(MSG3) - 1)
+ exit(0);
+ }
+
+#define MSG4 "\07\07Time to leave!\n"
+ for (bother = 10; bother--;) {
+ sleep((u_int)ONEMIN);
+ if (write(STDOUT_FILENO, MSG4, sizeof(MSG4) - 1) != sizeof(MSG4) - 1)
+ exit(0);
+ }
+
+#define MSG5 "\07\07That was the last time I'll tell you. Bye.\n"
+ (void)write(STDOUT_FILENO, MSG5, sizeof(MSG5) - 1);
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: leave [[+]hhmm]\n");
+ exit(1);
+}
diff --git a/misc_cmds/misc_cmds.xcodeproj/project.pbxproj b/misc_cmds/misc_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..7d5a051
--- /dev/null
+++ b/misc_cmds/misc_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,971 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 723CE9B30FC36FAF00064057 /* Build All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 723CE9C10FC36FEB00064057 /* Build configuration list for PBXAggregateTarget "Build All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 723CE9BE0FC36FC600064057 /* PBXTargetDependency */,
+ 723CE9BC0FC36FC600064057 /* PBXTargetDependency */,
+ 723CE9BA0FC36FC600064057 /* PBXTargetDependency */,
+ 723CE9B80FC36FC600064057 /* PBXTargetDependency */,
+ 53D2642B112DD86900FFBD9F /* PBXTargetDependency */,
+ 723CE9B60FC36FC600064057 /* PBXTargetDependency */,
+ );
+ name = "Build All";
+ productName = "Build All";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 3E59B92E1D4939A700D3128C /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E59B92D1D4939A700D3128C /* libncurses.dylib */; };
+ 3E59B92F1D4939B000D3128C /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E59B92D1D4939A700D3128C /* libncurses.dylib */; };
+ 53D2641F112DD84700FFBD9F /* calendar.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE9040FC34BFF00064057 /* calendar.c */; };
+ 53D26420112DD84700FFBD9F /* easter.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE9060FC34BFF00064057 /* easter.c */; };
+ 53D26421112DD84700FFBD9F /* ncal.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE9080FC34BFF00064057 /* ncal.c */; settings = {COMPILER_FLAGS = "-I$(SRCROOT)/ncal"; }; };
+ 723CE8750FC3450300064057 /* leave.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE8590FC3436900064057 /* leave.c */; settings = {COMPILER_FLAGS = "-D__FBSDID=__RCSID -include stdint.h -Du_int=uint32_t"; }; };
+ 723CE8870FC3453000064057 /* leave.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 723CE8580FC3436900064057 /* leave.1 */; };
+ 723CE8B90FC3478800064057 /* tsort.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE89D0FC346BA00064057 /* tsort.c */; };
+ 723CE8BB0FC347A300064057 /* tsort.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 723CE89C0FC346BA00064057 /* tsort.1 */; };
+ 723CE8D20FC3488100064057 /* units.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE8CA0FC3486000064057 /* units.c */; };
+ 723CE8D60FC348D700064057 /* units.1 in Copy manpage */ = {isa = PBXBuildFile; fileRef = 723CE8CB0FC3486D00064057 /* units.1 */; };
+ 723CE8EB0FC34A0B00064057 /* units.lib in Copy Unit Files */ = {isa = PBXBuildFile; fileRef = 723CE8E90FC349ED00064057 /* units.lib */; };
+ 723CE90C0FC34C1A00064057 /* calendar.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE9040FC34BFF00064057 /* calendar.c */; };
+ 723CE90E0FC34C1A00064057 /* easter.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE9060FC34BFF00064057 /* easter.c */; };
+ 723CE90F0FC34C1A00064057 /* ncal.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE9080FC34BFF00064057 /* ncal.c */; settings = {COMPILER_FLAGS = "-I$(SRCROOT)/ncal"; }; };
+ 723CE9130FC34C5400064057 /* ncal.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 723CE9070FC34BFF00064057 /* ncal.1 */; };
+ 723CE9600FC350FF00064057 /* calendar.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE9590FC350FF00064057 /* calendar.c */; };
+ 723CE9610FC350FF00064057 /* day.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE95B0FC350FF00064057 /* day.c */; };
+ 723CE9620FC350FF00064057 /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE95C0FC350FF00064057 /* io.c */; };
+ 723CE9630FC350FF00064057 /* ostern.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE95D0FC350FF00064057 /* ostern.c */; };
+ 723CE9640FC350FF00064057 /* paskha.c in Sources */ = {isa = PBXBuildFile; fileRef = 723CE95E0FC350FF00064057 /* paskha.c */; };
+ 723CE9C70FC3792900064057 /* calendar.1 in Copy manpage */ = {isa = PBXBuildFile; fileRef = 723CE9C30FC378FD00064057 /* calendar.1 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 53D2642A112DD86900FFBD9F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 723CE84B0FC342D200064057 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 53D2641D112DD84700FFBD9F;
+ remoteInfo = cal;
+ };
+ 723CE9B50FC36FC600064057 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 723CE84B0FC342D200064057 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723CE94A0FC3505500064057;
+ remoteInfo = calendar;
+ };
+ 723CE9B70FC36FC600064057 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 723CE84B0FC342D200064057 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723CE8F20FC34BD300064057;
+ remoteInfo = ncal;
+ };
+ 723CE9B90FC36FC600064057 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 723CE84B0FC342D200064057 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723CE8CE0FC3487200064057;
+ remoteInfo = units;
+ };
+ 723CE9BB0FC36FC600064057 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 723CE84B0FC342D200064057 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723CE8B40FC3476900064057;
+ remoteInfo = tsort;
+ };
+ 723CE9BD0FC36FC600064057 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 723CE84B0FC342D200064057 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723CE85C0FC3437B00064057;
+ remoteInfo = leave;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 723CE8880FC3454E00064057 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 723CE8870FC3453000064057 /* leave.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 723CE8C20FC347C600064057 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 723CE8BB0FC347A300064057 /* tsort.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 723CE8D40FC348B200064057 /* Copy manpage */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 723CE8D60FC348D700064057 /* units.1 in Copy manpage */,
+ );
+ name = "Copy manpage";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 723CE8E20FC3496B00064057 /* Copy Unit Files */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/misc/;
+ dstSubfolderSpec = 0;
+ files = (
+ 723CE8EB0FC34A0B00064057 /* units.lib in Copy Unit Files */,
+ );
+ name = "Copy Unit Files";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 723CE91D0FC34C9600064057 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 723CE9130FC34C5400064057 /* ncal.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 723CE9DA0FC379A200064057 /* Copy manpage */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 723CE9C70FC3792900064057 /* calendar.1 in Copy manpage */,
+ );
+ name = "Copy manpage";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 3E59B92D1D4939A700D3128C /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = usr/lib/libncurses.dylib; sourceTree = SDKROOT; };
+ 53D26428112DD84700FFBD9F /* cal */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cal; sourceTree = BUILT_PRODUCTS_DIR; };
+ 723CE8580FC3436900064057 /* leave.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = leave.1; sourceTree = "<group>"; };
+ 723CE8590FC3436900064057 /* leave.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = leave.c; sourceTree = "<group>"; };
+ 723CE85D0FC3437B00064057 /* leave */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = leave; sourceTree = BUILT_PRODUCTS_DIR; };
+ 723CE89C0FC346BA00064057 /* tsort.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = tsort.1; sourceTree = "<group>"; };
+ 723CE89D0FC346BA00064057 /* tsort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tsort.c; sourceTree = "<group>"; };
+ 723CE8B50FC3476900064057 /* tsort */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tsort; sourceTree = BUILT_PRODUCTS_DIR; };
+ 723CE8CA0FC3486000064057 /* units.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = units.c; sourceTree = "<group>"; };
+ 723CE8CB0FC3486D00064057 /* units.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = units.1; sourceTree = "<group>"; };
+ 723CE8CF0FC3487200064057 /* units */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = units; sourceTree = BUILT_PRODUCTS_DIR; };
+ 723CE8DD0FC3491B00064057 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ 723CE8E90FC349ED00064057 /* units.lib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = units.lib; sourceTree = "<group>"; };
+ 723CE8EA0FC34A0600064057 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ 723CE8F30FC34BD300064057 /* ncal */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ncal; sourceTree = BUILT_PRODUCTS_DIR; };
+ 723CE9040FC34BFF00064057 /* calendar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = calendar.c; sourceTree = "<group>"; };
+ 723CE9050FC34BFF00064057 /* calendar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = calendar.h; sourceTree = "<group>"; };
+ 723CE9060FC34BFF00064057 /* easter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = easter.c; sourceTree = "<group>"; };
+ 723CE9070FC34BFF00064057 /* ncal.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ncal.1; sourceTree = "<group>"; };
+ 723CE9080FC34BFF00064057 /* ncal.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ncal.c; sourceTree = "<group>"; };
+ 723CE94B0FC3505500064057 /* calendar */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = calendar; sourceTree = BUILT_PRODUCTS_DIR; };
+ 723CE9590FC350FF00064057 /* calendar.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = calendar.c; sourceTree = "<group>"; };
+ 723CE95A0FC350FF00064057 /* calendar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = calendar.h; sourceTree = "<group>"; };
+ 723CE95B0FC350FF00064057 /* day.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = day.c; sourceTree = "<group>"; };
+ 723CE95C0FC350FF00064057 /* io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = io.c; sourceTree = "<group>"; };
+ 723CE95D0FC350FF00064057 /* ostern.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ostern.c; sourceTree = "<group>"; };
+ 723CE95E0FC350FF00064057 /* paskha.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = paskha.c; sourceTree = "<group>"; };
+ 723CE95F0FC350FF00064057 /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ 723CE96A0FC36C6400064057 /* calendar.all */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.all; sourceTree = "<group>"; };
+ 723CE96B0FC36C6400064057 /* calendar.australia */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.australia; sourceTree = "<group>"; };
+ 723CE96C0FC36C6400064057 /* calendar.birthday */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.birthday; sourceTree = "<group>"; };
+ 723CE96D0FC36C6400064057 /* calendar.christian */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.christian; sourceTree = "<group>"; };
+ 723CE96E0FC36C6400064057 /* calendar.computer */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.computer; sourceTree = "<group>"; };
+ 723CE96F0FC36C6400064057 /* calendar.croatian */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.croatian; sourceTree = "<group>"; };
+ 723CE9700FC36C6400064057 /* calendar.dutch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.dutch; sourceTree = "<group>"; };
+ 723CE9710FC36C6400064057 /* calendar.freebsd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.freebsd; sourceTree = "<group>"; };
+ 723CE9720FC36C6400064057 /* calendar.french */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.french; sourceTree = "<group>"; };
+ 723CE9730FC36C6400064057 /* calendar.german */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.german; sourceTree = "<group>"; };
+ 723CE9740FC36C6400064057 /* calendar.history */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.history; sourceTree = "<group>"; };
+ 723CE9750FC36C6400064057 /* calendar.holiday */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.holiday; sourceTree = "<group>"; };
+ 723CE9760FC36C6400064057 /* calendar.hungarian */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.hungarian; sourceTree = "<group>"; };
+ 723CE9770FC36C6400064057 /* calendar.judaic */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.judaic; sourceTree = "<group>"; };
+ 723CE9780FC36C6400064057 /* calendar.lotr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.lotr; sourceTree = "<group>"; };
+ 723CE9790FC36C6400064057 /* calendar.music */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.music; sourceTree = "<group>"; };
+ 723CE97A0FC36C6400064057 /* calendar.newzealand */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.newzealand; sourceTree = "<group>"; };
+ 723CE97B0FC36C6400064057 /* calendar.russian */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.russian; sourceTree = "<group>"; };
+ 723CE97C0FC36C6400064057 /* calendar.southafrica */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.southafrica; sourceTree = "<group>"; };
+ 723CE97D0FC36C6400064057 /* calendar.ukrainian */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.ukrainian; sourceTree = "<group>"; };
+ 723CE97E0FC36C6400064057 /* calendar.usholiday */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.usholiday; sourceTree = "<group>"; };
+ 723CE97F0FC36C6400064057 /* calendar.world */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.world; sourceTree = "<group>"; };
+ 723CE9810FC36C6400064057 /* calendar.feiertag */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.feiertag; sourceTree = "<group>"; };
+ 723CE9830FC36C6400064057 /* calendar.all */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.all; sourceTree = "<group>"; };
+ 723CE9840FC36C6400064057 /* calendar.feiertag */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.feiertag; sourceTree = "<group>"; };
+ 723CE9850FC36C6400064057 /* calendar.geschichte */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.geschichte; sourceTree = "<group>"; };
+ 723CE9860FC36C6400064057 /* calendar.kirche */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.kirche; sourceTree = "<group>"; };
+ 723CE9870FC36C6400064057 /* calendar.literatur */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.literatur; sourceTree = "<group>"; };
+ 723CE9880FC36C6400064057 /* calendar.musik */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.musik; sourceTree = "<group>"; };
+ 723CE9890FC36C6400064057 /* calendar.wissenschaft */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.wissenschaft; sourceTree = "<group>"; };
+ 723CE98B0FC36C6400064057 /* calendar.all */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.all; sourceTree = "<group>"; };
+ 723CE98C0FC36C6400064057 /* calendar.fetes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.fetes; sourceTree = "<group>"; };
+ 723CE98D0FC36C6400064057 /* calendar.french */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.french; sourceTree = "<group>"; };
+ 723CE98E0FC36C6400064057 /* calendar.jferies */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.jferies; sourceTree = "<group>"; };
+ 723CE98F0FC36C6400064057 /* calendar.proverbes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.proverbes; sourceTree = "<group>"; };
+ 723CE9910FC36C6400064057 /* calendar.all */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.all; sourceTree = "<group>"; };
+ 723CE9920FC36C6400064057 /* calendar.praznici */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.praznici; sourceTree = "<group>"; };
+ 723CE9940FC36C6400064057 /* calendar.all */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.all; sourceTree = "<group>"; };
+ 723CE9950FC36C6400064057 /* calendar.nevnapok */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.nevnapok; sourceTree = "<group>"; };
+ 723CE9960FC36C6400064057 /* calendar.unnepek */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.unnepek; sourceTree = "<group>"; };
+ 723CE9980FC36C6400064057 /* calendar.all */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.all; sourceTree = "<group>"; };
+ 723CE9990FC36C6400064057 /* calendar.common */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.common; sourceTree = "<group>"; };
+ 723CE99A0FC36C6400064057 /* calendar.holiday */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.holiday; sourceTree = "<group>"; };
+ 723CE99B0FC36C6400064057 /* calendar.military */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.military; sourceTree = "<group>"; };
+ 723CE99C0FC36C6400064057 /* calendar.msk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.msk; sourceTree = "<group>"; };
+ 723CE99D0FC36C6400064057 /* calendar.orthodox */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.orthodox; sourceTree = "<group>"; };
+ 723CE99E0FC36C6400064057 /* calendar.pagan */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.pagan; sourceTree = "<group>"; };
+ 723CE9A00FC36C6400064057 /* calendar.all */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.all; sourceTree = "<group>"; };
+ 723CE9A10FC36C6400064057 /* calendar.holiday */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.holiday; sourceTree = "<group>"; };
+ 723CE9A20FC36C6400064057 /* calendar.misc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.misc; sourceTree = "<group>"; };
+ 723CE9A30FC36C6400064057 /* calendar.orthodox */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = calendar.orthodox; sourceTree = "<group>"; };
+ 723CE9C30FC378FD00064057 /* calendar.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = calendar.1; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 53D26422112DD84700FFBD9F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3E59B92E1D4939A700D3128C /* libncurses.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE85B0FC3437B00064057 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE8B30FC3476900064057 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE8CD0FC3487200064057 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE8F10FC34BD300064057 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 3E59B92F1D4939B000D3128C /* libncurses.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE9490FC3505500064057 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 3E59B92C1D4939A700D3128C /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 3E59B92D1D4939A700D3128C /* libncurses.dylib */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 723CE8490FC342D200064057 = {
+ isa = PBXGroup;
+ children = (
+ 723CE8530FC3432200064057 /* Source */,
+ 723CE85E0FC3437B00064057 /* Products */,
+ 3E59B92C1D4939A700D3128C /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 723CE8530FC3432200064057 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE94F0FC3509E00064057 /* calendar */,
+ 723CE8F60FC34BE400064057 /* ncal */,
+ 723CE8C30FC3481100064057 /* units */,
+ 723CE8540FC3432D00064057 /* leave */,
+ 723CE8970FC3469A00064057 /* tsort */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 723CE8540FC3432D00064057 /* leave */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE8580FC3436900064057 /* leave.1 */,
+ 723CE8590FC3436900064057 /* leave.c */,
+ );
+ path = leave;
+ sourceTree = "<group>";
+ };
+ 723CE85E0FC3437B00064057 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE85D0FC3437B00064057 /* leave */,
+ 723CE8B50FC3476900064057 /* tsort */,
+ 723CE8CF0FC3487200064057 /* units */,
+ 723CE8F30FC34BD300064057 /* ncal */,
+ 723CE94B0FC3505500064057 /* calendar */,
+ 53D26428112DD84700FFBD9F /* cal */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 723CE8970FC3469A00064057 /* tsort */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE89C0FC346BA00064057 /* tsort.1 */,
+ 723CE89D0FC346BA00064057 /* tsort.c */,
+ );
+ path = tsort;
+ sourceTree = "<group>";
+ };
+ 723CE8C30FC3481100064057 /* units */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE8EA0FC34A0600064057 /* README */,
+ 723CE8E90FC349ED00064057 /* units.lib */,
+ 723CE8DD0FC3491B00064057 /* pathnames.h */,
+ 723CE8CA0FC3486000064057 /* units.c */,
+ 723CE8CB0FC3486D00064057 /* units.1 */,
+ );
+ path = units;
+ sourceTree = "<group>";
+ };
+ 723CE8F60FC34BE400064057 /* ncal */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE9040FC34BFF00064057 /* calendar.c */,
+ 723CE9050FC34BFF00064057 /* calendar.h */,
+ 723CE9060FC34BFF00064057 /* easter.c */,
+ 723CE9070FC34BFF00064057 /* ncal.1 */,
+ 723CE9080FC34BFF00064057 /* ncal.c */,
+ );
+ path = ncal;
+ sourceTree = "<group>";
+ };
+ 723CE94F0FC3509E00064057 /* calendar */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE9C30FC378FD00064057 /* calendar.1 */,
+ 723CE9690FC36C6400064057 /* calendars */,
+ 723CE9590FC350FF00064057 /* calendar.c */,
+ 723CE95A0FC350FF00064057 /* calendar.h */,
+ 723CE95B0FC350FF00064057 /* day.c */,
+ 723CE95C0FC350FF00064057 /* io.c */,
+ 723CE95D0FC350FF00064057 /* ostern.c */,
+ 723CE95E0FC350FF00064057 /* paskha.c */,
+ 723CE95F0FC350FF00064057 /* pathnames.h */,
+ );
+ path = calendar;
+ sourceTree = "<group>";
+ };
+ 723CE9690FC36C6400064057 /* calendars */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE96A0FC36C6400064057 /* calendar.all */,
+ 723CE96B0FC36C6400064057 /* calendar.australia */,
+ 723CE96C0FC36C6400064057 /* calendar.birthday */,
+ 723CE96D0FC36C6400064057 /* calendar.christian */,
+ 723CE96E0FC36C6400064057 /* calendar.computer */,
+ 723CE96F0FC36C6400064057 /* calendar.croatian */,
+ 723CE9700FC36C6400064057 /* calendar.dutch */,
+ 723CE9710FC36C6400064057 /* calendar.freebsd */,
+ 723CE9720FC36C6400064057 /* calendar.french */,
+ 723CE9730FC36C6400064057 /* calendar.german */,
+ 723CE9740FC36C6400064057 /* calendar.history */,
+ 723CE9750FC36C6400064057 /* calendar.holiday */,
+ 723CE9760FC36C6400064057 /* calendar.hungarian */,
+ 723CE9770FC36C6400064057 /* calendar.judaic */,
+ 723CE9780FC36C6400064057 /* calendar.lotr */,
+ 723CE9790FC36C6400064057 /* calendar.music */,
+ 723CE97A0FC36C6400064057 /* calendar.newzealand */,
+ 723CE97B0FC36C6400064057 /* calendar.russian */,
+ 723CE97C0FC36C6400064057 /* calendar.southafrica */,
+ 723CE97D0FC36C6400064057 /* calendar.ukrainian */,
+ 723CE97E0FC36C6400064057 /* calendar.usholiday */,
+ 723CE97F0FC36C6400064057 /* calendar.world */,
+ 723CE9800FC36C6400064057 /* de_AT.ISO_8859-15 */,
+ 723CE9820FC36C6400064057 /* de_DE.ISO8859-1 */,
+ 723CE98A0FC36C6400064057 /* fr_FR.ISO8859-1 */,
+ 723CE9900FC36C6400064057 /* hr_HR.ISO8859-2 */,
+ 723CE9930FC36C6400064057 /* hu_HU.ISO8859-2 */,
+ 723CE9970FC36C6400064057 /* ru_RU.KOI8-R */,
+ 723CE99F0FC36C6400064057 /* uk_UA.KOI8-U */,
+ );
+ path = calendars;
+ sourceTree = "<group>";
+ };
+ 723CE9800FC36C6400064057 /* de_AT.ISO_8859-15 */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE9810FC36C6400064057 /* calendar.feiertag */,
+ );
+ path = "de_AT.ISO_8859-15";
+ sourceTree = "<group>";
+ };
+ 723CE9820FC36C6400064057 /* de_DE.ISO8859-1 */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE9830FC36C6400064057 /* calendar.all */,
+ 723CE9840FC36C6400064057 /* calendar.feiertag */,
+ 723CE9850FC36C6400064057 /* calendar.geschichte */,
+ 723CE9860FC36C6400064057 /* calendar.kirche */,
+ 723CE9870FC36C6400064057 /* calendar.literatur */,
+ 723CE9880FC36C6400064057 /* calendar.musik */,
+ 723CE9890FC36C6400064057 /* calendar.wissenschaft */,
+ );
+ path = "de_DE.ISO8859-1";
+ sourceTree = "<group>";
+ };
+ 723CE98A0FC36C6400064057 /* fr_FR.ISO8859-1 */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE98B0FC36C6400064057 /* calendar.all */,
+ 723CE98C0FC36C6400064057 /* calendar.fetes */,
+ 723CE98D0FC36C6400064057 /* calendar.french */,
+ 723CE98E0FC36C6400064057 /* calendar.jferies */,
+ 723CE98F0FC36C6400064057 /* calendar.proverbes */,
+ );
+ path = "fr_FR.ISO8859-1";
+ sourceTree = "<group>";
+ };
+ 723CE9900FC36C6400064057 /* hr_HR.ISO8859-2 */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE9910FC36C6400064057 /* calendar.all */,
+ 723CE9920FC36C6400064057 /* calendar.praznici */,
+ );
+ path = "hr_HR.ISO8859-2";
+ sourceTree = "<group>";
+ };
+ 723CE9930FC36C6400064057 /* hu_HU.ISO8859-2 */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE9940FC36C6400064057 /* calendar.all */,
+ 723CE9950FC36C6400064057 /* calendar.nevnapok */,
+ 723CE9960FC36C6400064057 /* calendar.unnepek */,
+ );
+ path = "hu_HU.ISO8859-2";
+ sourceTree = "<group>";
+ };
+ 723CE9970FC36C6400064057 /* ru_RU.KOI8-R */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE9980FC36C6400064057 /* calendar.all */,
+ 723CE9990FC36C6400064057 /* calendar.common */,
+ 723CE99A0FC36C6400064057 /* calendar.holiday */,
+ 723CE99B0FC36C6400064057 /* calendar.military */,
+ 723CE99C0FC36C6400064057 /* calendar.msk */,
+ 723CE99D0FC36C6400064057 /* calendar.orthodox */,
+ 723CE99E0FC36C6400064057 /* calendar.pagan */,
+ );
+ path = "ru_RU.KOI8-R";
+ sourceTree = "<group>";
+ };
+ 723CE99F0FC36C6400064057 /* uk_UA.KOI8-U */ = {
+ isa = PBXGroup;
+ children = (
+ 723CE9A00FC36C6400064057 /* calendar.all */,
+ 723CE9A10FC36C6400064057 /* calendar.holiday */,
+ 723CE9A20FC36C6400064057 /* calendar.misc */,
+ 723CE9A30FC36C6400064057 /* calendar.orthodox */,
+ );
+ path = "uk_UA.KOI8-U";
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 53D2641D112DD84700FFBD9F /* cal */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 53D26426112DD84700FFBD9F /* Build configuration list for PBXNativeTarget "cal" */;
+ buildPhases = (
+ 53D2641E112DD84700FFBD9F /* Sources */,
+ 53D26422112DD84700FFBD9F /* Frameworks */,
+ 53D26425112DD84700FFBD9F /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cal;
+ productName = ncal;
+ productReference = 53D26428112DD84700FFBD9F /* cal */;
+ productType = "com.apple.product-type.tool";
+ };
+ 723CE85C0FC3437B00064057 /* leave */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 723CE8620FC3437C00064057 /* Build configuration list for PBXNativeTarget "leave" */;
+ buildPhases = (
+ 723CE85A0FC3437B00064057 /* Sources */,
+ 723CE85B0FC3437B00064057 /* Frameworks */,
+ 723CE8880FC3454E00064057 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = leave;
+ productName = leave;
+ productReference = 723CE85D0FC3437B00064057 /* leave */;
+ productType = "com.apple.product-type.tool";
+ };
+ 723CE8B40FC3476900064057 /* tsort */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 723CE8B80FC3478800064057 /* Build configuration list for PBXNativeTarget "tsort" */;
+ buildPhases = (
+ 723CE8B20FC3476900064057 /* Sources */,
+ 723CE8B30FC3476900064057 /* Frameworks */,
+ 723CE8C20FC347C600064057 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tsort;
+ productName = tsort;
+ productReference = 723CE8B50FC3476900064057 /* tsort */;
+ productType = "com.apple.product-type.tool";
+ };
+ 723CE8CE0FC3487200064057 /* units */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 723CE8D50FC348B200064057 /* Build configuration list for PBXNativeTarget "units" */;
+ buildPhases = (
+ 723CE8CC0FC3487200064057 /* Sources */,
+ 723CE8CD0FC3487200064057 /* Frameworks */,
+ 723CE8D40FC348B200064057 /* Copy manpage */,
+ 723CE8E20FC3496B00064057 /* Copy Unit Files */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = units;
+ productName = units;
+ productReference = 723CE8CF0FC3487200064057 /* units */;
+ productType = "com.apple.product-type.tool";
+ };
+ 723CE8F20FC34BD300064057 /* ncal */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 723CE8F70FC34BE400064057 /* Build configuration list for PBXNativeTarget "ncal" */;
+ buildPhases = (
+ 723CE8F00FC34BD300064057 /* Sources */,
+ 723CE8F10FC34BD300064057 /* Frameworks */,
+ 723CE91D0FC34C9600064057 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ncal;
+ productName = ncal;
+ productReference = 723CE8F30FC34BD300064057 /* ncal */;
+ productType = "com.apple.product-type.tool";
+ };
+ 723CE94A0FC3505500064057 /* calendar */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 723CE94E0FC3507300064057 /* Build configuration list for PBXNativeTarget "calendar" */;
+ buildPhases = (
+ 723CE9480FC3505500064057 /* Sources */,
+ 723CE9490FC3505500064057 /* Frameworks */,
+ 723CE9DA0FC379A200064057 /* Copy manpage */,
+ 72FA601A0FC497B500E6462C /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = calendar;
+ productName = calendar;
+ productReference = 723CE94B0FC3505500064057 /* calendar */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 723CE84B0FC342D200064057 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ };
+ buildConfigurationList = 723CE84E0FC342D200064057 /* Build configuration list for PBXProject "misc_cmds" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = 723CE8490FC342D200064057;
+ productRefGroup = 723CE85E0FC3437B00064057 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 723CE9B30FC36FAF00064057 /* Build All */,
+ 723CE85C0FC3437B00064057 /* leave */,
+ 723CE8B40FC3476900064057 /* tsort */,
+ 723CE8CE0FC3487200064057 /* units */,
+ 723CE8F20FC34BD300064057 /* ncal */,
+ 723CE94A0FC3505500064057 /* calendar */,
+ 53D2641D112DD84700FFBD9F /* cal */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 53D26425112DD84700FFBD9F /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cp $DSTROOT/usr/share/man/man1/ncal.1 $DSTROOT/usr/share/man/man1/cal.1";
+ };
+ 72FA601A0FC497B500E6462C /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/bash;
+ shellScript = "mkdir -p $DSTROOT/usr/share/calendar\ncp -R $SRCROOT/calendar/calendars/ $DSTROOT/usr/share/calendar/\nmkdir -p $DSTROOT/usr/share/calendar/de_DE.ISO8859-15\nmkdir -p $DSTROOT/usr/share/calendar/fr_FR.ISO8859-15";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 53D2641E112DD84700FFBD9F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 53D2641F112DD84700FFBD9F /* calendar.c in Sources */,
+ 53D26420112DD84700FFBD9F /* easter.c in Sources */,
+ 53D26421112DD84700FFBD9F /* ncal.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE85A0FC3437B00064057 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 723CE8750FC3450300064057 /* leave.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE8B20FC3476900064057 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 723CE8B90FC3478800064057 /* tsort.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE8CC0FC3487200064057 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 723CE8D20FC3488100064057 /* units.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE8F00FC34BD300064057 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 723CE90C0FC34C1A00064057 /* calendar.c in Sources */,
+ 723CE90E0FC34C1A00064057 /* easter.c in Sources */,
+ 723CE90F0FC34C1A00064057 /* ncal.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723CE9480FC3505500064057 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 723CE9600FC350FF00064057 /* calendar.c in Sources */,
+ 723CE9610FC350FF00064057 /* day.c in Sources */,
+ 723CE9620FC350FF00064057 /* io.c in Sources */,
+ 723CE9630FC350FF00064057 /* ostern.c in Sources */,
+ 723CE9640FC350FF00064057 /* paskha.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 53D2642B112DD86900FFBD9F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 53D2641D112DD84700FFBD9F /* cal */;
+ targetProxy = 53D2642A112DD86900FFBD9F /* PBXContainerItemProxy */;
+ };
+ 723CE9B60FC36FC600064057 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723CE94A0FC3505500064057 /* calendar */;
+ targetProxy = 723CE9B50FC36FC600064057 /* PBXContainerItemProxy */;
+ };
+ 723CE9B80FC36FC600064057 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723CE8F20FC34BD300064057 /* ncal */;
+ targetProxy = 723CE9B70FC36FC600064057 /* PBXContainerItemProxy */;
+ };
+ 723CE9BA0FC36FC600064057 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723CE8CE0FC3487200064057 /* units */;
+ targetProxy = 723CE9B90FC36FC600064057 /* PBXContainerItemProxy */;
+ };
+ 723CE9BC0FC36FC600064057 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723CE8B40FC3476900064057 /* tsort */;
+ targetProxy = 723CE9BB0FC36FC600064057 /* PBXContainerItemProxy */;
+ };
+ 723CE9BE0FC36FC600064057 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723CE85C0FC3437B00064057 /* leave */;
+ targetProxy = 723CE9BD0FC36FC600064057 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 53D26427112DD84700FFBD9F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ OTHER_CFLAGS = "-D__FBSDID=__RCSID";
+ PREBINDING = NO;
+ PRODUCT_NAME = cal;
+ STRIP_INSTALLED_PRODUCT = YES;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 723CE84D0FC342D200064057 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GENERATE_MASTER_OBJECT_FILE = NO;
+ INSTALL_MODE_FLAG = "gou-w,a+rX";
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ USE_HEADERMAP = NO;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_BUILDER = "$(USER)";
+ VERSION_INFO_FILE = "$(PRODUCT_NAME)_vers.c";
+ VERSION_INFO_PREFIX = __;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 723CE8610FC3437C00064057 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = leave;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = __;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 723CE8B70FC3476A00064057 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = tsort;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 723CE8D10FC3487300064057 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ OTHER_CFLAGS = "";
+ PREBINDING = NO;
+ PRODUCT_NAME = units;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 723CE8F50FC34BD300064057 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/bin;
+ OTHER_CFLAGS = "-D__FBSDID=__RCSID";
+ PREBINDING = NO;
+ PRODUCT_NAME = ncal;
+ STRIP_INSTALLED_PRODUCT = YES;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 723CE94D0FC3505500064057 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ INSTALL_PATH = /usr/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = calendar;
+ STRIP_INSTALLED_PRODUCT = YES;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 723CE9B40FC36FB000064057 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = "Build All";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 53D26426112DD84700FFBD9F /* Build configuration list for PBXNativeTarget "cal" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 53D26427112DD84700FFBD9F /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723CE84E0FC342D200064057 /* Build configuration list for PBXProject "misc_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723CE84D0FC342D200064057 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723CE8620FC3437C00064057 /* Build configuration list for PBXNativeTarget "leave" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723CE8610FC3437C00064057 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723CE8B80FC3478800064057 /* Build configuration list for PBXNativeTarget "tsort" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723CE8B70FC3476A00064057 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723CE8D50FC348B200064057 /* Build configuration list for PBXNativeTarget "units" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723CE8D10FC3487300064057 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723CE8F70FC34BE400064057 /* Build configuration list for PBXNativeTarget "ncal" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723CE8F50FC34BD300064057 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723CE94E0FC3507300064057 /* Build configuration list for PBXNativeTarget "calendar" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723CE94D0FC3505500064057 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723CE9C10FC36FEB00064057 /* Build configuration list for PBXAggregateTarget "Build All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723CE9B40FC36FB000064057 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 723CE84B0FC342D200064057 /* Project object */;
+}
diff --git a/misc_cmds/ncal/calendar.c b/misc_cmds/ncal/calendar.c
new file mode 100644
index 0000000..fca63ee
--- /dev/null
+++ b/misc_cmds/ncal/calendar.c
@@ -0,0 +1,330 @@
+/*-
+ * Copyright (c) 1997 Wolfgang Helbig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "calendar.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/*
+ * For each month tabulate the number of days elapsed in a year before the
+ * month. This assumes the internal date representation, where a year
+ * starts on March 1st. So we don't need a special table for leap years.
+ * But we do need a special table for the year 1582, since 10 days are
+ * deleted in October. This is month1s for the switch from Julian to
+ * Gregorian calendar.
+ */
+static int const month1[] =
+ {0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337};
+ /* M A M J J A S O N D J */
+static int const month1s[]=
+ {0, 31, 61, 92, 122, 153, 184, 214, 235, 265, 296, 327};
+
+typedef struct date date;
+
+/* The last day of Julian calendar, in internal and ndays representation */
+static int nswitch; /* The last day of Julian calendar */
+static date jiswitch = {1582, 7, 3};
+
+static date *date2idt(date *idt, date *dt);
+static date *idt2date(date *dt, date *idt);
+static int ndaysji(date *idt);
+static int ndaysgi(date *idt);
+static int firstweek(int year);
+
+/*
+ * Compute the Julian date from the number of days elapsed since
+ * March 1st of year zero.
+ */
+date *
+jdate(int ndays, date *dt)
+{
+ date idt; /* Internal date representation */
+ int r; /* hold the rest of days */
+
+ /*
+ * Compute the year by starting with an approximation not smaller
+ * than the answer and using linear search for the greatest
+ * year which does not begin after ndays.
+ */
+ idt.y = ndays / 365;
+ idt.m = 0;
+ idt.d = 0;
+ while ((r = ndaysji(&idt)) > ndays)
+ idt.y--;
+
+ /*
+ * Set r to the days left in the year and compute the month by
+ * linear search as the largest month that does not begin after r
+ * days.
+ */
+ r = ndays - r;
+ for (idt.m = 11; month1[idt.m] > r; idt.m--)
+ ;
+
+ /* Compute the days left in the month */
+ idt.d = r - month1[idt.m];
+
+ /* return external representation of the date */
+ return (idt2date(dt, &idt));
+}
+
+/*
+ * Return the number of days since March 1st of the year zero.
+ * The date is given according to Julian calendar.
+ */
+int
+ndaysj(date *dt)
+{
+ date idt; /* Internal date representation */
+
+ if (date2idt(&idt, dt) == NULL)
+ return (-1);
+ else
+ return (ndaysji(&idt));
+}
+
+/*
+ * Same as above, where the Julian date is given in internal notation.
+ * This formula shows the beauty of this notation.
+ */
+static int
+ndaysji(date * idt)
+{
+
+ return (idt->d + month1[idt->m] + idt->y * 365 + idt->y / 4);
+}
+
+/*
+ * Compute the date according to the Gregorian calendar from the number of
+ * days since March 1st, year zero. The date computed will be Julian if it
+ * is older than 1582-10-05. This is the reverse of the function ndaysg().
+ */
+date *
+gdate(int ndays, date *dt)
+{
+ int const *montht; /* month-table */
+ date idt; /* for internal date representation */
+ int r; /* holds the rest of days */
+
+ /*
+ * Compute the year by starting with an approximation not smaller
+ * than the answer and search linearly for the greatest year not
+ * starting after ndays.
+ */
+ idt.y = ndays / 365;
+ idt.m = 0;
+ idt.d = 0;
+ while ((r = ndaysgi(&idt)) > ndays)
+ idt.y--;
+
+ /*
+ * Set ndays to the number of days left and compute by linear
+ * search the greatest month which does not start after ndays. We
+ * use the table month1 which provides for each month the number
+ * of days that elapsed in the year before that month. Here the
+ * year 1582 is special, as 10 days are left out in October to
+ * resynchronize the calendar with the earth's orbit. October 4th
+ * 1582 is followed by October 15th 1582. We use the "switch"
+ * table month1s for this year.
+ */
+ ndays = ndays - r;
+ if (idt.y == 1582)
+ montht = month1s;
+ else
+ montht = month1;
+
+ for (idt.m = 11; montht[idt.m] > ndays; idt.m--)
+ ;
+
+ idt.d = ndays - montht[idt.m]; /* the rest is the day in month */
+
+ /* Advance ten days deleted from October if after switch in Oct 1582 */
+ if (idt.y == jiswitch.y && idt.m == jiswitch.m && jiswitch.d < idt.d)
+ idt.d += 10;
+
+ /* return external representation of found date */
+ return (idt2date(dt, &idt));
+}
+
+/*
+ * Return the number of days since March 1st of the year zero. The date is
+ * assumed Gregorian if younger than 1582-10-04 and Julian otherwise. This
+ * is the reverse of gdate.
+ */
+int
+ndaysg(date *dt)
+{
+ date idt; /* Internal date representation */
+
+ if (date2idt(&idt, dt) == NULL)
+ return (-1);
+ return (ndaysgi(&idt));
+}
+
+/*
+ * Same as above, but with the Gregorian date given in internal
+ * representation.
+ */
+static int
+ndaysgi(date *idt)
+{
+ int nd; /* Number of days--return value */
+
+ /* Cache nswitch if not already done */
+ if (nswitch == 0)
+ nswitch = ndaysji(&jiswitch);
+
+ /*
+ * Assume Julian calendar and adapt to Gregorian if necessary, i. e.
+ * younger than nswitch. Gregori deleted
+ * the ten days from Oct 5th to Oct 14th 1582.
+ * Thereafter years which are multiples of 100 and not multiples
+ * of 400 were not leap years anymore.
+ * This makes the average length of a year
+ * 365d +.25d - .01d + .0025d = 365.2425d. But the tropical
+ * year measures 365.2422d. So in 10000/3 years we are
+ * again one day ahead of the earth. Sigh :-)
+ * (d is the average length of a day and tropical year is the
+ * time from one spring point to the next.)
+ */
+ if ((nd = ndaysji(idt)) == -1)
+ return (-1);
+ if (idt->y >= 1600)
+ nd = (nd - 10 - (idt->y - 1600) / 100 + (idt->y - 1600) / 400);
+ else if (nd > nswitch)
+ nd -= 10;
+ return (nd);
+}
+
+/*
+ * Compute the week number from the number of days since March 1st year 0.
+ * The weeks are numbered per year starting with 1. If the first
+ * week of a year includes at least four days of that year it is week 1,
+ * otherwise it gets the number of the last week of the previous year.
+ * The variable y will be filled with the year that contains the greater
+ * part of the week.
+ */
+int
+week(int nd, int *y)
+{
+ date dt;
+ int fw; /* 1st day of week 1 of previous, this and
+ * next year */
+ gdate(nd, &dt);
+ for (*y = dt.y + 1; nd < (fw = firstweek(*y)); (*y)--)
+ ;
+ return ((nd - fw) / 7 + 1);
+}
+
+/* return the first day of week 1 of year y */
+static int
+firstweek(int y)
+{
+ date idt;
+ int nd, wd;
+
+ idt.y = y - 1; /* internal representation of y-1-1 */
+ idt.m = 10;
+ idt.d = 0;
+
+ nd = ndaysgi(&idt);
+ /*
+ * If more than 3 days of this week are in the preceding year, the
+ * next week is week 1 (and the next monday is the answer),
+ * otherwise this week is week 1 and the last monday is the
+ * answer.
+ */
+ if ((wd = weekday(nd)) > 3)
+ return (nd - wd + 7);
+ else
+ return (nd - wd);
+}
+
+/* return the weekday (Mo = 0 .. Su = 6) */
+int
+weekday(int nd)
+{
+ date dmondaygi = {1997, 8, 16}; /* Internal repr. of 1997-11-17 */
+ static int nmonday; /* ... which is a monday */
+
+ /* Cache the daynumber of one monday */
+ if (nmonday == 0)
+ nmonday = ndaysgi(&dmondaygi);
+
+ /* return (nd - nmonday) modulo 7 which is the weekday */
+ nd = (nd - nmonday) % 7;
+ if (nd < 0)
+ return (nd + 7);
+ else
+ return (nd);
+}
+
+/*
+ * Convert a date to internal date representation: The year starts on
+ * March 1st, month and day numbering start at zero. E. g. March 1st of
+ * year zero is written as y=0, m=0, d=0.
+ */
+static date *
+date2idt(date *idt, date *dt)
+{
+
+ idt->d = dt->d - 1;
+ if (dt->m > 2) {
+ idt->m = dt->m - 3;
+ idt->y = dt->y;
+ } else {
+ idt->m = dt->m + 9;
+ idt->y = dt->y - 1;
+ }
+ if (idt->m < 0 || idt->m > 11 || idt->y < 0)
+ return (NULL);
+ else
+ return idt;
+}
+
+/* Reverse of date2idt */
+static date *
+idt2date(date *dt, date *idt)
+{
+
+ dt->d = idt->d + 1;
+ if (idt->m < 10) {
+ dt->m = idt->m + 3;
+ dt->y = idt->y;
+ } else {
+ dt->m = idt->m - 9;
+ dt->y = idt->y + 1;
+ }
+ if (dt->m < 1)
+ return (NULL);
+ else
+ return (dt);
+}
diff --git a/misc_cmds/ncal/calendar.h b/misc_cmds/ncal/calendar.h
new file mode 100644
index 0000000..2c42d6c
--- /dev/null
+++ b/misc_cmds/ncal/calendar.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1997 Wolfgang Helbig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+struct date {
+ int y; /* year */
+ int m; /* month */
+ int d; /* day */
+};
+
+struct date *easterg(int _year, struct date *_dt);
+struct date *easterog(int _year, struct date *_dt);
+struct date *easteroj(int _year, struct date *_dt);
+struct date *gdate(int _nd, struct date *_dt);
+struct date *jdate(int _nd, struct date *_dt);
+int ndaysg(struct date *_dt);
+int ndaysj(struct date *_dt);
+int week(int _nd, int *_year);
+int weekday(int _nd);
diff --git a/misc_cmds/ncal/easter.c b/misc_cmds/ncal/easter.c
new file mode 100644
index 0000000..8bb3e1c
--- /dev/null
+++ b/misc_cmds/ncal/easter.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 1997 Wolfgang Helbig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "calendar.h"
+
+typedef struct date date;
+
+static int easterodn(int y);
+
+/* Compute Easter Sunday in Gregorian Calendar */
+date *
+easterg(int y, date *dt)
+{
+ int c, i, j, k, l, n;
+
+ n = y % 19;
+ c = y / 100;
+ k = (c - 17) / 25;
+ i = (c - c/4 -(c-k)/3 + 19 * n + 15) % 30;
+ i = i -(i/28) * (1 - (i/28) * (29/(i + 1)) * ((21 - n)/11));
+ j = (y + y/4 + i + 2 - c + c/4) % 7;
+ l = i - j;
+ dt->m = 3 + (l + 40) / 44;
+ dt->d = l + 28 - 31*(dt->m / 4);
+ dt->y = y;
+ return (dt);
+}
+
+/* Compute the Gregorian date of Easter Sunday in Julian Calendar */
+date *
+easterog(int y, date *dt)
+{
+
+ return (gdate(easterodn(y), dt));
+}
+
+/* Compute the Julian date of Easter Sunday in Julian Calendar */
+date *
+easteroj(int y, date * dt)
+{
+
+ return (jdate(easterodn(y), dt));
+}
+
+/* Compute the day number of Easter Sunday in Julian Calendar */
+static int
+easterodn(int y)
+{
+ /*
+ * Table for the easter limits in one metonic (19-year) cycle. 21
+ * to 31 is in March, 1 through 18 in April. Easter is the first
+ * sunday after the easter limit.
+ */
+ int mc[] = {5, 25, 13, 2, 22, 10, 30, 18, 7, 27, 15, 4,
+ 24, 12, 1, 21, 9, 29, 17};
+
+ /* Offset from a weekday to next sunday */
+ int ns[] = {6, 5, 4, 3, 2, 1, 7};
+ date dt;
+ int dn;
+
+ /* Assign the easter limit of y to dt */
+ dt.d = mc[y % 19];
+
+ if (dt.d < 21)
+ dt.m = 4;
+ else
+ dt.m = 3;
+
+ dt.y = y;
+
+ /* Return the next sunday after the easter limit */
+ dn = ndaysj(&dt);
+ return (dn + ns[weekday(dn)]);
+}
diff --git a/misc_cmds/ncal/ncal.1 b/misc_cmds/ncal/ncal.1
new file mode 100644
index 0000000..329db6d
--- /dev/null
+++ b/misc_cmds/ncal/ncal.1
@@ -0,0 +1,198 @@
+.\" Copyright (c) 1997 Wolfgang Helbig
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 14, 2009
+.Dt CAL 1
+.Os
+.Sh NAME
+.Nm cal ,
+.Nm ncal
+.Nd displays a calendar and the date of Easter
+.Sh SYNOPSIS
+.Nm
+.Op Fl 3hjy
+.Op Fl A Ar number
+.Op Fl B Ar number
+.Oo
+.Op Ar month
+.Ar year
+.Oc
+.Nm
+.Op Fl 3hj
+.Op Fl A Ar number
+.Op Fl B Ar number
+.Fl m Ar month
+.Op Ar year
+.Nm ncal
+.Op Fl 3hjJpwy
+.Op Fl A Ar number
+.Op Fl B Ar number
+.Op Fl s Ar country_code
+.Oo
+.Op Ar month
+.Ar year
+.Oc
+.Nm ncal
+.Op Fl 3hJeo
+.Op Fl A Ar number
+.Op Fl B Ar number
+.Op Ar year
+.Nm ncal
+.Op Fl CN
+.Op Fl H Ar yyyy-mm-dd
+.Op Fl d Ar yyyy-mm
+.Sh DESCRIPTION
+The
+.Nm
+utility displays a simple calendar in traditional format and
+.Nm ncal
+offers an alternative layout, more options and the date of Easter.
+The new format is a little cramped but it makes a year fit
+on a 25x80 terminal.
+If arguments are not specified,
+the current month is displayed.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl h
+Turns off highlighting of today.
+.It Fl J
+Display Julian Calendar, if combined with the
+.Fl e
+option, display date of Easter according to the Julian Calendar.
+.It Fl e
+Display date of Easter (for western churches).
+.It Fl j
+Display Julian days (days one-based, numbered from January 1).
+.It Fl m Ar month
+Display the specified
+.Ar month .
+If
+.Ar month
+is specified as a decimal number, it may be followed by the letter
+.Ql f
+or
+.Ql p
+to indicate the following or preceding month of that number,
+respectively.
+.It Fl o
+Display date of Orthodox Easter (Greek and Russian
+Orthodox Churches).
+.It Fl p
+Print the country codes and switching days from Julian to Gregorian
+Calendar as they are assumed by
+.Nm ncal .
+The country code as determined from the local environment is marked
+with an asterisk.
+.It Fl s Ar country_code
+Assume the switch from Julian to Gregorian Calendar at the date
+associated with the
+.Ar country_code .
+If not specified,
+.Nm ncal
+tries to guess the switch date from the local environment or
+falls back to September 2, 1752.
+This was when Great
+Britain and her colonies switched to the Gregorian Calendar.
+.It Fl w
+Print the number of the week below each week column.
+.It Fl y
+Display a calendar for the specified year.
+.It Fl 3
+Display the previous, current and next month surrounding today.
+.It Fl A Ar number
+Display the
+.Ar number
+of months after the current month.
+.It Fl B Ar number
+Display the
+.Ar number
+of months before the current month.
+.It Fl C
+Switch to
+.Nm cal
+mode.
+.It Fl N
+Switch to
+.Nm ncal
+mode.
+.It Fl d Ar yyyy-mm
+Use
+.Ar yyyy-mm
+as the current date (for debugging of date selection).
+.It Fl H Ar yyyy-mm-dd
+Use
+.Ar yyyy-mm-dd
+as the current date (for debugging of highlighting).
+.El
+.Pp
+A single parameter specifies the year (1\(en9999) to be displayed;
+note the year must be fully specified:
+.Dq Li cal 89
+will
+.Em not
+display a calendar for 1989. Two parameters denote the month and
+year; the month is either a number between 1 and 12, or a full or
+abbreviated name as specified by the current locale. Month and
+year default to those of the current system clock and time zone (so
+.Dq Li cal -m 8
+will display a calendar for the month of August in the current
+year).
+.Pp
+Not all options can be used together. For example
+.Dq Li -3 -A 2 -B 3 -y -m 7
+would mean:
+show me the three months around the seventh month, three before
+that, two after that and the whole year.
+.Nm ncal
+will warn about these combinations.
+.Pp
+A year starts on January 1.
+.Pp
+Highlighting of dates is disabled if stdout is not a tty.
+.Sh SEE ALSO
+.Xr calendar 3 ,
+.Xr strftime 3
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v5 .
+The
+.Nm ncal
+command appeared in
+.Fx 2.2.6 .
+.Sh AUTHORS
+The
+.Nm ncal
+command and manual were written by
+.An Wolfgang Helbig Aq Mt helbig@FreeBSD.org .
+.Sh BUGS
+The assignment of Julian\(enGregorian switching dates to country
+codes is historically naive for many countries.
+.Pp
+Not all options are compatible and using them in different orders
+will give varying results.
diff --git a/misc_cmds/ncal/ncal.c b/misc_cmds/ncal/ncal.c
new file mode 100644
index 0000000..5a5cbc3
--- /dev/null
+++ b/misc_cmds/ncal/ncal.c
@@ -0,0 +1,1177 @@
+/*-
+ * Copyright (c) 1997 Wolfgang Helbig
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <calendar.h>
+#include <ctype.h>
+#include <err.h>
+#include <langinfo.h>
+#include <libgen.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <time.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <term.h>
+#undef lines /* term.h defines this */
+
+/* Width of one month with backward compatibility and in regular mode*/
+#define MONTH_WIDTH_B_J 27
+#define MONTH_WIDTH_B 20
+
+#define MONTH_WIDTH_R_J 24
+#define MONTH_WIDTH_R 18
+
+#define MAX_WIDTH 64
+
+typedef struct date date;
+
+struct monthlines {
+ wchar_t name[MAX_WIDTH + 1];
+ char lines[7][MAX_WIDTH + 1];
+ char weeks[MAX_WIDTH + 1];
+ unsigned int extralen[7];
+};
+
+struct weekdays {
+ wchar_t names[7][4];
+};
+
+/* The switches from Julian to Gregorian in some countries */
+static struct djswitch {
+ const char *cc; /* Country code according to ISO 3166 */
+ const char *nm; /* Name of country */
+ date dt; /* Last day of Julian calendar */
+} switches[] = {
+ {"AL", "Albania", {1912, 11, 30}},
+ {"AT", "Austria", {1583, 10, 5}},
+ {"AU", "Australia", {1752, 9, 2}},
+ {"BE", "Belgium", {1582, 12, 14}},
+ {"BG", "Bulgaria", {1916, 3, 18}},
+ {"CA", "Canada", {1752, 9, 2}},
+ {"CH", "Switzerland", {1655, 2, 28}},
+ {"CN", "China", {1911, 12, 18}},
+ {"CZ", "Czech Republic",{1584, 1, 6}},
+ {"DE", "Germany", {1700, 2, 18}},
+ {"DK", "Denmark", {1700, 2, 18}},
+ {"ES", "Spain", {1582, 10, 4}},
+ {"FI", "Finland", {1753, 2, 17}},
+ {"FR", "France", {1582, 12, 9}},
+ {"GB", "United Kingdom",{1752, 9, 2}},
+ {"GR", "Greece", {1924, 3, 9}},
+ {"HU", "Hungary", {1587, 10, 21}},
+ {"IS", "Iceland", {1700, 11, 16}},
+ {"IT", "Italy", {1582, 10, 4}},
+ {"JP", "Japan", {1918, 12, 18}},
+ {"LI", "Lithuania", {1918, 2, 1}},
+ {"LN", "Latin", {9999, 05, 31}},
+ {"LU", "Luxembourg", {1582, 12, 14}},
+ {"LV", "Latvia", {1918, 2, 1}},
+ {"NL", "Netherlands", {1582, 12, 14}},
+ {"NO", "Norway", {1700, 2, 18}},
+ {"PL", "Poland", {1582, 10, 4}},
+ {"PT", "Portugal", {1582, 10, 4}},
+ {"RO", "Romania", {1919, 3, 31}},
+ {"RU", "Russia", {1918, 1, 31}},
+ {"SI", "Slovenia", {1919, 3, 4}},
+ {"SE", "Sweden", {1753, 2, 17}},
+ {"TR", "Turkey", {1926, 12, 18}},
+ {"US", "United States", {1752, 9, 2}},
+ {"YU", "Yugoslavia", {1919, 3, 4}}
+};
+
+static struct djswitch *dftswitch =
+ switches + sizeof(switches) / sizeof(struct djswitch) - 2;
+ /* default switch (should be "US") */
+
+/* Table used to print day of month and week numbers */
+static char daystr[] = " 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15"
+ " 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31"
+ " 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47"
+ " 48 49 50 51 52 53";
+
+/* Table used to print day of year and week numbers */
+static char jdaystr[] = " 1 2 3 4 5 6 7 8 9"
+ " 10 11 12 13 14 15 16 17 18 19"
+ " 20 21 22 23 24 25 26 27 28 29"
+ " 30 31 32 33 34 35 36 37 38 39"
+ " 40 41 42 43 44 45 46 47 48 49"
+ " 50 51 52 53 54 55 56 57 58 59"
+ " 60 61 62 63 64 65 66 67 68 69"
+ " 70 71 72 73 74 75 76 77 78 79"
+ " 80 81 82 83 84 85 86 87 88 89"
+ " 90 91 92 93 94 95 96 97 98 99"
+ " 100 101 102 103 104 105 106 107 108 109"
+ " 110 111 112 113 114 115 116 117 118 119"
+ " 120 121 122 123 124 125 126 127 128 129"
+ " 130 131 132 133 134 135 136 137 138 139"
+ " 140 141 142 143 144 145 146 147 148 149"
+ " 150 151 152 153 154 155 156 157 158 159"
+ " 160 161 162 163 164 165 166 167 168 169"
+ " 170 171 172 173 174 175 176 177 178 179"
+ " 180 181 182 183 184 185 186 187 188 189"
+ " 190 191 192 193 194 195 196 197 198 199"
+ " 200 201 202 203 204 205 206 207 208 209"
+ " 210 211 212 213 214 215 216 217 218 219"
+ " 220 221 222 223 224 225 226 227 228 229"
+ " 230 231 232 233 234 235 236 237 238 239"
+ " 240 241 242 243 244 245 246 247 248 249"
+ " 250 251 252 253 254 255 256 257 258 259"
+ " 260 261 262 263 264 265 266 267 268 269"
+ " 270 271 272 273 274 275 276 277 278 279"
+ " 280 281 282 283 284 285 286 287 288 289"
+ " 290 291 292 293 294 295 296 297 298 299"
+ " 300 301 302 303 304 305 306 307 308 309"
+ " 310 311 312 313 314 315 316 317 318 319"
+ " 320 321 322 323 324 325 326 327 328 329"
+ " 330 331 332 333 334 335 336 337 338 339"
+ " 340 341 342 343 344 345 346 347 348 349"
+ " 350 351 352 353 354 355 356 357 358 359"
+ " 360 361 362 363 364 365 366";
+
+static int flag_nohighlight; /* user doesn't want a highlighted today */
+static int flag_weeks; /* user wants number of week */
+static int nswitch; /* user defined switch date */
+static int nswitchb; /* switch date for backward compatibility */
+static int highlightdate;
+
+static char *center(char *s, char *t, int w);
+static wchar_t *wcenter(wchar_t *s, wchar_t *t, int w);
+static int firstday(int y, int m);
+static void highlight(char *dst, char *src, int len, int *extraletters);
+static void mkmonthr(int year, int month, int jd_flag,
+ struct monthlines * monthl);
+static void mkmonthb(int year, int month, int jd_flag,
+ struct monthlines * monthl);
+static void mkweekdays(struct weekdays * wds);
+static void monthranger(int year, int m, int jd_flag,
+ int before, int after);
+static void monthrangeb(int year, int m, int jd_flag,
+ int before, int after);
+static int parsemonth(const char *s, int *m, int *y);
+static void printcc(void);
+static void printeaster(int year, int julian, int orthodox);
+static date *sdater(int ndays, struct date * d);
+static date *sdateb(int ndays, struct date * d);
+static int sndaysr(struct date * d);
+static int sndaysb(struct date * d);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct djswitch *p, *q; /* to search user defined switch date */
+ date never = {10000, 1, 1}; /* outside valid range of dates */
+ date ukswitch = {1752, 9, 2};/* switch date for Great Britain */
+ date dt;
+ int ch; /* holds the option character */
+ int m = 0; /* month */
+ int y = 0; /* year */
+ int flag_backward = 0; /* user called cal--backward compat. */
+ int flag_wholeyear = 0; /* user wants the whole year */
+ int flag_julian_cal = 0; /* user wants Julian Calendar */
+ int flag_julian_day = 0; /* user wants the Julian day numbers */
+ int flag_orthodox = 0; /* user wants Orthodox easter */
+ int flag_easter = 0; /* user wants easter date */
+ int flag_3months = 0; /* user wants 3 month display (-3) */
+ int flag_after = 0; /* user wants to see months after */
+ int flag_before = 0; /* user wants to see months before */
+ int flag_specifiedmonth = 0;/* user wants to see this month (-m) */
+ int flag_givenmonth = 0; /* user has specified month [n] */
+ int flag_givenyear = 0; /* user has specified year [n] */
+ char *cp; /* character pointer */
+ char *flag_today = NULL; /* debug: use date as being today */
+ char *flag_month = NULL; /* requested month as string */
+ char *flag_highlightdate = NULL; /* debug: date to highlight */
+ int before, after;
+ const char *locale; /* locale to get country code */
+
+ flag_nohighlight = 0;
+ flag_weeks = 0;
+
+ /*
+ * Use locale to determine the country code,
+ * and use the country code to determine the default
+ * switchdate and date format from the switches table.
+ */
+ if (setlocale(LC_ALL, "") == NULL)
+ warn("setlocale");
+ locale = setlocale(LC_TIME, NULL);
+ if (locale == NULL ||
+ strcmp(locale, "C") == 0 ||
+ strcmp(locale, "POSIX") == 0 ||
+ strcmp(locale, "ASCII") == 0 ||
+ strcmp(locale, "US-ASCII") == 0)
+ locale = "_US";
+ q = switches + sizeof(switches) / sizeof(struct djswitch);
+ for (p = switches; p != q; p++)
+ if ((cp = strstr(locale, p->cc)) != NULL && *(cp - 1) == '_')
+ break;
+ if (p == q) {
+ nswitch = ndaysj(&dftswitch->dt);
+ } else {
+ nswitch = ndaysj(&p->dt);
+ dftswitch = p;
+ }
+
+
+ /*
+ * Get the filename portion of argv[0] and set flag_backward if
+ * this program is called "cal".
+ */
+ if (strncmp(basename(argv[0]), "cal", strlen("cal")) == 0)
+ flag_backward = 1;
+
+ /* Set the switch date to United Kingdom if backwards compatible */
+ if (flag_backward)
+ nswitchb = ndaysj(&ukswitch);
+
+ before = after = -1;
+
+ while ((ch = getopt(argc, argv, "3A:B:Cd:eH:hjJm:Nops:wy")) != -1)
+ switch (ch) {
+ case '3':
+ flag_3months = 1;
+ break;
+ case 'A':
+ if (flag_after > 0)
+ errx(EX_USAGE, "Double -A specified");
+ flag_after = strtol(optarg, NULL, 10);
+ if (flag_after <= 0)
+ errx(EX_USAGE,
+ "Argument to -A must be positive");
+ break;
+ case 'B':
+ if (flag_before > 0)
+ errx(EX_USAGE, "Double -A specified");
+ flag_before = strtol(optarg, NULL, 10);
+ if (flag_before <= 0)
+ errx(EX_USAGE,
+ "Argument to -B must be positive");
+ break;
+ case 'J':
+ if (flag_backward)
+ usage();
+ nswitch = ndaysj(&never);
+ flag_julian_cal = 1;
+ break;
+ case 'C':
+ flag_backward = 1;
+ break;
+ case 'N':
+ flag_backward = 0;
+ break;
+ case 'd':
+ flag_today = optarg;
+ break;
+ case 'H':
+ flag_highlightdate = optarg;
+ break;
+ case 'h':
+ flag_nohighlight = 1;
+ break;
+ case 'e':
+ if (flag_backward)
+ usage();
+ flag_easter = 1;
+ break;
+ case 'j':
+ flag_julian_day = 1;
+ break;
+ case 'm':
+ if (flag_specifiedmonth)
+ errx(EX_USAGE, "Double -m specified");
+ flag_month = optarg;
+ flag_specifiedmonth = 1;
+ break;
+ case 'o':
+ if (flag_backward)
+ usage();
+ flag_orthodox = 1;
+ flag_easter = 1;
+ break;
+ case 'p':
+ if (flag_backward)
+ usage();
+ printcc();
+ return (0);
+ break;
+ case 's':
+ if (flag_backward)
+ usage();
+ q = switches +
+ sizeof(switches) / sizeof(struct djswitch);
+ for (p = switches;
+ p != q && strcmp(p->cc, optarg) != 0; p++)
+ ;
+ if (p == q)
+ errx(EX_USAGE,
+ "%s: invalid country code", optarg);
+ nswitch = ndaysj(&(p->dt));
+ break;
+ case 'w':
+ if (flag_backward)
+ usage();
+ flag_weeks = 1;
+ break;
+ case 'y':
+ flag_wholeyear = 1;
+ break;
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) {
+ case 2:
+ if (flag_easter)
+ usage();
+ flag_month = *argv++;
+ flag_givenmonth = 1;
+ m = strtol(flag_month, NULL, 10);
+ /* FALLTHROUGH */
+ case 1:
+ y = atoi(*argv);
+ if (y < 1 || y > 9999)
+ errx(EX_USAGE, "year `%s' not in range 1..9999", *argv);
+ argv++;
+ flag_givenyear = 1;
+ break;
+ case 0:
+ if (flag_today != NULL) {
+ y = strtol(flag_today, NULL, 10);
+ m = strtol(flag_today + 5, NULL, 10);
+ } else {
+ time_t t;
+ struct tm *tm;
+
+ t = time(NULL);
+ tm = localtime(&t);
+ y = tm->tm_year + 1900;
+ m = tm->tm_mon + 1;
+ }
+ break;
+ default:
+ usage();
+ }
+
+ if (flag_month != NULL) {
+ if (parsemonth(flag_month, &m, &y)) {
+ errx(EX_USAGE,
+ "%s is neither a month number (1..12) nor a name",
+ flag_month);
+ }
+ }
+
+ /*
+ * What is not supported:
+ * -3 with -A or -B
+ * -3 displays 3 months, -A and -B change that behaviour.
+ * -3 with -y
+ * -3 displays 3 months, -y says display a whole year.
+ * -3 with a given year but no given month or without -m
+ * -3 displays 3 months, no month specified doesn't make clear
+ * which three months.
+ * -m with a given month
+ * conflicting arguments, both specify the same field.
+ * -y with -m
+ * -y displays the whole year, -m displays a single month.
+ * -y with a given month
+ * -y displays the whole year, the given month displays a single
+ * month.
+ * -y with -A or -B
+ * -y displays the whole year, -A and -B display extra months.
+ */
+
+ /* -3 together with -A or -B. */
+ if (flag_3months && (flag_after || flag_before))
+ errx(EX_USAGE, "-3 together with -A and -B is not supported.");
+ /* -3 together with -y. */
+ if (flag_3months && flag_wholeyear)
+ errx(EX_USAGE, "-3 together with -y is not supported.");
+ /* -3 together with givenyear but no givenmonth. */
+ if (flag_3months && flag_givenyear &&
+ !(flag_givenmonth || flag_specifiedmonth))
+ errx(EX_USAGE,
+ "-3 together with a given year but no given month is "
+ "not supported.");
+ /* -m together with xx xxxx. */
+ if (flag_specifiedmonth && flag_givenmonth)
+ errx(EX_USAGE,
+ "-m together with a given month is not supported.");
+ /* -y together with -m. */
+ if (flag_wholeyear && flag_specifiedmonth)
+ errx(EX_USAGE, "-y together with -m is not supported.");
+ /* -y together with xx xxxx. */
+ if (flag_wholeyear && flag_givenmonth)
+ errx(EX_USAGE, "-y together a given month is not supported.");
+ /* -y together with -A or -B. */
+ if (flag_wholeyear && (flag_before > 0 || flag_after > 0))
+ errx(EX_USAGE, "-y together a -A or -B is not supported.");
+ /* The rest should be fine. */
+
+ /* Select the period to display, in order of increasing priority .*/
+ if (flag_wholeyear ||
+ (flag_givenyear && !(flag_givenmonth || flag_specifiedmonth))) {
+ m = 1;
+ before = 0;
+ after = 11;
+ }
+ if (flag_givenyear && flag_givenmonth) {
+ before = 0;
+ after = 0;
+ }
+ if (flag_specifiedmonth) {
+ before = 0;
+ after = 0;
+ }
+ if (flag_before) {
+ before = flag_before;
+ }
+ if (flag_after) {
+ after = flag_after;
+ }
+ if (flag_3months) {
+ before = 1;
+ after = 1;
+ }
+ if (after == -1)
+ after = 0;
+ if (before == -1)
+ before = 0;
+
+ /* Highlight a specified day or today .*/
+ if (flag_highlightdate != NULL) {
+ dt.y = strtol(flag_highlightdate, NULL, 10);
+ dt.m = strtol(flag_highlightdate + 5, NULL, 10);
+ dt.d = strtol(flag_highlightdate + 8, NULL, 10);
+ } else {
+ time_t t;
+ struct tm *tm1;
+
+ t = time(NULL);
+ tm1 = localtime(&t);
+ dt.y = tm1->tm_year + 1900;
+ dt.m = tm1->tm_mon + 1;
+ dt.d = tm1->tm_mday;
+ }
+ highlightdate = sndaysb(&dt);
+
+ /* And now we finally start to calculate and output calendars. */
+ if (flag_easter)
+ printeaster(y, flag_julian_cal, flag_orthodox);
+ else
+ if (flag_backward)
+ monthrangeb(y, m, flag_julian_day, before, after);
+ else
+ monthranger(y, m, flag_julian_day, before, after);
+ return (0);
+}
+
+static void
+usage(void)
+{
+
+ fputs(
+"Usage: cal [general options] [-hjy] [[month] year]\n"
+" cal [general options] [-hj] [-m month] [year]\n"
+" ncal [general options] [-hJjpwy] [-s country_code] [[month] year]\n"
+" ncal [general options] [-hJeo] [year]\n"
+"General options: [-NC3] [-A months] [-B months]\n"
+"For debug the highlighting: [-H yyyy-mm-dd] [-d yyyy-mm]\n",
+ stderr);
+ exit(EX_USAGE);
+}
+
+/* Print the assumed switches for all countries. */
+static void
+printcc(void)
+{
+ struct djswitch *p;
+ int n; /* number of lines to print */
+ int m; /* offset from left to right table entry on the same line */
+
+#define FSTR "%c%s %-15s%4d-%02d-%02d"
+#define DFLT(p) ((p) == dftswitch ? '*' : ' ')
+#define FSTRARG(p) DFLT(p), (p)->cc, (p)->nm, (p)->dt.y, (p)->dt.m, (p)->dt.d
+
+ n = sizeof(switches) / sizeof(struct djswitch);
+ m = (n + 1) / 2;
+ n /= 2;
+ for (p = switches; p != switches + n; p++)
+ printf(FSTR" "FSTR"\n", FSTRARG(p), FSTRARG(p+m));
+ if (m != n)
+ printf(FSTR"\n", FSTRARG(p));
+}
+
+/* Print the date of easter sunday. */
+static void
+printeaster(int y, int julian, int orthodox)
+{
+ date dt;
+ struct tm tm;
+ char buf[MAX_WIDTH];
+ static int d_first = -1;
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ /* force orthodox easter for years before 1583 */
+ if (y < 1583)
+ orthodox = 1;
+
+ if (orthodox)
+ if (julian)
+ easteroj(y, &dt);
+ else
+ easterog(y, &dt);
+ else
+ easterg(y, &dt);
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = dt.y - 1900;
+ tm.tm_mon = dt.m - 1;
+ tm.tm_mday = dt.d;
+ strftime(buf, sizeof(buf), d_first ? "%e %B %Y" : "%B %e %Y", &tm);
+ printf("%s\n", buf);
+}
+
+#define MW(mw, me) ((mw) + me)
+#define DECREASEMONTH(m, y) \
+ if (--m == 0) { \
+ m = 12; \
+ y--; \
+ }
+#define INCREASEMONTH(m, y) \
+ if (++(m) == 13) { \
+ (m) = 1; \
+ (y)++; \
+ }
+#define M2Y(m) ((m) / 12)
+#define M2M(m) (1 + (m) % 12)
+
+/* Print all months for the period in the range [ before .. y-m .. after ]. */
+static void
+monthrangeb(int y, int m, int jd_flag, int before, int after)
+{
+ struct monthlines year[12];
+ struct weekdays wds;
+ char s[MAX_WIDTH], t[MAX_WIDTH];
+ wchar_t ws[MAX_WIDTH], ws1[MAX_WIDTH];
+ const char *wdss;
+ int i, j;
+ int mpl;
+ int mw;
+ int m1, m2;
+ int printyearheader;
+ int prevyear = -1;
+
+ mpl = jd_flag ? 2 : 3;
+ mw = jd_flag ? MONTH_WIDTH_B_J : MONTH_WIDTH_B;
+ wdss = (mpl == 2) ? " " : "";
+
+ while (before != 0) {
+ DECREASEMONTH(m, y);
+ before--;
+ after++;
+ }
+ m1 = y * 12 + m - 1;
+ m2 = m1 + after;
+
+ mkweekdays(&wds);
+
+ /*
+ * The year header is printed when there are more than 'mpl' months
+ * and if the first month is a multitude of 'mpl'.
+ * If not, it will print the year behind every month.
+ */
+ printyearheader = (after >= mpl - 1) && (M2M(m1) - 1) % mpl == 0;
+
+ m = m1;
+ while (m <= m2) {
+ int count = 0;
+ for (i = 0; i != mpl && m + i <= m2; i++) {
+ mkmonthb(M2Y(m + i), M2M(m + i) - 1, jd_flag, year + i);
+ count++;
+ }
+
+ /* Empty line between two rows of months */
+ if (m != m1)
+ printf("\n");
+
+ /* Year at the top. */
+ if (printyearheader && M2Y(m) != prevyear) {
+ sprintf(s, "%d", M2Y(m));
+ printf("%s\n", center(t, s, mpl * mw));
+ prevyear = M2Y(m);
+ }
+
+ /* Month names. */
+ for (i = 0; i < count; i++)
+ if (printyearheader)
+ wprintf(L"%-*ls ",
+ mw, wcenter(ws, year[i].name, mw));
+ else {
+ swprintf(ws, sizeof(ws)/sizeof(ws[0]),
+ L"%-ls %d", year[i].name, M2Y(m + i));
+ wprintf(L"%-*ls ", mw, wcenter(ws1, ws, mw));
+ }
+ printf("\n");
+
+ /* Day of the week names. */
+ for (i = 0; i < count; i++) {
+ wprintf(L"%s%ls%s%ls%s%ls%s%ls%s%ls%s%ls%s%ls ",
+ wdss, wds.names[6], wdss, wds.names[0],
+ wdss, wds.names[1], wdss, wds.names[2],
+ wdss, wds.names[3], wdss, wds.names[4],
+ wdss, wds.names[5]);
+ }
+ printf("\n");
+
+ /* And the days of the month. */
+ for (i = 0; i != 6; i++) {
+ for (j = 0; j < count; j++)
+ printf("%-*s ",
+ MW(mw, year[j].extralen[i]),
+ year[j].lines[i]+1);
+ printf("\n");
+ }
+
+ m += mpl;
+ }
+}
+
+static void
+monthranger(int y, int m, int jd_flag, int before, int after)
+{
+ struct monthlines year[12];
+ struct weekdays wds;
+ char s[MAX_WIDTH], t[MAX_WIDTH];
+ int i, j;
+ int mpl;
+ int mw;
+ int m1, m2;
+ int prevyear = -1;
+ int printyearheader;
+
+ mpl = jd_flag ? 3 : 4;
+ mw = jd_flag ? MONTH_WIDTH_R_J : MONTH_WIDTH_R;
+
+ while (before != 0) {
+ DECREASEMONTH(m, y);
+ before--;
+ after++;
+ }
+ m1 = y * 12 + m - 1;
+ m2 = m1 + after;
+
+ mkweekdays(&wds);
+
+ /*
+ * The year header is printed when there are more than 'mpl' months
+ * and if the first month is a multitude of 'mpl'.
+ * If not, it will print the year behind every month.
+ */
+ printyearheader = (after >= mpl - 1) && (M2M(m1) - 1) % mpl == 0;
+
+ m = m1;
+ while (m <= m2) {
+ int count = 0;
+ for (i = 0; i != mpl && m + i <= m2; i++) {
+ mkmonthr(M2Y(m + i), M2M(m + i) - 1, jd_flag, year + i);
+ count++;
+ }
+
+ /* Empty line between two rows of months. */
+ if (m != m1)
+ printf("\n");
+
+ /* Year at the top. */
+ if (printyearheader && M2Y(m) != prevyear) {
+ sprintf(s, "%d", M2Y(m));
+ printf("%s\n", center(t, s, mpl * mw));
+ prevyear = M2Y(m);
+ }
+
+ /* Month names. */
+ wprintf(L" ");
+ for (i = 0; i < count; i++)
+ if (printyearheader)
+ wprintf(L"%-*ls", mw, year[i].name);
+ else
+ wprintf(L"%-ls %-*d", year[i].name,
+ mw - wcslen(year[i].name) - 1, M2Y(m + i));
+ printf("\n");
+
+ /* And the days of the month. */
+ for (i = 0; i != 7; i++) {
+ /* Week day */
+ wprintf(L"%.2ls", wds.names[i]);
+
+ /* Full months */
+ for (j = 0; j < count; j++)
+ printf("%-*s",
+ MW(mw, year[j].extralen[i]),
+ year[j].lines[i]);
+ printf("\n");
+ }
+
+ /* Week numbers. */
+ if (flag_weeks) {
+ printf(" ");
+ for (i = 0; i < count; i++)
+ printf("%-*s", mw, year[i].weeks);
+ printf("\n");
+ }
+
+ m += mpl;
+ }
+ return;
+}
+
+static void
+mkmonthr(int y, int m, int jd_flag, struct monthlines *mlines)
+{
+
+ struct tm tm; /* for strftime printing local names of
+ * months */
+ date dt; /* handy date */
+ int dw; /* width of numbers */
+ int first; /* first day of month */
+ int firstm; /* first day of first week of month */
+ int i, j, k, l; /* just indices */
+ int last; /* the first day of next month */
+ int jan1 = 0; /* the first day of this year */
+ char *ds; /* pointer to day strings (daystr or
+ * jdaystr) */
+
+ /* Set name of month. */
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_mon = m;
+ wcsftime(mlines->name, sizeof(mlines->name) / sizeof(mlines->name[0]),
+ L"%OB", &tm);
+ mlines->name[0] = towupper(mlines->name[0]);
+
+ /*
+ * Set first and last to the day number of the first day of this
+ * month and the first day of next month respectively. Set jan1 to
+ * the day number of the first day of this year.
+ */
+ first = firstday(y, m + 1);
+ if (m == 11)
+ last = firstday(y + 1, 1);
+ else
+ last = firstday(y, m + 2);
+
+ if (jd_flag)
+ jan1 = firstday(y, 1);
+
+ /*
+ * Set firstm to the day number of monday of the first week of
+ * this month. (This might be in the last month)
+ */
+ firstm = first - weekday(first);
+
+ /* Set ds (daystring) and dw (daywidth) according to the jd_flag. */
+ if (jd_flag) {
+ ds = jdaystr;
+ dw = 4;
+ } else {
+ ds = daystr;
+ dw = 3;
+ }
+
+ /*
+ * Fill the lines with day of month or day of year (julian day)
+ * line index: i, each line is one weekday. column index: j, each
+ * column is one day number. print column index: k.
+ */
+ for (i = 0; i != 7; i++) {
+ l = 0;
+ for (j = firstm + i, k = 0; j < last; j += 7, k += dw) {
+ if (j >= first) {
+ if (jd_flag)
+ dt.d = j - jan1 + 1;
+ else
+ sdater(j, &dt);
+ if (j == highlightdate && !flag_nohighlight
+ && isatty(STDOUT_FILENO))
+ highlight(mlines->lines[i] + k,
+ ds + dt.d * dw, dw, &l);
+ else
+ memcpy(mlines->lines[i] + k + l,
+ ds + dt.d * dw, dw);
+ } else
+ memcpy(mlines->lines[i] + k + l, " ", dw);
+ }
+ mlines->lines[i][k + l] = '\0';
+ mlines->extralen[i] = l;
+ }
+
+ /* fill the weeknumbers. */
+ if (flag_weeks) {
+ for (j = firstm, k = 0; j < last; k += dw, j += 7)
+ if (j <= nswitch)
+ memset(mlines->weeks + k, ' ', dw);
+ else
+ memcpy(mlines->weeks + k,
+ ds + week(j, &i)*dw, dw);
+ mlines->weeks[k] = '\0';
+ }
+}
+
+static void
+mkmonthb(int y, int m, int jd_flag, struct monthlines *mlines)
+{
+
+ struct tm tm; /* for strftime printing local names of
+ * months */
+ date dt; /* handy date */
+ int dw; /* width of numbers */
+ int first; /* first day of month */
+ int firsts; /* sunday of first week of month */
+ int i, j, k, l; /* just indices */
+ int jan1 = 0; /* the first day of this year */
+ int last; /* the first day of next month */
+ char *ds; /* pointer to day strings (daystr or
+ * jdaystr) */
+
+ /* Set ds (daystring) and dw (daywidth) according to the jd_flag */
+ if (jd_flag) {
+ ds = jdaystr;
+ dw = 4;
+ } else {
+ ds = daystr;
+ dw = 3;
+ }
+
+ /* Set name of month centered. */
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_mon = m;
+ wcsftime(mlines->name, sizeof(mlines->name) / sizeof(mlines->name[0]),
+ L"%OB", &tm);
+ mlines->name[0] = towupper(mlines->name[0]);
+
+ /*
+ * Set first and last to the day number of the first day of this
+ * month and the first day of next month respectively. Set jan1 to
+ * the day number of Jan 1st of this year.
+ */
+ dt.y = y;
+ dt.m = m + 1;
+ dt.d = 1;
+ first = sndaysb(&dt);
+ if (m == 11) {
+ dt.y = y + 1;
+ dt.m = 1;
+ dt.d = 1;
+ } else {
+ dt.y = y;
+ dt.m = m + 2;
+ dt.d = 1;
+ }
+ last = sndaysb(&dt);
+
+ if (jd_flag) {
+ dt.y = y;
+ dt.m = 1;
+ dt.d = 1;
+ jan1 = sndaysb(&dt);
+ }
+
+ /*
+ * Set firsts to the day number of sunday of the first week of
+ * this month. (This might be in the last month)
+ */
+ firsts = first - (weekday(first)+1) % 7;
+
+ /*
+ * Fill the lines with day of month or day of year (Julian day)
+ * line index: i, each line is one week. column index: j, each
+ * column is one day number. print column index: k.
+ */
+ for (i = 0; i != 6; i++) {
+ l = 0;
+ for (j = firsts + 7 * i, k = 0; j < last && k != dw * 7;
+ j++, k += dw) {
+ if (j >= first) {
+ if (jd_flag)
+ dt.d = j - jan1 + 1;
+ else
+ sdateb(j, &dt);
+ if (j == highlightdate && !flag_nohighlight)
+ highlight(mlines->lines[i] + k,
+ ds + dt.d * dw, dw, &l);
+ else
+ memcpy(mlines->lines[i] + k + l,
+ ds + dt.d * dw, dw);
+ } else
+ memcpy(mlines->lines[i] + k + l, " ", dw);
+ }
+ if (k == 0)
+ mlines->lines[i][1] = '\0';
+ else
+ mlines->lines[i][k + l] = '\0';
+ mlines->extralen[i] = l;
+ }
+}
+
+/* Put the local names of weekdays into the wds. */
+static void
+mkweekdays(struct weekdays *wds)
+{
+ int i, len, width = 0;
+ struct tm tm;
+ wchar_t buf[20];
+
+ memset(&tm, 0, sizeof(tm));
+
+ for (i = 0; i != 7; i++) {
+ tm.tm_wday = (i+1) % 7;
+ wcsftime(buf, sizeof(buf)/sizeof(buf[0]), L"%a", &tm);
+ for (len = 2; len > 0; --len) {
+ if ((width = wcswidth(buf, len)) <= 2)
+ break;
+ }
+ wmemset(wds->names[i], L'\0', 4);
+ if (width == 1)
+ wds->names[i][0] = L' ';
+ wcsncat(wds->names[i], buf, len);
+ wcsncat(wds->names[i], L" ", 1);
+ }
+}
+
+/*
+ * Compute the day number of the first existing date after the first day in
+ * month. (the first day in month and even the month might not exist!)
+ */
+static int
+firstday(int y, int m)
+{
+ date dt;
+ int nd;
+
+ dt.y = y;
+ dt.m = m;
+ dt.d = 1;
+ nd = sndaysr(&dt);
+ for (;;) {
+ sdater(nd, &dt);
+ if ((dt.m >= m && dt.y == y) || dt.y > y)
+ return (nd);
+ else
+ nd++;
+ }
+ /* NEVER REACHED */
+}
+
+/*
+ * Compute the number of days from date, obey the local switch from
+ * Julian to Gregorian if specified by the user.
+ */
+static int
+sndaysr(struct date *d)
+{
+
+ if (nswitch != 0)
+ if (nswitch < ndaysj(d))
+ return (ndaysg(d));
+ else
+ return (ndaysj(d));
+ else
+ return ndaysg(d);
+}
+
+/*
+ * Compute the number of days from date, obey the switch from
+ * Julian to Gregorian as used by UK and her colonies.
+ */
+static int
+sndaysb(struct date *d)
+{
+
+ if (nswitchb < ndaysj(d))
+ return (ndaysg(d));
+ else
+ return (ndaysj(d));
+}
+
+/* Inverse of sndays. */
+static struct date *
+sdater(int nd, struct date *d)
+{
+
+ if (nswitch < nd)
+ return (gdate(nd, d));
+ else
+ return (jdate(nd, d));
+}
+
+/* Inverse of sndaysb. */
+static struct date *
+sdateb(int nd, struct date *d)
+{
+
+ if (nswitchb < nd)
+ return (gdate(nd, d));
+ else
+ return (jdate(nd, d));
+}
+
+/* Center string t in string s of length w by putting enough leading blanks. */
+static char *
+center(char *s, char *t, int w)
+{
+ char blanks[MAX_WIDTH];
+
+ memset(blanks, ' ', sizeof(blanks));
+ sprintf(s, "%.*s%s", (int)(w - strlen(t)) / 2, blanks, t);
+ return (s);
+}
+
+/* Center string t in string s of length w by putting enough leading blanks. */
+static wchar_t *
+wcenter(wchar_t *s, wchar_t *t, int w)
+{
+ char blanks[MAX_WIDTH];
+
+ memset(blanks, ' ', sizeof(blanks));
+ swprintf(s, MAX_WIDTH, L"%.*s%ls", (int)(w - wcslen(t)) / 2, blanks, t);
+ return (s);
+}
+
+static int
+parsemonth(const char *s, int *m, int *y)
+{
+ int nm, ny;
+ char *cp;
+ struct tm tm;
+
+ nm = (int)strtol(s, &cp, 10);
+ if (cp != s) {
+ ny = *y;
+ if (*cp == '\0') {
+ ; /* no special action */
+ } else if (*cp == 'f' || *cp == 'F') {
+ if (nm <= *m)
+ ny++;
+ } else if (*cp == 'p' || *cp == 'P') {
+ if (nm >= *m)
+ ny--;
+ } else
+ return (1);
+ if (nm < 1 || nm > 12)
+ return 1;
+ *m = nm;
+ *y = ny;
+ return (0);
+ }
+ if (strptime(s, "%B", &tm) != NULL || strptime(s, "%b", &tm) != NULL) {
+ *m = tm.tm_mon + 1;
+ return (0);
+ }
+ return (1);
+}
+
+static void
+highlight(char *dst, char *src, int len, int *extralen)
+{
+ static int first = 1;
+ static const char *term_so, *term_se;
+
+ if (first) {
+ char tbuf[1024], cbuf[512], *b;
+
+ term_se = term_so = NULL;
+
+ /* On how to highlight on this type of terminal (if any). */
+ if (isatty(STDOUT_FILENO) && tgetent(tbuf, NULL) == 1) {
+ b = cbuf;
+ term_so = tgetstr("so", &b);
+ term_se = tgetstr("se", &b);
+ }
+
+ first = 0;
+ }
+
+ /*
+ * This check is not necessary, should have been handled before calling
+ * this function.
+ */
+ if (flag_nohighlight) {
+ memcpy(dst, src, len);
+ return;
+ }
+
+ /*
+ * If it is a real terminal, use the data from the termcap database.
+ */
+ if (term_so != NULL && term_se != NULL) {
+ /* separator. */
+ dst[0] = ' ';
+ dst++;
+ /* highlight on. */
+ memcpy(dst, term_so, strlen(term_so));
+ dst += strlen(term_so);
+ /* the actual text. (minus leading space) */
+ len--;
+ src++;
+ memcpy(dst, src, len);
+ dst += len;
+ /* highlight off. */
+ memcpy(dst, term_se, strlen(term_se));
+ *extralen = strlen(term_so) + strlen(term_se);
+ return;
+ }
+
+ /*
+ * Otherwise, print a _, backspace and the letter.
+ */
+ *extralen = 0;
+ /* skip leading space. */
+ src++;
+ len--;
+ /* separator. */
+ dst[0] = ' ';
+ dst++;
+ while (len > 0) {
+ /* _ and backspace. */
+ memcpy(dst, "_\010", 2);
+ dst += 2;
+ *extralen += 2;
+ /* the character. */
+ *dst++ = *src++;
+ len--;
+ }
+ return;
+}
diff --git a/misc_cmds/tsort/tsort.1 b/misc_cmds/tsort/tsort.1
new file mode 100644
index 0000000..a95793d
--- /dev/null
+++ b/misc_cmds/tsort/tsort.1
@@ -0,0 +1,90 @@
+.\" $NetBSD: tsort.1,v 1.7 1997/10/20 01:09:53 lukem Exp $
+.\"
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This manual is derived from one contributed to Berkeley by
+.\" Michael Rendell of Memorial University of Newfoundland.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tsort.1 8.3 (Berkeley) 4/1/94
+.\"
+.Dd April 1, 1994
+.Dt TSORT 1
+.Os
+.Sh NAME
+.Nm tsort
+.Nd topological sort of a directed graph
+.Sh SYNOPSIS
+.Nm
+.Op Fl l
+.Op Fl q
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+takes a list of pairs of node names representing directed arcs in
+a graph and prints the nodes in topological order on standard output.
+Input is taken from the named
+.Ar file ,
+or from standard input if no file
+is given.
+.Pp
+Node names in the input are separated by white space and there must
+be an even number of node pairs.
+.Pp
+Presence of a node in a graph can be represented by an arc from the node
+to itself.
+This is useful when a node is not connected to any other nodes.
+.Pp
+If the graph contains a cycle (and therefore cannot be properly sorted),
+one of the arcs in the cycle is ignored and the sort continues.
+Cycles are reported on standard error.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl l
+Search for and display the longest cycle.
+Can take a very long time.
+.It Fl q
+Do not display informational messages about cycles. This is primarily
+intended for building libraries, where optimal ordering is not critical,
+and cycles occur often.
+.El
+.Sh SEE ALSO
+.Xr ar 1
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v7 .
+This
+.Nm
+command and manual page are derived from sources contributed to Berkeley by
+Michael Rendell of Memorial University of Newfoundland.
diff --git a/misc_cmds/tsort/tsort.c b/misc_cmds/tsort/tsort.c
new file mode 100644
index 0000000..819f086
--- /dev/null
+++ b/misc_cmds/tsort/tsort.c
@@ -0,0 +1,443 @@
+/* $NetBSD: tsort.c,v 1.13 1998/08/25 20:59:42 ross Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Rendell of Memorial University of Newfoundland.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tsort.c 8.3 (Berkeley) 5/4/95";
+#endif
+__RCSID("$NetBSD: tsort.c,v 1.13 1998/08/25 20:59:42 ross Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * Topological sort. Input is a list of pairs of strings separated by
+ * white space (spaces, tabs, and/or newlines); strings are written to
+ * standard output in sorted order, one per line.
+ *
+ * usage:
+ * tsort [-l] [inputfile]
+ * If no input file is specified, standard input is read.
+ *
+ * Should be compatable with AT&T tsort HOWEVER the output is not identical
+ * (i.e. for most graphs there is more than one sorted order, and this tsort
+ * usually generates a different one then the AT&T tsort). Also, cycle
+ * reporting seems to be more accurate in this version (the AT&T tsort
+ * sometimes says a node is in a cycle when it isn't).
+ *
+ * Michael Rendell, michael@stretch.cs.mun.ca - Feb 26, '90
+ */
+#define HASHSIZE 53 /* doesn't need to be big */
+#define NF_MARK 0x1 /* marker for cycle detection */
+#define NF_ACYCLIC 0x2 /* this node is cycle free */
+#define NF_NODEST 0x4 /* Unreachable */
+
+typedef struct node_str NODE;
+
+struct node_str {
+ NODE **n_prevp; /* pointer to previous node's n_next */
+ NODE *n_next; /* next node in graph */
+ NODE **n_arcs; /* array of arcs to other nodes */
+ int n_narcs; /* number of arcs in n_arcs[] */
+ int n_arcsize; /* size of n_arcs[] array */
+ int n_refcnt; /* # of arcs pointing to this node */
+ int n_flags; /* NF_* */
+ char n_name[1]; /* name of this node */
+};
+
+typedef struct _buf {
+ char *b_buf;
+ int b_bsize;
+} BUF;
+
+DB *db;
+NODE *graph, **cycle_buf, **longest_cycle;
+int debug, longest, quiet;
+
+void add_arc __P((char *, char *));
+void clear_cycle __P((void));
+int find_cycle __P((NODE *, NODE *, int, int));
+NODE *get_node __P((char *));
+void *grow_buf __P((void *, int));
+int main __P((int, char **));
+void remove_node __P((NODE *));
+void tsort __P((void));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ BUF *b;
+ int c, n;
+ FILE *fp;
+ int bsize, ch, nused;
+ BUF bufs[2];
+
+ fp = NULL;
+ while ((ch = getopt(argc, argv, "dlq")) != -1)
+ switch (ch) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'l':
+ longest = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) {
+ case 0:
+ fp = stdin;
+ break;
+ case 1:
+ if ((fp = fopen(*argv, "r")) == NULL)
+ err(1, "%s", *argv);
+ break;
+ default:
+ usage();
+ }
+
+ for (b = bufs, n = 2; --n >= 0; b++)
+ b->b_buf = grow_buf(NULL, b->b_bsize = 1024);
+
+ /* parse input and build the graph */
+ for (n = 0, c = getc(fp);;) {
+ while (c != EOF && isspace(c))
+ c = getc(fp);
+ if (c == EOF)
+ break;
+
+ nused = 0;
+ b = &bufs[n];
+ bsize = b->b_bsize;
+ do {
+ b->b_buf[nused++] = c;
+ if (nused == bsize)
+ b->b_buf = grow_buf(b->b_buf, bsize *= 2);
+ c = getc(fp);
+ } while (c != EOF && !isspace(c));
+
+ b->b_buf[nused] = '\0';
+ b->b_bsize = bsize;
+ if (n)
+ add_arc(bufs[0].b_buf, bufs[1].b_buf);
+ n = !n;
+ }
+ (void)fclose(fp);
+ if (n)
+ errx(1, "odd data count");
+
+ /* do the sort */
+ tsort();
+ exit(0);
+}
+
+/* double the size of oldbuf and return a pointer to the new buffer. */
+void *
+grow_buf(bp, size)
+ void *bp;
+ int size;
+{
+ if ((bp = realloc(bp, (u_int)size)) == NULL)
+ err(1, "realloc");
+ return (bp);
+}
+
+/*
+ * add an arc from node s1 to node s2 in the graph. If s1 or s2 are not in
+ * the graph, then add them.
+ */
+void
+add_arc(s1, s2)
+ char *s1, *s2;
+{
+ NODE *n1;
+ NODE *n2;
+ int bsize, i;
+
+ n1 = get_node(s1);
+
+ if (!strcmp(s1, s2))
+ return;
+
+ n2 = get_node(s2);
+
+ /*
+ * Check if this arc is already here.
+ */
+ for (i = 0; i < n1->n_narcs; i++)
+ if (n1->n_arcs[i] == n2)
+ return;
+ /*
+ * Add it.
+ */
+ if (n1->n_narcs == n1->n_arcsize) {
+ if (!n1->n_arcsize)
+ n1->n_arcsize = 10;
+ bsize = n1->n_arcsize * sizeof(*n1->n_arcs) * 2;
+ n1->n_arcs = grow_buf(n1->n_arcs, bsize);
+ n1->n_arcsize = bsize / sizeof(*n1->n_arcs);
+ }
+ n1->n_arcs[n1->n_narcs++] = n2;
+ ++n2->n_refcnt;
+}
+
+/* Find a node in the graph (insert if not found) and return a pointer to it. */
+NODE *
+get_node(name)
+ char *name;
+{
+ DBT data, key;
+ NODE *n;
+
+ if (db == NULL &&
+ (db = dbopen(NULL, O_RDWR, 0, DB_HASH, NULL)) == NULL)
+ err(1, "db: %s", name);
+
+ key.data = name;
+ key.size = strlen(name) + 1;
+
+ switch ((*db->get)(db, &key, &data, 0)) {
+ case 0:
+ memmove(&n, data.data, sizeof(n));
+ return (n);
+ case 1:
+ break;
+ default:
+ case -1:
+ err(1, "db: %s", name);
+ }
+
+ if ((n = malloc(sizeof(NODE) + key.size)) == NULL)
+ err(1, "malloc");
+
+ n->n_narcs = 0;
+ n->n_arcsize = 0;
+ n->n_arcs = NULL;
+ n->n_refcnt = 0;
+ n->n_flags = 0;
+ memmove(n->n_name, name, key.size);
+
+ /* Add to linked list. */
+ if ((n->n_next = graph) != NULL)
+ graph->n_prevp = &n->n_next;
+ n->n_prevp = &graph;
+ graph = n;
+
+ /* Add to hash table. */
+ data.data = &n;
+ data.size = sizeof(n);
+ if ((*db->put)(db, &key, &data, 0))
+ err(1, "db: %s", name);
+ return (n);
+}
+
+
+/*
+ * Clear the NODEST flag from all nodes.
+ */
+void
+clear_cycle()
+{
+ NODE *n;
+
+ for (n = graph; n != NULL; n = n->n_next)
+ n->n_flags &= ~NF_NODEST;
+}
+
+/* do topological sort on graph */
+void
+tsort()
+{
+ NODE *n, *next;
+ int cnt, i;
+
+ while (graph != NULL) {
+ /*
+ * Keep getting rid of simple cases until there are none left,
+ * if there are any nodes still in the graph, then there is
+ * a cycle in it.
+ */
+ do {
+ for (cnt = 0, n = graph; n != NULL; n = next) {
+ next = n->n_next;
+ if (n->n_refcnt == 0) {
+ remove_node(n);
+ ++cnt;
+ }
+ }
+ } while (graph != NULL && cnt);
+
+ if (graph == NULL)
+ break;
+
+ if (!cycle_buf) {
+ /*
+ * Allocate space for two cycle logs - one to be used
+ * as scratch space, the other to save the longest
+ * cycle.
+ */
+ for (cnt = 0, n = graph; n != NULL; n = n->n_next)
+ ++cnt;
+ cycle_buf = malloc((u_int)sizeof(NODE *) * cnt);
+ longest_cycle = malloc((u_int)sizeof(NODE *) * cnt);
+ if (cycle_buf == NULL || longest_cycle == NULL)
+ err(1, "malloc");
+ }
+ for (n = graph; n != NULL; n = n->n_next) {
+ if (!(n->n_flags & NF_ACYCLIC)) {
+ if ((cnt = find_cycle(n, n, 0, 0)) != 0) {
+ if (!quiet) {
+ warnx("cycle in data");
+ for (i = 0; i < cnt; i++)
+ warnx("%s",
+ longest_cycle[i]->n_name);
+ }
+ remove_node(n);
+ clear_cycle();
+ break;
+ } else {
+ /* to avoid further checks */
+ n->n_flags |= NF_ACYCLIC;
+ clear_cycle();
+ }
+ }
+ }
+ if (n == NULL)
+ errx(1, "internal error -- could not find cycle");
+ }
+}
+
+/* print node and remove from graph (does not actually free node) */
+void
+remove_node(n)
+ NODE *n;
+{
+ NODE **np;
+ int i;
+
+ (void)printf("%s\n", n->n_name);
+ for (np = n->n_arcs, i = n->n_narcs; --i >= 0; np++)
+ --(*np)->n_refcnt;
+ n->n_narcs = 0;
+ *n->n_prevp = n->n_next;
+ if (n->n_next)
+ n->n_next->n_prevp = n->n_prevp;
+}
+
+
+/* look for the longest? cycle from node from to node to. */
+int
+find_cycle(from, to, longest_len, depth)
+ NODE *from, *to;
+ int depth, longest_len;
+{
+ NODE **np;
+ int i, len;
+
+ /*
+ * avoid infinite loops and ignore portions of the graph known
+ * to be acyclic
+ */
+ if (from->n_flags & (NF_NODEST|NF_MARK|NF_ACYCLIC))
+ return (0);
+ from->n_flags |= NF_MARK;
+
+ for (np = from->n_arcs, i = from->n_narcs; --i >= 0; np++) {
+ cycle_buf[depth] = *np;
+ if (*np == to) {
+ if (depth + 1 > longest_len) {
+ longest_len = depth + 1;
+ (void)memcpy((char *)longest_cycle,
+ (char *)cycle_buf,
+ longest_len * sizeof(NODE *));
+ }
+ } else {
+ if ((*np)->n_flags & (NF_MARK|NF_ACYCLIC|NF_NODEST))
+ continue;
+ len = find_cycle(*np, to, longest_len, depth + 1);
+
+ if (debug)
+ (void)printf("%*s %s->%s %d\n", depth, "",
+ from->n_name, to->n_name, len);
+
+ if (len == 0)
+ (*np)->n_flags |= NF_NODEST;
+
+ if (len > longest_len)
+ longest_len = len;
+
+ if (len > 0 && !longest)
+ break;
+ }
+ }
+ from->n_flags &= ~NF_MARK;
+ return (longest_len);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: tsort [-lq] [file]\n");
+ exit(1);
+}
diff --git a/misc_cmds/units/pathnames.h b/misc_cmds/units/pathnames.h
new file mode 100644
index 0000000..b8c1d3d
--- /dev/null
+++ b/misc_cmds/units/pathnames.h
@@ -0,0 +1,33 @@
+/* $FreeBSD: src/usr.bin/units/pathnames.h,v 1.4.56.1.2.1 2009/10/25 01:10:29 kensmith Exp $ */
+
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#define _PATH_UNITSLIB "/usr/share/misc/units.lib"
diff --git a/misc_cmds/units/units.1 b/misc_cmds/units/units.1
new file mode 100644
index 0000000..80b1333
--- /dev/null
+++ b/misc_cmds/units/units.1
@@ -0,0 +1,181 @@
+.\" $FreeBSD: src/usr.bin/units/units.1,v 1.18.22.1.2.1 2009/10/25 01:10:29 kensmith Exp $
+.Dd July 14, 1993
+.Dt UNITS 1
+.Os
+.Sh NAME
+.Nm units
+.Nd conversion program
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar filename
+.Op Fl qv
+.Op Ar from-unit to-unit
+.Sh OPTIONS
+The following options are available:
+.Bl -tag -width indent
+.It Fl f Ar filename
+Specify the name of the units data file to load.
+.It Fl q
+Suppress prompting of the user for units and the display of statistics
+about the number of units loaded.
+.It Fl v
+Print the version number.
+.It Ar from-unit to-unit
+Allow a single unit conversion to be done directly from the command
+line.
+The program will not print prompts.
+It will print out the
+result of the single specified conversion.
+.El
+.Sh DESCRIPTION
+The
+.Nm
+program converts quantities expressed in various scales to
+their equivalents in other scales.
+The
+.Nm
+program can only
+handle multiplicative scale changes.
+It cannot convert Celsius
+to Fahrenheit, for example.
+It works interactively by prompting
+the user for input:
+.Bd -literal
+ You have: meters
+ You want: feet
+ * 3.2808399
+ / 0.3048
+
+ You have: cm^3
+ You want: gallons
+ * 0.00026417205
+ / 3785.4118
+
+ You have: meters/s
+ You want: furlongs/fortnight
+ * 6012.8848
+ / 0.00016630952
+
+ You have: 1|2 inch
+ You want: cm
+ * 1.27
+ / 0.78740157
+.Ed
+.Pp
+Powers of units can be specified using the '^' character as shown in
+the example, or by simple concatenation: 'cm3' is equivalent to 'cm^3'.
+Multiplication of units can be specified by using spaces, a dash or
+an asterisk.
+Division of units is indicated by the slash ('/').
+Note that multiplication has a higher precedence than division,
+so 'm/s/s' is the same as 'm/s^2' or 'm/s s'.
+Division of numbers
+must be indicated using the vertical bar ('|').
+To convert half a
+meter, you would write '1|2 meter'.
+If you write '1/2 meter' then the
+units program would interpret that as equivalent to '0.5/meter'.
+If you enter incompatible unit types, the units program will
+print a message indicating that the units are not conformable and
+it will display the reduced form for each unit:
+.Bd -literal
+ You have: ergs/hour
+ You want: fathoms kg^2 / day
+ conformability error
+ 2.7777778e-11 kg m^2 / sec^3
+ 2.1166667e-05 kg^2 m / sec
+.Ed
+.Pp
+The conversion information is read from a units data file.
+The default
+file includes definitions for most familiar units, abbreviations and
+metric prefixes.
+Some constants of nature included are:
+.Pp
+.Bl -column -offset indent -compact "mercury"
+.It "pi ratio of circumference to diameter
+.It "c speed of light
+.It "e charge on an electron
+.It "g acceleration of gravity
+.It "force same as g
+.It "mole Avogadro's number
+.It "water pressure per unit height of water
+.It "mercury pressure per unit height of mercury
+.It "au astronomical unit
+.El
+.Pp
+The unit 'pound' is a unit of mass.
+Compound names are run together
+so 'pound force' is a unit of force.
+The unit 'ounce' is also a unit
+of mass.
+The fluid ounce is 'floz'.
+British units that differ from
+their US counterparts are prefixed with 'br', and currency is prefixed
+with its country name: 'belgiumfranc', 'britainpound'.
+When searching
+for a unit, if the specified string does not appear exactly as a unit
+name, then
+.Nm
+will try to remove a trailing 's' or a
+trailing 'es' and check again for a match.
+.Pp
+To find out what units are available read the standard units file.
+If you want to add your own units you can supply your own file.
+A unit is specified on a single line by
+giving its name and an equivalence.
+Be careful to define
+new units in terms of old ones so that a reduction leads to the
+primitive units which are marked with '!' characters.
+The
+.Nm
+program will not detect infinite loops that could be caused
+by careless unit definitions.
+Comments in the unit definition file
+begin with a '/' character at the beginning of a line.
+.Pp
+Prefixes are defined in the same was as standard units, but with
+a trailing dash at the end of the prefix name.
+If a unit is not found
+even after removing trailing 's' or 'es', then it will be checked
+against the list of prefixes.
+Prefixes will be removed until a legal
+base unit is identified.
+.Pp
+Here is an example of a short units file that defines some basic
+units.
+.Pp
+.Bl -column -offset indent -compact "minute"
+.It "m !a!
+.It "sec !b!
+.It "micro- 1e-6
+.It "minute 60 sec
+.It "hour 60 min
+.It "inch 0.0254 m
+.It "ft 12 inches
+.It "mile 5280 ft
+.El
+.Sh FILES
+.Bl -tag -width /usr/share/misc/units.lib -compact
+.It Pa /usr/share/misc/units.lib
+the standard units library
+.El
+.Sh AUTHORS
+.An Adrian Mariano Aq adrian@cam.cornell.edu
+.Sh BUGS
+The effect of including a '/' in a prefix is surprising.
+.Pp
+Exponents entered by the user can be only one digit.
+You can work around this by multiplying several terms.
+.Pp
+The user must use | to indicate division of numbers and / to
+indicate division of symbols.
+This distinction should not
+be necessary.
+.Pp
+The program contains various arbitrary limits on the length
+of the units converted and on the length of the data file.
+.Pp
+The program should use a hash table to store units so that
+it does not take so long to load the units list and check
+for duplication.
diff --git a/misc_cmds/units/units.c b/misc_cmds/units/units.c
new file mode 100644
index 0000000..169c79b
--- /dev/null
+++ b/misc_cmds/units/units.c
@@ -0,0 +1,749 @@
+/*
+ * units.c Copyright (c) 1993 by Adrian Mariano (adrian@cam.cornell.edu)
+ *
+ * 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. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ * Disclaimer: This software is provided by the author "as is". The author
+ * shall not be liable for any damages caused in any way by this software.
+ *
+ * I would appreciate (though I do not require) receiving a copy of any
+ * improvements you might make to this program.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/units/units.c,v 1.11.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $";
+#endif /* not lint */
+
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+#define VERSION "1.0"
+
+#ifndef UNITSFILE
+#define UNITSFILE _PATH_UNITSLIB
+#endif
+
+#define MAXUNITS 1000
+#define MAXPREFIXES 100
+
+#define MAXSUBUNITS 500
+
+#define PRIMITIVECHAR '!'
+
+const char *powerstring = "^";
+
+struct {
+ char *uname;
+ char *uval;
+} unittable[MAXUNITS];
+
+struct unittype {
+ char *numerator[MAXSUBUNITS];
+ char *denominator[MAXSUBUNITS];
+ double factor;
+ double offset;
+ int quantity;
+};
+
+struct {
+ char *prefixname;
+ char *prefixval;
+} prefixtable[MAXPREFIXES];
+
+
+char NULLUNIT[] = "";
+
+#ifdef MSDOS
+#define SEPARATOR ";"
+#else
+#define SEPARATOR ":"
+#endif
+
+int unitcount;
+int prefixcount;
+
+char *dupstr(const char *str);
+void readunits(const char *userfile);
+void initializeunit(struct unittype * theunit);
+int addsubunit(char *product[], char *toadd);
+void showunit(struct unittype * theunit);
+void zeroerror(void);
+int addunit(struct unittype *theunit, char *toadd, int flip, int quantity);
+int compare(const void *item1, const void *item2);
+void sortunit(struct unittype * theunit);
+void cancelunit(struct unittype * theunit);
+char *lookupunit(const char *unit);
+int reduceproduct(struct unittype * theunit, int flip);
+int reduceunit(struct unittype * theunit);
+int compareproducts(char **one, char **two);
+int compareunits(struct unittype * first, struct unittype * second);
+int completereduce(struct unittype * unit);
+void showanswer(struct unittype * have, struct unittype * want);
+void usage(void);
+
+char *
+dupstr(const char *str)
+{
+ char *ret;
+
+ ret = malloc(strlen(str) + 1);
+ if (!ret)
+ errx(3, "memory allocation error");
+ strcpy(ret, str);
+ return (ret);
+}
+
+
+void
+readunits(const char *userfile)
+{
+ FILE *unitfile;
+ char line[512], *lineptr;
+ int len, linenum, i;
+
+ unitcount = 0;
+ linenum = 0;
+
+ if (userfile) {
+ unitfile = fopen(userfile, "rt");
+ if (!unitfile)
+ errx(1, "unable to open units file '%s'", userfile);
+ }
+ else {
+ unitfile = fopen(UNITSFILE, "rt");
+ if (!unitfile) {
+ char *direc, *env;
+ char filename[1000];
+
+ env = getenv("PATH");
+ if (env) {
+ direc = strtok(env, SEPARATOR);
+ while (direc) {
+ snprintf(filename, sizeof(filename),
+ "%s/%s", direc, UNITSFILE);
+ unitfile = fopen(filename, "rt");
+ if (unitfile)
+ break;
+ direc = strtok(NULL, SEPARATOR);
+ }
+ }
+ if (!unitfile)
+ errx(1, "can't find units file '%s'", UNITSFILE);
+ }
+ }
+ while (!feof(unitfile)) {
+ if (!fgets(line, sizeof(line), unitfile))
+ break;
+ linenum++;
+ lineptr = line;
+ if (*lineptr == '/')
+ continue;
+ lineptr += strspn(lineptr, " \n\t");
+ len = strcspn(lineptr, " \n\t");
+ lineptr[len] = 0;
+ if (!strlen(lineptr))
+ continue;
+ if (lineptr[strlen(lineptr) - 1] == '-') { /* it's a prefix */
+ if (prefixcount == MAXPREFIXES) {
+ warnx("memory for prefixes exceeded in line %d", linenum);
+ continue;
+ }
+ lineptr[strlen(lineptr) - 1] = 0;
+ prefixtable[prefixcount].prefixname = dupstr(lineptr);
+ for (i = 0; i < prefixcount; i++)
+ if (!strcmp(prefixtable[i].prefixname, lineptr)) {
+ warnx("redefinition of prefix '%s' on line %d ignored",
+ lineptr, linenum);
+ continue;
+ }
+ lineptr += len + 1;
+ lineptr += strspn(lineptr, " \n\t");
+ len = strcspn(lineptr, "\n\t");
+ if (len == 0) {
+ warnx("unexpected end of prefix on line %d",
+ linenum);
+ continue;
+ }
+ lineptr[len] = 0;
+ prefixtable[prefixcount++].prefixval = dupstr(lineptr);
+ }
+ else { /* it's not a prefix */
+ if (unitcount == MAXUNITS) {
+ warnx("memory for units exceeded in line %d", linenum);
+ continue;
+ }
+ unittable[unitcount].uname = dupstr(lineptr);
+ for (i = 0; i < unitcount; i++)
+ if (!strcmp(unittable[i].uname, lineptr)) {
+ warnx("redefinition of unit '%s' on line %d ignored",
+ lineptr, linenum);
+ continue;
+ }
+ lineptr += len + 1;
+ lineptr += strspn(lineptr, " \n\t");
+ if (!strlen(lineptr)) {
+ warnx("unexpected end of unit on line %d",
+ linenum);
+ continue;
+ }
+ len = strcspn(lineptr, "\n\t");
+ lineptr[len] = 0;
+ unittable[unitcount++].uval = dupstr(lineptr);
+ }
+ }
+ fclose(unitfile);
+}
+
+void
+initializeunit(struct unittype * theunit)
+{
+ theunit->numerator[0] = theunit->denominator[0] = NULL;
+ theunit->factor = 1.0;
+ theunit->offset = 0.0;
+ theunit->quantity = 0;
+}
+
+
+int
+addsubunit(char *product[], char *toadd)
+{
+ char **ptr;
+
+ for (ptr = product; *ptr && *ptr != NULLUNIT; ptr++);
+ if (ptr >= product + MAXSUBUNITS) {
+ warnx("memory overflow in unit reduction");
+ return 1;
+ }
+ if (!*ptr)
+ *(ptr + 1) = 0;
+ *ptr = dupstr(toadd);
+ return 0;
+}
+
+
+void
+showunit(struct unittype * theunit)
+{
+ char **ptr;
+ int printedslash;
+ int counter = 1;
+
+ printf("\t%.8g", theunit->factor);
+ if (theunit->offset)
+ printf("&%.8g", theunit->offset);
+ for (ptr = theunit->numerator; *ptr; ptr++) {
+ if (ptr > theunit->numerator && **ptr &&
+ !strcmp(*ptr, *(ptr - 1)))
+ counter++;
+ else {
+ if (counter > 1)
+ printf("%s%d", powerstring, counter);
+ if (**ptr)
+ printf(" %s", *ptr);
+ counter = 1;
+ }
+ }
+ if (counter > 1)
+ printf("%s%d", powerstring, counter);
+ counter = 1;
+ printedslash = 0;
+ for (ptr = theunit->denominator; *ptr; ptr++) {
+ if (ptr > theunit->denominator && **ptr &&
+ !strcmp(*ptr, *(ptr - 1)))
+ counter++;
+ else {
+ if (counter > 1)
+ printf("%s%d", powerstring, counter);
+ if (**ptr) {
+ if (!printedslash)
+ printf(" /");
+ printedslash = 1;
+ printf(" %s", *ptr);
+ }
+ counter = 1;
+ }
+ }
+ if (counter > 1)
+ printf("%s%d", powerstring, counter);
+ printf("\n");
+}
+
+
+void
+zeroerror(void)
+{
+ warnx("unit reduces to zero");
+}
+
+/*
+ Adds the specified string to the unit.
+ Flip is 0 for adding normally, 1 for adding reciprocal.
+ Quantity is 1 if this is a quantity to be converted rather than a pure unit.
+
+ Returns 0 for successful addition, nonzero on error.
+*/
+
+int
+addunit(struct unittype * theunit, char *toadd, int flip, int quantity)
+{
+ char *scratch, *savescr;
+ char *item;
+ char *divider, *slash, *offset;
+ int doingtop;
+
+ if (!strlen(toadd))
+ return 1;
+
+ savescr = scratch = dupstr(toadd);
+ for (slash = scratch + 1; *slash; slash++)
+ if (*slash == '-' &&
+ (tolower(*(slash - 1)) != 'e' ||
+ !strchr(".0123456789", *(slash + 1))))
+ *slash = ' ';
+ slash = strchr(scratch, '/');
+ if (slash)
+ *slash = 0;
+ doingtop = 1;
+ do {
+ item = strtok(scratch, " *\t\n/");
+ while (item) {
+ if (strchr("0123456789.", *item)) { /* item is a number */
+ double num, offsetnum;
+
+ if (quantity)
+ theunit->quantity = 1;
+
+ offset = strchr(item, '&');
+ if (offset) {
+ *offset = 0;
+ offsetnum = atof(offset+1);
+ } else
+ offsetnum = 0.0;
+
+ divider = strchr(item, '|');
+ if (divider) {
+ *divider = 0;
+ num = atof(item);
+ if (!num) {
+ zeroerror();
+ return 1;
+ }
+ if (doingtop ^ flip) {
+ theunit->factor *= num;
+ theunit->offset *= num;
+ } else {
+ theunit->factor /= num;
+ theunit->offset /= num;
+ }
+ num = atof(divider + 1);
+ if (!num) {
+ zeroerror();
+ return 1;
+ }
+ if (doingtop ^ flip) {
+ theunit->factor /= num;
+ theunit->offset /= num;
+ } else {
+ theunit->factor *= num;
+ theunit->offset *= num;
+ }
+ }
+ else {
+ num = atof(item);
+ if (!num) {
+ zeroerror();
+ return 1;
+ }
+ if (doingtop ^ flip) {
+ theunit->factor *= num;
+ theunit->offset *= num;
+ } else {
+ theunit->factor /= num;
+ theunit->offset /= num;
+ }
+ }
+ if (doingtop ^ flip)
+ theunit->offset += offsetnum;
+ }
+ else { /* item is not a number */
+ int repeat = 1;
+
+ if (strchr("23456789",
+ item[strlen(item) - 1])) {
+ repeat = item[strlen(item) - 1] - '0';
+ item[strlen(item) - 1] = 0;
+ }
+ for (; repeat; repeat--)
+ if (addsubunit(doingtop ^ flip ? theunit->numerator : theunit->denominator, item))
+ return 1;
+ }
+ item = strtok(NULL, " *\t/\n");
+ }
+ doingtop--;
+ if (slash) {
+ scratch = slash + 1;
+ }
+ else
+ doingtop--;
+ } while (doingtop >= 0);
+ free(savescr);
+ return 0;
+}
+
+
+int
+compare(const void *item1, const void *item2)
+{
+ return strcmp(*(const char * const *)item1, *(const char * const *)item2);
+}
+
+
+void
+sortunit(struct unittype * theunit)
+{
+ char **ptr;
+ unsigned int count;
+
+ for (count = 0, ptr = theunit->numerator; *ptr; ptr++, count++);
+ qsort(theunit->numerator, count, sizeof(char *), compare);
+ for (count = 0, ptr = theunit->denominator; *ptr; ptr++, count++);
+ qsort(theunit->denominator, count, sizeof(char *), compare);
+}
+
+
+void
+cancelunit(struct unittype * theunit)
+{
+ char **den, **num;
+ int comp;
+
+ den = theunit->denominator;
+ num = theunit->numerator;
+
+ while (*num && *den) {
+ comp = strcmp(*den, *num);
+ if (!comp) {
+/* if (*den!=NULLUNIT) free(*den);
+ if (*num!=NULLUNIT) free(*num);*/
+ *den++ = NULLUNIT;
+ *num++ = NULLUNIT;
+ }
+ else if (comp < 0)
+ den++;
+ else
+ num++;
+ }
+}
+
+
+
+
+/*
+ Looks up the definition for the specified unit.
+ Returns a pointer to the definition or a null pointer
+ if the specified unit does not appear in the units table.
+*/
+
+static char buffer[100]; /* buffer for lookupunit answers with
+ prefixes */
+
+char *
+lookupunit(const char *unit)
+{
+ int i;
+ char *copy;
+
+ for (i = 0; i < unitcount; i++) {
+ if (!strcmp(unittable[i].uname, unit))
+ return unittable[i].uval;
+ }
+
+ if (unit[strlen(unit) - 1] == '^') {
+ copy = dupstr(unit);
+ copy[strlen(copy) - 1] = 0;
+ for (i = 0; i < unitcount; i++) {
+ if (!strcmp(unittable[i].uname, copy)) {
+ strlcpy(buffer, copy, sizeof(buffer));
+ free(copy);
+ return buffer;
+ }
+ }
+ free(copy);
+ }
+ if (unit[strlen(unit) - 1] == 's') {
+ copy = dupstr(unit);
+ copy[strlen(copy) - 1] = 0;
+ for (i = 0; i < unitcount; i++) {
+ if (!strcmp(unittable[i].uname, copy)) {
+ strlcpy(buffer, copy, sizeof(buffer));
+ free(copy);
+ return buffer;
+ }
+ }
+ if (copy[strlen(copy) - 1] == 'e') {
+ copy[strlen(copy) - 1] = 0;
+ for (i = 0; i < unitcount; i++) {
+ if (!strcmp(unittable[i].uname, copy)) {
+ strlcpy(buffer, copy, sizeof(buffer));
+ free(copy);
+ return buffer;
+ }
+ }
+ }
+ free(copy);
+ }
+ for (i = 0; i < prefixcount; i++) {
+ size_t len = strlen(prefixtable[i].prefixname);
+ if (len && !strncmp(prefixtable[i].prefixname, unit, len)) {
+ if (!strlen(unit + len) || lookupunit(unit + len)) {
+ snprintf(buffer, sizeof(buffer), "%s %s",
+ prefixtable[i].prefixval, unit + len);
+ return buffer;
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+/*
+ reduces a product of symbolic units to primitive units.
+ The three low bits are used to return flags:
+
+ bit 0 (1) set on if reductions were performed without error.
+ bit 1 (2) set on if no reductions are performed.
+ bit 2 (4) set on if an unknown unit is discovered.
+*/
+
+
+#define ERROR 4
+
+int
+reduceproduct(struct unittype * theunit, int flip)
+{
+
+ char *toadd;
+ char **product;
+ int didsomething = 2;
+
+ if (flip)
+ product = theunit->denominator;
+ else
+ product = theunit->numerator;
+
+ for (; *product; product++) {
+
+ for (;;) {
+ if (!strlen(*product))
+ break;
+ toadd = lookupunit(*product);
+ if (!toadd) {
+ printf("unknown unit '%s'\n", *product);
+ return ERROR;
+ }
+ if (strchr(toadd, PRIMITIVECHAR))
+ break;
+ didsomething = 1;
+ if (*product != NULLUNIT) {
+ free(*product);
+ *product = NULLUNIT;
+ }
+ if (addunit(theunit, toadd, flip, 0))
+ return ERROR;
+ }
+ }
+ return didsomething;
+}
+
+
+/*
+ Reduces numerator and denominator of the specified unit.
+ Returns 0 on success, or 1 on unknown unit error.
+*/
+
+int
+reduceunit(struct unittype * theunit)
+{
+ int ret;
+
+ ret = 1;
+ while (ret & 1) {
+ ret = reduceproduct(theunit, 0) | reduceproduct(theunit, 1);
+ if (ret & 4)
+ return 1;
+ }
+ return 0;
+}
+
+
+int
+compareproducts(char **one, char **two)
+{
+ while (*one || *two) {
+ if (!*one && *two != NULLUNIT)
+ return 1;
+ if (!*two && *one != NULLUNIT)
+ return 1;
+ if (*one == NULLUNIT)
+ one++;
+ else if (*two == NULLUNIT)
+ two++;
+ else if (strcmp(*one, *two))
+ return 1;
+ else
+ one++, two++;
+ }
+ return 0;
+}
+
+
+/* Return zero if units are compatible, nonzero otherwise */
+
+int
+compareunits(struct unittype * first, struct unittype * second)
+{
+ return
+ compareproducts(first->numerator, second->numerator) ||
+ compareproducts(first->denominator, second->denominator);
+}
+
+
+int
+completereduce(struct unittype * unit)
+{
+ if (reduceunit(unit))
+ return 1;
+ sortunit(unit);
+ cancelunit(unit);
+ return 0;
+}
+
+
+void
+showanswer(struct unittype * have, struct unittype * want)
+{
+ if (compareunits(have, want)) {
+ printf("conformability error\n");
+ showunit(have);
+ showunit(want);
+ }
+ else if (have->offset != want->offset) {
+ if (want->quantity)
+ printf("WARNING: conversion of non-proportional quantities.\n");
+ printf("\t");
+ if (have->quantity)
+ printf("%.8g\n",
+ (have->factor + have->offset-want->offset)/want->factor);
+ else
+ printf(" (-> x*%.8g %+.8g)\n\t (<- y*%.8g %+.8g)\n",
+ have->factor / want->factor,
+ (have->offset-want->offset)/want->factor,
+ want->factor / have->factor,
+ (want->offset - have->offset)/have->factor);
+ }
+ else
+ printf("\t* %.8g\n\t/ %.8g\n", have->factor / want->factor,
+ want->factor / have->factor);
+}
+
+
+void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: units [-f unitsfile] [-q] [-v] [from-unit to-unit]\n");
+ exit(3);
+}
+
+
+int
+main(int argc, char **argv)
+{
+
+ struct unittype have, want;
+ char havestr[81], wantstr[81];
+ int optchar;
+ char *userfile = 0;
+ int quiet = 0;
+
+ while ((optchar = getopt(argc, argv, "vqf:")) != -1) {
+ switch (optchar) {
+ case 'f':
+ userfile = optarg;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'v':
+ fprintf(stderr, "\n units version %s Copyright (c) 1993 by Adrian Mariano\n",
+ VERSION);
+ fprintf(stderr, " This program may be freely distributed\n");
+ usage();
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (optind != argc - 2 && optind != argc)
+ usage();
+
+ readunits(userfile);
+
+ if (optind == argc - 2) {
+ strlcpy(havestr, argv[optind], sizeof(havestr));
+ strlcpy(wantstr, argv[optind + 1], sizeof(wantstr));
+ initializeunit(&have);
+ addunit(&have, havestr, 0, 1);
+ completereduce(&have);
+ initializeunit(&want);
+ addunit(&want, wantstr, 0, 1);
+ completereduce(&want);
+ showanswer(&have, &want);
+ }
+ else {
+ if (!quiet)
+ printf("%d units, %d prefixes\n", unitcount,
+ prefixcount);
+ for (;;) {
+ do {
+ initializeunit(&have);
+ if (!quiet)
+ printf("You have: ");
+ if (!fgets(havestr, sizeof(havestr), stdin)) {
+ if (!quiet)
+ putchar('\n');
+ exit(0);
+ }
+ } while (addunit(&have, havestr, 0, 1) ||
+ completereduce(&have));
+ do {
+ initializeunit(&want);
+ if (!quiet)
+ printf("You want: ");
+ if (!fgets(wantstr, sizeof(wantstr), stdin)) {
+ if (!quiet)
+ putchar('\n');
+ exit(0);
+ }
+ } while (addunit(&want, wantstr, 0, 1) ||
+ completereduce(&want));
+ showanswer(&have, &want);
+ }
+ }
+
+ return(0);
+}
diff --git a/misc_cmds/units/units.lib b/misc_cmds/units/units.lib
new file mode 100644
index 0000000..9d415ef
--- /dev/null
+++ b/misc_cmds/units/units.lib
@@ -0,0 +1,732 @@
+/ $FreeBSD: src/usr.bin/units/units.lib,v 1.19.2.1.2.1 2009/10/25 01:10:29 kensmith Exp $
+
+/ primitive units
+
+m !a!
+kg !b!
+sec !c!
+coul !d!
+candela !e!
+usdollar !f!
+euro !g!
+bit !h!
+erlang !i!
+K !j!
+
+/ prefixes
+
+yotta- 1e24
+zetta- 1e21
+exa- 1e18
+peta- 1e15
+tera- 1e12
+giga- 1e9
+mega- 1e6
+myria- 1e4
+kilo- 1e3
+hecto- 1e2
+deka- 1e1
+deca- deka
+deci- 1e-1
+centi- 1e-2
+milli- 1e-3
+micro- 1e-6
+nano- 1e-9
+pico- 1e-12
+femto- 1e-15
+atto- 1e-18
+zopto- 1e-21
+zepto- zopto
+yocto- 1e-24
+
+semi- .5
+demi- .5
+
+Y- yotta
+Z- zetta
+E- exa
+P- peta
+T- tera
+G- giga
+M- mega
+k- kilo
+h- hecto
+da- deka
+d- deci
+c- centi
+m- milli
+n- nano
+p- pico
+f- femto
+a- atto
+z- zopto
+y- yocto
+
+/ binary prefixes introduced in 1999
+exbi- 1152921504606846976
+pebi- 1125899906842624
+tebi- 1099511627776
+gibi- 1073741824
+mebi- 1048576
+kibi- 1024
+
+Ei- exbi
+Pi- pebi
+Ti- tebi
+Gi- gibi
+Mi- mebi
+Ki- kibi
+
+/ constants
+
+fuzz 1
+pi 3.14159265358979323846
+c 2.99792458e+8 m/sec
+g0 9.80665 m/sec2
+g g0
+bigG 6.67428e-11 m3/kg/s2
+AU 1.49597870691e+11 m fuzz
+au AU
+mole 6.0221417930e+23 fuzz
+e 1.6021917e-19 coul fuzz
+energy c2
+force g
+mercury 1.3332239e+5 kg/m2-sec2
+hg mercury
+mmHg 0.001 m hg
+#mu 4.e-7 pi-N/A2
+epsilon 1.0 /mu/c2
+alpha 0.5 mu-c-e2/planck
+planck 6.6260755e-34 joule-sec
+hbar 0.5 planck/pi
+electronmass 9.1093821545-31 kg
+protonmass 1.6726217129-27 kg
+neutronmass 1.6749272928-27 kg
+
+/ dimensionless
+
+radian .5 / pi
+degree 1|180 pi-radian
+circle 2 pi-radian
+turn 2 pi-radian
+revolution turn
+rev turn
+grade .9 degree
+arcdeg 1 degree
+arcmin 1|60 arcdeg
+ccs 1|36 erlang
+arcsec 1|60 arcmin
+
+steradian radian2
+sphere 4 pi-steradian
+sr steradian
+
+/ Time
+
+second sec
+s sec
+minute 60 sec
+min minute
+hour 60 min
+hr hour
+day 24 hr
+da day
+week 7 day
+year 365.24219879 day fuzz
+yr year
+month 1|12 year
+us microsec
+
+/ Mass
+
+gram millikg
+gm gram
+metricton kilokg
+
+/ Avoirdupois
+
+lb .45359237 kg
+pound lb
+lbf lb g
+ounce 1|16 lb
+oz ounce
+dram 1|16 oz
+dr dram
+grain 1|7000 lb
+gr grain
+shortton 2000 lb
+ton shortton
+longton 2240 lb
+
+/ Apothecary
+
+scruple 20 grain
+apdram 60 grain
+apounce 480 grain
+appound 5760 grain
+troypound appound
+
+/ Mining
+
+troyounce apounce
+troz apounce
+pennyweight 1|20 troz
+pwt pennyweight
+dwt pennyweight
+
+/ Length
+
+meter m
+micron micrometer
+angstrom decinanometer
+ao 0.25 alpha/pi/rydbergconst
+
+inch 2.54 cm
+in inch
+foot 12 in
+feet foot
+ft foot
+yard 3 ft
+yd yard
+rod 5.5 yd
+rd rod
+mile 5280 ft
+mi mile
+
+british 1200|3937 m/ft
+nmile 1852 m
+
+acre 4840 yd2
+
+cc cm3
+liter kilocc
+ml milliliter
+
+/ US Liquid
+
+gallon 231 in3
+imperial 1.20095
+gal gallon
+quart 1|4 gal
+qt quart
+pint 1|2 qt
+pt pint
+
+floz 1|16 pt
+fldr 1|8 floz
+shot 3|2 floz
+
+/ US Dry
+
+dry 268.8025 in3/gallon fuzz
+peck 8 dry-quart
+pk peck
+bushel 4 peck
+bu bushel
+chaldron 36 bushel
+
+/ British
+
+brgallon 277.420 in3 fuzz
+brquart 1|4 brgallon
+brpint 1|2 brquart
+brfloz 1|20 brpint
+brpeck 554.84 in3 fuzz
+brbushel 4 brpeck
+brhundredweight 112 lb
+
+/ Bottles
+
+bottle 750 milliliter
+/bottle fifth
+
+miniature 100 milliliter
+split 1|4 bottle
+half 1|2 bottle
+magnum 2 bottle
+jeroboam 4 bottle
+rehoboam 6 bottle
+methuselah 8 bottle
+salmanazar 12 bottle
+balthazar 16 bottle
+nebuchadnezzar 20 bottle
+sovereign 34 bottle
+
+/ Bottles - alternate names and spellings
+
+pony split
+fillette half
+tappit-hen 3 imperial
+rheoboam rehoboam
+shalmaneser salmanazar
+
+/ Russian
+berkovets 10 pood
+pood 40 funt
+funt 0.40951 kg
+lot 1|32 funt
+zolotnik 1|3 lot
+dolya 1|96 zolotnik
+rumile 7 verst
+mezhevayaverst 2 verst
+verst 1066.8 m
+sazhen 1|500 verst
+kosayasazhen 1|430.2 verst
+arshin 1|1500 verst
+/ is not exactly defined
+ruell 16.54 in
+liniya 1|10 in
+vershok 1.75 in
+pyad 7 in
+vedro 12.3 liter
+shtoff 1|10 vedro
+vinebottle 1|16 vedro
+vodkabottle 1|20 vedro
+charka 1|100 vedro
+shkalik 1|200 vedro
+desyatina_state 109.3 are
+desyatina_farmery 0.75 desyatina_state
+sqverst 104.2 desyatina_state
+sqarshin 1|21600 desyatina_state
+sqfoot 1|117600 desyatina_state
+
+/ Energy Work
+
+newton kg-m/sec2
+nt newton
+N newton
+joule nt-m
+J joule
+cal 4.1868 joule
+
+/ Electrical
+
+coulomb coul
+C coul
+ampere coul/sec
+A ampere
+amp ampere
+watt joule/sec
+W watt
+volt watt/amp
+ohm volt/amp
+mho /ohm
+farad coul/volt
+F farad
+henry sec2/farad
+H henry
+weber volt-sec
+Wb weber
+
+/ Light
+
+cd candela
+lumen cd sr
+lux cd sr/m2
+
+/ EMU currencies have constant exchange rate against Euro since 1.1.1999.
+/ See http://en.wikipedia.org/wiki/Euro for details.
+austriaschilling 1|13.7603 euro
+belgiumfranc 1|40.3399 euro
+finlandmarkka 1|5.94573 euro
+francefranc 1|6.55957 euro
+germanymark 1|1.95583 euro
+greecedrachma 1|340.750 euro
+irelandpunt 1|0.787564 euro
+italylira 1|1936.27 euro
+luxembourgfranc 1|40.3399 euro
+netherlandsguilder 1|2.20371 euro
+portugalescudo 1|200.482 euro
+spainpeseta 1|166.386 euro
+sloveniantolar 1|239.640 euro
+cypriotpound 1|0.585274 euro
+malteselira 1|0.429300 euro
+slovakkoruna 1|30.1260 euro
+
+/ These ones are pegged to the Euro
+/ See http://en.wikipedia.org/wiki/Euro for details.
+bosniaherzegovinamark 1|1.95583 euro
+bulgarianlev 1|1.95583 euro
+capeverdeanescudo 1|110.265 euro
+centralafricancfafranc 1|655.957 euro
+comorosfranc 1|491.96775 euro
+danishkrone 1|7.46038 euro
+estoniakroon 1|15.6466 euro
+lithuanianlitas 1|3.45280 euro
+pacificfrancexchange 1|0.00838 euro
+westafricancfafranc 1|655.957 euro
+
+/ These ones are pegged on the US Dollar
+/ See http://en.wikipedia.org/wiki/USD for details.
+dollar usdollar
+arubanflorin 1|1.75 usdollar
+bahamiandollar 1|1 usdollar
+bahrainidinar 1|0.376 usdollar
+barbadiandollar 1|2 usdollar
+belizedollar 1|2 usdollar
+belarusianruble 1|2135 usdollar
+bermudiandollar 1|1 usdollar
+caymanislandsdollar 1.2 usdollar
+cubanconvertiblepeso 1.08 usdollar
+djiboutianfranc 1|177.721 usdollar
+eastcaribbeandollar 1|2.7 usdollar
+eritreannakfa 1|15 usdollar
+hongkongdollar 1|7.80 usdollar
+macanesepatacas 1|1.03 hongkongdollar
+jordaniandinar 1|0.709 usdollar
+lebanesepound 1|1507.5 usdollar
+maldivianrufiyaa 1|12.8 usdollar
+netherlandsantilleanguilder 1|1.79 usdollar
+omanirial 2.6008 usdollar
+qataririyal 1|3.64 usdollar
+saudiriyal 1|3.75 usdollar
+unitedarabemiratesdirham 1|3.6725 usdollar
+
+bosniamark bosniaherzegovinamark
+cfafranc centralafricancfafranc
+cfpfranc pacificfrancexchange
+drachma greecedrachma
+escudo portugalescudo
+franc francefranc
+guilder netherlandsguilder
+herzegovinamark bosniaherzegovinamark
+hollandguilder netherlandsguilder
+lira italylira
+mark germanymark
+markka finlandmarkka
+peseta spainpeseta
+rand southafricarand
+
+/ computer
+
+baud bit/sec
+nibble 4 bit
+nybble nibble
+byte 8 bit
+word 2 byte
+block 512 byte
+kbyte 1024 byte
+megabyte 1024 kbyte
+gigabyte 1024 megabyte
+terabyte 1024 gigabyte
+petabyte 1024 terabyte
+exabyte 1024 petabyte
+zettabyte 1024 exabyte
+yottabyte 1024 zettabyte
+kilobyte kbyte
+meg megabyte
+
+
+/ Trivia
+
+% 1|100
+abampere 10 ampere
+admiraltyknot 6080 ft/hr
+apostilb cd/pi-m2
+are 1e+2 m2
+asb apostilb
+arpentcan 27.52 mi
+arpentlin 191.835 ft
+astronomicalunit au
+atmosphere 1.01325e+5 nt/m2
+atm atmosphere
+atomicmassunit 1.66053878283e-27 kg fuzz
+# year 3.15569259747e7 sec fuzz
+amu atomicmassunit
+bag 94 lb
+bakersdozen 13
+bar 1e+5 nt/m2
+barie 1e-1 nt/m2
+barleycorn 1|3 in
+barn 1e-28 m2
+oilbarrel 42 gal
+barrel oilbarrel
+barye 1e-1 nt/m2
+baryl microbar
+bev 1e+9 e-volt
+biot 10 amp
+blondel cd/pi-m2
+boardfoot 144 in3
+bolt 40 yd
+bottommeasure 1|40 in
+britishthermalunit 1.05506e+3 joule fuzz
+btu britishthermalunit
+refrigeration 12000 btu/ton-hour
+buck usdollar
+cable 720 ft
+caliber 1e-2 in
+calorie cal
+carat 205 milligram
+caratgold 1|24
+cent centidollar
+cental 100 lb
+centesimalminute 1e-2 grade
+centesimalsecond 1e-4 grade
+century 100 year
+cfs ft3/sec
+chain 66 ft
+circularinch 1|4 pi-in2
+circularmil 1e-6|4 pi-in2
+clusec 1e-8 mm-hg m3/s
+coomb 4 bu
+cord 128 ft3
+cordfoot cord
+crith 9.06e-2 gm
+cubit 18 in
+cup 1|2 pt
+curie 3.7e+10 /sec
+dalton amu
+decade 10 yr
+dioptre /m
+displacementton 35 ft3
+doppelzentner 100 kg
+dozen 12
+drop .03 cm3
+dyne cm-gm/sec2
+electronvolt e-volt
+ell 45 in
+engineerschain 100 ft
+engineerslink 100|100 ft
+equivalentfootcandle lumen/pi-ft2
+equivalentlux lumen/pi-m2
+equivalentphot cd/pi-cm2
+erg cm2-gm/sec2
+ev e-volt
+faraday 9.6485309e+4 coul
+fathom 6 ft
+fermi 1e-15 m
+fifth 4|5 qt
+fin 5 usdollar
+finger 7|8 in
+firkin 9 gal
+footcandle lumen/ft2
+footlambert cd/pi-ft2
+fortnight 14 da
+franklin 3.33564e-10 coul
+frigorie kilocal
+furlong 220 yd
+galileo 1e-2 m/sec2
+gamma 1e-9 weber/m2
+gauss 1e-4 weber/m2
+G gauss
+geodeticfoot british-ft
+geographicalmile 1852 m
+gilbert 2.5 amp/pi
+gill 1|4 pt
+gross 144
+gunterschain 22 yd
+hand 4 in
+hartree 2 rydberg
+head water
+hectare 1e+4 m2
+hefnercandle .92 cd
+hertz /sec
+Hz hertz
+hogshead 63 gallon
+hd hogshead
+homestead 1|4 mi2
+horsepower 735.50 watt
+hp horsepower
+hubble 1e9 ly
+hyl gm force sec2/m
+hz /sec
+imaginarycubicfoot 1.4 ft3
+jansky 1e-26 W/m2-Hz
+Jy jansky
+karat 1|24
+kayser /cm
+key kg
+kilderkin 18 gal
+knot nmile/hr
+kn knot
+lambert cd/pi-cm2
+Lb lambert
+langley cal/cm2
+last 80 bu
+league 3 mi
+lightyear c-yr
+ly lightyear
+line 1|12 in
+link 66|100 ft
+longhundredweight 112 lb
+longquarter 28 lb
+lusec 1e-6 mm-hg m3/s
+m_earth 5.97223e24 kg
+m_moon 7.34e22 kg
+m_sun 1.98843e30 kg
+mach 331.46 m/sec
+marineleague 3 nmile
+maxwell 1e-8 weber
+Mx maxwell
+metriccarat 200 milligram
+mgd megagal/day
+mh millihenry
+mil 1e-3 in
+millennium 1000 year
+minersinch 1.5 ft3/min
+minim 1|60 fldr
+mo month
+mpg mile/gal
+mph mile/hr
+nail 1|16 yd
+nauticalmile nmile
+nit cd/m2
+noggin 1|8 qt
+nox 1e-3 lux
+oersted 2.5e+2 amp/m/pi
+Oe oersted
+pace 36 in
+pair 2
+palm 3 in
+parasang 3.5 mi
+parsec AU-radian/arcsec
+pascal nt/m2
+Pa pascal
+pc parsec
+percent %
+perch rd
+phot lumen/cm2
+pica 1|6 in
+pieze 1e+3 nt/m2
+pipe 4 barrel
+point 1|72 in
+poise gm/cm-sec
+P poise
+pole rd
+pond 9.80665e-3 nt
+poundal ft-lb/sec2
+pdl poundal
+proof 1|200
+psi lb-g/in2
+quarter 9 in
+quartersection 1|4 mi2
+quintal 100 kg
+quire 25
+r_earth 6.378e8 cm
+r_moon 1.738e7 cm
+r_sun 6.9599e10 cm
+rackunit 1.75 in
+rad 100 erg/gm
+ream 500
+registerton 100 ft3
+rem 0.01 J/kg
+rhe 10 m2/nt-sec
+rontgen 2.58e-4 curie/kg
+roentgen rontgen
+rood 1.21e+3 yd
+rope 20 ft
+RU rackunit
+rutherford 1e+6 /sec
+rydbergconst 0.5 elctronmass-c-alpha2/planck
+rydberg rydbergconst-planck-c
+sabin 1 ft2
+sack 3 bu
+score 20
+seam 8 bu
+section mi2
+shed 1e-24 barn
+shippington 40 ft3
+shorthundredweight 100 lb
+shortquarter 25 lb
+siemens /ohm
+sigma microsec
+skein 120 yd
+skot 1e-3 apostilb
+slug lb-g-sec2/ft
+smoot 67 in
+span 9 in
+spat 4 pi sr
+spindle 14400 yd
+square 100 ft2
+stere m3
+sthene 1e+3 nt
+stilb cd/cm2
+sb stilb
+stoke 1e-4 m2/sec
+stone 14 lb
+strike 2 bu
+surveyfoot british-ft
+surveyyard 3 surveyfoot
+surveyorschain 66 ft
+surveyorslink 66|100 ft
+tablespoon 4 fldr
+tbl tablespoon
+tbsp tablespoon
+teaspoon 4|3 fldr
+tesla weber/m2
+T tesla
+therm 1e+5 btu
+thermie 1e+6 cal
+timberfoot ft3
+tnt 4.6e+6 m2/sec2
+tonne 1e+6 gm
+torr mm hg
+township 36 mi2
+tsp teaspoon
+tun 8 barrel
+water gram g / cc
+wey 40 bu
+weymass 252 lb
+Xunit 1.00206e-13 m
+k 1.38047e-16 erg/degC
+
+
+degC 1&+273.15 K
+kelvin K
+brewster 1e-12 m2/newton
+degF 5|9&255.37222222222222222222 K
+degreesrankine 5|9 K
+degrankine degreesrankine
+degreerankine degreesrankine
+degreaumur 10|8&+273.15 K
+drachm 60 grain
+poncelet 100 kg m g / sec
+denier .05|450 gram / m
+tex .001 gram / m
+englishell 45 inch
+scottishell 37.2 inch
+flemishell 27 inch
+V volt
+eV e V
+bohrradius hbar2-C2/8.988e9 N m2-e2-electronmass
+becquerel 1|3.7e10 curie
+fresnel 1e12 hertz
+statcoul 1|2.99792458e9 coul
+statamp 1|2.99792458e9 amp
+statvolt 2.99792458e2 volt
+statcoulomb statcoul
+statampere statamp
+debye 3.33564e-30 coul-m
+pulsatance 2 pi/sec
+rpm rev/minute
+rps rev/sec
+kilohm kiloohm
+megohm megaohm
+siderealyear 365.256360417 day
+siderealday 23.934469444 hour
+siderealhour 1|24 sidereal day
+lunarmonth 29.5305555 day
+synodicmonth lunarmonth
+siderealmonth 27.32152777 day
+tropicalyear year
+solaryear year
+lunaryear 12 lunarmonth
+cran 37.5 brgallon
+kip 1000 lbf
+frenchfoot 16|15 ft
+frenchfeet frenchfoot
+toise 6 frenchfeet
+sievert 8.4 rontgen
+candle 1.02 candela
+militarypace 2.5 feet
+metre meter
+litre liter
+gramme gram
+iudiptheria 62.8 microgram
+iupenicillin .6 microgram
+iuinsulin 41.67 microgram
+cottonyarncount 2520 ft/pound
+linenyarncount 900 ft/pound
+worstedyarncount 1680 ft/pound
+metricyarncount meter/gram
+jewlerspoint 2 milligram
diff --git a/network_cmds/APPLE_LICENSE b/network_cmds/APPLE_LICENSE
new file mode 100644
index 0000000..e7aa7d0
--- /dev/null
+++ b/network_cmds/APPLE_LICENSE
@@ -0,0 +1,370 @@
+ APPLE PUBLIC SOURCE LICENSE
+ Version 1.0 - March 16, 1999
+
+Please read this License carefully before downloading this software.
+By downloading and using this software, you are agreeing to be bound
+by the terms of this License. If you do not or cannot agree to the
+terms of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+ work which Apple Computer, Inc. ("Apple") publicly announces as
+ subject to this Apple Public Source License and which contains a
+ notice placed by Apple identifying such program or work as "Original
+ Code" and stating that it is subject to the terms of this Apple
+ Public Source License version 1.0 (or subsequent version thereof),
+ as it may be revised from time to time by Apple ("License"). As
+ used in this License:
+
+1.1 "Applicable Patents" mean: (a) in the case where Apple is the
+ grantor of rights, (i) patents or patent applications that are now
+ or hereafter acquired, owned by or assigned to Apple and (ii) whose
+ claims cover subject matter contained in the Original Code, but only
+ to the extent necessary to use, reproduce and/or distribute the
+ Original Code without infringement; and (b) in the case where You
+ are the grantor of rights, (i) patents and patent applications that
+ are now or hereafter acquired, owned by or assigned to You and (ii)
+ whose claims cover subject matter in Your Modifications, taken alone
+ or in combination with Original Code.
+
+1.2 "Covered Code" means the Original Code, Modifications, the
+ combination of Original Code and any Modifications, and/or any
+ respective portions thereof.
+
+1.3 "Deploy" means to use, sublicense or distribute Covered Code other
+ than for Your internal research and development (R&D), and includes
+ without limitation, any and all internal use or distribution of
+ Covered Code within Your business or organization except for R&D
+ use, as well as direct or indirect sublicensing or distribution of
+ Covered Code by You to any third party in any form or manner.
+
+1.4 "Larger Work" means a work which combines Covered Code or portions
+ thereof with code not governed by the terms of this License.
+
+1.5 "Modifications" mean any addition to, deletion from, and/or change
+ to, the substance and/or structure of Covered Code. When code is
+ released as a series of files, a Modification is: (a) any addition
+ to or deletion from the contents of a file containing Covered Code;
+ and/or (b) any new file or other representation of computer program
+ statements that contains any part of Covered Code.
+
+1.6 "Original Code" means the Source Code of a program or other work
+ as originally made available by Apple under this License, including
+ the Source Code of any updates or upgrades to such programs or works
+ made available by Apple under this License, and that has been
+ expressly identified by Apple as such in the header file(s) of such
+ work.
+
+1.7 "Source Code" means the human readable form of a program or other
+ work that is suitable for making modifications to it, including all
+ modules it contains, plus any associated interface definition files,
+ scripts used to control compilation and installation of an
+ executable (object code).
+
+1.8 "You" or "Your" means an individual or a legal entity exercising
+ rights under this License. For legal entities, "You" or "Your"
+ includes any entity which controls, is controlled by, or is under
+ common control with, You, where "control" means (a) the power,
+ direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership of fifty
+ percent (50%) or more of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+ and conditions of this License, Apple hereby grants You, effective
+ on the date You accept this License and download the Original Code,
+ a world-wide, royalty-free, non-exclusive license, to the extent of
+ Apple's Applicable Patents and copyrights covering the Original
+ Code, to do the following:
+
+2.1 You may use, copy, modify and distribute Original Code, with or
+ without Modifications, solely for Your internal research and
+ development, provided that You must in each instance:
+
+(a) retain and reproduce in all copies of Original Code the copyright
+and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code
+that refer to this License;
+
+(b) include a copy of this License with every copy of Source Code of
+Covered Code and documentation You distribute, and You may not offer
+or impose any terms on such Source Code that alter or restrict this
+License or the recipients' rights hereunder, except as permitted under
+Section 6; and
+
+(c) completely and accurately document all Modifications that you have
+made and the date of each such Modification, designate the version of
+the Original Code you used, prominently include a file carrying such
+information with the Modifications, and duplicate the notice in
+Exhibit A in each file of the Source Code of all such Modifications.
+
+2.2 You may Deploy Covered Code, provided that You must in each
+ instance:
+
+(a) satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) make all Your Deployed Modifications publicly available in Source
+Code form via electronic distribution (e.g. download from a web site)
+under the terms of this License and subject to the license grants set
+forth in Section 3 below, and any additional terms You may choose to
+offer under Section 6. You must continue to make the Source Code of
+Your Deployed Modifications available for as long as you Deploy the
+Covered Code or twelve (12) months from the date of initial
+Deployment, whichever is longer;
+
+(c) must notify Apple and other third parties of how to obtain Your
+Deployed Modifications by filling out and submitting the required
+information found at
+http://www.apple.com/publicsource/modifications.html; and
+
+(d) if you Deploy Covered Code in object code, executable form only,
+include a prominent notice, in the code itself as well as in related
+documentation, stating that Source Code of the Covered Code is
+available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+ licenses granted to You under this License:
+
+(a) You hereby grant to Apple and all third parties a non-exclusive,
+royalty-free license, under Your Applicable Patents and other
+intellectual property rights owned or controlled by You, to use,
+reproduce, modify, distribute and Deploy Your Modifications of the
+same scope and extent as Apple's licenses under Sections 2.1 and 2.2;
+and
+
+(b) You hereby grant to Apple and its subsidiaries a non-exclusive,
+worldwide, royalty-free, perpetual and irrevocable license, under Your
+Applicable Patents and other intellectual property rights owned or
+controlled by You, to use, reproduce, execute, compile, display,
+perform, modify or have modified (for Apple and/or its subsidiaries),
+sublicense and distribute Your Modifications, in any form, through
+multiple tiers of distribution.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+ Code with other code not governed by the terms of this License and
+ distribute the Larger Work as a single product. In each such
+ instance, You must make sure the requirements of this License are
+ fulfilled for the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+ Section 2, no other patent rights, express or implied, are granted
+ by Apple herein. Modifications and/or Larger Works may require
+ additional patent licenses from Apple which Apple may grant in its
+ sole discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee
+ for, warranty, support, indemnity or liability obligations and/or
+ other rights consistent with the scope of the license granted herein
+ ("Additional Terms") to one or more recipients of Covered
+ Code. However, You may do so only on Your own behalf and as Your
+ sole responsibility, and not on behalf of Apple. You must obtain the
+ recipient's agreement that any such Additional Terms are offered by
+ You alone, and You hereby agree to indemnify, defend and hold Apple
+ harmless for any liability incurred by or claims asserted against
+ Apple by reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+ versions of this License from time to time. Each version will be
+ given a distinguishing version number. Once Original Code has been
+ published under a particular version of this License, You may
+ continue to use it under the terms of that version. You may also
+ choose to use such Original Code under the terms of any subsequent
+ version of this License published by Apple. No one other than Apple
+ has the right to modify the terms applicable to Covered Code created
+ under this License.
+
+8. NO WARRANTY OR SUPPORT. The Original Code may contain in whole or
+ in part pre-release, untested, or not fully tested works. The
+ Original Code may contain errors that could cause failures or loss
+ of data, and may be incomplete or contain inaccuracies. You
+ expressly acknowledge and agree that use of the Original Code, or
+ any portion thereof, is at Your sole and entire risk. THE ORIGINAL
+ CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT
+ OF ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF
+ SECTIONS 8 AND 9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY
+ REFERRED TO AS "APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR
+ CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY OR
+ SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE DOES NOT WARRANT THAT
+ THE FUNCTIONS CONTAINED IN THE ORIGINAL CODE WILL MEET YOUR
+ REQUIREMENTS, OR THAT THE OPERATION OF THE ORIGINAL CODE WILL BE
+ UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE ORIGINAL CODE
+ WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN
+ BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE SHALL CREATE A
+ WARRANTY OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY. You
+ acknowledge that the Original Code is not intended for use in the
+ operation of nuclear facilities, aircraft navigation, communication
+ systems, or air traffic control machines in which case the failure
+ of the Original Code could lead to death, personal injury, or severe
+ physical or environmental damage.
+
+9. Liability.
+
+9.1 Infringement. If any of the Original Code becomes the subject of
+ a claim of infringement ("Affected Original Code"), Apple may, at
+ its sole discretion and option: (a) attempt to procure the rights
+ necessary for You to continue using the Affected Original Code; (b)
+ modify the Affected Original Code so that it is no longer
+ infringing; or (c) terminate Your rights to use the Affected
+ Original Code, effective immediately upon Apple's posting of a
+ notice to such effect on the Apple web site that is used for
+ implementation of this License.
+
+9.2 LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES SHALL APPLE BE
+ LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR
+ INABILITY TO USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER
+ UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE),
+ PRODUCTS LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF
+ ESSENTIAL PURPOSE OF ANY REMEDY. In no event shall Apple's total
+ liability to You for all damages under this License exceed the
+ amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+ trademarks or trade names "Apple", "Apple Computer", "Mac OS X",
+ "Mac OS X Server" or any other trademarks or trade names belonging
+ to Apple (collectively "Apple Marks") and no Apple Marks may be
+ used to endorse or promote products derived from the Original Code
+ other than as permitted by and in strict compliance at all times
+ with Apple's third party trademark usage guidelines which are
+ posted at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Apple retains all rights, title and interest in and to
+ the Original Code and any Modifications made by or on behalf of
+ Apple ("Apple Modifications"), and such Apple Modifications will
+ not be automatically subject to this License. Apple may, at its
+ sole discretion, choose to license such Apple Modifications under
+ this License, or on different terms from those contained in this
+ License or may choose not to license them at all. Apple's
+ development, use, reproduction, modification, sublicensing and
+ distribution of Covered Code will not be subject to this License.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+ terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach; (b) immediately in the event of
+the circumstances described in Sections 9.1 and/or 13.6(b); or (c)
+automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement
+against Apple.
+
+12.2 Effect of Termination. Upon termination, You agree to
+ immediately stop any further use, reproduction, modification and
+ distribution of the Covered Code, or Affected Original Code in the
+ case of termination under Section 9.1, and to destroy all copies of
+ the Covered Code or Affected Original Code (in the case of
+ termination under Section 9.1) that are in your possession or
+ control. All sublicenses to the Covered Code which have been
+ properly granted prior to termination shall survive any termination
+ of this License. Provisions which, by their nature, should remain
+ in effect beyond the termination of this License shall survive,
+ including but not limited to Sections 3, 5, 8, 9, 10, 11, 12.2 and
+ 13. Neither party will be liable to the other for compensation,
+ indemnity or damages of any sort solely as a result of terminating
+ this License in accordance with its terms, and termination of this
+ License will be without prejudice to any other right or remedy of
+ either party.
+
+13. Miscellaneous.
+
+13.1 Export Law Assurances. You may not use or otherwise export or
+ re-export the Original Code except as authorized by United States
+ law and the laws of the jurisdiction in which the Original Code was
+ obtained. In particular, but without limitation, the Original Code
+ may not be exported or re-exported (a) into (or to a national or
+ resident of) any U.S. embargoed country or (b) to anyone on the
+ U.S. Treasury Department's list of Specially Designated Nationals
+ or the U.S. Department of Commerce's Table of Denial Orders. By
+ using the Original Code, You represent and warrant that You are not
+ located in, under control of, or a national or resident of any such
+ country or on any such list.
+
+13.2 Government End Users. The Covered Code is a "commercial item" as
+ defined in FAR 2.101. Government software and technical data
+ rights in the Covered Code include only those rights customarily
+ provided to the public as defined in this License. This customary
+ commercial license in technical data and software is provided in
+ accordance with FAR 12.211 (Technical Data) and 12.212 (Computer
+ Software) and, for Department of Defense purchases, DFAR
+ 252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3
+ (Rights in Commercial Computer Software or Computer Software
+ Documentation). Accordingly, all U.S. Government End Users acquire
+ Covered Code with only those rights set forth herein.
+
+13.3 Relationship of Parties. This License will not be construed as
+ creating an agency, partnership, joint venture or any other form of
+ legal association between You and Apple, and You will not represent
+ to the contrary, whether expressly, by implication, appearance or
+ otherwise.
+
+13.4 Independent Development. Nothing in this License will impair
+ Apple's right to acquire, license, develop, have others develop for
+ it, market and/or distribute technology or products that perform
+ the same or similar functions as, or otherwise compete with,
+ Modifications, Larger Works, technology or products that You may
+ develop, produce, market or distribute.
+
+13.5 Waiver; Construction. Failure by Apple to enforce any provision
+ of this License will not be deemed a waiver of future enforcement
+ of that or any other provision. Any law or regulation which
+ provides that the language of a contract shall be construed against
+ the drafter will not apply to this License.
+
+13.6 Severability. (a) If for any reason a court of competent
+ jurisdiction finds any provision of this License, or portion
+ thereof, to be unenforceable, that provision of the License will be
+ enforced to the maximum extent permissible so as to effect the
+ economic benefits and intent of the parties, and the remainder of
+ this License will continue in full force and effect. (b)
+ Notwithstanding the foregoing, if applicable law prohibits or
+ restricts You from fully and/or specifically complying with
+ Sections 2 and/or 3 or prevents the enforceability of either of
+ those Sections, this License will immediately terminate and You
+ must immediately discontinue any use of the Covered Code and
+ destroy all copies of it that are in your possession or control.
+
+13.7 Dispute Resolution. Any litigation or other dispute resolution
+ between You and Apple relating to this License shall take place in
+ the Northern District of California, and You and Apple hereby
+ consent to the personal jurisdiction of, and venue in, the state
+ and federal courts within that District with respect to this
+ License. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly
+ excluded.
+
+13.8 Entire Agreement; Governing Law. This License constitutes the
+ entire agreement between the parties with respect to the subject
+ matter hereof. This License shall be governed by the laws of the
+ United States and the State of California, except that body of
+ California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+Reserved. This file contains Original Code and/or Modifications of
+Original Code as defined in and that are subject to the Apple Public
+Source License Version 1.0 (the 'License'). You may not use this file
+except in compliance with the License. Please obtain a copy of the
+License at http://www.apple.com/publicsource and read it before using
+this file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+License for the specific language governing rights and limitations
+under the License."
diff --git a/network_cmds/arp.tproj/IMPORT_NOTES b/network_cmds/arp.tproj/IMPORT_NOTES
new file mode 100644
index 0000000..231c5ca
--- /dev/null
+++ b/network_cmds/arp.tproj/IMPORT_NOTES
@@ -0,0 +1,3 @@
+arp.c - FreeBSD file, included types.h, socket.h, ethernet.h, removed
+ token ring header, removed __unused__ attributes, hid token ring code
+ with #ifndef __APPLE__
diff --git a/network_cmds/arp.tproj/arp.8 b/network_cmds/arp.tproj/arp.8
new file mode 100644
index 0000000..b586c26
--- /dev/null
+++ b/network_cmds/arp.tproj/arp.8
@@ -0,0 +1,251 @@
+.\" Copyright (c) 2012 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)arp.8 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.sbin/arp/arp.8,v 1.25.2.1 2008/04/25 16:38:14 sam Exp $
+.\"
+.Dd March 18, 2008
+.Dt ARP 8
+.Os
+.Sh NAME
+.Nm arp
+.Nd address resolution display and control
+.Sh SYNOPSIS
+.Nm
+.Op Fl n
+.Op Fl i Ar interface
+.Ar hostname
+.Nm
+.Op Fl n
+.Op Fl i Ar interface
+.Op Fl l
+.Fl a
+.Nm
+.Fl d Ar hostname
+.Op Cm pub
+.Op Cm ifscope interface
+.Nm
+.Fl d
+.Op Fl i Ar interface
+.Fl a
+.Nm
+.Fl s Ar hostname ether_addr
+.Op Cm temp
+.Op Cm reject
+.Op Cm blackhole
+.Op Cm pub Op Cm only
+.Op Cm ifscope interface
+.Nm
+.Fl S Ar hostname ether_addr
+.Op Cm temp
+.Op Cm reject
+.Op Cm blackhole
+.Op Cm pub Op Cm only
+.Op Cm ifscope interface
+.Nm
+.Fl f Ar filename
+.Sh DESCRIPTION
+The
+.Nm
+utility displays and modifies the Internet-to-Ethernet address translation
+tables used by the address resolution protocol
+.Pq Xr arp 4 .
+With no flags, the program displays the current
+.Tn ARP
+entry for
+.Ar hostname .
+The host may be specified by name or by number,
+using Internet dot notation.
+.Pp
+Available options:
+.Bl -tag -width indent
+.It Fl a
+The program displays or deletes all of the current
+.Tn ARP
+entries.
+.It Fl d
+A super-user may delete an entry for the host called
+.Ar hostname
+with the
+.Fl d
+flag.
+If the
+.Cm pub
+keyword is specified, only the
+.Dq published
+.Tn ARP
+entry
+for this host will be deleted.
+If the
+.Cm ifscope
+keyword is specified, the entry specific to the interface will be deleted.
+.Pp
+Alternatively, the
+.Fl d
+flag may be combined with the
+.Fl a
+flag to delete all entries.
+.It Fl i Ar interface
+Limit the operation scope to the
+.Tn ARP
+entries on
+.Ar interface .
+Applicable only to the following operations:
+display one, display all, delete all.
+.It Fl l
+Show link-layer reachability information.
+.It Fl n
+Show network addresses as numbers (normally
+.Nm
+attempts to display addresses symbolically).
+.It Fl s Ar hostname ether_addr
+Create an
+.Tn ARP
+entry for the host called
+.Ar hostname
+with the Ethernet address
+.Ar ether_addr .
+The Ethernet address is given as six hex bytes separated by colons.
+The entry will be permanent unless the word
+.Cm temp
+is given in the command.
+If the word
+.Cm pub
+is given, the entry will be
+.Dq published ;
+i.e., this system will
+act as an
+.Tn ARP
+server,
+responding to requests for
+.Ar hostname
+even though the host address is not its own.
+In this case the
+.Ar ether_addr
+can be given as
+.Cm auto
+in which case the interfaces on this host will be examined,
+and if one of them is found to occupy the same subnet, its
+Ethernet address will be used.
+If the
+.Cm only
+keyword is also specified, this will create a
+.Dq "published (proxy only)"
+entry.
+This type of entry is created automatically if
+.Nm
+detects that a routing table entry for
+.Ar hostname
+already exists.
+.Pp
+If the
+.Cm reject
+keyword is specified the entry will be marked so that traffic to
+the host will be discarded and the sender will be notified the
+host is unreachable.
+The
+.Cm blackhole
+keyword is similar in that traffic is discarded but the sender is
+not notified.
+These can be used to block external traffic to a host without
+using a firewall.
+.Pp
+If the
+.Cm ifscope
+keyword is specified, the entry will set with an additional property that
+strictly associate the entry to the interface. This allows
+for the presence of mutiple entries with the same destination
+on different interfaces.
+.It Fl S Ar hostname ether_addr
+Is just like
+.Fl s
+except any existing
+.Tn ARP
+entry for this host will be deleted first.
+.It Fl f Ar filename
+Cause the file
+.Ar filename
+to be read and multiple entries to be set in the
+.Tn ARP
+tables.
+Entries
+in the file should be of the form
+.Pp
+.Bd -ragged -offset indent -compact
+.Ar hostname ether_addr
+.Op Cm temp
+.Op Cm pub Op Cm only
+.Op Cm ifscope interface
+.Ed
+.Pp
+with argument meanings as given above.
+Leading whitespace and empty lines are ignored.
+A
+.Ql #
+character will mark the rest of the line as a comment.
+.It Fl x
+Show extended link-layer reachability information in addition to that shown by
+the
+.Fl l
+flag.
+.El
+.Sh SEE ALSO
+.Xr inet 3 ,
+.Xr arp 4 ,
+.Xr ifconfig 8 ,
+.Xr ndp 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 .
diff --git a/network_cmds/arp.tproj/arp.c b/network_cmds/arp.tproj/arp.c
new file mode 100644
index 0000000..eeca003
--- /dev/null
+++ b/network_cmds/arp.tproj/arp.c
@@ -0,0 +1,1163 @@
+/*
+ * Copyright (c) 2003-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1984, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sun Microsystems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1984, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+#endif
+
+/*
+ * arp - display, set, and delete arp table entries
+ */
+
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#if 0
+#include <net/iso88025.h>
+#endif
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+typedef void (action_fn)(struct sockaddr_dl *sdl,
+ struct sockaddr_inarp *s_in, struct rt_msghdr *rtm);
+typedef void (action_ext_fn)(struct sockaddr_dl *sdl,
+ struct sockaddr_inarp *s_in, struct rt_msghdr_ext *rtm);
+
+static int search(in_addr_t addr, action_fn *action);
+static int search_ext(in_addr_t addr, action_ext_fn *action);
+static action_fn print_entry;
+static action_fn nuke_entry;
+static action_ext_fn print_entry_ext;
+
+static char *print_lladdr(struct sockaddr_dl *);
+static int delete(char *host, int do_proxy);
+static void usage(void);
+static int set(int argc, char **argv);
+static int get(char *host);
+static int file(char *name);
+static struct rt_msghdr *rtmsg(int cmd,
+ struct sockaddr_inarp *dst, struct sockaddr_dl *sdl);
+static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr);
+static struct sockaddr_inarp *getaddr(char *host);
+static int valid_type(int type);
+static char *sec2str(time_t);
+
+static int nflag; /* no reverse dns lookups */
+static int xflag; /* extended link-layer reachability information */
+static char *rifname;
+
+static int expire_time, flags, doing_proxy, proxy_only;
+
+static char *boundif = NULL;
+static unsigned int ifscope = 0;
+
+/* which function we're supposed to do */
+#define F_GET 1
+#define F_SET 2
+#define F_FILESET 3
+#define F_REPLACE 4
+#define F_DELETE 5
+
+#ifndef SA_SIZE
+#define SA_SIZE(sa) \
+ ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \
+ sizeof(uint32_t) : \
+ 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(uint32_t) - 1) ) )
+#endif
+
+#define SETFUNC(f) { if (func) usage(); func = (f); }
+
+
+int
+main(int argc, char *argv[])
+{
+ int ch, func = 0;
+ int rtn = 0;
+ int aflag = 0; /* do it for all entries */
+ int lflag = 0;
+ uint32_t ifindex = 0;
+
+ while ((ch = getopt(argc, argv, "andflsSi:x")) != -1)
+ switch((char)ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'd':
+ SETFUNC(F_DELETE);
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'S':
+ SETFUNC(F_REPLACE);
+ break;
+ case 's':
+ SETFUNC(F_SET);
+ break;
+ case 'f' :
+ SETFUNC(F_FILESET);
+ break;
+ case 'i':
+ rifname = optarg;
+ break;
+ case 'x':
+ xflag = 1;
+ lflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!func)
+ func = F_GET;
+ if (rifname) {
+ if (func != F_GET && !(func == F_DELETE && aflag))
+ errx(1, "-i not applicable to this operation");
+ if ((ifindex = if_nametoindex(rifname)) == 0) {
+ if (errno == ENXIO)
+ errx(1, "interface %s does not exist", rifname);
+ else
+ err(1, "if_nametoindex(%s)", rifname);
+ }
+ }
+ switch (func) {
+ case F_GET:
+ if (aflag) {
+ if (argc != 0)
+ usage();
+ if (lflag) {
+ printf("%-23s %-17s %-9.9s %-9.9s %8.8s %4s "
+ "%4s", "Neighbor",
+ "Linklayer Address", "Expire(O)",
+ "Expire(I)", "Netif", "Refs", "Prbs");
+ if (xflag)
+ printf(" %-7.7s %-7.7s %-7.7s",
+ "RSSI", "LQM", "NPM");
+ printf("\n");
+ search_ext(0, print_entry_ext);
+ } else {
+ search(0, print_entry);
+ }
+ } else {
+ if (argc != 1)
+ usage();
+ rtn = get(argv[0]);
+ }
+ break;
+ case F_SET:
+ case F_REPLACE:
+ if (argc < 2 || argc > 6)
+ usage();
+ if (func == F_REPLACE)
+ (void)delete(argv[0], 0);
+ rtn = set(argc, argv) ? 1 : 0;
+ break;
+ case F_DELETE:
+ if (aflag) {
+ if (argc != 0)
+ usage();
+ search(0, nuke_entry);
+ } else {
+ int do_proxy = 0;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strncmp(argv[i], "pub", sizeof("pub")) == 0) {
+ do_proxy = SIN_PROXY;
+ } else if (strncmp(argv[i], "ifscope", sizeof("ifscope")) == 0) {
+ if (i + 1 >= argc) {
+ printf("ifscope needs an interface parameter\n");
+ return (1);
+ }
+ boundif = argv[++i];
+ if ((ifscope = if_nametoindex(boundif)) == 0)
+ errx(1, "ifscope has bad interface name: %s", boundif);
+ } else {
+ usage();
+ }
+ }
+ if (i > argc)
+ usage();
+ rtn = delete(argv[0], do_proxy);
+ }
+ break;
+ case F_FILESET:
+ if (argc != 1)
+ usage();
+ rtn = file(argv[0]);
+ break;
+ }
+
+ return (rtn);
+}
+
+/*
+ * Process a file to set standard arp entries
+ */
+static int
+file(char *name)
+{
+ FILE *fp;
+ int i, retval;
+ char line[128], arg[7][50], *args[7], *p;
+
+ if ((fp = fopen(name, "r")) == NULL)
+ err(1, "cannot open %s", name);
+ args[0] = &arg[0][0];
+ args[1] = &arg[1][0];
+ args[2] = &arg[2][0];
+ args[3] = &arg[3][0];
+ args[4] = &arg[4][0];
+ args[5] = &arg[5][0];
+ args[6] = &arg[6][0];
+ retval = 0;
+ while(fgets(line, sizeof(line), fp) != NULL) {
+ if ((p = strchr(line, '#')) != NULL)
+ *p = '\0';
+ for (p = line; isblank(*p); p++);
+ if (*p == '\n' || *p == '\0')
+ continue;
+ i = sscanf(p, "%49s %49s %49s %49s %49s %49s %49s", arg[0], arg[1],
+ arg[2], arg[3], arg[4], arg[5], arg[6]);
+ if (i < 2) {
+ warnx("bad line: %s", line);
+ retval = 1;
+ continue;
+ }
+ if (set(i, args))
+ retval = 1;
+ }
+ fclose(fp);
+ return (retval);
+}
+
+/*
+ * Given a hostname, fills up a (static) struct sockaddr_inarp with
+ * the address of the host and returns a pointer to the
+ * structure.
+ */
+static struct sockaddr_inarp *
+getaddr(char *host)
+{
+ struct hostent *hp;
+ static struct sockaddr_inarp reply;
+
+ bzero(&reply, sizeof(reply));
+ reply.sin_len = sizeof(reply);
+ reply.sin_family = AF_INET;
+ reply.sin_addr.s_addr = inet_addr(host);
+ if (reply.sin_addr.s_addr == INADDR_NONE) {
+ if (!(hp = gethostbyname(host))) {
+ warnx("%s: %s", host, hstrerror(h_errno));
+ return (NULL);
+ }
+ bcopy((char *)hp->h_addr, (char *)&reply.sin_addr,
+ sizeof reply.sin_addr);
+ }
+ return (&reply);
+}
+
+/*
+ * Returns true if the type is a valid one for ARP.
+ */
+static int
+valid_type(int type)
+{
+
+ switch (type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ case IFT_ISO88023:
+ case IFT_ISO88024:
+#if 0
+ case IFT_ISO88025:
+#endif
+ case IFT_L2VLAN:
+#ifdef IFT_BRIDGE
+ case IFT_BRIDGE:
+#endif
+ return (1);
+ default:
+ return (0);
+ }
+}
+
+/*
+ * Set an individual arp entry
+ */
+static int
+set(int argc, char **argv)
+{
+ struct sockaddr_inarp *addr;
+ struct sockaddr_inarp *dst; /* what are we looking for */
+ struct sockaddr_dl *sdl;
+ struct rt_msghdr *rtm;
+ struct ether_addr *ea;
+ char *host = argv[0], *eaddr = argv[1];
+ struct sockaddr_dl sdl_m;
+
+ argc -= 2;
+ argv += 2;
+
+ bzero(&sdl_m, sizeof(sdl_m));
+ sdl_m.sdl_len = sizeof(sdl_m);
+ sdl_m.sdl_family = AF_LINK;
+
+ dst = getaddr(host);
+ if (dst == NULL)
+ return (1);
+ doing_proxy = flags = proxy_only = expire_time = 0;
+ boundif = NULL;
+ ifscope = 0;
+ while (argc-- > 0) {
+ if (strncmp(argv[0], "temp", sizeof("temp")) == 0) {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ expire_time = tv.tv_sec + 20 * 60;
+ } else if (strncmp(argv[0], "pub", sizeof("pub")) == 0) {
+ flags |= RTF_ANNOUNCE;
+ doing_proxy = 1;
+ if (argc && strncmp(argv[1], "only", sizeof("only")) == 0) {
+ proxy_only = 1;
+ dst->sin_other = SIN_PROXY;
+ argc--; argv++;
+ }
+ } else if (strncmp(argv[0], "blackhole", sizeof("blackhole")) == 0) {
+ flags |= RTF_BLACKHOLE;
+ } else if (strncmp(argv[0], "reject", sizeof("reject")) == 0) {
+ flags |= RTF_REJECT;
+ } else if (strncmp(argv[0], "trail", sizeof("trail")) == 0) {
+ /* XXX deprecated and undocumented feature */
+ printf("%s: Sending trailers is no longer supported\n",
+ host);
+ } else if (strncmp(argv[0], "ifscope", sizeof("ifscope")) == 0) {
+ if (argc < 1) {
+ printf("ifscope needs an interface parameter\n");
+ return (1);
+ }
+ boundif = argv[1];
+ if ((ifscope = if_nametoindex(boundif)) == 0)
+ errx(1, "ifscope has bad interface name: %s", boundif);
+ argc--; argv++;
+ }
+ argv++;
+ }
+ ea = (struct ether_addr *)LLADDR(&sdl_m);
+ if (doing_proxy && !strcmp(eaddr, "auto")) {
+ if (!get_ether_addr(dst->sin_addr.s_addr, ea)) {
+ printf("no interface found for %s\n",
+ inet_ntoa(dst->sin_addr));
+ return (1);
+ }
+ sdl_m.sdl_alen = ETHER_ADDR_LEN;
+ } else {
+ struct ether_addr *ea1 = ether_aton(eaddr);
+
+ if (ea1 == NULL) {
+ warnx("invalid Ethernet address '%s'", eaddr);
+ return (1);
+ } else {
+ *ea = *ea1;
+ sdl_m.sdl_alen = ETHER_ADDR_LEN;
+ }
+ }
+ for (;;) { /* try at most twice */
+ rtm = rtmsg(RTM_GET, dst, &sdl_m);
+ if (rtm == NULL) {
+ warn("%s", host);
+ return (1);
+ }
+ addr = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
+ if (addr->sin_addr.s_addr != dst->sin_addr.s_addr)
+ break;
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY) &&
+ valid_type(sdl->sdl_type) )
+ break;
+ /*
+ * If we asked for a scope entry and did not get one or
+ * did not asked for a scope entry and got one, we can
+ * proceed.
+ */
+ if ((ifscope != 0) != (rtm->rtm_flags & RTF_IFSCOPE))
+ break;
+ if (doing_proxy == 0) {
+ printf("set: can only proxy for %s\n", host);
+ return (1);
+ }
+ if (dst->sin_other & SIN_PROXY) {
+ printf("set: proxy entry exists for non 802 device\n");
+ return (1);
+ }
+ dst->sin_other = SIN_PROXY;
+ proxy_only = 1;
+ }
+
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot intuit interface index and type for %s\n", host);
+ return (1);
+ }
+ sdl_m.sdl_type = sdl->sdl_type;
+ sdl_m.sdl_index = sdl->sdl_index;
+ return (rtmsg(RTM_ADD, dst, &sdl_m) == NULL);
+}
+
+/*
+ * Display an individual arp entry
+ */
+static int
+get(char *host)
+{
+ struct sockaddr_inarp *addr;
+
+ addr = getaddr(host);
+ if (addr == NULL)
+ return (1);
+ if (0 == search(addr->sin_addr.s_addr, print_entry)) {
+ printf("%s (%s) -- no entry",
+ host, inet_ntoa(addr->sin_addr));
+ if (rifname)
+ printf(" on %s", rifname);
+ printf("\n");
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Delete an arp entry
+ */
+static int
+delete(char *host, int do_proxy)
+{
+ struct sockaddr_inarp *addr, *dst;
+ struct rt_msghdr *rtm;
+ struct sockaddr_dl *sdl;
+
+ dst = getaddr(host);
+ if (dst == NULL)
+ return (1);
+ dst->sin_other = do_proxy;
+ for (;;) { /* try twice */
+ rtm = rtmsg(RTM_GET, dst, NULL);
+ if (rtm == NULL) {
+ warn("%s", host);
+ return (1);
+ }
+ addr = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr);
+ if (addr->sin_addr.s_addr == dst->sin_addr.s_addr &&
+ sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY) &&
+ valid_type(sdl->sdl_type) )
+ break; /* found it */
+ if (dst->sin_other & SIN_PROXY) {
+ fprintf(stderr, "delete: cannot locate %s\n",host);
+ return (1);
+ }
+ dst->sin_other = SIN_PROXY;
+ }
+ if (rtmsg(RTM_DELETE, dst, NULL) != NULL) {
+ printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr));
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Search the arp table and do some action on matching entries
+ */
+static int
+search(in_addr_t addr, action_fn *action)
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *newbuf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_inarp *sin2;
+ struct sockaddr_dl *sdl;
+ char ifname[IF_NAMESIZE];
+ int st, found_entry = 0;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "route-sysctl-estimate");
+ if (needed == 0) /* empty table */
+ return 0;
+ buf = NULL;
+ for (;;) {
+ newbuf = realloc(buf, needed);
+ if (newbuf == NULL) {
+ if (buf != NULL)
+ free(buf);
+ errx(1, "could not reallocate memory");
+ }
+ buf = newbuf;
+ st = sysctl(mib, 6, buf, &needed, NULL, 0);
+ if (st == 0 || errno != ENOMEM)
+ break;
+ needed += needed / 8;
+ }
+ if (st == -1)
+ err(1, "actual retrieval of routing table");
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ sin2 = (struct sockaddr_inarp *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
+ if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
+ strcmp(ifname, rifname))
+ continue;
+ if (addr) {
+ if (addr != sin2->sin_addr.s_addr)
+ continue;
+ found_entry = 1;
+ }
+ (*action)(sdl, sin2, rtm);
+ }
+ free(buf);
+ return (found_entry);
+}
+
+/*
+ * Stolen and adapted from ifconfig
+ */
+static char *
+print_lladdr(struct sockaddr_dl *sdl)
+{
+ static char buf[256];
+ char *cp;
+ int n, bufsize = sizeof (buf), p = 0;
+
+ bzero(buf, sizeof (buf));
+ cp = (char *)LLADDR(sdl);
+ if ((n = sdl->sdl_alen) > 0) {
+ while (--n >= 0)
+ p += snprintf(buf + p, bufsize - p, "%x%s",
+ *cp++ & 0xff, n > 0 ? ":" : "");
+ }
+ return (buf);
+}
+
+/*
+ * Display an arp entry
+ */
+static void
+print_entry(struct sockaddr_dl *sdl,
+ struct sockaddr_inarp *addr, struct rt_msghdr *rtm)
+{
+ const char *host;
+ struct hostent *hp;
+ char ifname[IF_NAMESIZE];
+#if 0
+ struct iso88025_sockaddr_dl_data *trld;
+ int seg;
+#endif
+
+ if (nflag == 0)
+ hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
+ sizeof addr->sin_addr, AF_INET);
+ else
+ hp = 0;
+ if (hp)
+ host = hp->h_name;
+ else {
+ host = "?";
+ if (h_errno == TRY_AGAIN)
+ nflag = 1;
+ }
+ printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr));
+ if (sdl->sdl_alen) {
+#if 1
+ printf("%s", print_lladdr(sdl));
+#else
+ if ((sdl->sdl_type == IFT_ETHER ||
+ sdl->sdl_type == IFT_L2VLAN ||
+ sdl->sdl_type == IFT_BRIDGE) &&
+ sdl->sdl_alen == ETHER_ADDR_LEN)
+ printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl)));
+ else {
+ int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+
+ printf("%s", link_ntoa(sdl) + n);
+ }
+#endif
+ } else
+ printf("(incomplete)");
+ if (if_indextoname(sdl->sdl_index, ifname) != NULL)
+ printf(" on %s", ifname);
+ if ((rtm->rtm_flags & RTF_IFSCOPE))
+ printf(" ifscope");
+ if (rtm->rtm_rmx.rmx_expire == 0)
+ printf(" permanent");
+ if (addr->sin_other & SIN_PROXY)
+ printf(" published (proxy only)");
+ if (rtm->rtm_addrs & RTA_NETMASK) {
+ addr = (struct sockaddr_inarp *)
+ (SA_SIZE(sdl) + (char *)sdl);
+ if (addr->sin_addr.s_addr == 0xffffffff)
+ printf(" published");
+ if (addr->sin_len != 8)
+ printf("(weird)");
+ }
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+ printf(" [ethernet]");
+ break;
+#if 0
+ case IFT_ISO88025:
+ printf(" [token-ring]");
+ trld = SDL_ISO88025(sdl);
+ if (trld->trld_rcf != 0) {
+ printf(" rt=%x", ntohs(trld->trld_rcf));
+ for (seg = 0;
+ seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2);
+ seg++)
+ printf(":%x", ntohs(*(trld->trld_route[seg])));
+ }
+ break;
+#endif
+ case IFT_FDDI:
+ printf(" [fddi]");
+ break;
+ case IFT_ATM:
+ printf(" [atm]");
+ break;
+ case IFT_L2VLAN:
+ printf(" [vlan]");
+ break;
+ case IFT_IEEE1394:
+ printf(" [firewire]");
+ break;
+#ifdef IFT_BRIDGE
+ case IFT_BRIDGE:
+ printf(" [bridge]");
+ break;
+#endif
+ default:
+ break;
+ }
+
+ printf("\n");
+
+}
+
+/*
+ * Nuke an arp entry
+ */
+static void
+nuke_entry(struct sockaddr_dl *sdl __unused,
+ struct sockaddr_inarp *addr, struct rt_msghdr *rtm)
+{
+ char ip[20];
+
+ snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr));
+ /*
+ * When deleting all entries, specify the interface scope of each entry
+ */
+ if ((rtm->rtm_flags & RTF_IFSCOPE))
+ ifscope = rtm->rtm_index;
+ (void)delete(ip, 0);
+ ifscope = 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+ "usage: arp [-n] [-i interface] hostname",
+ " arp [-n] [-i interface] [-l] -a",
+ " arp -d hostname [pub] [ifscope interface]",
+ " arp -d [-i interface] -a",
+ " arp -s hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
+ " arp -S hostname ether_addr [temp] [reject] [blackhole] [pub [only]] [ifscope interface]",
+ " arp -f filename");
+ exit(1);
+}
+
+static struct rt_msghdr *
+rtmsg(int cmd, struct sockaddr_inarp *dst, struct sockaddr_dl *sdl)
+{
+ static int seq;
+ int rlen;
+ int l;
+ struct sockaddr_in so_mask, *so_mask_ptr = &so_mask;
+ static int s = -1;
+ static pid_t pid;
+
+ static struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+ } m_rtmsg;
+
+ struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ char *cp = m_rtmsg.m_space;
+
+ if (s < 0) { /* first time: open socket, get pid */
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0)
+ err(1, "socket");
+ pid = getpid();
+ }
+ bzero(&so_mask, sizeof(so_mask));
+ so_mask.sin_len = 8;
+ so_mask.sin_addr.s_addr = 0xffffffff;
+
+ errno = 0;
+ /*
+ * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer
+ * appropriately (except for the mask set just above).
+ */
+ if (cmd == RTM_DELETE)
+ goto doit;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ /*
+ * Note: On RTM_GET the kernel will return a scoped route when both a scoped route and
+ * a unscoped route exist. That means we cannot delete a unscoped route if there is
+ * also a matching scope route
+ */
+ if (ifscope) {
+ rtm->rtm_index = ifscope;
+ rtm->rtm_flags |= RTF_IFSCOPE;
+ }
+
+ switch (cmd) {
+ default:
+ errx(1, "internal wrong cmd");
+ case RTM_ADD:
+ rtm->rtm_addrs |= RTA_GATEWAY;
+ rtm->rtm_rmx.rmx_expire = expire_time;
+ rtm->rtm_inits = RTV_EXPIRE;
+ rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
+ dst->sin_other = 0;
+ if (doing_proxy) {
+ if (proxy_only)
+ dst->sin_other = SIN_PROXY;
+ else {
+ rtm->rtm_addrs |= RTA_NETMASK;
+ rtm->rtm_flags &= ~RTF_HOST;
+ }
+ }
+ /* FALLTHROUGH */
+ case RTM_GET:
+ rtm->rtm_addrs |= RTA_DST;
+ }
+#define NEXTADDR(w, s) \
+ if ((s) != NULL && rtm->rtm_addrs & (w)) { \
+ bcopy((s), cp, sizeof(*(s))); cp += SA_SIZE(s);}
+
+ NEXTADDR(RTA_DST, dst);
+ NEXTADDR(RTA_GATEWAY, sdl);
+ NEXTADDR(RTA_NETMASK, so_mask_ptr);
+
+ rtm->rtm_msglen = cp - (char *)&m_rtmsg;
+doit:
+ l = rtm->rtm_msglen;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_type = cmd;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ if (errno != ESRCH || cmd != RTM_DELETE) {
+ warn("writing to routing socket");
+ return (NULL);
+ }
+ }
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+ if (l < 0)
+ warn("read from routing socket");
+ return (rtm);
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS 32
+
+static int
+get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr)
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ in_addr_t ina, mask;
+ struct sockaddr_dl *dla;
+ struct ifreq ifreq;
+ struct ifconf ifc;
+ struct ifreq ifs[MAX_IFS];
+ int sock;
+ int retval = 0;
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0)
+ err(1, "socket");
+
+ ifc.ifc_len = sizeof(ifs);
+ ifc.ifc_req = ifs;
+ if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+ warnx("ioctl(SIOCGIFCONF)");
+ goto done;
+ }
+
+#define NEXTIFR(i) \
+ ((struct ifreq *)((char *)&(i)->ifr_addr \
+ + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) )
+
+ /*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len);
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr) ) {
+ if (ifr->ifr_addr.sa_family != AF_INET)
+ continue;
+ strlcpy(ifreq.ifr_name, ifr->ifr_name,
+ sizeof(ifreq.ifr_name));
+ ifreq.ifr_addr = ifr->ifr_addr;
+ /*
+ * Check that the interface is up,
+ * and not point-to-point or loopback.
+ */
+ if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0)
+ continue;
+ if ((ifreq.ifr_flags &
+ (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
+ IFF_LOOPBACK|IFF_NOARP))
+ != (IFF_UP|IFF_BROADCAST))
+ continue;
+ /*
+ * Get its netmask and check that it's on
+ * the right subnet.
+ */
+ if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+ ina = ((struct sockaddr_in *)
+ &ifr->ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) == (ina & mask))
+ break; /* ok, we got it! */
+ }
+
+ if (ifr >= ifend)
+ goto done;
+
+ /*
+ * Now scan through again looking for a link-level address
+ * for this interface.
+ */
+ ifp = ifr;
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr))
+ if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 &&
+ ifr->ifr_addr.sa_family == AF_LINK)
+ break;
+ if (ifr >= ifend)
+ goto done;
+ /*
+ * Found the link-level address - copy it out
+ */
+ dla = (struct sockaddr_dl *) &ifr->ifr_addr;
+ memcpy(hwaddr, LLADDR(dla), dla->sdl_alen);
+ printf("using interface %s for proxy with address ",
+ ifp->ifr_name);
+ printf("%s\n", ether_ntoa(hwaddr));
+ retval = dla->sdl_alen;
+done:
+ close(sock);
+ return (retval);
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+
+ return(result);
+}
+
+static int
+search_ext(in_addr_t addr, action_ext_fn *action)
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *newbuf, *next;
+ struct rt_msghdr_ext *ertm;
+ struct sockaddr_inarp *sin2;
+ struct sockaddr_dl *sdl;
+ char ifname[IF_NAMESIZE];
+ int st, found_entry = 0;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET;
+ mib[4] = NET_RT_DUMPX_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "route-sysctl-estimate");
+ if (needed == 0) /* empty table */
+ return 0;
+ buf = NULL;
+ for (;;) {
+ newbuf = realloc(buf, needed);
+ if (newbuf == NULL) {
+ if (buf != NULL)
+ free(buf);
+ errx(1, "could not reallocate memory");
+ }
+ buf = newbuf;
+ st = sysctl(mib, 6, buf, &needed, NULL, 0);
+ if (st == 0 || errno != ENOMEM)
+ break;
+ needed += needed / 8;
+ }
+ if (st == -1)
+ err(1, "actual retrieval of routing table");
+ lim = buf + needed;
+ for (next = buf; next < lim; next += ertm->rtm_msglen) {
+ ertm = (struct rt_msghdr_ext *)next;
+ sin2 = (struct sockaddr_inarp *)(ertm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2));
+ if (rifname && if_indextoname(sdl->sdl_index, ifname) &&
+ strcmp(ifname, rifname))
+ continue;
+ if (addr) {
+ if (addr != sin2->sin_addr.s_addr)
+ continue;
+ found_entry = 1;
+ }
+ (*action)(sdl, sin2, ertm);
+ }
+ free(buf);
+ return (found_entry);
+}
+
+static void
+print_entry_ext(struct sockaddr_dl *sdl, struct sockaddr_inarp *addr,
+ struct rt_msghdr_ext *ertm)
+{
+ const char *host;
+ struct hostent *hp;
+ char ifname[IF_NAMESIZE];
+ struct timeval time;
+
+ if (nflag == 0)
+ hp = gethostbyaddr((caddr_t)&(addr->sin_addr),
+ sizeof (addr->sin_addr), AF_INET);
+ else
+ hp = 0;
+
+ if (hp)
+ host = hp->h_name;
+ else
+ host = inet_ntoa(addr->sin_addr);
+
+ printf("%-23s ", host);
+
+ if (sdl->sdl_alen)
+ printf("%-17s ", print_lladdr(sdl));
+ else
+ printf("%-17s ", "(incomplete)");
+
+ gettimeofday(&time, 0);
+
+ if (ertm->rtm_ri.ri_refcnt == 0 || ertm->rtm_ri.ri_snd_expire == 0)
+ printf("%-9.9s ", "(none)");
+ else if (ertm->rtm_ri.ri_snd_expire > time.tv_sec)
+ printf("%-9.9s ",
+ sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec));
+ else
+ printf("%-9.9s ", "expired");
+
+ if (ertm->rtm_ri.ri_refcnt == 0 || ertm->rtm_ri.ri_rcv_expire == 0)
+ printf("%-9.9s", "(none)");
+ else if (ertm->rtm_ri.ri_rcv_expire > time.tv_sec)
+ printf("%-9.9s",
+ sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec));
+ else
+ printf("%-9.9s", "expired");
+
+ if (if_indextoname(sdl->sdl_index, ifname) == NULL)
+ snprintf(ifname, sizeof (ifname), "%s", "?");
+ printf(" %8.8s", ifname);
+
+ if (ertm->rtm_ri.ri_refcnt) {
+ printf(" %4d", ertm->rtm_ri.ri_refcnt);
+ if (ertm->rtm_ri.ri_probes)
+ printf(" %4d", ertm->rtm_ri.ri_probes);
+
+ if (xflag) {
+ if (!ertm->rtm_ri.ri_probes)
+ printf(" %-4.4s", "none");
+
+ if (ertm->rtm_ri.ri_rssi != IFNET_RSSI_UNKNOWN)
+ printf(" %7d", ertm->rtm_ri.ri_rssi);
+ else
+ printf(" %-7.7s", "unknown");
+
+ switch (ertm->rtm_ri.ri_lqm)
+ {
+ case IFNET_LQM_THRESH_OFF:
+ printf(" %-7.7s", "off");
+ break;
+ case IFNET_LQM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_LQM_THRESH_POOR:
+ printf(" %-7.7s", "poor");
+ break;
+ case IFNET_LQM_THRESH_GOOD:
+ printf(" %-7.7s", "good");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_lqm);
+ break;
+ }
+
+ switch (ertm->rtm_ri.ri_npm)
+ {
+ case IFNET_NPM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_NPM_THRESH_NEAR:
+ printf(" %-7.7s", "near");
+ break;
+ case IFNET_NPM_THRESH_GENERAL:
+ printf(" %-7.7s", "general");
+ break;
+ case IFNET_NPM_THRESH_FAR:
+ printf(" %-7.7s", "far");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_npm);
+ break;
+ }
+ }
+ }
+ printf("\n");
+}
diff --git a/network_cmds/arp.tproj/arp4.4 b/network_cmds/arp.tproj/arp4.4
new file mode 100644
index 0000000..a8bb6e7
--- /dev/null
+++ b/network_cmds/arp.tproj/arp4.4
@@ -0,0 +1,123 @@
+.\" Copyright (c) 1985, 1986, 1988, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)arp4.4 6.5 (Berkeley) 4/18/94
+.\"
+.Dd April 18, 1994
+.Dt ARP 4
+.Os BSD 4
+.Sh NAME
+.Nm arp
+.Nd Address Resolution Protocol
+.Sh SYNOPSIS
+.Em "pseudo-device ether"
+.Sh DESCRIPTION
+The Address Resolution Protocol (ARP) is a protocol used to dynamically
+map between Internet host addresses and 10Mb/s Ethernet addresses.
+It is used by all the 10Mb/s Ethernet interface drivers.
+It is not specific to Internet protocols or to 10Mb/s Ethernet,
+but this implementation currently supports only that combination.
+.Pp
+ARP caches Internet-Ethernet address mappings.
+When an interface requests a mapping for an address not in the cache,
+ARP queues the message which requires the mapping and broadcasts
+a message on the associated network requesting the address mapping.
+If a response is provided, the new mapping is cached and any pending
+message is transmitted.
+ARP will queue at most one packet while waiting for a response to a
+mapping request;
+only the most recently ``transmitted'' packet is kept.
+If the target host does not respond after several requests,
+the host is considered to be down for a short period (normally 20 seconds),
+allowing an error to be returned to transmission attempts during this
+interval.
+The error is
+.Li EHOSTDOWN
+for a non-responding destination host, and
+.Li EHOSTUNREACH
+for a non-responding router.
+.Pp
+The ARP cache is stored in the system routing table as
+dynamically-created host routes.
+The route to a directly-attached Ethernet network is installed as a
+.Dq cloning
+route (one with the
+.Li RTF_CLONING
+flag set),
+causing routes to individual hosts on that network to be created on
+demand.
+These routes time out periodically (normally 20 minutes after validated;
+entries are not validated when not in use).
+An entry for a host which is not responding is a
+.Dq reject
+route (one with the
+.Li RTF_REJECT
+flag set).
+.Pp
+ARP entries may be added, deleted or changed with the
+.Xr arp 8
+utility.
+Manually-added entries may be temporary or permanent,
+and may be
+.Dq published ,
+in which case the system will respond to ARP requests for that host
+as if it were the target of the request.
+.Pp
+In the past,
+ARP was used to negotiate the use of a trailer encapsulation.
+This is no longer supported.
+.Pp
+ARP watches passively for hosts impersonating the local host (i.e. a host
+which responds to an ARP mapping request for the local host's address).
+.Sh DIAGNOSTICS
+.Em "duplicate IP address %x!! sent from ethernet address: %x:%x:%x:%x:%x:%x."
+ARP has discovered another host on the local network which responds to
+mapping requests for its own Internet address with a different Ethernet
+address, generally indicating that two hosts are attempting to use the
+same Internet address.
+.Sh SEE ALSO
+.Xr inet 4 ,
+.Xr route 4 ,
+.Xr arp 8 ,
+.Xr ifconfig 8 ,
+.Xr route 8
+.sp
+.Rs
+.%A Plummer, D.
+.%B "An Ethernet Address Resolution Protocol"
+.%T RFC826
+.Re
+.Rs
+.%A Leffler, S.J.
+.%A Karels, M.J.
+.%B "Trailer Encapsulations
+.%T RFC893
+.Re
diff --git a/network_cmds/cfilutil/cfilstat.c b/network_cmds/cfilutil/cfilstat.c
new file mode 100644
index 0000000..a012e06
--- /dev/null
+++ b/network_cmds/cfilutil/cfilstat.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/errno.h>
+#include <sys/sysctl.h>
+#include <net/content_filter.h>
+#include <libproc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <unistd.h>
+#include <string.h>
+
+#define IPPROTOCOL_TCP 6
+#define IPPROTOCOL_UDP 17
+
+void
+print_filter_list()
+{
+ size_t total_len, curr_len;
+ void *buffer = NULL;
+ void *ptr;
+ uint32_t line = 0;
+
+ if (sysctlbyname("net.cfil.filter_list", NULL, &total_len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.filter_list)");
+
+ buffer = malloc(total_len);
+ if (buffer == NULL)
+ err(1, "malloc()");
+ if (sysctlbyname("net.cfil.filter_list", buffer, &total_len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.filter_list)");
+
+ ptr = buffer;
+ curr_len = 0;
+ do {
+ struct cfil_filter_stat *filter_stat;
+
+ filter_stat = (struct cfil_filter_stat *)ptr;
+
+ if (curr_len + filter_stat->cfs_len > total_len ||
+ filter_stat->cfs_len < sizeof(struct cfil_filter_stat))
+ break;
+
+ if (line % 16 == 0)
+ printf("%10s %10s %10s %10s\n",
+ "filter", "flags", "count", "necpunit");
+
+ printf("%10u 0x%08x %10u %10u\n",
+ filter_stat->cfs_filter_id,
+ filter_stat->cfs_flags,
+ filter_stat->cfs_sock_count,
+ filter_stat->cfs_necp_control_unit);
+
+ ptr += filter_stat->cfs_len;
+ curr_len += filter_stat->cfs_len;
+ } while (1);
+
+ free(buffer);
+}
+
+void
+sprint_offset(char *str, size_t len, const char *fmt, uint64_t offset)
+{
+ if (offset == CFM_MAX_OFFSET)
+ snprintf(str, len, "%s", "MAX");
+ else
+ snprintf(str, len, fmt, offset);
+}
+
+void
+print_socket_list()
+{
+ size_t total_len, curr_len;
+ void *buffer = NULL;
+ void *ptr;
+ int i;
+
+ if (sysctlbyname("net.cfil.sock_list", NULL, &total_len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.sock_list)");
+
+ buffer = malloc(total_len);
+ if (buffer == NULL)
+ err(1, "malloc()");
+ if (sysctlbyname("net.cfil.sock_list", buffer, &total_len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.sock_list)");
+
+ ptr = buffer;
+ curr_len = 0;
+ do {
+ struct cfil_sock_stat *sock_stat;
+ char opass[32];
+ char ipass[32];
+ char namebuffer[256];
+ char *procName = "<not found>";
+
+ sock_stat = (struct cfil_sock_stat *)ptr;
+
+ if (curr_len + sock_stat->cfs_len > total_len ||
+ sock_stat->cfs_len < sizeof(struct cfil_sock_stat))
+ break;
+
+ if (proc_name(sock_stat->cfs_e_pid, namebuffer, sizeof(namebuffer)) > 0) {
+ procName = namebuffer;
+ }
+
+ sprint_offset(opass, 32, "%8llu", sock_stat->cfs_snd.cbs_pass_offset);
+ sprint_offset(ipass, 32, "%8llu", sock_stat->cfs_rcv.cbs_pass_offset);
+
+ printf("%16s %5s %10s "
+ "%8s %8s %8s %8s %8s %8s %8s "
+ "%8s %8s %8s %8s %8s %8s %8s "
+ "%8s %8s %15s\n",
+ "sockid", "proto", "flags",
+ "ofirst", "olast", "oqlen", " ", "opass", " ", " ",
+ "ifirst", "ilast", "iqlen", " ", "ipass", " ", " ",
+ "pid", "epid", "eprocname");
+
+ printf("%016llu %5s 0x%08llx "
+ "%8llu %8llu %8llu %8s %8s %8s %8s "
+ "%8llu %8llu %8llu %8s %8s %8s %8s "
+ "%8u %8u %15s\n",
+
+ sock_stat->cfs_sock_id,
+ sock_stat->cfs_sock_protocol == IPPROTOCOL_TCP ? "TCP" : "UDP",
+ sock_stat->cfs_flags,
+
+ sock_stat->cfs_snd.cbs_pending_first,
+ sock_stat->cfs_snd.cbs_pending_last,
+ sock_stat->cfs_snd.cbs_inject_q_len,
+ " ",
+ opass,
+ " ",
+ " ",
+
+ sock_stat->cfs_rcv.cbs_pending_first,
+ sock_stat->cfs_rcv.cbs_pending_last,
+ sock_stat->cfs_rcv.cbs_inject_q_len,
+ " ",
+ ipass,
+ " ",
+ " ",
+ sock_stat->cfs_pid,
+ sock_stat->cfs_e_pid,
+ procName);
+
+
+ printf("%7s %10s %10s "
+ "%8s %8s %8s %8s %8s %8s %8s "
+ "%8s %8s %8s %8s %8s %8s %8s\n",
+ " ",
+ "filter", "flags",
+ "octlfrst", "octllast", "opndfrst", "opndlast", "opass", "opked", "opeek",
+ "ictlfrst", "ictllast", "ipndfrst", "ipndlast", "ipass", "ipked", "ipeek");
+ for (i = 0; i < CFIL_MAX_FILTER_COUNT; i++) {
+ struct cfil_entry_stat *estat;
+ char spass[32];
+ char speek[32];
+ char spked[32];
+ char rpass[32];
+ char rpeek[32];
+ char rpked[32];
+
+ estat = &sock_stat->ces_entries[i];
+
+ sprint_offset(spass, 32, "%8llu", estat->ces_snd.cbs_pass_offset);
+ sprint_offset(speek, 32, "%8llu", estat->ces_snd.cbs_peek_offset);
+ sprint_offset(spked, 32, "%8llu", estat->ces_snd.cbs_peeked);
+
+ sprint_offset(rpass, 32, "%8llu", estat->ces_rcv.cbs_pass_offset);
+ sprint_offset(rpeek, 32, "%8llu", estat->ces_rcv.cbs_peek_offset);
+ sprint_offset(rpked, 32, "%8llu", estat->ces_rcv.cbs_peeked);
+
+ printf("%7s %10u 0x%08x "
+ "%8llu %8llu %8llu %8llu %8s %8s %8s "
+ "%8llu %8llu %8llu %8llu %8s %8s %8s\n",
+
+ " ",
+ estat->ces_filter_id,
+ estat->ces_flags,
+
+ estat->ces_snd.cbs_ctl_first,
+ estat->ces_snd.cbs_ctl_last,
+ estat->ces_snd.cbs_pending_first,
+ estat->ces_snd.cbs_pending_last,
+ spass,
+ spked,
+ speek,
+
+ estat->ces_rcv.cbs_ctl_first,
+ estat->ces_rcv.cbs_ctl_last,
+ estat->ces_rcv.cbs_pending_first,
+ estat->ces_rcv.cbs_pending_last,
+ rpass,
+ rpked,
+ rpeek);
+ }
+
+
+ ptr += sock_stat->cfs_len;
+ curr_len += sock_stat->cfs_len;
+ } while (1);
+
+ free(buffer);
+}
+
+
+#define PR32(x) printf(#x " %u\n", stats-> x)
+#define PR64(x) printf(#x " %llu\n", stats-> x)
+void
+print_cfil_stats()
+{
+ size_t len, alloc_len;
+ void *buffer = NULL;
+ struct cfil_stats *stats;
+
+ if (sysctlbyname("net.cfil.stats", NULL, &len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.stats)");
+
+ if (len < sizeof(struct cfil_stats))
+ alloc_len = sizeof(struct cfil_stats);
+ else
+ alloc_len = len;
+
+ buffer = malloc(alloc_len);
+ if (buffer == NULL)
+ err(1, "malloc()");
+ if (sysctlbyname("net.cfil.stats", buffer, &len, NULL, 0) == -1)
+ err(1, "sysctlbyname(net.cfil.stats)");
+ stats = (struct cfil_stats *)buffer;
+
+ PR32(cfs_ctl_connect_ok);
+ PR32(cfs_ctl_connect_fail);
+ PR32(cfs_ctl_connect_ok);
+ PR32(cfs_ctl_connect_fail);
+ PR32(cfs_ctl_disconnect_ok);
+ PR32(cfs_ctl_disconnect_fail);
+ PR32(cfs_ctl_send_ok);
+ PR32(cfs_ctl_send_bad);
+ PR32(cfs_ctl_rcvd_ok);
+ PR32(cfs_ctl_rcvd_bad);
+ PR32(cfs_ctl_rcvd_flow_lift);
+ PR32(cfs_ctl_action_data_update);
+ PR32(cfs_ctl_action_drop);
+ PR32(cfs_ctl_action_bad_op);
+ PR32(cfs_ctl_action_bad_len);
+
+ PR32(cfs_sock_id_not_found);
+
+ PR32(cfs_cfi_alloc_ok);
+ PR32(cfs_cfi_alloc_fail);
+
+ PR32(cfs_sock_userspace_only);
+ PR32(cfs_sock_attach_in_vain);
+ PR32(cfs_sock_attach_already);
+ PR32(cfs_sock_attach_no_mem);
+ PR32(cfs_sock_attach_failed);
+ PR32(cfs_sock_attached);
+ PR32(cfs_sock_detached);
+
+ PR32(cfs_attach_event_ok);
+ PR32(cfs_attach_event_flow_control);
+ PR32(cfs_attach_event_fail);
+
+ PR32(cfs_closed_event_ok);
+ PR32(cfs_closed_event_flow_control);
+ PR32(cfs_closed_event_fail);
+
+ PR32(cfs_data_event_ok);
+ PR32(cfs_data_event_flow_control);
+ PR32(cfs_data_event_fail);
+
+ PR32(cfs_disconnect_in_event_ok);
+ PR32(cfs_disconnect_out_event_ok);
+ PR32(cfs_disconnect_event_flow_control);
+ PR32(cfs_disconnect_event_fail);
+
+ PR32(cfs_ctl_q_not_started);
+
+ PR32(cfs_close_wait);
+ PR32(cfs_close_wait_timeout);
+
+ PR32(cfs_flush_in_drop);
+ PR32(cfs_flush_out_drop);
+ PR32(cfs_flush_in_close);
+ PR32(cfs_flush_out_close);
+ PR32(cfs_flush_in_free);
+ PR32(cfs_flush_out_free);
+
+ PR32(cfs_inject_q_nomem);
+ PR32(cfs_inject_q_nobufs);
+ PR32(cfs_inject_q_detached);
+ PR32(cfs_inject_q_in_fail);
+ PR32(cfs_inject_q_out_fail);
+
+ PR32(cfs_inject_q_in_retry);
+ PR32(cfs_inject_q_out_retry);
+
+ PR32(cfs_data_in_control);
+ PR32(cfs_data_in_oob);
+ PR32(cfs_data_out_control);
+ PR32(cfs_data_out_oob);
+
+ PR64(cfs_ctl_q_in_enqueued);
+ PR64(cfs_ctl_q_out_enqueued);
+ PR64(cfs_ctl_q_in_peeked);
+ PR64(cfs_ctl_q_out_peeked);
+
+ PR64(cfs_pending_q_in_enqueued);
+ PR64(cfs_pending_q_out_enqueued);
+
+ PR64(cfs_inject_q_in_enqueued);
+ PR64(cfs_inject_q_out_enqueued);
+ PR64(cfs_inject_q_in_passed);
+ PR64(cfs_inject_q_out_passed);
+}
diff --git a/network_cmds/cfilutil/cfilutil.1 b/network_cmds/cfilutil/cfilutil.1
new file mode 100644
index 0000000..0d97adf
--- /dev/null
+++ b/network_cmds/cfilutil/cfilutil.1
@@ -0,0 +1,56 @@
+.Dd 2/10/14
+.Dt cfilutil 1
+.Os Darwin
+.Sh NAME
+.Nm cfilutil
+.Nd Tool to exercise the content filter subsystem.
+.Sh SYNOPSIS
+.Nm
+.Op Fl hilqsv
+.Fl u Ar unit
+.Op Fl a Ar offset
+.Op Fl d Ar offset value
+.Op Fl k Ar increment
+.Op Fl m Ar length
+.Op Fl p Ar offset
+.Op Fl r Ar random
+.Op Fl t Ar delay
+.Sh DESCRIPTION
+Use
+.Nm
+to exercise the content filter subsystem.
+.Pp
+The flags have the following meaning:
+.Bl -tag -width -indent
+.It Fl a Ar offset
+Auto start filtering with given offset.
+.It Fl a Ar offset value
+Default values for offset passin, peekin, passout, peekout, pass or peek.
+.It Fl h
+Display this help.
+.It Fl i
+Interactive mode.
+.It Fl k Ar increment
+Peek mode with increment.
+.It Fl l
+Pass loopback traffic.
+.It Fl m Ar length
+Maximum dump length.
+.It Fl p Ar offset
+Pass mode (all or after given offset if it is > 0).
+.It Fl q
+Decrease verbosity.
+.It Fl r Ar rate
+Random drop rate.
+.It Fl s
+display content filter statistics (all, sock, filt, cfil).
+.It Fl t Ar delay
+Pass delay in microseconds.
+.It Fl u Ar unit
+NECP filter control unit.
+.It Fl v
+Increase verbosity.
+.El
+.Pp
+.Sh SEE ALSO
+.Xr neutil 1 \" rdar://16115914
diff --git a/network_cmds/cfilutil/cfilutil.c b/network_cmds/cfilutil/cfilutil.c
new file mode 100644
index 0000000..4aaa719
--- /dev/null
+++ b/network_cmds/cfilutil/cfilutil.c
@@ -0,0 +1,987 @@
+/*
+ * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/sys_domain.h>
+#include <sys/ioctl.h>
+#include <sys/kern_control.h>
+#include <sys/queue.h>
+#include <net/content_filter.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sysexits.h>
+
+extern void print_filter_list(void);
+extern void print_socket_list(void);
+extern void print_cfil_stats(void);
+
+#define MAX_BUFFER (65536 + 1024)
+
+#define MAXHEXDUMPCOL 16
+
+
+enum {
+ MODE_NONE = 0,
+ MODE_INTERACTIVE = 0x01,
+ MODE_PEEK = 0x02,
+ MODE_PASS = 0x04,
+ MODE_DELAY = 0x08
+};
+int mode = MODE_NONE;
+
+unsigned long delay_ms = 0;
+struct timeval delay_tv = { 0, 0 };
+long verbosity = 0;
+uint32_t necp_control_unit = 0;
+unsigned long auto_start = 0;
+uint64_t peek_inc = 0;
+uint64_t pass_offset = 0;
+struct timeval now, deadline;
+int sf = -1;
+int pass_loopback = 0;
+uint32_t random_drop = 0;
+uint32_t event_total = 0;
+uint32_t event_dropped = 0;
+
+uint64_t default_in_pass = 0;
+uint64_t default_in_peek = 0;
+uint64_t default_out_pass = 0;
+uint64_t default_out_peek = 0;
+
+unsigned long max_dump_len = 32;
+
+TAILQ_HEAD(sock_info_head, sock_info) sock_info_head = TAILQ_HEAD_INITIALIZER(sock_info_head);
+
+
+struct sock_info {
+ TAILQ_ENTRY(sock_info) si_link;
+ cfil_sock_id_t si_sock_id;
+ struct timeval si_deadline;
+ uint64_t si_in_pass;
+ uint64_t si_in_peek;
+ uint64_t si_out_pass;
+ uint64_t si_out_peek;
+};
+
+static void
+HexDump(void *data, size_t len)
+{
+ size_t i, j, k;
+ unsigned char *ptr = (unsigned char *)data;
+ unsigned char buf[32 + 3 * MAXHEXDUMPCOL + 2 + MAXHEXDUMPCOL + 1];
+
+ for (i = 0; i < len; i += MAXHEXDUMPCOL) {
+ k = snprintf((char *)buf, sizeof(buf), "\t0x%04lx: ", i);
+ for (j = i; j < i + MAXHEXDUMPCOL; j++) {
+ if (j < len) {
+ unsigned char msnbl = ptr[j] >> 4;
+ unsigned char lsnbl = ptr[j] & 0x0f;
+
+ buf[k++] = msnbl < 10 ? msnbl + '0' : msnbl + 'a' - 10;
+ buf[k++] = lsnbl < 10 ? lsnbl + '0' : lsnbl + 'a' - 10;
+ } else {
+ buf[k++] = ' ';
+ buf[k++] = ' ';
+ }
+ if ((j % 2) == 1)
+ buf[k++] = ' ';
+ if ((j % MAXHEXDUMPCOL) == MAXHEXDUMPCOL - 1)
+ buf[k++] = ' ';
+ }
+
+ buf[k++] = ' ';
+ buf[k++] = ' ';
+
+ for (j = i; j < i + MAXHEXDUMPCOL && j < len; j++) {
+ if (isprint(ptr[j]))
+ buf[k++] = ptr[j];
+ else
+ buf[k++] = '.';
+ }
+ buf[k] = 0;
+ printf("%s\n", buf);
+ }
+}
+
+void
+print_hdr(struct cfil_msg_hdr *hdr)
+{
+ const char *typestr = "unknown";
+ const char *opstr = "unknown";
+
+ if (hdr->cfm_type == CFM_TYPE_EVENT) {
+ typestr = "event";
+ switch (hdr->cfm_op) {
+ case CFM_OP_SOCKET_ATTACHED:
+ opstr = "attached";
+ break;
+ case CFM_OP_SOCKET_CLOSED:
+ opstr = "closed";
+ break;
+ case CFM_OP_DATA_OUT:
+ opstr = "dataout";
+ break;
+ case CFM_OP_DATA_IN:
+ opstr = "datain";
+ break;
+ case CFM_OP_DISCONNECT_OUT:
+ opstr = "disconnectout";
+ break;
+ case CFM_OP_DISCONNECT_IN:
+ opstr = "disconnectin";
+ break;
+
+ default:
+ break;
+ }
+ } else if (hdr->cfm_type == CFM_TYPE_ACTION) {
+ typestr = "action";
+ switch (hdr->cfm_op) {
+ case CFM_OP_DATA_UPDATE:
+ opstr = "update";
+ break;
+ case CFM_OP_DROP:
+ opstr = "drop";
+ break;
+
+ default:
+ break;
+ }
+
+ }
+ printf("%s %s len %u version %u type %u op %u sock_id 0x%llx\n",
+ typestr, opstr,
+ hdr->cfm_len, hdr->cfm_version, hdr->cfm_type,
+ hdr->cfm_op, hdr->cfm_sock_id);
+}
+
+void
+print_data_req(struct cfil_msg_data_event *data_req)
+{
+ size_t datalen;
+ void *databuf;
+
+ if (verbosity <= 0)
+ return;
+
+ print_hdr(&data_req->cfd_msghdr);
+
+ printf(" start %llu end %llu\n",
+ data_req->cfd_start_offset, data_req->cfd_end_offset);
+
+ datalen = (size_t)(data_req->cfd_end_offset - data_req->cfd_start_offset);
+
+ databuf = (void *)(data_req + 1);
+
+ if (verbosity > 1)
+ HexDump(databuf, MIN(datalen, max_dump_len));
+}
+
+void
+print_action_msg(struct cfil_msg_action *action)
+{
+ if (verbosity <= 0)
+ return;
+
+ print_hdr(&action->cfa_msghdr);
+
+ if (action->cfa_msghdr.cfm_op == CFM_OP_DATA_UPDATE)
+ printf(" out pass %llu peek %llu in pass %llu peek %llu\n",
+ action->cfa_out_pass_offset, action->cfa_out_peek_offset,
+ action->cfa_in_pass_offset, action->cfa_in_peek_offset);
+}
+
+struct sock_info *
+find_sock_info(cfil_sock_id_t sockid)
+{
+ struct sock_info *sock_info;
+
+ TAILQ_FOREACH(sock_info, &sock_info_head, si_link) {
+ if (sock_info->si_sock_id == sockid)
+ return (sock_info);
+ }
+ return (NULL);
+}
+
+struct sock_info *
+add_sock_info(cfil_sock_id_t sockid)
+{
+ struct sock_info *sock_info;
+
+ if (find_sock_info(sockid) != NULL)
+ return (NULL);
+
+ sock_info = calloc(1, sizeof(struct sock_info));
+ if (sock_info == NULL)
+ err(EX_OSERR, "calloc()");
+ sock_info->si_sock_id = sockid;
+ TAILQ_INSERT_TAIL(&sock_info_head, sock_info, si_link);
+
+ return (sock_info);
+}
+
+void
+remove_sock_info(cfil_sock_id_t sockid)
+{
+ struct sock_info *sock_info = find_sock_info(sockid);
+
+ if (sock_info != NULL) {
+ TAILQ_REMOVE(&sock_info_head, sock_info, si_link);
+ free(sock_info);
+ }
+}
+
+/* return 0 if timer is already set */
+int
+set_sock_info_deadline(struct sock_info *sock_info)
+{
+ if (timerisset(&sock_info->si_deadline))
+ return (0);
+
+ timeradd(&now, &sock_info->si_deadline, &sock_info->si_deadline);
+
+ if (!timerisset(&deadline)) {
+ timeradd(&now, &delay_tv, &deadline);
+ }
+
+ return (1);
+}
+
+void
+send_action_message(uint32_t op, struct sock_info *sock_info, int nodelay)
+{
+ struct cfil_msg_action action;
+
+ if (!nodelay && delay_ms) {
+ set_sock_info_deadline(sock_info);
+ return;
+ }
+ bzero(&action, sizeof(struct cfil_msg_action));
+ action.cfa_msghdr.cfm_len = sizeof(struct cfil_msg_action);
+ action.cfa_msghdr.cfm_version = CFM_VERSION_CURRENT;
+ action.cfa_msghdr.cfm_type = CFM_TYPE_ACTION;
+ action.cfa_msghdr.cfm_op = op;
+ action.cfa_msghdr.cfm_sock_id = sock_info->si_sock_id;
+ switch (op) {
+ case CFM_OP_DATA_UPDATE:
+ action.cfa_out_pass_offset = sock_info->si_out_pass;
+ action.cfa_out_peek_offset = sock_info->si_out_peek;
+ action.cfa_in_pass_offset = sock_info->si_in_pass;
+ action.cfa_in_peek_offset = sock_info->si_in_peek;
+ break;
+
+ default:
+ break;
+ }
+
+ if (verbosity > -1)
+ print_action_msg(&action);
+
+ if (send(sf, &action, sizeof(struct cfil_msg_action), 0) == -1)
+ warn("send()");
+
+ timerclear(&sock_info->si_deadline);
+}
+
+void
+process_delayed_actions()
+{
+ struct sock_info *sock_info;
+
+ TAILQ_FOREACH(sock_info, &sock_info_head, si_link) {
+ if (timerisset(&sock_info->si_deadline) &&
+ timercmp(&sock_info->si_deadline, &now, >=))
+ send_action_message(CFM_OP_DATA_UPDATE, sock_info, 1);
+ }
+}
+
+int
+set_non_blocking(int fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ warn("fcntl(F_GETFL)");
+ return (-1);
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) == -1) {
+ warn("fcntl(F_SETFL)");
+ return (-1);
+ }
+ return (0);
+}
+
+int
+offset_from_str(const char *str, uint64_t *ret_val)
+{
+ char *endptr;
+ uint64_t offset;
+ int success = 1;
+
+ if (strcasecmp(str, "max") == 0 || strcasecmp(str, "all") == 0)
+ offset = CFM_MAX_OFFSET;
+ else {
+ offset = strtoull(str, &endptr, 0);
+ if (*str == '\0' || *endptr != '\0')
+ success = 0;
+ }
+ if (success)
+ *ret_val = offset;
+ return (success);
+}
+
+#define IN6_IS_ADDR_V4MAPPED_LOOPBACK(a) \
+ ((*(const __uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
+ (*(const __uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
+ (*(const __uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)) && \
+ (*(const __uint32_t *)(const void *)(&(a)->s6_addr[12]) == ntohl(INADDR_LOOPBACK)))
+
+
+int
+is_loopback(struct cfil_msg_data_event *data_req)
+{
+ if (data_req->cfc_dst.sa.sa_family == AF_INET &&
+ ntohl(data_req->cfc_dst.sin.sin_addr.s_addr) == INADDR_LOOPBACK)
+ return (1);
+ if (data_req->cfc_dst.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LOOPBACK(&data_req->cfc_dst.sin6.sin6_addr))
+ return (1);
+ if (data_req->cfc_dst.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED_LOOPBACK(&data_req->cfc_dst.sin6.sin6_addr))
+ return (1);
+
+ if (data_req->cfc_src.sa.sa_family == AF_INET &&
+ ntohl(data_req->cfc_src.sin.sin_addr.s_addr) == INADDR_LOOPBACK)
+ return (1);
+ if (data_req->cfc_src.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_LOOPBACK(&data_req->cfc_src.sin6.sin6_addr))
+ return (1);
+ if (data_req->cfc_src.sa.sa_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED_LOOPBACK(&data_req->cfc_src.sin6.sin6_addr))
+ return (1);
+
+ return (0);
+}
+
+int
+drop(struct sock_info *sock_info)
+{
+ event_total++;
+ if (random_drop > 0) {
+ uint32_t r = arc4random();
+ if (r <= random_drop) {
+ event_dropped++;
+ printf("dropping 0x%llx dropped %u total %u rate %f\n",
+ sock_info->si_sock_id,
+ event_dropped, event_total,
+ (double)event_dropped/(double)event_total * 100);
+ send_action_message(CFM_OP_DROP, sock_info, 0);
+ return (1);
+ }
+ }
+ return (0);
+}
+
+int
+doit()
+{
+ struct sockaddr_ctl sac;
+ struct ctl_info ctl_info;
+ void *buffer = NULL;
+ struct cfil_msg_hdr *hdr;
+ int kq = -1;
+ struct kevent kv;
+ int fdin = fileno(stdin);
+ char *linep = NULL;
+ size_t linecap = 0;
+ char *cmdptr = NULL;
+ char *argptr = NULL;
+ size_t cmdlen = 0;
+ struct cfil_msg_action action;
+ cfil_sock_id_t last_sock_id = 0;
+ struct sock_info *sock_info = NULL;
+ struct timeval last_time, elapsed, delta;
+ struct timespec interval, *timeout = NULL;
+
+ kq = kqueue();
+ if (kq == -1)
+ err(1, "kqueue()");
+
+ sf = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (sf == -1)
+ err(1, "socket()");
+
+ bzero(&ctl_info, sizeof(struct ctl_info));
+ strlcpy(ctl_info.ctl_name, CONTENT_FILTER_CONTROL_NAME, sizeof(ctl_info.ctl_name));
+ if (ioctl(sf, CTLIOCGINFO, &ctl_info) == -1)
+ err(1, "ioctl(CTLIOCGINFO)");
+
+ if (fcntl(sf, F_SETNOSIGPIPE, 1) == -1)
+ err(1, "fcntl(F_SETNOSIGPIPE)");
+
+ bzero(&sac, sizeof(struct sockaddr_ctl));
+ sac.sc_len = sizeof(struct sockaddr_ctl);
+ sac.sc_family = AF_SYSTEM;
+ sac.ss_sysaddr = AF_SYS_CONTROL;
+ sac.sc_id = ctl_info.ctl_id;
+
+ if (connect(sf, (struct sockaddr *)&sac, sizeof(struct sockaddr_ctl)) == -1)
+ err(1, "connect()");
+
+ if (set_non_blocking(sf) == -1)
+ err(1, "set_non_blocking(sf)");
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, CFIL_OPT_NECP_CONTROL_UNIT,
+ &necp_control_unit, sizeof(uint32_t)) == -1)
+ err(1, "setsockopt(CFIL_OPT_NECP_CONTROL_UNIT, %u)", necp_control_unit);
+
+ bzero(&kv, sizeof(struct kevent));
+ kv.ident = sf;
+ kv.filter = EVFILT_READ;
+ kv.flags = EV_ADD;
+ if (kevent(kq, &kv, 1, NULL, 0, NULL) == -1)
+ err(1, "kevent(sf %d)", sf);
+
+ /*
+ * We can only read from an interactive terminal
+ */
+ if (isatty(fdin)) {
+ bzero(&kv, sizeof(struct kevent));
+ kv.ident = fdin;
+ kv.filter = EVFILT_READ;
+ kv.flags = EV_ADD;
+ if (kevent(kq, &kv, 1, NULL, 0, NULL) == -1)
+ err(1, "kevent(fdin %d)", fdin);
+ }
+
+ buffer = malloc(MAX_BUFFER);
+ if (buffer == NULL)
+ err(1, "malloc()");
+
+ gettimeofday(&now, NULL);
+
+ while (1) {
+ last_time = now;
+ if (delay_ms && timerisset(&deadline)) {
+ timersub(&deadline, &now, &delta);
+ TIMEVAL_TO_TIMESPEC(&delta, &interval);
+ timeout = &interval;
+ } else {
+ timeout = NULL;
+ }
+
+ if (kevent(kq, NULL, 0, &kv, 1, timeout) == -1) {
+ if (errno == EINTR)
+ continue;
+ err(1, "kevent()");
+ }
+ gettimeofday(&now, NULL);
+ timersub(&now, &last_time, &elapsed);
+ if (delay_ms && timerisset(&deadline)) {
+ if (timercmp(&now, &deadline, >=)) {
+ process_delayed_actions();
+ interval.tv_sec = 0;
+ interval.tv_nsec = 0;
+ }
+ }
+
+ if (kv.ident == sf && kv.filter == EVFILT_READ) {
+ while (1) {
+ ssize_t nread;
+
+ nread = recv(sf, buffer, MAX_BUFFER, 0);
+ if (nread == 0) {
+ warnx("recv(sf) returned 0, connection closed");
+ break;
+ }
+ if (nread == -1) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK)
+ break;
+ err(1, "recv()");
+
+ }
+ if (nread < sizeof(struct cfil_msg_hdr))
+ errx(1, "too small");
+ hdr = (struct cfil_msg_hdr *)buffer;
+
+
+ if (hdr->cfm_type != CFM_TYPE_EVENT) {
+ warnx("not a content filter event type %u", hdr->cfm_type);
+ continue;
+ }
+ switch (hdr->cfm_op) {
+ case CFM_OP_SOCKET_ATTACHED: {
+ struct cfil_msg_sock_attached *msg_attached = (struct cfil_msg_sock_attached *)hdr;
+
+ if (verbosity > -2)
+ print_hdr(hdr);
+ if (verbosity > -1)
+ printf(" fam %d type %d proto %d pid %u epid %u\n",
+ msg_attached->cfs_sock_family,
+ msg_attached->cfs_sock_type,
+ msg_attached->cfs_sock_protocol,
+ msg_attached->cfs_pid,
+ msg_attached->cfs_e_pid);
+ break;
+ }
+ case CFM_OP_SOCKET_CLOSED:
+ case CFM_OP_DISCONNECT_IN:
+ case CFM_OP_DISCONNECT_OUT:
+ if (verbosity > -2)
+ print_hdr(hdr);
+ break;
+ case CFM_OP_DATA_OUT:
+ case CFM_OP_DATA_IN:
+ if (verbosity > -3)
+ print_data_req((struct cfil_msg_data_event *)hdr);
+ break;
+ default:
+ warnx("unknown content filter event op %u", hdr->cfm_op);
+ continue;
+ }
+ switch (hdr->cfm_op) {
+ case CFM_OP_SOCKET_ATTACHED:
+ sock_info = add_sock_info(hdr->cfm_sock_id);
+ if (sock_info == NULL) {
+ warnx("sock_id %llx already exists", hdr->cfm_sock_id);
+ continue;
+ }
+ break;
+ case CFM_OP_DATA_OUT:
+ case CFM_OP_DATA_IN:
+ case CFM_OP_DISCONNECT_IN:
+ case CFM_OP_DISCONNECT_OUT:
+ case CFM_OP_SOCKET_CLOSED:
+ sock_info = find_sock_info(hdr->cfm_sock_id);
+
+ if (sock_info == NULL) {
+ warnx("unexpected data message, sock_info is NULL");
+ continue;
+ }
+ break;
+ default:
+ warnx("unknown content filter event op %u", hdr->cfm_op);
+ continue;
+ }
+
+
+ switch (hdr->cfm_op) {
+ case CFM_OP_SOCKET_ATTACHED: {
+ if ((mode & MODE_PASS) || (mode & MODE_PEEK) || auto_start) {
+ sock_info->si_out_pass = default_out_pass;
+ sock_info->si_out_peek = (mode & MODE_PEEK) ? peek_inc : (mode & MODE_PASS) ? CFM_MAX_OFFSET : default_out_peek;
+ sock_info->si_in_pass = default_in_pass;
+ sock_info->si_in_peek = (mode & MODE_PEEK) ? peek_inc : (mode & MODE_PASS) ? CFM_MAX_OFFSET : default_in_peek;
+
+ send_action_message(CFM_OP_DATA_UPDATE, sock_info, 0);
+ }
+ break;
+ }
+ case CFM_OP_SOCKET_CLOSED: {
+ remove_sock_info(hdr->cfm_sock_id);
+ sock_info = NULL;
+ break;
+ }
+ case CFM_OP_DATA_OUT:
+ case CFM_OP_DATA_IN: {
+ struct cfil_msg_data_event *data_req = (struct cfil_msg_data_event *)hdr;
+
+ if (pass_loopback && is_loopback(data_req)) {
+ sock_info->si_out_pass = CFM_MAX_OFFSET;
+ sock_info->si_in_pass = CFM_MAX_OFFSET;
+ } else {
+ if (drop(sock_info))
+ continue;
+
+ if ((mode & MODE_PASS)) {
+ if (data_req->cfd_msghdr.cfm_op == CFM_OP_DATA_OUT) {
+ if (pass_offset == 0 || pass_offset == CFM_MAX_OFFSET)
+ sock_info->si_out_pass = data_req->cfd_end_offset;
+ else if (data_req->cfd_end_offset > pass_offset) {
+ sock_info->si_out_pass = CFM_MAX_OFFSET;
+ sock_info->si_in_pass = CFM_MAX_OFFSET;
+ }
+ sock_info->si_out_peek = (mode & MODE_PEEK) ?
+ data_req->cfd_end_offset + peek_inc : 0;
+ } else {
+ if (pass_offset == 0 || pass_offset == CFM_MAX_OFFSET)
+ sock_info->si_in_pass = data_req->cfd_end_offset;
+ else if (data_req->cfd_end_offset > pass_offset) {
+ sock_info->si_out_pass = CFM_MAX_OFFSET;
+ sock_info->si_in_pass = CFM_MAX_OFFSET;
+ }
+ sock_info->si_in_peek = (mode & MODE_PEEK) ?
+ data_req->cfd_end_offset + peek_inc : 0;
+ }
+ } else {
+ break;
+ }
+ }
+ send_action_message(CFM_OP_DATA_UPDATE, sock_info, 0);
+
+ break;
+ }
+ case CFM_OP_DISCONNECT_IN:
+ case CFM_OP_DISCONNECT_OUT: {
+ if (drop(sock_info))
+ continue;
+
+ if ((mode & MODE_PASS)) {
+ sock_info->si_out_pass = CFM_MAX_OFFSET;
+ sock_info->si_in_pass = CFM_MAX_OFFSET;
+
+ send_action_message(CFM_OP_DATA_UPDATE, sock_info, 0);
+ }
+ break;
+ }
+ default:
+ warnx("unkown message op %u", hdr->cfm_op);
+ break;
+ }
+ if (sock_info)
+ last_sock_id = sock_info->si_sock_id;
+ }
+ }
+ if (kv.ident == fdin && kv.filter == EVFILT_READ) {
+ ssize_t nread;
+ uint64_t offset = 0;
+ int nitems;
+ int op = 0;
+
+ nread = getline(&linep, &linecap, stdin);
+ if (nread == -1)
+ errx(1, "getline()");
+
+ if (verbosity > 2)
+ printf("linecap %lu nread %lu\n", linecap, nread);
+ if (nread > 0)
+ linep[nread - 1] = '\0';
+
+ if (verbosity > 2)
+ HexDump(linep, linecap);
+
+ if (*linep == 0)
+ continue;
+
+ if (cmdptr == NULL || argptr == NULL || linecap > cmdlen) {
+ cmdlen = linecap;
+ cmdptr = realloc(cmdptr, cmdlen);
+ argptr = realloc(argptr, cmdlen);
+ }
+
+ /*
+ * Trick to support unisgned and hexadecimal arguments
+ * as I can't figure out sscanf() conversions
+ */
+ nitems = sscanf(linep, "%s %s", cmdptr, argptr);
+ if (nitems == 0) {
+ warnx("I didn't get that...");
+ continue;
+ } else if (nitems > 1) {
+ if (offset_from_str(argptr, &offset) == 0) {
+ warnx("I didn't get that either...");
+ continue;
+ }
+ }
+ if (verbosity > 2)
+ printf("nitems %d %s %s\n", nitems, cmdptr, argptr);
+
+ bzero(&action, sizeof(struct cfil_msg_action));
+ action.cfa_msghdr.cfm_len = sizeof(struct cfil_msg_action);
+ action.cfa_msghdr.cfm_version = CFM_VERSION_CURRENT;
+ action.cfa_msghdr.cfm_type = CFM_TYPE_ACTION;
+
+ if (strcasecmp(cmdptr, "passout") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_pass_offset = offset;
+ } else if (strcasecmp(cmdptr, "passin") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_in_pass_offset = offset;
+ } else if (strcasecmp(cmdptr, "pass") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_pass_offset = offset;
+ action.cfa_in_pass_offset = offset;
+ } else if (strcasecmp(cmdptr, "peekout") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_peek_offset = offset;
+ } else if (strcasecmp(cmdptr, "peekin") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_in_peek_offset = offset;
+ } else if (strcasecmp(cmdptr, "peek") == 0 && nitems > 1) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_peek_offset = offset;
+ action.cfa_in_peek_offset = offset;
+ } else if (strcasecmp(cmdptr, "start") == 0) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_pass_offset = 0;
+ action.cfa_out_peek_offset = CFM_MAX_OFFSET;
+ action.cfa_in_pass_offset = 0;
+ action.cfa_in_peek_offset = CFM_MAX_OFFSET;
+ } else if (strcasecmp(cmdptr, "peekall") == 0) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_peek_offset = CFM_MAX_OFFSET;
+ action.cfa_in_peek_offset = CFM_MAX_OFFSET;
+ } else if (strcasecmp(cmdptr, "passall") == 0) {
+ op = CFM_OP_DATA_UPDATE;
+ action.cfa_out_pass_offset = CFM_MAX_OFFSET;
+ action.cfa_out_peek_offset = CFM_MAX_OFFSET;
+ action.cfa_in_pass_offset = CFM_MAX_OFFSET;
+ action.cfa_in_peek_offset = CFM_MAX_OFFSET;
+ } else if (strcasecmp(cmdptr, "drop") == 0)
+ op = CFM_OP_DROP;
+ else if (strcasecmp(cmdptr, "sock") == 0) {
+ last_sock_id = offset;
+ printf("last_sock_id 0x%llx\n", last_sock_id);
+ } else
+ warnx("syntax error");
+
+ if (op == CFM_OP_DATA_UPDATE || op == CFM_OP_DROP) {
+ action.cfa_msghdr.cfm_op = op;
+ action.cfa_msghdr.cfm_sock_id = last_sock_id;
+ print_action_msg(&action);
+
+ if (send(sf, &action, sizeof(struct cfil_msg_action), 0) == -1)
+ warn("send()");
+ }
+ }
+ }
+
+ return 0;
+}
+
+static const char *
+basename(const char * str)
+{
+ const char *last_slash = strrchr(str, '/');
+
+ if (last_slash == NULL)
+ return (str);
+ else
+ return (last_slash + 1);
+}
+
+struct option_desc {
+ const char *option;
+ const char *description;
+ int required;
+};
+
+struct option_desc option_desc_list[] = {
+ { "-a offset", "auto start with offset", 0 },
+ { "-d offset value", "default offset value for passin, peekin, passout, peekout, pass, peek", 0 },
+ { "-h", "dsiplay this help", 0 },
+ { "-i", "interactive mode", 0 },
+ { "-k increment", "peek mode with increment", 0 },
+ {"-l", "pass loopback", 0 },
+ { "-m length", "max dump length", 0 },
+ { "-p offset", "pass mode (all or after given offset if > 0)", 0 },
+ { "-q", "decrease verbose level", 0 },
+ { "-r random", "random drop rate", 0 },
+ { "-s ", "display content filter statistics (all, sock, filt, cfil)", 0 },
+ { "-t delay", "pass delay in microseconds", 0 },
+ { "-u unit", "NECP filter control unit", 1 },
+ { "-v", "increase verbose level", 0 },
+ { NULL, NULL, 0 } /* Mark end of list */
+};
+
+static void
+usage(const char *cmd)
+{
+ struct option_desc *option_desc;
+ char *usage_str = malloc(LINE_MAX);
+ size_t usage_len;
+
+ if (usage_str == NULL)
+ err(1, "%s: malloc(%d)", __func__, LINE_MAX);
+
+ usage_len = snprintf(usage_str, LINE_MAX, "# usage: %s ", basename(cmd));
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ int len;
+
+ if (option_desc->required)
+ len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "%s ", option_desc->option);
+ else
+ len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "[%s] ", option_desc->option);
+ if (len < 0)
+ err(1, "%s: snprintf(", __func__);
+
+ usage_len += len;
+ if (usage_len > LINE_MAX)
+ break;
+ }
+ printf("%s\n", usage_str);
+ printf("options:\n");
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ printf(" %-20s # %s\n", option_desc->option, option_desc->description);
+ }
+
+}
+
+int
+main(int argc, char * const argv[])
+{
+ int ch;
+ double d;
+ int stats_sock_list = 0;
+ int stats_filt_list = 0;
+ int stats_cfil_stats = 0;
+
+ while ((ch = getopt(argc, argv, "a:d:hik:lm:p:qr:s:t:u:v")) != -1) {
+ switch (ch) {
+ case 'a':
+ auto_start = strtoul(optarg, NULL, 0);
+ break;
+ case 'd': {
+ if (optind >= argc)
+ errx(1, "'-d' needs 2 parameters");
+ if (strcasecmp(optarg, "passout") == 0) {
+ if (offset_from_str(argv[optind], &default_out_pass) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ } else if (strcasecmp(optarg, "passin") == 0) {
+ if (offset_from_str(argv[optind], &default_in_pass) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ } else if (strcasecmp(optarg, "pass") == 0) {
+ if (offset_from_str(argv[optind], &default_out_pass) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ default_in_pass = default_out_pass;
+ } else if (strcasecmp(optarg, "peekout") == 0) {
+ if (offset_from_str(argv[optind], &default_out_peek) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ } else if (strcasecmp(optarg, "peekin") == 0) {
+ if (offset_from_str(argv[optind], &default_in_peek) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ } else if (strcasecmp(optarg, "peek") == 0) {
+ if (offset_from_str(argv[optind], &default_out_peek) == 0)
+ errx(1, "bad %s offset: %s", optarg, argv[optind + 1]);
+ default_in_peek = default_out_peek;
+ } else
+ errx(1, "syntax error");
+ break;
+ }
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ case 'i':
+ mode |= MODE_INTERACTIVE;
+ break;
+ case 'k':
+ mode |= MODE_PEEK;
+ if (offset_from_str(optarg, &peek_inc) == 0)
+ errx(1, "bad peek offset: %s", optarg);
+ break;
+ case 'l':
+ pass_loopback = 1;
+ break;
+ case 'm':
+ max_dump_len = strtoul(optarg, NULL, 0);
+ break;
+ case 'p':
+ mode |= MODE_PASS;
+ if (offset_from_str(optarg, &pass_offset) == 0)
+ errx(1, "bad pass offset: %s", optarg);
+ break;
+ case 'q':
+ verbosity--;
+ break;
+ case 'r':
+ d = strtod(optarg, NULL);
+ if (d < 0 || d > 1)
+ errx(1, "bad drop rate: %s -- it must be between 0 and 1", optarg);
+ random_drop = (uint32_t)(d * UINT32_MAX);
+ break;
+ case 's':
+ if (strcasecmp(optarg, "all") == 0) {
+ stats_sock_list = 1;
+ stats_filt_list = 1;
+ stats_cfil_stats = 1;
+ } else if (strcasecmp(optarg, "sock") == 0) {
+ stats_sock_list = 1;
+ } else if (strcasecmp(optarg, "filt") == 0) {
+ stats_filt_list = 1;
+ } else if (strcasecmp(optarg, "cfil") == 0) {
+ stats_cfil_stats = 1;
+ } else {
+ warnx("# Error: unknown type of statistic: %s", optarg);
+ usage(argv[0]);
+ exit(0);
+ }
+ break;
+ case 't':
+ mode |= MODE_DELAY;
+ delay_ms = strtoul(optarg, NULL, 0);
+ delay_tv.tv_sec = delay_ms / 1000;
+ delay_tv.tv_usec = (delay_ms % 1000) * 1000;
+ break;
+ case 'u':
+ necp_control_unit = (uint32_t)strtoul(optarg, NULL, 0);
+ break;
+ case 'v':
+ verbosity++;
+ break;
+ default:
+ errx(1, "# syntax error, unknow option '%d'", ch);
+ usage(argv[0]);
+ exit(0);
+ }
+ }
+
+ if (stats_filt_list)
+ print_filter_list();
+ if (stats_sock_list)
+ print_socket_list();
+ if (stats_cfil_stats)
+ print_cfil_stats();
+ if (necp_control_unit == 0 && (stats_filt_list || stats_sock_list || stats_cfil_stats))
+ return (0);
+
+ if (necp_control_unit == 0) {
+ warnx("necp filter control unit is 0");
+ usage(argv[0]);
+ exit(EX_USAGE);
+ }
+ doit();
+
+
+ return (0);
+}
+
diff --git a/network_cmds/dnctl/dnctl.8 b/network_cmds/dnctl/dnctl.8
new file mode 100644
index 0000000..4da4724
--- /dev/null
+++ b/network_cmds/dnctl/dnctl.8
@@ -0,0 +1,508 @@
+.Dd August 13, 2002
+.Dt DNCTL 8
+.Os Darwin
+.Sh NAME
+.Nm dnctl
+.Nd Traffic shaper control program
+.Sh SYNOPSIS
+.Nm
+.Op Fl anqs
+.Brq Cm list | show
+.Nm
+.Op Fl f | q
+.Cm flush
+.Nm
+.Op Fl q
+.Brq Cm delete
+.Op Ar number ...
+.Nm
+.Brq Cm pipe | queue
+.Ar number
+.Cm config
+.Ar config-options
+.Nm
+.Op Fl s Op Ar field
+.Brq Cm pipe | queue
+.Brq Cm delete | list | show
+.Op Ar number ...
+.Nm
+.Op Fl nq
+.Oo
+.Fl p Ar preproc
+.Oo
+.Ar preproc-flags
+.Oc
+.Oc
+.Ar pathname
+.Sh DESCRIPTION
+.Pp
+The
+.Nm
+utility is the user interface for controlling the
+.Xr dummynet 4
+traffic shaper.
+.Pp
+.Nm dummynet
+operates by first using a packet filter to classify packets and divide them into
+.Em flows ,
+using any match pattern that can be used in
+.Nm
+rules.
+Depending on local policies, a flow can contain packets for a single
+TCP connection, or from/to a given host, or entire subnet, or a
+protocol type, etc.
+.Pp
+Packets belonging to the same flow are then passed to either of two
+different objects, which implement the traffic regulation:
+.Bl -hang -offset XXXX
+.It Em pipe
+A pipe emulates a link with given bandwidth, propagation delay,
+queue size and packet loss rate.
+Packets are queued in front of the pipe as they come out from the classifier,
+and then transferred to the pipe according to the pipe's parameters.
+.Pp
+.It Em queue
+A queue
+is an abstraction used to implement the WF2Q+
+(Worst-case Fair Weighted Fair Queueing) policy, which is
+an efficient variant of the WFQ policy.
+.br
+The queue associates a
+.Em weight
+and a reference pipe to each flow, and then all backlogged (i.e.,
+with packets queued) flows linked to the same pipe share the pipe's
+bandwidth proportionally to their weights.
+Note that weights are not priorities; a flow with a lower weight
+is still guaranteed to get its fraction of the bandwidth even if a
+flow with a higher weight is permanently backlogged.
+.Pp
+.El
+In practice,
+.Em pipes
+can be used to set hard limits to the bandwidth that a flow can use, whereas
+.Em queues
+can be used to determine how different flow share the available bandwidth.
+.Pp
+The
+.Em pipe
+and
+.Em queue
+configuration commands are the following:
+.Bd -ragged -offset indent
+.Cm pipe Ar number Cm config Ar pipe-configuration
+.Pp
+.Cm queue Ar number Cm config Ar queue-configuration
+.Ed
+.Pp
+The following parameters can be configured for a pipe:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm bw Ar bandwidth | device
+Bandwidth, measured in
+.Sm off
+.Op Cm K | M
+.Brq Cm bit/s | Byte/s .
+.Sm on
+.Pp
+A value of 0 (default) means unlimited bandwidth.
+The unit must immediately follow the number, as in
+.Pp
+.Dl "dnctl pipe 1 config bw 300Kbit/s"
+.Pp
+If a device name is specified instead of a numeric value, as in
+.Pp
+.Dl "dnctl pipe 1 config bw tun0"
+.Pp
+then the transmit clock is supplied by the specified device.
+At the moment no
+device supports this
+functionality.
+.Pp
+.It Cm delay Ar ms-delay
+Propagation delay, measured in milliseconds.
+The value is rounded to the next multiple of the clock tick
+(typically 10ms, but it is a good practice to run kernels
+with
+.Dq "options HZ=1000"
+to reduce
+the granularity to 1ms or less).
+Default value is 0, meaning no delay.
+.El
+.Pp
+The following parameters can be configured for a queue:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm pipe Ar pipe_nr
+Connects a queue to the specified pipe.
+Multiple queues (with the same or different weights) can be connected to
+the same pipe, which specifies the aggregate rate for the set of queues.
+.Pp
+.It Cm weight Ar weight
+Specifies the weight to be used for flows matching this queue.
+The weight must be in the range 1..100, and defaults to 1.
+.El
+.Pp
+Finally, the following parameters can be configured for both
+pipes and queues:
+.Pp
+.Bl -tag -width XXXX -compact
+.It Cm buckets Ar hash-table-size
+Specifies the size of the hash table used for storing the
+various queues.
+Default value is 64 controlled by the
+.Xr sysctl 8
+variable
+.Em net.inet.ip.dummynet.hash_size ,
+allowed range is 16 to 65536.
+.Pp
+.It Cm mask Ar mask-specifier
+Packets sent to a given pipe or queue by an
+.Nm
+rule can be further classified into multiple flows, each of which is then
+sent to a different
+.Em dynamic
+pipe or queue.
+A flow identifier is constructed by masking the IP addresses,
+ports and protocol types as specified with the
+.Cm mask
+options in the configuration of the pipe or queue.
+For each different flow identifier, a new pipe or queue is created
+with the same parameters as the original object, and matching packets
+are sent to it.
+.Pp
+Thus, when
+.Em dynamic pipes
+are used, each flow will get the same bandwidth as defined by the pipe,
+whereas when
+.Em dynamic queues
+are used, each flow will share the parent's pipe bandwidth evenly
+with other flows generated by the same queue (note that other queues
+with different weights might be connected to the same pipe).
+.br
+Available mask specifiers are a combination of one or more of the following:
+.Pp
+.Cm dst-ip Ar mask ,
+.Cm dst-ip6 Ar mask ,
+.Cm src-ip Ar mask ,
+.Cm src-ip6 Ar mask ,
+.Cm dst-port Ar mask ,
+.Cm src-port Ar mask ,
+.Cm proto Ar mask
+or
+.Cm all ,
+.Pp
+where the latter means all bits in all fields are significant.
+.Pp
+.It Cm noerror
+When a packet is dropped by a dummynet queue or pipe, the error
+is normally reported to the caller routine in the kernel, in the
+same way as it happens when a device queue fills up. Setting this
+option reports the packet as successfully delivered, which can be
+needed for some experimental setups where you want to simulate
+loss or congestion at a remote router.
+.Pp
+.It Cm plr Ar packet-loss-rate
+Packet loss rate.
+Argument
+.Ar packet-loss-rate
+is a floating-point number between 0 and 1, with 0 meaning no
+loss, 1 meaning 100% loss.
+The loss rate is internally represented on 31 bits.
+.Pp
+.It Cm queue Brq Ar slots | size Ns Cm Kbytes
+Queue size, in
+.Ar slots
+or
+.Cm KBytes .
+Default value is 50 slots, which
+is the typical queue size for Ethernet devices.
+Note that for slow speed links you should keep the queue
+size short or your traffic might be affected by a significant
+queueing delay.
+E.g., 50 max-sized ethernet packets (1500 bytes) mean 600Kbit
+or 20s of queue on a 30Kbit/s pipe.
+Even worse effect can result if you get packets from an
+interface with a much larger MTU, e.g. the loopback interface
+with its 16KB packets.
+.Pp
+.It Cm red | gred Ar w_q Ns / Ns Ar min_th Ns / Ns Ar max_th Ns / Ns Ar max_p
+Make use of the RED (Random Early Detection) queue management algorithm.
+.Ar w_q
+and
+.Ar max_p
+are floating
+point numbers between 0 and 1 (0 not included), while
+.Ar min_th
+and
+.Ar max_th
+are integer numbers specifying thresholds for queue management
+(thresholds are computed in bytes if the queue has been defined
+in bytes, in slots otherwise).
+The
+.Xr dummynet 4
+also supports the gentle RED variant (gred).
+.Pp
+Three
+.Xr sysctl 8
+variables can be used to control the RED behaviour:
+.Bl -tag -width indent
+.It Em net.inet.ip.dummynet.red_lookup_depth
+specifies the accuracy in computing the average queue
+when the link is idle (defaults to 256, must be greater than zero)
+.It Em net.inet.ip.dummynet.red_avg_pkt_size
+specifies the expected average packet size (defaults to 512, must be
+greater than zero)
+.It Em net.inet.ip.dummynet.red_max_pkt_size
+specifies the expected maximum packet size, only used when queue
+thresholds are in bytes (defaults to 1500, must be greater than zero).
+.El
+.El
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+While listing, show counter values.
+The
+.Cm show
+command just implies this option.
+.It Fl f
+Don't ask for confirmation for commands that can cause problems
+if misused,
+.No i.e. Cm flush .
+If there is no tty associated with the process, this is implied.
+.It Fl h
+Displays a short help.
+.It Fl n
+Only check syntax of the command strings, without actually passing
+them to the kernel.
+.It Fl q
+While
+.Cm add Ns ing ,
+.Cm zero Ns ing ,
+.Cm resetlog Ns ging
+or
+.Cm flush Ns ing ,
+be quiet about actions
+(implies
+.Fl f ) .
+This is useful for adjusting rules by executing multiple
+.Nm
+commands in a script
+or by processing a file of many
+.Nm
+rules across a remote login session.
+If a
+.Cm flush
+is performed in normal (verbose) mode (with the default kernel
+configuration), it prints a message.
+Because all rules are flushed, the message might not be delivered
+to the login session, causing the remote login session to be closed
+and the remainder of the ruleset to not be processed.
+Access to the console would then be required to recover.
+.It Fl s Op Ar field
+While listing pipes, sort according to one of the four
+counters (total or current packets or bytes).
+.It Fl v
+Be verbose.
+.El
+.Pp
+To ease configuration, rules can be put into a file which is
+processed using
+.Nm
+as shown in the last synopsis line.
+An absolute
+.Ar pathname
+must be used.
+The file will be read line by line and applied as arguments to the
+.Nm
+utility.
+.Pp
+Optionally, a preprocessor can be specified using
+.Fl p Ar preproc
+where
+.Ar pathname
+is to be piped through.
+Useful preprocessors include
+.Xr cpp 1
+and
+.Xr m4 1 .
+If
+.Ar preproc
+doesn't start with a slash
+.Pq Ql /
+as its first character, the usual
+.Ev PATH
+name search is performed.
+Care should be taken with this in environments where not all
+file systems are mounted (yet) by the time
+.Nm
+is being run (e.g. when they are mounted over NFS).
+Once
+.Fl p
+has been specified, any additional arguments as passed on to the preprocessor
+for interpretation.
+This allows for flexible configuration files (like conditionalizing
+them on the local hostname) and the use of macros to centralize
+frequently required arguments like IP addresses.
+.El
+.Sh CHECKLIST
+Here are some important points to consider when designing your
+rules:
+.Bl -bullet
+.It
+Remember that you filter both packets going
+.Cm in
+and
+.Cm out .
+Most connections need packets going in both directions.
+.It
+Remember to test very carefully.
+It is a good idea to be near the console when doing this.
+.It
+Don't forget the loopback interface.
+.El
+.Sh SYSCTL VARIABLES
+A set of
+.Xr sysctl 8
+variables controls the behaviour of the
+.Nm dummynet
+module.
+These are shown below together with their default value
+(but always check with the
+.Xr sysctl 8
+command what value is actually in use) and meaning:
+.Bl -tag -width indent
+.It Em net.inet.ip.dummynet.expire : No 1
+Lazily delete dynamic pipes/queue once they have no pending traffic.
+You can disable this by setting the variable to 0, in which case
+the pipes/queues will only be deleted when the threshold is reached.
+.It Em net.inet.ip.dummynet.hash_size : No 64
+Default size of the hash table used for dynamic pipes/queues.
+This value is used when no
+.Cm buckets
+option is specified when configuring a pipe/queue.
+.It Em net.inet.ip.dummynet.max_chain_len : No 16
+Target value for the maximum number of pipes/queues in a hash bucket.
+The product
+.Cm max_chain_len*hash_size
+is used to determine the threshold over which empty pipes/queues
+will be expired even when
+.Cm net.inet.ip.dummynet.expire=0 .
+.It Em net.inet.ip.dummynet.red_lookup_depth : No 256
+.It Em net.inet.ip.dummynet.red_avg_pkt_size : No 512
+.It Em net.inet.ip.dummynet.red_max_pkt_size : No 1500
+Parameters used in the computations of the drop probability
+for the RED algorithm.
+.El
+.Sh EXAMPLES
+The following rules show some of the applications of
+for simulations and the like by using
+.Em dummynet
+rules in
+.Xr pf.conf 8
+configuration files.
+.Pp
+To drop random incoming IPv4 and IPv6 ICMP packets with a probability of 5%,
+create a pipe:
+.Dl "dnctl pipe 10 config plr 0.05"
+.Pp
+and add these rules in your pf.conf file:
+.Dl "dummynet in inet proto icmp all pipe 10"
+.Dl "dummynet in inet6 proto ipv6-icmp all pipe 10"
+.Pp
+Should we want to simulate a bidirectional link with bandwidth
+limitations, the correct way is to create a pipe for each direction:
+.Dl "dnctl pipe 1 config bw 14Kbit/s queue 10Kbytes"
+.Dl "dnctl pipe 2 config bw 1Kbit/s queue 10Kbytes"
+.Pp
+and add these rules in your pf.conf file:
+.Dl "dummynet in all pipe 1"
+.Dl "dummynet out all pipe 2"
+.Pp
+The above can be very useful, e.g. if you want to see how
+your fancy Web page will look for a residential user who
+is connected only through a slow link.
+You should not use only one pipe for both directions, unless
+you want to simulate a half-duplex medium (e.g. AppleTalk,
+Ethernet, IRDA).
+.Pp
+Note that with the above rules the pipes receive traffic for both the
+IPv4 and IPv6 protocols.
+.Pp
+Should we want to verify network performance with the RED queue
+management algorithm, create this pipe:
+.Dl "dnctl pipe 1 config bw 500Kbit/s queue 100 red 0.002/30/80/0.1"
+.Pp
+and then add these rules to you pf.conf file:
+.Dl "dummynet all pipe 1"
+.Pp
+Another typical application of the traffic shaper is to
+introduce some delay in the communication.
+This can significantly affect applications which do a lot of Remote
+Procedure Calls, and where the round-trip-time of the
+connection often becomes a limiting factor much more than
+bandwidth:
+.Dl "dnctl pipe 1 config delay 250ms bw 1Mbit/s"
+.Dl "dnctl pipe 2 config delay 250ms bw 1Mbit/s"
+.Pp
+and add these rules in your pf.conf file:
+.Dl "dummynet in all pipe 1"
+.Dl "dummynet out all pipe 2"
+.Pp
+Per-flow queueing can be useful for a variety of purposes.
+A very simple one is counting traffic:
+.Dl "dnctl pipe 1 config mask all"
+.Pp
+and add these statements in your pf.conf file:
+.Dl "dummynet in quick proto tcp all pipe 1"
+.Dl "dummynet out quick proto tcp all pipe 1"
+.Dl "dummynet in quick proto udp all pipe 1"
+.Dl "dummynet out quick proto udp all pipe 1"
+.Dl "dummynet in quick all pipe 1"
+.Dl "dummynet out quick all pipe 1"
+.Pp
+The above set of rules will create queues (and collect
+statistics) for all traffic.
+Because the pipes have no limitations, the only effect is
+collecting statistics.
+Note that we need six rules, not just the last two one, because
+when
+.Nm
+tries to match IP packets it will not consider ports, so we
+would not see connections on separate ports as different
+ones.
+.Sh SEE ALSO
+.Xr cpp 1 ,
+.Xr dummynet 4 ,
+.Xr m4 1 ,
+.Xr ip 4 ,
+.Xr pfctl 8 ,
+.Xr pf.conf 5 ,
+.Xr protocols 5 ,
+.Xr services 5 ,
+.Xr sysctl 8
+.Sh AUTHORS
+.An Ugen J. S. Antsilevich ,
+.An Poul-Henning Kamp ,
+.An Alex Nash ,
+.An Archie Cobbs ,
+.An Luigi Rizzo .
+.Pp
+.An -nosplit
+API based upon code written by
+.An Daniel Boulet
+for BSDI.
+.Pp
+Work on
+.Xr dummynet 4
+traffic shaper supported by Akamba Corp.
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 2.0 .
+.Xr dummynet 4
+was introduced in
+.Fx 2.2.8 .
+Stateful extensions were introduced in
+.Fx 4.0 .
diff --git a/network_cmds/dnctl/dnctl.c b/network_cmds/dnctl/dnctl.c
new file mode 100644
index 0000000..38cffe8
--- /dev/null
+++ b/network_cmds/dnctl/dnctl.c
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 2002-2003 Luigi Rizzo
+ * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
+ * Copyright (c) 1994 Ugen J.S.Antsilevich
+ *
+ * Idea and grammar partially left from:
+ * Copyright (c) 1993 Daniel Boulet
+ *
+ * Redistribution and use in source forms, with and without modification,
+ * are permitted provided that this entire comment appears intact.
+ *
+ * Redistribution in binary form may occur without any restrictions.
+ * Obviously, it would be nice if you gave credit where credit is due
+ * but requiring it would be too onerous.
+ *
+ * This software is provided ``AS IS'' without any warranties of any kind.
+ */
+
+/*
+ * Ripped off ipfw2.c
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_dummynet.h>
+#include <arpa/inet.h>
+
+/*
+ * Limit delay to avoid computation overflow
+ */
+#define MAX_DELAY (INT_MAX / 1000)
+
+
+int
+do_quiet, /* Be quiet in add and flush */
+do_pipe, /* this cmd refers to a pipe */
+do_sort, /* field to sort results (0 = no) */
+test_only, /* only check syntax */
+verbose;
+
+#define IP_MASK_ALL 0xffffffff
+
+/*
+ * _s_x is a structure that stores a string <-> token pairs, used in
+ * various places in the parser. Entries are stored in arrays,
+ * with an entry with s=NULL as terminator.
+ * The search routines are match_token() and match_value().
+ * Often, an element with x=0 contains an error string.
+ *
+ */
+struct _s_x {
+ char const *s;
+ int x;
+};
+
+enum tokens {
+ TOK_NULL=0,
+
+ TOK_ACCEPT,
+ TOK_COUNT,
+ TOK_PIPE,
+ TOK_QUEUE,
+
+ TOK_PLR,
+ TOK_NOERROR,
+ TOK_BUCKETS,
+ TOK_DSTIP,
+ TOK_SRCIP,
+ TOK_DSTPORT,
+ TOK_SRCPORT,
+ TOK_ALL,
+ TOK_MASK,
+ TOK_BW,
+ TOK_DELAY,
+ TOK_RED,
+ TOK_GRED,
+ TOK_DROPTAIL,
+ TOK_PROTO,
+ TOK_WEIGHT,
+
+ TOK_DSTIP6,
+ TOK_SRCIP6,
+};
+
+struct _s_x dummynet_params[] = {
+ { "plr", TOK_PLR },
+ { "noerror", TOK_NOERROR },
+ { "buckets", TOK_BUCKETS },
+ { "dst-ip", TOK_DSTIP },
+ { "src-ip", TOK_SRCIP },
+ { "dst-port", TOK_DSTPORT },
+ { "src-port", TOK_SRCPORT },
+ { "proto", TOK_PROTO },
+ { "weight", TOK_WEIGHT },
+ { "all", TOK_ALL },
+ { "mask", TOK_MASK },
+ { "droptail", TOK_DROPTAIL },
+ { "red", TOK_RED },
+ { "gred", TOK_GRED },
+ { "bw", TOK_BW },
+ { "bandwidth", TOK_BW },
+ { "delay", TOK_DELAY },
+ { "pipe", TOK_PIPE },
+ { "queue", TOK_QUEUE },
+ { "dst-ipv6", TOK_DSTIP6},
+ { "dst-ip6", TOK_DSTIP6},
+ { "src-ipv6", TOK_SRCIP6},
+ { "src-ip6", TOK_SRCIP6},
+ { "dummynet-params", TOK_NULL },
+ { NULL, 0 } /* terminator */
+};
+
+static void show_usage(void);
+
+
+void n2mask(struct in6_addr *, int );
+unsigned long long align_uint64(const uint64_t *);
+
+/* n2mask sets n bits of the mask */
+void
+n2mask(struct in6_addr *mask, int n)
+{
+ static int minimask[9] =
+ { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+ u_char *p;
+
+ memset(mask, 0, sizeof(struct in6_addr));
+ p = (u_char *) mask;
+ for (; n > 0; p++, n -= 8) {
+ if (n >= 8)
+ *p = 0xff;
+ else
+ *p = minimask[n];
+ }
+ return;
+}
+
+/*
+ * The following is used to generate a printable argument for
+ * 64-bit numbers, irrespective of platform alignment and bit size.
+ * Because all the printf in this program use %llu as a format,
+ * we just return an unsigned long long, which is larger than
+ * we need in certain cases, but saves the hassle of using
+ * PRIu64 as a format specifier.
+ * We don't care about inlining, this is not performance critical code.
+ */
+unsigned long long
+align_uint64(const uint64_t *pll)
+{
+ uint64_t ret;
+
+ bcopy (pll, &ret, sizeof(ret));
+ return ret;
+}
+
+/*
+ * conditionally runs the command.
+ */
+static int
+do_cmd(int optname, void *optval, socklen_t *optlen)
+{
+ static int s = -1; /* the socket */
+ int i;
+
+ if (test_only)
+ return 0;
+
+ if (s == -1)
+ s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (s < 0)
+ err(EX_UNAVAILABLE, "socket");
+
+ if (optname == IP_DUMMYNET_GET)
+ i = getsockopt(s, IPPROTO_IP, optname, optval, optlen);
+ else
+ i = setsockopt(s, IPPROTO_IP, optname, optval, optlen ? *optlen : 0);
+ return i;
+}
+
+/**
+ * match_token takes a table and a string, returns the value associated
+ * with the string (-1 in case of failure).
+ */
+static int
+match_token(struct _s_x *table, char *string)
+{
+ struct _s_x *pt;
+ size_t i = strlen(string);
+
+ for (pt = table ; i && pt->s != NULL ; pt++)
+ if (strlen(pt->s) == i && !bcmp(string, pt->s, i))
+ return pt->x;
+ return -1;
+};
+
+static int
+sort_q(const void *pa, const void *pb)
+{
+ int rev = (do_sort < 0);
+ int field = rev ? -do_sort : do_sort;
+ long long res = 0;
+ const struct dn_flow_queue *a = pa;
+ const struct dn_flow_queue *b = pb;
+
+ switch (field) {
+ case 1: /* pkts */
+ res = a->len - b->len;
+ break;
+ case 2: /* bytes */
+ res = a->len_bytes - b->len_bytes;
+ break;
+
+ case 3: /* tot pkts */
+ res = a->tot_pkts - b->tot_pkts;
+ break;
+
+ case 4: /* tot bytes */
+ res = a->tot_bytes - b->tot_bytes;
+ break;
+ }
+ if (res < 0)
+ res = -1;
+ if (res > 0)
+ res = 1;
+ return (int)(rev ? res : -res);
+}
+
+static void
+list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
+{
+ int l;
+ int index_printed = 0, indexes = 0;
+ char buff[255];
+ struct protoent *pe;
+
+ printf(" mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+ fs->flow_mask.proto,
+ fs->flow_mask.src_ip, fs->flow_mask.src_port,
+ fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
+ if (fs->rq_elements == 0)
+ return;
+
+ printf("BKT Prot ___Source IP/port____ "
+ "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
+ if (do_sort != 0)
+ heapsort(q, fs->rq_elements, sizeof(struct dn_flow_queue), sort_q);
+
+ /* Print IPv4 flows */
+ for (l = 0; l < fs->rq_elements; l++) {
+ struct in_addr ina;
+
+ /* XXX: Should check for IPv4 flows */
+ if (IS_IP6_FLOW_ID(&(q[l].id)))
+ continue;
+
+ if (!index_printed) {
+ index_printed = 1;
+ if (indexes > 0) /* currently a no-op */
+ printf("\n");
+ indexes++;
+ printf(" "
+ "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
+ fs->flow_mask.proto,
+ fs->flow_mask.src_ip, fs->flow_mask.src_port,
+ fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
+
+ printf("BKT Prot ___Source IP/port____ "
+ "____Dest. IP/port____ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ }
+
+ printf("%3d ", q[l].hash_slot);
+ pe = getprotobynumber(q[l].id.proto);
+ if (pe)
+ printf("%-4s ", pe->p_name);
+ else
+ printf("%4u ", q[l].id.proto);
+ ina.s_addr = htonl(q[l].id.src_ip);
+ printf("%15s/%-5d ",
+ inet_ntoa(ina), q[l].id.src_port);
+ ina.s_addr = htonl(q[l].id.dst_ip);
+ printf("%15s/%-5d ",
+ inet_ntoa(ina), q[l].id.dst_port);
+ printf("%4llu %8llu %2u %4u %3u\n",
+ align_uint64(&q[l].tot_pkts),
+ align_uint64(&q[l].tot_bytes),
+ q[l].len, q[l].len_bytes, q[l].drops);
+ if (verbose)
+ printf(" S %20llu F %20llu\n",
+ align_uint64(&q[l].S), align_uint64(&q[l].F));
+ }
+
+ /* Print IPv6 flows */
+ index_printed = 0;
+ for (l = 0; l < fs->rq_elements; l++) {
+ if (!IS_IP6_FLOW_ID(&(q[l].id)))
+ continue;
+
+ if (!index_printed) {
+ index_printed = 1;
+ if (indexes > 0)
+ printf("\n");
+ indexes++;
+ printf("\n mask: proto: 0x%02x, flow_id: 0x%08x, ",
+ fs->flow_mask.proto, fs->flow_mask.flow_id6);
+ inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
+ buff, sizeof(buff));
+ printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
+ inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
+ buff, sizeof(buff) );
+ printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
+
+ printf("BKT ___Prot___ _flow-id_ "
+ "______________Source IPv6/port_______________ "
+ "_______________Dest. IPv6/port_______________ "
+ "Tot_pkt/bytes Pkt/Byte Drp\n");
+ }
+ printf("%3d ", q[l].hash_slot);
+ pe = getprotobynumber(q[l].id.proto);
+ if (pe != NULL)
+ printf("%9s ", pe->p_name);
+ else
+ printf("%9u ", q[l].id.proto);
+ printf("%7d %39s/%-5d ", q[l].id.flow_id6,
+ inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)),
+ q[l].id.src_port);
+ printf(" %39s/%-5d ",
+ inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)),
+ q[l].id.dst_port);
+ printf(" %4llu %8llu %2u %4u %3u\n",
+ align_uint64(&q[l].tot_pkts),
+ align_uint64(&q[l].tot_bytes),
+ q[l].len, q[l].len_bytes, q[l].drops);
+ if (verbose)
+ printf(" S %20llu F %20llu\n",
+ align_uint64(&q[l].S),
+ align_uint64(&q[l].F));
+ }
+}
+
+static void
+print_flowset_parms(struct dn_flow_set *fs, char *prefix)
+{
+ int l;
+ char qs[30];
+ char plr[30];
+ char red[90]; /* Display RED parameters */
+
+ l = fs->qsize;
+ if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
+ if (l >= 8192)
+ snprintf(qs, sizeof(qs), "%d KB", l / 1024);
+ else
+ snprintf(qs, sizeof(qs), "%d B", l);
+ } else
+ snprintf(qs, sizeof(qs), "%3d sl.", l);
+ if (fs->plr)
+ snprintf(plr, sizeof(plr), "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
+ else
+ plr[0] = '\0';
+ if (fs->flags_fs & DN_IS_RED) /* RED parameters */
+ snprintf(red, sizeof(red),
+ "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
+ (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
+ 1.0 * fs->w_q / (double)(1 << SCALE_RED),
+ SCALE_VAL(fs->min_th),
+ SCALE_VAL(fs->max_th),
+ 1.0 * fs->max_p / (double)(1 << SCALE_RED));
+ else
+ snprintf(red, sizeof(red), "droptail");
+
+ printf("%s %s%s %d queues (%d buckets) %s\n",
+ prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
+}
+
+static void
+list_pipes(void *data, size_t nbytes, int ac, char *av[])
+{
+ unsigned int rulenum;
+ void *next = data;
+ struct dn_pipe *p = (struct dn_pipe *) data;
+ struct dn_flow_set *fs;
+ struct dn_flow_queue *q;
+ size_t l;
+
+ if (ac > 0)
+ rulenum = (unsigned int)strtoul(*av++, NULL, 10);
+ else
+ rulenum = 0;
+ for (; nbytes >= sizeof(struct dn_pipe); p = (struct dn_pipe *)next) {
+ double b = p->bandwidth;
+ char buf[30];
+ char prefix[80];
+
+ if (p->next.sle_next != (struct dn_pipe *)DN_IS_PIPE)
+ break; /* done with pipes, now queues */
+
+ /*
+ * compute length, as pipe have variable size
+ */
+ l = sizeof(struct dn_pipe) + p->fs.rq_elements * sizeof(struct dn_flow_queue);
+ next = (char *)p + l;
+ nbytes -= l;
+
+ if (rulenum != 0 && rulenum != p->pipe_nr)
+ continue;
+
+ /*
+ * Print rate (or clocking interface)
+ */
+ if (p->if_name[0] != '\0')
+ snprintf(buf, sizeof(buf), "%s", p->if_name);
+ else if (b == 0)
+ snprintf(buf, sizeof(buf), "unlimited");
+ else if (b >= 1000000)
+ snprintf(buf, sizeof(buf), "%7.3f Mbit/s", b/1000000);
+ else if (b >= 1000)
+ snprintf(buf, sizeof(buf), "%7.3f Kbit/s", b/1000);
+ else
+ snprintf(buf, sizeof(buf), "%7.3f bit/s ", b);
+
+ snprintf(prefix, sizeof(prefix), "%05d: %s %4d ms ",
+ p->pipe_nr, buf, p->delay);
+ print_flowset_parms(&(p->fs), prefix);
+ if (verbose)
+ printf(" V %20qd\n", p->V >> MY_M);
+
+ q = (struct dn_flow_queue *)(p+1);
+ list_queues(&(p->fs), q);
+ }
+ for (fs = next; nbytes >= sizeof *fs; fs = next) {
+ char prefix[80];
+
+ if (fs->next.sle_next != (struct dn_flow_set *)DN_IS_QUEUE)
+ break;
+ l = sizeof(struct dn_flow_set) + fs->rq_elements * sizeof(struct dn_flow_queue);
+ next = (char *)fs + l;
+ nbytes -= l;
+ q = (struct dn_flow_queue *)(fs+1);
+ snprintf(prefix, sizeof(prefix), "q%05d: weight %d pipe %d ",
+ fs->fs_nr, fs->weight, fs->parent_nr);
+ print_flowset_parms(fs, prefix);
+ list_queues(fs, q);
+ }
+}
+
+static void
+list(int ac, char *av[], int show_counters)
+{
+ void *data = NULL;
+ socklen_t nbytes;
+ int exitval = EX_OK;
+
+ int nalloc = 1024; /* start somewhere... */
+
+ if (test_only) {
+ fprintf(stderr, "Testing only, list disabled\n");
+ return;
+ }
+
+ ac--;
+ av++;
+
+ /* get rules or pipes from kernel, resizing array as necessary */
+ nbytes = nalloc;
+
+ while (nbytes >= nalloc) {
+ nalloc = nalloc * 2 + 200;
+ nbytes = nalloc;
+ if ((data = realloc(data, nbytes)) == NULL)
+ err(EX_OSERR, "realloc");
+
+ if (do_cmd(IP_DUMMYNET_GET, data, &nbytes) < 0) {
+ if (errno == ENOBUFS) {
+ nbytes = 0;
+ break;
+ }
+ err(EX_OSERR, "getsockopt(IP_DUMMYNET_GET)");
+
+ }
+ }
+
+ list_pipes(data, nbytes, ac, av);
+
+ free(data);
+
+ if (exitval != EX_OK)
+ exit(exitval);
+}
+
+static void
+show_usage(void)
+{
+ fprintf(stderr, "usage: dnctl [options]\n"
+ "do \"dnctl -h\" or see dnctl manpage for details\n"
+ );
+ exit(EX_USAGE);
+}
+
+static void
+help(void)
+{
+ fprintf(stderr,
+ "dnclt [-acdeftTnNpqS] <command> where <command> is one of:\n"
+ "{pipe|queue} N config PIPE-BODY\n"
+ "[pipe|queue] {zero|delete|show} [N{,N}]\n"
+ );
+ exit(0);
+}
+
+static void
+delete(int ac, char *av[])
+{
+ struct dn_pipe p;
+ int i;
+ int exitval = EX_OK;
+ socklen_t len;
+
+ memset(&p, 0, sizeof(struct dn_pipe));
+
+ av++; ac--;
+
+ while (ac && isdigit(**av)) {
+ i = atoi(*av); av++; ac--;
+
+ if (do_pipe == 1)
+ p.pipe_nr = i;
+ else
+ p.fs.fs_nr = i;
+ len = sizeof(struct dn_pipe);
+ i = do_cmd(IP_DUMMYNET_DEL, &p, &len);
+ if (i) {
+ exitval = 1;
+ warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
+ do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr);
+ }
+ }
+ if (exitval != EX_OK)
+ exit(exitval);
+}
+
+/*
+ * the following macro returns an error message if we run out of
+ * arguments.
+ */
+#define NEED1(msg) {if (!ac) errx(EX_USAGE, msg);}
+#define NEED2(msg, arg) {if (!ac) errx(EX_USAGE, msg, arg);}
+
+static void
+config_pipe(int ac, char **av)
+{
+ struct dn_pipe p;
+ int i;
+ char *end;
+ void *par = NULL;
+ socklen_t len;
+
+ memset(&p, 0, sizeof(struct dn_pipe));
+
+ av++; ac--;
+ /* Pipe number */
+ if (ac && isdigit(**av)) {
+ i = atoi(*av); av++; ac--;
+ if (do_pipe == 1)
+ p.pipe_nr = i;
+ else
+ p.fs.fs_nr = i;
+ }
+ while (ac > 0) {
+ double d;
+ int tok = match_token(dummynet_params, *av);
+ ac--; av++;
+
+ switch(tok) {
+ case TOK_NOERROR:
+ p.fs.flags_fs |= DN_NOERROR;
+ break;
+
+ case TOK_PLR:
+ NEED1("plr needs argument 0..1\n");
+ d = strtod(av[0], NULL);
+ if (d > 1)
+ d = 1;
+ else if (d < 0)
+ d = 0;
+ p.fs.plr = (int)(d*0x7fffffff);
+ ac--; av++;
+ break;
+
+ case TOK_QUEUE:
+ NEED1("queue needs queue size\n");
+ end = NULL;
+ p.fs.qsize = (int)strtoul(av[0], &end, 0);
+ if (*end == 'K' || *end == 'k') {
+ p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
+ p.fs.qsize *= 1024;
+ } else if (*end == 'B' || !strncmp(end, "by", 2)) {
+ p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
+ }
+ ac--; av++;
+ break;
+
+ case TOK_BUCKETS:
+ NEED1("buckets needs argument\n");
+ p.fs.rq_size = (int)strtoul(av[0], NULL, 0);
+ ac--; av++;
+ break;
+
+ case TOK_MASK:
+ NEED1("mask needs mask specifier\n");
+ /*
+ * per-flow queue, mask is dst_ip, dst_port,
+ * src_ip, src_port, proto measured in bits
+ */
+ par = NULL;
+
+ p.fs.flow_mask.dst_ip = 0;
+ p.fs.flow_mask.src_ip = 0;
+ p.fs.flow_mask.dst_port = 0;
+ p.fs.flow_mask.src_port = 0;
+ p.fs.flow_mask.proto = 0;
+ end = NULL;
+
+ while (ac >= 1) {
+ uint32_t *p32 = NULL;
+ uint16_t *p16 = NULL;
+ struct in6_addr *pa6 = NULL;
+ uint32_t a;
+
+ tok = match_token(dummynet_params, *av);
+ ac--; av++;
+ switch(tok) {
+ case TOK_ALL:
+ /*
+ * special case, all bits significant
+ */
+ p.fs.flow_mask.dst_ip = ~0;
+ p.fs.flow_mask.src_ip = ~0;
+ p.fs.flow_mask.dst_port = ~0;
+ p.fs.flow_mask.src_port = ~0;
+ p.fs.flow_mask.proto = ~0;
+ n2mask(&(p.fs.flow_mask.dst_ip6), 128);
+ n2mask(&(p.fs.flow_mask.src_ip6), 128);
+ p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
+ goto end_mask;
+
+ case TOK_DSTIP:
+ p32 = &p.fs.flow_mask.dst_ip;
+ break;
+
+ case TOK_SRCIP:
+ p32 = &p.fs.flow_mask.src_ip;
+ break;
+
+ case TOK_DSTIP6:
+ pa6 = &(p.fs.flow_mask.dst_ip6);
+ break;
+
+ case TOK_SRCIP6:
+ pa6 = &(p.fs.flow_mask.src_ip6);
+ break;
+
+ case TOK_DSTPORT:
+ p16 = &p.fs.flow_mask.dst_port;
+ break;
+
+ case TOK_SRCPORT:
+ p16 = &p.fs.flow_mask.src_port;
+ break;
+
+ case TOK_PROTO:
+ break;
+
+ default:
+ ac++; av--; /* backtrack */
+ goto end_mask;
+ }
+ if (ac < 1)
+ errx(EX_USAGE, "mask: value missing");
+ if (*av[0] == '/') {
+ a = (int)strtoul(av[0]+1, &end, 0);
+ if (pa6 == NULL)
+ a = (a == 32) ? ~0 : (1 << a) - 1;
+ } else
+ a = (int)strtoul(av[0], &end, 0);
+ if (p32 != NULL)
+ *p32 = a;
+ else if (p16 != NULL) {
+ if (a > 65535)
+ errx(EX_DATAERR,
+ "mask: must be 16 bit");
+ *p16 = (uint16_t)a;
+ } else if (pa6 != NULL) {
+ if (a > 128)
+ errx(EX_DATAERR,
+ "in6addr invalid mask len");
+ else
+ n2mask(pa6, a);
+ } else {
+ if (a > 255)
+ errx(EX_DATAERR,
+ "mask: must be 8 bit");
+ p.fs.flow_mask.proto = (uint8_t)a;
+ }
+ if (a != 0)
+ p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
+ ac--; av++;
+ } /* end while, config masks */
+end_mask:
+ break;
+
+ case TOK_RED:
+ case TOK_GRED:
+ NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
+ p.fs.flags_fs |= DN_IS_RED;
+ if (tok == TOK_GRED)
+ p.fs.flags_fs |= DN_IS_GENTLE_RED;
+ /*
+ * the format for parameters is w_q/min_th/max_th/max_p
+ */
+ if ((end = strsep(&av[0], "/"))) {
+ double w_q = strtod(end, NULL);
+ if (w_q > 1 || w_q <= 0)
+ errx(EX_DATAERR, "0 < w_q <= 1");
+ p.fs.w_q = (int) (w_q * (1 << SCALE_RED));
+ }
+ if ((end = strsep(&av[0], "/"))) {
+ p.fs.min_th = (int)strtoul(end, &end, 0);
+ if (*end == 'K' || *end == 'k')
+ p.fs.min_th *= 1024;
+ }
+ if ((end = strsep(&av[0], "/"))) {
+ p.fs.max_th = (int)strtoul(end, &end, 0);
+ if (*end == 'K' || *end == 'k')
+ p.fs.max_th *= 1024;
+ }
+ if ((end = strsep(&av[0], "/"))) {
+ double max_p = strtod(end, NULL);
+ if (max_p > 1 || max_p <= 0)
+ errx(EX_DATAERR, "0 < max_p <= 1");
+ p.fs.max_p = (int)(max_p * (1 << SCALE_RED));
+ }
+ ac--; av++;
+ break;
+
+ case TOK_DROPTAIL:
+ p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
+ break;
+
+ case TOK_BW:
+ NEED1("bw needs bandwidth or interface\n");
+ if (do_pipe != 1)
+ errx(EX_DATAERR, "bandwidth only valid for pipes");
+ /*
+ * set clocking interface or bandwidth value
+ */
+ if (av[0][0] >= 'a' && av[0][0] <= 'z') {
+ /* interface name */
+ strlcpy(p.if_name, av[0], sizeof(p.if_name));
+ p.bandwidth = 0;
+ } else {
+ p.if_name[0] = '\0';
+ p.bandwidth = (int)strtoul(av[0], &end, 0);
+ if (*end == 'K' || *end == 'k') {
+ end++;
+ p.bandwidth *= 1000;
+ } else if (*end == 'M') {
+ end++;
+ p.bandwidth *= 1000000;
+ }
+ if (*end == 'B' || !strncmp(end, "by", 2))
+ p.bandwidth *= 8;
+ if (p.bandwidth < 0)
+ errx(EX_DATAERR, "bandwidth too large");
+ }
+ ac--; av++;
+ break;
+
+ case TOK_DELAY:
+ if (do_pipe != 1)
+ errx(EX_DATAERR, "delay only valid for pipes");
+ NEED2("delay needs argument 0..%d\n", MAX_DELAY);
+ p.delay = (int)strtoul(av[0], NULL, 0);
+ ac--; av++;
+ break;
+
+ case TOK_WEIGHT:
+ if (do_pipe == 1)
+ errx(EX_DATAERR,"weight only valid for queues");
+ NEED1("weight needs argument 0..100\n");
+ p.fs.weight = (int)strtoul(av[0], &end, 0);
+ ac--; av++;
+ break;
+
+ case TOK_PIPE:
+ if (do_pipe == 1)
+ errx(EX_DATAERR,"pipe only valid for queues");
+ NEED1("pipe needs pipe_number\n");
+ p.fs.parent_nr = strtoul(av[0], &end, 0);
+ ac--; av++;
+ break;
+
+ default:
+ errx(EX_DATAERR, "unrecognised option ``%s''", *(--av));
+ }
+ }
+ if (do_pipe == 1) {
+ if (p.pipe_nr == 0)
+ errx(EX_DATAERR, "pipe_nr must be > 0");
+ if (p.delay > MAX_DELAY)
+ errx(EX_DATAERR, "delay must be < %d ms", MAX_DELAY);
+ } else { /* do_pipe == 2, queue */
+ if (p.fs.parent_nr == 0)
+ errx(EX_DATAERR, "pipe must be > 0");
+ if (p.fs.weight >100)
+ errx(EX_DATAERR, "weight must be <= 100");
+ }
+ if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) {
+ if (p.fs.qsize > 1024*1024)
+ errx(EX_DATAERR, "queue size must be < 1MB");
+ } else {
+ if (p.fs.qsize > 100)
+ errx(EX_DATAERR, "2 <= queue size <= 100");
+ }
+ if (p.fs.flags_fs & DN_IS_RED) {
+ size_t len;
+ int lookup_depth, avg_pkt_size;
+ double s, idle, weight, w_q;
+ struct clockinfo ck;
+ int t;
+
+ if (p.fs.min_th >= p.fs.max_th)
+ errx(EX_DATAERR, "min_th %d must be < than max_th %d",
+ p.fs.min_th, p.fs.max_th);
+ if (p.fs.max_th == 0)
+ errx(EX_DATAERR, "max_th must be > 0");
+
+ len = sizeof(int);
+ if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
+ &lookup_depth, &len, NULL, 0) == -1)
+
+ errx(1, "sysctlbyname(\"%s\")",
+ "net.inet.ip.dummynet.red_lookup_depth");
+ if (lookup_depth == 0)
+ errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
+ " must be greater than zero");
+
+ len = sizeof(int);
+ if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
+ &avg_pkt_size, &len, NULL, 0) == -1)
+
+ errx(1, "sysctlbyname(\"%s\")",
+ "net.inet.ip.dummynet.red_avg_pkt_size");
+ if (avg_pkt_size == 0)
+ errx(EX_DATAERR,
+ "net.inet.ip.dummynet.red_avg_pkt_size must"
+ " be greater than zero");
+
+ len = sizeof(struct clockinfo);
+ if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1)
+ errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
+
+ /*
+ * Ticks needed for sending a medium-sized packet.
+ * Unfortunately, when we are configuring a WF2Q+ queue, we
+ * do not have bandwidth information, because that is stored
+ * in the parent pipe, and also we have multiple queues
+ * competing for it. So we set s=0, which is not very
+ * correct. But on the other hand, why do we want RED with
+ * WF2Q+ ?
+ */
+ if (p.bandwidth==0) /* this is a WF2Q+ queue */
+ s = 0;
+ else
+ s = ck.hz * avg_pkt_size * 8 / p.bandwidth;
+
+ /*
+ * max idle time (in ticks) before avg queue size becomes 0.
+ * NOTA: (3/w_q) is approx the value x so that
+ * (1-w_q)^x < 10^-3.
+ */
+ w_q = ((double)p.fs.w_q) / (1 << SCALE_RED);
+ idle = s * 3. / w_q;
+ p.fs.lookup_step = (int)idle / lookup_depth;
+ if (!p.fs.lookup_step)
+ p.fs.lookup_step = 1;
+ weight = 1 - w_q;
+ for (t = p.fs.lookup_step; t > 0; --t)
+ weight *= weight;
+ p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
+ }
+ len = sizeof(struct dn_pipe);
+ i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, &len);
+ if (i)
+ err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
+}
+
+static void
+flush(int force)
+{
+ if (!force && !do_quiet) { /* need to ask user */
+ int c;
+
+ printf("Are you sure? [yn] ");
+ fflush(stdout);
+ do {
+ c = toupper(getc(stdin));
+ while (c != '\n' && getc(stdin) != '\n')
+ if (feof(stdin))
+ return; /* and do not flush */
+ } while (c != 'Y' && c != 'N');
+ printf("\n");
+ if (c == 'N') /* user said no */
+ return;
+ }
+
+ if (do_cmd(IP_DUMMYNET_FLUSH, NULL, 0) < 0)
+ err(EX_UNAVAILABLE, "setsockopt(IP_DUMMYNET_FLUSH)");
+
+ if (!do_quiet)
+ printf("Flushed all pipes.\n");
+}
+
+/*
+ * Free a the (locally allocated) copy of command line arguments.
+ */
+static void
+free_args(int ac, char **av)
+{
+ int i;
+
+ for (i=0; i < ac; i++)
+ free(av[i]);
+ free(av);
+}
+
+/*
+ * Called with the arguments (excluding program name).
+ * Returns 0 if successful, 1 if empty command, errx() in case of errors.
+ */
+static int
+parse_args(int oldac, char **oldav)
+{
+ int ch, ac, save_ac;
+ char **av, **save_av;
+ int do_acct = 0; /* Show packet/byte count */
+ int do_force = 0; /* Don't ask for confirmation */
+
+#define WHITESP " \t\f\v\n\r"
+ if (oldac == 0)
+ return 1;
+ else if (oldac == 1) {
+ /*
+ * If we are called with a single string, try to split it into
+ * arguments for subsequent parsing.
+ * But first, remove spaces after a ',', by copying the string
+ * in-place.
+ */
+ char *arg = oldav[0]; /* The string... */
+ size_t l = strlen(arg);
+ int copy = 0; /* 1 if we need to copy, 0 otherwise */
+ int i, j;
+ for (i = j = 0; i < l; i++) {
+ if (arg[i] == '#') /* comment marker */
+ break;
+ if (copy) {
+ arg[j++] = arg[i];
+ copy = !index("," WHITESP, arg[i]);
+ } else {
+ copy = !index(WHITESP, arg[i]);
+ if (copy)
+ arg[j++] = arg[i];
+ }
+ }
+ if (!copy && j > 0) /* last char was a 'blank', remove it */
+ j--;
+ l = j; /* the new argument length */
+ arg[j++] = '\0';
+ if (l == 0) /* empty string! */
+ return 1;
+
+ /*
+ * First, count number of arguments. Because of the previous
+ * processing, this is just the number of blanks plus 1.
+ */
+ for (i = 0, ac = 1; i < l; i++)
+ if (index(WHITESP, arg[i]) != NULL)
+ ac++;
+
+ av = calloc(ac, sizeof(char *));
+
+ /*
+ * Second, copy arguments from cmd[] to av[]. For each one,
+ * j is the initial character, i is the one past the end.
+ */
+ for (ac = 0, i = j = 0; i < l; i++)
+ if (index(WHITESP, arg[i]) != NULL || i == l-1) {
+ if (i == l-1)
+ i++;
+ av[ac] = calloc(i-j+1, 1);
+ bcopy(arg+j, av[ac], i-j);
+ ac++;
+ j = i + 1;
+ }
+ } else {
+ /*
+ * If an argument ends with ',' join with the next one.
+ * Just add its length to 'l' and continue. When we have a string
+ * without a ',' ending, we'll have the combined length in 'l'
+ */
+ int first, i;
+ size_t l;
+
+ av = calloc(oldac, sizeof(char *));
+ for (first = i = ac = 0, l = 0; i < oldac; i++) {
+ char *arg = oldav[i];
+ size_t k = strlen(arg);
+
+ l += k;
+ if (arg[k-1] != ',' || i == oldac-1) {
+ size_t buflen = l+1;
+ /* Time to copy. */
+ av[ac] = calloc(l+1, 1);
+ for (l=0; first <= i; first++) {
+ strlcat(av[ac]+l, oldav[first], buflen-l);
+ l += strlen(oldav[first]);
+ }
+ ac++;
+ l = 0;
+ first = i+1;
+ }
+ }
+ }
+
+ /* Set the force flag for non-interactive processes */
+ do_force = !isatty(STDIN_FILENO);
+
+ /* Save arguments for final freeing of memory. */
+ save_ac = ac;
+ save_av = av;
+
+ optind = optreset = 0;
+ while ((ch = getopt(ac, av, "afhnqsv")) != -1)
+ switch (ch) {
+ case 'a':
+ do_acct = 1;
+ break;
+
+ case 'f':
+ do_force = 1;
+ break;
+
+ case 'h': /* help */
+ free_args(save_ac, save_av);
+ help();
+ break; /* NOTREACHED */
+
+ case 'n':
+ test_only = 1;
+ break;
+
+ case 'q':
+ do_quiet = 1;
+ break;
+
+ case 's': /* sort */
+ do_sort = atoi(optarg);
+ break;
+
+ case 'v': /* verbose */
+ verbose = 1;
+ break;
+
+ default:
+ free_args(save_ac, save_av);
+ return 1;
+ }
+
+ ac -= optind;
+ av += optind;
+ NEED1("bad arguments, for usage summary ``dnctl''");
+
+ /*
+ * An undocumented behaviour of dnctl1 was to allow rule numbers first,
+ * e.g. "100 add allow ..." instead of "add 100 allow ...".
+ * In case, swap first and second argument to get the normal form.
+ */
+ if (ac > 1 && isdigit(*av[0])) {
+ char *p = av[0];
+
+ av[0] = av[1];
+ av[1] = p;
+ }
+
+ /*
+ * optional: pipe or queue
+ */
+ do_pipe = 0;
+ if (!strncmp(*av, "pipe", strlen(*av)))
+ do_pipe = 1;
+ else if (!strncmp(*av, "queue", strlen(*av)))
+ do_pipe = 2;
+ if (do_pipe) {
+ ac--;
+ av++;
+ }
+ NEED1("missing command");
+
+ /*
+ * For pipes and queues we normally say 'pipe NN config'
+ * but the code is easier to parse as 'pipe config NN'
+ * so we swap the two arguments.
+ */
+ if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) {
+ char *p = av[0];
+
+ av[0] = av[1];
+ av[1] = p;
+ }
+
+ if (do_pipe && !strncmp(*av, "config", strlen(*av)))
+ config_pipe(ac, av);
+ else if (!strncmp(*av, "delete", strlen(*av)))
+ delete(ac, av);
+ else if (!strncmp(*av, "flush", strlen(*av)))
+ flush(do_force);
+ else if (!strncmp(*av, "print", strlen(*av)) ||
+ !strncmp(*av, "list", strlen(*av)))
+ list(ac, av, do_acct);
+ else if (!strncmp(*av, "show", strlen(*av)))
+ list(ac, av, 1 /* show counters */);
+ else
+ errx(EX_USAGE, "bad command `%s'", *av);
+
+ /* Free memory allocated in the argument parsing. */
+ free_args(save_ac, save_av);
+ return 0;
+}
+
+static void
+dnctl_readfile(int ac, char *av[])
+{
+#define MAX_ARGS 32
+ char buf[BUFSIZ];
+ char *cmd = NULL, *filename = av[ac-1];
+ int c, lineno=0;
+ FILE *f = NULL;
+ pid_t preproc = 0;
+
+ while ((c = getopt(ac, av, "np:q")) != -1) {
+ switch(c) {
+ case 'n':
+ test_only = 1;
+ break;
+
+ case 'p':
+ cmd = optarg;
+ /*
+ * Skip previous args and delete last one, so we
+ * pass all but the last argument to the preprocessor
+ * via av[optind-1]
+ */
+ av += optind - 1;
+ ac -= optind - 1;
+ av[ac-1] = NULL;
+ fprintf(stderr, "command is %s\n", av[0]);
+ break;
+
+ case 'q':
+ do_quiet = 1;
+ break;
+
+ default:
+ errx(EX_USAGE, "bad arguments, for usage"
+ " summary ``dnctl''");
+ }
+
+ if (cmd != NULL)
+ break;
+ }
+
+ if (cmd == NULL && ac != optind + 1) {
+ fprintf(stderr, "ac %d, optind %d\n", ac, optind);
+ errx(EX_USAGE, "extraneous filename arguments");
+ }
+
+ if ((f = fopen(filename, "r")) == NULL)
+ err(EX_UNAVAILABLE, "fopen: %s", filename);
+
+ if (cmd != NULL) { /* pipe through preprocessor */
+ int pipedes[2];
+
+ if (pipe(pipedes) == -1)
+ err(EX_OSERR, "cannot create pipe");
+
+ preproc = fork();
+ if (preproc == -1)
+ err(EX_OSERR, "cannot fork");
+
+ if (preproc == 0) {
+ /*
+ * Child, will run the preprocessor with the
+ * file on stdin and the pipe on stdout.
+ */
+ if (dup2(fileno(f), 0) == -1
+ || dup2(pipedes[1], 1) == -1)
+ err(EX_OSERR, "dup2()");
+ fclose(f);
+ close(pipedes[1]);
+ close(pipedes[0]);
+ execvp(cmd, av);
+ err(EX_OSERR, "execvp(%s) failed", cmd);
+ } else { /* parent, will reopen f as the pipe */
+ fclose(f);
+ close(pipedes[1]);
+ if ((f = fdopen(pipedes[0], "r")) == NULL) {
+ int savederrno = errno;
+
+ (void)kill(preproc, SIGTERM);
+ errno = savederrno;
+ err(EX_OSERR, "fdopen()");
+ }
+ }
+ }
+
+ while (fgets(buf, BUFSIZ, f)) { /* read commands */
+ char linename[16];
+ char *args[1];
+
+ lineno++;
+ snprintf(linename, sizeof(linename), "Line %d", lineno);
+ setprogname(linename); /* XXX */
+ args[0] = buf;
+ parse_args(1, args);
+ }
+ fclose(f);
+ if (cmd != NULL) {
+ int status;
+
+ if (waitpid(preproc, &status, 0) == -1)
+ errx(EX_OSERR, "waitpid()");
+ if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
+ errx(EX_UNAVAILABLE,
+ "preprocessor exited with status %d",
+ WEXITSTATUS(status));
+ else if (WIFSIGNALED(status))
+ errx(EX_UNAVAILABLE,
+ "preprocessor exited with signal %d",
+ WTERMSIG(status));
+ }
+}
+
+int
+main(int ac, char *av[])
+{
+ /*
+ * If the last argument is an absolute pathname, interpret it
+ * as a file to be preprocessed.
+ */
+
+ if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
+ dnctl_readfile(ac, av);
+ else {
+ if (parse_args(ac-1, av+1))
+ show_usage();
+ }
+ return EX_OK;
+}
diff --git a/network_cmds/ecnprobe/base.h b/network_cmds/ecnprobe/base.h
new file mode 100644
index 0000000..562b4ef
--- /dev/null
+++ b/network_cmds/ecnprobe/base.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <ctype.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <assert.h>
diff --git a/network_cmds/ecnprobe/capture.c b/network_cmds/ecnprobe/capture.c
new file mode 100644
index 0000000..32a8e0b
--- /dev/null
+++ b/network_cmds/ecnprobe/capture.c
@@ -0,0 +1,204 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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/time.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "gmt2local.h"
+#include "pcap.h"
+#include "inet.h"
+#include "capture.h"
+
+/* set snaplen to max etherenet packet size */
+#define DEFAULT_SNAPLEN 1500
+
+pcap_t *pc; /* pcap device */
+int datalinkOffset; /* offset of ip packet from datalink packet */
+int captureDebug = 1;
+unsigned int thisTimeZone;
+
+void CaptureInit(u_int32_t sourceIP, u_int16_t sourcePort,
+ u_int32_t targetIP, u_int16_t targetPort, char *dev)
+{
+
+ char *device = NULL;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ int snaplen = DEFAULT_SNAPLEN;
+ int promisc = 1;
+ int timeout = 10; /* timeout in 1 second (10 ms) */
+ char filtercmds[255];
+ bpf_u_int32 netmask = 0;
+ struct bpf_program filter;
+ char source[18];
+ char target[18];
+ int i;
+
+ /* Get local time zone for interpreting timestamps */
+ /* XXX - does this belong here? */
+ thisTimeZone = gmt2local(0);
+
+ if (dev != NULL) {
+ device = dev;
+ } else {
+ pcap_if_t *devlist;
+ /*
+ * Find the list of interfaces, and pick
+ * the first interface.
+ */
+ if (pcap_findalldevs(&devlist, errbuf) >= 0 &&
+ devlist != NULL) {
+ device = strdup(devlist->name);
+ pcap_freealldevs(devlist);
+ }
+
+ if (device == NULL) {
+ fprintf(stderr, "Can't find capture device: %s\n", errbuf);
+ exit(-1);
+ }
+ }
+
+ if (captureDebug) {
+ printf("Device name is %s\n", device);
+ }
+ pc = pcap_open_live(device, snaplen, promisc, timeout, errbuf);
+ if (pc == NULL) {
+ fprintf(stderr,"Can't open capture device %s: %s\n",device, errbuf);
+ exit(-1);
+ }
+
+ /* XXX why do we need to do this? */
+ i = pcap_snapshot(pc);
+ if (snaplen < i) {
+ fprintf(stderr, "Warning: snaplen raised to %d from %d",
+ snaplen, i);
+ }
+
+ if ((i = pcap_datalink(pc)) < 0) {
+ fprintf(stderr,"Unable to determine datalink type for %s: %s\n",
+ device, errbuf);
+ exit(-1);
+ }
+
+ switch(i) {
+
+ case DLT_EN10MB: datalinkOffset = 14; break;
+ case DLT_IEEE802: datalinkOffset = 22; break;
+ case DLT_NULL: datalinkOffset = 4; break;
+ case DLT_SLIP:
+ case DLT_PPP: datalinkOffset = 24; break;
+ case DLT_RAW: datalinkOffset = 0; break;
+ default:
+ fprintf(stderr,"Unknown datalink type %d\n",i);
+ exit(-1);
+ break;
+
+ }
+
+ if (InetAddress(sourceIP) < 0) {
+ fprintf(stderr, "Invalid source IP address (%d)\n", sourceIP);
+ exit(-1);
+ }
+
+ strlcpy(source, InetAddress(sourceIP), sizeof(source));
+ strlcpy(target, InetAddress(targetIP), sizeof(target));
+
+ /* Setup initial filter */
+ sprintf(filtercmds,
+ "(host %s && host %s && port %d) || icmp\n",
+ source, target, targetPort);
+
+ if (captureDebug) {
+ printf("datalinkOffset = %d\n", datalinkOffset);
+ printf("filter = %s\n", filtercmds);
+ }
+ if (pcap_compile(pc, &filter, filtercmds, 1, netmask) < 0) {
+ printf("Error: %s", pcap_geterr(pc));
+ exit(-1);
+ }
+
+ if (pcap_setfilter(pc, &filter) < 0) {
+ fprintf(stderr, "Can't set filter: %s",pcap_geterr(pc));
+ exit(-1);
+ }
+
+ if (captureDebug) {
+ printf("Listening on %s...\n", device);
+ }
+
+}
+
+char *CaptureGetPacket(struct pcap_pkthdr *pi)
+{
+
+ const u_char *p;
+
+ p = pcap_next(pc, (struct pcap_pkthdr *)pi);
+
+ if (p != NULL) {
+ p += datalinkOffset;
+ }
+
+ pi->ts.tv_sec = (pi->ts.tv_sec + thisTimeZone) % 86400;
+
+ return (char *)p;
+
+}
+
+
+void CaptureEnd()
+{
+ struct pcap_stat stat;
+
+ if (pcap_stats(pc, &stat) < 0) {
+ (void)fprintf(stderr, "pcap_stats: %s\n", pcap_geterr(pc));
+ }
+ else {
+ (void)fprintf(stderr, "%d packets received by filter\n", stat.ps_recv);
+ (void)fprintf(stderr, "%d packets dropped by kernel\n", stat.ps_drop);
+ }
+
+ pcap_close(pc);
+}
+
diff --git a/network_cmds/ecnprobe/capture.h b/network_cmds/ecnprobe/capture.h
new file mode 100644
index 0000000..9bb83be
--- /dev/null
+++ b/network_cmds/ecnprobe/capture.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 _CAPTURE_H_
+#define _CAPTURE_H_
+#include <pcap/pcap.h>
+
+struct PacketInfo {
+ struct timeval ts;
+ unsigned int caplen;
+ unsigned int len;
+};
+
+void CaptureInit(u_int32_t sourceIP, u_int16_t sourcePort,
+ u_int32_t targetIP, u_int16_t targetPort, char *dev);
+char *CaptureGetPacket(struct pcap_pkthdr *);
+void CaptureEnd();
+
+#endif /* _CAPTURE_H_ */
diff --git a/network_cmds/ecnprobe/ecn.c b/network_cmds/ecnprobe/ecn.c
new file mode 100644
index 0000000..b7dabdf
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn.c
@@ -0,0 +1,1119 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "history.h"
+#include "ecn.h"
+
+extern struct TcpSession session;
+extern struct History history[];
+
+#define ESTABLISH_SUCCESS 0
+#define ESTABLISH_FAILURE_EARLY_RST 1
+#define ESTABLISH_FAILURE_NO_REPLY 2
+int EstablishTcpConnection(u_int8_t syn_flags, u_int8_t ip_tos)
+{
+ struct IPPacket *synPacket = NULL, *ackPacket = NULL;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ int tcpoptlen = 4; /* For negotiating MSS */
+ u_int8_t *opt = NULL;
+ struct IPPacket *p = NULL;
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ synPacket = AllocateIPPacket(0, tcpoptlen, 0, "ECN (SYN)");
+ opt = (((u_int8_t *)synPacket->tcp) + sizeof(struct TcpHeader));
+ opt[0] = (u_int8_t)TCPOPT_MAXSEG;
+ opt[1] = (u_int8_t)TCPOLEN_MAXSEG;
+ *((u_int16_t *)((u_int8_t *)opt + 2)) = htons(session.mss);
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
+ timeoutTime = GetTime() + 1;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < 3) {
+ while(GetTime() < timeoutTime) {
+ /* Have we captured any packets? */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport,
+ session.dst, session.dport)) {
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totSeenSent++ ;
+ } else {
+ processBadPacket(p);
+ }
+ continue;
+ }
+
+ /* Received a packet from them to us */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport)) {
+ /* Is it a SYN/ACK? */
+ if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK)) {
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+
+ /*
+ * Save ttl for,admittedly poor,indications of reverse
+ * route change
+ */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd ++;
+ break;
+ } else {
+ if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
+ printf ("ERROR: EARLY_RST\n");
+ return(ESTABLISH_FAILURE_EARLY_RST);
+ }
+ }
+ }
+ }
+ }
+
+ if (!synAckReceived) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN | syn_flags, 0, tcpoptlen, ip_tos);
+ timeoutTime = GetTime() + 1;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= 3) {
+ printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
+ NO_CONNECTION);
+ return(ESTABLISH_FAILURE_NO_REPLY);
+ }
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("Received SYN-ACK, try to send the third Ack\n");
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("src = %s:%d (%u)\n", InetAddress(session.src),
+ session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n",InetAddress(session.dst),
+ session.dport, session.irs);
+ }
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ ackPacket = AllocateIPPacket(0, 0, 0, "Third ACK");
+ /* send an ACK */
+ SendSessionPacket(ackPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ TCPFLAGS_ACK, 0, 0, 0);
+ FreeIPPacket(&synPacket);
+ FreeIPPacket(&ackPacket);
+ return(ESTABLISH_SUCCESS);
+}
+
+void ECNTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss)
+{
+ int rawSocket, rc, flag = 1;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ /* random initial sequence number */
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime ();
+ session.maxpkts = 1000;
+/* session.debug = SESSION_DEBUG_LOW; */
+ session.debug = 0;
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memmory to store data:\nRETURN CODE: %d",
+ ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Establish a TCP connections with ECN bits */
+ rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
+ switch (rc) {
+ case ESTABLISH_FAILURE_EARLY_RST:
+ {
+ /* Received a RST when ECN bits are used. Try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Received RST with or without ECN negotiation\n");
+ printf("The server might not be listening on this port\n");
+ Quit(EARLY_RST);
+ } else if (rc == ESTABLISH_SUCCESS) {
+ printf("Received RST with ECN.\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Received RST with ECN\n");
+ printf("Exceed max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ }
+ break;
+ }
+ case ESTABLISH_FAILURE_NO_REPLY:
+ {
+ /* No reply after retring, try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Received RST without ECN\n");
+ Quit(NO_CONNECTION);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Exceeded max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ } else {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ }
+ break;
+ }
+ }
+
+ /* Test for propogation of CE correctly */
+ DataPkt(session.filename, 3, 0);
+
+ checkECN();
+ return;
+}
+
+void DataPkt (char *filename, u_int8_t iptos, u_int8_t tcp_flags)
+{
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i ;
+ int sendflag = 1 ;
+ u_int16_t lastSeqSent = session.snd_nxt;
+ double startTime = 0;
+ char *dataptr ;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+
+ datalen = PrepareRequest (data, filename);
+
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr,(void *)data, datalen);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+
+ /* send the data packet
+ * we try to "achieve" reliability by
+ * sending the packet upto 5 times, wating for
+ * 2 seconds between packets
+ * BAD busy-wait loop
+ */
+
+ i = 0 ;
+ while(1) {
+
+ if (sendflag == 1) {
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, iptos);
+
+ startTime = GetTime();
+ sendflag = 0 ;
+ i++ ;
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src, session.sport,
+ session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ SEQ_GT(ntohl(p->tcp->tcp_seq), lastSeqSent) &&
+ SEQ_LEQ(ntohl(p->tcp->tcp_ack), session.rcv_nxt)) {
+ lastSeqSent = ntohl(p->tcp->tcp_seq);
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.snd_nxt += datalen + 1;
+ session.totSeenSent ++ ;
+ continue ;
+ }
+
+ /*
+ * from them?
+ */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport) && (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ SEQ_GT(ntohl(p->tcp->tcp_ack), session.snd_una)) {
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ session.snd_nxt = session.snd_una;
+ if (p->ip->ip_ttl != session.ttl) {
+ session.ttl = p->ip->ip_ttl;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totRcvd ++;
+ break ;
+ }
+ /*
+ * otherwise, this is a bad packet
+ * we must quit
+ */
+ //processBadPacket(p);
+ }
+ if ((GetTime() - startTime >= 1) && (sendflag == 0) && (i < 3)) {
+ sendflag = 1 ;
+ }
+ if (i >= 3) {
+ printf ("ERROR: sent request 3 times without response\n");
+ return;
+ }
+ }
+
+ FreeIPPacket(&datapkt);
+
+ /* process any response by sending Acks */
+ rcvData (ECNAckData);
+}
+
+void ECNAckData (struct IPPacket *p)
+{
+
+ uint32 seq = history[session.hsz - 1].seqno;
+ uint16 datalen = history[session.hsz - 1].dlen;
+ int fin = history[session.hsz - 1].fin;
+ int rst = history[session.hsz - 1].rst;
+ int i;
+ struct IPPacket *ackpkt = NULL;
+ static int ECT_00 = 0;
+ static int ECT_01 = 0;
+ static int ECT_10 = 0;
+ static int ECT_11 = 0;
+ static int ECN_ECHO = 0;
+ static int send_cwr = 0;
+ static int send_ece = 0;
+ uint8 tcp_flags = 0;
+
+
+ /* Legend:
+ * ECN_ECHO: counts packets with TCP header ECN bit set
+ * ECT_XX: counts packets with ECT codepoint XX (IP)
+ */
+
+ if (datalen > session.mss) {
+ printf ("ERROR: mss=%d datalen=%d\nRETURN CODE: %d\n",
+ session.mss, datalen, MSS_ERR);
+ Quit(MSS_ERR);
+ }
+
+ if (datalen > 0) {
+ char *http_code = (char *)calloc(4, sizeof(char));
+ if (seq - session.irs == 1) {
+ /* Response to request packet --> check HTTP response code */
+ memcpy(http_code, ((char *)(p->tcp) + sizeof(struct TcpHeader) +
+ history[session.hsz - 1].optlen + 9), 3);
+ if (strncmp(http_code, HTTP_OK, 3) != 0) {
+ printf("HTTP ERROR - HTTP RESPONSE CODE: %s\nRETURN CODE: %d\n",
+ http_code, atoi(http_code));
+ Quit(atoi(http_code));
+ }
+ }
+
+ session.totDataPktsRcvd++;
+
+ if (session.verbose) {
+ printf ("r %f %d %d\n",
+ GetTime() - session.epochTime,
+ seq - session.irs,
+ seq - session.irs + datalen);
+ }
+
+ }
+
+ /* Check if packet has the ECN_ECHO flag set */
+ if (history[session.hsz - 1].ecn_echo) {
+ ECN_ECHO += 1;
+ }
+
+ if ((p->ip->ip_tos & 0x17) == 0) {
+ ECT_00 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 1) {
+ ECT_01 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 2) {
+ ECT_10 += 1;
+ }
+ if ((p->ip->ip_tos & 0x17) == 3) {
+ ECT_11 += 1;
+ }
+
+ if(session.maxseqseen < seq + datalen - 1) {
+ session.maxseqseen = seq + datalen - 1;
+ } else {
+ if (datalen > 0) {
+ if (reordered(p) != 1) {
+ session.num_unwanted_drops += 1;
+ }
+ }
+ }
+
+ /* from TCP/IP vol. 2, p 808 */
+ if (SEQ_LEQ(session.rcv_nxt, seq) &&
+ SEQ_LT(seq, (session.rcv_nxt + session.rcv_wnd)) &&
+ SEQ_LEQ(session.rcv_nxt, (seq + datalen)) &&
+ SEQ_LT((seq+datalen-1), (session.rcv_nxt + session.rcv_wnd))) {
+ int start, end;
+ start = seq - session.irs ;
+ end = start + datalen ;
+
+ for (i = start ; i < end ; i++) {
+ session.dataRcvd[i] = 1 ;
+ }
+
+ start = session.rcv_nxt - session.irs ;
+ end = session.mss * session.maxpkts ;
+
+ for (i = start ; i < end ; i++) {
+ if (session.dataRcvd[i] == 0) {
+ break ;
+ }
+ session.rcv_nxt++ ;
+ }
+ }
+
+ if (datalen > 0) {
+ if (session.verbose) {
+ printf ("a %f %d\n", GetTime() - session.epochTime,
+ session.rcv_nxt - session.irs);
+ }
+ ackpkt = AllocateIPPacket(0, 0, 0, "NewECN (ACK)");
+ if ((p->ip->ip_tos & 0x17) == 3) {
+ tcp_flags = TCPFLAGS_ACK | TCPFLAGS_ECN_ECHO;
+ } else {
+ tcp_flags = TCPFLAGS_ACK;
+ }
+
+ if (send_cwr == 2 && send_ece < 2) {
+ /* Send ECE as if a CE was received, we have to get CWR back */
+ send_ece = 1;
+ tcp_flags |= TCPFLAGS_ECN_ECHO;
+ }
+
+ SendSessionPacket (ackpkt,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ tcp_flags, 0, 0, 0);
+ }
+
+ if (send_cwr == 0 && (p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
+ /* Send CWR atleast once if ECN ECHO is set */
+ int datalen;
+ struct IPPacket *datapkt;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int ipsz;
+
+ datalen = PrepareRequest(data, NULL);
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr, (void *)data, datalen);
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) +
+ datalen + 1;
+
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | TCPFLAGS_CWR, 0, 0, 2);
+
+ session.snd_nxt += (datalen + 1);
+ send_cwr = 1;
+ FreeIPPacket(&datapkt);
+ }
+
+ if (send_cwr == 1 && !(p->tcp->tcp_flags & TCPFLAGS_ECN_ECHO)) {
+ /* ECE was reset in response to CWR, move to the next state of probing */
+ send_cwr = 2;
+ }
+
+ if (send_ece == 1 && (p->tcp->tcp_flags & TCPFLAGS_CWR)) {
+ /* Received CWR in response to ECE */
+ send_ece = 2;
+ }
+
+ if (SEQ_GT(ntohl(p->tcp->tcp_ack), session.snd_una))
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ if (SEQ_LT(session.snd_nxt, session.snd_una))
+ session.snd_nxt = session.snd_una;
+
+ if (fin || rst) {
+ /* Increment sequence number for FIN rcvd */
+ session.rcv_nxt++;
+ if (ECT_01 == 0 && ECT_10 == 0) {
+ printf("Never received ECT(0) or ECT(1) in ToS field: FAIL\n");
+ }
+ if (ECT_11 > 3) {
+ /* If we received more than 3 CE, flag it as an error */
+ printf("Received too many ECT_CE (%d): FAIL\n", ECT_11);
+ }
+ printf ("Totdata = %d ECN_ECHO: %d ECT00: %d ECT01: %d ECT10: %d ECT11: %d drops: %d\n",
+ session.rcv_nxt - session.irs, ECN_ECHO, ECT_00,
+ ECT_01, ECT_10, ECT_11, session.num_unwanted_drops);
+ if (fin) {
+ SendSessionPacket (ackpkt,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ tcp_flags, 0, 0, 0);
+ }
+ checkECN();
+ Quit(SUCCESS);
+ }
+}
+
+void checkECN ()
+{
+ int i;
+ int sr = 0; /* sr=1: SYN/ACK rcvd */
+ int se = 0; /* se=0: no CWR/no ECHO; se=1: no CWR/ECHO; se=2: CWR/ECHO */
+ int ar = 0; /* ar=0: no ACK rcvd; ar=1: ACK rcvd */
+ int ae = 0; /* ae=0: ACK/no ECHO; ae=1: ACK/ECHO */
+ int we = 0; /* we=0: no ECHO; we=1 ECHO/CWR; we=2 ECHO/CWR/ECHO stop */
+ int ee = 0; /* ee=0 never sent ECE; ee=1 sent ECE; ee=2 ECE / CWR */
+
+ for (i = 0 ; i < session.hsz; i++) {
+ if ((history[i].type == RCVD) && (history[i].syn == 1) &&
+ (history[i].ack == 1)) {
+ sr = 1;
+ if (history[i].ecn_echo == 1) {
+ se = 1;
+ if (history[i].cwr == 1) {
+ se = 2;
+ }
+ }
+ }
+ }
+
+ for (i = 0 ; i < session.hsz; i++) {
+ if (history[i].type == RCVD && history[i].syn == 0 &&
+ history[i].ack == 1) {
+ ar = 1;
+ if (history[i].ecn_echo == 1) {
+ ae = 1;
+ }
+ }
+ }
+
+ for (i = 0; i < session.hsz; i++) {
+ if (history[i].type == SENT && history[i].dlen > 0 &&
+ history[i].cwr == 1) {
+ we = 1;
+ continue;
+ }
+ if (we == 1 && history[i].type == RCVD && history[i].ecn_echo == 0) {
+ we = 2;
+ break;
+ }
+ if (we == 2 && history[i].type == RCVD && history[i].ecn_echo == 1) {
+ we = 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < session.hsz; i++) {
+ if (history[i].type == SENT && history[i].ecn_echo == 1) {
+ ee = 1;
+ continue;
+ }
+ if (ee == 1 && history[i].type == RCVD && history[i].dlen > 0 &&
+ history[i].cwr == 1) {
+ /* Received cwr in response to ECE */
+ ee = 2;
+ break;
+ }
+ }
+
+ printf ("sr=%d se=%d ar=%d ae=%d we=%d\n", sr, se, ar, ae, we);
+ switch (sr) {
+ case 0:
+ printf("No SYN/ACK received from server\n");
+ break;
+ case 1:
+ printf("SYN/ACK received: PASS \n");
+ break;
+ default:
+ printf("Unknown value for sr: %d\n", sr);
+ break;
+ }
+ switch (se) {
+ case 0:
+ printf("No CWR or ECE on SYN/ACK, server does not support ECN\n");
+ break;
+ case 1:
+ printf("ECE flag set on SYN/ACK, server supports ECN: PASS\n");
+ break;
+ case 2:
+ printf("Both CWR and ECE set on SYN/ACK, incompatible SYN/ACK\n");
+ break;
+ default:
+ printf("Unknown value for se: %d\n", se);
+ break;
+ }
+
+ switch (ar) {
+ case 0:
+ printf("No ACK received\n");
+ break;
+ case 1:
+ printf("ACK received: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ar: %d\n", ar);
+ break;
+ }
+
+ switch (ae) {
+ case 0:
+ printf("Received ACKS but never ECE\n");
+ break;
+ case 1:
+ printf("Received ACKs with ECE, in response to simulated CE bit: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ae: %d\n", ae);
+ break;
+ }
+
+ switch (we) {
+ case 0:
+ printf("Never received ECE\n");
+ break;
+ case 1:
+ printf("Received ECE and sent CWR\n");
+ break;
+ case 2:
+ printf("Received ECE, sent CWR and stopped receiving ECE afterwards: PASS\n");
+ break;
+ default:
+ printf("Unknown value for we: %d\n", we);
+ break;
+ }
+
+ switch (ee) {
+ case 0:
+ printf("Never sent ECE\n");
+ break;
+ case 1:
+ printf("Sent ECE to simulate receiving CE \n");
+ break;
+ case 2:
+ printf("Sent ECE and received CWR in response: PASS\n");
+ break;
+ default:
+ printf("Unknown value for ee: %d\n", ee);
+ break;
+ }
+ return;
+}
+
+void DataPktPathCheck(char *filename, u_int8_t iptos, u_int8_t tcp_flags)
+{
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i ;
+ int sendflag = 1 ;
+ u_int16_t lastSeqSent = session.snd_nxt;
+ double startTime = 0;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+ unsigned int init_ttl;
+
+ datalen = PrepareRequest (data, filename);
+
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "ECN (datapkt)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr,(void *)data, datalen);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+ /* send the data packet
+ * we try to "achieve" reliability by
+ * sending the packet upto 5 times, wating for
+ * 2 seconds between packets
+ * BAD busy-wait loop
+ */
+
+ i = 0 ;
+ init_ttl = 1;
+ while(1) {
+
+ if (sendflag == 1) {
+ session.curr_ttl = ++init_ttl;
+ if (init_ttl > 64) /* reached the max */
+ break;
+ SendSessionPacket(datapkt, ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK | tcp_flags, 0, 0, 0x3);
+
+ startTime = GetTime();
+ sendflag = 0;
+ i++ ;
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet =(char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src, session.sport,
+ session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ SEQ_GT(ntohl(p->tcp->tcp_seq), lastSeqSent) &&
+ SEQ_LEQ(ntohl(p->tcp->tcp_ack), session.rcv_nxt)) {
+ lastSeqSent = ntohl(p->tcp->tcp_seq);
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.snd_nxt += datalen + 1;
+ session.totSeenSent ++ ;
+ continue ;
+ }
+
+ /*
+ * from them?
+ */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport) && (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ ntohl(p->tcp->tcp_ack) == session.snd_nxt) {
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+ session.snd_nxt = session.snd_una;
+ if (p->ip->ip_ttl != session.ttl) {
+ session.ttl = p->ip->ip_ttl;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totRcvd ++;
+ break ;
+ }
+ /*
+ * ICMP ttl exceeded
+ */
+ if (p->ip->ip_p == IPPROTOCOL_ICMP) {
+ uint16_t ip_hl;
+ struct IcmpHeader *icmp;
+ ip_hl = (p->ip->ip_vhl & 0x0f) << 2;
+ void *nexthdr;
+
+ icmp = (struct IcmpHeader *)((char *)p->ip + ip_hl);
+ nexthdr = (void *)icmp;
+ if (icmp->icmp_type == ICMP_TIMXCEED) {
+ struct IpHeader off_ip;
+ struct TcpHeader off_tcp;
+
+ bzero(&off_ip, sizeof(struct IpHeader));
+ nexthdr = nexthdr + sizeof(struct IcmpHeader);
+ memcpy((void *)&off_ip, nexthdr,
+ sizeof(struct IpHeader));
+ nexthdr += sizeof(struct IpHeader);
+
+ bzero(&off_tcp, sizeof(struct TcpHeader));
+ memcpy(&off_tcp, nexthdr, 4);
+ if (session.src == off_ip.ip_src &&
+ session.dst == off_ip.ip_dst) {
+ printf("Received ICMP TTL exceeded from %s:"
+ "ttl used %u ip_tos 0x%x sport %u dport %u\n",
+ InetAddress(p->ip->ip_src), init_ttl, off_ip.ip_tos,
+ ntohs(off_tcp.tcp_sport), ntohs(off_tcp.tcp_dport));
+ }
+ }
+ }
+ /*
+ * otherwise, this is a bad packet
+ * we must quit
+ */
+ //processBadPacket(p);
+ }
+ if ((GetTime() - startTime >= 1) && (sendflag == 0)) {
+ sendflag = 1;
+ session.snd_nxt = session.snd_una;
+ }
+ }
+
+ FreeIPPacket(&datapkt);
+}
+void ECNPathCheckTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss)
+{
+ int rawSocket, rc, flag;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime();
+ session.maxpkts = 1000;
+ session.debug = 0;
+
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memory to store data, error: %d \n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ flag = 1;
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Establish a TCP connections with ECN bits */
+ rc = EstablishTcpConnection(TCPFLAGS_ECN_ECHO | TCPFLAGS_CWR, 0);
+ switch (rc) {
+ case ESTABLISH_FAILURE_EARLY_RST:
+ {
+ /* Received a RST when ECN bits are used. Try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Received RST with or without ECN negotiation\n");
+ printf("The server might not be listening on this port\n");
+ Quit(EARLY_RST);
+ } else if (rc == ESTABLISH_SUCCESS) {
+ printf("Received RST with ECN.\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Received RST with ECN\n");
+ printf("Exceed max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ }
+ break;
+ }
+ case ESTABLISH_FAILURE_NO_REPLY:
+ {
+ /* No reply after retring, try again without ECN */
+ rc = EstablishTcpConnection(0, 0);
+ if (rc == ESTABLISH_FAILURE_EARLY_RST) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Received RST without ECN\n");
+ Quit(NO_CONNECTION);
+ } else if (rc == ESTABLISH_FAILURE_NO_REPLY) {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Exceeded max SYN retransmits without ECN\n");
+ Quit(NO_CONNECTION);
+ } else {
+ printf("Exceeded max SYN retransmits with ECN\n");
+ printf("Connection established successfully without ECN\n");
+ Quit(ECN_SYN_DROP);
+ }
+ break;
+ }
+ }
+
+ DataPktPathCheck(session.filename, 3, 0);
+ return;
+}
+
+
+void
+SynTest(u_int32_t sourceAddress, u_int16_t sourcePort,
+ u_int32_t targetAddress, u_int16_t targetPort, int mss, int syn_reply)
+{
+ int rawSocket, flag;
+ struct IPPacket *synPacket = NULL, *ackPacket = NULL;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ int tcpoptlen = 4; /* For negotiating MSS */
+ u_int8_t *opt = NULL;
+ struct IPPacket *p = NULL;
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = 5*mss;
+ session.snd_nxt = arc4random();
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss;
+ session.maxseqseen = 0;
+ session.epochTime = GetTime();
+ session.maxpkts = 1000;
+
+ if ((session.dataRcvd = (u_int8_t *)calloc(sizeof(u_int8_t),
+ mss * session.maxpkts)) == NULL) {
+ printf("no memory to store data, error: %d \n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ flag = 1;
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL,
+ (char *)&flag, sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ synPacket = AllocateIPPacket(0, tcpoptlen, 0, "ECN (SYN)");
+ opt = (((u_int8_t *)synPacket->tcp) + sizeof(struct TcpHeader));
+ opt[0] = (u_int8_t)TCPOPT_MAXSEG;
+ opt[1] = (u_int8_t)TCPOLEN_MAXSEG;
+ *((u_int16_t *)((u_int8_t *)opt + 2)) = htons(session.mss);
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN , 0, tcpoptlen, 0);
+ timeoutTime = GetTime() + 1;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < 3) {
+ while(GetTime() < timeoutTime) {
+ /* Have we captured any packets? */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport,
+ session.dst, session.dport)) {
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+ session.totSeenSent++ ;
+ } else {
+ processBadPacket(p);
+ }
+ continue;
+ }
+
+ /* Received a packet from them to us */
+ if (INSESSION(p, session.dst, session.dport, session.src,
+ session.sport)) {
+ /* Is it a SYN/ACK? */
+ if ((p->tcp->tcp_flags & TCPFLAGS_SYN) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK)) {
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ PrintTcpPacket(p);
+ }
+ StorePacket(p);
+
+ /*
+ * Save ttl for,admittedly poor,indications of reverse
+ * route change
+ */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd ++;
+ break;
+ } else {
+ if ((p->tcp->tcp_flags)& (TCPFLAGS_RST)) {
+ printf ("ERROR: EARLY_RST\n");
+ goto done;
+ }
+ }
+ }
+ }
+ }
+
+ if (!synAckReceived) {
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader) + tcpoptlen,
+ TCPFLAGS_SYN , 0, tcpoptlen, 0);
+ timeoutTime = GetTime() + 1;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= 3) {
+ printf("ERROR: No connection after 3 retries...\nRETURN CODE: %d\n",
+ NO_CONNECTION);
+ goto done;
+ }
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("Received SYN-ACK\n");
+ if (syn_reply != 0) {
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("try to send the %s\n", syn_reply == TCPFLAGS_ACK ? "third Ack" : "RST");
+ printf("src = %s:%d (%u)\n", InetAddress(session.src),
+ session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n",InetAddress(session.dst),
+ session.dport, session.irs);
+ }
+
+ /* allocate the syn packet -- Changed for new IPPacket structure */
+ ackPacket = AllocateIPPacket(0, 0, 0, "SYN reply");
+ /* send an ACK */
+ SendSessionPacket(ackPacket,
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ syn_reply, 0, 0, 0);
+ FreeIPPacket(&ackPacket);
+ }
+done:
+ FreeIPPacket(&synPacket);
+}
diff --git a/network_cmds/ecnprobe/ecn.h b/network_cmds/ecnprobe/ecn.h
new file mode 100644
index 0000000..5ac582c
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+void ECNTest (u_int32_t sourceIpAddress, u_int16_t sourcePort, u_int32_t targetIpAddress, u_int16_t targetPort, int mss) ;
+void ECNAckData (struct IPPacket *p);
+void DataPkt (char *filename, u_int8_t iptos, u_int8_t tcp_flags);
+void checkECN ();
+void ECNPathCheckTest(u_int32_t sourceIpAddress, u_int16_t surcePort,
+ u_int32_t targetIpAddress, u_int16_t targetPort, int mss);
+void SynTest(u_int32_t sourceIpAddress, u_int16_t surcePort, u_int32_t targetIpAddress, u_int16_t targetPort, int mss, int syn_reply);
diff --git a/network_cmds/ecnprobe/ecn_probe.c b/network_cmds/ecnprobe/ecn_probe.c
new file mode 100644
index 0000000..362ff4f
--- /dev/null
+++ b/network_cmds/ecnprobe/ecn_probe.c
@@ -0,0 +1,469 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <spawn.h>
+#include <ifaddrs.h>
+#include "inet.h"
+#include "capture.h"
+#include "support.h"
+#include "session.h"
+#include "ecn.h"
+#include "history.h"
+
+extern struct TcpSession session;
+
+void usage (char *name);
+int GetCannonicalInfo(char *string, size_t str_size, u_int32_t *address);
+int BindTcpPort(int sockfd) ;
+
+void usage(char *name)
+{
+ printf("%s [options]\n", name);
+ printf("\t-n <target hostname | ipaddress>\n");
+ printf("\t-p <target port>\n");
+ printf("\t-m <mss>\n");
+ printf("\t-M <mtu>\n");
+ printf("\t-w <sourcePort>\n");
+ printf("\t-s <source hostname or ip address>\n");
+ printf("\t-f <file-name to get>\n");
+ printf("\t-d <interface name>\n");
+ printf("\t-C for CE path check\n");
+ printf("\t-S [A|R|X] SYN followed by ACK or RST or nothing\n");
+ printf("\t-F [set|clear|skip] how to handle firewall rules\n");
+ return;
+}
+
+void SetupFirewall(u_int32_t targetIP, u_int16_t port, char *dev)
+{
+ char pfcmd[512];
+ char *pf_file_name = "/tmp/pf.conf";
+ int pf_fd = 0, rc;
+ ssize_t bytes;
+ char *args[4];
+
+ bzero(pfcmd, sizeof(pfcmd));
+
+ bzero(args, sizeof(args));
+ sprintf(pfcmd, "block in quick on %s inet proto tcp from %s port %u\n",
+ dev, InetAddress(targetIP), port);
+ if (session.debug >= SESSION_DEBUG_LOW)
+ printf("PF rule: %s\n", pfcmd);
+
+ pf_fd = open(pf_file_name, O_RDWR|O_TRUNC|O_CREAT);
+ if (pf_fd < 0) {
+ perror("failed to open pf file");
+ exit(1);
+ }
+ bytes = write(pf_fd, pfcmd, strlen(pfcmd) + 1);
+ close(pf_fd);
+ args[0] = "pfctl";
+ args[1] = "-d";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -d: %d\n", rc);
+ Quit(FAIL);
+ }
+
+ args[1] = "-f";
+ args[2] = pf_file_name;
+ args[3] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -f /tmp/pf.conf: %d\n", rc);
+ Quit(FAIL);
+ }
+
+ args[1] = "-e";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -e: %d\n", rc);
+ Quit(FAIL);
+ }
+}
+
+void CleanupFirewall()
+{
+ char * args[3];
+ int rc;
+
+ args[0] = "pfctl";
+ args[1] = "-d";
+ args[2] = NULL;
+ rc = posix_spawn(NULL, "/sbin/pfctl", NULL, NULL, args, NULL);
+ if (rc != 0) {
+ printf("Failed to exec: pfctl -d: %d\n", rc);
+ Quit(FAIL);
+ }
+}
+
+void Cleanup()
+{
+ if (session.initSession > 0) {
+ shutdown(session.socket, 2);
+ }
+ if (session.initCapture > 0) {
+ CaptureEnd();
+ }
+ if (session.initFirewall > 0) {
+ CleanupFirewall();
+ }
+}
+
+void Quit(int how)
+{
+ SendReset();
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(how);
+}
+
+void SigHandle(int signo)
+{
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(-1);
+}
+
+int GetCannonicalInfo(char *string, size_t str_size, u_int32_t *address)
+{
+ struct hostent *hp;
+ /* Is string in dotted decimal format? */
+ if ((*address = inet_addr(string)) == INADDR_NONE) {
+ /* No, then lookup IP address */
+ if ((hp = gethostbyname(string)) == NULL) {
+ /* Can't find IP address */
+ printf("ERROR: Couldn't obtain address for %s\n"
+ "RETURN CODE: %d\n", string, FAIL);
+ return(-1);
+ } else {
+ strlcpy(string, hp->h_name, str_size);
+ memcpy((void *)address, (void *)hp->h_addr,
+ hp->h_length);
+ }
+ } else {
+ if ((hp = gethostbyaddr((char *)address, sizeof(*address),
+ AF_INET)) == NULL) {
+ /*
+ * Can't get cannonical hostname, so just use
+ * input string
+ */
+ if (session.debug) {
+ printf("WARNING: Couldn't obtain cannonical"
+ " name for %s\nRETURN CODE: %d",
+ string, NO_SRC_CANON_INFO);
+ }
+ /* strlcpy(name, string, MAXHOSTNAMELEN);*/
+ } else {
+ /* strlcpy(name, hp->h_name, MAXHOSTNAMELEN);*/
+ }
+ }
+ return(0);
+}
+
+int BindTcpPort(int sockfd)
+{
+ struct sockaddr_in sockName;
+ int port, result;
+ int randomOffset;
+
+#define START_PORT (50*1024)
+#define END_PORT (0xFFFF)
+
+ /*
+ * Choose random offset to reduce likelihood of
+ * collision with last run
+ */
+ randomOffset = (int)(1000.0*drand48());
+
+ /* Try to find a free port in the range START_PORT+1..END_PORT */
+ port = START_PORT+randomOffset;
+ do {
+ ++port;
+ sockName.sin_addr.s_addr = INADDR_ANY;
+ sockName.sin_family = AF_INET;
+ sockName.sin_port = 0; //htons(port);
+ result = bind(sockfd, (struct sockaddr *)&sockName,
+ sizeof(sockName));
+ } while ((result < 0) && (port < END_PORT));
+
+
+ if (result < 0) {
+ /* No free ports */
+ perror("bind");
+ port = 0;
+ } else {
+ socklen_t len = sizeof(sockName);
+ result = getsockname(sockfd, (struct sockaddr *)&sockName, &len);
+ if (result < 0) {
+ perror("getsockname");
+ port = 0;
+ } else {
+ port = ntohs(sockName.sin_port);
+ }
+ }
+ return port;
+
+}
+
+#define FIREWALL_DEFAULT 0
+#define FIREWALL_SET_ONLY 1
+#define FIREWALL_CLEAR_ONLY 2
+#define FIREWALL_SKIP 3
+
+int main(int argc, char **argv)
+{
+ u_int32_t targetIpAddress = 0;
+ u_int16_t targetPort = DEFAULT_TARGETPORT;
+ u_int16_t sourcePort = 0;
+ u_int32_t sourceIpAddress = 0;
+ int mss = DEFAULT_MSS;
+ int mtu = DEFAULT_MTU;
+ int fd, opt, usedev = 0, rc = 0, path_check = 0;
+ int syn_test = 0, syn_reply = 0;
+ struct sockaddr_in saddr;
+ char dev[11]; /* device name for pcap init */
+ struct ifaddrs *ifap, *tmp;
+ int firewall_mode = FIREWALL_DEFAULT;
+
+ bzero(&session, sizeof(session));
+ while ((opt = getopt(argc, argv, "n:p:w:m:M:s:d:f:-CS:vF:")) != -1) {
+ switch (opt) {
+ case 'n':
+ if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
+ printf("Target host name too long, max %u chars\n", MAXHOSTNAMELEN);
+ Quit(FAIL);
+ }
+ strlcpy(session.targetHostName, optarg,
+ sizeof(session.targetHostName));
+ strlcpy(session.targetName, session.targetHostName,
+ sizeof(session.targetName));
+ break;
+ case 'p':
+ targetPort = atoi(optarg);
+ break;
+ case 'm':
+ mss = atoi(optarg);
+ break;
+ case 'M':
+ mtu = atoi(optarg);
+ break;
+ case 'w':
+ sourcePort = atoi(optarg);
+ break;
+ case 's':
+ if (strlen(optarg) > (MAXHOSTNAMELEN - 1)) {
+ printf("Source host name too long, max %u chars\n", MAXHOSTNAMELEN);
+ Quit(FAIL);
+ }
+ strlcpy(session.sourceHostName, optarg,
+ MAXHOSTNAMELEN);
+ break;
+ case 'd':
+ if (strlen(optarg) > (sizeof(dev) - 1)) {
+ printf("Interface nae is too large, max %lu chars\n", (sizeof(dev) - 1));
+ Quit(FAIL);
+ }
+ bzero(dev, sizeof(dev));
+ strlcpy(dev, optarg, sizeof(dev));
+ usedev = 1;
+ break;
+ case 'f':
+ if (strlen(optarg) > 0) {
+ session.filename = strndup(optarg, strlen(optarg) + 1);
+ } else {
+ printf("Invalid file name \n");
+ }
+ break;
+ case 'F':
+ if (strcasecmp(optarg, "default") == 0)
+ firewall_mode = FIREWALL_DEFAULT;
+ else if (strcasecmp(optarg, "set") == 0)
+ firewall_mode = FIREWALL_SET_ONLY;
+ else if (strcasecmp(optarg, "clear") == 0)
+ firewall_mode = FIREWALL_CLEAR_ONLY;
+ else if (strcasecmp(optarg, "skip") == 0)
+ firewall_mode = FIREWALL_SKIP;
+ else
+ printf("firewall mode\n");
+ break;
+ case 'C':
+ path_check = 1;
+ break;
+ case 'S':
+ syn_test = 1;
+ if (strcasecmp(optarg, "A") == 0)
+ syn_reply = TCPFLAGS_ACK;
+ else if (strcasecmp(optarg, "R") == 0)
+ syn_reply = TCPFLAGS_RST;
+ else if (strcasecmp(optarg, "X") == 0)
+ syn_reply = 0;
+ else
+ printf("Invalid SYN reply \n");
+ break;
+ case 'v':
+ session.debug++;
+ break;
+ default:
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+ signal(SIGTERM, SigHandle);
+ signal(SIGINT, SigHandle);
+ signal(SIGHUP, SigHandle);
+
+ if (GetCannonicalInfo(session.targetHostName, sizeof(session.targetHostName),
+ &targetIpAddress) < 0)
+ {
+ printf("Failed to convert targetIP address\n");
+ Quit(NO_TARGET_CANON_INFO);
+ }
+ rc = getifaddrs(&ifap);
+ if (rc != 0 || ifap == NULL) {
+ printf("Failed to get source addresswith getifaddrs: %d\n", rc);
+ Quit(FAIL);
+ }
+ tmp = ifap;
+ sourceIpAddress = 0;
+ bzero(session.sourceHostName, MAXHOSTNAMELEN);
+ for (tmp = ifap; tmp != NULL; tmp = tmp->ifa_next) {
+ struct sockaddr_in *sin;
+ if (tmp->ifa_addr == NULL)
+ continue;
+ if (tmp->ifa_addr->sa_family != PF_INET)
+ continue;
+ if (usedev == 1) {
+ /* we know which interface to use */
+ if (strcmp(dev, tmp->ifa_name) == 0) {
+ sin = (struct sockaddr_in *)tmp->ifa_addr;
+ sourceIpAddress = sin->sin_addr.s_addr;
+ strlcpy(session.sourceHostName,
+ inet_ntoa(sin->sin_addr),
+ sizeof(session.sourceHostName));
+ } else {
+ continue;
+ }
+ } else {
+ /* pick the first address */
+ bzero(dev, sizeof(dev));
+ sin = (struct sockaddr_in *)tmp->ifa_addr;
+ sourceIpAddress = sin->sin_addr.s_addr;
+ strlcpy(session.sourceHostName,
+ inet_ntoa(sin->sin_addr),
+ sizeof(session.sourceHostName));
+ strlcpy(dev, tmp->ifa_name, sizeof(dev));
+ }
+ }
+ freeifaddrs(ifap);
+ if (sourceIpAddress == 0) {
+ printf("Failed to get source Ip address\n");
+ Quit(FAIL);
+ }
+
+ if (sourcePort == 0) {
+ bzero(&saddr, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ printf("Can't open socket\n");
+ return (-1);
+ }
+ if ((sourcePort = BindTcpPort(fd)) == 0) {
+ printf("Can't bind to port\n");
+ return (-1);
+ }
+ }
+ printf("Source: %s:%d\n", session.sourceHostName, sourcePort);
+ printf("Destination: %s:%d\n", session.targetHostName, targetPort);
+
+ switch (firewall_mode) {
+ case FIREWALL_DEFAULT:
+ SetupFirewall(targetIpAddress, targetPort, dev);
+ session.initFirewall = 1;
+ break;
+ case FIREWALL_SET_ONLY:
+ SetupFirewall(targetIpAddress, targetPort, dev);
+ goto done;
+ case FIREWALL_CLEAR_ONLY:
+ session.initFirewall = 1;
+ goto done;
+ case FIREWALL_SKIP:
+ break;
+ }
+
+ CaptureInit(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, dev);
+ session.initCapture = 1;
+
+
+ printf("Starting ECN test\n");
+ if (syn_test) {
+ session.dont_send_reset = 1;
+ SynTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss, syn_reply);
+ } else if (path_check) {
+ ECNPathCheckTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss);
+ } else {
+ ECNTest(sourceIpAddress, sourcePort, targetIpAddress,
+ targetPort, mss);
+ }
+done:
+ Quit(SUCCESS);
+ close(session.socket);
+ return (0);
+}
diff --git a/network_cmds/ecnprobe/ecnprobe.1 b/network_cmds/ecnprobe/ecnprobe.1
new file mode 100644
index 0000000..76c2173
--- /dev/null
+++ b/network_cmds/ecnprobe/ecnprobe.1
@@ -0,0 +1,20 @@
+.Dd 5/7/2015
+.Dt ecnprobe 1
+.Os Darwin
+.Sh NAME
+.Nm ecnprobe
+.Nd Tool to probe for TCP ECN related incompatibilities in the network
+.Sh SYNOPSIS
+.Nm
+.Op Fl n Ar target hostname or ipaddress
+.Op Fl p Ar target port
+.Op Fl m Ar mss
+.Op Fl M Ar mtu
+.Op Fl w Ar source port
+.Op Fl s Ar source ip address
+.Op Fl f Ar file name to get
+.Op Fl d Ar interface name
+.Sh DESCRIPTION
+The
+.Nm
+utility can be used to test TCP ECN related incompatibilities in the network.
diff --git a/network_cmds/ecnprobe/gmt2local.c b/network_cmds/ecnprobe/gmt2local.c
new file mode 100644
index 0000000..a6114f3
--- /dev/null
+++ b/network_cmds/ecnprobe/gmt2local.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "gmt2local.h"
+
+/*
+ * Returns the difference between gmt and local time in seconds.
+ * Use gmtime() and localtime() to keep things simple.
+ */
+int32_t
+gmt2local(time_t t)
+{
+ register int dt, dir;
+ register struct tm *gmt, *loc;
+ struct tm sgmt;
+
+ if (t == 0)
+ t = time(NULL);
+ gmt = &sgmt;
+ *gmt = *gmtime(&t);
+ loc = localtime(&t);
+ dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
+ (loc->tm_min - gmt->tm_min) * 60;
+
+ /*
+ * If the year or julian day is different, we span 00:00 GMT
+ * and must add or subtract a day. Check the year first to
+ * avoid problems when the julian day wraps.
+ */
+ dir = loc->tm_year - gmt->tm_year;
+ if (dir == 0)
+ dir = loc->tm_yday - gmt->tm_yday;
+ dt += dir * 24 * 60 * 60;
+
+ return (dt);
+}
diff --git a/network_cmds/ecnprobe/gmt2local.h b/network_cmds/ecnprobe/gmt2local.h
new file mode 100644
index 0000000..4933b09
--- /dev/null
+++ b/network_cmds/ecnprobe/gmt2local.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: gmt2local.h,v 1.2 97/01/23 22:31:40 leres Exp $ (LBL)
+ */
+#ifndef gmt2local_h
+#define gmt2local_h
+
+int32_t gmt2local(time_t);
+#endif
diff --git a/network_cmds/ecnprobe/history.c b/network_cmds/ecnprobe/history.c
new file mode 100644
index 0000000..e19b0ba
--- /dev/null
+++ b/network_cmds/ecnprobe/history.c
@@ -0,0 +1,211 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "support.h"
+#include "history.h"
+
+extern struct TcpSession session;
+struct History history[MAXHSZ];
+
+void StorePacket (struct IPPacket *p) {
+
+ uint32 src, dst, seq, ack ;
+ uint16 sport, dport, win, urp, datalen, optlen;
+ uint16 ip_optlen;
+ uint8 flags;
+
+ ReadIPPacket(p,
+ &src, &dst,
+ &sport, &dport,
+ &seq,
+ &ack,
+ &flags,
+ &win,
+ &urp,
+ &datalen,
+ &ip_optlen,
+ &optlen);
+
+ if (src == session.src) {
+ history[session.hsz].type = SENT;
+ } else {
+ history[session.hsz].type = RCVD ;
+ }
+
+ history[session.hsz].timestamp = GetTime () - session.epochTime;
+ history[session.hsz].seqno = seq;
+ history[session.hsz].nextbyte = seq + datalen;
+ history[session.hsz].ackno = ack ;
+ history[session.hsz].fin = (flags & TCPFLAGS_FIN) ? 1 : 0;
+ history[session.hsz].syn = (flags & TCPFLAGS_SYN) ? 1 : 0;
+ history[session.hsz].rst = (flags & TCPFLAGS_RST) ? 1 : 0;
+ history[session.hsz].psh = (flags & TCPFLAGS_PSH) ? 1 : 0;
+ history[session.hsz].ack = (flags & TCPFLAGS_ACK) ? 1 : 0;
+ history[session.hsz].urg = (flags & TCPFLAGS_URG) ? 1 : 0;
+ history[session.hsz].ecn_echo = (flags & TCPFLAGS_ECN_ECHO) ? 1:0;
+ history[session.hsz].cwr = (flags & TCPFLAGS_CWR) ? 1 : 0;
+ history[session.hsz].ip_optlen = ip_optlen;
+ history[session.hsz].optlen = optlen ;
+
+ /* Grab IP Options from Ip Header - New */
+ if (ip_optlen > 0) {
+ if ((history[session.hsz].ip_opt = calloc(sizeof(uint8), ip_optlen)) == NULL) {
+ printf("StorePacket Error: Could not allocate history memory\nRETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit (ERR_MEM_ALLOC);
+ }
+ memcpy(history[session.hsz].ip_opt, (char *)p->ip + sizeof(struct IpHeader), ip_optlen);
+ }
+
+
+ /* Grab TCP options from TCP Header */
+ if (optlen > 0) {
+ if ((history[session.hsz].opt = calloc(sizeof(uint8), optlen)) == NULL) {
+ Quit (ERR_MEM_ALLOC);
+ }
+
+ memcpy(history[session.hsz].opt, (char *)p->tcp + sizeof(struct TcpHeader), optlen);
+ }
+
+ history[session.hsz].dlen = datalen;
+
+ if ((history[session.hsz].data = calloc(sizeof(uint8), datalen)) == NULL) {
+ Quit (ERR_MEM_ALLOC);
+ }
+
+ /* Copy data bytes */
+ memcpy(history[session.hsz].data,
+ (char *)p->tcp + sizeof(struct TcpHeader) + optlen,
+ datalen);
+
+ session.hsz++;
+
+ if (session.hsz >= MAXHSZ) {
+ Quit(TOO_MANY_PKTS);
+ }
+
+}
+
+int reordered(struct IPPacket *p) {
+
+ int i;
+ int count = 0;
+ double ts = -99999;
+
+ /*
+ * This might be either an unwanted packet drop, or just a reordering.
+ * Test:
+ * If we have not sent three acks for this packet
+ * AND the gap between this packet and previous one is "small" (i.e. not a timeout)
+ * then its a reordering, and not a retransmission.
+ */
+
+ /* count the number of (dup) ACKs sent */
+ for (i = 0; i < session.hsz; i++) {
+ if ((history[i].type == SENT) &&
+ (history[i].ack)) {
+ if (history[i].ackno == history[session.hsz - 1].seqno)
+ count += 1;
+ }
+ }
+
+ if (count > 0) {
+
+ session.num_dup_acks += count - 1;
+
+ switch (count) {
+ case 1: /* no dup acks */
+ session.num_pkts_0_dup_acks += 1;
+ break;
+
+ case 2: /* 1 dup acks */
+ session.num_pkts_1_dup_acks += 1;
+ break;
+
+ case 3: /* 2 dup acks */
+ session.num_pkts_2_dup_acks += 1;
+ break;
+
+ case 4: /* 3 dup acks */
+ session.num_pkts_3_dup_acks += 1;
+ break;
+
+ default:
+ session.num_pkts_4_or_more_dup_acks += 1;
+ break;
+ }
+ }
+
+ /* 3 dup acks? => Fast retransmission */
+ if (count > 3) {
+ printf("Fast retransmit...\n");
+ return 3;
+ }
+
+ /* Compute elapsed time between this packet and the previously RCVD packet */
+ for (i = (session.hsz - 2); i >= 0; i--) {
+ if ((history[i].type == RCVD) && (history[i].dlen > 0)) {
+ ts = history[i].timestamp;
+ break;
+ }
+ }
+
+ if ((history[session.hsz - 1].timestamp - ts) > RTT_TO_MULT * (session.rtt + PLOTDIFF)) {
+ printf ("RTO ===> %f %f\n", history[session.hsz - 1].timestamp, ts);
+ return 2;
+ }
+
+ printf ("#### Acks %d\n", count);
+ printf ("#### reordering detected\n");
+ session.num_reordered++;
+
+ return 1;
+
+}
diff --git a/network_cmds/ecnprobe/history.h b/network_cmds/ecnprobe/history.h
new file mode 100644
index 0000000..9e69d44
--- /dev/null
+++ b/network_cmds/ecnprobe/history.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+#define SENT 1
+#define RCVD 2
+#define MAXHSZ 10000
+
+struct History { /* store history of each packet as it is seen */
+
+ int type ; /* sent or received */
+ double timestamp; /* when */
+ uint32 seqno;
+ uint32 nextbyte; /* seqno + dlen */
+ uint32 ackno;
+ int hlen;
+ int ecn_echo;
+ int cwr;
+ int urg;
+ int ack;
+ int psh;
+ int rst;
+ int syn;
+ int fin;
+ int ip_optlen; /* added to support IP options */
+ uint8 *ip_opt; /* added to support IP options */
+ int optlen;
+ uint8 *opt;
+ uint8 *data;
+ int dlen;
+
+ int pkt_num;
+
+};
+
+void StorePacket (struct IPPacket *p);
+int reordered (struct IPPacket *p);
diff --git a/network_cmds/ecnprobe/inet.c b/network_cmds/ecnprobe/inet.c
new file mode 100644
index 0000000..b145412
--- /dev/null
+++ b/network_cmds/ecnprobe/inet.c
@@ -0,0 +1,503 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "history.h"
+
+extern struct TcpSession session;
+extern struct History history[];
+
+/*
+ * Deal with struct in_addr type agreement once and for all
+ */
+char *InetAddress(uint32 addr)
+{
+
+ struct in_addr s;
+ s.s_addr = addr;
+
+ //printf("In InetAddress:\n");
+ //printf("addr = %s (%0x)\n", inet_ntoa(s), addr);
+
+ return (inet_ntoa(s));
+}
+
+/*
+ * Really slow implementation of ip checksum
+ * ripped off from rfc1071
+ */
+
+uint16 InetChecksum(uint16 *ip, uint16 *tcp, uint16 ip_len, uint16 tcp_len) {
+
+ uint32 sum = 0;
+
+ uint32 ip_count = ip_len;
+ uint32 tcp_count = tcp_len;
+ uint16 *ip_addr = ip;
+ uint16 *tcp_addr = tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In InetChecksum...\n");
+ printf("iplen: %d, tcplen: %d\n", ip_len, tcp_len);
+ }
+
+
+ while(ip_count > 1) {
+ //printf("ip[%d]: %x\n", ip_len - ip_count, htons(*ip_addr));
+ sum += *ip_addr++;
+ ip_count -= 2;
+ }
+
+ while(tcp_count > 1) {
+ //printf("tcp[%d]: %x\n", tcp_len - tcp_count, htons(*tcp_addr));
+ sum += *tcp_addr++;
+ tcp_count -= 2;
+ }
+
+ if(ip_count > 0) {
+ sum += *(uint8 *)ip_addr;
+ }
+
+ if(tcp_count > 0) {
+ sum += *(uint8 *)tcp_addr;
+ }
+
+ while (sum >> 16) {
+ sum = (sum & 0xffff) + (sum >> 16);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out InetChecksum...\n");
+ }
+
+ return(~sum);
+
+}
+
+
+void WriteIPPacket(struct IPPacket *p,
+ uint32 src,
+ uint32 dst,
+ uint16 sport,
+ uint16 dport,
+ uint32 seq,
+ uint32 ack,
+ uint8 flags,
+ uint16 win,
+ uint16 urp,
+ uint16 datalen,
+ uint16 ip_optlen,
+ uint16 optlen,
+ uint8 iptos,
+ uint8 u4tf)
+{
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In WriteIPPacket...\n");
+ }
+
+ /* Zero out IpHeader to ensure proper checksum computation */
+ bzero((char *)(p->ip), sizeof(struct IpHeader));
+
+ ip->ip_src = src;
+ ip->ip_dst = dst;
+ ip->ip_p = IPPROTOCOL_TCP;
+ ip->ip_xsum =
+ htons((uint16)(sizeof(struct TcpHeader) + datalen + optlen)); /* pseudo hdr */
+
+ tcp->tcp_sport = htons(sport);
+ tcp->tcp_dport = htons(dport);
+ tcp->tcp_seq = htonl(seq);
+ tcp->tcp_ack = htonl(ack);
+ tcp->tcp_hl = (sizeof(struct TcpHeader) + optlen) << 2;
+ tcp->tcp_hl = tcp->tcp_hl | u4tf;
+ tcp->tcp_flags = flags;
+
+ tcp->tcp_win = htons(win);
+ tcp->tcp_urp = htons(urp);
+
+ tcp->tcp_xsum = 0;
+ tcp->tcp_xsum = InetChecksum((uint16 *)ip, (uint16 *)tcp,
+ (uint16)sizeof(struct IpHeader), /* IP Options should aren't included */
+ (uint16)(sizeof(struct TcpHeader) + datalen + optlen));
+
+ /* Fill in real ip header */
+ if (session.curr_ttl != 0) {
+ ip->ip_ttl = session.curr_ttl;
+ }else {
+ ip->ip_ttl = 60;
+ }
+
+ //printf("TTL: %d\n", ip->ip_ttl);
+
+ ip->ip_tos = iptos;
+
+ /* IP Version and Header len field */
+ ip->ip_vhl = 0x40 + 0x5 + (int)(ip_optlen/4);
+ ip->ip_p = IPPROTOCOL_TCP;
+
+ ip->ip_off = IP_DF;
+ ip->ip_len = (uint16)(sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen + datalen);
+
+ ip->ip_xsum = 0;
+ ip->ip_xsum = InetChecksum((uint16 *)ip, NULL,
+ (uint16)sizeof(struct IpHeader) + ip_optlen, /* IP Options should aren't included */
+ 0);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out WriteIPPacket...\n");
+ }
+
+}
+
+void ReadIPPacket(struct IPPacket *p,
+ uint32 *src,
+ uint32 *dst,
+ uint16 *sport,
+ uint16 *dport,
+ uint32 *seq,
+ uint32 *ack,
+ uint8 *flags,
+ uint16 *win,
+ uint16 *urp,
+ uint16 *datalen,
+ uint16 *ip_optlen,
+ uint16 *optlen)
+{
+
+ /* TODO: Add reading of IP options, if any */
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ uint16 ip_len;
+ uint16 ip_hl;
+ uint16 tcp_hl;
+
+ /* XXX do checksum check? */
+ if (ip->ip_p != IPPROTOCOL_TCP && ip->ip_p != IPPROTOCOL_ICMP) {
+ printf("Unexpected protocol packet: %u\n", ip->ip_p);
+ Quit(ERR_CHECKSUM);
+ }
+
+ *src = ip->ip_src;
+ *dst = ip->ip_dst;
+ *sport = ntohs(tcp->tcp_sport);
+ *dport = ntohs(tcp->tcp_dport);
+ *seq = ntohl(tcp->tcp_seq);
+ *ack = ntohl(tcp->tcp_ack);
+ *flags = tcp->tcp_flags;
+ *win = ntohs(tcp->tcp_win);
+ *urp = ntohs(tcp->tcp_urp);
+
+ tcp_hl = tcp->tcp_hl >> 2;
+ ip_len = ntohs(ip->ip_len);
+ ip_hl = (ip->ip_vhl & 0x0f) << 2;
+ *datalen = (ip_len - ip_hl) - tcp_hl;
+ *ip_optlen = ip_hl - (unsigned int)sizeof(struct IpHeader); /* added to support IP Options */
+ *optlen = tcp_hl - (unsigned int)sizeof(struct TcpHeader);
+
+}
+
+void PrintICMPUnreachableErrorPacket(struct ICMPUnreachableErrorPacket *p)
+{
+
+ struct IpHeader *ip = &p->ip;
+ struct IcmpHeader *icmp = &p->icmp;
+ struct IpHeader *off_ip = &p->off_ip;
+
+ printf("IPHdr: ");
+ printf("%s > ", InetAddress(ip->ip_src));
+ printf("%s ", InetAddress(ip->ip_dst));
+ printf(" datalen: %u\n", ip->ip_len);
+ printf("ICMPHdr: ");
+ printf("Type: %u Code: %u MTU next hop: %u xsum: %x\n",
+ icmp->icmp_type,
+ icmp->icmp_code,
+ ntohs(icmp->icmp_mtu),
+ icmp->icmp_xsum);
+ printf("Off IPHdr: ");
+ printf("%s > ", InetAddress(off_ip->ip_src));
+ printf("%s ", InetAddress(off_ip->ip_dst));
+ printf(" datalen: %u ", off_ip->ip_len);
+ printf("tcp sport: %u ", ntohs(p->tcp_sport));
+ printf("tcp dport: %u ", ntohs(p->tcp_dport));
+ printf("tcp seqno: %u\n", (uint32)ntohl(p->tcp_seqno));
+
+}
+
+void PrintTcpPacket(struct IPPacket *p)
+{
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ char *opt;
+ int optlen;
+ char *ip_opt;
+ int ip_optlen;
+ int i;
+
+ printf("%s.%u > ", InetAddress(ip->ip_src), ntohs(tcp->tcp_sport));
+ printf("%s.%u ", InetAddress(ip->ip_dst), ntohs(tcp->tcp_dport));
+
+ if (tcp->tcp_flags & TCPFLAGS_SYN) {
+ printf("S");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_ACK) {
+ printf("A");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_FIN) {
+ printf("F");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_ECN_ECHO) {
+ printf("E");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_CWR) {
+ printf("W");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_RST) {
+ printf("R");
+ }
+ if (tcp->tcp_flags & TCPFLAGS_PSH) {
+ printf("P");
+ }
+
+ if (tcp->tcp_flags & TCPFLAGS_URG) {
+ printf("U");
+ }
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport)) {
+ printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.iss, (uint32)ntohl(tcp->tcp_ack) - session.irs);
+ } else {
+ printf(" seq: %u, ack: %u", (uint32)ntohl(tcp->tcp_seq) - session.irs, (uint32)ntohl(tcp->tcp_ack) - session.iss);
+ }
+
+ /* IP Options */
+ ip_optlen = ((ip->ip_vhl & 0x0f) << 2) - sizeof(struct IpHeader);
+ ip_opt = (char *)ip + sizeof(struct IpHeader);
+
+ i = 0;
+ while (i < ip_optlen) {
+
+ switch ((unsigned char)ip_opt[i]) {
+ case IPOPT_NOP:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_NOP");
+ i = i + 1;
+ break;
+
+ case IPOPT_EOL:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_EOL");
+ i = ip_optlen + 1;
+ break;
+
+ case IPOPT_RR:
+ printf(" ipopt%d: %s ", i + 1, "IPOPT_RR");
+ i = i + IPOLEN_RR;
+ break;
+
+ default:
+ printf("ip_opt%d: UNKNOWN ", i + 1);
+ i = i + (uint8)ip_opt[i+1] ;
+ }
+ }
+
+ printf(" win: %u, urg: %u, ttl: %d", ntohs(tcp->tcp_win), ntohs(tcp->tcp_urp), ip->ip_ttl);
+ printf(" datalen: %u, optlen: %u ",
+ ip->ip_len - ((ip->ip_vhl &0x0f) << 2) - (tcp->tcp_hl >> 2),
+ (tcp->tcp_hl >> 2) - (unsigned int)sizeof(struct TcpHeader));
+
+
+ /* TCP Options */
+ optlen = (tcp->tcp_hl >> 2) - (unsigned int)sizeof (struct TcpHeader) ;
+ opt = (char *)tcp + sizeof(struct TcpHeader);
+
+ i = 0 ;
+
+ while (i < optlen) {
+
+ switch ((unsigned char)opt[i]) {
+
+ case TCPOPT_EOL:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_EOL");
+ i = optlen + 1;
+ break ;
+
+ case TCPOPT_NOP:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_NOP");
+ i++ ;
+ break ;
+
+ case TCPOPT_MAXSEG:
+ printf (" opt%d: %s: %d ", i + 1, "TCPOPT_MAXSEG", ntohs(*(uint16 *)((char *)opt+2)));
+ i = i + TCPOLEN_MAXSEG ;
+ break ;
+
+ case TCPOPT_WINDOW:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_WINDOW");
+ i = i + TCPOLEN_WINDOW ;
+ break ;
+
+ case TCPOPT_SACK_PERMITTED:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_SACK_PERMITTED");
+ i = i + TCPOLEN_SACK_PERMITTED ;
+ break ;
+
+ case TCPOPT_TIMESTAMP:
+ printf (" opt%d: %s ", i + 1, "TCPOPT_TIMESTAMP");
+ i = i + TCPOLEN_TIMESTAMP ;
+ break ;
+
+ default:
+ printf (" opt%d c:%d l:%d: UNKNOWN ", i + 1, (uint8)opt[i], (uint8)opt[i+1]);
+ if ((uint8)opt[i+1] > 0) {
+ i = i + (uint8)opt[i+1] ;
+ } else {
+ Quit(20);
+ }
+ break ;
+ }
+ }
+ printf ("\n");
+}
+
+
+struct IPPacket *FindHeaderBoundaries(char *p) {
+
+ struct IPPacket *packet;
+ uint16 ip_hl;
+
+ if ((packet = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) == NULL) {
+ printf("FindHeaderBoundaries: Cannot allocate memory for read packet\nRETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ packet->ip = (struct IpHeader *)p;
+
+ if (packet->ip->ip_p != IPPROTOCOL_TCP &&
+ packet->ip->ip_p != IPPROTOCOL_ICMP) {
+ printf("Error: Unexpected protocol packet: %u \n", packet->ip->ip_p);
+ Quit(ERR_CHECKSUM);
+ }
+
+ ip_hl = (packet->ip->ip_vhl & 0x0f) << 2;
+
+ packet->tcp = (struct TcpHeader *)((char *)p + ip_hl);
+ return packet;
+
+}
+
+
+struct IPPacket *
+AllocateIPPacket(int ip_optlen, int tcp_optlen, int datalen, char *str)
+{
+ struct IPPacket *p;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In AllocateIPPacket: %s...\n", str);
+ }
+
+ if ((p = (struct IPPacket *)calloc(1, sizeof(struct IPPacket)))
+ == NULL) {
+ printf("%s ERROR: No space for packet\nRETURN CODE: %d",
+ str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((p->ip = (struct IpHeader *)calloc(1,
+ sizeof(struct IpHeader) + ip_optlen)) == NULL) {
+ printf("%s ERROR: No IpHeader space for packet\n"
+ "RETURN CODE: %d", str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if ((p->tcp = (struct TcpHeader *)calloc(1,
+ sizeof(struct TcpHeader) + tcp_optlen + datalen)) == NULL) {
+ printf("%s ERROR: No TcpHeader space for packet\n"
+ "RETURN CODE: %d", str, ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of AllocateIPPacket: %s...\n", str);
+ }
+ return(p);
+}
+
+void
+FreeIPPacket(struct IPPacket **pkt_p)
+{
+ struct IPPacket *pkt;
+ if (pkt_p == NULL)
+ return;
+ if ((pkt = *pkt_p) == NULL)
+ return;
+ if (pkt->ip != NULL) {
+ free(pkt->ip);
+ pkt->ip = NULL;
+ }
+ if (pkt->tcp != NULL) {
+ free(pkt->tcp);
+ pkt->tcp = NULL;
+ }
+ free(pkt);
+ *pkt_p = NULL;
+}
+
diff --git a/network_cmds/ecnprobe/inet.h b/network_cmds/ecnprobe/inet.h
new file mode 100644
index 0000000..8d1ccff
--- /dev/null
+++ b/network_cmds/ecnprobe/inet.h
@@ -0,0 +1,206 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 _INET_H_
+#define _INET_H_
+
+/* XXX These are machine/compiler dependent */
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+typedef unsigned int uint32;
+
+#define IPPROTOCOL_ICMP 1
+#define IPPROTOCOL_IGMP 2
+#define IPPROTOCOL_TCP 6
+#define IPPROTOCOL_UDP 17
+#define IP_DF 0x4000
+
+/* ICMP type */
+#define ICMP_TIMXCEED 11
+
+/* TCP Flags */
+#define TCPFLAGS_FIN 0x01
+#define TCPFLAGS_SYN 0x02
+#define TCPFLAGS_RST 0x04
+#define TCPFLAGS_PSH 0x08
+#define TCPFLAGS_ACK 0x10
+#define TCPFLAGS_URG 0x20
+#define TCPFLAGS_ECN_ECHO 0x40
+#define TCPFLAGS_CWR 0x80
+
+/* IP Options Parameters -- for IP Options te*/
+#define IPOPT_EOL 0x0
+#define IPOLEN_EOL 0x1
+#define IPOPT_NOP 0x1
+#define IPOLEN_NOP 0x1
+#define IPOPT_RR 0x7
+#define IPOLEN_RR 0x27 /* Maximum length; up to 9 IP addresses */
+#define IPOPT_TS 0x44
+#define IPOLEN_TS 0x28
+#define IPOPT_FAKED 0xff
+#define IPOLEN_FAKED 0x4
+
+/* TCP Options Parameters */
+#define TCPOPT_EOL 0
+#define TCPOLEN_EOL 1
+#define TCPOPT_NOP 1
+#define TCPOLEN_NOP 1
+#define TCPOPT_MAXSEG 2
+#define TCPOLEN_MAXSEG 4
+#define TCPOPT_WINDOW 3
+#define TCPOLEN_WINDOW 3
+#define TCPOPT_SACK_PERMITTED 4
+#define TCPOLEN_SACK_PERMITTED 2
+#define TCPOPT_SACK 5
+#define TCPOPT_TIMESTAMP 8
+#define TCPOLEN_TIMESTAMP 10
+#define TCPOPT_FAKED 0x19
+#define TCPOLEN_FAKED 0x4
+
+struct IpHeader {
+ uint8 ip_vhl; /* version (4bits) & header length (4 bits) */
+ uint8 ip_tos; /* type of service */
+ uint16 ip_len; /* length of IP datagram */
+ uint16 ip_id; /* identification (for frags) */
+ uint16 ip_off; /* offset (within a fragment) and flags (3 bits) */
+ uint8 ip_ttl; /* time to live */
+ uint8 ip_p; /* protocol number */
+ uint16 ip_xsum; /* checksum */
+ uint32 ip_src; /* source address */
+ uint32 ip_dst; /* destination address */
+};
+
+/* Pseudo header for doing TCP checksum calculation */
+struct PseudoIpHeader {
+ uint32 filler[2];
+ uint8 zero;
+ uint8 ip_p;
+ uint16 ip_len;
+ uint32 ip_src;
+ uint32 ip_dst;
+};
+
+struct TcpHeader {
+ uint16 tcp_sport; /* source port */
+ uint16 tcp_dport; /* destination port */
+ uint32 tcp_seq; /* sequence number */
+ uint32 tcp_ack; /* acknoledgement number */
+ uint8 tcp_hl; /* header length (4 bits) */
+ uint8 tcp_flags; /* flags */
+ uint16 tcp_win; /* advertized window size */
+ uint16 tcp_xsum; /* checksum */
+ uint16 tcp_urp; /* urgent pointer */
+};
+
+
+
+struct IcmpHeader {
+ uint8 icmp_type; /* ICMP message type */
+ uint8 icmp_code; /* Message code */
+ uint16 icmp_xsum; /* checksum */
+ uint16 icmp_unused; /* unused field */
+ uint16 icmp_mtu; /* MTU of limiting interface */
+};
+
+struct IPPacket {
+ struct IpHeader *ip;
+ struct TcpHeader *tcp;
+};
+
+struct ICMPUnreachableErrorPacket {
+ struct IpHeader ip;
+ struct IcmpHeader icmp;
+ struct IpHeader off_ip;
+ /* 8-first bytes of TCP header */
+ uint16 tcp_sport;
+ uint16 tcp_dport;
+ uint32 tcp_seqno;
+};
+
+struct ICMPTimeExceededErrorPacket {
+ struct IpHeader ip;
+ struct IcmpHeader icmp;
+ struct IpHeader off_ip;
+ /* 8-first bytes of Tcpheader */
+ uint16 tcp_sport;
+ uint16 tcp_dport;
+ uint32 tcp_seqno;
+};
+
+char *InetAddress(uint32 addr);
+
+uint16 InetChecksum(uint16 *ip_addr, uint16 *tcp_addr, uint16 ip_len, uint16 tcp_len);
+
+void PrintTcpPacket(struct IPPacket *p);
+void PrintICMPUnreachableErrorPacket(struct ICMPUnreachableErrorPacket *p);
+
+void WriteIPPacket(struct IPPacket *p,
+ uint32 src,
+ uint32 dst,
+ uint16 sport,
+ uint16 dport,
+ uint32 seq,
+ uint32 ack,
+ uint8 flags,
+ uint16 win,
+ uint16 urp,
+ uint16 datalen,
+ uint16 ip_optlen,
+ uint16 optlen,
+ uint8 iptos,
+ uint8 u4tf);
+
+void ReadIPPacket(struct IPPacket *p, uint32 *src, uint32 *dst,
+ uint16 *sport, uint16 *dport, uint32 *seq, uint32 *ack,
+ uint8 *flags, uint16 *win, uint16 *urp, uint16 *datalen,
+ uint16 *ip_optlen, uint16 *optlen);
+
+void StorePacket (struct IPPacket *p);
+
+struct IPPacket *FindHeaderBoundaries(char *p);
+
+struct IPPacket *AllocateIPPacket(int ip_optlen, int tcp_optlen, int datalen, char *str);
+
+void FreeIPPacket(struct IPPacket **pkt_p);
+
+#endif /* _INET_H_ */
diff --git a/network_cmds/ecnprobe/session.c b/network_cmds/ecnprobe/session.c
new file mode 100644
index 0000000..5ca97d8
--- /dev/null
+++ b/network_cmds/ecnprobe/session.c
@@ -0,0 +1,785 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+#include "ecn.h"
+#include <errno.h>
+
+struct TcpSession session;
+
+int EstablishSession(uint32 sourceAddress,
+ uint16 sourcePort,
+ uint32 targetAddress,
+ uint16 targetPort,
+ int ip_optlen, // AM: add support for IP options
+ char *ip_opt, // AM: add support for IP options
+ int mss,
+ int optlen,
+ char *opt,
+ int maxwin,
+ int maxpkts,
+ uint8 iptos,
+ uint8 tcp_flags) // AM: Add a tcp_flags parameter
+{
+
+ int rawSocket;
+
+ struct IPPacket *p = NULL;
+ struct IPPacket *synPacket;
+ char *read_packet;
+ struct pcap_pkthdr pi;
+ int synAckReceived = 0;
+ int numRetransmits = 0;
+ double timeoutTime;
+ double ts1 = 0, ts2;
+ int flag = 1;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In EstablishSession...\n");
+ }
+
+ arc4random_stir();
+
+ session.src = sourceAddress;
+ session.sport = sourcePort;
+ session.dst = targetAddress;
+ session.dport = targetPort;
+ session.rcv_wnd = maxwin * mss;
+ session.snd_nxt = arc4random(); /* random initial sequence number */
+ session.iss = session.snd_nxt;
+ session.rcv_nxt = 0;
+ session.irs = 0;
+ session.mss = mss ;
+ session.maxseqseen = 0 ;
+ session.epochTime = GetTime();
+ session.maxpkts = maxpkts;
+ session.num_unwanted_drops = 0;
+ session.num_reordered = 0;
+ session.num_rtos = 0;
+ session.num_dup_acks = 0;
+ session.num_pkts_0_dup_acks = 0;
+ session.num_pkts_1_dup_acks = 0;
+ session.num_pkts_2_dup_acks = 0;
+ session.num_pkts_3_dup_acks = 0;
+ session.num_pkts_4_or_more_dup_acks = 0;
+ session.num_dupack_ret = 0;
+ session.num_reord_ret = 0;
+ session.num_reordered = 0;
+ session.num_dup_transmissions = 0;
+ session.ignore_result = 0;
+ session.curr_ttl = 0;
+
+ if ((session.mtu < 1) || (session.mtu > 1460)) {
+ session.mtu = 1500;
+ }
+
+ if (session.verbose) {
+ printf("session.MTU = %d\n", session.mtu);
+ }
+
+ if ((session.dataRcvd = (uint8 *)calloc(sizeof(uint8), mss * session.maxpkts)) == NULL) {
+ perror("ERROR: no memmory to store data:\n");
+ printf("RETURN CODE: %d\n", ERR_MEM_ALLOC);
+ Quit(ERR_MEM_ALLOC);
+ }
+
+ /* Now open a raw socket for sending our "fake" TCP segments */
+ if ((rawSocket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
+ perror("ERROR: couldn't open socket:");
+ printf("RETURN CODE: %d\n", ERR_SOCKET_OPEN);
+ Quit(ERR_SOCKET_OPEN);
+ }
+
+ if (setsockopt(rawSocket, IPPROTO_IP, IP_HDRINCL, (char *)&flag,sizeof(flag)) < 0) {
+ perror("ERROR: couldn't set raw socket options:");
+ printf("RETURN CODE: %d\n", ERR_SOCKOPT);
+ Quit(ERR_SOCKOPT);
+ }
+
+ session.socket = rawSocket;
+
+ /* Allocate SYN packet */
+ synPacket = AllocateIPPacket(ip_optlen, optlen, 0, "EstablishSession (SYN)");
+
+ /* Copy IP options at the end of IpHeader structure - New */
+ if (ip_optlen > 0) {
+ memcpy((char *)synPacket->ip + sizeof(struct IpHeader), ip_opt, ip_optlen);
+ }
+
+ /* Copy TCP options at the end of TcpHeader structure - New */
+ if (optlen > 0) {
+ memcpy((char *)synPacket->tcp + sizeof(struct TcpHeader), opt, optlen);
+ }
+
+ /* Send SYN Pkt */
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
+ TCPFLAGS_SYN | tcp_flags,
+ ip_optlen, /* IP opt len */
+ optlen, /* TCP opt len */
+ iptos);
+
+ timeoutTime = GetTime() + SYNTIMEOUT;
+
+ /*
+ * Wait for SYN/ACK and retransmit SYN if appropriate
+ * not great, but it gets the job done
+ */
+
+ while(!synAckReceived && numRetransmits < MAXSYNRETRANSMITS) {
+
+ while(GetTime() < timeoutTime) {
+
+ /* Have we captured any packets? */
+
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /* Received a packet from us to them */
+ if (INSESSION(p, session.src, session.sport, session.dst, session.dport)) {
+
+ /* Is it a SYN? */
+ if (p->tcp->tcp_flags & TCPFLAGS_SYN) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit\n");
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+
+ ts1 = pi.ts.tv_sec + (double)pi.ts.tv_usec/1000000.0;
+ session.totSeenSent ++ ;
+
+ }
+
+ free(p);
+ continue;
+
+
+ }
+
+ if (INSESSION(p, session.dst, session.dport, session.src, session.sport)) {
+
+ /* Is it a SYN/ACK? */
+ if (p->tcp->tcp_flags & (TCPFLAGS_SYN | TCPFLAGS_ACK)) {
+
+ timeoutTime = GetTime(); /* force exit */
+ synAckReceived++;
+ ts2 = pi.ts.tv_sec + (double)pi.ts.tv_usec/1000000.0;
+ session.rtt = ts2 - ts1 ;
+
+ if (numRetransmits > 0) {
+ session.rtt_unreliable = 1;
+ printf("##### Unreliable\n"); /* ACK for which SYN? */
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd:\n");
+ PrintTcpPacket(p);
+ printf("Connection setup took %d ms\n",(int)((ts2 - ts1) * 1000.0));
+ }
+
+ StorePacket(p);
+
+ /* Save ttl for,admittedly poor,indications of reverse route change */
+ session.ttl = p->ip->ip_ttl;
+ session.snd_wnd = ntohl(p->tcp->tcp_win);
+ session.totRcvd++;
+
+ free(p);
+ break ;
+
+ }
+
+ }
+
+ free(p->ip);
+ free(p->tcp);
+ free(p);
+
+ }
+
+ }
+
+ if (!synAckReceived) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("SYN timeout. Retransmitting\n");
+ }
+
+ SendSessionPacket(synPacket,
+ sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + optlen,
+ TCPFLAGS_SYN | tcp_flags,
+ ip_optlen, /* IP opt len */
+ optlen, /* TCP opt len */
+ iptos);
+
+ timeoutTime = GetTime() + SYNTIMEOUT;
+ numRetransmits++;
+ }
+ }
+
+ if (numRetransmits >= MAXSYNRETRANSMITS) {
+ printf("ERROR: Could not establish contact after %d retries\nRETURN CODE: %d\n",
+ numRetransmits, NO_CONNECTION);
+ Quit(NO_CONNECTION);
+ }
+
+ /* Update session variables */
+ session.irs = ntohl(p->tcp->tcp_seq);
+ session.dataRcvd[0] = 1 ;
+ session.rcv_nxt = session.irs + 1; /* SYN/ACK takes up a byte of seq space */
+ session.snd_nxt = session.iss + 1; /* SYN takes up a byte of seq space */
+ session.snd_una = session.iss + 1;
+ session.maxseqseen = ntohl(p->tcp->tcp_seq);
+
+ session.initSession = 1;
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("src = %s:%d (%u)\n", InetAddress(session.src), session.sport, session.iss);
+ printf("dst = %s:%d (%u)\n", InetAddress(session.dst), session.dport, session.irs);
+ }
+
+ free(synPacket->ip);
+ free(synPacket->tcp);
+ free(synPacket);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of EstablishSession...\n");
+ }
+
+ session.start_time = GetTime();
+
+ return 1;
+
+}
+
+int PrepareRequest(char *data, char *filename)
+{
+
+ char h1[] = "GET ";
+ char h2[] = " HTTP/1.1";
+ char h3[] = "Host: ";
+ char h4[] = "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11; DigExt; TBIT)";
+ char h5[] = "Accept: */*";
+
+ /* New */
+ char h7[] = "Pragma: no-cache";
+ char h8[] = "Cache-control: no-chache";
+ char deffile[] = DEFAULT_FILENAME;
+
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In PrepareRequest...\n");
+ }
+
+ if (filename == NULL) {
+ filename = deffile;
+ }
+
+
+ if (strlen(session.targetName) > 0) {
+
+ sprintf(data,
+
+ "%s/%s %s\r\n%s\r\n%s\r\n%s\r\n%s\r\n%s%s\r\n\r\n",
+ h1,
+ filename,
+ h2,
+ h4,
+ h7,
+ h8,
+ h5,
+ h3,
+ session.targetName);
+ }else {
+
+ sprintf(data,
+ "%s%s%s\r\n%s\r\n\r\n",
+ h1,
+ filename,
+ h2,
+ h4);
+ }
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out PrepareRequest...\n");
+ }
+
+ return ((int)strlen(data));
+
+}
+
+
+void SendRequest(char *filename, void (*ackData)(struct IPPacket *p))
+{
+
+ struct IPPacket *p, *datapkt;
+ struct pcap_pkthdr pi;
+ char *read_packet;
+ int i;
+ int sendflag = 1;
+ double startTime = 0;
+ char *dataptr;
+ char data[MAXREQUESTLEN];
+ int datalen;
+ int ipsz;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendRequest...\n");
+ }
+
+ datalen = PrepareRequest(data, filename);
+
+ ipsz = sizeof(struct IpHeader) + sizeof(struct TcpHeader) + datalen + 1;
+
+ /* Allocate space for IP data packet */
+ datapkt = AllocateIPPacket(0, 0, datalen + 1, "SendRequest (Data)");
+
+ dataptr = (char *)datapkt->tcp + sizeof(struct TcpHeader);
+ memcpy((void *)dataptr, (void *)data, datalen);
+
+ /* Send the data packet. Try to "achieve" reliability by sending the
+ * packet upto 5 times, wating for 2 seconds between packets (BAD
+ * busy-wait loop)
+ */
+
+ i = 0 ;
+ while(1) {
+
+ if (sendflag == 1) {
+
+ SendSessionPacket(datapkt,
+ ipsz,
+ TCPFLAGS_PSH | TCPFLAGS_ACK,
+ 0, /* ip opt len */
+ 0, /* tcp opt len */
+ 0); /* tos */
+
+ startTime = GetTime();
+ sendflag = 0 ;
+ i++;
+
+ }
+
+ /* Check if we have received any packets */
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * packet that we sent?
+ */
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport) &&
+ (p->tcp->tcp_flags == (TCPFLAGS_PSH | TCPFLAGS_ACK)) &&
+ (ntohl(p->tcp->tcp_seq) == session.snd_nxt) &&
+ (ntohl(p->tcp->tcp_ack) <= session.rcv_nxt)) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit %d\n", i);
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+
+ free(p);
+
+ //session.snd_nxt += datalen + 1;
+ session.totSeenSent++;
+ continue;
+
+ }
+ /*
+ * packet from them?
+ */
+
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_seq) == session.rcv_nxt) &&
+ (ntohl(p->tcp->tcp_ack) >= session.snd_una)) {
+
+
+ session.snd_una = ntohl(p->tcp->tcp_ack);
+
+ if (p->ip->ip_ttl != session.ttl) {
+ printf("#### WARNING: route may have changed (ttl was %d, is %d).\n",
+ session.ttl, p->ip->ip_ttl);
+ session.ttl = p->ip->ip_ttl;
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd %d\n", i);
+ PrintTcpPacket(p);
+ }
+
+ StorePacket(p);
+ session.totRcvd ++;
+ session.snd_nxt += datalen + 1;
+
+ /* if the packet also contains data, receive it and send an ack if needed */
+ (*ackData)(p);
+
+ free(p);
+ break;
+
+ }
+
+ free(p);
+
+ }
+
+ if ((GetTime() - startTime >= REXMITDELAY) &&
+ (sendflag == 0) && (i < MAXDATARETRANSMITS)) {
+ sendflag = 1 ;
+ }
+
+ if (i >= MAXDATARETRANSMITS) {
+ printf ("ERROR: sent request 5 times without response\nRETURN CODE: %d\n",
+ SEND_REQUEST_FAILED);
+ Quit(SEND_REQUEST_FAILED);
+ }
+
+ }
+
+ free(datapkt->ip);
+ free(datapkt->tcp);
+ free(datapkt);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendRequest...\n");
+ }
+}
+
+void SendSessionPacket(struct IPPacket *p,
+ uint16 ip_len, uint8 tcp_flags, uint16 ip_optlen, uint16 optlen,
+ uint8 iptos)
+{
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendSessionPacket...\n");
+ }
+ WriteIPPacket(p,
+ session.src, session.dst, session.sport, session.dport,
+ session.snd_nxt, session.rcv_nxt, tcp_flags,
+ session.rcv_wnd, 0,
+ (ip_len - sizeof(struct IpHeader) - ip_optlen - sizeof(struct TcpHeader) - optlen),
+ ip_optlen, optlen, iptos, 0);
+
+
+ /* Store packet here rather than in rcvData() because otherwise some
+ * ACKs may not be accounted for upon receiving reordered packets */
+
+ StorePacket(p);
+
+ SendPkt(p,
+ ip_len, /* Total IP datagram size */
+ ip_optlen, /* ip options len */
+ optlen); /* tcp options len */
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendSessionPacket...\n");
+ }
+
+}
+
+
+void SendICMPReply(struct IPPacket *p)
+{
+
+ struct ICMPUnreachableErrorPacket *icmp_pkt;
+ int icmpsz;
+
+ struct IpHeader *ip = p->ip;
+ struct TcpHeader *tcp = p->tcp;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendICMPReply...\n");
+ }
+
+ icmpsz = sizeof(struct ICMPUnreachableErrorPacket);
+ if ((icmp_pkt = (struct ICMPUnreachableErrorPacket *)calloc(icmpsz + 1, 1)) == NULL) {
+ perror("ERROR: no space for ICMP packet:");
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ /* Fill IP Header of ICMP packet */
+ bzero((char *)icmp_pkt, sizeof(struct ICMPUnreachableErrorPacket));
+ icmp_pkt->ip.ip_src = ip->ip_dst;
+ icmp_pkt->ip.ip_dst = ip->ip_src;
+ icmp_pkt->ip.ip_p = IPPROTOCOL_ICMP;
+ icmp_pkt->ip.ip_xsum =
+ htons((uint16)(sizeof(struct IcmpHeader) + sizeof(struct IpHeader) + sizeof(struct IpHeader) + 8)); /* pseudo hdr */
+ icmp_pkt->ip.ip_ttl = 60;
+ icmp_pkt->ip.ip_tos = 0x00;
+ icmp_pkt->ip.ip_vhl = 0x45;
+#ifdef __FreeBSD__
+ icmp_pkt->ip.ip_off = IP_DF;
+ icmp_pkt->ip.ip_len = (uint16)(sizeof(struct ICMPUnreachableErrorPacket));
+#else /* __FreeBSD__ */
+ icmp_pkt->ip.ip_off = htons(IP_DF);
+ icmp_pkt->ip.ip_len = htons((uint16)((sizeof (struct ICMPUnreachableErrorPacket) + 8 + 1)));
+#endif /* __FreeBSD__ */
+
+ /* Fill ICMP header */
+ icmp_pkt->icmp.icmp_type = 0x3;
+ icmp_pkt->icmp.icmp_code = 0x4;
+ icmp_pkt->icmp.icmp_xsum = 0;
+ icmp_pkt->icmp.icmp_unused = 0;
+ icmp_pkt->icmp.icmp_mtu = htons(session.mtu);
+
+ /* Fill in ip header of offending packet */
+ icmp_pkt->off_ip.ip_src = ip->ip_src;
+ icmp_pkt->off_ip.ip_dst = ip->ip_dst;
+ icmp_pkt->off_ip.ip_p = ip->ip_p;
+ icmp_pkt->off_ip.ip_xsum = ip->ip_xsum;
+ icmp_pkt->off_ip.ip_ttl = ip->ip_ttl;
+ icmp_pkt->off_ip.ip_tos = ip->ip_tos;
+ icmp_pkt->off_ip.ip_vhl = ip->ip_vhl;
+ icmp_pkt->off_ip.ip_p = ip->ip_p;
+#ifdef __FreeBSD__
+ icmp_pkt->off_ip.ip_off = ntohs(ip->ip_off);
+ icmp_pkt->off_ip.ip_len = ntohs(ip->ip_len);
+#else /* __FreeBSD__ */
+ icmp_pkt->off_ip.ip_off = ip->ip_off;
+ icmp_pkt->off_ip.ip_len = ip->ip_len;
+#endif /* __FreeBSD__ */
+
+ icmp_pkt->tcp_sport = tcp->tcp_sport;
+ icmp_pkt->tcp_dport = tcp->tcp_dport;
+ icmp_pkt->tcp_seqno = (uint32)tcp->tcp_seq;
+
+ icmp_pkt->icmp.icmp_xsum = InetChecksum((uint16 *)(&(icmp_pkt->icmp)), NULL,
+ (uint16)(sizeof(struct IcmpHeader) + sizeof(struct IpHeader) + 8), 0);
+
+ if (session.verbose) {
+ printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ printf("TCP Packet: %lu\n", sizeof(struct IPPacket));
+ PrintTcpPacket(p);
+ printf("ICMP Packet: %lu\n", sizeof(struct ICMPUnreachableErrorPacket));
+ PrintICMPUnreachableErrorPacket(icmp_pkt);
+ printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
+ }
+
+ SendICMPPkt(icmp_pkt, sizeof(struct ICMPUnreachableErrorPacket));
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out of SendICMPReply...\n");
+ }
+
+}
+
+void SendPkt(struct IPPacket *p, uint16 ip_len, int ip_optlen,
+ int tcp_optlen) {
+ int nbytes, datalen;
+ struct sockaddr_in sockAddr;
+ char *assembled_pkt;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In SendPkt...\n");
+ }
+ /* Assemble contiguos packet to be sent */
+ if ((assembled_pkt = (char *)calloc(1, ip_len)) == NULL) {
+ printf("SendPkt: Cannot allocate memory for assembled packet\n");
+ Quit(ERR_MEM_ALLOC);
+ }
+ /* Copy IP Header and options, if any */
+ memcpy((char *)assembled_pkt, (char *)(p->ip),
+ sizeof(struct IpHeader) + ip_optlen);
+
+ /* Copy TCP Header and options, if any */
+ memcpy((char *)(assembled_pkt + sizeof(struct IpHeader) + ip_optlen),
+ (char *)(p->tcp),
+ sizeof(struct TcpHeader) + tcp_optlen);
+
+ /* Copy data bytes, if any */
+ datalen = ip_len - ((sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + tcp_optlen));
+
+ if (datalen > 0) {
+ memcpy((char *)assembled_pkt + sizeof(struct IpHeader) + ip_optlen + sizeof(struct TcpHeader) + tcp_optlen,
+ (char *)p->tcp + sizeof(struct TcpHeader) + tcp_optlen, datalen);
+ }
+
+
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = session.dst;
+
+ if ((nbytes = (int)sendto(session.socket,
+ (char *)assembled_pkt,
+ ip_len,
+ 0,
+ (struct sockaddr *)&sockAddr,
+ sizeof(sockAddr))) < ip_len) {
+ printf("#### WARNING: only sent %d of %d bytes\n", nbytes, ip_len);
+ perror("here");
+
+ }
+
+ session.totSent++;
+
+ free(assembled_pkt);
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("Out SendPkt...\n");
+ }
+
+}
+
+
+
+void SendICMPPkt(struct ICMPUnreachableErrorPacket *p, uint16 len) {
+
+ ssize_t nbytes;
+ struct sockaddr_in sockAddr;
+
+ sockAddr.sin_family = AF_INET;
+ sockAddr.sin_addr.s_addr = session.dst;
+
+ nbytes = sendto(session.socket, (char *)p, len, 0,
+ (struct sockaddr *)&sockAddr,
+ sizeof(sockAddr));
+
+ if (nbytes < len) {
+ printf("#### WARNING: only sent %zd of %d (errno: %d) bytes\n",
+ nbytes, len, errno);
+ perror("here");
+ }
+
+ session.totSent++ ;
+
+}
+
+void rcvData (void (*ackData)(struct IPPacket *p))
+{
+
+ struct pcap_pkthdr pi;
+ struct IPPacket *p;
+ char *read_packet;
+ double startTime = GetTime () ;
+
+ if (session.debug >= SESSION_DEBUG_HIGH) {
+ printf("In rcvData...\n");
+ }
+
+ while (1) {
+
+ if ((GetTime() - startTime) > (MAXDATARETRANSMITS * REXMITDELAY)) {
+ printf ("ERROR: no Data received for %f seconds\nRETURN CODE: %d\n",
+ (MAXDATARETRANSMITS*REXMITDELAY), NO_DATA_RCVD);
+ Quit(NO_DATA_RCVD) ;
+ }
+
+ if ((read_packet = (char *)CaptureGetPacket(&pi)) != NULL) {
+
+ p = (struct IPPacket *)FindHeaderBoundaries(read_packet);
+
+ /*
+ * Packet that we sent?
+ */
+
+ if (INSESSION(p,session.src,session.sport,session.dst,session.dport) &&
+ ((p->tcp->tcp_flags & TCPFLAGS_ACK) || (p->tcp->tcp_flags & TCPFLAGS_FIN)) &&
+ (ntohl(p->tcp->tcp_seq) == session.snd_nxt) &&
+ (ntohl(p->tcp->tcp_ack) <= session.rcv_nxt)) {
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("xmit:\n");
+ PrintTcpPacket(p);
+ }
+
+ session.totSeenSent++ ;
+
+ free(p);
+ continue;
+
+ }
+
+ /*
+ * Data that we were expecting?
+ */
+
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) &&
+ (p->tcp->tcp_flags & TCPFLAGS_ACK) &&
+ (ntohl(p->tcp->tcp_ack) >= session.snd_una)) {
+
+ if (p->ip->ip_ttl != session.ttl) {
+ printf("#### WARNING: route may have changed (ttl was %d, is %d).\n",
+ session.ttl, p->ip->ip_ttl);
+ session.ttl = p->ip->ip_ttl;
+ }
+
+ if (session.debug >= SESSION_DEBUG_LOW) {
+ printf("rcvd: \n");
+ PrintTcpPacket(p);
+ }
+
+ session.totRcvd++ ;
+ startTime = GetTime () ;
+ StorePacket(p);
+
+ /* if the packet also contains data, receive it, and send an ack if needed */
+ ECNAckData(p);
+
+ free(p);
+ continue ;
+
+ } else {
+
+ free(p);
+
+ }
+ }
+ }
+}
+
+
diff --git a/network_cmds/ecnprobe/session.h b/network_cmds/ecnprobe/session.h
new file mode 100644
index 0000000..bff3296
--- /dev/null
+++ b/network_cmds/ecnprobe/session.h
@@ -0,0 +1,183 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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.
+*/
+
+#define MAXREQUESTLEN 1000
+
+#define SESSION_DEBUG_LOW 1
+#define SESSION_DEBUG_MEDIUM 2
+#define SESSION_DEBUG_HIGH 3
+
+struct TcpSession {
+
+ /* target name, as specified by the user */
+ char targetName[MAXHOSTNAMELEN];
+
+ /* DNS name of hosts */
+ char targetHostName[MAXHOSTNAMELEN];
+ char sourceHostName[MAXHOSTNAMELEN];
+
+ /* raw socket we use to send on */
+ int socket;
+
+ /* connection endpoint identifiers */
+ u_int32_t src;
+ u_int16_t sport;
+ u_int32_t dst;
+ u_int16_t dport;
+
+ /* sender info, from RFC 793 */
+ u_int32_t iss; // initial send sequence
+ u_int32_t snd_una; // sequence numbers of unacknowledged data
+ u_int32_t snd_nxt; // sequence number to be sent next
+ u_int16_t snd_wnd;
+ u_int16_t sndmss;
+
+ /* Receiver info */
+ u_int32_t irs;
+ u_int32_t rcv_wnd;
+ u_int32_t rcv_nxt;
+ u_int32_t maxseqseen;
+ u_int16_t mss;
+
+ /* timing */
+ double rtt;
+ u_int8_t ttl;
+ double start_time;
+
+ /* data buffer */
+ u_int8_t *dataRcvd ;
+
+ /* basic results */
+ int totSent;
+ int totRcvd;
+ int totSeenSent;
+ int totDataPktsRcvd;
+ int totOutofSeq;
+ int hsz;
+
+ /* basic control*/
+ int epochTime;
+ int debug;
+ int verbose;
+ int initSession;
+ int initCapture;
+ int initFirewall;
+ int firewall_rule_number;
+ char *filename;
+ int maxpkts;
+
+ /* New loss-rate parameters */
+ float loss_rate;
+ float prop_delay;
+
+ /* results are suspect for various reasons */
+ int rtt_unreliable;
+ int ignore_result;
+
+ /* Drops and reordering startistics */
+ int num_reordered;
+ int num_unwanted_drops;
+ int num_rtos;
+ int num_reord_ret;
+ int num_dup_transmissions;
+ int num_dup_acks;
+ int num_pkts_0_dup_acks;
+ int num_pkts_1_dup_acks;
+ int num_pkts_2_dup_acks;
+ int num_pkts_3_dup_acks;
+ int num_pkts_4_or_more_dup_acks;
+ int num_dupack_ret;
+
+ /* For PMTUD test */
+ int mtu;
+
+ /* For ByteCounting test */
+ int bytecounting_type;
+ int ack_bytes; /* How many bytes covered per ACK */
+ int ack_rate; /* ACK [every | every other | every third |...] packet */
+
+ /* For WindowScale Option test */
+ u_int8_t receiving_shift_count;
+ u_int8_t sending_shift_count;
+
+ /* For MidBoxTTL test */
+ int curr_ttl;
+
+ int dont_send_reset;
+};
+
+//void SendSessionPacket(struct IPPacket *packet,
+void SendSessionPacket(struct IPPacket *packet,
+ u_int16_t ip_len, /* Total size of IP datagram */
+ u_int8_t tcp_flags,
+ u_int16_t ip_optlen, /* IP options len - New */
+ u_int16_t optlen, /* TCP options len */
+ u_int8_t iptos);
+
+void SendICMPReply(struct IPPacket *p);
+
+void SendPkt(struct IPPacket *p, u_int16_t ip_len, int ip_optlen, int tcp_optlen);
+
+void SendICMPPkt(struct ICMPUnreachableErrorPacket *p, u_int16_t ip_len);
+
+void StorePacket (struct IPPacket *p);
+
+int EstablishSession(u_int32_t sourceAddress, \
+ u_int16_t sourcePort, \
+ u_int32_t targetAddress,
+ u_int16_t targetPort, \
+ int ip_optlen,\
+ char *ip_opt,\
+ int mss,
+ int optlen,
+ char *opt, \
+ int maxwin,
+ int maxpkts,
+ u_int8_t iptos,
+ u_int8_t tcp_flags);
+
+void rcvData (void (*ackData)(struct IPPacket *p));
+
+void SendRequest(char *filename, void (*ackData)(struct IPPacket *p));
+
+int PrepareRequest(char *data, char *filename) ;
diff --git a/network_cmds/ecnprobe/support.c b/network_cmds/ecnprobe/support.c
new file mode 100644
index 0000000..2cdb405
--- /dev/null
+++ b/network_cmds/ecnprobe/support.c
@@ -0,0 +1,246 @@
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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/time.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "base.h"
+#include "inet.h"
+#include "session.h"
+#include "capture.h"
+#include "support.h"
+
+extern struct TcpSession session;
+
+void SendReset()
+{
+ struct IPPacket *p;
+ int i;
+
+ if (session.dont_send_reset)
+ return;
+
+ if ((p = (struct IPPacket *)calloc(1, sizeof(struct IPPacket))) == NULL) {
+ perror("ERROR: Could not allocate RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ if ((p->ip = (struct IpHeader *)calloc(1, sizeof(struct IpHeader))) == NULL) {
+ perror("ERROR: Could not allocate IP Header for RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ if ((p->tcp = (struct TcpHeader *)calloc(1, sizeof(struct TcpHeader))) == NULL) {
+ perror("ERROR: Could not allocate TCP Header for RST packet:") ;
+ Quit(ERR_MEM_ALLOC) ;
+ }
+
+ for (i = 0; i < MAXRESETRETRANSMITS; i++) {
+ SendSessionPacket(p,
+ //sizeof(struct IPPacket),
+ sizeof(struct IpHeader) + sizeof(struct TcpHeader),
+ TCPFLAGS_RST,
+ 0,
+ 0,
+ 0);
+ }
+
+/* free(p->ip);
+ free(p->tcp);
+ free(p);
+*/
+
+}
+
+#if 0
+/* make a clean exit on interrupts */
+void SigHandle (int signo)
+{
+ Cleanup () ;
+ fflush(stdout);
+ fflush(stderr);
+ exit(-1);
+}
+
+
+void Cleanup()
+{
+
+ char ipfw_rule[100];
+ int r;
+
+ /* If a firewall rule has been installed then remove it */
+ if (session.initFirewall > 0) {
+
+#ifdef linux
+#define IP_FW_DEL (IP_FW_DELETE)
+#endif /* linux */
+
+ sprintf(ipfw_rule, "ipfw del 00%d", session.firewall_rule_number);
+ r = system(ipfw_rule);
+
+ }
+
+ if (session.initSession > 0) {
+
+ SendReset();
+ shutdown(session.socket,2);
+
+ }
+
+ if (session.initCapture > 0) {
+ CaptureEnd();
+ }
+
+}
+
+void Quit(int how)
+{
+
+ Cleanup();
+ fflush(stdout);
+ fflush(stderr);
+ exit(how);
+
+}
+#endif /* 0 */
+
+double GetTime()
+{
+ struct timeval tv;
+ struct timezone tz;
+ double postEpochSecs;
+
+ if (gettimeofday(&tv, &tz) < 0) {
+ perror("GetTime");
+ exit(-1);
+ }
+
+ postEpochSecs = (double)tv.tv_sec + ((double)tv.tv_usec/(double)1000000.0);
+ return postEpochSecs;
+}
+
+double GetTimeMicroSeconds()
+{
+ struct timeval tv;
+ struct timezone tz;
+ double postEpochMicroSecs;
+
+ if (gettimeofday(&tv, &tz) < 0) {
+ perror("GetTimeMicroSeconds");
+ exit(-1);
+ }
+
+ postEpochMicroSecs = (double)tv.tv_sec * 1000000 + (double)tv.tv_usec;
+ return postEpochMicroSecs;
+
+}
+
+void PrintTimeStamp(struct timeval *ts)
+{
+ (void)printf("%02d:%02d:%02d.%06u ",
+ (unsigned int)ts->tv_sec / 3600,
+ ((unsigned int)ts->tv_sec % 3600) / 60,
+ (unsigned int)ts->tv_sec % 60, (unsigned int)ts->tv_usec);
+}
+
+void processBadPacket (struct IPPacket *p)
+{
+
+ if (session.debug == SESSION_DEBUG_HIGH) {
+ printf("In ProcessBadPacket...\n");
+ }
+ /*
+ * reset? the other guy does not like us?
+ */
+ if (INSESSION(p,session.dst,session.dport,session.src,session.sport) && (p->tcp->tcp_flags & TCPFLAGS_RST)) {
+ printf("ERROR: EARLY_RST.\nRETURN CODE: %d\n", EARLY_RST);
+ Quit(EARLY_RST);
+ }
+ /*
+ * some other packet between us that is none of the above
+ */
+ if (INSESSION(p, session.src, session.sport, session.dst, session.dport) ||
+ INSESSION(p, session.dst, session.dport, session.src, session.sport)) {
+
+ printf("ERROR: Unexpected packet\nRETURN CODE: %d\n", UNEXPECTED_PKT);
+ printf("Expecting:\n");
+ printf("\tsrc = %s:%d (seq=%u, ack=%u)\n",
+ InetAddress(session.src), session.sport,
+ session.snd_nxt-session.iss,
+ session.rcv_nxt-session.irs);
+ printf("\tdst = %s:%d (seq=%u, ack=%u)\n",
+ InetAddress(session.dst),session.dport,
+ session.rcv_nxt-session.irs, session.snd_una-session.iss);
+ printf("Received:\n\t");
+ PrintTcpPacket(p);
+ printf ("session.snd_nxt=%d, session.rcv_nxt=%d, session.snd_una=%d\n",
+ session.snd_nxt-session.iss, session.rcv_nxt-session.irs, session.snd_una-session.iss);
+ Quit(UNEXPECTED_PKT);
+ }
+ /*
+ * none of the above,
+ * so we must be seeing packets
+ * from some other flow!
+ */
+ else {
+ printf("ERRROR: Received packet from different flow\nRETURN CODE: %d\n", DIFF_FLOW);
+ PrintTcpPacket(p);
+ Quit(DIFF_FLOW) ;
+ }
+
+ if (session.debug == SESSION_DEBUG_HIGH) {
+ printf("Out ProcessBadPacket...\n");
+ }
+}
+
+void busy_wait (double wait)
+{
+ double now = GetTime();
+ double x = now ;
+ while ((x - now) < wait) {
+ x = GetTime();
+ }
+}
diff --git a/network_cmds/ecnprobe/support.h b/network_cmds/ecnprobe/support.h
new file mode 100644
index 0000000..94be2e5
--- /dev/null
+++ b/network_cmds/ecnprobe/support.h
@@ -0,0 +1,132 @@
+
+/*
+ Copyright (c) 2000
+ International Computer Science Institute
+ All rights reserved.
+
+ This file may contain software code originally developed for the
+ Sting project. The Sting software carries the following copyright:
+
+ Copyright (c) 1998, 1999
+ Stefan Savage and the University of Washington.
+ 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 acknowledgment:
+ This product includes software developed by ACIRI, the AT&T
+ Center for Internet Research at ICSI (the International Computer
+ Science Institute). This product may also include software developed
+ by Stefan Savage at the University of Washington.
+ 4. The names of ACIRI, ICSI, Stefan Savage and University of Washington
+ may not be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY ICSI 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 ICSI 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 <signal.h>
+
+#define MAXRESETRETRANSMITS (3)
+/*#define INSESSION(p, src, sport, dst, dport) \
+ (((p)->ip.ip_src == (src)) && ((p)->ip.ip_dst == (dst)) && \
+ ((p)->ip.ip_p == IPPROTOCOL_TCP) && \
+ ((p)->tcp.tcp_sport == htons(sport)) && \
+ ((p)->tcp.tcp_dport == htons(dport)))*/
+
+#define INSESSION(p, src, sport, dst, dport) \
+ (((p)->ip->ip_src == (src)) && ((p)->ip->ip_dst == (dst)) && \
+ ((p)->ip->ip_p == IPPROTOCOL_TCP) && \
+ ((p)->tcp->tcp_sport == htons(sport)) && \
+ ((p)->tcp->tcp_dport == htons(dport)))
+
+#define SEQ_LT(a,b) ((int)((a)-(b)) < 0)
+#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0)
+#define SEQ_GT(a,b) ((int)((a)-(b)) > 0)
+#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0)
+
+#define DEFAULT_TARGETPORT (80)
+#define DEFAULT_MSS 1360
+#define DEFAULT_MTU 1500
+#define RTT_TO_MULT 5
+#define PLOTDIFF 0.00009
+
+/* Response codes */
+#define FAIL -1
+#define SUCCESS 0
+#define NO_TARGET_CANON_INFO 1
+#define NO_LOCAL_HOSTNAME 2
+#define NO_SRC_CANON_INFO 3
+#define NO_SESSION_ESTABLISH 4
+#define MSS_TOO_SMALL 5
+#define BAD_ARGS 6
+#define FIREWALL_ERR 7
+#define ERR_SOCKET_OPEN 8
+#define ERR_SOCKOPT 9
+#define ERR_MEM_ALLOC 10
+#define NO_CONNECTION 11
+#define MSS_ERR 12
+#define BUFFER_OVERFLOW 13
+#define UNWANTED_PKT_DROP 14
+#define EARLY_RST 15
+#define UNEXPECTED_PKT 16
+#define DIFF_FLOW 17
+#define ERR_CHECKSUM 18
+#define NOT_ENOUGH_PKTS 19
+#define BAD_OPT_LEN 20
+#define TOO_MANY_PKTS 21
+#define NO_DATA_RCVD 22
+#define NO_TRGET_SPECIFIED 23
+#define BAD_OPTIONS 24
+#define TOO_MANY_TIMEOUTS 25
+#define TOO_MANY_RXMTS 26
+#define NO_SACK 27
+#define ERR_IN_SB_CALC 28
+#define TOO_MANY_HOLES 29
+#define TOO_MANY_DROPS 30
+#define UNWANTED_PKT_REORDER 31
+#define NO_PMTUD_ENABLED 32
+#define UNKNOWN_BEHAVIOR 33
+#define NO_SYNACK_RCVD 34
+#define SEND_REQUEST_FAILED 35
+#define PKT_SIZE_CHANGED 36
+#define ECN_SYN_DROP 37
+
+#define DEFAULT_FILENAME "/"
+
+#define RTT_TO_MULT 5
+#define SYNTIMEOUT (2.0)
+#define REXMITDELAY (2.0)
+#define MAXSYNRETRANSMITS (6)
+#define MAXDATARETRANSMITS (6)
+
+/* HTTP Response Codes */
+#define HTTP_OK "200"
+
+
+void SendReset();
+void SigHandle (int signo);
+void Cleanup();
+void Quit(int how);
+double GetTime();
+double GetTimeMicroSeconds();
+void PrintTimeStamp(struct timeval *ts);
+void processBadPacket (struct IPPacket *p);
+void busy_wait (double wait);
diff --git a/network_cmds/frame_delay/frame_delay.8 b/network_cmds/frame_delay/frame_delay.8
new file mode 100644
index 0000000..0f454d5
--- /dev/null
+++ b/network_cmds/frame_delay/frame_delay.8
@@ -0,0 +1,45 @@
+.Dd October 12, 2015
+.Dt FRAME_DELAY 8
+.Os Darwin
+.Sh NAME
+.Nm frame_delay
+.Nd Utility to measure TCP/UDP frame delay
+
+.Sh DESCRIPTION
+.Pp
+The
+.Nm
+utility is designed to measure the effect of latency on
+delivery of evenly spaced TCP/UDP frames. This can be latency induced
+due to buffering or protocol stack or network drivers.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl m
+Server/Client mode. Should be "server" or "client".
+.It Fl t
+TCP/UDP frame. Should be either "tcp" or "udp".
+.It Fl i
+(Client Only) Server ip address.
+.It Fl p
+Port number.
+.It Fl n
+Number of frames.
+.It Fl f
+Frame size.
+.It Fl d
+(Client only) Delay traffic class. Pick one from {BK_SYS, BK, BE, RD, QAM, AV, RV, VI, VO, CTL}.
+.El
+
+.Sh EXAMPLES
+.Pp
+Setup TCP server:
+.Dl "frame_delay -m server -t tcp -p 10010 -n 10 -f 1000"
+.Pp
+Setup corresponding TCP client:
+.Dl "frame_delay -m client -t tcp -i 127.0.0.1 -p 10010 -n 10 -f 1000 -d 2000 -k RD"
+
+.Sh AUTHORS
+.An Padma Bhooma ,
+.An Kang Sun ,
+.An Vincent Lubet . \ No newline at end of file
diff --git a/network_cmds/frame_delay/frame_delay.c b/network_cmds/frame_delay/frame_delay.c
new file mode 100644
index 0000000..37a58b7
--- /dev/null
+++ b/network_cmds/frame_delay/frame_delay.c
@@ -0,0 +1,595 @@
+/*
+ * Copyright (c) 2009-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Usage for frame_delay
+ *
+ * Server
+ * ./frame_delay -m server -t <tcp/udp> -p <port> -n <num_frames> -f <frame_size>
+ *
+ * Client
+ * ./frame_delay -m client -t <tcp/udp> -i <srv_ipv4_add> -p <srv_port> -n <num_frames> -f <frame_size> -d <delay_ms> -k <traffic_class>
+ */
+
+/*
+ * TODO list :
+ * 1. UDP fragmentation and reassembly
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+
+/* Server Static variable */
+static int so, srv_so;
+static int srv_port = 0;
+static struct sockaddr_in laddr, dst_addr;
+/* Client Static variable */
+static struct sockaddr_in srv_addr;
+static uint32_t tc = 0;
+/* Usage */
+void ErrorUsage(void);
+/* str2svc */
+uint32_t str2svc(const char *str);
+/* Show Stastics */
+void ShowStastics(int64_t *DiffsBuf, int num_frames);
+/* Returns difference between two timevals in microseconds */
+int64_t time_diff(struct timeval *b, struct timeval *a);
+/* tcp server */
+void tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf);
+/* udp server */
+void udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf);
+/* tcp server */
+void tcpClient(int num_frames, int frame_size,
+ const char *buf, struct timespec sleep_time);
+/* udp server */
+void udpClient(int num_frames, int frame_size,
+ const char *buf, struct timespec sleep_time);
+
+/* Main function */
+int
+main(int argc, char *argv[])
+{
+ int num_frames = 0, frame_size = 0, delay_ms = 0, rc = 0;
+ char *buf = NULL, ch, *type = NULL, *mode = NULL, *ip_addr = NULL;
+ int64_t *DiffsBuf;
+ struct timespec sleep_time;
+
+ while ((ch = getopt(argc, argv, "m:p:f:n:t:d:i:k:")) != -1) {
+ switch (ch) {
+ case 'm': {
+ mode = optarg;
+ break;
+ }
+ case 'p': {
+ srv_port = atoi(optarg);
+ break;
+ }
+ case 'f' : {
+ frame_size = atoi(optarg);
+ break;
+ }
+ case 'n' : {
+ num_frames = atoi(optarg);
+ break;
+ }
+ case 'i': {
+ ip_addr = optarg;
+ bzero(&srv_addr, sizeof(srv_addr));
+ rc = inet_aton(optarg, &srv_addr.sin_addr);
+ if (rc == 0) {
+ perror("inet_ntoa failed");
+ exit(1);
+ }
+ }
+ case 'd': {
+ delay_ms = atoi(optarg);
+ break;
+ }
+ case 't' : {
+ type = optarg;
+ break;
+ }
+ case 'k': {
+ tc = str2svc(optarg);
+ break;
+ }
+ default: {
+ printf("Invalid option: %c\n", ch);
+ ErrorUsage();
+ }
+ }
+ }
+ /* General check for both server and client */
+ if (srv_port <= 0 || frame_size <= 0 || num_frames <= 0 || !mode || !type) {
+ ErrorUsage();
+ }
+ if ( strcmp(type, "tcp") != 0 && strcmp(type, "udp") != 0 ) {
+ ErrorUsage();
+ }
+ /* Allocate memory for buf */
+ buf = calloc(1, frame_size);
+ if (buf == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if ( strcmp(mode, "server") == 0 ) {
+ /* Server */
+ printf("<LOG> : Start %s server on port %d with expected frame size of %d\n",
+ type, srv_port, frame_size);
+ DiffsBuf = (int64_t *)calloc(num_frames, sizeof(int64_t));
+ if (DiffsBuf == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if( strcmp(type, "tcp") == 0) {
+ /* tcpServer */
+ tcpServer(frame_size, num_frames, buf, DiffsBuf);
+ } else {
+ /* updServer */
+ udpServer(frame_size, num_frames, buf, DiffsBuf);
+ }
+ }
+ else if ( strcmp(mode, "client") == 0 ){
+ if ( !ip_addr || (tc > 0 && (tc < SO_TC_BK_SYS || tc > SO_TC_CTL)) ){
+ ErrorUsage();
+ }
+ /* Client */
+ printf("<LOG> : Start sending %d %s frames to %s:%d with a frame size of %d\n",
+ num_frames, type, ip_addr, srv_port, frame_size);
+ /* Resolving sleep time bug : delay_ms should just be calculated once */
+ bzero(&sleep_time, sizeof(sleep_time));
+ while (delay_ms >= 1000) {
+ sleep_time.tv_sec++;
+ delay_ms -= 1000;
+ }
+ sleep_time.tv_nsec = delay_ms * 1000 * 1000;
+ if( strcmp(type, "tcp") == 0) {
+ /* Call TCP client */
+ tcpClient(num_frames, frame_size, buf, sleep_time);
+ } else {
+ /* Call UDP client */
+ udpClient(num_frames, frame_size, buf, sleep_time);
+ }
+ } else {
+ ErrorUsage();
+ }
+}
+
+/* Error usage */
+void
+ErrorUsage(void) {
+ printf("Correct Usage");
+ printf("Server : frame_delay -m server -t <tcp/udp> -p <port> -n <num_frames> -f <frame_size>\n");
+ printf("Client : frame_delay -m client -t <tcp/udp> -i <srv_ipv4_add> -p <srv_port> -n <num_frames> -f <frame_size> -d <delay_ms> -k <traffic_class>\n");
+ exit(1);
+}
+
+/* str2svc */
+uint32_t
+str2svc(const char *str)
+{
+ uint32_t svc;
+ char *endptr;
+
+ if (str == NULL || *str == '\0')
+ svc = UINT32_MAX;
+ else if (strcasecmp(str, "BK_SYS") == 0)
+ return SO_TC_BK_SYS;
+ else if (strcasecmp(str, "BK") == 0)
+ return SO_TC_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return SO_TC_BE;
+ else if (strcasecmp(str, "RD") == 0)
+ return SO_TC_RD;
+ else if (strcasecmp(str, "OAM") == 0)
+ return SO_TC_OAM;
+ else if (strcasecmp(str, "AV") == 0)
+ return SO_TC_AV;
+ else if (strcasecmp(str, "RV") == 0)
+ return SO_TC_RV;
+ else if (strcasecmp(str, "VI") == 0)
+ return SO_TC_VI;
+ else if (strcasecmp(str, "VO") == 0)
+ return SO_TC_VO;
+ else if (strcasecmp(str, "CTL") == 0)
+ return SO_TC_CTL;
+ else {
+ svc = (uint32_t)strtoul(str, &endptr, 0);
+ if (*endptr != '\0')
+ svc = UINT32_MAX;
+ }
+ return (svc);
+}
+
+/* Show Stastics */
+void
+ShowStastics(int64_t *DiffsBuf, int num_frames) {
+ int i = 0;
+ int64_t sum = 0, mean = 0;
+
+ /* Mean */
+ while(i < num_frames)
+ sum += DiffsBuf[i++];
+ mean = sum / num_frames;
+ printf("<LOG> : Mean: %.2f usecs\n", sum / (double)num_frames);
+ /* Popular Standard Deviation */
+ i = 0;
+ sum = 0;
+ while(i < num_frames) {
+ sum += (DiffsBuf[i]-mean)*(DiffsBuf[i]-mean);
+ i++;
+ }
+ printf("<LOG> : Popular Standard Deviation: %.2f usecs\n",
+ sqrt(sum/(double)num_frames));
+}
+
+/* Returns difference between two timevals in microseconds */
+int64_t
+time_diff(struct timeval *b, struct timeval *a)
+{
+ int64_t usecs;
+ usecs = (a->tv_sec - b->tv_sec) * 1000 * 1000;
+ usecs += (int64_t)(a->tv_usec - b->tv_usec);
+ return(usecs);
+}
+
+/* Server */
+
+/* tcp server */
+void
+tcpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) {
+ int rc = 0, i = 0, ignore_count = 0;
+ uint32_t dst_len = 0;
+ struct timeval before, after;
+ ssize_t bytes;
+ int64_t usecs;
+ /* New change from Padama */
+ uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0;
+ uint64_t min_variation = 0, max_variation = 0, avg_variation = 0;
+
+ printf("<LOG> : TCP Server\n");
+ so = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (so == -1) {
+ perror("failed to create socket");
+ exit(1);
+ }
+ bzero(&laddr, sizeof(laddr));
+ laddr.sin_family = AF_INET;
+ laddr.sin_port = htons(srv_port);
+ rc = bind(so, (const struct sockaddr *)&laddr, sizeof(laddr));
+ if (rc != 0) {
+ perror("failed to bind");
+ exit(1);
+ }
+ rc = listen(so, 10);
+ if (rc != 0) {
+ perror("failed to listen");
+ exit(1);
+ }
+ srv_so = accept(so, (struct sockaddr *)&dst_addr, &dst_len);
+ if (srv_so == -1) {
+ perror("failed to accept");
+ exit(1);
+ }
+ while (1) {
+ if ( i == num_frames ) {
+ printf("<LOG> : Completed\n");
+ break;
+ }
+ printf("<LOG> : Waiting for receiving\n");
+ bzero(&before, sizeof(before));
+ bzero(&after, sizeof(after));
+ rc = gettimeofday(&before, NULL);
+ if (rc == -1) {
+ perror("gettimeofday failed");
+ exit(1);
+ }
+ bytes = recv(srv_so, buf, frame_size, MSG_WAITALL);
+ if (bytes == -1) {
+ perror("recv failed");
+ exit(1);
+ }
+ else if (bytes > 0 && bytes != frame_size) {
+ printf("Client exited\n");
+ printf("Didn't recv the complete frame, bytes %ld\n",
+ bytes);
+ exit(1);
+ }
+ else if (bytes == 0) {
+ break;
+ }
+ rc = gettimeofday(&after, NULL);
+ if (rc == -1) {
+ perror("gettimeofday failed");
+ exit(1);
+ }
+ cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec;
+ memcpy((void *)&frame_ts, buf, sizeof(frame_ts));
+ if (prev_frame_ts > 0) {
+ int64_t d_variation = 0;
+ d_variation = (int64_t)((cur_recv - prev_recv) -
+ (frame_ts - prev_frame_ts));
+ /* printf("Frame %u ts %llu d_variation %lld usecs\n",
+ i, frame_ts, d_variation);*/
+ if (d_variation > 0) {
+ if (min_variation == 0)
+ min_variation = d_variation;
+ else
+ min_variation = ((min_variation <= d_variation) ?
+ min_variation : d_variation);
+ max_variation = ((max_variation >= d_variation) ?
+ max_variation : d_variation);
+ avg_variation += d_variation;
+ } else {
+ ignore_count++;
+ }
+ }
+ prev_recv = cur_recv;
+ prev_frame_ts = frame_ts;
+ ++i;
+ /* Compute the time differenc */
+ usecs = time_diff(&before, &after);
+ DiffsBuf[i] = usecs;
+ printf("<LOG> : Frame %d received after %lld usecs\n", i, usecs);
+ }
+ if (i != ignore_count)
+ avg_variation = avg_variation / (i - ignore_count);
+ else
+ avg_variation = 0;
+
+ printf("<LOG> : Received frames: %u\n", i);
+ printf("<LOG> : Ignored frames: %u\n", ignore_count);
+ printf("<LOG> : Minimum delay variation: %llu usecs\n", min_variation);
+ printf("<LOG> : Maximum delay variation: %llu usecs\n", max_variation);
+ printf("<LOG> : Average delay variation: %llu usecs\n", avg_variation);
+ ShowStastics(DiffsBuf, num_frames);
+}
+
+/* udp server */
+void
+udpServer(int frame_size, int num_frames, char *buf, int64_t *DiffsBuf) {
+ int rc = 0, i = 0, ignore_count = 0;
+ uint32_t dst_len = 0;
+ ssize_t bytes;
+ struct timeval before, after;
+ int64_t usecs;
+ /* New change from Padama */
+ uint64_t prev_frame_ts = 0, prev_recv = 0, frame_ts = 0, cur_recv = 0;
+ uint64_t min_variation = 0, max_variation = 0, avg_variation = 0;
+
+ printf("<LOG> : UDP Server\n");
+ so = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (so == -1) {
+ perror("failed to create socket");
+ exit(1);
+ }
+ bzero(&laddr,sizeof(laddr));
+ laddr.sin_family = AF_INET;
+ laddr.sin_addr.s_addr=htonl(INADDR_ANY);
+ laddr.sin_port=htons(srv_port);
+ rc = bind(so, (struct sockaddr *)&laddr,sizeof(laddr));
+ if (rc != 0) {
+ perror("failed to bind");
+ exit(1);
+ }
+ while (1) {
+ if ( i == num_frames ) {
+ printf("<LOG> : Completed\n");
+ break;
+ }
+ printf("<LOG> : Waiting for receiving\n");
+ bzero(&before, sizeof(before));
+ bzero(&after, sizeof(after));
+ rc = gettimeofday(&before, NULL);
+ if (rc == -1) {
+ perror("gettimeofday failed");
+ exit(1);
+ }
+ bytes = recvfrom(so, buf, frame_size, 0, (struct sockaddr *)&dst_addr, &dst_len);
+ if (bytes == -1) {
+ perror("recv failed");
+ exit(1);
+ }
+ else if (bytes > 0 && bytes != frame_size) {
+ printf("Client exited\n");
+ printf("Didn't recv the complete frame, bytes %ld\n",
+ bytes);
+ exit(1);
+ }
+ else if (bytes == 0) {
+ break;
+ }
+ rc = gettimeofday(&after, NULL);
+ if (rc == -1) {
+ perror("gettimeofday failed");
+ exit(1);
+ }
+ cur_recv = after.tv_sec * 1000 * 1000 + after.tv_usec;
+ memcpy((void *)&frame_ts, buf, sizeof(frame_ts));
+ if (prev_frame_ts > 0) {
+ int64_t d_variation = 0;
+
+ d_variation = (int64_t)((cur_recv - prev_recv) -
+ (frame_ts - prev_frame_ts));
+ /* printf("Frame %u ts %llu d_variation %lld usecs\n",
+ i, frame_ts, d_variation);*/
+ if (d_variation > 0) {
+ if (min_variation == 0)
+ min_variation = d_variation;
+ else
+ min_variation = ((min_variation <= d_variation) ?
+ min_variation : d_variation);
+ max_variation = ((max_variation >= d_variation) ?
+ max_variation : d_variation);
+ avg_variation += d_variation;
+ } else {
+ ignore_count++;
+ }
+ }
+ prev_recv = cur_recv;
+ prev_frame_ts = frame_ts;
+ ++i;
+ /* Compute the time differenc */
+ usecs = time_diff(&before, &after);
+ DiffsBuf[i] = usecs;
+ printf("<LOG> : Frame %d received after %lld usecs\n", i, usecs);
+ }
+ if (i != ignore_count)
+ avg_variation = avg_variation / (i - ignore_count);
+ else
+ avg_variation = 0;
+ printf("<LOG> : Received frames: %u\n", i);
+ printf("<LOG> : Ignored frames: %u\n", ignore_count);
+ printf("<LOG> : Minimum delay variation: %llu usecs\n", min_variation);
+ printf("<LOG> : Maximum delay variation: %llu usecs\n", max_variation);
+ printf("<LOG> : Average delay variation: %llu usecs\n", avg_variation);
+ ShowStastics(DiffsBuf, num_frames);
+}
+
+/* Client */
+void
+tcpClient(int num_frames, int frame_size,
+ const char *buf, struct timespec sleep_time){
+ int rc = 0, i = 0;
+ ssize_t bytes;
+
+ printf("<LOG> : TCP Client\n");
+ so = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ if (so <= 0) {
+ perror("creating socket failed");
+ exit(1);
+ }
+ srv_addr.sin_port = htons(srv_port);
+ srv_addr.sin_len = sizeof(srv_addr);
+ srv_addr.sin_family = AF_INET;
+ rc = connect(so, (const struct sockaddr *)&srv_addr,
+ sizeof(srv_addr));
+ if (rc != 0) {
+ perror("connect failed");
+ exit(1);
+ }
+ if (tc > 0) {
+ rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc,
+ sizeof(tc));
+ if (rc == -1) {
+ perror("failed to set traffic class");
+ exit(1);
+ }
+ }
+ for (i = 0; i < num_frames; ++i) {
+ struct timeval fts;
+ uint64_t frame_ts;
+ /* Add a timestamp to the frame */
+ rc = gettimeofday(&fts, NULL);
+ if (rc == -1) {
+ perror("faile to get time of day");
+ exit(1);
+ }
+ frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec;
+ memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts));
+ bytes = send(so, buf, frame_size, 0);
+ if (bytes == -1) {
+ perror("send failed \n");
+ exit(1);
+ }
+ if (bytes != frame_size) {
+ printf("failed to send all bytes, sent %ld\n", bytes);
+ exit (1);
+ }
+ rc = nanosleep(&sleep_time, NULL);
+ if (rc == -1) {
+ perror("sleep failed");
+ exit(1);
+ }
+ printf("<LOG> : Sent %u frames as a whole\n", (i + 1));
+ }
+}
+
+void
+udpClient(int num_frames, int frame_size,
+ const char *buf, struct timespec sleep_time){
+ int rc = 0, i = 0;
+ ssize_t bytes;
+
+ printf("<LOG> : UDP Client\n");
+ so = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (so <= 0) {
+ perror("creating socket failed");
+ exit(1);
+ }
+ srv_addr.sin_port = htons(srv_port);
+ srv_addr.sin_len = sizeof(srv_addr);
+ srv_addr.sin_family = AF_INET;
+ if (tc > 0) {
+ rc = setsockopt(so, SOL_SOCKET, SO_TRAFFIC_CLASS, &tc,
+ sizeof(tc));
+ if (rc == -1) {
+ perror("failed to set traffic class");
+ exit(1);
+ }
+ }
+ for (i = 0; i < num_frames; ++i) {
+ struct timeval fts;
+ uint64_t frame_ts;
+ /* Add a timestamp to the frame */
+ rc = gettimeofday(&fts, NULL);
+ if (rc == -1) {
+ perror("faile to get time of day");
+ exit(1);
+ }
+ frame_ts = fts.tv_sec * 1000 * 1000 + fts.tv_usec;
+ memcpy((void *)buf, (const void *)&frame_ts, sizeof(frame_ts));
+ bytes = sendto(so, buf, frame_size, 0, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
+ if (bytes == -1) {
+ perror("send failed \n");
+ exit(1);
+ }
+ if (bytes != frame_size) {
+ printf("failed to send all bytes, sent %ld\n", bytes);
+ exit (1);
+ }
+ rc = nanosleep(&sleep_time, NULL);
+ if (rc == -1) {
+ perror("sleep failed");
+ exit(1);
+ }
+ printf("<LOG> : Sent %u frames as a whole\n", (i + 1));
+ }
+}
+
+
diff --git a/network_cmds/ifconfig.tproj/af_inet.c b/network_cmds/ifconfig.tproj/af_inet.c
new file mode 100644
index 0000000..621bd16
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/af_inet.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2009-2011, 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h> /* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "ifconfig.h"
+
+static struct ifaliasreq in_addreq;
+static struct ifreq in_ridreq;
+
+static void
+in_status(int s __unused, const struct ifaddrs *ifa)
+{
+ struct sockaddr_in *sin, null_sin;
+
+ memset(&null_sin, 0, sizeof(null_sin));
+
+ sin = (struct sockaddr_in *)ifa->ifa_addr;
+ if (sin == NULL)
+ return;
+
+ printf("\tinet %s ", inet_ntoa(sin->sin_addr));
+
+ if (ifa->ifa_flags & IFF_POINTOPOINT) {
+ sin = (struct sockaddr_in *)ifa->ifa_dstaddr;
+ if (sin == NULL)
+ sin = &null_sin;
+ printf("--> %s ", inet_ntoa(sin->sin_addr));
+ }
+
+ sin = (struct sockaddr_in *)ifa->ifa_netmask;
+ if (sin == NULL)
+ sin = &null_sin;
+ printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr));
+
+ if (ifa->ifa_flags & IFF_BROADCAST) {
+ sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
+ if (sin != NULL && sin->sin_addr.s_addr != 0)
+ printf("broadcast %s", inet_ntoa(sin->sin_addr));
+ }
+ putchar('\n');
+}
+
+#define SIN(x) ((struct sockaddr_in *) &(x))
+static struct sockaddr_in *sintab[] = {
+ SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
+ SIN(in_addreq.ifra_mask), SIN(in_addreq.ifra_broadaddr)
+};
+
+static void
+in_getaddr(const char *s, int which)
+{
+#ifndef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#endif /* MIN */
+ struct sockaddr_in *sin = sintab[which];
+ struct hostent *hp;
+ struct netent *np;
+
+ sin->sin_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin_family = AF_INET;
+
+ if (which == ADDR) {
+ char *p = NULL;
+
+ if((p = strrchr(s, '/')) != NULL) {
+ /* address is `name/masklen' */
+ int masklen;
+ int ret;
+ struct sockaddr_in *min = sintab[MASK];
+ *p = '\0';
+ ret = sscanf(p+1, "%u", &masklen);
+ if(ret != 1 || (masklen < 0 || masklen > 32)) {
+ *p = '/';
+ errx(1, "%s: bad value", s);
+ }
+ min->sin_len = sizeof(*min);
+ min->sin_addr.s_addr = htonl(~((1LL << (32 - masklen)) - 1) &
+ 0xffffffff);
+ }
+ }
+
+ if (inet_aton(s, &sin->sin_addr))
+ return;
+ if ((hp = gethostbyname(s)) != 0)
+ bcopy(hp->h_addr, (char *)&sin->sin_addr,
+ MIN(hp->h_length, sizeof(sin->sin_addr)));
+ else if ((np = getnetbyname(s)) != 0)
+ sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY);
+ else
+ errx(1, "%s: bad value", s);
+#undef MIN
+}
+
+static void
+in_status_tunnel(int s)
+{
+ char src[NI_MAXHOST];
+ char dst[NI_MAXHOST];
+ struct ifreq ifr;
+ const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0)
+ return;
+ if (sa->sa_family != AF_INET)
+ return;
+ if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0)
+ src[0] = '\0';
+
+ if (ioctl(s, SIOCGIFPDSTADDR, (caddr_t)&ifr) < 0)
+ return;
+ if (sa->sa_family != AF_INET)
+ return;
+ if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0)
+ dst[0] = '\0';
+
+ printf("\ttunnel inet %s --> %s\n", src, dst);
+}
+
+static void
+in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+ struct ifaliasreq addreq;
+
+ memset(&addreq, 0, sizeof(addreq));
+ strlcpy(addreq.ifra_name, name, sizeof(addreq.ifra_name));
+ memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+ memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len);
+
+ if (ioctl(s, SIOCSIFPHYADDR, &addreq) < 0)
+ warn("SIOCSIFPHYADDR");
+}
+
+static void
+in_set_router(int s, int enable)
+{
+ struct ifreq ifr;
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_intval = enable;
+
+ if (ioctl(s, SIOCSETROUTERMODE, &ifr) < 0)
+ warn("SIOCSETROUTERMODE");
+}
+
+static int
+routermode_from_string(char * str, int *mode_p)
+{
+ int success = 1;
+
+ if (strcasecmp(str, "enabled") == 0) {
+ *mode_p = 1;
+ } else if (strcasecmp(str, "disabled") == 0) {
+ *mode_p = 0;
+ } else {
+ success = 0;
+ }
+ return (success);
+}
+
+static const char *
+routermode_string(int mode)
+{
+ const char * str;
+
+ switch (mode) {
+ case 0:
+ str = "disabled";
+ break;
+ case 1:
+ str = "enabled";
+ break;
+ default:
+ str = "<unknown>";
+ break;
+ }
+ return str;
+}
+
+static int
+in_routermode(int s, int argc, char *const*argv)
+{
+ struct ifreq ifr;
+ int ret;
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (argc == 0) {
+ ret = 0;
+#ifndef SIOCGETROUTERMODE
+#define SIOCGETROUTERMODE _IOWR('i', 209, struct ifreq) /* get IPv4 router mode state */
+#endif /* SIOCGETROUTERMODE */
+ if (ioctl(s, SIOCGETROUTERMODE, &ifr) < 0) {
+ if (argv != NULL) {
+ warn("SIOCGETROUTERMODE");
+ }
+ } else {
+ /* argv is NULL if we're called from status() */
+ printf("%s%s\n",
+ (argv == NULL) ? "\troutermode4: " : "",
+ routermode_string(ifr.ifr_intval));
+ }
+ ret = 0;
+ } else {
+ int mode;
+
+ if (routermode_from_string(argv[0], &mode) == 0) {
+ errx(EXIT_FAILURE,
+ "mode '%s' invalid, must be one of "
+ "disabled or enabled",
+ argv[0]);
+ }
+ ifr.ifr_intval = mode;
+ if (ioctl(s, SIOCSETROUTERMODE, &ifr) < 0) {
+ warn("SIOCSETROUTERMODE");
+ }
+ ret = 1;
+ }
+ return ret;
+}
+
+static struct afswtch af_inet = {
+ .af_name = "inet",
+ .af_af = AF_INET,
+ .af_status = in_status,
+ .af_getaddr = in_getaddr,
+ .af_status_tunnel = in_status_tunnel,
+ .af_settunnel = in_set_tunnel,
+ .af_setrouter = in_set_router,
+ .af_routermode = in_routermode,
+ .af_difaddr = SIOCDIFADDR,
+ .af_aifaddr = SIOCAIFADDR,
+ .af_ridreq = &in_ridreq,
+ .af_addreq = &in_addreq,
+};
+
+static __constructor void
+inet_ctor(void)
+{
+ af_register(&af_inet);
+}
diff --git a/network_cmds/ifconfig.tproj/af_inet6.c b/network_cmds/ifconfig.tproj/af_inet6.c
new file mode 100644
index 0000000..c32c5c0
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/af_inet6.c
@@ -0,0 +1,753 @@
+/*
+ * Copyright (c) 2009-2017, 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+#include <arpa/inet.h>
+
+#include <netinet/in.h>
+#include <net/if_var.h> /* for struct ifaddr */
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
+
+#include "ifconfig.h"
+
+#define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
+ "\004IFDISABLED\005DONT_SET_IFROUTE\006PROXY_PREFIXES" \
+ "\007IGNORE_NA\010INSECURE\011REPLICATED\012DAD"
+
+static struct in6_ifreq in6_ridreq;
+static struct in6_aliasreq in6_addreq =
+ { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ 0,
+ { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
+static int ip6lifetime;
+
+static void in6_fillscopeid(struct sockaddr_in6 *sin6);
+static int prefix(void *, int);
+static char *sec2str(time_t);
+static int explicit_prefix = 0;
+
+static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
+
+static void
+setifprefixlen(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getprefix != NULL)
+ afp->af_getprefix(addr, MASK);
+ explicit_prefix = 1;
+}
+
+static void
+setnd6flags(const char *dummyaddr __unused, int d, int s,
+ const struct afswtch *afp)
+{
+ struct in6_ndireq nd;
+ int error;
+
+ memset(&nd, 0, sizeof(nd));
+ strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
+ error = ioctl(s, SIOCGIFINFO_IN6, &nd);
+ if (error) {
+ warn("ioctl(SIOCGIFINFO_IN6)");
+ return;
+ }
+ if (d < 0)
+ nd.ndi.flags &= ~(-d);
+ else
+ nd.ndi.flags |= d;
+ error = ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd);
+ if (error)
+ warn("ioctl(SIOCSIFINFO_FLAGS)");
+}
+
+static void
+setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
+ const struct afswtch *afp)
+{
+ if (afp->af_af != AF_INET6)
+ err(1, "address flags can be set only for inet6 addresses");
+
+ if (flag < 0)
+ in6_addreq.ifra_flags &= ~(-flag);
+ else
+ in6_addreq.ifra_flags |= flag;
+}
+
+static void
+setip6lifetime(const char *cmd, const char *val, int s,
+ const struct afswtch *afp)
+{
+ time_t newval, t;
+ char *ep;
+
+ t = time(NULL);
+ newval = (time_t)strtoul(val, &ep, 0);
+ if (val == ep)
+ errx(1, "invalid %s", cmd);
+ if (afp->af_af != AF_INET6)
+ errx(1, "%s not allowed for the AF", cmd);
+ if (strcmp(cmd, "vltime") == 0) {
+ in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
+ in6_addreq.ifra_lifetime.ia6t_vltime = newval;
+ } else if (strcmp(cmd, "pltime") == 0) {
+ in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
+ in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+ }
+}
+
+static void
+setip6pltime(const char *seconds, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ setip6lifetime("pltime", seconds, s, afp);
+}
+
+static void
+setip6vltime(const char *seconds, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ setip6lifetime("vltime", seconds, s, afp);
+}
+
+static void
+setip6eui64(const char *cmd, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ struct ifaddrs *ifap, *ifa;
+ const struct sockaddr_in6 *sin6 = NULL;
+ const struct in6_addr *lladdr = NULL;
+ struct in6_addr *in6;
+
+ if (afp->af_af != AF_INET6)
+ errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
+ in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
+ if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
+ errx(EXIT_FAILURE, "interface index is already filled");
+ if (getifaddrs(&ifap) != 0)
+ err(EXIT_FAILURE, "getifaddrs");
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family == AF_INET6 &&
+ strcmp(ifa->ifa_name, name) == 0) {
+ sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ lladdr = &sin6->sin6_addr;
+ break;
+ }
+ }
+ }
+ if (!lladdr)
+ errx(EXIT_FAILURE, "could not determine link local address");
+
+ memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
+
+ freeifaddrs(ifap);
+}
+
+static void
+in6_fillscopeid(struct sockaddr_in6 *sin6)
+{
+#if defined(__KAME__) && defined(KAME_SCOPEID)
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ sin6->sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
+ sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+}
+
+static void
+in6_status(int s __unused, const struct ifaddrs *ifa)
+{
+ struct sockaddr_in6 *sin, null_sin;
+ struct in6_ifreq ifr6;
+ int s6;
+ u_int32_t flags6;
+ struct in6_addrlifetime lifetime;
+ time_t t = time(NULL);
+ int error;
+ u_int32_t scopeid;
+
+ memset(&null_sin, 0, sizeof(null_sin));
+
+ sin = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (sin == NULL)
+ return;
+
+ strlcpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
+ if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warn("socket(AF_INET6,SOCK_DGRAM)");
+ return;
+ }
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ warn("ioctl(SIOCGIFAFLAG_IN6)");
+ close(s6);
+ return;
+ }
+ flags6 = ifr6.ifr_ifru.ifru_flags6;
+ memset(&lifetime, 0, sizeof(lifetime));
+ ifr6.ifr_addr = *sin;
+ if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
+ warn("ioctl(SIOCGIFALIFETIME_IN6)");
+ close(s6);
+ return;
+ }
+ lifetime = ifr6.ifr_ifru.ifru_lifetime;
+ close(s6);
+
+ /* XXX: embedded link local addr check */
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+ *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+ u_short index;
+
+ index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+ *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = ntohs(index);
+ }
+ scopeid = sin->sin6_scope_id;
+
+ error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
+ sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
+ if (error != 0)
+ inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+ sizeof(addr_buf));
+ printf("\tinet6 %s ", addr_buf);
+
+ if (ifa->ifa_flags & IFF_POINTOPOINT) {
+ sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
+ /*
+ * some of the interfaces do not have valid destination
+ * address.
+ */
+ if (sin != NULL && sin->sin6_family == AF_INET6) {
+ int error;
+
+ /* XXX: embedded link local addr check */
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
+ *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
+ u_short index;
+
+ index = *(u_short *)&sin->sin6_addr.s6_addr[2];
+ *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = ntohs(index);
+ }
+
+ error = getnameinfo((struct sockaddr *)sin,
+ sin->sin6_len, addr_buf,
+ sizeof(addr_buf), NULL, 0,
+ NI_NUMERICHOST);
+ if (error != 0)
+ inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
+ sizeof(addr_buf));
+ printf("--> %s ", addr_buf);
+ }
+ }
+
+ sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
+ if (sin == NULL)
+ sin = &null_sin;
+ printf("prefixlen %d ", prefix(&sin->sin6_addr,
+ sizeof(struct in6_addr)));
+
+ if ((flags6 & IN6_IFF_ANYCAST) != 0)
+ printf("anycast ");
+ if ((flags6 & IN6_IFF_TENTATIVE) != 0)
+ printf("tentative ");
+ if ((flags6 & IN6_IFF_OPTIMISTIC) != 0)
+ printf("optimistic ");
+ if ((flags6 & IN6_IFF_DUPLICATED) != 0)
+ printf("duplicated ");
+ if ((flags6 & IN6_IFF_DETACHED) != 0)
+ printf("detached ");
+ if ((flags6 & IN6_IFF_DEPRECATED) != 0)
+ printf("deprecated ");
+ if ((flags6 & IN6_IFF_AUTOCONF) != 0)
+ printf("autoconf ");
+ if ((flags6 & IN6_IFF_TEMPORARY) != 0)
+ printf("temporary ");
+ if ((flags6 & IN6_IFF_DYNAMIC) != 0)
+ printf("dynamic ");
+ if ((flags6 & IN6_IFF_SECURED) != 0)
+ printf("secured ");
+ if ((flags6 & IN6_IFF_CLAT46) != 0)
+ printf("clat46 ");
+
+ if (scopeid)
+ printf("scopeid 0x%x ", scopeid);
+
+ if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
+ printf("pltime ");
+ if (lifetime.ia6t_preferred) {
+ printf("%s ", lifetime.ia6t_preferred < t
+ ? "0" : sec2str(lifetime.ia6t_preferred - t));
+ } else
+ printf("infty ");
+
+ printf("vltime ");
+ if (lifetime.ia6t_expire) {
+ printf("%s ", lifetime.ia6t_expire < t
+ ? "0" : sec2str(lifetime.ia6t_expire - t));
+ } else
+ printf("infty ");
+ }
+
+ putchar('\n');
+}
+
+#define SIN6(x) ((struct sockaddr_in6 *) &(x))
+static struct sockaddr_in6 *sin6tab[] = {
+ SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
+ SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
+};
+
+static void
+in6_getprefix(const char *plen, int which)
+{
+ struct sockaddr_in6 *sin = sin6tab[which];
+ u_char *cp;
+ int len = atoi(plen);
+
+ if ((len < 0) || (len > 128))
+ errx(1, "%s: bad value", plen);
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+ if ((len == 0) || (len == 128)) {
+ memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
+ return;
+ }
+ memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
+ for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
+ *cp++ = 0xff;
+ *cp = 0xff << (8 - len);
+}
+
+static void
+in6_getaddr(const char *s, int which)
+{
+ struct sockaddr_in6 *sin = sin6tab[which];
+ struct addrinfo hints, *res;
+ int error = -1;
+
+ newaddr &= 1;
+
+ sin->sin6_len = sizeof(*sin);
+ if (which != MASK)
+ sin->sin6_family = AF_INET6;
+
+ if (which == ADDR) {
+ char *p = NULL;
+ if((p = strrchr(s, '/')) != NULL) {
+ *p = '\0';
+ in6_getprefix(p + 1, MASK);
+ explicit_prefix = 1;
+ }
+ }
+
+ if (sin->sin6_family == AF_INET6) {
+ bzero(&hints, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET6;
+ error = getaddrinfo(s, NULL, &hints, &res);
+ }
+ if (error != 0) {
+ if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
+ errx(1, "%s: bad value", s);
+ } else
+ bcopy(res->ai_addr, sin, res->ai_addrlen);
+}
+
+static int
+prefix(void *val, int size)
+{
+ u_char *name = (u_char *)val;
+ int byte, bit, plen = 0;
+
+ for (byte = 0; byte < size; byte++, plen += 8)
+ if (name[byte] != 0xff)
+ break;
+ if (byte == size)
+ return (plen);
+ for (bit = 7; bit != 0; bit--, plen++)
+ if (!(name[byte] & (1 << bit)))
+ break;
+ for (; bit != 0; bit--)
+ if (name[byte] & (1 << bit))
+ return(0);
+ byte++;
+ for (; byte < size; byte++)
+ if (name[byte])
+ return(0);
+ return (plen);
+}
+
+static char *
+sec2str(time_t total)
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ if (0) {
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+ } else
+ snprintf(result, sizeof(result), "%lu", (unsigned long)total);
+
+ return(result);
+}
+
+static void
+in6_postproc(int s, const struct afswtch *afp)
+{
+ if (explicit_prefix == 0) {
+ /* Aggregatable address architecture defines all prefixes
+ are 64. So, it is convenient to set prefixlen to 64 if
+ it is not specified. */
+ setifprefixlen("64", 0, s, afp);
+ /* in6_getprefix("64", MASK) if MASK is available here... */
+ }
+}
+
+static void
+in6_status_tunnel(int s)
+{
+ char src[NI_MAXHOST];
+ char dst[NI_MAXHOST];
+ struct in6_ifreq in6_ifr;
+ const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
+
+ memset(&in6_ifr, 0, sizeof(in6_ifr));
+ strlcpy(in6_ifr.ifr_name, name, sizeof(in6_ifr.ifr_name));
+
+ if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
+ return;
+ if (sa->sa_family != AF_INET6)
+ return;
+ in6_fillscopeid(&in6_ifr.ifr_addr);
+ if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
+ NI_NUMERICHOST) != 0)
+ src[0] = '\0';
+
+ if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
+ return;
+ if (sa->sa_family != AF_INET6)
+ return;
+ in6_fillscopeid(&in6_ifr.ifr_addr);
+ if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
+ NI_NUMERICHOST) != 0)
+ dst[0] = '\0';
+
+ printf("\ttunnel inet6 %s --> %s\n", src, dst);
+}
+
+static void
+nd6_status(int s)
+{
+ struct in6_ndireq nd;
+ int s6;
+ int error;
+
+ memset(&nd, 0, sizeof(nd));
+ strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
+ if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ if (errno != EPROTONOSUPPORT)
+ warn("socket(AF_INET6, SOCK_DGRAM)");
+ return;
+ }
+ error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
+ if (error) {
+ if (errno != EPFNOSUPPORT && errno != EINVAL)
+ warn("ioctl(SIOCGIFINFO_IN6)");
+ close(s6);
+ return;
+ }
+ close(s6);
+ if (nd.ndi.flags == 0)
+ return;
+ printb("\tnd6 options", (unsigned int)nd.ndi.flags, ND6BITS);
+ putchar('\n');
+}
+
+static void
+in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
+{
+ struct in6_aliasreq in6_addreq;
+
+ memset(&in6_addreq, 0, sizeof(in6_addreq));
+ strlcpy(in6_addreq.ifra_name, name, sizeof(in6_addreq.ifra_name));
+ memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
+ memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
+ dstres->ai_addr->sa_len);
+
+ if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
+ warn("SIOCSIFPHYADDR_IN6");
+}
+
+#ifndef IPV6_ROUTER_MODE_EXCLUSIVE
+#define IPV6_ROUTER_MODE_DISABLED 0
+#define IPV6_ROUTER_MODE_EXCLUSIVE 1
+#define IPV6_ROUTER_MODE_HYBRID 2
+#endif /* IPV6_ROUTER_MODE_EXCLUSIVE */
+
+static void
+in6_set_router(int s, int enable)
+{
+ struct ifreq ifr;
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_intval = (enable == 0)
+ ? IPV6_ROUTER_MODE_DISABLED
+ : IPV6_ROUTER_MODE_EXCLUSIVE;
+
+ if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0)
+ warn("SIOCSETROUTERMODE_IN6");
+}
+
+static int
+routermode_from_string(char * str, int *mode_p)
+{
+ int success = 1;
+
+ if (strcasecmp(str, "exclusive") == 0 ||
+ strcasecmp(str, "enabled") == 0) {
+ *mode_p = IPV6_ROUTER_MODE_EXCLUSIVE;
+ } else if (strcasecmp(str, "hybrid") == 0) {
+ *mode_p = IPV6_ROUTER_MODE_HYBRID;
+ } else if (strcasecmp(str, "disabled") == 0) {
+ *mode_p = IPV6_ROUTER_MODE_DISABLED;
+ } else {
+ success = 0;
+ }
+ return (success);
+}
+
+static const char *
+routermode_string(int mode)
+{
+ const char * str;
+
+ switch (mode) {
+ case IPV6_ROUTER_MODE_EXCLUSIVE:
+ str = "enabled";
+ break;
+ case IPV6_ROUTER_MODE_HYBRID:
+ str = "hybrid";
+ break;
+ case IPV6_ROUTER_MODE_DISABLED:
+ str = "disabled";
+ break;
+ default:
+ str = "<unknown>";
+ break;
+ }
+ return str;
+}
+
+static int
+in6_routermode(int s, int argc, char *const*argv)
+{
+ struct in6_ifreq ifr;
+ int ret;
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (argc == 0) {
+ ret = 0;
+#ifndef SIOCGETROUTERMODE_IN6
+#define SIOCGETROUTERMODE_IN6 _IOWR('i', 137, struct in6_ifreq)
+#endif /* SIOCGETROUTERMODE_IN6 */
+ if (ioctl(s, SIOCGETROUTERMODE_IN6, &ifr) < 0) {
+ if (argv != NULL) {
+ warn("SIOCGETROUTERMODE_IN6");
+ }
+ } else {
+ /* argv is NULL if we're called from status() */
+ printf("%s%s\n",
+ (argv == NULL) ? "\troutermode6: " : "",
+ routermode_string(ifr.ifr_intval));
+ }
+ ret = 0;
+ } else {
+ int mode;
+
+ if (routermode_from_string(argv[0], &mode) == 0) {
+ errx(EXIT_FAILURE,
+ "mode '%s' invalid, must be one of "
+ "disabled, exclusive, or hybrid",
+ argv[0]);
+ }
+ ifr.ifr_intval = mode;
+ if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0) {
+ warn("SIOCSETROUTERMODE_IN6");
+ }
+ ret = 1;
+ }
+ return ret;
+}
+
+static struct cmd inet6_cmds[] = {
+ DEF_CMD_ARG("prefixlen", setifprefixlen),
+ DEF_CMD("anycast", IN6_IFF_ANYCAST, setip6flags),
+ DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags),
+ DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags),
+ /* RFC 4429, section 3.1, says:
+ * "Optimistic DAD SHOULD NOT be used for manually entered
+ * addresses."
+ * it's not a MUST...
+ */
+ DEF_CMD("optimistic", IN6_IFF_OPTIMISTIC, setip6flags),
+ DEF_CMD("-optimistic", -IN6_IFF_OPTIMISTIC, setip6flags),
+ DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags),
+ DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
+ DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
+ DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
+ DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags),
+ DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags),
+ DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
+ DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags),
+ DEF_CMD("replicated", ND6_IFF_REPLICATED, setnd6flags),
+ DEF_CMD("-replicated", -ND6_IFF_REPLICATED, setnd6flags),
+ DEF_CMD("proxy_prefixes", ND6_IFF_PROXY_PREFIXES, setnd6flags),
+ DEF_CMD("-proxy_prefixes", -ND6_IFF_PROXY_PREFIXES, setnd6flags),
+ DEF_CMD("insecure", ND6_IFF_INSECURE, setnd6flags),
+ DEF_CMD("-insecure", -ND6_IFF_INSECURE, setnd6flags),
+ DEF_CMD_ARG("pltime", setip6pltime),
+ DEF_CMD_ARG("vltime", setip6vltime),
+ DEF_CMD("eui64", 0, setip6eui64),
+ DEF_CMD("secured", IN6_IFF_SECURED, setip6flags),
+ DEF_CMD("-secured", -IN6_IFF_SECURED, setip6flags),
+ DEF_CMD("dad", ND6_IFF_DAD, setnd6flags),
+ DEF_CMD("-dad", -ND6_IFF_DAD, setnd6flags),
+};
+
+static struct afswtch af_inet6 = {
+ .af_name = "inet6",
+ .af_af = AF_INET6,
+ .af_status = in6_status,
+ .af_getaddr = in6_getaddr,
+ .af_getprefix = in6_getprefix,
+ .af_other_status = nd6_status,
+ .af_postproc = in6_postproc,
+ .af_status_tunnel = in6_status_tunnel,
+ .af_settunnel = in6_set_tunnel,
+ .af_setrouter = in6_set_router,
+ .af_routermode = in6_routermode,
+ .af_difaddr = SIOCDIFADDR_IN6,
+ .af_aifaddr = SIOCAIFADDR_IN6,
+ .af_ridreq = &in6_ridreq,
+ .af_addreq = &in6_addreq,
+};
+
+static void
+in6_Lopt_cb(const char *optarg __unused)
+{
+ ip6lifetime++; /* print IPv6 address lifetime */
+}
+static struct option in6_Lopt = { "L", "[-L]", in6_Lopt_cb };
+
+static __constructor void
+inet6_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(inet6_cmds); i++)
+ cmd_register(&inet6_cmds[i]);
+ af_register(&af_inet6);
+ opt_register(&in6_Lopt);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/af_link.c b/network_cmds/ifconfig.tproj/af_link.c
new file mode 100644
index 0000000..ca9444c
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/af_link.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ifaddrs.h>
+
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+
+#include "ifconfig.h"
+
+static struct ifreq link_ridreq;
+
+static void
+link_status(int s __unused, const struct ifaddrs *ifa)
+{
+ /* XXX no const 'cuz LLADDR is defined wrong */
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
+
+ if (sdl != NULL && sdl->sdl_alen > 0) {
+#ifdef notyet
+ if (sdl->sdl_type == IFT_ETHER &&
+ sdl->sdl_alen == ETHER_ADDR_LEN)
+ printf("\tether %s\n",
+ ether_ntoa((struct ether_addr *)LLADDR(sdl)));
+ else {
+ int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+
+ printf("\tlladdr %s\n", link_ntoa(sdl) + n);
+ }
+#else
+ char *cp = (char *)LLADDR(sdl);
+ int n = sdl->sdl_alen;
+
+ if (sdl->sdl_type == IFT_ETHER)
+ printf ("\tether ");
+ else
+ printf ("\tlladdr ");
+ while (--n >= 0)
+ printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
+ putchar('\n');
+#endif
+ }
+}
+
+static void
+link_getaddr(const char *addr, int which)
+{
+ char *temp;
+ struct sockaddr_dl sdl;
+ struct sockaddr *sa = &link_ridreq.ifr_addr;
+ size_t slen = strlen(addr);
+
+ if (which != ADDR)
+ errx(1, "can't set link-level netmask or broadcast");
+ if ((temp = malloc(slen + 2)) == NULL)
+ errx(1, "malloc failed");
+ temp[0] = ':';
+ strlcpy(temp + 1, addr, slen + 1);
+ sdl.sdl_len = sizeof(sdl);
+ link_addr(temp, &sdl);
+ free(temp);
+ if (sdl.sdl_alen > sizeof(sa->sa_data))
+ errx(1, "malformed link-level address");
+ sa->sa_family = AF_LINK;
+ sa->sa_len = sdl.sdl_alen;
+ bcopy(LLADDR(&sdl), sa->sa_data, sdl.sdl_alen);
+}
+
+static struct afswtch af_link = {
+ .af_name = "link",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+static struct afswtch af_ether = {
+ .af_name = "ether",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+static struct afswtch af_lladdr = {
+ .af_name = "lladdr",
+ .af_af = AF_LINK,
+ .af_status = link_status,
+ .af_getaddr = link_getaddr,
+ .af_aifaddr = SIOCSIFLLADDR,
+ .af_addreq = &link_ridreq,
+};
+
+static __constructor void
+link_ctor(void)
+{
+ af_register(&af_link);
+ af_register(&af_ether);
+ af_register(&af_lladdr);
+}
diff --git a/network_cmds/ifconfig.tproj/if6lowpan.c b/network_cmds/ifconfig.tproj/if6lowpan.c
new file mode 100644
index 0000000..f0f4b2e
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/if6lowpan.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2017-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. 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 Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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 <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_6lowpan_var.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+#include <sys/cdefs.h>
+
+
+static boolean_t is_sixlowpan_inited = FALSE;
+static struct sixlowpanreq params;
+
+static int
+get6lowpan(int s, struct ifreq *ifr, struct sixlowpanreq *req)
+{
+ bzero((char *)req, sizeof(*req));
+ ifr->ifr_data = (caddr_t)req;
+ return ioctl(s, SIOCGIF6LOWPAN, (caddr_t)ifr);
+}
+
+static void
+sixlowpan_status(int s)
+{
+ struct sixlowpanreq req;
+
+ if (get6lowpan(s, &ifr, &req) != -1)
+ printf("\t6lowpan: parent interface: %s\n",
+ req.parent[0] == '\0' ?
+ "<none>" : req.parent);
+}
+
+
+static void
+set6lowpandev(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct sixlowpanreq req;
+
+ strlcpy(params.parent, val, sizeof(params.parent));
+ is_sixlowpan_inited = TRUE;
+ fprintf(stderr, "val %s\n", val);
+
+ strlcpy(req.parent, val, sizeof(req.parent));
+ ifr.ifr_data = (caddr_t) &req;
+ if (ioctl(s, SIOCSIF6LOWPAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIF6LOWPAN");
+}
+
+static void
+unset6lowpandev(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct sixlowpanreq req;
+
+ bzero((char *)&req, sizeof(req));
+ ifr.ifr_data = (caddr_t)&req;
+
+ if (ioctl(s, SIOCGIF6LOWPAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGIF6LOWPAN");
+
+ bzero((char *)&req, sizeof(req));
+ if (ioctl(s, SIOCSIF6LOWPAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIF6LOWPAN");
+}
+
+static void
+sixlowpan_create(const char *val, int d, int s, const struct afswtch *afp)
+{
+ strlcpy(params.parent, val, sizeof(params.parent));
+ is_sixlowpan_inited = TRUE;
+}
+
+static void
+sixlowpan_clone_cb(int s, void *arg)
+{
+ if (is_sixlowpan_inited == TRUE && params.parent[0] == '\0')
+ errx(1, "6lowpandev must be specified");
+}
+
+static struct cmd sixlowpan_cmds[] = {
+ DEF_CLONE_CMD_ARG("6lowpandev", sixlowpan_create),
+ DEF_CMD_OPTARG("6lowpansetdev", set6lowpandev),
+ DEF_CMD_OPTARG("6lowpanunsetdev", unset6lowpandev),
+};
+static struct afswtch af_6lowpan = {
+ .af_name = "af_6lowpan",
+ .af_af = AF_UNSPEC,
+ .af_other_status = sixlowpan_status,
+};
+
+static __constructor void
+sixlowpan_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(sixlowpan_cmds); i++)
+ cmd_register(&sixlowpan_cmds[i]);
+ af_register(&af_6lowpan);
+ callback_register(sixlowpan_clone_cb, NULL);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/ifbond.c b/network_cmds/ifconfig.tproj/ifbond.c
new file mode 100644
index 0000000..b8bcdfe
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifbond.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * ifbond.c
+ * - add and remove interfaces from a bond interface
+ */
+
+/*
+ * Modification History:
+ *
+ * July 14, 2004 Dieter Siegmund (dieter@apple.com)
+ * - created
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_bond_var.h>
+
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+extern int bond_details;
+
+#define EA_FORMAT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define EA_CH(e, i) ((u_char)((u_char *)(e))[(i)])
+#define EA_LIST(ea) EA_CH(ea,0),EA_CH(ea,1),EA_CH(ea,2),EA_CH(ea,3),EA_CH(ea,4),EA_CH(ea,5)
+
+static __inline__ const char *
+selected_state_string(u_char s)
+{
+ static const char * names[] = { "unselected", "selected", "standby" };
+
+ if (s <= IF_BOND_STATUS_SELECTED_STATE_STANDBY) {
+ return (names[s]);
+ }
+ return ("<unknown>");
+}
+
+static void
+bond_print_details(struct if_bond_status * ibs_p, int count)
+
+{
+ int i;
+ struct if_bond_status * scan_p = ibs_p;
+
+ for (i = 0; i < count; i++, scan_p++) {
+ struct if_bond_partner_state * ps;
+ ps = &scan_p->ibs_partner_state;
+ printf("\tbond interface: %s priority: 0x%04x "
+ "state: 0x%02x partner system: 0x%04x,"
+ EA_FORMAT " "
+ "key: 0x%04x port: 0x%04x priority: 0x%04x "
+ "state: 0x%02x\n",
+ scan_p->ibs_if_name, scan_p->ibs_port_priority,
+ scan_p->ibs_state, ps->ibps_system_priority,
+ EA_LIST(&ps->ibps_system), ps->ibps_key,
+ ps->ibps_port, ps->ibps_port_priority,
+ ps->ibps_state);
+ }
+ return;
+}
+
+void
+bond_status(int s)
+{
+ int i;
+ struct if_bond_req ibr;
+ struct if_bond_status * ibs_p;
+ struct if_bond_status_req * ibsr_p;
+ char mode_buf[16];
+ const char * mode_str;
+
+ bzero((char *)&ibr, sizeof(ibr));
+ ibr.ibr_op = IF_BOND_OP_GET_STATUS;
+ ibsr_p = &ibr.ibr_ibru.ibru_status;
+ ibsr_p->ibsr_version = IF_BOND_STATUS_REQ_VERSION;
+ ifr.ifr_data = (caddr_t)&ibr;
+
+ /* how many of them are there? */
+ if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
+ return;
+ }
+ switch (ibsr_p->ibsr_mode) {
+ case IF_BOND_MODE_LACP:
+ mode_str = "lacp";
+ break;
+ case IF_BOND_MODE_STATIC:
+ mode_str = "static";
+ break;
+ default:
+ snprintf(mode_buf, sizeof(mode_buf), "%d", ibsr_p->ibsr_mode);
+ mode_str = mode_buf;
+ break;
+ }
+ if (ibsr_p->ibsr_total == 0) {
+ if (bond_details) {
+ printf("\tbond mode: %s\n"
+ "\tbond key: 0x%04x interfaces: <none>",
+ mode_str, ibsr_p->ibsr_key);
+ }
+ else {
+ printf("\tbond interfaces: <none>\n");
+ }
+ return;
+ }
+ ibsr_p->ibsr_buffer
+ = (char *)malloc(sizeof(struct if_bond_status)
+ * ibsr_p->ibsr_total);
+ ibsr_p->ibsr_count = ibsr_p->ibsr_total;
+
+ /* get the list */
+ if (ioctl(s, SIOCGIFBOND, (caddr_t)&ifr) < 0) {
+ goto done;
+ }
+ if (ibsr_p->ibsr_total > 0) {
+ if (bond_details) {
+ printf("\tbond mode: %s\n"
+ "\tbond key: 0x%04x interfaces:",
+ mode_str, ibsr_p->ibsr_key);
+ }
+ else {
+ printf("\tbond interfaces:");
+ }
+ ibs_p = (struct if_bond_status *)ibsr_p->ibsr_buffer;
+ for (i = 0; i < ibsr_p->ibsr_total; i++, ibs_p++) {
+ printf(" %s", ibs_p->ibs_if_name);
+ if (bond_details) {
+ u_char s = ibs_p->ibs_selected_state;
+ printf(" (%s)", selected_state_string(s));
+ }
+ }
+ printf("\n");
+ if (bond_details) {
+ bond_print_details((struct if_bond_status *)
+ ibsr_p->ibsr_buffer,
+ ibsr_p->ibsr_total);
+ }
+ }
+ else if (bond_details) {
+ printf("\tbond mode: %s\n"
+ "\tbond key: 0x%04x interfaces: <none>\n",
+ mode_str, ibsr_p->ibsr_key);
+ }
+ else {
+ printf("\tbond interfaces: <none>\n");
+ }
+
+ done:
+ free(ibsr_p->ibsr_buffer);
+ return;
+}
+
+static
+DECL_CMD_FUNC(setbonddev, val, d)
+{
+ struct if_bond_req ibr;
+
+ bzero((char *)&ibr, sizeof(ibr));
+ if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
+ sizeof(ibr.ibr_ibru.ibru_if_name),
+ "%s", val) >= IFNAMSIZ) {
+ errx(1, "interface name too long");
+ }
+ ibr.ibr_op = IF_BOND_OP_ADD_INTERFACE;
+ ifr.ifr_data = (caddr_t)&ibr;
+ if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIFBOND add interface");
+
+ return;
+}
+
+static
+DECL_CMD_FUNC(unsetbonddev, val, d)
+{
+ struct if_bond_req ibr;
+
+ bzero((char *)&ibr, sizeof(ibr));
+ if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
+ sizeof(ibr.ibr_ibru.ibru_if_name),
+ "%s", val) >= IFNAMSIZ) {
+ errx(1, "interface name too long");
+ }
+ ibr.ibr_op = IF_BOND_OP_REMOVE_INTERFACE;
+ ifr.ifr_data = (caddr_t)&ibr;
+ if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIFBOND remove interface");
+
+ return;
+}
+
+static
+DECL_CMD_FUNC(setbondmode, val, d)
+{
+ struct if_bond_req ibr;
+ int mode;
+
+ if (strcmp(val, "lacp") == 0) {
+ mode = IF_BOND_MODE_LACP;
+ }
+ else if (strcmp(val, "static") == 0) {
+ mode = IF_BOND_MODE_STATIC;
+ }
+ else {
+ mode = strtoul(val, NULL, 0);
+ if (errno != 0) {
+ errx(1, "invalid mode value "
+ "(must be either \"lacp\" or \"static\")");
+ }
+ }
+
+ bzero((char *)&ibr, sizeof(ibr));
+ if ((unsigned int)snprintf(ibr.ibr_ibru.ibru_if_name,
+ sizeof(ibr.ibr_ibru.ibru_if_name),
+ "%s", val) >= IFNAMSIZ) {
+ errx(1, "interface name too long");
+ }
+ ibr.ibr_op = IF_BOND_OP_SET_MODE;
+ ibr.ibr_ibru.ibru_int_val = mode;
+ ifr.ifr_data = (caddr_t)&ibr;
+ if (ioctl(s, SIOCSIFBOND, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSIFBOND set mode");
+
+ return;
+}
+
+static struct cmd bond_cmds[] = {
+ DEF_CLONE_CMD_ARG("bonddev", setbonddev),
+ DEF_CLONE_CMD_ARG("-bonddev", unsetbonddev),
+ DEF_CMD_ARG("bondmode", setbondmode),
+};
+static struct afswtch af_bond = {
+ .af_name = "af_bond",
+ .af_af = AF_UNSPEC,
+ .af_other_status = bond_status,
+};
+
+static __constructor void
+bond_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(bond_cmds); i++)
+ cmd_register(&bond_cmds[i]);
+ af_register(&af_bond);
+#undef N
+}
+
diff --git a/network_cmds/ifconfig.tproj/ifbridge.c b/network_cmds/ifconfig.tproj/ifbridge.c
new file mode 100644
index 0000000..951c56b
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifbridge.c
@@ -0,0 +1,952 @@
+/*
+ * Copyright (c) 2009-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*-
+ * Copyright 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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 for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * 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 <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_bridgevar.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+
+#include "ifconfig.h"
+
+#define PV2ID(pv, epri, eaddr) do { \
+ epri = pv >> 48; \
+ eaddr[0] = pv >> 40; \
+ eaddr[1] = pv >> 32; \
+ eaddr[2] = pv >> 24; \
+ eaddr[3] = pv >> 16; \
+ eaddr[4] = pv >> 8; \
+ eaddr[5] = pv >> 0; \
+} while (0)
+
+static const char *stpstates[] = {
+ "disabled",
+ "listening",
+ "learning",
+ "forwarding",
+ "blocking",
+ "discarding"
+};
+static const char *stpproto[] = {
+ "stp",
+ "-",
+ "rstp"
+};
+static const char *stproles[] = {
+ "disabled",
+ "root",
+ "designated",
+ "alternate",
+ "backup"
+};
+
+static int
+get_val(const char *cp, u_long *valp)
+{
+ char *endptr;
+ u_long val;
+
+ errno = 0;
+ val = strtoul(cp, &endptr, 0);
+ if (cp[0] == '\0' || endptr[0] != '\0' || errno == ERANGE)
+ return (-1);
+
+ *valp = val;
+ return (0);
+}
+
+static int
+do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
+{
+ struct ifdrv ifd;
+
+ memset(&ifd, 0, sizeof(ifd));
+
+ strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+ ifd.ifd_cmd = op;
+ ifd.ifd_len = argsize;
+ ifd.ifd_data = arg;
+
+ return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
+}
+
+static void
+do_bridgeflag(int sock, const char *ifs, int flag, int set)
+{
+ struct ifbreq req;
+
+ strlcpy(req.ifbr_ifsname, ifs, sizeof(req.ifbr_ifsname));
+
+ if (do_cmd(sock, BRDGGIFFLGS, &req, sizeof(req), 0) < 0)
+ err(1, "unable to get bridge flags");
+
+ if (set)
+ req.ifbr_ifsflags |= flag;
+ else
+ req.ifbr_ifsflags &= ~flag;
+
+ if (do_cmd(sock, BRDGSIFFLGS, &req, sizeof(req), 1) < 0)
+ err(1, "unable to set bridge flags");
+}
+
+static void
+bridge_interfaces(int s, const char *prefix)
+{
+ struct ifbifconf bifc;
+ struct ifbreq *req;
+ char *inbuf = NULL, *ninbuf;
+ char *p, *pad;
+ int i, len = 8192;
+
+ pad = strdup(prefix);
+ if (pad == NULL)
+ err(1, "strdup");
+ /* replace the prefix with whitespace */
+ for (p = pad; *p != '\0'; p++) {
+ if(isprint(*p))
+ *p = ' ';
+ }
+
+ for (;;) {
+ ninbuf = realloc(inbuf, len);
+ if (ninbuf == NULL)
+ err(1, "unable to allocate interface buffer");
+ bifc.ifbic_len = len;
+ bifc.ifbic_buf = inbuf = ninbuf;
+ if (do_cmd(s, BRDGGIFS, &bifc, sizeof(bifc), 0) < 0)
+ err(1, "unable to get interface list");
+ if ((bifc.ifbic_len + sizeof(*req)) < len)
+ break;
+ len *= 2;
+ }
+
+ for (i = 0; i < bifc.ifbic_len / sizeof(*req); i++) {
+ req = bifc.ifbic_req + i;
+ printf("%s%s ", prefix, req->ifbr_ifsname);
+ printb("flags", req->ifbr_ifsflags, IFBIFBITS);
+ printf("\n");
+
+ printf("%s", pad);
+ printf("ifmaxaddr %u", req->ifbr_addrmax);
+ printf(" port %u priority %u", req->ifbr_portno,
+ req->ifbr_priority);
+ printf(" path cost %u", req->ifbr_path_cost);
+
+ if (req->ifbr_ifsflags & IFBIF_STP) {
+ if (req->ifbr_proto <
+ sizeof(stpproto) / sizeof(stpproto[0]))
+ printf(" proto %s", stpproto[req->ifbr_proto]);
+ else
+ printf(" <unknown proto %d>",
+ req->ifbr_proto);
+
+ printf("\n%s", pad);
+ if (req->ifbr_role <
+ sizeof(stproles) / sizeof(stproles[0]))
+ printf("role %s", stproles[req->ifbr_role]);
+ else
+ printf("<unknown role %d>",
+ req->ifbr_role);
+ if (req->ifbr_state <
+ sizeof(stpstates) / sizeof(stpstates[0]))
+ printf(" state %s", stpstates[req->ifbr_state]);
+ else
+ printf(" <unknown state %d>",
+ req->ifbr_state);
+ }
+ printf("\n");
+
+ if (verbose) {
+ struct ifbrhostfilter ifbrfh;
+ struct in_addr in;
+ struct ether_addr ea;
+
+ bzero(&ifbrfh, sizeof(struct ifbrhostfilter));
+ strlcpy(ifbrfh.ifbrhf_ifsname, req->ifbr_ifsname, sizeof(ifbrfh.ifbrhf_ifsname));
+ if (do_cmd(s, BRDGGHOSTFILTER, &ifbrfh, sizeof(ifbrfh), 0) < 0)
+ err(1, "unable to get host filter settings for %s",
+ ifbrfh.ifbrhf_ifsname);
+
+ if (ifbrfh.ifbrhf_flags & IFBRHF_ENABLED) {
+ in.s_addr = ifbrfh.ifbrhf_ipsrc;
+ bcopy(ifbrfh.ifbrhf_hwsrca, ea.octet, ETHER_ADDR_LEN);
+ } else {
+ in.s_addr = INADDR_ANY;
+ bzero(ea.octet, ETHER_ADDR_LEN);
+ }
+ printf("%s", pad);
+ printf("hostfilter %d hw: %s ip: %s",
+ ifbrfh.ifbrhf_flags & IFBRHF_ENABLED ? 1 : 0,
+ ether_ntoa(&ea), inet_ntoa(in));
+
+ printf("\n");
+ }
+ }
+
+ free(inbuf);
+ free(pad);
+}
+
+static void
+bridge_addresses(int s, const char *prefix)
+{
+ struct ifbaconf ifbac;
+ struct ifbareq *ifba;
+ char *inbuf = NULL, *ninbuf;
+ int i, len = 8192;
+ struct ether_addr ea;
+
+ for (;;) {
+ ninbuf = realloc(inbuf, len);
+ if (ninbuf == NULL)
+ err(1, "unable to allocate address buffer");
+ ifbac.ifbac_len = len;
+ ifbac.ifbac_buf = inbuf = ninbuf;
+ if (do_cmd(s, BRDGRTS, &ifbac, sizeof(ifbac), 0) < 0)
+ err(1, "unable to get address cache");
+ if ((ifbac.ifbac_len + sizeof(*ifba)) < len)
+ break;
+ len *= 2;
+ }
+
+ for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) {
+ ifba = ifbac.ifbac_req + i;
+ memcpy(ea.octet, ifba->ifba_dst,
+ sizeof(ea.octet));
+ printf("%s%s Vlan%d %s %lu ", prefix, ether_ntoa(&ea),
+ ifba->ifba_vlan, ifba->ifba_ifsname, ifba->ifba_expire);
+ printb("flags", ifba->ifba_flags, IFBAFBITS);
+ printf("\n");
+ }
+
+ free(inbuf);
+}
+
+#define MAX_IPv6_STR_LEN INET6_ADDRSTRLEN
+static void
+bridge_mac_nat(int s, const char *prefix)
+{
+ char *buf;
+ unsigned int count;
+ struct ether_addr ea;
+ unsigned int i;
+ struct ifbrmnelist mnl;
+ char *scan;
+
+ bzero(&mnl, sizeof(mnl));
+ if (do_cmd(s, BRDGGMACNATLIST, &mnl, sizeof(mnl), 0) < 0) {
+ /* err(1, "unable to get mac nat list"); */
+ return;
+ }
+ if (mnl.ifbml_len == 0) {
+ return;
+ }
+ printf("\tMAC NAT list:\n");
+ if (mnl.ifbml_elsize == 0) {
+ err(1, "kernel reported zero length element size");
+ }
+ if (mnl.ifbml_elsize < sizeof(struct ifbrmne)) {
+ err(1, "struct element size too small, kernel mismatch");
+ }
+ buf = malloc(mnl.ifbml_len);
+ if (buf == NULL) {
+ err(1, "unable to allocate mac nat list buffer");
+ }
+ mnl.ifbml_buf = buf;
+ if (do_cmd(s, BRDGGMACNATLIST, &mnl, sizeof(mnl), 0) < 0) {
+ err(1, "unable to get mac nat list");
+ }
+ count = mnl.ifbml_len / mnl.ifbml_elsize;
+ for (i = 0, scan = buf; i < count; i++, scan += mnl.ifbml_elsize) {
+ struct ifbrmne *ifbmne = (struct ifbrmne *)scan;
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ memcpy(ea.octet, ifbmne->ifbmne_mac,
+ sizeof(ea.octet));
+ inet_ntop(ifbmne->ifbmne_af, &ifbmne->ifbmne_ip,
+ ntopbuf, sizeof(ntopbuf));
+ printf("%s%s %s %s %lu\n",
+ prefix, ifbmne->ifbmne_ifname, ntopbuf, ether_ntoa(&ea),
+ (unsigned long)ifbmne->ifbmne_expire);
+ }
+ free(buf);
+}
+
+static void
+bridge_status(int s)
+{
+ struct ifbropreq ifbp;
+ struct ifbrparam param;
+ u_int16_t pri;
+ u_int8_t ht, fd, ma, hc, pro;
+ u_int8_t lladdr[ETHER_ADDR_LEN];
+ u_int16_t bprio;
+ u_int32_t csize, ctime;
+ u_int32_t ipfflags;
+
+ if (do_cmd(s, BRDGGCACHE, &param, sizeof(param), 0) < 0)
+ return;
+ csize = param.ifbrp_csize;
+ if (do_cmd(s, BRDGGTO, &param, sizeof(param), 0) < 0)
+ return;
+ ctime = param.ifbrp_ctime;
+ if (do_cmd(s, BRDGGFILT, &param, sizeof(param), 0) < 0)
+ return;
+ ipfflags = param.ifbrp_filter;
+ if (do_cmd(s, BRDGPARAM, &ifbp, sizeof(ifbp), 0) < 0)
+ return;
+ pri = ifbp.ifbop_priority;
+ pro = ifbp.ifbop_protocol;
+ ht = ifbp.ifbop_hellotime;
+ fd = ifbp.ifbop_fwddelay;
+ hc = ifbp.ifbop_holdcount;
+ ma = ifbp.ifbop_maxage;
+
+ printf("\tConfiguration:\n");
+ PV2ID(ifbp.ifbop_bridgeid, bprio, lladdr);
+ printf("\t\tid %s priority %u hellotime %u fwddelay %u\n",
+ ether_ntoa((struct ether_addr *)lladdr), pri, ht, fd);
+ printf("\t\tmaxage %u holdcnt %u proto %s maxaddr %u timeout %u\n",
+ ma, hc, stpproto[pro], csize, ctime);
+
+ PV2ID(ifbp.ifbop_designated_root, bprio, lladdr);
+ printf("\t\troot id %s priority %d ifcost %u port %u\n",
+ ether_ntoa((struct ether_addr *)lladdr), bprio,
+ ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff);
+
+ printf("\t\tipfilter %s flags 0x%x\n",
+ (ipfflags & IFBF_FILT_USEIPF) ? "enabled" : "disabled", ipfflags);
+
+ bridge_interfaces(s, "\tmember: ");
+
+ if (!all || verbose > 1) {
+ printf("\tAddress cache:\n");
+ bridge_addresses(s, "\t\t");
+ bridge_mac_nat(s, "\t\t");
+ }
+ return;
+
+}
+
+static void
+setbridge_add(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+ if (do_cmd(s, BRDGADD, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGADD %s", val);
+}
+
+static void
+setbridge_delete(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+ if (do_cmd(s, BRDGDEL, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGDEL %s", val);
+}
+
+static void
+setbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_DISCOVER, 1);
+}
+
+static void
+unsetbridge_discover(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_DISCOVER, 0);
+}
+
+static void
+setbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_LEARNING, 1);
+}
+
+static void
+unsetbridge_learn(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_LEARNING, 0);
+}
+
+#ifdef notdef
+static void
+setbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_STICKY, 1);
+}
+
+static void
+unsetbridge_sticky(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_STICKY, 0);
+}
+
+static void
+setbridge_span(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+ if (do_cmd(s, BRDGADDS, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGADDS %s", val);
+}
+
+static void
+unsetbridge_span(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, val, sizeof(req.ifbr_ifsname));
+ if (do_cmd(s, BRDGDELS, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGDELS %s", val);
+}
+#endif
+
+static void
+setbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_STP, 1);
+}
+
+static void
+unsetbridge_stp(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_STP, 0);
+}
+
+#ifdef notdef
+static void
+setbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 1);
+}
+
+static void
+unsetbridge_edge(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_EDGE, 0);
+}
+
+static void
+setbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 1);
+}
+
+static void
+unsetbridge_autoedge(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_AUTOEDGE, 0);
+}
+
+static void
+setbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_PTP, 1);
+}
+
+static void
+unsetbridge_ptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_PTP, 0);
+}
+
+static void
+setbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 1);
+}
+
+static void
+unsetbridge_autoptp(const char *val, int d, int s, const struct afswtch *afp)
+{
+ do_bridgeflag(s, val, IFBIF_BSTP_AUTOPTP, 0);
+}
+#endif
+
+static void
+setbridge_flush(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ req.ifbr_ifsflags = IFBF_FLUSHDYN;
+ if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGFLUSH");
+}
+
+static void
+setbridge_flushall(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbreq req;
+
+ memset(&req, 0, sizeof(req));
+ req.ifbr_ifsflags = IFBF_FLUSHALL;
+ if (do_cmd(s, BRDGFLUSH, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGFLUSH");
+}
+
+static void
+setbridge_static(const char *val, const char *mac, int s,
+ const struct afswtch *afp)
+{
+ struct ifbareq req;
+ struct ether_addr *ea;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifba_ifsname, val, sizeof(req.ifba_ifsname));
+
+ ea = ether_aton(mac);
+ if (ea == NULL)
+ errx(1, "%s: invalid address: %s", val, mac);
+
+ memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+ req.ifba_flags = IFBAF_STATIC;
+ req.ifba_vlan = 1; /* XXX allow user to specify */
+
+ if (do_cmd(s, BRDGSADDR, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSADDR %s", val);
+}
+
+static void
+setbridge_deladdr(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifbareq req;
+ struct ether_addr *ea;
+
+ memset(&req, 0, sizeof(req));
+
+ ea = ether_aton(val);
+ if (ea == NULL)
+ errx(1, "invalid address: %s", val);
+
+ memcpy(req.ifba_dst, ea->octet, sizeof(req.ifba_dst));
+
+ if (do_cmd(s, BRDGDADDR, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGDADDR %s", val);
+}
+
+static void
+setbridge_addr(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ bridge_addresses(s, "");
+}
+
+static void
+setbridge_maxaddr(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_csize = val & 0xffffffff;
+
+ if (do_cmd(s, BRDGSCACHE, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSCACHE %s", arg);
+}
+
+static void
+setbridge_hellotime(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_hellotime = val & 0xff;
+
+ if (do_cmd(s, BRDGSHT, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSHT %s", arg);
+}
+
+static void
+setbridge_fwddelay(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_fwddelay = val & 0xff;
+
+ if (do_cmd(s, BRDGSFD, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSFD %s", arg);
+}
+
+static void
+setbridge_maxage(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_maxage = val & 0xff;
+
+ if (do_cmd(s, BRDGSMA, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSMA %s", arg);
+}
+
+static void
+setbridge_priority(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xffff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_prio = val & 0xffff;
+
+ if (do_cmd(s, BRDGSPRI, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSPRI %s", arg);
+}
+
+#ifdef notdef
+static void
+setbridge_protocol(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+
+ if (strcasecmp(arg, "stp") == 0) {
+ param.ifbrp_proto = 0;
+ } else if (strcasecmp(arg, "rstp") == 0) {
+ param.ifbrp_proto = 2;
+ } else {
+ errx(1, "unknown stp protocol");
+ }
+
+ if (do_cmd(s, BRDGSPROTO, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSPROTO %s", arg);
+}
+
+static void
+setbridge_holdcount(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_txhc = val & 0xff;
+
+ if (do_cmd(s, BRDGSTXHC, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSTXHC %s", arg);
+}
+#endif
+
+static void
+setbridge_ifpriority(const char *ifn, const char *pri, int s,
+ const struct afswtch *afp)
+{
+ struct ifbreq req;
+ u_long val;
+
+ memset(&req, 0, sizeof(req));
+
+ if (get_val(pri, &val) < 0 || (val & ~0xff) != 0)
+ errx(1, "invalid value: %s", pri);
+
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ req.ifbr_priority = val & 0xff;
+
+ if (do_cmd(s, BRDGSIFPRIO, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFPRIO %s", pri);
+}
+
+static void
+setbridge_ifpathcost(const char *ifn, const char *cost, int s,
+ const struct afswtch *afp)
+{
+ struct ifbreq req;
+ u_long val;
+
+ memset(&req, 0, sizeof(req));
+
+ if (get_val(cost, &val) < 0)
+ errx(1, "invalid value: %s", cost);
+
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ req.ifbr_path_cost = val;
+
+ if (do_cmd(s, BRDGSIFCOST, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFCOST %s", cost);
+}
+
+#ifdef notdef
+static void
+setbridge_ifmaxaddr(const char *ifn, const char *arg, int s,
+ const struct afswtch *afp)
+{
+ struct ifbreq req;
+ u_long val;
+
+ memset(&req, 0, sizeof(req));
+
+ if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
+ req.ifbr_addrmax = val & 0xffffffff;
+
+ if (do_cmd(s, BRDGSIFAMAX, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFAMAX %s", arg);
+}
+#endif
+
+static void
+setbridge_timeout(const char *arg, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrparam param;
+ u_long val;
+
+ if (get_val(arg, &val) < 0 || (val & ~0xffffffff) != 0)
+ errx(1, "invalid value: %s", arg);
+
+ param.ifbrp_ctime = val & 0xffffffff;
+
+ if (do_cmd(s, BRDGSTO, &param, sizeof(param), 1) < 0)
+ err(1, "BRDGSTO %s", arg);
+}
+
+#ifdef notdef
+static void
+setbridge_private(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_PRIVATE, 1);
+}
+
+static void
+unsetbridge_private(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_PRIVATE, 0);
+}
+#endif
+
+
+static void
+setbridge_hostfilter(const char *ifn, const char *addr, int s,
+ const struct afswtch *afp)
+{
+ struct ifbrhostfilter req;
+ struct ether_addr *ea;
+ struct in_addr in;
+
+ memset(&req, 0, sizeof(req));
+ req.ifbrhf_flags = IFBRHF_ENABLED;
+
+ strlcpy(req.ifbrhf_ifsname, ifn, sizeof(req.ifbrhf_ifsname));
+
+ ea = ether_aton(addr);
+ if (ea != NULL) {
+ req.ifbrhf_flags |= IFBRHF_HWSRC;
+ bcopy(ea, req.ifbrhf_hwsrca, sizeof(req.ifbrhf_hwsrca));
+ } else if (inet_aton(addr, &in) != 0) {
+ req.ifbrhf_flags |= IFBRHF_IPSRC;
+ req.ifbrhf_ipsrc = in.s_addr;
+ } else
+ errx(1, "invalid address: %s", addr);
+
+ if (do_cmd(s, BRDGSHOSTFILTER, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSHOSTFILTER %s %s", ifn, addr);
+}
+
+static void
+unsetbridge_hostfilter(const char *ifn, int d, int s, const struct afswtch *afp)
+{
+ struct ifbrhostfilter req;
+
+ memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbrhf_ifsname, ifn, sizeof(req.ifbrhf_ifsname));
+
+ if (do_cmd(s, BRDGSHOSTFILTER, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSHOSTFILTER");
+}
+
+static void
+setbridge_macnat(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_MAC_NAT, 1);
+}
+
+static void
+unsetbridge_macnat(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ do_bridgeflag(s, val, IFBIF_MAC_NAT, 0);
+}
+
+static struct cmd bridge_cmds[] = {
+ DEF_CMD_ARG("addm", setbridge_add),
+ DEF_CMD_ARG("deletem", setbridge_delete),
+ DEF_CMD_ARG("discover", setbridge_discover),
+ DEF_CMD_ARG("-discover", unsetbridge_discover),
+ DEF_CMD_ARG("learn", setbridge_learn),
+ DEF_CMD_ARG("-learn", unsetbridge_learn),
+#ifdef notdef
+ DEF_CMD_ARG("sticky", setbridge_sticky),
+ DEF_CMD_ARG("-sticky", unsetbridge_sticky),
+ DEF_CMD_ARG("span", setbridge_span),
+ DEF_CMD_ARG("-span", unsetbridge_span),
+#endif
+ DEF_CMD_ARG("stp", setbridge_stp),
+ DEF_CMD_ARG("-stp", unsetbridge_stp),
+#ifdef notdef
+ DEF_CMD_ARG("edge", setbridge_edge),
+ DEF_CMD_ARG("-edge", unsetbridge_edge),
+ DEF_CMD_ARG("autoedge", setbridge_autoedge),
+ DEF_CMD_ARG("-autoedge", unsetbridge_autoedge),
+ DEF_CMD_ARG("ptp", setbridge_ptp),
+ DEF_CMD_ARG("-ptp", unsetbridge_ptp),
+ DEF_CMD_ARG("autoptp", setbridge_autoptp),
+ DEF_CMD_ARG("-autoptp", unsetbridge_autoptp),
+#endif
+ DEF_CMD("flush", 0, setbridge_flush),
+ DEF_CMD("flushall", 0, setbridge_flushall),
+ DEF_CMD_ARG2("static", setbridge_static),
+ DEF_CMD_ARG("deladdr", setbridge_deladdr),
+ DEF_CMD("addr", 1, setbridge_addr),
+ DEF_CMD_ARG("maxaddr", setbridge_maxaddr),
+ DEF_CMD_ARG("hellotime", setbridge_hellotime),
+ DEF_CMD_ARG("fwddelay", setbridge_fwddelay),
+ DEF_CMD_ARG("maxage", setbridge_maxage),
+ DEF_CMD_ARG("priority", setbridge_priority),
+#ifdef notdef
+ DEF_CMD_ARG("proto", setbridge_protocol),
+ DEF_CMD_ARG("holdcnt", setbridge_holdcount),
+#endif
+ DEF_CMD_ARG2("ifpriority", setbridge_ifpriority),
+ DEF_CMD_ARG2("ifpathcost", setbridge_ifpathcost),
+#ifdef notdef
+ DEF_CMD_ARG2("ifmaxaddr", setbridge_ifmaxaddr),
+#endif
+ DEF_CMD_ARG("timeout", setbridge_timeout),
+#ifdef notdef
+ DEF_CMD_ARG("private", setbridge_private),
+ DEF_CMD_ARG("-private", unsetbridge_private),
+#endif
+ DEF_CMD_ARG2("hostfilter", setbridge_hostfilter),
+ DEF_CMD_ARG("-hostfilter", unsetbridge_hostfilter),
+ DEF_CMD_ARG("macnat", setbridge_macnat),
+ DEF_CMD_ARG("-macnat", unsetbridge_macnat),
+};
+static struct afswtch af_bridge = {
+ .af_name = "af_bridge",
+ .af_af = AF_UNSPEC,
+ .af_other_status = bridge_status,
+};
+
+static __constructor void
+bridge_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(bridge_cmds); i++)
+ cmd_register(&bridge_cmds[i]);
+ af_register(&af_bridge);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/ifclone.c b/network_cmds/ifconfig.tproj/ifclone.c
new file mode 100644
index 0000000..127d10b
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifclone.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void
+list_cloners(void)
+{
+ struct if_clonereq ifcr;
+ char *cp, *buf;
+ int idx;
+ int s;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s == -1)
+ err(1, "socket(AF_INET,SOCK_DGRAM)");
+
+ memset(&ifcr, 0, sizeof(ifcr));
+
+ if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+ err(1, "SIOCIFGCLONERS for count");
+
+ buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
+ if (buf == NULL)
+ err(1, "unable to allocate cloner name buffer");
+
+ ifcr.ifcr_count = ifcr.ifcr_total;
+ ifcr.ifcr_buffer = buf;
+
+ if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0)
+ err(1, "SIOCIFGCLONERS for names");
+
+ /*
+ * In case some disappeared in the mean time, clamp it down.
+ */
+ if (ifcr.ifcr_count > ifcr.ifcr_total)
+ ifcr.ifcr_count = ifcr.ifcr_total;
+
+ for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) {
+ if (idx > 0)
+ putchar(' ');
+ printf("%s", cp);
+ }
+
+ putchar('\n');
+ free(buf);
+}
+
+static clone_callback_func *clone_cb = NULL;
+
+void
+clone_setcallback(clone_callback_func *p)
+{
+ if (clone_cb != NULL && clone_cb != p)
+ errx(1, "conflicting device create parameters");
+ clone_cb = p;
+}
+
+/*
+ * Do the actual clone operation. Any parameters must have been
+ * setup by now. If a callback has been setup to do the work
+ * then defer to it; otherwise do a simple create operation with
+ * no parameters.
+ */
+static void
+ifclonecreate(int s, void *arg)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (clone_cb == NULL) {
+#ifdef SIOCIFCREATE2
+ /* NB: no parameters */
+ if (ioctl(s, SIOCIFCREATE2, &ifr) < 0)
+ err(1, "SIOCIFCREATE2");
+#else
+ if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
+ err(1, "SIOCIFCREATE");
+#endif
+ } else {
+ clone_cb(s, &ifr);
+ }
+
+ /*
+ * If we get a different name back than we put in, print it.
+ */
+ if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) {
+ strlcpy(name, ifr.ifr_name, sizeof(name));
+ printf("%s\n", name);
+ }
+}
+
+static
+DECL_CMD_FUNC(clone_create, arg, d)
+{
+ callback_register(ifclonecreate, NULL);
+}
+
+static
+DECL_CMD_FUNC(clone_destroy, arg, d)
+{
+ (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCIFDESTROY, &ifr) < 0)
+ err(1, "SIOCIFDESTROY");
+}
+
+static struct cmd clone_cmds[] = {
+ DEF_CLONE_CMD("create", 0, clone_create),
+ DEF_CMD("destroy", 0, clone_destroy),
+ DEF_CLONE_CMD("plumb", 0, clone_create),
+ DEF_CMD("unplumb", 0, clone_destroy),
+};
+
+static void
+clone_Copt_cb(const char *optarg __unused)
+{
+ list_cloners();
+ exit(0);
+}
+static struct option clone_Copt = { "C", "[-C]", clone_Copt_cb };
+
+static __constructor void
+clone_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(clone_cmds); i++)
+ cmd_register(&clone_cmds[i]);
+ opt_register(&clone_Copt);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/ifconfig.8 b/network_cmds/ifconfig.tproj/ifconfig.8
new file mode 100644
index 0000000..9b06f04
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifconfig.8
@@ -0,0 +1,1109 @@
+.\" Copyright (c) 2013 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
+.\" $FreeBSD: src/sbin/ifconfig/ifconfig.8,v 1.142.2.6.2.1 2008/11/25 02:59:29 kensmith Exp $
+.\"
+.Dd June 20, 2008
+.Dt IFCONFIG 8
+.Os
+.Sh NAME
+.Nm ifconfig
+.Nd configure network interface parameters
+.Sh SYNOPSIS
+.Nm
+.Op Fl L
+.Op Fl m
+.Op Fl r
+.Ar interface
+.Op Cm create
+.Op Ar address_family
+.Oo
+.Ar address
+.Op Ar dest_address
+.Oc
+.Op Ar parameters
+.Nm
+.Ar interface
+.Cm destroy
+.Nm
+.Fl a
+.Op Fl L
+.Op Fl d
+.Op Fl m
+.Op Fl r
+.Op Fl u
+.Op Fl v
+.Op Ar address_family
+.Nm
+.Fl l
+.Op Fl d
+.Op Fl u
+.Op Ar address_family
+.Nm
+.Op Fl L
+.Op Fl d
+.Op Fl m
+.Op Fl r
+.Op Fl u
+.Op Fl v
+.Op Fl C
+.Nm
+.Ar interface
+.Cm vlan
+.Ar vlan-tag
+.Cm vlandev
+.Ar iface
+.Nm
+.Ar interface
+.Cm -vlandev
+.Ar iface
+.Nm
+.Ar interface
+.Cm bonddev
+.Ar iface
+.Nm
+.Ar interface
+.Cm -bonddev
+.Ar iface
+.Nm
+.Ar interface
+.Cm bondmode
+.Ar lacp | static
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to assign an address
+to a network interface and/or configure
+network interface parameters.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Ar address
+For the
+.Tn DARPA Ns -Internet
+family,
+the address is either a host name present in the host name data
+base,
+.Xr hosts 5 ,
+or a
+.Tn DARPA
+Internet address expressed in the Internet standard
+.Dq dot notation .
+.Pp
+It is also possible to use the CIDR notation (also known as the
+slash notation) to include the netmask.
+That is, one can specify an address like
+.Li 192.168.0.1/16 .
+.Pp
+For the
+.Dq inet6
+family, it is also possible to specify the prefix length using the slash
+notation, like
+.Li ::1/128 .
+See the
+.Cm prefixlen
+parameter below for more information.
+.\" For the Xerox Network Systems(tm) family,
+.\" addresses are
+.\" .Ar net:a.b.c.d.e.f ,
+.\" where
+.\" .Ar net
+.\" is the assigned network number (in decimal),
+.\" and each of the six bytes of the host number,
+.\" .Ar a
+.\" through
+.\" .Ar f ,
+.\" are specified in hexadecimal.
+.\" The host number may be omitted on IEEE 802 protocol
+.\" (Ethernet, FDDI, and Token Ring) interfaces,
+.\" which use the hardware physical address,
+.\" and on interfaces other than the first.
+.\" For the
+.\" .Tn ISO
+.\" family, addresses are specified as a long hexadecimal string,
+.\" as in the Xerox family.
+.\" However, two consecutive dots imply a zero
+.\" byte, and the dots are optional, if the user wishes to (carefully)
+.\" count out long strings of digits in network byte order.
+.Pp
+The link-level
+.Pq Dq link
+address
+is specified as a series of colon-separated hex digits.
+This can be used to
+e.g.\& set a new MAC address on an ethernet interface, though the
+mechanism used is not ethernet-specific.
+If the interface is already
+up when this option is used, it will be briefly brought down and
+then brought back up again in order to ensure that the receive
+filter in the underlying ethernet hardware is properly reprogrammed.
+.It Ar address_family
+Specify the
+address family
+which affects interpretation of the remaining parameters.
+Since an interface can receive transmissions in differing protocols
+with different naming schemes, specifying the address family is recommended.
+The address or protocol families currently
+supported are
+.Dq inet ,
+.Dq inet6 ,
+.\".Dq atalk ,
+.\".Dq ipx ,
+.\" .Dq iso ,
+and
+.Dq link .
+.\" and
+.\" .Dq ns .
+The default is
+.Dq inet .
+.Dq ether
+and
+.Dq lladdr
+are synonyms for
+.Dq link .
+.It Ar dest_address
+Specify the address of the correspondent on the other end
+of a point to point link.
+.It Ar interface
+This
+parameter is a string of the form
+.Dq name unit ,
+for example,
+.Dq Li en0 .
+\.El
+.Pp
+The following parameters may be set with
+.Nm :
+.Bl -tag -width indent
+.It Cm add
+Another name for the
+.Cm alias
+parameter.
+Introduced for compatibility
+with
+.Bsx .
+.It Cm alias
+Establish an additional network address for this interface.
+This is sometimes useful when changing network numbers, and
+one wishes to accept packets addressed to the old interface.
+If the address is on the same subnet as the first network address
+for this interface, a non-conflicting netmask must be given.
+Usually
+.Li 0xffffffff
+is most appropriate.
+.It Fl alias
+Remove the network address specified.
+This would be used if you incorrectly specified an alias, or it
+was no longer needed.
+If you have incorrectly set an NS address having the side effect
+of specifying the host portion, removing all NS addresses will
+allow you to respecify the host portion.
+.It Cm anycast
+(Inet6 only.)
+Specify that the address configured is an anycast address.
+Based on the current specification,
+only routers may configure anycast addresses.
+Anycast address will not be used as source address of any of outgoing
+IPv6 packets.
+.It Cm arp
+Enable the use of the Address Resolution Protocol
+.Pq Xr arp 4
+in mapping
+between network level addresses and link level addresses (default).
+This is currently implemented for mapping between
+.Tn DARPA
+Internet
+addresses and
+.Tn IEEE
+802 48-bit MAC addresses (Ethernet, FDDI, and Token Ring addresses).
+.It Fl arp
+Disable the use of the Address Resolution Protocol
+.Pq Xr arp 4 .
+.It Cm broadcast
+(Inet only.)
+Specify the address to use to represent broadcasts to the
+network.
+The default broadcast address is the address with a host part of all 1's.
+.It Cm debug
+Enable driver dependent debugging code; usually, this turns on
+extra console error logging.
+.It Fl debug
+Disable driver dependent debugging code.
+.It Cm delete
+Another name for the
+.Fl alias
+parameter.
+.It Cm down
+Mark an interface
+.Dq down .
+When an interface is marked
+.Dq down ,
+the system will not attempt to
+transmit messages through that interface.
+If possible, the interface will be reset to disable reception as well.
+.It Cm ether
+Another name for the
+.Cm lladdr
+parameter.
+.\" .It Cm ipdst
+.\" This is used to specify an Internet host who is willing to receive
+.\" ip packets encapsulating NS packets bound for a remote network.
+.\" An apparent point to point link is constructed, and
+.\" the address specified will be taken as the NS address and network
+.\" of the destination.
+.\" IP encapsulation of
+.\" .Tn CLNP
+.\" packets is done differently.
+.It Cm lladdr Ar addr
+Set the link-level address on an interface.
+This can be used to
+e.g. set a new MAC address on an ethernet interface, though the
+mechanism used is not ethernet-specific.
+The address
+.Ar addr
+is specified as a series of colon-separated hex digits.
+If the interface is already
+up when this option is used, it will be briefly brought down and
+then brought back up again in order to ensure that the receive
+filter in the underlying ethernet hardware is properly reprogrammed.
+.It Cm media Ar type
+If the driver supports the media selection system, set the media type
+of the interface to
+.Ar type .
+Some interfaces support the mutually exclusive use of one of several
+different physical media connectors.
+For example, a 10Mbit/s Ethernet
+interface might support the use of either
+.Tn AUI
+or twisted pair connectors.
+Setting the media type to
+.Cm 10base5/AUI
+would change the currently active connector to the AUI port.
+Setting it to
+.Cm 10baseT/UTP
+would activate twisted pair.
+Refer to the interfaces' driver
+specific documentation or man page for a complete list of the
+available types.
+.It Cm mediaopt Ar opts
+If the driver supports the media selection system, set the specified
+media options on the interface.
+The
+.Ar opts
+argument
+is a comma delimited list of options to apply to the interface.
+Refer to the interfaces' driver specific man page for a complete
+list of available options.
+.It Fl mediaopt Ar opts
+If the driver supports the media selection system, disable the
+specified media options on the interface.
+.It Cm rxcsum , txcsum
+If the driver supports user-configurable checksum offloading,
+enable receive (or transmit) checksum offloading on the interface.
+Some drivers may not be able to enable these flags independently
+of each other, so setting one may also set the other.
+The driver will offload as much checksum work as it can reliably
+support, the exact level of offloading varies between drivers.
+.It Fl rxcsum , txcsum
+If the driver supports user-configurable checksum offloading,
+disable receive (or transmit) checksum offloading on the interface.
+These settings may not always be independent of each other.
+.It Cm tso
+If the driver supports
+.Xr tcp 4
+segmentation offloading, enable TSO on the interface.
+Some drivers may not be able to support TSO for
+.Xr ip 4
+and
+.Xr ip6 4
+packets, so they may enable only one of them.
+.It Fl tso
+If the driver supports
+.Xr tcp 4
+segmentation offloading, disable TSO on the interface.
+It will always disable TSO for
+.Xr ip 4
+and
+.Xr ip6 4 .
+.It Cm lro
+If the driver supports
+.Xr tcp 4
+large receive offloading, enable LRO on the interface.
+.It Fl lro
+If the driver supports
+.Xr tcp 4
+large receive offloading, disable LRO on the interface.
+.It Cm av
+If supported by the driver, enable 802.1 AVB on the interface.
+.It Fl av
+If supported by the driver, disable 802.1 AVB on the interface.
+.It Cm vlanmtu , vlanhwtag
+If the driver offers user-configurable VLAN support, enable
+reception of extended frames or tag processing in hardware,
+respectively.
+Note that this must be issued on a physical interface associated with
+.Xr vlan 4 ,
+not on a
+.Xr vlan 4
+interface itself.
+.It Fl vlanmtu , vlanhwtag
+If the driver offers user-configurable VLAN support, disable
+reception of extended frames or tag processing in hardware,
+respectively.
+.It Cm create
+Create the specified network pseudo-device.
+If the interface is given without a unit number, try to create a new
+device with an arbitrary unit number.
+If creation of an arbitrary device is successful, the new device name is
+printed to standard output unless the interface is renamed or destroyed
+in the same
+.Nm
+invocation.
+.It Cm destroy
+Destroy the specified network pseudo-device.
+.It Cm plumb
+Another name for the
+.Cm create
+parameter.
+Included for
+.Tn Solaris
+compatibility.
+.It Cm unplumb
+Another name for the
+.Cm destroy
+parameter.
+Included for
+.Tn Solaris
+compatibility.
+.It Cm metric Ar n
+Set the routing metric of the interface to
+.Ar n ,
+default 0.
+The routing metric is used by the routing protocol
+.Pq Xr routed 8 .
+Higher metrics have the effect of making a route
+less favorable; metrics are counted as additional hops
+to the destination network or host.
+.It Cm mtu Ar n
+Set the maximum transmission unit of the interface to
+.Ar n ,
+default is interface specific.
+The MTU is used to limit the size of packets that are transmitted on an
+interface.
+Not all interfaces support setting the MTU, and some interfaces have
+range restrictions.
+.It Cm netmask Ar mask
+.\" (Inet and ISO.)
+(Inet only.)
+Specify how much of the address to reserve for subdividing
+networks into sub-networks.
+The mask includes the network part of the local address
+and the subnet part, which is taken from the host field of the address.
+The mask can be specified as a single hexadecimal number
+with a leading
+.Ql 0x ,
+with a dot-notation Internet address,
+or with a pseudo-network name listed in the network table
+.Xr networks 5 .
+The mask contains 1's for the bit positions in the 32-bit address
+which are to be used for the network and subnet parts,
+and 0's for the host part.
+The mask should contain at least the standard network portion,
+and the subnet field should be contiguous with the network
+portion.
+.Pp
+The netmask can also be specified in CIDR notation after the address.
+See the
+.Ar address
+option above for more information.
+.It Cm prefixlen Ar len
+(Inet6 only.)
+Specify that
+.Ar len
+bits are reserved for subdividing networks into sub-networks.
+The
+.Ar len
+must be integer, and for syntactical reason it must be between 0 to 128.
+It is almost always 64 under the current IPv6 assignment rule.
+If the parameter is omitted, 64 is used.
+.Pp
+The prefix can also be specified using the slash notation after the address.
+See the
+.Ar address
+option above for more information.
+.\" see
+.\" Xr eon 5 .
+.\" .It Cm nsellength Ar n
+.\" .Pf ( Tn ISO
+.\" only)
+.\" This specifies a trailing number of bytes for a received
+.\" .Tn NSAP
+.\" used for local identification, the remaining leading part of which is
+.\" taken to be the
+.\" .Tn NET
+.\" (Network Entity Title).
+.\" The default value is 1, which is conformant to US
+.\" .Tn GOSIP .
+.\" When an ISO address is set in an ifconfig command,
+.\" it is really the
+.\" .Tn NSAP
+.\" which is being specified.
+.\" For example, in
+.\" .Tn US GOSIP ,
+.\" 20 hex digits should be
+.\" specified in the
+.\" .Tn ISO NSAP
+.\" to be assigned to the interface.
+.\" There is some evidence that a number different from 1 may be useful
+.\" for
+.\" .Tn AFI
+.\" 37 type addresses.
+.It Cm remove
+Another name for the
+.Fl alias
+parameter.
+Introduced for compatibility
+with
+.Bsx .
+.Sm off
+.It Cm link Op Cm 0 No - Cm 2
+.Sm on
+Enable special processing of the link level of the interface.
+These three options are interface specific in actual effect, however,
+they are in general used to select special modes of operation.
+An example
+of this is to enable SLIP compression, or to select the connector type
+for some Ethernet cards.
+Refer to the man page for the specific driver
+for more information.
+.Sm off
+.It Fl link Op Cm 0 No - Cm 2
+.Sm on
+Disable special processing at the link level with the specified interface.
+.It Cm up
+Mark an interface
+.Dq up .
+This may be used to enable an interface after an
+.Dq Nm Cm down .
+It happens automatically when setting the first address on an interface.
+If the interface was reset when previously marked down,
+the hardware will be re-initialized.
+.El
+.Pp
+The following parameters are for ICMPv6 Neighbor Discovery Protocol.
+Note that the address family keyword
+.Dq Li inet6
+is needed for them:
+.Bl -tag -width indent
+.It Cm nud
+Perform network unreachability detection (NUD).
+.It Cm -nud
+Do not perform network unreachability detection (NUD).
+.It Cm ifdisabled
+Disable all IPv6 communication on the interface.
+.It Cm -ifdisabled
+Do not disable all IPv6 communication on the interface.
+.It Cm insecure
+Disable the processing of Secure Neighbor Discovery (SEND).
+.It Cm -insecure
+Do not disabled the processing of Secure Neighbor Discovery (SEND).
+.It Cm dad
+Perform duplicate address detection (DAD).
+.It Cm -dad
+Do not perform duplicate address detection (DAD).
+.It Cm replicated
+Modify duplicate address detection (DAD) protocol to expect that interface
+configuration is replicated at a network sleep proxy. Ignores certain NA
+messages and disables optimistic DAD.
+.It Cm -replicated
+Do not use modified duplicated address detection (DAD) protocol.
+.El
+.Pp
+The following parameters are specific to link aggregate interfaces:
+.Bl -tag -width indent
+.It Cm bonddev Ar iface
+If the interface is a bond pseudo device, associate physical interface
+.Ar iface
+with it. By default, the bond pseudo device is in LACP
+(Link Aggregation Control Protocol) mode (see \fBbondmode\fR below). In
+this mode, the device conforms to the IEEE 802.3ad Link Aggregation
+specification.
+.Pp
+If this is the first physical interface to be associated with the bond
+interface, the bond interface inherits the ethernet address from the
+physical interface. Physical interfaces that are added to the bond have
+their ethernet address re-programmed so that all members of the bond have
+the same ethernet address. If the physical interface is subsequently
+removed from the bond using
+.Fl bonddev ,
+a new ethernet address is chosen from the remaining interfaces, and all
+interfaces are re-programmed again with the new ethernet address. If no
+remaining interfaces exist, the bond interface's ethernet address is cleared.
+.Pp
+If the specified physical interface
+.Ar iface
+is not capable of having its ethernet address re-programmed, the
+.Cm bonddev
+command will fail.
+.Pp
+Once the physical interface
+.Ar iface
+is successfully associated with the bond interface, all received packets
+are diverted to the bond interface. The physical interface is no longer
+useable on its own, and remains that way until it is removed from the bond using
+.Fl bonddev .
+.Pp
+It is possible that the specified interface
+.Ar iface
+is not capable of aggregating, and may remain unused until the operating
+conditions change.
+.Pp
+The link status of the bond interface depends on the state of link aggregation.
+If no active partner is detected, the link status will remain inactive.
+.Pp
+To monitor the 802.3ad Link Aggregation state, use the
+.Fl b
+option.
+.Pp
+A physical interface that is associated with a vlan pseudo device cannot
+at the same time be associated with a bond pseudo device. A physical interface
+cannot be associated with more than one bond pseudo device at the same time.
+.Pp
+It is not possible to associate a bond with pseudo interfaces such as vlan.
+Only physical ethernet interfaces may be associated with a bond.
+.It Fl bonddev Ar iface
+If the interface is a bond pseudo device, disassociate the physical interface
+.Ar iface
+from it. Before the interface is removed from the bond, the bond device
+announces to the link partner that the interface is now individual and
+no longer aggregatable.
+If the physical
+.Ar iface
+is the last interface in the bond, the bond interface clears its link address.
+.It Cm bondmode Ar lacp | static
+If the interface is a bond pseudo device, this option will set the \fImode\fR
+on the bond interface. The two currently supported modes are
+.Ar lacp
+and
+.Ar static .
+The default mode is
+.Ar lacp .
+.Pp
+To enable static mode (and turn off LACP), specify
+.Ar static .
+In static mode, a member interface is made an active part of the
+link aggregate as long as the link status is active.
+.Pp
+To re-enable LACP mode, specify
+.Ar lacp .
+.El
+.Pp
+The following parameters are specific to IP tunnel interfaces,
+.Xr gif 4 :
+.Bl -tag -width indent
+.It Cm tunnel Ar src_addr dest_addr
+Configure the physical source and destination address for IP tunnel
+interfaces.
+The arguments
+.Ar src_addr
+and
+.Ar dest_addr
+are interpreted as the outer source/destination for the encapsulating
+IPv4/IPv6 header.
+.It Fl tunnel
+Unconfigure the physical source and destination address for IP tunnel
+interfaces previously configured with
+.Cm tunnel .
+.It Cm deletetunnel
+Another name for the
+.Fl tunnel
+parameter.
+.El
+.Pp
+The following parameters are specific to bridge interfaces:
+.Bl -tag -width indent
+.It Cm addm Ar interface
+Add the interface named by
+.Ar interface
+as a member of the bridge.
+The interface is put into promiscuous mode
+so that it can receive every packet sent on the network.
+.It Cm deletem Ar interface
+Remove the interface named by
+.Ar interface
+from the bridge.
+Promiscuous mode is disabled on the interface when
+it is removed from the bridge.
+.It Cm maxaddr Ar size
+Set the size of the bridge address cache to
+.Ar size .
+The default is 100 entries.
+.It Cm timeout Ar seconds
+Set the timeout of address cache entries to
+.Ar seconds
+seconds.
+If
+.Ar seconds
+is zero, then address cache entries will not be expired.
+The default is 240 seconds.
+.It Cm addr
+Display the addresses that have been learned by the bridge.
+.It Cm static Ar interface-name Ar address
+Add a static entry into the address cache pointing to
+.Ar interface-name .
+Static entries are never aged out of the cache or re-placed, even if the
+address is seen on a different interface.
+.It Cm deladdr Ar address
+Delete
+.Ar address
+from the address cache.
+.It Cm flush
+Delete all dynamically-learned addresses from the address cache.
+.It Cm flushall
+Delete all addresses, including static addresses, from the address cache.
+.It Cm discover Ar interface
+Mark an interface as a
+.Dq discovering
+interface.
+When the bridge has no address cache entry
+(either dynamic or static)
+for the destination address of a packet,
+the bridge will forward the packet to all
+member interfaces marked as
+.Dq discovering .
+This is the default for all interfaces added to a bridge.
+.It Cm -discover Ar interface
+Clear the
+.Dq discovering
+attribute on a member interface.
+For packets without the
+.Dq discovering
+attribute, the only packets forwarded on the interface are broadcast
+or multicast packets and packets for which the destination address
+is known to be on the interface's segment.
+.It Cm learn Ar interface
+Mark an interface as a
+.Dq learning
+interface.
+When a packet arrives on such an interface, the source
+address of the packet is entered into the address cache as being a
+destination address on the interface's segment.
+This is the default for all interfaces added to a bridge.
+.It Cm -learn Ar interface
+Clear the
+.Dq learning
+attribute on a member interface.
+.\".It Cm sticky Ar interface
+.\"Mark an interface as a
+.\".Dq sticky
+.\"interface.
+.\"Dynamically learned address entries are treated at static once entered into
+.\"the cache.
+.\"Sticky entries are never aged out of the cache or replaced, even if the
+.\"address is seen on a different interface.
+.\".It Cm -sticky Ar interface
+.\"Clear the
+.\".Dq sticky
+.\"attribute on a member interface.
+.\".It Cm private Ar interface
+.\"Mark an interface as a
+.\".Dq private
+.\"interface.
+.\"A private interface does not forward any traffic to any other port that is also
+.\"a private interface.
+.\".It Cm -private Ar interface
+.\"Clear the
+.\".Dq private
+.\"attribute on a member interface.
+.\".It Cm span Ar interface
+.\"Add the interface named by
+.\".Ar interface
+.\"as a span port on the bridge.
+.\"Span ports transmit a copy of every frame received by the bridge.
+.\"This is most useful for snooping a bridged network passively on
+.\"another host connected to one of the span ports of the bridge.
+.\".It Cm -span Ar interface
+.\"Delete the interface named by
+.\".Ar interface
+.\"from the list of span ports of the bridge.
+.It Cm stp Ar interface
+Enable Spanning Tree protocol on
+.Ar interface .
+The
+.Xr if_bridge 4
+driver has support for the IEEE 802.1D Spanning Tree protocol (STP).
+Spanning Tree is used to detect and remove loops in a network topology.
+.It Cm -stp Ar interface
+Disable Spanning Tree protocol on
+.Ar interface .
+This is the default for all interfaces added to a bridge.
+.\".It Cm edge Ar interface
+.\"Set
+.\".Ar interface
+.\"as an edge port.
+.\"An edge port connects directly to end stations cannot create bridging
+.\"loops in the network, this allows it to transition straight to forwarding.
+.\".It Cm -edge Ar interface
+.\"Disable edge status on
+.\".Ar interface .
+.\".It Cm autoedge Ar interface
+.\"Allow
+.\".Ar interface
+.\"to automatically detect edge status.
+.\"This is the default for all interfaces added to a bridge.
+.\".It Cm -autoedge Ar interface
+.\"Disable automatic edge status on
+.\".Ar interface .
+.\".It Cm ptp Ar interface
+.\"Set the
+.\".Ar interface
+.\"as a point to point link.
+.\"This is required for straight transitions to forwarding and
+.\"should be enabled on a direct link to another RSTP capable switch.
+.\".It Cm -ptp Ar interface
+.\"Disable point to point link status on
+.\".Ar interface .
+.\"This should be disabled for a half duplex link and for an interface
+.\"connected to a shared network segment,
+.\"like a hub or a wireless network.
+.\".It Cm autoptp Ar interface
+.\"Automatically detect the point to point status on
+.\".Ar interface
+.\"by checking the full duplex link status.
+.\"This is the default for interfaces added to the bridge.
+.\".It Cm -autoptp Ar interface
+.\"Disable automatic point to point link detection on
+.\".Ar interface .
+.It Cm maxage Ar seconds
+Set the time that a Spanning Tree protocol configuration is valid.
+The default is 20 seconds.
+The minimum is 6 seconds and the maximum is 40 seconds.
+.It Cm fwddelay Ar seconds
+Set the time that must pass before an interface begins forwarding
+packets when Spanning Tree is enabled.
+The default is 15 seconds.
+The minimum is 4 seconds and the maximum is 30 seconds.
+.It Cm hellotime Ar seconds
+Set the time between broadcasting of Spanning Tree protocol
+configuration messages.
+The hello time may only be changed when operating in legacy stp mode.
+The default is 2 seconds.
+The minimum is 1 second and the maximum is 2 seconds.
+.It Cm priority Ar value
+Set the bridge priority for Spanning Tree.
+The default is 32768.
+The minimum is 0 and the maximum is 61440.
+.\".It Cm proto Ar value
+.\"Set the Spanning Tree protocol.
+.\"The default is rstp.
+.\"The available options are stp and rstp.
+.\".It Cm holdcnt Ar value
+.\"Set the transmit hold count for Spanning Tree.
+.\"This is the number of packets transmitted before being rate limited.
+.\"The default is 6.
+.\"The minimum is 1 and the maximum is 10.
+.It Cm ifpriority Ar interface Ar value
+Set the Spanning Tree priority of
+.Ar interface
+to
+.Ar value .
+The default is 128.
+The minimum is 0 and the maximum is 240.
+.It Cm ifpathcost Ar interface Ar value
+Set the Spanning Tree path cost of
+.Ar interface
+to
+.Ar value .
+The default is calculated from the link speed.
+To change a previously selected path cost back to automatic, set the
+cost to 0.
+The minimum is 1 and the maximum is 200000000.
+.It Cm ifmaxaddr Ar interface Ar size
+Set the maximum number of hosts allowed from an interface, packets with unknown
+source addresses are dropped until an existing host cache entry expires or is
+removed.
+Set to 0 to disable.
+.It Cm hostfilter Ar interface Ar address
+Configure the bridge to accept incoming packet on the interface
+only if they match the given MAC address and IP address
+-- use the command twice to set both type of addresses.
+Other filtering restrictions apply.
+.It Cm -hostfilter Ar interface
+Allow traffic from any host on that interface.
+.El
+.Pp
+The following parameters are specific to vlan interfaces:
+.Bl -tag -width indent
+.It Cm vlan Ar vlan_tag
+Set the VLAN tag value to
+.Ar vlan_tag .
+This value is a 16-bit number which is used to create an 802.1Q
+VLAN header for packets sent from the
+.Xr vlan 4
+interface.
+Note that
+.Cm vlan
+and
+.Cm vlandev
+must both be set at the same time.
+.It Cm vlandev Ar iface
+Associate the physical interface
+.Ar iface
+with a
+.Xr vlan 4
+interface.
+Packets transmitted through the
+.Xr vlan 4
+interface will be
+diverted to the specified physical interface
+.Ar iface
+with 802.1Q VLAN encapsulation.
+Packets with 802.1Q encapsulation received
+by the parent interface with the correct VLAN tag will be diverted to
+the associated
+.Xr vlan 4
+pseudo-interface.
+The
+.Xr vlan 4
+interface is assigned a
+copy of the parent interface's flags and the parent's ethernet address.
+The
+.Cm vlandev
+and
+.Cm vlan
+must both be set at the same time.
+If the
+.Xr vlan 4
+interface already has
+a physical interface associated with it, this command will fail.
+To
+change the association to another physical interface, the existing
+association must be cleared first.
+.Pp
+Note: if the hardware tagging capability
+is set on the parent interface, the
+.Xr vlan 4
+pseudo
+interface's behavior changes:
+the
+.Xr vlan 4
+interface recognizes that the
+parent interface supports insertion and extraction of VLAN tags on its
+own (usually in firmware) and that it should pass packets to and from
+the parent unaltered.
+.It Fl vlandev Op Ar iface
+If the driver is a
+.Xr vlan 4
+pseudo device, disassociate the parent interface from it.
+This breaks the link between the
+.Xr vlan 4
+interface and its parent,
+clears its VLAN tag, flags and its link address and shuts the interface down.
+The
+.Ar iface
+argument is useless and hence deprecated.
+.El
+.Pp
+The
+.Nm
+utility displays the current configuration for a network interface
+when no optional parameters are supplied.
+If a protocol family is specified,
+.Nm
+will report only the details specific to that protocol family.
+.Pp
+If the
+.Fl m
+flag is passed before an interface name,
+.Nm
+will display the capability list and all
+of the supported media for the specified interface.
+.Pp
+If
+.Fl L
+flag is supplied, address lifetime is displayed for IPv6 addresses,
+as time offset string.
+.Pp
+Optionally, the
+.Fl a
+flag may be used instead of an interface name.
+This flag instructs
+.Nm
+to display information about all interfaces in the system.
+The
+.Fl d
+flag limits this to interfaces that are down, and
+.Fl u
+limits this to interfaces that are up.
+When no arguments are given,
+.Fl a
+is implied.
+.Pp
+The
+.Fl l
+flag may be used to list all available interfaces on the system, with
+no other additional information.
+Use of this flag is mutually exclusive
+with all other flags and commands, except for
+.Fl d
+(only list interfaces that are down)
+and
+.Fl u
+(only list interfaces that are up).
+.Pp
+The
+.Fl v
+flag may be used to get more verbose status for an interface.
+.Pp
+The
+.Fl C
+flag may be used to list all of the interface cloners available on
+the system, with no additional information.
+Use of this flag is mutually exclusive with all other flags and commands.
+.Pp
+The
+.Fl r
+flag may be used to show additional information related to the count of route references on the network interface.
+.Pp
+For bridge interfaces, the list of addresses learned by the bridge is not shown when displaying information about
+all interfaces except when the
+.Fl v
+flag is used.
+.Pp
+Only the super-user may modify the configuration of a network interface.
+.Sh NOTES
+The media selection system is relatively new and only some drivers support
+it (or have need for it).
+.Sh EXAMPLES
+Assign the IPv4 address
+.Li 192.0.2.10 ,
+with a network mask of
+.Li 255.255.255.0 ,
+to the interface
+.Li en0 :
+.Dl # ifconfig en0 inet 192.0.2.10 netmask 255.255.255.0
+.Pp
+Add the IPv4 address
+.Li 192.0.2.45 ,
+with the CIDR network prefix
+.Li /28 ,
+to the interface
+.Li en0 ,
+using
+.Cm add
+as a synonym for the canonical form of the option
+.Cm alias :
+.Dl # ifconfig en0 inet 192.0.2.45/28 add
+.Pp
+Remove the IPv4 address
+.Li 192.0.2.45
+from the interface
+.Li en0 :
+.Dl # ifconfig en0 inet 192.0.2.45 -alias
+.Pp
+Add the IPv6 address
+.Li 2001:DB8:DBDB::123/48
+to the interface
+.Li en0 :
+.Dl # ifconfig en0 inet6 2001:db8:bdbd::123 prefixlen 48 alias
+Note that lower case hexadecimal IPv6 addresses are acceptable.
+.Pp
+Remove the IPv6 address added in the above example,
+using the
+.Li /
+character as shorthand for the network prefix,
+and using
+.Cm delete
+as a synonym for the canonical form of the option
+.Fl alias :
+.Dl # ifconfig en0 inet6 2001:db8:bdbd::123/48 delete
+.Pp
+Configure the interface
+.Li en1 ,
+to use 100baseTX, full duplex Ethernet media options:
+.Dl # ifconfig en1 media 100baseTX mediaopt full-duplex
+.Pp
+Create the software network interface
+.Li gif1 :
+.Dl # ifconfig gif1 create
+.Pp
+Destroy the software network interface
+.Li gif1 :
+.Dl # ifconfig gif1 destroy
+.Sh DIAGNOSTICS
+Messages indicating the specified interface does not exist, the
+requested address is unknown, or the user is not privileged and
+tried to alter an interface's configuration.
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr netintro 4 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.2 .
+.Sh BUGS
+Basic IPv6 node operation requires a link-local address on each
+interface configured for IPv6.
+Normally, such an address is automatically configured by the
+kernel on each interface added to the system; this behaviour may
+be disabled by setting the sysctl MIB variable
+.Va net.inet6.ip6.auto_linklocal
+to 0.
+.Pp
+If you delete such an address using
+.Nm ,
+the kernel may act very odd.
+Do this at your own risk.
diff --git a/network_cmds/ifconfig.tproj/ifconfig.c b/network_cmds/ifconfig.tproj/ifconfig.c
new file mode 100644
index 0000000..3449301
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifconfig.c
@@ -0,0 +1,2692 @@
+/*
+ * Copyright (c) 2009-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#ifndef __APPLE__
+#include <sys/module.h>
+#include <sys/linker.h>
+#endif
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_mib.h>
+#include <net/route.h>
+#include <net/pktsched/pktsched.h>
+#include <net/network_agent.h>
+
+/* IP */
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ifaddrs.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <syslog.h>
+
+#include "ifconfig.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+/*
+ * Since "struct ifreq" is composed of various union members, callers
+ * should pay special attention to interprete the value.
+ * (.e.g. little/big endian difference in the structure.)
+ */
+struct ifreq ifr;
+
+char name[IFNAMSIZ];
+int setaddr;
+int setmask;
+int doalias;
+int clearaddr;
+int newaddr = 1;
+int noload;
+int all;
+
+int bond_details = 0;
+int supmedia = 0;
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+int verbose = 1;
+int showrtref = 1;
+#else /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+int verbose = 0;
+int showrtref = 0;
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+int printkeys = 0; /* Print keying material for interfaces. */
+
+static int ifconfig(int argc, char *const *argv, int iscreate,
+ const struct afswtch *afp);
+static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
+ struct ifaddrs *ifa);
+static char *bytes_to_str(unsigned long long bytes);
+static char *bps_to_str(unsigned long long rate);
+static char *ns_to_str(unsigned long long nsec);
+static void tunnel_status(int s);
+static void clat46_addr(int s, char *name);
+static void nat64_status(int s, char *name);
+static void usage(void);
+static char *sched2str(unsigned int s);
+static char *tl2str(unsigned int s);
+static char *ift2str(unsigned int t, unsigned int f, unsigned int sf);
+static char *iffunct2str(u_int32_t functional_type);
+
+static struct afswtch *af_getbyname(const char *name);
+static struct afswtch *af_getbyfamily(int af);
+static void af_other_status(int);
+
+static struct option *opts = NULL;
+
+void
+opt_register(struct option *p)
+{
+ p->next = opts;
+ opts = p;
+}
+
+static void
+usage(void)
+{
+ char options[1024];
+ struct option *p;
+
+ /* XXX not right but close enough for now */
+ options[0] = '\0';
+ for (p = opts; p != NULL; p = p->next) {
+ strlcat(options, p->opt_usage, sizeof(options));
+ strlcat(options, " ", sizeof(options));
+ }
+
+ fprintf(stderr,
+ "usage: ifconfig %sinterface address_family [address [dest_address]]\n"
+ " [parameters]\n"
+ " ifconfig interface create\n"
+ " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n"
+ " ifconfig -l [-d] [-u] [address_family]\n"
+ " ifconfig %s[-d] [-m] [-u] [-v]\n",
+ options, options, options);
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c, namesonly, downonly, uponly;
+ const struct afswtch *afp = NULL;
+ int ifindex;
+ struct ifaddrs *ifap, *ifa;
+ struct ifreq paifr;
+ const struct sockaddr_dl *sdl;
+ char options[1024], *cp;
+ const char *ifname;
+ struct option *p;
+ size_t iflen;
+
+ all = downonly = uponly = namesonly = noload = 0;
+
+ /* Parse leading line options */
+#ifndef __APPLE__
+ strlcpy(options, "adklmnuv", sizeof(options));
+#else
+ strlcpy(options, "abdlmruv", sizeof(options));
+#endif
+ for (p = opts; p != NULL; p = p->next)
+ strlcat(options, p->opt, sizeof(options));
+ while ((c = getopt(argc, argv, options)) != -1) {
+ switch (c) {
+ case 'a': /* scan all interfaces */
+ all++;
+ break;
+ case 'b': /* bond detailed output */
+ bond_details++;
+ break;
+ case 'd': /* restrict scan to "down" interfaces */
+ downonly++;
+ break;
+#ifndef __APPLE__
+ case 'k':
+ printkeys++;
+ break;
+#endif
+ case 'l': /* scan interface names only */
+ namesonly++;
+ break;
+ case 'm': /* show media choices in status */
+ supmedia = 1;
+ break;
+#ifndef __APPLE__
+ case 'n': /* suppress module loading */
+ noload++;
+ break;
+#endif
+ case 'r':
+ showrtref++;
+ break;
+ case 'u': /* restrict scan to "up" interfaces */
+ uponly++;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ for (p = opts; p != NULL; p = p->next)
+ if (p->opt[0] == c) {
+ p->cb(optarg);
+ break;
+ }
+ if (p == NULL)
+ usage();
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* -l cannot be used with -a or -q or -m or -b */
+ if (namesonly &&
+ (all || supmedia || bond_details))
+ usage();
+
+ /* nonsense.. */
+ if (uponly && downonly)
+ usage();
+
+ /* no arguments is equivalent to '-a' */
+ if (!namesonly && argc < 1)
+ all = 1;
+
+ /* -a and -l allow an address family arg to limit the output */
+ if (all || namesonly) {
+ if (argc > 1)
+ usage();
+
+ ifname = NULL;
+ if (argc == 1) {
+ afp = af_getbyname(*argv);
+ if (afp == NULL)
+ usage();
+ if (afp->af_name != NULL)
+ argc--, argv++;
+ /* leave with afp non-zero */
+ }
+ } else {
+ /* not listing, need an argument */
+ if (argc < 1)
+ usage();
+
+ ifname = *argv;
+ argc--, argv++;
+
+#ifdef notdef
+ /* check and maybe load support for this interface */
+ ifmaybeload(ifname);
+#endif
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0) {
+ /*
+ * NOTE: We must special-case the `create' command
+ * right here as we would otherwise fail when trying
+ * to find the interface.
+ */
+ if (argc > 0 && (strcmp(argv[0], "create") == 0 ||
+ strcmp(argv[0], "plumb") == 0)) {
+ iflen = strlcpy(name, ifname, sizeof(name));
+ if (iflen >= sizeof(name))
+ errx(1, "%s: cloning name too long",
+ ifname);
+ ifconfig(argc, argv, 1, NULL);
+ exit(0);
+ }
+ errx(1, "interface %s does not exist", ifname);
+ }
+ }
+
+ /* Check for address family */
+ if (argc > 0) {
+ afp = af_getbyname(*argv);
+ if (afp != NULL)
+ argc--, argv++;
+ }
+
+ if (getifaddrs(&ifap) != 0)
+ err(EXIT_FAILURE, "getifaddrs");
+ cp = NULL;
+ ifindex = 0;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ memset(&paifr, 0, sizeof(paifr));
+ strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name));
+ if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) {
+ memcpy(&paifr.ifr_addr, ifa->ifa_addr,
+ ifa->ifa_addr->sa_len);
+ }
+
+ if (ifname != NULL && strcmp(ifname, ifa->ifa_name) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family == AF_LINK)
+ sdl = (const struct sockaddr_dl *) ifa->ifa_addr;
+ else
+ sdl = NULL;
+ if (cp != NULL && strcmp(cp, ifa->ifa_name) == 0)
+ continue;
+ iflen = strlcpy(name, ifa->ifa_name, sizeof(name));
+ if (iflen >= sizeof(name)) {
+ warnx("%s: interface name too long, skipping",
+ ifa->ifa_name);
+ continue;
+ }
+ cp = ifa->ifa_name;
+
+ if (downonly && (ifa->ifa_flags & IFF_UP) != 0)
+ continue;
+ if (uponly && (ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+ ifindex++;
+ /*
+ * Are we just listing the interfaces?
+ */
+ if (namesonly) {
+ if (ifindex > 1)
+ printf(" ");
+ fputs(name, stdout);
+ continue;
+ }
+
+ if (argc > 0)
+ ifconfig(argc, argv, 0, afp);
+ else
+ status(afp, sdl, ifa);
+ }
+ if (namesonly)
+ printf("\n");
+ freeifaddrs(ifap);
+
+ exit(0);
+}
+
+static struct afswtch *afs = NULL;
+
+void
+af_register(struct afswtch *p)
+{
+ p->af_next = afs;
+ afs = p;
+}
+
+static struct afswtch *
+af_getbyname(const char *name)
+{
+ struct afswtch *afp;
+
+ for (afp = afs; afp != NULL; afp = afp->af_next)
+ if (strcmp(afp->af_name, name) == 0)
+ return afp;
+ return NULL;
+}
+
+static struct afswtch *
+af_getbyfamily(int af)
+{
+ struct afswtch *afp;
+
+ for (afp = afs; afp != NULL; afp = afp->af_next)
+ if (afp->af_af == af)
+ return afp;
+ return NULL;
+}
+
+static void
+af_other_status(int s)
+{
+ struct afswtch *afp;
+ uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+ memset(afmask, 0, sizeof(afmask));
+ for (afp = afs; afp != NULL; afp = afp->af_next) {
+ if (afp->af_other_status == NULL)
+ continue;
+ if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+ continue;
+ afp->af_other_status(s);
+ setbit(afmask, afp->af_af);
+ }
+}
+
+static void
+af_all_tunnel_status(int s)
+{
+ struct afswtch *afp;
+ uint8_t afmask[howmany(AF_MAX, NBBY)];
+
+ memset(afmask, 0, sizeof(afmask));
+ for (afp = afs; afp != NULL; afp = afp->af_next) {
+ if (afp->af_status_tunnel == NULL)
+ continue;
+ if (afp->af_af != AF_UNSPEC && isset(afmask, afp->af_af))
+ continue;
+ afp->af_status_tunnel(s);
+ setbit(afmask, afp->af_af);
+ }
+}
+
+static struct cmd *cmds = NULL;
+
+void
+cmd_register(struct cmd *p)
+{
+ p->c_next = cmds;
+ cmds = p;
+}
+
+static const struct cmd *
+cmd_lookup(const char *name)
+{
+#define N(a) (sizeof(a)/sizeof(a[0]))
+ const struct cmd *p;
+
+ for (p = cmds; p != NULL; p = p->c_next)
+ if (strcmp(name, p->c_name) == 0)
+ return p;
+ return NULL;
+#undef N
+}
+
+struct callback {
+ callback_func *cb_func;
+ void *cb_arg;
+ struct callback *cb_next;
+};
+static struct callback *callbacks = NULL;
+
+void
+callback_register(callback_func *func, void *arg)
+{
+ struct callback *cb;
+
+ cb = malloc(sizeof(struct callback));
+ if (cb == NULL)
+ errx(1, "unable to allocate memory for callback");
+ cb->cb_func = func;
+ cb->cb_arg = arg;
+ cb->cb_next = callbacks;
+ callbacks = cb;
+}
+
+/* specially-handled commands */
+static void setifaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifaddr_cmd = DEF_CMD("ifaddr", 0, setifaddr);
+
+static void setifdstaddr(const char *, int, int, const struct afswtch *);
+static const struct cmd setifdstaddr_cmd =
+ DEF_CMD("ifdstaddr", 0, setifdstaddr);
+
+static int
+ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *afp)
+{
+ const struct afswtch *nafp;
+ struct callback *cb;
+ int ret, s;
+
+ strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+top:
+ if (afp == NULL)
+ afp = af_getbyname("inet");
+ ifr.ifr_addr.sa_family =
+ afp->af_af == AF_LINK || afp->af_af == AF_UNSPEC ?
+ AF_INET : afp->af_af;
+
+ if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family);
+
+ while (argc > 0) {
+ const struct cmd *p;
+
+ p = cmd_lookup(*argv);
+ if (p == NULL) {
+ /*
+ * Not a recognized command, choose between setting
+ * the interface address and the dst address.
+ */
+ p = (setaddr ? &setifdstaddr_cmd : &setifaddr_cmd);
+ }
+ if (p->c_u.c_func || p->c_u.c_func2) {
+ if (iscreate && !p->c_iscloneop) {
+ /*
+ * Push the clone create callback so the new
+ * device is created and can be used for any
+ * remaining arguments.
+ */
+ cb = callbacks;
+ if (cb == NULL)
+ errx(1, "internal error, no callback");
+ callbacks = cb->cb_next;
+ cb->cb_func(s, cb->cb_arg);
+ iscreate = 0;
+ /*
+ * Handle any address family spec that
+ * immediately follows and potentially
+ * recreate the socket.
+ */
+ nafp = af_getbyname(*argv);
+ if (nafp != NULL) {
+ argc--, argv++;
+ if (nafp != afp) {
+ close(s);
+ afp = nafp;
+ goto top;
+ }
+ }
+ }
+ if (p->c_parameter == NEXTARG) {
+ if (argv[1] == NULL)
+ errx(1, "'%s' requires argument",
+ p->c_name);
+ p->c_u.c_func(argv[1], 0, s, afp);
+ argc--, argv++;
+ } else if (p->c_parameter == OPTARG) {
+ p->c_u.c_func(argv[1], 0, s, afp);
+ if (argv[1] != NULL)
+ argc--, argv++;
+ } else if (p->c_parameter == NEXTARG2) {
+ if (argc < 3)
+ errx(1, "'%s' requires 2 arguments",
+ p->c_name);
+ p->c_u.c_func2(argv[1], argv[2], s, afp);
+ argc -= 2, argv += 2;
+ } else if (p->c_parameter == VAARGS) {
+ ret = p->c_u.c_funcv(argc - 1, argv + 1, s, afp);
+ if (ret < 0)
+ errx(1, "'%s' command error",
+ p->c_name);
+ argc -= ret, argv += ret;
+ } else {
+ p->c_u.c_func(*argv, p->c_parameter, s, afp);
+ }
+ }
+ argc--, argv++;
+ }
+
+ /*
+ * Do any post argument processing required by the address family.
+ */
+ if (afp->af_postproc != NULL)
+ afp->af_postproc(s, afp);
+ /*
+ * Do deferred callbacks registered while processing
+ * command-line arguments.
+ */
+ for (cb = callbacks; cb != NULL; cb = cb->cb_next)
+ cb->cb_func(s, cb->cb_arg);
+ /*
+ * Do deferred operations.
+ */
+ if (clearaddr) {
+ if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
+ warnx("interface %s cannot change %s addresses!",
+ name, afp->af_name);
+ clearaddr = 0;
+ }
+ }
+ if (clearaddr) {
+ strlcpy(afp->af_ridreq, name, sizeof ifr.ifr_name);
+ ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
+ if (ret < 0) {
+ if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
+ /* means no previous address for interface */
+ } else
+ Perror("ioctl (SIOCDIFADDR)");
+ }
+ }
+ if (newaddr) {
+ if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
+ warnx("interface %s cannot change %s addresses!",
+ name, afp->af_name);
+ newaddr = 0;
+ }
+ }
+ if (newaddr && (setaddr || setmask)) {
+ strlcpy(afp->af_addreq, name, sizeof ifr.ifr_name);
+ if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
+ Perror("ioctl (SIOCAIFADDR)");
+ }
+
+ close(s);
+ return(0);
+}
+
+/*ARGSUSED*/
+static void
+setifaddr(const char *addr, int param, int s, const struct afswtch *afp)
+{
+ if (afp->af_getaddr == NULL)
+ return;
+ /*
+ * Delay the ioctl to set the interface addr until flags are all set.
+ * The address interpretation may depend on the flags,
+ * and the flags may change when the address is set.
+ */
+ setaddr++;
+ if (doalias == 0 && afp->af_af != AF_LINK)
+ clearaddr = 1;
+ afp->af_getaddr(addr, (doalias >= 0 ? ADDR : RIDADDR));
+}
+
+static void
+settunnel(const char *src, const char *dst, int s, const struct afswtch *afp)
+{
+ struct addrinfo *srcres, *dstres;
+ int ecode;
+
+ if (afp->af_settunnel == NULL) {
+ warn("address family %s does not support tunnel setup",
+ afp->af_name);
+ return;
+ }
+
+ if ((ecode = getaddrinfo(src, NULL, NULL, &srcres)) != 0)
+ errx(1, "error in parsing address string: %s",
+ gai_strerror(ecode));
+
+ if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0)
+ errx(1, "error in parsing address string: %s",
+ gai_strerror(ecode));
+
+ if (srcres->ai_addr->sa_family != dstres->ai_addr->sa_family)
+ errx(1,
+ "source and destination address families do not match");
+
+ afp->af_settunnel(s, srcres, dstres);
+
+ freeaddrinfo(srcres);
+ freeaddrinfo(dstres);
+}
+
+/* ARGSUSED */
+static void
+deletetunnel(const char *vname, int param, int s, const struct afswtch *afp)
+{
+
+ if (ioctl(s, SIOCDIFPHYADDR, &ifr) < 0)
+ err(1, "SIOCDIFPHYADDR");
+}
+
+static void
+setifnetmask(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getaddr != NULL) {
+ setmask++;
+ afp->af_getaddr(addr, MASK);
+ }
+}
+
+static void
+setifbroadaddr(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getaddr != NULL)
+ afp->af_getaddr(addr, DSTADDR);
+}
+
+static void
+setifipdst(const char *addr, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ const struct afswtch *inet;
+
+ inet = af_getbyname("inet");
+ if (inet == NULL)
+ return;
+ inet->af_getaddr(addr, DSTADDR);
+ clearaddr = 0;
+ newaddr = 0;
+}
+
+static void
+notealias(const char *addr, int param, int s, const struct afswtch *afp)
+{
+#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
+ if (setaddr && doalias == 0 && param < 0)
+ if (afp->af_addreq != NULL && afp->af_ridreq != NULL)
+ bcopy((caddr_t)rqtosa(af_addreq),
+ (caddr_t)rqtosa(af_ridreq),
+ rqtosa(af_addreq)->sa_len);
+ doalias = param;
+ if (param < 0) {
+ clearaddr = 1;
+ newaddr = 0;
+ } else
+ clearaddr = 0;
+#undef rqtosa
+}
+
+/*ARGSUSED*/
+static void
+setifdstaddr(const char *addr, int param __unused, int s,
+ const struct afswtch *afp)
+{
+ if (afp->af_getaddr != NULL)
+ afp->af_getaddr(addr, DSTADDR);
+}
+
+/*
+ * Note: doing an SIOCIGIFFLAGS scribbles on the union portion
+ * of the ifreq structure, which may confuse other parts of ifconfig.
+ * Make a private copy so we can avoid that.
+ */
+static void
+setifflags(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ struct ifreq my_ifr;
+ int flags;
+
+ bcopy((char *)&ifr, (char *)&my_ifr, sizeof(struct ifreq));
+
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&my_ifr) < 0) {
+ Perror("ioctl (SIOCGIFFLAGS)");
+ exit(1);
+ }
+ strlcpy(my_ifr.ifr_name, name, sizeof (my_ifr.ifr_name));
+ flags = my_ifr.ifr_flags;
+
+ if (value < 0) {
+ value = -value;
+ flags &= ~value;
+ } else
+ flags |= value;
+ my_ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&my_ifr) < 0)
+ Perror(vname);
+}
+
+void
+setifcap(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ int flags;
+
+ if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) < 0) {
+ Perror("ioctl (SIOCGIFCAP)");
+ exit(1);
+ }
+ flags = ifr.ifr_curcap;
+ if (value < 0) {
+ value = -value;
+ flags &= ~value;
+ } else
+ flags |= value;
+ flags &= ifr.ifr_reqcap;
+ ifr.ifr_reqcap = flags;
+ if (ioctl(s, SIOCSIFCAP, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+static void
+setifmetric(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+ ifr.ifr_metric = atoi(val);
+ if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0)
+ warn("ioctl (set metric)");
+}
+
+static void
+setifmtu(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = atoi(val);
+ if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0)
+ warn("ioctl (set mtu)");
+}
+
+#ifndef __APPLE__
+static void
+setifname(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ char *newname;
+
+ newname = strdup(val);
+ if (newname == NULL) {
+ warn("no memory to set ifname");
+ return;
+ }
+ ifr.ifr_data = newname;
+ if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
+ warn("ioctl (set name)");
+ free(newname);
+ return;
+ }
+ strlcpy(name, newname, sizeof(name));
+ free(newname);
+}
+#endif
+
+static void
+setrouter(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ if (afp->af_setrouter == NULL) {
+ warn("address family %s does not support router mode",
+ afp->af_name);
+ return;
+ }
+
+ afp->af_setrouter(s, value);
+}
+
+static int
+routermode(int argc, char *const *argv, int s, const struct afswtch *afp)
+{
+ return (*afp->af_routermode)(s, argc, argv);
+}
+
+
+static void
+setifdesc(const char *val, int dummy __unused, int s, const struct afswtch *afp)
+{
+ struct if_descreq ifdr;
+
+ bzero(&ifdr, sizeof (ifdr));
+ strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
+ ifdr.ifdr_len = strlen(val);
+ strlcpy((char *)ifdr.ifdr_desc, val, sizeof (ifdr.ifdr_desc));
+
+ if (ioctl(s, SIOCSIFDESC, (caddr_t)&ifdr) < 0) {
+ warn("ioctl (set desc)");
+ }
+}
+
+static void
+settbr(const char *val, int dummy __unused, int s, const struct afswtch *afp)
+{
+ struct if_linkparamsreq iflpr;
+ long double bps;
+ u_int64_t rate;
+ u_int32_t percent = 0;
+ char *cp;
+
+ errno = 0;
+ bzero(&iflpr, sizeof (iflpr));
+ strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
+
+ bps = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid value '%s'", val);
+ return;
+ }
+ rate = (u_int64_t)bps;
+ if (cp != NULL) {
+ if (!strcmp(cp, "b") || !strcmp(cp, "bps")) {
+ ; /* nothing */
+ } else if (!strcmp(cp, "Kb") || !strcmp(cp, "Kbps")) {
+ rate *= 1000;
+ } else if (!strcmp(cp, "Mb") || !strcmp(cp, "Mbps")) {
+ rate *= 1000 * 1000;
+ } else if (!strcmp(cp, "Gb") || !strcmp(cp, "Gbps")) {
+ rate *= 1000 * 1000 * 1000;
+ } else if (!strcmp(cp, "%")) {
+ percent = rate;
+ if (percent == 0 || percent > 100) {
+ printf("Value out of range '%s'", val);
+ return;
+ }
+ } else if (*cp != '\0') {
+ printf("Unknown unit '%s'", cp);
+ return;
+ }
+ }
+ iflpr.iflpr_output_tbr_rate = rate;
+ iflpr.iflpr_output_tbr_percent = percent;
+ if (ioctl(s, SIOCSIFLINKPARAMS, &iflpr) < 0 &&
+ errno != ENOENT && errno != ENXIO && errno != ENODEV) {
+ warn("ioctl (set link params)");
+ } else if (errno == ENXIO) {
+ printf("TBR cannot be set on %s\n", name);
+ } else if (errno == 0 && rate == 0) {
+ printf("%s: TBR is now disabled\n", name);
+ } else if (errno == ENODEV) {
+ printf("%s: requires absolute TBR rate\n", name);
+ } else if (percent != 0) {
+ printf("%s: TBR rate set to %u%% of effective link rate\n",
+ name, percent);
+ } else {
+ printf("%s: TBR rate set to %s\n", name, bps_to_str(rate));
+ }
+}
+
+static int
+get_int64(uint64_t *i, char const *s)
+{
+ char *cp;
+ *i = strtol(s, &cp, 10);
+ if (cp == s || errno != 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+get_int32(uint32_t *i, char const *s)
+{
+ char *cp;
+ *i = strtol(s, &cp, 10);
+ if (cp == s || errno != 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+get_percent(double *d, const char *s)
+{
+ char *cp;
+ *d = strtod(s, &cp) / (double)100;
+ if (*d == HUGE_VALF || *d == HUGE_VALL) {
+ return (-1);
+ }
+ if (*d == 0.0 || (*cp != '\0' && strcmp(cp, "%") != 0)) {
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+get_percent_fixed_point(uint32_t *i, const char *s)
+{
+ double p;
+
+ if (get_percent(&p, s) != 0){
+ return (-1);
+ }
+
+ *i = p * IF_NETEM_PARAMS_PSCALE;
+ return (0);
+}
+
+static int
+netem_parse_args(struct if_netem_params *p, int argc, char *const *argv)
+{
+ int argc_saved = argc;
+ uint64_t bandwitdh = 0;
+ uint32_t latency = 0, jitter = 0;
+ uint32_t corruption = 0;
+ uint32_t duplication = 0;
+ uint32_t loss_p_gr_gl = 0, loss_p_gr_bl = 0, loss_p_bl_br = 0,
+ loss_p_bl_gr = 0, loss_p_br_bl = 0;
+ uint32_t reordering = 0;
+
+ bzero(p, sizeof (*p));
+
+ /* take out "input"/"output" */
+ argc--, argv++;
+
+ for ( ; argc > 0; ) {
+ if (strcmp(*argv, "bandwidth") == 0) {
+ argc--, argv++;
+ if (argc <= 0 || get_int64(&bandwitdh, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ argc--, argv++;
+ } else if (strcmp(*argv, "corruption") == 0) {
+ argc--, argv++;
+ if (argc <= 0 ||
+ get_percent_fixed_point(&corruption, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ argc--, argv++;
+ } else if (strcmp(*argv, "delay") == 0) {
+ argc--, argv++;
+ if (argc <= 0 || get_int32(&latency, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ argc--, argv++;
+ if (argc > 0 && get_int32(&jitter, *argv) == 0) {
+ argc--, argv++;
+ }
+ } else if (strcmp(*argv, "duplication") == 0) {
+ argc--, argv++;
+ if (argc <= 0 ||
+ get_percent_fixed_point(&duplication, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ return (-1);
+ }
+ argc--, argv++;
+ } else if (strcmp(*argv, "loss") == 0) {
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_gl, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ /* we may have all 5 probs, use naive model if not */
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_gr_bl, *argv) != 0) {
+ continue;
+ }
+ /* if more than p_gr_gl, then should have all probs */
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_br, *argv) != 0) {
+ err(1, "Invalid value '%s' for p_bl_br", *argv);
+ }
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_bl_gr, *argv) != 0) {
+ err(1, "Invalid value '%s' for p_bl_gr", *argv);
+ }
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&loss_p_br_bl, *argv) != 0) {
+ err(1, "Invalid value '%s' for p_br_bl", *argv);
+ }
+ argc--, argv++;
+ } else if (strcmp(*argv, "reordering") == 0) {
+ argc--, argv++;
+ if (argc <= 0 || get_percent_fixed_point(&reordering, *argv) != 0) {
+ err(1, "Invalid value '%s'", *argv);
+ }
+ argc--, argv++;
+ } else {
+ return (-1);
+ }
+ }
+
+ if (corruption > IF_NETEM_PARAMS_PSCALE) {
+ err(1, "corruption percentage > 100%%");
+ }
+
+ if (duplication > IF_NETEM_PARAMS_PSCALE) {
+ err(1, "duplication percentage > 100%%");
+ }
+
+ if (duplication > 0 && latency == 0) {
+ /* we need to insert dup'ed packet with latency */
+ err(1, "duplication needs latency param");
+ }
+
+ if (latency > 1000) {
+ err(1, "latency %dms too big (> 1 sec)", latency);
+ }
+
+ if (jitter * 3 > latency) {
+ err(1, "jitter %dms too big (latency %dms)", jitter, latency);
+ }
+
+ /* if gr_gl == 0 (no loss), other prob should all be zero */
+ if (loss_p_gr_gl == 0 &&
+ (loss_p_gr_bl != 0 || loss_p_bl_br != 0 || loss_p_bl_gr != 0 ||
+ loss_p_br_bl != 0)) {
+ err(1, "loss params not all zero when gr_gl is zero");
+ }
+
+ /* check state machine transition prob integrity */
+ if (loss_p_gr_gl > IF_NETEM_PARAMS_PSCALE ||
+ /* gr_gl = IF_NETEM_PARAMS_PSCALE for total loss */
+ loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_bl_br > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_br_bl > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_gr_gl + loss_p_gr_bl > IF_NETEM_PARAMS_PSCALE ||
+ loss_p_bl_br + loss_p_bl_gr > IF_NETEM_PARAMS_PSCALE) {
+ err(1, "loss params too big");
+ }
+
+ if (reordering > IF_NETEM_PARAMS_PSCALE) {
+ err(1, "reordering percentage > 100%%");
+ }
+
+ p->ifnetem_bandwidth_bps = bandwitdh;
+ p->ifnetem_latency_ms = latency;
+ p->ifnetem_jitter_ms = jitter;
+ p->ifnetem_corruption_p = corruption;
+ p->ifnetem_duplication_p = duplication;
+ p->ifnetem_loss_p_gr_gl = loss_p_gr_gl;
+ p->ifnetem_loss_p_gr_bl = loss_p_gr_bl;
+ p->ifnetem_loss_p_bl_br = loss_p_bl_br;
+ p->ifnetem_loss_p_bl_gr = loss_p_bl_gr;
+ p->ifnetem_loss_p_br_bl = loss_p_br_bl;
+ p->ifnetem_reordering_p = reordering;
+
+ return (argc_saved - argc);
+}
+
+void
+print_netem_params(struct if_netem_params *p, const char *desc)
+{
+ struct if_netem_params zero_params;
+ double pscale = IF_NETEM_PARAMS_PSCALE / 100;
+ bzero(&zero_params, sizeof (zero_params));
+
+ if (memcmp(p, &zero_params, sizeof (zero_params)) == 0) {
+ printf("%s NetEm Disabled\n\n", desc);
+ } else {
+ printf(
+ "%s NetEm Parameters\n"
+ "\tbandwidth rate %llubps\n"
+ "\tdelay latency %dms\n"
+ "\t jitter %dms\n",
+ desc, p->ifnetem_bandwidth_bps,
+ p->ifnetem_latency_ms, p->ifnetem_jitter_ms);
+ if (p->ifnetem_loss_p_gr_bl == 0 &&
+ p->ifnetem_loss_p_bl_br == 0 &&
+ p->ifnetem_loss_p_bl_gr == 0 &&
+ p->ifnetem_loss_p_br_bl == 0) {
+ printf(
+ "\tloss %.3f%%\n",
+ (double) p->ifnetem_loss_p_gr_gl / pscale);
+ } else {
+ printf(
+ "\tloss GAP_RECV -> GAP_LOSS %.3f%%\n"
+ "\t GAP_RECV -> BURST_LOSS %.3f%%\n"
+ "\t BURST_LOSS -> BURST_RECV %.3f%%\n"
+ "\t BURST_LOSS -> GAP_RECV %.3f%%\n"
+ "\t BURST_RECV -> BURST_LOSS %.3f%%\n",
+ (double) p->ifnetem_loss_p_gr_gl / pscale,
+ (double) p->ifnetem_loss_p_gr_bl / pscale,
+ (double) p->ifnetem_loss_p_bl_br / pscale,
+ (double) p->ifnetem_loss_p_bl_gr / pscale,
+ (double) p->ifnetem_loss_p_br_bl / pscale);
+ }
+ printf(
+ "\tcorruption %.3f%%\n"
+ "\treordering %.3f%%\n\n",
+ (double) p->ifnetem_corruption_p / pscale,
+ (double) p->ifnetem_reordering_p / pscale);
+ }
+}
+
+static int
+setnetem(int argc, char *const *argv, int s, const struct afswtch *afp)
+{
+ struct if_linkparamsreq iflpr;
+ struct if_netem_params input_params, output_params;
+ int ret = 0, error = 0;
+
+ bzero(&iflpr, sizeof (iflpr));
+ bzero(&input_params, sizeof (input_params));
+ bzero(&output_params, sizeof (output_params));
+
+ if (argc > 1) {
+ if (strcmp(argv[0], "input") == 0) {
+ ret = netem_parse_args(&input_params, argc, argv);
+ } else if (strcmp(argv[0], "output") == 0) {
+ ret = netem_parse_args(&output_params, argc, argv);
+ } else if (strcmp(argv[0], "-h") == 0 || strcmp(argv[0], "--help") == 0) {
+ goto bad_args;
+ } else {
+ fprintf(stderr, "uknown option %s\n", argv[0]);
+ goto bad_args;
+ }
+ if (ret < 0) {
+ goto bad_args;
+ }
+ }
+
+ errno = 0;
+ strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
+ error = ioctl(s, SIOCGIFLINKPARAMS, &iflpr);
+ if (error < 0) {
+ warn("ioctl (get link params)");
+ }
+
+ if (argc == 0) {
+ print_netem_params(&iflpr.iflpr_input_netem, "Input");
+ print_netem_params(&iflpr.iflpr_output_netem, "Output");
+ return (0);
+ } else if (argc == 1) {
+ if (strcmp(argv[0], "input") == 0) {
+ bzero(&iflpr.iflpr_input_netem,
+ sizeof (iflpr.iflpr_input_netem));
+ } else if (strcmp(argv[0], "output") == 0) {
+ bzero(&iflpr.iflpr_output_netem,
+ sizeof (iflpr.iflpr_output_netem));
+ } else {
+ fprintf(stderr, "uknown option %s\n", argv[0]);
+ goto bad_args;
+ }
+ printf("%s: netem is now disabled for %s\n", name, argv[0]);
+ ret = 1;
+ } else {
+ if (strcmp(argv[0], "input") == 0) {
+ iflpr.iflpr_input_netem = input_params;
+ } else if (strcmp(argv[0], "output") == 0) {
+ iflpr.iflpr_output_netem = output_params;
+ }
+ }
+
+ error = ioctl(s, SIOCSIFLINKPARAMS, &iflpr);
+ if (error < 0 && errno != ENOENT && errno != ENXIO && errno != ENODEV) {
+ warn("ioctl (set link params)");
+ } else if (errno == ENXIO) {
+ printf("netem cannot be set on %s\n", name);
+ } else {
+ printf("%s: netem configured\n", name);
+ }
+
+ return (ret);
+bad_args:
+ fprintf(stderr, "Usage:\n"
+ "\tTo enable/set netem params\n"
+ "\t\tnetem <input|output>\n"
+ "\t\t [ bandwidth BIT_PER_SEC ]\n"
+ "\t\t [ delay DELAY_MSEC [ JITTER_MSEC ] ]\n"
+ "\t\t [ loss PERCENTAGE ]\n"
+ "\t\t [ duplication PERCENTAGE ]\n"
+ "\t\t [ reordering PERCENTAGE ]\n\n"
+ "\tTo disable <input|output> netem\n"
+ "\t\tnetem <input|output>\n\n"
+ "\tTo show current settings\n"
+ "\t\tnetem\n\n");
+ return (-1);
+}
+
+static void
+setthrottle(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ struct if_throttlereq iftr;
+ char *cp;
+
+ errno = 0;
+ bzero(&iftr, sizeof (iftr));
+ strlcpy(iftr.ifthr_name, name, sizeof (iftr.ifthr_name));
+
+ iftr.ifthr_level = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid value '%s'", val);
+ return;
+ }
+
+ if (ioctl(s, SIOCSIFTHROTTLE, &iftr) < 0 && errno != ENXIO) {
+ warn("ioctl (set throttling level)");
+ } else if (errno == ENXIO) {
+ printf("throttling level cannot be set on %s\n", name);
+ } else {
+ printf("%s: throttling level set to %d\n", name,
+ iftr.ifthr_level);
+ }
+}
+
+static void
+setdisableoutput(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ struct ifreq ifr;
+ char *cp;
+ errno = 0;
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+
+ ifr.ifr_ifru.ifru_disable_output = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid value '%s'", val);
+ return;
+ }
+
+ if (ioctl(s, SIOCSIFDISABLEOUTPUT, &ifr) < 0 && errno != ENXIO) {
+ warn("ioctl set disable output");
+ } else if (errno == ENXIO) {
+ printf("output thread can not be disabled on %s\n", name);
+ } else {
+ printf("output %s on %s\n",
+ ((ifr.ifr_ifru.ifru_disable_output == 0) ? "enabled" : "disabled"),
+ name);
+ }
+}
+
+static void
+setlog(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ char *cp;
+
+ errno = 0;
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ ifr.ifr_log.ifl_level = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid value '%s'", val);
+ return;
+ }
+ ifr.ifr_log.ifl_flags = (IFRLOGF_DLIL|IFRLOGF_FAMILY|IFRLOGF_DRIVER|
+ IFRLOGF_FIRMWARE);
+
+ if (ioctl(s, SIOCSIFLOG, &ifr) < 0)
+ warn("ioctl (set logging parameters)");
+}
+
+void
+setcl2k(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_2kcl = value;
+
+ if (ioctl(s, SIOCSIF2KCL, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+void
+setexpensive(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_expensive = value;
+
+ if (ioctl(s, SIOCSIFEXPENSIVE, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+#ifdef SIOCSIFCONSTRAINED
+void
+setconstrained(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_constrained = value;
+
+ if (ioctl(s, SIOCSIFCONSTRAINED, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+#endif
+
+static void
+setifmpklog(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_mpk_log = value;
+
+ if (ioctl(s, SIOCSIFMPKLOG, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+void
+settimestamp(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (value == 0) {
+ if (ioctl(s, SIOCSIFTIMESTAMPDISABLE, (caddr_t)&ifr) < 0)
+ Perror(vname);
+ } else {
+ if (ioctl(s, SIOCSIFTIMESTAMPENABLE, (caddr_t)&ifr) < 0)
+ Perror(vname);
+ }
+}
+
+void
+setecnmode(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ char *cp;
+
+ if (strcmp(val, "default") == 0)
+ ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DEFAULT;
+ else if (strcmp(val, "enable") == 0)
+ ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_ENABLE;
+ else if (strcmp(val, "disable") == 0)
+ ifr.ifr_ifru.ifru_ecn_mode = IFRTYPE_ECN_DISABLE;
+ else {
+ ifr.ifr_ifru.ifru_ecn_mode = strtold(val, &cp);
+ if (val == cp || errno != 0) {
+ warn("Invalid ECN mode value '%s'", val);
+ return;
+ }
+ }
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ioctl(s, SIOCSECNMODE, (caddr_t)&ifr) < 0)
+ Perror("ioctl(SIOCSECNMODE)");
+}
+
+void
+setprobeconnectivity(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_ifru.ifru_probe_connectivity = value;
+
+ if (ioctl(s, SIOCSIFPROBECONNECTIVITY, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+#if defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED)
+
+void
+setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp)
+{
+ u_long ioc;
+
+#if (DEBUG | DEVELOPMENT)
+ printf("%s(%s, %s)\n", __func__, cmd, arg);
+#endif /* (DEBUG | DEVELOPMENT) */
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (strcmp(cmd, "mode") == 0) {
+ ioc = SIOCSQOSMARKINGMODE;
+
+ if (strcmp(arg, "fastlane") == 0)
+ ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_FASTLANE;
+ else if (strcmp(arg, "rfc4594") == 0)
+ ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_RFC4594;
+ else if (strcasecmp(arg, "none") == 0 || strcasecmp(arg, "off") == 0)
+ ifr.ifr_qosmarking_mode = IFRTYPE_QOSMARKING_MODE_NONE;
+ else
+ err(EX_USAGE, "bad value for qosmarking mode: %s", arg);
+ } else if (strcmp(cmd, "enabled") == 0) {
+ ioc = SIOCSQOSMARKINGENABLED;
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ ifr.ifr_qosmarking_enabled = 1;
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ ifr.ifr_qosmarking_enabled = 0;
+ else
+ err(EX_USAGE, "bad value for qosmarking enabled: %s", arg);
+ } else {
+ err(EX_USAGE, "qosmarking takes mode or enabled");
+ }
+
+ if (ioctl(s, ioc, (caddr_t)&ifr) < 0)
+ err(EX_OSERR, "ioctl(%s, %s)", cmd, arg);
+}
+
+void
+setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ warnx("### fastlane is obsolete, use qosmarking ###");
+
+ if (strcmp(cmd, "capable") == 0) {
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ setqosmarking("mode", "fastlane", s, afp);
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ setqosmarking("mode", "off", s, afp);
+ else
+ err(EX_USAGE, "bad value for fastlane %s", cmd);
+ } else if (strcmp(cmd, "enable") == 0) {
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ setqosmarking("enabled", "1", s, afp);
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ setqosmarking("enabled", "0", s, afp);
+ else
+ err(EX_USAGE, "bad value for fastlane %s", cmd);
+ } else {
+ err(EX_USAGE, "fastlane takes capable or enable");
+ }
+}
+
+#else /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */
+
+void
+setfastlane(const char *cmd, const char *arg, int s, const struct afswtch *afp)
+{
+ int value;
+ u_long ioc;
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (strcmp(cmd, "capable") == 0)
+ ioc = SIOCSFASTLANECAPABLE;
+ else if (strcmp(cmd, "enable") == 0)
+ ioc = SIOCSFASTLEENABLED;
+ else
+ err(EX_USAGE, "fastlane takes capable or enabled");
+
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ value = 1;
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ value = 0;
+ else
+ err(EX_USAGE, "bad value for fastlane %s", cmd);
+
+ if (ioc == SIOCSFASTLANECAPABLE)
+ ifr.ifr_fastlane_capable = value;
+ else
+ ifr.ifr_fastlane_enabled = value;
+
+ if (ioctl(s, ioc, (caddr_t)&ifr) < 0)
+ err(EX_OSERR, "ioctl(%s, %s)", cmd, arg);
+}
+
+
+void
+setqosmarking(const char *cmd, const char *arg, int s, const struct afswtch *afp)
+{
+ if (strcmp(cmd, "mode") == 0) {
+ if (strcmp(arg, "fastlane") == 0)
+ setfastlane("capable", "on", s, afp);
+ else if (strcmp(arg, "none") == 0)
+ setfastlane("capable", "off", s, afp);
+ else
+ err(EX_USAGE, "bad value for qosmarking mode: %s", arg);
+ } else if (strcmp(cmd, "enabled") == 0) {
+ if (strcmp(arg, "1") == 0 || strcasecmp(arg, "on") == 0||
+ strcasecmp(arg, "yes") == 0 || strcasecmp(arg, "true") == 0)
+ setfastlane("enable", "on", s, afp);
+ else if (strcmp(arg, "0") == 0 || strcasecmp(arg, "off") == 0||
+ strcasecmp(arg, "no") == 0 || strcasecmp(arg, "false") == 0)
+ setfastlane("enable", "off", s, afp);
+ else
+ err(EX_USAGE, "bad value for qosmarking enabled: %s", arg);
+ } else {
+ err(EX_USAGE, "qosmarking takes mode or enabled");
+ }
+}
+
+#endif /* defined(SIOCSQOSMARKINGMODE) && defined(SIOCSQOSMARKINGENABLED) */
+
+void
+setlowpowermode(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_low_power_mode = !!value;
+
+ if (ioctl(s, SIOCSIFLOWPOWER, (caddr_t)&ifr) < 0)
+ Perror(vname);
+}
+
+struct str2num {
+ const char *str;
+ uint32_t num;
+};
+
+static struct str2num subfamily_str2num[] = {
+ { .str = "any", .num = IFRTYPE_SUBFAMILY_ANY },
+ { .str = "USB", .num = IFRTYPE_SUBFAMILY_USB },
+ { .str = "Bluetooth", .num = IFRTYPE_SUBFAMILY_BLUETOOTH },
+ { .str = "Wi-Fi", .num = IFRTYPE_SUBFAMILY_WIFI },
+ { .str = "wifi", .num = IFRTYPE_SUBFAMILY_WIFI },
+ { .str = "Thunderbolt", .num = IFRTYPE_SUBFAMILY_THUNDERBOLT },
+ { .str = "reserverd", .num = IFRTYPE_SUBFAMILY_RESERVED },
+ { .str = "intcoproc", .num = IFRTYPE_SUBFAMILY_INTCOPROC },
+ { .str = "QuickRelay", .num = IFRTYPE_SUBFAMILY_QUICKRELAY },
+ { .str = "Default", .num = IFRTYPE_SUBFAMILY_DEFAULT },
+ { .str = NULL, .num = 0 },
+};
+
+static uint32_t
+get_num_from_str(struct str2num* str2nums, const char *str)
+{
+ struct str2num *str2num = str2nums;
+
+ while (str2num != NULL && str2num->str != NULL) {
+ if (strcasecmp(str2num->str, str) == 0) {
+ return str2num->num;
+ }
+ str2num++;
+ }
+ return 0;
+}
+
+static void
+setifsubfamily(const char *val, int dummy __unused, int s,
+ const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
+
+ char *endptr;
+ uint32_t subfamily = strtoul(val, &endptr, 0);
+ if (*endptr != 0) {
+ subfamily = get_num_from_str(subfamily_str2num, val);
+ if (subfamily == 0) {
+ return;
+ }
+ }
+
+ ifr.ifr_type.ift_subfamily = subfamily;
+ if (ioctl(s, SIOCSIFSUBFAMILY, (caddr_t)&ifr) < 0)
+ warn("ioctl(SIOCSIFSUBFAMILY)");
+}
+
+void
+setifavailability(const char *vname, int value, int s, const struct afswtch *afp)
+{
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_interface_state.valid_bitmask = IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID;
+ if (value == 0) {
+ ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE;
+ } else {
+ ifr.ifr_interface_state.interface_availability = IF_INTERFACE_STATE_INTERFACE_AVAILABLE;
+ }
+ if (ioctl(s, SIOCSIFINTERFACESTATE, (caddr_t)&ifr) < 0)
+ warn("ioctl(SIOCSIFINTERFACESTATE)");
+}
+
+static void
+show_routermode(int s)
+{
+ struct afswtch *afp;
+
+ afp = af_getbyname("inet");
+ if (afp != NULL) {
+ (*afp->af_routermode)(s, 0, NULL);
+ }
+}
+
+static void
+show_routermode6(void)
+{
+ struct afswtch *afp;
+ static int s = -1;
+
+ afp = af_getbyname("inet6");
+ if (afp != NULL) {
+ if (s < 0) {
+ s = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return;
+ }
+ }
+ (*afp->af_routermode)(s, 0, NULL);
+ }
+}
+
+#define IFFBITS \
+"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
+"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
+"\20MULTICAST"
+
+#define IFEFBITS \
+"\020\1AUTOCONFIGURING\4PROBE_CONNECTIVITY\5FASTLN_CAP\6IPV6_DISABLED\7ACCEPT_RTADV\10TXSTART\11RXPOLL" \
+"\12VLAN\13BOND\14ARPLL\15CLAT46\16NOAUTOIPV6LL\17EXPENSIVE\20ROUTER4" \
+"\22LOCALNET_PRIVATE\23ND6ALT\24RESTRICTED_RECV\25AWDL\26NOACKPRI" \
+"\27AWDL_RESTRICTED\30CL2K\31ECN_ENABLE\32ECN_DISABLE\33CHANNEL_DRV\34CA" \
+"\35SENDLIST\36DIRECTLINK\37FASTLN_ON\40UPDOWNCHANGE"
+
+#define IFXFBITS \
+"\020\1WOL\2TIMESTAMP\3NOAUTONX\4LEGACY\5TXLOWINET\6RXLOWINET\7ALLOCKPI" \
+"\10LOWPOWER\11MPKLOG\12CONSTRAINED"
+
+#define IFCAPBITS \
+"\020\1RXCSUM\2TXCSUM\3VLAN_MTU\4VLAN_HWTAGGING\5JUMBO_MTU" \
+"\6TSO4\7TSO6\10LRO\11AV\12TXSTATUS\13CHANNEL_IO\14HW_TIMESTAMP\15SW_TIMESTAMP" \
+"\16PARTIAL_CSUM\17ZEROINVERT_CSUM"
+
+#define IFRLOGF_BITS \
+"\020\1DLIL\21FAMILY\31DRIVER\35FIRMWARE"
+
+/*
+ * Print the status of the interface. If an address family was
+ * specified, show only it; otherwise, show them all.
+ */
+static void
+status(const struct afswtch *afp, const struct sockaddr_dl *sdl,
+ struct ifaddrs *ifa)
+{
+ struct ifaddrs *ift;
+ int allfamilies, s;
+ struct ifstat ifs;
+ struct if_descreq ifdr;
+ struct if_linkparamsreq iflpr;
+ int mib[6];
+ struct ifmibdata_supplemental ifmsupp;
+ size_t miblen = sizeof(struct ifmibdata_supplemental);
+ u_int64_t eflags = 0;
+ u_int64_t xflags = 0;
+ int curcap = 0;
+
+ if (afp == NULL) {
+ allfamilies = 1;
+ afp = af_getbyname("inet");
+ } else
+ allfamilies = 0;
+
+ ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_INET : afp->af_af;
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
+ if (s < 0)
+ err(1, "socket(family %u,SOCK_DGRAM)", ifr.ifr_addr.sa_family);
+
+ printf("%s: ", name);
+ printb("flags", ifa->ifa_flags, IFFBITS);
+ if (ioctl(s, SIOCGIFMETRIC, &ifr) != -1)
+ if (ifr.ifr_metric)
+ printf(" metric %d", ifr.ifr_metric);
+ if (ioctl(s, SIOCGIFMTU, &ifr) != -1)
+ printf(" mtu %d", ifr.ifr_mtu);
+ if (showrtref && ioctl(s, SIOCGIFGETRTREFCNT, &ifr) != -1)
+ printf(" rtref %d", ifr.ifr_route_refcnt);
+ if (verbose) {
+ unsigned int ifindex = if_nametoindex(ifa->ifa_name);
+ if (ifindex != 0)
+ printf(" index %u", ifindex);
+ }
+#ifdef SIOCGIFCONSTRAINED
+ // Constrained is stored in if_xflags which isn't exposed directly
+ if (ioctl(s, SIOCGIFCONSTRAINED, (caddr_t)&ifr) == 0 &&
+ ifr.ifr_constrained != 0) {
+ printf(" constrained");
+ }
+#endif
+ putchar('\n');
+
+ if (verbose && ioctl(s, SIOCGIFEFLAGS, (caddr_t)&ifr) != -1 &&
+ (eflags = ifr.ifr_eflags) != 0) {
+ printb("\teflags", eflags, IFEFBITS);
+ putchar('\n');
+ }
+
+ if (verbose && ioctl(s, SIOCGIFXFLAGS, (caddr_t)&ifr) != -1 &&
+ (xflags = ifr.ifr_xflags) != 0) {
+ printb("\txflags", xflags, IFXFBITS);
+ putchar('\n');
+ }
+
+ if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) == 0) {
+ if (ifr.ifr_curcap != 0) {
+ curcap = ifr.ifr_curcap;
+ printb("\toptions", ifr.ifr_curcap, IFCAPBITS);
+ putchar('\n');
+ }
+ if (supmedia && ifr.ifr_reqcap != 0) {
+ printb("\tcapabilities", ifr.ifr_reqcap, IFCAPBITS);
+ putchar('\n');
+ }
+ }
+
+ tunnel_status(s);
+
+ for (ift = ifa; ift != NULL; ift = ift->ifa_next) {
+ if (ift->ifa_addr == NULL)
+ continue;
+ if (strcmp(ifa->ifa_name, ift->ifa_name) != 0)
+ continue;
+ if (allfamilies) {
+ const struct afswtch *p;
+ p = af_getbyfamily(ift->ifa_addr->sa_family);
+ if (p != NULL && p->af_status != NULL)
+ p->af_status(s, ift);
+ } else if (afp->af_af == ift->ifa_addr->sa_family)
+ afp->af_status(s, ift);
+ }
+
+/* Print CLAT46 address */
+ clat46_addr(s, name);
+
+/* Print NAT64 prefix */
+ nat64_status(s, name);
+
+#if 0
+ if (allfamilies || afp->af_af == AF_LINK) {
+ const struct afswtch *lafp;
+
+ /*
+ * Hack; the link level address is received separately
+ * from the routing information so any address is not
+ * handled above. Cobble together an entry and invoke
+ * the status method specially.
+ */
+ lafp = af_getbyname("lladdr");
+ if (lafp != NULL) {
+ info.rti_info[RTAX_IFA] = (struct sockaddr *)sdl;
+ lafp->af_status(s, &info);
+ }
+ }
+#endif
+ if (allfamilies)
+ af_other_status(s);
+ else if (afp->af_other_status != NULL)
+ afp->af_other_status(s);
+
+ strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name);
+ if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0)
+ printf("%s", ifs.ascii);
+
+ /* The rest is for when verbose is set; if not set, we're done */
+ if (!verbose)
+ goto done;
+
+ if (ioctl(s, SIOCGIFTYPE, &ifr) != -1) {
+ char *c = ift2str(ifr.ifr_type.ift_type,
+ ifr.ifr_type.ift_family, ifr.ifr_type.ift_subfamily);
+ if (c != NULL)
+ printf("\ttype: %s\n", c);
+ }
+
+ if (verbose > 1) {
+ if (ioctl(s, SIOCGIFFUNCTIONALTYPE, &ifr) != -1) {
+ char *c = iffunct2str(ifr.ifr_functional_type);
+ if (c != NULL)
+ printf("\tfunctional type: %s\n", c);
+ }
+ }
+ {
+ struct if_agentidsreq ifar;
+ memset(&ifar, 0, sizeof(ifar));
+
+ strlcpy(ifar.ifar_name, name, sizeof(ifar.ifar_name));
+
+ if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != -1) {
+ if (ifar.ifar_count != 0) {
+ ifar.ifar_uuids = calloc(ifar.ifar_count, sizeof(uuid_t));
+ if (ifar.ifar_uuids != NULL) {
+ if (ioctl(s, SIOCGIFAGENTIDS, &ifar) != 1) {
+ for (int agent_i = 0; agent_i < ifar.ifar_count; agent_i++) {
+ struct netagent_req nar;
+ memset(&nar, 0, sizeof(nar));
+
+ uuid_copy(nar.netagent_uuid, ifar.ifar_uuids[agent_i]);
+
+ if (ioctl(s, SIOCGIFAGENTDATA, &nar) != 1) {
+ printf("\tagent domain:%s type:%s flags:0x%x desc:\"%s\"\n",
+ nar.netagent_domain, nar.netagent_type,
+ nar.netagent_flags, nar.netagent_desc);
+ }
+ }
+ }
+ free(ifar.ifar_uuids);
+ }
+ }
+ }
+ }
+
+ if (ioctl(s, SIOCGIFLINKQUALITYMETRIC, &ifr) != -1) {
+ int lqm = ifr.ifr_link_quality_metric;
+ if (verbose > 1) {
+ printf("\tlink quality: %d ", lqm);
+ if (lqm == IFNET_LQM_THRESH_OFF)
+ printf("(off)");
+ else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
+ printf("(unknown)");
+ else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
+ lqm <= IFNET_LQM_THRESH_BAD)
+ printf("(bad)");
+ else if (lqm > IFNET_LQM_THRESH_UNKNOWN &&
+ lqm <= IFNET_LQM_THRESH_POOR)
+ printf("(poor)");
+ else if (lqm > IFNET_LQM_THRESH_POOR &&
+ lqm <= IFNET_LQM_THRESH_GOOD)
+ printf("(good)");
+ else
+ printf("(?)");
+ printf("\n");
+ } else if (lqm > IFNET_LQM_THRESH_UNKNOWN) {
+ printf("\tlink quality: %d ", lqm);
+ if (lqm <= IFNET_LQM_THRESH_BAD)
+ printf("(bad)");
+ else if (lqm <= IFNET_LQM_THRESH_POOR)
+ printf("(poor)");
+ else if (lqm <= IFNET_LQM_THRESH_GOOD)
+ printf("(good)");
+ else
+ printf("(?)");
+ printf("\n");
+ }
+ }
+
+ {
+ if (ioctl(s, SIOCGIFINTERFACESTATE, &ifr) != -1) {
+ printf("\tstate");
+ if (ifr.ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_RRC_STATE_VALID) {
+ uint8_t rrc_state = ifr.ifr_interface_state.rrc_state;
+
+ printf(" rrc: %u ", rrc_state);
+ if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_CONNECTED)
+ printf("(connected)");
+ else if (rrc_state == IF_INTERFACE_STATE_RRC_STATE_IDLE)
+ printf("(idle)");
+ else
+ printf("(?)");
+ }
+ if (ifr.ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) {
+ uint8_t ifavail = ifr.ifr_interface_state.interface_availability;
+
+ printf(" availability: %u ", ifavail);
+ if (ifavail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE)
+ printf("(true)");
+ else if (ifavail == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE)
+ printf("(false)");
+ else
+ printf("(?)");
+ } else {
+ printf(" availability: (not valid)");
+ }
+ if (verbose > 1 &&
+ ifr.ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_LQM_STATE_VALID) {
+ int8_t lqm = ifr.ifr_interface_state.lqm_state;
+
+ printf(" lqm: %d", lqm);
+
+ if (lqm == IFNET_LQM_THRESH_OFF)
+ printf("(off)");
+ else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
+ printf("(unknown)");
+ else if (lqm == IFNET_LQM_THRESH_BAD)
+ printf("(bad)");
+ else if (lqm == IFNET_LQM_THRESH_POOR)
+ printf("(poor)");
+ else if (lqm == IFNET_LQM_THRESH_GOOD)
+ printf("(good)");
+ else
+ printf("(?)");
+ }
+ }
+ printf("\n");
+ }
+
+ bzero(&iflpr, sizeof (iflpr));
+ strlcpy(iflpr.iflpr_name, name, sizeof (iflpr.iflpr_name));
+ if (ioctl(s, SIOCGIFLINKPARAMS, &iflpr) != -1) {
+ u_int64_t ibw_max = iflpr.iflpr_input_bw.max_bw;
+ u_int64_t ibw_eff = iflpr.iflpr_input_bw.eff_bw;
+ u_int64_t obw_max = iflpr.iflpr_output_bw.max_bw;
+ u_int64_t obw_eff = iflpr.iflpr_output_bw.eff_bw;
+ u_int64_t obw_tbr = iflpr.iflpr_output_tbr_rate;
+ u_int32_t obw_pct = iflpr.iflpr_output_tbr_percent;
+ u_int64_t ilt_max = iflpr.iflpr_input_lt.max_lt;
+ u_int64_t ilt_eff = iflpr.iflpr_input_lt.eff_lt;
+ u_int64_t olt_max = iflpr.iflpr_output_lt.max_lt;
+ u_int64_t olt_eff = iflpr.iflpr_output_lt.eff_lt;
+
+
+ if (eflags & IFEF_TXSTART) {
+ u_int32_t flags = iflpr.iflpr_flags;
+ u_int32_t sched = iflpr.iflpr_output_sched;
+ struct if_throttlereq iftr;
+
+ printf("\tscheduler: %s%s ",
+ (flags & IFLPRF_ALTQ) ? "ALTQ_" : "",
+ sched2str(sched));
+ if (flags & IFLPRF_DRVMANAGED)
+ printf("(driver managed)");
+ printf("\n");
+
+ bzero(&iftr, sizeof (iftr));
+ strlcpy(iftr.ifthr_name, name,
+ sizeof (iftr.ifthr_name));
+ if (ioctl(s, SIOCGIFTHROTTLE, &iftr) != -1 &&
+ iftr.ifthr_level != IFNET_THROTTLE_OFF)
+ printf("\tthrottling: level %d (%s)\n",
+ iftr.ifthr_level, tl2str(iftr.ifthr_level));
+ }
+
+ if (obw_tbr != 0 && obw_eff > obw_tbr)
+ obw_eff = obw_tbr;
+
+ if (ibw_max != 0 || obw_max != 0) {
+ if (ibw_max == obw_max && ibw_eff == obw_eff &&
+ ibw_max == ibw_eff && obw_tbr == 0) {
+ printf("\tlink rate: %s\n",
+ bps_to_str(ibw_max));
+ } else {
+ printf("\tuplink rate: %s [eff] / ",
+ bps_to_str(obw_eff));
+ if (obw_tbr != 0) {
+ if (obw_pct == 0)
+ printf("%s [tbr] / ",
+ bps_to_str(obw_tbr));
+ else
+ printf("%s [tbr %u%%] / ",
+ bps_to_str(obw_tbr),
+ obw_pct);
+ }
+ printf("%s", bps_to_str(obw_max));
+ if (obw_tbr != 0)
+ printf(" [max]");
+ printf("\n");
+ if (ibw_eff == ibw_max) {
+ printf("\tdownlink rate: %s\n",
+ bps_to_str(ibw_max));
+ } else {
+ printf("\tdownlink rate: "
+ "%s [eff] / ", bps_to_str(ibw_eff));
+ printf("%s [max]\n",
+ bps_to_str(ibw_max));
+ }
+ }
+ } else if (obw_tbr != 0) {
+ printf("\tuplink rate: %s [tbr]\n",
+ bps_to_str(obw_tbr));
+ }
+
+ if (ilt_max != 0 || olt_max != 0) {
+ if (ilt_max == olt_max && ilt_eff == olt_eff &&
+ ilt_max == ilt_eff) {
+ printf("\tlink latency: %s\n",
+ ns_to_str(ilt_max));
+ } else {
+ if (olt_max != 0 && olt_eff == olt_max) {
+ printf("\tuplink latency: %s\n",
+ ns_to_str(olt_max));
+ } else if (olt_max != 0) {
+ printf("\tuplink latency: "
+ "%s [eff] / ", ns_to_str(olt_eff));
+ printf("%s [max]\n",
+ ns_to_str(olt_max));
+ }
+ if (ilt_max != 0 && ilt_eff == ilt_max) {
+ printf("\tdownlink latency: %s\n",
+ ns_to_str(ilt_max));
+ } else if (ilt_max != 0) {
+ printf("\tdownlink latency: "
+ "%s [eff] / ", ns_to_str(ilt_eff));
+ printf("%s [max]\n",
+ ns_to_str(ilt_max));
+ }
+ }
+ }
+ }
+
+ /* Common OID prefix */
+ mib[0] = CTL_NET;
+ mib[1] = PF_LINK;
+ mib[2] = NETLINK_GENERIC;
+ mib[3] = IFMIB_IFDATA;
+ mib[4] = if_nametoindex(name);
+ mib[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(mib, 6, &ifmsupp, &miblen, (void *)0, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+ if (ifmsupp.ifmd_data_extended.ifi_alignerrs != 0) {
+ printf("\tunaligned pkts: %llu\n",
+ ifmsupp.ifmd_data_extended.ifi_alignerrs);
+ }
+ if (ifmsupp.ifmd_data_extended.ifi_dt_bytes != 0) {
+ printf("\tdata milestone interval: %s\n",
+ bytes_to_str(ifmsupp.ifmd_data_extended.ifi_dt_bytes));
+ }
+
+ bzero(&ifdr, sizeof (ifdr));
+ strlcpy(ifdr.ifdr_name, name, sizeof (ifdr.ifdr_name));
+ if (ioctl(s, SIOCGIFDESC, &ifdr) != -1 && ifdr.ifdr_len) {
+ printf("\tdesc: %s\n", ifdr.ifdr_desc);
+ }
+
+ if (ioctl(s, SIOCGIFLOG, &ifr) != -1 && ifr.ifr_log.ifl_level) {
+ printf("\tlogging: level %d ", ifr.ifr_log.ifl_level);
+ printb("facilities", ifr.ifr_log.ifl_flags, IFRLOGF_BITS);
+ putchar('\n');
+ }
+
+ if (ioctl(s, SIOCGIFDELEGATE, &ifr) != -1 && ifr.ifr_delegated) {
+ char delegatedif[IFNAMSIZ+1];
+ if (if_indextoname(ifr.ifr_delegated, delegatedif) != NULL)
+ printf("\teffective interface: %s\n", delegatedif);
+ }
+
+ if (ioctl(s, SIOCGSTARTDELAY, &ifr) != -1) {
+ if (ifr.ifr_start_delay_qlen > 0 &&
+ ifr.ifr_start_delay_timeout > 0) {
+ printf("\ttxstart qlen: %u packets "
+ "timeout: %u microseconds\n",
+ ifr.ifr_start_delay_qlen,
+ ifr.ifr_start_delay_timeout/1000);
+ }
+ }
+#if defined(IFCAP_HW_TIMESTAMP) && defined(IFCAP_SW_TIMESTAMP)
+ if ((curcap & (IFCAP_HW_TIMESTAMP | IFCAP_SW_TIMESTAMP)) &&
+ ioctl(s, SIOCGIFTIMESTAMPENABLED, &ifr) != -1) {
+ printf("\ttimestamp: %s\n",
+ (ifr.ifr_intval != 0) ? "enabled" : "disabled");
+ }
+#endif
+#if defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE)
+ if (ioctl(s, SIOCGQOSMARKINGENABLED, &ifr) != -1) {
+ printf("\tqosmarking enabled: %s mode: ",
+ ifr.ifr_qosmarking_enabled ? "yes" : "no");
+ if (ioctl(s, SIOCGQOSMARKINGMODE, &ifr) != -1) {
+ switch (ifr.ifr_qosmarking_mode) {
+ case IFRTYPE_QOSMARKING_FASTLANE:
+ printf("fastlane\n");
+ break;
+ case IFRTYPE_QOSMARKING_RFC4594:
+ printf("RFC4594\n");
+ break;
+ case IFRTYPE_QOSMARKING_MODE_NONE:
+ printf("none\n");
+ break;
+ default:
+ printf("unknown (%u)\n", ifr.ifr_qosmarking_mode);
+ break;
+ }
+ }
+ }
+#endif /* defined(SIOCGQOSMARKINGENABLED) && defined(SIOCGQOSMARKINGMODE) */
+
+ if (ioctl(s, SIOCGIFLOWPOWER, &ifr) != -1) {
+ printf("\tlow power mode: %s\n",
+ (ifr.ifr_low_power_mode != 0) ? "enabled" : "disabled");
+ }
+ if (ioctl(s, SIOCGIFMPKLOG, &ifr) != -1) {
+ printf("\tmulti layer packet logging (mpklog): %s\n",
+ (ifr.ifr_mpk_log != 0) ? "enabled" : "disabled");
+ }
+ show_routermode(s);
+ show_routermode6();
+
+done:
+ close(s);
+ return;
+}
+
+#define KILOBYTES 1024
+#define MEGABYTES (KILOBYTES * KILOBYTES)
+#define GIGABYTES (KILOBYTES * KILOBYTES * KILOBYTES)
+
+static char *
+bytes_to_str(unsigned long long bytes)
+{
+ static char buf[32];
+ const char *u;
+ long double n = bytes, t;
+
+ if (bytes >= GIGABYTES) {
+ t = n / GIGABYTES;
+ u = "GB";
+ } else if (n >= MEGABYTES) {
+ t = n / MEGABYTES;
+ u = "MB";
+ } else if (n >= KILOBYTES) {
+ t = n / KILOBYTES;
+ u = "KB";
+ } else {
+ t = n;
+ u = "bytes";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %s", t, u);
+ return (buf);
+}
+
+#define GIGABIT_PER_SEC 1000000000 /* gigabit per second */
+#define MEGABIT_PER_SEC 1000000 /* megabit per second */
+#define KILOBIT_PER_SEC 1000 /* kilobit per second */
+
+static char *
+bps_to_str(unsigned long long rate)
+{
+ static char buf[32];
+ const char *u;
+ long double n = rate, t;
+
+ if (rate >= GIGABIT_PER_SEC) {
+ t = n / GIGABIT_PER_SEC;
+ u = "Gbps";
+ } else if (n >= MEGABIT_PER_SEC) {
+ t = n / MEGABIT_PER_SEC;
+ u = "Mbps";
+ } else if (n >= KILOBIT_PER_SEC) {
+ t = n / KILOBIT_PER_SEC;
+ u = "Kbps";
+ } else {
+ t = n;
+ u = "bps ";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
+ return (buf);
+}
+
+#define NSEC_PER_SEC 1000000000 /* nanosecond per second */
+#define USEC_PER_SEC 1000000 /* microsecond per second */
+#define MSEC_PER_SEC 1000 /* millisecond per second */
+
+static char *
+ns_to_str(unsigned long long nsec)
+{
+ static char buf[32];
+ const char *u;
+ long double n = nsec, t;
+
+ if (nsec >= NSEC_PER_SEC) {
+ t = n / NSEC_PER_SEC;
+ u = "sec ";
+ } else if (n >= USEC_PER_SEC) {
+ t = n / USEC_PER_SEC;
+ u = "msec";
+ } else if (n >= MSEC_PER_SEC) {
+ t = n / MSEC_PER_SEC;
+ u = "usec";
+ } else {
+ t = n;
+ u = "nsec";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
+ return (buf);
+}
+
+static void
+tunnel_status(int s)
+{
+ af_all_tunnel_status(s);
+}
+
+static void
+clat46_addr(int s, char * if_name)
+{
+ struct if_clat46req ifr;
+ char buf[MAXHOSTNAMELEN];
+
+ bzero(&ifr, sizeof (ifr));
+ strlcpy(ifr.ifclat46_name, if_name, sizeof(ifr.ifclat46_name));
+
+ if (ioctl(s, SIOCGIFCLAT46ADDR, &ifr) < 0) {
+ if (errno != ENOENT)
+ syslog(LOG_WARNING, "ioctl (SIOCGIFCLAT46ADDR): %d", errno);
+ return;
+ }
+
+ if (inet_ntop(AF_INET6, &ifr.ifclat46_addr.v6_address, buf, sizeof(buf)) != NULL)
+ printf("\tinet6 %s prefixlen %d clat46\n",
+ buf, ifr.ifclat46_addr.v6_prefixlen);
+}
+
+static void
+nat64_status(int s, char * if_name)
+{
+ int i;
+ struct if_nat64req ifr;
+ char buf[MAXHOSTNAMELEN];
+
+ bzero(&ifr, sizeof(ifr));
+ strlcpy(ifr.ifnat64_name, if_name, sizeof(ifr.ifnat64_name));
+
+ if (ioctl(s, SIOCGIFNAT64PREFIX, &ifr) < 0) {
+ if (errno != ENOENT)
+ syslog(LOG_WARNING, "ioctl(SIOCGIFNAT64PREFIX): %d", errno);
+ return;
+ }
+
+ for (i = 0; i < NAT64_MAX_NUM_PREFIXES; i++) {
+ if (ifr.ifnat64_prefixes[i].prefix_len > 0) {
+ inet_ntop(AF_INET6, &ifr.ifnat64_prefixes[i].ipv6_prefix, buf, sizeof(buf));
+ printf("\tnat64 prefix %s prefixlen %d\n",
+ buf, ifr.ifnat64_prefixes[i].prefix_len << 3);
+ }
+ }
+}
+
+void
+Perror(const char *cmd)
+{
+ switch (errno) {
+
+ case ENXIO:
+ errx(1, "%s: no such interface", cmd);
+ break;
+
+ case EPERM:
+ errx(1, "%s: permission denied", cmd);
+ break;
+
+ default:
+ err(1, "%s", cmd);
+ }
+}
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ */
+void
+printb(const char *s, unsigned v, const char *bits)
+{
+ int i, any = 0;
+ char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++) != '\0') {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else
+ for (; *bits > 32; bits++)
+ ;
+ }
+ putchar('>');
+ }
+}
+
+#ifndef __APPLE__
+void
+ifmaybeload(const char *name)
+{
+#define MOD_PREFIX_LEN 3 /* "if_" */
+ struct module_stat mstat;
+ int fileid, modid;
+ char ifkind[IFNAMSIZ + MOD_PREFIX_LEN], ifname[IFNAMSIZ], *dp;
+ const char *cp;
+
+ /* loading suppressed by the user */
+ if (noload)
+ return;
+
+ /* trim the interface number off the end */
+ strlcpy(ifname, name, sizeof(ifname));
+ for (dp = ifname; *dp != 0; dp++)
+ if (isdigit(*dp)) {
+ *dp = 0;
+ break;
+ }
+
+ /* turn interface and unit into module name */
+ strlcpy(ifkind, "if_", sizeof(ifkind));
+ strlcpy(ifkind + MOD_PREFIX_LEN, ifname,
+ sizeof(ifkind) - MOD_PREFIX_LEN);
+
+ /* scan files in kernel */
+ mstat.version = sizeof(struct module_stat);
+ for (fileid = kldnext(0); fileid > 0; fileid = kldnext(fileid)) {
+ /* scan modules in file */
+ for (modid = kldfirstmod(fileid); modid > 0;
+ modid = modfnext(modid)) {
+ if (modstat(modid, &mstat) < 0)
+ continue;
+ /* strip bus name if present */
+ if ((cp = strchr(mstat.name, '/')) != NULL) {
+ cp++;
+ } else {
+ cp = mstat.name;
+ }
+ /* already loaded? */
+ if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 ||
+ strncmp(ifkind, cp, strlen(ifkind) + 1) == 0)
+ return;
+ }
+ }
+
+ /* not present, we should try to load it */
+ kldload(ifkind);
+}
+#endif
+
+static struct cmd basic_cmds[] = {
+ DEF_CMD("up", IFF_UP, setifflags),
+ DEF_CMD("down", -IFF_UP, setifflags),
+ DEF_CMD("arp", -IFF_NOARP, setifflags),
+ DEF_CMD("-arp", IFF_NOARP, setifflags),
+ DEF_CMD("debug", IFF_DEBUG, setifflags),
+ DEF_CMD("-debug", -IFF_DEBUG, setifflags),
+#ifdef IFF_PPROMISC
+ DEF_CMD("promisc", IFF_PPROMISC, setifflags),
+ DEF_CMD("-promisc", -IFF_PPROMISC, setifflags),
+#endif /* IFF_PPROMISC */
+ DEF_CMD("add", IFF_UP, notealias),
+ DEF_CMD("alias", IFF_UP, notealias),
+ DEF_CMD("-alias", -IFF_UP, notealias),
+ DEF_CMD("delete", -IFF_UP, notealias),
+ DEF_CMD("remove", -IFF_UP, notealias),
+#ifdef notdef
+#define EN_SWABIPS 0x1000
+ DEF_CMD("swabips", EN_SWABIPS, setifflags),
+ DEF_CMD("-swabips", -EN_SWABIPS, setifflags),
+#endif
+ DEF_CMD_ARG("netmask", setifnetmask),
+ DEF_CMD_ARG("metric", setifmetric),
+ DEF_CMD_ARG("broadcast", setifbroadaddr),
+ DEF_CMD_ARG("ipdst", setifipdst),
+ DEF_CMD_ARG2("tunnel", settunnel),
+ DEF_CMD("-tunnel", 0, deletetunnel),
+ DEF_CMD("deletetunnel", 0, deletetunnel),
+ DEF_CMD("link0", IFF_LINK0, setifflags),
+ DEF_CMD("-link0", -IFF_LINK0, setifflags),
+ DEF_CMD("link1", IFF_LINK1, setifflags),
+ DEF_CMD("-link1", -IFF_LINK1, setifflags),
+ DEF_CMD("link2", IFF_LINK2, setifflags),
+ DEF_CMD("-link2", -IFF_LINK2, setifflags),
+#ifdef IFF_MONITOR
+ DEF_CMD("monitor", IFF_MONITOR:, setifflags),
+ DEF_CMD("-monitor", -IFF_MONITOR, setifflags),
+#endif /* IFF_MONITOR */
+ DEF_CMD("mpklog", 1, setifmpklog),
+ DEF_CMD("-mpklog", 0, setifmpklog),
+#ifdef IFF_STATICARP
+ DEF_CMD("staticarp", IFF_STATICARP, setifflags),
+ DEF_CMD("-staticarp", -IFF_STATICARP, setifflags),
+#endif /* IFF_STATICARP */
+#ifdef IFCAP_RXCSUM
+ DEF_CMD("rxcsum", IFCAP_RXCSUM, setifcap),
+ DEF_CMD("-rxcsum", -IFCAP_RXCSUM, setifcap),
+#endif /* IFCAP_RXCSUM */
+#ifdef IFCAP_TXCSUM
+ DEF_CMD("txcsum", IFCAP_TXCSUM, setifcap),
+ DEF_CMD("-txcsum", -IFCAP_TXCSUM, setifcap),
+#endif /* IFCAP_TXCSUM */
+#ifdef IFCAP_NETCONS
+ DEF_CMD("netcons", IFCAP_NETCONS, setifcap),
+ DEF_CMD("-netcons", -IFCAP_NETCONS, setifcap),
+#endif /* IFCAP_NETCONS */
+#ifdef IFCAP_POLLING
+ DEF_CMD("polling", IFCAP_POLLING, setifcap),
+ DEF_CMD("-polling", -IFCAP_POLLING, setifcap),
+#endif /* IFCAP_POLLING */
+#ifdef IFCAP_TSO
+ DEF_CMD("tso", IFCAP_TSO, setifcap),
+ DEF_CMD("-tso", -IFCAP_TSO, setifcap),
+#endif /* IFCAP_TSO */
+#ifdef IFCAP_LRO
+ DEF_CMD("lro", IFCAP_LRO, setifcap),
+ DEF_CMD("-lro", -IFCAP_LRO, setifcap),
+#endif /* IFCAP_LRO */
+#ifdef IFCAP_WOL
+ DEF_CMD("wol", IFCAP_WOL, setifcap),
+ DEF_CMD("-wol", -IFCAP_WOL, setifcap),
+#endif /* IFCAP_WOL */
+#ifdef IFCAP_WOL_UCAST
+ DEF_CMD("wol_ucast", IFCAP_WOL_UCAST, setifcap),
+ DEF_CMD("-wol_ucast", -IFCAP_WOL_UCAST, setifcap),
+#endif /* IFCAP_WOL_UCAST */
+#ifdef IFCAP_WOL_MCAST
+ DEF_CMD("wol_mcast", IFCAP_WOL_MCAST, setifcap),
+ DEF_CMD("-wol_mcast", -IFCAP_WOL_MCAST, setifcap),
+#endif /* IFCAP_WOL_MCAST */
+#ifdef IFCAP_WOL_MAGIC
+ DEF_CMD("wol_magic", IFCAP_WOL_MAGIC, setifcap),
+ DEF_CMD("-wol_magic", -IFCAP_WOL_MAGIC, setifcap),
+#endif /* IFCAP_WOL_MAGIC */
+ DEF_CMD("normal", -IFF_LINK0, setifflags),
+ DEF_CMD("compress", IFF_LINK0, setifflags),
+ DEF_CMD("noicmp", IFF_LINK1, setifflags),
+ DEF_CMD_ARG("mtu", setifmtu),
+#ifdef notdef
+ DEF_CMD_ARG("name", setifname),
+#endif /* notdef */
+#ifdef IFCAP_AV
+ DEF_CMD("av", IFCAP_AV, setifcap),
+ DEF_CMD("-av", -IFCAP_AV, setifcap),
+#endif /* IFCAP_AV */
+ DEF_CMD("router", 1, setrouter),
+ DEF_CMD("-router", 0, setrouter),
+ DEF_CMD_VA("routermode", routermode),
+ DEF_CMD_ARG("desc", setifdesc),
+ DEF_CMD_ARG("tbr", settbr),
+ DEF_CMD_VA("netem", setnetem),
+ DEF_CMD_ARG("throttle", setthrottle),
+ DEF_CMD_ARG("log", setlog),
+ DEF_CMD("cl2k", 1, setcl2k),
+ DEF_CMD("-cl2k", 0, setcl2k),
+ DEF_CMD("expensive", 1, setexpensive),
+ DEF_CMD("-expensive", 0, setexpensive),
+#ifdef SIOCSIFCONSTRAINED
+ DEF_CMD("constrained", 1, setconstrained),
+ DEF_CMD("-constrained", 0, setconstrained),
+#endif
+ DEF_CMD("timestamp", 1, settimestamp),
+ DEF_CMD("-timestamp", 0, settimestamp),
+ DEF_CMD_ARG("ecn", setecnmode),
+ DEF_CMD_ARG2("fastlane", setfastlane),
+ DEF_CMD_ARG2("qosmarking", setqosmarking),
+ DEF_CMD_ARG("disable_output", setdisableoutput),
+ DEF_CMD("probe_connectivity", 1, setprobeconnectivity),
+ DEF_CMD("-probe_connectivity", 0, setprobeconnectivity),
+ DEF_CMD("lowpowermode", 1, setlowpowermode),
+ DEF_CMD("-lowpowermode", 0, setlowpowermode),
+ DEF_CMD_ARG("subfamily", setifsubfamily),
+ DEF_CMD("available", 1, setifavailability),
+ DEF_CMD("-available", 0, setifavailability),
+ DEF_CMD("unavailable", 0, setifavailability),
+};
+
+static __constructor void
+ifconfig_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(basic_cmds); i++)
+ cmd_register(&basic_cmds[i]);
+#undef N
+}
+
+static char *
+sched2str(unsigned int s)
+{
+ char *c;
+
+ switch (s) {
+ case PKTSCHEDT_NONE:
+ c = "NONE";
+ break;
+ case PKTSCHEDT_FQ_CODEL:
+ c = "FQ_CODEL";
+ break;
+ default:
+ c = "UNKNOWN";
+ break;
+ }
+
+ return (c);
+}
+
+static char *
+tl2str(unsigned int s)
+{
+ char *c;
+
+ switch (s) {
+ case IFNET_THROTTLE_OFF:
+ c = "off";
+ break;
+ case IFNET_THROTTLE_OPPORTUNISTIC:
+ c = "opportunistic";
+ break;
+ default:
+ c = "unknown";
+ break;
+ }
+
+ return (c);
+}
+
+static char *
+ift2str(unsigned int t, unsigned int f, unsigned int sf)
+{
+ static char buf[256];
+ char *c = NULL;
+
+ switch (t) {
+ case IFT_ETHER:
+ switch (sf) {
+ case IFRTYPE_SUBFAMILY_USB:
+ c = "USB Ethernet";
+ break;
+ case IFRTYPE_SUBFAMILY_BLUETOOTH:
+ c = "Bluetooth PAN";
+ break;
+ case IFRTYPE_SUBFAMILY_WIFI:
+ c = "Wi-Fi";
+ break;
+ case IFRTYPE_SUBFAMILY_THUNDERBOLT:
+ c = "IP over Thunderbolt";
+ break;
+ case IFRTYPE_SUBFAMILY_ANY:
+ default:
+ c = "Ethernet";
+ break;
+ }
+ break;
+
+ case IFT_IEEE1394:
+ c = "IP over FireWire";
+ break;
+
+ case IFT_PKTAP:
+ c = "Packet capture";
+ break;
+
+ case IFT_CELLULAR:
+ c = "Cellular";
+ break;
+
+ case IFT_OTHER:
+ if (ifr.ifr_type.ift_family == APPLE_IF_FAM_IPSEC) {
+ if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_BLUETOOTH) {
+ c = "Companion Link Bluetooth";
+ } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_QUICKRELAY) {
+ c = "Companion Link QuickRelay";
+ } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_WIFI) {
+ c = "Companion Link Wi-Fi";
+ } else if (ifr.ifr_type.ift_subfamily == IFRTYPE_SUBFAMILY_DEFAULT) {
+ c = "Companion Link Default";
+ }
+ }
+ break;
+
+ case IFT_BRIDGE:
+ case IFT_PFLOG:
+ case IFT_PFSYNC:
+ case IFT_PPP:
+ case IFT_LOOP:
+ case IFT_GIF:
+ case IFT_STF:
+ case IFT_L2VLAN:
+ case IFT_IEEE8023ADLAG:
+ default:
+ break;
+ }
+
+ if (verbose > 1) {
+ if (c == NULL) {
+ (void) snprintf(buf, sizeof (buf),
+ "0x%x family: %u subfamily: %u",
+ ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
+ ifr.ifr_type.ift_subfamily);
+ } else {
+ (void) snprintf(buf, sizeof (buf),
+ "%s (0x%x) family: %u subfamily: %u", c,
+ ifr.ifr_type.ift_type, ifr.ifr_type.ift_family,
+ ifr.ifr_type.ift_subfamily);
+ }
+ c = buf;
+ }
+
+ return (c);
+}
+
+static char *
+iffunct2str(u_int32_t functional_type)
+{
+ char *str = NULL;
+
+ switch (functional_type) {
+ case IFRTYPE_FUNCTIONAL_UNKNOWN:
+ break;
+
+ case IFRTYPE_FUNCTIONAL_LOOPBACK:
+ str = "loopback";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_WIRED:
+ str = "wired";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_WIFI_INFRA:
+ str = "wifi";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_WIFI_AWDL:
+ str = "awdl";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_CELLULAR:
+ str = "cellular";
+ break;
+
+ case IFRTYPE_FUNCTIONAL_INTCOPROC:
+ break;
+
+ case IFRTYPE_FUNCTIONAL_COMPANIONLINK:
+ str = "companionlink";
+ break;
+
+ default:
+ break;
+ }
+ return str;
+}
diff --git a/network_cmds/ifconfig.tproj/ifconfig.h b/network_cmds/ifconfig.tproj/ifconfig.h
new file mode 100644
index 0000000..5d4a7e0
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifconfig.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2009-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997 Peter Wemm.
+ * 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 for the FreeBSD Project
+ * by Peter Wemm.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ *
+ * so there!
+ *
+ * $FreeBSD: src/sbin/ifconfig/ifconfig.h,v 1.21.2.1.2.1 2008/11/25 02:59:29 kensmith Exp $
+ */
+
+#define __constructor __attribute__((constructor))
+
+struct afswtch;
+struct cmd;
+
+typedef void c_func(const char *cmd, int arg, int s, const struct afswtch *afp);
+typedef void c_func2(const char *arg1, const char *arg2, int s, const struct afswtch *afp);
+typedef int c_funcv(int argc, char *const *argv, int s, const struct afswtch *afp);
+
+struct cmd {
+ const char *c_name;
+ int c_parameter;
+#define NEXTARG 0xffffff /* has following arg */
+#define NEXTARG2 0xfffffe /* has 2 following args */
+#define OPTARG 0xfffffd /* has optional following arg */
+#define VAARGS 0xfffffc /* has variable following args */
+ union {
+ c_func *c_func;
+ c_func2 *c_func2;
+ c_funcv *c_funcv;
+ } c_u;
+ int c_iscloneop;
+ struct cmd *c_next;
+};
+void cmd_register(struct cmd *);
+
+typedef void callback_func(int s, void *);
+void callback_register(callback_func *, void *);
+
+/*
+ * Macros for declaring command functions and initializing entries.
+ */
+#define DECL_CMD_FUNC(name, cmd, arg) \
+ void name(const char *cmd, int arg, int s, const struct afswtch *afp)
+#define DECL_CMD_FUNC2(name, arg1, arg2) \
+ void name(const char *arg1, const char *arg2, int s, const struct afswtch *afp)
+
+#define DEF_CMD(name, param, func) { name, param, { .c_func = func } }
+#define DEF_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func } }
+#define DEF_CMD_OPTARG(name, func) { name, OPTARG, { .c_func = func } }
+#define DEF_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func } }
+#define DEF_CMD_VA(name, func) { name, VAARGS, { .c_funcv = func } }
+#define DEF_CLONE_CMD(name, param, func) { name, param, { .c_func = func }, 1 }
+#define DEF_CLONE_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func }, 1 }
+
+struct ifaddrs;
+struct addrinfo;
+
+enum {
+ RIDADDR,
+ ADDR,
+ MASK,
+ DSTADDR,
+};
+
+struct afswtch {
+ const char *af_name; /* as given on cmd line, e.g. "inet" */
+ short af_af; /* AF_* */
+ /*
+ * Status is handled one of two ways; if there is an
+ * address associated with the interface then the
+ * associated address family af_status method is invoked
+ * with the appropriate addressin info. Otherwise, if
+ * all possible info is to be displayed and af_other_status
+ * is defined then it is invoked after all address status
+ * is presented.
+ */
+ void (*af_status)(int, const struct ifaddrs *);
+ void (*af_other_status)(int);
+ /* parse address method */
+ void (*af_getaddr)(const char *, int);
+ /* parse prefix method (IPv6) */
+ void (*af_getprefix)(const char *, int);
+ void (*af_postproc)(int s, const struct afswtch *);
+ u_long af_difaddr; /* set dst if address ioctl */
+ u_long af_aifaddr; /* set if address ioctl */
+ void *af_ridreq; /* */
+ void *af_addreq; /* */
+ struct afswtch *af_next;
+
+ /* XXX doesn't fit model */
+ void (*af_status_tunnel)(int);
+ void (*af_settunnel)(int s, struct addrinfo *srcres,
+ struct addrinfo *dstres);
+
+ void (*af_setrouter)(int, int);
+ int (*af_routermode)(int, int, char *const *);
+};
+void af_register(struct afswtch *);
+
+struct option {
+ const char *opt;
+ const char *opt_usage;
+ void (*cb)(const char *arg);
+ struct option *next;
+};
+void opt_register(struct option *);
+
+extern struct ifreq ifr;
+extern char name[IFNAMSIZ]; /* name of interface */
+extern int allmedia;
+extern int supmedia;
+extern int printkeys;
+extern int newaddr;
+extern int verbose;
+extern int all;
+
+void setifcap(const char *, int value, int s, const struct afswtch *);
+
+void Perror(const char *cmd);
+void printb(const char *s, unsigned value, const char *bits);
+
+void ifmaybeload(const char *name);
+
+typedef void clone_callback_func(int, struct ifreq *);
+void clone_setcallback(clone_callback_func *);
+
+/*
+ * XXX expose this so modules that neeed to know of any pending
+ * operations on ifmedia can avoid cmd line ordering confusion.
+ */
+struct ifmediareq *ifmedia_getstate(int s);
diff --git a/network_cmds/ifconfig.tproj/iffake.c b/network_cmds/ifconfig.tproj/iffake.c
new file mode 100644
index 0000000..c8065a2
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/iffake.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2017 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * iffake.c
+ * - manage fake interfaces that pretend to be e.g. ethernet
+ */
+
+/*
+ * Modification History:
+ *
+ * January 17, 2017 Dieter Siegmund (dieter@apple.com)
+ * - created
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_fake_var.h>
+
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static void
+fake_status(int s)
+{
+ struct ifdrv ifd;
+ struct if_fake_request iffr;
+
+ bzero((char *)&ifd, sizeof(ifd));
+ bzero((char *)&iffr, sizeof(iffr));
+ strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+ ifd.ifd_cmd = IF_FAKE_G_CMD_GET_PEER;
+ ifd.ifd_len = sizeof(iffr);
+ ifd.ifd_data = &iffr;
+ if (ioctl(s, SIOCGDRVSPEC, &ifd) < 0) {
+ return;
+ }
+ if (iffr.iffr_peer_name[0] == '\0') {
+ printf("\tpeer: <none>\n");
+ } else {
+ printf("\tpeer: %s\n", iffr.iffr_peer_name);
+ }
+ return;
+}
+
+static void
+set_peer(int s, const char * operation, const char * val)
+{
+ struct ifdrv ifd;
+ struct if_fake_request iffr;
+
+ bzero((char *)&ifd, sizeof(ifd));
+ bzero((char *)&iffr, sizeof(iffr));
+ strlcpy(ifd.ifd_name, ifr.ifr_name, sizeof(ifd.ifd_name));
+ ifd.ifd_cmd = IF_FAKE_S_CMD_SET_PEER;
+ ifd.ifd_len = sizeof(iffr);
+ ifd.ifd_data = &iffr;
+ if (val != NULL) {
+ strlcpy(iffr.iffr_peer_name, val, sizeof(iffr.iffr_peer_name));
+ }
+ if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
+ err(1, "SIOCDRVSPEC %s peer", operation);
+ }
+ return;
+}
+
+static
+DECL_CMD_FUNC(setpeer, val, d)
+{
+ set_peer(s, "set", val);
+ return;
+}
+
+static
+DECL_CMD_FUNC(unsetpeer, val, d)
+{
+ set_peer(s, "unset", NULL);
+ return;
+}
+
+static struct cmd fake_cmds[] = {
+ DEF_CLONE_CMD_ARG("peer", setpeer),
+ DEF_CMD_OPTARG("-peer", unsetpeer),
+};
+static struct afswtch af_fake = {
+ .af_name = "af_fake",
+ .af_af = AF_UNSPEC,
+ .af_other_status = fake_status,
+};
+
+static __constructor void
+fake_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(fake_cmds); i++)
+ cmd_register(&fake_cmds[i]);
+ af_register(&af_fake);
+#undef N
+}
+
diff --git a/network_cmds/ifconfig.tproj/ifmedia.c b/network_cmds/ifconfig.tproj/ifmedia.c
new file mode 100644
index 0000000..713c136
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifmedia.c
@@ -0,0 +1,872 @@
+/* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */
+/* $FreeBSD: src/sbin/ifconfig/ifmedia.c,v 1.25.6.1 2008/11/25 02:59:29 kensmith Exp $ */
+
+/*
+ * Copyright (c) 1997 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ * by Jason R. Thorpe.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ifconfig.h"
+
+static void domediaopt(const char *, int, int);
+static int get_media_subtype(int, const char *);
+#ifdef notdef
+static int get_media_mode(int, const char *);
+#endif
+static int get_media_options(int, const char *);
+static int lookup_media_word(struct ifmedia_description *, const char *);
+static void print_media_word(int, int);
+static void print_media_word_ifconfig(int);
+
+static struct ifmedia_description *get_toptype_desc(int);
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
+static struct ifmedia_description *get_subtype_desc(int,
+ struct ifmedia_type_to_subtype *ttos);
+
+static void
+media_status(int s)
+{
+ struct ifmediareq ifmr;
+ int *media_list, i;
+
+ (void) memset(&ifmr, 0, sizeof(ifmr));
+ (void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) {
+ /*
+ * Interface doesn't support SIOC{G,S}IFMEDIA.
+ */
+ return;
+ }
+
+ if (ifmr.ifm_count == 0) {
+ warnx("%s: no media types?", name);
+ return;
+ }
+
+ media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
+ if (media_list == NULL)
+ err(1, "malloc");
+ ifmr.ifm_ulist = media_list;
+
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0)
+ err(1, "SIOCGIFXMEDIA");
+
+ printf("\tmedia: ");
+ print_media_word(ifmr.ifm_current, 1);
+ if (ifmr.ifm_active != ifmr.ifm_current) {
+ putchar(' ');
+ putchar('(');
+ print_media_word(ifmr.ifm_active, 0);
+ putchar(')');
+ }
+
+ putchar('\n');
+
+ if (ifmr.ifm_status & IFM_AVALID) {
+ printf("\tstatus: ");
+#ifdef notdef
+ switch (IFM_TYPE(ifmr.ifm_active)) {
+ case IFM_ETHER:
+ case IFM_ATM:
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ printf("active");
+ else
+ printf("no carrier");
+ break;
+
+ case IFM_FDDI:
+ case IFM_TOKEN:
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ printf("inserted");
+ else
+ printf("no ring");
+ break;
+
+ case IFM_IEEE80211:
+ /* XXX: Different value for adhoc? */
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ printf("associated");
+ else
+ printf("no carrier");
+ break;
+ }
+#else
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ printf("active");
+ else
+ printf("inactive");
+#endif
+ putchar('\n');
+ }
+
+ if (ifmr.ifm_count > 0 && supmedia) {
+ printf("\tsupported media:\n");
+ for (i = 0; i < ifmr.ifm_count; i++) {
+ printf("\t\t");
+ print_media_word_ifconfig(media_list[i]);
+ putchar('\n');
+ }
+ }
+
+ free(media_list);
+}
+
+struct ifmediareq *
+ifmedia_getstate(int s)
+{
+ static struct ifmediareq *ifmr = NULL;
+ int *mwords;
+
+ if (ifmr == NULL) {
+ ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
+ if (ifmr == NULL)
+ err(1, "malloc");
+
+ (void) memset(ifmr, 0, sizeof(struct ifmediareq));
+ (void) strlcpy(ifmr->ifm_name, name,
+ sizeof(ifmr->ifm_name));
+
+ ifmr->ifm_count = 0;
+ ifmr->ifm_ulist = NULL;
+
+ /*
+ * We must go through the motions of reading all
+ * supported media because we need to know both
+ * the current media type and the top-level type.
+ */
+
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) {
+ err(1, "SIOCGIFXMEDIA");
+ }
+
+ if (ifmr->ifm_count == 0)
+ errx(1, "%s: no media types?", name);
+
+ mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
+ if (mwords == NULL)
+ err(1, "malloc");
+
+ ifmr->ifm_ulist = mwords;
+ if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0)
+ err(1, "SIOCGIFXMEDIA");
+ }
+
+ return ifmr;
+}
+
+static void
+setifmediacallback(int s, void *arg)
+{
+ struct ifmediareq *ifmr = (struct ifmediareq *)arg;
+ static int did_it = 0;
+
+ if (!did_it) {
+ ifr.ifr_media = ifmr->ifm_current;
+ if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
+ err(1, "SIOCSIFMEDIA (media)");
+ free(ifmr->ifm_ulist);
+ free(ifmr);
+ did_it = 1;
+ }
+}
+
+static void
+setmedia(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifmediareq *ifmr;
+ int subtype;
+
+ ifmr = ifmedia_getstate(s);
+
+ /*
+ * We are primarily concerned with the top-level type.
+ * However, "current" may be only IFM_NONE, so we just look
+ * for the top-level type in the first "supported type"
+ * entry.
+ *
+ * (I'm assuming that all supported media types for a given
+ * interface will be the same top-level type..)
+ */
+ subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_media = (ifmr->ifm_current & ~(IFM_NMASK|IFM_TMASK)) |
+ IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
+
+ if ((ifr.ifr_media & IFM_TMASK) == 0) {
+ ifr.ifr_media &= ~IFM_GMASK;
+ }
+
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ domediaopt(val, 0, s);
+}
+
+static void
+unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+ domediaopt(val, 1, s);
+}
+
+static void
+domediaopt(const char *val, int clear, int s)
+{
+ struct ifmediareq *ifmr;
+ int options;
+
+ ifmr = ifmedia_getstate(s);
+
+ options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_media = ifmr->ifm_current;
+ if (clear)
+ ifr.ifr_media &= ~options;
+ else {
+ if (options & IFM_HDX) {
+ ifr.ifr_media &= ~IFM_FDX;
+ options &= ~IFM_HDX;
+ }
+ ifr.ifr_media |= options;
+ }
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediainst(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifmediareq *ifmr;
+ int inst;
+
+ ifmr = ifmedia_getstate(s);
+
+ inst = atoi(val);
+ if (inst < 0 || inst > IFM_INST_MAX)
+ errx(1, "invalid media instance: %s", val);
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
+
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
+}
+
+#ifdef notdef
+static void
+setmediamode(const char *val, int d, int s, const struct afswtch *afp)
+{
+ struct ifmediareq *ifmr;
+ int mode;
+
+ ifmr = ifmedia_getstate(s);
+
+ mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
+
+ ifmr->ifm_current = ifr.ifr_media;
+ callback_register(setifmediacallback, (void *)ifmr);
+}
+#endif
+
+/**********************************************************************
+ * A good chunk of this is duplicated from sys/net/ifmedia.c
+ **********************************************************************/
+
+static struct ifmedia_description ifm_type_descriptions[] =
+ IFM_TYPE_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
+ IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
+ IFM_SUBTYPE_ETHERNET_ALIASES;
+
+static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
+ IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
+ IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
+ IFM_SUBTYPE_TOKENRING_ALIASES;
+
+static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
+ IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
+ IFM_SUBTYPE_FDDI_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_fddi_aliases[] =
+ IFM_SUBTYPE_FDDI_ALIASES;
+
+static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
+ IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+ IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+ IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
+
+#ifdef notdef
+static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
+IFM_SUBTYPE_IEEE80211_ALIASES;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
+ IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
+ IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_descriptions[] =
+ IFM_SUBTYPE_ATM_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_atm_aliases[] =
+ IFM_SUBTYPE_ATM_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
+ IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
+#endif
+
+static struct ifmedia_description ifm_subtype_shared_descriptions[] =
+ IFM_SUBTYPE_SHARED_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_shared_aliases[] =
+ IFM_SUBTYPE_SHARED_ALIASES;
+
+static struct ifmedia_description ifm_shared_option_descriptions[] =
+ IFM_SHARED_OPTION_DESCRIPTIONS;
+
+struct ifmedia_type_to_subtype {
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } subtypes[5];
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } options[3];
+ struct {
+ struct ifmedia_description *desc;
+ int alias;
+ } modes[3];
+};
+
+/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
+static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_ethernet_descriptions[0], 0 },
+ { &ifm_subtype_ethernet_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_ethernet_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_tokenring_descriptions[0], 0 },
+ { &ifm_subtype_tokenring_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_tokenring_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_fddi_descriptions[0], 0 },
+ { &ifm_subtype_fddi_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_fddi_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+#ifdef __APPLE__
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_ieee80211_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_ieee80211_option_descriptions[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+#else /* __APPLE__ */
+#ifdef notdef
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_ieee80211_descriptions[0], 0 },
+ { &ifm_subtype_ieee80211_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_ieee80211_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
+ { &ifm_subtype_ieee80211_mode_aliases[0], 0 },
+ { NULL, 0 },
+ },
+ },
+ {
+ {
+ { &ifm_subtype_shared_descriptions[0], 0 },
+ { &ifm_subtype_shared_aliases[0], 1 },
+ { &ifm_subtype_atm_descriptions[0], 0 },
+ { &ifm_subtype_atm_aliases[0], 1 },
+ { NULL, 0 },
+ },
+ {
+ { &ifm_shared_option_descriptions[0], 0 },
+ { &ifm_subtype_atm_option_descriptions[0], 0 },
+ { NULL, 0 },
+ },
+ {
+ { NULL, 0 },
+ },
+ },
+#endif
+#endif /* __APPLE__ */
+};
+
+static int
+get_media_subtype(int type, const char *val)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ int rval, i;
+
+ /* Find the top-level interface type. */
+ for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+ desc->ifmt_string != NULL; desc++, ttos++)
+ if (type == desc->ifmt_word)
+ break;
+ if (desc->ifmt_string == NULL)
+ errx(1, "unknown media type 0x%x", type);
+
+ for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
+ rval = lookup_media_word(ttos->subtypes[i].desc, val);
+ if (rval != -1)
+ return (rval);
+ }
+ errx(1, "unknown media subtype: %s", val);
+ /*NOTREACHED*/
+}
+
+#ifdef notdef
+static int
+get_media_mode(int type, const char *val)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ int rval, i;
+
+ /* Find the top-level interface type. */
+ for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+ desc->ifmt_string != NULL; desc++, ttos++)
+ if (type == desc->ifmt_word)
+ break;
+ if (desc->ifmt_string == NULL)
+ errx(1, "unknown media mode 0x%x", type);
+
+ for (i = 0; ttos->modes[i].desc != NULL; i++) {
+ rval = lookup_media_word(ttos->modes[i].desc, val);
+ if (rval != -1)
+ return (rval);
+ }
+ return -1;
+}
+#endif
+
+static int
+get_media_options(int type, const char *val)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ char *optlist, *optptr;
+ int option = 0, i, rval = 0;
+
+ /* We muck with the string, so copy it. */
+ optlist = strdup(val);
+ if (optlist == NULL)
+ err(1, "strdup");
+
+ /* Find the top-level interface type. */
+ for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+ desc->ifmt_string != NULL; desc++, ttos++)
+ if (type == desc->ifmt_word)
+ break;
+ if (desc->ifmt_string == NULL)
+ errx(1, "unknown media type 0x%x", type);
+
+ /*
+ * Look up the options in the user-provided comma-separated
+ * list.
+ */
+ optptr = optlist;
+ for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
+ for (i = 0; ttos->options[i].desc != NULL; i++) {
+ option = lookup_media_word(ttos->options[i].desc, optptr);
+ if (option != -1)
+ break;
+ }
+ if (option == 0)
+ errx(1, "unknown option: %s", optptr);
+ rval |= option;
+ }
+
+ free(optlist);
+ return (rval);
+}
+
+static int
+lookup_media_word(struct ifmedia_description *desc, const char *val)
+{
+
+ for (; desc->ifmt_string != NULL; desc++)
+ if (strcasecmp(desc->ifmt_string, val) == 0)
+ return (desc->ifmt_word);
+
+ return (-1);
+}
+
+static struct ifmedia_description *get_toptype_desc(int ifmw)
+{
+ struct ifmedia_description *desc;
+
+ for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
+ if (IFM_TYPE(ifmw) == desc->ifmt_word)
+ break;
+
+ return desc;
+}
+
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+
+ for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+ desc->ifmt_string != NULL; desc++, ttos++)
+ if (IFM_TYPE(ifmw) == desc->ifmt_word)
+ break;
+
+ return ttos;
+}
+
+static struct ifmedia_description *get_subtype_desc(int ifmw,
+ struct ifmedia_type_to_subtype *ttos)
+{
+ int i;
+ struct ifmedia_description *desc;
+
+ for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
+ if (ttos->subtypes[i].alias)
+ continue;
+ for (desc = ttos->subtypes[i].desc;
+ desc->ifmt_string != NULL; desc++) {
+ if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
+ return desc;
+ }
+ }
+
+ return NULL;
+}
+
+#ifdef notdef
+static struct ifmedia_description *get_mode_desc(int ifmw,
+ struct ifmedia_type_to_subtype *ttos)
+{
+ int i;
+ struct ifmedia_description *desc;
+
+ for (i = 0; ttos->modes[i].desc != NULL; i++) {
+ if (ttos->modes[i].alias)
+ continue;
+ for (desc = ttos->modes[i].desc;
+ desc->ifmt_string != NULL; desc++) {
+ if (IFM_MODE(ifmw) == desc->ifmt_word)
+ return desc;
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+static void
+print_media_word(int ifmw, int print_toptype)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ int seen_option = 0, i;
+
+ /* Find the top-level interface type. */
+ desc = get_toptype_desc(ifmw);
+ ttos = get_toptype_ttos(ifmw);
+ if (desc->ifmt_string == NULL) {
+ printf("<unknown type>");
+ return;
+#ifdef notdef
+ } else if (print_toptype) {
+ printf("%s", desc->ifmt_string);
+#endif
+ }
+
+ /*
+ * Don't print the top-level type; it's not like we can
+ * change it, or anything.
+ */
+
+ /* Find subtype. */
+ desc = get_subtype_desc(ifmw, ttos);
+ if (desc == NULL) {
+ printf("<unknown subtype>");
+ return;
+ }
+
+#ifdef notdef
+ if (print_toptype)
+ putchar(' ');
+#endif
+
+ printf("%s", desc->ifmt_string);
+
+#ifdef notdef
+ if (print_toptype) {
+ desc = get_mode_desc(ifmw, ttos);
+ if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
+ printf(" mode %s", desc->ifmt_string);
+ }
+#endif
+ /* Find options. */
+ for (i = 0; ttos->options[i].desc != NULL; i++) {
+ if (ttos->options[i].alias)
+ continue;
+ for (desc = ttos->options[i].desc;
+ desc->ifmt_string != NULL; desc++) {
+ if (ifmw & desc->ifmt_word) {
+ if (seen_option == 0)
+ printf(" <");
+ printf("%s%s", seen_option++ ? "," : "",
+ desc->ifmt_string);
+ }
+ }
+ }
+ printf("%s", seen_option ? ">" : "");
+
+#ifdef notdef
+ if (print_toptype && IFM_INST(ifmw) != 0)
+ printf(" instance %d", IFM_INST(ifmw));
+#endif
+}
+
+static void
+print_media_word_ifconfig(int ifmw)
+{
+ struct ifmedia_description *desc;
+ struct ifmedia_type_to_subtype *ttos;
+ int i;
+
+ /* Find the top-level interface type. */
+ desc = get_toptype_desc(ifmw);
+ ttos = get_toptype_ttos(ifmw);
+ if (desc->ifmt_string == NULL) {
+ printf("<unknown type>");
+ return;
+ }
+
+ /*
+ * Don't print the top-level type; it's not like we can
+ * change it, or anything.
+ */
+
+ /* Find subtype. */
+ desc = get_subtype_desc(ifmw, ttos);
+ if (desc == NULL) {
+ printf("<unknown subtype>");
+ return;
+ }
+
+ printf("media %s", desc->ifmt_string);
+
+#ifdef notdef
+ desc = get_mode_desc(ifmw, ttos);
+ if (desc != NULL)
+ printf(" mode %s", desc->ifmt_string);
+#endif
+
+ /* Find options. */
+ for (i = 0; ttos->options[i].desc != NULL; i++) {
+ if (ttos->options[i].alias)
+ continue;
+ for (desc = ttos->options[i].desc;
+ desc->ifmt_string != NULL; desc++) {
+ if (ifmw & desc->ifmt_word) {
+ printf(" mediaopt %s", desc->ifmt_string);
+ }
+ }
+ }
+
+ if (IFM_INST(ifmw) != 0)
+ printf(" instance %d", IFM_INST(ifmw));
+}
+
+/**********************************************************************
+ * ...until here.
+ **********************************************************************/
+
+static struct cmd media_cmds[] = {
+ DEF_CMD_ARG("media", setmedia),
+#ifdef notdef
+ DEF_CMD_ARG("mode", setmediamode),
+#endif
+ DEF_CMD_ARG("mediaopt", setmediaopt),
+ DEF_CMD_ARG("-mediaopt",unsetmediaopt),
+ DEF_CMD_ARG("inst", setmediainst),
+ DEF_CMD_ARG("instance", setmediainst),
+};
+static struct afswtch af_media = {
+ .af_name = "af_media",
+ .af_af = AF_UNSPEC,
+ .af_other_status = media_status,
+};
+
+static __constructor void
+ifmedia_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(media_cmds); i++)
+ cmd_register(&media_cmds[i]);
+ af_register(&af_media);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/ifvlan.c b/network_cmds/ifconfig.tproj/ifvlan.c
new file mode 100644
index 0000000..9ec0a0a
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/ifvlan.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1999
+ * Bill Paul <wpaul@ctr.columbia.edu>. 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 Bill Paul.
+ * 4. 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 Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
+ * 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 <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_vlan_var.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+#include <sys/cdefs.h>
+
+#define NOTAG ((u_short) -1)
+
+static struct vlanreq params = {
+ .vlr_tag = NOTAG,
+};
+
+static int
+getvlan(int s, struct ifreq *ifr, struct vlanreq *vreq)
+{
+ bzero((char *)vreq, sizeof(*vreq));
+ ifr->ifr_data = (caddr_t)vreq;
+
+ return ioctl(s, SIOCGETVLAN, (caddr_t)ifr);
+}
+
+static void
+vlan_status(int s)
+{
+ struct vlanreq vreq;
+
+ if (getvlan(s, &ifr, &vreq) != -1)
+ printf("\tvlan: %d parent interface: %s\n",
+ vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
+ "<none>" : vreq.vlr_parent);
+}
+
+static void
+vlan_create(int s, struct ifreq *ifr)
+{
+ if (params.vlr_tag != NOTAG || params.vlr_parent[0] != '\0') {
+ /*
+ * One or both parameters were specified, make sure both.
+ */
+ if (params.vlr_tag == NOTAG)
+ errx(1, "must specify a tag for vlan create");
+ if (params.vlr_parent[0] == '\0')
+ errx(1, "must specify a parent device for vlan create");
+ ifr->ifr_data = (caddr_t) &params;
+ }
+#ifdef SIOCIFCREATE2
+ if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
+ err(1, "SIOCIFCREATE2");
+#else
+ if (ioctl(s, SIOCIFCREATE, ifr) < 0)
+ err(1, "SIOCIFCREATE");
+#endif
+}
+
+static void
+vlan_cb(int s, void *arg)
+{
+ if ((params.vlr_tag != NOTAG) ^ (params.vlr_parent[0] != '\0'))
+ errx(1, "both vlan and vlandev must be specified");
+}
+
+static void
+vlan_set(int s, struct ifreq *ifr)
+{
+ if (params.vlr_tag != NOTAG && params.vlr_parent[0] != '\0') {
+ ifr->ifr_data = (caddr_t) &params;
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)ifr) == -1)
+ err(1, "SIOCSETVLAN");
+ }
+}
+
+static
+DECL_CMD_FUNC(setvlantag, val, d)
+{
+ struct vlanreq vreq;
+ u_long ul;
+ char *endp;
+
+ ul = strtoul(val, &endp, 0);
+ if (*endp != '\0')
+ errx(1, "invalid value for vlan");
+ params.vlr_tag = ul;
+ /* check if the value can be represented in vlr_tag */
+ if (params.vlr_tag != ul)
+ errx(1, "value for vlan out of range");
+
+ if (getvlan(s, &ifr, &vreq) != -1)
+ vlan_set(s, &ifr);
+ else
+ clone_setcallback(vlan_create);
+}
+
+static
+DECL_CMD_FUNC(setvlandev, val, d)
+{
+ struct vlanreq vreq;
+
+ strlcpy(params.vlr_parent, val, sizeof(params.vlr_parent));
+
+ if (getvlan(s, &ifr, &vreq) != -1)
+ vlan_set(s, &ifr);
+ else
+ clone_setcallback(vlan_create);
+}
+
+static
+DECL_CMD_FUNC(unsetvlandev, val, d)
+{
+ struct vlanreq vreq;
+
+ bzero((char *)&vreq, sizeof(struct vlanreq));
+ ifr.ifr_data = (caddr_t)&vreq;
+
+ if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCGETVLAN");
+
+ bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
+ vreq.vlr_tag = 0;
+
+ if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETVLAN");
+}
+
+static struct cmd vlan_cmds[] = {
+ DEF_CLONE_CMD_ARG("vlan", setvlantag),
+ DEF_CLONE_CMD_ARG("vlandev", setvlandev),
+ /* XXX For compatibility. Should become DEF_CMD() some day. */
+ DEF_CMD_OPTARG("-vlandev", unsetvlandev),
+#ifdef IFCAP_VLAN_MTU
+ DEF_CMD("vlanmtu", IFCAP_VLAN_MTU, setifcap),
+ DEF_CMD("-vlanmtu", -IFCAP_VLAN_MTU, setifcap),
+#endif /* IFCAP_VLAN_MTU */
+#ifdef IFCAP_VLAN_HWTAGGING
+ DEF_CMD("vlanhwtag", IFCAP_VLAN_HWTAGGING, setifcap),
+ DEF_CMD("-vlanhwtag", -IFCAP_VLAN_HWTAGGING, setifcap),
+#endif /* IFCAP_VLAN_HWTAGGING */
+};
+static struct afswtch af_vlan = {
+ .af_name = "af_vlan",
+ .af_af = AF_UNSPEC,
+ .af_other_status = vlan_status,
+};
+
+static __constructor void
+vlan_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(vlan_cmds); i++)
+ cmd_register(&vlan_cmds[i]);
+ af_register(&af_vlan);
+ callback_register(vlan_cb, NULL);
+#undef N
+}
diff --git a/network_cmds/ifconfig.tproj/nexus.c b/network_cmds/ifconfig.tproj/nexus.c
new file mode 100644
index 0000000..3df9842
--- /dev/null
+++ b/network_cmds/ifconfig.tproj/nexus.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * nexus.c
+ * - report information about attached nexus
+ */
+
+/*
+ * Modification History:
+ *
+ * April 10, 2017 Dieter Siegmund (dieter@apple.com)
+ * - created
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_fake_var.h>
+
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static void
+nexus_status(int s)
+{
+ struct if_nexusreq ifnr;
+ uuid_string_t flowswitch;
+ uuid_string_t netif;
+
+ if (!verbose) {
+ return;
+ }
+ bzero((char *)&ifnr, sizeof(ifnr));
+ strlcpy(ifnr.ifnr_name, ifr.ifr_name, sizeof(ifnr.ifnr_name));
+ if (ioctl(s, SIOCGIFNEXUS, &ifnr) < 0) {
+ return;
+ }
+ if (uuid_is_null(ifnr.ifnr_netif)) {
+ /* technically, this shouldn't happen */
+ return;
+ }
+ uuid_unparse_upper(ifnr.ifnr_netif, netif);
+ printf("\tnetif: %s\n", netif);
+ if (uuid_is_null(ifnr.ifnr_flowswitch) == 0) {
+ uuid_unparse_upper(ifnr.ifnr_flowswitch, flowswitch);
+ printf("\tflowswitch: %s\n", flowswitch);
+ }
+ return;
+}
+
+static struct afswtch af_fake = {
+ .af_name = "af_fake",
+ .af_af = AF_UNSPEC,
+ .af_other_status = nexus_status,
+};
+
+static __constructor void
+fake_ctor(void)
+{
+ af_register(&af_fake);
+}
+
diff --git a/network_cmds/ip6addrctl.tproj/ip6addrctl.8 b/network_cmds/ip6addrctl.tproj/ip6addrctl.8
new file mode 100644
index 0000000..59154d4
--- /dev/null
+++ b/network_cmds/ip6addrctl.tproj/ip6addrctl.8
@@ -0,0 +1,126 @@
+.\" $KAME: ip6addrctl.8,v 1.3 2003/03/22 05:56:41 jinmei Exp $
+.\"
+.\" Copyright (C) 2001 WIDE Project.
+.\" 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 25, 2001
+.Dt IP6ADDRCTL 8
+.Os
+.\"
+.Sh NAME
+.Nm ip6addrctl
+.Nd configure address selection policy for IPv6 and IPv4
+.\"
+.Sh SYNOPSIS
+.Nm
+.Op Cm show
+.Nm
+.Cm add
+.Ar prefix precedence label
+.Nm
+.Cm delete
+.Ar prefix
+.Nm
+.Cm flush
+.Nm
+.Cm install
+.Ar configfile
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+utility manages the policy table of source and destination address
+selection for outgoing IPv4 and IPv6 packets.
+When
+.Nm
+is invoked without an argument or with a single argument
+.Cm show ,
+it prints the content of the policy table currently installed in the
+kernel.
+.Pp
+To modify the table, the following operations are available:
+.Bl -tag -width indent
+.It Cm add Ar prefix precedence label
+Add a policy entry.
+The
+.Ar prefix
+argument
+is an IPv6 prefix, which is a key for the entry.
+An IPv4 prefix should be specified with an IPv6 prefix using an
+IPv4-mapped IPv6 address.
+The
+.Ar precedence
+and
+.Ar label
+arguments
+are decimal numbers, which specify the precedence and label values
+for the entry, respectively.
+This operation should be performed without an existing entry for the
+prefix.
+.It Cm delete Ar prefix
+Delete a policy entry specified by
+.Ar prefix ,
+which should be an IPv6 prefix.
+A corresponding entry for the prefix should have already been
+installed.
+.It Cm flush
+Delete all existing policy entries in the kernel.
+.It Cm install Ar configfile
+Install policy entries from a configuration file named
+.Ar configfile .
+The configuration file should contain a set of policy entries.
+Each entry is specified in a single line which contains an IPv6 prefix,
+a decimal precedence value, and a decimal label value, separated with
+white space or tab characters.
+In the configuration file, lines beginning with the pound-sign
+.Pq Ql #
+are
+comments and are ignored.
+.El
+.\"
+.Sh EXIT STATUS
+.Ex -std
+.\"
+.Sh SEE ALSO
+.Rs
+.%A "Richard Draves"
+.%T "Default Address Selection for IPv6"
+.%N RFC 3484
+.Re
+.\"
+.Sh HISTORY
+The
+.Nm
+utility first appeared in the KAME IPv6 protocol stack kit.
+The original command name was
+.Nm addrselect ,
+but it was then renamed to the current one so that the name would
+describe its function well.
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/network_cmds/ip6addrctl.tproj/ip6addrctl.c b/network_cmds/ip6addrctl.tproj/ip6addrctl.c
new file mode 100644
index 0000000..400412a
--- /dev/null
+++ b/network_cmds/ip6addrctl.tproj/ip6addrctl.c
@@ -0,0 +1,467 @@
+/* $KAME: ip6addrctl.c,v 1.3 2003/12/16 08:14:28 suz Exp $ */
+
+/*
+ * Copyright (C) 2001 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+
+#include <stdlib.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <err.h>
+
+static char *configfile;
+
+struct policyqueue {
+ TAILQ_ENTRY(policyqueue) pc_entry;
+ struct in6_addrpolicy pc_policy;
+};
+TAILQ_HEAD(policyhead, policyqueue);
+struct policyhead policyhead;
+
+static void usage __P((void));
+static void get_policy __P((void));
+static void dump_policy __P((void));
+static int mask2plen __P((struct sockaddr_in6 *));
+static int parse_prefix __P((const char *, struct in6_addrpolicy *));
+static void make_policy_fromfile __P((char *));
+static void plen2mask __P((struct sockaddr_in6 *, int));
+static void set_policy __P((void));
+static void add_policy __P((char *, char *, char *));
+static void delete_policy __P((char *));
+static void flush_policy __P(());
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ TAILQ_INIT(&policyhead);
+
+ if (argc == 1 || strcasecmp(argv[1], "show") == 0) {
+ get_policy();
+ dump_policy();
+ } else if (strcasecmp(argv[1], "add") == 0) {
+ if (argc < 5)
+ usage();
+ add_policy(argv[2], argv[3], argv[4]);
+ } else if (strcasecmp(argv[1], "delete") == 0) {
+ if (argc < 3)
+ usage();
+ delete_policy(argv[2]);
+ } else if (strcasecmp(argv[1], "flush") == 0) {
+ get_policy();
+ flush_policy();
+ } else if (strcasecmp(argv[1], "install") == 0) {
+ if (argc < 3)
+ usage();
+ configfile = argv[2];
+ make_policy_fromfile(configfile);
+ set_policy();
+ } else
+ usage();
+
+ exit(0);
+}
+
+static void
+get_policy()
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
+ size_t l;
+ char *buf;
+ struct in6_addrpolicy *pol, *ep;
+
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
+ err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
+ /* NOTREACHED */
+ }
+ if (l == 0) {
+ printf("no source-address-selection policy is installed\n");
+ return;
+ }
+ if ((buf = malloc(l)) == NULL) {
+ errx(1, "malloc failed");
+ /* NOTREACHED */
+ }
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
+ err(1, "sysctl(IPV6CTL_ADDRCTLPOLICY)");
+ /* NOTREACHED */
+ }
+
+ ep = (struct in6_addrpolicy *)(buf + l);
+ for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
+ struct policyqueue *new;
+
+ if ((new = malloc(sizeof(*new))) == NULL)
+ errx(1, "malloc failed\n");
+ new->pc_policy = *pol;
+ TAILQ_INSERT_TAIL(&policyhead, new, pc_entry);
+ }
+
+ free(buf);
+}
+
+static void
+dump_policy()
+{
+ size_t addrlen;
+ char addrbuf[NI_MAXHOST];
+ struct in6_addrpolicy *pol;
+ struct policyqueue *ent;
+ int plen, first = 1;
+
+ for (ent = TAILQ_FIRST(&policyhead); ent;
+ ent = TAILQ_NEXT(ent, pc_entry)) {
+ pol = &ent->pc_policy;
+ if (first) {
+ printf("%-30s %5s %5s %8s\n",
+ "Prefix", "Prec", "Label", "Use");
+ first = 0;
+ }
+
+ if ((getnameinfo((struct sockaddr *)&pol->addr,
+ sizeof(pol->addr), addrbuf, sizeof(addrbuf),
+ NULL, 0, NI_NUMERICHOST))) {
+ warnx("getnameinfo for prefix address failed");
+ continue;
+ }
+ if ((plen = mask2plen(&pol->addrmask)) < 0) {
+ warnx("invalid address mask");
+ continue;
+ }
+ addrlen = strlen(addrbuf);
+ if (addrlen + sizeof("/128") < sizeof(addrbuf)) {
+ snprintf(&addrbuf[addrlen],
+ sizeof(addrbuf) - addrlen - 1,
+ "/%d", plen);
+ printf("%-30s", addrbuf);
+ } else /* XXX */
+ printf("%s/%d", addrbuf, plen);
+ printf(" %5d %5d %8llu\n", pol->preced, pol->label,
+ (unsigned long long)pol->use);
+ }
+}
+
+#define SKIP_WHITE(p, emptyok) \
+ do { \
+ while((*(p) == ' ' || *(p) == '\t')) \
+ (p)++; \
+ if ((*(p) == '\0' || (*(p) == '\n')) && !(emptyok)) \
+ goto bad; \
+ } while (0);
+#define SKIP_WORD(p) \
+ do { \
+ while(*(p) != ' ' && *(p) != '\t') \
+ (p)++; \
+ if (*(p) == '\0' || *(p) == '\n') \
+ goto bad; \
+ } while (0);
+
+static void
+make_policy_fromfile(conf)
+ char *conf;
+{
+ char line[_POSIX2_LINE_MAX], *cp;
+ char *addrstr;
+ FILE *fp;
+ int count = 0;
+ struct in6_addrpolicy pol0;
+ struct policyqueue *new;
+
+ if ((fp = fopen(conf, "r")) == NULL)
+ err(1, "fopen: %s", conf);
+
+ while(fgets(line, sizeof(line), fp)) {
+ count++;
+ cp = line;
+
+ memset(&pol0, 0, sizeof(pol0));
+
+ /* get prefix */
+ SKIP_WHITE(cp, 1);
+ if (*cp == '\n') /* empty line */
+ continue;
+ if (*cp == '#')
+ continue;
+ addrstr = cp;
+ if (parse_prefix((const char *)addrstr, &pol0))
+ goto bad;
+
+ /* get precedence value */
+ SKIP_WORD(cp);
+ SKIP_WHITE(cp, 0);
+ pol0.preced = atoi(cp);
+
+ /* get label */
+ SKIP_WORD(cp);
+ SKIP_WHITE(cp, 0);
+ pol0.label = atoi(cp);
+
+ /* parse succeeded. make a control buffer entry. */
+ if ((new = malloc(sizeof(*new))) == NULL)
+ errx(1, "malloc failed\n");
+ memset(new, 0, sizeof(*new));
+ new->pc_policy = pol0;
+ TAILQ_INSERT_TAIL(&policyhead, new, pc_entry);
+ }
+
+ fclose(fp);
+ return;
+
+ bad:
+ errx(1, "parse failed at line %d", count);
+ /* NOTREACHED */
+}
+
+static int
+parse_prefix(prefix0, pol)
+ const char *prefix0;
+ struct in6_addrpolicy *pol;
+{
+ int e = 0, plen;
+ char *prefix, *plenstr;
+ struct addrinfo hints, *res;
+
+ if ((prefix = strdup(prefix0)) == NULL)
+ errx(1, "strdup failed");
+
+ if ((plenstr = strchr(prefix, '/')) == NULL) {
+ e = -1;
+ goto end;
+ }
+ *plenstr = '\0';
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = AF_INET6;
+
+ if ((e = getaddrinfo(prefix, NULL, &hints, &res)) != 0) {
+ warnx("getaddrinfo failed for %s: %s", prefix,
+ gai_strerror(e));
+ goto end;
+ }
+ memcpy(&pol->addr, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ plen = atoi(plenstr + 1);
+ if (plen < 0 || plen > 128) {
+ warnx("invalid prefix length: %d", plen);
+ e = -1;
+ goto end;
+ }
+ plen2mask(&pol->addrmask, plen);
+
+ end:
+ free(prefix);
+ return(e);
+}
+
+static void
+plen2mask(mask, plen)
+ struct sockaddr_in6 *mask;
+ int plen;
+{
+ u_char *cp = (unsigned char *)&mask->sin6_addr;
+
+ memset(mask, 0, sizeof(*mask));
+ mask->sin6_family = AF_INET6; /* just in case */
+ mask->sin6_len = sizeof(*mask);
+
+ for(; plen >= 8; plen -= 8)
+ *cp++ = 0xff;
+ if (plen > 0)
+ *cp = (0xff << (8 - plen));
+}
+
+static void
+set_policy()
+{
+ struct policyqueue *ent;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(1, "socket(UDP)");
+
+ for (ent = TAILQ_FIRST(&policyhead); ent;
+ ent = TAILQ_NEXT(ent, pc_entry)) {
+ if (ioctl(s, SIOCAADDRCTL_POLICY, &ent->pc_policy))
+ warn("ioctl(SIOCAADDRCTL_POLICY)");
+ }
+
+ close(s);
+}
+
+static int
+mask2plen(mask)
+ struct sockaddr_in6 *mask;
+{
+ int masklen, final = 0;
+ u_char *p, *lim;
+
+ masklen = 0;
+ lim = (u_char *)(mask + 1);
+ for (p = (u_char *)(&mask->sin6_addr); p < lim; p++) {
+ if (final && *p) {
+ goto bad;
+ }
+
+ switch (*p & 0xff) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ final++;
+ break;
+ case 0xfc:
+ masklen += 6;
+ final++;
+ break;
+ case 0xf8:
+ masklen += 5;
+ final++;
+ break;
+ case 0xf0:
+ masklen += 4;
+ final++;
+ break;
+ case 0xe0:
+ masklen += 3;
+ final++;
+ break;
+ case 0xc0:
+ masklen += 2;
+ final++;
+ break;
+ case 0x80:
+ masklen += 1;
+ final++;
+ break;
+ case 0x00:
+ final++;
+ break;
+ default:
+ goto bad;
+ break;
+ }
+ }
+ return(masklen);
+
+ bad:
+ return(-1);
+}
+
+static void
+add_policy(prefix, prec, label)
+ char *prefix, *prec, *label;
+{
+ struct in6_addrpolicy p;
+ int s;
+
+ memset(&p, 0, sizeof(p));
+
+ if (parse_prefix((const char *)prefix, &p))
+ errx(1, "bad prefix: %s", prefix);
+ p.preced = atoi(prec);
+ p.label = atoi(label);
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(1, "socket(UDP)");
+ if (ioctl(s, SIOCAADDRCTL_POLICY, &p))
+ err(1, "ioctl(SIOCAADDRCTL_POLICY)");
+
+ close(s);
+}
+
+static void
+delete_policy(prefix)
+ char *prefix;
+{
+ struct in6_addrpolicy p;
+ int s;
+
+ memset(&p, 0, sizeof(p));
+
+ if (parse_prefix((const char *)prefix, &p))
+ errx(1, "bad prefix: %s", prefix);
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(1, "socket(UDP)");
+ if (ioctl(s, SIOCDADDRCTL_POLICY, &p))
+ err(1, "ioctl(SIOCDADDRCTL_POLICY)");
+
+ close(s);
+}
+
+static void
+flush_policy()
+{
+ struct policyqueue *ent;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ err(1, "socket(UDP)");
+
+ for (ent = TAILQ_FIRST(&policyhead); ent;
+ ent = TAILQ_NEXT(ent, pc_entry)) {
+ if (ioctl(s, SIOCDADDRCTL_POLICY, &ent->pc_policy))
+ warn("ioctl(SIOCDADDRCTL_POLICY)");
+ }
+
+ close(s);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: ip6addrctl [show]\n");
+ fprintf(stderr, " ip6addrctl add "
+ "<prefix> <precedence> <label>\n");
+ fprintf(stderr, " ip6addrctl delete <prefix>\n");
+ fprintf(stderr, " ip6addrctl flush\n");
+ fprintf(stderr, " ip6addrctl install <configfile>\n");
+
+ exit(1);
+}
diff --git a/network_cmds/ip6addrctl.tproj/ip6addrctl.conf b/network_cmds/ip6addrctl.tproj/ip6addrctl.conf
new file mode 100644
index 0000000..a2b3759
--- /dev/null
+++ b/network_cmds/ip6addrctl.tproj/ip6addrctl.conf
@@ -0,0 +1,12 @@
+# default policy table based on RFC 3484.
+# usage: ip6addrctl install path_to_this_file
+#
+# $FreeBSD$
+#
+#Format:
+#Prefix Precedence Label
+::1/128 50 0
+::/0 40 1
+2002::/16 30 2
+::/96 20 3
+::ffff:0:0/96 10 4
diff --git a/network_cmds/kdumpd.tproj/com.apple.kdumpd.plist b/network_cmds/kdumpd.tproj/com.apple.kdumpd.plist
new file mode 100644
index 0000000..3b09ade
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/com.apple.kdumpd.plist
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>InitGroups</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.kdumpd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/kdumpd</string>
+ <string>/var/tmp/PanicDumps</string>
+ </array>
+ <key>Sockets</key>
+ <dict>
+ <key>Listener</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>1069</string>
+ <key>SockType</key>
+ <string>dgram</string>
+ </dict>
+ </dict>
+ <key>UserName</key>
+ <string>nobody</string>
+ <key>Umask</key>
+ <integer>7</integer>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <true/>
+ </dict>
+</dict>
+</plist>
diff --git a/network_cmds/kdumpd.tproj/kdump.h b/network_cmds/kdumpd.tproj/kdump.h
new file mode 100644
index 0000000..9536946
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdump.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)kdump.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _KDUMP_H_
+#define _KDUMP_H_
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+/* Mac OS X kernel core dump server, based on the BSD trivial file
+ * transfer protocol server (FreeBSD distribution), with several
+ * modifications. This server is *not* compatible with tftp, as the
+ * protocol has changed considerably.
+ */
+
+#define SEGSIZE 512 /* data segment size */
+#define MAXIMUM_KDP_PKTSIZE (16384)
+/*
+ * Packet types.
+ */
+#define RRQ 1 /* read request */
+#define WRQ 2 /* write request */
+#define DATA 3 /* data packet */
+#define ACK 4 /* acknowledgement */
+#define ERROR 5 /* error code */
+#define KDP_SEEK 6 /* Seek to specified offset */
+#define KDP_EOF 7 /* end of file */
+
+struct kdumphdr {
+ short th_opcode; /* packet type */
+ union {
+ unsigned int tu_block; /* block # */
+ unsigned int tu_code; /* error code */
+ char tu_stuff[1]; /* request packet stuff */
+ } th_u;
+ char th_data[0]; /* data or error string */
+}__attribute__((packed));
+
+#define th_block th_u.tu_block
+#define th_code th_u.tu_code
+#define th_stuff th_u.tu_stuff
+#define th_msg th_data
+
+/*
+ * Error codes.
+ */
+#define EUNDEF 0 /* not defined */
+#define ENOTFOUND 1 /* file not found */
+#define EACCESS 2 /* access violation */
+#define ENOSPACE 3 /* disk full or allocation exceeded */
+#define EBADOP 4 /* illegal KDUMP operation */
+#define EBADID 5 /* unknown transfer ID */
+#define EEXISTS 6 /* file already exists */
+#define ENOUSER 7 /* no such user */
+
+#define DEBUG 0
+#define WRITE_DEBUG 0
+#define KDUMPD_DEBUG_LEVEL LOG_ALERT
+#define KDP_LARGE_CRASHDUMP_PKT_SIZE (1440 - sizeof(struct udpiphdr))
+
+#endif
diff --git a/network_cmds/kdumpd.tproj/kdumpd.8 b/network_cmds/kdumpd.tproj/kdumpd.8
new file mode 100755
index 0000000..8ce4a8e
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdumpd.8
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tftpd.8 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/libexec/tftpd/tftpd.8,v 1.15 2001/07/15 07:53:42 dd Exp $
+.\"
+.Dd June 10, 2020
+.Dt KDUMPD 8
+.Os
+.Sh NAME
+.Nm kdumpd
+.Nd Mac OS X remote kernel core dump server
+.Sh SYNOPSIS
+.Nm /usr/libexec/kdumpd
+.Op Ar directory
+.Sh DESCRIPTION
+.Nm Kdumpd
+is a server which receives
+kernel states in the form of
+a core dump from a remote
+Mac OS X machine.
+The
+.Tn kdumpd
+server operates
+on UDP port 1069, although this
+may be configurable in the future.
+The server should be started by
+.Xr launchctl 1 .
+.Pp
+The server should have the user ID
+with the lowest possible privilege,
+usually the user "nobody".
+.Pp
+By default the server stores kernel cores
+in the directory
+.Pa /var/tmp/PanicDumps .
+The directory needs to already exist for kdumpd
+to save core dumps.
+.Pp
+The server returns an EEXIST error
+to the remote kernel if it receives a
+request for an existing file - i.e.
+only new files can be created. The server
+also disallows path specifications in the
+incoming file name.
+.Sh HISTORY
+The
+.Nm
+command is based on Berkeley
+.Xr tftpd 8 ,
+by way of FreeBSD, with several modifications.
+.Sh SEE ALSO
+.Xr launchd 8 ,
+.Xr launchctl 1 ,
+.Xr launchd.plist 5
diff --git a/network_cmds/kdumpd.tproj/kdumpd.c b/network_cmds/kdumpd.tproj/kdumpd.c
new file mode 100644
index 0000000..61762fe
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdumpd.c
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/* Mac OS X kernel core dump server, based on the BSD trivial file
+ * transfer protocol server (FreeBSD distribution), with several
+ * modifications. This server is *not* compatible with tftp, as the
+ * protocol has changed considerably.
+ */
+
+/*
+ * Based on the trivial file transfer protocol server.
+ *
+ * The original version included many modifications by Jim Guyton
+ * <guyton@rand-unix>.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <netinet/in.h>
+#include "kdump.h"
+#include <arpa/inet.h>
+
+#include <assert.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <libkern/OSByteOrder.h>
+
+#include "kdumpsubs.h"
+
+#define DEFAULT_KDUMPD_PORTNO (1069)
+#define TIMEOUT 2
+
+int peer;
+int rexmtval = TIMEOUT;
+int maxtimeout = 25 * TIMEOUT;
+
+#define PKTSIZE SEGSIZE+6
+
+char buf[MAXIMUM_KDP_PKTSIZE];
+char ackbuf[MAXIMUM_KDP_PKTSIZE];
+struct sockaddr_in from;
+socklen_t fromlen;
+
+void kdump __P((struct kdumphdr *, int));
+
+/*
+ * Null-terminated directory prefix list for absolute pathname requests and
+ * search list for relative pathname requests.
+ *
+ * MAXDIRS should be at least as large as the number of arguments that
+ * inetd allows (currently 20).
+ */
+#define MAXDIRS 20
+static struct dirlist {
+ char *name;
+ int len;
+} dirs[MAXDIRS+1];
+static int suppress_naks;
+static int logging = 1;
+static int ipchroot;
+static int server_mode = 1;
+
+static char *errtomsg __P((int));
+static void nak __P((int));
+static char * __P(verifyhost(struct sockaddr_in *));
+uint32_t kdp_crashdump_pkt_size = (SEGSIZE + (sizeof(struct kdumphdr)));
+uint32_t kdp_crashdump_seg_size = SEGSIZE;
+
+#define KDP_FEATURE_MASK_STRING "features"
+enum {KDP_FEATURE_LARGE_CRASHDUMPS = 1, KDP_FEATURE_LARGE_PKT_SIZE = 2};
+
+uint32_t kdp_crashdump_feature_mask;
+uint32_t kdp_feature_large_crashdumps, kdp_feature_large_packets;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct kdumphdr *tp;
+ register int n;
+ int ch, on;
+ struct sockaddr_in sin;
+ char *chroot_dir = NULL;
+ struct passwd *nobody;
+ char *chuser = "nobody";
+
+ openlog("kdumpd", LOG_PID | LOG_NDELAY, LOG_FTP);
+ while ((ch = getopt(argc, argv, "cClns:u:w")) != -1) {
+ switch (ch) {
+ case 'c':
+ ipchroot = 1;
+ break;
+ case 'C':
+ ipchroot = 2;
+ break;
+ case 'l':
+ logging = 1;
+ break;
+ case 'n':
+ suppress_naks = 1;
+ break;
+ case 's':
+ chroot_dir = optarg;
+ break;
+ case 'u':
+ chuser = optarg;
+ break;
+ case 'w':
+ server_mode = 0;
+ break;
+ default:
+ syslog(LOG_WARNING, "ignoring unknown option -%c", ch);
+ }
+ }
+
+ if (optind < argc) {
+ struct dirlist *dirp;
+
+ /* Get list of directory prefixes. Skip relative pathnames. */
+ for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
+ optind++) {
+ if (argv[optind][0] == '/') {
+ dirp->name = argv[optind];
+ dirp->len = strlen(dirp->name);
+ dirp++;
+ }
+ }
+ }
+ else if (chroot_dir) {
+ dirs->name = "/";
+ dirs->len = 1;
+ }
+ if (ipchroot && chroot_dir == NULL) {
+ syslog(LOG_ERR, "-c requires -s");
+ exit(1);
+ }
+
+ /* If we are not in server mode, skip the whole 'inetd' logic below. */
+ if (server_mode) {
+ on = 1;
+ if (ioctl(0, FIONBIO, &on) < 0) {
+ syslog(LOG_ERR, "ioctl(FIONBIO): %m");
+ exit(1);
+ }
+ fromlen = sizeof (from);
+ n = recvfrom(0, buf, sizeof (buf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ if (n < 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ exit(1);
+ }
+ /*
+ * Now that we have read the message out of the UDP
+ * socket, we fork and exit. Thus, inetd will go back
+ * to listening to the kdump port, and the next request
+ * to come in will start up a new instance of kdumpd.
+ *
+ * We do this so that inetd can run kdumpd in "wait" mode.
+ * The problem with kdumpd running in "nowait" mode is that
+ * inetd may get one or more successful "selects" on the
+ * kdump port before we do our receive, so more than one
+ * instance of kdumpd may be started up. Worse, if kdumpd
+ * breaks before doing the above "recvfrom", inetd would
+ * spawn endless instances, clogging the system.
+ */
+ {
+ int pid;
+ int i;
+ socklen_t j;
+
+ for (i = 1; i < 20; i++) {
+ pid = fork();
+ if (pid < 0) {
+ sleep(i);
+ /*
+ * flush out to most recently sent request.
+ *
+ * This may drop some requests, but those
+ * will be resent by the clients when
+ * they timeout. The positive effect of
+ * this flush is to (try to) prevent more
+ * than one kdumpd being started up to service
+ * a single request from a single client.
+ */
+ j = sizeof from;
+ i = recvfrom(0, buf, sizeof (buf), 0,
+ (struct sockaddr *)&from, &j);
+ if (i > 0) {
+ n = i;
+ fromlen = j;
+ }
+ } else {
+ break;
+ }
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ exit(1);
+ } else if (pid != 0) {
+ exit(0);
+ }
+ }
+ }
+
+ /*
+ * Since we exit here, we should do that only after the above
+ * recvfrom to keep inetd from constantly forking should there
+ * be a problem. See the above comment about system clogging.
+ */
+ if (chroot_dir) {
+ if (ipchroot) {
+ char tempchroot[MAXPATHLEN];
+ char *tempaddr;
+ struct stat sb;
+ int statret;
+
+ tempaddr = inet_ntoa(from.sin_addr);
+ snprintf(tempchroot, sizeof(tempchroot), "%s/%s", chroot_dir, tempaddr);
+ statret = stat(tempchroot, &sb);
+ if (((sb.st_mode & S_IFMT ) == S_IFDIR) &&
+ (statret == 0 || (statret == -1 && ipchroot == 1)))
+ chroot_dir = tempchroot;
+ }
+ /* Must get this before chroot because /etc might go away */
+ if ((nobody = getpwnam(chuser)) == NULL) {
+ syslog(LOG_ERR, "%s: no such user", chuser);
+ exit(1);
+ }
+ if (chroot(chroot_dir)) {
+ syslog(LOG_ERR, "chroot: %s: %m", chroot_dir);
+ exit(1);
+ }
+ chdir( "/" );
+ setuid(nobody->pw_uid);
+ } else if (0 != chdir(dirs->name)) {
+ syslog(LOG_ERR, "chdir%s: %m", dirs->name);
+ }
+
+ from.sin_family = AF_INET;
+ alarm(0);
+ close(0);
+ close(1);
+ peer = socket(AF_INET, SOCK_DGRAM, 0);
+ if (peer < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ exit(1);
+ }
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+
+ if (!server_mode) {
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ sin.sin_port = htons((uint16_t) DEFAULT_KDUMPD_PORTNO);
+ }
+
+ if (bind(peer, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ exit(1);
+ }
+
+ if (!server_mode) {
+ /*
+ * Wait for an incoming message from a remote peer, note that we need to
+ * populate n since kdump() expect the first message to be in buf
+ * already.
+ */
+ socklen_t slen = sizeof(from);
+ n = recvfrom(peer, buf, sizeof(buf), 0,
+ (struct sockaddr *) &from, &slen);
+ if (n <= 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ exit(1);
+ }
+ }
+
+ if (connect(peer, (struct sockaddr *)&from, sizeof(from)) < 0) {
+ syslog(LOG_ERR, "connect: %m");
+ exit(1);
+ }
+ tp = (struct kdumphdr *)buf;
+ tp->th_opcode = ntohs(tp->th_opcode);
+ if (tp->th_opcode == WRQ)
+ kdump(tp, n);
+ exit(1);
+}
+
+struct formats;
+int validate_access __P((char **, int));
+
+void recvfile __P((struct formats *));
+
+struct formats {
+ char *f_mode;
+ int (*f_validate) __P((char **, int));
+
+ void (*f_recv) __P((struct formats *));
+ int f_convert;
+} formats[] = {
+ { "netascii", validate_access, recvfile, 1 },
+ { "octet", validate_access, recvfile, 0 },
+ { 0 }
+};
+
+/*
+ * Handle initial connection protocol.
+ */
+void
+kdump(tp, size)
+ struct kdumphdr *tp;
+ int size;
+{
+ register char *cp;
+ int first = 1, ecode;
+ register struct formats *pf;
+ char *filename, *mode = NULL;
+
+ filename = cp = tp->th_stuff;
+again:
+ while (cp < buf + size) {
+ if (*cp == '\0')
+ break;
+ cp++;
+ }
+ if (*cp != '\0') {
+ nak(EBADOP);
+ exit(1);
+ }
+ if (first) {
+ mode = ++cp;
+ first = 0;
+ goto again;
+ }
+ for (cp = mode; *cp; cp++)
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+
+ cp++;
+ if (strncmp(KDP_FEATURE_MASK_STRING, cp, sizeof(KDP_FEATURE_MASK_STRING)) == 0) {
+ kdp_crashdump_feature_mask = ntohl(*(uint32_t *) (cp + sizeof(KDP_FEATURE_MASK_STRING)));
+ kdp_feature_large_crashdumps = kdp_crashdump_feature_mask & KDP_FEATURE_LARGE_CRASHDUMPS;
+ kdp_feature_large_packets = kdp_crashdump_feature_mask & KDP_FEATURE_LARGE_PKT_SIZE;
+
+ if (kdp_feature_large_packets) {
+ kdp_crashdump_pkt_size = KDP_LARGE_CRASHDUMP_PKT_SIZE;
+ kdp_crashdump_seg_size = kdp_crashdump_pkt_size - sizeof(struct kdumphdr);
+ }
+ syslog(KDUMPD_DEBUG_LEVEL, "Received feature mask %s:0x%x", cp, kdp_crashdump_feature_mask);
+ } else
+ syslog(KDUMPD_DEBUG_LEVEL, "Unable to locate feature mask, mode: %s", mode);
+
+ for (pf = formats; pf->f_mode; pf++)
+ if (strcmp(pf->f_mode, mode) == 0)
+ break;
+ if (pf->f_mode == 0) {
+ nak(EBADOP);
+ exit(1);
+ }
+ ecode = (*pf->f_validate)(&filename, tp->th_opcode);
+ if (logging) {
+ syslog(KDUMPD_DEBUG_LEVEL, "%s: %s request for %s: %s", verifyhost(&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ filename, errtomsg(ecode));
+ }
+ if (ecode) {
+ /*
+ * Avoid storms of naks to a RRQ broadcast for a relative
+ * bootfile pathname from a diskless Sun.
+ */
+ if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
+ exit(0);
+ nak(ecode);
+ exit(1);
+ }
+ if (tp->th_opcode == WRQ)
+ (*pf->f_recv)(pf);
+
+ exit(0);
+}
+
+
+FILE *file;
+
+/*
+ * Validate file access. We only allow storage of files that do not already
+ * exist, and that do not include directory specifiers in their pathnames.
+ * This is because kernel coredump filenames should always be of the form
+ * "core-version-IP as dotted quad-random string" as in :
+ * core-custom-17.202.40.204-a75b4eec
+ * The file is written to the directory supplied as the first argument
+ * in inetd.conf
+ */
+
+int
+validate_access(char **filep, int mode)
+{
+ struct stat stbuf;
+ int fd;
+ char *filename = *filep;
+ static char pathname[MAXPATHLEN];
+
+ if (strstr(filename, "/") || strstr(filename, ".."))
+ return (EACCESS);
+
+ snprintf(pathname, sizeof(pathname), "./%s", filename);
+
+ if (0 == stat(pathname, &stbuf))
+ return (EEXIST);
+
+ if (errno != ENOENT)
+ return (errno);
+
+
+ fd = open(filename, O_RDWR|O_CREAT|O_TRUNC , S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+
+ if (fd < 0)
+ return (errno + 100);
+
+ file = fdopen(fd, (mode == RRQ)? "r":"w");
+ if (file == NULL) {
+ return errno+100;
+ }
+
+ return (0);
+}
+
+int timeout;
+jmp_buf timeoutbuf;
+
+void
+timer()
+{
+
+ timeout += rexmtval;
+ if (timeout >= maxtimeout)
+ {
+ longjmp(timeoutbuf, 2);
+ }
+ longjmp(timeoutbuf, 1);
+}
+
+void
+justquit()
+{
+ exit(0);
+}
+
+/*
+ * Receive a file.
+ */
+void
+recvfile(pf)
+ struct formats *pf;
+{
+ struct kdumphdr *dp, *w_init();
+ register struct kdumphdr *ap; /* ack buffer */
+ register int n, size;
+ volatile unsigned int block;
+ volatile unsigned int jmpval = 0;
+
+ signal(SIGALRM, timer);
+ dp = w_init();
+ ap = (struct kdumphdr *)ackbuf;
+ block = 0;
+ do {
+send_seek_ack: timeout = 0;
+ if (block == 0)
+ ap->th_opcode = htons((u_short)ACK | ((kdp_feature_large_crashdumps | kdp_feature_large_packets) << 8));
+ else
+ ap->th_opcode = htons((u_short)ACK);
+ ap->th_block = htonl((unsigned int)block);
+ block++;
+ jmpval = setjmp(timeoutbuf);
+ if (2 == jmpval)
+ {
+ syslog (LOG_ERR, "Timing out and flushing file to disk");
+ goto flushfile;
+ }
+send_ack:
+ if (send(peer, ackbuf, 6 , 0) != 6) {
+ syslog(LOG_ERR, "write: %m");
+ goto abort;
+ }
+ write_behind(file, pf->f_convert);
+ for ( ; ; ) {
+ alarm(rexmtval);
+ n = recv(peer, dp, kdp_crashdump_pkt_size, 0);
+ alarm(0);
+ if (n < 0) { /* really? */
+ syslog(LOG_ERR, "read: %m");
+ goto abort;
+ }
+ dp->th_opcode = ntohs((u_short)dp->th_opcode);
+ dp->th_block = ntohl((unsigned int)dp->th_block);
+#if DEBUG
+ syslog(KDUMPD_DEBUG_LEVEL, "Received packet type %u, block %u\n", (unsigned)dp->th_opcode, (unsigned)dp->th_block);
+#endif
+
+ if (dp->th_opcode == ERROR)
+ goto abort;
+
+ if (dp->th_opcode == KDP_EOF)
+ {
+ syslog (LOG_ERR, "Received last panic dump packet");
+ goto final_ack;
+ }
+ if (dp->th_opcode == KDP_SEEK)
+ {
+ if (dp->th_block == block)
+ {
+ off_t crashdump_offset = 0;
+ unsigned int tempoff = 0;
+
+ if (kdp_feature_large_crashdumps) {
+ crashdump_offset = OSSwapBigToHostInt64((*(uint64_t *)dp->th_data));
+ }
+ else {
+ bcopy (dp->th_data, &tempoff, sizeof(unsigned int));
+ crashdump_offset = ntohl(tempoff);
+ }
+
+#if DEBUG
+ syslog(KDUMPD_DEBUG_LEVEL, "Seeking to offset 0x%llx\n", crashdump_offset);
+#endif
+ errno = 0;
+ lseek(fileno (file), crashdump_offset, SEEK_SET);
+ if (errno)
+ syslog (LOG_ERR, "lseek: %m");
+
+ goto send_seek_ack;
+ }
+ (void) synchnet(peer);
+ if (dp->th_block == (block-1))
+ {
+ syslog (LOG_DAEMON|LOG_ERR, "Retransmitting seek ack - current block %u, received block %u", block, dp->th_block);
+ goto send_ack; /* rexmit */
+ }
+ }
+
+ if (dp->th_opcode == DATA) {
+ if (dp->th_block == block) {
+ break; /* normal */
+ }
+ /* Re-synchronize with the other side */
+ (void) synchnet(peer);
+ if (dp->th_block == (block-1))
+ {
+ syslog (LOG_DAEMON|LOG_ERR, "Retransmitting ack - current block %u, received block %u", block, dp->th_block);
+ goto send_ack; /* rexmit */
+ }
+ else
+ syslog (LOG_DAEMON|LOG_ERR, "Not retransmitting ack - current block %u, received block %u", block, dp->th_block);
+ }
+ }
+#if DEBUG
+ syslog(KDUMPD_DEBUG_LEVEL, "Writing block sized %u, current offset 0x%llx\n", n - 6, ftello(file));
+#endif
+ size = writeit(file, &dp, n - 6, pf->f_convert);
+ if (size != (n-6)) { /* ahem */
+ if (size < 0) nak(errno + 100);
+ else nak(ENOSPACE);
+ goto abort;
+ }
+ } while (dp->th_opcode != KDP_EOF);
+
+final_ack:
+ ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
+ ap->th_block = htonl((unsigned int) (block));
+ (void) send(peer, ackbuf, 6, 0);
+flushfile:
+ write_behind(file, pf->f_convert);
+ (void) fclose(file); /* close data file */
+ syslog (LOG_ERR, "file closed, sending final ACK\n");
+
+ signal(SIGALRM, justquit); /* just quit on timeout */
+ alarm(rexmtval);
+ n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
+ alarm(0);
+ if (n >= 6 && /* if read some data */
+ dp->th_opcode == DATA && /* and got a data block */
+ block == dp->th_block) { /* then my last ack was lost */
+ (void) send(peer, ackbuf, 6, 0); /* resend final ack */
+ }
+abort:
+ return;
+}
+
+/* update if needed, when adding new errmsgs */
+#define MAXERRMSGLEN 40
+
+struct errmsg {
+ int e_code;
+ char *e_msg;
+} errmsgs[] = {
+ { EUNDEF, "Undefined error code" },
+ { ENOTFOUND, "File not found" },
+ { EACCESS, "Access violation" },
+ { ENOSPACE, "Disk full or allocation exceeded" },
+ { EBADOP, "Illegal KDUMP operation" },
+ { EBADID, "Unknown transfer ID" },
+ { EEXISTS, "File already exists" },
+ { ENOUSER, "No such user" },
+ { -1, 0 }
+};
+
+static char *
+errtomsg(error)
+ int error;
+{
+ static char buf[20];
+ register struct errmsg *pe;
+ if (error == 0)
+ return "success";
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ return pe->e_msg;
+ snprintf(buf, sizeof(buf), "error %d", error);
+ return buf;
+}
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard KDUMP codes, or a UNIX errno
+ * offset by 100.
+ */
+static void
+nak(error)
+ int error;
+{
+ register struct kdumphdr *tp;
+ int length;
+ register struct errmsg *pe;
+
+ tp = (struct kdumphdr *)buf;
+ tp->th_opcode = htons((u_short)ERROR);
+ tp->th_code = htons((unsigned int)error);
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ break;
+ if (pe->e_code < 0) {
+ pe->e_msg = strerror(error - 100);
+ tp->th_code = EUNDEF; /* set 'undef' errorcode */
+ }
+ if (strlen(pe->e_msg) > MAXERRMSGLEN) {
+ syslog(LOG_ERR, "nak: error msg too long");
+ return;
+ }
+
+ strlcpy(tp->th_msg, pe->e_msg, MAXERRMSGLEN);
+ length = strlen(pe->e_msg);
+ tp->th_msg[length] = '\0';
+ length += 5;
+ if (send(peer, buf, length, 0) != length)
+ syslog(LOG_ERR, "nak: %m");
+
+ return;
+}
+
+static char *
+verifyhost(fromp)
+ struct sockaddr_in *fromp;
+{
+ struct hostent *hp;
+
+ hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(fromp->sin_addr),
+ fromp->sin_family);
+ if(hp)
+ return hp->h_name;
+ else
+ return inet_ntoa(fromp->sin_addr);
+}
diff --git a/network_cmds/kdumpd.tproj/kdumpsubs.c b/network_cmds/kdumpd.tproj/kdumpsubs.c
new file mode 100644
index 0000000..283ca62
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdumpsubs.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Simple minded read-ahead/write-behind subroutines for tftp user and
+ server. Written originally with multiple buffers in mind, but current
+ implementation has two buffer logic wired in.
+
+ Todo: add some sort of final error check so when the write-buffer
+ is finally flushed, the caller can detect if the disk filled up
+ (or had an i/o error) and return a nak to the other side.
+
+ Jim Guyton 10/85
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+#include <netinet/in.h>
+#include "kdump.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <syslog.h>
+
+#include "kdumpsubs.h"
+
+#define PKTSIZE SEGSIZE+6 /* should be moved to kdump.h */
+
+struct bf {
+ int counter; /* size of data in buffer, or flag */
+ char buf[MAXIMUM_KDP_PKTSIZE]; /* room for data packet */
+} bfs[2];
+
+ /* Values for bf.counter */
+#define BF_ALLOC -3 /* alloc'd but not yet filled */
+#define BF_FREE -2 /* free */
+/* [-1 .. SEGSIZE] = size of data in the data buffer */
+
+static int nextone; /* index of next buffer to use */
+static int current; /* index of buffer in use */
+
+ /* control flags for crlf conversions */
+int newline = 0; /* fillbuf: in middle of newline expansion */
+int prevchar = -1; /* putbuf: previous char (cr check) */
+
+static struct kdumphdr *rw_init __P ((int));
+
+struct kdumphdr *w_init() { return rw_init(0); } /* write-behind */
+struct kdumphdr *r_init() { return rw_init(1); } /* read-ahead */
+
+extern uint32_t kdp_crashdump_pkt_size;
+extern uint32_t kdp_crashdump_seg_size;
+
+/* init for either read-ahead or write-behind */
+/* zero for write-behind, one for read-head */
+static struct kdumphdr *
+rw_init(int x)
+{
+ newline = 0; /* init crlf flag */
+ prevchar = -1;
+ bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
+ current = 0;
+ bfs[1].counter = BF_FREE;
+ nextone = x; /* ahead or behind? */
+ return (struct kdumphdr *)bfs[0].buf;
+}
+
+
+/* Have emptied current buffer by sending to net and getting ack.
+ Free it and return next buffer filled with data.
+ */
+/* if true, convert to ascii */
+/* file opened for read */
+
+/* int */
+/* readit(FILE *file, struct kdumphdr **dpp, int convert) */
+/* { */
+/* struct bf *b; */
+
+/* bfs[current].counter = BF_FREE; /\* free old one *\/ */
+/* current = !current; /\* "incr" current *\/ */
+
+/* b = &bfs[current]; /\* look at new buffer *\/ */
+/* if (b->counter == BF_FREE) /\* if it's empty *\/ */
+/* read_ahead(file, convert); /\* fill it *\/ */
+/* /\* assert(b->counter != BF_FREE);*\//\* check *\/ */
+/* *dpp = (struct kdumphdr *)b->buf; /\* set caller's ptr *\/ */
+/* return b->counter; */
+/* } */
+
+/*
+ * fill the input buffer, doing ascii conversions if requested
+ * conversions are lf -> cr,lf and cr -> cr, nul
+ */
+/* FILE *file; file opened for read */
+/* int convert; if true, convert to ascii */
+void
+read_ahead(FILE *file, int convert)
+{
+ register int i;
+ register char *p;
+ register int c;
+ struct bf *b;
+ struct kdumphdr *dp;
+
+ b = &bfs[nextone]; /* look at "next" buffer */
+ if (b->counter != BF_FREE) /* nop if not free */
+ return;
+ nextone = !nextone; /* "incr" next buffer ptr */
+
+ dp = (struct kdumphdr *)b->buf;
+
+ if (convert == 0) {
+ b->counter = read(fileno(file), dp->th_data, kdp_crashdump_seg_size);
+ return;
+ }
+
+ p = dp->th_data;
+ for (i = 0 ; i < kdp_crashdump_seg_size; i++) {
+ if (newline) {
+ if (prevchar == '\n')
+ c = '\n'; /* lf to cr,lf */
+ else c = '\0'; /* cr to cr,nul */
+ newline = 0;
+ }
+ else {
+ c = getc(file);
+ if (c == EOF) break;
+ if (c == '\n' || c == '\r') {
+ prevchar = c;
+ c = '\r';
+ newline = 1;
+ }
+ }
+ *p++ = c;
+ }
+ b->counter = (int)(p - dp->th_data);
+}
+
+/* Update count associated with the buffer, get new buffer
+ from the queue. Calls write_behind only if next buffer not
+ available.
+ */
+int
+writeit(FILE *file, struct kdumphdr **dpp, int ct, int convert)
+{
+ bfs[current].counter = ct; /* set size of data to write */
+ current = !current; /* switch to other buffer */
+ if (bfs[current].counter != BF_FREE) /* if not free */
+ (void)write_behind(file, convert); /* flush it */
+ bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
+ *dpp = (struct kdumphdr *)bfs[current].buf;
+ return ct; /* this is a lie of course */
+}
+
+
+/*
+ * Output a buffer to a file, converting from netascii if requested.
+ * CR,NUL -> CR and CR,LF => LF.
+ * Note spec is undefined if we get CR as last byte of file or a
+ * CR followed by anything else. In this case we leave it alone.
+ */
+int
+write_behind(FILE *file, int convert)
+{
+ char *buf;
+ int count;
+ register int ct;
+ register char *p;
+ register int c; /* current character */
+ struct bf *b;
+ struct kdumphdr *dp;
+
+ b = &bfs[nextone];
+ if (b->counter < -1) /* anything to flush? */
+ return 0; /* just nop if nothing to do */
+
+ count = b->counter; /* remember byte count */
+ b->counter = BF_FREE; /* reset flag */
+ dp = (struct kdumphdr *)b->buf;
+ nextone = !nextone; /* incr for next time */
+ buf = dp->th_data;
+
+ if (count <= 0) return -1; /* nak logic? */
+
+ if (convert == 0)
+ return write(fileno(file), buf, count);
+
+ p = buf;
+ ct = count;
+ while (ct--) { /* loop over the buffer */
+ c = *p++; /* pick up a character */
+ if (prevchar == '\r') { /* if prev char was cr */
+ if (c == '\n') /* if have cr,lf then just */
+ fseek(file, -1, 1); /* smash lf on top of the cr */
+ else
+ if (c == '\0') /* if have cr,nul then */
+ goto skipit; /* just skip over the putc */
+ /* else just fall through and allow it */
+ }
+ putc(c, file);
+skipit:
+ prevchar = c;
+ }
+ return count;
+}
+
+
+/* When an error has occurred, it is possible that the two sides
+ * are out of synch. Ie: that what I think is the other side's
+ * response to packet N is really their response to packet N-1.
+ *
+ * So, to try to prevent that, we flush all the input queued up
+ * for us on the network connection on our host.
+ *
+ * We return the number of packets we flushed (mostly for reporting
+ * when trace is active).
+ */
+
+/*int f;socket to flush */
+int
+synchnet(int f)
+{
+ int i, j = 0;
+ char rbuf[kdp_crashdump_pkt_size];
+ struct sockaddr_in from;
+ socklen_t fromlen;
+
+ while (1) {
+ (void) ioctl(f, FIONREAD, &i);
+ if (i) {
+ j++;
+ fromlen = sizeof from;
+ (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ } else {
+ return(j);
+ }
+ }
+}
diff --git a/network_cmds/kdumpd.tproj/kdumpsubs.h b/network_cmds/kdumpd.tproj/kdumpsubs.h
new file mode 100644
index 0000000..b7ec1c6
--- /dev/null
+++ b/network_cmds/kdumpd.tproj/kdumpsubs.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)kdumpsubs.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Prototypes for read-ahead/write-behind subroutines for kdump user and
+ * server.
+ */
+struct kdumphdr *r_init __P((void));
+void read_ahead __P((FILE *, int));
+int readit __P((FILE *, struct kdumphdr **, int));
+
+int synchnet __P((int));
+
+struct kdumphdr *w_init __P((void));
+int write_behind __P((FILE *, int));
+int writeit __P((FILE *, struct kdumphdr **, int, int));
+
diff --git a/network_cmds/mnc.tproj/LICENCE b/network_cmds/mnc.tproj/LICENCE
new file mode 100644
index 0000000..4fec3e3
--- /dev/null
+++ b/network_cmds/mnc.tproj/LICENCE
@@ -0,0 +1,37 @@
+/*
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * 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 the HEAnet Ltd. 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 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.
+ *
+ */
+
diff --git a/network_cmds/mnc.tproj/README b/network_cmds/mnc.tproj/README
new file mode 100644
index 0000000..77cbaa8
--- /dev/null
+++ b/network_cmds/mnc.tproj/README
@@ -0,0 +1,63 @@
+1 MNC - Multicast NetCat
+ ------------------------
+
+1. Introduction
+
+mnc is a simple, one-direction-at-a-time, "netcat"-like application using
+multicast. The aim is to provide a tool for easy debugging and testing when
+setting up a multicast network or host. MNC supports IPv4 and IPv6
+any-source-multicast and single-source-multicast, but depending on your
+platform some of those features may not be available:
+
+ L = Listen (Implies IGMP/MLD mupport)
+ S = Send
+
+ +----------+----------+----------+----------+----------+
+ | Platform | IPv4 ASM | IPv4 SSM | IPv6 ASM | IPv6 SSM |
+ +----------+----------+----------+----------+----------+
+ | *nix | L + S | L + S | L + S | L + S |
+ +----------+----------+----------+----------+----------+
+ | Win2k | L + S | S | None | None |
+ +----------+----------+----------+----------+----------+
+ | WinXP | L + S | L + S | S | S |
+ +----------+----------+----------+----------+----------+
+ | Win2k3 | L + S | L + S | S | S |
+ +----------+----------+----------+----------+----------+
+
+man doc/mnc.1 for information and help on how to run multicast.
+
+2. Supported platforms
+
+As of September 2004, mnc has been compiled and tested with Linux 2.6.8
+kernels, the BSD KAME stack and Windows XP Profesional. Currently automatic
+interface selection does not work on a KAME-based host and you will need to
+specify the interface when in listening mode.
+
+3. Installing mnc from source on UNIX:
+
+ ./configure ; make ; make install
+
+4. Compiling from source on Windows:
+
+nmc is compilable with free utilities available from Microsoft. You need to
+download and install the free (as in beer) MS Visual C++ command-line tools
+from:
+
+ http://msdn.microsoft.com/visualc/vctoolkit2003/
+
+and the SDK relevant to your platform from:
+
+ http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
+
+You can run a Visual C++ command-line session, and use:
+
+ cl /DWINDOWS=1 /TC /c *.c
+ link /fixed /out:mnc.exe *.obj ws2_32.lib
+
+to compile a working mnc.exe. The Windows version of MNC does not yet fully
+support IPv6 due to underlying limitation in the Operating System.
+
+5. Reporting problems
+
+Any problems, bugs or suggested features should be mailed to colm
+at apache.org.
diff --git a/network_cmds/mnc.tproj/mnc.1 b/network_cmds/mnc.tproj/mnc.1
new file mode 100644
index 0000000..ed1073b
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc.1
@@ -0,0 +1,101 @@
+.\"
+.\" mnc.1 -- mnc manual
+.\"
+.\" Colm MacCárthaigh, <colm@apache.org>
+.\"
+.\" Copyright (c) 2007 Coolm MacCarthaigh.
+.\" Copyright (c) 2004-2006 HEAnet Ltd.
+.\"
+.\" This software is an open source.
+.\"
+.\" 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 the HEAnet Ltd. 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 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.
+.\"
+.TH mnc 1 "17 September 2004" "mnc"
+.SH NAME
+mnc \- Multicast NetCat
+.SH SYNOPSIS
+.BR mnc
+[ -l ] [ -i interface ] [ -p port ] group-id [ source-address ]
+.SH DESCRIPTION
+.B mnc
+is designed for simple multicast debugging and testing. It supports
+IPv4 and IPv6 any-source multicast and source-specific multicast.
+In standard mode it will multicast the standard-input verbatim.
+In listening mode it recieves the content and displays it on the
+standard output.
+.PP
+When given the optional source-address, mnc will attempt to use
+source-specific multicast. You may also specify this address
+in standard mode and mnc will use this source-address for
+outgoing packets.
+.PP
+.SH OPTIONS
+.IP \-l
+Listen for multicast packets. Default is to send.
+.IP \-i\ "interface"
+When listening for multicast packets, use the specified interface.
+.IP \-p\ "port"
+Specify a UDP port to use for sending or receiving packets. Default is to use port 1234.
+.SH "SEE ALSO"
+.BR nc (1)
+.PP
+.SH EXAMPLES
+To send IPv4 packets to an ASM group-id:
+.PP
+.RS
+mnc 233.1.2.3
+.RE
+.PP
+To receive IPv4 ASM packets from the same group-id, using eth0 as
+the listening interface:
+.PP
+.RS
+mnc -l -i eth0 233.1.2.3
+.RE
+.PP
+To receive IPv4 packets from an SSM group-id, using eth1 as the
+listening interface and 193.1.219.90 as the permitted source:
+.PP
+.RS
+mnc -l -i eth1 232.0.0.1 193.1.219.90
+.RE
+.PP
+To receive IPv6 packets from an SSM group-id, using eth1 as the
+listening interface and 2001:770:18:2::90 as the permitted source:
+.PP
+.RS
+mnc -l -i eth1 ff31::12 2001:770:18:2::90
+.RE
+.PP
+.SH CREDITS
+mnc is by Colm MacCárthaigh <colm@apache.org> and is available from:
+.PP
+http://people.apache.org/~colm/mnc/
+.PP
+Additional multicast development and support provided by John Lyons
+<john.lyons@heanet.ie> and Eoin Kenny <eoin.kenny@heanet.ie>
diff --git a/network_cmds/mnc.tproj/mnc.h b/network_cmds/mnc.tproj/mnc.h
new file mode 100644
index 0000000..db6e68e
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc.h
@@ -0,0 +1,92 @@
+/*
+ * $Id: mnc.h,v 1.4 2004/09/22 14:07:10 colmmacc Exp $
+ *
+ * mnc.h -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * 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 the HEAnet Ltd. 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 REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _MNC_H_
+#define _MNC_H_
+
+#ifndef WINDOWS
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#else
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#endif
+
+/* The UDP port MNC will use by default */
+#define MNC_DEFAULT_PORT "1234"
+
+struct mnc_configuration
+{
+ /* Are we sending or recieving ? */
+ enum {SENDER, LISTENER} mode;
+
+ /* What UDP port are we using ? */
+ char * port;
+
+ /* The group-id */
+ struct addrinfo * group;
+
+ /* The source */
+ struct addrinfo * source;
+
+ /* An interface index for listening */
+ char * iface;
+};
+
+
+/* Functions in mnc_opts.c */
+void usage(void);
+struct mnc_configuration * parse_arguments(int argc, char **argv);
+
+/* Functions in mnc_multicast.c */
+int multicast_setup_listen(int, struct addrinfo *, struct addrinfo *, char *);
+int multicast_setup_send(int, struct addrinfo *, struct addrinfo *);
+
+/* Functions in mnc_error.c */
+void mnc_warning(char * string, ...);
+void mnc_error(char * string, ...);
+
+#endif /* _MNC_H_ */
diff --git a/network_cmds/mnc.tproj/mnc_error.c b/network_cmds/mnc.tproj/mnc_error.c
new file mode 100644
index 0000000..4478e7e
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc_error.c
@@ -0,0 +1,95 @@
+/*
+ * $Id: mnc_error.c,v 1.2 2004/09/22 16:02:26 colmmacc Exp $
+ *
+ * mnc_multicast.c -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * 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 the HEAnet Ltd. 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 REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "mnc.h"
+
+void mnc_warning(char * string, ...)
+{
+ va_list ap;
+
+ /* Do the vararg stuff */
+ va_start(ap, string);
+
+ /* Output our name */
+ if (fprintf(stderr, "mnc: ") < 0)
+ {
+ exit(2);
+ }
+
+ /* Output our error */
+ if (vfprintf(stderr, string, ap) < 0)
+ {
+ exit(2);
+ }
+
+ /* End the vararg stuff */
+ va_end(ap);
+}
+
+void mnc_error(char * string, ...)
+{
+ va_list ap;
+
+ /* Do the vararg stuff */
+ va_start(ap, string);
+
+ /* Output our name */
+ if (fprintf(stderr, "mnc: ") < 0)
+ {
+ exit(2);
+ }
+
+ /* Output our error */
+ if (vfprintf(stderr, string, ap) < 0)
+ {
+ exit(2);
+ }
+
+ /* End the vararg stuff */
+ va_end(ap);
+
+ /* Die! */
+ exit(1);
+}
diff --git a/network_cmds/mnc.tproj/mnc_main.c b/network_cmds/mnc.tproj/mnc_main.c
new file mode 100644
index 0000000..1e5c5af
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc_main.c
@@ -0,0 +1,131 @@
+/*
+ * $Id: mnc_main.c,v 1.12 2004/09/22 19:14:23 colmmacc Exp $
+ *
+ * mnc_main.c -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * 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 the HEAnet Ltd. 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 REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef WINDOWS
+
+/* Non-windows includes */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#else
+
+/* Windows-specific includes */
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#endif /* WINDOWS */
+
+#include "mnc.h"
+
+int main(int argc, char **argv)
+{
+ /* Utility variables */
+ int sock,
+ len;
+ char buffer[1024];
+
+ /* Our main configuration */
+ struct mnc_configuration * config;
+
+#ifdef WINDOWS
+ WSADATA wsaData;
+
+ if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
+ {
+ mnc_error("This operating system is not supported\n");
+ }
+#endif
+
+ /* Parse the command line */
+ config = parse_arguments(argc, argv);
+
+ /* Create a socket */
+ if ((sock = socket(config->group->ai_family, config->group->ai_socktype,
+ config->group->ai_protocol)) < 0)
+ {
+ mnc_error("Could not create socket\n");
+ }
+
+ /* Are we supposed to listen? */
+ if (config->mode == LISTENER)
+ {
+ /* Set up the socket for listening */
+ if (multicast_setup_listen(sock, config->group, config->source,
+ config->iface) < 0)
+ {
+ mnc_error("Can not listen for multicast packets.\n");
+ }
+
+ /* Recieve the packets */
+ while ((len = recvfrom(sock, buffer, sizeof(buffer),
+ 0, NULL, NULL)) >= 0)
+ {
+ write(STDOUT_FILENO, buffer, len);
+ }
+ }
+ else /* Assume MODE == SENDER */
+ {
+ /* Set up the socket for sending */
+ if (multicast_setup_send(sock, config->group, config->source)
+ < 0)
+ {
+ mnc_error("Can not send multicast packets\n");
+ }
+
+ /* Send the packets */
+ while((len = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0)
+ {
+ sendto(sock, buffer, len, 0, config->group->ai_addr,
+ config->group->ai_addrlen);
+ }
+ }
+
+ /* Close the socket */
+ close(sock);
+
+ return 0;
+}
diff --git a/network_cmds/mnc.tproj/mnc_multicast.c b/network_cmds/mnc.tproj/mnc_multicast.c
new file mode 100644
index 0000000..35f3415
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc_multicast.c
@@ -0,0 +1,404 @@
+/*
+ * $Id: mnc_multicast.c,v 1.8 2004/09/22 19:14:23 colmmacc Exp $
+ *
+ * mnc_multicast.c -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * 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 the HEAnet Ltd. 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 REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef WINDOWS
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <string.h>
+#include <netdb.h>
+#include <errno.h>
+
+#else
+
+#include <sys/types.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <stdlib.h>
+
+#endif
+
+#include "mnc.h"
+
+#ifndef MCAST_JOIN_GROUP
+
+#ifdef IP_ADD_SOURCE_MEMBERSHIP
+int mnc_join_ipv4_ssm(int socket, struct addrinfo * group,
+ struct addrinfo * source, char * iface)
+{
+ struct ip_mreq_source multicast_request;
+
+ if (iface != NULL)
+ {
+ /* See if interface is a literal IPv4 address */
+ if ((multicast_request.imr_interface.s_addr =
+ inet_addr(iface)) == INADDR_NONE)
+ {
+ mnc_warning("Invalid interface address\n");
+ return -1;
+ }
+ }
+ else
+ {
+ /* set the interface to the default */
+ multicast_request.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ multicast_request.imr_multiaddr.s_addr =
+ ((struct sockaddr_in *)group->ai_addr)->sin_addr.s_addr;
+
+ multicast_request.imr_sourceaddr.s_addr =
+ ((struct sockaddr_in *)source->ai_addr)->sin_addr.s_addr;
+
+ /* Set the socket option */
+ if (setsockopt(socket, IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP,
+ (char *) &multicast_request,
+ sizeof(multicast_request)) != 0)
+ {
+ mnc_warning("Could not join the multicast group: %s\n",
+ strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+#else
+
+int mnc_join_ipv4_ssm(int socket, struct addrinfo * group,
+ struct addrinfo * source, char * iface)
+{
+ mnc_warning("Sorry, No support for IPv4 source-specific multicast in this build\n");
+
+ return -1;
+}
+#endif
+
+int mnc_join_ipv6_ssm(int socket, struct addrinfo * group,
+ struct addrinfo * source, char * iface)
+{
+ mnc_warning("Sorry, No support for IPv6 source-specific multicast in this build\n");
+
+ return -1;
+}
+#else /* if MCAST_JOIN_GROUP .. */
+
+#define mnc_join_ipv6_asm(a, b, c) mnc_join_ip_asm((a), (b), (c))
+#define mnc_join_ipv4_asm(a, b, c) mnc_join_ip_asm((a), (b), (c))
+
+int mnc_join_ip_asm(int socket, struct addrinfo * group, char * iface)
+{
+ struct group_req multicast_request;
+ int ip_proto;
+
+ if (group->ai_family == AF_INET6)
+ {
+ ip_proto = IPPROTO_IPV6;
+ }
+ else
+ {
+ ip_proto = IPPROTO_IP;
+ }
+
+ if (iface != NULL)
+ {
+ if ((multicast_request.gr_interface = if_nametoindex(iface))
+ == 0)
+ {
+ mnc_warning("Ignoring unknown interface: %s\n", iface);
+ }
+ }
+ else
+ {
+ multicast_request.gr_interface = 0;
+ }
+
+ memcpy(&multicast_request.gr_group, group->ai_addr, group->ai_addrlen);
+
+ /* Set the socket option */
+ if (setsockopt(socket, ip_proto, MCAST_JOIN_GROUP, (char *)
+ &multicast_request, sizeof(multicast_request)) != 0)
+ {
+ mnc_warning("Could not join the multicast group: %s\n",
+ strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* MCAST_JOIN_GROUP */
+
+#ifndef MCAST_JOIN_SOURCE_GROUP
+int mnc_join_ipv4_asm(int socket, struct addrinfo * group, char * iface)
+{
+ struct ip_mreq multicast_request;
+
+ if (iface != NULL)
+ {
+ /* See if interface is a literal IPv4 address */
+ if ((multicast_request.imr_interface.s_addr =
+ inet_addr(iface)) == INADDR_NONE)
+ {
+ mnc_warning("Invalid interface address\n");
+ return -1;
+ }
+ }
+ else
+ {
+ /* Set the interface to the default */
+ multicast_request.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ multicast_request.imr_multiaddr.s_addr =
+ ((struct sockaddr_in *)group->ai_addr)->sin_addr.s_addr;
+
+ /* Set the socket option */
+ if (setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *) &multicast_request,
+ sizeof(multicast_request)) != 0)
+ {
+ mnc_warning("Could not join the multicast group: %s\n",
+ strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+
+int mnc_join_ipv6_asm(int socket, struct addrinfo * group, char * iface)
+{
+ mnc_warning("Sorry, No support for IPv6 any-source multicast in this build\n");
+
+ return -1;
+}
+#else /* if MCAST_JOIN_SOURCE_GROUP ... */
+
+#define mnc_join_ipv4_ssm(a, b, c, d) mnc_join_ip_ssm((a), (b), (c), (d))
+#define mnc_join_ipv6_ssm(a, b, c, d) mnc_join_ip_ssm((a), (b), (c), (d))
+
+int mnc_join_ip_ssm(int socket, struct addrinfo * group,
+ struct addrinfo * source,
+ char * iface)
+{
+ struct group_source_req multicast_request;
+ int ip_proto;
+
+ if (group->ai_family == AF_INET6)
+ {
+ ip_proto = IPPROTO_IPV6;
+ }
+ else
+ {
+ ip_proto = IPPROTO_IP;
+ }
+
+ if (iface != NULL)
+ {
+ if ((multicast_request.gsr_interface = if_nametoindex(iface))
+ == 0)
+ {
+ mnc_warning("Ignoring unknown interface: %s\n", iface);
+ }
+ }
+ else
+ {
+ multicast_request.gsr_interface = 0;
+ }
+
+ memcpy(&multicast_request.gsr_group, group->ai_addr, group->ai_addrlen);
+ memcpy(&multicast_request.gsr_source, source->ai_addr,
+ source->ai_addrlen);
+
+ /* Set the socket option */
+ if (setsockopt(socket, ip_proto, MCAST_JOIN_SOURCE_GROUP,
+ (char *) &multicast_request,
+ sizeof(multicast_request)) != 0)
+ {
+ mnc_warning("Could not join the multicast group: %s\n",
+ strerror(errno));
+
+ return -1;
+ }
+
+ return 0;
+}
+#endif /* MCAST_JOIN_SOURCE_GROUP */
+
+int multicast_setup_listen(int socket, struct addrinfo * group,
+ struct addrinfo * source, char * iface)
+{
+ size_t rcvbuf;
+
+#ifndef WINDOWS
+ /* bind to the group address before anything */
+ if (bind(socket, group->ai_addr, group->ai_addrlen) != 0)
+ {
+ mnc_warning("Could not bind to group-id\n");
+ return -1;
+ }
+#else
+ if (group->ai_family == AF_INET)
+ {
+ struct sockaddr_in sin;
+
+ sin.sin_family = group->ai_family;
+ sin.sin_port = group->ai_port;
+ sin.sin_addr = INADDR_ANY;
+
+ if (bind(socket, (struct sockaddr *) sin,
+ sizeof(sin)) != 0)
+ {
+ mnc_warning("Could not bind to ::\n");
+ return -1;
+ }
+ }
+ else if (group->ai_family == AF_INET6)
+ {
+ struct sockaddr_in6 sin6;
+
+ sin6.sin6_family = group->ai_family;
+ sin6.sin6_port = group->ai_port;
+ sin6.sin6_addr = in6addr_any;
+
+ if (bind(socket, (struct sockaddr *) sin6,
+ sizeof(sin6)) != 0)
+ {
+ mnc_warning("Could not bind to ::\n");
+ return -1;
+ }
+ }
+#endif
+
+ /* Set a receive buffer size of 64k */
+ rcvbuf = 1 << 15;
+ if (setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
+ sizeof(rcvbuf)) < 0) {
+ mnc_warning("Could not set receive buffer to 64k\n");
+ }
+
+ if (source != NULL)
+ {
+ if (group->ai_family == AF_INET6)
+ {
+ /* Use whatever IPv6 API is appropriate */
+ return
+ mnc_join_ipv6_ssm(socket, group, source, iface);
+ }
+ else if (group->ai_family == AF_INET)
+ {
+ /* Use the fully portable IPv4 API */
+ return
+ mnc_join_ipv4_ssm(socket, group, source, iface);
+ }
+ else
+ {
+ mnc_warning("Only IPv4 and IPv6 are supported\n");
+ return -1;
+ }
+ }
+ else
+ {
+ if (group->ai_family == AF_INET6)
+ {
+ /* Use the fully portable IPv4 API */
+ return
+ mnc_join_ipv6_asm(socket, group, iface);
+ }
+ else if (group->ai_family == AF_INET)
+ {
+ /* Use the fully portable IPv4 API */
+ return
+ mnc_join_ipv4_asm(socket, group, iface);
+ }
+ else
+ {
+ mnc_warning("Only IPv4 and IPv6 are supported\n");
+ return -1;
+ }
+ }
+
+ /* We should never get here */
+ return -1;
+}
+
+
+int multicast_setup_send(int socket, struct addrinfo * group,
+ struct addrinfo * source)
+{
+ int ttl = 255;
+
+ if (source != NULL)
+ {
+ /* bind to the address before anything */
+ if (bind(socket, source->ai_addr, source->ai_addrlen) != 0)
+ {
+ mnc_warning("Could not bind to source-address\n");
+ return -1;
+ }
+ }
+
+ if (group->ai_family == AF_INET)
+ {
+ if (setsockopt(socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)
+ &ttl, sizeof(ttl)) != 0)
+ {
+ mnc_warning("Could not increase the TTL\n");
+ return -1;
+ }
+ }
+ else if (group->ai_family == AF_INET6)
+ {
+ if (setsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ (char *) &ttl, sizeof(ttl)) != 0)
+ {
+ mnc_warning("Could not increase the hop-count\n");
+ return -1;
+ }
+ }
+
+ return 0;
+}
diff --git a/network_cmds/mnc.tproj/mnc_opts.c b/network_cmds/mnc.tproj/mnc_opts.c
new file mode 100644
index 0000000..606746f
--- /dev/null
+++ b/network_cmds/mnc.tproj/mnc_opts.c
@@ -0,0 +1,182 @@
+/*
+ * $Id: mnc_opts.c,v 1.3 2004/09/22 16:02:26 colmmacc Exp $
+ *
+ * mnc_opts.c -- Multicast NetCat
+ *
+ * Colm MacCarthaigh, <colm@apache.org>
+ *
+ * Copyright (c) 2007, Colm MacCarthaigh.
+ * Copyright (c) 2004 - 2006, HEAnet Ltd.
+ *
+ * This software is an open source.
+ *
+ * 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 the HEAnet Ltd. 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 REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifndef WINDOWS
+
+/* UNIX-y includes */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#else
+
+/* WINDOWS-y includes */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "mnc.h"
+
+/* Display a usage statement */
+void usage(void)
+{
+ fprintf(stderr,
+ "Usage: mnc [-l] [-i interface] [-p port] group-id "
+ "[source-address]\n\n"
+ "-l : listen mode\n"
+ "-i : specify interface to listen\n"
+ "-p : specify port to listen/send on\n\n");
+ exit(1);
+}
+
+struct mnc_configuration * parse_arguments(int argc, char **argv)
+{
+ /* Utility variables */
+ int optind,
+ errorcode;
+ struct addrinfo hints;
+
+ /* Our persisting configuration */
+ static struct mnc_configuration config;
+
+ /* Set some defaults */
+ config.mode = SENDER;
+ config.port = MNC_DEFAULT_PORT;
+ config.iface = NULL;
+ config.source = NULL;
+
+ /* Loop through the arguments */
+ for (optind = 1; optind < (argc - 1); optind++)
+ {
+ if ( (argv[optind][0] == '-') || (argv[optind][0] == '/') )
+ {
+ switch(argv[optind][1])
+ {
+ /* Set listening mode */
+ case 'l': config.mode = LISTENER;
+ break;
+
+ /* Set port */
+ case 'p': config.port = argv[++optind];
+ break;
+
+ /* Set an interface */
+ case 'i': config.iface = argv[++optind];
+ break;
+
+ /* Unrecognised option */
+ default: usage();
+ break;
+ }
+ }
+ else
+ {
+ /* assume we've ran out of options */
+ break;
+ }
+ }
+
+ /* There's a chance we were passed one option */
+ if (optind >= argc || argv[optind][0] == '-')
+ {
+ usage();
+ }
+
+ /* Now make sure we have either exactly 1 or 2 more arguments */
+ if ( (argc - optind) != 1 && (argc - optind) != 2 )
+ {
+ /* We have not been given the right ammount of
+ arguments */
+ usage();
+ }
+
+ /* You can't have an interface without also listening */
+ if (config.mode == SENDER && config.iface != NULL)
+ {
+ mnc_error("You may only specify the interface when in"
+ " listening mode\n");
+ }
+
+ /* Set some hints for getaddrinfo */
+ memset(&hints, 0, sizeof(hints));
+
+ /* We want a UDP socket */
+ hints.ai_socktype = SOCK_DGRAM;
+
+ /* Don't do any name-lookups */
+ hints.ai_flags = AI_NUMERICHOST;
+
+ /* Get the group-id information */
+ if ( (errorcode =
+ getaddrinfo(argv[optind], config.port, &hints, &config.group)) != 0)
+ {
+ mnc_error("Error getting group-id address information: %s\n",
+ gai_strerror(errorcode));
+ }
+
+ /* Move on to next argument */
+ optind++;
+
+ /* Get the source information */
+ if ( (argc - optind) == 1)
+ {
+
+ if ( (errorcode =
+ getaddrinfo(argv[optind], config.port, &hints, &config.source))
+ != 0)
+ {
+ mnc_error("Error getting source-address information: %s\n",
+ gai_strerror(errorcode));
+ }
+
+ /* Confirm that the source and group are in the same Address Family */
+ if ( config.source->ai_family != config.group->ai_family )
+ {
+ mnc_error("Group ID and Source address are not of "
+ "the same type\n");
+ }
+ }
+
+ return &config;
+}
diff --git a/network_cmds/mptcp_client/conn_lib.c b/network_cmds/mptcp_client/conn_lib.c
new file mode 100644
index 0000000..1c83915
--- /dev/null
+++ b/network_cmds/mptcp_client/conn_lib.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+//
+// Created by Anumita Biswas on 10/30/12.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+
+#include "conn_lib.h"
+
+int
+copyassocids(int s, sae_associd_t **aidpp, uint32_t *cnt)
+{
+ struct so_aidreq aidr;
+ sae_associd_t *buf;
+ int err;
+
+ if (aidpp == NULL || cnt == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ *aidpp = NULL;
+ *cnt = 0;
+
+ bzero(&aidr, sizeof (aidr));
+
+ err = ioctl(s, SIOCGASSOCIDS, &aidr);
+ if (err != 0)
+ return (-1);
+
+ /* none, just return */
+ if (aidr.sar_cnt == 0)
+ return (0);
+
+ buf = calloc(aidr.sar_cnt, sizeof (sae_associd_t));
+ if (buf == NULL)
+ return (-1);
+
+ aidr.sar_aidp = buf;
+ err = ioctl(s, SIOCGASSOCIDS, &aidr);
+ if (err != 0) {
+ free(buf);
+ return (-1);
+ }
+
+ *aidpp = buf;
+ *cnt = aidr.sar_cnt;
+
+ return (0);
+}
+
+void
+freeassocids(sae_associd_t *aidp)
+{
+ free(aidp);
+}
+
+int
+copyconnids(int s, sae_associd_t aid, sae_connid_t **cidp, uint32_t *cnt)
+{
+ struct so_cidreq cidr;
+ sae_connid_t *buf;
+ int err;
+
+ if (cidp == NULL || cnt == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+ *cidp = NULL;
+ *cnt = 0;
+
+ bzero(&cidr, sizeof (cidr));
+
+ cidr.scr_aid = aid;
+ err = ioctl(s, SIOCGCONNIDS, &cidr);
+ if (err != 0)
+ return (-1);
+
+ /* none, just return */
+ if (cidr.scr_cnt == 0)
+ return (0);
+
+ buf = calloc(cidr.scr_cnt, sizeof (sae_connid_t));
+ if (buf == NULL)
+ return (-1);
+
+ cidr.scr_cidp = buf;
+ err = ioctl(s, SIOCGCONNIDS, &cidr);
+ if (err != 0) {
+ free(buf);
+ return (-1);
+ }
+
+ *cidp = buf;
+ *cnt = cidr.scr_cnt;
+
+ return (0);
+}
+
+void
+freeconnids(sae_connid_t *cidp)
+{
+ free(cidp);
+}
+
+int
+copyconninfo(int s, sae_connid_t cid, conninfo_t **cfop)
+{
+ struct sockaddr *src = NULL, *dst = NULL, *aux = NULL;
+ struct so_cinforeq scir;
+ conninfo_t *buf = NULL;
+
+ if (cfop == NULL) {
+ errno = EINVAL;
+ goto error;
+ }
+ *cfop = NULL;
+
+ bzero(&scir, sizeof (scir));
+
+ scir.scir_cid = cid;
+ if (ioctl(s, SIOCGCONNINFO, &scir) != 0)
+ goto error;
+
+ if (scir.scir_src_len != 0) {
+ src = calloc(1, scir.scir_src_len);
+ if (src == NULL)
+ goto error;
+ scir.scir_src = src;
+ }
+ if (scir.scir_dst_len != 0) {
+ dst = calloc(1, scir.scir_dst_len);
+ if (dst == NULL)
+ goto error;
+ scir.scir_dst = dst;
+ }
+ if (scir.scir_aux_len != 0) {
+ aux = calloc(1, scir.scir_aux_len);
+ if (aux == NULL)
+ goto error;
+ scir.scir_aux_data = aux;
+ }
+
+ if (ioctl(s, SIOCGCONNINFO, &scir) != 0)
+ goto error;
+
+ buf = calloc(1, sizeof (*buf));
+ if (buf == NULL)
+ goto error;
+
+ // When we query for the length using the first ioctl call above, the kernel
+ // tells us the length of the aux structure so we know how much to allocate
+ // memory. There may not be any aux data, which will be indicated by the aux
+ // data length using the second ioctl call.
+ if (scir.scir_aux_len == 0 && aux != NULL) {
+ free(aux);
+ aux = NULL;
+ scir.scir_aux_data = NULL;
+ }
+
+ buf->ci_flags = scir.scir_flags;
+ buf->ci_ifindex = scir.scir_ifindex;
+ buf->ci_src = src;
+ buf->ci_dst = dst;
+ buf->ci_error = scir.scir_error;
+ buf->ci_aux_type = scir.scir_aux_type;
+ buf->ci_aux_data = aux;
+ *cfop = (conninfo_t*)buf;
+
+ return (0);
+
+error:
+ if (src != NULL)
+ free(src);
+ if (dst != NULL)
+ free(dst);
+ if (aux != NULL)
+ free(aux);
+ if (buf != NULL)
+ free(buf);
+
+ return (-1);
+}
+
+void
+freeconninfo(conninfo_t *cfo)
+{
+ if (cfo->ci_src != NULL)
+ free(cfo->ci_src);
+
+ if (cfo->ci_dst != NULL)
+ free(cfo->ci_dst);
+
+ if (cfo->ci_aux_data != NULL)
+ free(cfo->ci_aux_data);
+
+ free(cfo);
+}
diff --git a/network_cmds/mptcp_client/conn_lib.h b/network_cmds/mptcp_client/conn_lib.h
new file mode 100644
index 0000000..b69b73c
--- /dev/null
+++ b/network_cmds/mptcp_client/conn_lib.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+//
+// Created by Anumita Biswas on 10/30/12.
+//
+
+#ifndef mptcp_client_conn_lib_h
+#define mptcp_client_conn_lib_h
+
+typedef struct conninfo {
+ __uint32_t ci_flags; /* see flags in sys/socket.h (CIF_CONNECTING, etc...) */
+ __uint32_t ci_ifindex; /* outbound interface */
+ struct sockaddr *ci_src; /* source address */
+ struct sockaddr *ci_dst; /* destination address */
+ int ci_error; /* saved error */
+ __uint32_t ci_aux_type; /* auxiliary data type */
+ void *ci_aux_data; /* auxiliary data */
+} conninfo_t;
+
+extern int copyassocids(int, sae_associd_t **, uint32_t *);
+extern void freeassocids(sae_associd_t *);
+extern int copyconnids(int, sae_associd_t, sae_connid_t **, uint32_t *);
+extern void freeconnids(sae_connid_t *);
+extern int copyconninfo(int, sae_connid_t, conninfo_t **);
+extern void freeconninfo(conninfo_t *);
+
+#endif
diff --git a/network_cmds/mptcp_client/mptcp_client.1 b/network_cmds/mptcp_client/mptcp_client.1
new file mode 100644
index 0000000..2ca3cad
--- /dev/null
+++ b/network_cmds/mptcp_client/mptcp_client.1
@@ -0,0 +1,21 @@
+.Dd 6/12/14
+.Dt mptcp_client 1
+.Os Darwin
+.Sh NAME
+.Nm mptcp_client
+.Nd Tool to exercise MPTCP.
+.Sh SYNOPSIS
+.Nm
+.Ar hostname
+.Ar port
+.Ar reqlen
+.Ar rsplen
+.Ar times
+.Ar alt_addr
+.Ar 0
+.Ar longlived
+.Sh DESCRIPTION
+.Nm
+is as an MPTCP client test tool that use the
+.Xr socket 2
+API.
diff --git a/network_cmds/mptcp_client/mptcp_client.c b/network_cmds/mptcp_client/mptcp_client.c
new file mode 100644
index 0000000..770aabc
--- /dev/null
+++ b/network_cmds/mptcp_client/mptcp_client.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+//
+// Created by Anumita Biswas on 7/17/12.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <err.h>
+#include <sysexits.h>
+#include <getopt.h>
+
+#include "conn_lib.h"
+
+struct so_cordreq socorder;
+static void showmpinfo(int s);
+
+#define MSG_HDR "Message Header"
+#define RESPONSE "I got your message"
+
+static int verbose = 0;
+
+static int32_t thiszone = 0; /* time difference with gmt */
+
+char *setup_buffer1(int bufsz)
+{
+ int i = 0, j = 1;
+ char *buf;
+
+ buf = malloc(bufsz);
+ if (!buf)
+ return NULL;
+
+ bzero(buf, bufsz);
+ strlcpy(buf, MSG_HDR, bufsz);
+
+ for (i = sizeof(MSG_HDR); i < bufsz; i++) {
+ buf[i] = j;
+ j++;
+ if (j >= 255)
+ j = 1;
+ }
+ return buf;
+}
+
+char *setup_buffer2(int bufsz)
+{
+ int i = 0;
+ char j = 'A';
+ char *buf;
+
+ buf = malloc(bufsz);
+ if (!buf)
+ return NULL;
+
+ bzero(buf, bufsz);
+ strlcpy(buf, MSG_HDR, bufsz);
+
+ for (i = sizeof(MSG_HDR); i < bufsz; i++) {
+ buf[i] = j;
+ j++;
+ if (j >= 'z')
+ j = 'A';
+ }
+ return buf;
+}
+
+char *setup_buffer3(int bufsz)
+{
+ char *buf;
+
+ buf = malloc(bufsz);
+ if (!buf)
+ return NULL;
+
+ bzero(buf, bufsz);
+ return buf;
+}
+
+/*
+ * Returns the difference between gmt and local time in seconds.
+ * Use gmtime() and localtime() to keep things simple.
+ * from tcpdump/gmt2local.c
+ */
+static int32_t
+gmt2local(time_t t)
+{
+ int dt, dir;
+ struct tm *gmt, *loc;
+ struct tm sgmt;
+
+ if (t == 0)
+ t = time(NULL);
+ gmt = &sgmt;
+ *gmt = *gmtime(&t);
+ loc = localtime(&t);
+ dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
+ (loc->tm_min - gmt->tm_min) * 60;
+
+ /*
+ * If the year or julian day is different, we span 00:00 GMT
+ * and must add or subtract a day. Check the year first to
+ * avoid problems when the julian day wraps.
+ */
+ dir = loc->tm_year - gmt->tm_year;
+ if (dir == 0)
+ dir = loc->tm_yday - gmt->tm_yday;
+ dt += dir * 24 * 60 * 60;
+
+ return (dt);
+}
+
+/*
+ * Print the timestamp
+ * from tcpdump/util.c
+ */
+static void
+ts_print(void)
+{
+ int s;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ /* Default */
+ s = (tv.tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tv.tv_usec);
+}
+
+static const char *
+basename(const char * str)
+{
+ const char *last_slash = strrchr(str, '/');
+
+ if (last_slash == NULL)
+ return (str);
+ else
+ return (last_slash + 1);
+}
+
+struct option_desc {
+ const char *option;
+ const char *description;
+ int required;
+};
+
+struct option_desc option_desc_list[] = {
+ { "--host addr", "address of server to connect to", 1 },
+ { "--port n", "port of server to connect to", 1 },
+ { "--reqlen n", "length of request (256 by default)", 0 },
+ { "--rsplen n", "length of response (256 by default)", 0 },
+ { "--ntimes n", "number of time to send request (1 by default)", 0 },
+ { "--alt_addr addr", "alternate server to connect to", 0 },
+ { "--verbose", "increase verbosity", 0 },
+ { "--help", "display this help", 0 },
+
+ { NULL, NULL, 0 } /* Mark end of list */
+};
+
+static void
+usage(const char *cmd)
+{
+ struct option_desc *option_desc;
+ char *usage_str = malloc(LINE_MAX);
+ size_t usage_len;
+
+ if (usage_str == NULL)
+ err(1, "%s: malloc(%d)", __func__, LINE_MAX);
+
+ usage_len = snprintf(usage_str, LINE_MAX, "# usage: %s ", basename(cmd));
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ int len;
+
+ if (option_desc->required)
+ len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "%s ", option_desc->option);
+ else
+ len = snprintf(usage_str + usage_len, LINE_MAX - usage_len, "[%s] ", option_desc->option);
+ if (len < 0)
+ err(1, "%s: snprintf(", __func__);
+
+ usage_len += len;
+ if (usage_len > LINE_MAX)
+ break;
+ }
+ printf("%s\n", usage_str);
+ printf("options:\n");
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ printf(" %-24s # %s\n", option_desc->option, option_desc->description);
+ }
+ printf("\n");
+ printf("# legacy usage: ");
+}
+
+static struct option longopts[] = {
+ { "host", required_argument, NULL, 'c' },
+ { "port", required_argument, NULL, 'p' },
+ { "reqlen", required_argument, NULL, 'r' },
+ { "rsplen", required_argument, NULL, 'R' },
+ { "ntimes", required_argument, NULL, 'n' },
+ { "alt_addr", required_argument, NULL, 'a' },
+ { "help", no_argument, NULL, 'h' },
+ { "verbose", no_argument, NULL, 'v' },
+ { "quiet", no_argument, NULL, 'q' },
+ { NULL, 0, NULL, 0 }
+};
+
+static int
+sprint_sockaddr(char *str, socklen_t strlen, struct sockaddr *sa)
+{
+ int retval = 0;
+
+ if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in*)sa;
+ char str4[INET_ADDRSTRLEN];
+
+ inet_ntop(AF_INET, &sin->sin_addr, str4, sizeof(str4));
+
+ retval = snprintf(str, strlen, "%s:%u", str4, ntohs(sin->sin_port));
+ } else if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)sa;
+ char str6[INET6_ADDRSTRLEN];
+ char ifname[IF_NAMESIZE];
+ char scopestr[2 + IF_NAMESIZE];
+
+ inet_ntop(AF_INET6, &sin6->sin6_addr, str6, sizeof(str6));
+
+ if (sin6->sin6_scope_id == 0)
+ *scopestr = '\0';
+ else {
+ if_indextoname(sin6->sin6_scope_id, ifname);
+ snprintf(scopestr, sizeof(scopestr), "%%%s", ifname);
+ }
+
+ retval = snprintf(str, strlen, "%s%s:%u",
+ str6,
+ scopestr,
+ ntohs(sin6->sin6_port));
+ }
+ return (retval);
+}
+
+int main(int argc, char * const *argv)
+{
+ int sockfd, portno;
+ ssize_t n;
+ int reqlen = 256;
+ int rsplen = 256;
+ int ntimes = 1;
+ char *buffer = NULL;
+ char *buffer1;
+ char *buffer2;
+ char *buffer3;
+ struct addrinfo *ares = NULL, ahints;
+ struct addrinfo *altres = NULL;
+ int retval = 0;
+ int which_buf = 0;
+ sae_connid_t cid1, cid2;
+ int iter;
+ int bytes_to_rdwr;
+ int ch;
+ const char *host_arg = NULL;
+ const char *port_arg = NULL;
+ const char *reqlen_arg = "256";
+ const char *rsplen_arg = "256";
+ const char *ntimes_arg = "1";
+ const char *alt_addr_arg = NULL;
+ const char *alt_port_arg = "0";
+ int gotopt = 0;
+
+ thiszone = gmt2local(0);
+
+ while ((ch = getopt_long(argc, argv, "a:c:hn:p:qr:R:v", longopts, NULL)) != -1) {
+ gotopt = 1;
+ switch (ch) {
+ case 'a':
+ alt_addr_arg = optarg;
+ break;
+ case 'c':
+ host_arg = optarg;
+ break;
+ case 'n':
+ ntimes_arg = optarg;
+ break;
+ case 'p':
+ port_arg = optarg;
+ break;
+ case 'q':
+ verbose--;
+ break;
+ case 'r':
+ reqlen_arg = optarg;
+ break;
+ case 'R':
+ rsplen_arg = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ usage(argv[0]);
+ exit(EX_USAGE);
+ }
+ }
+
+ if (gotopt == 0) {
+ if (argc == 12) {
+ host_arg = argv[1];
+ port_arg = argv[2];
+ reqlen_arg = argv[3];
+ rsplen_arg = argv[4];
+ ntimes_arg = argv[5];
+ alt_addr_arg = argv[6];
+ } else {
+ usage(argv[0]);
+ exit(EX_USAGE);
+ }
+ }
+
+ if (host_arg == NULL)
+ errx(EX_USAGE, "missing required host option\n");
+
+ if (port_arg == NULL)
+ errx(EX_USAGE, "missing required port option\n");
+ portno = atoi(port_arg);
+ if (portno < 0 || portno > 65535)
+ errx(EX_USAGE, "invalid port %s\n", port_arg);
+
+ if (reqlen_arg != NULL) {
+ reqlen = atoi(reqlen_arg);
+ if (reqlen < 0 || reqlen > 1024 * 1024)
+ errx(EX_USAGE, "invalid request length %s\n", reqlen_arg);
+ }
+
+ if (rsplen_arg != NULL) {
+ rsplen = atoi(rsplen_arg);
+ if (rsplen < 0 || rsplen > 1024 * 1024)
+ errx(EX_USAGE, "invalid response length %s\n", rsplen_arg);
+ }
+
+ if (ntimes_arg != NULL) {
+ ntimes = atoi(ntimes_arg);
+ if (ntimes < 1)
+ errx(EX_USAGE, "invalid ntimes option %s\n", ntimes_arg);
+ }
+
+ buffer1 = setup_buffer1(reqlen);
+ if (!buffer1) {
+ printf("client: failed to alloc buffer space \n");
+ return -1;
+ }
+
+ buffer2 = setup_buffer2(reqlen);
+ if (!buffer2) {
+ printf("client: failed to alloc buffer space \n");
+ return -1;
+ }
+
+ buffer3 = setup_buffer3(rsplen);
+ if (!buffer3) {
+ printf("client: failed to alloc buffer space \n");
+ return -1;
+ }
+
+ if (verbose > 0)
+ printf("host: %s port: %s reqlen: %d rsplen: %d ntimes: %d alt_addr: %s\n",
+ host_arg, port_arg, reqlen, rsplen, ntimes, alt_addr_arg);
+
+ sockfd = socket(AF_MULTIPATH, SOCK_STREAM, 0);
+ if (sockfd < 0)
+ err(EX_OSERR, "ERROR opening socket");
+
+ memset(&ahints, 0, sizeof(struct addrinfo));
+ ahints.ai_family = AF_INET;
+ ahints.ai_socktype = SOCK_STREAM;
+ ahints.ai_protocol = IPPROTO_TCP;
+
+ retval = getaddrinfo(host_arg, port_arg, &ahints, &ares);
+ if (retval != 0)
+ printf("getaddrinfo(%s, %s) failed %d\n", host_arg, port_arg, retval);
+
+ bytes_to_rdwr = reqlen;
+
+ cid1 = cid2 = SAE_CONNID_ANY;
+ int ifscope = 0;
+ int error = 0;
+
+ if (verbose > 0) {
+ char str[2 * INET6_ADDRSTRLEN];
+
+ ts_print();
+
+ sprint_sockaddr(str, sizeof(str), ares->ai_addr);
+ printf("connectx(%s, %d, %d)\n", str, ifscope, cid1);
+ }
+ sa_endpoints_t sa;
+ bzero(&sa, sizeof(sa));
+ sa.sae_dstaddr = ares->ai_addr;
+ sa.sae_dstaddrlen = ares->ai_addrlen;
+ sa.sae_srcif = ifscope;
+
+ error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid1);
+ if (error != 0)
+ err(EX_OSERR, "ERROR connecting");
+
+ iter = 0;
+
+ while (ntimes) {
+ if (iter == 0) {
+ /* Add alternate path if available */
+
+ if (alt_addr_arg && alt_addr_arg[0] != 0) {
+ retval = getaddrinfo(alt_addr_arg, alt_port_arg, &ahints, &altres);
+
+ if (retval != 0)
+ printf("client: alternate address resolution failed. \n");
+ else {
+ printf("client: connecting to alternate address (ifscope %d)\n", ifscope);
+
+ if (verbose > 0) {
+ char str[2 * INET6_ADDRSTRLEN];
+
+ ts_print();
+
+ sprint_sockaddr(str, sizeof(str), altres->ai_addr);
+ printf("connectx(%s, %d, %d)\n", str, ifscope, cid1);
+ }
+ sa_endpoints_t sa;
+ bzero(&sa, sizeof(sa));
+ sa.sae_srcif = ifscope;
+ sa.sae_srcaddr = altres->ai_addr;
+ sa.sae_srcaddrlen = altres->ai_addrlen;
+ sa.sae_dstaddr = ares->ai_addr;
+ sa.sae_dstaddrlen = ares->ai_addrlen;
+
+ error = connectx(sockfd, &sa, SAE_ASSOCID_ANY, 0, NULL, 0, NULL, &cid2);
+ if (error < 0) {
+ err(EX_OSERR, "ERROR setting up alternate path");
+ }
+ }
+ }
+ }
+
+ if (which_buf == 0) {
+ buffer = buffer1;
+ which_buf = 1;
+ } else {
+ buffer = buffer2;
+ which_buf = 0;
+ }
+
+ while (bytes_to_rdwr) {
+ if (verbose) {
+ ts_print();
+ printf("writing %d bytes\n", bytes_to_rdwr);
+ }
+ n = write(sockfd, buffer, bytes_to_rdwr);
+ if (n <= 0) {
+ err(EX_OSERR, "ERROR writing to socket");
+ }
+ if (n <= bytes_to_rdwr)
+ bytes_to_rdwr -= n;
+ else {
+ errx(EX_DATAERR, "ERROR extra data write %zd %d\n", n, bytes_to_rdwr);
+ }
+ }
+ bytes_to_rdwr = rsplen;
+ while (bytes_to_rdwr) {
+ if (verbose) {
+ ts_print();
+ printf("reading %d bytes\n", rsplen);
+ }
+ n = read(sockfd, buffer3, rsplen);
+
+ if (n <= 0) {
+ err(EX_OSERR, "ERROR reading from socket");
+ }
+ if (n <= bytes_to_rdwr)
+ bytes_to_rdwr -= n;
+ else {
+ errx(EX_DATAERR, "ERROR extra bytes read n:%zd expected:%d\n", n, bytes_to_rdwr);
+ }
+ }
+ bytes_to_rdwr = reqlen;
+ ntimes--;
+ iter++;
+ }
+
+ printf("client: Req size %d Rsp size %d Read/Write %d times \n", reqlen, rsplen, iter);
+
+ showmpinfo(sockfd);
+
+ if (verbose) {
+ ts_print();
+ printf("close(%d)\n", sockfd);
+ }
+ close(sockfd);
+
+ freeaddrinfo(ares);
+ if (altres)
+ freeaddrinfo(altres);
+ return 0;
+}
+
+#define CIF_BITS \
+"\020\1CONNECTING\2CONNECTED\3DISCONNECTING\4DISCONNECTED\5BOUND_IF"\
+"\6BOUND_IP\7BOUND_PORT\10PREFERRED\11MP_CAPABLE\12MP_READY" \
+"\13MP_DEGRADED"
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ */
+static void
+printb(const char *s, unsigned v, const char *bits)
+{
+ int i, any = 0;
+ char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++) != '\0') {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else {
+ for (; *bits > 32; bits++)
+ ;
+ }
+ }
+ putchar('>');
+ }
+}
+
+static int
+showconninfo(int s, sae_connid_t cid)
+{
+ char buf[INET6_ADDRSTRLEN];
+ conninfo_t *cfo = NULL;
+ int err;
+
+ err = copyconninfo(s, cid, &cfo);
+ if (err != 0) {
+ printf("getconninfo failed for cid %d\n", cid);
+ goto out;
+ }
+
+ printf("%6d:\t", cid);
+ printb("flags", cfo->ci_flags, CIF_BITS);
+ printf("\n");
+
+ if (cfo->ci_src != NULL) {
+ printf("\tsrc %s port %d\n", inet_ntop(cfo->ci_src->sa_family,
+ (cfo->ci_src->sa_family == AF_INET) ?
+ (void *)&((struct sockaddr_in *)cfo->ci_src)->
+ sin_addr.s_addr :
+ (void *)&((struct sockaddr_in6 *)cfo->ci_src)->sin6_addr,
+ buf, sizeof (buf)),
+ (cfo->ci_src->sa_family == AF_INET) ?
+ ntohs(((struct sockaddr_in *)cfo->ci_src)->sin_port) :
+ ntohs(((struct sockaddr_in6 *)cfo->ci_src)->sin6_port));
+ }
+ if (cfo->ci_dst != NULL) {
+ printf("\tdst %s port %d\n", inet_ntop(cfo->ci_dst->sa_family,
+ (cfo->ci_dst->sa_family == AF_INET) ?
+ (void *)&((struct sockaddr_in *)cfo->ci_dst)->
+ sin_addr.s_addr :
+ (void *)&((struct sockaddr_in6 *)cfo->ci_dst)->sin6_addr,
+ buf, sizeof (buf)),
+ (cfo->ci_dst->sa_family == AF_INET) ?
+ ntohs(((struct sockaddr_in *)cfo->ci_dst)->sin_port) :
+ ntohs(((struct sockaddr_in6 *)cfo->ci_dst)->sin6_port));
+ }
+ if (cfo->ci_aux_data != NULL) {
+ switch (cfo->ci_aux_type) {
+ case CIAUX_TCP:
+ printf("\tTCP aux info available\n");
+ break;
+ default:
+ printf("\tUnknown aux type %d\n", cfo->ci_aux_type);
+ break;
+ }
+ }
+out:
+ if (cfo != NULL)
+ freeconninfo(cfo);
+
+ return (err);
+}
+
+static void
+showmpinfo(int s)
+{
+ uint32_t aid_cnt = 0, cid_cnt = 0;
+ sae_associd_t *aid = NULL;
+ sae_connid_t *cid = NULL;
+ int i, error = 0;
+
+ error = copyassocids(s, &aid, &aid_cnt);
+ if (error != 0) {
+ printf("copyassocids failed\n");
+ goto done;
+ } else {
+ printf("found %d associations", aid_cnt);
+ if (aid_cnt > 0) {
+ printf(" with IDs:");
+ for (i = 0; i < aid_cnt; i++)
+ printf(" %d\n", aid[i]);
+ }
+ printf("\n");
+ }
+
+ /* just do an association for now */
+ error = copyconnids(s, SAE_ASSOCID_ANY, &cid, &cid_cnt);
+ if (error != 0) {
+ warn("getconnids failed\n");
+ goto done;
+ } else {
+ printf("found %d connections", cid_cnt);
+ if (cid_cnt > 0) {
+ printf(":\n");
+ for (i = 0; i < cid_cnt; i++) {
+ if (showconninfo(s, cid[i]) != 0)
+ break;
+ }
+ }
+ printf("\n");
+ }
+
+done:
+ if (aid != NULL)
+ freeassocids(aid);
+ if (cid != NULL)
+ freeconnids(cid);
+}
diff --git a/network_cmds/mtest.tproj/COPYING b/network_cmds/mtest.tproj/COPYING
new file mode 100644
index 0000000..77bafa4
--- /dev/null
+++ b/network_cmds/mtest.tproj/COPYING
@@ -0,0 +1,27 @@
+Copyright (c) 2007-2009 Bruce Simpson.
+Copyright (c) 2000 Wilbert De Graaf.
+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
+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. \ No newline at end of file
diff --git a/network_cmds/mtest.tproj/mtest.8 b/network_cmds/mtest.tproj/mtest.8
new file mode 100644
index 0000000..b618cc0
--- /dev/null
+++ b/network_cmds/mtest.tproj/mtest.8
@@ -0,0 +1,175 @@
+.\"
+.\" Copyright (c) 2007-2009 Bruce Simpson.
+.\" 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. 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.
+.\"
+.\" $FreeBSD: src/usr.sbin/mtest/mtest.8,v 1.11 2009/04/29 09:50:04 bms Exp $
+.\"
+.Dd April 29, 2009
+.Os
+.Dt MTEST 8
+.Sh NAME
+.Nm mtest
+.Nd test multicast socket operations
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility
+is a small program for testing multicast socket operations.
+.Pp
+It accepts the following commands, interactively, or as part of a scripted
+input file (useful for automated testing):
+.Bl -tag -width "a ifname e.e.e.e e.e.e.e" -compact -offset indent
+.Pp
+.\"
+.It Ic a Ar ifname Ar mac-addr
+Join the link-layer group address
+.Ar mac-addr
+on interface
+.Ar ifname .
+The group address should be in IEEE 802 MAC format,
+delimited by colon (':') characters.
+.It Ic d Ar ifname Ar mac-addr
+Leave the link-layer group address
+.Ar mac-addr
+on interface
+.Ar ifname .
+.It Ic m Ar ifname Ar 1/0
+Set or reset ALLMULTI mode on interface
+.Ar ifname .
+This option is deprecated and is now a no-op.
+.\".It Ic p Ar ifname Ar 1/0
+.\"Set or reset promiscuous mode on interface
+.\".Ar ifname .
+.Pp
+.It Ic j Ar mcast-addr Ar ifname Op Ar source-addr
+Join the multicast address
+.Ar mcast-addr
+on the interface with name
+.Ar ifname .
+.Pp
+If an optional source
+.Ar source-addr
+is specified, a source-specific join will be performed;
+if
+.Nm
+is already joined to the multicast address, the source
+will be added to its filter list.
+.Pp
+.It Ic l Ar mcast-addr Ar ifname Op Ar source-addr
+Leave the multicast address
+.Ar mcast-addr
+on the interface with address
+.Ar ifname .
+If a source
+.Ar source-addr
+is specified, only that source will be left.
+.\"
+.It Ic i Ar mcast-addr Ar ifname Ar n Ar source-addr ...
+Set the socket with membership of
+.Ar mcast-addr
+on interface
+.Ar ifname
+to include filter mode, and add
+.Ar n
+sources beginning with
+.Ar source-addr
+to the inclusion filter list.
+.\"
+.It Ic e Ar mcast-addr Ar ifname Ar n Ar source-addr ...
+Set the socket with membership of
+.Ar mcast-addr
+on interface
+.Ar ifname
+to exclude filter mode, and add
+.Ar n
+sources beginning with
+.Ar source-addr
+to the exclusion filter list.
+.\"
+.It Ic t Ar mcast-addr Ar ifname Ar source-addr
+Set the socket with membership of
+.Ar mcast-addr
+on interface
+.Ar ifname
+to block traffic from source
+.Ar source-addr .
+.\"
+.It Ic b Ar mcast-addr Ar ifname Ar source-addr
+Set the socket with membership of
+.Ar mcast-addr
+on interface
+.Ar ifname
+to allow traffic from source
+.Ar source-addr .
+.\"
+.Pp
+.It Ic g Ar mcast-addr Ar ifname Ar n
+Print
+.Ar n
+source filter entries for
+.An mcast-addr
+on interface
+.An ifname .
+.\"
+.Pp
+.It Ic f Ar filename
+Read commands from the file
+.Ar filename .
+.It Ic s Ar n
+Sleep for
+.Ar n
+seconds.
+.It Ic ?\&
+List legal commands.
+.It Ic q
+Quit the program.
+.El
+.Sh IMPLEMENTATION NOTES
+For each command implemented by
+.Nm ,
+the address family of each argument must be identical; it is not possible
+to mix IPv4 multicast memberships with IPv6, for example.
+.Pp
+To support IPv6, all commands have now changed to accept an interface
+name rather than an interface address.
+For IPv4, the program will perform
+a lookup of the primary IP address based on the interface name.
+This may fail if no primary IP address is assigned.
+.Pp
+.Sh SEE ALSO
+.Rs
+.%A D. Thaler
+.%A B. Fenner
+.%A B. Quinn
+.%T "Socket Interface Extensions for Multicast Filters"
+.%O RFC 3678
+.Re
+.Sh AUTHORS
+.An -split
+.An "Bruce Simpson"
+.An "Steve Deering"
+.An "Wilbert De Graaf"
diff --git a/network_cmds/mtest.tproj/mtest.c b/network_cmds/mtest.tproj/mtest.c
new file mode 100644
index 0000000..9c1614e
--- /dev/null
+++ b/network_cmds/mtest.tproj/mtest.c
@@ -0,0 +1,825 @@
+/*-
+ * Copyright (c) 2007-2009 Bruce Simpson.
+ * Copyright (c) 2000 Wilbert De Graaf.
+ * 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
+ * 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.
+ */
+
+/*
+ * Diagnostic and test utility for multicast sockets.
+ * TODO: Support embedded KAME Scope ID in IPv6 group addresses.
+ * TODO: Use IPv4 link-local address when source address selection
+ * is implemented; use MCAST_JOIN_SOURCE for IPv4.
+ */
+
+#define INET6
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#ifdef INET6
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+
+#ifdef IP_ADD_SOURCE_MEMBERSHIP
+#define HAS_SSM 1
+#endif
+
+union sockunion {
+ struct sockaddr_storage ss;
+ struct sockaddr sa;
+ struct sockaddr_dl sdl;
+ struct sockaddr_in sin;
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
+};
+typedef union sockunion sockunion_t;
+
+union mrequnion {
+ struct ip_mreq mr;
+#ifdef HAS_SSM
+ struct ip_mreq_source mrs;
+#endif
+#ifdef INET6
+ struct ipv6_mreq mr6;
+#ifdef HAS_SSM
+ struct group_source_req gr;
+#endif
+#endif
+};
+typedef union mrequnion mrequnion_t;
+
+#define MAX_ADDRS 20
+#define STR_SIZE 64
+#define LINE_LENGTH 80
+
+static int __ifindex_to_primary_ip(const uint32_t, struct in_addr *);
+static uint32_t parse_cmd_args(sockunion_t *, sockunion_t *,
+ const char *, const char *, const char *);
+static void process_file(char *, int, int);
+static void process_cmd(char*, int, int, FILE *);
+static int su_cmp(const void *, const void *);
+static void usage(void);
+
+/*
+ * Ordering predicate for qsort().
+ */
+static int
+su_cmp(const void *a, const void *b)
+{
+ const sockunion_t *sua = (const sockunion_t *)a;
+ const sockunion_t *sub = (const sockunion_t *)b;
+
+ assert(sua->sa.sa_family == sub->sa.sa_family);
+
+ switch (sua->sa.sa_family) {
+ case AF_INET:
+ return ((int)(sua->sin.sin_addr.s_addr -
+ sub->sin.sin_addr.s_addr));
+ break;
+#ifdef INET6
+ case AF_INET6:
+ return (memcmp(&sua->sin6.sin6_addr, &sub->sin6.sin6_addr,
+ sizeof(struct in6_addr)));
+ break;
+#endif
+ default:
+ break;
+ }
+
+ assert(sua->sa.sa_len == sub->sa.sa_len);
+ return (memcmp(sua, sub, sua->sa.sa_len));
+}
+
+/*
+ * Internal: Map an interface index to primary IPv4 address.
+ * This is somewhat inefficient. This is a useful enough operation
+ * that it probably belongs in the C library.
+ * Return zero if found, -1 on error, 1 on not found.
+ */
+static int
+__ifindex_to_primary_ip(const uint32_t ifindex, struct in_addr *pina)
+{
+ char ifname[IFNAMSIZ];
+ struct ifaddrs *ifa;
+ struct ifaddrs *ifaddrs;
+ sockunion_t *psu;
+ int retval;
+
+ assert(ifindex != 0);
+
+ retval = -1;
+ if (if_indextoname(ifindex, ifname) == NULL)
+ return (retval);
+ if (getifaddrs(&ifaddrs) < 0)
+ return (retval);
+
+ /*
+ * Find the ifaddr entry corresponding to the interface name,
+ * and return the first matching IPv4 address.
+ */
+ retval = 1;
+ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
+ if (strcmp(ifa->ifa_name, ifname) != 0)
+ continue;
+ psu = (sockunion_t *)ifa->ifa_addr;
+ if (psu && psu->sa.sa_family == AF_INET) {
+ retval = 0;
+ memcpy(pina, &psu->sin.sin_addr,
+ sizeof(struct in_addr));
+ break;
+ }
+ }
+
+ if (retval != 0)
+ errno = EADDRNOTAVAIL; /* XXX */
+
+ freeifaddrs(ifaddrs);
+ return (retval);
+}
+
+int
+main(int argc, char **argv)
+{
+ char line[LINE_LENGTH];
+ char *p;
+ int i, s, s6;
+
+ s = -1;
+ s6 = -1;
+ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (s == -1)
+ err(1, "can't open IPv4 socket");
+#ifdef INET6
+ s6 = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+ if (s6 == -1)
+ err(1, "can't open IPv6 socket");
+#endif
+
+ if (argc < 2) {
+ if (isatty(STDIN_FILENO)) {
+ printf("multicast membership test program; "
+ "enter ? for list of commands\n");
+ }
+ do {
+ if (fgets(line, sizeof(line), stdin) != NULL) {
+ if (line[0] != 'f')
+ process_cmd(line, s, s6, stdin);
+ else {
+ /* Get the filename */
+ for (i = 1; isblank(line[i]); i++);
+ if ((p = (char*)strchr(line, '\n'))
+ != NULL)
+ *p = '\0';
+ process_file(&line[i], s, s6);
+ }
+ }
+ } while (!feof(stdin));
+ } else {
+ for (i = 1; i < argc; i++) {
+ process_file(argv[i], s, s6);
+ }
+ }
+
+ if (s != -1)
+ close(s);
+ if (s6 != -1)
+ close(s6);
+
+ exit (0);
+}
+
+static void
+process_file(char *fname, int s, int s6)
+{
+ char line[80];
+ FILE *fp;
+ char *lineptr;
+
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ warn("fopen");
+ return;
+ }
+
+ /* Skip comments and empty lines. */
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ lineptr = line;
+ while (isblank(*lineptr))
+ lineptr++;
+ if (*lineptr != '#' && *lineptr != '\n')
+ process_cmd(lineptr, s, s6, fp);
+ }
+
+ fclose(fp);
+}
+
+/*
+ * Parse join/leave/allow/block arguments, given:
+ * str1: group (as AF_INET or AF_INET6 printable)
+ * str2: ifname
+ * str3: optional source address (may be NULL).
+ * This argument must have the same parsed address family as str1.
+ * Return the ifindex of ifname, or 0 if any parse element failed.
+ */
+static uint32_t
+parse_cmd_args(sockunion_t *psu, sockunion_t *psu2,
+ const char *str1, const char *str2, const char *str3)
+{
+ struct addrinfo hints;
+ struct addrinfo *res;
+ uint32_t ifindex;
+ int af, error;
+
+ assert(psu != NULL);
+ assert(str1 != NULL);
+ assert(str2 != NULL);
+
+ af = AF_UNSPEC;
+
+ ifindex = if_nametoindex(str2);
+ if (ifindex == 0)
+ return (0);
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ memset(psu, 0, sizeof(sockunion_t));
+ psu->sa.sa_family = AF_UNSPEC;
+
+ error = getaddrinfo(str1, "0", &hints, &res);
+ if (error) {
+ warnx("getaddrinfo: %s", gai_strerror(error));
+ return (0);
+ }
+ assert(res != NULL);
+ af = res->ai_family;
+ memcpy(psu, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+
+ /* sscanf() may pass the empty string. */
+ if (psu2 != NULL && str3 != NULL && *str3 != '\0') {
+ memset(psu2, 0, sizeof(sockunion_t));
+ psu2->sa.sa_family = AF_UNSPEC;
+
+ /* look for following address family; str3 is *optional*. */
+ hints.ai_family = af;
+ error = getaddrinfo(str3, "0", &hints, &res);
+ if (error) {
+ warnx("getaddrinfo: %s", gai_strerror(error));
+ ifindex = 0;
+ } else {
+ if (af != res->ai_family) {
+ errno = EINVAL; /* XXX */
+ ifindex = 0;
+ }
+ memcpy(psu2, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ }
+ }
+
+ return (ifindex);
+}
+
+static __inline int
+af2sock(const int af, int s, int s6)
+{
+
+ if (af == AF_INET)
+ return (s);
+#ifdef INET6
+ if (af == AF_INET6)
+ return (s6);
+#endif
+ return (-1);
+}
+
+static void
+process_cmd(char *cmd, int s, int s6 __unused, FILE *fp __unused)
+{
+ char str1[STR_SIZE];
+ char str2[STR_SIZE];
+ char str3[STR_SIZE];
+ mrequnion_t mr;
+ sockunion_t su, su2;
+ struct ifreq ifr;
+ char *line;
+ char *toptname;
+ void *optval;
+ uint32_t fmode, ifindex;
+ socklen_t optlen;
+ int af, error, i, level, n = 0, optname;
+#ifndef __APPLE__
+ int f, flags;
+#endif /* __APPLE__ */
+
+ af = AF_UNSPEC;
+ su.sa.sa_family = AF_UNSPEC;
+ su2.sa.sa_family = AF_UNSPEC;
+
+ line = cmd;
+ while (isblank(*++line))
+ ; /* Skip whitespace. */
+
+ switch (*cmd) {
+ case '?':
+ usage();
+ break;
+
+ case 'q':
+ close(s);
+ exit(0);
+
+ case 's':
+ if ((sscanf(line, "%d", &n) != 1) || (n < 1)) {
+ printf("-1\n");
+ break;
+ }
+ sleep(n);
+ printf("ok\n");
+ break;
+
+ case 'j':
+ case 'l':
+ str3[0] = '\0';
+ toptname = "";
+ sscanf(line, "%s %s %s", str1, str2, str3);
+ ifindex = parse_cmd_args(&su, &su2, str1, str2, str3);
+ if (ifindex == 0) {
+ printf("-1\n");
+ break;
+ }
+ af = su.sa.sa_family;
+ if (af == AF_INET) {
+ struct in_addr ina;
+
+ error = __ifindex_to_primary_ip(ifindex, &ina);
+ if (error != 0) {
+ warn("primary_ip_lookup %s", str2);
+ printf("-1\n");
+ break;
+ }
+ level = IPPROTO_IP;
+
+#ifdef HAS_SSM
+ if (su2.sa.sa_family != AF_UNSPEC) {
+ mr.mrs.imr_multiaddr = su.sin.sin_addr;
+ mr.mrs.imr_sourceaddr = su2.sin.sin_addr;
+ mr.mrs.imr_interface = ina;
+ optname = (*cmd == 'j') ?
+ IP_ADD_SOURCE_MEMBERSHIP :
+ IP_DROP_SOURCE_MEMBERSHIP;
+ toptname = (*cmd == 'j') ?
+ "IP_ADD_SOURCE_MEMBERSHIP" :
+ "IP_DROP_SOURCE_MEMBERSHIP";
+ optval = (void *)&mr.mrs;
+ optlen = sizeof(mr.mrs);
+ } else {
+#endif
+ mr.mr.imr_multiaddr = su.sin.sin_addr;
+ mr.mr.imr_interface = ina;
+ optname = (*cmd == 'j') ?
+ IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
+ toptname = (*cmd == 'j') ?
+ "IP_ADD_MEMBERSHIP" : "IP_DROP_MEMBERSHIP";
+ optval = (void *)&mr.mr;
+ optlen = sizeof(mr.mr);
+#ifdef HAS_SSM
+ }
+#endif
+ if (setsockopt(s, level, optname, optval,
+ optlen) == 0) {
+ printf("ok\n");
+ break;
+ } else {
+ warn("setsockopt %s", toptname);
+ }
+ }
+#ifdef INET6
+ else
+#endif /* INET6 */
+#ifdef INET6
+ if (af == AF_INET6) {
+ level = IPPROTO_IPV6;
+#ifdef HAS_SSM
+ if (su2.sa.sa_family != AF_UNSPEC) {
+ mr.gr.gsr_interface = ifindex;
+ mr.gr.gsr_group = su.ss;
+ mr.gr.gsr_source = su2.ss;
+ optname = (*cmd == 'j') ?
+ MCAST_JOIN_SOURCE_GROUP:
+ MCAST_LEAVE_SOURCE_GROUP;
+ toptname = (*cmd == 'j') ?
+ "MCAST_JOIN_SOURCE_GROUP":
+ "MCAST_LEAVE_SOURCE_GROUP";
+ optval = (void *)&mr.gr;
+ optlen = sizeof(mr.gr);
+ } else {
+#endif
+ mr.mr6.ipv6mr_multiaddr = su.sin6.sin6_addr;
+ mr.mr6.ipv6mr_interface = ifindex;
+ optname = (*cmd == 'j') ?
+ IPV6_JOIN_GROUP :
+ IPV6_LEAVE_GROUP;
+ toptname = (*cmd == 'j') ?
+ "IPV6_JOIN_GROUP" :
+ "IPV6_LEAVE_GROUP";
+ optval = (void *)&mr.mr6;
+ optlen = sizeof(mr.mr6);
+#ifdef HAS_SSM
+ }
+#endif
+ if (setsockopt(s6, level, optname, optval,
+ optlen) == 0) {
+ printf("ok\n");
+ break;
+ } else {
+ warn("setsockopt %s", toptname);
+ }
+ }
+#endif /* INET6 */
+ /* FALLTHROUGH */
+ printf("-1\n");
+ break;
+
+#ifdef HAS_SSM
+ /*
+ * Set the socket to include or exclude filter mode, and
+ * add some sources to the filterlist, using the full-state API.
+ */
+ case 'i':
+ case 'e': {
+ sockunion_t sources[MAX_ADDRS];
+ struct addrinfo hints;
+ struct addrinfo *res;
+ char *cp;
+ int af1;
+
+ n = 0;
+ fmode = (*cmd == 'i') ? MCAST_INCLUDE : MCAST_EXCLUDE;
+ if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) {
+ printf("-1\n");
+ break;
+ }
+
+ ifindex = parse_cmd_args(&su, NULL, str1, str2, NULL);
+ if (ifindex == 0 || n < 0 || n > MAX_ADDRS) {
+ printf("-1\n");
+ break;
+ }
+ af = su.sa.sa_family;
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_DGRAM;
+
+ for (i = 0; i < n; i++) {
+ sockunion_t *psu = (sockunion_t *)&sources[i];
+ /*
+ * Trim trailing whitespace, as getaddrinfo()
+ * can't cope with it.
+ */
+ fgets(str1, sizeof(str1), fp);
+ cp = strchr(str1, '\n');
+ if (cp != NULL)
+ *cp = '\0';
+
+ res = NULL;
+ error = getaddrinfo(str1, "0", &hints, &res);
+ if (error)
+ break;
+ assert(res != NULL);
+
+ memset(psu, 0, sizeof(sockunion_t));
+ af1 = res->ai_family;
+ if (af1 == af)
+ memcpy(psu, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ if (af1 != af)
+ break;
+ }
+ if (i < n) {
+ if (error)
+ warnx("getaddrinfo: %s", gai_strerror(error));
+ printf("-1\n");
+ break;
+ }
+ if (setsourcefilter(af2sock(af, s, s6), ifindex,
+ &su.sa, su.sa.sa_len, fmode, n, &sources[0].ss) != 0)
+ warn("setsourcefilter");
+ else
+ printf("ok\n");
+ } break;
+
+ /*
+ * Allow or block traffic from a source, using the
+ * delta based api.
+ */
+ case 't':
+ case 'b': {
+ str3[0] = '\0';
+ toptname = "";
+ sscanf(line, "%s %s %s", str1, str2, str3);
+ ifindex = parse_cmd_args(&su, &su2, str1, str2, str3);
+ if (ifindex == 0 || su2.sa.sa_family == AF_UNSPEC) {
+ printf("-1\n");
+ break;
+ }
+ af = su.sa.sa_family;
+
+ /* First determine our current filter mode. */
+ n = 0;
+ if (getsourcefilter(af2sock(af, s, s6), ifindex,
+ &su.sa, su.sa.sa_len, &fmode, (uint32_t *)&n, NULL) != 0) {
+ warn("getsourcefilter");
+ break;
+ }
+ if (af == AF_INET) {
+ struct in_addr ina;
+
+ error = __ifindex_to_primary_ip(ifindex, &ina);
+ if (error != 0) {
+ warn("primary_ip_lookup %s", str2);
+ printf("-1\n");
+ break;
+ }
+ level = IPPROTO_IP;
+ optval = (void *)&mr.mrs;
+ optlen = sizeof(mr.mrs);
+ mr.mrs.imr_multiaddr = su.sin.sin_addr;
+ mr.mrs.imr_sourceaddr = su2.sin.sin_addr;
+ mr.mrs.imr_interface = ina;
+ if (fmode == MCAST_EXCLUDE) {
+ /* Any-source mode socket membership. */
+ optname = (*cmd == 't') ?
+ IP_UNBLOCK_SOURCE :
+ IP_BLOCK_SOURCE;
+ toptname = (*cmd == 't') ?
+ "IP_UNBLOCK_SOURCE" :
+ "IP_BLOCK_SOURCE";
+ } else {
+ /* Source-specific mode socket membership. */
+ optname = (*cmd == 't') ?
+ IP_ADD_SOURCE_MEMBERSHIP :
+ IP_DROP_SOURCE_MEMBERSHIP;
+ toptname = (*cmd == 't') ?
+ "IP_ADD_SOURCE_MEMBERSHIP" :
+ "IP_DROP_SOURCE_MEMBERSHIP";
+ }
+ if (setsockopt(s, level, optname, optval,
+ optlen) == 0) {
+ printf("ok\n");
+ break;
+ } else {
+ warn("setsockopt %s", toptname);
+ }
+ }
+#ifdef INET6
+ else
+#endif /* INET6 */
+#ifdef INET6
+ if (af == AF_INET6) {
+ level = IPPROTO_IPV6;
+ mr.gr.gsr_interface = ifindex;
+ mr.gr.gsr_group = su.ss;
+ mr.gr.gsr_source = su2.ss;
+ if (fmode == MCAST_EXCLUDE) {
+ /* Any-source mode socket membership. */
+ optname = (*cmd == 't') ?
+ MCAST_UNBLOCK_SOURCE :
+ MCAST_BLOCK_SOURCE;
+ toptname = (*cmd == 't') ?
+ "MCAST_UNBLOCK_SOURCE" :
+ "MCAST_BLOCK_SOURCE";
+ } else {
+ /* Source-specific mode socket membership. */
+ optname = (*cmd == 't') ?
+ MCAST_JOIN_SOURCE_GROUP :
+ MCAST_LEAVE_SOURCE_GROUP;
+ toptname = (*cmd == 't') ?
+ "MCAST_JOIN_SOURCE_GROUP":
+ "MCAST_LEAVE_SOURCE_GROUP";
+ }
+ optval = (void *)&mr.gr;
+ optlen = sizeof(mr.gr);
+ if (setsockopt(s6, level, optname, optval,
+ optlen) == 0) {
+ printf("ok\n");
+ break;
+ } else {
+ warn("setsockopt %s", toptname);
+ }
+ }
+#endif /* INET6 */
+ /* FALLTHROUGH */
+ printf("-1\n");
+ } break;
+
+ case 'g': {
+ sockunion_t sources[MAX_ADDRS];
+ char addrbuf[NI_MAXHOST];
+ int nreqsrc, nsrc;
+
+ if ((sscanf(line, "%s %s %d", str1, str2, &nreqsrc)) != 3) {
+ printf("-1\n");
+ break;
+ }
+ ifindex = parse_cmd_args(&su, NULL, str1, str2, NULL);
+ if (ifindex == 0 || (n < 0 || n > MAX_ADDRS)) {
+ printf("-1\n");
+ break;
+ }
+
+ af = su.sa.sa_family;
+ nsrc = nreqsrc;
+ if (getsourcefilter(af2sock(af, s, s6), ifindex, &su.sa,
+ su.sa.sa_len, &fmode, (uint32_t *)&nsrc,
+ &sources[0].ss) != 0) {
+ warn("getsourcefilter");
+ printf("-1\n");
+ break;
+ }
+ printf("%s\n", (fmode == MCAST_INCLUDE) ? "include" :
+ "exclude");
+ printf("%d\n", nsrc);
+
+ nsrc = MIN(nreqsrc, nsrc);
+ fprintf(stderr, "hexdump of sources:\n");
+ uint8_t *bp = (uint8_t *)&sources[0];
+ for (i = 0; i < (nsrc * sizeof(sources[0])); i++) {
+ fprintf(stderr, "%02x", bp[i]);
+ }
+ fprintf(stderr, "\nend hexdump\n");
+
+ qsort(sources, nsrc, sizeof (sockunion_t), su_cmp);
+ for (i = 0; i < nsrc; i++) {
+ sockunion_t *psu = (sockunion_t *)&sources[i];
+ addrbuf[0] = '\0';
+ error = getnameinfo(&psu->sa, psu->sa.sa_len,
+ addrbuf, sizeof(addrbuf), NULL, 0,
+ NI_NUMERICHOST);
+ if (error)
+ warnx("getnameinfo: %s", gai_strerror(error));
+ else
+ printf("%s\n", addrbuf);
+ }
+ printf("ok\n");
+ } break;
+#endif
+ /* link-layer stuff follows. */
+
+ case 'a':
+ case 'd': {
+ struct sockaddr_dl *dlp;
+ struct ether_addr *ep;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ dlp = (struct sockaddr_dl *)&ifr.ifr_addr;
+ dlp->sdl_len = sizeof(struct sockaddr_dl);
+ dlp->sdl_family = AF_LINK;
+ dlp->sdl_index = 0;
+ dlp->sdl_nlen = 0;
+ dlp->sdl_alen = ETHER_ADDR_LEN;
+ dlp->sdl_slen = 0;
+ if (sscanf(line, "%s %s", str1, str2) != 2) {
+ warnc(EINVAL, "sscanf");
+ break;
+ }
+ ep = ether_aton(str2);
+ if (ep == NULL) {
+ warnc(EINVAL, "ether_aton");
+ break;
+ }
+ strlcpy(ifr.ifr_name, str1, sizeof(ifr.ifr_name));
+ memcpy(LLADDR(dlp), ep, ETHER_ADDR_LEN);
+ if (ioctl(s, (*cmd == 'a') ? SIOCADDMULTI : SIOCDELMULTI,
+ &ifr) == -1) {
+ warn("ioctl SIOCADDMULTI/SIOCDELMULTI");
+ printf("-1\n");
+ } else
+ printf("ok\n");
+ break;
+ }
+
+ case 'm':
+ fprintf(stderr,
+ "warning: IFF_ALLMULTI cannot be set from userland "
+ "in Darwin; command ignored.\n");
+ printf("-1\n");
+ break;
+
+#ifndef __APPLE__
+ case 'p':
+ if (sscanf(line, "%s %u", ifr.ifr_name, &f) != 2) {
+ printf("-1\n");
+ break;
+ }
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) {
+ warn("ioctl SIOCGIFFLAGS");
+ break;
+ }
+ flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
+ if (f == 0) {
+ flags &= ~IFF_PPROMISC;
+ } else {
+ flags |= IFF_PPROMISC;
+ }
+ ifr.ifr_flags = flags & 0xffff;
+ ifr.ifr_flagshigh = flags >> 16;
+ if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1)
+ warn("ioctl SIOCGIFFLAGS");
+ else
+ printf( "changed to 0x%08x\n", flags );
+ break;
+#endif /* __APPLE__ */
+ case '\n':
+ break;
+ default:
+ printf("invalid command\n");
+ break;
+ }
+}
+
+static void
+usage(void)
+{
+
+#ifndef HAS_SSM
+ printf("j mcast-addr ifname - join IP multicast group\n");
+ printf("l mcast-addr ifname - leave IP multicast group\n");
+#else /* HAS_SSM */
+ printf("j mcast-addr ifname [src-addr] - join IP multicast group\n");
+ printf("l mcast-addr ifname [src-addr] - leave IP multicast group\n");
+ printf(
+ "i mcast-addr ifname n - set n include mode src filter\n");
+ printf(
+ "e mcast-addr ifname n - set n exclude mode src filter\n");
+ printf("t mcast-addr ifname src-addr - allow traffic from src\n");
+ printf("b mcast-addr ifname src-addr - block traffic from src\n");
+ printf("g mcast-addr ifname n - get and show n src filters\n");
+#endif
+ printf("a ifname mac-addr - add link multicast filter\n");
+ printf("d ifname mac-addr - delete link multicast filter\n");
+ printf("m ifname 1/0 - set/clear ether allmulti flag\n");
+#ifndef __APPLE__
+ printf("p ifname 1/0 - set/clear ether promisc flag\n");
+#endif /* __APPLE__ */
+ printf("f filename - read command(s) from file\n");
+ printf("s seconds - sleep for some time\n");
+ printf("q - quit\n");
+}
+
diff --git a/network_cmds/ndp.tproj/gnuc.h b/network_cmds/ndp.tproj/gnuc.h
new file mode 100644
index 0000000..5c6b29e
--- /dev/null
+++ b/network_cmds/ndp.tproj/gnuc.h
@@ -0,0 +1,2 @@
+/* $FreeBSD: src/usr.sbin/ndp/gnuc.h,v 1.1 2000/01/06 12:40:40 shin Exp $ */
+/* this is dummy to pacify gmt2local.c. */
diff --git a/network_cmds/ndp.tproj/ndp.8 b/network_cmds/ndp.tproj/ndp.8
new file mode 100644
index 0000000..b1217eb
--- /dev/null
+++ b/network_cmds/ndp.tproj/ndp.8
@@ -0,0 +1,236 @@
+.\" Copyright (c) 2012-2013 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" 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 project 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 PROJECT 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 PROJECT 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 May 17, 1998
+.Dt NDP 8
+.Os
+.\"
+.Sh NAME
+.Nm ndp
+.Nd control/diagnose IPv6 neighbor discovery protocol
+.\"
+.Sh SYNOPSIS
+.Nm
+.Fl a
+.Op Fl lnt
+.Nm
+.Fl A Ar wait
+.Op Fl nt
+.Nm
+.Fl c
+.Op Fl nt
+.Nm
+.Fl d
+.Op Fl nt
+.Ar hostname
+.Nm
+.Fl f
+.Op Fl nt
+.Ar filename
+.Nm
+.Fl H
+.Nm
+.Fl I
+.Op Cm delete | Ar interface
+.Nm
+.Fl i
+.Ar interface
+.Op Ar flags...
+.Nm
+.Fl p
+.Nm
+.Fl P
+.Nm
+.Fl r
+.Nm
+.Fl R
+.Nm
+.Fl s
+.Op Fl nt
+.Ar nodename
+.Ar ether_addr
+.Op Li temp
+.Op Li proxy
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+command manipulates the address mapping table
+used by Neighbor Discovery Protocol (NDP).
+.Bl -tag -width Ds
+.It Fl a
+Dump the currently existing NDP entries.
+.It Fl A Ar wait
+Repeat
+.Fl a
+(dump NDP entries)
+every
+.Ar wait
+seconds.
+.It Fl c
+Erase all the NDP entries.
+.It Fl d
+Delete specified NDP entry.
+.It Fl f
+Parse the file specified by
+.Ar filename .
+.It Fl H
+Harmonize consistency between the routing table and the default router
+list; install the top entry of the list into the kernel routing table.
+.It Fl I Op Cm delete | Ar interface
+Shows or specifies the default interface used as the default route when
+there is no default router.
+If no argument is given to the option,
+the current default interface will be shown.
+If an
+.Ar interface
+is specified, the interface will be used as the default.
+If a special keyword
+.Ic delete
+is specified, the current default interface will be deleted from the kernel.
+.It Fl i Ar interface Op Ar flags...
+View ND information for the specified interface.
+If additional arguments
+.Ar flags
+are given,
+.Nm
+sets or clears the specified flags for the interface.
+Possible flags are as follows.
+All of the flags can begin with the
+special character
+.Ql - ,
+which means the flag should be cleared.
+.\"
+.Bl -tag -width Ds -compact
+.It Xo
+.Ic nud
+.Xc
+turn on or off NUD (Neighbor Unreachability Detection) on the
+interface.
+NUD is usually turned on by default.
+.It Xo
+.Ic disabled
+.Xc
+IPv6 can be disabled separately from other network protocols. This flag can be
+turned on automatically when Duplicate Address Detection (DAD) indicates that
+another device on the network is using the same link-local address.
+.It Xo
+.Ic proxy_prefixes
+.Xc
+the interface is enabled to proxy neighbor discovery for global scope prefixes
+matching those on link at other interfaces.
+.It Xo
+.Ic insecure
+do not use cryptographically generated addresses (CGA) on this interface.
+.Xc
+.It Xo
+.Ic replicated
+Address autoconfiguration proceeds under the assumption that interface
+configuration is replicated by a sleep proxy at another node on the link.
+Disables optimistic DAD and sends unsolicited NA with O=1 when DAD completes.
+Ignores DAD failures from other hardware addresses.
+.Xc
+.El
+.It Fl l
+Show link-layer reachability information.
+.It Fl n
+Do not try to resolve numeric address to hostname.
+.It Fl p
+Show prefix list.
+.It Fl P
+Flush all the entries in the prefix list.
+.It Fl r
+Show default router list.
+.It Fl R
+Flush all the entries in the default router list.
+.It Fl s
+Register an NDP entry for a node.
+The entry will be permanent unless the word
+.Li temp
+is given in the command.
+If the word
+.Li proxy
+is given, this system will act as an proxy NDP server,
+responding to requests for
+.Ar hostname
+even though the host address is not its own.
+.It Fl t
+Print timestamp on each entries,
+to make it possible to merge output with
+.Xr tcpdump 1 .
+Most useful when used with
+.Fl A .
+.It Fl x
+Show extended link-layer reachability information in addition to that shown by
+the
+.Fl l
+flag.
+.It Fl w
+Show the cryptographically generated address (CGA) parameters for the node.
+.El
+.\"
+.Sh RETURN VALUES
+The
+.Nm
+command will exit with 0 on success, and non-zero on errors.
+.\"
+.Sh SEE ALSO
+.Xr arp 8
+.\"
+.Sh HISTORY
+The
+.Nm
+command first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.\"
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/network_cmds/ndp.tproj/ndp.c b/network_cmds/ndp.tproj/ndp.c
new file mode 100644
index 0000000..b485fa1
--- /dev/null
+++ b/network_cmds/ndp.tproj/ndp.c
@@ -0,0 +1,1696 @@
+/*
+ * Copyright (c) 2009-2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+/*
+ * Copyright (c) 1984, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Sun Microsystems, Inc.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Based on:
+ * "@(#) Copyright (c) 1984, 1993\n\
+ * The Regents of the University of California. All rights reserved.\n";
+ *
+ * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
+ */
+
+/*
+ * ndp - display, set, delete and flush neighbor cache
+ */
+
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <netinet/icmp6.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <nlist.h>
+#include <stdio.h>
+#include <string.h>
+#include <paths.h>
+#include <err.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* packing rule for routing socket */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof (uint32_t) - 1))) : \
+ sizeof (uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+static int pid;
+static int cflag;
+static int nflag;
+static int tflag;
+static int32_t thiszone = 0; /* time difference with gmt */
+static int s = -1;
+static int repeat = 0;
+
+static char host_buf[NI_MAXHOST]; /* getnameinfo() */
+static char ifix_buf[IFNAMSIZ]; /* if_indextoname() */
+
+static int file(char *);
+static void getsocket(void);
+static int set(int, char **);
+static void get(char *);
+static int delete(char *);
+static void dump(struct in6_addr *);
+static void dump_ext(struct in6_addr *, int);
+static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
+static char *ether_str(struct sockaddr_dl *);
+static int ndp_ether_aton(char *, u_char *);
+static void usage(void);
+static int rtmsg(int);
+static void ifinfo(int, char **);
+static void rtrlist(void);
+static void plist(void);
+static void pfx_flush(void);
+static void rtrlist(void);
+static void rtr_flush(void);
+static void harmonize_rtr(void);
+static void getdefif(void);
+static void setdefif(char *);
+static char *sec2str(time_t);
+static char *ether_str(struct sockaddr_dl *);
+static void ts_print(const struct timeval *);
+static void read_cga_parameters(void);
+static void write_cga_parameters(const char[]);
+
+static char *rtpref_str[] = {
+ "medium", /* 00 */
+ "high", /* 01 */
+ "rsv", /* 10 */
+ "low" /* 11 */
+};
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ int aflag = 0, dflag = 0, sflag = 0, Hflag = 0, pflag = 0, rflag = 0,
+ Pflag = 0, Rflag = 0, lflag = 0, xflag = 0, wflag = 0;
+
+ pid = getpid();
+ while ((ch = getopt(argc, argv, "acndfIilprstA:HPRxwW")) != -1)
+ switch ((char) ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'I':
+ if (argc > 2)
+ setdefif(argv[2]);
+ getdefif(); /* always call it to print the result */
+ exit(0);
+ case 'i' :
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ usage();
+ ifinfo(argc, argv);
+ exit(0);
+ case 'n':
+ nflag = 1;
+ continue;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'f' :
+ if (argc != 3)
+ usage();
+ file(argv[2]);
+ exit(0);
+ case 'l' :
+ lflag = 1;
+ break;
+ case 'r' :
+ rflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'A':
+ aflag = 1;
+ repeat = atoi(optarg);
+ if (repeat < 0)
+ usage();
+ break;
+ case 'H' :
+ Hflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ lflag = 1;
+ break;
+ case 'w':
+ wflag = 1;
+ break;
+ case 'W':
+ if (argc != 3)
+ usage();
+ write_cga_parameters(argv[2]);
+ exit(0);
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (aflag || cflag) {
+ if (lflag)
+ dump_ext(0, xflag);
+ else
+ dump(0);
+ exit(0);
+ }
+ if (dflag) {
+ if (argc != 1)
+ usage();
+ delete(argv[0]);
+ exit(0);
+ }
+ if (pflag) {
+ plist();
+ exit(0);
+ }
+ if (rflag) {
+ rtrlist();
+ exit(0);
+ }
+ if (sflag) {
+ if (argc < 2 || argc > 4)
+ usage();
+ exit(set(argc, argv) ? 1 : 0);
+ }
+ if (Hflag) {
+ harmonize_rtr();
+ exit(0);
+ }
+ if (Pflag) {
+ pfx_flush();
+ exit(0);
+ }
+ if (Rflag) {
+ rtr_flush();
+ exit(0);
+ }
+ if (wflag) {
+ read_cga_parameters();
+ exit(0);
+ }
+
+ if (argc != 1)
+ usage();
+ get(argv[0]);
+ exit(0);
+}
+
+/*
+ * Process a file to set standard ndp entries
+ */
+static int
+file(char *name)
+{
+ FILE *fp;
+ int i, retval;
+ char line[100], arg[5][50], *args[5];
+
+ if ((fp = fopen(name, "r")) == NULL) {
+ fprintf(stderr, "ndp: cannot open %s\n", name);
+ exit(1);
+ }
+ args[0] = &arg[0][0];
+ args[1] = &arg[1][0];
+ args[2] = &arg[2][0];
+ args[3] = &arg[3][0];
+ args[4] = &arg[4][0];
+ retval = 0;
+ while (fgets(line, 100, fp) != NULL) {
+ i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
+ arg[3], arg[4]);
+ if (i < 2) {
+ fprintf(stderr, "ndp: bad line: %s\n", line);
+ retval = 1;
+ continue;
+ }
+ if (set(i, args))
+ retval = 1;
+ }
+ fclose(fp);
+ return (retval);
+}
+
+static void
+getsocket(void)
+{
+ if (s < 0) {
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ }
+}
+
+struct sockaddr_in6 so_mask = {sizeof (so_mask), AF_INET6 };
+struct sockaddr_in6 blank_sin = {sizeof (blank_sin), AF_INET6 }, sin_m;
+struct sockaddr_dl blank_sdl = {sizeof (blank_sdl), AF_LINK }, sdl_m;
+int expire_time, flags, found_entry;
+struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+/*
+ * Set an individual neighbor cache entry
+ */
+static int
+set(int argc, char **argv)
+{
+ register struct sockaddr_in6 *sin = &sin_m;
+ register struct sockaddr_dl *sdl;
+ register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
+ struct addrinfo hints, *res;
+ int gai_error;
+ u_char *ea;
+ char *host = argv[0], *eaddr = argv[1];
+ int ealen;
+
+ getsocket();
+ argc -= 2;
+ argv += 2;
+ sdl_m = blank_sdl;
+ sin_m = blank_sin;
+
+ bzero(&hints, sizeof (hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return (1);
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
+ htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
+ }
+#endif
+ ea = (u_char *)LLADDR(&sdl_m);
+
+ ealen = ndp_ether_aton(eaddr, ea);
+ if (ealen != -1)
+ sdl_m.sdl_alen = ealen;
+ flags = expire_time = 0;
+ while (argc-- > 0) {
+ if (strncmp(argv[0], "temp", 4) == 0) {
+ struct timeval time;
+ gettimeofday(&time, 0);
+ expire_time = time.tv_sec + 20 * 60;
+ } else if (strncmp(argv[0], "proxy", 5) == 0)
+ flags |= RTF_ANNOUNCE;
+ argv++;
+ }
+ if (rtmsg(RTM_GET) < 0) {
+ perror(host);
+ return (1);
+ }
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
+ if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
+ case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
+ case IFT_ISO88024: case IFT_ISO88025:
+ case IFT_6LOWPAN:
+ goto overwrite;
+ }
+ /*
+ * IPv4 arp command retries with sin_other = SIN_PROXY here.
+ */
+ fprintf(stderr, "set: cannot configure a new entry\n");
+ return (1);
+ }
+
+overwrite:
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot intuit interface index and type for %s\n", host);
+ return (1);
+ }
+ sdl_m.sdl_type = sdl->sdl_type;
+ sdl_m.sdl_index = sdl->sdl_index;
+ return (rtmsg(RTM_ADD));
+}
+
+/*
+ * Display an individual neighbor cache entry
+ */
+static void
+get(char *host)
+{
+ struct sockaddr_in6 *sin = &sin_m;
+ struct addrinfo hints, *res;
+ int gai_error;
+
+ sin_m = blank_sin;
+ bzero(&hints, sizeof (hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return;
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
+ htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
+ }
+#endif
+ dump(&sin->sin6_addr);
+ if (found_entry == 0) {
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof (host_buf), NULL, 0, NI_WITHSCOPEID | (nflag ?
+ NI_NUMERICHOST : 0));
+ printf("%s (%s) -- no entry\n", host, host_buf);
+ exit(1);
+ }
+}
+
+/*
+ * Delete a neighbor cache entry
+ */
+static int
+delete(char *host)
+{
+ struct sockaddr_in6 *sin = &sin_m;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ struct sockaddr_dl *sdl;
+ struct addrinfo hints, *res;
+ int gai_error;
+
+ getsocket();
+ sin_m = blank_sin;
+
+ bzero(&hints, sizeof (hints));
+ hints.ai_family = AF_INET6;
+ gai_error = getaddrinfo(host, NULL, &hints, &res);
+ if (gai_error) {
+ fprintf(stderr, "ndp: %s: %s\n", host,
+ gai_strerror(gai_error));
+ return (1);
+ }
+ sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
+ htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
+ }
+#endif
+ if (rtmsg(RTM_GET) < 0) {
+ perror(host);
+ return (1);
+ }
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
+ if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
+ if (sdl->sdl_family == AF_LINK &&
+ (rtm->rtm_flags & RTF_LLINFO) &&
+ !(rtm->rtm_flags & RTF_GATEWAY)) {
+ goto delete;
+ }
+ /*
+ * IPv4 arp command retries with sin_other = SIN_PROXY here.
+ */
+ fprintf(stderr, "delete: cannot delete non-NDP entry\n");
+ return (1);
+ }
+
+delete:
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot locate %s\n", host);
+ return (1);
+ }
+ if (rtmsg(RTM_DELETE) == 0) {
+ struct sockaddr_in6 s6 = *sin;
+
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
+ s6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
+ *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
+ }
+#endif
+ getnameinfo((struct sockaddr *)&s6,
+ s6.sin6_len, host_buf,
+ sizeof (host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ printf("%s (%s) deleted\n", host, host_buf);
+ }
+
+ return (0);
+}
+
+#define W_ADDR 31
+#define W_LL 17
+#define W_IF 6
+
+/*
+ * Dump the entire neighbor cache
+ */
+static void
+dump(struct in6_addr *addr)
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *next;
+ struct rt_msghdr *rtm;
+ struct sockaddr_in6 *sin;
+ struct sockaddr_dl *sdl;
+ struct in6_nbrinfo *nbi;
+ struct timeval time;
+ int addrwidth;
+ int llwidth;
+ int ifwidth;
+ char flgbuf[8];
+ char *ifname;
+
+ /* Print header */
+ if (!tflag && !cflag)
+ printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n",
+ W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
+ W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs");
+
+again:;
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET6;
+ mib[4] = NET_RT_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE estimate)");
+ if (needed > 0) {
+ if ((buf = malloc(needed)) == NULL)
+ errx(1, "malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
+ lim = buf + needed;
+ } else
+ buf = lim = NULL;
+
+ for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
+ int isrouter = 0, prbs = 0;
+
+ rtm = (struct rt_msghdr *)next;
+ sin = (struct sockaddr_in6 *)(rtm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin +
+ ROUNDUP(sin->sin6_len));
+
+ /*
+ * Some OSes can produce a route that has the LINK flag but
+ * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
+ * and BSD/OS, where xx is not the interface identifier on
+ * lo0). Such routes entry would annoy getnbrinfo() below,
+ * so we skip them.
+ * XXX: such routes should have the GATEWAY flag, not the
+ * LINK flag. However, there are rotten routing software
+ * that advertises all routes that have the GATEWAY flag.
+ * Thus, KAME kernel intentionally does not set the LINK flag.
+ * What is to be fixed is not ndp, but such routing software
+ * (and the kernel workaround)...
+ */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+
+ if (addr) {
+ if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
+ continue;
+ found_entry = 1;
+ } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
+ continue;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
+ /* should scope id be filled in the kernel? */
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = sdl->sdl_index;
+#ifdef __KAME__
+ /* KAME specific hack; removed the embedded id */
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
+#endif
+ }
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof (host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ if (cflag == 1) {
+ if (rtm->rtm_flags & RTF_WASCLONED)
+ delete(host_buf);
+ continue;
+ }
+ gettimeofday(&time, 0);
+ if (tflag)
+ ts_print(&time);
+
+ addrwidth = strlen(host_buf);
+ if (addrwidth < W_ADDR)
+ addrwidth = W_ADDR;
+ llwidth = strlen(ether_str(sdl));
+ if (W_ADDR + W_LL - addrwidth > llwidth)
+ llwidth = W_ADDR + W_LL - addrwidth;
+ ifname = if_indextoname(sdl->sdl_index, ifix_buf);
+ if (!ifname)
+ ifname = "?";
+ ifwidth = strlen(ifname);
+ if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
+ ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
+
+ printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
+ llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
+
+ /* Print neighbor discovery specific informations */
+ nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
+ if (nbi) {
+ if (nbi->expire > time.tv_sec) {
+ printf(" %-9.9s", sec2str(nbi->expire -
+ time.tv_sec));
+ } else if (nbi->expire == 0)
+ printf(" %-9.9s", "permanent");
+ else
+ printf(" %-9.9s", "expired");
+
+ switch (nbi->state) {
+ case ND6_LLINFO_NOSTATE:
+ printf(" N");
+ break;
+ case ND6_LLINFO_INCOMPLETE:
+ printf(" I");
+ break;
+ case ND6_LLINFO_REACHABLE:
+ printf(" R");
+ break;
+ case ND6_LLINFO_STALE:
+ printf(" S");
+ break;
+ case ND6_LLINFO_DELAY:
+ printf(" D");
+ break;
+ case ND6_LLINFO_PROBE:
+ printf(" P");
+ break;
+ default:
+ printf(" ?");
+ break;
+ }
+
+ isrouter = nbi->isrouter;
+ prbs = nbi->asked;
+ } else {
+ warnx("failed to get neighbor information");
+ printf(" ");
+ }
+ putchar(' ');
+
+ /*
+ * other flags. R: router, P: proxy, W: ??
+ */
+ if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
+ snprintf(flgbuf, sizeof (flgbuf), "%s%s",
+ isrouter ? "R" : "",
+ (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ } else {
+ sin = (struct sockaddr_in6 *)
+ (sdl->sdl_len + (char *)sdl);
+ snprintf(flgbuf, sizeof (flgbuf), "%s%s%s%s",
+ isrouter ? "R" : "",
+ !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
+ ? "P" : "",
+ (sin->sin6_len != sizeof (struct sockaddr_in6))
+ ? "W" : "",
+ (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ }
+ printf(" %-4.4s", flgbuf);
+
+ if (prbs)
+ printf(" %4d", prbs);
+
+ printf("\n");
+ }
+ if (buf != NULL)
+ free(buf);
+
+ if (repeat) {
+ printf("\n");
+ sleep(repeat);
+ goto again;
+ }
+}
+
+/*
+ * Dump the entire neighbor cache (extended)
+ */
+void
+dump_ext(addr, xflag)
+ struct in6_addr *addr;
+ int xflag;
+{
+ int mib[6];
+ size_t needed;
+ char *lim, *buf, *next;
+ struct rt_msghdr_ext *ertm;
+ struct sockaddr_in6 *sin;
+ struct sockaddr_dl *sdl;
+ struct in6_nbrinfo *nbi;
+ struct timeval time;
+ int addrwidth;
+ int llwidth;
+ int ifwidth;
+ char flgbuf[8];
+ char *ifname;
+
+ /* Print header */
+ if (!tflag && !cflag) {
+ printf("%-*.*s %-*.*s %*.*s %-9.9s %-9.9s %2s %4s %4s",
+ W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
+ W_IF, W_IF, "Netif", "Expire(O)", "Expire(I)", "St",
+ "Flgs", "Prbs");
+ if (xflag)
+ printf(" %-7.7s %-7.7s %-7.7s", "RSSI", "LQM", "NPM");
+ printf("\n");
+ }
+
+again:;
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET6;
+ mib[4] = NET_RT_DUMPX_FLAGS;
+ mib[5] = RTF_LLINFO;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE estimate)");
+ if (needed > 0) {
+ if ((buf = malloc(needed)) == NULL)
+ errx(1, "malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
+ lim = buf + needed;
+ } else
+ buf = lim = NULL;
+
+ for (next = buf; next && next < lim; next += ertm->rtm_msglen) {
+ int isrouter = 0, prbs = 0;
+
+ ertm = (struct rt_msghdr_ext *)next;
+ sin = (struct sockaddr_in6 *)(ertm + 1);
+ sdl = (struct sockaddr_dl *)((char *)sin +
+ ROUNDUP(sin->sin6_len));
+
+ /*
+ * Some OSes can produce a route that has the LINK flag but
+ * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
+ * and BSD/OS, where xx is not the interface identifier on
+ * lo0). Such routes entry would annoy getnbrinfo() below,
+ * so we skip them.
+ * XXX: such routes should have the GATEWAY flag, not the
+ * LINK flag. However, there are rotten routing software
+ * that advertises all routes that have the GATEWAY flag.
+ * Thus, KAME kernel intentionally does not set the LINK flag.
+ * What is to be fixed is not ndp, but such routing software
+ * (and the kernel workaround)...
+ */
+ if (sdl->sdl_family != AF_LINK)
+ continue;
+
+ if (addr) {
+ if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
+ continue;
+ found_entry = 1;
+ } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
+ continue;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
+ /* should scope id be filled in the kernel? */
+ if (sin->sin6_scope_id == 0)
+ sin->sin6_scope_id = sdl->sdl_index;
+#ifdef __KAME__
+ /* KAME specific hack; removed the embedded id */
+ *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
+#endif
+ }
+ getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
+ sizeof (host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
+ if (cflag == 1) {
+ if (ertm->rtm_flags & RTF_WASCLONED)
+ delete(host_buf);
+ continue;
+ }
+ gettimeofday(&time, 0);
+ if (tflag)
+ ts_print(&time);
+
+ addrwidth = strlen(host_buf);
+ if (addrwidth < W_ADDR)
+ addrwidth = W_ADDR;
+ llwidth = strlen(ether_str(sdl));
+ if (W_ADDR + W_LL - addrwidth > llwidth)
+ llwidth = W_ADDR + W_LL - addrwidth;
+ ifname = if_indextoname(sdl->sdl_index, ifix_buf);
+ if (!ifname)
+ ifname = "?";
+ ifwidth = strlen(ifname);
+ if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
+ ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
+
+ printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
+ llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
+
+ if (ertm->rtm_ri.ri_refcnt == 0 ||
+ ertm->rtm_ri.ri_snd_expire == 0)
+ printf(" %-9.9s", "(none)");
+ else if (ertm->rtm_ri.ri_snd_expire > time.tv_sec)
+ printf(" %-9.9s",
+ sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec));
+ else
+ printf(" %-9.9s", "expired");
+
+ if (ertm->rtm_ri.ri_refcnt == 0 ||
+ ertm->rtm_ri.ri_rcv_expire == 0)
+ printf(" %-9.9s", "(none)");
+ else if (ertm->rtm_ri.ri_rcv_expire > time.tv_sec)
+ printf(" %-9.9s",
+ sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec));
+ else
+ printf(" %-9.9s", "expired");
+
+ /* Print neighbor discovery specific informations */
+ nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
+ if (nbi) {
+ switch (nbi->state) {
+ case ND6_LLINFO_NOSTATE:
+ printf(" N");
+ break;
+ case ND6_LLINFO_INCOMPLETE:
+ printf(" I");
+ break;
+ case ND6_LLINFO_REACHABLE:
+ printf(" R");
+ break;
+ case ND6_LLINFO_STALE:
+ printf(" S");
+ break;
+ case ND6_LLINFO_DELAY:
+ printf(" D");
+ break;
+ case ND6_LLINFO_PROBE:
+ printf(" P");
+ break;
+ default:
+ printf(" ?");
+ break;
+ }
+
+ isrouter = nbi->isrouter;
+ prbs = nbi->asked;
+ } else {
+ warnx("failed to get neighbor information");
+ printf(" ");
+ }
+ putchar(' ');
+
+ /*
+ * other flags. R: router, P: proxy, W: ??
+ */
+ if ((ertm->rtm_addrs & RTA_NETMASK) == 0) {
+ snprintf(flgbuf, sizeof (flgbuf), "%s%s",
+ isrouter ? "R" : "",
+ (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ } else {
+ sin = (struct sockaddr_in6 *)
+ (sdl->sdl_len + (char *)sdl);
+ snprintf(flgbuf, sizeof (flgbuf), "%s%s%s%s",
+ isrouter ? "R" : "",
+ !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
+ ? "P" : "",
+ (sin->sin6_len != sizeof (struct sockaddr_in6))
+ ? "W" : "",
+ (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
+ }
+ printf(" %-4.4s", flgbuf);
+
+ if (prbs)
+ printf(" %4d", prbs);
+
+ if (xflag) {
+ if (!prbs)
+ printf(" %-4.4s", "none");
+
+ if (ertm->rtm_ri.ri_rssi != IFNET_RSSI_UNKNOWN)
+ printf(" %7d", ertm->rtm_ri.ri_rssi);
+ else
+ printf(" %-7.7s", "unknown");
+
+ switch (ertm->rtm_ri.ri_lqm)
+ {
+ case IFNET_LQM_THRESH_OFF:
+ printf(" %-7.7s", "off");
+ break;
+ case IFNET_LQM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_LQM_THRESH_POOR:
+ printf(" %-7.7s", "poor");
+ break;
+ case IFNET_LQM_THRESH_GOOD:
+ printf(" %-7.7s", "good");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_lqm);
+ break;
+ }
+
+ switch (ertm->rtm_ri.ri_npm)
+ {
+ case IFNET_NPM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_NPM_THRESH_NEAR:
+ printf(" %-7.7s", "near");
+ break;
+ case IFNET_NPM_THRESH_GENERAL:
+ printf(" %-7.7s", "general");
+ break;
+ case IFNET_NPM_THRESH_FAR:
+ printf(" %-7.7s", "far");
+ break;
+ default:
+ printf(" %7d", ertm->rtm_ri.ri_npm);
+ break;
+ }
+ }
+
+ printf("\n");
+ }
+ if (buf != NULL)
+ free(buf);
+
+ if (repeat) {
+ printf("\n");
+ sleep(repeat);
+ goto again;
+ }
+}
+
+static struct in6_nbrinfo *
+getnbrinfo(addr, ifindex, warning)
+ struct in6_addr *addr;
+ int ifindex;
+ int warning;
+{
+ static struct in6_nbrinfo nbi;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ bzero(&nbi, sizeof (nbi));
+ if_indextoname(ifindex, nbi.ifname);
+ nbi.addr = *addr;
+ if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
+ if (warning)
+ warn("ioctl(SIOCGNBRINFO_IN6)");
+ close(s);
+ return (NULL);
+ }
+
+ close(s);
+ return (&nbi);
+}
+
+static char *
+ether_str(struct sockaddr_dl *sdl)
+{
+ static char ebuf[32];
+ u_char *cp;
+
+ if (sdl->sdl_alen) {
+ cp = (u_char *)LLADDR(sdl);
+ snprintf(ebuf, sizeof (ebuf), "%x:%x:%x:%x:%x:%x",
+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+ } else {
+ snprintf(ebuf, sizeof (ebuf), "(incomplete)");
+ }
+
+ return (ebuf);
+}
+
+static int
+ndp_ether_aton(char *a, u_char *n)
+{
+ int i, o[8];
+ int len;
+
+ len = sscanf(a, "%x:%x:%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], &o[3], &o[4],
+ &o[5], &o[6], &o[7]);
+ if (len != 6 && len != 8) {
+ fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
+ return (-1);
+ }
+ for (i = 0; i < len; i++)
+ n[i] = o[i];
+ return (len);
+}
+
+static void
+usage(void)
+{
+ printf("usage: ndp hostname\n");
+ printf(" ndp -a[lnt]\n");
+ printf(" ndp [-nt] -A wait\n");
+ printf(" ndp -c[nt]\n");
+ printf(" ndp -d[nt] hostname\n");
+ printf(" ndp -f[nt] filename\n");
+ printf(" ndp -i interface [flags...]\n");
+ printf(" ndp -I [interface|delete]\n");
+ printf(" ndp -p\n");
+ printf(" ndp -r\n");
+ printf(" ndp -s hostname ether_addr [temp] [proxy]\n");
+ printf(" ndp -H\n");
+ printf(" ndp -P\n");
+ printf(" ndp -R\n");
+ printf(" ndp -w\n");
+ printf(" ndp -W cfgfile\n");
+ exit(1);
+}
+
+static int
+rtmsg(int cmd)
+{
+ static int seq;
+ int rlen;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+
+ errno = 0;
+ if (cmd == RTM_DELETE)
+ goto doit;
+ bzero((char *)&m_rtmsg, sizeof (m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ switch (cmd) {
+ default:
+ fprintf(stderr, "ndp: internal wrong cmd\n");
+ exit(1);
+ case RTM_ADD:
+ rtm->rtm_addrs |= RTA_GATEWAY;
+ rtm->rtm_rmx.rmx_expire = expire_time;
+ rtm->rtm_inits = RTV_EXPIRE;
+ rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
+ if (rtm->rtm_flags & RTF_ANNOUNCE) {
+ rtm->rtm_flags &= ~RTF_HOST;
+ rtm->rtm_flags |= RTA_NETMASK;
+ }
+ /* FALLTHROUGH */
+ case RTM_GET:
+ rtm->rtm_addrs |= RTA_DST;
+ }
+#define NEXTADDR(w, s) \
+ if (rtm->rtm_addrs & (w)) { \
+ bcopy((char *)&s, cp, sizeof (s)); cp += sizeof (s); \
+ }
+
+ NEXTADDR(RTA_DST, sin_m);
+ NEXTADDR(RTA_GATEWAY, sdl_m);
+ memset(&so_mask.sin6_addr, 0xff, sizeof (so_mask.sin6_addr));
+ NEXTADDR(RTA_NETMASK, so_mask);
+
+ rtm->rtm_msglen = cp - (char *)&m_rtmsg;
+doit:
+ l = rtm->rtm_msglen;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_type = cmd;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ if (errno != ESRCH || cmd != RTM_DELETE) {
+ perror("writing to routing socket");
+ return (-1);
+ }
+ }
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg));
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
+ if (l < 0)
+ (void) fprintf(stderr, "ndp: read from routing socket: %s\n",
+ strerror(errno));
+ return (0);
+}
+
+static void
+ifinfo(int argc, char **argv)
+{
+ struct in6_ndireq nd;
+ int i, s;
+ char *ifname = argv[0];
+ u_int32_t newflags;
+ u_int8_t nullbuf[8];
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("ndp: socket");
+ exit(1);
+ }
+ bzero(&nd, sizeof (nd));
+ strlcpy(nd.ifname, ifname, sizeof (nd.ifname));
+ if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
+ perror("ioctl (SIOCGIFINFO_IN6)");
+ exit(1);
+ }
+#define ND nd.ndi
+ newflags = ND.flags;
+ for (i = 1; i < argc; i++) {
+ int clear = 0;
+ char *cp = argv[i];
+
+ if (*cp == '-') {
+ clear = 1;
+ cp++;
+ }
+
+#define SETFLAG(s, f) \
+ do {\
+ if (strcmp(cp, (s)) == 0) {\
+ if (clear)\
+ newflags &= ~(f);\
+ else\
+ newflags |= (f);\
+ }\
+ } while (0)
+ SETFLAG("nud", ND6_IFF_PERFORMNUD);
+ SETFLAG("proxy_prefixes", ND6_IFF_PROXY_PREFIXES);
+ SETFLAG("disabled", ND6_IFF_IFDISABLED);
+ SETFLAG("insecure", ND6_IFF_INSECURE);
+ SETFLAG("replicated", ND6_IFF_REPLICATED);
+
+ ND.flags = newflags;
+ if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
+ perror("ioctl(SIOCSIFINFO_FLAGS)");
+ exit(1);
+ }
+#undef SETFLAG
+ }
+
+ printf("linkmtu=%d", ND.linkmtu);
+ printf(", curhlim=%d", ND.chlim);
+ printf(", basereachable=%ds%dms", ND.basereachable / 1000,
+ ND.basereachable % 1000);
+ printf(", reachable=%ds", ND.reachable);
+ printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
+ memset(nullbuf, 0, sizeof (nullbuf));
+ if (memcmp(nullbuf, ND.randomid, sizeof (nullbuf)) != 0) {
+ int j;
+ u_int8_t *rbuf = NULL;
+
+ for (i = 0; i < 3; i++) {
+ switch (i) {
+ case 0:
+ printf("\nRandom seed(0): ");
+ rbuf = ND.randomseed0;
+ break;
+ case 1:
+ printf("\nRandom seed(1): ");
+ rbuf = ND.randomseed1;
+ break;
+ case 2:
+ printf("\nRandom ID: ");
+ rbuf = ND.randomid;
+ break;
+ }
+ for (j = 0; j < 8; j++)
+ printf("%02x", rbuf[j]);
+ }
+ }
+ if (ND.flags) {
+ printf("\nFlags: 0x%x ", ND.flags);
+ if ((ND.flags & ND6_IFF_IFDISABLED) != 0)
+ printf("IFDISABLED ");
+ if ((ND.flags & ND6_IFF_INSECURE) != 0)
+ printf("INSECURE ");
+ if ((ND.flags & ND6_IFF_PERFORMNUD) != 0)
+ printf("PERFORMNUD ");
+ if ((ND.flags & ND6_IFF_PROXY_PREFIXES) != 0)
+ printf("PROXY_PREFIXES ");
+ if ((ND.flags & ND6_IFF_REPLICATED) != 0)
+ printf("REPLICATED ");
+ if ((ND.flags & ND6_IFF_DAD) != 0)
+ printf("DAD ");
+ }
+ putc('\n', stdout);
+#undef ND
+
+ close(s);
+}
+
+#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */
+#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
+#endif
+
+static void
+rtrlist(void)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
+ char *buf;
+ struct in6_defrouter *p, *ep;
+ size_t l;
+ struct timeval time;
+
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), NULL, &l, NULL, 0)
+ < 0) {
+ err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
+ /*NOTREACHED*/
+ }
+ buf = malloc(l);
+ if (!buf) {
+ errx(1, "not enough core");
+ /*NOTREACHED*/
+ }
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), buf, &l, NULL, 0) < 0) {
+ err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
+ /*NOTREACHED*/
+ }
+
+ ep = (struct in6_defrouter *)(buf + l);
+ for (p = (struct in6_defrouter *)buf; p < ep; p++) {
+ int rtpref;
+
+ if (getnameinfo((struct sockaddr *)&p->rtaddr,
+ p->rtaddr.sin6_len, host_buf, sizeof (host_buf), NULL, 0,
+ NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)) != 0)
+ strlcpy(host_buf, "?", sizeof (host_buf));
+
+ printf("%s if=%s", host_buf, if_indextoname(p->if_index,
+ ifix_buf));
+ printf(", flags=%s%s%s%s%s",
+ p->stateflags & NDDRF_IFSCOPE ? "I" : "",
+ p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
+ p->flags & ND_RA_FLAG_OTHER ? "O" : "",
+ p->stateflags & NDDRF_STATIC ? "S" : "",
+ p->stateflags & NDDRF_INSTALLED ? "T" : "");
+ rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
+ printf(", pref=%s", rtpref_str[rtpref]);
+
+ gettimeofday(&time, 0);
+ if (p->expire == 0)
+ printf(", expire=Never\n");
+ else
+ printf(", expire=%s\n",
+ sec2str(p->expire - time.tv_sec));
+ }
+ free(buf);
+}
+
+static void
+plist(void)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
+ char *buf;
+ struct in6_prefix *p, *ep, *n;
+ struct sockaddr_in6 *advrtr;
+ size_t l;
+ struct timeval time;
+ const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
+ int ninflags = (nflag ? NI_NUMERICHOST : 0) | NI_WITHSCOPEID;
+ char namebuf[NI_MAXHOST];
+
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), NULL, &l, NULL, 0)
+ < 0) {
+ err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
+ /*NOTREACHED*/
+ }
+ buf = malloc(l);
+ if (!buf) {
+ errx(1, "not enough core");
+ /*NOTREACHED*/
+ }
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), buf, &l, NULL, 0)
+ < 0) {
+ err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
+ /*NOTREACHED*/
+ }
+
+ ep = (struct in6_prefix *)(buf + l);
+ for (p = (struct in6_prefix *)buf; p < ep; p = n) {
+ advrtr = (struct sockaddr_in6 *)(p + 1);
+ n = (struct in6_prefix *)&advrtr[p->advrtrs];
+
+ if (getnameinfo((struct sockaddr *)&p->prefix,
+ p->prefix.sin6_len, namebuf, sizeof (namebuf),
+ NULL, 0, niflags) != 0)
+ strlcpy(namebuf, "?", sizeof (namebuf));
+ printf("%s/%d if=%s\n", namebuf, p->prefixlen,
+ if_indextoname(p->if_index, ifix_buf));
+
+ gettimeofday(&time, 0);
+ /*
+ * meaning of fields, especially flags, is very different
+ * by origin. notify the difference to the users.
+ */
+ printf("flags=%s%s%s%s%s%s%s",
+ p->raflags.autonomous ? "A" : "",
+ (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
+ (p->flags & NDPRF_IFSCOPE) != 0 ? "I" : "",
+ p->raflags.onlink ? "L" : "",
+ (p->flags & NDPRF_STATIC) != 0 ? "S" : "",
+ (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
+ (p->flags & NDPRF_PRPROXY) != 0 ? "Y" : "");
+ if (p->vltime == ND6_INFINITE_LIFETIME)
+ printf(" vltime=infinity");
+ else
+ printf(" vltime=%ld", (long)p->vltime);
+ if (p->pltime == ND6_INFINITE_LIFETIME)
+ printf(", pltime=infinity");
+ else
+ printf(", pltime=%ld", (long)p->pltime);
+ if (p->expire == 0)
+ printf(", expire=Never");
+ else if (p->expire >= time.tv_sec)
+ printf(", expire=%s",
+ sec2str(p->expire - time.tv_sec));
+ else
+ printf(", expired");
+ printf(", ref=%d", p->refcnt);
+ printf("\n");
+ /*
+ * "advertising router" list is meaningful only if the prefix
+ * information is from RA.
+ */
+ if (p->advrtrs) {
+ int j;
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)(p + 1);
+ printf(" advertised by\n");
+ for (j = 0; j < p->advrtrs; j++) {
+ struct in6_nbrinfo *nbi;
+
+ if (getnameinfo((struct sockaddr *)sin6,
+ sin6->sin6_len, namebuf, sizeof (namebuf),
+ NULL, 0, ninflags) != 0)
+ strlcpy(namebuf, "?", sizeof (namebuf));
+ printf(" %s", namebuf);
+
+ nbi = getnbrinfo(&sin6->sin6_addr, p->if_index,
+ 0);
+ if (nbi) {
+ switch (nbi->state) {
+ case ND6_LLINFO_REACHABLE:
+ case ND6_LLINFO_STALE:
+ case ND6_LLINFO_DELAY:
+ case ND6_LLINFO_PROBE:
+ printf(" (reachable)\n");
+ break;
+ default:
+ printf(" (unreachable)\n");
+ }
+ } else
+ printf(" (no neighbor state)\n");
+ sin6++;
+ }
+ } else
+ printf(" No advertising router\n");
+ }
+ free(buf);
+}
+
+static void
+pfx_flush(void)
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
+ if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
+ err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
+}
+
+static void
+rtr_flush(void)
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
+ if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
+ err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
+
+ close(s);
+}
+
+static void
+harmonize_rtr(void)
+{
+ char dummyif[IFNAMSIZ+8];
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+ strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
+ if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
+ err(1, "ioctl (SIOCSNDFLUSH_IN6)");
+
+ close(s);
+}
+
+static void
+setdefif(char *ifname)
+{
+ struct in6_ndifreq ndifreq;
+ unsigned int ifindex;
+
+ if (strcasecmp(ifname, "delete") == 0)
+ ifindex = 0;
+ else {
+ if ((ifindex = if_nametoindex(ifname)) == 0)
+ err(1, "failed to resolve i/f index for %s", ifname);
+ }
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ strlcpy(ndifreq.ifname, "lo0", sizeof (ndifreq.ifname)); /* dummy */
+ ndifreq.ifindex = ifindex;
+
+ if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
+ err(1, "ioctl (SIOCSDEFIFACE_IN6)");
+
+ close(s);
+}
+
+static void
+getdefif(void)
+{
+ struct in6_ndifreq ndifreq;
+ char ifname[IFNAMSIZ+8];
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "socket");
+
+ memset(&ndifreq, 0, sizeof (ndifreq));
+ strlcpy(ndifreq.ifname, "lo0", sizeof (ndifreq.ifname)); /* dummy */
+
+ if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
+ err(1, "ioctl (SIOCGDEFIFACE_IN6)");
+
+ if (ndifreq.ifindex == 0)
+ printf("No default interface.\n");
+ else {
+ if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
+ err(1, "failed to resolve ifname for index %lu",
+ ndifreq.ifindex);
+ printf("ND default interface = %s\n", ifname);
+ }
+
+ close(s);
+}
+
+static char *
+sec2str(time_t total)
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof (result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof (result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins)
+ p += snprintf(p, sizeof (result) - (p - result), "%dm", mins);
+ snprintf(p, sizeof (result) - (p - result), "%ds", secs);
+
+ return (result);
+}
+
+/*
+ * Print the timestamp
+ * from tcpdump/util.c
+ */
+static void
+ts_print(const struct timeval *tvp)
+{
+ int s;
+
+ /* Default */
+ s = (tvp->tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tvp->tv_usec);
+}
+
+#define SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \
+ 2 * (sizeof (size_t) + IN6_CGA_KEY_MAXSIZE) + \
+ sizeof (struct in6_cga_prepare)
+
+static void
+read_cga_parameters(void)
+{
+ static char oldb[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
+
+ int error;
+ struct in6_cga_nodecfg cfg;
+ struct iovec *iov;
+ const char *oldp;
+ const char *finp;
+ size_t oldn;
+ unsigned int column;
+ uint16_t u16;
+
+ oldn = sizeof oldb;
+ error = sysctlbyname("net.inet6.send.cga_parameters", oldb, &oldn,
+ NULL, NULL);
+ if (error != 0)
+ err(1, "sysctlbyname");
+
+ if (oldn == 0) {
+ printf("No CGA parameters.\n");
+ exit(0);
+ }
+
+ oldp = oldb;
+ finp = &oldb[oldn];
+ memset(&cfg, 0, sizeof (cfg));
+
+ if (oldp + sizeof (cfg.cga_prepare) > finp)
+ err(1, "format error[1]");
+
+ memcpy(&cfg.cga_prepare, oldp, sizeof (cfg.cga_prepare));
+ oldp += sizeof (cfg.cga_prepare);
+
+ iov = &cfg.cga_pubkey;
+
+ if (oldp + sizeof (u16) > finp)
+ err(1, "format error[2]");
+
+ memcpy(&u16, oldp, sizeof (u16));
+ oldp += sizeof (u16);
+ iov->iov_len = u16;
+
+ if (oldp + iov->iov_len > finp)
+ err(1, "format error[3]");
+
+ iov->iov_base = (void *)oldp;
+ oldp += iov->iov_len;
+
+ if (oldp != finp)
+ err(1, "format error[4]");
+
+ puts("Public Key:");
+ finp = &iov->iov_base[iov->iov_len];
+ column = 0;
+ oldp = iov->iov_base;
+ while (oldp < finp) {
+ if (column++ != 0)
+ putchar(':');
+ printf("%02x", (unsigned char) *oldp++);
+ if (column >= 32) {
+ column = 0;
+ puts("");
+ }
+ }
+ if (column < 32)
+ puts("");
+ puts("");
+ puts("Modifier:");
+ oldp = (const char*) cfg.cga_prepare.cga_modifier.octets;
+ finp = &oldp[sizeof (cfg.cga_prepare.cga_modifier.octets)];
+ column = 0;
+ while (oldp < finp) {
+ if (column++ != 0)
+ putchar(':');
+ printf("%02x", (unsigned char) *oldp++);
+ }
+ puts("\n");
+ printf("Security Level: %u\n", cfg.cga_prepare.cga_security_level);
+}
+
+static void
+write_cga_parameters(const char filename[])
+{
+ static char newb[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
+
+ int error;
+ FILE* fp;
+ size_t oldn, newn;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ err(1, "opening '%s' for reading.", filename);
+
+ newn = fread(newb, 1, sizeof (newb), fp);
+ if (feof(fp) == 0)
+ err(1, "parameters too large");
+
+ if (fclose(fp) != 0)
+ err(1, "closing file.");
+
+ oldn = 0;
+ error = sysctlbyname("net.inet6.send.cga_parameters", NULL, NULL, newb,
+ newn);
+ if (error != 0)
+ err(1, "sysctlbyname");
+}
diff --git a/network_cmds/netstat.tproj/DERIVED_FILES b/network_cmds/netstat.tproj/DERIVED_FILES
new file mode 100644
index 0000000..a4fa6c9
--- /dev/null
+++ b/network_cmds/netstat.tproj/DERIVED_FILES
@@ -0,0 +1 @@
+unix/bsd/netiso/tp_astring.c
diff --git a/network_cmds/netstat.tproj/data.c b/network_cmds/netstat.tproj/data.c
new file mode 100644
index 0000000..9e0bbe2
--- /dev/null
+++ b/network_cmds/netstat.tproj/data.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* NeXT */
+#ifndef EXTERN
+#define EXTERN
+#endif
+#include "netstat.h"
diff --git a/network_cmds/netstat.tproj/if.c b/network_cmds/netstat.tproj/if.c
new file mode 100644
index 0000000..2fe6182
--- /dev/null
+++ b/network_cmds/netstat.tproj/if.c
@@ -0,0 +1,2259 @@
+/*
+ * Copyright (c) 2008-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/kern_control.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_mib.h>
+#include <net/if_llreach.h>
+#include <net/ethernet.h>
+#include <net/route.h>
+#include <net/ntstat.h>
+
+#include <net/pktsched/pktsched.h>
+#include <net/classq/if_classq.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+
+#include <arpa/inet.h>
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <assert.h>
+
+#include "netstat.h"
+
+#define YES 1
+#define NO 0
+
+#define ROUNDUP(a, size) (((a) & ((size) - 1)) ? (1 + ((a)|(size - 1))) : (a))
+
+#define NEXT_SA(p) (struct sockaddr *) \
+ ((caddr_t)p + (p->sa_len ? ROUNDUP(p->sa_len, sizeof(uint32_t)) : \
+ sizeof(uint32_t)))
+
+static void sidewaysintpr ();
+static void catchalarm (int);
+static char *sec2str(time_t);
+static void llreach_sysctl(uint32_t);
+static char *nsec_to_str(unsigned long long);
+static char *sched2str(unsigned int);
+static char *pri2str(unsigned int i);
+
+#define AVGN_MAX 8
+
+struct queue_stats {
+ int avgn;
+ double avg_bytes;
+ double avg_packets;
+ u_int64_t prev_bytes;
+ u_int64_t prev_packets;
+ unsigned int handle;
+};
+
+static void update_avg(struct if_ifclassq_stats *, struct queue_stats *);
+static void print_fq_codel_stats(int slot, struct fq_codel_classstats *,
+ struct queue_stats *);
+
+struct queue_stats qstats[IFCQ_SC_MAX];
+
+#ifdef INET6
+char *netname6 (struct sockaddr_in6 *, struct sockaddr *);
+static char ntop_buf[INET6_ADDRSTRLEN]; /* for inet_ntop() */
+#endif
+
+/*
+ * Display a formatted value, or a '-' in the same space.
+ */
+static void
+show_stat(const char *fmt, int width, u_int64_t value, short showvalue)
+{
+ char newfmt[32];
+
+ /* Construct the format string */
+ if (showvalue) {
+ snprintf(newfmt, sizeof(newfmt), "%%%d%s", width, fmt);
+ printf(newfmt, value);
+ } else {
+ snprintf(newfmt, sizeof(newfmt), "%%%ds", width);
+ printf(newfmt, "-");
+ }
+}
+
+size_t
+get_rti_info(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+ size_t len = 0;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ if (sa->sa_len < sizeof(struct sockaddr))
+ len += sizeof(struct sockaddr);
+ else
+ len += sa->sa_len;
+ sa = NEXT_SA(sa);
+ } else {
+ rti_info[i] = NULL;
+ }
+ }
+ return len;
+}
+
+static void
+multipr(int family, char *buf, char *lim)
+{
+ char *next;
+
+ for (next = buf; next < lim; ) {
+ struct ifma_msghdr2 *ifmam = (struct ifma_msghdr2 *)next;
+ struct sockaddr *rti_info[RTAX_MAX];
+ struct sockaddr *sa;
+ const char *fmt = 0;
+
+ next += ifmam->ifmam_msglen;
+ if (ifmam->ifmam_type == RTM_IFINFO2)
+ break;
+ else if (ifmam->ifmam_type != RTM_NEWMADDR2)
+ continue;
+ get_rti_info(ifmam->ifmam_addrs, (struct sockaddr*)(ifmam + 1), rti_info);
+ sa = rti_info[RTAX_IFA];
+
+ if (sa->sa_family != family)
+ continue;
+ switch (sa->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ fmt = routename(sin->sin_addr.s_addr);
+ break;
+ }
+ #ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 sin6;
+
+ memcpy(&sin6, sa, sizeof(struct sockaddr_in6));
+
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) {
+ sin6.sin6_scope_id = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+
+ printf("%23s %-19.19s(refs: %d)\n", "",
+ inet_ntop(AF_INET6, &sin6.sin6_addr,
+ ntop_buf, sizeof(ntop_buf)),
+ ifmam->ifmam_refcount);
+ break;
+ }
+ #endif /* INET6 */
+ case AF_LINK: {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ case IFT_FDDI:
+ fmt = ether_ntoa((struct ether_addr *)
+ LLADDR(sdl));
+ break;
+ }
+ break;
+ }
+ }
+ if (fmt)
+ printf("%23s %s\n", "", fmt);
+ }
+}
+
+/*
+ * Print a description of the network interfaces.
+ */
+void
+intpr(void (*pfunc)(char *))
+{
+ u_int64_t opackets = 0;
+ u_int64_t ipackets = 0;
+ u_int64_t obytes = 0;
+ u_int64_t ibytes = 0;
+ u_int64_t oerrors = 0;
+ u_int64_t ierrors = 0;
+ u_int64_t collisions = 0;
+ u_int64_t fpackets = 0;
+ u_int64_t fbytes = 0;
+ uint32_t mtu = 0;
+ int timer = 0;
+ int drops = 0;
+ struct sockaddr *sa = NULL;
+ char name[32];
+ short network_layer;
+ short link_layer;
+ int mib[6];
+ char *buf = NULL, *lim, *next;
+ size_t len;
+ struct if_msghdr *ifm;
+ struct sockaddr *rti_info[RTAX_MAX];
+ unsigned int ifindex = 0;
+
+ if (interval) {
+ sidewaysintpr();
+ return;
+ }
+
+ if (interface != 0)
+ ifindex = if_nametoindex(interface);
+
+ mib[0] = CTL_NET; // networking subsystem
+ mib[1] = PF_ROUTE; // type of information
+ mib[2] = 0; // protocol (IPPROTO_xxx)
+ mib[3] = 0; // address family
+ mib[4] = NET_RT_IFLIST2; // operation
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return;
+ if ((buf = malloc(len)) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ if (buf)
+ free(buf);
+ return;
+ }
+
+ if (!pfunc) {
+ if (lflag) {
+ printf("%-10.10s %-5.5s %-39.39s %-39.39s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ } else {
+ printf("%-10.10s %-5.5s %-13.13s %-15.15s %8.8s %5.5s",
+ "Name", "Mtu", "Network", "Address", "Ipkts", "Ierrs");
+ }
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Itcpkts", "Ipvpkts");
+ if (bflag) {
+ printf(" %10.10s","Ibytes");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Itcbytes", "Ipvbytes");
+ }
+ printf(" %8.8s %5.5s", "Opkts", "Oerrs");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Otcpkts", "Opvpkts");
+ if (bflag) {
+ printf(" %10.10s","Obytes");
+ if (prioflag >= 0)
+ printf(" %8.8s %8.8s", "Otcbytes", "Opvbytes");
+ }
+ printf(" %5s", "Coll");
+ if (tflag)
+ printf(" %s", "Time");
+ if (dflag)
+ printf(" %s", "Drop");
+ if (Fflag) {
+ printf(" %8.8s", "Fpkts");
+ if (bflag)
+ printf(" %10.10s", "Fbytes");
+ }
+ putchar('\n');
+ }
+ lim = buf + len;
+ for (next = buf; next < lim; ) {
+ char *cp;
+ int n, m;
+ struct ifmibdata_supplemental ifmsupp;
+ u_int64_t ift_itcp = 0; /* input tc packets */
+ u_int64_t ift_itcb = 0; /* input tc bytes */
+ u_int64_t ift_otcp = 0; /* output tc packets */
+ u_int64_t ift_otcb = 0; /* output tc bytes */
+ u_int64_t ift_ipvp = 0; /* input priv tc packets */
+ u_int64_t ift_ipvb = 0; /* input priv tc bytes */
+ u_int64_t ift_opvp = 0; /* output priv tc packets */
+ u_int64_t ift_opvb = 0; /* output priv tc bytes */
+
+ bzero(&ifmsupp, sizeof(struct ifmibdata_supplemental));
+
+ network_layer = 0;
+ link_layer = 0;
+ ifm = (struct if_msghdr *)next;
+ next += ifm->ifm_msglen;
+
+ if (ifm->ifm_type == RTM_IFINFO2) {
+ struct if_msghdr2 *if2m = (struct if_msghdr2 *)ifm;
+ struct sockaddr_dl *sdl =
+ (struct sockaddr_dl *)(if2m + 1);
+ int mibname[6];
+ size_t miblen = sizeof(struct ifmibdata_supplemental);
+
+ if (interface != 0 && if2m->ifm_index != ifindex)
+ continue;
+
+ /* The interface name is not a zero-ended string */
+ memcpy(name, sdl->sdl_data, MIN(sizeof(name) - 1, sdl->sdl_nlen));
+ name[MIN(sizeof(name) - 1, sdl->sdl_nlen)] = 0;
+
+ if (pfunc) {
+ (*pfunc)(name);
+ continue;
+ }
+
+ cp = index(name, '\0');
+ if ((if2m->ifm_flags & IFF_UP) == 0)
+ *cp++ = '*';
+ *cp = '\0';
+
+ /*
+ * Get the interface stats. These may get
+ * overriden below on a per-interface basis.
+ */
+ opackets = if2m->ifm_data.ifi_opackets;
+ ipackets = if2m->ifm_data.ifi_ipackets;
+ obytes = if2m->ifm_data.ifi_obytes;
+ ibytes = if2m->ifm_data.ifi_ibytes;
+ oerrors =if2m->ifm_data.ifi_oerrors;
+ ierrors = if2m->ifm_data.ifi_ierrors;
+ collisions = if2m->ifm_data.ifi_collisions;
+ timer = if2m->ifm_timer;
+ drops = if2m->ifm_snd_drops;
+ mtu = if2m->ifm_data.ifi_mtu;
+
+ /* Common OID prefix */
+ mibname[0] = CTL_NET;
+ mibname[1] = PF_LINK;
+ mibname[2] = NETLINK_GENERIC;
+ mibname[3] = IFMIB_IFDATA;
+ mibname[4] = if2m->ifm_index;
+ mibname[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(mibname, 6, &ifmsupp, &miblen, NULL, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+ fpackets = ifmsupp.ifmd_data_extended.ifi_fpackets;
+ fbytes = ifmsupp.ifmd_data_extended.ifi_fbytes;
+
+ if (prioflag >= 0) {
+ switch (prioflag) {
+ case SO_TC_BE:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibepackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibebytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obepackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_obkpackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivipackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivibytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovipackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ ift_itcp = ifmsupp.ifmd_traffic_class.ifi_ivopackets;
+ ift_itcb = ifmsupp.ifmd_traffic_class.ifi_ivobytes;
+ ift_otcp = ifmsupp.ifmd_traffic_class.ifi_ovopackets;
+ ift_otcb = ifmsupp.ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ ift_itcp = 0;
+ ift_itcb = 0;
+ ift_otcp = 0;
+ ift_otcb = 0;
+ ift_ipvp = 0;
+ ift_ipvb = 0;
+ ift_opvp = 0;
+ ift_opvb = 0;
+ break;
+ }
+ ift_ipvp = ifmsupp.ifmd_traffic_class.ifi_ipvpackets;
+ ift_ipvb = ifmsupp.ifmd_traffic_class.ifi_ipvbytes;
+ ift_opvp = ifmsupp.ifmd_traffic_class.ifi_opvpackets;
+ ift_opvb = ifmsupp.ifmd_traffic_class.ifi_opvbytes;
+ }
+
+ get_rti_info(if2m->ifm_addrs,
+ (struct sockaddr*)(if2m + 1), rti_info);
+ sa = rti_info[RTAX_IFP];
+ } else if (ifm->ifm_type == RTM_NEWADDR) {
+ struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
+
+ if (interface != 0 && ifam->ifam_index != ifindex)
+ continue;
+ get_rti_info(ifam->ifam_addrs,
+ (struct sockaddr*)(ifam + 1), rti_info);
+ sa = rti_info[RTAX_IFA];
+ } else {
+ continue;
+ }
+ if (lflag) {
+ printf("%-10.10s %-5u ", name, mtu);
+ } else {
+ printf("%-5.5s %-5u ", name, mtu);
+ }
+
+ if (sa == 0) {
+ printf(lflag ? "%-39.39s " : "%-13.13s ", "none");
+ printf(lflag ? "%-39.39s " : "%-15.15s ", "none");
+ } else {
+ switch (sa->sa_family) {
+ case AF_UNSPEC:
+ printf(lflag ? "%-39.39s " : "%-13.13s ", "none");
+ printf(lflag ? "%-39.39s " : "%-15.15s ", "none");
+ break;
+
+ case AF_INET: {
+ struct sockaddr_in *sin =
+ (struct sockaddr_in *)sa;
+ struct sockaddr_in mask;
+
+ mask.sin_addr.s_addr = 0;
+ memcpy(&mask, rti_info[RTAX_NETMASK],
+ ((struct sockaddr_in *)
+ rti_info[RTAX_NETMASK])->sin_len);
+
+ printf(lflag ? "%-39.39s " : "%-13.13s ",
+ netname(sin->sin_addr.s_addr &
+ mask.sin_addr.s_addr,
+ ntohl(mask.sin_addr.s_addr)));
+
+ printf(lflag ? "%-39.39s " : "%-15.15s ",
+ routename(sin->sin_addr.s_addr));
+
+ network_layer = 1;
+ break;
+ }
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 =
+ (struct sockaddr_in6 *)sa;
+ struct sockaddr *mask =
+ (struct sockaddr *)rti_info[RTAX_NETMASK];
+
+ printf(lflag ? "%-39.39s " : "%-11.11s ", netname6(sin6, mask));
+ printf(lflag ? "%-39.39s " : "%-17.17s ", (char *)inet_ntop(AF_INET6,
+ &sin6->sin6_addr, ntop_buf,
+ sizeof(ntop_buf)));
+
+ network_layer = 1;
+ break;
+ }
+#endif /*INET6*/
+ case AF_LINK: {
+ struct sockaddr_dl *sdl =
+ (struct sockaddr_dl *)sa;
+ char linknum[10];
+ cp = (char *)LLADDR(sdl);
+ n = sdl->sdl_alen;
+ snprintf(linknum, sizeof(linknum),
+ "<Link#%d>", sdl->sdl_index);
+ m = printf(lflag ? "%-39.39s " : "%-11.11s ", linknum);
+ goto hexprint;
+ }
+
+ default:
+ m = printf("(%d)", sa->sa_family);
+ for (cp = sa->sa_len + (char *)sa;
+ --cp > sa->sa_data && (*cp == 0);) {}
+ n = cp - sa->sa_data + 1;
+ cp = sa->sa_data;
+ hexprint:
+ while (--n >= 0)
+ m += printf("%02x%c", *cp++ & 0xff,
+ n > 0 ? ':' : ' ');
+ m = (lflag ? 80 : 30) - m;
+ while (m-- > 0)
+ putchar(' ');
+
+ link_layer = 1;
+ break;
+ }
+ }
+
+ show_stat("llu", 8, ipackets, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 5, ierrors, link_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_itcp, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_ipvp, link_layer|network_layer);
+ printf(" ");
+ }
+ if (bflag) {
+ show_stat("llu", 10, ibytes, link_layer|network_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_itcb, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_ipvb, link_layer|network_layer);
+ printf(" ");
+ }
+ }
+ show_stat("llu", 8, opackets, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 5, oerrors, link_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_otcp, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_opvp, link_layer|network_layer);
+ printf(" ");
+ }
+ if (bflag) {
+ show_stat("llu", 10, obytes, link_layer|network_layer);
+ printf(" ");
+ if (prioflag >= 0) {
+ show_stat("llu", 8, ift_otcb, link_layer|network_layer);
+ printf(" ");
+ show_stat("llu", 8, ift_opvb, link_layer|network_layer);
+ printf(" ");
+ }
+ }
+ show_stat("llu", 5, collisions, link_layer);
+ if (tflag) {
+ printf(" ");
+ show_stat("d", 3, timer, link_layer);
+ }
+ if (dflag) {
+ printf(" ");
+ show_stat("d", 3, drops, link_layer);
+ }
+ if (Fflag) {
+ printf(" ");
+ show_stat("llu", 8, fpackets, link_layer|network_layer);
+ if (bflag) {
+ printf(" ");
+ show_stat("llu", 10, fbytes,
+ link_layer|network_layer);
+ }
+ }
+ putchar('\n');
+
+ if (aflag)
+ multipr(sa->sa_family, next, lim);
+ }
+ free(buf);
+}
+
+struct iftot {
+ SLIST_ENTRY(iftot) chain;
+ char ift_name[16]; /* interface name */
+ u_int64_t ift_ip; /* input packets */
+ u_int64_t ift_ie; /* input errors */
+ u_int64_t ift_op; /* output packets */
+ u_int64_t ift_oe; /* output errors */
+ u_int64_t ift_co; /* collisions */
+ u_int64_t ift_dr; /* drops */
+ u_int64_t ift_ib; /* input bytes */
+ u_int64_t ift_ob; /* output bytes */
+ u_int64_t ift_itcp; /* input tc packets */
+ u_int64_t ift_itcb; /* input tc bytes */
+ u_int64_t ift_otcp; /* output tc packets */
+ u_int64_t ift_otcb; /* output tc bytes */
+ u_int64_t ift_ipvp; /* input priv tc packets */
+ u_int64_t ift_ipvb; /* input priv tc bytes */
+ u_int64_t ift_opvp; /* output priv tc packets */
+ u_int64_t ift_opvb; /* output priv tc bytes */
+ u_int64_t ift_fp; /* forwarded packets */
+ u_int64_t ift_fb; /* forwarded bytes */
+};
+
+u_char signalled; /* set if alarm goes off "early" */
+
+/*
+ * Print a running summary of interface statistics.
+ * Repeat display every interval seconds, showing statistics
+ * collected over that interval. Assumes that interval is non-zero.
+ * First line printed at top of screen is always cumulative.
+ * XXX - should be rewritten to use ifmib(4).
+ */
+static void
+sidewaysintpr()
+{
+ struct iftot *total, *sum, *interesting;
+ register int line;
+ int first;
+ int name[6];
+ size_t len;
+ unsigned int ifcount, i;
+ struct ifmibdata *ifmdall = 0;
+ int interesting_row;
+ sigset_t sigset, oldsigset;
+ struct itimerval timer_interval;
+
+ /* Common OID prefix */
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+
+ len = sizeof(int);
+ name[3] = IFMIB_SYSTEM;
+ name[4] = IFMIB_IFCOUNT;
+ if (sysctl(name, 5, &ifcount, &len, 0, 0) == 1)
+ err(1, "sysctl IFMIB_IFCOUNT");
+
+ len = ifcount * sizeof(struct ifmibdata);
+ ifmdall = malloc(len);
+ if (ifmdall == 0)
+ err(1, "malloc failed");
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA");
+
+ interesting = NULL;
+ interesting_row = 0;
+ for (i = 0; i < ifcount; i++) {
+ struct ifmibdata *ifmd = ifmdall + i;
+
+ if (interface && strcmp(ifmd->ifmd_name, interface) == 0) {
+ if ((interesting = calloc(ifcount,
+ sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+ interesting_row = if_nametoindex(interface);
+ snprintf(interesting->ift_name, 16, "(%s)",
+ ifmd->ifmd_name);;
+ }
+ }
+ if ((total = calloc(1, sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+
+ if ((sum = calloc(1, sizeof(struct iftot))) == NULL)
+ err(1, "malloc failed");
+
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void)signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void)setitimer(ITIMER_REAL, &timer_interval, NULL);
+ first = 1;
+banner:
+ if (vflag > 0)
+ printf("%9s", " ");
+
+ if (prioflag >= 0)
+ printf("%39s %39s %36s", "input",
+ interesting ? interesting->ift_name : "(Total)", "output");
+ else
+ printf("%17s %14s %16s", "input",
+ interesting ? interesting->ift_name : "(Total)", "output");
+ putchar('\n');
+
+ if (vflag > 0)
+ printf("%9s", " ");
+
+ printf("%10s %5s %10s ", "packets", "errs", "bytes");
+ if (prioflag >= 0)
+ printf(" %10s %10s %10s %10s",
+ "tcpkts", "tcbytes", "pvpkts", "pvbytes");
+ printf("%10s %5s %10s %5s", "packets", "errs", "bytes", "colls");
+ if (dflag)
+ printf(" %5.5s", "drops");
+ if (prioflag >= 0)
+ printf(" %10s %10s %10s %10s",
+ "tcpkts", "tcbytes", "pvpkts", "pvbytes");
+ if (Fflag)
+ printf(" %10s %10s", "fpackets", "fbytes");
+ putchar('\n');
+ fflush(stdout);
+ line = 0;
+loop:
+ if (vflag && !first)
+ print_time();
+
+ if (interesting != NULL) {
+ struct ifmibdata ifmd;
+ struct ifmibdata_supplemental ifmsupp;
+
+ len = sizeof(struct ifmibdata);
+ name[3] = IFMIB_IFDATA;
+ name[4] = interesting_row;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, &ifmd, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFDATA_GENERAL %d", interesting_row);
+
+ len = sizeof(struct ifmibdata_supplemental);
+ name[3] = IFMIB_IFDATA;
+ name[4] = interesting_row;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, &ifmsupp, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL %d",
+ interesting_row);
+
+ if (!first) {
+ printf("%10llu %5llu %10llu ",
+ ifmd.ifmd_data.ifi_ipackets - interesting->ift_ip,
+ ifmd.ifmd_data.ifi_ierrors - interesting->ift_ie,
+ ifmd.ifmd_data.ifi_ibytes - interesting->ift_ib);
+ switch (prioflag) {
+ case SO_TC_BE:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ibepackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ibebytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_BK:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ibkpackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ibkbytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_VI:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ivipackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ivibytes -
+ interesting->ift_itcb);
+ break;
+ case SO_TC_VO:
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ivopackets -
+ interesting->ift_itcp,
+ ifmsupp.ifmd_traffic_class.ifi_ivobytes -
+ interesting->ift_itcb);
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_ipvpackets -
+ interesting->ift_ipvp,
+ ifmsupp.ifmd_traffic_class.ifi_ipvbytes -
+ interesting->ift_ipvb);
+ }
+ printf("%10llu %5llu %10llu %5llu",
+ ifmd.ifmd_data.ifi_opackets - interesting->ift_op,
+ ifmd.ifmd_data.ifi_oerrors - interesting->ift_oe,
+ ifmd.ifmd_data.ifi_obytes - interesting->ift_ob,
+ ifmd.ifmd_data.ifi_collisions - interesting->ift_co);
+ if (dflag)
+ printf(" %5llu",
+ ifmd.ifmd_snd_drops - interesting->ift_dr);
+ switch (prioflag) {
+ case SO_TC_BE:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_obepackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_obebytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_BK:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_obkpackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_obkbytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_VI:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_ovipackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_ovibytes -
+ interesting->ift_otcb);
+ break;
+ case SO_TC_VO:
+ printf(" %10llu %10llu",
+ ifmsupp.ifmd_traffic_class.ifi_ovopackets -
+ interesting->ift_otcp,
+ ifmsupp.ifmd_traffic_class.ifi_ovobytes -
+ interesting->ift_otcb);
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ printf("%10llu %10llu ",
+ ifmsupp.ifmd_traffic_class.ifi_opvpackets -
+ interesting->ift_opvp,
+ ifmsupp.ifmd_traffic_class.ifi_opvbytes -
+ interesting->ift_opvb);
+ }
+ if (Fflag) {
+ printf("%10llu %10llu",
+ ifmsupp.ifmd_data_extended.ifi_fpackets -
+ interesting->ift_fp,
+ ifmsupp.ifmd_data_extended.ifi_fbytes -
+ interesting->ift_fb);
+ }
+ }
+ interesting->ift_ip = ifmd.ifmd_data.ifi_ipackets;
+ interesting->ift_ie = ifmd.ifmd_data.ifi_ierrors;
+ interesting->ift_ib = ifmd.ifmd_data.ifi_ibytes;
+ interesting->ift_op = ifmd.ifmd_data.ifi_opackets;
+ interesting->ift_oe = ifmd.ifmd_data.ifi_oerrors;
+ interesting->ift_ob = ifmd.ifmd_data.ifi_obytes;
+ interesting->ift_co = ifmd.ifmd_data.ifi_collisions;
+ interesting->ift_dr = ifmd.ifmd_snd_drops;
+
+ /* private counters */
+ switch (prioflag) {
+ case SO_TC_BE:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ibepackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ibebytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_obepackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ibkpackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ibkbytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_obkpackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ivipackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ivibytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_ovipackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ interesting->ift_itcp =
+ ifmsupp.ifmd_traffic_class.ifi_ivopackets;
+ interesting->ift_itcb =
+ ifmsupp.ifmd_traffic_class.ifi_ivobytes;
+ interesting->ift_otcp =
+ ifmsupp.ifmd_traffic_class.ifi_ovopackets;
+ interesting->ift_otcb =
+ ifmsupp.ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ break;
+ }
+ if (prioflag >= 0) {
+ interesting->ift_ipvp =
+ ifmsupp.ifmd_traffic_class.ifi_ipvpackets;
+ interesting->ift_ipvb =
+ ifmsupp.ifmd_traffic_class.ifi_ipvbytes;
+ interesting->ift_opvp =
+ ifmsupp.ifmd_traffic_class.ifi_opvpackets;
+ interesting->ift_opvb =
+ ifmsupp.ifmd_traffic_class.ifi_opvbytes;
+ }
+ interesting->ift_fp = ifmsupp.ifmd_data_extended.ifi_fpackets;
+ interesting->ift_fb = ifmsupp.ifmd_data_extended.ifi_fbytes;
+ } else {
+ unsigned int latest_ifcount;
+ struct ifmibdata_supplemental *ifmsuppall = NULL;
+
+ len = sizeof(int);
+ name[3] = IFMIB_SYSTEM;
+ name[4] = IFMIB_IFCOUNT;
+ if (sysctl(name, 5, &latest_ifcount, &len, 0, 0) == 1)
+ err(1, "sysctl IFMIB_IFCOUNT");
+ if (latest_ifcount > ifcount) {
+ ifcount = latest_ifcount;
+ len = ifcount * sizeof(struct ifmibdata);
+ free(ifmdall);
+ ifmdall = malloc(len);
+ if (ifmdall == 0)
+ err(1, "malloc ifmdall failed");
+ } else if (latest_ifcount > ifcount) {
+ ifcount = latest_ifcount;
+ len = ifcount * sizeof(struct ifmibdata);
+ }
+ len = ifcount * sizeof(struct ifmibdata);
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_GENERAL;
+ if (sysctl(name, 6, ifmdall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA");
+
+ len = ifcount * sizeof(struct ifmibdata_supplemental);
+ ifmsuppall = malloc(len);
+ if (ifmsuppall == NULL)
+ err(1, "malloc ifmsuppall failed");
+ name[3] = IFMIB_IFALLDATA;
+ name[4] = 0;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, ifmsuppall, &len, (void *)0, 0) == -1)
+ err(1, "sysctl IFMIB_IFALLDATA SUPPLEMENTAL");
+
+ sum->ift_ip = 0;
+ sum->ift_ie = 0;
+ sum->ift_ib = 0;
+ sum->ift_op = 0;
+ sum->ift_oe = 0;
+ sum->ift_ob = 0;
+ sum->ift_co = 0;
+ sum->ift_dr = 0;
+ sum->ift_itcp = 0;
+ sum->ift_itcb = 0;
+ sum->ift_otcp = 0;
+ sum->ift_otcb = 0;
+ sum->ift_ipvp = 0;
+ sum->ift_ipvb = 0;
+ sum->ift_opvp = 0;
+ sum->ift_opvb = 0;
+ sum->ift_fp = 0;
+ sum->ift_fb = 0;
+ for (i = 0; i < ifcount; i++) {
+ struct ifmibdata *ifmd = ifmdall + i;
+ struct ifmibdata_supplemental *ifmsupp = ifmsuppall + i;
+
+ sum->ift_ip += ifmd->ifmd_data.ifi_ipackets;
+ sum->ift_ie += ifmd->ifmd_data.ifi_ierrors;
+ sum->ift_ib += ifmd->ifmd_data.ifi_ibytes;
+ sum->ift_op += ifmd->ifmd_data.ifi_opackets;
+ sum->ift_oe += ifmd->ifmd_data.ifi_oerrors;
+ sum->ift_ob += ifmd->ifmd_data.ifi_obytes;
+ sum->ift_co += ifmd->ifmd_data.ifi_collisions;
+ sum->ift_dr += ifmd->ifmd_snd_drops;
+ /* private counters */
+ if (prioflag >= 0) {
+ switch (prioflag) {
+ case SO_TC_BE:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibepackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibebytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obepackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obebytes;
+ break;
+ case SO_TC_BK:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ibkpackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ibkbytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_obkpackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_obkbytes;
+ break;
+ case SO_TC_VI:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivipackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivibytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovipackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovibytes;
+ break;
+ case SO_TC_VO:
+ sum->ift_itcp += ifmsupp->ifmd_traffic_class.ifi_ivopackets;
+ sum->ift_itcb += ifmsupp->ifmd_traffic_class.ifi_ivobytes;
+ sum->ift_otcp += ifmsupp->ifmd_traffic_class.ifi_ovopackets;
+ sum->ift_otcb += ifmsupp->ifmd_traffic_class.ifi_ovobytes;
+ break;
+ default:
+ break;
+ }
+ sum->ift_ipvp += ifmsupp->ifmd_traffic_class.ifi_ipvpackets;
+ sum->ift_ipvb += ifmsupp->ifmd_traffic_class.ifi_ipvbytes;
+ sum->ift_opvp += ifmsupp->ifmd_traffic_class.ifi_opvpackets;
+ sum->ift_opvb += ifmsupp->ifmd_traffic_class.ifi_opvbytes;
+ }
+ sum->ift_fp += ifmsupp->ifmd_data_extended.ifi_fpackets;
+ sum->ift_fb += ifmsupp->ifmd_data_extended.ifi_fbytes;
+ }
+ if (!first) {
+ printf("%10llu %5llu %10llu ",
+ sum->ift_ip - total->ift_ip,
+ sum->ift_ie - total->ift_ie,
+ sum->ift_ib - total->ift_ib);
+ if (prioflag >= 0)
+ printf(" %10llu %10llu %10llu %10llu",
+ sum->ift_itcp - total->ift_itcp,
+ sum->ift_itcb - total->ift_itcb,
+ sum->ift_ipvp - total->ift_ipvp,
+ sum->ift_ipvb - total->ift_ipvb);
+ printf("%10llu %5llu %10llu %5llu",
+ sum->ift_op - total->ift_op,
+ sum->ift_oe - total->ift_oe,
+ sum->ift_ob - total->ift_ob,
+ sum->ift_co - total->ift_co);
+ if (dflag)
+ printf(" %5llu", sum->ift_dr - total->ift_dr);
+ if (prioflag >= 0)
+ printf(" %10llu %10llu %10llu %10llu",
+ sum->ift_otcp - total->ift_otcp,
+ sum->ift_otcb - total->ift_otcb,
+ sum->ift_opvp - total->ift_opvp,
+ sum->ift_opvb - total->ift_opvb);
+ if (Fflag)
+ printf(" %10llu %10llu",
+ sum->ift_fp - total->ift_fp,
+ sum->ift_fb - total->ift_fb);
+ }
+ *total = *sum;
+
+ free(ifmsuppall);
+ }
+ if (!first)
+ putchar('\n');
+ fflush(stdout);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void)sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void)sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ line++;
+ first = 0;
+ if (line == 21)
+ goto banner;
+ else
+ goto loop;
+ /*NOTREACHED*/
+}
+
+void
+intervalpr(void (*pr)(uint32_t, char *, int), uint32_t off, char *name , int af)
+{
+ struct itimerval timer_interval;
+ sigset_t sigset, oldsigset;
+
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+
+ for (;;) {
+ pr(off, name, af);
+
+ fflush(stdout);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ signalled = NO;
+ }
+}
+
+/*
+ * Called if an interval expires before sidewaysintpr has completed a loop.
+ * Sets a flag to not wait for the alarm.
+ */
+static void
+catchalarm(int signo )
+{
+ signalled = YES;
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+
+ return(result);
+}
+
+void
+intpr_ri(void (*pfunc)(char *))
+{
+ int mib[6];
+ char *buf = NULL, *lim, *next;
+ size_t len;
+ unsigned int ifindex = 0;
+ struct if_msghdr2 *if2m;
+
+ if (interface != 0) {
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ printf("interface name is not valid: %s\n", interface);
+ exit(1);
+ }
+ }
+
+ mib[0] = CTL_NET; /* networking subsystem */
+ mib[1] = PF_ROUTE; /* type of information */
+ mib[2] = 0; /* protocol (IPPROTO_xxx) */
+ mib[3] = 0; /* address family */
+ mib[4] = NET_RT_IFLIST2; /* operation */
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return;
+ if ((buf = malloc(len)) == NULL) {
+ printf("malloc failed\n");
+ exit(1);
+ }
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ free(buf);
+ return;
+ }
+
+ printf("%-6s %-17s %8.8s %-9.9s %4s %4s",
+ "Proto", "Linklayer Address", "Netif", "Expire", "Refs",
+ "Prbs");
+ if (xflag)
+ printf(" %7s %7s %7s", "RSSI", "LQM", "NPM");
+ printf("\n");
+
+ lim = buf + len;
+ if2m = (struct if_msghdr2 *)buf;
+
+ for (next = buf; next < lim; ) {
+ if2m = (struct if_msghdr2 *)next;
+ next += if2m->ifm_msglen;
+
+ if (if2m->ifm_type != RTM_IFINFO2)
+ continue;
+ else if (interface != 0 && if2m->ifm_index != ifindex)
+ continue;
+
+ llreach_sysctl(if2m->ifm_index);
+ }
+ free(buf);
+}
+
+static void
+llreach_sysctl(uint32_t ifindex)
+{
+#define MAX_SYSCTL_TRY 5
+ int mib[6], i, ntry = 0;
+ size_t mibsize, len, needed, cnt;
+ struct if_llreach_info *lri;
+ struct timeval time;
+ char *buf;
+ char ifname[IF_NAMESIZE];
+
+ bzero(&mib, sizeof (mib));
+ mibsize = sizeof (mib) / sizeof (mib[0]);
+ if (sysctlnametomib("net.link.generic.system.llreach_info", mib,
+ &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+
+ mibsize = sizeof (mib) / sizeof (mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.link.generic.system.llreach_info");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ cnt = len / sizeof (*lri);
+ lri = (struct if_llreach_info *)buf;
+
+ gettimeofday(&time, 0);
+ if (if_indextoname(ifindex, ifname) == NULL)
+ snprintf(ifname, sizeof (ifname), "%s", "?");
+
+ for (i = 0; i < cnt; i++, lri++) {
+ printf("0x%-4x %-17s %8.8s ", lri->lri_proto,
+ ether_ntoa((struct ether_addr *)lri->lri_addr), ifname);
+
+ if (lri->lri_expire > time.tv_sec)
+ printf("%-9.9s", sec2str(lri->lri_expire - time.tv_sec));
+ else if (lri->lri_expire == 0)
+ printf("%-9.9s", "permanent");
+ else
+ printf("%-9.9s", "expired");
+
+ printf(" %4d", lri->lri_refcnt);
+ if (lri->lri_probes)
+ printf(" %4d", lri->lri_probes);
+
+ if (xflag) {
+ if (!lri->lri_probes)
+ printf(" %-4.4s", "none");
+
+ if (lri->lri_rssi != IFNET_RSSI_UNKNOWN)
+ printf(" %7d", lri->lri_rssi);
+ else
+ printf(" %-7.7s", "unknown");
+
+ switch (lri->lri_lqm)
+ {
+ case IFNET_LQM_THRESH_OFF:
+ printf(" %-7.7s", "off");
+ break;
+ case IFNET_LQM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_LQM_THRESH_POOR:
+ printf(" %-7.7s", "poor");
+ break;
+ case IFNET_LQM_THRESH_GOOD:
+ printf(" %-7.7s", "good");
+ break;
+ default:
+ printf(" %7d", lri->lri_lqm);
+ break;
+ }
+
+ switch (lri->lri_npm)
+ {
+ case IFNET_NPM_THRESH_UNKNOWN:
+ printf(" %-7.7s", "unknown");
+ break;
+ case IFNET_NPM_THRESH_NEAR:
+ printf(" %-7.7s", "near");
+ break;
+ case IFNET_NPM_THRESH_GENERAL:
+ printf(" %-7.7s", "general");
+ break;
+ case IFNET_NPM_THRESH_FAR:
+ printf(" %-7.7s", "far");
+ break;
+ default:
+ printf(" %7d", lri->lri_npm);
+ break;
+ }
+ }
+
+ printf("\n");
+ len -= sizeof (*lri);
+ }
+
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.link.generic.system.llreach_info");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+void
+aqstatpr(void)
+{
+ unsigned int ifindex;
+ struct itimerval timer_interval;
+ struct if_qstatsreq ifqr;
+ struct if_ifclassq_stats *ifcqs;
+ sigset_t sigset, oldsigset;
+ u_int32_t scheduler;
+ int s, n;
+
+ if (cq < -1 || cq >= IFCQ_SC_MAX) {
+ fprintf(stderr, "Invalid classq index (range is 0-%d)\n",
+ IFCQ_SC_MAX-1);
+ return;
+ }
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ ifcqs = malloc(sizeof (*ifcqs));
+ if (ifcqs == NULL) {
+ fprintf(stderr, "Unable to allocate memory\n");
+ return;
+ }
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET)");
+ free(ifcqs);
+ return;
+ }
+
+ bzero(&ifqr, sizeof (ifqr));
+ strlcpy(ifqr.ifqr_name, interface, sizeof (ifqr.ifqr_name));
+ ifqr.ifqr_buf = ifcqs;
+ ifqr.ifqr_len = sizeof (*ifcqs);
+
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ ifqr.ifqr_slot = 0;
+ if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
+ if (errno == ENXIO) {
+ printf("Queue statistics are not available on %s\n",
+ interface);
+ } else {
+ perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
+ }
+ goto done;
+ }
+ scheduler = ifcqs->ifqs_scheduler;
+
+ printf("%s:\n"
+ " [ sched: %9s qlength: %3d/%3d ]\n",
+ interface, sched2str(ifcqs->ifqs_scheduler),
+ ifcqs->ifqs_len, ifcqs->ifqs_maxlen);
+ printf(" [ pkts: %10llu bytes: %10llu "
+ " dropped pkts: %6llu bytes: %6llu ]\n",
+ ifcqs->ifqs_xmitcnt.packets, ifcqs->ifqs_xmitcnt.bytes,
+ ifcqs->ifqs_dropcnt.packets, ifcqs->ifqs_dropcnt.bytes);
+
+ for (n = 0; n < IFCQ_SC_MAX && scheduler != PKTSCHEDT_NONE; n++) {
+ if (cq >= 0 && cq != n)
+ continue;
+
+ ifqr.ifqr_slot = n;
+ if (ioctl(s, SIOCGIFQUEUESTATS, (char *)&ifqr) < 0) {
+ perror("Warning: ioctl(SIOCGIFQUEUESTATS)");
+ goto done;
+ }
+
+ update_avg(ifcqs, &qstats[n]);
+
+ switch (scheduler) {
+ case PKTSCHEDT_FQ_CODEL:
+ print_fq_codel_stats(n,
+ &ifcqs->ifqs_fq_codel_stats,
+ &qstats[n]);
+ break;
+ case PKTSCHEDT_NONE:
+ default:
+ break;
+ }
+ }
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+
+done:
+ free(ifcqs);
+ close(s);
+}
+
+static void
+print_fq_codel_stats(int pri, struct fq_codel_classstats *fqst,
+ struct queue_stats *qs)
+{
+ int i = 0;
+
+ if (fqst->fcls_service_class == 0 && fqst->fcls_pri == 0)
+ return;
+ printf("=====================================================\n");
+ printf(" [ pri: %s (%d)\tsrv_cl: 0x%x\tquantum: %d\tdrr_max: %d ]\n",
+ pri2str(fqst->fcls_pri), fqst->fcls_pri,
+ fqst->fcls_service_class, fqst->fcls_quantum,
+ fqst->fcls_drr_max);
+ printf(" [ queued pkts: %llu\tbytes: %llu ]\n",
+ fqst->fcls_pkt_cnt, fqst->fcls_byte_cnt);
+ printf(" [ dequeued pkts: %llu\tbytes: %llu ]\n",
+ fqst->fcls_dequeue, fqst->fcls_dequeue_bytes);
+ printf(" [ budget: %lld\ttarget qdelay: %10s\t",
+ fqst->fcls_budget, nsec_to_str(fqst->fcls_target_qdelay));
+ printf("update interval:%10s ]\n",
+ nsec_to_str(fqst->fcls_update_interval));
+ printf(" [ flow control: %u\tfeedback: %u\tstalls: %u\tfailed: %u ]\n",
+ fqst->fcls_flow_control, fqst->fcls_flow_feedback,
+ fqst->fcls_dequeue_stall, fqst->fcls_flow_control_fail);
+ printf(" [ drop overflow: %llu\tearly: %llu\tmemfail: %u\tduprexmt:%u ]\n",
+ fqst->fcls_drop_overflow, fqst->fcls_drop_early,
+ fqst->fcls_drop_memfailure, fqst->fcls_dup_rexmts);
+ printf(" [ flows total: %u\tnew: %u\told: %u ]\n",
+ fqst->fcls_flows_cnt,
+ fqst->fcls_newflows_cnt, fqst->fcls_oldflows_cnt);
+ printf(" [ throttle on: %u\toff: %u\tdrop: %u ]\n",
+ fqst->fcls_throttle_on, fqst->fcls_throttle_off,
+ fqst->fcls_throttle_drops);
+ printf(" [ compressible pkts: %u compressed pkts: %u]\n",
+ fqst->fcls_pkts_compressible, fqst->fcls_pkts_compressed);
+
+ if (qflag < 2)
+ return;
+
+ if (fqst->fcls_flowstats_cnt > 0) {
+ printf("Flowhash\tBytes\tMin qdelay\tFlags\t\n");
+ for (i = 0; i < fqst->fcls_flowstats_cnt; i++) {
+ printf("%u\t%u\t%14s\t",
+ fqst->fcls_flowstats[i].fqst_flowhash,
+ fqst->fcls_flowstats[i].fqst_bytes,
+ nsec_to_str(fqst->fcls_flowstats[i].fqst_min_qdelay));
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_OLD_FLOW)
+ printf("O");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_NEW_FLOW)
+ printf("N");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_LARGE_FLOW)
+ printf("L");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_DELAY_HIGH)
+ printf("D");
+ if (fqst->fcls_flowstats[i].fqst_flags &
+ FQ_FLOWSTATS_FLOWCTL_ON)
+ printf("F");
+ printf("\n");
+ }
+ }
+}
+
+static void
+update_avg(struct if_ifclassq_stats *ifcqs, struct queue_stats *qs)
+{
+ u_int64_t b, p;
+ int n;
+
+ n = qs->avgn;
+
+ switch (ifcqs->ifqs_scheduler) {
+ case PKTSCHEDT_FQ_CODEL:
+ b = ifcqs->ifqs_fq_codel_stats.fcls_dequeue_bytes;
+ p = ifcqs->ifqs_fq_codel_stats.fcls_dequeue;
+ break;
+ default:
+ b = 0;
+ p = 0;
+ break;
+ }
+
+ if (n == 0) {
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ qs->avgn++;
+ return;
+ }
+
+ if (b >= qs->prev_bytes)
+ qs->avg_bytes = ((qs->avg_bytes * (n - 1)) +
+ (b - qs->prev_bytes)) / n;
+
+ if (p >= qs->prev_packets)
+ qs->avg_packets = ((qs->avg_packets * (n - 1)) +
+ (p - qs->prev_packets)) / n;
+
+ qs->prev_bytes = b;
+ qs->prev_packets = p;
+ if (n < AVGN_MAX)
+ qs->avgn++;
+}
+
+#define NSEC_PER_SEC 1000000000 /* nanoseconds per second */
+#define USEC_PER_SEC 1000000 /* microseconds per second */
+#define MSEC_PER_SEC 1000 /* milliseconds per second */
+
+static char *
+nsec_to_str(unsigned long long nsec)
+{
+ static char buf[32];
+ const char *u;
+ long double n = nsec, t;
+
+ if (nsec >= NSEC_PER_SEC) {
+ t = n / NSEC_PER_SEC;
+ u = "sec ";
+ } else if (n >= USEC_PER_SEC) {
+ t = n / USEC_PER_SEC;
+ u = "msec";
+ } else if (n >= MSEC_PER_SEC) {
+ t = n / MSEC_PER_SEC;
+ u = "usec";
+ } else {
+ t = n;
+ u = "nsec";
+ }
+
+ snprintf(buf, sizeof (buf), "%-4.2Lf %4s", t, u);
+ return (buf);
+}
+
+static char *
+sched2str(unsigned int s)
+{
+ char *c;
+
+ switch (s) {
+ case PKTSCHEDT_NONE:
+ c = "NONE";
+ break;
+ case PKTSCHEDT_FQ_CODEL:
+ c = "FQ_CODEL";
+ break;
+ default:
+ c = "UNKNOWN";
+ break;
+ }
+
+ return (c);
+}
+
+static char *
+pri2str(unsigned int i)
+{
+ char *c;
+ switch (i) {
+ case 9:
+ c = "BK_SYS";
+ break;
+ case 8:
+ c = "BK";
+ break;
+ case 7:
+ c = "BE";
+ break;
+ case 6:
+ c = "RD";
+ break;
+ case 5:
+ c = "OAM";
+ break;
+ case 4:
+ c = "AV";
+ break;
+ case 3:
+ c = "RV";
+ break;
+ case 2:
+ c = "VI";
+ break;
+ case 1:
+ c = "VO";
+ break;
+ case 0:
+ c = "CTL";
+ break;
+ default:
+ c = "?";
+ break;
+ }
+ return (c);
+}
+
+void
+rxpollstatpr(void)
+{
+ struct ifmibdata_supplemental ifmsupp;
+ size_t miblen = sizeof (ifmsupp);
+ struct itimerval timer_interval;
+ struct if_rxpoll_stats *sp;
+ struct if_netif_stats *np;
+ sigset_t sigset, oldsigset;
+ unsigned int ifindex;
+ int name[6];
+
+ ifindex = if_nametoindex(interface);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ bzero(&ifmsupp, sizeof (struct ifmibdata_supplemental));
+
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ /* Common OID prefix */
+ name[0] = CTL_NET;
+ name[1] = PF_LINK;
+ name[2] = NETLINK_GENERIC;
+ name[3] = IFMIB_IFDATA;
+ name[4] = ifindex;
+ name[5] = IFDATA_SUPPLEMENTAL;
+ if (sysctl(name, 6, &ifmsupp, &miblen, NULL, 0) == -1)
+ err(1, "sysctl IFDATA_SUPPLEMENTAL");
+
+ sp = &ifmsupp.ifmd_rxpoll_stats;
+
+ printf("%-4s [ poll on requests: %15u errors: %27u ]\n",
+ interface, sp->ifi_poll_on_req, sp->ifi_poll_on_err);
+ printf(" [ poll off requests: %15u errors: %27u ]\n",
+ sp->ifi_poll_off_req, sp->ifi_poll_off_err);
+ printf(" [ polled packets: %18llu per poll limit: %19u ]\n",
+ sp->ifi_poll_packets, sp->ifi_poll_packets_limit);
+ printf(" [ polled bytes: %20llu ]\n", sp->ifi_poll_bytes);
+ printf(" [ poll interval: %14llu nsec ]\n",
+ sp->ifi_poll_interval_time);
+ printf(" [ sampled packets avg/min/max: %12u / %12u / %12u ]\n",
+ sp->ifi_poll_packets_avg, sp->ifi_poll_packets_min,
+ sp->ifi_poll_packets_max);
+ printf(" [ sampled bytes avg/min/max: %12u / %12u / %12u ]\n",
+ sp->ifi_poll_bytes_avg, sp->ifi_poll_bytes_min,
+ sp->ifi_poll_bytes_max);
+ printf(" [ sampled wakeups avg: %12u ]\n",
+ sp->ifi_poll_wakeups_avg);
+ printf(" [ packets lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_packets_lowat, sp->ifi_poll_packets_hiwat);
+ printf(" [ bytes lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_bytes_lowat, sp->ifi_poll_bytes_hiwat);
+ printf(" [ wakeups lowat/hiwat threshold: %10u / %10u ]\n",
+ sp->ifi_poll_wakeups_lowat, sp->ifi_poll_wakeups_hiwat);
+
+ np = &ifmsupp.ifmd_netif_stats;
+ printf(" [ mit mode: %24U cfg idx: %26u ]\n",
+ np->ifn_rx_mit_mode, np->ifn_rx_mit_cfg_idx);
+ printf(" [ cfg packets lo/hi threshold: %12u / %12u ]\n",
+ np->ifn_rx_mit_cfg_packets_lowat, np->ifn_rx_mit_cfg_packets_hiwat);
+ printf(" [ cfg bytes lo/hi threshold: %12u / %12u ]\n",
+ np->ifn_rx_mit_cfg_bytes_lowat, np->ifn_rx_mit_cfg_bytes_hiwat);
+ printf(" [ cfg interval: %15u nsec ]\n",
+ np->ifn_rx_mit_cfg_interval);
+ printf(" [ mit interval: %15llu nsec ]\n",
+ np->ifn_rx_mit_interval);
+ printf(" [ mit packets avg/min/max: %12u / %12u / %12u ]\n",
+ np->ifn_rx_mit_packets_avg, np->ifn_rx_mit_packets_min,
+ np->ifn_rx_mit_packets_max);
+ printf(" [ mit bytes avg/min/max: %12u / %12u / %12u ]\n",
+ np->ifn_rx_mit_bytes_avg, np->ifn_rx_mit_bytes_min,
+ np->ifn_rx_mit_bytes_max);
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+}
+
+static int
+create_control_socket(const char *control_name)
+{
+ struct sockaddr_ctl sc;
+ struct ctl_info ctl;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (fd == -1) {
+ perror("socket(PF_SYSTEM)");
+ return fd;
+ }
+
+ /* Get the control ID for statistics */
+ bzero(&ctl, sizeof(ctl));
+ strlcpy(ctl.ctl_name, control_name, sizeof(ctl.ctl_name));
+ if (ioctl(fd, CTLIOCGINFO, &ctl) == -1)
+ {
+ perror("ioctl(CTLIOCGINFO)");
+ close(fd);
+ return -1;
+ }
+
+ /* Connect to the statistics control */
+ bzero(&sc, sizeof(sc));
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = SYSPROTO_CONTROL;
+ sc.sc_id = ctl.ctl_id;
+ sc.sc_unit = 0;
+ if (connect(fd, (struct sockaddr*)&sc, sc.sc_len) != 0)
+ {
+ perror("connect(SYSPROTO_CONTROL)");
+ close(fd);
+ return -1;
+ }
+
+ /* Set socket to non-blocking operation */
+ if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) == -1) {
+ perror("fcnt(F_SETFL,O_NONBLOCK)");
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+static int
+add_nstat_src(int fd, const nstat_ifnet_add_param *ifparam,
+ nstat_src_ref_t *outsrc)
+{
+ nstat_msg_add_src_req *addreq;
+ nstat_msg_src_added *addedmsg;
+ nstat_ifnet_add_param *param;
+ char buffer[sizeof(*addreq) + sizeof(*param)];
+ ssize_t result;
+ const u_int32_t addreqsize =
+ offsetof(struct nstat_msg_add_src, param) + sizeof(*param);
+
+ /* Setup the add source request */
+ addreq = (nstat_msg_add_src_req *)buffer;
+ param = (nstat_ifnet_add_param*)addreq->param;
+ bzero(addreq, addreqsize);
+ addreq->hdr.context = (uintptr_t)&buffer;
+ addreq->hdr.type = NSTAT_MSG_TYPE_ADD_SRC;
+ addreq->provider = NSTAT_PROVIDER_IFNET;
+ bzero(param, sizeof(*param));
+ param->ifindex = ifparam->ifindex;
+ param->threshold = ifparam->threshold;
+
+ /* Send the add source request */
+ result = send(fd, addreq, addreqsize, 0);
+ if (result != addreqsize)
+ {
+ if (result == -1)
+ perror("send(NSTAT_ADD_SRC_REQ)");
+ else
+ fprintf(stderr, "%s: could only sent %ld out of %d\n",
+ __func__, result, addreqsize);
+ return -1;
+ }
+
+ /* Receive the response */
+ addedmsg = (nstat_msg_src_added *)buffer;
+ result = recv(fd, addedmsg, sizeof(buffer), 0);
+ if (result < sizeof(*addedmsg))
+ {
+ if (result == -1)
+ perror("recv(NSTAT_ADD_SRC_RSP)");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %lu\n", __func__, result,
+ sizeof(*addedmsg));
+ return -1;
+ }
+
+ if (addedmsg->hdr.type != NSTAT_MSG_TYPE_SRC_ADDED)
+ {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, addedmsg->hdr.type,
+ NSTAT_MSG_TYPE_SRC_ADDED);
+ return -1;
+ }
+
+ if (addedmsg->hdr.context != (uintptr_t)&buffer)
+ {
+ fprintf(stderr, "%s: received wrong context, received %llu "
+ "expected %lu\n", __func__, addedmsg->hdr.context,
+ (uintptr_t)&buffer);
+ return -1;
+ }
+ *outsrc = addedmsg->srcref;
+ return 0;
+}
+
+static int
+rem_nstat_src(int fd, nstat_src_ref_t sref)
+{
+ nstat_msg_rem_src_req *remreq;
+ nstat_msg_src_removed *remrsp;
+ char buffer[sizeof(*remreq)];
+ ssize_t result;
+
+ /* Setup the add source request */
+ remreq = (nstat_msg_rem_src_req *)buffer;
+ bzero(remreq, sizeof(*remreq));
+ remreq->hdr.type = NSTAT_MSG_TYPE_REM_SRC;
+ remreq->srcref = sref;
+
+ /* Send the remove source request */
+ result = send(fd, remreq, sizeof(*remreq), 0);
+ if (result != sizeof(*remreq)) {
+ if (result == -1)
+ perror("send(NSTAT_REM_SRC_REQ)");
+ else
+ fprintf(stderr, "%s: could only sent %ld out of %lu\n",
+ __func__, result, sizeof(*remreq));
+ return -1;
+ }
+
+ /* Receive the response */
+ remrsp = (nstat_msg_src_removed *)buffer;
+ result = recv(fd, remrsp, sizeof(buffer), 0);
+ if (result < sizeof(*remrsp)) {
+ if (result == -1)
+ perror("recv(NSTAT_REM_SRC_RSP)");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %lu\n", __func__, result,
+ sizeof(*remrsp));
+ return -1;
+ }
+
+ if (remrsp->hdr.type != NSTAT_MSG_TYPE_SRC_REMOVED) {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, remrsp->hdr.type,
+ NSTAT_MSG_TYPE_SRC_REMOVED);
+ return -1;
+ }
+
+ if (remrsp->srcref != sref) {
+ fprintf(stderr, "%s: received invalid srcref, received %llu "
+ "expected %llu\n", __func__, remrsp->srcref, sref);
+ }
+ return 0;
+}
+
+static int
+get_src_decsription(int fd, nstat_src_ref_t srcref,
+ struct nstat_ifnet_descriptor *ifdesc)
+{
+ nstat_msg_get_src_description *dreq;
+ nstat_msg_src_description *drsp;
+ char buffer[sizeof(*drsp) + sizeof(*ifdesc)];
+ ssize_t result;
+ const u_int32_t descsize =
+ offsetof(struct nstat_msg_src_description, data) +
+ sizeof(nstat_ifnet_descriptor);
+
+ dreq = (nstat_msg_get_src_description *)buffer;
+ bzero(dreq, sizeof(*dreq));
+ dreq->hdr.type = NSTAT_MSG_TYPE_GET_SRC_DESC;
+ dreq->srcref = srcref;
+ result = send(fd, dreq, sizeof(*dreq), 0);
+ if (result != sizeof(*dreq))
+ {
+ if (result == -1)
+ perror("send(NSTAT_GET_SRC_DESC_REQ)");
+ else
+ fprintf(stderr, "%s: sent %ld out of %lu\n",
+ __func__, result, sizeof(*dreq));
+ return -1;
+ }
+
+ /* Receive the source description response */
+ drsp = (nstat_msg_src_description *)buffer;
+ result = recv(fd, drsp, sizeof(buffer), 0);
+ if (result < descsize)
+ {
+ if (result == -1)
+ perror("recv(NSTAT_GET_SRC_DESC_RSP");
+ else
+ fprintf(stderr, "%s: recv too small, received %ld, "
+ "expected %u\n", __func__, result, descsize);
+ return -1;
+ }
+
+ if (drsp->hdr.type != NSTAT_MSG_TYPE_SRC_DESC)
+ {
+ fprintf(stderr, "%s: received wrong message type, received %u "
+ "expected %u\n", __func__, drsp->hdr.type,
+ NSTAT_MSG_TYPE_SRC_DESC);
+ return -1;
+ }
+
+ if (drsp->srcref != srcref)
+ {
+ fprintf(stderr, "%s: received message for wrong source, "
+ "received 0x%llx expected 0x%llx\n",
+ __func__, drsp->srcref, srcref);
+ return -1;
+ }
+
+ bcopy(drsp->data, ifdesc, sizeof(*ifdesc));
+ return 0;
+}
+
+static void
+print_wifi_status(nstat_ifnet_desc_wifi_status *status)
+{
+ int tmp;
+#define val(x, f) \
+ ((status->valid_bitmask & NSTAT_IFNET_DESC_WIFI_ ## f ## _VALID) ?\
+ status->x : -1)
+#define parg(n, un) #n, val(n, un)
+#define pretxtl(n, un) \
+ (((tmp = val(n, un)) == -1) ? "(not valid)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_NONE) ? "(none)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_LOW) ? "(low)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \
+ ((tmp == NSTAT_IFNET_DESC_WIFI_UL_RETXT_LEVEL_HIGH) ? "(high)" : \
+ "(?)")))))
+
+ printf("\nwifi status:\n");
+ printf(
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d%s\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d\n",
+ parg(link_quality_metric, LINK_QUALITY_METRIC),
+ parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH),
+ parg(ul_max_bandwidth, UL_MAX_BANDWIDTH),
+ parg(ul_min_latency, UL_MIN_LATENCY),
+ parg(ul_effective_latency, UL_EFFECTIVE_LATENCY),
+ parg(ul_max_latency, UL_MAX_LATENCY),
+ parg(ul_retxt_level, UL_RETXT_LEVEL),
+ pretxtl(ul_retxt_level, UL_RETXT_LEVEL),
+ parg(ul_bytes_lost, UL_BYTES_LOST),
+ parg(ul_error_rate, UL_ERROR_RATE),
+ parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH),
+ parg(dl_max_bandwidth, DL_MAX_BANDWIDTH),
+ parg(dl_min_latency, DL_MIN_LATENCY),
+ parg(dl_effective_latency, DL_EFFECTIVE_LATENCY),
+ parg(dl_max_latency, DL_MAX_LATENCY),
+ parg(dl_error_rate, DL_ERROR_RATE),
+ parg(config_frequency, CONFIG_FREQUENCY),
+ parg(config_multicast_rate, CONFIG_MULTICAST_RATE),
+ parg(scan_count, CONFIG_SCAN_COUNT),
+ parg(scan_duration, CONFIG_SCAN_DURATION)
+ );
+#undef pretxtl
+#undef parg
+#undef val
+}
+
+static void
+print_cellular_status(nstat_ifnet_desc_cellular_status *status)
+{
+ int tmp, tmp_mss;
+#define val(x, f) \
+ ((status->valid_bitmask & NSTAT_IFNET_DESC_CELL_ ## f ## _VALID) ?\
+ status->x : -1)
+#define parg(n, un) #n, val(n, un)
+#define pretxtl(n, un) \
+ (((tmp = val(n, un)) == -1) ? "(not valid)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_NONE) ? "(none)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_LOW) ? "(low)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_MEDIUM) ? "(medium)" : \
+ ((tmp == NSTAT_IFNET_DESC_CELL_UL_RETXT_LEVEL_HIGH) ? "(high)" : \
+ "(?)")))))
+#define pretxtm(n, un) \
+ (((tmp_mss = val(n,un)) == -1) ? "(not valid)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_NONE) ? "(none)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_MEDIUM) ? "(medium)" : \
+ ((tmp_mss == NSTAT_IFNET_DESC_MSS_RECOMMENDED_LOW) ? "(low)" : \
+ "(?)"))))
+
+ printf("\ncellular status:\n");
+ printf(
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t\t%d%s\n"
+ "\t%s:\t\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d\n"
+ "\t%s:\t%d %s\n",
+ parg(link_quality_metric, LINK_QUALITY_METRIC),
+ parg(ul_effective_bandwidth, UL_EFFECTIVE_BANDWIDTH),
+ parg(ul_max_bandwidth, UL_MAX_BANDWIDTH),
+ parg(ul_min_latency, UL_MIN_LATENCY),
+ parg(ul_effective_latency, UL_EFFECTIVE_LATENCY),
+ parg(ul_max_latency, UL_MAX_LATENCY),
+ parg(ul_retxt_level, UL_RETXT_LEVEL),
+ pretxtl(ul_retxt_level, UL_RETXT_LEVEL),
+ parg(ul_bytes_lost, UL_BYTES_LOST),
+ parg(ul_min_queue_size, UL_MIN_QUEUE_SIZE),
+ parg(ul_avg_queue_size, UL_AVG_QUEUE_SIZE),
+ parg(ul_max_queue_size, UL_MAX_QUEUE_SIZE),
+ parg(dl_effective_bandwidth, DL_EFFECTIVE_BANDWIDTH),
+ parg(dl_max_bandwidth, DL_MAX_BANDWIDTH),
+ parg(config_inactivity_time, CONFIG_INACTIVITY_TIME),
+ parg(config_backoff_time, CONFIG_BACKOFF_TIME),
+ parg(mss_recommended, MSS_RECOMMENDED),
+ pretxtm(mss_recommended, MSS_RECOMMENDED)
+ );
+#undef pretxtl
+#undef parg
+#undef val
+}
+
+static int
+get_interface_state(int fd, const char *ifname, struct ifreq *ifr)
+{
+ bzero(ifr, sizeof(*ifr));
+ snprintf(ifr->ifr_name, sizeof(ifr->ifr_name), "%s", ifname);
+
+ if (ioctl(fd, SIOCGIFINTERFACESTATE, ifr) == -1) {
+ perror("ioctl(CTLIOCGINFO)");
+ return -1;
+ }
+ return 0;
+}
+
+static void
+print_interface_state(struct ifreq *ifr)
+{
+ int lqm, rrc, avail;
+
+ printf("\ninterface state:\n");
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_LQM_STATE_VALID) {
+ printf("\tlqm: ");
+ lqm = ifr->ifr_interface_state.lqm_state;
+ if (lqm == IFNET_LQM_THRESH_GOOD)
+ printf("\"good\"");
+ else if (lqm == IFNET_LQM_THRESH_POOR)
+ printf("\"poor\"");
+ else if (lqm == IFNET_LQM_THRESH_BAD)
+ printf("\"bad\"");
+ else if (lqm == IFNET_LQM_THRESH_UNKNOWN)
+ printf("\"unknown\"");
+ else if (lqm == IFNET_LQM_THRESH_OFF)
+ printf("\"off\"");
+ else
+ printf("invalid(%d)", lqm);
+ }
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_RRC_STATE_VALID) {
+ printf("\trrc: ");
+ rrc = ifr->ifr_interface_state.rrc_state;
+ if (rrc == IF_INTERFACE_STATE_RRC_STATE_CONNECTED)
+ printf("\"connected\"");
+ else if (rrc == IF_INTERFACE_STATE_RRC_STATE_IDLE)
+ printf("\"idle\"");
+ else
+ printf("\"invalid(%d)\"", rrc);
+ }
+
+ if (ifr->ifr_interface_state.valid_bitmask &
+ IF_INTERFACE_STATE_INTERFACE_AVAILABILITY_VALID) {
+ printf("\tavailability: ");
+ avail = ifr->ifr_interface_state.interface_availability;
+ if (avail == IF_INTERFACE_STATE_INTERFACE_AVAILABLE)
+ printf("\"true\"");
+ else if (rrc == IF_INTERFACE_STATE_INTERFACE_UNAVAILABLE)
+ printf("\"false\"");
+ else
+ printf("\"invalid(%d)\"", avail);
+ }
+}
+
+void
+print_link_status(const char *ifname)
+{
+ unsigned int ifindex;
+ struct itimerval timer_interval;
+ sigset_t sigset, oldsigset;
+ struct nstat_ifnet_descriptor ifdesc;
+ nstat_ifnet_add_param ifparam;
+ nstat_src_ref_t sref = 0;
+ struct ifreq ifr;
+ int ctl_fd;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0) {
+ fprintf(stderr, "Invalid interface name\n");
+ return;
+ }
+
+ if ((ctl_fd = create_control_socket(NET_STAT_CONTROL_NAME)) < 0)
+ return;
+
+ ifparam.ifindex = ifindex;
+ ifparam.threshold = UINT64_MAX;
+ if (add_nstat_src(ctl_fd, &ifparam, &sref))
+ goto done;
+loop:
+ if (interval > 0) {
+ /* create a timer that fires repeatedly every interval
+ * seconds */
+ timer_interval.it_value.tv_sec = interval;
+ timer_interval.it_value.tv_usec = 0;
+ timer_interval.it_interval.tv_sec = interval;
+ timer_interval.it_interval.tv_usec = 0;
+ (void) signal(SIGALRM, catchalarm);
+ signalled = NO;
+ (void) setitimer(ITIMER_REAL, &timer_interval, NULL);
+ }
+
+ /* get interface state */
+ if (get_interface_state(ctl_fd, ifname, &ifr))
+ goto done;
+
+ /* get ntstat interface description */
+ if (get_src_decsription(ctl_fd, sref, &ifdesc))
+ goto done;
+
+ /* print time */
+ printf("\n%s: ", ifname);
+ print_time();
+
+ /* print interface state */
+ print_interface_state(&ifr);
+
+ /* print ntsat interface link status */
+ if (ifdesc.link_status.link_status_type ==
+ NSTAT_IFNET_DESC_LINK_STATUS_TYPE_CELLULAR)
+ print_cellular_status(&ifdesc.link_status.u.cellular);
+ else if (ifdesc.link_status.link_status_type ==
+ NSTAT_IFNET_DESC_LINK_STATUS_TYPE_WIFI)
+ print_wifi_status(&ifdesc.link_status.u.wifi);
+
+ fflush(stdout);
+
+ if (interval > 0) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ (void) sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ if (!signalled) {
+ sigemptyset(&sigset);
+ sigsuspend(&sigset);
+ }
+ (void) sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+
+ signalled = NO;
+ goto loop;
+ }
+done:
+ if (sref)
+ rem_nstat_src(ctl_fd, sref);
+ close(ctl_fd);
+}
diff --git a/network_cmds/netstat.tproj/inet.c b/network_cmds/netstat.tproj/inet.c
new file mode 100644
index 0000000..68e4ddb
--- /dev/null
+++ b/network_cmds/netstat.tproj/inet.c
@@ -0,0 +1,1361 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ ** @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if_arp.h>
+#include <net/net_perf.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#ifdef INET6
+#include <netinet/ip6.h>
+#endif /* INET6 */
+#include <netinet/in_pcb.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/igmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+#include <netinet/tcp_seq.h>
+#define TCPSTATES
+#include <netinet/tcp_fsm.h>
+#include <netinet/tcp_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#define ROUNDUP64(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
+#define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
+
+char *inetname (struct in_addr *);
+void inetprint (struct in_addr *, int, char *, int);
+#ifdef INET6
+extern void inet6print (struct in6_addr *, int, char *, int);
+static int udp_done, tcp_done;
+extern int mptcp_done;
+#endif /* INET6 */
+
+#ifdef SRVCACHE
+typedef struct __table_private table_t;
+
+extern table_t *_nc_table_new(uint32_t n);
+extern void _nc_table_free(table_t *tin);
+
+extern void _nc_table_insert(table_t *t, const char *key, void *datum);
+extern void *_nc_table_find(table_t *t, const char *key);
+extern void _nc_table_delete(table_t *t, const char *key);
+
+static table_t *_serv_cache = NULL;
+
+/*
+ * Read and cache all known services
+ */
+static void
+_serv_cache_open()
+{
+ struct servent *s;
+ char *key, *name, *test;
+
+ if (_serv_cache != NULL) return;
+
+ _serv_cache = _nc_table_new(8192);
+ setservent(0);
+
+ while (NULL != (s = getservent()))
+ {
+ if (s->s_name == NULL) continue;
+ key = NULL;
+ asprintf(&key, "%hu/%s", (unsigned short)ntohs(s->s_port), s->s_proto);
+ name = strdup(s->s_name);
+ test = _nc_table_find(_serv_cache, key);
+ if (test == NULL) _nc_table_insert(_serv_cache, key, name);
+ free(key);
+ }
+
+ endservent();
+}
+
+void
+_serv_cache_close()
+{
+ _nc_table_free(_serv_cache);
+ _serv_cache = NULL;
+}
+
+struct servent *
+_serv_cache_getservbyport(int port, char *proto)
+{
+ static struct servent s;
+ char *key;
+ unsigned short p;
+
+ _serv_cache_open();
+
+ memset(&s, 0, sizeof(struct servent));
+ asprintf(&key, "%u/%s", port, (proto == NULL) ? "udp" : proto);
+
+ s.s_name = _nc_table_find(_serv_cache, key);
+ free(key);
+ if (s.s_name == NULL) return NULL;
+
+ p = port;
+ s.s_port = htons(p);
+ s.s_proto = proto;
+ return &s;
+}
+
+#endif /* SRVCACHE */
+
+/*
+ * Print a summary of connections related to an Internet
+ * protocol. For TCP, also give state of connection.
+ * Listening processes (aflag) are suppressed unless the
+ * -a (all) flag is specified.
+ */
+
+struct xgen_n {
+ u_int32_t xgn_len; /* length of this structure */
+ u_int32_t xgn_kind; /* number of PCBs at this time */
+};
+
+#define ALL_XGN_KIND_INP (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_INPCB)
+#define ALL_XGN_KIND_TCP (ALL_XGN_KIND_INP | XSO_TCPCB)
+
+void
+protopr(uint32_t proto, /* for sysctl version we pass proto # */
+ char *name, int af)
+{
+ int istcp;
+ static int first = 1;
+ char *buf, *next;
+ const char *mibvar;
+ struct xinpgen *xig, *oxig;
+ struct xgen_n *xgn;
+ size_t len;
+ struct xtcpcb_n *tp = NULL;
+ struct xinpcb_n *inp = NULL;
+ struct xsocket_n *so = NULL;
+ struct xsockbuf_n *so_rcv = NULL;
+ struct xsockbuf_n *so_snd = NULL;
+ struct xsockstat_n *so_stat = NULL;
+ int which = 0;
+
+ istcp = 0;
+ switch (proto) {
+ case IPPROTO_TCP:
+#ifdef INET6
+ if (tcp_done != 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+ istcp = 1;
+ mibvar = "net.inet.tcp.pcblist_n";
+ break;
+ case IPPROTO_UDP:
+#ifdef INET6
+ if (udp_done != 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+ mibvar = "net.inet.udp.pcblist_n";
+ break;
+ case IPPROTO_DIVERT:
+ mibvar = "net.inet.divert.pcblist_n";
+ break;
+ default:
+ mibvar = "net.inet.raw.pcblist_n";
+ break;
+ }
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= sizeof(struct xinpgen)) {
+ free(buf);
+ return;
+ }
+
+ oxig = xig = (struct xinpgen *)buf;
+ for (next = buf + ROUNDUP64(xig->xig_len); next < buf + len; next += ROUNDUP64(xgn->xgn_len)) {
+
+ xgn = (struct xgen_n*)next;
+ if (xgn->xgn_len <= sizeof(struct xinpgen))
+ break;
+
+ if ((which & xgn->xgn_kind) == 0) {
+ which |= xgn->xgn_kind;
+ switch (xgn->xgn_kind) {
+ case XSO_SOCKET:
+ so = (struct xsocket_n *)xgn;
+ break;
+ case XSO_RCVBUF:
+ so_rcv = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_SNDBUF:
+ so_snd = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_STATS:
+ so_stat = (struct xsockstat_n *)xgn;
+ break;
+ case XSO_INPCB:
+ inp = (struct xinpcb_n *)xgn;
+ break;
+ case XSO_TCPCB:
+ tp = (struct xtcpcb_n *)xgn;
+ break;
+ default:
+ printf("unexpected kind %d\n", xgn->xgn_kind);
+ break;
+ }
+ } else {
+ if (vflag)
+ printf("got %d twice\n", xgn->xgn_kind);
+ }
+
+ if ((istcp && which != ALL_XGN_KIND_TCP) || (!istcp && which != ALL_XGN_KIND_INP))
+ continue;
+ which = 0;
+
+ /* Ignore sockets for protocols other than the desired one. */
+ if (so->xso_protocol != (int)proto)
+ continue;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (inp->inp_gencnt > oxig->xig_gen)
+ continue;
+
+ if ((af == AF_INET && (inp->inp_vflag & INP_IPV4) == 0)
+#ifdef INET6
+ || (af == AF_INET6 && (inp->inp_vflag & INP_IPV6) == 0)
+#endif /* INET6 */
+ || (af == AF_UNSPEC && ((inp->inp_vflag & INP_IPV4) == 0
+#ifdef INET6
+ && (inp->inp_vflag &
+ INP_IPV6) == 0
+#endif /* INET6 */
+ ))
+ )
+ continue;
+
+ /*
+ * Local address is not an indication of listening socket or
+ * server sockey but just rather the socket has been bound.
+ * That why many UDP sockets were not displayed in the original code.
+ */
+ if (!aflag && istcp && tp->t_state <= TCPS_LISTEN)
+ continue;
+
+ if (Lflag && !so->so_qlimit)
+ continue;
+
+ if (first) {
+ if (!Lflag) {
+ printf("Active Internet connections");
+ if (aflag)
+ printf(" (including servers)");
+ } else
+ printf(
+ "Current listen queue sizes (qlen/incqlen/maxqlen)");
+ putchar('\n');
+ if (Aflag) {
+ printf("%-16.16s ", "Socket");
+ printf("%-9.9s", "Flowhash");
+ }
+ if (Lflag)
+ printf("%-14.14s %-22.22s\n",
+ "Listen", "Local Address");
+ else {
+ printf((Aflag && !Wflag) ?
+ "%-5.5s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s" :
+ "%-5.5s %-6.6s %-6.6s %-22.22s %-22.22s %-11.11s",
+ "Proto", "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address",
+ "(state)");
+ if (bflag > 0)
+ printf(" %10.10s %10.10s", "rxbytes", "txbytes");
+ if (prioflag >= 0)
+ printf(" %7.7s[%1d] %7.7s[%1d]", "rxbytes", prioflag, "txbytes", prioflag);
+ if (vflag > 0)
+ printf(" %6.6s %6.6s %6.6s %6.6s %6s %10s",
+ "rhiwat", "shiwat", "pid", "epid", "state", "options");
+ printf("\n");
+ }
+ first = 0;
+ }
+ if (Aflag) {
+ if (istcp)
+ printf("%16lx ", (u_long)inp->inp_ppcb);
+ else
+ printf("%16lx ", (u_long)so->so_pcb);
+ printf("%8x ", inp->inp_flowhash);
+ }
+ if (Lflag) {
+ char buf[15];
+
+ snprintf(buf, 15, "%d/%d/%d", so->so_qlen,
+ so->so_incqlen, so->so_qlimit);
+ printf("%-14.14s ", buf);
+ }
+ else {
+ const char *vchar;
+
+#ifdef INET6
+ if ((inp->inp_vflag & INP_IPV6) != 0)
+ vchar = ((inp->inp_vflag & INP_IPV4) != 0)
+ ? "46" : "6 ";
+ else
+#endif
+ vchar = ((inp->inp_vflag & INP_IPV4) != 0)
+ ? "4 " : " ";
+
+ printf("%-3.3s%-2.2s %6u %6u ", name, vchar,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ }
+ if (nflag) {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name, 1);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 1);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ } else if (inp->inp_flags & INP_ANONPORT) {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 1);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name, 0);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 1);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name, 0);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ } else {
+ if (inp->inp_vflag & INP_IPV4) {
+ inetprint(&inp->inp_laddr, (int)inp->inp_lport,
+ name, 0);
+ if (!Lflag)
+ inetprint(&inp->inp_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport !=
+ inp->inp_fport);
+ }
+#ifdef INET6
+ else if (inp->inp_vflag & INP_IPV6) {
+ inet6print(&inp->in6p_laddr,
+ (int)inp->inp_lport, name, 0);
+ if (!Lflag)
+ inet6print(&inp->in6p_faddr,
+ (int)inp->inp_fport, name,
+ inp->inp_lport !=
+ inp->inp_fport);
+ } /* else nothing printed now */
+#endif /* INET6 */
+ }
+ if (istcp && !Lflag) {
+ if (tp->t_state < 0 || tp->t_state >= TCP_NSTATES)
+ printf("%-11d", tp->t_state);
+ else {
+ printf("%-11s", tcpstates[tp->t_state]);
+ }
+ }
+ if (!istcp)
+ printf("%-11s", " ");
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+
+ printf(" %10llu %10llu", rxbytes, txbytes);
+ }
+ if (prioflag >= 0) {
+ printf(" %10llu %10llu",
+ prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].rxbytes : 0,
+ prioflag < SO_TC_STATS_MAX ? so_stat->xst_tc_stats[prioflag].txbytes : 0);
+ }
+ if (vflag > 0) {
+ printf(" %6u %6u %6u %6u 0x%04x 0x%08x",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid,
+ so->so_state,
+ so->so_options);
+ }
+ putchar('\n');
+ }
+ if (xig != oxig && xig->xig_gen != oxig->xig_gen) {
+ if (oxig->xig_count > xig->xig_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ name);
+ } else if (oxig->xig_count < xig->xig_count) {
+ printf("Some %s sockets may have been created.\n",
+ name);
+ } else {
+ printf("Some %s sockets may have been created or deleted",
+ name);
+ }
+ }
+ free(buf);
+}
+
+/*
+ * Dump TCP statistics structure.
+ */
+void
+tcp_stats(uint32_t off , char *name, int af)
+{
+ static struct tcpstat ptcpstat;
+ struct tcpstat tcpstat;
+ size_t len = sizeof tcpstat;
+ static uint32_t r_swcsum, pr_swcsum;
+ static uint32_t t_swcsum, pt_swcsum;
+
+ if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.tcp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (tcp_done != 0 && interval == 0)
+ return;
+ else
+ tcp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define TCPDIFF(f) (tcpstat.f - ptcpstat.f)
+#define p(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f), plural(TCPDIFF(f)))
+#define p1a(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f))
+#define p2(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
+ printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2), plural(TCPDIFF(f2)))
+#define p2a(f1, f2, m) if (TCPDIFF(f1) || TCPDIFF(f2) || sflag <= 1) \
+ printf(m, TCPDIFF(f1), plural(TCPDIFF(f1)), TCPDIFF(f2))
+#define p3(f, m) if (TCPDIFF(f) || sflag <= 1) \
+ printf(m, TCPDIFF(f), plurales(TCPDIFF(f)))
+
+ p(tcps_sndtotal, "\t%u packet%s sent\n");
+ p2(tcps_sndpack,tcps_sndbyte,
+ "\t\t%u data packet%s (%u byte%s)\n");
+ p2(tcps_sndrexmitpack, tcps_sndrexmitbyte,
+ "\t\t%u data packet%s (%u byte%s) retransmitted\n");
+ p(tcps_mturesent, "\t\t%u resend%s initiated by MTU discovery\n");
+ p2a(tcps_sndacks, tcps_delack,
+ "\t\t%u ack-only packet%s (%u delayed)\n");
+ p(tcps_sndurg, "\t\t%u URG only packet%s\n");
+ p(tcps_sndprobe, "\t\t%u window probe packet%s\n");
+ p(tcps_sndwinup, "\t\t%u window update packet%s\n");
+ p(tcps_sndctrl, "\t\t%u control packet%s\n");
+ p(tcps_fcholdpacket, "\t\t%u data packet%s sent after flow control\n");
+ p(tcps_synchallenge, "\t\t%u challenge ACK%s sent due to unexpected SYN\n");
+ p(tcps_rstchallenge, "\t\t%u challenge ACK%s sent due to unexpected RST\n");
+ t_swcsum = tcpstat.tcps_snd_swcsum + tcpstat.tcps_snd6_swcsum;
+ if ((t_swcsum - pt_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
+ p2(tcps_snd_swcsum, tcps_snd_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(tcps_snd6_swcsum, tcps_snd6_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p(tcps_rcvtotal, "\t%u packet%s received\n");
+ p2(tcps_rcvackpack, tcps_rcvackbyte, "\t\t%u ack%s (for %u byte%s)\n");
+ p(tcps_rcvdupack, "\t\t%u duplicate ack%s\n");
+ p(tcps_rcvacktoomuch, "\t\t%u ack%s for unsent data\n");
+ p2(tcps_rcvpack, tcps_rcvbyte,
+ "\t\t%u packet%s (%u byte%s) received in-sequence\n");
+ p2(tcps_rcvduppack, tcps_rcvdupbyte,
+ "\t\t%u completely duplicate packet%s (%u byte%s)\n");
+ p(tcps_pawsdrop, "\t\t%u old duplicate packet%s\n");
+ p(tcps_rcvmemdrop, "\t\t%u received packet%s dropped due to low memory\n");
+ p2(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
+ "\t\t%u packet%s with some dup. data (%u byte%s duped)\n");
+ p2(tcps_rcvoopack, tcps_rcvoobyte,
+ "\t\t%u out-of-order packet%s (%u byte%s)\n");
+ p2(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
+ "\t\t%u packet%s (%u byte%s) of data after window\n");
+ p(tcps_rcvwinprobe, "\t\t%u window probe%s\n");
+ p(tcps_rcvwinupd, "\t\t%u window update packet%s\n");
+ p(tcps_recovered_pkts, "\t\t%u packet%s recovered after loss\n");
+ p(tcps_rcvafterclose, "\t\t%u packet%s received after close\n");
+ p(tcps_badrst, "\t\t%u bad reset%s\n");
+ p(tcps_rcvbadsum, "\t\t%u discarded for bad checksum%s\n");
+ r_swcsum = tcpstat.tcps_rcv_swcsum + tcpstat.tcps_rcv6_swcsum;
+ if ((r_swcsum - pr_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n",
+ (r_swcsum - pr_swcsum));
+ p2(tcps_rcv_swcsum, tcps_rcv_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(tcps_rcv6_swcsum, tcps_rcv6_swcsum_bytes,
+ "\t\t\t%u segment%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p(tcps_rcvbadoff, "\t\t%u discarded for bad header offset field%s\n");
+ p1a(tcps_rcvshort, "\t\t%u discarded because packet too short\n");
+ p(tcps_connattempt, "\t%u connection request%s\n");
+ p(tcps_accepts, "\t%u connection accept%s\n");
+ p(tcps_badsyn, "\t%u bad connection attempt%s\n");
+ p(tcps_listendrop, "\t%u listen queue overflow%s\n");
+ p(tcps_connects, "\t%u connection%s established (including accepts)\n");
+ p2(tcps_closed, tcps_drops,
+ "\t%u connection%s closed (including %u drop%s)\n");
+ p(tcps_cachedrtt, "\t\t%u connection%s updated cached RTT on close\n");
+ p(tcps_cachedrttvar,
+ "\t\t%u connection%s updated cached RTT variance on close\n");
+ p(tcps_cachedssthresh,
+ "\t\t%u connection%s updated cached ssthresh on close\n");
+ p(tcps_usedrtt, "\t\t%u connection%s initialized RTT from route cache\n");
+ p(tcps_usedrttvar,
+ "\t\t%u connection%s initialized RTT variance from route cache\n");
+ p(tcps_usedssthresh,
+ "\t\t%u connection%s initialized ssthresh from route cache\n");
+ p(tcps_conndrops, "\t%u embryonic connection%s dropped\n");
+ p2(tcps_rttupdated, tcps_segstimed,
+ "\t%u segment%s updated rtt (of %u attempt%s)\n");
+ p(tcps_rexmttimeo, "\t%u retransmit timeout%s\n");
+ p(tcps_timeoutdrop, "\t\t%u connection%s dropped by rexmit timeout\n");
+ p(tcps_rxtfindrop, "\t\t%u connection%s dropped after retransmitting FIN\n");
+ p(tcps_sndrexmitbad, "\t\t%u unnecessary packet retransmissions%s\n");
+ p(tcps_persisttimeo, "\t%u persist timeout%s\n");
+ p(tcps_persistdrop, "\t\t%u connection%s dropped by persist timeout\n");
+ p(tcps_keeptimeo, "\t%u keepalive timeout%s\n");
+ p(tcps_keepprobe, "\t\t%u keepalive probe%s sent\n");
+ p(tcps_keepdrops, "\t\t%u connection%s dropped by keepalive\n");
+ p(tcps_ka_offload_drops, "\t\t%u connection%s dropped by keepalive offload\n");
+ p(tcps_predack, "\t%u correct ACK header prediction%s\n");
+ p(tcps_preddat, "\t%u correct data packet header prediction%s\n");
+#ifdef TCP_MAX_SACK
+ /* TCP_MAX_SACK indicates the header has the SACK structures */
+ p(tcps_sack_recovery_episode, "\t%u SACK recovery episode%s\n");
+ p(tcps_sack_rexmits,
+ "\t%u segment rexmit%s in SACK recovery episodes\n");
+ p(tcps_sack_rexmit_bytes,
+ "\t%u byte rexmit%s in SACK recovery episodes\n");
+ p(tcps_sack_rcv_blocks,
+ "\t%u SACK option%s (SACK blocks) received\n");
+ p(tcps_sack_send_blocks, "\t%u SACK option%s (SACK blocks) sent\n");
+ p1a(tcps_sack_sboverflow, "\t%u SACK scoreboard overflow\n");
+#endif /* TCP_MAX_SACK */
+ p(tcps_limited_txt, "\t%u limited transmit%s done\n");
+ p(tcps_early_rexmt, "\t%u early retransmit%s done\n");
+ p(tcps_sack_ackadv, "\t%u time%s cumulative ack advanced along with SACK\n");
+ p(tcps_pto, "\t%u probe timeout%s\n");
+ p(tcps_rto_after_pto, "\t\t%u time%s retransmit timeout triggered after probe\n");
+ p(tcps_probe_if, "\t\t%u time%s probe packets were sent for an interface\n");
+ p(tcps_probe_if_conflict, "\t\t%u time%s couldn't send probe packets for an interface\n");
+ p(tcps_tlp_recovery, "\t\t%u time%s fast recovery after tail loss\n");
+ p(tcps_tlp_recoverlastpkt, "\t\t%u time%s recovered last packet \n");
+ p(tcps_pto_in_recovery, "\t\t%u SACK based rescue retransmit%s\n");
+ p(tcps_ecn_client_setup, "\t%u client connection%s attempted to negotiate ECN\n");
+ p(tcps_ecn_client_success, "\t\t%u client connection%s successfully negotiated ECN\n");
+ p(tcps_ecn_not_supported, "\t\t%u time%s graceful fallback to Non-ECN connection\n");
+ p(tcps_ecn_lost_syn, "\t\t%u time%s lost ECN negotiating SYN, followed by retransmission\n");
+ p(tcps_ecn_server_setup, "\t\t%u server connection%s attempted to negotiate ECN\n");
+ p(tcps_ecn_server_success, "\t\t%u server connection%s successfully negotiated ECN\n");
+ p(tcps_ecn_lost_synack, "\t\t%u time%s lost ECN negotiating SYN-ACK, followed by retransmission\n");
+ p(tcps_ecn_recv_ce, "\t\t%u time%s received congestion experienced (CE) notification\n");
+ p(tcps_ecn_recv_ece, "\t\t%u time%s CWR was sent in response to ECE\n");
+ p(tcps_ecn_sent_ece, "\t\t%u time%s sent ECE notification\n");
+ p(tcps_ecn_conn_recv_ce, "\t\t%u connection%s received CE atleast once\n");
+ p(tcps_ecn_conn_recv_ece, "\t\t%u connection%s received ECE atleast once\n");
+ p(tcps_ecn_conn_plnoce, "\t\t%u connection%s using ECN have seen packet loss but no CE\n");
+ p(tcps_ecn_conn_pl_ce, "\t\t%u connection%s using ECN have seen packet loss and CE\n");
+ p(tcps_ecn_conn_nopl_ce, "\t\t%u connection%s using ECN received CE but no packet loss\n");
+ p(tcps_ecn_fallback_synloss, "\t\t%u connection%s fell back to non-ECN due to SYN-loss\n");
+ p(tcps_ecn_fallback_reorder, "\t\t%u connection%s fell back to non-ECN due to reordering\n");
+ p(tcps_ecn_fallback_ce, "\t\t%u connection%s fell back to non-ECN due to excessive CE-markings\n");
+ p(tcps_ecn_fallback_droprst, "\t\t%u connection%s fell back caused by connection drop due to RST\n");
+ p(tcps_ecn_fallback_droprxmt, "\t\t%u connection%s fell back due to drop after multiple retransmits \n");
+ p(tcps_ecn_fallback_synrst, "\t\t%u connection%s fell back due to RST after SYN\n");
+
+ p(tcps_detect_reordering, "\t%u time%s packet reordering was detected on a connection\n");
+ p(tcps_reordered_pkts, "\t\t%u time%s transmitted packets were reordered\n");
+ p(tcps_delay_recovery, "\t\t%u time%s fast recovery was delayed to handle reordering\n");
+ p(tcps_avoid_rxmt, "\t\t%u time%s retransmission was avoided by delaying recovery\n");
+ p(tcps_unnecessary_rxmt, "\t\t%u retransmission%s not needed \n");
+ p(tcps_tailloss_rto, "\t%u retransmission%s due to tail loss\n");
+ p(tcps_dsack_sent, "\t%u time%s DSACK option was sent\n");
+ p(tcps_dsack_recvd, "\t\t%u time%s DSACK option was received\n");
+ p(tcps_dsack_disable, "\t\t%u time%s DSACK was disabled on a connection\n");
+ p(tcps_dsack_badrexmt, "\t\t%u time%s recovered from bad retransmission using DSACK\n");
+ p(tcps_dsack_ackloss,"\t\t%u time%s ignored DSACK due to ack loss\n");
+ p(tcps_dsack_recvd_old,"\t\t%u time%s ignored old DSACK options\n");
+ p(tcps_pmtudbh_reverted, "\t%u time%s PMTU Blackhole detection, size reverted\n");
+ p(tcps_drop_after_sleep, "\t%u connection%s were dropped after long sleep\n");
+ p(tcps_nostretchack, "\t%u connection%s had stretch ack algorithm disabled\n");
+
+ p(tcps_tfo_cookie_sent,"\t%u time%s a TFO-cookie has been announced\n");
+ p(tcps_tfo_syn_data_rcv,"\t%u SYN%s with data and a valid TFO-cookie have been received\n");
+ p(tcps_tfo_cookie_req_rcv,"\t%u SYN%s with TFO-cookie-request received\n");
+ p(tcps_tfo_cookie_invalid,"\t%u time%s an invalid TFO-cookie has been received\n");
+ p(tcps_tfo_cookie_req,"\t%u time%s we requested a TFO-cookie\n");
+ p(tcps_tfo_cookie_rcv,"\t\t%u time%s the peer announced a TFO-cookie\n");
+ p(tcps_tfo_syn_data_sent,"\t%u time%s we combined SYN with data and a TFO-cookie\n");
+ p(tcps_tfo_syn_data_acked,"\t\t%u time%s our SYN with data has been acknowledged\n");
+ p(tcps_tfo_syn_loss,"\t%u time%s a connection-attempt with TFO fell back to regular TCP\n");
+ p(tcps_tfo_blackhole,"\t%u time%s a TFO-connection blackhole'd\n");
+ p(tcps_tfo_cookie_wrong,"\t%u time%s a TFO-cookie we sent was wrong\n");
+ p(tcps_tfo_no_cookie_rcv,"\t%u time%s did not received a TFO-cookie we asked for\n");
+ p(tcps_tfo_heuristics_disable,"\t%u time%s TFO got disabled due to heuristicsn\n");
+ p(tcps_tfo_sndblackhole,"\t%u time%s TFO got blackholed in the sending direction\n");
+
+ p(tcps_mss_to_default,"\t%u time%s maximum segment size was changed to default\n");
+ p(tcps_mss_to_medium,"\t%u time%s maximum segment size was changed to medium\n");
+ p(tcps_mss_to_low,"\t%u time%s maximum segment size was changed to low\n");
+
+ p(tcps_timer_drift_le_1_ms,"\t%u timer drift%s less or equal to 1 ms\n");
+ p(tcps_timer_drift_le_10_ms,"\t%u timer drift%s less or equal to 10 ms\n");
+ p(tcps_timer_drift_le_20_ms,"\t%u timer drift%s less or equal to 20 ms\n");
+ p(tcps_timer_drift_le_50_ms,"\t%u timer drift%s less or equal to 50 ms\n");
+ p(tcps_timer_drift_le_100_ms,"\t%u timer drift%s less or equal to 100 ms\n");
+ p(tcps_timer_drift_le_200_ms,"\t%u timer drift%s less or equal to 200 ms\n");
+ p(tcps_timer_drift_le_500_ms,"\t%u timer drift%s less or equal to 500 ms\n");
+ p(tcps_timer_drift_le_1000_ms,"\t%u timer drift%s less or equal to 1000 ms\n");
+ p(tcps_timer_drift_gt_1000_ms,"\t%u timer drift%s greater than to 1000 ms\n");
+
+ if (interval > 0) {
+ bcopy(&tcpstat, &ptcpstat, len);
+ pr_swcsum = r_swcsum;
+ pt_swcsum = t_swcsum;
+ }
+
+#undef TCPDIFF
+#undef p
+#undef p1a
+#undef p2
+#undef p2a
+#undef p3
+}
+
+/*
+ * Dump MPTCP statistics
+ */
+void
+mptcp_stats(uint32_t off , char *name, int af)
+{
+ static struct tcpstat ptcpstat;
+ struct tcpstat tcpstat;
+ size_t len = sizeof tcpstat;
+
+ if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.tcp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (mptcp_done != 0 && interval == 0)
+ return;
+ else
+ mptcp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define MPTCPDIFF(f) (tcpstat.f - ptcpstat.f)
+#define p(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f), plural(MPTCPDIFF(f)))
+#define p1a(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f))
+#define p2(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), \
+ MPTCPDIFF(f2), plural(MPTCPDIFF(f2)))
+#define p2a(f1, f2, m) if (MPTCPDIFF(f1) || MPTCPDIFF(f2) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f1), plural(MPTCPDIFF(f1)), MPTCPDIFF(f2))
+#define p3(f, m) if (MPTCPDIFF(f) || sflag <= 1) \
+ printf(m, MPTCPDIFF(f), plurales(MPTCPDIFF(f)))
+
+ p(tcps_mp_sndpacks, "\t%u data packet%s sent\n");
+ p(tcps_mp_sndbytes, "\t%u data byte%s sent\n");
+ p(tcps_mp_rcvtotal, "\t%u data packet%s received\n");
+ p(tcps_mp_rcvbytes, "\t%u data byte%s received\n");
+ p(tcps_invalid_mpcap, "\t%u packet%s with an invalid MPCAP option\n");
+ p(tcps_invalid_joins, "\t%u packet%s with an invalid MPJOIN option\n");
+ p(tcps_mpcap_fallback, "\t%u time%s primary subflow fell back to "
+ "TCP\n");
+ p(tcps_join_fallback, "\t%u time%s secondary subflow fell back to "
+ "TCP\n");
+ p(tcps_estab_fallback, "\t%u DSS option drop%s\n");
+ p(tcps_invalid_opt, "\t%u other invalid MPTCP option%s\n");
+ p(tcps_mp_reducedwin, "\t%u time%s the MPTCP subflow window was reduced\n");
+ p(tcps_mp_badcsum, "\t%u bad DSS checksum%s\n");
+ p(tcps_mp_oodata, "\t%u time%s received out of order data \n");
+ p3(tcps_mp_switches, "\t%u subflow switch%s\n");
+ p3(tcps_mp_sel_symtomsd, "\t%u subflow switch%s due to advisory\n");
+ p3(tcps_mp_sel_rtt, "\t%u subflow switch%s due to rtt\n");
+ p3(tcps_mp_sel_rto, "\t%u subflow switch%s due to rto\n");
+ p3(tcps_mp_sel_peer, "\t%u subflow switch%s due to peer\n");
+ p3(tcps_mp_num_probes, "\t%u number of subflow probe%s\n");
+
+ if (interval > 0) {
+ bcopy(&tcpstat, &ptcpstat, len);
+ }
+
+#undef MPTCPDIFF
+#undef p
+#undef p1a
+#undef p2
+#undef p2a
+#undef p3
+}
+
+/*
+ * Dump UDP statistics structure.
+ */
+void
+udp_stats(uint32_t off , char *name, int af )
+{
+ static struct udpstat pudpstat;
+ struct udpstat udpstat;
+ size_t len = sizeof udpstat;
+ uint32_t delivered;
+ static uint32_t r_swcsum, pr_swcsum;
+ static uint32_t t_swcsum, pt_swcsum;
+
+ if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.udp.stats");
+ return;
+ }
+
+#ifdef INET6
+ if (udp_done != 0 && interval == 0)
+ return;
+ else
+ udp_done = 1;
+#endif
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define UDPDIFF(f) (udpstat.f - pudpstat.f)
+#define p(f, m) if (UDPDIFF(f) || sflag <= 1) \
+ printf(m, UDPDIFF(f), plural(UDPDIFF(f)))
+#define p1a(f, m) if (UDPDIFF(f) || sflag <= 1) \
+ printf(m, UDPDIFF(f))
+#define p2(f1, f2, m) if (UDPDIFF(f1) || UDPDIFF(f2) || sflag <= 1) \
+ printf(m, UDPDIFF(f1), plural(UDPDIFF(f1)), UDPDIFF(f2), plural(UDPDIFF(f2)))
+ p(udps_ipackets, "\t%u datagram%s received\n");
+ p1a(udps_hdrops, "\t\t%u with incomplete header\n");
+ p1a(udps_badlen, "\t\t%u with bad data length field\n");
+ p1a(udps_badsum, "\t\t%u with bad checksum\n");
+ p1a(udps_nosum, "\t\t%u with no checksum\n");
+ r_swcsum = udpstat.udps_rcv_swcsum + udpstat.udps_rcv6_swcsum;
+ if ((r_swcsum - pr_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (r_swcsum - pr_swcsum));
+ p2(udps_rcv_swcsum, udps_rcv_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(udps_rcv6_swcsum, udps_rcv6_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+ p1a(udps_noport, "\t\t%u dropped due to no socket\n");
+ p(udps_noportbcast,
+ "\t\t%u broadcast/multicast datagram%s undelivered\n");
+ /* the next statistic is cumulative in udps_noportbcast */
+ p(udps_filtermcast,
+ "\t\t%u time%s multicast source filter matched\n");
+ p1a(udps_fullsock, "\t\t%u dropped due to full socket buffers\n");
+ p1a(udpps_pcbhashmiss, "\t\t%u not for hashed pcb\n");
+ delivered = UDPDIFF(udps_ipackets) -
+ UDPDIFF(udps_hdrops) -
+ UDPDIFF(udps_badlen) -
+ UDPDIFF(udps_badsum) -
+ UDPDIFF(udps_noport) -
+ UDPDIFF(udps_noportbcast) -
+ UDPDIFF(udps_fullsock);
+ if (delivered || sflag <= 1)
+ printf("\t\t%u delivered\n", delivered);
+ p(udps_opackets, "\t%u datagram%s output\n");
+ t_swcsum = udpstat.udps_snd_swcsum + udpstat.udps_snd6_swcsum;
+ if ((t_swcsum - pt_swcsum) || sflag <= 1)
+ printf("\t\t%u checksummed in software\n", (t_swcsum - pt_swcsum));
+ p2(udps_snd_swcsum, udps_snd_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv4\n");
+#if INET6
+ p2(udps_snd6_swcsum, udps_snd6_swcsum_bytes,
+ "\t\t\t%u datagram%s (%u byte%s) over IPv6\n");
+#endif /* INET6 */
+
+ if (interval > 0) {
+ bcopy(&udpstat, &pudpstat, len);
+ pr_swcsum = r_swcsum;
+ pt_swcsum = t_swcsum;
+ }
+
+#undef UDPDIFF
+#undef p
+#undef p1a
+#undef p2
+}
+
+/*
+ * Dump IP statistics structure.
+ */
+void
+ip_stats(uint32_t off , char *name, int af )
+{
+ static struct ipstat pipstat;
+ struct ipstat ipstat;
+ size_t ipstat_len = sizeof ipstat;
+
+ static net_perf_t pout_net_perf, pin_net_perf;
+ net_perf_t out_net_perf, in_net_perf;
+ size_t out_net_perf_len = sizeof (out_net_perf);
+ size_t in_net_perf_len = sizeof (in_net_perf);
+
+ if (sysctlbyname("net.inet.ip.stats", &ipstat, &ipstat_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.stats");
+ return;
+ }
+
+ if (sysctlbyname("net.inet.ip.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.output_perf_data");
+ bzero(&out_net_perf, out_net_perf_len);
+ }
+
+ if (sysctlbyname("net.inet.ip.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
+ warn("sysctl: net.inet.ip.input_perf_data");
+ bzero(&in_net_perf, in_net_perf_len);
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IPDIFF(f) (ipstat.f - pipstat.f)
+#define p(f, m) if (IPDIFF(f) || sflag <= 1) \
+ printf(m, IPDIFF(f), plural(IPDIFF(f)))
+#define p1a(f, m) if (IPDIFF(f) || sflag <= 1) \
+ printf(m, IPDIFF(f))
+#define p2(f1, f2, m) if (IPDIFF(f1) || IPDIFF(f2) || sflag <= 1) \
+ printf(m, IPDIFF(f1), plural(IPDIFF(f1)), IPDIFF(f2), plural(IPDIFF(f2)))
+
+ p(ips_total, "\t%u total packet%s received\n");
+ p(ips_badsum, "\t\t%u bad header checksum%s\n");
+ p2(ips_rcv_swcsum, ips_rcv_swcsum_bytes,
+ "\t\t%u header%s (%u byte%s) checksummed in software\n");
+ p1a(ips_toosmall, "\t\t%u with size smaller than minimum\n");
+ p1a(ips_tooshort, "\t\t%u with data size < data length\n");
+ p1a(ips_adj, "\t\t%u with data size > data length\n");
+ p(ips_adj_hwcsum_clr,
+ "\t\t\t%u packet%s forced to software checksum\n");
+ p1a(ips_toolong, "\t\t%u with ip length > max ip packet size\n");
+ p1a(ips_badhlen, "\t\t%u with header length < data size\n");
+ p1a(ips_badlen, "\t\t%u with data length < header length\n");
+ p1a(ips_badoptions, "\t\t%u with bad options\n");
+ p1a(ips_badvers, "\t\t%u with incorrect version number\n");
+ p(ips_fragments, "\t\t%u fragment%s received\n");
+ p1a(ips_fragdropped, "\t\t\t%u dropped (dup or out of space)\n");
+ p1a(ips_fragtimeout, "\t\t\t%u dropped after timeout\n");
+ p1a(ips_reassembled, "\t\t\t%u reassembled ok\n");
+ p(ips_delivered, "\t\t%u packet%s for this host\n");
+ p(ips_noproto, "\t\t%u packet%s for unknown/unsupported protocol\n");
+ p(ips_forward, "\t\t%u packet%s forwarded");
+ p(ips_fastforward, " (%u packet%s fast forwarded)");
+ if (IPDIFF(ips_forward) || sflag <= 1)
+ putchar('\n');
+ p(ips_cantforward, "\t\t%u packet%s not forwardable\n");
+ p(ips_notmember,
+ "\t\t%u packet%s received for unknown multicast group\n");
+ p(ips_redirectsent, "\t\t%u redirect%s sent\n");
+ p(ips_rxc_collisions, "\t\t%u input packet%s not chained due to collision\n");
+ p(ips_rxc_chained, "\t\t%u input packet%s processed in a chain\n");
+ p(ips_rxc_notchain, "\t\t%u input packet%s unable to chain\n");
+ p(ips_rxc_chainsz_gt2,
+ "\t\t%u input packet chain%s processed with length greater than 2\n");
+ p(ips_rxc_chainsz_gt4,
+ "\t\t%u input packet chain%s processed with length greater than 4\n");
+ p(ips_rxc_notlist,
+ "\t\t%u input packet%s did not go through list processing path\n");
+
+ p(ips_rcv_if_weak_match,
+ "\t\t%u input packet%s that passed the weak ES interface address match\n");
+ p(ips_rcv_if_no_match,
+ "\t\t%u input packet%s with no interface address match\n");
+
+#define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
+ if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
+ printf("\tInput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
+ INPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
+ INPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
+ INPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
+ INPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
+ }
+#undef INPERFDIFF
+
+ p(ips_localout, "\t%u packet%s sent from this host\n");
+ p(ips_rawout, "\t\t%u packet%s sent with fabricated ip header\n");
+ p(ips_odropped,
+ "\t\t%u output packet%s dropped due to no bufs, etc.\n");
+ p(ips_noroute, "\t\t%u output packet%s discarded due to no route\n");
+ p(ips_fragmented, "\t\t%u output datagram%s fragmented\n");
+ p(ips_ofragments, "\t\t%u fragment%s created\n");
+ p(ips_cantfrag, "\t\t%u datagram%s that can't be fragmented\n");
+ p(ips_nogif, "\t\t%u tunneling packet%s that can't find gif\n");
+ p(ips_badaddr, "\t\t%u datagram%s with bad address in header\n");
+ p(ips_pktdropcntrl,
+ "\t\t%u packet%s dropped due to no bufs for control data\n");
+ p(ips_necp_policy_drop, "\t\t%u packet%s dropped due to NECP policy\n");
+ p2(ips_snd_swcsum, ips_snd_swcsum_bytes,
+ "\t\t%u header%s (%u byte%s) checksummed in software\n");
+
+#define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
+ if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
+ printf("\tOutput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
+ OUTPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
+ OUTPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
+ OUTPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
+ OUTPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
+ }
+#undef OUTPERFDIFF
+
+ if (interval > 0) {
+ bcopy(&ipstat, &pipstat, ipstat_len);
+ bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
+ bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
+ }
+
+#undef IPDIFF
+#undef p
+#undef p1a
+#undef p2
+}
+
+/*
+ * Dump ARP statistics structure.
+ */
+void
+arp_stats(uint32_t off, char *name, int af)
+{
+ static struct arpstat parpstat;
+ struct arpstat arpstat;
+ size_t len = sizeof (arpstat);
+
+ if (sysctlbyname("net.link.ether.inet.stats", &arpstat,
+ &len, 0, 0) < 0) {
+ warn("sysctl: net.link.ether.inet.stats");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ARPDIFF(f) (arpstat.f - parpstat.f)
+#define p(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), plural(ARPDIFF(f)))
+#define p2(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), pluralies(ARPDIFF(f)))
+#define p3(f, m) if (ARPDIFF(f) || sflag <= 1) \
+ printf(m, ARPDIFF(f), plural(ARPDIFF(f)), pluralies(ARPDIFF(f)))
+
+ p(txrequests, "\t%u broadast ARP request%s sent\n");
+ p(txurequests, "\t%u unicast ARP request%s sent\n");
+ p2(txreplies, "\t%u ARP repl%s sent\n");
+ p(txannounces, "\t%u ARP announcement%s sent\n");
+ p(rxrequests, "\t%u ARP request%s received\n");
+ p2(rxreplies, "\t%u ARP repl%s received\n");
+ p(received, "\t%u total ARP packet%s received\n");
+ p(txconflicts, "\t%u ARP conflict probe%s sent\n");
+ p(invalidreqs, "\t%u invalid ARP resolve request%s\n");
+ p(reqnobufs, "\t%u total packet%s dropped due to lack of memory\n");
+ p3(held, "\t%u total packet%s held awaiting ARP repl%s\n");
+ p(dropped, "\t%u total packet%s dropped due to no ARP entry\n");
+ p(purged, "\t%u total packet%s dropped during ARP entry removal\n");
+ p2(timeouts, "\t%u ARP entr%s timed out\n");
+ p(dupips, "\t%u Duplicate IP%s seen\n");
+
+ if (interval > 0)
+ bcopy(&arpstat, &parpstat, len);
+
+#undef ARPDIFF
+#undef p
+#undef p2
+}
+
+static char *icmpnames[] = {
+ "echo reply",
+ "#1",
+ "#2",
+ "destination unreachable",
+ "source quench",
+ "routing redirect",
+ "#6",
+ "#7",
+ "echo",
+ "router advertisement",
+ "router solicitation",
+ "time exceeded",
+ "parameter problem",
+ "time stamp",
+ "time stamp reply",
+ "information request",
+ "information request reply",
+ "address mask request",
+ "address mask reply",
+};
+
+/*
+ * Dump ICMP statistics.
+ */
+void
+icmp_stats(uint32_t off , char *name, int af )
+{
+ static struct icmpstat picmpstat;
+ struct icmpstat icmpstat;
+ int i, first;
+ int mib[4]; /* CTL_NET + PF_INET + IPPROTO_ICMP + req */
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_ICMP;
+ mib[3] = ICMPCTL_STATS;
+
+ len = sizeof icmpstat;
+ memset(&icmpstat, 0, len);
+ if (sysctl(mib, 4, &icmpstat, &len, (void *)0, 0) < 0)
+ return; /* XXX should complain, but not traditional */
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ICMPDIFF(f) (icmpstat.f - picmpstat.f)
+#define p(f, m) if (ICMPDIFF(f) || sflag <= 1) \
+ printf(m, ICMPDIFF(f), plural(ICMPDIFF(f)))
+#define p1a(f, m) if (ICMPDIFF(f) || sflag <= 1) \
+ printf(m, ICMPDIFF(f))
+
+ p(icps_error, "\t%u call%s to icmp_error\n");
+ p(icps_oldicmp,
+ "\t%u error%s not generated 'cuz old message was icmp\n");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (ICMPDIFF(icps_outhist[i]) != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %u\n", icmpnames[i],
+ ICMPDIFF(icps_outhist[i]));
+ }
+ p(icps_badcode, "\t%u message%s with bad code fields\n");
+ p(icps_tooshort, "\t%u message%s < minimum length\n");
+ p(icps_checksum, "\t%u bad checksum%s\n");
+ p(icps_badlen, "\t%u message%s with bad length\n");
+ p1a(icps_bmcastecho, "\t%u multicast echo requests ignored\n");
+ p1a(icps_bmcasttstamp, "\t%u multicast timestamp requests ignored\n");
+ for (first = 1, i = 0; i < ICMP_MAXTYPE + 1; i++)
+ if (ICMPDIFF(icps_inhist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %u\n", icmpnames[i],
+ ICMPDIFF(icps_inhist[i]));
+ }
+ p(icps_reflect, "\t%u message response%s generated\n");
+
+#undef ICMPDIFF
+#undef p
+#undef p1a
+ mib[3] = ICMPCTL_MASKREPL;
+ len = sizeof i;
+ if (sysctl(mib, 4, &i, &len, (void *)0, 0) < 0)
+ return;
+ printf("\tICMP address mask responses are %sabled\n",
+ i ? "en" : "dis");
+
+ if (interval > 0)
+ bcopy(&icmpstat, &picmpstat, sizeof (icmpstat));
+}
+
+/*
+ * Dump IGMP statistics structure.
+ */
+void
+igmp_stats(uint32_t off , char *name, int af )
+{
+ static struct igmpstat_v3 pigmpstat;
+ struct igmpstat_v3 igmpstat;
+ size_t len = sizeof igmpstat;
+
+ if (sysctlbyname("net.inet.igmp.v3stats", &igmpstat, &len, 0, 0) < 0) {
+ warn("sysctl: net.inet.igmp.v3stats");
+ return;
+ }
+
+ if (igmpstat.igps_version != IGPS_VERSION_3) {
+ warnx("%s: version mismatch (%d != %d)", __func__,
+ igmpstat.igps_version, IGPS_VERSION_3);
+ }
+ if (igmpstat.igps_len != IGPS_VERSION3_LEN) {
+ warnx("%s: size mismatch (%d != %d)", __func__,
+ igmpstat.igps_len, IGPS_VERSION3_LEN);
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IGMPDIFF(f) ((uintmax_t)(igmpstat.f - pigmpstat.f))
+#define p64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
+ printf(m, IGMPDIFF(f), plural(IGMPDIFF(f)))
+#define py64(f, m) if (IGMPDIFF(f) || sflag <= 1) \
+ printf(m, IGMPDIFF(f), IGMPDIFF(f) != 1 ? "ies" : "y")
+
+ p64(igps_rcv_total, "\t%ju message%s received\n");
+ p64(igps_rcv_tooshort, "\t%ju message%s received with too few bytes\n");
+ p64(igps_rcv_badttl, "\t%ju message%s received with wrong TTL\n");
+ p64(igps_rcv_badsum, "\t%ju message%s received with bad checksum\n");
+ py64(igps_rcv_v1v2_queries, "\t%ju V1/V2 membership quer%s received\n");
+ py64(igps_rcv_v3_queries, "\t%ju V3 membership quer%s received\n");
+ py64(igps_rcv_badqueries,
+ "\t%ju membership quer%s received with invalid field(s)\n");
+ py64(igps_rcv_gen_queries, "\t%ju general quer%s received\n");
+ py64(igps_rcv_group_queries, "\t%ju group quer%s received\n");
+ py64(igps_rcv_gsr_queries, "\t%ju group-source quer%s received\n");
+ py64(igps_drop_gsr_queries, "\t%ju group-source quer%s dropped\n");
+ p64(igps_rcv_reports, "\t%ju membership report%s received\n");
+ p64(igps_rcv_badreports,
+ "\t%ju membership report%s received with invalid field(s)\n");
+ p64(igps_rcv_ourreports,
+"\t%ju membership report%s received for groups to which we belong\n");
+ p64(igps_rcv_nora, "\t%ju V3 report%s received without Router Alert\n");
+ p64(igps_snd_reports, "\t%ju membership report%s sent\n");
+
+ if (interval > 0)
+ bcopy(&igmpstat, &pigmpstat, len);
+
+#undef IGMPDIFF
+#undef p64
+#undef py64
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ */
+void
+inetprint(struct in_addr *in, int port, char *proto, int numeric_port)
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ if (Wflag)
+ snprintf(line, sizeof(line), "%s.", inetname(in));
+ else
+ snprintf(line, sizeof(line), "%.*s.", (Aflag && !numeric_port) ? 12 : 16, inetname(in));
+ cp = index(line, '\0');
+ if (!numeric_port && port)
+#ifdef _SERVICE_CACHE_
+ sp = _serv_cache_getservbyport(port, proto);
+#else
+ sp = getservbyport((int)port, proto);
+#endif
+ if (sp || port == 0)
+ snprintf(cp, sizeof(line) - (cp - line), "%.15s ", sp ? sp->s_name : "*");
+ else
+ snprintf(cp, sizeof(line) - (cp - line), "%d ", ntohs((u_short)port));
+ width = (Aflag && !Wflag) ? 18 : 22;
+ if (Wflag)
+ printf("%-*s ", width, line);
+ else
+ printf("%-*.*s ", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+char *
+inetname(struct in_addr *inp)
+{
+ register char *cp;
+ static char line[MAXHOSTNAMELEN];
+ struct hostent *hp;
+ struct netent *np;
+
+ cp = 0;
+ if (!nflag && inp->s_addr != INADDR_ANY) {
+ int net = inet_netof(*inp);
+ int lna = inet_lnaof(*inp);
+
+ if (lna == INADDR_ANY) {
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ cp = np->n_name;
+ }
+ if (cp == 0) {
+ hp = gethostbyaddr((char *)inp, sizeof (*inp), AF_INET);
+ if (hp) {
+ cp = hp->h_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ }
+ if (inp->s_addr == INADDR_ANY)
+ strlcpy(line, "*", sizeof(line));
+ else if (cp) {
+ strlcpy(line, cp, sizeof(line));
+ } else {
+ inp->s_addr = ntohl(inp->s_addr);
+#define C(x) ((u_int)((x) & 0xff))
+ snprintf(line, sizeof(line), "%u.%u.%u.%u", C(inp->s_addr >> 24),
+ C(inp->s_addr >> 16), C(inp->s_addr >> 8), C(inp->s_addr));
+ }
+ return (line);
+}
diff --git a/network_cmds/netstat.tproj/inet6.c b/network_cmds/netstat.tproj/inet6.c
new file mode 100644
index 0000000..4bc757c
--- /dev/null
+++ b/network_cmds/netstat.tproj/inet6.c
@@ -0,0 +1,1333 @@
+/*
+ * Copyright (c) 2008-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* BSDI inet.c,v 2.3 1995/10/24 02:19:29 prb Exp */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/netstat/inet6.c,v 1.3.2.9 2001/08/10 09:07:09 ru Exp $
+ */
+
+#ifdef INET6
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/net_perf.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/in_systm.h>
+#include <netinet6/in6_pcb.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/ip6_var.h>
+#include <netinet6/raw_ip6.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#if defined(__APPLE__) && !defined(__unused)
+#define __unused
+#endif
+
+char *inet6name (struct in6_addr *);
+void inet6print (struct in6_addr *, int, char *, int);
+
+static char *ip6nh[] = {
+ "hop by hop",
+ "ICMP",
+ "IGMP",
+ "#3",
+ "IP",
+ "#5",
+ "TCP",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "UDP",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "IDP",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "TP",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "IP6",
+ "#42",
+ "routing",
+ "fragment",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "ESP",
+ "AH",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "ICMP6",
+ "no next header",
+ "destination option",
+ "#61",
+ "mobility",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "ISOIP",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "OSPF",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "Ethernet",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "PIM",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "#128",
+ "#129",
+ "#130",
+ "#131",
+ "#132",
+ "#133",
+ "#134",
+ "#135",
+ "#136",
+ "#137",
+ "#138",
+ "#139",
+ "#140",
+ "#141",
+ "#142",
+ "#143",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+
+static const char *srcrulenames[IP6S_SRCRULE_COUNT] = {
+ "default", // IP6S_SRCRULE_0
+ "prefer same address", // IP6S_SRCRULE_1
+ "prefer appropriate scope", // IP6S_SRCRULE_2
+ "avoid deprecated addresses", // IP6S_SRCRULE_3
+ "prefer home addresses", // IP6S_SRCRULE_4
+ "prefer outgoing interface", // IP6S_SRCRULE_5
+ "prefer matching label", // IP6S_SRCRULE_6
+ "prefer temporary addresses", // IP6S_SRCRULE_7
+ "prefer addresses on alive interfaces", // IP6S_SRCRULE_7x
+ "use longest matching prefix", // IP6S_SRCRULE_8
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/*
+ * Dump IP6 statistics structure.
+ */
+void
+ip6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct ip6stat pip6stat;
+ struct ip6stat ip6stat;
+ int first, i;
+ int mib[4];
+ size_t len;
+ static net_perf_t pout_net_perf, pin_net_perf;
+ net_perf_t out_net_perf, in_net_perf;
+ size_t out_net_perf_len = sizeof (out_net_perf);
+ size_t in_net_perf_len = sizeof (in_net_perf);
+
+ if (sysctlbyname("net.inet6.ip6.output_perf_data", &out_net_perf, &out_net_perf_len, 0, 0) < 0) {
+ perror("sysctl: net.inet6.ip6.output_perf_data");
+ return;
+ }
+
+ if (sysctlbyname("net.inet6.ip6.input_perf_data", &in_net_perf, &in_net_perf_len, 0, 0) < 0) {
+ perror("sysctl: net.inet6.ip6.input_perf_data");
+ return;
+ }
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_STATS;
+
+ len = sizeof ip6stat;
+ memset(&ip6stat, 0, len);
+ if (sysctl(mib, 4, &ip6stat, &len, (void *)0, 0) < 0)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define IP6DIFF(f) (ip6stat.f - pip6stat.f)
+#define p(f, m) if (IP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)IP6DIFF(f), plural(IP6DIFF(f)))
+#define p1a(f, m) if (IP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)IP6DIFF(f))
+
+ p(ip6s_total, "\t%llu total packet%s received\n");
+ p1a(ip6s_toosmall, "\t\t%llu with size smaller than minimum\n");
+ p1a(ip6s_tooshort, "\t\t%llu with data size < data length\n");
+ p1a(ip6s_adj, "\t\t%llu with data size > data length\n");
+ p(ip6s_adj_hwcsum_clr,
+ "\t\t\t%llu packet%s forced to software checksum\n");
+ p1a(ip6s_badoptions, "\t\t%llu with bad options\n");
+ p1a(ip6s_badvers, "\t\t%llu with incorrect version number\n");
+ p(ip6s_fragments, "\t\t%llu fragment%s received\n");
+ p1a(ip6s_fragdropped,
+ "\t\t\t%llu dropped (dup or out of space)\n");
+ p1a(ip6s_fragtimeout, "\t\t\t%llu dropped after timeout\n");
+ p1a(ip6s_fragoverflow, "\t\t\t%llu exceeded limit\n");
+ p1a(ip6s_reassembled, "\t\t\t%llu reassembled ok\n");
+ p1a(ip6s_atmfrag_rcvd, "\t\t\t%llu atomic fragments received\n");
+ p(ip6s_delivered, "\t\t%llu packet%s for this host\n");
+ p(ip6s_forward, "\t\t%llu packet%s forwarded\n");
+ p(ip6s_cantforward, "\t\t%llu packet%s not forwardable\n");
+ p(ip6s_redirectsent, "\t\t%llu redirect%s sent\n");
+ p(ip6s_notmember, "\t\t%llu multicast packet%s which we don't join\n");
+ p(ip6s_exthdrtoolong,
+ "\t\t%llu packet%s whose headers are not continuous\n");
+ p(ip6s_nogif, "\t\t%llu tunneling packet%s that can't find gif\n");
+ p(ip6s_toomanyhdr,
+ "\t\t%llu packet%s discarded due to too may headers\n");
+ p1a(ip6s_forward_cachehit, "\t\t%llu forward cache hit\n");
+ p1a(ip6s_forward_cachemiss, "\t\t%llu forward cache miss\n");
+ p(ip6s_pktdropcntrl,
+ "\t\t%llu packet%s dropped due to no bufs for control data\n");
+ /* CLAT46 input stats */
+ p(ip6s_clat464_in_tooshort_drop,
+ "\t\t%llu input packet%s dropped due to too short length \n");
+ p(ip6s_clat464_in_nov6addr_drop,
+ "\t\t%llu input packet%s dropped due to missing CLAT46 IPv6 address\n");
+ p(ip6s_clat464_in_nov4addr_drop,
+ "\t\t%llu input packet%s dropped due to missing CLAT46 IPv4 address\n");
+ p(ip6s_clat464_in_v4synthfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 IPv4 address derivation failure\n");
+ p(ip6s_clat464_in_64transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 IP header translation failure\n");
+ p(ip6s_clat464_in_64proto_transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 protocol translation failure\n");
+ p(ip6s_clat464_in_64frag_transfail_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 fragment translation failure\n");
+ p(ip6s_clat464_in_invalpbuf_drop,
+ "\t\t%llu input packet%s dropped due to invalid pbuf\n");
+ p(ip6s_clat464_in_v4_drop,
+ "\t\t%llu input IPv4 packet%s dropped on CLAT46 enabled interface\n");
+ p(ip6s_clat464_in_drop,
+ "\t\t%llu input packet%s dropped due to CLAT46 failures\n");
+ p(ip6s_clat464_in_success,
+ "\t\t%llu input packet%s successfully translated from IPv6 to IPv4\n");
+
+#define INPERFDIFF(f) (in_net_perf.f - pin_net_perf.f)
+ if (INPERFDIFF(np_total_pkts) > 0 && in_net_perf.np_total_usecs > 0) {
+ printf("\tInput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", INPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", INPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)in_net_perf.np_total_usecs/(double)in_net_perf.np_total_pkts);
+ printf("\t\tPerformance Histogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", in_net_perf.np_hist_bars[0],
+ INPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[0], in_net_perf.np_hist_bars[1],
+ INPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[1], in_net_perf.np_hist_bars[2],
+ INPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ in_net_perf.np_hist_bars[2], in_net_perf.np_hist_bars[3],
+ INPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ in_net_perf.np_hist_bars[3], INPERFDIFF(np_hist5));
+ }
+#undef INPERFDIFF
+
+ p(ip6s_localout, "\t%llu packet%s sent from this host\n");
+ p(ip6s_rawout, "\t\t%llu packet%s sent with fabricated ip header\n");
+ p(ip6s_odropped,
+ "\t\t%llu output packet%s dropped due to no bufs, etc.\n");
+ p(ip6s_noroute, "\t\t%llu output packet%s discarded due to no route\n");
+ p(ip6s_fragmented, "\t\t%llu output datagram%s fragmented\n");
+ p(ip6s_ofragments, "\t\t%llu fragment%s created\n");
+ p(ip6s_cantfrag, "\t\t%llu datagram%s that can't be fragmented\n");
+ p(ip6s_badscope, "\t\t%llu packet%s that violated scope rules\n");
+ p(ip6s_necp_policy_drop, "\t\t%llu packet%s dropped due to NECP policy\n");
+ /* CLAT46 output stats */
+ p(ip6s_clat464_out_nov6addr_drop,
+ "\t\t%llu output packet%s dropped due to missing CLAT46 IPv6 address\n");
+ p(ip6s_clat464_out_v6synthfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 IPv6 address synthesis failure\n");
+ p(ip6s_clat464_out_46transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 IP header translation failure\n");
+ p(ip6s_clat464_out_46proto_transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 protocol translation failure\n");
+ p(ip6s_clat464_out_46frag_transfail_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 fragment translation failure\n");
+ p(ip6s_clat464_out_invalpbuf_drop,
+ "\t\t%llu output packet%s dropped due to invalid pbuf\n");
+ p(ip6s_clat464_out_drop,
+ "\t\t%llu output packet%s dropped due to CLAT46 failures\n");
+ p(ip6s_clat464_out_success,
+ "\t\t%llu output packet%s successfully translated from IPv4 to IPv6\n");
+ p(ip6s_rcv_if_weak_match,
+ "\t\t%llu input packet%s that passed the weak ES interface address match\n");
+ p(ip6s_rcv_if_no_match,
+ "\t\t%llu input packet%s with no interface address match\n");
+
+#define OUTPERFDIFF(f) (out_net_perf.f - pout_net_perf.f)
+ if (OUTPERFDIFF(np_total_pkts) > 0 && out_net_perf.np_total_usecs > 0) {
+ printf("\tOutput Performance Stats:\n");
+ printf("\t\t%llu total packets measured\n", OUTPERFDIFF(np_total_pkts));
+ printf("\t\t%llu total usec elapsed\n", OUTPERFDIFF(np_total_usecs));
+ printf("\t\t%f usec per packet\n",
+ (double)out_net_perf.np_total_usecs/(double)out_net_perf.np_total_pkts);
+ printf("\t\tHistogram:\n");
+ printf("\t\t\t x <= %u: %llu\n", out_net_perf.np_hist_bars[0],
+ OUTPERFDIFF(np_hist1));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[0], out_net_perf.np_hist_bars[1],
+ OUTPERFDIFF(np_hist2));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[1], out_net_perf.np_hist_bars[2],
+ OUTPERFDIFF(np_hist3));
+ printf("\t\t\t %u < x <= %u: %llu\n",
+ out_net_perf.np_hist_bars[2], out_net_perf.np_hist_bars[3],
+ OUTPERFDIFF(np_hist4));
+ printf("\t\t\t %u < x: %llu\n",
+ out_net_perf.np_hist_bars[3], OUTPERFDIFF(np_hist5));
+ }
+#undef OUTPERFDIFF
+
+ for (first = 1, i = 0; i < 256; i++)
+ if (IP6DIFF(ip6s_nxthist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", ip6nh[i],
+ (unsigned long long)IP6DIFF(ip6s_nxthist[i]));
+ }
+ printf("\tMbuf statistics:\n");
+ printf("\t\t%llu one mbuf\n", (unsigned long long)IP6DIFF(ip6s_m1));
+ for (first = 1, i = 0; i < 32; i++) {
+ char ifbuf[IFNAMSIZ];
+ if (IP6DIFF(ip6s_m2m[i]) != 0) {
+ if (first) {
+ printf("\t\ttwo or more mbuf:\n");
+ first = 0;
+ }
+ printf("\t\t\t%s= %llu\n",
+ if_indextoname(i, ifbuf),
+ (unsigned long long)IP6DIFF(ip6s_m2m[i]));
+ }
+ }
+ printf("\t\t%llu one ext mbuf\n",
+ (unsigned long long)IP6DIFF(ip6s_mext1));
+ printf("\t\t%llu two or more ext mbuf\n",
+ (unsigned long long)IP6DIFF(ip6s_mext2m));
+
+ /* for debugging source address selection */
+#define PRINT_SCOPESTAT(s,i) do {\
+ switch(i) { /* XXX hardcoding in each case */\
+ case 1:\
+ p(s, "\t\t\t%llu node-local%s\n");\
+ break;\
+ case 2:\
+ p(s,"\t\t\t%llu link-local%s\n");\
+ break;\
+ case 5:\
+ p(s,"\t\t\t%llu site-local%s\n");\
+ break;\
+ case 14:\
+ p(s,"\t\t\t%llu global%s\n");\
+ break;\
+ default:\
+ printf("\t\t\t%llu addresses scope=%x\n",\
+ (unsigned long long)IP6DIFF(s), i);\
+ }\
+ } while (0);
+
+ p(ip6s_sources_none,
+ "\t\t%llu failure%s of source address selection\n");
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_sameif[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses on an outgoing I/F\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_sameif[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_otherif[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses on a non-outgoing I/F\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_otherif[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_samescope[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses of same scope\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_samescope[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_otherscope[i]) || 1) {
+ if (first) {
+ printf("\t\tsource addresses of a different scope\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_otherscope[i], i);
+ }
+ }
+ for (first = 1, i = 0; i < SCOPE6_ID_MAX; i++) {
+ if (IP6DIFF(ip6s_sources_deprecated[i]) || 1) {
+ if (first) {
+ printf("\t\tdeprecated source addresses\n");
+ first = 0;
+ }
+ PRINT_SCOPESTAT(ip6s_sources_deprecated[i], i);
+ }
+ }
+#define PRINT_SRCRULESTAT(s,i) do {\
+ if (srcrulenames[i] != NULL) \
+ printf("\t\t\t%llu rule%s %s\n", \
+ (unsigned long long)IP6DIFF(s), \
+ plural(IP6DIFF(s)), \
+ srcrulenames[i]); \
+} while (0);
+
+ for (first = 1, i = 0; i < IP6S_SRCRULE_COUNT; i++) {
+ if (IP6DIFF(ip6s_sources_rule[i]) || 1) {
+ if (first) {
+ printf("\t\tsource address selection\n");
+ first = 0;
+ }
+ PRINT_SRCRULESTAT(ip6s_sources_rule[i], i);
+ }
+ }
+
+ p(ip6s_dad_collide, "\t\t%llu duplicate address detection collision%s\n");
+
+ p(ip6s_dad_loopcount, "\t\t%llu duplicate address detection NS loop%s\n");
+
+ p(ip6s_sources_skip_expensive_secondary_if, "\t\t%llu time%s ignored source on secondary expensive I/F\n");
+
+ if (interval > 0) {
+ bcopy(&ip6stat, &pip6stat, len);
+ bcopy(&in_net_perf, &pin_net_perf, in_net_perf_len);
+ bcopy(&out_net_perf, &pout_net_perf, out_net_perf_len);
+ }
+#undef IP6DIFF
+#undef p
+#undef p1a
+}
+
+/*
+ * Dump IPv6 per-interface statistics based on RFC 2465.
+ */
+void
+ip6_ifstats(char *ifname)
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_stat.f, plural(ifr.ifr_ifru.ifru_stat.f))
+#define p_5(f, m) if (ifr.ifr_ifru.ifru_stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ip6stat.f)
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ printf("ip6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_IN6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_IN6)");
+ goto end;
+ }
+
+ p(ifs6_in_receive, "\t%llu total input datagram%s\n");
+ p(ifs6_in_hdrerr, "\t%llu datagram%s with invalid header received\n");
+ p(ifs6_in_toobig, "\t%llu datagram%s exceeded MTU received\n");
+ p(ifs6_in_noroute, "\t%llu datagram%s with no route received\n");
+ p(ifs6_in_addrerr, "\t%llu datagram%s with invalid dst received\n");
+ p(ifs6_in_protounknown, "\t%llu datagram%s with unknown proto received\n");
+ p(ifs6_in_truncated, "\t%llu truncated datagram%s received\n");
+ p(ifs6_in_discard, "\t%llu input datagram%s discarded\n");
+ p(ifs6_in_deliver,
+ "\t%llu datagram%s delivered to an upper layer protocol\n");
+ p(ifs6_out_forward, "\t%llu datagram%s forwarded to this interface\n");
+ p(ifs6_out_request,
+ "\t%llu datagram%s sent from an upper layer protocol\n");
+ p(ifs6_out_discard, "\t%llu total discarded output datagram%s\n");
+ p(ifs6_out_fragok, "\t%llu output datagram%s fragmented\n");
+ p(ifs6_out_fragfail, "\t%llu output datagram%s failed on fragment\n");
+ p(ifs6_out_fragcreat, "\t%llu output datagram%s succeeded on fragment\n");
+ p(ifs6_reass_reqd, "\t%llu incoming datagram%s fragmented\n");
+ p(ifs6_reass_ok, "\t%llu datagram%s reassembled\n");
+ p(ifs6_atmfrag_rcvd, "\t%llu atomic fragments%s received\n");
+ p(ifs6_reass_fail, "\t%llu datagram%s failed on reassembling\n");
+ p(ifs6_in_mcast, "\t%llu multicast datagram%s received\n");
+ p(ifs6_out_mcast, "\t%llu multicast datagram%s sent\n");
+
+ p(ifs6_cantfoward_icmp6, "\t%llu ICMPv6 packet%s received for unreachable destination\n");
+ p(ifs6_addr_expiry_cnt, "\t%llu address expiry event%s reported\n");
+ p(ifs6_pfx_expiry_cnt, "\t%llu prefix expiry event%s reported\n");
+ p(ifs6_defrtr_expiry_cnt, "\t%llu default router expiry event%s reported\n");
+ end:
+ close(s);
+
+#undef p
+#undef p_5
+}
+
+static char *icmp6names[] = {
+ "#0",
+ "unreach",
+ "packet too big",
+ "time exceed",
+ "parameter problem",
+ "#5",
+ "#6",
+ "#7",
+ "#8",
+ "#9",
+ "#10",
+ "#11",
+ "#12",
+ "#13",
+ "#14",
+ "#15",
+ "#16",
+ "#17",
+ "#18",
+ "#19",
+ "#20",
+ "#21",
+ "#22",
+ "#23",
+ "#24",
+ "#25",
+ "#26",
+ "#27",
+ "#28",
+ "#29",
+ "#30",
+ "#31",
+ "#32",
+ "#33",
+ "#34",
+ "#35",
+ "#36",
+ "#37",
+ "#38",
+ "#39",
+ "#40",
+ "#41",
+ "#42",
+ "#43",
+ "#44",
+ "#45",
+ "#46",
+ "#47",
+ "#48",
+ "#49",
+ "#50",
+ "#51",
+ "#52",
+ "#53",
+ "#54",
+ "#55",
+ "#56",
+ "#57",
+ "#58",
+ "#59",
+ "#60",
+ "#61",
+ "#62",
+ "#63",
+ "#64",
+ "#65",
+ "#66",
+ "#67",
+ "#68",
+ "#69",
+ "#70",
+ "#71",
+ "#72",
+ "#73",
+ "#74",
+ "#75",
+ "#76",
+ "#77",
+ "#78",
+ "#79",
+ "#80",
+ "#81",
+ "#82",
+ "#83",
+ "#84",
+ "#85",
+ "#86",
+ "#87",
+ "#88",
+ "#89",
+ "#80",
+ "#91",
+ "#92",
+ "#93",
+ "#94",
+ "#95",
+ "#96",
+ "#97",
+ "#98",
+ "#99",
+ "#100",
+ "#101",
+ "#102",
+ "#103",
+ "#104",
+ "#105",
+ "#106",
+ "#107",
+ "#108",
+ "#109",
+ "#110",
+ "#111",
+ "#112",
+ "#113",
+ "#114",
+ "#115",
+ "#116",
+ "#117",
+ "#118",
+ "#119",
+ "#120",
+ "#121",
+ "#122",
+ "#123",
+ "#124",
+ "#125",
+ "#126",
+ "#127",
+ "echo",
+ "echo reply",
+ "multicast listener query",
+ "MLDv1 listener report",
+ "MLDv1 listener done",
+ "router solicitation",
+ "router advertisement",
+ "neighbor solicitation",
+ "neighbor advertisement",
+ "redirect",
+ "router renumbering",
+ "node information request",
+ "node information reply",
+ "inverse neighbor solicitation",
+ "inverse neighbor advertisement",
+ "MLDv2 listener report",
+ "#144",
+ "#145",
+ "#146",
+ "#147",
+ "#148",
+ "#149",
+ "#150",
+ "#151",
+ "#152",
+ "#153",
+ "#154",
+ "#155",
+ "#156",
+ "#157",
+ "#158",
+ "#159",
+ "#160",
+ "#161",
+ "#162",
+ "#163",
+ "#164",
+ "#165",
+ "#166",
+ "#167",
+ "#168",
+ "#169",
+ "#170",
+ "#171",
+ "#172",
+ "#173",
+ "#174",
+ "#175",
+ "#176",
+ "#177",
+ "#178",
+ "#179",
+ "#180",
+ "#181",
+ "#182",
+ "#183",
+ "#184",
+ "#185",
+ "#186",
+ "#187",
+ "#188",
+ "#189",
+ "#180",
+ "#191",
+ "#192",
+ "#193",
+ "#194",
+ "#195",
+ "#196",
+ "#197",
+ "#198",
+ "#199",
+ "#200",
+ "#201",
+ "#202",
+ "#203",
+ "#204",
+ "#205",
+ "#206",
+ "#207",
+ "#208",
+ "#209",
+ "#210",
+ "#211",
+ "#212",
+ "#213",
+ "#214",
+ "#215",
+ "#216",
+ "#217",
+ "#218",
+ "#219",
+ "#220",
+ "#221",
+ "#222",
+ "#223",
+ "#224",
+ "#225",
+ "#226",
+ "#227",
+ "#228",
+ "#229",
+ "#230",
+ "#231",
+ "#232",
+ "#233",
+ "#234",
+ "#235",
+ "#236",
+ "#237",
+ "#238",
+ "#239",
+ "#240",
+ "#241",
+ "#242",
+ "#243",
+ "#244",
+ "#245",
+ "#246",
+ "#247",
+ "#248",
+ "#249",
+ "#250",
+ "#251",
+ "#252",
+ "#253",
+ "#254",
+ "#255",
+};
+
+/*
+ * Dump ICMP6 statistics.
+ */
+void
+icmp6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct icmp6stat picmp6stat;
+ struct icmp6stat icmp6stat;
+ register int i, first;
+ int mib[4];
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_ICMPV6;
+ mib[3] = ICMPV6CTL_STATS;
+
+ len = sizeof icmp6stat;
+ memset(&icmp6stat, 0, len);
+ if (sysctl(mib, 4, &icmp6stat, &len, (void *)0, 0) < 0)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define ICMP6DIFF(f) (icmp6stat.f - picmp6stat.f)
+#define p(f, m) if (ICMP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)ICMP6DIFF(f), plural(ICMP6DIFF(f)))
+#define p_5(f, m) printf(m, (unsigned long long)ICMP6DIFF(f))
+
+ p(icp6s_error, "\t%llu call%s to icmp_error\n");
+ p(icp6s_canterror,
+ "\t%llu error%s not generated because old message was icmp error or so\n");
+ p(icp6s_toofreq,
+ "\t%llu error%s not generated because rate limitation\n");
+#define NELEM (sizeof(icmp6stat.icp6s_outhist)/sizeof(icmp6stat.icp6s_outhist[0]))
+ for (first = 1, i = 0; i < NELEM; i++)
+ if (ICMP6DIFF(icp6s_outhist[i]) != 0) {
+ if (first) {
+ printf("\tOutput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", icmp6names[i],
+ (unsigned long long)ICMP6DIFF(icp6s_outhist[i]));
+ }
+#undef NELEM
+ p(icp6s_badcode, "\t%llu message%s with bad code fields\n");
+ p(icp6s_tooshort, "\t%llu message%s < minimum length\n");
+ p(icp6s_checksum, "\t%llu bad checksum%s\n");
+ p(icp6s_badlen, "\t%llu message%s with bad length\n");
+#define NELEM (sizeof(icmp6stat.icp6s_inhist)/sizeof(icmp6stat.icp6s_inhist[0]))
+ for (first = 1, i = 0; i < NELEM; i++)
+ if (ICMP6DIFF(icp6s_inhist[i]) != 0) {
+ if (first) {
+ printf("\tInput histogram:\n");
+ first = 0;
+ }
+ printf("\t\t%s: %llu\n", icmp6names[i],
+ (unsigned long long)ICMP6DIFF(icp6s_inhist[i]));
+ }
+#undef NELEM
+ printf("\tHistogram of error messages to be generated:\n");
+ p_5(icp6s_odst_unreach_noroute, "\t\t%llu no route\n");
+ p_5(icp6s_odst_unreach_admin, "\t\t%llu administratively prohibited\n");
+ p_5(icp6s_odst_unreach_beyondscope, "\t\t%llu beyond scope\n");
+ p_5(icp6s_odst_unreach_addr, "\t\t%llu address unreachable\n");
+ p_5(icp6s_odst_unreach_noport, "\t\t%llu port unreachable\n");
+ p_5(icp6s_opacket_too_big, "\t\t%llu packet too big\n");
+ p_5(icp6s_otime_exceed_transit, "\t\t%llu time exceed transit\n");
+ p_5(icp6s_otime_exceed_reassembly, "\t\t%llu time exceed reassembly\n");
+ p_5(icp6s_oparamprob_header, "\t\t%llu erroneous header field\n");
+ p_5(icp6s_oparamprob_nextheader, "\t\t%llu unrecognized next header\n");
+ p_5(icp6s_oparamprob_option, "\t\t%llu unrecognized option\n");
+ p_5(icp6s_oredirect, "\t\t%llu redirect\n");
+ p_5(icp6s_ounknown, "\t\t%llu unknown\n");
+
+ p(icp6s_reflect, "\t%llu message response%s generated\n");
+ p(icp6s_nd_toomanyopt, "\t%llu message%s with too many ND options\n");
+ p(icp6s_nd_badopt, "\t%qu message%s with bad ND options\n");
+ p(icp6s_badns, "\t%qu bad neighbor solicitation message%s\n");
+ p(icp6s_badna, "\t%qu bad neighbor advertisement message%s\n");
+ p(icp6s_badrs, "\t%qu bad router solicitation message%s\n");
+ p(icp6s_badra, "\t%qu bad router advertisement message%s\n");
+ p(icp6s_badredirect, "\t%qu bad redirect message%s\n");
+ p(icp6s_pmtuchg, "\t%llu path MTU change%s\n");
+ p(icp6s_rfc6980_drop, "\t%qu dropped fragmented NDP message%s\n");
+
+ if (interval > 0)
+ bcopy(&icmp6stat, &picmp6stat, len);
+
+#undef ICMP6DIFF
+#undef p
+#undef p_5
+}
+
+/*
+ * Dump ICMPv6 per-interface statistics based on RFC 2466.
+ */
+void
+icmp6_ifstats(char *ifname)
+{
+ struct in6_ifreq ifr;
+ int s;
+#define p(f, m) if (ifr.ifr_ifru.ifru_icmp6stat.f || sflag <= 1) \
+ printf(m, (unsigned long long)ifr.ifr_ifru.ifru_icmp6stat.f, plural(ifr.ifr_ifru.ifru_icmp6stat.f))
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("Warning: socket(AF_INET6)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ printf("icmp6 on %s:\n", ifr.ifr_name);
+
+ if (ioctl(s, SIOCGIFSTAT_ICMP6, (char *)&ifr) < 0) {
+ perror("Warning: ioctl(SIOCGIFSTAT_ICMP6)");
+ goto end;
+ }
+
+ p(ifs6_in_msg, "\t%llu total input message%s\n");
+ p(ifs6_in_error, "\t%llu total input error message%s\n");
+ p(ifs6_in_dstunreach, "\t%llu input destination unreachable error%s\n");
+ p(ifs6_in_adminprohib, "\t%llu input administratively prohibited error%s\n");
+ p(ifs6_in_timeexceed, "\t%llu input time exceeded error%s\n");
+ p(ifs6_in_paramprob, "\t%llu input parameter problem error%s\n");
+ p(ifs6_in_pkttoobig, "\t%llu input packet too big error%s\n");
+ p(ifs6_in_echo, "\t%llu input echo request%s\n");
+ p(ifs6_in_echoreply, "\t%llu input echo reply%s\n");
+ p(ifs6_in_routersolicit, "\t%llu input router solicitation%s\n");
+ p(ifs6_in_routeradvert, "\t%llu input router advertisement%s\n");
+ p(ifs6_in_neighborsolicit, "\t%llu input neighbor solicitation%s\n");
+ p(ifs6_in_neighboradvert, "\t%llu input neighbor advertisement%s\n");
+ p(ifs6_in_redirect, "\t%llu input redirect%s\n");
+ p(ifs6_in_mldquery, "\t%llu input MLD query%s\n");
+ p(ifs6_in_mldreport, "\t%llu input MLD report%s\n");
+ p(ifs6_in_mlddone, "\t%llu input MLD done%s\n");
+
+ p(ifs6_out_msg, "\t%llu total output message%s\n");
+ p(ifs6_out_error, "\t%llu total output error message%s\n");
+ p(ifs6_out_dstunreach, "\t%llu output destination unreachable error%s\n");
+ p(ifs6_out_adminprohib, "\t%llu output administratively prohibited error%s\n");
+ p(ifs6_out_timeexceed, "\t%llu output time exceeded error%s\n");
+ p(ifs6_out_paramprob, "\t%llu output parameter problem error%s\n");
+ p(ifs6_out_pkttoobig, "\t%llu output packet too big error%s\n");
+ p(ifs6_out_echo, "\t%llu output echo request%s\n");
+ p(ifs6_out_echoreply, "\t%llu output echo reply%s\n");
+ p(ifs6_out_routersolicit, "\t%llu output router solicitation%s\n");
+ p(ifs6_out_routeradvert, "\t%llu output router advertisement%s\n");
+ p(ifs6_out_neighborsolicit, "\t%llu output neighbor solicitation%s\n");
+ p(ifs6_out_neighboradvert, "\t%llu output neighbor advertisement%s\n");
+ p(ifs6_out_redirect, "\t%llu output redirect%s\n");
+ p(ifs6_out_mldquery, "\t%llu output MLD query%s\n");
+ p(ifs6_out_mldreport, "\t%llu output MLD report%s\n");
+ p(ifs6_out_mlddone, "\t%llu output MLD done%s\n");
+
+ end:
+ close(s);
+#undef p
+}
+
+/*
+ * Dump raw ip6 statistics structure.
+ */
+void
+rip6_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct rip6stat prip6stat;
+ struct rip6stat rip6stat;
+ u_quad_t delivered;
+ int mib[4];
+ size_t l;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET6;
+ mib[2] = IPPROTO_IPV6;
+ mib[3] = IPV6CTL_RIP6STATS;
+ l = sizeof(rip6stat);
+ if (sysctl(mib, 4, &rip6stat, &l, NULL, 0) < 0) {
+ perror("Warning: sysctl(net.inet6.ip6.rip6stats)");
+ return;
+ }
+
+ if (interval && vflag > 0)
+ print_time();
+ printf("%s:\n", name);
+
+#define RIP6DIFF(f) (rip6stat.f - prip6stat.f)
+#define p(f, m) if (RIP6DIFF(f) || sflag <= 1) \
+ printf(m, (unsigned long long)RIP6DIFF(f), plural(RIP6DIFF(f)))
+ p(rip6s_ipackets, "\t%llu message%s received\n");
+ p(rip6s_isum, "\t%llu checksum calculation%s on inbound\n");
+ p(rip6s_badsum, "\t%llu message%s with bad checksum\n");
+ p(rip6s_nosock, "\t%llu message%s dropped due to no socket\n");
+ p(rip6s_nosockmcast,
+ "\t%llu multicast message%s dropped due to no socket\n");
+ p(rip6s_fullsock,
+ "\t%llu message%s dropped due to full socket buffers\n");
+ delivered = RIP6DIFF(rip6s_ipackets) -
+ RIP6DIFF(rip6s_badsum) -
+ RIP6DIFF(rip6s_nosock) -
+ RIP6DIFF(rip6s_nosockmcast) -
+ RIP6DIFF(rip6s_fullsock);
+ if (delivered || sflag <= 1)
+ printf("\t%llu delivered\n", (unsigned long long)delivered);
+ p(rip6s_opackets, "\t%llu datagram%s output\n");
+
+ if (interval > 0)
+ bcopy(&rip6stat, &prip6stat, l);
+
+#undef RIP6DIFF
+#undef p
+}
+
+/*
+ * Pretty print an Internet address (net address + port).
+ * If the nflag was specified, use numbers instead of names.
+ */
+#ifdef SRVCACHE
+extern struct servent * _serv_cache_getservbyport(int port, char *proto);
+
+#define GETSERVBYPORT6(port, proto, ret)\
+{\
+ if (strcmp((proto), "tcp6") == 0)\
+ (ret) = _serv_cache_getservbyport((int)(port), "tcp");\
+ else if (strcmp((proto), "udp6") == 0)\
+ (ret) = _serv_cache_getservbyport((int)(port), "udp");\
+ else\
+ (ret) = _serv_cache_getservbyport((int)(port), (proto));\
+};
+#else
+#define GETSERVBYPORT6(port, proto, ret)\
+{\
+ if (strcmp((proto), "tcp6") == 0)\
+ (ret) = getservbyport((int)(port), "tcp");\
+ else if (strcmp((proto), "udp6") == 0)\
+ (ret) = getservbyport((int)(port), "udp");\
+ else\
+ (ret) = getservbyport((int)(port), (proto));\
+};
+#endif
+void
+inet6print(struct in6_addr *in6, int port, char *proto, int numeric)
+{
+ struct servent *sp = 0;
+ char line[80], *cp;
+ int width;
+
+ snprintf(line, sizeof(line), "%.*s.", lflag ? 39 :
+ (Aflag && !numeric) ? 12 : 16, inet6name(in6));
+ cp = index(line, '\0');
+ if (!numeric && port)
+ GETSERVBYPORT6(port, proto, sp);
+ if (sp || port == 0)
+ snprintf(cp, sizeof(line) - (cp - line), "%.15s", sp ? sp->s_name : "*");
+ else
+ snprintf(cp, sizeof(line) - (cp - line), "%d", ntohs((u_short)port));
+ width = lflag ? 45 : Aflag ? 18 : 22;
+ printf("%-*.*s ", width, width, line);
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+
+char *
+inet6name(struct in6_addr *in6p)
+{
+ register char *cp;
+ static char line[50];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN];
+ static int first = 1;
+ char hbuf[NI_MAXHOST];
+ struct sockaddr_in6 sin6;
+ const int niflag = NI_NUMERICHOST;
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.')))
+ (void) memmove(domain, cp + 1, strlen(cp + 1) + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = 0;
+ if (!nflag && !IN6_IS_ADDR_UNSPECIFIED(in6p)) {
+ hp = gethostbyaddr((char *)in6p, sizeof(*in6p), AF_INET6);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED(in6p))
+ strlcpy(line, "*", sizeof(line));
+ else if (cp)
+ strlcpy(line, cp, sizeof(line));
+ else {
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(sin6);
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = *in6p;
+
+ if (IN6_IS_ADDR_LINKLOCAL(in6p) ||
+ IN6_IS_ADDR_MC_NODELOCAL(in6p) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6p)) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&in6p->s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, niflag) != 0)
+ strlcpy(hbuf, "?", sizeof(hbuf));
+ strlcpy(line, hbuf, sizeof(line));
+ }
+ return (line);
+}
+#endif /*INET6*/
diff --git a/network_cmds/netstat.tproj/ipsec.c b/network_cmds/netstat.tproj/ipsec.c
new file mode 100644
index 0000000..0eab162
--- /dev/null
+++ b/network_cmds/netstat.tproj/ipsec.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2008-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/* $FreeBSD: src/usr.bin/netstat/ipsec.c,v 1.1.2.3 2001/08/10 09:07:09 ru Exp $ */
+/* $NetBSD: inet.c,v 1.35.2.1 1999/04/29 14:57:08 perry Exp $ */
+/* $KAME: ipsec.c,v 1.25 2001/03/12 09:04:39 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#include <netkey/keysock.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+
+#if defined(__APPLE__) && !defined(__unused)
+#define __unused
+#endif
+/*
+ * portability issues:
+ * - bsdi[34] uses PLURAL(), not plural().
+ * - freebsd2 can't print "unsigned long long" properly.
+ */
+/*
+ * XXX see PORTABILITY for the twist
+ */
+#define LLU "%llu"
+#define CAST unsigned long long
+
+#ifdef IPSEC
+struct val2str {
+ int val;
+ const char *str;
+};
+
+static struct val2str ipsec_ahnames[] = {
+ { SADB_AALG_NONE, "none", },
+ { SADB_AALG_MD5HMAC, "hmac-md5", },
+ { SADB_AALG_SHA1HMAC, "hmac-sha1", },
+ { SADB_X_AALG_MD5, "md5", },
+ { SADB_X_AALG_SHA, "sha", },
+ { SADB_X_AALG_NULL, "null", },
+#ifdef SADB_X_AALG_SHA2_256
+ { SADB_X_AALG_SHA2_256, "hmac-sha2-256", },
+#endif
+#ifdef SADB_X_AALG_SHA2_384
+ { SADB_X_AALG_SHA2_384, "hmac-sha2-384", },
+#endif
+#ifdef SADB_X_AALG_SHA2_512
+ { SADB_X_AALG_SHA2_512, "hmac-sha2-512", },
+#endif
+ { -1, NULL },
+};
+
+static struct val2str ipsec_espnames[] = {
+ { SADB_EALG_NONE, "none", },
+ { SADB_EALG_DESCBC, "des-cbc", },
+ { SADB_EALG_3DESCBC, "3des-cbc", },
+ { SADB_EALG_NULL, "null", },
+#ifdef SADB_X_EALG_RC5CBC
+ { SADB_X_EALG_RC5CBC, "rc5-cbc", },
+#endif
+ { SADB_X_EALG_CAST128CBC, "cast128-cbc", },
+ { SADB_X_EALG_BLOWFISHCBC, "blowfish-cbc", },
+#ifdef SADB_X_EALG_RIJNDAELCBC
+ { SADB_X_EALG_RIJNDAELCBC, "rijndael-cbc", },
+#endif
+ { -1, NULL },
+};
+
+static struct val2str ipsec_compnames[] = {
+ { SADB_X_CALG_NONE, "none", },
+ { SADB_X_CALG_OUI, "oui", },
+ { SADB_X_CALG_DEFLATE, "deflate", },
+ { SADB_X_CALG_LZS, "lzs", },
+ { -1, NULL },
+};
+
+static const char *pfkey_msgtypenames[] = {
+ "reserved", "getspi", "update", "add", "delete",
+ "get", "acquire", "register", "expire", "flush",
+ "dump", "x_promisc", "x_pchange", "x_spdupdate", "x_spdadd",
+ "x_spddelete", "x_spdget", "x_spdacquire", "x_spddump", "x_spdflush",
+ "x_spdsetidx", "x_spdexpire", "x_spddelete2"
+};
+
+static struct ipsecstat pipsecstat;
+static struct ipsecstat ipsecstat;
+
+static void print_ipsecstats (void);
+static const char *pfkey_msgtype_names (int);
+static void ipsec_hist (const u_quad_t *, const u_quad_t *, size_t,
+ const struct val2str *, const char *);
+
+/*
+ * Dump IPSEC statistics structure.
+ */
+static void
+ipsec_hist(const u_quad_t *hist,
+ const u_quad_t *phist,
+ size_t histmax,
+ const struct val2str *name,
+ const char *title)
+{
+ int first;
+ size_t proto;
+ const struct val2str *p;
+
+ first = 1;
+ for (proto = 0; proto < histmax; proto++) {
+ if ((hist[proto] - phist[proto]) <= 0)
+ continue;
+ if (first) {
+ printf("\t%s histogram:\n", title);
+ first = 0;
+ }
+ for (p = name; p && p->str; p++) {
+ if (p->val == (int)proto)
+ break;
+ }
+ if (p && p->str) {
+ printf("\t\t%s: " LLU "\n", p->str,
+ (CAST)hist[proto] - (CAST)phist[proto]);
+ } else {
+ printf("\t\t#%ld: " LLU "\n", (long)proto,
+ (CAST)hist[proto] - (CAST)phist[proto]);
+ }
+ }
+}
+
+static void
+print_ipsecstats(void)
+{
+#define IPSECDIFF(f) (ipsecstat.f - pipsecstat.f)
+#define p(f, m) if (IPSECDIFF(f) || sflag <= 1) \
+ printf(m, (CAST)IPSECDIFF(f), plural(IPSECDIFF(f)))
+#define hist(f, n, t) \
+ ipsec_hist(ipsecstat.f, pipsecstat.f, \
+ sizeof(ipsecstat.f)/sizeof(ipsecstat.f[0]), (n), (t));
+
+ if (interval && vflag > 0)
+ print_time();
+
+ p(in_success, "\t" LLU " inbound packet%s processed successfully\n");
+ p(in_polvio, "\t" LLU " inbound packet%s violated process security "
+ "policy\n");
+ p(in_nosa, "\t" LLU " inbound packet%s with no SA available\n");
+ p(in_inval, "\t" LLU " invalid inbound packet%s\n");
+ p(in_nomem, "\t" LLU " inbound packet%s failed due to insufficient memory\n");
+ p(in_badspi, "\t" LLU " inbound packet%s failed getting SPI\n");
+ p(in_ahreplay, "\t" LLU " inbound packet%s failed on AH replay check\n");
+ p(in_espreplay, "\t" LLU " inbound packet%s failed on ESP replay check\n");
+ p(in_ahauthsucc, "\t" LLU " inbound packet%s considered authentic\n");
+ p(in_ahauthfail, "\t" LLU " inbound packet%s failed on authentication\n");
+ hist(in_ahhist, ipsec_ahnames, "AH input");
+ hist(in_esphist, ipsec_espnames, "ESP input");
+ hist(in_comphist, ipsec_compnames, "IPComp input");
+
+ p(out_success, "\t" LLU " outbound packet%s processed successfully\n");
+ p(out_polvio, "\t" LLU " outbound packet%s violated process security "
+ "policy\n");
+ p(out_nosa, "\t" LLU " outbound packet%s with no SA available\n");
+ p(out_inval, "\t" LLU " invalid outbound packet%s\n");
+ p(out_nomem, "\t" LLU " outbound packet%s failed due to insufficient memory\n");
+ p(out_noroute, "\t" LLU " outbound packet%s with no route\n");
+ hist(out_ahhist, ipsec_ahnames, "AH output");
+ hist(out_esphist, ipsec_espnames, "ESP output");
+ hist(out_comphist, ipsec_compnames, "IPComp output");
+#undef IPSECDIFF
+#undef p
+#undef hist
+}
+
+void
+ipsec_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ size_t len;
+
+ len = sizeof(struct ipsecstat);
+ if (strcmp(name, "ipsec") == 0) {
+ if (sysctlbyname("net.inet.ipsec.stats", &ipsecstat, &len, 0, 0) == -1)
+ return;
+ } else if (strcmp(name, "ipsec6") == 0) {
+ if (sysctlbyname("net.inet6.ipsec6.stats", &ipsecstat, &len, 0, 0) == -1)
+ return;
+ } else
+ return;
+ printf ("%s:\n", name);
+
+ print_ipsecstats();
+
+ if (interval > 0)
+ bcopy(&ipsecstat, &pipsecstat, len);
+}
+
+static const char *
+pfkey_msgtype_names(int x)
+{
+ const int max =
+ sizeof(pfkey_msgtypenames)/sizeof(pfkey_msgtypenames[0]);
+ static char buf[10];
+
+ if (x < max && pfkey_msgtypenames[x])
+ return pfkey_msgtypenames[x];
+ snprintf(buf, sizeof(buf), "#%d", x);
+ return buf;
+}
+
+void
+pfkey_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct pfkeystat ppfkeystat;
+ struct pfkeystat pfkeystat;
+ unsigned first, type;
+ size_t len;
+
+ len = sizeof(struct pfkeystat);
+ if (sysctlbyname("net.key.pfkeystat", &pfkeystat, &len, 0, 0) == -1)
+ return;
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define PFKEYDIFF(f) (pfkeystat.f - ppfkeystat.f)
+#define p(f, m) if (PFKEYDIFF(f) || sflag <= 1) \
+ printf(m, (CAST)PFKEYDIFF(f), plural(PFKEYDIFF(f)))
+
+ /* kernel -> userland */
+ p(out_total, "\t" LLU " request%s sent to userland\n");
+ p(out_bytes, "\t" LLU " byte%s sent to userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.out_msgtype)/sizeof(pfkeystat.out_msgtype[0]);
+ type++) {
+ if (PFKEYDIFF(out_msgtype[type]) <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type),
+ (CAST)PFKEYDIFF(out_msgtype[type]));
+ }
+ p(out_invlen, "\t" LLU " message%s with invalid length field\n");
+ p(out_invver, "\t" LLU " message%s with invalid version field\n");
+ p(out_invmsgtype, "\t" LLU " message%s with invalid message type field\n");
+ p(out_tooshort, "\t" LLU " message%s too short\n");
+ p(out_nomem, "\t" LLU " message%s with memory allocation failure\n");
+ p(out_dupext, "\t" LLU " message%s with duplicate extension\n");
+ p(out_invexttype, "\t" LLU " message%s with invalid extension type\n");
+ p(out_invsatype, "\t" LLU " message%s with invalid sa type\n");
+ p(out_invaddr, "\t" LLU " message%s with invalid address extension\n");
+
+ /* userland -> kernel */
+ p(in_total, "\t" LLU " request%s sent from userland\n");
+ p(in_bytes, "\t" LLU " byte%s sent from userland\n");
+ for (first = 1, type = 0;
+ type < sizeof(pfkeystat.in_msgtype)/sizeof(pfkeystat.in_msgtype[0]);
+ type++) {
+ if (PFKEYDIFF(in_msgtype[type]) <= 0)
+ continue;
+ if (first) {
+ printf("\thistogram by message type:\n");
+ first = 0;
+ }
+ printf("\t\t%s: " LLU "\n", pfkey_msgtype_names(type),
+ (CAST)PFKEYDIFF(in_msgtype[type]));
+ }
+ p(in_msgtarget[KEY_SENDUP_ONE],
+ "\t" LLU " message%s toward single socket\n");
+ p(in_msgtarget[KEY_SENDUP_ALL],
+ "\t" LLU " message%s toward all sockets\n");
+ p(in_msgtarget[KEY_SENDUP_REGISTERED],
+ "\t" LLU " message%s toward registered sockets\n");
+ p(in_nomem, "\t" LLU " message%s with memory allocation failure\n");
+
+ if (interval > 0)
+ bcopy(&pfkeystat, &ppfkeystat, len);
+#undef PFKEYDIFF
+#undef p
+}
+#endif /*IPSEC*/
diff --git a/network_cmds/netstat.tproj/main.c b/network_cmds/netstat.tproj/main.c
new file mode 100644
index 0000000..1b8381e
--- /dev/null
+++ b/network_cmds/netstat.tproj/main.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char const copyright[] =
+"@(#) Copyright (c) 1983, 1988, 1993\n\
+ Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/sys_domain.h>
+
+#include <netinet/in.h>
+#include <net/pfkeyv2.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "netstat.h"
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+/*
+ * ----------------------------------------------------------------------------
+ * "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
+ * ----------------------------------------------------------------------------
+ *
+ * $Id: main.c,v 1.8 2004/10/14 22:24:09 lindak Exp $
+ *
+ */
+
+struct protox {
+ void (*pr_cblocks)(uint32_t, char *, int);
+ /* control blocks printing routine */
+ void (*pr_stats)(uint32_t, char *, int);
+ /* statistics printing routine */
+ void (*pr_istats)(char *); /* per/if statistics printing routine */
+ char *pr_name; /* well-known name */
+ int pr_protocol;
+} protox[] = {
+ { protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { protopr, udp_stats, NULL, "udp", IPPROTO_UDP },
+ { protopr, NULL, NULL, "divert", IPPROTO_DIVERT },
+ { protopr, ip_stats, NULL, "ip", IPPROTO_RAW },
+ { protopr, icmp_stats, NULL, "icmp", IPPROTO_ICMP },
+ { protopr, igmp_stats, NULL, "igmp", IPPROTO_IGMP },
+#ifdef IPSEC
+ { NULL, ipsec_stats, NULL, "ipsec", IPPROTO_ESP},
+#endif
+ { NULL, arp_stats, NULL, "arp", 0 },
+ { mptcppr, mptcp_stats, NULL, "mptcp", IPPROTO_TCP },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+#ifdef INET6
+struct protox ip6protox[] = {
+ { protopr, tcp_stats, NULL, "tcp", IPPROTO_TCP },
+ { protopr, udp_stats, NULL, "udp", IPPROTO_UDP },
+ { protopr, ip6_stats, ip6_ifstats, "ip6", IPPROTO_RAW },
+ { protopr, icmp6_stats, icmp6_ifstats, "icmp6",IPPROTO_ICMPV6 },
+#ifdef IPSEC
+ { NULL, ipsec_stats, NULL, "ipsec6", IPPROTO_ESP },
+#endif
+ { NULL, rip6_stats, NULL, "rip6", IPPROTO_RAW },
+ { mptcppr, mptcp_stats, NULL, "mptcp", IPPROTO_TCP },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif /*INET6*/
+
+#ifdef IPSEC
+struct protox pfkeyprotox[] = {
+ { NULL, pfkey_stats, NULL, "pfkey", PF_KEY_V2 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif
+
+
+struct protox systmprotox[] = {
+ { systmpr, NULL, NULL, "reg", 0 },
+ { systmpr, kevt_stats, NULL, "kevt", SYSPROTO_EVENT },
+ { systmpr, kctl_stats, NULL, "kctl", SYSPROTO_CONTROL },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox nstatprotox[] = {
+ { NULL, print_nstat_stats, NULL, "nstat", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox ipcprotox[] = {
+ { NULL, print_extbkidle_stats, NULL, "xbkidle", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+struct protox kernprotox[] = {
+ { NULL, print_net_api_stats, NULL, "net_api", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+
+#ifdef AF_VSOCK
+struct protox vsockprotox[] = {
+ { vsockpr, NULL, NULL, "vsock", 0 },
+ { NULL, NULL, NULL, NULL, 0 }
+};
+#endif
+
+struct protox *protoprotox[] = {
+ protox,
+#ifdef INET6
+ ip6protox,
+#endif
+#ifdef IPSEC
+ pfkeyprotox,
+#endif
+ systmprotox,
+ nstatprotox,
+ ipcprotox,
+ kernprotox,
+#ifdef AF_VSOCK
+ vsockprotox,
+#endif
+ NULL
+};
+
+static void printproto (struct protox *, char *);
+static void usage (void);
+static struct protox *name2protox (char *);
+static struct protox *knownname (char *);
+#ifdef SRVCACHE
+extern void _serv_cache_close();
+#endif
+
+int Aflag; /* show addresses of protocol control block */
+int aflag; /* show all sockets (including servers) */
+int bflag; /* show i/f total bytes in/out */
+int cflag; /* show specific classq */
+int dflag; /* show i/f dropped packets */
+int Fflag; /* show i/f forwarded packets */
+#if defined(__APPLE__)
+int gflag; /* show group (multicast) routing or stats */
+#endif
+int iflag; /* show interfaces */
+int lflag; /* show routing table with more information */
+int Lflag; /* show size of listen queues */
+int mflag; /* show memory stats */
+int nflag; /* show addresses numerically */
+static int pflag; /* show given protocol */
+int prioflag = -1; /* show packet priority statistics */
+int Rflag; /* show reachability information */
+int rflag; /* show routing tables (or routing stats) */
+int sflag; /* show protocol statistics */
+int Sflag; /* show additional i/f link status */
+int tflag; /* show i/f watchdog timers */
+int vflag; /* more verbose */
+int Wflag; /* wide display */
+int qflag; /* classq stats display */
+int Qflag; /* opportunistic polling stats display */
+int xflag; /* show extended link-layer reachability information */
+int zflag; /* show only entries with non zero rtt metrics */
+
+int cq = -1; /* send classq index (-1 for all) */
+int interval; /* repeat interval for i/f stats */
+
+char *interface; /* desired i/f for stats, or NULL for all i/fs */
+int unit; /* unit number for above */
+
+int af; /* address family */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register struct protox *tp = NULL; /* for printing cblocks & stats */
+ int ch;
+
+ af = AF_UNSPEC;
+
+ while ((ch = getopt(argc, argv, "Aabc:dFf:gI:ikLlmnP:p:qQrRsStuvWw:xz")) != -1)
+ switch(ch) {
+ case 'A':
+ Aflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'c':
+ cflag = 1;
+ cq = atoi(optarg);
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'f':
+ if (strcmp(optarg, "ipx") == 0)
+ af = AF_IPX;
+ else if (strcmp(optarg, "inet") == 0)
+ af = AF_INET;
+#ifdef INET6
+ else if (strcmp(optarg, "inet6") == 0)
+ af = AF_INET6;
+#endif /*INET6*/
+#ifdef INET6
+ else if (strcmp(optarg, "pfkey") == 0)
+ af = PF_KEY;
+#endif /*INET6*/
+ else if (strcmp(optarg, "unix") == 0)
+ af = AF_UNIX;
+ else if (strcmp(optarg, "systm") == 0)
+ af = AF_SYSTEM;
+ else {
+ errx(1, "%s: unknown address family", optarg);
+ }
+ break;
+#if defined(__APPLE__)
+ case 'g':
+ gflag = 1;
+ break;
+#endif
+ case 'I': {
+ char *cp;
+
+ iflag = 1;
+ for (cp = interface = optarg; isalpha(*cp); cp++)
+ continue;
+ unit = atoi(cp);
+ break;
+ }
+ case 'i':
+ iflag = 1;
+ break;
+ case 'l':
+ lflag += 1;
+ break;
+ case 'L':
+ Lflag = 1;
+ break;
+ case 'm':
+ mflag++;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'P':
+ prioflag = atoi(optarg);
+ break;
+ case 'p':
+ if ((tp = name2protox(optarg)) == NULL) {
+ errx(1,
+ "%s: unknown or uninstrumented protocol",
+ optarg);
+ }
+ pflag = 1;
+ break;
+ case 'q':
+ qflag++;
+ break;
+ case 'Q':
+ Qflag++;
+ break;
+ case 'R':
+ Rflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ ++sflag;
+ break;
+ case 'S':
+ Sflag = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'u':
+ af = AF_UNIX;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'W':
+ Wflag = 1;
+ break;
+ case 'w':
+ interval = atoi(optarg);
+ iflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ Rflag = 1;
+ break;
+ case 'z':
+ zflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+#define BACKWARD_COMPATIBILITY
+#ifdef BACKWARD_COMPATIBILITY
+ if (*argv) {
+ if (isdigit(**argv)) {
+ interval = atoi(*argv);
+ if (interval <= 0)
+ usage();
+ ++argv;
+ iflag = 1;
+ }
+ }
+#endif
+
+ if (mflag) {
+ mbpr();
+ exit(0);
+ }
+ if (iflag && !sflag && !Sflag && !gflag && !qflag && !Qflag) {
+ if (Rflag)
+ intpr_ri(NULL);
+ else
+ intpr(NULL);
+ exit(0);
+ }
+ if (rflag) {
+ if (sflag)
+ rt_stats();
+ else
+ routepr();
+ exit(0);
+ }
+ if (qflag || Qflag) {
+ if (interface == NULL) {
+ fprintf(stderr, "%s statistics option "
+ "requires interface name\n", qflag ? "Queue" :
+ "Polling");
+ } else if (qflag) {
+ aqstatpr();
+ } else {
+ rxpollstatpr();
+ }
+ exit(0);
+ }
+ if (Sflag) {
+ if (interface == NULL) {
+ fprintf(stderr, "additional link status option"
+ " requires interface name\n");
+ } else {
+ print_link_status(interface);
+ }
+ exit(0);
+ }
+
+#if defined(__APPLE__)
+ if (gflag) {
+ ifmalist_dump();
+ exit(0);
+ }
+#endif
+
+ if (tp) {
+ printproto(tp, tp->pr_name);
+ exit(0);
+ }
+ if (af == AF_INET || af == AF_UNSPEC)
+ for (tp = protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#ifdef INET6
+ if (af == AF_INET6 || af == AF_UNSPEC)
+ for (tp = ip6protox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*INET6*/
+#ifdef IPSEC
+ if (af == PF_KEY || af == AF_UNSPEC)
+ for (tp = pfkeyprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*IPSEC*/
+ if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
+ unixpr();
+
+ if ((af == AF_SYSTEM || af == AF_UNSPEC) && !Lflag)
+ for (tp = systmprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#if TARGET_OS_IPHONE
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = nstatprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /* TARGET_OS_IPHONE */
+
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = ipcprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+
+ if (af == AF_UNSPEC && !Lflag)
+ for (tp = kernprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+
+#ifdef AF_VSOCK
+ if (af == AF_VSOCK || af == AF_UNSPEC)
+ for (tp = vsockprotox; tp->pr_name; tp++)
+ printproto(tp, tp->pr_name);
+#endif /*AF_VSOCK*/
+
+#ifdef SRVCACHE
+ _serv_cache_close();
+#endif
+ exit(0);
+}
+
+/*
+ * Print out protocol statistics or control blocks (per sflag).
+ * If the interface was not specifically requested, and the symbol
+ * is not in the namelist, ignore this one.
+ */
+static void
+printproto(tp, name)
+ register struct protox *tp;
+ char *name;
+{
+ void (*pr)(uint32_t, char *, int);
+ uint32_t off;
+
+ if (sflag) {
+ if (iflag && !pflag) {
+ if (tp->pr_istats)
+ intpr(tp->pr_istats);
+ else if (vflag)
+ printf("%s: no per-interface stats routine\n",
+ tp->pr_name);
+ return;
+ }
+ else {
+ pr = tp->pr_stats;
+ if (!pr) {
+ if (pflag && vflag)
+ printf("%s: no stats routine\n",
+ tp->pr_name);
+ return;
+ }
+ off = tp->pr_protocol;
+ }
+ } else {
+ pr = tp->pr_cblocks;
+ if (!pr) {
+ if (pflag && vflag)
+ printf("%s: no PCB routine\n", tp->pr_name);
+ return;
+ }
+ off = tp->pr_protocol;
+ }
+ if (pr != NULL) {
+ if (sflag && iflag && pflag)
+ intervalpr(pr, off, name, af);
+ else
+ (*pr)(off, name, af);
+ } else {
+ printf("### no stats for %s\n", name);
+ }
+}
+
+char *
+plural(int n)
+{
+ return (n > 1 ? "s" : "");
+}
+
+char *
+plurales(int n)
+{
+ return (n > 1 ? "es" : "");
+}
+
+char *
+pluralies(int n)
+{
+ return (n > 1 ? "ies" : "y");
+}
+
+/*
+ * Find the protox for the given "well-known" name.
+ */
+static struct protox *
+knownname(char *name)
+{
+ struct protox **tpp, *tp;
+
+ for (tpp = protoprotox; *tpp; tpp++)
+ for (tp = *tpp; tp->pr_name; tp++)
+ if (strcmp(tp->pr_name, name) == 0)
+ return (tp);
+ return (NULL);
+}
+
+/*
+ * Find the protox corresponding to name.
+ */
+static struct protox *
+name2protox(char *name)
+{
+ struct protox *tp;
+ char **alias; /* alias from p->aliases */
+ struct protoent *p;
+
+ /*
+ * Try to find the name in the list of "well-known" names. If that
+ * fails, check if name is an alias for an Internet protocol.
+ */
+ if ((tp = knownname(name)) != NULL)
+ return (tp);
+
+ setprotoent(1); /* make protocol lookup cheaper */
+ while ((p = getprotoent()) != NULL) {
+ /* assert: name not same as p->name */
+ for (alias = p->p_aliases; *alias; alias++)
+ if (strcmp(name, *alias) == 0) {
+ endprotoent();
+ return (knownname(p->p_name));
+ }
+ }
+ endprotoent();
+ return (NULL);
+}
+
+#define NETSTAT_USAGE "\
+Usage: netstat [-AaLlnW] [-f address_family | -p protocol]\n\
+ netstat [-gilns] [-f address_family]\n\
+ netstat -i | -I interface [-w wait] [-abdgRtS]\n\
+ netstat -s [-s] [-f address_family | -p protocol] [-w wait]\n\
+ netstat -i | -I interface -s [-f address_family | -p protocol]\n\
+ netstat -m [-m]\n\
+ netstat -r [-Aaln] [-f address_family]\n\
+ netstat -rs [-s]\n\
+"
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr, "%s\n", NETSTAT_USAGE);
+ exit(1);
+}
+
+int
+print_time(void)
+{
+ time_t now;
+ struct tm tm;
+ int num_written = 0;
+
+ (void) time(&now);
+ (void) localtime_r(&now, &tm);
+
+ num_written += printf("%02d:%02d:%02d ", tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ return (num_written);
+}
+
diff --git a/network_cmds/netstat.tproj/mbuf.c b/network_cmds/netstat.tproj/mbuf.c
new file mode 100644
index 0000000..38645e9
--- /dev/null
+++ b/network_cmds/netstat.tproj/mbuf.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "netstat.h"
+
+#define YES 1
+typedef int bool;
+
+struct mbstat mbstat;
+
+static struct mbtypes {
+ int mt_type;
+ char *mt_name;
+} mbtypes[] = {
+ { MT_DATA, "data" },
+ { MT_OOBDATA, "oob data" },
+ { MT_CONTROL, "ancillary data" },
+ { MT_HEADER, "packet headers" },
+ { MT_SOCKET, "socket structures" }, /* XXX */
+ { MT_PCB, "protocol control blocks" }, /* XXX */
+ { MT_RTABLE, "routing table entries" }, /* XXX */
+ { MT_HTABLE, "IMP host table entries" }, /* XXX */
+ { MT_ATABLE, "address resolution tables" },
+ { MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */
+ { MT_SONAME, "socket names and addresses" },
+ { MT_SOOPTS, "socket options" },
+ { MT_RIGHTS, "access rights" },
+ { MT_IFADDR, "interface addresses" }, /* XXX */
+ { MT_TAG, "packet tags" }, /* XXX */
+ { 0, 0 }
+};
+
+int nmbtypes = sizeof(mbstat.m_mtypes) / sizeof(short);
+bool seen[256]; /* "have we seen this type yet?" */
+
+mb_stat_t *mb_stat;
+unsigned int njcl, njclbytes;
+mleak_stat_t *mleak_stat;
+struct mleak_table table;
+
+#define KERN_IPC_MB_STAT "kern.ipc.mb_stat"
+#define KERN_IPC_NJCL "kern.ipc.njcl"
+#define KERN_IPC_NJCL_BYTES "kern.ipc.njclbytes"
+#define KERN_IPC_MLEAK_TABLE "kern.ipc.mleak_table"
+#define KERN_IPC_MLEAK_TOP_TRACE "kern.ipc.mleak_top_trace"
+
+#define MB_STAT_HDR1 "\
+class buf active ctotal total cache cached uncached memory\n\
+name size bufs bufs bufs state bufs bufs usage\n\
+---------- ----- -------- -------- -------- ----- -------- -------- ---------\n\
+"
+
+#define MB_STAT_HDR2 "\n\
+class waiter notify purge wretry nwretry failure\n\
+name count count count count count count\n\
+---------- -------- -------- -------- -------- -------- --------\n\
+"
+
+#define MB_LEAK_HDR "\n\
+ calltrace [1] calltrace [2] calltrace [3] calltrace [4] calltrace [5] \n\
+ ------------------ ------------------ ------------------ ------------------ ------------------ \n\
+"
+
+#define MB_LEAK_SPACING " "
+static const char *mbpr_state(int);
+static const char *mbpr_mem(u_int32_t);
+static int mbpr_getdata(void);
+
+/*
+ * Print mbuf statistics.
+ */
+void
+mbpr(void)
+{
+ unsigned long totmem = 0, totfree = 0, totmbufs, totused, totreturned = 0;
+ double totpct;
+ u_int32_t m_msize, m_mbufs = 0, m_clfree = 0, m_bigclfree = 0;
+ u_int32_t m_mbufclfree = 0, m_mbufbigclfree = 0;
+ u_int32_t m_16kclusters = 0, m_16kclfree = 0, m_mbuf16kclfree = 0;
+ int i;
+ struct mbtypes *mp;
+ mb_class_stat_t *cp;
+
+ if (mbpr_getdata() != 0)
+ return;
+
+ m_msize = mbstat.m_msize;
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ if (cp->mbcl_size == m_msize) {
+ m_mbufs = cp->mbcl_active;
+ } else if (cp->mbcl_size == mbstat.m_mclbytes) {
+ m_clfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (cp->mbcl_size == mbstat.m_bigmclbytes) {
+ m_bigclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (njcl > 0 && cp->mbcl_size == njclbytes) {
+ m_16kclfree = cp->mbcl_total - cp->mbcl_active;
+ m_16kclusters = cp->mbcl_total;
+ } else if (cp->mbcl_size == (m_msize + mbstat.m_mclbytes)) {
+ m_mbufclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (cp->mbcl_size == (m_msize + mbstat.m_bigmclbytes)) {
+ m_mbufbigclfree = cp->mbcl_total - cp->mbcl_active;
+ } else if (njcl > 0 && cp->mbcl_size == (m_msize + njclbytes)) {
+ m_mbuf16kclfree = cp->mbcl_total - cp->mbcl_active;
+ }
+ }
+
+ /* adjust free counts to include composite caches */
+ m_clfree += m_mbufclfree;
+ m_bigclfree += m_mbufbigclfree;
+ m_16kclfree += m_mbuf16kclfree;
+
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ u_int32_t mem;
+
+ mem = cp->mbcl_ctotal * cp->mbcl_size;
+ totmem += mem;
+ totreturned += cp->mbcl_release_cnt;
+ totfree += (cp->mbcl_mc_cached + cp->mbcl_infree) *
+ cp->mbcl_size;
+ if (mflag > 1) {
+ if (i == 0)
+ printf(MB_STAT_HDR1);
+
+ if (njcl == 0 &&
+ cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
+ continue;
+
+ printf("%-10s %5u %8u %8u %8u %5s %8u %8u %9s\n",
+ cp->mbcl_cname, cp->mbcl_size, cp->mbcl_active,
+ cp->mbcl_ctotal, cp->mbcl_total,
+ mbpr_state(cp->mbcl_mc_state), cp->mbcl_mc_cached,
+ cp->mbcl_infree, mbpr_mem(mem));
+ }
+ }
+
+ cp = &mb_stat->mbs_class[0];
+ for (i = 0; i < mb_stat->mbs_cnt; i++, cp++) {
+ if (mflag > 2) {
+ if (i == 0)
+ printf(MB_STAT_HDR2);
+
+ if (njcl == 0 &&
+ cp->mbcl_size > (m_msize + mbstat.m_bigmclbytes))
+ continue;
+
+ printf("%-10s %8u %8llu %8llu %8u %8u %8llu\n",
+ cp->mbcl_cname, cp->mbcl_mc_waiter_cnt,
+ cp->mbcl_notified, cp->mbcl_purge_cnt,
+ cp->mbcl_mc_wretry_cnt, cp->mbcl_mc_nwretry_cnt,
+ cp->mbcl_fail_cnt);
+ }
+ }
+
+ if (mflag > 1)
+ printf("\n");
+
+ totmbufs = 0;
+ for (mp = mbtypes; mp->mt_name; mp++)
+ totmbufs += mbstat.m_mtypes[mp->mt_type];
+ /*
+ * These stats are not updated atomically in the kernel;
+ * adjust the total as neeeded.
+ */
+ if (totmbufs > m_mbufs)
+ totmbufs = m_mbufs;
+ printf("%lu/%u mbufs in use:\n", totmbufs, m_mbufs);
+ for (mp = mbtypes; mp->mt_name; mp++)
+ if (mbstat.m_mtypes[mp->mt_type]) {
+ seen[mp->mt_type] = YES;
+ printf("\t%u mbufs allocated to %s\n",
+ mbstat.m_mtypes[mp->mt_type], mp->mt_name);
+ }
+ seen[MT_FREE] = YES;
+ for (i = 0; i < nmbtypes; i++)
+ if (!seen[i] && mbstat.m_mtypes[i]) {
+ printf("\t%u mbufs allocated to <mbuf type %d>\n",
+ mbstat.m_mtypes[i], i);
+ }
+ if ((m_mbufs - totmbufs) > 0)
+ printf("\t%lu mbufs allocated to caches\n",
+ m_mbufs - totmbufs);
+ printf("%u/%u mbuf 2KB clusters in use\n",
+ (unsigned int)(mbstat.m_clusters - m_clfree),
+ (unsigned int)mbstat.m_clusters);
+ printf("%u/%u mbuf 4KB clusters in use\n",
+ (unsigned int)(mbstat.m_bigclusters - m_bigclfree),
+ (unsigned int)mbstat.m_bigclusters);
+ if (njcl > 0) {
+ printf("%u/%u mbuf %uKB clusters in use\n",
+ m_16kclusters - m_16kclfree, m_16kclusters,
+ njclbytes/1024);
+ }
+ totused = totmem - totfree;
+ if (totmem == 0)
+ totpct = 0;
+ else if (totused < (ULONG_MAX/100))
+ totpct = (totused * 100)/(double)totmem;
+ else {
+ u_long totmem1 = totmem/100;
+ u_long totused1 = totused/100;
+ totpct = (totused1 * 100)/(double)totmem1;
+ }
+ printf("%lu KB allocated to network (%.1f%% in use)\n",
+ totmem / 1024, totpct);
+ printf("%lu KB returned to the system\n", totreturned / 1024);
+
+ printf("%u requests for memory denied\n", (unsigned int)mbstat.m_drops);
+ printf("%u requests for memory delayed\n", (unsigned int)mbstat.m_wait);
+ printf("%u calls to drain routines\n", (unsigned int)mbstat.m_drain);
+
+ free(mb_stat);
+ mb_stat = NULL;
+
+ if (mleak_stat != NULL) {
+ mleak_trace_stat_t *mltr;
+
+ printf("\nmbuf leak detection table:\n");
+ printf("\ttotal captured: %u (one per %u)\n"
+ "\ttotal allocs outstanding: %llu\n"
+ "\tnew hash recorded: %llu allocs, %llu traces\n"
+ "\thash collisions: %llu allocs, %llu traces\n"
+ "\toverwrites: %llu allocs, %llu traces\n"
+ "\tlock conflicts: %llu\n\n",
+ table.mleak_capture / table.mleak_sample_factor,
+ table.mleak_sample_factor,
+ table.outstanding_allocs,
+ table.alloc_recorded, table.trace_recorded,
+ table.alloc_collisions, table.trace_collisions,
+ table.alloc_overwrites, table.trace_overwrites,
+ table.total_conflicts);
+
+ printf("top %d outstanding traces:\n", mleak_stat->ml_cnt);
+ for (i = 0; i < mleak_stat->ml_cnt; i++) {
+ mltr = &mleak_stat->ml_trace[i];
+ printf("[%d] %llu outstanding alloc(s), "
+ "%llu hit(s), %llu collision(s)\n", (i + 1),
+ mltr->mltr_allocs, mltr->mltr_hitcount,
+ mltr->mltr_collisions);
+ }
+
+ printf(MB_LEAK_HDR);
+ for (i = 0; i < MLEAK_STACK_DEPTH; i++) {
+ int j;
+
+ printf("%2d: ", (i + 1));
+ for (j = 0; j < mleak_stat->ml_cnt; j++) {
+ mltr = &mleak_stat->ml_trace[j];
+ if (i < mltr->mltr_depth) {
+ if (mleak_stat->ml_isaddr64) {
+ printf("0x%0llx ",
+ mltr->mltr_addr[i]);
+ } else {
+ printf("0x%08x ",
+ (u_int32_t)mltr->mltr_addr[i]);
+ }
+ } else {
+ printf(MB_LEAK_SPACING);
+ }
+ }
+ printf("\n");
+ }
+ free(mleak_stat);
+ mleak_stat = NULL;
+ }
+}
+
+static const char *
+mbpr_state(int state)
+{
+ char *msg = "?";
+
+ switch (state) {
+ case MCS_DISABLED:
+ msg = "dis";
+ break;
+
+ case MCS_ONLINE:
+ msg = "on";
+ break;
+
+ case MCS_PURGING:
+ msg = "purge";
+ break;
+
+ case MCS_OFFLINE:
+ msg = "off";
+ break;
+ }
+ return (msg);
+}
+
+static const char *
+mbpr_mem(u_int32_t bytes)
+{
+ static char buf[33];
+ double mem = bytes;
+
+ if (mem < 1024) {
+ (void) snprintf(buf, sizeof (buf), "%d", (int)mem);
+ } else if ((mem /= 1024) < 1024) {
+ (void) snprintf(buf, sizeof (buf), "%.1f KB", mem);
+ } else {
+ mem /= 1024;
+ (void) snprintf(buf, sizeof (buf), "%.1f MB", mem);
+ }
+ return (buf);
+}
+
+static int
+mbpr_getdata(void)
+{
+ size_t len;
+ int error = -1;
+
+ if (nmbtypes != 256) {
+ (void) fprintf(stderr,
+ "netstat: unexpected change to mbstat; check source\n");
+ goto done;
+ }
+
+ len = sizeof(mbstat);
+ if (sysctlbyname("kern.ipc.mbstat", &mbstat, &len, 0, 0) == -1)
+ goto done;
+
+ if (sysctlbyname(KERN_IPC_MB_STAT, NULL, &len, 0, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error retrieving length for %s\n", KERN_IPC_MB_STAT);
+ goto done;
+ }
+
+ mb_stat = calloc(1, len);
+ if (mb_stat == NULL) {
+ (void) fprintf(stderr,
+ "Error allocating %lu bytes for sysctl data\n", len);
+ goto done;
+ }
+
+ if (sysctlbyname(KERN_IPC_MB_STAT, mb_stat, &len, 0, 0) == -1) {
+ (void) fprintf(stderr,
+ "Error %d getting %s\n", errno, KERN_IPC_MB_STAT);
+ goto done;
+ }
+
+ if (mb_stat->mbs_cnt == 0) {
+ (void) fprintf(stderr,
+ "Invalid mbuf class count (%d)\n", mb_stat->mbs_cnt);
+ goto done;
+ }
+
+ /* mbuf leak detection! */
+ if (mflag > 3) {
+ errno = 0;
+ len = sizeof (table);
+ if (sysctlbyname(KERN_IPC_MLEAK_TABLE, &table, &len, 0, 0) ==
+ -1 && errno != ENXIO) {
+ (void) fprintf(stderr, "error %d getting %s\n", errno,
+ KERN_IPC_MLEAK_TABLE);
+ goto done;
+ } else if (errno == ENXIO) {
+ (void) fprintf(stderr, "mbuf leak detection is not "
+ "enabled in the kernel.\n");
+ goto skip;
+ }
+
+ if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, NULL, &len,
+ 0, 0) == -1) {
+ (void) fprintf(stderr, "Error retrieving length for "
+ "%s: %d\n", KERN_IPC_MB_STAT, errno);
+ goto done;
+ }
+
+ mleak_stat = calloc(1, len);
+ if (mleak_stat == NULL) {
+ (void) fprintf(stderr, "Error allocating %lu bytes "
+ "for sysctl data\n", len);
+ goto done;
+ }
+
+ if (sysctlbyname(KERN_IPC_MLEAK_TOP_TRACE, mleak_stat, &len,
+ 0, 0) == -1) {
+ (void) fprintf(stderr, "error %d getting %s\n", errno,
+ KERN_IPC_MLEAK_TOP_TRACE);
+ goto done;
+ }
+ }
+
+skip:
+ len = sizeof (njcl);
+ (void) sysctlbyname(KERN_IPC_NJCL, &njcl, &len, 0, 0);
+ len = sizeof (njclbytes);
+ (void) sysctlbyname(KERN_IPC_NJCL_BYTES, &njclbytes, &len, 0, 0);
+
+ error = 0;
+
+done:
+ if (error != 0 && mb_stat != NULL) {
+ free(mb_stat);
+ mb_stat = NULL;
+ }
+
+ if (error != 0 && mleak_stat != NULL) {
+ free(mleak_stat);
+ mleak_stat = NULL;
+ }
+
+ return (error);
+}
diff --git a/network_cmds/netstat.tproj/mcast.c b/network_cmds/netstat.tproj/mcast.c
new file mode 100644
index 0000000..3637f4d
--- /dev/null
+++ b/network_cmds/netstat.tproj/mcast.c
@@ -0,0 +1,887 @@
+/*
+ * Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 2007 Bruce M. Simpson <bms@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+
+/*
+ * Print the running system's current multicast group memberships.
+ * As this relies on getifmaddrs(), it may not be used with a core file.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_mib.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <netinet/igmp_var.h>
+#include <netinet6/mld6_var.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <ifaddrs.h>
+#include <sysexits.h>
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <ifaddrs.h>
+
+
+#include "netstat.h"
+
+union sockunion {
+ struct sockaddr_storage ss;
+ struct sockaddr sa;
+ struct sockaddr_dl sdl;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+typedef union sockunion sockunion_t;
+
+/*
+ * This may have been defined in <net/if.h>. Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+#endif
+
+//struct ifmaddrs {
+// struct ifmaddrs *ifma_next;
+// struct sockaddr *ifma_name;
+// struct sockaddr *ifma_addr;
+// struct sockaddr *ifma_lladdr;
+//};
+
+void ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af);
+static int ifmalist_dump_mcstat(struct ifmaddrs *);
+static void in_ifinfo(struct igmp_ifinfo *);
+static const char *inm_mode(u_int);
+static void inm_print_sources_sysctl(uint32_t, struct in_addr);
+#ifdef INET6
+static void in6_ifinfo(struct mld_ifinfo *);
+static void in6m_print_sources_sysctl(uint32_t, struct in6_addr *);
+static const char *inet6_n2a(struct in6_addr *);
+#endif
+static void printb(const char *, unsigned int, const char *);
+static const char *sdl_addr_to_hex(const struct sockaddr_dl *, char *, int);
+
+extern char *routename6(struct sockaddr_in6 *);
+
+#define sa_equal(a1, a2) \
+ (bcmp((a1), (a2), ((a1))->sa_len) == 0)
+
+#define sa_dl_equal(a1, a2) \
+ ((((struct sockaddr_dl *)(a1))->sdl_len == \
+ ((struct sockaddr_dl *)(a2))->sdl_len) && \
+ (bcmp(LLADDR((struct sockaddr_dl *)(a1)), \
+ LLADDR((struct sockaddr_dl *)(a2)), \
+ ((struct sockaddr_dl *)(a1))->sdl_alen) == 0))
+
+#define SALIGN (sizeof(uint32_t) - 1)
+#define SA_RLEN(sa) (sa ? ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
+ (SALIGN + 1)) : 0)
+#define MAX_SYSCTL_TRY 5
+#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
+
+void
+ifmalist_dump_af(const struct ifmaddrs * const ifmap, int const af)
+{
+ const struct ifmaddrs *ifma;
+ sockunion_t *psa;
+ char myifname[IFNAMSIZ];
+ char *pcolon;
+ char *pafname, *pifname, *plladdr = NULL, *pgroup = NULL;
+
+ switch (af) {
+ case AF_INET:
+ pafname = "IPv4";
+ break;
+#ifdef INET6
+ case AF_INET6:
+ pafname = "IPv6";
+ break;
+#endif
+ case AF_LINK:
+ pafname = "Link-layer";
+ break;
+ default:
+ return; /* XXX */
+ }
+
+ fprintf(stdout, "%s Multicast Group Memberships\n", pafname);
+ fprintf(stdout, "%-20s\t%-16s\t%s\n", "Group", "Link-layer Address",
+ "Netif");
+
+ for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
+
+ if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
+ continue;
+
+ /* Group address */
+ psa = (sockunion_t *)ifma->ifma_addr;
+ if (psa->sa.sa_family != af)
+ continue;
+
+ switch (psa->sa.sa_family) {
+ case AF_INET:
+ pgroup = inet_ntoa(psa->sin.sin_addr);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ pgroup = routename6(&(psa->sin6));
+ break;
+#endif
+ case AF_LINK:
+ if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) ||
+ (psa->sdl.sdl_type == IFT_ETHER)) {
+ pgroup =
+ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
+#ifdef notyet
+ } else {
+ pgroup = addr2ascii(AF_LINK,
+ &psa->sdl,
+ sizeof(struct sockaddr_dl),
+ addrbuf);
+#endif
+ }
+ break;
+ default:
+ continue; /* XXX */
+ }
+
+ /* Link-layer mapping, if any */
+ psa = (sockunion_t *)ifma->ifma_lladdr;
+ if (psa != NULL) {
+ if (psa->sa.sa_family == AF_LINK) {
+ if ((psa->sdl.sdl_alen == ETHER_ADDR_LEN) ||
+ (psa->sdl.sdl_type == IFT_ETHER)) {
+ /* IEEE 802 */
+ plladdr =
+ether_ntoa((struct ether_addr *)&psa->sdl.sdl_data);
+#ifdef notyet
+ } else {
+ /* something more exotic */
+ plladdr = addr2ascii(AF_LINK,
+ &psa->sdl,
+ sizeof(struct sockaddr_dl),
+ addrbuf);
+#endif
+ }
+ } else {
+ int i;
+
+ /* not a link-layer address */
+ plladdr = "<invalid>";
+
+ for (i = 0; psa->sa.sa_len > 2 && i < psa->sa.sa_len - 2; i++)
+ printf("0x%x ", psa->sa.sa_data[i]);
+ printf("\n");
+ }
+ } else {
+ plladdr = "<none>";
+ }
+
+ /* Interface upon which the membership exists */
+ psa = (sockunion_t *)ifma->ifma_name;
+ if (psa != NULL && psa->sa.sa_family == AF_LINK) {
+ strlcpy(myifname, link_ntoa(&psa->sdl), sizeof(myifname));
+ pcolon = strchr(myifname, ':');
+ if (pcolon)
+ *pcolon = '\0';
+ pifname = myifname;
+ } else {
+ pifname = "";
+ }
+
+ fprintf(stdout, "%-20s\t%-16s\t%s\n", pgroup, plladdr, pifname);
+ }
+}
+
+void
+ifmalist_dump(void)
+{
+ struct ifmaddrs *ifmap;
+
+ if (getifmaddrs(&ifmap))
+ err(EX_OSERR, "getifmaddrs");
+
+ ifmalist_dump_af(ifmap, AF_LINK);
+ fputs("\n", stdout);
+ ifmalist_dump_af(ifmap, AF_INET);
+#ifdef INET6
+ fputs("\n", stdout);
+ ifmalist_dump_af(ifmap, AF_INET6);
+#endif
+ if (sflag) {
+ fputs("\n", stdout);
+ ifmalist_dump_mcstat(ifmap);
+ }
+
+ freeifmaddrs(ifmap);
+}
+
+static int
+ifmalist_dump_mcstat(struct ifmaddrs *ifmap)
+{
+ char thisifname[IFNAMSIZ];
+ char addrbuf[NI_MAXHOST];
+ struct ifaddrs *ifap, *ifa;
+ struct ifmaddrs *ifma;
+ sockunion_t lastifasa;
+ sockunion_t *psa, *pgsa, *pllsa, *pifasa;
+ char *pcolon;
+ char *pafname;
+ uint32_t lastifindex, thisifindex;
+ int error;
+ uint32_t ifindex = 0;
+
+ if (interface != NULL)
+ ifindex = if_nametoindex(interface);
+
+ error = 0;
+ ifap = NULL;
+ lastifindex = 0;
+ thisifindex = 0;
+ lastifasa.ss.ss_family = AF_UNSPEC;
+
+ if (getifaddrs(&ifap) != 0) {
+ warn("getifmaddrs");
+ return (-1);
+ }
+
+ for (ifma = ifmap; ifma; ifma = ifma->ifma_next) {
+ error = 0;
+ if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL)
+ continue;
+
+ psa = (sockunion_t *)ifma->ifma_name;
+ if (psa->sa.sa_family != AF_LINK) {
+ fprintf(stderr,
+ "WARNING: Kernel returned invalid data.\n");
+ error = -1;
+ break;
+ }
+
+ /* Filter on interface name. */
+ thisifindex = psa->sdl.sdl_index;
+ if (ifindex != 0 && thisifindex != ifindex)
+ continue;
+
+ /* Filter on address family. */
+ pgsa = (sockunion_t *)ifma->ifma_addr;
+ if (af != 0 && pgsa->sa.sa_family != af)
+ continue;
+
+ strlcpy(thisifname, link_ntoa(&psa->sdl), sizeof(thisifname));
+ pcolon = strchr(thisifname, ':');
+ if (pcolon)
+ *pcolon = '\0';
+
+ /* Only print the banner for the first ifmaddrs entry. */
+ if (lastifindex == 0 || lastifindex != thisifindex) {
+ lastifindex = thisifindex;
+ fprintf(stdout, "%s:\n", thisifname);
+ }
+
+ /*
+ * Currently, multicast joins only take place on the
+ * primary IPv4 address, and only on the link-local IPv6
+ * address, as per IGMPv2/3 and MLDv1/2 semantics.
+ * Therefore, we only look up the primary address on
+ * the first pass.
+ */
+ pifasa = NULL;
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if ((strcmp(ifa->ifa_name, thisifname) != 0) ||
+ (ifa->ifa_addr == NULL) ||
+ (ifa->ifa_addr->sa_family != pgsa->sa.sa_family))
+ continue;
+ /*
+ * For AF_INET6 only the link-local address should
+ * be returned. If built without IPv6 support,
+ * skip this address entirely.
+ */
+ pifasa = (sockunion_t *)ifa->ifa_addr;
+ if (pifasa->sa.sa_family == AF_INET6
+#ifdef INET6
+ && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr)
+#endif
+ ) {
+ pifasa = NULL;
+ continue;
+ }
+ break;
+ }
+ if (pifasa == NULL)
+ continue; /* primary address not found */
+
+ if (!vflag && pifasa->sa.sa_family == AF_LINK)
+ continue;
+
+ /* Parse and print primary address, if not already printed. */
+ if (lastifasa.ss.ss_family == AF_UNSPEC ||
+ ((lastifasa.ss.ss_family == AF_LINK &&
+ !sa_dl_equal(&lastifasa.sa, &pifasa->sa)) ||
+ !sa_equal(&lastifasa.sa, &pifasa->sa))) {
+
+ switch (pifasa->sa.sa_family) {
+ case AF_INET:
+ pafname = "inet";
+ break;
+ case AF_INET6:
+ pafname = "inet6";
+ break;
+ case AF_LINK:
+ pafname = "link";
+ break;
+ default:
+ pafname = "unknown";
+ break;
+ }
+
+ switch (pifasa->sa.sa_family) {
+ case AF_INET6:
+#ifdef INET6
+ {
+ const char *p =
+ inet6_n2a(&pifasa->sin6.sin6_addr);
+ strlcpy(addrbuf, p, sizeof(addrbuf));
+ break;
+ }
+#else
+ /* FALLTHROUGH */
+#endif
+ case AF_INET:
+ error = getnameinfo(&pifasa->sa,
+ pifasa->sa.sa_len,
+ addrbuf, sizeof(addrbuf), NULL, 0,
+ NI_NUMERICHOST);
+ if (error)
+ printf("getnameinfo: %s\n",
+ gai_strerror(error));
+ break;
+ case AF_LINK: {
+ (void) sdl_addr_to_hex(&pifasa->sdl, addrbuf,
+ sizeof (addrbuf));
+ break;
+ }
+ default:
+ addrbuf[0] = '\0';
+ break;
+ }
+
+ fprintf(stdout, "\t%s %s\n", pafname, addrbuf);
+ /*
+ * Print per-link IGMP information, if available.
+ */
+ if (pifasa->sa.sa_family == AF_INET) {
+ struct igmp_ifinfo igi;
+ size_t mibsize, len;
+ int mib[5];
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet.igmp.ifinfo",
+ mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ goto next_ifnet;
+ }
+ mib[mibsize] = thisifindex;
+ len = sizeof(struct igmp_ifinfo);
+ if (sysctl(mib, mibsize + 1, &igi, &len, NULL,
+ 0) == -1) {
+ perror("sysctl net.inet.igmp.ifinfo");
+ goto next_ifnet;
+ }
+ in_ifinfo(&igi);
+ }
+#ifdef INET6
+ /*
+ * Print per-link MLD information, if available.
+ */
+ if (pifasa->sa.sa_family == AF_INET6) {
+ struct mld_ifinfo mli;
+ size_t mibsize, len;
+ int mib[5];
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet6.mld.ifinfo",
+ mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ goto next_ifnet;
+ }
+ mib[mibsize] = thisifindex;
+ len = sizeof(struct mld_ifinfo);
+ if (sysctl(mib, mibsize + 1, &mli, &len, NULL,
+ 0) == -1) {
+ perror("sysctl net.inet6.mld.ifinfo");
+ goto next_ifnet;
+ }
+ in6_ifinfo(&mli);
+ }
+#endif /* INET6 */
+#if defined(INET6)
+next_ifnet:
+#endif
+ lastifasa = *pifasa;
+ }
+
+ /* Print this group address. */
+#ifdef INET6
+ if (pgsa->sa.sa_family == AF_INET6) {
+ const char *p = inet6_n2a(&pgsa->sin6.sin6_addr);
+ strlcpy(addrbuf, p, sizeof(addrbuf));
+ } else
+#endif
+ if (pgsa->sa.sa_family == AF_INET) {
+ error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len,
+ addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
+ if (error)
+ printf("getnameinfo: %s\n",
+ gai_strerror(error));
+ } else {
+ (void) sdl_addr_to_hex(&pgsa->sdl, addrbuf,
+ sizeof (addrbuf));
+ }
+
+ fprintf(stdout, "\t\tgroup %s", addrbuf);
+ if (pgsa->sa.sa_family == AF_INET) {
+ inm_print_sources_sysctl(thisifindex,
+ pgsa->sin.sin_addr);
+ }
+#ifdef INET6
+ if (pgsa->sa.sa_family == AF_INET6) {
+ in6m_print_sources_sysctl(thisifindex,
+ &pgsa->sin6.sin6_addr);
+ }
+#endif
+ fprintf(stdout, "\n");
+
+ /* Link-layer mapping, if present. */
+ pllsa = (sockunion_t *)ifma->ifma_lladdr;
+ if (pllsa != NULL) {
+ (void) sdl_addr_to_hex(&pllsa->sdl, addrbuf,
+ sizeof (addrbuf));
+ fprintf(stdout, "\t\t\tmcast-macaddr %s\n", addrbuf);
+ }
+ }
+
+ if (ifap != NULL)
+ freeifaddrs(ifap);
+
+ return (error);
+}
+
+static void
+in_ifinfo(struct igmp_ifinfo *igi)
+{
+
+ printf("\t");
+ switch (igi->igi_version) {
+ case IGMP_VERSION_1:
+ case IGMP_VERSION_2:
+ case IGMP_VERSION_3:
+ printf("igmpv%d", igi->igi_version);
+ break;
+ default:
+ printf("igmpv?(%d)", igi->igi_version);
+ break;
+ }
+ printb(" flags", igi->igi_flags, "\020\1SILENT\2LOOPBACK");
+ if (igi->igi_version == IGMP_VERSION_3) {
+ printf(" rv %u qi %u qri %u uri %u",
+ igi->igi_rv, igi->igi_qi, igi->igi_qri, igi->igi_uri);
+ }
+ if (vflag >= 2) {
+ printf(" v1timer %u v2timer %u v3timer %u",
+ igi->igi_v1_timer, igi->igi_v2_timer, igi->igi_v3_timer);
+ }
+ printf("\n");
+}
+
+static const char *inm_modes[] = {
+ "undefined",
+ "include",
+ "exclude",
+};
+
+static const char *
+inm_mode(u_int mode)
+{
+
+ if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE)
+ return (inm_modes[mode]);
+ return (NULL);
+}
+
+/*
+ * Retrieve per-group source filter mode and lists via sysctl.
+ */
+static void
+inm_print_sources_sysctl(uint32_t ifindex, struct in_addr gina)
+{
+#define MAX_SYSCTL_TRY 5
+ int mib[7];
+ int ntry = 0;
+ size_t mibsize;
+ size_t len;
+ size_t needed;
+ size_t cnt;
+ int i;
+ char *buf;
+ struct in_addr *pina;
+ uint32_t *p;
+ uint32_t fmode;
+ const char *modestr;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet.ip.mcast.filters", mib, &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+ mib[6] = gina.s_addr; /* 32 bits wide */
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.inet.ip.mcast.filters");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ if (len < sizeof(uint32_t)) {
+ perror("sysctl");
+ goto out_free;
+ }
+
+ p = (uint32_t *)buf;
+ fmode = *p++;
+ len -= sizeof(uint32_t);
+
+ modestr = inm_mode(fmode);
+ if (modestr)
+ printf(" mode %s", modestr);
+ else
+ printf(" mode (%u)", fmode);
+
+ if (vflag == 0)
+ goto out_free;
+
+ cnt = len / sizeof(struct in_addr);
+ pina = (struct in_addr *)p;
+
+ for (i = 0; i < cnt; i++) {
+ if (i == 0)
+ printf(" srcs ");
+ fprintf(stdout, "%s%s", (i == 0 ? "" : ","),
+ inet_ntoa(*pina++));
+ len -= sizeof(struct in_addr);
+ }
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.inet.ip.mcast.filters");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+#ifdef INET6
+
+static void
+in6_ifinfo(struct mld_ifinfo *mli)
+{
+
+ printf("\t");
+ switch (mli->mli_version) {
+ case MLD_VERSION_1:
+ case MLD_VERSION_2:
+ printf("mldv%d", mli->mli_version);
+ break;
+ default:
+ printf("mldv?(%d)", mli->mli_version);
+ break;
+ }
+ printb(" flags", mli->mli_flags, "\020\1SILENT");
+ if (mli->mli_version == MLD_VERSION_2) {
+ printf(" rv %u qi %u qri %u uri %u",
+ mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri);
+ }
+ if (vflag >= 2) {
+ printf(" v1timer %u v2timer %u", mli->mli_v1_timer,
+ mli->mli_v2_timer);
+ }
+ printf("\n");
+}
+
+/*
+ * Retrieve MLD per-group source filter mode and lists via sysctl.
+ *
+ * Note: The 128-bit IPv6 group addres needs to be segmented into
+ * 32-bit pieces for marshaling to sysctl. So the MIB name ends
+ * up looking like this:
+ * a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3]
+ * Assumes that pgroup originated from the kernel, so its components
+ * are already in network-byte order.
+ */
+static void
+in6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup)
+{
+#define MAX_SYSCTL_TRY 5
+ char addrbuf[INET6_ADDRSTRLEN];
+ int mib[10];
+ int ntry = 0;
+ int *pi;
+ size_t mibsize;
+ size_t len;
+ size_t needed;
+ size_t cnt;
+ int i;
+ char *buf;
+ struct in6_addr *pina;
+ uint32_t *p;
+ uint32_t fmode;
+ const char *modestr;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib,
+ &mibsize) == -1) {
+ perror("sysctlnametomib");
+ return;
+ }
+
+ needed = 0;
+ mib[5] = ifindex;
+ pi = (int *)pgroup;
+ for (i = 0; i < 4; i++)
+ mib[6 + i] = *pi++;
+
+ mibsize = sizeof(mib) / sizeof(mib[0]);
+ do {
+ if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) {
+ perror("sysctl net.inet6.ip6.mcast.filters");
+ return;
+ }
+ if ((buf = malloc(needed)) == NULL) {
+ perror("malloc");
+ return;
+ }
+ if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ perror("sysctl");
+ goto out_free;
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
+
+ len = needed;
+ if (len < sizeof(uint32_t)) {
+ perror("sysctl");
+ goto out_free;
+ }
+
+ p = (uint32_t *)buf;
+ fmode = *p++;
+ len -= sizeof(uint32_t);
+
+ modestr = inm_mode(fmode);
+ if (modestr)
+ printf(" mode %s", modestr);
+ else
+ printf(" mode (%u)", fmode);
+
+ if (vflag == 0)
+ goto out_free;
+
+ cnt = len / sizeof(struct in6_addr);
+ pina = (struct in6_addr *)p;
+
+ for (i = 0; i < cnt; i++) {
+ if (i == 0)
+ printf(" srcs ");
+ inet_ntop(AF_INET6, (const char *)pina++, addrbuf,
+ INET6_ADDRSTRLEN);
+ fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf);
+ len -= sizeof(struct in6_addr);
+ }
+ if (len > 0) {
+ fprintf(stderr, "warning: %u trailing bytes from %s\n",
+ (unsigned int)len, "net.inet6.ip6.mcast.filters");
+ }
+
+out_free:
+ free(buf);
+#undef MAX_SYSCTL_TRY
+}
+
+static const char *
+inet6_n2a(struct in6_addr *p)
+{
+ static char buf[NI_MAXHOST];
+ struct sockaddr_in6 sin6;
+ u_int32_t scopeid;
+ const int niflags = NI_NUMERICHOST;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = *p;
+ if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) ||
+ IN6_IS_ADDR_MC_NODELOCAL(p)) {
+ scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ if (scopeid) {
+ sin6.sin6_scope_id = scopeid;
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+ }
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ buf, sizeof(buf), NULL, 0, niflags) == 0) {
+ return (buf);
+ } else {
+ return ("(invalid)");
+ }
+}
+#endif /* INET6 */
+
+/*
+ * Print a value a la the %b format of the kernel's printf
+ */
+void
+printb(const char *s, unsigned int v, const char *bits)
+{
+ int i, any = 0;
+ char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++) != '\0') {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else
+ for (; *bits > 32; bits++)
+ ;
+ }
+ putchar('>');
+ }
+}
+
+/*
+ * convert hardware address to hex string for logging errors.
+ */
+static const char *
+sdl_addr_to_hex(const struct sockaddr_dl *sdl, char *orig_buf, int buflen)
+{
+ char *buf = orig_buf;
+ int i;
+ const u_char *lladdr;
+ int maxbytes = buflen / 3;
+
+ lladdr = (u_char *)(size_t)sdl->sdl_data + sdl->sdl_nlen;
+
+ if (maxbytes > sdl->sdl_alen) {
+ maxbytes = sdl->sdl_alen;
+ }
+ *buf = '\0';
+ for (i = 0; i < maxbytes; i++) {
+ snprintf(buf, 3, "%02x", lladdr[i]);
+ buf += 2;
+ *buf = (i == maxbytes - 1) ? '\0' : ':';
+ buf++;
+ }
+ return (orig_buf);
+}
+
diff --git a/network_cmds/netstat.tproj/misc.c b/network_cmds/netstat.tproj/misc.c
new file mode 100644
index 0000000..ac2a2ca
--- /dev/null
+++ b/network_cmds/netstat.tproj/misc.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/sysctl.h>
+
+#include <net/net_api_stats.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "netstat.h"
+
+void
+print_net_api_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct net_api_stats pnet_api_stats;
+ struct net_api_stats net_api_stats;
+ size_t len = sizeof(struct net_api_stats);
+ const char *mibvar = "net.api_stats";
+
+ if (sysctlbyname(mibvar, &net_api_stats, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (net_api_stats.f - pnet_api_stats.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p(nas_iflt_attach_count, "\t%lld interface filter%s currently attached\n");
+ p(nas_iflt_attach_total, "\t%lld interface filter%s attached since boot\n");
+ p(nas_iflt_attach_os_total, "\t%lld interface filter%s attached since boot by OS\n");
+
+ p(nas_ipf_add_count, "\t%lld IP filter%s currently attached\n");
+ p(nas_ipf_add_total, "\t%lld IP filter%s attached since boot\n");
+ p(nas_ipf_add_os_total, "\t%lld IP filter%s attached since boot by OS\n");
+
+ p(nas_sfltr_register_count, "\t%lld socket filter%s currently attached\n");
+ p(nas_sfltr_register_total, "\t%lld socket filter%s attached since boot\n");
+ p(nas_sfltr_register_os_total, "\t%lld socket filter%s attached since boot by OS\n");
+
+ p(nas_socket_alloc_total, "\t%lld socket%s allocated since boot\n");
+ p(nas_socket_in_kernel_total, "\t%lld socket%s allocated in-kernel since boot\n");
+ p(nas_socket_in_kernel_os_total, "\t%lld socket%s allocated in-kernel by OS\n");
+ p(nas_socket_necp_clientuuid_total, "\t%lld socket%s with NECP client UUID since boot\n");
+
+ p(nas_socket_domain_local_total, "\t%lld local domain socket%s allocated since boot\n");
+ p(nas_socket_domain_route_total, "\t%lld route domain socket%s allocated since boot\n");
+ p(nas_socket_domain_inet_total, "\t%lld inet domain socket%s allocated since boot\n");
+ p(nas_socket_domain_inet6_total, "\t%lld inet6 domain socket%s allocated since boot\n");
+ p(nas_socket_domain_system_total, "\t%lld system domain socket%s allocated since boot\n");
+ p(nas_socket_domain_multipath_total, "\t%lld multipath domain socket%s allocated since boot\n");
+ p(nas_socket_domain_key_total, "\t%lld key domain socket%s allocated since boot\n");
+ p(nas_socket_domain_ndrv_total, "\t%lld ndrv domain socket%s allocated since boot\n");
+ p(nas_socket_domain_other_total, "\t%lld other domains socket%s allocated since boot\n");
+
+ p(nas_socket_inet_stream_total, "\t%lld IPv4 stream socket%s created since boot\n");
+ p(nas_socket_inet_dgram_total, "\t%lld IPv4 datagram socket%s created since boot\n");
+ p(nas_socket_inet_dgram_connected, "\t%lld IPv4 datagram socket%s connected\n");
+ p(nas_socket_inet_dgram_dns, "\t%lld IPv4 DNS socket%s\n");
+ p(nas_socket_inet_dgram_no_data, "\t%lld IPv4 datagram socket%s without data\n");
+
+ p(nas_socket_inet6_stream_total, "\t%lld IPv6 stream socket%s created since boot\n");
+ p(nas_socket_inet6_dgram_total, "\t%lld IPv6 datagram socket%s created since boot\n");
+ p(nas_socket_inet6_dgram_connected, "\t%lld IPv6 datagram socket%s connected\n");
+ p(nas_socket_inet6_dgram_dns, "\t%lld IPv6 DNS socket%s\n");
+ p(nas_socket_inet6_dgram_no_data, "\t%lld IPv6 datagram socket%s without data\n");
+
+ p(nas_socket_mcast_join_total, "\t%lld socket multicast join%s since boot\n");
+ p(nas_socket_mcast_join_os_total, "\t%lld socket multicast join%s since boot by OS\n");
+
+ p(nas_nx_flow_inet_stream_total, "\t%lld IPv4 stream nexus flow%s added since boot\n");
+ p(nas_nx_flow_inet_dgram_total, "\t%lld IPv4 datagram nexus flow%s added since boot\n");
+
+ p(nas_nx_flow_inet6_stream_total, "\t%lld IPv6 stream nexus flow%s added since boot\n");
+ p(nas_nx_flow_inet6_dgram_total, "\t%lld IPv6 datagram nexus flow%s added since boot\n");
+
+ p(nas_ifnet_alloc_count, "\t%lld interface%s currently allocated\n");
+ p(nas_ifnet_alloc_total, "\t%lld interface%s allocated since boot\n");
+ p(nas_ifnet_alloc_os_count, "\t%lld interface%s currently allocated by OS\n");
+ p(nas_ifnet_alloc_os_total, "\t%lld extended interface%s allocated since boot by OS\n");
+
+ p(nas_pf_addrule_total, "\t%lld PF addrule operation%s since boot\n");
+ p(nas_pf_addrule_os, "\t%lld PF addrule operation%s since boot by OS\n");
+
+ p(nas_vmnet_total, "\t%lld vmnet start%s since boot\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
+
diff --git a/network_cmds/netstat.tproj/mptcp.c b/network_cmds/netstat.tproj/mptcp.c
new file mode 100644
index 0000000..70be928
--- /dev/null
+++ b/network_cmds/netstat.tproj/mptcp.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include <stdio.h>
+#include <err.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <inttypes.h>
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netinet/mptcp_var.h>
+
+#include <arpa/inet.h>
+
+#include "netstat.h"
+
+/* XXX we can't include tcp_fsm.h because inet.c already includes it. */
+static const char *tcpstates[] = {
+ "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD",
+ "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING",
+ "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT"
+};
+
+static const char *mptcpstates[] = {
+ "CLOSED", "LISTEN", "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1",
+ "CLOSING", "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", "TERMINATE"
+};
+
+int mptcp_done = 0;
+extern void inetprint (struct in_addr *, int, char *, int);
+extern void inet6print (struct in6_addr *, int, char *, int);
+
+static void
+printmptcp(int id, conninfo_mptcp_t *mptcp)
+{
+ int i;
+ conninfo_tcp_t *tcpci;
+ struct sockaddr_storage *src, *dst;
+ mptcp_flow_t *flow;
+ int af;
+
+ printf("mptcp/%-2.2d %-8.8x/%-8.8x %50s \n"
+ " [tok(%#"PRIx32") snd(%#"PRIx64") rcv(%#"PRIx64") "
+ "aid(%d)]\n", id,
+ mptcp->mptcpci_mpte_flags, mptcp->mptcpci_flags,
+ mptcpstates[mptcp->mptcpci_state], mptcp->mptcpci_rtoken,
+ mptcp->mptcpci_sndnxt, mptcp->mptcpci_rcvnxt,
+ mptcp->mptcpci_mpte_addrid);
+
+ flow = (mptcp_flow_t*)((caddr_t)mptcp + mptcp->mptcpci_flow_offset);
+
+ for (i = 0; i < mptcp->mptcpci_nflows; i++) {
+ src = &flow->flow_src;
+ dst = &flow->flow_dst;
+ af = src->ss_family;
+ printf(" tcp%d/%-2.2d ", af == AF_INET ? 4 : 6,
+ flow->flow_cid);
+ printf("%-8.8x ", flow->flow_flags);
+#define SIN(x) ((struct sockaddr_in *)(x))
+#define SIN6(x) ((struct sockaddr_in6 *)(x))
+ switch (af) {
+ case AF_INET:
+ inetprint(&SIN(src)->sin_addr, SIN(src)->sin_port,
+ "tcp", nflag);
+ inetprint(&SIN(dst)->sin_addr, SIN(dst)->sin_port,
+ "tcp", nflag);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ inet6print(&SIN6(src)->sin6_addr, SIN6(src)->sin6_port,
+ "tcp", nflag);
+ inet6print(&SIN6(dst)->sin6_addr, SIN6(dst)->sin6_port,
+ "tcp", nflag);
+ break;
+ }
+#endif
+#undef SIN
+#undef SIN6
+ tcpci = (conninfo_tcp_t*)((caddr_t)flow +
+ flow->flow_tcpci_offset);
+ printf("%s \n"
+ " [relseq(%-4.4d), err(%d)]\n",
+ tcpstates[tcpci->tcpci_tcp_info.tcpi_state],
+ flow->flow_relseq,
+ flow->flow_soerror);
+
+ flow = (mptcp_flow_t*)((caddr_t)flow + flow->flow_len);
+ }
+}
+
+void
+mptcppr(uint32_t off, char *name, int af)
+{
+#pragma unused(off, name, af)
+ const char *mibvar = "net.inet.mptcp.pcblist";
+ size_t len = 0;
+ conninfo_mptcp_t *mptcp;
+ char *buf, *bufp;
+ int id = 0;
+
+ if (Lflag || Aflag || mptcp_done)
+ return;
+ mptcp_done = 1;
+
+ if (sysctlbyname(mibvar, 0, &len, NULL, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == NULL) {
+ warn("malloc");
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, NULL, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ printf("Active Multipath Internet connections\n");
+ printf("%-8.8s %-9.9s %-22.22s %-22.22s %-11.11s\n",
+ "Proto/ID", "Flags",
+ "Local Address", "Foreign Address",
+ "(state)");
+
+ bufp = buf;
+ while (bufp < buf + len) {
+ /* Sanity check */
+ if (buf + len - bufp < sizeof(conninfo_mptcp_t))
+ break;
+ mptcp = (conninfo_mptcp_t *)bufp;
+ printmptcp(id++, mptcp);
+ bufp += mptcp->mptcpci_len;
+ }
+ free(buf);
+}
diff --git a/network_cmds/netstat.tproj/netstat.1 b/network_cmds/netstat.tproj/netstat.1
new file mode 100644
index 0000000..61ab843
--- /dev/null
+++ b/network_cmds/netstat.tproj/netstat.1
@@ -0,0 +1,445 @@
+.\" Copyright (c) 2015 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1983, 1990, 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)netstat.1 8.8 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/netstat/netstat.1,v 1.22.2.7 2001/08/10 09:07:09 ru Exp $
+.\"
+.Dd June 15, 2001
+.Dt NETSTAT 1
+.Os Darwin
+.Sh NAME
+.Nm netstat
+.Nd show network status
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaLlnW
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Nm
+.Op Fl gilns
+.Op Fl v
+.Op Fl f Ar address_family
+.Op Fl I Ar interface
+.Nm
+.Fl i | I Ar interface
+.Op Fl w Ar wait
+.Op Fl c Ar queue
+.Op Fl abdgqRtS
+.Nm
+.Fl s Op Fl s
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Op Fl w Ar wait
+.Nm
+.Fl i | I Ar interface Fl s
+.Op Fl f Ar address_family | Fl p Ar protocol
+.Nm
+.Fl m
+.Op Fl m
+.Nm
+.Fl r
+.Op Fl Aaln
+.Op Fl f Ar address_family
+.Nm
+.Fl rs
+.Op Fl s
+.\"-----------------------------------------------------------------------------------------
+.Sh DESCRIPTION
+.\"-----------------------------------------------------------------------------------------
+The
+.Nm
+command symbolically displays the contents of various network-related data structures.
+There are a number of output formats, depending on the options for the information presented.
+The first form of the command displays a list of active sockets for each protocol.
+The second form presents the contents of one of the other network data structures according
+to the option selected. Using the third form, with a
+.Ar wait
+interval specified,
+.Nm
+will continuously display the information regarding packet traffic on the configured network
+interfaces. The fourth form displays statistics for the specified protocol or address family. If a
+.Ar wait
+interval is specified, the protocol information over the last interval seconds will be displayed.
+The fifth form displays per-interface statistics for the specified protocol or address family.
+The sixth form displays
+.Xr mbuf 9
+statistics. The seventh form displays routing table for the specified address family. The
+eighth form displays routing statistics.
+.Pp
+The options have the following meaning:
+.Bl -tag -width flag
+.It Fl A
+With the default display, show the address of any protocol control blocks associated with
+sockets and the flow hash; used for debugging.
+.It Fl a
+With the default display, show the state of all sockets; normally sockets used by server
+processes are not shown. With the routing table display (option
+.Fl r ,
+as described below), show protocol-cloned routes (routes generated by a
+.Dv RTF_PRCLONING
+parent route); normally these routes are not shown.
+.It Fl b
+With the interface display (option
+.Fl i ,
+as described below), show the number of bytes in and out.
+.It Fl c Ar queue
+With the queue statistics (option
+.Fl q ,
+as described below), show only those for the specified
+.Ar queue .
+.It Fl d
+With either interface display (option
+.Fl i
+or an interval, as described below), show the number of dropped packets.
+.It Fl f Ar address_family
+Limit statistics or address control block reports to those of the specified
+.Ar address family .
+The following address families are recognized:
+.Ar inet ,
+for
+.Dv AF_INET ,
+.Ar inet6 ,
+for
+.Dv AF_INET6
+and
+.Ar unix ,
+for
+.Dv AF_UNIX .
+.It Fl g
+Show information related to multicast (group address) membership. If the
+.Fl s
+option is also present, show extended interface group management statistics. If the
+.Fl v
+option is specified, show link-layer memberships; they are suppressed by default.
+Source lists for each group will also be printed. Specifiying
+.Fl v
+twice will print the control plane timers for each interface and the source list counters
+for each group. If the
+.Fl i
+is specified, only that interface will be shown. If the
+.Fl f
+is specified, only information for the address family will be displayed.
+.It Fl I Ar interface
+Show information about the specified interface; used with a
+.Ar wait
+interval as described below.
+If the
+.Fl s
+option is present, show per-interface protocol statistics on the
+.Ar interface
+for the specified
+.Ar address_family
+or
+.Ar protocol ,
+or for all protocol families.
+.It Fl i
+Show the state of interfaces which have been auto-configured (interfaces statically
+configured into a system, but not located at boot time are not shown). If the
+.Fl a
+options is also present, multicast addresses currently in use are shown for each
+Ethernet interface and for each IP interface address. Multicast addresses are shown
+on separate lines following the interface address with which they are associated.
+If the
+.Fl s
+option is present, show per-interface statistics on all interfaces for the specified
+.Ar address_family
+or
+.Ar protocol ,
+or for all protocol families.
+.It Fl L
+Show the size of the various listen queues. The first count shows the number of
+unaccepted connections. The second count shows the amount of unaccepted incomplete
+connections. The third count is the maximum number of queued connections.
+.It Fl l
+Print full IPv6 address.
+.It Fl m
+Show statistics recorded by the memory management routines (the network stack manages a private pool of memory buffers). More detailed information about the buffers, which includes their cache related statistics, can be obtained by using
+.Fl mm
+or
+.Fl m
+.Fl m
+option.
+.It Fl n
+Show network addresses as numbers (normally
+.Nm
+interprets addresses and attempts to display them symbolically). This option may be
+used with any of the display formats.
+.It Fl p Ar protocol
+Show statistics about
+.Ar protocol ,
+which is either a well-known name for a protocol or an alias for it. Some protocol
+names and aliases are listed in the file
+.Pa /etc/protocols .
+The special protocol name
+.Dq bdg
+is used to show bridging statistics. A null response typically means that there are
+no interesting numbers to report. The program will complain if
+.Ar protocol
+is unknown or if there is no statistics routine for it.
+.It Fl q
+Show network interface send queue statistics. By default all queues are displayed, unless
+specified with
+.Fl c .
+This option requires specifying an interface with
+.Fl I
+option. More detailed information about the queues, which includes their queueing algorithm related statistics, can be obtained by using
+.Fl qq
+or
+.Fl q
+.Fl q
+option.
+.It Fl r
+Show the routing tables. Use with
+.Fl a
+to show protocol-cloned routes. When
+.Fl s
+is also present, show routing statistics instead. When
+.Fl l
+is also present,
+.Nm
+assumes more columns are there and the maximum transmission unit.
+More detailed information about the route metrics are displayed with
+.Fl ll
+for TCP round trip times
+.Fl lll
+for all metrics.
+Use the
+.Fl z
+flags to display only entries with non-zero RTT values.
+.Pq Dq mtu
+are also displayed.
+.It Fl R
+Show reachability information. Use with
+.Fl i
+to show link-layer reachability information for a given interface.
+.It Fl s
+Show per-protocol statistics. If this option is repeated, counters with a value of
+zero are suppressed. For security reasons, root privileges are required to read TCP statistics and in the absence of such privileges all TCP counters will be reported as zero.
+.It Fl S
+Show interface link status and interface state information about the specified interface. This option requires specifying an interface with
+.Fl I
+option.
+.It Fl v
+Increase verbosity level.
+.It Fl W
+In certain displays, avoid truncating addresses even if this causes some fields to
+overflow.
+.It Fl w Ar wait
+Show network interface or protocol statistics at intervals of
+.Ar wait
+seconds.
+.It Fl x
+Show extended link-layer reachability information in addition to that shown by
+the
+.Fl R
+flag.
+.El
+.Pp
+.\"-------------------------------------------------------------------------------
+.Sh OUTPUT
+.\"-------------------------------------------------------------------------------
+The default display, for active sockets, shows the local and remote addresses,
+send and receive queue sizes (in bytes), protocol, and the internal state of
+the protocol. Address formats are of the form
+.Dq host.port
+or
+.Dq network.port
+if a socket's address specifies a network but no specific host address.
+If known, the host and network addresses are displayed symbolically
+according to the databases
+.Pa /etc/hosts
+and
+.Pa /etc/networks ,
+respectively. If a symbolic name for an address is unknown, or if the
+.Fl n
+option is specified, the address is printed numerically, according to the
+address family. For more information regarding the Internet
+.Dq dot format ,
+refer to
+.Xr inet 3 ) .
+Unspecified,
+or
+.Dq wildcard ,
+addresses and ports appear as
+.Dq * .
+.Pp
+Internet domain socket states:
+.Bl -column X LISTEN
+CLOSED: The socket is not in use.
+.Pp
+LISTEN: The socket is listening for incoming connections. Unconnected
+listening sockets like these are only displayed when using the -a option.
+.Pp
+SYN_SENT: The socket is actively trying to establish a connection to a
+remote peer.
+.Pp
+SYN_RCVD: The socket has passively received a connection request from a
+remote peer.
+.Pp
+ESTABLISHED: The socket has an established connection between a local
+application and a remote peer.
+.Pp
+CLOSE_WAIT: The socket connection has been closed by the remote peer,
+and the system is waiting for the local application to close its half of
+the connection.
+.Pp
+LAST_ACK: The socket connection has been closed by the remote peer, the
+local application has closed its half of the connection, and the system
+is waiting for the remote peer to acknowledge the close.
+.Pp
+FIN_WAIT_1: The socket connection has been closed by the local
+application, the remote peer has not yet acknowledged the close, and the
+system is waiting for it to close its half of the connection.
+.Pp
+FIN_WAIT_2: The socket connection has been closed by the local
+application, the remote peer has acknowledged the close, and the system
+is waiting for it to close its half of the connection.
+.Pp
+CLOSING: The socket connection has been closed by the local application
+and the remote peer simultaneously, and the remote peer has not yet
+acknowledged the close attempt of the local application.
+.Pp
+TIME_WAIT: The socket connection has been closed by the local
+application, the remote peer has closed its half of the connection, and
+the system is waiting to be sure that the remote peer received the last
+acknowledgement.
+.El
+.Pp
+The interface display provides a table of cumulative statistics regarding
+packets transferred, errors, and collisions. The network addresses of the
+interface and the maximum transmission unit
+.Pq Dq mtu
+are also displayed.
+.Pp
+The routing table display indicates the available routes and their status.
+Each route consists of a destination host or network and a gateway to use
+in forwarding packets. The flags field shows a collection of information
+about the route stored as binary choices. The individual flags are discussed
+in more detail in the
+.Xr route 8
+and
+.Xr route 4
+manual pages. The mapping between letters and flags is:
+.Bl -column XXXX RTF_BLACKHOLE
+1 RTF_PROTO1 Protocol specific routing flag #1
+2 RTF_PROTO2 Protocol specific routing flag #2
+3 RTF_PROTO3 Protocol specific routing flag #3
+B RTF_BLACKHOLE Just discard packets (during updates)
+b RTF_BROADCAST The route represents a broadcast address
+C RTF_CLONING Generate new routes on use
+c RTF_PRCLONING Protocol-specified generate new routes on use
+D RTF_DYNAMIC Created dynamically (by redirect)
+G RTF_GATEWAY Destination requires forwarding by intermediary
+H RTF_HOST Host entry (net otherwise)
+I RTF_IFSCOPE Route is associated with an interface scope
+i RTF_IFREF Route is holding a reference to the interface
+L RTF_LLINFO Valid protocol to link address translation
+M RTF_MODIFIED Modified dynamically (by redirect)
+m RTF_MULTICAST The route represents a multicast address
+R RTF_REJECT Host or net unreachable
+r RTF_ROUTER Host is a default router
+S RTF_STATIC Manually added
+U RTF_UP Route usable
+W RTF_WASCLONED Route was generated as a result of cloning
+X RTF_XRESOLVE External daemon translates proto to link address
+Y RTF_PROXY Proxying; cloned routes will not be scoped
+.El
+.Pp
+Direct routes are created for each interface attached to the local host;
+the gateway field for such entries shows the address of the outgoing
+interface. The refcnt field gives the current number of active uses of
+the route. Connection oriented protocols normally hold on to a single
+route for the duration of a connection while connectionless protocols
+obtain a route while sending to the same destination. The use field
+provides a count of the number of packets sent using that route. The
+interface entry indicates the network interface utilized for the route.
+A route which is marked with the RTF_IFSCOPE flag is instantiated for
+the corresponding interface. A cloning route which is marked with the
+RTF_PROXY flag will not generate new routes that are associated
+with its interface scope.
+.Pp
+When
+.Nm netstat
+is invoked with the
+.Fl w
+option and a
+.Ar wait
+interval argument, it displays a running count of statistics related to
+network interfaces or protocols. An obsolete version of this option used a numeric
+parameter with no option, and is currently supported for backward
+compatibility. By default, this display summarizes information for all
+interfaces. Information for a specific interface may be displayed with the
+.Fl I
+option.
+.Sh SEE ALSO
+.Xr nfsstat 1 ,
+.Xr ps 1 ,
+.Xr inet 4 ,
+.Xr unix 4 ,
+.Xr hosts 5 ,
+.Xr networks 5 ,
+.Xr protocols 5 ,
+.Xr route 8 ,
+.Xr services 5 ,
+.Xr iostat 8 ,
+.Sh HISTORY
+The
+.Nm netstat
+command appeared in
+.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
+.Sh BUGS
+The notion of errors is ill-defined.
diff --git a/network_cmds/netstat.tproj/netstat.h b/network_cmds/netstat.tproj/netstat.h
new file mode 100644
index 0000000..68511da
--- /dev/null
+++ b/network_cmds/netstat.tproj/netstat.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2008-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1992, 1993
+ * Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)netstat.h 8.2 (Berkeley) 1/4/94
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <stdint.h>
+
+#include <TargetConditionals.h>
+
+extern int Aflag; /* show addresses of protocol control block */
+extern int aflag; /* show all sockets (including servers) */
+extern int bflag; /* show i/f total bytes in/out */
+extern int cflag; /* show specific classq */
+extern int dflag; /* show i/f dropped packets */
+extern int Fflag; /* show i/f forwarded packets */
+extern int gflag; /* show group (multicast) routing or stats */
+extern int iflag; /* show interfaces */
+extern int lflag; /* show routing table with use and ref */
+extern int Lflag; /* show size of listen queues */
+extern int mflag; /* show memory stats */
+extern int nflag; /* show addresses numerically */
+extern int Rflag; /* show reachability information */
+extern int rflag; /* show routing tables (or routing stats) */
+extern int sflag; /* show protocol statistics */
+extern int prioflag; /* show packet priority statistics */
+extern int tflag; /* show i/f watchdog timers */
+extern int vflag; /* more verbose */
+extern int Wflag; /* wide display */
+extern int qflag; /* Display ifclassq stats */
+extern int Qflag; /* Display opportunistic polling stats */
+extern int xflag; /* show extended link-layer reachability information */
+extern int zflag; /* show only entries with non zero rtt metrics */
+
+extern int cq; /* send classq index (-1 for all) */
+extern int interval; /* repeat interval for i/f stats */
+
+extern char *interface; /* desired i/f for stats, or NULL for all i/fs */
+extern int unit; /* unit number for above */
+
+extern int af; /* address family */
+
+extern char *plural(int);
+extern char *plurales(int);
+extern char *pluralies(int);
+
+extern void protopr(uint32_t, char *, int);
+extern void mptcppr(uint32_t, char *, int);
+extern void tcp_stats(uint32_t, char *, int);
+extern void mptcp_stats(uint32_t, char *, int);
+extern void udp_stats(uint32_t, char *, int);
+extern void ip_stats(uint32_t, char *, int);
+extern void icmp_stats(uint32_t, char *, int);
+extern void igmp_stats(uint32_t, char *, int);
+extern void arp_stats(uint32_t, char *, int);
+#ifdef IPSEC
+extern void ipsec_stats(uint32_t, char *, int);
+#endif
+
+#ifdef INET6
+extern void ip6_stats(uint32_t, char *, int);
+extern void ip6_ifstats(char *);
+extern void icmp6_stats(uint32_t, char *, int);
+extern void icmp6_ifstats(char *);
+extern void rip6_stats(uint32_t, char *, int);
+
+/* forward references */
+struct sockaddr_in6;
+struct in6_addr;
+struct sockaddr;
+
+extern char *routename6(struct sockaddr_in6 *);
+extern char *netname6(struct sockaddr_in6 *, struct sockaddr *);
+#endif /*INET6*/
+
+#ifdef IPSEC
+extern void pfkey_stats(uint32_t, char *, int);
+#endif
+
+extern void systmpr(uint32_t, char *, int);
+extern void kctl_stats(uint32_t, char *, int);
+extern void kevt_stats(uint32_t, char *, int);
+
+extern void mbpr(void);
+
+extern void intpr(void (*)(char *));
+extern void intpr_ri(void (*)(char *));
+extern void intervalpr(void (*)(uint32_t, char *, int), uint32_t,
+ char *, int);
+
+extern void pr_rthdr(int);
+extern void pr_family(int);
+extern void rt_stats(void);
+extern void upHex(char *);
+extern char *routename(uint32_t);
+extern char *netname(uint32_t, uint32_t);
+extern void routepr(void);
+
+extern void unixpr(void);
+extern void aqstatpr(void);
+extern void rxpollstatpr(void);
+extern void vsockpr(uint32_t,char *,int);
+
+extern void ifmalist_dump(void);
+
+extern int print_time(void);
+extern void print_link_status(const char *);
+
+extern void print_extbkidle_stats(uint32_t, char *, int);
+extern void print_nstat_stats(uint32_t, char *, int);
+extern void print_net_api_stats(uint32_t, char *, int);
+
diff --git a/network_cmds/netstat.tproj/route.c b/network_cmds/netstat.tproj/route.c
new file mode 100644
index 0000000..943e3c8
--- /dev/null
+++ b/network_cmds/netstat.tproj/route.c
@@ -0,0 +1,795 @@
+/*
+ * Copyright (c) 2008-2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/route.h>
+#include <net/radix.h>
+
+#include <netinet/in.h>
+
+#include <sys/sysctl.h>
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <err.h>
+#include <time.h>
+#include "netstat.h"
+
+/* alignment constraint for routing socket */
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+/*
+ * Definitions for showing gateway flags.
+ */
+struct bits {
+ uint32_t b_mask;
+ char b_val;
+} bits[] = {
+ { RTF_UP, 'U' },
+ { RTF_GATEWAY, 'G' },
+ { RTF_HOST, 'H' },
+ { RTF_REJECT, 'R' },
+ { RTF_DYNAMIC, 'D' },
+ { RTF_MODIFIED, 'M' },
+ { RTF_MULTICAST,'m' },
+ { RTF_DONE, 'd' }, /* Completed -- for routing messages only */
+ { RTF_CLONING, 'C' },
+ { RTF_XRESOLVE, 'X' },
+ { RTF_LLINFO, 'L' },
+ { RTF_STATIC, 'S' },
+ { RTF_PROTO1, '1' },
+ { RTF_PROTO2, '2' },
+ { RTF_WASCLONED,'W' },
+ { RTF_PRCLONING,'c' },
+ { RTF_PROTO3, '3' },
+ { RTF_BLACKHOLE,'B' },
+ { RTF_BROADCAST,'b' },
+ { RTF_IFSCOPE, 'I' },
+ { RTF_IFREF, 'i' },
+ { RTF_PROXY, 'Y' },
+ { RTF_ROUTER, 'r' },
+ { 0 }
+};
+
+typedef union {
+ uint32_t dummy; /* Helps align structure. */
+ struct sockaddr u_sa;
+ u_short u_data[128];
+} sa_u;
+
+static void np_rtentry __P((struct rt_msghdr2 *));
+static void p_sockaddr __P((struct sockaddr *, struct sockaddr *, int, int));
+static void p_flags __P((int, char *));
+static uint32_t forgemask __P((uint32_t));
+static void domask __P((char *, uint32_t, uint32_t));
+
+/*
+ * Print address family header before a section of the routing table.
+ */
+void
+pr_family(int af)
+{
+ char *afname;
+
+ switch (af) {
+ case AF_INET:
+ afname = "Internet";
+ break;
+#ifdef INET6
+ case AF_INET6:
+ afname = "Internet6";
+ break;
+#endif /*INET6*/
+ case AF_IPX:
+ afname = "IPX";
+ break;
+ default:
+ afname = NULL;
+ break;
+ }
+ if (afname)
+ printf("\n%s:\n", afname);
+ else
+ printf("\nProtocol Family %d:\n", af);
+}
+
+/* column widths; each followed by one space */
+#ifndef INET6
+#define WID_DST(af) 18 /* width of destination column */
+#define WID_GW(af) 18 /* width of gateway column */
+#define WID_RT_IFA(af) 18 /* width of source column */
+#define WID_IF(af) 7 /* width of netif column */
+#else
+#define WID_DST(af) \
+ ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39: 18)) : 18)
+#define WID_GW(af) \
+ ((af) == AF_INET6 ? (lflag ? 31 : (nflag ? 31 : 18)) : 18)
+#define WID_RT_IFA(af) \
+ ((af) == AF_INET6 ? (lflag ? 39 : (nflag ? 39 : 18)) : 18)
+#define WID_IF(af) ((af) == AF_INET6 ? 8 : 7)
+#endif /*INET6*/
+
+/*
+ * Print header for routing table columns.
+ */
+void
+pr_rthdr(int af)
+{
+ if (lflag) {
+ if (lflag > 2)
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
+ "%10s %10s %8s %8s %8s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire",
+ "rtt(ms)", "rttvar(ms)", "recvpipe", "sendpipe", "ssthresh");
+ else if (lflag > 1)
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s "
+ "%10s %10s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire",
+ "rtt(ms)", "rttvar(ms)");
+ else
+ printf("%-*.*s %-*.*s %-*.*s %-10.10s %6.6s %8.8s %6.6s %*.*s %6s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ WID_RT_IFA(af), WID_RT_IFA(af), "RT_IFA",
+ "Flags", "Refs", "Use", "Mtu",
+ WID_IF(af), WID_IF(af), "Netif", "Expire");
+ } else {
+ printf("%-*.*s %-*.*s %-10.10s %*.*s %6s\n",
+ WID_DST(af), WID_DST(af), "Destination",
+ WID_GW(af), WID_GW(af), "Gateway",
+ "Flags", WID_IF(af), WID_IF(af), "Netif", "Expire");
+ }
+}
+
+/*
+ * Print routing tables.
+ */
+void
+routepr(void)
+{
+ size_t extra_space;
+ size_t needed;
+ int mib[6];
+ char *buf, *next, *lim;
+ struct rt_msghdr2 *rtm;
+ int try = 1;
+
+ printf("Routing tables\n");
+
+ again:
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP2;
+ mib[5] = 0;
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
+ err(1, "sysctl: net.route.0.0.dump estimate");
+ }
+ /* allocate extra space in case the table grows */
+ extra_space = needed / 2;
+ if (needed <= (SIZE_MAX - extra_space)) {
+ needed += extra_space;
+ }
+ if ((buf = malloc(needed)) == 0) {
+ err(2, "malloc(%lu)", (unsigned long)needed);
+ }
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+#define MAX_TRIES 10
+ if (errno == ENOMEM && try < MAX_TRIES) {
+ /* the buffer we provided was too small, try again */
+ free(buf);
+ try++;
+ goto again;
+ }
+ err(1, "sysctl: net.route.0.0.dump");
+ }
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr2 *)next;
+ np_rtentry(rtm);
+ }
+}
+
+static void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
+ } else {
+ rti_info[i] = NULL;
+ }
+}
+}
+
+static void
+np_rtentry(struct rt_msghdr2 *rtm)
+{
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+ struct sockaddr *rti_info[RTAX_MAX];
+ static int old_fam;
+ int fam = 0;
+ u_short lastindex = 0xffff;
+ static char ifname[IFNAMSIZ + 1];
+ sa_u addr, mask;
+
+ /*
+ * Don't print protocol-cloned routes unless -a.
+ */
+ if ((rtm->rtm_flags & RTF_WASCLONED) &&
+ (rtm->rtm_parentflags & RTF_PRCLONING) &&
+ !aflag) {
+ return;
+ }
+
+ if (lflag > 1 && zflag != 0 && rtm->rtm_rmx.rmx_rtt == 0 && rtm->rtm_rmx.rmx_rttvar == 0)
+ return;
+ fam = sa->sa_family;
+ if (af != AF_UNSPEC && af != fam)
+ return;
+ if (fam != old_fam) {
+ pr_family(fam);
+ pr_rthdr(fam);
+ old_fam = fam;
+ }
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ bzero(&addr, sizeof(addr));
+ if ((rtm->rtm_addrs & RTA_DST))
+ bcopy(rti_info[RTAX_DST], &addr, rti_info[RTAX_DST]->sa_len);
+ bzero(&mask, sizeof(mask));
+ if ((rtm->rtm_addrs & RTA_NETMASK))
+ bcopy(rti_info[RTAX_NETMASK], &mask, rti_info[RTAX_NETMASK]->sa_len);
+ p_sockaddr(&addr.u_sa, &mask.u_sa, rtm->rtm_flags,
+ WID_DST(addr.u_sa.sa_family));
+
+ p_sockaddr(rti_info[RTAX_GATEWAY], NULL, RTF_HOST,
+ WID_GW(addr.u_sa.sa_family));
+
+ if (lflag && (rtm->rtm_addrs & RTA_IFA)) {
+ p_sockaddr(rti_info[RTAX_IFA], NULL, RTF_HOST,
+ WID_RT_IFA(addr.u_sa.sa_family));
+ }
+
+ p_flags(rtm->rtm_flags, "%-10.10s ");
+
+ if (lflag) {
+ printf("%6u %8u ", rtm->rtm_refcnt, (unsigned int)rtm->rtm_use);
+ if (rtm->rtm_rmx.rmx_mtu != 0)
+ printf("%6u ", rtm->rtm_rmx.rmx_mtu);
+ else
+ printf("%6s ", "");
+ }
+
+ if (rtm->rtm_index != lastindex) {
+ if_indextoname(rtm->rtm_index, ifname);
+ lastindex = rtm->rtm_index;
+ }
+ printf("%*.*s", WID_IF(addr.u_sa.sa_family),
+ WID_IF(addr.u_sa.sa_family), ifname);
+
+ if (rtm->rtm_rmx.rmx_expire) {
+ time_t expire_time;
+
+ if ((expire_time =
+ rtm->rtm_rmx.rmx_expire - time((time_t *)0)) > 0)
+ printf(" %6d", (int)expire_time);
+ else
+ printf(" %6s", "!");
+ } else {
+ printf(" %6s", "");
+ }
+ if (lflag > 1) {
+ if (rtm->rtm_rmx.rmx_rtt != 0)
+ printf(" %6u.%03u", rtm->rtm_rmx.rmx_rtt / 1000,
+ rtm->rtm_rmx.rmx_rtt % 1000);
+ else
+ printf(" %10s", "");
+ if (rtm->rtm_rmx.rmx_rttvar != 0)
+ printf(" %6u.%03u", rtm->rtm_rmx.rmx_rttvar / 1000,
+ rtm->rtm_rmx.rmx_rttvar % 1000);
+ else
+ printf(" %10s", "");
+ if (lflag > 2) {
+ if (rtm->rtm_rmx.rmx_recvpipe != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_recvpipe);
+ else
+ printf(" %8s", "");
+ if (rtm->rtm_rmx.rmx_sendpipe != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_sendpipe);
+ else
+ printf(" %8s", "");
+ if (rtm->rtm_rmx.rmx_ssthresh != 0)
+ printf(" %8u", rtm->rtm_rmx.rmx_ssthresh);
+ else
+ printf(" %8s", "");
+ }
+ }
+ putchar('\n');
+}
+
+static void
+p_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags, int width)
+{
+ char workbuf[128], *cplim;
+ char *cp = workbuf;
+
+ switch(sa->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ if ((sin->sin_addr.s_addr == INADDR_ANY) &&
+ mask &&
+ (ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr) == 0L || mask->sa_len == 0))
+ cp = "default" ;
+ else if (flags & RTF_HOST)
+ cp = routename(sin->sin_addr.s_addr);
+ else if (mask)
+ cp = netname(sin->sin_addr.s_addr,
+ ntohl(((struct sockaddr_in *)mask)->
+ sin_addr.s_addr));
+ else
+ cp = netname(sin->sin_addr.s_addr, 0L);
+ break;
+ }
+
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+ struct in6_addr *in6 = &sa6->sin6_addr;
+
+ /*
+ * XXX: This is a special workaround for KAME kernels.
+ * sin6_scope_id field of SA should be set in the future.
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(in6) ||
+ IN6_IS_ADDR_MC_NODELOCAL(in6) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(in6)) {
+ /* XXX: override is ok? */
+ sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
+ *(u_short *)&in6->s6_addr[2] = 0;
+ }
+
+ if (flags & RTF_HOST)
+ cp = routename6(sa6);
+ else if (mask)
+ cp = netname6(sa6, mask);
+ else
+ cp = netname6(sa6, NULL);
+ break;
+ }
+#endif /*INET6*/
+
+ case AF_LINK: {
+ struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
+
+ if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0) {
+ (void) snprintf(workbuf, sizeof(workbuf), "link#%d", sdl->sdl_index);
+ } else {
+ switch (sdl->sdl_type) {
+
+ case IFT_ETHER: {
+ int i;
+ u_char *lla = (u_char *)sdl->sdl_data +
+ sdl->sdl_nlen;
+
+ cplim = "";
+ for (i = 0; i < sdl->sdl_alen; i++, lla++) {
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%s%x", cplim, *lla);
+ cplim = ":";
+ }
+ cp = workbuf;
+ break;
+ }
+
+ default:
+ cp = link_ntoa(sdl);
+ break;
+ }
+ }
+ break;
+ }
+
+ default: {
+ u_char *s = (u_char *)sa->sa_data, *slim;
+
+ slim = sa->sa_len + (u_char *) sa;
+ cplim = cp + sizeof(workbuf) - 6;
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "(%d)", sa->sa_family);
+ while (s < slim && cp < cplim) {
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), " %02x", *s++);
+ if (s < slim)
+ cp += snprintf(cp, sizeof(workbuf) - (cp - workbuf), "%02x", *s++);
+ }
+ cp = workbuf;
+ }
+ }
+ if (width < 0 ) {
+ printf("%s ", cp);
+ } else {
+ if (nflag)
+ printf("%-*s ", width, cp);
+ else
+ printf("%-*.*s ", width, width, cp);
+ }
+}
+
+static void
+p_flags(int f, char *format)
+{
+ char name[33], *flags;
+ struct bits *p = bits;
+
+ for (flags = name; p->b_mask; p++)
+ if (p->b_mask & f)
+ *flags++ = p->b_val;
+ *flags = '\0';
+ printf(format, name);
+}
+
+char *
+routename(uint32_t in)
+{
+ char *cp;
+ static char line[MAXHOSTNAMELEN];
+ struct hostent *hp;
+
+ cp = 0;
+ if (!nflag) {
+ hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ cp = hp->h_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ if (cp) {
+ strlcpy(line, cp, sizeof(line));
+ } else {
+#define C(x) ((x) & 0xff)
+ in = ntohl(in);
+ snprintf(line, sizeof(line), "%u.%u.%u.%u",
+ C(in >> 24), C(in >> 16), C(in >> 8), C(in));
+ }
+ return (line);
+}
+
+static uint32_t
+forgemask(uint32_t a)
+{
+ uint32_t m;
+
+ if (IN_CLASSA(a))
+ m = IN_CLASSA_NET;
+ else if (IN_CLASSB(a))
+ m = IN_CLASSB_NET;
+ else
+ m = IN_CLASSC_NET;
+ return (m);
+}
+
+static void
+domask(char *dst, uint32_t addr, uint32_t mask)
+{
+ int b, i;
+
+ if (!mask || (forgemask(addr) == mask)) {
+ *dst = '\0';
+ return;
+ }
+ i = 0;
+ for (b = 0; b < 32; b++)
+ if (mask & (1 << b)) {
+ int bb;
+
+ i = b;
+ for (bb = b+1; bb < 32; bb++)
+ if (!(mask & (1 << bb))) {
+ i = -1; /* noncontig */
+ break;
+ }
+ break;
+ }
+ if (i == -1)
+ snprintf(dst, sizeof(dst), "&0x%x", mask);
+ else
+ snprintf(dst, sizeof(dst), "/%d", 32-i);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net or subnet, not a host.
+ */
+char *
+netname(uint32_t in, uint32_t mask)
+{
+ char *cp = 0;
+ static char line[MAXHOSTNAMELEN];
+ struct netent *np = 0;
+ uint32_t net, omask, dmask;
+ uint32_t i;
+
+ i = ntohl(in);
+ dmask = forgemask(i);
+ omask = mask;
+ if (!nflag && i) {
+ net = i & dmask;
+ if (!(np = getnetbyaddr(i, AF_INET)) && net != i)
+ np = getnetbyaddr(net, AF_INET);
+ if (np) {
+ cp = np->n_name;
+ //### trimdomain(cp, strlen(cp));
+ }
+ }
+ if (cp)
+ strlcpy(line, cp, sizeof(line));
+ else {
+ switch (dmask) {
+ case IN_CLASSA_NET:
+ if ((i & IN_CLASSA_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u", C(i >> 24));
+ break;
+ }
+ /* FALLTHROUGH */
+ case IN_CLASSB_NET:
+ if ((i & IN_CLASSB_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u.%u",
+ C(i >> 24), C(i >> 16));
+ break;
+ }
+ /* FALLTHROUGH */
+ case IN_CLASSC_NET:
+ if ((i & IN_CLASSC_HOST) == 0) {
+ snprintf(line, sizeof(line), "%u.%u.%u",
+ C(i >> 24), C(i >> 16), C(i >> 8));
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ snprintf(line, sizeof(line), "%u.%u.%u.%u",
+ C(i >> 24), C(i >> 16), C(i >> 8), C(i));
+ break;
+ }
+ }
+ domask(line+strlen(line), i, omask);
+ return (line);
+}
+
+#ifdef INET6
+char *
+netname6(struct sockaddr_in6 *sa6, struct sockaddr *sam)
+{
+ static char line[MAXHOSTNAMELEN];
+ u_char *lim;
+ int masklen, illegal = 0, flag = NI_WITHSCOPEID;
+ struct in6_addr *mask = sam ? &((struct sockaddr_in6 *)sam)->sin6_addr : 0;
+
+ if (sam && sam->sa_len == 0) {
+ masklen = 0;
+ } else if (mask) {
+ u_char *p = (u_char *)mask;
+ for (masklen = 0, lim = p + 16; p < lim; p++) {
+ switch (*p) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ break;
+ case 0xfc:
+ masklen += 6;
+ break;
+ case 0xf8:
+ masklen += 5;
+ break;
+ case 0xf0:
+ masklen += 4;
+ break;
+ case 0xe0:
+ masklen += 3;
+ break;
+ case 0xc0:
+ masklen += 2;
+ break;
+ case 0x80:
+ masklen += 1;
+ break;
+ case 0x00:
+ break;
+ default:
+ illegal ++;
+ break;
+ }
+ }
+ if (illegal)
+ fprintf(stderr, "illegal prefixlen\n");
+ } else {
+ masklen = 128;
+ }
+ if (masklen == 0 && IN6_IS_ADDR_UNSPECIFIED(&sa6->sin6_addr))
+ return("default");
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+ getnameinfo((struct sockaddr *)sa6, sa6->sin6_len, line, sizeof(line),
+ NULL, 0, flag);
+
+ if (nflag)
+ snprintf(&line[strlen(line)], sizeof(line) - strlen(line), "/%d", masklen);
+
+ return line;
+}
+
+char *
+routename6(struct sockaddr_in6 *sa6)
+{
+ static char line[MAXHOSTNAMELEN];
+ int flag = NI_WITHSCOPEID;
+ /* use local variable for safety */
+ struct sockaddr_in6 sa6_local = {sizeof(sa6_local), AF_INET6, };
+
+ sa6_local.sin6_addr = sa6->sin6_addr;
+ sa6_local.sin6_scope_id = sa6->sin6_scope_id;
+
+ if (nflag)
+ flag |= NI_NUMERICHOST;
+
+ getnameinfo((struct sockaddr *)&sa6_local, sa6_local.sin6_len,
+ line, sizeof(line), NULL, 0, flag);
+
+ return line;
+}
+#endif /*INET6*/
+
+/*
+ * Print routing statistics
+ */
+void
+rt_stats(void)
+{
+ struct rtstat rtstat;
+ int rttrash;
+ int mib[6];
+ size_t len;
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_STAT;
+ mib[5] = 0;
+ len = sizeof(struct rtstat);
+ if (sysctl(mib, 6, &rtstat, &len, 0, 0) == -1)
+ return;
+
+ mib[0] = CTL_NET;
+ mib[1] = AF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_TRASH;
+ mib[5] = 0;
+ len = sizeof(rttrash);
+ if (sysctl(mib, 6, &rttrash, &len, 0, 0) == -1)
+ return;
+
+ printf("routing:\n");
+
+#define p(f, m) if (rtstat.f || sflag <= 1) \
+ printf(m, rtstat.f, plural(rtstat.f))
+
+ p(rts_badredirect, "\t%u bad routing redirect%s\n");
+ p(rts_dynamic, "\t%u dynamically created route%s\n");
+ p(rts_newgateway, "\t%u new gateway%s due to redirects\n");
+ p(rts_unreach, "\t%u destination%s found unreachable\n");
+ p(rts_wildcard, "\t%u use%s of a wildcard route\n");
+ p(rts_badrtgwroute, "\t%u lookup%s returned indirect "
+ "routes pointing to indirect gateway route\n");
+#undef p
+
+ if (rttrash || sflag <= 1)
+ printf("\t%u route%s not in table but not freed\n",
+ rttrash, plural(rttrash));
+}
+
+void
+upHex(char *p0)
+{
+ char *p = p0;
+
+ for (; *p; p++)
+ switch (*p) {
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ *p += ('A' - 'a');
+ break;
+ }
+}
diff --git a/network_cmds/netstat.tproj/systm.c b/network_cmds/netstat.tproj/systm.c
new file mode 100644
index 0000000..3e076ca
--- /dev/null
+++ b/network_cmds/netstat.tproj/systm.c
@@ -0,0 +1,503 @@
+/*
+ * Copyright (c) 2014-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/sys_domain.h>
+#include <sys/kern_control.h>
+#include <sys/kern_event.h>
+#include <net/ntstat.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "netstat.h"
+
+#define ROUNDUP64(a) \
+((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint64_t) - 1))) : sizeof(uint64_t))
+#define ADVANCE64(x, n) (((char *)x) += ROUNDUP64(n))
+
+struct xgen_n {
+ u_int32_t xgn_len; /* length of this structure */
+ u_int32_t xgn_kind; /* number of PCBs at this time */
+};
+
+#define ALL_XGN_KIND_KCREG (XSO_KCREG)
+#define ALL_XGN_KIND_EVT (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_EVT)
+#define ALL_XGN_KIND_KCB (XSO_SOCKET | XSO_RCVBUF | XSO_SNDBUF | XSO_STATS | XSO_KCB)
+
+void
+systmpr(uint32_t proto,
+ char *name, int af)
+{
+ const char *mibvar;
+ size_t len;
+ char *buf, *next;
+ struct xsystmgen *xig, *oxig;
+ struct xgen_n *xgn;
+ int which = 0;
+ struct xsocket_n *so = NULL;
+ struct xsockbuf_n *so_rcv = NULL;
+ struct xsockbuf_n *so_snd = NULL;
+ struct xsockstat_n *so_stat = NULL;
+ struct xkctl_reg *kctl = NULL;
+ struct xkctlpcb *kcb = NULL;
+ struct xkevtpcb *kevb = NULL;
+ int first = 1;
+
+ switch (proto) {
+ case SYSPROTO_EVENT:
+ mibvar = "net.systm.kevt.pcblist";
+ break;
+ case SYSPROTO_CONTROL:
+ mibvar = "net.systm.kctl.pcblist";
+ break;
+ case 0:
+ mibvar = "net.systm.kctl.reg_list";
+ break;
+ default:
+ mibvar = NULL;
+ break;
+ }
+ if (mibvar == NULL)
+ return;
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= sizeof(struct xsystmgen)) {
+ free(buf);
+ return;
+ }
+ oxig = xig = (struct xsystmgen *)buf;
+ for (next = buf + ROUNDUP64(xig->xg_len); next < buf + len;
+ next += ROUNDUP64(xgn->xgn_len)) {
+ xgn = (struct xgen_n*)next;
+ if (xgn->xgn_len <= sizeof(struct xsystmgen))
+ break;
+
+ if ((which & xgn->xgn_kind) == 0) {
+ which |= xgn->xgn_kind;
+ switch (xgn->xgn_kind) {
+ case XSO_SOCKET:
+ so = (struct xsocket_n *)xgn;
+ break;
+ case XSO_RCVBUF:
+ so_rcv = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_SNDBUF:
+ so_snd = (struct xsockbuf_n *)xgn;
+ break;
+ case XSO_STATS:
+ so_stat = (struct xsockstat_n *)xgn;
+ break;
+ case XSO_KCREG:
+ kctl = (struct xkctl_reg *)xgn;
+ break;
+ case XSO_KCB:
+ kcb = (struct xkctlpcb *)xgn;
+ break;
+ case XSO_EVT:
+ kevb = (struct xkevtpcb *)xgn;
+ break;
+ default:
+ printf("unexpected kind %d\n", xgn->xgn_kind);
+ break;
+ }
+ } else {
+ if (vflag)
+ printf("got %d twice\n", xgn->xgn_kind);
+ }
+
+ if (which == ALL_XGN_KIND_KCREG) {
+ which = 0;
+
+ if (first) {
+ printf("Registered kernel control modules\n");
+ if (Aflag)
+ printf("%-16.16s ", "kctlref");
+ printf("%-8.8s ", "id");
+ if (Aflag)
+ printf("%-8.8s ", "unit");
+ printf("%-8.8s ", "flags");
+ printf("%-8.8s ", "pcbcount");
+ printf("%-8.8s ", "rcvbuf");
+ printf("%-8.8s ", "sndbuf");
+ printf("%s ", "name");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kctl->xkr_kctlref);
+ printf("%8x ", kctl->xkr_id);
+ if (Aflag)
+ printf("%8d ", kctl->xkr_reg_unit);
+ printf("%8x ", kctl->xkr_flags);
+ printf("%8d ", kctl->xkr_pcbcount);
+ printf("%8d ", kctl->xkr_recvbufsize);
+ printf("%8d ", kctl->xkr_sendbufsize);
+ printf("%s ", kctl->xkr_name);
+ printf("\n");
+ } else if (which == ALL_XGN_KIND_KCB) {
+ which = 0;
+
+ if (first) {
+ printf("Active kernel control sockets\n");
+ if (Aflag)
+ printf("%16.16s ", "pcb");
+ printf("%-5.5s %-6.6s %-6.6s ",
+ "Proto", "Recv-Q", "Send-Q");
+ if (bflag > 0)
+ printf("%10.10s %10.10s ",
+ "rxbytes", "txbytes");
+ if (vflag > 0)
+ printf("%6.6s %6.6s %6.6s %6.6s ",
+ "rhiwat", "shiwat", "pid", "epid");
+ printf("%6.6s ", "unit");
+ printf("%6.6s ", "id");
+ printf("%s", "name");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kcb->xkp_kctpcb);
+ printf("%-5.5s %6u %6u ", name,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+ printf("%10llu %10llu ", rxbytes, txbytes);
+ }
+ if (vflag > 0) {
+ printf("%6u %6u %6u %6u ",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid);
+ }
+ printf("%6d ", kcb->xkp_unit);
+ printf("%6d ", kcb->xkp_kctlid);
+ printf("%s", kcb->xkp_kctlname);
+ printf("\n");
+
+ } else if (which == ALL_XGN_KIND_EVT) {
+ which = 0;
+ if (first) {
+ printf("Active kernel event sockets\n");
+ if (Aflag)
+ printf("%16.16s ", "pcb");
+ printf("%-5.5s %-6.6s %-6.6s ",
+ "Proto", "Recv-Q", "Send-Q");
+ printf("%6.6s ", "vendor");
+ printf("%6.6s ", "class");
+ printf("%6.6s", "subclass");
+ if (bflag > 0)
+ printf("%10.10s %10.10s ",
+ "rxbytes", "txbytes");
+ if (vflag > 0)
+ printf("%6.6s %6.6s %6.6s %6.6s",
+ "rhiwat", "shiwat", "pid", "epid");
+ printf("\n");
+ first = 0;
+ }
+ if (Aflag)
+ printf("%16llx ", kevb->kep_evtpcb);
+ printf("%-5.5s %6u %6u ", name,
+ so_rcv->sb_cc,
+ so_snd->sb_cc);
+ printf("%6d ", kevb->kep_vendor_code_filter);
+ printf("%6d ", kevb->kep_class_filter);
+ printf("%6d", kevb->kep_subclass_filter);
+ if (bflag > 0) {
+ int i;
+ u_int64_t rxbytes = 0;
+ u_int64_t txbytes = 0;
+
+ for (i = 0; i < SO_TC_STATS_MAX; i++) {
+ rxbytes += so_stat->xst_tc_stats[i].rxbytes;
+ txbytes += so_stat->xst_tc_stats[i].txbytes;
+ }
+ printf("%10llu %10llu ", rxbytes, txbytes);
+ }
+ if (vflag > 0) {
+ printf("%6u %6u %6u %6u",
+ so_rcv->sb_hiwat,
+ so_snd->sb_hiwat,
+ so->so_last_pid,
+ so->so_e_pid);
+ }
+ printf("\n");
+ }
+
+ }
+ if (xig != oxig && xig->xg_gen != oxig->xg_gen) {
+ if (oxig->xg_count > xig->xg_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ name);
+ } else if (oxig->xg_count < xig->xg_count) {
+ printf("Some %s sockets may have been created.\n",
+ name);
+ } else {
+ printf("Some %s sockets may have been created or deleted",
+ name);
+ }
+ }
+ free(buf);
+}
+
+void
+kctl_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct kctlstat pkctlstat;
+ struct kctlstat kctlstat;
+ size_t len = sizeof(struct kctlstat);
+ const char *mibvar = "net.systm.kctl.stats";
+
+ if (sysctlbyname(mibvar, &kctlstat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define STATDIFF(f) (kctlstat.f - pkctlstat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ p(kcs_reg_total, "\t%llu total kernel control module%s registered\n");
+ p(kcs_reg_count, "\t%llu current kernel control module%s registered\n");
+ p(kcs_pcbcount, "\t%llu current kernel control socket%s\n");
+ p1a(kcs_gencnt, "\t%llu kernel control generation count\n");
+ p(kcs_connections, "\t%llu connection attempt%s\n");
+ p(kcs_conn_fail, "\t%llu connection failure%s\n");
+ p(kcs_send_fail, "\t%llu send failure%s\n");
+ p(kcs_send_list_fail, "\t%llu send list failure%s\n");
+ p(kcs_enqueue_fail, "\t%llu enqueue failure%s\n");
+ p(kcs_enqueue_fullsock, "\t%llu packet%s dropped due to full socket buffers\n");
+ p(kcs_bad_kctlref, "\t%llu failure%s with bad kern_ctl_ref\n");
+ p(kcs_tbl_size_too_big, "\t%llu register failure%s because of too many kern_ctl_ref\n");
+ p(kcs_enqdata_mb_alloc_fail, "\t%llu enqueuedata failure%s because could not allocate a packet\n");
+ p(kcs_enqdata_sbappend_fail, "\t%llu enqueuedata failure%s due to full socket buffers\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+
+ if (interval > 0)
+ bcopy(&kctlstat, &pkctlstat, len);
+}
+
+void
+kevt_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct kevtstat pkevtstat;
+ struct kevtstat kevtstat;
+ size_t len = sizeof(struct kevtstat);
+ const char *mibvar = "net.systm.kevt.stats";
+
+ if (sysctlbyname(mibvar, &kevtstat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+#define STATDIFF(f) (kevtstat.f - pkevtstat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ p(kes_pcbcount, "\t%llu current kernel control socket%s\n");
+ p1a(kes_gencnt, "\t%llu kernel control generation count\n");
+ p(kes_badvendor, "\t%llu bad vendor failure%s\n");
+ p(kes_toobig, "\t%llu message too big failure%s\n");
+ p(kes_nomem, "\t%llu out of memory failure%s\n");
+ p(kes_fullsock, "\t%llu message%s dropped due to full socket buffers\n");
+ p(kes_posted, "\t%llu message%s posted\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+
+ if (interval > 0)
+ bcopy(&kevtstat, &pkevtstat, len);
+}
+
+void
+print_extbkidle_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct soextbkidlestat psoextbkidlestat;
+ struct soextbkidlestat soextbkidlestat;
+ size_t len = sizeof(struct soextbkidlestat);
+ const char *mibvar = "kern.ipc.extbkidlestat";
+
+ if (sysctlbyname(mibvar, &soextbkidlestat, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (soextbkidlestat.f - psoextbkidlestat.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+ printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p1a(so_xbkidle_maxperproc, "\t%u max per process\n");
+ p1a(so_xbkidle_time, "\t%u maximum time (seconds)\n");
+ p1a(so_xbkidle_rcvhiwat, "\t%u high water mark\n");
+ p(so_xbkidle_notsupp, "\t%u socket option not supported failure%s\n");
+ p(so_xbkidle_toomany, "\t%u too many sockets failure%s\n");
+ p(so_xbkidle_wantok, "\t%u total socket%s requested OK\n");
+ p(so_xbkidle_active, "\t%u extended bk idle socket%s\n");
+ p(so_xbkidle_nocell, "\t%u no cellular failure%s\n");
+ p(so_xbkidle_notime, "\t%u no time failures%s\n");
+ p(so_xbkidle_forced, "\t%u forced defunct socket%s\n");
+ p(so_xbkidle_resumed, "\t%u resumed socket%s\n");
+ p(so_xbkidle_expired, "\t%u timeout expired failure%s\n");
+ p1a(so_xbkidle_expired, "\t%u timer rescheduled\n");
+ p(so_xbkidle_nodlgtd, "\t%u no delegated failure%s\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
+
+void
+print_nstat_stats(uint32_t off __unused, char *name, int af __unused)
+{
+ static struct nstat_stats pnstat_stats;
+ struct nstat_stats nstat_stats;
+ size_t len = sizeof(struct nstat_stats);
+ const char *mibvar = "net.stats.stats";
+
+ if (sysctlbyname(mibvar, &nstat_stats, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+
+#define STATDIFF(f) (nstat_stats.f - pnstat_stats.f)
+#define p(f, m) if (STATDIFF(f) || sflag <= 1) \
+printf(m, STATDIFF(f), plural(STATDIFF(f)))
+#define p1a(f, m) if (STATDIFF(f) || sflag <= 1) \
+printf(m, STATDIFF(f))
+
+ if (interval && vflag > 0)
+ print_time();
+ printf ("%s:\n", name);
+
+ p(nstat_successmsgfailures, "\t%u enqueue success message failure%s\n");
+ p(nstat_sendcountfailures, "\t%u enqueue source counts message failure%s\n");
+ p(nstat_sysinfofailures, "\t%u enqueue sysinfo message failure%s\n");
+ p(nstat_srcupatefailures, "\t%u enqueue source udpate message failure%s\n");
+ p(nstat_descriptionfailures, "\t%u enqueue description message failure%s\n");
+ p(nstat_msgremovedfailures, "\t%u enqueue remove message failure%s\n");
+ p(nstat_srcaddedfailures, "\t%u enqueue source added message failure%s\n");
+ p(nstat_msgerrorfailures, "\t%u enqueue error message failure%s\n");
+ p(nstat_copy_descriptor_failures, "\t%u copy descriptor failure%s\n");
+ p(nstat_provider_counts_failures, "\t%u provider counts failure%s\n");
+ p(nstat_control_send_description_failures, "\t%u control send description failure%s\n");
+ p(nstat_control_send_goodbye_failures, "\t%u control send goodbye failure%s\n");
+ p(nstat_flush_accumulated_msgs_failures, "\t%u flush accumulated messages failure%s\n");
+ p(nstat_accumulate_msg_failures, "\t%u accumulated message failure%s\n");
+ p(nstat_control_cleanup_source_failures, "\t%u control cleanup source failure%s\n");
+ p(nstat_handle_msg_failures, "\t%u handle message failure%s\n");
+
+#undef STATDIFF
+#undef p
+#undef p1a
+}
diff --git a/network_cmds/netstat.tproj/tp_astring.c b/network_cmds/netstat.tproj/tp_astring.c
new file mode 100644
index 0000000..af08ceb
--- /dev/null
+++ b/network_cmds/netstat.tproj/tp_astring.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tp_astring.c 8.1 (Berkeley) 6/10/93
+ */
+
+char *tp_sstring[] = {
+"ST_ERROR(0x0)",
+"TP_CLOSED(0x1)",
+"TP_CRSENT(0x2)",
+"TP_AKWAIT(0x3)",
+"TP_OPEN(0x4)",
+"TP_CLOSING(0x5)",
+"TP_REFWAIT(0x6)",
+"TP_LISTENING(0x7)",
+"TP_CONFIRMING(0x8)",
+};
+
+char *tp_estring[] = {
+"TM_inact(0x0)",
+"TM_retrans(0x1)",
+"TM_sendack(0x2)",
+"TM_notused(0x3)",
+"TM_reference(0x4)",
+"TM_data_retrans(0x5)",
+"ER_TPDU(0x6)",
+"CR_TPDU(0x7)",
+"DR_TPDU(0x8)",
+"DC_TPDU(0x9)",
+"CC_TPDU(0xa)",
+"AK_TPDU(0xb)",
+"DT_TPDU(0xc)",
+"XPD_TPDU(0xd)",
+"XAK_TPDU(0xe)",
+"T_CONN_req(0xf)",
+"T_DISC_req(0x10)",
+"T_LISTEN_req(0x11)",
+"T_DATA_req(0x12)",
+"T_XPD_req(0x13)",
+"T_USR_rcvd(0x14)",
+"T_USR_Xrcvd(0x15)",
+"T_DETACH(0x16)",
+"T_NETRESET(0x17)",
+"T_ACPT_req(0x18)",
+};
diff --git a/network_cmds/netstat.tproj/unix.c b/network_cmds/netstat.tproj/unix.c
new file mode 100644
index 0000000..eece65a
--- /dev/null
+++ b/network_cmds/netstat.tproj/unix.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1983, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Display protocol blocks in the unix domain.
+ */
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/un.h>
+#include <sys/unpcb.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+static void unixdomainpr __P((struct xunpcb64 *, struct xsocket64 *));
+#else
+static void unixdomainpr __P((struct xunpcb *, struct xsocket *));
+#endif
+
+static const char *const socktype[] =
+ { "#0", "stream", "dgram", "raw" };
+
+void
+unixpr()
+{
+ char *buf;
+ int type;
+ size_t len;
+ struct xunpgen *xug, *oxug;
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct xsocket64 *so;
+ struct xunpcb64 *xunp;
+ char mibvar[sizeof "net.local.seqpacket.pcblist64"];
+#else
+ struct xsocket *so;
+ struct xunpcb *xunp;
+ char mibvar[sizeof "net.local.seqpacket.pcblist"];
+#endif
+
+ for (type = SOCK_STREAM; type <= SOCK_RAW; type++) {
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist64", socktype[type]);
+#else
+ snprintf(mibvar, sizeof(mibvar), "net.local.%s.pcblist", socktype[type]);
+#endif
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ continue;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ oxug = xug = (struct xunpgen *)buf;
+ for (xug = (struct xunpgen *)((char *)xug + xug->xug_len);
+ xug->xug_len > sizeof(struct xunpgen);
+ xug = (struct xunpgen *)((char *)xug + xug->xug_len)) {
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ xunp = (struct xunpcb64 *)xug;
+#else
+ xunp = (struct xunpcb *)xug;
+#endif
+ so = &xunp->xu_socket;
+
+ /* Ignore PCBs which were freed during copyout. */
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (xunp->xunp_gencnt > oxug->xug_gen)
+#else
+ if (xunp->xu_unp.unp_gencnt > oxug->xug_gen)
+#endif
+ continue;
+ unixdomainpr(xunp, so);
+ }
+ if (xug != oxug && xug->xug_gen != oxug->xug_gen) {
+ if (oxug->xug_count > xug->xug_count) {
+ printf("Some %s sockets may have been deleted.\n",
+ socktype[type]);
+ } else if (oxug->xug_count < xug->xug_count) {
+ printf("Some %s sockets may have been created.\n",
+ socktype[type]);
+ } else {
+ printf("Some %s sockets may have been created or deleted\n",
+ socktype[type]);
+ }
+ }
+ free(buf);
+ }
+}
+
+static void
+unixdomainpr(xunp, so)
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct xunpcb64 *xunp;
+ struct xsocket64 *so;
+#else
+ struct xunpcb *xunp;
+ struct xsocket *so;
+#endif
+{
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ struct unpcb *unp;
+#endif
+ struct sockaddr_un *sa;
+ static int first = 1;
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ sa = &xunp->xu_addr;
+#else
+ unp = &xunp->xu_unp;
+ if (unp->unp_addr)
+ sa = &xunp->xu_addr;
+ else
+ sa = (struct sockaddr_un *)0;
+#endif
+
+ if (first) {
+ printf("Active LOCAL (UNIX) domain sockets\n");
+ printf(
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+"%-16.16s %-6.6s %-6.6s %-6.6s %16.16s %16.16s %16.16s %16.16s Addr\n",
+#else
+"%-8.8s %-6.6s %-6.6s %-6.6s %8.8s %8.8s %8.8s %8.8s Addr\n",
+#endif
+ "Address", "Type", "Recv-Q", "Send-Q",
+ "Inode", "Conn", "Refs", "Nextref");
+ first = 0;
+ }
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ printf("%16lx %-6.6s %6u %6u %16lx %16lx %16lx %16lx",
+ (long)xunp->xu_unpp, socktype[so->so_type], so->so_rcv.sb_cc,
+ so->so_snd.sb_cc,
+ (long)xunp->xunp_vnode, (long)xunp->xunp_conn,
+ (long)xunp->xunp_refs, (long)xunp->xunp_reflink.le_next);
+#else
+ printf("%8lx %-6.6s %6u %6u %8lx %8lx %8lx %8lx",
+ (long)so->so_pcb, socktype[so->so_type], so->so_rcv.sb_cc,
+ so->so_snd.sb_cc,
+ (long)unp->unp_vnode, (long)unp->unp_conn,
+ (long)unp->unp_refs.lh_first, (long)unp->unp_reflink.le_next);
+#endif
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (sa->sun_len)
+#else
+ if (sa)
+#endif
+ printf(" %.*s",
+ (int)(sa->sun_len - offsetof(struct sockaddr_un, sun_path)),
+ sa->sun_path);
+ putchar('\n');
+}
diff --git a/network_cmds/netstat.tproj/vsock.c b/network_cmds/netstat.tproj/vsock.c
new file mode 100644
index 0000000..b52dc5e
--- /dev/null
+++ b/network_cmds/netstat.tproj/vsock.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Display protocol blocks in the vsock domain.
+ */
+#include <sys/proc_info.h>
+#include <sys/socketvar.h>
+#include <sys/sysctl.h>
+#include <sys/vsock.h>
+
+#include <errno.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netstat.h"
+
+#ifdef AF_VSOCK
+
+static void vsockdomainpr __P((struct xvsockpcb *));
+
+void
+vsockpr(uint32_t proto,
+char *name, int af)
+{
+ char *buf, *next;
+ size_t len;
+ struct xvsockpgen *xvg, *oxvg;
+ struct xvsockpcb *xpcb;
+
+ const char* mibvar = "net.vsock.pcblist";
+ len = 0;
+ if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
+ if (errno != ENOENT)
+ warn("sysctl: %s", mibvar);
+ return;
+ }
+ if ((buf = malloc(len)) == 0) {
+ warn("malloc %lu bytes", (u_long)len);
+ return;
+ }
+ if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
+ warn("sysctl: %s", mibvar);
+ free(buf);
+ return;
+ }
+
+ /*
+ * Bail-out to avoid logic error in the loop below when
+ * there is in fact no more control block to process
+ */
+ if (len <= 2 * sizeof(struct xvsockpgen)) {
+ free(buf);
+ return;
+ }
+
+ oxvg = (struct xvsockpgen *)buf;
+
+ // Save room for the last xvsockpgen.
+ len -= oxvg->xvg_len;
+
+ for (next = buf + oxvg->xvg_len; next < buf + len; next += xpcb->xv_len) {
+ xpcb = (struct xvsockpcb *)next;
+
+ /* Ignore PCBs which were freed during copyout. */
+ if (xpcb->xvp_gencnt > oxvg->xvg_gen)
+ continue;
+ vsockdomainpr(xpcb);
+ }
+ xvg = (struct xvsockpgen *)next;
+ if (xvg != oxvg && xvg->xvg_gen != oxvg->xvg_gen) {
+ if (oxvg->xvg_count > xvg->xvg_count) {
+ printf("Some vsock sockets may have been deleted.\n");
+ } else if (oxvg->xvg_count < xvg->xvg_count) {
+ printf("Some vsock sockets may have been created.\n");
+ } else {
+ printf("Some vsock sockets may have been created or deleted.\n");
+ }
+ }
+ free(buf);
+}
+
+static void
+vsock_print_addr(buf, cid, port)
+ char *buf;
+ uint32_t cid;
+ uint32_t port;
+{
+ if (cid == VMADDR_CID_ANY && port == VMADDR_PORT_ANY) {
+ (void) sprintf(buf, "*:*");
+ } else if (cid == VMADDR_CID_ANY) {
+ (void) sprintf(buf, "*:%u", port);
+ } else if (port == VMADDR_PORT_ANY) {
+ (void) sprintf(buf, "%u:*", cid);
+ } else {
+ (void) sprintf(buf, "%u:%u", cid, port);
+ }
+}
+
+static void
+vsockdomainpr(xpcb)
+ struct xvsockpcb *xpcb;
+{
+ static int first = 1;
+
+ if (first) {
+ printf("Active VSock sockets\n");
+ printf("%-5.5s %-6.6s %-6.6s %-6.6s %-18.18s %-18.18s %-11.11s",
+ "Proto", "Type",
+ "Recv-Q", "Send-Q",
+ "Local Address", "Foreign Address",
+ "State");
+ if (vflag > 0)
+ printf(" %10.10s %10.10s %10.10s %10.10s %6.6s %6.6s %6.6s %6s %10s",
+ "rxcnt", "txcnt", "peer_rxcnt", "peer_rxhiwat",
+ "rxhiwat", "txhiwat", "pid", "state", "options");
+ printf("\n");
+ first = 0;
+ }
+
+ struct xsocket *so = &xpcb->xv_socket;
+
+ char srcAddr[50];
+ char dstAddr[50];
+
+ vsock_print_addr(srcAddr, xpcb->xvp_local_cid, xpcb->xvp_local_port);
+ vsock_print_addr(dstAddr, xpcb->xvp_remote_cid, xpcb->xvp_remote_port);
+
+ // Determine the vsock socket state.
+ char *state;
+ if (so->so_state & SOI_S_ISCONNECTING) {
+ state = "CONNECTING";
+ } else if (so->so_state & SOI_S_ISCONNECTED) {
+ state = "ESTABLISHED";
+ } else if (so->so_state & SOI_S_ISDISCONNECTING) {
+ state = "CLOSING";
+ } else if (so->so_options & SO_ACCEPTCONN) {
+ state = "LISTEN";
+ } else {
+ state = "CLOSED";
+ }
+
+ printf("%-5.5s %-6.6s %6u %6u %-18s %-18s %-11s",
+ "vsock", "stream",
+ so->so_rcv.sb_cc, so->so_snd.sb_cc,
+ srcAddr, dstAddr,
+ state);
+ if (vflag > 0)
+ printf(" %10u %10u %10u %10u %6u %6u %6u 0x%04x 0x%08x",
+ xpcb->xvp_rxcnt,
+ xpcb->xvp_txcnt,
+ xpcb->xvp_peer_rxcnt,
+ xpcb->xvp_peer_rxhiwat,
+ so->so_rcv.sb_hiwat,
+ so->so_snd.sb_hiwat,
+ xpcb->xvp_last_pid,
+ so->so_state,
+ so->so_options);
+ printf("\n");
+}
+
+#endif /* AF_VSOCK */
diff --git a/network_cmds/network-client-server-entitlements.plist b/network_cmds/network-client-server-entitlements.plist
new file mode 100644
index 0000000..c326c83
--- /dev/null
+++ b/network_cmds/network-client-server-entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.network.client</key>
+ <true/>
+ <key>com.apple.security.network.server</key>
+ <true/>
+</dict>
+</plist>
diff --git a/network_cmds/network_cmds.plist b/network_cmds/network_cmds.plist
new file mode 100644
index 0000000..9d6cf73
--- /dev/null
+++ b/network_cmds/network_cmds.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>mtest</string>
+ <key>OpenSourceVersion</key>
+ <string>1.11</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.sbin/mtest/</string>
+ <key>OpenSourceURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/usr.sbin/mtest/mtest.c?rev=1.11;content-type=text%2Fplain</string>
+ <key>OpenSourceSHA1</key>
+ <string></string>
+ <key>OpenSourceMD5</key>
+ <string></string>
+ <key>OpenSourceImportDate</key>
+ <string>2011-01-13</string>
+ <key>OpenSourceLicense</key>
+ <string>Other</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>network_cmds.txt</string>
+ </dict>
+</array>
+</plist>
diff --git a/network_cmds/network_cmds.xcodeproj/project.pbxproj b/network_cmds/network_cmds.xcodeproj/project.pbxproj
new file mode 100755
index 0000000..cce64f8
--- /dev/null
+++ b/network_cmds/network_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,5098 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 72570DA20EE8EBF3000F4CFB /* All-Embedded */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 72570DA60EE8EC0F000F4CFB /* Build configuration list for PBXAggregateTarget "All-Embedded" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 034E4464100BDCA3009CA3DC /* PBXTargetDependency */,
+ 72B732EB1899B19A0060E6D4 /* PBXTargetDependency */,
+ 72179EAE146233390098FB3E /* PBXTargetDependency */,
+ 7282BA571AFBDEAD005DE836 /* PBXTargetDependency */,
+ 72946F4C1BBF063800087E35 /* PBXTargetDependency */,
+ 034E4469100BDD00009CA3DC /* PBXTargetDependency */,
+ 565825AF13392239003E5FA5 /* PBXTargetDependency */,
+ 72311F4D194A34F500EB4788 /* PBXTargetDependency */,
+ 690D97BC12DE7151004323A7 /* PBXTargetDependency */,
+ 03B2DBD1100BE626005349BC /* PBXTargetDependency */,
+ 034E4475100BDEC6009CA3DC /* PBXTargetDependency */,
+ 7250E1491616642900A11A76 /* PBXTargetDependency */,
+ 7200F3051958A4FA0033E22C /* PBXTargetDependency */,
+ 034E447B100BDF0D009CA3DC /* PBXTargetDependency */,
+ 03B2DBD3100BE645005349BC /* PBXTargetDependency */,
+ 18515B85133D1DBF000148A4 /* PBXTargetDependency */,
+ 034E447F100BDF54009CA3DC /* PBXTargetDependency */,
+ 03B2DBDB100BE6D2005349BC /* PBXTargetDependency */,
+ 034E4485100BE15F009CA3DC /* PBXTargetDependency */,
+ 03B2DBDD100BE6D5005349BC /* PBXTargetDependency */,
+ );
+ name = "All-Embedded";
+ productName = "All-Embedded";
+ };
+ 726121430EE8717500AFED1B /* All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 7261214B0EE8717D00AFED1B /* Build configuration list for PBXAggregateTarget "All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 726121490EE8717B00AFED1B /* PBXTargetDependency */,
+ 72B732E91899B18F0060E6D4 /* PBXTargetDependency */,
+ 723C7074142BB003007C87E9 /* PBXTargetDependency */,
+ 7282BA5B1AFBDED3005DE836 /* PBXTargetDependency */,
+ 7263724B1BCC709900E4B026 /* PBXTargetDependency */,
+ 7261217D0EE8896800AFED1B /* PBXTargetDependency */,
+ 4D2B05141208C6BB0004A3F3 /* PBXTargetDependency */,
+ 724DABC30EE890A6008900D0 /* PBXTargetDependency */,
+ 565825AD13392232003E5FA5 /* PBXTargetDependency */,
+ 72311F4B194A34EB00EB4788 /* PBXTargetDependency */,
+ 690D97BE12DE7166004323A7 /* PBXTargetDependency */,
+ 724DAC240EE89525008900D0 /* PBXTargetDependency */,
+ 7216D2670EE8978F00AE70E4 /* PBXTargetDependency */,
+ 7250E1471616642000A11A76 /* PBXTargetDependency */,
+ 7200F3031958A4F10033E22C /* PBXTargetDependency */,
+ 7216D2C00EE89ADF00AE70E4 /* PBXTargetDependency */,
+ 7216D2C20EE89ADF00AE70E4 /* PBXTargetDependency */,
+ 7216D2DA0EE89BE900AE70E4 /* PBXTargetDependency */,
+ 7216D3060EE89D9A00AE70E4 /* PBXTargetDependency */,
+ 7216D34D0EE89FEC00AE70E4 /* PBXTargetDependency */,
+ 7216D37F0EE8A0B300AE70E4 /* PBXTargetDependency */,
+ 7294F0EA0EE8BAC80052EC88 /* PBXTargetDependency */,
+ 7294F1210EE8BCC20052EC88 /* PBXTargetDependency */,
+ 72CD1D9C0EE8C47C005F825D /* PBXTargetDependency */,
+ 71D958C51A9455A000C9B286 /* PBXTargetDependency */,
+ );
+ name = All;
+ productName = "network_cmds (Aggregate)";
+ };
+ 72ABD0811083D742008C721C /* All-EmbeddedOther */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 72ABD0A11083D792008C721C /* Build configuration list for PBXAggregateTarget "All-EmbeddedOther" */;
+ buildPhases = (
+ );
+ dependencies = (
+ 72ABD0A41083D818008C721C /* PBXTargetDependency */,
+ 72ABD0881083D750008C721C /* PBXTargetDependency */,
+ 7282BA591AFBDEC2005DE836 /* PBXTargetDependency */,
+ 72946F4E1BBF063F00087E35 /* PBXTargetDependency */,
+ 565825B113392242003E5FA5 /* PBXTargetDependency */,
+ 72311F4F194A34FE00EB4788 /* PBXTargetDependency */,
+ 690D97BA12DE7130004323A7 /* PBXTargetDependency */,
+ 72ABD08C1083D75D008C721C /* PBXTargetDependency */,
+ 72ABD08E1083D75F008C721C /* PBXTargetDependency */,
+ 7250E14B1616643000A11A76 /* PBXTargetDependency */,
+ 7200F3071958A5040033E22C /* PBXTargetDependency */,
+ 72ABD0901083D762008C721C /* PBXTargetDependency */,
+ 72ABD0921083D764008C721C /* PBXTargetDependency */,
+ 72ABD0941083D767008C721C /* PBXTargetDependency */,
+ 72ABD0961083D76A008C721C /* PBXTargetDependency */,
+ 72ABD0981083D76D008C721C /* PBXTargetDependency */,
+ 72ABD09A1083D76F008C721C /* PBXTargetDependency */,
+ 72ABD09C1083D772008C721C /* PBXTargetDependency */,
+ 72ABD09E1083D774008C721C /* PBXTargetDependency */,
+ );
+ name = "All-EmbeddedOther";
+ productName = "All-EmbeddedOther";
+ };
+ 72C77D3A1484199C002D2577 /* network_cmds_libs */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 72C77D671484199C002D2577 /* Build configuration list for PBXAggregateTarget "network_cmds_libs" */;
+ buildPhases = (
+ );
+ dependencies = (
+ );
+ name = network_cmds_libs;
+ productName = "network_cmds (Aggregate)";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 01560DFD241969D3001AA29A /* vsock.c in Sources */ = {isa = PBXBuildFile; fileRef = 01560DFC241969D3001AA29A /* vsock.c */; };
+ 03EB2F9A120A1DDA0007C1A0 /* ip6addrctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4D2B04E41208C12F0004A3F3 /* ip6addrctl.8 */; };
+ 4D2B04F81208C21B0004A3F3 /* ip6addrctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 4D2B04E51208C12F0004A3F3 /* ip6addrctl.c */; };
+ 565825A4133921A3003E5FA5 /* mnc_error.c in Sources */ = {isa = PBXBuildFile; fileRef = 565825961339217B003E5FA5 /* mnc_error.c */; };
+ 565825A5133921A3003E5FA5 /* mnc_main.c in Sources */ = {isa = PBXBuildFile; fileRef = 565825971339217B003E5FA5 /* mnc_main.c */; };
+ 565825A6133921A3003E5FA5 /* mnc_multicast.c in Sources */ = {isa = PBXBuildFile; fileRef = 565825981339217B003E5FA5 /* mnc_multicast.c */; };
+ 565825A7133921A3003E5FA5 /* mnc_opts.c in Sources */ = {isa = PBXBuildFile; fileRef = 565825991339217B003E5FA5 /* mnc_opts.c */; };
+ 565825A9133921CF003E5FA5 /* mnc.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 565825941339217B003E5FA5 /* mnc.1 */; };
+ 56B6B66816F79A1C00D8A7A9 /* mptcp.c in Sources */ = {isa = PBXBuildFile; fileRef = 56B6B66716F79A1C00D8A7A9 /* mptcp.c */; };
+ 690D97A612DE6F96004323A7 /* mtest.c in Sources */ = {isa = PBXBuildFile; fileRef = 690D979412DE6E6B004323A7 /* mtest.c */; };
+ 690D97AE12DE70AE004323A7 /* mtest.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 690D979512DE6E76004323A7 /* mtest.8 */; };
+ 7200F2FD1958A34D0033E22C /* packet_mangler.c in Sources */ = {isa = PBXBuildFile; fileRef = 7200F2FC1958A34D0033E22C /* packet_mangler.c */; };
+ 721654C31EC52447005B17BA /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = 721654C21EC52447005B17BA /* misc.c */; };
+ 7216D24C0EE896F300AE70E4 /* data.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261208B0EE86F4800AFED1B /* data.c */; };
+ 7216D24D0EE896F300AE70E4 /* if.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261208D0EE86F4800AFED1B /* if.c */; };
+ 7216D24E0EE896F300AE70E4 /* inet.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261208E0EE86F4800AFED1B /* inet.c */; };
+ 7216D24F0EE896F300AE70E4 /* inet6.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261208F0EE86F4800AFED1B /* inet6.c */; };
+ 7216D2500EE896F300AE70E4 /* ipsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120900EE86F4800AFED1B /* ipsec.c */; };
+ 7216D2510EE896F300AE70E4 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120910EE86F4800AFED1B /* main.c */; };
+ 7216D2520EE896F300AE70E4 /* mbuf.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120930EE86F4800AFED1B /* mbuf.c */; };
+ 7216D2530EE896F300AE70E4 /* mcast.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120940EE86F4800AFED1B /* mcast.c */; };
+ 7216D2560EE896F300AE70E4 /* route.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120990EE86F4800AFED1B /* route.c */; };
+ 7216D2570EE896F300AE70E4 /* tp_astring.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261209A0EE86F4800AFED1B /* tp_astring.c */; };
+ 7216D2580EE896F300AE70E4 /* unix.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261209B0EE86F4800AFED1B /* unix.c */; };
+ 7216D2600EE8971500AE70E4 /* netstat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120970EE86F4800AFED1B /* netstat.1 */; };
+ 7216D2800EE8981C00AE70E4 /* ping.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120A10EE86F5000AFED1B /* ping.c */; };
+ 7216D2880EE8982F00AE70E4 /* ping.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120A00EE86F5000AFED1B /* ping.8 */; };
+ 7216D2A00EE898DF00AE70E4 /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120A60EE86F5C00AFED1B /* md5.c */; };
+ 7216D2A10EE898DF00AE70E4 /* ping6.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120A90EE86F5C00AFED1B /* ping6.c */; };
+ 7216D2A90EE898F300AE70E4 /* ping6.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120A80EE86F5C00AFED1B /* ping6.8 */; };
+ 7216D2D10EE89B8300AE70E4 /* rarpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120AF0EE86F6700AFED1B /* rarpd.c */; };
+ 7216D2E40EE89C8B00AE70E4 /* rarpd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120AE0EE86F6700AFED1B /* rarpd.8 */; };
+ 7216D2F20EE89CD600AE70E4 /* route.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120B80EE86F7200AFED1B /* route.c */; };
+ 7216D3040EE89D4900AE70E4 /* route.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120B70EE86F7200AFED1B /* route.8 */; };
+ 7216D3190EE89EC100AE70E4 /* advcap.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120BC0EE86F8200AFED1B /* advcap.c */; };
+ 7216D31A0EE89EC100AE70E4 /* config.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120BE0EE86F8200AFED1B /* config.c */; };
+ 7216D31B0EE89EC100AE70E4 /* dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120C00EE86F8200AFED1B /* dump.c */; };
+ 7216D31C0EE89EC100AE70E4 /* if.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120C20EE86F8200AFED1B /* if.c */; };
+ 7216D31D0EE89EC100AE70E4 /* rrenum.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120C60EE86F8200AFED1B /* rrenum.c */; };
+ 7216D31E0EE89EC100AE70E4 /* rtadvd.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120C90EE86F8200AFED1B /* rtadvd.c */; };
+ 7216D31F0EE89EC100AE70E4 /* timer.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120CD0EE86F8200AFED1B /* timer.c */; };
+ 7216D3240EE89F4200AE70E4 /* rtadvd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120C80EE86F8200AFED1B /* rtadvd.8 */; };
+ 7216D3390EE89F8400AE70E4 /* rtadvd.conf.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120CB0EE86F8200AFED1B /* rtadvd.conf.5 */; };
+ 7216D3410EE89FAF00AE70E4 /* rtadvd.conf in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120CA0EE86F8200AFED1B /* rtadvd.conf */; };
+ 7216D3670EE8A04700AE70E4 /* dump.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D20EE86F9100AFED1B /* dump.c */; };
+ 7216D3680EE8A04700AE70E4 /* if.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D30EE86F9100AFED1B /* if.c */; };
+ 7216D3690EE8A04700AE70E4 /* probe.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D50EE86F9100AFED1B /* probe.c */; };
+ 7216D36A0EE8A04700AE70E4 /* rtsock.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D60EE86F9100AFED1B /* rtsock.c */; };
+ 7216D36B0EE8A04700AE70E4 /* rtsol.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D80EE86F9100AFED1B /* rtsol.c */; };
+ 7216D36C0EE8A04700AE70E4 /* rtsold.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120D90EE86F9100AFED1B /* rtsold.c */; };
+ 7216D3700EE8A05B00AE70E4 /* rtsol.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120D70EE86F9100AFED1B /* rtsol.8 */; };
+ 7216D3AB0EE8A3C400AE70E4 /* spray.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120E00EE86F9D00AFED1B /* spray.c */; };
+ 7216D3AF0EE8A3D800AE70E4 /* spray.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120DF0EE86F9D00AFED1B /* spray.8 */; };
+ 7218B54A191D4202001B7B52 /* systm.c in Sources */ = {isa = PBXBuildFile; fileRef = 7218B549191D4202001B7B52 /* systm.c */; };
+ 72311F54194A354F00EB4788 /* conn_lib.c in Sources */ = {isa = PBXBuildFile; fileRef = 72311F50194A354F00EB4788 /* conn_lib.c */; };
+ 72311F55194A354F00EB4788 /* mptcp_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 72311F53194A354F00EB4788 /* mptcp_client.c */; };
+ 72311F56194A76DA00EB4788 /* mptcp_client.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72311F52194A354F00EB4788 /* mptcp_client.1 */; };
+ 724753E7144905E300F6A941 /* dnctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 724753E61448E1EF00F6A941 /* dnctl.8 */; };
+ 724769371CE2B1FF00AAB5F0 /* gmt2local.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3C1AFAD58E005DE836 /* gmt2local.c */; };
+ 724769381CE2C1E400AAB5F0 /* gmt2local.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3C1AFAD58E005DE836 /* gmt2local.c */; };
+ 7247B83616165EDC00873B3C /* pktapctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7247B83516165EDC00873B3C /* pktapctl.8 */; };
+ 7247B83C16165F0100873B3C /* pktapctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 7247B83B16165F0100873B3C /* pktapctl.c */; };
+ 724DABA60EE88FED008900D0 /* kdumpd.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120710EE86F2D00AFED1B /* kdumpd.c */; };
+ 724DABA70EE88FED008900D0 /* kdumpsubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120720EE86F2D00AFED1B /* kdumpsubs.c */; };
+ 724DABAB0EE89006008900D0 /* kdumpd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120700EE86F2D00AFED1B /* kdumpd.8 */; };
+ 724DABBC0EE8908A008900D0 /* com.apple.kdumpd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7261206E0EE86F2D00AFED1B /* com.apple.kdumpd.plist */; };
+ 724DAC120EE89423008900D0 /* ndp.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120870EE86F4000AFED1B /* ndp.c */; };
+ 724DAC3B0EE89555008900D0 /* ndp.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120860EE86F4000AFED1B /* ndp.8 */; };
+ 726121310EE8711E00AFED1B /* arp.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261204E0EE86EF900AFED1B /* arp.c */; };
+ 726121350EE8713800AFED1B /* arp.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7261204D0EE86EF900AFED1B /* arp.8 */; };
+ 7261215A0EE8883900AFED1B /* ifbond.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120550EE86F0900AFED1B /* ifbond.c */; };
+ 7261215B0EE8883900AFED1B /* ifconfig.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120570EE86F0900AFED1B /* ifconfig.c */; };
+ 7261215C0EE8883900AFED1B /* ifmedia.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120590EE86F0900AFED1B /* ifmedia.c */; };
+ 7261215D0EE8883900AFED1B /* ifvlan.c in Sources */ = {isa = PBXBuildFile; fileRef = 7261205A0EE86F0900AFED1B /* ifvlan.c */; };
+ 726121610EE8885400AFED1B /* ifconfig.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120560EE86F0900AFED1B /* ifconfig.8 */; };
+ 7263A9630EEE31C800164D5D /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72CD1DB50EE8C619005F825D /* libipsec.dylib */; };
+ 7282BA491AFAD58E005DE836 /* capture.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA351AFAD58E005DE836 /* capture.c */; };
+ 7282BA4B1AFAD58E005DE836 /* ecn_probe.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA391AFAD58E005DE836 /* ecn_probe.c */; };
+ 7282BA4C1AFAD58E005DE836 /* ecn.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3A1AFAD58E005DE836 /* ecn.c */; };
+ 7282BA4D1AFAD58E005DE836 /* gmt2local.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3C1AFAD58E005DE836 /* gmt2local.c */; };
+ 7282BA4E1AFAD58E005DE836 /* history.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA3E1AFAD58E005DE836 /* history.c */; };
+ 7282BA4F1AFAD58E005DE836 /* inet.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA401AFAD58E005DE836 /* inet.c */; };
+ 7282BA521AFAD58E005DE836 /* session.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA451AFAD58E005DE836 /* session.c */; };
+ 7282BA531AFAD58E005DE836 /* support.c in Sources */ = {isa = PBXBuildFile; fileRef = 7282BA471AFAD58E005DE836 /* support.c */; };
+ 7282BA551AFBCA66005DE836 /* libpcap.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 7282BA541AFBCA66005DE836 /* libpcap.dylib */; };
+ 72946F501BBF07FF00087E35 /* frame_delay.c in Sources */ = {isa = PBXBuildFile; fileRef = 72946F4F1BBF07FF00087E35 /* frame_delay.c */; };
+ 7294F0DF0EE8BA730052EC88 /* spray.x in Sources */ = {isa = PBXBuildFile; fileRef = 726120E10EE86F9D00AFED1B /* spray.x */; };
+ 7294F1000EE8BB990052EC88 /* as.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120E50EE86FA700AFED1B /* as.c */; };
+ 7294F1010EE8BB990052EC88 /* findsaddr-socket.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120E70EE86FA700AFED1B /* findsaddr-socket.c */; };
+ 7294F1020EE8BB990052EC88 /* ifaddrlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120EA0EE86FA700AFED1B /* ifaddrlist.c */; };
+ 7294F1030EE8BB990052EC88 /* traceroute.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120F10EE86FA700AFED1B /* traceroute.c */; };
+ 7294F1040EE8BB990052EC88 /* version.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120F30EE86FA700AFED1B /* version.c */; };
+ 7294F1080EE8BBB10052EC88 /* traceroute.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120F00EE86FA700AFED1B /* traceroute.8 */; };
+ 7294F12E0EE8BD2F0052EC88 /* traceroute6.c in Sources */ = {isa = PBXBuildFile; fileRef = 726120FB0EE86FB500AFED1B /* traceroute6.c */; };
+ 7294F1320EE8BD430052EC88 /* traceroute6.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 726120FA0EE86FB500AFED1B /* traceroute6.8 */; };
+ 72B732DF1899B0380060E6D4 /* cfilutil.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 72B732DE1899B0380060E6D4 /* cfilutil.1 */; };
+ 72B732EF1899B23A0060E6D4 /* cfilutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B732EE1899B23A0060E6D4 /* cfilutil.c */; };
+ 72B732F11899B2430060E6D4 /* cfilstat.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B732F01899B2430060E6D4 /* cfilstat.c */; };
+ 72B7F36B1BA69352003A9AA2 /* if6lowpan.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B7F36A1BA69281003A9AA2 /* if6lowpan.c */; };
+ 72B894EC0EEDB17C00C218D6 /* libipsec.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72CD1DB50EE8C619005F825D /* libipsec.dylib */; };
+ 72D000C4142BB11100151981 /* dnctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 72D000C3142BB11100151981 /* dnctl.c */; };
+ 72D33F572271319400EF5B5E /* rtadvd_logging.c in Sources */ = {isa = PBXBuildFile; fileRef = 72D33F562271220100EF5B5E /* rtadvd_logging.c */; };
+ 72E42BA314B7CF3D003AAE28 /* network_cmds.plist in Install OSS Plist */ = {isa = PBXBuildFile; fileRef = 72E42BA214B7CF37003AAE28 /* network_cmds.plist */; };
+ 72E650A7107BF2F000AAF325 /* af_inet.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A2107BF2F000AAF325 /* af_inet.c */; };
+ 72E650A8107BF2F000AAF325 /* af_inet6.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A3107BF2F000AAF325 /* af_inet6.c */; };
+ 72E650A9107BF2F000AAF325 /* af_link.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A4107BF2F000AAF325 /* af_link.c */; };
+ 72E650AA107BF2F000AAF325 /* ifbridge.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A5107BF2F000AAF325 /* ifbridge.c */; };
+ 72E650AB107BF2F000AAF325 /* ifclone.c in Sources */ = {isa = PBXBuildFile; fileRef = 72E650A6107BF2F000AAF325 /* ifclone.c */; };
+ E01AB0901368880F008C66FF /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E01AB08F1368880F008C66FF /* libutil.dylib */; };
+ F940359D1E2FF5A900283EB1 /* iffake.c in Sources */ = {isa = PBXBuildFile; fileRef = F940359C1E2FF58500283EB1 /* iffake.c */; };
+ F97F1E041E9C3FC8002355FF /* nexus.c in Sources */ = {isa = PBXBuildFile; fileRef = F97F1E031E9C3FBC002355FF /* nexus.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+ 7216D47D0EE8B84900AE70E4 /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.proxy.script;
+ filePatterns = "$(PROJECT_DIR)/spray.tproj/spray.x";
+ fileType = pattern.proxy;
+ inputFiles = (
+ );
+ isEditable = 1;
+ outputFiles = (
+ "$(DERIVED_FILES_DIR)/$(INPUT_FILE_BASE).h",
+ "$(DERIVED_FILES_DIR)/$(INPUT_FILE_BASE)_xdr.c",
+ );
+ script = "/usr/bin/rpcgen -h -o ${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}.h ${INPUT_FILE_PATH}\n/usr/bin/rpcgen -c -o ${DERIVED_FILES_DIR}/${INPUT_FILE_BASE}_xdr.c ${INPUT_FILE_PATH}";
+ };
+/* End PBXBuildRule section */
+
+/* Begin PBXContainerItemProxy section */
+ 034E4463100BDCA3009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7261212C0EE8710B00AFED1B;
+ remoteInfo = arp;
+ };
+ 034E4468100BDD00009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 726121530EE8881700AFED1B;
+ remoteInfo = ifconfig;
+ };
+ 034E4474100BDEC6009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2450EE896C000AE70E4;
+ remoteInfo = netstat;
+ };
+ 034E447A100BDF0D009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D27B0EE8980A00AE70E4;
+ remoteInfo = ping;
+ };
+ 034E447E100BDF54009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2EC0EE89CBC00AE70E4;
+ remoteInfo = route;
+ };
+ 034E4484100BE15F009CA3DC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F0F80EE8BB460052EC88;
+ remoteInfo = traceroute;
+ };
+ 03B2DBD0100BE626005349BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724DAC0C0EE8940D008900D0;
+ remoteInfo = ndp;
+ };
+ 03B2DBD2100BE645005349BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2990EE898BD00AE70E4;
+ remoteInfo = ping6;
+ };
+ 03B2DBDA100BE6D2005349BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3580EE8A02200AE70E4;
+ remoteInfo = rtsol;
+ };
+ 03B2DBDC100BE6D5005349BC /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F1290EE8BD280052EC88;
+ remoteInfo = traceroute6;
+ };
+ 18515B84133D1DBF000148A4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3130EE89E9E00AE70E4;
+ remoteInfo = rtadvd;
+ };
+ 4D2B05131208C6BB0004A3F3 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 4D2B04F21208C2040004A3F3;
+ remoteInfo = ip6addrctl;
+ };
+ 565825AC13392232003E5FA5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5658259E1339218F003E5FA5;
+ remoteInfo = mnc;
+ };
+ 565825AE13392239003E5FA5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5658259E1339218F003E5FA5;
+ remoteInfo = mnc;
+ };
+ 565825B013392242003E5FA5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5658259E1339218F003E5FA5;
+ remoteInfo = mnc;
+ };
+ 690D97B912DE7130004323A7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 690D978012DE6034004323A7;
+ remoteInfo = mtest;
+ };
+ 690D97BB12DE7151004323A7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 690D978012DE6034004323A7;
+ remoteInfo = mtest;
+ };
+ 690D97BD12DE7166004323A7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 690D978012DE6034004323A7;
+ remoteInfo = mtest;
+ };
+ 71D958C41A9455A000C9B286 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 713297671A93C743002359CF;
+ remoteInfo = unbound;
+ };
+ 7200F3021958A4F10033E22C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7200F2F91958A34D0033E22C;
+ remoteInfo = pktmnglr;
+ };
+ 7200F3041958A4FA0033E22C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7200F2F91958A34D0033E22C;
+ remoteInfo = pktmnglr;
+ };
+ 7200F3061958A5040033E22C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7200F2F91958A34D0033E22C;
+ remoteInfo = pktmnglr;
+ };
+ 7216D2660EE8978F00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2450EE896C000AE70E4;
+ remoteInfo = netstat;
+ };
+ 7216D2BF0EE89ADF00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D27B0EE8980A00AE70E4;
+ remoteInfo = ping;
+ };
+ 7216D2C10EE89ADF00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2990EE898BD00AE70E4;
+ remoteInfo = ping6;
+ };
+ 7216D2D90EE89BE900AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2CC0EE89B7900AE70E4;
+ remoteInfo = rarpd;
+ };
+ 7216D3050EE89D9A00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2EC0EE89CBC00AE70E4;
+ remoteInfo = route;
+ };
+ 7216D34C0EE89FEC00AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3130EE89E9E00AE70E4;
+ remoteInfo = rtadvd;
+ };
+ 7216D37E0EE8A0B300AE70E4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3580EE8A02200AE70E4;
+ remoteInfo = rtsol;
+ };
+ 72179EAD146233390098FB3E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723C7067142BAFEA007C87E9;
+ remoteInfo = dnctl;
+ };
+ 72311F4A194A34EB00EB4788 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72311F41194A349000EB4788;
+ remoteInfo = mptcp_client;
+ };
+ 72311F4C194A34F500EB4788 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72311F41194A349000EB4788;
+ remoteInfo = mptcp_client;
+ };
+ 72311F4E194A34FE00EB4788 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72311F41194A349000EB4788;
+ remoteInfo = mptcp_client;
+ };
+ 723C7073142BB003007C87E9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 723C7067142BAFEA007C87E9;
+ remoteInfo = dnctl;
+ };
+ 724DABC20EE890A6008900D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724DABA10EE88FE3008900D0;
+ remoteInfo = kdumpd;
+ };
+ 724DAC230EE89525008900D0 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724DAC0C0EE8940D008900D0;
+ remoteInfo = ndp;
+ };
+ 7250E1461616642000A11A76 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7247B83016165EDC00873B3C;
+ remoteInfo = pktapctl;
+ };
+ 7250E1481616642900A11A76 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7247B83016165EDC00873B3C;
+ remoteInfo = pktapctl;
+ };
+ 7250E14A1616643000A11A76 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7247B83016165EDC00873B3C;
+ remoteInfo = pktapctl;
+ };
+ 726121480EE8717B00AFED1B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7261212C0EE8710B00AFED1B;
+ remoteInfo = arp;
+ };
+ 7261217C0EE8896800AFED1B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 726121530EE8881700AFED1B;
+ remoteInfo = ifconfig;
+ };
+ 7263724A1BCC709900E4B026 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72946F421BBF055700087E35;
+ remoteInfo = frame_delay;
+ };
+ 7282BA561AFBDEAD005DE836 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7282BA0B1AFAD4C9005DE836;
+ remoteInfo = ecnprobe;
+ };
+ 7282BA581AFBDEC2005DE836 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7282BA0B1AFAD4C9005DE836;
+ remoteInfo = ecnprobe;
+ };
+ 7282BA5A1AFBDED3005DE836 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7282BA0B1AFAD4C9005DE836;
+ remoteInfo = ecnprobe;
+ };
+ 72946F4B1BBF063800087E35 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72946F421BBF055700087E35;
+ remoteInfo = frame_delay;
+ };
+ 72946F4D1BBF063F00087E35 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72946F421BBF055700087E35;
+ remoteInfo = frame_delay;
+ };
+ 7294F0E90EE8BAC80052EC88 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3A60EE8A3BA00AE70E4;
+ remoteInfo = spray;
+ };
+ 7294F1200EE8BCC20052EC88 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F0F80EE8BB460052EC88;
+ remoteInfo = traceroute;
+ };
+ 72ABD0871083D750008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 726121530EE8881700AFED1B;
+ remoteInfo = ifconfig;
+ };
+ 72ABD08B1083D75D008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 724DAC0C0EE8940D008900D0;
+ remoteInfo = ndp;
+ };
+ 72ABD08D1083D75F008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2450EE896C000AE70E4;
+ remoteInfo = netstat;
+ };
+ 72ABD08F1083D762008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D27B0EE8980A00AE70E4;
+ remoteInfo = ping;
+ };
+ 72ABD0911083D764008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2990EE898BD00AE70E4;
+ remoteInfo = ping6;
+ };
+ 72ABD0931083D767008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2CC0EE89B7900AE70E4;
+ remoteInfo = rarpd;
+ };
+ 72ABD0951083D76A008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D2EC0EE89CBC00AE70E4;
+ remoteInfo = route;
+ };
+ 72ABD0971083D76D008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3130EE89E9E00AE70E4;
+ remoteInfo = rtadvd;
+ };
+ 72ABD0991083D76F008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7216D3580EE8A02200AE70E4;
+ remoteInfo = rtsol;
+ };
+ 72ABD09B1083D772008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F0F80EE8BB460052EC88;
+ remoteInfo = traceroute;
+ };
+ 72ABD09D1083D774008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F1290EE8BD280052EC88;
+ remoteInfo = traceroute6;
+ };
+ 72ABD0A31083D818008C721C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7261212C0EE8710B00AFED1B;
+ remoteInfo = arp;
+ };
+ 72B732E81899B18F0060E6D4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72B732D91899B0380060E6D4;
+ remoteInfo = cfilutil;
+ };
+ 72B732EA1899B19A0060E6D4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 72B732D91899B0380060E6D4;
+ remoteInfo = cfilutil;
+ };
+ 72CD1D9B0EE8C47C005F825D /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 724862310EE86EB7001D0DE9 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 7294F1290EE8BD280052EC88;
+ remoteInfo = traceroute6;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 4D2B05221208CB410004A3F3 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 03EB2F9A120A1DDA0007C1A0 /* ip6addrctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 565825AA133921ED003E5FA5 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 565825A9133921CF003E5FA5 /* mnc.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 690D97AD12DE7074004323A7 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 690D97AE12DE70AE004323A7 /* mtest.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 69C10A6312DF7D5300BCDF4C /* Install OSS Plist */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/OpenSourceVersions/;
+ dstSubfolderSpec = 0;
+ files = (
+ 72E42BA314B7CF3D003AAE28 /* network_cmds.plist in Install OSS Plist */,
+ );
+ name = "Install OSS Plist";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 713297661A93C743002359CF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 71D958BB1A9452C200C9B286 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 71D958BE1A9453A500C9B286 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/etc/unbound;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7200F2F81958A34D0033E22C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2750EE8979500AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D2600EE8971500AE70E4 /* netstat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2930EE8988200AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D2880EE8982F00AE70E4 /* ping.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2AA0EE8991200AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D2A90EE898F300AE70E4 /* ping6.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2E20EE89BEA00AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D2E40EE89C8B00AE70E4 /* rarpd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D2FA0EE89D2600AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3040EE89D4900AE70E4 /* route.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D3370EE89F7500AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3240EE89F4200AE70E4 /* rtadvd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D3380EE89F7500AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3390EE89F8400AE70E4 /* rtadvd.conf.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D3460EE89FD700AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3410EE89FAF00AE70E4 /* rtadvd.conf in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D37B0EE8A06200AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3700EE8A05B00AE70E4 /* rtsol.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7216D3C10EE8A42D00AE70E4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7216D3AF0EE8A3D800AE70E4 /* spray.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72311F40194A349000EB4788 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 72311F56194A76DA00EB4788 /* mptcp_client.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 723C7066142BAFEA007C87E9 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 724753E7144905E300F6A941 /* dnctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7247B82F16165EDC00873B3C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ 7247B83616165EDC00873B3C /* pktapctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724DABB70EE89035008900D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 724DABAB0EE89006008900D0 /* kdumpd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724DABC10EE89090008900D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ 724DABBC0EE8908A008900D0 /* com.apple.kdumpd.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 724DAC1D0EE894E8008900D0 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 724DAC3B0EE89555008900D0 /* ndp.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7261213F0EE8713B00AFED1B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 726121350EE8713800AFED1B /* arp.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 726121620EE8887300AFED1B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 726121610EE8885400AFED1B /* ifconfig.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7282BA0A1AFAD4C9005DE836 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72946F411BBF055700087E35 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7294F11A0EE8BC0C0052EC88 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7294F1080EE8BBB10052EC88 /* traceroute.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 7294F13E0EE8BDB30052EC88 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 7294F1320EE8BD430052EC88 /* traceroute6.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 72B732D81899B0380060E6D4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 72B732DF1899B0380060E6D4 /* cfilutil.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 01560DFC241969D3001AA29A /* vsock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vsock.c; sourceTree = "<group>"; };
+ 4D2B04E41208C12F0004A3F3 /* ip6addrctl.8 */ = {isa = PBXFileReference; explicitFileType = text; fileEncoding = 4; path = ip6addrctl.8; sourceTree = "<group>"; };
+ 4D2B04E51208C12F0004A3F3 /* ip6addrctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ip6addrctl.c; sourceTree = "<group>"; };
+ 4D2B04E61208C12F0004A3F3 /* ip6addrctl.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ip6addrctl.conf; sourceTree = "<group>"; };
+ 4D2B04F31208C2040004A3F3 /* ip6addrctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ip6addrctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 565825941339217B003E5FA5 /* mnc.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mnc.1; sourceTree = "<group>"; };
+ 565825951339217B003E5FA5 /* LICENCE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENCE; sourceTree = "<group>"; };
+ 565825961339217B003E5FA5 /* mnc_error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mnc_error.c; sourceTree = "<group>"; };
+ 565825971339217B003E5FA5 /* mnc_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mnc_main.c; sourceTree = "<group>"; };
+ 565825981339217B003E5FA5 /* mnc_multicast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mnc_multicast.c; sourceTree = "<group>"; };
+ 565825991339217B003E5FA5 /* mnc_opts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mnc_opts.c; sourceTree = "<group>"; };
+ 5658259A1339217B003E5FA5 /* mnc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mnc.h; sourceTree = "<group>"; };
+ 5658259B1339217B003E5FA5 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ 5658259F1339218F003E5FA5 /* mnc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mnc; sourceTree = BUILT_PRODUCTS_DIR; };
+ 56B6B66716F79A1C00D8A7A9 /* mptcp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mptcp.c; sourceTree = "<group>"; };
+ 690D978112DE6034004323A7 /* mtest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mtest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 690D979412DE6E6B004323A7 /* mtest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mtest.c; sourceTree = "<group>"; };
+ 690D979512DE6E76004323A7 /* mtest.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mtest.8; sourceTree = "<group>"; };
+ 69C10A7912DF80F200BCDF4C /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; };
+ 713297681A93C743002359CF /* unbound */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unbound; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7200F2FA1958A34D0033E22C /* pktmnglr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pktmnglr; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7200F2FC1958A34D0033E22C /* packet_mangler.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = packet_mangler.c; sourceTree = "<group>"; };
+ 7211D9B2190713A60086EF20 /* network-client-server-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "network-client-server-entitlements.plist"; sourceTree = "<group>"; };
+ 721654C21EC52447005B17BA /* misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+ 7216D2460EE896C000AE70E4 /* netstat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = netstat; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D27C0EE8980A00AE70E4 /* ping */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ping; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D29A0EE898BD00AE70E4 /* ping6 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ping6; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D2CD0EE89B7900AE70E4 /* rarpd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rarpd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D2ED0EE89CBC00AE70E4 /* route */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = route; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D3140EE89E9E00AE70E4 /* rtadvd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rtadvd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D3590EE8A02200AE70E4 /* rtsol */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rtsol; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7216D3A70EE8A3BB00AE70E4 /* spray */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = spray; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7218B549191D4202001B7B52 /* systm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = systm.c; sourceTree = "<group>"; };
+ 72311F42194A349000EB4788 /* mptcp_client */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mptcp_client; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72311F50194A354F00EB4788 /* conn_lib.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = conn_lib.c; sourceTree = "<group>"; };
+ 72311F51194A354F00EB4788 /* conn_lib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = conn_lib.h; sourceTree = "<group>"; };
+ 72311F52194A354F00EB4788 /* mptcp_client.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mptcp_client.1; sourceTree = "<group>"; };
+ 72311F53194A354F00EB4788 /* mptcp_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mptcp_client.c; sourceTree = "<group>"; };
+ 723C7068142BAFEA007C87E9 /* dnctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 724753E61448E1EF00F6A941 /* dnctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = dnctl.8; sourceTree = "<group>"; };
+ 7247B83116165EDC00873B3C /* pktapctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pktapctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7247B83516165EDC00873B3C /* pktapctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pktapctl.8; sourceTree = "<group>"; };
+ 7247B83B16165F0100873B3C /* pktapctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pktapctl.c; sourceTree = "<group>"; };
+ 724DABA20EE88FE3008900D0 /* kdumpd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = kdumpd; sourceTree = BUILT_PRODUCTS_DIR; };
+ 724DAC0D0EE8940D008900D0 /* ndp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ndp; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7255D4301E44036D008F4A32 /* libcrypto.35.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.35.dylib; path = usr/lib/libcrypto.35.dylib; sourceTree = SDKROOT; };
+ 7255D4321E44037F008F4A32 /* libssl.35.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libssl.35.dylib; path = usr/lib/libssl.35.dylib; sourceTree = SDKROOT; };
+ 7261204D0EE86EF900AFED1B /* arp.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = arp.8; sourceTree = "<group>"; };
+ 7261204E0EE86EF900AFED1B /* arp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arp.c; sourceTree = "<group>"; };
+ 7261204F0EE86EF900AFED1B /* arp4.4 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = arp4.4; sourceTree = "<group>"; };
+ 726120550EE86F0900AFED1B /* ifbond.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifbond.c; sourceTree = "<group>"; };
+ 726120560EE86F0900AFED1B /* ifconfig.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ifconfig.8; sourceTree = "<group>"; };
+ 726120570EE86F0900AFED1B /* ifconfig.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifconfig.c; sourceTree = "<group>"; };
+ 726120580EE86F0900AFED1B /* ifconfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ifconfig.h; sourceTree = "<group>"; };
+ 726120590EE86F0900AFED1B /* ifmedia.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifmedia.c; sourceTree = "<group>"; };
+ 7261205A0EE86F0900AFED1B /* ifvlan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifvlan.c; sourceTree = "<group>"; };
+ 7261206E0EE86F2D00AFED1B /* com.apple.kdumpd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.kdumpd.plist; sourceTree = "<group>"; };
+ 7261206F0EE86F2D00AFED1B /* kdump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kdump.h; sourceTree = "<group>"; };
+ 726120700EE86F2D00AFED1B /* kdumpd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = kdumpd.8; sourceTree = "<group>"; };
+ 726120710EE86F2D00AFED1B /* kdumpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kdumpd.c; sourceTree = "<group>"; };
+ 726120720EE86F2D00AFED1B /* kdumpsubs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kdumpsubs.c; sourceTree = "<group>"; };
+ 726120730EE86F2D00AFED1B /* kdumpsubs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kdumpsubs.h; sourceTree = "<group>"; };
+ 726120840EE86F4000AFED1B /* gnuc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gnuc.h; sourceTree = "<group>"; };
+ 726120860EE86F4000AFED1B /* ndp.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ndp.8; sourceTree = "<group>"; };
+ 726120870EE86F4000AFED1B /* ndp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ndp.c; sourceTree = "<group>"; };
+ 7261208B0EE86F4800AFED1B /* data.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = data.c; sourceTree = "<group>"; };
+ 7261208C0EE86F4800AFED1B /* DERIVED_FILES */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DERIVED_FILES; sourceTree = "<group>"; };
+ 7261208D0EE86F4800AFED1B /* if.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = if.c; sourceTree = "<group>"; };
+ 7261208E0EE86F4800AFED1B /* inet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet.c; sourceTree = "<group>"; };
+ 7261208F0EE86F4800AFED1B /* inet6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet6.c; sourceTree = "<group>"; };
+ 726120900EE86F4800AFED1B /* ipsec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ipsec.c; sourceTree = "<group>"; };
+ 726120910EE86F4800AFED1B /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ 726120930EE86F4800AFED1B /* mbuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mbuf.c; sourceTree = "<group>"; };
+ 726120940EE86F4800AFED1B /* mcast.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mcast.c; sourceTree = "<group>"; };
+ 726120970EE86F4800AFED1B /* netstat.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = netstat.1; sourceTree = "<group>"; };
+ 726120980EE86F4800AFED1B /* netstat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = netstat.h; sourceTree = "<group>"; };
+ 726120990EE86F4800AFED1B /* route.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = route.c; sourceTree = "<group>"; };
+ 7261209A0EE86F4800AFED1B /* tp_astring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = tp_astring.c; sourceTree = "<group>"; };
+ 7261209B0EE86F4800AFED1B /* unix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unix.c; sourceTree = "<group>"; };
+ 726120A00EE86F5000AFED1B /* ping.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ping.8; sourceTree = "<group>"; };
+ 726120A10EE86F5000AFED1B /* ping.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ping.c; sourceTree = "<group>"; };
+ 726120A60EE86F5C00AFED1B /* md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = md5.c; sourceTree = "<group>"; };
+ 726120A70EE86F5C00AFED1B /* md5.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = md5.h; sourceTree = "<group>"; };
+ 726120A80EE86F5C00AFED1B /* ping6.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ping6.8; sourceTree = "<group>"; };
+ 726120A90EE86F5C00AFED1B /* ping6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ping6.c; sourceTree = "<group>"; };
+ 726120AE0EE86F6700AFED1B /* rarpd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rarpd.8; sourceTree = "<group>"; };
+ 726120AF0EE86F6700AFED1B /* rarpd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rarpd.c; sourceTree = "<group>"; };
+ 726120B30EE86F7200AFED1B /* gen_header.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = gen_header.pl; sourceTree = "<group>"; };
+ 726120B40EE86F7200AFED1B /* keywords */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = keywords; sourceTree = "<group>"; };
+ 726120B50EE86F7200AFED1B /* keywords.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keywords.h; sourceTree = "<group>"; };
+ 726120B70EE86F7200AFED1B /* route.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = route.8; sourceTree = "<group>"; };
+ 726120B80EE86F7200AFED1B /* route.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = route.c; sourceTree = "<group>"; };
+ 726120BC0EE86F8200AFED1B /* advcap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = advcap.c; sourceTree = "<group>"; };
+ 726120BD0EE86F8200AFED1B /* advcap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = advcap.h; sourceTree = "<group>"; };
+ 726120BE0EE86F8200AFED1B /* config.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = config.c; sourceTree = "<group>"; };
+ 726120BF0EE86F8200AFED1B /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
+ 726120C00EE86F8200AFED1B /* dump.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dump.c; sourceTree = "<group>"; };
+ 726120C10EE86F8200AFED1B /* dump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dump.h; sourceTree = "<group>"; };
+ 726120C20EE86F8200AFED1B /* if.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = if.c; sourceTree = "<group>"; };
+ 726120C30EE86F8200AFED1B /* if.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = if.h; sourceTree = "<group>"; };
+ 726120C50EE86F8200AFED1B /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ 726120C60EE86F8200AFED1B /* rrenum.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rrenum.c; sourceTree = "<group>"; };
+ 726120C70EE86F8200AFED1B /* rrenum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rrenum.h; sourceTree = "<group>"; };
+ 726120C80EE86F8200AFED1B /* rtadvd.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rtadvd.8; sourceTree = "<group>"; };
+ 726120C90EE86F8200AFED1B /* rtadvd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtadvd.c; sourceTree = "<group>"; };
+ 726120CA0EE86F8200AFED1B /* rtadvd.conf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rtadvd.conf; sourceTree = "<group>"; };
+ 726120CB0EE86F8200AFED1B /* rtadvd.conf.5 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rtadvd.conf.5; sourceTree = "<group>"; };
+ 726120CC0EE86F8200AFED1B /* rtadvd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtadvd.h; sourceTree = "<group>"; };
+ 726120CD0EE86F8200AFED1B /* timer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = timer.c; sourceTree = "<group>"; };
+ 726120CE0EE86F8200AFED1B /* timer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = timer.h; sourceTree = "<group>"; };
+ 726120D20EE86F9100AFED1B /* dump.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dump.c; sourceTree = "<group>"; };
+ 726120D30EE86F9100AFED1B /* if.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = if.c; sourceTree = "<group>"; };
+ 726120D50EE86F9100AFED1B /* probe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = probe.c; sourceTree = "<group>"; };
+ 726120D60EE86F9100AFED1B /* rtsock.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtsock.c; sourceTree = "<group>"; };
+ 726120D70EE86F9100AFED1B /* rtsol.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = rtsol.8; sourceTree = "<group>"; };
+ 726120D80EE86F9100AFED1B /* rtsol.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtsol.c; sourceTree = "<group>"; };
+ 726120D90EE86F9100AFED1B /* rtsold.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtsold.c; sourceTree = "<group>"; };
+ 726120DA0EE86F9100AFED1B /* rtsold.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtsold.h; sourceTree = "<group>"; };
+ 726120DF0EE86F9D00AFED1B /* spray.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = spray.8; sourceTree = "<group>"; };
+ 726120E00EE86F9D00AFED1B /* spray.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = spray.c; sourceTree = "<group>"; };
+ 726120E10EE86F9D00AFED1B /* spray.x */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = spray.x; sourceTree = "<group>"; };
+ 726120E50EE86FA700AFED1B /* as.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = as.c; sourceTree = "<group>"; };
+ 726120E60EE86FA700AFED1B /* as.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = as.h; sourceTree = "<group>"; };
+ 726120E70EE86FA700AFED1B /* findsaddr-socket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = "findsaddr-socket.c"; sourceTree = "<group>"; };
+ 726120E80EE86FA700AFED1B /* findsaddr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = findsaddr.h; sourceTree = "<group>"; };
+ 726120E90EE86FA700AFED1B /* gnuc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gnuc.h; sourceTree = "<group>"; };
+ 726120EA0EE86FA700AFED1B /* ifaddrlist.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifaddrlist.c; sourceTree = "<group>"; };
+ 726120EB0EE86FA700AFED1B /* ifaddrlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ifaddrlist.h; sourceTree = "<group>"; };
+ 726120ED0EE86FA700AFED1B /* mean.awk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mean.awk; sourceTree = "<group>"; };
+ 726120EE0EE86FA700AFED1B /* median.awk */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = median.awk; sourceTree = "<group>"; };
+ 726120EF0EE86FA700AFED1B /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ 726120F00EE86FA700AFED1B /* traceroute.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = traceroute.8; sourceTree = "<group>"; };
+ 726120F10EE86FA700AFED1B /* traceroute.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = traceroute.c; sourceTree = "<group>"; };
+ 726120F20EE86FA700AFED1B /* traceroute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = traceroute.h; sourceTree = "<group>"; };
+ 726120F30EE86FA700AFED1B /* version.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = version.c; sourceTree = "<group>"; };
+ 726120FA0EE86FB500AFED1B /* traceroute6.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = traceroute6.8; sourceTree = "<group>"; };
+ 726120FB0EE86FB500AFED1B /* traceroute6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = traceroute6.c; sourceTree = "<group>"; };
+ 7261212D0EE8710B00AFED1B /* arp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = arp; sourceTree = BUILT_PRODUCTS_DIR; };
+ 726121540EE8881700AFED1B /* ifconfig */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ifconfig; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7263724C1BCC718B00E4B026 /* frame_delay.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = frame_delay.8; sourceTree = "<group>"; };
+ 7282BA0C1AFAD4C9005DE836 /* ecnprobe */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ecnprobe; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7282BA341AFAD58E005DE836 /* base.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = base.h; sourceTree = "<group>"; };
+ 7282BA351AFAD58E005DE836 /* capture.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = capture.c; sourceTree = "<group>"; };
+ 7282BA361AFAD58E005DE836 /* capture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = capture.h; sourceTree = "<group>"; };
+ 7282BA391AFAD58E005DE836 /* ecn_probe.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ecn_probe.c; sourceTree = "<group>"; };
+ 7282BA3A1AFAD58E005DE836 /* ecn.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ecn.c; sourceTree = "<group>"; };
+ 7282BA3B1AFAD58E005DE836 /* ecn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ecn.h; sourceTree = "<group>"; };
+ 7282BA3C1AFAD58E005DE836 /* gmt2local.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = gmt2local.c; sourceTree = "<group>"; };
+ 7282BA3D1AFAD58E005DE836 /* gmt2local.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gmt2local.h; sourceTree = "<group>"; };
+ 7282BA3E1AFAD58E005DE836 /* history.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = history.c; sourceTree = "<group>"; };
+ 7282BA3F1AFAD58E005DE836 /* history.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = history.h; sourceTree = "<group>"; };
+ 7282BA401AFAD58E005DE836 /* inet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inet.c; sourceTree = "<group>"; };
+ 7282BA411AFAD58E005DE836 /* inet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inet.h; sourceTree = "<group>"; };
+ 7282BA451AFAD58E005DE836 /* session.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = session.c; sourceTree = "<group>"; };
+ 7282BA461AFAD58E005DE836 /* session.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = session.h; sourceTree = "<group>"; };
+ 7282BA471AFAD58E005DE836 /* support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = support.c; sourceTree = "<group>"; };
+ 7282BA481AFAD58E005DE836 /* support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = support.h; sourceTree = "<group>"; };
+ 7282BA541AFBCA66005DE836 /* libpcap.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpcap.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/lib/libpcap.dylib; sourceTree = DEVELOPER_DIR; };
+ 7282BA5C1AFBED07005DE836 /* ecnprobe.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ecnprobe.1; sourceTree = "<group>"; };
+ 72946F431BBF055700087E35 /* frame_delay */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = frame_delay; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72946F4F1BBF07FF00087E35 /* frame_delay.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = frame_delay.c; sourceTree = "<group>"; };
+ 7294F0F90EE8BB460052EC88 /* traceroute */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = traceroute; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7294F12A0EE8BD280052EC88 /* traceroute6 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = traceroute6; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72B732DA1899B0380060E6D4 /* cfilutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cfilutil; sourceTree = BUILT_PRODUCTS_DIR; };
+ 72B732DE1899B0380060E6D4 /* cfilutil.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = cfilutil.1; sourceTree = "<group>"; };
+ 72B732EE1899B23A0060E6D4 /* cfilutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cfilutil.c; sourceTree = "<group>"; };
+ 72B732F01899B2430060E6D4 /* cfilstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cfilstat.c; sourceTree = "<group>"; };
+ 72B7F36A1BA69281003A9AA2 /* if6lowpan.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = if6lowpan.c; sourceTree = "<group>"; };
+ 72CD1DB50EE8C619005F825D /* libipsec.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libipsec.dylib; path = /usr/lib/libipsec.dylib; sourceTree = "<absolute>"; };
+ 72D000C3142BB11100151981 /* dnctl.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnctl.c; sourceTree = "<group>"; };
+ 72D33F552271220100EF5B5E /* rtadvd_logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rtadvd_logging.h; sourceTree = "<group>"; };
+ 72D33F562271220100EF5B5E /* rtadvd_logging.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rtadvd_logging.c; sourceTree = "<group>"; };
+ 72E42BA214B7CF37003AAE28 /* network_cmds.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = network_cmds.plist; sourceTree = "<group>"; };
+ 72E650A2107BF2F000AAF325 /* af_inet.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = af_inet.c; sourceTree = "<group>"; };
+ 72E650A3107BF2F000AAF325 /* af_inet6.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = af_inet6.c; sourceTree = "<group>"; };
+ 72E650A4107BF2F000AAF325 /* af_link.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = af_link.c; sourceTree = "<group>"; };
+ 72E650A5107BF2F000AAF325 /* ifbridge.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifbridge.c; sourceTree = "<group>"; };
+ 72E650A6107BF2F000AAF325 /* ifclone.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ifclone.c; sourceTree = "<group>"; };
+ E01AB08F1368880F008C66FF /* libutil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libutil.dylib; path = $SDKROOT/usr/lib/libutil.dylib; sourceTree = "<group>"; };
+ F940359C1E2FF58500283EB1 /* iffake.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iffake.c; sourceTree = "<group>"; };
+ F97F1E031E9C3FBC002355FF /* nexus.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nexus.c; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 5658259D1339218F003E5FA5 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 690D977F12DE6034004323A7 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 713297651A93C743002359CF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7200F2F71958A34D0033E22C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2440EE896C000AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D27A0EE8980A00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2980EE898BD00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7263A9630EEE31C800164D5D /* libipsec.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2CB0EE89B7900AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2EB0EE89CBC00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3120EE89E9E00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ E01AB0901368880F008C66FF /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3570EE8A02200AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3A50EE8A3BA00AE70E4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72311F3F194A349000EB4788 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723C7065142BAFEA007C87E9 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7247B82E16165EDC00873B3C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724DABA00EE88FE3008900D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724DAC0B0EE8940D008900D0 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7261212B0EE8710B00AFED1B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 726121520EE8881700AFED1B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7282BA091AFAD4C9005DE836 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7282BA551AFBCA66005DE836 /* libpcap.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72946F401BBF055700087E35 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7294F0F70EE8BB460052EC88 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7294F1280EE8BD280052EC88 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72B894EC0EEDB17C00C218D6 /* libipsec.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72B732D71899B0380060E6D4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 4D2B04E31208C12F0004A3F3 /* ip6addrctl.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 4D2B04E41208C12F0004A3F3 /* ip6addrctl.8 */,
+ 4D2B04E51208C12F0004A3F3 /* ip6addrctl.c */,
+ 4D2B04E61208C12F0004A3F3 /* ip6addrctl.conf */,
+ );
+ path = ip6addrctl.tproj;
+ sourceTree = "<group>";
+ };
+ 56582591133920B5003E5FA5 /* mnc.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 565825941339217B003E5FA5 /* mnc.1 */,
+ 565825951339217B003E5FA5 /* LICENCE */,
+ 565825961339217B003E5FA5 /* mnc_error.c */,
+ 565825971339217B003E5FA5 /* mnc_main.c */,
+ 565825981339217B003E5FA5 /* mnc_multicast.c */,
+ 565825991339217B003E5FA5 /* mnc_opts.c */,
+ 5658259A1339217B003E5FA5 /* mnc.h */,
+ 5658259B1339217B003E5FA5 /* README */,
+ );
+ path = mnc.tproj;
+ sourceTree = "<group>";
+ };
+ 690D973F12DE5A21004323A7 /* mtest.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 690D979512DE6E76004323A7 /* mtest.8 */,
+ 690D979412DE6E6B004323A7 /* mtest.c */,
+ 69C10A7912DF80F200BCDF4C /* COPYING */,
+ );
+ path = mtest.tproj;
+ sourceTree = "<group>";
+ };
+ 7200F2FB1958A34D0033E22C /* pktmnglr */ = {
+ isa = PBXGroup;
+ children = (
+ 7200F2FC1958A34D0033E22C /* packet_mangler.c */,
+ );
+ path = pktmnglr;
+ sourceTree = "<group>";
+ };
+ 72311F43194A349100EB4788 /* mptcp_client */ = {
+ isa = PBXGroup;
+ children = (
+ 72311F53194A354F00EB4788 /* mptcp_client.c */,
+ 72311F50194A354F00EB4788 /* conn_lib.c */,
+ 72311F51194A354F00EB4788 /* conn_lib.h */,
+ 72311F52194A354F00EB4788 /* mptcp_client.1 */,
+ );
+ path = mptcp_client;
+ sourceTree = "<group>";
+ };
+ 723C706A142BAFEA007C87E9 /* dnctl */ = {
+ isa = PBXGroup;
+ children = (
+ 724753E61448E1EF00F6A941 /* dnctl.8 */,
+ 72D000C3142BB11100151981 /* dnctl.c */,
+ );
+ path = dnctl;
+ sourceTree = "<group>";
+ };
+ 7247B83216165EDC00873B3C /* pktapctl */ = {
+ isa = PBXGroup;
+ children = (
+ 7247B83B16165F0100873B3C /* pktapctl.c */,
+ 7247B83516165EDC00873B3C /* pktapctl.8 */,
+ );
+ path = pktapctl;
+ sourceTree = "<group>";
+ };
+ 7248622F0EE86EB7001D0DE9 = {
+ isa = PBXGroup;
+ children = (
+ 7282BA541AFBCA66005DE836 /* libpcap.dylib */,
+ 72E42BA214B7CF37003AAE28 /* network_cmds.plist */,
+ 7211D9B2190713A60086EF20 /* network-client-server-entitlements.plist */,
+ E01AB08F1368880F008C66FF /* libutil.dylib */,
+ 7261204C0EE86EF900AFED1B /* arp.tproj */,
+ 72B732DB1899B0380060E6D4 /* cfilutil */,
+ 723C706A142BAFEA007C87E9 /* dnctl */,
+ 7282BA0D1AFAD4C9005DE836 /* ecnprobe */,
+ 72946F441BBF055700087E35 /* frame_delay */,
+ 726120540EE86F0900AFED1B /* ifconfig.tproj */,
+ 4D2B04E31208C12F0004A3F3 /* ip6addrctl.tproj */,
+ 7261206D0EE86F2D00AFED1B /* kdumpd.tproj */,
+ 56582591133920B5003E5FA5 /* mnc.tproj */,
+ 72311F43194A349100EB4788 /* mptcp_client */,
+ 690D973F12DE5A21004323A7 /* mtest.tproj */,
+ 726120830EE86F4000AFED1B /* ndp.tproj */,
+ 7261208A0EE86F4800AFED1B /* netstat.tproj */,
+ 7247B83216165EDC00873B3C /* pktapctl */,
+ 7200F2FB1958A34D0033E22C /* pktmnglr */,
+ 7261209E0EE86F5000AFED1B /* ping.tproj */,
+ 726120A40EE86F5C00AFED1B /* ping6.tproj */,
+ 726120AC0EE86F6700AFED1B /* rarpd.tproj */,
+ 726120B20EE86F7200AFED1B /* route.tproj */,
+ 726120BB0EE86F8200AFED1B /* rtadvd.tproj */,
+ 726120D10EE86F9100AFED1B /* rtsol.tproj */,
+ 726120DD0EE86F9D00AFED1B /* spray.tproj */,
+ 726120E40EE86FA700AFED1B /* traceroute.tproj */,
+ 726120F80EE86FB500AFED1B /* traceroute6.tproj */,
+ 72CD1DB50EE8C619005F825D /* libipsec.dylib */,
+ 7261210D0EE8707500AFED1B /* Products */,
+ 7255D42F1E44036D008F4A32 /* Frameworks */,
+ );
+ sourceTree = "<group>";
+ };
+ 7255D42F1E44036D008F4A32 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 7255D4321E44037F008F4A32 /* libssl.35.dylib */,
+ 7255D4301E44036D008F4A32 /* libcrypto.35.dylib */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 7261204C0EE86EF900AFED1B /* arp.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 7261204D0EE86EF900AFED1B /* arp.8 */,
+ 7261204E0EE86EF900AFED1B /* arp.c */,
+ 7261204F0EE86EF900AFED1B /* arp4.4 */,
+ );
+ path = arp.tproj;
+ sourceTree = "<group>";
+ };
+ 726120540EE86F0900AFED1B /* ifconfig.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 72B7F36A1BA69281003A9AA2 /* if6lowpan.c */,
+ 72E650A2107BF2F000AAF325 /* af_inet.c */,
+ 72E650A3107BF2F000AAF325 /* af_inet6.c */,
+ 72E650A4107BF2F000AAF325 /* af_link.c */,
+ 72E650A5107BF2F000AAF325 /* ifbridge.c */,
+ 72E650A6107BF2F000AAF325 /* ifclone.c */,
+ 726120550EE86F0900AFED1B /* ifbond.c */,
+ 726120560EE86F0900AFED1B /* ifconfig.8 */,
+ 726120570EE86F0900AFED1B /* ifconfig.c */,
+ 726120580EE86F0900AFED1B /* ifconfig.h */,
+ F940359C1E2FF58500283EB1 /* iffake.c */,
+ 726120590EE86F0900AFED1B /* ifmedia.c */,
+ 7261205A0EE86F0900AFED1B /* ifvlan.c */,
+ F97F1E031E9C3FBC002355FF /* nexus.c */,
+ );
+ path = ifconfig.tproj;
+ sourceTree = "<group>";
+ };
+ 7261206D0EE86F2D00AFED1B /* kdumpd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 7261206E0EE86F2D00AFED1B /* com.apple.kdumpd.plist */,
+ 7261206F0EE86F2D00AFED1B /* kdump.h */,
+ 726120700EE86F2D00AFED1B /* kdumpd.8 */,
+ 726120710EE86F2D00AFED1B /* kdumpd.c */,
+ 726120720EE86F2D00AFED1B /* kdumpsubs.c */,
+ 726120730EE86F2D00AFED1B /* kdumpsubs.h */,
+ );
+ path = kdumpd.tproj;
+ sourceTree = "<group>";
+ };
+ 726120830EE86F4000AFED1B /* ndp.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120840EE86F4000AFED1B /* gnuc.h */,
+ 726120860EE86F4000AFED1B /* ndp.8 */,
+ 726120870EE86F4000AFED1B /* ndp.c */,
+ );
+ path = ndp.tproj;
+ sourceTree = "<group>";
+ };
+ 7261208A0EE86F4800AFED1B /* netstat.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 7261208B0EE86F4800AFED1B /* data.c */,
+ 7261208C0EE86F4800AFED1B /* DERIVED_FILES */,
+ 7261208D0EE86F4800AFED1B /* if.c */,
+ 7261208E0EE86F4800AFED1B /* inet.c */,
+ 7261208F0EE86F4800AFED1B /* inet6.c */,
+ 726120900EE86F4800AFED1B /* ipsec.c */,
+ 726120910EE86F4800AFED1B /* main.c */,
+ 726120930EE86F4800AFED1B /* mbuf.c */,
+ 726120940EE86F4800AFED1B /* mcast.c */,
+ 56B6B66716F79A1C00D8A7A9 /* mptcp.c */,
+ 726120970EE86F4800AFED1B /* netstat.1 */,
+ 726120980EE86F4800AFED1B /* netstat.h */,
+ 726120990EE86F4800AFED1B /* route.c */,
+ 7261209A0EE86F4800AFED1B /* tp_astring.c */,
+ 7261209B0EE86F4800AFED1B /* unix.c */,
+ 7218B549191D4202001B7B52 /* systm.c */,
+ 721654C21EC52447005B17BA /* misc.c */,
+ 01560DFC241969D3001AA29A /* vsock.c */,
+ );
+ path = netstat.tproj;
+ sourceTree = "<group>";
+ };
+ 7261209E0EE86F5000AFED1B /* ping.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120A00EE86F5000AFED1B /* ping.8 */,
+ 726120A10EE86F5000AFED1B /* ping.c */,
+ );
+ path = ping.tproj;
+ sourceTree = "<group>";
+ };
+ 726120A40EE86F5C00AFED1B /* ping6.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120A60EE86F5C00AFED1B /* md5.c */,
+ 726120A70EE86F5C00AFED1B /* md5.h */,
+ 726120A80EE86F5C00AFED1B /* ping6.8 */,
+ 726120A90EE86F5C00AFED1B /* ping6.c */,
+ );
+ path = ping6.tproj;
+ sourceTree = "<group>";
+ };
+ 726120AC0EE86F6700AFED1B /* rarpd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120AE0EE86F6700AFED1B /* rarpd.8 */,
+ 726120AF0EE86F6700AFED1B /* rarpd.c */,
+ );
+ path = rarpd.tproj;
+ sourceTree = "<group>";
+ };
+ 726120B20EE86F7200AFED1B /* route.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120B30EE86F7200AFED1B /* gen_header.pl */,
+ 726120B40EE86F7200AFED1B /* keywords */,
+ 726120B50EE86F7200AFED1B /* keywords.h */,
+ 726120B70EE86F7200AFED1B /* route.8 */,
+ 726120B80EE86F7200AFED1B /* route.c */,
+ );
+ path = route.tproj;
+ sourceTree = "<group>";
+ };
+ 726120BB0EE86F8200AFED1B /* rtadvd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 72D33F562271220100EF5B5E /* rtadvd_logging.c */,
+ 72D33F552271220100EF5B5E /* rtadvd_logging.h */,
+ 726120BC0EE86F8200AFED1B /* advcap.c */,
+ 726120BD0EE86F8200AFED1B /* advcap.h */,
+ 726120BE0EE86F8200AFED1B /* config.c */,
+ 726120BF0EE86F8200AFED1B /* config.h */,
+ 726120C00EE86F8200AFED1B /* dump.c */,
+ 726120C10EE86F8200AFED1B /* dump.h */,
+ 726120C20EE86F8200AFED1B /* if.c */,
+ 726120C30EE86F8200AFED1B /* if.h */,
+ 726120C50EE86F8200AFED1B /* pathnames.h */,
+ 726120C60EE86F8200AFED1B /* rrenum.c */,
+ 726120C70EE86F8200AFED1B /* rrenum.h */,
+ 726120C80EE86F8200AFED1B /* rtadvd.8 */,
+ 726120C90EE86F8200AFED1B /* rtadvd.c */,
+ 726120CA0EE86F8200AFED1B /* rtadvd.conf */,
+ 726120CB0EE86F8200AFED1B /* rtadvd.conf.5 */,
+ 726120CC0EE86F8200AFED1B /* rtadvd.h */,
+ 726120CD0EE86F8200AFED1B /* timer.c */,
+ 726120CE0EE86F8200AFED1B /* timer.h */,
+ );
+ path = rtadvd.tproj;
+ sourceTree = "<group>";
+ };
+ 726120D10EE86F9100AFED1B /* rtsol.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120D20EE86F9100AFED1B /* dump.c */,
+ 726120D30EE86F9100AFED1B /* if.c */,
+ 726120D50EE86F9100AFED1B /* probe.c */,
+ 726120D60EE86F9100AFED1B /* rtsock.c */,
+ 726120D70EE86F9100AFED1B /* rtsol.8 */,
+ 726120D80EE86F9100AFED1B /* rtsol.c */,
+ 726120D90EE86F9100AFED1B /* rtsold.c */,
+ 726120DA0EE86F9100AFED1B /* rtsold.h */,
+ );
+ path = rtsol.tproj;
+ sourceTree = "<group>";
+ };
+ 726120DD0EE86F9D00AFED1B /* spray.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120DF0EE86F9D00AFED1B /* spray.8 */,
+ 726120E00EE86F9D00AFED1B /* spray.c */,
+ 726120E10EE86F9D00AFED1B /* spray.x */,
+ );
+ path = spray.tproj;
+ sourceTree = "<group>";
+ };
+ 726120E40EE86FA700AFED1B /* traceroute.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120E50EE86FA700AFED1B /* as.c */,
+ 726120E60EE86FA700AFED1B /* as.h */,
+ 726120E70EE86FA700AFED1B /* findsaddr-socket.c */,
+ 726120E80EE86FA700AFED1B /* findsaddr.h */,
+ 726120E90EE86FA700AFED1B /* gnuc.h */,
+ 726120EA0EE86FA700AFED1B /* ifaddrlist.c */,
+ 726120EB0EE86FA700AFED1B /* ifaddrlist.h */,
+ 726120ED0EE86FA700AFED1B /* mean.awk */,
+ 726120EE0EE86FA700AFED1B /* median.awk */,
+ 726120EF0EE86FA700AFED1B /* README */,
+ 726120F00EE86FA700AFED1B /* traceroute.8 */,
+ 726120F10EE86FA700AFED1B /* traceroute.c */,
+ 726120F20EE86FA700AFED1B /* traceroute.h */,
+ 726120F30EE86FA700AFED1B /* version.c */,
+ );
+ path = traceroute.tproj;
+ sourceTree = "<group>";
+ };
+ 726120F80EE86FB500AFED1B /* traceroute6.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 726120FA0EE86FB500AFED1B /* traceroute6.8 */,
+ 726120FB0EE86FB500AFED1B /* traceroute6.c */,
+ );
+ path = traceroute6.tproj;
+ sourceTree = "<group>";
+ };
+ 7261210D0EE8707500AFED1B /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 7261212D0EE8710B00AFED1B /* arp */,
+ 726121540EE8881700AFED1B /* ifconfig */,
+ 724DABA20EE88FE3008900D0 /* kdumpd */,
+ 724DAC0D0EE8940D008900D0 /* ndp */,
+ 7216D2460EE896C000AE70E4 /* netstat */,
+ 7216D27C0EE8980A00AE70E4 /* ping */,
+ 7216D29A0EE898BD00AE70E4 /* ping6 */,
+ 7216D2CD0EE89B7900AE70E4 /* rarpd */,
+ 7216D2ED0EE89CBC00AE70E4 /* route */,
+ 7216D3140EE89E9E00AE70E4 /* rtadvd */,
+ 7216D3590EE8A02200AE70E4 /* rtsol */,
+ 7216D3A70EE8A3BB00AE70E4 /* spray */,
+ 7294F0F90EE8BB460052EC88 /* traceroute */,
+ 7294F12A0EE8BD280052EC88 /* traceroute6 */,
+ 4D2B04F31208C2040004A3F3 /* ip6addrctl */,
+ 690D978112DE6034004323A7 /* mtest */,
+ 5658259F1339218F003E5FA5 /* mnc */,
+ 723C7068142BAFEA007C87E9 /* dnctl */,
+ 7247B83116165EDC00873B3C /* pktapctl */,
+ 72B732DA1899B0380060E6D4 /* cfilutil */,
+ 72311F42194A349000EB4788 /* mptcp_client */,
+ 7200F2FA1958A34D0033E22C /* pktmnglr */,
+ 713297681A93C743002359CF /* unbound */,
+ 7282BA0C1AFAD4C9005DE836 /* ecnprobe */,
+ 72946F431BBF055700087E35 /* frame_delay */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 7282BA0D1AFAD4C9005DE836 /* ecnprobe */ = {
+ isa = PBXGroup;
+ children = (
+ 7282BA341AFAD58E005DE836 /* base.h */,
+ 7282BA351AFAD58E005DE836 /* capture.c */,
+ 7282BA361AFAD58E005DE836 /* capture.h */,
+ 7282BA391AFAD58E005DE836 /* ecn_probe.c */,
+ 7282BA3A1AFAD58E005DE836 /* ecn.c */,
+ 7282BA3B1AFAD58E005DE836 /* ecn.h */,
+ 7282BA3C1AFAD58E005DE836 /* gmt2local.c */,
+ 7282BA3D1AFAD58E005DE836 /* gmt2local.h */,
+ 7282BA3E1AFAD58E005DE836 /* history.c */,
+ 7282BA3F1AFAD58E005DE836 /* history.h */,
+ 7282BA401AFAD58E005DE836 /* inet.c */,
+ 7282BA411AFAD58E005DE836 /* inet.h */,
+ 7282BA451AFAD58E005DE836 /* session.c */,
+ 7282BA461AFAD58E005DE836 /* session.h */,
+ 7282BA471AFAD58E005DE836 /* support.c */,
+ 7282BA481AFAD58E005DE836 /* support.h */,
+ 7282BA5C1AFBED07005DE836 /* ecnprobe.1 */,
+ );
+ path = ecnprobe;
+ sourceTree = "<group>";
+ };
+ 72946F441BBF055700087E35 /* frame_delay */ = {
+ isa = PBXGroup;
+ children = (
+ 72946F4F1BBF07FF00087E35 /* frame_delay.c */,
+ 7263724C1BCC718B00E4B026 /* frame_delay.8 */,
+ );
+ path = frame_delay;
+ sourceTree = "<group>";
+ };
+ 72B732DB1899B0380060E6D4 /* cfilutil */ = {
+ isa = PBXGroup;
+ children = (
+ 72B732EE1899B23A0060E6D4 /* cfilutil.c */,
+ 72B732F01899B2430060E6D4 /* cfilstat.c */,
+ 72B732DE1899B0380060E6D4 /* cfilutil.1 */,
+ );
+ path = cfilutil;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 4D2B04F21208C2040004A3F3 /* ip6addrctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 4D2B05121208C2300004A3F3 /* Build configuration list for PBXNativeTarget "ip6addrctl" */;
+ buildPhases = (
+ 4D2B04F01208C2040004A3F3 /* Sources */,
+ 4D2B05221208CB410004A3F3 /* CopyFiles */,
+ 039D6A11120A2CF60006B8C8 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ip6addrctl;
+ productName = ip6addrctl;
+ productReference = 4D2B04F31208C2040004A3F3 /* ip6addrctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 5658259E1339218F003E5FA5 /* mnc */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 565825AB133921ED003E5FA5 /* Build configuration list for PBXNativeTarget "mnc" */;
+ buildPhases = (
+ 5658259C1339218F003E5FA5 /* Sources */,
+ 5658259D1339218F003E5FA5 /* Frameworks */,
+ 565825AA133921ED003E5FA5 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mnc;
+ productName = mnc;
+ productReference = 5658259F1339218F003E5FA5 /* mnc */;
+ productType = "com.apple.product-type.tool";
+ };
+ 690D978012DE6034004323A7 /* mtest */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 690D978612DE6053004323A7 /* Build configuration list for PBXNativeTarget "mtest" */;
+ buildPhases = (
+ 690D977E12DE6034004323A7 /* Sources */,
+ 690D977F12DE6034004323A7 /* Frameworks */,
+ 690D97AD12DE7074004323A7 /* CopyFiles */,
+ 69C10A6312DF7D5300BCDF4C /* Install OSS Plist */,
+ 69C10A7612DF7EBB00BCDF4C /* Install OSS License */,
+ 690D97C212DE71CF004323A7 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mtest;
+ productName = mtest;
+ productReference = 690D978112DE6034004323A7 /* mtest */;
+ productType = "com.apple.product-type.tool";
+ };
+ 713297671A93C743002359CF /* unbound */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7132976F1A93C743002359CF /* Build configuration list for PBXNativeTarget "unbound" */;
+ buildPhases = (
+ 713297641A93C743002359CF /* Sources */,
+ 713297651A93C743002359CF /* Frameworks */,
+ 713297661A93C743002359CF /* CopyFiles */,
+ 71D958BB1A9452C200C9B286 /* CopyFiles */,
+ 71D958BE1A9453A500C9B286 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = unbound;
+ productName = unbound;
+ productReference = 713297681A93C743002359CF /* unbound */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7200F2F91958A34D0033E22C /* pktmnglr */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7200F3011958A34E0033E22C /* Build configuration list for PBXNativeTarget "pktmnglr" */;
+ buildPhases = (
+ 7200F2F61958A34D0033E22C /* Sources */,
+ 7200F2F71958A34D0033E22C /* Frameworks */,
+ 7200F2F81958A34D0033E22C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pktmnglr;
+ productName = pktmnglr;
+ productReference = 7200F2FA1958A34D0033E22C /* pktmnglr */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D2450EE896C000AE70E4 /* netstat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D24B0EE896EC00AE70E4 /* Build configuration list for PBXNativeTarget "netstat" */;
+ buildPhases = (
+ 7216D2430EE896C000AE70E4 /* Sources */,
+ 7216D2440EE896C000AE70E4 /* Frameworks */,
+ 7216D2750EE8979500AE70E4 /* CopyFiles */,
+ 7216D2640EE8972E00AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = netstat;
+ productName = netstat;
+ productReference = 7216D2460EE896C000AE70E4 /* netstat */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D27B0EE8980A00AE70E4 /* ping */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D2940EE8988200AE70E4 /* Build configuration list for PBXNativeTarget "ping" */;
+ buildPhases = (
+ 7216D2790EE8980A00AE70E4 /* Sources */,
+ 7216D27A0EE8980A00AE70E4 /* Frameworks */,
+ 7216D2930EE8988200AE70E4 /* CopyFiles */,
+ 7216D2870EE8982900AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ping;
+ productName = ping;
+ productReference = 7216D27C0EE8980A00AE70E4 /* ping */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D2990EE898BD00AE70E4 /* ping6 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D2AB0EE8991200AE70E4 /* Build configuration list for PBXNativeTarget "ping6" */;
+ buildPhases = (
+ 7216D2970EE898BD00AE70E4 /* Sources */,
+ 7216D2980EE898BD00AE70E4 /* Frameworks */,
+ 7216D2AA0EE8991200AE70E4 /* CopyFiles */,
+ 7216D2AF0EE8993100AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ping6;
+ productName = ping6;
+ productReference = 7216D29A0EE898BD00AE70E4 /* ping6 */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D2CC0EE89B7900AE70E4 /* rarpd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D2E30EE89BEA00AE70E4 /* Build configuration list for PBXNativeTarget "rarpd" */;
+ buildPhases = (
+ 7216D2CA0EE89B7900AE70E4 /* Sources */,
+ 7216D2CB0EE89B7900AE70E4 /* Frameworks */,
+ 7216D2E20EE89BEA00AE70E4 /* CopyFiles */,
+ 7216D2D80EE89B9B00AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rarpd;
+ productName = rarpd;
+ productReference = 7216D2CD0EE89B7900AE70E4 /* rarpd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D2EC0EE89CBC00AE70E4 /* route */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D2FB0EE89D2600AE70E4 /* Build configuration list for PBXNativeTarget "route" */;
+ buildPhases = (
+ 7216D2EA0EE89CBC00AE70E4 /* Sources */,
+ 7216D2EB0EE89CBC00AE70E4 /* Frameworks */,
+ 7216D2FA0EE89D2600AE70E4 /* CopyFiles */,
+ 7216D3030EE89D4300AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = route;
+ productName = route;
+ productReference = 7216D2ED0EE89CBC00AE70E4 /* route */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D3130EE89E9E00AE70E4 /* rtadvd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D3200EE89EDF00AE70E4 /* Build configuration list for PBXNativeTarget "rtadvd" */;
+ buildPhases = (
+ 7216D3110EE89E9E00AE70E4 /* Sources */,
+ 7216D3120EE89E9E00AE70E4 /* Frameworks */,
+ 7216D3370EE89F7500AE70E4 /* CopyFiles */,
+ 7216D3380EE89F7500AE70E4 /* CopyFiles */,
+ 7216D3460EE89FD700AE70E4 /* CopyFiles */,
+ 7216D3450EE89FB900AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rtadvd;
+ productName = rtadvd;
+ productReference = 7216D3140EE89E9E00AE70E4 /* rtadvd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D3580EE8A02200AE70E4 /* rtsol */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D3660EE8A02B00AE70E4 /* Build configuration list for PBXNativeTarget "rtsol" */;
+ buildPhases = (
+ 7216D3560EE8A02200AE70E4 /* Sources */,
+ 7216D3570EE8A02200AE70E4 /* Frameworks */,
+ 7216D37B0EE8A06200AE70E4 /* CopyFiles */,
+ 7216D3740EE8A06000AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rtsol;
+ productName = rtsol;
+ productReference = 7216D3590EE8A02200AE70E4 /* rtsol */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7216D3A60EE8A3BA00AE70E4 /* spray */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7216D3C20EE8A42D00AE70E4 /* Build configuration list for PBXNativeTarget "spray" */;
+ buildPhases = (
+ 7216D3A40EE8A3BA00AE70E4 /* Sources */,
+ 7216D3A50EE8A3BA00AE70E4 /* Frameworks */,
+ 7216D3C10EE8A42D00AE70E4 /* CopyFiles */,
+ 7216D3B30EE8A3E000AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ 7216D47D0EE8B84900AE70E4 /* PBXBuildRule */,
+ );
+ dependencies = (
+ );
+ name = spray;
+ productName = spray;
+ productReference = 7216D3A70EE8A3BB00AE70E4 /* spray */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72311F41194A349000EB4788 /* mptcp_client */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72311F46194A349100EB4788 /* Build configuration list for PBXNativeTarget "mptcp_client" */;
+ buildPhases = (
+ 72311F3E194A349000EB4788 /* Sources */,
+ 72311F3F194A349000EB4788 /* Frameworks */,
+ 72311F40194A349000EB4788 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mptcp_client;
+ productName = mptcp_client;
+ productReference = 72311F42194A349000EB4788 /* mptcp_client */;
+ productType = "com.apple.product-type.tool";
+ };
+ 723C7067142BAFEA007C87E9 /* dnctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 723C706F142BAFEA007C87E9 /* Build configuration list for PBXNativeTarget "dnctl" */;
+ buildPhases = (
+ 723C7064142BAFEA007C87E9 /* Sources */,
+ 723C7065142BAFEA007C87E9 /* Frameworks */,
+ 723C7066142BAFEA007C87E9 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dnctl;
+ productName = dnctl;
+ productReference = 723C7068142BAFEA007C87E9 /* dnctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7247B83016165EDC00873B3C /* pktapctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7247B83A16165EDC00873B3C /* Build configuration list for PBXNativeTarget "pktapctl" */;
+ buildPhases = (
+ 7247B82D16165EDC00873B3C /* Sources */,
+ 7247B82E16165EDC00873B3C /* Frameworks */,
+ 7247B82F16165EDC00873B3C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pktapctl;
+ productName = pktapctl;
+ productReference = 7247B83116165EDC00873B3C /* pktapctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 724DABA10EE88FE3008900D0 /* kdumpd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 724DABB80EE89035008900D0 /* Build configuration list for PBXNativeTarget "kdumpd" */;
+ buildPhases = (
+ 724DAB9F0EE88FE3008900D0 /* Sources */,
+ 724DABA00EE88FE3008900D0 /* Frameworks */,
+ 724DABB70EE89035008900D0 /* CopyFiles */,
+ 724DABC10EE89090008900D0 /* CopyFiles */,
+ 7216D25F0EE8970100AE70E4 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = kdumpd;
+ productName = kdumpd;
+ productReference = 724DABA20EE88FE3008900D0 /* kdumpd */;
+ productType = "com.apple.product-type.tool";
+ };
+ 724DAC0C0EE8940D008900D0 /* ndp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 724DAC1E0EE894E8008900D0 /* Build configuration list for PBXNativeTarget "ndp" */;
+ buildPhases = (
+ 724DAC0A0EE8940D008900D0 /* Sources */,
+ 724DAC0B0EE8940D008900D0 /* Frameworks */,
+ 724DAC1D0EE894E8008900D0 /* CopyFiles */,
+ 724DAC440EE89562008900D0 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ndp;
+ productName = ndp;
+ productReference = 724DAC0D0EE8940D008900D0 /* ndp */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7261212C0EE8710B00AFED1B /* arp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 726121400EE8713B00AFED1B /* Build configuration list for PBXNativeTarget "arp" */;
+ buildPhases = (
+ 7261212A0EE8710B00AFED1B /* Sources */,
+ 7261212B0EE8710B00AFED1B /* Frameworks */,
+ 7261213F0EE8713B00AFED1B /* CopyFiles */,
+ 72CD1DA00EE8C4EC005F825D /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = arp;
+ productName = arp;
+ productReference = 7261212D0EE8710B00AFED1B /* arp */;
+ productType = "com.apple.product-type.tool";
+ };
+ 726121530EE8881700AFED1B /* ifconfig */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 726121630EE8887300AFED1B /* Build configuration list for PBXNativeTarget "ifconfig" */;
+ buildPhases = (
+ 726121510EE8881700AFED1B /* Sources */,
+ 726121520EE8881700AFED1B /* Frameworks */,
+ 726121620EE8887300AFED1B /* CopyFiles */,
+ 72CD1DA40EE8C500005F825D /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ifconfig;
+ productName = ifconfig;
+ productReference = 726121540EE8881700AFED1B /* ifconfig */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7282BA0B1AFAD4C9005DE836 /* ecnprobe */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7282BA131AFAD4C9005DE836 /* Build configuration list for PBXNativeTarget "ecnprobe" */;
+ buildPhases = (
+ 7282BA081AFAD4C9005DE836 /* Sources */,
+ 7282BA091AFAD4C9005DE836 /* Frameworks */,
+ 7282BA0A1AFAD4C9005DE836 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ecnprobe;
+ productName = ecnprobe;
+ productReference = 7282BA0C1AFAD4C9005DE836 /* ecnprobe */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72946F421BBF055700087E35 /* frame_delay */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72946F4A1BBF055700087E35 /* Build configuration list for PBXNativeTarget "frame_delay" */;
+ buildPhases = (
+ 72946F3F1BBF055700087E35 /* Sources */,
+ 72946F401BBF055700087E35 /* Frameworks */,
+ 72946F411BBF055700087E35 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = frame_delay;
+ productName = frame_delay;
+ productReference = 72946F431BBF055700087E35 /* frame_delay */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7294F0F80EE8BB460052EC88 /* traceroute */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7294F0FD0EE8BB550052EC88 /* Build configuration list for PBXNativeTarget "traceroute" */;
+ buildPhases = (
+ 7294F0F60EE8BB460052EC88 /* Sources */,
+ 7294F0F70EE8BB460052EC88 /* Frameworks */,
+ 7294F11A0EE8BC0C0052EC88 /* CopyFiles */,
+ 7294F10C0EE8BBB60052EC88 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = traceroute;
+ productName = traceroute;
+ productReference = 7294F0F90EE8BB460052EC88 /* traceroute */;
+ productType = "com.apple.product-type.tool";
+ };
+ 7294F1290EE8BD280052EC88 /* traceroute6 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7294F13F0EE8BDB30052EC88 /* Build configuration list for PBXNativeTarget "traceroute6" */;
+ buildPhases = (
+ 7294F1270EE8BD280052EC88 /* Sources */,
+ 7294F1280EE8BD280052EC88 /* Frameworks */,
+ 7294F13E0EE8BDB30052EC88 /* CopyFiles */,
+ 7294F1360EE8BD4D0052EC88 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = traceroute6;
+ productName = traceroute6;
+ productReference = 7294F12A0EE8BD280052EC88 /* traceroute6 */;
+ productType = "com.apple.product-type.tool";
+ };
+ 72B732D91899B0380060E6D4 /* cfilutil */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 72B732E31899B0380060E6D4 /* Build configuration list for PBXNativeTarget "cfilutil" */;
+ buildPhases = (
+ 72B732D61899B0380060E6D4 /* Sources */,
+ 72B732D71899B0380060E6D4 /* Frameworks */,
+ 72B732D81899B0380060E6D4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cfilutil;
+ productName = cfilutil;
+ productReference = 72B732DA1899B0380060E6D4 /* cfilutil */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 724862310EE86EB7001D0DE9 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0800;
+ TargetAttributes = {
+ 713297671A93C743002359CF = {
+ CreatedOnToolsVersion = 6.3;
+ };
+ 7200F2F91958A34D0033E22C = {
+ CreatedOnToolsVersion = 6.0;
+ };
+ 72311F41194A349000EB4788 = {
+ CreatedOnToolsVersion = 6.0;
+ };
+ 7282BA0B1AFAD4C9005DE836 = {
+ CreatedOnToolsVersion = 7.0;
+ };
+ 72946F421BBF055700087E35 = {
+ CreatedOnToolsVersion = 6.3;
+ };
+ };
+ };
+ buildConfigurationList = 724862340EE86EB7001D0DE9 /* Build configuration list for PBXProject "network_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 7248622F0EE86EB7001D0DE9;
+ productRefGroup = 7261210D0EE8707500AFED1B /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 726121430EE8717500AFED1B /* All */,
+ 72570DA20EE8EBF3000F4CFB /* All-Embedded */,
+ 72ABD0811083D742008C721C /* All-EmbeddedOther */,
+ 72C77D3A1484199C002D2577 /* network_cmds_libs */,
+ 7261212C0EE8710B00AFED1B /* arp */,
+ 72B732D91899B0380060E6D4 /* cfilutil */,
+ 723C7067142BAFEA007C87E9 /* dnctl */,
+ 7282BA0B1AFAD4C9005DE836 /* ecnprobe */,
+ 72946F421BBF055700087E35 /* frame_delay */,
+ 726121530EE8881700AFED1B /* ifconfig */,
+ 4D2B04F21208C2040004A3F3 /* ip6addrctl */,
+ 724DABA10EE88FE3008900D0 /* kdumpd */,
+ 5658259E1339218F003E5FA5 /* mnc */,
+ 72311F41194A349000EB4788 /* mptcp_client */,
+ 690D978012DE6034004323A7 /* mtest */,
+ 724DAC0C0EE8940D008900D0 /* ndp */,
+ 7216D2450EE896C000AE70E4 /* netstat */,
+ 7247B83016165EDC00873B3C /* pktapctl */,
+ 7200F2F91958A34D0033E22C /* pktmnglr */,
+ 7216D27B0EE8980A00AE70E4 /* ping */,
+ 7216D2990EE898BD00AE70E4 /* ping6 */,
+ 7216D2CC0EE89B7900AE70E4 /* rarpd */,
+ 7216D2EC0EE89CBC00AE70E4 /* route */,
+ 7216D3130EE89E9E00AE70E4 /* rtadvd */,
+ 7216D3580EE8A02200AE70E4 /* rtsol */,
+ 7216D3A60EE8A3BA00AE70E4 /* spray */,
+ 7294F0F80EE8BB460052EC88 /* traceroute */,
+ 7294F1290EE8BD280052EC88 /* traceroute6 */,
+ 713297671A93C743002359CF /* unbound */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 039D6A11120A2CF60006B8C8 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/local/share/man/man8/ip6addrctl.8";
+ };
+ 690D97C212DE71CF004323A7 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/local/share/man/man8/mtest.8";
+ };
+ 69C10A7612DF7EBB00BCDF4C /* Install OSS License */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/mtest.tproj/COPYING",
+ );
+ name = "Install OSS License";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/network_cmds.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "cp \"$SRCROOT/mtest.tproj/COPYING\" \"$DERIVED_FILE_DIR/network_cmds.txt\"\n\nmkdir -p \"$DSTROOT/usr/local/OpenSourceLicenses\"\ncp \"$DERIVED_FILE_DIR/network_cmds.txt\" \"$DSTROOT/usr/local/OpenSourceLicenses/\"\n\n";
+ };
+ 7216D25F0EE8970100AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/kdumpd.8\n/bin/chmod 0644 $DSTROOT/System/Library/LaunchDaemons/com.apple.kdumpd.plist";
+ };
+ 7216D2640EE8972E00AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man1/netstat.1\t";
+ };
+ 7216D2870EE8982900AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ping.8\t";
+ };
+ 7216D2AF0EE8993100AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ping6.8";
+ };
+ 7216D2D80EE89B9B00AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/rarpd.8";
+ };
+ 7216D3030EE89D4300AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/route.8";
+ };
+ 7216D3450EE89FB900AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/rtadvd.8\n/bin/chmod 0444 $DSTROOT/usr/share/man/man5/rtadvd.conf.5\n/bin/chmod 0644 $DSTROOT/private/etc/rtadvd.conf";
+ };
+ 7216D3740EE8A06000AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/rtsol.8\n/bin/ln -f $DSTROOT/usr/share/man/man8/rtsol.8 $DSTROOT/usr/share/man/man8/rtsold.8\n/bin/ln -f $DSTROOT/sbin/rtsol $DSTROOT/usr/sbin/rtsold\n/usr/bin/strip $DSTROOT/usr/sbin/rtsold\n/bin/chmod 0555 $DSTROOT/usr/sbin/rtsold\n";
+ };
+ 7216D3B30EE8A3E000AE70E4 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/spray.8";
+ };
+ 724DAC440EE89562008900D0 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ndp.8\t";
+ };
+ 7294F10C0EE8BBB60052EC88 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/traceroute.8";
+ };
+ 7294F1360EE8BD4D0052EC88 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/traceroute6.8";
+ };
+ 72CD1DA00EE8C4EC005F825D /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/arp.8";
+ };
+ 72CD1DA40EE8C500005F825D /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "/bin/chmod 0444 $DSTROOT/usr/share/man/man8/ifconfig.8\t";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 4D2B04F01208C2040004A3F3 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 4D2B04F81208C21B0004A3F3 /* ip6addrctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 5658259C1339218F003E5FA5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 565825A4133921A3003E5FA5 /* mnc_error.c in Sources */,
+ 565825A5133921A3003E5FA5 /* mnc_main.c in Sources */,
+ 565825A6133921A3003E5FA5 /* mnc_multicast.c in Sources */,
+ 565825A7133921A3003E5FA5 /* mnc_opts.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 690D977E12DE6034004323A7 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 690D97A612DE6F96004323A7 /* mtest.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 713297641A93C743002359CF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7200F2F61958A34D0033E22C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7200F2FD1958A34D0033E22C /* packet_mangler.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2430EE896C000AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D24C0EE896F300AE70E4 /* data.c in Sources */,
+ 7216D24D0EE896F300AE70E4 /* if.c in Sources */,
+ 7216D24E0EE896F300AE70E4 /* inet.c in Sources */,
+ 7216D24F0EE896F300AE70E4 /* inet6.c in Sources */,
+ 7216D2500EE896F300AE70E4 /* ipsec.c in Sources */,
+ 7216D2510EE896F300AE70E4 /* main.c in Sources */,
+ 01560DFD241969D3001AA29A /* vsock.c in Sources */,
+ 7216D2520EE896F300AE70E4 /* mbuf.c in Sources */,
+ 7216D2530EE896F300AE70E4 /* mcast.c in Sources */,
+ 7218B54A191D4202001B7B52 /* systm.c in Sources */,
+ 7216D2560EE896F300AE70E4 /* route.c in Sources */,
+ 7216D2570EE896F300AE70E4 /* tp_astring.c in Sources */,
+ 56B6B66816F79A1C00D8A7A9 /* mptcp.c in Sources */,
+ 7216D2580EE896F300AE70E4 /* unix.c in Sources */,
+ 721654C31EC52447005B17BA /* misc.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2790EE8980A00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724769381CE2C1E400AAB5F0 /* gmt2local.c in Sources */,
+ 7216D2800EE8981C00AE70E4 /* ping.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2970EE898BD00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724769371CE2B1FF00AAB5F0 /* gmt2local.c in Sources */,
+ 7216D2A00EE898DF00AE70E4 /* md5.c in Sources */,
+ 7216D2A10EE898DF00AE70E4 /* ping6.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2CA0EE89B7900AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D2D10EE89B8300AE70E4 /* rarpd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D2EA0EE89CBC00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D2F20EE89CD600AE70E4 /* route.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3110EE89E9E00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72D33F572271319400EF5B5E /* rtadvd_logging.c in Sources */,
+ 7216D3190EE89EC100AE70E4 /* advcap.c in Sources */,
+ 7216D31A0EE89EC100AE70E4 /* config.c in Sources */,
+ 7216D31B0EE89EC100AE70E4 /* dump.c in Sources */,
+ 7216D31C0EE89EC100AE70E4 /* if.c in Sources */,
+ 7216D31D0EE89EC100AE70E4 /* rrenum.c in Sources */,
+ 7216D31E0EE89EC100AE70E4 /* rtadvd.c in Sources */,
+ 7216D31F0EE89EC100AE70E4 /* timer.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3560EE8A02200AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D3670EE8A04700AE70E4 /* dump.c in Sources */,
+ 7216D3680EE8A04700AE70E4 /* if.c in Sources */,
+ 7216D3690EE8A04700AE70E4 /* probe.c in Sources */,
+ 7216D36A0EE8A04700AE70E4 /* rtsock.c in Sources */,
+ 7216D36B0EE8A04700AE70E4 /* rtsol.c in Sources */,
+ 7216D36C0EE8A04700AE70E4 /* rtsold.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7216D3A40EE8A3BA00AE70E4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7216D3AB0EE8A3C400AE70E4 /* spray.c in Sources */,
+ 7294F0DF0EE8BA730052EC88 /* spray.x in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72311F3E194A349000EB4788 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72311F54194A354F00EB4788 /* conn_lib.c in Sources */,
+ 72311F55194A354F00EB4788 /* mptcp_client.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 723C7064142BAFEA007C87E9 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72D000C4142BB11100151981 /* dnctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7247B82D16165EDC00873B3C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7247B83C16165F0100873B3C /* pktapctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724DAB9F0EE88FE3008900D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724DABA60EE88FED008900D0 /* kdumpd.c in Sources */,
+ 724DABA70EE88FED008900D0 /* kdumpsubs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 724DAC0A0EE8940D008900D0 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 724DAC120EE89423008900D0 /* ndp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7261212A0EE8710B00AFED1B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 726121310EE8711E00AFED1B /* arp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 726121510EE8881700AFED1B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72B7F36B1BA69352003A9AA2 /* if6lowpan.c in Sources */,
+ 7261215A0EE8883900AFED1B /* ifbond.c in Sources */,
+ 7261215B0EE8883900AFED1B /* ifconfig.c in Sources */,
+ 7261215C0EE8883900AFED1B /* ifmedia.c in Sources */,
+ 7261215D0EE8883900AFED1B /* ifvlan.c in Sources */,
+ 72E650A7107BF2F000AAF325 /* af_inet.c in Sources */,
+ 72E650A8107BF2F000AAF325 /* af_inet6.c in Sources */,
+ 72E650A9107BF2F000AAF325 /* af_link.c in Sources */,
+ 72E650AA107BF2F000AAF325 /* ifbridge.c in Sources */,
+ 72E650AB107BF2F000AAF325 /* ifclone.c in Sources */,
+ F940359D1E2FF5A900283EB1 /* iffake.c in Sources */,
+ F97F1E041E9C3FC8002355FF /* nexus.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7282BA081AFAD4C9005DE836 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7282BA531AFAD58E005DE836 /* support.c in Sources */,
+ 7282BA4D1AFAD58E005DE836 /* gmt2local.c in Sources */,
+ 7282BA4C1AFAD58E005DE836 /* ecn.c in Sources */,
+ 7282BA4B1AFAD58E005DE836 /* ecn_probe.c in Sources */,
+ 7282BA521AFAD58E005DE836 /* session.c in Sources */,
+ 7282BA491AFAD58E005DE836 /* capture.c in Sources */,
+ 7282BA4E1AFAD58E005DE836 /* history.c in Sources */,
+ 7282BA4F1AFAD58E005DE836 /* inet.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72946F3F1BBF055700087E35 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72946F501BBF07FF00087E35 /* frame_delay.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7294F0F60EE8BB460052EC88 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7294F1000EE8BB990052EC88 /* as.c in Sources */,
+ 7294F1010EE8BB990052EC88 /* findsaddr-socket.c in Sources */,
+ 7294F1020EE8BB990052EC88 /* ifaddrlist.c in Sources */,
+ 7294F1030EE8BB990052EC88 /* traceroute.c in Sources */,
+ 7294F1040EE8BB990052EC88 /* version.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 7294F1270EE8BD280052EC88 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 7294F12E0EE8BD2F0052EC88 /* traceroute6.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 72B732D61899B0380060E6D4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 72B732EF1899B23A0060E6D4 /* cfilutil.c in Sources */,
+ 72B732F11899B2430060E6D4 /* cfilstat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 034E4464100BDCA3009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7261212C0EE8710B00AFED1B /* arp */;
+ targetProxy = 034E4463100BDCA3009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E4469100BDD00009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 726121530EE8881700AFED1B /* ifconfig */;
+ targetProxy = 034E4468100BDD00009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E4475100BDEC6009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2450EE896C000AE70E4 /* netstat */;
+ targetProxy = 034E4474100BDEC6009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E447B100BDF0D009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D27B0EE8980A00AE70E4 /* ping */;
+ targetProxy = 034E447A100BDF0D009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E447F100BDF54009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2EC0EE89CBC00AE70E4 /* route */;
+ targetProxy = 034E447E100BDF54009CA3DC /* PBXContainerItemProxy */;
+ };
+ 034E4485100BE15F009CA3DC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F0F80EE8BB460052EC88 /* traceroute */;
+ targetProxy = 034E4484100BE15F009CA3DC /* PBXContainerItemProxy */;
+ };
+ 03B2DBD1100BE626005349BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724DAC0C0EE8940D008900D0 /* ndp */;
+ targetProxy = 03B2DBD0100BE626005349BC /* PBXContainerItemProxy */;
+ };
+ 03B2DBD3100BE645005349BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2990EE898BD00AE70E4 /* ping6 */;
+ targetProxy = 03B2DBD2100BE645005349BC /* PBXContainerItemProxy */;
+ };
+ 03B2DBDB100BE6D2005349BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3580EE8A02200AE70E4 /* rtsol */;
+ targetProxy = 03B2DBDA100BE6D2005349BC /* PBXContainerItemProxy */;
+ };
+ 03B2DBDD100BE6D5005349BC /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F1290EE8BD280052EC88 /* traceroute6 */;
+ targetProxy = 03B2DBDC100BE6D5005349BC /* PBXContainerItemProxy */;
+ };
+ 18515B85133D1DBF000148A4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3130EE89E9E00AE70E4 /* rtadvd */;
+ targetProxy = 18515B84133D1DBF000148A4 /* PBXContainerItemProxy */;
+ };
+ 4D2B05141208C6BB0004A3F3 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 4D2B04F21208C2040004A3F3 /* ip6addrctl */;
+ targetProxy = 4D2B05131208C6BB0004A3F3 /* PBXContainerItemProxy */;
+ };
+ 565825AD13392232003E5FA5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5658259E1339218F003E5FA5 /* mnc */;
+ targetProxy = 565825AC13392232003E5FA5 /* PBXContainerItemProxy */;
+ };
+ 565825AF13392239003E5FA5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5658259E1339218F003E5FA5 /* mnc */;
+ targetProxy = 565825AE13392239003E5FA5 /* PBXContainerItemProxy */;
+ };
+ 565825B113392242003E5FA5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5658259E1339218F003E5FA5 /* mnc */;
+ targetProxy = 565825B013392242003E5FA5 /* PBXContainerItemProxy */;
+ };
+ 690D97BA12DE7130004323A7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 690D978012DE6034004323A7 /* mtest */;
+ targetProxy = 690D97B912DE7130004323A7 /* PBXContainerItemProxy */;
+ };
+ 690D97BC12DE7151004323A7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 690D978012DE6034004323A7 /* mtest */;
+ targetProxy = 690D97BB12DE7151004323A7 /* PBXContainerItemProxy */;
+ };
+ 690D97BE12DE7166004323A7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 690D978012DE6034004323A7 /* mtest */;
+ targetProxy = 690D97BD12DE7166004323A7 /* PBXContainerItemProxy */;
+ };
+ 71D958C51A9455A000C9B286 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 713297671A93C743002359CF /* unbound */;
+ targetProxy = 71D958C41A9455A000C9B286 /* PBXContainerItemProxy */;
+ };
+ 7200F3031958A4F10033E22C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7200F2F91958A34D0033E22C /* pktmnglr */;
+ targetProxy = 7200F3021958A4F10033E22C /* PBXContainerItemProxy */;
+ };
+ 7200F3051958A4FA0033E22C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7200F2F91958A34D0033E22C /* pktmnglr */;
+ targetProxy = 7200F3041958A4FA0033E22C /* PBXContainerItemProxy */;
+ };
+ 7200F3071958A5040033E22C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7200F2F91958A34D0033E22C /* pktmnglr */;
+ targetProxy = 7200F3061958A5040033E22C /* PBXContainerItemProxy */;
+ };
+ 7216D2670EE8978F00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2450EE896C000AE70E4 /* netstat */;
+ targetProxy = 7216D2660EE8978F00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D2C00EE89ADF00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D27B0EE8980A00AE70E4 /* ping */;
+ targetProxy = 7216D2BF0EE89ADF00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D2C20EE89ADF00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2990EE898BD00AE70E4 /* ping6 */;
+ targetProxy = 7216D2C10EE89ADF00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D2DA0EE89BE900AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2CC0EE89B7900AE70E4 /* rarpd */;
+ targetProxy = 7216D2D90EE89BE900AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D3060EE89D9A00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2EC0EE89CBC00AE70E4 /* route */;
+ targetProxy = 7216D3050EE89D9A00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D34D0EE89FEC00AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3130EE89E9E00AE70E4 /* rtadvd */;
+ targetProxy = 7216D34C0EE89FEC00AE70E4 /* PBXContainerItemProxy */;
+ };
+ 7216D37F0EE8A0B300AE70E4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3580EE8A02200AE70E4 /* rtsol */;
+ targetProxy = 7216D37E0EE8A0B300AE70E4 /* PBXContainerItemProxy */;
+ };
+ 72179EAE146233390098FB3E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723C7067142BAFEA007C87E9 /* dnctl */;
+ targetProxy = 72179EAD146233390098FB3E /* PBXContainerItemProxy */;
+ };
+ 72311F4B194A34EB00EB4788 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72311F41194A349000EB4788 /* mptcp_client */;
+ targetProxy = 72311F4A194A34EB00EB4788 /* PBXContainerItemProxy */;
+ };
+ 72311F4D194A34F500EB4788 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72311F41194A349000EB4788 /* mptcp_client */;
+ targetProxy = 72311F4C194A34F500EB4788 /* PBXContainerItemProxy */;
+ };
+ 72311F4F194A34FE00EB4788 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72311F41194A349000EB4788 /* mptcp_client */;
+ targetProxy = 72311F4E194A34FE00EB4788 /* PBXContainerItemProxy */;
+ };
+ 723C7074142BB003007C87E9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 723C7067142BAFEA007C87E9 /* dnctl */;
+ targetProxy = 723C7073142BB003007C87E9 /* PBXContainerItemProxy */;
+ };
+ 724DABC30EE890A6008900D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724DABA10EE88FE3008900D0 /* kdumpd */;
+ targetProxy = 724DABC20EE890A6008900D0 /* PBXContainerItemProxy */;
+ };
+ 724DAC240EE89525008900D0 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724DAC0C0EE8940D008900D0 /* ndp */;
+ targetProxy = 724DAC230EE89525008900D0 /* PBXContainerItemProxy */;
+ };
+ 7250E1471616642000A11A76 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7247B83016165EDC00873B3C /* pktapctl */;
+ targetProxy = 7250E1461616642000A11A76 /* PBXContainerItemProxy */;
+ };
+ 7250E1491616642900A11A76 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7247B83016165EDC00873B3C /* pktapctl */;
+ targetProxy = 7250E1481616642900A11A76 /* PBXContainerItemProxy */;
+ };
+ 7250E14B1616643000A11A76 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7247B83016165EDC00873B3C /* pktapctl */;
+ targetProxy = 7250E14A1616643000A11A76 /* PBXContainerItemProxy */;
+ };
+ 726121490EE8717B00AFED1B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7261212C0EE8710B00AFED1B /* arp */;
+ targetProxy = 726121480EE8717B00AFED1B /* PBXContainerItemProxy */;
+ };
+ 7261217D0EE8896800AFED1B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 726121530EE8881700AFED1B /* ifconfig */;
+ targetProxy = 7261217C0EE8896800AFED1B /* PBXContainerItemProxy */;
+ };
+ 7263724B1BCC709900E4B026 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72946F421BBF055700087E35 /* frame_delay */;
+ targetProxy = 7263724A1BCC709900E4B026 /* PBXContainerItemProxy */;
+ };
+ 7282BA571AFBDEAD005DE836 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7282BA0B1AFAD4C9005DE836 /* ecnprobe */;
+ targetProxy = 7282BA561AFBDEAD005DE836 /* PBXContainerItemProxy */;
+ };
+ 7282BA591AFBDEC2005DE836 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7282BA0B1AFAD4C9005DE836 /* ecnprobe */;
+ targetProxy = 7282BA581AFBDEC2005DE836 /* PBXContainerItemProxy */;
+ };
+ 7282BA5B1AFBDED3005DE836 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7282BA0B1AFAD4C9005DE836 /* ecnprobe */;
+ targetProxy = 7282BA5A1AFBDED3005DE836 /* PBXContainerItemProxy */;
+ };
+ 72946F4C1BBF063800087E35 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72946F421BBF055700087E35 /* frame_delay */;
+ targetProxy = 72946F4B1BBF063800087E35 /* PBXContainerItemProxy */;
+ };
+ 72946F4E1BBF063F00087E35 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72946F421BBF055700087E35 /* frame_delay */;
+ targetProxy = 72946F4D1BBF063F00087E35 /* PBXContainerItemProxy */;
+ };
+ 7294F0EA0EE8BAC80052EC88 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3A60EE8A3BA00AE70E4 /* spray */;
+ targetProxy = 7294F0E90EE8BAC80052EC88 /* PBXContainerItemProxy */;
+ };
+ 7294F1210EE8BCC20052EC88 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F0F80EE8BB460052EC88 /* traceroute */;
+ targetProxy = 7294F1200EE8BCC20052EC88 /* PBXContainerItemProxy */;
+ };
+ 72ABD0881083D750008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 726121530EE8881700AFED1B /* ifconfig */;
+ targetProxy = 72ABD0871083D750008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD08C1083D75D008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 724DAC0C0EE8940D008900D0 /* ndp */;
+ targetProxy = 72ABD08B1083D75D008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD08E1083D75F008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2450EE896C000AE70E4 /* netstat */;
+ targetProxy = 72ABD08D1083D75F008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0901083D762008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D27B0EE8980A00AE70E4 /* ping */;
+ targetProxy = 72ABD08F1083D762008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0921083D764008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2990EE898BD00AE70E4 /* ping6 */;
+ targetProxy = 72ABD0911083D764008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0941083D767008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2CC0EE89B7900AE70E4 /* rarpd */;
+ targetProxy = 72ABD0931083D767008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0961083D76A008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D2EC0EE89CBC00AE70E4 /* route */;
+ targetProxy = 72ABD0951083D76A008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0981083D76D008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3130EE89E9E00AE70E4 /* rtadvd */;
+ targetProxy = 72ABD0971083D76D008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD09A1083D76F008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7216D3580EE8A02200AE70E4 /* rtsol */;
+ targetProxy = 72ABD0991083D76F008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD09C1083D772008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F0F80EE8BB460052EC88 /* traceroute */;
+ targetProxy = 72ABD09B1083D772008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD09E1083D774008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F1290EE8BD280052EC88 /* traceroute6 */;
+ targetProxy = 72ABD09D1083D774008C721C /* PBXContainerItemProxy */;
+ };
+ 72ABD0A41083D818008C721C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7261212C0EE8710B00AFED1B /* arp */;
+ targetProxy = 72ABD0A31083D818008C721C /* PBXContainerItemProxy */;
+ };
+ 72B732E91899B18F0060E6D4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72B732D91899B0380060E6D4 /* cfilutil */;
+ targetProxy = 72B732E81899B18F0060E6D4 /* PBXContainerItemProxy */;
+ };
+ 72B732EB1899B19A0060E6D4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 72B732D91899B0380060E6D4 /* cfilutil */;
+ targetProxy = 72B732EA1899B19A0060E6D4 /* PBXContainerItemProxy */;
+ };
+ 72CD1D9C0EE8C47C005F825D /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 7294F1290EE8BD280052EC88 /* traceroute6 */;
+ targetProxy = 72CD1D9B0EE8C47C005F825D /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 03B2DBE2100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_RFC2292BIS=1",
+ "__APPLE_USE_RFC_3542=1",
+ "__APPLE_API_OBSOLETE=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PREBINDING = NO;
+ SDKROOT = macosx.internal;
+ "STRIPFLAGS[sdk=iphoneos*]" = "-S";
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ WARNING_CFLAGS = "-Wall";
+ ZERO_LINK = NO;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBE3100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = network_cmds;
+ ZERO_LINK = NO;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBE4100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = network_cmds;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBE6100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = arp;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBE7100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ USE_IF_MEDIA,
+ NO_IPX,
+ INET6,
+ );
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ "$(inherited)",
+ USE_VLANS,
+ USE_BONDS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ifconfig;
+ ZERO_LINK = NO;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBEB100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = kdumpd;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBED100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC_DEBUG,
+ KAME_SCOPEID,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = ndp;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBEE100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ $inherited,
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = netstat;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBEF100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF0100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping6;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF1100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "TFTP_DIR=\\\"/tftpboot\\\"",
+ );
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rarpd;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF2100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = route;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF3100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rtadvd;
+ USE_HEADERMAP = NO;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ "-Wno-address-of-packed-member",
+ );
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF4100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = rtsol;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ );
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF5100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = spray;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF6100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALTERNATE_MODE = 04555;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ HAVE_SOCKADDR_SA_LEN,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute;
+ };
+ name = "Ignore Me";
+ };
+ 03B2DBF7100BE71D005349BC /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute6;
+ };
+ name = "Ignore Me";
+ };
+ 4D2B04F51208C2050004A3F3 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALTERNATE_MODE = 0555;
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = ip6addrctl;
+ };
+ name = Debug;
+ };
+ 4D2B04F61208C2050004A3F3 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = ip6addrctl;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 4D2B04F71208C2050004A3F3 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = ip6addrctl;
+ };
+ name = "Ignore Me";
+ };
+ 565825A11339218F003E5FA5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mnc;
+ };
+ name = Debug;
+ };
+ 565825A21339218F003E5FA5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mnc;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 565825A31339218F003E5FA5 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mnc;
+ };
+ name = "Ignore Me";
+ };
+ 690D978312DE6035004323A7 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mtest;
+ };
+ name = Debug;
+ };
+ 690D978412DE6035004323A7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mtest;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 690D978512DE6035004323A7 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/local/bin;
+ PREBINDING = NO;
+ PRODUCT_NAME = mtest;
+ };
+ name = "Ignore Me";
+ };
+ 7132976C1A93C743002359CF /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ HEADER_SEARCH_PATHS = /usr/local/libressl/include;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ LIBRARY_SEARCH_PATHS = /usr/local/libressl/lib;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ OTHER_LDFLAGS = (
+ "-lssl",
+ "-lcrypto",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = macosx;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/unbound";
+ USE_HEADERMAP = NO;
+ VALID_ARCHS = "x86_64 x86_64h";
+ };
+ name = Debug;
+ };
+ 7132976D1A93C743002359CF /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ HEADER_SEARCH_PATHS = /usr/local/libressl/include;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ LIBRARY_SEARCH_PATHS = /usr/local/libressl/lib;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_LDFLAGS = (
+ "-lssl",
+ "-lcrypto",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = macosx;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/unbound";
+ USE_HEADERMAP = NO;
+ VALID_ARCHS = "x86_64 x86_64h";
+ };
+ name = Release;
+ };
+ 7132976E1A93C743002359CF /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ HEADER_SEARCH_PATHS = /usr/local/libressl/include;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ LIBRARY_SEARCH_PATHS = /usr/local/libressl/lib;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_LDFLAGS = (
+ "-lssl",
+ "-lcrypto",
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = macosx;
+ USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/unbound";
+ USE_HEADERMAP = NO;
+ VALID_ARCHS = "x86_64 x86_64h";
+ };
+ name = "Ignore Me";
+ };
+ 7200F2FE1958A34D0033E22C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7200F2FF1958A34D0033E22C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7200F3001958A34D0033E22C /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 7216D2480EE896C100AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ $inherited,
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = netstat;
+ };
+ name = Debug;
+ };
+ 7216D2490EE896C100AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ $inherited,
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = netstat;
+ };
+ name = Release;
+ };
+ 7216D27E0EE8980B00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_RFC2292BIS=1",
+ "__APPLE_USE_RFC_3542=1",
+ "__APPLE_API_OBSOLETE=1",
+ "DEBUG=1",
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping;
+ };
+ name = Debug;
+ };
+ 7216D27F0EE8980B00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping;
+ };
+ name = Release;
+ };
+ 7216D29C0EE898BE00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping6;
+ };
+ name = Debug;
+ };
+ 7216D29D0EE898BE00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ping6;
+ };
+ name = Release;
+ };
+ 7216D2CF0EE89B7A00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "TFTP_DIR=\\\"/tftpboot\\\"",
+ );
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rarpd;
+ };
+ name = Debug;
+ };
+ 7216D2D00EE89B7A00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "TFTP_DIR=\\\"/tftpboot\\\"",
+ );
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rarpd;
+ };
+ name = Release;
+ };
+ 7216D2EF0EE89CBC00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = route;
+ };
+ name = Debug;
+ };
+ 7216D2F00EE89CBC00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = route;
+ };
+ name = Release;
+ };
+ 7216D3160EE89E9F00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rtadvd;
+ USE_HEADERMAP = NO;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ "-Wno-address-of-packed-member",
+ );
+ };
+ name = Debug;
+ };
+ 7216D3170EE89E9F00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = rtadvd;
+ USE_HEADERMAP = NO;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ "-Wno-address-of-packed-member",
+ );
+ };
+ name = Release;
+ };
+ 7216D35B0EE8A02300AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = rtsol;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ );
+ };
+ name = Debug;
+ };
+ 7216D35C0EE8A02300AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ HAVE_GETIFADDRS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = rtsol;
+ WARNING_CFLAGS = (
+ "$(inherited)",
+ "-Wno-deprecated-declarations",
+ );
+ };
+ name = Release;
+ };
+ 7216D3A90EE8A3BB00AE70E4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = spray;
+ };
+ name = Debug;
+ };
+ 7216D3AA0EE8A3BB00AE70E4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = spray;
+ };
+ name = Release;
+ };
+ 72311F47194A349100EB4788 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72311F48194A349100EB4788 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72311F49194A349100EB4788 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ METAL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 723C7070142BAFEA007C87E9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 723C7071142BAFEA007C87E9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 723C7072142BAFEA007C87E9 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 7247B83716165EDC00873B3C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7247B83816165EDC00873B3C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7247B83916165EDC00873B3C /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 724862320EE86EB7001D0DE9 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPRESSION = lossless;
+ COPY_PHASE_STRIP = NO;
+ DEAD_CODE_STRIPPING = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_RFC2292BIS=1",
+ "__APPLE_USE_RFC_3542=1",
+ "__APPLE_API_OBSOLETE=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PREBINDING = NO;
+ SDKROOT = macosx.internal;
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ WARNING_CFLAGS = "-Wall";
+ };
+ name = Debug;
+ };
+ 724862330EE86EB7001D0DE9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPRESSION = "respect-asset-catalog";
+ COPY_PHASE_STRIP = YES;
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ "DEBUG_INFORMATION_FORMAT[sdk=iphoneos*][arch=*]" = dwarf;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "USE_RFC2292BIS=1",
+ "__APPLE_USE_RFC_3542=1",
+ "__APPLE_API_OBSOLETE=1",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PREBINDING = NO;
+ SDKROOT = macosx.internal;
+ "STRIPFLAGS[sdk=iphoneos*]" = "-S";
+ SUPPORTED_PLATFORMS = "macosx iphoneos";
+ WARNING_CFLAGS = "-Wall";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 724DABA40EE88FE3008900D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = kdumpd;
+ };
+ name = Debug;
+ };
+ 724DABA50EE88FE3008900D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = kdumpd;
+ };
+ name = Release;
+ };
+ 724DAC0F0EE8940E008900D0 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC_DEBUG,
+ KAME_SCOPEID,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = ndp;
+ };
+ name = Debug;
+ };
+ 724DAC100EE8940E008900D0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC_DEBUG,
+ KAME_SCOPEID,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = ndp;
+ };
+ name = Release;
+ };
+ 72570DA30EE8EBF3000F4CFB /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = network_cmds;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 72570DA40EE8EBF3000F4CFB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = network_cmds;
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+ 7261212F0EE8710B00AFED1B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = arp;
+ };
+ name = Debug;
+ };
+ 726121300EE8710B00AFED1B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = arp;
+ };
+ name = Release;
+ };
+ 726121440EE8717500AFED1B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = network_cmds;
+ };
+ name = Debug;
+ };
+ 726121450EE8717500AFED1B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = network_cmds;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 726121560EE8881800AFED1B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ USE_IF_MEDIA,
+ NO_IPX,
+ INET6,
+ );
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ $inherited,
+ USE_VLANS,
+ USE_BONDS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ifconfig;
+ };
+ name = Debug;
+ };
+ 726121570EE8881800AFED1B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ USE_IF_MEDIA,
+ NO_IPX,
+ INET6,
+ );
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ "$(inherited)",
+ USE_VLANS,
+ USE_BONDS,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = ifconfig;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 7282BA101AFAD4C9005DE836 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 7282BA111AFAD4C9005DE836 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 7282BA121AFAD4C9005DE836 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 72946F471BBF055700087E35 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include,
+ /System/Library/Frameworks/System.framework/PrivateHeaders,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72946F481BBF055700087E35 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include,
+ /System/Library/Frameworks/System.framework/PrivateHeaders,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72946F491BBF055700087E35 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/OSX10.11.xctoolchain/usr/include,
+ /System/Library/Frameworks/System.framework/PrivateHeaders,
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 7294F0FB0EE8BB460052EC88 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALTERNATE_MODE = 04555;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ HAVE_SOCKADDR_SA_LEN,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute;
+ };
+ name = Debug;
+ };
+ 7294F0FC0EE8BB460052EC88 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALTERNATE_MODE = 04555;
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ HAVE_SOCKADDR_SA_LEN,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute;
+ };
+ name = Release;
+ };
+ 7294F12C0EE8BD290052EC88 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute6;
+ };
+ name = Debug;
+ };
+ 7294F12D0EE8BD290052EC88 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/network-client-server-entitlements.plist";
+ CODE_SIGN_IDENTITY = "-";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ INET6,
+ IPSEC,
+ );
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 04555;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = traceroute6;
+ };
+ name = Release;
+ };
+ 72ABD0821083D743008C721C /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = "All-EmbeddedOther";
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 72ABD0831083D743008C721C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = "All-EmbeddedOther";
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 72ABD0841083D743008C721C /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "All-EmbeddedOther";
+ SDKROOT = iphoneos;
+ SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = "Ignore Me";
+ };
+ 72B732E01899B0380060E6D4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ MACOSX_DEPLOYMENT_TARGET = "";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 72B732E11899B0380060E6D4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ MACOSX_DEPLOYMENT_TARGET = "";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 72B732E21899B0380060E6D4 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ ENABLE_NS_ASSERTIONS = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = /System/Library/Frameworks/System.framework/PrivateHeaders;
+ INSTALL_MODE_FLAG = 0555;
+ MACOSX_DEPLOYMENT_TARGET = "";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = "Ignore Me";
+ };
+ 72C77D681484199C002D2577 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = network_cmds_libs;
+ };
+ name = Debug;
+ };
+ 72C77D691484199C002D2577 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = network_cmds_libs;
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 72C77D6A1484199C002D2577 /* Ignore Me */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = network_cmds_libs;
+ ZERO_LINK = NO;
+ };
+ name = "Ignore Me";
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 4D2B05121208C2300004A3F3 /* Build configuration list for PBXNativeTarget "ip6addrctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 4D2B04F51208C2050004A3F3 /* Debug */,
+ 4D2B04F61208C2050004A3F3 /* Release */,
+ 4D2B04F71208C2050004A3F3 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 565825AB133921ED003E5FA5 /* Build configuration list for PBXNativeTarget "mnc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 565825A11339218F003E5FA5 /* Debug */,
+ 565825A21339218F003E5FA5 /* Release */,
+ 565825A31339218F003E5FA5 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 690D978612DE6053004323A7 /* Build configuration list for PBXNativeTarget "mtest" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 690D978312DE6035004323A7 /* Debug */,
+ 690D978412DE6035004323A7 /* Release */,
+ 690D978512DE6035004323A7 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7132976F1A93C743002359CF /* Build configuration list for PBXNativeTarget "unbound" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7132976C1A93C743002359CF /* Debug */,
+ 7132976D1A93C743002359CF /* Release */,
+ 7132976E1A93C743002359CF /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7200F3011958A34E0033E22C /* Build configuration list for PBXNativeTarget "pktmnglr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7200F2FE1958A34D0033E22C /* Debug */,
+ 7200F2FF1958A34D0033E22C /* Release */,
+ 7200F3001958A34D0033E22C /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D24B0EE896EC00AE70E4 /* Build configuration list for PBXNativeTarget "netstat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D2480EE896C100AE70E4 /* Debug */,
+ 7216D2490EE896C100AE70E4 /* Release */,
+ 03B2DBEE100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D2940EE8988200AE70E4 /* Build configuration list for PBXNativeTarget "ping" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D27E0EE8980B00AE70E4 /* Debug */,
+ 7216D27F0EE8980B00AE70E4 /* Release */,
+ 03B2DBEF100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D2AB0EE8991200AE70E4 /* Build configuration list for PBXNativeTarget "ping6" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D29C0EE898BE00AE70E4 /* Debug */,
+ 7216D29D0EE898BE00AE70E4 /* Release */,
+ 03B2DBF0100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D2E30EE89BEA00AE70E4 /* Build configuration list for PBXNativeTarget "rarpd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D2CF0EE89B7A00AE70E4 /* Debug */,
+ 7216D2D00EE89B7A00AE70E4 /* Release */,
+ 03B2DBF1100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D2FB0EE89D2600AE70E4 /* Build configuration list for PBXNativeTarget "route" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D2EF0EE89CBC00AE70E4 /* Debug */,
+ 7216D2F00EE89CBC00AE70E4 /* Release */,
+ 03B2DBF2100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D3200EE89EDF00AE70E4 /* Build configuration list for PBXNativeTarget "rtadvd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D3160EE89E9F00AE70E4 /* Debug */,
+ 7216D3170EE89E9F00AE70E4 /* Release */,
+ 03B2DBF3100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D3660EE8A02B00AE70E4 /* Build configuration list for PBXNativeTarget "rtsol" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D35B0EE8A02300AE70E4 /* Debug */,
+ 7216D35C0EE8A02300AE70E4 /* Release */,
+ 03B2DBF4100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7216D3C20EE8A42D00AE70E4 /* Build configuration list for PBXNativeTarget "spray" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7216D3A90EE8A3BB00AE70E4 /* Debug */,
+ 7216D3AA0EE8A3BB00AE70E4 /* Release */,
+ 03B2DBF5100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72311F46194A349100EB4788 /* Build configuration list for PBXNativeTarget "mptcp_client" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72311F47194A349100EB4788 /* Debug */,
+ 72311F48194A349100EB4788 /* Release */,
+ 72311F49194A349100EB4788 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 723C706F142BAFEA007C87E9 /* Build configuration list for PBXNativeTarget "dnctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 723C7070142BAFEA007C87E9 /* Debug */,
+ 723C7071142BAFEA007C87E9 /* Release */,
+ 723C7072142BAFEA007C87E9 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7247B83A16165EDC00873B3C /* Build configuration list for PBXNativeTarget "pktapctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7247B83716165EDC00873B3C /* Debug */,
+ 7247B83816165EDC00873B3C /* Release */,
+ 7247B83916165EDC00873B3C /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724862340EE86EB7001D0DE9 /* Build configuration list for PBXProject "network_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724862320EE86EB7001D0DE9 /* Debug */,
+ 724862330EE86EB7001D0DE9 /* Release */,
+ 03B2DBE2100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724DABB80EE89035008900D0 /* Build configuration list for PBXNativeTarget "kdumpd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724DABA40EE88FE3008900D0 /* Debug */,
+ 724DABA50EE88FE3008900D0 /* Release */,
+ 03B2DBEB100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 724DAC1E0EE894E8008900D0 /* Build configuration list for PBXNativeTarget "ndp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 724DAC0F0EE8940E008900D0 /* Debug */,
+ 724DAC100EE8940E008900D0 /* Release */,
+ 03B2DBED100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72570DA60EE8EC0F000F4CFB /* Build configuration list for PBXAggregateTarget "All-Embedded" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72570DA30EE8EBF3000F4CFB /* Debug */,
+ 72570DA40EE8EBF3000F4CFB /* Release */,
+ 03B2DBE4100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 726121400EE8713B00AFED1B /* Build configuration list for PBXNativeTarget "arp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7261212F0EE8710B00AFED1B /* Debug */,
+ 726121300EE8710B00AFED1B /* Release */,
+ 03B2DBE6100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7261214B0EE8717D00AFED1B /* Build configuration list for PBXAggregateTarget "All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 726121440EE8717500AFED1B /* Debug */,
+ 726121450EE8717500AFED1B /* Release */,
+ 03B2DBE3100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 726121630EE8887300AFED1B /* Build configuration list for PBXNativeTarget "ifconfig" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 726121560EE8881800AFED1B /* Debug */,
+ 726121570EE8881800AFED1B /* Release */,
+ 03B2DBE7100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7282BA131AFAD4C9005DE836 /* Build configuration list for PBXNativeTarget "ecnprobe" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7282BA101AFAD4C9005DE836 /* Debug */,
+ 7282BA111AFAD4C9005DE836 /* Release */,
+ 7282BA121AFAD4C9005DE836 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72946F4A1BBF055700087E35 /* Build configuration list for PBXNativeTarget "frame_delay" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72946F471BBF055700087E35 /* Debug */,
+ 72946F481BBF055700087E35 /* Release */,
+ 72946F491BBF055700087E35 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7294F0FD0EE8BB550052EC88 /* Build configuration list for PBXNativeTarget "traceroute" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7294F0FB0EE8BB460052EC88 /* Debug */,
+ 7294F0FC0EE8BB460052EC88 /* Release */,
+ 03B2DBF6100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7294F13F0EE8BDB30052EC88 /* Build configuration list for PBXNativeTarget "traceroute6" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7294F12C0EE8BD290052EC88 /* Debug */,
+ 7294F12D0EE8BD290052EC88 /* Release */,
+ 03B2DBF7100BE71D005349BC /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72ABD0A11083D792008C721C /* Build configuration list for PBXAggregateTarget "All-EmbeddedOther" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72ABD0821083D743008C721C /* Debug */,
+ 72ABD0831083D743008C721C /* Release */,
+ 72ABD0841083D743008C721C /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72B732E31899B0380060E6D4 /* Build configuration list for PBXNativeTarget "cfilutil" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72B732E01899B0380060E6D4 /* Debug */,
+ 72B732E11899B0380060E6D4 /* Release */,
+ 72B732E21899B0380060E6D4 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 72C77D671484199C002D2577 /* Build configuration list for PBXAggregateTarget "network_cmds_libs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 72C77D681484199C002D2577 /* Debug */,
+ 72C77D691484199C002D2577 /* Release */,
+ 72C77D6A1484199C002D2577 /* Ignore Me */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 724862310EE86EB7001D0DE9 /* Project object */;
+}
diff --git a/network_cmds/ping.tproj/ping.8 b/network_cmds/ping.tproj/ping.8
new file mode 100644
index 0000000..a2955a6
--- /dev/null
+++ b/network_cmds/ping.tproj/ping.8
@@ -0,0 +1,616 @@
+.\" Copyright (c) 1999-2013 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ping.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd March 29, 2013
+.Dt PING 8
+.Os
+.Sh NAME
+.Nm ping
+.Nd send
+.Tn ICMP ECHO_REQUEST
+packets to network hosts
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaCDdfnoQqRrv
+.Op Fl b Ar boundif
+.Op Fl c Ar count
+.Op Fl G Ar sweepmaxsize
+.Op Fl g Ar sweepminsize
+.Op Fl h Ar sweepincrsize
+.Op Fl i Ar wait
+.Op Fl k Ar trafficclass
+.Op Fl K Ar netservicetype
+.Op Fl l Ar preload
+.Op Fl M Cm mask | time
+.Op Fl m Ar ttl
+.Op Fl P Ar policy
+.Op Fl p Ar pattern
+.Op Fl S Ar src_addr
+.Op Fl s Ar packetsize
+.Op Fl t Ar timeout
+.Op Fl W Ar waittime
+.Op Fl z Ar tos
+.Op Fl Fl apple-connect
+.Op Fl Fl apple-time
+.Ar host
+.Nm
+.Op Fl AaDdfLnoQqRrv
+.Op Fl b Ar boundif
+.Op Fl c Ar count
+.Op Fl I Ar iface
+.Op Fl i Ar wait
+.Op Fl k Ar trafficclass
+.Op Fl K Ar netservicetype
+.Op Fl l Ar preload
+.Op Fl M Cm mask | time
+.Op Fl m Ar ttl
+.Op Fl P Ar policy
+.Op Fl p Ar pattern
+.Op Fl S Ar src_addr
+.Op Fl s Ar packetsize
+.Op Fl T Ar ttl
+.Op Fl t Ar timeout
+.Op Fl W Ar waittime
+.Op Fl z Ar tos
+.Op Fl Fl apple-connect
+.Op Fl Fl apple-time
+.Ar mcast-group
+.Sh DESCRIPTION
+The
+.Nm
+utility uses the
+.Tn ICMP
+.No protocol Ap s mandatory
+.Tn ECHO_REQUEST
+datagram to elicit an
+.Tn ICMP ECHO_RESPONSE
+from a host or gateway.
+.Tn ECHO_REQUEST
+datagrams
+.Pq Dq pings
+have an IP and
+.Tn ICMP
+header, followed by a
+.Dq struct timeval
+and then an arbitrary number of
+.Dq pad
+bytes used to fill out the packet.
+The options are as follows:
+.Bl -tag -width indent
+.It Fl A
+Audible.
+Output a bell
+.Tn ( ASCII
+0x07)
+character when no packet is received before the next packet
+is transmitted.
+To cater for round-trip times that are longer than the interval
+between transmissions, further missing packets cause a bell only
+if the maximum number of unreceived packets has increased.
+.It Fl a
+Audible.
+Include a bell
+.Tn ( ASCII
+0x07)
+character in the output when any packet is received.
+This option is ignored
+if other format options are present.
+.It Fl b Ar boundif
+Bind the socket to interface
+.Ar boundif
+for sending.
+This option is an Apple addition.
+.It Fl C
+Prohibit the socket from using the cellular network interface.
+This option is an Apple addition.
+.It Fl c Ar count
+Stop after sending
+(and receiving)
+.Ar count
+.Tn ECHO_RESPONSE
+packets.
+If this option is not specified,
+.Nm
+will operate until interrupted.
+If this option is specified in conjunction with ping sweeps,
+each sweep will consist of
+.Ar count
+packets.
+.It Fl D
+Set the Don't Fragment bit.
+.It Fl d
+Set the
+.Dv SO_DEBUG
+option on the socket being used.
+.It Fl f
+Flood ping.
+Outputs packets as fast as they come back or one hundred times per second,
+whichever is more.
+For every
+.Tn ECHO_REQUEST
+sent a period
+.Dq .\&
+is printed, while for every
+.Tn ECHO_REPLY
+received a backspace is printed.
+This provides a rapid display of how many packets are being dropped.
+Only the super-user may use this option.
+.Bf -emphasis
+This can be very hard on a network and should be used with caution.
+.Ef
+.It Fl G Ar sweepmaxsize
+Specify the maximum size of
+.Tn ICMP
+payload when sending sweeping pings.
+This option is required for ping sweeps.
+.It Fl g Ar sweepminsize
+Specify the size of
+.Tn ICMP
+payload to start with when sending sweeping pings.
+The default value is 0.
+.It Fl h Ar sweepincrsize
+Specify the number of bytes to increment the size of
+.Tn ICMP
+payload after
+each sweep when sending sweeping pings.
+The default value is 1.
+.It Fl I Ar iface
+Source multicast packets with the given interface address.
+This flag only applies if the ping destination is a multicast address.
+.It Fl i Ar wait
+Wait
+.Ar wait
+seconds
+.Em between sending each packet .
+The default is to wait for one second between each packet.
+The wait time may be fractional, but only the super-user may specify
+values less than 0.1 second.
+This option is incompatible with the
+.Fl f
+option.
+.It Fl k Ar trafficclass
+Specifies the traffic class to use for sending ICMP packets.
+The supported traffic classes are
+BK_SYS, BK, BE, RD, OAM, AV, RV, VI, VO and CTL.
+By default
+.Nm
+uses the control traffic class (CTL).
+This option is an Apple addition.
+.It Fl K Ar netservicetype
+Specifies the network service type to use for sending ICMP packets.
+The supported network service type are BK_SYS, BK, BE, RV, AV, RD, OAM, VI, SIG and VO.
+Note this overrides the default traffic class (-k can still be specified after -K to use both).
+This option is an Apple addition.
+.It Fl L
+Suppress loopback of multicast packets.
+This flag only applies if the ping destination is a multicast address.
+.It Fl l Ar preload
+If
+.Ar preload
+is specified,
+.Nm
+sends that many packets as fast as possible before falling into its normal
+mode of behavior.
+Only the super-user may use this option.
+.It Fl M Cm mask | time
+Use
+.Dv ICMP_MASKREQ
+or
+.Dv ICMP_TSTAMP
+instead of
+.Dv ICMP_ECHO .
+For
+.Cm mask ,
+print the netmask of the remote machine.
+Set the
+.Va net.inet.icmp.maskrepl
+MIB variable to enable
+.Dv ICMP_MASKREPLY .
+For
+.Cm time ,
+print the origination, reception and transmission timestamps.
+.It Fl m Ar ttl
+Set the IP Time To Live for outgoing packets.
+If not specified, the kernel uses the value of the
+.Va net.inet.ip.ttl
+MIB variable.
+.It Fl n
+Numeric output only.
+No attempt will be made to lookup symbolic names for host addresses.
+.It Fl o
+Exit successfully after receiving one reply packet.
+.It Fl P Ar policy
+.Ar policy
+specifies IPsec policy for the ping session.
+For details please refer to
+.Xr ipsec 4
+and
+.Xr ipsec_set_policy 3 .
+.It Fl p Ar pattern
+You may specify up to 16
+.Dq pad
+bytes to fill out the packet you send.
+This is useful for diagnosing data-dependent problems in a network.
+For example,
+.Dq Li \-p ff
+will cause the sent packet to be filled with all
+ones.
+.It Fl Q
+Somewhat quiet output.
+.No Don Ap t
+display ICMP error messages that are in response to our query messages.
+Originally, the
+.Fl v
+flag was required to display such errors, but
+.Fl v
+displays all ICMP error messages.
+On a busy machine, this output can be overbearing.
+Without the
+.Fl Q
+flag,
+.Nm
+prints out any ICMP error messages caused by its own ECHO_REQUEST
+messages.
+.It Fl q
+Quiet output.
+Nothing is displayed except the summary lines at startup time and
+when finished.
+.It Fl R
+Record route.
+Includes the
+.Tn RECORD_ROUTE
+option in the
+.Tn ECHO_REQUEST
+packet and displays
+the route buffer on returned packets.
+Note that the IP header is only large enough for nine such routes;
+the
+.Xr traceroute 8
+command is usually better at determining the route packets take to a
+particular destination.
+If more routes come back than should, such as due to an illegal spoofed
+packet, ping will print the route list and then truncate it at the correct
+spot.
+Many hosts ignore or discard the
+.Tn RECORD_ROUTE
+option.
+.It Fl r
+Bypass the normal routing tables and send directly to a host on an attached
+network.
+If the host is not on a directly-attached network, an error is returned.
+This option can be used to ping a local host through an interface
+that has no route through it
+(e.g., after the interface was dropped by
+.Xr routed 8 ) .
+.It Fl S Ar src_addr
+Use the following IP address as the source address in outgoing packets.
+On hosts with more than one IP address, this option can be used to
+force the source address to be something other than the IP address
+of the interface the probe packet is sent on.
+If the IP address
+is not one of this machine's interface addresses, an error is
+returned and nothing is sent.
+.It Fl s Ar packetsize
+Specify the number of data bytes to be sent.
+The default is 56, which translates into 64
+.Tn ICMP
+data bytes when combined
+with the 8 bytes of
+.Tn ICMP
+header data.
+This option cannot be used with ping sweeps.
+.It Fl T Ar ttl
+Set the IP Time To Live for multicasted packets.
+This flag only applies if the ping destination is a multicast address.
+.It Fl t Ar timeout
+Specify a timeout, in seconds, before ping exits regardless of how
+many packets have been received.
+.It Fl v
+Verbose output.
+.Tn ICMP
+packets other than
+.Tn ECHO_RESPONSE
+that are received are listed.
+.It Fl W Ar waittime
+Time in milliseconds to wait for a reply for each packet sent.
+If a reply arrives later, the packet is not printed as replied, but
+considered as replied when calculating statistics.
+.It Fl z Ar tos
+Use the specified type of service.
+.It Fl Fl apple-connect
+Connects the socket to the destination address.
+This option is an Apple addition.
+.It Fl Fl apple-time
+Prints the time a packet was received.
+This option is an Apple addition.
+.El
+.Pp
+When using
+.Nm
+for fault isolation, it should first be run on the local host, to verify
+that the local network interface is up and running.
+Then, hosts and gateways further and further away should be
+.Dq pinged .
+Round-trip times and packet loss statistics are computed.
+If duplicate packets are received, they are not included in the packet
+loss calculation, although the round trip time of these packets is used
+in calculating the round-trip time statistics.
+When the specified number of packets have been sent
+(and received)
+or if the program is terminated with a
+.Dv SIGINT ,
+a brief summary is displayed, showing the number of packets sent and
+received, and the minimum, mean, maximum, and standard deviation of
+the round-trip times.
+.Pp
+If
+.Nm
+receives a
+.Dv SIGINFO
+(see the
+.Cm status
+argument for
+.Xr stty 1 )
+signal, the current number of packets sent and received, and the
+minimum, mean, and maximum of the round-trip times will be written to
+the standard error output.
+.Pp
+This program is intended for use in network testing, measurement and
+management.
+Because of the load it can impose on the network, it is unwise to use
+.Nm
+during normal operations or from automated scripts.
+.Sh ICMP PACKET DETAILS
+An IP header without options is 20 bytes.
+An
+.Tn ICMP
+.Tn ECHO_REQUEST
+packet contains an additional 8 bytes worth of
+.Tn ICMP
+header followed by an arbitrary amount of data.
+When a
+.Ar packetsize
+is given, this indicated the size of this extra piece of data
+(the default is 56).
+Thus the amount of data received inside of an IP packet of type
+.Tn ICMP
+.Tn ECHO_REPLY
+will always be 8 bytes more than the requested data space
+(the
+.Tn ICMP
+header).
+.Pp
+If the data space is at least eight bytes large,
+.Nm
+uses the first eight bytes of this space to include a timestamp which
+it uses in the computation of round trip times.
+If less than eight bytes of pad are specified, no round trip times are
+given.
+.Sh DUPLICATE AND DAMAGED PACKETS
+The
+.Nm
+utility will report duplicate and damaged packets.
+Duplicate packets should never occur when pinging a unicast address,
+and seem to be caused by
+inappropriate link-level retransmissions.
+Duplicates may occur in many situations and are rarely
+(if ever)
+a good sign, although the presence of low levels of duplicates may not
+always be cause for alarm.
+Duplicates are expected when pinging a broadcast or multicast address,
+since they are not really duplicates but replies from different hosts
+to the same request.
+.Pp
+Damaged packets are obviously serious cause for alarm and often
+indicate broken hardware somewhere in the
+.Nm
+packet's path (in the network or in the hosts).
+.Sh TRYING DIFFERENT DATA PATTERNS
+The
+(inter)network
+layer should never treat packets differently depending on the data
+contained in the data portion.
+Unfortunately, data-dependent problems have been known to sneak into
+networks and remain undetected for long periods of time.
+In many cases the particular pattern that will have problems is something
+that does not have sufficient
+.Dq transitions ,
+such as all ones or all zeros, or a pattern right at the edge, such as
+almost all zeros.
+It is not
+necessarily enough to specify a data pattern of all zeros (for example)
+on the command line because the pattern that is of interest is
+at the data link level, and the relationship between what you type and
+what the controllers transmit can be complicated.
+.Pp
+This means that if you have a data-dependent problem you will probably
+have to do a lot of testing to find it.
+If you are lucky, you may manage to find a file that either
+cannot
+be sent across your network or that takes much longer to transfer than
+other similar length files.
+You can then examine this file for repeated patterns that you can test
+using the
+.Fl p
+option of
+.Nm .
+.Sh TTL DETAILS
+The
+.Tn TTL
+value of an IP packet represents the maximum number of IP routers
+that the packet can go through before being thrown away.
+In current practice you can expect each router in the Internet to decrement
+the
+.Tn TTL
+field by exactly one.
+.Pp
+The
+.Tn TCP/IP
+specification recommends setting the
+.Tn TTL
+field for
+.Tn IP
+packets to 64, but many systems use smaller values
+.No ( Bx 4.3
+uses 30,
+.Bx 4.2
+used 15).
+.Pp
+The maximum possible value of this field is 255, and most
+.Ux
+systems set
+the
+.Tn TTL
+field of
+.Tn ICMP ECHO_REQUEST
+packets to 255.
+This is why you will find you can
+.Dq ping
+some hosts, but not reach them with
+.Xr telnet 1
+or
+.Xr ftp 1 .
+.Pp
+In normal operation
+.Nm
+prints the ttl value from the packet it receives.
+When a remote system receives a ping packet, it can do one of three things
+with the
+.Tn TTL
+field in its response:
+.Bl -bullet
+.It
+Not change it; this is what
+.Bx
+systems did before the
+.Bx 4.3 tahoe
+release.
+In this case the
+.Tn TTL
+value in the received packet will be 255 minus the
+number of routers in the round-trip path.
+.It
+Set it to 255; this is what current
+.Bx
+systems do.
+In this case the
+.Tn TTL
+value in the received packet will be 255 minus the
+number of routers in the path
+.Em from
+the remote system
+.Em to
+the
+.Nm Ns Em ing
+host.
+.It
+Set it to some other value.
+Some machines use the same value for
+.Tn ICMP
+packets that they use for
+.Tn TCP
+packets, for example either 30 or 60.
+Others may use completely wild values.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width indent
+.It 0
+At least one response was heard from the specified
+.Ar host .
+.It 2
+The transmission was successful but no responses were received.
+.It any other value
+An error occurred.
+These values are defined in
+.In sysexits.h .
+.El
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ifconfig 8 ,
+.Xr routed 8 ,
+.Xr traceroute 8 ,
+.Xr ping6 8
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 .
+.Sh AUTHORS
+The original
+.Nm
+utility was written by
+.An Mike Muuss
+while at the US Army Ballistics
+Research Laboratory.
+.Sh BUGS
+Many Hosts and Gateways ignore the
+.Tn RECORD_ROUTE
+option.
+.Pp
+The maximum IP header length is too small for options like
+.Tn RECORD_ROUTE
+to be completely useful.
+.No There Ap s
+not much that can be done about this, however.
+.Pp
+Flood pinging is not recommended in general, and flood pinging the
+broadcast address should only be done under very controlled conditions.
+.Pp
+The
+.Fl v
+option is not worth much on busy hosts.
diff --git a/network_cmds/ping.tproj/ping.c b/network_cmds/ping.tproj/ping.c
new file mode 100644
index 0000000..58e7f80
--- /dev/null
+++ b/network_cmds/ping.tproj/ping.c
@@ -0,0 +1,2134 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * P I N G . C
+ *
+ * Using the Internet Control Message Protocol (ICMP) "ECHO" facility,
+ * measure round-trip-delays and packet loss across network paths.
+ *
+ * Author -
+ * Mike Muuss
+ * U. S. Army Ballistic Research Laboratory
+ * December, 1983
+ *
+ * Status -
+ * Public Domain. Distribution Unlimited.
+ * Bugs -
+ * More statistics could always be gathered.
+ * This program has to run SUID to ROOT to access the ICMP socket.
+ */
+
+#include <sys/param.h> /* NB: we rely on this for <sys/types.h> */
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/ip_var.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#ifdef IPSEC
+#include <netinet6/ipsec.h>
+#endif /*IPSEC*/
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <math.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+#include <getopt.h>
+
+#define INADDR_LEN ((int)sizeof(in_addr_t))
+#define TIMEVAL_LEN ((int)sizeof(struct tv32))
+#define MASK_LEN (ICMP_MASKLEN - ICMP_MINLEN)
+#define TS_LEN (ICMP_TSLEN - ICMP_MINLEN)
+#define DEFDATALEN 56 /* default data length */
+#define FLOOD_BACKOFF 20000 /* usecs to back off if F_FLOOD mode */
+ /* runs out of buffer space */
+#define MAXIPLEN (sizeof(struct ip) + MAX_IPOPTLEN)
+#define MAXICMPLEN (ICMP_ADVLENMIN + MAX_IPOPTLEN)
+#define MAXWAIT 10000 /* max ms to wait for response */
+#define MAXALARM (60 * 60) /* max seconds for alarm timeout */
+#define MAXTOS 255
+
+#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
+#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
+#define SET(bit) (A(bit) |= B(bit))
+#define CLR(bit) (A(bit) &= (~B(bit)))
+#define TST(bit) (A(bit) & B(bit))
+
+struct tv32 {
+ u_int32_t tv32_sec;
+ u_int32_t tv32_usec;
+};
+
+/* various options */
+int options;
+#define F_FLOOD 0x0001
+#define F_INTERVAL 0x0002
+#define F_NUMERIC 0x0004
+#define F_PINGFILLED 0x0008
+#define F_QUIET 0x0010
+#define F_RROUTE 0x0020
+#define F_SO_DEBUG 0x0040
+#define F_SO_DONTROUTE 0x0080
+#define F_VERBOSE 0x0100
+#define F_QUIET2 0x0200
+#define F_NOLOOP 0x0400
+#define F_MTTL 0x0800
+#define F_MIF 0x1000
+#define F_AUDIBLE 0x2000
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+#define F_POLICY 0x4000
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+#define F_TTL 0x8000
+#define F_MISSED 0x10000
+#define F_ONCE 0x20000
+#define F_HDRINCL 0x40000
+#define F_MASK 0x80000
+#define F_TIME 0x100000
+#define F_SWEEP 0x200000
+#define F_WAITTIME 0x400000
+#define F_CONNECT 0x800000
+#define F_PRTIME 0x1000000
+
+/*
+ * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
+ * number of received sequence numbers we can keep track of. Change 128
+ * to 8192 for complete accuracy...
+ */
+#define MAX_DUP_CHK (8 * 128)
+int mx_dup_ck = MAX_DUP_CHK;
+char rcvd_tbl[MAX_DUP_CHK / 8];
+
+struct sockaddr_in whereto; /* who to ping */
+int datalen = DEFDATALEN;
+int maxpayload;
+int s; /* socket file descriptor */
+u_char outpackhdr[IP_MAXPACKET], *outpack;
+char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */
+char BSPACE = '\b'; /* characters written for flood */
+char DOT = '.';
+char *hostname;
+char *shostname;
+int ident; /* process id to identify our packets */
+int uid; /* cached uid for micro-optimization */
+u_char icmp_type = ICMP_ECHO;
+u_char icmp_type_rsp = ICMP_ECHOREPLY;
+int phdr_len = 0;
+int send_len;
+char *boundif;
+unsigned int ifscope;
+int nocell;
+int use_sendmsg = 0;
+int use_recvmsg = 0;
+int traffic_class = SO_TC_CTL; /* use control class, by default */
+int net_service_type = -1;
+int no_dup = 0;
+
+/* counters */
+long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
+long npackets; /* max packets to transmit */
+long nreceived; /* # of packets we got back */
+long nrepeats; /* number of duplicates */
+long ntransmitted; /* sequence # for outbound packets = #sent */
+long snpackets; /* max packets to transmit in one sweep */
+long snreceived; /* # of packets we got back in this sweep */
+long sntransmitted; /* # of packets we sent in this sweep */
+int sweepmax; /* max value of payload in sweep */
+int sweepmin = 0; /* start value of payload in sweep */
+int sweepincr = 1; /* payload increment in sweep */
+int interval = 1000; /* interval between packets, ms */
+int waittime = MAXWAIT; /* timeout for each packet */
+long nrcvtimeout = 0; /* # of packets we got back after waittime */
+int icmp_len = 0; /* length of the ICMP header */
+
+/* timing */
+int timing; /* flag to do timing */
+double tmin = 999999999.0; /* minimum round trip time */
+double tmax = 0.0; /* maximum round trip time */
+double tsum = 0.0; /* sum of all times, for doing average */
+double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
+
+volatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */
+volatile sig_atomic_t siginfo_p;
+
+static void fill(char *, char *);
+static u_short in_cksum(u_short *, int);
+static void check_status(void);
+static void finish(void) __dead2;
+static void pinger(void);
+static char *pr_addr(struct in_addr);
+static char *pr_ntime(n_time);
+static void pr_icmph(struct icmp *);
+static void pr_iph(struct ip *);
+static void pr_pack(char *, int, struct sockaddr_in *, struct timeval *, int);
+static void pr_retip(struct ip *);
+static void status(int);
+static void stopit(int);
+static void tvsub(struct timeval *, const struct timeval *);
+static int str2sotc(const char *, bool *);
+static int str2netservicetype(const char *, bool *);
+static u_int8_t str2tos(const char *, bool *);
+static void usage(void) __dead2;
+
+int32_t thiszone; /* seconds offset from gmt to local time */
+extern int32_t gmt2local(time_t);
+static void pr_currenttime(void);
+
+static int longopt_flag = 0;
+
+#define LOF_CONNECT 0x01
+#define LOF_PRTIME 0x02
+
+static const struct option longopts[] = {
+ { "apple-connect", no_argument, &longopt_flag, LOF_CONNECT },
+ { "apple-time", no_argument, &longopt_flag, LOF_PRTIME },
+ { NULL, 0, NULL, 0 }
+};
+
+int
+main(int argc, char *const *argv)
+{
+ struct sockaddr_in from, sock_in;
+ struct in_addr ifaddr;
+ struct timeval last, intvl;
+ struct iovec iov;
+ struct ip *ip;
+ struct msghdr msg;
+ struct sigaction si_sa;
+ size_t sz;
+ u_char *datap, packet[IP_MAXPACKET] __attribute__((aligned(4)));
+ char *ep, *source, *target, *payload;
+ struct hostent *hp;
+#ifdef IPSEC_POLICY_IPSEC
+ char *policy_in, *policy_out;
+#endif
+ struct sockaddr_in *to;
+ double t;
+ u_long alarmtimeout, ultmp;
+ int almost_done, ch, df, hold, i, mib[4], preload, sockerrno,
+ tos, ttl;
+ char ctrl[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(int))];
+ char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
+#ifdef IP_OPTIONS
+ char rspace[MAX_IPOPTLEN]; /* record route space */
+#endif
+ unsigned char loop, mttl;
+
+ payload = source = NULL;
+#ifdef IPSEC_POLICY_IPSEC
+ policy_in = policy_out = NULL;
+#endif
+ bool valid;
+
+ /*
+ * Do the stuff that we need root priv's for *first*, and
+ * then drop our setuid bit. Save error reporting for
+ * after arg parsing.
+ */
+ if (getuid())
+ s = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
+ else
+ s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ sockerrno = errno;
+
+ if (setuid(getuid()) != 0)
+ err(EX_NOPERM, "setuid() failed");
+ uid = getuid();
+
+ alarmtimeout = df = preload = tos = 0;
+
+ outpack = outpackhdr + sizeof(struct ip);
+ while ((ch = getopt_long(argc, argv,
+ "AaB:b:Cc:DdfG:g:h:I:i:k:K:Ll:M:m:noP:p:QqRrS:s:T:t:vW:z:",
+ longopts, NULL)) != -1)
+ {
+ switch(ch) {
+ case 'A':
+ options |= F_MISSED;
+ break;
+ case 'a':
+ options |= F_AUDIBLE;
+ break;
+ case 'B':
+ case 'b':
+ boundif = optarg;
+ break;
+ case 'C':
+ nocell++;
+ break;
+ case 'c':
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > LONG_MAX || !ultmp)
+ errx(EX_USAGE,
+ "invalid count of packets to transmit: `%s'",
+ optarg);
+ npackets = ultmp;
+ break;
+ case 'D':
+ options |= F_HDRINCL;
+ df = 1;
+ break;
+ case 'd':
+ options |= F_SO_DEBUG;
+ break;
+ case 'f':
+ if (uid) {
+ errno = EPERM;
+ err(EX_NOPERM, "-f flag");
+ }
+ options |= F_FLOOD;
+ setbuf(stdout, (char *)NULL);
+ break;
+ case 'G': /* Maximum packet size for ping sweep */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "invalid packet size: `%s'",
+ optarg);
+#ifndef __APPLE__
+ if (uid != 0 && ultmp > DEFDATALEN) {
+ errno = EPERM;
+ err(EX_NOPERM,
+ "packet size too large: %lu > %u",
+ ultmp, DEFDATALEN);
+ }
+#endif /* __APPLE__ */
+ options |= F_SWEEP;
+ sweepmax = ultmp;
+ break;
+ case 'g': /* Minimum packet size for ping sweep */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "invalid packet size: `%s'",
+ optarg);
+#ifndef __APPLE__
+ if (uid != 0 && ultmp > DEFDATALEN) {
+ errno = EPERM;
+ err(EX_NOPERM,
+ "packet size too large: %lu > %u",
+ ultmp, DEFDATALEN);
+ }
+#endif /* __APPLE__ */
+ options |= F_SWEEP;
+ sweepmin = ultmp;
+ break;
+ case 'h': /* Packet size increment for ping sweep */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp < 1)
+ errx(EX_USAGE, "invalid increment size: `%s'",
+ optarg);
+#ifndef __APPLE__
+ if (uid != 0 && ultmp > DEFDATALEN) {
+ errno = EPERM;
+ err(EX_NOPERM,
+ "packet size too large: %lu > %u",
+ ultmp, DEFDATALEN);
+ }
+#endif /* __APPLE__ */
+ options |= F_SWEEP;
+ sweepincr = ultmp;
+ break;
+ case 'I': /* multicast interface */
+ if (inet_aton(optarg, &ifaddr) == 0)
+ errx(EX_USAGE,
+ "invalid multicast interface: `%s'",
+ optarg);
+ options |= F_MIF;
+ break;
+ case 'i': /* wait between sending packets */
+ t = strtod(optarg, &ep) * 1000.0;
+ if (*ep || ep == optarg || t > (double)INT_MAX)
+ errx(EX_USAGE, "invalid timing interval: `%s'",
+ optarg);
+ options |= F_INTERVAL;
+ interval = (int)t;
+ if (uid && interval < 100) {
+ errno = EPERM;
+ err(EX_NOPERM, "-i interval too short");
+ }
+ break;
+ case 'k':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ if (strcasecmp(optarg, "recvmsg") == 0) {
+ use_recvmsg++;
+ break;
+ }
+ traffic_class = str2sotc(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad traffic class: `%s'",
+ optarg);
+ break;
+ case 'K':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ net_service_type = str2netservicetype(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad network service type: `%s'",
+ optarg);
+ /* suppress default traffic class (-k can still be specified after -K) */
+ traffic_class = -1;
+ break;
+ case 'L':
+ options |= F_NOLOOP;
+ loop = 0;
+ break;
+ case 'l':
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > INT_MAX)
+ errx(EX_USAGE,
+ "invalid preload value: `%s'", optarg);
+ if (uid) {
+ errno = EPERM;
+ err(EX_NOPERM, "-l flag");
+ }
+ preload = ultmp;
+ break;
+ case 'M':
+ switch(optarg[0]) {
+ case 'M':
+ case 'm':
+ options |= F_MASK;
+ break;
+ case 'T':
+ case 't':
+ options |= F_TIME;
+ break;
+ default:
+ errx(EX_USAGE, "invalid message: `%c'", optarg[0]);
+ break;
+ }
+ break;
+ case 'm': /* TTL */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > MAXTTL)
+ errx(EX_USAGE, "invalid TTL: `%s'", optarg);
+ ttl = ultmp;
+ options |= F_TTL;
+ break;
+ case 'n':
+ options |= F_NUMERIC;
+ break;
+ case 'o':
+ options |= F_ONCE;
+ break;
+ case 'P':
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ options |= F_POLICY;
+ if (!strncmp("in", optarg, 2))
+ policy_in = strdup(optarg);
+ else if (!strncmp("out", optarg, 3))
+ policy_out = strdup(optarg);
+ else
+ errx(1, "invalid security policy");
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+ break;
+ case 'p': /* fill buffer with user pattern */
+ options |= F_PINGFILLED;
+ payload = optarg;
+ break;
+ case 'Q':
+ options |= F_QUIET2;
+ break;
+ case 'q':
+ options |= F_QUIET;
+ break;
+ case 'R':
+ options |= F_RROUTE;
+ break;
+ case 'r':
+ options |= F_SO_DONTROUTE;
+ break;
+ case 'S':
+ source = optarg;
+ break;
+ case 's': /* size of packet to send */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "invalid packet size: `%s'",
+ optarg);
+#ifndef __APPLE__
+ if (uid != 0 && ultmp > DEFDATALEN) {
+ errno = EPERM;
+ err(EX_NOPERM,
+ "packet size too large: %lu > %u",
+ ultmp, DEFDATALEN);
+ }
+#endif /* __APPLE__ */
+ datalen = ultmp;
+ break;
+ case 'T': /* multicast TTL */
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > MAXTTL)
+ errx(EX_USAGE, "invalid multicast TTL: `%s'",
+ optarg);
+ mttl = ultmp;
+ options |= F_MTTL;
+ break;
+ case 't':
+ alarmtimeout = strtoul(optarg, &ep, 0);
+ if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX))
+ errx(EX_USAGE, "invalid timeout: `%s'",
+ optarg);
+ if (alarmtimeout > MAXALARM)
+ errx(EX_USAGE, "invalid timeout: `%s' > %d",
+ optarg, MAXALARM);
+ alarm((unsigned int)alarmtimeout);
+ break;
+ case 'v':
+ options |= F_VERBOSE;
+ break;
+ case 'W': /* wait ms for answer */
+ t = strtod(optarg, &ep);
+ if (*ep || ep == optarg || t > (double)INT_MAX)
+ errx(EX_USAGE, "invalid timing interval: `%s'",
+ optarg);
+ options |= F_WAITTIME;
+ waittime = (int)t;
+ break;
+ case 'z':
+ options |= F_HDRINCL;
+ tos = str2tos(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "invalid TOS: `%s'", optarg);
+ break;
+ case 0:
+ switch (longopt_flag) {
+ case LOF_CONNECT:
+ options |= F_CONNECT;
+ break;
+ case LOF_PRTIME:
+ options |= F_PRTIME;
+ thiszone = gmt2local(0);
+ break;
+ default:
+ break;
+ }
+ longopt_flag = 0;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (boundif != NULL && (ifscope = if_nametoindex(boundif)) == 0)
+ errx(1, "bad interface name");
+
+ if (argc - optind != 1)
+ usage();
+ target = argv[optind];
+
+ switch (options & (F_MASK|F_TIME)) {
+ case 0: break;
+ case F_MASK:
+ icmp_type = ICMP_MASKREQ;
+ icmp_type_rsp = ICMP_MASKREPLY;
+ phdr_len = MASK_LEN;
+ if (!(options & F_QUIET))
+ (void)printf("ICMP_MASKREQ\n");
+ break;
+ case F_TIME:
+ icmp_type = ICMP_TSTAMP;
+ icmp_type_rsp = ICMP_TSTAMPREPLY;
+ phdr_len = TS_LEN;
+ if (!(options & F_QUIET))
+ (void)printf("ICMP_TSTAMP\n");
+ break;
+ default:
+ errx(EX_USAGE, "ICMP_TSTAMP and ICMP_MASKREQ are exclusive.");
+ break;
+ }
+ icmp_len = sizeof(struct ip) + ICMP_MINLEN + phdr_len;
+ if (options & F_RROUTE)
+ icmp_len += MAX_IPOPTLEN;
+ maxpayload = IP_MAXPACKET - icmp_len;
+ if (datalen > maxpayload)
+ errx(EX_USAGE, "packet size too large: %d > %d", datalen,
+ maxpayload);
+ send_len = icmp_len + datalen;
+ datap = &outpack[ICMP_MINLEN + phdr_len + TIMEVAL_LEN];
+ if (options & F_PINGFILLED) {
+ fill((char *)datap, payload);
+ }
+ if (source) {
+ bzero((char *)&sock_in, sizeof(sock_in));
+ sock_in.sin_family = AF_INET;
+ if (inet_aton(source, &sock_in.sin_addr) != 0) {
+ shostname = source;
+ } else {
+ hp = gethostbyname2(source, AF_INET);
+ if (!hp)
+ errx(EX_NOHOST, "cannot resolve %s: %s",
+ source, hstrerror(h_errno));
+
+ sock_in.sin_len = sizeof sock_in;
+ if ((unsigned)hp->h_length > sizeof(sock_in.sin_addr) ||
+ hp->h_length < 0)
+ errx(1, "gethostbyname2: illegal address");
+ memcpy(&sock_in.sin_addr, hp->h_addr_list[0],
+ sizeof(sock_in.sin_addr));
+ (void)strlcpy(snamebuf, hp->h_name,
+ sizeof(snamebuf));
+ shostname = snamebuf;
+ }
+ if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1)
+#if (DEBUG || DEVELOPMENT)
+ options |= F_HDRINCL;
+#else
+ err(1, "bind");
+#endif /* DEBUG || DEVELOPMENT */
+ }
+
+ bzero(&whereto, sizeof(whereto));
+ to = &whereto;
+ to->sin_family = AF_INET;
+ to->sin_len = sizeof *to;
+ if (inet_aton(target, &to->sin_addr) != 0) {
+ hostname = target;
+ } else {
+ hp = gethostbyname2(target, AF_INET);
+ if (!hp)
+ errx(EX_NOHOST, "cannot resolve %s: %s",
+ target, hstrerror(h_errno));
+
+ if ((unsigned)hp->h_length > sizeof(to->sin_addr))
+ errx(1, "gethostbyname2 returned an illegal address");
+ memcpy(&to->sin_addr, hp->h_addr_list[0], sizeof to->sin_addr);
+ (void)strlcpy(hnamebuf, hp->h_name, sizeof(hnamebuf));
+ hostname = hnamebuf;
+ }
+
+ do {
+ struct ifaddrs *ifa_list, *ifa;
+
+ if (IN_MULTICAST(ntohl(whereto.sin_addr.s_addr)) || whereto.sin_addr.s_addr == INADDR_BROADCAST) {
+ no_dup = 1;
+ break;
+ }
+
+ if (getifaddrs(&ifa_list) == -1)
+ break;
+ for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_INET)
+ continue;
+ if ((ifa->ifa_flags & IFF_BROADCAST) == 0 || ifa->ifa_broadaddr == NULL)
+ continue;
+ if (whereto.sin_addr.s_addr != ((struct sockaddr_in*)ifa->ifa_broadaddr)->sin_addr.s_addr)
+ continue;
+ no_dup = 1;
+ break;
+ }
+
+ freeifaddrs(ifa_list);
+ } while (0);
+
+ if (options & F_FLOOD && options & F_INTERVAL)
+ errx(EX_USAGE, "-f and -i: incompatible options");
+
+ if (options & F_FLOOD && IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
+ errx(EX_USAGE,
+ "-f flag cannot be used with multicast destination");
+ if (options & (F_MIF | F_NOLOOP | F_MTTL)
+ && !IN_MULTICAST(ntohl(to->sin_addr.s_addr)))
+ errx(EX_USAGE,
+ "-I, -L, -T flags cannot be used with unicast destination");
+
+ if (!(options & F_PINGFILLED))
+ for (i = TIMEVAL_LEN; i < MAX(datalen, sweepmax); ++i)
+ *datap++ = i;
+
+ ident = getpid() & 0xFFFF;
+
+ if (s < 0) {
+ errno = sockerrno;
+ err(EX_OSERR, "socket");
+ }
+ hold = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&hold,
+ sizeof(hold));
+ if (ifscope != 0) {
+ if (setsockopt(s, IPPROTO_IP, IP_BOUND_IF,
+ (char *)&ifscope, sizeof (ifscope)) != 0)
+ err(EX_OSERR, "setsockopt(IP_BOUND_IF)");
+ }
+ if (nocell) {
+ if (setsockopt(s, IPPROTO_IP, IP_NO_IFT_CELLULAR,
+ (char *)&nocell, sizeof (nocell)) != 0)
+ err(EX_OSERR, "setsockopt(IP_NO_IFT_CELLULAR)");
+ }
+ if (options & F_SO_DEBUG)
+ (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
+ sizeof(hold));
+ if (options & F_SO_DONTROUTE)
+ (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
+ sizeof(hold));
+ if (use_sendmsg == 0) {
+ if (net_service_type != -1)
+ if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE,
+ (void *)&net_service_type, sizeof (net_service_type)) != 0)
+ warn("setsockopt(SO_NET_SERVICE_TYPE");
+ if (traffic_class != -1) {
+ if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
+ (void *)&traffic_class, sizeof (traffic_class)) != 0)
+ warn("setsockopt(SO_TRAFFIC_CLASS");
+
+ }
+ }
+ if (use_recvmsg > 0) {
+ int on = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS,
+ (void *)&on, sizeof (on));
+ }
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ if (options & F_POLICY) {
+ char *buf;
+ if (policy_in != NULL) {
+ buf = ipsec_set_policy(policy_in, strlen(policy_in));
+ if (buf == NULL)
+ errx(EX_CONFIG, "%s", ipsec_strerror());
+ if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf)) < 0)
+ err(EX_CONFIG,
+ "ipsec policy cannot be configured");
+ free(buf);
+ }
+
+ if (policy_out != NULL) {
+ buf = ipsec_set_policy(policy_out, strlen(policy_out));
+ if (buf == NULL)
+ errx(EX_CONFIG, "%s", ipsec_strerror());
+ if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf)) < 0)
+ err(EX_CONFIG,
+ "ipsec policy cannot be configured");
+ free(buf);
+ }
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+ if (options & F_HDRINCL) {
+ ip = (struct ip*)outpackhdr;
+ if (!(options & (F_TTL | F_MTTL))) {
+ mib[0] = CTL_NET;
+ mib[1] = PF_INET;
+ mib[2] = IPPROTO_IP;
+ mib[3] = IPCTL_DEFTTL;
+ sz = sizeof(ttl);
+ if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1)
+ err(1, "sysctl(net.inet.ip.ttl)");
+ }
+ setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(struct ip) >> 2;
+ ip->ip_tos = tos;
+ ip->ip_id = 0;
+ ip->ip_off = df ? IP_DF : 0;
+ ip->ip_ttl = ttl;
+ ip->ip_p = IPPROTO_ICMP;
+ ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY;
+ ip->ip_dst = to->sin_addr;
+ }
+ /* record route option */
+ if (options & F_RROUTE) {
+#ifdef IP_OPTIONS
+ bzero(rspace, sizeof(rspace));
+ rspace[IPOPT_OPTVAL] = IPOPT_RR;
+ rspace[IPOPT_OLEN] = sizeof(rspace) - 1;
+ rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
+ rspace[sizeof(rspace) - 1] = IPOPT_EOL;
+ if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
+ sizeof(rspace)) < 0)
+ err(EX_OSERR, "setsockopt IP_OPTIONS");
+#else
+ errx(EX_UNAVAILABLE,
+ "record route not available in this implementation");
+#endif /* IP_OPTIONS */
+ }
+
+ if (options & F_TTL) {
+ if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl,
+ sizeof(ttl)) < 0) {
+ err(EX_OSERR, "setsockopt IP_TTL");
+ }
+ }
+ if (options & F_NOLOOP) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
+ sizeof(loop)) < 0) {
+ err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP");
+ }
+ }
+ if (options & F_MTTL) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl,
+ sizeof(mttl)) < 0) {
+ err(EX_OSERR, "setsockopt IP_MULTICAST_TTL");
+ }
+ }
+ if (options & F_MIF) {
+ if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
+ sizeof(ifaddr)) < 0) {
+ err(EX_OSERR, "setsockopt IP_MULTICAST_IF");
+ }
+ }
+#ifdef SO_TIMESTAMP
+ { int on = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
+ err(EX_OSERR, "setsockopt SO_TIMESTAMP");
+ }
+#endif
+
+ if ((options & F_CONNECT)) {
+ if (connect(s, (struct sockaddr *)&whereto, sizeof whereto) == -1)
+ err(EX_OSERR, "connect");
+ }
+
+ if (sweepmax) {
+ if (sweepmin >= sweepmax)
+ errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
+
+ if (datalen != DEFDATALEN)
+ errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive");
+
+ if (npackets > 0) {
+ snpackets = npackets;
+ npackets = 0;
+ } else
+ snpackets = 1;
+ datalen = sweepmin;
+ send_len = icmp_len + sweepmin;
+ }
+ if (options & F_SWEEP && !sweepmax)
+ errx(EX_USAGE, "Maximum sweep size must be specified");
+
+ /*
+ * When pinging the broadcast address, you can get a lot of answers.
+ * Doing something so evil is useful if you are trying to stress the
+ * ethernet, or just want to fill the arp cache to get some stuff for
+ * /etc/ethers. But beware: RFC 1122 allows hosts to ignore broadcast
+ * or multicast pings if they wish.
+ */
+
+ /*
+ * XXX receive buffer needs undetermined space for mbuf overhead
+ * as well.
+ */
+ hold = IP_MAXPACKET + 128;
+ (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
+ sizeof(hold));
+ if (uid == 0)
+ (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold,
+ sizeof(hold));
+
+ if (to->sin_family == AF_INET) {
+ (void)printf("PING %s (%s)", hostname,
+ inet_ntoa(to->sin_addr));
+ if (source)
+ (void)printf(" from %s", shostname);
+ if (sweepmax)
+ (void)printf(": (%d ... %d) data bytes\n",
+ sweepmin, sweepmax);
+ else
+ (void)printf(": %d data bytes\n", datalen);
+
+ } else {
+ if (sweepmax)
+ (void)printf("PING %s: (%d ... %d) data bytes\n",
+ hostname, sweepmin, sweepmax);
+ else
+ (void)printf("PING %s: %d data bytes\n", hostname, datalen);
+ }
+
+ /*
+ * rdar://25829310
+ *
+ * Clear blocked signals inherited from the parent
+ */
+ sigset_t newset;
+ sigemptyset(&newset);
+ if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0)
+ err(EX_OSERR, "sigprocmask(newset)");
+
+ /*
+ * Use sigaction() instead of signal() to get unambiguous semantics,
+ * in particular with SA_RESTART not set.
+ */
+
+ sigemptyset(&si_sa.sa_mask);
+ si_sa.sa_flags = 0;
+
+ si_sa.sa_handler = stopit;
+ if (sigaction(SIGINT, &si_sa, 0) == -1) {
+ err(EX_OSERR, "sigaction SIGINT");
+ }
+ si_sa.sa_handler = stopit;
+ if (sigaction(SIGQUIT, &si_sa, 0) == -1) {
+ err(EX_OSERR, "sigaction SIGQUIT");
+ }
+
+ si_sa.sa_handler = status;
+ if (sigaction(SIGINFO, &si_sa, 0) == -1) {
+ err(EX_OSERR, "sigaction SIGINFO");
+ }
+
+ if (alarmtimeout > 0) {
+ si_sa.sa_handler = stopit;
+ if (sigaction(SIGALRM, &si_sa, 0) == -1)
+ err(EX_OSERR, "sigaction SIGALRM");
+ }
+
+ bzero(&msg, sizeof(msg));
+ msg.msg_name = (caddr_t)&from;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+#ifdef SO_TIMESTAMP
+ msg.msg_control = (caddr_t)ctrl;
+#endif
+ iov.iov_base = packet;
+ iov.iov_len = IP_MAXPACKET;
+
+ if (preload == 0)
+ pinger(); /* send the first ping */
+ else {
+ if (npackets != 0 && preload > npackets)
+ preload = npackets;
+ while (preload--) /* fire off them quickies */
+ pinger();
+ }
+ (void)gettimeofday(&last, NULL);
+
+ if (options & F_FLOOD) {
+ intvl.tv_sec = 0;
+ intvl.tv_usec = 10000;
+ } else {
+ intvl.tv_sec = interval / 1000;
+ intvl.tv_usec = interval % 1000 * 1000;
+ }
+
+ almost_done = 0;
+ while (!finish_up) {
+ struct timeval now, timeout;
+ fd_set rfds;
+ int cc, n;
+ int tc = -1;
+
+ check_status();
+ if ((unsigned)s >= FD_SETSIZE)
+ errx(EX_OSERR, "descriptor too large");
+ FD_ZERO(&rfds);
+ FD_SET(s, &rfds);
+ (void)gettimeofday(&now, NULL);
+ timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
+ timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
+ while (timeout.tv_usec < 0) {
+ timeout.tv_usec += 1000000;
+ timeout.tv_sec--;
+ }
+ while (timeout.tv_usec >= 1000000) {
+ timeout.tv_usec -= 1000000;
+ timeout.tv_sec++;
+ }
+ if (timeout.tv_sec < 0)
+ timeout.tv_sec = timeout.tv_usec = 0;
+ n = select(s + 1, &rfds, NULL, NULL, &timeout);
+ if (n < 0)
+ continue; /* Must be EINTR. */
+ if (n == 1) {
+ struct timeval *tv = NULL;
+#ifdef SO_TIMESTAMP
+ struct cmsghdr *cmsg;
+
+ msg.msg_controllen = sizeof(ctrl);
+#endif
+ msg.msg_namelen = sizeof(from);
+ if ((cc = recvmsg(s, &msg, 0)) < 0) {
+ if (errno == EINTR)
+ continue;
+ warn("recvmsg");
+ continue;
+ }
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+#ifdef SO_TIMESTAMP
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_TIMESTAMP &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof *tv)) {
+ /* Copy to avoid alignment problems: */
+ memcpy(&now, CMSG_DATA(cmsg), sizeof(now));
+ tv = &now;
+ }
+#endif
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SO_TRAFFIC_CLASS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
+ /* Copy to avoid alignment problems: */
+ memcpy(&tc, CMSG_DATA(cmsg), sizeof(tc));
+ }
+ }
+ if (tv == NULL) {
+ (void)gettimeofday(&now, NULL);
+ tv = &now;
+ }
+ pr_pack((char *)packet, cc, &from, tv, tc);
+ if ((options & F_ONCE && nreceived) ||
+ (npackets && nreceived >= npackets))
+ break;
+ }
+ if (n == 0 || options & F_FLOOD) {
+ if (sweepmax && sntransmitted == snpackets) {
+ datalen += sweepincr;
+ if (datalen > sweepmax)
+ break;
+ send_len = icmp_len + datalen;
+ sntransmitted = 0;
+ }
+ if (!npackets || ntransmitted < npackets)
+ pinger();
+ else {
+ if (almost_done)
+ break;
+ almost_done = 1;
+ intvl.tv_usec = 0;
+ if (nreceived) {
+ intvl.tv_sec = 2 * tmax / 1000;
+ if (!intvl.tv_sec)
+ intvl.tv_sec = 1;
+ } else {
+ intvl.tv_sec = waittime / 1000;
+ intvl.tv_usec = waittime % 1000 * 1000;
+ }
+ }
+ (void)gettimeofday(&last, NULL);
+ if (ntransmitted - nreceived - 1 > nmissedmax) {
+ nmissedmax = ntransmitted - nreceived - 1;
+ if (options & F_MISSED)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ if (!(options & F_QUIET)) {
+ printf("Request timeout for icmp_seq %u\n",
+ (uint16_t)(ntransmitted - 2));
+ if (!(options & F_FLOOD))
+ (void)fflush(stdout);
+ }
+ }
+ }
+ }
+ finish();
+ /* NOTREACHED */
+ exit(0); /* Make the compiler happy */
+}
+
+/*
+ * stopit --
+ * Set the global bit that causes the main loop to quit.
+ * Do NOT call finish() from here, since finish() does far too much
+ * to be called from a signal handler.
+ */
+void
+stopit(int sig __unused)
+{
+
+ /*
+ * When doing reverse DNS lookups, the finish_up flag might not
+ * be noticed for a while. Just exit if we get a second SIGINT.
+ */
+ if (!(options & F_NUMERIC) && finish_up)
+ _exit(nreceived ? 0 : 2);
+ finish_up = 1;
+}
+
+/*
+ * pinger --
+ * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
+ * will be added on by the kernel. The ID field is our UNIX process ID,
+ * and the sequence number is an ascending integer. The first TIMEVAL_LEN
+ * bytes of the data portion are used to hold a UNIX "timeval" struct in
+ * host byte-order, to compute the round-trip time.
+ */
+static void
+pinger(void)
+{
+ struct timeval now;
+ struct tv32 tv32;
+ struct ip *ip;
+ struct icmp *icp;
+ int cc, i;
+ u_char *packet;
+
+ packet = outpack;
+ icp = (struct icmp *)outpack;
+ icp->icmp_type = icmp_type;
+ icp->icmp_code = 0;
+ icp->icmp_cksum = 0;
+ icp->icmp_seq = htons(ntransmitted);
+ icp->icmp_id = ident; /* ID */
+
+ CLR(ntransmitted % mx_dup_ck);
+
+ if (datalen >= TIMEVAL_LEN) /* can we time transfer */
+ timing = 1;
+ else
+ timing = 0;
+
+ if ((options & F_TIME) || timing) {
+ (void)gettimeofday(&now, NULL);
+
+ tv32.tv32_sec = htonl(now.tv_sec);
+ tv32.tv32_usec = htonl(now.tv_usec);
+ if (options & F_TIME)
+ icp->icmp_otime = htonl((now.tv_sec % (24*60*60))
+ * 1000 + now.tv_usec / 1000);
+ if (timing)
+ bcopy((void *)&tv32,
+ (void *)&outpack[ICMP_MINLEN + phdr_len],
+ sizeof(tv32));
+ }
+
+ cc = ICMP_MINLEN + phdr_len + datalen;
+
+ /* compute ICMP checksum here */
+ icp->icmp_cksum = in_cksum((u_short *)icp, cc);
+
+ if (options & F_HDRINCL) {
+ cc += sizeof(struct ip);
+ ip = (struct ip *)outpackhdr;
+ ip->ip_len = cc;
+ ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);
+ packet = outpackhdr;
+ }
+ if (use_sendmsg > 0) {
+ struct msghdr msg;
+ struct iovec iov;
+ char cmbuf[2 * CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cm = (struct cmsghdr *)cmbuf;
+
+ if ((options & F_CONNECT)) {
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ } else {
+ msg.msg_name = &whereto;
+ msg.msg_namelen = sizeof(whereto);
+ }
+ iov.iov_base = packet;
+ iov.iov_len = cc;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ msg.msg_controllen = 0;
+ msg.msg_control = NULL;
+
+ if (traffic_class >= 0) {
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ cm->cmsg_level = SOL_SOCKET;
+ cm->cmsg_type = SO_TRAFFIC_CLASS;
+ *(int *)CMSG_DATA(cm) = traffic_class;
+ msg.msg_controllen += CMSG_SPACE(sizeof(int));
+ cm = (struct cmsghdr *)(((char *)cm) + CMSG_SPACE(sizeof(int)));
+ }
+ if (net_service_type >= 0) {
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ cm->cmsg_level = SOL_SOCKET;
+ cm->cmsg_type = SO_NET_SERVICE_TYPE;
+ msg.msg_controllen += CMSG_SPACE(sizeof(int));
+ *(int *)CMSG_DATA(cm) = net_service_type;
+ }
+ msg.msg_control = cmbuf;
+
+ msg.msg_flags = 0;
+
+ i = sendmsg(s, &msg, 0);
+ } else {
+ if ((options & F_CONNECT)) {
+ i = send(s, (char *)packet, cc, 0);
+ } else {
+ i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto,
+ sizeof(whereto));
+ }
+ }
+ if (i < 0 || i != cc) {
+ if (i < 0) {
+ if (options & F_FLOOD && errno == ENOBUFS) {
+ usleep(FLOOD_BACKOFF);
+ return;
+ }
+ warn("sendto");
+ } else {
+ warn("%s: partial write: %d of %d bytes",
+ hostname, i, cc);
+ }
+ }
+ ntransmitted++;
+ sntransmitted++;
+ if (!(options & F_QUIET) && options & F_FLOOD)
+ (void)write(STDOUT_FILENO, &DOT, 1);
+}
+
+/*
+ * pr_pack --
+ * Print out the packet, if it came from us. This logic is necessary
+ * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
+ * which arrive ('tis only fair). This permits multiple copies of this
+ * program to be run without having intermingled output (or statistics!).
+ */
+static void
+pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv,
+ int tc)
+{
+ struct in_addr ina;
+ u_char *cp, *dp;
+ struct icmp *icp;
+ struct ip *ip;
+ const void *tp;
+ double triptime;
+ int dupflag, hlen, i, j, recv_len, seq;
+ static int old_rrlen;
+ static char old_rr[MAX_IPOPTLEN];
+
+ /* Check the IP header */
+ ip = (struct ip *)buf;
+ hlen = ip->ip_hl << 2;
+ recv_len = cc;
+ if (cc < hlen + ICMP_MINLEN) {
+ if (options & F_VERBOSE)
+ warn("packet too short (%d bytes) from %s", cc,
+ inet_ntoa(from->sin_addr));
+ return;
+ }
+
+ /* Now the ICMP part */
+ cc -= hlen;
+ icp = (struct icmp *)(buf + hlen);
+ if (icp->icmp_type == icmp_type_rsp) {
+ if (icp->icmp_id != ident)
+ return; /* 'Twas not our ECHO */
+ ++nreceived;
+ triptime = 0.0;
+ if (timing) {
+ struct timeval tv1;
+ struct tv32 tv32;
+#ifndef icmp_data
+ tp = &icp->icmp_ip;
+#else
+ tp = icp->icmp_data;
+#endif
+ tp = (const char *)tp + phdr_len;
+
+ if (cc - ICMP_MINLEN - phdr_len >= sizeof(tv1)) {
+ /* Copy to avoid alignment problems: */
+ memcpy(&tv32, tp, sizeof(tv32));
+ tv1.tv_sec = ntohl(tv32.tv32_sec);
+ tv1.tv_usec = ntohl(tv32.tv32_usec);
+ tvsub(tv, &tv1);
+ triptime = ((double)tv->tv_sec) * 1000.0 +
+ ((double)tv->tv_usec) / 1000.0;
+ tsum += triptime;
+ tsumsq += triptime * triptime;
+ if (triptime < tmin)
+ tmin = triptime;
+ if (triptime > tmax)
+ tmax = triptime;
+ } else
+ timing = 0;
+ }
+
+ seq = ntohs(icp->icmp_seq);
+
+ if (TST(seq % mx_dup_ck)) {
+ ++nrepeats;
+ --nreceived;
+ dupflag = 1;
+ } else {
+ SET(seq % mx_dup_ck);
+ dupflag = 0;
+ }
+
+ if (options & F_QUIET)
+ return;
+
+ if (options & F_WAITTIME && triptime > waittime) {
+ ++nrcvtimeout;
+ return;
+ }
+
+ if (options & F_FLOOD)
+ (void)write(STDOUT_FILENO, &BSPACE, 1);
+ else {
+ int seq_sent_len = send_len;
+ int seq_datalen = datalen;
+
+ if (sweepmax != 0) {
+ /*
+ * When sweeping take in account the length of that
+ * was sent based on the sequence number
+ */
+ seq_datalen = sweepmin + (seq / snpackets) * sweepincr;
+ seq_sent_len = icmp_len + seq_datalen;
+ }
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s: icmp_seq=%u", cc,
+ inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
+ seq);
+ (void)printf(" ttl=%d", ip->ip_ttl);
+ if (timing)
+ (void)printf(" time=%.3f ms", triptime);
+ if (tc != -1) {
+ (void)printf(" tc=%d", tc);
+ }
+ if (dupflag && no_dup == 0) {
+ (void)printf(" (DUP!)");
+ }
+ if (options & F_AUDIBLE)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ if (options & F_MASK) {
+ /* Just prentend this cast isn't ugly */
+ (void)printf(" mask=%s",
+ pr_addr(*(struct in_addr *)&(icp->icmp_mask)));
+ }
+ if (options & F_TIME) {
+ (void)printf(" tso=%s", pr_ntime(icp->icmp_otime));
+ (void)printf(" tsr=%s", pr_ntime(icp->icmp_rtime));
+ (void)printf(" tst=%s", pr_ntime(icp->icmp_ttime));
+ }
+ if (recv_len != seq_sent_len) {
+ (void)printf(
+ "\nwrong total length %d instead of %d",
+ recv_len, seq_sent_len);
+ }
+ /* check the data */
+ cp = (u_char*)&icp->icmp_data[phdr_len];
+ dp = &outpack[ICMP_MINLEN + phdr_len];
+ cc -= ICMP_MINLEN + phdr_len;
+ i = 0;
+ if (timing) { /* don't check variable timestamp */
+ cp += TIMEVAL_LEN;
+ dp += TIMEVAL_LEN;
+ cc -= TIMEVAL_LEN;
+ i += TIMEVAL_LEN;
+ }
+ for (; i < seq_datalen && cc > 0; ++i, ++cp, ++dp, --cc) {
+ if (*cp != *dp) {
+ (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
+ i, *dp, *cp);
+ (void)printf("\ncp:");
+ cp = (u_char*)&icp->icmp_data[0];
+ for (i = 0; i < seq_datalen; ++i, ++cp) {
+ if ((i % 16) == 0)
+ (void)printf("\n\t");
+ (void)printf("%2x ", *cp);
+ }
+ (void)printf("\ndp:");
+ cp = &outpack[ICMP_MINLEN];
+ for (i = 0; i < seq_datalen; ++i, ++cp) {
+ if ((i % 16) == 0)
+ (void)printf("\n\t");
+ (void)printf("%2x ", *cp);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ /*
+ * We've got something other than an ECHOREPLY.
+ * See if it's a reply to something that we sent.
+ * We can compare IP destination, protocol,
+ * and ICMP type and ID.
+ *
+ * Only print all the error messages if we are running
+ * as root to avoid leaking information not normally
+ * available to those not running as root.
+ */
+#ifndef icmp_data
+ struct ip *oip = &icp->icmp_ip;
+#else
+ struct ip *oip = (struct ip *)icp->icmp_data;
+#endif
+ struct icmp *oicmp = (struct icmp *)(oip + 1);
+
+ if (((options & F_VERBOSE) && uid == 0) ||
+ (!(options & F_QUIET2) &&
+ (oip->ip_dst.s_addr == whereto.sin_addr.s_addr) &&
+ (oip->ip_p == IPPROTO_ICMP) &&
+ (oicmp->icmp_type == ICMP_ECHO) &&
+ (oicmp->icmp_id == ident))) {
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s: ", cc,
+ pr_addr(from->sin_addr));
+ pr_icmph(icp);
+ } else
+ return;
+ }
+
+ /* Display any IP options */
+ cp = (u_char *)buf + sizeof(struct ip);
+
+ for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
+ switch (*cp) {
+ case IPOPT_EOL:
+ hlen = 0;
+ break;
+ case IPOPT_LSRR:
+ case IPOPT_SSRR:
+ (void)printf(*cp == IPOPT_LSRR ?
+ "\nLSRR: " : "\nSSRR: ");
+ j = cp[IPOPT_OLEN] - IPOPT_MINOFF + 1;
+ hlen -= 2;
+ cp += 2;
+ if (j >= INADDR_LEN &&
+ j <= hlen - (int)sizeof(struct ip)) {
+ for (;;) {
+ bcopy(++cp, &ina.s_addr, INADDR_LEN);
+ if (ina.s_addr == 0)
+ (void)printf("\t0.0.0.0");
+ else
+ (void)printf("\t%s",
+ pr_addr(ina));
+ hlen -= INADDR_LEN;
+ cp += INADDR_LEN - 1;
+ j -= INADDR_LEN;
+ if (j < INADDR_LEN)
+ break;
+ (void)putchar('\n');
+ }
+ } else
+ (void)printf("\t(truncated route)\n");
+ break;
+ case IPOPT_RR:
+ j = cp[IPOPT_OLEN]; /* get length */
+ i = cp[IPOPT_OFFSET]; /* and pointer */
+ hlen -= 2;
+ cp += 2;
+ if (i > j)
+ i = j;
+ i = i - IPOPT_MINOFF + 1;
+ if (i < 0 || i > (hlen - (int)sizeof(struct ip))) {
+ old_rrlen = 0;
+ continue;
+ }
+ if (i == old_rrlen
+ && !bcmp((char *)cp, old_rr, i)
+ && !(options & F_FLOOD)) {
+ (void)printf("\t(same route)");
+ hlen -= i;
+ cp += i;
+ break;
+ }
+ old_rrlen = i;
+ bcopy((char *)cp, old_rr, i);
+ (void)printf("\nRR: ");
+ if (i >= INADDR_LEN &&
+ i <= hlen - (int)sizeof(struct ip)) {
+ for (;;) {
+ bcopy(++cp, &ina.s_addr, INADDR_LEN);
+ if (ina.s_addr == 0)
+ (void)printf("\t0.0.0.0");
+ else
+ (void)printf("\t%s",
+ pr_addr(ina));
+ hlen -= INADDR_LEN;
+ cp += INADDR_LEN - 1;
+ i -= INADDR_LEN;
+ if (i < INADDR_LEN)
+ break;
+ (void)putchar('\n');
+ }
+ } else
+ (void)printf("\t(truncated route)");
+ break;
+ case IPOPT_NOP:
+ (void)printf("\nNOP");
+ break;
+ default:
+ (void)printf("\nunknown option %x", *cp);
+ break;
+ }
+ if (!(options & F_FLOOD)) {
+ (void)putchar('\n');
+ (void)fflush(stdout);
+ }
+}
+
+/*
+ * in_cksum --
+ * Checksum routine for Internet Protocol family headers (C Version)
+ */
+u_short
+in_cksum(u_short *addr, int len)
+{
+ int nleft, sum;
+ u_short *w;
+ union {
+ u_short us;
+ u_char uc[2];
+ } last;
+ u_short answer;
+
+ nleft = len;
+ sum = 0;
+ w = addr;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum), we add
+ * sequential 16 bit words to it, and at the end, fold back all the
+ * carry bits from the top 16 bits into the lower 16 bits.
+ */
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if (nleft == 1) {
+ last.uc[0] = *(u_char *)w;
+ last.uc[1] = 0;
+ sum += last.us;
+ }
+
+ /* add back carry outs from top 16 bits to low 16 bits */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return(answer);
+}
+
+/*
+ * tvsub --
+ * Subtract 2 timeval structs: out = out - in. Out is assumed to
+ * be >= in.
+ */
+static void
+tvsub(struct timeval *out, const struct timeval *in)
+{
+
+ if ((out->tv_usec -= in->tv_usec) < 0) {
+ --out->tv_sec;
+ out->tv_usec += 1000000;
+ }
+ out->tv_sec -= in->tv_sec;
+}
+
+/*
+ * status --
+ * Print out statistics when SIGINFO is received.
+ */
+
+static void
+status(int sig __unused)
+{
+
+ siginfo_p = 1;
+}
+
+static void
+check_status(void)
+{
+
+ if (siginfo_p) {
+ siginfo_p = 0;
+ (void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)",
+ nreceived, ntransmitted,
+ ntransmitted ? nreceived * 100.0 / ntransmitted : 0.0);
+ if (nreceived && timing)
+ (void)fprintf(stderr, " %.3f min / %.3f avg / %.3f max",
+ tmin, tsum / (nreceived + nrepeats), tmax);
+ (void)fprintf(stderr, "\n");
+ }
+}
+
+/*
+ * finish --
+ * Print out statistics, and give up.
+ */
+static void
+finish(void)
+{
+
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGALRM, SIG_IGN);
+ (void)putchar('\n');
+ (void)fflush(stdout);
+ (void)printf("--- %s ping statistics ---\n", hostname);
+ (void)printf("%ld packets transmitted, ", ntransmitted);
+ (void)printf("%ld packets received, ", nreceived);
+ if (nrepeats)
+ (void)printf("+%ld duplicates, ", nrepeats);
+ if (ntransmitted) {
+ if (nreceived > ntransmitted)
+ (void)printf("-- somebody's printing up packets!");
+ else
+ (void)printf("%.1f%% packet loss",
+ ((ntransmitted - nreceived) * 100.0) /
+ ntransmitted);
+ }
+ if (nrcvtimeout)
+ (void)printf(", %ld packets out of wait time", nrcvtimeout);
+ (void)putchar('\n');
+ if (nreceived && timing) {
+ double n = nreceived + nrepeats;
+ double avg = tsum / n;
+ double vari = tsumsq / n - avg * avg;
+ (void)printf(
+ "round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n",
+ tmin, avg, tmax, sqrt(vari));
+ }
+
+ if (nreceived)
+ exit(0);
+ else
+ exit(2);
+}
+
+#ifdef notdef
+static char *ttab[] = {
+ "Echo Reply", /* ip + seq + udata */
+ "Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
+ "Source Quench", /* IP */
+ "Redirect", /* redirect type, gateway, + IP */
+ "Echo",
+ "Time Exceeded", /* transit, frag reassem + IP */
+ "Parameter Problem", /* pointer + IP */
+ "Timestamp", /* id + seq + three timestamps */
+ "Timestamp Reply", /* " */
+ "Info Request", /* id + sq */
+ "Info Reply" /* " */
+};
+#endif
+
+/*
+ * pr_icmph --
+ * Print a descriptive string about an ICMP header.
+ */
+static void
+pr_icmph(struct icmp *icp)
+{
+
+ switch(icp->icmp_type) {
+ case ICMP_ECHOREPLY:
+ (void)printf("Echo Reply\n");
+ /* XXX ID + Seq + Data */
+ break;
+ case ICMP_UNREACH:
+ switch(icp->icmp_code) {
+ case ICMP_UNREACH_NET:
+ (void)printf("Destination Net Unreachable\n");
+ break;
+ case ICMP_UNREACH_HOST:
+ (void)printf("Destination Host Unreachable\n");
+ break;
+ case ICMP_UNREACH_PROTOCOL:
+ (void)printf("Destination Protocol Unreachable\n");
+ break;
+ case ICMP_UNREACH_PORT:
+ (void)printf("Destination Port Unreachable\n");
+ break;
+ case ICMP_UNREACH_NEEDFRAG:
+ (void)printf("frag needed and DF set (MTU %d)\n",
+ ntohs(icp->icmp_nextmtu));
+ break;
+ case ICMP_UNREACH_SRCFAIL:
+ (void)printf("Source Route Failed\n");
+ break;
+ case ICMP_UNREACH_FILTER_PROHIB:
+ (void)printf("Communication prohibited by filter\n");
+ break;
+ default:
+ (void)printf("Dest Unreachable, Bad Code: %d\n",
+ icp->icmp_code);
+ break;
+ }
+ /* Print returned IP header information */
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_SOURCEQUENCH:
+ (void)printf("Source Quench\n");
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_REDIRECT:
+ switch(icp->icmp_code) {
+ case ICMP_REDIRECT_NET:
+ (void)printf("Redirect Network");
+ break;
+ case ICMP_REDIRECT_HOST:
+ (void)printf("Redirect Host");
+ break;
+ case ICMP_REDIRECT_TOSNET:
+ (void)printf("Redirect Type of Service and Network");
+ break;
+ case ICMP_REDIRECT_TOSHOST:
+ (void)printf("Redirect Type of Service and Host");
+ break;
+ default:
+ (void)printf("Redirect, Bad Code: %d", icp->icmp_code);
+ break;
+ }
+ (void)printf("(New addr: %s)\n", inet_ntoa(icp->icmp_gwaddr));
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_ECHO:
+ (void)printf("Echo Request\n");
+ /* XXX ID + Seq + Data */
+ break;
+ case ICMP_TIMXCEED:
+ switch(icp->icmp_code) {
+ case ICMP_TIMXCEED_INTRANS:
+ (void)printf("Time to live exceeded\n");
+ break;
+ case ICMP_TIMXCEED_REASS:
+ (void)printf("Frag reassembly time exceeded\n");
+ break;
+ default:
+ (void)printf("Time exceeded, Bad Code: %d\n",
+ icp->icmp_code);
+ break;
+ }
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_PARAMPROB:
+ (void)printf("Parameter problem: pointer = 0x%02x\n",
+ icp->icmp_hun.ih_pptr);
+#ifndef icmp_data
+ pr_retip(&icp->icmp_ip);
+#else
+ pr_retip((struct ip *)icp->icmp_data);
+#endif
+ break;
+ case ICMP_TSTAMP:
+ (void)printf("Timestamp\n");
+ /* XXX ID + Seq + 3 timestamps */
+ break;
+ case ICMP_TSTAMPREPLY:
+ (void)printf("Timestamp Reply\n");
+ /* XXX ID + Seq + 3 timestamps */
+ break;
+ case ICMP_IREQ:
+ (void)printf("Information Request\n");
+ /* XXX ID + Seq */
+ break;
+ case ICMP_IREQREPLY:
+ (void)printf("Information Reply\n");
+ /* XXX ID + Seq */
+ break;
+ case ICMP_MASKREQ:
+ (void)printf("Address Mask Request\n");
+ break;
+ case ICMP_MASKREPLY:
+ (void)printf("Address Mask Reply\n");
+ break;
+ case ICMP_ROUTERADVERT:
+ (void)printf("Router Advertisement\n");
+ break;
+ case ICMP_ROUTERSOLICIT:
+ (void)printf("Router Solicitation\n");
+ break;
+ default:
+ (void)printf("Bad ICMP type: %d\n", icp->icmp_type);
+ }
+}
+
+/*
+ * pr_iph --
+ * Print an IP header with options.
+ */
+static void
+pr_iph(struct ip *ip)
+{
+ u_char *cp;
+ int hlen;
+
+ hlen = ip->ip_hl << 2;
+ cp = (u_char *)ip + 20; /* point to options */
+
+ (void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n");
+ (void)printf(" %1x %1x %02x %04x %04x",
+ ip->ip_v, ip->ip_hl, ip->ip_tos, ntohs(ip->ip_len),
+ ntohs(ip->ip_id));
+ (void)printf(" %1lx %04lx",
+ (u_long) (ntohl(ip->ip_off) & 0xe000) >> 13,
+ (u_long) ntohl(ip->ip_off) & 0x1fff);
+ (void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p,
+ ntohs(ip->ip_sum));
+ (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
+ (void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
+ /* dump any option bytes */
+ while (hlen-- > 20) {
+ (void)printf("%02x", *cp++);
+ }
+ (void)putchar('\n');
+}
+
+/*
+ * pr_addr --
+ * Return an ascii host address as a dotted quad and optionally with
+ * a hostname.
+ */
+static char *
+pr_addr(struct in_addr ina)
+{
+ struct hostent *hp;
+ static char buf[16 + 3 + MAXHOSTNAMELEN];
+
+ if ((options & F_NUMERIC) ||
+ !(hp = gethostbyaddr((char *)&ina, 4, AF_INET)))
+ return inet_ntoa(ina);
+ else
+ (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
+ inet_ntoa(ina));
+ return(buf);
+}
+
+/*
+ * pr_retip --
+ * Dump some info on a returned (via ICMP) IP packet.
+ */
+static void
+pr_retip(struct ip *ip)
+{
+ u_char *cp;
+ int hlen;
+
+ pr_iph(ip);
+ hlen = ip->ip_hl << 2;
+ cp = (u_char *)ip + hlen;
+
+ if (ip->ip_p == 6)
+ (void)printf("TCP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
+ else if (ip->ip_p == 17)
+ (void)printf("UDP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
+}
+
+static char *
+pr_ntime(n_time timestamp)
+{
+ static char buf[10];
+ int hour, min, sec;
+
+ sec = ntohl(timestamp) / 1000;
+ hour = sec / 60 / 60;
+ min = (sec % (60 * 60)) / 60;
+ sec = (sec % (60 * 60)) % 60;
+
+ (void)snprintf(buf, sizeof(buf), "%02d:%02d:%02d", hour, min, sec);
+
+ return (buf);
+}
+
+static void
+fill(char *bp, char *patp)
+{
+ char *cp;
+ int pat[16];
+ u_int ii, jj, kk;
+
+ for (cp = patp; *cp; cp++) {
+ if (!isxdigit(*cp))
+ errx(EX_USAGE,
+ "patterns must be specified as hex digits");
+
+ }
+ ii = sscanf(patp,
+ "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
+ &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
+ &pat[13], &pat[14], &pat[15]);
+
+ if (ii > 0)
+ for (kk = 0; kk <= maxpayload - (TIMEVAL_LEN + ii); kk += ii)
+ for (jj = 0; jj < ii; ++jj)
+ bp[jj + kk] = pat[jj];
+ if (!(options & F_QUIET)) {
+ (void)printf("PATTERN: 0x");
+ for (jj = 0; jj < ii; ++jj)
+ (void)printf("%02x", bp[jj] & 0xFF);
+ (void)printf("\n");
+ }
+}
+
+int
+str2sotc(const char *str, bool *valid)
+{
+ int sotc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK_SYS") == 0)
+ return SO_TC_BK_SYS;
+ else if (strcasecmp(str, "BK") == 0)
+ return SO_TC_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return SO_TC_BE;
+ else if (strcasecmp(str, "RD") == 0)
+ return SO_TC_RD;
+ else if (strcasecmp(str, "OAM") == 0)
+ return SO_TC_OAM;
+ else if (strcasecmp(str, "AV") == 0)
+ return SO_TC_AV;
+ else if (strcasecmp(str, "RV") == 0)
+ return SO_TC_RV;
+ else if (strcasecmp(str, "VI") == 0)
+ return SO_TC_VI;
+ else if (strcasecmp(str, "VO") == 0)
+ return SO_TC_VO;
+ else if (strcasecmp(str, "CTL") == 0)
+ return SO_TC_CTL;
+ else {
+ sotc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (sotc);
+}
+
+int
+str2netservicetype(const char *str, bool *valid)
+{
+ int svc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK") == 0)
+ return NET_SERVICE_TYPE_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return NET_SERVICE_TYPE_BE;
+ else if (strcasecmp(str, "VI") == 0)
+ return NET_SERVICE_TYPE_VI;
+ else if (strcasecmp(str, "SIG") == 0)
+ return NET_SERVICE_TYPE_SIG;
+ else if (strcasecmp(str, "VO") == 0)
+ return NET_SERVICE_TYPE_VO;
+ else if (strcasecmp(str, "RV") == 0)
+ return NET_SERVICE_TYPE_RV;
+ else if (strcasecmp(str, "AV") == 0)
+ return NET_SERVICE_TYPE_AV;
+ else if (strcasecmp(str, "OAM") == 0)
+ return NET_SERVICE_TYPE_OAM;
+ else if (strcasecmp(str, "RD") == 0)
+ return NET_SERVICE_TYPE_RD;
+ else {
+ svc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (svc);
+}
+
+u_int8_t
+str2tos(const char *str, bool *valid)
+{
+ u_int8_t dscp = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "DF") == 0)
+ dscp = _DSCP_DF;
+ else if (strcasecmp(str, "EF") == 0)
+ dscp = _DSCP_EF;
+ else if (strcasecmp(str, "VA") == 0)
+ dscp = _DSCP_VA;
+
+ else if (strcasecmp(str, "CS0") == 0)
+ dscp = _DSCP_CS0;
+ else if (strcasecmp(str, "CS1") == 0)
+ dscp = _DSCP_CS1;
+ else if (strcasecmp(str, "CS2") == 0)
+ dscp = _DSCP_CS2;
+ else if (strcasecmp(str, "CS3") == 0)
+ dscp = _DSCP_CS3;
+ else if (strcasecmp(str, "CS4") == 0)
+ dscp = _DSCP_CS4;
+ else if (strcasecmp(str, "CS5") == 0)
+ dscp = _DSCP_CS5;
+ else if (strcasecmp(str, "CS6") == 0)
+ dscp = _DSCP_CS6;
+ else if (strcasecmp(str, "CS7") == 0)
+ dscp = _DSCP_CS7;
+
+ else if (strcasecmp(str, "AF11") == 0)
+ dscp = _DSCP_AF11;
+ else if (strcasecmp(str, "AF12") == 0)
+ dscp = _DSCP_AF12;
+ else if (strcasecmp(str, "AF13") == 0)
+ dscp = _DSCP_AF13;
+ else if (strcasecmp(str, "AF21") == 0)
+ dscp = _DSCP_AF21;
+ else if (strcasecmp(str, "AF22") == 0)
+ dscp = _DSCP_AF22;
+ else if (strcasecmp(str, "AF23") == 0)
+ dscp = _DSCP_AF23;
+ else if (strcasecmp(str, "AF31") == 0)
+ dscp = _DSCP_AF31;
+ else if (strcasecmp(str, "AF32") == 0)
+ dscp = _DSCP_AF32;
+ else if (strcasecmp(str, "AF33") == 0)
+ dscp = _DSCP_AF33;
+ else if (strcasecmp(str, "AF41") == 0)
+ dscp = _DSCP_AF41;
+ else if (strcasecmp(str, "AF42") == 0)
+ dscp = _DSCP_AF42;
+ else if (strcasecmp(str, "AF43") == 0)
+ dscp = _DSCP_AF43;
+
+ else {
+ unsigned long val = strtoul(str, &endptr, 0);
+ if (*endptr != '\0' || val > 255)
+ *valid = false;
+ else
+ return ((u_int8_t)val);
+ }
+ /* DSCP occupies the 6 upper bits of the TOS field */
+ return (dscp << 2);
+}
+
+void
+pr_currenttime(void)
+{
+ int s;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ s = (tv.tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tv.tv_usec);
+}
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+#define SECOPT " [-P policy]"
+#else
+#define SECOPT ""
+#endif
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+"usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize]",
+" [-g sweepminsize] [-h sweepincrsize] [-i wait]",
+" [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern]",
+" [-S src_addr] [-s packetsize] [-t timeout][-W waittime]",
+" [-z tos] host",
+" ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait]",
+" [-l preload] [-M mask | time] [-m ttl]" SECOPT " [-p pattern] [-S src_addr]",
+" [-s packetsize] [-T ttl] [-t timeout] [-W waittime]",
+" [-z tos] mcast-group");
+ (void)fprintf(stderr, "Apple specific options (to be specified before mcast-group or host like all options)\n");
+ (void)fprintf(stderr, " -b boundif # bind the socket to the interface\n");
+ (void)fprintf(stderr, " -k traffic_class # set traffic class socket option\n");
+ (void)fprintf(stderr, " -K net_service_type # set traffic class socket options\n");
+ (void)fprintf(stderr, " -apple-connect # call connect(2) in the socket\n");
+ (void)fprintf(stderr, " -apple-time # display current time\n");
+ exit(EX_USAGE);
+}
diff --git a/network_cmds/ping6.tproj/md5.c b/network_cmds/ping6.tproj/md5.c
new file mode 100644
index 0000000..68a654b
--- /dev/null
+++ b/network_cmds/ping6.tproj/md5.c
@@ -0,0 +1,308 @@
+/* $KAME: md5.c,v 1.3 2000/05/27 07:14:22 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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/types.h>
+#include <sys/cdefs.h>
+#include <sys/time.h>
+#include <string.h>
+#include "md5.h"
+
+#define SHIFT(X, s) (((X) << (s)) | ((X) >> (32 - (s))))
+
+#define F(X, Y, Z) (((X) & (Y)) | ((~X) & (Z)))
+#define G(X, Y, Z) (((X) & (Z)) | ((Y) & (~Z)))
+#define H(X, Y, Z) ((X) ^ (Y) ^ (Z))
+#define I(X, Y, Z) ((Y) ^ ((X) | (~Z)))
+
+#define ROUND1(a, b, c, d, k, s, i) { \
+ (a) = (a) + F((b), (c), (d)) + X[(k)] + T[(i)]; \
+ (a) = SHIFT((a), (s)); \
+ (a) = (b) + (a); \
+}
+
+#define ROUND2(a, b, c, d, k, s, i) { \
+ (a) = (a) + G((b), (c), (d)) + X[(k)] + T[(i)]; \
+ (a) = SHIFT((a), (s)); \
+ (a) = (b) + (a); \
+}
+
+#define ROUND3(a, b, c, d, k, s, i) { \
+ (a) = (a) + H((b), (c), (d)) + X[(k)] + T[(i)]; \
+ (a) = SHIFT((a), (s)); \
+ (a) = (b) + (a); \
+}
+
+#define ROUND4(a, b, c, d, k, s, i) { \
+ (a) = (a) + I((b), (c), (d)) + X[(k)] + T[(i)]; \
+ (a) = SHIFT((a), (s)); \
+ (a) = (b) + (a); \
+}
+
+#define Sa 7
+#define Sb 12
+#define Sc 17
+#define Sd 22
+
+#define Se 5
+#define Sf 9
+#define Sg 14
+#define Sh 20
+
+#define Si 4
+#define Sj 11
+#define Sk 16
+#define Sl 23
+
+#define Sm 6
+#define Sn 10
+#define So 15
+#define Sp 21
+
+#define MD5_A0 0x67452301
+#define MD5_B0 0xefcdab89
+#define MD5_C0 0x98badcfe
+#define MD5_D0 0x10325476
+
+/* Integer part of 4294967296 times abs(sin(i)), where i is in radians. */
+static const u_int32_t T[65] = {
+ 0,
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
+};
+
+static const u_int8_t md5_paddat[MD5_BUFLEN] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static void md5_calc __P((u_int8_t *, md5_ctxt *));
+
+void md5_init(ctxt)
+ md5_ctxt *ctxt;
+{
+ ctxt->md5_n = 0;
+ ctxt->md5_i = 0;
+ ctxt->md5_sta = MD5_A0;
+ ctxt->md5_stb = MD5_B0;
+ ctxt->md5_stc = MD5_C0;
+ ctxt->md5_std = MD5_D0;
+ bzero(ctxt->md5_buf, sizeof(ctxt->md5_buf));
+}
+
+void md5_loop(ctxt, input, len)
+ md5_ctxt *ctxt;
+ u_int8_t *input;
+ u_int len; /* number of bytes */
+{
+ u_int gap, i;
+
+ ctxt->md5_n += len * 8; /* byte to bit */
+ gap = MD5_BUFLEN - ctxt->md5_i;
+
+ if (len >= gap) {
+ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
+ gap);
+ md5_calc(ctxt->md5_buf, ctxt);
+
+ for (i = gap; i + MD5_BUFLEN <= len; i += MD5_BUFLEN) {
+ md5_calc((u_int8_t *)(input + i), ctxt);
+ }
+
+ ctxt->md5_i = len - i;
+ bcopy((void *)(input + i), (void *)ctxt->md5_buf, ctxt->md5_i);
+ } else {
+ bcopy((void *)input, (void *)(ctxt->md5_buf + ctxt->md5_i),
+ len);
+ ctxt->md5_i += len;
+ }
+}
+
+void md5_pad(ctxt)
+ md5_ctxt *ctxt;
+{
+ u_int gap;
+
+ /* Don't count up padding. Keep md5_n. */
+ gap = MD5_BUFLEN - ctxt->md5_i;
+ if (gap > 8) {
+ bcopy((void *)md5_paddat,
+ (void *)(ctxt->md5_buf + ctxt->md5_i),
+ gap - sizeof(ctxt->md5_n));
+ } else {
+ /* including gap == 8 */
+ bcopy((void *)md5_paddat, (void *)(ctxt->md5_buf + ctxt->md5_i),
+ gap);
+ md5_calc(ctxt->md5_buf, ctxt);
+ bcopy((void *)(md5_paddat + gap),
+ (void *)ctxt->md5_buf,
+ MD5_BUFLEN - sizeof(ctxt->md5_n));
+ }
+
+ /* 8 byte word */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ bcopy(&ctxt->md5_n8[0], &ctxt->md5_buf[56], 8);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ ctxt->md5_buf[56] = ctxt->md5_n8[7];
+ ctxt->md5_buf[57] = ctxt->md5_n8[6];
+ ctxt->md5_buf[58] = ctxt->md5_n8[5];
+ ctxt->md5_buf[59] = ctxt->md5_n8[4];
+ ctxt->md5_buf[60] = ctxt->md5_n8[3];
+ ctxt->md5_buf[61] = ctxt->md5_n8[2];
+ ctxt->md5_buf[62] = ctxt->md5_n8[1];
+ ctxt->md5_buf[63] = ctxt->md5_n8[0];
+#endif
+
+ md5_calc(ctxt->md5_buf, ctxt);
+}
+
+void md5_result(digest, ctxt)
+ u_int8_t *digest;
+ md5_ctxt *ctxt;
+{
+ /* 4 byte words */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ bcopy(&ctxt->md5_st8[0], digest, 16);
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ digest[ 0] = ctxt->md5_st8[ 3]; digest[ 1] = ctxt->md5_st8[ 2];
+ digest[ 2] = ctxt->md5_st8[ 1]; digest[ 3] = ctxt->md5_st8[ 0];
+ digest[ 4] = ctxt->md5_st8[ 7]; digest[ 5] = ctxt->md5_st8[ 6];
+ digest[ 6] = ctxt->md5_st8[ 5]; digest[ 7] = ctxt->md5_st8[ 4];
+ digest[ 8] = ctxt->md5_st8[11]; digest[ 9] = ctxt->md5_st8[10];
+ digest[10] = ctxt->md5_st8[ 9]; digest[11] = ctxt->md5_st8[ 8];
+ digest[12] = ctxt->md5_st8[15]; digest[13] = ctxt->md5_st8[14];
+ digest[14] = ctxt->md5_st8[13]; digest[15] = ctxt->md5_st8[12];
+#endif
+}
+
+#if BYTE_ORDER == BIG_ENDIAN
+u_int32_t X[16];
+#endif
+
+static void md5_calc(b64, ctxt)
+ u_int8_t *b64;
+ md5_ctxt *ctxt;
+{
+ u_int32_t A = ctxt->md5_sta;
+ u_int32_t B = ctxt->md5_stb;
+ u_int32_t C = ctxt->md5_stc;
+ u_int32_t D = ctxt->md5_std;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int32_t *X = (u_int32_t *)b64;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ /* 4 byte words */
+ /* what a brute force but fast! */
+ u_int8_t *y = (u_int8_t *)X;
+ y[ 0] = b64[ 3]; y[ 1] = b64[ 2]; y[ 2] = b64[ 1]; y[ 3] = b64[ 0];
+ y[ 4] = b64[ 7]; y[ 5] = b64[ 6]; y[ 6] = b64[ 5]; y[ 7] = b64[ 4];
+ y[ 8] = b64[11]; y[ 9] = b64[10]; y[10] = b64[ 9]; y[11] = b64[ 8];
+ y[12] = b64[15]; y[13] = b64[14]; y[14] = b64[13]; y[15] = b64[12];
+ y[16] = b64[19]; y[17] = b64[18]; y[18] = b64[17]; y[19] = b64[16];
+ y[20] = b64[23]; y[21] = b64[22]; y[22] = b64[21]; y[23] = b64[20];
+ y[24] = b64[27]; y[25] = b64[26]; y[26] = b64[25]; y[27] = b64[24];
+ y[28] = b64[31]; y[29] = b64[30]; y[30] = b64[29]; y[31] = b64[28];
+ y[32] = b64[35]; y[33] = b64[34]; y[34] = b64[33]; y[35] = b64[32];
+ y[36] = b64[39]; y[37] = b64[38]; y[38] = b64[37]; y[39] = b64[36];
+ y[40] = b64[43]; y[41] = b64[42]; y[42] = b64[41]; y[43] = b64[40];
+ y[44] = b64[47]; y[45] = b64[46]; y[46] = b64[45]; y[47] = b64[44];
+ y[48] = b64[51]; y[49] = b64[50]; y[50] = b64[49]; y[51] = b64[48];
+ y[52] = b64[55]; y[53] = b64[54]; y[54] = b64[53]; y[55] = b64[52];
+ y[56] = b64[59]; y[57] = b64[58]; y[58] = b64[57]; y[59] = b64[56];
+ y[60] = b64[63]; y[61] = b64[62]; y[62] = b64[61]; y[63] = b64[60];
+#endif
+
+ ROUND1(A, B, C, D, 0, Sa, 1); ROUND1(D, A, B, C, 1, Sb, 2);
+ ROUND1(C, D, A, B, 2, Sc, 3); ROUND1(B, C, D, A, 3, Sd, 4);
+ ROUND1(A, B, C, D, 4, Sa, 5); ROUND1(D, A, B, C, 5, Sb, 6);
+ ROUND1(C, D, A, B, 6, Sc, 7); ROUND1(B, C, D, A, 7, Sd, 8);
+ ROUND1(A, B, C, D, 8, Sa, 9); ROUND1(D, A, B, C, 9, Sb, 10);
+ ROUND1(C, D, A, B, 10, Sc, 11); ROUND1(B, C, D, A, 11, Sd, 12);
+ ROUND1(A, B, C, D, 12, Sa, 13); ROUND1(D, A, B, C, 13, Sb, 14);
+ ROUND1(C, D, A, B, 14, Sc, 15); ROUND1(B, C, D, A, 15, Sd, 16);
+
+ ROUND2(A, B, C, D, 1, Se, 17); ROUND2(D, A, B, C, 6, Sf, 18);
+ ROUND2(C, D, A, B, 11, Sg, 19); ROUND2(B, C, D, A, 0, Sh, 20);
+ ROUND2(A, B, C, D, 5, Se, 21); ROUND2(D, A, B, C, 10, Sf, 22);
+ ROUND2(C, D, A, B, 15, Sg, 23); ROUND2(B, C, D, A, 4, Sh, 24);
+ ROUND2(A, B, C, D, 9, Se, 25); ROUND2(D, A, B, C, 14, Sf, 26);
+ ROUND2(C, D, A, B, 3, Sg, 27); ROUND2(B, C, D, A, 8, Sh, 28);
+ ROUND2(A, B, C, D, 13, Se, 29); ROUND2(D, A, B, C, 2, Sf, 30);
+ ROUND2(C, D, A, B, 7, Sg, 31); ROUND2(B, C, D, A, 12, Sh, 32);
+
+ ROUND3(A, B, C, D, 5, Si, 33); ROUND3(D, A, B, C, 8, Sj, 34);
+ ROUND3(C, D, A, B, 11, Sk, 35); ROUND3(B, C, D, A, 14, Sl, 36);
+ ROUND3(A, B, C, D, 1, Si, 37); ROUND3(D, A, B, C, 4, Sj, 38);
+ ROUND3(C, D, A, B, 7, Sk, 39); ROUND3(B, C, D, A, 10, Sl, 40);
+ ROUND3(A, B, C, D, 13, Si, 41); ROUND3(D, A, B, C, 0, Sj, 42);
+ ROUND3(C, D, A, B, 3, Sk, 43); ROUND3(B, C, D, A, 6, Sl, 44);
+ ROUND3(A, B, C, D, 9, Si, 45); ROUND3(D, A, B, C, 12, Sj, 46);
+ ROUND3(C, D, A, B, 15, Sk, 47); ROUND3(B, C, D, A, 2, Sl, 48);
+
+ ROUND4(A, B, C, D, 0, Sm, 49); ROUND4(D, A, B, C, 7, Sn, 50);
+ ROUND4(C, D, A, B, 14, So, 51); ROUND4(B, C, D, A, 5, Sp, 52);
+ ROUND4(A, B, C, D, 12, Sm, 53); ROUND4(D, A, B, C, 3, Sn, 54);
+ ROUND4(C, D, A, B, 10, So, 55); ROUND4(B, C, D, A, 1, Sp, 56);
+ ROUND4(A, B, C, D, 8, Sm, 57); ROUND4(D, A, B, C, 15, Sn, 58);
+ ROUND4(C, D, A, B, 6, So, 59); ROUND4(B, C, D, A, 13, Sp, 60);
+ ROUND4(A, B, C, D, 4, Sm, 61); ROUND4(D, A, B, C, 11, Sn, 62);
+ ROUND4(C, D, A, B, 2, So, 63); ROUND4(B, C, D, A, 9, Sp, 64);
+
+ ctxt->md5_sta += A;
+ ctxt->md5_stb += B;
+ ctxt->md5_stc += C;
+ ctxt->md5_std += D;
+}
diff --git a/network_cmds/ping6.tproj/md5.h b/network_cmds/ping6.tproj/md5.h
new file mode 100644
index 0000000..b0752af
--- /dev/null
+++ b/network_cmds/ping6.tproj/md5.h
@@ -0,0 +1,75 @@
+/* $KAME: md5.h,v 1.1 2000/05/27 06:18:21 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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 _NETINET6_MD5_H_
+#define _NETINET6_MD5_H_
+
+#define MD5_BUFLEN 64
+
+typedef struct {
+ union {
+ u_int32_t md5_state32[4];
+ u_int8_t md5_state8[16];
+ } md5_st;
+
+#define md5_sta md5_st.md5_state32[0]
+#define md5_stb md5_st.md5_state32[1]
+#define md5_stc md5_st.md5_state32[2]
+#define md5_std md5_st.md5_state32[3]
+#define md5_st8 md5_st.md5_state8
+
+ union {
+ u_int64_t md5_count64;
+ u_int8_t md5_count8[8];
+ } md5_count;
+#define md5_n md5_count.md5_count64
+#define md5_n8 md5_count.md5_count8
+
+ u_int md5_i;
+ u_int8_t md5_buf[MD5_BUFLEN];
+} md5_ctxt;
+
+extern void md5_init __P((md5_ctxt *));
+extern void md5_loop __P((md5_ctxt *, u_int8_t *, u_int));
+extern void md5_pad __P((md5_ctxt *));
+extern void md5_result __P((u_int8_t *, md5_ctxt *));
+
+/* compatibility */
+#define MD5_CTX md5_ctxt
+#define MD5Init(x) md5_init((x))
+#define MD5Update(x, y, z) md5_loop((x), (y), (z))
+#define MD5Final(x, y) \
+do { \
+ md5_pad((y)); \
+ md5_result((x), (y)); \
+} while (0)
+
+#endif /* ! _NETINET6_MD5_H_*/
diff --git a/network_cmds/ping6.tproj/ping6.8 b/network_cmds/ping6.tproj/ping6.8
new file mode 100644
index 0000000..7ec0b70
--- /dev/null
+++ b/network_cmds/ping6.tproj/ping6.8
@@ -0,0 +1,625 @@
+.\" Copyright (c) 2002-2013 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. The rights granted to you under the License
+.\" may not be used to create, or enable the creation or redistribution of,
+.\" unlawful or unlicensed copies of an Apple operating system, or to
+.\" circumvent, violate, or enable the circumvention or violation of, any
+.\" terms of an Apple operating system software license agreement.
+.\"
+.\" Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+.\"
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" 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 project 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 PROJECT 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 PROJECT 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 March 29, 2013
+.Dt PING6 8
+.Os
+.Sh NAME
+.Nm ping6
+.Nd send
+.Tn ICMPv6 ECHO_REQUEST
+packets to network hosts
+.Sh SYNOPSIS
+.Nm
+.\" without ipsec, or new ipsec
+.Op Fl CDdfHmnNoqtvwW
+.\" old ipsec
+.\" .Op Fl ADdEfmnNqRtvwW
+.Bk -words
+.Op Fl a Ar addrtype
+.Ek
+.Bk -words
+.Op Fl b Ar bufsiz
+.Ek
+.Bk -words
+.Op Fl B Ar boundif
+.Ek
+.Bk -words
+.Op Fl c Ar count
+.Ek
+.Bk -words
+.Op Fl G Ar sweepmaxsize[,sweepminsize[,sweepincrsize]]
+.Ek
+.Bk -words
+.Op Fl g Ar gateway
+.Ek
+.Bk -words
+.Op Fl G Ar sweep
+.Ek
+.Bk -words
+.Op Fl h Ar hoplimit
+.Ek
+.Bk -words
+.Op Fl I Ar interface
+.Ek
+.Bk -words
+.Op Fl i Ar wait
+.Ek
+.Bk -words
+.Op Fl k Ar trafficclass
+.Ek
+.Bk -words
+.Op Fl K Ar netservicetype
+.Ek
+.Bk -words
+.Op Fl l Ar preload
+.Ek
+.Bk -words
+.\" new ipsec
+.Op Fl P Ar policy
+.Ek
+.Bk -words
+.Op Fl p Ar pattern
+.Ek
+.Bk -words
+.Op Fl S Ar sourceaddr
+.Ek
+.Bk -words
+.Op Fl s Ar packetsize
+.Ek
+.Bk -words
+.Op Fl z Ar tclass
+.Ek
+.Bk -words
+.Op Fl Fl apple-connect
+.Ek
+.Bk -words
+.Op Fl Fl apple-time
+.Ek
+.Bk -words
+.Op Ar hops ...
+.Ek
+.Bk -words
+.Ar host
+.Ek
+.Sh DESCRIPTION
+The
+.Nm
+utility uses the
+.Tn ICMPv6
+protocol's mandatory
+.Tn ICMP6_ECHO_REQUEST
+datagram to elicit an
+.Tn ICMP6_ECHO_REPLY
+from a host or gateway.
+.Tn ICMP6_ECHO_REQUEST
+datagrams (``pings'') have an IPv6 header,
+and
+.Tn ICMPv6
+header formatted as documented in RFC2463.
+The options are as follows:
+.Bl -tag -width Ds
+.\" old ipsec
+.\" .It Fl A
+.\" Enables transport-mode IPsec authentication header
+.\" (experimental).
+.It Fl a Ar addrtype
+Generate ICMPv6 Node Information Node Addresses query, rather than echo-request.
+.Ar addrtype
+must be a string constructed of the following characters.
+.Bl -tag -width Ds -compact
+.It Ic a
+requests unicast addresses from all of the responder's interfaces.
+If the character is omitted,
+only those addresses which belong to the interface which has the
+responder's address are requests.
+.It Ic c
+requests responder's IPv4-compatible and IPv4-mapped addresses.
+.It Ic g
+requests responder's global-scope addresses.
+.It Ic s
+requests responder's site-local addresses.
+.It Ic l
+requests responder's link-local addresses.
+.It Ic A
+requests responder's anycast addresses.
+Without this character, the responder will return unicast addresses only.
+With this character, the responder will return anycast addresses only.
+Note that the specification does not specify how to get responder's
+anycast addresses.
+This is an experimental option.
+.El
+.It Fl b Ar bufsiz
+Set socket buffer size.
+.It Fl B Ar boundif
+Bind the socket to interface
+This option is an Apple addition.
+.Ar boundif
+for sending.
+.It Fl C
+Prohibit the socket from using the cellular network interface.
+.It Fl c Ar count
+Stop after sending
+(and receiving)
+.Ar count
+.Tn ECHO_RESPONSE
+packets.
+If this option is specified in conjunction with ping sweeps,
+each sweep will consist of
+.Ar count
+packets.
+.It Fl D
+Disable IPv6 fragmentation.
+.It Fl d
+Set the
+.Dv SO_DEBUG
+option on the socket being used.
+.\" .It Fl E
+.\" Enables transport-mode IPsec encapsulated security payload
+.\" (experimental).
+.It Fl f
+Flood ping.
+Outputs packets as fast as they come back or one hundred times per second,
+whichever is more.
+For every
+.Tn ECHO_REQUEST
+sent a period
+.Dq \&.
+is printed, while for every
+.Tn ECHO_REPLY
+received a backspace is printed.
+This provides a rapid display of how many packets are being dropped.
+Only the super-user may use this option.
+.Bf -emphasis
+This can be very hard on a network and should be used with caution.
+.Ef
+.It Fl G Ar sweepmaxsize[,sweepminsize[,sweepincrsize]]
+.Ar sweepmaxsize
+specifies the maximum size of the payload when sending sweeping
+pings and is required for sweeps.
+.Ar sweepminsize
+specifies the size of the payload to start with when sending
+sweeping pings -- the default value is 0.
+.Ar sweepincrsize
+specifies the number of bytes to increment the size of the payload
+after each sweep when sending sweeping pings -- the default value
+is 1.
+This option is an Apple addition.
+.It Fl g Ar gateway
+Specifies to use
+.Ar gateway
+as the next hop to the destination.
+The gateway must be a neighbor of the sending node.
+.It Fl H
+Specifies to try reverse-lookup of IPv6 addresses.
+The
+.Nm
+utility does not try reverse-lookup unless the option is specified.
+.It Fl h Ar hoplimit
+Set the IPv6 hoplimit.
+.It Fl I Ar interface
+Source packets with the given interface address.
+This flag applies if the ping destination is a multicast address,
+or link-local/site-local unicast address.
+.It Fl i Ar wait
+Wait
+.Ar wait
+seconds
+.Em between sending each packet .
+The default is to wait for one second between each packet.
+The wait time may be fractional, but only the super-user may specify
+values less than 0.1 second.
+This option is incompatible with the
+.Fl f
+option.
+.It Fl k Ar trafficclass
+Specifies the traffic class to use for sending ICMPv6 packets.
+The supported traffic classes are
+BK_SYS, BK, BE, RD, OAM, AV, RV, VI, VO and CTL.
+By default
+.Nm
+uses the control traffic class (CTL).
+This option is an Apple addition.
+.It Fl K Ar netservicetype
+Specifies the network service type to use for sending ICMPv6 packets.
+The supported network service type are BK_SYS, BK, BE, RV, AV, RD, OAM, VI, SIG and VO.
+Note this overrides the default traffic class (-k can still be specified after -K to use both).
+This option is an Apple addition.
+.It Fl l Ar preload
+If
+.Ar preload
+is specified,
+.Nm
+sends that many packets as fast as possible before falling into its normal
+mode of behavior.
+Only the super-user may use this option.
+.It Fl m
+By default,
+.Nm
+asks the kernel to fragment packets to fit into the minimum IPv6 MTU.
+The
+.Fl m
+option
+will suppress the behavior in the following two levels:
+when the option is specified once, the behavior will be disabled for
+unicast packets.
+When the option is more than once, it will be disabled for both
+unicast and multicast packets.
+.It Fl n
+Numeric output only.
+No attempt will be made to lookup symbolic names from addresses in the reply.
+.It Fl N
+Probe node information multicast group
+.Pq Li ff02::2:xxxx:xxxx .
+.Ar host
+must be string hostname of the target
+(must not be a numeric IPv6 address).
+Node information multicast group will be computed based on given
+.Ar host ,
+and will be used as the final destination.
+Since node information multicast group is a link-local multicast group,
+outgoing interface needs to be specified by
+.Fl I
+option.
+.It Fl o
+Exit successfully after receiving one reply packet.
+.It Fl p Ar pattern
+You may specify up to 16
+.Dq pad
+bytes to fill out the packet you send.
+This is useful for diagnosing data-dependent problems in a network.
+For example,
+.Dq Li \-p ff
+will cause the sent packet to be filled with all
+ones.
+.\" new ipsec
+.It Fl P Ar policy
+.Ar policy
+specifies IPsec policy to be used for the probe.
+.It Fl q
+Quiet output.
+Nothing is displayed except the summary lines at startup time and
+when finished.
+.It Fl r
+Audible.
+Include a bell
+.Tn ( ASCII
+0x07)
+character in the output when any packet is received.
+.It Fl R
+Audible.
+Output a bell
+.Tn ( ASCII
+0x07)
+character when no packet is received before the next packet
+is transmitted.
+To cater for round-trip times that are longer than the interval
+between transmissions, further missing packets cause a bell only
+if the maximum number of unreceived packets has increased.
+.It Fl S Ar sourceaddr
+Specifies the source address of request packets.
+The source address must be one of the unicast addresses of the sending node,
+and must be numeric.
+.It Fl s Ar packetsize
+Specifies the number of data bytes to be sent.
+The default is 56, which translates into 64
+.Tn ICMP
+data bytes when combined
+with the 8 bytes of
+.Tn ICMP
+header data.
+You may need to specify
+.Fl b
+as well to extend socket buffer size.
+.It Fl t
+Generate ICMPv6 Node Information supported query types query,
+rather than echo-request.
+.Fl s
+has no effect if
+.Fl t
+is specified.
+.It Fl v
+Verbose output.
+.Tn ICMP
+packets other than
+.Tn ECHO_RESPONSE
+that are received are listed.
+.It Fl w
+Generate ICMPv6 Node Information DNS Name query, rather than echo-request.
+.Fl s
+has no effect if
+.Fl w
+is specified.
+.It Fl W
+Same as
+.Fl w ,
+but with old packet format based on 03 draft.
+This option is present for backward compatibility.
+.Fl s
+has no effect if
+.Fl w
+is specified.
+.It Fl z Ar tclass
+Use the specified traffic class.
+.It Fl Fl apple-connect
+Connects the socket to the destination address.
+This option is an Apple addition.
+.It Fl Fl apple-time
+Prints the time a packet was received.
+This option is an Apple addition.
+.It Ar hops
+IPv6 addresses for intermediate nodes,
+which will be put into type 0 routing header.
+.It Ar host
+IPv6 address of the final destination node.
+.El
+.Pp
+When using
+.Nm
+for fault isolation, it should first be run on the local host, to verify
+that the local network interface is up and running.
+Then, hosts and gateways further and further away should be
+.Dq pinged .
+Round-trip times and packet loss statistics are computed.
+If duplicate packets are received, they are not included in the packet
+loss calculation, although the round trip time of these packets is used
+in calculating the round-trip time statistics.
+When the specified number of packets have been sent
+(and received)
+or if the program is terminated with a
+.Dv SIGINT ,
+a brief summary is displayed, showing the number of packets sent and
+received, and the minimum, mean, maximum, and standard deviation of
+the round-trip times.
+.Pp
+If
+.Nm
+receives a
+.Dv SIGINFO
+(see the
+.Cm status
+argument for
+.Xr stty 1 )
+signal, the current number of packets sent and received, and the
+minimum, mean, maximum, and standard deviation of the round-trip times
+will be written to the standard output in the same format as the
+standard completion message.
+.Pp
+This program is intended for use in network testing, measurement and
+management.
+Because of the load it can impose on the network, it is unwise to use
+.Nm
+during normal operations or from automated scripts.
+.\" .Sh ICMP PACKET DETAILS
+.\" An IP header without options is 20 bytes.
+.\" An
+.\" .Tn ICMP
+.\" .Tn ECHO_REQUEST
+.\" packet contains an additional 8 bytes worth of
+.\" .Tn ICMP
+.\" header followed by an arbitrary amount of data.
+.\" When a
+.\" .Ar packetsize
+.\" is given, this indicated the size of this extra piece of data
+.\" (the default is 56).
+.\" Thus the amount of data received inside of an IP packet of type
+.\" .Tn ICMP
+.\" .Tn ECHO_REPLY
+.\" will always be 8 bytes more than the requested data space
+.\" (the
+.\" .Tn ICMP
+.\" header).
+.\" .Pp
+.\" If the data space is at least eight bytes large,
+.\" .Nm
+.\" uses the first eight bytes of this space to include a timestamp which
+.\" it uses in the computation of round trip times.
+.\" If less than eight bytes of pad are specified, no round trip times are
+.\" given.
+.Sh DUPLICATE AND DAMAGED PACKETS
+The
+.Nm
+utility will report duplicate and damaged packets.
+Duplicate packets should never occur when pinging a unicast address,
+and seem to be caused by
+inappropriate link-level retransmissions.
+Duplicates may occur in many situations and are rarely
+(if ever)
+a good sign, although the presence of low levels of duplicates may not
+always be cause for alarm.
+Duplicates are expected when pinging a broadcast or multicast address,
+since they are not really duplicates but replies from different hosts
+to the same request.
+.Pp
+Damaged packets are obviously serious cause for alarm and often
+indicate broken hardware somewhere in the
+.Nm
+packet's path
+(in the network or in the hosts).
+.Sh TRYING DIFFERENT DATA PATTERNS
+The
+(inter)network
+layer should never treat packets differently depending on the data
+contained in the data portion.
+Unfortunately, data-dependent problems have been known to sneak into
+networks and remain undetected for long periods of time.
+In many cases the particular pattern that will have problems is something
+that does not have sufficient
+.Dq transitions ,
+such as all ones or all zeros, or a pattern right at the edge, such as
+almost all zeros.
+It is not
+necessarily enough to specify a data pattern of all zeros (for example)
+on the command line because the pattern that is of interest is
+at the data link level, and the relationship between what you type and
+what the controllers transmit can be complicated.
+.Pp
+This means that if you have a data-dependent problem you will probably
+have to do a lot of testing to find it.
+If you are lucky, you may manage to find a file that either
+cannot
+be sent across your network or that takes much longer to transfer than
+other similar length files.
+You can then examine this file for repeated patterns that you can test
+using the
+.Fl p
+option of
+.Nm .
+.Sh EXIT STATUS
+The
+.Nm
+utility returns 0 on success (the host is alive),
+2 if the transmission was successful but no responses were received,
+any other non-zero value if the arguments are incorrect or
+another error has occurred.
+.Sh EXAMPLES
+Normally,
+.Nm
+works just like
+.Xr ping 8
+would work; the following will send ICMPv6 echo request to
+.Li dst.foo.com .
+.Bd -literal -offset indent
+ping6 -n dst.foo.com
+.Ed
+.Pp
+The following will probe hostnames for all nodes on the network link attached to
+.Li wi0
+interface.
+The address
+.Li ff02::1
+is named the link-local all-node multicast address, and the packet would
+reach every node on the network link.
+.Bd -literal -offset indent
+ping6 -w ff02::1%wi0
+.Ed
+.Pp
+The following will probe addresses assigned to the destination node,
+.Li dst.foo.com .
+.Bd -literal -offset indent
+ping6 -a agl dst.foo.com
+.Ed
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr icmp6 4 ,
+.Xr inet6 4 ,
+.Xr ip6 4 ,
+.Xr ifconfig 8 ,
+.Xr ping 8 ,
+.Xr routed 8 ,
+.Xr traceroute 8 ,
+.Xr traceroute6 8
+.Rs
+.%A A. Conta
+.%A S. Deering
+.%T "Internet Control Message Protocol (ICMPv6) for the Internet Protocol Version 6 (IPv6) Specification"
+.%N RFC2463
+.%D December 1998
+.Re
+.Rs
+.%A Matt Crawford
+.%T "IPv6 Node Information Queries"
+.%N draft-ietf-ipngwg-icmp-name-lookups-09.txt
+.%D May 2002
+.%O work in progress material
+.Re
+.Sh HISTORY
+The
+.Xr ping 8
+utility appeared in
+.Bx 4.3 .
+The
+.Nm
+utility with IPv6 support first appeared in the WIDE Hydrangea IPv6
+protocol stack kit.
+.Pp
+IPv6 and IPsec support based on the KAME Project
+.Pq Pa http://www.kame.net/
+stack was initially integrated into
+.Fx 4.0 .
+.Sh BUGS
+The
+.Nm
+utility
+is intentionally separate from
+.Xr ping 8 .
+.Pp
+There have been many discussions on why we separate
+.Nm
+and
+.Xr ping 8 .
+Some people argued that it would be more convenient to uniform the
+ping command for both IPv4 and IPv6.
+The followings are an answer to the request.
+.Pp
+From a developer's point of view:
+since the underling raw sockets API is totally different between IPv4
+and IPv6, we would end up having two types of code base.
+There would actually be less benefit to uniform the two commands
+into a single command from the developer's standpoint.
+.Pp
+From an operator's point of view: unlike ordinary network applications
+like remote login tools, we are usually aware of address family when using
+network management tools.
+We do not just want to know the reachability to the host, but want to know the
+reachability to the host via a particular network protocol such as
+IPv6.
+Thus, even if we had a unified
+.Xr ping 8
+command for both IPv4 and IPv6, we would usually type a
+.Fl 6
+or
+.Fl 4
+option (or something like those) to specify the particular address family.
+This essentially means that we have two different commands.
diff --git a/network_cmds/ping6.tproj/ping6.c b/network_cmds/ping6.tproj/ping6.c
new file mode 100644
index 0000000..7890e66
--- /dev/null
+++ b/network_cmds/ping6.tproj/ping6.c
@@ -0,0 +1,3340 @@
+/*
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Muuss.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
+ * measure round-trip-delays and packet loss across network paths.
+ *
+ * Author -
+ * Mike Muuss
+ * U. S. Army Ballistic Research Laboratory
+ * December, 1983
+ *
+ * Status -
+ * Public Domain. Distribution Unlimited.
+ * Bugs -
+ * More statistics could always be gathered.
+ * This program has to run SUID to ROOT to access the ICMP socket.
+ */
+/*
+ * NOTE:
+ * USE_SIN6_SCOPE_ID assumes that sin6_scope_id has the same semantics
+ * as IPV6_PKTINFO. Some people object it (sin6_scope_id specifies *link*
+ * while IPV6_PKTINFO specifies *interface*. Link is defined as collection of
+ * network attached to 1 or more interfaces)
+ */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/route.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <math.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysexits.h>
+#include <getopt.h>
+
+#ifdef IPSEC
+#include <netinet6/ah.h>
+#include <netinet6/ipsec.h>
+#endif
+
+#include "md5.h"
+
+struct tv32 {
+ u_int32_t tv32_sec;
+ u_int32_t tv32_usec;
+};
+
+#define MAXPACKETLEN 131072
+#define IP6LEN 40
+#define ICMP6ECHOLEN 8 /* icmp echo header len excluding time */
+#define ICMP6ECHOTMLEN sizeof(struct tv32)
+#define ICMP6_NIQLEN (ICMP6ECHOLEN + 8)
+# define CONTROLLEN 10240 /* ancillary data buffer size RFC3542 20.1 */
+/* FQDN case, 64 bits of nonce + 32 bits ttl */
+#define ICMP6_NIRLEN (ICMP6ECHOLEN + 12)
+#define EXTRA 256 /* for AH and various other headers. weird. */
+#define DEFDATALEN ICMP6ECHOTMLEN
+#define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN
+#define NROUTES 9 /* number of record route slots */
+#define MAXWAIT 10000 /* max ms to wait for response */
+#define MAXALARM (60 * 60) /* max seconds for alarm timeout */
+
+#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
+#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
+#define SET(bit) (A(bit) |= B(bit))
+#define CLR(bit) (A(bit) &= (~B(bit)))
+#define TST(bit) (A(bit) & B(bit))
+
+#define F_FLOOD 0x0001
+#define F_INTERVAL 0x0002
+#define F_PINGFILLED 0x0008
+#define F_QUIET 0x0010
+#define F_RROUTE 0x0020
+#define F_SO_DEBUG 0x0040
+#define F_PRTIME 0x0080
+#define F_VERBOSE 0x0100
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+#define F_POLICY 0x0400
+#else
+#define F_AUTHHDR 0x0200
+#define F_ENCRYPT 0x0400
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+#define F_NODEADDR 0x0800
+#define F_FQDN 0x1000
+#define F_INTERFACE 0x2000
+#define F_SRCADDR 0x4000
+#define F_HOSTNAME 0x10000
+#define F_FQDNOLD 0x20000
+#define F_NIGROUP 0x40000
+#define F_SUPTYPES 0x80000
+#define F_NOMINMTU 0x100000
+#define F_ONCE 0x200000
+#define F_AUDIBLE 0x400000
+#define F_MISSED 0x800000
+#define F_DONTFRAG 0x1000000
+#define F_SWEEP 0x2000000
+#define F_CONNECT 0x4000000
+#define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES)
+#define F_WAITTIME 0x8000000
+u_int options;
+
+static int longopt_flag = 0;
+
+#define LOF_CONNECT 0x01
+#define LOF_PRTIME 0x02
+
+static const struct option longopts[] = {
+ { "apple-connect", no_argument, &longopt_flag, LOF_CONNECT },
+ { "apple-time", no_argument, &longopt_flag, LOF_PRTIME },
+ { NULL, 0, NULL, 0 }
+};
+
+#define IN6LEN sizeof(struct in6_addr)
+#define SA6LEN sizeof(struct sockaddr_in6)
+#define DUMMY_PORT 10101
+
+#define SIN6(s) ((struct sockaddr_in6 *)(s))
+
+#define MAXTOS 255
+/*
+ * MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
+ * number of received sequence numbers we can keep track of. Change 128
+ * to 8192 for complete accuracy...
+ */
+#define MAX_DUP_CHK (8 * 8192)
+int mx_dup_ck = MAX_DUP_CHK;
+char rcvd_tbl[MAX_DUP_CHK / 8];
+
+struct addrinfo *res;
+struct sockaddr_in6 dst; /* who to ping6 */
+struct sockaddr_in6 src; /* src addr of this packet */
+socklen_t srclen;
+int datalen = DEFDATALEN;
+int s; /* socket file descriptor */
+u_char outpack[MAXPACKETLEN];
+char BSPACE = '\b'; /* characters written for flood */
+char BBELL = '\a'; /* characters written for AUDIBLE */
+char DOT = '.';
+char *hostname;
+int ident; /* process id to identify our packets */
+u_int8_t nonce[8]; /* nonce field for node information */
+int hoplimit = -1; /* hoplimit */
+int pathmtu = 0; /* path MTU for the destination. 0 = unspec. */
+u_char *packet = NULL;
+struct cmsghdr *cm = NULL;
+char *boundif;
+unsigned int ifscope;
+int nocell;
+
+/* counters */
+long nmissedmax; /* max value of ntransmitted - nreceived - 1 */
+long npackets; /* max packets to transmit */
+long nreceived; /* # of packets we got back */
+long nrepeats; /* number of duplicates */
+long ntransmitted; /* sequence # for outbound packets = #sent */
+static int interval = 1000; /* interval between packets in ms */
+static int waittime = MAXWAIT; /* timeout for each packet */
+static long nrcvtimeout = 0; /* # of packets we got back after waittime */
+
+long snpackets = 0; /* max packets to transmit in one sweep */
+long sntransmitted = 0; /* # of packets we sent in this sweep */
+int sweepmax = 0; /* max value of payload in sweep */
+int sweepmin = 0; /* start value of payload in sweep */
+int sweepincr = 1; /* payload increment in sweep */
+
+/* timing */
+int timing; /* flag to do timing */
+double tmin = 999999999.0; /* minimum round trip time */
+double tmax = 0.0; /* maximum round trip time */
+double tsum = 0.0; /* sum of all times, for doing average */
+double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
+
+/* for node addresses */
+u_short naflags;
+
+/* for ancillary data(advanced API) */
+struct msghdr smsghdr;
+struct iovec smsgiov[2];
+char *scmsg = NULL;
+
+volatile sig_atomic_t seenalrm;
+volatile sig_atomic_t seenint;
+#ifdef SIGINFO
+volatile sig_atomic_t seeninfo;
+#endif
+
+int rcvtclass = 0;
+
+int use_sendmsg = 0;
+int use_recvmsg = 0;
+int so_traffic_class = SO_TC_CTL; /* use control class, by default */
+int net_service_type = -1;
+
+int32_t thiszone; /* seconds offset from gmt to local time */
+extern int32_t gmt2local(time_t);
+static void pr_currenttime(void);
+
+int main(int, char *[]);
+void fill(char *, char *);
+int get_hoplim(struct msghdr *);
+int get_pathmtu(struct msghdr *);
+int get_tclass(struct msghdr *);
+int get_so_traffic_class(struct msghdr *);
+struct in6_pktinfo *get_rcvpktinfo(struct msghdr *);
+void onsignal(int);
+void onint(int);
+size_t pingerlen(void);
+int pinger(void);
+const char *pr_addr(struct sockaddr *, int);
+void pr_icmph(struct icmp6_hdr *, u_char *);
+void pr_iph(struct ip6_hdr *);
+void pr_suptypes(struct icmp6_nodeinfo *, size_t);
+void pr_nodeaddr(struct icmp6_nodeinfo *, int);
+int myechoreply(const struct icmp6_hdr *);
+int mynireply(const struct icmp6_nodeinfo *);
+char *dnsdecode(const u_char **, const u_char *, const u_char *,
+ char *, size_t);
+void pr_pack(u_char *, int, struct msghdr *);
+void pr_exthdrs(struct msghdr *);
+void pr_ip6opt(void *, size_t);
+void pr_rthdr(void *, size_t);
+int pr_bitrange(u_int32_t, int, int);
+void pr_retip(struct ip6_hdr *, u_char *);
+void summary(void);
+void tvsub(struct timeval *, struct timeval *);
+int setpolicy(int, char *);
+char *nigroup(char *, int);
+static int str2sotc(const char *, bool *);
+static int str2netservicetype(const char *, bool *);
+static u_int8_t str2tclass(const char *, bool *);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct timeval last, intvl;
+ struct sockaddr_in6 from;
+ struct addrinfo hints;
+ int cc, i;
+ int almost_done, ch, hold, packlen, preload, optval, ret_ga;
+ int nig_oldmcprefix = -1;
+ u_char *datap;
+ char *e, *target, *ifname = NULL, *gateway = NULL;
+ int ip6optlen = 0;
+ struct cmsghdr *scmsgp = NULL;
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ u_long lsockbufsize;
+ int sockbufsize = 0;
+#endif
+ int usepktinfo = 0;
+ struct in6_pktinfo *pktinfo = NULL;
+#ifdef USE_RFC2292BIS
+ struct ip6_rthdr *rthdr = NULL;
+#endif
+#ifdef IPSEC_POLICY_IPSEC
+ char *policy_in = NULL;
+ char *policy_out = NULL;
+#endif
+ double t;
+ u_long alarmtimeout;
+ size_t rthlen;
+#ifdef IPV6_USE_MIN_MTU
+ int mflag = 0;
+#endif
+ /* T_CLASS value -1 means default, so -2 means do not bother */
+ int tclass = -2;
+ bool valid;
+
+ /* just to be sure */
+ memset(&smsghdr, 0, sizeof(smsghdr));
+ memset(&smsgiov, 0, sizeof(smsgiov));
+
+ preload = 0;
+ datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN];
+#ifndef IPSEC
+#define ADDOPTS
+#else
+#ifdef IPSEC_POLICY_IPSEC
+#define ADDOPTS "P:"
+#else
+#define ADDOPTS "AE"
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif
+ while ((ch = getopt_long(argc, argv,
+ "a:b:B:Cc:DdfHG:g:h:I:i:k:K:l:mnNop:qrRS:s:tvwWz:" ADDOPTS,
+ longopts, NULL)) != -1) {
+#undef ADDOPTS
+ switch (ch) {
+ case 'a':
+ {
+ char *cp;
+
+ options &= ~F_NOUSERDATA;
+ options |= F_NODEADDR;
+ for (cp = optarg; *cp != '\0'; cp++) {
+ switch (*cp) {
+ case 'a':
+ naflags |= NI_NODEADDR_FLAG_ALL;
+ break;
+ case 'c':
+ case 'C':
+ naflags |= NI_NODEADDR_FLAG_COMPAT;
+ break;
+ case 'l':
+ case 'L':
+ naflags |= NI_NODEADDR_FLAG_LINKLOCAL;
+ break;
+ case 's':
+ case 'S':
+ naflags |= NI_NODEADDR_FLAG_SITELOCAL;
+ break;
+ case 'g':
+ case 'G':
+ naflags |= NI_NODEADDR_FLAG_GLOBAL;
+ break;
+ case 'A': /* experimental. not in the spec */
+#ifdef NI_NODEADDR_FLAG_ANYCAST
+ naflags |= NI_NODEADDR_FLAG_ANYCAST;
+ break;
+#else
+ errx(1, "-a A is not supported on "
+ "the platform");
+ /*NOTREACHED*/
+#endif
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ break;
+ }
+ case 'b':
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ errno = 0;
+ e = NULL;
+ lsockbufsize = strtoul(optarg, &e, 10);
+ sockbufsize = lsockbufsize;
+ if (errno || !*optarg || *e ||
+ sockbufsize != lsockbufsize)
+ errx(1, "invalid socket buffer size");
+#else
+ errx(1, "-b option ignored: SO_SNDBUF/SO_RCVBUF "
+ "socket options not supported");
+#endif
+ break;
+ case 'B':
+ boundif = optarg;
+ break;
+ case 'C':
+ nocell++;
+ break;
+ case 'c':
+ npackets = strtol(optarg, &e, 10);
+ if (npackets <= 0 || *optarg == '\0' || *e != '\0')
+ errx(1,
+ "illegal number of packets -- %s", optarg);
+ break;
+ case 'D':
+ options |= F_DONTFRAG;
+ break;
+ case 'd':
+ options |= F_SO_DEBUG;
+ break;
+ case 'f':
+ if (getuid()) {
+ errno = EPERM;
+ errx(1, "Must be superuser to flood ping");
+ }
+ options |= F_FLOOD;
+ setbuf(stdout, (char *)NULL);
+ break;
+ case 'g':
+ gateway = optarg;
+ break;
+ case 'G': {
+ char *ptr ;
+ char *tofree;
+ unsigned long ultmp;
+
+ tofree = strdup(optarg);
+ if (tofree == NULL)
+ errx(1, "### strdup() failed");
+ ptr = tofree;
+ do {
+ char *str;
+ char *ep;
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ errx(1, "-G requires maximum packet size");
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid maximum packet size: `%s'",
+ str);
+ options |= F_SWEEP;
+ sweepmax = ultmp;
+ if (sweepmax < 1 || sweepmax > MAXDATALEN) {
+ errx(1,
+ "-G invalid maximum packet size, needs to be between 1 and %d",
+ MAXDATALEN);
+ }
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ break;
+ if (*str != 0) {
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid minimum packet size: `%s'",
+ str);
+ sweepmin = ultmp;
+ if (sweepmin < 0 || sweepmin > MAXDATALEN) {
+ errx(1,
+ "-G invalid minimum packet size, needs to be between 0 and %d",
+ MAXDATALEN);
+ }
+ }
+
+ if ((str = strsep(&ptr, ",")) == NULL)
+ break;
+ if (*str == 0)
+ break;
+ ultmp = strtoul(str, &ep, 0);
+ if (*ep || ep == optarg)
+ errx(EX_USAGE, "option -G invalid sweep increment size: `%s'",
+ str);
+ sweepincr = ultmp;
+ if (sweepincr < 1 || sweepincr > MAXDATALEN) {
+ errx(1,
+ "-G invalid sweep increment size, needs to be between 1 and %d",
+ MAXDATALEN);
+ }
+ } while (0);
+ free(tofree);
+ break;
+ }
+ case 'H':
+ options |= F_HOSTNAME;
+ break;
+ case 'h': /* hoplimit */
+ hoplimit = strtol(optarg, &e, 10);
+ if (*optarg == '\0' || *e != '\0')
+ errx(1, "illegal hoplimit %s", optarg);
+ if (255 < hoplimit || hoplimit < -1)
+ errx(1,
+ "illegal hoplimit -- %s", optarg);
+ break;
+ case 'I':
+ ifname = optarg;
+ options |= F_INTERFACE;
+#ifndef USE_SIN6_SCOPE_ID
+ usepktinfo++;
+#endif
+ break;
+ case 'i': /* wait between sending packets */
+ t = strtod(optarg, &e);
+ if (*optarg == '\0' || *e != '\0')
+ errx(1, "illegal timing interval %s", optarg);
+ if (t < 0.1 && getuid()) {
+ errx(1, "%s: only root may use interval < 1s",
+ strerror(EPERM));
+ }
+ intvl.tv_sec = (long)t;
+ intvl.tv_usec =
+ (long)((t - intvl.tv_sec) * 1000000);
+ if (intvl.tv_sec < 0)
+ errx(1, "illegal timing interval %s", optarg);
+ /* less than 1/hz does not make sense */
+ if (intvl.tv_sec == 0 && intvl.tv_usec < 1) {
+ warnx("too small interval, raised to .000001");
+ intvl.tv_usec = 1;
+ }
+ options |= F_INTERVAL;
+ break;
+ case 'k':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ if (strcasecmp(optarg, "recvmsg") == 0) {
+ use_recvmsg++;
+ break;
+ }
+ so_traffic_class = str2sotc(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad traffic class: `%s'",
+ optarg);
+ break;
+ case 'K':
+ if (strcasecmp(optarg, "sendmsg") == 0) {
+ use_sendmsg++;
+ break;
+ }
+ net_service_type = str2netservicetype(optarg, &valid);
+ if (valid == false)
+ errx(EX_USAGE, "bad network service type: `%s'",
+ optarg);
+ /* suppress default traffic class (-k can still be specified after -K) */
+ so_traffic_class = -1;
+ break;
+ case 'l':
+ if (getuid()) {
+ errno = EPERM;
+ errx(1, "Must be superuser to preload");
+ }
+ preload = strtol(optarg, &e, 10);
+ if (preload < 0 || *optarg == '\0' || *e != '\0')
+ errx(1, "illegal preload value -- %s", optarg);
+ break;
+ case 'm':
+#ifdef IPV6_USE_MIN_MTU
+ mflag++;
+ break;
+#else
+ errx(1, "-%c is not supported on this platform", ch);
+ /*NOTREACHED*/
+#endif
+ case 'n':
+ options &= ~F_HOSTNAME;
+ break;
+ case 'N':
+ options |= F_NIGROUP;
+ nig_oldmcprefix++;
+ break;
+ case 'o':
+ options |= F_ONCE;
+ break;
+ case 'p': /* fill buffer with user pattern */
+ options |= F_PINGFILLED;
+ fill((char *)datap, optarg);
+ break;
+ case 'q':
+ options |= F_QUIET;
+ break;
+ case 'r':
+ options |= F_AUDIBLE;
+ break;
+ case 'R':
+ options |= F_MISSED;
+ break;
+ case 'S':
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_NUMERICHOST; /* allow hostname? */
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = IPPROTO_ICMPV6;
+
+ ret_ga = getaddrinfo(optarg, NULL, &hints, &res);
+ if (ret_ga) {
+ errx(1, "invalid source address: %s",
+ gai_strerror(ret_ga));
+ }
+ /*
+ * res->ai_family must be AF_INET6 and res->ai_addrlen
+ * must be sizeof(src).
+ */
+ memcpy(&src, res->ai_addr, res->ai_addrlen);
+ srclen = res->ai_addrlen;
+ freeaddrinfo(res);
+ res = NULL;
+ options |= F_SRCADDR;
+ break;
+ case 's': /* size of packet to send */
+ datalen = strtol(optarg, &e, 10);
+ if (datalen <= 0 || *optarg == '\0' || *e != '\0')
+ errx(1, "illegal datalen value -- %s", optarg);
+ if (datalen > MAXDATALEN) {
+ errx(1,
+ "datalen value too large, maximum is %d",
+ MAXDATALEN);
+ }
+ break;
+ case 't':
+ options &= ~F_NOUSERDATA;
+ options |= F_SUPTYPES;
+ break;
+ case 'v':
+ options |= F_VERBOSE;
+ break;
+ case 'w':
+ options &= ~F_NOUSERDATA;
+ options |= F_FQDN;
+ break;
+ case 'W':
+ options &= ~F_NOUSERDATA;
+ options |= F_FQDNOLD;
+ break;
+ case 'z':
+ tclass = str2tclass(optarg, &valid);
+ if (valid == false)
+ errx(1, "illegal TOS value -- %s", optarg);
+ rcvtclass = 1;
+ break;
+ case 'X':
+ alarmtimeout = strtoul(optarg, &e, 0);
+ if (alarmtimeout < 1 || alarmtimeout == ULONG_MAX)
+ errx(EX_USAGE, "invalid timeout: `%s'",
+ optarg);
+ if (alarmtimeout > MAXALARM)
+ errx(EX_USAGE, "invalid timeout: `%s' > %d",
+ optarg, MAXALARM);
+ alarm((int)alarmtimeout);
+ break;
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ case 'P':
+ options |= F_POLICY;
+ if (!strncmp("in", optarg, 2)) {
+ if ((policy_in = strdup(optarg)) == NULL)
+ errx(1, "strdup");
+ } else if (!strncmp("out", optarg, 3)) {
+ if ((policy_out = strdup(optarg)) == NULL)
+ errx(1, "strdup");
+ } else
+ errx(1, "invalid security policy");
+ break;
+#else
+ case 'A':
+ options |= F_AUTHHDR;
+ break;
+ case 'E':
+ options |= F_ENCRYPT;
+ break;
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+ case 0:
+ switch (longopt_flag) {
+ case LOF_CONNECT:
+ options |= F_CONNECT;
+ break;
+ case LOF_PRTIME:
+ options |= F_PRTIME;
+ thiszone = gmt2local(0);
+ break;
+ default:
+ break;
+ }
+ longopt_flag = 0;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+
+ if (boundif != NULL && (ifscope = if_nametoindex(boundif)) == 0)
+ errx(1, "bad interface name");
+
+ if ((options & F_SWEEP) && !sweepmax)
+ errx(EX_USAGE, "Maximum sweep size must be specified");
+
+ if ((options & F_SWEEP) && (options & F_NOUSERDATA))
+ errx(EX_USAGE, "Option -G incompatible with -t, -w and -W");
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ usage();
+ /*NOTREACHED*/
+ }
+
+ if (argc > 1) {
+#ifdef IPV6_RECVRTHDR /* 2292bis */
+ rthlen = CMSG_SPACE(inet6_rth_space(IPV6_RTHDR_TYPE_0,
+ argc - 1));
+#else /* RFC2292 */
+ rthlen = inet6_rthdr_space(IPV6_RTHDR_TYPE_0, argc - 1);
+#endif
+ if (rthlen == 0) {
+ errx(1, "too many intermediate hops");
+ /*NOTREACHED*/
+ }
+ ip6optlen += rthlen;
+ }
+
+ if (options & F_NIGROUP) {
+ target = nigroup(argv[argc - 1], nig_oldmcprefix);
+ if (target == NULL) {
+ usage();
+ /*NOTREACHED*/
+ }
+ } else
+ target = argv[argc - 1];
+
+ /* getaddrinfo */
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = IPPROTO_ICMPV6;
+
+ ret_ga = getaddrinfo(target, NULL, &hints, &res);
+ if (ret_ga)
+ errx(1, "getaddrinfo -- %s", gai_strerror(ret_ga));
+ if (res->ai_canonname)
+ hostname = strdup(res->ai_canonname);
+ else
+ hostname = target;
+
+ if (!res->ai_addr)
+ errx(1, "getaddrinfo failed");
+
+ (void)memcpy(&dst, res->ai_addr, res->ai_addrlen);
+
+ res->ai_socktype = getuid() ? SOCK_DGRAM : SOCK_RAW;
+ res->ai_protocol = IPPROTO_ICMPV6;
+
+ if ((s = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol)) < 0)
+ err(1, "socket");
+
+ if (ifscope != 0) {
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF,
+ (char *)&ifscope, sizeof (ifscope)) != 0)
+ err(1, "setsockopt(IPV6_BOUND_IF)");
+ }
+
+ if (nocell != 0) {
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_NO_IFT_CELLULAR,
+ (char *)&nocell, sizeof (nocell)) != 0)
+ err(1, "setsockopt(IPV6_NO_IFT_CELLULAR)");
+ }
+
+ /* set the source address if specified. */
+ if ((options & F_SRCADDR) &&
+ bind(s, (struct sockaddr *)&src, srclen) != 0) {
+ err(1, "bind");
+ }
+
+ /* set the gateway (next hop) if specified */
+ if (gateway) {
+ struct addrinfo ghints, *gres;
+ int error;
+
+ memset(&ghints, 0, sizeof(ghints));
+ ghints.ai_family = AF_INET6;
+ ghints.ai_socktype = SOCK_RAW;
+ ghints.ai_protocol = IPPROTO_ICMPV6;
+
+ error = getaddrinfo(gateway, NULL, &hints, &gres);
+ if (error) {
+ errx(1, "getaddrinfo for the gateway %s: %s",
+ gateway, gai_strerror(error));
+ }
+ if (gres->ai_next && (options & F_VERBOSE))
+ warnx("gateway resolves to multiple addresses");
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP,
+ gres->ai_addr, gres->ai_addrlen)) {
+ err(1, "setsockopt(IPV6_NEXTHOP)");
+ }
+
+ freeaddrinfo(gres);
+ }
+
+ /*
+ * let the kerel pass extension headers of incoming packets,
+ * for privileged socket options
+ */
+ if ((options & F_VERBOSE) != 0) {
+ int opton = 1;
+
+#ifdef IPV6_RECVHOPOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVHOPOPTS)");
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_HOPOPTS)");
+#endif
+#ifdef IPV6_RECVDSTOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVDSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVDSTOPTS)");
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_DSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_DSTOPTS)");
+#endif
+#ifdef IPV6_RECVRTHDRDSTOPTS
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDRDSTOPTS, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVRTHDRDSTOPTS)");
+#endif
+ }
+
+ /* revoke root privilege */
+ if (seteuid(getuid()) != 0)
+ err(1, "seteuid() failed");
+ if (setuid(getuid()) != 0)
+ err(1, "setuid() failed");
+
+ if ((options & F_FLOOD) && (options & F_INTERVAL))
+ errx(1, "-f and -i incompatible options");
+
+ if ((options & F_CONNECT)) {
+ if (connect(s, (struct sockaddr *)&dst, sizeof(dst)) == -1)
+ err(EX_OSERR, "connect");
+ }
+
+ if (sweepmax) {
+ if (sweepmin >= sweepmax)
+ errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size");
+
+ if (datalen != DEFDATALEN)
+ errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive");
+
+ if (npackets > 0) {
+ snpackets = npackets;
+ npackets = 0;
+ } else
+ snpackets = 1;
+ datalen = sweepmin;
+ }
+
+ if ((options & F_NOUSERDATA) == 0) {
+ if (datalen >= sizeof(struct tv32)) {
+ /* we can time transfer */
+ timing = 1;
+ } else
+ timing = 0;
+ /* in F_VERBOSE case, we may get non-echoreply packets*/
+ if (options & F_VERBOSE)
+ packlen = MAX(2048, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA;
+ else
+ packlen = MAX(datalen, sweepmax) + IP6LEN + ICMP6ECHOLEN + EXTRA;
+ } else {
+ /* suppress timing for node information query */
+ timing = 0;
+ datalen = 2048;
+ packlen = 2048 + IP6LEN + ICMP6ECHOLEN + EXTRA;
+ }
+
+ if (!(packet = (u_char *)malloc(packlen)))
+ err(1, "Unable to allocate packet");
+ if (!(options & F_PINGFILLED))
+ for (i = ICMP6ECHOLEN; i < MAX(datalen, sweepmax); ++i)
+ *datap++ = i;
+
+ ident = getpid() & 0xFFFF;
+ arc4random_buf(nonce, sizeof(nonce));
+ optval = 1;
+ if (options & F_DONTFRAG)
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG,
+ &optval, sizeof(optval)) == -1)
+ err(1, "IPV6_DONTFRAG");
+ hold = 1;
+
+ if (options & F_SO_DEBUG)
+ (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
+ sizeof(hold));
+
+ hold = 1;
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&hold,
+ sizeof(hold));
+
+ optval = IPV6_DEFHLIM;
+ if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ &optval, sizeof(optval)) == -1)
+ err(1, "IPV6_MULTICAST_HOPS");
+#ifdef IPV6_USE_MIN_MTU
+ if (mflag != 1) {
+ optval = mflag > 1 ? 0 : 1;
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_USE_MIN_MTU)");
+ }
+#ifdef IPV6_RECVPATHMTU
+ else {
+ optval = 1;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPATHMTU,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_RECVPATHMTU)");
+ }
+#endif /* IPV6_RECVPATHMTU */
+#endif /* IPV6_USE_MIN_MTU */
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ if (options & F_POLICY) {
+ if (setpolicy(s, policy_in) < 0)
+ errx(1, "%s", ipsec_strerror());
+ if (setpolicy(s, policy_out) < 0)
+ errx(1, "%s", ipsec_strerror());
+ }
+#else
+ if (options & F_AUTHHDR) {
+ optval = IPSEC_LEVEL_REQUIRE;
+#ifdef IPV6_AUTH_TRANS_LEVEL
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_AUTH_TRANS_LEVEL)");
+#else /* old def */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_AUTH_LEVEL,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_AUTH_LEVEL)");
+#endif
+ }
+ if (options & F_ENCRYPT) {
+ optval = IPSEC_LEVEL_REQUIRE;
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL,
+ &optval, sizeof(optval)) == -1)
+ err(1, "setsockopt(IPV6_ESP_TRANS_LEVEL)");
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif
+
+#ifdef ICMP6_FILTER
+ {
+ struct icmp6_filter filt;
+ if (!(options & F_VERBOSE)) {
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ if ((options & F_FQDN) || (options & F_FQDNOLD) ||
+ (options & F_NODEADDR) || (options & F_SUPTYPES))
+ ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt);
+ else
+ ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
+ } else {
+ ICMP6_FILTER_SETPASSALL(&filt);
+ }
+ if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) < 0)
+ err(1, "setsockopt(ICMP6_FILTER)");
+ }
+#endif /*ICMP6_FILTER*/
+
+ /* let the kerel pass extension headers of incoming packets */
+ if ((options & F_VERBOSE) != 0) {
+ int opton = 1;
+
+#ifdef IPV6_RECVRTHDR
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVRTHDR, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RECVRTHDR)");
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RTHDR, &opton,
+ sizeof(opton)))
+ err(1, "setsockopt(IPV6_RTHDR)");
+#endif
+ }
+
+ if (tclass != -2) {
+ int on = 1;
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVTCLASS, &on,
+ sizeof(on)))
+ err(1, "setsockopt(IPV6_RECVTCLASS)");
+
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &tclass,
+ sizeof(tclass)))
+ err(1, "setsockopt(IPV6_TCLASS)");
+ }
+
+/*
+ optval = 1;
+ if (IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
+ &optval, sizeof(optval)) == -1)
+ err(1, "IPV6_MULTICAST_LOOP");
+*/
+
+ /* Specify the outgoing interface and/or the source address */
+ if (usepktinfo)
+ ip6optlen += CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+ if (hoplimit != -1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+
+#ifdef IPV6_USE_MIN_MTU
+ if (mflag != 1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+#endif /* IPV6_USE_MIN_MTU */
+
+ if (tclass != -2)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+
+ if (use_sendmsg == 0) {
+ if (net_service_type != -1)
+ if (setsockopt(s, SOL_SOCKET, SO_NET_SERVICE_TYPE,
+ (void *)&net_service_type, sizeof (net_service_type)) != 0)
+ warn("setsockopt(SO_NET_SERVICE_TYPE");
+ if (so_traffic_class != -1) {
+ if (setsockopt(s, SOL_SOCKET, SO_TRAFFIC_CLASS,
+ (void *)&so_traffic_class, sizeof (so_traffic_class)) != 0)
+ warn("setsockopt(SO_TRAFFIC_CLASS");
+
+ }
+ } else {
+ if (net_service_type != -1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+ if (so_traffic_class != -1)
+ ip6optlen += CMSG_SPACE(sizeof(int));
+ }
+ if (use_recvmsg > 0) {
+ int on = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_RECV_TRAFFIC_CLASS,
+ (void *)&on, sizeof (on)) != 0)
+ warn("setsockopt(SO_RECV_TRAFFIC_CLASS");
+ }
+
+ /* set IP6 packet options */
+ if (ip6optlen) {
+ if ((scmsg = (char *)malloc(ip6optlen)) == 0)
+ errx(1, "can't allocate enough memory");
+ smsghdr.msg_control = (caddr_t)scmsg;
+ smsghdr.msg_controllen = ip6optlen;
+ scmsgp = (struct cmsghdr *)scmsg;
+ }
+ if (usepktinfo) {
+ pktinfo = (struct in6_pktinfo *)(CMSG_DATA(scmsgp));
+ memset(pktinfo, 0, sizeof(*pktinfo));
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_PKTINFO;
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+
+ /* set the outgoing interface */
+ if (ifname) {
+#ifndef USE_SIN6_SCOPE_ID
+ /* pktinfo must have already been allocated */
+ if ((pktinfo->ipi6_ifindex = if_nametoindex(ifname)) == 0)
+ errx(1, "%s: invalid interface name", ifname);
+#else
+ if ((dst.sin6_scope_id = if_nametoindex(ifname)) == 0)
+ errx(1, "%s: invalid interface name", ifname);
+#endif
+ }
+ if (hoplimit != -1) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_HOPLIMIT;
+ *(int *)(CMSG_DATA(scmsgp)) = hoplimit;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+
+#ifdef IPV6_USE_MIN_MTU
+ if (mflag != 1) {
+ optval = mflag > 1 ? 0 : 1;
+
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_USE_MIN_MTU;
+ *(int *)(CMSG_DATA(scmsgp)) = optval;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+#endif /* IPV6_USE_MIN_MTU */
+
+ if (argc > 1) { /* some intermediate addrs are specified */
+ int hops, error;
+#ifdef USE_RFC2292BIS
+ int rthdrlen;
+#endif
+
+#ifdef USE_RFC2292BIS
+ rthdrlen = inet6_rth_space(IPV6_RTHDR_TYPE_0, argc - 1);
+ scmsgp->cmsg_len = CMSG_LEN(rthdrlen);
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_RTHDR;
+ rthdr = (struct ip6_rthdr *)CMSG_DATA(scmsgp);
+ rthdr = inet6_rth_init((void *)rthdr, rthdrlen,
+ IPV6_RTHDR_TYPE_0, argc - 1);
+ if (rthdr == NULL)
+ errx(1, "can't initialize rthdr");
+#else /* old advanced API */
+ if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp,
+ IPV6_RTHDR_TYPE_0)) == 0)
+ errx(1, "can't initialize rthdr");
+#endif /* USE_RFC2292BIS */
+
+ for (hops = 0; hops < argc - 1; hops++) {
+ struct addrinfo *iaip;
+
+ if ((error = getaddrinfo(argv[hops], NULL, &hints,
+ &iaip)))
+ errx(1, "%s", gai_strerror(error));
+ if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6)
+ errx(1,
+ "bad addr family of an intermediate addr");
+
+#ifdef USE_RFC2292BIS
+ if (inet6_rth_add(rthdr,
+ &(SIN6(iaip->ai_addr))->sin6_addr))
+ errx(1, "can't add an intermediate node");
+#else /* old advanced API */
+ if (inet6_rthdr_add(scmsgp,
+ &(SIN6(iaip->ai_addr))->sin6_addr,
+ IPV6_RTHDR_LOOSE))
+ errx(1, "can't add an intermediate node");
+#endif /* USE_RFC2292BIS */
+ freeaddrinfo(iaip);
+ }
+
+#ifndef USE_RFC2292BIS
+ if (inet6_rthdr_lasthop(scmsgp, IPV6_RTHDR_LOOSE))
+ errx(1, "can't set the last flag");
+#endif
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+
+ if (tclass != -2) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = IPPROTO_IPV6;
+ scmsgp->cmsg_type = IPV6_TCLASS;
+ *(int *)(CMSG_DATA(scmsgp)) = tclass;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+ if (use_sendmsg != 0) {
+ if (so_traffic_class != -1) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = SOL_SOCKET;
+ scmsgp->cmsg_type = SO_TRAFFIC_CLASS;
+ *(int *)(CMSG_DATA(scmsgp)) = so_traffic_class;
+
+ scmsgp = CMSG_NXTHDR(&smsghdr, scmsgp);
+ }
+ if (net_service_type != -1) {
+ scmsgp->cmsg_len = CMSG_LEN(sizeof(int));
+ scmsgp->cmsg_level = SOL_SOCKET;
+ scmsgp->cmsg_type = SO_NET_SERVICE_TYPE;
+ *(int *)(CMSG_DATA(scmsgp)) = net_service_type;
+ }
+ }
+ if (!(options & F_SRCADDR)) {
+ /*
+ * get the source address. XXX since we revoked the root
+ * privilege, we cannot use a raw socket for this.
+ */
+ int dummy;
+ socklen_t len = sizeof(src);
+
+ if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ err(1, "UDP socket");
+
+ if (ifscope != 0) {
+ if (setsockopt(dummy, IPPROTO_IPV6, IPV6_BOUND_IF,
+ (char *)&ifscope, sizeof (ifscope)) != 0)
+ err(1, "setsockopt(IPV6_BOUND_IF)");
+ }
+
+ if (nocell != 0) {
+ if (setsockopt(dummy, IPPROTO_IPV6, IPV6_NO_IFT_CELLULAR,
+ (char *)&nocell, sizeof (nocell)) != 0)
+ err(1, "setsockopt(IPV6_NO_IFT_CELLULAR)");
+ }
+
+ src.sin6_family = AF_INET6;
+ src.sin6_addr = dst.sin6_addr;
+ src.sin6_port = ntohs(DUMMY_PORT);
+ src.sin6_scope_id = dst.sin6_scope_id;
+
+#ifdef USE_RFC2292BIS
+ if (pktinfo &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTINFO,
+ (void *)pktinfo, sizeof(*pktinfo)))
+ err(1, "UDP setsockopt(IPV6_PKTINFO)");
+
+ if (hoplimit != -1 &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ (void *)&hoplimit, sizeof(hoplimit)))
+ err(1, "UDP setsockopt(IPV6_UNICAST_HOPS)");
+
+ if (hoplimit != -1 &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+ (void *)&hoplimit, sizeof(hoplimit)))
+ err(1, "UDP setsockopt(IPV6_MULTICAST_HOPS)");
+
+ if (rthdr &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_RTHDR,
+ (void *)rthdr, (rthdr->ip6r_len + 1) << 3))
+ err(1, "UDP setsockopt(IPV6_RTHDR)");
+#else /* old advanced API */
+ if (smsghdr.msg_control &&
+ setsockopt(dummy, IPPROTO_IPV6, IPV6_PKTOPTIONS,
+ (void *)smsghdr.msg_control, smsghdr.msg_controllen))
+ err(1, "UDP setsockopt(IPV6_PKTOPTIONS)");
+#endif
+
+ if (connect(dummy, (struct sockaddr *)&src, len) < 0)
+ err(1, "UDP connect");
+
+ if (getsockname(dummy, (struct sockaddr *)&src, &len) < 0)
+ err(1, "getsockname");
+
+ close(dummy);
+ }
+
+#if defined(SO_SNDBUF) && defined(SO_RCVBUF)
+ if (sockbufsize) {
+ if (MAX(datalen, sweepmax) > sockbufsize)
+ warnx("you need -b to increase socket buffer size");
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize,
+ sizeof(sockbufsize)) < 0)
+ err(1, "setsockopt(SO_SNDBUF)");
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &sockbufsize,
+ sizeof(sockbufsize)) < 0)
+ err(1, "setsockopt(SO_RCVBUF)");
+ }
+ else {
+ if (MAX(datalen, sweepmax) > 8 * 1024) /*XXX*/
+ warnx("you need -b to increase socket buffer size");
+ /*
+ * When pinging the broadcast address, you can get a lot of
+ * answers. Doing something so evil is useful if you are trying
+ * to stress the ethernet, or just want to fill the arp cache
+ * to get some stuff for /etc/ethers.
+ */
+ hold = 48 * 1024;
+ setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
+ sizeof(hold));
+ }
+#endif
+
+ optval = 1;
+#ifndef USE_SIN6_SCOPE_ID
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_RECVPKTINFO)"); /* XXX err? */
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_PKTINFO)"); /* XXX err? */
+#endif
+#endif /* USE_SIN6_SCOPE_ID */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_RECVHOPLIMIT)"); /* XXX err? */
+#else /* old adv. API */
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, &optval,
+ sizeof(optval)) < 0)
+ warn("setsockopt(IPV6_HOPLIMIT, %d, %lu)",
+ optval, sizeof(optval)); /* XXX err? */
+#endif
+
+ if (sweepmax)
+ printf("PING6(40+8+[%lu...%lu] bytes) ",
+ (unsigned long)(sweepmin),
+ (unsigned long)(sweepmax));
+ else
+ printf("PING6(%lu=40+8+%lu bytes) ", (unsigned long)(40 + pingerlen()),
+ (unsigned long)(pingerlen() - 8));
+ printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src)));
+ printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst)));
+
+ if (preload == 0)
+ pinger();
+ else {
+ if (npackets != 0 && preload > npackets)
+ preload = npackets;
+ while (preload--)
+ pinger();
+ }
+ gettimeofday(&last, NULL);
+
+ /*
+ * rdar://25829310
+ *
+ * Clear blocked signals inherited from the parent
+ */
+ sigset_t newset;
+ sigemptyset(&newset);
+ if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0)
+ err(EX_OSERR, "sigprocmask(newset)");
+
+ seenalrm = seenint = 0;
+#ifdef SIGINFO
+ seeninfo = 0;
+#endif
+
+ (void)signal(SIGINT, onsignal);
+#ifdef SIGINFO
+ (void)signal(SIGINFO, onsignal);
+#endif
+ if (alarmtimeout > 0) {
+ (void)signal(SIGALRM, onsignal);
+ }
+
+ if (options & F_FLOOD) {
+ intvl.tv_sec = 0;
+ intvl.tv_usec = 10000;
+ } else if ((options & F_INTERVAL) == 0) {
+ intvl.tv_sec = interval / 1000;
+ intvl.tv_usec = interval % 1000 * 1000;
+ }
+
+ /* For control (ancillary) data received from recvmsg() */
+ cm = (struct cmsghdr *)malloc(CONTROLLEN);
+ if (cm == NULL)
+ err(1, "malloc");
+
+ almost_done = 0;
+ while (seenint == 0) {
+ struct timeval now, timeout;
+ struct msghdr m;
+ struct iovec iov[2];
+ fd_set rfds;
+ int n;
+
+ /* signal handling */
+ if (seenint)
+ onint(SIGINT);
+#ifdef SIGINFO
+ if (seeninfo) {
+ summary();
+ seeninfo = 0;
+ continue;
+ }
+#endif
+ FD_ZERO(&rfds);
+ FD_SET(s, &rfds);
+ gettimeofday(&now, NULL);
+ timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
+ timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
+ while (timeout.tv_usec < 0) {
+ timeout.tv_usec += 1000000;
+ timeout.tv_sec--;
+ }
+ while (timeout.tv_usec > 1000000) {
+ timeout.tv_usec -= 1000000;
+ timeout.tv_sec++;
+ }
+ if (timeout.tv_sec < 0)
+ timeout.tv_sec = timeout.tv_usec = 0;
+
+ n = select(s + 1, &rfds, NULL, NULL, &timeout);
+ if (n < 0)
+ continue; /* EINTR */
+ if (n == 1) {
+ m.msg_name = (caddr_t)&from;
+ m.msg_namelen = sizeof(from);
+ memset(&iov, 0, sizeof(iov));
+ iov[0].iov_base = (caddr_t)packet;
+ iov[0].iov_len = packlen;
+ m.msg_iov = iov;
+ m.msg_iovlen = 1;
+ memset(cm, 0, CONTROLLEN);
+ m.msg_control = (void *)cm;
+ m.msg_controllen = CONTROLLEN;
+ m.msg_flags = 0;
+
+ cc = recvmsg(s, &m, 0);
+ if (cc < 0) {
+ if (errno != EINTR) {
+ warn("recvmsg");
+ sleep(1);
+ }
+ continue;
+ } else if (cc == 0) {
+ int mtu;
+
+ /*
+ * receive control messages only. Process the
+ * exceptions (currently the only possibility is
+ * a path MTU notification.)
+ */
+ if ((mtu = get_pathmtu(&m)) > 0) {
+ if ((options & F_VERBOSE) != 0) {
+ printf("new path MTU (%d) is "
+ "notified\n", mtu);
+ }
+ }
+ continue;
+ } else {
+ /*
+ * an ICMPv6 message (probably an echoreply)
+ * arrived.
+ */
+ pr_pack(packet, cc, &m);
+ }
+ if (((options & F_ONCE) != 0 && nreceived > 0) ||
+ (npackets > 0 && nreceived >= npackets) ||
+ (sweepmax && datalen > sweepmax))
+ break;
+ }
+ if (n == 0 || (options & F_FLOOD)) {
+ if (npackets == 0 || ntransmitted < npackets)
+ pinger();
+ else {
+ if (almost_done)
+ break;
+ almost_done = 1;
+ /*
+ * If we're not transmitting any more packets,
+ * change the timer to wait two round-trip times
+ * if we've received any packets or (waittime)
+ * milliseconds if we haven't.
+ */
+ intvl.tv_usec = 0;
+ if (nreceived) {
+ intvl.tv_sec = 2 * tmax / 1000;
+ if (intvl.tv_sec == 0)
+ intvl.tv_sec = 1;
+ } else {
+ intvl.tv_sec = waittime / 1000;
+ intvl.tv_usec = waittime % 1000 * 1000;
+ }
+ }
+ gettimeofday(&last, NULL);
+ if (ntransmitted - nreceived - 1 > nmissedmax) {
+ nmissedmax = ntransmitted - nreceived - 1;
+ if (options & F_MISSED)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ }
+ }
+ }
+ sigemptyset(&newset);
+ if (sigprocmask(SIG_SETMASK, &newset, NULL) != 0)
+ err(EX_OSERR, "sigprocmask(newset)");
+ summary();
+
+ if (packet != NULL)
+ free(packet);
+
+ exit(nreceived == 0 ? 2 : 0);
+}
+
+void
+onsignal(int sig)
+{
+ fflush(stdout);
+
+ switch (sig) {
+ case SIGINT:
+ case SIGALRM:
+ seenint++;
+ break;
+#ifdef SIGINFO
+ case SIGINFO:
+ seeninfo++;
+ break;
+#endif
+ }
+}
+
+/*
+ * pinger --
+ * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
+ * will be added on by the kernel. The ID field is our UNIX process ID,
+ * and the sequence number is an ascending integer. The first 8 bytes
+ * of the data portion are used to hold a UNIX "timeval" struct in VAX
+ * byte-order, to compute the round-trip time.
+ */
+size_t
+pingerlen(void)
+{
+ size_t l;
+
+ if (options & F_FQDN)
+ l = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
+ else if (options & F_FQDNOLD)
+ l = ICMP6_NIQLEN;
+ else if (options & F_NODEADDR)
+ l = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
+ else if (options & F_SUPTYPES)
+ l = ICMP6_NIQLEN;
+ else
+ l = ICMP6ECHOLEN + datalen;
+
+ return l;
+}
+
+int
+pinger(void)
+{
+ struct icmp6_hdr *icp;
+ int i, cc;
+ struct icmp6_nodeinfo *nip;
+ int seq;
+
+ if (npackets && ntransmitted >= npackets)
+ return(-1); /* no more transmission */
+
+ if (sweepmax && sntransmitted == snpackets) {
+ datalen += sweepincr;
+ if (datalen > sweepmax)
+ return(-1); /* no more transmission */
+ sntransmitted = 0;
+ }
+
+ icp = (struct icmp6_hdr *)outpack;
+ nip = (struct icmp6_nodeinfo *)outpack;
+ memset(icp, 0, sizeof(*icp));
+ icp->icmp6_cksum = 0;
+ seq = ntransmitted++;
+ CLR(seq % mx_dup_ck);
+
+ if (options & F_FQDN) {
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = ICMP6_NI_SUBJ_IPV6;
+ nip->ni_qtype = htons(NI_QTYPE_FQDN);
+ nip->ni_flags = htons(0);
+
+ memcpy(nip->icmp6_ni_nonce, nonce,
+ sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
+ memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr,
+ sizeof(dst.sin6_addr));
+ cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
+ datalen = 0;
+ } else if (options & F_FQDNOLD) {
+ /* packet format in 03 draft - no Subject data on queries */
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = 0; /* code field is always 0 */
+ nip->ni_qtype = htons(NI_QTYPE_FQDN);
+ nip->ni_flags = htons(0);
+
+ memcpy(nip->icmp6_ni_nonce, nonce,
+ sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
+ cc = ICMP6_NIQLEN;
+ datalen = 0;
+ } else if (options & F_NODEADDR) {
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = ICMP6_NI_SUBJ_IPV6;
+ nip->ni_qtype = htons(NI_QTYPE_NODEADDR);
+ nip->ni_flags = naflags;
+
+ memcpy(nip->icmp6_ni_nonce, nonce,
+ sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+
+ memcpy(&outpack[ICMP6_NIQLEN], &dst.sin6_addr,
+ sizeof(dst.sin6_addr));
+ cc = ICMP6_NIQLEN + sizeof(dst.sin6_addr);
+ datalen = 0;
+ } else if (options & F_SUPTYPES) {
+ icp->icmp6_type = ICMP6_NI_QUERY;
+ icp->icmp6_code = ICMP6_NI_SUBJ_FQDN; /*empty*/
+ nip->ni_qtype = htons(NI_QTYPE_SUPTYPES);
+ /* we support compressed bitmap */
+ nip->ni_flags = NI_SUPTYPE_FLAG_COMPRESS;
+
+ memcpy(nip->icmp6_ni_nonce, nonce,
+ sizeof(nip->icmp6_ni_nonce));
+ *(u_int16_t *)nip->icmp6_ni_nonce = ntohs(seq);
+ cc = ICMP6_NIQLEN;
+ datalen = 0;
+ } else {
+ icp->icmp6_type = ICMP6_ECHO_REQUEST;
+ icp->icmp6_code = 0;
+ icp->icmp6_id = htons(ident);
+ icp->icmp6_seq = ntohs(seq);
+ if (timing) {
+ struct timeval tv;
+ struct tv32 *tv32;
+ (void)gettimeofday(&tv, NULL);
+ tv32 = (struct tv32 *)&outpack[ICMP6ECHOLEN];
+ tv32->tv32_sec = htonl(tv.tv_sec);
+ tv32->tv32_usec = htonl(tv.tv_usec);
+ }
+ cc = ICMP6ECHOLEN + datalen;
+ }
+
+#ifdef DIAGNOSTIC
+ if (pingerlen() != cc)
+ errx(1, "internal error; length mismatch");
+#endif
+
+ if ((options & F_CONNECT)) {
+ smsghdr.msg_name = NULL;
+ smsghdr.msg_namelen = 0;
+ } else {
+ smsghdr.msg_name = (caddr_t)&dst;
+ smsghdr.msg_namelen = sizeof(dst);
+ }
+ memset(&smsgiov, 0, sizeof(smsgiov));
+ smsgiov[0].iov_base = (caddr_t)outpack;
+ smsgiov[0].iov_len = cc;
+ smsghdr.msg_iov = smsgiov;
+ smsghdr.msg_iovlen = 1;
+
+ i = sendmsg(s, &smsghdr, 0);
+
+ if (i < 0 || i != cc) {
+ if (i < 0)
+ warn("sendmsg");
+ (void)printf("ping6: wrote %s %d chars, ret=%d\n",
+ hostname, cc, i);
+ }
+ sntransmitted++;
+ if (!(options & F_QUIET) && options & F_FLOOD)
+ (void)write(STDOUT_FILENO, &DOT, 1);
+
+ return(0);
+}
+
+int
+myechoreply(const struct icmp6_hdr *icp)
+{
+ if (ntohs(icp->icmp6_id) == ident)
+ return 1;
+ else
+ return 0;
+}
+
+int
+mynireply(const struct icmp6_nodeinfo *nip)
+{
+ if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t),
+ nonce + sizeof(u_int16_t),
+ sizeof(nonce) - sizeof(u_int16_t)) == 0)
+ return 1;
+ else
+ return 0;
+}
+
+char *
+dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf,
+ size_t bufsiz)
+ /*base for compressed name*/
+{
+ int i = 0;
+ const u_char *cp;
+ char cresult[NS_MAXDNAME + 1];
+ const u_char *comp;
+ int l;
+
+ cp = *sp;
+ *buf = '\0';
+
+ if (cp >= ep)
+ return NULL;
+ while (cp < ep) {
+ i = *cp;
+ if (i == 0 || cp != *sp) {
+ if (strlcat((char *)buf, ".", bufsiz) >= bufsiz)
+ return NULL; /*result overrun*/
+ }
+ if (i == 0)
+ break;
+ cp++;
+
+ if ((i & 0xc0) == 0xc0 && cp - base > (i & 0x3f)) {
+ /* DNS compression */
+ if (!base)
+ return NULL;
+
+ comp = base + (i & 0x3f);
+ if (dnsdecode(&comp, cp, base, cresult,
+ sizeof(cresult)) == NULL)
+ return NULL;
+ if (strlcat(buf, cresult, bufsiz) >= bufsiz)
+ return NULL; /*result overrun*/
+ break;
+ } else if ((i & 0x3f) == i) {
+ if (i > ep - cp)
+ return NULL; /*source overrun*/
+ while (i-- > 0 && cp < ep) {
+ l = snprintf(cresult, sizeof(cresult),
+ isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff);
+ if (l >= sizeof(cresult) || l < 0)
+ return NULL;
+ if (strlcat(buf, cresult, bufsiz) >= bufsiz)
+ return NULL; /*result overrun*/
+ cp++;
+ }
+ } else
+ return NULL; /*invalid label*/
+ }
+ if (i != 0)
+ return NULL; /*not terminated*/
+ cp++;
+ *sp = cp;
+ return buf;
+}
+
+/*
+ * pr_pack --
+ * Print out the packet, if it came from us. This logic is necessary
+ * because ALL readers of the ICMP socket get a copy of ALL ICMP packets
+ * which arrive ('tis only fair). This permits multiple copies of this
+ * program to be run without having intermingled output (or statistics!).
+ */
+void
+pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
+{
+#define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c)
+ struct icmp6_hdr *icp;
+ struct icmp6_nodeinfo *ni;
+ int i;
+ int hoplim;
+ struct sockaddr *from;
+ int fromlen;
+ u_char *cp = NULL, *dp, *end = buf + cc;
+ struct in6_pktinfo *pktinfo = NULL;
+ struct timeval tv, tp;
+ struct tv32 *tpp;
+ double triptime = 0;
+ int dupflag;
+ size_t off;
+ int oldfqdn;
+ u_int16_t seq;
+ char dnsname[NS_MAXDNAME + 1];
+ int tclass = 0;
+ int sotc = -1;
+
+ (void)gettimeofday(&tv, NULL);
+
+ if (!mhdr || !mhdr->msg_name ||
+ mhdr->msg_namelen != sizeof(struct sockaddr_in6) ||
+ ((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET6) {
+ if (options & F_VERBOSE)
+ warnx("invalid peername");
+ return;
+ }
+ from = (struct sockaddr *)mhdr->msg_name;
+ fromlen = mhdr->msg_namelen;
+ if (cc < sizeof(struct icmp6_hdr)) {
+ if (options & F_VERBOSE)
+ warnx("packet too short (%d bytes) from %s", cc,
+ pr_addr(from, fromlen));
+ return;
+ }
+ if (((mhdr->msg_flags & MSG_CTRUNC) != 0) &&
+ (options & F_VERBOSE) != 0)
+ warnx("some control data discarded, insufficient buffer size");
+ icp = (struct icmp6_hdr *)buf;
+ ni = (struct icmp6_nodeinfo *)buf;
+ off = 0;
+
+ if ((hoplim = get_hoplim(mhdr)) == -1) {
+ warnx("failed to get receiving hop limit");
+ return;
+ }
+ if ((pktinfo = get_rcvpktinfo(mhdr)) == NULL) {
+ warnx("failed to get receiving packet information");
+ return;
+ }
+ if (rcvtclass && (tclass = get_tclass(mhdr)) == -1) {
+ warnx("failed to get receiving traffic class");
+ return;
+ }
+
+ if (use_recvmsg > 0)
+ sotc = get_so_traffic_class(mhdr);
+
+ if (icp->icmp6_type == ICMP6_ECHO_REPLY && myechoreply(icp)) {
+ seq = ntohs(icp->icmp6_seq);
+ ++nreceived;
+ if (timing) {
+ tpp = (struct tv32 *)(icp + 1);
+ tp.tv_sec = ntohl(tpp->tv32_sec);
+ tp.tv_usec = ntohl(tpp->tv32_usec);
+ tvsub(&tv, &tp);
+ triptime = ((double)tv.tv_sec) * 1000.0 +
+ ((double)tv.tv_usec) / 1000.0;
+ tsum += triptime;
+ tsumsq += triptime * triptime;
+ if (triptime < tmin)
+ tmin = triptime;
+ if (triptime > tmax)
+ tmax = triptime;
+ }
+
+ if (TST(seq % mx_dup_ck)) {
+ ++nrepeats;
+ --nreceived;
+ dupflag = 1;
+ } else {
+ SET(seq % mx_dup_ck);
+ dupflag = 0;
+ }
+
+ if (options & F_QUIET)
+ return;
+
+ if (options & F_WAITTIME && triptime > waittime) {
+ ++nrcvtimeout;
+ return;
+ }
+
+ if (options & F_FLOOD)
+ (void)write(STDOUT_FILENO, &BSPACE, 1);
+ else {
+ if (options & F_AUDIBLE)
+ (void)write(STDOUT_FILENO, &BBELL, 1);
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s, icmp_seq=%u", cc,
+ pr_addr(from, fromlen), seq);
+ (void)printf(" hlim=%d", hoplim);
+ if ((options & F_VERBOSE) != 0) {
+ struct sockaddr_in6 dstsa;
+
+ memset(&dstsa, 0, sizeof(dstsa));
+ dstsa.sin6_family = AF_INET6;
+ dstsa.sin6_len = sizeof(dstsa);
+ dstsa.sin6_scope_id = pktinfo->ipi6_ifindex;
+ dstsa.sin6_addr = pktinfo->ipi6_addr;
+ (void)printf(" dst=%s",
+ pr_addr((struct sockaddr *)&dstsa,
+ sizeof(dstsa)));
+ }
+ if (timing)
+ (void)printf(" time=%.3f ms", triptime);
+ if (dupflag) {
+ if (!IN6_IS_ADDR_MULTICAST(&dst.sin6_addr))
+ (void)printf("(DUP!)");
+ }
+ if (rcvtclass)
+ (void)printf(" tclass=%d", tclass);
+ if (sotc != -1)
+ (void)printf(" sotc=%d", sotc);
+ /* check the data */
+ cp = buf + off + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
+ dp = outpack + ICMP6ECHOLEN + ICMP6ECHOTMLEN;
+ for (i = 8; cp < end; ++i, ++cp, ++dp) {
+ if (*cp != *dp) {
+ (void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x", i, *dp, *cp);
+ break;
+ }
+ }
+ }
+ } else if (icp->icmp6_type == ICMP6_NI_REPLY && mynireply(ni)) {
+ seq = ntohs(*(u_int16_t *)ni->icmp6_ni_nonce);
+ ++nreceived;
+ if (TST(seq % mx_dup_ck)) {
+ ++nrepeats;
+ --nreceived;
+ dupflag = 1;
+ } else {
+ SET(seq % mx_dup_ck);
+ dupflag = 0;
+ }
+
+ if (options & F_QUIET)
+ return;
+
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
+
+ switch (ntohs(ni->ni_code)) {
+ case ICMP6_NI_SUCCESS:
+ break;
+ case ICMP6_NI_REFUSED:
+ printf("refused, type 0x%x", ntohs(ni->ni_type));
+ goto fqdnend;
+ case ICMP6_NI_UNKNOWN:
+ printf("unknown, type 0x%x", ntohs(ni->ni_type));
+ goto fqdnend;
+ default:
+ printf("unknown code 0x%x, type 0x%x",
+ ntohs(ni->ni_code), ntohs(ni->ni_type));
+ goto fqdnend;
+ }
+
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ printf("NodeInfo NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ pr_suptypes(ni, end - (u_char *)ni);
+ break;
+ case NI_QTYPE_NODEADDR:
+ pr_nodeaddr(ni, end - (u_char *)ni);
+ break;
+ case NI_QTYPE_FQDN:
+ default: /* XXX: for backward compatibility */
+ cp = (u_char *)ni + ICMP6_NIRLEN;
+ if (buf[off + ICMP6_NIRLEN] ==
+ cc - off - ICMP6_NIRLEN - 1)
+ oldfqdn = 1;
+ else
+ oldfqdn = 0;
+ if (oldfqdn) {
+ cp++; /* skip length */
+ while (cp < end) {
+ safeputc(*cp & 0xff);
+ cp++;
+ }
+ } else {
+ i = 0;
+ while (cp < end) {
+ if (dnsdecode((const u_char **)&cp, end,
+ (const u_char *)(ni + 1), dnsname,
+ sizeof(dnsname)) == NULL) {
+ printf("???");
+ break;
+ }
+ /*
+ * name-lookup special handling for
+ * truncated name
+ */
+ if (cp + 1 <= end && !*cp &&
+ strlen(dnsname) > 0) {
+ dnsname[strlen(dnsname) - 1] = '\0';
+ cp++;
+ }
+ printf("%s%s", i > 0 ? "," : "",
+ dnsname);
+ }
+ }
+ if (options & F_VERBOSE) {
+ int32_t ttl;
+ int comma = 0;
+
+ (void)printf(" ("); /*)*/
+
+ switch (ni->ni_code) {
+ case ICMP6_NI_REFUSED:
+ (void)printf("refused");
+ comma++;
+ break;
+ case ICMP6_NI_UNKNOWN:
+ (void)printf("unknown qtype");
+ comma++;
+ break;
+ }
+
+ if ((end - (u_char *)ni) < ICMP6_NIRLEN) {
+ /* case of refusion, unknown */
+ /*(*/
+ putchar(')');
+ goto fqdnend;
+ }
+ ttl = (int32_t)ntohl(*(u_long *)&buf[off+ICMP6ECHOLEN+8]);
+ if (comma)
+ printf(",");
+ if (!(ni->ni_flags & NI_FQDN_FLAG_VALIDTTL)) {
+ (void)printf("TTL=%d:meaningless",
+ (int)ttl);
+ } else {
+ if (ttl < 0) {
+ (void)printf("TTL=%d:invalid",
+ ttl);
+ } else
+ (void)printf("TTL=%d", ttl);
+ }
+ comma++;
+
+ if (oldfqdn) {
+ if (comma)
+ printf(",");
+ printf("03 draft");
+ comma++;
+ } else {
+ cp = (u_char *)ni + ICMP6_NIRLEN;
+ if (cp == end) {
+ if (comma)
+ printf(",");
+ printf("no name");
+ comma++;
+ }
+ }
+
+ if (buf[off + ICMP6_NIRLEN] !=
+ cc - off - ICMP6_NIRLEN - 1 && oldfqdn) {
+ if (comma)
+ printf(",");
+ (void)printf("invalid namelen:%d/%lu",
+ buf[off + ICMP6_NIRLEN],
+ (u_long)cc - off - ICMP6_NIRLEN - 1);
+ comma++;
+ }
+ /*(*/
+ putchar(')');
+ }
+ fqdnend:
+ ;
+ }
+ } else {
+ /* We've got something other than an ECHOREPLY */
+ if (!(options & F_VERBOSE))
+ return;
+ if (options & F_PRTIME)
+ pr_currenttime();
+ (void)printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
+ pr_icmph(icp, end);
+ }
+
+ if (!(options & F_FLOOD)) {
+ (void)putchar('\n');
+ if (options & F_VERBOSE)
+ pr_exthdrs(mhdr);
+ (void)fflush(stdout);
+ }
+#undef safeputc
+}
+
+void
+pr_exthdrs(struct msghdr *mhdr)
+{
+ ssize_t bufsize;
+ void *bufp;
+ struct cmsghdr *cm;
+
+ bufsize = 0;
+ bufp = mhdr->msg_control;
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_level != IPPROTO_IPV6)
+ continue;
+
+ bufsize = CONTROLLEN - ((caddr_t)CMSG_DATA(cm) - (caddr_t)bufp);
+ if (bufsize <= 0)
+ continue;
+ switch (cm->cmsg_type) {
+ case IPV6_HOPOPTS:
+ printf(" HbH Options: ");
+ pr_ip6opt(CMSG_DATA(cm), (size_t)bufsize);
+ break;
+ case IPV6_DSTOPTS:
+#ifdef IPV6_RTHDRDSTOPTS
+ case IPV6_RTHDRDSTOPTS:
+#endif
+ printf(" Dst Options: ");
+ pr_ip6opt(CMSG_DATA(cm), (size_t)bufsize);
+ break;
+ case IPV6_RTHDR:
+ printf(" Routing: ");
+ pr_rthdr(CMSG_DATA(cm), (size_t)bufsize);
+ break;
+ }
+ }
+}
+
+#ifdef USE_RFC2292BIS
+void
+pr_ip6opt(void *extbuf, size_t bufsize)
+{
+ struct ip6_hbh *ext;
+ int currentlen;
+ u_int8_t type;
+ socklen_t extlen, len;
+ void *databuf;
+ size_t offset;
+ u_int16_t value2;
+ u_int32_t value4;
+
+ ext = (struct ip6_hbh *)extbuf;
+ extlen = (ext->ip6h_len + 1) * 8;
+ printf("nxt %u, len %u (%lu bytes)\n", ext->ip6h_nxt,
+ (unsigned int)ext->ip6h_len, (unsigned long)extlen);
+
+ /*
+ * Bounds checking on the ancillary data buffer:
+ * subtract the size of a cmsg structure from the buffer size.
+ */
+ if (bufsize < (extlen + CMSG_SPACE(0))) {
+ extlen = bufsize - CMSG_SPACE(0);
+ warnx("options truncated, showing only %u (total=%u)",
+ (unsigned int)(extlen / 8 - 1),
+ (unsigned int)(ext->ip6h_len));
+ }
+
+ currentlen = 0;
+ while (1) {
+ currentlen = inet6_opt_next(extbuf, extlen, currentlen,
+ &type, &len, &databuf);
+ if (currentlen == -1)
+ break;
+ switch (type) {
+ /*
+ * Note that inet6_opt_next automatically skips any padding
+ * optins.
+ */
+ case IP6OPT_JUMBO:
+ offset = 0;
+ (void) inet6_opt_get_val(databuf, offset,
+ &value4, sizeof(value4));
+ printf(" Jumbo Payload Opt: Length %u\n",
+ (u_int32_t)ntohl(value4));
+ break;
+ case IP6OPT_ROUTER_ALERT:
+ offset = 0;
+ (void)inet6_opt_get_val(databuf, offset,
+ &value2, sizeof(value2));
+ printf(" Router Alert Opt: Type %u\n",
+ ntohs(value2));
+ break;
+ default:
+ printf(" Received Opt %u len %lu\n",
+ type, (unsigned long)len);
+ break;
+ }
+ }
+ return;
+}
+#else /* !USE_RFC2292BIS */
+/* ARGSUSED */
+void
+pr_ip6opt(void *extbuf, size_t bufsize __unused)
+{
+ putchar('\n');
+ return;
+}
+#endif /* USE_RFC2292BIS */
+
+#ifdef USE_RFC2292BIS
+void
+pr_rthdr(void *extbuf, size_t bufsize)
+{
+ struct in6_addr *in6;
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct ip6_rthdr *rh = (struct ip6_rthdr *)extbuf;
+ int i, segments, origsegs, rthsize, size0, size1;
+
+ /* print fixed part of the header */
+ printf("nxt %u, len %u (%d bytes), type %u, ", rh->ip6r_nxt,
+ rh->ip6r_len, (rh->ip6r_len + 1) << 3, rh->ip6r_type);
+ if ((segments = inet6_rth_segments(extbuf)) >= 0) {
+ printf("%d segments, ", segments);
+ printf("%d left\n", rh->ip6r_segleft);
+ } else {
+ printf("segments unknown, ");
+ printf("%d left\n", rh->ip6r_segleft);
+ return;
+ }
+
+ /*
+ * Bounds checking on the ancillary data buffer. When calculating
+ * the number of items to show keep in mind:
+ * - The size of the cmsg structure
+ * - The size of one segment (the size of a Type 0 routing header)
+ * - When dividing add a fudge factor of one in case the
+ * dividend is not evenly divisible by the divisor
+ */
+ rthsize = (rh->ip6r_len + 1) * 8;
+ if (bufsize < (rthsize + CMSG_SPACE(0))) {
+ origsegs = segments;
+ size0 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 0);
+ size1 = inet6_rth_space(IPV6_RTHDR_TYPE_0, 1);
+ segments -= (rthsize - (bufsize - CMSG_SPACE(0))) /
+ (size1 - size0) + 1;
+ warnx("segments truncated, showing only %d (total=%d)",
+ segments, origsegs);
+ }
+
+ for (i = 0; i < segments; i++) {
+ in6 = inet6_rth_getaddr(extbuf, i);
+ if (in6 == NULL)
+ printf(" [%d]<NULL>\n", i);
+ else {
+ if (!inet_ntop(AF_INET6, in6, ntopbuf,
+ sizeof(ntopbuf)))
+ strlcpy(ntopbuf, "?", sizeof(ntopbuf));
+ printf(" [%d]%s\n", i, ntopbuf);
+ }
+ }
+
+ return;
+
+}
+
+#else /* !USE_RFC2292BIS */
+/* ARGSUSED */
+void
+pr_rthdr(void *extbuf, size_t bufsize __unused)
+{
+ putchar('\n');
+ return;
+}
+#endif /* USE_RFC2292BIS */
+
+int
+pr_bitrange(u_int32_t v, int soff, int ii)
+{
+ int off;
+ int i;
+
+ off = 0;
+ while (off < 32) {
+ /* shift till we have 0x01 */
+ if ((v & 0x01) == 0) {
+ if (ii > 1)
+ printf("-%u", soff + off - 1);
+ ii = 0;
+ switch (v & 0x0f) {
+ case 0x00:
+ v >>= 4;
+ off += 4;
+ continue;
+ case 0x08:
+ v >>= 3;
+ off += 3;
+ continue;
+ case 0x04: case 0x0c:
+ v >>= 2;
+ off += 2;
+ continue;
+ default:
+ v >>= 1;
+ off += 1;
+ continue;
+ }
+ }
+
+ /* we have 0x01 with us */
+ for (i = 0; i < 32 - off; i++) {
+ if ((v & (0x01 << i)) == 0)
+ break;
+ }
+ if (!ii)
+ printf(" %u", soff + off);
+ ii += i;
+ v >>= i; off += i;
+ }
+ return ii;
+}
+
+void
+pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen)
+ /* ni->qtype must be SUPTYPES */
+{
+ size_t clen;
+ u_int32_t v;
+ const u_char *cp, *end;
+ u_int16_t cur;
+ struct cbit {
+ u_int16_t words; /*32bit count*/
+ u_int16_t skip;
+ } cbit = { 0, 0 };
+#define MAXQTYPES (1 << 16)
+ size_t off;
+ int b;
+
+ cp = (u_char *)(ni + 1);
+ end = ((u_char *)ni) + nilen;
+ cur = 0;
+ b = 0;
+
+ printf("NodeInfo Supported Qtypes");
+ if (options & F_VERBOSE) {
+ if (ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS)
+ printf(", compressed bitmap");
+ else
+ printf(", raw bitmap");
+ }
+
+ while (cp < end) {
+ clen = (size_t)(end - cp);
+ if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) == 0) {
+ if (clen == 0 || clen > MAXQTYPES / 8 ||
+ clen % sizeof(v)) {
+ printf("???");
+ return;
+ }
+ } else {
+ if (clen < sizeof(cbit) || clen % sizeof(v))
+ return;
+ memcpy(&cbit, cp, sizeof(cbit));
+ if (sizeof(cbit) + ntohs(cbit.words) * sizeof(v) >
+ clen)
+ return;
+ cp += sizeof(cbit);
+ clen = ntohs(cbit.words) * sizeof(v);
+ if (cur + clen * 8 + (u_long)ntohs(cbit.skip) * 32 >
+ MAXQTYPES)
+ return;
+ }
+
+ for (off = 0; off < clen; off += sizeof(v)) {
+ memcpy(&v, cp + off, sizeof(v));
+ v = (u_int32_t)ntohl(v);
+ b = pr_bitrange(v, (int)(cur + off * 8), b);
+ }
+ /* flush the remaining bits */
+ b = pr_bitrange(0, (int)(cur + off * 8), b);
+
+ cp += clen;
+ cur += clen * 8;
+ if ((ni->ni_flags & NI_SUPTYPE_FLAG_COMPRESS) != 0)
+ cur += ntohs(cbit.skip) * 32;
+ }
+}
+
+void
+pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen)
+ /* ni->qtype must be NODEADDR */
+{
+ u_char *cp = (u_char *)(ni + 1);
+ char ntop_buf[INET6_ADDRSTRLEN];
+ int withttl = 0;
+
+ nilen -= sizeof(struct icmp6_nodeinfo);
+
+ if (options & F_VERBOSE) {
+ switch (ni->ni_code) {
+ case ICMP6_NI_REFUSED:
+ (void)printf("refused");
+ break;
+ case ICMP6_NI_UNKNOWN:
+ (void)printf("unknown qtype");
+ break;
+ }
+ if (ni->ni_flags & NI_NODEADDR_FLAG_TRUNCATE)
+ (void)printf(" truncated");
+ }
+ putchar('\n');
+ if (nilen <= 0)
+ printf(" no address\n");
+
+ /*
+ * In icmp-name-lookups 05 and later, TTL of each returned address
+ * is contained in the resposne. We try to detect the version
+ * by the length of the data, but note that the detection algorithm
+ * is incomplete. We assume the latest draft by default.
+ */
+ if (nilen % (sizeof(u_int32_t) + sizeof(struct in6_addr)) == 0)
+ withttl = 1;
+ while (nilen > 0) {
+ u_int32_t ttl = 0;
+
+ if (withttl) {
+ /* XXX: alignment? */
+ ttl = (u_int32_t)ntohl(*(u_int32_t *)cp);
+ cp += sizeof(u_int32_t);
+ nilen -= sizeof(u_int32_t);
+ }
+
+ if (inet_ntop(AF_INET6, cp, ntop_buf, sizeof(ntop_buf)) ==
+ NULL)
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ printf(" %s", ntop_buf);
+ if (withttl) {
+ if (ttl == 0xffffffff) {
+ /*
+ * XXX: can this convention be applied to all
+ * type of TTL (i.e. non-ND TTL)?
+ */
+ printf("(TTL=infty)");
+ }
+ else
+ printf("(TTL=%u)", ttl);
+ }
+ putchar('\n');
+
+ nilen -= sizeof(struct in6_addr);
+ cp += sizeof(struct in6_addr);
+ }
+}
+
+int
+get_hoplim(struct msghdr *mhdr)
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(-1);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ return(*(int *)CMSG_DATA(cm));
+ }
+
+ return(-1);
+}
+
+struct in6_pktinfo *
+get_rcvpktinfo(struct msghdr *mhdr)
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(NULL);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
+ return((struct in6_pktinfo *)CMSG_DATA(cm));
+ }
+
+ return(NULL);
+}
+
+int
+get_pathmtu(struct msghdr *mhdr)
+{
+#ifdef IPV6_RECVPATHMTU
+ struct cmsghdr *cm;
+ struct ip6_mtuinfo *mtuctl = NULL;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(0);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PATHMTU &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct ip6_mtuinfo))) {
+ mtuctl = (struct ip6_mtuinfo *)CMSG_DATA(cm);
+
+ /*
+ * If the notified destination is different from
+ * the one we are pinging, just ignore the info.
+ * We check the scope ID only when both notified value
+ * and our own value have non-0 values, because we may
+ * have used the default scope zone ID for sending,
+ * in which case the scope ID value is 0.
+ */
+ if (!IN6_ARE_ADDR_EQUAL(&mtuctl->ip6m_addr.sin6_addr,
+ &dst.sin6_addr) ||
+ (mtuctl->ip6m_addr.sin6_scope_id &&
+ dst.sin6_scope_id &&
+ mtuctl->ip6m_addr.sin6_scope_id !=
+ dst.sin6_scope_id)) {
+ if ((options & F_VERBOSE) != 0) {
+ printf("path MTU for %s is notified. "
+ "(ignored)\n",
+ pr_addr((struct sockaddr *)&mtuctl->ip6m_addr,
+ sizeof(mtuctl->ip6m_addr)));
+ }
+ return(0);
+ }
+
+ /*
+ * Ignore an invalid MTU. XXX: can we just believe
+ * the kernel check?
+ */
+ if (mtuctl->ip6m_mtu < IPV6_MMTU)
+ return(0);
+
+ /* notification for our destination. return the MTU. */
+ return((int)mtuctl->ip6m_mtu);
+ }
+ }
+#endif
+ return(0);
+}
+
+int
+get_tclass(mhdr)
+ struct msghdr *mhdr;
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(-1);
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_TCLASS &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ return(*(int *)CMSG_DATA(cm));
+ }
+
+ return(-1);
+}
+
+int
+get_so_traffic_class(struct msghdr *mhdr)
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_len == 0)
+ return(-1);
+
+ if (cm->cmsg_level == SOL_SOCKET &&
+ cm->cmsg_type == SO_TRAFFIC_CLASS &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ return(*(int *)CMSG_DATA(cm));
+ }
+
+ return(-1);
+}
+
+/*
+ * tvsub --
+ * Subtract 2 timeval structs: out = out - in. Out is assumed to
+ * be >= in.
+ */
+void
+tvsub(struct timeval *out, struct timeval *in)
+{
+ if ((out->tv_usec -= in->tv_usec) < 0) {
+ --out->tv_sec;
+ out->tv_usec += 1000000;
+ }
+ out->tv_sec -= in->tv_sec;
+}
+
+/*
+ * onint --
+ * SIGINT handler.
+ */
+/* ARGSUSED */
+void
+onint(int notused __unused)
+{
+ /*
+ * When doing reverse DNS lookups, the seenint flag might not
+ * be noticed for a while. Just exit if we get a second SIGINT.
+ */
+ if ((options & F_HOSTNAME) && seenint != 0)
+ _exit(nreceived ? 0 : 2);
+}
+
+/*
+ * summary --
+ * Print out statistics.
+ */
+void
+summary(void)
+{
+ (void)printf("\n--- %s ping6 statistics ---\n", hostname);
+ (void)printf("%ld packets transmitted, ", ntransmitted);
+ (void)printf("%ld packets received, ", nreceived);
+ if (nrepeats)
+ (void)printf("+%ld duplicates, ", nrepeats);
+ if (ntransmitted) {
+ if (nreceived > ntransmitted)
+ (void)printf("-- somebody's duplicating packets!");
+ else
+ (void)printf("%.1f%% packet loss",
+ ((((double)ntransmitted - nreceived) * 100.0) /
+ ntransmitted));
+ }
+ if (nrcvtimeout)
+ printf(", %ld packets out of wait time", nrcvtimeout);
+ (void)putchar('\n');
+ if (nreceived && timing) {
+ /* Only display average to microseconds */
+ double num = nreceived + nrepeats;
+ double avg = tsum / num;
+ double dev = sqrt(tsumsq / num - avg * avg);
+ (void)printf(
+ "round-trip min/avg/max/std-dev = %.3f/%.3f/%.3f/%.3f ms\n",
+ tmin, avg, tmax, dev);
+ (void)fflush(stdout);
+ }
+ (void)fflush(stdout);
+}
+
+/*subject type*/
+static const char *niqcode[] = {
+ "IPv6 address",
+ "DNS label", /*or empty*/
+ "IPv4 address",
+};
+
+/*result code*/
+static const char *nircode[] = {
+ "Success", "Refused", "Unknown",
+};
+
+/*
+ * pr_icmph --
+ * Print a descriptive string about an ICMP header.
+ */
+void
+pr_icmph(struct icmp6_hdr *icp, u_char *end)
+{
+ char ntop_buf[INET6_ADDRSTRLEN];
+ struct nd_redirect *red;
+ struct icmp6_nodeinfo *ni;
+ char dnsname[NS_MAXDNAME + 1];
+ const u_char *cp;
+ size_t l;
+
+ switch (icp->icmp6_type) {
+ case ICMP6_DST_UNREACH:
+ switch (icp->icmp6_code) {
+ case ICMP6_DST_UNREACH_NOROUTE:
+ (void)printf("No Route to Destination\n");
+ break;
+ case ICMP6_DST_UNREACH_ADMIN:
+ (void)printf("Destination Administratively "
+ "Unreachable\n");
+ break;
+ case ICMP6_DST_UNREACH_BEYONDSCOPE:
+ (void)printf("Destination Unreachable Beyond Scope\n");
+ break;
+ case ICMP6_DST_UNREACH_ADDR:
+ (void)printf("Destination Host Unreachable\n");
+ break;
+ case ICMP6_DST_UNREACH_NOPORT:
+ (void)printf("Destination Port Unreachable\n");
+ break;
+ default:
+ (void)printf("Destination Unreachable, Bad Code: %d\n",
+ icp->icmp6_code);
+ break;
+ }
+ /* Print returned IP header information */
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ (void)printf("Packet too big mtu = %d\n",
+ (int)ntohl(icp->icmp6_mtu));
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ switch (icp->icmp6_code) {
+ case ICMP6_TIME_EXCEED_TRANSIT:
+ (void)printf("Time to live exceeded\n");
+ break;
+ case ICMP6_TIME_EXCEED_REASSEMBLY:
+ (void)printf("Frag reassembly time exceeded\n");
+ break;
+ default:
+ (void)printf("Time exceeded, Bad Code: %d\n",
+ icp->icmp6_code);
+ break;
+ }
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
+ break;
+ case ICMP6_PARAM_PROB:
+ (void)printf("Parameter problem: ");
+ switch (icp->icmp6_code) {
+ case ICMP6_PARAMPROB_HEADER:
+ (void)printf("Erroneous Header ");
+ break;
+ case ICMP6_PARAMPROB_NEXTHEADER:
+ (void)printf("Unknown Nextheader ");
+ break;
+ case ICMP6_PARAMPROB_OPTION:
+ (void)printf("Unrecognized Option ");
+ break;
+ default:
+ (void)printf("Bad code(%d) ", icp->icmp6_code);
+ break;
+ }
+ (void)printf("pointer = 0x%02x\n",
+ (u_int32_t)ntohl(icp->icmp6_pptr));
+ pr_retip((struct ip6_hdr *)(icp + 1), end);
+ break;
+ case ICMP6_ECHO_REQUEST:
+ (void)printf("Echo Request");
+ /* XXX ID + Seq + Data */
+ break;
+ case ICMP6_ECHO_REPLY:
+ (void)printf("Echo Reply");
+ /* XXX ID + Seq + Data */
+ break;
+ case ICMP6_MEMBERSHIP_QUERY:
+ (void)printf("Listener Query");
+ break;
+ case ICMP6_MEMBERSHIP_REPORT:
+ (void)printf("Listener Report");
+ break;
+ case ICMP6_MEMBERSHIP_REDUCTION:
+ (void)printf("Listener Done");
+ break;
+ case ND_ROUTER_SOLICIT:
+ (void)printf("Router Solicitation");
+ break;
+ case ND_ROUTER_ADVERT:
+ (void)printf("Router Advertisement");
+ break;
+ case ND_NEIGHBOR_SOLICIT:
+ (void)printf("Neighbor Solicitation");
+ break;
+ case ND_NEIGHBOR_ADVERT:
+ (void)printf("Neighbor Advertisement");
+ break;
+ case ND_REDIRECT:
+ red = (struct nd_redirect *)icp;
+ (void)printf("Redirect\n");
+ if (!inet_ntop(AF_INET6, &red->nd_rd_dst, ntop_buf,
+ sizeof(ntop_buf)))
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ (void)printf("Destination: %s", ntop_buf);
+ if (!inet_ntop(AF_INET6, &red->nd_rd_target, ntop_buf,
+ sizeof(ntop_buf)))
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ (void)printf(" New Target: %s", ntop_buf);
+ break;
+ case ICMP6_NI_QUERY:
+ (void)printf("Node Information Query");
+ /* XXX ID + Seq + Data */
+ ni = (struct icmp6_nodeinfo *)icp;
+ l = end - (u_char *)(ni + 1);
+ printf(", ");
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ (void)printf("NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ (void)printf("Supported qtypes");
+ break;
+ case NI_QTYPE_FQDN:
+ (void)printf("DNS name");
+ break;
+ case NI_QTYPE_NODEADDR:
+ (void)printf("nodeaddr");
+ break;
+ case NI_QTYPE_IPV4ADDR:
+ (void)printf("IPv4 nodeaddr");
+ break;
+ default:
+ (void)printf("unknown qtype");
+ break;
+ }
+ if (options & F_VERBOSE) {
+ switch (ni->ni_code) {
+ case ICMP6_NI_SUBJ_IPV6:
+ if (l == sizeof(struct in6_addr) &&
+ inet_ntop(AF_INET6, ni + 1, ntop_buf,
+ sizeof(ntop_buf)) != NULL) {
+ (void)printf(", subject=%s(%s)",
+ niqcode[ni->ni_code], ntop_buf);
+ } else {
+#if 1
+ /* backward compat to -W */
+ (void)printf(", oldfqdn");
+#else
+ (void)printf(", invalid");
+#endif
+ }
+ break;
+ case ICMP6_NI_SUBJ_FQDN:
+ if (end == (u_char *)(ni + 1)) {
+ (void)printf(", no subject");
+ break;
+ }
+ printf(", subject=%s", niqcode[ni->ni_code]);
+ cp = (const u_char *)(ni + 1);
+ if (dnsdecode(&cp, end, NULL, dnsname,
+ sizeof(dnsname)) != NULL)
+ printf("(%s)", dnsname);
+ else
+ printf("(invalid)");
+ break;
+ case ICMP6_NI_SUBJ_IPV4:
+ if (l == sizeof(struct in_addr) &&
+ inet_ntop(AF_INET, ni + 1, ntop_buf,
+ sizeof(ntop_buf)) != NULL) {
+ (void)printf(", subject=%s(%s)",
+ niqcode[ni->ni_code], ntop_buf);
+ } else
+ (void)printf(", invalid");
+ break;
+ default:
+ (void)printf(", invalid");
+ break;
+ }
+ }
+ break;
+ case ICMP6_NI_REPLY:
+ (void)printf("Node Information Reply");
+ /* XXX ID + Seq + Data */
+ ni = (struct icmp6_nodeinfo *)icp;
+ printf(", ");
+ switch (ntohs(ni->ni_qtype)) {
+ case NI_QTYPE_NOOP:
+ (void)printf("NOOP");
+ break;
+ case NI_QTYPE_SUPTYPES:
+ (void)printf("Supported qtypes");
+ break;
+ case NI_QTYPE_FQDN:
+ (void)printf("DNS name");
+ break;
+ case NI_QTYPE_NODEADDR:
+ (void)printf("nodeaddr");
+ break;
+ case NI_QTYPE_IPV4ADDR:
+ (void)printf("IPv4 nodeaddr");
+ break;
+ default:
+ (void)printf("unknown qtype");
+ break;
+ }
+ if (options & F_VERBOSE) {
+ if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0]))
+ printf(", invalid");
+ else
+ printf(", %s", nircode[ni->ni_code]);
+ }
+ break;
+ default:
+ (void)printf("Bad ICMP type: %d", icp->icmp6_type);
+ }
+}
+
+/*
+ * pr_iph --
+ * Print an IP6 header.
+ */
+void
+pr_iph(struct ip6_hdr *ip6)
+{
+ u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK;
+ u_int8_t tc;
+ char ntop_buf[INET6_ADDRSTRLEN];
+
+ tc = *(&ip6->ip6_vfc + 1); /* XXX */
+ tc = (tc >> 4) & 0x0f;
+ tc |= (ip6->ip6_vfc << 4);
+
+ printf("Vr TC Flow Plen Nxt Hlim\n");
+ printf(" %1x %02x %05x %04x %02x %02x\n",
+ (ip6->ip6_vfc & IPV6_VERSION_MASK) >> 4, tc, (u_int32_t)ntohl(flow),
+ ntohs(ip6->ip6_plen), ip6->ip6_nxt, ip6->ip6_hlim);
+ if (!inet_ntop(AF_INET6, &ip6->ip6_src, ntop_buf, sizeof(ntop_buf)))
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ printf("%s->", ntop_buf);
+ if (!inet_ntop(AF_INET6, &ip6->ip6_dst, ntop_buf, sizeof(ntop_buf)))
+ strlcpy(ntop_buf, "?", sizeof(ntop_buf));
+ printf("%s\n", ntop_buf);
+}
+
+/*
+ * pr_addr --
+ * Return an ascii host address as a dotted quad and optionally with
+ * a hostname.
+ */
+const char *
+pr_addr(struct sockaddr *addr, int addrlen)
+{
+ static char buf[NI_MAXHOST];
+ int flag = 0;
+
+ if ((options & F_HOSTNAME) == 0)
+ flag |= NI_NUMERICHOST;
+
+ if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0)
+ return (buf);
+ else
+ return "?";
+}
+
+/*
+ * pr_retip --
+ * Dump some info on a returned (via ICMPv6) IPv6 packet.
+ */
+void
+pr_retip(struct ip6_hdr *ip6, u_char *end)
+{
+ u_char *cp = (u_char *)ip6, nh;
+ int hlen;
+
+ if (end - (u_char *)ip6 < sizeof(*ip6)) {
+ printf("IP6");
+ goto trunc;
+ }
+ pr_iph(ip6);
+ hlen = sizeof(*ip6);
+
+ nh = ip6->ip6_nxt;
+ cp += hlen;
+ while (end - cp >= 8) {
+ switch (nh) {
+ case IPPROTO_HOPOPTS:
+ printf("HBH ");
+ hlen = (((struct ip6_hbh *)cp)->ip6h_len+1) << 3;
+ nh = ((struct ip6_hbh *)cp)->ip6h_nxt;
+ break;
+ case IPPROTO_DSTOPTS:
+ printf("DSTOPT ");
+ hlen = (((struct ip6_dest *)cp)->ip6d_len+1) << 3;
+ nh = ((struct ip6_dest *)cp)->ip6d_nxt;
+ break;
+ case IPPROTO_FRAGMENT:
+ printf("FRAG ");
+ hlen = sizeof(struct ip6_frag);
+ nh = ((struct ip6_frag *)cp)->ip6f_nxt;
+ break;
+ case IPPROTO_ROUTING:
+ printf("RTHDR ");
+ hlen = (((struct ip6_rthdr *)cp)->ip6r_len+1) << 3;
+ nh = ((struct ip6_rthdr *)cp)->ip6r_nxt;
+ break;
+#ifdef IPSEC
+ case IPPROTO_AH:
+ printf("AH ");
+ hlen = (((struct ah *)cp)->ah_len+2) << 2;
+ nh = ((struct ah *)cp)->ah_nxt;
+ break;
+#endif
+ case IPPROTO_ICMPV6:
+ printf("ICMP6: type = %d, code = %d\n",
+ *cp, *(cp + 1));
+ return;
+ case IPPROTO_ESP:
+ printf("ESP\n");
+ return;
+ case IPPROTO_TCP:
+ printf("TCP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)),
+ (*(cp + 2) * 256 + *(cp + 3)));
+ return;
+ case IPPROTO_UDP:
+ printf("UDP: from port %u, to port %u (decimal)\n",
+ (*cp * 256 + *(cp + 1)),
+ (*(cp + 2) * 256 + *(cp + 3)));
+ return;
+ default:
+ printf("Unknown Header(%d)\n", nh);
+ return;
+ }
+
+ if ((cp += hlen) >= end)
+ goto trunc;
+ }
+ if (end - cp < 8)
+ goto trunc;
+
+ putchar('\n');
+ return;
+
+ trunc:
+ printf("...\n");
+ return;
+}
+
+void
+fill(char *bp, char *patp)
+{
+ int ii, jj, kk;
+ int pat[16];
+ char *cp;
+
+ for (cp = patp; *cp; cp++)
+ if (!isxdigit(*cp))
+ errx(1, "patterns must be specified as hex digits");
+ ii = sscanf(patp,
+ "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
+ &pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
+ &pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
+ &pat[13], &pat[14], &pat[15]);
+
+/* xxx */
+ if (ii > 0)
+ for (kk = 0;
+ kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii);
+ kk += ii)
+ for (jj = 0; jj < ii; ++jj)
+ bp[jj + kk] = pat[jj];
+ if (!(options & F_QUIET)) {
+ (void)printf("PATTERN: 0x");
+ for (jj = 0; jj < ii; ++jj)
+ (void)printf("%02x", bp[jj] & 0xFF);
+ (void)printf("\n");
+ }
+}
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+int
+setpolicy(int so __unused, char *policy)
+{
+ char *buf;
+
+ if (policy == NULL)
+ return 0; /* ignore */
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL)
+ errx(1, "%s", ipsec_strerror());
+ if (setsockopt(s, IPPROTO_IPV6, IPV6_IPSEC_POLICY, buf,
+ ipsec_get_policylen(buf)) < 0)
+ warnx("Unable to set IPsec policy");
+ free(buf);
+
+ return 0;
+}
+#endif
+#endif
+
+char *
+nigroup(char *name, int nig_oldmcprefix)
+{
+ char *p;
+ char *q;
+ MD5_CTX ctxt;
+ u_int8_t digest[16];
+ u_int8_t c;
+ size_t l;
+ char hbuf[NI_MAXHOST];
+ struct in6_addr in6;
+ int valid;
+
+ p = strchr(name, '.');
+ if (!p)
+ p = name + strlen(name);
+ l = p - name;
+ if (l > 63 || l > sizeof(hbuf) - 1)
+ return NULL; /*label too long*/
+ strlcpy(hbuf, name, l);
+ hbuf[(int)l] = '\0';
+
+ for (q = name; *q; q++) {
+ if (isupper(*(unsigned char *)q))
+ *q = tolower(*(unsigned char *)q);
+ }
+
+ /* generate 16 bytes of pseudo-random value. */
+ memset(&ctxt, 0, sizeof(ctxt));
+ MD5Init(&ctxt);
+ c = l & 0xff;
+ MD5Update(&ctxt, &c, sizeof(c));
+ MD5Update(&ctxt, (unsigned char *)name, l);
+ MD5Final(digest, &ctxt);
+
+ if (nig_oldmcprefix) {
+ /* draft-ietf-ipngwg-icmp-name-lookup */
+ valid = inet_pton(AF_INET6, "ff02::2:0000:0000", &in6);
+ } else {
+ /* RFC 4620 */
+ valid = inet_pton(AF_INET6, "ff02::2:ff00:0000", &in6);
+ }
+ if (valid != 1)
+ return NULL; /*XXX*/
+
+ if (nig_oldmcprefix) {
+ /* draft-ietf-ipngwg-icmp-name-lookup */
+ bcopy(digest, &in6.s6_addr[12], 4);
+ } else {
+ /* RFC 4620 */
+ bcopy(digest, &in6.s6_addr[13], 3);
+ }
+
+ if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL)
+ return NULL;
+
+ return strdup(hbuf);
+}
+
+int
+str2sotc(const char *str, bool *valid)
+{
+ int sotc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK_SYS") == 0)
+ return SO_TC_BK_SYS;
+ else if (strcasecmp(str, "BK") == 0)
+ return SO_TC_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return SO_TC_BE;
+ else if (strcasecmp(str, "RD") == 0)
+ return SO_TC_RD;
+ else if (strcasecmp(str, "OAM") == 0)
+ return SO_TC_OAM;
+ else if (strcasecmp(str, "AV") == 0)
+ return SO_TC_AV;
+ else if (strcasecmp(str, "RV") == 0)
+ return SO_TC_RV;
+ else if (strcasecmp(str, "VI") == 0)
+ return SO_TC_VI;
+ else if (strcasecmp(str, "VO") == 0)
+ return SO_TC_VO;
+ else if (strcasecmp(str, "CTL") == 0)
+ return SO_TC_CTL;
+ else {
+ sotc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (sotc);
+}
+
+int
+str2netservicetype(const char *str, bool *valid)
+{
+ int svc = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "BK") == 0)
+ return NET_SERVICE_TYPE_BK;
+ else if (strcasecmp(str, "BE") == 0)
+ return NET_SERVICE_TYPE_BE;
+ else if (strcasecmp(str, "VI") == 0)
+ return NET_SERVICE_TYPE_VI;
+ else if (strcasecmp(str, "SIG") == 0)
+ return NET_SERVICE_TYPE_SIG;
+ else if (strcasecmp(str, "VO") == 0)
+ return NET_SERVICE_TYPE_VO;
+ else if (strcasecmp(str, "RV") == 0)
+ return NET_SERVICE_TYPE_RV;
+ else if (strcasecmp(str, "AV") == 0)
+ return NET_SERVICE_TYPE_AV;
+ else if (strcasecmp(str, "OAM") == 0)
+ return NET_SERVICE_TYPE_OAM;
+ else if (strcasecmp(str, "RD") == 0)
+ return NET_SERVICE_TYPE_RD;
+ else {
+ svc = (int)strtol(str, &endptr, 0);
+ if (*endptr != '\0')
+ *valid = false;
+ }
+ return (svc);
+}
+
+u_int8_t
+str2tclass(const char *str, bool *valid)
+{
+ u_int8_t dscp = -1;
+ char *endptr;
+
+ *valid = true;
+
+ if (str == NULL || *str == '\0')
+ *valid = false;
+ else if (strcasecmp(str, "DF") == 0)
+ dscp = _DSCP_DF;
+ else if (strcasecmp(str, "EF") == 0)
+ dscp = _DSCP_EF;
+ else if (strcasecmp(str, "VA") == 0)
+ dscp = _DSCP_VA;
+
+ else if (strcasecmp(str, "CS0") == 0)
+ dscp = _DSCP_CS0;
+ else if (strcasecmp(str, "CS1") == 0)
+ dscp = _DSCP_CS1;
+ else if (strcasecmp(str, "CS2") == 0)
+ dscp = _DSCP_CS2;
+ else if (strcasecmp(str, "CS3") == 0)
+ dscp = _DSCP_CS3;
+ else if (strcasecmp(str, "CS4") == 0)
+ dscp = _DSCP_CS4;
+ else if (strcasecmp(str, "CS5") == 0)
+ dscp = _DSCP_CS5;
+ else if (strcasecmp(str, "CS6") == 0)
+ dscp = _DSCP_CS6;
+ else if (strcasecmp(str, "CS7") == 0)
+ dscp = _DSCP_CS7;
+
+ else if (strcasecmp(str, "AF11") == 0)
+ dscp = _DSCP_AF11;
+ else if (strcasecmp(str, "AF12") == 0)
+ dscp = _DSCP_AF12;
+ else if (strcasecmp(str, "AF13") == 0)
+ dscp = _DSCP_AF13;
+ else if (strcasecmp(str, "AF21") == 0)
+ dscp = _DSCP_AF21;
+ else if (strcasecmp(str, "AF22") == 0)
+ dscp = _DSCP_AF22;
+ else if (strcasecmp(str, "AF23") == 0)
+ dscp = _DSCP_AF23;
+ else if (strcasecmp(str, "AF31") == 0)
+ dscp = _DSCP_AF31;
+ else if (strcasecmp(str, "AF32") == 0)
+ dscp = _DSCP_AF32;
+ else if (strcasecmp(str, "AF33") == 0)
+ dscp = _DSCP_AF33;
+ else if (strcasecmp(str, "AF41") == 0)
+ dscp = _DSCP_AF41;
+ else if (strcasecmp(str, "AF42") == 0)
+ dscp = _DSCP_AF42;
+ else if (strcasecmp(str, "AF43") == 0)
+ dscp = _DSCP_AF43;
+
+ else {
+ unsigned long val = strtoul(str, &endptr, 0);
+ if (*endptr != '\0' || val > 255)
+ *valid = false;
+ else
+ return ((u_int8_t)val);
+ }
+ /* DSCP occupies the 6 upper bits of the traffic class field */
+ return (dscp << 2);
+}
+
+void
+pr_currenttime(void)
+{
+ int s;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ s = (tv.tv_sec + thiszone) % 86400;
+ printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
+ (u_int32_t)tv.tv_usec);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr,
+#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
+ "A"
+#endif
+ "usage: ping6 [-"
+ "Dd"
+#if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC)
+ "E"
+#endif
+ "fH"
+#ifdef IPV6_USE_MIN_MTU
+ "m"
+#endif
+ "nNoqrRtvwW] "
+ "[-a addrtype] [-b bufsiz] [-c count]\n"
+ " [-g gateway] [-h hoplimit] [-I interface] [-i wait] [-l preload]"
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ " [-P policy]"
+#endif
+ "\n"
+ " [-p pattern] [-S sourceaddr] [-s packetsize] [-z tclass] "
+ "[-k traffic_class] [-K net_service_type] "
+ "[hops ...] host\n");
+ (void)fprintf(stderr, "Apple specific options (to be specified before hops or host like all options)\n");
+ (void)fprintf(stderr, " -b boundif # bind the socket to the interface\n");
+ (void)fprintf(stderr, " -k traffic_class # set traffic class socket option\n");
+ (void)fprintf(stderr, " -K net_service_type # set traffic class socket options\n");
+ (void)fprintf(stderr, " -apple-connect # call connect(2) in the socket\n");
+ (void)fprintf(stderr, " -apple-time # display current time\n");
+ (void)fprintf(stderr, " -apple-progress # show progress for debugging\n");
+ exit(1);
+}
diff --git a/network_cmds/pktapctl/pktapctl.8 b/network_cmds/pktapctl/pktapctl.8
new file mode 100644
index 0000000..5f11615
--- /dev/null
+++ b/network_cmds/pktapctl/pktapctl.8
@@ -0,0 +1,41 @@
+.Dd 9/28/12
+.Dt pktapctl 8
+.Os Darwin
+.Sh NAME
+.Nm pktapctl
+.Sh SYNOPSIS
+.Nm
+.Op Fl g
+.Op Fl h
+.Op Fl i Ar interface
+.Op Fl p Ar rule
+.Op Fl s Ar rule
+.Sh DESCRIPTION
+.Nm
+let you configure a pktap virtual interface.
+.Pp
+This is an experimental command whose syntax and functionalities may change in
+future releases.
+.Pp
+The options have the following meaning:
+.Bl -tag -width -indent
+.It Fl g
+Get the list of filter rules for the given
+.Ar interface.
+.It Fl h
+Display a quick help and exit.
+.It Fl p
+To add a pass interface filter rule.
+.It Fl s
+To add a skip interface filter rule.
+.El
+.Pp
+Here is the syntax of the interface filter rules:
+.Bl -tag -indent
+.It type number
+An interface type number or 0 for any interface type.
+.It name string
+To specify interface with name matching the given string.
+.El
+.Sh SEE ALSO
+.Xr tcpdump 1
diff --git a/network_cmds/pktapctl/pktapctl.c b/network_cmds/pktapctl/pktapctl.c
new file mode 100644
index 0000000..9bbe0ed
--- /dev/null
+++ b/network_cmds/pktapctl/pktapctl.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/ioctl.h>
+#include <net/pktap.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+const char *ifname = NULL;
+unsigned int ifindex = 0;
+int do_get = 0;
+int num_filter_entries = 0;
+struct pktap_filter set_filter[PKTAP_MAX_FILTERS];
+
+static const char *parameters_format = " %-24s %s\n";
+
+static void
+usage(const char *s)
+{
+ printf("# usage: %s -i <ifname> -g -p <filter_rule> -s <filter_rule> -h\n", s);
+ printf(" Get or set filtering rules on a pktap interface\n");
+ printf(" Options:\n");
+ printf(parameters_format, "-h", "display this help");
+ printf(parameters_format, "-i <ifname>", "name pktap interface");
+ printf(parameters_format, "-g", "get filter rules");
+ printf(parameters_format, "-p <filter_rule> param", "add a pass rule");
+ printf(parameters_format, "-s <filter_rule> param", "add a skip rule");
+ printf(" Format of <filter_rule> parameter:\n");
+ printf(parameters_format, "type <iftype>", "interfaces of given type");
+ printf(parameters_format, "", "use 0 for any interface type");
+ printf(parameters_format, "name <ifname>", "interface of given name");
+}
+
+static void
+print_filter_entry(struct pktap_filter *filter)
+{
+ printf("filter_op: %u filter_param %u ", filter->filter_op, filter->filter_param);
+ if (filter->filter_param == PKTAP_FILTER_PARAM_IF_TYPE)
+ printf("%u", filter->filter_param_if_type);
+ else if (filter->filter_param == PKTAP_FILTER_PARAM_IF_NAME)
+ printf("%s", filter->filter_param_if_name);
+}
+
+int main(int argc, char * const argv[])
+{
+ int ch;
+ struct ifdrv ifdr;
+ int fd = -1;
+ int i;
+
+ //printf("sizeof(struct pktap_filter) %lu\n", sizeof(struct pktap_filter));
+ //printf("sizeof(pktap_filter) %lu\n", sizeof(set_filter));
+
+ while ((ch = getopt(argc, argv, "ghi:p:s:")) != -1) {
+ switch (ch) {
+ case 'g':
+ do_get++;
+ break;
+
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ /* NOT REACHED */
+
+ case 'i':
+ ifname = optarg;
+
+ ifindex = if_nametoindex(ifname);
+ if (ifindex == 0)
+ err(1, "if_nametoindex(%s) failed", ifname);
+
+ break;
+
+ case 'p':
+ case 's': {
+ /* -p (type|name) <value> */
+ struct pktap_filter entry;
+
+ if (num_filter_entries >= PKTAP_MAX_FILTERS)
+ errx(1, "Too many filter entries, max is %u", PKTAP_MAX_FILTERS);
+ if (optind + 1 > argc)
+ errx(1, "-%c needs two arguments optind %d argc %d", ch, optind, argc);
+ if (ch == 'p')
+ entry.filter_op = PKTAP_FILTER_OP_PASS;
+ else
+ entry.filter_op = PKTAP_FILTER_OP_SKIP;
+ if (strcmp(optarg, "type") == 0) {
+ entry.filter_param = PKTAP_FILTER_PARAM_IF_TYPE;
+ entry.filter_param_if_type = (uint32_t)strtoul(argv[optind], NULL, 0);
+ } else if (strcmp(optarg, "name") == 0) {
+ entry.filter_param = PKTAP_FILTER_PARAM_IF_NAME;
+ snprintf(entry.filter_param_if_name, sizeof(entry.filter_param_if_name), "%s", argv[optind]);
+ } else
+ errx(1, "syntax error -p %s", optarg);
+ printf("Addin entry: ");
+ print_filter_entry(&entry);
+ printf("\n");
+ set_filter[num_filter_entries] = entry;
+
+ num_filter_entries++;
+ optind++;
+ break;
+ }
+
+ case '?':
+ default:
+ err(1, "syntax error");
+ exit(0);
+ /* NOT REACHED */
+ }
+ }
+ if (ifname == NULL)
+ errx(1, "missing interface");
+
+ fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (fd == -1)
+ err(1, "socket(PF_INET, SOCK_DGRAM, 0)");
+
+ if (num_filter_entries > 0) {
+ for (i = num_filter_entries; i < PKTAP_MAX_FILTERS; i++) {
+ struct pktap_filter *filter = set_filter + i;
+ filter->filter_op = PKTAP_FILTER_OP_NONE;
+ filter->filter_param = PKTAP_FILTER_PARAM_NONE;
+ }
+
+ snprintf(ifdr.ifd_name, sizeof(ifdr.ifd_name), "%s", ifname);
+ ifdr.ifd_cmd = PKTP_CMD_FILTER_SET;
+ ifdr.ifd_len = sizeof(set_filter);
+ ifdr.ifd_data = &set_filter[0];
+
+ if (ioctl(fd, SIOCSDRVSPEC, &ifdr) == -1)
+ err(1, "ioctl(SIOCSDRVSPEC)");
+
+ }
+
+ if (do_get) {
+ struct pktap_filter get_filter[PKTAP_MAX_FILTERS];
+
+ snprintf(ifdr.ifd_name, sizeof(ifdr.ifd_name), "%s", ifname);
+ ifdr.ifd_cmd = PKTP_CMD_FILTER_GET;
+ ifdr.ifd_len = sizeof(get_filter);
+ ifdr.ifd_data = &get_filter[0];
+
+ if (ioctl(fd, SIOCGDRVSPEC, &ifdr) == -1)
+ err(1, "ioctl(SIOCGDRVSPEC)");
+
+ for (i = 0; i < PKTAP_MAX_FILTERS; i++) {
+ struct pktap_filter *filter = get_filter + i;
+
+ printf("[%d] ", i);
+ print_filter_entry(filter);
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
+
diff --git a/network_cmds/pktmnglr/packet_mangler.c b/network_cmds/pktmnglr/packet_mangler.c
new file mode 100644
index 0000000..cf94cd4
--- /dev/null
+++ b/network_cmds/pktmnglr/packet_mangler.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+//
+// Created by Prabhakar Lakhera on 06/23/14.
+//
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sys/errno.h>
+#include <sys/sys_domain.h>
+#include <sys/ioctl.h>
+#include <sys/kern_control.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <err.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <sysexits.h>
+#include <net/packet_mangler.h>
+
+
+#define BUF_MAX 1000
+int doit();
+
+Pkt_Mnglr_Flow dir = INOUT;
+struct addrinfo * p_localaddr = NULL;
+struct addrinfo * p_remoteaddr = NULL;
+struct sockaddr_storage l_saddr = {0};
+struct sockaddr_storage r_saddr = {0};
+
+int sf = -1;
+uint32_t duration = 0;
+uint32_t protocol = 0;
+uint32_t proto_act_mask = 0;
+uint32_t ip_act_mask = 0;
+uint16_t local_port = 0;
+uint16_t remote_port = 0;
+uint8_t activate = 1;
+
+static const char *
+basename(const char * str)
+{
+ const char *last_slash = strrchr(str, '/');
+
+ if (last_slash == NULL)
+ return (str);
+ else
+ return (last_slash + 1);
+}
+
+struct option_desc {
+ const char *option;
+ const char *description;
+ int required;
+};
+
+struct option_desc option_desc_list[] = {
+ { "-h ", "Help", 0 },
+ { "-f flow", "flow direction to apply mangler on. Values can be: in/out/inout. default is inout", 0 },
+ { "-l IP address ", "Local IP we are interested in ", 0 },
+ { "-r IP address ", "Remote IP we are interested in", 0 },
+ { "-m IP action mask ", "IP action mask", 0 },
+ { "-t time", "Run duration for which packet mangler will run. A value of 0 means forever (till program is killed).", 0 },
+ { "-p IP Protocol ", "IP protocol i.e. one of tcp, udp, icmp, icmpv6", 0 },
+ { "-L Local port ", "Local port", 0 },
+ { "-R Remote port ", "Remote port", 0 },
+ { "-M Protocol action mask ", "Protocol action mask", 0 },
+ { NULL, NULL, 0 } /* Mark end of list */
+};
+
+
+static void
+usage(const char *cmd)
+{
+ struct option_desc *option_desc;
+ char * usage_str = (char *)malloc(BUF_MAX);
+ size_t usage_len;
+
+ if (usage_str == NULL)
+ err(1, "%s: malloc(%d)", __func__, BUF_MAX);
+
+ usage_len = snprintf(usage_str, BUF_MAX, "# usage: %s ", basename(cmd));
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ int len;
+
+ if (option_desc->required)
+ len = snprintf(usage_str + usage_len, BUF_MAX - usage_len, "%s ", option_desc->option);
+ else
+ len = snprintf(usage_str + usage_len, BUF_MAX - usage_len, "[%s] ", option_desc->option);
+ if (len < 0)
+ err(1, "%s: snprintf(", __func__);
+
+ usage_len += len;
+ if (usage_len > BUF_MAX)
+ break;
+ }
+ printf("%s\n", usage_str);
+ printf("options:\n");
+
+ for (option_desc = option_desc_list; option_desc->option != NULL; option_desc++) {
+ printf(" %-20s # %s\n", option_desc->option, option_desc->description);
+ }
+
+}
+
+int
+main(int argc, char * const argv[]) {
+ int ch;
+ int error;
+
+ if (argc == 1) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ while ((ch = getopt(argc, argv, "hf:l:r:t:p:m:M:L:R:")) != -1) {
+ switch (ch) {
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case 'f': {
+ if (strcasecmp(optarg, "in") == 0) {
+ dir = IN;
+ } else if (strcasecmp(optarg, "out") == 0) {
+ dir = OUT;
+ } else if (strcasecmp(optarg, "inout") == 0) {
+ dir = INOUT;
+ } else {
+ usage(argv[0]);
+ errx(1, "syntax error");
+ }
+ }
+ break;
+ case 'l':
+ if ((error = getaddrinfo(optarg, NULL, NULL, &p_localaddr)))
+ errx(1, "getaddrinfo returned error: %s", gai_strerror(error));
+
+ break;
+ case 'r':
+ if ((error = getaddrinfo(optarg, NULL, NULL, &p_remoteaddr)))
+ errx(1, "getaddrinfo returned error: %s", gai_strerror(error));
+
+ break;
+ case 'm':
+ ip_act_mask = (uint32_t)atoi(optarg);
+ break;
+ case 't':
+ duration = (uint32_t)atoi(optarg);
+ break;
+ case 'p':
+ /* Only support tcp for now */
+ if (strcasecmp(optarg, "tcp") == 0) {
+ protocol = IPPROTO_TCP;
+ } else if (strcasecmp(optarg, "udp") == 0) {
+ protocol = IPPROTO_UDP;
+ errx(1, "Protocol not supported.");
+ } else if (strcasecmp(optarg, "icmp") == 0) {
+ protocol = IPPROTO_ICMP;
+ errx(1, "Protocol not supported.");
+ } else if (strcasecmp(optarg, "icmpv6") == 0) {
+ protocol = IPPROTO_ICMPV6;
+ errx(1, "Protocol not supported.");
+ } else {
+ errx(1, "Protocol not supported.");
+ }
+ break;
+
+ case 'L':
+ local_port = htons((uint16_t)atoi(optarg));
+ break;
+ case 'R':
+ remote_port = htons((uint16_t)atoi(optarg));
+ break;
+ case 'M':
+ proto_act_mask = (uint32_t)atoi(optarg);
+ break;
+
+ default:
+ warnx("# syntax error, unknow option '%d'", ch);
+ usage(argv[0]);
+ exit(0);
+ }
+ }
+
+ if (p_localaddr && p_remoteaddr) {
+ if (p_localaddr->ai_family!=p_remoteaddr->ai_family) {
+ errx(1, "The address families for local and remote address"
+ " when both present, must be equal");
+ }
+ }
+
+
+ doit();
+
+ return (0);
+}
+
+
+int
+doit()
+{
+ struct sockaddr_ctl addr;
+
+ sf = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+ if (sf == -1) {
+ err(1, "socket()");
+ }
+
+ /* Connect the socket */
+ bzero(&addr, sizeof(addr));
+ addr.sc_len = sizeof(addr);
+ addr.sc_family = AF_SYSTEM;
+ addr.ss_sysaddr = AF_SYS_CONTROL;
+
+ {
+ struct ctl_info info;
+ memset(&info, 0, sizeof(info));
+ strlcpy(info.ctl_name, PACKET_MANGLER_CONTROL_NAME, sizeof(info.ctl_name));
+ if (ioctl(sf, CTLIOCGINFO, &info)) {
+ perror("Could not get ID for kernel control.\n");
+ exit(-1);
+ }
+ addr.sc_id = info.ctl_id;
+ addr.sc_unit = 1;
+ }
+
+ if (connect(sf, (struct sockaddr *)&addr, sizeof(struct sockaddr_ctl)) == -1) {
+ err(1, "connect()");
+ }
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_DIRECTION,
+ &dir, sizeof(uint32_t)) == -1) {
+ err(1, "setsockopt could not set direction.");
+ }
+
+ /* Set the IP addresses for the flow */
+ if (p_localaddr) {
+ l_saddr = *((struct sockaddr_storage *)(p_localaddr->ai_addr));
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_LOCAL_IP,
+ &l_saddr, sizeof(struct sockaddr_storage)) == -1) {
+ err(1, "setsockopt could not set local address.");
+ }
+ freeaddrinfo(p_localaddr);
+ p_localaddr = NULL;
+ }
+
+ if (p_remoteaddr) {
+ r_saddr = *((struct sockaddr_storage *)(p_remoteaddr->ai_addr));
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_REMOTE_IP,
+ &r_saddr, sizeof(struct sockaddr_storage)) == -1) {
+ err(1, "setsockopt could not set remote address.");
+ }
+ freeaddrinfo(p_remoteaddr);
+ p_remoteaddr = NULL;
+ }
+
+ /* Set ports for the flow */
+ if (local_port && (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_LOCAL_PORT,
+ &local_port, sizeof(uint16_t)) == -1)) {
+ err(1, "setsockopt could not set local port.");
+
+ }
+
+ if (remote_port && (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_REMOTE_PORT,
+ &remote_port, sizeof(uint16_t)) == -1)) {
+ err(1, "setsockopt could not set remote port.");
+
+ }
+
+ if (protocol && setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_PROTOCOL,
+ &protocol, sizeof(uint32_t)) == -1) {
+ err(1, "setsockopt could not set protocol.");
+ }
+
+ if (proto_act_mask &&
+ (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_PROTO_ACT_MASK,
+ &proto_act_mask, sizeof(uint32_t))==-1)) {
+ err(1, "setsockopt could not set protocol action mask.");
+ }
+
+ if (setsockopt(sf, SYSPROTO_CONTROL, PKT_MNGLR_OPT_ACTIVATE,
+ &activate, sizeof(uint8_t))== -1) {
+ err(1, "setsockopt could not activate packet mangler.");
+ }
+
+ if (!duration) {
+ pause();
+ } else {
+ sleep(duration);
+ }
+
+ close(sf);
+ return 0;
+}
diff --git a/network_cmds/rarpd.tproj/rarpd.8 b/network_cmds/rarpd.tproj/rarpd.8
new file mode 100644
index 0000000..39ecff6
--- /dev/null
+++ b/network_cmds/rarpd.tproj/rarpd.8
@@ -0,0 +1,92 @@
+.\"
+.\" Copyright (c) 1988-1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that: (1) source code distributions
+.\" retain the above copyright notice and this paragraph in its entirety, (2)
+.\" distributions including binary code include the above copyright notice and
+.\" this paragraph in its entirety in the documentation or other materials
+.\" provided with the distribution, and (3) all advertising materials mentioning
+.\" features or use of this software display the following acknowledgement:
+.\" ``This product includes software developed by the University of California,
+.\" Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+.\" the University nor the names of its contributors may be used to endorse
+.\" or promote products derived from this software without specific prior
+.\" written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\" @(#) $Id: rarpd.8,v 1.1 1999/05/02 03:57:59 wsanchez Exp $
+.\"
+.Dd October 26, 1990
+.Dt RARPD 8
+.Sh NAME
+.Nm rarpd
+.Nd Reverse ARP Daemon
+.Sh SYNOPSIS
+.Nm rarpd
+.Op Fl adf
+.Op Ar interface
+.Sh DESCRIPTION
+.Nm Rarpd
+services Reverse ARP requests on the Ethernet connected to
+.Ar interface.
+Upon receiving a request,
+.Nm rarpd
+maps the target hardware address to an IP address via its name, which
+must be present in both the
+.Xr ethers 5
+and
+.Xr hosts 5
+databases.
+If a host does not exist in both databases, the translation cannot
+proceed and a reply will not be sent.
+.Pp
+Additionally, a request is honored only if the server
+(i.e., the host that rarpd is running on)
+can "boot" the target; that is, if the directory
+.Pa /tftpboot/ Ns Em ipaddr
+exists, where
+.Rm ipaddr
+is the target IP address.
+.Pp
+In normal operation,
+.Nm rarpd
+forks a copy of itself and runs in
+the background. Anomalies and errors are reported via
+.Xr syslog 3 .
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl a
+Listen on all the Ethernets attached to the system.
+If
+.Sq Fl a
+is omitted, an interface must be specified.
+.It Fl d
+Run in debug mode, with all the output to stderr.
+This option implies the
+.Fl f
+option.
+.It Fl f
+Run in the foreground.
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /etc/ethers
+.It Pa /etc/hosts
+.It Pa /tftpboot
+.El
+.Sh SEE ALSO
+.Xr bpf 4 ,
+.Rs
+.%R A Reverse Address Resolution Protocol
+.%N RFC 903
+.%A Finlayson, R.
+.%A Mann, T.
+.%A Mogul, J.C.
+.%A Theimer, M.
+.Re
+.Sh AUTHORS
+Craig Leres (leres@ee.lbl.gov) and Steven McCanne (mccanne@ee.lbl.gov).
+Lawrence Berkeley Laboratory, University of California, Berkeley, CA.
diff --git a/network_cmds/rarpd.tproj/rarpd.c b/network_cmds/rarpd.tproj/rarpd.c
new file mode 100644
index 0000000..1a3ae51
--- /dev/null
+++ b/network_cmds/rarpd.tproj/rarpd.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright (c) 1999-2009 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * rarpd - Reverse ARP Daemon
+ *
+ * Usage: rarpd -a [ -d -f ]
+ * rarpd [ -d -f ] interface
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+
+#define FATAL 1 /* fatal error occurred */
+#define NONFATAL 0 /* non fatal error occurred */
+
+/*
+ * The structure for each interface.
+ */
+struct if_info {
+ int ii_fd; /* BPF file descriptor */
+ u_char ii_eaddr[6]; /* Ethernet address of this interface */
+ in_addr_t ii_ipaddr; /* IP address of this interface */
+ in_addr_t ii_netmask; /* subnet or net mask */
+ struct if_info *ii_next;
+};
+/*
+ * The list of all interfaces that are being listened to. rarp_loop()
+ * "selects" on the descriptors in this list.
+ */
+struct if_info *iflist;
+
+int rarp_open __P((char *));
+int rarp_bootable __P((in_addr_t));
+void init_one __P((char *));
+void init_all __P((void));
+void rarp_loop __P((void));
+void lookup_eaddr __P((char *, u_char *));
+void lookup_ipaddr __P((char *, in_addr_t *, in_addr_t *));
+void usage __P((void));
+void rarp_process __P((struct if_info *, u_char *));
+void rarp_reply __P((struct if_info *, struct ether_header *, in_addr_t));
+void update_arptab __P((u_char *, in_addr_t));
+void err __P((int, const char *,...));
+void debug __P((const char *,...));
+in_addr_t ipaddrtonetmask __P((in_addr_t));
+
+int aflag = 0; /* listen on "all" interfaces */
+int dflag = 0; /* print debugging messages */
+int fflag = 0; /* don't fork */
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int op, pid, devnull, f;
+ char *ifname, *hostname, *name;
+
+ extern int optind, opterr;
+
+ if ((name = strrchr(argv[0], '/')) != NULL)
+ ++name;
+ else
+ name = argv[0];
+ if (*name == '-')
+ ++name;
+
+ /* All error reporting is done through syslogs. */
+ openlog(name, LOG_PID | LOG_CONS, LOG_DAEMON);
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "adf")) != EOF) {
+ switch (op) {
+ case 'a':
+ ++aflag;
+ break;
+
+ case 'd':
+ ++dflag;
+ break;
+
+ case 'f':
+ ++fflag;
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ ifname = argv[optind++];
+ hostname = ifname ? argv[optind] : 0;
+ if ((aflag && ifname) || (!aflag && ifname == 0))
+ usage();
+
+ if (aflag)
+ init_all();
+ else
+ init_one(ifname);
+
+ if ((!fflag) && (!dflag)) {
+ pid = fork();
+ if (pid > 0)
+ /* Parent exits, leaving child in background. */
+ exit(0);
+ else
+ if (pid == -1) {
+ err(FATAL, "cannot fork");
+ /* NOTREACHED */
+ }
+ /* Fade into the background */
+ f = open("/dev/tty", O_RDWR);
+ if (f >= 0) {
+ if (ioctl(f, TIOCNOTTY, 0) < 0) {
+ err(FATAL, "TIOCNOTTY: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) close(f);
+ }
+ (void) chdir("/");
+ (void) setpgid(0, getpid());
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull >= 0) {
+ (void) dup2(devnull, 0);
+ (void) dup2(devnull, 1);
+ (void) dup2(devnull, 2);
+ if (devnull > 2)
+ (void) close(devnull);
+ }
+ }
+ rarp_loop();
+ /* NOTREACHED */
+ return 0;
+}
+/*
+ * Add 'ifname' to the interface list. Lookup its IP address and network
+ * mask and Ethernet address, and open a BPF file for it.
+ */
+void
+init_one(ifname)
+ char *ifname;
+{
+ struct if_info *p;
+
+ p = (struct if_info *)malloc(sizeof(*p));
+ if (p == 0) {
+ err(FATAL, "malloc: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ p->ii_next = iflist;
+ iflist = p;
+
+ p->ii_fd = rarp_open(ifname);
+ lookup_eaddr(ifname, p->ii_eaddr);
+ lookup_ipaddr(ifname, &p->ii_ipaddr, &p->ii_netmask);
+}
+/*
+ * Initialize all "candidate" interfaces that are in the system
+ * configuration list. A "candidate" is up, not loopback and not
+ * point to point.
+ */
+void
+init_all()
+{
+ char inbuf[8192];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ int fd;
+ int i, len;
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ err(FATAL, "init_all: SIOCGIFCONF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ ifr = ifc.ifc_req;
+ for (i = 0; i < ifc.ifc_len;
+ i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
+ len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+ if (ioctl(fd, SIOCGIFFLAGS, (caddr_t)ifr) < 0) {
+ err(FATAL, "init_all: SIOCGIFFLAGS: %s",
+ strerror(errno));
+ /* NOTREACHED */
+ }
+ if ((ifr->ifr_flags &
+ (IFF_UP | IFF_LOOPBACK | IFF_POINTOPOINT)) != IFF_UP)
+ continue;
+ init_one(ifr->ifr_name);
+ }
+ (void) close(fd);
+}
+
+void
+usage()
+{
+ (void) fprintf(stderr, "usage: rarpd -a [ -d -f ]\n");
+ (void) fprintf(stderr, " rarpd [ -d -f ] interface\n");
+ exit(1);
+}
+
+static int
+bpf_open()
+{
+ int fd;
+ int n = 0;
+ char device[sizeof "/dev/bpf000"];
+
+ /* Go through all the minors and find one that isn't in use. */
+ do {
+ (void) snprintf(device, sizeof(device), "/dev/bpf%d", n++);
+ fd = open(device, O_RDWR);
+ } while (fd < 0 && errno == EBUSY);
+
+ if (fd < 0) {
+ err(FATAL, "%s: %s", device, strerror(errno));
+ /* NOTREACHED */
+ }
+ return fd;
+}
+/*
+ * Open a BPF file and attach it to the interface named 'device'.
+ * Set immediate mode, and set a filter that accepts only RARP requests.
+ */
+int
+rarp_open(device)
+ char *device;
+{
+ int fd;
+ struct ifreq ifr;
+ u_int dlt;
+ int immediate;
+
+ static struct bpf_insn insns[] = {
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_REVARP, 0, 3),
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ARPOP_REVREQUEST, 0, 1),
+ BPF_STMT(BPF_RET | BPF_K, sizeof(struct ether_arp) +
+ sizeof(struct ether_header)),
+ BPF_STMT(BPF_RET | BPF_K, 0),
+ };
+ static struct bpf_program filter = {
+ sizeof insns / sizeof(insns[0]),
+ insns
+ };
+
+ fd = bpf_open();
+
+ /* Set immediate mode so packets are processed as they arrive. */
+ immediate = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &immediate) < 0) {
+ err(FATAL, "BIOCIMMEDIATE: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) strlcpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
+ if (ioctl(fd, BIOCSETIF, (caddr_t) & ifr) < 0) {
+ err(FATAL, "BIOCSETIF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /* Check that the data link layer is an Ethernet; this code won't work
+ * with anything else. */
+ if (ioctl(fd, BIOCGDLT, (caddr_t) & dlt) < 0) {
+ err(FATAL, "BIOCGDLT: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ if (dlt != DLT_EN10MB) {
+ err(FATAL, "%s is not an ethernet", device);
+ /* NOTREACHED */
+ }
+ /* Set filter program. */
+ if (ioctl(fd, BIOCSETF, (caddr_t) & filter) < 0) {
+ err(FATAL, "BIOCSETF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ return fd;
+}
+/*
+ * Perform various sanity checks on the RARP request packet. Return
+ * false on failure and log the reason.
+ */
+static int
+rarp_check(p, len)
+ u_char *p;
+ int len;
+{
+ struct ether_header *ep = (struct ether_header *) p;
+ struct ether_arp *ap = (struct ether_arp *) (p + sizeof(*ep));
+
+ (void) debug("got a packet");
+
+ if (len < sizeof(*ep) + sizeof(*ap)) {
+ err(NONFATAL, "truncated request");
+ return 0;
+ }
+ /* XXX This test might be better off broken out... */
+ if (ntohs (ep->ether_type) != ETHERTYPE_REVARP ||
+ ntohs (ap->arp_hrd) != ARPHRD_ETHER ||
+ ntohs (ap->arp_op) != ARPOP_REVREQUEST ||
+ ntohs (ap->arp_pro) != ETHERTYPE_IP ||
+ ap->arp_hln != 6 || ap->arp_pln != 4) {
+ err(NONFATAL, "request fails sanity check");
+ return 0;
+ }
+ if (bcmp((char *) &ep->ether_shost, (char *) &ap->arp_sha, 6) != 0) {
+ err(NONFATAL, "ether/arp sender address mismatch");
+ return 0;
+ }
+ if (bcmp((char *) &ap->arp_sha, (char *) &ap->arp_tha, 6) != 0) {
+ err(NONFATAL, "ether/arp target address mismatch");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Loop indefinitely listening for RARP requests on the
+ * interfaces in 'iflist'.
+ */
+void
+rarp_loop()
+{
+ u_char *buf, *bp, *ep;
+ int cc, fd;
+ fd_set fds, listeners;
+ int bufsize, maxfd = 0;
+ struct if_info *ii;
+
+ if (iflist == 0) {
+ err(FATAL, "no interfaces");
+ /* NOTREACHED */
+ }
+ if (ioctl(iflist->ii_fd, BIOCGBLEN, (caddr_t) & bufsize) < 0) {
+ err(FATAL, "BIOCGBLEN: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ buf = (u_char *) malloc((unsigned) bufsize);
+ if (buf == 0) {
+ err(FATAL, "malloc: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /*
+ * Find the highest numbered file descriptor for select().
+ * Initialize the set of descriptors to listen to.
+ */
+ FD_ZERO(&fds);
+ for (ii = iflist; ii; ii = ii->ii_next) {
+ FD_SET(ii->ii_fd, &fds);
+ if (ii->ii_fd > maxfd)
+ maxfd = ii->ii_fd;
+ }
+ while (1) {
+ listeners = fds;
+ if (select(maxfd + 1, &listeners, (struct fd_set *) 0,
+ (struct fd_set *) 0, (struct timeval *) 0) < 0) {
+ err(FATAL, "select: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ for (ii = iflist; ii; ii = ii->ii_next) {
+ fd = ii->ii_fd;
+ if (!FD_ISSET(fd, &listeners))
+ continue;
+ again:
+ cc = read(fd, (char *) buf, bufsize);
+ /* Don't choke when we get ptraced */
+ if (cc < 0 && errno == EINTR)
+ goto again;
+ /* Due to a SunOS bug, after 2^31 bytes, the file
+ * offset overflows and read fails with EINVAL. The
+ * lseek() to 0 will fix things. */
+ if (cc < 0) {
+ if (errno == EINVAL &&
+ (lseek(fd, 0, SEEK_CUR) + bufsize) < 0) {
+ (void) lseek(fd, 0, 0);
+ goto again;
+ }
+ err(FATAL, "read: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ /* Loop through the packet(s) */
+#define bhp ((struct bpf_hdr *)bp)
+ bp = buf;
+ ep = bp + cc;
+ while (bp < ep) {
+ register int caplen, hdrlen;
+
+ caplen = bhp->bh_caplen;
+ hdrlen = bhp->bh_hdrlen;
+ if (rarp_check(bp + hdrlen, caplen))
+ rarp_process(ii, bp + hdrlen);
+ bp += BPF_WORDALIGN(hdrlen + caplen);
+ }
+ }
+ }
+}
+#ifndef TFTP_DIR
+#define TFTP_DIR "/tftpboot"
+#endif
+
+/*
+ * True if this server can boot the host whose IP address is 'addr'.
+ * This check is made by looking in the tftp directory for the
+ * configuration file.
+ */
+int
+rarp_bootable(addr)
+ in_addr_t addr;
+{
+ register struct dirent *dent;
+ register DIR *d;
+ char ipname[9];
+ static DIR *dd = 0;
+
+ (void) snprintf(ipname, sizeof(ipname), "%08X", addr);
+ /* If directory is already open, rewind it. Otherwise, open it. */
+ if ((d = dd) != NULL)
+ rewinddir(d);
+ else {
+ if (chdir(TFTP_DIR) == -1) {
+ err(FATAL, "chdir: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ d = opendir(".");
+ if (d == 0) {
+ err(FATAL, "opendir: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ dd = d;
+ }
+ while ((dent = readdir(d)) != NULL)
+ if (strncmp(dent->d_name, ipname, 8) == 0)
+ return 1;
+ return 0;
+}
+/*
+ * Given a list of IP addresses, 'alist', return the first address that
+ * is on network 'net'; 'netmask' is a mask indicating the network portion
+ * of the address.
+ */
+in_addr_t
+choose_ipaddr(alist, net, netmask)
+ in_addr_t **alist;
+ in_addr_t net;
+ in_addr_t netmask;
+{
+ for (; *alist; ++alist) {
+ if ((**alist & netmask) == net)
+ return **alist;
+ }
+ return 0;
+}
+/*
+ * Answer the RARP request in 'pkt', on the interface 'ii'. 'pkt' has
+ * already been checked for validity. The reply is overlaid on the request.
+ */
+void
+rarp_process(ii, pkt)
+ struct if_info *ii;
+ u_char *pkt;
+{
+ struct ether_header *ep;
+ struct hostent *hp;
+ in_addr_t target_ipaddr;
+ char ename[256];
+ struct in_addr in;
+
+ ep = (struct ether_header *) pkt;
+
+ if (ether_ntohost(ename, (struct ether_addr *)&ep->ether_shost) != 0 ||
+ (hp = gethostbyname(ename)) == 0)
+ return;
+
+ /* Choose correct address from list. */
+ if (hp->h_addrtype != AF_INET) {
+ err(FATAL, "cannot handle non IP addresses");
+ /* NOTREACHED */
+ }
+ target_ipaddr = choose_ipaddr((in_addr_t **) hp->h_addr_list,
+ ii->ii_ipaddr & ii->ii_netmask, ii->ii_netmask);
+
+ if (target_ipaddr == 0) {
+ in.s_addr = ii->ii_ipaddr & ii->ii_netmask;
+ err(NONFATAL, "cannot find %s on net %s\n",
+ ename, inet_ntoa(in));
+ return;
+ }
+ if (rarp_bootable(htonl(target_ipaddr)))
+ rarp_reply(ii, ep, target_ipaddr);
+}
+/*
+ * Lookup the ethernet address of the interface attached to the BPF
+ * file descriptor 'fd'; return it in 'eaddr'.
+ */
+void
+lookup_eaddr(ifname, eaddr)
+ char *ifname;
+ u_char *eaddr;
+{
+ char inbuf[8192];
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct sockaddr_dl *sdl;
+ int fd;
+ int i, len;
+
+ /* We cannot use SIOCGIFADDR on the BPF descriptor.
+ We must instead get all the interfaces with SIOCGIFCONF
+ and find the right one. */
+
+ /* Use datagram socket to get Ethernet address. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+
+ ifc.ifc_len = sizeof(inbuf);
+ ifc.ifc_buf = inbuf;
+ if (ioctl(fd, SIOCGIFCONF, (caddr_t)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ err(FATAL, "lookup_eaddr: SIOGIFCONF: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ ifr = ifc.ifc_req;
+ for (i = 0; i < ifc.ifc_len;
+ i += len, ifr = (struct ifreq *)((caddr_t)ifr + len)) {
+ len = sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
+ sdl = (struct sockaddr_dl *)&ifr->ifr_addr;
+ if (sdl->sdl_family != AF_LINK || sdl->sdl_type != IFT_ETHER ||
+ sdl->sdl_alen != 6)
+ continue;
+ if (!strncmp(ifr->ifr_name, ifname, sizeof(ifr->ifr_name))) {
+ bcopy((caddr_t)LLADDR(sdl), (caddr_t)eaddr, 6);
+ if (dflag)
+ fprintf(stderr, "%s: %x:%x:%x:%x:%x:%x\n",
+ ifr->ifr_name, eaddr[0], eaddr[1],
+ eaddr[2], eaddr[3], eaddr[4], eaddr[5]);
+ return;
+ }
+ }
+
+ err(FATAL, "lookup_eaddr: Never saw interface `%s'!", ifname);
+}
+/*
+ * Lookup the IP address and network mask of the interface named 'ifname'.
+ */
+void
+lookup_ipaddr(ifname, addrp, netmaskp)
+ char *ifname;
+ in_addr_t *addrp;
+ in_addr_t *netmaskp;
+{
+ int fd;
+ struct ifreq ifr;
+
+ /* Use datagram socket to get IP address. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ err(FATAL, "socket: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) strlcpy(ifr.ifr_name, ifname, sizeof ifr.ifr_name);
+ if (ioctl(fd, SIOCGIFADDR, (char *) &ifr) < 0) {
+ err(FATAL, "SIOCGIFADDR: %s", strerror(errno));
+ /* NOTREACHED */
+ }
+ *addrp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr;
+ if (ioctl(fd, SIOCGIFNETMASK, (char *) &ifr) < 0) {
+ perror("SIOCGIFNETMASK");
+ exit(1);
+ }
+ *netmaskp = ((struct sockaddr_in *) & ifr.ifr_addr)->sin_addr.s_addr;
+ /* If SIOCGIFNETMASK didn't work, figure out a mask from the IP
+ * address class. */
+ if (*netmaskp == 0)
+ *netmaskp = ipaddrtonetmask(*addrp);
+
+ (void) close(fd);
+}
+/*
+ * Poke the kernel arp tables with the ethernet/ip address combinataion
+ * given. When processing a reply, we must do this so that the booting
+ * host (i.e. the guy running rarpd), won't try to ARP for the hardware
+ * address of the guy being booted (he cannot answer the ARP).
+ */
+void
+update_arptab(ep, ipaddr)
+ u_char *ep;
+ in_addr_t ipaddr;
+{
+ //int s;
+ struct arpreq request;
+ struct sockaddr_in *sin;
+
+ request.arp_flags = 0;
+ sin = (struct sockaddr_in *) & request.arp_pa;
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = ipaddr;
+ request.arp_ha.sa_family = AF_UNSPEC;
+ /* This is needed #if defined(COMPAT_43) && BYTE_ORDER != BIG_ENDIAN,
+ because AF_UNSPEC is zero and the kernel assumes that a zero
+ sa_family means that the real sa_family value is in sa_len. */
+ request.arp_ha.sa_len = 16; /* XXX */
+ bcopy((char *) ep, (char *) request.arp_ha.sa_data, 6);
+
+#if 0
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ioctl(s, SIOCSARP, (caddr_t) & request) < 0) {
+ err(NONFATAL, "SIOCSARP: %s", strerror(errno));
+ }
+ (void) close(s);
+#endif
+}
+/*
+ * Build a reverse ARP packet and sent it out on the interface.
+ * 'ep' points to a valid ARPOP_REVREQUEST. The ARPOP_REVREPLY is built
+ * on top of the request, then written to the network.
+ *
+ * RFC 903 defines the ether_arp fields as follows. The following comments
+ * are taken (more or less) straight from this document.
+ *
+ * ARPOP_REVREQUEST
+ *
+ * arp_sha is the hardware address of the sender of the packet.
+ * arp_spa is undefined.
+ * arp_tha is the 'target' hardware address.
+ * In the case where the sender wishes to determine his own
+ * protocol address, this, like arp_sha, will be the hardware
+ * address of the sender.
+ * arp_tpa is undefined.
+ *
+ * ARPOP_REVREPLY
+ *
+ * arp_sha is the hardware address of the responder (the sender of the
+ * reply packet).
+ * arp_spa is the protocol address of the responder (see the note below).
+ * arp_tha is the hardware address of the target, and should be the same as
+ * that which was given in the request.
+ * arp_tpa is the protocol address of the target, that is, the desired address.
+ *
+ * Note that the requirement that arp_spa be filled in with the responder's
+ * protocol is purely for convenience. For instance, if a system were to use
+ * both ARP and RARP, then the inclusion of the valid protocol-hardware
+ * address pair (arp_spa, arp_sha) may eliminate the need for a subsequent
+ * ARP request.
+ */
+void
+rarp_reply(ii, ep, ipaddr)
+ struct if_info *ii;
+ struct ether_header *ep;
+ in_addr_t ipaddr;
+{
+ int n;
+ struct ether_arp *ap = (struct ether_arp *) (ep + 1);
+ int len;
+
+ update_arptab((u_char *) & ap->arp_sha, ipaddr);
+
+ /* Build the rarp reply by modifying the rarp request in place. */
+ ep->ether_type = htons(ETHERTYPE_REVARP);
+ ap->ea_hdr.ar_hrd = htons(ARPHRD_ETHER);
+ ap->ea_hdr.ar_pro = htons(ETHERTYPE_IP);
+ ap->arp_op = htons(ARPOP_REVREPLY);
+
+ bcopy((char *) &ap->arp_sha, (char *) &ep->ether_dhost, 6);
+ bcopy((char *) ii->ii_eaddr, (char *) &ep->ether_shost, 6);
+ bcopy((char *) ii->ii_eaddr, (char *) &ap->arp_sha, 6);
+
+ bcopy((char *) &ipaddr, (char *) ap->arp_tpa, 4);
+ /* Target hardware is unchanged. */
+ bcopy((char *) &ii->ii_ipaddr, (char *) ap->arp_spa, 4);
+
+ len = sizeof(*ep) + sizeof(*ap);
+ n = write(ii->ii_fd, (char *) ep, len);
+ if (n != len) {
+ err(NONFATAL, "write: only %d of %d bytes written", n, len);
+ }
+}
+/*
+ * Get the netmask of an IP address. This routine is used if
+ * SIOCGIFNETMASK doesn't work.
+ */
+in_addr_t
+ipaddrtonetmask(addr)
+ in_addr_t addr;
+{
+ if (IN_CLASSA(addr))
+ return IN_CLASSA_NET;
+ if (IN_CLASSB(addr))
+ return IN_CLASSB_NET;
+ if (IN_CLASSC(addr))
+ return IN_CLASSC_NET;
+ err(FATAL, "unknown IP address class: %08X", addr);
+ /* NOTREACHED */
+ return 0;
+}
+
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+err(int fatal, const char *fmt,...)
+#else
+err(fmt, va_alist)
+ int fatal;
+ char *fmt;
+va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ if (dflag) {
+ if (fatal)
+ (void) fprintf(stderr, "rarpd: error: ");
+ else
+ (void) fprintf(stderr, "rarpd: warning: ");
+ (void) vfprintf(stderr, fmt, ap);
+ (void) fprintf(stderr, "\n");
+ }
+ vsyslog(LOG_ERR, fmt, ap);
+ va_end(ap);
+ if (fatal)
+ exit(1);
+ /* NOTREACHED */
+}
+
+void
+#if __STDC__
+debug(const char *fmt,...)
+#else
+debug(fmt, va_alist)
+ char *fmt;
+va_dcl
+#endif
+{
+ va_list ap;
+
+ if (dflag) {
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void) fprintf(stderr, "rarpd: ");
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void) fprintf(stderr, "\n");
+ }
+}
diff --git a/network_cmds/route.tproj/gen_header.pl b/network_cmds/route.tproj/gen_header.pl
new file mode 100755
index 0000000..dfd9963
--- /dev/null
+++ b/network_cmds/route.tproj/gen_header.pl
@@ -0,0 +1,15 @@
+#!/usr/local/bin/perl -n
+#
+# Too run convert the keywords run the following command
+# gen_header.pl keywords > keywords.h
+
+next if m/^#/;
+next if m/^$/;
+$line_no++;
+chop;
+$keyword = $_;
+$upper = $keyword;
+$upper =~ tr/a-z/A-Z/;
+
+printf "#define\tK_%s\t%d\n\t{\"%s\", K_%s},\n",
+ $upper, $line_no, $keyword, $upper;
diff --git a/network_cmds/route.tproj/keywords b/network_cmds/route.tproj/keywords
new file mode 100644
index 0000000..8e740e3
--- /dev/null
+++ b/network_cmds/route.tproj/keywords
@@ -0,0 +1,49 @@
+# @(#)keywords 8.2 (Berkeley) 3/19/94
+
+add
+atalk
+blackhole
+change
+cloning
+delete
+dst
+expire
+flush
+gateway
+genmask
+get
+host
+hopcount
+iface
+ifscope
+interface
+ifa
+ifp
+inet
+inet6
+iso
+link
+llinfo
+lock
+lockrest
+mask
+monitor
+mtu
+net
+netmask
+nostatic
+osi
+prefixlen
+proto1
+proto2
+recvpipe
+reject
+rtt
+rttvar
+sa
+sendpipe
+ssthresh
+static
+x25
+xns
+xresolve
diff --git a/network_cmds/route.tproj/keywords.h b/network_cmds/route.tproj/keywords.h
new file mode 100644
index 0000000..b9edd54
--- /dev/null
+++ b/network_cmds/route.tproj/keywords.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#define K_ADD 1
+ {"add", K_ADD},
+#define K_BLACKHOLE 2
+ {"blackhole", K_BLACKHOLE},
+#define K_CHANGE 3
+ {"change", K_CHANGE},
+#define K_CLONING 4
+ {"cloning", K_CLONING},
+#define K_DELETE 5
+ {"delete", K_DELETE},
+#define K_DST 6
+ {"dst", K_DST},
+#define K_EXPIRE 7
+ {"expire", K_EXPIRE},
+#define K_FLUSH 8
+ {"flush", K_FLUSH},
+#define K_GATEWAY 9
+ {"gateway", K_GATEWAY},
+#define K_GENMASK 10
+ {"genmask", K_GENMASK},
+#define K_GET 11
+ {"get", K_GET},
+#define K_HOST 12
+ {"host", K_HOST},
+#define K_HOPCOUNT 13
+ {"hopcount", K_HOPCOUNT},
+#define K_IFACE 14
+ {"iface", K_IFACE},
+#define K_INTERFACE 15
+ {"interface", K_INTERFACE},
+#define K_IFA 16
+ {"ifa", K_IFA},
+#define K_IFP 17
+ {"ifp", K_IFP},
+#define K_INET 18
+ {"inet", K_INET},
+#define K_INET6 19
+ {"inet6", K_INET6},
+#define K_ISO 20
+ {"iso", K_ISO},
+#define K_LINK 21
+ {"link", K_LINK},
+#define K_LLINFO 22
+ {"llinfo", K_LLINFO},
+#define K_LOCK 23
+ {"lock", K_LOCK},
+#define K_LOCKREST 24
+ {"lockrest", K_LOCKREST},
+#define K_MASK 25
+ {"mask", K_MASK},
+#define K_MONITOR 26
+ {"monitor", K_MONITOR},
+#define K_MTU 27
+ {"mtu", K_MTU},
+#define K_NET 28
+ {"net", K_NET},
+#define K_NETMASK 29
+ {"netmask", K_NETMASK},
+#define K_NOSTATIC 30
+ {"nostatic", K_NOSTATIC},
+#define K_OSI 31
+ {"osi", K_OSI},
+#define K_PREFIXLEN 32
+ {"prefixlen", K_PREFIXLEN},
+#define K_PROTO1 33
+ {"proto1", K_PROTO1},
+#define K_PROTO2 34
+ {"proto2", K_PROTO2},
+#define K_RECVPIPE 35
+ {"recvpipe", K_RECVPIPE},
+#define K_REJECT 36
+ {"reject", K_REJECT},
+#define K_RTT 37
+ {"rtt", K_RTT},
+#define K_RTTVAR 38
+ {"rttvar", K_RTTVAR},
+#define K_SA 39
+ {"sa", K_SA},
+#define K_SENDPIPE 40
+ {"sendpipe", K_SENDPIPE},
+#define K_SSTHRESH 41
+ {"ssthresh", K_SSTHRESH},
+#define K_STATIC 42
+ {"static", K_STATIC},
+#define K_X25 43
+ {"x25", K_X25},
+#define K_XNS 44
+ {"xns", K_XNS},
+#define K_XRESOLVE 45
+ {"xresolve", K_XRESOLVE},
+#define K_IFSCOPE 46
+ {"ifscope", K_IFSCOPE},
diff --git a/network_cmds/route.tproj/route.8 b/network_cmds/route.tproj/route.8
new file mode 100644
index 0000000..74609c9
--- /dev/null
+++ b/network_cmds/route.tproj/route.8
@@ -0,0 +1,405 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)route.8 8.3 (Berkeley) 3/19/94
+.\" $FreeBSD: src/sbin/route/route.8,v 1.17.2.7 2001/10/02 10:04:01 ru Exp $
+.\"
+.Dd June 8, 2001
+.Dt ROUTE 8
+.Os BSD 4.4
+.Sh NAME
+.Nm route
+.Nd manually manipulate the routing tables
+.Sh SYNOPSIS
+.Nm
+.Op Fl dnqtv
+.Ar command
+.Oo
+.Op Ar modifiers
+.Ar args
+.Oc
+.Sh DESCRIPTION
+.Nm Route
+is a utility used to manually manipulate the network
+routing tables. It normally is not needed, as a
+system routing table management daemon such as
+.Xr routed 8 ,
+should tend to this task.
+.Pp
+The
+.Nm
+utility supports a limited number of general options,
+but a rich command language, enabling the user to specify
+any arbitrary request that could be delivered via the
+programmatic interface discussed in
+.Xr route 4 .
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl d
+Run in debug-only mode, i.e., do not actually modify the routing table.
+.It Fl n
+Bypass attempts to print host and network names symbolically
+when reporting actions. (The process of translating between symbolic
+names and numerical equivalents can be quite time consuming, and
+may require correct operation of the network; thus it may be expedient
+to forget this, especially when attempting to repair networking operations).
+.It Fl t
+Run in test-only mode.
+.Pa /dev/null
+is used instead of a socket.
+.It Fl v
+(verbose) Print additional details.
+.It Fl q
+Suppress all output.
+.El
+.Pp
+The
+.Nm
+utility provides six commands:
+.Pp
+.Bl -tag -width Fl -compact
+.It Cm add
+Add a route.
+.It Cm flush
+Remove all routes.
+.It Cm delete
+Delete a specific route.
+.It Cm change
+Change aspects of a route (such as its gateway).
+.It Cm get
+Lookup and display the route for a destination.
+.It Cm monitor
+Continuously report any changes to the routing information base,
+routing lookup misses, or suspected network partitionings.
+.El
+.Pp
+The monitor command has the syntax:
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Op Fl n
+.Cm monitor
+.Ed
+.Pp
+The flush command has the syntax:
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Op Fl n
+.Cm flush
+.Op Ar family
+.Ed
+.Pp
+If the
+.Cm flush
+command is specified,
+.Nm
+will ``flush'' the routing tables of all gateway entries.
+When the address family may is specified by any of the
+.Fl osi ,
+.Fl xns ,
+.Fl atalk ,
+.Fl inet6 ,
+or
+.Fl inet
+modifiers, only routes having destinations with addresses in the
+delineated family will be deleted.
+.Pp
+The other commands have the following syntax:
+.Pp
+.Bd -ragged -offset indent -compact
+.Nm
+.Op Fl n
+.Ar command
+.Op Fl net No \&| Fl host
+.Oo Fl ifscope
+.Ar boundif
+.Oc
+.Ar destination gateway
+.Op Ar netmask
+.Ed
+.Pp
+where
+.Ar destination
+is the destination host or network,
+.Ar gateway
+is the next-hop intermediary via which packets should be routed.
+Routes to a particular host may be distinguished from those to
+a network by interpreting the Internet address specified as the
+.Ar destination
+argument.
+The optional modifiers
+.Fl net
+and
+.Fl host
+force the destination to be interpreted as a network or a host, respectively.
+Otherwise, if the
+.Ar destination
+has a
+.Dq local address part
+of
+INADDR_ANY
+.Pq Li 0.0.0.0 ,
+or if the
+.Ar destination
+is the symbolic name of a network, then the route is
+assumed to be to a network; otherwise, it is presumed to be a
+route to a host.
+Optionally, the
+.Ar destination
+could also be specified in the
+.Ar net Ns / Ns Ar bits
+format.
+.Pp
+For example,
+.Li 128.32
+is interpreted as
+.Fl host Li 128.0.0.32 ;
+.Li 128.32.130
+is interpreted as
+.Fl host Li 128.32.0.130 ;
+.Fl net Li 128.32
+is interpreted as
+.Li 128.32.0.0;
+.Fl net Li 128.32.130
+is interpreted as
+.Li 128.32.130.0;
+and
+.Li 192.168.64/20
+is interpreted as
+.Fl net Li 192.168.64 Fl netmask Li 255.255.240.0 .
+.Pp
+A
+.Ar destination
+of
+.Ar default
+is a synonym for
+.Fl net Li 0.0.0.0 ,
+which is the default route.
+.Pp
+If the destination is directly reachable
+via an interface requiring
+no intermediary system to act as a gateway, the
+.Fl interface
+modifier should be specified;
+the gateway given is the address of this host on the common network,
+indicating the interface to be used for transmission.
+Alternately, if the interface is point to point the name of the interface
+itself may be given, in which case the route remains valid even
+if the local or remote addresses change.
+.Pp
+For AF_INET and AF_INET6, the
+.Fl ifscope
+modifier specifies the additional property of the route related to
+the interface scope derived from interface
+.Ar boundif .
+Such property allows for the presence of multiple route entries with
+the same destination, where each route is associated with a unique
+interface. This modifier is required in order to manipulate route
+entries marked with the RTF_IFSCOPE flag.
+.Pp
+The optional modifier
+.Fl link
+specify that all subsequent addresses
+are specified as link-level addresses,
+and the names must be numeric specifications rather than
+symbolic names.
+.Pp
+The optional
+.Fl netmask
+modifier is intended
+to achieve the effect of an
+.Tn OSI
+.Tn ESIS
+redirect with the netmask option,
+or to manually add subnet routes with
+netmasks different from that of the implied network interface
+(as would otherwise be communicated using the OSPF or ISIS routing protocols).
+One specifies an additional ensuing address parameter
+(to be interpreted as a network mask).
+The implicit network mask generated in the AF_INET case
+can be overridden by making sure this option follows the destination parameter.
+.Pp
+For
+.Dv AF_INET6 ,
+the
+.Fl prefixlen
+qualifier
+is available instead of the
+.Fl mask
+qualifier because non-continuous masks are not allowed in IPv6.
+For example,
+.Fl prefixlen Li 32
+specifies network mask of
+.Li ffff:ffff:0000:0000:0000:0000:0000:0000
+to be used.
+The default value of prefixlen is 64 to get along with
+the aggregatable address.
+But 0 is assumed if
+.Cm default
+is specified.
+Note that the qualifier works only for
+.Dv AF_INET6
+address family.
+.Pp
+Routes have associated flags which influence operation of the protocols
+when sending to destinations matched by the routes.
+These flags may be set (or sometimes cleared)
+by indicating the following corresponding modifiers:
+.Bd -literal
+-cloning RTF_CLONING - generates a new route on use
+-xresolve RTF_XRESOLVE - emit mesg on use (for external lookup)
+-iface ~RTF_GATEWAY - destination is directly reachable
+-static RTF_STATIC - manually added route
+-nostatic ~RTF_STATIC - pretend route added by kernel or daemon
+-reject RTF_REJECT - emit an ICMP unreachable when matched
+-blackhole RTF_BLACKHOLE - silently discard pkts (during updates)
+-proto1 RTF_PROTO1 - set protocol specific routing flag #1
+-proto2 RTF_PROTO2 - set protocol specific routing flag #2
+-llinfo RTF_LLINFO - validly translates proto addr to link addr
+.Ed
+.Pp
+The optional modifiers
+.Fl rtt ,
+.Fl rttvar ,
+.Fl sendpipe ,
+.Fl recvpipe ,
+.Fl mtu ,
+.Fl hopcount ,
+.Fl expire ,
+and
+.Fl ssthresh
+provide initial values to quantities maintained in the routing entry
+by transport level protocols, such as TCP or TP4.
+These may be individually locked by preceding each such modifier to
+be locked by
+the
+.Fl lock
+meta-modifier, or one can
+specify that all ensuing metrics may be locked by the
+.Fl lockrest
+meta-modifier.
+.Pp
+In a
+.Cm change
+or
+.Cm add
+command where the destination and gateway are not sufficient to specify
+the route (as in the
+.Tn ISO
+case where several interfaces may have the
+same address), the
+.Fl ifp
+or
+.Fl ifa
+modifiers may be used to determine the interface or interface address.
+.Pp
+The optional
+.Fl proxy
+modifier specifies that the
+.Dv RTF_LLINFO
+routing table entry is the
+.Dq published (proxy-only)
+.Tn ARP
+entry, as reported by
+.Xr arp 8 .
+.Pp
+All symbolic names specified for a
+.Ar destination
+or
+.Ar gateway
+are looked up first as a host name using
+.Xr gethostbyname 3 .
+If this lookup fails,
+.Xr getnetbyname 3
+is then used to interpret the name as that of a network.
+.Pp
+.Nm Route
+uses a routing socket and the new message types
+.Dv RTM_ADD , RTM_DELETE , RTM_GET ,
+and
+.Dv RTM_CHANGE .
+As such, only the super-user may modify
+the routing tables.
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "add [host \&| network ] %s: gateway %s flags %x"
+The specified route is being added to the tables. The
+values printed are from the routing table entry supplied
+in the
+.Xr ioctl 2
+call.
+If the gateway address used was not the primary address of the gateway
+(the first one returned by
+.Xr gethostbyname 3 ) ,
+the gateway address is printed numerically as well as symbolically.
+.It "delete [ host \&| network ] %s: gateway %s flags %x"
+As above, but when deleting an entry.
+.It "%s %s done"
+When the
+.Cm flush
+command is specified, each routing table entry deleted
+is indicated with a message of this form.
+.It "Network is unreachable"
+An attempt to add a route failed because the gateway listed was not
+on a directly-connected network.
+The next-hop gateway must be given.
+.It "not in table"
+A delete operation was attempted for an entry which
+wasn't present in the tables.
+.It "routing table overflow"
+An add operation was attempted, but the system was
+low on resources and was unable to allocate memory
+to create the new entry.
+.It "gateway uses the same route"
+A
+.Cm change
+operation resulted in a route whose gateway uses the
+same route as the one being changed.
+The next-hop gateway should be reachable through a different route.
+.El
+.Pp
+.Ex -std
+.Sh SEE ALSO
+.Xr netintro 4 ,
+.Xr route 4 ,
+.Xr arp 8 ,
+.Xr routed 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Sh BUGS
+The first paragraph may have slightly exaggerated
+.Xr routed 8 Ns 's
+abilities.
diff --git a/network_cmds/route.tproj/route.c b/network_cmds/route.tproj/route.c
new file mode 100644
index 0000000..9f7f4bd
--- /dev/null
+++ b/network_cmds/route.tproj/route.c
@@ -0,0 +1,1571 @@
+/*
+ * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1983, 1989, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1983, 1989, 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+
+struct keytab {
+ char *kt_cp;
+ int kt_i;
+} keywords[] = {
+#include "keywords.h"
+ {0, 0}
+};
+
+union sockunion {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+#endif
+ struct sockaddr_dl sdl;
+ struct sockaddr_storage ss; /* added to avoid memory overrun */
+} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
+
+typedef union sockunion *sup;
+int pid, rtm_addrs, uid;
+int s;
+int forcehost, forcenet, doflush, nflag, af, qflag, tflag, keyword();
+int iflag, verbose, aflen = sizeof (struct sockaddr_in);
+int locking, lockrest, debugonly;
+struct rt_metrics rt_metrics;
+u_long rtm_inits;
+unsigned int ifscope;
+
+static const char *route_strerror(int);
+const char *routename(), *netname();
+void flushroutes(), newroute(), monitor(), sockaddr(), sodump(), bprintf();
+void print_getmsg(), print_rtmsg(), pmsg_common(), pmsg_addrs(), mask_addr();
+int getaddr(), rtmsg(), x25_makemask();
+int prefixlen();
+extern char *iso_ntoa();
+
+static void
+inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin,
+ struct sockaddr_in *sin_mask, in_addr_t bits);
+
+void usage __P((const char *)) __dead2;
+
+void
+usage(cp)
+ const char *cp;
+{
+ if (cp)
+ warnx("bad keyword: %s", cp);
+ (void) fprintf(stderr,
+ "usage: route [-dnqtv] command [[modifiers] args]\n");
+ exit(EX_USAGE);
+ /* NOTREACHED */
+}
+
+#define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch;
+
+ if (argc < 2)
+ usage((char *)NULL);
+
+ while ((ch = getopt(argc, argv, "nqdtv")) != -1)
+ switch(ch) {
+ case 'n':
+ nflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'd':
+ debugonly = 1;
+ break;
+ case '?':
+ default:
+ usage((char *)NULL);
+ }
+ argc -= optind;
+ argv += optind;
+
+ pid = getpid();
+ uid = geteuid();
+ if (tflag)
+ s = open(_PATH_DEVNULL, O_WRONLY, 0);
+ else
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0)
+ err(EX_OSERR, "socket");
+ setuid(uid);
+ if (*argv)
+ switch (keyword(*argv)) {
+ case K_GET:
+ uid = 0;
+ /* FALLTHROUGH */
+
+ case K_CHANGE:
+ case K_ADD:
+ case K_DELETE:
+ newroute(argc, argv);
+ exit(0);
+ /* NOTREACHED */
+
+ case K_MONITOR:
+ monitor();
+ /* NOTREACHED */
+
+ case K_FLUSH:
+ flushroutes(argc, argv);
+ exit(0);
+ /* NOTREACHED */
+ }
+ usage(*argv);
+ /* NOTREACHED */
+}
+
+/*
+ * Purge all entries in the routing tables not
+ * associated with network interfaces.
+ */
+void
+flushroutes(argc, argv)
+ int argc;
+ char *argv[];
+{
+ size_t needed;
+ int mib[6], rlen, seqno;
+ char *buf, *next, *lim;
+ register struct rt_msghdr *rtm;
+
+ if (uid) {
+ errx(EX_NOPERM, "must be root to alter routing table");
+ }
+ shutdown(s, 0); /* Don't want to read back our messages */
+ if (argc > 1) {
+ argv++;
+ if (argc == 2 && **argv == '-')
+ switch (keyword(*argv + 1)) {
+ case K_INET:
+ af = AF_INET;
+ break;
+#ifdef INET6
+ case K_INET6:
+ af = AF_INET6;
+ break;
+#endif
+ case K_LINK:
+ af = AF_LINK;
+ break;
+ default:
+ goto bad;
+ } else
+bad: usage(*argv);
+ }
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(EX_OSERR, "route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ errx(EX_OSERR, "malloc failed");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(EX_OSERR, "route-sysctl-get");
+ lim = buf + needed;
+ if (verbose)
+ (void) printf("Examining routing table from sysctl\n");
+ seqno = 0; /* ??? */
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ if (verbose)
+ print_rtmsg(rtm, rtm->rtm_msglen);
+ if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
+ continue;
+ if (af) {
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+
+ if (sa->sa_family != af)
+ continue;
+ }
+ if (debugonly)
+ continue;
+ rtm->rtm_type = RTM_DELETE;
+ rtm->rtm_seq = seqno;
+ rlen = write(s, next, rtm->rtm_msglen);
+ if (rlen < (int)rtm->rtm_msglen) {
+ warn("write to routing socket");
+ (void) printf("got only %d for rlen\n", rlen);
+ break;
+ }
+ seqno++;
+ if (qflag)
+ continue;
+ if (verbose)
+ print_rtmsg(rtm, rlen);
+ else {
+ struct sockaddr *sa = (struct sockaddr *)(rtm + 1);
+ (void) printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ?
+ routename(sa) : netname(sa));
+ sa = (struct sockaddr *)(ROUNDUP(sa->sa_len) + (char *)sa);
+ (void) printf("%-20.20s ", routename(sa));
+ (void) printf("done\n");
+ }
+ }
+}
+
+const char *
+routename(sa)
+ struct sockaddr *sa;
+{
+ register char *cp;
+ static char line[MAXHOSTNAMELEN + 1];
+ struct hostent *hp;
+ static char domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+
+ if (first) {
+ first = 0;
+ if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
+ (cp = index(domain, '.'))) {
+ domain[MAXHOSTNAMELEN] = '\0';
+ (void) memmove(domain, cp + 1, strlen(cp + 1) + 1);
+ } else
+ domain[0] = 0;
+ }
+
+ if (sa->sa_len == 0)
+ strlcpy(line, "default", sizeof(line));
+ else switch (sa->sa_family) {
+
+ case AF_INET:
+ { struct in_addr in;
+ in = ((struct sockaddr_in *)sa)->sin_addr;
+
+ cp = 0;
+ if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
+ cp = "default";
+ if (cp == 0 && !nflag) {
+ hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
+ AF_INET);
+ if (hp) {
+ if ((cp = index(hp->h_name, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = hp->h_name;
+ }
+ }
+ if (cp) {
+ strlcpy(line, cp, sizeof(line));
+ } else {
+ /* XXX - why not inet_ntoa()? */
+#define C(x) (unsigned)((x) & 0xff)
+ in.s_addr = ntohl(in.s_addr);
+ (void) snprintf(line, sizeof(line), "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr));
+ }
+ break;
+ }
+
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 sin6; /* use static var for safety */
+ int niflags = 0;
+#ifdef NI_WITHSCOPEID
+ niflags = NI_WITHSCOPEID;
+#endif
+
+ memset(&sin6, 0, sizeof(sin6));
+ memcpy(&sin6, sa, sa->sa_len);
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+#ifdef __KAME__
+ if (sa->sa_len == sizeof(struct sockaddr_in6) &&
+ (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
+ sin6.sin6_scope_id == 0) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+ if (nflag)
+ niflags |= NI_NUMERICHOST;
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ line, sizeof(line), NULL, 0, niflags) != 0)
+ strlcpy(line, "invalid", sizeof(line));
+
+ return(line);
+ }
+#endif
+
+ case AF_LINK:
+ return (link_ntoa((struct sockaddr_dl *)sa));
+
+ default:
+ { u_short *s = (u_short *)sa;
+ u_short *slim = s + ((sa->sa_len + 1) >> 1);
+ char *cp = line + snprintf(line, sizeof(line), "(%d)", sa->sa_family);
+ char *cpe = line + sizeof(line);
+
+ while (++s < slim && cp < cpe) /* start with sa->sa_data */
+ cp += snprintf(cp, cpe - cp, " %x", *s);
+ break;
+ }
+ }
+ return (line);
+}
+
+/*
+ * Return the name of the network whose address is given.
+ * The address is assumed to be that of a net, not a host.
+ */
+const char *
+netname(sa)
+ struct sockaddr *sa;
+{
+ char *cp = NULL;
+ static char line[MAXHOSTNAMELEN + 1];
+ struct netent *np = NULL;
+ register in_addr_t i;
+
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ { struct in_addr in;
+ in = ((struct sockaddr_in *)sa)->sin_addr;
+
+ i = in.s_addr = ntohl(in.s_addr);
+ if (in.s_addr == 0)
+ cp = "default";
+ else if (!nflag) {
+ np = getnetbyaddr(i, AF_INET);
+ if (np != NULL)
+ cp = np->n_name;
+ }
+#define C(x) (unsigned)((x) & 0xff)
+ if (cp != NULL)
+ strlcpy(line, cp, sizeof(line));
+ else if ((in.s_addr & 0xffffff) == 0)
+ (void) sprintf(line, "%u", C(in.s_addr >> 24));
+ else if ((in.s_addr & 0xffff) == 0)
+ (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16));
+ else if ((in.s_addr & 0xff) == 0)
+ (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8));
+ else
+ (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+ C(in.s_addr >> 16), C(in.s_addr >> 8),
+ C(in.s_addr));
+#undef C
+ break;
+ }
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct sockaddr_in6 sin6; /* use static var for safety */
+ int niflags = 0;
+#ifdef NI_WITHSCOPEID
+ niflags = NI_WITHSCOPEID;
+#endif
+
+ memset(&sin6, 0, sizeof(sin6));
+ memcpy(&sin6, sa, sa->sa_len);
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_family = AF_INET6;
+#ifdef __KAME__
+ if (sa->sa_len == sizeof(struct sockaddr_in6) &&
+ (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr)) &&
+ sin6.sin6_scope_id == 0) {
+ sin6.sin6_scope_id =
+ ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
+ sin6.sin6_addr.s6_addr[2] = 0;
+ sin6.sin6_addr.s6_addr[3] = 0;
+ }
+#endif
+ if (nflag)
+ niflags |= NI_NUMERICHOST;
+ if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
+ line, sizeof(line), NULL, 0, niflags) != 0)
+ strlcpy(line, "invalid", sizeof(line));
+
+ return(line);
+ }
+#endif
+
+ case AF_LINK:
+ return (link_ntoa((struct sockaddr_dl *)sa));
+
+
+ default:
+ { u_short *s = (u_short *)sa->sa_data;
+ u_short *slim = s + ((sa->sa_len + 1)>>1);
+ char *cp = line + snprintf(line, sizeof(line), "af %d:", sa->sa_family);
+ char *cpe = line + sizeof(line);
+
+ while (s < slim && cp < cpe)
+ cp += snprintf(cp, cpe - cp, " %x", *s++);
+ break;
+ }
+ }
+ return (line);
+}
+
+static const char *
+route_strerror(int error)
+{
+
+ switch (error) {
+ case ESRCH:
+ return "not in table";
+ case EBUSY:
+ return "entry in use";
+ case ENOBUFS:
+ return "routing table overflow";
+ default:
+ return (strerror(error));
+ }
+}
+
+void
+set_metric(value, key)
+ char *value;
+ int key;
+{
+ int flag = 0;
+ u_int noval, *valp = &noval;
+
+ switch (key) {
+#define caseof(x, y, z) case x: valp = (u_int *)&rt_metrics.z; flag = y; break
+ caseof(K_MTU, RTV_MTU, rmx_mtu);
+ caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount);
+ caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire);
+ caseof(K_RECVPIPE, RTV_RPIPE, rmx_recvpipe);
+ caseof(K_SENDPIPE, RTV_SPIPE, rmx_sendpipe);
+ caseof(K_SSTHRESH, RTV_SSTHRESH, rmx_ssthresh);
+ caseof(K_RTT, RTV_RTT, rmx_rtt);
+ caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar);
+ }
+ rtm_inits |= flag;
+ if (lockrest || locking)
+ rt_metrics.rmx_locks |= flag;
+ if (locking)
+ locking = 0;
+ *valp = atoi(value);
+}
+
+void
+newroute(argc, argv)
+ int argc;
+ register char **argv;
+{
+ char *cmd, *dest = "", *gateway = "";
+ int ishost = 0, ret, attempts, oerrno, flags = RTF_STATIC;
+ int key;
+ struct hostent *hp = 0;
+
+ if (uid) {
+ errx(EX_NOPERM, "must be root to alter routing table");
+ }
+ cmd = argv[0];
+ if (*cmd != 'g')
+ shutdown(s, 0); /* Don't want to read back our messages */
+ while (--argc > 0) {
+ if (**(++argv)== '-') {
+ switch (key = keyword(1 + *argv)) {
+ case K_LINK:
+ af = AF_LINK;
+ aflen = sizeof(struct sockaddr_dl);
+ break;
+ case K_INET:
+ af = AF_INET;
+ aflen = sizeof(struct sockaddr_in);
+ break;
+#ifdef INET6
+ case K_INET6:
+ af = AF_INET6;
+ aflen = sizeof(struct sockaddr_in6);
+ break;
+#endif
+ case K_SA:
+ af = PF_ROUTE;
+ aflen = sizeof(union sockunion);
+ break;
+ case K_IFACE:
+ case K_INTERFACE:
+ iflag++;
+ break;
+ case K_NOSTATIC:
+ flags &= ~RTF_STATIC;
+ break;
+ case K_LLINFO:
+ flags |= RTF_LLINFO;
+ break;
+ case K_LOCK:
+ locking = 1;
+ break;
+ case K_LOCKREST:
+ lockrest = 1;
+ break;
+ case K_HOST:
+ forcehost++;
+ break;
+ case K_REJECT:
+ flags |= RTF_REJECT;
+ break;
+ case K_BLACKHOLE:
+ flags |= RTF_BLACKHOLE;
+ break;
+ case K_PROTO1:
+ flags |= RTF_PROTO1;
+ break;
+ case K_PROTO2:
+ flags |= RTF_PROTO2;
+ break;
+ case K_CLONING:
+ flags |= RTF_CLONING;
+ break;
+ case K_XRESOLVE:
+ flags |= RTF_XRESOLVE;
+ break;
+ case K_STATIC:
+ flags |= RTF_STATIC;
+ break;
+ case K_IFA:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_IFA, *++argv, 0);
+ break;
+ case K_IFP:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_IFP, *++argv, 0);
+ break;
+ case K_GENMASK:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_GENMASK, *++argv, 0);
+ break;
+ case K_GATEWAY:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_GATEWAY, *++argv, 0);
+ break;
+ case K_DST:
+ if (!--argc)
+ usage((char *)NULL);
+ ishost = getaddr(RTA_DST, *++argv, &hp);
+ dest = *argv;
+ break;
+ case K_NETMASK:
+ if (!--argc)
+ usage((char *)NULL);
+ (void) getaddr(RTA_NETMASK, *++argv, 0);
+ /* FALLTHROUGH */
+ case K_NET:
+ forcenet++;
+ break;
+ case K_PREFIXLEN:
+ if (!--argc)
+ usage((char *)NULL);
+ if (prefixlen(*++argv) == -1) {
+ forcenet = 0;
+ ishost = 1;
+ } else {
+ forcenet = 1;
+ ishost = 0;
+ }
+ break;
+ case K_MTU:
+ case K_HOPCOUNT:
+ case K_EXPIRE:
+ case K_RECVPIPE:
+ case K_SENDPIPE:
+ case K_SSTHRESH:
+ case K_RTT:
+ case K_RTTVAR:
+ if (!--argc)
+ usage((char *)NULL);
+ set_metric(*++argv, key);
+ break;
+ case K_IFSCOPE:
+ if (!--argc)
+ usage((char *)NULL);
+ if ((ifscope = if_nametoindex(*++argv)) != 0)
+ flags |= RTF_IFSCOPE;
+ else
+ errx(1, "bad interface name");
+ break;
+ default:
+ usage(1+*argv);
+ }
+ } else {
+ if ((rtm_addrs & RTA_DST) == 0) {
+ dest = *argv;
+ ishost = getaddr(RTA_DST, *argv, &hp);
+ } else if ((rtm_addrs & RTA_GATEWAY) == 0) {
+ gateway = *argv;
+ (void) getaddr(RTA_GATEWAY, *argv, &hp);
+ } else {
+ (void) getaddr(RTA_NETMASK, *argv, 0);
+ }
+ }
+ }
+ if (forcehost) {
+ ishost = 1;
+#ifdef INET6
+ if (af == AF_INET6) {
+ rtm_addrs &= ~RTA_NETMASK;
+ memset((void *)&so_mask, 0, sizeof(so_mask));
+ }
+#endif
+ }
+ if (forcenet)
+ ishost = 0;
+ flags |= RTF_UP;
+ if (ishost)
+ flags |= RTF_HOST;
+ if (iflag == 0)
+ flags |= RTF_GATEWAY;
+ if (so_mask.sin.sin_family == AF_INET) {
+ // make sure the mask is contiguous
+ long i;
+ for (i = 0; i < 32; i++)
+ if (((so_mask.sin.sin_addr.s_addr) & ntohl((1 << i))) != 0)
+ break;
+ for (; i < 32; i++)
+ if (((so_mask.sin.sin_addr.s_addr) & ntohl((1 << i))) == 0)
+ errx(EX_NOHOST, "invalid mask: %s", inet_ntoa(so_mask.sin.sin_addr));
+ }
+ for (attempts = 1; ; attempts++) {
+ errno = 0;
+ if ((ret = rtmsg(*cmd, flags)) == 0)
+ break;
+ if (errno != ENETUNREACH && errno != ESRCH)
+ break;
+ if (af == AF_INET && *gateway && hp && hp->h_addr_list[1]) {
+ hp->h_addr_list++;
+ bcopy(hp->h_addr_list[0], &so_gate.sin.sin_addr,
+ MIN(hp->h_length, sizeof(so_gate.sin.sin_addr)));
+ } else
+ break;
+ }
+ if (*cmd == 'g')
+ exit(0);
+ oerrno = errno;
+ (void) printf("%s %s %s", cmd, ishost? "host" : "net", dest);
+ if (*gateway) {
+ (void) printf(": gateway %s", gateway);
+ if (attempts > 1 && ret == 0 && af == AF_INET)
+ (void) printf(" (%s)", inet_ntoa(so_gate.sin.sin_addr));
+ }
+ if (ret == 0)
+ (void) printf("\n");
+ else {
+ (void)printf(": %s\n", route_strerror(oerrno));
+ }
+}
+
+static void
+inet_makenetandmask(in_addr_t net, struct sockaddr_in *sin,
+ struct sockaddr_in *sin_mask, in_addr_t bits)
+{
+ in_addr_t mask = 0;
+
+ rtm_addrs |= RTA_NETMASK;
+ /*
+ * MSB of net should be meaningful. 0/0 is exception.
+ */
+ if (net > 0)
+ while ((net & 0xff000000) == 0)
+ net <<= 8;
+
+ /*
+ * If no /xx was specified we must calculate the
+ * CIDR address.
+ */
+ if ((bits == 0) && (net != 0)) {
+ u_long i, j;
+
+ for(i = 0, j = 0xff; i < 4; i++) {
+ if (net & j) {
+ break;
+ }
+ j <<= 8;
+ }
+ /* i holds the first non zero bit */
+ bits = 32 - (i*8);
+ }
+ if (bits != 0)
+ mask = 0xffffffff << (32 - bits);
+
+ sin->sin_addr.s_addr = htonl(net);
+ sin_mask->sin_addr.s_addr = htonl(mask);
+ sin_mask->sin_len = sizeof(struct sockaddr_in);
+ sin_mask->sin_family = AF_INET;
+}
+
+#ifdef INET6
+/*
+ * XXX the function may need more improvement...
+ */
+static int
+inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen)
+{
+ struct in6_addr in6;
+
+ if (plen == NULL) {
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
+ sin6->sin6_scope_id == 0) {
+ plen = "0";
+ } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) {
+ /* aggregatable global unicast - RFC2374 */
+ memset(&in6, 0, sizeof(in6));
+ if (!memcmp(&sin6->sin6_addr.s6_addr[8],
+ &in6.s6_addr[8], 8))
+ plen = "64";
+ }
+ }
+
+ if (plen == NULL || strcmp(plen, "128") == 0)
+ return (1);
+ rtm_addrs |= RTA_NETMASK;
+ prefixlen(plen);
+ return (0);
+}
+#endif
+
+/*
+ * Interpret an argument as a network address of some kind,
+ * returning 1 if a host address, 0 if a network address.
+ */
+int
+getaddr(which, s, hpp)
+ int which;
+ char *s;
+ struct hostent **hpp;
+{
+ register sup su = NULL;
+ struct hostent *hp;
+ struct netent *np;
+ in_addr_t val;
+ char *q;
+ int afamily; /* local copy of af so we can change it */
+
+ if (af == 0) {
+ af = AF_INET;
+ aflen = sizeof(struct sockaddr_in);
+ }
+ afamily = af;
+ rtm_addrs |= which;
+ switch (which) {
+ case RTA_DST:
+ su = &so_dst;
+ break;
+ case RTA_GATEWAY:
+ su = &so_gate;
+ if (iflag) {
+ struct ifaddrs *ifap, *ifa;
+ struct sockaddr_dl *sdl = NULL;
+
+ if (getifaddrs(&ifap))
+ err(1, "getifaddrs");
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ if (strcmp(s, ifa->ifa_name))
+ continue;
+
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ }
+ /* If we found it, then use it */
+ if (sdl) {
+ /*
+ * Copy is safe since we have a
+ * sockaddr_storage member in sockunion{}.
+ * Note that we need to copy before calling
+ * freeifaddrs().
+ */
+ memcpy(&su->sdl, sdl, sdl->sdl_len);
+ }
+ freeifaddrs(ifap);
+ if (sdl)
+ return(1);
+ }
+ break;
+ case RTA_NETMASK:
+ su = &so_mask;
+ break;
+ case RTA_GENMASK:
+ su = &so_genmask;
+ break;
+ case RTA_IFP:
+ su = &so_ifp;
+ afamily = AF_LINK;
+ break;
+ case RTA_IFA:
+ su = &so_ifa;
+ break;
+ default:
+ usage("internal error");
+ /*NOTREACHED*/
+ }
+ su->sa.sa_len = aflen;
+ su->sa.sa_family = afamily; /* cases that don't want it have left already */
+ if (strcmp(s, "default") == 0) {
+ /*
+ * Default is net 0.0.0.0/0
+ */
+ switch (which) {
+ case RTA_DST:
+ forcenet++;
+ /* bzero(su, sizeof(*su)); *//* for readability */
+ (void) getaddr(RTA_NETMASK, s, 0);
+ break;
+ case RTA_NETMASK:
+ case RTA_GENMASK:
+ /* bzero(su, sizeof(*su)); *//* for readability */
+ su->sa.sa_len = 0;
+ break;
+ }
+ return (0);
+ }
+ switch (afamily) {
+#ifdef INET6
+ case AF_INET6:
+ {
+ struct addrinfo hints, *res;
+ int ecode;
+
+ q = NULL;
+ if (which == RTA_DST && (q = strchr(s, '/')) != NULL)
+ *q = '\0';
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = afamily; /*AF_INET6*/
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ ecode = getaddrinfo(s, NULL, &hints, &res);
+ if (ecode != 0 || res->ai_family != AF_INET6 ||
+ res->ai_addrlen != sizeof(su->sin6)) {
+ (void) fprintf(stderr, "%s: %s\n", s,
+ gai_strerror(ecode));
+ exit(1);
+ }
+ memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
+#ifdef __KAME__
+ if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_NODELOCAL(&su->sin6.sin6_addr) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr)) &&
+ su->sin6.sin6_scope_id) {
+ *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] =
+ htons(su->sin6.sin6_scope_id);
+ su->sin6.sin6_scope_id = 0;
+ }
+#endif
+ freeaddrinfo(res);
+ if (hints.ai_flags == AI_NUMERICHOST) {
+ if (q != NULL)
+ *q++ = '/';
+ if (which == RTA_DST)
+ return (inet6_makenetandmask(&su->sin6, q));
+ return (0);
+ } else {
+ return (1);
+ }
+ }
+#endif /* INET6 */
+
+ case AF_LINK:
+ link_addr(s, &su->sdl);
+ return (1);
+
+
+ case PF_ROUTE:
+ su->sa.sa_len = sizeof(*su);
+ sockaddr(s, &su->sa);
+ return (1);
+
+ case AF_INET:
+ default:
+ break;
+ }
+
+ if (hpp == NULL)
+ hpp = &hp;
+ *hpp = NULL;
+
+ q = strchr(s,'/');
+ if (q && which == RTA_DST) {
+ *q = '\0';
+ if ((val = inet_network(s)) != INADDR_NONE) {
+ inet_makenetandmask(
+ val, &su->sin, (struct sockaddr_in *)&so_mask,
+ strtoul(q+1, 0, 0));
+ return (0);
+ }
+ *q = '/';
+ }
+ if ((which != RTA_DST || forcenet == 0) &&
+ inet_aton(s, &su->sin.sin_addr)) {
+ val = su->sin.sin_addr.s_addr;
+ if (which != RTA_DST || forcehost ||
+ inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
+ return (1);
+ else {
+ val = ntohl(val);
+ goto netdone;
+ }
+ }
+ if (which == RTA_DST && forcehost == 0 &&
+ ((val = inet_network(s)) != INADDR_NONE ||
+ ((np = getnetbyname(s)) != NULL && (val = np->n_net) != 0))) {
+netdone:
+ inet_makenetandmask(val, &su->sin, (struct sockaddr_in *)&so_mask, 0);
+ return (0);
+ }
+ hp = gethostbyname(s);
+ if (hp) {
+ *hpp = hp;
+ su->sin.sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, (char *)&su->sin.sin_addr,
+ MIN(hp->h_length, sizeof(su->sin.sin_addr)));
+ return (1);
+ }
+ errx(EX_NOHOST, "bad address: %s", s);
+}
+
+int
+prefixlen(s)
+ char *s;
+{
+ int len = atoi(s), q, r;
+ int max;
+ char *p;
+
+ rtm_addrs |= RTA_NETMASK;
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+ max = 128;
+ p = (char *)&so_mask.sin6.sin6_addr;
+ break;
+#endif
+ case AF_INET:
+ max = 32;
+ p = (char *)&so_mask.sin.sin_addr;
+ break;
+ default:
+ (void) fprintf(stderr, "prefixlen not supported in this af\n");
+ exit(1);
+ /*NOTREACHED*/
+ }
+
+ if (len < 0 || max < len) {
+ (void) fprintf(stderr, "%s: bad value\n", s);
+ exit(1);
+ }
+
+ q = len >> 3;
+ r = len & 7;
+ so_mask.sa.sa_family = af;
+ so_mask.sa.sa_len = aflen;
+ memset((void *)p, 0, max / 8);
+ if (q > 0)
+ memset((void *)p, 0xff, q);
+ if (r > 0)
+ *((u_char *)p + q) = (0xff00 >> r) & 0xff;
+ if (len == max)
+ return -1;
+ else
+ return len;
+}
+
+void
+interfaces()
+{
+ size_t needed;
+ int mib[6];
+ char *buf, *lim, *next;
+ register struct rt_msghdr *rtm;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0; /* protocol */
+ mib[3] = 0; /* wildcard address family */
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ err(EX_OSERR, "route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ errx(EX_OSERR, "malloc failed");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ err(EX_OSERR, "actual retrieval of interface table");
+ lim = buf + needed;
+ for (next = buf; next < lim; next += rtm->rtm_msglen) {
+ rtm = (struct rt_msghdr *)next;
+ print_rtmsg(rtm, rtm->rtm_msglen);
+ }
+}
+
+void
+monitor()
+{
+ int n;
+ char msg[2048];
+
+ verbose = 1;
+ if (debugonly) {
+ interfaces();
+ exit(0);
+ }
+ for(;;) {
+ time_t now;
+ n = read(s, msg, 2048);
+ now = time(NULL);
+ (void) printf("\ngot message of size %d on %s", n, ctime(&now));
+ print_rtmsg((struct rt_msghdr *)msg, n);
+ }
+}
+
+struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+int
+rtmsg(cmd, flags)
+ int cmd, flags;
+{
+ static int seq;
+ int rlen;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+
+#define NEXTADDR(w, u) \
+ if (rtm_addrs & (w)) {\
+ l = ROUNDUP(u.sa.sa_len); bcopy((char *)&(u), cp, l); cp += l;\
+ if (verbose) sodump(&(u),"u");\
+ }
+
+ errno = 0;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ if (cmd == 'a')
+ cmd = RTM_ADD;
+ else if (cmd == 'c')
+ cmd = RTM_CHANGE;
+ else if (cmd == 'g') {
+ cmd = RTM_GET;
+ if (so_ifp.sa.sa_family == 0) {
+ so_ifp.sa.sa_family = AF_LINK;
+ so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
+ rtm_addrs |= RTA_IFP;
+ }
+ } else
+ cmd = RTM_DELETE;
+#define rtm m_rtmsg.m_rtm
+ rtm.rtm_type = cmd;
+ rtm.rtm_flags = flags;
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_seq = ++seq;
+ rtm.rtm_addrs = rtm_addrs;
+ rtm.rtm_rmx = rt_metrics;
+ rtm.rtm_inits = rtm_inits;
+ rtm.rtm_index = ifscope;
+
+ if (rtm_addrs & RTA_NETMASK)
+ mask_addr();
+ NEXTADDR(RTA_DST, so_dst);
+ NEXTADDR(RTA_GATEWAY, so_gate);
+ NEXTADDR(RTA_NETMASK, so_mask);
+ NEXTADDR(RTA_GENMASK, so_genmask);
+ NEXTADDR(RTA_IFP, so_ifp);
+ NEXTADDR(RTA_IFA, so_ifa);
+ rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
+ if (verbose)
+ print_rtmsg(&rtm, l);
+ if (debugonly)
+ return (0);
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ warnx("writing to routing socket: %s", route_strerror(errno));
+ return (-1);
+ }
+ if (cmd == RTM_GET) {
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+ if (l < 0)
+ warn("read from routing socket");
+ else
+ print_getmsg(&rtm, l);
+ }
+#undef rtm
+ return (0);
+}
+
+void
+mask_addr()
+{
+ int olen = so_mask.sa.sa_len;
+ register char *cp1 = olen + (char *)&so_mask, *cp2;
+
+ for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
+ if (*--cp1 != 0) {
+ so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
+ break;
+ }
+ if ((rtm_addrs & RTA_DST) == 0)
+ return;
+ switch (so_dst.sa.sa_family) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ case AF_APPLETALK:
+ case 0:
+ return;
+ }
+ cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
+ cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
+ while (cp2 > cp1)
+ *--cp2 = 0;
+ cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
+ while (cp1 > so_dst.sa.sa_data)
+ *--cp1 &= *--cp2;
+}
+
+char *msgtypes[] = {
+ "",
+ "RTM_ADD: Add Route",
+ "RTM_DELETE: Delete Route",
+ "RTM_CHANGE: Change Metrics or flags",
+ "RTM_GET: Report Metrics",
+ "RTM_LOSING: Kernel Suspects Partitioning",
+ "RTM_REDIRECT: Told to use different route",
+ "RTM_MISS: Lookup failed on this address",
+ "RTM_LOCK: fix specified metrics",
+ "RTM_OLDADD: caused by SIOCADDRT",
+ "RTM_OLDDEL: caused by SIOCDELRT",
+ "RTM_RESOLVE: Route created by cloning",
+ "RTM_NEWADDR: address being added to iface",
+ "RTM_DELADDR: address being removed from iface",
+ "RTM_IFINFO: iface status change",
+ "RTM_NEWMADDR: new multicast group membership on iface",
+ "RTM_DELMADDR: multicast group membership removed from iface",
+ 0,
+};
+
+char metricnames[] =
+"\011pksent\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire\2hopcount"
+"\1mtu";
+char routeflags[] =
+"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE\010DELCLONE"
+"\011CLONING\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE\016b016"
+"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3\024b024"
+"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\031IFSCOPE\032CONDEMNED"
+"\033IFREF\034PROXY\035ROUTER";
+char ifnetflags[] =
+"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
+"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
+"\017LINK2\020MULTICAST";
+char addrnames[] =
+"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
+
+void
+print_rtmsg(rtm, msglen)
+ register struct rt_msghdr *rtm;
+ int msglen;
+{
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+#ifdef RTM_NEWMADDR
+ struct ifma_msghdr *ifmam;
+#endif
+
+ if (verbose == 0)
+ return;
+ if (rtm->rtm_version != RTM_VERSION) {
+ (void) printf("routing message version %d not understood\n",
+ rtm->rtm_version);
+ return;
+ }
+ (void)printf("%s: len %d, ", msgtypes[rtm->rtm_type], rtm->rtm_msglen);
+ switch (rtm->rtm_type) {
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *)rtm;
+ (void) printf("if# %d, flags:", ifm->ifm_index);
+ bprintf(stdout, ifm->ifm_flags, ifnetflags);
+ pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+ (void) printf("metric %d, flags:", ifam->ifam_metric);
+ bprintf(stdout, ifam->ifam_flags, routeflags);
+ pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs);
+ break;
+#ifdef RTM_NEWMADDR
+ case RTM_NEWMADDR:
+ case RTM_DELMADDR:
+ ifmam = (struct ifma_msghdr *)rtm;
+ pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs);
+ break;
+#endif
+ default:
+ (void) printf("pid: %ld, seq %d, errno %d, ",
+ (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
+ if (rtm->rtm_flags & RTF_IFSCOPE)
+ (void) printf("ifscope %d, ", rtm->rtm_index);
+ if (rtm->rtm_flags & RTF_IFREF)
+ (void) printf("ifref, ");
+ (void) printf("flags:");
+ bprintf(stdout, rtm->rtm_flags, routeflags);
+ pmsg_common(rtm);
+ }
+}
+
+void
+print_getmsg(rtm, msglen)
+ register struct rt_msghdr *rtm;
+ int msglen;
+{
+ struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
+ struct sockaddr_dl *ifp = NULL;
+ register struct sockaddr *sa;
+ register char *cp;
+ register int i;
+
+ (void) printf(" route to: %s\n", routename(&so_dst.sa));
+ if (rtm->rtm_version != RTM_VERSION) {
+ warnx("routing message version %d not understood",
+ rtm->rtm_version);
+ return;
+ }
+ if (rtm->rtm_msglen > msglen) {
+ warnx("message length mismatch, in packet %d, returned %d",
+ rtm->rtm_msglen, msglen);
+ }
+ if (rtm->rtm_errno) {
+ errno = rtm->rtm_errno;
+ warn("message indicates error %d", errno);
+ return;
+ }
+ cp = ((char *)(rtm + 1));
+ if (rtm->rtm_addrs)
+ for (i = 1; i; i <<= 1)
+ if (i & rtm->rtm_addrs) {
+ sa = (struct sockaddr *)cp;
+ switch (i) {
+ case RTA_DST:
+ dst = sa;
+ break;
+ case RTA_GATEWAY:
+ gate = sa;
+ break;
+ case RTA_NETMASK:
+ mask = sa;
+ break;
+ case RTA_IFP:
+ if (sa->sa_family == AF_LINK &&
+ ((struct sockaddr_dl *)sa)->sdl_nlen)
+ ifp = (struct sockaddr_dl *)sa;
+ break;
+ }
+ ADVANCE(cp, sa);
+ }
+ if (dst && mask)
+ mask->sa_family = dst->sa_family; /* XXX */
+ if (dst)
+ (void)printf("destination: %s\n", routename(dst));
+ if (mask) {
+ int savenflag = nflag;
+
+ nflag = 1;
+ (void)printf(" mask: %s\n", routename(mask));
+ nflag = savenflag;
+ }
+ if (gate && rtm->rtm_flags & RTF_GATEWAY)
+ (void)printf(" gateway: %s\n", routename(gate));
+ if (ifp)
+ (void)printf(" interface: %.*s\n",
+ ifp->sdl_nlen, ifp->sdl_data);
+ (void)printf(" flags: ");
+ bprintf(stdout, rtm->rtm_flags, routeflags);
+
+#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
+#define msec(u) (((u) + 500) / 1000) /* usec to msec */
+
+ (void) printf("\n%s\n", "\
+ recvpipe sendpipe ssthresh rtt,msec rttvar hopcount mtu expire");
+ printf("%8u%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
+ printf("%8u%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
+ printf("%8u%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
+ printf("%8u%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
+ printf("%8u%c ", msec(rtm->rtm_rmx.rmx_rttvar), lock(RTTVAR));
+ printf("%8u%c ", rtm->rtm_rmx.rmx_hopcount, lock(HOPCOUNT));
+ printf("%8u%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
+ if (rtm->rtm_rmx.rmx_expire)
+ rtm->rtm_rmx.rmx_expire -= time(0);
+ printf("%8d%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
+#undef lock
+#undef msec
+#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
+ if (verbose)
+ pmsg_common(rtm);
+ else if (rtm->rtm_addrs &~ RTA_IGN) {
+ (void) printf("sockaddrs: ");
+ bprintf(stdout, rtm->rtm_addrs, addrnames);
+ putchar('\n');
+ }
+#undef RTA_IGN
+}
+
+void
+pmsg_common(rtm)
+ register struct rt_msghdr *rtm;
+{
+ (void) printf("\nlocks: ");
+ bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
+ (void) printf(" inits: ");
+ bprintf(stdout, rtm->rtm_inits, metricnames);
+ pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs);
+}
+
+void
+pmsg_addrs(cp, addrs)
+ char *cp;
+ int addrs;
+{
+ register struct sockaddr *sa;
+ int i;
+
+ if (addrs == 0) {
+ (void) putchar('\n');
+ return;
+ }
+ (void) printf("\nsockaddrs: ");
+ bprintf(stdout, addrs, addrnames);
+ (void) putchar('\n');
+ for (i = 1; i; i <<= 1)
+ if (i & addrs) {
+ sa = (struct sockaddr *)cp;
+ (void) printf(" %s", routename(sa));
+ ADVANCE(cp, sa);
+ }
+ (void) putchar('\n');
+ (void) fflush(stdout);
+}
+
+void
+bprintf(fp, b, s)
+ register FILE *fp;
+ register int b;
+ register u_char *s;
+{
+ register int i;
+ int gotsome = 0;
+
+ if (b == 0)
+ return;
+ while ((i = *s++) != 0) {
+ if (b & (1 << (i-1))) {
+ if (gotsome == 0)
+ i = '<';
+ else
+ i = ',';
+ (void) putc(i, fp);
+ gotsome = 1;
+ for (; (i = *s) > 32; s++)
+ (void) putc(i, fp);
+ } else
+ while (*s > 32)
+ s++;
+ }
+ if (gotsome)
+ (void) putc('>', fp);
+}
+
+int
+keyword(cp)
+ char *cp;
+{
+ register struct keytab *kt = keywords;
+
+ while (kt->kt_cp && strcmp(kt->kt_cp, cp))
+ kt++;
+ return kt->kt_i;
+}
+
+void
+sodump(su, which)
+ register sup su;
+ char *which;
+{
+ switch (su->sa.sa_family) {
+ case AF_LINK:
+ (void) printf("%s: link %s; ",
+ which, link_ntoa(&su->sdl));
+ break;
+ case AF_INET:
+ (void) printf("%s: inet %s; ",
+ which, inet_ntoa(su->sin.sin_addr));
+ break;
+ }
+ (void) fflush(stdout);
+}
+
+/* States*/
+#define VIRGIN 0
+#define GOTONE 1
+#define GOTTWO 2
+/* Inputs */
+#define DIGIT (4*0)
+#define END (4*1)
+#define DELIM (4*2)
+
+void
+sockaddr(addr, sa)
+ register char *addr;
+ register struct sockaddr *sa;
+{
+ register char *cp = (char *)sa;
+ int size = sa->sa_len;
+ char *cplim = cp + size;
+ register int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
+
+ bzero(cp, size);
+ cp++;
+ do {
+ if ((*addr >= '0') && (*addr <= '9')) {
+ new = *addr - '0';
+ } else if ((*addr >= 'a') && (*addr <= 'f')) {
+ new = *addr - 'a' + 10;
+ } else if ((*addr >= 'A') && (*addr <= 'F')) {
+ new = *addr - 'A' + 10;
+ } else if (*addr == 0)
+ state |= END;
+ else
+ state |= DELIM;
+ addr++;
+ switch (state /* | INPUT */) {
+ case GOTTWO | DIGIT:
+ *cp++ = byte; /*FALLTHROUGH*/
+ case VIRGIN | DIGIT:
+ state = GOTONE; byte = new; continue;
+ case GOTONE | DIGIT:
+ state = GOTTWO; byte = new + (byte << 4); continue;
+ default: /* | DELIM */
+ state = VIRGIN; *cp++ = byte; byte = 0; continue;
+ case GOTONE | END:
+ case GOTTWO | END:
+ *cp++ = byte; /* FALLTHROUGH */
+ case VIRGIN | END:
+ break;
+ }
+ break;
+ } while (cp < cplim);
+ sa->sa_len = cp - (char *)sa;
+}
diff --git a/network_cmds/rtadvd.tproj/advcap.c b/network_cmds/rtadvd.tproj/advcap.c
new file mode 100644
index 0000000..33b6fae
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/advcap.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: advcap.c,v 1.11 2003/05/19 09:46:50 keiichi Exp $ */
+
+/*
+ * Copyright (c) 1983 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * remcap - routines for dealing with the remote host data base
+ *
+ * derived from termcap
+ */
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "pathnames.h"
+#include "rtadvd_logging.h"
+
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+#define MAXHOP 32 /* max number of tc= indirections */
+
+#define tgetent agetent
+#define tnchktc anchktc
+#define tnamatch anamatch
+#define tgetnum agetnum
+#define tgetflag agetflag
+#define tgetstr agetstr
+
+#if 0
+#define V_TERMCAP "REMOTE"
+#define V_TERM "HOST"
+#endif
+
+char *RM;
+
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG: Should use a "last" pointer in tbuf, so that searching
+ * for capabilities alphabetically would not be a n**2/2
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+static char *tbuf;
+static int hopcount; /* detect infinite loops in termcap, init 0 */
+
+static char *remotefile;
+
+extern char *conffile;
+
+int tgetent(char *, char *);
+int getent(char *, char *, char *);
+int tnchktc(void);
+int tnamatch(char *);
+static char *tskip(char *);
+int64_t tgetnum(char *);
+int tgetflag(char *);
+char *tgetstr(char *, char **);
+static char *tdecode(char *, char **);
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+int
+tgetent(bp, name)
+ char *bp, *name;
+{
+ char *cp;
+
+ remotefile = cp = conffile ? conffile : _PATH_RTADVDCONF;
+ return (getent(bp, name, cp));
+}
+
+int
+getent(bp, name, cp)
+ char *bp, *name, *cp;
+{
+ int c;
+ int i = 0, cnt = 0;
+ char ibuf[BUFSIZ];
+ int tf;
+
+ tbuf = bp;
+ tf = 0;
+ /*
+ * TERMCAP can have one of two things in it. It can be the
+ * name of a file to use instead of /etc/termcap. In this
+ * case it better start with a "/". Or it can be an entry to
+ * use so we don't have to read the file. In this case it
+ * has to already have the newlines crunched out.
+ */
+ if (cp && *cp) {
+ tf = open(RM = cp, O_RDONLY);
+ }
+ if (tf < 0) {
+ infolog("<%s> open: %s", __func__, strerror(errno));
+ return (-2);
+ }
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = read(tf, ibuf, BUFSIZ);
+ if (cnt <= 0) {
+ close(tf);
+ return (0);
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\') {
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp + BUFSIZ - 1) {
+ write(STDERR_FILENO, "Remcap entry too long\n",
+ 22);
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = 0;
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ close(tf);
+ return (tnchktc());
+ }
+ }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+int
+tnchktc()
+{
+ char *p, *q;
+ char tcname[16]; /* name of similar terminal */
+ char tcbuf[BUFSIZ];
+ char *holdtbuf = tbuf;
+ int l;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p < tbuf) {
+ write(STDERR_FILENO, "Bad remcap entry\n", 18);
+ return (0);
+ }
+ p++;
+ /* p now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return (1);
+ strlcpy(tcname, p + 3, sizeof tcname);
+ q = tcname;
+ while (*q && *q != ':')
+ q++;
+ *q = 0;
+ if (++hopcount > MAXHOP) {
+ write(STDERR_FILENO, "Infinite tc= loop\n", 18);
+ return (0);
+ }
+ if (getent(tcbuf, tcname, remotefile) != 1) {
+ return (0);
+ }
+ for (q = tcbuf; *q++ != ':'; )
+ ;
+ l = p - holdtbuf + strlen(q);
+
+ /* check length before copying string below */
+ if (l > BUFSIZ) {
+ write(STDERR_FILENO, "Remcap entry too long\n", 23);
+ q[BUFSIZ - (p-holdtbuf)] = 0;
+ }
+ strlcpy(p, q, p-tbuf);
+ tbuf = holdtbuf;
+ return (1);
+}
+
+/*
+ * Tnamatch deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name. The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+int
+tnamatch(np)
+ char *np;
+{
+ char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return (0);
+ for (;;) {
+ for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+ continue;
+ if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+ return (1);
+ while (*Bp && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == 0 || *Bp == ':')
+ return (0);
+ Bp++;
+ }
+}
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about \: escapes or any such. If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+ char *bp;
+{
+ int dquote;
+
+ dquote = 0;
+ while (*bp) {
+ switch (*bp) {
+ case ':':
+ if (!dquote)
+ goto breakbreak;
+ else
+ bp++;
+ break;
+ case '\\':
+ bp++;
+ if (isdigit(*bp)) {
+ while (isdigit(*bp++))
+ ;
+ } else
+ bp++;
+ case '"':
+ dquote = (dquote ? 1 : 0);
+ bp++;
+ break;
+ default:
+ bp++;
+ break;
+ }
+ }
+breakbreak:
+ if (*bp == ':')
+ bp++;
+ return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character. If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+int64_t
+tgetnum(id)
+ char *id;
+{
+ int64_t i;
+ int base;
+ char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == 0)
+ return (-1);
+ if (strncmp(bp, id, strlen(id)) != 0)
+ continue;
+ bp += strlen(id);
+ if (*bp == '@')
+ return (-1);
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return (i);
+ }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+int
+tgetflag(id)
+ char *id;
+{
+ char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (strncmp(bp, id, strlen(id)) == 0) {
+ bp += strlen(id);
+ if (!*bp || *bp == ':')
+ return (1);
+ else if (*bp == '@')
+ return (0);
+ }
+ }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+ char *id, **area;
+{
+ char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return (0);
+ if (strncmp(bp, id, strlen(id)) != 0)
+ continue;
+ bp += strlen(id);
+ if (*bp == '@')
+ return (0);
+ if (*bp != '=')
+ continue;
+ bp++;
+ return (tdecode(bp, area));
+ }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+ char *str;
+ char **area;
+{
+ char *cp;
+ int c;
+ char *dp;
+ int i;
+ char term;
+
+ term = ':';
+ cp = *area;
+again:
+ if (*str == '"') {
+ term = '"';
+ str++;
+ }
+ while ((c = *str++) && c != term) {
+ switch (c) {
+
+ case '^':
+ c = *str++ & 037;
+ break;
+
+ case '\\':
+ dp = "E\033^^\\\\::n\nr\rt\tb\bf\f\"\"";
+ c = *str++;
+nextc:
+ if (*dp++ == c) {
+ c = *dp++;
+ break;
+ }
+ dp++;
+ if (*dp)
+ goto nextc;
+ if (isdigit(c)) {
+ c -= '0', i = 2;
+ do
+ c <<= 3, c |= *str++ - '0';
+ while (--i && isdigit(*str));
+ }
+ break;
+ }
+ *cp++ = c;
+ }
+ if (c == term && term != ':') {
+ term = ':';
+ goto again;
+ }
+ *cp++ = 0;
+ str = *area;
+ *area = cp;
+ return (str);
+}
diff --git a/network_cmds/rtadvd.tproj/advcap.h b/network_cmds/rtadvd.tproj/advcap.h
new file mode 100644
index 0000000..1b42b40
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/advcap.h
@@ -0,0 +1,45 @@
+/* $KAME: advcap.h,v 1.5 2003/06/09 05:40:54 t-momose Exp $ */
+
+/*
+ * Copyright (C) 1994,1995 by Andrey A. Chernov, Moscow, Russia.
+ * 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 ``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.
+ */
+
+/* Based on Id: termcap.h,v 1.8 1996/09/10 12:42:10 peter Exp */
+
+#ifndef _ADVCAP_H_
+#define _ADVCAP_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+extern int agetent(char *, const char *);
+extern int agetflag(const char *);
+extern int64_t agetnum(const char *);
+extern char *agetstr(const char *, char **);
+
+__END_DECLS
+
+#endif /* _ADVCAP_H_ */
diff --git a/network_cmds/rtadvd.tproj/config.c b/network_cmds/rtadvd.tproj/config.c
new file mode 100644
index 0000000..3d6388d
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/config.c
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (c) 2009-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: config.c,v 1.84 2003/08/05 12:34:23 itojun Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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 <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <search.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+#include <stddef.h>
+
+#include "rtadvd.h"
+#include "advcap.h"
+#include "timer.h"
+#include "if.h"
+#include "config.h"
+
+static time_t prefix_timo = (60 * 120); /* 2 hours.
+ * XXX: should be configurable. */
+extern struct rainfo *ralist;
+
+static struct rtadvd_timer *prefix_timeout(void *);
+static void makeentry(char *, size_t, int, char *);
+static int getinet6sysctl(int);
+static int encode_domain(char *, u_char *);
+
+void
+getconfig(intface)
+ char *intface;
+{
+ int stat, i;
+ int rdnss_length;
+ int dnssl_length;
+ char tbuf[BUFSIZ];
+ struct rainfo *rai;
+ long val;
+ int64_t val64;
+ char buf[BUFSIZ];
+ char *bp = buf;
+ char *addr, *flagstr;
+ char *capport;
+ static int forwarding = -1;
+
+#define MUSTHAVE(var, cap) \
+ do { \
+ int64_t t; \
+ if ((t = agetnum(cap)) < 0) { \
+ fprintf(stderr, "rtadvd: need %s for interface %s\n", \
+ cap, intface); \
+ exit(1); \
+ } \
+ var = t; \
+ } while (0)
+#define MAYHAVE(var, cap, def) \
+ do { \
+ if ((var = agetnum(cap)) < 0) \
+ var = def; \
+ } while (0)
+
+ if ((stat = agetent(tbuf, intface)) <= 0) {
+ memset(tbuf, 0, sizeof(tbuf));
+ errorlog("<%s> %s isn't defined in the configuration file"
+ " or the configuration file doesn't exist."
+ " Treat it as default",
+ __func__, intface);
+ }
+
+ ELM_MALLOC(rai, exit(1));
+ rai->prefix.next = rai->prefix.prev = &rai->prefix;
+#ifdef ROUTEINFO
+ rai->route.next = rai->route.prev = &rai->route;
+#endif
+ rai->rdnss_list.next = rai->rdnss_list.prev = &rai->rdnss_list;
+ rai->dnssl_list.next = rai->dnssl_list.prev = &rai->dnssl_list;
+
+ /* check if we are allowed to forward packets (if not determined) */
+ if (forwarding < 0) {
+ if ((forwarding = getinet6sysctl(IPV6CTL_FORWARDING)) < 0)
+ exit(1);
+ }
+
+ /* get interface information */
+ if (agetflag("nolladdr"))
+ rai->advlinkopt = 0;
+ else
+ rai->advlinkopt = 1;
+ if (rai->advlinkopt) {
+ if ((rai->sdl = if_nametosdl(intface)) == NULL) {
+ errorlog("<%s> can't get information of %s",
+ __func__, intface);
+ exit(1);
+ }
+ rai->ifindex = rai->sdl->sdl_index;
+ } else
+ rai->ifindex = if_nametoindex(intface);
+ strlcpy(rai->ifname, intface, sizeof(rai->ifname));
+ if ((rai->phymtu = if_getmtu(intface)) == 0) {
+ rai->phymtu = IPV6_MMTU;
+ errorlog("<%s> can't get interface mtu of %s. Treat as %d",
+ __func__, intface, IPV6_MMTU);
+ }
+
+ /*
+ * set router configuration variables.
+ */
+ MAYHAVE(val, "maxinterval", DEF_MAXRTRADVINTERVAL);
+ if (val < MIN_MAXINTERVAL || val > MAX_MAXINTERVAL) {
+ errorlog("<%s> maxinterval (%ld) on %s is invalid "
+ "(must be between %u and %u)", __func__, val,
+ intface, MIN_MAXINTERVAL, MAX_MAXINTERVAL);
+ exit(1);
+ }
+ rai->maxinterval = (u_int)val;
+ MAYHAVE(val, "mininterval", rai->maxinterval/3);
+ if (val < MIN_MININTERVAL || val > (rai->maxinterval * 3) / 4) {
+ errorlog("<%s> mininterval (%ld) on %s is invalid "
+ "(must be between %d and %d)",
+ __func__, val, intface, MIN_MININTERVAL,
+ (rai->maxinterval * 3) / 4);
+ exit(1);
+ }
+ rai->mininterval = (u_int)val;
+
+ MAYHAVE(val, "chlim", DEF_ADVCURHOPLIMIT);
+ rai->hoplimit = val & 0xff;
+
+ if ((flagstr = (char *)agetstr("raflags", &bp))) {
+ val = 0;
+ if (strchr(flagstr, 'm'))
+ val |= ND_RA_FLAG_MANAGED;
+ if (strchr(flagstr, 'o'))
+ val |= ND_RA_FLAG_OTHER;
+ if (strchr(flagstr, 'h'))
+ val |= ND_RA_FLAG_RTPREF_HIGH;
+ if (strchr(flagstr, 'l')) {
+ if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
+ errorlog("<%s> the \'h\' and \'l\'"
+ " router flags are exclusive", __func__);
+ exit(1);
+ }
+ val |= ND_RA_FLAG_RTPREF_LOW;
+ }
+ } else {
+ MAYHAVE(val, "raflags", 0);
+ }
+ rai->managedflg = val & ND_RA_FLAG_MANAGED;
+ rai->otherflg = val & ND_RA_FLAG_OTHER;
+#ifndef ND_RA_FLAG_RTPREF_MASK
+#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
+#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */
+#endif
+ rai->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
+ if (rai->rtpref == ND_RA_FLAG_RTPREF_RSV) {
+ errorlog("<%s> invalid router preference (%02x) on %s",
+ __func__, rai->rtpref, intface);
+ exit(1);
+ }
+
+ MAYHAVE(val, "rltime", rai->maxinterval * 3);
+ if (val && (val < rai->maxinterval || val > MAXROUTERLIFETIME)) {
+ errorlog("<%s> router lifetime (%ld) on %s is invalid "
+ "(must be 0 or between %d and %d)",
+ __func__, val, intface,
+ rai->maxinterval,
+ MAXROUTERLIFETIME);
+ exit(1);
+ }
+ /*
+ * Basically, hosts MUST NOT send Router Advertisement messages at any
+ * time (RFC 2461, Section 6.2.3). However, it would sometimes be
+ * useful to allow hosts to advertise some parameters such as prefix
+ * information and link MTU. Thus, we allow hosts to invoke rtadvd
+ * only when router lifetime (on every advertising interface) is
+ * explicitly set zero. (see also the above section)
+ */
+ if (val && forwarding == 0) {
+ errorlog("<%s> non zero router lifetime is specified for %s, "
+ "which must not be allowed for hosts. you must "
+ "change router lifetime or enable IPv6 forwarding.",
+ __func__, intface);
+ exit(1);
+ }
+ rai->lifetime = val & 0xffff;
+
+ MAYHAVE(val, "rtime", DEF_ADVREACHABLETIME);
+ if (val < 0 || val > MAXREACHABLETIME) {
+ errorlog("<%s> reachable time (%ld) on %s is invalid "
+ "(must be no greater than %d)",
+ __func__, val, intface, MAXREACHABLETIME);
+ exit(1);
+ }
+ rai->reachabletime = (u_int32_t)val;
+
+ MAYHAVE(val64, "retrans", DEF_ADVRETRANSTIMER);
+ if (val64 < 0 || val64 > 0xffffffff) {
+ errorlog("<%s> retrans time (%lld) on %s out of range",
+ __func__, (long long)val64, intface);
+ exit(1);
+ }
+ rai->retranstimer = (u_int32_t)val64;
+
+ if (agetnum("hapref") != -1 || agetnum("hatime") != -1) {
+ errorlog("<%s> mobile-ip6 configuration not supported",
+ __func__);
+ exit(1);
+ }
+ /* prefix information */
+
+ /*
+ * This is an implementation specific parameter to consider
+ * link propagation delays and poorly synchronized clocks when
+ * checking consistency of advertised lifetimes.
+ */
+ MAYHAVE(val, "clockskew", 0);
+ rai->clockskew = val;
+
+ rai->pfxs = 0;
+ for (i = -1; i < MAXPREFIX; i++) {
+ struct prefix *pfx;
+ char entbuf[256];
+
+ makeentry(entbuf, sizeof(entbuf), i, "addr");
+ addr = (char *)agetstr(entbuf, &bp);
+ if (addr == NULL)
+ continue;
+
+ /* allocate memory to store prefix information */
+ ELM_MALLOC(pfx, exit(1));
+
+ pfx->rainfo = rai;
+ pfx->origin = PREFIX_FROM_CONFIG;
+
+ if (inet_pton(AF_INET6, addr, &pfx->prefix) != 1) {
+ errorlog("<%s> inet_pton failed for %s",
+ __func__, addr);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_MULTICAST(&pfx->prefix)) {
+ errorlog("<%s> multicast prefix (%s) must "
+ "not be advertised on %s",
+ __func__, addr, intface);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(&pfx->prefix))
+ noticelog("<%s> link-local prefix (%s) will be"
+ " advertised on %s",
+ __func__, addr, intface);
+
+ makeentry(entbuf, sizeof(entbuf), i, "prefixlen");
+ MAYHAVE(val, entbuf, 64);
+ if (val < 0 || val > 128) {
+ errorlog("<%s> prefixlen (%ld) for %s "
+ "on %s out of range",
+ __func__, val, addr, intface);
+ exit(1);
+ }
+ pfx->prefixlen = (int)val;
+
+ makeentry(entbuf, sizeof(entbuf), i, "pinfoflags");
+ if ((flagstr = (char *)agetstr(entbuf, &bp))) {
+ val = 0;
+ if (strchr(flagstr, 'l'))
+ val |= ND_OPT_PI_FLAG_ONLINK;
+ if (strchr(flagstr, 'a'))
+ val |= ND_OPT_PI_FLAG_AUTO;
+ } else {
+ MAYHAVE(val, entbuf,
+ (ND_OPT_PI_FLAG_ONLINK|ND_OPT_PI_FLAG_AUTO));
+ }
+ pfx->onlinkflg = val & ND_OPT_PI_FLAG_ONLINK;
+ pfx->autoconfflg = val & ND_OPT_PI_FLAG_AUTO;
+
+ makeentry(entbuf, sizeof(entbuf), i, "vltime");
+ MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
+ if (val64 < 0 || val64 > 0xffffffff) {
+ errorlog("<%s> vltime (%lld) for "
+ "%s/%d on %s is out of range",
+ __func__, (long long)val64,
+ addr, pfx->prefixlen, intface);
+ exit(1);
+ }
+ pfx->validlifetime = (u_int32_t)val64;
+
+ makeentry(entbuf, sizeof(entbuf), i, "vltimedecr");
+ if (agetflag(entbuf)) {
+ struct timeval now;
+ gettimeofday(&now, 0);
+ pfx->vltimeexpire =
+ now.tv_sec + pfx->validlifetime;
+ }
+
+ makeentry(entbuf, sizeof(entbuf), i, "pltime");
+ MAYHAVE(val64, entbuf, DEF_ADVPREFERREDLIFETIME);
+ if (val64 < 0 || val64 > 0xffffffff) {
+ errorlog("<%s> pltime (%lld) for %s/%d on %s "
+ "is out of range",
+ __func__, (long long)val64,
+ addr, pfx->prefixlen, intface);
+ exit(1);
+ }
+ pfx->preflifetime = (u_int32_t)val64;
+
+ makeentry(entbuf, sizeof(entbuf), i, "pltimedecr");
+ if (agetflag(entbuf)) {
+ struct timeval now;
+ gettimeofday(&now, 0);
+ pfx->pltimeexpire =
+ now.tv_sec + pfx->preflifetime;
+ }
+ /* link into chain */
+ insque(pfx, &rai->prefix);
+ rai->pfxs++;
+ }
+ if (rai->pfxs == 0)
+ get_prefix(rai);
+
+ MAYHAVE(val, "mtu", 0);
+ if (val < 0 || val > 0xffffffff) {
+ errorlog("<%s> mtu (%ld) on %s out of range",
+ __func__, val, intface);
+ exit(1);
+ }
+ rai->linkmtu = (u_int32_t)val;
+ if (rai->linkmtu == 0) {
+ char *mtustr;
+
+ if ((mtustr = (char *)agetstr("mtu", &bp)) &&
+ strcmp(mtustr, "auto") == 0)
+ rai->linkmtu = rai->phymtu;
+ }
+ else if (rai->linkmtu < IPV6_MMTU || rai->linkmtu > rai->phymtu) {
+ errorlog("<%s> advertised link mtu (%lu) on %s is invalid (must "
+ "be between least MTU (%d) and physical link MTU (%d)",
+ __func__, (unsigned long)rai->linkmtu, intface,
+ IPV6_MMTU, rai->phymtu);
+ exit(1);
+ }
+
+#ifdef SIOCSIFINFO_IN6
+ {
+ struct in6_ndireq ndi;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ exit(1);
+ }
+ memset(&ndi, 0, sizeof(ndi));
+ strlcpy(ndi.ifname, intface, sizeof(ndi.ifname));
+ if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&ndi) < 0) {
+ infolog("<%s> ioctl:SIOCGIFINFO_IN6 at %s: %s",
+ __func__, intface, strerror(errno));
+ }
+
+ /* reflect the RA info to the host variables in kernel */
+ ndi.ndi.chlim = rai->hoplimit;
+ ndi.ndi.retrans = rai->retranstimer;
+ ndi.ndi.basereachable = rai->reachabletime;
+ if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&ndi) < 0) {
+ infolog("<%s> ioctl:SIOCSIFINFO_IN6 at %s: %s",
+ __func__, intface, strerror(errno));
+ }
+ close(s);
+ }
+#endif
+
+ /* route information */
+#ifdef ROUTEINFO
+ rai->routes = 0;
+ for (i = -1; i < MAXROUTE; i++) {
+ struct rtinfo *rti;
+ char entbuf[256], oentbuf[256];
+
+ makeentry(entbuf, sizeof(entbuf), i, "rtprefix");
+ addr = (char *)agetstr(entbuf, &bp);
+ if (addr == NULL) {
+ makeentry(oentbuf, sizeof(oentbuf), i, "rtrprefix");
+ addr = (char *)agetstr(oentbuf, &bp);
+ if (addr) {
+ fprintf(stderr, "%s was obsoleted. Use %s.\n",
+ oentbuf, entbuf);
+ }
+ }
+ if (addr == NULL)
+ continue;
+
+ /* allocate memory to store prefix information */
+ ELM_MALLOC(rti, exit(1));
+
+ /* link into chain */
+ insque(rti, &rai->route);
+ rai->routes++;
+
+ if (inet_pton(AF_INET6, addr, &rti->prefix) != 1) {
+ errorlog( "<%s> inet_pton failed for %s",
+ __func__, addr);
+ exit(1);
+ }
+#if 0
+ /*
+ * XXX: currently there's no restriction in route information
+ * prefix according to
+ * draft-ietf-ipngwg-router-selection-00.txt.
+ * However, I think the similar restriction be necessary.
+ */
+ MAYHAVE(val64, entbuf, DEF_ADVVALIDLIFETIME);
+ if (IN6_IS_ADDR_MULTICAST(&rti->prefix)) {
+ errorlog("<%s> multicast route (%s) must "
+ "not be advertised on %s",
+ __func__, addr, intface);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_LINKLOCAL(&rti->prefix)) {
+ noticelog("<%s> link-local route (%s) will "
+ "be advertised on %s",
+ __func__, addr, intface);
+ exit(1);
+ }
+#endif
+
+ makeentry(entbuf, sizeof(entbuf), i, "rtplen");
+ /* XXX: 256 is a magic number for compatibility check. */
+ MAYHAVE(val, entbuf, 256);
+ if (val == 256) {
+ makeentry(oentbuf, sizeof(oentbuf), i, "rtrplen");
+ MAYHAVE(val, oentbuf, 256);
+ if (val != 256) {
+ fprintf(stderr, "%s was obsoleted. Use %s.\n",
+ oentbuf, entbuf);
+ } else
+ val = 64;
+ }
+ if (val < 0 || val > 128) {
+ errorlog("<%s> prefixlen (%ld) for %s on %s "
+ "out of range",
+ __func__, val, addr, intface);
+ exit(1);
+ }
+ rti->prefixlen = (int)val;
+
+ makeentry(entbuf, sizeof(entbuf), i, "rtflags");
+ if ((flagstr = (char *)agetstr(entbuf, &bp))) {
+ val = 0;
+ if (strchr(flagstr, 'h'))
+ val |= ND_RA_FLAG_RTPREF_HIGH;
+ if (strchr(flagstr, 'l')) {
+ if ((val & ND_RA_FLAG_RTPREF_HIGH)) {
+ errorlog(
+ "<%s> the \'h\' and \'l\' route"
+ " preferences are exclusive",
+ __func__);
+ exit(1);
+ }
+ val |= ND_RA_FLAG_RTPREF_LOW;
+ }
+ } else
+ MAYHAVE(val, entbuf, 256); /* XXX */
+ if (val == 256) {
+ makeentry(oentbuf, sizeof(oentbuf), i, "rtrflags");
+ MAYHAVE(val, oentbuf, 256);
+ if (val != 256) {
+ fprintf(stderr, "%s was obsoleted. Use %s.\n",
+ oentbuf, entbuf);
+ } else
+ val = 0;
+ }
+ rti->rtpref = val & ND_RA_FLAG_RTPREF_MASK;
+ if (rti->rtpref == ND_RA_FLAG_RTPREF_RSV) {
+ errorlog("<%s> invalid route preference (%02x) "
+ "for %s/%d on %s",
+ __func__, rti->rtpref, addr,
+ rti->prefixlen, intface);
+ exit(1);
+ }
+
+ /*
+ * Since the spec does not a default value, we should make
+ * this entry mandatory. However, FreeBSD 4.4 has shipped
+ * with this field being optional, we use the router lifetime
+ * as an ad-hoc default value with a warning message.
+ */
+ makeentry(entbuf, sizeof(entbuf), i, "rtltime");
+ MAYHAVE(val64, entbuf, -1);
+ if (val64 == -1) {
+ makeentry(oentbuf, sizeof(oentbuf), i, "rtrltime");
+ MAYHAVE(val64, oentbuf, -1);
+ if (val64 != -1) {
+ fprintf(stderr, "%s was obsoleted. Use %s.\n",
+ oentbuf, entbuf);
+ } else {
+ fprintf(stderr, "%s should be specified "
+ "for interface %s.\n",
+ entbuf, intface);
+ val64 = rai->lifetime;
+ }
+ }
+ if (val64 < 0 || val64 > 0xffffffff) {
+ errorlog( "<%s> route lifetime (%lld) for "
+ "%s/%d on %s out of range", __func__,
+ (long long)val64, addr, rti->prefixlen, intface);
+ exit(1);
+ }
+ rti->ltime = (u_int32_t)val64;
+ }
+#endif
+
+ /* RDNSS option (RFC5006) */
+ MAYHAVE(val, "rdnsslifetime", 2 * rai->maxinterval);
+ if (val < rai->maxinterval || val > (2 * rai->maxinterval)) {
+ noticelog("<%s> rdnsslifetime (%lu) on %s SHOULD "
+ "be between %u and %u", __func__, val,
+ intface, rai->maxinterval, 2 * rai->maxinterval);
+ }
+ rai->rdnss_lifetime = val;
+ if ((rdnss_length = agetnum("rdnssaddrs")) < 0) {
+ rai->rdnss_length = 0;
+ }
+ else {
+ rai->rdnss_length = rdnss_length;
+
+ /* traverse in reverse order so that the queue has correct order */
+ for (i = (rdnss_length - 1); i >= 0; i--) {
+ struct rdnss *rdnss;
+ char entbuf[256];
+
+ /* allocate memory to store server address information */
+ ELM_MALLOC(rdnss, exit(1));
+ /* link into chain */
+ insque(rdnss, &rai->rdnss_list);
+
+ makeentry(entbuf, sizeof(entbuf), i, "rdnssaddr");
+ addr = (char *)agetstr(entbuf, &bp);
+
+ if (addr == NULL && rdnss_length == 1) {
+ makeentry(entbuf, sizeof(entbuf), -1, "rdnssaddr");
+ addr = agetstr(entbuf, &bp);
+ }
+
+ if (addr == NULL) {
+ errorlog("<%s> need %s as a DNS server address for "
+ "interface %s",
+ __func__, entbuf, intface);
+ exit(1);
+ }
+
+ if (inet_pton(AF_INET6, addr, &rdnss->addr) != 1) {
+ errorlog("<%s> inet_pton failed for %s",
+ __func__, addr);
+ exit(1);
+ }
+ if (IN6_IS_ADDR_MULTICAST(&rdnss->addr)) {
+ errorlog("<%s> multicast address (%s) must "
+ "not be advertised as recursive DNS server",
+ __func__, addr);
+ exit(1);
+ }
+ }
+ }
+
+ /* DNSSL option (RFC6106) */
+
+ /* Parse the DNSSL lifetime from the config */
+ MAYHAVE(val, "dnssllifetime", 2 * rai->maxinterval);
+ if (val < rai->maxinterval || val > (2 * rai->maxinterval)) {
+ noticelog("<%s> dnssllifetime (%lu) on %s SHOULD "
+ "be between %u and %u", __func__, val,
+ intface, rai->maxinterval, 2 * rai->maxinterval);
+ }
+ rai->dnssl_lifetime = val;
+ rai->dnssl_option_length = 8; /* 8 bytes for the option header */
+
+ /* Parse the DNSSL domain list from the config */
+ if ((dnssl_length = agetnum("dnssldomains")) < 0) {
+ rai->dnssl_length = 0;
+ } else {
+ rai->dnssl_length = dnssl_length;
+
+ for (i = (rai->dnssl_length - 1); i >= 0; i--) {
+ unsigned char *dnssl_buf;
+ struct dnssl *dnssl;
+ int dnssl_len;
+ char entbuf[sizeof("dnssldomain") + 20];
+ char *domain;
+ int domain_len;
+
+ makeentry(entbuf, sizeof(entbuf), i, "dnssldomain");
+ domain = agetstr(entbuf, &bp);
+
+ if (domain == NULL && rai->dnssl_length == 1) {
+ makeentry(entbuf, sizeof(entbuf), -1, "dnssldomain");
+ domain = agetstr(entbuf, &bp);
+ }
+
+ if (domain == NULL) {
+ errorlog("<%s> need %s as a DNS search domain for "
+ "interface %s",
+ __func__, entbuf, intface);
+ exit(1);
+ }
+
+ domain_len = strlen(domain);
+
+ /* Trim off leading dots */
+ while (domain_len > 0 && domain[0] == '.') {
+ domain++;
+ domain_len--;
+ }
+
+ /* Trim off trailing dots */
+ while (domain_len > 0 && domain[domain_len-1] == '.') {
+ domain_len--;
+ }
+
+ if (domain_len > 0) {
+ dnssl_len = sizeof(struct dnssl) + domain_len + 1;
+ dnssl_buf = (unsigned char *)malloc(dnssl_len);
+
+ memset(dnssl_buf, 0, dnssl_len);
+
+ dnssl = (struct dnssl *)dnssl_buf;
+ insque(dnssl, &rai->dnssl_list);
+
+ /* Copy the domain name in at the end of the dnssl struct */
+ memcpy(dnssl_buf + offsetof(struct dnssl, domain), domain,
+ domain_len);
+
+ /* Add 2 for leading length byte and the trailing 0 byte */
+ rai->dnssl_option_length += domain_len + 2;
+ }
+ }
+
+ /* Round up to the next multiple of 8 */
+ rai->dnssl_option_length += (8 - (rai->dnssl_option_length & 0x7));
+ }
+
+ /* captive portal */
+ capport = agetstr("capport", &bp);
+ if (capport != NULL) {
+ rai->capport = strdup(capport);
+ rai->capport_length = strlen(capport);
+ rai->capport_option_length
+ = sizeof(struct nd_opt_hdr) + rai->capport_length;
+ rai->capport_option_length
+ += (8 - (rai->capport_option_length & 0x7));
+ }
+
+ /* okey */
+ rai->next = ralist;
+ ralist = rai;
+
+ /* construct the sending packet */
+ make_packet(rai);
+
+ /* set timer */
+ rai->timer = rtadvd_add_timer(ra_timeout, ra_timer_update,
+ rai, rai);
+ ra_timer_update((void *)rai, &rai->timer->tm);
+ rtadvd_set_timer(&rai->timer->tm, rai->timer);
+}
+
+void
+get_prefix(struct rainfo *rai)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct prefix *pfx;
+ struct in6_addr *a;
+ u_char *p, *ep, *m, *lim;
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ if (getifaddrs(&ifap) < 0) {
+ errorlog(
+ "<%s> can't get interface addresses",
+ __func__);
+ exit(1);
+ }
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ int plen;
+
+ if (strcmp(ifa->ifa_name, rai->ifname) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ a = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+ if (IN6_IS_ADDR_LINKLOCAL(a))
+ continue;
+ /* get prefix length */
+ m = (u_char *)&((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
+ lim = (u_char *)(ifa->ifa_netmask) + ifa->ifa_netmask->sa_len;
+ plen = prefixlen(m, lim);
+ if (plen <= 0 || plen > 128) {
+ errorlog( "<%s> failed to get prefixlen "
+ "or prefix is invalid",
+ __func__);
+ exit(1);
+ }
+ if (plen == 128) /* XXX */
+ continue;
+ if (find_prefix(rai, a, plen)) {
+ /* ignore a duplicated prefix. */
+ continue;
+ }
+
+ /* allocate memory to store prefix info. */
+ ELM_MALLOC(pfx, exit(1));
+ /* set prefix, sweep bits outside of prefixlen */
+ pfx->prefixlen = plen;
+ memcpy(&pfx->prefix, a, sizeof(*a));
+ p = (u_char *)&pfx->prefix;
+ ep = (u_char *)(&pfx->prefix + 1);
+ while (m < lim && p < ep)
+ *p++ &= *m++;
+ while (p < ep)
+ *p++ = 0x00;
+ if (!inet_ntop(AF_INET6, &pfx->prefix, ntopbuf,
+ sizeof(ntopbuf))) {
+ errorlog("<%s> inet_ntop failed", __func__);
+ exit(1);
+ }
+ debuglog("<%s> add %s/%d to prefix list on %s",
+ __func__, ntopbuf, pfx->prefixlen, rai->ifname);
+
+ /* set other fields with protocol defaults */
+ pfx->validlifetime = DEF_ADVVALIDLIFETIME;
+ pfx->preflifetime = DEF_ADVPREFERREDLIFETIME;
+ pfx->onlinkflg = 1;
+ pfx->autoconfflg = 1;
+ pfx->origin = PREFIX_FROM_KERNEL;
+ pfx->rainfo = rai;
+
+ /* link into chain */
+ insque(pfx, &rai->prefix);
+
+ /* counter increment */
+ rai->pfxs++;
+ }
+
+ freeifaddrs(ifap);
+}
+
+static void
+makeentry(buf, len, id, string)
+ char *buf;
+ size_t len;
+ int id;
+ char *string;
+{
+
+ if (id < 0)
+ strlcpy(buf, string, len);
+ else
+ snprintf(buf, len, "%s%d", string, id);
+}
+
+/*
+ * Add a prefix to the list of specified interface and reconstruct
+ * the outgoing packet.
+ * The prefix must not be in the list.
+ * XXX: other parameters of the prefix (e.g. lifetime) should be
+ * able to be specified.
+ */
+static void
+add_prefix(struct rainfo *rai, struct in6_prefixreq *ipr)
+{
+ struct prefix *prefix;
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ ELM_MALLOC(prefix, exit(1));
+ prefix->prefix = ipr->ipr_prefix.sin6_addr;
+ prefix->prefixlen = ipr->ipr_plen;
+ prefix->validlifetime = ipr->ipr_vltime;
+ prefix->preflifetime = ipr->ipr_pltime;
+ prefix->onlinkflg = ipr->ipr_raf_onlink;
+ prefix->autoconfflg = ipr->ipr_raf_auto;
+ prefix->origin = PREFIX_FROM_DYNAMIC;
+ prefix->rainfo = rai;
+
+ insque(prefix, &rai->prefix);
+
+ debuglog("<%s> new prefix %s/%d was added on %s",
+ __func__, inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ ipr->ipr_plen, rai->ifname);
+
+ /* free the previous packet */
+ free(rai->ra_data);
+ rai->ra_data = NULL;
+
+ /* reconstruct the packet */
+ rai->pfxs++;
+ make_packet(rai);
+}
+
+/*
+ * Delete a prefix to the list of specified interface and reconstruct
+ * the outgoing packet.
+ * The prefix must be in the list.
+ */
+void
+delete_prefix(struct prefix *prefix)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct rainfo *rai = prefix->rainfo;
+
+ remque(prefix);
+ debuglog("<%s> prefix %s/%d was deleted on %s",
+ __func__, inet_ntop(AF_INET6, &prefix->prefix,
+ ntopbuf, INET6_ADDRSTRLEN),
+ prefix->prefixlen, rai->ifname);
+ if (prefix->timer)
+ rtadvd_remove_timer(&prefix->timer);
+ free(prefix);
+ rai->pfxs--;
+}
+
+void
+invalidate_prefix(struct prefix *prefix)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct timeval timo;
+ struct rainfo *rai = prefix->rainfo;
+
+ if (prefix->timer) { /* sanity check */
+ errorlog("<%s> assumption failure: timer already exists",
+ __func__);
+ exit(1);
+ }
+
+ debuglog("<%s> prefix %s/%d was invalidated on %s, "
+ "will expire in %ld seconds", __func__,
+ inet_ntop(AF_INET6, &prefix->prefix, ntopbuf, INET6_ADDRSTRLEN),
+ prefix->prefixlen, rai->ifname, (long)prefix_timo);
+
+ /* set the expiration timer */
+ prefix->timer = rtadvd_add_timer(prefix_timeout, NULL, prefix, NULL);
+ if (prefix->timer == NULL) {
+ errorlog("<%s> failed to add a timer for a prefix. "
+ "remove the prefix", __func__);
+ delete_prefix(prefix);
+ return;
+ }
+ timo.tv_sec = prefix_timo;
+ timo.tv_usec = 0;
+ rtadvd_set_timer(&timo, prefix->timer);
+}
+
+static struct rtadvd_timer *
+prefix_timeout(void *arg)
+{
+ struct prefix *prefix = (struct prefix *)arg;
+
+ delete_prefix(prefix);
+
+ return(NULL);
+}
+
+void
+update_prefix(struct prefix * prefix)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+ struct rainfo *rai = prefix->rainfo;
+
+ if (prefix->timer == NULL) { /* sanity check */
+ errorlog("<%s> assumption failure: timer does not exist",
+ __func__);
+ exit(1);
+ }
+
+ debuglog("<%s> prefix %s/%d was re-enabled on %s",
+ __func__, inet_ntop(AF_INET6, &prefix->prefix, ntopbuf,
+ INET6_ADDRSTRLEN), prefix->prefixlen, rai->ifname);
+
+ /* stop the expiration timer */
+ rtadvd_remove_timer(&prefix->timer);
+}
+
+/*
+ * Try to get an in6_prefixreq contents for a prefix which matches
+ * ipr->ipr_prefix and ipr->ipr_plen and belongs to
+ * the interface whose name is ipr->ipr_name[].
+ */
+static int
+init_prefix(struct in6_prefixreq *ipr)
+{
+#if 0
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ exit(1);
+ }
+
+ if (ioctl(s, SIOCGIFPREFIX_IN6, (caddr_t)ipr) < 0) {
+ infolog("<%s> ioctl:SIOCGIFPREFIX %s", __func__,
+ strerror(errno));
+
+ ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
+ ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
+ ipr->ipr_raf_onlink = 1;
+ ipr->ipr_raf_auto = 1;
+ /* omit other field initialization */
+ }
+ else if (ipr->ipr_origin < PR_ORIG_RR) {
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ noticelog("<%s> Added prefix(%s)'s origin %d is"
+ "lower than PR_ORIG_RR(router renumbering)."
+ "This should not happen if I am router", __func__,
+ inet_ntop(AF_INET6, &ipr->ipr_prefix.sin6_addr, ntopbuf,
+ sizeof(ntopbuf)), ipr->ipr_origin);
+ close(s);
+ return 1;
+ }
+
+ close(s);
+ return 0;
+#else
+ ipr->ipr_vltime = DEF_ADVVALIDLIFETIME;
+ ipr->ipr_pltime = DEF_ADVPREFERREDLIFETIME;
+ ipr->ipr_raf_onlink = 1;
+ ipr->ipr_raf_auto = 1;
+ return 0;
+#endif
+}
+
+void
+make_prefix(struct rainfo *rai, int ifindex, struct in6_addr *addr, int plen)
+{
+ struct in6_prefixreq ipr;
+
+ memset(&ipr, 0, sizeof(ipr));
+ if (if_indextoname(ifindex, ipr.ipr_name) == NULL) {
+ errorlog("<%s> Prefix added interface No.%d doesn't"
+ "exist. This should not happen! %s", __func__,
+ ifindex, strerror(errno));
+ exit(1);
+ }
+ ipr.ipr_prefix.sin6_len = sizeof(ipr.ipr_prefix);
+ ipr.ipr_prefix.sin6_family = AF_INET6;
+ ipr.ipr_prefix.sin6_addr = *addr;
+ ipr.ipr_plen = plen;
+
+ if (init_prefix(&ipr))
+ return; /* init failed by some error */
+ add_prefix(rai, &ipr);
+}
+
+void
+make_packet(struct rainfo *rainfo)
+{
+ size_t packlen, lladdroptlen = 0;
+ u_char *buf;
+ struct nd_router_advert *ra;
+ struct nd_opt_prefix_info *ndopt_pi;
+ struct nd_opt_mtu *ndopt_mtu;
+#ifdef ROUTEINFO
+ struct nd_opt_route_info *ndopt_rti;
+ struct rtinfo *rti;
+#endif
+ struct prefix *pfx;
+
+ /* calculate total length */
+ packlen = sizeof(struct nd_router_advert);
+ if (rainfo->advlinkopt) {
+ if ((lladdroptlen = lladdropt_length(rainfo->sdl)) == 0) {
+ infolog("<%s> link-layer address option has"
+ " null length on %s. Treat as not included.",
+ __func__, rainfo->ifname);
+ rainfo->advlinkopt = 0;
+ }
+ packlen += lladdroptlen;
+ }
+ if (rainfo->pfxs)
+ packlen += sizeof(struct nd_opt_prefix_info) * rainfo->pfxs;
+ if (rainfo->linkmtu)
+ packlen += sizeof(struct nd_opt_mtu);
+#ifdef ROUTEINFO
+ for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next)
+ packlen += sizeof(struct nd_opt_route_info) +
+ ((rti->prefixlen + 0x3f) >> 6) * 8;
+#endif
+ if (rainfo->rdnss_length > 0)
+ packlen += 8 + sizeof(struct in6_addr) * rainfo->rdnss_length;
+
+ if (rainfo->dnssl_length > 0) {
+ packlen += rainfo->dnssl_option_length;
+ }
+ if (rainfo->capport_option_length != 0) {
+ packlen += rainfo->capport_option_length;
+ }
+
+ /* allocate memory for the packet */
+ if ((buf = malloc(packlen)) == NULL) {
+ errorlog("<%s> can't get enough memory for an RA packet",
+ __func__);
+ exit(1);
+ }
+ if (rainfo->ra_data) {
+ /* free the previous packet */
+ free(rainfo->ra_data);
+ rainfo->ra_data = NULL;
+ }
+ rainfo->ra_data = buf;
+ /* XXX: what if packlen > 576? */
+ rainfo->ra_datalen = packlen;
+
+ /*
+ * construct the packet
+ */
+ ra = (struct nd_router_advert *)buf;
+ ra->nd_ra_type = ND_ROUTER_ADVERT;
+ ra->nd_ra_code = 0;
+ ra->nd_ra_cksum = 0;
+ ra->nd_ra_curhoplimit = (u_int8_t)(0xff & rainfo->hoplimit);
+ ra->nd_ra_flags_reserved = 0; /* just in case */
+ /*
+ * XXX: the router preference field, which is a 2-bit field, should be
+ * initialized before other fields.
+ */
+ ra->nd_ra_flags_reserved = 0xff & rainfo->rtpref;
+ ra->nd_ra_flags_reserved |=
+ rainfo->managedflg ? ND_RA_FLAG_MANAGED : 0;
+ ra->nd_ra_flags_reserved |=
+ rainfo->otherflg ? ND_RA_FLAG_OTHER : 0;
+ ra->nd_ra_router_lifetime = htons(rainfo->lifetime);
+ ra->nd_ra_reachable = htonl(rainfo->reachabletime);
+ ra->nd_ra_retransmit = htonl(rainfo->retranstimer);
+ buf += sizeof(*ra);
+
+ if (rainfo->advlinkopt) {
+ lladdropt_fill(rainfo->sdl, (struct nd_opt_hdr *)buf);
+ buf += lladdroptlen;
+ }
+
+ if (rainfo->linkmtu) {
+ ndopt_mtu = (struct nd_opt_mtu *)buf;
+ ndopt_mtu->nd_opt_mtu_type = ND_OPT_MTU;
+ ndopt_mtu->nd_opt_mtu_len = 1;
+ ndopt_mtu->nd_opt_mtu_reserved = 0;
+ ndopt_mtu->nd_opt_mtu_mtu = htonl(rainfo->linkmtu);
+ buf += sizeof(struct nd_opt_mtu);
+ }
+
+ for (pfx = rainfo->prefix.next;
+ pfx != &rainfo->prefix; pfx = pfx->next) {
+ u_int32_t vltime, pltime;
+ struct timeval now;
+
+ ndopt_pi = (struct nd_opt_prefix_info *)buf;
+ ndopt_pi->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
+ ndopt_pi->nd_opt_pi_len = 4;
+ ndopt_pi->nd_opt_pi_prefix_len = pfx->prefixlen;
+ ndopt_pi->nd_opt_pi_flags_reserved = 0;
+ if (pfx->onlinkflg)
+ ndopt_pi->nd_opt_pi_flags_reserved |=
+ ND_OPT_PI_FLAG_ONLINK;
+ if (pfx->autoconfflg)
+ ndopt_pi->nd_opt_pi_flags_reserved |=
+ ND_OPT_PI_FLAG_AUTO;
+ if (pfx->timer)
+ vltime = 0;
+ else {
+ if (pfx->vltimeexpire || pfx->pltimeexpire)
+ gettimeofday(&now, NULL);
+ if (pfx->vltimeexpire == 0)
+ vltime = pfx->validlifetime;
+ else
+ vltime = (pfx->vltimeexpire > now.tv_sec) ?
+ pfx->vltimeexpire - now.tv_sec : 0;
+ }
+ if (pfx->timer)
+ pltime = 0;
+ else {
+ if (pfx->pltimeexpire == 0)
+ pltime = pfx->preflifetime;
+ else
+ pltime = (pfx->pltimeexpire > now.tv_sec) ?
+ pfx->pltimeexpire - now.tv_sec : 0;
+ }
+ if (vltime < pltime) {
+ /*
+ * this can happen if vltime is decrement but pltime
+ * is not.
+ */
+ pltime = vltime;
+ }
+ ndopt_pi->nd_opt_pi_valid_time = htonl(vltime);
+ ndopt_pi->nd_opt_pi_preferred_time = htonl(pltime);
+ ndopt_pi->nd_opt_pi_reserved2 = 0;
+ ndopt_pi->nd_opt_pi_prefix = pfx->prefix;
+
+ buf += sizeof(struct nd_opt_prefix_info);
+ }
+
+#ifdef ROUTEINFO
+ for (rti = rainfo->route.next; rti != &rainfo->route; rti = rti->next) {
+ u_int8_t psize = (rti->prefixlen + 0x3f) >> 6;
+
+ ndopt_rti = (struct nd_opt_route_info *)buf;
+ ndopt_rti->nd_opt_rti_type = ND_OPT_ROUTE_INFO;
+ ndopt_rti->nd_opt_rti_len = 1 + psize;
+ ndopt_rti->nd_opt_rti_prefixlen = rti->prefixlen;
+ ndopt_rti->nd_opt_rti_flags = 0xff & rti->rtpref;
+ ndopt_rti->nd_opt_rti_lifetime = htonl(rti->ltime);
+ memcpy(ndopt_rti + 1, &rti->prefix, psize * 8);
+ buf += sizeof(struct nd_opt_route_info) + psize * 8;
+ }
+#endif
+
+ if (rainfo->rdnss_length > 0) {
+ struct nd_opt_rdnss * ndopt_rdnss;
+ struct rdnss * rdnss;
+
+ ndopt_rdnss = (struct nd_opt_rdnss*) buf;
+ ndopt_rdnss->nd_opt_rdnss_type = ND_OPT_RDNSS;
+ ndopt_rdnss->nd_opt_rdnss_len = 1 + (rainfo->rdnss_length * 2);
+ ndopt_rdnss->nd_opt_rdnss_reserved = 0;
+ ndopt_rdnss->nd_opt_rdnss_lifetime = htonl(rainfo->rdnss_lifetime);
+ buf += 8;
+
+ for (rdnss = rainfo->rdnss_list.next;
+ rdnss != &rainfo->rdnss_list;
+ rdnss = rdnss->next)
+ {
+ struct in6_addr* addr6 = (struct in6_addr*) buf;
+ *addr6 = rdnss->addr;
+ buf += sizeof *addr6;
+ }
+ }
+
+ if (rainfo->dnssl_length > 0) {
+ struct nd_opt_dnssl * dnssl_opt;
+ struct dnssl * dnssl;
+ int domains_length = 0;
+ u_char * cursor = buf;
+
+ memset(cursor, 0, rainfo->dnssl_option_length);
+
+ dnssl_opt = (struct nd_opt_dnssl *)cursor;
+ dnssl_opt->nd_opt_dnssl_type = ND_OPT_DNSSL;
+ /*
+ * Length is in units of 8 octets. Divide total byte length
+ * of the option by 8.
+ */
+ dnssl_opt->nd_opt_dnssl_len = rainfo->dnssl_option_length >> 3;
+ dnssl_opt->nd_opt_dnssl_reserved = 0;
+ dnssl_opt->nd_opt_dnssl_lifetime =
+ htonl(rainfo->dnssl_lifetime);
+
+ cursor += offsetof(struct nd_opt_dnssl, nd_opt_dnssl_domains);
+
+ for (dnssl = rainfo->dnssl_list.next;
+ dnssl != &rainfo->dnssl_list;
+ dnssl = dnssl->next)
+ {
+ int encodeLen = encode_domain(dnssl->domain, cursor);
+ cursor += encodeLen;
+ domains_length += encodeLen;
+ }
+
+ buf += rainfo->dnssl_option_length;
+ }
+ if (rainfo->capport != NULL) {
+ struct nd_opt_hdr * capport_opt;
+ u_int32_t zero_space;
+
+ capport_opt = (struct nd_opt_hdr *)buf;
+#ifndef ND_OPT_CAPTIVE_PORTAL
+#define ND_OPT_CAPTIVE_PORTAL 37 /* RFC 7710 */
+#endif /* ND_OPT_CAPTIVE_PORTAL */
+ capport_opt->nd_opt_type = ND_OPT_CAPTIVE_PORTAL;
+ capport_opt->nd_opt_len = rainfo->capport_option_length >> 3;
+ buf += sizeof(*capport_opt);
+ bcopy(rainfo->capport, buf, rainfo->capport_length);
+ buf += rainfo->capport_length;
+ zero_space = rainfo->capport_option_length
+ - rainfo->capport_length;
+ if (zero_space > 0) {
+ bzero(buf, zero_space);
+ buf += zero_space;
+ }
+ }
+ return;
+}
+
+static int
+getinet6sysctl(int code)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
+ int value;
+ size_t size;
+
+ mib[3] = code;
+ size = sizeof(value);
+ if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0)
+ < 0) {
+ errorlog( "<%s>: failed to get ip6 sysctl(%d): %s",
+ __func__, code,
+ strerror(errno));
+ return(-1);
+ }
+ else
+ return(value);
+}
+
+/*
+ * Encode a domain name into a buffer according to the rules in RFC 1035 section
+ * 3.1. Do not use the compression techniques outlined in section 4.1.4.
+ */
+int
+encode_domain(char *domain, u_char *dst)
+{
+ char *domainCopy = strdup(domain);
+ char *input = domainCopy;
+ char *label;
+ u_char *cursor = dst;
+
+ while ((label = strsep(&input, ".")) != NULL) {
+ int label_len = strlen(label) & 0x3f; /* Max length is 63 */
+ if (label_len > 0) {
+ *cursor = (u_char)label_len;
+ cursor++;
+ memcpy(cursor, label, label_len);
+ cursor += label_len;
+ }
+ }
+ *cursor = 0;
+ cursor++;
+
+ free(domainCopy);
+
+ return (cursor - dst);
+}
diff --git a/network_cmds/rtadvd.tproj/config.h b/network_cmds/rtadvd.tproj/config.h
new file mode 100644
index 0000000..f1f0387
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/config.h
@@ -0,0 +1,46 @@
+/* $KAME: config.h,v 1.8 2003/06/17 08:26:22 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+extern void getconfig(char *);
+extern void delete_prefix(struct prefix *);
+extern void invalidate_prefix(struct prefix *);
+extern void update_prefix(struct prefix *);
+extern void make_prefix(struct rainfo *, int, struct in6_addr *, int);
+extern void make_packet(struct rainfo *);
+extern void get_prefix(struct rainfo *);
+
+
+/*
+ * it is highly unlikely to have 100 prefix information options,
+ * so it should be okay to limit it
+ */
+#define MAXPREFIX 100
+#define MAXROUTE 100
diff --git a/network_cmds/rtadvd.tproj/dump.c b/network_cmds/rtadvd.tproj/dump.c
new file mode 100644
index 0000000..ea5dcd9
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/dump.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2009-2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: dump.c,v 1.32 2003/05/19 09:46:50 keiichi Exp $ */
+
+/*
+ * Copyright (C) 2000 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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/socket.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+
+/* XXX: the following two are non-standard include files */
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "rtadvd.h"
+#include "timer.h"
+#include "if.h"
+#include "dump.h"
+
+static FILE *fp;
+
+extern struct rainfo *ralist;
+
+static char *ether_str(struct sockaddr_dl *);
+static void if_dump(void);
+
+static char *rtpref_str[] = {
+ "medium", /* 00 */
+ "high", /* 01 */
+ "rsv", /* 10 */
+ "low" /* 11 */
+};
+
+static char *
+ether_str(sdl)
+ struct sockaddr_dl *sdl;
+{
+ static char hbuf[32];
+ u_char *cp;
+
+ if (sdl->sdl_alen && sdl->sdl_alen > 5) {
+ cp = (u_char *)LLADDR(sdl);
+ snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x",
+ cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+ } else
+ snprintf(hbuf, sizeof(hbuf), "NONE");
+
+ return(hbuf);
+}
+
+static void
+if_dump()
+{
+ struct rainfo *rai;
+ struct prefix *pfx;
+#ifdef ROUTEINFO
+ struct rtinfo *rti;
+#endif
+ char prefixbuf[INET6_ADDRSTRLEN];
+ int first;
+ struct timeval now;
+
+ gettimeofday(&now, NULL); /* XXX: unused in most cases */
+ for (rai = ralist; rai; rai = rai->next) {
+ fprintf(fp, "%s:\n", rai->ifname);
+ struct if_msghdr *ifm = get_interface_entry(rai->ifindex);
+ if (ifm == NULL) {
+ debuglog("Skippingg RA entry for interface %s"
+ "as we couldn't find interface entry for it.", rai->ifname);
+ continue;
+ }
+ fprintf(fp, " Status: %s\n",
+ (ifm->ifm_flags & IFF_UP) ? "UP" :
+ "DOWN");
+
+ /* control information */
+ if (rai->lastsent.tv_sec) {
+ /* note that ctime() appends CR by itself */
+ fprintf(fp, " Last RA sent: %s",
+ ctime((time_t *)&rai->lastsent.tv_sec));
+ }
+ if (rai->timer) {
+ fprintf(fp, " Next RA will be sent: %s",
+ ctime((time_t *)&rai->timer->tm.tv_sec));
+ }
+ else
+ fprintf(fp, " RA timer is stopped");
+ fprintf(fp, " waits: %d, initcount: %d\n",
+ rai->waiting, rai->initcounter);
+
+ /* statistics */
+ fprintf(fp, " statistics: RA(out/in/inconsistent): "
+ "%llu/%llu/%llu, ",
+ (unsigned long long)rai->raoutput,
+ (unsigned long long)rai->rainput,
+ (unsigned long long)rai->rainconsistent);
+ fprintf(fp, "RS(input): %llu\n",
+ (unsigned long long)rai->rsinput);
+
+ /* interface information */
+ if (rai->advlinkopt)
+ fprintf(fp, " Link-layer address: %s\n",
+ ether_str(rai->sdl));
+ fprintf(fp, " MTU: %d\n", rai->phymtu);
+
+ /* Router configuration variables */
+ fprintf(fp, " DefaultLifetime: %d, MaxAdvInterval: %d, "
+ "MinAdvInterval: %d\n", rai->lifetime, rai->maxinterval,
+ rai->mininterval);
+ fprintf(fp, " Flags: %s%s%s, ",
+ rai->managedflg ? "M" : "", rai->otherflg ? "O" : "", "");
+ fprintf(fp, "Preference: %s, ",
+ rtpref_str[(rai->rtpref >> 3) & 0xff]);
+ fprintf(fp, "MTU: %d\n", rai->linkmtu);
+ fprintf(fp, " ReachableTime: %d, RetransTimer: %d, "
+ "CurHopLimit: %d\n", rai->reachabletime,
+ rai->retranstimer, rai->hoplimit);
+ if (rai->clockskew)
+ fprintf(fp, " Clock skew: %ldsec\n",
+ rai->clockskew);
+ for (first = 1, pfx = rai->prefix.next; pfx != &rai->prefix;
+ pfx = pfx->next) {
+ if (first) {
+ fprintf(fp, " Prefixes:\n");
+ first = 0;
+ }
+ fprintf(fp, " %s/%d(",
+ inet_ntop(AF_INET6, &pfx->prefix, prefixbuf,
+ sizeof(prefixbuf)), pfx->prefixlen);
+ switch (pfx->origin) {
+ case PREFIX_FROM_KERNEL:
+ fprintf(fp, "KERNEL, ");
+ break;
+ case PREFIX_FROM_CONFIG:
+ fprintf(fp, "CONFIG, ");
+ break;
+ case PREFIX_FROM_DYNAMIC:
+ fprintf(fp, "DYNAMIC, ");
+ break;
+ }
+ if (pfx->validlifetime == ND6_INFINITE_LIFETIME)
+ fprintf(fp, "vltime: infinity");
+ else
+ fprintf(fp, "vltime: %ld",
+ (long)pfx->validlifetime);
+ if (pfx->vltimeexpire != 0)
+ fprintf(fp, "(decr,expire %ld), ", (long)
+ pfx->vltimeexpire > now.tv_sec ?
+ pfx->vltimeexpire - now.tv_sec : 0);
+ else
+ fprintf(fp, ", ");
+ if (pfx->preflifetime == ND6_INFINITE_LIFETIME)
+ fprintf(fp, "pltime: infinity");
+ else
+ fprintf(fp, "pltime: %ld",
+ (long)pfx->preflifetime);
+ if (pfx->pltimeexpire != 0)
+ fprintf(fp, "(decr,expire %ld), ", (long)
+ pfx->pltimeexpire > now.tv_sec ?
+ pfx->pltimeexpire - now.tv_sec : 0);
+ else
+ fprintf(fp, ", ");
+ fprintf(fp, "flags: %s%s%s",
+ pfx->onlinkflg ? "L" : "",
+ pfx->autoconfflg ? "A" : "",
+ "");
+ if (pfx->timer) {
+ struct timeval *rest;
+
+ rest = rtadvd_timer_rest(pfx->timer);
+ if (rest) { /* XXX: what if not? */
+ fprintf(fp, ", expire in: %ld",
+ (long)rest->tv_sec);
+ }
+ }
+ fprintf(fp, ")\n");
+ }
+#ifdef ROUTEINFO
+ for (first = 1, rti = rai->route.next; rti != &rai->route;
+ rti = rti->next) {
+ if (first) {
+ fprintf(fp, " Route Information:\n");
+ first = 0;
+ }
+ fprintf(fp, " %s/%d (",
+ inet_ntop(AF_INET6, &rti->prefix,
+ prefixbuf, sizeof(prefixbuf)),
+ rti->prefixlen);
+ fprintf(fp, "preference: %s, ",
+ rtpref_str[0xff & (rti->rtpref >> 3)]);
+ if (rti->ltime == ND6_INFINITE_LIFETIME)
+ fprintf(fp, "lifetime: infinity");
+ else
+ fprintf(fp, "lifetime: %ld", (long)rti->ltime);
+ fprintf(fp, ")\n");
+ }
+#endif
+ }
+}
+
+void
+rtadvd_dump_file(dumpfile)
+ char *dumpfile;
+{
+ debuglog("<%s> dump current status to %s", __func__,
+ dumpfile);
+
+ if ((fp = fopen(dumpfile, "w")) == NULL) {
+ errorlog("<%s> open a dump file(%s)",
+ __func__, dumpfile);
+ return;
+ }
+
+ if_dump();
+
+ fclose(fp);
+}
diff --git a/network_cmds/rtadvd.tproj/dump.h b/network_cmds/rtadvd.tproj/dump.h
new file mode 100644
index 0000000..4e10b4a
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/dump.h
@@ -0,0 +1,32 @@
+/* $KAME: dump.h,v 1.1 2000/05/23 11:31:26 itojun Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+extern void rtadvd_dump_file(char *);
diff --git a/network_cmds/rtadvd.tproj/if.c b/network_cmds/rtadvd.tproj/if.c
new file mode 100644
index 0000000..9862af2
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/if.c
@@ -0,0 +1,604 @@
+/* $KAME: if.c,v 1.17 2001/01/21 15:27:30 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+#include <ifaddrs.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include "rtadvd.h"
+#include "if.h"
+
+#define ROUNDUP(a, size) \
+ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
+
+#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
+ ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
+ sizeof(uint32_t)) :\
+ sizeof(uint32_t)))
+
+/* Interface list */
+TAILQ_HEAD(ifilist_head_t, ifinfo);
+struct ifilist_head_t ifilist = TAILQ_HEAD_INITIALIZER(ifilist);
+size_t ifblock_size;
+char *ifblock;
+
+static void get_iflist(char **buf, size_t *size);
+static void parse_iflist(char *buf, size_t bufsize);
+static void purge_iflist();
+
+static void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ NEXT_SA(sa);
+ }
+ else
+ rti_info[i] = NULL;
+ }
+}
+
+struct sockaddr_dl *
+if_nametosdl(char *name)
+{
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
+ char *buf, *next, *lim;
+ size_t len;
+ struct if_msghdr *ifm;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ struct sockaddr_dl *sdl = NULL, *ret_sdl = NULL;
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return(NULL);
+ if ((buf = malloc(len)) == NULL)
+ return(NULL);
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ free(buf);
+ return(NULL);
+ }
+
+ lim = buf + len;
+ for (next = buf; next < lim; next += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sa = (struct sockaddr *)(ifm + 1);
+ get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
+ if ((sa = rti_info[RTAX_IFP]) != NULL) {
+ if (sa->sa_family == AF_LINK) {
+ sdl = (struct sockaddr_dl *)sa;
+ if (strlen(name) != sdl->sdl_nlen)
+ continue; /* not same len */
+ if (strncmp(&sdl->sdl_data[0],
+ name,
+ sdl->sdl_nlen) == 0) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (next == lim) {
+ /* search failed */
+ free(buf);
+ return(NULL);
+ }
+
+ if (sdl == NULL || (ret_sdl = malloc(sdl->sdl_len)) == NULL)
+ goto end;
+ memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
+
+end:
+ free(buf);
+ return(ret_sdl);
+}
+
+int
+if_getmtu(char *name)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct if_data *ifd;
+ int mtu = 0;
+
+ if (getifaddrs(&ifap) < 0)
+ return(0);
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (strcmp(ifa->ifa_name, name) == 0) {
+ ifd = ifa->ifa_data;
+ if (ifd)
+ mtu = ifd->ifi_mtu;
+ break;
+ }
+ }
+ freeifaddrs(ifap);
+
+#ifdef SIOCGIFMTU /* XXX: this ifdef may not be necessary */
+ if (mtu == 0) {
+ struct ifreq ifr;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
+ return(0);
+
+ ifr.ifr_addr.sa_family = AF_INET6;
+ strlcpy(ifr.ifr_name, name,
+ sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) < 0) {
+ close(s);
+ return(0);
+ }
+ close(s);
+
+ mtu = ifr.ifr_mtu;
+ }
+#endif
+
+ return(mtu);
+}
+
+/* give interface index and its old flags, then new flags returned */
+int
+if_getflags(int ifindex, int oifflags)
+{
+ struct ifreq ifr;
+ int s;
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ return (oifflags & ~IFF_UP);
+ }
+
+ if_indextoname(ifindex, ifr.ifr_name);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ errorlog("<%s> ioctl:SIOCGIFFLAGS: failed for %s",
+ __func__, ifr.ifr_name);
+ close(s);
+ return (oifflags & ~IFF_UP);
+ }
+ close(s);
+ return (ifr.ifr_flags);
+}
+
+#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
+int
+lladdropt_length(struct sockaddr_dl *sdl)
+{
+ switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ return(ROUNDUP8(ETHER_ADDR_LEN + 2));
+ default:
+ return(0);
+ }
+}
+
+void
+lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
+{
+ char *addr;
+
+ ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
+
+ switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
+ addr = (char *)(ndopt + 1);
+ memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
+ break;
+ default:
+ errorlog("<%s> unsupported link type(%d)",
+ __func__, sdl->sdl_type);
+ exit(1);
+ }
+
+ return;
+}
+
+int
+rtbuf_len()
+{
+ size_t len;
+
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET6, NET_RT_DUMP, 0};
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return(-1);
+
+ return(len);
+}
+
+#define FILTER_MATCH(type, filter) ((0x1 << type) & filter)
+#define SIN6(s) ((struct sockaddr_in6 *)(s))
+#define SDL(s) ((struct sockaddr_dl *)(s))
+char *
+get_next_msg(char *buf, char *lim, int ifindex, size_t *lenp, int filter)
+{
+ struct rt_msghdr *rtm;
+ struct ifa_msghdr *ifam;
+ struct sockaddr *sa, *dst, *gw, *ifa, *rti_info[RTAX_MAX];
+
+ *lenp = 0;
+ for (rtm = (struct rt_msghdr *)buf;
+ rtm < (struct rt_msghdr *)lim;
+ rtm = (struct rt_msghdr *)(((char *)rtm) + rtm->rtm_msglen)) {
+ /* just for safety */
+ if (!rtm->rtm_msglen) {
+ errorlog("<%s> rtm_msglen is 0 "
+ "(buf=%p lim=%p rtm=%p)", __func__,
+ buf, lim, rtm);
+ break;
+ }
+ if (FILTER_MATCH(rtm->rtm_type, filter) == 0) {
+ continue;
+ }
+
+ switch (rtm->rtm_type) {
+ case RTM_GET:
+ case RTM_ADD:
+ case RTM_DELETE:
+ /* address related checks */
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ if ((dst = rti_info[RTAX_DST]) == NULL ||
+ dst->sa_family != AF_INET6)
+ continue;
+
+ if (IN6_IS_ADDR_LINKLOCAL(&SIN6(dst)->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&SIN6(dst)->sin6_addr))
+ continue;
+
+ if ((gw = rti_info[RTAX_GATEWAY]) == NULL ||
+ gw->sa_family != AF_LINK)
+ continue;
+ if (ifindex && SDL(gw)->sdl_index != ifindex)
+ continue;
+
+ if (rti_info[RTAX_NETMASK] == NULL)
+ continue;
+
+ /* found */
+ *lenp = rtm->rtm_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ ifam = (struct ifa_msghdr *)rtm;
+
+ /* address related checks */
+ sa = (struct sockaddr *)(ifam + 1);
+ get_rtaddrs(ifam->ifam_addrs, sa, rti_info);
+ if ((ifa = rti_info[RTAX_IFA]) == NULL ||
+ (ifa->sa_family != AF_INET &&
+ ifa->sa_family != AF_INET6))
+ continue;
+
+ if (ifa->sa_family == AF_INET6 &&
+ (IN6_IS_ADDR_LINKLOCAL(&SIN6(ifa)->sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&SIN6(ifa)->sin6_addr)))
+ continue;
+
+ if (ifindex && ifam->ifam_index != ifindex)
+ continue;
+
+ /* found */
+ *lenp = ifam->ifam_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ case RTM_IFINFO:
+ /* found */
+ *lenp = rtm->rtm_msglen;
+ return (char *)rtm;
+ /* NOTREACHED */
+ }
+ }
+
+ return (char *)rtm;
+}
+#undef FILTER_MATCH
+
+struct in6_addr *
+get_addr(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+
+ return(&SIN6(rti_info[RTAX_DST])->sin6_addr);
+}
+
+int
+get_rtm_ifindex(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+
+ return(((struct sockaddr_dl *)rti_info[RTAX_GATEWAY])->sdl_index);
+}
+
+int
+get_ifm_ifindex(char *buf)
+{
+ struct if_msghdr *ifm = (struct if_msghdr *)buf;
+
+ return ((int)ifm->ifm_index);
+}
+
+int
+get_ifam_ifindex(char *buf)
+{
+ struct ifa_msghdr *ifam = (struct ifa_msghdr *)buf;
+
+ return ((int)ifam->ifam_index);
+}
+
+int
+get_ifm_flags(char *buf)
+{
+ struct if_msghdr *ifm = (struct if_msghdr *)buf;
+
+ return (ifm->ifm_flags);
+}
+
+int
+get_prefixlen(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ u_char *p, *lim;
+
+ sa = (struct sockaddr *)(rtm + 1);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ sa = rti_info[RTAX_NETMASK];
+
+ p = (u_char *)(&SIN6(sa)->sin6_addr);
+ lim = (u_char *)sa + sa->sa_len;
+ return prefixlen(p, lim);
+}
+
+int
+prefixlen(u_char *p, u_char *lim)
+{
+ int masklen;
+
+ for (masklen = 0; p < lim; p++) {
+ switch (*p) {
+ case 0xff:
+ masklen += 8;
+ break;
+ case 0xfe:
+ masklen += 7;
+ break;
+ case 0xfc:
+ masklen += 6;
+ break;
+ case 0xf8:
+ masklen += 5;
+ break;
+ case 0xf0:
+ masklen += 4;
+ break;
+ case 0xe0:
+ masklen += 3;
+ break;
+ case 0xc0:
+ masklen += 2;
+ break;
+ case 0x80:
+ masklen += 1;
+ break;
+ case 0x00:
+ break;
+ default:
+ return(-1);
+ }
+ }
+
+ return(masklen);
+}
+
+int
+rtmsg_type(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+
+ return(rtm->rtm_type);
+}
+
+int
+rtmsg_len(char *buf)
+{
+ struct rt_msghdr *rtm = (struct rt_msghdr *)buf;
+
+ return(rtm->rtm_msglen);
+}
+
+int
+ifmsg_len(char *buf)
+{
+ struct if_msghdr *ifm = (struct if_msghdr *)buf;
+
+ return(ifm->ifm_msglen);
+}
+
+/*
+ * alloc buffer and get if_msghdrs block from kernel,
+ * and put them into the buffer
+ */
+static void
+get_iflist(char **buf, size_t *size)
+{
+ int mib[6];
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_INET6;
+ mib[4] = NET_RT_IFLIST;
+ mib[5] = 0;
+
+ if (sysctl(mib, 6, NULL, size, NULL, 0) < 0) {
+ errorlog("<%s> sysctl: iflist size get failed",
+ __func__);
+ exit(1);
+ }
+ if ((*buf = malloc(*size)) == NULL) {
+ errorlog("<%s> malloc failed", __func__);
+ exit(1);
+ }
+ if (sysctl(mib, 6, *buf, size, NULL, 0) < 0) {
+ errorlog("<%s> sysctl: iflist get failed",
+ __func__);
+ exit(1);
+ }
+ return;
+}
+
+struct if_msghdr *
+get_interface_entry(int if_index)
+{
+ struct ifinfo *ifi = NULL;
+ struct if_msghdr *ifm = NULL;
+
+ TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
+ if (if_index == ifi->ifm->ifm_index) {
+ ifm = ifi->ifm;
+ break;
+ }
+ }
+ return ifm;
+}
+
+/*
+ * alloc buffer and parse if_msghdrs block passed as arg,
+ * and init the buffer as list of pointers ot each of the if_msghdr.
+ */
+static void
+parse_iflist(char *buf, size_t bufsize)
+{
+ struct if_msghdr *ifm;
+ struct ifa_msghdr *ifam;
+ char *lim;
+
+ lim = buf + bufsize;
+ for (ifm = (struct if_msghdr *)buf; ifm < (struct if_msghdr *)lim;) {
+ if (ifm->ifm_msglen == 0) {
+ errorlog("<%s> ifm_msglen is 0 "
+ "(buf=%p lim=%p ifm=%p)", __func__,
+ buf, lim, ifm);
+ return;
+ }
+
+ if (ifm->ifm_type == RTM_IFINFO) {
+ struct ifinfo *ifi = NULL;
+
+ if (get_interface_entry(ifm->ifm_index) != NULL) {
+ debuglog("Interface entry is already present for "
+ "interface index: %d. Skipping.", ifm->ifm_index);
+ continue;
+ }
+
+ ELM_MALLOC(ifi, exit(1));
+ ifi->ifm = ifm;
+ TAILQ_INSERT_TAIL(&ifilist, ifi, ifi_next);
+ } else {
+ errorlog("out of sync parsing NET_RT_IFLIST\n"
+ "expected %d, got %d\n msglen = %d\n"
+ "buf:%p, ifm:%p, lim:%p\n",
+ RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen,
+ buf, ifm, lim);
+ exit (1);
+ }
+ for (ifam = (struct ifa_msghdr *)
+ ((char *)ifm + ifm->ifm_msglen);
+ ifam < (struct ifa_msghdr *)lim;
+ ifam = (struct ifa_msghdr *)
+ ((char *)ifam + ifam->ifam_msglen)) {
+ /* just for safety */
+ if (!ifam->ifam_msglen) {
+ errorlog("<%s> ifa_msglen is 0 "
+ "(buf=%p lim=%p ifam=%p)", __func__,
+ buf, lim, ifam);
+ return;
+ }
+ if (ifam->ifam_type != RTM_NEWADDR)
+ break;
+ }
+ ifm = (struct if_msghdr *)ifam;
+ }
+}
+
+static void
+purge_iflist()
+{
+ struct ifinfo *ifi = NULL;
+ if (!TAILQ_EMPTY(&ifilist)) {
+ while ((ifi = TAILQ_FIRST(&ifilist)) != NULL) {
+ TAILQ_REMOVE(&ifilist, ifi, ifi_next);
+ free(ifi);
+ }
+ }
+}
+
+void
+init_iflist()
+{
+ purge_iflist();
+
+ if (ifblock) {
+ free(ifblock);
+ ifblock_size = 0;
+ }
+
+ /* get iflist block from kernel */
+ get_iflist(&ifblock, &ifblock_size);
+
+ /* make list of pointers to each if_msghdr */
+ parse_iflist(ifblock, ifblock_size);
+}
diff --git a/network_cmds/rtadvd.tproj/if.h b/network_cmds/rtadvd.tproj/if.h
new file mode 100644
index 0000000..e733d63
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/if.h
@@ -0,0 +1,64 @@
+/* $KAME: if.h,v 1.10 2003/02/24 11:29:10 ono Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+#define RTADV_TYPE2BITMASK(type) (0x1 << type)
+
+extern size_t ifblock_size;
+extern char *ifblock;
+
+struct nd_opt_hdr;
+struct sockaddr_dl *if_nametosdl(char *);
+int if_getmtu(char *);
+int if_getflags(int, int);
+int lladdropt_length(struct sockaddr_dl *);
+void lladdropt_fill(struct sockaddr_dl *, struct nd_opt_hdr *);
+int rtbuf_len(void);
+char *get_next_msg(char *, char *, int, size_t *, int);
+struct in6_addr *get_addr(char *);
+int get_rtm_ifindex(char *);
+int get_ifm_ifindex(char *);
+int get_ifam_ifindex(char *);
+int get_ifm_flags(char *);
+int get_prefixlen(char *);
+int prefixlen(u_char *, u_char *);
+int rtmsg_type(char *);
+int ifmsg_type(char *);
+int rtmsg_len(char *);
+int ifmsg_len(char *);
+void init_iflist(void);
+
+struct ifinfo {
+ TAILQ_ENTRY(ifinfo) ifi_next;
+ struct if_msghdr * ifm;
+};
+
+struct if_msghdr *get_interface_entry(int if_index);
+
diff --git a/network_cmds/rtadvd.tproj/pathnames.h b/network_cmds/rtadvd.tproj/pathnames.h
new file mode 100644
index 0000000..d288ab9
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/pathnames.h
@@ -0,0 +1,4 @@
+/* $KAME: pathnames.h,v 1.2 2000/05/16 13:34:13 itojun Exp $ */
+/* $FreeBSD: src/usr.sbin/rtadvd/pathnames.h,v 1.2.2.2 2001/07/03 11:02:14 ume Exp $ */
+
+#define _PATH_RTADVDCONF "/etc/rtadvd.conf"
diff --git a/network_cmds/rtadvd.tproj/rrenum.c b/network_cmds/rtadvd.tproj/rrenum.c
new file mode 100644
index 0000000..ae04a55
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rrenum.c
@@ -0,0 +1,484 @@
+/* $KAME: rrenum.c,v 1.12 2002/06/10 19:59:47 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <netinet/in.h>
+#include <netinet/in_var.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rtadvd.h"
+#include "rrenum.h"
+#include "if.h"
+
+#define RR_ISSET_SEGNUM(segnum_bits, segnum) \
+ ((((segnum_bits)[(segnum) >> 5]) & (1 << ((segnum) & 31))) != 0)
+#define RR_SET_SEGNUM(segnum_bits, segnum) \
+ (((segnum_bits)[(segnum) >> 5]) |= (1 << ((segnum) & 31)))
+
+struct rr_operation {
+ u_long rro_seqnum;
+ u_long rro_segnum_bits[8];
+};
+
+static struct rr_operation rro;
+static int rr_rcvifindex;
+static int rrcmd2pco[RPM_PCO_MAX] = {
+ 0,
+ SIOCAIFPREFIX_IN6,
+ SIOCCIFPREFIX_IN6,
+ SIOCSGIFPREFIX_IN6
+};
+static int s = -1;
+
+/*
+ * Check validity of a Prefix Control Operation(PCO).
+ * Return 0 on success, 1 on failure.
+ */
+static int
+rr_pco_check(int len, struct rr_pco_match *rpm)
+{
+ struct rr_pco_use *rpu, *rpulim;
+ int checklen;
+
+ /* rpm->rpm_len must be (4N * 3) as router-renum-05.txt */
+ if ((rpm->rpm_len - 3) < 0 || /* must be at least 3 */
+ (rpm->rpm_len - 3) & 0x3) { /* must be multiple of 4 */
+ errorlog("<%s> rpm_len %d is not 4N * 3",
+ __func__, rpm->rpm_len);
+ return 1;
+ }
+ /* rpm->rpm_code must be valid value */
+ switch (rpm->rpm_code) {
+ case RPM_PCO_ADD:
+ case RPM_PCO_CHANGE:
+ case RPM_PCO_SETGLOBAL:
+ break;
+ default:
+ errorlog("<%s> unknown rpm_code %d", __func__,
+ rpm->rpm_code);
+ return 1;
+ }
+ /* rpm->rpm_matchlen must be 0 to 128 inclusive */
+ if (rpm->rpm_matchlen > 128) {
+ errorlog("<%s> rpm_matchlen %d is over 128",
+ __func__, rpm->rpm_matchlen);
+ return 1;
+ }
+
+ /*
+ * rpu->rpu_uselen, rpu->rpu_keeplen, and sum of them must be
+ * between 0 and 128 inclusive
+ */
+ for (rpu = (struct rr_pco_use *)(rpm + 1),
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+ rpu < rpulim;
+ rpu += 1) {
+ checklen = rpu->rpu_uselen;
+ checklen += rpu->rpu_keeplen;
+ /*
+ * omit these check, because either of rpu_uselen
+ * and rpu_keeplen is unsigned char
+ * (128 > rpu_uselen > 0)
+ * (128 > rpu_keeplen > 0)
+ * (rpu_uselen + rpu_keeplen > 0)
+ */
+ if (checklen > 128) {
+ errorlog("<%s> sum of rpu_uselen %d and"
+ " rpu_keeplen %d is %d(over 128)",
+ __func__, rpu->rpu_uselen,
+ rpu->rpu_keeplen,
+ rpu->rpu_uselen + rpu->rpu_keeplen);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+do_use_prefix(int len, struct rr_pco_match *rpm,
+ struct in6_rrenumreq *irr, int ifindex)
+{
+ struct rr_pco_use *rpu, *rpulim;
+ struct rainfo *rai;
+ struct prefix *pp;
+
+ rpu = (struct rr_pco_use *)(rpm + 1);
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+
+ if (rpu == rpulim) { /* no use prefix */
+ if (rpm->rpm_code == RPM_PCO_ADD)
+ return;
+
+ irr->irr_u_uselen = 0;
+ irr->irr_u_keeplen = 0;
+ irr->irr_raf_mask_onlink = 0;
+ irr->irr_raf_mask_auto = 0;
+ irr->irr_vltime = 0;
+ irr->irr_pltime = 0;
+ memset(&irr->irr_flags, 0, sizeof(irr->irr_flags));
+ irr->irr_useprefix.sin6_len = 0; /* let it mean, no addition */
+ irr->irr_useprefix.sin6_family = 0;
+ irr->irr_useprefix.sin6_addr = in6addr_any;
+ if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
+ errno != EADDRNOTAVAIL)
+ errorlog("<%s> ioctl: %s", __func__,
+ strerror(errno));
+ return;
+ }
+
+ for (rpu = (struct rr_pco_use *)(rpm + 1),
+ rpulim = (struct rr_pco_use *)((char *)rpm + len);
+ rpu < rpulim;
+ rpu += 1) {
+ /* init in6_rrenumreq fields */
+ irr->irr_u_uselen = rpu->rpu_uselen;
+ irr->irr_u_keeplen = rpu->rpu_keeplen;
+ irr->irr_raf_mask_onlink =
+ !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK);
+ irr->irr_raf_mask_auto =
+ !!(rpu->rpu_ramask & ICMP6_RR_PCOUSE_RAFLAGS_AUTO);
+ irr->irr_vltime = ntohl(rpu->rpu_vltime);
+ irr->irr_pltime = ntohl(rpu->rpu_pltime);
+ irr->irr_raf_onlink =
+ (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_ONLINK) == 0 ? 0 : 1;
+ irr->irr_raf_auto =
+ (rpu->rpu_raflags & ICMP6_RR_PCOUSE_RAFLAGS_AUTO) == 0 ? 0 : 1;
+ irr->irr_rrf_decrvalid =
+ (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME) == 0 ? 0 : 1;
+ irr->irr_rrf_decrprefd =
+ (rpu->rpu_flags & ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME) == 0 ? 0 : 1;
+ irr->irr_useprefix.sin6_len = sizeof(irr->irr_useprefix);
+ irr->irr_useprefix.sin6_family = AF_INET6;
+ irr->irr_useprefix.sin6_addr = rpu->rpu_prefix;
+
+ if (ioctl(s, rrcmd2pco[rpm->rpm_code], (caddr_t)irr) < 0 &&
+ errno != EADDRNOTAVAIL)
+ errorlog("<%s> ioctl: %s", __func__,
+ strerror(errno));
+
+ /* very adhoc: should be rewritten */
+ if (rpm->rpm_code == RPM_PCO_CHANGE &&
+ IN6_ARE_ADDR_EQUAL(&rpm->rpm_prefix, &rpu->rpu_prefix) &&
+ rpm->rpm_matchlen == rpu->rpu_uselen &&
+ rpu->rpu_uselen == rpu->rpu_keeplen) {
+ if ((rai = if_indextorainfo(ifindex)) == NULL)
+ continue; /* non-advertising IF */
+
+ for (pp = rai->prefix.next; pp != &rai->prefix;
+ pp = pp->next) {
+ struct timeval now;
+
+ if (prefix_match(&pp->prefix, pp->prefixlen,
+ &rpm->rpm_prefix,
+ rpm->rpm_matchlen)) {
+ /* change parameters */
+ pp->validlifetime = ntohl(rpu->rpu_vltime);
+ pp->preflifetime = ntohl(rpu->rpu_pltime);
+ if (irr->irr_rrf_decrvalid) {
+ gettimeofday(&now, 0);
+ pp->vltimeexpire =
+ now.tv_sec + pp->validlifetime;
+ } else
+ pp->vltimeexpire = 0;
+ if (irr->irr_rrf_decrprefd) {
+ gettimeofday(&now, 0);
+ pp->pltimeexpire =
+ now.tv_sec + pp->preflifetime;
+ } else
+ pp->pltimeexpire = 0;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * process a Prefix Control Operation(PCO).
+ * return 0 on success, 1 on failure
+ */
+static int
+do_pco(struct icmp6_router_renum *rr, int len, struct rr_pco_match *rpm)
+{
+ int ifindex = 0;
+ struct in6_rrenumreq irr;
+
+ if ((rr_pco_check(len, rpm) != 0))
+ return 1;
+
+ if (s == -1 && (s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ exit(1);
+ }
+
+ memset(&irr, 0, sizeof(irr));
+ irr.irr_origin = PR_ORIG_RR;
+ irr.irr_m_len = rpm->rpm_matchlen;
+ irr.irr_m_minlen = rpm->rpm_minlen;
+ irr.irr_m_maxlen = rpm->rpm_maxlen;
+ irr.irr_matchprefix.sin6_len = sizeof(irr.irr_matchprefix);
+ irr.irr_matchprefix.sin6_family = AF_INET6;
+ irr.irr_matchprefix.sin6_addr = rpm->rpm_prefix;
+
+ while (if_indextoname(++ifindex, irr.irr_name)) {
+ struct if_msghdr * ifm = get_interface_entry(ifindex);
+ if (ifm == NULL) {
+ debuglog("Couldn't find interface entry for %d. Skipping.", ifindex);
+ continue;
+ }
+ /*
+ * if ICMP6_RR_FLAGS_FORCEAPPLY(A flag) is 0 and IFF_UP is off,
+ * the interface is not applied
+ */
+ if ((rr->rr_flags & ICMP6_RR_FLAGS_FORCEAPPLY) == 0 &&
+ (ifm->ifm_flags & IFF_UP) == 0)
+ continue;
+ /* TODO: interface scope check */
+ do_use_prefix(len, rpm, &irr, ifindex);
+ }
+ if (errno == ENXIO)
+ return 0;
+ else if (errno) {
+ errorlog("<%s> if_indextoname: %s", __func__,
+ strerror(errno));
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * call do_pco() for each Prefix Control Operations(PCOs) in a received
+ * Router Renumbering Command packet.
+ * return 0 on success, 1 on failure
+ */
+static int
+do_rr(int len, struct icmp6_router_renum *rr)
+{
+ struct rr_pco_match *rpm;
+ char *cp, *lim;
+
+ lim = (char *)rr + len;
+ cp = (char *)(rr + 1);
+ len -= sizeof(struct icmp6_router_renum);
+
+ /* get iflist block from kernel again, to get up-to-date information */
+ init_iflist();
+
+ while (cp < lim) {
+ int rpmlen;
+
+ rpm = (struct rr_pco_match *)cp;
+ if (len < sizeof(struct rr_pco_match)) {
+ tooshort:
+ errorlog("<%s> pkt too short. left len = %d. "
+ "gabage at end of pkt?", __func__, len);
+ return 1;
+ }
+ rpmlen = rpm->rpm_len << 3;
+ if (len < rpmlen)
+ goto tooshort;
+
+ if (do_pco(rr, rpmlen, rpm)) {
+ errorlog("<%s> invalid PCO", __func__);
+ goto next;
+ }
+
+ next:
+ cp += rpmlen;
+ len -= rpmlen;
+ }
+
+ return 0;
+}
+
+/*
+ * check validity of a router renumbering command packet
+ * return 0 on success, 1 on failure
+ */
+static int
+rr_command_check(int len, struct icmp6_router_renum *rr, struct in6_addr *from,
+ struct in6_addr *dst)
+{
+ char ntopbuf[INET6_ADDRSTRLEN];
+
+ /* omit rr minimal length check. hope kernel have done it. */
+ /* rr_command length check */
+ if (len < (sizeof(struct icmp6_router_renum) +
+ sizeof(struct rr_pco_match))) {
+ errorlog("<%s> rr_command len %d is too short",
+ __func__, len);
+ return 1;
+ }
+
+ /* destination check. only for multicast. omit unicast check. */
+ if (IN6_IS_ADDR_MULTICAST(dst) && !IN6_IS_ADDR_MC_LINKLOCAL(dst) &&
+ !IN6_IS_ADDR_MC_SITELOCAL(dst)) {
+ errorlog("<%s> dst mcast addr %s is illegal",
+ __func__,
+ inet_ntop(AF_INET6, dst, ntopbuf, INET6_ADDRSTRLEN));
+ return 1;
+ }
+
+ /* seqnum and segnum check */
+ if (rro.rro_seqnum > rr->rr_seqnum) {
+ errorlog("<%s> rcvd old seqnum %d from %s",
+ __func__, (u_int32_t)ntohl(rr->rr_seqnum),
+ inet_ntop(AF_INET6, from, ntopbuf, INET6_ADDRSTRLEN));
+ return 1;
+ }
+ if (rro.rro_seqnum == rr->rr_seqnum &&
+ (rr->rr_flags & ICMP6_RR_FLAGS_TEST) == 0 &&
+ RR_ISSET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum)) {
+ if ((rr->rr_flags & ICMP6_RR_FLAGS_REQRESULT) != 0)
+ errorlog("<%s> rcvd duped segnum %d from %s",
+ __func__, rr->rr_segnum,
+ inet_ntop(AF_INET6, from, ntopbuf,
+ INET6_ADDRSTRLEN));
+ return 0;
+ }
+
+ /* update seqnum */
+ if (rro.rro_seqnum != rr->rr_seqnum) {
+ /* then must be "<" */
+
+ /* init rro_segnum_bits */
+ memset(rro.rro_segnum_bits, 0,
+ sizeof(rro.rro_segnum_bits));
+ }
+ rro.rro_seqnum = rr->rr_seqnum;
+
+ return 0;
+}
+
+static void
+rr_command_input(int len, struct icmp6_router_renum *rr,
+ struct in6_addr *from, struct in6_addr *dst)
+{
+ /* rr_command validity check */
+ if (rr_command_check(len, rr, from, dst))
+ goto failed;
+ if ((rr->rr_flags & (ICMP6_RR_FLAGS_TEST|ICMP6_RR_FLAGS_REQRESULT)) ==
+ ICMP6_RR_FLAGS_TEST)
+ return;
+
+ /* do router renumbering */
+ if (do_rr(len, rr)) {
+ goto failed;
+ }
+
+ /* update segnum */
+ RR_SET_SEGNUM(rro.rro_segnum_bits, rr->rr_segnum);
+
+ return;
+
+ failed:
+ errorlog("<%s> received RR was invalid", __func__);
+ return;
+}
+
+void
+rr_input(int len, struct icmp6_router_renum *rr, struct in6_pktinfo *pi,
+ struct sockaddr_in6 *from, struct in6_addr *dst)
+{
+ char ntopbuf[2][INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+
+ debuglog("<%s> RR received from %s to %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf[0], INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ /* packet validation based on Section 4.1 of RFC2894 */
+ if (len < sizeof(struct icmp6_router_renum)) {
+ noticelog("<%s>: RR short message (size %d) from %s to %s on %s",
+ __func__, len,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf[0], INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &dst, ntopbuf[1], INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ /*
+ * If the IPv6 destination address is neither an All Routers multicast
+ * address [AARCH] nor one of the receiving router's unicast addresses,
+ * the message MUST be discarded and SHOULD be logged to network
+ * management.
+ * We rely on the kernel input routine for unicast addresses, and thus
+ * check multicast destinations only.
+ */
+ if (IN6_IS_ADDR_MULTICAST(&pi->ipi6_addr) &&
+ !IN6_ARE_ADDR_EQUAL(&in6a_site_allrouters, &pi->ipi6_addr)) {
+ noticelog("<%s>: RR message with invalid destination (%s) "
+ "from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &dst, ntopbuf[0], INET6_ADDRSTRLEN),
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf[1], INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ rr_rcvifindex = pi->ipi6_ifindex;
+
+ switch (rr->rr_code) {
+ case ICMP6_ROUTER_RENUMBERING_COMMAND:
+ rr_command_input(len, rr, &from->sin6_addr, dst);
+ /* TODO: send reply msg */
+ break;
+ case ICMP6_ROUTER_RENUMBERING_RESULT:
+ /* RESULT will be processed by rrenumd */
+ break;
+ case ICMP6_ROUTER_RENUMBERING_SEQNUM_RESET:
+ /* TODO: sequence number reset */
+ break;
+ default:
+ errorlog("<%s> received unknown code %d",
+ __func__, rr->rr_code);
+ break;
+
+ }
+
+ return;
+}
diff --git a/network_cmds/rtadvd.tproj/rrenum.h b/network_cmds/rtadvd.tproj/rrenum.h
new file mode 100644
index 0000000..b6ed486
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rrenum.h
@@ -0,0 +1,33 @@
+/* $KAME: rrenum.h,v 1.3 2001/01/21 15:37:14 itojun Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+void rr_input(int, struct icmp6_router_renum *, struct in6_pktinfo *,
+ struct sockaddr_in6 *, struct in6_addr *);
diff --git a/network_cmds/rtadvd.tproj/rtadvd.8 b/network_cmds/rtadvd.tproj/rtadvd.8
new file mode 100644
index 0000000..27429de
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.8
@@ -0,0 +1,207 @@
+.\" $FreeBSD: src/usr.sbin/rtadvd/rtadvd.8,v 1.3.2.6 2001/08/16 15:56:30 ru Exp $
+.\" $KAME: rtadvd.8,v 1.24 2002/05/31 16:16:08 jinmei Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" 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 project 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 PROJECT 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 PROJECT 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 August 27, 2011
+.Dt RTADVD 8
+.Os
+.Sh NAME
+.Nm rtadvd
+.Nd router advertisement daemon
+.Sh SYNOPSIS
+.Nm
+.Op Fl dDfMRs
+.Op Fl c Ar configfile
+.Op Fl F Ar dumpfile
+.Op Fl p Ar pidfile
+.Ar interface ...
+.Sh DESCRIPTION
+.Nm
+sends router advertisement packets to the specified
+.Ar interfaces .
+.Pp
+The program will daemonize itself on invocation.
+It will then send router advertisement packets periodically, as well
+as in response to router solicitation messages sent by end hosts.
+.Pp
+Router advertisements can be configured on a per-interface basis, as
+described in
+.Xr rtadvd.conf 5 .
+.Pp
+If there is no configuration file entry for an interface,
+or if the configuration file does not exist altogether,
+.Nm
+sets all the parameters to their default values.
+In particular,
+.Nm
+reads all the interface routes from the routing table and advertises
+them as on-link prefixes.
+.Pp
+.Nm
+also watches the routing table.
+If an interface direct route is
+added on an advertising interface and no static prefixes are
+specified by the configuration file,
+.Nm
+adds the corresponding prefix to its advertising list.
+.Pp
+Similarly, when an interface direct route is deleted,
+.Nm
+will start advertising the prefixes with zero valid and preferred
+lifetimes to help the receiving hosts switch to a new prefix when
+renumbering.
+Note, however, that the zero valid lifetime cannot invalidate the
+autoconfigured addresses at a receiving host immediately.
+According to the specification, the host will retain the address
+for a certain period, which will typically be two hours.
+The zero lifetimes rather intend to make the address deprecated,
+indicating that a new non-deprecated address should be used as the
+source address of a new connection.
+This behavior will last for two hours.
+Then
+.Nm
+will completely remove the prefix from the advertising list,
+and succeeding advertisements will not contain the prefix information.
+.Pp
+Moreover, if the status of an advertising interface changes,
+.Nm
+will start or stop sending router advertisements according
+to the latest status.
+.Pp
+The
+.Fl s
+option may be used to disable this behavior;
+.Nm
+will not watch the routing table and the whole functionality described
+above will be suppressed.
+.Pp
+Basically, hosts MUST NOT send Router Advertisement messages at any
+time (RFC 2461, Section 6.2.3).
+However, it would sometimes be useful to allow hosts to advertise some
+parameters such as prefix information and link MTU.
+Thus,
+.Nm
+can be invoked if router lifetime is explicitly set zero on every
+advertising interface.
+.Pp
+The command line options are:
+.Bl -tag -width indent
+.\"
+.It Fl c
+Specify an alternate location,
+.Ar configfile ,
+for the configuration file.
+By default,
+.Pa /etc/rtadvd.conf
+is used.
+.It Fl d
+Print debugging information.
+.It Fl D
+Even more debugging information is printed.
+.It Fl f
+This option is now deprecated and ignored.
+.It Fl F
+Specify an alternative file in which to dump internal states when
+.Nm
+receives signal
+.Dv SIGUSR1 .
+The default is
+.Pa /var/run/rtadvd.dump .
+.It Fl M
+Specify an interface to join the all-routers site-local multicast group.
+By default,
+.Nm
+tries to join the first advertising interface appearing on the command
+line.
+This option has meaning only with the
+.Fl R
+option, which enables routing renumbering protocol support.
+.It Fl p
+Specify an alternative file in which to store the process ID.
+The default is
+.Pa /var/run/rtadvd.pid.
+.It Fl R
+Accept router renumbering requests.
+If you enable it, certain IPsec setup is suggested for security reasons.
+This option is currently disabled, and is ignored by
+.Nm
+with a warning message.
+.It Fl s
+Do not add or delete prefixes dynamically.
+Only statically configured prefixes, if any, will be advertised.
+.El
+.Pp
+Upon receipt of signal
+.Dv SIGUSR1 ,
+.Nm
+will dump the current internal state into
+.Pa /var/run/rtadvd.dump
+or the file specified with option
+.Fl F .
+.Pp
+Use
+.Dv SIGTERM
+to kill
+.Nm
+gracefully.
+In this case,
+.Nm
+will transmit router advertisement with router lifetime 0
+to all the interfaces
+.Pq in accordance with RFC2461 6.2.5 .
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /etc/rtadvd.conf
+The default configuration file.
+.It Pa /var/run/rtadvd.pid
+The default process ID file.
+.It Pa /var/run/rtadvd.dump
+The default file in which
+.Nm
+dumps its internal state.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr rtadvd.conf 5 ,
+.Xr rtsol 8
+.Sh HISTORY
+The
+.Nm
+command first appeared in the WIDE Hydrangea IPv6 protocol stack kit.
+.Sh BUGS
+There used to be some text that recommended users not to let
+.Nm
+advertise Router Advertisement messages on an upstream link to avoid
+undesirable
+.Xr icmp6 4
+redirect messages.
+However, based on the later discussion in the IETF ipng working group,
+all routers should rather advertise the messages regardless of
+the network topology, in order to ensure reachability.
diff --git a/network_cmds/rtadvd.tproj/rtadvd.c b/network_cmds/rtadvd.tproj/rtadvd.c
new file mode 100644
index 0000000..be5c0f8
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.c
@@ -0,0 +1,1650 @@
+/*
+ * Copyright (c) 2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: rtadvd.c,v 1.82 2003/08/05 12:34:23 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <err.h>
+#include <errno.h>
+#include <libutil.h>
+#include <string.h>
+#include <stdlib.h>
+#include "rtadvd.h"
+#include "rrenum.h"
+#include "advcap.h"
+#include "timer.h"
+#include "if.h"
+#include "config.h"
+#include "dump.h"
+
+struct msghdr rcvmhdr;
+static u_char *rcvcmsgbuf;
+static size_t rcvcmsgbuflen;
+static u_char *sndcmsgbuf = NULL;
+static size_t sndcmsgbuflen;
+volatile sig_atomic_t do_dump;
+volatile sig_atomic_t do_die;
+struct msghdr sndmhdr;
+struct iovec rcviov[2];
+struct iovec sndiov[2];
+struct sockaddr_in6 rcvfrom;
+struct sockaddr_in6 sin6_allnodes = {sizeof(sin6_allnodes), AF_INET6};
+struct in6_addr in6a_site_allrouters;
+static char *dumpfilename = "/var/run/rtadvd.dump";
+static char *pidfilename = "/var/run/rtadvd.pid";
+static struct pidfh *pfh;
+static char *mcastif;
+int sock;
+int rtsock = -1;
+int accept_rr = 0;
+int dflag = 0, sflag = 0;
+int so_traffic_class = SO_TC_CTL; /* use control class, by default */
+char *conffile = NULL;
+
+struct rainfo *ralist = NULL;
+
+struct nd_optlist {
+ struct nd_optlist *next;
+ struct nd_opt_hdr *opt;
+};
+union nd_opts {
+ struct nd_opt_hdr *nd_opt_array[9];
+ struct {
+ struct nd_opt_hdr *zero;
+ struct nd_opt_hdr *src_lladdr;
+ struct nd_opt_hdr *tgt_lladdr;
+ struct nd_opt_prefix_info *pi;
+ struct nd_opt_rd_hdr *rh;
+ struct nd_opt_mtu *mtu;
+ struct nd_optlist *list;
+ } nd_opt_each;
+};
+#define nd_opts_src_lladdr nd_opt_each.src_lladdr
+#define nd_opts_tgt_lladdr nd_opt_each.tgt_lladdr
+#define nd_opts_pi nd_opt_each.pi
+#define nd_opts_rh nd_opt_each.rh
+#define nd_opts_mtu nd_opt_each.mtu
+#define nd_opts_list nd_opt_each.list
+
+#define NDOPT_FLAG_SRCLINKADDR 0x1
+#define NDOPT_FLAG_TGTLINKADDR 0x2
+#define NDOPT_FLAG_PREFIXINFO 0x4
+#define NDOPT_FLAG_RDHDR 0x8
+#define NDOPT_FLAG_MTU 0x10
+
+u_int32_t ndopt_flags[] = {
+ 0, NDOPT_FLAG_SRCLINKADDR, NDOPT_FLAG_TGTLINKADDR,
+ NDOPT_FLAG_PREFIXINFO, NDOPT_FLAG_RDHDR, NDOPT_FLAG_MTU,
+};
+
+int main(int, char *[]);
+static void set_die(int);
+static void die(void);
+static void sock_open(void);
+static void rtsock_open(void);
+static void rtadvd_input(void);
+static void rs_input(int, struct nd_router_solicit *,
+ struct in6_pktinfo *, struct sockaddr_in6 *);
+static void ra_input(int, struct nd_router_advert *,
+ struct in6_pktinfo *, struct sockaddr_in6 *);
+static int prefix_check(struct nd_opt_prefix_info *, struct rainfo *,
+ struct sockaddr_in6 *);
+static int nd6_options(struct nd_opt_hdr *, int,
+ union nd_opts *, u_int32_t);
+static void free_ndopts(union nd_opts *);
+static void ra_output(struct rainfo *);
+static void rtmsg_input(void);
+static void rtadvd_set_dump_file(int);
+static void set_short_delay(struct rainfo *);
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ fd_set *fdsetp, *selectfdp;
+ int fdmasks;
+ int maxfd = 0;
+ struct timeval *timeout;
+ int i, ch;
+ int fflag = 0;
+ pid_t pid, otherpid;
+
+ /* get command line options and arguments */
+ while ((ch = getopt(argc, argv, "c:dDF:fMp:Rs")) != -1) {
+ switch (ch) {
+ case 'c':
+ conffile = optarg;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'D':
+ dflag = 2;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'M':
+ mcastif = optarg;
+ break;
+ case 'R':
+ fprintf(stderr, "rtadvd: "
+ "the -R option is currently ignored.\n");
+ /* accept_rr = 1; */
+ /* run anyway... */
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'p':
+ pidfilename = optarg;
+ break;
+ case 'F':
+ dumpfilename = optarg;
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc == 0) {
+ fprintf(stderr,
+ "usage: rtadvd [-dDfMRs] [-c conffile] "
+ "[-F dumpfile] [-p pidfile] interfaces...\n");
+ exit(1);
+ }
+
+ /* timer initialization */
+ rtadvd_timer_init();
+
+ /* random value initialization */
+ srandom((u_long)time(NULL));
+
+ /* get iflist block from kernel */
+ init_iflist();
+
+ while (argc--)
+ getconfig(*argv++);
+
+ if (inet_pton(AF_INET6, ALLNODES, &sin6_allnodes.sin6_addr) != 1) {
+ fprintf(stderr, "fatal: inet_pton failed\n");
+ exit(1);
+ }
+
+ pfh = pidfile_open(pidfilename, 0600, &otherpid);
+ if (pfh == NULL) {
+ if (errno == EEXIST)
+ errx(1, "%s already running, pid: %d",
+ getprogname(), otherpid);
+ errorlog("<%s> failed to open the pid log file, run anyway.",
+ __func__);
+ }
+
+ if (!fflag)
+ daemon(1, 0);
+
+ sock_open();
+
+ /* record the current PID */
+ pid = getpid();
+ pidfile_write(pfh);
+
+ maxfd = sock;
+ if (sflag == 0) {
+ rtsock_open();
+ if (rtsock > sock)
+ maxfd = rtsock;
+ } else
+ rtsock = -1;
+
+ fdmasks = howmany(maxfd + 1, NFDBITS) * sizeof(fd_mask);
+ if ((fdsetp = malloc(fdmasks)) == NULL) {
+ err(1, "malloc");
+ /*NOTREACHED*/
+ }
+ if ((selectfdp = malloc(fdmasks)) == NULL) {
+ err(1, "malloc");
+ /*NOTREACHED*/
+ }
+ memset(fdsetp, 0, fdmasks);
+ FD_SET(sock, fdsetp);
+ if (rtsock >= 0)
+ FD_SET(rtsock, fdsetp);
+
+ signal(SIGTERM, set_die);
+ signal(SIGUSR1, rtadvd_set_dump_file);
+
+ while (1) {
+ memcpy(selectfdp, fdsetp, fdmasks); /* reinitialize */
+
+ if (do_dump) { /* SIGUSR1 */
+ do_dump = 0;
+ rtadvd_dump_file(dumpfilename);
+ }
+
+ if (do_die) {
+ die();
+ /*NOTREACHED*/
+ }
+
+ /* timer expiration check and reset the timer */
+ timeout = rtadvd_check_timer();
+
+ if (timeout != NULL) {
+ debuglog("<%s> set timer to %ld:%ld. waiting for "
+ "inputs or timeout", __func__,
+ (long int)timeout->tv_sec,
+ (long int)timeout->tv_usec);
+ } else {
+ debuglog("<%s> there's no timer. waiting for inputs",
+ __func__);
+ }
+
+ if ((i = select(maxfd + 1, selectfdp, NULL, NULL,
+ timeout)) < 0) {
+ /* EINTR would occur upon SIGUSR1 for status dump */
+ if (errno != EINTR)
+ errorlog( "<%s> select: %s",
+ __func__, strerror(errno));
+ continue;
+ }
+ if (i == 0) /* timeout */
+ continue;
+ if (rtsock != -1 && FD_ISSET(rtsock, selectfdp))
+ rtmsg_input();
+ if (FD_ISSET(sock, selectfdp))
+ rtadvd_input();
+ }
+ exit(0); /* NOTREACHED */
+}
+
+static void
+rtadvd_set_dump_file(sig)
+ int sig;
+{
+ do_dump = 1;
+}
+
+static void
+set_die(sig)
+ int sig;
+{
+ do_die = 1;
+}
+
+static void
+die()
+{
+ struct rainfo *ra;
+ int i;
+ const int retrans = MAX_FINAL_RTR_ADVERTISEMENTS;
+
+ if (dflag > 1) {
+ debuglog("<%s> cease to be an advertising router\n",
+ __func__);
+ }
+
+ for (ra = ralist; ra; ra = ra->next) {
+ ra->lifetime = 0;
+ make_packet(ra);
+ }
+ for (i = 0; i < retrans; i++) {
+ for (ra = ralist; ra; ra = ra->next)
+ ra_output(ra);
+
+ if (retrans != 1)
+ sleep(MIN_DELAY_BETWEEN_RAS);
+ }
+ pidfile_remove(pfh);
+ exit(0);
+ /*NOTREACHED*/
+}
+
+static void
+rtmsg_input()
+{
+ int n, type, ifindex = 0, plen;
+ size_t len;
+ char msg[2048], *next, *lim;
+ char ifname[IF_NAMESIZE];
+ struct prefix *prefix;
+ struct rainfo *rai;
+ struct in6_addr *addr;
+ char addrbuf[INET6_ADDRSTRLEN];
+ int prefixchange = 0;
+
+ n = read(rtsock, msg, sizeof(msg));
+ if (dflag > 1) {
+ debuglog( "<%s> received a routing message "
+ "(type = %d, len = %d)", __func__, rtmsg_type(msg), n);
+ }
+ if (n > rtmsg_len(msg)) {
+ /*
+ * This usually won't happen for messages received on
+ * a routing socket.
+ */
+ if (dflag > 1)
+ debuglog("<%s> received data length is larger than "
+ "1st routing message len. multiple messages? "
+ "read %d bytes, but 1st msg len = %d",
+ __func__, n, rtmsg_len(msg));
+#if 0
+ /* adjust length */
+ n = rtmsg_len(msg);
+#endif
+ }
+
+ lim = msg + n;
+ for (next = msg; next < lim; next += len) {
+ struct if_msghdr * ifm = NULL;
+ int oldifflags;
+
+ next = get_next_msg(next, lim, 0, &len,
+ RTADV_TYPE2BITMASK(RTM_ADD) |
+ RTADV_TYPE2BITMASK(RTM_DELETE) |
+ RTADV_TYPE2BITMASK(RTM_NEWADDR) |
+ RTADV_TYPE2BITMASK(RTM_DELADDR) |
+ RTADV_TYPE2BITMASK(RTM_IFINFO));
+ if (len == 0)
+ break;
+ type = rtmsg_type(next);
+ switch (type) {
+ case RTM_ADD:
+ case RTM_DELETE:
+ ifindex = get_rtm_ifindex(next);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ ifindex = get_ifam_ifindex(next);
+ break;
+ case RTM_IFINFO:
+ ifindex = get_ifm_ifindex(next);
+ break;
+ default:
+ /* should not reach here */
+ if (dflag > 1) {
+ debuglog("<%s:%d> unknown rtmsg %d on %s",
+ __func__, __LINE__, type,
+ if_indextoname(ifindex, ifname));
+ }
+ continue;
+ }
+
+ if ((rai = if_indextorainfo(ifindex)) == NULL) {
+ if (dflag > 1) {
+ debuglog("<%s> route changed on "
+ "non advertising interface(%s)",
+ __func__,
+ if_indextoname(ifindex, ifname));
+ }
+ continue;
+ }
+ ifm = get_interface_entry(ifindex);
+ if (ifm == NULL) {
+ debuglog("Couldn't find interface entry for %d. Skipping.", ifindex);
+ continue;
+ }
+ oldifflags = ifm->ifm_flags;
+
+ switch (type) {
+ case RTM_ADD:
+ /* init ifflags because it may have changed */
+ ifm->ifm_flags =
+ if_getflags(ifindex, ifm->ifm_flags);
+
+ if (sflag)
+ break; /* we aren't interested in prefixes */
+
+ addr = get_addr(msg);
+ plen = get_prefixlen(msg);
+ /* sanity check for plen */
+ /* as RFC2373, prefixlen is at least 4 */
+ if (plen < 4 || plen > 127) {
+ infolog("<%s> new interface route's"
+ "plen %d is invalid for a prefix",
+ __func__, plen);
+ break;
+ }
+ prefix = find_prefix(rai, addr, plen);
+ if (prefix) {
+ if (prefix->timer) {
+ /*
+ * If the prefix has been invalidated,
+ * make it available again.
+ */
+ update_prefix(prefix);
+ prefixchange = 1;
+ } else if (dflag > 1) {
+ debuglog("<%s> new prefix(%s/%d) "
+ "added on %s, "
+ "but it was already in list",
+ __func__,
+ inet_ntop(AF_INET6, addr,
+ (char *)addrbuf, INET6_ADDRSTRLEN),
+ plen, rai->ifname);
+ }
+ break;
+ }
+ make_prefix(rai, ifindex, addr, plen);
+ prefixchange = 1;
+ break;
+ case RTM_DELETE:
+ /* init ifflags because it may have changed */
+ ifm->ifm_flags = if_getflags(ifindex, ifm->ifm_flags);
+
+ if (sflag)
+ break;
+
+ addr = get_addr(msg);
+ plen = get_prefixlen(msg);
+ /* sanity check for plen */
+ /* as RFC2373, prefixlen is at least 4 */
+ if (plen < 4 || plen > 127) {
+ infolog("<%s> deleted interface route's "
+ "plen %d is invalid for a prefix",
+ __func__, plen);
+ break;
+ }
+ prefix = find_prefix(rai, addr, plen);
+ if (prefix == NULL) {
+ if (dflag > 1) {
+ debuglog("<%s> prefix(%s/%d) was "
+ "deleted on %s, "
+ "but it was not in list",
+ __func__,
+ inet_ntop(AF_INET6, addr,
+ (char *)addrbuf, INET6_ADDRSTRLEN),
+ plen, rai->ifname);
+ }
+ break;
+ }
+ invalidate_prefix(prefix);
+ prefixchange = 1;
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ /* init ifflags because it may have changed */
+ ifm->ifm_flags = if_getflags(ifindex, ifm->ifm_flags);
+ break;
+ case RTM_IFINFO:
+ ifm->ifm_flags = get_ifm_flags(next);
+ break;
+ default:
+ /* should not reach here */
+ if (dflag > 1) {
+ debuglog("<%s:%d> unknown rtmsg %d on %s",
+ __func__, __LINE__, type,
+ if_indextoname(ifindex, ifname));
+ }
+ return;
+ }
+
+ /* check if an interface flag is changed */
+ if ((oldifflags & IFF_UP) && /* UP to DOWN */
+ !(ifm->ifm_flags & IFF_UP)) {
+ infolog("<%s> interface %s becomes down. stop timer.",
+ __func__, rai->ifname);
+ rtadvd_remove_timer(&rai->timer);
+ } else if (!(oldifflags & IFF_UP) && /* DOWN to UP */
+ (ifm->ifm_flags & IFF_UP)) {
+ infolog("<%s> interface %s becomes up. restart timer.",
+ __func__, rai->ifname);
+
+ rai->initcounter = 0; /* reset the counter */
+ rai->waiting = 0; /* XXX */
+ rai->timer = rtadvd_add_timer(ra_timeout,
+ ra_timer_update, rai, rai);
+ ra_timer_update((void *)rai, &rai->timer->tm);
+ rtadvd_set_timer(&rai->timer->tm, rai->timer);
+ } else if (prefixchange &&
+ (ifm->ifm_flags & IFF_UP)) {
+ /*
+ * An advertised prefix has been added or invalidated.
+ * Will notice the change in a short delay.
+ */
+ rai->initcounter = 0;
+ set_short_delay(rai);
+ }
+ }
+
+ return;
+}
+
+void
+rtadvd_input()
+{
+ int i;
+ int *hlimp = NULL;
+#ifdef OLDRAWSOCKET
+ struct ip6_hdr *ip;
+#endif
+ struct icmp6_hdr *icp;
+ int ifindex = 0;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi = NULL;
+ char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ struct in6_addr dst = in6addr_any;
+ struct if_msghdr *ifm = NULL;
+
+ /*
+ * Get message. We reset msg_controllen since the field could
+ * be modified if we had received a message before setting
+ * receive options.
+ */
+ rcvmhdr.msg_controllen = rcvcmsgbuflen;
+ if ((i = recvmsg(sock, &rcvmhdr, 0)) < 0)
+ return;
+
+ /* extract optional information via Advanced API */
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
+ cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
+ pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
+ ifindex = pi->ipi6_ifindex;
+ dst = pi->ipi6_addr;
+ }
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ hlimp = (int *)CMSG_DATA(cm);
+ }
+ if (ifindex == 0) {
+ errorlog("<%s> failed to get receiving interface",
+ __func__);
+ return;
+ }
+ if (hlimp == NULL) {
+ errorlog("<%s> failed to get receiving hop limit",
+ __func__);
+ return;
+ }
+
+ ifm = get_interface_entry(pi->ipi6_ifindex);
+ /*
+ * If we happen to receive data on an interface which is now gone
+ * or down, just discard the data.
+ */
+ if (ifm == NULL ||
+ (ifm->ifm_flags & IFF_UP) == 0) {
+ infolog("<%s> received data on a disabled interface (%s)",
+ __func__,
+ (ifm == NULL) ? "[gone]" :
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+#ifdef OLDRAWSOCKET
+ if (i < sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr)) {
+ errorlog("<%s> packet size(%d) is too short",
+ __func__, i);
+ return;
+ }
+
+ ip = (struct ip6_hdr *)rcvmhdr.msg_iov[0].iov_base;
+ icp = (struct icmp6_hdr *)(ip + 1); /* XXX: ext. hdr? */
+#else
+ if (i < sizeof(struct icmp6_hdr)) {
+ errorlog("<%s> packet size(%d) is too short",
+ __func__, i);
+ return;
+ }
+
+ icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
+#endif
+
+ switch (icp->icmp6_type) {
+ case ND_ROUTER_SOLICIT:
+ /*
+ * Message verification - RFC-2461 6.1.1
+ * XXX: these checks must be done in the kernel as well,
+ * but we can't completely rely on them.
+ */
+ if (*hlimp != 255) {
+ noticelog("<%s> RS with invalid hop limit(%d) "
+ "received from %s on %s",
+ __func__, *hlimp,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ if (icp->icmp6_code) {
+ noticelog("<%s> RS with invalid ICMP6 code(%d) "
+ "received from %s on %s",
+ __func__, icp->icmp6_code,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ if (i < sizeof(struct nd_router_solicit)) {
+ noticelog("<%s> RS from %s on %s does not have enough "
+ "length (len = %d)",
+ __func__,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
+ return;
+ }
+ rs_input(i, (struct nd_router_solicit *)icp, pi, &rcvfrom);
+ break;
+ case ND_ROUTER_ADVERT:
+ /*
+ * Message verification - RFC-2461 6.1.2
+ * XXX: there's a same dilemma as above...
+ */
+ if (*hlimp != 255) {
+ noticelog("<%s> RA with invalid hop limit(%d) "
+ "received from %s on %s",
+ __func__, *hlimp,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ if (icp->icmp6_code) {
+ noticelog("<%s> RA with invalid ICMP6 code(%d) "
+ "received from %s on %s",
+ __func__, icp->icmp6_code,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+ if (i < sizeof(struct nd_router_advert)) {
+ noticelog("<%s> RA from %s on %s does not have enough "
+ "length (len = %d)",
+ __func__,
+ inet_ntop(AF_INET6, &rcvfrom.sin6_addr, ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf), i);
+ return;
+ }
+ ra_input(i, (struct nd_router_advert *)icp, pi, &rcvfrom);
+ break;
+ case ICMP6_ROUTER_RENUMBERING:
+ if (accept_rr == 0) {
+ errorlog("<%s> received a router renumbering "
+ "message, but not allowed to be accepted",
+ __func__);
+ break;
+ }
+ rr_input(i, (struct icmp6_router_renum *)icp, pi, &rcvfrom,
+ &dst);
+ break;
+ default:
+ /*
+ * Note that this case is POSSIBLE, especially just
+ * after invocation of the daemon. This is because we
+ * could receive message after opening the socket and
+ * before setting ICMP6 type filter(see sock_open()).
+ */
+ errorlog("<%s> invalid icmp type(%d)",
+ __func__, icp->icmp6_type);
+ return;
+ }
+
+ return;
+}
+
+static void
+rs_input(int len, struct nd_router_solicit *rs,
+ struct in6_pktinfo *pi, struct sockaddr_in6 *from)
+{
+ char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ union nd_opts ndopts;
+ struct rainfo *ra;
+ struct soliciter *sol;
+
+ debuglog(
+ "<%s> RS received from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ /* ND option check */
+ memset(&ndopts, 0, sizeof(ndopts));
+ if (nd6_options((struct nd_opt_hdr *)(rs + 1),
+ len - sizeof(struct nd_router_solicit),
+ &ndopts, NDOPT_FLAG_SRCLINKADDR)) {
+ infolog("<%s> ND option check failed for an RS from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ /*
+ * If the IP source address is the unspecified address, there
+ * must be no source link-layer address option in the message.
+ * (RFC-2461 6.1.1)
+ */
+ if (IN6_IS_ADDR_UNSPECIFIED(&from->sin6_addr) &&
+ ndopts.nd_opts_src_lladdr) {
+ infolog("<%s> RS from unspecified src on %s has a link-layer"
+ " address option",
+ __func__,
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+
+ ra = ralist;
+ while (ra != NULL) {
+ if (pi->ipi6_ifindex == ra->ifindex)
+ break;
+ ra = ra->next;
+ }
+ if (ra == NULL) {
+ infolog("<%s> RS received on non advertising interface(%s)",
+ __func__,
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+
+ ra->rsinput++; /* increment statistics */
+
+ /*
+ * Decide whether to send RA according to the rate-limit
+ * consideration.
+ */
+
+ /* record sockaddr waiting for RA, if possible */
+ sol = (struct soliciter *)malloc(sizeof(*sol));
+ if (sol) {
+ sol->addr = *from;
+ /* XXX RFC2553 need clarification on flowinfo */
+ sol->addr.sin6_flowinfo = 0;
+ sol->next = ra->soliciter;
+ ra->soliciter = sol;
+ }
+
+ /*
+ * If there is already a waiting RS packet, don't
+ * update the timer.
+ */
+ if (ra->waiting++)
+ goto done;
+
+ set_short_delay(ra);
+
+ done:
+ free_ndopts(&ndopts);
+ return;
+}
+
+static void
+set_short_delay(rai)
+ struct rainfo *rai;
+{
+ long delay; /* must not be greater than 1000000 */
+ struct timeval interval, now, min_delay, tm_tmp, *rest;
+
+ if (rai->timer == NULL)
+ return;
+ /*
+ * Compute a random delay. If the computed value
+ * corresponds to a time later than the time the next
+ * multicast RA is scheduled to be sent, ignore the random
+ * delay and send the advertisement at the
+ * already-scheduled time. RFC-2461 6.2.6
+ */
+#ifdef HAVE_ARC4RANDOM
+ delay = arc4random_uniform(MAX_RA_DELAY_TIME);
+#else
+ delay = random() % MAX_RA_DELAY_TIME;
+#endif
+ interval.tv_sec = 0;
+ interval.tv_usec = delay;
+ rest = rtadvd_timer_rest(rai->timer);
+ if (TIMEVAL_LT(*rest, interval)) {
+ debuglog("<%s> random delay is larger than "
+ "the rest of the current timer", __func__);
+ interval = *rest;
+ }
+
+ /*
+ * If we sent a multicast Router Advertisement within
+ * the last MIN_DELAY_BETWEEN_RAS seconds, schedule
+ * the advertisement to be sent at a time corresponding to
+ * MIN_DELAY_BETWEEN_RAS plus the random value after the
+ * previous advertisement was sent.
+ */
+ gettimeofday(&now, NULL);
+ TIMEVAL_SUB(&now, &rai->lastsent, &tm_tmp);
+ min_delay.tv_sec = MIN_DELAY_BETWEEN_RAS;
+ min_delay.tv_usec = 0;
+ if (TIMEVAL_LT(tm_tmp, min_delay)) {
+ TIMEVAL_SUB(&min_delay, &tm_tmp, &min_delay);
+ TIMEVAL_ADD(&min_delay, &interval, &interval);
+ }
+ rtadvd_set_timer(&interval, rai->timer);
+}
+
+static void
+ra_input(int len, struct nd_router_advert *ra,
+ struct in6_pktinfo *pi, struct sockaddr_in6 *from)
+{
+ struct rainfo *rai;
+ char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+ union nd_opts ndopts;
+ char *on_off[] = {"OFF", "ON"};
+ u_int32_t reachabletime, retranstimer, mtu;
+ int inconsistent = 0;
+
+ debuglog("<%s> RA received from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+
+ /* ND option check */
+ memset(&ndopts, 0, sizeof(ndopts));
+ if (nd6_options((struct nd_opt_hdr *)(ra + 1),
+ len - sizeof(struct nd_router_advert),
+ &ndopts, NDOPT_FLAG_SRCLINKADDR |
+ NDOPT_FLAG_PREFIXINFO | NDOPT_FLAG_MTU)) {
+ infolog("<%s> ND option check failed for an RA from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ return;
+ }
+
+ /*
+ * RA consistency check according to RFC-2461 6.2.7
+ */
+ if ((rai = if_indextorainfo(pi->ipi6_ifindex)) == 0) {
+ infolog("<%s> received RA from %s on non-advertising"
+ " interface(%s)",
+ __func__,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, ifnamebuf));
+ goto done;
+ }
+ rai->rainput++; /* increment statistics */
+
+ /* Cur Hop Limit value */
+ if (ra->nd_ra_curhoplimit && rai->hoplimit &&
+ ra->nd_ra_curhoplimit != rai->hoplimit) {
+ infolog("<%s> CurHopLimit inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ rai->ifname,
+ ra->nd_ra_curhoplimit,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->hoplimit);
+ inconsistent++;
+ }
+ /* M flag */
+ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) !=
+ rai->managedflg) {
+ infolog("<%s> M flag inconsistent on %s:"
+ " %s from %s, %s from us",
+ __func__,
+ rai->ifname,
+ on_off[!rai->managedflg],
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ on_off[rai->managedflg]);
+ inconsistent++;
+ }
+ /* O flag */
+ if ((ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) !=
+ rai->otherflg) {
+ infolog("<%s> O flag inconsistent on %s:"
+ " %s from %s, %s from us",
+ __func__,
+ rai->ifname,
+ on_off[!rai->otherflg],
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ on_off[rai->otherflg]);
+ inconsistent++;
+ }
+ /* Reachable Time */
+ reachabletime = ntohl(ra->nd_ra_reachable);
+ if (reachabletime && rai->reachabletime &&
+ reachabletime != rai->reachabletime) {
+ infolog("<%s> ReachableTime inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ rai->ifname,
+ reachabletime,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->reachabletime);
+ inconsistent++;
+ }
+ /* Retrans Timer */
+ retranstimer = ntohl(ra->nd_ra_retransmit);
+ if (retranstimer && rai->retranstimer &&
+ retranstimer != rai->retranstimer) {
+ infolog("<%s> RetranceTimer inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ rai->ifname,
+ retranstimer,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->retranstimer);
+ inconsistent++;
+ }
+ /* Values in the MTU options */
+ if (ndopts.nd_opts_mtu) {
+ mtu = ntohl(ndopts.nd_opts_mtu->nd_opt_mtu_mtu);
+ if (mtu && rai->linkmtu && mtu != rai->linkmtu) {
+ infolog("<%s> MTU option value inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ rai->ifname, mtu,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->linkmtu);
+ inconsistent++;
+ }
+ }
+ /* Preferred and Valid Lifetimes for prefixes */
+ {
+ struct nd_optlist *optp = ndopts.nd_opts_list;
+
+ if (ndopts.nd_opts_pi) {
+ if (prefix_check(ndopts.nd_opts_pi, rai, from))
+ inconsistent++;
+ }
+ while (optp) {
+ if (prefix_check((struct nd_opt_prefix_info *)optp->opt,
+ rai, from))
+ inconsistent++;
+ optp = optp->next;
+ }
+ }
+
+ if (inconsistent)
+ rai->rainconsistent++;
+
+ done:
+ free_ndopts(&ndopts);
+ return;
+}
+
+/* return a non-zero value if the received prefix is inconsitent with ours */
+static int
+prefix_check(struct nd_opt_prefix_info *pinfo,
+ struct rainfo *rai, struct sockaddr_in6 *from)
+{
+ u_int32_t preferred_time, valid_time;
+ struct prefix *pp;
+ int inconsistent = 0;
+ char ntopbuf[INET6_ADDRSTRLEN], prefixbuf[INET6_ADDRSTRLEN];
+ struct timeval now;
+
+#if 0 /* impossible */
+ if (pinfo->nd_opt_pi_type != ND_OPT_PREFIX_INFORMATION)
+ return(0);
+#endif
+
+ /*
+ * log if the adveritsed prefix has link-local scope(sanity check?)
+ */
+ if (IN6_IS_ADDR_LINKLOCAL(&pinfo->nd_opt_pi_prefix)) {
+ infolog("<%s> link-local prefix %s/%d is advertised "
+ "from %s on %s",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->ifname);
+ }
+
+ if ((pp = find_prefix(rai, &pinfo->nd_opt_pi_prefix,
+ pinfo->nd_opt_pi_prefix_len)) == NULL) {
+ infolog("<%s> prefix %s/%d from %s on %s is not in our list",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ rai->ifname);
+ return(0);
+ }
+
+ preferred_time = ntohl(pinfo->nd_opt_pi_preferred_time);
+ if (pp->pltimeexpire) {
+ /*
+ * The lifetime is decremented in real time, so we should
+ * compare the expiration time.
+ * (RFC 2461 Section 6.2.7.)
+ * XXX: can we really expect that all routers on the link
+ * have synchronized clocks?
+ */
+ gettimeofday(&now, NULL);
+ preferred_time += now.tv_sec;
+
+ if (!pp->timer && rai->clockskew &&
+ preferred_time - pp->pltimeexpire > rai->clockskew) {
+ infolog("<%s> preferred lifetime for %s/%d"
+ " (decr. in real time) inconsistent on %s:"
+ " %d from %s, %ld from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->pltimeexpire);
+ inconsistent++;
+ }
+ } else if (!pp->timer && preferred_time != pp->preflifetime) {
+ infolog("<%s> preferred lifetime for %s/%d"
+ " inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->preflifetime);
+ }
+
+ valid_time = ntohl(pinfo->nd_opt_pi_valid_time);
+ if (pp->vltimeexpire) {
+ gettimeofday(&now, NULL);
+ valid_time += now.tv_sec;
+
+ if (!pp->timer && rai->clockskew &&
+ valid_time - pp->vltimeexpire > rai->clockskew) {
+ infolog("<%s> valid lifetime for %s/%d"
+ " (decr. in real time) inconsistent on %s:"
+ " %d from %s, %ld from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, preferred_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->vltimeexpire);
+ inconsistent++;
+ }
+ } else if (!pp->timer && valid_time != pp->validlifetime) {
+ infolog("<%s> valid lifetime for %s/%d"
+ " inconsistent on %s:"
+ " %d from %s, %d from us",
+ __func__,
+ inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
+ prefixbuf, INET6_ADDRSTRLEN),
+ pinfo->nd_opt_pi_prefix_len,
+ rai->ifname, valid_time,
+ inet_ntop(AF_INET6, &from->sin6_addr,
+ ntopbuf, INET6_ADDRSTRLEN),
+ pp->validlifetime);
+ inconsistent++;
+ }
+
+ return(inconsistent);
+}
+
+struct prefix *
+find_prefix(struct rainfo *rai, struct in6_addr *prefix, int plen)
+{
+ struct prefix *pp;
+ int bytelen, bitlen;
+ u_char bitmask;
+
+ for (pp = rai->prefix.next; pp != &rai->prefix; pp = pp->next) {
+ if (plen != pp->prefixlen)
+ continue;
+ bytelen = plen / 8;
+ bitlen = plen % 8;
+ bitmask = 0xff << (8 - bitlen);
+ if (memcmp((void *)prefix, (void *)&pp->prefix, bytelen))
+ continue;
+ if (bitlen == 0 ||
+ ((prefix->s6_addr[bytelen] & bitmask) ==
+ (pp->prefix.s6_addr[bytelen] & bitmask))) {
+ return(pp);
+ }
+ }
+
+ return(NULL);
+}
+
+/* check if p0/plen0 matches p1/plen1; return 1 if matches, otherwise 0. */
+int
+prefix_match(struct in6_addr *p0, int plen0,
+ struct in6_addr *p1, int plen1)
+{
+ int bytelen, bitlen;
+ u_char bitmask;
+
+ if (plen0 < plen1)
+ return(0);
+ bytelen = plen1 / 8;
+ bitlen = plen1 % 8;
+ bitmask = 0xff << (8 - bitlen);
+ if (memcmp((void *)p0, (void *)p1, bytelen))
+ return(0);
+ if (bitlen == 0 ||
+ ((p0->s6_addr[bytelen] & bitmask) ==
+ (p1->s6_addr[bytelen] & bitmask))) {
+ return(1);
+ }
+
+ return(0);
+}
+
+static int
+nd6_options(struct nd_opt_hdr *hdr, int limit,
+ union nd_opts *ndopts, u_int32_t optflags)
+{
+ int optlen = 0;
+
+ for (; limit > 0; limit -= optlen) {
+ if (limit < sizeof(struct nd_opt_hdr)) {
+ infolog("<%s> short option header", __func__);
+ goto bad;
+ }
+
+ hdr = (struct nd_opt_hdr *)((caddr_t)hdr + optlen);
+ if (hdr->nd_opt_len == 0) {
+ infolog("<%s> bad ND option length(0) (type = %d)",
+ __func__, hdr->nd_opt_type);
+ goto bad;
+ }
+ optlen = hdr->nd_opt_len << 3;
+ if (optlen > limit) {
+ infolog("<%s> short option", __func__);
+ goto bad;
+ }
+
+ if (hdr->nd_opt_type > ND_OPT_MTU) {
+ infolog("<%s> unknown ND option(type %d)",
+ __func__, hdr->nd_opt_type);
+ continue;
+ }
+
+ if ((ndopt_flags[hdr->nd_opt_type] & optflags) == 0) {
+ infolog("<%s> unexpected ND option(type %d)",
+ __func__, hdr->nd_opt_type);
+ continue;
+ }
+
+ /*
+ * Option length check. Do it here for all fixed-length
+ * options.
+ */
+ if ((hdr->nd_opt_type == ND_OPT_MTU &&
+ (optlen != sizeof(struct nd_opt_mtu))) ||
+ ((hdr->nd_opt_type == ND_OPT_PREFIX_INFORMATION &&
+ optlen != sizeof(struct nd_opt_prefix_info)))) {
+ infolog("<%s> invalid option length",
+ __func__);
+ continue;
+ }
+
+ switch (hdr->nd_opt_type) {
+ case ND_OPT_TARGET_LINKADDR:
+ case ND_OPT_REDIRECTED_HEADER:
+ break; /* we don't care about these options */
+ case ND_OPT_SOURCE_LINKADDR:
+ case ND_OPT_MTU:
+ if (ndopts->nd_opt_array[hdr->nd_opt_type]) {
+ infolog("<%s> duplicated ND option (type = %d)",
+ __func__, hdr->nd_opt_type);
+ }
+ ndopts->nd_opt_array[hdr->nd_opt_type] = hdr;
+ break;
+ case ND_OPT_PREFIX_INFORMATION:
+ {
+ struct nd_optlist *pfxlist;
+
+ if (ndopts->nd_opts_pi == 0) {
+ ndopts->nd_opts_pi =
+ (struct nd_opt_prefix_info *)hdr;
+ continue;
+ }
+ if ((pfxlist = malloc(sizeof(*pfxlist))) == NULL) {
+ errorlog("<%s> can't allocate memory",
+ __func__);
+ goto bad;
+ }
+ pfxlist->next = ndopts->nd_opts_list;
+ pfxlist->opt = hdr;
+ ndopts->nd_opts_list = pfxlist;
+
+ break;
+ }
+ default: /* impossible */
+ break;
+ }
+ }
+
+ return(0);
+
+ bad:
+ free_ndopts(ndopts);
+
+ return(-1);
+}
+
+static void
+free_ndopts(union nd_opts *ndopts)
+{
+ struct nd_optlist *opt = ndopts->nd_opts_list, *next;
+
+ while (opt) {
+ next = opt->next;
+ free(opt);
+ opt = next;
+ }
+}
+
+void
+sock_open()
+{
+ struct icmp6_filter filt;
+ struct ipv6_mreq mreq;
+ struct rainfo *ra = ralist;
+ int on;
+ /* XXX: should be max MTU attached to the node */
+ static u_char answer[1500];
+
+ rcvcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ rcvcmsgbuf = (u_char *)malloc(rcvcmsgbuflen);
+ if (rcvcmsgbuf == NULL) {
+ errorlog("<%s> not enough core", __func__);
+ exit(1);
+ }
+
+ sndcmsgbuflen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ sndcmsgbuf = (u_char *)malloc(sndcmsgbuflen);
+ if (sndcmsgbuf == NULL) {
+ errorlog("<%s> not enough core", __func__);
+ exit(1);
+ }
+
+ if ((sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ errorlog("<%s> socket: %s", __func__,
+ strerror(errno));
+ exit(1);
+ }
+
+ (void) setsockopt(sock, SOL_SOCKET, SO_TRAFFIC_CLASS,
+ (void *)&so_traffic_class, sizeof (so_traffic_class));
+
+ /* specify to tell receiving interface */
+ on = 1;
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ sizeof(on)) < 0) {
+ errorlog("<%s> IPV6_RECVPKTINFO: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+#else /* old adv. API */
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
+ sizeof(on)) < 0) {
+ errorlog("<%s> IPV6_PKTINFO: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+#endif
+
+ on = 1;
+ /* specify to tell value of hoplimit field of received IP6 hdr */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ errorlog( "<%s> IPV6_RECVHOPLIMIT: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+#else /* old adv. API */
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ errorlog("<%s> IPV6_HOPLIMIT: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+#endif
+
+ on = 1;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_DONTFRAG, &on,
+ sizeof(on)) < 0) {
+ errorlog("<%s> IPV6_DONTFRAG: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filt);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+ if (accept_rr)
+ ICMP6_FILTER_SETPASS(ICMP6_ROUTER_RENUMBERING, &filt);
+ if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) < 0) {
+ errorlog("<%s> IICMP6_FILTER: %s",
+ __func__, strerror(errno));
+ exit(1);
+ }
+
+ /*
+ * join all routers multicast address on each advertising interface.
+ */
+ if (inet_pton(AF_INET6, ALLROUTERS_LINK,
+ &mreq.ipv6mr_multiaddr.s6_addr)
+ != 1) {
+ errorlog("<%s> inet_pton failed(library bug?)",
+ __func__);
+ exit(1);
+ }
+ while (ra) {
+ mreq.ipv6mr_interface = ra->ifindex;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq,
+ sizeof(mreq)) < 0) {
+ errorlog("<%s> IPV6_JOIN_GROUP(link) on %s: %s",
+ __func__, ra->ifname, strerror(errno));
+ exit(1);
+ }
+ ra = ra->next;
+ }
+
+ /*
+ * When attending router renumbering, join all-routers site-local
+ * multicast group.
+ */
+ if (accept_rr) {
+ if (inet_pton(AF_INET6, ALLROUTERS_SITE,
+ &in6a_site_allrouters) != 1) {
+ errorlog("<%s> inet_pton failed(library bug?)",
+ __func__);
+ exit(1);
+ }
+ mreq.ipv6mr_multiaddr = in6a_site_allrouters;
+ if (mcastif) {
+ if ((mreq.ipv6mr_interface = if_nametoindex(mcastif))
+ == 0) {
+ errorlog("<%s> invalid interface: %s",
+ __func__, mcastif);
+ exit(1);
+ }
+ } else
+ mreq.ipv6mr_interface = ralist->ifindex;
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ &mreq, sizeof(mreq)) < 0) {
+ errorlog("<%s> IPV6_JOIN_GROUP(site) on %s: %s",
+ __func__,
+ mcastif ? mcastif : ralist->ifname,
+ strerror(errno));
+ exit(1);
+ }
+ }
+
+ /* initialize msghdr for receiving packets */
+ rcviov[0].iov_base = (caddr_t)answer;
+ rcviov[0].iov_len = sizeof(answer);
+ rcvmhdr.msg_name = (caddr_t)&rcvfrom;
+ rcvmhdr.msg_namelen = sizeof(rcvfrom);
+ rcvmhdr.msg_iov = rcviov;
+ rcvmhdr.msg_iovlen = 1;
+ rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
+ rcvmhdr.msg_controllen = rcvcmsgbuflen;
+
+ /* initialize msghdr for sending packets */
+ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ sndmhdr.msg_iov = sndiov;
+ sndmhdr.msg_iovlen = 1;
+ sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
+ sndmhdr.msg_controllen = sndcmsgbuflen;
+
+ return;
+}
+
+/* open a routing socket to watch the routing table */
+static void
+rtsock_open()
+{
+ if ((rtsock = socket(PF_ROUTE, SOCK_RAW, 0)) < 0) {
+ errorlog("<%s> socket: %s", __func__, strerror(errno));
+ exit(1);
+ }
+}
+
+struct rainfo *
+if_indextorainfo(int idx)
+{
+ struct rainfo *rai = ralist;
+
+ for (rai = ralist; rai; rai = rai->next) {
+ if (rai->ifindex == idx)
+ return(rai);
+ }
+
+ return(NULL); /* search failed */
+}
+
+static void
+ra_output(rainfo)
+struct rainfo *rainfo;
+{
+ int i;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi;
+ struct soliciter *sol, *nextsol;
+ struct if_msghdr *ifm = get_interface_entry(rainfo->ifindex);
+
+ if (ifm == NULL ||
+ (ifm->ifm_flags & IFF_UP) == 0) {
+ debuglog("<%s> %s is not up, skip sending RA",
+ __func__, rainfo->ifname);
+ return;
+ }
+
+ make_packet(rainfo); /* XXX: inefficient */
+
+ sndmhdr.msg_name = (caddr_t)&sin6_allnodes;
+ sndmhdr.msg_iov[0].iov_base = (caddr_t)rainfo->ra_data;
+ sndmhdr.msg_iov[0].iov_len = rainfo->ra_datalen;
+
+ cm = CMSG_FIRSTHDR(&sndmhdr);
+ /* specify the outgoing interface */
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
+ pi->ipi6_ifindex = rainfo->ifindex;
+
+ /* specify the hop limit of the packet */
+ {
+ int hoplimit = 255;
+
+ cm = CMSG_NXTHDR(&sndmhdr, cm);
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_HOPLIMIT;
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ }
+
+ debuglog("<%s> send RA on %s, # of waitings = %d",
+ __func__, rainfo->ifname, rainfo->waiting);
+
+ i = sendmsg(sock, &sndmhdr, 0);
+
+ if (i < 0 || i != rainfo->ra_datalen) {
+ if (i < 0) {
+ errorlog("<%s> sendmsg on %s: %s",
+ __func__, rainfo->ifname,
+ strerror(errno));
+ }
+ }
+ /* update counter */
+ if (rainfo->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS)
+ rainfo->initcounter++;
+ rainfo->raoutput++;
+
+ /*
+ * unicast advertisements
+ * XXX commented out. reason: though spec does not forbit it, unicast
+ * advert does not really help
+ */
+ for (sol = rainfo->soliciter; sol; sol = nextsol) {
+ nextsol = sol->next;
+
+ sol->next = NULL;
+ free(sol);
+ }
+ rainfo->soliciter = NULL;
+
+ /* update timestamp */
+ gettimeofday(&rainfo->lastsent, NULL);
+
+ /* reset waiting conter */
+ rainfo->waiting = 0;
+}
+
+/* process RA timer */
+struct rtadvd_timer *
+ra_timeout(void *data)
+{
+ struct rainfo *rai = (struct rainfo *)data;
+
+#ifdef notyet
+ /* if necessary, reconstruct the packet. */
+#endif
+
+ debuglog("<%s> RA timer on %s is expired",
+ __func__, rai->ifname);
+
+ ra_output(rai);
+
+ return(rai->timer);
+}
+
+/* update RA timer */
+void
+ra_timer_update(void *data, struct timeval *tm)
+{
+ struct rainfo *rai = (struct rainfo *)data;
+ long interval;
+
+ /*
+ * Whenever a multicast advertisement is sent from an interface,
+ * the timer is reset to a uniformly-distributed random value
+ * between the interface's configured MinRtrAdvInterval and
+ * MaxRtrAdvInterval (RFC2461 6.2.4).
+ */
+ interval = rai->mininterval;
+ interval += random() % (rai->maxinterval - rai->mininterval);
+
+ /*
+ * The first advertisement is sent as soon as rtadvd starts up
+ * and for the next few advertisements (up to
+ * MAX_INITIAL_RTR_ADVERTISEMENTS), if the randomly chosen interval
+ * is greater than MAX_INITIAL_RTR_ADVERT_INTERVAL, the timer
+ * SHOULD be set to MAX_INITIAL_RTR_ADVERT_INTERVAL instead.
+ * (RFC-2461 6.2.4)
+ */
+ if (rai->initcounter < MAX_INITIAL_RTR_ADVERTISEMENTS &&
+ interval > MAX_INITIAL_RTR_ADVERT_INTERVAL)
+ interval = MAX_INITIAL_RTR_ADVERT_INTERVAL;
+
+ tm->tv_sec = rai->initcounter == 0 ? 0 : interval;
+ tm->tv_usec = 0;
+
+ debuglog("<%s> RA timer on %s is set to %ld:%ld",
+ __func__, rai->ifname,
+ (long int)tm->tv_sec, (long int)tm->tv_usec);
+
+ return;
+}
diff --git a/network_cmds/rtadvd.tproj/rtadvd.conf b/network_cmds/rtadvd.tproj/rtadvd.conf
new file mode 100644
index 0000000..6d109b2
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.conf
@@ -0,0 +1,20 @@
+# $KAME: rtadvd.conf,v 1.13 2003/06/25 03:45:21 itojun Exp $
+#
+# Note: All of the following parameters have default values defined
+# in specifications, and hence you usually do not have to set them
+# by hand unless you need special non-default values.
+#
+# You even do not need to create the configuration file. rtadvd
+# would usually work well without a configuration file.
+# See also: rtadvd(8)
+
+# per-interface definitions.
+# Mainly IPv6 prefixes are configured in this part. However, rtadvd
+# automatically learns appropriate prefixes from the kernel's routing
+# table, and advertises the prefixes, so you don't have to configure
+# this part, either.
+# If you don't want the automatic advertisement, (uncomment and) configure
+# this part by hand, and then invoke rtadvd with the -s option.
+
+#ef0:\
+# :addr="3ffe:501:ffff:1000::":prefixlen#64:
diff --git a/network_cmds/rtadvd.tproj/rtadvd.conf.5 b/network_cmds/rtadvd.tproj/rtadvd.conf.5
new file mode 100644
index 0000000..87978fc
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.conf.5
@@ -0,0 +1,509 @@
+.\" $KAME: rtadvd.conf.5,v 1.50 2005/01/14 05:30:59 jinmei Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" 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 project 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 PROJECT 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 PROJECT 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 February 24, 2012
+.Dt RTADVD.CONF 5
+.Os
+.Sh NAME
+.Nm rtadvd.conf
+.Nd config file for router advertisement daemon
+.Sh DESCRIPTION
+This file describes how the router advertisement packets must be constructed
+for each of the interfaces.
+.Pp
+As described in
+.Xr rtadvd 8 ,
+you do not have to set this configuration file up at all,
+unless you need some special configurations.
+You may even omit the file as a whole.
+In such cases, the
+.Nm rtadvd
+daemon will automatically configure itself using default values
+specified in the specification.
+.Pp
+It obeys the famous
+.Xr termcap 5
+file format.
+Each line in the file describes a network interface.
+Fields are separated by a colon
+.Pq Sq \&: ,
+and each field contains one capability description.
+Lines may be concatenated by the
+.Sq \e
+character.
+The comment marker is the
+.Sq \&#
+character.
+.Sh CAPABILITIES
+Capabilities describe the value to be filled into ICMPv6 router
+advertisement messages and to control
+.Xr rtadvd 8
+behavior.
+Therefore, you are encouraged to read IETF neighbor discovery documents
+if you would like to modify the sample configuration file.
+.Pp
+Note that almost all items have default values.
+If you omit an item, the default value of the item will be used.
+.Pp
+There are two items which control the interval of sending router advertisements.
+These items can be omitted, then
+.Nm rtadvd
+will use the default values.
+.Bl -tag -width indent
+.It Cm \&maxinterval
+(num) The maximum time allowed between sending unsolicited
+multicast router advertisements
+.Pq unit: seconds .
+The default value is 600.
+Its value must be no less than 4 seconds
+and no greater than 1800 seconds.
+.It Cm \&mininterval
+(num) The minimum time allowed between sending unsolicited multicast
+router advertisements
+.Pq unit: seconds .
+The default value is the one third of value of
+.Cm maxinterval .
+Its value must be no less than 3 seconds and no greater than .75 *
+the value of
+.Cm maxinterval .
+.El
+.Pp
+The following items are for ICMPv6 router advertisement message
+header.
+These items can be omitted, then
+.Nm rtadvd
+will use the default values.
+.Bl -tag -width indent
+.It Cm \&chlim
+(num) The value for Cur Hop Limit field.
+The default value is 64.
+.It Cm \&raflags
+(str or num) A 8-bit flags field in router advertisement message header.
+This field can be specified either as a case-sensitive string or as an
+integer.
+A string consists of characters each of which corresponds to a
+particular flag bit(s).
+An integer should be the logical OR of all enabled bits.
+Bit 7
+.Po
+.Li 'm' or 0x80
+.Pc
+means Managed address configuration flag bit,
+and Bit 6
+.Po
+.Li 'o' or 0x40
+.Pc
+means Other stateful configuration flag bit.
+Bit 4
+.Po
+.Li 0x10
+.Pc
+and Bit 3
+.Po
+.Li 0x08
+.Pc
+are used to encode router preference.
+Bits 01
+.Po
+or 'h'
+.Pc
+means high, 00 means medium, and 11
+.Po
+or 'l'
+.Pc
+means low.
+Bits 10 is reserved, and must not be specified.
+There is no character to specify the medium preference explicitly.
+The default value of the entire flag is 0
+.Po
+or a null string,
+.Pc
+which means no additional
+configuration methods, and the medium router preference.
+.It Cm \&rltime
+(num) Router lifetime field
+.Pq unit: seconds .
+The value must be either zero or between
+the value of
+.Cm maxinterval
+and 9000.
+When
+.Nm rtadvd
+runs on a host, this value must explicitly set 0 on all the
+advertising interfaces as described in
+.Xr rtadvd 8 .
+The default value is 1800.
+.It Cm \&rtime
+(num) Reachable time field
+.Pq unit: milliseconds .
+The default value is 0, which means unspecified by this router.
+.It Cm \&retrans
+(num) Retrans Timer field
+.Pq unit: milliseconds .
+The default value is 0, which means unspecified by this router.
+.El
+.Pp
+The following items are for ICMPv6 prefix information option,
+which will be attached to router advertisement header.
+These items can be omitted, then
+.Nm rtadvd
+will automatically get appropriate prefixes from the kernel's routing table,
+and advertise the prefixes with the default parameters.
+Keywords other than
+.Cm clockskew
+can be augmented with a number, like
+.Dq Li prefix2 ,
+to specify multiple prefixes.
+.Bl -tag -width indent
+.It Cm \&clockskew
+(num) Time skew to adjust link propagation delays and clock skews
+between routers on the link
+.Pq unit: seconds .
+This value is used in consistency check for locally-configured and
+advertised prefix lifetimes, and has its meaning when the local router
+configures a prefix on the link with a lifetime that decrements in
+real time.
+If the value is 0, it means the consistency check will be skipped
+for such prefixes.
+The default value is 0.
+.It Cm \&prefixlen
+(num) Prefix length field.
+The default value is 64.
+.It Cm \&pinfoflags
+(str or num) A 8-bit flags field in prefix information option.
+This field can be specified either as a case-sensitive string or as an
+integer.
+A string consists of characters each of which corresponds to a
+particular flag bit(s).
+An integer should be the logical OR of all enabled bits.
+Bit 7
+.Po
+.Li 'l' or 0x80
+.Pc
+means On-link flag bit,
+and Bit 6
+.Po
+.Li 'a' or 0x40
+.Pc
+means Autonomous address-configuration flag bit.
+The default value is "la" or 0xc0, i.e., both bits are set.
+.It Cm \&addr
+(str) The address filled into Prefix field.
+Since
+.Dq \&:
+is used for
+.Xr termcap 5
+file format as well as IPv6 numeric address, the field MUST be quoted by
+doublequote character.
+.It Cm \&vltime
+(num) Valid lifetime field
+.Pq unit: seconds .
+The default value is 2592000 (30 days).
+.It Cm \&vltimedecr
+(bool) This item means the advertised valid lifetime will decrement
+in real time, which is disabled by default.
+.It Cm \&pltime
+(num) Preferred lifetime field
+.Pq unit: seconds .
+The default value is 604800 (7 days).
+.It Cm \&pltimedecr
+(bool) This item means the advertised preferred lifetime will decrement
+in real time, which is disabled by default.
+.El
+.Pp
+The following item is for ICMPv6 MTU option,
+which will be attached to router advertisement header.
+This item can be omitted, then
+.Nm rtadvd
+will use the default value.
+.Bl -tag -width indent
+.It Cm \&mtu
+(num or str) MTU (maximum transmission unit) field.
+If 0 is specified, it means that the option will not be included.
+The default value is 0.
+If the special string
+.Dq auto
+is specified for this item, MTU option will be included and its value
+will be set to the interface MTU automatically.
+.El
+.Pp
+The following item controls ICMPv6 source link-layer address option,
+which will be attached to router advertisement header.
+As noted above, you can just omit the item, then
+.Nm rtadvd
+will use the default value.
+.Bl -tag -width indent
+.It Cm \&nolladdr
+(bool) By default
+.Po
+if
+.Cm \&nolladdr
+is not specified
+.Pc ,
+.Xr rtadvd 8
+will try to get link-layer address for the interface from the kernel,
+and attach that in source link-layer address option.
+If this capability exists,
+.Xr rtadvd 8
+will not attach source link-layer address option to
+router advertisement packets.
+.El
+.Pp
+The following item controls ICMPv6 home agent information option,
+which was defined with mobile IPv6 support.
+It will be attached to router advertisement header just like other options do.
+.Bl -tag -width indent
+.It Cm \&hapref
+(num) Specifies home agent preference.
+If set to non-zero,
+.Cm \&hatime
+must be present as well.
+.It Cm \&hatime
+(num) Specifies home agent lifetime.
+.El
+.Pp
+When mobile IPv6 support is turned on for
+.Xr rtadvd 8 ,
+advertisement interval option will be attached to router advertisement
+packet, by configuring
+.Cm \&maxinterval
+explicitly.
+.Pp
+The following items are for ICMPv6 route information option,
+which will be attached to router advertisement header.
+These items are optional.
+Each items can be augmented with number, like
+.Dq Li rtplen2 ,
+to specify multiple routes.
+.Bl -tag -width indent
+.It Cm \&rtprefix
+(str) The prefix filled into the Prefix field of route information option.
+Since
+.Dq \&:
+is used for
+.Xr termcap 5
+file format as well as IPv6 numeric address, the field MUST be quoted by
+doublequote character.
+.It Cm \&rtplen
+(num) Prefix length field in route information option.
+The default value is 64.
+.It Cm \&rtflags
+(str or num) A 8-bit flags field in route information option.
+Currently only the preference values are defined.
+The notation is same as that of the raflags field.
+Bit 4
+.Po
+.Li 0x10
+.Pc
+and
+Bit 3
+.Po
+.Li 0x08
+.Pc
+are used to encode the route preference for the route.
+The default value is 0x00, i.e., medium preference.
+.It Cm \&rtltime
+(num) route lifetime field in route information option.
+.Pq unit: seconds .
+Since the specification does not define the default value of this
+item, the value for this item should be specified by hand.
+However,
+.Nm rtadvd
+allows this item to be unspecified, and uses the router lifetime
+as the default value in such a case, just for compatibility with an
+old version of the program.
+.El
+.Pp
+In the above list, each keyword beginning with
+.Dq Li rt
+could be replaced with the one beginning with
+.Dq Li rtr
+for backward compatibility reason.
+For example,
+.Cm rtrplen
+is accepted instead of
+.Cm rtplen .
+However, keywords that start with
+.Dq Li rtr
+have basically been obsoleted, and should not be used any more.
+.Pp
+You can also refer one line from another by using
+.Cm tc
+capability.
+See
+.Xr termcap 5
+for details on the capability.
+.Pp
+The following items are for the ICMPv6 recursive DNS server (RDNSS) option,
+which will be attached to the router advertisement header.
+.Bl -tag -width indent
+.It Cm \&rdnssaddrs
+(num) Number of recursive DNS server addresses.
+Its default is 0, so it must explicitly be set to positive values
+if you want to specify any DNS server address.
+If its value is 0, no DNS server information is sent.
+If its value is more than 1, you must specify the index of the address
+for the
+.Cm rdnssaddr
+item below.
+Indices vary from 0 to N-1, where N is the
+value of
+.Cm rdnssaddrs .
+Each index shall follow the name of
+.Cm rdnssaddr ,
+e.g.,
+.Dq rdnssaddr0 .
+.It Cm \&rdnssaddr
+(str) The IPv6 address of the recursive DNS server.
+Since
+.Dq \&:
+is used for
+.Xr termcap 5
+file format as well as IPv6 numeric address, the field MUST be quoted by
+doublequote character.
+This field cannot be
+omitted if the value of
+.Cm rdnssaddrs
+is more than 0.
+.It Cm \&rdnsslifetime
+(num) The lifetime field in RDNSS option.
+(unit: seconds).
+The default value is 2 * the value of
+.Cm \&maxinterval ,
+which is also the maximum value that should be set. The minimum value is
+.Cm \&maxinterval .
+If you specify a value outside of this range, a message is logged.
+.El
+.Pp
+The following items are for the ICMPv6 DNS search list (DNSSL) option,
+which will be attached to the router advertisement header.
+.Bl -tag -width indent
+.It Cm \&dnssldomains
+(num) Number of DNS search domains.
+Its default is 0, so it must explicitly be set to positive values
+if you want to specify any DNS search domains.
+If its value is 0, no DNS search domain information is sent.
+If its value is more than 1, you must specify the index of the search domain
+for the
+.Cm dnssldomain
+item below.
+Indices vary from 0 to N-1, where N is the
+value of
+.Cm dnssldomains .
+Each index shall follow the name of
+.Cm dnssldomain ,
+e.g.,
+.Dq dnssldomain0 .
+.It Cm \&dnssldomain
+(str) The DNS search domain.
+This field cannot be
+omitted if the value of
+.Cm dnssldomains
+is more than 0.
+.It Cm \&dnssllifetime
+(num) The lifetime field in the DNSSL option.
+(unit: seconds).
+The default value is 2 * the value of
+.Cm \&maxinterval ,
+which is also the maximum value that should be set. The minimum value is
+.Cm \&maxinterval .
+If you specify a value outside of this range, a message is logged.
+.El
+.Sh EXAMPLES
+As presented above, all of the advertised parameters have default values
+defined in specifications, and hence you usually do not have to set them
+by hand, unless you need special non-default values.
+It can cause interoperability problem if you use an ill-configured
+parameter.
+.Pp
+To override a configuration parameter, you can specify the parameter alone.
+With the following configuration,
+.Xr rtadvd 8
+overrides the router lifetime parameter for the
+.Li ne0
+interface.
+.Bd -literal -offset
+ne0:\\
+ :rltime#0:
+.Ed
+.Pp
+The following example manually configures prefixes advertised from the
+.Li ef0
+interface.
+The configuration must be used with the
+.Fl s
+option to
+.Xr rtadvd 8 .
+.Bd -literal -offset
+ef0:\\
+ :addr="3ffe:501:ffff:1000::":prefixlen#64:
+.Ed
+.Pp
+The following example presents the default values in an explicit manner.
+The configuration is provided just for reference purposes;
+YOU DO NOT NEED TO HAVE IT AT ALL.
+.Bd -literal -offset
+default:\\
+ :chlim#64:raflags#0:rltime#1800:rtime#0:retrans#0:\\
+ :pinfoflags="la":vltime#2592000:pltime#604800:mtu#0:
+ef0:\\
+ :addr="3ffe:501:ffff:1000::":prefixlen#64:tc=default:
+.Ed
+.Sh SEE ALSO
+.Xr termcap 5 ,
+.Xr rtadvd 8 ,
+.Xr rtsol 8
+.Rs
+.%A Thomas Narten
+.%A Erik Nordmark
+.%A W. A. Simpson
+.%T Neighbor Discovery for IP version 6 (IPv6)
+.%R RFC 2461
+.Re
+.Rs
+.%A Richard Draves
+.%T Default Router Preferences and More-Specific Routes
+.%R draft-ietf-ipngwg-router-selection-xx.txt
+.Re
+.Rs
+.%A J. Jeong
+.%A S. Park
+.%A L. Beloeil
+.%A S. Madanapalli
+.%T IPv6 Router Advertisement Option for DNS Configuration
+.%R RFC 5006
+.Re
+.Sh HISTORY
+The
+.Xr rtadvd 8
+and the configuration file
+.Nm
+first appeared in WIDE Hydrangea IPv6 protocol stack kit.
+.\" .Sh BUGS
+.\" (to be written)
diff --git a/network_cmds/rtadvd.tproj/rtadvd.h b/network_cmds/rtadvd.tproj/rtadvd.h
new file mode 100644
index 0000000..504f398
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd.h
@@ -0,0 +1,205 @@
+/* $KAME: rtadvd.h,v 1.26 2003/08/05 12:34:23 itojun Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * Copyright (C) 2011 Hiroki Sato <hrs@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.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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 "rtadvd_logging.h"
+
+#define ELM_MALLOC(p, error_action) \
+ do { \
+ p = malloc(sizeof(*p)); \
+ if (p == NULL) { \
+ errorlog("<%s> malloc failed: %s", \
+ __func__, strerror(errno)); \
+ error_action; \
+ } \
+ memset(p, 0, sizeof(*p)); \
+ } while(0)
+
+#define ROUTEINFO 1
+
+#define ALLNODES "ff02::1"
+#define ALLROUTERS_LINK "ff02::2"
+#define ALLROUTERS_SITE "ff05::2"
+#define ANY "::"
+#define RTSOLLEN 8
+
+/* protocol constants and default values */
+#define DEF_MAXRTRADVINTERVAL 600
+#define DEF_ADVLINKMTU 0
+#define DEF_ADVREACHABLETIME 0
+#define DEF_ADVRETRANSTIMER 0
+#define DEF_ADVCURHOPLIMIT 64
+#define DEF_ADVVALIDLIFETIME 2592000
+#define DEF_ADVPREFERREDLIFETIME 604800
+
+#define MAXROUTERLIFETIME 9000
+#define MIN_MAXINTERVAL 4
+#define MAX_MAXINTERVAL 1800
+#define MIN_MININTERVAL 3
+#define MAXREACHABLETIME 3600000
+
+#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16
+#define MAX_INITIAL_RTR_ADVERTISEMENTS 3
+#define MAX_FINAL_RTR_ADVERTISEMENTS 1
+#define MIN_DELAY_BETWEEN_RAS 3
+#define MAX_RA_DELAY_TIME 500000 /* usec */
+
+#define PREFIX_FROM_KERNEL 1
+#define PREFIX_FROM_CONFIG 2
+#define PREFIX_FROM_DYNAMIC 3
+
+struct prefix {
+ struct prefix *next; /* forward link */
+ struct prefix *prev; /* previous link */
+
+ struct rainfo *rainfo; /* back pointer to the interface */
+
+ struct rtadvd_timer *timer; /* expiration timer. used when a prefix
+ * derived from the kernel is deleted.
+ */
+
+ u_int32_t validlifetime; /* AdvValidLifetime */
+ long vltimeexpire; /* expiration of vltime; decrement case only */
+ u_int32_t preflifetime; /* AdvPreferredLifetime */
+ long pltimeexpire; /* expiration of pltime; decrement case only */
+ u_int onlinkflg; /* bool: AdvOnLinkFlag */
+ u_int autoconfflg; /* bool: AdvAutonomousFlag */
+ int prefixlen;
+ int origin; /* from kernel or config */
+ struct in6_addr prefix;
+};
+
+#ifdef ROUTEINFO
+struct rtinfo {
+ struct rtinfo *prev; /* previous link */
+ struct rtinfo *next; /* forward link */
+
+ u_int32_t ltime; /* route lifetime */
+ u_int rtpref; /* route preference */
+ int prefixlen;
+ struct in6_addr prefix;
+};
+#endif
+
+struct soliciter {
+ struct soliciter *next;
+ struct sockaddr_in6 addr;
+};
+
+struct rdnss {
+ struct rdnss *next; /* forward link */
+ struct rdnss *prev; /* previous link */
+
+ struct in6_addr addr;
+};
+
+struct dnssl {
+ struct dnssl *next;
+ struct dnssl *prev;
+
+ char domain[1];
+};
+
+struct rainfo {
+ /* pointer for list */
+ struct rainfo *next;
+
+ /* timer related parameters */
+ struct rtadvd_timer *timer;
+ int initcounter; /* counter for the first few advertisements */
+ struct timeval lastsent; /* timestamp when the latest RA was sent */
+ int waiting; /* number of RS waiting for RA */
+
+ /* interface information */
+ int ifindex;
+ int advlinkopt; /* bool: whether include link-layer addr opt */
+ struct sockaddr_dl *sdl;
+ char ifname[16];
+ int phymtu; /* mtu of the physical interface */
+
+ /* Router configuration variables */
+ u_short lifetime; /* AdvDefaultLifetime */
+ u_int maxinterval; /* MaxRtrAdvInterval */
+ u_int mininterval; /* MinRtrAdvInterval */
+ int managedflg; /* AdvManagedFlag */
+ int otherflg; /* AdvOtherConfigFlag */
+
+ int rtpref; /* router preference */
+ u_int32_t linkmtu; /* AdvLinkMTU */
+ u_int32_t reachabletime; /* AdvReachableTime */
+ u_int32_t retranstimer; /* AdvRetransTimer */
+ u_int hoplimit; /* AdvCurHopLimit */
+ struct prefix prefix; /* AdvPrefixList(link head) */
+ int pfxs; /* number of prefixes */
+ long clockskew; /* used for consisitency check of lifetimes */
+
+#ifdef ROUTEINFO
+ struct rtinfo route; /* route information option (link head) */
+ int routes; /* number of route information options */
+#endif
+
+ /* Recursive DNS Servers RFC5006 */
+ struct rdnss rdnss_list;
+ int rdnss_length;
+ u_int32_t rdnss_lifetime;
+
+ /* DNS Search List RFC6106 */
+ struct dnssl dnssl_list;
+ int dnssl_length;
+ u_int32_t dnssl_lifetime;
+ u_int32_t dnssl_option_length;
+
+ /* Captive Portal RFC 7710 */
+ char * capport;
+ u_int32_t capport_length;
+ u_int32_t capport_option_length;
+
+ /* actual RA packet data and its length */
+ size_t ra_datalen;
+ u_char *ra_data;
+
+ /* statistics */
+ u_quad_t raoutput; /* number of RAs sent */
+ u_quad_t rainput; /* number of RAs received */
+ u_quad_t rainconsistent; /* number of RAs inconsistent with ours */
+ u_quad_t rsinput; /* number of RSs received */
+
+ /* info about soliciter */
+ struct soliciter *soliciter; /* recent solication source */
+};
+
+struct rtadvd_timer *ra_timeout(void *);
+void ra_timer_update(void *, struct timeval *);
+
+int prefix_match(struct in6_addr *, int, struct in6_addr *, int);
+struct rainfo *if_indextorainfo(int);
+struct prefix *find_prefix(struct rainfo *, struct in6_addr *, int);
+
+extern struct in6_addr in6a_site_allrouters;
diff --git a/network_cmds/rtadvd.tproj/rtadvd_logging.c b/network_cmds/rtadvd.tproj/rtadvd_logging.c
new file mode 100644
index 0000000..90dec08
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd_logging.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * This document is the property of Apple Inc.
+ * It is considered confidential and proprietary.
+ *
+ * This document may not be reproduced or transmitted in any form,
+ * in whole or in part, without the express written permission of
+ * Apple Inc.
+ */
+#include <assert.h>
+#include <os/log_private.h>
+
+#define kRtadvdLoggerID "com.apple.rtadvd"
+static os_log_t rtadvdLogger = NULL; /* Handle for Logger */
+
+static boolean_t rtadvd_logger_create(void);
+
+static boolean_t
+rtadvd_logger_create(void)
+{
+ assert(rtadvdLogger == NULL);
+ rtadvdLogger = os_log_create(kRtadvdLoggerID, "daemon");
+
+ if (rtadvdLogger == NULL) {
+ os_log_error(OS_LOG_DEFAULT, "Couldn't create os log object");
+ }
+
+ return (rtadvdLogger != NULL);
+}
+
+void
+rtadvdLog(int level, const char *format, ...)
+{
+ va_list args;
+
+ if (rtadvdLogger == NULL && !rtadvd_logger_create()) {
+ return;
+ }
+
+ va_start(args, format);
+ os_log_with_args(rtadvdLogger, level, format, args, __builtin_return_address(0));
+ va_end(args);
+ return;
+}
diff --git a/network_cmds/rtadvd.tproj/rtadvd_logging.h b/network_cmds/rtadvd.tproj/rtadvd_logging.h
new file mode 100644
index 0000000..11273e6
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/rtadvd_logging.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 Apple Inc. All rights reserved.
+ *
+ * This document is the property of Apple Inc.
+ * It is considered confidential and proprietary.
+ *
+ * This document may not be reproduced or transmitted in any form,
+ * in whole or in part, without the express written permission of
+ * Apple Inc.
+ */
+#include <os/log.h>
+extern void rtadvdLog(int level, const char *format, ...);
+
+#define errorlog(__format, ...) \
+rtadvdLog(OS_LOG_TYPE_DEFAULT, __format, ## __VA_ARGS__)
+
+#define noticelog(__format, ...) \
+rtadvdLog(OS_LOG_TYPE_DEFAULT, __format, ## __VA_ARGS__)
+
+#define infolog(__format, ...) \
+rtadvdLog(OS_LOG_TYPE_INFO, __format, ## __VA_ARGS__)
+
+#define debuglog(__format, ...) \
+rtadvdLog(OS_LOG_TYPE_DEBUG, __format, ## __VA_ARGS__)
diff --git a/network_cmds/rtadvd.tproj/timer.c b/network_cmds/rtadvd.tproj/timer.c
new file mode 100644
index 0000000..3134fc0
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/timer.c
@@ -0,0 +1,205 @@
+/* $KAME: timer.c,v 1.9 2002/06/10 19:59:47 itojun Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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/time.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <search.h>
+#include "timer.h"
+#include "rtadvd_logging.h"
+
+static struct rtadvd_timer timer_head;
+
+#define MILLION 1000000
+#define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\
+ (t1)->tv_usec == (t2)->tv_usec)
+
+static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
+
+void
+rtadvd_timer_init()
+{
+ memset(&timer_head, 0, sizeof(timer_head));
+
+ timer_head.next = timer_head.prev = &timer_head;
+ timer_head.tm = tm_max;
+}
+
+struct rtadvd_timer *
+rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
+ void (*update)(void *, struct timeval *),
+ void *timeodata, void *updatedata)
+{
+ struct rtadvd_timer *newtimer;
+
+ if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
+ errorlog("<%s> can't allocate memory", __func__);
+ exit(1);
+ }
+
+ memset(newtimer, 0, sizeof(*newtimer));
+
+ if (timeout == NULL) {
+ errorlog("<%s> timeout function unspecified", __func__);
+ exit(1);
+ }
+ newtimer->expire = timeout;
+ newtimer->update = update;
+ newtimer->expire_data = timeodata;
+ newtimer->update_data = updatedata;
+ newtimer->tm = tm_max;
+
+ /* link into chain */
+ insque(newtimer, &timer_head);
+
+ return(newtimer);
+}
+
+void
+rtadvd_remove_timer(struct rtadvd_timer **timer)
+{
+ remque(*timer);
+ free(*timer);
+ *timer = NULL;
+}
+
+void
+rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
+{
+ struct timeval now;
+
+ /* reset the timer */
+ gettimeofday(&now, NULL);
+
+ TIMEVAL_ADD(&now, tm, &timer->tm);
+
+ /* update the next expiration time */
+ if (TIMEVAL_LT(timer->tm, timer_head.tm))
+ timer_head.tm = timer->tm;
+
+ return;
+}
+
+/*
+ * Check expiration for each timer. If a timer expires,
+ * call the expire function for the timer and update the timer.
+ * Return the next interval for select() call.
+ */
+struct timeval *
+rtadvd_check_timer()
+{
+ static struct timeval returnval;
+ struct timeval now;
+ struct rtadvd_timer *tm = timer_head.next, *tm_next;
+
+ gettimeofday(&now, NULL);
+
+ timer_head.tm = tm_max;
+
+ for (tm = timer_head.next; tm != &timer_head; tm = tm_next) {
+ tm_next = tm->next;
+
+ if (TIMEVAL_LEQ(tm->tm, now)) {
+ if (((*tm->expire)(tm->expire_data) == NULL))
+ continue; /* the timer was removed */
+ if (tm->update)
+ (*tm->update)(tm->update_data, &tm->tm);
+ TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
+ }
+
+ if (TIMEVAL_LT(tm->tm, timer_head.tm))
+ timer_head.tm = tm->tm;
+ }
+
+ if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) {
+ /* no need to timeout */
+ return(NULL);
+ } else if (TIMEVAL_LT(timer_head.tm, now)) {
+ /* this may occur when the interval is too small */
+ returnval.tv_sec = returnval.tv_usec = 0;
+ } else
+ TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
+ return(&returnval);
+}
+
+struct timeval *
+rtadvd_timer_rest(struct rtadvd_timer *timer)
+{
+ static struct timeval returnval, now;
+
+ gettimeofday(&now, NULL);
+ if (TIMEVAL_LEQ(timer->tm, now)) {
+ debuglog("<%s> a timer must be expired, but not yet",
+ __func__);
+ returnval.tv_sec = returnval.tv_usec = 0;
+ }
+ else
+ TIMEVAL_SUB(&timer->tm, &now, &returnval);
+
+ return(&returnval);
+}
+
+/* result = a + b */
+void
+TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec + b->tv_usec) < MILLION) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec + b->tv_sec;
+ }
+ else {
+ result->tv_usec = l - MILLION;
+ result->tv_sec = a->tv_sec + b->tv_sec + 1;
+ }
+}
+
+/*
+ * result = a - b
+ * XXX: this function assumes that a >= b.
+ */
+void
+TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec - b->tv_usec) >= 0) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec - b->tv_sec;
+ }
+ else {
+ result->tv_usec = MILLION + l;
+ result->tv_sec = a->tv_sec - b->tv_sec - 1;
+ }
+}
diff --git a/network_cmds/rtadvd.tproj/timer.h b/network_cmds/rtadvd.tproj/timer.h
new file mode 100644
index 0000000..78314b7
--- /dev/null
+++ b/network_cmds/rtadvd.tproj/timer.h
@@ -0,0 +1,64 @@
+/* $KAME: timer.h,v 1.5 2002/05/31 13:30:38 jinmei Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+/* a < b */
+#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\
+ (((a).tv_sec == (b).tv_sec) && \
+ ((a).tv_usec < (b).tv_usec)))
+
+/* a <= b */
+#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\
+ (((a).tv_sec == (b).tv_sec) &&\
+ ((a).tv_usec <= (b).tv_usec)))
+
+struct rtadvd_timer {
+ struct rtadvd_timer *next;
+ struct rtadvd_timer *prev;
+ struct rainfo *rai;
+ struct timeval tm;
+
+ struct rtadvd_timer *(*expire)(void *); /* expiration function */
+ void *expire_data;
+ void (*update)(void *, struct timeval *); /* update function */
+ void *update_data;
+};
+
+void rtadvd_timer_init(void);
+struct rtadvd_timer *rtadvd_add_timer(struct rtadvd_timer *(*)(void *),
+ void (*)(void *, struct timeval *), void *, void *);
+void rtadvd_set_timer(struct timeval *, struct rtadvd_timer *);
+void rtadvd_remove_timer(struct rtadvd_timer **);
+struct timeval * rtadvd_check_timer(void);
+struct timeval * rtadvd_timer_rest(struct rtadvd_timer *);
+void TIMEVAL_ADD(struct timeval *, struct timeval *,
+ struct timeval *);
+void TIMEVAL_SUB(struct timeval *, struct timeval *,
+ struct timeval *);
diff --git a/network_cmds/rtsol.tproj/dump.c b/network_cmds/rtsol.tproj/dump.c
new file mode 100644
index 0000000..69937f0
--- /dev/null
+++ b/network_cmds/rtsol.tproj/dump.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: dump.c,v 1.8 2000/10/05 22:20:39 itojun Exp $ */
+
+/*
+ * Copyright (C) 1999 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/dump.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+#include <syslog.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "rtsold.h"
+
+static FILE *fp;
+
+extern struct ifinfo *iflist;
+
+static void dump_interface_status __P((void));
+static char *sec2str __P((time_t));
+char *ifstatstr[] = {
+ "IDLE", "DELAY", "PROBE", "DOWN", "TENTATIVE", "OPTIMISTIC"
+};
+
+static void
+dump_interface_status()
+{
+ struct ifinfo *ifinfo;
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
+ fprintf(fp, "Interface %s\n", ifinfo->ifname);
+ fprintf(fp, " probe interval: ");
+ if (ifinfo->probeinterval) {
+ fprintf(fp, "%d\n", ifinfo->probeinterval);
+ fprintf(fp, " probe timer: %d\n", ifinfo->probetimer);
+ }
+ else {
+ fprintf(fp, "infinity\n");
+ fprintf(fp, " no probe timer\n");
+ }
+ fprintf(fp, " interface status: %s\n",
+ ifinfo->active > 0 ? "active" : "inactive");
+ fprintf(fp, " rtsold status: %s\n", ifstatstr[ifinfo->state]);
+ fprintf(fp, " carrier detection: %s\n",
+ ifinfo->mediareqok ? "available" : "unavailable");
+ fprintf(fp, " probes: %d, dadcount = %d\n",
+ ifinfo->probes, ifinfo->dadcount);
+ if (ifinfo->timer.tv_sec == tm_max.tv_sec &&
+ ifinfo->timer.tv_usec == tm_max.tv_usec)
+ fprintf(fp, " no timer\n");
+ else {
+ fprintf(fp, " timer: interval=%d:%d, expire=%s\n",
+ (int)ifinfo->timer.tv_sec,
+ (int)ifinfo->timer.tv_usec,
+ (ifinfo->expire.tv_sec < now.tv_sec) ? "expired"
+ : sec2str(ifinfo->expire.tv_sec - now.tv_sec));
+ }
+ fprintf(fp, " number of valid RAs: %d\n", ifinfo->racnt);
+ }
+}
+
+void
+rtsold_dump_file(dumpfile)
+ char *dumpfile;
+{
+ if ((fp = fopen(dumpfile, "w")) == NULL) {
+ warnmsg(LOG_WARNING, __FUNCTION__, "open a dump file(%s): %s",
+ dumpfile, strerror(errno));
+ return;
+ }
+
+ dump_interface_status();
+
+ fclose(fp);
+}
+
+static char *
+sec2str(total)
+ time_t total;
+{
+ static char result[256];
+ int days, hours, mins, secs;
+ int first = 1;
+ char *p = result;
+
+ days = total / 3600 / 24;
+ hours = (total / 3600) % 24;
+ mins = (total / 60) % 60;
+ secs = total % 60;
+
+ if (days) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
+ }
+ if (!first || hours) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
+ }
+ if (!first || mins) {
+ first = 0;
+ p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
+ }
+ snprintf(p, sizeof(result) - (p - result), "%ds", secs);
+
+ return(result);
+}
diff --git a/network_cmds/rtsol.tproj/if.c b/network_cmds/rtsol.tproj/if.c
new file mode 100644
index 0000000..b46c781
--- /dev/null
+++ b/network_cmds/rtsol.tproj/if.c
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: if.c,v 1.15 2001/05/22 06:04:17 jinmei Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/if.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3 || defined (__APPLE__)
+#include <net/if_var.h>
+#endif /* __FreeBSD__ >= 3 */
+#include <net/if_types.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#if defined ( __FreeBSD__) || defined (__APPLE__)
+# include <net/ethernet.h>
+#endif
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#endif
+#if defined(__bsdi__) || defined(__OpenBSD__)
+# include <netinet/in.h>
+# include <netinet/if_ether.h>
+#endif
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+#include <netinet6/in6_var.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#endif
+
+#include "rtsold.h"
+
+extern int rssock;
+static int ifsock;
+
+static int get_llflag __P((const char *name));
+#ifndef HAVE_GETIFADDRS
+static unsigned int if_maxindex __P((void));
+#endif
+static void get_rtaddrs __P((int addrs, struct sockaddr *sa,
+ struct sockaddr **rti_info));
+
+int
+ifinit()
+{
+ ifsock = rssock;
+
+ return(0);
+}
+
+int
+interface_up(char *name)
+{
+ struct ifreq ifr;
+ int llflag;
+
+ strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ioctl(ifsock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ warnmsg(LOG_WARNING, __FUNCTION__, "ioctl(SIOCGIFFLAGS): %s",
+ strerror(errno));
+ return(-1);
+ }
+ if (!(ifr.ifr_flags & IFF_UP)) {
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(ifsock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "ioctl(SIOCSIFFLAGS): %s", strerror(errno));
+ }
+ return(-1);
+ }
+
+ warnmsg(LOG_DEBUG, __FUNCTION__, "checking if %s is ready...", name);
+
+ llflag = get_llflag(name);
+ if (llflag < 0) {
+ warnmsg(LOG_WARNING, __FUNCTION__,
+ "get_llflag() failed, anyway I'll try");
+ return 0;
+ }
+
+ if (!(llflag & (IN6_IFF_NOTREADY | IN6_IFF_DADPROGRESS))) {
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "%s is ready", name);
+ return(0);
+ } else {
+ if (llflag & IN6_IFF_TENTATIVE) {
+ warnmsg(LOG_DEBUG, __FUNCTION__, "%s is tentative",
+ name);
+ return IFS_TENTATIVE;
+ }
+ if (llflag & IN6_IFF_OPTIMISTIC) {
+ warnmsg(LOG_DEBUG, __FUNCTION__, "%s is optimistic",
+ name);
+ return IFS_OPTIMISTIC;
+ }
+ if (llflag & IN6_IFF_DUPLICATED)
+ warnmsg(LOG_DEBUG, __FUNCTION__, "%s is duplicated",
+ name);
+ return -1;
+ }
+}
+
+int
+interface_status(struct ifinfo *ifinfo)
+{
+ char *ifname = ifinfo->ifname;
+ struct ifreq ifr;
+ struct ifmediareq ifmr;
+
+ /* get interface flags */
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(ifsock, SIOCGIFFLAGS, &ifr) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGIFFLAGS) on %s: %s",
+ ifname, strerror(errno));
+ return(-1);
+ }
+ /*
+ * if one of UP and RUNNING flags is dropped,
+ * the interface is not active.
+ */
+ if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+ goto inactive;
+ }
+
+ /* Next, check carrier on the interface, if possible */
+ if (!ifinfo->mediareqok)
+ goto active;
+ memset(&ifmr, 0, sizeof(ifmr));
+ strlcpy(ifmr.ifm_name, ifname, sizeof(ifmr.ifm_name));
+
+ if (ioctl(ifsock, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+ if (errno != EINVAL) {
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "ioctl(SIOCGIFMEDIA) on %s: %s",
+ ifname, strerror(errno));
+ return(-1);
+ }
+ /*
+ * EINVAL simply means that the interface does not support
+ * the SIOCGIFMEDIA ioctl. We regard it alive.
+ */
+ ifinfo->mediareqok = 0;
+ goto active;
+ }
+
+ if (ifmr.ifm_status & IFM_AVALID) {
+ switch(ifmr.ifm_active & IFM_NMASK) {
+ case IFM_ETHER:
+ if (ifmr.ifm_status & IFM_ACTIVE)
+ goto active;
+ else
+ goto inactive;
+ break;
+ default:
+ goto inactive;
+ }
+ }
+
+ inactive:
+ return(0);
+
+ active:
+ return(1);
+}
+
+#define ROUNDUP(a, size) \
+ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
+
+#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
+ ((caddr_t)(ap) + ((ap)->sa_len ? ROUNDUP((ap)->sa_len,\
+ sizeof(uint32_t)) :\
+ sizeof(uint32_t)))
+#define ROUNDUP8(a) (1 + (((a) - 1) | 7))
+
+int
+lladdropt_length(struct sockaddr_dl *sdl)
+{
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
+ return(ROUNDUP8(ETHER_ADDR_LEN + 2));
+ default:
+ return(0);
+ }
+}
+
+void
+lladdropt_fill(struct sockaddr_dl *sdl, struct nd_opt_hdr *ndopt)
+{
+ char *addr;
+
+ ndopt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; /* fixed */
+
+ switch(sdl->sdl_type) {
+ case IFT_ETHER:
+#ifdef IFT_IEEE80211
+ case IFT_IEEE80211:
+#endif
+ ndopt->nd_opt_len = (ROUNDUP8(ETHER_ADDR_LEN + 2)) >> 3;
+ addr = (char *)(ndopt + 1);
+ memcpy(addr, LLADDR(sdl), ETHER_ADDR_LEN);
+ break;
+ default:
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "unsupported link type(%d)", sdl->sdl_type);
+ exit(1);
+ }
+
+ return;
+}
+
+struct sockaddr_dl *
+if_nametosdl(char *name)
+{
+ int mib[6] = {CTL_NET, AF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
+ char *buf, *next, *lim;
+ size_t len;
+ struct if_msghdr *ifm;
+ struct sockaddr *sa, *rti_info[RTAX_MAX];
+ struct sockaddr_dl *sdl = NULL, *ret_sdl;
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return(NULL);
+ if ((buf = malloc(len)) == NULL)
+ return(NULL);
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ free(buf);
+ return(NULL);
+ }
+
+ lim = buf + len;
+ for (next = buf; next < lim; next += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)next;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ sa = (struct sockaddr *)(ifm + 1);
+ get_rtaddrs(ifm->ifm_addrs, sa, rti_info);
+ if ((sa = rti_info[RTAX_IFP]) != NULL) {
+ if (sa->sa_family == AF_LINK) {
+ sdl = (struct sockaddr_dl *)sa;
+ if (strlen(name) != sdl->sdl_nlen)
+ continue; /* not same len */
+ if (strncmp(&sdl->sdl_data[0],
+ name,
+ sdl->sdl_nlen) == 0) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (next == lim) {
+ /* search failed */
+ free(buf);
+ return(NULL);
+ }
+
+ if ((ret_sdl = malloc(sdl->sdl_len)) == NULL)
+ return(NULL);
+ memcpy((caddr_t)ret_sdl, (caddr_t)sdl, sdl->sdl_len);
+
+ free(buf);
+ return(ret_sdl);
+}
+
+int
+getinet6sysctl(int code)
+{
+ int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, 0 };
+ int value;
+ size_t size;
+
+ mib[3] = code;
+ size = sizeof(value);
+ if (sysctl(mib, sizeof(mib)/sizeof(mib[0]), &value, &size, NULL, 0) < 0)
+ return -1;
+ else
+ return value;
+}
+
+/*------------------------------------------------------------*/
+
+/* get ia6_flags for link-local addr on if. returns -1 on error. */
+static int
+get_llflag(const char *name)
+{
+#ifdef HAVE_GETIFADDRS
+ struct ifaddrs *ifap, *ifa;
+ struct in6_ifreq ifr6;
+ struct sockaddr_in6 *sin6;
+ int s;
+
+ if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket(SOCK_DGRAM): %s",
+ strerror(errno));
+ exit(1);
+ }
+ if (getifaddrs(&ifap) != 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "etifaddrs: %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if (strlen(ifa->ifa_name) != strlen(name)
+ || strncmp(ifa->ifa_name, name, strlen(name)) != 0)
+ continue;
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ continue;
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
+ memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len);
+ if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno));
+ exit(1);
+ }
+
+ freeifaddrs(ifap);
+ close(s);
+ return ifr6.ifr_ifru.ifru_flags6;
+ }
+
+ freeifaddrs(ifap);
+ close(s);
+ return -1;
+#else
+ int s;
+ unsigned int maxif;
+ struct ifreq *iflist;
+ struct ifconf ifconf;
+ struct ifreq *ifr, *ifr_end;
+ struct sockaddr_in6 *sin6;
+ struct in6_ifreq ifr6;
+
+ maxif = if_maxindex() + 1;
+ iflist = (struct ifreq *)malloc(maxif * BUFSIZ); /* XXX */
+ if (iflist == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__, "not enough core");
+ exit(1);
+ }
+
+ if ((s = socket(PF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket(SOCK_DGRAM): %s",
+ strerror(errno));
+ exit(1);
+ }
+ memset(&ifconf, 0, sizeof(ifconf));
+ ifconf.ifc_req = iflist;
+ ifconf.ifc_len = maxif * BUFSIZ; /* XXX */
+ if (ioctl(s, SIOCGIFCONF, &ifconf) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGIFCONF): %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ /* Look for this interface in the list */
+ ifr_end = (struct ifreq *) (ifconf.ifc_buf + ifconf.ifc_len);
+ for (ifr = ifconf.ifc_req;
+ ifr < ifr_end;
+ ifr = (struct ifreq *) ((char *) &ifr->ifr_addr
+ + ifr->ifr_addr.sa_len)) {
+ if (strlen(ifr->ifr_name) != strlen(name)
+ || strncmp(ifr->ifr_name, name, strlen(name)) != 0)
+ continue;
+ if (ifr->ifr_addr.sa_family != AF_INET6)
+ continue;
+ sin6 = (struct sockaddr_in6 *)&ifr->ifr_addr;
+ if (!IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ continue;
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ strlcpy(ifr6.ifr_name, name, sizeof(ifr6.ifr_name));
+ memcpy(&ifr6.ifr_ifru.ifru_addr, sin6, sin6->sin6_len);
+ if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "ioctl(SIOCGIFAFLAG_IN6): %s", strerror(errno));
+ exit(1);
+ }
+
+ free(iflist);
+ close(s);
+ return ifr6.ifr_ifru.ifru_flags6;
+ }
+
+ free(iflist);
+ close(s);
+ return -1;
+#endif
+}
+
+#ifndef HAVE_GETIFADDRS
+static unsigned int
+if_maxindex()
+{
+ struct if_nameindex *p, *p0;
+ unsigned int max = 0;
+
+ p0 = if_nameindex();
+ for (p = p0; p && p->if_index && p->if_name; p++) {
+ if (max < p->if_index)
+ max = p->if_index;
+ }
+ if_freenameindex(p0);
+ return max;
+}
+#endif
+
+static void
+get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
+{
+ int i;
+
+ for (i = 0; i < RTAX_MAX; i++) {
+ if (addrs & (1 << i)) {
+ rti_info[i] = sa;
+ NEXT_SA(sa);
+ }
+ else
+ rti_info[i] = NULL;
+ }
+}
diff --git a/network_cmds/rtsol.tproj/probe.c b/network_cmds/rtsol.tproj/probe.c
new file mode 100644
index 0000000..305d0a2
--- /dev/null
+++ b/network_cmds/rtsol.tproj/probe.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/* $KAME: probe.c,v 1.10 2000/08/13 06:14:59 itojun Exp $ */
+
+/*
+ * Copyright (C) 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/probe.c,v 1.2.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#if defined(__FreeBSD__) && __FreeBSD__ >= 3
+#include <net/if_var.h>
+#endif /* __FreeBSD__ >= 3 */
+
+#include <netinet/in.h>
+#include <netinet6/in6_var.h>
+#include <netinet/icmp6.h>
+#include <netinet6/nd6.h>
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <stdlib.h>
+
+#include "rtsold.h"
+
+static struct msghdr sndmhdr;
+static struct iovec sndiov[2];
+static int probesock;
+static void sendprobe __P((struct in6_addr *addr, int ifindex));
+
+
+int
+probe_init()
+{
+ int scmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ static u_char *sndcmsgbuf = NULL;
+
+ if (sndcmsgbuf == NULL &&
+ (sndcmsgbuf = (u_char *)malloc(scmsglen)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__, "malloc failed");
+ return(-1);
+ }
+
+ if ((probesock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
+ return(-1);
+ }
+
+#ifndef __APPLE__
+ /* make the socket send-only */
+ if (shutdown(probesock, 0)) {
+ warnmsg(LOG_ERR, __FUNCTION__, "shutdown: %s", strerror(errno));
+ return(-1);
+ }
+#endif /* __APPLE__ */
+
+ /* initialize msghdr for sending packets */
+ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ sndmhdr.msg_iov = sndiov;
+ sndmhdr.msg_iovlen = 1;
+ sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
+ sndmhdr.msg_controllen = scmsglen;
+
+ return(0);
+}
+
+/*
+ * Probe if each router in the default router list is still alive.
+ */
+void
+defrouter_probe(int ifindex)
+{
+ struct in6_drlist dr;
+ int s, i;
+ u_char ntopbuf[INET6_ADDRSTRLEN];
+
+ if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
+ return;
+ }
+ bzero(&dr, sizeof(dr));
+ strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy interface */
+ if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "ioctl(SIOCGDRLST_IN6): %s",
+ strerror(errno));
+ goto closeandend;
+ }
+
+ for(i = 0; dr.defrouter[i].if_index && i < PRLSTSIZ; i++) {
+ if (ifindex && dr.defrouter[i].if_index == ifindex) {
+ /* sanity check */
+ if (!IN6_IS_ADDR_LINKLOCAL(&dr.defrouter[i].rtaddr)) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "default router list contains a "
+ "non-linklocal address(%s)",
+ inet_ntop(AF_INET6,
+ &dr.defrouter[i].rtaddr,
+ (char *)ntopbuf, INET6_ADDRSTRLEN));
+ continue; /* ignore the address */
+ }
+ sendprobe(&dr.defrouter[i].rtaddr,
+ dr.defrouter[i].if_index);
+ }
+ }
+
+ closeandend:
+ close(s);
+ return;
+}
+
+static void
+sendprobe(struct in6_addr *addr, int ifindex)
+{
+ struct sockaddr_in6 sa6_probe;
+ struct in6_pktinfo *pi;
+ struct cmsghdr *cm;
+ u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];;
+
+ bzero(&sa6_probe, sizeof(sa6_probe));
+ sa6_probe.sin6_family = AF_INET6;
+ sa6_probe.sin6_len = sizeof(sa6_probe);
+ sa6_probe.sin6_addr = *addr;
+
+ sndmhdr.msg_name = (caddr_t)&sa6_probe;
+ sndmhdr.msg_iov[0].iov_base = NULL;
+ sndmhdr.msg_iov[0].iov_len = 0;
+
+ cm = CMSG_FIRSTHDR(&sndmhdr);
+ /* specify the outgoing interface */
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
+ pi->ipi6_ifindex = ifindex;
+
+ /* specify the hop limit of the packet for safety */
+ {
+ int hoplimit = 1;
+
+ cm = CMSG_NXTHDR(&sndmhdr, cm);
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_HOPLIMIT;
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ }
+
+ warnmsg(LOG_DEBUG, __FUNCTION__, "probe a router %s on %s",
+ inet_ntop(AF_INET6, addr, (char *)ntopbuf, INET6_ADDRSTRLEN),
+ if_indextoname(ifindex, (char *)ifnamebuf));
+
+ if (sendmsg(probesock, &sndmhdr, 0))
+ warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s",
+ if_indextoname(ifindex, (char *)ifnamebuf), strerror(errno));
+
+ return;
+}
diff --git a/network_cmds/rtsol.tproj/rtsock.c b/network_cmds/rtsol.tproj/rtsock.c
new file mode 100644
index 0000000..e3f16e4
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsock.c
@@ -0,0 +1,179 @@
+/* $KAME: rtsock.c,v 1.3 2000/10/10 08:46:45 itojun Exp $ */
+/* $FreeBSD: src/usr.sbin/rtsold/rtsock.c,v 1.1.2.1 2001/07/03 11:02:16 ume Exp $ */
+
+/*
+ * Copyright (C) 2000 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include "rtsold.h"
+
+#define ROUNDUP(a, size) \
+ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
+
+#define NEXT_SA(ap) (ap) = (struct sockaddr *) \
+ ((caddr_t)(ap) + \
+ ((ap)->sa_len ? ROUNDUP((ap)->sa_len, sizeof(uint32_t)) \
+ : sizeof(uint32_t)))
+
+#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
+static int rtsock_input_ifannounce __P((int, struct rt_msghdr *, char *));
+#endif
+
+static struct {
+ u_char type;
+ size_t minlen;
+ int (*func) __P((int, struct rt_msghdr *, char *));
+} rtsock_dispatch[] = {
+#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
+ { RTM_IFANNOUNCE, sizeof(struct if_announcemsghdr),
+ rtsock_input_ifannounce },
+#endif
+ { 0, 0UL, NULL },
+};
+
+int
+rtsock_open()
+{
+
+ return socket(PF_ROUTE, SOCK_RAW, 0);
+}
+
+int
+rtsock_input(s)
+ int s;
+{
+ ssize_t n;
+ char msg[2048];
+ char *lim, *next;
+ struct rt_msghdr *rtm;
+ int idx;
+ size_t len;
+ int ret = 0;
+ const size_t lenlim =
+ offsetof(struct rt_msghdr, rtm_msglen) + sizeof(rtm->rtm_msglen);
+
+ n = read(s, msg, sizeof(msg));
+
+ lim = msg + n;
+ for (next = msg; next < lim; next += len) {
+ rtm = (struct rt_msghdr *)next;
+ if (lim - next < lenlim)
+ break;
+ len = rtm->rtm_msglen;
+ if (len < lenlim)
+ break;
+
+ if (dflag > 1) {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "rtmsg type %d, len=%lu", rtm->rtm_type,
+ (u_long)len);
+ }
+
+ for (idx = 0; rtsock_dispatch[idx].func; idx++) {
+ if (rtm->rtm_type != rtsock_dispatch[idx].type)
+ continue;
+ if (rtm->rtm_msglen < rtsock_dispatch[idx].minlen) {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "rtmsg type %d too short!", rtm->rtm_type);
+ continue;
+ }
+
+ ret = (*rtsock_dispatch[idx].func)(s, rtm, lim);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+#ifdef RTM_IFANNOUNCE /*NetBSD 1.5 or later*/
+static int
+rtsock_input_ifannounce(s, rtm, lim)
+ int s;
+ struct rt_msghdr *rtm;
+ char *lim;
+{
+ struct if_announcemsghdr *ifan;
+ struct ifinfo *ifinfo;
+
+ ifan = (struct if_announcemsghdr *)rtm;
+ if ((char *)(ifan + 1) > lim)
+ return -1;
+
+ switch (ifan->ifan_what) {
+ case IFAN_ARRIVAL:
+ /*
+ * XXX for NetBSD 1.5, interface index will monotonically be
+ * increased as new pcmcia card gets inserted.
+ * we may be able to do a name-based interface match,
+ * and call ifreconfig() to enable the interface again.
+ */
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "interface %s inserted", ifan->ifan_name);
+ break;
+ case IFAN_DEPARTURE:
+ warnmsg(LOG_WARNING, __FUNCTION__,
+ "interface %s removed", ifan->ifan_name);
+ ifinfo = find_ifinfo(ifan->ifan_index);
+ if (ifinfo) {
+ if (dflag > 1) {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "bring interface %s to DOWN state",
+ ifan->ifan_name);
+ }
+ ifinfo->state = IFS_DOWN;
+ }
+ break;
+ }
+
+ return 0;
+}
+#endif
diff --git a/network_cmds/rtsol.tproj/rtsol.8 b/network_cmds/rtsol.tproj/rtsol.8
new file mode 100644
index 0000000..30c3768
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsol.8
@@ -0,0 +1,224 @@
+.\" $KAME: rtsold.8,v 1.16 2000/10/15 13:19:05 itojun Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.sbin/rtsold/rtsold.8,v 1.1.2.5 2001/08/16 15:56:30 ru Exp $
+.\"
+.Dd May 17, 1998
+.Dt RTSOLD 8
+.Os
+.\"
+.Sh NAME
+.Nm rtsold
+.Nd router solicitation daemon
+.\"
+.Sh SYNOPSIS
+.Nm
+.Op Fl dDfm1
+.Ar interface ...
+.Nm
+.Op Fl dDfm1
+.Fl a
+.Nm rtsol
+.Op Fl dD
+.Ar interface ...
+.Nm rtsol
+.Op Fl dD
+.Fl a
+.\"
+.Sh DESCRIPTION
+.Nm
+is the daemon program to send ICMPv6 Router Solicitation messages
+on the specified interfaces.
+If a node (re)attaches to a link,
+.Nm
+sends some Router Solicitations on the link destined to the link-local scope
+all-routers multicast address to discover new routers
+and to get non link-local addresses.
+.Pp
+.Nm
+should be used on IPv6 hosts
+(non-router nodes)
+only.
+.Pp
+If you invoke the program as
+.Nm rtsol ,
+it will transmit probes from the specified
+.Ar interface ,
+without becoming a daemon.
+In other words,
+.Nm rtsol
+behaves as
+.Do
+.Nm
+.Fl f1
+.Ar interfaces
+.Dc .
+.Pp
+Specifically,
+.Nm
+sends at most 3 Router Solicitations on an interface
+after one of the following events:
+.Pp
+.Bl -bullet -compact
+.It
+Just after invocation of
+.Nm
+daemon.
+.It
+The interface is up after a temporary interface failure.
+.Nm
+detects such failures by periodically probing to see if the status
+of the interface is active or not.
+Note that some network cards and drivers do not allow the extraction
+of link state.
+In such cases,
+.Nm
+cannot detect the change of the interface status.
+.It
+Every 60 seconds if the
+.Fl m
+option is specified and the
+.Nm
+daemon cannot get the interface status.
+This feature does not conform to the IPv6 neighbor discovery
+specification, but is provided for mobile stations.
+The default interval for router advertisements, which is on the order of 10
+minutes, is slightly long for mobile stations.
+This feature is provided
+for such stations so that they can find new routers as soon as possible
+when they attach to another link.
+.El
+.Lp
+Once
+.Nm
+has sent a Router Solicitation, and has received a valid Router Advertisement,
+it refrains from sending additional solicitations on that interface, until
+the next time one of the above events occurs.
+.Lp
+When sending a Router Solicitation on an interface,
+.Nm
+includes a Source Link-layer address option if the interface
+has a link-layer address.
+.Pp
+Upon receipt of signal
+.Dv SIGUSR1 ,
+.Nm
+will dump the current internal state into
+.Pa /var/run/rtsold.dump .
+.\"
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl a
+Autoprobe outgoing interface.
+.Nm
+will try to find a non-loopback, non-point-to-point, IPv6-capable interface.
+If
+.Nm
+finds multiple interfaces,
+.Nm
+will exit with error.
+.\"
+.It Fl d
+Enable debugging.
+.It Fl D
+Enable more debugging including the printing of internal timer information.
+.It Fl f
+.Fl f
+prevents
+.Nm
+from becoming a daemon (foreground mode).
+Warning messages are generated to standard error
+instead of
+.Xr syslog 3 .
+.It Fl m
+Enable mobility support.
+If this option is specified,
+.Nm
+sends probing packets to default routers that have advertised Router
+Advertisements
+when the node (re)attaches to an interface.
+Moreover, if the option is specified,
+.Nm
+periodically sends Router Solicitation on an interface that does not support
+.Dv SIOCGIFMEDIA
+ioctl.
+.It Fl 1
+Perform only one probe.
+Transmit Router Solicitation packets until at least one valid Router
+Advertisement packet has arrived on each
+.Ar interface ,
+then exit.
+.El
+.Sh DIAGNOSTICS
+.Ex -std
+.\"
+.Sh FILES
+.Bl -tag -width /var/run/rtsold.dump -compact
+.It Pa /var/run/rtsold.pid
+the pid of the currently running
+.Nm .
+.It Pa /var/run/rtsold.dump
+dumps internal state on.
+.El
+.\"
+.Sh SEE ALSO
+.Xr rtadvd 8 ,
+.Xr sysctl 8
+.\"
+.Sh HISTORY
+The
+.Nm
+command is based on the
+.Nm rtsol
+command, which first appeared in WIDE/KAME IPv6 protocol stack kit.
+.Nm rtsol
+is now integrated into
+.Xr rtsold 8 .
+.\"
+.Sh BUGS
+In some operating systems, when a PCMCIA network card is removed
+and reinserted, the corresponding interface index is changed.
+However,
+.Nm
+assumes such changes will not occur, and always uses the index that
+it got at invocation. As a result,
+.Nm
+may not work if you reinsert a network card.
+In such a case,
+.Nm
+should be killed and restarted.
+.Pp
+The IPv6 autoconfiguration specification assumes a single-interface host.
+You may see kernel error messages if you try to autoconfigure a host with
+multiple interfaces.
+Also, it seems contradictory for
+.Nm
+to accept multiple
+.Ar interface
+arguments.
diff --git a/network_cmds/rtsol.tproj/rtsol.c b/network_cmds/rtsol.tproj/rtsol.c
new file mode 100644
index 0000000..e1b9bff
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsol.c
@@ -0,0 +1,343 @@
+/* $KAME: rtsol.c,v 1.11 2000/08/13 06:14:59 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/rtsol.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet6/ip6_var.h>
+#include <netinet/icmp6.h>
+
+#include <arpa/inet.h>
+
+#include <time.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include "rtsold.h"
+
+#define ALLROUTER "ff02::2"
+
+static struct msghdr rcvmhdr;
+static struct msghdr sndmhdr;
+static struct iovec rcviov[2];
+static struct iovec sndiov[2];
+static struct sockaddr_in6 from;
+
+int rssock;
+
+static struct sockaddr_in6 sin6_allrouters = {sizeof(sin6_allrouters), AF_INET6};
+
+int
+sockopen()
+{
+ int on;
+ struct icmp6_filter filt;
+ static u_char answer[1500];
+ int rcvcmsglen, sndcmsglen;
+ static u_char *rcvcmsgbuf = NULL, *sndcmsgbuf = NULL;
+
+ sndcmsglen = rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ if (rcvcmsgbuf == NULL && (rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "malloc for receive msghdr failed");
+ return(-1);
+ }
+ if (sndcmsgbuf == NULL && (sndcmsgbuf = malloc(sndcmsglen)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "malloc for send msghdr failed");
+ return(-1);
+ }
+ memset(&sin6_allrouters, 0, sizeof(struct sockaddr_in6));
+ if (inet_pton(AF_INET6, ALLROUTER,
+ &sin6_allrouters.sin6_addr.s6_addr) != 1) {
+ warnmsg(LOG_ERR, __FUNCTION__, "inet_pton failed for %s",
+ ALLROUTER);
+ return(-1);
+ }
+
+ if ((rssock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "socket: %s", strerror(errno));
+ return(-1);
+ }
+
+ /* specify to tell receiving interface */
+ on = 1;
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ sizeof(on)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "IPV6_RECVPKTINFO: %s",
+ strerror(errno));
+ exit(1);
+ }
+#else /* old adv. API */
+ if (setsockopt(rssock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
+ sizeof(on)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "IPV6_PKTINFO: %s",
+ strerror(errno));
+ exit(1);
+ }
+#endif
+
+ on = 1;
+ /* specify to tell value of hoplimit field of received IP6 hdr */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(rssock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "IPV6_RECVHOPLIMIT: %s",
+ strerror(errno));
+ exit(1);
+ }
+#else /* old adv. API */
+ if (setsockopt(rssock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
+ sizeof(on)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "IPV6_HOPLIMIT: %s",
+ strerror(errno));
+ exit(1);
+ }
+#endif
+
+ /* specfiy to accept only router advertisements on the socket */
+ ICMP6_FILTER_SETBLOCKALL(&filt);
+ ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt);
+ if (setsockopt(rssock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
+ sizeof(filt)) == -1) {
+ warnmsg(LOG_ERR, __FUNCTION__, "setsockopt(ICMP6_FILTER): %s",
+ strerror(errno));
+ return(-1);
+ }
+
+ /* initialize msghdr for receiving packets */
+ rcviov[0].iov_base = (caddr_t)answer;
+ rcviov[0].iov_len = sizeof(answer);
+ rcvmhdr.msg_name = (caddr_t)&from;
+ rcvmhdr.msg_namelen = sizeof(from);
+ rcvmhdr.msg_iov = rcviov;
+ rcvmhdr.msg_iovlen = 1;
+ rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
+ rcvmhdr.msg_controllen = rcvcmsglen;
+
+ /* initialize msghdr for sending packets */
+ sndmhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ sndmhdr.msg_iov = sndiov;
+ sndmhdr.msg_iovlen = 1;
+ sndmhdr.msg_control = (caddr_t)sndcmsgbuf;
+ sndmhdr.msg_controllen = sndcmsglen;
+
+ return(rssock);
+}
+
+void
+sendpacket(struct ifinfo *ifinfo)
+{
+ int i;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi;
+
+ sndmhdr.msg_name = (caddr_t)&sin6_allrouters;
+ sndmhdr.msg_iov[0].iov_base = (caddr_t)ifinfo->rs_data;
+ sndmhdr.msg_iov[0].iov_len = ifinfo->rs_datalen;
+
+ cm = CMSG_FIRSTHDR(&sndmhdr);
+ /* specify the outgoing interface */
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_PKTINFO;
+ cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ pi = (struct in6_pktinfo *)CMSG_DATA(cm);
+ memset(&pi->ipi6_addr, 0, sizeof(pi->ipi6_addr)); /*XXX*/
+ pi->ipi6_ifindex = ifinfo->sdl->sdl_index;
+
+ /* specify the hop limit of the packet */
+ {
+ int hoplimit = 255;
+
+ cm = CMSG_NXTHDR(&sndmhdr, cm);
+ cm->cmsg_level = IPPROTO_IPV6;
+ cm->cmsg_type = IPV6_HOPLIMIT;
+ cm->cmsg_len = CMSG_LEN(sizeof(int));
+ memcpy(CMSG_DATA(cm), &hoplimit, sizeof(int));
+ }
+
+ warnmsg(LOG_DEBUG,
+ __FUNCTION__, "send RS on %s, whose state is %d",
+ ifinfo->ifname, ifinfo->state);
+
+ i = sendmsg(rssock, &sndmhdr, 0);
+
+ if (i < 0 || i != ifinfo->rs_datalen) {
+ /*
+ * ENETDOWN is not so serious, especially when using several
+ * network cards on a mobile node. We ignore it.
+ */
+ if (errno != ENETDOWN || dflag > 0)
+ warnmsg(LOG_ERR, __FUNCTION__, "sendmsg on %s: %s",
+ ifinfo->ifname, strerror(errno));
+ }
+
+ /* update counter */
+ ifinfo->probes++;
+}
+
+void
+rtsol_input(int s)
+{
+ int i;
+ int *hlimp = NULL;
+ struct icmp6_hdr *icp;
+ int ifindex = 0;
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi = NULL;
+ struct ifinfo *ifi = NULL;
+ u_char ntopbuf[INET6_ADDRSTRLEN], ifnamebuf[IFNAMSIZ];
+
+ /* get message */
+ if ((i = recvmsg(s, &rcvmhdr, 0)) < 0) {
+ warnmsg(LOG_ERR, __FUNCTION__, "recvmsg: %s", strerror(errno));
+ return;
+ }
+
+ /* extract optional information via Advanced API */
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&rcvmhdr);
+ cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(&rcvmhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) {
+ pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
+ ifindex = pi->ipi6_ifindex;
+ }
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ hlimp = (int *)CMSG_DATA(cm);
+ }
+
+ if (ifindex == 0) {
+ warnmsg(LOG_ERR,
+ __FUNCTION__, "failed to get receiving interface");
+ return;
+ }
+ if (hlimp == NULL) {
+ warnmsg(LOG_ERR,
+ __FUNCTION__, "failed to get receiving hop limit");
+ return;
+ }
+
+ if (i < sizeof(struct nd_router_advert)) {
+ warnmsg(LOG_ERR,
+ __FUNCTION__, "packet size(%d) is too short", i);
+ return;
+ }
+
+ icp = (struct icmp6_hdr *)rcvmhdr.msg_iov[0].iov_base;
+
+ if (icp->icmp6_type != ND_ROUTER_ADVERT) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "invalid icmp type(%d) from %s on %s", icp->icmp6_type,
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ if (icp->icmp6_code != 0) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "invalid icmp code(%d) from %s on %s", icp->icmp6_code,
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ if (*hlimp != 255) {
+ warnmsg(LOG_NOTICE, __FUNCTION__,
+ "invalid RA with hop limit(%d) from %s on %s",
+ *hlimp,
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ if (pi && !IN6_IS_ADDR_LINKLOCAL(&from.sin6_addr)) {
+ warnmsg(LOG_NOTICE, __FUNCTION__,
+ "invalid RA with non link-local source from %s on %s",
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ /* xxx: more validation? */
+
+ if ((ifi = find_ifinfo(pi->ipi6_ifindex)) == NULL) {
+ warnmsg(LOG_NOTICE, __FUNCTION__,
+ "received RA from %s on an unexpeced IF(%s)",
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ if_indextoname(pi->ipi6_ifindex, (char *)ifnamebuf));
+ return;
+ }
+
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "received RA from %s on %s, state is %d",
+ inet_ntop(AF_INET6, &from.sin6_addr, (char *)ntopbuf,
+ INET6_ADDRSTRLEN),
+ ifi->ifname, ifi->state);
+
+ ifi->racnt++;
+
+ switch(ifi->state) {
+ case IFS_IDLE: /* should be ignored */
+ case IFS_DELAY: /* right? */
+ break;
+ case IFS_PROBE:
+ ifi->state = IFS_IDLE;
+ ifi->probes = 0;
+ rtsol_timer_update(ifi);
+ break;
+ }
+}
diff --git a/network_cmds/rtsol.tproj/rtsold.c b/network_cmds/rtsol.tproj/rtsold.c
new file mode 100644
index 0000000..68923ec
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsold.c
@@ -0,0 +1,791 @@
+/* $KAME: rtsold.c,v 1.31 2001/05/22 06:03:06 jinmei Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/rtsold.c,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+#include <signal.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <err.h>
+#include <stdarg.h>
+#include <ifaddrs.h>
+#include "rtsold.h"
+
+struct ifinfo *iflist;
+struct timeval tm_max = {0x7fffffff, 0x7fffffff};
+int aflag = 0;
+int dflag = 0;
+static int log_upto = 999;
+static int fflag = 0;
+
+/* protocol constatns */
+#define MAX_RTR_SOLICITATION_DELAY 1 /* second */
+#define RTR_SOLICITATION_INTERVAL 4 /* seconds */
+#define MAX_RTR_SOLICITATIONS 3 /* times */
+
+/* implementation dependent constants */
+#define PROBE_INTERVAL 60 /* secondes XXX: should be configurable */
+
+/* utility macros */
+/* a < b */
+#define TIMEVAL_LT(a, b) (((a).tv_sec < (b).tv_sec) ||\
+ (((a).tv_sec == (b).tv_sec) && \
+ ((a).tv_usec < (b).tv_usec)))
+
+/* a <= b */
+#define TIMEVAL_LEQ(a, b) (((a).tv_sec < (b).tv_sec) ||\
+ (((a).tv_sec == (b).tv_sec) &&\
+ ((a).tv_usec <= (b).tv_usec)))
+
+/* a == b */
+#define TIMEVAL_EQ(a, b) (((a).tv_sec==(b).tv_sec) && ((a).tv_usec==(b).tv_usec))
+
+int main __P((int argc, char *argv[]));
+
+/* static variables and functions */
+static int mobile_node = 0;
+static int do_dump;
+static char *dumpfilename = "/var/run/rtsold.dump"; /* XXX: should be configurable */
+static char *pidfilename = "/var/run/rtsold.pid"; /* should be configurable */
+
+static int ifconfig __P((char *ifname));
+#if 0
+static int ifreconfig __P((char *ifname));
+#endif
+static int make_packet __P((struct ifinfo *ifinfo));
+static struct timeval *rtsol_check_timer __P((void));
+static void TIMEVAL_ADD __P((struct timeval *a, struct timeval *b,
+ struct timeval *result));
+static void TIMEVAL_SUB __P((struct timeval *a, struct timeval *b,
+ struct timeval *result));
+
+static void rtsold_set_dump_file __P((void));
+static void usage __P((char *progname));
+static char **autoifprobe __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int s, rtsock, maxfd, ch;
+ int once = 0;
+ struct timeval *timeout;
+ struct fd_set fdset;
+ char *argv0;
+ char *opts;
+
+ /*
+ * Initialization
+ */
+ argv0 = argv[0];
+
+ /* get option */
+ if (argv0 && argv0[strlen(argv0) - 1] != 'd') {
+ fflag = 1;
+ once = 1;
+ opts = "adD";
+ } else
+ opts = "adDfm1";
+
+ while ((ch = getopt(argc, argv, opts)) != -1) {
+ switch (ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'D':
+ dflag = 2;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'm':
+ mobile_node = 1;
+ break;
+ case '1':
+ once = 1;
+ break;
+ default:
+ usage(argv0);
+ /*NOTREACHED*/
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (aflag) {
+ int i;
+
+ if (argc != 0) {
+ usage(argv0);
+ /*NOTREACHED*/
+ }
+
+ argv = autoifprobe();
+ if (!argv) {
+ errx(1, "could not autoprobe interface");
+ /*NOTREACHED*/
+ }
+
+ for (i = 0; argv[i]; i++)
+ ;
+ argc = i;
+ }
+ if (argc == 0) {
+ usage(argv0);
+ /*NOTREACHED*/
+ }
+
+ /* set log level */
+ if (dflag == 0)
+ log_upto = LOG_NOTICE;
+ if (!fflag) {
+ char *ident;
+ ident = strrchr(argv0, '/');
+ if (!ident)
+ ident = argv0;
+ else
+ ident++;
+ openlog(ident, LOG_NDELAY|LOG_PID, LOG_DAEMON);
+ if (log_upto >= 0)
+ setlogmask(LOG_UPTO(log_upto));
+ }
+
+#ifndef HAVE_ARC4RANDOM
+ /* random value initilization */
+ srandom((u_long)time(NULL));
+#endif
+
+ /* warn if accept_rtadv is down */
+ if (!getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
+ warnx("kernel is configured not to accept RAs");
+ /* warn if forwarding is up */
+ if (getinet6sysctl(IPV6CTL_FORWARDING))
+ warnx("kernel is configured as a router, not a host");
+
+ /* initialization to dump internal status to a file */
+ if (signal(SIGUSR1, (void *)rtsold_set_dump_file) < 0) {
+ errx(1, "failed to set signal for dump status");
+ /*NOTREACHED*/
+ }
+
+ /*
+ * Open a socket for sending RS and receiving RA.
+ * This should be done before calling ifinit(), since the function
+ * uses the socket.
+ */
+ if ((s = sockopen()) < 0) {
+ errx(1, "failed to open a socket");
+ /*NOTREACHED*/
+ }
+ maxfd = s;
+ if ((rtsock = rtsock_open()) < 0) {
+ errx(1, "failed to open a socket");
+ /*NOTREACHED*/
+ }
+ if (rtsock > maxfd)
+ maxfd = rtsock;
+
+ /* configuration per interface */
+ if (ifinit()) {
+ errx(1, "failed to initilizatoin interfaces");
+ /*NOTREACHED*/
+ }
+ while (argc--) {
+ if (ifconfig(*argv)) {
+ errx(1, "failed to initialize %s", *argv);
+ /*NOTREACHED*/
+ }
+ argv++;
+ }
+
+ /* setup for probing default routers */
+ if (probe_init()) {
+ errx(1, "failed to setup for probing routers");
+ /*NOTREACHED*/
+ }
+
+ if (!fflag)
+ daemon(0, 0); /* act as a daemon */
+
+ /* dump the current pid */
+ if (!once) {
+ pid_t pid = getpid();
+ FILE *fp;
+
+ if ((fp = fopen(pidfilename, "w")) == NULL)
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "failed to open a log file(%s): %s",
+ pidfilename, strerror(errno));
+ else {
+ fprintf(fp, "%d\n", pid);
+ fclose(fp);
+ }
+ }
+
+ FD_ZERO(&fdset);
+ FD_SET(s, &fdset);
+ FD_SET(rtsock, &fdset);
+ while (1) { /* main loop */
+ int e;
+ struct fd_set select_fd = fdset;
+
+ if (do_dump) { /* SIGUSR1 */
+ do_dump = 0;
+ rtsold_dump_file(dumpfilename);
+ }
+
+ timeout = rtsol_check_timer();
+
+ if (once) {
+ struct ifinfo *ifi;
+
+ /* if we have no timeout, we are done (or failed) */
+ if (timeout == NULL)
+ break;
+
+ /* if all interfaces have got RA packet, we are done */
+ for (ifi = iflist; ifi; ifi = ifi->next) {
+ if (ifi->state != IFS_DOWN && ifi->racnt == 0)
+ break;
+ }
+ if (ifi == NULL)
+ break;
+ }
+ e = select(maxfd + 1, &select_fd, NULL, NULL, timeout);
+ if (e < 1) {
+ if (e < 0 && errno != EINTR) {
+ warnmsg(LOG_ERR, __FUNCTION__, "select: %s",
+ strerror(errno));
+ }
+ continue;
+ }
+
+ /* packet reception */
+ if (FD_ISSET(rtsock, &select_fd))
+ rtsock_input(rtsock);
+ if (FD_ISSET(s, &select_fd))
+ rtsol_input(s);
+ }
+ /* NOTREACHED */
+
+ return 0;
+}
+
+static int
+ifconfig(char *ifname)
+{
+ struct ifinfo *ifinfo;
+ struct sockaddr_dl *sdl;
+ int flags;
+
+ if ((sdl = if_nametosdl(ifname)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "failed to get link layer information for %s", ifname);
+ return(-1);
+ }
+ if (find_ifinfo(sdl->sdl_index)) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "interface %s was already cofigured", ifname);
+ free(sdl);
+ return(-1);
+ }
+
+ if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__, "memory allocation failed");
+ free(sdl);
+ return(-1);
+ }
+ memset(ifinfo, 0, sizeof(*ifinfo));
+ ifinfo->sdl = sdl;
+
+ strlcpy(ifinfo->ifname, ifname, sizeof(ifinfo->ifname));
+
+ /* construct a router solicitation message */
+ if (make_packet(ifinfo))
+ goto bad;
+
+ /*
+ * check if the interface is available.
+ * also check if SIOCGIFMEDIA ioctl is OK on the interface.
+ */
+ ifinfo->mediareqok = 1;
+ ifinfo->active = interface_status(ifinfo);
+ if (!ifinfo->mediareqok) {
+ /*
+ * probe routers periodically even if the link status
+ * does not change.
+ */
+ ifinfo->probeinterval = PROBE_INTERVAL;
+ }
+
+ /* activate interface: interface_up returns 0 on success */
+ flags = interface_up(ifinfo->ifname);
+ if (flags == 0)
+ ifinfo->state = IFS_DELAY;
+ else if (flags == IFS_TENTATIVE)
+ ifinfo->state = IFS_TENTATIVE;
+ else
+ ifinfo->state = IFS_DOWN;
+
+ rtsol_timer_update(ifinfo);
+
+ /* link into chain */
+ if (iflist)
+ ifinfo->next = iflist;
+ iflist = ifinfo;
+
+ return(0);
+
+ bad:
+ free(ifinfo->sdl);
+ free(ifinfo);
+ return(-1);
+}
+
+#if 0
+static int
+ifreconfig(char *ifname)
+{
+ struct ifinfo *ifi, *prev;
+ int rv;
+
+ prev = NULL;
+ for (ifi = iflist; ifi; ifi = ifi->next) {
+ if (strncmp(ifi->ifname, ifname, sizeof(ifi->ifname)) == 0)
+ break;
+ prev = ifi;
+ }
+ prev->next = ifi->next;
+
+ rv = ifconfig(ifname);
+
+ /* reclaim it after ifconfig() in case ifname is pointer inside ifi */
+ if (ifi->rs_data)
+ free(ifi->rs_data);
+ free(ifi->sdl);
+ free(ifi);
+
+ return rv;
+}
+#endif
+
+struct ifinfo *
+find_ifinfo(int ifindex)
+{
+ struct ifinfo *ifi;
+
+ for (ifi = iflist; ifi; ifi = ifi->next)
+ if (ifi->sdl->sdl_index == ifindex)
+ return(ifi);
+
+ return(NULL);
+}
+
+static int
+make_packet(struct ifinfo *ifinfo)
+{
+ char *buf;
+ struct nd_router_solicit *rs;
+ size_t packlen = sizeof(struct nd_router_solicit), lladdroptlen = 0;
+
+ if ((lladdroptlen = lladdropt_length(ifinfo->sdl)) == 0) {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "link-layer address option has null length"
+ " on %s. Treat as not included.", ifinfo->ifname);
+ }
+ packlen += lladdroptlen;
+ ifinfo->rs_datalen = packlen;
+
+ /* allocate buffer */
+ if ((buf = malloc(packlen)) == NULL) {
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "memory allocation failed for %s", ifinfo->ifname);
+ return(-1);
+ }
+ ifinfo->rs_data = (u_char *)buf;
+
+ /* fill in the message */
+ rs = (struct nd_router_solicit *)buf;
+ rs->nd_rs_type = ND_ROUTER_SOLICIT;
+ rs->nd_rs_code = 0;
+ rs->nd_rs_cksum = 0;
+ rs->nd_rs_reserved = 0;
+ buf += sizeof(*rs);
+
+ /* fill in source link-layer address option */
+ if (lladdroptlen)
+ lladdropt_fill(ifinfo->sdl, (struct nd_opt_hdr *)buf);
+
+ return(0);
+}
+
+static struct timeval *
+rtsol_check_timer()
+{
+ static struct timeval returnval;
+ struct timeval now, rtsol_timer;
+ struct ifinfo *ifinfo;
+ int flags;
+
+ gettimeofday(&now, NULL);
+
+ rtsol_timer = tm_max;
+
+ for (ifinfo = iflist; ifinfo; ifinfo = ifinfo->next) {
+ if (TIMEVAL_LEQ(ifinfo->expire, now)) {
+ if (dflag > 1)
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "timer expiration on %s, "
+ "state = %d", ifinfo->ifname,
+ ifinfo->state);
+
+ switch (ifinfo->state) {
+ case IFS_DOWN:
+ case IFS_TENTATIVE:
+ /* interface_up returns 0 on success */
+ flags = interface_up(ifinfo->ifname);
+ if (flags == 0)
+ ifinfo->state = IFS_DELAY;
+ else if (flags == IFS_TENTATIVE)
+ ifinfo->state = IFS_TENTATIVE;
+ else
+ ifinfo->state = IFS_DOWN;
+ break;
+ case IFS_IDLE:
+ {
+ int oldstatus = ifinfo->active;
+ int probe = 0;
+
+ ifinfo->active =
+ interface_status(ifinfo);
+
+ if (oldstatus != ifinfo->active) {
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "%s status is changed"
+ " from %d to %d",
+ ifinfo->ifname,
+ oldstatus, ifinfo->active);
+ probe = 1;
+ ifinfo->state = IFS_DELAY;
+ }
+ else if (ifinfo->probeinterval &&
+ (ifinfo->probetimer -=
+ ifinfo->timer.tv_sec) <= 0) {
+ /* probe timer expired */
+ ifinfo->probetimer =
+ ifinfo->probeinterval;
+ probe = 1;
+ ifinfo->state = IFS_PROBE;
+ }
+
+ if (probe && mobile_node)
+ defrouter_probe(ifinfo->sdl->sdl_index);
+ break;
+ }
+ case IFS_DELAY:
+ ifinfo->state = IFS_PROBE;
+ sendpacket(ifinfo);
+ break;
+ case IFS_PROBE:
+ if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
+ sendpacket(ifinfo);
+ else {
+ warnmsg(LOG_INFO, __FUNCTION__,
+ "No answer "
+ "after sending %d RSs",
+ ifinfo->probes);
+ ifinfo->probes = 0;
+ ifinfo->state = IFS_IDLE;
+ }
+ break;
+ }
+ rtsol_timer_update(ifinfo);
+ }
+
+ if (TIMEVAL_LT(ifinfo->expire, rtsol_timer))
+ rtsol_timer = ifinfo->expire;
+ }
+
+ if (TIMEVAL_EQ(rtsol_timer, tm_max)) {
+ warnmsg(LOG_DEBUG, __FUNCTION__, "there is no timer");
+ return(NULL);
+ }
+ else if (TIMEVAL_LT(rtsol_timer, now))
+ /* this may occur when the interval is too small */
+ returnval.tv_sec = returnval.tv_usec = 0;
+ else
+ TIMEVAL_SUB(&rtsol_timer, &now, &returnval);
+
+ if (dflag > 1)
+ warnmsg(LOG_DEBUG, __FUNCTION__, "New timer is %ld:%08ld",
+ (long)returnval.tv_sec, (long)returnval.tv_usec);
+
+ return(&returnval);
+}
+
+void
+rtsol_timer_update(struct ifinfo *ifinfo)
+{
+#define MILLION 1000000
+#define DADRETRY 10 /* XXX: adhoc */
+ long interval;
+ struct timeval now;
+
+ bzero(&ifinfo->timer, sizeof(ifinfo->timer));
+
+ switch (ifinfo->state) {
+ case IFS_DOWN:
+ case IFS_TENTATIVE:
+ if (++ifinfo->dadcount > DADRETRY) {
+ ifinfo->dadcount = 0;
+ ifinfo->timer.tv_sec = PROBE_INTERVAL;
+ }
+ else
+ ifinfo->timer.tv_sec = 1;
+ break;
+ case IFS_IDLE:
+ if (mobile_node) {
+ /* XXX should be configurable */
+ ifinfo->timer.tv_sec = 3;
+ }
+ else
+ ifinfo->timer = tm_max; /* stop timer(valid?) */
+ break;
+ case IFS_DELAY:
+#ifndef HAVE_ARC4RANDOM
+ interval = random() % (MAX_RTR_SOLICITATION_DELAY * MILLION);
+#else
+ interval = arc4random() % (MAX_RTR_SOLICITATION_DELAY * MILLION);
+#endif
+ ifinfo->timer.tv_sec = interval / MILLION;
+ ifinfo->timer.tv_usec = interval % MILLION;
+ break;
+ case IFS_PROBE:
+ if (ifinfo->probes < MAX_RTR_SOLICITATIONS)
+ ifinfo->timer.tv_sec = RTR_SOLICITATION_INTERVAL;
+ else {
+ /*
+ * After sending MAX_RTR_SOLICITATIONS solicitations,
+ * we're just waiting for possible replies; there
+ * will be no more solicatation. Thus, we change
+ * the timer value to MAX_RTR_SOLICITATION_DELAY based
+ * on RFC 2461, Section 6.3.7.
+ */
+ ifinfo->timer.tv_sec = MAX_RTR_SOLICITATION_DELAY;
+ }
+ break;
+ default:
+ warnmsg(LOG_ERR, __FUNCTION__,
+ "illegal interface state(%d) on %s",
+ ifinfo->state, ifinfo->ifname);
+ return;
+ }
+
+ /* reset the timer */
+ if (TIMEVAL_EQ(ifinfo->timer, tm_max)) {
+ ifinfo->expire = tm_max;
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "stop timer for %s", ifinfo->ifname);
+ }
+ else {
+ gettimeofday(&now, NULL);
+ TIMEVAL_ADD(&now, &ifinfo->timer, &ifinfo->expire);
+
+ if (dflag > 1)
+ warnmsg(LOG_DEBUG, __FUNCTION__,
+ "set timer for %s to %d:%d", ifinfo->ifname,
+ (int)ifinfo->timer.tv_sec,
+ (int)ifinfo->timer.tv_usec);
+ }
+
+#undef MILLION
+}
+
+/* timer related utility functions */
+#define MILLION 1000000
+
+/* result = a + b */
+static void
+TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec + b->tv_usec) < MILLION) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec + b->tv_sec;
+ }
+ else {
+ result->tv_usec = l - MILLION;
+ result->tv_sec = a->tv_sec + b->tv_sec + 1;
+ }
+}
+
+/*
+ * result = a - b
+ * XXX: this function assumes that a >= b.
+ */
+void
+TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
+{
+ long l;
+
+ if ((l = a->tv_usec - b->tv_usec) >= 0) {
+ result->tv_usec = l;
+ result->tv_sec = a->tv_sec - b->tv_sec;
+ }
+ else {
+ result->tv_usec = MILLION + l;
+ result->tv_sec = a->tv_sec - b->tv_sec - 1;
+ }
+}
+
+static void
+rtsold_set_dump_file()
+{
+ do_dump = 1;
+}
+
+static void
+usage(char *progname)
+{
+ if (progname && progname[strlen(progname) - 1] != 'd') {
+ fprintf(stderr, "usage: rtsol [-dD] interfaces...\n");
+ fprintf(stderr, "usage: rtsol [-dD] -a\n");
+ } else {
+ fprintf(stderr, "usage: rtsold [-adDfm1] interfaces...\n");
+ fprintf(stderr, "usage: rtsold [-dDfm1] -a\n");
+ }
+ exit(1);
+}
+
+void
+#if __STDC__
+warnmsg(int priority, const char *func, const char *msg, ...)
+#else
+warnmsg(priority, func, msg, va_alist)
+ int priority;
+ const char *func;
+ const char *msg;
+ va_dcl
+#endif
+{
+ va_list ap;
+ char buf[BUFSIZ];
+
+ va_start(ap, msg);
+ if (fflag) {
+ if (priority <= log_upto) {
+ (void)vfprintf(stderr, msg, ap);
+ (void)fprintf(stderr, "\n");
+ }
+ } else {
+ snprintf(buf, sizeof(buf), "<%s> %s", func, msg);
+ msg = buf;
+ vsyslog(priority, msg, ap);
+ }
+ va_end(ap);
+}
+
+static char **
+autoifprobe()
+{
+#ifndef HAVE_GETIFADDRS
+ errx(1, "-a is not available with the configuration");
+#else
+ static char ifname[IFNAMSIZ + 1];
+ static char *argv[2];
+ struct ifaddrs *ifap, *ifa, *target;
+
+ if (getifaddrs(&ifap) != 0)
+ return NULL;
+
+ target = NULL;
+ /* find an ethernet */
+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+ if ((ifa->ifa_flags & IFF_UP) == 0)
+ continue;
+ if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
+ continue;
+ if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
+ continue;
+ if ((ifa->ifa_flags & IFF_MULTICAST) == 0)
+ continue;
+
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+
+ if (target && strcmp(target->ifa_name, ifa->ifa_name) == 0)
+ continue;
+
+ if (!target)
+ target = ifa;
+ else {
+ /* if we find multiple candidates, failure. */
+ if (dflag > 1)
+ warnx("multiple interfaces found");
+ target = NULL;
+ break;
+ }
+ }
+
+ if (target) {
+ strlcpy(ifname, target->ifa_name, sizeof(ifname));
+ argv[0] = ifname;
+ argv[1] = NULL;
+
+ if (dflag > 0)
+ warnx("probing %s", argv[0]);
+ }
+ freeifaddrs(ifap);
+ if (target)
+ return argv;
+ else
+ return (char **)NULL;
+#endif
+}
diff --git a/network_cmds/rtsol.tproj/rtsold.h b/network_cmds/rtsol.tproj/rtsold.h
new file mode 100644
index 0000000..fdda539
--- /dev/null
+++ b/network_cmds/rtsol.tproj/rtsold.h
@@ -0,0 +1,96 @@
+/* $KAME: rtsold.h,v 1.11 2000/10/10 06:18:04 itojun Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.sbin/rtsold/rtsold.h,v 1.1.2.3 2001/07/03 11:02:16 ume Exp $
+ */
+
+struct ifinfo {
+ struct ifinfo *next; /* pointer to the next interface */
+
+ struct sockaddr_dl *sdl; /* link-layer address */
+ char ifname[IF_NAMESIZE]; /* interface name */
+ int active; /* interface status */
+ int probeinterval; /* interval of probe timer(if necessary) */
+ int probetimer; /* rest of probe timer */
+ int mediareqok; /* wheter the IF supports SIOCGIFMEDIA */
+ int state;
+ int probes;
+ int dadcount;
+ struct timeval timer;
+ struct timeval expire;
+ int errors; /* # of errors we've got - detect wedge */
+
+ int racnt; /* total # of valid RAs it have got */
+
+ size_t rs_datalen;
+ u_char *rs_data;
+};
+
+/* per interface status */
+#define IFS_IDLE 0
+#define IFS_DELAY 1
+#define IFS_PROBE 2
+#define IFS_DOWN 3
+#define IFS_TENTATIVE 4
+#define IFS_OPTIMISTIC 5
+
+/* rtsold.c */
+extern struct timeval tm_max;
+extern int dflag;
+struct ifinfo *find_ifinfo __P((int ifindex));
+void rtsol_timer_update __P((struct ifinfo *ifinfo));
+extern void warnmsg __P((int, const char *, const char *, ...))
+ __attribute__((__format__(__printf__, 3, 4)));
+
+/* if.c */
+extern int ifinit __P((void));
+extern int interface_up __P((char *name));
+extern int interface_status __P((struct ifinfo*));
+extern int lladdropt_length __P((struct sockaddr_dl *sdl));
+extern void lladdropt_fill __P((struct sockaddr_dl *sdl,
+ struct nd_opt_hdr *ndopt));
+extern struct sockaddr_dl *if_nametosdl __P((char *name));
+extern int getinet6sysctl __P((int code));
+
+/* rtsol.c */
+extern int sockopen __P((void));
+extern void sendpacket __P((struct ifinfo *ifinfo));
+extern void rtsol_input __P((int s));
+
+/* probe.c */
+extern int probe_init __P((void));
+extern void defrouter_probe __P((int ifindex));
+
+/* dump.c */
+extern void rtsold_dump_file __P((char *));
+
+/* rtsock.c */
+extern int rtsock_open __P((void));
+extern int rtsock_input __P((int));
diff --git a/network_cmds/spray.tproj/spray.8 b/network_cmds/spray.tproj/spray.8
new file mode 100644
index 0000000..0f61422
--- /dev/null
+++ b/network_cmds/spray.tproj/spray.8
@@ -0,0 +1,74 @@
+.\"
+.\" Copyright (c) 1994 James A. Jegers
+.\" 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. 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.
+.\"
+.Dd July 10, 1995
+.Dt SPRAY 8
+.Os
+.Sh NAME
+.Nm spray
+.Nd send many packets to host
+.Sh SYNOPSIS
+.Nm spray
+.Op Fl c Ar count
+.Op Fl d Ar delay
+.Op Fl l Ar length
+.Ar host
+\&...
+.Sh DESCRIPTION
+.Nm Spray
+sends multiple RPC packets to
+.Ar host
+and records how many of them were correctly received and how long it took.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c Ar count
+Send
+.Ar count
+packets.
+.It Fl d Ar delay
+Pause
+.Ar delay
+microseconds between sending each packet.
+.It Fl l Ar length
+Set the length of the packet that holds the RPC call message to
+.Ar length
+bytes.
+Not all values of
+.Ar length
+are possible because RPC data is encoded using XDR.
+.Nm Spray
+rounds up to the nearest possible value.
+.El
+.Pp
+.Nm Spray
+is intended for use in network testing, measurement, and management.
+This command
+.Bf -emphasis
+can be very hard on a network and should be used with caution.
+.Ef
+.Pp
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ifconfig 8 ,
+.Xr ping 8
diff --git a/network_cmds/spray.tproj/spray.c b/network_cmds/spray.tproj/spray.c
new file mode 100644
index 0000000..70fd8db
--- /dev/null
+++ b/network_cmds/spray.tproj/spray.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1993 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ *
+ * $Id: spray.c,v 1.2 2006/02/07 06:22:44 lindak Exp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <rpc/rpc.h>
+#include <rpcsvc/spray.h>
+
+#ifndef SPRAYOVERHEAD
+#define SPRAYOVERHEAD 86
+#endif
+
+void usage ();
+void print_xferstats ();
+
+/* spray buffer */
+char spray_buffer[SPRAYMAX];
+
+/* RPC timeouts */
+struct timeval NO_DEFAULT = { -1, -1 };
+struct timeval ONE_WAY = { 0, 0 };
+struct timeval TIMEOUT = { 25, 0 };
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ char *progname;
+ spraycumul host_stats;
+ sprayarr host_array;
+ CLIENT *cl;
+ int c;
+ int i;
+ int count = 0;
+ int delay = 0;
+ int length = 0;
+ double xmit_time; /* time to receive data */
+
+ progname = *argv;
+ while ((c = getopt(argc, argv, "c:d:l:")) != -1) {
+ switch (c) {
+ case 'c':
+ count = atoi(optarg);
+ break;
+ case 'd':
+ delay = atoi(optarg);
+ break;
+ case 'l':
+ length = atoi(optarg);
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1) {
+ usage();
+ /* NOTREACHED */
+ }
+
+
+ /* Correct packet length. */
+ if (length > SPRAYMAX) {
+ length = SPRAYMAX;
+ } else if (length < SPRAYOVERHEAD) {
+ length = SPRAYOVERHEAD;
+ } else {
+ /* The RPC portion of the packet is a multiple of 32 bits. */
+ length -= SPRAYOVERHEAD - 3;
+ length &= ~3;
+ length += SPRAYOVERHEAD;
+ }
+
+
+ /*
+ * The default value of count is the number of packets required
+ * to make the total stream size 100000 bytes.
+ */
+ if (!count) {
+ count = 100000 / length;
+ }
+
+ /* Initialize spray argument */
+ host_array.sprayarr_len = length - SPRAYOVERHEAD;
+ host_array.sprayarr_val = spray_buffer;
+
+
+ /* create connection with server */
+ cl = clnt_create(*argv, SPRAYPROG, SPRAYVERS, "udp");
+ if (cl == NULL) {
+ clnt_pcreateerror(progname);
+ exit(1);
+ }
+
+
+ /*
+ * For some strange reason, RPC 4.0 sets the default timeout,
+ * thus timeouts specified in clnt_call() are always ignored.
+ *
+ * The following (undocumented) hack resets the internal state
+ * of the client handle.
+ */
+ clnt_control(cl, CLSET_TIMEOUT, (char *)&NO_DEFAULT);
+
+
+ /* Clear server statistics */
+ if (clnt_call(cl, SPRAYPROC_CLEAR, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
+ clnt_perror(cl, progname);
+ exit(1);
+ }
+
+
+ /* Spray server with packets */
+ printf ("sending %d packets of lnth %d to %s ...", count, length, *argv);
+ fflush (stdout);
+
+ for (i = 0; i < count; i++) {
+ clnt_call(cl, SPRAYPROC_SPRAY, (xdrproc_t)xdr_sprayarr, &host_array, (xdrproc_t)xdr_void, NULL, ONE_WAY);
+
+ if (delay) {
+ usleep(delay);
+ }
+ }
+
+
+ /* Collect statistics from server */
+ if (clnt_call(cl, SPRAYPROC_GET, (xdrproc_t)xdr_void, NULL, (xdrproc_t)xdr_spraycumul, &host_stats, TIMEOUT) != RPC_SUCCESS) {
+ clnt_perror(cl, progname);
+ exit(1);
+ }
+
+ xmit_time = host_stats.clock.sec +
+ (host_stats.clock.usec / 1000000.0);
+
+ printf ("\n\tin %.2f seconds elapsed time\n", xmit_time);
+
+
+ /* report dropped packets */
+ if (host_stats.counter != count) {
+ int packets_dropped = count - host_stats.counter;
+
+ printf("\t%d packets (%.2f%%) dropped\n",
+ packets_dropped,
+ 100.0 * packets_dropped / count );
+ } else {
+ printf("\tno packets dropped\n");
+ }
+
+ printf("Sent:");
+ print_xferstats(count, length, xmit_time);
+
+ printf("Rcvd:");
+ print_xferstats(host_stats.counter, length, xmit_time);
+
+ exit (0);
+}
+
+
+void
+print_xferstats(packets, packetlen, xfertime)
+ int packets;
+ int packetlen;
+ double xfertime;
+{
+ int datalen;
+ double pps; /* packets per second */
+ double bps; /* bytes per second */
+
+ datalen = packets * packetlen;
+ pps = packets / xfertime;
+ bps = datalen / xfertime;
+
+ printf("\t%.0f packets/sec, ", pps);
+
+ if (bps >= 1024)
+ printf ("%.1fK ", bps / 1024);
+ else
+ printf ("%.0f ", bps);
+
+ printf("bytes/sec\n");
+}
+
+
+void
+usage ()
+{
+ fprintf(stderr, "usage: spray [-c count] [-l length] [-d delay] host\n");
+ exit(1);
+}
diff --git a/network_cmds/spray.tproj/spray.x b/network_cmds/spray.tproj/spray.x
new file mode 100644
index 0000000..5d2f883
--- /dev/null
+++ b/network_cmds/spray.tproj/spray.x
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <rpcsvc/spray.x>
diff --git a/network_cmds/traceroute.tproj/README b/network_cmds/traceroute.tproj/README
new file mode 100644
index 0000000..6d33c6c
--- /dev/null
+++ b/network_cmds/traceroute.tproj/README
@@ -0,0 +1,126 @@
+Tue Dec 27 06:24:24 PST 1988
+
+Traceroute is a system administrators utility to trace the route
+ip packets from the current system take in getting to some
+destination system. See the comments at the front of the
+program for a description of its use.
+
+This program
+
+ a) can only be run by root (it uses raw ip sockets).
+
+ b) REQUIRES A KERNEL MOD to the raw ip output code to run.
+
+If you want to hack on your kernel, my modified version of the
+routine rip_output (in file /sys/netinet/raw_ip.c) is attached.
+This code may or may not resemble the code in your kernel.
+It may offer you a place to start but I make no promises.
+If you do hack your kernel, remember to test everything that uses
+raw ip sockets (e.g., ping and egpup/gated) & make sure they still
+work. I wish you the best of luck and you're on your own.
+
+If your system has the ttl bug mentioned in the source, you
+might want to fix it while you're in the kernel. (This bug
+appears in all releases of BSD up to but not including 4.3tahoe.
+If your version of netinet/ip_icmp.c is any earlier than 7.3
+(April, '87), it has the bug.) The fix is just to add the line
+ ip->ip_ttl = MAXTTL;
+after the line
+ ip->ip_src = t;
+(or anywhere before the call to icmp_send) in routine icmp_reflect.
+
+If you're running this on a pre-4.3bsd system (e.g., Sun 3.x,
+Ultrix) that strips ip headers from icmp messages, add -DARCHAIC
+to CFLAGS in the Makefile. Also note that rip_output contains
+a conditional for a 4.2/4.3 change in the location of a raw
+socket's protocol number. I've checked this under 4.3 & Sun OS
+3.5 but you should double-check your system to make sure the
+appropriate branch of the #if is taken (check the line that
+assigned to ip->ip_p in your system's original rip_output).
+
+A couple of awk programs to massage the traceroute output are
+included. "mean.awk" and "median.awk" compute the mean and median
+time to each hop, respectively. I've found that something like
+
+ traceroute -q 7 foo.somewhere >t
+ awk -f median.awk t | graph
+
+can give you a quick picture of the bad spots on a long
+path (median is usually a better noise filter than mean).
+
+Enjoy.
+
+ - Van Jacobson (van@helios.ee.lbl.gov)
+
+-------------------- rip_output from /sys/netinet/raw_ip.c
+rip_output(m, so)
+ register struct mbuf *m;
+ struct socket *so;
+{
+ register struct ip *ip;
+ int error;
+ struct rawcb *rp = sotorawcb(so);
+ struct sockaddr_in *sin;
+#if BSD>=43
+ short proto = rp->rcb_proto.sp_protocol;
+#else
+ short proto = so->so_proto->pr_protocol;
+#endif
+ /*
+ * if the protocol is IPPROTO_RAW, the user handed us a
+ * complete IP packet. Otherwise, allocate an mbuf for a
+ * header and fill it in as needed.
+ */
+ if (proto != IPPROTO_RAW) {
+ /*
+ * Calculate data length and get an mbuf
+ * for IP header.
+ */
+ int len = 0;
+ struct mbuf *m0;
+
+ for (m0 = m; m; m = m->m_next)
+ len += m->m_len;
+
+ m = m_get(M_DONTWAIT, MT_HEADER);
+ if (m == 0) {
+ m = m0;
+ error = ENOBUFS;
+ goto bad;
+ }
+ m->m_off = MMAXOFF - sizeof(struct ip);
+ m->m_len = sizeof(struct ip);
+ m->m_next = m0;
+
+ ip = mtod(m, struct ip *);
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_p = proto;
+ ip->ip_len = sizeof(struct ip) + len;
+ ip->ip_ttl = MAXTTL;
+ } else
+ ip = mtod(m, struct ip *);
+
+ if (rp->rcb_flags & RAW_LADDR) {
+ sin = (struct sockaddr_in *)&rp->rcb_laddr;
+ if (sin->sin_family != AF_INET) {
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+ ip->ip_src.s_addr = sin->sin_addr.s_addr;
+ } else
+ ip->ip_src.s_addr = 0;
+
+ ip->ip_dst = ((struct sockaddr_in *)&rp->rcb_faddr)->sin_addr;
+
+#if BSD>=43
+ return (ip_output(m, rp->rcb_options, &rp->rcb_route,
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+#else
+ return (ip_output(m, (struct mbuf *)0, &rp->rcb_route,
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+#endif
+bad:
+ m_freem(m);
+ return (error);
+}
diff --git a/network_cmds/traceroute.tproj/as.c b/network_cmds/traceroute.tproj/as.c
new file mode 100644
index 0000000..eb96851
--- /dev/null
+++ b/network_cmds/traceroute.tproj/as.c
@@ -0,0 +1,242 @@
+/* $FreeBSD: src/contrib/traceroute/as.c,v 1.1 2008/02/20 23:29:52 rpaulo Exp $ */
+/* $NetBSD: as.c,v 1.1 2001/11/04 23:14:36 atatat Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Brown.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <err.h>
+#include <stdio.h>
+
+#include "as.h"
+
+#define DEFAULT_AS_SERVER "whois.radb.net"
+#undef AS_DEBUG_FILE
+
+struct aslookup {
+ FILE *as_f;
+#ifdef AS_DEBUG_FILE
+ FILE *as_debug;
+#endif /* AS_DEBUG_FILE */
+};
+
+void *
+as_setup(server)
+ char *server;
+{
+ struct aslookup *asn;
+ struct hostent *he = NULL;
+ struct servent *se;
+ struct sockaddr_in in;
+ FILE *f;
+ int s;
+
+ if (server == NULL)
+ server = DEFAULT_AS_SERVER;
+
+ (void)memset(&in, 0, sizeof(in));
+ in.sin_family = AF_INET;
+ in.sin_len = sizeof(in);
+ if ((se = getservbyname("whois", "tcp")) == NULL) {
+ warnx("warning: whois/tcp service not found");
+ in.sin_port = ntohs(43);
+ } else
+ in.sin_port = se->s_port;
+
+ if (inet_aton(server, &in.sin_addr) == 0 &&
+ ((he = gethostbyname(server)) == NULL ||
+ he->h_addr == NULL)) {
+ warnx("%s: %s", server, hstrerror(h_errno));
+ return (NULL);
+ }
+
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+ warn("socket");
+ return (NULL);
+ }
+
+ do {
+ if (he != NULL) {
+ memcpy(&in.sin_addr, he->h_addr, he->h_length);
+ he->h_addr_list++;
+ }
+ if (connect(s, (struct sockaddr *)&in, sizeof(in)) == 0)
+ break;
+ if (he == NULL || he->h_addr == NULL) {
+ close(s);
+ s = -1;
+ break;
+ }
+ } while (1);
+
+ if (s == -1) {
+ warn("connect");
+ return (NULL);
+ }
+
+ f = fdopen(s, "r+");
+ (void)fprintf(f, "!!\n");
+ (void)fflush(f);
+
+ asn = malloc(sizeof(struct aslookup));
+ if (asn == NULL)
+ (void)fclose(f);
+ else
+ asn->as_f = f;
+
+#ifdef AS_DEBUG_FILE
+ asn->as_debug = fopen(AS_DEBUG_FILE, "w");
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, ">> !!\n");
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ return (asn);
+}
+
+int
+as_lookup(_asn, addr)
+ void *_asn;
+ struct in_addr *addr;
+{
+ struct aslookup *asn = _asn;
+ char buf[1024];
+ int as, rc, dlen;
+
+ as = rc = dlen = 0;
+ (void)fprintf(asn->as_f, "!r%s/32,l\n", inet_ntoa(*addr));
+ (void)fflush(asn->as_f);
+
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, ">> !r%s/32,l\n",
+ inet_ntoa(*addr));
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ while (fgets(buf, sizeof(buf), asn->as_f) != NULL) {
+ buf[sizeof(buf) - 1] = '\0';
+
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, "<< %s", buf);
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ if (rc == 0) {
+ rc = buf[0];
+ switch (rc) {
+ case 'A':
+ /* A - followed by # bytes of answer */
+ sscanf(buf, "A%d\n", &dlen);
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug,
+ "dlen: %d\n", dlen);
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+ break;
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ /* C - no data returned */
+ /* D - key not found */
+ /* E - multiple copies of key */
+ /* F - some other error */
+ break;
+ }
+ if (rc == 'A')
+ /* skip to next input line */
+ continue;
+ }
+
+ if (dlen == 0)
+ /* out of data, next char read is end code */
+ rc = buf[0];
+ if (rc != 'A')
+ /* either an error off the bat, or a done code */
+ break;
+
+ /* data received, thank you */
+ dlen -= strlen(buf);
+
+ /* origin line is the interesting bit */
+ if (as == 0 && strncasecmp(buf, "origin:", 7) == 0) {
+ sscanf(buf + 7, " AS%d", &as);
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, "as: %d\n", as);
+ (void)fflush(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+ }
+ }
+
+ return (as);
+}
+
+void
+as_shutdown(_asn)
+ void *_asn;
+{
+ struct aslookup *asn = _asn;
+
+ (void)fprintf(asn->as_f, "!q\n");
+ (void)fclose(asn->as_f);
+
+#ifdef AS_DEBUG_FILE
+ if (asn->as_debug) {
+ (void)fprintf(asn->as_debug, ">> !q\n");
+ (void)fclose(asn->as_debug);
+ }
+#endif /* AS_DEBUG_FILE */
+
+ free(asn);
+}
diff --git a/network_cmds/traceroute.tproj/as.h b/network_cmds/traceroute.tproj/as.h
new file mode 100644
index 0000000..a4c6f47
--- /dev/null
+++ b/network_cmds/traceroute.tproj/as.h
@@ -0,0 +1,42 @@
+/* $FreeBSD: src/contrib/traceroute/as.h,v 1.1 2008/02/20 23:29:52 rpaulo Exp $ */
+/* $NetBSD: as.h,v 1.1 2001/11/04 23:14:36 atatat Exp $ */
+
+/*
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Brown.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+void *as_setup __P((char *));
+int as_lookup __P((void *, struct in_addr *));
+void as_shutdown __P((void *));
diff --git a/network_cmds/traceroute.tproj/findsaddr-socket.c b/network_cmds/traceroute.tproj/findsaddr-socket.c
new file mode 100644
index 0000000..01dcef1
--- /dev/null
+++ b/network_cmds/traceroute.tproj/findsaddr-socket.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 2000
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/contrib/traceroute/findsaddr-socket.c,v 1.2 2002/07/30 04:49:13 fenner Exp $
+ */
+
+/* XXX Yes this is WAY too complicated */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#include <sys/time.h> /* concession to AIX */
+
+#if __STDC__
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "findsaddr.h"
+
+#ifdef HAVE_SOCKADDR_SA_LEN
+#define SALEN(sa) ((sa)->sa_len)
+#else
+#define SALEN(sa) salen(sa)
+#endif
+
+#ifndef roundup
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */
+#endif
+
+struct rtmsg {
+ struct rt_msghdr rtmsg;
+ u_char data[512];
+};
+
+static struct rtmsg rtmsg = {
+ { 0, RTM_VERSION, RTM_GET, 0,
+ RTF_UP | RTF_GATEWAY | RTF_HOST | RTF_STATIC,
+ RTA_DST | RTA_IFA, 0, 0, 0, 0, 0, { 0 } },
+ { 0 }
+};
+
+#ifndef HAVE_SOCKADDR_SA_LEN
+static int salen(struct sockaddr *);
+#endif
+
+/*
+ * Return the source address for the given destination address
+ */
+const char *
+findsaddr(register const struct sockaddr_in *to,
+ register struct sockaddr_in *from)
+{
+ register struct rt_msghdr *rp;
+ register u_char *cp;
+
+ register struct sockaddr_in *sp, *ifa;
+ register struct sockaddr *sa;
+ register int s, size, cc, seq, i;
+ register pid_t pid;
+ static char errbuf[512];
+
+ s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
+ if (s < 0) {
+ snprintf(errbuf, sizeof(errbuf), "socket: %.128s", strerror(errno));
+ return (errbuf);
+ }
+
+ seq = 0;
+ pid = getpid();
+
+ rp = &rtmsg.rtmsg;
+ rp->rtm_seq = ++seq;
+ cp = (u_char *)(rp + 1);
+
+ sp = (struct sockaddr_in *)cp;
+ *sp = *to;
+ cp += roundup(SALEN((struct sockaddr *)sp), sizeof(u_int32_t));
+
+ size = cp - (u_char *)rp;
+ rp->rtm_msglen = size;
+
+ cc = write(s, (char *)rp, size);
+ if (cc < 0) {
+ snprintf(errbuf, sizeof(errbuf), "write: %.128s", strerror(errno));
+ close(s);
+ return (errbuf);
+ }
+ if (cc != size) {
+ snprintf(errbuf, sizeof(errbuf), "short write (%d != %d)", cc, size);
+ close(s);
+ return (errbuf);
+ }
+
+ size = sizeof(rtmsg);
+ do {
+ memset(rp, 0, size);
+ cc = read(s, (char *)rp, size);
+ if (cc < 0) {
+ snprintf(errbuf, sizeof(errbuf), "read: %.128s", strerror(errno));
+ close(s);
+ return (errbuf);
+ }
+
+ } while (rp->rtm_seq != seq || rp->rtm_pid != pid);
+ close(s);
+
+
+ if (rp->rtm_version != RTM_VERSION) {
+ snprintf(errbuf, sizeof(errbuf), "bad version %d", rp->rtm_version);
+ return (errbuf);
+ }
+ if (rp->rtm_msglen > cc) {
+ snprintf(errbuf, sizeof(errbuf), "bad msglen %d > %d", rp->rtm_msglen, cc);
+ return (errbuf);
+ }
+ if (rp->rtm_errno != 0) {
+ snprintf(errbuf, sizeof(errbuf), "rtm_errno: %.128s", strerror(rp->rtm_errno));
+ return (errbuf);
+ }
+
+ /* Find the interface sockaddr */
+ cp = (u_char *)(rp + 1);
+ for (i = 1; i != 0; i <<= 1)
+ if ((i & rp->rtm_addrs) != 0) {
+ sa = (struct sockaddr *)cp;
+ switch (i) {
+
+ case RTA_IFA:
+ if (sa->sa_family == AF_INET) {
+ ifa = (struct sockaddr_in *)cp;
+ if (ifa->sin_addr.s_addr != 0) {
+ *from = *ifa;
+ return (NULL);
+ }
+ }
+ break;
+
+ default:
+ break;
+ /* empty */
+ }
+
+ if (SALEN(sa) == 0)
+ cp += sizeof (u_int32_t);
+ else
+ cp += roundup(SALEN(sa), sizeof (u_int32_t));
+ }
+
+ return ("failed!");
+}
+
+#ifndef HAVE_SOCKADDR_SA_LEN
+static int
+salen(struct sockaddr *sa)
+{
+ switch (sa->sa_family) {
+
+ case AF_INET:
+ return (sizeof(struct sockaddr_in));
+
+ case AF_LINK:
+ return (sizeof(struct sockaddr_dl));
+
+ default:
+ return (sizeof(struct sockaddr));
+ }
+}
+#endif
diff --git a/network_cmds/traceroute.tproj/findsaddr.h b/network_cmds/traceroute.tproj/findsaddr.h
new file mode 100644
index 0000000..49ed9e1
--- /dev/null
+++ b/network_cmds/traceroute.tproj/findsaddr.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2000
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Id: findsaddr.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+const char *findsaddr(const struct sockaddr_in *, struct sockaddr_in *);
diff --git a/network_cmds/traceroute.tproj/gnuc.h b/network_cmds/traceroute.tproj/gnuc.h
new file mode 100644
index 0000000..f13c0be
--- /dev/null
+++ b/network_cmds/traceroute.tproj/gnuc.h
@@ -0,0 +1,43 @@
+/* @(#) $Header: /Volumes/george/fs-svn/network_cmds/traceroute.tproj/gnuc.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL) */
+
+/* Define __P() macro, if necessary */
+#ifndef __P
+#if __STDC__
+#define __P(protos) protos
+#else
+#define __P(protos) ()
+#endif
+#endif
+
+/* inline foo */
+#ifdef __GNUC__
+#define inline __inline
+#else
+#define inline
+#endif
+
+/*
+ * Handle new and old "dead" routine prototypes
+ *
+ * For example:
+ *
+ * __dead void foo(void) __attribute__((volatile));
+ *
+ */
+#ifdef __GNUC__
+#ifndef __dead
+#define __dead volatile
+#endif
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
+#else
+#ifndef __dead
+#define __dead
+#endif
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
diff --git a/network_cmds/traceroute.tproj/ifaddrlist.c b/network_cmds/traceroute.tproj/ifaddrlist.c
new file mode 100644
index 0000000..17b1026
--- /dev/null
+++ b/network_cmds/traceroute.tproj/ifaddrlist.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997, 1998, 1999, 2000
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#include <sys/time.h> /* concession to AIX */
+
+#if __STDC__
+struct mbuf;
+struct rtentry;
+#endif
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+#include "ifaddrlist.h"
+
+/*
+ * Return the interface list
+ */
+int
+ifaddrlist(register struct ifaddrlist **ipaddrp, register char *errbuf, size_t errbuflen)
+{
+ register int fd, nipaddr;
+#ifdef HAVE_SOCKADDR_SA_LEN
+ register int n;
+#endif
+ register struct ifreq *ifrp, *ifend, *ifnext, *mp;
+ register struct sockaddr_in *sin;
+ register struct ifaddrlist *al;
+ struct ifconf ifc;
+ struct ifreq ibuf[(32 * 1024) / sizeof(struct ifreq)], ifr;
+#define MAX_IPADDR (sizeof(ibuf) / sizeof(ibuf[0]))
+ static struct ifaddrlist ifaddrlist[MAX_IPADDR];
+ char device[sizeof(ifr.ifr_name) + 1];
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ (void)snprintf(errbuf, errbuflen, "socket: %s", strerror(errno));
+ return (-1);
+ }
+ ifc.ifc_len = sizeof(ibuf);
+ ifc.ifc_buf = (caddr_t)ibuf;
+
+ if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ if (errno == EINVAL)
+ (void)snprintf(errbuf, sizeof(errbuf),
+ "SIOCGIFCONF: ifreq struct too small (%d bytes)",
+ (int)sizeof(ibuf));
+ else
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFCONF: %s",
+ strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+ ifrp = ibuf;
+ ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+
+ al = ifaddrlist;
+ mp = NULL;
+ nipaddr = 0;
+ for (; ifrp < ifend; ifrp = ifnext) {
+#ifdef HAVE_SOCKADDR_SA_LEN
+ n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
+ if (n < sizeof(*ifrp))
+ ifnext = ifrp + 1;
+ else
+ ifnext = (struct ifreq *)((char *)ifrp + n);
+ if (ifrp->ifr_addr.sa_family != AF_INET)
+ continue;
+#else
+ ifnext = ifrp + 1;
+#endif
+ /*
+ * Need a template to preserve address info that is
+ * used below to locate the next entry. (Otherwise,
+ * SIOCGIFFLAGS stomps over it because the requests
+ * are returned in a union.)
+ */
+ strlcpy(ifr.ifr_name, ifrp->ifr_name, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+ if (errno == ENXIO)
+ continue;
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFFLAGS: %.*s: %s",
+ (int)sizeof(ifr.ifr_name), ifr.ifr_name,
+ strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+
+ /* Must be up */
+ if ((ifr.ifr_flags & IFF_UP) == 0)
+ continue;
+
+
+ (void)strlcpy(device, ifr.ifr_name, sizeof(device));
+#ifdef sun
+ /* Ignore sun virtual interfaces */
+ if (strchr(device, ':') != NULL)
+ continue;
+#endif
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+ (void)snprintf(errbuf, errbuflen, "SIOCGIFADDR: %s: %s",
+ device, strerror(errno));
+ (void)close(fd);
+ return (-1);
+ }
+
+ if (nipaddr >= MAX_IPADDR) {
+ (void)snprintf(errbuf, errbuflen, "Too many interfaces (%d)",
+ (int)MAX_IPADDR);
+ (void)close(fd);
+ return (-1);
+ }
+ sin = (struct sockaddr_in *)&ifr.ifr_addr;
+ al->addr = sin->sin_addr.s_addr;
+ al->device = strdup(device);
+ ++al;
+ ++nipaddr;
+ }
+ (void)close(fd);
+
+ *ipaddrp = ifaddrlist;
+ return (nipaddr);
+}
diff --git a/network_cmds/traceroute.tproj/ifaddrlist.h b/network_cmds/traceroute.tproj/ifaddrlist.h
new file mode 100644
index 0000000..53d91d9
--- /dev/null
+++ b/network_cmds/traceroute.tproj/ifaddrlist.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: /Volumes/george/fs-svn/network_cmds/traceroute.tproj/ifaddrlist.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+
+struct ifaddrlist {
+ u_int32_t addr;
+ char *device;
+};
+
+int ifaddrlist(struct ifaddrlist **, char *, size_t );
diff --git a/network_cmds/traceroute.tproj/mean.awk b/network_cmds/traceroute.tproj/mean.awk
new file mode 100644
index 0000000..e97a56f
--- /dev/null
+++ b/network_cmds/traceroute.tproj/mean.awk
@@ -0,0 +1,50 @@
+#!/bin/awk -f
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Van Jacobson.
+#
+# 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 the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)mean.awk 8.1 (Berkeley) 6/6/93
+#
+/^ *[0-9]/ {
+ # print out the average time to each hop along a route.
+ tottime = 0; n = 0;
+ for (f = 5; f <= NF; ++f) {
+ if ($f == "ms") {
+ tottime += $(f - 1)
+ ++n
+ }
+ }
+ if (n > 0)
+ print $1, tottime/n, median
+}
diff --git a/network_cmds/traceroute.tproj/median.awk b/network_cmds/traceroute.tproj/median.awk
new file mode 100644
index 0000000..1a8d81d
--- /dev/null
+++ b/network_cmds/traceroute.tproj/median.awk
@@ -0,0 +1,67 @@
+#!/bin/awk -f
+#
+# Copyright (c) 1990, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Van Jacobson.
+#
+# 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 the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)median.awk 8.1 (Berkeley) 6/6/93
+#
+/^ *[0-9]/ {
+ # print out the median time to each hop along a route.
+ tottime = 0; n = 0;
+ for (f = 5; f <= NF; ++f) {
+ if ($f == "ms") {
+ ++n
+ time[n] = $(f - 1)
+ }
+ }
+ if (n > 0) {
+ # insertion sort the times to find the median
+ for (i = 2; i <= n; ++i) {
+ v = time[i]; j = i - 1;
+ while (time[j] > v) {
+ time[j+1] = time[j];
+ j = j - 1;
+ if (j < 0)
+ break;
+ }
+ time[j+1] = v;
+ }
+ if (n > 1 && (n % 2) == 0)
+ median = (time[n/2] + time[(n/2) + 1]) / 2
+ else
+ median = time[(n+1)/2]
+
+ print $1, median
+ }
+}
diff --git a/network_cmds/traceroute.tproj/traceroute.8 b/network_cmds/traceroute.tproj/traceroute.8
new file mode 100644
index 0000000..c726d7a
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.8
@@ -0,0 +1,439 @@
+.\" Copyright (c) 1989, 1995, 1996, 1997, 1999, 2000
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted
+.\" provided that the above copyright notice and this paragraph are
+.\" duplicated in all such forms and that any documentation,
+.\" advertising materials, and other materials related to such
+.\" distribution and use acknowledge that the software was developed
+.\" by the University of California, Berkeley. The name of the
+.\" University may not be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+.\" WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.Dd May 29, 2008
+.Dt TRACEROUTE 8
+.Os BSD 4.3
+.Sh NAME
+.Nm traceroute
+.Nd print the route packets take to network host
+.Sh SYNOPSIS
+.Nm traceroute
+.Op Fl adeFISdNnrvx
+.Op Fl A Ar as_server
+.Op Fl f Ar first_ttl
+.Op Fl g Ar gateway
+.Op Fl i Ar iface
+.Op Fl M Ar first_ttl
+.Op Fl m Ar max_ttl
+.Op Fl P Ar proto
+.Op Fl p Ar port
+.Op Fl q Ar nqueries
+.Op Fl s Ar src_addr
+.Op Fl t Ar tos
+.Op Fl w Ar waittime
+.Op Fl z Ar pausemsecs
+.Ar host
+.Op Ar packetsize
+.Sh DESCRIPTION
+The Internet is a large and complex aggregation of
+network hardware, connected together by gateways.
+Tracking the route one's packets follow (or finding the miscreant
+gateway that's discarding your packets) can be difficult.
+.Nm
+utilizes the IP protocol `time to live' field and attempts to elicit an
+.Tn ICMP
+.Dv TIME_EXCEEDED
+response from each gateway along the path to some
+host.
+.Pp
+The only mandatory parameter is the destination host name or IP number.
+The default probe datagram length is 40 bytes, but this may be increased
+by specifying a packet size (in bytes) after the destination host
+name.
+.Pp
+Other options are:
+.Bl -tag -width Ds
+.It Fl a
+Turn on AS# lookups for each hop encountered.
+.It Fl A Ar as_server
+Turn on AS# lookups and use the given server instead of the
+default.
+.It Fl d
+Enable socket level debugging.
+.It Fl D
+When an ICMP response to our probe datagram is received,
+print the differences between the transmitted packet and
+the packet quoted by the ICMP response.
+A key showing the location of fields within the transmitted packet is printed,
+followed by the original packet in hex,
+followed by the quoted packet in hex.
+Bytes that are unchanged in the quoted packet are shown as underscores.
+Note,
+the IP checksum and the TTL of the quoted packet are not expected to match.
+By default, only one probe per hop is sent with this option.
+.It Fl e
+Firewall evasion mode.
+Use fixed destination ports for UDP and TCP probes.
+The destination port does NOT increment with each packet sent.
+.It Fl f Ar first_ttl
+Set the initial time-to-live used in the first outgoing probe packet.
+.It Fl F
+Set the "don't fragment" bit.
+.It Fl g Ar gateway
+Specify a loose source route gateway (8 maximum).
+.It Fl i Ar iface
+Specify a network interface to obtain the source IP address for
+outgoing probe packets. This is normally only useful on a multi-homed
+host. (See the
+.Fl s
+flag for another way to do this.)
+.It Fl I
+Use
+.Tn ICMP
+ECHO instead of
+.Tn UDP
+datagrams. (A synonym for "-P icmp").
+.It Fl M Ar first_ttl
+Set the initial time-to-live value used in outgoing probe packets.
+The default is 1, i.e., start with the first hop.
+.It Fl m Ar max_ttl
+Set the max time-to-live (max number of hops) used in outgoing probe
+packets. The default is
+.Em net.inet.ip.ttl
+hops (the same default used for
+.Tn TCP
+connections).
+.It Fl n
+Print hop addresses numerically rather than symbolically and numerically
+(saves a nameserver address-to-name lookup for each gateway found on the
+path).
+.It Fl P Ar proto
+Send packets of specified IP protocol. The currently supported protocols
+are:
+.Tn UDP
+,
+.Tn TCP
+,
+.Tn GRE
+and
+.Tn ICMP
+Other protocols may also be specified (either by name or by number), though
+.Nm
+does not implement any special knowledge of their packet formats. This
+option is useful for determining which router along a path may be
+blocking packets based on IP protocol number. But see BUGS below.
+.It Fl p Ar port
+Protocol specific. For
+.Tn UDP
+and
+.Tn TCP,
+sets the base
+.Ar port
+number used in probes (default is 33434).
+.Nm
+hopes that nothing is listening on
+.Tn UDP
+ports
+.Em base
+to
+.Em base+nhops-1
+at the destination host (so an
+.Tn ICMP
+.Dv PORT_UNREACHABLE
+message will
+be returned to terminate the route tracing). If something is
+listening on a port in the default range, this option can be used
+to pick an unused port range.
+.It Fl q Ar nqueries
+Set the number of probes per ``ttl'' to
+.Ar nqueries
+(default is three probes).
+.It Fl r
+Bypass the normal routing tables and send directly to a host on an attached
+network.
+If the host is not on a directly-attached network,
+an error is returned.
+This option can be used to ping a local host through an interface
+that has no route through it (e.g., after the interface was dropped by
+.Xr routed 8 ) .
+.It Fl s Ar src_addr
+Use the following IP address
+(which must be given as an IP number, not
+a hostname) as the source address in outgoing probe packets. On
+hosts with more than one IP address, this option can be used to
+force the source address to be something other than the IP address
+of the interface the probe packet is sent on. If the IP address
+is not one of this machine's interface addresses, an error is
+returned and nothing is sent.
+(See the
+.Fl i
+flag for another way to do this.)
+.It Fl S
+Print a summary of how many probes were not answered for each hop.
+.It Fl t Ar tos
+Set the
+.Em type-of-service
+in probe packets to the following value (default zero). The value must be
+a decimal integer in the range 0 to 255. This option can be used to
+see if different types-of-service result in different paths. (If you
+are not running a
+.Bx 4.4
+or later system, this may be academic since the normal network
+services like telnet and ftp don't let you control the
+.Dv TOS ) .
+Not all values of
+.Dv TOS
+are legal or
+meaningful \- see the IP spec for definitions. Useful values are
+probably
+.Ql \-t 16
+(low delay) and
+.Ql \-t 8
+(high throughput).
+.It Fl v
+Verbose output. Received
+.Tn ICMP
+packets other than
+.Dv TIME_EXCEEDED
+and
+.Dv UNREACHABLE Ns s
+are listed.
+.It Fl w
+Set the time (in seconds) to wait for a response to a probe (default 5 sec.).
+.It Fl x
+Toggle IP checksums. Normally, this prevents
+.Nm
+from calculating
+IP checksums. In some cases, the operating system can overwrite parts of
+the outgoing packet but not recalculate the checksum (so in some cases
+the default is to not calculate checksums and using
+.Fl x
+causes them to be calculated). Note that checksums are usually required
+for the last hop when using
+.Tn ICMP
+ECHO probes (
+.Fl I
+). So they are always calculated when using ICMP.
+.It Fl z Ar pausemsecs
+Set the time (in milliseconds) to pause between probes (default 0).
+Some systems such as Solaris and routers such as Ciscos rate limit
+ICMP messages. A good value to use with this this is 500 (e.g. 1/2 second).
+.El
+.Pp
+This program attempts to trace the route an IP packet would follow to some
+internet host by launching
+.Tn UDP
+probe
+packets with a small ttl (time to live) then listening for an
+.Tn ICMP
+"time exceeded" reply from a gateway. We start our probes
+with a ttl of one and increase by one until we get an
+.Tn ICMP
+"port unreachable"
+(which means we got to "host") or hit a max (which
+defaults to
+.Em net.inet.ip.ttl
+hops & can be changed with the
+.Fl m
+flag). Three
+probes (changed with
+.Fl q
+flag) are sent at each ttl setting and a
+line is printed showing the ttl, address of the gateway and
+round trip time of each probe. If the probe answers come from
+different gateways, the address of each responding system will
+be printed. If there is no response within a 5 sec. timeout
+interval (changed with the
+.Fl w
+flag), a "*" is printed for that
+probe.
+.Pp
+We don't want the destination
+host to process the
+.Tn UDP
+probe packets so the destination port is set to an
+unlikely value (if some clod on the destination is using that
+value, it can be changed with the
+.Fl p
+flag).
+.Pp
+A sample use and output might be:
+.Bd -literal
+[yak 71]% traceroute nis.nsf.net.
+traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 38 byte packet
+1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
+5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
+6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
+7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
+8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
+9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
+10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
+11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
+
+.Ed
+Note that lines 2 & 3 are the same. This is due to a buggy
+kernel on the 2nd hop system \- lbl-csam.arpa \- that forwards
+packets with a zero ttl (a bug in the distributed version
+of 4.3
+.Tn BSD ) .
+Note that you have to guess what path
+the packets are taking cross-country since the
+.Tn NSFNet
+(129.140)
+doesn't supply address-to-name translations for its
+.Tn NSS Ns es .
+.Pp
+A more interesting example is:
+.Bd -literal
+[yak 72]% traceroute allspice.lcs.mit.edu.
+traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
+1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
+5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
+6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
+7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
+8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
+9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
+10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
+11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
+12 * * *
+13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
+14 * * *
+15 * * *
+16 * * *
+17 * * *
+18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
+
+.Ed
+Note that the gateways 12, 14, 15, 16 & 17 hops away
+either don't send
+.Tn ICMP
+"time exceeded" messages or send them
+with a ttl too small to reach us. 14 \- 17 are running the
+.Tn MIT
+C Gateway code that doesn't send "time exceeded"s. God
+only knows what's going on with 12.
+.Pp
+The silent gateway 12 in the above may be the result of a bug in
+the 4.[23]
+.Tn BSD
+network code (and its derivatives): 4.x (x <= 3)
+sends an unreachable message using whatever ttl remains in the
+original datagram. Since, for gateways, the remaining ttl is
+zero, the
+.Tn ICMP
+"time exceeded" is guaranteed to not make it back
+to us. The behavior of this bug is slightly more interesting
+when it appears on the destination system:
+.Bd -literal
+1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
+3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
+4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
+5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
+6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
+7 * * *
+8 * * *
+9 * * *
+10 * * *
+11 * * *
+12 * * *
+13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
+
+.Ed
+Notice that there are 12 "gateways" (13 is the final
+destination) and exactly the last half of them are "missing".
+What's really happening is that rip (a Sun-3 running Sun OS3.5)
+is using the ttl from our arriving datagram as the ttl in its
+.Tn ICMP
+reply. So, the reply will time out on the return path
+(with no notice sent to anyone since
+.Tn ICMP's
+aren't sent for
+.Tn ICMP's )
+until we probe with a ttl that's at least twice the path
+length. I.e., rip is really only 7 hops away. A reply that
+returns with a ttl of 1 is a clue this problem exists.
+.Nm
+prints a "!" after the time if the ttl is <= 1.
+Since vendors ship a lot of obsolete
+.Pf ( Tn DEC Ns \'s
+Ultrix, Sun 3.x) or
+non-standard
+.Pq Tn HPUX
+software, expect to see this problem
+frequently and/or take care picking the target host of your
+probes.
+.Pp
+Other possible annotations after the time are
+.Sy !H ,
+.Sy !N ,
+or
+.Sy !P
+(host, network or protocol unreachable),
+.Sy !S
+(source route failed),
+.B !F\-<pmtu>
+(fragmentation needed \- the RFC1191 Path MTU Discovery value is displayed),
+.Sy !U
+or
+.Sy !W
+(destination network/host unknown),
+.Sy !I
+(source host is isolated),
+.Sy !A
+(communication with destination network administratively prohibited),
+.Sy !Z
+(communication with destination host administratively prohibited),
+.Sy !Q
+(for this ToS the destination network is unreachable),
+.Sy !T
+(for this ToS the destination host is unreachable),
+.Sy !X
+(communication administratively prohibited),
+.Sy !V
+(host precedence violation),
+.Sy !C
+(precedence cutoff in effect), or
+.Sy !<num>
+(ICMP unreachable code <num>).
+These are defined by RFC1812 (which supersedes RFC1716).
+If almost all the probes result in some kind of unreachable,
+.Nm
+will give up and exit.
+.Pp
+This program is intended for use in network testing, measurement
+and management.
+It should be used primarily for manual fault isolation.
+Because of the load it could impose on the network, it is unwise to use
+.Nm
+during normal operations or from automated scripts.
+.Sh AUTHOR
+Implemented by Van Jacobson from a suggestion by Steve Deering. Debugged
+by a cast of thousands with particularly cogent suggestions or fixes from
+C. Philip Wood, Tim Seaver and Ken Adelman.
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr ping 8 ,
+.Xr traceroute6 8
+.Sh BUGS
+When using protocols other than UDP, functionality is reduced.
+In particular, the last packet will often appear to be lost, because
+even though it reaches the destination host, there's no way to know
+that because no ICMP message is sent back.
+In the TCP case,
+.Nm
+should listen for a RST from the destination host (or an intermediate
+router that's filtering packets), but this is not implemented yet.
+.Pp
+The AS number capability reports information that may sometimes be
+inaccurate due to discrepancies between the contents of the
+routing database server and the current state of the Internet.
diff --git a/network_cmds/traceroute.tproj/traceroute.c b/network_cmds/traceroute.tproj/traceroute.c
new file mode 100644
index 0000000..a411d0a
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.c
@@ -0,0 +1,1822 @@
+/*
+ * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+ "@(#) Copyright (c) 1988, 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000\n\
+The Regents of the University of California. All rights reserved.\n";
+#endif
+
+/*
+ * traceroute host - trace the route ip packets follow going to "host".
+ *
+ * Attempt to trace the route an ip packet would follow to some
+ * internet host. We find out intermediate hops by launching probe
+ * packets with a small ttl (time to live) then listening for an
+ * icmp "time exceeded" reply from a gateway. We start our probes
+ * with a ttl of one and increase by one until we get an icmp "port
+ * unreachable" (which means we got to "host") or hit a max (which
+ * defaults to net.inet.ip.ttl hops & can be changed with the -m flag).
+ * Three probes (change with -q flag) are sent at each ttl setting and
+ * a line is printed showing the ttl, address of the gateway and
+ * round trip time of each probe. If the probe answers come from
+ * different gateways, the address of each responding system will
+ * be printed. If there is no response within a 5 sec. timeout
+ * interval (changed with the -w flag), a "*" is printed for that
+ * probe.
+ *
+ * Probe packets are UDP format. We don't want the destination
+ * host to process them so the destination port is set to an
+ * unlikely value (if some clod on the destination is using that
+ * value, it can be changed with the -p flag).
+ *
+ * A sample use might be:
+ *
+ * [yak 71]% traceroute nis.nsf.net.
+ * traceroute to nis.nsf.net (35.1.1.48), 64 hops max, 56 byte packet
+ * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
+ * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
+ * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
+ * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
+ *
+ * Note that lines 2 & 3 are the same. This is due to a buggy
+ * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
+ * packets with a zero ttl.
+ *
+ * A more interesting example is:
+ *
+ * [yak 72]% traceroute allspice.lcs.mit.edu.
+ * traceroute to allspice.lcs.mit.edu (18.26.0.115), 64 hops max
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
+ * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
+ * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
+ * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
+ * 12 * * *
+ * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
+ * 14 * * *
+ * 15 * * *
+ * 16 * * *
+ * 17 * * *
+ * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
+ *
+ * (I start to see why I'm having so much trouble with mail to
+ * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
+ * either don't send ICMP "time exceeded" messages or send them
+ * with a ttl too small to reach us. 14 - 17 are running the
+ * MIT C Gateway code that doesn't send "time exceeded"s. God
+ * only knows what's going on with 12.
+ *
+ * The silent gateway 12 in the above may be the result of a bug in
+ * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
+ * sends an unreachable message using whatever ttl remains in the
+ * original datagram. Since, for gateways, the remaining ttl is
+ * zero, the icmp "time exceeded" is guaranteed to not make it back
+ * to us. The behavior of this bug is slightly more interesting
+ * when it appears on the destination system:
+ *
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
+ * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
+ * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
+ * 7 * * *
+ * 8 * * *
+ * 9 * * *
+ * 10 * * *
+ * 11 * * *
+ * 12 * * *
+ * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
+ *
+ * Notice that there are 12 "gateways" (13 is the final
+ * destination) and exactly the last half of them are "missing".
+ * What's really happening is that rip (a Sun-3 running Sun OS3.5)
+ * is using the ttl from our arriving datagram as the ttl in its
+ * icmp reply. So, the reply will time out on the return path
+ * (with no notice sent to anyone since icmp's aren't sent for
+ * icmp's) until we probe with a ttl that's at least twice the path
+ * length. I.e., rip is really only 7 hops away. A reply that
+ * returns with a ttl of 1 is a clue this problem exists.
+ * Traceroute prints a "!" after the time if the ttl is <= 1.
+ * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
+ * non-standard (HPUX) software, expect to see this problem
+ * frequently and/or take care picking the target host of your
+ * probes.
+ *
+ * Other possible annotations after the time are !H, !N, !P (got a host,
+ * network or protocol unreachable, respectively), !S or !F (source
+ * route failed or fragmentation needed -- neither of these should
+ * ever occur and the associated gateway is busted if you see one). If
+ * almost all the probes result in some kind of unreachable, traceroute
+ * will give up and exit.
+ *
+ * Notes
+ * -----
+ * This program must be run by root or be setuid. (I suggest that
+ * you *don't* make it setuid -- casual use could result in a lot
+ * of unnecessary traffic on our poor, congested nets.)
+ *
+ * This program requires a kernel mod that does not appear in any
+ * system available from Berkeley: A raw ip socket using proto
+ * IPPROTO_RAW must interpret the data sent as an ip datagram (as
+ * opposed to data to be wrapped in a ip datagram). See the README
+ * file that came with the source to this program for a description
+ * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
+ * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
+ * MODIFIED TO RUN THIS PROGRAM.
+ *
+ * The udp port usage may appear bizarre (well, ok, it is bizarre).
+ * The problem is that an icmp message only contains 8 bytes of
+ * data from the original datagram. 8 bytes is the size of a udp
+ * header so, if we want to associate replies with the original
+ * datagram, the necessary information must be encoded into the
+ * udp header (the ip id could be used but there's no way to
+ * interlock with the kernel's assignment of ip id's and, anyway,
+ * it would have taken a lot more kernel hacking to allow this
+ * code to set the ip id). So, to allow two or more users to
+ * use traceroute simultaneously, we use this task's pid as the
+ * source port (the high bit is set to move the port number out
+ * of the "likely" range). To keep track of which probe is being
+ * replied to (so times and/or hop counts don't get confused by a
+ * reply that was delayed in transit), we increment the destination
+ * port number before each probe.
+ *
+ * Don't use this as a coding example. I was trying to find a
+ * routing problem and this code sort-of popped out after 48 hours
+ * without sleep. I was amazed it ever compiled, much less ran.
+ *
+ * I stole the idea for this program from Steve Deering. Since
+ * the first release, I've learned that had I attended the right
+ * IETF working group meetings, I also could have stolen it from Guy
+ * Almes or Matt Mathis. I don't know (or care) who came up with
+ * the idea first. I envy the originators' perspicacity and I'm
+ * glad they didn't keep the idea a secret.
+ *
+ * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
+ * enhancements to the original distribution.
+ *
+ * I've hacked up a round-trip-route version of this that works by
+ * sending a loose-source-routed udp datagram through the destination
+ * back to yourself. Unfortunately, SO many gateways botch source
+ * routing, the thing is almost worthless. Maybe one day...
+ *
+ * -- Van Jacobson (van@ee.lbl.gov)
+ * Tue Dec 20 03:50:13 PST 1988
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+#include <sys/time.h>
+
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+#include <netinet/tcp.h>
+#include <netinet/tcpip.h>
+
+#include <arpa/inet.h>
+
+#ifdef IPSEC
+#include <net/route.h>
+#include <netinet6/ipsec.h> /* XXX */
+#endif /* IPSEC */
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#include <memory.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "gnuc.h"
+#ifdef HAVE_OS_PROTO_H
+#include "os-proto.h"
+#endif
+
+/* rfc1716 */
+#ifndef ICMP_UNREACH_FILTER_PROHIB
+#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */
+#endif
+#ifndef ICMP_UNREACH_HOST_PRECEDENCE
+#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */
+#endif
+#ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF
+#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */
+#endif
+
+#include "findsaddr.h"
+#include "ifaddrlist.h"
+#include "as.h"
+#include "traceroute.h"
+
+/* Maximum number of gateways (include room for one noop) */
+#define NGATEWAYS ((int)((MAX_IPOPTLEN - IPOPT_MINOFF - 1) / sizeof(u_int32_t)))
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#define Fprintf (void)fprintf
+#define Printf (void)printf
+
+/* What a GRE packet header looks like */
+struct grehdr {
+ u_int16_t flags;
+ u_int16_t proto;
+ u_int16_t length; /* PPTP version of these fields */
+ u_int16_t callId;
+};
+#ifndef IPPROTO_GRE
+#define IPPROTO_GRE 47
+#endif
+
+/* For GRE, we prepare what looks like a PPTP packet */
+#define GRE_PPTP_PROTO 0x880b
+
+/* Host name and address list */
+struct hostinfo {
+ char *name;
+ int n;
+ u_int32_t *addrs;
+};
+
+/* Data section of the probe packet */
+struct outdata {
+ u_char seq; /* sequence number of this packet */
+ u_char ttl; /* ttl packet left with */
+ struct timeval tv; /* time packet left */
+};
+
+#ifndef HAVE_ICMP_NEXTMTU
+/* Path MTU Discovery (RFC1191) */
+struct my_pmtu {
+ u_short ipm_void;
+ u_short ipm_nextmtu;
+};
+#endif
+
+u_char packet[512]; /* last inbound (icmp) packet */
+
+struct ip *outip; /* last output ip packet */
+u_char *outp; /* last output inner protocol packet */
+
+struct ip *hip = NULL; /* Quoted IP header */
+int hiplen = 0;
+
+/* loose source route gateway list (including room for final destination) */
+u_int32_t gwlist[NGATEWAYS + 1];
+
+int s; /* receive (icmp) socket file descriptor */
+int sndsock; /* send (udp) socket file descriptor */
+
+struct sockaddr whereto; /* Who to try to reach */
+struct sockaddr wherefrom; /* Who we are */
+int packlen; /* total length of packet */
+int protlen; /* length of protocol part of packet */
+int minpacket; /* min ip packet size */
+int maxpacket = 32 * 1024; /* max ip packet size */
+int pmtu; /* Path MTU Discovery (RFC1191) */
+u_int pausemsecs;
+
+char *prog;
+char *source;
+char *hostname;
+char *device;
+static const char devnull[] = "/dev/null";
+
+int nprobes = -1;
+int max_ttl;
+int first_ttl = 1;
+u_short ident;
+u_short port; /* protocol specific base "port" */
+
+int options; /* socket options */
+int verbose;
+int waittime = 5; /* time to wait for response (in seconds) */
+int nflag; /* print addresses numerically */
+int as_path; /* print as numbers for each hop */
+char *as_server = NULL;
+void *asn;
+#ifdef CANT_HACK_IPCKSUM
+int doipcksum = 0; /* don't calculate ip checksums by default */
+#else
+int doipcksum = 1; /* calculate ip checksums by default */
+#endif
+int optlen; /* length of ip options */
+int fixedPort = 0; /* Use fixed destination port for TCP and UDP */
+int printdiff = 0; /* Print the difference between sent and quoted */
+
+extern int optind;
+extern int opterr;
+extern char *optarg;
+
+/* Forwards */
+double deltaT(struct timeval *, struct timeval *);
+void freehostinfo(struct hostinfo *);
+void getaddr(u_int32_t *, char *);
+struct hostinfo *gethostinfo(char *);
+u_short in_cksum(u_short *, int);
+char *inetname(struct in_addr);
+int main(int, char **);
+u_short p_cksum(struct ip *, u_short *, int);
+int packet_ok(u_char *, int, struct sockaddr_in *, int);
+char *pr_type(u_char);
+void print(u_char *, int, struct sockaddr_in *);
+#ifdef IPSEC
+int setpolicy __P((int so, char *policy));
+#endif
+void send_probe(int, int);
+struct outproto *setproto(char *);
+int str2val(const char *, const char *, int, int);
+void tvsub(struct timeval *, struct timeval *);
+void usage(void);
+int wait_for_reply(int, struct sockaddr_in *, const struct timeval *);
+void pkt_compare(const u_char *, int, const u_char *, int);
+#ifndef HAVE_USLEEP
+int usleep(u_int);
+#endif
+
+void udp_prep(struct outdata *);
+int udp_check(const u_char *, int);
+void tcp_prep(struct outdata *);
+int tcp_check(const u_char *, int);
+void gre_prep(struct outdata *);
+int gre_check(const u_char *, int);
+void gen_prep(struct outdata *);
+int gen_check(const u_char *, int);
+void icmp_prep(struct outdata *);
+int icmp_check(const u_char *, int);
+
+/* Descriptor structure for each outgoing protocol we support */
+struct outproto {
+ char *name; /* name of protocol */
+ const char *key; /* An ascii key for the bytes of the header */
+ u_char num; /* IP protocol number */
+ u_short hdrlen; /* max size of protocol header */
+ u_short port; /* default base protocol-specific "port" */
+ void (*prepare)(struct outdata *);
+ /* finish preparing an outgoing packet */
+ int (*check)(const u_char *, int);
+ /* check an incoming packet */
+};
+
+/* List of supported protocols. The first one is the default. The last
+ one is the handler for generic protocols not explicitly listed. */
+struct outproto protos[] = {
+ {
+ "udp",
+ "spt dpt len sum",
+ IPPROTO_UDP,
+ sizeof(struct udphdr),
+ 32768 + 666,
+ udp_prep,
+ udp_check
+ },
+ {
+ "tcp",
+ "spt dpt seq ack xxflwin sum urp",
+ IPPROTO_TCP,
+ sizeof(struct tcphdr),
+ 32768 + 666,
+ tcp_prep,
+ tcp_check
+ },
+ {
+ "gre",
+ "flg pro len clid",
+ IPPROTO_GRE,
+ sizeof(struct grehdr),
+ GRE_PPTP_PROTO,
+ gre_prep,
+ gre_check
+ },
+ {
+ "icmp",
+ "typ cod sum ",
+ IPPROTO_ICMP,
+ sizeof(struct icmp),
+ 0,
+ icmp_prep,
+ icmp_check
+ },
+ {
+ NULL,
+ NULL,
+ 0,
+ 2 * sizeof(u_short),
+ 0,
+ gen_prep,
+ gen_check
+ },
+};
+struct outproto *proto = &protos[0];
+
+const char *ip_hdr_key = "vhtslen id off tlprsum srcip dstip opts";
+
+int
+main(int argc, char **argv)
+{
+ register int op, code, n;
+ register char *cp;
+ register const char *err;
+ register u_int32_t *ap;
+ register struct sockaddr_in *from = (struct sockaddr_in *)&wherefrom;
+ register struct sockaddr_in *to = (struct sockaddr_in *)&whereto;
+ register struct hostinfo *hi;
+ int on = 1;
+ register struct protoent *pe;
+ register int ttl, probe, i;
+ register int seq = 0;
+ int tos = 0, settos = 0;
+ register int lsrr = 0;
+ register u_short off = 0;
+ struct ifaddrlist *al;
+ char errbuf[132];
+ int requestPort = -1;
+ int sump = 0;
+ int sockerrno = 0;
+
+ if (argv[0] == NULL)
+ prog = "traceroute";
+ else if ((cp = strrchr(argv[0], '/')) != NULL)
+ prog = cp + 1;
+ else
+ prog = argv[0];
+
+ /* Insure the socket fds won't be 0, 1 or 2 */
+ if (open(devnull, O_RDONLY) < 0 ||
+ open(devnull, O_RDONLY) < 0 ||
+ open(devnull, O_RDONLY) < 0) {
+ Fprintf(stderr, "%s: open \"%s\": %s\n",
+ prog, devnull, strerror(errno));
+ exit(1);
+ }
+ /*
+ * Do the setuid-required stuff first, then lose priveleges ASAP.
+ * Do error checking for these two calls where they appeared in
+ * the original code.
+ */
+ cp = "icmp";
+ pe = getprotobyname(cp);
+ if (pe) {
+ if ((s = socket(AF_INET, SOCK_RAW, pe->p_proto)) < 0)
+ sockerrno = errno;
+ else if ((sndsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
+ sockerrno = errno;
+ }
+
+ setuid(getuid());
+
+#ifdef IPCTL_DEFTTL
+ {
+ int mib[4] = { CTL_NET, PF_INET, IPPROTO_IP, IPCTL_DEFTTL };
+ size_t sz = sizeof(max_ttl);
+
+ if (sysctl(mib, 4, &max_ttl, &sz, NULL, 0) == -1) {
+ perror("sysctl(net.inet.ip.ttl)");
+ exit(1);
+ }
+ }
+#else
+ max_ttl = 30;
+#endif
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "aA:edDFInrSvxf:g:i:M:m:P:p:q:s:t:w:z:")) != EOF)
+ switch (op) {
+ case 'a':
+ as_path = 1;
+ break;
+
+ case 'A':
+ as_path = 1;
+ as_server = optarg;
+ break;
+
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+
+ case 'D':
+ printdiff = 1;
+ break;
+
+ case 'e':
+ fixedPort = 1;
+ break;
+
+ case 'f':
+ case 'M': /* FreeBSD compat. */
+ first_ttl = str2val(optarg, "first ttl", 1, 255);
+ break;
+
+ case 'F':
+ off = IP_DF;
+ break;
+
+ case 'g':
+ if (lsrr >= NGATEWAYS) {
+ Fprintf(stderr,
+ "%s: No more than %d gateways\n",
+ prog, NGATEWAYS);
+ exit(1);
+ }
+ getaddr(gwlist + lsrr, optarg);
+ ++lsrr;
+ break;
+
+ case 'i':
+ device = optarg;
+ break;
+
+ case 'I':
+ proto = setproto("icmp");
+ break;
+
+ case 'm':
+ max_ttl = str2val(optarg, "max ttl", 1, 255);
+ break;
+
+ case 'n':
+ ++nflag;
+ break;
+
+ case 'P':
+ proto = setproto(optarg);
+ break;
+
+ case 'p':
+ requestPort = (u_short)str2val(optarg, "port",
+ 1, (1 << 16) - 1);
+ break;
+
+ case 'q':
+ nprobes = str2val(optarg, "nprobes", 1, -1);
+ break;
+
+ case 'r':
+ options |= SO_DONTROUTE;
+ break;
+
+ case 's':
+ /*
+ * set the ip source address of the outbound
+ * probe (e.g., on a multi-homed host).
+ */
+ source = optarg;
+ break;
+
+ case 'S':
+ sump = 1;
+ break;
+
+ case 't':
+ tos = str2val(optarg, "tos", 0, 255);
+ ++settos;
+ break;
+
+ case 'v':
+ ++verbose;
+ break;
+
+ case 'x':
+ doipcksum = (doipcksum == 0);
+ break;
+
+ case 'w':
+ waittime = str2val(optarg, "wait time",
+ 1, 24 * 60 * 60);
+ break;
+
+ case 'z':
+ pausemsecs = str2val(optarg, "pause msecs",
+ 0, 60 * 60 * 1000);
+ break;
+
+ default:
+ usage();
+ }
+
+ /* Set requested port, if any, else default for this protocol */
+ port = (requestPort != -1) ? requestPort : proto->port;
+
+ if (nprobes == -1)
+ nprobes = printdiff ? 1 : 3;
+
+ if (first_ttl > max_ttl) {
+ Fprintf(stderr,
+ "%s: first ttl (%d) may not be greater than max ttl (%d)\n",
+ prog, first_ttl, max_ttl);
+ exit(1);
+ }
+
+ if (!doipcksum)
+ Fprintf(stderr, "%s: Warning: ip checksums disabled\n", prog);
+
+ if (lsrr > 0)
+ optlen = (lsrr + 1) * sizeof(gwlist[0]);
+ minpacket = sizeof(*outip) + proto->hdrlen + sizeof(struct outdata) + optlen;
+ packlen = minpacket; /* minimum sized packet */
+
+ /* Process destination and optional packet size */
+ switch (argc - optind) {
+
+ case 2:
+ packlen = str2val(argv[optind + 1],
+ "packet length", minpacket, maxpacket);
+ /* Fall through */
+
+ case 1:
+ hostname = argv[optind];
+ hi = gethostinfo(hostname);
+ setsin(to, hi->addrs[0]);
+ if (hi->n > 1)
+ Fprintf(stderr,
+ "%s: Warning: %s has multiple addresses; using %s\n",
+ prog, hostname, inet_ntoa(to->sin_addr));
+ hostname = hi->name;
+ hi->name = NULL;
+ freehostinfo(hi);
+ break;
+
+ default:
+ usage();
+ }
+
+#ifdef HAVE_SETLINEBUF
+ setlinebuf (stdout);
+#else
+ setvbuf(stdout, NULL, _IOLBF, 0);
+#endif
+
+ protlen = packlen - sizeof(*outip) - optlen;
+
+ outip = (struct ip *)malloc((unsigned)packlen);
+ if (outip == NULL) {
+ Fprintf(stderr, "%s: malloc: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ memset((char *)outip, 0, packlen);
+
+ outip->ip_v = IPVERSION;
+ if (settos)
+ outip->ip_tos = tos;
+#ifdef BYTESWAP_IP_HDR
+ outip->ip_len = htons(packlen);
+ outip->ip_off = htons(off);
+#else
+ outip->ip_len = packlen;
+ outip->ip_off = off;
+#endif
+ outip->ip_p = proto->num;
+ outp = (u_char *)(outip + 1);
+#ifdef HAVE_RAW_OPTIONS
+ if (lsrr > 0) {
+ register u_char *optlist;
+
+ optlist = outp;
+ outp += optlen;
+
+ /* final hop */
+ gwlist[lsrr] = to->sin_addr.s_addr;
+
+ outip->ip_dst.s_addr = gwlist[0];
+
+ /* force 4 byte alignment */
+ optlist[0] = IPOPT_NOP;
+ /* loose source route option */
+ optlist[1] = IPOPT_LSRR;
+ i = lsrr * sizeof(gwlist[0]);
+ optlist[2] = i + 3;
+ /* Pointer to LSRR addresses */
+ optlist[3] = IPOPT_MINOFF;
+ memcpy(optlist + 4, gwlist + 1, i);
+ } else
+#endif
+ outip->ip_dst = to->sin_addr;
+
+ outip->ip_hl = (outp - (u_char *)outip) >> 2;
+ ident = (getpid() & 0xffff) | 0x8000;
+
+ if (pe == NULL) {
+ Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
+ exit(1);
+ }
+ if (s < 0) {
+ errno = sockerrno;
+ Fprintf(stderr, "%s: icmp socket: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ (void) setsockopt(s, SOL_SOCKET, SO_RECV_ANYIF, (char *)&on,
+ sizeof(on));
+ if (options & SO_DEBUG)
+ (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
+ sizeof(on));
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(s, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+
+ if (setpolicy(s, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
+
+ if (sndsock < 0) {
+ errno = sockerrno;
+ Fprintf(stderr, "%s: raw socket: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+
+#if defined(IP_OPTIONS) && !defined(HAVE_RAW_OPTIONS)
+ if (lsrr > 0) {
+ u_char optlist[MAX_IPOPTLEN];
+
+ cp = "ip";
+ if ((pe = getprotobyname(cp)) == NULL) {
+ Fprintf(stderr, "%s: unknown protocol %s\n", prog, cp);
+ exit(1);
+ }
+
+ /* final hop */
+ gwlist[lsrr] = to->sin_addr.s_addr;
+ ++lsrr;
+
+ /* force 4 byte alignment */
+ optlist[0] = IPOPT_NOP;
+ /* loose source route option */
+ optlist[1] = IPOPT_LSRR;
+ i = lsrr * sizeof(gwlist[0]);
+ optlist[2] = i + 3;
+ /* Pointer to LSRR addresses */
+ optlist[3] = IPOPT_MINOFF;
+ memcpy(optlist + 4, gwlist, i);
+
+ if ((setsockopt(sndsock, pe->p_proto, IP_OPTIONS,
+ (char *)optlist, i + sizeof(gwlist[0]))) < 0) {
+ Fprintf(stderr, "%s: IP_OPTIONS: %s\n",
+ prog, strerror(errno));
+ exit(1);
+ }
+ }
+#endif
+
+#ifdef SO_SNDBUF
+ if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&packlen,
+ sizeof(packlen)) < 0) {
+ Fprintf(stderr, "%s: SO_SNDBUF: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+#endif
+#ifdef IP_HDRINCL
+ if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
+ sizeof(on)) < 0) {
+ Fprintf(stderr, "%s: IP_HDRINCL: %s\n", prog, strerror(errno));
+ exit(1);
+ }
+#else
+#ifdef IP_TOS
+ if (settos && setsockopt(sndsock, IPPROTO_IP, IP_TOS,
+ (char *)&tos, sizeof(tos)) < 0) {
+ Fprintf(stderr, "%s: setsockopt tos %d: %s\n",
+ prog, tos, strerror(errno));
+ exit(1);
+ }
+#endif
+#endif
+ if (options & SO_DEBUG)
+ (void)setsockopt(sndsock, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void)setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE, (char *)&on,
+ sizeof(on));
+
+ /* Get the interface address list */
+ n = ifaddrlist(&al, errbuf, sizeof(errbuf));
+ if (n < 0) {
+ Fprintf(stderr, "%s: ifaddrlist: %s\n", prog, errbuf);
+ exit(1);
+ }
+ if (n == 0) {
+ Fprintf(stderr,
+ "%s: Can't find any network interfaces\n", prog);
+ exit(1);
+ }
+
+ /* Look for a specific device */
+ if (device != NULL) {
+ for (i = n; i > 0; --i, ++al)
+ if (strcmp(device, al->device) == 0)
+ break;
+ if (i <= 0) {
+ Fprintf(stderr, "%s: Can't find interface %.32s\n",
+ prog, device);
+ exit(1);
+ }
+ }
+
+ /* Determine our source address */
+ if (source == NULL) {
+ /*
+ * If a device was specified, use the interface address.
+ * Otherwise, try to determine our source address.
+ */
+ if (device != NULL)
+ setsin(from, al->addr);
+ else if ((err = findsaddr(to, from)) != NULL) {
+ Fprintf(stderr, "%s: findsaddr: %s\n",
+ prog, err);
+ exit(1);
+ }
+ } else {
+ hi = gethostinfo(source);
+ source = hi->name;
+ hi->name = NULL;
+ /*
+ * If the device was specified make sure it
+ * corresponds to the source address specified.
+ * Otherwise, use the first address (and warn if
+ * there are more than one).
+ */
+ if (device != NULL) {
+ for (i = hi->n, ap = hi->addrs; i > 0; --i, ++ap)
+ if (*ap == al->addr)
+ break;
+ if (i <= 0) {
+ Fprintf(stderr,
+ "%s: %s is not on interface %.32s\n",
+ prog, source, device);
+ exit(1);
+ }
+ setsin(from, *ap);
+ } else {
+ setsin(from, hi->addrs[0]);
+ if (hi->n > 1)
+ Fprintf(stderr,
+ "%s: Warning: %s has multiple addresses; using %s\n",
+ prog, source, inet_ntoa(from->sin_addr));
+ }
+ freehostinfo(hi);
+ }
+
+ outip->ip_src = from->sin_addr;
+
+ /* Check the source address (-s), if any, is valid */
+ if (bind(sndsock, (struct sockaddr *)from, sizeof(*from)) < 0) {
+ Fprintf(stderr, "%s: bind: %s\n",
+ prog, strerror(errno));
+ exit (1);
+ }
+
+ if (as_path) {
+ asn = as_setup(as_server);
+ if (asn == NULL) {
+ Fprintf(stderr, "%s: as_setup failed, AS# lookups"
+ " disabled\n", prog);
+ (void)fflush(stderr);
+ as_path = 0;
+ }
+ }
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(sndsock, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+
+ if (setpolicy(sndsock, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#endif /* defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) */
+
+ Fprintf(stderr, "%s to %s (%s)",
+ prog, hostname, inet_ntoa(to->sin_addr));
+ if (source)
+ Fprintf(stderr, " from %s", source);
+ Fprintf(stderr, ", %d hops max, %d byte packets\n", max_ttl, packlen);
+ (void)fflush(stderr);
+
+ for (ttl = first_ttl; ttl <= max_ttl; ++ttl) {
+ u_int32_t lastaddr = 0;
+ int gotlastaddr = 0;
+ int got_there = 0;
+ int unreachable = 0;
+ int sentfirst = 0;
+ int loss;
+
+ Printf("%2d ", ttl);
+ for (probe = 0, loss = 0; probe < nprobes; ++probe) {
+ register int cc;
+ struct timeval t1, t2;
+ struct timezone tz;
+ register struct ip *ip;
+ struct outdata outdata;
+
+ if (sentfirst && pausemsecs > 0)
+ usleep(pausemsecs * 1000);
+ /* Prepare outgoing data */
+ outdata.seq = ++seq;
+ outdata.ttl = ttl;
+
+ /* Avoid alignment problems by copying bytewise: */
+ (void)gettimeofday(&t1, &tz);
+ memcpy(&outdata.tv, &t1, sizeof(outdata.tv));
+
+ /* Finalize and send packet */
+ (*proto->prepare)(&outdata);
+ send_probe(seq, ttl);
+ ++sentfirst;
+
+ /* Wait for a reply */
+ while ((cc = wait_for_reply(s, from, &t1)) != 0) {
+ double T;
+ int precis;
+
+ (void)gettimeofday(&t2, &tz);
+ i = packet_ok(packet, cc, from, seq);
+ /* Skip short packet */
+ if (i == 0)
+ continue;
+ if (!gotlastaddr ||
+ from->sin_addr.s_addr != lastaddr) {
+ if (gotlastaddr) printf("\n ");
+ print(packet, cc, from);
+ lastaddr = from->sin_addr.s_addr;
+ ++gotlastaddr;
+ }
+ T = deltaT(&t1, &t2);
+#ifdef SANE_PRECISION
+ if (T >= 1000.0)
+ precis = 0;
+ else if (T >= 100.0)
+ precis = 1;
+ else if (T >= 10.0)
+ precis = 2;
+ else
+#endif
+ precis = 3;
+ Printf(" %.*f ms", precis, T);
+ if (printdiff) {
+ Printf("\n");
+ Printf("%*.*s%s\n",
+ -(outip->ip_hl << 3),
+ outip->ip_hl << 3,
+ ip_hdr_key,
+ proto->key);
+ pkt_compare((void *)outip, packlen,
+ (void *)hip, hiplen);
+ }
+ if (i == -2) {
+#ifndef ARCHAIC
+ ip = (struct ip *)packet;
+ if (ip->ip_ttl <= 1)
+ Printf(" !");
+#endif
+ ++got_there;
+ break;
+ }
+ /* time exceeded in transit */
+ if (i == -1)
+ break;
+ code = i - 1;
+ switch (code) {
+
+ case ICMP_UNREACH_PORT:
+#ifndef ARCHAIC
+ ip = (struct ip *)packet;
+ if (ip->ip_ttl <= 1)
+ Printf(" !");
+#endif
+ ++got_there;
+ break;
+
+ case ICMP_UNREACH_NET:
+ ++unreachable;
+ Printf(" !N");
+ break;
+
+ case ICMP_UNREACH_HOST:
+ ++unreachable;
+ Printf(" !H");
+ break;
+
+ case ICMP_UNREACH_PROTOCOL:
+ ++got_there;
+ Printf(" !P");
+ break;
+
+ case ICMP_UNREACH_NEEDFRAG:
+ ++unreachable;
+ Printf(" !F-%d", pmtu);
+ break;
+
+ case ICMP_UNREACH_SRCFAIL:
+ ++unreachable;
+ Printf(" !S");
+ break;
+
+ case ICMP_UNREACH_NET_UNKNOWN:
+ ++unreachable;
+ Printf(" !U");
+ break;
+
+ case ICMP_UNREACH_HOST_UNKNOWN:
+ ++unreachable;
+ Printf(" !W");
+ break;
+
+ case ICMP_UNREACH_ISOLATED:
+ ++unreachable;
+ Printf(" !I");
+ break;
+
+ case ICMP_UNREACH_NET_PROHIB:
+ ++unreachable;
+ Printf(" !A");
+ break;
+
+ case ICMP_UNREACH_HOST_PROHIB:
+ ++unreachable;
+ Printf(" !Z");
+ break;
+
+ case ICMP_UNREACH_TOSNET:
+ ++unreachable;
+ Printf(" !Q");
+ break;
+
+ case ICMP_UNREACH_TOSHOST:
+ ++unreachable;
+ Printf(" !T");
+ break;
+
+ case ICMP_UNREACH_FILTER_PROHIB:
+ ++unreachable;
+ Printf(" !X");
+ break;
+
+ case ICMP_UNREACH_HOST_PRECEDENCE:
+ ++unreachable;
+ Printf(" !V");
+ break;
+
+ case ICMP_UNREACH_PRECEDENCE_CUTOFF:
+ ++unreachable;
+ Printf(" !C");
+ break;
+
+ default:
+ ++unreachable;
+ Printf(" !<%d>", code);
+ break;
+ }
+ break;
+ }
+ if (cc == 0) {
+ loss++;
+ Printf(" *");
+ }
+ (void)fflush(stdout);
+ }
+ if (sump) {
+ Printf(" (%d%% loss)", (loss * 100) / nprobes);
+ }
+ putchar('\n');
+ if (got_there ||
+ (unreachable > 0 && unreachable >= nprobes - 1))
+ break;
+ }
+ if (as_path)
+ as_shutdown(asn);
+ exit(0);
+}
+
+int
+wait_for_reply(register int sock, register struct sockaddr_in *fromp,
+ register const struct timeval *tp)
+{
+ fd_set *fdsp;
+ size_t nfds;
+ struct timeval now, wait;
+ struct timezone tz;
+ register int cc = 0;
+ register int error;
+ socklen_t fromlen = sizeof(*fromp);
+
+ nfds = howmany(sock + 1, NFDBITS);
+ if ((fdsp = malloc(nfds * sizeof(fd_set))) == NULL)
+ err(1, "malloc");
+ memset(fdsp, 0, nfds * sizeof(fd_set));
+ FD_SET(sock, fdsp);
+
+ wait.tv_sec = tp->tv_sec + waittime;
+ wait.tv_usec = tp->tv_usec;
+ (void)gettimeofday(&now, &tz);
+ tvsub(&wait, &now);
+ if (wait.tv_sec < 0) {
+ wait.tv_sec = 0;
+ wait.tv_usec = 1;
+ }
+
+ error = select(sock + 1, fdsp, NULL, NULL, &wait);
+ if (error == -1 && errno == EINVAL) {
+ Fprintf(stderr, "%s: botched select() args\n", prog);
+ exit(1);
+ }
+ if (error > 0)
+ cc = recvfrom(sock, (char *)packet, sizeof(packet), 0,
+ (struct sockaddr *)fromp, &fromlen);
+
+ free(fdsp);
+ return(cc);
+}
+
+void
+send_probe(int seq, int ttl)
+{
+ register int cc;
+
+ outip->ip_ttl = ttl;
+ outip->ip_id = htons(ident + seq);
+
+ /* XXX undocumented debugging hack */
+ if (verbose > 1) {
+ register const u_short *sp;
+ register int nshorts, i;
+
+ sp = (u_short *)outip;
+ nshorts = (u_int)packlen / sizeof(u_short);
+ i = 0;
+ Printf("[ %d bytes", packlen);
+ while (--nshorts >= 0) {
+ if ((i++ % 8) == 0)
+ Printf("\n\t");
+ Printf(" %04x", ntohs(*sp++));
+ }
+ if (packlen & 1) {
+ if ((i % 8) == 0)
+ Printf("\n\t");
+ Printf(" %02x", *(u_char *)sp);
+ }
+ Printf("]\n");
+ }
+
+#if !defined(IP_HDRINCL) && defined(IP_TTL)
+ if (setsockopt(sndsock, IPPROTO_IP, IP_TTL,
+ (char *)&ttl, sizeof(ttl)) < 0) {
+ Fprintf(stderr, "%s: setsockopt ttl %d: %s\n",
+ prog, ttl, strerror(errno));
+ exit(1);
+ }
+#endif
+
+ cc = sendto(sndsock, (char *)outip,
+ packlen, 0, &whereto, sizeof(whereto));
+ if (cc < 0 || cc != packlen) {
+ if (cc < 0)
+ Fprintf(stderr, "%s: sendto: %s\n",
+ prog, strerror(errno));
+ Printf("%s: wrote %s %d chars, ret=%d\n",
+ prog, hostname, packlen, cc);
+ (void)fflush(stdout);
+ }
+}
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+int
+setpolicy(so, policy)
+ int so;
+ char *policy;
+{
+ char *buf;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL) {
+ warnx("%s", ipsec_strerror());
+ return -1;
+ }
+ (void)setsockopt(so, IPPROTO_IP, IP_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf));
+
+ free(buf);
+
+ return 0;
+}
+#endif
+
+double
+deltaT(struct timeval *t1p, struct timeval *t2p)
+{
+ register double dt;
+
+ dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
+ (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+ return (dt);
+}
+
+/*
+ * Convert an ICMP "type" field to a printable string.
+ */
+char *
+pr_type(register u_char t)
+{
+ static char *ttab[] = {
+ "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable",
+ "Source Quench", "Redirect", "ICMP 6", "ICMP 7",
+ "Echo", "ICMP 9", "ICMP 10", "Time Exceeded",
+ "Param Problem", "Timestamp", "Timestamp Reply", "Info Request",
+ "Info Reply"
+ };
+
+ if (t > 16)
+ return("OUT-OF-RANGE");
+
+ return(ttab[t]);
+}
+
+int
+packet_ok(register u_char *buf, int cc, register struct sockaddr_in *from,
+ register int seq)
+{
+ register struct icmp *icp;
+ register u_char type, code;
+ register int hlen;
+#ifndef ARCHAIC
+ register struct ip *ip;
+
+ ip = (struct ip *) buf;
+ hlen = ip->ip_hl << 2;
+ if (cc < hlen + ICMP_MINLEN) {
+ if (verbose)
+ Printf("packet too short (%d bytes) from %s\n", cc,
+ inet_ntoa(from->sin_addr));
+ return (0);
+ }
+ cc -= hlen;
+ icp = (struct icmp *)(buf + hlen);
+#else
+ icp = (struct icmp *)buf;
+#endif
+ type = icp->icmp_type;
+ code = icp->icmp_code;
+ /* Path MTU Discovery (RFC1191) */
+ if (code != ICMP_UNREACH_NEEDFRAG)
+ pmtu = 0;
+ else {
+#ifdef HAVE_ICMP_NEXTMTU
+ pmtu = ntohs(icp->icmp_nextmtu);
+#else
+ pmtu = ntohs(((struct my_pmtu *)&icp->icmp_void)->ipm_nextmtu);
+#endif
+ }
+ if (type == ICMP_ECHOREPLY
+ && proto->num == IPPROTO_ICMP
+ && (*proto->check)((u_char *)icp, (u_char)seq))
+ return -2;
+ if ((type == ICMP_TIMXCEED && code == ICMP_TIMXCEED_INTRANS) ||
+ type == ICMP_UNREACH) {
+ u_char *inner;
+
+ hip = &icp->icmp_ip;
+ hiplen = ((u_char *)icp + cc) - (u_char *)hip;
+ hlen = hip->ip_hl << 2;
+ inner = (u_char *)((u_char *)hip + hlen);
+ if (hlen + 12 <= cc
+ && hip->ip_p == proto->num
+ && (*proto->check)(inner, (u_char)seq))
+ return (type == ICMP_TIMXCEED ? -1 : code + 1);
+ }
+#ifndef ARCHAIC
+ if (verbose) {
+ register int i;
+ u_int32_t *lp = (u_int32_t *)&icp->icmp_ip;
+
+ Printf("\n%d bytes from %s to ", cc, inet_ntoa(from->sin_addr));
+ Printf("%s: icmp type %d (%s) code %d\n",
+ inet_ntoa(ip->ip_dst), type, pr_type(type), icp->icmp_code);
+ for (i = 4; i < cc ; i += sizeof(*lp))
+ Printf("%2d: x%8.8x\n", i, *lp++);
+ }
+#endif
+ return(0);
+}
+
+void
+icmp_prep(struct outdata *outdata)
+{
+ struct icmp *const icmpheader = (struct icmp *) outp;
+
+ icmpheader->icmp_type = ICMP_ECHO;
+ icmpheader->icmp_id = htons(ident);
+ icmpheader->icmp_seq = htons(outdata->seq);
+ icmpheader->icmp_cksum = 0;
+ icmpheader->icmp_cksum = in_cksum((u_short *)icmpheader, protlen);
+ if (icmpheader->icmp_cksum == 0)
+ icmpheader->icmp_cksum = 0xffff;
+}
+
+int
+icmp_check(const u_char *data, int seq)
+{
+ struct icmp *const icmpheader = (struct icmp *) data;
+
+ return (icmpheader->icmp_id == htons(ident)
+ && icmpheader->icmp_seq == htons(seq));
+}
+
+void
+udp_prep(struct outdata *outdata)
+{
+ struct udphdr *const outudp = (struct udphdr *) outp;
+
+ outudp->uh_sport = htons(ident + (fixedPort ? outdata->seq : 0));
+ outudp->uh_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+ outudp->uh_ulen = htons((u_short)protlen);
+ outudp->uh_sum = 0;
+ if (doipcksum) {
+ u_short sum = p_cksum(outip, (u_short*)outudp, protlen);
+ outudp->uh_sum = (sum) ? sum : 0xffff;
+ }
+
+ return;
+}
+
+int
+udp_check(const u_char *data, int seq)
+{
+ struct udphdr *const udp = (struct udphdr *) data;
+
+ return (ntohs(udp->uh_sport) == ident + (fixedPort ? seq : 0) &&
+ ntohs(udp->uh_dport) == port + (fixedPort ? 0 : seq));
+}
+
+void
+tcp_prep(struct outdata *outdata)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) outp;
+
+ tcp->th_sport = htons(ident);
+ tcp->th_dport = htons(port + (fixedPort ? 0 : outdata->seq));
+ tcp->th_seq = (tcp->th_sport << 16) | (tcp->th_dport +
+ (fixedPort ? outdata->seq : 0));
+ tcp->th_ack = 0;
+ tcp->th_off = 5;
+ tcp->th_flags = TH_SYN;
+ tcp->th_sum = 0;
+
+ if (doipcksum) {
+ u_short sum = p_cksum(outip, (u_short*)tcp, protlen);
+ tcp->th_sum = (sum) ? sum : 0xffff;
+ }
+}
+
+int
+tcp_check(const u_char *data, int seq)
+{
+ struct tcphdr *const tcp = (struct tcphdr *) data;
+
+ return (ntohs(tcp->th_sport) == ident
+ && ntohs(tcp->th_dport) == port + (fixedPort ? 0 : seq))
+ && tcp->th_seq == ((ident << 16) | (port + seq));
+}
+
+void
+gre_prep(struct outdata *outdata)
+{
+ struct grehdr *const gre = (struct grehdr *) outp;
+
+ gre->flags = htons(0x2001);
+ gre->proto = htons(port);
+ gre->length = 0;
+ gre->callId = htons(ident + outdata->seq);
+}
+
+int
+gre_check(const u_char *data, int seq)
+{
+ struct grehdr *const gre = (struct grehdr *) data;
+
+ return(ntohs(gre->proto) == port
+ && ntohs(gre->callId) == ident + seq);
+}
+
+void
+gen_prep(struct outdata *outdata)
+{
+ u_int16_t *const ptr = (u_int16_t *) outp;
+
+ ptr[0] = htons(ident);
+ ptr[1] = htons(port + outdata->seq);
+}
+
+int
+gen_check(const u_char *data, int seq)
+{
+ u_int16_t *const ptr = (u_int16_t *) data;
+
+ return(ntohs(ptr[0]) == ident
+ && ntohs(ptr[1]) == port + seq);
+}
+
+void
+print(register u_char *buf, register int cc, register struct sockaddr_in *from)
+{
+ register struct ip *ip;
+ register int hlen;
+
+ ip = (struct ip *) buf;
+ hlen = ip->ip_hl << 2;
+ cc -= hlen;
+
+ if (as_path)
+ Printf(" [AS%d]", as_lookup(asn, &from->sin_addr));
+
+ if (nflag)
+ Printf(" %s", inet_ntoa(from->sin_addr));
+ else
+ Printf(" %s (%s)", inetname(from->sin_addr),
+ inet_ntoa(from->sin_addr));
+
+ if (verbose)
+ Printf(" %d bytes to %s", cc, inet_ntoa (ip->ip_dst));
+}
+
+/*
+ * Checksum routine for UDP and TCP headers.
+ */
+u_short
+p_cksum(struct ip *ip, u_short *data, int len)
+{
+ static struct ipovly ipo;
+ u_short sumh, sumd;
+ u_int32_t sumt;
+
+ ipo.ih_pr = ip->ip_p;
+ ipo.ih_len = htons(len);
+ ipo.ih_src = ip->ip_src;
+ ipo.ih_dst = ip->ip_dst;
+
+ sumh = in_cksum((u_short*)&ipo, sizeof(ipo)); /* pseudo ip hdr cksum */
+ sumd = in_cksum((u_short*)data, len); /* payload data cksum */
+ sumt = (sumh << 16) | (sumd);
+
+ return ~in_cksum((u_short*)&sumt, sizeof(sumt));
+}
+
+/*
+ * Checksum routine for Internet Protocol family headers (C Version)
+ */
+u_short
+in_cksum(register u_short *addr, register int len)
+{
+ register int nleft = len;
+ register u_short *w = addr;
+ register u_short answer;
+ register int sum = 0;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if (nleft == 1)
+ sum += *(u_char *)w;
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
+
+/*
+ * Subtract 2 timeval structs: out = out - in.
+ * Out is assumed to be within about LONG_MAX seconds of in.
+ */
+void
+tvsub(register struct timeval *out, register struct timeval *in)
+{
+
+ if ((out->tv_usec -= in->tv_usec) < 0) {
+ --out->tv_sec;
+ out->tv_usec += 1000000;
+ }
+ out->tv_sec -= in->tv_sec;
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+char *
+inetname(struct in_addr in)
+{
+ register char *cp;
+ register struct hostent *hp;
+ static int first = 1;
+ static char domain[MAXHOSTNAMELEN + 1], line[MAXHOSTNAMELEN + 1];
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, sizeof(domain) - 1) < 0)
+ domain[0] = '\0';
+ else {
+ cp = strchr(domain, '.');
+ if (cp == NULL) {
+ hp = gethostbyname(domain);
+ if (hp != NULL)
+ cp = strchr(hp->h_name, '.');
+ }
+ if (cp == NULL)
+ domain[0] = '\0';
+ else {
+ ++cp;
+ memmove(domain, cp, strlen(cp) + 1);
+ }
+ }
+ }
+ if (!nflag && in.s_addr != INADDR_ANY) {
+ hp = gethostbyaddr((char *)&in, sizeof(in), AF_INET);
+ if (hp != NULL) {
+ if ((cp = strchr(hp->h_name, '.')) != NULL &&
+ strcmp(cp + 1, domain) == 0)
+ *cp = '\0';
+ (void)strlcpy(line, hp->h_name, sizeof(line));
+ return (line);
+ }
+ }
+ return (inet_ntoa(in));
+}
+
+struct hostinfo *
+gethostinfo(register char *hostname)
+{
+ register int n;
+ register struct hostent *hp;
+ register struct hostinfo *hi;
+ register char **p;
+ register u_int32_t addr, *ap;
+
+ if (strlen(hostname) > 64) {
+ Fprintf(stderr, "%s: hostname \"%.32s...\" is too long\n",
+ prog, hostname);
+ exit(1);
+ }
+ hi = calloc(1, sizeof(*hi));
+ if (hi == NULL) {
+ Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ addr = inet_addr(hostname);
+ if ((int32_t)addr != -1) {
+ hi->name = strdup(hostname);
+ hi->n = 1;
+ hi->addrs = calloc(1, sizeof(hi->addrs[0]));
+ if (hi->addrs == NULL) {
+ Fprintf(stderr, "%s: calloc %s\n",
+ prog, strerror(errno));
+ exit(1);
+ }
+ hi->addrs[0] = addr;
+ return (hi);
+ }
+
+ hp = gethostbyname(hostname);
+ if (hp == NULL) {
+ Fprintf(stderr, "%s: unknown host %s\n", prog, hostname);
+ exit(1);
+ }
+ if (hp->h_addrtype != AF_INET || hp->h_length != 4) {
+ Fprintf(stderr, "%s: bad host %s\n", prog, hostname);
+ exit(1);
+ }
+ hi->name = strdup(hp->h_name);
+ for (n = 0, p = hp->h_addr_list; *p != NULL; ++n, ++p)
+ continue;
+ hi->n = n;
+ hi->addrs = calloc(n, sizeof(hi->addrs[0]));
+ if (hi->addrs == NULL) {
+ Fprintf(stderr, "%s: calloc %s\n", prog, strerror(errno));
+ exit(1);
+ }
+ for (ap = hi->addrs, p = hp->h_addr_list; *p != NULL; ++ap, ++p)
+ memcpy(ap, *p, sizeof(*ap));
+ return (hi);
+}
+
+void
+freehostinfo(register struct hostinfo *hi)
+{
+ if (hi->name != NULL) {
+ free(hi->name);
+ hi->name = NULL;
+ }
+ free((char *)hi->addrs);
+ free((char *)hi);
+}
+
+void
+getaddr(register u_int32_t *ap, register char *hostname)
+{
+ register struct hostinfo *hi;
+
+ hi = gethostinfo(hostname);
+ *ap = hi->addrs[0];
+ freehostinfo(hi);
+}
+
+void
+setsin(register struct sockaddr_in *sin, register u_int32_t addr)
+{
+
+ memset(sin, 0, sizeof(*sin));
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sin->sin_len = sizeof(*sin);
+#endif
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = addr;
+}
+
+/* String to value with optional min and max. Handles decimal and hex. */
+int
+str2val(register const char *str, register const char *what,
+ register int mi, register int ma)
+{
+ register const char *cp;
+ register int val;
+ char *ep;
+
+ if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) {
+ cp = str + 2;
+ val = (int)strtol(cp, &ep, 16);
+ } else
+ val = (int)strtol(str, &ep, 10);
+ if (*ep != '\0') {
+ Fprintf(stderr, "%s: \"%s\" bad value for %s \n",
+ prog, str, what);
+ exit(1);
+ }
+ if (val < mi && mi >= 0) {
+ if (mi == 0)
+ Fprintf(stderr, "%s: %s must be >= %d\n",
+ prog, what, mi);
+ else
+ Fprintf(stderr, "%s: %s must be > %d\n",
+ prog, what, mi - 1);
+ exit(1);
+ }
+ if (val > ma && ma >= 0) {
+ Fprintf(stderr, "%s: %s must be <= %d\n", prog, what, ma);
+ exit(1);
+ }
+ return (val);
+}
+
+struct outproto *
+setproto(char *pname)
+{
+ struct outproto *proto;
+ int i;
+
+ for (i = 0; protos[i].name != NULL; i++) {
+ if (strcasecmp(protos[i].name, pname) == 0) {
+ break;
+ }
+ }
+ proto = &protos[i];
+ if (proto->name == NULL) { /* generic handler */
+ struct protoent *pe;
+ u_int32_t pnum;
+
+ /* Determine the IP protocol number */
+ if ((pe = getprotobyname(pname)) != NULL)
+ pnum = pe->p_proto;
+ else
+ pnum = str2val(optarg, "proto number", 1, 255);
+ proto->num = pnum;
+ }
+ return proto;
+}
+
+void
+pkt_compare(const u_char *a, int la, const u_char *b, int lb) {
+ int l;
+ int i;
+
+ for (i = 0; i < la; i++)
+ Printf("%02x", (unsigned int)a[i]);
+ Printf("\n");
+ l = (la <= lb) ? la : lb;
+ for (i = 0; i < l; i++)
+ if (a[i] == b[i])
+ Printf("__");
+ else
+ Printf("%02x", (unsigned int)b[i]);
+ for (; i < lb; i++)
+ Printf("%02x", (unsigned int)b[i]);
+ Printf("\n");
+}
+
+
+void
+usage(void)
+{
+ extern char version[];
+
+ Fprintf(stderr, "Version %s\n", version);
+ Fprintf(stderr,
+ "Usage: %s [-adDeFInrSvx] [-A as_server] [-f first_ttl] [-g gateway] [-i iface]\n"
+ "\t[-M first_ttl] [-m max_ttl] [-p port] [-P proto] [-q nqueries] [-s src_addr]\n"
+ "\t[-t tos] [-w waittime] [-z pausemsecs] host [packetlen]\n", prog);
+ exit(1);
+}
diff --git a/network_cmds/traceroute.tproj/traceroute.h b/network_cmds/traceroute.tproj/traceroute.h
new file mode 100644
index 0000000..31154d8
--- /dev/null
+++ b/network_cmds/traceroute.tproj/traceroute.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2000
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Id: traceroute.h,v 1.2 2004/08/08 00:27:54 lindak Exp $ (LBL)
+ */
+
+extern char *prog;
+
+void setsin(struct sockaddr_in *, u_int32_t);
diff --git a/network_cmds/traceroute.tproj/version.c b/network_cmds/traceroute.tproj/version.c
new file mode 100644
index 0000000..680dcd4
--- /dev/null
+++ b/network_cmds/traceroute.tproj/version.c
@@ -0,0 +1 @@
+char version[] = "1.4a12+Darwin";
diff --git a/network_cmds/traceroute6.tproj/traceroute6.8 b/network_cmds/traceroute6.tproj/traceroute6.8
new file mode 100644
index 0000000..b5b220b
--- /dev/null
+++ b/network_cmds/traceroute6.tproj/traceroute6.8
@@ -0,0 +1,178 @@
+.\" $KAME: traceroute6.8,v 1.10 2004/06/06 12:35:15 suz Exp $
+.\"
+.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" 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 project 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 PROJECT 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 PROJECT OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.sbin/traceroute6/traceroute6.8,v 1.17 2008/02/10 21:06:38 dwmalone Exp $
+.\"
+.Dd May 17, 1998
+.Dt TRACEROUTE6 8
+.Os
+.\"
+.Sh NAME
+.Nm traceroute6
+.Nd "print the route IPv6 packets will take to a network node"
+.\"
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl dIlnNrvU
+.Ek
+.Bk -words
+.Op Fl f Ar firsthop
+.Ek
+.Bk -words
+.Op Fl g Ar gateway
+.Ek
+.Bk -words
+.Op Fl m Ar hoplimit
+.Ek
+.Bk -words
+.Op Fl p Ar port
+.Ek
+.Bk -words
+.Op Fl q Ar probes
+.Ek
+.Bk -words
+.Op Fl s Ar src
+.Ek
+.Bk -words
+.Op Fl w Ar waittime
+.Ek
+.Bk -words
+.Ar target
+.Op Ar datalen
+.Ek
+.\"
+.Sh DESCRIPTION
+The
+.Nm
+utility
+uses the IPv6 protocol hop limit field to elicit an ICMPv6 TIME_EXCEEDED
+response from each gateway along the path to some host.
+.Pp
+The only mandatory parameter is the destination host name or IPv6 address.
+The default probe datagram carries 12 bytes of payload,
+in addition to the IPv6 header.
+The size of the payload can be specified by giving a length
+(in bytes)
+after the destination host name.
+.Pp
+Other options are:
+.Bl -tag -width Ds
+.It Fl d
+Debug mode.
+.It Fl f Ar firsthop
+Specify how many hops to skip in trace.
+.It Fl g Ar gateway
+Specify intermediate gateway
+.Nm (
+uses routing header).
+.It Fl I
+Use ICMP6 ECHO instead of UDP datagrams.
+.It Fl l
+Print both host hostnames and numeric addresses.
+Normally
+.Nm
+prints only hostnames if
+.Fl n
+is not specified, and only numeric addresses if
+.Fl n
+is specified.
+.It Fl m Ar hoplimit
+Specify maximum hoplimit, up to 255.
+The default is 30 hops.
+.It Fl n
+Do not resolve numeric address to hostname.
+.It Fl N
+Use a packet with no upper layer header for the probes,
+instead of UDP datagrams.
+.It Fl p Ar port
+Set UDP port number to
+.Ar port .
+.It Fl q Ar probes
+Set the number of probe per hop count to
+.Ar probes .
+.It Fl r
+Bypass the normal routing tables and send directly to a host
+on an attached network.
+If the host is not on a directly-connected network,
+an error is returned.
+This option corresponds to the
+.Dv SO_DONTROUTE
+socket option;
+it can be used to ping a local host through an interface
+that has no route through it
+(e.g., after the interface was dropped by a routing daemon).
+.It Fl s Ar src
+.Ar Src
+specifies the source IPv6 address to be used.
+.It Fl U
+Use UDP datagrams for the probes.
+This is the default.
+.It Fl v
+Be verbose.
+.It Fl w Ar waittime
+Specify the delay time between probes.
+.El
+.Pp
+This program prints the route to the given destination and the round-trip
+time to each gateway, in the same manner as traceroute.
+.Pp
+Here is a list of possible annotations after the round-trip time for each gateway:
+.Bl -hang -offset indent
+.It !N
+Destination Unreachable - No Route to Host.
+.It !P
+Destination Unreachable - Administratively Prohibited.
+.It !S
+Destination Unreachable - Not a Neighbour.
+.It !A
+Destination Unreachable - Address Unreachable.
+.It !\&
+This is printed if the hop limit is <= 1 on a port unreachable message.
+This means that the packet got to the destination,
+but that the reply had a hop limit that was just large enough to
+allow it to get back to the source of the traceroute6.
+This was more interesting in the IPv4 case,
+where some IP stack bugs could be identified by this behaviour.
+.El
+.\"
+.Sh RETURN VALUES
+The
+.Nm
+utility will exit with 0 on success, and non-zero on errors.
+.\"
+.Sh SEE ALSO
+.Xr ping 8 ,
+.Xr ping6 8 ,
+.Xr traceroute 8
+.\"
+.Sh HISTORY
+The
+.Nm
+utility first appeared in WIDE hydrangea IPv6 protocol stack kit.
diff --git a/network_cmds/traceroute6.tproj/traceroute6.c b/network_cmds/traceroute6.tproj/traceroute6.c
new file mode 100644
index 0000000..1de7809
--- /dev/null
+++ b/network_cmds/traceroute6.tproj/traceroute6.c
@@ -0,0 +1,1423 @@
+/* $KAME: traceroute6.c,v 1.68 2004/01/25 11:16:12 suz Exp $ */
+
+/*
+ * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+ * 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 project 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 PROJECT 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 PROJECT 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.
+ */
+
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Van Jacobson.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * traceroute host - trace the route ip packets follow going to "host".
+ *
+ * Attempt to trace the route an ip packet would follow to some
+ * internet host. We find out intermediate hops by launching probe
+ * packets with a small ttl (time to live) then listening for an
+ * icmp "time exceeded" reply from a gateway. We start our probes
+ * with a ttl of one and increase by one until we get an icmp "port
+ * unreachable" (which means we got to "host") or hit a max (which
+ * defaults to 30 hops & can be changed with the -m flag). Three
+ * probes (change with -q flag) are sent at each ttl setting and a
+ * line is printed showing the ttl, address of the gateway and
+ * round trip time of each probe. If the probe answers come from
+ * different gateways, the address of each responding system will
+ * be printed. If there is no response within a 5 sec. timeout
+ * interval (changed with the -w flag), a "*" is printed for that
+ * probe.
+ *
+ * Probe packets are UDP format. We don't want the destination
+ * host to process them so the destination port is set to an
+ * unlikely value (if some clod on the destination is using that
+ * value, it can be changed with the -p flag).
+ *
+ * A sample use might be:
+ *
+ * [yak 71]% traceroute nis.nsf.net.
+ * traceroute to nis.nsf.net (35.1.1.48), 30 hops max, 56 byte packet
+ * 1 helios.ee.lbl.gov (128.3.112.1) 19 ms 19 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 39 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 40 ms 59 ms 59 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 59 ms
+ * 8 129.140.70.13 (129.140.70.13) 99 ms 99 ms 80 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 239 ms 319 ms
+ * 10 129.140.81.7 (129.140.81.7) 220 ms 199 ms 199 ms
+ * 11 nic.merit.edu (35.1.1.48) 239 ms 239 ms 239 ms
+ *
+ * Note that lines 2 & 3 are the same. This is due to a buggy
+ * kernel on the 2nd hop system -- lbl-csam.arpa -- that forwards
+ * packets with a zero ttl.
+ *
+ * A more interesting example is:
+ *
+ * [yak 72]% traceroute allspice.lcs.mit.edu.
+ * traceroute to allspice.lcs.mit.edu (18.26.0.115), 30 hops max
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 19 ms 19 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 19 ms 39 ms 39 ms
+ * 5 ccn-nerif22.Berkeley.EDU (128.32.168.22) 20 ms 39 ms 39 ms
+ * 6 128.32.197.4 (128.32.197.4) 59 ms 119 ms 39 ms
+ * 7 131.119.2.5 (131.119.2.5) 59 ms 59 ms 39 ms
+ * 8 129.140.70.13 (129.140.70.13) 80 ms 79 ms 99 ms
+ * 9 129.140.71.6 (129.140.71.6) 139 ms 139 ms 159 ms
+ * 10 129.140.81.7 (129.140.81.7) 199 ms 180 ms 300 ms
+ * 11 129.140.72.17 (129.140.72.17) 300 ms 239 ms 239 ms
+ * 12 * * *
+ * 13 128.121.54.72 (128.121.54.72) 259 ms 499 ms 279 ms
+ * 14 * * *
+ * 15 * * *
+ * 16 * * *
+ * 17 * * *
+ * 18 ALLSPICE.LCS.MIT.EDU (18.26.0.115) 339 ms 279 ms 279 ms
+ *
+ * (I start to see why I'm having so much trouble with mail to
+ * MIT.) Note that the gateways 12, 14, 15, 16 & 17 hops away
+ * either don't send ICMP "time exceeded" messages or send them
+ * with a ttl too small to reach us. 14 - 17 are running the
+ * MIT C Gateway code that doesn't send "time exceeded"s. God
+ * only knows what's going on with 12.
+ *
+ * The silent gateway 12 in the above may be the result of a bug in
+ * the 4.[23]BSD network code (and its derivatives): 4.x (x <= 3)
+ * sends an unreachable message using whatever ttl remains in the
+ * original datagram. Since, for gateways, the remaining ttl is
+ * zero, the icmp "time exceeded" is guaranteed to not make it back
+ * to us. The behavior of this bug is slightly more interesting
+ * when it appears on the destination system:
+ *
+ * 1 helios.ee.lbl.gov (128.3.112.1) 0 ms 0 ms 0 ms
+ * 2 lilac-dmc.Berkeley.EDU (128.32.216.1) 39 ms 19 ms 39 ms
+ * 3 lilac-dmc.Berkeley.EDU (128.32.216.1) 19 ms 39 ms 19 ms
+ * 4 ccngw-ner-cc.Berkeley.EDU (128.32.136.23) 39 ms 40 ms 19 ms
+ * 5 ccn-nerif35.Berkeley.EDU (128.32.168.35) 39 ms 39 ms 39 ms
+ * 6 csgw.Berkeley.EDU (128.32.133.254) 39 ms 59 ms 39 ms
+ * 7 * * *
+ * 8 * * *
+ * 9 * * *
+ * 10 * * *
+ * 11 * * *
+ * 12 * * *
+ * 13 rip.Berkeley.EDU (128.32.131.22) 59 ms ! 39 ms ! 39 ms !
+ *
+ * Notice that there are 12 "gateways" (13 is the final
+ * destination) and exactly the last half of them are "missing".
+ * What's really happening is that rip (a Sun-3 running Sun OS3.5)
+ * is using the ttl from our arriving datagram as the ttl in its
+ * icmp reply. So, the reply will time out on the return path
+ * (with no notice sent to anyone since icmp's aren't sent for
+ * icmp's) until we probe with a ttl that's at least twice the path
+ * length. I.e., rip is really only 7 hops away. A reply that
+ * returns with a ttl of 1 is a clue this problem exists.
+ * Traceroute prints a "!" after the time if the ttl is <= 1.
+ * Since vendors ship a lot of obsolete (DEC's Ultrix, Sun 3.x) or
+ * non-standard (HPUX) software, expect to see this problem
+ * frequently and/or take care picking the target host of your
+ * probes.
+ *
+ * Other possible annotations after the time are !H, !N, !P (got a host,
+ * network or protocol unreachable, respectively), !S or !F (source
+ * route failed or fragmentation needed -- neither of these should
+ * ever occur and the associated gateway is busted if you see one). If
+ * almost all the probes result in some kind of unreachable, traceroute
+ * will give up and exit.
+ *
+ * Notes
+ * -----
+ * This program must be run by root or be setuid. (I suggest that
+ * you *don't* make it setuid -- casual use could result in a lot
+ * of unnecessary traffic on our poor, congested nets.)
+ *
+ * This program requires a kernel mod that does not appear in any
+ * system available from Berkeley: A raw ip socket using proto
+ * IPPROTO_RAW must interpret the data sent as an ip datagram (as
+ * opposed to data to be wrapped in an ip datagram). See the README
+ * file that came with the source to this program for a description
+ * of the mods I made to /sys/netinet/raw_ip.c. Your mileage may
+ * vary. But, again, ANY 4.x (x < 4) BSD KERNEL WILL HAVE TO BE
+ * MODIFIED TO RUN THIS PROGRAM.
+ *
+ * The udp port usage may appear bizarre (well, ok, it is bizarre).
+ * The problem is that an icmp message only contains 8 bytes of
+ * data from the original datagram. 8 bytes is the size of a udp
+ * header so, if we want to associate replies with the original
+ * datagram, the necessary information must be encoded into the
+ * udp header (the ip id could be used but there's no way to
+ * interlock with the kernel's assignment of ip id's and, anyway,
+ * it would have taken a lot more kernel hacking to allow this
+ * code to set the ip id). So, to allow two or more users to
+ * use traceroute simultaneously, we use this task's pid as the
+ * source port (the high bit is set to move the port number out
+ * of the "likely" range). To keep track of which probe is being
+ * replied to (so times and/or hop counts don't get confused by a
+ * reply that was delayed in transit), we increment the destination
+ * port number before each probe.
+ *
+ * Don't use this as a coding example. I was trying to find a
+ * routing problem and this code sort-of popped out after 48 hours
+ * without sleep. I was amazed it ever compiled, much less ran.
+ *
+ * I stole the idea for this program from Steve Deering. Since
+ * the first release, I've learned that had I attended the right
+ * IETF working group meetings, I also could have stolen it from Guy
+ * Almes or Matt Mathis. I don't know (or care) who came up with
+ * the idea first. I envy the originators' perspicacity and I'm
+ * glad they didn't keep the idea a secret.
+ *
+ * Tim Seaver, Ken Adelman and C. Philip Wood provided bug fixes and/or
+ * enhancements to the original distribution.
+ *
+ * I've hacked up a round-trip-route version of this that works by
+ * sending a loose-source-routed udp datagram through the destination
+ * back to yourself. Unfortunately, SO many gateways botch source
+ * routing, the thing is almost worthless. Maybe one day...
+ *
+ * -- Van Jacobson (van@helios.ee.lbl.gov)
+ * Tue Dec 20 03:50:13 PST 1988
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <err.h>
+#ifdef HAVE_POLL
+#include <poll.h>
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#include <netinet/udp.h>
+
+#ifdef IPSEC
+#include <net/route.h>
+#include <netinet6/ipsec.h>
+#endif
+
+#define DUMMY_PORT 10010
+
+#define MAXPACKET 65535 /* max ip packet size */
+
+#ifndef HAVE_GETIPNODEBYNAME
+#define getipnodebyname(x, y, z, u) gethostbyname2((x), (y))
+#define freehostent(x)
+#endif
+
+/*
+ * format of a (udp) probe packet.
+ */
+struct tv32 {
+ u_int32_t tv32_sec;
+ u_int32_t tv32_usec;
+};
+
+struct opacket {
+ u_char seq; /* sequence number of this packet */
+ u_char hops; /* hop limit of the packet */
+ u_char pad[2];
+ struct tv32 tv; /* time packet left */
+} __attribute__((__packed__));
+
+u_char packet[512]; /* last inbound (icmp) packet */
+struct opacket *outpacket; /* last output (udp) packet */
+
+int main(int, char *[]);
+int wait_for_reply(int, struct msghdr *);
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+int setpolicy(int so, char *policy);
+#endif
+#endif
+void send_probe(int, u_long);
+void *get_uphdr(struct ip6_hdr *, u_char *);
+int get_hoplim(struct msghdr *);
+double deltaT(struct timeval *, struct timeval *);
+char *pr_type(int);
+int packet_ok(struct msghdr *, int, int);
+void print(struct msghdr *, int);
+const char *inetname(struct sockaddr *);
+void usage(void);
+
+int rcvsock; /* receive (icmp) socket file descriptor */
+int sndsock; /* send (udp) socket file descriptor */
+
+struct msghdr rcvmhdr;
+struct iovec rcviov[2];
+int rcvhlim;
+struct in6_pktinfo *rcvpktinfo;
+
+struct sockaddr_in6 Src, Dst, Rcv;
+u_long datalen; /* How much data */
+#define ICMP6ECHOLEN 8
+/* XXX: 2064 = 127(max hops in type 0 rthdr) * sizeof(ip6_hdr) + 16(margin) */
+char rtbuf[2064];
+#ifdef USE_RFC2292BIS
+struct ip6_rthdr *rth;
+#endif
+struct cmsghdr *cmsg;
+
+char *source = 0;
+char *hostname;
+
+u_long nprobes = 3;
+u_long first_hop = 1;
+u_long max_hops = 30;
+u_int16_t srcport;
+u_int16_t port = 32768+666; /* start udp dest port # for probe packets */
+u_int16_t ident;
+int options; /* socket options */
+int verbose;
+int waittime = 5; /* time to wait for response (in seconds) */
+int nflag; /* print addresses numerically */
+int useproto = IPPROTO_UDP; /* protocol to use to send packet */
+int lflag; /* print both numerical address & hostname */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int mib[4] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_DEFHLIM };
+ char hbuf[NI_MAXHOST], src0[NI_MAXHOST], *ep;
+ int ch, i, on = 1, seq, rcvcmsglen, error, minlen;
+ struct addrinfo hints, *res;
+ static u_char *rcvcmsgbuf;
+ u_long probe, hops, lport;
+ struct hostent *hp;
+ size_t size;
+
+ /*
+ * Receive ICMP
+ */
+ if ((rcvsock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
+ perror("socket(ICMPv6)");
+ exit(5);
+ }
+
+ size = sizeof(i);
+ (void) sysctl(mib, sizeof(mib)/sizeof(mib[0]), &i, &size, NULL, 0);
+ max_hops = i;
+
+ /* specify to tell receiving interface */
+#ifdef IPV6_RECVPKTINFO
+ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on,
+ sizeof(on)) < 0)
+ err(1, "setsockopt(IPV6_RECVPKTINFO)");
+#else /* old adv. API */
+ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_PKTINFO, &on,
+ sizeof(on)) < 0)
+ err(1, "setsockopt(IPV6_PKTINFO)");
+#endif
+
+ /* specify to tell value of hoplimit field of received IP6 hdr */
+#ifdef IPV6_RECVHOPLIMIT
+ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on,
+ sizeof(on)) < 0)
+ err(1, "setsockopt(IPV6_RECVHOPLIMIT)");
+#else /* old adv. API */
+ if (setsockopt(rcvsock, IPPROTO_IPV6, IPV6_HOPLIMIT, &on,
+ sizeof(on)) < 0)
+ err(1, "setsockopt(IPV6_HOPLIMIT)");
+#endif
+
+ seq = 0;
+
+ while ((ch = getopt(argc, argv, "df:g:Ilm:nNp:q:rs:Uvw:")) != -1)
+ switch (ch) {
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+ case 'f':
+ ep = NULL;
+ errno = 0;
+ first_hop = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep || first_hop > 255) {
+ fprintf(stderr,
+ "traceroute6: invalid min hoplimit.\n");
+ exit(1);
+ }
+ break;
+ case 'g':
+ hp = getipnodebyname(optarg, AF_INET6, 0, &h_errno);
+ if (hp == NULL) {
+ fprintf(stderr,
+ "traceroute6: unknown host %s\n", optarg);
+ exit(1);
+ }
+#ifdef USE_RFC2292BIS
+ if (rth == NULL) {
+ /*
+ * XXX: We can't detect the number of
+ * intermediate nodes yet.
+ */
+ if ((rth = inet6_rth_init((void *)rtbuf,
+ sizeof(rtbuf), IPV6_RTHDR_TYPE_0,
+ 0)) == NULL) {
+ fprintf(stderr,
+ "inet6_rth_init failed.\n");
+ exit(1);
+ }
+ }
+ if (inet6_rth_add((void *)rth,
+ (struct in6_addr *)hp->h_addr)) {
+ fprintf(stderr,
+ "inet6_rth_add failed for %s\n",
+ optarg);
+ exit(1);
+ }
+#else /* old advanced API */
+ if (cmsg == NULL)
+ cmsg = inet6_rthdr_init(rtbuf, IPV6_RTHDR_TYPE_0);
+ inet6_rthdr_add(cmsg, (struct in6_addr *)hp->h_addr,
+ IPV6_RTHDR_LOOSE);
+#endif
+ freehostent(hp);
+ break;
+ case 'I':
+ useproto = IPPROTO_ICMPV6;
+ ident = htons(getpid() & 0xffff); /* same as ping6 */
+ break;
+ case 'l':
+ lflag++;
+ break;
+ case 'm':
+ ep = NULL;
+ errno = 0;
+ max_hops = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep || max_hops > 255) {
+ fprintf(stderr,
+ "traceroute6: invalid max hoplimit.\n");
+ exit(1);
+ }
+ break;
+ case 'n':
+ nflag++;
+ break;
+ case 'N':
+ useproto = IPPROTO_NONE;
+ break;
+ case 'p':
+ ep = NULL;
+ errno = 0;
+ lport = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep) {
+ fprintf(stderr, "traceroute6: invalid port.\n");
+ exit(1);
+ }
+ if (lport == 0 || lport != (lport & 0xffff)) {
+ fprintf(stderr,
+ "traceroute6: port out of range.\n");
+ exit(1);
+ }
+ port = lport & 0xffff;
+ break;
+ case 'q':
+ ep = NULL;
+ errno = 0;
+ nprobes = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep) {
+ fprintf(stderr,
+ "traceroute6: invalid nprobes.\n");
+ exit(1);
+ }
+ if (nprobes < 1) {
+ fprintf(stderr,
+ "traceroute6: nprobes must be >0.\n");
+ exit(1);
+ }
+ break;
+ case 'r':
+ options |= SO_DONTROUTE;
+ break;
+ case 's':
+ /*
+ * set the ip source address of the outbound
+ * probe (e.g., on a multi-homed host).
+ */
+ source = optarg;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'U':
+ useproto = IPPROTO_UDP;
+ break;
+ case 'w':
+ ep = NULL;
+ errno = 0;
+ waittime = strtoul(optarg, &ep, 0);
+ if (errno || !*optarg || *ep) {
+ fprintf(stderr,
+ "traceroute6: invalid wait time.\n");
+ exit(1);
+ }
+ if (waittime < 1) {
+ fprintf(stderr,
+ "traceroute6: wait must be >= 1 sec.\n");
+ exit(1);
+ }
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * Open socket to send probe packets.
+ */
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ sndsock = rcvsock;
+ break;
+ case IPPROTO_UDP:
+ if ((sndsock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("socket(SOCK_DGRAM)");
+ exit(5);
+ }
+ break;
+ case IPPROTO_NONE:
+ if ((sndsock = socket(AF_INET6, SOCK_RAW, IPPROTO_NONE)) < 0) {
+ perror("socket(SOCK_RAW)");
+ exit(5);
+ }
+ break;
+ default:
+ fprintf(stderr, "traceroute6: unknown probe protocol %d",
+ useproto);
+ exit(5);
+ }
+ if (max_hops < first_hop) {
+ fprintf(stderr,
+ "traceroute6: max hoplimit must be larger than first hoplimit.\n");
+ exit(1);
+ }
+
+ /* revoke privs */
+ seteuid(getuid());
+ setuid(getuid());
+
+ if (argc < 1 || argc > 2)
+ usage();
+
+#if 1
+ setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
+#else
+ setlinebuf(stdout);
+#endif
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET6;
+ hints.ai_socktype = SOCK_RAW;
+ hints.ai_protocol = IPPROTO_ICMPV6;
+ hints.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(*argv, NULL, &hints, &res);
+ if (error) {
+ fprintf(stderr,
+ "traceroute6: %s\n", gai_strerror(error));
+ exit(1);
+ }
+ if (res->ai_addrlen != sizeof(Dst)) {
+ fprintf(stderr,
+ "traceroute6: size of sockaddr mismatch\n");
+ exit(1);
+ }
+ memcpy(&Dst, res->ai_addr, res->ai_addrlen);
+ hostname = res->ai_canonname ? strdup(res->ai_canonname) : *argv;
+ if (!hostname) {
+ fprintf(stderr, "traceroute6: not enough core\n");
+ exit(1);
+ }
+ if (res->ai_next) {
+ if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
+ sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(hbuf, "?", sizeof(hbuf));
+ fprintf(stderr, "traceroute6: Warning: %s has multiple "
+ "addresses; using %s\n", hostname, hbuf);
+ }
+
+ if (*++argv) {
+ ep = NULL;
+ errno = 0;
+ datalen = strtoul(*argv, &ep, 0);
+ if (errno || !*argv || *ep) {
+ fprintf(stderr,
+ "traceroute6: invalid packet length.\n");
+ exit(1);
+ }
+ }
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ minlen = ICMP6ECHOLEN + sizeof(struct tv32);
+ break;
+ case IPPROTO_UDP:
+ minlen = sizeof(struct opacket);
+ break;
+ case IPPROTO_NONE:
+ minlen = 0;
+ datalen = 0;
+ break;
+ default:
+ fprintf(stderr, "traceroute6: unknown probe protocol %d.\n",
+ useproto);
+ exit(1);
+ }
+ if (datalen < minlen)
+ datalen = minlen;
+ else if (datalen >= MAXPACKET) {
+ fprintf(stderr,
+ "traceroute6: packet size must be %d <= s < %ld.\n",
+ minlen, (long)MAXPACKET);
+ exit(1);
+ }
+ outpacket = (struct opacket *)malloc((unsigned)datalen);
+ if (!outpacket) {
+ perror("malloc");
+ exit(1);
+ }
+ (void) bzero((char *)outpacket, datalen);
+
+ /* initialize msghdr for receiving packets */
+ rcviov[0].iov_base = (caddr_t)packet;
+ rcviov[0].iov_len = sizeof(packet);
+ rcvmhdr.msg_name = (caddr_t)&Rcv;
+ rcvmhdr.msg_namelen = sizeof(Rcv);
+ rcvmhdr.msg_iov = rcviov;
+ rcvmhdr.msg_iovlen = 1;
+ rcvcmsglen = CMSG_SPACE(sizeof(struct in6_pktinfo)) +
+ CMSG_SPACE(sizeof(int));
+ if ((rcvcmsgbuf = malloc(rcvcmsglen)) == NULL) {
+ fprintf(stderr, "traceroute6: malloc failed\n");
+ exit(1);
+ }
+ rcvmhdr.msg_control = (caddr_t) rcvcmsgbuf;
+ rcvmhdr.msg_controllen = rcvcmsglen;
+
+ (void) setsockopt(rcvsock, SOL_SOCKET, SO_RECV_ANYIF, (char *)&on,
+ sizeof(on));
+ if (options & SO_DEBUG)
+ (void) setsockopt(rcvsock, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void) setsockopt(rcvsock, SOL_SOCKET, SO_DONTROUTE,
+ (char *)&on, sizeof(on));
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ /*
+ * do not raise error even if setsockopt fails, kernel may have ipsec
+ * turned off.
+ */
+ if (setpolicy(rcvsock, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+ if (setpolicy(rcvsock, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#else
+ {
+ int level = IPSEC_LEVEL_NONE;
+
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
+ sizeof(level));
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
+ sizeof(level));
+#ifdef IP_AUTH_TRANS_LEVEL
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
+ sizeof(level));
+#else
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
+ sizeof(level));
+#endif
+#ifdef IP_AUTH_NETWORK_LEVEL
+ (void)setsockopt(rcvsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
+ sizeof(level));
+#endif
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+#ifdef SO_SNDBUF
+ i = datalen;
+ if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&i,
+ sizeof(i)) < 0 && useproto != IPPROTO_NONE) {
+ perror("setsockopt(SO_SNDBUF)");
+ exit(6);
+ }
+#endif /* SO_SNDBUF */
+ if (options & SO_DEBUG)
+ (void) setsockopt(sndsock, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ if (options & SO_DONTROUTE)
+ (void) setsockopt(sndsock, SOL_SOCKET, SO_DONTROUTE,
+ (char *)&on, sizeof(on));
+#ifdef USE_RFC2292BIS
+ if (rth) {/* XXX: there is no library to finalize the header... */
+ rth->ip6r_len = rth->ip6r_segleft * 2;
+ if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_RTHDR,
+ (void *)rth, (rth->ip6r_len + 1) << 3)) {
+ fprintf(stderr, "setsockopt(IPV6_RTHDR): %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ }
+#else /* old advanced API */
+ if (cmsg != NULL) {
+ inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
+ if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_PKTOPTIONS,
+ rtbuf, cmsg->cmsg_len) < 0) {
+ fprintf(stderr, "setsockopt(IPV6_PKTOPTIONS): %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ }
+#endif /* USE_RFC2292BIS */
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+ /*
+ * do not raise error even if setsockopt fails, kernel may have ipsec
+ * turned off.
+ */
+ if (setpolicy(sndsock, "in bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+ if (setpolicy(sndsock, "out bypass") < 0)
+ errx(1, "%s", ipsec_strerror());
+#else
+ {
+ int level = IPSEC_LEVEL_BYPASS;
+
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_TRANS_LEVEL, &level,
+ sizeof(level));
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_ESP_NETWORK_LEVEL, &level,
+ sizeof(level));
+#ifdef IP_AUTH_TRANS_LEVEL
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_TRANS_LEVEL, &level,
+ sizeof(level));
+#else
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_LEVEL, &level,
+ sizeof(level));
+#endif
+#ifdef IP_AUTH_NETWORK_LEVEL
+ (void)setsockopt(sndsock, IPPROTO_IPV6, IPV6_AUTH_NETWORK_LEVEL, &level,
+ sizeof(level));
+#endif
+ }
+#endif /*IPSEC_POLICY_IPSEC*/
+#endif /*IPSEC*/
+
+ /*
+ * Source selection
+ */
+ bzero(&Src, sizeof(Src));
+ if (source) {
+ struct addrinfo hints, *res;
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET6;
+ hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(source, "0", &hints, &res);
+ if (error) {
+ printf("traceroute6: %s: %s\n", source,
+ gai_strerror(error));
+ exit(1);
+ }
+ if (res->ai_addrlen > sizeof(Src)) {
+ printf("traceroute6: %s: %s\n", source,
+ gai_strerror(error));
+ exit(1);
+ }
+ memcpy(&Src, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ } else {
+ struct sockaddr_in6 Nxt;
+ int dummy;
+ socklen_t len;
+
+ Nxt = Dst;
+ Nxt.sin6_port = htons(DUMMY_PORT);
+ if (cmsg != NULL)
+ bcopy(inet6_rthdr_getaddr(cmsg, 1), &Nxt.sin6_addr,
+ sizeof(Nxt.sin6_addr));
+ if ((dummy = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ exit(1);
+ }
+ if (connect(dummy, (struct sockaddr *)&Nxt, Nxt.sin6_len) < 0) {
+ perror("connect");
+ exit(1);
+ }
+ len = sizeof(Src);
+ if (getsockname(dummy, (struct sockaddr *)&Src, &len) < 0) {
+ perror("getsockname");
+ exit(1);
+ }
+ if (getnameinfo((struct sockaddr *)&Src, Src.sin6_len,
+ src0, sizeof(src0), NULL, 0, NI_NUMERICHOST)) {
+ fprintf(stderr, "getnameinfo failed for source\n");
+ exit(1);
+ }
+ source = src0;
+ close(dummy);
+ }
+
+ Src.sin6_port = htons(0);
+ if (bind(sndsock, (struct sockaddr *)&Src, Src.sin6_len) < 0) {
+ perror("bind");
+ exit(1);
+ }
+
+ {
+ socklen_t len;
+
+ len = sizeof(Src);
+ if (getsockname(sndsock, (struct sockaddr *)&Src, &len) < 0) {
+ perror("getsockname");
+ exit(1);
+ }
+ srcport = ntohs(Src.sin6_port);
+ }
+
+ /*
+ * Message to users
+ */
+ if (getnameinfo((struct sockaddr *)&Dst, Dst.sin6_len, hbuf,
+ sizeof(hbuf), NULL, 0, NI_NUMERICHOST))
+ strlcpy(hbuf, "(invalid)", sizeof(hbuf));
+ fprintf(stderr, "traceroute6");
+ fprintf(stderr, " to %s (%s)", hostname, hbuf);
+ if (source)
+ fprintf(stderr, " from %s", source);
+ fprintf(stderr, ", %lu hops max, %lu byte packets\n",
+ max_hops, datalen);
+ (void) fflush(stderr);
+
+ if (first_hop > 1)
+ printf("Skipping %lu intermediate hops\n", first_hop - 1);
+
+ /*
+ * Main loop
+ */
+ for (hops = first_hop; hops <= max_hops; ++hops) {
+ struct in6_addr lastaddr;
+ int got_there = 0;
+ int unreachable = 0;
+
+ printf("%2lu ", hops);
+ bzero(&lastaddr, sizeof(lastaddr));
+ for (probe = 0; probe < nprobes; ++probe) {
+ int cc;
+ struct timeval t1, t2;
+
+ (void) gettimeofday(&t1, NULL);
+ send_probe(++seq, hops);
+ while ((cc = wait_for_reply(rcvsock, &rcvmhdr))) {
+ (void) gettimeofday(&t2, NULL);
+ if ((i = packet_ok(&rcvmhdr, cc, seq))) {
+ if (!IN6_ARE_ADDR_EQUAL(&Rcv.sin6_addr,
+ &lastaddr)) {
+ if (probe > 0)
+ fputs("\n ", stdout);
+ print(&rcvmhdr, cc);
+ lastaddr = Rcv.sin6_addr;
+ }
+ printf(" %.3f ms", deltaT(&t1, &t2));
+ switch (i - 1) {
+ case ICMP6_DST_UNREACH_NOROUTE:
+ ++unreachable;
+ printf(" !N");
+ break;
+ case ICMP6_DST_UNREACH_ADMIN:
+ ++unreachable;
+ printf(" !P");
+ break;
+ case ICMP6_DST_UNREACH_NOTNEIGHBOR:
+ ++unreachable;
+ printf(" !S");
+ break;
+ case ICMP6_DST_UNREACH_ADDR:
+ ++unreachable;
+ printf(" !A");
+ break;
+ case ICMP6_DST_UNREACH_NOPORT:
+ if (rcvhlim >= 0 &&
+ rcvhlim <= 1)
+ printf(" !");
+ ++got_there;
+ break;
+ }
+ break;
+ }
+ }
+ if (cc == 0)
+ printf(" *");
+ (void) fflush(stdout);
+ }
+ putchar('\n');
+ if (got_there ||
+ (unreachable > 0 && unreachable >= ((nprobes + 1) / 2))) {
+ exit(0);
+ }
+ }
+
+ exit(0);
+}
+
+int
+wait_for_reply(sock, mhdr)
+ int sock;
+ struct msghdr *mhdr;
+{
+#ifdef HAVE_POLL
+ struct pollfd pfd[1];
+ int cc = 0;
+
+ pfd[0].fd = sock;
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+
+ if (poll(pfd, 1, waittime * 1000) > 0)
+ cc = recvmsg(rcvsock, mhdr, 0);
+
+ return(cc);
+#else
+ fd_set *fdsp;
+ struct timeval wait;
+ int cc = 0, fdsn;
+
+ fdsn = howmany(sock + 1, NFDBITS) * sizeof(fd_mask);
+ if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
+ err(1, "malloc");
+ memset(fdsp, 0, fdsn);
+ FD_SET(sock, fdsp);
+ wait.tv_sec = waittime; wait.tv_usec = 0;
+
+ if (select(sock+1, fdsp, (fd_set *)0, (fd_set *)0, &wait) > 0)
+ cc = recvmsg(rcvsock, mhdr, 0);
+
+ free(fdsp);
+ return(cc);
+#endif
+}
+
+#ifdef IPSEC
+#ifdef IPSEC_POLICY_IPSEC
+int
+setpolicy(so, policy)
+ int so;
+ char *policy;
+{
+ char *buf;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL) {
+ warnx("%s", ipsec_strerror());
+ return -1;
+ }
+ (void)setsockopt(so, IPPROTO_IPV6, IPV6_IPSEC_POLICY,
+ buf, ipsec_get_policylen(buf));
+
+ free(buf);
+
+ return 0;
+}
+#endif
+#endif
+
+void
+send_probe(seq, hops)
+ int seq;
+ u_long hops;
+{
+ struct icmp6_hdr *icp;
+ struct opacket *op;
+ struct timeval tv;
+ struct tv32 tv32;
+ int i;
+
+ i = hops;
+ if (setsockopt(sndsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ (char *)&i, sizeof(i)) < 0) {
+ perror("setsockopt IPV6_UNICAST_HOPS");
+ }
+
+ Dst.sin6_port = htons(port + seq);
+ (void) gettimeofday(&tv, NULL);
+ tv32.tv32_sec = htonl(tv.tv_sec);
+ tv32.tv32_usec = htonl(tv.tv_usec);
+
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ icp = (struct icmp6_hdr *)outpacket;
+
+ icp->icmp6_type = ICMP6_ECHO_REQUEST;
+ icp->icmp6_code = 0;
+ icp->icmp6_cksum = 0;
+ icp->icmp6_id = ident;
+ icp->icmp6_seq = htons(seq);
+ bcopy(&tv32, ((u_int8_t *)outpacket + ICMP6ECHOLEN),
+ sizeof(tv32));
+ break;
+ case IPPROTO_UDP:
+ op = outpacket;
+
+ op->seq = seq;
+ op->hops = hops;
+ bcopy(&tv32, &op->tv, sizeof tv32);
+ break;
+ case IPPROTO_NONE:
+ /* No space for anything. No harm as seq/tv32 are decorative. */
+ break;
+ default:
+ fprintf(stderr, "Unknown probe protocol %d.\n", useproto);
+ exit(1);
+ }
+
+ i = sendto(sndsock, (char *)outpacket, datalen, 0,
+ (struct sockaddr *)&Dst, Dst.sin6_len);
+ if (i < 0 || i != datalen) {
+ if (i < 0)
+ perror("sendto");
+ printf("traceroute6: wrote %s %lu chars, ret=%d\n",
+ hostname, datalen, i);
+ (void) fflush(stdout);
+ }
+}
+
+int
+get_hoplim(mhdr)
+ struct msghdr *mhdr;
+{
+ struct cmsghdr *cm;
+
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ return(*(int *)CMSG_DATA(cm));
+ }
+
+ return(-1);
+}
+
+double
+deltaT(t1p, t2p)
+ struct timeval *t1p, *t2p;
+{
+ double dt;
+
+ dt = (double)(t2p->tv_sec - t1p->tv_sec) * 1000.0 +
+ (double)(t2p->tv_usec - t1p->tv_usec) / 1000.0;
+ return (dt);
+}
+
+/*
+ * Convert an ICMP "type" field to a printable string.
+ */
+char *
+pr_type(t0)
+ int t0;
+{
+ u_char t = t0 & 0xff;
+ char *cp;
+
+ switch (t) {
+ case ICMP6_DST_UNREACH:
+ cp = "Destination Unreachable";
+ break;
+ case ICMP6_PACKET_TOO_BIG:
+ cp = "Packet Too Big";
+ break;
+ case ICMP6_TIME_EXCEEDED:
+ cp = "Time Exceeded";
+ break;
+ case ICMP6_PARAM_PROB:
+ cp = "Parameter Problem";
+ break;
+ case ICMP6_ECHO_REQUEST:
+ cp = "Echo Request";
+ break;
+ case ICMP6_ECHO_REPLY:
+ cp = "Echo Reply";
+ break;
+ case ICMP6_MEMBERSHIP_QUERY:
+ cp = "Group Membership Query";
+ break;
+ case ICMP6_MEMBERSHIP_REPORT:
+ cp = "Group Membership Report";
+ break;
+ case ICMP6_MEMBERSHIP_REDUCTION:
+ cp = "Group Membership Reduction";
+ break;
+ case ND_ROUTER_SOLICIT:
+ cp = "Router Solicitation";
+ break;
+ case ND_ROUTER_ADVERT:
+ cp = "Router Advertisement";
+ break;
+ case ND_NEIGHBOR_SOLICIT:
+ cp = "Neighbor Solicitation";
+ break;
+ case ND_NEIGHBOR_ADVERT:
+ cp = "Neighbor Advertisement";
+ break;
+ case ND_REDIRECT:
+ cp = "Redirect";
+ break;
+ default:
+ cp = "Unknown";
+ break;
+ }
+ return cp;
+}
+
+int
+packet_ok(mhdr, cc, seq)
+ struct msghdr *mhdr;
+ int cc;
+ int seq;
+{
+ struct icmp6_hdr *icp;
+ struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
+ u_char type, code;
+ char *buf = (char *)mhdr->msg_iov[0].iov_base;
+ struct cmsghdr *cm;
+ int *hlimp;
+ char hbuf[NI_MAXHOST];
+
+#ifdef OLDRAWSOCKET
+ int hlen;
+ struct ip6_hdr *ip;
+#endif
+
+#ifdef OLDRAWSOCKET
+ ip = (struct ip6_hdr *) buf;
+ hlen = sizeof(struct ip6_hdr);
+ if (cc < hlen + sizeof(struct icmp6_hdr)) {
+ if (verbose) {
+ if (getnameinfo((struct sockaddr *)from, from->sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(hbuf, "invalid", sizeof(hbuf));
+ printf("packet too short (%d bytes) from %s\n", cc,
+ hbuf);
+ }
+ return (0);
+ }
+ cc -= hlen;
+ icp = (struct icmp6_hdr *)(buf + hlen);
+#else
+ if (cc < sizeof(struct icmp6_hdr)) {
+ if (verbose) {
+ if (getnameinfo((struct sockaddr *)from, from->sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(hbuf, "invalid", sizeof(hbuf));
+ printf("data too short (%d bytes) from %s\n", cc, hbuf);
+ }
+ return(0);
+ }
+ icp = (struct icmp6_hdr *)buf;
+#endif
+ /* get optional information via advanced API */
+ rcvpktinfo = NULL;
+ hlimp = NULL;
+ for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
+ cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_PKTINFO &&
+ cm->cmsg_len ==
+ CMSG_LEN(sizeof(struct in6_pktinfo)))
+ rcvpktinfo = (struct in6_pktinfo *)(CMSG_DATA(cm));
+
+ if (cm->cmsg_level == IPPROTO_IPV6 &&
+ cm->cmsg_type == IPV6_HOPLIMIT &&
+ cm->cmsg_len == CMSG_LEN(sizeof(int)))
+ hlimp = (int *)CMSG_DATA(cm);
+ }
+ if (rcvpktinfo == NULL || hlimp == NULL) {
+ warnx("failed to get received hop limit or packet info");
+#if 0
+ return(0);
+#else
+ rcvhlim = 0; /*XXX*/
+#endif
+ }
+ else
+ rcvhlim = *hlimp;
+
+ type = icp->icmp6_type;
+ code = icp->icmp6_code;
+ if ((type == ICMP6_TIME_EXCEEDED && code == ICMP6_TIME_EXCEED_TRANSIT)
+ || type == ICMP6_DST_UNREACH) {
+ struct ip6_hdr *hip;
+ void *up;
+
+ hip = (struct ip6_hdr *)(icp + 1);
+ if ((up = get_uphdr(hip, (u_char *)(buf + cc))) == NULL) {
+ if (verbose)
+ warnx("failed to get upper layer header");
+ return(0);
+ }
+ switch (useproto) {
+ case IPPROTO_ICMPV6:
+ if (((struct icmp6_hdr *)up)->icmp6_id == ident &&
+ ((struct icmp6_hdr *)up)->icmp6_seq == htons(seq))
+ return (type == ICMP6_TIME_EXCEEDED ?
+ -1 : code + 1);
+ break;
+ case IPPROTO_UDP:
+ if (((struct udphdr *)up)->uh_sport == htons(srcport) &&
+ ((struct udphdr *)up)->uh_dport == htons(port + seq))
+ return (type == ICMP6_TIME_EXCEEDED ?
+ -1 : code + 1);
+ break;
+ case IPPROTO_NONE:
+ return (type == ICMP6_TIME_EXCEEDED ? -1 : code + 1);
+ default:
+ fprintf(stderr, "Unknown probe proto %d.\n", useproto);
+ break;
+ }
+ } else if (useproto == IPPROTO_ICMPV6 && type == ICMP6_ECHO_REPLY) {
+ if (icp->icmp6_id == ident &&
+ icp->icmp6_seq == htons(seq))
+ return (ICMP6_DST_UNREACH_NOPORT + 1);
+ }
+ if (verbose) {
+ char sbuf[NI_MAXHOST+1], dbuf[INET6_ADDRSTRLEN];
+ u_int8_t *p;
+ int i;
+
+ if (getnameinfo((struct sockaddr *)from, from->sin6_len,
+ sbuf, sizeof(sbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(sbuf, "invalid", sizeof(sbuf));
+ printf("\n%d bytes from %s to %s", cc, sbuf,
+ rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
+ dbuf, sizeof(dbuf)) : "?");
+ printf(": icmp type %d (%s) code %d\n", type, pr_type(type),
+ icp->icmp6_code);
+ p = (u_int8_t *)(icp + 1);
+#define WIDTH 16
+ for (i = 0; i < cc; i++) {
+ if (i % WIDTH == 0)
+ printf("%04x:", i);
+ if (i % 4 == 0)
+ printf(" ");
+ printf("%02x", p[i]);
+ if (i % WIDTH == WIDTH - 1)
+ printf("\n");
+ }
+ if (cc % WIDTH != 0)
+ printf("\n");
+ }
+ return(0);
+}
+
+/*
+ * Increment pointer until find the UDP or ICMP header.
+ */
+void *
+get_uphdr(ip6, lim)
+ struct ip6_hdr *ip6;
+ u_char *lim;
+{
+ u_char *cp = (u_char *)ip6, nh;
+ int hlen;
+ static u_char none_hdr[1]; /* Fake pointer for IPPROTO_NONE. */
+
+ if (cp + sizeof(*ip6) > lim)
+ return(NULL);
+
+ nh = ip6->ip6_nxt;
+ cp += sizeof(struct ip6_hdr);
+
+ while (lim - cp >= (nh == IPPROTO_NONE ? 0 : 8)) {
+ switch (nh) {
+ case IPPROTO_ESP:
+ case IPPROTO_TCP:
+ return(NULL);
+ case IPPROTO_ICMPV6:
+ return(useproto == nh ? cp : NULL);
+ case IPPROTO_UDP:
+ return(useproto == nh ? cp : NULL);
+ case IPPROTO_NONE:
+ return(useproto == nh ? none_hdr : NULL);
+ case IPPROTO_FRAGMENT:
+ hlen = sizeof(struct ip6_frag);
+ nh = ((struct ip6_frag *)cp)->ip6f_nxt;
+ break;
+ case IPPROTO_AH:
+ hlen = (((struct ip6_ext *)cp)->ip6e_len + 2) << 2;
+ nh = ((struct ip6_ext *)cp)->ip6e_nxt;
+ break;
+ default:
+ hlen = (((struct ip6_ext *)cp)->ip6e_len + 1) << 3;
+ nh = ((struct ip6_ext *)cp)->ip6e_nxt;
+ break;
+ }
+
+ cp += hlen;
+ }
+
+ return(NULL);
+}
+
+void
+print(mhdr, cc)
+ struct msghdr *mhdr;
+ int cc;
+{
+ struct sockaddr_in6 *from = (struct sockaddr_in6 *)mhdr->msg_name;
+ char hbuf[NI_MAXHOST];
+
+ if (getnameinfo((struct sockaddr *)from, from->sin6_len,
+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
+ strlcpy(hbuf, "invalid", sizeof(hbuf));
+ if (nflag)
+ printf(" %s", hbuf);
+ else if (lflag)
+ printf(" %s (%s)", inetname((struct sockaddr *)from), hbuf);
+ else
+ printf(" %s", inetname((struct sockaddr *)from));
+
+ if (verbose) {
+#ifdef OLDRAWSOCKET
+ printf(" %d bytes to %s", cc,
+ rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
+ hbuf, sizeof(hbuf)) : "?");
+#else
+ printf(" %d bytes of data to %s", cc,
+ rcvpktinfo ? inet_ntop(AF_INET6, &rcvpktinfo->ipi6_addr,
+ hbuf, sizeof(hbuf)) : "?");
+#endif
+ }
+}
+
+/*
+ * Construct an Internet address representation.
+ * If the nflag has been supplied, give
+ * numeric value, otherwise try for symbolic name.
+ */
+const char *
+inetname(sa)
+ struct sockaddr *sa;
+{
+ static char line[NI_MAXHOST], domain[MAXHOSTNAMELEN + 1];
+ static int first = 1;
+ char *cp;
+
+ if (first && !nflag) {
+ first = 0;
+ if (gethostname(domain, sizeof(domain)) == 0 &&
+ (cp = strchr(domain, '.')))
+ (void) memmove(domain, cp + 1, strlen(cp + 1) + 1);
+ else
+ domain[0] = 0;
+ }
+ cp = NULL;
+ if (!nflag) {
+ if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
+ NI_NAMEREQD) == 0) {
+ if ((cp = strchr(line, '.')) &&
+ !strcmp(cp + 1, domain))
+ *cp = 0;
+ cp = line;
+ }
+ }
+ if (cp)
+ return cp;
+
+ if (getnameinfo(sa, sa->sa_len, line, sizeof(line), NULL, 0,
+ NI_NUMERICHOST) != 0)
+ strlcpy(line, "invalid", sizeof(line));
+ return line;
+}
+
+void
+usage()
+{
+
+ fprintf(stderr,
+"usage: traceroute6 [-dIlnNrUv] [-f firsthop] [-g gateway] [-m hoplimit]\n"
+" [-p port] [-q probes] [-s src] [-w waittime] target [datalen]\n");
+ exit(1);
+}
diff --git a/patch_cmds/diffstat/CHANGES b/patch_cmds/diffstat/CHANGES
new file mode 100644
index 0000000..00f95ca
--- /dev/null
+++ b/patch_cmds/diffstat/CHANGES
@@ -0,0 +1,373 @@
+-- $Id: CHANGES,v 1.73 2012/01/03 09:38:29 tom Exp $
+
+2012/01/03 (diffstat 1.55)
+ + add -R option, like patch's, to reverse the order of the comparison.
+
+ + FreeBSD ports/148604, ports/149500 reported that lzcat may not
+ support extracting files compressed in xz format (patch by Frederic
+ Culot, FreeBSD #149500).
+
+ + address documentation issue raised in Novell #739210
+
+ + correct typo s/Solaris/Solar/.
+
+ + updated configure script macros:
+ CF_ANSI_CC_CHECK CF_DISABLE_LEAKS CF_GCC_ATTRIBUTES CF_GCC_WARNINGS
+ CF_MAKE_TAGS CF_MSG_LOG CF_PATH_PROG CF_WITH_INSTALL_PREFIX
+ CF_XOPEN_SOURCE
+
+ + update config.guess, config.sub
+
+2010/10/10 (diffstat 1.54)
+ + change Debian package script to use native format.
+
+ + correct counts used for new files when -S/-D options are used.
+
+ + minor typography improvement to manpage (patch by Solar Designer)
+
+ + remove the temporary directory on error, introduced in 1.48+ (patch
+ by Solar Designer).
+
+2010/07/19 (diffstat 1.53)
+
+ + add missing "break" statement which left "-c" option falling-through
+ into "-C".
+
+2010/07/16 (diffstat 1.52)
+
+ + add "-C" option to show the histogram using SGR colors.
+
+ + add "-s" option to show only the summary line.
+
+ + add configure check for "xz", using this in preference to "lzcat"
+ (FreeBSD #148604).
+
+ + also escape literal dashes used as part of the histogram in the
+ manpage.
+
+ + modify hyphens vs dashes in manpage per
+ http://lintian.debian.org/tags/hyphen-used-as-minus-sign.html
+ (patch by Francois Marier).
+
+ + drop mkdirs.sh, use "mkdir -p"
+
+ + add configure checks for ctags and lint.
+
+ + updated configure macros
+
+ + reformat CHANGES to work with metrics script.
+
+ + fix strict gcc warnings, e.g., using const.
+
+ + improve a case where filenames have embedded blanks (patch by Reinier
+ Post).
+
+ + update config.guess, config.sub
+
+2009/11/07 (diffstat 1.51)
+
+ + correct suffix-check for ".xz" files as command-line parameters
+ rather than as piped input (report by Moritz Barsnick).
+
+2009/11/6 (diffstat 1.50)
+
+ + build/test fixes for MSYS, i.e., MinGW.
+
+ + improve configure check for get_unlocked function.
+
+ + use $TMPDIR for path of temporary file used in decompression.
+
+ + correct else-condition for detecting compression type (patch by Zach
+ Hirsch).
+
+2009/08/31 (diffstat 1.49)
+
+ + improve lzma support, add support for xz (patch by Eric Blake).
+
+ + add special case for no-newline message from some diff's (Ubuntu
+ #269895).
+
+ + improve configure check for getopt header.
+
+ + add configure special case for HPUX 11 with _XOPEN_SOURCE definition.
+
+ + update config.guess, config.sub
+
+2009/08/11 (diffstat 1.48)
+
+ + add decompression tests for lzma and pack file types.
+
+ + check for zcat and uncompress in preference to "compress -dc".
+
+ + modify to check the first few bytes of standard input, and use a
+ corresponding decompression utility if the stream appears to be
+ compressed. This requires making a temporary copy of the data
+ (Debian #491575).
+
+ + add -N option, to truncate filenames.
+
+ + use getc_unlocked() rather than fgetc_unlocked()
+
+ + modify to recognize Perforce-style diffs (patch by Ed Schouten).
+
+ + updated configure macros to improve compiler warning checks, use
+ $PATH_SEPARATOR rather than $PATH_SEP (for consistency with some
+ autoconf versions),
+
+ + fix typo in configure --with-install-prefix option (report by
+ Dagobert Michelsen).
+
+ + update config.guess, config.sub
+
+2009/03/29 (diffstat 1.47)
+
+ modify to work with patch ".rej" files, which do not have a header to
+ tell which file is affected.
+
+ fix typo in usage message (reports by Moritz Barsnick, John McNamara,
+ Richard Quadling).
+
+2008-08-06 (diffstat 1.46)
+
+ + add "-S", "-D" and "-m" options to provide a way to show the amount
+ of difference relative to the total sizes of the files.
+
+ + add "-q" option (Debian #488248, patch by Greg Norris).
+
+2007/09/04 (diffstat 1.45)
+
+ + add "-b" option (Debian #379380, patch by Greg Norris).
+
+2007/08/26 (diffstat 1.44)
+
+ + add a check for default-diff output, e.g., "diff foo bar|diffstat",
+ which has no "diff" command in the output for diffstat to guess that
+ a diff is beginning.
+
+ + add a check after completing a chunk for unified diff to ensure that
+ the next line either begins another chunk for the diff, or starts
+ another diff, e.g., a context diff (report by Adrian Bunk).
+
+ + add configure options for leak-checking valgrind, etc.
+
+ + use install-sh rather than install.sh
+
+ + updated config.guess and config.sub
+
+ + updated configure macros CF_GCC_ATTRIBUTES CF_GCC_WARNINGS CF_MSG_LOG
+ CF_PATH_SYNTAX CF_VERBOSE CF_XOPEN_SOURCE
+
+2006/07/16 (diffstat 1.43)
+
+ + fix to avoid modifying data which is being used by tsearch() for
+ ordering the binary tree (report by Adrian Bunk).
+
+2006/07/02 (diffstat 1.42)
+
+ + do not ignore pathnames in /tmp/, since some tools create usable
+ for both old/new files there (Debian #376086).
+
+ + correct ifdef for fgetc_unlocked().
+
+ + updated configure macros CF_GCC_VERSION, CF_PATH_SYNTAX and
+ CF_XOPEN_SOURCE
+
+ + add configure check for compress, gzip and bzip2 programs that may be
+ used to decompress files.
+
+2005/08/24 (diffstat 1.41)
+
+ + update usage message for options added in 1.40 (report by Eric Blake).
+
+2005-08-15 (diffstat 1.40)
+
+ + add options -l, -r and -t. add to -f option (patch, comments by
+ Jean Delvare, Michael Burian).
+
+ + improve I/O on Linux using fgetc_locked().
+
+ + improve searching of long sorted lists using tsearch()
+
+ + improve configure-script checks for Intel compiler warnings.
+
+2005-04-10 (diffstat 1.39)
+
+ + change order of merging and prefix-stripping so stripping all prefixes,
+ e.g., with -p9, will be sorted as expected (patch by Jean Delvare).
+
+ + correct a reference to freed memory after merging found with valgrind.
+
+2005-01-16 (diffstat 1.38)
+
+ + add makefile.wnt, etc., for win32 port.
+
+ + fix "make check" to work even when PATH or the build directory has
+ spaces in it (patch by Eric Blake).
+
+ + add support for '--help' and '--version' command line arguments, for a
+ consistent interface with GNU tools, and still compatible to POSIX
+ requirements on utility options (patch by Eric Blake).
+
+2004-12-18
+
+ + modify makefile.in and run_test.sh to allow "make check" to be run
+ from a build directory which is not the same as the source directory,
+ i.e., when the configure --srcdir option is used (request by Eric
+ Blake).
+
+ + modify distribution to include sample of regression tests, so a
+ "make check" will work (request by Eric Blake).
+
+2004-12-16 (diffstat 1.37)
+
+ + fix a different case for data beginning with "--" which was treated
+ as a header line.
+
+2004-12-14 (diffstat 1.36)
+
+ + Fix allocation problems. Open files in binary mode for reading.
+ Getopt returns -1, not necessarily EOF. Add const where useful. Use
+ NO_IDENT where necessary. malloc() comes from <stdlib.h> in standard
+ systems (Patch by Eric Blake <ebb9@byu.net>.)
+
+2004-11-08 (diffstat 1.35)
+
+ + modify makefile.in to work with configure --srcdir option (report by
+ Eric Blake).
+
+ + minor fix for resync of unified diffs checks for range (line beginning
+ with '@' without header lines (successive lines beginning with "---"
+ and "+++") (Debian #264098).
+
+ + miscellaneous updates for configure script
+
+2003-11-09 (diffstat 1.34)
+
+ + improve check for certain lines (not those that begin a chunk) that
+ begin with '-', treating all except "---" as a delete (report by
+ James Rowe <Jay@jnrowe.uklinux.net>).
+
+ + minor updates to configure script.
+
+2003-02-14 (diffstat 1.33)
+
+ + modified to work around a case where the filename+date was incomplete,
+ i.e., missing one of the components such as the day of the month.
+ While diffstat does not use the date directly, it helps distinguish
+ some lines from non-patches (report by Moritz Barsnick
+ <moritz@barsnick.net>).
+
+ + add "-h" option (request by Moritz Barsnick).
+
+ + fix a typo in usage message (report by Moritz Barsnick).
+
+ + add "-e" and "-o" options to simplify testing on OS/2 EMX.
+
+2003-01-04 (diffstat 1.32)
+
+ + modified to handle patches generated by makepatch-2.00_09, which uses
+ both "Index" and "diff" lines (report by D Roland Walker). As a side
+ effect, the additional merging eliminates occasional reports with
+ zero differences.
+
+ + modified to avoid buffer overflows.
+
+ + fixes for Debian #155000 (did not handle a '-' in first content-column
+ of a unified diff) and #170947 (option to turn the progress messages
+ off).
+
+ + updated configure script using aclocal.m4 macros
+
+ + update makefile.in to improve use of autoconf (report/patch by Nix
+ <nix@esperi.demon.co.uk>).
+
+2002-08-20 (diffstat 1.31)
+
+ + add -u, -k options to override diffstat's normal sorting (-u) and
+ merging (-k) of identical filenames. (-u requested by H Peter Anvin
+ <hpa@zytor.com>).
+
+2002-08-09 (diffstat 1.30)
+
+ + allow either '/' or '-' as delimiters in dates, to accommodate
+ gendiff (report by Rik van Riel <riel@conectiva.com.br>). This
+ corresponds to the time format used in diffutils 2.8 whose changelog
+ states that this is ISO 8601 (though online references differ).
+
+2001-10-10 (diffstat 1.29)
+
+ + add bzip2 (.bz2) suffix (suggested by Gregory T Norris
+ <haphazard@socket.net>, Debian #82969).
+
+ + add check for diff from RCS archive where the "diff" lines do not
+ reference a filename.
+
+2000-03-29 (diffstat 1.28)
+
+ + Add -c option (to prefix output with '#' comment), eliminating a step
+ in my script that combines diffstat output with a patch. This is a
+ workaround for OSF1's broken sed utility.
+
+ + Check for compressed file suffixes .Z and .gz, read uncompressed data
+ via pipe (Debian wishlist item #53975 by ch@lathspell.westend.com).
+
+ + Simplified makefile based on comments by M Sweger
+ <mikesw@whiterose.net>
+
+ + Adapted changes from Troy Engel <tengel@sonic.net> as "-f" option.
+
+1998-05-27 (diffstat 1.27)
+
+ + Debian diff's don't show dates on the lines where we expect to see
+ filenames.
+
+1998-01-16 (diffstat 1.26, Patch 5)
+
+ + Change copyright terms.
+
+ + Accommodate patches w/o tabs in header lines (e.g., from cut/paste).
+ Still prefer the tabs because otherwise we cannot have spaces in
+ filenames.
+
+ + Strip suffixes such as ".orig", to avoid confusing output.
+
+1996-03-16 (diffstat 1.24, Patch 4)
+
+ + Corrected state-transition after "Binary".
+
+ + Added testing subdirectory
+
+ + Added -p option.
+
+ + Handle differences from /tmp (e.g., for X11R5 patches).
+
+1995-05-06 (diffstat 1.17 Patch 3)
+
+ + Repost whole program to comp.sources.misc (1.17)
+
+ + Mods to scaling: limit to 1:1 if only a few changes were made; added
+ logic to accumulate error across +/-/! calls.
+
+ + added logic to recognize 'rcsdiff -u' output.
+
+1994-12-26 (diffstat 1.15, Patch 2)
+
+ + Strip common pathname prefix (1.15)
+
+1994-11-13 (diffstat 1.14, Patch 1)
+
+ + Test for <string.h> vs <strings.h>
+
+ + Corrected error in 'match()' that didn't handle properly the case
+ when an argument was a null string (i.e., blank lines in a unified
+ diff).
+
+ + Added options '-n' and '-V'
+
+ + Added patchlev.h, CHANGES files.
+
+ + Added install.sh, for autoconf 2.1
+
+1994-06-13 (diffstat 1.12, Patch 0)
+
+ + Initial release of 'diffstat' (1.12).
diff --git a/patch_cmds/diffstat/aclocal.m4 b/patch_cmds/diffstat/aclocal.m4
new file mode 100644
index 0000000..1f93487
--- /dev/null
+++ b/patch_cmds/diffstat/aclocal.m4
@@ -0,0 +1,1306 @@
+dnl $Id: aclocal.m4,v 1.21 2012/01/03 09:37:14 tom Exp $
+dnl autoconf macros for 'diffstat'
+dnl
+dnl Copyright 2003-2010,2012 Thomas E. Dickey
+dnl
+dnl See also
+dnl http://invisible-island.net/autoconf/
+dnl
+dnl ---------------------------------------------------------------------------
+dnl ---------------------------------------------------------------------------
+dnl CF_ADD_CFLAGS version: 10 updated: 2010/05/26 05:38:42
+dnl -------------
+dnl Copy non-preprocessor flags to $CFLAGS, preprocessor flags to $CPPFLAGS
+dnl The second parameter if given makes this macro verbose.
+dnl
+dnl Put any preprocessor definitions that use quoted strings in $EXTRA_CPPFLAGS,
+dnl to simplify use of $CPPFLAGS in compiler checks, etc., that are easily
+dnl confused by the quotes (which require backslashes to keep them usable).
+AC_DEFUN([CF_ADD_CFLAGS],
+[
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $1
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[[^=]]*='\''\"[[^"]]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+ CF_REMOVE_DEFINE(CPPFLAGS,$CPPFLAGS,$cf_tst_cppflags)
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[[^"]]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+ ifelse([$2],,,[CF_VERBOSE(add to \$CFLAGS $cf_new_cflags)])
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+ ifelse([$2],,,[CF_VERBOSE(add to \$CPPFLAGS $cf_new_cppflags)])
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+ ifelse([$2],,,[CF_VERBOSE(add to \$EXTRA_CPPFLAGS $cf_new_extra_cppflags)])
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+AC_SUBST(EXTRA_CPPFLAGS)
+
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_ANSI_CC_CHECK version: 11 updated: 2011/07/01 19:47:45
+dnl ----------------
+dnl This was originally adapted from the macros 'fp_PROG_CC_STDC' and
+dnl 'fp_C_PROTOTYPES' in the sharutils 4.2 distribution.
+AC_DEFUN([CF_ANSI_CC_CHECK],
+[
+# This should have been defined by AC_PROG_CC
+: ${CC:=cc}
+
+# Check for user's environment-breakage by stuffing CFLAGS/CPPFLAGS content
+# into CC. This will not help with broken scripts that wrap the compiler with
+# options, but eliminates a more common category of user confusion.
+AC_MSG_CHECKING(\$CC variable)
+case "$CC" in #(vi
+*[[\ \ ]]-[[IUD]]*)
+ AC_MSG_RESULT(broken)
+ AC_MSG_WARN(your environment misuses the CC variable to hold CFLAGS/CPPFLAGS options)
+ # humor him...
+ cf_flags=`echo "$CC" | sed -e 's/^[[^ ]]*[[ ]]//'`
+ CC=`echo "$CC" | sed -e 's/[[ ]].*//'`
+ CF_ADD_CFLAGS($cf_flags)
+ ;;
+*)
+ AC_MSG_RESULT(ok)
+ ;;
+esac
+
+AC_CACHE_CHECK(for ${CC:-cc} option to accept ANSI C, cf_cv_ansi_cc,[
+cf_cv_ansi_cc=no
+cf_save_CFLAGS="$CFLAGS"
+cf_save_CPPFLAGS="$CPPFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX -Aa -D_HPUX_SOURCE
+# SVR4 -Xc
+# UnixWare 1.2 (cannot use -Xc, since ANSI/POSIX clashes)
+for cf_arg in "-DCC_HAS_PROTOS" \
+ "" \
+ -qlanglvl=ansi \
+ -std1 \
+ -Ae \
+ "-Aa -D_HPUX_SOURCE" \
+ -Xc
+do
+ CF_ADD_CFLAGS($cf_arg)
+ AC_TRY_COMPILE(
+[
+#ifndef CC_HAS_PROTOS
+#if !defined(__STDC__) || (__STDC__ != 1)
+choke me
+#endif
+#endif
+],[
+ int test (int i, double x);
+ struct s1 {int (*f) (int a);};
+ struct s2 {int (*f) (double a);};],
+ [cf_cv_ansi_cc="$cf_arg"; break])
+done
+CFLAGS="$cf_save_CFLAGS"
+CPPFLAGS="$cf_save_CPPFLAGS"
+])
+
+if test "$cf_cv_ansi_cc" != "no"; then
+if test ".$cf_cv_ansi_cc" != ".-DCC_HAS_PROTOS"; then
+ CF_ADD_CFLAGS($cf_cv_ansi_cc)
+else
+ AC_DEFINE(CC_HAS_PROTOS)
+fi
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_ANSI_CC_REQD version: 4 updated: 2008/03/23 14:48:54
+dnl ---------------
+dnl For programs that must use an ANSI compiler, obtain compiler options that
+dnl will make it recognize prototypes. We'll do preprocessor checks in other
+dnl macros, since tools such as unproto can fake prototypes, but only part of
+dnl the preprocessor.
+AC_DEFUN([CF_ANSI_CC_REQD],
+[AC_REQUIRE([CF_ANSI_CC_CHECK])
+if test "$cf_cv_ansi_cc" = "no"; then
+ AC_MSG_ERROR(
+[Your compiler does not appear to recognize prototypes.
+You have the following choices:
+ a. adjust your compiler options
+ b. get an up-to-date compiler
+ c. use a wrapper such as unproto])
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_ARG_DISABLE version: 3 updated: 1999/03/30 17:24:31
+dnl --------------
+dnl Allow user to disable a normally-on option.
+AC_DEFUN([CF_ARG_DISABLE],
+[CF_ARG_OPTION($1,[$2],[$3],[$4],yes)])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_ARG_OPTION version: 4 updated: 2010/05/26 05:38:42
+dnl -------------
+dnl Restricted form of AC_ARG_ENABLE that ensures user doesn't give bogus
+dnl values.
+dnl
+dnl Parameters:
+dnl $1 = option name
+dnl $2 = help-string
+dnl $3 = action to perform if option is not default
+dnl $4 = action if perform if option is default
+dnl $5 = default option value (either 'yes' or 'no')
+AC_DEFUN([CF_ARG_OPTION],
+[AC_ARG_ENABLE([$1],[$2],[test "$enableval" != ifelse([$5],no,yes,no) && enableval=ifelse([$5],no,no,yes)
+ if test "$enableval" != "$5" ; then
+ifelse([$3],,[ :]dnl
+,[ $3]) ifelse([$4],,,[
+ else
+ $4])
+ fi],[enableval=$5 ifelse([$4],,,[
+ $4
+])dnl
+ ])])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_CHECK_CACHE version: 11 updated: 2008/03/23 14:45:59
+dnl --------------
+dnl Check if we're accidentally using a cache from a different machine.
+dnl Derive the system name, as a check for reusing the autoconf cache.
+dnl
+dnl If we've packaged config.guess and config.sub, run that (since it does a
+dnl better job than uname). Normally we'll use AC_CANONICAL_HOST, but allow
+dnl an extra parameter that we may override, e.g., for AC_CANONICAL_SYSTEM
+dnl which is useful in cross-compiles.
+dnl
+dnl Note: we would use $ac_config_sub, but that is one of the places where
+dnl autoconf 2.5x broke compatibility with autoconf 2.13
+AC_DEFUN([CF_CHECK_CACHE],
+[
+if test -f $srcdir/config.guess || test -f $ac_aux_dir/config.guess ; then
+ ifelse([$1],,[AC_CANONICAL_HOST],[$1])
+ system_name="$host_os"
+else
+ system_name="`(uname -s -r) 2>/dev/null`"
+ if test -z "$system_name" ; then
+ system_name="`(hostname) 2>/dev/null`"
+ fi
+fi
+test -n "$system_name" && AC_DEFINE_UNQUOTED(SYSTEM_NAME,"$system_name")
+AC_CACHE_VAL(cf_cv_system_name,[cf_cv_system_name="$system_name"])
+
+test -z "$system_name" && system_name="$cf_cv_system_name"
+test -n "$cf_cv_system_name" && AC_MSG_RESULT(Configuring for $cf_cv_system_name)
+
+if test ".$system_name" != ".$cf_cv_system_name" ; then
+ AC_MSG_RESULT(Cached system name ($system_name) does not agree with actual ($cf_cv_system_name))
+ AC_MSG_ERROR("Please remove config.cache and try again.")
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_DISABLE_ECHO version: 11 updated: 2009/12/13 13:16:57
+dnl ---------------
+dnl You can always use "make -n" to see the actual options, but it's hard to
+dnl pick out/analyze warning messages when the compile-line is long.
+dnl
+dnl Sets:
+dnl ECHO_LT - symbol to control if libtool is verbose
+dnl ECHO_LD - symbol to prefix "cc -o" lines
+dnl RULE_CC - symbol to put before implicit "cc -c" lines (e.g., .c.o)
+dnl SHOW_CC - symbol to put before explicit "cc -c" lines
+dnl ECHO_CC - symbol to put before any "cc" line
+dnl
+AC_DEFUN([CF_DISABLE_ECHO],[
+AC_MSG_CHECKING(if you want to see long compiling messages)
+CF_ARG_DISABLE(echo,
+ [ --disable-echo display "compiling" commands],
+ [
+ ECHO_LT='--silent'
+ ECHO_LD='@echo linking [$]@;'
+ RULE_CC='@echo compiling [$]<'
+ SHOW_CC='@echo compiling [$]@'
+ ECHO_CC='@'
+],[
+ ECHO_LT=''
+ ECHO_LD=''
+ RULE_CC=''
+ SHOW_CC=''
+ ECHO_CC=''
+])
+AC_MSG_RESULT($enableval)
+AC_SUBST(ECHO_LT)
+AC_SUBST(ECHO_LD)
+AC_SUBST(RULE_CC)
+AC_SUBST(SHOW_CC)
+AC_SUBST(ECHO_CC)
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_DISABLE_LEAKS version: 6 updated: 2010/07/23 04:14:32
+dnl ----------------
+dnl Combine no-leak checks with the libraries or tools that are used for the
+dnl checks.
+AC_DEFUN([CF_DISABLE_LEAKS],[
+
+AC_REQUIRE([CF_WITH_DMALLOC])
+AC_REQUIRE([CF_WITH_DBMALLOC])
+AC_REQUIRE([CF_WITH_VALGRIND])
+
+AC_MSG_CHECKING(if you want to perform memory-leak testing)
+AC_ARG_ENABLE(leaks,
+ [ --disable-leaks test: free permanent memory, analyze leaks],
+ [if test "x$enableval" = xno; then with_no_leaks=yes; else with_no_leaks=no; fi],
+ : ${with_no_leaks:=no})
+AC_MSG_RESULT($with_no_leaks)
+
+if test "$with_no_leaks" = yes ; then
+ AC_DEFINE(NO_LEAKS)
+ AC_DEFINE(YY_NO_LEAKS)
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_GCC_ATTRIBUTES version: 14 updated: 2010/10/23 15:52:32
+dnl -----------------
+dnl Test for availability of useful gcc __attribute__ directives to quiet
+dnl compiler warnings. Though useful, not all are supported -- and contrary
+dnl to documentation, unrecognized directives cause older compilers to barf.
+AC_DEFUN([CF_GCC_ATTRIBUTES],
+[
+if test "$GCC" = yes
+then
+cat > conftest.i <<EOF
+#ifndef GCC_PRINTF
+#define GCC_PRINTF 0
+#endif
+#ifndef GCC_SCANF
+#define GCC_SCANF 0
+#endif
+#ifndef GCC_NORETURN
+#define GCC_NORETURN /* nothing */
+#endif
+#ifndef GCC_UNUSED
+#define GCC_UNUSED /* nothing */
+#endif
+EOF
+if test "$GCC" = yes
+then
+ AC_CHECKING([for $CC __attribute__ directives])
+cat > conftest.$ac_ext <<EOF
+#line __oline__ "${as_me:-configure}"
+#include "confdefs.h"
+#include "conftest.h"
+#include "conftest.i"
+#if GCC_PRINTF
+#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
+#else
+#define GCC_PRINTFLIKE(fmt,var) /*nothing*/
+#endif
+#if GCC_SCANF
+#define GCC_SCANFLIKE(fmt,var) __attribute__((format(scanf,fmt,var)))
+#else
+#define GCC_SCANFLIKE(fmt,var) /*nothing*/
+#endif
+extern void wow(char *,...) GCC_SCANFLIKE(1,2);
+extern void oops(char *,...) GCC_PRINTFLIKE(1,2) GCC_NORETURN;
+extern void foo(void) GCC_NORETURN;
+int main(int argc GCC_UNUSED, char *argv[[]] GCC_UNUSED) { return 0; }
+EOF
+ cf_printf_attribute=no
+ cf_scanf_attribute=no
+ for cf_attribute in scanf printf unused noreturn
+ do
+ CF_UPPER(cf_ATTRIBUTE,$cf_attribute)
+ cf_directive="__attribute__(($cf_attribute))"
+ echo "checking for $CC $cf_directive" 1>&AC_FD_CC
+
+ case $cf_attribute in #(vi
+ printf) #(vi
+ cf_printf_attribute=yes
+ cat >conftest.h <<EOF
+#define GCC_$cf_ATTRIBUTE 1
+EOF
+ ;;
+ scanf) #(vi
+ cf_scanf_attribute=yes
+ cat >conftest.h <<EOF
+#define GCC_$cf_ATTRIBUTE 1
+EOF
+ ;;
+ *) #(vi
+ cat >conftest.h <<EOF
+#define GCC_$cf_ATTRIBUTE $cf_directive
+EOF
+ ;;
+ esac
+
+ if AC_TRY_EVAL(ac_compile); then
+ test -n "$verbose" && AC_MSG_RESULT(... $cf_attribute)
+ cat conftest.h >>confdefs.h
+ case $cf_attribute in #(vi
+ printf) #(vi
+ if test "$cf_printf_attribute" = no ; then
+ cat >>confdefs.h <<EOF
+#define GCC_PRINTFLIKE(fmt,var) /* nothing */
+EOF
+ else
+ cat >>confdefs.h <<EOF
+#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
+EOF
+ fi
+ ;;
+ scanf) #(vi
+ if test "$cf_scanf_attribute" = no ; then
+ cat >>confdefs.h <<EOF
+#define GCC_SCANFLIKE(fmt,var) /* nothing */
+EOF
+ else
+ cat >>confdefs.h <<EOF
+#define GCC_SCANFLIKE(fmt,var) __attribute__((format(scanf,fmt,var)))
+EOF
+ fi
+ ;;
+ esac
+ fi
+ done
+else
+ fgrep define conftest.i >>confdefs.h
+fi
+rm -rf conftest*
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_GCC_VERSION version: 5 updated: 2010/04/24 11:02:31
+dnl --------------
+dnl Find version of gcc
+AC_DEFUN([CF_GCC_VERSION],[
+AC_REQUIRE([AC_PROG_CC])
+GCC_VERSION=none
+if test "$GCC" = yes ; then
+ AC_MSG_CHECKING(version of $CC)
+ GCC_VERSION="`${CC} --version 2>/dev/null | sed -e '2,$d' -e 's/^.*(GCC) //' -e 's/^[[^0-9.]]*//' -e 's/[[^0-9.]].*//'`"
+ test -z "$GCC_VERSION" && GCC_VERSION=unknown
+ AC_MSG_RESULT($GCC_VERSION)
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_GCC_WARNINGS version: 27 updated: 2010/10/23 15:52:32
+dnl ---------------
+dnl Check if the compiler supports useful warning options. There's a few that
+dnl we don't use, simply because they're too noisy:
+dnl
+dnl -Wconversion (useful in older versions of gcc, but not in gcc 2.7.x)
+dnl -Wredundant-decls (system headers make this too noisy)
+dnl -Wtraditional (combines too many unrelated messages, only a few useful)
+dnl -Wwrite-strings (too noisy, but should review occasionally). This
+dnl is enabled for ncurses using "--enable-const".
+dnl -pedantic
+dnl
+dnl Parameter:
+dnl $1 is an optional list of gcc warning flags that a particular
+dnl application might want to use, e.g., "no-unused" for
+dnl -Wno-unused
+dnl Special:
+dnl If $with_ext_const is "yes", add a check for -Wwrite-strings
+dnl
+AC_DEFUN([CF_GCC_WARNINGS],
+[
+AC_REQUIRE([CF_GCC_VERSION])
+CF_INTEL_COMPILER(GCC,INTEL_COMPILER,CFLAGS)
+
+cat > conftest.$ac_ext <<EOF
+#line __oline__ "${as_me:-configure}"
+int main(int argc, char *argv[[]]) { return (argv[[argc-1]] == 0) ; }
+EOF
+
+if test "$INTEL_COMPILER" = yes
+then
+# The "-wdXXX" options suppress warnings:
+# remark #1419: external declaration in primary source file
+# remark #1683: explicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
+# remark #1684: conversion from pointer to same-sized integral type (potential portability problem)
+# remark #193: zero used for undefined preprocessing identifier
+# remark #593: variable "curs_sb_left_arrow" was set but never used
+# remark #810: conversion from "int" to "Dimension={unsigned short}" may lose significant bits
+# remark #869: parameter "tw" was never referenced
+# remark #981: operands are evaluated in unspecified order
+# warning #279: controlling expression is constant
+
+ AC_CHECKING([for $CC warning options])
+ cf_save_CFLAGS="$CFLAGS"
+ EXTRA_CFLAGS="-Wall"
+ for cf_opt in \
+ wd1419 \
+ wd1683 \
+ wd1684 \
+ wd193 \
+ wd593 \
+ wd279 \
+ wd810 \
+ wd869 \
+ wd981
+ do
+ CFLAGS="$cf_save_CFLAGS $EXTRA_CFLAGS -$cf_opt"
+ if AC_TRY_EVAL(ac_compile); then
+ test -n "$verbose" && AC_MSG_RESULT(... -$cf_opt)
+ EXTRA_CFLAGS="$EXTRA_CFLAGS -$cf_opt"
+ fi
+ done
+ CFLAGS="$cf_save_CFLAGS"
+
+elif test "$GCC" = yes
+then
+ AC_CHECKING([for $CC warning options])
+ cf_save_CFLAGS="$CFLAGS"
+ EXTRA_CFLAGS=
+ cf_warn_CONST=""
+ test "$with_ext_const" = yes && cf_warn_CONST="Wwrite-strings"
+ for cf_opt in W Wall \
+ Wbad-function-cast \
+ Wcast-align \
+ Wcast-qual \
+ Winline \
+ Wmissing-declarations \
+ Wmissing-prototypes \
+ Wnested-externs \
+ Wpointer-arith \
+ Wshadow \
+ Wstrict-prototypes \
+ Wundef $cf_warn_CONST $1
+ do
+ CFLAGS="$cf_save_CFLAGS $EXTRA_CFLAGS -$cf_opt"
+ if AC_TRY_EVAL(ac_compile); then
+ test -n "$verbose" && AC_MSG_RESULT(... -$cf_opt)
+ case $cf_opt in #(vi
+ Wcast-qual) #(vi
+ CPPFLAGS="$CPPFLAGS -DXTSTRINGDEFINES"
+ ;;
+ Winline) #(vi
+ case $GCC_VERSION in
+ [[34]].*)
+ CF_VERBOSE(feature is broken in gcc $GCC_VERSION)
+ continue;;
+ esac
+ ;;
+ esac
+ EXTRA_CFLAGS="$EXTRA_CFLAGS -$cf_opt"
+ fi
+ done
+ CFLAGS="$cf_save_CFLAGS"
+fi
+rm -rf conftest*
+
+AC_SUBST(EXTRA_CFLAGS)
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_GETOPT_HEADER version: 4 updated: 2009/08/31 20:07:52
+dnl ----------------
+dnl Check for getopt's variables which are commonly defined in stdlib.h,
+dnl unistd.h or (nonstandard) in getopt.h
+AC_DEFUN([CF_GETOPT_HEADER],
+[
+AC_HAVE_HEADERS(unistd.h getopt.h)
+AC_CACHE_CHECK(for header declaring getopt variables,cf_cv_getopt_header,[
+cf_cv_getopt_header=none
+for cf_header in stdio.h stdlib.h unistd.h getopt.h
+do
+AC_TRY_COMPILE([
+#include <$cf_header>],
+[int x = optind; char *y = optarg],
+[cf_cv_getopt_header=$cf_header
+ break])
+done
+])
+if test $cf_cv_getopt_header != none ; then
+ AC_DEFINE(HAVE_GETOPT_HEADER)
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_GNU_SOURCE version: 6 updated: 2005/07/09 13:23:07
+dnl -------------
+dnl Check if we must define _GNU_SOURCE to get a reasonable value for
+dnl _XOPEN_SOURCE, upon which many POSIX definitions depend. This is a defect
+dnl (or misfeature) of glibc2, which breaks portability of many applications,
+dnl since it is interwoven with GNU extensions.
+dnl
+dnl Well, yes we could work around it...
+AC_DEFUN([CF_GNU_SOURCE],
+[
+AC_CACHE_CHECK(if we must define _GNU_SOURCE,cf_cv_gnu_source,[
+AC_TRY_COMPILE([#include <sys/types.h>],[
+#ifndef _XOPEN_SOURCE
+make an error
+#endif],
+ [cf_cv_gnu_source=no],
+ [cf_save="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+ AC_TRY_COMPILE([#include <sys/types.h>],[
+#ifdef _XOPEN_SOURCE
+make an error
+#endif],
+ [cf_cv_gnu_source=no],
+ [cf_cv_gnu_source=yes])
+ CPPFLAGS="$cf_save"
+ ])
+])
+test "$cf_cv_gnu_source" = yes && CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_GNU_SOURCE version: 6 updated: 2005/07/09 13:23:07
+dnl -------------
+dnl Check if we must define _GNU_SOURCE to get a reasonable value for
+dnl _XOPEN_SOURCE, upon which many POSIX definitions depend. This is a defect
+dnl (or misfeature) of glibc2, which breaks portability of many applications,
+dnl since it is interwoven with GNU extensions.
+dnl
+dnl Well, yes we could work around it...
+AC_DEFUN([CF_GNU_SOURCE],
+[
+AC_CACHE_CHECK(if we must define _GNU_SOURCE,cf_cv_gnu_source,[
+AC_TRY_COMPILE([#include <sys/types.h>],[
+#ifndef _XOPEN_SOURCE
+make an error
+#endif],
+ [cf_cv_gnu_source=no],
+ [cf_save="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+ AC_TRY_COMPILE([#include <sys/types.h>],[
+#ifdef _XOPEN_SOURCE
+make an error
+#endif],
+ [cf_cv_gnu_source=no],
+ [cf_cv_gnu_source=yes])
+ CPPFLAGS="$cf_save"
+ ])
+])
+test "$cf_cv_gnu_source" = yes && CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_INTEL_COMPILER version: 4 updated: 2010/05/26 05:38:42
+dnl -----------------
+dnl Check if the given compiler is really the Intel compiler for Linux. It
+dnl tries to imitate gcc, but does not return an error when it finds a mismatch
+dnl between prototypes, e.g., as exercised by CF_MISSING_CHECK.
+dnl
+dnl This macro should be run "soon" after AC_PROG_CC or AC_PROG_CPLUSPLUS, to
+dnl ensure that it is not mistaken for gcc/g++. It is normally invoked from
+dnl the wrappers for gcc and g++ warnings.
+dnl
+dnl $1 = GCC (default) or GXX
+dnl $2 = INTEL_COMPILER (default) or INTEL_CPLUSPLUS
+dnl $3 = CFLAGS (default) or CXXFLAGS
+AC_DEFUN([CF_INTEL_COMPILER],[
+ifelse([$2],,INTEL_COMPILER,[$2])=no
+
+if test "$ifelse([$1],,[$1],GCC)" = yes ; then
+ case $host_os in
+ linux*|gnu*)
+ AC_MSG_CHECKING(if this is really Intel ifelse([$1],GXX,C++,C) compiler)
+ cf_save_CFLAGS="$ifelse([$3],,CFLAGS,[$3])"
+ ifelse([$3],,CFLAGS,[$3])="$ifelse([$3],,CFLAGS,[$3]) -no-gcc"
+ AC_TRY_COMPILE([],[
+#ifdef __INTEL_COMPILER
+#else
+make an error
+#endif
+],[ifelse([$2],,INTEL_COMPILER,[$2])=yes
+cf_save_CFLAGS="$cf_save_CFLAGS -we147 -no-gcc"
+],[])
+ ifelse([$3],,CFLAGS,[$3])="$cf_save_CFLAGS"
+ AC_MSG_RESULT($ifelse([$2],,INTEL_COMPILER,[$2]))
+ ;;
+ esac
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_MAKE_TAGS version: 6 updated: 2010/10/23 15:52:32
+dnl ------------
+dnl Generate tags/TAGS targets for makefiles. Do not generate TAGS if we have
+dnl a monocase filesystem.
+AC_DEFUN([CF_MAKE_TAGS],[
+AC_REQUIRE([CF_MIXEDCASE_FILENAMES])
+
+AC_CHECK_PROGS(CTAGS, exctags ctags)
+AC_CHECK_PROGS(ETAGS, exetags etags)
+
+AC_CHECK_PROG(MAKE_LOWER_TAGS, ${CTAGS:-ctags}, yes, no)
+
+if test "$cf_cv_mixedcase" = yes ; then
+ AC_CHECK_PROG(MAKE_UPPER_TAGS, ${ETAGS:-etags}, yes, no)
+else
+ MAKE_UPPER_TAGS=no
+fi
+
+if test "$MAKE_UPPER_TAGS" = yes ; then
+ MAKE_UPPER_TAGS=
+else
+ MAKE_UPPER_TAGS="#"
+fi
+
+if test "$MAKE_LOWER_TAGS" = yes ; then
+ MAKE_LOWER_TAGS=
+else
+ MAKE_LOWER_TAGS="#"
+fi
+
+AC_SUBST(CTAGS)
+AC_SUBST(ETAGS)
+
+AC_SUBST(MAKE_UPPER_TAGS)
+AC_SUBST(MAKE_LOWER_TAGS)
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_MIXEDCASE_FILENAMES version: 3 updated: 2003/09/20 17:07:55
+dnl ----------------------
+dnl Check if the file-system supports mixed-case filenames. If we're able to
+dnl create a lowercase name and see it as uppercase, it doesn't support that.
+AC_DEFUN([CF_MIXEDCASE_FILENAMES],
+[
+AC_CACHE_CHECK(if filesystem supports mixed-case filenames,cf_cv_mixedcase,[
+if test "$cross_compiling" = yes ; then
+ case $target_alias in #(vi
+ *-os2-emx*|*-msdosdjgpp*|*-cygwin*|*-mingw32*|*-uwin*) #(vi
+ cf_cv_mixedcase=no
+ ;;
+ *)
+ cf_cv_mixedcase=yes
+ ;;
+ esac
+else
+ rm -f conftest CONFTEST
+ echo test >conftest
+ if test -f CONFTEST ; then
+ cf_cv_mixedcase=no
+ else
+ cf_cv_mixedcase=yes
+ fi
+ rm -f conftest CONFTEST
+fi
+])
+test "$cf_cv_mixedcase" = yes && AC_DEFINE(MIXEDCASE_FILENAMES)
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_MSG_LOG version: 5 updated: 2010/10/23 15:52:32
+dnl ----------
+dnl Write a debug message to config.log, along with the line number in the
+dnl configure script.
+AC_DEFUN([CF_MSG_LOG],[
+echo "${as_me:-configure}:__oline__: testing $* ..." 1>&AC_FD_CC
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_NO_LEAKS_OPTION version: 4 updated: 2006/12/16 14:24:05
+dnl ------------------
+dnl see CF_WITH_NO_LEAKS
+AC_DEFUN([CF_NO_LEAKS_OPTION],[
+AC_MSG_CHECKING(if you want to use $1 for testing)
+AC_ARG_WITH($1,
+ [$2],
+ [AC_DEFINE($3)ifelse([$4],,[
+ $4
+])
+ : ${with_cflags:=-g}
+ : ${with_no_leaks:=yes}
+ with_$1=yes],
+ [with_$1=])
+AC_MSG_RESULT(${with_$1:-no})
+
+case .$with_cflags in #(vi
+.*-g*)
+ case .$CFLAGS in #(vi
+ .*-g*) #(vi
+ ;;
+ *)
+ CF_ADD_CFLAGS([-g])
+ ;;
+ esac
+ ;;
+esac
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_PATHSEP version: 5 updated: 2010/05/26 05:38:42
+dnl ----------
+dnl Provide a value for the $PATH and similar separator
+AC_DEFUN([CF_PATHSEP],
+[
+ case $cf_cv_system_name in
+ os2*) PATH_SEPARATOR=';' ;;
+ *) PATH_SEPARATOR=':' ;;
+ esac
+ifelse([$1],,,[$1=$PATH_SEPARATOR])
+ AC_SUBST(PATH_SEPARATOR)
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_PATH_PROG version: 8 updated: 2010/10/23 16:12:25
+dnl ------------
+dnl Check for a given program, defining corresponding symbol.
+dnl $1 = environment variable, which is suffixed by "_PATH" in the #define.
+dnl $2 = program name to find.
+dnl $3 = optional list of additional program names to test.
+dnl
+dnl If there is more than one token in the result, #define the remaining tokens
+dnl to $1_ARGS. We need this for 'install' in particular.
+dnl
+dnl FIXME: we should allow this to be overridden by environment variables
+dnl
+AC_DEFUN([CF_PATH_PROG],[
+AC_REQUIRE([CF_PATHSEP])
+test -z "[$]$1" && $1=$2
+AC_PATH_PROGS($1,[$]$1 $2 $3,[$]$1)
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_$1
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+ CF_PATH_SYNTAX(cf_temp,break)
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+ CF_MSG_LOG(defining path for ${cf_path_prog})
+ AC_DEFINE_UNQUOTED($1_PATH,"$cf_path_prog")
+ test -n "$cf_path_args" && AC_DEFINE_UNQUOTED($1_ARGS,"$cf_path_args")
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_PATH_SYNTAX version: 13 updated: 2010/05/26 05:38:42
+dnl --------------
+dnl Check the argument to see that it looks like a pathname. Rewrite it if it
+dnl begins with one of the prefix/exec_prefix variables, and then again if the
+dnl result begins with 'NONE'. This is necessary to work around autoconf's
+dnl delayed evaluation of those symbols.
+AC_DEFUN([CF_PATH_SYNTAX],[
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".[$]$1" in #(vi
+.\[$]\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[[a-zA-Z]]:[[\\/]]*) #(vi OS/2 EMX
+ ;;
+.\[$]{*prefix}*) #(vi
+ eval $1="[$]$1"
+ case ".[$]$1" in #(vi
+ .NONE/*)
+ $1=`echo [$]$1 | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ $1=`echo [$]$1 | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ ifelse([$2],,[AC_MSG_ERROR([expected a pathname, not \"[$]$1\"])],$2)
+ ;;
+esac
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_POSIX_C_SOURCE version: 8 updated: 2010/05/26 05:38:42
+dnl -----------------
+dnl Define _POSIX_C_SOURCE to the given level, and _POSIX_SOURCE if needed.
+dnl
+dnl POSIX.1-1990 _POSIX_SOURCE
+dnl POSIX.1-1990 and _POSIX_SOURCE and
+dnl POSIX.2-1992 C-Language _POSIX_C_SOURCE=2
+dnl Bindings Option
+dnl POSIX.1b-1993 _POSIX_C_SOURCE=199309L
+dnl POSIX.1c-1996 _POSIX_C_SOURCE=199506L
+dnl X/Open 2000 _POSIX_C_SOURCE=200112L
+dnl
+dnl Parameters:
+dnl $1 is the nominal value for _POSIX_C_SOURCE
+AC_DEFUN([CF_POSIX_C_SOURCE],
+[
+cf_POSIX_C_SOURCE=ifelse([$1],,199506L,[$1])
+
+cf_save_CFLAGS="$CFLAGS"
+cf_save_CPPFLAGS="$CPPFLAGS"
+
+CF_REMOVE_DEFINE(cf_trim_CFLAGS,$cf_save_CFLAGS,_POSIX_C_SOURCE)
+CF_REMOVE_DEFINE(cf_trim_CPPFLAGS,$cf_save_CPPFLAGS,_POSIX_C_SOURCE)
+
+AC_CACHE_CHECK(if we should define _POSIX_C_SOURCE,cf_cv_posix_c_source,[
+ CF_MSG_LOG(if the symbol is already defined go no further)
+ AC_TRY_COMPILE([#include <sys/types.h>],[
+#ifndef _POSIX_C_SOURCE
+make an error
+#endif],
+ [cf_cv_posix_c_source=no],
+ [cf_want_posix_source=no
+ case .$cf_POSIX_C_SOURCE in #(vi
+ .[[12]]??*) #(vi
+ cf_cv_posix_c_source="-D_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE"
+ ;;
+ .2) #(vi
+ cf_cv_posix_c_source="-D_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE"
+ cf_want_posix_source=yes
+ ;;
+ .*)
+ cf_want_posix_source=yes
+ ;;
+ esac
+ if test "$cf_want_posix_source" = yes ; then
+ AC_TRY_COMPILE([#include <sys/types.h>],[
+#ifdef _POSIX_SOURCE
+make an error
+#endif],[],
+ cf_cv_posix_c_source="$cf_cv_posix_c_source -D_POSIX_SOURCE")
+ fi
+ CF_MSG_LOG(ifdef from value $cf_POSIX_C_SOURCE)
+ CFLAGS="$cf_trim_CFLAGS"
+ CPPFLAGS="$cf_trim_CPPFLAGS $cf_cv_posix_c_source"
+ CF_MSG_LOG(if the second compile does not leave our definition intact error)
+ AC_TRY_COMPILE([#include <sys/types.h>],[
+#ifndef _POSIX_C_SOURCE
+make an error
+#endif],,
+ [cf_cv_posix_c_source=no])
+ CFLAGS="$cf_save_CFLAGS"
+ CPPFLAGS="$cf_save_CPPFLAGS"
+ ])
+])
+
+if test "$cf_cv_posix_c_source" != no ; then
+ CFLAGS="$cf_trim_CFLAGS"
+ CPPFLAGS="$cf_trim_CPPFLAGS"
+ CF_ADD_CFLAGS($cf_cv_posix_c_source)
+fi
+
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_PROG_CC_U_D version: 1 updated: 2005/07/14 16:59:30
+dnl --------------
+dnl Check if C (preprocessor) -U and -D options are processed in the order
+dnl given rather than by type of option. Some compilers insist on apply all
+dnl of the -U options after all of the -D options. Others allow mixing them,
+dnl and may predefine symbols that conflict with those we define.
+AC_DEFUN([CF_PROG_CC_U_D],
+[
+AC_CACHE_CHECK(if $CC -U and -D options work together,cf_cv_cc_u_d_options,[
+ cf_save_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-UU_D_OPTIONS -DU_D_OPTIONS -DD_U_OPTIONS -UD_U_OPTIONS"
+ AC_TRY_COMPILE([],[
+#ifndef U_D_OPTIONS
+make an undefined-error
+#endif
+#ifdef D_U_OPTIONS
+make a defined-error
+#endif
+ ],[
+ cf_cv_cc_u_d_options=yes],[
+ cf_cv_cc_u_d_options=no])
+ CPPFLAGS="$cf_save_CPPFLAGS"
+])
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_PROG_EXT version: 10 updated: 2004/01/03 19:28:18
+dnl -----------
+dnl Compute $PROG_EXT, used for non-Unix ports, such as OS/2 EMX.
+AC_DEFUN([CF_PROG_EXT],
+[
+AC_REQUIRE([CF_CHECK_CACHE])
+case $cf_cv_system_name in
+os2*)
+ CFLAGS="$CFLAGS -Zmt"
+ CPPFLAGS="$CPPFLAGS -D__ST_MT_ERRNO__"
+ CXXFLAGS="$CXXFLAGS -Zmt"
+ # autoconf's macro sets -Zexe and suffix both, which conflict:w
+ LDFLAGS="$LDFLAGS -Zmt -Zcrtdll"
+ ac_cv_exeext=.exe
+ ;;
+esac
+
+AC_EXEEXT
+AC_OBJEXT
+
+PROG_EXT="$EXEEXT"
+AC_SUBST(PROG_EXT)
+test -n "$PROG_EXT" && AC_DEFINE_UNQUOTED(PROG_EXT,"$PROG_EXT")
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_PROG_LINT version: 2 updated: 2009/08/12 04:43:14
+dnl ------------
+AC_DEFUN([CF_PROG_LINT],
+[
+AC_CHECK_PROGS(LINT, tdlint lint alint splint lclint)
+AC_SUBST(LINT_OPTS)
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_REMOVE_DEFINE version: 3 updated: 2010/01/09 11:05:50
+dnl ----------------
+dnl Remove all -U and -D options that refer to the given symbol from a list
+dnl of C compiler options. This works around the problem that not all
+dnl compilers process -U and -D options from left-to-right, so a -U option
+dnl cannot be used to cancel the effect of a preceding -D option.
+dnl
+dnl $1 = target (which could be the same as the source variable)
+dnl $2 = source (including '$')
+dnl $3 = symbol to remove
+define([CF_REMOVE_DEFINE],
+[
+$1=`echo "$2" | \
+ sed -e 's/-[[UD]]'"$3"'\(=[[^ ]]*\)\?[[ ]]/ /g' \
+ -e 's/-[[UD]]'"$3"'\(=[[^ ]]*\)\?[$]//g'`
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_STDIO_UNLOCKED version: 3 updated: 2009/10/06 19:54:39
+dnl -----------------
+dnl The four functions getc_unlocked(), getchar_unlocked(), putc_unlocked(),
+dnl putchar_unlocked() are in POSIX.1-2001.
+dnl
+dnl Test for one or more of the "unlocked" stdio getc/putc functions, and (if
+dnl the system requires it to declare the prototype) define _REENTRANT
+dnl
+dnl $1 = one or more stdio functions to check for existence and prototype.
+AC_DEFUN([CF_STDIO_UNLOCKED],
+[
+cf_stdio_unlocked=no
+AC_CHECK_FUNCS(ifelse([$1],,[getc_unlocked putc_unlocked],[$1]),
+ [cf_stdio_unlocked=$ac_func])
+if test "$cf_stdio_unlocked" != no ; then
+ case "$CPPFLAGS" in #(vi
+ *-D_REENTRANT*) #(vi
+ ;;
+ *)
+ AC_CACHE_CHECK(if we should define _REENTRANT,cf_cv_stdio_unlocked,[
+ AC_TRY_COMPILE([#include <stdio.h>],[
+ extern void *$cf_stdio_unlocked(void *);
+ void *dummy = $cf_stdio_unlocked(0)],
+ [cf_cv_stdio_unlocked=yes],
+ [cf_cv_stdio_unlocked=no])])
+ if test "$cf_cv_stdio_unlocked" = yes ; then
+ AC_DEFINE(_REENTRANT)
+ fi
+ ;;
+ esac
+fi
+])
+dnl ---------------------------------------------------------------------------
+dnl CF_TRY_XOPEN_SOURCE version: 1 updated: 2011/10/30 17:09:50
+dnl -------------------
+dnl If _XOPEN_SOURCE is not defined in the compile environment, check if we
+dnl can define it successfully.
+AC_DEFUN([CF_TRY_XOPEN_SOURCE],[
+AC_CACHE_CHECK(if we should define _XOPEN_SOURCE,cf_cv_xopen_source,[
+ AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+],[
+#ifndef _XOPEN_SOURCE
+make an error
+#endif],
+ [cf_cv_xopen_source=no],
+ [cf_save="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=$cf_XOPEN_SOURCE"
+ AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+],[
+#ifdef _XOPEN_SOURCE
+make an error
+#endif],
+ [cf_cv_xopen_source=no],
+ [cf_cv_xopen_source=$cf_XOPEN_SOURCE])
+ CPPFLAGS="$cf_save"
+ ])
+])
+
+if test "$cf_cv_xopen_source" != no ; then
+ CF_REMOVE_DEFINE(CFLAGS,$CFLAGS,_XOPEN_SOURCE)
+ CF_REMOVE_DEFINE(CPPFLAGS,$CPPFLAGS,_XOPEN_SOURCE)
+ cf_temp_xopen_source="-D_XOPEN_SOURCE=$cf_cv_xopen_source"
+ CF_ADD_CFLAGS($cf_temp_xopen_source)
+fi
+])
+dnl ---------------------------------------------------------------------------
+dnl CF_UPPER version: 5 updated: 2001/01/29 23:40:59
+dnl --------
+dnl Make an uppercase version of a variable
+dnl $1=uppercase($2)
+AC_DEFUN([CF_UPPER],
+[
+$1=`echo "$2" | sed y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%`
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_VERBOSE version: 3 updated: 2007/07/29 09:55:12
+dnl ----------
+dnl Use AC_VERBOSE w/o the warnings
+AC_DEFUN([CF_VERBOSE],
+[test -n "$verbose" && echo " $1" 1>&AC_FD_MSG
+CF_MSG_LOG([$1])
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_WITH_DBMALLOC version: 7 updated: 2010/06/21 17:26:47
+dnl ----------------
+dnl Configure-option for dbmalloc. The optional parameter is used to override
+dnl the updating of $LIBS, e.g., to avoid conflict with subsequent tests.
+AC_DEFUN([CF_WITH_DBMALLOC],[
+CF_NO_LEAKS_OPTION(dbmalloc,
+ [ --with-dbmalloc test: use Conor Cahill's dbmalloc library],
+ [USE_DBMALLOC])
+
+if test "$with_dbmalloc" = yes ; then
+ AC_CHECK_HEADER(dbmalloc.h,
+ [AC_CHECK_LIB(dbmalloc,[debug_malloc]ifelse([$1],,[],[,$1]))])
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_WITH_DMALLOC version: 7 updated: 2010/06/21 17:26:47
+dnl ---------------
+dnl Configure-option for dmalloc. The optional parameter is used to override
+dnl the updating of $LIBS, e.g., to avoid conflict with subsequent tests.
+AC_DEFUN([CF_WITH_DMALLOC],[
+CF_NO_LEAKS_OPTION(dmalloc,
+ [ --with-dmalloc test: use Gray Watson's dmalloc library],
+ [USE_DMALLOC])
+
+if test "$with_dmalloc" = yes ; then
+ AC_CHECK_HEADER(dmalloc.h,
+ [AC_CHECK_LIB(dmalloc,[dmalloc_debug]ifelse([$1],,[],[,$1]))])
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_WITH_INSTALL_PREFIX version: 4 updated: 2010/10/23 15:52:32
+dnl ----------------------
+dnl Configure-script option to give a default value for the poorly-chosen name
+dnl $(DESTDIR).
+AC_DEFUN([CF_WITH_INSTALL_PREFIX],
+[
+AC_MSG_CHECKING(for install-prefix)
+AC_ARG_WITH(install-prefix,
+ [ --with-install-prefix=XXX sets DESTDIR, useful for packaging],
+ [cf_opt_with_install_prefix=$withval],
+ [cf_opt_with_install_prefix=${DESTDIR:-no}])
+AC_MSG_RESULT($cf_opt_with_install_prefix)
+if test "$cf_opt_with_install_prefix" != no ; then
+ CF_PATH_SYNTAX(cf_opt_with_install_prefix)
+ DESTDIR=$cf_opt_with_install_prefix
+fi
+AC_SUBST(DESTDIR)
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_WITH_PURIFY version: 2 updated: 2006/12/14 18:43:43
+dnl --------------
+AC_DEFUN([CF_WITH_PURIFY],[
+CF_NO_LEAKS_OPTION(purify,
+ [ --with-purify test: use Purify],
+ [USE_PURIFY],
+ [LINK_PREFIX="$LINK_PREFIX purify"])
+AC_SUBST(LINK_PREFIX)
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_WITH_VALGRIND version: 1 updated: 2006/12/14 18:00:21
+dnl ----------------
+AC_DEFUN([CF_WITH_VALGRIND],[
+CF_NO_LEAKS_OPTION(valgrind,
+ [ --with-valgrind test: use valgrind],
+ [USE_VALGRIND])
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_WITH_WARNINGS version: 5 updated: 2004/07/23 14:40:34
+dnl ----------------
+dnl Combine the checks for gcc features into a configure-script option
+dnl
+dnl Parameters:
+dnl $1 - see CF_GCC_WARNINGS
+AC_DEFUN([CF_WITH_WARNINGS],
+[
+if ( test "$GCC" = yes || test "$GXX" = yes )
+then
+AC_MSG_CHECKING(if you want to check for gcc warnings)
+AC_ARG_WITH(warnings,
+ [ --with-warnings test: turn on gcc warnings],
+ [cf_opt_with_warnings=$withval],
+ [cf_opt_with_warnings=no])
+AC_MSG_RESULT($cf_opt_with_warnings)
+if test "$cf_opt_with_warnings" != no ; then
+ CF_GCC_ATTRIBUTES
+ CF_GCC_WARNINGS([$1])
+fi
+fi
+])dnl
+dnl ---------------------------------------------------------------------------
+dnl CF_XOPEN_SOURCE version: 41 updated: 2011/12/10 18:58:47
+dnl ---------------
+dnl Try to get _XOPEN_SOURCE defined properly that we can use POSIX functions,
+dnl or adapt to the vendor's definitions to get equivalent functionality,
+dnl without losing the common non-POSIX features.
+dnl
+dnl Parameters:
+dnl $1 is the nominal value for _XOPEN_SOURCE
+dnl $2 is the nominal value for _POSIX_C_SOURCE
+AC_DEFUN([CF_XOPEN_SOURCE],[
+
+cf_XOPEN_SOURCE=ifelse([$1],,500,[$1])
+cf_POSIX_C_SOURCE=ifelse([$2],,199506L,[$2])
+cf_xopen_source=
+
+case $host_os in #(vi
+aix[[4-7]]*) #(vi
+ cf_xopen_source="-D_ALL_SOURCE"
+ ;;
+cygwin) #(vi
+ cf_XOPEN_SOURCE=600
+ ;;
+darwin[[0-8]].*) #(vi
+ cf_xopen_source="-D_APPLE_C_SOURCE"
+ ;;
+darwin*) #(vi
+ cf_xopen_source="-D_DARWIN_C_SOURCE"
+ ;;
+freebsd*|dragonfly*) #(vi
+ # 5.x headers associate
+ # _XOPEN_SOURCE=600 with _POSIX_C_SOURCE=200112L
+ # _XOPEN_SOURCE=500 with _POSIX_C_SOURCE=199506L
+ cf_POSIX_C_SOURCE=200112L
+ cf_XOPEN_SOURCE=600
+ cf_xopen_source="-D_BSD_TYPES -D__BSD_VISIBLE -D_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE -D_XOPEN_SOURCE=$cf_XOPEN_SOURCE"
+ ;;
+hpux11*) #(vi
+ cf_xopen_source="-D_HPUX_SOURCE -D_XOPEN_SOURCE=500"
+ ;;
+hpux*) #(vi
+ cf_xopen_source="-D_HPUX_SOURCE"
+ ;;
+irix[[56]].*) #(vi
+ cf_xopen_source="-D_SGI_SOURCE"
+ cf_XOPEN_SOURCE=
+ ;;
+linux*|gnu*|mint*|k*bsd*-gnu) #(vi
+ CF_GNU_SOURCE
+ ;;
+mirbsd*) #(vi
+ # setting _XOPEN_SOURCE or _POSIX_SOURCE breaks <sys/select.h> and other headers which use u_int / u_short types
+ cf_XOPEN_SOURCE=
+ CF_POSIX_C_SOURCE($cf_POSIX_C_SOURCE)
+ ;;
+netbsd*) #(vi
+ cf_xopen_source="-D_NETBSD_SOURCE" # setting _XOPEN_SOURCE breaks IPv6 for lynx on NetBSD 1.6, breaks xterm, is not needed for ncursesw
+ ;;
+openbsd[[4-9]]*) #(vi
+ # setting _XOPEN_SOURCE lower than 500 breaks g++ compile with wchar.h, needed for ncursesw
+ cf_XOPEN_SOURCE=600
+ ;;
+openbsd*) #(vi
+ # setting _XOPEN_SOURCE breaks xterm on OpenBSD 2.8, is not needed for ncursesw
+ ;;
+osf[[45]]*) #(vi
+ cf_xopen_source="-D_OSF_SOURCE"
+ ;;
+nto-qnx*) #(vi
+ cf_xopen_source="-D_QNX_SOURCE"
+ ;;
+sco*) #(vi
+ # setting _XOPEN_SOURCE breaks Lynx on SCO Unix / OpenServer
+ ;;
+solaris2.*) #(vi
+ cf_xopen_source="-D__EXTENSIONS__"
+ ;;
+*)
+ CF_TRY_XOPEN_SOURCE
+ CF_POSIX_C_SOURCE($cf_POSIX_C_SOURCE)
+ ;;
+esac
+
+if test -n "$cf_xopen_source" ; then
+ CF_ADD_CFLAGS($cf_xopen_source)
+fi
+
+dnl In anything but the default case, we may have system-specific setting
+dnl which is still not guaranteed to provide all of the entrypoints that
+dnl _XOPEN_SOURCE would yield.
+if test -n "$cf_XOPEN_SOURCE" && test -z "$cf_cv_xopen_source" ; then
+ AC_MSG_CHECKING(if _XOPEN_SOURCE really is set)
+ AC_TRY_COMPILE([#include <stdlib.h>],[
+#ifndef _XOPEN_SOURCE
+make an error
+#endif],
+ [cf_XOPEN_SOURCE_set=yes],
+ [cf_XOPEN_SOURCE_set=no])
+ AC_MSG_RESULT($cf_XOPEN_SOURCE_set)
+ if test $cf_XOPEN_SOURCE_set = yes
+ then
+ AC_TRY_COMPILE([#include <stdlib.h>],[
+#if (_XOPEN_SOURCE - 0) < $cf_XOPEN_SOURCE
+make an error
+#endif],
+ [cf_XOPEN_SOURCE_set_ok=yes],
+ [cf_XOPEN_SOURCE_set_ok=no])
+ if test $cf_XOPEN_SOURCE_set_ok = no
+ then
+ AC_MSG_WARN(_XOPEN_SOURCE is lower than requested)
+ fi
+ else
+ CF_TRY_XOPEN_SOURCE
+ fi
+fi
+])
diff --git a/patch_cmds/diffstat/config.guess b/patch_cmds/diffstat/config.guess
new file mode 100644
index 0000000..bec935b
--- /dev/null
+++ b/patch_cmds/diffstat/config.guess
@@ -0,0 +1,1508 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+# Free Software Foundation, Inc.
+
+timestamp='2010-09-24'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to <config-patches@gnu.org> and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' HUP INT TERM
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" HUP INT PIPE TERM ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null | \
+ grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-tilera-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/patch_cmds/diffstat/config.h b/patch_cmds/diffstat/config.h
new file mode 100644
index 0000000..16f0d23
--- /dev/null
+++ b/patch_cmds/diffstat/config.h
@@ -0,0 +1,38 @@
+/* config.h. Generated automatically by configure. */
+/*
+ * $Id: config_h.in,v 1.1 1994/06/12 23:48:18 tom Exp $
+ * config_h.in is a template file used by configure to produce config.h.
+ * config_h is then transformed (by config.status) into the header file
+ * config.h -- Kevin Buettner.
+ */
+
+
+#define CC_HAS_PROTOS 1
+//#define SYSTEM_NAME "darwin13.0.0"
+#define BZCAT_PATH "bzcat"
+#define BZIP2_PATH "bzip2"
+#define COMPRESS_PATH "compress"
+#define GZIP_PATH "gzip"
+#define LZCAT_PATH "xz"
+#define UNCOMPRESS_PATH "uncompress"
+#define XZ_PATH "xz"
+#define ZCAT_PATH "zcat"
+#define STDC_HEADERS 1
+#define HAVE_SEARCH_H 1
+#define HAVE_STRING_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_GETOPT_H 1
+#define HAVE_GETOPT_HEADER 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRING_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_MKDTEMP 1
+#define HAVE_POPEN 1
+#define HAVE_TSEARCH 1
+#define HAVE_GETC_UNLOCKED 1
diff --git a/patch_cmds/diffstat/config.sub b/patch_cmds/diffstat/config.sub
new file mode 100644
index 0000000..de11910
--- /dev/null
+++ b/patch_cmds/diffstat/config.sub
@@ -0,0 +1,1739 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+# Free Software Foundation, Inc.
+
+timestamp='2010-09-11'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be\
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile-* | tilegx-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ # This must be matched before tile*.
+ tilegx*)
+ basic_machine=tilegx-unknown
+ os=-linux-gnu
+ ;;
+ tile*)
+ basic_machine=tile-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/patch_cmds/diffstat/config_h.in b/patch_cmds/diffstat/config_h.in
new file mode 100644
index 0000000..ac8ff1d
--- /dev/null
+++ b/patch_cmds/diffstat/config_h.in
@@ -0,0 +1,8 @@
+/*
+ * $Id: config_h.in,v 1.1 1994/06/12 23:48:18 tom Exp $
+ * config_h.in is a template file used by configure to produce config.h.
+ * config_h is then transformed (by config.status) into the header file
+ * config.h -- Kevin Buettner.
+ */
+
+@DEFS@
diff --git a/patch_cmds/diffstat/configure b/patch_cmds/diffstat/configure
new file mode 100644
index 0000000..35e6b67
--- /dev/null
+++ b/patch_cmds/diffstat/configure
@@ -0,0 +1,7291 @@
+#! /bin/sh
+# From configure.in Revision: 1.22 .
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by Autoconf 2.52.20101002.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Name of the executable.
+as_me=`echo "$0" |sed 's,.*[\\/],,'`
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+# NLS nuisances.
+$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; }
+$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; }
+$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; }
+$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; }
+$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; }
+$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; }
+$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; }
+$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; }
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; }
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+cross_compiling=no
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+ac_unique_file="diffstat.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: should be removed in autoconf 3.0.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo "$ac_prog" | sed 's%[\\/][^\\/][^\\/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<EOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+EOF
+
+ cat <<EOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+EOF
+
+ cat <<\EOF
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST build programs to run on HOST [BUILD]
+EOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\EOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+
+ --disable-echo display "compiling" commands
+ --with-install-prefix=XXX sets DESTDIR, useful for packaging
+ --with-warnings test: turn on gcc warnings
+ --with-dmalloc test: use Gray Watson's dmalloc library
+ --with-dbmalloc test: use Conor Cahill's dbmalloc library
+ --with-valgrind test: use valgrind
+ --disable-leaks test: free permanent memory, analyze leaks
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+EOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_subdir in : $ac_subdirs_all; do test "x$ac_subdir" = x: && continue
+ cd $ac_subdir
+ # A "../" for each directory in /$ac_subdir.
+ ac_dots=`echo $ac_subdir |
+ sed 's,^\./,,;s,[^/]$,&/,;s,[^/]*/,../,g'`
+
+ case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_sub_srcdir=$srcdir ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_sub_srcdir=$srcdir/$ac_subdir ;;
+ *) # Relative path.
+ ac_sub_srcdir=$ac_dots$srcdir/$ac_subdir ;;
+ esac
+
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_sub_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_sub_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_sub_srcdir/configure; then
+ echo
+ $SHELL $ac_sub_srcdir/configure --help=recursive
+ elif test -f $ac_sub_srcdir/configure.ac ||
+ test -f $ac_sub_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_subdir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\EOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+EOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<EOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.52.20101002. Invocation command line was
+
+ $ $0 $@
+
+EOF
+{
+cat <<_ASUNAME
+## ---------- ##
+## Platform. ##
+## ---------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+PATH = $PATH
+
+_ASUNAME
+} >&5
+
+cat >&5 <<EOF
+## ------------ ##
+## Core tests. ##
+## ------------ ##
+
+EOF
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell meta-characters.
+ac_configure_args=
+ac_sep=
+for ac_arg
+do
+ case $ac_arg in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"`
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ ac_sep=" " ;;
+ *) ac_configure_args="$ac_configure_args$ac_sep$ac_arg"
+ ac_sep=" " ;;
+ esac
+ # Get rid of the leading space.
+done
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ echo >&5
+ echo "## ----------------- ##" >&5
+ echo "## Cache variables. ##" >&5
+ echo "## ----------------- ##" >&5
+ echo >&5
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} >&5
+ sed "/^$/d" confdefs.h >conftest.log
+ if test -s conftest.log; then
+ echo >&5
+ echo "## ------------ ##" >&5
+ echo "## confdefs.h. ##" >&5
+ echo "## ------------ ##" >&5
+ echo >&5
+ cat conftest.log >&5
+ fi
+ (echo; echo) >&5
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal" >&5
+ echo "$as_me: exit $exit_status" >&5
+ rm -rf conftest* confdefs* core core.* *.core conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:876: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ cat "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:887: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:895: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:911: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:915: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:921: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:923: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:925: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status. It doesn't matter if
+ # we pass some twice (in addition to the command line arguments).
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"`
+ ac_configure_args="$ac_configure_args '$ac_arg'"
+ ;;
+ *) ac_configure_args="$ac_configure_args $ac_var=$ac_new_val"
+ ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:944: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:946: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_main_return=return
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+echo "#! $SHELL" >conftest.sh
+echo "exit 0" >>conftest.sh
+chmod +x conftest.sh
+if { (echo "$as_me:967: PATH=\".;.\"; conftest.sh") >&5
+ (PATH=".;."; conftest.sh) 2>&5
+ ac_status=$?
+ echo "$as_me:970: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ ac_path_separator=';'
+else
+ ac_path_separator=:
+fi
+PATH_SEPARATOR="$ac_path_separator"
+rm -f conftest.sh
+
+ac_config_headers="$ac_config_headers config.h:config_h.in"
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_main_return=return
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:990: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="${ac_tool_prefix}gcc"
+echo "$as_me:1005: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1013: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1016: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:1025: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="gcc"
+echo "$as_me:1040: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:1048: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:1051: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:1064: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="${ac_tool_prefix}cc"
+echo "$as_me:1079: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1087: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1090: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:1099: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="cc"
+echo "$as_me:1114: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:1122: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:1125: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:1138: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+fi
+ac_cv_prog_CC="cc"
+echo "$as_me:1158: found $ac_dir/$ac_word" >&5
+break
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" ${1+"$@"}
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1180: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1183: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:1194: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+echo "$as_me:1209: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1217: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1220: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:1233: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="$ac_prog"
+echo "$as_me:1248: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:1256: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:1259: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+test -z "$CC" && { { echo "$as_me:1271: error: no acceptable cc found in \$PATH" >&5
+echo "$as_me: error: no acceptable cc found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:1276:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:1279: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1282: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:1284: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1287: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:1289: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1292: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line 1296 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:1312: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:1315: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:1318: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+for ac_file in `ls a.exe conftest.exe 2>/dev/null;
+ ls a.out conftest 2>/dev/null;
+ ls a.* conftest.* 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.dbg | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+ a.out ) # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool --akim.
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:1341: error: C compiler cannot create executables" >&5
+echo "$as_me: error: C compiler cannot create executables" >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:1347: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:1352: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:1358: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1361: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:1368: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:1376: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:1383: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:1385: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:1388: checking for executable suffix" >&5
+echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6
+if { (eval echo "$as_me:1390: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:1393: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.dbg | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:1409: error: cannot compute EXEEXT: cannot compile and link" >&5
+echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:1415: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:1421: checking for object suffix" >&5
+echo $ECHO_N "checking for object suffix... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1427 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:1439: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1442: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.dbg | *.pdb | *.xSYM | *.map | *.inf ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:1454: error: cannot compute OBJEXT: cannot compile" >&5
+echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:1461: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:1465: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1471 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1486: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1489: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1492: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1495: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:1507: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:1513: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1519 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1531: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1534: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1537: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1540: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:1550: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1577: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1580: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1583: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1586: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1598 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1611: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1614: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1617: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1620: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1630 "configure"
+#include "confdefs.h"
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1642: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1645: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1648: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1651: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -rf conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_main_return=return
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:1696: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:1716: checking for a BSD compatible install" >&5
+echo $ECHO_N "checking for a BSD compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ for ac_dir in $PATH; do
+ IFS=$ac_save_IFS
+ # Account for people who put trailing slashes in PATH elements.
+ case $ac_dir/ in
+ / | ./ | .// | /cC/* \
+ | /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* \
+ | /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if $as_executable_p "$ac_dir/$ac_prog"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$ac_dir/$ac_prog" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$ac_dir/$ac_prog" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:1765: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+for ac_prog in tdlint lint alint splint lclint
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:1780: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_LINT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$LINT"; then
+ ac_cv_prog_LINT="$LINT" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_LINT="$ac_prog"
+echo "$as_me:1795: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+LINT=$ac_cv_prog_LINT
+if test -n "$LINT"; then
+ echo "$as_me:1803: result: $LINT" >&5
+echo "${ECHO_T}$LINT" >&6
+else
+ echo "$as_me:1806: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$LINT" && break
+done
+
+echo "$as_me:1813: checking if filesystem supports mixed-case filenames" >&5
+echo $ECHO_N "checking if filesystem supports mixed-case filenames... $ECHO_C" >&6
+if test "${cf_cv_mixedcase+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+if test "$cross_compiling" = yes ; then
+ case $target_alias in #(vi
+ *-os2-emx*|*-msdosdjgpp*|*-cygwin*|*-mingw32*|*-uwin*) #(vi
+ cf_cv_mixedcase=no
+ ;;
+ *)
+ cf_cv_mixedcase=yes
+ ;;
+ esac
+else
+ rm -f conftest CONFTEST
+ echo test >conftest
+ if test -f CONFTEST ; then
+ cf_cv_mixedcase=no
+ else
+ cf_cv_mixedcase=yes
+ fi
+ rm -f conftest CONFTEST
+fi
+
+fi
+echo "$as_me:1840: result: $cf_cv_mixedcase" >&5
+echo "${ECHO_T}$cf_cv_mixedcase" >&6
+test "$cf_cv_mixedcase" = yes && cat >>confdefs.h <<\EOF
+#define MIXEDCASE_FILENAMES 1
+EOF
+
+for ac_prog in exctags ctags
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:1850: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CTAGS+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CTAGS"; then
+ ac_cv_prog_CTAGS="$CTAGS" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CTAGS="$ac_prog"
+echo "$as_me:1865: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CTAGS=$ac_cv_prog_CTAGS
+if test -n "$CTAGS"; then
+ echo "$as_me:1873: result: $CTAGS" >&5
+echo "${ECHO_T}$CTAGS" >&6
+else
+ echo "$as_me:1876: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CTAGS" && break
+done
+
+for ac_prog in exetags etags
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:1887: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ETAGS+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ETAGS"; then
+ ac_cv_prog_ETAGS="$ETAGS" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ETAGS="$ac_prog"
+echo "$as_me:1902: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ETAGS=$ac_cv_prog_ETAGS
+if test -n "$ETAGS"; then
+ echo "$as_me:1910: result: $ETAGS" >&5
+echo "${ECHO_T}$ETAGS" >&6
+else
+ echo "$as_me:1913: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ETAGS" && break
+done
+
+# Extract the first word of "${CTAGS:-ctags}", so it can be a program name with args.
+set dummy ${CTAGS:-ctags}; ac_word=$2
+echo "$as_me:1922: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_MAKE_LOWER_TAGS+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$MAKE_LOWER_TAGS"; then
+ ac_cv_prog_MAKE_LOWER_TAGS="$MAKE_LOWER_TAGS" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_MAKE_LOWER_TAGS="yes"
+echo "$as_me:1937: found $ac_dir/$ac_word" >&5
+break
+done
+
+ test -z "$ac_cv_prog_MAKE_LOWER_TAGS" && ac_cv_prog_MAKE_LOWER_TAGS="no"
+fi
+fi
+MAKE_LOWER_TAGS=$ac_cv_prog_MAKE_LOWER_TAGS
+if test -n "$MAKE_LOWER_TAGS"; then
+ echo "$as_me:1946: result: $MAKE_LOWER_TAGS" >&5
+echo "${ECHO_T}$MAKE_LOWER_TAGS" >&6
+else
+ echo "$as_me:1949: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if test "$cf_cv_mixedcase" = yes ; then
+ # Extract the first word of "${ETAGS:-etags}", so it can be a program name with args.
+set dummy ${ETAGS:-etags}; ac_word=$2
+echo "$as_me:1956: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_MAKE_UPPER_TAGS+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$MAKE_UPPER_TAGS"; then
+ ac_cv_prog_MAKE_UPPER_TAGS="$MAKE_UPPER_TAGS" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_MAKE_UPPER_TAGS="yes"
+echo "$as_me:1971: found $ac_dir/$ac_word" >&5
+break
+done
+
+ test -z "$ac_cv_prog_MAKE_UPPER_TAGS" && ac_cv_prog_MAKE_UPPER_TAGS="no"
+fi
+fi
+MAKE_UPPER_TAGS=$ac_cv_prog_MAKE_UPPER_TAGS
+if test -n "$MAKE_UPPER_TAGS"; then
+ echo "$as_me:1980: result: $MAKE_UPPER_TAGS" >&5
+echo "${ECHO_T}$MAKE_UPPER_TAGS" >&6
+else
+ echo "$as_me:1983: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+else
+ MAKE_UPPER_TAGS=no
+fi
+
+if test "$MAKE_UPPER_TAGS" = yes ; then
+ MAKE_UPPER_TAGS=
+else
+ MAKE_UPPER_TAGS="#"
+fi
+
+if test "$MAKE_LOWER_TAGS" = yes ; then
+ MAKE_LOWER_TAGS=
+else
+ MAKE_LOWER_TAGS="#"
+fi
+
+# This should have been defined by AC_PROG_CC
+: ${CC:=cc}
+
+# Check for user's environment-breakage by stuffing CFLAGS/CPPFLAGS content
+# into CC. This will not help with broken scripts that wrap the compiler with
+# options, but eliminates a more common category of user confusion.
+echo "$as_me:2009: checking \$CC variable" >&5
+echo $ECHO_N "checking \$CC variable... $ECHO_C" >&6
+case "$CC" in #(vi
+*[\ \ ]-[IUD]*)
+ echo "$as_me:2013: result: broken" >&5
+echo "${ECHO_T}broken" >&6
+ { echo "$as_me:2015: WARNING: your environment misuses the CC variable to hold CFLAGS/CPPFLAGS options" >&5
+echo "$as_me: WARNING: your environment misuses the CC variable to hold CFLAGS/CPPFLAGS options" >&2;}
+ # humor him...
+ cf_flags=`echo "$CC" | sed -e 's/^[^ ]*[ ]//'`
+ CC=`echo "$CC" | sed -e 's/[ ].*//'`
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $cf_flags
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+ ;;
+*)
+ echo "$as_me:2101: result: ok" >&5
+echo "${ECHO_T}ok" >&6
+ ;;
+esac
+
+echo "$as_me:2106: checking for ${CC:-cc} option to accept ANSI C" >&5
+echo $ECHO_N "checking for ${CC:-cc} option to accept ANSI C... $ECHO_C" >&6
+if test "${cf_cv_ansi_cc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cf_cv_ansi_cc=no
+cf_save_CFLAGS="$CFLAGS"
+cf_save_CPPFLAGS="$CPPFLAGS"
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX -Aa -D_HPUX_SOURCE
+# SVR4 -Xc
+# UnixWare 1.2 (cannot use -Xc, since ANSI/POSIX clashes)
+for cf_arg in "-DCC_HAS_PROTOS" \
+ "" \
+ -qlanglvl=ansi \
+ -std1 \
+ -Ae \
+ "-Aa -D_HPUX_SOURCE" \
+ -Xc
+do
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $cf_arg
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line 2210 "configure"
+#include "confdefs.h"
+
+#ifndef CC_HAS_PROTOS
+#if !defined(__STDC__) || (__STDC__ != 1)
+choke me
+#endif
+#endif
+
+int
+main ()
+{
+
+ int test (int i, double x);
+ struct s1 {int (*f) (int a);};
+ struct s2 {int (*f) (double a);};
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:2231: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:2234: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:2237: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:2240: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_ansi_cc="$cf_arg"; break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+CFLAGS="$cf_save_CFLAGS"
+CPPFLAGS="$cf_save_CPPFLAGS"
+
+fi
+echo "$as_me:2253: result: $cf_cv_ansi_cc" >&5
+echo "${ECHO_T}$cf_cv_ansi_cc" >&6
+
+if test "$cf_cv_ansi_cc" != "no"; then
+if test ".$cf_cv_ansi_cc" != ".-DCC_HAS_PROTOS"; then
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $cf_cv_ansi_cc
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+else
+ cat >>confdefs.h <<\EOF
+#define CC_HAS_PROTOS 1
+EOF
+
+fi
+fi
+
+if test "$cf_cv_ansi_cc" = "no"; then
+ { { echo "$as_me:2346: error: Your compiler does not appear to recognize prototypes.
+You have the following choices:
+ a. adjust your compiler options
+ b. get an up-to-date compiler
+ c. use a wrapper such as unproto" >&5
+echo "$as_me: error: Your compiler does not appear to recognize prototypes.
+You have the following choices:
+ a. adjust your compiler options
+ b. get an up-to-date compiler
+ c. use a wrapper such as unproto" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+echo "$as_me:2359: checking if you want to see long compiling messages" >&5
+echo $ECHO_N "checking if you want to see long compiling messages... $ECHO_C" >&6
+
+# Check whether --enable-echo or --disable-echo was given.
+if test "${enable_echo+set}" = set; then
+ enableval="$enable_echo"
+ test "$enableval" != no && enableval=yes
+ if test "$enableval" != "yes" ; then
+
+ ECHO_LT='--silent'
+ ECHO_LD='@echo linking $@;'
+ RULE_CC='@echo compiling $<'
+ SHOW_CC='@echo compiling $@'
+ ECHO_CC='@'
+
+ else
+
+ ECHO_LT=''
+ ECHO_LD=''
+ RULE_CC=''
+ SHOW_CC=''
+ ECHO_CC=''
+
+ fi
+else
+ enableval=yes
+
+ ECHO_LT=''
+ ECHO_LD=''
+ RULE_CC=''
+ SHOW_CC=''
+ ECHO_CC=''
+
+fi;
+echo "$as_me:2393: result: $enableval" >&5
+echo "${ECHO_T}$enableval" >&6
+
+# Make sure we can run config.sub.
+$ac_config_sub sun4 >/dev/null 2>&1 ||
+ { { echo "$as_me:2398: error: cannot run $ac_config_sub" >&5
+echo "$as_me: error: cannot run $ac_config_sub" >&2;}
+ { (exit 1); exit 1; }; }
+
+echo "$as_me:2402: checking build system type" >&5
+echo $ECHO_N "checking build system type... $ECHO_C" >&6
+if test "${ac_cv_build+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_build_alias=$build_alias
+test -z "$ac_cv_build_alias" &&
+ ac_cv_build_alias=`$ac_config_guess`
+test -z "$ac_cv_build_alias" &&
+ { { echo "$as_me:2411: error: cannot guess build type; you must specify one" >&5
+echo "$as_me: error: cannot guess build type; you must specify one" >&2;}
+ { (exit 1); exit 1; }; }
+ac_cv_build=`$ac_config_sub $ac_cv_build_alias` ||
+ { { echo "$as_me:2415: error: $ac_config_sub $ac_cv_build_alias failed." >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_build_alias failed." >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:2420: result: $ac_cv_build" >&5
+echo "${ECHO_T}$ac_cv_build" >&6
+build=$ac_cv_build
+build_cpu=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $ac_cv_build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+if test -f $srcdir/config.guess || test -f $ac_aux_dir/config.guess ; then
+ echo "$as_me:2428: checking host system type" >&5
+echo $ECHO_N "checking host system type... $ECHO_C" >&6
+if test "${ac_cv_host+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_host_alias=$host_alias
+test -z "$ac_cv_host_alias" &&
+ ac_cv_host_alias=$ac_cv_build_alias
+ac_cv_host=`$ac_config_sub $ac_cv_host_alias` ||
+ { { echo "$as_me:2437: error: $ac_config_sub $ac_cv_host_alias failed" >&5
+echo "$as_me: error: $ac_config_sub $ac_cv_host_alias failed" >&2;}
+ { (exit 1); exit 1; }; }
+
+fi
+echo "$as_me:2442: result: $ac_cv_host" >&5
+echo "${ECHO_T}$ac_cv_host" >&6
+host=$ac_cv_host
+host_cpu=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $ac_cv_host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+
+ system_name="$host_os"
+else
+ system_name="`(uname -s -r) 2>/dev/null`"
+ if test -z "$system_name" ; then
+ system_name="`(hostname) 2>/dev/null`"
+ fi
+fi
+test -n "$system_name" && cat >>confdefs.h <<EOF
+#define SYSTEM_NAME "$system_name"
+EOF
+
+if test "${cf_cv_system_name+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cf_cv_system_name="$system_name"
+fi
+
+test -z "$system_name" && system_name="$cf_cv_system_name"
+test -n "$cf_cv_system_name" && echo "$as_me:2467: result: Configuring for $cf_cv_system_name" >&5
+echo "${ECHO_T}Configuring for $cf_cv_system_name" >&6
+
+if test ".$system_name" != ".$cf_cv_system_name" ; then
+ echo "$as_me:2471: result: Cached system name ($system_name) does not agree with actual ($cf_cv_system_name)" >&5
+echo "${ECHO_T}Cached system name ($system_name) does not agree with actual ($cf_cv_system_name)" >&6
+ { { echo "$as_me:2473: error: \"Please remove config.cache and try again.\"" >&5
+echo "$as_me: error: \"Please remove config.cache and try again.\"" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+case $cf_cv_system_name in
+os2*)
+ CFLAGS="$CFLAGS -Zmt"
+ CPPFLAGS="$CPPFLAGS -D__ST_MT_ERRNO__"
+ CXXFLAGS="$CXXFLAGS -Zmt"
+ # autoconf's macro sets -Zexe and suffix both, which conflict:w
+ LDFLAGS="$LDFLAGS -Zmt -Zcrtdll"
+ ac_cv_exeext=.exe
+ ;;
+esac
+
+PROG_EXT="$EXEEXT"
+
+test -n "$PROG_EXT" && cat >>confdefs.h <<EOF
+#define PROG_EXT "$PROG_EXT"
+EOF
+
+echo "$as_me:2495: checking for install-prefix" >&5
+echo $ECHO_N "checking for install-prefix... $ECHO_C" >&6
+
+# Check whether --with-install-prefix or --without-install-prefix was given.
+if test "${with_install_prefix+set}" = set; then
+ withval="$with_install_prefix"
+ cf_opt_with_install_prefix=$withval
+else
+ cf_opt_with_install_prefix=${DESTDIR:-no}
+fi;
+echo "$as_me:2505: result: $cf_opt_with_install_prefix" >&5
+echo "${ECHO_T}$cf_opt_with_install_prefix" >&6
+if test "$cf_opt_with_install_prefix" != no ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_opt_with_install_prefix" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_opt_with_install_prefix="$cf_opt_with_install_prefix"
+ case ".$cf_opt_with_install_prefix" in #(vi
+ .NONE/*)
+ cf_opt_with_install_prefix=`echo $cf_opt_with_install_prefix | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_opt_with_install_prefix=`echo $cf_opt_with_install_prefix | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ { { echo "$as_me:2534: error: expected a pathname, not \"$cf_opt_with_install_prefix\"" >&5
+echo "$as_me: error: expected a pathname, not \"$cf_opt_with_install_prefix\"" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
+esac
+
+ DESTDIR=$cf_opt_with_install_prefix
+fi
+
+with_full_paths=no
+
+ case $cf_cv_system_name in
+ os2*) PATH_SEPARATOR=';' ;;
+ *) PATH_SEPARATOR=':' ;;
+ esac
+
+test -z "$BZCAT" && BZCAT=bzcat
+for ac_prog in $BZCAT bzcat
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:2555: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_BZCAT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $BZCAT in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_BZCAT="$BZCAT" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_BZCAT="$ac_dir/$ac_word"
+ echo "$as_me:2572: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+BZCAT=$ac_cv_path_BZCAT
+
+if test -n "$BZCAT"; then
+ echo "$as_me:2583: result: $BZCAT" >&5
+echo "${ECHO_T}$BZCAT" >&6
+else
+ echo "$as_me:2586: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$BZCAT" && break
+done
+test -n "$BZCAT" || BZCAT="$BZCAT"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_BZCAT
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:2645: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define BZCAT_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define BZCAT_ARGS "$cf_path_args"
+EOF
+
+fi
+
+test -z "$BZIP2" && BZIP2=bzip2
+for ac_prog in $BZIP2 bzip2
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:2662: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_BZIP2+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $BZIP2 in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_BZIP2="$BZIP2" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_BZIP2="$ac_dir/$ac_word"
+ echo "$as_me:2679: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+BZIP2=$ac_cv_path_BZIP2
+
+if test -n "$BZIP2"; then
+ echo "$as_me:2690: result: $BZIP2" >&5
+echo "${ECHO_T}$BZIP2" >&6
+else
+ echo "$as_me:2693: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$BZIP2" && break
+done
+test -n "$BZIP2" || BZIP2="$BZIP2"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_BZIP2
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:2752: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define BZIP2_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define BZIP2_ARGS "$cf_path_args"
+EOF
+
+fi
+
+test -z "$COMPRESS" && COMPRESS=compress
+for ac_prog in $COMPRESS compress gzip
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:2769: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_COMPRESS+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $COMPRESS in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_COMPRESS="$COMPRESS" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_COMPRESS="$ac_dir/$ac_word"
+ echo "$as_me:2786: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+COMPRESS=$ac_cv_path_COMPRESS
+
+if test -n "$COMPRESS"; then
+ echo "$as_me:2797: result: $COMPRESS" >&5
+echo "${ECHO_T}$COMPRESS" >&6
+else
+ echo "$as_me:2800: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$COMPRESS" && break
+done
+test -n "$COMPRESS" || COMPRESS="$COMPRESS"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_COMPRESS
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:2859: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define COMPRESS_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define COMPRESS_ARGS "$cf_path_args"
+EOF
+
+fi
+
+test -z "$GZIP" && GZIP=gzip
+for ac_prog in $GZIP gzip
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:2876: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_GZIP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $GZIP in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_GZIP="$GZIP" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_GZIP="$ac_dir/$ac_word"
+ echo "$as_me:2893: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+GZIP=$ac_cv_path_GZIP
+
+if test -n "$GZIP"; then
+ echo "$as_me:2904: result: $GZIP" >&5
+echo "${ECHO_T}$GZIP" >&6
+else
+ echo "$as_me:2907: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$GZIP" && break
+done
+test -n "$GZIP" || GZIP="$GZIP"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_GZIP
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:2966: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define GZIP_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define GZIP_ARGS "$cf_path_args"
+EOF
+
+fi
+
+test -z "$LZCAT" && LZCAT=lzcat
+for ac_prog in $LZCAT lzcat xz
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:2983: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_LZCAT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $LZCAT in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_LZCAT="$LZCAT" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_LZCAT="$ac_dir/$ac_word"
+ echo "$as_me:3000: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+LZCAT=$ac_cv_path_LZCAT
+
+if test -n "$LZCAT"; then
+ echo "$as_me:3011: result: $LZCAT" >&5
+echo "${ECHO_T}$LZCAT" >&6
+else
+ echo "$as_me:3014: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$LZCAT" && break
+done
+test -n "$LZCAT" || LZCAT="$LZCAT"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_LZCAT
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:3073: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define LZCAT_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define LZCAT_ARGS "$cf_path_args"
+EOF
+
+fi
+
+test -z "$PCAT" && PCAT=pcat
+for ac_prog in $PCAT pcat
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:3090: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PCAT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PCAT in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PCAT="$PCAT" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_PCAT="$ac_dir/$ac_word"
+ echo "$as_me:3107: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+PCAT=$ac_cv_path_PCAT
+
+if test -n "$PCAT"; then
+ echo "$as_me:3118: result: $PCAT" >&5
+echo "${ECHO_T}$PCAT" >&6
+else
+ echo "$as_me:3121: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$PCAT" && break
+done
+test -n "$PCAT" || PCAT="$PCAT"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_PCAT
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:3180: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define PCAT_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define PCAT_ARGS "$cf_path_args"
+EOF
+
+fi
+
+test -z "$UNCOMPRESS" && UNCOMPRESS=uncompress.real
+for ac_prog in $UNCOMPRESS uncompress.real uncompress
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:3197: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_UNCOMPRESS+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $UNCOMPRESS in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_UNCOMPRESS="$UNCOMPRESS" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_UNCOMPRESS="$ac_dir/$ac_word"
+ echo "$as_me:3214: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+UNCOMPRESS=$ac_cv_path_UNCOMPRESS
+
+if test -n "$UNCOMPRESS"; then
+ echo "$as_me:3225: result: $UNCOMPRESS" >&5
+echo "${ECHO_T}$UNCOMPRESS" >&6
+else
+ echo "$as_me:3228: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$UNCOMPRESS" && break
+done
+test -n "$UNCOMPRESS" || UNCOMPRESS="$UNCOMPRESS"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_UNCOMPRESS
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:3287: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define UNCOMPRESS_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define UNCOMPRESS_ARGS "$cf_path_args"
+EOF
+
+fi
+
+test -z "$XZ" && XZ=xz
+for ac_prog in $XZ xz lzcat
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:3304: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_XZ+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $XZ in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_XZ="$XZ" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_XZ="$ac_dir/$ac_word"
+ echo "$as_me:3321: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+XZ=$ac_cv_path_XZ
+
+if test -n "$XZ"; then
+ echo "$as_me:3332: result: $XZ" >&5
+echo "${ECHO_T}$XZ" >&6
+else
+ echo "$as_me:3335: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$XZ" && break
+done
+test -n "$XZ" || XZ="$XZ"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_XZ
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:3394: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define XZ_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define XZ_ARGS "$cf_path_args"
+EOF
+
+fi
+
+test -z "$ZCAT" && ZCAT=zcat
+for ac_prog in $ZCAT zcat
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:3411: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_ZCAT+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $ZCAT in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ZCAT="$ZCAT" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_ZCAT="$ac_dir/$ac_word"
+ echo "$as_me:3428: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ ;;
+esac
+fi
+ZCAT=$ac_cv_path_ZCAT
+
+if test -n "$ZCAT"; then
+ echo "$as_me:3439: result: $ZCAT" >&5
+echo "${ECHO_T}$ZCAT" >&6
+else
+ echo "$as_me:3442: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ZCAT" && break
+done
+test -n "$ZCAT" || ZCAT="$ZCAT"
+
+cf_path_prog=""
+cf_path_args=""
+IFS="${IFS:- }"; cf_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR"
+for cf_temp in $ac_cv_path_ZCAT
+do
+ if test -z "$cf_path_prog" ; then
+ if test "$with_full_paths" = yes ; then
+
+if test "x$prefix" != xNONE; then
+ cf_path_syntax="$prefix"
+else
+ cf_path_syntax="$ac_default_prefix"
+fi
+
+case ".$cf_temp" in #(vi
+.\$\(*\)*|.\'*\'*) #(vi
+ ;;
+..|./*|.\\*) #(vi
+ ;;
+.[a-zA-Z]:[\\/]*) #(vi OS/2 EMX
+ ;;
+.\${*prefix}*) #(vi
+ eval cf_temp="$cf_temp"
+ case ".$cf_temp" in #(vi
+ .NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+ esac
+ ;; #(vi
+.no|.NONE/*)
+ cf_temp=`echo $cf_temp | sed -e s%NONE%$cf_path_syntax%`
+ ;;
+*)
+ break
+ ;;
+esac
+
+ cf_path_prog="$cf_temp"
+ else
+ cf_path_prog="`basename $cf_temp`"
+ fi
+ elif test -z "$cf_path_args" ; then
+ cf_path_args="$cf_temp"
+ else
+ cf_path_args="$cf_path_args $cf_temp"
+ fi
+done
+IFS="$cf_save_ifs"
+
+if test -n "$cf_path_prog" ; then
+
+echo "${as_me:-configure}:3501: testing defining path for ${cf_path_prog} ..." 1>&5
+
+ cat >>confdefs.h <<EOF
+#define ZCAT_PATH "$cf_path_prog"
+EOF
+
+ test -n "$cf_path_args" && cat >>confdefs.h <<EOF
+#define ZCAT_ARGS "$cf_path_args"
+EOF
+
+fi
+
+cf_XOPEN_SOURCE=500
+cf_POSIX_C_SOURCE=199506L
+cf_xopen_source=
+
+case $host_os in #(vi
+aix[4-7]*) #(vi
+ cf_xopen_source="-D_ALL_SOURCE"
+ ;;
+cygwin) #(vi
+ cf_XOPEN_SOURCE=600
+ ;;
+darwin[0-8].*) #(vi
+ cf_xopen_source="-D_APPLE_C_SOURCE"
+ ;;
+darwin*) #(vi
+ cf_xopen_source="-D_DARWIN_C_SOURCE"
+ ;;
+freebsd*|dragonfly*) #(vi
+ # 5.x headers associate
+ # _XOPEN_SOURCE=600 with _POSIX_C_SOURCE=200112L
+ # _XOPEN_SOURCE=500 with _POSIX_C_SOURCE=199506L
+ cf_POSIX_C_SOURCE=200112L
+ cf_XOPEN_SOURCE=600
+ cf_xopen_source="-D_BSD_TYPES -D__BSD_VISIBLE -D_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE -D_XOPEN_SOURCE=$cf_XOPEN_SOURCE"
+ ;;
+hpux11*) #(vi
+ cf_xopen_source="-D_HPUX_SOURCE -D_XOPEN_SOURCE=500"
+ ;;
+hpux*) #(vi
+ cf_xopen_source="-D_HPUX_SOURCE"
+ ;;
+irix[56].*) #(vi
+ cf_xopen_source="-D_SGI_SOURCE"
+ cf_XOPEN_SOURCE=
+ ;;
+linux*|gnu*|mint*|k*bsd*-gnu) #(vi
+
+echo "$as_me:3550: checking if we must define _GNU_SOURCE" >&5
+echo $ECHO_N "checking if we must define _GNU_SOURCE... $ECHO_C" >&6
+if test "${cf_cv_gnu_source+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cat >conftest.$ac_ext <<_ACEOF
+#line 3557 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int
+main ()
+{
+
+#ifndef _XOPEN_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:3572: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:3575: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:3578: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:3581: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_gnu_source=no
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_save="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+ cat >conftest.$ac_ext <<_ACEOF
+#line 3590 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int
+main ()
+{
+
+#ifdef _XOPEN_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:3605: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:3608: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:3611: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:3614: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_gnu_source=no
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_cv_gnu_source=yes
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ CPPFLAGS="$cf_save"
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:3629: result: $cf_cv_gnu_source" >&5
+echo "${ECHO_T}$cf_cv_gnu_source" >&6
+test "$cf_cv_gnu_source" = yes && CPPFLAGS="$CPPFLAGS -D_GNU_SOURCE"
+
+ ;;
+mirbsd*) #(vi
+ # setting _XOPEN_SOURCE or _POSIX_SOURCE breaks <sys/select.h> and other headers which use u_int / u_short types
+ cf_XOPEN_SOURCE=
+
+cf_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE
+
+cf_save_CFLAGS="$CFLAGS"
+cf_save_CPPFLAGS="$CPPFLAGS"
+
+cf_trim_CFLAGS=`echo "$cf_save_CFLAGS" | \
+ sed -e 's/-[UD]'"_POSIX_C_SOURCE"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"_POSIX_C_SOURCE"'\(=[^ ]*\)\?$//g'`
+
+cf_trim_CPPFLAGS=`echo "$cf_save_CPPFLAGS" | \
+ sed -e 's/-[UD]'"_POSIX_C_SOURCE"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"_POSIX_C_SOURCE"'\(=[^ ]*\)\?$//g'`
+
+echo "$as_me:3651: checking if we should define _POSIX_C_SOURCE" >&5
+echo $ECHO_N "checking if we should define _POSIX_C_SOURCE... $ECHO_C" >&6
+if test "${cf_cv_posix_c_source+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+echo "${as_me:-configure}:3657: testing if the symbol is already defined go no further ..." 1>&5
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line 3660 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int
+main ()
+{
+
+#ifndef _POSIX_C_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:3675: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:3678: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:3681: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:3684: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_posix_c_source=no
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_want_posix_source=no
+ case .$cf_POSIX_C_SOURCE in #(vi
+ .[12]??*) #(vi
+ cf_cv_posix_c_source="-D_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE"
+ ;;
+ .2) #(vi
+ cf_cv_posix_c_source="-D_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE"
+ cf_want_posix_source=yes
+ ;;
+ .*)
+ cf_want_posix_source=yes
+ ;;
+ esac
+ if test "$cf_want_posix_source" = yes ; then
+ cat >conftest.$ac_ext <<_ACEOF
+#line 3705 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int
+main ()
+{
+
+#ifdef _POSIX_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:3720: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:3723: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:3726: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:3729: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_cv_posix_c_source="$cf_cv_posix_c_source -D_POSIX_SOURCE"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ fi
+
+echo "${as_me:-configure}:3740: testing ifdef from value $cf_POSIX_C_SOURCE ..." 1>&5
+
+ CFLAGS="$cf_trim_CFLAGS"
+ CPPFLAGS="$cf_trim_CPPFLAGS $cf_cv_posix_c_source"
+
+echo "${as_me:-configure}:3745: testing if the second compile does not leave our definition intact error ..." 1>&5
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line 3748 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int
+main ()
+{
+
+#ifndef _POSIX_C_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:3763: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:3766: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:3769: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:3772: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_cv_posix_c_source=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$cf_save_CFLAGS"
+ CPPFLAGS="$cf_save_CPPFLAGS"
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:3788: result: $cf_cv_posix_c_source" >&5
+echo "${ECHO_T}$cf_cv_posix_c_source" >&6
+
+if test "$cf_cv_posix_c_source" != no ; then
+ CFLAGS="$cf_trim_CFLAGS"
+ CPPFLAGS="$cf_trim_CPPFLAGS"
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $cf_cv_posix_c_source
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+fi
+
+ ;;
+netbsd*) #(vi
+ cf_xopen_source="-D_NETBSD_SOURCE" # setting _XOPEN_SOURCE breaks IPv6 for lynx on NetBSD 1.6, breaks xterm, is not needed for ncursesw
+ ;;
+openbsd[4-9]*) #(vi
+ # setting _XOPEN_SOURCE lower than 500 breaks g++ compile with wchar.h, needed for ncursesw
+ cf_XOPEN_SOURCE=600
+ ;;
+openbsd*) #(vi
+ # setting _XOPEN_SOURCE breaks xterm on OpenBSD 2.8, is not needed for ncursesw
+ ;;
+osf[45]*) #(vi
+ cf_xopen_source="-D_OSF_SOURCE"
+ ;;
+nto-qnx*) #(vi
+ cf_xopen_source="-D_QNX_SOURCE"
+ ;;
+sco*) #(vi
+ # setting _XOPEN_SOURCE breaks Lynx on SCO Unix / OpenServer
+ ;;
+solaris2.*) #(vi
+ cf_xopen_source="-D__EXTENSIONS__"
+ ;;
+*)
+
+echo "$as_me:3900: checking if we should define _XOPEN_SOURCE" >&5
+echo $ECHO_N "checking if we should define _XOPEN_SOURCE... $ECHO_C" >&6
+if test "${cf_cv_xopen_source+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line 3907 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+int
+main ()
+{
+
+#ifndef _XOPEN_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:3926: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:3929: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:3932: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:3935: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_xopen_source=no
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_save="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=$cf_XOPEN_SOURCE"
+ cat >conftest.$ac_ext <<_ACEOF
+#line 3944 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+int
+main ()
+{
+
+#ifdef _XOPEN_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:3963: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:3966: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:3969: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:3972: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_xopen_source=no
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_cv_xopen_source=$cf_XOPEN_SOURCE
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ CPPFLAGS="$cf_save"
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:3987: result: $cf_cv_xopen_source" >&5
+echo "${ECHO_T}$cf_cv_xopen_source" >&6
+
+if test "$cf_cv_xopen_source" != no ; then
+
+CFLAGS=`echo "$CFLAGS" | \
+ sed -e 's/-[UD]'"_XOPEN_SOURCE"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"_XOPEN_SOURCE"'\(=[^ ]*\)\?$//g'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"_XOPEN_SOURCE"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"_XOPEN_SOURCE"'\(=[^ ]*\)\?$//g'`
+
+ cf_temp_xopen_source="-D_XOPEN_SOURCE=$cf_cv_xopen_source"
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $cf_temp_xopen_source
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+fi
+
+cf_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE
+
+cf_save_CFLAGS="$CFLAGS"
+cf_save_CPPFLAGS="$CPPFLAGS"
+
+cf_trim_CFLAGS=`echo "$cf_save_CFLAGS" | \
+ sed -e 's/-[UD]'"_POSIX_C_SOURCE"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"_POSIX_C_SOURCE"'\(=[^ ]*\)\?$//g'`
+
+cf_trim_CPPFLAGS=`echo "$cf_save_CPPFLAGS" | \
+ sed -e 's/-[UD]'"_POSIX_C_SOURCE"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"_POSIX_C_SOURCE"'\(=[^ ]*\)\?$//g'`
+
+echo "$as_me:4095: checking if we should define _POSIX_C_SOURCE" >&5
+echo $ECHO_N "checking if we should define _POSIX_C_SOURCE... $ECHO_C" >&6
+if test "${cf_cv_posix_c_source+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+echo "${as_me:-configure}:4101: testing if the symbol is already defined go no further ..." 1>&5
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line 4104 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int
+main ()
+{
+
+#ifndef _POSIX_C_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:4119: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4122: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:4125: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:4128: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_posix_c_source=no
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_want_posix_source=no
+ case .$cf_POSIX_C_SOURCE in #(vi
+ .[12]??*) #(vi
+ cf_cv_posix_c_source="-D_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE"
+ ;;
+ .2) #(vi
+ cf_cv_posix_c_source="-D_POSIX_C_SOURCE=$cf_POSIX_C_SOURCE"
+ cf_want_posix_source=yes
+ ;;
+ .*)
+ cf_want_posix_source=yes
+ ;;
+ esac
+ if test "$cf_want_posix_source" = yes ; then
+ cat >conftest.$ac_ext <<_ACEOF
+#line 4149 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int
+main ()
+{
+
+#ifdef _POSIX_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:4164: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4167: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:4170: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:4173: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_cv_posix_c_source="$cf_cv_posix_c_source -D_POSIX_SOURCE"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ fi
+
+echo "${as_me:-configure}:4184: testing ifdef from value $cf_POSIX_C_SOURCE ..." 1>&5
+
+ CFLAGS="$cf_trim_CFLAGS"
+ CPPFLAGS="$cf_trim_CPPFLAGS $cf_cv_posix_c_source"
+
+echo "${as_me:-configure}:4189: testing if the second compile does not leave our definition intact error ..." 1>&5
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line 4192 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+int
+main ()
+{
+
+#ifndef _POSIX_C_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:4207: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4210: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:4213: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:4216: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_cv_posix_c_source=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$cf_save_CFLAGS"
+ CPPFLAGS="$cf_save_CPPFLAGS"
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:4232: result: $cf_cv_posix_c_source" >&5
+echo "${ECHO_T}$cf_cv_posix_c_source" >&6
+
+if test "$cf_cv_posix_c_source" != no ; then
+ CFLAGS="$cf_trim_CFLAGS"
+ CPPFLAGS="$cf_trim_CPPFLAGS"
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $cf_cv_posix_c_source
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+fi
+
+ ;;
+esac
+
+if test -n "$cf_xopen_source" ; then
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $cf_xopen_source
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+fi
+
+if test -n "$cf_XOPEN_SOURCE" && test -z "$cf_cv_xopen_source" ; then
+ echo "$as_me:4405: checking if _XOPEN_SOURCE really is set" >&5
+echo $ECHO_N "checking if _XOPEN_SOURCE really is set... $ECHO_C" >&6
+ cat >conftest.$ac_ext <<_ACEOF
+#line 4408 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+int
+main ()
+{
+
+#ifndef _XOPEN_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:4423: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4426: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:4429: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:4432: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_XOPEN_SOURCE_set=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_XOPEN_SOURCE_set=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ echo "$as_me:4441: result: $cf_XOPEN_SOURCE_set" >&5
+echo "${ECHO_T}$cf_XOPEN_SOURCE_set" >&6
+ if test $cf_XOPEN_SOURCE_set = yes
+ then
+ cat >conftest.$ac_ext <<_ACEOF
+#line 4446 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+int
+main ()
+{
+
+#if (_XOPEN_SOURCE - 0) < $cf_XOPEN_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:4461: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4464: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:4467: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:4470: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_XOPEN_SOURCE_set_ok=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_XOPEN_SOURCE_set_ok=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ if test $cf_XOPEN_SOURCE_set_ok = no
+ then
+ { echo "$as_me:4481: WARNING: _XOPEN_SOURCE is lower than requested" >&5
+echo "$as_me: WARNING: _XOPEN_SOURCE is lower than requested" >&2;}
+ fi
+ else
+
+echo "$as_me:4486: checking if we should define _XOPEN_SOURCE" >&5
+echo $ECHO_N "checking if we should define _XOPEN_SOURCE... $ECHO_C" >&6
+if test "${cf_cv_xopen_source+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line 4493 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+int
+main ()
+{
+
+#ifndef _XOPEN_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:4512: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4515: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:4518: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:4521: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_xopen_source=no
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_save="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE=$cf_XOPEN_SOURCE"
+ cat >conftest.$ac_ext <<_ACEOF
+#line 4530 "configure"
+#include "confdefs.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+
+int
+main ()
+{
+
+#ifdef _XOPEN_SOURCE
+make an error
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:4549: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4552: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:4555: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:4558: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_xopen_source=no
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_cv_xopen_source=$cf_XOPEN_SOURCE
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ CPPFLAGS="$cf_save"
+
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+
+fi
+echo "$as_me:4573: result: $cf_cv_xopen_source" >&5
+echo "${ECHO_T}$cf_cv_xopen_source" >&6
+
+if test "$cf_cv_xopen_source" != no ; then
+
+CFLAGS=`echo "$CFLAGS" | \
+ sed -e 's/-[UD]'"_XOPEN_SOURCE"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"_XOPEN_SOURCE"'\(=[^ ]*\)\?$//g'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"_XOPEN_SOURCE"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"_XOPEN_SOURCE"'\(=[^ ]*\)\?$//g'`
+
+ cf_temp_xopen_source="-D_XOPEN_SOURCE=$cf_cv_xopen_source"
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in $cf_temp_xopen_source
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+fi
+
+ fi
+fi
+
+GCC_VERSION=none
+if test "$GCC" = yes ; then
+ echo "$as_me:4673: checking version of $CC" >&5
+echo $ECHO_N "checking version of $CC... $ECHO_C" >&6
+ GCC_VERSION="`${CC} --version 2>/dev/null | sed -e '2,$d' -e 's/^.*(GCC) //' -e 's/^[^0-9.]*//' -e 's/[^0-9.].*//'`"
+ test -z "$GCC_VERSION" && GCC_VERSION=unknown
+ echo "$as_me:4677: result: $GCC_VERSION" >&5
+echo "${ECHO_T}$GCC_VERSION" >&6
+fi
+
+if ( test "$GCC" = yes || test "$GXX" = yes )
+then
+echo "$as_me:4683: checking if you want to check for gcc warnings" >&5
+echo $ECHO_N "checking if you want to check for gcc warnings... $ECHO_C" >&6
+
+# Check whether --with-warnings or --without-warnings was given.
+if test "${with_warnings+set}" = set; then
+ withval="$with_warnings"
+ cf_opt_with_warnings=$withval
+else
+ cf_opt_with_warnings=no
+fi;
+echo "$as_me:4693: result: $cf_opt_with_warnings" >&5
+echo "${ECHO_T}$cf_opt_with_warnings" >&6
+if test "$cf_opt_with_warnings" != no ; then
+
+if test "$GCC" = yes
+then
+cat > conftest.i <<EOF
+#ifndef GCC_PRINTF
+#define GCC_PRINTF 0
+#endif
+#ifndef GCC_SCANF
+#define GCC_SCANF 0
+#endif
+#ifndef GCC_NORETURN
+#define GCC_NORETURN /* nothing */
+#endif
+#ifndef GCC_UNUSED
+#define GCC_UNUSED /* nothing */
+#endif
+EOF
+if test "$GCC" = yes
+then
+ { echo "$as_me:4715: checking for $CC __attribute__ directives..." >&5
+echo "$as_me: checking for $CC __attribute__ directives..." >&6;}
+cat > conftest.$ac_ext <<EOF
+#line 4718 "${as_me:-configure}"
+#include "confdefs.h"
+#include "conftest.h"
+#include "conftest.i"
+#if GCC_PRINTF
+#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
+#else
+#define GCC_PRINTFLIKE(fmt,var) /*nothing*/
+#endif
+#if GCC_SCANF
+#define GCC_SCANFLIKE(fmt,var) __attribute__((format(scanf,fmt,var)))
+#else
+#define GCC_SCANFLIKE(fmt,var) /*nothing*/
+#endif
+extern void wow(char *,...) GCC_SCANFLIKE(1,2);
+extern void oops(char *,...) GCC_PRINTFLIKE(1,2) GCC_NORETURN;
+extern void foo(void) GCC_NORETURN;
+int main(int argc GCC_UNUSED, char *argv[] GCC_UNUSED) { return 0; }
+EOF
+ cf_printf_attribute=no
+ cf_scanf_attribute=no
+ for cf_attribute in scanf printf unused noreturn
+ do
+
+cf_ATTRIBUTE=`echo "$cf_attribute" | sed y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%`
+
+ cf_directive="__attribute__(($cf_attribute))"
+ echo "checking for $CC $cf_directive" 1>&5
+
+ case $cf_attribute in #(vi
+ printf) #(vi
+ cf_printf_attribute=yes
+ cat >conftest.h <<EOF
+#define GCC_$cf_ATTRIBUTE 1
+EOF
+ ;;
+ scanf) #(vi
+ cf_scanf_attribute=yes
+ cat >conftest.h <<EOF
+#define GCC_$cf_ATTRIBUTE 1
+EOF
+ ;;
+ *) #(vi
+ cat >conftest.h <<EOF
+#define GCC_$cf_ATTRIBUTE $cf_directive
+EOF
+ ;;
+ esac
+
+ if { (eval echo "$as_me:4767: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4770: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ test -n "$verbose" && echo "$as_me:4772: result: ... $cf_attribute" >&5
+echo "${ECHO_T}... $cf_attribute" >&6
+ cat conftest.h >>confdefs.h
+ case $cf_attribute in #(vi
+ printf) #(vi
+ if test "$cf_printf_attribute" = no ; then
+ cat >>confdefs.h <<EOF
+#define GCC_PRINTFLIKE(fmt,var) /* nothing */
+EOF
+ else
+ cat >>confdefs.h <<EOF
+#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var)))
+EOF
+ fi
+ ;;
+ scanf) #(vi
+ if test "$cf_scanf_attribute" = no ; then
+ cat >>confdefs.h <<EOF
+#define GCC_SCANFLIKE(fmt,var) /* nothing */
+EOF
+ else
+ cat >>confdefs.h <<EOF
+#define GCC_SCANFLIKE(fmt,var) __attribute__((format(scanf,fmt,var)))
+EOF
+ fi
+ ;;
+ esac
+ fi
+ done
+else
+ fgrep define conftest.i >>confdefs.h
+fi
+rm -rf conftest*
+fi
+
+INTEL_COMPILER=no
+
+if test "$GCC" = yes ; then
+ case $host_os in
+ linux*|gnu*)
+ echo "$as_me:4812: checking if this is really Intel C compiler" >&5
+echo $ECHO_N "checking if this is really Intel C compiler... $ECHO_C" >&6
+ cf_save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -no-gcc"
+ cat >conftest.$ac_ext <<_ACEOF
+#line 4817 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+#ifdef __INTEL_COMPILER
+#else
+make an error
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:4834: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4837: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:4840: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:4843: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ INTEL_COMPILER=yes
+cf_save_CFLAGS="$cf_save_CFLAGS -we147 -no-gcc"
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ CFLAGS="$cf_save_CFLAGS"
+ echo "$as_me:4854: result: $INTEL_COMPILER" >&5
+echo "${ECHO_T}$INTEL_COMPILER" >&6
+ ;;
+ esac
+fi
+
+cat > conftest.$ac_ext <<EOF
+#line 4861 "${as_me:-configure}"
+int main(int argc, char *argv[]) { return (argv[argc-1] == 0) ; }
+EOF
+
+if test "$INTEL_COMPILER" = yes
+then
+# The "-wdXXX" options suppress warnings:
+# remark #1419: external declaration in primary source file
+# remark #1683: explicit conversion of a 64-bit integral type to a smaller integral type (potential portability problem)
+# remark #1684: conversion from pointer to same-sized integral type (potential portability problem)
+# remark #193: zero used for undefined preprocessing identifier
+# remark #593: variable "curs_sb_left_arrow" was set but never used
+# remark #810: conversion from "int" to "Dimension={unsigned short}" may lose significant bits
+# remark #869: parameter "tw" was never referenced
+# remark #981: operands are evaluated in unspecified order
+# warning #279: controlling expression is constant
+
+ { echo "$as_me:4878: checking for $CC warning options..." >&5
+echo "$as_me: checking for $CC warning options..." >&6;}
+ cf_save_CFLAGS="$CFLAGS"
+ EXTRA_CFLAGS="-Wall"
+ for cf_opt in \
+ wd1419 \
+ wd1683 \
+ wd1684 \
+ wd193 \
+ wd593 \
+ wd279 \
+ wd810 \
+ wd869 \
+ wd981
+ do
+ CFLAGS="$cf_save_CFLAGS $EXTRA_CFLAGS -$cf_opt"
+ if { (eval echo "$as_me:4894: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4897: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ test -n "$verbose" && echo "$as_me:4899: result: ... -$cf_opt" >&5
+echo "${ECHO_T}... -$cf_opt" >&6
+ EXTRA_CFLAGS="$EXTRA_CFLAGS -$cf_opt"
+ fi
+ done
+ CFLAGS="$cf_save_CFLAGS"
+
+elif test "$GCC" = yes
+then
+ { echo "$as_me:4908: checking for $CC warning options..." >&5
+echo "$as_me: checking for $CC warning options..." >&6;}
+ cf_save_CFLAGS="$CFLAGS"
+ EXTRA_CFLAGS=
+ cf_warn_CONST=""
+ test "$with_ext_const" = yes && cf_warn_CONST="Wwrite-strings"
+ for cf_opt in W Wall \
+ Wbad-function-cast \
+ Wcast-align \
+ Wcast-qual \
+ Winline \
+ Wmissing-declarations \
+ Wmissing-prototypes \
+ Wnested-externs \
+ Wpointer-arith \
+ Wshadow \
+ Wstrict-prototypes \
+ Wundef $cf_warn_CONST
+ do
+ CFLAGS="$cf_save_CFLAGS $EXTRA_CFLAGS -$cf_opt"
+ if { (eval echo "$as_me:4928: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:4931: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ test -n "$verbose" && echo "$as_me:4933: result: ... -$cf_opt" >&5
+echo "${ECHO_T}... -$cf_opt" >&6
+ case $cf_opt in #(vi
+ Wcast-qual) #(vi
+ CPPFLAGS="$CPPFLAGS -DXTSTRINGDEFINES"
+ ;;
+ Winline) #(vi
+ case $GCC_VERSION in
+ [34].*)
+ test -n "$verbose" && echo " feature is broken in gcc $GCC_VERSION" 1>&6
+
+echo "${as_me:-configure}:4944: testing feature is broken in gcc $GCC_VERSION ..." 1>&5
+
+ continue;;
+ esac
+ ;;
+ esac
+ EXTRA_CFLAGS="$EXTRA_CFLAGS -$cf_opt"
+ fi
+ done
+ CFLAGS="$cf_save_CFLAGS"
+fi
+rm -rf conftest*
+
+fi
+fi
+
+echo "$as_me:4960: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+#line 4968 "configure"
+#include "confdefs.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:5017: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:5020: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:5023: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5026: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
+
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:5043: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:5046: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+echo "$as_me:5051: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5057 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:5115: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:5118: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:5121: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5124: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_const=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_c_const=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:5134: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
+if test $ac_cv_c_const = no; then
+
+cat >>confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_main_return=return
+echo "$as_me:5150: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5171 "configure"
+#include "confdefs.h"
+#include <assert.h>
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:5176: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:5182: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5205 "configure"
+#include "confdefs.h"
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:5209: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:5215: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:5252: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5262 "configure"
+#include "confdefs.h"
+#include <assert.h>
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:5267: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:5273: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5296 "configure"
+#include "confdefs.h"
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:5300: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:5306: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
+else
+ { { echo "$as_me:5334: error: C preprocessor \"$CPP\" fails sanity check" >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+ac_main_return=return
+
+echo "$as_me:5346: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5352 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+_ACEOF
+if { (eval echo "$as_me:5360: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:5366: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_cv_header_stdc=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_header_stdc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5388 "configure"
+#include "confdefs.h"
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -rf conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5406 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+rm -rf conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then
+ :
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5427 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ $ac_main_return(2);
+ $ac_main_return (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:5453: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:5456: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:5458: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5461: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_header_stdc=no
+fi
+rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:5474: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
+if test $ac_cv_header_stdc = yes; then
+
+cat >>confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_header in \
+malloc.h \
+search.h \
+string.h \
+
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:5491: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5497 "configure"
+#include "confdefs.h"
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:5501: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:5507: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:5526: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<EOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+EOF
+
+fi
+done
+
+for ac_header in unistd.h getopt.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:5539: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5545 "configure"
+#include "confdefs.h"
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:5549: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:5555: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ eval "$as_ac_Header=no"
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:5574: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<EOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+EOF
+
+fi
+done
+
+echo "$as_me:5584: checking for header declaring getopt variables" >&5
+echo $ECHO_N "checking for header declaring getopt variables... $ECHO_C" >&6
+if test "${cf_cv_getopt_header+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+cf_cv_getopt_header=none
+for cf_header in stdio.h stdlib.h unistd.h getopt.h
+do
+cat >conftest.$ac_ext <<_ACEOF
+#line 5594 "configure"
+#include "confdefs.h"
+
+#include <$cf_header>
+int
+main ()
+{
+int x = optind; char *y = optarg
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:5607: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:5610: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:5613: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5616: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_getopt_header=$cf_header
+ break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+
+fi
+echo "$as_me:5628: result: $cf_cv_getopt_header" >&5
+echo "${ECHO_T}$cf_cv_getopt_header" >&6
+if test $cf_cv_getopt_header != none ; then
+ cat >>confdefs.h <<\EOF
+#define HAVE_GETOPT_HEADER 1
+EOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:5643: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5649 "configure"
+#include "confdefs.h"
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:5655: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:5658: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:5661: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5664: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:5674: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<EOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+EOF
+
+fi
+done
+
+echo "$as_me:5684: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5690 "configure"
+#include "confdefs.h"
+$ac_includes_default
+int
+main ()
+{
+if ((size_t *) 0)
+ return 0;
+if (sizeof (size_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:5705: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:5708: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:5711: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5714: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_type_size_t=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_type_size_t=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:5724: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<EOF
+#define size_t unsigned
+EOF
+
+fi
+
+for ac_func in \
+mkdtemp \
+popen \
+tsearch \
+
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:5743: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5749 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:5780: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:5783: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:5786: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5789: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:5799: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<EOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+EOF
+
+fi
+done
+
+cf_stdio_unlocked=no
+
+for ac_func in getc_unlocked
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:5814: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5820 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+f = $ac_func;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:5851: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:5854: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:5857: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5860: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:5870: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<EOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+EOF
+ cf_stdio_unlocked=$ac_func
+fi
+done
+
+if test "$cf_stdio_unlocked" != no ; then
+ case "$CPPFLAGS" in #(vi
+ *-D_REENTRANT*) #(vi
+ ;;
+ *)
+ echo "$as_me:5885: checking if we should define _REENTRANT" >&5
+echo $ECHO_N "checking if we should define _REENTRANT... $ECHO_C" >&6
+if test "${cf_cv_stdio_unlocked+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+
+ cat >conftest.$ac_ext <<_ACEOF
+#line 5892 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int
+main ()
+{
+
+ extern void *$cf_stdio_unlocked(void *);
+ void *dummy = $cf_stdio_unlocked(0)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:5906: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:5909: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:5912: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:5915: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cf_cv_stdio_unlocked=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+cf_cv_stdio_unlocked=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:5925: result: $cf_cv_stdio_unlocked" >&5
+echo "${ECHO_T}$cf_cv_stdio_unlocked" >&6
+ if test "$cf_cv_stdio_unlocked" = yes ; then
+ cat >>confdefs.h <<\EOF
+#define _REENTRANT 1
+EOF
+
+ fi
+ ;;
+ esac
+fi
+
+echo "$as_me:5937: checking if you want to use dmalloc for testing" >&5
+echo $ECHO_N "checking if you want to use dmalloc for testing... $ECHO_C" >&6
+
+# Check whether --with-dmalloc or --without-dmalloc was given.
+if test "${with_dmalloc+set}" = set; then
+ withval="$with_dmalloc"
+ cat >>confdefs.h <<\EOF
+#define USE_DMALLOC 1
+EOF
+
+ : ${with_cflags:=-g}
+ : ${with_no_leaks:=yes}
+ with_dmalloc=yes
+else
+ with_dmalloc=
+fi;
+echo "$as_me:5953: result: ${with_dmalloc:-no}" >&5
+echo "${ECHO_T}${with_dmalloc:-no}" >&6
+
+case .$with_cflags in #(vi
+.*-g*)
+ case .$CFLAGS in #(vi
+ .*-g*) #(vi
+ ;;
+ *)
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in -g
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+ ;;
+ esac
+ ;;
+esac
+
+if test "$with_dmalloc" = yes ; then
+ echo "$as_me:6047: checking for dmalloc.h" >&5
+echo $ECHO_N "checking for dmalloc.h... $ECHO_C" >&6
+if test "${ac_cv_header_dmalloc_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 6053 "configure"
+#include "confdefs.h"
+#include <dmalloc.h>
+_ACEOF
+if { (eval echo "$as_me:6057: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:6063: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_cv_header_dmalloc_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_header_dmalloc_h=no
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:6082: result: $ac_cv_header_dmalloc_h" >&5
+echo "${ECHO_T}$ac_cv_header_dmalloc_h" >&6
+if test $ac_cv_header_dmalloc_h = yes; then
+
+echo "$as_me:6086: checking for dmalloc_debug in -ldmalloc" >&5
+echo $ECHO_N "checking for dmalloc_debug in -ldmalloc... $ECHO_C" >&6
+if test "${ac_cv_lib_dmalloc_dmalloc_debug+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldmalloc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line 6094 "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char dmalloc_debug ();
+int
+main ()
+{
+dmalloc_debug ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:6113: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:6116: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:6119: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:6122: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dmalloc_dmalloc_debug=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_dmalloc_dmalloc_debug=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:6133: result: $ac_cv_lib_dmalloc_dmalloc_debug" >&5
+echo "${ECHO_T}$ac_cv_lib_dmalloc_dmalloc_debug" >&6
+if test $ac_cv_lib_dmalloc_dmalloc_debug = yes; then
+ cat >>confdefs.h <<EOF
+#define HAVE_LIBDMALLOC 1
+EOF
+
+ LIBS="-ldmalloc $LIBS"
+
+fi
+
+fi
+
+fi
+
+echo "$as_me:6148: checking if you want to use dbmalloc for testing" >&5
+echo $ECHO_N "checking if you want to use dbmalloc for testing... $ECHO_C" >&6
+
+# Check whether --with-dbmalloc or --without-dbmalloc was given.
+if test "${with_dbmalloc+set}" = set; then
+ withval="$with_dbmalloc"
+ cat >>confdefs.h <<\EOF
+#define USE_DBMALLOC 1
+EOF
+
+ : ${with_cflags:=-g}
+ : ${with_no_leaks:=yes}
+ with_dbmalloc=yes
+else
+ with_dbmalloc=
+fi;
+echo "$as_me:6164: result: ${with_dbmalloc:-no}" >&5
+echo "${ECHO_T}${with_dbmalloc:-no}" >&6
+
+case .$with_cflags in #(vi
+.*-g*)
+ case .$CFLAGS in #(vi
+ .*-g*) #(vi
+ ;;
+ *)
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in -g
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+ ;;
+ esac
+ ;;
+esac
+
+if test "$with_dbmalloc" = yes ; then
+ echo "$as_me:6258: checking for dbmalloc.h" >&5
+echo $ECHO_N "checking for dbmalloc.h... $ECHO_C" >&6
+if test "${ac_cv_header_dbmalloc_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 6264 "configure"
+#include "confdefs.h"
+#include <dbmalloc.h>
+_ACEOF
+if { (eval echo "$as_me:6268: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:6274: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_cv_header_dbmalloc_h=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_header_dbmalloc_h=no
+fi
+rm -f conftest.err conftest.$ac_ext
+fi
+echo "$as_me:6293: result: $ac_cv_header_dbmalloc_h" >&5
+echo "${ECHO_T}$ac_cv_header_dbmalloc_h" >&6
+if test $ac_cv_header_dbmalloc_h = yes; then
+
+echo "$as_me:6297: checking for debug_malloc in -ldbmalloc" >&5
+echo $ECHO_N "checking for debug_malloc in -ldbmalloc... $ECHO_C" >&6
+if test "${ac_cv_lib_dbmalloc_debug_malloc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldbmalloc $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line 6305 "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char debug_malloc ();
+int
+main ()
+{
+debug_malloc ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:6324: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:6327: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:6330: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:6333: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dbmalloc_debug_malloc=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_dbmalloc_debug_malloc=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:6344: result: $ac_cv_lib_dbmalloc_debug_malloc" >&5
+echo "${ECHO_T}$ac_cv_lib_dbmalloc_debug_malloc" >&6
+if test $ac_cv_lib_dbmalloc_debug_malloc = yes; then
+ cat >>confdefs.h <<EOF
+#define HAVE_LIBDBMALLOC 1
+EOF
+
+ LIBS="-ldbmalloc $LIBS"
+
+fi
+
+fi
+
+fi
+
+echo "$as_me:6359: checking if you want to use valgrind for testing" >&5
+echo $ECHO_N "checking if you want to use valgrind for testing... $ECHO_C" >&6
+
+# Check whether --with-valgrind or --without-valgrind was given.
+if test "${with_valgrind+set}" = set; then
+ withval="$with_valgrind"
+ cat >>confdefs.h <<\EOF
+#define USE_VALGRIND 1
+EOF
+
+ : ${with_cflags:=-g}
+ : ${with_no_leaks:=yes}
+ with_valgrind=yes
+else
+ with_valgrind=
+fi;
+echo "$as_me:6375: result: ${with_valgrind:-no}" >&5
+echo "${ECHO_T}${with_valgrind:-no}" >&6
+
+case .$with_cflags in #(vi
+.*-g*)
+ case .$CFLAGS in #(vi
+ .*-g*) #(vi
+ ;;
+ *)
+
+cf_fix_cppflags=no
+cf_new_cflags=
+cf_new_cppflags=
+cf_new_extra_cppflags=
+
+for cf_add_cflags in -g
+do
+case $cf_fix_cppflags in
+no)
+ case $cf_add_cflags in #(vi
+ -undef|-nostdinc*|-I*|-D*|-U*|-E|-P|-C) #(vi
+ case $cf_add_cflags in
+ -D*)
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^-D[^=]*='\''\"[^"]*//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=yes
+
+ if test $cf_fix_cppflags = yes ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ elif test "${cf_tst_cflags}" = "\"'" ; then
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+ continue
+ fi
+ ;;
+ esac
+ case "$CPPFLAGS" in
+ *$cf_add_cflags) #(vi
+ ;;
+ *) #(vi
+ case $cf_add_cflags in #(vi
+ -D*)
+ cf_tst_cppflags=`echo "x$cf_add_cflags" | sed -e 's/^...//' -e 's/=.*//'`
+
+CPPFLAGS=`echo "$CPPFLAGS" | \
+ sed -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?[ ]/ /g' \
+ -e 's/-[UD]'"$cf_tst_cppflags"'\(=[^ ]*\)\?$//g'`
+
+ ;;
+ esac
+ cf_new_cppflags="$cf_new_cppflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+ *)
+ cf_new_cflags="$cf_new_cflags $cf_add_cflags"
+ ;;
+ esac
+ ;;
+yes)
+ cf_new_extra_cppflags="$cf_new_extra_cppflags $cf_add_cflags"
+
+ cf_tst_cflags=`echo ${cf_add_cflags} |sed -e 's/^[^"]*"'\''//'`
+
+ test "${cf_add_cflags}" != "${cf_tst_cflags}" \
+ && test -z "${cf_tst_cflags}" \
+ && cf_fix_cppflags=no
+ ;;
+esac
+done
+
+if test -n "$cf_new_cflags" ; then
+
+ CFLAGS="$CFLAGS $cf_new_cflags"
+fi
+
+if test -n "$cf_new_cppflags" ; then
+
+ CPPFLAGS="$CPPFLAGS $cf_new_cppflags"
+fi
+
+if test -n "$cf_new_extra_cppflags" ; then
+
+ EXTRA_CPPFLAGS="$cf_new_extra_cppflags $EXTRA_CPPFLAGS"
+fi
+
+ ;;
+ esac
+ ;;
+esac
+
+echo "$as_me:6468: checking if you want to perform memory-leak testing" >&5
+echo $ECHO_N "checking if you want to perform memory-leak testing... $ECHO_C" >&6
+
+# Check whether --enable-leaks or --disable-leaks was given.
+if test "${enable_leaks+set}" = set; then
+ enableval="$enable_leaks"
+ if test "x$enableval" = xno; then with_no_leaks=yes; else with_no_leaks=no; fi
+else
+ : ${with_no_leaks:=no}
+fi;
+echo "$as_me:6478: result: $with_no_leaks" >&5
+echo "${ECHO_T}$with_no_leaks" >&6
+
+if test "$with_no_leaks" = yes ; then
+ cat >>confdefs.h <<\EOF
+#define NO_LEAKS 1
+EOF
+
+ cat >>confdefs.h <<\EOF
+#define YY_NO_LEAKS 1
+EOF
+
+fi
+
+### output makefile and config.h
+ac_config_files="$ac_config_files makefile"
+ac_config_commands="$ac_config_commands default"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overriden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if cmp -s $cache_file confcache; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+DEFS=-DHAVE_CONFIG_H
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:6574: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+ac_cs_invocation="\$0 \$@"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Name of the executable.
+as_me=`echo "$0" |sed 's,.*[\\/],,'`
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+# NLS nuisances.
+$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; }
+$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; }
+$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; }
+$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; }
+$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; }
+$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; }
+$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; }
+$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; }
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; }
+
+exec 6>&1
+
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\EOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to <dickey@invisible-island.net>."
+EOF
+
+cat >>$CONFIG_STATUS <<EOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.52.20101002,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ shift
+ set dummy "$ac_option" "$ac_optarg" ${1+"$@"}
+ shift
+ ;;
+ -*);;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_need_defaults=false;;
+ esac
+
+ case $1 in
+ # Handling of the options.
+EOF
+cat >>$CONFIG_STATUS <<EOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion"
+ exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;;
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:6750: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ shift
+ CONFIG_FILES="$CONFIG_FILES $1"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $1"
+ ac_need_defaults=false;;
+
+ # This is an error.
+ -*) { { echo "$as_me:6769: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+exec 5>>config.log
+cat >&5 << _ACEOF
+
+## ----------------------- ##
+## Running config.status. ##
+## ----------------------- ##
+
+This file was extended by $as_me 2.52.20101002, executed with
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ > $ac_cs_invocation
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+
+_ACEOF
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "makefile" ) CONFIG_FILES="$CONFIG_FILES makefile" ;;
+ "default" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;;
+ "config.h" ) CONFIG_HEADERS="$CONFIG_HEADERS config.h:config_h.in" ;;
+ *) { { echo "$as_me:6807: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+: ${TMPDIR=/tmp}
+{
+ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=$TMPDIR/cs$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in $TMPDIR" >&2
+ { (exit 1); exit 1; }
+}
+
+EOF
+
+cat >>$CONFIG_STATUS <<EOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@DEFS@,$DEFS,;t t
+s,@LIBS@,$LIBS,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@LINT@,$LINT,;t t
+s,@LINT_OPTS@,$LINT_OPTS,;t t
+s,@CTAGS@,$CTAGS,;t t
+s,@ETAGS@,$ETAGS,;t t
+s,@MAKE_LOWER_TAGS@,$MAKE_LOWER_TAGS,;t t
+s,@MAKE_UPPER_TAGS@,$MAKE_UPPER_TAGS,;t t
+s,@EXTRA_CPPFLAGS@,$EXTRA_CPPFLAGS,;t t
+s,@ECHO_LT@,$ECHO_LT,;t t
+s,@ECHO_LD@,$ECHO_LD,;t t
+s,@RULE_CC@,$RULE_CC,;t t
+s,@SHOW_CC@,$SHOW_CC,;t t
+s,@ECHO_CC@,$ECHO_CC,;t t
+s,@build@,$build,;t t
+s,@build_cpu@,$build_cpu,;t t
+s,@build_vendor@,$build_vendor,;t t
+s,@build_os@,$build_os,;t t
+s,@host@,$host,;t t
+s,@host_cpu@,$host_cpu,;t t
+s,@host_vendor@,$host_vendor,;t t
+s,@host_os@,$host_os,;t t
+s,@PROG_EXT@,$PROG_EXT,;t t
+s,@DESTDIR@,$DESTDIR,;t t
+s,@BZCAT@,$BZCAT,;t t
+s,@BZIP2@,$BZIP2,;t t
+s,@COMPRESS@,$COMPRESS,;t t
+s,@GZIP@,$GZIP,;t t
+s,@LZCAT@,$LZCAT,;t t
+s,@PCAT@,$PCAT,;t t
+s,@UNCOMPRESS@,$UNCOMPRESS,;t t
+s,@XZ@,$XZ,;t t
+s,@ZCAT@,$ZCAT,;t t
+s,@EXTRA_CFLAGS@,$EXTRA_CFLAGS,;t t
+s,@CPP@,$CPP,;t t
+CEOF
+
+EOF
+
+ cat >>$CONFIG_STATUS <<\EOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ { case "$ac_dir" in
+ [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+ *) as_incr_dir=.;;
+esac
+as_dummy="$ac_dir"
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+ case $as_mkdir_dir in
+ # Skip DOS drivespec
+ ?:) as_incr_dir=$as_mkdir_dir ;;
+ *)
+ as_incr_dir=$as_incr_dir/$as_mkdir_dir
+ test -d "$as_incr_dir" || mkdir "$as_incr_dir"
+ ;;
+ esac
+done; }
+
+ ac_dir_suffix="/`echo $ac_dir|sed 's,^\./,,'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo "$ac_dir_suffix" | sed 's,/[^/]*,../,g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case $srcdir in
+ .) ac_srcdir=.
+ if test -z "$ac_dots"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_dots | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* )
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_dots$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_dots$srcdir ;;
+ esac
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_dots$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:7046: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated automatically by config.status. */
+ configure_input="Generated automatically from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:7064: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:7077: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+EOF
+cat >>$CONFIG_STATUS <<EOF
+ sed "$ac_vpsub
+$extrasub
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+
+#
+# CONFIG_HEADER section.
+#
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s,^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='[ ].*$,\1#\2'
+ac_dC=' '
+ac_dD=',;t'
+# ac_i turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_iA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_iB='\([ ]\),\1#\2define\3'
+ac_iC=' '
+ac_iD='\4,;t'
+# ac_u turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_uA='s,^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='$,\1#\2define\3'
+ac_uC=' '
+ac_uD=',;t'
+
+for ac_file in : $CONFIG_HEADERS; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ test x"$ac_file" != x- && { echo "$as_me:7143: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:7154: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:7167: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+ # Remove the trailing spaces.
+ sed 's/[ ]*$//' $ac_file_inputs >$tmp/in
+
+EOF
+
+# Transform confdefs.h into a list of #define's. We won't use it as a sed
+# script, but as data to insert where we see @DEFS@. We expect AC_SAVE_DEFS to
+# be either 'cat' or 'sort'.
+cat confdefs.h | uniq >conftest.vals
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+echo ' rm -f conftest.frag' >> $CONFIG_STATUS
+while grep . conftest.vals >/dev/null
+do
+ # Write chunks of a limited-size here document to conftest.frag.
+ echo ' cat >> conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals | sed -e 's/#ifdef.*/#if 0/' >> $CONFIG_STATUS
+ echo 'CEOF' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+# Run sed to substitute the contents of conftest.frag into $tmp/in at the
+# marker @DEFS@.
+echo ' cat >> conftest.edit <<CEOF
+/@DEFS@/r conftest.frag
+/@DEFS@/d
+CEOF
+sed -f conftest.edit $tmp/in > $tmp/out
+rm -f $tmp/in
+mv $tmp/out $tmp/in
+rm -f conftest.edit conftest.frag
+' >> $CONFIG_STATUS
+
+cat >>$CONFIG_STATUS <<\EOF
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated automatically by config.status. */
+ if test x"$ac_file" = x-; then
+ echo "/* Generated automatically by configure. */" >$tmp/config.h
+ else
+ echo "/* $ac_file. Generated automatically by configure. */" >$tmp/config.h
+ fi
+ cat $tmp/in >>$tmp/config.h
+ rm -f $tmp/in
+ if test x"$ac_file" != x-; then
+ if cmp -s $ac_file $tmp/config.h 2>/dev/null; then
+ { echo "$as_me:7225: $ac_file is unchanged" >&5
+echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ { case "$ac_dir" in
+ [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+ *) as_incr_dir=.;;
+esac
+as_dummy="$ac_dir"
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+ case $as_mkdir_dir in
+ # Skip DOS drivespec
+ ?:) as_incr_dir=$as_mkdir_dir ;;
+ *)
+ as_incr_dir=$as_incr_dir/$as_mkdir_dir
+ test -d "$as_incr_dir" || mkdir "$as_incr_dir"
+ ;;
+ esac
+done; }
+
+ fi
+ rm -f $ac_file
+ mv $tmp/config.h $ac_file
+ fi
+ else
+ cat $tmp/config.h
+ rm -f $tmp/config.h
+ fi
+done
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+
+{ (exit 0); exit 0; }
+EOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/patch_cmds/diffstat/configure.in b/patch_cmds/diffstat/configure.in
new file mode 100644
index 0000000..d4fd5e0
--- /dev/null
+++ b/patch_cmds/diffstat/configure.in
@@ -0,0 +1,54 @@
+dnl Process this file with 'autoconf' to produce a 'configure' script
+dnl $Id: configure.in,v 1.22 2010/07/16 09:25:15 tom Exp $
+AC_PREREQ(2.13.20020210)
+AC_REVISION($Revision: 1.22 $)
+AC_INIT(diffstat.c)
+AC_CONFIG_HEADER(config.h:config_h.in)
+
+AC_PROG_CC
+AC_PROG_INSTALL
+CF_PROG_LINT
+CF_MAKE_TAGS
+
+CF_ANSI_CC_REQD
+CF_DISABLE_ECHO
+CF_PROG_EXT
+CF_WITH_INSTALL_PREFIX
+
+with_full_paths=no
+CF_PATH_PROG(BZCAT, bzcat)
+CF_PATH_PROG(BZIP2, bzip2)
+CF_PATH_PROG(COMPRESS, compress, gzip)
+CF_PATH_PROG(GZIP, gzip)
+CF_PATH_PROG(LZCAT, lzcat, xz)
+CF_PATH_PROG(PCAT, pcat)
+CF_PATH_PROG(UNCOMPRESS, uncompress.real, uncompress)
+CF_PATH_PROG(XZ, xz, lzcat)
+CF_PATH_PROG(ZCAT, zcat)
+
+CF_XOPEN_SOURCE
+CF_WITH_WARNINGS
+
+AC_CONST
+AC_STDC_HEADERS
+AC_HAVE_HEADERS(\
+malloc.h \
+search.h \
+string.h \
+)
+CF_GETOPT_HEADER
+
+AC_TYPE_SIZE_T
+
+AC_CHECK_FUNCS(\
+mkdtemp \
+popen \
+tsearch \
+)
+
+CF_STDIO_UNLOCKED(getc_unlocked)
+
+CF_DISABLE_LEAKS
+
+### output makefile and config.h
+AC_OUTPUT(makefile,,,cat)
diff --git a/patch_cmds/diffstat/diffstat.1 b/patch_cmds/diffstat/diffstat.1
new file mode 100644
index 0000000..d7c0345
--- /dev/null
+++ b/patch_cmds/diffstat/diffstat.1
@@ -0,0 +1,235 @@
+.\"*****************************************************************************
+.\" Copyright 1994-2009,2010 by Thomas E. Dickey *
+.\" All Rights Reserved. *
+.\" *
+.\" Permission to use, copy, modify, and distribute this software and its *
+.\" documentation for any purpose and without fee is hereby granted, provided *
+.\" that the above copyright notice appear in all copies and that both that *
+.\" copyright notice and this permission notice appear in supporting *
+.\" documentation, and that the name of the above listed copyright holder(s) *
+.\" not be used in advertising or publicity pertaining to distribution of the *
+.\" software without specific, written prior permission. *
+.\" *
+.\" THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD *
+.\" TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND *
+.\" FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE *
+.\" FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR *
+.\" IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+.\"*****************************************************************************
+.\" $Id: diffstat.1,v 1.30 2012/01/02 19:20:26 tom Exp $
+.TH DIFFSTAT 1
+.SH NAME
+\fBdiffstat\fP \- make histogram from diff-output
+.SH SYNOPSIS
+\fBdiffstat\fP\fI [options] [file-specifications]\fP
+.SH DESCRIPTION
+This program reads the output of \fBdiff\fP and displays a histogram
+of the insertions, deletions, and modifications per-file.
+Diffstat is a program that is useful for reviewing large, complex patch files.
+It reads from one or more input files which contain output from \fBdiff\fP,
+producing a histogram of the total lines changed for each file referenced.
+.PP
+If the input filename ends with .bz2, .gz, .lzma, .z or .Z,
+diffstat will read the
+uncompressed data via a pipe from the corresponding program.
+It also can infer the compression type from files piped via the standard input.
+.PP
+Diffstat recognizes the most popular types of output from diff:
+.RS
+.TP
+unified
+preferred by the \fBpatch\fP utility.
+.TP
+context
+best for readability, but not very compact.
+.TP
+default
+not good for much, but simple to generate.
+.RE
+.PP
+\fBDiffstat\fP detects the lines that are output by \fBdiff\fP to
+tell which files are compared, and then counts the markers in the
+first column that denote the type of change (insertion, deletion
+or modification).
+These are shown in the histogram as "+", "\-" and "!" characters.
+.PP
+If no filename is given on the command line,
+\fBdiffstat\fP reads the differences from the standard input.
+.SH OPTIONS
+.TP
+.B \-b
+ignore lines matching "Binary files XXX and YYY differ" in the diff
+.TP
+.B \-c
+prefix each line of output with "#", making it a comment-line for shell
+scripts.
+.TP
+.B \-C
+add SGR color escape sequences to highlight the histogram.
+.TP
+.BI \-D " destination"
+specify a directory containing files which can be referred to as
+the result of applying the differences.
+\fBdiffstat\fP will count the lines in the corresponding files
+(after adjusting the names by the \fB\-p\fP option)
+to obtain the total number of lines in each file.
+.IP
+The remainder, after subtracting modified and deleted lines,
+is shown as "unchanged lines".
+.TP
+.BI \-e " file"
+redirect standard error to \fIfile\fR.
+.TP
+.BI \-f " format"
+specify the format of the histogram.
+.RS
+.TP 3
+0
+for concise, which shows only the value and a single histogram code for each of
+insert (+),
+delete (\-) or
+modify (!)
+.TP 3
+1
+for normal output,
+.TP 3
+2
+to fill in the histogram with dots,
+.TP 3
+4
+to print each value with the histogram.
+.RE
+.IP
+Any nonzero value gives a histogram.
+The dots and individual values can be combined,
+e.g., \fB\-f6\fP gives both.
+.TP
+.B \-h
+prints the usage message and exits.
+.TP
+.B \-k
+suppress the merging of filenames in the report.
+.TP
+.B \-l
+lists only the filenames.
+No histogram is generated.
+.TP
+.B \-m
+merge insert/delete counts from each "chunk" of the patch file to
+approximate a count of the modified lines.
+.TP
+.BI \-n " number"
+specify the minimum width used for filenames.
+If you do not specify this, \fBdiffstat\fP uses the length of the longest
+filename, after stripping common prefixes.
+.TP
+.BI \-N " number"
+specify the maximum width used for filenames.
+Names longer than this limit are truncated on the left.
+If you do not specify this, \fBdiffstat\fP next checks the \fB\-n\fP option.
+.TP
+.BI \-o " file"
+redirect standard output to \fIfile\fR.
+.TP
+.BI \-p " number"
+override the logic that strips common pathnames, simulating the \fBpatch\fP
+"\-p" option.
+.TP
+.B \-q
+suppress the "0 files changed" message for empty diffs.
+.TP
+.B \-r " code"
+provides optional rounding of the data shown in histogram,
+rather than truncating with error adjustments.
+.RS
+.TP 3
+0
+is the default.
+No rounding is performed,
+but accumulated errors are added to following columns.
+.TP 3
+1
+rounds the data
+.TP 3
+2
+rounds the data and adjusts the histogram to ensure that
+it displays something if there are any differences even if
+those would normally be rounded to zero.
+.RE
+.TP
+.B \-R
+Assume patch was created with old and new files swapped.
+.TP
+.BI \-s
+show only the summary line, e.g., number of insertions and deletions.
+.TP
+.BI \-S " source"
+this is like the \fB\-D\fP option, but specifies a location where
+the original files (before applying differences) can be found.
+.TP
+.B \-t
+overrides the histogram,
+generates output of comma separated values.
+.TP
+.B \-u
+suppress the sorting of filenames in the report.
+.TP
+.B \-v
+show progress,
+e.g., if the output is redirected to a file,
+write progress messages to the standard error.
+.TP
+.B \-V
+prints the current version number and exits.
+.TP
+.BI \-w " number"
+specify the maximum width of the histogram.
+The histogram will never be shorter than 10 columns,
+just in case the filenames get too large.
+.SH ENVIRONMENT
+.PP
+\fBDiffstat\fP runs in a portable UNIX\*R environment.
+.PP
+You can override the compiled-in paths of programs used for decompressing
+input files by setting environment variables corresponding to their name:
+.sp
+.RS
+.nf
+DIFFSTAT_BZCAT_PATH
+DIFFSTAT_BZIP2_PATH
+DIFFSTAT_COMPRESS_PATH
+DIFFSTAT_GZIP_PATH
+DIFFSTAT_LZCAT_PATH
+DIFFSTAT_PCAT_PATH
+DIFFSTAT_UNCOMPRESS_PATH
+DIFFSTAT_XZ_PATH
+DIFFSTAT_ZCAT_PATH
+.fi
+.RE
+.PP
+However, \fBdiffstat\fP assumes that the resulting program uses the
+same command-line options, e.g., "\-c" to decompress to the standard output.
+.SH FILES
+.PP
+\fBDiffstat\fP is a single binary module, which uses no auxiliary files.
+.SH BUGS
+.PP
+\fBDiffstat\fP makes a lot of assumptions about the format of a \fBdiff\fP file.
+.PP
+There is no way to obtain a filename from the standard diff between
+two files with no options.
+Context diffs work,
+as well as unified diffs.
+.PP
+There's no easy way to determine the degree of overlap between the
+"before" and "after" displays of modified lines.
+\fBdiffstat\fP simply counts the number of inserted and deleted lines
+to approximate modified lines for the \fB\-m\fP option.
+.SH SEE ALSO
+.PP
+.BR diff (1).
+.SH AUTHOR
+.PP
+Thomas Dickey <dickey@invisible-island.net>.
diff --git a/patch_cmds/diffstat/diffstat.c b/patch_cmds/diffstat/diffstat.c
new file mode 100644
index 0000000..7027ba3
--- /dev/null
+++ b/patch_cmds/diffstat/diffstat.c
@@ -0,0 +1,2491 @@
+/******************************************************************************
+ * Copyright 1994-2010,2012 by Thomas E. Dickey *
+ * All Rights Reserved. *
+ * *
+ * Permission to use, copy, modify, and distribute this software and its *
+ * documentation for any purpose and without fee is hereby granted, provided *
+ * that the above copyright notice appear in all copies and that both that *
+ * copyright notice and this permission notice appear in supporting *
+ * documentation, and that the name of the above listed copyright holder(s) *
+ * not be used in advertising or publicity pertaining to distribution of the *
+ * software without specific, written prior permission. *
+ * *
+ * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD *
+ * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND *
+ * FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE *
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR *
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ******************************************************************************/
+
+#ifndef NO_IDENT
+static const char *Id = "$Id: diffstat.c,v 1.55 2012/01/03 09:44:24 tom Exp $";
+#endif
+
+/*
+ * Title: diffstat.c
+ * Author: T.E.Dickey
+ * Created: 02 Feb 1992
+ * Modified:
+ * 03 Jan 2012, Correct case for "xz" suffix in is_compressed()
+ * (patch from Frederic Culot in FreeBSD ports). Add
+ * "-R" option. Improve dequoting of filenames in
+ * headers.
+ * 10 Oct 2010, correct display of new files when -S/-D options
+ * are used. Remove the temporary directory on
+ * error, introduced in 1.48+ (patch by Solar
+ * Designer).
+ * 19 Jul 2010, add missing "break" statement which left "-c"
+ * option falling-through into "-C".
+ * 16 Jul 2010, configure "xz" path explicitly, in case lzcat
+ * does not support xz format. Add "-s" (summary)
+ * and "-C" (color) options.
+ * 15 Jul 2010, fix strict gcc warnings, e.g., using const.
+ * 10 Jan 2010, improve a case where filenames have embedded blanks
+ * (patch by Reinier Post).
+ * 07 Nov 2009, correct suffix-check for ".xz" files as
+ * command-line parameters rather than as piped
+ * input (report by Moritz Barsnick).
+ * 06 Oct 2009, fixes to build/run with MSYS or MinGW. use
+ * $TMPDIR for path of temporary file used in
+ * decompression. correct else-condition for
+ * detecting compression type (patch by Zach Hirsch).
+ * 31 Aug 2009, improve lzma support, add support for xz (patch by
+ * Eric Blake). Add special case for no-newline
+ * message from some diff's (Ubuntu #269895).
+ * Improve configure check for getopt().
+ * 11 Aug 2009, Add logic to check standard input, decompress if
+ * possible. Add -N option, to truncate long names.
+ * Add pack/pcat as a compression type.
+ * Add lzma/lzcat as a compression type.
+ * Allow overriding program paths with environment.
+ * 10 Aug 2009, modify to work with Perforce-style diffs (patch
+ * by Ed Schouten).
+ * 29 Mar 2009, modify to work with patch ".rej" files, which have
+ * no filename header (use the name of the ".rej"
+ * file if it is available).
+ * 29 Sep 2008, fix typo in usage message.
+ * 06 Aug 2008, add "-m", "-S" and "-D" options.
+ * 05 Aug 2008, add "-q" option to suppress 0-files-changed
+ * message (patch by Greg Norris).
+ * 04 Sep 2007, add "-b" option to suppress binary-files (patch
+ * by Greg Norris).
+ * 26 Aug 2007, add "-d" option to show debugging traces, rather
+ * than by defining DEBUG. Add check after
+ * unified-diff chunk to avoid adding non-diff text
+ * (report by Adrian Bunk). Quote pathname passed
+ * in command to gzip/uncompress. Add a check for
+ * default-diff output without the "diff" command
+ * supplied to provide filename, mark as "unknown".
+ * 16 Jul 2006, fix to avoid modifying which is being used by
+ * tsearch() for ordering the binary tree (report by
+ * Adrian Bunk).
+ * 02 Jul 2006, do not ignore pathnames in /tmp/, since some tools
+ * create usable pathnames for both old/new files
+ * there (Debian #376086). Correct ifdef for
+ * fgetc_unlocked(). Add configure check for
+ * compress, gzip and bzip2 programs that may be used
+ * to decompress files.
+ * 24 Aug 2005, update usage message for -l, -r changes.
+ * 15 Aug 2005, apply PLURAL() to num_files (Jean Delvare).
+ * add -l option (request by Michael Burian).
+ * Use fgetc_locked() if available.
+ * 14 Aug 2005, add -r2 option (rounding with adjustment to ensure
+ * that nonzero values always display a histogram
+ * bar), adapted from patch by Jean Delvare. Extend
+ * the -f option (2=filled, 4=verbose).
+ * 12 Aug 2005, modify to use tsearch() for sorted lists.
+ * 11 Aug 2005, minor fixes to scaling of modified lines. Add
+ * -r (round) option.
+ * 05 Aug 2005, add -t (table) option.
+ * 10 Apr 2005, change order of merging and prefix-stripping so
+ * stripping all prefixes, e.g., with -p9, will be
+ * sorted as expected (Patch by Jean Delvare
+ * <khali@linux-fr.org>).
+ * 10 Jan 2005, add support for '--help' and '--version' (Patch
+ * by Eric Blake <ebb9@byu.net>.)
+ * 16 Dec 2004, fix a different case for data beginning with "--"
+ * which was treated as a header line.
+ * 14 Dec 2004, Fix allocation problems. Open files in binary
+ * mode for reading. Getopt returns -1, not
+ * necessarily EOF. Add const where useful. Use
+ * NO_IDENT where necessary. malloc() comes from
+ * <stdlib.h> in standard systems (Patch by Eric
+ * Blake <ebb9@byu.net>.)
+ * 08 Nov 2004, minor fix for resync of unified diffs checks for
+ * range (line beginning with '@' without header
+ * lines (successive lines beginning with "---" and
+ * "+++"). Fix a few problems reported by valgrind.
+ * 09 Nov 2003, modify check for lines beginning with '-' or '+'
+ * to treat only "---" in old-style diffs as a
+ * special case.
+ * 14 Feb 2003, modify check for filenames to allow for some cases
+ * of incomplete dates (the reported example omitted
+ * the day of the month). Correct a typo in usage().
+ * Add -e, -h, -o options.
+ * 04 Jan 2003, improve tracking of chunks in unified diff, in
+ * case the original files contained a '+' or '-' in
+ * the first column (Debian #155000). Add -v option
+ * (Debian #170947). Modify to allocate buffers big
+ * enough for long input lines. Do additional
+ * merging to handle unusual Index/diff constructs in
+ * recent makepatch script.
+ * 20 Aug 2002, add -u option to tell diffstat to preserve the
+ * order of filenames as given rather than sort them
+ * (request by H Peter Anvin <hpa@zytor.com>). Add
+ * -k option for completeness.
+ * 09 Aug 2002, allow either '/' or '-' as delimiters in dates,
+ * to accommodate diffutils 2.8 (report by Rik van
+ * Riel <riel@conectiva.com.br>).
+ * 10 Oct 2001, add bzip2 (.bz2) suffix as suggested by
+ * Gregory T Norris <haphazard@socket.net> in Debian
+ * bug report #82969).
+ * add check for diff from RCS archive where the
+ * "diff" lines do not reference a filename.
+ * 29 Mar 2000, add -c option. Check for compressed input, read
+ * via pipe. Change to ANSI C. Adapted change from
+ * Troy Engel to add option that displays a number
+ * only, rather than a histogram.
+ * 17 May 1998, handle Debian diff files, which do not contain
+ * dates on the header lines.
+ * 16 Jan 1998, accommodate patches w/o tabs in header lines (e.g.,
+ * from cut/paste). Strip suffixes such as ".orig".
+ * 24 Mar 1996, corrected -p0 logic, more fixes in do_merging.
+ * 16 Mar 1996, corrected state-change for "Binary". Added -p
+ * option.
+ * 17 Dec 1995, corrected matching algorithm in 'do_merging()'
+ * 11 Dec 1995, mods to accommodate diffs against /dev/null or
+ * /tmp/XXX (tempfiles).
+ * 06 May 1995, limit scaling -- only shrink-to-fit.
+ * 29 Apr 1995, recognize 'rcsdiff -u' format.
+ * 26 Dec 1994, strip common pathname-prefix.
+ * 13 Nov 1994, added '-n' option. Corrected logic of 'match'.
+ * 17 Jun 1994, ifdef-<string.h>
+ * 12 Jun 1994, recognize unified diff, and output of makepatch.
+ * 04 Oct 1993, merge multiple diff-files, busy message when the
+ * output is piped to a file.
+ *
+ * Function: this program reads the output of 'diff' and displays a histogram
+ * of the insertions/deletions/modifications per-file.
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include <config.h>
+#endif
+
+#if defined(WIN32) && !defined(HAVE_CONFIG_H)
+#define HAVE_STDLIB_H
+#define HAVE_STRING_H
+#define HAVE_MALLOC_H
+#define HAVE_GETOPT_H
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#define strchr index
+#define strrchr rindex
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+extern int atoi(const char *);
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#else
+extern int isatty(int);
+#endif
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#if defined(HAVE_SEARCH_H) && defined(HAVE_TSEARCH)
+#include <search.h>
+#else
+#undef HAVE_TSEARCH
+#endif
+
+#ifdef HAVE_GETC_UNLOCKED
+#define MY_GETC getc_unlocked
+#else
+#define MY_GETC getc
+#endif
+
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#elif !defined(HAVE_GETOPT_HEADER)
+extern int getopt(int, char *const *, const char *);
+extern char *optarg;
+extern int optind;
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if !defined(EXIT_SUCCESS)
+#define EXIT_SUCCESS 0
+#define EXIT_FAILURE 1
+#endif
+
+#ifndef BZCAT_PATH
+#define BZCAT_PATH ""
+#endif
+
+#ifndef BZIP2_PATH
+#define BZIP2_PATH ""
+#endif
+
+#ifndef COMPRESS_PATH
+#define COMPRESS_PATH ""
+#endif
+
+#ifndef GZIP_PATH
+#define GZIP_PATH ""
+#endif
+
+#ifndef LZCAT_PATH
+#define LZCAT_PATH ""
+#endif
+
+#ifndef PCAT_PATH
+#define PCAT_PATH ""
+#endif
+
+#ifndef UNCOMPRESS_PATH
+#define UNCOMPRESS_PATH ""
+#endif
+
+#ifndef XZ_PATH
+#define XZ_PATH ""
+#endif
+
+#ifndef ZCAT_PATH
+#define ZCAT_PATH ""
+#endif
+
+/******************************************************************************/
+
+#if defined(__MINGW32__) || defined(WIN32)
+#define MKDIR(name,mode) mkdir(name)
+#else
+#define MKDIR(name,mode) mkdir(name,mode)
+#endif
+
+#if defined(WIN32) && !defined(__MINGW32__)
+#define PATHSEP '\\'
+#else
+#define PATHSEP '/'
+#endif
+
+#define SQUOTE '\''
+#define EOS '\0'
+#define BLANK ' '
+
+#define UC(c) ((unsigned char)(c))
+
+#ifndef OPT_TRACE
+#define OPT_TRACE 1
+#endif
+
+#if OPT_TRACE
+#define TRACE(p) if (trace_opt) printf p
+#else
+#define TRACE(p) /*nothing */
+#endif
+
+#define contain_any(s,reject) (strcspn(s,reject) != strlen(s))
+
+#define HAVE_NOTHING 0
+#define HAVE_GENERIC 1 /* e.g., "Index: foo" w/o pathname */
+#define HAVE_PATH 2 /* reference-file from "diff dirname/foo" */
+#define HAVE_PATH2 4 /* comparison-file from "diff dirname/foo" */
+
+#define FMT_CONCISE 0
+#define FMT_NORMAL 1
+#define FMT_FILLED 2
+#define FMT_VERBOSE 4
+
+typedef enum comment {
+ Normal, Only, Binary
+} Comment;
+
+#define MARKS 4 /* each of +, - and ! */
+
+typedef enum {
+ cInsert = 0,
+ cDelete,
+ cModify,
+ cEquals
+} Change;
+
+#define InsOf(p) (p)->count[cInsert] /* "+" count inserted lines */
+#define DelOf(p) (p)->count[cDelete] /* "-" count deleted lines */
+#define ModOf(p) (p)->count[cModify] /* "!" count modified lines */
+#define EqlOf(p) (p)->count[cEquals] /* "=" count unmodified lines */
+
+#define TotalOf(p) (InsOf(p) + DelOf(p) + ModOf(p) + EqlOf(p))
+#define for_each_mark(n) for (n = 0; n < num_marks; ++n)
+
+typedef struct _data {
+ struct _data *link;
+ char *name; /* the filename */
+ int copy; /* true if filename is const-literal */
+ int base; /* beginning of name if -p option used */
+ Comment cmt;
+ int pending;
+ long chunks; /* total number of chunks */
+ long chunk[MARKS]; /* counts for the current chunk */
+ long count[MARKS]; /* counts for the file */
+} DATA;
+
+typedef enum {
+ dcNone = 0,
+ dcBzip,
+ dcCompress,
+ dcGzip,
+ dcLzma,
+ dcPack,
+ dcXz,
+ dcEmpty
+} Decompress;
+
+static const char marks[MARKS + 1] = "+-!=";
+static const int colors[MARKS + 1] =
+{2, 1, 6, 4};
+
+static DATA *all_data;
+static const char *comment_opt = "";
+static char *path_opt = 0;
+static int format_opt = FMT_NORMAL;
+static int max_width; /* the specified width-limit */
+static int merge_names = 1; /* true if we merge similar filenames */
+static int merge_opt = 0; /* true if we merge ins/del as modified */
+static int min_name_wide; /* minimum amount reserved for filenames */
+static int max_name_wide; /* maximum amount reserved for filenames */
+static int names_only; /* true if we list filenames only */
+static int num_marks = 3; /* 3 or 4, according to "-P" option */
+static int reverse_opt; /* true if results are reversed */
+static int show_colors; /* true if showing SGR colors */
+static int show_progress; /* if not writing to tty, show progress */
+static int summary_only = 0; /* true if only summary line is shown */
+static int path_dest; /* true if path_opt is destination (patched) */
+static int plot_width; /* the amount left over for histogram */
+static int prefix_opt = -1; /* if positive, controls stripping of PATHSEP */
+static int round_opt = 0; /* if nonzero, round data for histogram */
+static int table_opt = 0; /* if nonzero, write table rather than plot */
+static int trace_opt = 0; /* if nonzero, write debugging information */
+static int sort_names = 1; /* true if we sort filenames */
+static int verbose = 0; /* -v option */
+static int quiet = 0; /* -q option */
+static int suppress_binary = 0; /* -b option */
+static long plot_scale; /* the effective scale (1:maximum) */
+
+#ifdef HAVE_TSEARCH
+static int use_tsearch;
+static void *sorted_data;
+#endif
+
+static int prefix_len = -1;
+
+/******************************************************************************/
+
+static void
+failed(const char *s)
+{
+ perror(s);
+ exit(EXIT_FAILURE);
+}
+
+/* malloc wrapper that never returns NULL */
+static void *
+xmalloc(size_t s)
+{
+ void *p;
+ if ((p = malloc(s)) == NULL)
+ failed("malloc");
+ return p;
+}
+
+static int
+is_dir(const char *name)
+{
+ struct stat sb;
+ return (stat(name, &sb) == 0 &&
+ (sb.st_mode & S_IFMT) == S_IFDIR);
+}
+
+static void
+blip(int c)
+{
+ if (show_progress) {
+ (void) fputc(c, stderr);
+ (void) fflush(stderr);
+ }
+}
+
+static char *
+new_string(const char *s)
+{
+ return strcpy((char *) xmalloc((size_t) (strlen(s) + 1)), s);
+}
+
+static int
+compare_data(const void *a, const void *b)
+{
+ const DATA *p = (const DATA *) a;
+ const DATA *q = (const DATA *) b;
+ return strcmp(p->name + p->base, q->name + q->base);
+}
+
+static void
+init_data(DATA * data, const char *name, int copy, int base)
+{
+ memset(data, 0, sizeof(*data));
+ data->name = (char *) name;
+ data->copy = copy;
+ data->base = base;
+ data->cmt = Normal;
+}
+
+static DATA *
+new_data(const char *name, int base)
+{
+ DATA *r = (DATA *) xmalloc(sizeof(DATA));
+
+ init_data(r, new_string(name), 0, base);
+
+ return r;
+}
+
+#ifdef HAVE_TSEARCH
+static DATA *
+add_tsearch_data(const char *name, int base)
+{
+ DATA find;
+ DATA *result;
+ void *pp;
+
+ init_data(&find, name, 1, base);
+ if ((pp = tfind(&find, &sorted_data, compare_data)) != 0) {
+ result = *(DATA **) pp;
+ return result;
+ }
+ result = new_data(name, base);
+ (void) tsearch(result, &sorted_data, compare_data);
+ result->link = all_data;
+ all_data = result;
+
+ return result;
+}
+#endif
+
+static DATA *
+find_data(const char *name)
+{
+ DATA *p, *q, *r;
+ DATA find;
+ int base = 0;
+
+ TRACE(("** find_data(%s)\n", name));
+
+ /* Compute the base offset if the prefix option is used */
+ if (prefix_opt >= 0) {
+ int n;
+
+ for (n = prefix_opt; n > 0; n--) {
+ char *s = strchr(name + base, PATHSEP);
+ if (s == 0 || *++s == EOS)
+ break;
+ base = (int) (s - name);
+ }
+ TRACE(("** base set to %d\n", base));
+ }
+
+ /* Insert into sorted list (usually sorted). If we are not sorting or
+ * merging names, we fall off the end and link the new entry to the end of
+ * the list. If the prefix option is used, the prefix is ignored by the
+ * merge and sort operations.
+ *
+ * If we have tsearch(), we will maintain the sorted list using it and
+ * tfind().
+ */
+#ifdef HAVE_TSEARCH
+ if (use_tsearch) {
+ r = add_tsearch_data(name, base);
+ } else
+#endif
+ {
+ init_data(&find, name, 1, base);
+ for (p = all_data, q = 0; p != 0; q = p, p = p->link) {
+ int cmp = compare_data(p, &find);
+ if (merge_names && (cmp == 0))
+ return p;
+ if (sort_names && (cmp > 0))
+ break;
+ }
+ r = new_data(name, base);
+ if (q != 0)
+ q->link = r;
+ else
+ all_data = r;
+
+ r->link = p;
+ }
+
+ return r;
+}
+
+/*
+ * Remove a unneeded data item from the linked list. Free the name as well.
+ */
+static int
+delink(DATA * data)
+{
+ DATA *p, *q;
+
+ TRACE(("** delink '%s'\n", data->name));
+
+#ifdef HAVE_TSEARCH
+ if (use_tsearch) {
+ if (tdelete(data, &sorted_data, compare_data) == 0)
+ return 0;
+ }
+#endif
+ for (p = all_data, q = 0; p != 0; q = p, p = p->link) {
+ if (p == data) {
+ if (q != 0)
+ q->link = p->link;
+ else
+ all_data = p->link;
+ if (!p->copy)
+ free(p->name);
+ free(p);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Compare string 's' against a constant, returning either a pointer just
+ * past the matched part of 's' if it matches exactly, or null if a mismatch
+ * was found.
+ */
+static char *
+match(char *s, const char *p)
+{
+ int ok = 0;
+
+ while (*s != EOS) {
+ if (*p == EOS) {
+ ok = 1;
+ break;
+ }
+ if (*s++ != *p++)
+ break;
+ if (*s == EOS && *p == EOS) {
+ ok = 1;
+ break;
+ }
+ }
+ return ok ? s : 0;
+}
+
+static int
+version_num(const char *s)
+{
+ int main_ver, sub_ver;
+ char temp[2];
+ return (sscanf(s, "%d.%d%c", &main_ver, &sub_ver, temp) == 2);
+}
+
+/*
+ * Check for a range of line-numbers, used in editing scripts.
+ */
+static int
+edit_range(const char *s)
+{
+ int first, last;
+ char temp[2];
+ return (sscanf(s, "%d,%d%c", &first, &last, temp) == 2)
+ || (sscanf(s, "%d%c", &first, temp) == 1);
+}
+
+/*
+ * Decode a range for default diff.
+ */
+static int
+decode_default(char *s,
+ long *first, long *first_size,
+ long *second, long *second_size)
+{
+ int rc = 0;
+ char *next;
+
+ if (isdigit(UC(*s))) {
+ *first_size = 1;
+ *second_size = 1;
+
+ *first = strtol(s, &next, 10);
+ if (next != 0 && next != s) {
+ if (*next == ',') {
+ s = ++next;
+ *first_size = strtol(s, &next, 10) + 1 - *first;
+ }
+ }
+ if (next != 0 && next != s) {
+ switch (*next++) {
+ case 'a':
+ case 'c':
+ case 'd':
+ s = next;
+ *second = strtol(s, &next, 10);
+ if (next != 0 && next != s) {
+ if (*next == ',') {
+ s = ++next;
+ *second_size = strtol(s, &next, 10) + 1 - *second;
+ }
+ }
+ if (next != 0 && next != s && *next == EOS)
+ rc = 1;
+ break;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+ * Decode a range for unified diff. Oddly, the comments in diffutils code
+ * claim that both numbers are line-numbers. However, inspection of the output
+ * shows that the numbers are a line-number followed by a count.
+ */
+static int
+decode_range(const char *s, int *first, int *second)
+{
+ int rc = 0;
+ char check;
+
+ if (isdigit(UC(*s))) {
+ if (sscanf(s, "%d,%d%c", first, second, &check) == 2) {
+ TRACE(("** decode_range #1 first=%d, second=%d\n", *first, *second));
+ rc = 1;
+ } else if (sscanf(s, "%d%c", first, &check) == 1) {
+ *second = *first; /* diffutils 2.7 does this */
+ TRACE(("** decode_range #2 first=%d, second=%d\n", *first, *second));
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
+static int
+HadDiffs(const DATA * data)
+{
+ return InsOf(data) != 0
+ || DelOf(data) != 0
+ || ModOf(data) != 0
+ || data->cmt != Normal;
+}
+
+/*
+ * If the given path is not one of the "ignore" paths, then return true.
+ */
+static int
+can_be_merged(const char *path)
+{
+ int result = 0;
+ if (strcmp(path, "")
+ && strcmp(path, "/dev/null"))
+ result = 1;
+ return result;
+}
+
+static int
+is_leaf(const char *theLeaf, const char *path)
+{
+ char *s;
+
+ if (strchr(theLeaf, PATHSEP) == 0
+ && (s = strrchr(path, PATHSEP)) != 0
+ && !strcmp(++s, theLeaf))
+ return 1;
+ return 0;
+}
+
+static char *
+trim_datapath(DATA ** datap, size_t length, int *localp)
+{
+ char *target = (*datap)->name;
+
+#ifdef HAVE_TSEARCH
+ /*
+ * If we are using tsearch(), make a local copy of the data
+ * so we can trim it without interfering with tsearch's
+ * notion of the ordering of data. That will create some
+ * spurious empty data, so we add the changed() macro in a
+ * few places to skip over those.
+ */
+ if (use_tsearch) {
+ char *trim = new_string(target);
+ trim[length] = EOS;
+ *datap = add_tsearch_data(trim, (*datap)->base);
+ target = (*datap)->name;
+ free(trim);
+ *localp = 1;
+ } else
+#endif
+ target[length] = EOS;
+
+ return target;
+}
+
+/*
+ * The 'data' parameter points to the first of two markers, while
+ * 'path' is the pathname from the second marker.
+ *
+ * On the first call for
+ * a given file, the 'data' parameter stores no differences.
+ */
+static char *
+do_merging(DATA * data, char *path, int *freed)
+{
+ char *target = reverse_opt ? path : data->name;
+ char *source = reverse_opt ? data->name : path;
+ char *result = source;
+
+ TRACE(("** do_merging(\"%s\",\"%s\") diffs:%d\n",
+ data->name, path, HadDiffs(data)));
+
+ *freed = 0;
+ if (!HadDiffs(data)) {
+
+ if (is_leaf(target, source)) {
+ TRACE(("** is_leaf: \"%s\" vs \"%s\"\n", target, source));
+ if (reverse_opt) {
+ TRACE((".. no action @%d\n", __LINE__));
+ } else {
+ *freed = delink(data);
+ }
+ } else if (can_be_merged(target)
+ && can_be_merged(source)) {
+ size_t len1 = strlen(target);
+ size_t len2 = strlen(source);
+ size_t n;
+ int matched = 0;
+ int diff = 0;
+ int local = 0;
+
+ /*
+ * If the source/target differ only by some suffix, e.g., ".orig"
+ * or ".bak", strip that off. The target may may also be a
+ * temporary filename (which would not be merged since it has no
+ * apparent relationship to the current).
+ */
+ if (len1 > len2) {
+ if (!strncmp(target, source, len2)) {
+ TRACE(("** trimming data \"%s\" to \"%.*s\"\n",
+ target, (int) len2, target));
+ if (reverse_opt) {
+ TRACE((".. no action @%d\n", __LINE__));
+ } else {
+ target = trim_datapath(&data, len1 = len2, &local);
+ }
+ }
+ } else if (len1 < len2) {
+ if (!strncmp(target, source, len1)) {
+ TRACE(("** trimming source \"%s\" to \"%.*s\"\n",
+ source, (int) len1, source));
+ if (reverse_opt) {
+ TRACE((".. no action @%d\n", __LINE__));
+ } else {
+ source[len2 = len1] = EOS;
+ }
+ }
+ }
+
+ /*
+ * If there was no "-p" option, look for the best match by
+ * stripping prefixes from both source/target strings.
+ */
+ if (prefix_opt < 0) {
+ /*
+ * Now (whether or not we trimmed a suffix), scan back from the
+ * end of source/target strings to find if they happen to share
+ * a common ending, e.g., a/b/c versus d/b/c. If the strings
+ * are not identical, then 'diff' will be set, but if they have
+ * a common ending then 'matched' will be set.
+ */
+ for (n = 1; n <= len1 && n <= len2; n++) {
+ if (target[len1 - n] != source[len2 - n]) {
+ diff = (int) n;
+ break;
+ }
+ if (source[len2 - n] == PATHSEP) {
+ matched = (int) n;
+ }
+ }
+
+ TRACE(("** merge @%d, prefix_opt=%d matched=%d diff=%d\n",
+ __LINE__, prefix_opt, matched, diff));
+ if (matched != 0 && diff) {
+ if (reverse_opt) {
+ TRACE((".. no action @%d\n", __LINE__));
+ } else {
+ result = source + ((int) len2 - matched + 1);
+ }
+ }
+ }
+
+ if (!local) {
+ if (reverse_opt) {
+ TRACE((".. no action @%d\n", __LINE__));
+ } else {
+ *freed = delink(data);
+ }
+ }
+ } else if (reverse_opt) {
+ TRACE((".. no action @%d\n", __LINE__));
+ if (can_be_merged(source)) {
+ TRACE(("** merge @%d\n", __LINE__));
+ } else {
+ TRACE(("** do not merge, retain @%d\n", __LINE__));
+ /* must not merge, retain existing name */
+ result = target;
+ }
+ } else {
+ if (can_be_merged(source)) {
+ TRACE(("** merge @%d\n", __LINE__));
+ *freed = delink(data);
+ } else {
+ TRACE(("** do not merge, retain @%d\n", __LINE__));
+ /* must not merge, retain existing name */
+ result = target;
+ }
+ }
+ } else if (reverse_opt) {
+ TRACE((".. no action @%d\n", __LINE__));
+ if (can_be_merged(source)) {
+ TRACE(("** merge @%d\n", __LINE__));
+ result = target;
+ } else {
+ TRACE(("** do not merge, retain @%d\n", __LINE__));
+ }
+ } else {
+ if (can_be_merged(source)) {
+ TRACE(("** merge @%d\n", __LINE__));
+ } else {
+ TRACE(("** do not merge, retain @%d\n", __LINE__));
+ result = target;
+ }
+ }
+ TRACE(("** finish do_merging ->\"%s\"\n", result));
+ return result;
+}
+
+static int
+begin_data(const DATA * p)
+{
+ if (!can_be_merged(p->name)
+ && strchr(p->name, PATHSEP) != 0) {
+ TRACE(("** begin_data:HAVE_PATH\n"));
+ return HAVE_PATH;
+ }
+ TRACE(("** begin_data:HAVE_GENERIC\n"));
+ return HAVE_GENERIC;
+}
+
+static char *
+skip_blanks(char *s)
+{
+ while (isspace(UC(*s)))
+ ++s;
+ return s;
+}
+
+/*
+ * Skip a filename, which may be in quotes, to allow embedded blanks in the
+ * name.
+ */
+static char *
+skip_filename(char *s)
+{
+ if (*s == SQUOTE && s[1] != EOS && strchr(s + 1, SQUOTE)) {
+ ++s;
+ while (*s != EOS && (*s != SQUOTE) && isgraph(UC(*s))) {
+ ++s;
+ }
+ ++s;
+ } else {
+ while (*s != EOS && isgraph(UC(*s))) {
+ ++s;
+ }
+ }
+ return s;
+}
+
+static char *
+skip_options(char *params)
+{
+ while (*params != EOS) {
+ params = skip_blanks(params);
+ if (*params == '-') {
+ while (isgraph(UC(*params)))
+ params++;
+ } else {
+ break;
+ }
+ }
+ return skip_blanks(params);
+}
+
+/*
+ * Strip single-quotes from a name (needed for recent makepatch versions).
+ */
+static void
+dequote(char *s)
+{
+ size_t len = strlen(s);
+ int n;
+
+ if (*s == SQUOTE && len > 2 && s[len - 1] == SQUOTE) {
+ for (n = 0; (s[n] = s[n + 1]) != EOS; ++n) {
+ ;
+ }
+ s[len - 2] = EOS;
+ }
+}
+
+/*
+ * Allocate a fixed-buffer
+ */
+static void
+fixed_buffer(char **buffer, size_t want)
+{
+ *buffer = (char *) xmalloc(want);
+}
+
+/*
+ * Reallocate a fixed-buffer
+ */
+static void
+adjust_buffer(char **buffer, size_t want)
+{
+ if ((*buffer = (char *) realloc(*buffer, want)) == 0)
+ failed("realloc");
+}
+
+/*
+ * Read until newline or end-of-file, allocating the line-buffer so it is long
+ * enough for the input.
+ */
+static int
+get_line(char **buffer, size_t *have, FILE *fp)
+{
+ int ch;
+ size_t used = 0;
+
+ while ((ch = MY_GETC(fp)) != EOF) {
+ if (used + 2 > *have) {
+ adjust_buffer(buffer, *have *= 2);
+ }
+ (*buffer)[used++] = (char) ch;
+ if (ch == '\n')
+ break;
+ }
+ (*buffer)[used] = EOS;
+ return (used != 0);
+}
+
+static char *
+data_filename(const DATA * p)
+{
+ return (p->name + (prefix_opt >= 0 ? p->base : prefix_len));
+}
+
+/*
+ * Count the (new)lines in a file, return -1 if the file is not found.
+ */
+static int
+count_lines(DATA * p)
+{
+ int result = -1;
+ char *filename = 0;
+ char *filetail = data_filename(p);
+ size_t want = strlen(path_opt) + 2 + strlen(filetail);
+ FILE *fp;
+ int ch;
+
+ if ((filename = malloc(want)) != 0) {
+ int merge = 0;
+
+ if (path_dest) {
+ size_t path_len = strlen(path_opt);
+ size_t tail_len;
+ char *tail_sep = strchr(filetail, PATHSEP);
+
+ if (tail_sep != 0) {
+ tail_len = (size_t) (tail_sep - filetail);
+ if (tail_len != 0 && tail_len <= path_len) {
+ if (tail_len < path_len
+ && path_opt[path_len - tail_len - 1] != PATHSEP) {
+ merge = 0;
+ } else if (!strncmp(path_opt + path_len - tail_len,
+ filetail,
+ tail_len - 1)) {
+ merge = 1;
+ if (path_len > tail_len) {
+ sprintf(filename, "%.*s%c%s",
+ (int) (path_len - tail_len),
+ path_opt,
+ PATHSEP,
+ filetail);
+ } else {
+ strcpy(filename, filetail);
+ }
+ }
+ }
+ }
+ }
+ if (!merge) {
+ sprintf(filename, "%s%c%s", path_opt, PATHSEP, filetail);
+ }
+
+ TRACE(("count_lines %s\n", filename));
+ if ((fp = fopen(filename, "r")) != 0) {
+ result = 0;
+ while ((ch = MY_GETC(fp)) != EOF) {
+ if (ch == '\n')
+ ++result;
+ }
+ fclose(fp);
+ } else {
+ fprintf(stderr, "Cannot open %s\n", filename);
+ }
+ free(filename);
+ } else {
+ failed("count_lines");
+ }
+ return result;
+}
+
+static void
+update_chunk(DATA * p, Change change)
+{
+ if (merge_opt) {
+ p->pending += 1;
+ p->chunk[change] += 1;
+ } else {
+ p->count[change] += 1;
+ }
+}
+
+static void
+finish_chunk(DATA * p)
+{
+ int i;
+
+ if (p->pending) {
+ p->pending = 0;
+ p->chunks += 1;
+ if (merge_opt) {
+ /*
+ * This is crude, but to make it really precise we would have
+ * to keep an array of line-numbers to which which in a chunk
+ * are marked as insert/delete.
+ */
+ if (p->chunk[cInsert] && p->chunk[cDelete]) {
+ long change;
+ if (p->chunk[cInsert] > p->chunk[cDelete]) {
+ change = p->chunk[cDelete];
+ } else {
+ change = p->chunk[cInsert];
+ }
+ p->chunk[cInsert] -= change;
+ p->chunk[cDelete] -= change;
+ p->chunk[cModify] += change;
+ }
+ }
+ for_each_mark(i) {
+ p->count[i] += p->chunk[i];
+ p->chunk[i] = 0;
+ }
+ }
+}
+
+#define date_delims(a,b) (((a)=='/' && (b)=='/') || ((a) == '-' && (b) == '-'))
+#define CASE_TRACE() TRACE(("** handle case for '%c' %d:%s\n", *buffer, ok, that ? that->name : ""))
+
+static void
+do_file(FILE *fp, const char *default_name)
+{
+ static const char *only_stars = "***************";
+
+ DATA dummy;
+ DATA *that = &dummy;
+ DATA *prev = 0;
+ char *buffer = 0;
+ char *b_fname = 0;
+ char *b_temp1 = 0;
+ char *b_temp2 = 0;
+ char *b_temp3 = 0;
+ size_t length = 0;
+ size_t fixed = 0;
+ int ok = HAVE_NOTHING;
+ int marker;
+ int freed = 0;
+
+ int unified = 0;
+ int old_unify = 0;
+ int new_unify = 0;
+ int expect_unify = 0;
+
+ long old_dft = 0;
+ long new_dft = 0;
+
+ int context = 1;
+
+ char *s;
+#if OPT_TRACE
+ int line_no = 0;
+#endif
+
+ init_data(&dummy, "", 1, 0);
+
+ fixed_buffer(&buffer, fixed = length = BUFSIZ);
+ fixed_buffer(&b_fname, length);
+ fixed_buffer(&b_temp1, length);
+ fixed_buffer(&b_temp2, length);
+ fixed_buffer(&b_temp3, length);
+
+ while (get_line(&buffer, &length, fp)) {
+ /*
+ * Adjust size of fixed-buffers so that a sscanf cannot overflow.
+ */
+ if (length > fixed) {
+ fixed = length;
+ adjust_buffer(&b_fname, length);
+ adjust_buffer(&b_temp1, length);
+ adjust_buffer(&b_temp2, length);
+ adjust_buffer(&b_temp3, length);
+ }
+
+ /*
+ * Trim trailing newline.
+ */
+ for (s = buffer + strlen(buffer); s > buffer; s--) {
+ if ((UC(s[-1]) == '\n') || (UC(s[-1]) == '\r'))
+ s[-1] = EOS;
+ else
+ break;
+ }
+ ++line_no;
+ TRACE(("[%05d] %s\n", line_no, buffer));
+
+ /*
+ * "patch -U" can create ".rej" files lacking a filename header,
+ * in unified format. Check for those.
+ */
+ if (line_no == 1 && !strncmp(buffer, "@@", (size_t) 2)) {
+ unified = 2;
+ that = find_data(default_name);
+ ok = begin_data(that);
+ }
+
+ /*
+ * The lines identifying files in a context diff depend on how it was
+ * invoked. But after the header, each chunk begins with a line
+ * containing 15 *'s. Each chunk may contain a line-range with '***'
+ * for the "before", and a line-range with '---' for the "after". The
+ * part of the chunk depicting the deletion may be absent, though the
+ * edit line is present.
+ *
+ * The markers for unified diff are a little different from the normal
+ * context-diff. Also, the edit-lines in a unified diff won't have a
+ * space in column 2. Because of the missing space, we have to count
+ * lines to ensure we do not confuse the marker lines.
+ */
+ marker = 0;
+ if (that != &dummy && !strcmp(buffer, only_stars)) {
+ finish_chunk(that);
+ TRACE(("** begin context chunk\n"));
+ context = 2;
+ } else if (line_no == 1 && !strcmp(buffer, only_stars)) {
+ TRACE(("** begin context chunk\n"));
+ context = 2;
+ that = find_data(default_name);
+ ok = begin_data(that);
+ } else if (context == 2 && match(buffer, "*** ")) {
+ context = 1;
+ } else if (context == 1 && match(buffer, "--- ")) {
+ marker = 1;
+ context = 0;
+ } else if (match(buffer, "*** ")) {
+ } else if ((old_unify + new_unify) == 0 && match(buffer, "==== ")) {
+ finish_chunk(that);
+ unified = 2;
+ } else if ((old_unify + new_unify) == 0 && match(buffer, "--- ")) {
+ finish_chunk(that);
+ marker = unified = 1;
+ } else if ((old_unify + new_unify) == 0 && match(buffer, "+++ ")) {
+ marker = unified = 2;
+ } else if (unified == 2
+ || ((old_unify + new_unify) == 0 && (*buffer == '@'))) {
+ finish_chunk(that);
+ unified = 0;
+ if (*buffer == '@') {
+ int old_base, new_base, old_size, new_size;
+ char test_at;
+
+ old_unify = new_unify = 0;
+ if (sscanf(buffer, "@@ -%[0-9,] +%[0-9,] @%c",
+ b_temp1,
+ b_temp2,
+ &test_at) == 3
+ && test_at == '@'
+ && decode_range(b_temp1, &old_base, &old_size)
+ && decode_range(b_temp2, &new_base, &new_size)) {
+ old_unify = old_size;
+ new_unify = new_size;
+ unified = -1;
+ }
+ }
+ } else if (unified == 1 && !context) {
+ /*
+ * If unified==1, we guessed we would find a "+++" line, but since
+ * we are here, we did not find that. The context check ensures
+ * we do not mistake the "---" for a unified diff with that for
+ * a context diff's "after" line-range.
+ *
+ * If we guessed wrong, then we probably found a data line with
+ * "--" in the first two columns of the diff'd file.
+ */
+ unified = 0;
+ TRACE(("?? Expected \"+++\" for unified diff\n"));
+ if (prev != 0
+ && prev != that
+ && InsOf(that) == 0
+ && DelOf(that) == 0
+ && strcmp(prev->name, that->name)) {
+ TRACE(("?? giveup on %ld/%ld %s\n", InsOf(that),
+ DelOf(that), that->name));
+ TRACE(("?? revert to %ld/%ld %s\n", InsOf(prev),
+ DelOf(prev), prev->name));
+ (void) delink(that);
+ that = prev;
+ update_chunk(that, cDelete);
+ }
+ } else if (old_unify + new_unify) {
+ switch (*buffer) {
+ case '-':
+ if (old_unify)
+ --old_unify;
+ break;
+ case '+':
+ if (new_unify)
+ --new_unify;
+ break;
+ case EOS:
+ case ' ':
+ if (old_unify)
+ --old_unify;
+ if (new_unify)
+ --new_unify;
+ break;
+ case '\\':
+ if (strstr(buffer, "newline") != 0) {
+ break;
+ }
+ /* FALLTHRU */
+ default:
+ TRACE(("?? expected more in chunk\n"));
+ old_unify = new_unify = 0;
+ break;
+ }
+ if (!(old_unify + new_unify)) {
+ expect_unify = 2;
+ }
+ } else {
+ long old_base, new_base;
+
+ unified = 0;
+
+ if (line_no == 1
+ && decode_default(buffer,
+ &old_base, &old_dft,
+ &new_base, &new_dft)) {
+ TRACE(("DFT %ld,%ld -> %ld,%ld\n",
+ old_base, old_base + old_dft - 1,
+ new_base, new_base + new_dft - 1));
+ finish_chunk(that);
+ that = find_data("unknown");
+ ok = begin_data(that);
+ }
+ }
+
+ /*
+ * If the previous line ended a chunk of a unified diff, we may begin
+ * another chunk, or begin another type of diff. If neither, do not
+ * continue to accumulate counts for the unified diff which has ended.
+ */
+ if (expect_unify != 0) {
+ if (expect_unify-- == 1) {
+ if (unified == 0) {
+ TRACE(("?? did not get chunk\n"));
+ finish_chunk(that);
+ that = &dummy;
+ }
+ }
+ }
+
+ /*
+ * Override the beginning of the line to simplify the case statement
+ * below.
+ */
+ if (marker > 0) {
+ TRACE(("** have marker=%d, override %s\n", marker, buffer));
+ (void) strncpy(buffer, "***", (size_t) 3);
+ }
+
+ /*
+ * Use the first character of the input line to determine its
+ * type:
+ */
+ switch (*buffer) {
+ case 'O': /* Only */
+ CASE_TRACE();
+ if (match(buffer, "Only in ")) {
+ char *path = buffer + 8;
+ int found = 0;
+ for (s = path; *s != EOS; s++) {
+ if (match(s, ": ")) {
+ found = 1;
+ *s++ = PATHSEP;
+ while ((s[0] = s[1]) != EOS)
+ s++;
+ break;
+ }
+ }
+ if (found) {
+ blip('.');
+ finish_chunk(that);
+ that = find_data(path);
+ that->cmt = Only;
+ ok = HAVE_NOTHING;
+ }
+ }
+ break;
+
+ /*
+ * Several different scripts produce "Index:" lines
+ * (e.g., "makepatch"). Not all bother to put the
+ * pathname of the files; some put only the leaf names.
+ */
+ case 'I':
+ CASE_TRACE();
+ if ((s = match(buffer, "Index: ")) != 0) {
+ s = skip_blanks(s);
+ dequote(s);
+ blip('.');
+ finish_chunk(that);
+ s = do_merging(that, s, &freed);
+ that = find_data(s);
+ ok = begin_data(that);
+ }
+ break;
+
+ case 'd': /* diff command trace */
+ CASE_TRACE();
+ if ((s = match(buffer, "diff ")) != 0
+ && *(s = skip_options(s)) != EOS) {
+ if (reverse_opt) {
+ *skip_filename(s) = EOS;
+ } else {
+ s = skip_filename(s);
+ s = skip_blanks(s);
+ }
+ dequote(s);
+ blip('.');
+ finish_chunk(that);
+ s = do_merging(that, s, &freed);
+ that = find_data(s);
+ ok = begin_data(that);
+ }
+ break;
+
+ case '*':
+ CASE_TRACE();
+ if (!(ok & HAVE_PATH)) {
+ int ddd, hour, minute, second;
+ int day, month, year;
+ char yrmon, monday;
+
+ /* check for tab-delimited first, so we can
+ * accept filenames containing spaces.
+ */
+ if (sscanf(buffer,
+ "*** %[^\t]\t%[^ ] %[^ ] %d %d:%d:%d %d",
+ b_fname,
+ b_temp2, b_temp3, &ddd,
+ &hour, &minute, &second, &year) == 8
+ || (sscanf(buffer,
+ "*** %[^\t]\t%d%c%d%c%d %d:%d:%d",
+ b_fname,
+ &year, &yrmon, &month, &monday, &day,
+ &hour, &minute, &second) == 9
+ && date_delims(yrmon, monday)
+ && !version_num(b_fname))
+ || sscanf(buffer,
+ "*** %[^\t ]%[\t ]%[^ ] %[^ ] %d %d:%d:%d %d",
+ b_fname,
+ b_temp1,
+ b_temp2, b_temp3, &ddd,
+ &hour, &minute, &second, &year) == 9
+ || (sscanf(buffer,
+ "*** %[^\t ]%[\t ]%d%c%d%c%d %d:%d:%d",
+ b_fname,
+ b_temp1,
+ &year, &yrmon, &month, &monday, &day,
+ &hour, &minute, &second) == 10
+ && date_delims(yrmon, monday)
+ && !version_num(b_fname))
+ || (sscanf(buffer,
+ "*** %[^\t ]%[\t ]",
+ b_fname,
+ b_temp1) >= 1
+ && !version_num(b_fname)
+ && !contain_any(b_fname, "*")
+ && !edit_range(b_fname))
+ ) {
+ prev = that;
+ finish_chunk(that);
+ s = do_merging(that, b_fname, &freed);
+ if (freed)
+ prev = 0;
+ that = find_data(s);
+ ok = begin_data(that);
+ TRACE(("** after merge:%d:%s\n", ok, s));
+ }
+ }
+ break;
+
+ case '=':
+ CASE_TRACE();
+ if (!(ok & HAVE_PATH)) {
+ int rev;
+
+ if (((sscanf(buffer,
+ "==== %[^\t #]#%d - %[^\t ]",
+ b_fname,
+ &rev,
+ b_temp1) == 3)
+ || ((sscanf(buffer,
+ "==== %[^\t #]#%d (%[^)]) - %[^\t ]",
+ b_fname,
+ &rev,
+ b_temp1,
+ b_temp2) == 4)))
+ && !version_num(b_fname)
+ && !contain_any(b_fname, "*")
+ && !edit_range(b_fname)) {
+ TRACE(("** found p4-diff\n"));
+ prev = that;
+ finish_chunk(that);
+ s = do_merging(that, b_fname, &freed);
+ if (freed)
+ prev = 0;
+ that = find_data(s);
+ ok = begin_data(that);
+ TRACE(("** after merge:%d:%s\n", ok, s));
+ }
+ }
+ break;
+
+ case '+':
+ /* FALL-THRU */
+ case '>':
+ CASE_TRACE();
+ if (ok) {
+ update_chunk(that, cInsert);
+ }
+ break;
+
+ case '-':
+ if (!ok) {
+ CASE_TRACE();
+ break;
+ }
+ if (!unified && !strcmp(buffer, "---")) {
+ CASE_TRACE();
+ break;
+ }
+ /* fall-thru */
+ case '<':
+ CASE_TRACE();
+ if (ok) {
+ update_chunk(that, cDelete);
+ }
+ break;
+
+ case '!':
+ CASE_TRACE();
+ if (ok) {
+ update_chunk(that, cModify);
+ }
+ break;
+
+ /* Expecting "Binary files XXX and YYY differ" */
+ case 'B': /* Binary */
+ /* FALL-THRU */
+ case 'b': /* binary */
+ CASE_TRACE();
+ if ((s = match(buffer + 1, "inary files ")) != 0) {
+ char *first = skip_blanks(s);
+ /* blindly assume the first filename does not contain " and " */
+ char *at_and = strstr(s, " and ");
+ s = strrchr(buffer, BLANK);
+ if ((at_and != NULL) && !strcmp(s, " differ")) {
+ char *second = skip_blanks(at_and + 5);
+
+ if (reverse_opt) {
+ *at_and = EOS;
+ s = first;
+ } else {
+ *s = EOS;
+ s = second;
+ }
+ blip('.');
+ finish_chunk(that);
+ that = find_data(s);
+ that->cmt = Binary;
+ ok = HAVE_NOTHING;
+ }
+ }
+ break;
+ }
+ }
+ blip('\n');
+
+ finish_chunk(that);
+ finish_chunk(&dummy);
+ if (buffer != 0) {
+ free(buffer);
+ free(b_fname);
+ free(b_temp1);
+ free(b_temp2);
+ free(b_temp3);
+ }
+}
+
+static void
+show_color(int color)
+{
+ if (color >= 0)
+ printf("\033[%dm", color + 30);
+ else
+ printf("\033[0;39m");
+}
+
+static long
+plot_bar(long count, int c, int color)
+{
+ long result = count;
+
+ if (show_colors && result != 0)
+ show_color(color);
+
+ while (--count >= 0)
+ (void) putchar(c);
+
+ if (show_colors && result != 0)
+ show_color(-1);
+
+ return result;
+}
+
+/*
+ * Each call to 'plot_num()' prints a scaled bar of 'c' characters. The
+ * 'extra' parameter is used to keep the accumulated error in the bar's total
+ * length from getting large.
+ */
+static long
+plot_num(long num_value, int c, int color, long *extra)
+{
+ long product;
+ long result = 0;
+
+ /* the value to plot */
+ /* character to display in the bar */
+ /* accumulated error in the bar */
+ if (num_value) {
+ product = (plot_width * num_value);
+ result = ((product + *extra) / plot_scale);
+ *extra = product - (result * plot_scale) - *extra;
+ plot_bar(result, c, color);
+ }
+ return result;
+}
+
+static long
+plot_round1(const long num[MARKS])
+{
+ long result = 0;
+ long scaled[MARKS];
+ long remain[MARKS];
+ long want = 0;
+ long have = 0;
+ long half = (plot_scale / 2);
+ int i, j;
+
+ for_each_mark(i) {
+ long product = (plot_width * num[i]);
+ scaled[i] = (product / plot_scale);
+ remain[i] = (product % plot_scale);
+ want += product;
+ have += product - remain[i];
+ }
+ while (want > have) {
+ j = -1;
+ for_each_mark(i) {
+ if (remain[i] != 0
+ && (remain[i] > (j >= 0 ? remain[j] : half))) {
+ j = i;
+ }
+ }
+ if (j >= 0) {
+ have += remain[j];
+ remain[j] = 0;
+ scaled[j] += 1;
+ } else {
+ break;
+ }
+ }
+ for_each_mark(i) {
+ plot_bar(scaled[i], marks[i], colors[i]);
+ result += scaled[i];
+ }
+ return result;
+}
+
+/*
+ * Print a scaled bar of characters, where c[0] is for insertions, c[1]
+ * for deletions and c[2] for modifications. The num array contains the
+ * count for each type of change, in the same order.
+ */
+static long
+plot_round2(const long num[MARKS])
+{
+ long result = 0;
+ long scaled[MARKS];
+ long remain[MARKS];
+ long total = 0;
+ int i;
+
+ for (i = 0; i < MARKS; i++)
+ total += num[i];
+
+ if (total == 0)
+ return result;
+
+ total = (total * plot_width + (plot_scale / 2)) / plot_scale;
+ /* display at least one character */
+ if (total == 0)
+ total++;
+
+ for_each_mark(i) {
+ scaled[i] = num[i] * plot_width / plot_scale;
+ remain[i] = num[i] * plot_width - scaled[i] * plot_scale;
+ total -= scaled[i];
+ }
+
+ /* assign the missing chars using the largest remainder algo */
+ while (total) {
+ int largest, largest_count; /* largest is a bit field */
+ long max_remain;
+
+ /* search for the largest remainder */
+ largest = largest_count = 0;
+ max_remain = 0;
+ for_each_mark(i) {
+ if (remain[i] > max_remain) {
+ largest = 1 << i;
+ largest_count = 1;
+ max_remain = remain[i];
+ } else if (remain[i] == max_remain) { /* ex aequo */
+ largest |= 1 << i;
+ largest_count++;
+ }
+ }
+
+ /* if there are more greatest remainders than characters
+ missing, don't assign them at all */
+ if (total < largest_count)
+ break;
+
+ /* allocate the extra characters */
+ for_each_mark(i) {
+ if (largest & (1 << i)) {
+ scaled[i]++;
+ total--;
+ remain[i] -= plot_width;
+ }
+ }
+ }
+
+ for_each_mark(i) {
+ result += plot_bar(scaled[i], marks[i], colors[i]);
+ }
+
+ return result;
+}
+
+static void
+plot_numbers(const DATA * p)
+{
+ long temp = 0;
+ long used = 0;
+ int i;
+
+ printf("%5ld ", TotalOf(p));
+
+ if (format_opt & FMT_VERBOSE) {
+ printf("%5ld ", InsOf(p));
+ printf("%5ld ", DelOf(p));
+ printf("%5ld ", ModOf(p));
+ if (path_opt)
+ printf("%5ld ", EqlOf(p));
+ }
+
+ if (format_opt == FMT_CONCISE) {
+ for_each_mark(i) {
+ printf("\t%ld %c", p->count[i], marks[i]);
+ }
+ } else {
+ switch (round_opt) {
+ default:
+ for_each_mark(i) {
+ used += plot_num(p->count[i], marks[i], colors[i], &temp);
+ }
+ break;
+ case 1:
+ used = plot_round1(p->count);
+ break;
+
+ case 2:
+ used = plot_round2(p->count);
+ break;
+ }
+
+ if ((format_opt & FMT_FILLED) != 0) {
+ if (used > plot_width)
+ printf("%ld", used - plot_width); /* oops */
+ else
+ plot_bar(plot_width - used, '.', 0);
+ }
+ }
+}
+
+#define changed(p) (!merge_names \
+ || (p)->cmt != Normal \
+ || (TotalOf(p)) != 0)
+
+static void
+show_data(const DATA * p)
+{
+ char *name = data_filename(p);
+ int width;
+
+ if (summary_only) {
+ ;
+ } else if (!changed(p)) {
+ ;
+ } else if (p->cmt == Binary && suppress_binary == 1) {
+ ;
+ } else if (table_opt) {
+ if (names_only) {
+ printf("%s\n", name);
+ } else {
+ printf("%ld,%ld,%ld,",
+ InsOf(p),
+ DelOf(p),
+ ModOf(p));
+ if (path_opt)
+ printf("%ld,", EqlOf(p));
+ printf("%s\n", name);
+ }
+ } else if (names_only) {
+ printf("%s\n", name);
+ } else {
+ printf("%s ", comment_opt);
+ if (max_name_wide > 0
+ && max_name_wide < min_name_wide
+ && max_name_wide < ((width = (int) strlen(name)))) {
+ printf("%.*s", max_name_wide, name + (width - max_name_wide));
+ } else {
+ width = ((max_name_wide > 0 && max_name_wide < min_name_wide)
+ ? max_name_wide
+ : min_name_wide);
+ printf("%-*.*s", width, width, name);
+ }
+ putchar('|');
+ switch (p->cmt) {
+ default:
+ case Normal:
+ plot_numbers(p);
+ break;
+ case Binary:
+ printf("binary");
+ break;
+ case Only:
+ printf("only");
+ break;
+ }
+ printf("\n");
+ }
+}
+
+#ifdef HAVE_TSEARCH
+static void
+show_tsearch(const void *nodep, const VISIT which, const int depth)
+{
+ const DATA *p = *(DATA * const *) nodep;
+ (void) depth;
+ if (which == postorder || which == leaf)
+ show_data(p);
+}
+#endif
+
+static int
+ignore_data(DATA * p)
+{
+ return ((!changed(p))
+ || (p->cmt == Binary && suppress_binary));
+}
+
+static void
+summarize(void)
+{
+ DATA *p;
+ long total_ins = 0;
+ long total_del = 0;
+ long total_mod = 0;
+ long total_eql = 0;
+ long temp;
+ int num_files = 0, shortest_name = -1, longest_name = -1;
+
+ plot_scale = 0;
+ for (p = all_data; p; p = p->link) {
+ int len = (int) strlen(p->name);
+
+ if (ignore_data(p))
+ continue;
+
+ /*
+ * If "-pX" option is given, prefix_opt is positive.
+ *
+ * "-p0" gives the whole pathname unmodified. "-p1" strips
+ * through the first path-separator, etc.
+ */
+ if (prefix_opt >= 0) {
+ /* p->base has been computed at node creation */
+ if (min_name_wide < (len - p->base))
+ min_name_wide = (len - p->base);
+ } else {
+ /*
+ * If "-pX" option is not given, strip off any prefix which is
+ * shared by all of the names.
+ */
+ if (len < prefix_len || prefix_len < 0)
+ prefix_len = len;
+ while (prefix_len > 0) {
+ if (p->name[prefix_len - 1] != PATHSEP)
+ prefix_len--;
+ else if (strncmp(all_data->name, p->name, (size_t) prefix_len))
+ prefix_len--;
+ else
+ break;
+ }
+
+ if (len > longest_name)
+ longest_name = len;
+ if (len < shortest_name || shortest_name < 0)
+ shortest_name = len;
+ }
+ }
+
+ /*
+ * Use a separate loop after computing prefix_len so we can apply the "-S"
+ * or "-D" options to find files that we can use as reference for the
+ * unchanged-count.
+ */
+ for (p = all_data; p; p = p->link) {
+ if (!ignore_data(p)) {
+ EqlOf(p) = 0;
+ if (reverse_opt) {
+ int save_ins = InsOf(p);
+ int save_del = DelOf(p);
+ InsOf(p) = save_del;
+ DelOf(p) = save_ins;
+ }
+ if (path_opt != 0) {
+ int count = count_lines(p);
+
+ if (count >= 0) {
+ EqlOf(p) = count - ModOf(p);
+ if (path_dest != 0) {
+ EqlOf(p) -= InsOf(p);
+ } else {
+ EqlOf(p) -= DelOf(p);
+ }
+ if (EqlOf(p) < 0)
+ EqlOf(p) = 0;
+ }
+ }
+ num_files++;
+ total_ins += InsOf(p);
+ total_del += DelOf(p);
+ total_mod += ModOf(p);
+ total_eql += EqlOf(p);
+ temp = TotalOf(p);
+ if (temp > plot_scale)
+ plot_scale = temp;
+ }
+ }
+
+ if (prefix_opt < 0) {
+ if (prefix_len < 0)
+ prefix_len = 0;
+ if ((longest_name - prefix_len) > min_name_wide)
+ min_name_wide = (longest_name - prefix_len);
+ }
+
+ min_name_wide++; /* make sure it's nonzero */
+ plot_width = (max_width - min_name_wide - 8);
+ if (plot_width < 10)
+ plot_width = 10;
+
+ if (plot_scale < plot_width)
+ plot_scale = plot_width; /* 1:1 */
+
+ if (table_opt) {
+ if (!names_only) {
+ printf("INSERTED,DELETED,MODIFIED,");
+ if (path_opt)
+ printf("UNCHANGED,");
+ }
+ printf("FILENAME\n");
+ }
+#ifdef HAVE_TSEARCH
+ if (use_tsearch) {
+ twalk(sorted_data, show_tsearch);
+ } else
+#endif
+ for (p = all_data; p; p = p->link) {
+ show_data(p);
+ }
+
+ if (!table_opt && !names_only) {
+#define PLURAL(n) n, n != 1 ? "s" : ""
+ if (num_files > 0 || !quiet) {
+ printf("%s %d file%s changed", comment_opt, PLURAL(num_files));
+ if (total_ins)
+ printf(", %ld insertion%s(+)", PLURAL(total_ins));
+ if (total_del)
+ printf(", %ld deletion%s(-)", PLURAL(total_del));
+ if (total_mod)
+ printf(", %ld modification%s(!)", PLURAL(total_mod));
+ if (total_eql && path_opt != 0)
+ printf(", %ld unchanged line%s(=)", PLURAL(total_eql));
+ (void) putchar('\n');
+ }
+ }
+}
+
+#ifdef HAVE_POPEN
+static const char *
+get_program(const char *name, const char *dft)
+{
+ const char *result = getenv(name);
+ if (result == 0 || *result == EOS)
+ result = dft;
+ TRACE(("get_program(%s) = %s\n", name, result));
+ return result;
+}
+#define GET_PROGRAM(name) get_program("DIFFSTAT_" #name, name)
+
+static char *
+decompressor(Decompress which, const char *name)
+{
+ const char *verb = 0;
+ const char *opts = "";
+ char *result = 0;
+ size_t len = strlen(name);
+
+ switch (which) {
+ case dcBzip:
+ verb = GET_PROGRAM(BZCAT_PATH);
+ if (*verb == '\0') {
+ verb = GET_PROGRAM(BZIP2_PATH);
+ opts = "-dc";
+ }
+ break;
+ case dcCompress:
+ verb = GET_PROGRAM(ZCAT_PATH);
+ if (*verb == '\0') {
+ verb = GET_PROGRAM(UNCOMPRESS_PATH);
+ opts = "-c";
+ if (*verb == '\0') {
+ /* not all compress's recognize the options, test this last */
+ verb = GET_PROGRAM(COMPRESS_PATH);
+ opts = "-dc";
+ }
+ }
+ break;
+ case dcGzip:
+ verb = GET_PROGRAM(GZIP_PATH);
+ opts = "-dc";
+ break;
+ case dcLzma:
+ verb = GET_PROGRAM(LZCAT_PATH);
+ opts = "-dc";
+ break;
+ case dcPack:
+ verb = GET_PROGRAM(PCAT_PATH);
+ break;
+ case dcXz:
+ verb = GET_PROGRAM(XZ_PATH);
+ opts = "-dc";
+ break;
+ case dcEmpty:
+ /* FALLTHRU */
+ case dcNone:
+ break;
+ }
+ if (verb != 0 && *verb != '\0') {
+ result = (char *) xmalloc(strlen(verb) + 10 + len);
+ sprintf(result, "%s %s", verb, opts);
+ if (*name != '\0') {
+ sprintf(result + strlen(result), " \"%s\"", name);
+ }
+ }
+ return result;
+}
+
+static char *
+is_compressed(const char *name)
+{
+ size_t len = strlen(name);
+ Decompress which;
+
+ if (len > 2 && !strcmp(name + len - 2, ".Z")) {
+ which = dcCompress;
+ } else if (len > 2 && !strcmp(name + len - 2, ".z")) {
+ which = dcPack;
+ } else if (len > 3 && !strcmp(name + len - 3, ".gz")) {
+ which = dcGzip;
+ } else if (len > 4 && !strcmp(name + len - 4, ".bz2")) {
+ which = dcBzip;
+ } else if (len > 5 && !strcmp(name + len - 5, ".lzma")) {
+ which = dcLzma;
+ } else if (len > 3 && !strcmp(name + len - 3, ".xz")) {
+ which = dcXz;
+ } else {
+ which = dcNone;
+ }
+ return decompressor(which, name);
+}
+
+#ifdef HAVE_MKDTEMP
+#define MY_MKDTEMP(path) mkdtemp(path)
+#else
+/*
+ * mktemp is supposedly marked obsolete at the same point that mkdtemp is
+ * introduced.
+ */
+static char *
+my_mkdtemp(char *path)
+{
+ char *result = mktemp(path);
+ if (result != 0) {
+ if (MKDIR(result, 0700) < 0) {
+ result = 0;
+ }
+ }
+ return path;
+}
+#define MY_MKDTEMP(path) my_mkdtemp(path)
+#endif
+
+static char *
+copy_stdin(char **dirpath)
+{
+ const char *tmp = getenv("TMPDIR");
+ char *result = 0;
+ int ch;
+ FILE *fp;
+
+ if (tmp == 0)
+ tmp = "/tmp/";
+ *dirpath = xmalloc(strlen(tmp) + 12);
+
+ strcpy(*dirpath, tmp);
+ strcat(*dirpath, "/diffXXXXXX");
+ if (MY_MKDTEMP(*dirpath) != 0) {
+ result = xmalloc(strlen(*dirpath) + 10);
+ sprintf(result, "%s/stdin", *dirpath);
+
+ if ((fp = fopen(result, "w")) != 0) {
+ while ((ch = MY_GETC(stdin)) != EOF) {
+ fputc(ch, fp);
+ }
+ fclose(fp);
+ } else {
+ free(result);
+ result = 0;
+ rmdir(*dirpath); /* Assume that the /stdin file was not created */
+ free(*dirpath);
+ *dirpath = 0;
+ }
+ } else {
+ free(*dirpath);
+ *dirpath = 0;
+ }
+ return result;
+}
+#endif
+
+static void
+set_path_opt(char *value, int destination)
+{
+ path_opt = value;
+ path_dest = destination;
+ if (*path_opt != 0) {
+ if (is_dir(path_opt)) {
+ num_marks = 4;
+ } else {
+ fprintf(stderr, "Not a directory:%s\n", path_opt);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+static void
+usage(FILE *fp)
+{
+ static const char *msg[] =
+ {
+ "Usage: diffstat [options] [files]",
+ "",
+ "Reads from one or more input files which contain output from 'diff',",
+ "producing a histogram of total lines changed for each file referenced.",
+ "If no filename is given on the command line, reads from standard input.",
+ "",
+ "Options:",
+ " -c prefix each line with comment (#)",
+#if OPT_TRACE
+ " -d debug - prints a lot of information",
+#endif
+ " -D PATH specify location of patched files, use for unchanged-count",
+ " -e FILE redirect standard error to FILE",
+ " -f NUM format (0=concise, 1=normal, 2=filled, 4=values)",
+ " -h print this message",
+ " -k do not merge filenames",
+ " -l list filenames only",
+ " -m merge insert/delete data in chunks as modified-lines",
+ " -n NUM specify minimum width for the filenames (default: auto)",
+ " -N NUM specify maximum width for the filenames (default: auto)",
+ " -o FILE redirect standard output to FILE",
+ " -p NUM specify number of pathname-separators to strip (default: common)",
+ " -q suppress the \"0 files changed\" message for empty diffs",
+ " -r NUM specify rounding for histogram (0=none, 1=simple, 2=adjusted)",
+ " -R assume patch was created with old and new files swapped",
+ " -S PATH specify location of original files, use for unchanged-count",
+ " -t print a table (comma-separated-values) rather than histogram",
+ " -u do not sort the input list",
+ " -v show progress if output is redirected to a file",
+ " -V prints the version number",
+ " -w NUM specify maximum width of the output (default: 80)",
+ };
+ unsigned j;
+ for (j = 0; j < sizeof(msg) / sizeof(msg[0]); j++)
+ fprintf(fp, "%s\n", msg[j]);
+}
+
+/* Wrapper around getopt that also parses "--help" and "--version".
+ * argc, argv, opts, return value, and globals optarg, optind,
+ * opterr, and optopt are as in getopt(). help and version designate
+ * what should be returned if --help or --version are encountered. */
+static int
+getopt_helper(int argc, char *const argv[], const char *opts,
+ int help, int version)
+{
+ if (optind < argc && argv[optind] != NULL) {
+ if (strcmp(argv[optind], "--help") == 0) {
+ optind++;
+ return help;
+ } else if (strcmp(argv[optind], "--version") == 0) {
+ optind++;
+ return version;
+ }
+ }
+ return getopt(argc, argv, opts);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int j;
+ char version[80];
+
+ max_width = 80;
+
+ while ((j = getopt_helper(argc, argv,
+ "bcCdD:e:f:hklmn:N:o:p:qr:RsS:tuvVw:", 'h', 'V'))
+ != -1) {
+ switch (j) {
+ case 'b':
+ suppress_binary = 1;
+ break;
+ case 'c':
+ comment_opt = "#";
+ break;
+ case 'C':
+ show_colors = 1;
+ break;
+#if OPT_TRACE
+ case 'd':
+ trace_opt = 1;
+ break;
+#endif
+ case 'D':
+ set_path_opt(optarg, 1);
+ break;
+ case 'e':
+ if (freopen(optarg, "w", stderr) == 0)
+ failed(optarg);
+ break;
+ case 'f':
+ format_opt = atoi(optarg);
+ break;
+ case 'h':
+ usage(stdout);
+ return (EXIT_SUCCESS);
+ case 'k':
+ merge_names = 0;
+ break;
+ case 'l':
+ names_only = 1;
+ break;
+ case 'm':
+ merge_opt = 1;
+ break;
+ case 'n':
+ min_name_wide = atoi(optarg);
+ break;
+ case 'N':
+ max_name_wide = atoi(optarg);
+ break;
+ case 'o':
+ if (freopen(optarg, "w", stdout) == 0)
+ failed(optarg);
+ break;
+ case 'p':
+ prefix_opt = atoi(optarg);
+ break;
+ case 'r':
+ round_opt = atoi(optarg);
+ break;
+ case 'R':
+ reverse_opt = 1;
+ break;
+ case 's':
+ summary_only = 1;
+ break;
+ case 'S':
+ set_path_opt(optarg, 0);
+ break;
+ case 't':
+ table_opt = 1;
+ break;
+ case 'u':
+ sort_names = 0;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'V':
+#ifndef NO_IDENT
+ if (!sscanf(Id, "%*s %*s %s", version))
+#endif
+ (void) strcpy(version, "?");
+ printf("diffstat version %s\n", version);
+ return (EXIT_SUCCESS);
+ case 'w':
+ max_width = atoi(optarg);
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ default:
+ usage(stderr);
+ return (EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * The numbers from -S/-D options will only be useful if the merge option
+ * is added.
+ */
+ if (path_opt)
+ merge_opt = 1;
+
+ show_progress = verbose && (!isatty(fileno(stdout))
+ && isatty(fileno(stderr)));
+
+#ifdef HAVE_TSEARCH
+ use_tsearch = (sort_names && merge_names);
+#endif
+
+ if (optind < argc) {
+ while (optind < argc) {
+ FILE *fp;
+ char *name = argv[optind++];
+#ifdef HAVE_POPEN
+ char *command = is_compressed(name);
+ if (command != 0) {
+ if ((fp = popen(command, "r")) != 0) {
+ if (show_progress) {
+ (void) fprintf(stderr, "%s\n", name);
+ (void) fflush(stderr);
+ }
+ do_file(fp, name);
+ (void) pclose(fp);
+ }
+ free(command);
+ } else
+#endif
+ if ((fp = fopen(name, "rb")) != 0) {
+ if (show_progress) {
+ (void) fprintf(stderr, "%s\n", name);
+ (void) fflush(stderr);
+ }
+ do_file(fp, name);
+ (void) fclose(fp);
+ } else {
+ failed(name);
+ }
+ }
+ } else {
+#ifdef HAVE_POPEN
+ FILE *fp;
+ Decompress which = dcEmpty;
+ char *stdin_dir = 0;
+ char *myfile;
+ char sniff[8];
+ int ch;
+ unsigned got = 0;
+ char *command;
+
+ if ((ch = MY_GETC(stdin)) != EOF) {
+ which = dcNone;
+ if (ch == 'B') { /* perhaps bzip2 (poor magic design...) */
+ sniff[got++] = (char) ch;
+ while (got < 5) {
+ if ((ch = MY_GETC(stdin)) == EOF)
+ break;
+ sniff[got++] = (char) ch;
+ }
+ if (got == 5
+ && !strncmp(sniff, "BZh", (size_t) 3)
+ && isdigit((unsigned char) sniff[3])
+ && isdigit((unsigned char) sniff[4])) {
+ which = dcBzip;
+ }
+ } else if (ch == ']') { /* perhaps lzma */
+ sniff[got++] = (char) ch;
+ while (got < 4) {
+ if ((ch = MY_GETC(stdin)) == EOF)
+ break;
+ sniff[got++] = (char) ch;
+ }
+ if (got == 4
+ && !memcmp(sniff, "]\0\0\200", (size_t) 4)) {
+ which = dcLzma;
+ }
+ } else if (ch == 0xfd) { /* perhaps xz */
+ sniff[got++] = (char) ch;
+ while (got < 6) {
+ if ((ch = MY_GETC(stdin)) == EOF)
+ break;
+ sniff[got++] = (char) ch;
+ }
+ if (got == 6
+ && !memcmp(sniff, "\3757zXZ\0", (size_t) 6)) {
+ which = dcXz;
+ }
+ } else if (ch == '\037') { /* perhaps compress, etc. */
+ sniff[got++] = (char) ch;
+ if ((ch = MY_GETC(stdin)) != EOF) {
+ sniff[got++] = (char) ch;
+ switch (ch) {
+ case 0213:
+ which = dcGzip;
+ break;
+ case 0235:
+ which = dcCompress;
+ break;
+ case 0036:
+ which = dcPack;
+ break;
+ }
+ }
+ } else {
+ sniff[got++] = (char) ch;
+ }
+ }
+ /*
+ * The C standard only guarantees one ungetc;
+ * virtually everyone allows more.
+ */
+ while (got != 0) {
+ ungetc(sniff[--got], stdin);
+ }
+ if (which != dcNone
+ && which != dcEmpty
+ && (myfile = copy_stdin(&stdin_dir)) != 0) {
+
+ /* open pipe to decompress temporary file */
+ command = decompressor(which, myfile);
+ if ((fp = popen(command, "r")) != 0) {
+ do_file(fp, "stdin");
+ (void) pclose(fp);
+ }
+ free(command);
+
+ unlink(myfile);
+ free(myfile);
+ myfile = 0;
+ rmdir(stdin_dir);
+ free(stdin_dir);
+ stdin_dir = 0;
+ } else if (which != dcEmpty)
+#endif
+ do_file(stdin, "stdin");
+ }
+ summarize();
+#if defined(NO_LEAKS)
+ while (all_data != 0) {
+ delink(all_data);
+ }
+#endif
+ return (EXIT_SUCCESS);
+}
diff --git a/patch_cmds/diffstat/install-sh b/patch_cmds/diffstat/install-sh
new file mode 100644
index 0000000..462fa9c
--- /dev/null
+++ b/patch_cmds/diffstat/install-sh
@@ -0,0 +1,294 @@
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+#
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd=$cpprog
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd=$stripprog
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "$0: no input file specified" >&2
+ exit 1
+else
+ :
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d "$dst" ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=$mkdirprog
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f "$src" ] || [ -d "$src" ]
+ then
+ :
+ else
+ echo "$0: $src does not exist" >&2
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "$0: no destination specified" >&2
+ exit 1
+ else
+ :
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d "$dst" ]
+ then
+ dst=$dst/`basename "$src"`
+ else
+ :
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+ '
+IFS="${IFS-$defaultIFS}"
+
+oIFS=$IFS
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS=$oIFS
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp=$pathcomp$1
+ shift
+
+ if [ ! -d "$pathcomp" ] ;
+ then
+ $mkdirprog "$pathcomp"
+ else
+ :
+ fi
+
+ pathcomp=$pathcomp/
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd "$dst" &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename "$dst"`
+ else
+ dstfile=`basename "$dst" $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename "$dst"`
+ else
+ :
+ fi
+
+# Make a couple of temp file names in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+ rmtmp=$dstdir/#rm.$$#
+
+# Trap to clean up temp files at exit.
+
+ trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
+ trap '(exit $?); exit' 1 2 13 15
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd "$src" "$dsttmp" &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
+
+# Now remove or move aside any old file at destination location. We try this
+# two ways since rm can't unlink itself on some systems and the destination
+# file might be busy for other reasons. In this case, the final cleanup
+# might fail but the new file should still install successfully.
+
+{
+ if [ -f "$dstdir/$dstfile" ]
+ then
+ $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
+ $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
+ {
+ echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
+ (exit 1); exit
+ }
+ else
+ :
+ fi
+} &&
+
+# Now rename the file to the real destination.
+
+ $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
+
+fi &&
+
+# The final little trick to "correctly" pass the exit status to the exit trap.
+
+{
+ (exit 0); exit
+}
diff --git a/patch_cmds/diffstat/makefile.in b/patch_cmds/diffstat/makefile.in
new file mode 100644
index 0000000..cf18c53
--- /dev/null
+++ b/patch_cmds/diffstat/makefile.in
@@ -0,0 +1,144 @@
+# $Id: makefile.in,v 1.29 2010/07/15 22:45:54 tom Exp $
+# Makefile-template for 'diffstat'
+
+THIS = diffstat
+
+#### Start of system configuration section. ####
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+DESTDIR = @DESTDIR@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+mandir = @mandir@
+
+CC = @CC@
+LINK = $(CC)
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+LINT = @LINT@
+CTAGS = @CTAGS@
+ETAGS = @ETAGS@
+
+CFLAGS = @CFLAGS@ @EXTRA_CFLAGS@
+CPPFLAGS = -I. -I$(srcdir) -DHAVE_CONFIG_H @CPPFLAGS@
+
+LIBS = @LIBS@
+LDFLAGS = @LDFLAGS@
+
+o = .@OBJEXT@
+x = @EXEEXT@
+
+BINDIR = $(DESTDIR)$(bindir)
+MANDIR = $(DESTDIR)$(mandir)
+
+#### End of system configuration section. ####
+
+SHELL = /bin/sh
+
+man1dir = $(MANDIR)/man1
+manext = 1
+
+PROG = $(THIS)$x
+
+SRC = CHANGES \
+ README $(THIS).c $(THIS).1 \
+ config_h.in install-sh \
+ makefile.in configure.in aclocal.m4 \
+ makefile.wnt
+
+PORTFILES = porting/getopt.c \
+ porting/getopt.h \
+ porting/system.h \
+ porting/wildcard.c
+
+TESTFILES = testing/README \
+ testing/run_test.sh \
+ testing/case0[1-5]*
+
+DISTFILES = configure config.guess config.sub $(SRC)
+
+.SUFFIXES: .c $o
+
+.c$o:
+ @RULE_CC@
+ @ECHO_CC@$(CC) -c $(CPPFLAGS) $(CFLAGS) $<
+
+all : $(PROG)
+
+$(PROG) : diffstat$o
+ @ECHO_LD@$(LINK) $(LDFLAGS) -o $@ diffstat$o $(LIBS)
+
+install : all installdirs
+ $(INSTALL_PROGRAM) $(PROG) $(BINDIR)/$(PROG)
+ $(INSTALL_DATA) $(srcdir)/$(THIS).1 $(man1dir)/$(THIS).$(manext)
+
+installdirs :
+ mkdir -p $(BINDIR) $(libdir) $(man1dir)
+
+uninstall :
+ rm -f $(BINDIR)/$(PROG) $(man1dir)/$(THIS).$(manext)
+
+mostlyclean :
+ rm -f *.o core *~ *.out *.err *.BAK *.atac
+
+clean : mostlyclean
+ rm -f $(PROG)
+
+distclean : clean
+ rm -f makefile config.log config.cache config.status config.h
+ rm -f tags TAGS # don't remove configure!
+
+realclean : distclean
+
+check : $(PROG)
+ $(SHELL) -c 'PATH=`pwd`:$${PATH}; export PATH; \
+ $(SHELL) $(srcdir)/testing/run_test.sh $(srcdir)/testing/case*.pat'
+
+lint :
+ $(LINT) $(CPPFLAGS) $(LINTOPTS) $(THIS).c
+
+tags :
+ $(CTAGS) $(THIS).c $(HDRS)
+
+@MAKE_UPPER_TAGS@TAGS :
+@MAKE_UPPER_TAGS@ $(ETAGS) $(THIS).c $(HDRS)
+
+dist: makefile $(DISTFILES)
+ # make a list of the files to distribute
+ echo $(THIS)-`sed \
+ -e '/"$$[A-Za-z]*: $(THIS)\.c.*$$"/!d' \
+ -e 's/^.*$(THIS)[^ ]*[ ]*//' \
+ -e 's/[ ].*$$//' \
+ -e q $(srcdir)/$(THIS).c` > .fname
+ rm -rf `cat .fname`
+ # contents of top directory
+ mkdir `cat .fname`
+ for file in $(DISTFILES); do \
+ ln $(srcdir)/$$file `cat .fname` \
+ || { echo copying $$file instead; cp -p $$file `cat .fname`; }; \
+ done
+ # contents of top/porting directory
+ mkdir `cat .fname`/porting
+ for file in $(PORTFILES); do \
+ ln $(srcdir)/$$file `cat .fname`/porting \
+ || { echo copying $$file instead; cp -p $$file `cat .fname`/porting; }; \
+ done
+ # contents of top/testing directory
+ mkdir `cat .fname`/testing
+ for file in $(TESTFILES); do \
+ ln $(srcdir)/$$file `cat .fname`/testing \
+ || { echo copying $$file instead; cp -p $$file `cat .fname`/testing; }; \
+ done
+ # tar and cleanup
+ tar -cf - `cat .fname` | gzip >`cat .fname`.tgz
+ rm -rf `cat .fname` .fname
+
+$(THIS).o : config.h
+
+$(SRC) :
diff --git a/patch_cmds/diffstat/makefile.wnt b/patch_cmds/diffstat/makefile.wnt
new file mode 100644
index 0000000..7fde72e
--- /dev/null
+++ b/patch_cmds/diffstat/makefile.wnt
@@ -0,0 +1,35 @@
+#
+# makefile for 'diffstat' on WIN32 using Microsoft Visual C++
+#
+# $Id: makefile.wnt,v 1.2 2009/09/01 00:33:28 tom Exp $
+#
+!include <ntwin32.mak>
+
+P = porting
+
+CFLAGS = $(cvars) $(cdebug) -nologo -G4 -W3 -I. -DWIN32 -I$P
+LDFLAGS = -nologo -pdb:none
+
+NAME = diffstat
+OBJ = $(NAME).obj \
+ $P/getopt.obj \
+ $P/wildcard.obj
+
+.c.obj:
+ $(cc) $(CFLAGS) -c $< -Fo$@
+
+all: $(NAME).exe
+
+$(NAME).exe: $(OBJ)
+ $(link) $(LDFLAGS) $(OBJ) setargv.obj $(ldebug) $(conlflags) $(conlibs) -out:$@ user32.lib
+
+$(OBJ) : #system.h
+
+install: $(NAME).exe
+ copy $(NAME).exe c:\com
+
+clean:
+ - del $(NAME).exe
+ - del /f/s/q *.obj
+ - del /f/s/q *.bak
+ - del /f/s/q *.pdb
diff --git a/patch_cmds/diffstat/package/debian/changelog b/patch_cmds/diffstat/package/debian/changelog
new file mode 100644
index 0000000..d48705d
--- /dev/null
+++ b/patch_cmds/diffstat/package/debian/changelog
@@ -0,0 +1,25 @@
+diffstat (1.55) unstable; urgency=low
+
+ * Add -R option.
+ * Documentation fixes.
+
+ -- Thomas E. Dickey <dickey@invisible-island.net> Tue, 03 Jan 2012 04:39:50 -0500
+
+diffstat (1.54) unstable; urgency=low
+
+ * Fix counts for -S/-D options.
+ * change source format to native.
+
+ -- Thomas E. Dickey <dickey@invisible-island.net> Sun, 10 Oct 2010 14:13:13 -0400
+
+diffstat (1.53) unstable; urgency=low
+
+ * Fix regression in "-c" option.
+
+ -- Thomas E. Dickey <dickey@invisible-island.net> Thu, 15 Jul 2010 19:39:36 -0400
+
+diffstat (1.52) unstable; urgency=low
+
+ * Add package scripts to upstream source, for test-builds.
+
+ -- Thomas E. Dickey <dickey@invisible-island.net> Thu, 15 Jul 2010 19:39:36 -0400
diff --git a/patch_cmds/diffstat/package/debian/compat b/patch_cmds/diffstat/package/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/patch_cmds/diffstat/package/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/patch_cmds/diffstat/package/debian/control b/patch_cmds/diffstat/package/debian/control
new file mode 100644
index 0000000..e1c0eed
--- /dev/null
+++ b/patch_cmds/diffstat/package/debian/control
@@ -0,0 +1,15 @@
+Source: diffstat
+Maintainer: Thomas E. Dickey <dickey@invisible-island.net>
+Section: devel
+Priority: extra
+Standards-Version: 3.8.4
+Build-Depends: debhelper (>= 5)
+Homepage: http://invisible-island.net/diffstat/
+
+Package: diffstat
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: generate C function prototypes and convert function definitions
+ Diffstat is is useful for reviewing large, complex patch files. It reads from
+ one or more input files which contain output from diff, producing a histogram
+ of the total lines changed for each file referenced.
diff --git a/patch_cmds/diffstat/package/debian/copyright b/patch_cmds/diffstat/package/debian/copyright
new file mode 100644
index 0000000..9b606c4
--- /dev/null
+++ b/patch_cmds/diffstat/package/debian/copyright
@@ -0,0 +1,109 @@
+Upstream source http://invisible-island.net/diffstat/diffstat.html
+
+/******************************************************************************
+ * Copyright 1994-2009,2010 by Thomas E. Dickey *
+ * All Rights Reserved. *
+ * *
+ * Permission to use, copy, modify, and distribute this software and its *
+ * documentation for any purpose and without fee is hereby granted, provided *
+ * that the above copyright notice appear in all copies and that both that *
+ * copyright notice and this permission notice appear in supporting *
+ * documentation, and that the name of the above listed copyright holder(s) *
+ * not be used in advertising or publicity pertaining to distribution of the *
+ * software without specific, written prior permission. *
+ * *
+ * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD *
+ * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND *
+ * FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE *
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR *
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ******************************************************************************/
+
+-------------------------------------------------------------------------------
+
+Files: aclocal.m4
+Licence: other-BSD
+Copyright: 2003-2009,2010 by Thomas E. Dickey
+ Permission is hereby granted, free of charge, to any person obtaining a
+ copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, distribute with modifications, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name(s) of the above copyright
+ holders shall not be used in advertising or otherwise to promote the
+ sale, use or other dealings in this Software without prior written
+ authorization.
+
+Files: install-sh
+Copyright: 1994 X Consortium
+Licence: other-BSD
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to
+ deal in the Software without restriction, including without limitation the
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+ TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ Except as contained in this notice, the name of the X Consortium shall not
+ be used in advertising or otherwise to promote the sale, use or other deal-
+ ings in this Software without prior written authorization from the X Consor-
+ tium.
+
+ FSF changes to this file are in the public domain.
+
+ Calling this script install-sh is preferred over install.sh, to prevent
+ `make' implicit rules from creating a file called install from it
+ when there is no Makefile.
+
+ This script is compatible with the BSD install script, but was written
+ from scratch. It can only install one file at a time, a restriction
+ shared with many OS's install programs.
+
+Files: debian/*
+Copyright: 2010 Thomas E. Dickey
+Licence: other-BSD
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose and without fee is hereby granted,
+ provided that the above copyright notice appear in all copies and that
+ both that copyright notice and this permission notice appear in
+ supporting documentation, and that the name of the above listed
+ copyright holder(s) not be used in advertising or publicity pertaining
+ to distribution of the software without specific, written prior
+ permission.
+
+ THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD
+ TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ AND FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE
+ LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+On Debian systems, the complete text of the GNU General
+Public License can be found in '/usr/share/common-licenses/GPL-2'
diff --git a/patch_cmds/diffstat/package/debian/docs b/patch_cmds/diffstat/package/debian/docs
new file mode 100644
index 0000000..e845566
--- /dev/null
+++ b/patch_cmds/diffstat/package/debian/docs
@@ -0,0 +1 @@
+README
diff --git a/patch_cmds/diffstat/package/debian/rules b/patch_cmds/diffstat/package/debian/rules
new file mode 100644
index 0000000..0d900e6
--- /dev/null
+++ b/patch_cmds/diffstat/package/debian/rules
@@ -0,0 +1,92 @@
+#!/usr/bin/make -f
+# MAde with the aid of dh_make, by Craig Small
+# Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess.
+# Some lines taken from debmake, by Cristoph Lameter.
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+# These are used for cross-compiling and for saving the configure script
+# from having to guess our platform (since we know it already)
+DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+CFLAGS =
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+ CFLAGS += -O0
+else
+ CFLAGS += -O2
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+ INSTALL_PROGRAM += -s
+endif
+
+
+configure: configure-stamp
+configure-stamp:
+ dh_testdir
+
+ CFLAGS="$(CFLAGS)" ./configure \
+ --host=$(DEB_HOST_GNU_TYPE) \
+ --build=$(DEB_BUILD_GNU_TYPE) \
+ --prefix=/usr \
+ --mandir=\$${prefix}/share/man \
+ --sysconfdir=/etc
+
+ touch configure-stamp
+
+build: build-stamp
+build-stamp: configure-stamp
+ dh_testdir
+
+ $(MAKE)
+
+ touch build-stamp
+
+clean:
+ dh_testdir
+ dh_testroot
+
+ [ ! -f Makefile ] || $(MAKE) clean
+
+ rm -f configure-stamp build-stamp install-stamp \
+ config.cache config.h config.status config.log makefile
+
+ rm -f *.o diffstat
+
+ dh_clean
+
+install: install-stamp
+install-stamp: build-stamp
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+ dh_installdirs
+
+ $(MAKE) install DESTDIR=$(CURDIR)/debian/diffstat
+
+ touch install-stamp
+
+# Build architecture-independent files here.
+binary-indep: build install
+# No binary-indep target.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+ dh_testdir
+ dh_testroot
+ dh_installdocs
+ dh_installexamples
+ dh_installchangelogs CHANGES
+ dh_strip
+ dh_compress
+ dh_fixperms
+ dh_installdeb
+ dh_shlibdeps
+ dh_gencontrol
+ dh_md5sums
+ dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install install-stamp
diff --git a/patch_cmds/diffstat/package/debian/source/format b/patch_cmds/diffstat/package/debian/source/format
new file mode 100644
index 0000000..89ae9db
--- /dev/null
+++ b/patch_cmds/diffstat/package/debian/source/format
@@ -0,0 +1 @@
+3.0 (native)
diff --git a/patch_cmds/diffstat/package/debian/watch b/patch_cmds/diffstat/package/debian/watch
new file mode 100644
index 0000000..716d237
--- /dev/null
+++ b/patch_cmds/diffstat/package/debian/watch
@@ -0,0 +1,4 @@
+version=3
+
+opts=passive ftp://invisible-island.net/cproto/cproto-(\d+)\.tgz \
+ debian uupdate
diff --git a/patch_cmds/diffstat/package/diffstat.spec b/patch_cmds/diffstat/package/diffstat.spec
new file mode 100644
index 0000000..99e91fe
--- /dev/null
+++ b/patch_cmds/diffstat/package/diffstat.spec
@@ -0,0 +1,54 @@
+Summary: diffstat - make histogram from diff-output
+%define AppProgram diffstat
+%define AppVersion 1.55
+# $XTermId: diffstat.spec,v 1.3 2010/10/10 18:09:56 tom Exp $
+Name: %{AppProgram}
+Version: %{AppVersion}
+Release: 1
+License: MIT
+Group: Applications/Development
+URL: ftp://invisible-island.net/%{AppProgram}
+Source0: %{AppProgram}-%{AppVersion}.tgz
+Packager: Thomas Dickey <dickey@invisible-island.net>
+
+%description
+Diffstat is is useful for reviewing large, complex patch files. It reads from
+one or more input files which contain output from diff, producing a histogram
+of the total lines changed for each file referenced.
+
+%prep
+
+%setup -q -n %{AppProgram}-%{AppVersion}
+
+%build
+
+INSTALL_PROGRAM='${INSTALL}' \
+ ./configure \
+ --target %{_target_platform} \
+ --prefix=%{_prefix} \
+ --bindir=%{_bindir} \
+ --libdir=%{_libdir} \
+ --mandir=%{_mandir}
+
+make
+
+%install
+[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+
+make install DESTDIR=$RPM_BUILD_ROOT
+
+strip $RPM_BUILD_ROOT%{_bindir}/%{AppProgram}
+
+%clean
+[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%{_prefix}/bin/%{AppProgram}
+%{_mandir}/man1/%{AppProgram}.*
+
+%changelog
+# each patch should add its ChangeLog entries here
+
+* Thu Jul 15 2010 Thomas Dickey
+- initial version
diff --git a/patch_cmds/diffstat/porting/getopt.c b/patch_cmds/diffstat/porting/getopt.c
new file mode 100644
index 0000000..39ed078
--- /dev/null
+++ b/patch_cmds/diffstat/porting/getopt.c
@@ -0,0 +1,79 @@
+/* ::[[ @(#) getopt.c 1.5 89/03/11 05:40:23 ]]:: */
+#ifndef LINT
+static const char Id[] = "$Id: getopt.c,v 1.2 2009/09/01 00:41:59 tom Exp $";
+#endif
+
+/*
+ * Here's something you've all been waiting for: the AT&T public domain
+ * source for getopt(3). It is the code which was given out at the 1985
+ * UNIFORUM conference in Dallas. I obtained it by electronic mail
+ * directly from AT&T. The people there assure me that it is indeed
+ * in the public domain.
+ *
+ * There is no manual page. That is because the one they gave out at
+ * UNIFORUM was slightly different from the current System V Release 2
+ * manual page. The difference apparently involved a note about the
+ * famous rules 5 and 6, recommending using white space between an option
+ * and its first argument, and not grouping options that have arguments.
+ * Getopt itself is currently lenient about both of these things White
+ * space is allowed, but not mandatory, and the last option in a group can
+ * have an argument. That particular version of the man page evidently
+ * has no official existence, and my source at AT&T did not send a copy.
+ * The current SVR2 man page reflects the actual behavor of this getopt.
+ * However, I am not about to post a copy of anything licensed by AT&T.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define ERR(szz,czz) if(opterr){fprintf(stderr,"%s%s%c\n",argv[0],szz,czz);}
+
+int opterr = 1;
+int optind = 1;
+int optopt;
+char *optarg;
+
+int
+getopt(int argc, char *const *argv, const char *opts)
+{
+ static int sp = 1;
+ register int c;
+ register char *cp;
+
+ if (sp == 1) {
+ if (optind >= argc ||
+ argv[optind][0] != '-' || argv[optind][1] == '\0')
+ return (EOF);
+ else if (strcmp(argv[optind], "--") == 0) {
+ optind++;
+ return (EOF);
+ }
+ }
+ optopt = c = argv[optind][sp];
+ if (c == ':' || (cp = strchr(opts, c)) == NULL) {
+ ERR(": illegal option -- ", c);
+ if (argv[optind][++sp] == '\0') {
+ optind++;
+ sp = 1;
+ }
+ return ('?');
+ }
+ if (*++cp == ':') {
+ if (argv[optind][sp + 1] != '\0')
+ optarg = &argv[optind++][sp + 1];
+ else if (++optind >= argc) {
+ ERR(": option requires an argument -- ", c);
+ sp = 1;
+ return ('?');
+ } else
+ optarg = argv[optind++];
+ sp = 1;
+ } else {
+ if (argv[optind][++sp] == '\0') {
+ sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return (c);
+}
diff --git a/patch_cmds/diffstat/porting/getopt.h b/patch_cmds/diffstat/porting/getopt.h
new file mode 100644
index 0000000..e02470d
--- /dev/null
+++ b/patch_cmds/diffstat/porting/getopt.h
@@ -0,0 +1,4 @@
+extern char *optarg;
+extern int optind, opterr;
+
+int getopt (int argc, char *const*argv, const char *options);
diff --git a/patch_cmds/diffstat/porting/system.h b/patch_cmds/diffstat/porting/system.h
new file mode 100644
index 0000000..02dc60e
--- /dev/null
+++ b/patch_cmds/diffstat/porting/system.h
@@ -0,0 +1,85 @@
+/* $Id: system.h,v 1.1 2002/11/22 22:36:56 tom Exp $ */
+
+#ifdef HAVE_CONFIG_H
+
+# include "config.h"
+# define SYS_UNIX 1
+
+#else
+ /* provide values for non-UNIX systems */
+# if defined(vms)
+# include <stsdef.h>
+# define SYS_VMS 1
+# define EXIT_SUCCESS (STS$M_INHIB_MSG | STS$K_SUCCESS)
+# define EXIT_FAILURE (STS$M_INHIB_MSG | STS$K_ERROR)
+# endif
+
+# if defined(MSDOS) || defined(__MSDOS__)
+# define SYS_MSDOS 1
+# endif
+
+# if !defined(SYS_VMS) || !defined(SYS_MSDOS) || defined(WIN32)
+# define SYS_UNIX 1 /* assume we're autoconfiguring */
+# endif
+
+#define HAVE_STRCHR 1
+
+#endif /* HAVE_CONFIG_H */
+
+#ifndef HAVE_GETOPT_H
+#define HAVE_GETOPT_H 0
+#endif
+
+#ifndef HAVE_MALLOC_H
+#define HAVE_MALLOC_H 0
+#endif
+
+#ifndef HAVE_STDLIB_H
+#define HAVE_STDLIB_H 1
+#endif
+
+#ifndef HAVE_STRING_H
+#define HAVE_STRING_H 1
+#endif
+
+#ifndef SYS_MSDOS
+#define SYS_MSDOS 0
+#endif
+
+#ifndef SYS_UNIX
+#define SYS_UNIX 0
+#endif
+
+#ifndef SYS_VMS
+#define SYS_VMS 0
+#endif
+
+#ifndef HAVE_GETOPT_HEADER
+#define HAVE_GETOPT_HEADER 0
+#endif
+
+#ifndef PRINT_ROUNDS_DOWN
+#define PRINT_ROUNDS_DOWN 0
+#endif
+
+#ifdef lint
+#define typeCalloc(type,elts) (type *)(elts)
+#else
+#define typeCalloc(type,elts) (type *)calloc(elts,sizeof(type))
+#endif
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+#undef EOS
+#define EOS '\0'
+
+ /* On VMS and MSDOS we can fake wildcards by embedding a directory
+ * scanning loop...
+ */
+#if !SYS_UNIX
+extern int has_wildcard(char *);
+extern int expand_wildcard(char *, int);
+#endif
diff --git a/patch_cmds/diffstat/porting/wildcard.c b/patch_cmds/diffstat/porting/wildcard.c
new file mode 100644
index 0000000..0b7c494
--- /dev/null
+++ b/patch_cmds/diffstat/porting/wildcard.c
@@ -0,0 +1,109 @@
+#ifndef NO_IDENT
+static char *Id = "$Id: wildcard.c,v 1.1 2004/05/03 13:12:10 tom Exp $";
+#endif
+
+/*
+ * wildcard.c - perform wildcard expansion for non-UNIX configurations
+ */
+
+#include "system.h"
+
+#if HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#if HAVE_STRING_H
+# include <string.h>
+#endif
+
+#if SYS_MSDOS || SYS_OS2
+# if SYS_MSDOS
+# include <dos.h>
+# include <dir.h> /* defines MAXPATH */
+# define FILENAME_MAX MAXPATH
+# endif
+# define DeclareFind(p) struct find_t p
+# define DirEntryStr(p) p.name
+# define DirFindFirst(path,p) (!_dos_findfirst(path, 0, &p))
+# define DirFindNext(p) (!_dos_findnext(&p))
+#endif
+
+#if SYS_VMS
+
+#include <starlet.h> /* DEC-C (e.g., sys$parse) */
+#include <stdio.h> /* perror */
+
+#include <rms.h>
+#include <descrip.h>
+
+#endif /* SYS_VMS */
+
+int
+has_wildcard(char *path)
+{
+#if SYS_VMS
+ return (strstr(path, "...") != 0
+ || strchr(path, '*') != 0
+ || strchr(path, '?') != 0);
+#else /* SYS_MSDOS, SYS_OS2 */
+ return (strchr(path, '*') != 0
+ || strchr(path, '?') != 0);
+#endif
+}
+
+int
+expand_wildcard(char *path, int initiate)
+{
+#if SYS_MSDOS || SYS_OS2
+ static DeclareFind(p);
+ static char temp[FILENAME_MAX + 1];
+ register char *leaf;
+
+ if ((leaf = strchr(path, '/')) == 0
+ && (leaf = strchr(path, '\\')) == 0)
+ leaf = path;
+ else
+ leaf++;
+
+ if ((initiate && DirFindFirst(strcpy(temp, path), p))
+ || DirFindNext(p)) {
+ (void) strcpy(leaf, DirEntryStr(p));
+ return TRUE;
+ }
+#endif /* SYS_MSDOS || SYS_OS2 */
+#if SYS_VMS
+ static struct FAB zfab;
+ static struct NAM znam;
+ static char my_esa[NAM$C_MAXRSS]; /* expanded: SYS$PARSE */
+ static char my_rsa[NAM$C_MAXRSS]; /* expanded: SYS$SEARCH */
+
+ if (initiate) {
+ zfab = cc$rms_fab;
+ zfab.fab$l_fop = FAB$M_NAM;
+ zfab.fab$l_nam = &znam; /* FAB => NAM block */
+ zfab.fab$l_dna = "*.*;"; /* Default-selection */
+ zfab.fab$b_dns = strlen(zfab.fab$l_dna);
+
+ zfab.fab$l_fna = path;
+ zfab.fab$b_fns = strlen(path);
+
+ znam = cc$rms_nam;
+ znam.nam$b_ess = sizeof(my_esa);
+ znam.nam$l_esa = my_esa;
+ znam.nam$b_rss = sizeof(my_rsa);
+ znam.nam$l_rsa = my_rsa;
+
+ if (sys$parse(&zfab) != RMS$_NORMAL) {
+ perror(path);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (sys$search(&zfab) == RMS$_NORMAL) {
+ strncpy(path, my_rsa, znam.nam$b_rsl)[znam.nam$b_rsl] = '\0';
+ return (TRUE);
+ }
+#endif /* SYS_VMS */
+#if SYS_MSDOS
+#endif
+ return FALSE;
+}
diff --git a/patch_cmds/diffstat/testing/case01.pat b/patch_cmds/diffstat/testing/case01.pat
new file mode 100644
index 0000000..fe0385d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01.pat
@@ -0,0 +1,417 @@
+--------------------------------------------------------------------------------
+--- /build/x11r6/XFree86-3.1.2Cf/xc/config/cf/hp.cf Sat Feb 10 13:55:35 1996
++++ /build/x11r6/XFree86-current/xc/config/cf/hp.cf Mon Feb 19 19:10:15 1996
+@@ -59,9 +59,16 @@
+ #define Malloc0ReturnsNull YES
+
+ #ifdef __hp9000s800
++#if HasGcc2
++#define OptimizedCDebugFlags -O
++#define DefaultCCOptions
++#define SharedLibraryCCOptions -fPIC
++#define PositionIndependentCFlags -fPIC
++#else
+ #define OptimizedCDebugFlags +O1
+ #define DefaultCCOptions -Ae +ESlit
+ #define SharedLibraryCCOptions -Ae
++#endif
+ #define StandardDefines -Dhpux -DSYSV
+ #define ServerExtraDefines -DXOS -DBSTORE -DSOFTWARE_CURSOR -DNO_ALLOCA -DSCREEN_PIXMAPS -DMERGE_SAVE_UNDERS -DHAS_IFREQ -DFORCE_SEPARATE_PRIVATE
+
+--- /build/x11r6/XFree86-3.1.2Cf/xc/config/cf/hpLib.rules Sat Jan 6 08:11:01 1996
++++ /build/x11r6/XFree86-current/xc/config/cf/hpLib.rules Mon Feb 19 19:11:14 1996
+@@ -29,8 +29,10 @@
+ #define InstLibFlags -m 0555
+ #endif
+ #ifndef UseInstalled
++#ifndef HasGcc2
+ /* assert: LdPostLib pulls in -L$(USRLIBDIR), so it doesn't need to be here */
+ #define ExtraLoadFlags -Wl,+s,+b,$(USRLIBDIR)
++#endif
+ #endif
+
+ /*
+--- /build/x11r6/XFree86-3.1.2Cf/xc/config/imake/imakemdep.h Sat Jan 6 08:11:01 1996
++++ /build/x11r6/XFree86-current/xc/config/imake/imakemdep.h Mon Feb 19 19:15:01 1996
+@@ -41,6 +41,10 @@
+ * These will be passed to the compile along with the contents of the
+ * make variable BOOTSTRAPCFLAGS.
+ */
++#if defined(clipper) || defined(__clipper__)
++#define imake_ccflags "-O -DSYSV -DBOOTSTRAPCFLAGS=-DSYSV"
++#endif
++
+ #ifdef hpux
+ #ifdef hp9000s800
+ #define imake_ccflags "-DSYSV"
+@@ -224,6 +228,9 @@
+ #ifdef apollo
+ #define DEFAULT_CPP "/usr/lib/cpp"
+ #endif
++#if defined(clipper) || defined(__clipper__)
++#define DEFAULT_CPP "/usr/lib/cpp"
++#endif
+ #if defined(_IBMR2) && !defined(DEFAULT_CPP)
+ #define DEFAULT_CPP "/usr/lpp/X11/Xamples/util/cpp/cpp"
+ #endif
+@@ -529,6 +536,12 @@
+ struct symtab predefs[] = {
+ #ifdef apollo
+ {"apollo", "1"},
++#endif
++#if defined(clipper) || defined(__clipper__)
++ {"clipper", "1"},
++ {"__clipper__", "1"},
++ {"clix", "1"},
++ {"__clix__", "1"},
+ #endif
+ #ifdef ibm032
+ {"ibm032", "1"},
+--- /build/x11r6/XFree86-3.1.2Cf/xc/config/makedepend/main.c Fri Jan 26 11:43:22 1996
++++ /build/x11r6/XFree86-current/xc/config/makedepend/main.c Mon Feb 19 19:16:06 1996
+@@ -570,7 +570,7 @@
+ return(file);
+ }
+
+-#if defined(USG) && !defined(CRAY) && !defined(SVR4) && !defined(__EMX__)
++#if defined(USG) && !defined(CRAY) && !defined(SVR4) && !defined(__EMX__) && !defined(clipper) && !defined(__clipper__)
+ int rename (from, to)
+ char *from, *to;
+ {
+--- /build/x11r6/XFree86-3.1.2Cf/xc/include/Xos.h Fri Jan 26 11:43:22 1996
++++ /build/x11r6/XFree86-current/xc/include/Xos.h Mon Feb 19 19:18:23 1996
+@@ -77,6 +77,7 @@
+
+ #ifndef X_NOT_STDC_ENV
+
++#if !(defined(sun) && !defined(SVR4)) /* 'index' is problem with K&R */
+ #include <string.h>
+ #ifndef index
+ #define index(s,c) (strchr((s),(c)))
+@@ -84,10 +85,14 @@
+ #ifndef rindex
+ #define rindex(s,c) (strrchr((s),(c)))
+ #endif
++#endif
+
+ #else
+
+ #ifdef SYSV
++#if defined(clipper) || defined(__clipper__)
++#include <malloc.h>
++#endif
+ #include <string.h>
+ #define index strchr
+ #define rindex strrchr
+@@ -149,7 +154,7 @@
+ #ifdef CRAY
+ #undef word
+ #endif /* CRAY */
+-#if defined(USG) && !defined(CRAY) && !defined(MOTOROLA) && !defined(uniosu) && !defined(__sxg__)
++#if defined(USG) && !defined(CRAY) && !defined(MOTOROLA) && !defined(uniosu) && !defined(__sxg__) && !defined(clipper) && !defined(__clipper__)
+ struct timeval {
+ long tv_sec;
+ long tv_usec;
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/XIE/mixie/import/mijpeg.c Sun Apr 17 20:34:54 1994
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/XIE/mixie/import/mijpeg.c Mon Feb 19 18:48:31 1996
+@@ -114,7 +114,7 @@
+
+ /*
+ * routines referenced by other DDXIE modules
+-/*
++ */
+ int CreateIPhotoJpegBase();
+ int InitializeIPhotoJpegBase();
+ int InitializeICPhotoJpegBase();
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/XIE/mixie/process/mpgeomaa.c Sun Apr 17 20:35:19 1994
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/XIE/mixie/process/mpgeomaa.c Mon Feb 19 18:49:43 1996
+@@ -242,7 +242,7 @@
+ }
+ }
+ /*------------------------------------------------------------------------
+-/*------------------------------------------------------------------------
++--------------------------------------------------------------------------
+ ---------------------------- initialize peTex . . . ----------------------
+ ------------------------------------------------------------------------*/
+ static int InitializeGeomAA(flo,ped)
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/XIE/mixie/process/mpgeomnn.c Sat Jan 6 08:11:01 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/XIE/mixie/process/mpgeomnn.c Mon Feb 19 18:50:29 1996
+@@ -259,7 +259,7 @@
+ }
+
+ /*------------------------------------------------------------------------
+-/*------------------------------------------------------------------------
++--------------------------------------------------------------------------
+ ---------------------------- initialize peTex . . . ----------------------
+ ------------------------------------------------------------------------*/
+ static int InitializeGeomNN(flo,ped)
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/hp/input/drivers/hil_driver.c Mon Jan 30 23:07:07 1995
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/hp/input/drivers/hil_driver.c Mon Feb 19 18:51:11 1996
+@@ -431,7 +431,7 @@
+ return FALSE;
+
+ id = describe[0];
+-/* printf("fd is %d errno is %d id is %x\n", fd, errno, id); /* */
++/* printf("fd is %d errno is %d id is %x\n", fd, errno, id); */
+
+ num_axes = (describe[1] & HIL_NUM_AXES);
+ if (id == NINE_KNOB_ID && num_axes != 3) id = QUAD_ID;
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/hp/input/hpKeyMap.c Mon Jan 30 23:06:55 1995
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/hp/input/hpKeyMap.c Mon Feb 19 18:52:20 1996
+@@ -85,7 +85,7 @@
+ /* code values in comments at line end are actual value reported on HIL.
+ REMEMBER, there is an offset of MIN_KEYCODE+2 applied to this table!
+ The PS2 keyboard table begins at offset 0, the 46021A table begins with
+- the third row. *./
++ the third row. */
+ /* Extend Char Right -- a.k.a. Kanji? */
+ XK_Control_R, NoSymbol, NoSymbol, NoSymbol, /* 0x00 */
+ NoSymbol, NoSymbol, NoSymbol, NoSymbol, /* 0x01 */
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/accel/i128/i128scrin.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/accel/i128/i128scrin.c Mon Feb 19 18:53:02 1996
+@@ -348,7 +348,7 @@
+ pScreen->DestroyColormap = (DestroyColormapProcPtr)NoopDDA;
+ pScreen->ResolveColor = cfbResolveColor;
+ pScreen->BitmapToRegion = mfbPixmapToRegion;
+-#if 0 /* What's this for?! /* *TO*DO* */
++#if 0 /* What's this for?! *TO*DO* */
+ pScreen->BlockHandler = i128BlockHandler;
+ #endif
+
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c Mon Feb 19 18:53:37 1996
+@@ -351,7 +351,7 @@
+ pScreen->DestroyColormap = (DestroyColormapProcPtr)NoopDDA;
+ pScreen->ResolveColor = cfbResolveColor;
+ pScreen->BitmapToRegion = mfbPixmapToRegion;
+-#if 0 /* What's this for?! /* *TO*DO* */
++#if 0 /* What's this for?! *TO*DO* */
+ pScreen->BlockHandler = p9000BlockHandler;
+ #endif
+
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h Mon Feb 19 18:54:57 1996
+@@ -8,7 +8,7 @@
+ * Hamish Coleman 11/93 hamish@zot.apana.org.au
+ *
+ * derived from:
+- * bdm2/hgc1280/*
++ * bdm2/hgc1280/...
+ * Pascal Haible 8/93, haible@izfm.uni-stuttgart.de
+ *
+ * see mono/COPYRIGHT for copyright and disclaimers.
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c Mon Feb 19 18:55:33 1996
+@@ -8,12 +8,12 @@
+ * Hamish Coleman 11/93 hamish@zot.apana.org.au
+ *
+ * derived from:
+- * bdm2/hgc1280/*
++ * bdm2/hgc1280/...
+ * Pascal Haible 8/93, haible@izfm.uni-stuttgart.de
+- * hga2/*
++ * hga2/...
+ * Author: Davor Matic, dmatic@athena.mit.edu
+ * and
+- * vga256/*
++ * vga256/...
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * Thanks to Herb Peyerl (hpeyerl@novatel.ca) for the information on
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c Mon Feb 19 18:55:54 1996
+@@ -6,10 +6,10 @@
+ * mono/driver/hgc1280/hgc1280driv.c
+ *
+ * derived from:
+- * hga2/*
++ * hga2/...
+ * Author: Davor Matic, dmatic@athena.mit.edu
+ * and
+- * vga256/*
++ * vga256/...
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * see mono/COPYRIGHT for copyright and disclaimers.
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c Mon Feb 19 18:56:15 1996
+@@ -7,10 +7,10 @@
+ * mono/driver/sigma/sigmadriv.c
+ *
+ * Parts derived from:
+- * hga2/*
++ * hga2/...
+ * Author: Davor Matic, dmatic@athena.mit.edu
+ * and
+- * vga256/*
++ * vga256/...
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * see mono/COPYRIGHT for copyright and disclaimers.
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/mono/mono.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/mono/mono.c Mon Feb 19 18:56:58 1996
+@@ -6,10 +6,10 @@
+ * mono/mono/mono.c
+ *
+ * derived from:
+- * hga2/*
++ * hga2/...
+ * Author: Davor Matic, dmatic@athena.mit.edu
+ * and
+- * vga256/*
++ * vga256/...
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * see mono/COPYRIGHT for copyright and disclaimers.
+@@ -512,7 +512,7 @@
+ DDXPointRec pixPt; /* Point: upper left corner */
+ PixmapPtr pspix; /* Pointer to the pixmap of the saved screen */
+ ScreenPtr pScreen = savepScreen; /* This is the 'old' Screen:
+- /* real screen on leave, dummy on enter */
++ real screen on leave, dummy on enter */
+
+ /* Set up pointer to the saved pixmap (pspix) only if not resetting
+ and not exiting */
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/mono/mono.h Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/mono/mono.h Mon Feb 19 18:57:19 1996
+@@ -6,10 +6,10 @@
+ * mono/mono/mono.h
+ *
+ * derived from:
+- * hga2/*
++ * hga2/...
+ * Author: Davor Matic, dmatic@athena.mit.edu
+ * and
+- * vga256/*
++ * vga256/...
+ * Copyright 1990,91 by Thomas Roell, Dinkelscherben, Germany.
+ *
+ * see mono/COPYRIGHT for copyright and disclaimers.
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c Mon Feb 19 18:57:57 1996
+@@ -27,7 +27,7 @@
+
+ #include "OScompiler.h"
+
+-/* #include "ibmIOArch.h" /* GJA */
++/* #include "ibmIOArch.h" -- GJA */
+
+ #include "vgaVideo.h"
+
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h Fri Feb 9 13:08:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h Mon Feb 19 18:58:43 1996
+@@ -679,7 +679,7 @@
+ #define GEN_TEST_CNT_VALUE 0x3f000000 /* Mach64CT/ET */
+ #define GEN_TEST_CC_EN 0x40000000 /* Mach64GX/CX */
+ #define GEN_TEST_CC_STROBE 0x80000000 /* Mach64GX/CX */
+-/* ? 0xc0000000 /* Mach64CT/ET */
++/* ? 0xc0000000 */ /* Mach64CT/ET */
+ #define CONFIG_CNTL 0x6aec
+ #define CFG_MEM_AP_SIZE 0x00000003
+ #define CFG_MEM_VGA_AP_EN 0x00000004
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c Fri Feb 9 13:08:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c Mon Feb 19 18:59:33 1996
+@@ -126,7 +126,7 @@
+ /* For the lower byte of the 32-bit color registers, there is no safe
+ * invalid value. We just set them to a specific value (making sure
+ * we don't write to non-existant color registers).
+- *
++ */
+ cirrusBackgroundColorShadow = 0xffffffff; /* Defeat the macros. */
+ cirrusForegroundColorShadow = 0xffffffff;
+ if (cirrusChip >= CLGD5422 && cirrusChip <= CLGD5430) {
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c Mon Feb 19 19:00:02 1996
+@@ -22,7 +22,7 @@
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Simon P. Cooper, <scooper@vizlab.rutgers.edu>
+- *
++ */
+ /* $XConsortium: cir_cursor.c /main/8 1995/11/13 08:20:54 kaleb $ */
+
+ #define CIRRUS_DEBUG_CURSOR
+--- /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c Mon Feb 5 12:03:00 1996
++++ /build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c Mon Feb 19 19:00:52 1996
+@@ -1402,7 +1402,7 @@
+ case OTI37C:
+ default:
+ #ifndef MONOVGA
+- /* new->std.CRTC[19] = vga256InfoRec.virtualX >> 3; /* 3 in byte mode */
++ /* new->std.CRTC[19] = vga256InfoRec.virtualX >> 3; -- 3 in byte mode */
+ /* much clearer as 0x01 than 0x41, seems odd though... */
+ new->std.Attribute[16] = 0x01;
+ if ( new->std.NoClock >= 0 )
+--- /build/x11r6/XFree86-3.1.2Cf/xc/test/xsuite/xtest/src/bin/mc/files.c Sun Apr 17 21:00:20 1994
++++ /build/x11r6/XFree86-current/xc/test/xsuite/xtest/src/bin/mc/files.c Mon Feb 19 19:02:49 1996
+@@ -95,7 +95,7 @@
+ char buf[BUFSIZ];
+
+ /*
+- * Look for a corresponding file with name lib/mc/*.mc .
++ * Look for a corresponding file with name lib/mc/{*}.mc .
+ */
+ (void) sprintf(buf, "mc/%s", file);
+ file = buf;
+--- /build/x11r6/XFree86-3.1.2Cf/xc/util/patch/malloc.c Wed Aug 15 01:13:33 1990
++++ /build/x11r6/XFree86-current/xc/util/patch/malloc.c Mon Feb 19 19:04:28 1996
+@@ -30,10 +30,8 @@
+ * go in the first int of the block, and the returned pointer will point
+ * to the second.
+ *
+-#ifdef MSTATS
+ * nmalloc[i] is the difference between the number of mallocs and frees
+ * for a given block size.
+-#endif /* MSTATS */
+ */
+
+ #define ISALLOC ((char) 0xf7) /* magic byte that implies allocation */
+@@ -208,7 +206,7 @@
+ if (--nblks <= 0) break;
+ CHAIN ((struct mhead *) cp) = (struct mhead *) (cp + siz);
+ cp += siz;}
+-/* CHAIN ((struct mhead *) cp) = 0; /* since sbrk() returns cleared core, this is already set */
++/* CHAIN ((struct mhead *) cp) = 0; -- since sbrk() returns cleared core, this is already set */
+ }
+
+ static
+@@ -449,10 +447,10 @@
+ return (1 << (p -> mh_index + 3)) - sizeof *p;
+ /**/
+ /* if (p -> mh_index >= 13)
+-/* return (1 << (p -> mh_index + 3)) - sizeof *p;
+-/* else
+-/* return p -> mh_size;
+-/**/
++ * return (1 << (p -> mh_index + 3)) - sizeof *p;
++ * else
++ * return p -> mh_size;
++ */
+ #endif /* rcheck */
+ }
+
+--- /build/x11r6/XFree86-3.1.2Cf/xc/util/patch/pch.c Sat Jan 6 08:11:01 1996
++++ /build/x11r6/XFree86-current/xc/util/patch/pch.c Mon Feb 19 19:05:12 1996
+@@ -1,5 +1,5 @@
+ /* oldHeader: pch.c,v 2.0.1.7 88/06/03 15:13:28 lwall Locked $
+-/* $XConsortium: pch.c,v 3.3 94/09/14 21:22:55 gildea Exp $
++ * $XConsortium: pch.c,v 3.3 94/09/14 21:22:55 gildea Exp $
+ *
+ * Revision 2.0.2.0 90/05/01 22:17:51 davison
+ * patch12u: unidiff support added
+--- /build/x11r6/XFree86-3.1.2Cf/xc/config/cf/Imake.cf Fri Jan 26 11:43:22 1996
++++ /build/x11r6/XFree86-current/xc/config/cf/Imake.cf Mon Feb 19 19:13:58 1996
+@@ -19,6 +19,13 @@
+ * 4. Create a .cf file with the name given by MacroFile.
+ */
+
++#if defined(clipper) || defined(__clipper__)
++# undef clipper
++# define MacroIncludeFile <ingr.cf>
++# define MacroFile ingr.cf
++# define IngrArchitecture
++#endif /* clipper */
++
+ #ifdef ultrix
+ # define MacroIncludeFile <ultrix.cf>
+ # define MacroFile ultrix.cf
diff --git a/patch_cmds/diffstat/testing/case01.ref b/patch_cmds/diffstat/testing/case01.ref
new file mode 100644
index 0000000..50e2e5e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01.ref
@@ -0,0 +1,28 @@
+ config/cf/Imake.cf | 7 +++++
+ config/cf/hp.cf | 7 +++++
+ config/cf/hpLib.rules | 2 +
+ config/imake/imakemdep.h | 13 ++++++++++
+ config/makedepend/main.c | 2 -
+ include/Xos.h | 7 ++++-
+ programs/Xserver/XIE/mixie/import/mijpeg.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 -
+ programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 -
+ programs/Xserver/hw/hp/input/hpKeyMap.c | 2 -
+ programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 -
+ programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 +--
+ programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 -
+ test/xsuite/xtest/src/bin/mc/files.c | 2 -
+ util/patch/malloc.c | 12 +++------
+ util/patch/pch.c | 2 -
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01R.ref b/patch_cmds/diffstat/testing/case01R.ref
new file mode 100644
index 0000000..f3eec8f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01R.ref
@@ -0,0 +1,28 @@
+ config/cf/Imake.cf | 7 -----
+ config/cf/hp.cf | 7 -----
+ config/cf/hpLib.rules | 2 -
+ config/imake/imakemdep.h | 13 ----------
+ config/makedepend/main.c | 2 -
+ include/Xos.h | 7 -----
+ programs/Xserver/XIE/mixie/import/mijpeg.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 -
+ programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 -
+ programs/Xserver/hw/hp/input/hpKeyMap.c | 2 -
+ programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 -
+ programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 +--
+ programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 -
+ test/xsuite/xtest/src/bin/mc/files.c | 2 -
+ util/patch/malloc.c | 12 +++++----
+ util/patch/pch.c | 2 -
+ 27 files changed, 36 insertions(+), 68 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01Rp0.ref b/patch_cmds/diffstat/testing/case01Rp0.ref
new file mode 100644
index 0000000..b7df45e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01Rp0.ref
@@ -0,0 +1,28 @@
+ /build/x11r6/XFree86-3.1.2Cf/xc/config/cf/Imake.cf | 7 -----
+ /build/x11r6/XFree86-3.1.2Cf/xc/config/cf/hp.cf | 7 -----
+ /build/x11r6/XFree86-3.1.2Cf/xc/config/cf/hpLib.rules | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/config/imake/imakemdep.h | 13 ----------
+ /build/x11r6/XFree86-3.1.2Cf/xc/config/makedepend/main.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/include/Xos.h | 7 -----
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/XIE/mixie/import/mijpeg.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/hp/input/hpKeyMap.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 +--
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 +--
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 +--
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/test/xsuite/xtest/src/bin/mc/files.c | 2 -
+ /build/x11r6/XFree86-3.1.2Cf/xc/util/patch/malloc.c | 12 +++++----
+ /build/x11r6/XFree86-3.1.2Cf/xc/util/patch/pch.c | 2 -
+ 27 files changed, 36 insertions(+), 68 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01b.ref b/patch_cmds/diffstat/testing/case01b.ref
new file mode 100644
index 0000000..50e2e5e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01b.ref
@@ -0,0 +1,28 @@
+ config/cf/Imake.cf | 7 +++++
+ config/cf/hp.cf | 7 +++++
+ config/cf/hpLib.rules | 2 +
+ config/imake/imakemdep.h | 13 ++++++++++
+ config/makedepend/main.c | 2 -
+ include/Xos.h | 7 ++++-
+ programs/Xserver/XIE/mixie/import/mijpeg.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 -
+ programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 -
+ programs/Xserver/hw/hp/input/hpKeyMap.c | 2 -
+ programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 -
+ programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 +--
+ programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 -
+ test/xsuite/xtest/src/bin/mc/files.c | 2 -
+ util/patch/malloc.c | 12 +++------
+ util/patch/pch.c | 2 -
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01f0.ref b/patch_cmds/diffstat/testing/case01f0.ref
new file mode 100644
index 0000000..729257c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01f0.ref
@@ -0,0 +1,28 @@
+ config/cf/Imake.cf | 7 7 + 0 - 0 !
+ config/cf/hp.cf | 7 7 + 0 - 0 !
+ config/cf/hpLib.rules | 2 2 + 0 - 0 !
+ config/imake/imakemdep.h | 13 13 + 0 - 0 !
+ config/makedepend/main.c | 2 1 + 1 - 0 !
+ include/Xos.h | 7 6 + 1 - 0 !
+ programs/Xserver/XIE/mixie/import/mijpeg.c | 2 1 + 1 - 0 !
+ programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 1 + 1 - 0 !
+ programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 1 + 1 - 0 !
+ programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 1 + 1 - 0 !
+ programs/Xserver/hw/hp/input/hpKeyMap.c | 2 1 + 1 - 0 !
+ programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 1 + 1 - 0 !
+ programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 1 + 1 - 0 !
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 1 + 1 - 0 !
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 3 + 3 - 0 !
+ programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 2 + 2 - 0 !
+ programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 2 + 2 - 0 !
+ programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 3 + 3 - 0 !
+ programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 2 + 2 - 0 !
+ programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 1 + 1 - 0 !
+ programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 1 + 1 - 0 !
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 1 + 1 - 0 !
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 1 + 1 - 0 !
+ programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 1 + 1 - 0 !
+ test/xsuite/xtest/src/bin/mc/files.c | 2 1 + 1 - 0 !
+ util/patch/malloc.c | 12 5 + 7 - 0 !
+ util/patch/pch.c | 2 1 + 1 - 0 !
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01k.ref b/patch_cmds/diffstat/testing/case01k.ref
new file mode 100644
index 0000000..50e2e5e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01k.ref
@@ -0,0 +1,28 @@
+ config/cf/Imake.cf | 7 +++++
+ config/cf/hp.cf | 7 +++++
+ config/cf/hpLib.rules | 2 +
+ config/imake/imakemdep.h | 13 ++++++++++
+ config/makedepend/main.c | 2 -
+ include/Xos.h | 7 ++++-
+ programs/Xserver/XIE/mixie/import/mijpeg.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 -
+ programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 -
+ programs/Xserver/hw/hp/input/hpKeyMap.c | 2 -
+ programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 -
+ programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 +--
+ programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 -
+ test/xsuite/xtest/src/bin/mc/files.c | 2 -
+ util/patch/malloc.c | 12 +++------
+ util/patch/pch.c | 2 -
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01p1.ref b/patch_cmds/diffstat/testing/case01p1.ref
new file mode 100644
index 0000000..97dd130
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01p1.ref
@@ -0,0 +1,28 @@
+ build/x11r6/XFree86-current/xc/config/cf/Imake.cf | 7 +++++
+ build/x11r6/XFree86-current/xc/config/cf/hp.cf | 7 +++++
+ build/x11r6/XFree86-current/xc/config/cf/hpLib.rules | 2 +
+ build/x11r6/XFree86-current/xc/config/imake/imakemdep.h | 13 ++++++++++
+ build/x11r6/XFree86-current/xc/config/makedepend/main.c | 2 -
+ build/x11r6/XFree86-current/xc/include/Xos.h | 7 ++++-
+ build/x11r6/XFree86-current/xc/programs/Xserver/XIE/mixie/import/mijpeg.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/hp/input/hpKeyMap.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 +--
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 +--
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 +--
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 -
+ build/x11r6/XFree86-current/xc/programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 -
+ build/x11r6/XFree86-current/xc/test/xsuite/xtest/src/bin/mc/files.c | 2 -
+ build/x11r6/XFree86-current/xc/util/patch/malloc.c | 12 +++------
+ build/x11r6/XFree86-current/xc/util/patch/pch.c | 2 -
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01p9.ref b/patch_cmds/diffstat/testing/case01p9.ref
new file mode 100644
index 0000000..cf6a8eb
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01p9.ref
@@ -0,0 +1,28 @@
+ Imake.cf | 7 +++++++
+ Xos.h | 7 ++++++-
+ accel/i128/i128scrin.c | 2 +-
+ accel/p9000/p9000scrin.c | 2 +-
+ bin/mc/files.c | 2 +-
+ hp.cf | 7 +++++++
+ hpLib.rules | 2 ++
+ imakemdep.h | 13 +++++++++++++
+ import/mijpeg.c | 2 +-
+ input/drivers/hil_driver.c | 2 +-
+ input/hpKeyMap.c | 2 +-
+ main.c | 2 +-
+ malloc.c | 12 +++++-------
+ mono/drivers/apollo/apolloHW.h | 2 +-
+ mono/drivers/apollo/apollodriv.c | 6 +++---
+ mono/drivers/hgc1280/hgc1280driv.c | 4 ++--
+ mono/drivers/sigma/sigmadriv.c | 4 ++--
+ mono/mono/mono.c | 6 +++---
+ mono/mono/mono.h | 4 ++--
+ pch.c | 2 +-
+ process/mpgeomaa.c | 2 +-
+ process/mpgeomnn.c | 2 +-
+ vga16/ibm/vgaImages.c | 2 +-
+ vga256/drivers/ati/regati.h | 2 +-
+ vga256/drivers/cirrus/cir_blitter.c | 2 +-
+ vga256/drivers/cirrus/cir_cursor.c | 2 +-
+ vga256/drivers/oak/oak_driver.c | 2 +-
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01r1.ref b/patch_cmds/diffstat/testing/case01r1.ref
new file mode 100644
index 0000000..08765ff
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01r1.ref
@@ -0,0 +1,28 @@
+ config/cf/Imake.cf | 7 +++++
+ config/cf/hp.cf | 7 +++++
+ config/cf/hpLib.rules | 2 ++
+ config/imake/imakemdep.h | 13 ++++++++++
+ config/makedepend/main.c | 2 +-
+ include/Xos.h | 7 +++++-
+ programs/Xserver/XIE/mixie/import/mijpeg.c | 2 +-
+ programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 +-
+ programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 +-
+ programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 +-
+ programs/Xserver/hw/hp/input/hpKeyMap.c | 2 +-
+ programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 +-
+ programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 +-
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 +-
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 ++--
+ programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 ++--
+ programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 ++--
+ programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 +-
+ programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 +-
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 +-
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 +-
+ programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 +-
+ test/xsuite/xtest/src/bin/mc/files.c | 2 +-
+ util/patch/malloc.c | 12 ++++-----
+ util/patch/pch.c | 2 +-
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01r2.ref b/patch_cmds/diffstat/testing/case01r2.ref
new file mode 100644
index 0000000..f386706
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01r2.ref
@@ -0,0 +1,28 @@
+ config/cf/Imake.cf | 7 +++++
+ config/cf/hp.cf | 7 +++++
+ config/cf/hpLib.rules | 2 ++
+ config/imake/imakemdep.h | 13 ++++++++++
+ config/makedepend/main.c | 2 +-
+ include/Xos.h | 7 ++++-
+ programs/Xserver/XIE/mixie/import/mijpeg.c | 2 +-
+ programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 +-
+ programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 +-
+ programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 +-
+ programs/Xserver/hw/hp/input/hpKeyMap.c | 2 +-
+ programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 +-
+ programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 +-
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 +-
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 +-
+ programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 +-
+ programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 +-
+ programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 +-
+ programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 +-
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 +-
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 +-
+ programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 +-
+ test/xsuite/xtest/src/bin/mc/files.c | 2 +-
+ util/patch/malloc.c | 12 ++++-----
+ util/patch/pch.c | 2 +-
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case01u.ref b/patch_cmds/diffstat/testing/case01u.ref
new file mode 100644
index 0000000..d919a69
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case01u.ref
@@ -0,0 +1,28 @@
+ config/cf/hp.cf | 7 +++++
+ config/cf/hpLib.rules | 2 +
+ config/imake/imakemdep.h | 13 ++++++++++
+ config/makedepend/main.c | 2 -
+ include/Xos.h | 7 ++++-
+ programs/Xserver/XIE/mixie/import/mijpeg.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomaa.c | 2 -
+ programs/Xserver/XIE/mixie/process/mpgeomnn.c | 2 -
+ programs/Xserver/hw/hp/input/drivers/hil_driver.c | 2 -
+ programs/Xserver/hw/hp/input/hpKeyMap.c | 2 -
+ programs/Xserver/hw/xfree86/accel/i128/i128scrin.c | 2 -
+ programs/Xserver/hw/xfree86/accel/p9000/p9000scrin.c | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apolloHW.h | 2 -
+ programs/Xserver/hw/xfree86/mono/drivers/apollo/apollodriv.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/drivers/hgc1280/hgc1280driv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/drivers/sigma/sigmadriv.c | 4 +--
+ programs/Xserver/hw/xfree86/mono/mono/mono.c | 6 ++--
+ programs/Xserver/hw/xfree86/mono/mono/mono.h | 4 +--
+ programs/Xserver/hw/xfree86/vga16/ibm/vgaImages.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/ati/regati.h | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_blitter.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/cirrus/cir_cursor.c | 2 -
+ programs/Xserver/hw/xfree86/vga256/drivers/oak/oak_driver.c | 2 -
+ test/xsuite/xtest/src/bin/mc/files.c | 2 -
+ util/patch/malloc.c | 12 +++------
+ util/patch/pch.c | 2 -
+ config/cf/Imake.cf | 7 +++++
+ 27 files changed, 68 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case02.pat b/patch_cmds/diffstat/testing/case02.pat
new file mode 100644
index 0000000..3e636e4
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02.pat
@@ -0,0 +1,486 @@
+
+Prereq: public-patch-25
+
+*** /tmp/da20646 Wed Nov 3 20:04:26 1993
+--- mit/bug-report Wed Nov 3 20:04:25 1993
+***************
+*** 2,8 ****
+ Subject: [area]: [synopsis] [replace with actual area and short description]
+
+ VERSION:
+! R5, public-patch-25
+ [MIT public patches will edit this line to indicate the patch level]
+
+ CLIENT MACHINE and OPERATING SYSTEM:
+--- 2,8 ----
+ Subject: [area]: [synopsis] [replace with actual area and short description]
+
+ VERSION:
+! R5, public-patch-26
+ [MIT public patches will edit this line to indicate the patch level]
+
+ CLIENT MACHINE and OPERATING SYSTEM:
+*** /tmp/da21897 Thu Nov 4 08:57:24 1993
+--- mit/clients/xterm/misc.c Thu Nov 4 08:57:23 1993
+***************
+*** 1,5 ****
+ /*
+! * $XConsortium: misc.c,v 1.92 92/03/13 17:02:08 gildea Exp $
+ */
+
+ /*
+--- 1,5 ----
+ /*
+! * $XConsortium: misc.c,v 1.95.1.1 93/11/04 08:56:48 gildea Exp $
+ */
+
+ /*
+***************
+*** 444,449 ****
+--- 444,518 ----
+ }
+ }
+
++ #if defined(ALLOWLOGGING) || defined(DEBUG)
++
++ #ifndef X_NOT_POSIX
++ #define HAS_WAITPID
++ #endif
++
++ /*
++ * create a file only if we could with the permissions of the real user id.
++ * We could emulate this with careful use of access() and following
++ * symbolic links, but that is messy and has race conditions.
++ * Forking is messy, too, but we can't count on setreuid() or saved set-uids
++ * being available.
++ */
++ void
++ creat_as(uid, gid, pathname, mode)
++ int uid;
++ int gid;
++ char *pathname;
++ int mode;
++ {
++ int fd;
++ int waited;
++ int pid;
++ #ifndef HAS_WAITPID
++ int (*chldfunc)();
++
++ chldfunc = signal(SIGCHLD, SIG_DFL);
++ #endif
++ pid = fork();
++ switch (pid)
++ {
++ case 0: /* child */
++ setgid(gid);
++ setuid(uid);
++ fd = open(pathname, O_WRONLY|O_CREAT|O_APPEND, mode);
++ if (fd >= 0) {
++ close(fd);
++ _exit(0);
++ } else
++ _exit(1);
++ case -1: /* error */
++ return;
++ default: /* parent */
++ #ifdef HAS_WAITPID
++ waitpid(pid, NULL, 0);
++ #else
++ waited = wait(NULL);
++ signal(SIGCHLD, chldfunc);
++ /*
++ Since we had the signal handler uninstalled for a while,
++ we might have missed the termination of our screen child.
++ If we can check for this possibility without hanging, do so.
++ */
++ do
++ if (waited == term->screen.pid)
++ Cleanup(0);
++ while ( (waited=nonblocking_wait()) > 0);
++ #endif
++ }
++ }
++ #endif
++
++ #ifdef ALLOWLOGGING
++ /*
++ * logging is a security hole, since it allows a setuid program to
++ * write arbitrary data to an arbitrary file. So it is disabled
++ * by default.
++ */
++
+ StartLog(screen)
+ register TScreen *screen;
+ {
+***************
+*** 530,551 ****
+ return;
+ #endif
+ } else {
+! if(access(screen->logfile, F_OK) == 0) {
+! if(access(screen->logfile, W_OK) < 0)
+! return;
+! } else if(cp = rindex(screen->logfile, '/')) {
+! *cp = 0;
+! i = access(screen->logfile, W_OK);
+! *cp = '/';
+! if(i < 0)
+! return;
+! } else if(access(".", W_OK) < 0)
+ return;
+! if((screen->logfd = open(screen->logfile, O_WRONLY | O_APPEND |
+! O_CREAT, 0644)) < 0)
+! return;
+! chown(screen->logfile, screen->uid, screen->gid);
+
+ }
+ screen->logstart = screen->TekEmu ? Tbptr : bptr;
+ screen->logging = TRUE;
+--- 599,618 ----
+ return;
+ #endif
+ } else {
+! if(access(screen->logfile, F_OK) != 0) {
+! if (errno == ENOENT)
+! creat_as(screen->uid, screen->gid,
+! screen->logfile, 0644);
+! else
+ return;
+! }
+
++ if(access(screen->logfile, F_OK) != 0
++ || access(screen->logfile, W_OK) != 0)
++ return;
++ if((screen->logfd = open(screen->logfile, O_WRONLY | O_APPEND,
++ 0644)) < 0)
++ return;
+ }
+ screen->logstart = screen->TekEmu ? Tbptr : bptr;
+ screen->logging = TRUE;
+***************
+*** 587,592 ****
+--- 654,660 ----
+ CloseLog(screen);
+ }
+ #endif /* ALLOWLOGFILEEXEC */
++ #endif /* ALLOWLOGGING */
+
+
+ do_osc(func)
+***************
+*** 626,631 ****
+--- 694,700 ----
+ Changetitle(buf);
+ break;
+
++ #ifdef ALLOWLOGGING
+ case 46: /* new log file */
+ #ifdef ALLOWLOGFILECHANGES
+ /*
+***************
+*** 643,648 ****
+--- 712,718 ----
+ Bell();
+ #endif
+ break;
++ #endif /* ALLOWLOGGING */
+
+ case 50:
+ SetVTFont (fontMenu_fontescape, True, buf, NULL);
+***************
+*** 903,912 ****
+--- 973,984 ----
+ register TScreen *screen = &term->screen;
+
+ if (screen->TekEmu) {
++ #ifdef ALLOWLOGGING
+ if (screen->logging) {
+ FlushLog (screen);
+ screen->logstart = buffer;
+ }
++ #endif
+ longjmp(Tekend, 1);
+ }
+ return;
+***************
+*** 917,926 ****
+--- 989,1000 ----
+ register TScreen *screen = &term->screen;
+
+ if (!screen->TekEmu) {
++ #ifdef ALLOWLOGGING
+ if(screen->logging) {
+ FlushLog(screen);
+ screen->logstart = Tbuffer;
+ }
++ #endif
+ screen->TekEmu = TRUE;
+ longjmp(VTend, 1);
+ }
+*** /tmp/da17839 Wed Nov 3 18:16:38 1993
+--- mit/clients/xterm/Tekproc.c Wed Nov 3 18:16:37 1993
+***************
+*** 1,5 ****
+ /*
+! * $XConsortium: Tekproc.c,v 1.107 91/06/25 19:49:48 gildea Exp $
+ *
+ * Warning, there be crufty dragons here.
+ */
+--- 1,5 ----
+ /*
+! * $XConsortium: Tekproc.c,v 1.112 93/02/25 17:17:40 gildea Exp $
+ *
+ * Warning, there be crufty dragons here.
+ */
+***************
+*** 46,51 ****
+--- 46,52 ----
+ #include <stdio.h>
+ #include <errno.h>
+ #include <setjmp.h>
++ #include <signal.h>
+
+ /*
+ * Check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX
+***************
+*** 74,80 ****
+
+ #define TekColormap DefaultColormap( screen->display, \
+ DefaultScreen(screen->display) )
+! #define DefaultGCID DefaultGC(screen->display, DefaultScreen(screen->display))->gid
+
+ /* Tek defines */
+
+--- 75,81 ----
+
+ #define TekColormap DefaultColormap( screen->display, \
+ DefaultScreen(screen->display) )
+! #define DefaultGCID XGContextFromGC(DefaultGC(screen->display, DefaultScreen(screen->display)))
+
+ /* Tek defines */
+
+***************
+*** 188,194 ****
+--- 189,197 ----
+ /* menu actions */
+ { "allow-send-events", HandleAllowSends },
+ { "set-visual-bell", HandleSetVisualBell },
++ #ifdef ALLOWLOGGING
+ { "set-logging", HandleLogging },
++ #endif
+ { "redraw", HandleRedraw },
+ { "send-signal", HandleSendSignal },
+ { "quit", HandleQuit },
+***************
+*** 335,342 ****
+ register int c, x, y;
+ char ch;
+
+! for( ; ; )
+! switch(Tparsestate[c = input()]) {
+ case CASE_REPORT:
+ /* report address */
+ if(screen->TekGIN) {
+--- 338,346 ----
+ register int c, x, y;
+ char ch;
+
+! for( ; ; ) {
+! c = input();
+! switch(Tparsestate[c]) {
+ case CASE_REPORT:
+ /* report address */
+ if(screen->TekGIN) {
+***************
+*** 356,365 ****
+--- 360,371 ----
+ /* special return to vt102 mode */
+ Tparsestate = curstate;
+ TekRecord->ptr[-1] = NAK; /* remove from recording */
++ #ifdef ALLOWLOGGING
+ if(screen->logging) {
+ FlushLog(screen);
+ screen->logstart = buffer;
+ }
++ #endif
+ return;
+
+ case CASE_SPT_STATE:
+***************
+*** 626,631 ****
+--- 632,638 ----
+ Tparsestate = curstate;
+ break;
+ }
++ }
+ }
+
+ static int rcnt;
+***************
+*** 667,675 ****
+ (int *) NULL, &crocktimeout);
+ #endif
+ if(Tselect_mask & pty_mask) {
+ if(screen->logging)
+ FlushLog(screen);
+! Tbcnt = read(screen->respond, Tbptr = Tbuffer, BUF_SIZE);
+ if(Tbcnt < 0) {
+ if(errno == EIO)
+ Cleanup (0);
+--- 674,684 ----
+ (int *) NULL, &crocktimeout);
+ #endif
+ if(Tselect_mask & pty_mask) {
++ #ifdef ALLOWLOGGING
+ if(screen->logging)
+ FlushLog(screen);
+! #endif
+! Tbcnt = read(screen->respond, (char *)(Tbptr = Tbuffer), BUF_SIZE);
+ if(Tbcnt < 0) {
+ if(errno == EIO)
+ Cleanup (0);
+***************
+*** 1150,1157 ****
+ * The following is called the create the tekWidget
+ */
+
+! static void TekInitialize(request, new)
+ Widget request, new;
+ {
+ /* look for focus related events on the shell, because we need
+ * to care about the shell's border being part of our focus.
+--- 1159,1168 ----
+ * The following is called the create the tekWidget
+ */
+
+! static void TekInitialize(request, new, args, num_args)
+ Widget request, new;
++ ArgList args;
++ Cardinal *num_args;
+ {
+ /* look for focus related events on the shell, because we need
+ * to care about the shell's border being part of our focus.
+***************
+*** 1549,1565 ****
+ }
+
+
+ /* write copy of screen to a file */
+
+ TekCopy()
+ {
+- register TekLink *Tp;
+- register int tekcopyfd;
+ register TScreen *screen = &term->screen;
+ register struct tm *tp;
+ long l;
+ char buf[32];
+
+ time(&l);
+ tp = localtime(&l);
+ sprintf(buf, "COPY%02d-%02d-%02d.%02d:%02d:%02d", tp->tm_year,
+--- 1560,1585 ----
+ }
+
+
++ #ifndef X_NOT_POSIX
++ #define HAS_WAITPID
++ #endif
++
+ /* write copy of screen to a file */
+
+ TekCopy()
+ {
+ register TScreen *screen = &term->screen;
+ register struct tm *tp;
+ long l;
+ char buf[32];
++ int waited;
++ int pid;
++ #ifndef HAS_WAITPID
++ int (*chldfunc)();
+
++ chldfunc = signal(SIGCHLD, SIG_DFL);
++ #endif
++
+ time(&l);
+ tp = localtime(&l);
+ sprintf(buf, "COPY%02d-%02d-%02d.%02d:%02d:%02d", tp->tm_year,
+***************
+*** 1573,1593 ****
+ Bell();
+ return;
+ }
+! if((tekcopyfd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0644)) < 0) {
+! Bell();
+! return;
+! }
+! chown(buf, screen->uid, screen->gid);
+! sprintf(buf, "\033%c\033%c", screen->page.fontsize + '8',
+! screen->page.linetype + '`');
+! write(tekcopyfd, buf, 4);
+! Tp = &Tek0;
+! do {
+ write(tekcopyfd, (char *)Tp->data, Tp->count);
+ Tp = Tp->next;
+! } while(Tp);
+! close(tekcopyfd);
+ }
+-
+-
+-
+--- 1593,1645 ----
+ Bell();
+ return;
+ }
+!
+! /* Write the file in an unprivileged child process because
+! using access before the open still leaves a small window
+! of opportunity. */
+! pid = fork();
+! switch (pid)
+! {
+! case 0: /* child */
+! {
+! register int tekcopyfd;
+! char initbuf[5];
+! register TekLink *Tp;
+!
+! setgid(screen->gid);
+! setuid(screen->uid);
+! tekcopyfd = open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+! if (tekcopyfd < 0)
+! _exit(1);
+! sprintf(initbuf, "\033%c\033%c", screen->page.fontsize + '8',
+! screen->page.linetype + '`');
+! write(tekcopyfd, initbuf, 4);
+! Tp = &Tek0;
+! do {
+ write(tekcopyfd, (char *)Tp->data, Tp->count);
+ Tp = Tp->next;
+! } while(Tp);
+! close(tekcopyfd);
+! _exit(0);
+! }
+! case -1: /* error */
+! Bell();
+! return;
+! default: /* parent */
+! #ifdef HAS_WAITPID
+! waitpid(pid, NULL, 0);
+! #else
+! waited = wait(NULL);
+! signal(SIGCHLD, chldfunc);
+! /*
+! Since we had the signal handler uninstalled for a while,
+! we might have missed the termination of our screen child.
+! If we can check for this possibility without hanging, do so.
+! */
+! do
+! if (waited == term->screen.pid)
+! Cleanup(0);
+! while ( (waited=nonblocking_wait()) > 0);
+! #endif
+! }
+ }
diff --git a/patch_cmds/diffstat/testing/case02.ref b/patch_cmds/diffstat/testing/case02.ref
new file mode 100644
index 0000000..cd187ac
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02.ref
@@ -0,0 +1,4 @@
+ bug-report | 2
+ clients/xterm/Tekproc.c | 98 +++++++++--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ clients/xterm/misc.c | 104 +++++++++++++++++++++++++++++++++++++!!!!!!!!!!!
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02R.ref b/patch_cmds/diffstat/testing/case02R.ref
new file mode 100644
index 0000000..072c3cd
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02R.ref
@@ -0,0 +1,4 @@
+ da17839 | 98 +++------------!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ da20646 | 2 !
+ da21897 | 104 --------------------------------------------------!!!!!!!!!!!!!!
+ 3 files changed, 5 insertions(+), 102 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02Rp0.ref b/patch_cmds/diffstat/testing/case02Rp0.ref
new file mode 100644
index 0000000..341babd
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02Rp0.ref
@@ -0,0 +1,4 @@
+ /tmp/da17839 | 98 ++------------!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ /tmp/da20646 | 2 !
+ /tmp/da21897 | 104 ----------------------------------------------!!!!!!!!!!!!!
+ 3 files changed, 5 insertions(+), 102 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02b.ref b/patch_cmds/diffstat/testing/case02b.ref
new file mode 100644
index 0000000..cd187ac
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02b.ref
@@ -0,0 +1,4 @@
+ bug-report | 2
+ clients/xterm/Tekproc.c | 98 +++++++++--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ clients/xterm/misc.c | 104 +++++++++++++++++++++++++++++++++++++!!!!!!!!!!!
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02f0.ref b/patch_cmds/diffstat/testing/case02f0.ref
new file mode 100644
index 0000000..7218297
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02f0.ref
@@ -0,0 +1,4 @@
+ bug-report | 2 0 + 0 - 2 !
+ clients/xterm/Tekproc.c | 98 20 + 5 - 73 !
+ clients/xterm/misc.c | 104 82 + 0 - 22 !
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02k.ref b/patch_cmds/diffstat/testing/case02k.ref
new file mode 100644
index 0000000..cd187ac
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02k.ref
@@ -0,0 +1,4 @@
+ bug-report | 2
+ clients/xterm/Tekproc.c | 98 +++++++++--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ clients/xterm/misc.c | 104 +++++++++++++++++++++++++++++++++++++!!!!!!!!!!!
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02p1.ref b/patch_cmds/diffstat/testing/case02p1.ref
new file mode 100644
index 0000000..cd187ac
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02p1.ref
@@ -0,0 +1,4 @@
+ bug-report | 2
+ clients/xterm/Tekproc.c | 98 +++++++++--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ clients/xterm/misc.c | 104 +++++++++++++++++++++++++++++++++++++!!!!!!!!!!!
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02p9.ref b/patch_cmds/diffstat/testing/case02p9.ref
new file mode 100644
index 0000000..3cd471b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02p9.ref
@@ -0,0 +1,4 @@
+ Tekproc.c | 98 +++++++++++---!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ bug-report | 2 !
+ misc.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++!!!!!!!!!!!!!
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02r1.ref b/patch_cmds/diffstat/testing/case02r1.ref
new file mode 100644
index 0000000..b63f8bc
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02r1.ref
@@ -0,0 +1,4 @@
+ bug-report | 2 !
+ clients/xterm/Tekproc.c | 98 +++++++++--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ clients/xterm/misc.c | 104 ++++++++++++++++++++++++++++++++++++++!!!!!!!!!!
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02r2.ref b/patch_cmds/diffstat/testing/case02r2.ref
new file mode 100644
index 0000000..b63f8bc
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02r2.ref
@@ -0,0 +1,4 @@
+ bug-report | 2 !
+ clients/xterm/Tekproc.c | 98 +++++++++--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ clients/xterm/misc.c | 104 ++++++++++++++++++++++++++++++++++++++!!!!!!!!!!
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case02u.ref b/patch_cmds/diffstat/testing/case02u.ref
new file mode 100644
index 0000000..e0d58ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case02u.ref
@@ -0,0 +1,4 @@
+ bug-report | 2
+ clients/xterm/misc.c | 104 +++++++++++++++++++++++++++++++++++++!!!!!!!!!!!
+ clients/xterm/Tekproc.c | 98 +++++++++--!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 3 files changed, 102 insertions(+), 5 deletions(-), 97 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case03.pat b/patch_cmds/diffstat/testing/case03.pat
new file mode 100644
index 0000000..c72c21b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03.pat
@@ -0,0 +1,35 @@
+diff -r -c diffstat/config.cache diffstat.orig/config.cache
+*** 1.1 Fri Mar 15 19:27:13 1996
+--- diffstat.orig/config.cache Fri Mar 15 19:51:02 1996
+***************
+*** 13,28 ****
+ # --recheck option to rerun configure.
+ #
+ ac_cv_c_const=${ac_cv_c_const='yes'}
+! ac_cv_c_cross=${ac_cv_c_cross='yes'}
+ ac_cv_header_getopt_h=${ac_cv_header_getopt_h='yes'}
+ ac_cv_header_malloc_h=${ac_cv_header_malloc_h='yes'}
+--- 13,28 ----
+ # --recheck option to rerun configure.
+ #
+ ac_cv_c_const=${ac_cv_c_const='yes'}
+ ac_cv_header_getopt_h=${ac_cv_header_getopt_h='yes'}
+ ac_cv_header_malloc_h=${ac_cv_header_malloc_h='yes'}
+diff -r -c diffstat/config.h diffstat.orig/config.h
+*** diffstat/config.h Fri Mar 15 19:27:15 1996
+--- diffstat.orig/config.h Fri Mar 15 19:51:04 1996
+***************
+*** 6,11 ****
+--- 6,12 ----
+ */
+
+
++ #define STDC_HEADERS 1
+ #define HAVE_STDLIB_H 1
+ #define HAVE_UNISTD_H 1
+ #define HAVE_GETOPT_H 1
+Only in diffstat.orig: configure.out
+Binary files diffstat/diffstat and diffstat.orig/diffstat differ
+< nothing
+> nothing again
+Binary files diffstat/diffstat.o and diffstat.orig/diffstat.o differ
diff --git a/patch_cmds/diffstat/testing/case03.ref b/patch_cmds/diffstat/testing/case03.ref
new file mode 100644
index 0000000..a5ceb9d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03.ref
@@ -0,0 +1,6 @@
+ config.cache | 1 !
+ config.h | 1 +
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ 5 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03R.ref b/patch_cmds/diffstat/testing/case03R.ref
new file mode 100644
index 0000000..352160f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03R.ref
@@ -0,0 +1,6 @@
+ diffstat.orig/configure.out |only
+ diffstat/config.cache | 1 !
+ diffstat/config.h | 1 -
+ diffstat/diffstat |binary
+ diffstat/diffstat.o |binary
+ 5 files changed, 1 deletion(-), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03Rp0.ref b/patch_cmds/diffstat/testing/case03Rp0.ref
new file mode 100644
index 0000000..352160f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03Rp0.ref
@@ -0,0 +1,6 @@
+ diffstat.orig/configure.out |only
+ diffstat/config.cache | 1 !
+ diffstat/config.h | 1 -
+ diffstat/diffstat |binary
+ diffstat/diffstat.o |binary
+ 5 files changed, 1 deletion(-), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03b.ref b/patch_cmds/diffstat/testing/case03b.ref
new file mode 100644
index 0000000..7ae438f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03b.ref
@@ -0,0 +1,4 @@
+ config.cache | 1 !
+ config.h | 1 +
+ configure.out |only
+ 3 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03f0.ref b/patch_cmds/diffstat/testing/case03f0.ref
new file mode 100644
index 0000000..0ea7d51
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03f0.ref
@@ -0,0 +1,6 @@
+ config.cache | 1 0 + 0 - 1 !
+ config.h | 1 1 + 0 - 0 !
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ 5 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03k.ref b/patch_cmds/diffstat/testing/case03k.ref
new file mode 100644
index 0000000..a5ceb9d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03k.ref
@@ -0,0 +1,6 @@
+ config.cache | 1 !
+ config.h | 1 +
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ 5 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03p1.ref b/patch_cmds/diffstat/testing/case03p1.ref
new file mode 100644
index 0000000..a5ceb9d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03p1.ref
@@ -0,0 +1,6 @@
+ config.cache | 1 !
+ config.h | 1 +
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ 5 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03p9.ref b/patch_cmds/diffstat/testing/case03p9.ref
new file mode 100644
index 0000000..a5ceb9d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03p9.ref
@@ -0,0 +1,6 @@
+ config.cache | 1 !
+ config.h | 1 +
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ 5 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03r1.ref b/patch_cmds/diffstat/testing/case03r1.ref
new file mode 100644
index 0000000..a5ceb9d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03r1.ref
@@ -0,0 +1,6 @@
+ config.cache | 1 !
+ config.h | 1 +
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ 5 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03r2.ref b/patch_cmds/diffstat/testing/case03r2.ref
new file mode 100644
index 0000000..a5ceb9d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03r2.ref
@@ -0,0 +1,6 @@
+ config.cache | 1 !
+ config.h | 1 +
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ 5 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case03u.ref b/patch_cmds/diffstat/testing/case03u.ref
new file mode 100644
index 0000000..a5ceb9d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case03u.ref
@@ -0,0 +1,6 @@
+ config.cache | 1 !
+ config.h | 1 +
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ 5 files changed, 1 insertion(+), 1 modification(!)
diff --git a/patch_cmds/diffstat/testing/case04.pat b/patch_cmds/diffstat/testing/case04.pat
new file mode 100644
index 0000000..84e122d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04.pat
@@ -0,0 +1,352 @@
+diff -r -c diffstat/config.cache diffstat.orig/config.cache
+*** diffstat/config.cache Fri Mar 15 19:27:13 1996
+--- diffstat.orig/config.cache Fri Mar 15 19:51:02 1996
+***************
+*** 13,28 ****
+ # --recheck option to rerun configure.
+ #
+ ac_cv_c_const=${ac_cv_c_const='yes'}
+! ac_cv_c_cross=${ac_cv_c_cross='yes'}
+ ac_cv_header_getopt_h=${ac_cv_header_getopt_h='yes'}
+ ac_cv_header_malloc_h=${ac_cv_header_malloc_h='yes'}
+! ac_cv_header_stdc=${ac_cv_header_stdc='no'}
+ ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h='yes'}
+ ac_cv_header_string_h=${ac_cv_header_string_h='yes'}
+ ac_cv_header_unistd_h=${ac_cv_header_unistd_h='yes'}
+ ac_cv_path_install=${ac_cv_path_install='/home/tom/com/install -c'}
+! ac_cv_prog_CC=${ac_cv_prog_CC='atacCC'}
+! ac_cv_prog_CPP=${ac_cv_prog_CPP='atacCC -E'}
+ ac_cv_prog_gcc=${ac_cv_prog_gcc='yes'}
+ ac_cv_prog_gcc_g=${ac_cv_prog_gcc_g='yes'}
+ ac_cv_prog_gcc_traditional=${ac_cv_prog_gcc_traditional='no'}
+--- 13,28 ----
+ # --recheck option to rerun configure.
+ #
+ ac_cv_c_const=${ac_cv_c_const='yes'}
+! ac_cv_c_cross=${ac_cv_c_cross='no'}
+ ac_cv_header_getopt_h=${ac_cv_header_getopt_h='yes'}
+ ac_cv_header_malloc_h=${ac_cv_header_malloc_h='yes'}
+! ac_cv_header_stdc=${ac_cv_header_stdc='yes'}
+ ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h='yes'}
+ ac_cv_header_string_h=${ac_cv_header_string_h='yes'}
+ ac_cv_header_unistd_h=${ac_cv_header_unistd_h='yes'}
+ ac_cv_path_install=${ac_cv_path_install='/home/tom/com/install -c'}
+! ac_cv_prog_CC=${ac_cv_prog_CC='gcc'}
+! ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'}
+ ac_cv_prog_gcc=${ac_cv_prog_gcc='yes'}
+ ac_cv_prog_gcc_g=${ac_cv_prog_gcc_g='yes'}
+ ac_cv_prog_gcc_traditional=${ac_cv_prog_gcc_traditional='no'}
+diff -r -c diffstat/config.h diffstat.orig/config.h
+*** diffstat/config.h Fri Mar 15 19:27:15 1996
+--- diffstat.orig/config.h Fri Mar 15 19:51:04 1996
+***************
+*** 6,11 ****
+--- 6,12 ----
+ */
+
+
++ #define STDC_HEADERS 1
+ #define HAVE_STDLIB_H 1
+ #define HAVE_UNISTD_H 1
+ #define HAVE_GETOPT_H 1
+diff -r -c diffstat/config.log diffstat.orig/config.log
+*** diffstat/config.log Fri Mar 15 19:26:59 1996
+--- diffstat.orig/config.log Fri Mar 15 19:50:58 1996
+***************
+*** 2,27 ****
+ running configure, to aid debugging if configure makes a mistake.
+
+ configure:607: sgtty.h: No such file or directory
+! /usr/tmp/atacCC17934/conftest.c:30: warning: missing braces around initializer for `ZUmain[0]'
+! /usr/tmp/atacCC17934/conftest.c:66: warning: function declaration isn't a prototype
+! /usr/tmp/atacCC17934/conftest.c: In function `main':
+! /usr/tmp/atacCC17934/conftest.c:67: warning: implicit declaration of function `aTaC'
+! /usr/tmp/atacCC17934/conftest.c: At top level:
+! /usr/tmp/atacCC17934/conftest.c:76: warning: function declaration isn't a prototype
+! /usr/tmp/atacCC17934/conftest.c: In function `t':
+! /usr/tmp/atacCC17934/conftest.c:97: warning: declaration of `t' shadows global declaration
+! /usr/tmp/atacCC17934/conftest.c:98: warning: unused variable `s'
+! /usr/tmp/atacCC17934/conftest.c:104: warning: declaration of `x' shadows previous local
+! /usr/tmp/atacCC17934/conftest.c:111: warning: declaration of `p' shadows previous local
+! /usr/tmp/atacCC17934/conftest.c:125: warning: unused variable `foo'
+! /usr/tmp/atacCC17934/conftest.c:86: warning: unused variable `zero'
+! /usr/tmp/atacCC17934/conftest.c:80: warning: unused variable `x'
+! /usr/tmp/atacCC17934/conftest.c: At top level:
+! /usr/tmp/atacCC17934/conftest.c:1: warning: `ZIDENT' defined but not used
+! /usr/tmp/atacCC17972/conftest.c:30: warning: missing braces around initializer for `ZUmain[0]'
+! /usr/tmp/atacCC17972/conftest.c:39: warning: return-type defaults to `int'
+! /usr/tmp/atacCC17972/conftest.c:39: warning: function declaration isn't a prototype
+! /usr/tmp/atacCC17972/conftest.c: In function `main':
+! /usr/tmp/atacCC17972/conftest.c:40: warning: implicit declaration of function `aTaC'
+! /usr/tmp/atacCC17972/conftest.c: At top level:
+! /usr/tmp/atacCC17972/conftest.c:1: warning: `ZIDENT' defined but not used
+--- 2,19 ----
+ running configure, to aid debugging if configure makes a mistake.
+
+ configure:607: sgtty.h: No such file or directory
+! configure:659: warning: function declaration isn't a prototype
+! configure:660: warning: function declaration isn't a prototype
+! configure: In function `t':
+! configure:680: warning: declaration of `t' shadows global declaration
+! configure:681: warning: unused variable `s'
+! configure:686: warning: declaration of `x' shadows previous local
+! configure:692: warning: declaration of `p' shadows previous local
+! configure:701: warning: unused variable `foo'
+! configure:669: warning: unused variable `zero'
+! configure:663: warning: unused variable `x'
+! configure:680: warning: `t' might be used uninitialized in this function
+! configure:698: warning: `b' might be used uninitialized in this function
+! configure:735: warning: return-type defaults to `int'
+! configure:735: warning: function declaration isn't a prototype
+! configure:821: warning: function declaration isn't a prototype
+diff -r -c diffstat/config.status diffstat.orig/config.status
+*** diffstat/config.status Fri Mar 15 19:27:14 1996
+--- diffstat.orig/config.status Fri Mar 15 19:51:03 1996
+***************
+*** 4,10 ****
+ # This directory was configured as follows,
+ # on host dickey-ppp:
+ #
+! # ./configure
+ #
+ # Compiler output produced by configure, useful for debugging
+ # configure, is in ./config.log if it exists.
+--- 4,10 ----
+ # This directory was configured as follows,
+ # on host dickey-ppp:
+ #
+! # ./configure --verbose --disable-echo --enable-warnings --with-warnings
+ #
+ # Compiler output produced by configure, useful for debugging
+ # configure, is in ./config.log if it exists.
+***************
+*** 14,21 ****
+ do
+ case "$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+! echo "running ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion"
+! exec ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "./config.status generated by autoconf version 2.3"
+ exit 0 ;;
+--- 14,21 ----
+ do
+ case "$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+! echo "running ${CONFIG_SHELL-/bin/sh} ./configure --verbose --disable-echo --enable-warnings --with-warnings --no-create --no-recursion"
+! exec ${CONFIG_SHELL-/bin/sh} ./configure --verbose --disable-echo --enable-warnings --with-warnings --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "./config.status generated by autoconf version 2.3"
+ exit 0 ;;
+***************
+*** 38,53 ****
+ s%@CFLAGS@%-O -Wall -Wshadow -Wconversion -Wstrict-prototypes -Wmissing-prototypes%g
+ s%@CPPFLAGS@%%g
+ s%@CXXFLAGS@%%g
+! s%@DEFS@% -DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETOPT_H=1 -DHAVE_STRING_H=1 -DHAVE_MALLOC_H=1 %g
+ s%@LDFLAGS@%%g
+ s%@LIBS@%%g
+ s%@exec_prefix@%${prefix}%g
+ s%@prefix@%/usr/local%g
+ s%@program_transform_name@%s,x,x,%g
+! s%@CC@%atacCC%g
+ s%@INSTALL_PROGRAM@%${INSTALL}%g
+ s%@INSTALL_DATA@%${INSTALL} -m 644%g
+! s%@CPP@%atacCC -E%g
+
+ CEOF
+
+--- 38,53 ----
+ s%@CFLAGS@%-O -Wall -Wshadow -Wconversion -Wstrict-prototypes -Wmissing-prototypes%g
+ s%@CPPFLAGS@%%g
+ s%@CXXFLAGS@%%g
+! s%@DEFS@% -DSTDC_HEADERS=1 -DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETOPT_H=1 -DHAVE_STRING_H=1 -DHAVE_MALLOC_H=1 %g
+ s%@LDFLAGS@%%g
+ s%@LIBS@%%g
+ s%@exec_prefix@%${prefix}%g
+ s%@prefix@%/usr/local%g
+ s%@program_transform_name@%s,x,x,%g
+! s%@CC@%gcc%g
+ s%@INSTALL_PROGRAM@%${INSTALL}%g
+ s%@INSTALL_DATA@%${INSTALL} -m 644%g
+! s%@CPP@%gcc -E%g
+
+ CEOF
+
+Only in diffstat.orig: configure.out
+Binary files diffstat/diffstat and diffstat.orig/diffstat differ
+Binary files diffstat/diffstat.o and diffstat.orig/diffstat.o differ
+diff -r -c diffstat/makefile diffstat.orig/makefile
+*** diffstat/makefile Fri Mar 15 19:27:15 1996
+--- diffstat.orig/makefile Fri Mar 15 19:51:04 1996
+***************
+*** 7,13 ****
+
+ srcdir = .
+
+! CC = atacCC
+ LINK = $(CC)
+ INSTALL = /home/tom/com/install -c
+ INSTALL_PROGRAM = ${INSTALL}
+--- 7,13 ----
+
+ srcdir = .
+
+! CC = gcc
+ LINK = $(CC)
+ INSTALL = /home/tom/com/install -c
+ INSTALL_PROGRAM = ${INSTALL}
+Only in diffstat/testing: Xlib-1.patch-
+Only in diffstat/testing: Xlib-1.ref
+Only in diffstat/testing: Xlib-2.patch-
+Only in diffstat/testing: Xlib-2.ref
+Only in diffstat/testing: Xlib-3.patch-
+Only in diffstat/testing: Xlib-3.ref
+Only in diffstat/testing: config-1.ref
+Only in diffstat/testing: nugent.ref
+Only in diffstat/testing: xserver-1.ref
+Only in diffstat/testing: xserver-2.patch-
+Only in diffstat/testing: xserver-2.ref
+Only in diffstat/testing: xterm-1.patch-
+Only in diffstat/testing: xterm-1.ref
+Only in diffstat/testing: xterm-10.patch-
+Only in diffstat/testing: xterm-10.ref
+Only in diffstat/testing: xterm-11.patch-
+Only in diffstat/testing: xterm-11.ref
+Only in diffstat/testing: xterm-2.patch-
+Only in diffstat/testing: xterm-2.ref
+Only in diffstat/testing: xterm-3.patch-
+Only in diffstat/testing: xterm-3.ref
+Only in diffstat/testing: xterm-4.patch-
+Only in diffstat/testing: xterm-4.ref
+Only in diffstat/testing: xterm-5.patch-
+Only in diffstat/testing: xterm-5.ref
+Only in diffstat/testing: xterm-6.patch-
+Only in diffstat/testing: xterm-6.ref
+Only in diffstat/testing: xterm-7.ref
+Only in diffstat/testing: xterm-8.patch-
+Only in diffstat/testing: xterm-8.ref
+Only in diffstat/testing: xterm-9.patch-
+Only in diffstat/testing: xterm-9.ref
+diff -r diffstat/config.cache diffstat.orig/config.cache
+16c16
+< ac_cv_c_cross=${ac_cv_c_cross='yes'}
+---
+> ac_cv_c_cross=${ac_cv_c_cross='no'}
+19c19
+< ac_cv_header_stdc=${ac_cv_header_stdc='no'}
+---
+> ac_cv_header_stdc=${ac_cv_header_stdc='yes'}
+24,25c24,25
+< ac_cv_prog_CC=${ac_cv_prog_CC='atacCC'}
+< ac_cv_prog_CPP=${ac_cv_prog_CPP='atacCC -E'}
+---
+> ac_cv_prog_CC=${ac_cv_prog_CC='gcc'}
+> ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'}
+diff -r diffstat/config.h diffstat.orig/config.h
+8a9
+> #define STDC_HEADERS 1
+diff -r diffstat/config.log diffstat.orig/config.log
+5,27c5,19
+< /usr/tmp/atacCC17934/conftest.c:30: warning: missing braces around initializer for `ZUmain[0]'
+< /usr/tmp/atacCC17934/conftest.c:66: warning: function declaration isn't a prototype
+< /usr/tmp/atacCC17934/conftest.c: In function `main':
+< /usr/tmp/atacCC17934/conftest.c:67: warning: implicit declaration of function `aTaC'
+< /usr/tmp/atacCC17934/conftest.c: At top level:
+< /usr/tmp/atacCC17934/conftest.c:76: warning: function declaration isn't a prototype
+< /usr/tmp/atacCC17934/conftest.c: In function `t':
+< /usr/tmp/atacCC17934/conftest.c:97: warning: declaration of `t' shadows global declaration
+< /usr/tmp/atacCC17934/conftest.c:98: warning: unused variable `s'
+< /usr/tmp/atacCC17934/conftest.c:104: warning: declaration of `x' shadows previous local
+< /usr/tmp/atacCC17934/conftest.c:111: warning: declaration of `p' shadows previous local
+< /usr/tmp/atacCC17934/conftest.c:125: warning: unused variable `foo'
+< /usr/tmp/atacCC17934/conftest.c:86: warning: unused variable `zero'
+< /usr/tmp/atacCC17934/conftest.c:80: warning: unused variable `x'
+< /usr/tmp/atacCC17934/conftest.c: At top level:
+< /usr/tmp/atacCC17934/conftest.c:1: warning: `ZIDENT' defined but not used
+< /usr/tmp/atacCC17972/conftest.c:30: warning: missing braces around initializer for `ZUmain[0]'
+< /usr/tmp/atacCC17972/conftest.c:39: warning: return-type defaults to `int'
+< /usr/tmp/atacCC17972/conftest.c:39: warning: function declaration isn't a prototype
+< /usr/tmp/atacCC17972/conftest.c: In function `main':
+< /usr/tmp/atacCC17972/conftest.c:40: warning: implicit declaration of function `aTaC'
+< /usr/tmp/atacCC17972/conftest.c: At top level:
+< /usr/tmp/atacCC17972/conftest.c:1: warning: `ZIDENT' defined but not used
+---
+> configure:659: warning: function declaration isn't a prototype
+> configure:660: warning: function declaration isn't a prototype
+> configure: In function `t':
+> configure:680: warning: declaration of `t' shadows global declaration
+> configure:681: warning: unused variable `s'
+> configure:686: warning: declaration of `x' shadows previous local
+> configure:692: warning: declaration of `p' shadows previous local
+> configure:701: warning: unused variable `foo'
+> configure:669: warning: unused variable `zero'
+> configure:663: warning: unused variable `x'
+> configure:680: warning: `t' might be used uninitialized in this function
+> configure:698: warning: `b' might be used uninitialized in this function
+> configure:735: warning: return-type defaults to `int'
+> configure:735: warning: function declaration isn't a prototype
+> configure:821: warning: function declaration isn't a prototype
+diff -r diffstat/config.status diffstat.orig/config.status
+7c7
+< # ./configure
+---
+> # ./configure --verbose --disable-echo --enable-warnings --with-warnings
+17,18c17,18
+< echo "running ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion"
+< exec ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion ;;
+---
+> echo "running ${CONFIG_SHELL-/bin/sh} ./configure --verbose --disable-echo --enable-warnings --with-warnings --no-create --no-recursion"
+> exec ${CONFIG_SHELL-/bin/sh} ./configure --verbose --disable-echo --enable-warnings --with-warnings --no-create --no-recursion ;;
+41c41
+< s%@DEFS@% -DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETOPT_H=1 -DHAVE_STRING_H=1 -DHAVE_MALLOC_H=1 %g
+---
+> s%@DEFS@% -DSTDC_HEADERS=1 -DHAVE_STDLIB_H=1 -DHAVE_UNISTD_H=1 -DHAVE_GETOPT_H=1 -DHAVE_STRING_H=1 -DHAVE_MALLOC_H=1 %g
+47c47
+< s%@CC@%atacCC%g
+---
+> s%@CC@%gcc%g
+50c50
+< s%@CPP@%atacCC -E%g
+---
+> s%@CPP@%gcc -E%g
+Only in diffstat.orig: configure.out
+Binary files diffstat/diffstat and diffstat.orig/diffstat differ
+Binary files diffstat/diffstat.o and diffstat.orig/diffstat.o differ
+diff -r diffstat/makefile diffstat.orig/makefile
+10c10
+< CC = atacCC
+---
+> CC = gcc
+Only in diffstat/testing: Xlib-1.patch-
+Only in diffstat/testing: Xlib-1.ref
+Only in diffstat/testing: Xlib-2.patch-
+Only in diffstat/testing: Xlib-2.ref
+Only in diffstat/testing: Xlib-3.patch-
+Only in diffstat/testing: Xlib-3.ref
+Only in diffstat/testing: config-1.ref
+Only in diffstat/testing: nugent.ref
+Only in diffstat/testing: xserver-1.ref
+Only in diffstat/testing: xserver-2.patch-
+Only in diffstat/testing: xserver-2.ref
+Only in diffstat/testing: xterm-1.patch-
+Only in diffstat/testing: xterm-1.ref
+Only in diffstat/testing: xterm-10.patch-
+Only in diffstat/testing: xterm-10.ref
+Only in diffstat/testing: xterm-11.patch-
+Only in diffstat/testing: xterm-11.ref
+Only in diffstat/testing: xterm-2.patch-
+Only in diffstat/testing: xterm-2.ref
+Only in diffstat/testing: xterm-3.patch-
+Only in diffstat/testing: xterm-3.ref
+Only in diffstat/testing: xterm-4.patch-
+Only in diffstat/testing: xterm-4.ref
+Only in diffstat/testing: xterm-5.patch-
+Only in diffstat/testing: xterm-5.ref
+Only in diffstat/testing: xterm-6.patch-
+Only in diffstat/testing: xterm-6.ref
+Only in diffstat/testing: xterm-7.ref
+Only in diffstat/testing: xterm-8.patch-
+Only in diffstat/testing: xterm-8.ref
+Only in diffstat/testing: xterm-9.patch-
+Only in diffstat/testing: xterm-9.ref
diff --git a/patch_cmds/diffstat/testing/case04.ref b/patch_cmds/diffstat/testing/case04.ref
new file mode 100644
index 0000000..48cc647
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04.ref
@@ -0,0 +1,41 @@
+ diffstat.orig/config.cache | 16 ++--!!!!
+ diffstat.orig/config.h | 2 +
+ diffstat.orig/config.log | 76 +++++++------------!!!!!!!!!!!!!!!!!!
+ diffstat.orig/config.status | 24 +++---!!!!!!
+ diffstat.orig/configure.out |only
+ diffstat.orig/diffstat |binary
+ diffstat.orig/diffstat.o |binary
+ diffstat.orig/makefile | 4 -
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ 40 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04R.ref b/patch_cmds/diffstat/testing/case04R.ref
new file mode 100644
index 0000000..b33d82b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04R.ref
@@ -0,0 +1,41 @@
+ diffstat.orig/configure.out |only
+ diffstat/config.cache | 16 ++--!!!!
+ diffstat/config.h | 2 -
+ diffstat/config.log | 76 +++++++++++--------!!!!!!!!!!!!!!!!!!
+ diffstat/config.status | 24 +++---!!!!!!
+ diffstat/diffstat |binary
+ diffstat/diffstat.o |binary
+ diffstat/makefile | 4 -
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ 40 files changed, 34 insertions(+), 28 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04Rp0.ref b/patch_cmds/diffstat/testing/case04Rp0.ref
new file mode 100644
index 0000000..b33d82b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04Rp0.ref
@@ -0,0 +1,41 @@
+ diffstat.orig/configure.out |only
+ diffstat/config.cache | 16 ++--!!!!
+ diffstat/config.h | 2 -
+ diffstat/config.log | 76 +++++++++++--------!!!!!!!!!!!!!!!!!!
+ diffstat/config.status | 24 +++---!!!!!!
+ diffstat/diffstat |binary
+ diffstat/diffstat.o |binary
+ diffstat/makefile | 4 -
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ 40 files changed, 34 insertions(+), 28 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04b.ref b/patch_cmds/diffstat/testing/case04b.ref
new file mode 100644
index 0000000..84c7b4a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04b.ref
@@ -0,0 +1,39 @@
+ diffstat.orig/config.cache | 16 ++--!!!!
+ diffstat.orig/config.h | 2 +
+ diffstat.orig/config.log | 76 +++++++------------!!!!!!!!!!!!!!!!!!
+ diffstat.orig/config.status | 24 +++---!!!!!!
+ diffstat.orig/configure.out |only
+ diffstat.orig/makefile | 4 -
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ 38 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04f0.ref b/patch_cmds/diffstat/testing/case04f0.ref
new file mode 100644
index 0000000..7765c5f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04f0.ref
@@ -0,0 +1,41 @@
+ diffstat.orig/config.cache | 16 4 + 4 - 8 !
+ diffstat.orig/config.h | 2 2 + 0 - 0 !
+ diffstat.orig/config.log | 76 15 + 23 - 38 !
+ diffstat.orig/config.status | 24 6 + 6 - 12 !
+ diffstat.orig/configure.out |only
+ diffstat.orig/diffstat |binary
+ diffstat.orig/diffstat.o |binary
+ diffstat.orig/makefile | 4 1 + 1 - 2 !
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ 40 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04k.ref b/patch_cmds/diffstat/testing/case04k.ref
new file mode 100644
index 0000000..b6f2928
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04k.ref
@@ -0,0 +1,81 @@
+ diffstat.orig/config.cache | 8 !!!!!!!!
+ diffstat.orig/config.cache | 8 ++++----
+ diffstat.orig/config.h | 1 +
+ diffstat.orig/config.h | 1 +
+ diffstat.orig/config.log | 38 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ diffstat.orig/config.log | 38 +++++++++++++++-----------------------
+ diffstat.orig/config.status | 12 !!!!!!!!!!!!
+ diffstat.orig/config.status | 12 ++++++------
+ diffstat.orig/configure.out |only
+ diffstat.orig/configure.out |only
+ diffstat.orig/diffstat |binary
+ diffstat.orig/diffstat |binary
+ diffstat.orig/diffstat.o |binary
+ diffstat.orig/diffstat.o |binary
+ diffstat.orig/makefile | 2 !!
+ diffstat.orig/makefile | 2 +-
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ diffstat/testing/xterm-9.ref |only
+ 80 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04p1.ref b/patch_cmds/diffstat/testing/case04p1.ref
new file mode 100644
index 0000000..4449805
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04p1.ref
@@ -0,0 +1,41 @@
+ config.cache | 16 ++--!!!!
+ config.h | 2 +
+ config.log | 76 +++++++++--------------!!!!!!!!!!!!!!!!!!!!!!!
+ config.status | 24 +++----!!!!!!
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ makefile | 4 -
+ testing/Xlib-1.patch- |only
+ testing/Xlib-1.ref |only
+ testing/Xlib-2.patch- |only
+ testing/Xlib-2.ref |only
+ testing/Xlib-3.patch- |only
+ testing/Xlib-3.ref |only
+ testing/config-1.ref |only
+ testing/nugent.ref |only
+ testing/xserver-1.ref |only
+ testing/xserver-2.patch- |only
+ testing/xserver-2.ref |only
+ testing/xterm-1.patch- |only
+ testing/xterm-1.ref |only
+ testing/xterm-10.patch- |only
+ testing/xterm-10.ref |only
+ testing/xterm-11.patch- |only
+ testing/xterm-11.ref |only
+ testing/xterm-2.patch- |only
+ testing/xterm-2.ref |only
+ testing/xterm-3.patch- |only
+ testing/xterm-3.ref |only
+ testing/xterm-4.patch- |only
+ testing/xterm-4.ref |only
+ testing/xterm-5.patch- |only
+ testing/xterm-5.ref |only
+ testing/xterm-6.patch- |only
+ testing/xterm-6.ref |only
+ testing/xterm-7.ref |only
+ testing/xterm-8.patch- |only
+ testing/xterm-8.ref |only
+ testing/xterm-9.patch- |only
+ testing/xterm-9.ref |only
+ 40 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04p9.ref b/patch_cmds/diffstat/testing/case04p9.ref
new file mode 100644
index 0000000..dcff047
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04p9.ref
@@ -0,0 +1,41 @@
+ Xlib-1.patch- |only
+ Xlib-1.ref |only
+ Xlib-2.patch- |only
+ Xlib-2.ref |only
+ Xlib-3.patch- |only
+ Xlib-3.ref |only
+ config-1.ref |only
+ config.cache | 16 ++---!!!!
+ config.h | 2 +
+ config.log | 76 ++++++++++-----------------!!!!!!!!!!!!!!!!!!!!!!!!!!
+ config.status | 24 ++++----!!!!!!!!
+ configure.out |only
+ diffstat |binary
+ diffstat.o |binary
+ makefile | 4 -
+ nugent.ref |only
+ xserver-1.ref |only
+ xserver-2.patch- |only
+ xserver-2.ref |only
+ xterm-1.patch- |only
+ xterm-1.ref |only
+ xterm-10.patch- |only
+ xterm-10.ref |only
+ xterm-11.patch- |only
+ xterm-11.ref |only
+ xterm-2.patch- |only
+ xterm-2.ref |only
+ xterm-3.patch- |only
+ xterm-3.ref |only
+ xterm-4.patch- |only
+ xterm-4.ref |only
+ xterm-5.patch- |only
+ xterm-5.ref |only
+ xterm-6.patch- |only
+ xterm-6.ref |only
+ xterm-7.ref |only
+ xterm-8.patch- |only
+ xterm-8.ref |only
+ xterm-9.patch- |only
+ xterm-9.ref |only
+ 40 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04r1.ref b/patch_cmds/diffstat/testing/case04r1.ref
new file mode 100644
index 0000000..9d2a23a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04r1.ref
@@ -0,0 +1,41 @@
+ diffstat.orig/config.cache | 16 ++--!!!!
+ diffstat.orig/config.h | 2 +
+ diffstat.orig/config.log | 76 +++++++-----------!!!!!!!!!!!!!!!!!!!
+ diffstat.orig/config.status | 24 +++---!!!!!!
+ diffstat.orig/configure.out |only
+ diffstat.orig/diffstat |binary
+ diffstat.orig/diffstat.o |binary
+ diffstat.orig/makefile | 4 !
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ 40 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04r2.ref b/patch_cmds/diffstat/testing/case04r2.ref
new file mode 100644
index 0000000..9d2a23a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04r2.ref
@@ -0,0 +1,41 @@
+ diffstat.orig/config.cache | 16 ++--!!!!
+ diffstat.orig/config.h | 2 +
+ diffstat.orig/config.log | 76 +++++++-----------!!!!!!!!!!!!!!!!!!!
+ diffstat.orig/config.status | 24 +++---!!!!!!
+ diffstat.orig/configure.out |only
+ diffstat.orig/diffstat |binary
+ diffstat.orig/diffstat.o |binary
+ diffstat.orig/makefile | 4 !
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ 40 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case04u.ref b/patch_cmds/diffstat/testing/case04u.ref
new file mode 100644
index 0000000..48cc647
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case04u.ref
@@ -0,0 +1,41 @@
+ diffstat.orig/config.cache | 16 ++--!!!!
+ diffstat.orig/config.h | 2 +
+ diffstat.orig/config.log | 76 +++++++------------!!!!!!!!!!!!!!!!!!
+ diffstat.orig/config.status | 24 +++---!!!!!!
+ diffstat.orig/configure.out |only
+ diffstat.orig/diffstat |binary
+ diffstat.orig/diffstat.o |binary
+ diffstat.orig/makefile | 4 -
+ diffstat/testing/Xlib-1.patch- |only
+ diffstat/testing/Xlib-1.ref |only
+ diffstat/testing/Xlib-2.patch- |only
+ diffstat/testing/Xlib-2.ref |only
+ diffstat/testing/Xlib-3.patch- |only
+ diffstat/testing/Xlib-3.ref |only
+ diffstat/testing/config-1.ref |only
+ diffstat/testing/nugent.ref |only
+ diffstat/testing/xserver-1.ref |only
+ diffstat/testing/xserver-2.patch- |only
+ diffstat/testing/xserver-2.ref |only
+ diffstat/testing/xterm-1.patch- |only
+ diffstat/testing/xterm-1.ref |only
+ diffstat/testing/xterm-10.patch- |only
+ diffstat/testing/xterm-10.ref |only
+ diffstat/testing/xterm-11.patch- |only
+ diffstat/testing/xterm-11.ref |only
+ diffstat/testing/xterm-2.patch- |only
+ diffstat/testing/xterm-2.ref |only
+ diffstat/testing/xterm-3.patch- |only
+ diffstat/testing/xterm-3.ref |only
+ diffstat/testing/xterm-4.patch- |only
+ diffstat/testing/xterm-4.ref |only
+ diffstat/testing/xterm-5.patch- |only
+ diffstat/testing/xterm-5.ref |only
+ diffstat/testing/xterm-6.patch- |only
+ diffstat/testing/xterm-6.ref |only
+ diffstat/testing/xterm-7.ref |only
+ diffstat/testing/xterm-8.patch- |only
+ diffstat/testing/xterm-8.ref |only
+ diffstat/testing/xterm-9.patch- |only
+ diffstat/testing/xterm-9.ref |only
+ 40 files changed, 28 insertions(+), 34 deletions(-), 60 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case05.pat b/patch_cmds/diffstat/testing/case05.pat
new file mode 100644
index 0000000..6328f4b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05.pat
@@ -0,0 +1,17 @@
+diff -r -c diffstat/config.cache diffstat.orig/config.cache
+*** 1.1 Fri Mar 15 19:27:13 1996
+--- diffstat.orig/config.cache Fri Mar 15 19:51:02 1996
+***************
+*** 13,28 ****
+ # --recheck option to rerun configure.
+ #
+ ac_cv_c_const=${ac_cv_c_const='yes'}
+- ac_cv_c_cross=${ac_cv_c_cross='yes'}
+ ac_cv_header_getopt_h=${ac_cv_header_getopt_h='yes'}
+ ac_cv_header_malloc_h=${ac_cv_header_malloc_h='yes'}
+--- 13,28 ----
+ # --recheck option to rerun configure.
+ #
+ ac_cv_c_const=${ac_cv_c_const='yes'}
+ ac_cv_header_getopt_h=${ac_cv_header_getopt_h='yes'}
+ ac_cv_header_malloc_h=${ac_cv_header_malloc_h='yes'}
diff --git a/patch_cmds/diffstat/testing/case05.ref b/patch_cmds/diffstat/testing/case05.ref
new file mode 100644
index 0000000..649df11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case05R.ref b/patch_cmds/diffstat/testing/case05R.ref
new file mode 100644
index 0000000..0f120f4
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05R.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case05Rp0.ref b/patch_cmds/diffstat/testing/case05Rp0.ref
new file mode 100644
index 0000000..8e29a87
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05Rp0.ref
@@ -0,0 +1,2 @@
+ diffstat/config.cache | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case05b.ref b/patch_cmds/diffstat/testing/case05b.ref
new file mode 100644
index 0000000..649df11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05b.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case05f0.ref b/patch_cmds/diffstat/testing/case05f0.ref
new file mode 100644
index 0000000..22e6a1e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05f0.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 0 + 1 - 0 !
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case05k.ref b/patch_cmds/diffstat/testing/case05k.ref
new file mode 100644
index 0000000..649df11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05k.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case05p1.ref b/patch_cmds/diffstat/testing/case05p1.ref
new file mode 100644
index 0000000..649df11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05p1.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case05p9.ref b/patch_cmds/diffstat/testing/case05p9.ref
new file mode 100644
index 0000000..649df11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05p9.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case05r1.ref b/patch_cmds/diffstat/testing/case05r1.ref
new file mode 100644
index 0000000..649df11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05r1.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case05r2.ref b/patch_cmds/diffstat/testing/case05r2.ref
new file mode 100644
index 0000000..649df11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05r2.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case05u.ref b/patch_cmds/diffstat/testing/case05u.ref
new file mode 100644
index 0000000..649df11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case05u.ref
@@ -0,0 +1,2 @@
+ config.cache | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case06.pat b/patch_cmds/diffstat/testing/case06.pat
new file mode 100644
index 0000000..ddc1760
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06.pat
@@ -0,0 +1,323 @@
+From esr@locke.ccil.org Sat Jan 13 18:02 EST 1996
+Received: from locke.ccil.org (esr@locke.ccil.org [205.164.136.88]) by mail.Clark.Net (8.7.3/8.6.5) with SMTP id SAA07403 for <dickey@clark.net>; Sat, 13 Jan 1996 18:02:54 -0500 (EST)
+Received: (esr@localhost) by locke.ccil.org (8.6.9/8.6.10) id SAA23481; Sat, 13 Jan 1996 18:28:57 -0500
+From: "Eric S. Raymond" <esr@locke.ccil.org>
+Message-Id: <199601132328.SAA23481@locke.ccil.org>
+Subject: patch #283 -- change line-breakout optimization logic
+To: zmbenhal@netcom.com, dickey@clark.net, ncurses-list@netcom.com
+Date: Sat, 13 Jan 1996 18:28:56 -0500 (EST)
+X-Mailer: ELM [version 2.4 PL24]
+Content-Type: text
+Content-Length: 9395
+Status: RO
+
+This patch (#283) changes the logic for line-breakout optimization.
+
+Daniel Barlow complained:
+>According to curs_inopts(3), curses periodically looks at the keyboard
+>while refreshing, and stops immediately if there is input pending.
+>
+>This works too well! I was playing with emacs to see if it would like
+>to use real ncurses routines to output to the screen instead of just
+>using it as a glorified termcap library, and found that if I held down
+>the `page down' key (which autorepeats), nothing displayed at all
+>until I let go of it again.
+
+This patch addresses the problem. See the comment leading the lib_doupdate.c
+patch band for details.
+
+This patch also makes a minor change in lib_initscr() to allow the maximum
+escape delay to be set from the environment. Finally, it includes a
+workaround for the ncurses 'p' test bug. A real fix is next on my agenda.
+
+Diffs between last version checked in and current workfile(s):
+
+--- NEWS 1996/01/11 19:47:02 1.3
++++ NEWS 1996/01/12 17:10:09
+@@ -6,6 +6,8 @@
+ * fixed broken wsyncup()/wysncdown(), as a result wnoutrefresh() now has
+ copy-changed-lines behavior.
+ * added and documented wresize() code.
++* changed the line-breakout optimization code to allow some lines to be
++ emitted before the first check.
+
+ ### ncurses-1.9.7 -> 1.9.8a
+
+--- ncurses/lib_doupdate.c 1996/01/12 16:09:44 1.6
++++ ncurses/lib_doupdate.c 1996/01/12 16:50:21
+@@ -43,6 +43,17 @@
+ #include "term.h"
+
+ /*
++ * This define controls the line-breakout optimization. Every once in a
++ * while during screen refresh, we want to check for input and abort the
++ * update if there's some waiting. CHECK_INTERVAL controls the number of
++ * changed lines to be emitted between input checks.
++ *
++ * Note: Input-check-and-abort is no longer done if the screen is being
++ * updated from scratch. This is a feature, not a bug.
++ */
++#define CHECK_INTERVAL 6
++
++/*
+ * Enable checking to see if doupdate and friends are tracking the true
+ * cursor position correctly. NOTE: this is a debugging hack which will
+ * work ONLY on ANSI-compatible terminals!
+@@ -146,6 +157,26 @@
+ }
+ }
+
++static bool check_pending(void)
++/* check for pending input */
++{
++ if (SP->_checkfd >= 0) {
++ fd_set fdset;
++ struct timeval ktimeout;
++
++ ktimeout.tv_sec =
++ ktimeout.tv_usec = 0;
++
++ FD_ZERO(&fdset);
++ FD_SET(SP->_checkfd, &fdset);
++ if (select(SP->_checkfd+1, &fdset, NULL, NULL, &ktimeout) != 0)
++ {
++ fflush(SP->_ofp);
++ return OK;
++ }
++ }
++}
++
+ /*
+ * No one supports recursive inline functions. However, gcc is quieter if we
+ * instantiate the recursive part separately.
+@@ -278,22 +309,6 @@
+ SP->_endwin = FALSE;
+ }
+
+- /* check for pending input */
+- if (SP->_checkfd >= 0) {
+- fd_set fdset;
+- struct timeval ktimeout;
+-
+- ktimeout.tv_sec =
+- ktimeout.tv_usec = 0;
+-
+- FD_ZERO(&fdset);
+- FD_SET(SP->_checkfd, &fdset);
+- if (select(SP->_checkfd+1, &fdset, NULL, NULL, &ktimeout) != 0) {
+- fflush(SP->_ofp);
+- return OK;
+- }
+- }
+-
+ /*
+ * FIXME: Full support for magic-cookie terminals could go in here.
+ * The theory: we scan the virtual screen looking for attribute
+@@ -315,10 +330,15 @@
+ ClrUpdate(newscr);
+ newscr->_clear = FALSE;
+ } else {
++ int changedlines;
++
+ _nc_scroll_optimize();
+
+ T(("Transforming lines"));
+- for (i = 0; i < min(screen_lines, newscr->_maxy + 1); i++) {
++ for (i = changedlines = 0;
++ i < min(screen_lines,newscr->_maxy+1);
++ i++)
++ {
+ /*
+ * newscr->line[i].firstchar is normally set
+ * by wnoutrefresh. curscr->line[i].firstchar
+@@ -327,17 +347,43 @@
+ */
+ if (newscr->_line[i].firstchar != _NOCHANGE
+ || curscr->_line[i].firstchar != _NOCHANGE)
++ {
+ TransformLine(i);
++ changedlines++;
++ }
++
++ /* mark line changed successfully */
++ if (i <= newscr->_maxy)
++ {
++ newscr->_line[i].firstchar = _NOCHANGE;
++ newscr->_line[i].lastchar = _NOCHANGE;
++ newscr->_line[i].oldindex = i;
++ }
++ if (i <= curscr->_maxy)
++ {
++ curscr->_line[i].firstchar = _NOCHANGE;
++ curscr->_line[i].lastchar = _NOCHANGE;
++ curscr->_line[i].oldindex = i;
++ }
++
++ /*
++ * Here is our line-breakout optimization.
++ */
++ if ((changedlines % CHECK_INTERVAL) == changedlines-1 && check_pending())
++ goto cleanup;
+ }
+ }
+ }
+- T(("marking screen as updated"));
+- for (i = 0; i <= newscr->_maxy; i++) {
++
++ /* this code won't be executed often */
++ for (i = screen_lines; i <= newscr->_maxy; i++)
++ {
+ newscr->_line[i].firstchar = _NOCHANGE;
+ newscr->_line[i].lastchar = _NOCHANGE;
+ newscr->_line[i].oldindex = i;
+ }
+- for (i = 0; i <= curscr->_maxy; i++) {
++ for (i = screen_lines; i <= curscr->_maxy; i++)
++ {
+ curscr->_line[i].firstchar = _NOCHANGE;
+ curscr->_line[i].lastchar = _NOCHANGE;
+ curscr->_line[i].oldindex = i;
+@@ -346,10 +392,11 @@
+ curscr->_curx = newscr->_curx;
+ curscr->_cury = newscr->_cury;
+
++ GoTo(curscr->_cury, curscr->_curx);
++
++ cleanup:
+ if (curscr->_attrs != A_NORMAL)
+ vidattr(curscr->_attrs = A_NORMAL);
+-
+- GoTo(curscr->_cury, curscr->_curx);
+
+ fflush(SP->_ofp);
+
+--- ncurses/lib_initscr.c 1996/01/12 20:11:34 1.1
++++ ncurses/lib_initscr.c 1996/01/12 20:17:54
+@@ -41,6 +41,10 @@
+ exit(1);
+ }
+
++ /* allow user to set maximum escape delay from the environment */
++ if ((name = getenv("ESCDELAY")))
++ ESCDELAY = atoi(getenv("ESCDELAY"));
++
+ def_shell_mode();
+
+ /* follow the XPG4 requirement to turn echo off at this point */
+--- ncurses/lib_pad.c 1995/12/29 15:34:11 1.2
++++ ncurses/lib_pad.c 1996/01/13 17:56:24
+@@ -107,6 +107,7 @@
+ short m, n;
+ short pmaxrow;
+ short pmaxcol;
++bool wide;
+
+ T(("pnoutrefresh(%p, %d, %d, %d, %d, %d, %d) called",
+ win, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol));
+@@ -140,20 +141,46 @@
+
+ T(("pad being refreshed"));
+
++ /*
++ * For pure efficiency, we'd want to transfer scrolling information
++ * from the pad to newscr whenever the window is wide enough that
++ * its update will dominate the cost of the update for the horizontal
++ * band of newscr that it occupies. Unfortunately, this threshold
++ * tends to be complex to estimate, and in any case scrolling the
++ * whole band and rewriting the parts outside win's image would look
++ * really ugly. So. What we do is consider the pad "wide" if it
++ * either (a) occupies the whole width of newscr, or (b) occupies
++ * all but at most one column on either vertical edge of the screen
++ * (this caters to fussy people who put boxes around full-screen
++ * windows). Note that changing this formula will not break any code,
++ * merely change the costs of various update cases.
++ */
++ wide = (sminrow <= 1 && win->_maxx >= (newscr->_maxx - 1));
++
+ for (i = pminrow, m = sminrow; i <= pmaxrow; i++, m++) {
++ register struct ldat *nline = &newscr->_line[m];
++ register struct ldat *oline = &win->_line[i];
++
+ for (j = pmincol, n = smincol; j <= pmaxcol; j++, n++) {
+- if (win->_line[i].text[j] != newscr->_line[m].text[n]) {
+- newscr->_line[m].text[n] = win->_line[i].text[j];
++ if (oline->text[j] != nline->text[n]) {
++ nline->text[n] = oline->text[j];
++
++ if (nline->firstchar == _NOCHANGE)
++ nline->firstchar = nline->lastchar = n;
++ else if (n < nline->firstchar)
++ nline->firstchar = n;
++ else if (n > nline->lastchar)
++ nline->lastchar = n;
++ }
++ }
++
++ if (wide) {
++ int oind = oline->oldindex;
+
+- if (newscr->_line[m].firstchar == _NOCHANGE)
+- newscr->_line[m].firstchar = newscr->_line[m].lastchar = n;
+- else if (n < newscr->_line[m].firstchar)
+- newscr->_line[m].firstchar = n;
+- else if (n > newscr->_line[m].lastchar)
+- newscr->_line[m].lastchar = n;
+- }
++ nline->oldindex = (oind == _NEWINDEX) ? _NEWINDEX : sminrow + oind;
+ }
+- win->_line[i].firstchar = win->_line[i].lastchar = _NOCHANGE;
++ oline->firstchar = oline->lastchar = _NOCHANGE;
++ oline->oldindex = i;
+ }
+
+ win->_begx = smincol;
+@@ -176,6 +203,7 @@
+ newscr->_cury = win->_cury - pminrow + win->_begy;
+ newscr->_curx = win->_curx - pmincol + win->_begx;
+ }
++ win->_flags &= ~_HASMOVED;
+ return OK;
+ }
+
+--- test/ncurses.c 1996/01/11 19:49:39 1.4
++++ test/ncurses.c 1996/01/13 23:00:26
+@@ -1368,6 +1368,35 @@
+ }
+
+ mvaddch(porty - 1, portx - 1, ACS_LRCORNER);
++
++ /*
++ * FIXME: this touchwin should not be necessary!
++ * There is something not quite right with the pad code
++ * Thomas Dickey writes:
++ *
++ * In the ncurses 'p' test, if I (now) press '<', '>', '<', then the
++ * right boundary of the box that outlines the pad is blanked. That's
++ * because
++ *
++ * + the value that marks the right boundary (porty) is incremented,
++ *
++ * + a new vertical line is written to stdscr
++ *
++ * + stdscr is flushed with wnoutrefresh, clearing its firstchar &
++ * lastchar markers. This writes the change (the new vertical line)
++ * to newscr.
++ *
++ * => previously stdscr was written to newscr entirely
++ *
++ * + the pad is written using prefresh, which writes directly to
++ * newscr, bypassing stdscr entirely.
++ *
++ * When I've pressed '>' (see above), this means that stdscr contains
++ * two columns of ACS_VLINE characters. The left one (column 79) is
++ * shadowed by the pad that's written to newscr.
++ */
++ touchwin(stdscr);
++
+ wnoutrefresh(stdscr);
+
+ prefresh(pad,
+
+End of diffs.
+
+
diff --git a/patch_cmds/diffstat/testing/case06.ref b/patch_cmds/diffstat/testing/case06.ref
new file mode 100644
index 0000000..3fbf503
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 +
+ ncurses/lib_doupdate.c | 91 +++++++++++++++++++++++++++++++++++++------------
+ ncurses/lib_initscr.c | 4 ++
+ ncurses/lib_pad.c | 48 ++++++++++++++++++++-----
+ test/ncurses.c | 29 +++++++++++++++
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06R.ref b/patch_cmds/diffstat/testing/case06R.ref
new file mode 100644
index 0000000..8cae5fd
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06R.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 -
+ ncurses/lib_doupdate.c | 91 +++++++++++--------------------------------------
+ ncurses/lib_initscr.c | 4 --
+ ncurses/lib_pad.c | 48 +++++--------------------
+ test/ncurses.c | 29 ---------------
+ 5 files changed, 32 insertions(+), 142 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06Rp0.ref b/patch_cmds/diffstat/testing/case06Rp0.ref
new file mode 100644
index 0000000..8cae5fd
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06Rp0.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 -
+ ncurses/lib_doupdate.c | 91 +++++++++++--------------------------------------
+ ncurses/lib_initscr.c | 4 --
+ ncurses/lib_pad.c | 48 +++++--------------------
+ test/ncurses.c | 29 ---------------
+ 5 files changed, 32 insertions(+), 142 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06b.ref b/patch_cmds/diffstat/testing/case06b.ref
new file mode 100644
index 0000000..3fbf503
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06b.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 +
+ ncurses/lib_doupdate.c | 91 +++++++++++++++++++++++++++++++++++++------------
+ ncurses/lib_initscr.c | 4 ++
+ ncurses/lib_pad.c | 48 ++++++++++++++++++++-----
+ test/ncurses.c | 29 +++++++++++++++
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06f0.ref b/patch_cmds/diffstat/testing/case06f0.ref
new file mode 100644
index 0000000..0ca6092
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06f0.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 2 + 0 - 0 !
+ ncurses/lib_doupdate.c | 91 69 + 22 - 0 !
+ ncurses/lib_initscr.c | 4 4 + 0 - 0 !
+ ncurses/lib_pad.c | 48 38 + 10 - 0 !
+ test/ncurses.c | 29 29 + 0 - 0 !
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06k.ref b/patch_cmds/diffstat/testing/case06k.ref
new file mode 100644
index 0000000..3fbf503
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06k.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 +
+ ncurses/lib_doupdate.c | 91 +++++++++++++++++++++++++++++++++++++------------
+ ncurses/lib_initscr.c | 4 ++
+ ncurses/lib_pad.c | 48 ++++++++++++++++++++-----
+ test/ncurses.c | 29 +++++++++++++++
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06p1.ref b/patch_cmds/diffstat/testing/case06p1.ref
new file mode 100644
index 0000000..eb6b552
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06p1.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 +
+ lib_doupdate.c | 91 +++++++++++++++++++++++++++++++++++++++++++--------------
+ lib_initscr.c | 4 ++
+ lib_pad.c | 48 +++++++++++++++++++++++-------
+ ncurses.c | 29 ++++++++++++++++++
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06p9.ref b/patch_cmds/diffstat/testing/case06p9.ref
new file mode 100644
index 0000000..eb6b552
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06p9.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 +
+ lib_doupdate.c | 91 +++++++++++++++++++++++++++++++++++++++++++--------------
+ lib_initscr.c | 4 ++
+ lib_pad.c | 48 +++++++++++++++++++++++-------
+ ncurses.c | 29 ++++++++++++++++++
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06r1.ref b/patch_cmds/diffstat/testing/case06r1.ref
new file mode 100644
index 0000000..5a05975
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06r1.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 +
+ ncurses/lib_doupdate.c | 91 +++++++++++++++++++++++++++++++++++++------------
+ ncurses/lib_initscr.c | 4 ++
+ ncurses/lib_pad.c | 48 ++++++++++++++++++++-----
+ test/ncurses.c | 29 ++++++++++++++++
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06r2.ref b/patch_cmds/diffstat/testing/case06r2.ref
new file mode 100644
index 0000000..38d1cb2
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06r2.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 +
+ ncurses/lib_doupdate.c | 91 +++++++++++++++++++++++++++++++++++++------------
+ ncurses/lib_initscr.c | 4 ++
+ ncurses/lib_pad.c | 48 +++++++++++++++++++++-----
+ test/ncurses.c | 29 ++++++++++++++++
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case06u.ref b/patch_cmds/diffstat/testing/case06u.ref
new file mode 100644
index 0000000..3fbf503
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case06u.ref
@@ -0,0 +1,6 @@
+ NEWS | 2 +
+ ncurses/lib_doupdate.c | 91 +++++++++++++++++++++++++++++++++++++------------
+ ncurses/lib_initscr.c | 4 ++
+ ncurses/lib_pad.c | 48 ++++++++++++++++++++-----
+ test/ncurses.c | 29 +++++++++++++++
+ 5 files changed, 142 insertions(+), 32 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case07.pat b/patch_cmds/diffstat/testing/case07.pat
new file mode 100644
index 0000000..e72061d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07.pat
@@ -0,0 +1,107 @@
+--- /dev/null 1.1 Sun Jul 17 19:46:18 1994
++++ ncurses-1.9.8a_960131_e285r/man/resizeterm.3x Wed Jan 31 20:21:04 1996
+@@ -0,0 +1,53 @@
++.\"*****************************************************************************
++.\" Testcase for "resizeterm" *
++.\" *
++.\" A discussion of this file is found at: *
++.\" http://invisible-island.net/ncurses/ncurses-license.html#ncurses_1_9_3 *
++.\" A later version of this manpage is included as part of ncurses. *
++.\"*****************************************************************************
++.TH resizeterm 3X ""
++.
++.SH NAME
++\fBresizeterm\fR - change the curses terminal size
++.
++.SH SYNOPSIS
++\fB#include <curses.h>\fR
++
++\fBint resizeterm(int lines, int columns);\fR
++.
++.SH DESCRIPTION
++This is an extension to the curses library.
++It provides callers with a hook into the \fBncurses\fR data to resize windows,
++primarily for use by programs running in an X Window terminal (e.g., xterm).
++The function \fBresizeterm\fR resizes the standard and current windows
++to the specified dimensions, and adjusts other bookkeeping data used by
++the \fBncurses\fR library that record the window dimensions.
++
++When resizing the windows, the function blank-fills the areas that are
++extended. The calling application should fill in these areas with
++appropriate data.
++
++The function does not resize other windows.
++.
++.SH RETURN VALUE
++The function returns the integer \fBERR\fR upon failure and \fBOK\fR on success.
++It will fail if either of the dimensions less than or equal to zero,
++or if an error occurs while (re)allocating memory for the windows.
++.
++.SH NOTES
++While this function is intended to be used to support a signal handler
++(i.e., for SIGWINCH), care should be taken to avoid invoking it in a
++context where \fBmalloc\fR or \fBrealloc\fR may have been interrupted,
++since it uses those functions.
++.
++.SH SEE ALSO
++\fBwresize\fR(3x).
++.
++.SH AUTHOR
++Thomas Dickey (from an equivalent function written in 1988 for BSD curses).
++.\"#
++.\"# The following sets edit modes for GNU EMACS
++.\"# Local Variables:
++.\"# mode:nroff
++.\"# fill-column:79
++.\"# End:
+--- /dev/null Sun Jul 17 19:46:18 1994
++++ ncurses-1.9.8a_960131_e285r/man/wresize.3x Wed Jan 31 20:21:04 1996
+@@ -0,0 +1,47 @@
++.\"*****************************************************************************
++.\" Testcase for "wresize" *
++.\" *
++.\" A discussion of this file is found at: *
++.\" http://invisible-island.net/ncurses/ncurses-license.html#ncurses_1_9_3 *
++.\" A later version of this manpage is included as part of ncurses. *
++.\" Copyright 1995 by Thomas E. Dickey. All Rights Reserved. *
++.\"*****************************************************************************
++.TH wresize 3X ""
++.
++.SH NAME
++\fBwresize\fR - resize a curses window
++.
++.SH SYNOPSIS
++\fB#include <curses.h>\fR
++
++\fBint wresize(WINDOW *win, int lines, int columns);\fR
++.
++.SH DESCRIPTION
++The \fBwresize\fR function reallocates storage for an \fBncurses\fR
++window to adjust its dimensions to the specified values.
++If either dimension is larger than the current values, the
++window's data is filled with blanks that have the current background rendition
++(as set by \fBwbkgndset\fR) merged into them.
++.
++.SH RETURN VALUE
++The function returns the integer \fBERR\fR upon failure and \fBOK\fR on success.
++It will fail if either of the dimensions less than or equal to zero,
++or if an error occurs while (re)allocating memory for the window.
++.
++.SH NOTES
++The only restriction placed on the dimensions is that they be greater than zero.
++The dimensions are not compared to \fBcurses\fR screen dimensions to
++simplify the logic of \fBresizeterm\fR.
++The caller must ensure that the window's dimensions fit within the
++actual screen dimensions.
++.
++.SH SEE ALSO
++\fBresizeterm\fR(3x).
++.
++.SH AUTHOR
++Thomas Dickey (from an equivalent function written in 1988 for BSD curses).
++.\"#
++.\"# The following sets edit modes for GNU EMACS
++.\"# Local Variables:
++.\"# mode:nroff
++.\"# fill-column:79
++.\"# End:
diff --git a/patch_cmds/diffstat/testing/case07.ref b/patch_cmds/diffstat/testing/case07.ref
new file mode 100644
index 0000000..c11d383
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07.ref
@@ -0,0 +1,3 @@
+ resizeterm.3x | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ wresize.3x | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case07R.ref b/patch_cmds/diffstat/testing/case07R.ref
new file mode 100644
index 0000000..95d7724
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07R.ref
@@ -0,0 +1,2 @@
+ null | 100 -------------------------------------------------------------------
+ 1 file changed, 100 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case07Rp0.ref b/patch_cmds/diffstat/testing/case07Rp0.ref
new file mode 100644
index 0000000..30e3f11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07Rp0.ref
@@ -0,0 +1,2 @@
+ /dev/null | 100 --------------------------------------------------------------
+ 1 file changed, 100 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case07b.ref b/patch_cmds/diffstat/testing/case07b.ref
new file mode 100644
index 0000000..c11d383
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07b.ref
@@ -0,0 +1,3 @@
+ resizeterm.3x | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ wresize.3x | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case07f0.ref b/patch_cmds/diffstat/testing/case07f0.ref
new file mode 100644
index 0000000..522fa8d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07f0.ref
@@ -0,0 +1,3 @@
+ resizeterm.3x | 53 53 + 0 - 0 !
+ wresize.3x | 47 47 + 0 - 0 !
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case07k.ref b/patch_cmds/diffstat/testing/case07k.ref
new file mode 100644
index 0000000..c11d383
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07k.ref
@@ -0,0 +1,3 @@
+ resizeterm.3x | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ wresize.3x | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case07p1.ref b/patch_cmds/diffstat/testing/case07p1.ref
new file mode 100644
index 0000000..0c52128
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07p1.ref
@@ -0,0 +1,3 @@
+ man/resizeterm.3x | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ man/wresize.3x | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case07p9.ref b/patch_cmds/diffstat/testing/case07p9.ref
new file mode 100644
index 0000000..c11d383
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07p9.ref
@@ -0,0 +1,3 @@
+ resizeterm.3x | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ wresize.3x | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case07r1.ref b/patch_cmds/diffstat/testing/case07r1.ref
new file mode 100644
index 0000000..c11d383
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07r1.ref
@@ -0,0 +1,3 @@
+ resizeterm.3x | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ wresize.3x | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case07r2.ref b/patch_cmds/diffstat/testing/case07r2.ref
new file mode 100644
index 0000000..c11d383
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07r2.ref
@@ -0,0 +1,3 @@
+ resizeterm.3x | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ wresize.3x | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case07u.ref b/patch_cmds/diffstat/testing/case07u.ref
new file mode 100644
index 0000000..c11d383
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case07u.ref
@@ -0,0 +1,3 @@
+ resizeterm.3x | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ wresize.3x | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 100 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case08.pat b/patch_cmds/diffstat/testing/case08.pat
new file mode 100644
index 0000000..380420a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08.pat
@@ -0,0 +1,343 @@
+Index: Imakefile
+*** /build/x11r6/XFree86-3.1.2Bn/xc/programs/xterm/Imakefile Fri Jan 26 11:43:22 1996
+--- /build/x11r6/XFree86-current/xc/programs/xterm/Imakefile Sun Jan 28 20:45:35 1996
+***************
+*** 10,15 ****
+--- 10,30 ----
+ XCOMM
+
+ /*
++ * Fixes to allow compile with X11R5
++ */
++ #ifndef XkbClientDefines
++ #define XkbClientDefines /**/
++ #endif
++
++ #ifndef XkbClientDepLibs
++ #define XkbClientDepLibs /**/
++ #endif
++
++ #ifndef XkbClientLibs
++ #define XkbClientLibs /**/
++ #endif
++
++ /*
+ * add -DWTMP and -DLASTLOG if you want them; make sure that bcopy can
+ * handle overlapping copies before using it.
+ */
+Index: Tekproc.c
+*** /build/x11r6/XFree86-3.1.2Bn/xc/programs/xterm/Tekproc.c Tue Jan 16 15:43:01 1996
+--- /build/x11r6/XFree86-current/xc/programs/xterm/Tekproc.c Sun Jan 28 20:45:35 1996
+***************
+*** 64,70 ****
+--- 64,77 ----
+ #include <X11/StringDefs.h>
+ #include <X11/Shell.h>
+ #include <X11/Xmu/CharSet.h>
++
++ #if XtSpecificationRelease >= 6
+ #include <X11/Xpoll.h>
++ #else
++ #define Select(n,r,w,e,t) select(0,(fd_set*)r,(fd_set*)w,(fd_set*)e,(struct timeval *)t)
++ #define XFD_COPYSET(src,dst) bcopy((src)->fds_bits, (dst)->fds_bits, sizeof(fd_set))
++ #endif
++
+ #include <stdio.h>
+ #include <errno.h>
+ #include <setjmp.h>
+Index: charproc.c
+*** /build/x11r6/XFree86-3.1.2Bn/xc/programs/xterm/charproc.c Fri Jan 26 11:43:22 1996
+--- /build/x11r6/XFree86-current/xc/programs/xterm/charproc.c Sun Jan 28 20:45:35 1996
+***************
+*** 63,70 ****
+--- 63,77 ----
+ #include <X11/Xmu/Atoms.h>
+ #include <X11/Xmu/CharSet.h>
+ #include <X11/Xmu/Converters.h>
++
++ #if XtSpecificationRelease >= 6
+ #include <X11/Xaw/XawImP.h>
+ #include <X11/Xpoll.h>
++ #else
++ #define Select(n,r,w,e,t) select(0,(fd_set*)r,(fd_set*)w,(fd_set*)e,(struct timeval *)t)
++ #define XFD_COPYSET(src,dst) bcopy((src)->fds_bits, (dst)->fds_bits, sizeof(fd_set))
++ #endif
++
+ #include <stdio.h>
+ #include <errno.h>
+ #include <setjmp.h>
+***************
+*** 572,577 ****
+--- 579,585 ----
+ {"font6", "Font6", XtRString, sizeof(String),
+ XtOffsetOf(XtermWidgetRec, screen.menu_font_names[fontMenu_font6]),
+ XtRString, (XtPointer) NULL},
++ #if XtSpecificationRelease >= 6
+ {XtNinputMethod, XtCInputMethod, XtRString, sizeof(char*),
+ XtOffsetOf(XtermWidgetRec, misc.input_method),
+ XtRString, (XtPointer)NULL},
+***************
+*** 581,586 ****
+--- 589,595 ----
+ {XtNopenIm, XtCOpenIm, XtRBoolean, sizeof(Boolean),
+ XtOffsetOf(XtermWidgetRec, misc.open_im),
+ XtRImmediate, (XtPointer)TRUE},
++ #endif
+ {XtNcolor0, XtCForeground, XtRPixel, sizeof(Pixel),
+ XtOffsetOf(XtermWidgetRec, screen.colors[COLOR_0]),
+ XtRString, "XtDefaultForeground"},
+***************
+*** 1153,1158 ****
+--- 1162,1172 ----
+ ? 8 : 0));
+ }
+ break;
++ case 39:
++ if( screen->colorMode ) {
++ SGR_Foreground(-1);
++ }
++ break;
+ case 40:
+ case 41:
+ case 42:
+***************
+*** 1165,1170 ****
+--- 1179,1189 ----
+ SGR_Background(param[row] - 40);
+ }
+ break;
++ case 49:
++ if( screen->colorMode ) {
++ SGR_Background(-1);
++ }
++ break;
+ case 100:
+ if( screen->colorMode ) {
+ if (term->flags & FG_COLOR)
+***************
+*** 2639,2644 ****
+--- 2658,2666 ----
+ for (i = 0; i < MAXCOLORS; i++) {
+ new->screen.colors[i] = request->screen.colors[i];
+ }
++
++ new->cur_foreground = 0;
++ new->cur_background = 0;
+
+ /*
+ * The definition of -rv now is that it changes the definition of
+Index: data.c
+*** /build/x11r6/XFree86-3.1.2Bn/xc/programs/xterm/data.c Sat Jan 6 08:11:01 1996
+--- /build/x11r6/XFree86-current/xc/programs/xterm/data.c Sun Jan 28 20:45:35 1996
+***************
+*** 26,32 ****
+--- 26,36 ----
+ */
+
+ #include "ptyx.h" /* gets Xt stuff, too */
++
++ #if XtSpecificationRelease >= 6
+ #include <X11/Xpoll.h>
++ #endif
++
+ #include "data.h"
+ #include <setjmp.h>
+
+Index: main.c
+*** /build/x11r6/XFree86-3.1.2Bn/xc/programs/xterm/main.c Thu Jan 11 14:01:01 1996
+--- /build/x11r6/XFree86-current/xc/programs/xterm/main.c Sun Jan 28 20:45:35 1996
+***************
+*** 75,82 ****
+--- 75,87 ----
+ #include <X11/Xos.h>
+ #include <X11/cursorfont.h>
+ #include <X11/Xaw/SimpleMenu.h>
++
++ #if XtSpecificationRelease >= 6
+ #include <X11/Xpoll.h>
++ #endif
++
+ #include <X11/Xlocale.h>
++
+ #include <pwd.h>
+ #include <ctype.h>
+ #include "data.h"
+***************
+*** 127,132 ****
+--- 132,138 ----
+ #endif
+
+ #ifdef SVR4
++ #undef SYSV /* predefined on Solaris 2.4 */
+ #define SYSV /* SVR4 is (approx) superset of SVR3 */
+ #define ATT
+ #define USE_SYSV_UTMP
+***************
+*** 453,459 ****
+ #endif
+
+ #ifdef SYSV
+! extern char *ptsname();
+ #endif
+
+ #include "xterm.h"
+--- 459,465 ----
+ #endif
+
+ #ifdef SYSV
+! extern char *ptsname PROTO((int));
+ #endif
+
+ #include "xterm.h"
+***************
+*** 1293,1303 ****
+
+ if (setegid(rgid) == -1)
+ (void) fprintf(stderr, "setegid(%d): %s\n",
+! rgid, strerror(errno));
+
+ if (seteuid(ruid) == -1)
+ (void) fprintf(stderr, "seteuid(%d): %s\n",
+! ruid, strerror(errno));
+ #endif
+
+ XtSetErrorHandler(xt_error);
+--- 1299,1309 ----
+
+ if (setegid(rgid) == -1)
+ (void) fprintf(stderr, "setegid(%d): %s\n",
+! (int) rgid, strerror(errno));
+
+ if (seteuid(ruid) == -1)
+ (void) fprintf(stderr, "seteuid(%d): %s\n",
+! (int) ruid, strerror(errno));
+ #endif
+
+ XtSetErrorHandler(xt_error);
+***************
+*** 1317,1327 ****
+ #ifdef HAS_POSIX_SAVED_IDS
+ if (seteuid(euid) == -1)
+ (void) fprintf(stderr, "seteuid(%d): %s\n",
+! euid, strerror(errno));
+
+ if (setegid(egid) == -1)
+ (void) fprintf(stderr, "setegid(%d): %s\n",
+! egid, strerror(errno));
+ #endif
+ }
+
+--- 1323,1333 ----
+ #ifdef HAS_POSIX_SAVED_IDS
+ if (seteuid(euid) == -1)
+ (void) fprintf(stderr, "seteuid(%d): %s\n",
+! (int) euid, strerror(errno));
+
+ if (setegid(egid) == -1)
+ (void) fprintf(stderr, "setegid(%d): %s\n",
+! (int) egid, strerror(errno));
+ #endif
+ }
+
+***************
+*** 1985,1992 ****
+ register TScreen *screen = &term->screen;
+ #ifdef USE_HANDSHAKE
+ handshake_t handshake;
+- #else
+- int fds[2];
+ #endif
+ int tty = -1;
+ int done;
+--- 1991,1996 ----
+***************
+*** 2458,2464 ****
+ {
+ #include <grp.h>
+ struct group *ttygrp;
+! if (ttygrp = getgrnam("tty")) {
+ /* change ownership of tty to real uid, "tty" gid */
+ chown (ttydev, screen->uid, ttygrp->gr_gid);
+ chmod (ttydev, 0620);
+--- 2462,2468 ----
+ {
+ #include <grp.h>
+ struct group *ttygrp;
+! if ((ttygrp = getgrnam("tty")) != 0) {
+ /* change ownership of tty to real uid, "tty" gid */
+ chown (ttydev, screen->uid, ttygrp->gr_gid);
+ chmod (ttydev, 0620);
+Index: menu.c
+*** /build/x11r6/XFree86-3.1.2Bn/xc/programs/xterm/menu.c Tue Jan 16 15:43:01 1996
+--- /build/x11r6/XFree86-current/xc/programs/xterm/menu.c Sun Jan 28 20:45:35 1996
+***************
+*** 397,411 ****
+ XtPointer closure, data;
+ {
+ register TScreen *screen = &term->screen;
+! Time time = CurrentTime; /* XXX - wrong */
+
+ if (screen->grabbedKbd) {
+! XUngrabKeyboard (screen->display, time);
+ ReverseVideo (term);
+ screen->grabbedKbd = FALSE;
+ } else {
+ if (XGrabKeyboard (screen->display, term->core.window,
+! True, GrabModeAsync, GrabModeAsync, time)
+ != GrabSuccess) {
+ Bell(XkbBI_MinorError, 100);
+ } else {
+--- 397,411 ----
+ XtPointer closure, data;
+ {
+ register TScreen *screen = &term->screen;
+! Time now = CurrentTime; /* XXX - wrong */
+
+ if (screen->grabbedKbd) {
+! XUngrabKeyboard (screen->display, now);
+ ReverseVideo (term);
+ screen->grabbedKbd = FALSE;
+ } else {
+ if (XGrabKeyboard (screen->display, term->core.window,
+! True, GrabModeAsync, GrabModeAsync, now)
+ != GrabSuccess) {
+ Bell(XkbBI_MinorError, 100);
+ } else {
+Index: misc.c
+*** /build/x11r6/XFree86-3.1.2Bn/xc/programs/xterm/misc.c Fri Jan 26 11:43:22 1996
+--- /build/x11r6/XFree86-current/xc/programs/xterm/misc.c Sun Jan 28 20:45:35 1996
+***************
+*** 50,55 ****
+--- 50,61 ----
+
+ #include "xterm.h"
+
++ #if XtSpecificationRelease < 6
++ #ifndef X_GETTIMEOFDAY
++ #define X_GETTIMEOFDAY(t) gettimeofday(t,(struct timezone *)0)
++ #endif
++ #endif
++
+ #ifdef AMOEBA
+ #include "amoeba.h"
+ #include "module/proc.h"
+Index: scrollbar.c
+*** /build/x11r6/XFree86-3.1.2Bn/xc/programs/xterm/scrollbar.c Tue Jan 16 15:43:01 1996
+--- /build/x11r6/XFree86-current/xc/programs/xterm/scrollbar.c Sun Jan 28 20:45:35 1996
+***************
+*** 221,227 ****
+ register Widget scrollWidget;
+ {
+ Arg args[4];
+! int nargs = XtNumber(args);
+ unsigned long bg, fg, bdr;
+ Pixmap bdpix;
+
+--- 221,227 ----
+ register Widget scrollWidget;
+ {
+ Arg args[4];
+! Cardinal nargs = XtNumber(args);
+ unsigned long bg, fg, bdr;
+ Pixmap bdpix;
+
diff --git a/patch_cmds/diffstat/testing/case08.ref b/patch_cmds/diffstat/testing/case08.ref
new file mode 100644
index 0000000..53afea5
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 +++++++++++++++
+ Tekproc.c | 7 +++++++
+ charproc.c | 22 ++++++++++++++++++++++
+ data.c | 4 ++++
+ main.c | 20 ++++++--!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ++++++
+ scrollbar.c | 2 !!
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08R.ref b/patch_cmds/diffstat/testing/case08R.ref
new file mode 100644
index 0000000..6e8272a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08R.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 ---------------
+ Tekproc.c | 7 -------
+ charproc.c | 22 ----------------------
+ data.c | 4 ----
+ main.c | 20 ++------!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ------
+ scrollbar.c | 2 !!
+ 8 files changed, 2 insertions(+), 60 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08Rp0.ref b/patch_cmds/diffstat/testing/case08Rp0.ref
new file mode 100644
index 0000000..6e8272a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08Rp0.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 ---------------
+ Tekproc.c | 7 -------
+ charproc.c | 22 ----------------------
+ data.c | 4 ----
+ main.c | 20 ++------!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ------
+ scrollbar.c | 2 !!
+ 8 files changed, 2 insertions(+), 60 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08b.ref b/patch_cmds/diffstat/testing/case08b.ref
new file mode 100644
index 0000000..53afea5
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08b.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 +++++++++++++++
+ Tekproc.c | 7 +++++++
+ charproc.c | 22 ++++++++++++++++++++++
+ data.c | 4 ++++
+ main.c | 20 ++++++--!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ++++++
+ scrollbar.c | 2 !!
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08f0.ref b/patch_cmds/diffstat/testing/case08f0.ref
new file mode 100644
index 0000000..7761a8d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08f0.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 15 + 0 - 0 !
+ Tekproc.c | 7 7 + 0 - 0 !
+ charproc.c | 22 22 + 0 - 0 !
+ data.c | 4 4 + 0 - 0 !
+ main.c | 20 6 + 2 - 12 !
+ menu.c | 6 0 + 0 - 6 !
+ misc.c | 6 6 + 0 - 0 !
+ scrollbar.c | 2 0 + 0 - 2 !
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08k.ref b/patch_cmds/diffstat/testing/case08k.ref
new file mode 100644
index 0000000..53afea5
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08k.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 +++++++++++++++
+ Tekproc.c | 7 +++++++
+ charproc.c | 22 ++++++++++++++++++++++
+ data.c | 4 ++++
+ main.c | 20 ++++++--!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ++++++
+ scrollbar.c | 2 !!
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08p1.ref b/patch_cmds/diffstat/testing/case08p1.ref
new file mode 100644
index 0000000..2bd31cb
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08p1.ref
@@ -0,0 +1,9 @@
+ build/x11r6/XFree86-current/xc/programs/xterm/Imakefile | 15 +++++++++
+ build/x11r6/XFree86-current/xc/programs/xterm/Tekproc.c | 7 ++++
+ build/x11r6/XFree86-current/xc/programs/xterm/charproc.c | 22 ++++++++++++++
+ build/x11r6/XFree86-current/xc/programs/xterm/data.c | 4 ++
+ build/x11r6/XFree86-current/xc/programs/xterm/main.c | 20 +++--!!!!!!
+ build/x11r6/XFree86-current/xc/programs/xterm/menu.c | 6 !!!
+ build/x11r6/XFree86-current/xc/programs/xterm/misc.c | 6 +++
+ build/x11r6/XFree86-current/xc/programs/xterm/scrollbar.c | 2 !
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08p9.ref b/patch_cmds/diffstat/testing/case08p9.ref
new file mode 100644
index 0000000..53afea5
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08p9.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 +++++++++++++++
+ Tekproc.c | 7 +++++++
+ charproc.c | 22 ++++++++++++++++++++++
+ data.c | 4 ++++
+ main.c | 20 ++++++--!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ++++++
+ scrollbar.c | 2 !!
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08r1.ref b/patch_cmds/diffstat/testing/case08r1.ref
new file mode 100644
index 0000000..53afea5
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08r1.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 +++++++++++++++
+ Tekproc.c | 7 +++++++
+ charproc.c | 22 ++++++++++++++++++++++
+ data.c | 4 ++++
+ main.c | 20 ++++++--!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ++++++
+ scrollbar.c | 2 !!
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08r2.ref b/patch_cmds/diffstat/testing/case08r2.ref
new file mode 100644
index 0000000..53afea5
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08r2.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 +++++++++++++++
+ Tekproc.c | 7 +++++++
+ charproc.c | 22 ++++++++++++++++++++++
+ data.c | 4 ++++
+ main.c | 20 ++++++--!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ++++++
+ scrollbar.c | 2 !!
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case08u.ref b/patch_cmds/diffstat/testing/case08u.ref
new file mode 100644
index 0000000..53afea5
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case08u.ref
@@ -0,0 +1,9 @@
+ Imakefile | 15 +++++++++++++++
+ Tekproc.c | 7 +++++++
+ charproc.c | 22 ++++++++++++++++++++++
+ data.c | 4 ++++
+ main.c | 20 ++++++--!!!!!!!!!!!!
+ menu.c | 6 !!!!!!
+ misc.c | 6 ++++++
+ scrollbar.c | 2 !!
+ 8 files changed, 60 insertions(+), 2 deletions(-), 20 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case09.pat b/patch_cmds/diffstat/testing/case09.pat
new file mode 100644
index 0000000..eced7bd
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09.pat
@@ -0,0 +1,13 @@
+Other testing
+Bad data
+Index!!!
+Index:::
+diff!!!
++++++++++++++
+---------------
+Only in ?
+Binary files XXX and YYY are the same
+<<
+--
+++
+!!
diff --git a/patch_cmds/diffstat/testing/case09.ref b/patch_cmds/diffstat/testing/case09.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09R.ref b/patch_cmds/diffstat/testing/case09R.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09R.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09Rp0.ref b/patch_cmds/diffstat/testing/case09Rp0.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09Rp0.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09b.ref b/patch_cmds/diffstat/testing/case09b.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09b.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09f0.ref b/patch_cmds/diffstat/testing/case09f0.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09f0.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09k.ref b/patch_cmds/diffstat/testing/case09k.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09k.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09p1.ref b/patch_cmds/diffstat/testing/case09p1.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09p1.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09p9.ref b/patch_cmds/diffstat/testing/case09p9.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09p9.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09r1.ref b/patch_cmds/diffstat/testing/case09r1.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09r1.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09r2.ref b/patch_cmds/diffstat/testing/case09r2.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09r2.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case09u.ref b/patch_cmds/diffstat/testing/case09u.ref
new file mode 100644
index 0000000..63b383b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case09u.ref
@@ -0,0 +1 @@
+ 0 files changed
diff --git a/patch_cmds/diffstat/testing/case10.pat b/patch_cmds/diffstat/testing/case10.pat
new file mode 100644
index 0000000..e3d4b61
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10.pat
@@ -0,0 +1,67 @@
+Index: allowev.c
+*** /build/x11r6/XFree86-960317/xc/programs/Xserver/Xi/allowev.c Sun Mar 17 20:08:01 1996
+--- /build/x11r6/XFree86-current/xc/programs/Xserver/Xi/allowev.c Wed Mar 20 20:47:09 1996
+***************
+*** 63,72 ****
+
+ #include "extnsionst.h"
+ #include "extinit.h" /* LookupDeviceIntRec */
+
+! extern int IReqCode;
+! extern int BadDevice;
+! extern void (* ReplySwapVector[256]) ();
+
+ /***********************************************************************
+ *
+--- 63,71 ----
+
+ #include "extnsionst.h"
+ #include "extinit.h" /* LookupDeviceIntRec */
++ #include "exglobals.h"
+
+! #include "allowev.h"
+
+ /***********************************************************************
+ *
+***************
+*** 99,105 ****
+ {
+ TimeStamp time;
+ DeviceIntPtr thisdev;
+- void AllowSome ();
+
+ REQUEST(xAllowDeviceEventsReq);
+ REQUEST_SIZE_MATCH(xAllowDeviceEventsReq);
+--- 98,103 ----
+Index: XIstubs.h
+*** /dev/null Sun Jul 17 19:46:18 1994
+--- /build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h Wed Mar 20 22:08:14 1996
+***************
+*** 0 ****
+--- 1,105 ----
++ /* $XConsortium$ */
++ /* $XFree86$ */
++
++ #ifndef XI_STUBS_H
++ #define XI_STUBS_H 1
++
++ int
++ ChangePointerDevice (
++ #if NeedFunctionPrototypes
++ DeviceIntPtr /* old_dev */,
++ DeviceIntPtr /* new_dev */,
++ unsigned char /* x */,
++ unsigned char /* y */
++ #endif
++ );
++
++ int
++ ChangeDeviceControl (
++ #if NeedFunctionPrototypes
++ ClientPtr /* client */,
++ DeviceIntPtr /* dev */,
++ xDeviceCtl * /* control */
++ #endif
++ );
++
++ #endif /* XI_STUBS_H */
diff --git a/patch_cmds/diffstat/testing/case10.ref b/patch_cmds/diffstat/testing/case10.ref
new file mode 100644
index 0000000..eab1d21
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10.ref
@@ -0,0 +1,3 @@
+ /build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h | 26 ++++++++++
+ xc/programs/Xserver/Xi/allowev.c | 6 !
+ 2 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10R.ref b/patch_cmds/diffstat/testing/case10R.ref
new file mode 100644
index 0000000..02d5b59
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10R.ref
@@ -0,0 +1,3 @@
+ XIstubs.h | 26 --------------------------
+ allowev.c | 6 +-!!!!
+ 2 files changed, 1 insertion(+), 27 deletions(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10Rp0.ref b/patch_cmds/diffstat/testing/case10Rp0.ref
new file mode 100644
index 0000000..02d5b59
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10Rp0.ref
@@ -0,0 +1,3 @@
+ XIstubs.h | 26 --------------------------
+ allowev.c | 6 +-!!!!
+ 2 files changed, 1 insertion(+), 27 deletions(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10b.ref b/patch_cmds/diffstat/testing/case10b.ref
new file mode 100644
index 0000000..eab1d21
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10b.ref
@@ -0,0 +1,3 @@
+ /build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h | 26 ++++++++++
+ xc/programs/Xserver/Xi/allowev.c | 6 !
+ 2 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10f0.ref b/patch_cmds/diffstat/testing/case10f0.ref
new file mode 100644
index 0000000..0aae099
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10f0.ref
@@ -0,0 +1,3 @@
+ /build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h | 26 26 + 0 - 0 !
+ xc/programs/Xserver/Xi/allowev.c | 6 1 + 1 - 4 !
+ 2 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10k.ref b/patch_cmds/diffstat/testing/case10k.ref
new file mode 100644
index 0000000..fe09222
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10k.ref
@@ -0,0 +1,4 @@
+ /build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h | 26 ++++++++++
+ XIstubs.h | 0
+ xc/programs/Xserver/Xi/allowev.c | 6 !
+ 3 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10p1.ref b/patch_cmds/diffstat/testing/case10p1.ref
new file mode 100644
index 0000000..c9f4be2
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10p1.ref
@@ -0,0 +1,3 @@
+ build/x11r6/XFree86-current/xc/programs/Xserver/Xi/allowev.c | 6 !
+ build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h | 26 ++++++++++
+ 2 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10p9.ref b/patch_cmds/diffstat/testing/case10p9.ref
new file mode 100644
index 0000000..7a6e9b6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10p9.ref
@@ -0,0 +1,3 @@
+ XIstubs.h | 26 ++++++++++++++++++++++++++
+ allowev.c | 6 +-!!!!
+ 2 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10r1.ref b/patch_cmds/diffstat/testing/case10r1.ref
new file mode 100644
index 0000000..07f96aa
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10r1.ref
@@ -0,0 +1,3 @@
+ /build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h | 26 ++++++++++
+ xc/programs/Xserver/Xi/allowev.c | 6 !!
+ 2 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10r2.ref b/patch_cmds/diffstat/testing/case10r2.ref
new file mode 100644
index 0000000..07f96aa
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10r2.ref
@@ -0,0 +1,3 @@
+ /build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h | 26 ++++++++++
+ xc/programs/Xserver/Xi/allowev.c | 6 !!
+ 2 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case10u.ref b/patch_cmds/diffstat/testing/case10u.ref
new file mode 100644
index 0000000..e5f9fac
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case10u.ref
@@ -0,0 +1,3 @@
+ xc/programs/Xserver/Xi/allowev.c | 6 !
+ /build/x11r6/XFree86-current/xc/programs/Xserver/include/XIstubs.h | 26 ++++++++++
+ 2 files changed, 27 insertions(+), 1 deletion(-), 4 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case11.pat b/patch_cmds/diffstat/testing/case11.pat
new file mode 100644
index 0000000..97df0fa
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11.pat
@@ -0,0 +1,12 @@
+*** test/ncurses.orig.c Sat Dec 21 08:04:03 1996
+--- test/ncurses.c Sun Dec 29 00:11:07 1996
+***************
+*** 2746,2751 ****
+--- 2746,2752 ----
+ static void
+ set_terminal_modes(void)
+ {
++ noraw();
+ cbreak();
+ noecho();
+ scrollok(stdscr, TRUE);
diff --git a/patch_cmds/diffstat/testing/case11.ref b/patch_cmds/diffstat/testing/case11.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case11R.ref b/patch_cmds/diffstat/testing/case11R.ref
new file mode 100644
index 0000000..de5637f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11R.ref
@@ -0,0 +1,2 @@
+ ncurses.orig.c | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case11Rp0.ref b/patch_cmds/diffstat/testing/case11Rp0.ref
new file mode 100644
index 0000000..0d33e9b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11Rp0.ref
@@ -0,0 +1,2 @@
+ test/ncurses.orig.c | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case11b.ref b/patch_cmds/diffstat/testing/case11b.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11b.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case11f0.ref b/patch_cmds/diffstat/testing/case11f0.ref
new file mode 100644
index 0000000..da5213d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11f0.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 1 + 0 - 0 !
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case11k.ref b/patch_cmds/diffstat/testing/case11k.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11k.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case11p1.ref b/patch_cmds/diffstat/testing/case11p1.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11p1.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case11p9.ref b/patch_cmds/diffstat/testing/case11p9.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11p9.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case11r1.ref b/patch_cmds/diffstat/testing/case11r1.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11r1.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case11r2.ref b/patch_cmds/diffstat/testing/case11r2.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11r2.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case11u.ref b/patch_cmds/diffstat/testing/case11u.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case11u.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case12.pat b/patch_cmds/diffstat/testing/case12.pat
new file mode 100644
index 0000000..a781855
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12.pat
@@ -0,0 +1,163 @@
+Index: xc/programs/xterm/main.c
+diff -u xc/programs/xterm/main.c:1.1.1.22 xc/programs/xterm/main.c:1.2
+--- xc/programs/xterm/main.c:1.1.1.22 Tue Mar 19 07:36:38 1996
++++ xc/programs/xterm/main.c Sun Mar 24 01:10:29 1996
+@@ -182,6 +182,10 @@
+ #undef CAPS_LOCK
+ #endif
+
++#ifdef CSRG_BASED
++#define USE_POSIX_TERMIOS
++#endif
++
+ #include <sys/ioctl.h>
+ #include <sys/stat.h>
+
+@@ -199,6 +203,9 @@
+ #endif
+ #endif
+
++#ifdef USE_POSIX_TERMIOS
++#include <termios.h>
++#else
+ #ifdef USE_TERMIOS
+ #include <termios.h>
+ /* this hacked termios support only works on SYSV */
+@@ -3143,11 +3197,11 @@
+ shname_minus = malloc(strlen(shname) + 2);
+ (void) strcpy(shname_minus, "-");
+ (void) strcat(shname_minus, shname);
+-#ifndef USE_SYSV_TERMIO
++#if !defined(USE_SYSV_TERMIO) && !defined(USE_POSIX_TERMIOS)
+ ldisc = XStrCmp("csh", shname + strlen(shname) - 3) == 0 ?
+ NTTYDISC : 0;
+ ioctl(0, TIOCSETD, (char *)&ldisc);
+-#endif /* !USE_SYSV_TERMIO */
++#endif /* !USE_SYSV_TERMIO && !USE_POSIX_TERMIOS */
+
+ #ifdef USE_LOGIN_DASH_P
+ if (term->misc.login_shell && pw && added_utmp_entry)
+Index: xc/programs/xterm/resize.c
+diff -u xc/programs/xterm/resize.c:1.1.1.9 xc/programs/xterm/resize.c:1.2
+--- xc/programs/xterm/resize.c:1.1.1.9 Wed Feb 14 21:58:14 1996
++++ xc/programs/xterm/resize.c Sun Mar 24 01:10:32 1996
+@@ -87,19 +87,19 @@
+ #define USE_TERMINFO
+ #endif
+
+-#ifdef MINIX
++#if defined(CSRG_BASED)
+ #define USE_TERMIOS
+ #endif
+
+ #include <sys/ioctl.h>
+ #ifdef USE_SYSV_TERMIO
+-#include <sys/termio.h>
++# include <sys/termio.h>
+ #else /* else not USE_SYSV_TERMIO */
+-#ifdef MINIX
+-#include <termios.h>
+-#else /* !MINIX */
+-#include <sgtty.h>
+-#endif /* MINIX */
++# ifdef USE_TERMIOS
++# include <termios.h>
++# else /* not USE_TERMIOS */
++# include <sgtty.h>
++# endif /* USE_TERMIOS */
+ #endif /* USE_SYSV_TERMIO */
+
+ #ifdef USE_USG_PTYS
+@@ -127,8 +127,9 @@
+ #define bzero(s, n) memset(s, 0, n)
+ #endif /* USE_SYSV_TERMIO */
+
+-#ifdef USE_TERMIOS
++#ifdef MINIX
+ #define USE_SYSV_TERMIO
++#include <sys/termios.h>
+ #define termio termios
+ #define TCGETA TCGETS
+ #define TCSETAW TCSETSW
+@@ -190,7 +191,11 @@
+ #ifdef USE_SYSV_TERMIO
+ struct termio tioorig;
+ #else /* not USE_SYSV_TERMIO */
++# ifdef USE_TERMIOS
++struct termios tioorig;
++# else /* not USE_TERMIOS */
+ struct sgttyb sgorig;
++# endif /* USE_TERMIOS */
+ #endif /* USE_SYSV_TERMIO */
+ char *size[EMULATIONS] = {
+ "\033[%d;%dR",
+@@ -244,7 +249,11 @@
+ #ifdef USE_SYSV_TERMIO
+ struct termio tio;
+ #else /* not USE_SYSV_TERMIO */
++#ifdef USE_TERMIOS
++ struct termios tio;
++#else /* not USE_TERMIOS */
+ struct sgttyb sg;
++#endif /* USE_TERMIOS */
+ #endif /* USE_SYSV_TERMIO */
+ #ifdef USE_TERMCAP
+ char termcap [1024];
+@@ -366,10 +375,20 @@
+ tio.c_cc[VMIN] = 6;
+ tio.c_cc[VTIME] = 1;
+ #else /* else not USE_SYSV_TERMIO */
++#if defined(USE_TERMIOS)
++ tcgetattr(tty, &tioorig);
++ tio = tioorig;
++ tio.c_iflag &= ~ICRNL;
++ tio.c_lflag &= ~(ICANON | ECHO);
++ tio.c_cflag |= CS8;
++ tio.c_cc[VMIN] = 6;
++ tio.c_cc[VTIME] = 1;
++#else /* not USE_TERMIOS */
+ ioctl (tty, TIOCGETP, &sgorig);
+ sg = sgorig;
+ sg.sg_flags |= RAW;
+ sg.sg_flags &= ~ECHO;
++#endif /* USE_TERMIOS */
+ #endif /* USE_SYSV_TERMIO */
+ signal(SIGINT, onintr);
+ signal(SIGQUIT, onintr);
+@@ -377,7 +396,11 @@
+ #ifdef USE_SYSV_TERMIO
+ ioctl (tty, TCSETAW, &tio);
+ #else /* not USE_SYSV_TERMIO */
++#ifdef USE_TERMIOS
++ tcsetattr(tty, TCSADRAIN, &tio);
++#else /* not USE_TERMIOS */
+ ioctl (tty, TIOCSETP, &sg);
++#endif /* USE_TERMIOS */
+ #endif /* USE_SYSV_TERMIO */
+
+ if (argc == 2) {
+@@ -434,7 +457,11 @@
+ #ifdef USE_SYSV_TERMIO
+ ioctl (tty, TCSETAW, &tioorig);
+ #else /* not USE_SYSV_TERMIO */
++#ifdef USE_TERMIOS
++ tcsetattr(tty, TCSADRAIN, &tioorig);
++#else /* not USE_TERMIOS */
+ ioctl (tty, TIOCSETP, &sgorig);
++#endif /* USE_TERMIOS */
+ #endif /* USE_SYSV_TERMIO */
+ signal(SIGINT, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+@@ -595,7 +622,11 @@
+ #ifdef USE_SYSV_TERMIO
+ ioctl (tty, TCSETAW, &tioorig);
+ #else /* not USE_SYSV_TERMIO */
++#ifdef USE_TERMIOS
++ tcsetattr (tty, TCSADRAIN, &tioorig);
++#else /* not USE_TERMIOS */
+ ioctl (tty, TIOCSETP, &sgorig);
++#endif /* use TERMIOS */
+ #endif /* USE_SYSV_TERMIO */
+ exit(1);
+ }
+
diff --git a/patch_cmds/diffstat/testing/case12.ref b/patch_cmds/diffstat/testing/case12.ref
new file mode 100644
index 0000000..0986dce
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12.ref
@@ -0,0 +1,3 @@
+ main.c | 11 +++++++++--
+ resize.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12R.ref b/patch_cmds/diffstat/testing/case12R.ref
new file mode 100644
index 0000000..d8cc25c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12R.ref
@@ -0,0 +1,3 @@
+ main.c | 11 ++---------
+ resize.c | 47 ++++++++---------------------------------------
+ 2 files changed, 10 insertions(+), 48 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12Rp0.ref b/patch_cmds/diffstat/testing/case12Rp0.ref
new file mode 100644
index 0000000..0a69555
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12Rp0.ref
@@ -0,0 +1,3 @@
+ xc/programs/xterm/main.c | 11 +---------
+ xc/programs/xterm/resize.c | 47 +++++++--------------------------------------
+ 2 files changed, 10 insertions(+), 48 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12b.ref b/patch_cmds/diffstat/testing/case12b.ref
new file mode 100644
index 0000000..0986dce
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12b.ref
@@ -0,0 +1,3 @@
+ main.c | 11 +++++++++--
+ resize.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12f0.ref b/patch_cmds/diffstat/testing/case12f0.ref
new file mode 100644
index 0000000..97127ea
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12f0.ref
@@ -0,0 +1,3 @@
+ main.c | 11 9 + 2 - 0 !
+ resize.c | 47 39 + 8 - 0 !
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12k.ref b/patch_cmds/diffstat/testing/case12k.ref
new file mode 100644
index 0000000..0986dce
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12k.ref
@@ -0,0 +1,3 @@
+ main.c | 11 +++++++++--
+ resize.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12p1.ref b/patch_cmds/diffstat/testing/case12p1.ref
new file mode 100644
index 0000000..ec28fb8
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12p1.ref
@@ -0,0 +1,3 @@
+ programs/xterm/main.c | 11 +++++++++--
+ programs/xterm/resize.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12p9.ref b/patch_cmds/diffstat/testing/case12p9.ref
new file mode 100644
index 0000000..0986dce
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12p9.ref
@@ -0,0 +1,3 @@
+ main.c | 11 +++++++++--
+ resize.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12r1.ref b/patch_cmds/diffstat/testing/case12r1.ref
new file mode 100644
index 0000000..0986dce
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12r1.ref
@@ -0,0 +1,3 @@
+ main.c | 11 +++++++++--
+ resize.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12r2.ref b/patch_cmds/diffstat/testing/case12r2.ref
new file mode 100644
index 0000000..0986dce
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12r2.ref
@@ -0,0 +1,3 @@
+ main.c | 11 +++++++++--
+ resize.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case12u.ref b/patch_cmds/diffstat/testing/case12u.ref
new file mode 100644
index 0000000..0986dce
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case12u.ref
@@ -0,0 +1,3 @@
+ main.c | 11 +++++++++--
+ resize.c | 47 +++++++++++++++++++++++++++++++++++++++--------
+ 2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case13.pat b/patch_cmds/diffstat/testing/case13.pat
new file mode 100644
index 0000000..1baad44
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13.pat
@@ -0,0 +1,303 @@
+From pauzner.dnttm.rssi.ru!uue@pauzner.dnttm.rssi.ru Wed Jan 14 05:40:34 1998
+Received: from allison.clark.net (allison.clark.net [207.97.14.170])
+ by ice.clark.net (8.8.8/8.8.8) with ESMTP id FAA28956
+ for <dickey@shell.clark.net>; Wed, 14 Jan 1998 05:40:28 -0500 (EST)
+Received: from helios.dnttm.ru (dnttm.wave.ras.ru [194.85.104.197])
+ by allison.clark.net (8.8.8/8.8.8) with ESMTP id NAA05915
+ for <dickey@clark.net>; Mon, 12 Jan 1998 13:50:43 -0500 (EST)
+Received: from pauzner.UUCP (uucp@localhost)
+ by helios.dnttm.ru (8.8.5/8.8.5/IP-3) with UUCP id VAA21992
+ for dickey@clark.net; Mon, 12 Jan 1998 21:46:03 +0300
+Received: by pauzner.dnttm.rssi.ru (dMail for DOS v2.06, 14Jul97);
+ Mon, 12 Jan 1998 21:44:21 +0300
+To: dickey@shell.clark.net
+References: <AAyibkq8tH@pauzner.dnttm.rssi.ru>
+Message-Id: <AB3Ickqyu0@pauzner.dnttm.rssi.ru>
+From: "Leonid Pauzner" <uue@pauzner.dnttm.rssi.ru>
+Date: Mon, 12 Jan 1998 21:44:19 +0300 (MSK)
+X-Mailer: dMail [Demos Mail for DOS v2.06]
+Subject: Re: please submit a patch NOW
+Lines: 276
+MIME-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+Content-Transfer-Encoding: 7bit
+Status: RO
+
+This is for russian Cyrillic chartrans only:
+koi8-r and other Cyrillics now fall down to def7_uni transliteration
+if necessary (as should be). No "strip high bit" any more for koi8-r
+(UCAux.c), which made text completely unreadable for human
+and come from "before Unicode Era".
+(Somebody should look in LYCharUtil.c and LYCharSet.c
+to remove unnecessary staff where)
+
+Leonid Pauzner.
+
+
+
+*** UCAux.c Thu Jan 8 16:53:06 1998
+--- UCAux.c.new Sat Jan 10 15:40:48 1998
+***************
+*** 64,70 ****
+ /*
+ ** CJK mode may be off (i.e., HTCJK == NOCJK) because
+ ** the current document is not CJK, but the check may
+! ** be for capability in relation to another document,
+ ** for which CJK mode might be turned on when retrieved.
+ ** Thus, when the from charset is CJK, check if the to
+ ** charset is CJK, and return TQ_NO or TQ_GOOD depending on
+--- 64,70 ----
+ /*
+ ** CJK mode may be off (i.e., HTCJK == NOCJK) because
+ ** the current document is not CJK, but the check may
+! ** be for campability in relation to another document,
+ ** for which CJK mode might be turned on when retrieved.
+ ** Thus, when the from charset is CJK, check if the to
+ ** charset is CJK, and return TQ_NO or TQ_GOOD depending on
+***************
+*** 84,113 ****
+ **/
+ return TQ_NO;
+ }
+! if (!strcmp(fromname, "koi8-r")) {
+! /*
+! * Will try to use stripping of high bit...
+! */
+! tqmin = TQ_POOR;
+! }
+!
+! if (!strcmp(fromname, "koi8-r") || /* from cyrillic */
+! !strcmp(fromname, "iso-8859-5") ||
+! !strcmp(fromname, "cp866") ||
+! !strcmp(fromname, "cp1251") ||
+! !strcmp(fromname, "koi-8")) {
+! if (strcmp(toname, "iso-8859-5") &&
+! strcmp(toname, "koi8-r") &&
+! strcmp(toname, "cp866") &&
+! strcmp(toname, "cp1251"))
+! tqmax = TQ_POOR;
+! }
+ return ((LYCharSet_UC[from].UChndl >= 0) ? tqmax : tqmin);
+ }
+ }
+
+ /*
+! ** Returns YES if no tranlation necessary (because
+ ** charsets are equal, are equivalent, etc.).
+ */
+ PUBLIC BOOL UCNeedNotTranslate ARGS2(
+--- 84,98 ----
+ **/
+ return TQ_NO;
+ }
+! /* I am not sure with tqmax and tqmin :
+! ** does we need them in this procedure et all now? -LP
+! */
+ return ((LYCharSet_UC[from].UChndl >= 0) ? tqmax : tqmin);
+ }
+ }
+
+ /*
+! ** Returns YES if no translation necessary (because
+ ** charsets are equal, are equivalent, etc.).
+ */
+ PUBLIC BOOL UCNeedNotTranslate ARGS2(
+***************
+*** 274,296 ****
+ ** We set this, presently, for VISCII. - FM
+ */
+ pT->repl_translated_C0 = (p_out->enc == UCT_ENC_8BIT_C0);
+- /*
+- ** This is a flag for whether we are dealing with koi8-r
+- ** as the input, and could do 8th-bit stripping for other
+- ** output charsets. Note that this always sets 8th-bit
+- ** stripping if the input charset is KOI8-R and the output
+- ** charset needs it, i.e., regardless of the RawMode and
+- ** consequent HTPassEightBitRaw setting, so you can't look
+- ** at raw koi8-r without selecting that as the display
+- ** character set (or transparent). That's just as well,
+- ** but worth noting for developers - FM
+- */
+- pT->strip_raw_char_in = ((!intm_ucs ||
+- (p_out->enc == UCT_ENC_7BIT) ||
+- (p_out->repertoire &
+- UCT_REP_SUBSETOF_LAT1)) &&
+- cs_in != cs_out &&
+- !strcmp(p_in->MIMEname, "koi8-r"));
+ /*
+ ** use_ucs should be set TRUE if we have or will create
+ ** Unicode values for input octets or UTF multibytes. - FM
+--- 259,264 ----
+
+*** def7_uni.tbl Sun Nov 16 20:36:50 1997
+--- def7_uni.tbl.new Sat Jan 10 15:14:34 1998
+***************
+*** 232,237 ****
+--- 232,238 ----
+ # IPA symbols, from
+ # Linkname: FAQ: Representing IPA Phonetics in ASCII
+ # URL: http://www.hpl.hp.com/personal/Evan_Kirshenbaum/IPA/faq.html
++ # (corrected in Russian Cyrillic area).
+ #
+ 0x41 U+0251 # LATIN SMALL LETTER SCRIPT A -> A
+ U+0252:A.
+***************
+*** 418,424 ****
+ U+03f4:'%
+ U+03f5:j3
+ # Cyrillic capital letters
+- 0x65 U+0401
+ U+0402:D%
+ U+0403:G%
+ U+0404:IE
+--- 419,424 ----
+***************
+*** 432,481 ****
+ U+040c:KJ
+ U+040e:V%
+ U+040f:DZ
+! 0x61-0x62 U+0410-U+0411
+! 0x77 U+0412
+! 0x67 U+0413
+! 0x64-0x65 U+0414-U+0415
+! 0x76 U+0416
+! 0x7a U+0417
+! 0x69-0x70 U+0418-U+041f
+! 0x72-0x75 U+0420-U+0423
+! 0x66 U+0424
+! 0x68 U+0425
+! 0x63 U+0426
+! 0x7e U+0427
+! 0x7b U+0428
+! 0x7d U+0429
+! 0x27 U+042a
+! 0x79 U+042b
+! 0x78 U+042c
+! 0x7c U+042d
+! 0x60 U+042e
+! 0x71 U+042f
+!
+! # Cyrillic small letters
+! 0x41-0x42 U+0430-U+0431
+! 0x57 U+0432
+! 0x47 U+0433
+! 0x44-0x45 U+0434-U+0435
+! 0x56 U+0436
+! 0x5a U+0437
+! 0x49-0x50 U+0438-U+043f
+! 0x52-0x55 U+0440-U+0443
+! 0x46 U+0444
+! 0x48 U+0445
+! 0x43 U+0446
+! 0x5e U+0447
+! 0x5b U+0448
+! 0x5d U+0449
+! 0x27 U+044a
+! 0x59 U+044b
+! 0x58 U+044c
+! 0x5c U+044d
+! 0x40 U+044e
+! 0x51 U+044f
+!
+! 0x65 U+0451 #:io
+ U+0452:d%
+ U+0453:g%
+ U+0454:ie
+--- 432,506 ----
+ U+040c:KJ
+ U+040e:V%
+ U+040f:DZ
+! # Russian Cyrillic letters, transliterated
+! U+0401:IO
+! U+0410:A
+! U+0411:B
+! U+0412:V
+! U+0413:G
+! U+0414:D
+! U+0415:E
+! U+0416:ZH
+! U+0417:Z
+! U+0418:I
+! U+0419:J
+! U+041a:K
+! U+041b:L
+! U+041c:M
+! U+041d:N
+! U+041e:O
+! U+041f:P
+! U+0420:R
+! U+0421:S
+! U+0422:T
+! U+0423:U
+! U+0424:F
+! U+0425:H
+! U+0426:C
+! U+0427:CH
+! U+0428:SH
+! U+0429:SCH
+! U+042a:"
+! U+042b:Y
+! U+042c:'
+! U+042d:`E
+! U+042e:JU
+! U+042f:JA
+! U+0430:a
+! U+0431:b
+! U+0432:v
+! U+0433:g
+! U+0434:d
+! U+0435:e
+! U+0436:zh
+! U+0437:z
+! U+0438:i
+! U+0439:j
+! U+043a:k
+! U+043b:l
+! U+043c:m
+! U+043d:n
+! U+043e:o
+! U+043f:p
+! U+0440:r
+! U+0441:s
+! U+0442:t
+! U+0443:u
+! U+0444:f
+! U+0445:h
+! U+0446:c
+! U+0447:ch
+! U+0448:sh
+! U+0449:sch
+! U+044a:"
+! U+044b:y
+! U+044c:'
+! U+044d:`e
+! U+044e:ju
+! U+044f:ja
+! U+0451:io
+! # end of Russian Cyrillic letters.
+! # Cyrillic small letters (and some archaic)
+ U+0452:d%
+ U+0453:g%
+ U+0454:ie
+***************
+*** 1432,1438 ****
+ U+223e:CG
+ U+2243:?-
+ U+2245:?=
+! U+2248:?2
+ U+224c:=?
+ U+2253:HI
+ U+2260:!=
+--- 1457,1464 ----
+ U+223e:CG
+ U+2243:?-
+ U+2245:?=
+! # ALMOST EQUAL TO:
+! U+2248:~=
+ U+224c:=?
+ U+2253:HI
+ U+2260:!=
+
+
+
+
diff --git a/patch_cmds/diffstat/testing/case13.ref b/patch_cmds/diffstat/testing/case13.ref
new file mode 100644
index 0000000..fb619f1
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 --------!!!!!!!!!!!!!
+ def7_uni.tbl | 118 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13R.ref b/patch_cmds/diffstat/testing/case13R.ref
new file mode 100644
index 0000000..5e07c7d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13R.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 ++++++++!!!!!!!!!!!!!
+ def7_uni.tbl | 118 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 18 insertions(+), 1 deletion(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13Rp0.ref b/patch_cmds/diffstat/testing/case13Rp0.ref
new file mode 100644
index 0000000..5e07c7d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13Rp0.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 ++++++++!!!!!!!!!!!!!
+ def7_uni.tbl | 118 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 18 insertions(+), 1 deletion(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13b.ref b/patch_cmds/diffstat/testing/case13b.ref
new file mode 100644
index 0000000..fb619f1
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13b.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 --------!!!!!!!!!!!!!
+ def7_uni.tbl | 118 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13f0.ref b/patch_cmds/diffstat/testing/case13f0.ref
new file mode 100644
index 0000000..cb23818
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13f0.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 0 + 17 - 25 !
+ def7_uni.tbl | 118 1 + 1 - 116 !
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13k.ref b/patch_cmds/diffstat/testing/case13k.ref
new file mode 100644
index 0000000..fb619f1
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13k.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 --------!!!!!!!!!!!!!
+ def7_uni.tbl | 118 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13p1.ref b/patch_cmds/diffstat/testing/case13p1.ref
new file mode 100644
index 0000000..fb619f1
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13p1.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 --------!!!!!!!!!!!!!
+ def7_uni.tbl | 118 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13p9.ref b/patch_cmds/diffstat/testing/case13p9.ref
new file mode 100644
index 0000000..fb619f1
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13p9.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 --------!!!!!!!!!!!!!
+ def7_uni.tbl | 118 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13r1.ref b/patch_cmds/diffstat/testing/case13r1.ref
new file mode 100644
index 0000000..a3694d4
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13r1.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 --------!!!!!!!!!!!!
+ def7_uni.tbl | 118 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13r2.ref b/patch_cmds/diffstat/testing/case13r2.ref
new file mode 100644
index 0000000..a3694d4
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13r2.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 --------!!!!!!!!!!!!
+ def7_uni.tbl | 118 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case13u.ref b/patch_cmds/diffstat/testing/case13u.ref
new file mode 100644
index 0000000..fb619f1
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case13u.ref
@@ -0,0 +1,3 @@
+ UCAux.c | 42 --------!!!!!!!!!!!!!
+ def7_uni.tbl | 118 -!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ 2 files changed, 1 insertion(+), 18 deletions(-), 141 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case14.pat b/patch_cmds/diffstat/testing/case14.pat
new file mode 100644
index 0000000..56dd567
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14.pat
@@ -0,0 +1,12 @@
+*** /tmp/xx010 Sat Dec 21 08:04:03 1996
+--- test/ncurses.c Sun Dec 29 00:11:07 1996
+***************
+*** 2746,2751 ****
+--- 2746,2752 ----
+ static void
+ set_terminal_modes(void)
+ {
++ noraw();
+ cbreak();
+ noecho();
+ scrollok(stdscr, TRUE);
diff --git a/patch_cmds/diffstat/testing/case14.ref b/patch_cmds/diffstat/testing/case14.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case14R.ref b/patch_cmds/diffstat/testing/case14R.ref
new file mode 100644
index 0000000..2a549f3
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14R.ref
@@ -0,0 +1,2 @@
+ xx010 | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case14Rp0.ref b/patch_cmds/diffstat/testing/case14Rp0.ref
new file mode 100644
index 0000000..4a9cbc9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14Rp0.ref
@@ -0,0 +1,2 @@
+ /tmp/xx010 | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case14b.ref b/patch_cmds/diffstat/testing/case14b.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14b.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case14f0.ref b/patch_cmds/diffstat/testing/case14f0.ref
new file mode 100644
index 0000000..da5213d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14f0.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 1 + 0 - 0 !
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case14k.ref b/patch_cmds/diffstat/testing/case14k.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14k.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case14p1.ref b/patch_cmds/diffstat/testing/case14p1.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14p1.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case14p9.ref b/patch_cmds/diffstat/testing/case14p9.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14p9.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case14r1.ref b/patch_cmds/diffstat/testing/case14r1.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14r1.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case14r2.ref b/patch_cmds/diffstat/testing/case14r2.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14r2.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case14u.ref b/patch_cmds/diffstat/testing/case14u.ref
new file mode 100644
index 0000000..51424e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case14u.ref
@@ -0,0 +1,2 @@
+ ncurses.c | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case15.pat b/patch_cmds/diffstat/testing/case15.pat
new file mode 100644
index 0000000..7db58a4
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15.pat
@@ -0,0 +1,443 @@
+--- nvi-1.79.orig/build/Makefile.in
++++ nvi-1.79/build/Makefile.in
+@@ -95,15 +95,15 @@
+ ($(mkdir) $(mandir)/cat1 && $(chmod) $(dmode) $(mandir)/cat1)
+ @echo "Installing man pages: $(mandir) ..."
+ cd $(mandir)/cat1 && $(rm) -f `echo vi.0 | sed '$(transform)'`
+- $(cp) $(srcdir)/docs/USD.doc/vi.man/vi.0 \
+- $(mandir)/cat1/`echo vi.0 | sed '$(transform)'`
+- cd $(mandir)/cat1 && $(chmod) $(fmode) `echo vi.0 | sed '$(transform)'`
+- cd $(mandir)/cat1 && $(rm) -f `echo ex.0 | sed '$(transform)'`
+- cd $(mandir)/cat1 && $(rm) -f `echo view.0 | sed '$(transform)'`
+- cd $(mandir)/cat1 && $(ln) \
+- `echo vi.0 | sed '$(transform)'` `echo ex.0 | sed '$(transform)'`
+- cd $(mandir)/cat1 && $(ln) \
+- `echo vi.0 | sed '$(transform)'` `echo view.0 | sed '$(transform)'`
++ #$(cp) $(srcdir)/docs/USD.doc/vi.man/vi.0 \
++ #$(mandir)/cat1/`echo vi.0 | sed '$(transform)'`
++ #cd $(mandir)/cat1 && $(chmod) $(fmode) `echo vi.0 | sed '$(transform)'`
++ #cd $(mandir)/cat1 && $(rm) -f `echo ex.0 | sed '$(transform)'`
++ #cd $(mandir)/cat1 && $(rm) -f `echo view.0 | sed '$(transform)'`
++ #cd $(mandir)/cat1 && $(ln) \
++ #`echo vi.0 | sed '$(transform)'` `echo ex.0 | sed '$(transform)'`
++ #cd $(mandir)/cat1 && $(ln) \
++ #`echo vi.0 | sed '$(transform)'` `echo view.0 | sed '$(transform)'`
+ [ -d $(mandir)/man1 ] || \
+ ($(mkdir) $(mandir)/man1 && $(chmod) $(dmode) $(mandir)/man1)
+ cd $(mandir)/man1 && $(rm) -f `echo vi.1 | sed '$(transform)'`
+@@ -137,16 +137,16 @@
+ $(chmod) $(dmode) $(datadir)/vi/catalog
+ (cd $(srcdir)/catalog && $(cp) $(cat) $(datadir)/vi/catalog && \
+ cd $(datadir)/vi/catalog && $(chmod) $(fmode) *)
+- @echo "Installing Perl scripts: $(datadir)/vi/perl ..."
+- $(mkdir) $(datadir)/vi/perl && $(chmod) $(dmode) $(datadir)/vi/perl
+- [ -f VI.pm ] && $(cp) VI.pm $(datadir)/vi/perl && \
+- cd $(datadir)/vi/perl && $(chmod) $(fmode) VI.pm)
+- (cd $(srcdir)/perl_scripts && $(cp) *.pl $(datadir)/vi/perl && \
+- cd $(datadir)/vi/perl && $(chmod) $(fmode) *.pl)
+- @echo "Installing Tcl scripts: $(datadir)/vi/tcl ..."
+- $(mkdir) $(datadir)/vi/tcl && $(chmod) $(dmode) $(datadir)/vi/tcl
+- (cd $(srcdir)/tcl_scripts && $(cp) *.tcl $(datadir)/vi/tcl && \
+- cd $(datadir)/vi/tcl && $(chmod) $(fmode) *.tcl)
++ #@echo "Installing Perl scripts: $(datadir)/vi/perl ..."
++ #$(mkdir) $(datadir)/vi/perl && $(chmod) $(dmode) $(datadir)/vi/perl
++ #[ -f VI.pm ] && $(cp) VI.pm $(datadir)/vi/perl && \
++ # cd $(datadir)/vi/perl && $(chmod) $(fmode) VI.pm)
++ #(cd $(srcdir)/perl_scripts && $(cp) *.pl $(datadir)/vi/perl && \
++ # cd $(datadir)/vi/perl && $(chmod) $(fmode) *.pl)
++ #@echo "Installing Tcl scripts: $(datadir)/vi/tcl ..."
++ #$(mkdir) $(datadir)/vi/tcl && $(chmod) $(dmode) $(datadir)/vi/tcl
++ #(cd $(srcdir)/tcl_scripts && $(cp) *.tcl $(datadir)/vi/tcl && \
++ # cd $(datadir)/vi/tcl && $(chmod) $(fmode) *.tcl)
+ @echo "Installing recover script: $(datadir)/vi/recover ..."
+ ($(cp) recover $(datadir)/vi/recover && \
+ $(chmod) $(emode) $(datadir)/vi/recover)
+--- nvi-1.79.orig/build/recover
++++ nvi-1.79/build/recover
+@@ -0,0 +1,49 @@
++#!/bin/sh -
++#
++# @(#)recover.in 8.8 (Berkeley) 10/10/96
++#
++# Script to recover nvi edit sessions.
++
++RECDIR="/var/tmp/vi.recover"
++SENDMAIL="/usr/sbin/sendmail"
++
++echo 'Recovering nvi editor sessions.'
++
++# Check editor backup files.
++vibackup=`echo $RECDIR/vi.*`
++if [ "$vibackup" != "$RECDIR/vi.*" ]; then
++ for i in $vibackup; do
++ # Only test files that are readable.
++ if test ! -r $i; then
++ continue
++ fi
++
++ # Unmodified nvi editor backup files either have the
++ # execute bit set or are zero length. Delete them.
++ if test -x $i -o ! -s $i; then
++ rm $i
++ fi
++ done
++fi
++
++# It is possible to get incomplete recovery files, if the editor crashes
++# at the right time.
++virecovery=`echo $RECDIR/recover.*`
++if [ "$virecovery" != "$RECDIR/recover.*" ]; then
++ for i in $virecovery; do
++ # Only test files that are readable.
++ if test ! -r $i; then
++ continue
++ fi
++
++ # Delete any recovery files that are zero length, corrupted,
++ # or that have no corresponding backup file. Else send mail
++ # to the user.
++ recfile=`awk '/^X-vi-recover-path:/{print $2}' < $i`
++ if test -n "$recfile" -a -s "$recfile"; then
++ $SENDMAIL -t < $i
++ else
++ rm $i
++ fi
++ done
++fi
+--- nvi-1.79.orig/debian/README.debian
++++ nvi-1.79/debian/README.debian
+@@ -0,0 +1,14 @@
++nvi for DEBIAN
++----------------------
++
++This package was debianized by Steve Greenland
++<stevegr@master.debian.org> on Tue, 29 Oct 1996, using
++the new source format. Much of it is based on previous work by Robert
++Sanders <Robert.Sanders@linux.org> or <rsanders@mindspring.com>, and
++Ian Murdock <imurdock@debian.org>.
++
++It was downloaded from ftp://mongoose.bostic.com/pub/nvi.tar.gz,
++which seems to be the new home site: ftp.cs.berkeley.edu no longer
++archives nvi.
++
++Steve Greenland <stevegr@master.debian.org>, Sat, 15 Nov 1997
+--- nvi-1.79.orig/debian/changelog
++++ nvi-1.79/debian/changelog
+@@ -0,0 +1,53 @@
++nvi (1.79-5) frozen unstable; urgency=low
++
++ * Fixed removal of editor alternative in prerm (reported by Dale Scheetz)
++
++ -- Steve Greenland <stevegr@master.debian.org> Sun, 10 May 1998 18:54:02 -0500
++
++nvi (1.79-4) unstable; urgency=low
++
++ * fixed uncompressed alternatives links (closes:Bug#16171)
++ * fixed build problem (clean failed when already clean) (closes:Bug#15263)
++
++ -- Steve Greenland <stevegr@master.debian.org> Sun, 5 Apr 1998 13:31:46 -0500
++
++nvi (1.79-3) frozen unstable; urgency=low
++
++ * Rebuilt with clean md5sum file. (closes:Bug#19377,Bug#18683)
++
++ -- Steve Greenland <stevegr@master.debian.org> Thu, 19 Mar 1998 22:14:12 -0600
++
++nvi (1.79-2) unstable; urgency=low
++
++ * Fixed build (actually clean) procedure (Bug#15263)
++
++ -- Steve Greenland <stevegr@master.debian.org> Fri, 28 Nov 1997 13:58:17 -0600
++
++nvi (1.79-1) unstable; urgency=low
++
++ * Removed cleanup of nvi-1.34-4 from postinst, shouldn't be necessary
++ any longer (Bug #6563)
++ * Removed /usr/man/cat1 from package (Bug #6240, #8226)
++ * Fixed permissions on executables (and man pages) (Bug #5998)
++ * New upstream version (Bug #14086)
++ * Compiled for libc6 (Bug #11709)
++ * debian/rules calls 'make distclean' on clean to remove configuration stuff
++ * Added update-alternatve calls to support Debian's /usr/bin/editor.
++
++ -- Steve Greenland <stevegr@master.debian.org> Sat, 15 Nov 1997 17:50:02 -0600
++
++nvi (1.76-1) unstable; urgency=low
++
++ * New upstream version. (Fixes Bugs 2825, 3967, 4511)
++ * Modified Makefile.in permissions.
++ * New source package format, using debstd (from debmake package).
++ * Modified Makefile.in to not install pre-formatted man pages.
++ * Cleaned up postinst to avoid dangling links from update alternatives.
++ * Modified Makefile.in to not install Perl, Tcl, and Tk stuff. (Will
++ probably add back later as a separate package.)
++
++ -- Steve Greenland <stevegr@master.debian.org> Sun, 1 Dec 1996 22:03:37 -0600
++
++Local variables:
++mode: debian-changelog
++End:
+--- nvi-1.79.orig/debian/conffiles
++++ nvi-1.79/debian/conffiles
+@@ -0,0 +1 @@
++/etc/rc.boot/nvi
+--- nvi-1.79.orig/debian/control
++++ nvi-1.79/debian/control
+@@ -0,0 +1,19 @@
++Source: nvi
++Section: editors
++Priority: important
++Maintainer: Steve Greenland <stevegr@master.debian.org>
++Standards-Version: 2.4.0.0
++
++Package: nvi
++Architecture: any
++Depends: ${shlibs:Depends}
++Description: 4.4BSD re-implementation of vi.
++ Vi is the original screen based text editor for Unix systems.
++ It is considered the standard text editor, and is available on
++ almost all Unix systems.
++ .
++ Nvi is intended as a "bug-for-bug compatible" clone of the original
++ BSD vi editor. As such, it doesn't have a lot of snazzy features as do
++ some of the other vi clones such as elvis and vim. However, if all
++ you want is vi, this is the one to get.
++
+--- nvi-1.79.orig/debian/postinst
++++ nvi-1.79/debian/postinst
+@@ -0,0 +1,21 @@
++#! /bin/sh
++
++# Remove the old view link (nvi-1.34-14, maybe earlier)
++# Don't bother the user with it.
++update-alternatives --remove view /usr/bin/nvi >/dev/null
++
++update-alternatives --install /usr/bin/ex ex /usr/bin/nex 30 \
++ --slave /usr/man/man1/ex.1.gz ex.1.gz /usr/man/man1/nex.1.gz
++update-alternatives --install /usr/bin/vi vi /usr/bin/nvi 30 \
++ --slave /usr/man/man1/vi.1.gz vi.1.gz /usr/man/man1/nvi.1.gz
++update-alternatives --install /usr/bin/view view /usr/bin/nview 30 \
++ --slave /usr/man/man1/view.1.gz view.1.gz /usr/man/man1/nview.1.gz
++
++# These are for the generic editor links
++
++update-alternatives --install /usr/bin/editor editor /usr/bin/nvi 100 \
++ --slave /usr/man/man1/editor.1.gz editor.1.gz /usr/man/man1/nvi.1.gz
++
++
++
++exit 0
+--- nvi-1.79.orig/debian/prerm
++++ nvi-1.79/debian/prerm
+@@ -0,0 +1,11 @@
++#! /bin/sh
++
++if [ "$1" != "upgrade" ]
++then
++ update-alternatives --remove editor /usr/bin/nvi
++ update-alternatives --remove ex /usr/bin/nex
++ update-alternatives --remove vi /usr/bin/nvi
++ update-alternatives --remove view /usr/bin/nview
++fi
++
++exit 0
+--- nvi-1.79.orig/debian/rc.boot
++++ nvi-1.79/debian/rc.boot
+@@ -0,0 +1,58 @@
++#!/bin/sh
++# @(#)recover.script 8.7 (Berkeley) 8/16/94
++#
++# Script to recover nvi edit sessions.
++#
++RECDIR=/var/tmp/vi.recover
++SENDMAIL=/usr/lib/sendmail
++
++case "$1" in
++ start)
++ echo -n 'Recovering nvi editor sessions... '
++
++ # Check editor backup files.
++ vibackup=`echo $RECDIR/vi.*`
++ if [ "$vibackup" != "$RECDIR/vi.*" ]; then
++ for i in $vibackup; do
++ # Only test files that are readable.
++ if test ! -r $i; then
++ continue
++ fi
++
++ # Unmodified nvi editor backup files either have the
++ # execute bit set or are zero length. Delete them.
++ if test -x $i -o ! -s $i; then
++ rm $i
++ fi
++ done
++ fi
++
++ # It is possible to get incomplete recovery files, if the editor crashes
++ # at the right time.
++ virecovery=`echo $RECDIR/recover.*`
++ if [ "$virecovery" != "$RECDIR/recover.*" ]; then
++ for i in $virecovery; do
++ # Only test files that are readable.
++ if test ! -r $i; then
++ continue
++ fi
++
++ # Delete any recovery files that are zero length, corrupted,
++ # or that have no corresponding backup file. Else send mail
++ # to the user.
++ recfile=`awk '/^X-vi-recover-path:/{print $2}' < $i`
++ if test -n "$recfile" -a -s "$recfile"; then
++ $SENDMAIL -t < $i
++ else
++ rm $i
++ fi
++ done
++ fi
++
++ echo "done."
++ ;;
++ stop)
++ ;;
++esac
++
++exit 0
+--- nvi-1.79.orig/debian/rules
++++ nvi-1.79/debian/rules
+@@ -0,0 +1,89 @@
++#!/usr/bin/make -f
++# Sample debian.rules file - for GNU Hello (1.3).
++# Copyright 1994,1995 by Ian Jackson.
++# I hereby give you perpetual unlimited permission to copy,
++# modify and relicense this file, provided that you do not remove
++# my name from the file itself. (I assert my moral right of
++# paternity under the Copyright, Designs and Patents Act 1988.)
++# This file may have to be extensively modified
++
++# There used to be `source' and `diff' targets in this file, and many
++# packages also had `changes' and `dist' targets. These functions
++# have been taken over by dpkg-source, dpkg-genchanges and
++# dpkg-buildpackage in a package-independent way, and so these targets
++# are obsolete.
++
++package=nvi
++
++# This is needed for the install target
++curdir=$(shell pwd)
++
++# This bit with build.deb is because the nvi package has a
++# 'build' directory, and the normal use of 'touch build' won't
++# work.
++
++build: build.deb
++
++build.deb:
++ $(checkdir)
++ (cd ./build && CC=gcc ADDCPPFLAGS="-O2 -g" ./configure --prefix=/usr --disable-curses --datadir=/usr/lib --program-prefix=n)
++ (cd ./build && make)
++ touch build.deb
++
++
++clean:
++ $(checkdir)
++ -rm -f build.deb
++ (cd ./build && make distclean || /bin/true )
++ -rm -rf *~ debian/tmp debian/*~ debian/files*
++
++binary-indep: checkroot build.deb
++ $(checkdir)
++# There are no architecture-independent files to be uploaded
++# generated by this package. If there were any they would be
++# made here.
++
++binary-arch: checkroot build.deb
++ $(checkdir)
++ -rm -rf debian/tmp
++ install -d debian/tmp/usr/bin debian/tmp/etc
++ (cd build && make install prefix=$(curdir)/debian/tmp/usr)
++ -rmdir debian/tmp/usr/man/cat1
++ chmod u+w debian/tmp/usr/bin/* debian/tmp/usr/man/man1/nvi.*
++ cp LICENSE debian/copyright
++ # Compress the man pages -- debstd can't do this because they
++ # are all links. Also, make them soft links instead of hard links
++ (cd debian/tmp/usr/man/man1 && \
++ rm {nex,nview}.1 && gzip -9 nvi.1 && \
++ ln -s nvi.1.gz nex.1.gz && ln -s nvi.1.gz nview.1.gz)
++# Must have debmake installed for this to work. Otherwise please copy
++# /usr/bin/debstd into the debian directory and change debstd to debian/debstd
++ debstd -m docs/changelog README FAQ
++ #
++ # Compress the changelogs if debstd didn't
++ #
++ ( set -e && cd debian/tmp/usr/doc/nvi && \
++ if [ -f changelog ] ; then gzip -9 changelog ; fi &&\
++ if [ -f changelog.Debian ] ; then gzip -9 changelog.Debian;fi)
++ dpkg-gencontrol
++ chown -R root.root debian/tmp
++ chmod -R g-ws debian/tmp
++ dpkg --build debian/tmp ..
++
++
++define checkdir
++ test -f debian/rules
++endef
++
++# Below here is fairly generic really
++
++binary: binary-indep binary-arch
++
++source diff:
++ @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false
++
++checkroot:
++ $(checkdir)
++ test root = "`whoami`"
++
++.PHONY: binary binary-arch binary-indep clean checkroot
+--- nvi-1.79.orig/debian/substvars
++++ nvi-1.79/debian/substvars
+@@ -0,0 +1 @@
++shlibs:Depends=libc6, ncurses3.4
+--- nvi-1.79.orig/debian/copyright
++++ nvi-1.79/debian/copyright
+@@ -0,0 +1,40 @@
++The vi program is freely redistributable. You are welcome to copy, modify
++and share it with others under the conditions listed in this file. If any
++company (not any individual!) finds vi sufficiently useful that you would
++have purchased it, or if any company wishes to redistribute it, contributions
++to the authors would be appreciated.
++
++/*-
++ * Copyright (c) 1991, 1992, 1993, 1994
++ * The Regents of the University of California. All rights reserved.
++ * Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996
++ * Keith Bostic. 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 the University of
++ * California, Berkeley and its contributors.
++ * 4. Neither the name of the University nor the names of its contributors
++ * may be used to endorse or promote products derived from this software
++ * without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
++ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
++ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
++ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
++ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
++ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
++ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
++ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
++ * SUCH DAMAGE.
++ */
diff --git a/patch_cmds/diffstat/testing/case15.ref b/patch_cmds/diffstat/testing/case15.ref
new file mode 100644
index 0000000..28906ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 ++++++++++-----------
+ build/recover | 49 ++++++++++++++++++++++++++++
+ debian/README.debian | 14 ++++++++
+ debian/changelog | 53 ++++++++++++++++++++++++++++++
+ debian/conffiles | 1
+ debian/control | 19 ++++++++++
+ debian/copyright | 40 ++++++++++++++++++++++
+ debian/postinst | 21 ++++++++++++
+ debian/prerm | 11 ++++++
+ debian/rc.boot | 58 +++++++++++++++++++++++++++++++++
+ debian/rules | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ debian/substvars | 1
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15R.ref b/patch_cmds/diffstat/testing/case15R.ref
new file mode 100644
index 0000000..ee378c8
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15R.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 ++++++++++-----------
+ build/recover | 49 ----------------------------
+ debian/README.debian | 14 --------
+ debian/changelog | 53 ------------------------------
+ debian/conffiles | 1
+ debian/control | 19 ----------
+ debian/copyright | 40 ----------------------
+ debian/postinst | 21 ------------
+ debian/prerm | 11 ------
+ debian/rc.boot | 58 ---------------------------------
+ debian/rules | 89 ---------------------------------------------------
+ debian/substvars | 1
+ 12 files changed, 19 insertions(+), 375 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15Rp0.ref b/patch_cmds/diffstat/testing/case15Rp0.ref
new file mode 100644
index 0000000..d7ff549
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15Rp0.ref
@@ -0,0 +1,13 @@
+ nvi-1.79.orig/build/Makefile.in | 38 +++++++--------
+ nvi-1.79.orig/build/recover | 49 --------------------
+ nvi-1.79.orig/debian/README.debian | 14 -----
+ nvi-1.79.orig/debian/changelog | 53 ----------------------
+ nvi-1.79.orig/debian/conffiles | 1
+ nvi-1.79.orig/debian/control | 19 -------
+ nvi-1.79.orig/debian/copyright | 40 ----------------
+ nvi-1.79.orig/debian/postinst | 21 --------
+ nvi-1.79.orig/debian/prerm | 11 ----
+ nvi-1.79.orig/debian/rc.boot | 58 ------------------------
+ nvi-1.79.orig/debian/rules | 89 -------------------------------------
+ nvi-1.79.orig/debian/substvars | 1
+ 12 files changed, 19 insertions(+), 375 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15b.ref b/patch_cmds/diffstat/testing/case15b.ref
new file mode 100644
index 0000000..28906ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15b.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 ++++++++++-----------
+ build/recover | 49 ++++++++++++++++++++++++++++
+ debian/README.debian | 14 ++++++++
+ debian/changelog | 53 ++++++++++++++++++++++++++++++
+ debian/conffiles | 1
+ debian/control | 19 ++++++++++
+ debian/copyright | 40 ++++++++++++++++++++++
+ debian/postinst | 21 ++++++++++++
+ debian/prerm | 11 ++++++
+ debian/rc.boot | 58 +++++++++++++++++++++++++++++++++
+ debian/rules | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ debian/substvars | 1
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15f0.ref b/patch_cmds/diffstat/testing/case15f0.ref
new file mode 100644
index 0000000..6664f4f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15f0.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 19 + 19 - 0 !
+ build/recover | 49 49 + 0 - 0 !
+ debian/README.debian | 14 14 + 0 - 0 !
+ debian/changelog | 53 53 + 0 - 0 !
+ debian/conffiles | 1 1 + 0 - 0 !
+ debian/control | 19 19 + 0 - 0 !
+ debian/copyright | 40 40 + 0 - 0 !
+ debian/postinst | 21 21 + 0 - 0 !
+ debian/prerm | 11 11 + 0 - 0 !
+ debian/rc.boot | 58 58 + 0 - 0 !
+ debian/rules | 89 89 + 0 - 0 !
+ debian/substvars | 1 1 + 0 - 0 !
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15k.ref b/patch_cmds/diffstat/testing/case15k.ref
new file mode 100644
index 0000000..28906ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15k.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 ++++++++++-----------
+ build/recover | 49 ++++++++++++++++++++++++++++
+ debian/README.debian | 14 ++++++++
+ debian/changelog | 53 ++++++++++++++++++++++++++++++
+ debian/conffiles | 1
+ debian/control | 19 ++++++++++
+ debian/copyright | 40 ++++++++++++++++++++++
+ debian/postinst | 21 ++++++++++++
+ debian/prerm | 11 ++++++
+ debian/rc.boot | 58 +++++++++++++++++++++++++++++++++
+ debian/rules | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ debian/substvars | 1
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15p1.ref b/patch_cmds/diffstat/testing/case15p1.ref
new file mode 100644
index 0000000..28906ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15p1.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 ++++++++++-----------
+ build/recover | 49 ++++++++++++++++++++++++++++
+ debian/README.debian | 14 ++++++++
+ debian/changelog | 53 ++++++++++++++++++++++++++++++
+ debian/conffiles | 1
+ debian/control | 19 ++++++++++
+ debian/copyright | 40 ++++++++++++++++++++++
+ debian/postinst | 21 ++++++++++++
+ debian/prerm | 11 ++++++
+ debian/rc.boot | 58 +++++++++++++++++++++++++++++++++
+ debian/rules | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ debian/substvars | 1
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15p9.ref b/patch_cmds/diffstat/testing/case15p9.ref
new file mode 100644
index 0000000..4fe8965
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15p9.ref
@@ -0,0 +1,13 @@
+ Makefile.in | 38 ++++++++++++------------
+ README.debian | 14 +++++++++
+ changelog | 53 ++++++++++++++++++++++++++++++++++
+ conffiles | 1
+ control | 19 ++++++++++++
+ copyright | 40 ++++++++++++++++++++++++++
+ postinst | 21 +++++++++++++
+ prerm | 11 +++++++
+ rc.boot | 58 +++++++++++++++++++++++++++++++++++++
+ recover | 49 +++++++++++++++++++++++++++++++
+ rules | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ substvars | 1
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15r1.ref b/patch_cmds/diffstat/testing/case15r1.ref
new file mode 100644
index 0000000..91bf4a2
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15r1.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 +++++++++++-----------
+ build/recover | 49 ++++++++++++++++++++++++++++
+ debian/README.debian | 14 ++++++++
+ debian/changelog | 53 ++++++++++++++++++++++++++++++
+ debian/conffiles | 1 +
+ debian/control | 19 +++++++++++
+ debian/copyright | 40 +++++++++++++++++++++++
+ debian/postinst | 21 ++++++++++++
+ debian/prerm | 11 ++++++
+ debian/rc.boot | 58 +++++++++++++++++++++++++++++++++
+ debian/rules | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ debian/substvars | 1 +
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15r2.ref b/patch_cmds/diffstat/testing/case15r2.ref
new file mode 100644
index 0000000..91bf4a2
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15r2.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 +++++++++++-----------
+ build/recover | 49 ++++++++++++++++++++++++++++
+ debian/README.debian | 14 ++++++++
+ debian/changelog | 53 ++++++++++++++++++++++++++++++
+ debian/conffiles | 1 +
+ debian/control | 19 +++++++++++
+ debian/copyright | 40 +++++++++++++++++++++++
+ debian/postinst | 21 ++++++++++++
+ debian/prerm | 11 ++++++
+ debian/rc.boot | 58 +++++++++++++++++++++++++++++++++
+ debian/rules | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ debian/substvars | 1 +
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case15u.ref b/patch_cmds/diffstat/testing/case15u.ref
new file mode 100644
index 0000000..2c98d98
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case15u.ref
@@ -0,0 +1,13 @@
+ build/Makefile.in | 38 ++++++++++-----------
+ build/recover | 49 ++++++++++++++++++++++++++++
+ debian/README.debian | 14 ++++++++
+ debian/changelog | 53 ++++++++++++++++++++++++++++++
+ debian/conffiles | 1
+ debian/control | 19 ++++++++++
+ debian/postinst | 21 ++++++++++++
+ debian/prerm | 11 ++++++
+ debian/rc.boot | 58 +++++++++++++++++++++++++++++++++
+ debian/rules | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ debian/substvars | 1
+ debian/copyright | 40 ++++++++++++++++++++++
+ 12 files changed, 375 insertions(+), 19 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16.pat b/patch_cmds/diffstat/testing/case16.pat
new file mode 100644
index 0000000..839a330
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16.pat
@@ -0,0 +1,2036 @@
+
+ PDCurses 2.5
+ (Public Domain Curses for DOS, OS/2, X11 and Win32)
+
+
+INTRODUCTION:
+
+This release of PDCurses includes the following changes:
+
+- full support of X11 selection handling
+- removed the need for the cursos2.h file
+- enabled the "shifted" key on the numeric keypad
+- added native clipboard support for X11, Win32 and OS/2
+- added extra functions for obtaining internal PDCUrses status
+- added clipboard and key modifier tests in testcurs.c
+- fixes for panel library
+- key modifiers pressed by themselves are now returned as keys
+- Added X11 shared library support
+- Added extra slk formats supported by ncurses
+- Fixed bug with resizing the terminal when slk were on.
+- Changed behaviour of slk_attrset(), slk_attron() alk_attroff()
+ functions to work more like ncurses.
+
+BUGS FIXED:
+
+some minor bug and portability fixes were included in this release
+
+NEW FUNCTIONS:
+
+PDC_getclipboard() and PDC_setclipboard() for accessing the native
+clipboard.
+PDC_set_title() for setting the title of the window (X11 and Win32 only)
+PDC_get_input_fd() for getting the file handle of the PDCurses input
+PDC_get_key_modifiers() for getting the keyboard modifier settings at the
+time of the last (w)getch()
+initscrX() (only for X11 port) which allows standard X11 switches to
+be passed to the application
+
+
+NEW COMPILER SUPPORT:
+
+- MingW32 GNU compiler under Win95/NT
+- Cygnus Win32 GNU compiler under Win95/NT
+- Borland C++ for OS/2 1.0+
+- lcc-win32 compiler under Win95/NT
+
+Makefiles for each platform/compiler option reside in the platform
+directory. These all have an extension of .mak.
+
+
+ACKNOWLEGEMENTS: (for this release)
+
+Georg Fuchs for various changes.
+Juan David Palomar for pointing out getnstr() was not implemented.
+William McBrine for fix to allow black/black as valid color pair.
+Peter Preus for pointing out the missing bccos2.mak file.
+Laura Michaels for a couple of bug fixes and changes required to support
+ Mingw32 compiler.
+Frank Heckenbach for PDC_get_input_fd() and some portability fixes and
+ the fixes for panel library.
+Matthias Burian for the lcc-win32 compiler support.
+
+Cheers, Mark
+------------------------------------------------------------------------
+ Mark Hessling Email: M.Hessling@qut.edu.au
+ PO Box 203 http://www.lightlink.com/hessling/
+ Bellara AUTHOR of | MAINTAINER of
+ QLD 4507 THE | PDCurses
+ Australia Rexx/SQL | Regina
+ Member of RexxLA: http://www.rexxla.org/
+------------------------------------------------------------------------
+
+ Module: PDCurses
+ Detailed differences between 2_4 and Latest
+
+--------------------------------------------------------------------------------
+
+Index: PDCurses/Makefile.in
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/Makefile.in,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -b -w -r1.1 -r1.3
+7,8c7,8
+< VER=24
+< VER_DOT=2.4
+---
+> VER=25
+> VER_DOT=2.5
+18,19c18
+< INSTALL =@INSTALL@
+< INSTALL_DATA =@INSTALL_DATA@
+---
+> INSTALL =$(srcdir)/install-sh
+20a20,22
+> RXLIBPRE = @RXLIBPRE@
+> RXLIBPST = @RXLIBPST@
+> SHLFILE = XCurses
+35,42c37,46
+< $(INSTALL_DATA) $(srcdir)/curses.h $(includedir)/xcurses.h
+< sed -e 's/#include <curses.h>/#include<xcurses.h>/' < panel.h > xpanel.h
+< $(INSTALL_DATA) $(srcdir)/xpanel.h $(includedir)/panel.h
+< $(INSTALL_DATA) pdcurses/libXCurses.a $(libdir)/libXCurses.a
+< $(INSTALL_DATA) pdcurses/$(RXLIBPRE)$(SHLFILE)$(RXLIBPST) $(libdir)/$(RXLIBPRE)$(SHLFILE)$(RXLIBPST)
+< $(RANLIB) $(libdir)/libXCurses.a
+< $(INSTALL_DATA) panel/libpanel.a $(libdir)/libpanel.a
+< $(RANLIB) $(libdir)/libpanel.a
+---
+> $(INSTALL) -d -m 755 $(libdir)
+> $(INSTALL) -d -m 755 $(includedir)
+> $(INSTALL) -c -m 644 $(srcdir)/curses.h $(includedir)/xcurses.h
+> sed -e 's/#include <curses.h>/#include <xcurses.h>/' < $(srcdir)/panel.h > ./xpanel.h
+> $(INSTALL) -m 644 ./xpanel.h $(includedir)/xpanel.h
+> $(INSTALL) -c -m 644 pdcurses/libXCurses.a $(libdir)/libXCurses.a
+> -$(RANLIB) $(libdir)/libXCurses.a
+> $(INSTALL) -c -m 555 pdcurses/$(RXLIBPRE)$(SHLFILE)$(RXLIBPST) $(libdir)/$(RXLIBPRE)$(SHLFILE)$(RXLIBPST)
+> $(INSTALL) -c -m 644 panel/libpanel.a $(libdir)/libpanel.a
+> -$(RANLIB) $(libdir)/libpanel.a
+57c61
+< curses.h xcurses.h curspriv.h panel.h x11.h maintain.er readme.* makezip.cmd \
+---
+> curses.h xcurses.h curspriv.h panel.h maintain.er readme.* makezip.cmd \
+63c67,68
+< x11/README x11/*.c x11/*.xbm x11/*.def x11/*.h \
+---
+> x11/README x11/*.c x11/*.xbm x11/*.def x11/*.h x11/process/*.c x11/*.exp \
+> x11/process/*.c x11/process/*.h x11/thread/*.c x11/thread/*.h \
+66c71
+< pdcurses/Makefile.in demos/Makefile.in panel/Makefile.in tools/Makefile.in
+---
+> pdcurses/Makefile.in pdcurses/Makefile.aix.in demos/Makefile.in panel/Makefile.in tools/Makefile.in
+69c74
+< (cd ..; tar cvf - $(PDC_DIR)/README $(PDC_DIR)/INSTALL $(PDC_DIR)/README $(PDC_DIR)/Makefile.in \
+---
+> (cd ..; tar cvf - $(PDC_DIR)/README $(PDC_DIR)/INSTALL $(PDC_DIR)/TODO $(PDC_DIR)/Makefile.in \
+71c76
+< $(PDC_DIR)/config.sub $(PDC_DIR)/install-sh $(PDC_DIR)/curses.h $(PDC_DIR)/xcurses.h \
+---
+> $(PDC_DIR)/config.sub $(PDC_DIR)/configure.in $(PDC_DIR)/install-sh $(PDC_DIR)/curses.h $(PDC_DIR)/xcurses.h \
+73c78
+< $(PDC_DIR)/x11.h $(PDC_DIR)/maintain.er $(PDC_DIR)/readme.* $(PDC_DIR)/makezip.cmd \
+---
+> $(PDC_DIR)/maintain.er $(PDC_DIR)/readme.* $(PDC_DIR)/makezip.cmd \
+75c80
+< $(PDC_DIR)/panel/README $(PDC_DIR)/panel/*.c \
+---
+> $(PDC_DIR)/panel/README $(PDC_DIR)/panel/*.c $(PDC_DIR)/*.spec \
+79c84,85
+< $(PDC_DIR)/x11/README $(PDC_DIR)/x11/*.c $(PDC_DIR)/x11/*.xbm $(PDC_DIR)/x11/*.def $(PDC_DIR)/x11/*.h \
+---
+> $(PDC_DIR)/x11/README $(PDC_DIR)/x11/*.c $(PDC_DIR)/x11/*.xbm $(PDC_DIR)/x11/*.def $(PDC_DIR)/x11/*.h $(PDC_DIR)/x11/*.exp \
+> $(PDC_DIR)/x11/process/*.c $(PDC_DIR)/x11/process/*.h $(PDC_DIR)/x11/thread/*.c $(PDC_DIR)/x11/thread/*.h \
+82c88
+< $(PDC_DIR)/pdcurses/Makefile.in $(PDC_DIR)/demos/Makefile.in $(PDC_DIR)/tools/Makefile.in \
+---
+> $(PDC_DIR)/pdcurses/Makefile.in $(PDC_DIR)/pdcurses/Makefile.aix.in $(PDC_DIR)/demos/Makefile.in $(PDC_DIR)/tools/Makefile.in \
+86c92
+< (cd ..; tar cvf - $(PDC_DIR)/README $(PDC_DIR)/INSTALL $(PDC_DIR)/README $(PDC_DIR)/Makefile.in \
+---
+> (cd ..; tar cvf - $(PDC_DIR)/README $(PDC_DIR)/INSTALL $(PDC_DIR)/TODO $(PDC_DIR)/Makefile.in \
+88c94
+< $(PDC_DIR)/config.sub $(PDC_DIR)/install-sh $(PDC_DIR)/curses.h $(PDC_DIR)/xcurses.h \
+---
+> $(PDC_DIR)/config.sub $(PDC_DIR)/configure.in $(PDC_DIR)/install-sh $(PDC_DIR)/curses.h $(PDC_DIR)/xcurses.h \
+90c96
+< $(PDC_DIR)/x11.h $(PDC_DIR)/maintain.er $(PDC_DIR)/readme.* $(PDC_DIR)/makezip.cmd \
+---
+> $(PDC_DIR)/maintain.er $(PDC_DIR)/readme.* $(PDC_DIR)/makezip.cmd \
+92c98
+< $(PDC_DIR)/panel/README $(PDC_DIR)/panel/*.c \
+---
+> $(PDC_DIR)/panel/README $(PDC_DIR)/panel/*.c $(PDC_DIR)/*.spec \
+96c102,103
+< $(PDC_DIR)/x11/README $(PDC_DIR)/x11/*.c $(PDC_DIR)/x11/*.xbm $(PDC_DIR)/x11/*.def $(PDC_DIR)/x11/*.h \
+---
+> $(PDC_DIR)/x11/README $(PDC_DIR)/x11/*.c $(PDC_DIR)/x11/*.xbm $(PDC_DIR)/x11/*.def $(PDC_DIR)/x11/*.h $(PDC_DIR)/x11/*.exp \
+> $(PDC_DIR)/x11/process/*.c $(PDC_DIR)/x11/process/*.h $(PDC_DIR)/x11/thread/*.c $(PDC_DIR)/x11/thread/*.h \
+99c106
+< $(PDC_DIR)/pdcurses/Makefile.in $(PDC_DIR)/demos/Makefile.in $(PDC_DIR)/tools/Makefile.in \
+---
+> $(PDC_DIR)/pdcurses/Makefile.in $(PDC_DIR)/pdcurses/Makefile.aix.in $(PDC_DIR)/demos/Makefile.in $(PDC_DIR)/tools/Makefile.in \
+
+Index: PDCurses/README
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/README,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+21,22c21,23
+< PDCurses has been ported to DOS, OS/2, X11, WIN32 and Flexos. A
+< directory containing the port-specific source files exists for each
+---
+> PDCurses has been ported to DOS, OS/2, X11, WIN32 and Amiga. A port
+> to Flexos is also included, but likely to be out of date.
+> A directory containing the port-specific source files exists for each
+
+Index: PDCurses/aclocal.m4
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/aclocal.m4,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+329c329,334
+< LD_RXLIB1="${CC} -Wl,-shared"
+---
+> LD_RXLIB1="${CC} -shared"
+> RXLIBPRE="lib"
+> RXLIBPST=".so"
+> ;;
+> *nto-qnx*)
+> LD_RXLIB1="${CC} -shared"
+
+Index: PDCurses/config.h.in
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/config.h.in,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+127a128,133
+> /* Define if you want to build XCurses with threads */
+> #undef USE_THREADS
+>
+> /* Define if you want to build XCurses with processes */
+> #undef USE_PROCESSES
+>
+
+Index: PDCurses/configure
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/configure,v
+retrieving revision 1.1
+retrieving revision 1.4
+diff -b -w -r1.1 -r1.4
+4c4
+< # Generated automatically using autoconf version 2.12
+---
+> # Generated automatically using autoconf version 2.13
+18a19,20
+> --with-threads build XCurses with threads"
+> ac_help="$ac_help
+59a62
+> SHELL=${CONFIG_SHELL-/bin/sh}
+343c346
+< echo "configure generated by autoconf version 2.12"
+---
+> echo "configure generated by autoconf version 2.13"
+513c516
+< ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+---
+> ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+515a519,520
+> ac_exeext=
+> ac_objext=o
+537c542
+< echo "configure:538: checking for one of the following C compilers: $all_words" >&5
+---
+> echo "configure:543: checking for one of the following C compilers: $all_words" >&5
+576c581
+< echo "configure:577: checking for $ac_word" >&5
+---
+> echo "configure:582: checking for $ac_word" >&5
+583,584c588,590
+< IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+< for ac_dir in $PATH; do
+---
+> IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+> ac_dummy="$PATH"
+> for ac_dir in $ac_dummy; do
+605c611
+< echo "configure:606: checking for $ac_word" >&5
+---
+> echo "configure:612: checking for $ac_word" >&5
+612c618
+< IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+---
+> IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+614c620,621
+< for ac_dir in $PATH; do
+---
+> ac_dummy="$PATH"
+> for ac_dir in $ac_dummy; do
+648a656,689
+> if test -z "$CC"; then
+> case "`uname -s`" in
+> *win32* | *WIN32*)
+> # Extract the first word of "cl", so it can be a program name with args.
+> set dummy cl; ac_word=$2
+> echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+> echo "configure:663: checking for $ac_word" >&5
+> if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+> echo $ac_n "(cached) $ac_c" 1>&6
+> else
+> if test -n "$CC"; then
+> ac_cv_prog_CC="$CC" # Let the user override the test.
+> else
+> IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+> ac_dummy="$PATH"
+> for ac_dir in $ac_dummy; do
+> test -z "$ac_dir" && ac_dir=.
+> if test -f $ac_dir/$ac_word; then
+> ac_cv_prog_CC="cl"
+> break
+> fi
+> done
+> IFS="$ac_save_ifs"
+> fi
+> fi
+> CC="$ac_cv_prog_CC"
+> if test -n "$CC"; then
+> echo "$ac_t""$CC" 1>&6
+> else
+> echo "$ac_t""no" 1>&6
+> fi
+> ;;
+> esac
+> fi
+653c694
+< echo "configure:654: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+---
+> echo "configure:695: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+659c700
+< ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+---
+> ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+663c704,705
+< #line 664 "configure"
+---
+>
+> #line 706 "configure"
+664a707
+>
+667c710
+< if { (eval echo configure:668: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+---
+> if { (eval echo configure:711: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+680a724,729
+> ac_ext=c
+> # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+> ac_cpp='$CPP $CPPFLAGS'
+> ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+> ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+> cross_compiling=$ac_cv_prog_cc_cross
+687c736
+< echo "configure:688: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+---
+> echo "configure:737: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+692c741
+< echo "configure:693: checking whether we are using GNU C" >&5
+---
+> echo "configure:742: checking whether we are using GNU C" >&5
+701c750
+< if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:702: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+---
+> if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:751: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+711a761,764
+> else
+> GCC=
+> fi
+>
+716c769
+< echo "configure:717: checking whether ${CC-cc} accepts -g" >&5
+---
+> echo "configure:770: checking whether ${CC-cc} accepts -g" >&5
+733a787
+> if test "$GCC" = yes; then
+736c790
+< CFLAGS="-O2"
+---
+> CFLAGS="-g"
+739,740c793,797
+< GCC=
+< test "${CFLAGS+set}" = set || CFLAGS="-g"
+---
+> if test "$GCC" = yes; then
+> CFLAGS="-O2"
+> else
+> CFLAGS=
+> fi
+744c801
+< echo "configure:745: checking for POSIXized ISC" >&5
+---
+> echo "configure:802: checking for POSIXized ISC" >&5
+808c865
+< if $ac_config_sub sun4 >/dev/null 2>&1; then :
+---
+> if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then :
+813c870
+< echo "configure:814: checking host system type" >&5
+---
+> echo "configure:871: checking host system type" >&5
+820c877
+< if host_alias=`$ac_config_guess`; then :
+---
+> if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then :
+827c884
+< host=`$ac_config_sub $host_alias`
+---
+> host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias`
+834c891
+< echo "configure:835: checking target system type" >&5
+---
+> echo "configure:892: checking target system type" >&5
+845c902
+< target=`$ac_config_sub $target_alias`
+---
+> target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias`
+852c909
+< echo "configure:853: checking build system type" >&5
+---
+> echo "configure:910: checking build system type" >&5
+863c920
+< build=`$ac_config_sub $build_alias`
+---
+> build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias`
+874a932
+> mymakefile="Makefile"
+881a940
+> mymakefile="Makefile.aix"
+894a954,955
+> *nto-qnx*)
+> ;;
+907c968
+< echo "configure:908: checking for maximum signal specifier:" >&5
+---
+> echo "configure:969: checking for maximum signal specifier:" >&5
+914c975
+< #line 915 "configure"
+---
+> #line 976 "configure"
+921c982
+< if { (eval echo configure:922: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+---
+> if { (eval echo configure:983: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+953c1014
+< echo "configure:954: checking for main in -l$mh_lib" >&5
+---
+> echo "configure:1015: checking for main in -l$mh_lib" >&5
+961c1022
+< #line 962 "configure"
+---
+> #line 1023 "configure"
+968c1029
+< if { (eval echo configure:969: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+---
+> if { (eval echo configure:1030: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+1002c1063
+< echo "configure:1003: checking for $ac_word" >&5
+---
+> echo "configure:1064: checking for $ac_word" >&5
+1009,1010c1070,1072
+< IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+< for ac_dir in $PATH; do
+---
+> IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
+> ac_dummy="$PATH"
+> for ac_dir in $ac_dummy; do
+1034a1097
+> # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+1039c1102
+< echo "configure:1040: checking for a BSD compatible install" >&5
+---
+> echo "configure:1103: checking for a BSD compatible install" >&5
+1044c1107
+< IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+---
+> IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
+1051c1114,1116
+< for ac_prog in ginstall installbsd scoinst install; do
+---
+> # Don't use installbsd from OSF since it installs stuff as root
+> # by default.
+> for ac_prog in ginstall scoinst install; do
+1056d1120
+< # OSF/1 installbsd also uses dspmsg, but is usable.
+1085a1150,1151
+> test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+>
+1089c1155
+< echo "configure:1090: checking whether ${MAKE-make} sets \${MAKE}" >&5
+---
+> echo "configure:1156: checking whether ${MAKE-make} sets \${MAKE}" >&5
+1117c1183
+< echo "configure:1118: checking how to run the C preprocessor" >&5
+---
+> echo "configure:1184: checking how to run the C preprocessor" >&5
+1132c1198
+< #line 1133 "configure"
+---
+> #line 1199 "configure"
+1138,1139c1204,1205
+< { (eval echo configure:1139: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+< ac_err=`grep -v '^ *+' conftest.out`
+---
+> { (eval echo configure:1205: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+> ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+1149c1215
+< #line 1150 "configure"
+---
+> #line 1216 "configure"
+1155,1156c1221,1239
+< { (eval echo configure:1156: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+< ac_err=`grep -v '^ *+' conftest.out`
+---
+> { (eval echo configure:1222: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+> ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+> if test -z "$ac_err"; then
+> :
+> else
+> echo "$ac_err" >&5
+> echo "configure: failed program was:" >&5
+> cat conftest.$ac_ext >&5
+> rm -rf conftest*
+> CPP="${CC-cc} -nologo -E"
+> cat > conftest.$ac_ext <<EOF
+> #line 1233 "configure"
+> #include "confdefs.h"
+> #include <assert.h>
+> Syntax Error
+> EOF
+> ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+> { (eval echo configure:1239: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+> ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+1168a1252,1253
+> fi
+> rm -f conftest*
+1179c1264
+< echo "configure:1180: checking for System V IPC support" >&5
+---
+> echo "configure:1265: checking for System V IPC support" >&5
+1182c1267
+< echo "configure:1183: checking for sys/ipc.h" >&5
+---
+> echo "configure:1268: checking for sys/ipc.h" >&5
+1187c1272
+< #line 1188 "configure"
+---
+> #line 1273 "configure"
+1192,1193c1277,1278
+< { (eval echo configure:1193: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+< ac_err=`grep -v '^ *+' conftest.out`
+---
+> { (eval echo configure:1278: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+> ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+1220c1305
+< echo "configure:1221: checking for ANSI C header files" >&5
+---
+> echo "configure:1306: checking for ANSI C header files" >&5
+1225c1310
+< #line 1226 "configure"
+---
+> #line 1311 "configure"
+1233,1234c1318,1319
+< { (eval echo configure:1234: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+< ac_err=`grep -v '^ *+' conftest.out`
+---
+> { (eval echo configure:1319: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+> ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+1250c1335
+< #line 1251 "configure"
+---
+> #line 1336 "configure"
+1268c1353
+< #line 1269 "configure"
+---
+> #line 1354 "configure"
+1289c1374
+< #line 1290 "configure"
+---
+> #line 1375 "configure"
+1300c1385
+< if { (eval echo configure:1301: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+---
+> if { (eval echo configure:1386: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+1339c1424
+< echo "configure:1340: checking for $ac_hdr" >&5
+---
+> echo "configure:1425: checking for $ac_hdr" >&5
+1344c1429
+< #line 1345 "configure"
+---
+> #line 1430 "configure"
+1349,1350c1434,1435
+< { (eval echo configure:1350: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+< ac_err=`grep -v '^ *+' conftest.out`
+---
+> { (eval echo configure:1435: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+> ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+1377c1462
+< echo "configure:1378: checking if compiler supports ANSI prototypes" >&5
+---
+> echo "configure:1463: checking if compiler supports ANSI prototypes" >&5
+1380c1465
+< #line 1381 "configure"
+---
+> #line 1466 "configure"
+1387c1472
+< if { (eval echo configure:1388: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+---
+> if { (eval echo configure:1473: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+1405c1490
+< echo "configure:1406: checking for working const" >&5
+---
+> echo "configure:1491: checking for working const" >&5
+1410c1495
+< #line 1411 "configure"
+---
+> #line 1496 "configure"
+1459c1544
+< if { (eval echo configure:1460: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+---
+> if { (eval echo configure:1545: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+1480c1565
+< echo "configure:1481: checking for size_t" >&5
+---
+> echo "configure:1566: checking for size_t" >&5
+1485c1570
+< #line 1486 "configure"
+---
+> #line 1571 "configure"
+1494c1579
+< egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+---
+> egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+1513c1598
+< echo "configure:1514: checking whether time.h and sys/time.h may both be included" >&5
+---
+> echo "configure:1599: checking whether time.h and sys/time.h may both be included" >&5
+1518c1603
+< #line 1519 "configure"
+---
+> #line 1604 "configure"
+1527c1612
+< if { (eval echo configure:1528: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+---
+> if { (eval echo configure:1613: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+1548c1633
+< echo "configure:1549: checking whether struct tm is in sys/time.h or time.h" >&5
+---
+> echo "configure:1634: checking whether struct tm is in sys/time.h or time.h" >&5
+1553c1638
+< #line 1554 "configure"
+---
+> #line 1639 "configure"
+1561c1646
+< if { (eval echo configure:1562: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+---
+> if { (eval echo configure:1647: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+1586c1671
+< echo "configure:1587: checking for main in -l$mh_lib" >&5
+---
+> echo "configure:1672: checking for main in -l$mh_lib" >&5
+1594c1679
+< #line 1595 "configure"
+---
+> #line 1680 "configure"
+1601c1686
+< if { (eval echo configure:1602: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+---
+> if { (eval echo configure:1687: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+1633c1718
+< echo "configure:1634: checking whether $CC understand -c and -o together" >&5
+---
+> echo "configure:1719: checking whether $CC understand -c and -o together" >&5
+1644c1729
+< if { (eval echo configure:__oline__: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } && test -f conftest.ooo && { (eval echo configure:1645: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; };
+---
+> if { (eval echo configure:__oline__: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } && test -f conftest.ooo && { (eval echo configure:1730: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; };
+1647c1732
+< if { (eval echo configure:__oline__: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } && test -f conftest.ooo && { (eval echo configure:1648: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; };
+---
+> if { (eval echo configure:__oline__: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } && test -f conftest.ooo && { (eval echo configure:1733: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; };
+1672c1757
+< echo "configure:1673: checking whether ${CC-cc} needs -traditional" >&5
+---
+> echo "configure:1758: checking whether ${CC-cc} needs -traditional" >&5
+1678c1763
+< #line 1679 "configure"
+---
+> #line 1764 "configure"
+1696c1781
+< #line 1697 "configure"
+---
+> #line 1782 "configure"
+1718c1803
+< echo "configure:1719: checking for 8-bit clean memcmp" >&5
+---
+> echo "configure:1804: checking for 8-bit clean memcmp" >&5
+1726c1811
+< #line 1727 "configure"
+---
+> #line 1812 "configure"
+1736c1821
+< if { (eval echo configure:1737: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+---
+> if { (eval echo configure:1822: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+1751c1836
+< test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.o"
+---
+> test $ac_cv_func_memcmp_clean = no && LIBOBJS="$LIBOBJS memcmp.${ac_objext}"
+1754c1839
+< echo "configure:1755: checking return type of signal handlers" >&5
+---
+> echo "configure:1840: checking return type of signal handlers" >&5
+1759c1844
+< #line 1760 "configure"
+---
+> #line 1845 "configure"
+1776c1861
+< if { (eval echo configure:1777: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+---
+> if { (eval echo configure:1862: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+1795c1880
+< echo "configure:1796: checking for vprintf" >&5
+---
+> echo "configure:1881: checking for vprintf" >&5
+1800c1885
+< #line 1801 "configure"
+---
+> #line 1886 "configure"
+1823c1908
+< if { (eval echo configure:1824: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+---
+> if { (eval echo configure:1909: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+1847c1932
+< echo "configure:1848: checking for _doprnt" >&5
+---
+> echo "configure:1933: checking for _doprnt" >&5
+1852c1937
+< #line 1853 "configure"
+---
+> #line 1938 "configure"
+1875c1960
+< if { (eval echo configure:1876: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+---
+> if { (eval echo configure:1961: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+1902c1987
+< echo "configure:1903: checking for $ac_func" >&5
+---
+> echo "configure:1988: checking for $ac_func" >&5
+1907c1992
+< #line 1908 "configure"
+---
+> #line 1993 "configure"
+1930c2015
+< if { (eval echo configure:1931: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+---
+> if { (eval echo configure:2016: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+1957c2042
+< echo "configure:1958: checking for location of X headers" >&5
+---
+> echo "configure:2043: checking for location of X headers" >&5
+2052c2137
+< echo "configure:2053: checking for location of X libraries" >&5
+---
+> echo "configure:2138: checking for location of X libraries" >&5
+2187c2272
+< echo "configure:2188: checking for $ac_hdr" >&5
+---
+> echo "configure:2273: checking for $ac_hdr" >&5
+2192c2277
+< #line 2193 "configure"
+---
+> #line 2278 "configure"
+2197,2198c2282,2283
+< { (eval echo configure:2198: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+< ac_err=`grep -v '^ *+' conftest.out`
+---
+> { (eval echo configure:2283: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+> ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+2232c2317
+< echo "configure:2233: checking for $mh_keydef in keysym.h" >&5
+---
+> echo "configure:2318: checking for $mh_keydef in keysym.h" >&5
+2235c2320
+< #line 2236 "configure"
+---
+> #line 2321 "configure"
+2242c2327
+< if { (eval echo configure:2243: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+---
+> if { (eval echo configure:2328: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+2316a2402,2424
+> # Check whether --with-threads or --without-threads was given.
+> if test "${with_threads+set}" = set; then
+> withval="$with_threads"
+> with_threads=$withval
+> else
+> with_threads=no
+> fi
+>
+> if test "$with_threads" = yes; then
+> cat >> confdefs.h <<\EOF
+> #define USE_THREADS 1
+> EOF
+>
+> x11type="thread"
+> else
+> cat >> confdefs.h <<\EOF
+> #define USE_PROCESSES 1
+> EOF
+>
+> x11type="process"
+> fi
+>
+>
+2397c2505
+< echo "configure:2398: checking compiler flags for a dynamic object" >&5
+---
+> echo "configure:2506: checking compiler flags for a dynamic object" >&5
+2400c2508
+< #line 2401 "configure"
+---
+> #line 2509 "configure"
+2412c2520
+< if { (eval echo configure:2413: \"$mh_compile\") 1>&5; (eval $mh_compile) 2>&5; }; then
+---
+> if { (eval echo configure:2521: \"$mh_compile\") 1>&5; (eval $mh_compile) 2>&5; }; then
+2500c2608
+< LD_RXLIB1="ld"
+---
+> LD_RXLIB1="ld -assert pure-text"
+2510c2618,2623
+< LD_RXLIB1="${CC} -Wl,-shared"
+---
+> LD_RXLIB1="${CC} -shared"
+> RXLIBPRE="lib"
+> RXLIBPST=".so"
+> ;;
+> *nto-qnx*)
+> LD_RXLIB1="${CC} -shared"
+2524c2637
+< #line 2525 "configure"
+---
+> #line 2638 "configure"
+2530c2643
+< if { (eval echo configure:2531: \"$mh_compile\") 1>&5; (eval $mh_compile) 2>&5; } && test -s conftest.o; then
+---
+> if { (eval echo configure:2644: \"$mh_compile\") 1>&5; (eval $mh_compile) 2>&5; } && test -s conftest.o; then
+2532c2645
+< if { (eval echo configure:2533: \"$mh_dyn_link\") 1>&5; (eval $mh_dyn_link) 2>&5; } && test -s conftest.rxlib; then
+---
+> if { (eval echo configure:2646: \"$mh_dyn_link\") 1>&5; (eval $mh_dyn_link) 2>&5; } && test -s conftest.rxlib; then
+2538c2651
+< if { (eval echo configure:2539: \"$mh_dyn_link\") 1>&5; (eval $mh_dyn_link) 2>&5; } && test -s conftest.rxlib; then
+---
+> if { (eval echo configure:2652: \"$mh_dyn_link\") 1>&5; (eval $mh_dyn_link) 2>&5; } && test -s conftest.rxlib; then
+2606c2719
+< case `(ac_space=' '; set) 2>&1` in
+---
+> case `(ac_space=' '; set | grep ac_space) 2>&1` in
+2673c2786
+< echo "$CONFIG_STATUS generated by autoconf version 2.12"
+---
+> echo "$CONFIG_STATUS generated by autoconf version 2.13"
+2684c2797
+< trap 'rm -fr `echo "Makefile pdcurses/Makefile demos/Makefile panel/Makefile tools/Makefile saa/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+---
+> trap 'rm -fr `echo "Makefile pdcurses/$mymakefile demos/Makefile panel/Makefile tools/Makefile saa/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+2692a2806
+> s%@SHELL@%$SHELL%g
+2695a2810
+> s%@FFLAGS@%$FFLAGS%g
+2732a2848
+> s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
+2739a2856
+> s%@x11type@%$x11type%g
+2802c2919
+< CONFIG_FILES=\${CONFIG_FILES-"Makefile pdcurses/Makefile demos/Makefile panel/Makefile tools/Makefile saa/Makefile"}
+---
+> CONFIG_FILES=\${CONFIG_FILES-"Makefile pdcurses/$mymakefile demos/Makefile panel/Makefile tools/Makefile saa/Makefile"}
+2979a3097,3105
+>
+> case "$target" in
+> *ibm-aix*)
+> mv pdcurses/Makefile.aix pdcurses/Makefile
+> echo "$ac_t""renaming pdcurses/Makefile.aix to pdcurses/Makefile" 1>&6
+> ;;
+> *)
+> ;;
+> esac
+
+Index: PDCurses/curses.h
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/curses.h,v
+retrieving revision 1.2
+retrieving revision 1.5
+diff -b -w -r1.2 -r1.5
+21c21
+< @Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @
+---
+> @Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @
+172c172
+< #define PDC_BUILD 2401
+---
+> #define PDC_BUILD 2501
+970a971,972
+> short line_color; /* Color of line attributes - default white */
+>
+1044,1045d1045
+< #define A_STANDOUT 0x00A00000L
+< #define A_BOLD 0x00800000L
+1048a1049,1050
+> # define A_BOLD 0x00800000L
+> # define A_RIGHTLINE 0x00010000L
+1050,1051d1051
+< #define A_INVIS 0x00080000L
+< #define A_PROTECT 0x00010000L
+1052a1053
+> # define A_INVIS 0x00080000L
+1056a1058,1062
+> # define A_LEFTLINE A_DIM
+> # define A_ITALIC A_INVIS
+> # define A_STANDOUT ( A_BOLD | A_REVERSE )
+> # define A_PROTECT ( A_UNDERLINE | A_LEFTLINE | A_RIGHTLINE )
+>
+1059c1065
+< #define A_NORMAL (chtype)0x0000 /* SysV */
+---
+> # define A_NORMAL (chtype)0x0000 /* System V */
+1499c1505,1507
+< # define KEY_MAX 0x222 /* Maximum curses key */
+---
+> # define KEY_SUP 0x223 /* Shifted up arrow */
+> # define KEY_SDOWN 0x224 /* Shifted down arrow */
+> # define KEY_MAX 0x224 /* Maximum curses key */
+1712a1721
+> int PDC_CDECL PDC_curs_set( int );
+1714a1724,1728
+> int PDC_CDECL PDC_wunderline( WINDOW*, int, bool );
+> int PDC_CDECL PDC_wleftline( WINDOW*, int, bool );
+> int PDC_CDECL PDC_wrightline( WINDOW*, int, bool );
+> int PDC_CDECL PDC_set_line_color( short );
+>
+1914a1929
+> int PDC_CDECL PDC_curs_set( /* int */ );
+1916a1932,1936
+> int PDC_CDECL PDC_wunderline( /* WINDOW*, int, bool */ );
+> int PDC_CDECL PDC_wleftline( /* WINDOW*, int, bool */ );
+> int PDC_CDECL PDC_wrightline( /* WINDOW*, int, bool */ );
+> int PDC_CDECL PDC_set_line_color( /* short */ );
+>
+1954a1975
+> #define getbkgd(w) ((w)->_bkgd)
+
+Index: PDCurses/curspriv.h
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/curspriv.h,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -b -w -r1.2 -r1.3
+21c21
+< @Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @
+---
+> @Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @
+370,371c370,371
+< int XCurses_display_cursor(int,int,int,int);
+< int XCurses_rawgetch(void);
+---
+> int XCurses_display_cursor(int,int,int,int,int);
+> int XCurses_rawgetch(int);
+385d384
+< void XCurses_set_title(char *);
+490,491c489,490
+< int XCurses_display_cursor( /*int,int,int,int*/ );
+< int XCurses_rawgetch( /*void*/ );
+---
+> int XCurses_display_cursor( /*int,int,int,int,int*/ );
+> int XCurses_rawgetch( /*int*/ );
+577a577
+> #define CURSES_DISPLAY_CURSOR 999986
+
+Index: PDCurses/demos/testcurs.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/demos/testcurs.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+36c36
+< char *rcsid_testcurs = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_testcurs = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+826c826,830
+< attrset(A_NORMAL);
+---
+> #ifdef XCURSES
+> attrset(A_PROTECT);
+> #else
+> attrset(A_BOLD);
+> #endif
+827a832
+> attrset(A_NORMAL);
+
+Index: PDCurses/doc/intro.man
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/doc/intro.man,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+366,376c366,376
+< *** slk_attroff slk
+< *** slk_attron slk
+< *** slk_attrset slk
+< *** slk_clear slk
+< *** slk_init slk
+< *** slk_label slk
+< *** slk_noutrefresh slk
+< *** slk_refresh slk
+< *** slk_restore slk
+< *** slk_set slk
+< *** slk_touch slk
+---
+> slk_attroff slk
+> slk_attron slk
+> slk_attrset slk
+> slk_clear slk
+> slk_init slk
+> slk_label slk
+> slk_noutrefresh slk
+> slk_refresh slk
+> slk_restore slk
+> slk_set slk
+> slk_touch slk
+497a498,499
+> PDC_get_input_fd pdckbd
+> PDC_get_key_modifiers pdckbd
+499a502
+> PDC_getclipboard pdcclip
+519a523,524
+> PDC_set_title pdcsetsc
+> PDC_setclipboard pdcclip
+
+Index: PDCurses/doc/x11.man
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/doc/x11.man,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -b -w -r1.1 -r1.3
+11,12c11,12
+< To use XCurses with an existing curses program, you need to make two
+< changes to your code.
+---
+> To use XCurses with an existing curses program, you need to make one
+> change to your code:
+14,25c14
+< The first is the addition of a definition of the program name as a
+< global char pointer. eg.
+<
+< #ifdef XCURSES
+< char *XCursesProgramName="sample";
+< #endif
+<
+< This name is used as the title of the X window, and for defining X
+< resources specific to your program.
+<
+< The second is a call to XCursesExit() just before exiting from your
+< program. eg.
+---
+> Call XCursesExit() just before exiting from your program. eg.
+35c24,26
+< When compiling your curses application, you need to add -DXCURSES.
+---
+> When compiling your curses application, you need to add -DXCURSES, and
+> include the <curses.h> or <xcurses.h> that comes with XCurses. You also
+> need to link your code with the XCurses library.
+47a39,45
+> To get the most out of XCurses in your curses application you need
+> to call Xinitscr() rather than initscr(). This allows you to pass
+> your program name and resource overrides to XCurses.
+>
+> The program name is used as the title of the X window, and for defining X
+> resources specific to your program.
+>
+70c68
+< boldFont
+---
+> italicFont
+82a81,88
+> colorBoldBlack
+> colorBoldRed
+> colorBoldGreen
+> colorBoldYellow
+> colorBoldBlue
+> colorBoldMagenta
+> colorBoldCyan
+> colorBoldWhite
+104c110
+< normalFont: the name of a fixed width font, used for A_NORMAL attribute
+---
+> normalFont: the name of a fixed width font
+107,110c113,116
+< boldFont: the name of a fixed width font, used for A_BOLD attribute
+< Default: 7x13bold
+<
+< NB. The dimensions of font and boldFont MUST be the same.
+---
+> italicFont: the name of a fixed width font to be used for
+> characters with A_ITALIC attributes. Must have the same
+> cell size as normalFont
+> Default: 7x13 (obviously not an italic font)
+125a132
+> Default: Black
+126a134
+> Default: red3
+127a136
+> Default: green3
+128a138
+> Default: yellow3
+129a140
+> Default: blue3
+130a142
+> Default: magenta3
+131a144
+> Default: cyan3
+133c146,162
+< Defaults are obvious :)
+---
+> Default: Grey
+> colorBoldBlack: the color of the COLOR_BLACK attribute combined with A_BOLD
+> Default: grey40
+> colorBoldRed the color of the COLOR_RED attribute combined with A_BOLD
+> Default: red1
+> colorBoldGreen the color of the COLOR_GREEN attribute combined with A_BOLD
+> Default: green1
+> colorBoldYellow the color of the COLOR_YELLOW attribute combined with A_BOLD
+> Default: yellow1
+> colorBoldBlue the color of the COLOR_BLUE attribute combined with A_BOLD
+> Default: blue1
+> colorBoldMagenta the color of the COLOR_MAGENTA attribute combined with A_BOLD
+> Default: magenta1
+> colorBoldCyan the color of the COLOR_CYAN attribute combined with A_BOLD
+> Default: cyan1
+> colorBoldWhite the color of the COLOR_WHITE attribute combined with A_BOLD
+> Default: White
+222d250
+< XCurses*boldFont: 9x13bold
+236,242c264,276
+< the.normalFont: 9x15
+< the.boldFont: 9x15bold
+< the.lines: 40
+< the.cols: 86
+< the.pointer: xterm
+< the.pointerForeColor: black
+< the.pointerBackColor: black
+---
+> ! resources with the * wildcard can be overridden by a parameter passed
+> ! to initscr()
+> !
+> the*normalFont: 9x15
+> the*lines: 40
+> the*cols: 86
+> the*pointer: xterm
+> the*pointerForeColor: white
+> the*pointerBackColor: black
+> !
+> ! resources with the . format can not be overridden by a parameter passed
+> ! to Xinitscr()
+> !
+243a278,283
+>
+> Resources may also be passed as a parameter to the Xinitscr() function.
+> The parameter is a string in the form of switches. eg. to set the color
+> "red" to "indianred", and the number of lines to 30, the string passed to
+> Xinitscr would be:
+> "-colorRed indianred -lines 30"
+
+Index: PDCurses/dos/pdckbd.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/dos/pdckbd.c,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -b -w -r1.2 -r1.3
+35c35
+< char *rcsid_PDCkbd = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_PDCkbd = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+56a57,62
+> /* Shifted Keypad */
+> 0xb0, KEY_SHOME, 0xb1, KEY_SUP, 0xb2, KEY_SPREVIOUS,
+> 0xb3, KEY_SLEFT, 0xb4, KEY_SRIGHT,
+> 0xb5, KEY_SEND, 0xb6, KEY_SDOWN, 0xb7, KEY_SNEXT,
+> 0xb8, KEY_SIC, 0xb9, KEY_SDC,
+>
+338a345,364
+> if (ascii == 0xe0 && scan == 0x47 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Home */
+> return ((int) (0xb0 << 8));
+> if (ascii == 0xe0 && scan == 0x48 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Up */
+> return ((int) (0xb1 << 8));
+> if (ascii == 0xe0 && scan == 0x49 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift PgUp */
+> return ((int) (0xb2 << 8));
+> if (ascii == 0xe0 && scan == 0x4b && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Left */
+> return ((int) (0xb3 << 8));
+> if (ascii == 0xe0 && scan == 0x4d && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Right */
+> return ((int) (0xb4 << 8));
+> if (ascii == 0xe0 && scan == 0x4f && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift End */
+> return ((int) (0xb5 << 8));
+> if (ascii == 0xe0 && scan == 0x50 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Down */
+> return ((int) (0xb6 << 8));
+> if (ascii == 0xe0 && scan == 0x51 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift PgDn */
+> return ((int) (0xb7 << 8));
+> if (ascii == 0xe0 && scan == 0x52 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Ins */
+> return ((int) (0xb8 << 8));
+> if (ascii == 0xe0 && scan == 0x53 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Del */
+> return ((int) (0xb9 << 8));
+
+Index: PDCurses/dos/wccdos.lrf
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/dos/wccdos.lrf,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -b -w -r1.2 -r1.3
+
+Index: PDCurses/dos/wccdos16.mak
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/dos/wccdos16.mak,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -b -w -r1.2 -r1.3
+
+Index: PDCurses/dos/wccdos4g.mak
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/dos/wccdos4g.mak,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -b -w -r1.2 -r1.3
+
+Index: PDCurses/install-sh
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/install-sh,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+4c4,16
+< # This comes from X11R5.
+---
+> # This comes from X11R5 (mit/util/scripts/install.sh).
+> #
+> # Copyright 1991 by the Massachusetts Institute of Technology
+> #
+> # Permission to use, copy, modify, distribute, and sell this software and its
+> # documentation for any purpose is hereby granted without fee, provided that
+> # the above copyright notice appear in all copies and that both that
+> # copyright notice and this permission notice appear in 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.
+11,12c23,24
+< # from scratch.
+< #
+---
+> # from scratch. It can only install one file at a time, a restriction
+> # shared with many OS's install programs.
+17a30,32
+> #
+> # Modified 1 Feb 2000 MHES to cater for mkdir -p
+> #
+32c47
+< tranformbasename=""
+---
+> transformbasename=""
+40a56
+> mkdircmd="$mkdirprog -p"
+171c187
+< $mkdirprog "${pathcomp}"
+---
+> $mkdircmd "${pathcomp}"
+
+Index: PDCurses/os2/gccos2.mak
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/os2/gccos2.mak,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -b -w -r1.2 -r1.3
+18c18
+< PDCURSES_HOME =c:\curses
+---
+> PDCURSES_HOME =e:\curses
+50c50
+< DLLTARGET = pdcurses.dll
+---
+> DLLTARGET = curses.dll
+62c62
+< DLLCURSES = pdcurses_dll.lib
+---
+> DLLCURSES = curses.lib
+206,209c206,209
+< pdcurses.dll : $(DLLOBJS) $(PDCDLOS)
+< $(LINK) $(DLLFLAGS) -o pdcurses.dll $(DLLOBJS) $(PDCDLOS) $(osdir)\pdcurses.def
+< emximp -o pdcurses_dll.lib $(osdir)\pdcurses.def
+< emximp -o pdcurses_dll.a pdcurses_dll.lib
+---
+> curses.dll : $(DLLOBJS) $(PDCDLOS)
+> $(LINK) $(DLLFLAGS) -o curses.dll $(DLLOBJS) $(PDCDLOS) $(osdir)\pdcurses.def
+> emximp -o curses.lib $(osdir)\pdcurses.def
+> emximp -o curses.a curses.lib
+
+Index: PDCurses/os2/pdckbd.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/os2/pdckbd.c,v
+retrieving revision 1.2
+retrieving revision 1.3
+diff -b -w -r1.2 -r1.3
+36c36
+< char *rcsid_PDCkbd = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_PDCkbd = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+57a58,63
+> /* Shifted Keypad */
+> 0xb0, KEY_SHOME, 0xb1, KEY_SUP, 0xb2, KEY_SPREVIOUS,
+> 0xb3, KEY_SLEFT, 0xb4, KEY_SRIGHT,
+> 0xb5, KEY_SEND, 0xb6, KEY_SDOWN, 0xb7, KEY_SNEXT,
+> 0xb8, KEY_SIC, 0xb9, KEY_SDC,
+>
+358a365,384
+> if (ascii == 0xe0 && scan == 0x47 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Home */
+> return ((int) (0xb0 << 8));
+> if (ascii == 0xe0 && scan == 0x48 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Up */
+> return ((int) (0xb1 << 8));
+> if (ascii == 0xe0 && scan == 0x49 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift PgUp */
+> return ((int) (0xb2 << 8));
+> if (ascii == 0xe0 && scan == 0x4b && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Left */
+> return ((int) (0xb3 << 8));
+> if (ascii == 0xe0 && scan == 0x4d && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Right */
+> return ((int) (0xb4 << 8));
+> if (ascii == 0xe0 && scan == 0x4f && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift End */
+> return ((int) (0xb5 << 8));
+> if (ascii == 0xe0 && scan == 0x50 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Down */
+> return ((int) (0xb6 << 8));
+> if (ascii == 0xe0 && scan == 0x51 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift PgDn */
+> return ((int) (0xb7 << 8));
+> if (ascii == 0xe0 && scan == 0x52 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Ins */
+> return ((int) (0xb8 << 8));
+> if (ascii == 0xe0 && scan == 0x53 && pdc_key_modifiers & PDC_KEY_MODIFIER_SHIFT) /* Shift Del */
+> return ((int) (0xb9 << 8));
+
+Index: PDCurses/os2/pdcurses.def
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/os2/pdcurses.def,v
+retrieving revision 1.2
+retrieving revision 1.4
+diff -b -w -r1.2 -r1.4
+1c1
+< LIBRARY PDCURSES
+---
+> LIBRARY CURSES
+95a96,98
+> slk_attroff
+> slk_attron
+> slk_attrset
+97a101
+> slk_label
+98a103,104
+> slk_refresh
+> slk_restore
+
+Index: PDCurses/pdcurses/Makefile.in
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/pdcurses/Makefile.in,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+13c13,14
+< x11dir = $(srcdir)/../x11
+---
+> x11basedir = $(srcdir)/../x11
+> x11dir = $(x11basedir)/@x11type@
+26c27
+< PDCURSES_X11_H =$(PDCURSES_HOME)/x11.h
+---
+> PDCURSES_X11_H =$(x11basedir)/pdcx11.h
+47c48
+< CPPFLAGS = -I$(INCDIR) -I$(srcdir)/.. -I.. @DEFS@ -DXCURSES @SYS_DEFS@
+---
+> CPPFLAGS = -I$(INCDIR) -I$(srcdir)/.. -I.. @DEFS@ -DXCURSES @SYS_DEFS@ -I$(x11basedir) -I$(x11dir)
+129a131,133
+> pdcx11.o \
+> x11curses.o \
+> x11common.o \
+185a190,192
+> pdcx11.sho \
+> x11curses.sho \
+> x11common.sho \
+311,312c318,319
+< pdcclip.o: $(x11dir)/pdcclip.c $(PDCURSES_HEADERS)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/pdcclip.c
+---
+> pdcclip.o: $(x11basedir)/pdcclip.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/pdcclip.c
+317,318c324,325
+< pdcdisp.o: $(x11dir)/pdcdisp.c $(PDCURSES_HEADERS)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/pdcdisp.c
+---
+> pdcdisp.o: $(x11basedir)/pdcdisp.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/pdcdisp.c
+320,321c327,328
+< pdcgetsc.o: $(x11dir)/pdcgetsc.c $(PDCURSES_HEADERS)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/pdcgetsc.c
+---
+> pdcgetsc.o: $(x11basedir)/pdcgetsc.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/pdcgetsc.c
+323,324c330,331
+< pdckbd.o: $(x11dir)/pdckbd.c $(PDCURSES_HEADERS)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/pdckbd.c
+---
+> pdckbd.o: $(x11basedir)/pdckbd.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/pdckbd.c
+326,327c333,334
+< pdcprint.o: $(x11dir)/pdcprint.c $(PDCURSES_HEADERS)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/pdcprint.c
+---
+> pdcprint.o: $(x11basedir)/pdcprint.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/pdcprint.c
+329,330c336,337
+< pdcscrn.o: $(x11dir)/pdcscrn.c $(PDCURSES_HEADERS)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/pdcscrn.c
+---
+> pdcscrn.o: $(x11basedir)/pdcscrn.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/pdcscrn.c
+332,333c339,340
+< pdcsetsc.o: $(x11dir)/pdcsetsc.c $(PDCURSES_HEADERS)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/pdcsetsc.c
+---
+> pdcsetsc.o: $(x11basedir)/pdcsetsc.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/pdcsetsc.c
+341,342c348,355
+< x11.o: $(x11dir)/x11.c $(PDCURSES_HEADERS) $(PDCURSES_X11_H)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/x11.c
+---
+> pdcx11.o: $(x11basedir)/pdcx11.c $(PDCURSES_HEADERS) $(PDCURSES_X11_H)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/pdcx11.c
+>
+> ScrollBox.o: $(x11basedir)/ScrollBox.c $(PDCURSES_HEADERS) $(PDCURSES_X11_H)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/ScrollBox.c
+>
+> sb.o: $(x11basedir)/sb.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11basedir)/sb.c
+344,345c357,361
+< ScrollBox.o: $(x11dir)/ScrollBox.c $(PDCURSES_HEADERS) $(PDCURSES_X11_H)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/ScrollBox.c
+---
+> x11common.o: $(x11dir)/x11common.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11dir)/x11common.c
+>
+> x11.o: $(x11dir)/x11.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11dir)/x11.c
+347,348c363,364
+< sb.o: $(x11dir)/sb.c $(PDCURSES_HEADERS)
+< $(CC) $(CCFLAGS) -o $@ $(x11dir)/sb.c
+---
+> x11curses.o: $(x11dir)/x11curses.c $(PDCURSES_HEADERS)
+> $(CC) $(CCFLAGS) -o $@ $(x11dir)/x11curses.c
+574c590
+< pdcclip.sho: $(x11dir)/pdcclip.c $(PDCURSES_HEADERS)
+---
+> pdcclip.sho: $(x11basedir)/pdcclip.c $(PDCURSES_HEADERS)
+576c592
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/pdcclip.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/pdcclip.c
+586c602
+< pdcdisp.sho: $(x11dir)/pdcdisp.c $(PDCURSES_HEADERS)
+---
+> pdcdisp.sho: $(x11basedir)/pdcdisp.c $(PDCURSES_HEADERS)
+588c604
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/pdcdisp.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/pdcdisp.c
+592c608
+< pdcgetsc.sho: $(x11dir)/pdcgetsc.c $(PDCURSES_HEADERS)
+---
+> pdcgetsc.sho: $(x11basedir)/pdcgetsc.c $(PDCURSES_HEADERS)
+594c610
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/pdcgetsc.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/pdcgetsc.c
+598c614
+< pdckbd.sho: $(x11dir)/pdckbd.c $(PDCURSES_HEADERS)
+---
+> pdckbd.sho: $(x11basedir)/pdckbd.c $(PDCURSES_HEADERS)
+600c616
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/pdckbd.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/pdckbd.c
+604c620
+< pdcprint.sho: $(x11dir)/pdcprint.c $(PDCURSES_HEADERS)
+---
+> pdcprint.sho: $(x11basedir)/pdcprint.c $(PDCURSES_HEADERS)
+606c622
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/pdcprint.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/pdcprint.c
+610c626
+< pdcscrn.sho: $(x11dir)/pdcscrn.c $(PDCURSES_HEADERS)
+---
+> pdcscrn.sho: $(x11basedir)/pdcscrn.c $(PDCURSES_HEADERS)
+612c628
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/pdcscrn.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/pdcscrn.c
+616c632
+< pdcsetsc.sho: $(x11dir)/pdcsetsc.c $(PDCURSES_HEADERS)
+---
+> pdcsetsc.sho: $(x11basedir)/pdcsetsc.c $(PDCURSES_HEADERS)
+618c634
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/pdcsetsc.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/pdcsetsc.c
+634c650
+< x11.sho: $(x11dir)/x11.c $(PDCURSES_HEADERS) $(PDCURSES_X11_H)
+---
+> pdcx11.sho: $(x11basedir)/pdcx11.c $(PDCURSES_HEADERS) $(PDCURSES_X11_H)
+636c652,658
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/x11.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/pdcx11.c
+> $(O2SHO)
+> $(SAVE2O)
+>
+> ScrollBox.sho: $(x11basedir)/ScrollBox.c $(PDCURSES_HEADERS) $(PDCURSES_X11_H)
+> $(O2SAVE)
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/ScrollBox.c
+640c662
+< ScrollBox.sho: $(x11dir)/ScrollBox.c $(PDCURSES_HEADERS) $(PDCURSES_X11_H)
+---
+> sb.sho: $(x11basedir)/sb.c $(PDCURSES_HEADERS)
+642c664,676
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/ScrollBox.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11basedir)/sb.c
+> $(O2SHO)
+> $(SAVE2O)
+>
+> x11common.sho: $(x11dir)/x11common.c $(PDCURSES_HEADERS)
+> $(O2SAVE)
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/x11common.c
+> $(O2SHO)
+> $(SAVE2O)
+>
+> x11.sho: $(x11dir)/x11.c $(PDCURSES_HEADERS)
+> $(O2SAVE)
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/x11.c
+646c680
+< sb.sho: $(x11dir)/sb.c $(PDCURSES_HEADERS)
+---
+> x11curses.sho: $(x11dir)/x11curses.c $(PDCURSES_HEADERS)
+648c682
+< $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/sb.c
+---
+> $(CC) $(CCFLAGS) $(DYN_COMP) $(CC2O) $(x11dir)/x11curses.c
+
+Index: PDCurses/pdcurses/border.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/pdcurses/border.c,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -b -w -r1.1 -r1.3
+33a34,36
+> #undef PDC_wunderline
+> #undef PDC_leftline
+> #undef PDC_rightline
+40c43
+< char *rcsid_border = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_border = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+56a60,62
+> int PDC_wunderline(WINDOW *win, int n, bool state);
+> int PDC_wleftline(WINDOW *win, int n, bool state);
+> int PDC_wrightline(WINDOW *win, int n, bool state);
+90c96
+< Portability X/Open BSD SYS V
+---
+> Portability X/Open BSD SYS V PDCurses
+92,98c98,107
+< border - - 4.0
+< wborder - - 4.0
+< box Y Y Y
+< hline - - 4.0
+< whline - - 4.0
+< vline - - 4.0
+< wvline - - 4.0
+---
+> border - - 4.0 Y
+> wborder - - 4.0 Y
+> box Y Y Y Y
+> hline - - 4.0 Y
+> whline - - 4.0 Y
+> vline - - 4.0 Y
+> wvline - - 4.0 Y
+> PDC_wunderline - - - Y
+> PDC_wleftline - - - Y
+> PDC_wrightline - - - Y
+415a425,565
+>
+> if (win->_firstch[n] == _NO_CHANGE)
+> {
+> win->_firstch[n] = win->_curx;
+> win->_lastch[n] = win->_curx;
+> }
+> else
+> {
+> win->_firstch[n] = min(win->_firstch[n], win->_curx);
+> win->_lastch[n] = max(win->_lastch[n], win->_curx);
+> }
+> }
+>
+> PDC_sync(win);
+> return (OK);
+> }
+> /***********************************************************************/
+> #ifdef HAVE_PROTO
+> int PDC_CDECL PDC_wunderline(WINDOW *win, int n, bool state)
+> #else
+> int PDC_CDECL PDC_wunderline(win,n,state)
+> WINDOW *win;
+> int n;
+> bool state;
+> #endif
+> /***********************************************************************/
+> {
+> int endpos;
+>
+> #ifdef PDCDEBUG
+> if (trace_on) PDC_debug("PDC_wunderline() - called\n");
+> #endif
+>
+> if (win == (WINDOW *)NULL)
+> return( ERR );
+>
+> if (n < 1)
+> return( ERR );
+>
+> endpos = min(win->_cury + n -1, win->_maxy);
+>
+> for (n = win->_cury; n <= endpos; n++)
+> {
+> if ( state )
+> win->_y[n][win->_curx] |= A_UNDERLINE; /* Turn ON A_UNDERLINE */
+> else
+> win->_y[n][win->_curx] |= ~A_UNDERLINE; /* Turn OFF A_UNDERLINE */
+>
+> if (win->_firstch[n] == _NO_CHANGE)
+> {
+> win->_firstch[n] = win->_curx;
+> win->_lastch[n] = win->_curx;
+> }
+> else
+> {
+> win->_firstch[n] = min(win->_firstch[n], win->_curx);
+> win->_lastch[n] = max(win->_lastch[n], win->_curx);
+> }
+> }
+>
+> PDC_sync(win);
+> return (OK);
+> }
+> /***********************************************************************/
+> #ifdef HAVE_PROTO
+> int PDC_CDECL PDC_wleftline(WINDOW *win, int n, bool state)
+> #else
+> int PDC_CDECL PDC_wleftline(win,n,state)
+> WINDOW *win;
+> int n;
+> bool state;
+> #endif
+> /***********************************************************************/
+> {
+> int endpos;
+>
+> #ifdef PDCDEBUG
+> if (trace_on) PDC_debug("PDC_wleftline() - called\n");
+> #endif
+>
+> if (win == (WINDOW *)NULL)
+> return( ERR );
+>
+> if (n < 1)
+> return( ERR );
+>
+> endpos = min(win->_cury + n -1, win->_maxy);
+>
+> for (n = win->_cury; n <= endpos; n++)
+> {
+> if ( state )
+> win->_y[n][win->_curx] |= A_LEFTLINE; /* Turn ON A_LEFTLINE */
+> else
+> win->_y[n][win->_curx] |= ~A_LEFTLINE; /* Turn OFF A_LEFTLINE */
+>
+> if (win->_firstch[n] == _NO_CHANGE)
+> {
+> win->_firstch[n] = win->_curx;
+> win->_lastch[n] = win->_curx;
+> }
+> else
+> {
+> win->_firstch[n] = min(win->_firstch[n], win->_curx);
+> win->_lastch[n] = max(win->_lastch[n], win->_curx);
+> }
+> }
+>
+> PDC_sync(win);
+> return (OK);
+> }
+> /***********************************************************************/
+> #ifdef HAVE_PROTO
+> int PDC_CDECL PDC_wrightline(WINDOW *win, int n, bool state)
+> #else
+> int PDC_CDECL PDC_wrightline(win,n,state)
+> WINDOW *win;
+> int n;
+> bool state;
+> #endif
+> /***********************************************************************/
+> {
+> int endpos;
+>
+> #ifdef PDCDEBUG
+> if (trace_on) PDC_debug("PDC_wrightline() - called\n");
+> #endif
+>
+> if (win == (WINDOW *)NULL)
+> return( ERR );
+>
+> if (n < 1)
+> return( ERR );
+>
+> endpos = min(win->_cury + n -1, win->_maxy);
+>
+> for (n = win->_cury; n <= endpos; n++)
+> {
+> if ( state )
+> win->_y[n][win->_curx] |= A_RIGHTLINE; /* Turn ON A_RIGHTLINE */
+> else
+> win->_y[n][win->_curx] |= ~A_RIGHTLINE; /* Turn OFF A_RIGHTLINE */
+
+Index: PDCurses/pdcurses/color.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/pdcurses/color.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+38a39
+> #undef PDC_set_line_color
+51c52
+< char *rcsid_color = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_color = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+65a67
+> int PDC_set_line_color(short color);
+101a104,107
+> PDC_set_line_color() is used to set the color, globally, for the
+> color of the lines drawn for the attributes: A_UNDERLINE, A_OVERLINE,
+> A_LEFTLINE and A_RIGHTLINE. PDCurses only feature.
+>
+111c117
+< Portability X/Open BSD SYS V
+---
+> Portability X/Open BSD SYS V PDCurses
+119a126
+> PDC_set_line_color - - - Y
+349a357,371
+> return(OK);
+> }
+> /***********************************************************************/
+> #ifdef HAVE_PROTO
+> int PDC_CDECL PDC_set_line_color(short color)
+> #else
+> int PDC_CDECL PDC_set_line_color(color)
+> short color;
+> #endif
+> /***********************************************************************/
+> {
+>
+> if (color >= COLORS || color < 0)
+> return(ERR);
+> SP->line_color = color;
+
+Index: PDCurses/pdcurses/getch.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/pdcurses/getch.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+42c42
+< char *rcsid_getch = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_getch = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+163c163
+< int waitingtenths = SP->delaytenths;
+---
+> int waitingtenths = 0;
+171a172,174
+> if ( SP->delaytenths )
+> waitingtenths = 10*SP->delaytenths;
+>
+282c285,286
+< napms(100);
+---
+> napms(10);
+> continue;
+304c308
+< if (SP->raw_inp || SP->cbreak)
+---
+> if ( (SP->raw_inp || SP->cbreak) )
+
+Index: PDCurses/pdcurses/initscr.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/pdcurses/initscr.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+64c64
+< char *rcsid_initscr = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_initscr = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+324,325c324,325
+< ACS_SBSS = (chtype)21|A_ALTCHARSET;
+< ACS_SSSB = (chtype)22|A_ALTCHARSET;
+---
+> ACS_SBSS = (chtype)22|A_ALTCHARSET;
+> ACS_SSSB = (chtype)21|A_ALTCHARSET;
+
+Index: PDCurses/pdcurses/util.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/pdcurses/util.c,v
+retrieving revision 1.1
+retrieving revision 1.3
+diff -b -w -r1.1 -r1.3
+68c68
+< char *rcsid_util = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_util = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+237c237
+< "KEY_RESIZE"
+---
+> "KEY_RESIZE", "KEY_SUP", "KEY_SDOWN"
+352c352
+< (void)XCurses_rawgetch();
+---
+> (void)XCurses_rawgetch(0);
+
+Index: PDCurses/win32/curses.def
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/win32/curses.def,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+2a3,5
+> ; used for Win32 port as well as AIX port
+> ; each entry point MUST be on a seperate line prefixed
+> ; by EXPORTS in column 1
+
+Index: PDCurses/win32/pdckbd.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/win32/pdckbd.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+28c28
+< char *rcsid_PDCkbd = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_PDCkbd = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+318c318
+< {KEY_UP, SHF_UP, CTL_UP, ALT_UP }, /* 38 */
+---
+> {KEY_UP, KEY_SUP, CTL_UP, ALT_UP }, /* 38 */
+320,322c320,322
+< {KEY_DOWN, SHF_DOWN, CTL_DOWN, ALT_DOWN }, /* 40 */
+< {KEY_IC, SHF_IC, CTL_INS, ALT_INS }, /* 45 */
+< {KEY_DC, SHF_DC, CTL_DEL, ALT_DEL }, /* 46 */
+---
+> {KEY_DOWN, KEY_SDOWN, CTL_DOWN, ALT_DOWN }, /* 40 */
+> {KEY_IC, KEY_SIC, CTL_INS, ALT_INS }, /* 45 */
+> {KEY_DC, KEY_SDC, CTL_DEL, ALT_DEL }, /* 46 */
+
+Index: PDCurses/x11/README
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/x11/README,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+12c12
+< The files in this directory are copyright Mark Hessling 1995-1999.
+---
+> The files in this directory are copyright Mark Hessling 1995-2000.
+26a27,39
+>
+> Structure
+> ---------
+>
+> x11.c - contains functions that are X11 specific functions that are
+> used by both the process and thread implementations
+> x11.h - #defines and includes for the X11 process/thread
+> x11_proc.c - contains functions that are used by the X11 (child) process
+> in the process implementation
+> curses_proc.c - contains functions that are used by the curses (parent)
+> process in the process implementation
+> x11_thread.c -
+> curses_thread.c -
+
+Index: PDCurses/x11/ScrollBox.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/x11/ScrollBox.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+124c124
+< Widget main, vscroll, hscroll;
+---
+> Widget wmain, vscroll, hscroll;
+130a131
+> #if 0
+132a134
+> #endif
+151c153
+< main = sbw->composite.children[0];
+---
+> wmain = sbw->composite.children[0];
+161c163
+< (2 * main->core.border_width);
+---
+> (2 * wmain->core.border_width);
+165c167
+< (2 * main->core.border_width);
+---
+> (2 * wmain->core.border_width);
+167c169
+< vx = main->core.x + mw + sbw->scrollBox.h_space + main->core.border_width + vscroll->core.border_width;
+---
+> vx = wmain->core.x + mw + sbw->scrollBox.h_space + wmain->core.border_width + vscroll->core.border_width;
+169c171
+< hy = main->core.y + mh + sbw->scrollBox.v_space + main->core.border_width + hscroll->core.border_width;
+---
+> hy = wmain->core.y + mh + sbw->scrollBox.v_space + wmain->core.border_width + hscroll->core.border_width;
+175c177
+< XtResizeWidget(main, mw, mh, 1);
+---
+> XtResizeWidget(wmain, mw, mh, 1);
+177c179
+< tw = main->core.width + (2 * sbw->scrollBox.h_space) +
+---
+> tw = wmain->core.width + (2 * sbw->scrollBox.h_space) +
+179c181
+< (2 * main->core.border_width);
+---
+> (2 * wmain->core.border_width);
+181c183
+< th = main->core.height + (2 * sbw->scrollBox.v_space) +
+---
+> th = wmain->core.height + (2 * sbw->scrollBox.v_space) +
+183c185
+< (2 * main->core.border_width);
+---
+> (2 * wmain->core.border_width);
+185,186c187,188
+< hw = mw = main->core.width;
+< vh = mh = main->core.height;
+---
+> hw = mw = wmain->core.width;
+> vh = mh = wmain->core.height;
+188c190
+< vx = main->core.x + mw + sbw->scrollBox.h_space + main->core.border_width + vscroll->core.border_width;
+---
+> vx = wmain->core.x + mw + sbw->scrollBox.h_space + wmain->core.border_width + vscroll->core.border_width;
+190c192
+< hy = main->core.y + mh + sbw->scrollBox.v_space + main->core.border_width + hscroll->core.border_width;
+---
+> hy = wmain->core.y + mh + sbw->scrollBox.v_space + wmain->core.border_width + hscroll->core.border_width;
+
+Index: PDCurses/x11/pdcdisp.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/x11/pdcdisp.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+37c37
+< char *rcsid_PDCdisp = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_PDCdisp = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+201c201
+< XCurses_display_cursor(SP->cursrow,SP->curscol,row,col);
+---
+> XCurses_display_cursor(SP->cursrow,SP->curscol,row,col,SP->visibility);
+
+Index: PDCurses/x11/pdckbd.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/x11/pdckbd.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+28c28
+< char *rcsid_PDCkbd = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_PDCkbd = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+243c243
+< c = XCurses_rawgetch();
+---
+> c = XCurses_rawgetch( SP->delaytenths );
+
+Index: PDCurses/x11/pdcscrn.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/x11/pdcscrn.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+27c27
+< char *rcsid_PDCscrn = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_PDCscrn = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+179a180
+> internal->line_color = COLOR_WHITE;
+
+Index: PDCurses/x11/pdcsetsc.c
+===================================================================
+RCS file: /usr/local/cvsroot/PDCurses/x11/pdcsetsc.c,v
+retrieving revision 1.1
+retrieving revision 1.2
+diff -b -w -r1.1 -r1.2
+27c27
+< char *rcsid_PDCsetsc = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+---
+> char *rcsid_PDCsetsc = "@Id: case16.pat,v 1.1 2001/04/22 23:30:04 tom Exp @";
+123c123
+< int ret_vis;
+---
+> int ret_vis = SP->visibility;
+129c129,130
+< ret_vis = SP->visibility;
+---
+> if ( visibility != -1 )
+> {
+131,132c132,133
+<
+< XCurses_display_cursor(SP->cursrow,SP->curscol,SP->cursrow,SP->curscol);
+---
+> }
+> XCurses_display_cursor(SP->cursrow,SP->curscol,SP->cursrow,SP->curscol,visibility);
diff --git a/patch_cmds/diffstat/testing/case16.ref b/patch_cmds/diffstat/testing/case16.ref
new file mode 100644
index 0000000..222db1b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 ++++----
+ README | 5
+ aclocal.m4 | 7
+ config.h.in | 6
+ configure | 386 +++++++++++++++++++++++++++++++++------------------
+ curses.h | 37 +++-
+ curspriv.h | 12 -
+ demos/testcurs.c | 9 -
+ doc/intro.man | 27 ++-
+ doc/x11.man | 100 +++++++++----
+ dos/pdckbd.c | 28 +++
+ install-sh | 26 ++-
+ os2/gccos2.mak | 14 -
+ os2/pdckbd.c | 28 +++
+ os2/pdcurses.def | 8 -
+ pdcurses/Makefile.in | 120 ++++++++++-----
+ pdcurses/border.c | 168 +++++++++++++++++++++-
+ pdcurses/color.c | 26 +++
+ pdcurses/getch.c | 12 +
+ pdcurses/initscr.c | 6
+ pdcurses/util.c | 6
+ win32/curses.def | 3
+ win32/pdckbd.c | 10 -
+ x11/README | 15 +
+ x11/ScrollBox.c | 32 ++--
+ x11/pdcdisp.c | 4
+ x11/pdckbd.c | 4
+ x11/pdcscrn.c | 3
+ x11/pdcsetsc.c | 11 -
+ 29 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16R.ref b/patch_cmds/diffstat/testing/case16R.ref
new file mode 100644
index 0000000..4325241
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16R.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 +++-----
+ README | 5
+ aclocal.m4 | 7
+ config.h.in | 6
+ configure | 386 +++++++++++++++++----------------------------------
+ curses.h | 37 +---
+ curspriv.h | 12 -
+ demos/testcurs.c | 9 -
+ doc/intro.man | 27 +--
+ doc/x11.man | 100 +++----------
+ dos/pdckbd.c | 28 ---
+ dos/wccdos.lrf | 26 ---
+ os2/gccos2.mak | 14 -
+ os2/pdckbd.c | 28 ---
+ os2/pdcurses.def | 8 -
+ pdcurses/Makefile.in | 120 +++++----------
+ pdcurses/border.c | 168 +---------------------
+ pdcurses/color.c | 26 ---
+ pdcurses/getch.c | 12 -
+ pdcurses/initscr.c | 6
+ pdcurses/util.c | 6
+ win32/curses.def | 3
+ win32/pdckbd.c | 10 -
+ x11/README | 15 -
+ x11/ScrollBox.c | 32 +---
+ x11/pdcdisp.c | 4
+ x11/pdckbd.c | 4
+ x11/pdcscrn.c | 3
+ x11/pdcsetsc.c | 11 -
+ 29 files changed, 327 insertions(+), 847 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16Rp0.ref b/patch_cmds/diffstat/testing/case16Rp0.ref
new file mode 100644
index 0000000..4054d02
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16Rp0.ref
@@ -0,0 +1,30 @@
+ PDCurses/Makefile.in | 61 ++----
+ PDCurses/README | 5
+ PDCurses/aclocal.m4 | 7
+ PDCurses/config.h.in | 6
+ PDCurses/configure | 386 ++++++++++++++----------------------------
+ PDCurses/curses.h | 37 ----
+ PDCurses/curspriv.h | 12 -
+ PDCurses/demos/testcurs.c | 9
+ PDCurses/doc/intro.man | 27 +-
+ PDCurses/doc/x11.man | 100 +++-------
+ PDCurses/dos/pdckbd.c | 28 ---
+ PDCurses/dos/wccdos.lrf | 26 --
+ PDCurses/os2/gccos2.mak | 14 -
+ PDCurses/os2/pdckbd.c | 28 ---
+ PDCurses/os2/pdcurses.def | 8
+ PDCurses/pdcurses/Makefile.in | 120 ++++---------
+ PDCurses/pdcurses/border.c | 168 ------------------
+ PDCurses/pdcurses/color.c | 26 --
+ PDCurses/pdcurses/getch.c | 12 -
+ PDCurses/pdcurses/initscr.c | 6
+ PDCurses/pdcurses/util.c | 6
+ PDCurses/win32/curses.def | 3
+ PDCurses/win32/pdckbd.c | 10 -
+ PDCurses/x11/README | 15 -
+ PDCurses/x11/ScrollBox.c | 32 +--
+ PDCurses/x11/pdcdisp.c | 4
+ PDCurses/x11/pdckbd.c | 4
+ PDCurses/x11/pdcscrn.c | 3
+ PDCurses/x11/pdcsetsc.c | 11 -
+ 29 files changed, 327 insertions(+), 847 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16b.ref b/patch_cmds/diffstat/testing/case16b.ref
new file mode 100644
index 0000000..222db1b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16b.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 ++++----
+ README | 5
+ aclocal.m4 | 7
+ config.h.in | 6
+ configure | 386 +++++++++++++++++++++++++++++++++------------------
+ curses.h | 37 +++-
+ curspriv.h | 12 -
+ demos/testcurs.c | 9 -
+ doc/intro.man | 27 ++-
+ doc/x11.man | 100 +++++++++----
+ dos/pdckbd.c | 28 +++
+ install-sh | 26 ++-
+ os2/gccos2.mak | 14 -
+ os2/pdckbd.c | 28 +++
+ os2/pdcurses.def | 8 -
+ pdcurses/Makefile.in | 120 ++++++++++-----
+ pdcurses/border.c | 168 +++++++++++++++++++++-
+ pdcurses/color.c | 26 +++
+ pdcurses/getch.c | 12 +
+ pdcurses/initscr.c | 6
+ pdcurses/util.c | 6
+ win32/curses.def | 3
+ win32/pdckbd.c | 10 -
+ x11/README | 15 +
+ x11/ScrollBox.c | 32 ++--
+ x11/pdcdisp.c | 4
+ x11/pdckbd.c | 4
+ x11/pdcscrn.c | 3
+ x11/pdcsetsc.c | 11 -
+ 29 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16f0.ref b/patch_cmds/diffstat/testing/case16f0.ref
new file mode 100644
index 0000000..e18c43a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16f0.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 34 + 27 - 0 !
+ README | 5 3 + 2 - 0 !
+ aclocal.m4 | 7 6 + 1 - 0 !
+ config.h.in | 6 6 + 0 - 0 !
+ configure | 386 256 + 130 - 0 !
+ curses.h | 37 29 + 8 - 0 !
+ curspriv.h | 12 6 + 6 - 0 !
+ demos/testcurs.c | 9 7 + 2 - 0 !
+ doc/intro.man | 27 16 + 11 - 0 !
+ doc/x11.man | 100 70 + 30 - 0 !
+ dos/pdckbd.c | 28 27 + 1 - 0 !
+ install-sh | 26 21 + 5 - 0 !
+ os2/gccos2.mak | 14 7 + 7 - 0 !
+ os2/pdckbd.c | 28 27 + 1 - 0 !
+ os2/pdcurses.def | 8 7 + 1 - 0 !
+ pdcurses/Makefile.in | 120 77 + 43 - 0 !
+ pdcurses/border.c | 168 159 + 9 - 0 !
+ pdcurses/color.c | 26 24 + 2 - 0 !
+ pdcurses/getch.c | 12 8 + 4 - 0 !
+ pdcurses/initscr.c | 6 3 + 3 - 0 !
+ pdcurses/util.c | 6 3 + 3 - 0 !
+ win32/curses.def | 3 3 + 0 - 0 !
+ win32/pdckbd.c | 10 5 + 5 - 0 !
+ x11/README | 15 14 + 1 - 0 !
+ x11/ScrollBox.c | 32 17 + 15 - 0 !
+ x11/pdcdisp.c | 4 2 + 2 - 0 !
+ x11/pdckbd.c | 4 2 + 2 - 0 !
+ x11/pdcscrn.c | 3 2 + 1 - 0 !
+ x11/pdcsetsc.c | 11 6 + 5 - 0 !
+ 29 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16k.ref b/patch_cmds/diffstat/testing/case16k.ref
new file mode 100644
index 0000000..222db1b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16k.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 ++++----
+ README | 5
+ aclocal.m4 | 7
+ config.h.in | 6
+ configure | 386 +++++++++++++++++++++++++++++++++------------------
+ curses.h | 37 +++-
+ curspriv.h | 12 -
+ demos/testcurs.c | 9 -
+ doc/intro.man | 27 ++-
+ doc/x11.man | 100 +++++++++----
+ dos/pdckbd.c | 28 +++
+ install-sh | 26 ++-
+ os2/gccos2.mak | 14 -
+ os2/pdckbd.c | 28 +++
+ os2/pdcurses.def | 8 -
+ pdcurses/Makefile.in | 120 ++++++++++-----
+ pdcurses/border.c | 168 +++++++++++++++++++++-
+ pdcurses/color.c | 26 +++
+ pdcurses/getch.c | 12 +
+ pdcurses/initscr.c | 6
+ pdcurses/util.c | 6
+ win32/curses.def | 3
+ win32/pdckbd.c | 10 -
+ x11/README | 15 +
+ x11/ScrollBox.c | 32 ++--
+ x11/pdcdisp.c | 4
+ x11/pdckbd.c | 4
+ x11/pdcscrn.c | 3
+ x11/pdcsetsc.c | 11 -
+ 29 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16p1.ref b/patch_cmds/diffstat/testing/case16p1.ref
new file mode 100644
index 0000000..222db1b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16p1.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 ++++----
+ README | 5
+ aclocal.m4 | 7
+ config.h.in | 6
+ configure | 386 +++++++++++++++++++++++++++++++++------------------
+ curses.h | 37 +++-
+ curspriv.h | 12 -
+ demos/testcurs.c | 9 -
+ doc/intro.man | 27 ++-
+ doc/x11.man | 100 +++++++++----
+ dos/pdckbd.c | 28 +++
+ install-sh | 26 ++-
+ os2/gccos2.mak | 14 -
+ os2/pdckbd.c | 28 +++
+ os2/pdcurses.def | 8 -
+ pdcurses/Makefile.in | 120 ++++++++++-----
+ pdcurses/border.c | 168 +++++++++++++++++++++-
+ pdcurses/color.c | 26 +++
+ pdcurses/getch.c | 12 +
+ pdcurses/initscr.c | 6
+ pdcurses/util.c | 6
+ win32/curses.def | 3
+ win32/pdckbd.c | 10 -
+ x11/README | 15 +
+ x11/ScrollBox.c | 32 ++--
+ x11/pdcdisp.c | 4
+ x11/pdckbd.c | 4
+ x11/pdcscrn.c | 3
+ x11/pdcsetsc.c | 11 -
+ 29 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16p9.ref b/patch_cmds/diffstat/testing/case16p9.ref
new file mode 100644
index 0000000..818a0de
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16p9.ref
@@ -0,0 +1,25 @@
+ Makefile.in | 181 ++++++++++++++++-----------
+ README | 20 ++-
+ ScrollBox.c | 32 ++--
+ aclocal.m4 | 7 -
+ border.c | 168 ++++++++++++++++++++++++-
+ color.c | 26 +++
+ config.h.in | 6
+ configure | 386 +++++++++++++++++++++++++++++++++++++++--------------------
+ curses.def | 3
+ curses.h | 37 ++++-
+ curspriv.h | 12 -
+ gccos2.mak | 14 +-
+ getch.c | 12 +
+ initscr.c | 6
+ install-sh | 26 +++
+ intro.man | 27 ++--
+ pdcdisp.c | 4
+ pdckbd.c | 70 +++++++++-
+ pdcscrn.c | 3
+ pdcsetsc.c | 11 -
+ pdcurses.def | 8 +
+ testcurs.c | 9 +
+ util.c | 6
+ x11.man | 100 ++++++++++-----
+ 24 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16r1.ref b/patch_cmds/diffstat/testing/case16r1.ref
new file mode 100644
index 0000000..cfa76c0
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16r1.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 ++++----
+ README | 5
+ aclocal.m4 | 7 +
+ config.h.in | 6 +
+ configure | 386 ++++++++++++++++++++++++++++++++++-----------------
+ curses.h | 37 ++++-
+ curspriv.h | 12 +-
+ demos/testcurs.c | 9 +
+ doc/intro.man | 27 ++-
+ doc/x11.man | 100 +++++++++----
+ dos/pdckbd.c | 28 ++++
+ install-sh | 26 +++-
+ os2/gccos2.mak | 14 +-
+ os2/pdckbd.c | 28 ++++
+ os2/pdcurses.def | 8 +
+ pdcurses/Makefile.in | 120 ++++++++++------
+ pdcurses/border.c | 168 +++++++++++++++++++++-
+ pdcurses/color.c | 26 +++
+ pdcurses/getch.c | 12 +-
+ pdcurses/initscr.c | 6
+ pdcurses/util.c | 6
+ win32/curses.def | 3
+ win32/pdckbd.c | 10 +-
+ x11/README | 15 ++
+ x11/ScrollBox.c | 32 ++--
+ x11/pdcdisp.c | 4
+ x11/pdckbd.c | 4
+ x11/pdcscrn.c | 3
+ x11/pdcsetsc.c | 11 +-
+ 29 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16r2.ref b/patch_cmds/diffstat/testing/case16r2.ref
new file mode 100644
index 0000000..4c56b61
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16r2.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 ++++----
+ README | 5 +
+ aclocal.m4 | 7 +
+ config.h.in | 6 +
+ configure | 386 ++++++++++++++++++++++++++++++++++-----------------
+ curses.h | 37 ++++-
+ curspriv.h | 12 +-
+ demos/testcurs.c | 9 +
+ doc/intro.man | 27 ++--
+ doc/x11.man | 100 +++++++++----
+ dos/pdckbd.c | 28 ++++
+ install-sh | 26 +++
+ os2/gccos2.mak | 14 +-
+ os2/pdckbd.c | 28 ++++
+ os2/pdcurses.def | 8 +
+ pdcurses/Makefile.in | 120 ++++++++++------
+ pdcurses/border.c | 168 +++++++++++++++++++++-
+ pdcurses/color.c | 26 +++
+ pdcurses/getch.c | 12 +-
+ pdcurses/initscr.c | 6
+ pdcurses/util.c | 6
+ win32/curses.def | 3 +
+ win32/pdckbd.c | 10
+ x11/README | 15 ++
+ x11/ScrollBox.c | 32 ++--
+ x11/pdcdisp.c | 4
+ x11/pdckbd.c | 4
+ x11/pdcscrn.c | 3 +
+ x11/pdcsetsc.c | 11 +
+ 29 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case16u.ref b/patch_cmds/diffstat/testing/case16u.ref
new file mode 100644
index 0000000..222db1b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case16u.ref
@@ -0,0 +1,30 @@
+ Makefile.in | 61 ++++----
+ README | 5
+ aclocal.m4 | 7
+ config.h.in | 6
+ configure | 386 +++++++++++++++++++++++++++++++++------------------
+ curses.h | 37 +++-
+ curspriv.h | 12 -
+ demos/testcurs.c | 9 -
+ doc/intro.man | 27 ++-
+ doc/x11.man | 100 +++++++++----
+ dos/pdckbd.c | 28 +++
+ install-sh | 26 ++-
+ os2/gccos2.mak | 14 -
+ os2/pdckbd.c | 28 +++
+ os2/pdcurses.def | 8 -
+ pdcurses/Makefile.in | 120 ++++++++++-----
+ pdcurses/border.c | 168 +++++++++++++++++++++-
+ pdcurses/color.c | 26 +++
+ pdcurses/getch.c | 12 +
+ pdcurses/initscr.c | 6
+ pdcurses/util.c | 6
+ win32/curses.def | 3
+ win32/pdckbd.c | 10 -
+ x11/README | 15 +
+ x11/ScrollBox.c | 32 ++--
+ x11/pdcdisp.c | 4
+ x11/pdckbd.c | 4
+ x11/pdcscrn.c | 3
+ x11/pdcsetsc.c | 11 -
+ 29 files changed, 847 insertions(+), 327 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case17.pat b/patch_cmds/diffstat/testing/case17.pat
new file mode 100644
index 0000000..3149deb
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17.pat
@@ -0,0 +1,115 @@
+--- linux/kernel/sched.c.user 2002-08-08 11:52:55.000000000 -0300
++++ linux/kernel/sched.c 2002-08-08 20:44:01.000000000 -0300
+@@ -124,6 +124,9 @@
+ # define finish_arch_switch(rq) spin_unlock_irq(&(rq)->lock)
+ #endif
+
++/* Per-user fair scheduler on/off switch. */
++int fairsched_enabled;
++
+ /*
+ * task_rq_lock - lock the runqueue a given task resides on and disable
+ * interrupts. Note the ordering: we can safely lookup the task_rq without
+@@ -167,6 +170,44 @@
+ p->array = array;
+ }
+
++/*
++ * Modify the per task bonus with a bonus based on the CPU usage
++ * of all the user's tasks combined. This won't just redistribute
++ * the CPU more fairly between the users, it will also make the
++ * interactive tasks of a CPU-hogging user "feel slower", giving
++ * that user a good reason to not hog the system ;)
++ */
++static inline int peruser_bonus(int bonus, struct user_struct * user)
++{
++ int userbonus, i, max_cpu;
++
++ /*
++ * Decay the per-user cpu usage once for every STARVATION_LIMIT
++ * interval. We round up the number of intervals so we won't
++ * have to recalculate again immediately and always increment
++ * user->cpu_lastcalc with a multiple of STARVATION_LIMIT so
++ * we don't have different decay rates for users with different
++ * wakeup patterns.
++ */
++ if (time_after(jiffies, user->cpu_lastcalc + STARVATION_LIMIT)) {
++ i = ((jiffies - user->cpu_lastcalc) / STARVATION_LIMIT) + 1;
++ user->cpu_lastcalc += i * STARVATION_LIMIT;
++ user->cpu_time >>= i;
++ }
++
++ /*
++ * 0% cpu usage -> + BONUS
++ * 50% cpu usage -> 0
++ * 100% cpu usage -> - BONUS
++ */
++ max_cpu = smp_num_cpus * STARVATION_LIMIT * 3 / 4;
++
++ /**** FIXME ****/
++ userbonus = max_cpu - (user->cpu_time + 1)
++
++ return (bonus + userbonus) / 2;
++}
++
+ static inline int effective_prio(task_t *p)
+ {
+ int bonus, prio;
+@@ -185,6 +226,9 @@
+ bonus = MAX_USER_PRIO*PRIO_BONUS_RATIO*p->sleep_avg/MAX_SLEEP_AVG/100 -
+ MAX_USER_PRIO*PRIO_BONUS_RATIO/100/2;
+
++ if (fairsched_enabled)
++ bonus = peruser_bonus(bonus, p->user);
++
+ prio = p->static_prio - bonus;
+ if (prio < MAX_RT_PRIO)
+ prio = MAX_RT_PRIO;
+@@ -673,6 +717,9 @@
+ kstat.per_cpu_user[cpu] += user_tick;
+ kstat.per_cpu_system[cpu] += system;
+
++ if (fairsched_enabled && p->user)
++ p->user->cpu_time++;
++
+ /* Task might have expired already, but not scheduled off yet */
+ if (p->array != rq->active) {
+ set_tsk_need_resched(p);
+--- linux/kernel/user.c.user 2002-08-08 19:30:05.000000000 -0300
++++ linux/kernel/user.c 2002-08-08 19:40:43.000000000 -0300
+@@ -101,6 +101,8 @@
+ atomic_set(&new->__count, 1);
+ atomic_set(&new->processes, 0);
+ atomic_set(&new->files, 0);
++ new->cpu_time = 0;
++ new->cpu_lastcalc = jiffies;
+
+ /*
+ * Before adding this, check whether we raced
+--- linux/include/linux/sched.h.user 2002-08-08 11:53:28.000000000 -0300
++++ linux/include/linux/sched.h 2002-08-08 20:25:13.000000000 -0300
+@@ -80,6 +80,9 @@
+ extern unsigned long nr_running(void);
+ extern unsigned long nr_uninterruptible(void);
+
++/* Per-user fair scheduler on/off switch */
++extern int fairsched_enabled;
++
+ //#include <linux/fs.h>
+ #include <linux/time.h>
+ #include <linux/param.h>
+@@ -288,6 +291,14 @@
+ atomic_t processes; /* How many processes does this user have? */
+ atomic_t files; /* How many open files does this user have? */
+
++ /*
++ * Fair scheduler CPU usage counting. If the per-user fair scheduler
++ * is enabled, we keep track of how much CPU time this user is using,
++ * using a floating average.
++ */
++ unsigned long cpu_time;
++ unsigned long cpu_lastcalc;
++
+ /* Hash table maintenance information */
+ struct user_struct *next, **pprev;
+ uid_t uid;
diff --git a/patch_cmds/diffstat/testing/case17.ref b/patch_cmds/diffstat/testing/case17.ref
new file mode 100644
index 0000000..2d08606
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17.ref
@@ -0,0 +1,4 @@
+ include/linux/sched.h | 11 +++++++++++
+ kernel/sched.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/user.c | 2 ++
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case17R.ref b/patch_cmds/diffstat/testing/case17R.ref
new file mode 100644
index 0000000..e9d1af7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17R.ref
@@ -0,0 +1,4 @@
+ include/linux/sched.h.user | 11 ----------
+ kernel/sched.c.user | 47 ---------------------------------------------
+ kernel/user.c.user | 2 -
+ 3 files changed, 60 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case17Rp0.ref b/patch_cmds/diffstat/testing/case17Rp0.ref
new file mode 100644
index 0000000..d1f5725
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17Rp0.ref
@@ -0,0 +1,4 @@
+ linux/include/linux/sched.h.user | 11 ---------
+ linux/kernel/sched.c.user | 47 ---------------------------------------
+ linux/kernel/user.c.user | 2 -
+ 3 files changed, 60 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case17b.ref b/patch_cmds/diffstat/testing/case17b.ref
new file mode 100644
index 0000000..2d08606
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17b.ref
@@ -0,0 +1,4 @@
+ include/linux/sched.h | 11 +++++++++++
+ kernel/sched.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/user.c | 2 ++
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case17f0.ref b/patch_cmds/diffstat/testing/case17f0.ref
new file mode 100644
index 0000000..c5fc68e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17f0.ref
@@ -0,0 +1,4 @@
+ include/linux/sched.h | 11 11 + 0 - 0 !
+ kernel/sched.c | 47 47 + 0 - 0 !
+ kernel/user.c | 2 2 + 0 - 0 !
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case17k.ref b/patch_cmds/diffstat/testing/case17k.ref
new file mode 100644
index 0000000..2d08606
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17k.ref
@@ -0,0 +1,4 @@
+ include/linux/sched.h | 11 +++++++++++
+ kernel/sched.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/user.c | 2 ++
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case17p1.ref b/patch_cmds/diffstat/testing/case17p1.ref
new file mode 100644
index 0000000..2d08606
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17p1.ref
@@ -0,0 +1,4 @@
+ include/linux/sched.h | 11 +++++++++++
+ kernel/sched.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/user.c | 2 ++
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case17p9.ref b/patch_cmds/diffstat/testing/case17p9.ref
new file mode 100644
index 0000000..8fab6ab
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17p9.ref
@@ -0,0 +1,4 @@
+ sched.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ sched.h | 11 +++++++++++
+ user.c | 2 ++
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case17r1.ref b/patch_cmds/diffstat/testing/case17r1.ref
new file mode 100644
index 0000000..2d08606
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17r1.ref
@@ -0,0 +1,4 @@
+ include/linux/sched.h | 11 +++++++++++
+ kernel/sched.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/user.c | 2 ++
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case17r2.ref b/patch_cmds/diffstat/testing/case17r2.ref
new file mode 100644
index 0000000..2d08606
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17r2.ref
@@ -0,0 +1,4 @@
+ include/linux/sched.h | 11 +++++++++++
+ kernel/sched.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/user.c | 2 ++
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case17u.ref b/patch_cmds/diffstat/testing/case17u.ref
new file mode 100644
index 0000000..c832b99
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case17u.ref
@@ -0,0 +1,4 @@
+ kernel/sched.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/user.c | 2 ++
+ include/linux/sched.h | 11 +++++++++++
+ 3 files changed, 60 insertions(+)
diff --git a/patch_cmds/diffstat/testing/case18.pat b/patch_cmds/diffstat/testing/case18.pat
new file mode 100644
index 0000000..42111ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18.pat
@@ -0,0 +1,7 @@
+diff -urN tst/foo tst.new/foo
+--- tst/foo 2002-11-27 17:21:54.000000000 +0200
++++ tst.new/foo 2002-11-27 17:22:00.000000000 +0200
+@@ -1,3 +1,2 @@
+ lalala
+--- ALWAYS!</b>:
+ foobar
diff --git a/patch_cmds/diffstat/testing/case18.ref b/patch_cmds/diffstat/testing/case18.ref
new file mode 100644
index 0000000..60a4d2b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18.ref
@@ -0,0 +1,2 @@
+ foo | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case18R.ref b/patch_cmds/diffstat/testing/case18R.ref
new file mode 100644
index 0000000..14aa1f7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18R.ref
@@ -0,0 +1,2 @@
+ foo | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case18Rp0.ref b/patch_cmds/diffstat/testing/case18Rp0.ref
new file mode 100644
index 0000000..e98fad1
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18Rp0.ref
@@ -0,0 +1,2 @@
+ tst/foo | 1 +
+ 1 file changed, 1 insertion(+)
diff --git a/patch_cmds/diffstat/testing/case18b.ref b/patch_cmds/diffstat/testing/case18b.ref
new file mode 100644
index 0000000..60a4d2b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18b.ref
@@ -0,0 +1,2 @@
+ foo | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case18f0.ref b/patch_cmds/diffstat/testing/case18f0.ref
new file mode 100644
index 0000000..ad90571
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18f0.ref
@@ -0,0 +1,2 @@
+ foo | 1 0 + 1 - 0 !
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case18k.ref b/patch_cmds/diffstat/testing/case18k.ref
new file mode 100644
index 0000000..60a4d2b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18k.ref
@@ -0,0 +1,2 @@
+ foo | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case18p1.ref b/patch_cmds/diffstat/testing/case18p1.ref
new file mode 100644
index 0000000..60a4d2b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18p1.ref
@@ -0,0 +1,2 @@
+ foo | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case18p9.ref b/patch_cmds/diffstat/testing/case18p9.ref
new file mode 100644
index 0000000..60a4d2b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18p9.ref
@@ -0,0 +1,2 @@
+ foo | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case18r1.ref b/patch_cmds/diffstat/testing/case18r1.ref
new file mode 100644
index 0000000..60a4d2b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18r1.ref
@@ -0,0 +1,2 @@
+ foo | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case18r2.ref b/patch_cmds/diffstat/testing/case18r2.ref
new file mode 100644
index 0000000..60a4d2b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18r2.ref
@@ -0,0 +1,2 @@
+ foo | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case18u.ref b/patch_cmds/diffstat/testing/case18u.ref
new file mode 100644
index 0000000..60a4d2b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case18u.ref
@@ -0,0 +1,2 @@
+ foo | 1 -
+ 1 file changed, 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case19.pat b/patch_cmds/diffstat/testing/case19.pat
new file mode 100644
index 0000000..dc7e362
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19.pat
@@ -0,0 +1,14 @@
+--- data.old Sat Jan 4 13:26:04 2003
++++ data.new Sat Jan 4 13:27:20 2003
+@@ -1,5 +1,8 @@
+ -Readme file for DiffStat.
+ -
+--This program is a simple filter that reads the output of the 'diff' program,
+--- and produces a histogram of the total number of lines that were changed. It is
+-useful for scanning a patch file to see which files were changed.
++-This program is
++- a simple filter that reads the output of the 'diff' program,
++++ and produces a histogram
++- of the total number of lines that were changed. It is
++++ useful
+++ for scanning a patch file to see which files were changed.
diff --git a/patch_cmds/diffstat/testing/case19.ref b/patch_cmds/diffstat/testing/case19.ref
new file mode 100644
index 0000000..14976e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19.ref
@@ -0,0 +1,2 @@
+ data.new | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19R.ref b/patch_cmds/diffstat/testing/case19R.ref
new file mode 100644
index 0000000..d3fb950
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19R.ref
@@ -0,0 +1,2 @@
+ data.old | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19Rp0.ref b/patch_cmds/diffstat/testing/case19Rp0.ref
new file mode 100644
index 0000000..d3fb950
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19Rp0.ref
@@ -0,0 +1,2 @@
+ data.old | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19b.ref b/patch_cmds/diffstat/testing/case19b.ref
new file mode 100644
index 0000000..14976e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19b.ref
@@ -0,0 +1,2 @@
+ data.new | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19f0.ref b/patch_cmds/diffstat/testing/case19f0.ref
new file mode 100644
index 0000000..2413833
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19f0.ref
@@ -0,0 +1,2 @@
+ data.new | 9 6 + 3 - 0 !
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19k.ref b/patch_cmds/diffstat/testing/case19k.ref
new file mode 100644
index 0000000..14976e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19k.ref
@@ -0,0 +1,2 @@
+ data.new | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19p1.ref b/patch_cmds/diffstat/testing/case19p1.ref
new file mode 100644
index 0000000..14976e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19p1.ref
@@ -0,0 +1,2 @@
+ data.new | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19p9.ref b/patch_cmds/diffstat/testing/case19p9.ref
new file mode 100644
index 0000000..14976e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19p9.ref
@@ -0,0 +1,2 @@
+ data.new | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19r1.ref b/patch_cmds/diffstat/testing/case19r1.ref
new file mode 100644
index 0000000..14976e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19r1.ref
@@ -0,0 +1,2 @@
+ data.new | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19r2.ref b/patch_cmds/diffstat/testing/case19r2.ref
new file mode 100644
index 0000000..14976e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19r2.ref
@@ -0,0 +1,2 @@
+ data.new | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case19u.ref b/patch_cmds/diffstat/testing/case19u.ref
new file mode 100644
index 0000000..14976e9
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case19u.ref
@@ -0,0 +1,2 @@
+ data.new | 9 ++++++---
+ 1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case20.pat b/patch_cmds/diffstat/testing/case20.pat
new file mode 100644
index 0000000..b132730
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20.pat
@@ -0,0 +1,111 @@
+diff -c 'vile-9.3+/README' 'vile-9.3j+/README'
+Index: ./README
+Prereq: 1.88
+*** ./README Tue Jun 25 20:25:57 2002
+--- ./README Sun Jun 30 16:27:52 2002
+***************
+*** 23,41 ****
+ impatient? just type "./configure; make", and get a cup of coffee, decaf
+ if necessary.
+
+ want X11 support? you'd better look at doc/config.doc, although
+ "./configure --with-screen=x11"; make" may well do what you want.
+
+ want PC support? look for precompiled binaries at the various ftp sites.
+
+ want to build vile on a PC host? refer to the file README.PC .
+
+! want VMS support? you'll need to build vile yourself. refer to the
+! file README.VMS .
+!
+! if you like vile, and wish to be informed of new releases, let me
+! know -- i maintain a mailing list for that purpose. don't worry -- the
+! volume won't fill your inbox.
+
+ paul fox, pgf@foxharp.boston.ma.us (original author)
+ kevin buettner, kev@primenet.com
+--- 23,49 ----
+ impatient? just type "./configure; make", and get a cup of coffee, decaf
+ if necessary.
+
++ want to know more about configure options? type "./configure --help"
++ and then read doc/config.doc for further details.
++
+ want X11 support? you'd better look at doc/config.doc, although
+ "./configure --with-screen=x11"; make" may well do what you want.
+
++ want syntax coloring? add "--with-builtin-filters" to your configure
++ options and then read the topics "Color basics" and "Syntax coloring" in
++ the file vile.hlp.
++
+ want PC support? look for precompiled binaries at the various ftp sites.
+
+ want to build vile on a PC host? refer to the file README.PC .
+
+! want VMS support? some precompiled binaries are available at
+! ftp://ftp.phred.org/pub/vile. otherwise, you'll need to build vile
+! yourself. In either case, refer to the file README.VMS .
+!
+! if you like vile, and wish to be informed of new releases, let me know -- i
+! maintain a mailing list for that purpose (scroll down a bit for details).
+! don't worry -- the volume won't fill your inbox.
+
+ paul fox, pgf@foxharp.boston.ma.us (original author)
+ kevin buettner, kev@primenet.com
+***************
+*** 628,632 ****
+ + add $prompt variable, to allow changing the command-line prompt.
+
+ -------------------------------
+! @Header: /users/tom/src/diffstat/testing/RCS/case20.pat,v 1.1 2003/01/04 18:59:35 tom Exp @
+ -------------------------------
+--- 636,640 ----
+ + add $prompt variable, to allow changing the command-line prompt.
+
+ -------------------------------
+! @Header: /users/tom/src/diffstat/testing/RCS/case20.pat,v 1.1 2003/01/04 18:59:35 tom Exp @
+ -------------------------------
+diff -c 'vile-9.3+/README.PC' 'vile-9.3j+/README.PC'
+Index: ./README.PC
+Prereq: 1.29
+*** ./README.PC Tue Jun 25 20:25:57 2002
+--- ./README.PC Sun Jun 30 16:27:52 2002
+***************
+*** 198,208 ****
+ install it in a directory located in your PATH and add the following
+ command-line option:
+
+! nmake -f makefile.wnt <OPTIONS_FROM_ABOVE> LEX=flex # or LEX=lex
+
+ take note that flex is a component of cygwin's GNU emulation package
+ and works quite well for this purpose. cygwin can be obtained from
+! Redhat at http://sources.redhat.com/cygwin.
+
+ [2] this option requires prior installation of perl. refer to the section
+ entitled "Perl preconditions" below.
+--- 198,209 ----
+ install it in a directory located in your PATH and add the following
+ command-line option:
+
+! nmake -f makefile.wnt <OPTIONS_FROM_ABOVE> FLT=1 LEX=flex # or LEX=lex
+
+ take note that flex is a component of cygwin's GNU emulation package
+ and works quite well for this purpose. cygwin can be obtained from
+! Redhat at http://sources.redhat.com/cygwin. the FLT option binds
+! all syntax coloring filters into the resultant [win]vile executable.
+
+ [2] this option requires prior installation of perl. refer to the section
+ entitled "Perl preconditions" below.
+***************
+*** 263,267 ****
+ paul fox, pgf@foxharp.boston.ma.us (home)
+
+ ------------------------
+! @Header: /users/tom/src/diffstat/testing/RCS/case20.pat,v 1.1 2003/01/04 18:59:35 tom Exp @
+ ------------------------
+--- 264,268 ----
+ paul fox, pgf@foxharp.boston.ma.us (home)
+
+ ------------------------
+! @Header: /users/tom/src/diffstat/testing/RCS/case20.pat,v 1.1 2003/01/04 18:59:35 tom Exp @
+ ------------------------
diff --git a/patch_cmds/diffstat/testing/case20.ref b/patch_cmds/diffstat/testing/case20.ref
new file mode 100644
index 0000000..4c948ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20.ref
@@ -0,0 +1,3 @@
+ README | 22 +++++++!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20R.ref b/patch_cmds/diffstat/testing/case20R.ref
new file mode 100644
index 0000000..fdf305d
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20R.ref
@@ -0,0 +1,3 @@
+ README | 22 -------!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 deletions(-), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20Rp0.ref b/patch_cmds/diffstat/testing/case20Rp0.ref
new file mode 100644
index 0000000..e1fb657
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20Rp0.ref
@@ -0,0 +1,3 @@
+ vile-9.3+/README | 22 -------!!!!!!!!!!!!!!!
+ vile-9.3+/README.PC | 7 !!!!!!!
+ 2 files changed, 7 deletions(-), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20b.ref b/patch_cmds/diffstat/testing/case20b.ref
new file mode 100644
index 0000000..4c948ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20b.ref
@@ -0,0 +1,3 @@
+ README | 22 +++++++!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20f0.ref b/patch_cmds/diffstat/testing/case20f0.ref
new file mode 100644
index 0000000..9d74623
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20f0.ref
@@ -0,0 +1,3 @@
+ README | 22 7 + 0 - 15 !
+ README.PC | 7 0 + 0 - 7 !
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20k.ref b/patch_cmds/diffstat/testing/case20k.ref
new file mode 100644
index 0000000..4c948ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20k.ref
@@ -0,0 +1,3 @@
+ README | 22 +++++++!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20p1.ref b/patch_cmds/diffstat/testing/case20p1.ref
new file mode 100644
index 0000000..4c948ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20p1.ref
@@ -0,0 +1,3 @@
+ README | 22 +++++++!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20p9.ref b/patch_cmds/diffstat/testing/case20p9.ref
new file mode 100644
index 0000000..4c948ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20p9.ref
@@ -0,0 +1,3 @@
+ README | 22 +++++++!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20r1.ref b/patch_cmds/diffstat/testing/case20r1.ref
new file mode 100644
index 0000000..4c948ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20r1.ref
@@ -0,0 +1,3 @@
+ README | 22 +++++++!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20r2.ref b/patch_cmds/diffstat/testing/case20r2.ref
new file mode 100644
index 0000000..4c948ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20r2.ref
@@ -0,0 +1,3 @@
+ README | 22 +++++++!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case20u.ref b/patch_cmds/diffstat/testing/case20u.ref
new file mode 100644
index 0000000..4c948ee
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case20u.ref
@@ -0,0 +1,3 @@
+ README | 22 +++++++!!!!!!!!!!!!!!!
+ README.PC | 7 !!!!!!!
+ 2 files changed, 7 insertions(+), 22 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21.pat b/patch_cmds/diffstat/testing/case21.pat
new file mode 100644
index 0000000..2ff04a5
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21.pat
@@ -0,0 +1,74 @@
+# remove duplicated files when reading applypatch input
+#
+# To apply this patch:
+# STEP 1: Chdir to the source directory.
+# STEP 2: Run the 'applypatch' program with this patch file as input.
+#
+# If you do not have 'applypatch', it is part of the 'makepatch' package
+# that you can fetch from the Comprehensive Perl Archive Network:
+# http://www.perl.com/CPAN/authors/Johan_Vromans/makepatch-x.y.tar.gz
+# In the above URL, 'x' should be 2 or higher.
+#
+# To apply this patch without the use of 'applypatch':
+# STEP 1: Chdir to the source directory.
+# STEP 2: Run the 'patch' program with this file as input.
+#
+#### End of Preamble ####
+
+#### Patch data follows ####
+diff -c 'diffstat-1.31/diffstat.c' 'diffstat-1.31_applypatch/diffstat.c'
+Index: ./diffstat.c
+Prereq: 1.31
+*** ./diffstat.c Tue Aug 20 19:38:52 2002
+--- ./diffstat.c Sat Nov 9 22:54:12 2002
+***************
+*** 483,489 ****
+ if (match(buffer, "Index: ")) {
+ s = strrchr(buffer, BLANK); /* last token is name */
+ blip('.');
+! that = new_data(s + 1);
+ ok = begin_data(that);
+ }
+ break;
+--- 483,491 ----
+ if (match(buffer, "Index: ")) {
+ s = strrchr(buffer, BLANK); /* last token is name */
+ blip('.');
+! if (strlen(that->name) != 0)
+! s = do_merging(that, s + 1);
+! that = new_data(s);
+ ok = begin_data(that);
+ }
+ break;
+***************
+*** 493,499 ****
+ && *(s = skip_options(buffer + 5)) != '\0') {
+ s = strrchr(buffer, BLANK);
+ blip('.');
+! that = new_data(s + 1);
+ ok = begin_data(that);
+ }
+ break;
+--- 495,503 ----
+ && *(s = skip_options(buffer + 5)) != '\0') {
+ s = strrchr(buffer, BLANK);
+ blip('.');
+! if (strlen(that->name) != 0)
+! s = do_merging(that, s + 1);
+! that = new_data(s);
+ ok = begin_data(that);
+ }
+ break;
+#### End of Patch data ####
+
+#### ApplyPatch data follows ####
+# Data version : 1.0
+# Date generated : Sat Nov 9 22:55:16 2002
+# Generated by : makepatch 2.00_05
+# Recurse directories : Yes
+# p 'diffstat.c' 21017 1036900452 0100644
+#### End of ApplyPatch data ####
+
+#### End of Patch kit [created: Sat Nov 9 22:55:16 2002] ####
+#### Patch checksum: 55 1528 36697 ####
+#### Checksum: 73 2205 27936 ####
diff --git a/patch_cmds/diffstat/testing/case21.ref b/patch_cmds/diffstat/testing/case21.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21R.ref b/patch_cmds/diffstat/testing/case21R.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21R.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21Rp0.ref b/patch_cmds/diffstat/testing/case21Rp0.ref
new file mode 100644
index 0000000..32019b3
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21Rp0.ref
@@ -0,0 +1,2 @@
+ diffstat-1.31/diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21b.ref b/patch_cmds/diffstat/testing/case21b.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21b.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21f0.ref b/patch_cmds/diffstat/testing/case21f0.ref
new file mode 100644
index 0000000..c5e255c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21f0.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 0 + 0 - 8 !
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21k.ref b/patch_cmds/diffstat/testing/case21k.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21k.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21p1.ref b/patch_cmds/diffstat/testing/case21p1.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21p1.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21p9.ref b/patch_cmds/diffstat/testing/case21p9.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21p9.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21r1.ref b/patch_cmds/diffstat/testing/case21r1.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21r1.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21r2.ref b/patch_cmds/diffstat/testing/case21r2.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21r2.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case21u.ref b/patch_cmds/diffstat/testing/case21u.ref
new file mode 100644
index 0000000..5c225f6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case21u.ref
@@ -0,0 +1,2 @@
+ diffstat.c | 8 !!!!!!!!
+ 1 file changed, 8 modifications(!)
diff --git a/patch_cmds/diffstat/testing/case22.pat b/patch_cmds/diffstat/testing/case22.pat
new file mode 100644
index 0000000..773ff0b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22.pat
@@ -0,0 +1,651 @@
+--- pgp-menu-traditional/PATCHES Dec 2002 17:44:54 -0000 3.6
++++ pgp-menu-traditional/PATCHES Feb 2003 11:26:39 -0000
+@@ -0,0 +1 @@
++patch-1.5.3.dw.pgp-menu-traditional.1
+--- pgp-menu-traditional/compose.c Dec 2002 11:19:39 -0000 3.8
++++ pgp-menu-traditional/compose.c Feb 2003 11:26:42 -0000
+@@ -145,2 +145,6 @@ static void redraw_crypt_lines (HEADER *
+ addstr (_("Clear"));
++#ifdef HAVE_PGP
++ if ((msg->security & PGPINLINE) == PGPINLINE)
++ addstr (_(" (inline)"));
++#endif
+ clrtoeol ();
+@@ -174,4 +178,4 @@ static int pgp_send_menu (HEADER *msg, i
+
+- switch (mutt_multi_choice (_("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "),
+- _("esabf")))
++ switch (mutt_multi_choice (_("PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline or (f)orget it? "),
++ _("esabtf")))
+ {
+@@ -208,6 +212,11 @@ static int pgp_send_menu (HEADER *msg, i
+ case 4: /* (b)oth */
+- msg->security = PGPENCRYPT | PGPSIGN;
++ msg->security |= PGPENCRYPT | PGPSIGN;
+ break;
+
+- case 5: /* (f)orget it */
++ case 5: /* (t)raditional inline */
++ if (msg->security & (ENCRYPT | SIGN))
++ msg->security |= PGPINLINE; /* should this be a toggle instead */
++ break;
++
++ case 6: /* (f)orget it */
+ msg->security = 0;
+--- pgp-menu-traditional/crypt.c Dec 2002 22:23:42 -0000 3.11
++++ pgp-menu-traditional/crypt.c Feb 2003 11:26:43 -0000
+@@ -172,3 +172,2 @@ int mutt_protect (HEADER *msg, char *key
+ BODY *tmp_pgp_pbody = NULL;
+- int traditional = 0;
+ int flags = msg->security, i;
+@@ -179,18 +178,9 @@ int mutt_protect (HEADER *msg, char *key
+ #ifdef HAVE_PGP
+- if (msg->security & APPLICATION_PGP)
++ if ((msg->security & PGPINLINE) == PGPINLINE)
+ {
+- if ((msg->content->type == TYPETEXT) &&
+- !ascii_strcasecmp (msg->content->subtype, "plain"))
+- {
+- if ((i = query_quadoption (OPT_PGPTRADITIONAL, _("Create an inline PGP message?"))) == -1)
+- return -1;
+- else if (i == M_YES)
+- traditional = 1;
+- }
+- if (traditional)
++ /* they really want to send it inline... go for it */
++ if (!isendwin ()) mutt_endwin _("Invoking PGP...");
++ pbody = pgp_traditional_encryptsign (msg->content, flags, keylist);
++ if (pbody)
+ {
+- if (!isendwin ()) mutt_endwin _("Invoking PGP...");
+- if (!(pbody = pgp_traditional_encryptsign (msg->content, flags, keylist)))
+- return -1;
+-
+ msg->content = pbody;
+@@ -198,2 +188,8 @@ int mutt_protect (HEADER *msg, char *key
+ }
++
++ /* otherwise inline won't work...ask for revert */
++ if ((i = query_quadoption (OPT_PGPMIMEASK, _("Message can't be sent inline. Revert to using PGP/MIME?"))) != M_YES)
++ return -1;
++
++ /* go ahead with PGP/MIME */
+ }
+--- pgp-menu-traditional/init.h Dec 2002 18:09:49 -0000 3.28
++++ pgp-menu-traditional/init.h Feb 2003 11:26:48 -0000
+@@ -1352,2 +1352,44 @@ struct option_t MuttVars[] = {
+ */
++ { "pgp_create_traditional", DT_SYN, R_NONE, UL "pgp_autoinline", 0 },
++ { "pgp_autoinline", DT_BOOL, R_NONE, OPTPGPAUTOINLINE, 0 },
++ /*
++ ** .pp
++ ** This option controls whether Mutt generates old-style inline
++ ** (traditional) PGP encrypted or signed messages under certain
++ ** circumstances. This can be overridden by use of the \fIpgp-menu\fP,
++ ** when inline is not required.
++ ** .pp
++ ** Note that Mutt might automatically use PGP/MIME for messages
++ ** which consist of more than a single MIME part. Mutt can be
++ ** configured to ask before sending PGP/MIME messages when inline
++ ** (traditional) would not work.
++ ** See also: ``$$pgp_mime_ask''.
++ ** .pp
++ ** Also note that using the old-style PGP message format is \fBstrongly\fP
++ ** \fBdeprecated\fP.
++ ** (PGP only)
++ */
++ { "pgp_auto_traditional", DT_SYN, R_NONE, UL "pgp_replyinline", 0 },
++ { "pgp_replyinline", DT_BOOL, R_NONE, OPTPGPREPLYINLINE, 0 },
++ /*
++ ** .pp
++ ** Setting this variable will cause Mutt to always attempt to
++ ** create an inline (traditional) message when replying to a
++ ** message which is PGP encrypted/signed inline. This can be
++ ** overridden by use of the \fIpgp-menu\fP, when inline is not
++ ** required. This option does not automatically detect if the
++ ** (replied-to) message is inline; instead it relies on Mutt
++ ** internals for previously checked/flagged messages.
++ ** .pp
++ ** Note that Mutt might automatically use PGP/MIME for messages
++ ** which consist of more than a single MIME part. Mutt can be
++ ** configured to ask before sending PGP/MIME messages when inline
++ ** (traditional) would not work.
++ ** See also: ``$$pgp_mime_ask''.
++ ** .pp
++ ** Also note that using the old-style PGP message format is \fBstrongly\fP
++ ** \fBdeprecated\fP.
++ ** (PGP only)
++ **
++ */
+ { "pgp_show_unusable", DT_BOOL, R_NONE, OPTPGPSHOWUNUSABLE, 1 },
+@@ -1396,11 +1438,8 @@ struct option_t MuttVars[] = {
+ */
+- { "pgp_create_traditional", DT_QUAD, R_NONE, OPT_PGPTRADITIONAL, M_NO },
++ { "pgp_mime_ask", DT_QUAD, R_NONE, OPT_PGPMIMEASK, M_NO },
+ /*
+ ** .pp
+- ** This option controls whether Mutt generates old-style PGP encrypted
+- ** or signed messages under certain circumstances.
+- ** .pp
+- ** Note that PGP/MIME will be used automatically for messages which have
+- ** a character set different from us-ascii, or which consist of more than
+- ** a single MIME part.
++ ** This option controls whether Mutt will prompt you for
++ ** automatically sending a (signed/encrypted) message using
++ ** PGP/MIME when inline (traditional) fails (for any reason).
+ ** .pp
+@@ -1409,2 +1448,3 @@ struct option_t MuttVars[] = {
+ */
++
+
+--- pgp-menu-traditional/mutt.h Dec 2002 08:53:21 -0000 3.12
++++ pgp-menu-traditional/mutt.h Feb 2003 11:26:51 -0000
+@@ -270,3 +270,3 @@ enum
+ #ifdef HAVE_PGP
+- OPT_PGPTRADITIONAL, /* create old-style PGP messages */
++ OPT_PGPMIMEASK, /* ask to revert to PGP/MIME when inline fails */
+ #endif
+@@ -447,2 +447,4 @@ enum
+ OPTPGPLONGIDS,
++ OPTPGPAUTOINLINE,
++ OPTPGPREPLYINLINE,
+ #endif
+--- pgp-menu-traditional/pgp.c Dec 2002 17:59:51 -0000 3.18
++++ pgp-menu-traditional/pgp.c Feb 2003 11:26:55 -0000
+@@ -535,2 +535,5 @@ int mutt_is_application_pgp (BODY *m)
+ }
++ if (t)
++ t |= PGPINLINE;
++
+ return t;
+@@ -1057,3 +1060,3 @@ char *pgp_findKeys (ADDRESS *to, ADDRESS
+ int i;
+- pgp_key_t *k_info, *key;
++ pgp_key_t *k_info, *key = NULL;
+
+--- pgp-menu-traditional/pgplib.h Dec 2002 11:19:40 -0000 3.3
++++ pgp-menu-traditional/pgplib.h Feb 2003 11:26:56 -0000
+@@ -27,2 +27,3 @@
+ #define PGPKEY (APPLICATION_PGP | (1 << 3))
++#define PGPINLINE (APPLICATION_PGP | (1 << 4))
+
+--- pgp-menu-traditional/postpone.c Dec 2002 11:19:40 -0000 3.7
++++ pgp-menu-traditional/postpone.c Feb 2003 11:26:57 -0000
+@@ -492,2 +492,9 @@ int mutt_parse_crypt_hdr (char *p, int s
+
++ case 'i':
++ case 'I':
++#ifdef HAVE_PGP
++ pgp |= (PGPINLINE & ~APPLICATION_PGP);
++#endif
++ break;
++
+ default:
+--- pgp-menu-traditional/send.c Dec 2002 22:47:57 -0000 3.15
++++ pgp-menu-traditional/send.c Feb 2003 11:27:01 -0000
+@@ -1259,3 +1259,3 @@ ci_send_message (int flags, /* send mod
+ msg->security |= SIGN;
+- }
++ }
+
+@@ -1279,2 +1279,8 @@ ci_send_message (int flags, /* send mod
+ msg->security |= APPLICATION_PGP;
++ /*
++ * we leave this so late because PGPINLINE should be applied only when APPLICATION_PGP is high
++ * perhaps reserving a bit in crypt.h would be more reasonable, though it doesn't apply with S/MIME
++ */
++ if (option (OPTPGPREPLYINLINE) && (cur->security & PGPINLINE) == PGPINLINE)
++ msg->security |= PGPINLINE;
+ #endif /* HAVE_PGP */
+@@ -1294,2 +1300,10 @@ ci_send_message (int flags, /* send mod
+ }
++#ifdef HAVE_PGP
++ /*
++ * we leave this so late because PGPINLINE should be applied only when APPLICATION_PGP is high
++ * perhaps reserving a bit in crypt.h would be more reasonable, though it doesn't apply with S/MIME
++ */
++ if ((msg->security & APPLICATION_PGP) && (option (OPTPGPAUTOINLINE)))
++ msg->security |= PGPINLINE;
++#endif
+ #endif /* HAVE_PGP || HAVE_SMIME */
+--- pgp-menu-traditional/sendlib.c Dec 2002 20:56:48 -0000 3.18
++++ pgp-menu-traditional/sendlib.c Feb 2003 11:27:02 -0000
+@@ -2429,2 +2429,4 @@ int mutt_write_fcc (const char *path, HE
+ }
++ if ((hdr->security & PGPINLINE) == PGPINLINE)
++ fputc ('I', msg->fp);
+ fputc ('\n', msg->fp);
+--- pgp-menu-traditional/po/ca.po Dec 2002 10:37:21 -0000 3.7
++++ pgp-menu-traditional/po/ca.po Feb 2003 11:27:19 -0000
+@@ -596,10 +596,10 @@ msgstr "Xifra"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "(x)ifra, (s)igna, s(i)gna com a, (a)mbdós, o en (c)lar? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "(x)ifra, (s)igna, s(i)gna com a, (a)mbdós, traditional en (l)ínia, o en (c)lar? "
+
+ # ivb (2001/11/19)
+-# ivb (x)ifra, (s)igna, s(i)gna com a, (a)mbdós, (c)lar
++# ivb (x)ifra, (s)igna, s(i)gna com a, (a)mbdós, traditional en (l)ínia, o en (c)lar
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "xsiac"
++msgid "esabtf"
++msgstr "xsialc"
+
+--- pgp-menu-traditional/po/cs.po Dec 2002 10:37:21 -0000 3.6
++++ pgp-menu-traditional/po/cs.po Feb 2003 11:27:20 -0000
+@@ -676,4 +676,4 @@ msgstr "Za¹ifrovat"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "(¹)ifrovat, (p)odepsat, podepsat (j)ako, (o)bojí, èi (n)ic?"
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "(¹)ifrovat, (p)odepsat, podepsat (j)ako, (o)bojí, (t)raditional/pøímý, èi (n)ic?"
+
+@@ -681,4 +681,4 @@ msgstr "(¹)ifrovat, (p)odepsat, podepsat
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "¹pjon"
++msgid "esabtf"
++msgstr "¹pjotn"
+
+--- pgp-menu-traditional/po/da.po Dec 2002 10:37:21 -0000 3.6
++++ pgp-menu-traditional/po/da.po Feb 2003 11:27:21 -0000
+@@ -566,8 +566,8 @@ msgstr "Kryptér"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "(k)ryptér, (u)nderskriv, underskriv (s)om, (b)egge, (i)ngen PGP"
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "(k)ryptér, (u)nderskriv, underskriv (s)om, (b)egge, (t)raditional integreret, (i)ngen PGP"
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "kusbi"
++msgid "esabtf"
++msgstr "kusbti"
+
+--- pgp-menu-traditional/po/de.po Dec 2002 10:37:21 -0000 3.7
++++ pgp-menu-traditional/po/de.po Feb 2003 11:27:22 -0000
+@@ -558,8 +558,8 @@ msgstr "Verschlüsseln mit: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP (v)erschl., (s)ign., sign. (a)ls, (b)eides, (k)ein PGP? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP (v)erschl., (s)ign., sign. (a)ls, (b)eides, (t)raditionelles Inline, (k)ein PGP? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "vsabk"
++msgid "esabtf"
++msgstr "vsabtk"
+
+--- pgp-menu-traditional/po/el.po Dec 2002 10:37:21 -0000 3.7
++++ pgp-menu-traditional/po/el.po Feb 2003 11:27:24 -0000
+@@ -690,4 +690,4 @@ msgstr "ÊñõðôïãñÜöçóç ìå: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, Þ (f)orget it? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional êåßìåíï, Þ (f)orget it? "
+
+@@ -696,4 +696,4 @@ msgstr "PGP (e)ncrypt, (s)ign, sign (a)s
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "esabf"
++msgid "esabtf"
++msgstr "esabtf"
+
+--- pgp-menu-traditional/po/eo.po Dec 2002 10:37:21 -0000 3.6
++++ pgp-menu-traditional/po/eo.po Feb 2003 11:27:25 -0000
+@@ -566,8 +566,8 @@ msgstr "Æifri"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "æ(i)fri, (s)ubskribi, subskribi (k)iel, (a)mbaý, aý (f)orgesi? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "æ(i)fri, (s)ubskribi, subskribi (k)iel, (a)mbaý, (t)raditional \"inline\", aý (f)orgesi? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "iskaf"
++msgid "esabtf"
++msgstr "iskatf"
+
+--- pgp-menu-traditional/po/es.po Dec 2002 10:37:22 -0000 3.7
++++ pgp-menu-traditional/po/es.po Feb 2003 11:27:26 -0000
+@@ -564,8 +564,9 @@ msgstr "Cifrar"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "¿co(d)ificar, f(i)rmar (c)omo, amb(o)s o ca(n)celar? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "¿co(d)ificar, f(i)rmar (c)omo, amb(o)s, (t)radicional incluido, o ca(n)celar? "
++
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "dicon"
++msgid "esabtf"
++msgstr "dicotn"
+
+--- pgp-menu-traditional/po/et.po Dec 2002 10:37:22 -0000 3.8
++++ pgp-menu-traditional/po/et.po Feb 2003 11:27:27 -0000
+@@ -559,7 +559,7 @@ msgstr "Krüpti kasutades: "
+ msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP (k)rüpti, (a)llkiri, allk. ku(i), (m)õlemad või (u)nusta? "
++msgstr "PGP (k)rüpti, (a)llkiri, allk. ku(i), (m)õlemad, (t)raditional kehasse, või (u)nusta? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "kaimu"
++msgid "esabtf"
++msgstr "kaimtu"
+
+--- pgp-menu-traditional/po/fr.po Dec 2002 10:37:22 -0000 3.13
++++ pgp-menu-traditional/po/fr.po Feb 2003 11:27:28 -0000
+@@ -585,8 +585,8 @@ msgstr "Chiffrer avec : "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "(c)hiffrer PGP, (s)igner, (e)n tant que, les (d)eux, ou (o)ublier ? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "(c)hiffrer PGP, (s)igner, (e)n tant que, les (d)eux, (t)raditionnel en ligne, ou (o)ublier ? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "csedo"
++msgid "esabtf"
++msgstr "csedto"
+
+--- pgp-menu-traditional/po/gl.po Dec 2002 10:37:22 -0000 3.6
++++ pgp-menu-traditional/po/gl.po Feb 2003 11:27:30 -0000
+@@ -568,8 +568,8 @@ msgstr "Encriptar"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "¿(e)ncriptar, (f)irmar, firmar (c)omo, (a)mbas ou (o)lvidar? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "¿(e)ncriptar, (f)irmar, firmar (c)omo, (a)mbas, (t)raditional interior, ou (o)lvidar? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "efcao"
++msgid "esabtf"
++msgstr "efcato"
+
+--- pgp-menu-traditional/po/hu.po Dec 2002 10:37:23 -0000 3.6
++++ pgp-menu-traditional/po/hu.po Feb 2003 11:27:31 -0000
+@@ -569,8 +569,8 @@ msgstr "Titkosít"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "(t)itkosít, (a)láír, aláír (m)int, titkosít é(s) aláír, mé(g)se? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "(t)itkosít, (a)láír, aláír (m)int, titkosít é(s) aláír, traditional (b)eágyazott, mé(g)se? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "tamsg"
++msgid "esabtf"
++msgstr "tamsbg"
+
+--- pgp-menu-traditional/po/id.po Dec 2002 10:37:23 -0000 3.7
++++ pgp-menu-traditional/po/id.po Feb 2003 11:27:33 -0000
+@@ -562,8 +562,8 @@ msgstr "Enkrip dengan: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP (e)nkrip, (t)andatangan, tandatangan (s)bg, ke(d)uanya, (b)atal? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP (e)nkrip, (t)andatangan, tandatangan (s)bg, ke(d)uanya, traditional (i)nline, (b)atal? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "etsdb"
++msgid "esabtf"
++msgstr "etsdib"
+
+--- pgp-menu-traditional/po/it.po Dec 2002 10:37:23 -0000 3.6
++++ pgp-menu-traditional/po/it.po Feb 2003 11:27:34 -0000
+@@ -570,8 +570,8 @@ msgstr "Crittografa"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "cifra(e), firma(s), firma come(a), entrambi(b), annulla(f) "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "cifra(e), firma(s), firma come(a), entrambi(b), (t)radizionale in linea , annulla(f) "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "esabf"
++msgid "esabtf"
++msgstr "esabtf"
+
+--- pgp-menu-traditional/po/ja.po Dec 2002 10:37:23 -0000 3.13
++++ pgp-menu-traditional/po/ja.po Feb 2003 11:27:35 -0000
+@@ -558,8 +558,9 @@ msgstr " °Å¹æ²½Êý¼°: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP (e)°Å¹æ²½,(s)½ð̾,(a)..¤È¤·¤Æ½ð̾,(b)ξ¼Ô,(f)²ò½ü?"
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP (e)°Å¹æ²½,(s)½ð̾,(a)..¤È¤·¤Æ½ð̾,(b)ξ¼Ô,(i)nline,(f)²ò½ü?"
++
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr ""
++msgid "esabtf"
++msgstr "esabif"
+
+--- pgp-menu-traditional/po/ko.po Dec 2002 10:37:23 -0000 3.9
++++ pgp-menu-traditional/po/ko.po Feb 2003 11:27:36 -0000
+@@ -560,8 +560,8 @@ msgstr "¾Ïȣȭ ¹æ½Ä: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP ¾Ïȣȭ(e), ¼­¸í(s), »ç¿ë ¼­¸í(a), µÑ ´Ù(b), Ãë¼Ò(f)? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP ¾Ïȣȭ(e), ¼­¸í(s), »ç¿ë ¼­¸í(a), µÑ ´Ù(b), (i)nline, Ãë¼Ò(f)? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "esabf"
++msgid "esabtf"
++msgstr "esabif"
+
+--- pgp-menu-traditional/po/lt.po Dec 2002 10:37:23 -0000 3.6
++++ pgp-menu-traditional/po/lt.po Feb 2003 11:27:38 -0000
+@@ -566,5 +566,5 @@ msgstr "Uþðifruoti"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
+ msgstr ""
+-"(u)þðifruot, pa(s)iraðyt, pasiraðyt k(a)ip, a(b)u, rinktis (m)ic algoritmà, "
++"(u)þðifruot, pa(s)iraðyt, pasiraðyt k(a)ip, a(b)u, traditional (l)aiðke, "
+ "ar (p)amirðti?"
+@@ -573,4 +573,4 @@ msgstr ""
+ #, fuzzy
+-msgid "esabf"
+-msgstr "usabmp"
++msgid "esabtf"
++msgstr "usablp"
+
+@@ -586,4 +586,3 @@ msgid ""
+ msgstr ""
+-"(u)þðifruot, pa(s)iraðyt, pasiraðyt k(a)ip, a(b)u, rinktis (m)ic algoritmà, "
+-"ar (p)amirðti?"
++"(u)þðifruot, pa(s)iraðyt, uþðifruo(t) su, pasiraðyt k(a)ip, a(b)u, ar (p)amirðti?"
+
+@@ -592,3 +591,3 @@ msgstr ""
+ msgid "eswabf"
+-msgstr "usabmp"
++msgstr "ustabp"
+
+--- pgp-menu-traditional/po/nl.po Dec 2002 10:37:23 -0000 3.7
++++ pgp-menu-traditional/po/nl.po Feb 2003 11:27:39 -0000
+@@ -553,8 +553,8 @@ msgstr "Versleutelen met: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP (v)ersleutel, (o)ndertekenen, ondert. (a)ls, (b)eide, (g)een? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP (v)ersleutel, (o)ndertekenen, ondert. (a)ls, (b)eide, (t)raditioneel bericht, (g)een? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "voabg"
++msgid "esabtf"
++msgstr "voabtg"
+
+--- pgp-menu-traditional/po/pl.po Dec 2002 10:37:23 -0000 3.8
++++ pgp-menu-traditional/po/pl.po Feb 2003 11:27:40 -0000
+@@ -560,8 +560,8 @@ msgstr "Zaszyfruj u¿ywaj±c: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP (z)aszyfruj, podpi(s)z, podpisz j(a)ko, o(b)a, b(e)z PGP? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP (z)aszyfruj, podpi(s)z, podpisz j(a)ko, o(b)a, (t)raditional inline, b(e)z PGP? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "zsabe"
++msgid "esabtf"
++msgstr "zsabte"
+
+--- pgp-menu-traditional/po/pt_BR.po Dec 2002 10:37:23 -0000 3.7
++++ pgp-menu-traditional/po/pt_BR.po Feb 2003 11:27:41 -0000
+@@ -569,5 +569,5 @@ msgstr "Encriptar"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
+ msgstr ""
+-"(e)ncripa, a(s)sina, assina (c)omo, (a)mbos, escolhe (m)ic, ou es(q)uece? "
++"(e)ncripa, a(s)sina, assina (c)omo, (a)mbos, (t)raditional em (l)inha, ou es(q)uece? "
+
+@@ -575,4 +575,4 @@ msgstr ""
+ #, fuzzy
+-msgid "esabf"
+-msgstr "escamq"
++msgid "esabtf"
++msgstr "escalq"
+
+@@ -588,3 +588,3 @@ msgid ""
+ msgstr ""
+-"(e)ncripa, a(s)sina, assina (c)omo, (a)mbos, escolhe (m)ic, ou es(q)uece? "
++"(e)ncripa, a(s)sina, e(n)cripa com, assina (c)omo, (a)mbos, ou es(q)uece? "
+
+@@ -593,3 +593,3 @@ msgstr ""
+ msgid "eswabf"
+-msgstr "escamq"
++msgstr "esncaq"
+
+--- pgp-menu-traditional/po/ru.po Dec 2002 10:37:24 -0000 3.10
++++ pgp-menu-traditional/po/ru.po Feb 2003 11:27:43 -0000
+@@ -567,8 +567,8 @@ msgstr "úÁÛÉÆÒÏ×ÁÔØ: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP (e)ÛÉÆÒ, (s)ÐÏÄÐÉÓØ, (a)ÐÏÄÐÉÓØ ËÁË, (b)ÏÂÁ, (f)ÏÔËÁÚÁÔØÓÑ? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP (e)ÛÉÆÒ, (s)ÐÏÄÐÉÓØ, (a)ÐÏÄÐÉÓØ ËÁË, (b)ÏÂÁ, traditional (i)nline, (f)ÏÔËÁÚÁÔØÓÑ? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "esabf"
++msgid "esabtf"
++msgstr "esabif"
+
+--- pgp-menu-traditional/po/sk.po Dec 2002 10:37:24 -0000 3.6
++++ pgp-menu-traditional/po/sk.po Feb 2003 11:27:44 -0000
+@@ -574,5 +574,5 @@ msgstr "Za¹ifruj"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
+ msgstr ""
+-"(e)-¹ifr, (s)-podp, podp (a)ko, o(b)e, oznaè alg. mi(c), alebo (f)-zabudnú» "
++"(e)-¹ifr, (s)-podp, podp (a)ko, o(b)e, (t)raditional inline, alebo (f)-zabudnú» "
+ "na to? "
+@@ -581,4 +581,4 @@ msgstr ""
+ #, fuzzy
+-msgid "esabf"
+-msgstr "esabmf"
++msgid "esabtf"
++msgstr "esabtf"
+
+@@ -594,4 +594,3 @@ msgid ""
+ msgstr ""
+-"(e)-¹ifr, (s)-podp, podp (a)ko, o(b)e, oznaè alg. mi(c), alebo (f)-zabudnú» "
+-"na to? "
++"(e)-¹ifr, (s)-podp, (w)-¹ifr s, podp (a)ko, o(b)e, alebo (f)-zabudnú» na to? "
+
+@@ -600,3 +599,3 @@ msgstr ""
+ msgid "eswabf"
+-msgstr "esabmf"
++msgstr "eswabf"
+
+--- pgp-menu-traditional/po/sv.po Dec 2002 10:37:24 -0000 3.7
++++ pgp-menu-traditional/po/sv.po Feb 2003 11:27:45 -0000
+@@ -555,8 +555,8 @@ msgstr "Kryptera med: "
+ #: compose.c:175
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "PGP: (k)ryptera, (s)ignera, signera s(o)m, (b)åda, eller sk(i)ppa det?"
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "PGP: (k)ryptera, (s)ignera, signera s(o)m, (b)åda, (t)raditional infogat, eller sk(i)ppa det?"
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "ksobi"
++msgid "esabtf"
++msgstr "ksobti"
+
+--- pgp-menu-traditional/po/tr.po Dec 2002 10:37:24 -0000 3.6
++++ pgp-menu-traditional/po/tr.po Feb 2003 11:27:47 -0000
+@@ -565,5 +565,5 @@ msgstr "Þifrele"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
+ msgstr ""
+-"þ(i)frele, i(m)zala, (f)arklý imzala, i(k)isi de, mi(c) algoritmini seç "
++"þ(i)frele, i(m)zala, (f)arklý imzala, i(k)isi de, (t)raditional inline, "
+ "yoksa i(p)talmý? "
+@@ -571,4 +571,4 @@ msgstr ""
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "imfkcp"
++msgid "esabtf"
++msgstr "imfktp"
+
+--- pgp-menu-traditional/po/uk.po Dec 2002 10:37:24 -0000 3.7
++++ pgp-menu-traditional/po/uk.po Feb 2003 11:27:48 -0000
+@@ -560,8 +560,8 @@ msgstr "ûÉÆÒÕ×ÁÎÎÑ"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
+-msgstr "ÛÉÆÒ.(e), ЦÄÐ.(s), ЦÄÐ. ÑË(a), ÕÓÅ(b) ÞÉ ×¦ÄͦÎÁ(f)? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
++msgstr "ÛÉÆÒ.(e), ЦÄÐ.(s), ЦÄÐ. ÑË(a), ÕÓÅ(b), traditional (i)nline ÞÉ ×¦ÄͦÎÁ(f)? "
+
+ #: compose.c:176
+-msgid "esabf"
+-msgstr ""
++msgid "esabtf"
++msgstr "esabif"
+
+--- pgp-menu-traditional/po/zh_CN.po Dec 2002 10:37:24 -0000 3.6
++++ pgp-menu-traditional/po/zh_CN.po Feb 2003 11:27:50 -0000
+@@ -573,5 +573,5 @@ msgstr "¼ÓÃÜ"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
+ msgstr ""
+-"(e)¼ÓÃÜ, (s)Ç©Ãû, (a)ÓñðµÄÉí·ÝÇ©, (b)Á½Õß½ÔÒª, Ñ¡Ôñ (m)ic ÑÝËã·¨ »ò (f)·Å"
++"(e)¼ÓÃÜ, (s)Ç©Ãû, (a)ÓñðµÄÉí·ÝÇ©, (b)Á½Õß½ÔÒª, (t)raditional inline, »ò (f)·Å"
+ "Æú£¿"
+@@ -579,3 +579,3 @@ msgstr ""
+ #: compose.c:176
+-msgid "esabf"
++msgid "esabtf"
+ msgstr ""
+--- pgp-menu-traditional/po/zh_TW.po Dec 2002 10:37:24 -0000 3.6
++++ pgp-menu-traditional/po/zh_TW.po Feb 2003 11:27:51 -0000
+@@ -565,3 +565,3 @@ msgstr "加密"
+ #, fuzzy
+-msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, or (f)orget it? "
++msgid "PGP (e)ncrypt, (s)ign, sign (a)s, (b)oth, (t)raditional inline, or (f)orget it? "
+ msgstr "(1)加密, (2)ç°½å, (3)用別的身份簽, (4)兩者皆è¦, 或 (5)放棄?"
+@@ -569,4 +569,4 @@ msgstr "(1)加密, (2)ç°½å, (3)用別ç
+ #: compose.c:176
+-msgid "esabf"
+-msgstr "12345"
++msgid "esabtf"
++msgstr "1234t5"
+
diff --git a/patch_cmds/diffstat/testing/case22.ref b/patch_cmds/diffstat/testing/case22.ref
new file mode 100644
index 0000000..0cb180f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 +
+ compose.c | 17 +++++++++++++----
+ crypt.c | 26 +++++++++++---------------
+ init.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ mutt.h | 4 +++-
+ pgp.c | 5 ++++-
+ pgplib.h | 1 +
+ po/ca.po | 10 +++++-----
+ po/cs.po | 8 ++++----
+ po/da.po | 8 ++++----
+ po/de.po | 8 ++++----
+ po/el.po | 8 ++++----
+ po/eo.po | 8 ++++----
+ po/es.po | 9 +++++----
+ po/et.po | 6 +++---
+ po/fr.po | 8 ++++----
+ po/gl.po | 8 ++++----
+ po/hu.po | 8 ++++----
+ po/id.po | 8 ++++----
+ po/it.po | 8 ++++----
+ po/ja.po | 9 +++++----
+ po/ko.po | 8 ++++----
+ po/lt.po | 13 ++++++-------
+ po/nl.po | 8 ++++----
+ po/pl.po | 8 ++++----
+ po/pt_BR.po | 12 ++++++------
+ po/ru.po | 8 ++++----
+ po/sk.po | 13 ++++++-------
+ po/sv.po | 8 ++++----
+ po/tr.po | 8 ++++----
+ po/uk.po | 8 ++++----
+ po/zh_CN.po | 6 +++---
+ po/zh_TW.po | 6 +++---
+ postpone.c | 7 +++++++
+ send.c | 16 +++++++++++++++-
+ sendlib.c | 2 ++
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22R.ref b/patch_cmds/diffstat/testing/case22R.ref
new file mode 100644
index 0000000..b9c699b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22R.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 -
+ compose.c | 17 ++++-------------
+ crypt.c | 26 +++++++++++++++-----------
+ init.h | 54 +++++++-----------------------------------------------
+ mutt.h | 4 +---
+ pgp.c | 5 +----
+ pgplib.h | 1 -
+ po/ca.po | 10 +++++-----
+ po/cs.po | 8 ++++----
+ po/da.po | 8 ++++----
+ po/de.po | 8 ++++----
+ po/el.po | 8 ++++----
+ po/eo.po | 8 ++++----
+ po/es.po | 9 ++++-----
+ po/et.po | 6 +++---
+ po/fr.po | 8 ++++----
+ po/gl.po | 8 ++++----
+ po/hu.po | 8 ++++----
+ po/id.po | 8 ++++----
+ po/it.po | 8 ++++----
+ po/ja.po | 9 ++++-----
+ po/ko.po | 8 ++++----
+ po/lt.po | 13 +++++++------
+ po/nl.po | 8 ++++----
+ po/pl.po | 8 ++++----
+ po/pt_BR.po | 12 ++++++------
+ po/ru.po | 8 ++++----
+ po/sk.po | 13 +++++++------
+ po/sv.po | 8 ++++----
+ po/tr.po | 8 ++++----
+ po/uk.po | 8 ++++----
+ po/zh_CN.po | 6 +++---
+ po/zh_TW.po | 6 +++---
+ postpone.c | 7 -------
+ send.c | 16 +---------------
+ sendlib.c | 2 --
+ 36 files changed, 139 insertions(+), 214 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22Rp0.ref b/patch_cmds/diffstat/testing/case22Rp0.ref
new file mode 100644
index 0000000..fa59c21
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22Rp0.ref
@@ -0,0 +1,37 @@
+ pgp-menu-traditional/PATCHES | 1
+ pgp-menu-traditional/compose.c | 17 ++----------
+ pgp-menu-traditional/crypt.c | 26 ++++++++++--------
+ pgp-menu-traditional/init.h | 54 +++++----------------------------------
+ pgp-menu-traditional/mutt.h | 4 --
+ pgp-menu-traditional/pgp.c | 5 ---
+ pgp-menu-traditional/pgplib.h | 1
+ pgp-menu-traditional/po/ca.po | 10 +++----
+ pgp-menu-traditional/po/cs.po | 8 ++---
+ pgp-menu-traditional/po/da.po | 8 ++---
+ pgp-menu-traditional/po/de.po | 8 ++---
+ pgp-menu-traditional/po/el.po | 8 ++---
+ pgp-menu-traditional/po/eo.po | 8 ++---
+ pgp-menu-traditional/po/es.po | 9 ++----
+ pgp-menu-traditional/po/et.po | 6 ++--
+ pgp-menu-traditional/po/fr.po | 8 ++---
+ pgp-menu-traditional/po/gl.po | 8 ++---
+ pgp-menu-traditional/po/hu.po | 8 ++---
+ pgp-menu-traditional/po/id.po | 8 ++---
+ pgp-menu-traditional/po/it.po | 8 ++---
+ pgp-menu-traditional/po/ja.po | 9 ++----
+ pgp-menu-traditional/po/ko.po | 8 ++---
+ pgp-menu-traditional/po/lt.po | 13 +++++----
+ pgp-menu-traditional/po/nl.po | 8 ++---
+ pgp-menu-traditional/po/pl.po | 8 ++---
+ pgp-menu-traditional/po/pt_BR.po | 12 ++++----
+ pgp-menu-traditional/po/ru.po | 8 ++---
+ pgp-menu-traditional/po/sk.po | 13 +++++----
+ pgp-menu-traditional/po/sv.po | 8 ++---
+ pgp-menu-traditional/po/tr.po | 8 ++---
+ pgp-menu-traditional/po/uk.po | 8 ++---
+ pgp-menu-traditional/po/zh_CN.po | 6 ++--
+ pgp-menu-traditional/po/zh_TW.po | 6 ++--
+ pgp-menu-traditional/postpone.c | 7 -----
+ pgp-menu-traditional/send.c | 16 -----------
+ pgp-menu-traditional/sendlib.c | 2 -
+ 36 files changed, 139 insertions(+), 214 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22b.ref b/patch_cmds/diffstat/testing/case22b.ref
new file mode 100644
index 0000000..0cb180f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22b.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 +
+ compose.c | 17 +++++++++++++----
+ crypt.c | 26 +++++++++++---------------
+ init.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ mutt.h | 4 +++-
+ pgp.c | 5 ++++-
+ pgplib.h | 1 +
+ po/ca.po | 10 +++++-----
+ po/cs.po | 8 ++++----
+ po/da.po | 8 ++++----
+ po/de.po | 8 ++++----
+ po/el.po | 8 ++++----
+ po/eo.po | 8 ++++----
+ po/es.po | 9 +++++----
+ po/et.po | 6 +++---
+ po/fr.po | 8 ++++----
+ po/gl.po | 8 ++++----
+ po/hu.po | 8 ++++----
+ po/id.po | 8 ++++----
+ po/it.po | 8 ++++----
+ po/ja.po | 9 +++++----
+ po/ko.po | 8 ++++----
+ po/lt.po | 13 ++++++-------
+ po/nl.po | 8 ++++----
+ po/pl.po | 8 ++++----
+ po/pt_BR.po | 12 ++++++------
+ po/ru.po | 8 ++++----
+ po/sk.po | 13 ++++++-------
+ po/sv.po | 8 ++++----
+ po/tr.po | 8 ++++----
+ po/uk.po | 8 ++++----
+ po/zh_CN.po | 6 +++---
+ po/zh_TW.po | 6 +++---
+ postpone.c | 7 +++++++
+ send.c | 16 +++++++++++++++-
+ sendlib.c | 2 ++
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22f0.ref b/patch_cmds/diffstat/testing/case22f0.ref
new file mode 100644
index 0000000..cb44a93
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22f0.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 1 + 0 - 0 !
+ compose.c | 17 13 + 4 - 0 !
+ crypt.c | 26 11 + 15 - 0 !
+ init.h | 54 47 + 7 - 0 !
+ mutt.h | 4 3 + 1 - 0 !
+ pgp.c | 5 4 + 1 - 0 !
+ pgplib.h | 1 1 + 0 - 0 !
+ po/ca.po | 10 5 + 5 - 0 !
+ po/cs.po | 8 4 + 4 - 0 !
+ po/da.po | 8 4 + 4 - 0 !
+ po/de.po | 8 4 + 4 - 0 !
+ po/el.po | 8 4 + 4 - 0 !
+ po/eo.po | 8 4 + 4 - 0 !
+ po/es.po | 9 5 + 4 - 0 !
+ po/et.po | 6 3 + 3 - 0 !
+ po/fr.po | 8 4 + 4 - 0 !
+ po/gl.po | 8 4 + 4 - 0 !
+ po/hu.po | 8 4 + 4 - 0 !
+ po/id.po | 8 4 + 4 - 0 !
+ po/it.po | 8 4 + 4 - 0 !
+ po/ja.po | 9 5 + 4 - 0 !
+ po/ko.po | 8 4 + 4 - 0 !
+ po/lt.po | 13 6 + 7 - 0 !
+ po/nl.po | 8 4 + 4 - 0 !
+ po/pl.po | 8 4 + 4 - 0 !
+ po/pt_BR.po | 12 6 + 6 - 0 !
+ po/ru.po | 8 4 + 4 - 0 !
+ po/sk.po | 13 6 + 7 - 0 !
+ po/sv.po | 8 4 + 4 - 0 !
+ po/tr.po | 8 4 + 4 - 0 !
+ po/uk.po | 8 4 + 4 - 0 !
+ po/zh_CN.po | 6 3 + 3 - 0 !
+ po/zh_TW.po | 6 3 + 3 - 0 !
+ postpone.c | 7 7 + 0 - 0 !
+ send.c | 16 15 + 1 - 0 !
+ sendlib.c | 2 2 + 0 - 0 !
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22k.ref b/patch_cmds/diffstat/testing/case22k.ref
new file mode 100644
index 0000000..0cb180f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22k.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 +
+ compose.c | 17 +++++++++++++----
+ crypt.c | 26 +++++++++++---------------
+ init.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ mutt.h | 4 +++-
+ pgp.c | 5 ++++-
+ pgplib.h | 1 +
+ po/ca.po | 10 +++++-----
+ po/cs.po | 8 ++++----
+ po/da.po | 8 ++++----
+ po/de.po | 8 ++++----
+ po/el.po | 8 ++++----
+ po/eo.po | 8 ++++----
+ po/es.po | 9 +++++----
+ po/et.po | 6 +++---
+ po/fr.po | 8 ++++----
+ po/gl.po | 8 ++++----
+ po/hu.po | 8 ++++----
+ po/id.po | 8 ++++----
+ po/it.po | 8 ++++----
+ po/ja.po | 9 +++++----
+ po/ko.po | 8 ++++----
+ po/lt.po | 13 ++++++-------
+ po/nl.po | 8 ++++----
+ po/pl.po | 8 ++++----
+ po/pt_BR.po | 12 ++++++------
+ po/ru.po | 8 ++++----
+ po/sk.po | 13 ++++++-------
+ po/sv.po | 8 ++++----
+ po/tr.po | 8 ++++----
+ po/uk.po | 8 ++++----
+ po/zh_CN.po | 6 +++---
+ po/zh_TW.po | 6 +++---
+ postpone.c | 7 +++++++
+ send.c | 16 +++++++++++++++-
+ sendlib.c | 2 ++
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22p1.ref b/patch_cmds/diffstat/testing/case22p1.ref
new file mode 100644
index 0000000..0cb180f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22p1.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 +
+ compose.c | 17 +++++++++++++----
+ crypt.c | 26 +++++++++++---------------
+ init.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ mutt.h | 4 +++-
+ pgp.c | 5 ++++-
+ pgplib.h | 1 +
+ po/ca.po | 10 +++++-----
+ po/cs.po | 8 ++++----
+ po/da.po | 8 ++++----
+ po/de.po | 8 ++++----
+ po/el.po | 8 ++++----
+ po/eo.po | 8 ++++----
+ po/es.po | 9 +++++----
+ po/et.po | 6 +++---
+ po/fr.po | 8 ++++----
+ po/gl.po | 8 ++++----
+ po/hu.po | 8 ++++----
+ po/id.po | 8 ++++----
+ po/it.po | 8 ++++----
+ po/ja.po | 9 +++++----
+ po/ko.po | 8 ++++----
+ po/lt.po | 13 ++++++-------
+ po/nl.po | 8 ++++----
+ po/pl.po | 8 ++++----
+ po/pt_BR.po | 12 ++++++------
+ po/ru.po | 8 ++++----
+ po/sk.po | 13 ++++++-------
+ po/sv.po | 8 ++++----
+ po/tr.po | 8 ++++----
+ po/uk.po | 8 ++++----
+ po/zh_CN.po | 6 +++---
+ po/zh_TW.po | 6 +++---
+ postpone.c | 7 +++++++
+ send.c | 16 +++++++++++++++-
+ sendlib.c | 2 ++
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22p9.ref b/patch_cmds/diffstat/testing/case22p9.ref
new file mode 100644
index 0000000..2f2e7a2
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22p9.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 +
+ ca.po | 10 +++++-----
+ compose.c | 17 +++++++++++++----
+ crypt.c | 26 +++++++++++---------------
+ cs.po | 8 ++++----
+ da.po | 8 ++++----
+ de.po | 8 ++++----
+ el.po | 8 ++++----
+ eo.po | 8 ++++----
+ es.po | 9 +++++----
+ et.po | 6 +++---
+ fr.po | 8 ++++----
+ gl.po | 8 ++++----
+ hu.po | 8 ++++----
+ id.po | 8 ++++----
+ init.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ it.po | 8 ++++----
+ ja.po | 9 +++++----
+ ko.po | 8 ++++----
+ lt.po | 13 ++++++-------
+ mutt.h | 4 +++-
+ nl.po | 8 ++++----
+ pgp.c | 5 ++++-
+ pgplib.h | 1 +
+ pl.po | 8 ++++----
+ postpone.c | 7 +++++++
+ pt_BR.po | 12 ++++++------
+ ru.po | 8 ++++----
+ send.c | 16 +++++++++++++++-
+ sendlib.c | 2 ++
+ sk.po | 13 ++++++-------
+ sv.po | 8 ++++----
+ tr.po | 8 ++++----
+ uk.po | 8 ++++----
+ zh_CN.po | 6 +++---
+ zh_TW.po | 6 +++---
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22r1.ref b/patch_cmds/diffstat/testing/case22r1.ref
new file mode 100644
index 0000000..0cb180f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22r1.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 +
+ compose.c | 17 +++++++++++++----
+ crypt.c | 26 +++++++++++---------------
+ init.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ mutt.h | 4 +++-
+ pgp.c | 5 ++++-
+ pgplib.h | 1 +
+ po/ca.po | 10 +++++-----
+ po/cs.po | 8 ++++----
+ po/da.po | 8 ++++----
+ po/de.po | 8 ++++----
+ po/el.po | 8 ++++----
+ po/eo.po | 8 ++++----
+ po/es.po | 9 +++++----
+ po/et.po | 6 +++---
+ po/fr.po | 8 ++++----
+ po/gl.po | 8 ++++----
+ po/hu.po | 8 ++++----
+ po/id.po | 8 ++++----
+ po/it.po | 8 ++++----
+ po/ja.po | 9 +++++----
+ po/ko.po | 8 ++++----
+ po/lt.po | 13 ++++++-------
+ po/nl.po | 8 ++++----
+ po/pl.po | 8 ++++----
+ po/pt_BR.po | 12 ++++++------
+ po/ru.po | 8 ++++----
+ po/sk.po | 13 ++++++-------
+ po/sv.po | 8 ++++----
+ po/tr.po | 8 ++++----
+ po/uk.po | 8 ++++----
+ po/zh_CN.po | 6 +++---
+ po/zh_TW.po | 6 +++---
+ postpone.c | 7 +++++++
+ send.c | 16 +++++++++++++++-
+ sendlib.c | 2 ++
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22r2.ref b/patch_cmds/diffstat/testing/case22r2.ref
new file mode 100644
index 0000000..0cb180f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22r2.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 +
+ compose.c | 17 +++++++++++++----
+ crypt.c | 26 +++++++++++---------------
+ init.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ mutt.h | 4 +++-
+ pgp.c | 5 ++++-
+ pgplib.h | 1 +
+ po/ca.po | 10 +++++-----
+ po/cs.po | 8 ++++----
+ po/da.po | 8 ++++----
+ po/de.po | 8 ++++----
+ po/el.po | 8 ++++----
+ po/eo.po | 8 ++++----
+ po/es.po | 9 +++++----
+ po/et.po | 6 +++---
+ po/fr.po | 8 ++++----
+ po/gl.po | 8 ++++----
+ po/hu.po | 8 ++++----
+ po/id.po | 8 ++++----
+ po/it.po | 8 ++++----
+ po/ja.po | 9 +++++----
+ po/ko.po | 8 ++++----
+ po/lt.po | 13 ++++++-------
+ po/nl.po | 8 ++++----
+ po/pl.po | 8 ++++----
+ po/pt_BR.po | 12 ++++++------
+ po/ru.po | 8 ++++----
+ po/sk.po | 13 ++++++-------
+ po/sv.po | 8 ++++----
+ po/tr.po | 8 ++++----
+ po/uk.po | 8 ++++----
+ po/zh_CN.po | 6 +++---
+ po/zh_TW.po | 6 +++---
+ postpone.c | 7 +++++++
+ send.c | 16 +++++++++++++++-
+ sendlib.c | 2 ++
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case22u.ref b/patch_cmds/diffstat/testing/case22u.ref
new file mode 100644
index 0000000..328b2f4
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case22u.ref
@@ -0,0 +1,37 @@
+ PATCHES | 1 +
+ compose.c | 17 +++++++++++++----
+ crypt.c | 26 +++++++++++---------------
+ init.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++-------
+ mutt.h | 4 +++-
+ pgp.c | 5 ++++-
+ pgplib.h | 1 +
+ postpone.c | 7 +++++++
+ send.c | 16 +++++++++++++++-
+ sendlib.c | 2 ++
+ po/ca.po | 10 +++++-----
+ po/cs.po | 8 ++++----
+ po/da.po | 8 ++++----
+ po/de.po | 8 ++++----
+ po/el.po | 8 ++++----
+ po/eo.po | 8 ++++----
+ po/es.po | 9 +++++----
+ po/et.po | 6 +++---
+ po/fr.po | 8 ++++----
+ po/gl.po | 8 ++++----
+ po/hu.po | 8 ++++----
+ po/id.po | 8 ++++----
+ po/it.po | 8 ++++----
+ po/ja.po | 9 +++++----
+ po/ko.po | 8 ++++----
+ po/lt.po | 13 ++++++-------
+ po/nl.po | 8 ++++----
+ po/pl.po | 8 ++++----
+ po/pt_BR.po | 12 ++++++------
+ po/ru.po | 8 ++++----
+ po/sk.po | 13 ++++++-------
+ po/sv.po | 8 ++++----
+ po/tr.po | 8 ++++----
+ po/uk.po | 8 ++++----
+ po/zh_CN.po | 6 +++---
+ po/zh_TW.po | 6 +++---
+ 36 files changed, 214 insertions(+), 139 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23.pat b/patch_cmds/diffstat/testing/case23.pat
new file mode 100644
index 0000000..47d9bcc
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23.pat
@@ -0,0 +1,227 @@
+diff -ur bfm-0.6.1.orig/README bfm-0.6.1/README
+--- bfm-0.6.1.orig/README 2003-10-11 03:29:08.000000000 -0500
++++ bfm-0.6.1/README 2003-11-01 20:59:22.000000000 -0600
+@@ -7,7 +7,6 @@
+
+
+ TODO
+-- Any way to fix the update speed? Gkrellm maximum update is 10 per second.
+ - Someone tests/does the FreeBSD and SunOS platform?
+ - Possible/Make more sense, to make a gkrellm swallow plugin?
+ (Quick search on google:
+diff -ur bfm-0.6.1.orig/gkrellm-bfm.c bfm-0.6.1/gkrellm-bfm.c
+--- bfm-0.6.1.orig/gkrellm-bfm.c 2003-11-01 10:44:15.000000000 -0600
++++ bfm-0.6.1/gkrellm-bfm.c 2003-11-01 20:58:57.000000000 -0600
+@@ -68,6 +68,8 @@
+ static Chart *chart = NULL;
+ static ChartConfig *chart_config = NULL;
+
++static gint timeout_id,
++ update_interval;
+
+
+ /* From the actual bfm */
+@@ -92,13 +94,13 @@
+ GtkWidget *clock_check = NULL;
+ GtkWidget *fish_traffic_check = NULL;
+
+-static void
++static gboolean
+ update_plugin(void)
+ {
+ GdkEventExpose event;
+ gint ret_val;
+ gtk_signal_emit_by_name(GTK_OBJECT(chart->drawing_area), "expose_event", &event, &ret_val);
+-
++ return TRUE; /* restart timer */
+ }
+
+
+@@ -154,6 +156,15 @@
+ return TRUE;
+ }
+
++
++static void
++disable_plugin(void)
++ {
++ if (timeout_id)
++ gtk_timeout_remove(timeout_id);
++ timeout_id = 0;
++ }
++
+ static void
+ create_plugin(GtkWidget *vbox, gint first_create)
+ {
+@@ -182,7 +193,10 @@
+ "leave_notify_event", GTK_SIGNAL_FUNC(leave_notify_event),
+ NULL);
+ }
+-
++ if (!timeout_id)
++ timeout_id = gtk_timeout_add(1000 / update_interval,
++ (GtkFunction) update_plugin, NULL);
++ gkrellm_disable_plugin_connect(mon, disable_plugin);
+ }
+
+
+@@ -240,6 +254,44 @@
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(fish_traffic_check), fish_traffic);
+ }
+
++
++static void
++cb_interval_modified(GtkWidget *widget, GtkSpinButton *spin)
++ {
++ update_interval = gtk_spin_button_get_value_as_int(spin);
++ if (timeout_id)
++ gtk_timeout_remove(timeout_id);
++ timeout_id = gtk_timeout_add(1000 / update_interval,
++ (GtkFunction) update_plugin, NULL);
++ }
++
++static gchar *pending_prog;
++
++static void
++cb_prog_entry(GtkWidget *widget, gpointer data)
++{
++ gboolean activate_sig = GPOINTER_TO_INT(data);
++ gchar *s = gkrellm_gtk_entry_get_text(&prog_entry);
++
++ if (activate_sig)
++ {
++ gkrellm_dup_string(&prog, s);
++ g_free(pending_prog);
++ pending_prog = NULL;
++ }
++ else /* "changed" sig, entry is pending on "activate" or config close */
++ gkrellm_dup_string(&pending_prog, s);
++}
++
++static void
++config_destroyed(void)
++ {
++ if (pending_prog)
++ gkrellm_dup_string(&prog, pending_prog);
++ g_free(pending_prog);
++ pending_prog = NULL;
++ }
++
+ static void
+ create_plugin_tab(GtkWidget *tab_vbox)
+ {
+@@ -287,10 +339,7 @@
+ " fish swiming from right to left represents incoming traffic)\n",
+ "- Cute little duck swimming...\n",
+ "- Clock hands representing time (obviously)...\n",
+- "- Click and it will run a command for you (requested by Nick =)\n\n",
+- "<i>Notes\n\n",
+- "- Currently Gkrellm updates at most 10 times a second, and so\n",
+- " BFM updates is a bit jerky still.\n",
++ "- Click and it will run a command for you (requested by Nick =)\n",
+ "\n\n",
+ };
+
+@@ -307,6 +356,8 @@
+ tabs = gtk_notebook_new();
+ gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
+ gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
++ g_signal_connect(G_OBJECT(tabs),"destroy",
++ G_CALLBACK(config_destroyed), NULL);
+
+ /* Options tab */
+ options_tab = gkrellm_create_tab(tabs, _("Options"));
+@@ -346,6 +397,10 @@
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (prog_entry);
+ gtk_box_pack_start (GTK_BOX (prog_box), prog_entry, TRUE, TRUE, 0);
++ g_signal_connect(G_OBJECT(prog_entry), "activate",
++ G_CALLBACK(cb_prog_entry), GINT_TO_POINTER(1));
++ g_signal_connect(G_OBJECT(prog_entry), "changed",
++ G_CALLBACK(cb_prog_entry), GINT_TO_POINTER(0));
+
+ row1 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_set_name (row1, "row1");
+@@ -470,6 +525,11 @@
+ gtk_widget_show (fish_traffic_check);
+ gtk_box_pack_start (GTK_BOX (fish_traffic_box), fish_traffic_check, TRUE, TRUE, 0);
+
++ gkrellm_gtk_spin_button(main_box, NULL, update_interval,
++ 10.0, 50.0, 1.0, 5.0, 0, 60,
++ cb_interval_modified, NULL, FALSE,
++ _("Updates per second"));
++
+ setup_toggle_buttons();
+
+ gtk_signal_connect(GTK_OBJECT(cpu_check), "toggled", GTK_SIGNAL_FUNC(option_toggled_cb), NULL);
+@@ -494,15 +554,6 @@
+
+ }
+
+-static void
+-apply_plugin_config(void)
+-{
+- if(prog)
+- {
+- g_free(prog);
+- }
+- prog = g_strdup(gtk_editable_get_chars(GTK_EDITABLE(prog_entry), 0, -1));
+-}
+
+ static void
+ save_plugin_config(FILE *f)
+@@ -511,13 +562,15 @@
+ {
+ fprintf(f, "%s prog %s\n", PLUGIN_KEYWORD, prog);
+ }
+- fprintf(f, "%s options %d.%d.%d.%d.%d.%d\n", PLUGIN_KEYWORD,
++ fprintf(f, "%s options %d.%d.%d.%d.%d.%d.%d\n", PLUGIN_KEYWORD,
+ cpu_enabled,
+ duck_enabled,
+ memscreen_enabled,
+ fish_enabled,
+ fish_traffic,
+- time_enabled);
++ time_enabled,
++ update_interval);
++
+ }
+
+ static void
+@@ -539,13 +592,14 @@
+ }
+ else if(!strcmp(config_item, "options"))
+ {
+- sscanf(value, "%d.%d.%d.%d.%d.%d",
++ sscanf(value, "%d.%d.%d.%d.%d.%d.%d",
+ &cpu_enabled,
+ &duck_enabled,
+ &memscreen_enabled,
+ &fish_enabled,
+ &fish_traffic,
+- &time_enabled);
++ &time_enabled,
++ &update_interval);
+ }
+
+ }
+@@ -556,9 +610,9 @@
+ PLUGIN_NAME, /* Name, for config tab. */
+ 0, /* Id, 0 if a plugin */
+ create_plugin, /* The create_plugin() function */
+- update_plugin, /* The update_plugin() function */
++ NULL, /* The update_plugin() function */
+ create_plugin_tab, /* The create_plugin_tab() config function */
+- apply_plugin_config, /* The apply_plugin_config() function */
++ NULL, /* The apply_plugin_config() function */
+
+ save_plugin_config, /* The save_plugin_config() function */
+ load_plugin_config, /* The load_plugin_config() function */
+@@ -577,6 +631,7 @@
+ Monitor *
+ init_plugin(void)
+ {
++ update_interval = 20;
+ style_id = gkrellm_add_meter_style(&bfm_mon, PLUGIN_STYLE);
+ return (mon = &bfm_mon);
+ }
diff --git a/patch_cmds/diffstat/testing/case23.ref b/patch_cmds/diffstat/testing/case23.ref
new file mode 100644
index 0000000..7a6ac84
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23.ref
@@ -0,0 +1,3 @@
+ README | 1
+ gkrellm-bfm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23R.ref b/patch_cmds/diffstat/testing/case23R.ref
new file mode 100644
index 0000000..5ca71ed
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23R.ref
@@ -0,0 +1,3 @@
+ README | 1
+ gkrellm-bfm.c | 99 ++++++++++++----------------------------------------------
+ 2 files changed, 23 insertions(+), 77 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23Rp0.ref b/patch_cmds/diffstat/testing/case23Rp0.ref
new file mode 100644
index 0000000..e5c3893
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23Rp0.ref
@@ -0,0 +1,3 @@
+ bfm-0.6.1.orig/README | 1
+ bfm-0.6.1.orig/gkrellm-bfm.c | 99 +++++++++----------------------------------
+ 2 files changed, 23 insertions(+), 77 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23b.ref b/patch_cmds/diffstat/testing/case23b.ref
new file mode 100644
index 0000000..7a6ac84
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23b.ref
@@ -0,0 +1,3 @@
+ README | 1
+ gkrellm-bfm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23f0.ref b/patch_cmds/diffstat/testing/case23f0.ref
new file mode 100644
index 0000000..29339c7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23f0.ref
@@ -0,0 +1,3 @@
+ README | 1 0 + 1 - 0 !
+ gkrellm-bfm.c | 99 77 + 22 - 0 !
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23k.ref b/patch_cmds/diffstat/testing/case23k.ref
new file mode 100644
index 0000000..7a6ac84
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23k.ref
@@ -0,0 +1,3 @@
+ README | 1
+ gkrellm-bfm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23p1.ref b/patch_cmds/diffstat/testing/case23p1.ref
new file mode 100644
index 0000000..7a6ac84
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23p1.ref
@@ -0,0 +1,3 @@
+ README | 1
+ gkrellm-bfm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23p9.ref b/patch_cmds/diffstat/testing/case23p9.ref
new file mode 100644
index 0000000..7a6ac84
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23p9.ref
@@ -0,0 +1,3 @@
+ README | 1
+ gkrellm-bfm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23r1.ref b/patch_cmds/diffstat/testing/case23r1.ref
new file mode 100644
index 0000000..2200a09
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23r1.ref
@@ -0,0 +1,3 @@
+ README | 1 -
+ gkrellm-bfm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23r2.ref b/patch_cmds/diffstat/testing/case23r2.ref
new file mode 100644
index 0000000..2200a09
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23r2.ref
@@ -0,0 +1,3 @@
+ README | 1 -
+ gkrellm-bfm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case23u.ref b/patch_cmds/diffstat/testing/case23u.ref
new file mode 100644
index 0000000..7a6ac84
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case23u.ref
@@ -0,0 +1,3 @@
+ README | 1
+ gkrellm-bfm.c | 99 +++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 77 insertions(+), 23 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24.pat b/patch_cmds/diffstat/testing/case24.pat
new file mode 100644
index 0000000..dfb7406
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24.pat
@@ -0,0 +1,217 @@
+# ncurses 5.4 - patch 20040821 - T.Dickey
+#
+# ------------------------------------------------------------------------------
+#
+# Ncurses 5.4 is at
+# ftp.gnu.org:/pub/gnu
+#
+# Patches for ncurses 5.4 are in the subdirectory
+# ftp://invisible-island.net/ncurses/5.4
+#
+# ------------------------------------------------------------------------------
+Index: Ada95/gen/gen.c
+--- ncurses-5.4-20040814+/Ada95/gen/gen.c 2003-10-25 15:39:18.000000000 +0000
++++ ncurses-5.4-20040821/Ada95/gen/gen.c 2004-08-21 20:37:13.000000000 +0000
+@@ -1,5 +1,5 @@
+ /****************************************************************************
+- * Copyright (c) 1998,2000 Free Software Foundation, Inc. *
++ * Copyright (c) 1998,2000,2004 Free Software Foundation, Inc. *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining a *
+ * copy of this software and associated documentation files (the *
+@@ -32,7 +32,7 @@
+
+ /*
+ Version Control
+- @Revision: 1.36 @
++ @Id: gen.c,v 1.38 2004/08/21 20:37:13 tom Exp @
+ --------------------------------------------------------------------------*/
+ /*
+ This program generates various record structures and constants from the
+@@ -131,7 +131,6 @@
+ printf(" %-*s : Boolean;\n",width,nap[i].name);
+ }
+ printf(" end record;\n");
+- printf(" pragma Pack (%s);\n",name);
+ printf(" pragma Convention (C, %s);\n\n",name);
+
+ printf(" for %s use\n",name);
+Index: Ada95/gen/terminal_interface-curses-mouse.ads.m4
+--- ncurses-5.4-20040814+/Ada95/gen/terminal_interface-curses-mouse.ads.m4 2003-10-25 15:39:18.000000000 +0000
++++ ncurses-5.4-20040821/Ada95/gen/terminal_interface-curses-mouse.ads.m4 2004-08-21 21:37:00.000000000 +0000
+@@ -10,7 +10,7 @@
+ -- S P E C --
+ -- --
+ ------------------------------------------------------------------------------
+--- Copyright (c) 1998 Free Software Foundation, Inc. --
++-- Copyright (c) 1998,2004 Free Software Foundation, Inc. --
+ -- --
+ -- Permission is hereby granted, free of charge, to any person obtaining a --
+ -- copy of this software and associated documentation files (the --
+@@ -38,7 +38,8 @@
+ ------------------------------------------------------------------------------
+ -- Author: Juergen Pfeifer, 1996
+ -- Version Control:
+--- @Revision: 1.22 @
++-- @Revision: 1.25 @
++-- @Date: 2004/08/21 21:37:00 @
+ -- Binding Version 01.00
+ ------------------------------------------------------------------------------
+ include(`Mouse_Base_Defs')
+@@ -169,7 +170,6 @@
+ Bstate : Event_Mask;
+ end record;
+ pragma Convention (C, Mouse_Event);
+- pragma Pack (Mouse_Event);
+
+ include(`Mouse_Event_Rep')
+ Generation_Bit_Order : constant System.Bit_Order := System.M4_BIT_ORDER;
+Index: Ada95/gen/terminal_interface-curses.ads.m4
+--- ncurses-5.4-20040814+/Ada95/gen/terminal_interface-curses.ads.m4 2003-10-25 15:39:18.000000000 +0000
++++ ncurses-5.4-20040821/Ada95/gen/terminal_interface-curses.ads.m4 2004-08-21 21:37:00.000000000 +0000
+@@ -9,7 +9,7 @@
+ -- S P E C --
+ -- --
+ ------------------------------------------------------------------------------
+--- Copyright (c) 1998 Free Software Foundation, Inc. --
++-- Copyright (c) 1998,2004 Free Software Foundation, Inc. --
+ -- --
+ -- Permission is hereby granted, free of charge, to any person obtaining a --
+ -- copy of this software and associated documentation files (the --
+@@ -37,7 +37,8 @@
+ ------------------------------------------------------------------------------
+ -- Author: Juergen Pfeifer, 1996
+ -- Version Control:
+--- @Revision: 1.31 @
++-- @Revision: 1.35 @
++-- @Date: 2004/08/21 21:37:00 @
+ -- Binding Version 01.00
+ ------------------------------------------------------------------------------
+ include(`Base_Defs')
+@@ -59,11 +60,12 @@
+ subtype Column_Count is Column_Position range 1 .. Column_Position'Last;
+ -- Type to count columns. We do not allow null windows, so must be positive
+
+- type Key_Code is new Natural;
++ type Key_Code is new Integer;
+ -- That is anything including real characters, special keys and logical
+ -- request codes.
+
+- subtype Real_Key_Code is Key_Code range 0 .. M4_KEY_MAX;
++ -- FIXME: The "-1" should be Curses_Err
++ subtype Real_Key_Code is Key_Code range -1 .. M4_KEY_MAX;
+ -- This are the codes that potentially represent a real keystroke.
+ -- Not all codes may be possible on a specific terminal. To check the
+ -- availability of a special key, the Has_Key function is provided.
+Index: Ada95/samples/ncurses2-acs_and_scroll.adb
+--- ncurses-5.4-20040814+/Ada95/samples/ncurses2-acs_and_scroll.adb 2000-12-02 22:31:22.000000000 +0000
++++ ncurses-5.4-20040821/Ada95/samples/ncurses2-acs_and_scroll.adb 2004-08-21 21:37:00.000000000 +0000
+@@ -7,7 +7,7 @@
+ -- B O D Y --
+ -- --
+ ------------------------------------------------------------------------------
+--- Copyright (c) 2000 Free Software Foundation, Inc. --
++-- Copyright (c) 2000,2004 Free Software Foundation, Inc. --
+ -- --
+ -- Permission is hereby granted, free of charge, to any person obtaining a --
+ -- copy of this software and associated documentation files (the --
+@@ -35,7 +35,8 @@
+ ------------------------------------------------------------------------------
+ -- Author: Eugene V. Melaragno <aldomel@ix.netcom.com> 2000
+ -- Version Control
+--- @Revision: 1.1 @
++-- @Revision: 1.6 @
++-- @Date: 2004/08/21 21:37:00 @
+ -- Binding Version 01.00
+ ------------------------------------------------------------------------------
+ -- Windows and scrolling tester.
+@@ -224,8 +225,8 @@
+ );
+
+ buf : Bounded_String;
+- do_keypad : Boolean := HaveKeyPad (curpw);
+- do_scroll : Boolean := HaveScroll (curpw);
++ do_keypad : constant Boolean := HaveKeyPad (curpw);
++ do_scroll : constant Boolean := HaveScroll (curpw);
+
+ pos : Natural;
+
+@@ -331,8 +332,8 @@
+ res : pair;
+ i : Line_Position := 0;
+ j : Column_Position := 0;
+- si : Line_Position := lri - uli + 1;
+- sj : Column_Position := lrj - ulj + 1;
++ si : constant Line_Position := lri - uli + 1;
++ sj : constant Column_Position := lrj - ulj + 1;
+ begin
+ res.y := uli;
+ res.x := ulj;
+@@ -714,7 +715,7 @@
+
+ Allow_Scrolling (Mode => True);
+
+- End_Mouse;
++ End_Mouse (Mask2);
+ Set_Raw_Mode (SwitchOn => True);
+ Erase;
+ End_Windows;
+Index: Ada95/samples/ncurses2-acs_display.adb
+--- ncurses-5.4-20040814+/Ada95/samples/ncurses2-acs_display.adb 2000-12-02 22:31:23.000000000 +0000
++++ ncurses-5.4-20040821/Ada95/samples/ncurses2-acs_display.adb 2004-08-21 21:37:00.000000000 +0000
+@@ -7,7 +7,7 @@
+ -- B O D Y --
+ -- --
+ ------------------------------------------------------------------------------
+--- Copyright (c) 2000 Free Software Foundation, Inc. --
++-- Copyright (c) 2000,2004 Free Software Foundation, Inc. --
+ -- --
+ -- Permission is hereby granted, free of charge, to any person obtaining a --
+ -- copy of this software and associated documentation files (the --
+@@ -35,7 +35,8 @@
+ ------------------------------------------------------------------------------
+ -- Author: Eugene V. Melaragno <aldomel@ix.netcom.com> 2000
+ -- Version Control
+--- @Revision: 1.1 @
++-- @Revision: 1.4 @
++-- @Date: 2004/08/21 21:37:00 @
+ -- Binding Version 01.00
+ ------------------------------------------------------------------------------
+ with ncurses2.util; use ncurses2.util;
+@@ -57,8 +58,8 @@
+
+
+ procedure show_upper_chars (first : Integer) is
+- C1 : Boolean := (first = 128);
+- last : Integer := first + 31;
++ C1 : constant Boolean := (first = 128);
++ last : constant Integer := first + 31;
+ package p is new ncurses2.genericPuts (200);
+ use p;
+ use p.BS;
+@@ -91,9 +92,11 @@
+
+ for code in first .. last loop
+ declare
+- row : Line_Position := Line_Position (4 + ((code - first) mod 16));
+- col : Column_Position := Column_Position (((code - first) / 16) *
+- Integer (Columns) / 2);
++ row : constant Line_Position
++ := Line_Position (4 + ((code - first) mod 16));
++ col : constant Column_Position
++ := Column_Position (((code - first) / 16) *
++ Integer (Columns) / 2);
+ tmp3 : String (1 .. 3);
+ tmpx : String (1 .. Integer (Columns / 4));
+ reply : Key_Code;
+@@ -129,8 +132,8 @@
+ code : Attributed_Character)
+ return Integer is
+ height : constant Integer := 16;
+- row : Line_Position := Line_Position (4 + (N mod height));
+- col : Column_Position := Column_Position ((N / height) *
++ row : constant Line_Position := Line_Position (4 + (N mod height));
++ col : constant Column_Position := Column_Position ((N / height) *
+ Integer (Columns) / 2);
+ tmpx : String (1 .. Integer (Columns) / 3);
+ begin
diff --git a/patch_cmds/diffstat/testing/case24.ref b/patch_cmds/diffstat/testing/case24.ref
new file mode 100644
index 0000000..ab81687
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24.ref
@@ -0,0 +1,6 @@
+ gen/gen.c | 5 ++---
+ gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ gen/terminal_interface-curses.ads.m4 | 10 ++++++----
+ samples/ncurses2-acs_and_scroll.adb | 15 ++++++++-------
+ samples/ncurses2-acs_display.adb | 21 ++++++++++++---------
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24R.ref b/patch_cmds/diffstat/testing/case24R.ref
new file mode 100644
index 0000000..c9486b7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24R.ref
@@ -0,0 +1,6 @@
+ gen/gen.c | 5 +++--
+ gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ gen/terminal_interface-curses.ads.m4 | 10 ++++------
+ samples/ncurses2-acs_and_scroll.adb | 15 +++++++--------
+ samples/ncurses2-acs_display.adb | 21 +++++++++------------
+ 5 files changed, 26 insertions(+), 31 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24Rp0.ref b/patch_cmds/diffstat/testing/case24Rp0.ref
new file mode 100644
index 0000000..1315b22
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24Rp0.ref
@@ -0,0 +1,6 @@
+ Ada95/gen/gen.c | 5 +++--
+ Ada95/gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ Ada95/gen/terminal_interface-curses.ads.m4 | 10 ++++------
+ Ada95/samples/ncurses2-acs_and_scroll.adb | 15 +++++++--------
+ Ada95/samples/ncurses2-acs_display.adb | 21 +++++++++------------
+ 5 files changed, 26 insertions(+), 31 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24b.ref b/patch_cmds/diffstat/testing/case24b.ref
new file mode 100644
index 0000000..ab81687
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24b.ref
@@ -0,0 +1,6 @@
+ gen/gen.c | 5 ++---
+ gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ gen/terminal_interface-curses.ads.m4 | 10 ++++++----
+ samples/ncurses2-acs_and_scroll.adb | 15 ++++++++-------
+ samples/ncurses2-acs_display.adb | 21 ++++++++++++---------
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24f0.ref b/patch_cmds/diffstat/testing/case24f0.ref
new file mode 100644
index 0000000..9efc375
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24f0.ref
@@ -0,0 +1,6 @@
+ gen/gen.c | 5 2 + 3 - 0 !
+ gen/terminal_interface-curses-mouse.ads.m4 | 6 3 + 3 - 0 !
+ gen/terminal_interface-curses.ads.m4 | 10 6 + 4 - 0 !
+ samples/ncurses2-acs_and_scroll.adb | 15 8 + 7 - 0 !
+ samples/ncurses2-acs_display.adb | 21 12 + 9 - 0 !
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24k.ref b/patch_cmds/diffstat/testing/case24k.ref
new file mode 100644
index 0000000..ab81687
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24k.ref
@@ -0,0 +1,6 @@
+ gen/gen.c | 5 ++---
+ gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ gen/terminal_interface-curses.ads.m4 | 10 ++++++----
+ samples/ncurses2-acs_and_scroll.adb | 15 ++++++++-------
+ samples/ncurses2-acs_display.adb | 21 ++++++++++++---------
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24p1.ref b/patch_cmds/diffstat/testing/case24p1.ref
new file mode 100644
index 0000000..8d4d22a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24p1.ref
@@ -0,0 +1,6 @@
+ Ada95/gen/gen.c | 5 ++---
+ Ada95/gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ Ada95/gen/terminal_interface-curses.ads.m4 | 10 ++++++----
+ Ada95/samples/ncurses2-acs_and_scroll.adb | 15 ++++++++-------
+ Ada95/samples/ncurses2-acs_display.adb | 21 ++++++++++++---------
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24p9.ref b/patch_cmds/diffstat/testing/case24p9.ref
new file mode 100644
index 0000000..113c4b8
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24p9.ref
@@ -0,0 +1,6 @@
+ gen.c | 5 ++---
+ ncurses2-acs_and_scroll.adb | 15 ++++++++-------
+ ncurses2-acs_display.adb | 21 ++++++++++++---------
+ terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ terminal_interface-curses.ads.m4 | 10 ++++++----
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24r1.ref b/patch_cmds/diffstat/testing/case24r1.ref
new file mode 100644
index 0000000..ab81687
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24r1.ref
@@ -0,0 +1,6 @@
+ gen/gen.c | 5 ++---
+ gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ gen/terminal_interface-curses.ads.m4 | 10 ++++++----
+ samples/ncurses2-acs_and_scroll.adb | 15 ++++++++-------
+ samples/ncurses2-acs_display.adb | 21 ++++++++++++---------
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24r2.ref b/patch_cmds/diffstat/testing/case24r2.ref
new file mode 100644
index 0000000..ab81687
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24r2.ref
@@ -0,0 +1,6 @@
+ gen/gen.c | 5 ++---
+ gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ gen/terminal_interface-curses.ads.m4 | 10 ++++++----
+ samples/ncurses2-acs_and_scroll.adb | 15 ++++++++-------
+ samples/ncurses2-acs_display.adb | 21 ++++++++++++---------
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case24u.ref b/patch_cmds/diffstat/testing/case24u.ref
new file mode 100644
index 0000000..ab81687
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case24u.ref
@@ -0,0 +1,6 @@
+ gen/gen.c | 5 ++---
+ gen/terminal_interface-curses-mouse.ads.m4 | 6 +++---
+ gen/terminal_interface-curses.ads.m4 | 10 ++++++----
+ samples/ncurses2-acs_and_scroll.adb | 15 ++++++++-------
+ samples/ncurses2-acs_display.adb | 21 ++++++++++++---------
+ 5 files changed, 31 insertions(+), 26 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25.pat b/patch_cmds/diffstat/testing/case25.pat
new file mode 100644
index 0000000..8edbd31
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25.pat
@@ -0,0 +1,471 @@
+# vile 9.4m - patch 2004/12/15 - Thomas Dickey <dickey@his.com>
+# ------------------------------------------------------------------------------
+# $Header: | 1
+# CHANGES | 58
+# MANIFEST | 3
+# buffer.c | 208 ++-
+# buglist | 7
+# builtflt.c | 68 +
+# cmdtbl | 15
+# configure | 2652 ++++++++++++++++++++---------------------
+# configure.in | 16
+# display.c | 80 -
+# doc/filters.doc | 34
+# doc/macros.doc | 67 -
+# edef.h | 5
+# estruct.h | 13
+# eval.c | 196 ++-
+# filters/as-filt.l | 6
+# filters/asm-filt.l | 8
+# filters/au3-filt.l | 8
+# filters/bat-filt.l | 6
+# filters/c-filt.c | 20
+# filters/filterio.c | 33
+# filters/filters.c | 3
+# filters/filters.h | 7
+# filters/filters.rc | 40
+# filters/htmlfilt.l | 9
+# filters/imakeflt.l | 19
+# filters/key-filt.c | 11
+# filters/m4-filt.c | 3
+# filters/makefilt.l | 19
+# filters/pl-filt.c | 24
+# filters/pot-filt.l | 5
+# filters/ps-filt.l | 5
+# filters/rb-filt.l | 3
+# filters/rpm-filt.l | 16
+# filters/rubyfilt.c | 30
+# filters/sccsfilt.l | 5
+# filters/sed-filt.c | 3
+# filters/sh-filt.l | 16
+# filters/spell.rc | 36
+# filters/spellflt.l | 8
+# filters/sql-filt.l | 9
+# filters/tc-filt.l | 12
+# filters/tcl-filt.l | 4
+# filters/vilefilt.l | 10
+# filters/vl-filt.l | 20
+# filters/xml-filt.l | 50
+# filters/xresfilt.l | 11
+# input.c | 4
+# macros/gnugpg.rc | 8
+# macros/which.rc | 107 +
+# main.c | 5
+# makefile.in | 17
+# makefile.wnt | 3
+# modes.c | 358 +++--
+# modetbl | 22
+# ntconio.c | 51
+# ntwinio.c | 53
+# patchlev.h | 2
+# proto.h | 19
+# revlist | 129 +
+# statevar.c | 8
+# tbuff.c | 14
+# tcap.c | 3
+# vile-9.4.spec | 9
+# vile-9.4m/macros/showeach.rc | 78 +
+# vile.hlp | 16
+# x11.c | 370 ++---
+# 67 files changed, 3017 insertions(+), 2141 deletions(-)
+# ------------------------------------------------------------------------------
+Index: CHANGES
+--- vile-9.4l+/CHANGES 2004-12-08 01:01:53.000000000 +0000
++++ vile-9.4m/CHANGES 2004-12-15 23:56:47.000000000 +0000
+@@ -1,5 +1,63 @@
+ Changes for vile 9.5 (released ??? ??? ?? ????)
+
++ 20041215 (m)
++ > Tom Dickey:
++ + modify x11.c, ntconio.c and ntwinio.c to make modifiers work with tab
++ key, e.g., to add shift-key as a back-tab key.
++ + add macro show-each-buffer (file showeach.rc), which splits up the
++ screen into equal chunks to display as many of the non-scratch
++ buffers as possible.
++ + modify macro parameter evaluation so it does not attempt to compute
++ a value for function tokens or goto-labels. Otherwise pathnames such
++ as "~\foo" look like macro directives and produce an error.
++ + correct slash/backslash translation (win32, etc) for some of the
++ built-in functions; the translated result was not actually the return
++ value: &path and &pcat.
++ + correct flags in modetbl used to annotate trace of &seq and a few
++ other operators.
++ + correct length computed for $bflags variable; an empty string was
++ returned.
++ + add a section on command-line options to doc/filters.doc
++ + add macro which-filter to show which locations would be checked for
++ an external filter. If the filter happens to be built-in, this is
++ also noted, in the message line.
++ + improve 'eval' command, provide for mixture of functions and other
++ tokens which are passed to the script interpreter.
++ + modify SpellFilter macro to use the results from [Filter Messages]
++ with the error-finder to step through the misspellings.
++ + add macro show-filtermsgs to show syntax filter messages, setting the
++ list to the error-buffer to provide simple stepping through the
++ errors which are found.
++ + add commands popup-buffer and popdown-buffer, which open/close
++ windows for the given buffer rather than changing the current window
++ to show a different buffer. The popup-buffer command is a wrapper
++ for the existing logic used for help and similar commands. The
++ popdown-buffer command differs from delete-window by closing all
++ windows for the given buffer.
++ + remove the pre-9.4e workarounds for set-highlighting and
++ which-keywords macros.
++ + modify kdb_reply() to shift the minibuffer left/right as needed after
++ doing the initial tab of a name-completion, in case that left the
++ cursor position past the end of the line (report by Paul Fox).
++ + add new operators to make it simpler for macros to check for
++ features: &isa, &classof and &mclass.
++ + modify historical-buffer to allow tab/back-tab to cycle through the
++ first 9 buffers, solves the problem of seeing more than the first
++ few possibilities on the message line. Toggling with the repeated
++ '_' selects the first buffer shown.
++ + add back-tab to termcap/terminfo driver as a bindable key.
++ + modify configure script to make builtflt.h part of $(BUILTHDRS) to
++ simplify "make sources" rule.
++ + modify htmlfilt.l to match </script> in the middle of a line to
++ accommodate pages where the script is given by a "src=".
++ + add filtermsgs mode, for built-in filters to report syntax errors
++ into [Filter Messages] buffer so that one may use the error finder to
++ locate these (motivated by a 200,000 line xml file).
++ + correct state manipulation in xml-filt.l, which was confused by
++ CDATA pattern.
++ + correct $CPPFLAGS for linting configurations with built-in filters.
++ + correct typo in configure script from 9.4k fixes for iconv_open().
++
+ 20041207 (l)
+ > Clark Morgan:
+ + modify special treatment of "#" which prevents it from being shifted
+Index: MANIFEST
+--- vile-9.4l+/MANIFEST 2004-12-08 01:48:52.000000000 +0000
++++ vile-9.4m/MANIFEST 2004-12-16 00:53:14.000000000 +0000
+@@ -1,4 +1,4 @@
+-MANIFEST for vile, version v9_4l
++MANIFEST for vile, version v9_4m
+ --------------------------------------------------------------------------------
+ MANIFEST this file
+ CHANGES Change-log for VILE
+@@ -332,6 +332,7 @@
+ macros/pictmode.rc macros to support "picture-mode" editing
+ macros/search.rc find a file in one of several locations
+ macros/shifts.rc macros to shift words left/right
++macros/showeach.rc show-each-buffer
+ macros/vile-pager use vile as a pager
+ macros/vileinit.rc sample initialization file
+ macros/vilemenu.rc sample menu for xvile
+Index: cmdtbl
+Prereq: 1.230
+--- vile-9.4l+/cmdtbl 2004-12-07 01:28:55.000000000 +0000
++++ vile-9.4m/cmdtbl 2004-12-14 20:18:42.000000000 +0000
+@@ -97,7 +97,7 @@
+ # in '!' listed, then the flag does nothing, and should be
+ # viewed simply as documentation.
+ #
+-# @Header: /usr/build/vile/vile/RCS/cmdtbl,v 1.230 2004/12/07 01:28:55 tom Exp @
++# @Header: /usr/build/vile/vile/RCS/cmdtbl,v 1.233 2004/12/14 20:18:42 tom Exp @
+ #
+ #
+
+@@ -625,7 +625,7 @@
+ firstbuffer NONE
+ "rewind"
+ "rew!"
+- <go to first buffer in buffer list. (does nothing if \"autobuffer\" set>
++ <go to first buffer in buffer list>
+ firstnonwhite MOTION|MINIBUF
+ "first-nonwhite" !FEWNAMES
+ '^'
+@@ -1686,13 +1686,22 @@
+ edit_buffer NONE
+ "B"
+ "edit-buffer" !FEWNAMES
+- <make or switch to the given buffer; will not look for a file by that name>
++ <make or switch to the given buffer>
++popup_buffer NONE !SMALLER
++ "popup-buffer"
++ "open-window" !FEWNAMES
++ <open window for the given buffer>
++popdown_buffer NONE !SMALLER
++ "popdown-buffer"
++ "close-windows" !FEWNAMES
++ <open all windows for the given buffer>
+ usekreg REDO
+ "use-register" !FEWNAMES
+ '"'
+ <name a register, for use with a following command which references it>
+ userbeep NONE !SMALLER
+ "beep"
++ 'FN-b' KEY_BackTab
+ <force the terminal to ring (or flash, if \"set flash\" is active)>
+ visual NONE
+ "visual"
+Index: configure.in
+Prereq: 1.211
+--- vile-9.4l+/configure.in 2004-12-04 00:42:49.000000000 +0000
++++ vile-9.4m/configure.in 2004-12-10 22:52:59.000000000 +0000
+@@ -1,12 +1,12 @@
+ dnl Process this file with autoconf to produce a configure script.
+-AC_REVISION(@Revision: 1.211 @)
++AC_REVISION(@Revision: 1.214 @)
+ AC_PREREQ(2.13.20030927)
+ rm -f config.cache
+
+ ### Use "configure -with-screen" to override the default configuration, which is
+ ### termcap-based on unix systems.
+
+-dnl @Header: /usr/build/vile/vile/RCS/configure.in,v 1.211 2004/12/04 00:42:49 tom Exp @
++dnl @Header: /usr/build/vile/vile/RCS/configure.in,v 1.214 2004/12/10 22:52:59 tom Exp @
+
+ define(MAKELIST, sh $srcdir/filters/makelist.sh $srcdir/filters/genmake.mak)
+
+@@ -52,6 +52,10 @@
+ CF_LIB_PREFIX
+
+ ### options to control how much we build
++BUILTHDRS="nebind.h neproto.h neexec.h nefunc.h nemode.h nename.h nevars.h nefkeys.h nefsms.h"
++BUILTLIBS=
++BUILTSRCS=
++
+ AC_MSG_CHECKING(if you wish to build only core functions)
+ CF_ARG_DISABLE(extensions,
+ [ --disable-extensions test: build only core functions],
+@@ -287,6 +291,7 @@
+ perl_lib_path=`$PERL -MConfig -e 'print $Config{privlib}'`
+ AC_DEFINE(OPT_PERL)
+ EXTRAOBJS="$EXTRAOBJS perl.o"
++ BUILTSRCS="$BUILTSRCS perl.c"
+ LINK_PREFIX=`$PERL -MConfig -e 'print $Config{shrpenv}'`
+ ac_link="$LINK_PREFIX $ac_link"
+ CF_CHECK_CFLAGS(`$PERL -MExtUtils::Embed -e ccopts`)
+@@ -672,7 +677,7 @@
+ [cf_func_iconv="$withval"],
+ [cf_func_iconv=yes])
+ AC_MSG_RESULT($cf_func_iconv)
+-if test "$cf_func_iconv" == yes ; then
++if test "$cf_func_iconv" = yes ; then
+ AC_DEFINE(OPT_ICONV_FUNCS)
+ test "$cf_cv_func_iconv" != yes && LIBS="$cf_cv_func_iconv $LIBS"
+ fi # test $cf_func_iconv" = yes
+@@ -834,9 +839,10 @@
+
+ if test "$cf_filter_libs" = yes ; then
+ EXTRAOBJS="$EXTRAOBJS builtflt.o"
+- CFLAGS="-I\$(srcdir)/filters $CFLAGS"
++ CPPFLAGS="-I\$(srcdir)/filters $CPPFLAGS"
+ FILTER_LIBS="-Lfilters -lvlflt"
+ LIBBUILTFLT="${LIB_PREFIX}vlflt.a"
++ BUILTHDRS="$BUILTHDRS builtflt.h"
+ BUILTLIBS="$BUILTLIBS filters/$LIBBUILTFLT"
+ AC_DEFINE(OPT_FILTER)
+ else
+@@ -846,7 +852,9 @@
+ fi
+
+ AC_SUBST(EXTRAOBJS)
++AC_SUBST(BUILTHDRS)
+ AC_SUBST(BUILTLIBS)
++AC_SUBST(BUILTSRCS)
+ AC_SUBST(FILTER_LIBS)
+ AC_SUBST(LIBBUILTFLT)
+
+Index: doc/filters.doc
+Prereq: 1.32
+--- vile-9.4l+/doc/filters.doc 2004-11-11 00:47:06.000000000 +0000
++++ vile-9.4m/doc/filters.doc 2004-12-14 00:47:49.000000000 +0000
+@@ -33,7 +33,7 @@
+
+ [ If $VILE_STARTUP_PATH is not defined, the filter checks the
+ "prefix" directory specified when all filters were compiled
+- (default path is /usr/local/share/vile/vile.keyords). ]
++ (default path is /usr/local/share/vile/vile.keywords). ]
+
+ and then here:
+
+@@ -146,6 +146,38 @@
+ language keywords, if any.
+
+
++OPTIONS
++-------
++
++A few options are common to all filters:
++
++ -d is recognized when the filters have been compiled with "DEBUG" defined.
++ This is used in the more complicated filters such as perl and ruby to
++ show the parsing.
++
++ -k FILE
++
++ -q exits the filter before writing the marked-up output. This happens
++ after processing the class definitions, so it is useful in combination
++ with the -v option to simply obtain the class information.
++
++ -t holds the tabstop setting, which can be used in a filter for column
++ computations.
++
++ -v verbose, turns on extra output which can be used for troubleshooting
++ configuration problems.
++
++The C syntax filter recognizes additional options to customize it for Java and
++JavaScript:
++
++ -j Extend name- and literal-syntax to include Java.
++
++ -p Disallow preprocessor lines.
++
++ -s for JavaScript (to support jsmode). This controls whether to allow
++ regular expressions in certain cases.
++
++
+ PROGRAMS
+ --------
+
+@@ -230,4 +262,4 @@
+ The lex filters have been well tested only with flex, which treats newlines
+ differently. Older versions of lex may not support the %x states.
+
+--- @Header: /usr/build/vile/vile/doc/RCS/filters.doc,v 1.32 2004/11/11 00:47:06 tom Exp @
++-- @Header: /usr/build/vile/vile/doc/RCS/filters.doc,v 1.33 2004/12/14 00:47:49 tom Exp @
+Index: doc/macros.doc
+Prereq: 1.93
+--- vile-9.4l+/doc/macros.doc 2004-10-20 22:47:38.000000000 +0000
++++ vile-9.4m/doc/macros.doc 2004-12-12 20:29:24.000000000 +0000
+@@ -774,7 +774,7 @@
+ &mod "N1" "N2" Divide the "N1" by "N2", return remainder.
+ &negate "N" Return -(N).
+ &ascii "S" Return the ASCII code of the first
+- character in "S"
++ character in "S"
+ &random "N"
+ &rnd "N" Random number between 1 and N
+ &abs "N" Absolute value of "N"
+@@ -791,12 +791,12 @@
+ The rest return strings:
+
+ &bind "S" Return the function name bound to the
+- key sequence "S".
++ key sequence "S".
+ &cat "S1" "S2" Concatenate S1 and string "S".
+ &chr "N" Converts numeric "N" to an ASCII character.
+ &cclass "S" Character class (see "show-printable")
+ &env "S" Return the value of the user's environment
+- variable named "S".
++ variable named "S".
+ &gtkey Get a single raw keystroke from the user.
+ &gtsequence Get a complete vile key sequence from user.
+ &left "S" "N" Extract first "N" characters from "S"
+@@ -805,8 +805,8 @@
+ &middle "S" "N1" "N2" Extract "N2" chars at position "N1".
+ &upper "S" Return uppercase version of "S".
+ &trim "S" Remove whitespace at either end of "S",
+- reduce multiple spaces within "S"
+- to just one space each.
++ reduce multiple spaces within "S"
++ to just one space each.
+
+ Boolean/logical functions --
+
+@@ -820,6 +820,9 @@
+ &geq "N1" "N2" Is "N1" numerically not less than "N2"?
+ &greater "N1" "N2" Is "N1" numerically greater than "N2"?
+ &gt "N1" "N2" (same as &greater)
++ &isa "C" "N" Is "N" a member of class "C". Classes
++ include: buffer, color, mode, submode,
++ Majormode.
+ &leq "N1" "N2" Is "N1" numerically not greater than "N2"?
+ &lessthan "N1" "N2" Is "N1" numerically less than "N2"?
+ &lt "N1" "N2" (same as &lessthan)
+@@ -860,19 +863,26 @@
+
+ These all return string values:
+
++ &classof "N" Retrieves the class(es) to which the given
++ name may return. Usually this is a single
++ name, e.g., one of those checked by &isa.
++ If multiple matches are found, the result
++ contains each classname separated by a
++ space.
++
+ &default "MODENAME" Retrieves initial/default value for the
+- given mode or state variable.
++ given mode or state variable.
+
+ &global "MODENAME" Retrieves universal/global mode setting.
+
+- &indirect "S" Evaluate value of "S" as a
+- macro language variable itself.
+- Thus if %foo has value "HOME",
+- then &env &indirect %foo will
+- return the home directory pathname.
++ &indirect "S" Evaluate value of "S" as a macro language
++ variable itself. Thus if %foo has value
++ "HOME", then
++ &env &indirect %foo
++ will return the home directory pathname.
+
+ &local "MODENAME" Retrieves local mode setting (for
+- current buffer).
++ current buffer).
+
+ &lookup "N" "P" The "N" keyword tells which field to use
+ looking for the file "P":
+@@ -890,25 +900,31 @@
+ bin, startup, path, libdir. Note that
+ the directory lists may overlap.
+
++ &mclass "M" Retrieve the class to which the given
++ mode belongs. This is different from
++ &mclass since it distinguishes the modes
++ Return values include: universal buffer
++ window submode Majormode.
++
+ &qpasswd "S" Present "S" to the user and return their
+- response. Each typed character is
+- echoed as '*'. The response is not
+- recallable via the editor's history
+- mechanism.
++ response. Each typed character is
++ echoed as '*'. The response is not
++ recallable via the editor's history
++ mechanism.
+
+ &query "S" Present "S" to the user, and return
+- their typed response.
++ their typed response.
+
+ &date "F" "T" If strftime() is found, format the time "T"
+- using the "F" format. Otherwise, use
+- ctime() to format the time. Times are
+- numbers (see &ftime and &stime).
++ using the "F" format. Otherwise, use
++ ctime() to format the time. Times are
++ numbers (see &ftime and &stime).
+
+ &dquery "S" "D" Present "S" to the user, and return
+- their typed response. If "D" is given,
+- use that as the default response.
+- Otherwise use the previous response
+- as the default.
++ their typed response. If "D" is given,
++ use that as the default response.
++ Otherwise use the previous response
++ as the default.
+
+ &path "N" "P" The "N" keyword tells which field to extract
+ from the pathname "P":
+@@ -1056,7 +1072,6 @@
+ The ~break directive allows early termination of an enclosing
+ while-loop. Extending the above example:
+
+-
+ ; count the occurrences of a pattern in all buffers
+ set nowrapscan
+ set noautobuffer
+@@ -1465,6 +1480,6 @@
+ ========================= end vile.rc =======================
+
+ -----------------------------------
+- @Header: /usr/build/vile/vile/doc/RCS/macros.doc,v 1.93 2004/10/20 22:47:38 tom Exp @
++ @Header: /usr/build/vile/vile/doc/RCS/macros.doc,v 1.94 2004/12/12 20:29:24 tom Exp @
+ -----------------------------------
+
diff --git a/patch_cmds/diffstat/testing/case25.ref b/patch_cmds/diffstat/testing/case25.ref
new file mode 100644
index 0000000..a270cc6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
+ MANIFEST | 3 +-
+ cmdtbl | 15 ++++++++++--
+ configure.in | 16 ++++++++++---
+ doc/filters.doc | 36 ++++++++++++++++++++++++++++--
+ doc/macros.doc | 67 ++++++++++++++++++++++++++++++++++----------------------
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25R.ref b/patch_cmds/diffstat/testing/case25R.ref
new file mode 100644
index 0000000..c594cda
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25R.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ------------------------------------------------
+ MANIFEST | 3 --
+ cmdtbl | 15 ++----------
+ configure.in | 16 +++----------
+ doc/filters.doc | 36 +-----------------------------
+ doc/macros.doc | 67 +++++++++++++++++++++-----------------------------------
+ 6 files changed, 36 insertions(+), 159 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25Rp0.ref b/patch_cmds/diffstat/testing/case25Rp0.ref
new file mode 100644
index 0000000..c594cda
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25Rp0.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ------------------------------------------------
+ MANIFEST | 3 --
+ cmdtbl | 15 ++----------
+ configure.in | 16 +++----------
+ doc/filters.doc | 36 +-----------------------------
+ doc/macros.doc | 67 +++++++++++++++++++++-----------------------------------
+ 6 files changed, 36 insertions(+), 159 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25b.ref b/patch_cmds/diffstat/testing/case25b.ref
new file mode 100644
index 0000000..a270cc6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25b.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
+ MANIFEST | 3 +-
+ cmdtbl | 15 ++++++++++--
+ configure.in | 16 ++++++++++---
+ doc/filters.doc | 36 ++++++++++++++++++++++++++++--
+ doc/macros.doc | 67 ++++++++++++++++++++++++++++++++++----------------------
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25f0.ref b/patch_cmds/diffstat/testing/case25f0.ref
new file mode 100644
index 0000000..72c0992
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25f0.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 58 + 0 - 0 !
+ MANIFEST | 3 2 + 1 - 0 !
+ cmdtbl | 15 12 + 3 - 0 !
+ configure.in | 16 12 + 4 - 0 !
+ doc/filters.doc | 36 34 + 2 - 0 !
+ doc/macros.doc | 67 41 + 26 - 0 !
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25k.ref b/patch_cmds/diffstat/testing/case25k.ref
new file mode 100644
index 0000000..a270cc6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25k.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
+ MANIFEST | 3 +-
+ cmdtbl | 15 ++++++++++--
+ configure.in | 16 ++++++++++---
+ doc/filters.doc | 36 ++++++++++++++++++++++++++++--
+ doc/macros.doc | 67 ++++++++++++++++++++++++++++++++++----------------------
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25p1.ref b/patch_cmds/diffstat/testing/case25p1.ref
new file mode 100644
index 0000000..a270cc6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25p1.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
+ MANIFEST | 3 +-
+ cmdtbl | 15 ++++++++++--
+ configure.in | 16 ++++++++++---
+ doc/filters.doc | 36 ++++++++++++++++++++++++++++--
+ doc/macros.doc | 67 ++++++++++++++++++++++++++++++++++----------------------
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25p9.ref b/patch_cmds/diffstat/testing/case25p9.ref
new file mode 100644
index 0000000..7a6e072
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25p9.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ MANIFEST | 3 +-
+ cmdtbl | 15 ++++++++++---
+ configure.in | 16 ++++++++++----
+ filters.doc | 36 +++++++++++++++++++++++++++++--
+ macros.doc | 67 ++++++++++++++++++++++++++++++++++++-----------------------
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25r1.ref b/patch_cmds/diffstat/testing/case25r1.ref
new file mode 100644
index 0000000..c1f392c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25r1.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
+ MANIFEST | 3 ++-
+ cmdtbl | 15 ++++++++++---
+ configure.in | 16 ++++++++++---
+ doc/filters.doc | 36 ++++++++++++++++++++++++++++--
+ doc/macros.doc | 67 ++++++++++++++++++++++++++++++++++----------------------
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25r2.ref b/patch_cmds/diffstat/testing/case25r2.ref
new file mode 100644
index 0000000..c1f392c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25r2.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
+ MANIFEST | 3 ++-
+ cmdtbl | 15 ++++++++++---
+ configure.in | 16 ++++++++++---
+ doc/filters.doc | 36 ++++++++++++++++++++++++++++--
+ doc/macros.doc | 67 ++++++++++++++++++++++++++++++++++----------------------
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case25u.ref b/patch_cmds/diffstat/testing/case25u.ref
new file mode 100644
index 0000000..a270cc6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case25u.ref
@@ -0,0 +1,7 @@
+ CHANGES | 58 ++++++++++++++++++++++++++++++++++++++++++++++++
+ MANIFEST | 3 +-
+ cmdtbl | 15 ++++++++++--
+ configure.in | 16 ++++++++++---
+ doc/filters.doc | 36 ++++++++++++++++++++++++++++--
+ doc/macros.doc | 67 ++++++++++++++++++++++++++++++++++----------------------
+ 6 files changed, 159 insertions(+), 36 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26.pat b/patch_cmds/diffstat/testing/case26.pat
new file mode 100644
index 0000000..fec3a21
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26.pat
@@ -0,0 +1,1901 @@
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/config.h /tmp/KfNDqvamm0/flwm-1.01/config.h
+--- /tmp/8FTwAYJlot/flwm-1.00/config.h 1999-08-24 22:59:35.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/config.h 2002-03-24 02:02:33.000000000 +0100
+@@ -25,6 +25,12 @@
+ // nothing is done if this is not defined:
+ //#define AUTO_RAISE 0.5
+
++// Perform "smart" autoplacement.
++// New windows are put at positions where they cover as few existing windows
++// as possible. A brute force algorithm is used, so it consumes quite a bit
++// of CPU time.
++#define SMART_PLACEMENT 1
++
+ // set this to zero to remove the multiple-desktop code. This will
+ // make flwm about 20K smaller
+ #define DESKTOPS 1
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/changelog /tmp/KfNDqvamm0/flwm-1.01/debian/changelog
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/changelog 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/changelog 2006-06-30 11:01:41.000000000 +0200
+@@ -1,3 +1,15 @@
++flwm (1.01-1) unstable; urgency=low
++
++ * New upstream release
++ + This release catch the release of the Alt key again. Closes: #246089.
++ + The following patches were applied upstream (Thanks Bill Spitzak).
++ 100_fl_filename_name 101_visible_focus 102_charstruct 103_man_typo
++ 104_g++-4.1_warning 105_double_ampersand 201_background_color
++ + Add 100_double_ampersand to fix atypo in this release.
++ * debian/watch: added.
++
++ -- Bill Allombert <ballombe@debian.org> Fri, 30 Jun 2006 01:17:06 +0200
++
+ flwm (1.00-10) unstable; urgency=low
+
+ * Add patch 104_g++-4.1_warning that fix five warnings.
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patched/100_double_ampersand.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patched/100_double_ampersand.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patched/100_double_ampersand.dpatch 1970-01-01 01:00:00.000000000 +0100
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patched/100_double_ampersand.dpatch 2006-06-30 11:01:41.000000000 +0200
+@@ -0,0 +1 @@
++patching file Menu.C
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patched/100_fl_filename_name.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patched/100_fl_filename_name.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patched/100_fl_filename_name.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patched/100_fl_filename_name.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,2 +0,0 @@
+-patching file main.C
+-Hunk #1 succeeded at 351 (offset -1 lines).
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patched/101_visible_focus.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patched/101_visible_focus.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patched/101_visible_focus.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patched/101_visible_focus.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1 +0,0 @@
+-patching file main.C
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patched/102_charstruct.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patched/102_charstruct.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patched/102_charstruct.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patched/102_charstruct.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1 +0,0 @@
+-patching file Rotated.C
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patched/103_man_typo.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patched/103_man_typo.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patched/103_man_typo.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patched/103_man_typo.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1 +0,0 @@
+-patching file flwm.1
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patched/104_g++-4.1_warning.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patched/104_g++-4.1_warning.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patched/104_g++-4.1_warning.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patched/104_g++-4.1_warning.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,3 +0,0 @@
+-patching file Frame.C
+-patching file Menu.C
+-patching file Rotated.C
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patched/105_double_ampersand.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patched/105_double_ampersand.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patched/105_double_ampersand.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patched/105_double_ampersand.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1 +0,0 @@
+-patching file Menu.C
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patched/201_background_color.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patched/201_background_color.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patched/201_background_color.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patched/201_background_color.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,2 +0,0 @@
+-patching file Frame.C
+-patching file Menu.C
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/00list /tmp/KfNDqvamm0/flwm-1.01/debian/patches/00list
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/00list 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/00list 2006-06-30 11:01:41.000000000 +0200
+@@ -1,8 +1,2 @@
+-100_fl_filename_name
+-101_visible_focus
+-102_charstruct
+-103_man_typo
+-104_g++-4.1_warning
+-105_double_ampersand
++100_double_ampersand
+ 200_Debian_menu
+-201_background_color
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/100_double_ampersand.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/100_double_ampersand.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/100_double_ampersand.dpatch 1970-01-01 01:00:00.000000000 +0100
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/100_double_ampersand.dpatch 2006-06-30 11:01:41.000000000 +0200
+@@ -0,0 +1,19 @@
++#! /bin/sh /usr/share/dpatch/dpatch-run
++## 100_double_ampersand.dpatch by <ballombe@debian.org>
++##
++## All lines beginning with `## DP:' are a description of the patch.
++## DP: fix handling of ampersand in titles in windows list.
++
++@DPATCH@
++diff -urNad flwm-1.01~/Menu.C flwm-1.01/Menu.C
++--- flwm-1.01~/Menu.C 2006-06-30 10:52:34.000000000 +0200
+++++ flwm-1.01/Menu.C 2006-06-30 10:54:31.000000000 +0200
++@@ -98,7 +98,7 @@
++ char* t = buf;
++ while (t < buf+254 && *l) {
++ if (*l=='&') *t++ = *l;
++- *t++ = *l;
+++ *t++ = *l++;
++ }
++ *t = 0;
++ l = buf;
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/100_fl_filename_name.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/100_fl_filename_name.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/100_fl_filename_name.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/100_fl_filename_name.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,20 +0,0 @@
+-#! /bin/sh /usr/share/dpatch/dpatch-run
+-## 100_fl_filename_name.dpatch by Tommi Virtanen <tv@debian.org>
+-##
+-## All lines beginning with `## DP:' are a description of the patch.
+-## DP: Transition from fltk-1.0 to fltk-1.1.
+-## DP: Applied upstream.
+-
+-@DPATCH@
+-diff -urNad flwm-1.00~/main.C flwm-1.00/main.C
+---- flwm-1.00~/main.C 2006-02-23 21:41:10.000000000 +0100
+-+++ flwm-1.00/main.C 2006-02-23 21:41:39.000000000 +0100
+-@@ -352,7 +352,7 @@
+- }
+-
+- int main(int argc, char** argv) {
+-- program_name = filename_name(argv[0]);
+-+ program_name = fl_filename_name(argv[0]);
+- int i; if (Fl::args(argc, argv, i, arg) < argc) Fl::error(
+- "options are:\n"
+- " -d[isplay] host:#.#\tX display & screen to use\n"
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/101_visible_focus.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/101_visible_focus.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/101_visible_focus.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/101_visible_focus.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,19 +0,0 @@
+-#! /bin/sh /usr/share/dpatch/dpatch-run
+-## 101_visible_focus.dpatch by Bill Allombert <ballombe@debian.org>
+-##
+-## All lines beginning with `## DP:' are a description of the patch.
+-## DP: Restore fltk-1.0 focus behaviour
+-## DP: (Applied upstream)
+-
+-@DPATCH@
+-diff -urNad flwm-1.00~/main.C flwm-1.00/main.C
+---- flwm-1.00~/main.C 2006-02-23 21:41:57.000000000 +0100
+-+++ flwm-1.00/main.C 2006-02-23 21:42:21.000000000 +0100
+-@@ -298,6 +298,7 @@
+- XFree((void *)wins);
+-
+- #endif
+-+ Fl::visible_focus(0);
+- }
+-
+- ////////////////////////////////////////////////////////////////
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/102_charstruct.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/102_charstruct.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/102_charstruct.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/102_charstruct.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,45 +0,0 @@
+-#! /bin/sh /usr/share/dpatch/dpatch-run
+-## 102_charstruct.dpatch by Tommi Virtanen <tv@debian.org>
+-##
+-## All lines beginning with `## DP:' are a description of the patch.
+-## DP: Support fonts for which fontstruct->per_char is NULL.
+-## DP: (Applied upstream).
+-
+-@DPATCH@
+-diff -urNad flwm-1.00~/Rotated.C flwm-1.00/Rotated.C
+---- flwm-1.00~/Rotated.C 2006-02-23 21:42:31.000000000 +0100
+-+++ flwm-1.00/Rotated.C 2006-02-23 21:43:03.000000000 +0100
+-@@ -116,20 +116,27 @@
+- /* font needs rotation ... */
+- /* loop through each character ... */
+- for (ichar = min_char; ichar <= max_char; ichar++) {
+-+ XCharStruct *charstruct;
+-
+- index = ichar-fontstruct->min_char_or_byte2;
+--
+-+
+-+ if (fontstruct->per_char) {
+-+ charstruct = &fontstruct->per_char[index];
+-+ } else {
+-+ charstruct = &fontstruct->min_bounds;
+-+ }
+-+
+- /* per char dimensions ... */
+- ascent = rotfont->per_char[ichar].ascent =
+-- fontstruct->per_char[index].ascent;
+-+ charstruct->ascent;
+- descent = rotfont->per_char[ichar].descent =
+-- fontstruct->per_char[index].descent;
+-+ charstruct->descent;
+- lbearing = rotfont->per_char[ichar].lbearing =
+-- fontstruct->per_char[index].lbearing;
+-+ charstruct->lbearing;
+- rbearing = rotfont->per_char[ichar].rbearing =
+-- fontstruct->per_char[index].rbearing;
+-+ charstruct->rbearing;
+- rotfont->per_char[ichar].width =
+-- fontstruct->per_char[index].width;
+-+ charstruct->width;
+-
+- /* some space chars have zero body, but a bitmap can't have ... */
+- if (!ascent && !descent)
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/103_man_typo.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/103_man_typo.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/103_man_typo.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/103_man_typo.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,19 +0,0 @@
+-#! /bin/sh /usr/share/dpatch/dpatch-run
+-## 103_man_typo.dpatch by Bill Allombert <ballombe@debian.org>
+-##
+-## All lines beginning with `## DP:' are a description of the patch.
+-## DP: Fix typo in man page.
+-
+-@DPATCH@
+-diff -urNad flwm-1.00~/flwm.1 flwm-1.00/flwm.1
+---- flwm-1.00~/flwm.1 2006-02-23 21:54:54.000000000 +0100
+-+++ flwm-1.00/flwm.1 2006-02-23 21:55:39.000000000 +0100
+-@@ -78,7 +78,7 @@
+-
+- .SH MENU ITEMS
+-
+--Flwm can launch programs from it's menu. This is controlled by files
+-+Flwm can launch programs from its menu. This is controlled by files
+- in the directory
+- .B ~/.wmx
+- (this was chosen to be compatible with wmx and wm2).
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/104_g++-4.1_warning.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/104_g++-4.1_warning.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/104_g++-4.1_warning.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/104_g++-4.1_warning.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,58 +0,0 @@
+-#! /bin/sh /usr/share/dpatch/dpatch-run
+-## 104_g++-4.1-warning.dpatch by Bill Allombert <ballombe@debian.org>
+-##
+-## All lines beginning with `## DP:' are a description of the patch.
+-## DP: Fix 5 g++ -4.1 warnings
+-
+-@DPATCH@
+-diff -urNad flwm-1.00~/Frame.C flwm-1.00/Frame.C
+---- flwm-1.00~/Frame.C 2006-06-10 13:41:04.000000000 +0200
+-+++ flwm-1.00/Frame.C 2006-06-10 13:41:08.000000000 +0200
+-@@ -1681,15 +1681,15 @@
+- int format;
+- unsigned long n, extra;
+- int status;
+-- void* prop;
+-+ uchar* prop;
+- status = XGetWindowProperty(fl_display, w,
+- a, 0L, 256L, False, type, &realType,
+-- &format, &n, &extra, (uchar**)&prop);
+-+ &format, &n, &extra, &prop);
+- if (status != Success) return 0;
+- if (!prop) return 0;
+- if (!n) {XFree(prop); return 0;}
+- if (np) *np = (int)n;
+-- return prop;
+-+ return (void *)prop;
+- }
+-
+- int Frame::getIntProperty(Atom a, Atom type, int deflt) const {
+-diff -urNad flwm-1.00~/Menu.C flwm-1.00/Menu.C
+---- flwm-1.00~/Menu.C 2006-06-10 13:41:04.000000000 +0200
+-+++ flwm-1.00/Menu.C 2006-06-10 13:41:08.000000000 +0200
+-@@ -246,8 +246,8 @@
+- if (fork() == 0) {
+- if (fork() == 0) {
+- close(ConnectionNumber(fl_display));
+-- if (name == xtermname) execlp(name, name, "-ut", 0);
+-- else execl(name, name, 0);
+-+ if (name == xtermname) execlp(name, name, "-ut", NULL);
+-+ else execl(name, name, NULL);
+- fprintf(stderr, "flwm: can't run %s, %s\n", name, strerror(errno));
+- XBell(fl_display, 70);
+- exit(1);
+-diff -urNad flwm-1.00~/Rotated.C flwm-1.00/Rotated.C
+---- flwm-1.00~/Rotated.C 2006-06-10 13:41:07.000000000 +0200
+-+++ flwm-1.00/Rotated.C 2006-06-10 13:41:41.000000000 +0200
+-@@ -242,9 +242,9 @@
+- }
+-
+- for (ichar = 0; ichar < min_char; ichar++)
+-- rotfont->per_char[ichar] = rotfont->per_char['?'];
+-+ rotfont->per_char[ichar] = rotfont->per_char[(int)'?'];
+- for (ichar = max_char+1; ichar < 256; ichar++)
+-- rotfont->per_char[ichar] = rotfont->per_char['?'];
+-+ rotfont->per_char[ichar] = rotfont->per_char[(int)'?'];
+-
+- /* free pixmap and GC ... */
+- XFreePixmap(dpy, canvas);
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/105_double_ampersand.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/105_double_ampersand.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/105_double_ampersand.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/105_double_ampersand.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,48 +0,0 @@
+-#! /bin/sh /usr/share/dpatch/dpatch-run
+-## 105_double_ampersand.dpatch by Bill Allombert <ballombe@debian.org>
+-##
+-## All lines beginning with `## DP:' are a description of the patch.
+-## DP: Handle & in window titles correctly in the windows list.
+-
+-@DPATCH@
+-diff -urNad flwm-1.00~/Menu.C flwm-1.00/Menu.C
+---- flwm-1.00~/Menu.C 2006-03-24 00:02:57.000000000 +0100
+-+++ flwm-1.00/Menu.C 2006-03-24 00:03:18.000000000 +0100
+-@@ -20,6 +20,24 @@
+- #include <dirent.h>
+- #include <sys/stat.h>
+-
+-+static char *double_ampersand(const char *s)
+-+{
+-+ long i,l;
+-+ for(i=0,l=0;s[i];i++)
+-+ if (s[i]=='&')
+-+ l++;
+-+ char *c = new (char [l+i+1]);
+-+ for(i=0,l=0;s[i];i++)
+-+ {
+-+ c[l++]=s[i];
+-+ if (s[i]=='&')
+-+ c[l++]=s[i];
+-+ }
+-+ c[l]=0;
+-+ return c;
+-+}
+-+
+-+
+- // it is possible for the window to be deleted or withdrawn while
+- // the menu is up. This will detect that case (with reasonable
+- // reliability):
+-@@ -90,8 +108,11 @@
+- }
+- fl_font(o->font, o->size);
+- fl_color((Fl_Color)o->color);
+-- const char* l = f->label(); if (!l) l = "unnamed";
+-+ const char* l = f->label();
+-+ if (!l) l = "unnamed";
+-+ else l = double_ampersand(f->label());
+- fl_draw(l, X+MENU_ICON_W+3, Y, W-MENU_ICON_W-3, H, align);
+-+ delete l;
+- }
+-
+- static void
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/200_Debian_menu.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/200_Debian_menu.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/200_Debian_menu.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/200_Debian_menu.dpatch 2006-06-30 11:01:41.000000000 +0200
+@@ -5,10 +5,10 @@
+ ## DP: Add Debian menu support.
+
+ @DPATCH@
+-diff -urNad flwm-1.00~/Menu.C flwm-1.00/Menu.C
+---- flwm-1.00~/Menu.C 2006-06-10 22:22:59.000000000 +0200
+-+++ flwm-1.00/Menu.C 2006-06-10 22:23:00.000000000 +0200
+-@@ -395,7 +395,11 @@
++diff -urNad flwm-1.01~/Menu.C flwm-1.01/Menu.C
++--- flwm-1.01~/Menu.C 2006-06-30 09:02:01.000000000 +0200
+++++ flwm-1.01/Menu.C 2006-06-30 09:02:05.000000000 +0200
++@@ -393,7 +393,11 @@
+ strcpy(path, home);
+ if (path[strlen(path)-1] != '/') strcat(path, "/");
+ strcat(path, ".wmx/");
+@@ -21,9 +21,9 @@
+ if (st.st_mtime == wmx_time) return;
+ wmx_time = st.st_mtime;
+ num_wmx = 0;
+-diff -urNad flwm-1.00~/flwm.1 flwm-1.00/flwm.1
+---- flwm-1.00~/flwm.1 2006-06-10 22:22:59.000000000 +0200
+-+++ flwm-1.00/flwm.1 2006-06-10 22:23:00.000000000 +0200
++diff -urNad flwm-1.01~/flwm.1 flwm-1.01/flwm.1
++--- flwm-1.01~/flwm.1 2006-06-30 09:02:01.000000000 +0200
+++++ flwm-1.01/flwm.1 2006-06-30 09:02:05.000000000 +0200
+ @@ -102,10 +102,13 @@
+ chmod +x !*
+ .fi
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/201_background_color.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/201_background_color.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/201_background_color.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/201_background_color.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,57 +0,0 @@
+-#! /bin/sh /usr/share/dpatch/dpatch-run
+-## 201_background_color.dpatch by Bill Allombert <ballombe@debian.org>
+-##
+-## All lines beginning with `## DP:' are a description of the patch.
+-## DP: Fix -fg and -bg options
+-
+-@DPATCH@
+-diff -urNad flwm-1.00~/Frame.C flwm-1.00/Frame.C
+---- flwm-1.00~/Frame.C 2006-06-10 22:24:58.000000000 +0200
+-+++ flwm-1.00/Frame.C 2006-06-10 22:25:00.000000000 +0200
+-@@ -88,6 +88,7 @@
+- min_w_button.callback(button_cb_static);
+- end();
+- box(FL_NO_BOX); // relies on background color erasing interior
+-+ labelcolor(FL_FOREGROUND_COLOR);
+- next = first;
+- first = this;
+-
+-@@ -674,7 +675,7 @@
+- XSetWindowAttributes a;
+- a.background_pixel = fl_xpixel(FL_SELECTION_COLOR);
+- XChangeWindowAttributes(fl_display, fl_xid(this), CWBackPixel, &a);
+-- labelcolor(contrast(FL_BLACK, FL_SELECTION_COLOR));
+-+ labelcolor(contrast(FL_FOREGROUND_COLOR, FL_SELECTION_COLOR));
+- XClearArea(fl_display, fl_xid(this), 2, 2, w()-4, h()-4, 1);
+- #else
+- #if defined(SHOW_CLOCK)
+-@@ -694,7 +695,7 @@
+- XSetWindowAttributes a;
+- a.background_pixel = fl_xpixel(FL_GRAY);
+- XChangeWindowAttributes(fl_display, fl_xid(this), CWBackPixel, &a);
+-- labelcolor(FL_BLACK);
+-+ labelcolor(FL_FOREGROUND_COLOR);
+- XClearArea(fl_display, fl_xid(this), 2, 2, w()-4, h()-4, 1);
+- #else
+- #if defined(SHOW_CLOCK)
+-diff -urNad flwm-1.00~/Menu.C flwm-1.00/Menu.C
+---- flwm-1.00~/Menu.C 2006-06-10 22:24:59.000000000 +0200
+-+++ flwm-1.00/Menu.C 2006-06-10 22:25:00.000000000 +0200
+-@@ -99,7 +99,7 @@
+- if (h < 3) h = 3;
+- if (y+h > SCREEN_H) y = SCREEN_H-h;
+- if (y < 0) y = 0;
+-- fl_color(FL_BLACK);
+-+ fl_color(FL_FOREGROUND_COLOR);
+- if (c->state() == ICONIC)
+- fl_rect(X+x+SCREEN_DX, Y+y+SCREEN_DX, w, h);
+- else
+-@@ -304,7 +304,7 @@
+- m.shortcut(0);
+- m.labelfont(MENU_FONT_SLOT);
+- m.labelsize(MENU_FONT_SIZE);
+-- m.labelcolor(FL_BLACK);
+-+ m.labelcolor(FL_FOREGROUND_COLOR);
+- }
+-
+- #if WMX_MENU_ITEMS
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/patches/202_background_color_2.dpatch /tmp/KfNDqvamm0/flwm-1.01/debian/patches/202_background_color_2.dpatch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/patches/202_background_color_2.dpatch 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/patches/202_background_color_2.dpatch 1970-01-01 01:00:00.000000000 +0100
+@@ -1,92 +0,0 @@
+-#! /bin/sh /usr/share/dpatch/dpatch-run
+-## 203_background_color.dpatch by <ballombe@debian.org>
+-##
+-## All lines beginning with `## DP:' are a description of the patch.
+-## DP: fix the -fg -bg, -bg2 options.
+-
+-@DPATCH@
+-diff -urNad flwm-1.00~/Menu.C flwm-1.00/Menu.C
+---- flwm-1.00~/Menu.C 2006-02-23 21:32:53.000000000 +0100
+-+++ flwm-1.00/Menu.C 2006-02-23 21:36:32.000000000 +0100
+-@@ -172,10 +172,14 @@
+- new_desktop_input = new Fl_Input(10,30,170,25,"New desktop name:");
+- new_desktop_input->align(FL_ALIGN_TOP_LEFT);
+- new_desktop_input->labelfont(FL_BOLD);
+-+ new_desktop_input->labelcolor(FL_FOREGROUND_COLOR);
+-+
+- Fl_Return_Button* b = new Fl_Return_Button(100,60,80,20,"OK");
+- b->callback(new_desktop_ok_cb);
+-+ b->labelcolor(FL_FOREGROUND_COLOR);
+- Fl_Button* b2 = new Fl_Button(10,60,80,20,"Cancel");
+- b2->callback(cancel_cb);
+-+ b2->labelcolor(FL_FOREGROUND_COLOR);
+- w->set_non_modal();
+- w->end();
+- }
+-@@ -217,10 +221,13 @@
+- w = new FrameWindow(190,90);
+- Fl_Box* l = new Fl_Box(0, 0, 190, 60, "Really log out?");
+- l->labelfont(FL_BOLD);
+-+ l->labelcolor(FL_FOREGROUND_COLOR);
+- Fl_Return_Button* b = new Fl_Return_Button(100,60,80,20,"OK");
+- b->callback(exit_cb);
+-+ b->labelcolor(FL_FOREGROUND_COLOR);
+- Fl_Button* b2 = new Fl_Button(10,60,80,20,"Cancel");
+- b2->callback(cancel_cb);
+-+ b2->labelcolor(FL_FOREGROUND_COLOR);
+- w->set_non_modal();
+- w->end();
+- }
+-@@ -280,10 +287,10 @@
+- m.label(data);
+- m.flags = 0;
+- m.labeltype(FL_NORMAL_LABEL);
+-+ m.labelcolor(FL_FOREGROUND_COLOR);
+- m.shortcut(0);
+- m.labelfont(MENU_FONT_SLOT);
+- m.labelsize(MENU_FONT_SIZE);
+-- m.labelcolor(FL_FOREGROUND_COLOR);
+- }
+-
+- #if WMX_MENU_ITEMS
+-@@ -513,6 +520,7 @@
+- if (c->state() == UNMAPPED || c->transient_for()) continue;
+- init(menu[n],(char*)c);
+- menu[n].labeltype(FRAME_LABEL);
+-+ menu[n].labelcolor(FL_FOREGROUND_COLOR);
+- menu[n].callback(frame_callback, c);
+- if (is_active_frame(c)) preset = menu+n;
+- n++;
+-@@ -542,6 +550,7 @@
+- if (c->desktop() == d || !c->desktop() && d == Desktop::current()) {
+- init(menu[n],(char*)c);
+- menu[n].labeltype(FRAME_LABEL);
+-+ menu[n].labelcolor(FL_FOREGROUND_COLOR);
+- menu[n].callback(d == Desktop::current() ?
+- frame_callback : move_frame_callback, c);
+- if (d == Desktop::current() && is_active_frame(c)) preset = menu+n;
+-@@ -589,7 +598,10 @@
+- if (one_desktop)
+- #endif
+- if (!level)
+-+ {
+- menu[n].labeltype(TEXT_LABEL);
+-+ menu[n].labelcolor(FL_FOREGROUND_COLOR);
+-+ }
+-
+- int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1;
+- if (nextlev < level) {
+-@@ -621,8 +633,11 @@
+- if (one_desktop)
+- #endif
+- // fix the menus items so they are indented to align with window names:
+-- while (menu[n].label()) menu[n++].labeltype(TEXT_LABEL);
+--
+-+ while (menu[n].label())
+-+ {
+-+ menu[n].labelcolor(FL_FOREGROUND_COLOR);
+-+ menu[n++].labeltype(TEXT_LABEL);
+-+ }
+- const Fl_Menu_Item* picked =
+- menu->popup(Fl::event_x(), Fl::event_y(), 0, preset);
+- if (picked && picked->callback()) picked->do_callback(0);
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/debian/watch /tmp/KfNDqvamm0/flwm-1.01/debian/watch
+--- /tmp/8FTwAYJlot/flwm-1.00/debian/watch 1970-01-01 01:00:00.000000000 +0100
++++ /tmp/KfNDqvamm0/flwm-1.01/debian/watch 2006-06-30 11:01:41.000000000 +0200
+@@ -0,0 +1,3 @@
++# Site Directory Pattern Version Script
++version=2
++http://flwm.sourceforge.net/flwm-(.*)\.tgz debian uupdate
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/flwm.1 /tmp/KfNDqvamm0/flwm-1.01/flwm.1
+--- /tmp/8FTwAYJlot/flwm-1.00/flwm.1 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/flwm.1 2006-06-30 11:01:41.000000000 +0200
+@@ -184,14 +184,14 @@
+ the keyboard, use left arrow to go to the desktop names, move up and
+ down to the other desktop).
+
+-If a desktop is empty you can delete it. It's sub menu will show
++If a desktop is empty you can delete it. Its sub menu will show
+ .B delete this desktop.
+ Pick that and the desktop is gone.
+
+ .B Sticky
+ is a special "desktop": windows on it appear on all desktops. To make
+ a window "sticky" switch to the Sticky desktop and pick the window off
+-it's current desktop (thus "moving" it to the Sticky desktop). To
++its current desktop (thus "moving" it to the Sticky desktop). To
+ "unstick" a window go to another desktop and pick the window off the
+ sticky desktop menu.
+
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/flwm_wmconfig /tmp/KfNDqvamm0/flwm-1.01/flwm_wmconfig
+--- /tmp/8FTwAYJlot/flwm-1.00/flwm_wmconfig 1999-04-26 21:09:10.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/flwm_wmconfig 2000-09-19 18:38:37.000000000 +0200
+@@ -16,7 +16,9 @@
+ set name ""
+ set exec ""
+ while {[gets $f list]>=0} {
+- if [llength $list]<3 continue
++ set n 0
++ catch {set n [llength $list]}
++ if $n<3 continue
+ set tag [lindex $list 1]
+ set value [lrange $list 2 1000]
+ if [llength $value]==1 {set value [lindex $value 0]}
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/Frame.C /tmp/KfNDqvamm0/flwm-1.01/Frame.C
+--- /tmp/8FTwAYJlot/flwm-1.00/Frame.C 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/Frame.C 2006-06-29 08:08:35.000000000 +0200
+@@ -8,6 +8,7 @@
+ #include <FL/fl_draw.H>
+ #include "Rotated.H"
+
++
+ static Atom wm_state = 0;
+ static Atom wm_change_state;
+ static Atom wm_protocols;
+@@ -63,7 +64,7 @@
+ // passed for an already-existing window when the window manager is
+ // starting up. If so we don't want to alter the state, size, or
+ // position. If null than this is a MapRequest of a new window.
+-Frame::Frame(Window window, XWindowAttributes* existing) :
++Frame::Frame(XWindow window, XWindowAttributes* existing) :
+ Fl_Window(0,0),
+ window_(window),
+ state_flags_(0),
+@@ -78,6 +79,9 @@
+ max_w_button(BUTTON_LEFT,BUTTON_TOP+BUTTON_H,BUTTON_W,BUTTON_H,"w"),
+ min_w_button(BUTTON_LEFT,BUTTON_TOP+2*BUTTON_H,BUTTON_W,BUTTON_H,"W")
+ {
++#if FL_MAJOR_VERSION > 1
++ clear_double_buffer();
++#endif
+ close_button.callback(button_cb_static);
+ iconize_button.callback(button_cb_static);
+ max_h_button.type(FL_TOGGLE_BUTTON);
+@@ -224,20 +228,9 @@
+ show_hide_buttons();
+
+ if (autoplace && !existing && !(transient_for() && (x() || y()))) {
+- // autoplacement (stupid version for now)
+- x(Root->x()+(Root->w()-w())/2);
+- y(Root->y()+(Root->h()-h())/2);
+- // move it until it does not hide any existing windows:
+- const int delta = TITLE_WIDTH+LEFT;
+- for (Frame* f = next; f; f = f->next) {
+- if (f->x()+delta > x() && f->y()+delta > y() &&
+- f->x()+f->w()-delta < x()+w() && f->y()+f->h()-delta < y()+h()) {
+- x(max(x(),f->x()+delta));
+- y(max(y(),f->y()+delta));
+- f = this;
+- }
+- }
++ place_window();
+ }
++
+ // move window so contents and border are visible:
+ x(force_x_onscreen(x(), w()));
+ y(force_y_onscreen(y(), h()));
+@@ -261,7 +254,8 @@
+ sattr.bit_gravity = NorthWestGravity;
+ sattr.override_redirect = 1;
+ sattr.background_pixel = fl_xpixel(FL_GRAY);
+- Fl_X::set_xid(this, XCreateWindow(fl_display, fl_xid(Root),
++ Fl_X::set_xid(this, XCreateWindow(fl_display,
++ RootWindow(fl_display,fl_screen),
+ x(), y(), w(), h(), 0,
+ fl_visual->depth,
+ InputOutput,
+@@ -278,15 +272,140 @@
+ sendConfigureNotify(); // many apps expect this even if window size unchanged
+
+ #if CLICK_RAISES || CLICK_TO_TYPE
+- XGrabButton(fl_display, AnyButton, AnyModifier, window, False,
+- ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
++ if (!dont_set_event_mask)
++ XGrabButton(fl_display, AnyButton, AnyModifier, window, False,
++ ButtonPressMask, GrabModeSync, GrabModeAsync, None, None);
+ #endif
+
+ if (state_ == NORMAL) {
+ XMapWindow(fl_display, fl_xid(this));
+ if (!existing) activate_if_transient();
+ }
++ set_visible();
++}
++
++#if SMART_PLACEMENT
++// Helper functions for "smart" window placement.
++int overlap1(int p1, int l1, int p2, int l2) {
++ int ret = 0;
++ if(p1 <= p2 && p2 <= p1 + l1) {
++ ret = min(p1 + l1 - p2, l2);
++ } else if (p2 <= p1 && p1 <= p2 + l2) {
++ ret = min(p2 + l2 - p1, l1);
++ }
++ return ret;
++}
++
++int overlap(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
++ return (overlap1(x1, w1, x2, w2) * overlap1(y1, h1, y2, h2));
++}
++
++// Compute the overlap with existing windows.
++// For normal windows the overlapping area is taken into account plus a
++// constant value for every overlapping window.
++// The active window counts twice.
++// For iconic windows half the overlapping area is taken into account.
++int getOverlap(int x, int y, int w, int h, Frame *first, Frame *self) {
++ int ret = 0;
++ short state;
++ for (Frame* f = first; f; f = f->next) {
++ if (f != self) {
++ state = f->state();
++ if (state == NORMAL || state == ICONIC) {
++ int o = overlap(x, y, w, h, f->x(), f->y(), f->w(), f->h());
++ if (state == NORMAL) {
++ ret = ret + o + (o>0?40000:0) + (o * f->active());
++ } else if (state == ICONIC) {
++ ret = ret + o/2;
++ }
++ }
++ }
++ }
++ return ret;
++}
++
++// autoplacement (brute force version for now)
++void Frame::place_window() {
++ int min_overlap = -1;
++ int tmp_x, tmp_y, tmp_o;
++ int best_x = 0;
++ int best_y = 0;
++ int _w = w();
++ int _h = h();
++ int max_x = Root->x() + Root->w();
++ int max_y = Root->y() + Root->h();
++
++ Frame *f1 = Frame::first;
++ for(int i=0;; i++) {
++ if (i==0) {
++ tmp_x = 0;
++ } else if (i==1) {
++ tmp_x = max_x - _w;
++ } else {
++ if (f1 == this) {
++ f1 = f1->next;
++ }
++ if (!f1) {
++ break;
++ }
++ tmp_x = f1->x() + f1->w();
++ f1 = f1->next;
++ }
++ Frame *f2 = Frame::first;
++ for(int j=0;; j++) {
++ if (j==0) {
++ tmp_y = 0;
++ } else if (j==1) {
++ tmp_y = max_y - _h;
++ } else {
++ if (f2 == this) {
++ f2 = f2->next;
++ }
++ if (!f2) {
++ break;
++ }
++ tmp_y = f2->y() + f2->h();
++ f2 = f2->next;
++ }
++
++ if ((tmp_x + _w <= max_x) && (tmp_y + _h <= max_y)) {
++ tmp_o = getOverlap(tmp_x, tmp_y, _w, _h, Frame::first, this);
++ if(tmp_o < min_overlap || min_overlap < 0) {
++ best_x = tmp_x;
++ best_y = tmp_y;
++ min_overlap = tmp_o;
++ if (min_overlap == 0) {
++ break;
++ }
++ }
++ }
++ }
++ if (min_overlap == 0) {
++ break;
++ }
++ }
++ x(best_x);
++ y(best_y);
++}
++
++#else
++
++// autoplacement (stupid version for now)
++void Frame::place_window() {
++ x(Root->x()+(Root->w()-w())/2);
++ y(Root->y()+(Root->h()-h())/2);
++ // move it until it does not hide any existing windows:
++ const int delta = TITLE_WIDTH+LEFT;
++ for (Frame* f = next; f; f = f->next) {
++ if (f->x()+delta > x() && f->y()+delta > y() &&
++ f->x()+f->w()-delta < x()+w() && f->y()+f->h()-delta < y()+h()) {
++ x(max(x(),f->x()+delta));
++ y(max(y(),f->y()+delta));
++ f = this;
++ }
++ }
+ }
++#endif
+
+ // modify the passed X & W to a legal horizontal window position
+ int Frame::force_x_onscreen(int X, int W) {
+@@ -334,10 +453,12 @@
+ // a legal state value to this location:
+ state_ = UNMAPPED;
+
++#if FL_MAJOR_VERSION < 2
+ // fix fltk bug:
+ fl_xfocus = 0;
+ fl_xmousewin = 0;
+ Fl::focus_ = 0;
++#endif
+
+ // remove any pointers to this:
+ Frame** cp; for (cp = &first; *cp; cp = &((*cp)->next))
+@@ -555,7 +676,7 @@
+ // see if they set "input hint" to non-zero:
+ // prop[3] should be nonzero but the only example of this I have
+ // found is Netscape 3.0 and it sets it to zero...
+- if (!shown() && (prop[0]&4) /*&& prop[3]*/) set_flag(MODAL);
++ if (!shown() && (prop[0]&4) /*&& prop[3]*/) set_flag(::MODAL);
+
+ // see if it is forcing the iconize button back on. This makes
+ // transient_for act like group instead...
+@@ -579,7 +700,7 @@
+ delete[] window_Colormaps;
+ }
+ int n;
+- Window* cw = (Window*)getProperty(wm_colormap_windows, XA_WINDOW, &n);
++ XWindow* cw = (XWindow*)getProperty(wm_colormap_windows, XA_WINDOW, &n);
+ if (cw) {
+ colormapWinCount = n;
+ colormapWindows = cw;
+@@ -645,7 +766,7 @@
+ int Frame::activate(int warp) {
+ // see if a modal & newer window is up:
+ for (Frame* c = first; c && c != this; c = c->next)
+- if (c->flag(MODAL) && c->transient_for() == this)
++ if (c->flag(::MODAL) && c->transient_for() == this)
+ if (c->activate(warp)) return 1;
+ // ignore invisible windows:
+ if (state() != NORMAL || w() <= dwidth) return 0;
+@@ -671,14 +792,14 @@
+ if (active_ != this) {
+ if (active_) active_->deactivate();
+ active_ = this;
+-#if defined(ACTIVE_COLOR)
++#ifdef ACTIVE_COLOR
+ XSetWindowAttributes a;
+ a.background_pixel = fl_xpixel(FL_SELECTION_COLOR);
+ XChangeWindowAttributes(fl_display, fl_xid(this), CWBackPixel, &a);
+ labelcolor(contrast(FL_FOREGROUND_COLOR, FL_SELECTION_COLOR));
+ XClearArea(fl_display, fl_xid(this), 2, 2, w()-4, h()-4, 1);
+ #else
+-#if defined(SHOW_CLOCK)
++#ifdef SHOW_CLOCK
+ redraw();
+ #endif
+ #endif
+@@ -691,14 +812,14 @@
+ // this private function should only be called by constructor and if
+ // the window is active():
+ void Frame::deactivate() {
+-#if defined(ACTIVE_COLOR)
++#ifdef ACTIVE_COLOR
+ XSetWindowAttributes a;
+ a.background_pixel = fl_xpixel(FL_GRAY);
+ XChangeWindowAttributes(fl_display, fl_xid(this), CWBackPixel, &a);
+ labelcolor(FL_FOREGROUND_COLOR);
+ XClearArea(fl_display, fl_xid(this), 2, 2, w()-4, h()-4, 1);
+ #else
+-#if defined(SHOW_CLOCK)
++#ifdef SHOW_CLOCK
+ redraw();
+ #endif
+ #endif
+@@ -738,9 +859,9 @@
+ switch (newstate) {
+ case UNMAPPED:
+ throw_focus();
+- set_state_flag(IGNORE_UNMAP);
+ XUnmapWindow(fl_display, fl_xid(this));
+- XUnmapWindow(fl_display, window_);
++ //set_state_flag(IGNORE_UNMAP);
++ //XUnmapWindow(fl_display, window_);
+ XRemoveFromSaveSet(fl_display, window_);
+ break;
+ case NORMAL:
+@@ -754,9 +875,9 @@
+ XAddToSaveSet(fl_display, window_);
+ } else if (oldstate == NORMAL) {
+ throw_focus();
+- set_state_flag(IGNORE_UNMAP);
+ XUnmapWindow(fl_display, fl_xid(this));
+- XUnmapWindow(fl_display, window_);
++ //set_state_flag(IGNORE_UNMAP);
++ //XUnmapWindow(fl_display, window_);
+ } else {
+ return; // don't setStateProperty IconicState multiple times
+ }
+@@ -906,10 +1027,10 @@
+ int minh = (nh < h()) ? nh : h();
+ XClearArea(fl_display, fl_xid(this), 0, minh-BOTTOM, w(), BOTTOM, 1);
+ // see if label or close box moved, erase the minimum area:
+- int old_label_y = label_y;
+- int old_label_h = label_h;
++// int old_label_y = label_y;
++// int old_label_h = label_h;
+ h(nh); show_hide_buttons();
+-#ifdef SHOW_CLOCK
++#if 1 //def SHOW_CLOCK
+ int t = label_y + 3; // we have to clear the entire label area
+ #else
+ int t = nh;
+@@ -1076,6 +1197,12 @@
+
+ // make sure fltk does not try to set the window size:
+ void Frame::resize(int, int, int, int) {}
++// For fltk2.0:
++void Frame::layout() {
++#if FL_MAJOR_VERSION>1
++ layout_damage(0); // actually this line is not needed in newest cvs fltk2.0
++#endif
++}
+
+ ////////////////////////////////////////////////////////////////
+
+@@ -1111,19 +1238,28 @@
+
+ ////////////////////////////////////////////////////////////////
+ // Drawing code:
++#if FL_MAJOR_VERSION>1
++# include <fltk/Box.h>
++#endif
+
+ void Frame::draw() {
+ if (flag(NO_BORDER)) return;
+ if (!flag(THIN_BORDER)) Fl_Window::draw();
+ if (damage() != FL_DAMAGE_CHILD) {
+-#if ACTIVE_COLOR
++#ifdef ACTIVE_COLOR
+ fl_frame2(active() ? "AAAAJJWW" : "AAAAJJWWNNTT",0,0,w(),h());
+ if (active()) {
+ fl_color(FL_GRAY_RAMP+('N'-'A'));
+ fl_xyline(2, h()-3, w()-3, 2);
+ }
+ #else
++# if FL_MAJOR_VERSION>1
++ static fltk::FrameBox framebox(0,"AAAAJJWWNNTT");
++ drawstyle(style(),fltk::INVISIBLE); // INVISIBLE = draw edge only
++ framebox.draw(Rectangle(w(),h()));
++# else
+ fl_frame("AAAAWWJJTTNN",0,0,w(),h());
++# endif
+ #endif
+ if (!flag(THIN_BORDER) && label_h > 3) {
+ #ifdef SHOW_CLOCK
+@@ -1169,39 +1305,48 @@
+ #endif
+
+ void FrameButton::draw() {
++#if FL_MAJOR_VERSION>1
++ const int x = value()?1:0;
++ const int y = x;
++ drawstyle(style(),flags()|fltk::OUTPUT);
++ FL_UP_BOX->draw(Rectangle(w(),h()));
++#else
++ const int x = this->x();
++ const int y = this->y();
+ Fl_Widget::draw_box(value() ? FL_DOWN_FRAME : FL_UP_FRAME, FL_GRAY);
++#endif
+ fl_color(parent()->labelcolor());
+ switch (label()[0]) {
+ case 'W':
+ #if MINIMIZE_ARROW
+- fl_line (x()+2,y()+(h())/2,x()+w()-4,y()+h()/2);
+- fl_line (x()+2,y()+(h())/2,x()+2+4,y()+h()/2+4);
+- fl_line (x()+2,y()+(h())/2,x()+2+4,y()+h()/2-4);
++ fl_line (x+2,y+(h())/2,x+w()-4,y+h()/2);
++ fl_line (x+2,y+(h())/2,x+2+4,y+h()/2+4);
++ fl_line (x+2,y+(h())/2,x+2+4,y+h()/2-4);
+ #else
+- fl_rect(x()+(h()-7)/2,y()+3,2,h()-6);
++ fl_rect(x+(h()-7)/2,y+3,2,h()-6);
+ #endif
+ return;
+ case 'w':
+- fl_rect(x()+2,y()+(h()-7)/2,w()-4,7);
++ fl_rect(x+2,y+(h()-7)/2,w()-4,7);
+ return;
+ case 'h':
+- fl_rect(x()+(h()-7)/2,y()+2,7,h()-4);
++ fl_rect(x+(h()-7)/2,y+2,7,h()-4);
+ return;
+ case 'X':
+ #if CLOSE_X
+- fl_line(x()+2,y()+3,x()+w()-5,y()+h()-4);
+- fl_line(x()+3,y()+3,x()+w()-4,y()+h()-4);
+- fl_line(x()+2,y()+h()-4,x()+w()-5,y()+3);
+- fl_line(x()+3,y()+h()-4,x()+w()-4,y()+3);
++ fl_line(x+2,y+3,x+w()-5,y+h()-4);
++ fl_line(x+3,y+3,x+w()-4,y+h()-4);
++ fl_line(x+2,y+h()-4,x+w()-5,y+3);
++ fl_line(x+3,y+h()-4,x+w()-4,y+3);
+ #endif
+ #if CLOSE_HITTITE_LIGHTNING
+- fl_arc(x()+3,y()+3,w()-6,h()-6,0,360);
+- fl_line(x()+7,y()+3, x()+7,y()+11);
++ fl_arc(x+3,y+3,w()-6,h()-6,0,360);
++ fl_line(x+7,y+3, x+7,y+11);
+ #endif
+ return;
+ case 'i':
+ #if ICONIZE_BOX
+- fl_rect(x()+w()/2-1,y()+h()/2-1,3,3);
++ fl_rect(x+w()/2-1,y+h()/2-1,3,3);
+ #endif
+ return;
+ }
+@@ -1320,6 +1465,9 @@
+ c = FL_CURSOR_NESW;
+ break;
+ }
++#if FL_MAJOR_VERSION>1
++ cursor(c);
++#else
+ static Frame* previous_frame;
+ static Fl_Cursor previous_cursor;
+ if (this != previous_frame || c != previous_cursor) {
+@@ -1327,6 +1475,7 @@
+ previous_cursor = c;
+ cursor(c, CURSOR_FG_SLOT, CURSOR_BG_SLOT);
+ }
++#endif
+ }
+
+ #ifdef AUTO_RAISE
+@@ -1348,10 +1497,17 @@
+ int Frame::handle(int e) {
+ static int what, dx, dy, ix, iy, iw, ih;
+ // see if child widget handles event:
+- if (Fl_Window::handle(e) && e != FL_ENTER && e != FL_MOVE) {
++#if FL_MAJOR_VERSION > 1
++ if (fltk::Group::handle(e) && e != FL_ENTER && e != FL_MOVE) {
++ if (e == FL_PUSH) set_cursor(-1);
++ return 1;
++ }
++#else
++ if (Fl_Group::handle(e) && e != FL_ENTER && e != FL_MOVE) {
+ if (e == FL_PUSH) set_cursor(-1);
+ return 1;
+ }
++#endif
+ switch (e) {
+
+ case FL_SHOW:
+@@ -1381,42 +1537,33 @@
+ #endif
+ goto GET_CROSSINGS;
+
+- case 0:
++ case FL_MOVE:
+ GET_CROSSINGS:
+ // set cursor_inside to true when the mouse is inside a window
+ // set it false when mouse is on a frame or outside a window.
+ // fltk mangles the X enter/leave events, we need the original ones:
+
+ switch (fl_xevent->type) {
+- case EnterNotify:
++ case LeaveNotify:
++ if (fl_xevent->xcrossing.detail == NotifyInferior) {
++ // cursor moved from frame to interior
++ cursor_inside = this;
++ break;
++ } else {
++ // cursor moved to another window
++ return 1;
++ }
+
++ case EnterNotify:
+ // see if cursor skipped over frame and directly to interior:
+ if (fl_xevent->xcrossing.detail == NotifyVirtual ||
+ fl_xevent->xcrossing.detail == NotifyNonlinearVirtual)
+ cursor_inside = this;
+-
+ else {
+ // cursor is now pointing at frame:
+ cursor_inside = 0;
+ }
+-
+- // fall through to FL_MOVE:
+- break;
+-
+- case LeaveNotify:
+- if (fl_xevent->xcrossing.detail == NotifyInferior) {
+- // cursor moved from frame to interior
+- cursor_inside = this;
+- set_cursor(-1);
+- return 1;
+- }
+- return 1;
+-
+- default:
+- return 0; // other X event we don't understand
+ }
+-
+- case FL_MOVE:
+ if (Fl::belowmouse() != this || cursor_inside == this)
+ set_cursor(-1);
+ else
+@@ -1578,9 +1725,10 @@
+
+ case UnmapNotify: {
+ const XUnmapEvent* e = &(ei->xunmap);
+- if (e->from_configure);
+- else if (state_flags_&IGNORE_UNMAP) clear_state_flag(IGNORE_UNMAP);
+- else state(UNMAPPED);
++ if (e->window == window_ && !e->from_configure) {
++ if (state_flags_&IGNORE_UNMAP) clear_state_flag(IGNORE_UNMAP);
++ else state(UNMAPPED);
++ }
+ return 1;}
+
+ case DestroyNotify: {
+@@ -1677,7 +1825,7 @@
+ return ::getProperty(window_, a, type, np);
+ }
+
+-void* getProperty(Window w, Atom a, Atom type, int* np) {
++void* getProperty(XWindow w, Atom a, Atom type, int* np) {
+ Atom realType;
+ int format;
+ unsigned long n, extra;
+@@ -1690,14 +1838,14 @@
+ if (!prop) return 0;
+ if (!n) {XFree(prop); return 0;}
+ if (np) *np = (int)n;
+- return (void *)prop;
++ return (void*)prop;
+ }
+
+ int Frame::getIntProperty(Atom a, Atom type, int deflt) const {
+ return ::getIntProperty(window_, a, type, deflt);
+ }
+
+-int getIntProperty(Window w, Atom a, Atom type, int deflt) {
++int getIntProperty(XWindow w, Atom a, Atom type, int deflt) {
+ void* prop = getProperty(w, a, type);
+ if (!prop) return deflt;
+ int r = int(*(long*)prop);
+@@ -1705,7 +1853,7 @@
+ return r;
+ }
+
+-void setProperty(Window w, Atom a, Atom type, int v) {
++void setProperty(XWindow w, Atom a, Atom type, int v) {
+ long prop = v;
+ XChangeProperty(fl_display, w, a, type, 32, PropModeReplace, (uchar*)&prop,1);
+ }
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/Frame.H /tmp/KfNDqvamm0/flwm-1.01/Frame.H
+--- /tmp/8FTwAYJlot/flwm-1.00/Frame.H 1999-08-24 22:59:35.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/Frame.H 2003-12-16 16:15:40.000000000 +0100
+@@ -9,6 +9,9 @@
+ #include <FL/Fl_Window.H>
+ #include <FL/Fl_Button.H>
+ #include <FL/x.H>
++#if FL_MAJOR_VERSION<2
++# define XWindow Window
++#endif
+
+ // The state is an enumeration of reasons why the window may be invisible.
+ // Only if it is NORMAL is the window visible.
+@@ -58,7 +61,7 @@
+
+ class Frame : public Fl_Window {
+
+- Window window_;
++ XWindow window_;
+
+ short state_; // X server state: iconic, withdrawn, normal
+ short state_flags_; // above state flags
+@@ -79,14 +82,14 @@
+ int label_y, label_h; // location of label
+ int label_w; // measured width of printed label
+
+- Window transient_for_xid; // value from X
++ XWindow transient_for_xid; // value from X
+ Frame* transient_for_; // the frame for that xid, if found
+
+ Frame* revert_to; // probably the xterm this was run from
+
+ Colormap colormap; // this window's colormap
+ int colormapWinCount; // list of other windows to install colormaps for
+- Window *colormapWindows;
++ XWindow *colormapWindows;
+ Colormap *window_Colormaps; // their colormaps
+
+ Desktop* desktop_;
+@@ -101,6 +104,7 @@
+ int maximize_height();
+ int force_x_onscreen(int X, int W);
+ int force_y_onscreen(int Y, int H);
++ void place_window();
+
+ void sendMessage(Atom, Atom) const;
+ void sendConfigureNotify() const;
+@@ -122,6 +126,7 @@
+
+ void set_size(int,int,int,int, int warp=0);
+ void resize(int,int,int,int);
++ void layout();
+ void show_hide_buttons();
+
+ int handle(int); // handle fltk events
+@@ -151,10 +156,10 @@
+ static Frame* first;
+ Frame* next; // stacking order, top to bottom
+
+- Frame(Window, XWindowAttributes* = 0);
++ Frame(XWindow, XWindowAttributes* = 0);
+ ~Frame();
+
+- Window window() const {return window_;}
++ XWindow window() const {return window_;}
+ Frame* transient_for() const {return transient_for_;}
+ int is_transient_for(const Frame*) const;
+
+@@ -185,8 +190,8 @@
+ };
+
+ // handy wrappers for those ugly X routines:
+-void* getProperty(Window, Atom, Atom = AnyPropertyType, int* length = 0);
+-int getIntProperty(Window, Atom, Atom = AnyPropertyType, int deflt = 0);
+-void setProperty(Window, Atom, Atom, int);
++void* getProperty(XWindow, Atom, Atom = AnyPropertyType, int* length = 0);
++int getIntProperty(XWindow, Atom, Atom = AnyPropertyType, int deflt = 0);
++void setProperty(XWindow, Atom, Atom, int);
+
+ #endif
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/Hotkeys.C /tmp/KfNDqvamm0/flwm-1.01/Hotkeys.C
+--- /tmp/8FTwAYJlot/flwm-1.00/Hotkeys.C 2000-09-22 18:53:05.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/Hotkeys.C 2006-06-29 09:18:08.000000000 +0200
+@@ -149,6 +149,36 @@
+ #endif
+ {0}};
+
++#if FL_MAJOR_VERSION > 1
++// Define missing function, this should get put in fltk2.0:
++namespace fltk {
++int test_shortcut(int shortcut) {
++ if (!shortcut) return 0;
++
++ int shift = Fl::event_state();
++ // see if any required shift flags are off:
++ if ((shortcut&shift) != (shortcut&0x7fff0000)) return 0;
++ // record shift flags that are wrong:
++ int mismatch = (shortcut^shift)&0x7fff0000;
++ // these three must always be correct:
++ if (mismatch&(FL_META|FL_ALT|FL_CTRL)) return 0;
++
++ int key = shortcut & 0xffff;
++
++ // if shift is also correct, check for exactly equal keysyms:
++ if (!(mismatch&(FL_SHIFT)) && unsigned(key) == Fl::event_key()) return 1;
++
++ // try matching ascii, ignore shift:
++ if (key == event_text()[0]) return 1;
++
++ // kludge so that Ctrl+'_' works (as opposed to Ctrl+'^_'):
++ if ((shift&FL_CTRL) && key >= 0x3f && key <= 0x5F
++ && event_text()[0]==(key^0x40)) return 1;
++ return 0;
++}
++}
++#endif
++
+ int Handle_Hotkey() {
+ for (int i = 0; keybindings[i].key; i++) {
+ if (Fl::test_shortcut(keybindings[i].key) ||
+@@ -165,7 +195,7 @@
+ extern Fl_Window* Root;
+
+ void Grab_Hotkeys() {
+- Window root = fl_xid(Root);
++ XWindow root = fl_xid(Root);
+ for (int i = 0; keybindings[i].key; i++) {
+ int k = keybindings[i].key;
+ int keycode = XKeysymToKeycode(fl_display, k & 0xFFFF);
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/logo.fl /tmp/KfNDqvamm0/flwm-1.01/logo.fl
+--- /tmp/8FTwAYJlot/flwm-1.00/logo.fl 1970-01-01 01:00:00.000000000 +0100
++++ /tmp/KfNDqvamm0/flwm-1.01/logo.fl 2006-04-13 18:06:59.000000000 +0200
+@@ -0,0 +1,19 @@
++# data file for the FLTK User Interface Designer (FLUID)
++version 2.0100
++header_name {.h}
++code_name {.cxx}
++gridx 5
++gridy 5
++snap 3
++Function {make_window()} {open
++} {
++ {fltk::Window} {} {
++ label flwm open
++ xywh {990 285 265 115} visible
++ } {
++ {fltk::Group} {} {
++ label {The Fast Light Window Manager} open selected
++ xywh {0 0 265 115} align 128 box PLASTIC_UP_BOX labelfont 1 labeltype ENGRAVED_LABEL color 0x7d9dae00 textcolor 0x979b9700 labelcolor 0x393a3900 labelsize 27
++ } {}
++ }
++}
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/main.C /tmp/KfNDqvamm0/flwm-1.01/main.C
+--- /tmp/8FTwAYJlot/flwm-1.00/main.C 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/main.C 2006-06-29 09:17:24.000000000 +0200
+@@ -43,10 +43,15 @@
+ class Fl_Root : public Fl_Window {
+ int handle(int);
+ public:
+- Fl_Root() : Fl_Window(0,0,Fl::w(),Fl::h()) {}
++ Fl_Root() : Fl_Window(0,0,Fl::w(),Fl::h()) {
++#if FL_MAJOR_VERSION > 1
++ clear_double_buffer();
++#endif
++ }
+ void show() {
+ if (!shown()) Fl_X::set_xid(this, RootWindow(fl_display, fl_screen));
+ }
++ void flush() {}
+ };
+ Fl_Window *Root;
+
+@@ -69,7 +74,7 @@
+ // fltk calls this for any events it does not understand:
+ static int flwm_event_handler(int e) {
+ if (!e) { // XEvent that fltk did not understand.
+- Window window = fl_xevent->xany.window;
++ XWindow window = fl_xevent->xany.window;
+ // unfortunately most of the redirect events put the interesting
+ // window id in a different place:
+ switch (fl_xevent->type) {
+@@ -107,18 +112,31 @@
+ const XMapRequestEvent* e = &(fl_xevent->xmaprequest);
+ (void)new Frame(e->window);
+ return 1;}
+- case KeyRelease: {
++#if FL_MAJOR_VERSION<2
++ // this was needed for *some* earlier versions of fltk
++ case KeyRelease:
+ if (!Fl::grab()) return 0;
+- // see if they released the alt key:
+- unsigned long keysym =
++ Fl::e_keysym =
+ XKeycodeToKeysym(fl_display, fl_xevent->xkey.keycode, 0);
+- if (keysym == FL_Alt_L || keysym == FL_Alt_R) {
+- Fl::e_keysym = FL_Enter;
+- return Fl::grab()->handle(FL_KEYBOARD);
+- }
+- return 0;}
++ goto KEYUP;
++#endif
++ }
++ } else if (e == FL_KEYUP) {
++#if FL_MAJOR_VERSION<2
++ KEYUP:
++#endif
++ if (!Fl::grab()) return 0;
++ // when alt key released, pretend they hit enter & pick menu item
++ if (Fl::event_key()==FL_Alt_L || Fl::event_key()==FL_Alt_R) {
++ Fl::e_keysym = FL_Enter;
++#if FL_MAJOR_VERSION>1
++ return Fl::modal()->handle(FL_KEYBOARD);
++#else
++ return Fl::grab()->handle(FL_KEYBOARD);
++#endif
+ }
+- } else if (e == FL_SHORTCUT) {
++ return 0;
++ } else if (e == FL_SHORTCUT || e == FL_KEYBOARD) {
+ #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 0 && FL_PATCH_VERSION < 3
+ // make the tab keys work in the menus in older fltk's:
+ // (they do not cycle around however, so a new fltk is a good idea)
+@@ -189,28 +207,26 @@
+ #endif
+
+ static const char* cfg, *cbg;
++#if FL_MAJOR_VERSION>1
++static fltk::Cursor* cursor = FL_CURSOR_ARROW;
++extern FL_API fltk::Color fl_cursor_fg;
++extern FL_API fltk::Color fl_cursor_bg;
++#else
+ static int cursor = FL_CURSOR_ARROW;
+-
+-static void color_setup(Fl_Color slot, const char* arg, ulong value) {
+- if (arg) {
+- XColor x;
+- if (XParseColor(fl_display, fl_colormap, arg, &x))
+- value = ((x.red>>8)<<24)|((x.green>>8)<<16)|((x.blue));
+- }
+- Fl::set_color(slot, value);
+-}
++#endif
+
+ static void initialize() {
+
+ Display* d = fl_display;
+
+ #ifdef TEST
+- Window w = XCreateSimpleWindow(d, root,
++ XWindow w = XCreateSimpleWindow(d, RootWindow(d, fl_screen),
+ 100, 100, 200, 300, 10,
+ BlackPixel(fl_display, 0),
+ // WhitePixel(fl_display, 0));
+ 0x1234);
+ Frame* frame = new Frame(w);
++ frame->label("flwm test window");
+ XSelectInput(d, w,
+ ExposureMask | StructureNotifyMask |
+ KeyPressMask | KeyReleaseMask | FocusChangeMask |
+@@ -230,9 +246,12 @@
+ ButtonPressMask | ButtonReleaseMask |
+ EnterWindowMask | LeaveWindowMask |
+ KeyPressMask | KeyReleaseMask | KeymapStateMask);
+- color_setup(CURSOR_FG_SLOT, cfg, CURSOR_FG_COLOR<<8);
+- color_setup(CURSOR_BG_SLOT, cbg, CURSOR_BG_COLOR<<8);
++#if FL_MAJOR_VERSION>1
++ Root->cursor(cursor);
++#else
+ Root->cursor((Fl_Cursor)cursor, CURSOR_FG_SLOT, CURSOR_BG_SLOT);
++#endif
++ Fl::visible_focus(0);
+
+ #ifdef TITLE_FONT
+ Fl::set_font(TITLE_FONT_SLOT, TITLE_FONT);
+@@ -247,7 +266,7 @@
+ // Gnome crap:
+ // First create a window that can be watched to see if wm dies:
+ Atom a = XInternAtom(d, "_WIN_SUPPORTING_WM_CHECK", False);
+- Window win = XCreateSimpleWindow(d, fl_xid(Root), -200, -200, 5, 5, 0, 0, 0);
++ XWindow win = XCreateSimpleWindow(d, fl_xid(Root), -200, -200, 5, 5, 0, 0, 0);
+ CARD32 val = win;
+ XChangeProperty(d, fl_xid(Root), a, XA_CARDINAL, 32, PropModeReplace, (uchar*)&val, 1);
+ XChangeProperty(d, win, a, XA_CARDINAL, 32, PropModeReplace, (uchar*)&val, 1);
+@@ -287,7 +306,7 @@
+
+ // find all the windows and create a Frame for each:
+ unsigned int n;
+- Window w1, w2, *wins;
++ XWindow w1, w2, *wins;
+ XWindowAttributes attr;
+ XQueryTree(d, fl_xid(Root), &w1, &w2, &wins, &n);
+ for (i = 0; i < n; ++i) {
+@@ -298,7 +317,6 @@
+ XFree((void *)wins);
+
+ #endif
+- Fl::visible_focus(0);
+ }
+
+ ////////////////////////////////////////////////////////////////
+@@ -329,8 +347,10 @@
+ cfg = v;
+ } else if (!strcmp(s, "cbg")) {
+ cbg = v;
++#if FL_MAJOR_VERSION < 2
+ } else if (*s == 'c') {
+ cursor = atoi(v);
++#endif
+ } else if (*s == 'v') {
+ int visid = atoi(v);
+ fl_open_display();
+@@ -351,6 +371,17 @@
+ return 2;
+ }
+
++#if FL_MAJOR_VERSION<2
++static void color_setup(Fl_Color slot, const char* arg, ulong value) {
++ if (arg) {
++ XColor x;
++ if (XParseColor(fl_display, fl_colormap, arg, &x))
++ value = ((x.red>>8)<<24)|((x.green>>8)<<16)|((x.blue));
++ }
++ Fl::set_color(slot, value);
++}
++#endif
++
+ int main(int argc, char** argv) {
+ program_name = fl_filename_name(argv[0]);
+ int i; if (Fl::args(argc, argv, i, arg) < argc) Fl::error(
+@@ -370,8 +401,22 @@
+ #ifndef FL_NORMAL_SIZE // detect new versions of fltk where this is a variable
+ FL_NORMAL_SIZE = 12;
+ #endif
++#if FL_MAJOR_VERSION>1
++ if (cfg) fl_cursor_fg = fltk::color(cfg);
++ if (cbg) fl_cursor_bg = fltk::color(cbg);
++#else
++ fl_open_display();
++ color_setup(CURSOR_FG_SLOT, cfg, CURSOR_FG_COLOR<<8);
++ color_setup(CURSOR_BG_SLOT, cbg, CURSOR_BG_COLOR<<8);
+ Fl::set_color(FL_SELECTION_COLOR,0,0,128);
+- Root = new Fl_Root();
++#endif
++ Fl_Root root;
++ Root = &root;
++#if FL_MAJOR_VERSION>1
++ // show() is not a virtual function in fltk2.0, this fools it:
++ fltk::load_theme();
++ root.show();
++#endif
+ Root->show(argc,argv); // fools fltk into using -geometry to set the size
+ XSetErrorHandler(xerror_handler);
+ initialize();
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/Makefile /tmp/KfNDqvamm0/flwm-1.01/Makefile
+--- /tmp/8FTwAYJlot/flwm-1.00/Makefile 2000-09-22 18:53:04.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/Makefile 2006-06-30 00:11:16.000000000 +0200
+@@ -1,7 +1,7 @@
+ SHELL=/bin/sh
+
+ PROGRAM = flwm
+-VERSION = 1.00
++VERSION = 1.01
+
+ CXXFILES = main.C Frame.C Rotated.C Menu.C FrameWindow.C Desktop.C Hotkeys.C
+
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/Menu.C /tmp/KfNDqvamm0/flwm-1.01/Menu.C
+--- /tmp/8FTwAYJlot/flwm-1.00/Menu.C 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/Menu.C 2006-06-30 11:01:41.000000000 +0200
+@@ -20,24 +20,6 @@
+ #include <dirent.h>
+ #include <sys/stat.h>
+
+-static char *double_ampersand(const char *s)
+-{
+- long i,l;
+- for(i=0,l=0;s[i];i++)
+- if (s[i]=='&')
+- l++;
+- char *c = new (char [l+i+1]);
+- for(i=0,l=0;s[i];i++)
+- {
+- c[l++]=s[i];
+- if (s[i]=='&')
+- c[l++]=s[i];
+- }
+- c[l]=0;
+- return c;
+-}
+-
+-
+ // it is possible for the window to be deleted or withdrawn while
+ // the menu is up. This will detect that case (with reasonable
+ // reliability):
+@@ -79,6 +61,7 @@
+
+ extern Fl_Window* Root;
+
++#if FL_MAJOR_VERSION < 2
+ static void
+ frame_label_draw(const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align)
+ {
+@@ -108,11 +91,19 @@
+ }
+ fl_font(o->font, o->size);
+ fl_color((Fl_Color)o->color);
+- const char* l = f->label();
+- if (!l) l = "unnamed";
+- else l = double_ampersand(f->label());
++ const char* l = f->label(); if (!l) l = "unnamed";
++ // double any ampersands to turn off the underscores:
++ char buf[256];
++ if (strchr(l,'&')) {
++ char* t = buf;
++ while (t < buf+254 && *l) {
++ if (*l=='&') *t++ = *l;
++ *t++ = *l++;
++ }
++ *t = 0;
++ l = buf;
++ }
+ fl_draw(l, X+MENU_ICON_W+3, Y, W-MENU_ICON_W-3, H, align);
+- delete l;
+ }
+
+ static void
+@@ -152,6 +143,8 @@
+ #define FRAME_LABEL FL_FREE_LABELTYPE
+ #define TEXT_LABEL Fl_Labeltype(FL_FREE_LABELTYPE+1)
+
++#endif // FL_MAJOR_VERSION < 2
++
+ ////////////////////////////////////////////////////////////////
+
+ static void
+@@ -176,7 +169,7 @@
+
+ #if ASK_FOR_NEW_DESKTOP_NAME
+
+-static Fl_Input* new_desktop_input;
++static Fl_Input* new_desktop_input = 0;
+
+ static void
+ new_desktop_ok_cb(Fl_Widget* w, void*)
+@@ -226,6 +219,7 @@
+ static void
+ exit_cb(Fl_Widget*, void*)
+ {
++ printf("exit_cb\n");
+ Frame::save_protocol();
+ exit(0);
+ }
+@@ -233,7 +227,7 @@
+ static void
+ logout_cb(Fl_Widget*, void*)
+ {
+- static FrameWindow* w;
++ static FrameWindow* w = 0;
+ if (!w) {
+ w = new FrameWindow(190,90);
+ Fl_Box* l = new Fl_Box(0, 0, 190, 60, "Really log out?");
+@@ -267,8 +261,8 @@
+ if (fork() == 0) {
+ if (fork() == 0) {
+ close(ConnectionNumber(fl_display));
+- if (name == xtermname) execlp(name, name, "-ut", NULL);
+- else execl(name, name, NULL);
++ if (name == xtermname) execlp(name, name, "-ut", (void*)0);
++ else execl(name, name, (void*)0);
+ fprintf(stderr, "flwm: can't run %s, %s\n", name, strerror(errno));
+ XBell(fl_display, 70);
+ exit(1);
+@@ -299,7 +293,11 @@
+ m.style = 0;
+ #endif
+ m.label(data);
++#if FL_MAJOR_VERSION > 2
++ m.flags = fltk::RAW_LABEL;
++#else
+ m.flags = 0;
++#endif
+ m.labeltype(FL_NORMAL_LABEL);
+ m.shortcut(0);
+ m.labelfont(MENU_FONT_SLOT);
+@@ -444,8 +442,10 @@
+ static char beenhere;
+ if (!beenhere) {
+ beenhere = 1;
++#if FL_MAJOR_VERSION < 2
+ Fl::set_labeltype(FRAME_LABEL, frame_label_draw, frame_label_measure);
+ Fl::set_labeltype(TEXT_LABEL, label_draw, label_measure);
++#endif
+ if (exit_flag) {
+ Fl_Menu_Item* m = other_menu_items+num_other_items-2;
+ m->label("Exit");
+@@ -532,8 +532,12 @@
+ #endif
+ for (c = Frame::first; c; c = c->next) {
+ if (c->state() == UNMAPPED || c->transient_for()) continue;
++#if FL_MAJOR_VERSION < 2
+ init(menu[n],(char*)c);
+ menu[n].labeltype(FRAME_LABEL);
++#else
++ init(menu[n],c->label());
++#endif
+ menu[n].callback(frame_callback, c);
+ if (is_active_frame(c)) preset = menu+n;
+ n++;
+@@ -562,7 +566,12 @@
+ if (c->state() == UNMAPPED || c->transient_for()) continue;
+ if (c->desktop() == d || !c->desktop() && d == Desktop::current()) {
+ init(menu[n],(char*)c);
++#if FL_MAJOR_VERSION < 2
++ init(menu[n],(char*)c);
+ menu[n].labeltype(FRAME_LABEL);
++#else
++ init(menu[n],c->label());
++#endif
+ menu[n].callback(d == Desktop::current() ?
+ frame_callback : move_frame_callback, c);
+ if (d == Desktop::current() && is_active_frame(c)) preset = menu+n;
+@@ -606,13 +615,14 @@
+ cmd = wmxlist[i];
+ cmd += strspn(cmd, "/")-1;
+ init(menu[n], cmd+pathlen[level]);
++#if FL_MAJOR_VERSION < 2
+ #if DESKTOPS
+ if (one_desktop)
+ #endif
+ if (!level)
+ menu[n].labeltype(TEXT_LABEL);
+-
+- int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1;
++#endif
++ int nextlev = (i==num_wmx-1)?0:strspn(wmxlist[i+1], "/")-1;
+ if (nextlev < level) {
+ menu[n].callback(spawn_cb, cmd);
+ // Close 'em off
+@@ -638,15 +648,19 @@
+ #endif
+ #endif
+ memcpy(menu+n, other_menu_items, sizeof(other_menu_items));
++#if FL_MAJOR_VERSION < 2
+ #if DESKTOPS
+ if (one_desktop)
+ #endif
+ // fix the menus items so they are indented to align with window names:
+ while (menu[n].label()) menu[n++].labeltype(TEXT_LABEL);
++#endif
+
+ const Fl_Menu_Item* picked =
+ menu->popup(Fl::event_x(), Fl::event_y(), 0, preset);
++#if FL_MAJOR_VERSION < 2
+ if (picked && picked->callback()) picked->do_callback(0);
++#endif
+ }
+
+ void ShowMenu() {ShowTabMenu(0);}
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/patch-stamp /tmp/KfNDqvamm0/flwm-1.01/patch-stamp
+--- /tmp/8FTwAYJlot/flwm-1.00/patch-stamp 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/patch-stamp 2006-06-30 11:01:41.000000000 +0200
+@@ -1,29 +1,8 @@
+ Patches applied in the Debian version of :
+
+-debian/patches/100_fl_filename_name.dpatch (Tommi Virtanen <tv@debian.org>):
+- Transition from fltk-1.0 to fltk-1.1.
+- Applied upstream.
+-
+-debian/patches/101_visible_focus.dpatch (Bill Allombert <ballombe@debian.org>):
+- Restore fltk-1.0 focus behaviour
+- (Applied upstream)
+-
+-debian/patches/102_charstruct.dpatch (Tommi Virtanen <tv@debian.org>):
+- Support fonts for which fontstruct->per_char is NULL.
+- (Applied upstream).
+-
+-debian/patches/103_man_typo.dpatch (Bill Allombert <ballombe@debian.org>):
+- Fix typo in man page.
+-
+-debian/patches/104_g++-4.1_warning.dpatch (Bill Allombert <ballombe@debian.org>):
+- Fix 5 g++ -4.1 warnings
+-
+-debian/patches/105_double_ampersand.dpatch (Bill Allombert <ballombe@debian.org>):
+- Handle & in window titles correctly in the windows list.
++debian/patches/100_double_ampersand.dpatch (<ballombe@debian.org>):
++ fix handling of ampersand in titles in windows list.
+
+ debian/patches/200_Debian_menu.dpatch (Tommi Virtanen <tv@debian.org>):
+ Add Debian menu support.
+
+-debian/patches/201_background_color.dpatch (Bill Allombert <ballombe@debian.org>):
+- Fix -fg and -bg options
+-
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/README /tmp/KfNDqvamm0/flwm-1.01/README
+--- /tmp/8FTwAYJlot/flwm-1.00/README 1999-08-24 22:59:35.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/README 2001-04-13 17:40:54.000000000 +0200
+@@ -5,7 +5,7 @@
+ ----------------------------------------------------------------
+
+ You need fltk. If you do not have it yet, download it from
+-http://fltk.easysw.com, and compile and install it.
++http://www.fltk.org, and compile and install it.
+
+ To customize flwm (for instance to turn on click-to-type), edit the
+ config.h file.
+@@ -22,21 +22,21 @@
+ How to run flwm:
+ ----------------------------------------------------------------
+
+-Flwm should be run by X when it logs you in. This is done by putting
+-a call to flwm into the file ~/.xinitrc. With any luck you already
+-have this file. If not try copying /usr/X11/lib/X11/xinit/xinitrc.
+-Edit the file and try to remove any call to another window manager
+-(these are usually near the end).
++To run flwm as your login script, you need to create or replace
++~/.xinitrc or ~/.xsession (or both). Newer Linux systems with a login
++panel use .xsession, older systems where X was started after login
++use .xinitrc. You may also have to pick "default" from the "type of
++session" popup in your login window.
+
+-Recommended contents of ~/.xinitrc:
++The .xinitrc or .xsession file should look like this:
+
+ #!/bin/sh
+ xsetroot -solid \#006060
+ xrdb .Xresources
+-# <xset, xmodmap, other configuration programs>
++# xset, xmodmap, other configuration programs
+ flwm &
+ WindowManager=$!
+-# <xterm, other automatically-launched programs>
++# xterm, other automatically-launched programs
+ wait $WindowManager
+
+ ALLOWING THE WINDOW MANAGER TO EXIT W/O LOGOUT:
+diff -Nru /tmp/8FTwAYJlot/flwm-1.00/Rotated.C /tmp/KfNDqvamm0/flwm-1.01/Rotated.C
+--- /tmp/8FTwAYJlot/flwm-1.00/Rotated.C 2006-06-30 11:01:38.000000000 +0200
++++ /tmp/KfNDqvamm0/flwm-1.01/Rotated.C 2005-09-19 06:29:11.000000000 +0200
+@@ -27,6 +27,9 @@
+ /* ********************************************************************** */
+
+ #include <FL/x.H>
++#if FL_MAJOR_VERSION < 2
++# define XWindow Window
++#endif
+ #include <FL/fl_draw.H>
+ #include "Rotated.H"
+ #include <stdlib.h>
+@@ -67,7 +70,7 @@
+ char val;
+ XImage *I1, *I2;
+ Pixmap canvas;
+- Window root;
++ XWindow root;
+ int screen;
+ GC font_gc;
+ char text[3];/*, errstr[300];*/
+@@ -116,27 +119,21 @@
+ /* font needs rotation ... */
+ /* loop through each character ... */
+ for (ichar = min_char; ichar <= max_char; ichar++) {
+- XCharStruct *charstruct;
+
+ index = ichar-fontstruct->min_char_or_byte2;
+
+- if (fontstruct->per_char) {
+- charstruct = &fontstruct->per_char[index];
+- } else {
++ XCharStruct* charstruct;
++ if (fontstruct->per_char)
++ charstruct = fontstruct->per_char+index;
++ else
+ charstruct = &fontstruct->min_bounds;
+- }
+
+ /* per char dimensions ... */
+- ascent = rotfont->per_char[ichar].ascent =
+- charstruct->ascent;
+- descent = rotfont->per_char[ichar].descent =
+- charstruct->descent;
+- lbearing = rotfont->per_char[ichar].lbearing =
+- charstruct->lbearing;
+- rbearing = rotfont->per_char[ichar].rbearing =
+- charstruct->rbearing;
+- rotfont->per_char[ichar].width =
+- charstruct->width;
++ ascent = rotfont->per_char[ichar].ascent = charstruct->ascent;
++ descent = rotfont->per_char[ichar].descent = charstruct->descent;
++ lbearing = rotfont->per_char[ichar].lbearing = charstruct->lbearing;
++ rbearing = rotfont->per_char[ichar].rbearing = charstruct->rbearing;
++ rotfont->per_char[ichar].width = charstruct->width;
+
+ /* some space chars have zero body, but a bitmap can't have ... */
+ if (!ascent && !descent)
+@@ -242,9 +239,9 @@
+ }
+
+ for (ichar = 0; ichar < min_char; ichar++)
+- rotfont->per_char[ichar] = rotfont->per_char[(int)'?'];
++ rotfont->per_char[ichar] = rotfont->per_char[int('?')];
+ for (ichar = max_char+1; ichar < 256; ichar++)
+- rotfont->per_char[ichar] = rotfont->per_char[(int)'?'];
++ rotfont->per_char[ichar] = rotfont->per_char[int('?')];
+
+ /* free pixmap and GC ... */
+ XFreePixmap(dpy, canvas);
+@@ -358,23 +355,25 @@
+
+ static XRotFontStruct* font;
+
+-void draw_rotated(const char* text, int n, int x, int y, int angle) {
+- if (!text || !*text) return;
++static void setrotfont(int angle) {
+ /* make angle positive ... */
+ if (angle < 0) do angle += 360; while (angle < 0);
+ /* get nearest vertical or horizontal direction ... */
+ int dir = ((angle+45)/90)%4;
+-
+- if (font && font->xfontstruct == fl_xfont && font->dir == dir) {
+- ;
+- } else {
+- if (font) XRotUnloadFont(fl_display, font);
+- font = XRotLoadFont(fl_display, fl_xfont, dir);
++ if (font) {
++ if (font->xfontstruct == fl_xfont && font->dir == dir) return;
++ XRotUnloadFont(fl_display, font);
+ }
++ font = XRotLoadFont(fl_display, fl_xfont, dir);
++}
++
++void draw_rotated(const char* text, int n, int x, int y, int angle) {
++ if (!text || !*text) return;
++ setrotfont(angle);
+ XRotDrawString(fl_display, font, fl_window, fl_gc, x, y, text, n);
+ }
+
+-#ifndef FLWM
++#if !defined(FLWM) || FL_MAJOR_VERSION>=2
+ void draw_rotated(const char* text, int x, int y, int angle) {
+ if (!text || !*text) return;
+ draw_rotated(text, strlen(text), x, y, angle);
+@@ -391,12 +390,20 @@
+ if (!str || !*str) return;
+ if (w && h && !fl_not_clipped(x, y, w, h)) return;
+ if (align & FL_ALIGN_CLIP) fl_clip(x, y, w, h);
++#if FL_MAJOR_VERSION>1
++ setrotfont(90);
++ int a = font->xfontstruct->ascent;
++ int d = font->xfontstruct->descent;
++ XRotDrawString(fl_display, font, fl_window, fl_gc,
++ x+(w+a-d+1)/2, y+h, str, strlen(str));
++#else
+ int a1 = align&(-16);
+ if (align & FL_ALIGN_LEFT) a1 |= FL_ALIGN_TOP;
+ if (align & FL_ALIGN_RIGHT) a1 |= FL_ALIGN_BOTTOM;
+ if (align & FL_ALIGN_TOP) a1 |= FL_ALIGN_RIGHT;
+ if (align & FL_ALIGN_BOTTOM) a1 |= FL_ALIGN_LEFT;
+ fl_draw(str, -(y+h), x, h, w, (Fl_Align)a1, draw_rot90);
++#endif
+ if (align & FL_ALIGN_CLIP) fl_pop_clip();
+ }
+
diff --git a/patch_cmds/diffstat/testing/case26.ref b/patch_cmds/diffstat/testing/case26.ref
new file mode 100644
index 0000000..db5bece
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26.ref
@@ -0,0 +1,35 @@
+ Frame.C | 294 ++++++++++++++++++++-------
+ Frame.H | 21 +
+ Hotkeys.C | 32 ++
+ Makefile | 2
+ Menu.C | 70 +++---
+ README | 18 -
+ Rotated.C | 61 +++--
+ config.h | 6
+ debian/changelog | 12 +
+ debian/patched/100_double_ampersand.dpatch | 1
+ debian/patched/100_fl_filename_name.dpatch | 2
+ debian/patched/101_visible_focus.dpatch | 1
+ debian/patched/102_charstruct.dpatch | 1
+ debian/patched/103_man_typo.dpatch | 1
+ debian/patched/104_g++-4.1_warning.dpatch | 3
+ debian/patched/105_double_ampersand.dpatch | 1
+ debian/patched/201_background_color.dpatch | 2
+ debian/patches/00list | 8
+ debian/patches/100_double_ampersand.dpatch | 19 +
+ debian/patches/100_fl_filename_name.dpatch | 20 -
+ debian/patches/101_visible_focus.dpatch | 19 -
+ debian/patches/102_charstruct.dpatch | 45 ----
+ debian/patches/103_man_typo.dpatch | 19 -
+ debian/patches/104_g++-4.1_warning.dpatch | 58 -----
+ debian/patches/105_double_ampersand.dpatch | 48 ----
+ debian/patches/200_Debian_menu.dpatch | 14 -
+ debian/patches/201_background_color.dpatch | 57 -----
+ debian/patches/202_background_color_2.dpatch | 92 --------
+ debian/watch | 3
+ flwm.1 | 4
+ flwm_wmconfig | 4
+ logo.fl | 19 +
+ main.C | 99 ++++++---
+ patch-stamp | 25 --
+ 34 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26R.ref b/patch_cmds/diffstat/testing/case26R.ref
new file mode 100644
index 0000000..17abff8
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26R.ref
@@ -0,0 +1,35 @@
+ Frame.C | 294 ++++++---------------------
+ Frame.H | 21 -
+ Hotkeys.C | 32 --
+ Makefile | 2
+ Menu.C | 70 ++----
+ README | 18 -
+ Rotated.C | 61 ++---
+ config.h | 6
+ debian/changelog | 12 -
+ debian/patched/100_double_ampersand.dpatch | 1
+ debian/patched/100_fl_filename_name.dpatch | 2
+ debian/patched/101_visible_focus.dpatch | 1
+ debian/patched/102_charstruct.dpatch | 1
+ debian/patched/103_man_typo.dpatch | 1
+ debian/patched/104_g++-4.1_warning.dpatch | 3
+ debian/patched/105_double_ampersand.dpatch | 1
+ debian/patched/201_background_color.dpatch | 2
+ debian/patches/00list | 8
+ debian/patches/100_double_ampersand.dpatch | 19 -
+ debian/patches/100_fl_filename_name.dpatch | 20 +
+ debian/patches/101_visible_focus.dpatch | 19 +
+ debian/patches/102_charstruct.dpatch | 45 ++++
+ debian/patches/103_man_typo.dpatch | 19 +
+ debian/patches/104_g++-4.1_warning.dpatch | 58 +++++
+ debian/patches/105_double_ampersand.dpatch | 48 ++++
+ debian/patches/200_Debian_menu.dpatch | 14 -
+ debian/patches/201_background_color.dpatch | 57 +++++
+ debian/patches/202_background_color_2.dpatch | 92 ++++++++
+ debian/watch | 3
+ flwm.1 | 4
+ flwm_wmconfig | 4
+ logo.fl | 19 -
+ main.C | 99 ++-------
+ patch-stamp | 25 ++
+ 34 files changed, 583 insertions(+), 498 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26Rp0.ref b/patch_cmds/diffstat/testing/case26Rp0.ref
new file mode 100644
index 0000000..1998e37
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26Rp0.ref
@@ -0,0 +1,35 @@
+ /tmp/8FTwAYJlot/flwm-1.00/Frame.C | 294 ++--------
+ /tmp/8FTwAYJlot/flwm-1.00/Frame.H | 21
+ /tmp/8FTwAYJlot/flwm-1.00/Hotkeys.C | 32 -
+ /tmp/8FTwAYJlot/flwm-1.00/Makefile | 2
+ /tmp/8FTwAYJlot/flwm-1.00/Menu.C | 70 --
+ /tmp/8FTwAYJlot/flwm-1.00/README | 18
+ /tmp/8FTwAYJlot/flwm-1.00/Rotated.C | 61 --
+ /tmp/8FTwAYJlot/flwm-1.00/config.h | 6
+ /tmp/8FTwAYJlot/flwm-1.00/debian/changelog | 12
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patched/100_double_ampersand.dpatch | 1
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patched/100_fl_filename_name.dpatch | 2
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patched/101_visible_focus.dpatch | 1
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patched/102_charstruct.dpatch | 1
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patched/103_man_typo.dpatch | 1
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patched/104_g++-4.1_warning.dpatch | 3
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patched/105_double_ampersand.dpatch | 1
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patched/201_background_color.dpatch | 2
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/00list | 8
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/100_double_ampersand.dpatch | 19
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/100_fl_filename_name.dpatch | 20
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/101_visible_focus.dpatch | 19
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/102_charstruct.dpatch | 45 +
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/103_man_typo.dpatch | 19
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/104_g++-4.1_warning.dpatch | 58 +
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/105_double_ampersand.dpatch | 48 +
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/200_Debian_menu.dpatch | 14
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/201_background_color.dpatch | 57 +
+ /tmp/8FTwAYJlot/flwm-1.00/debian/patches/202_background_color_2.dpatch | 92 +++
+ /tmp/8FTwAYJlot/flwm-1.00/debian/watch | 3
+ /tmp/8FTwAYJlot/flwm-1.00/flwm.1 | 4
+ /tmp/8FTwAYJlot/flwm-1.00/flwm_wmconfig | 4
+ /tmp/8FTwAYJlot/flwm-1.00/logo.fl | 19
+ /tmp/8FTwAYJlot/flwm-1.00/main.C | 99 ---
+ /tmp/8FTwAYJlot/flwm-1.00/patch-stamp | 25
+ 34 files changed, 583 insertions(+), 498 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26b.ref b/patch_cmds/diffstat/testing/case26b.ref
new file mode 100644
index 0000000..db5bece
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26b.ref
@@ -0,0 +1,35 @@
+ Frame.C | 294 ++++++++++++++++++++-------
+ Frame.H | 21 +
+ Hotkeys.C | 32 ++
+ Makefile | 2
+ Menu.C | 70 +++---
+ README | 18 -
+ Rotated.C | 61 +++--
+ config.h | 6
+ debian/changelog | 12 +
+ debian/patched/100_double_ampersand.dpatch | 1
+ debian/patched/100_fl_filename_name.dpatch | 2
+ debian/patched/101_visible_focus.dpatch | 1
+ debian/patched/102_charstruct.dpatch | 1
+ debian/patched/103_man_typo.dpatch | 1
+ debian/patched/104_g++-4.1_warning.dpatch | 3
+ debian/patched/105_double_ampersand.dpatch | 1
+ debian/patched/201_background_color.dpatch | 2
+ debian/patches/00list | 8
+ debian/patches/100_double_ampersand.dpatch | 19 +
+ debian/patches/100_fl_filename_name.dpatch | 20 -
+ debian/patches/101_visible_focus.dpatch | 19 -
+ debian/patches/102_charstruct.dpatch | 45 ----
+ debian/patches/103_man_typo.dpatch | 19 -
+ debian/patches/104_g++-4.1_warning.dpatch | 58 -----
+ debian/patches/105_double_ampersand.dpatch | 48 ----
+ debian/patches/200_Debian_menu.dpatch | 14 -
+ debian/patches/201_background_color.dpatch | 57 -----
+ debian/patches/202_background_color_2.dpatch | 92 --------
+ debian/watch | 3
+ flwm.1 | 4
+ flwm_wmconfig | 4
+ logo.fl | 19 +
+ main.C | 99 ++++++---
+ patch-stamp | 25 --
+ 34 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26f0.ref b/patch_cmds/diffstat/testing/case26f0.ref
new file mode 100644
index 0000000..6c70fb3
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26f0.ref
@@ -0,0 +1,35 @@
+ Frame.C | 294 221 + 73 - 0 !
+ Frame.H | 21 13 + 8 - 0 !
+ Hotkeys.C | 32 31 + 1 - 0 !
+ Makefile | 2 1 + 1 - 0 !
+ Menu.C | 70 42 + 28 - 0 !
+ README | 18 9 + 9 - 0 !
+ Rotated.C | 61 34 + 27 - 0 !
+ config.h | 6 6 + 0 - 0 !
+ debian/changelog | 12 12 + 0 - 0 !
+ debian/patched/100_double_ampersand.dpatch | 1 1 + 0 - 0 !
+ debian/patched/100_fl_filename_name.dpatch | 2 0 + 2 - 0 !
+ debian/patched/101_visible_focus.dpatch | 1 0 + 1 - 0 !
+ debian/patched/102_charstruct.dpatch | 1 0 + 1 - 0 !
+ debian/patched/103_man_typo.dpatch | 1 0 + 1 - 0 !
+ debian/patched/104_g++-4.1_warning.dpatch | 3 0 + 3 - 0 !
+ debian/patched/105_double_ampersand.dpatch | 1 0 + 1 - 0 !
+ debian/patched/201_background_color.dpatch | 2 0 + 2 - 0 !
+ debian/patches/00list | 8 1 + 7 - 0 !
+ debian/patches/100_double_ampersand.dpatch | 19 19 + 0 - 0 !
+ debian/patches/100_fl_filename_name.dpatch | 20 0 + 20 - 0 !
+ debian/patches/101_visible_focus.dpatch | 19 0 + 19 - 0 !
+ debian/patches/102_charstruct.dpatch | 45 0 + 45 - 0 !
+ debian/patches/103_man_typo.dpatch | 19 0 + 19 - 0 !
+ debian/patches/104_g++-4.1_warning.dpatch | 58 0 + 58 - 0 !
+ debian/patches/105_double_ampersand.dpatch | 48 0 + 48 - 0 !
+ debian/patches/200_Debian_menu.dpatch | 14 7 + 7 - 0 !
+ debian/patches/201_background_color.dpatch | 57 0 + 57 - 0 !
+ debian/patches/202_background_color_2.dpatch | 92 0 + 92 - 0 !
+ debian/watch | 3 3 + 0 - 0 !
+ flwm.1 | 4 2 + 2 - 0 !
+ flwm_wmconfig | 4 3 + 1 - 0 !
+ logo.fl | 19 19 + 0 - 0 !
+ main.C | 99 72 + 27 - 0 !
+ patch-stamp | 25 2 + 23 - 0 !
+ 34 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26k.ref b/patch_cmds/diffstat/testing/case26k.ref
new file mode 100644
index 0000000..db5bece
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26k.ref
@@ -0,0 +1,35 @@
+ Frame.C | 294 ++++++++++++++++++++-------
+ Frame.H | 21 +
+ Hotkeys.C | 32 ++
+ Makefile | 2
+ Menu.C | 70 +++---
+ README | 18 -
+ Rotated.C | 61 +++--
+ config.h | 6
+ debian/changelog | 12 +
+ debian/patched/100_double_ampersand.dpatch | 1
+ debian/patched/100_fl_filename_name.dpatch | 2
+ debian/patched/101_visible_focus.dpatch | 1
+ debian/patched/102_charstruct.dpatch | 1
+ debian/patched/103_man_typo.dpatch | 1
+ debian/patched/104_g++-4.1_warning.dpatch | 3
+ debian/patched/105_double_ampersand.dpatch | 1
+ debian/patched/201_background_color.dpatch | 2
+ debian/patches/00list | 8
+ debian/patches/100_double_ampersand.dpatch | 19 +
+ debian/patches/100_fl_filename_name.dpatch | 20 -
+ debian/patches/101_visible_focus.dpatch | 19 -
+ debian/patches/102_charstruct.dpatch | 45 ----
+ debian/patches/103_man_typo.dpatch | 19 -
+ debian/patches/104_g++-4.1_warning.dpatch | 58 -----
+ debian/patches/105_double_ampersand.dpatch | 48 ----
+ debian/patches/200_Debian_menu.dpatch | 14 -
+ debian/patches/201_background_color.dpatch | 57 -----
+ debian/patches/202_background_color_2.dpatch | 92 --------
+ debian/watch | 3
+ flwm.1 | 4
+ flwm_wmconfig | 4
+ logo.fl | 19 +
+ main.C | 99 ++++++---
+ patch-stamp | 25 --
+ 34 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26p1.ref b/patch_cmds/diffstat/testing/case26p1.ref
new file mode 100644
index 0000000..909791a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26p1.ref
@@ -0,0 +1,35 @@
+ tmp/KfNDqvamm0/flwm-1.01/Frame.C | 294 +++++++---
+ tmp/KfNDqvamm0/flwm-1.01/Frame.H | 21
+ tmp/KfNDqvamm0/flwm-1.01/Hotkeys.C | 32 +
+ tmp/KfNDqvamm0/flwm-1.01/Makefile | 2
+ tmp/KfNDqvamm0/flwm-1.01/Menu.C | 70 +-
+ tmp/KfNDqvamm0/flwm-1.01/README | 18
+ tmp/KfNDqvamm0/flwm-1.01/Rotated.C | 61 +-
+ tmp/KfNDqvamm0/flwm-1.01/config.h | 6
+ tmp/KfNDqvamm0/flwm-1.01/debian/changelog | 12
+ tmp/KfNDqvamm0/flwm-1.01/debian/patched/100_double_ampersand.dpatch | 1
+ tmp/KfNDqvamm0/flwm-1.01/debian/patched/100_fl_filename_name.dpatch | 2
+ tmp/KfNDqvamm0/flwm-1.01/debian/patched/101_visible_focus.dpatch | 1
+ tmp/KfNDqvamm0/flwm-1.01/debian/patched/102_charstruct.dpatch | 1
+ tmp/KfNDqvamm0/flwm-1.01/debian/patched/103_man_typo.dpatch | 1
+ tmp/KfNDqvamm0/flwm-1.01/debian/patched/104_g++-4.1_warning.dpatch | 3
+ tmp/KfNDqvamm0/flwm-1.01/debian/patched/105_double_ampersand.dpatch | 1
+ tmp/KfNDqvamm0/flwm-1.01/debian/patched/201_background_color.dpatch | 2
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/00list | 8
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/100_double_ampersand.dpatch | 19
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/100_fl_filename_name.dpatch | 20
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/101_visible_focus.dpatch | 19
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/102_charstruct.dpatch | 45 -
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/103_man_typo.dpatch | 19
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/104_g++-4.1_warning.dpatch | 58 -
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/105_double_ampersand.dpatch | 48 -
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/200_Debian_menu.dpatch | 14
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/201_background_color.dpatch | 57 -
+ tmp/KfNDqvamm0/flwm-1.01/debian/patches/202_background_color_2.dpatch | 92 ---
+ tmp/KfNDqvamm0/flwm-1.01/debian/watch | 3
+ tmp/KfNDqvamm0/flwm-1.01/flwm.1 | 4
+ tmp/KfNDqvamm0/flwm-1.01/flwm_wmconfig | 4
+ tmp/KfNDqvamm0/flwm-1.01/logo.fl | 19
+ tmp/KfNDqvamm0/flwm-1.01/main.C | 99 ++-
+ tmp/KfNDqvamm0/flwm-1.01/patch-stamp | 25
+ 34 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26p9.ref b/patch_cmds/diffstat/testing/case26p9.ref
new file mode 100644
index 0000000..54ad0ed
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26p9.ref
@@ -0,0 +1,27 @@
+ 00list | 8 -
+ 100_double_ampersand.dpatch | 20 ++
+ 100_fl_filename_name.dpatch | 22 ---
+ 101_visible_focus.dpatch | 20 --
+ 102_charstruct.dpatch | 46 ------
+ 103_man_typo.dpatch | 20 --
+ 104_g++-4.1_warning.dpatch | 61 --------
+ 105_double_ampersand.dpatch | 49 -------
+ 200_Debian_menu.dpatch | 14 +-
+ 201_background_color.dpatch | 59 --------
+ 202_background_color_2.dpatch | 92 -------------
+ Frame.C | 294 +++++++++++++++++++++++++++++++-----------
+ Frame.H | 21 +--
+ Hotkeys.C | 32 ++++
+ Makefile | 2
+ Menu.C | 70 ++++++----
+ README | 18 +-
+ Rotated.C | 61 ++++----
+ changelog | 12 +
+ config.h | 6
+ flwm.1 | 4
+ flwm_wmconfig | 4
+ logo.fl | 19 ++
+ main.C | 99 ++++++++++----
+ patch-stamp | 25 ---
+ watch | 3
+ 26 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26r1.ref b/patch_cmds/diffstat/testing/case26r1.ref
new file mode 100644
index 0000000..e28a9fd
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26r1.ref
@@ -0,0 +1,35 @@
+ Frame.C | 294 ++++++++++++++++++++-------
+ Frame.H | 21 +-
+ Hotkeys.C | 32 +++
+ Makefile | 2
+ Menu.C | 70 ++++---
+ README | 18 +-
+ Rotated.C | 61 +++--
+ config.h | 6 +
+ debian/changelog | 12 +
+ debian/patched/100_double_ampersand.dpatch | 1
+ debian/patched/100_fl_filename_name.dpatch | 2
+ debian/patched/101_visible_focus.dpatch | 1
+ debian/patched/102_charstruct.dpatch | 1
+ debian/patched/103_man_typo.dpatch | 1
+ debian/patched/104_g++-4.1_warning.dpatch | 3
+ debian/patched/105_double_ampersand.dpatch | 1
+ debian/patched/201_background_color.dpatch | 2
+ debian/patches/00list | 8 -
+ debian/patches/100_double_ampersand.dpatch | 19 ++
+ debian/patches/100_fl_filename_name.dpatch | 20 --
+ debian/patches/101_visible_focus.dpatch | 19 --
+ debian/patches/102_charstruct.dpatch | 45 ----
+ debian/patches/103_man_typo.dpatch | 19 --
+ debian/patches/104_g++-4.1_warning.dpatch | 58 -----
+ debian/patches/105_double_ampersand.dpatch | 48 ----
+ debian/patches/200_Debian_menu.dpatch | 14 +-
+ debian/patches/201_background_color.dpatch | 57 -----
+ debian/patches/202_background_color_2.dpatch | 92 --------
+ debian/watch | 3
+ flwm.1 | 4
+ flwm_wmconfig | 4
+ logo.fl | 19 ++
+ main.C | 99 +++++++--
+ patch-stamp | 25 --
+ 34 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26r2.ref b/patch_cmds/diffstat/testing/case26r2.ref
new file mode 100644
index 0000000..4566808
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26r2.ref
@@ -0,0 +1,35 @@
+ Frame.C | 294 ++++++++++++++++++++-------
+ Frame.H | 21 +-
+ Hotkeys.C | 32 +++
+ Makefile | 2
+ Menu.C | 70 ++++--
+ README | 18 +-
+ Rotated.C | 61 +++---
+ config.h | 6 +
+ debian/changelog | 12 +
+ debian/patched/100_double_ampersand.dpatch | 1 +
+ debian/patched/100_fl_filename_name.dpatch | 2 -
+ debian/patched/101_visible_focus.dpatch | 1 -
+ debian/patched/102_charstruct.dpatch | 1 -
+ debian/patched/103_man_typo.dpatch | 1 -
+ debian/patched/104_g++-4.1_warning.dpatch | 3 -
+ debian/patched/105_double_ampersand.dpatch | 1 -
+ debian/patched/201_background_color.dpatch | 2 -
+ debian/patches/00list | 8 -
+ debian/patches/100_double_ampersand.dpatch | 19 ++
+ debian/patches/100_fl_filename_name.dpatch | 20 --
+ debian/patches/101_visible_focus.dpatch | 19 --
+ debian/patches/102_charstruct.dpatch | 45 ----
+ debian/patches/103_man_typo.dpatch | 19 --
+ debian/patches/104_g++-4.1_warning.dpatch | 58 -----
+ debian/patches/105_double_ampersand.dpatch | 48 ----
+ debian/patches/200_Debian_menu.dpatch | 14
+ debian/patches/201_background_color.dpatch | 57 -----
+ debian/patches/202_background_color_2.dpatch | 92 --------
+ debian/watch | 3 +
+ flwm.1 | 4
+ flwm_wmconfig | 4 +
+ logo.fl | 19 ++
+ main.C | 99 +++++++--
+ patch-stamp | 25 --
+ 34 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case26u.ref b/patch_cmds/diffstat/testing/case26u.ref
new file mode 100644
index 0000000..ab44c89
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case26u.ref
@@ -0,0 +1,35 @@
+ config.h | 6
+ debian/changelog | 12 +
+ debian/patched/100_double_ampersand.dpatch | 1
+ debian/patched/100_fl_filename_name.dpatch | 2
+ debian/patched/101_visible_focus.dpatch | 1
+ debian/patched/102_charstruct.dpatch | 1
+ debian/patched/103_man_typo.dpatch | 1
+ debian/patched/104_g++-4.1_warning.dpatch | 3
+ debian/patched/105_double_ampersand.dpatch | 1
+ debian/patched/201_background_color.dpatch | 2
+ debian/patches/00list | 8
+ debian/patches/100_double_ampersand.dpatch | 19 +
+ debian/patches/100_fl_filename_name.dpatch | 20 -
+ debian/patches/101_visible_focus.dpatch | 19 -
+ debian/patches/102_charstruct.dpatch | 45 ----
+ debian/patches/103_man_typo.dpatch | 19 -
+ debian/patches/104_g++-4.1_warning.dpatch | 58 -----
+ debian/patches/105_double_ampersand.dpatch | 48 ----
+ debian/patches/200_Debian_menu.dpatch | 14 -
+ debian/patches/201_background_color.dpatch | 57 -----
+ debian/patches/202_background_color_2.dpatch | 92 --------
+ debian/watch | 3
+ flwm.1 | 4
+ flwm_wmconfig | 4
+ Frame.C | 294 ++++++++++++++++++++-------
+ Frame.H | 21 +
+ Hotkeys.C | 32 ++
+ logo.fl | 19 +
+ main.C | 99 ++++++---
+ Makefile | 2
+ Menu.C | 70 +++---
+ patch-stamp | 25 --
+ README | 18 -
+ Rotated.C | 61 +++--
+ 34 files changed, 498 insertions(+), 583 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27.pat b/patch_cmds/diffstat/testing/case27.pat
new file mode 100644
index 0000000..f90bd44
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27.pat
@@ -0,0 +1,409 @@
+From bunk@kernel.org Fri Aug 24 01:11:51 2007
+From: Adrian Bunk <bunk@kernel.org>
+To: Andrew Morton <akpm@linux-foundation.org>,
+ Ram Pai <linuxram@us.ibm.com>, Sam Ravnborg <sam@ravnborg.org>
+Cc: linux-kernel@vger.kernel.org
+Subject: [2.6 patch] fix export_report.pl
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf-8
+Content-Disposition: inline
+X-Mutt-Fcc: =sent-mail
+Status: RO
+Content-Length: 466
+Lines: 22
+
+This patch fixes an annoying bug of export_report.pl missing the usages
+of some exports.
+
+Signed-off-by: Adrian Bunk <bunk@kernel.org>
+
+---
+
+This patch has been sent on:
+- 14 Aug 2007
+
+--- a/scripts/export_report.pl
++++ b/scripts/export_report.pl
+@@ -112,7 +112,7 @@ foreach my $thismod (@allcfiles) {
+ next;
+ }
+ if ($state eq 2) {
+- if ( $_ !~ /0x[0-9a-f]{7,8},/ ) {
++ if ( $_ !~ /0x[0-9a-f]+,/ ) {
+ next;
+ }
+ my $sym = (split /([,"])/,)[4];
+
+
+From bunk@kernel.org Fri Aug 24 01:13:29 2007
+From: Adrian Bunk <bunk@kernel.org>
+To: Andrew Morton <akpm@linux-foundation.org>,
+ Ram Pai <linuxram@us.ibm.com>, Sam Ravnborg <sam@ravnborg.org>
+Cc: linux-kernel@vger.kernel.org
+Subject: [2.6 patch] call export_report from the Makefile
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf-8
+Content-Disposition: inline
+X-Mutt-Fcc: =sent-mail
+Status: RO
+Content-Length: 827
+Lines: 31
+
+The main feature is that export_report now automatically works
+for O= builds.
+
+Signed-off-by: Adrian Bunk <bunk@kernel.org>
+
+---
+
+This patch has been sent on:
+- 14 Aug 2007
+
+--- a/Makefile
++++ b/Makefile
+@@ -1153,6 +1153,7 @@ help:
+ @echo 'Static analysers'
+ @echo ' checkstack - Generate a list of stack hogs'
+ @echo ' namespacecheck - Name space analysis on compiled kernel'
++ @echo ' export_report - List the usages of all exported symbols'
+ @if [ -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \
+ echo ' headers_check - Sanity check on exported headers'; \
+ fi
+@@ -1412,6 +1413,9 @@ versioncheck:
+ namespacecheck:
+ $(PERL) $(srctree)/scripts/namespace.pl
+
++export_report:
++ $(PERL) $(srctree)/scripts/export_report.pl
++
+ endif #ifeq ($(config-targets),1)
+ endif #ifeq ($(mixed-targets),1)
+
+
+
+From bunk@kernel.org Fri Aug 24 04:43:31 2007
+From: Adrian Bunk <bunk@kernel.org>
+To: Samuel Thibault <samuel.thibault@ens-lyon.org>,
+ Andrew Morton <akpm@linux-foundation.org>,
+ linux-input@atrey.karlin.mff.cuni.cz, linux-kernel@vger.kernel.org,
+ dtor@mail.ru, Jiri Kosina <jkosina@suse.cz>
+Subject: Re: [PATCH] Console keyboard events and accessibility
+References: <20070821005718.GD3658@interface.famille.thibault.fr> <20070821130233.58faaa8a.akpm@linux-foundation.org> <20070821202251.GB3658@interface.famille.thibault.fr>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf-8
+Content-Disposition: inline
+Content-Transfer-Encoding: 8bit
+In-Reply-To: <20070821202251.GB3658@interface.famille.thibault.fr>
+X-Mutt-References: <20070821202251.GB3658@interface.famille.thibault.fr>
+X-Mutt-Fcc: =sent-mail
+Status: RO
+Content-Length: 2121
+Lines: 57
+
+On Tue, Aug 21, 2007 at 10:22:51PM +0200, Samuel Thibault wrote:
+> Hi,
+>
+> Andrew Morton, le Tue 21 Aug 2007 13:02:33 -0700, a écrit :
+> > On Tue, 21 Aug 2007 02:57:18 +0200
+> > Samuel Thibault <samuel.thibault@ens-lyon.org> wrote:
+> >
+> > > Some external modules like Speakup need to use the PC keyboard to control
+> > > them and also need to get keyboard feedback (caps lock status, etc.)
+> > >
+> > > This adds a keyboard notifier that such modules can use to get the keyboard
+> > > events and possibly eat them, at several stages:
+> >
+> > Adding hooks for non-merged modules is considered sinful. Making these new
+> > exports EXPORT_SYMBOL_GPL might ease the pain.
+>
+> That should be fine.
+>
+> I'll soon propose a notifier for the console writes too, same story.
+>
+> > Is there any prospect of getting at least one of these "external modules
+> > like Speakup" merged into mainline?
+>
+> I'm working on it. The problem is that the current code quality is
+> still far from mainline requirements (though improving over time). This
+> hook (and the other one I'll post) is a step toward merging. If these
+> hooks can go mainline, then great, that will make life easier for the
+> few distributions that want to provide speakup as modules.
+
+How long does it take you for getting the first users submitted for
+review? If you are working on it it should be in the order of "a few
+months", and earlier merging would anyway gain you only one or two
+kernel releases.
+
+> If they
+> remain in -mm for some time and people don't complain, well that's good
+> too: at least we know how speakup may hook into the kernel when it gets
+> merged.
+>...
+
+Without any users it's dead code noone uses, and complaints will most
+likely not occur until you submit the first users for review...
+
+> Samuel
+
+cu
+Adrian
+
+BTW: Are these the speakup patches that were in -ac five years ago?
+
+--
+
+ "Is there not promise of rain?" Ling Tan asked suddenly out
+ of the darkness. There had been need of rain for many days.
+ "Only a promise," Lao Er said.
+ Pearl S. Buck - Dragon Seed
+
+
+From bunk@kernel.org Fri Aug 24 04:50:47 2007
+From: Adrian Bunk <bunk@kernel.org>
+To: Andrew Morton <akpm@linux-foundation.org>,
+ Adam Belay <abelay@novell.com>,
+ Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>,
+ Shaohua Li <shaohua.li@intel.com>
+Cc: linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org
+Subject: [-mm patch] make "struct menu_governor" static (again)
+References: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf-8
+Content-Disposition: inline
+In-Reply-To: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+X-Mutt-References: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+X-Mutt-Fcc: =sent-mail
+Status: RO
+Content-Length: 740
+Lines: 29
+
+On Wed, Aug 22, 2007 at 02:06:48AM -0700, Andrew Morton wrote:
+>...
+> Changes since 2.6.23-rc2-mm2:
+>...
+> git-acpi.patch
+>...
+> git trees
+>...
+
+"struct menu_governor" needlessly again became global.
+
+Signed-off-by: Adrian Bunk <bunk@kernel.org>
+
+---
+cb33b296204127cf50df54b84b2d79e152fb924b
+diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
+index f5a8865..8d3fdc5 100644
+--- a/drivers/cpuidle/governors/menu.c
++++ b/drivers/cpuidle/governors/menu.c
+@@ -117,7 +117,7 @@ static int menu_enable_device(struct cpuidle_device *dev)
+ return 0;
+ }
+
+-struct cpuidle_governor menu_governor = {
++static struct cpuidle_governor menu_governor = {
+ .name = "menu",
+ .rating = 20,
+ .enable = menu_enable_device,
+
+
+From bunk@kernel.org Fri Aug 24 05:01:58 2007
+From: Adrian Bunk <bunk@kernel.org>
+To: Andrew Morton <akpm@linux-foundation.org>,
+ "Eric W. Biederman" <ebiederm@xmission.com>
+Cc: linux-kernel@vger.kernel.org
+Subject: [-mm patch] remove parport_device_num()
+References: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf-8
+Content-Disposition: inline
+In-Reply-To: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+X-Mutt-References: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+X-Mutt-Fcc: =sent-mail
+Status: RO
+Content-Length: 3917
+Lines: 135
+
+On Wed, Aug 22, 2007 at 02:06:48AM -0700, Andrew Morton wrote:
+>...
+> Changes since 2.6.23-rc2-mm2:
+>...
+> +sysctl-parport-remove-binary-paths.patch
+>...
+> More sysctl work
+>...
+
+parport_device_num() is no longer used.
+
+Signed-off-by: Adrian Bunk <bunk@kernel.org>
+
+---
+
+ Documentation/parport-lowlevel.txt | 29 +++--------------------------
+ drivers/parport/daisy.c | 29 -----------------------------
+ include/linux/parport.h | 1 -
+ 3 files changed, 3 insertions(+), 56 deletions(-)
+
+0066510df2b5d4972cfd6a4450af8b82c763adfd
+diff --git a/Documentation/parport-lowlevel.txt b/Documentation/parport-lowlevel.txt
+index 8f23024..265fcdc 100644
+--- a/Documentation/parport-lowlevel.txt
++++ b/Documentation/parport-lowlevel.txt
+@@ -25,7 +25,6 @@ Global functions:
+ parport_open
+ parport_close
+ parport_device_id
+- parport_device_num
+ parport_device_coords
+ parport_find_class
+ parport_find_device
+@@ -735,7 +734,7 @@ NULL is returned.
+
+ SEE ALSO
+
+-parport_register_device, parport_device_num
++parport_register_device
+
+ parport_close - unregister device for particular device number
+ -------------
+@@ -787,29 +786,7 @@ Many devices have ill-formed IEEE 1284 Device IDs.
+
+ SEE ALSO
+
+-parport_find_class, parport_find_device, parport_device_num
+-
+-parport_device_num - convert device coordinates to device number
+-------------------
+-
+-SYNOPSIS
+-
+-#include <linux/parport.h>
+-
+-int parport_device_num (int parport, int mux, int daisy);
+-
+-DESCRIPTION
+-
+-Convert between device coordinates (port, multiplexor, daisy chain
+-address) and device number (zero-based).
+-
+-RETURN VALUE
+-
+-Device number, or -1 if no device at given coordinates.
+-
+-SEE ALSO
+-
+-parport_device_coords, parport_open, parport_device_id
++parport_find_class, parport_find_device
+
+ parport_device_coords - convert device number to device coordinates
+ ------------------
+@@ -833,7 +810,7 @@ Zero on success, in which case the coordinates are (*parport, *mux,
+
+ SEE ALSO
+
+-parport_device_num, parport_open, parport_device_id
++parport_open, parport_device_id
+
+ parport_find_class - find a device by its class
+ ------------------
+diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
+index ff9f344..5bbff20 100644
+--- a/drivers/parport/daisy.c
++++ b/drivers/parport/daisy.c
+@@ -275,35 +275,6 @@ void parport_close(struct pardevice *dev)
+ parport_unregister_device(dev);
+ }
+
+-/**
+- * parport_device_num - convert device coordinates
+- * @parport: parallel port number
+- * @mux: multiplexor port number (-1 for no multiplexor)
+- * @daisy: daisy chain address (-1 for no daisy chain address)
+- *
+- * This tries to locate a device on the given parallel port,
+- * multiplexor port and daisy chain address, and returns its
+- * device number or %-ENXIO if no device with those coordinates
+- * exists.
+- **/
+-
+-int parport_device_num(int parport, int mux, int daisy)
+-{
+- int res = -ENXIO;
+- struct daisydev *dev;
+-
+- spin_lock(&topology_lock);
+- dev = topology;
+- while (dev && dev->port->portnum != parport &&
+- dev->port->muxport != mux && dev->daisy != daisy)
+- dev = dev->next;
+- if (dev)
+- res = dev->devnum;
+- spin_unlock(&topology_lock);
+-
+- return res;
+-}
+-
+ /* Send a daisy-chain-style CPP command packet. */
+ static int cpp_daisy(struct parport *port, int cmd)
+ {
+diff --git a/include/linux/parport.h b/include/linux/parport.h
+index 9cdd694..ec3f765 100644
+--- a/include/linux/parport.h
++++ b/include/linux/parport.h
+@@ -510,7 +510,6 @@ extern struct pardevice *parport_open (int devnum, const char *name,
+ int flags, void *handle);
+ extern void parport_close (struct pardevice *dev);
+ extern ssize_t parport_device_id (int devnum, char *buffer, size_t len);
+-extern int parport_device_num (int parport, int mux, int daisy);
+ extern void parport_daisy_deselect_all (struct parport *port);
+ extern int parport_daisy_select (struct parport *port, int daisy, int mode);
+
+
+
+From bunk@kernel.org Fri Aug 24 05:07:37 2007
+From: Adrian Bunk <bunk@kernel.org>
+To: Andrew Morton <akpm@linux-foundation.org>,
+ Chris Wright <chrisw@sous-sol.org>
+Cc: linux-kernel@vger.kernel.org
+Subject: [-mm patch] make do_restart_poll() static
+References: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+MIME-Version: 1.0
+Content-Type: text/plain; charset=utf-8
+Content-Disposition: inline
+In-Reply-To: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+X-Mutt-References: <20070822020648.5ea3a612.akpm@linux-foundation.org>
+X-Mutt-Fcc: =sent-mail
+Status: RO
+Content-Length: 728
+Lines: 29
+
+On Wed, Aug 22, 2007 at 02:06:48AM -0700, Andrew Morton wrote:
+>...
+> Changes since 2.6.23-rc2-mm2:
+>...
+> +use-erestart_restartblock-if-poll-is-interrupted-by-a-signal.patch
+>...
+> The infamous misc
+>...
+
+do_restart_poll() can become static.
+
+Signed-off-by: Adrian Bunk <bunk@kernel.org>
+
+---
+59cd2d11f5f0189973bb280c59262eb50984cb88
+diff --git a/fs/select.c b/fs/select.c
+index 5a3ab01..3e515aa 100644
+--- a/fs/select.c
++++ b/fs/select.c
+@@ -711,7 +711,7 @@ out_fds:
+ return err;
+ }
+
+-long do_restart_poll(struct restart_block *restart_block)
++static long do_restart_poll(struct restart_block *restart_block)
+ {
+ struct pollfd __user *ufds = (struct pollfd __user*)restart_block->arg0;
+ int nfds = restart_block->arg1;
+
+
diff --git a/patch_cmds/diffstat/testing/case27.ref b/patch_cmds/diffstat/testing/case27.ref
new file mode 100644
index 0000000..1a49489
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27.ref
@@ -0,0 +1,8 @@
+ Makefile | 4 ++++
+ b/Documentation/parport-lowlevel.txt | 29 +++--------------------------
+ b/drivers/cpuidle/governors/menu.c | 2 +-
+ b/drivers/parport/daisy.c | 29 -----------------------------
+ b/fs/select.c | 2 +-
+ b/include/linux/parport.h | 1 -
+ scripts/export_report.pl | 2 +-
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27R.ref b/patch_cmds/diffstat/testing/case27R.ref
new file mode 100644
index 0000000..9adf7c2
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27R.ref
@@ -0,0 +1,8 @@
+ a/Documentation/parport-lowlevel.txt | 29 ++++++++++++++++++++++++++---
+ a/drivers/cpuidle/governors/menu.c | 2 +-
+ a/drivers/parport/daisy.c | 29 +++++++++++++++++++++++++++++
+ a/fs/select.c | 2 +-
+ a/include/linux/parport.h | 1 +
+ a/scripts/export_report.pl | 2 +-
+ b/Makefile | 4 ----
+ 7 files changed, 59 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27Rp0.ref b/patch_cmds/diffstat/testing/case27Rp0.ref
new file mode 100644
index 0000000..9adf7c2
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27Rp0.ref
@@ -0,0 +1,8 @@
+ a/Documentation/parport-lowlevel.txt | 29 ++++++++++++++++++++++++++---
+ a/drivers/cpuidle/governors/menu.c | 2 +-
+ a/drivers/parport/daisy.c | 29 +++++++++++++++++++++++++++++
+ a/fs/select.c | 2 +-
+ a/include/linux/parport.h | 1 +
+ a/scripts/export_report.pl | 2 +-
+ b/Makefile | 4 ----
+ 7 files changed, 59 insertions(+), 10 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27b.ref b/patch_cmds/diffstat/testing/case27b.ref
new file mode 100644
index 0000000..1a49489
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27b.ref
@@ -0,0 +1,8 @@
+ Makefile | 4 ++++
+ b/Documentation/parport-lowlevel.txt | 29 +++--------------------------
+ b/drivers/cpuidle/governors/menu.c | 2 +-
+ b/drivers/parport/daisy.c | 29 -----------------------------
+ b/fs/select.c | 2 +-
+ b/include/linux/parport.h | 1 -
+ scripts/export_report.pl | 2 +-
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27f0.ref b/patch_cmds/diffstat/testing/case27f0.ref
new file mode 100644
index 0000000..87c5d63
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27f0.ref
@@ -0,0 +1,8 @@
+ Makefile | 4 4 + 0 - 0 !
+ b/Documentation/parport-lowlevel.txt | 29 3 + 26 - 0 !
+ b/drivers/cpuidle/governors/menu.c | 2 1 + 1 - 0 !
+ b/drivers/parport/daisy.c | 29 0 + 29 - 0 !
+ b/fs/select.c | 2 1 + 1 - 0 !
+ b/include/linux/parport.h | 1 0 + 1 - 0 !
+ scripts/export_report.pl | 2 1 + 1 - 0 !
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27k.ref b/patch_cmds/diffstat/testing/case27k.ref
new file mode 100644
index 0000000..1a49489
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27k.ref
@@ -0,0 +1,8 @@
+ Makefile | 4 ++++
+ b/Documentation/parport-lowlevel.txt | 29 +++--------------------------
+ b/drivers/cpuidle/governors/menu.c | 2 +-
+ b/drivers/parport/daisy.c | 29 -----------------------------
+ b/fs/select.c | 2 +-
+ b/include/linux/parport.h | 1 -
+ scripts/export_report.pl | 2 +-
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27p1.ref b/patch_cmds/diffstat/testing/case27p1.ref
new file mode 100644
index 0000000..5e90eec
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27p1.ref
@@ -0,0 +1,8 @@
+ Documentation/parport-lowlevel.txt | 29 +++--------------------------
+ Makefile | 4 ++++
+ drivers/cpuidle/governors/menu.c | 2 +-
+ drivers/parport/daisy.c | 29 -----------------------------
+ fs/select.c | 2 +-
+ include/linux/parport.h | 1 -
+ scripts/export_report.pl | 2 +-
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27p9.ref b/patch_cmds/diffstat/testing/case27p9.ref
new file mode 100644
index 0000000..9f61d61
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27p9.ref
@@ -0,0 +1,8 @@
+ Makefile | 4 ++++
+ daisy.c | 29 -----------------------------
+ export_report.pl | 2 +-
+ menu.c | 2 +-
+ parport-lowlevel.txt | 29 +++--------------------------
+ parport.h | 1 -
+ select.c | 2 +-
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27r1.ref b/patch_cmds/diffstat/testing/case27r1.ref
new file mode 100644
index 0000000..1a49489
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27r1.ref
@@ -0,0 +1,8 @@
+ Makefile | 4 ++++
+ b/Documentation/parport-lowlevel.txt | 29 +++--------------------------
+ b/drivers/cpuidle/governors/menu.c | 2 +-
+ b/drivers/parport/daisy.c | 29 -----------------------------
+ b/fs/select.c | 2 +-
+ b/include/linux/parport.h | 1 -
+ scripts/export_report.pl | 2 +-
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27r2.ref b/patch_cmds/diffstat/testing/case27r2.ref
new file mode 100644
index 0000000..1a49489
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27r2.ref
@@ -0,0 +1,8 @@
+ Makefile | 4 ++++
+ b/Documentation/parport-lowlevel.txt | 29 +++--------------------------
+ b/drivers/cpuidle/governors/menu.c | 2 +-
+ b/drivers/parport/daisy.c | 29 -----------------------------
+ b/fs/select.c | 2 +-
+ b/include/linux/parport.h | 1 -
+ scripts/export_report.pl | 2 +-
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case27u.ref b/patch_cmds/diffstat/testing/case27u.ref
new file mode 100644
index 0000000..86b3dda
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case27u.ref
@@ -0,0 +1,8 @@
+ scripts/export_report.pl | 2 +-
+ Makefile | 4 ++++
+ b/drivers/cpuidle/governors/menu.c | 2 +-
+ b/Documentation/parport-lowlevel.txt | 29 +++--------------------------
+ b/drivers/parport/daisy.c | 29 -----------------------------
+ b/include/linux/parport.h | 1 -
+ b/fs/select.c | 2 +-
+ 7 files changed, 10 insertions(+), 59 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28.pat b/patch_cmds/diffstat/testing/case28.pat
new file mode 100644
index 0000000..c8fd4f7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28.pat
@@ -0,0 +1,326 @@
+***************
+*** 1,11 ****
+- revlist for vile-9.7c, version v9_7c
+ --------------------------------------------------------------------------------
+- aclocal.m4 1.183
+ ansi.c 1.49
+ api.c 1.44
+ api.h 1.13
+ basic.c 1.161
+- bind.c 1.320
+ blist.c 1.11
+ blist.h 1.4
+ borland.c 1.38
+--- 1,11 ----
++ revlist for vile, version v9_7d
+ --------------------------------------------------------------------------------
++ aclocal.m4 1.185
+ ansi.c 1.49
+ api.c 1.44
+ api.h 1.13
+ basic.c 1.161
++ bind.c 1.322
+ blist.c 1.11
+ blist.h 1.4
+ borland.c 1.38
+***************
+*** 14,20 ****
+ buffer.c 1.331
+ buglist 1.412
+ builtflt.c 1.63
+- CHANGES 1.1177
+ CHANGES.R3 1.1
+ CHANGES.R4 1.1
+ CHANGES.R5 1.1
+--- 14,20 ----
+ buffer.c 1.331
+ buglist 1.412
+ builtflt.c 1.63
++ CHANGES 1.1189
+ CHANGES.R3 1.1
+ CHANGES.R4 1.1
+ CHANGES.R5 1.1
+***************
+*** 23,34 ****
+ CHANGES.R8 1.1
+ charsets.c 1.56
+ chgdfunc.h 1.22
+- cmdtbl 1.253
+ config.guess 1.8
+ config_h.in 1.2
+ config.sub 1.9
+- configure 1.21
+- configure.in 1.246
+ COPYING 1.4
+ csrch.c 1.34
+ curses.c 1.38
+--- 23,34 ----
+ CHANGES.R8 1.1
+ charsets.c 1.56
+ chgdfunc.h 1.22
++ cmdtbl 1.255
+ config.guess 1.8
+ config_h.in 1.2
+ config.sub 1.9
++ configure 1.22
++ configure.in 1.247
+ COPYING 1.4
+ csrch.c 1.34
+ curses.c 1.38
+***************
+*** 37,47 ****
+ display.c 1.476
+ djhandl.c 1.6
+ dumbterm.c 1.23
+- edef.h 1.339
+ eightbit.c 1.45
+- estruct.h 1.663
+- eval.c 1.383
+- exec.c 1.314
+ externs.c 1.11
+ fences.c 1.86
+ file.c 1.415
+--- 37,47 ----
+ display.c 1.476
+ djhandl.c 1.6
+ dumbterm.c 1.23
++ edef.h 1.341
+ eightbit.c 1.45
++ estruct.h 1.665
++ eval.c 1.386
++ exec.c 1.325
+ externs.c 1.11
+ fences.c 1.86
+ file.c 1.415
+***************
+*** 52,97 ****
+ glob.c 1.93
+ gppconio.c 1.2
+ history.c 1.87
+- input.c 1.320
+ insert.c 1.167
+ INSTALL 1.6
+ install.sh 1.7
+ isearch.c 1.60
+ itbuff.c 1.25
+ lckfiles.c 1.11
+- line.c 1.193
+- main.c 1.642
+ makeargv.c 1.3
+ makeargv.h 1.3
+ makefile.blc 1.22
+ makefile.djg 1.38
+ makefile.icc 1.17
+- makefile.in 1.211
+ makefile.wnt 1.99
+ MANIFEST none
+ map.c 1.112
+- menu.c 1.51
+ mkdirs.sh 1.7
+ mkprlenv.wnt 1.9
+ mktbls.c 1.151
+ modes.c 1.363
+- modetbl 1.275
+ msgs.c 1.29
+- npopen.c 1.95
+ ntconio.c 1.91
+ ntwinio.c 1.188
+ nullterm.c 1.5
+ oneliner.c 1.112
+- opers.c 1.93
+ os2keys.h 1.2
+ os2pipe.c 1.5
+ os2vio.c 1.36
+- patchlev.h 1.378
+ path.c 1.162
+ perl.xs 1.111
+ plugin.c 1.1
+ plugin.h 1.1
+- proto.h 1.650
+ pscreen.h 1.2
+ ptypemap 1.7
+ random.c 1.319
+--- 52,97 ----
+ glob.c 1.93
+ gppconio.c 1.2
+ history.c 1.87
++ input.c 1.321
+ insert.c 1.167
+ INSTALL 1.6
+ install.sh 1.7
+ isearch.c 1.60
+ itbuff.c 1.25
+ lckfiles.c 1.11
++ line.c 1.194
++ main.c 1.647
+ makeargv.c 1.3
+ makeargv.h 1.3
+ makefile.blc 1.22
+ makefile.djg 1.38
+ makefile.icc 1.17
++ makefile.in 1.212
+ makefile.wnt 1.99
+ MANIFEST none
+ map.c 1.112
++ menu.c 1.52
+ mkdirs.sh 1.7
+ mkprlenv.wnt 1.9
+ mktbls.c 1.151
+ modes.c 1.363
++ modetbl 1.276
+ msgs.c 1.29
++ npopen.c 1.96
+ ntconio.c 1.91
+ ntwinio.c 1.188
+ nullterm.c 1.5
+ oneliner.c 1.112
++ opers.c 1.97
+ os2keys.h 1.2
+ os2pipe.c 1.5
+ os2vio.c 1.36
++ patchlev.h 1.379
+ path.c 1.162
+ perl.xs 1.111
+ plugin.c 1.1
+ plugin.h 1.1
++ proto.h 1.657
+ pscreen.h 1.2
+ ptypemap 1.7
+ random.c 1.319
+***************
+*** 100,125 ****
+ README.VMS 1.5
+ regexp.c 1.139
+ region.c 1.149
+- revlist v9_7c
+ search.c 1.146
+- select.c 1.167
+ sinstall.sh 1.1
+- spawn.c 1.195
+- statevar.c 1.122
+ tags.c 1.138
+- tbuff.c 1.68
+ tcap.c 1.177
+ tcap.h 1.14
+ termio.c 1.214
+ test_io.c 1.2
+- trace.c 1.80
+ trace.h 1.31
+ ucrypt.c 1.15
+- undo.c 1.96
+ version.c 1.66
+ vile.1 1.37
+- vile-9.7.spec 1.5
+- vile.hlp 1.655
+ vile.wmconfig 1.1
+ vl_alloc.h 1.1
+ vl_ctype.h 1.15
+--- 100,125 ----
+ README.VMS 1.5
+ regexp.c 1.139
+ region.c 1.149
++ revlist v9_7d
+ search.c 1.146
++ select.c 1.168
+ sinstall.sh 1.1
++ spawn.c 1.200
++ statevar.c 1.123
+ tags.c 1.138
++ tbuff.c 1.69
+ tcap.c 1.177
+ tcap.h 1.14
+ termio.c 1.214
+ test_io.c 1.2
++ trace.c 1.81
+ trace.h 1.31
+ ucrypt.c 1.15
++ undo.c 1.99
+ version.c 1.66
+ vile.1 1.37
++ vile-9.7.spec 1.6
++ vile.hlp 1.657
+ vile.wmconfig 1.1
+ vl_alloc.h 1.1
+ vl_ctype.h 1.15
+***************
+*** 159,165 ****
+ doc/config.doc 1.15
+ doc/dir.doc 1.3
+ doc/filters.doc 1.40
+- doc/macros.doc 1.107
+ doc/menus.doc 1.7
+ doc/modes.doc 1.17
+ doc/ncu-indent 1.16
+--- 159,165 ----
+ doc/config.doc 1.15
+ doc/dir.doc 1.3
+ doc/filters.doc 1.40
++ doc/macros.doc 1.111
+ doc/menus.doc 1.7
+ doc/modes.doc 1.17
+ doc/ncu-indent 1.16
+***************
+*** 237,250 ****
+ filters/key-filt.c 1.41
+ filters/latexflt.l 1.48
+ filters/latex.key 1.2
+- filters/lex-filt.l 1.62
+ filters/lex.key 1.8
+ filters/lispfilt.l 1.20
+ filters/lisp.key 1.2
+ filters/lua-filt.l 1.8
+ filters/lua.key 1.2
+ filters/m4-filt.c 1.30
+- filters/m4.key 1.3
+ filters/mailcap.key 1.3
+ filters/mailfilt.l 1.22
+ filters/mail.key 1.3
+--- 237,250 ----
+ filters/key-filt.c 1.41
+ filters/latexflt.l 1.48
+ filters/latex.key 1.2
++ filters/lex-filt.l 1.67
+ filters/lex.key 1.8
+ filters/lispfilt.l 1.20
+ filters/lisp.key 1.2
+ filters/lua-filt.l 1.8
+ filters/lua.key 1.2
+ filters/m4-filt.c 1.30
++ filters/m4.key 1.5
+ filters/mailcap.key 1.3
+ filters/mailfilt.l 1.22
+ filters/mail.key 1.3
+***************
+*** 332,338 ****
+ filters/vb6.key 1.5
+ filters/vb.key 1.15
+ filters/vbs.key 1.4
+- filters/vilefilt.l 1.57
+ filters/vile.key 1.8
+ filters/vim.key 1.2
+ filters/vl-filt.l 1.15
+--- 332,338 ----
+ filters/vb6.key 1.5
+ filters/vb.key 1.15
+ filters/vbs.key 1.4
++ filters/vilefilt.l 1.59
+ filters/vile.key 1.8
+ filters/vim.key 1.2
+ filters/vl-filt.l 1.15
+***************
+*** 362,368 ****
+ macros/gnugpg.rc 1.3
+ macros/loaderrs.rc 1.2
+ macros/manpage.rc 1.24
+- macros/modes.rc 1.79
+ macros/palettes.rc 1.8
+ macros/pictmode.rc 1.4
+ macros/search.rc 1.3
+--- 362,368 ----
+ macros/gnugpg.rc 1.3
+ macros/loaderrs.rc 1.2
+ macros/manpage.rc 1.24
++ macros/modes.rc 1.80
+ macros/palettes.rc 1.8
+ macros/pictmode.rc 1.4
+ macros/search.rc 1.3
diff --git a/patch_cmds/diffstat/testing/case28.ref b/patch_cmds/diffstat/testing/case28.ref
new file mode 100644
index 0000000..74f3d11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28R.ref b/patch_cmds/diffstat/testing/case28R.ref
new file mode 100644
index 0000000..74f3d11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28R.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28Rp0.ref b/patch_cmds/diffstat/testing/case28Rp0.ref
new file mode 100644
index 0000000..1300477
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28Rp0.ref
@@ -0,0 +1,2 @@
+ ./testing/case28.pat | 70 +++++++++++++++++++++++++--------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28b.ref b/patch_cmds/diffstat/testing/case28b.ref
new file mode 100644
index 0000000..74f3d11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28b.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28f0.ref b/patch_cmds/diffstat/testing/case28f0.ref
new file mode 100644
index 0000000..7b4e062
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28f0.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 35 + 35 - 0 !
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28k.ref b/patch_cmds/diffstat/testing/case28k.ref
new file mode 100644
index 0000000..74f3d11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28k.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28p1.ref b/patch_cmds/diffstat/testing/case28p1.ref
new file mode 100644
index 0000000..d36eb16
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28p1.ref
@@ -0,0 +1,2 @@
+ testing/case28.pat | 70 ++++++++++++++++++++++++++---------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28p9.ref b/patch_cmds/diffstat/testing/case28p9.ref
new file mode 100644
index 0000000..74f3d11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28p9.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28r1.ref b/patch_cmds/diffstat/testing/case28r1.ref
new file mode 100644
index 0000000..2d893c7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28r1.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 ++++++++++++++++++++++++++++++------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28r2.ref b/patch_cmds/diffstat/testing/case28r2.ref
new file mode 100644
index 0000000..2d893c7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28r2.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 ++++++++++++++++++++++++++++++------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case28u.ref b/patch_cmds/diffstat/testing/case28u.ref
new file mode 100644
index 0000000..74f3d11
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case28u.ref
@@ -0,0 +1,2 @@
+ case28.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29.pat b/patch_cmds/diffstat/testing/case29.pat
new file mode 100644
index 0000000..a38689f
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29.pat
@@ -0,0 +1,193 @@
+@@ -1,11 +1,11 @@
+-revlist for vile-9.7c, version v9_7c
++revlist for vile, version v9_7d
+ --------------------------------------------------------------------------------
+-aclocal.m4 1.183
++aclocal.m4 1.185
+ ansi.c 1.49
+ api.c 1.44
+ api.h 1.13
+ basic.c 1.161
+-bind.c 1.320
++bind.c 1.322
+ blist.c 1.11
+ blist.h 1.4
+ borland.c 1.38
+@@ -14,7 +14,7 @@
+ buffer.c 1.331
+ buglist 1.412
+ builtflt.c 1.63
+-CHANGES 1.1177
++CHANGES 1.1189
+ CHANGES.R3 1.1
+ CHANGES.R4 1.1
+ CHANGES.R5 1.1
+@@ -23,12 +23,12 @@
+ CHANGES.R8 1.1
+ charsets.c 1.56
+ chgdfunc.h 1.22
+-cmdtbl 1.253
++cmdtbl 1.255
+ config.guess 1.8
+ config_h.in 1.2
+ config.sub 1.9
+-configure 1.21
+-configure.in 1.246
++configure 1.22
++configure.in 1.247
+ COPYING 1.4
+ csrch.c 1.34
+ curses.c 1.38
+@@ -37,11 +37,11 @@
+ display.c 1.476
+ djhandl.c 1.6
+ dumbterm.c 1.23
+-edef.h 1.339
++edef.h 1.341
+ eightbit.c 1.45
+-estruct.h 1.663
+-eval.c 1.383
+-exec.c 1.314
++estruct.h 1.665
++eval.c 1.386
++exec.c 1.325
+ externs.c 1.11
+ fences.c 1.86
+ file.c 1.415
+@@ -52,46 +52,46 @@
+ glob.c 1.93
+ gppconio.c 1.2
+ history.c 1.87
+-input.c 1.320
++input.c 1.321
+ insert.c 1.167
+ INSTALL 1.6
+ install.sh 1.7
+ isearch.c 1.60
+ itbuff.c 1.25
+ lckfiles.c 1.11
+-line.c 1.193
+-main.c 1.642
++line.c 1.194
++main.c 1.647
+ makeargv.c 1.3
+ makeargv.h 1.3
+ makefile.blc 1.22
+ makefile.djg 1.38
+ makefile.icc 1.17
+-makefile.in 1.211
++makefile.in 1.212
+ makefile.wnt 1.99
+ MANIFEST none
+ map.c 1.112
+-menu.c 1.51
++menu.c 1.52
+ mkdirs.sh 1.7
+ mkprlenv.wnt 1.9
+ mktbls.c 1.151
+ modes.c 1.363
+-modetbl 1.275
++modetbl 1.276
+ msgs.c 1.29
+-npopen.c 1.95
++npopen.c 1.96
+ ntconio.c 1.91
+ ntwinio.c 1.188
+ nullterm.c 1.5
+ oneliner.c 1.112
+-opers.c 1.93
++opers.c 1.97
+ os2keys.h 1.2
+ os2pipe.c 1.5
+ os2vio.c 1.36
+-patchlev.h 1.378
++patchlev.h 1.379
+ path.c 1.162
+ perl.xs 1.111
+ plugin.c 1.1
+ plugin.h 1.1
+-proto.h 1.650
++proto.h 1.657
+ pscreen.h 1.2
+ ptypemap 1.7
+ random.c 1.319
+@@ -100,26 +100,26 @@
+ README.VMS 1.5
+ regexp.c 1.139
+ region.c 1.149
+-revlist v9_7c
++revlist v9_7d
+ search.c 1.146
+-select.c 1.167
++select.c 1.168
+ sinstall.sh 1.1
+-spawn.c 1.195
+-statevar.c 1.122
++spawn.c 1.200
++statevar.c 1.123
+ tags.c 1.138
+-tbuff.c 1.68
++tbuff.c 1.69
+ tcap.c 1.177
+ tcap.h 1.14
+ termio.c 1.214
+ test_io.c 1.2
+-trace.c 1.80
++trace.c 1.81
+ trace.h 1.31
+ ucrypt.c 1.15
+-undo.c 1.96
++undo.c 1.99
+ version.c 1.66
+ vile.1 1.37
+-vile-9.7.spec 1.5
+-vile.hlp 1.655
++vile-9.7.spec 1.6
++vile.hlp 1.657
+ vile.wmconfig 1.1
+ vl_alloc.h 1.1
+ vl_ctype.h 1.15
+@@ -159,7 +159,7 @@
+ doc/config.doc 1.15
+ doc/dir.doc 1.3
+ doc/filters.doc 1.40
+-doc/macros.doc 1.107
++doc/macros.doc 1.111
+ doc/menus.doc 1.7
+ doc/modes.doc 1.17
+ doc/ncu-indent 1.16
+@@ -237,14 +237,14 @@
+ filters/key-filt.c 1.41
+ filters/latexflt.l 1.48
+ filters/latex.key 1.2
+-filters/lex-filt.l 1.62
++filters/lex-filt.l 1.67
+ filters/lex.key 1.8
+ filters/lispfilt.l 1.20
+ filters/lisp.key 1.2
+ filters/lua-filt.l 1.8
+ filters/lua.key 1.2
+ filters/m4-filt.c 1.30
+-filters/m4.key 1.3
++filters/m4.key 1.5
+ filters/mailcap.key 1.3
+ filters/mailfilt.l 1.22
+ filters/mail.key 1.3
+@@ -332,7 +332,7 @@
+ filters/vb6.key 1.5
+ filters/vb.key 1.15
+ filters/vbs.key 1.4
+-filters/vilefilt.l 1.57
++filters/vilefilt.l 1.59
+ filters/vile.key 1.8
+ filters/vim.key 1.2
+ filters/vl-filt.l 1.15
+@@ -362,7 +362,7 @@
+ macros/gnugpg.rc 1.3
+ macros/loaderrs.rc 1.2
+ macros/manpage.rc 1.24
+-macros/modes.rc 1.79
++macros/modes.rc 1.80
+ macros/palettes.rc 1.8
+ macros/pictmode.rc 1.4
+ macros/search.rc 1.3
diff --git a/patch_cmds/diffstat/testing/case29.ref b/patch_cmds/diffstat/testing/case29.ref
new file mode 100644
index 0000000..15df096
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29R.ref b/patch_cmds/diffstat/testing/case29R.ref
new file mode 100644
index 0000000..15df096
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29R.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29Rp0.ref b/patch_cmds/diffstat/testing/case29Rp0.ref
new file mode 100644
index 0000000..2853ccf
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29Rp0.ref
@@ -0,0 +1,2 @@
+ ./testing/case29.pat | 70 +++++++++++++++++++++++++--------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29b.ref b/patch_cmds/diffstat/testing/case29b.ref
new file mode 100644
index 0000000..15df096
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29b.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29f0.ref b/patch_cmds/diffstat/testing/case29f0.ref
new file mode 100644
index 0000000..cfaaa2a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29f0.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 35 + 35 - 0 !
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29k.ref b/patch_cmds/diffstat/testing/case29k.ref
new file mode 100644
index 0000000..15df096
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29k.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29p1.ref b/patch_cmds/diffstat/testing/case29p1.ref
new file mode 100644
index 0000000..cc13b24
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29p1.ref
@@ -0,0 +1,2 @@
+ testing/case29.pat | 70 ++++++++++++++++++++++++++---------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29p9.ref b/patch_cmds/diffstat/testing/case29p9.ref
new file mode 100644
index 0000000..15df096
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29p9.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29r1.ref b/patch_cmds/diffstat/testing/case29r1.ref
new file mode 100644
index 0000000..7f84767
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29r1.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 ++++++++++++++++++++++++++++++------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29r2.ref b/patch_cmds/diffstat/testing/case29r2.ref
new file mode 100644
index 0000000..7f84767
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29r2.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 ++++++++++++++++++++++++++++++------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case29u.ref b/patch_cmds/diffstat/testing/case29u.ref
new file mode 100644
index 0000000..15df096
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case29u.ref
@@ -0,0 +1,2 @@
+ case29.pat | 70 ++++++++++++++++++++++++++++++-------------------------------
+ 1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31.pat b/patch_cmds/diffstat/testing/case31.pat
new file mode 100644
index 0000000..392005b
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31.pat
@@ -0,0 +1,22 @@
+==== //depot/vendor/freebsd/src/sys/dev/usb/usbdevs#353 (text+ko) - //depot/projects/usb/src/sys/dev/usb/usbdevs#72 (text+ko) ==== content
+1c1
+< $FreeBSD: src/sys/dev/usb/usbdevs,v 1.421 2009/07/30 18:53:06 weongyo Exp $
+---
+> $FreeBSD: src/sys/dev/usb/usbdevs,v 1.420 2009/07/30 00:15:17 alfred Exp $
+863a864,869
+> product APPLE KBD_TP_ANSI 0x0223 Apple Internal Keyboard/Trackpad (Wellspring/ANSI)
+> product APPLE KBD_TP_ISO 0x0224 Apple Internal Keyboard/Trackpad (Wellspring/ISO)
+> product APPLE KBD_TP_JIS 0x0225 Apple Internal Keyboard/Trackpad (Wellspring/JIS)
+> product APPLE KBD_TP_ANSI2 0x0230 Apple Internal Keyboard/Trackpad (Wellspring2/ANSI)
+> product APPLE KBD_TP_ISO2 0x0231 Apple Internal Keyboard/Trackpad (Wellspring2/ISO)
+> product APPLE KBD_TP_JIS2 0x0232 Apple Internal Keyboard/Trackpad (Wellspring2/JIS)
+904a911
+> product ASUS GMSC 0x422f ASUS Generic Mass Storage
+1180,1181d1186
+< product DLINK2 DWA120_NF 0x3a0d DWA-120 (no firmware)
+< product DLINK2 DWA120 0x3a0e DWA-120
+1185a1191,1192
+> product DLINK2 DWA120_NF 0x3c0d DWA-120 (no firmware)
+> product DLINK2 DWA120 0x3c0e DWA-120
+1973a1981
+> product PHILIPS SPE3030CC 0x083a USB 2.0 External Disk
diff --git a/patch_cmds/diffstat/testing/case31.ref b/patch_cmds/diffstat/testing/case31.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31R.ref b/patch_cmds/diffstat/testing/case31R.ref
new file mode 100644
index 0000000..92ce8c7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31R.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31Rp0.ref b/patch_cmds/diffstat/testing/case31Rp0.ref
new file mode 100644
index 0000000..fcade37
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31Rp0.ref
@@ -0,0 +1,2 @@
+ //depot/vendor/freebsd/src/sys/dev/usb/usbdevs | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31b.ref b/patch_cmds/diffstat/testing/case31b.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31b.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31f0.ref b/patch_cmds/diffstat/testing/case31f0.ref
new file mode 100644
index 0000000..8e2de2e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31f0.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 11 + 3 - 0 !
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31k.ref b/patch_cmds/diffstat/testing/case31k.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31k.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31l.pat b/patch_cmds/diffstat/testing/case31l.pat
new file mode 100644
index 0000000..8c422c6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31l.pat
@@ -0,0 +1,8 @@
+==== //depot/user/ed/newcons/sys/kern/tty.c#2 - /home/ed/p4/newcons/sys/kern/tty.c ====
+@@ -1,5 +1,5 @@
+ /*-
+- * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
++ * Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Portions of this software were developed under sponsorship from Snow
diff --git a/patch_cmds/diffstat/testing/case31l.ref b/patch_cmds/diffstat/testing/case31l.ref
new file mode 100644
index 0000000..203a288
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31l.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lR.ref b/patch_cmds/diffstat/testing/case31lR.ref
new file mode 100644
index 0000000..203a288
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lR.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lRp0.ref b/patch_cmds/diffstat/testing/case31lRp0.ref
new file mode 100644
index 0000000..870e071
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lRp0.ref
@@ -0,0 +1,2 @@
+ //depot/user/ed/newcons/sys/kern/tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lb.ref b/patch_cmds/diffstat/testing/case31lb.ref
new file mode 100644
index 0000000..203a288
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lb.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lf0.ref b/patch_cmds/diffstat/testing/case31lf0.ref
new file mode 100644
index 0000000..337c1eb
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lf0.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 1 + 1 - 0 !
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lk.ref b/patch_cmds/diffstat/testing/case31lk.ref
new file mode 100644
index 0000000..203a288
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lk.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lp1.ref b/patch_cmds/diffstat/testing/case31lp1.ref
new file mode 100644
index 0000000..c91504a
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lp1.ref
@@ -0,0 +1,2 @@
+ /depot/user/ed/newcons/sys/kern/tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lp9.ref b/patch_cmds/diffstat/testing/case31lp9.ref
new file mode 100644
index 0000000..203a288
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lp9.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lr1.ref b/patch_cmds/diffstat/testing/case31lr1.ref
new file mode 100644
index 0000000..203a288
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lr1.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lr2.ref b/patch_cmds/diffstat/testing/case31lr2.ref
new file mode 100644
index 0000000..203a288
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lr2.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31lu.ref b/patch_cmds/diffstat/testing/case31lu.ref
new file mode 100644
index 0000000..203a288
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31lu.ref
@@ -0,0 +1,2 @@
+ tty.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/patch_cmds/diffstat/testing/case31p1.ref b/patch_cmds/diffstat/testing/case31p1.ref
new file mode 100644
index 0000000..0481b33
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31p1.ref
@@ -0,0 +1,2 @@
+ /depot/vendor/freebsd/src/sys/dev/usb/usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31p9.ref b/patch_cmds/diffstat/testing/case31p9.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31p9.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31r1.ref b/patch_cmds/diffstat/testing/case31r1.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31r1.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31r2.ref b/patch_cmds/diffstat/testing/case31r2.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31r2.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31u.pat b/patch_cmds/diffstat/testing/case31u.pat
new file mode 100644
index 0000000..81c0046
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31u.pat
@@ -0,0 +1,51 @@
+==== //depot/vendor/freebsd/src/sys/dev/usb/usbdevs#353 (text+ko) - //depot/projects/usb/src/sys/dev/usb/usbdevs#72 (text+ko) ==== content
+@@ -1,4 +1,4 @@
+-$FreeBSD: src/sys/dev/usb/usbdevs,v 1.421 2009/07/30 18:53:06 weongyo Exp $
++$FreeBSD: src/sys/dev/usb/usbdevs,v 1.420 2009/07/30 00:15:17 alfred Exp $
+ /* $NetBSD: usbdevs,v 1.392 2004/12/29 08:38:44 imp Exp $ */
+
+ /*-
+@@ -861,6 +861,12 @@
+
+ /* Apple Computer products */
+ product APPLE EXT_KBD 0x020c Apple Extended USB Keyboard
++product APPLE KBD_TP_ANSI 0x0223 Apple Internal Keyboard/Trackpad (Wellspring/ANSI)
++product APPLE KBD_TP_ISO 0x0224 Apple Internal Keyboard/Trackpad (Wellspring/ISO)
++product APPLE KBD_TP_JIS 0x0225 Apple Internal Keyboard/Trackpad (Wellspring/JIS)
++product APPLE KBD_TP_ANSI2 0x0230 Apple Internal Keyboard/Trackpad (Wellspring2/ANSI)
++product APPLE KBD_TP_ISO2 0x0231 Apple Internal Keyboard/Trackpad (Wellspring2/ISO)
++product APPLE KBD_TP_JIS2 0x0232 Apple Internal Keyboard/Trackpad (Wellspring2/JIS)
+ product APPLE OPTMOUSE 0x0302 Optical mouse
+ product APPLE MIGHTYMOUSE 0x0304 Mighty Mouse
+ product APPLE EXT_KBD_HUB 0x1003 Hub in Apple Extended USB Keyboard
+@@ -902,6 +908,7 @@
+ product ASUS RT2573_2 0x1724 RT2573
+ product ASUS LCM 0x1726 LCM display
+ product ASUS P535 0x420f ASUS P535 PDA
++product ASUS GMSC 0x422f ASUS Generic Mass Storage
+
+ /* ATen products */
+ product ATEN UC1284 0x2001 Parallel printer
+@@ -1177,12 +1184,12 @@
+ product DLINK DSB650TX3 0x400b 10/100 Ethernet
+ product DLINK DSB650TX2 0x4102 10/100 Ethernet
+ product DLINK DSB650 0xabc1 10/100 Ethernet
+-product DLINK2 DWA120_NF 0x3a0d DWA-120 (no firmware)
+-product DLINK2 DWA120 0x3a0e DWA-120
+ product DLINK2 DWLG122C1 0x3c03 DWL-G122 c1
+ product DLINK2 WUA1340 0x3c04 WUA-1340
+ product DLINK2 DWA111 0x3c06 DWA-111
+ product DLINK2 DWA110 0x3c07 DWA-110
++product DLINK2 DWA120_NF 0x3c0d DWA-120 (no firmware)
++product DLINK2 DWA120 0x3c0e DWA-120
+
+ /* DMI products */
+ product DMI CFSM_RW 0xa109 CF/SM Reader/Writer
+@@ -1971,6 +1978,7 @@
+ product PHILIPS PCA646VC 0x0303 PCA646VC PC Camera
+ product PHILIPS PCVC680K 0x0308 PCVC680K Vesta Pro PC Camera
+ product PHILIPS DSS150 0x0471 DSS 150 Digital Speaker System
++product PHILIPS SPE3030CC 0x083a USB 2.0 External Disk
+ product PHILIPS SNU5600 0x1236 SNU5600
+ product PHILIPS UM10016 0x1552 ISP 1581 Hi-Speed USB MPEG2 Encoder Reference Kit
+ product PHILIPS DIVAUSB 0x1801 DIVA USB mp3 player
diff --git a/patch_cmds/diffstat/testing/case31u.ref b/patch_cmds/diffstat/testing/case31u.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31u.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31uR.ref b/patch_cmds/diffstat/testing/case31uR.ref
new file mode 100644
index 0000000..92ce8c7
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31uR.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31uRp0.ref b/patch_cmds/diffstat/testing/case31uRp0.ref
new file mode 100644
index 0000000..fcade37
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31uRp0.ref
@@ -0,0 +1,2 @@
+ //depot/vendor/freebsd/src/sys/dev/usb/usbdevs | 14 +++-----------
+ 1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31ub.ref b/patch_cmds/diffstat/testing/case31ub.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31ub.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31uf0.ref b/patch_cmds/diffstat/testing/case31uf0.ref
new file mode 100644
index 0000000..8e2de2e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31uf0.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 11 + 3 - 0 !
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31uk.ref b/patch_cmds/diffstat/testing/case31uk.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31uk.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31up1.ref b/patch_cmds/diffstat/testing/case31up1.ref
new file mode 100644
index 0000000..0481b33
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31up1.ref
@@ -0,0 +1,2 @@
+ /depot/vendor/freebsd/src/sys/dev/usb/usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31up9.ref b/patch_cmds/diffstat/testing/case31up9.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31up9.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31ur1.ref b/patch_cmds/diffstat/testing/case31ur1.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31ur1.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31ur2.ref b/patch_cmds/diffstat/testing/case31ur2.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31ur2.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case31uu.ref b/patch_cmds/diffstat/testing/case31uu.ref
new file mode 100644
index 0000000..7a9c6ad
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case31uu.ref
@@ -0,0 +1,2 @@
+ usbdevs | 14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32.pat b/patch_cmds/diffstat/testing/case32.pat
new file mode 100644
index 0000000..fc30350
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32.pat
@@ -0,0 +1,13 @@
+--- README 2001-10-10 20:23:46.000000000 -0400
++++ README.new 2009-08-31 05:24:30.000000000 -0400
+@@ -1,7 +1,7 @@
+ $Id: case32.pat,v 1.1 2009/08/31 09:24:46 tom Exp $
+
+-Readme file for DiffStat.
++Readme file for dIFFsTAT.
+
+ This program is a simple filter that reads the output of the 'diff' program,
+ and produces a histogram of the total number of lines that were changed. It is
+-useful for scanning a patch file to see which files were changed.
++useful for scanning a patch file to see which files were changed.
+\ No newline at end of file
diff --git a/patch_cmds/diffstat/testing/case32.ref b/patch_cmds/diffstat/testing/case32.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32R.ref b/patch_cmds/diffstat/testing/case32R.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32R.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32Rp0.ref b/patch_cmds/diffstat/testing/case32Rp0.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32Rp0.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32b.ref b/patch_cmds/diffstat/testing/case32b.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32b.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32f0.ref b/patch_cmds/diffstat/testing/case32f0.ref
new file mode 100644
index 0000000..bd160c6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32f0.ref
@@ -0,0 +1,2 @@
+ README | 4 2 + 2 - 0 !
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32k.ref b/patch_cmds/diffstat/testing/case32k.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32k.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32p1.ref b/patch_cmds/diffstat/testing/case32p1.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32p1.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32p9.ref b/patch_cmds/diffstat/testing/case32p9.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32p9.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32r1.ref b/patch_cmds/diffstat/testing/case32r1.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32r1.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32r2.ref b/patch_cmds/diffstat/testing/case32r2.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32r2.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case32u.ref b/patch_cmds/diffstat/testing/case32u.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case32u.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33.pat b/patch_cmds/diffstat/testing/case33.pat
new file mode 100644
index 0000000..69fe5f8
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33.pat
@@ -0,0 +1,13 @@
+--- README.new 2009-08-31 05:24:30.000000000 -0400
++++ README 2001-10-10 20:23:46.000000000 -0400
+@@ -1,7 +1,7 @@
+ $Id: case33.pat,v 1.1 2009/08/31 09:24:52 tom Exp $
+
+-Readme file for dIFFsTAT.
++Readme file for DiffStat.
+
+ This program is a simple filter that reads the output of the 'diff' program,
+ and produces a histogram of the total number of lines that were changed. It is
+-useful for scanning a patch file to see which files were changed.
+\ No newline at end of file
++useful for scanning a patch file to see which files were changed.
diff --git a/patch_cmds/diffstat/testing/case33.ref b/patch_cmds/diffstat/testing/case33.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33R.ref b/patch_cmds/diffstat/testing/case33R.ref
new file mode 100644
index 0000000..204cd97
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33R.ref
@@ -0,0 +1,2 @@
+ README.new | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33Rp0.ref b/patch_cmds/diffstat/testing/case33Rp0.ref
new file mode 100644
index 0000000..204cd97
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33Rp0.ref
@@ -0,0 +1,2 @@
+ README.new | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33b.ref b/patch_cmds/diffstat/testing/case33b.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33b.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33f0.ref b/patch_cmds/diffstat/testing/case33f0.ref
new file mode 100644
index 0000000..bd160c6
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33f0.ref
@@ -0,0 +1,2 @@
+ README | 4 2 + 2 - 0 !
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33k.ref b/patch_cmds/diffstat/testing/case33k.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33k.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33p1.ref b/patch_cmds/diffstat/testing/case33p1.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33p1.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33p9.ref b/patch_cmds/diffstat/testing/case33p9.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33p9.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33r1.ref b/patch_cmds/diffstat/testing/case33r1.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33r1.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33r2.ref b/patch_cmds/diffstat/testing/case33r2.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33r2.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/case33u.ref b/patch_cmds/diffstat/testing/case33u.ref
new file mode 100644
index 0000000..59cd19c
--- /dev/null
+++ b/patch_cmds/diffstat/testing/case33u.ref
@@ -0,0 +1,2 @@
+ README | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/patch_cmds/diffstat/testing/run_atac.sh b/patch_cmds/diffstat/testing/run_atac.sh
new file mode 100644
index 0000000..646862e
--- /dev/null
+++ b/patch_cmds/diffstat/testing/run_atac.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $Id: run_atac.sh,v 1.2 1998/01/17 01:10:06 tom Exp $
+rm -f /tmp/atac_dir/*
+run_test.sh
+atac -u ../*.atac /tmp/atac_dir/*
+atacmin ../*.atac /tmp/atac_dir/*
diff --git a/patch_cmds/diffstat/testing/run_test.sh b/patch_cmds/diffstat/testing/run_test.sh
new file mode 100644
index 0000000..c0faab2
--- /dev/null
+++ b/patch_cmds/diffstat/testing/run_test.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# $Id: run_test.sh,v 1.15 2012/01/03 10:18:14 tom Exp $
+# Test-script for DIFFSTAT
+
+# change this for ad hoc testing of compression
+#TYPE=.pat.Z
+#TYPE=.pat.gz
+#TYPE=.pat.bz2
+TYPE=.pat
+
+if [ $# = 0 ]
+then
+ eval '"$0" *${TYPE}'
+ exit
+fi
+PATH=`cd ..;pwd`:$PATH; export PATH
+# Sanity check, remembering that not every system has `which'.
+(which diffstat) >/dev/null 2>/dev/null && echo "Checking `which diffstat`"
+
+for item in $*
+do
+ echo "testing `basename $item $TYPE`"
+ for OPTS in "" "-p1" "-p9" "-f0" "-u" "-k" "-r1" "-r2" "-b" "-R" "-Rp0"
+ do
+ NAME=`echo $item | sed -e 's/'$TYPE'$//'`
+ DATA=${NAME}${TYPE}
+ if [ ".$OPTS" != "." ] ; then
+ NAME=$NAME`echo ./$OPTS|sed -e 's@./-@@'`
+ fi
+ TEST=`basename $NAME`
+ diffstat -e $TEST.err -o $TEST.out $OPTS $DATA
+ if [ -f $NAME.ref ]
+ then
+ diff -b $NAME.ref $TEST.out >check.out
+ if test -s check.out
+ then
+ echo "?? fail: $TEST"
+ ls -l check.out
+ cat check.out
+ else
+ echo "** ok: $TEST"
+ rm -f $TEST.out
+ rm -f $TEST.err
+ fi
+ else
+ echo "** save: $TEST"
+ mv $TEST.out $NAME.ref
+ rm -f $TEST.err
+ fi
+ done
+done
diff --git a/patch_cmds/patch/Makefile b/patch_cmds/patch/Makefile
new file mode 100644
index 0000000..d7071a4
--- /dev/null
+++ b/patch_cmds/patch/Makefile
@@ -0,0 +1,6 @@
+# $OpenBSD: Makefile,v 1.4 2005/05/16 15:22:46 espie Exp $
+
+PROG= patch
+SRCS= patch.c pch.c inp.c util.c backupfile.c mkpath.c
+
+.include <bsd.prog.mk>
diff --git a/patch_cmds/patch/backupfile.c b/patch_cmds/patch/backupfile.c
new file mode 100644
index 0000000..8d19aff
--- /dev/null
+++ b/patch_cmds/patch/backupfile.c
@@ -0,0 +1,235 @@
+/* $OpenBSD: backupfile.c,v 1.20 2009/10/27 23:59:41 deraadt Exp $ */
+
+/*
+ * backupfile.c -- make Emacs style backup file names Copyright (C) 1990 Free
+ * Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * without restriction.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * David MacKenzie <djm@ai.mit.edu>. Some algorithms adapted from GNU Emacs.
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "backupfile.h"
+
+
+#define ISDIGIT(c) (isascii (c) && isdigit (c))
+
+/* Which type of backup file names are generated. */
+enum backup_type backup_type = none;
+
+/*
+ * The extension added to file names to produce a simple (as opposed to
+ * numbered) backup file name.
+ */
+char *simple_backup_suffix = "~";
+
+static char *concat(const char *, const char *);
+static char *make_version_name(const char *, int);
+static int max_backup_version(const char *, const char *);
+static int version_number(const char *, const char *, size_t);
+static int argmatch(const char *, const char **);
+static void invalid_arg(const char *, const char *, int);
+
+/*
+ * Return the name of the new backup file for file FILE, allocated with
+ * malloc. Return 0 if out of memory. FILE must not end with a '/' unless it
+ * is the root directory. Do not call this function if backup_type == none.
+ */
+char *
+find_backup_file_name(const char *file)
+{
+ char *dir, *base_versions;
+ int highest_backup;
+
+ if (backup_type == simple)
+ return concat(file, simple_backup_suffix);
+ base_versions = concat(basename((char *)file), ".~");
+ if (base_versions == NULL)
+ return NULL;
+ dir = dirname((char *)file);
+ if (dir == NULL) {
+ free(base_versions);
+ return NULL;
+ }
+ highest_backup = max_backup_version(base_versions, dir);
+ free(base_versions);
+ if (backup_type == numbered_existing && highest_backup == 0)
+ return concat(file, simple_backup_suffix);
+ return make_version_name(file, highest_backup + 1);
+}
+
+/*
+ * Return the number of the highest-numbered backup file for file FILE in
+ * directory DIR. If there are no numbered backups of FILE in DIR, or an
+ * error occurs reading DIR, return 0. FILE should already have ".~" appended
+ * to it.
+ */
+static int
+max_backup_version(const char *file, const char *dir)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int highest_version, this_version;
+ size_t file_name_length;
+
+ dirp = opendir(dir);
+ if (dirp == NULL)
+ return 0;
+
+ highest_version = 0;
+ file_name_length = strlen(file);
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (dp->d_namlen <= file_name_length)
+ continue;
+
+ this_version = version_number(file, dp->d_name, file_name_length);
+ if (this_version > highest_version)
+ highest_version = this_version;
+ }
+ closedir(dirp);
+ return highest_version;
+}
+
+/*
+ * Return a string, allocated with malloc, containing "FILE.~VERSION~".
+ * Return 0 if out of memory.
+ */
+static char *
+make_version_name(const char *file, int version)
+{
+ char *backup_name;
+
+ if (asprintf(&backup_name, "%s.~%d~", file, version) == -1)
+ return NULL;
+ return backup_name;
+}
+
+/*
+ * If BACKUP is a numbered backup of BASE, return its version number;
+ * otherwise return 0. BASE_LENGTH is the length of BASE. BASE should
+ * already have ".~" appended to it.
+ */
+static int
+version_number(const char *base, const char *backup, size_t base_length)
+{
+ int version;
+ const char *p;
+
+ version = 0;
+ if (!strncmp(base, backup, base_length) && ISDIGIT(backup[base_length])) {
+ for (p = &backup[base_length]; ISDIGIT(*p); ++p)
+ version = version * 10 + *p - '0';
+ if (p[0] != '~' || p[1])
+ version = 0;
+ }
+ return version;
+}
+
+/*
+ * Return the newly-allocated concatenation of STR1 and STR2. If out of
+ * memory, return 0.
+ */
+static char *
+concat(const char *str1, const char *str2)
+{
+ char *newstr;
+
+ if (asprintf(&newstr, "%s%s", str1, str2) == -1)
+ return NULL;
+ return newstr;
+}
+
+/*
+ * If ARG is an unambiguous match for an element of the null-terminated array
+ * OPTLIST, return the index in OPTLIST of the matched element, else -1 if it
+ * does not match any element or -2 if it is ambiguous (is a prefix of more
+ * than one element).
+ */
+static int
+argmatch(const char *arg, const char **optlist)
+{
+ int i; /* Temporary index in OPTLIST. */
+ size_t arglen; /* Length of ARG. */
+ int matchind = -1; /* Index of first nonexact match. */
+ int ambiguous = 0; /* If nonzero, multiple nonexact match(es). */
+
+ arglen = strlen(arg);
+
+ /* Test all elements for either exact match or abbreviated matches. */
+ for (i = 0; optlist[i]; i++) {
+ if (!strncmp(optlist[i], arg, arglen)) {
+ if (strlen(optlist[i]) == arglen)
+ /* Exact match found. */
+ return i;
+ else if (matchind == -1)
+ /* First nonexact match found. */
+ matchind = i;
+ else
+ /* Second nonexact match found. */
+ ambiguous = 1;
+ }
+ }
+ if (ambiguous)
+ return -2;
+ else
+ return matchind;
+}
+
+/*
+ * Error reporting for argmatch. KIND is a description of the type of entity
+ * that was being matched. VALUE is the invalid value that was given. PROBLEM
+ * is the return value from argmatch.
+ */
+static void
+invalid_arg(const char *kind, const char *value, int problem)
+{
+ fprintf(stderr, "patch: ");
+ if (problem == -1)
+ fprintf(stderr, "invalid");
+ else /* Assume -2. */
+ fprintf(stderr, "ambiguous");
+ fprintf(stderr, " %s `%s'\n", kind, value);
+}
+
+static const char *backup_args[] = {
+ "never", "simple", "nil", "existing", "t", "numbered", 0
+};
+
+static enum backup_type backup_types[] = {
+ simple, simple, numbered_existing,
+ numbered_existing, numbered, numbered
+};
+
+/*
+ * Return the type of backup indicated by VERSION. Unique abbreviations are
+ * accepted.
+ */
+enum backup_type
+get_version(const char *version)
+{
+ int i;
+
+ if (version == NULL || *version == '\0')
+ return numbered_existing;
+ i = argmatch(version, backup_args);
+ if (i >= 0)
+ return backup_types[i];
+ invalid_arg("version control type", version, i);
+ exit(2);
+}
diff --git a/patch_cmds/patch/backupfile.h b/patch_cmds/patch/backupfile.h
new file mode 100644
index 0000000..7c20ddb
--- /dev/null
+++ b/patch_cmds/patch/backupfile.h
@@ -0,0 +1,38 @@
+/* $OpenBSD: backupfile.h,v 1.6 2003/07/28 18:35:36 otto Exp $ */
+
+/*
+ * backupfile.h -- declarations for making Emacs style backup file names
+ * Copyright (C) 1990 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * without restriction.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ */
+
+/* When to make backup files. */
+enum backup_type {
+ /* Never make backups. */
+ none,
+
+ /* Make simple backups of every file. */
+ simple,
+
+ /*
+ * Make numbered backups of files that already have numbered backups,
+ * and simple backups of the others.
+ */
+ numbered_existing,
+
+ /* Make numbered backups of every file. */
+ numbered
+};
+
+extern enum backup_type backup_type;
+extern char *simple_backup_suffix;
+
+char *find_backup_file_name(const char *file);
+enum backup_type get_version(const char *version);
diff --git a/patch_cmds/patch/common.h b/patch_cmds/patch/common.h
new file mode 100644
index 0000000..2027456
--- /dev/null
+++ b/patch_cmds/patch/common.h
@@ -0,0 +1,117 @@
+/* $OpenBSD: common.h,v 1.26 2006/03/11 19:41:30 otto Exp $ */
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
+
+#include <sys/types.h>
+
+#include <stdbool.h>
+#include <stdint.h> // for SIZE_MAX
+
+#define DEBUGGING
+
+/* constants */
+
+#define MAXHUNKSIZE 100000 /* is this enough lines? */
+#define INITHUNKMAX 125 /* initial dynamic allocation size */
+#define MAXLINELEN 8192
+#define BUFFERSIZE 1024
+
+#define SCCSPREFIX "s."
+#define GET "get -e %s"
+#define SCCSDIFF "get -p %s | diff - %s >/dev/null"
+
+#define RCSSUFFIX ",v"
+#define CHECKOUT "co -l %s"
+#define RCSDIFF "rcsdiff %s > /dev/null"
+
+#define ORIGEXT ".orig"
+#define REJEXT ".rej"
+
+/* handy definitions */
+
+#define strNE(s1,s2) (strcmp(s1, s2))
+#define strEQ(s1,s2) (!strcmp(s1, s2))
+#define strnNE(s1,s2,l) (strncmp(s1, s2, l))
+#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))
+
+/* typedefs */
+
+typedef long LINENUM; /* must be signed */
+
+/* globals */
+
+extern mode_t filemode;
+
+extern char buf[MAXLINELEN];/* general purpose buffer */
+
+extern bool using_plan_a; /* try to keep everything in memory */
+extern bool out_of_mem; /* ran out of memory in plan a */
+
+#define MAXFILEC 2
+
+extern char *filearg[MAXFILEC];
+extern bool ok_to_create_file;
+extern char *outname;
+extern char *origprae;
+
+extern char *TMPOUTNAME;
+extern char *TMPINNAME;
+extern char *TMPREJNAME;
+extern char *TMPPATNAME;
+extern bool toutkeep;
+extern bool trejkeep;
+
+#ifdef DEBUGGING
+extern int debug;
+#endif
+
+extern bool force;
+extern bool batch;
+extern int verbose;
+extern bool reverse;
+extern bool noreverse;
+extern bool skip_rest_of_patch;
+extern int strippath;
+extern bool canonicalize;
+/* TRUE if -C was specified on command line. */
+extern bool check_only;
+extern bool warn_on_invalid_line;
+extern bool last_line_missing_eol;
+
+
+#define CONTEXT_DIFF 1
+#define NORMAL_DIFF 2
+#define ED_DIFF 3
+#define NEW_CONTEXT_DIFF 4
+#define UNI_DIFF 5
+
+extern int diff_type;
+extern char *revision; /* prerequisite revision, if any */
+extern LINENUM input_lines; /* how long is input file in lines */
+
+extern int posix;
+
diff --git a/patch_cmds/patch/inp.c b/patch_cmds/patch/inp.c
new file mode 100644
index 0000000..6b5bf34
--- /dev/null
+++ b/patch_cmds/patch/inp.c
@@ -0,0 +1,471 @@
+/* $OpenBSD: inp.c,v 1.35 2009/10/27 23:59:41 deraadt Exp $ */
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <ctype.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "util.h"
+#include "pch.h"
+#include "inp.h"
+
+
+/* Input-file-with-indexable-lines abstract type */
+
+static off_t i_size; /* size of the input file */
+static char *i_womp; /* plan a buffer for entire file */
+static char **i_ptr; /* pointers to lines in i_womp */
+
+static int tifd = -1; /* plan b virtual string array */
+static char *tibuf[2]; /* plan b buffers */
+static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
+static LINENUM lines_per_buf; /* how many lines per buffer */
+static int tireclen; /* length of records in tmp file */
+
+static bool rev_in_string(const char *);
+static bool reallocate_lines(size_t *);
+
+/* returns false if insufficient memory */
+static bool plan_a(const char *);
+
+static void plan_b(const char *);
+
+/* New patch--prepare to edit another file. */
+
+void
+re_input(void)
+{
+ if (using_plan_a) {
+ i_size = 0;
+ free(i_ptr);
+ i_ptr = NULL;
+ if (i_womp != NULL) {
+ munmap(i_womp, i_size);
+ i_womp = NULL;
+ }
+ } else {
+ using_plan_a = true; /* maybe the next one is smaller */
+ close(tifd);
+ tifd = -1;
+ free(tibuf[0]);
+ free(tibuf[1]);
+ tibuf[0] = tibuf[1] = NULL;
+ tiline[0] = tiline[1] = -1;
+ tireclen = 0;
+ }
+}
+
+/* Construct the line index, somehow or other. */
+
+void
+scan_input(const char *filename)
+{
+ if (!plan_a(filename))
+ plan_b(filename);
+ if (verbose) {
+ say("Patching file %s using Plan %s...\n", filename,
+ (using_plan_a ? "A" : "B"));
+ } else {
+ say("patching file %s\n", filename);
+ }
+}
+
+static bool
+reallocate_lines(size_t *lines_allocated)
+{
+ char **p;
+ size_t new_size;
+
+ new_size = *lines_allocated * 3 / 2;
+ p = realloc(i_ptr, (new_size + 2) * sizeof(char *));
+ if (p == NULL) { /* shucks, it was a near thing */
+ munmap(i_womp, i_size);
+ i_womp = NULL;
+ free(i_ptr);
+ i_ptr = NULL;
+ *lines_allocated = 0;
+ return false;
+ }
+ *lines_allocated = new_size;
+ i_ptr = p;
+ return true;
+}
+
+/* Try keeping everything in memory. */
+
+static bool
+plan_a(const char *filename)
+{
+ int ifd, statfailed;
+ char *p, *s, lbuf[MAXLINELEN];
+ struct stat filestat;
+ off_t i;
+ ptrdiff_t sz;
+ size_t iline, lines_allocated;
+
+#ifdef DEBUGGING
+ if (debug & 8)
+ return false;
+#endif
+
+ if (filename == NULL || *filename == '\0')
+ return false;
+
+ statfailed = stat(filename, &filestat);
+ if (statfailed && ok_to_create_file) {
+ if (verbose)
+ say("(Creating file %s...)\n", filename);
+
+ /*
+ * in check_patch case, we still display `Creating file' even
+ * though we're not. The rule is that -C should be as similar
+ * to normal patch behavior as possible
+ */
+ if (check_only)
+ return true;
+ makedirs(filename, true);
+ close(creat(filename, 0666));
+ statfailed = stat(filename, &filestat);
+ }
+ if (statfailed && check_only)
+ fatal("%s not found, -C mode, can't probe further\n", filename);
+ /* For nonexistent or read-only files, look for RCS or SCCS versions. */
+ if (statfailed ||
+ /* No one can write to it. */
+ (filestat.st_mode & 0222) == 0 ||
+ /* I can't write to it. */
+ ((filestat.st_mode & 0022) == 0 && filestat.st_uid != getuid())) {
+ char *cs = NULL, *filebase, *filedir;
+ struct stat cstat;
+
+ filebase = basename((char *)filename);
+ filedir = dirname((char *)filename);
+
+ /* Leave room in lbuf for the diff command. */
+ s = lbuf + 20;
+
+#define try(f, a1, a2, a3) \
+ (snprintf(s, sizeof lbuf - 20, f, a1, a2, a3), stat(s, &cstat) == 0)
+
+ if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
+ try("%s/RCS/%s%s", filedir, filebase, "") ||
+ try("%s/%s%s", filedir, filebase, RCSSUFFIX)) {
+ snprintf(buf, sizeof buf, CHECKOUT, filename);
+ snprintf(lbuf, sizeof lbuf, RCSDIFF, filename);
+ cs = "RCS";
+ } else if (try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
+ try("%s/%s%s", filedir, SCCSPREFIX, filebase)) {
+ snprintf(buf, sizeof buf, GET, s);
+ snprintf(lbuf, sizeof lbuf, SCCSDIFF, s, filename);
+ cs = "SCCS";
+ } else if (statfailed)
+ fatal("can't find %s\n", filename);
+ /*
+ * else we can't write to it but it's not under a version
+ * control system, so just proceed.
+ */
+ if (cs) {
+ if (!statfailed) {
+ if ((filestat.st_mode & 0222) != 0)
+ /* The owner can write to it. */
+ fatal("file %s seems to be locked "
+ "by somebody else under %s\n",
+ filename, cs);
+ /*
+ * It might be checked out unlocked. See if
+ * it's safe to check out the default version
+ * locked.
+ */
+ if (verbose)
+ say("Comparing file %s to default "
+ "%s version...\n",
+ filename, cs);
+ if (system(lbuf))
+ fatal("can't check out file %s: "
+ "differs from default %s version\n",
+ filename, cs);
+ }
+ if (verbose)
+ say("Checking out file %s from %s...\n",
+ filename, cs);
+ if (system(buf) || stat(filename, &filestat))
+ fatal("can't check out file %s from %s\n",
+ filename, cs);
+ }
+ }
+ filemode = filestat.st_mode;
+ if (!S_ISREG(filemode))
+ fatal("%s is not a normal file--can't patch\n", filename);
+ i_size = filestat.st_size;
+ if (out_of_mem) {
+ set_hunkmax(); /* make sure dynamic arrays are allocated */
+ out_of_mem = false;
+ return false; /* force plan b because plan a bombed */
+ }
+ if (i_size > SIZE_MAX) {
+ say("block too large to mmap\n");
+ return false;
+ }
+ if ((ifd = open(filename, O_RDONLY)) < 0)
+ pfatal("can't open file %s", filename);
+
+ i_womp = mmap(NULL, i_size == 0 ? 64 : i_size, PROT_READ, MAP_PRIVATE, ifd, 0);
+ if (i_womp == MAP_FAILED) {
+ perror("mmap failed");
+ i_womp = NULL;
+ close(ifd);
+ return false;
+ }
+
+ close(ifd);
+ if (i_size)
+ madvise(i_womp, i_size, MADV_SEQUENTIAL);
+
+ /* estimate the number of lines */
+ lines_allocated = i_size / 25;
+ if (lines_allocated < 100)
+ lines_allocated = 100;
+
+ if (!reallocate_lines(&lines_allocated))
+ return false;
+
+ /* now scan the buffer and build pointer array */
+ iline = 1;
+ i_ptr[iline] = i_womp;
+ /* test for NUL too, to maintain the behavior of the original code */
+ for (s = i_womp, i = 0; i < i_size && *s != '\0'; s++, i++) {
+ if (*s == '\n') {
+ if (iline == lines_allocated) {
+ if (!reallocate_lines(&lines_allocated))
+ return false;
+ }
+ /* these are NOT NUL terminated */
+ i_ptr[++iline] = s + 1;
+ }
+ }
+ /* if the last line contains no EOL, append one */
+ if (i_size > 0 && i_womp[i_size - 1] != '\n') {
+ last_line_missing_eol = true;
+ /* fix last line */
+ sz = s - i_ptr[iline];
+ p = malloc(sz + 1);
+ if (p == NULL) {
+ free(i_ptr);
+ i_ptr = NULL;
+ munmap(i_womp, i_size);
+ i_womp = NULL;
+ return false;
+ }
+
+ memcpy(p, i_ptr[iline], sz);
+ p[sz] = '\n';
+ i_ptr[iline] = p;
+ /* count the extra line and make it point to some valid mem */
+ i_ptr[++iline] = "";
+ } else
+ last_line_missing_eol = false;
+
+ input_lines = iline - 1;
+
+ /* now check for revision, if any */
+
+ if (revision != NULL) {
+ if (!rev_in_string(i_womp)) {
+ if (force) {
+ if (verbose)
+ say("Warning: this file doesn't appear "
+ "to be the %s version--patching anyway.\n",
+ revision);
+ } else if (batch) {
+ fatal("this file doesn't appear to be the "
+ "%s version--aborting.\n",
+ revision);
+ } else {
+ ask("This file doesn't appear to be the "
+ "%s version--patch anyway? [n] ",
+ revision);
+ if (*buf != 'y')
+ fatal("aborted\n");
+ }
+ } else if (verbose)
+ say("Good. This file appears to be the %s version.\n",
+ revision);
+ }
+ return true; /* plan a will work */
+}
+
+/* Keep (virtually) nothing in memory. */
+
+static void
+plan_b(const char *filename)
+{
+ FILE *ifp;
+ size_t i = 0, j, maxlen = 1;
+ char *p;
+ bool found_revision = (revision == NULL);
+
+ using_plan_a = false;
+ if ((ifp = fopen(filename, "r")) == NULL)
+ pfatal("can't open file %s", filename);
+ (void) unlink(TMPINNAME);
+ if ((tifd = open(TMPINNAME, O_EXCL | O_CREAT | O_WRONLY, 0666)) < 0)
+ pfatal("can't open file %s", TMPINNAME);
+ while (fgets(buf, sizeof buf, ifp) != NULL) {
+ if (revision != NULL && !found_revision && rev_in_string(buf))
+ found_revision = true;
+ if ((i = strlen(buf)) > maxlen)
+ maxlen = i; /* find longest line */
+ }
+ last_line_missing_eol = i > 0 && buf[i - 1] != '\n';
+ if (last_line_missing_eol && maxlen == i)
+ maxlen++;
+
+ if (revision != NULL) {
+ if (!found_revision) {
+ if (force) {
+ if (verbose)
+ say("Warning: this file doesn't appear "
+ "to be the %s version--patching anyway.\n",
+ revision);
+ } else if (batch) {
+ fatal("this file doesn't appear to be the "
+ "%s version--aborting.\n",
+ revision);
+ } else {
+ ask("This file doesn't appear to be the %s "
+ "version--patch anyway? [n] ",
+ revision);
+ if (*buf != 'y')
+ fatal("aborted\n");
+ }
+ } else if (verbose)
+ say("Good. This file appears to be the %s version.\n",
+ revision);
+ }
+ fseek(ifp, 0L, SEEK_SET); /* rewind file */
+ lines_per_buf = BUFFERSIZE / maxlen;
+ tireclen = maxlen;
+ tibuf[0] = malloc(BUFFERSIZE + 1);
+ if (tibuf[0] == NULL)
+ fatal("out of memory\n");
+ tibuf[1] = malloc(BUFFERSIZE + 1);
+ if (tibuf[1] == NULL)
+ fatal("out of memory\n");
+ for (i = 1;; i++) {
+ p = tibuf[0] + maxlen * (i % lines_per_buf);
+ if (i % lines_per_buf == 0) /* new block */
+ if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ pfatal("can't write temp file");
+ if (fgets(p, maxlen + 1, ifp) == NULL) {
+ input_lines = i - 1;
+ if (i % lines_per_buf != 0)
+ if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
+ pfatal("can't write temp file");
+ break;
+ }
+ j = strlen(p);
+ /* These are '\n' terminated strings, so no need to add a NUL */
+ if (j == 0 || p[j - 1] != '\n')
+ p[j] = '\n';
+ }
+ fclose(ifp);
+ close(tifd);
+ if ((tifd = open(TMPINNAME, O_RDONLY)) < 0)
+ pfatal("can't reopen file %s", TMPINNAME);
+}
+
+/*
+ * Fetch a line from the input file, \n terminated, not necessarily \0.
+ */
+char *
+ifetch(LINENUM line, int whichbuf)
+{
+ if (line < 1 || line > input_lines) {
+ if (warn_on_invalid_line) {
+ say("No such line %ld in input file, ignoring\n", line);
+ warn_on_invalid_line = false;
+ }
+ return NULL;
+ }
+ if (using_plan_a)
+ return i_ptr[line];
+ else {
+ LINENUM offline = line % lines_per_buf;
+ LINENUM baseline = line - offline;
+
+ if (tiline[0] == baseline)
+ whichbuf = 0;
+ else if (tiline[1] == baseline)
+ whichbuf = 1;
+ else {
+ tiline[whichbuf] = baseline;
+
+ if (lseek(tifd, (off_t) (baseline / lines_per_buf *
+ BUFFERSIZE), SEEK_SET) < 0)
+ pfatal("cannot seek in the temporary input file");
+
+ if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
+ pfatal("error reading tmp file %s", TMPINNAME);
+ }
+ return tibuf[whichbuf] + (tireclen * offline);
+ }
+}
+
+/*
+ * True if the string argument contains the revision number we want.
+ */
+static bool
+rev_in_string(const char *string)
+{
+ const char *s;
+ size_t patlen;
+
+ if (revision == NULL)
+ return true;
+ patlen = strlen(revision);
+ if (strnEQ(string, revision, patlen) && isspace(string[patlen]))
+ return true;
+ for (s = string; *s; s++) {
+ if (isspace(*s) && strnEQ(s + 1, revision, patlen) &&
+ isspace(s[patlen + 1])) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/patch_cmds/patch/inp.h b/patch_cmds/patch/inp.h
new file mode 100644
index 0000000..aa66208
--- /dev/null
+++ b/patch_cmds/patch/inp.h
@@ -0,0 +1,31 @@
+/* $OpenBSD: inp.h,v 1.8 2003/08/15 08:00:51 otto Exp $ */
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
+
+void re_input(void);
+void scan_input(const char *);
+char *ifetch(LINENUM, int);
diff --git a/patch_cmds/patch/mkpath.c b/patch_cmds/patch/mkpath.c
new file mode 100644
index 0000000..1e600a8
--- /dev/null
+++ b/patch_cmds/patch/mkpath.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: mkpath.c,v 1.2 2005/06/20 07:14:06 otto Exp $ */
+/*
+ * Copyright (c) 1983, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+
+/* Code taken directly from mkdir(1).
+
+ * mkpath -- create directories.
+ * path - path
+ */
+int
+mkpath(char *path)
+{
+ struct stat sb;
+ char *slash;
+ int done = 0;
+
+ slash = path;
+
+ while (!done) {
+ slash += strspn(slash, "/");
+ slash += strcspn(slash, "/");
+
+ done = (*slash == '\0');
+ *slash = '\0';
+
+ if (stat(path, &sb)) {
+ if (errno != ENOENT || (mkdir(path, 0777) &&
+ errno != EEXIST)) {
+ warn("%s", path);
+ return (-1);
+ }
+ } else if (!S_ISDIR(sb.st_mode)) {
+ warnx("%s: %s", path, strerror(ENOTDIR));
+ return (-1);
+ }
+
+ *slash = '/';
+ }
+
+ return (0);
+}
+
diff --git a/patch_cmds/patch/patch.1 b/patch_cmds/patch/patch.1
new file mode 100644
index 0000000..611d898
--- /dev/null
+++ b/patch_cmds/patch/patch.1
@@ -0,0 +1,698 @@
+.\" $OpenBSD: patch.1,v 1.25 2009/02/08 17:33:01 jmc Exp $
+.\" Copyright 1986, Larry Wall
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following condition
+.\" is met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this condition and the following disclaimer.
+.\"
+.\" 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.
+.\"
+.Dd $Mdocdate: February 8 2009 $
+.Dt PATCH 1
+.Os
+.Sh NAME
+.Nm patch
+.Nd apply a diff file to an original
+.Sh SYNOPSIS
+.Nm patch
+.Bk -words
+.Op Fl bCcEeflNnRstuv
+.Op Fl B Ar backup-prefix
+.Op Fl D Ar symbol
+.Op Fl d Ar directory
+.Op Fl F Ar max-fuzz
+.Op Fl i Ar patchfile
+.Op Fl o Ar out-file
+.Op Fl p Ar strip-count
+.Op Fl r Ar rej-name
+.Op Fl V Cm t | nil | never
+.Op Fl x Ar number
+.Op Fl z Ar backup-ext
+.Op Fl Fl posix
+.Op Ar origfile Op Ar patchfile
+.Ek
+.Nm patch
+.Pf \*(Lt Ar patchfile
+.Sh DESCRIPTION
+.Nm
+will take a patch file containing any of the four forms of difference
+listing produced by the
+.Xr diff 1
+program and apply those differences to an original file,
+producing a patched version.
+If
+.Ar patchfile
+is omitted, or is a hyphen, the patch will be read from the standard input.
+.Pp
+.Nm
+will attempt to determine the type of the diff listing, unless overruled by a
+.Fl c ,
+.Fl e ,
+.Fl n ,
+or
+.Fl u
+option.
+Context diffs (old-style, new-style, and unified) and
+normal diffs are applied directly by the
+.Nm
+program itself, whereas ed diffs are simply fed to the
+.Xr ed 1
+editor via a pipe.
+.Pp
+If the
+.Ar patchfile
+contains more than one patch,
+.Nm
+will try to apply each of them as if they came from separate patch files.
+This means, among other things, that it is assumed that the name of the file
+to patch must be determined for each diff listing, and that the garbage before
+each diff listing will be examined for interesting things such as file names
+and revision level (see the section on
+.Sx Filename Determination
+below).
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Xo
+.Fl B Ar backup-prefix ,
+.Fl Fl prefix Ar backup-prefix
+.Xc
+Causes the next argument to be interpreted as a prefix to the backup file
+name.
+If this argument is specified, any argument to
+.Fl z
+will be ignored.
+.It Fl b , Fl Fl backup
+Save a backup copy of the file before it is modified.
+By default the original file is saved with a backup extension of
+.Qq .orig
+unless the file already has a numbered backup, in which case a numbered
+backup is made.
+This is equivalent to specifying
+.Qo Fl V Cm existing Qc .
+This option is currently the default, unless
+.Fl -posix
+is specified.
+.It Fl C , Fl Fl check
+Checks that the patch would apply cleanly, but does not modify anything.
+.It Fl c , Fl Fl context
+Forces
+.Nm
+to interpret the patch file as a context diff.
+.It Xo
+.Fl D Ar symbol ,
+.Fl Fl ifdef Ar symbol
+.Xc
+Causes
+.Nm
+to use the
+.Qq #ifdef...#endif
+construct to mark changes.
+The argument following will be used as the differentiating symbol.
+Note that, unlike the C compiler, there must be a space between the
+.Fl D
+and the argument.
+.It Xo
+.Fl d Ar directory ,
+.Fl Fl directory Ar directory
+.Xc
+Causes
+.Nm
+to interpret the next argument as a directory,
+and change working directory to it before doing anything else.
+.It Fl E , Fl Fl remove-empty-files
+Causes
+.Nm
+to remove output files that are empty after the patches have been applied.
+This option is useful when applying patches that create or remove files.
+.It Fl e , Fl Fl ed
+Forces
+.Nm
+to interpret the patch file as an
+.Xr ed 1
+script.
+.It Xo
+.Fl F Ar max-fuzz ,
+.Fl Fl fuzz Ar max-fuzz
+.Xc
+Sets the maximum fuzz factor.
+This option only applies to context diffs, and causes
+.Nm
+to ignore up to that many lines in looking for places to install a hunk.
+Note that a larger fuzz factor increases the odds of a faulty patch.
+The default fuzz factor is 2, and it may not be set to more than
+the number of lines of context in the context diff, ordinarily 3.
+.It Fl f , Fl Fl force
+Forces
+.Nm
+to assume that the user knows exactly what he or she is doing, and to not
+ask any questions.
+It assumes the following:
+skip patches for which a file to patch can't be found;
+patch files even though they have the wrong version for the
+.Qq Prereq:
+line in the patch;
+and assume that patches are not reversed even if they look like they are.
+This option does not suppress commentary; use
+.Fl s
+for that.
+.It Xo
+.Fl i Ar patchfile ,
+.Fl Fl input Ar patchfile
+.Xc
+Causes the next argument to be interpreted as the input file name
+(i.e. a patchfile).
+This option may be specified multiple times.
+.It Fl l , Fl Fl ignore-whitespace
+Causes the pattern matching to be done loosely, in case the tabs and
+spaces have been munged in your input file.
+Any sequence of whitespace in the pattern line will match any sequence
+in the input file.
+Normal characters must still match exactly.
+Each line of the context must still match a line in the input file.
+.It Fl N , Fl Fl forward
+Causes
+.Nm
+to ignore patches that it thinks are reversed or already applied.
+See also
+.Fl R .
+.It Fl n , Fl Fl normal
+Forces
+.Nm
+to interpret the patch file as a normal diff.
+.It Xo
+.Fl o Ar out-file ,
+.Fl Fl output Ar out-file
+.Xc
+Causes the next argument to be interpreted as the output file name.
+.It Xo
+.Fl p Ar strip-count ,
+.Fl Fl strip Ar strip-count
+.Xc
+Sets the pathname strip count,
+which controls how pathnames found in the patch file are treated,
+in case you keep your files in a different directory than the person who sent
+out the patch.
+The strip count specifies how many slashes are to be stripped from
+the front of the pathname.
+(Any intervening directory names also go away.)
+For example, supposing the file name in the patch file was
+.Pa /u/howard/src/blurfl/blurfl.c :
+.Pp
+Setting
+.Fl p Ns Ar 0
+gives the entire pathname unmodified.
+.Pp
+.Fl p Ns Ar 1
+gives
+.Pp
+.D1 Pa u/howard/src/blurfl/blurfl.c
+.Pp
+without the leading slash.
+.Pp
+.Fl p Ns Ar 4
+gives
+.Pp
+.D1 Pa blurfl/blurfl.c
+.Pp
+Not specifying
+.Fl p
+at all just gives you
+.Pa blurfl.c ,
+unless all of the directories in the leading path
+.Pq Pa u/howard/src/blurfl
+exist and that path is relative,
+in which case you get the entire pathname unmodified.
+Whatever you end up with is looked for either in the current directory,
+or the directory specified by the
+.Fl d
+option.
+.It Fl R , Fl Fl reverse
+Tells
+.Nm
+that this patch was created with the old and new files swapped.
+(Yes, I'm afraid that does happen occasionally, human nature being what it
+is.)
+.Nm
+will attempt to swap each hunk around before applying it.
+Rejects will come out in the swapped format.
+The
+.Fl R
+option will not work with ed diff scripts because there is too little
+information to reconstruct the reverse operation.
+.Pp
+If the first hunk of a patch fails,
+.Nm
+will reverse the hunk to see if it can be applied that way.
+If it can, you will be asked if you want to have the
+.Fl R
+option set.
+If it can't, the patch will continue to be applied normally.
+(Note: this method cannot detect a reversed patch if it is a normal diff
+and if the first command is an append (i.e. it should have been a delete)
+since appends always succeed, due to the fact that a null context will match
+anywhere.
+Luckily, most patches add or change lines rather than delete them, so most
+reversed normal diffs will begin with a delete, which will fail, triggering
+the heuristic.)
+.It Xo
+.Fl r Ar rej-name ,
+.Fl Fl reject-file Ar rej-name
+.Xc
+Causes the next argument to be interpreted as the reject file name.
+.It Xo
+.Fl s , Fl Fl quiet ,
+.Fl Fl silent
+.Xc
+Makes
+.Nm
+do its work silently, unless an error occurs.
+.It Fl t , Fl Fl batch
+Similar to
+.Fl f ,
+in that it suppresses questions, but makes some different assumptions:
+skip patches for which a file to patch can't be found (the same as
+.Fl f ) ;
+skip patches for which the file has the wrong version for the
+.Qq Prereq:
+line in the patch;
+and assume that patches are reversed if they look like they are.
+.It Fl u , Fl Fl unified
+Forces
+.Nm
+to interpret the patch file as a unified context diff (a unidiff).
+.It Xo
+.Fl V Cm t | nil | never ,
+.Fl Fl version-control Cm t | nil | never
+.Xc
+Causes the next argument to be interpreted as a method for creating
+backup file names.
+The type of backups made can also be given in the
+.Ev PATCH_VERSION_CONTROL
+or
+.Ev VERSION_CONTROL
+environment variables, which are overridden by this option.
+The
+.Fl B
+option overrides this option, causing the prefix to always be used for
+making backup file names.
+The values of the
+.Ev PATCH_VERSION_CONTROL
+and
+.Ev VERSION_CONTROL
+environment variables and the argument to the
+.Fl V
+option are like the GNU Emacs
+.Dq version-control
+variable; they also recognize synonyms that are more descriptive.
+The valid values are (unique abbreviations are accepted):
+.Bl -tag -width Ds -offset indent
+.It Cm t , numbered
+Always make numbered backups.
+.It Cm nil , existing
+Make numbered backups of files that already have them,
+simple backups of the others.
+.It Cm never , simple
+Always make simple backups.
+.El
+.It Fl v , Fl Fl version
+Causes
+.Nm
+to print out its revision header and patch level.
+.It Xo
+.Fl x Ar number ,
+.Fl Fl debug Ar number
+.Xc
+Sets internal debugging flags, and is of interest only to
+.Nm
+patchers.
+.It Xo
+.Fl z Ar backup-ext ,
+.Fl Fl suffix Ar backup-ext
+.Xc
+Causes the next argument to be interpreted as the backup extension, to be
+used in place of
+.Qq .orig .
+.It Fl Fl posix
+Enables strict
+.St -p1003.1-2008
+conformance, specifically:
+.Bl -enum
+.It
+Backup files are not created unless the
+.Fl b
+option is specified.
+.It
+If unspecified, the file name used is the first of the old, new and
+index files that exists.
+.El
+.El
+.Ss Patch Application
+.Nm
+will try to skip any leading garbage, apply the diff,
+and then skip any trailing garbage.
+Thus you could feed an article or message containing a
+diff listing to
+.Nm patch ,
+and it should work.
+If the entire diff is indented by a consistent amount,
+this will be taken into account.
+.Pp
+With context diffs, and to a lesser extent with normal diffs,
+.Nm
+can detect when the line numbers mentioned in the patch are incorrect,
+and will attempt to find the correct place to apply each hunk of the patch.
+As a first guess, it takes the line number mentioned for the hunk, plus or
+minus any offset used in applying the previous hunk.
+If that is not the correct place,
+.Nm
+will scan both forwards and backwards for a set of lines matching the context
+given in the hunk.
+First
+.Nm
+looks for a place where all lines of the context match.
+If no such place is found, and it's a context diff, and the maximum fuzz factor
+is set to 1 or more, then another scan takes place ignoring the first and last
+line of context.
+If that fails, and the maximum fuzz factor is set to 2 or more,
+the first two and last two lines of context are ignored,
+and another scan is made.
+.Pq The default maximum fuzz factor is 2.
+.Pp
+If
+.Nm
+cannot find a place to install that hunk of the patch, it will put the hunk
+out to a reject file, which normally is the name of the output file plus
+.Qq .rej .
+(Note that the rejected hunk will come out in context diff form whether the
+input patch was a context diff or a normal diff.
+If the input was a normal diff, many of the contexts will simply be null.)
+The line numbers on the hunks in the reject file may be different than
+in the patch file: they reflect the approximate location patch thinks the
+failed hunks belong in the new file rather than the old one.
+.Pp
+As each hunk is completed, you will be told whether the hunk succeeded or
+failed, and which line (in the new file)
+.Nm
+thought the hunk should go on.
+If this is different from the line number specified in the diff,
+you will be told the offset.
+A single large offset MAY be an indication that a hunk was installed in the
+wrong place.
+You will also be told if a fuzz factor was used to make the match, in which
+case you should also be slightly suspicious.
+.Ss Filename Determination
+If no original file is specified on the command line,
+.Nm
+will try to figure out from the leading garbage what the name of the file
+to edit is.
+When checking a prospective file name, pathname components are stripped
+as specified by the
+.Fl p
+option and the file's existence and writability are checked relative
+to the current working directory (or the directory specified by the
+.Fl d
+option).
+.Pp
+If the diff is a context or unified diff,
+.Nm
+is able to determine the old and new file names from the diff header.
+For context diffs, the
+.Dq old
+file is specified in the line beginning with
+.Qq ***
+and the
+.Dq new
+file is specified in the line beginning with
+.Qq --- .
+For a unified diff, the
+.Dq old
+file is specified in the line beginning with
+.Qq ---
+and the
+.Dq new
+file is specified in the line beginning with
+.Qq +++ .
+If there is an
+.Qq Index:
+line in the leading garbage (regardless of the diff type),
+.Nm
+will use the file name from that line as the
+.Dq index
+file.
+.Pp
+.Nm
+will choose the file name by performing the following steps, with the first
+match used:
+.Bl -enum
+.It
+If
+.Nm
+is operating in strict
+.St -p1003.1-2008
+mode, the first of the
+.Dq old ,
+.Dq new
+and
+.Dq index
+file names that exist is used.
+Otherwise,
+.Nm
+will examine either the
+.Dq old
+and
+.Dq new
+file names or, for a non-context diff, the
+.Dq index
+file name, and choose the file name with the fewest path components,
+the shortest basename, and the shortest total file name length (in that order).
+.It
+If no file exists,
+.Nm
+checks for the existence of the files in an SCCS or RCS directory
+(using the appropriate prefix or suffix) using the criteria specified
+above.
+If found,
+.Nm
+will attempt to get or check out the file.
+.It
+If no suitable file was found to patch, the patch file is a context or
+unified diff, and the old file was zero length, the new file name is
+created and used.
+.It
+If the file name still cannot be determined,
+.Nm
+will prompt the user for the file name to use.
+.El
+.Pp
+Additionally, if the leading garbage contains a
+.Qq Prereq:\ \&
+line,
+.Nm
+will take the first word from the prerequisites line (normally a version
+number) and check the input file to see if that word can be found.
+If not,
+.Nm
+will ask for confirmation before proceeding.
+.Pp
+The upshot of all this is that you should be able to say, while in a news
+interface, the following:
+.Pp
+.Dl | patch -d /usr/src/local/blurfl
+.Pp
+and patch a file in the blurfl directory directly from the article containing
+the patch.
+.Ss Backup Files
+By default, the patched version is put in place of the original, with
+the original file backed up to the same name with the extension
+.Qq .orig ,
+or as specified by the
+.Fl B ,
+.Fl V ,
+or
+.Fl z
+options.
+The extension used for making backup files may also be specified in the
+.Ev SIMPLE_BACKUP_SUFFIX
+environment variable, which is overridden by the options above.
+.Pp
+If the backup file is a symbolic or hard link to the original file,
+.Nm
+creates a new backup file name by changing the first lowercase letter
+in the last component of the file's name into uppercase.
+If there are no more lowercase letters in the name,
+it removes the first character from the name.
+It repeats this process until it comes up with a
+backup file that does not already exist or is not linked to the original file.
+.Pp
+You may also specify where you want the output to go with the
+.Fl o
+option; if that file already exists, it is backed up first.
+.Ss Notes For Patch Senders
+There are several things you should bear in mind if you are going to
+be sending out patches:
+.Pp
+First, you can save people a lot of grief by keeping a
+.Pa patchlevel.h
+file which is patched to increment the patch level as the first diff in the
+patch file you send out.
+If you put a
+.Qq Prereq:
+line in with the patch, it won't let them apply
+patches out of order without some warning.
+.Pp
+Second, make sure you've specified the file names right, either in a
+context diff header, or with an
+.Qq Index:
+line.
+If you are patching something in a subdirectory, be sure to tell the patch
+user to specify a
+.Fl p
+option as needed.
+.Pp
+Third, you can create a file by sending out a diff that compares a
+null file to the file you want to create.
+This will only work if the file you want to create doesn't exist already in
+the target directory.
+.Pp
+Fourth, take care not to send out reversed patches, since it makes people wonder
+whether they already applied the patch.
+.Pp
+Fifth, while you may be able to get away with putting 582 diff listings into
+one file, it is probably wiser to group related patches into separate files in
+case something goes haywire.
+.Sh ENVIRONMENT
+.Bl -tag -width "PATCH_VERSION_CONTROL" -compact
+.It Ev POSIXLY_CORRECT
+When set,
+.Nm
+behaves as if the
+.Fl Fl posix
+option has been specified.
+.It Ev SIMPLE_BACKUP_SUFFIX
+Extension to use for backup file names instead of
+.Qq .orig .
+.It Ev TMPDIR
+Directory to put temporary files in; default is
+.Pa /tmp .
+.It Ev PATCH_VERSION_CONTROL
+Selects when numbered backup files are made.
+.It Ev VERSION_CONTROL
+Same as
+.Ev PATCH_VERSION_CONTROL .
+.El
+.Sh FILES
+.Bl -tag -width "$TMPDIR/patch*" -compact
+.It Pa $TMPDIR/patch*
+.Nm
+temporary files
+.It Pa /dev/tty
+used to read input when
+.Nm
+prompts the user
+.El
+.Sh DIAGNOSTICS
+Too many to list here, but generally indicative that
+.Nm
+couldn't parse your patch file.
+.Pp
+The message
+.Qq Hmm...
+indicates that there is unprocessed text in the patch file and that
+.Nm
+is attempting to intuit whether there is a patch in that text and, if so,
+what kind of patch it is.
+.Pp
+The
+.Nm
+utility exits with one of the following values:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It \&0
+Successful completion.
+.It \&1
+One or more lines were written to a reject file.
+.It \*[Gt]\&1
+An error occurred.
+.El
+.Pp
+When applying a set of patches in a loop it behooves you to check this
+exit status so you don't apply a later patch to a partially patched file.
+.Sh SEE ALSO
+.Xr diff 1
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -p1003.1-2008
+specification
+(except as detailed above for the
+.Fl -posix
+option),
+though the presence of
+.Nm
+itself is optional.
+.Pp
+The flags
+.Op Fl BCEFfstVvxz
+and
+.Op Fl -posix
+are extensions to that specification.
+.Sh AUTHORS
+.An Larry Wall
+with many other contributors.
+.Sh CAVEATS
+.Nm
+cannot tell if the line numbers are off in an ed script, and can only detect
+bad line numbers in a normal diff when it finds a
+.Qq change
+or a
+.Qq delete
+command.
+A context diff using fuzz factor 3 may have the same problem.
+Until a suitable interactive interface is added, you should probably do
+a context diff in these cases to see if the changes made sense.
+Of course, compiling without errors is a pretty good indication that the patch
+worked, but not always.
+.Pp
+.Nm
+usually produces the correct results, even when it has to do a lot of
+guessing.
+However, the results are guaranteed to be correct only when the patch is
+applied to exactly the same version of the file that the patch was
+generated from.
+.Sh BUGS
+Could be smarter about partial matches, excessively deviant offsets and
+swapped code, but that would take an extra pass.
+.Pp
+Check patch mode
+.Pq Fl C
+will fail if you try to check several patches in succession that build on
+each other.
+The entire
+.Nm
+code would have to be restructured to keep temporary files around so that it
+can handle this situation.
+.Pp
+If code has been duplicated (for instance with #ifdef OLDCODE ... #else ...
+#endif),
+.Nm
+is incapable of patching both versions, and, if it works at all, will likely
+patch the wrong one, and tell you that it succeeded to boot.
+.Pp
+If you apply a patch you've already applied,
+.Nm
+will think it is a reversed patch, and offer to un-apply the patch.
+This could be construed as a feature.
diff --git a/patch_cmds/patch/patch.c b/patch_cmds/patch/patch.c
new file mode 100644
index 0000000..78d2ec2
--- /dev/null
+++ b/patch_cmds/patch/patch.c
@@ -0,0 +1,1058 @@
+/* $OpenBSD: patch.c,v 1.48 2009/10/27 23:59:41 deraadt Exp $ */
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <ctype.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "util.h"
+#include "pch.h"
+#include "inp.h"
+#include "backupfile.h"
+#include "pathnames.h"
+
+mode_t filemode = 0644;
+
+char buf[MAXLINELEN]; /* general purpose buffer */
+
+bool using_plan_a = true; /* try to keep everything in memory */
+bool out_of_mem = false; /* ran out of memory in plan a */
+
+#define MAXFILEC 2
+
+char *filearg[MAXFILEC];
+bool ok_to_create_file = false;
+char *outname = NULL;
+char *origprae = NULL;
+char *TMPOUTNAME;
+char *TMPINNAME;
+char *TMPREJNAME;
+char *TMPPATNAME;
+bool toutkeep = false;
+bool trejkeep = false;
+bool warn_on_invalid_line;
+bool last_line_missing_eol;
+
+#ifdef DEBUGGING
+int debug = 0;
+#endif
+
+bool force = false;
+bool batch = false;
+int verbose = false;
+bool reverse = false;
+bool noreverse = false;
+bool skip_rest_of_patch = false;
+int strippath = 957;
+bool canonicalize = false;
+bool check_only = false;
+int diff_type = 0;
+char *revision = NULL; /* prerequisite revision, if any */
+LINENUM input_lines = 0; /* how long is input file in lines */
+int posix = 0; /* strict POSIX mode? */
+
+static void reinitialize_almost_everything(void);
+static void get_some_switches(void);
+static LINENUM locate_hunk(LINENUM);
+static void abort_context_hunk(void);
+static void rej_line(int, LINENUM);
+static void abort_hunk(void);
+static void apply_hunk(LINENUM);
+static void init_output(const char *);
+static void init_reject(const char *);
+static void copy_till(LINENUM, bool);
+static void spew_output(void);
+static void dump_line(LINENUM, bool);
+static bool patch_match(LINENUM, LINENUM, LINENUM);
+static bool similar(const char *, const char *, int);
+static __dead void usage(void);
+
+/* true if -E was specified on command line. */
+static bool remove_empty_files = false;
+
+/* true if -R was specified on command line. */
+static bool reverse_flag_specified = false;
+
+/* buffer holding the name of the rejected patch file. */
+static char rejname[NAME_MAX + 1];
+
+/* buffer for stderr */
+static char serrbuf[BUFSIZ];
+
+/* how many input lines have been irretractibly output */
+static LINENUM last_frozen_line = 0;
+
+static int Argc; /* guess */
+static char **Argv;
+static int Argc_last; /* for restarting plan_b */
+static char **Argv_last;
+
+static FILE *ofp = NULL; /* output file pointer */
+static FILE *rejfp = NULL; /* reject file pointer */
+
+static int filec = 0; /* how many file arguments? */
+static LINENUM last_offset = 0;
+static LINENUM maxfuzz = 2;
+
+/* patch using ifdef, ifndef, etc. */
+static bool do_defines = false;
+/* #ifdef xyzzy */
+static char if_defined[128];
+/* #ifndef xyzzy */
+static char not_defined[128];
+/* #else */
+static const char else_defined[] = "#else\n";
+/* #endif xyzzy */
+static char end_defined[128];
+
+
+/* Apply a set of diffs as appropriate. */
+
+int
+main(int argc, char *argv[])
+{
+ int error = 0, hunk, failed, i, fd;
+ bool patch_seen;
+ LINENUM where = 0, newwhere, fuzz, mymaxfuzz;
+ const char *tmpdir;
+ char *v;
+
+ setbuf(stderr, serrbuf);
+ for (i = 0; i < MAXFILEC; i++)
+ filearg[i] = NULL;
+
+ /* Cons up the names of the temporary files. */
+ if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
+ tmpdir = _PATH_TMP;
+ for (i = strlen(tmpdir) - 1; i > 0 && tmpdir[i] == '/'; i--)
+ ;
+ i++;
+ if (asprintf(&TMPOUTNAME, "%.*s/patchoXXXXXXXXXX", i, tmpdir) == -1)
+ fatal("cannot allocate memory");
+ if ((fd = mkstemp(TMPOUTNAME)) < 0)
+ pfatal("can't create %s", TMPOUTNAME);
+ close(fd);
+
+ if (asprintf(&TMPINNAME, "%.*s/patchiXXXXXXXXXX", i, tmpdir) == -1)
+ fatal("cannot allocate memory");
+ if ((fd = mkstemp(TMPINNAME)) < 0)
+ pfatal("can't create %s", TMPINNAME);
+ close(fd);
+
+ if (asprintf(&TMPREJNAME, "%.*s/patchrXXXXXXXXXX", i, tmpdir) == -1)
+ fatal("cannot allocate memory");
+ if ((fd = mkstemp(TMPREJNAME)) < 0)
+ pfatal("can't create %s", TMPREJNAME);
+ close(fd);
+
+ if (asprintf(&TMPPATNAME, "%.*s/patchpXXXXXXXXXX", i, tmpdir) == -1)
+ fatal("cannot allocate memory");
+ if ((fd = mkstemp(TMPPATNAME)) < 0)
+ pfatal("can't create %s", TMPPATNAME);
+ close(fd);
+
+ v = getenv("SIMPLE_BACKUP_SUFFIX");
+ if (v)
+ simple_backup_suffix = v;
+ else
+ simple_backup_suffix = ORIGEXT;
+
+ /* parse switches */
+ Argc = argc;
+ Argv = argv;
+ get_some_switches();
+
+ if (backup_type == none) {
+ if ((v = getenv("PATCH_VERSION_CONTROL")) == NULL)
+ v = getenv("VERSION_CONTROL");
+ if (v != NULL || !posix)
+ backup_type = get_version(v); /* OK to pass NULL. */
+ }
+
+ /* make sure we clean up /tmp in case of disaster */
+ set_signals(0);
+
+ patch_seen = false;
+ for (open_patch_file(filearg[1]); there_is_another_patch();
+ reinitialize_almost_everything()) {
+ /* for each patch in patch file */
+
+ patch_seen = true;
+
+ warn_on_invalid_line = true;
+
+ if (outname == NULL)
+ outname = savestr(filearg[0]);
+
+ /* for ed script just up and do it and exit */
+ if (diff_type == ED_DIFF) {
+ do_ed_script();
+ continue;
+ }
+ /* initialize the patched file */
+ if (!skip_rest_of_patch)
+ init_output(TMPOUTNAME);
+
+ /* initialize reject file */
+ init_reject(TMPREJNAME);
+
+ /* find out where all the lines are */
+ if (!skip_rest_of_patch)
+ scan_input(filearg[0]);
+
+ /* from here on, open no standard i/o files, because malloc */
+ /* might misfire and we can't catch it easily */
+
+ /* apply each hunk of patch */
+ hunk = 0;
+ failed = 0;
+ out_of_mem = false;
+ while (another_hunk()) {
+ hunk++;
+ fuzz = 0;
+ mymaxfuzz = pch_context();
+ if (maxfuzz < mymaxfuzz)
+ mymaxfuzz = maxfuzz;
+ if (!skip_rest_of_patch) {
+ do {
+ where = locate_hunk(fuzz);
+ if (hunk == 1 && where == 0 && !force) {
+ /* dwim for reversed patch? */
+ if (!pch_swap()) {
+ if (fuzz == 0)
+ say("Not enough memory to try swapped hunk! Assuming unswapped.\n");
+ continue;
+ }
+ reverse = !reverse;
+ /* try again */
+ where = locate_hunk(fuzz);
+ if (where == 0) {
+ /* didn't find it swapped */
+ if (!pch_swap())
+ /* put it back to normal */
+ fatal("lost hunk on alloc error!\n");
+ reverse = !reverse;
+ } else if (noreverse) {
+ if (!pch_swap())
+ /* put it back to normal */
+ fatal("lost hunk on alloc error!\n");
+ reverse = !reverse;
+ say("Ignoring previously applied (or reversed) patch.\n");
+ skip_rest_of_patch = true;
+ } else if (batch) {
+ if (verbose)
+ say("%seversed (or previously applied) patch detected! %s -R.",
+ reverse ? "R" : "Unr",
+ reverse ? "Assuming" : "Ignoring");
+ } else {
+ ask("%seversed (or previously applied) patch detected! %s -R? [y] ",
+ reverse ? "R" : "Unr",
+ reverse ? "Assume" : "Ignore");
+ if (*buf == 'n') {
+ ask("Apply anyway? [n] ");
+ if (*buf != 'y')
+ skip_rest_of_patch = true;
+ where = 0;
+ reverse = !reverse;
+ if (!pch_swap())
+ /* put it back to normal */
+ fatal("lost hunk on alloc error!\n");
+ }
+ }
+ }
+ } while (!skip_rest_of_patch && where == 0 &&
+ ++fuzz <= mymaxfuzz);
+
+ if (skip_rest_of_patch) { /* just got decided */
+ fclose(ofp);
+ ofp = NULL;
+ }
+ }
+ newwhere = pch_newfirst() + last_offset;
+ if (skip_rest_of_patch) {
+ abort_hunk();
+ failed++;
+ if (verbose)
+ say("Hunk #%d ignored at %ld.\n",
+ hunk, newwhere);
+ } else if (where == 0) {
+ abort_hunk();
+ failed++;
+ if (verbose)
+ say("Hunk #%d failed at %ld.\n",
+ hunk, newwhere);
+ } else {
+ apply_hunk(where);
+ if (verbose) {
+ say("Hunk #%d succeeded at %ld",
+ hunk, newwhere);
+ if (fuzz != 0)
+ say(" with fuzz %ld", fuzz);
+ if (last_offset)
+ say(" (offset %ld line%s)",
+ last_offset,
+ last_offset == 1L ? "" : "s");
+ say(".\n");
+ }
+ }
+ }
+
+ if (out_of_mem && using_plan_a) {
+ Argc = Argc_last;
+ Argv = Argv_last;
+ say("\n\nRan out of memory using Plan A--trying again...\n\n");
+ if (ofp)
+ fclose(ofp);
+ ofp = NULL;
+ if (rejfp)
+ fclose(rejfp);
+ rejfp = NULL;
+ continue;
+ }
+ if (hunk == 0)
+ fatal("Internal error: hunk should not be 0\n");
+
+ /* finish spewing out the new file */
+ if (!skip_rest_of_patch)
+ spew_output();
+
+ /* and put the output where desired */
+ ignore_signals();
+ if (!skip_rest_of_patch) {
+ struct stat statbuf;
+ char *realout = outname;
+
+ if (!check_only) {
+ if (move_file(TMPOUTNAME, outname) < 0) {
+ toutkeep = true;
+ realout = TMPOUTNAME;
+ chmod(TMPOUTNAME, filemode);
+ } else
+ chmod(outname, filemode);
+
+ if (remove_empty_files &&
+ stat(realout, &statbuf) == 0 &&
+ statbuf.st_size == 0) {
+ if (verbose)
+ say("Removing %s (empty after patching).\n",
+ realout);
+ unlink(realout);
+ }
+ }
+ }
+ fclose(rejfp);
+ rejfp = NULL;
+ if (failed) {
+ error = 1;
+ if (*rejname == '\0') {
+ if (strlcpy(rejname, outname,
+ sizeof(rejname)) >= sizeof(rejname))
+ fatal("filename %s is too long\n", outname);
+ if (strlcat(rejname, REJEXT,
+ sizeof(rejname)) >= sizeof(rejname))
+ fatal("filename %s is too long\n", outname);
+ }
+ if (skip_rest_of_patch) {
+ say("%d out of %d hunks ignored--saving rejects to %s\n",
+ failed, hunk, rejname);
+ } else {
+ say("%d out of %d hunks failed--saving rejects to %s\n",
+ failed, hunk, rejname);
+ }
+ if (!check_only && move_file(TMPREJNAME, rejname) < 0)
+ trejkeep = true;
+ }
+ set_signals(1);
+ }
+
+ if (!patch_seen)
+ error = 2;
+
+ my_exit(error);
+ /* NOTREACHED */
+}
+
+/* Prepare to find the next patch to do in the patch file. */
+
+static void
+reinitialize_almost_everything(void)
+{
+ re_patch();
+ re_input();
+
+ input_lines = 0;
+ last_frozen_line = 0;
+
+ filec = 0;
+ if (!out_of_mem) {
+ free(filearg[0]);
+ filearg[0] = NULL;
+ }
+
+ free(outname);
+ outname = NULL;
+
+ last_offset = 0;
+ diff_type = 0;
+
+ free(revision);
+ revision = NULL;
+
+ reverse = reverse_flag_specified;
+ skip_rest_of_patch = false;
+
+ get_some_switches();
+}
+
+/* Process switches and filenames. */
+
+static void
+get_some_switches(void)
+{
+ const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:";
+ static struct option longopts[] = {
+ {"backup", no_argument, 0, 'b'},
+ {"batch", no_argument, 0, 't'},
+ {"binary", no_argument, 0, 1},
+ {"check", no_argument, 0, 'C'},
+ {"context", no_argument, 0, 'c'},
+ {"debug", required_argument, 0, 'x'},
+ {"directory", required_argument, 0, 'd'},
+ {"dry-run", no_argument, 0, 'C'},
+ {"ed", no_argument, 0, 'e'},
+ {"force", no_argument, 0, 'f'},
+ {"forward", no_argument, 0, 'N'},
+ {"fuzz", required_argument, 0, 'F'},
+ {"ifdef", required_argument, 0, 'D'},
+ {"input", required_argument, 0, 'i'},
+ {"ignore-whitespace", no_argument, 0, 'l'},
+ {"normal", no_argument, 0, 'n'},
+ {"output", required_argument, 0, 'o'},
+ {"prefix", required_argument, 0, 'B'},
+ {"quiet", no_argument, 0, 's'},
+ {"reject-file", required_argument, 0, 'r'},
+ {"remove-empty-files", no_argument, 0, 'E'},
+ {"reverse", no_argument, 0, 'R'},
+ {"silent", no_argument, 0, 's'},
+ {"strip", required_argument, 0, 'p'},
+ {"suffix", required_argument, 0, 'z'},
+ {"unified", no_argument, 0, 'u'},
+ {"version", no_argument, 0, 'v'},
+ {"version-control", required_argument, 0, 'V'},
+ {"posix", no_argument, &posix, 1},
+ {"verbose", no_argument, &verbose, true},
+ {NULL, 0, 0, 0}
+ };
+ int ch;
+
+ rejname[0] = '\0';
+ Argc_last = Argc;
+ Argv_last = Argv;
+ if (!Argc)
+ return;
+ optreset = optind = 1;
+ while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'b':
+ if (backup_type == none)
+ backup_type = numbered_existing;
+ if (optarg == NULL)
+ break;
+ if (verbose)
+ say("Warning, the ``-b suffix'' option has been"
+ " obsoleted by the -z option.\n");
+ /* FALLTHROUGH */
+ case 'z':
+ /* must directly follow 'b' case for backwards compat */
+ simple_backup_suffix = savestr(optarg);
+ break;
+ case 'B':
+ origprae = savestr(optarg);
+ break;
+ case 'c':
+ diff_type = CONTEXT_DIFF;
+ break;
+ case 'C':
+ check_only = true;
+ break;
+ case 'd':
+ if (chdir(optarg) < 0)
+ pfatal("can't cd to %s", optarg);
+ break;
+ case 'D':
+ do_defines = true;
+ if (!isalpha(*optarg) && *optarg != '_')
+ fatal("argument to -D is not an identifier\n");
+ snprintf(if_defined, sizeof if_defined,
+ "#ifdef %s\n", optarg);
+ snprintf(not_defined, sizeof not_defined,
+ "#ifndef %s\n", optarg);
+ snprintf(end_defined, sizeof end_defined,
+ "#endif /* %s */\n", optarg);
+ break;
+ case 'e':
+ diff_type = ED_DIFF;
+ break;
+ case 'E':
+ remove_empty_files = true;
+ break;
+ case 'f':
+ force = true;
+ break;
+ case 'F':
+ maxfuzz = atoi(optarg);
+ break;
+ case 'i':
+ if (++filec == MAXFILEC)
+ fatal("too many file arguments\n");
+ filearg[filec] = savestr(optarg);
+ break;
+ case 'l':
+ canonicalize = true;
+ break;
+ case 'n':
+ diff_type = NORMAL_DIFF;
+ break;
+ case 'N':
+ noreverse = true;
+ break;
+ case 'o':
+ outname = savestr(optarg);
+ break;
+ case 'p':
+ strippath = atoi(optarg);
+ break;
+ case 'r':
+ if (strlcpy(rejname, optarg,
+ sizeof(rejname)) >= sizeof(rejname))
+ fatal("argument for -r is too long\n");
+ break;
+ case 'R':
+ reverse = true;
+ reverse_flag_specified = true;
+ break;
+ case 's':
+ verbose = false;
+ break;
+ case 't':
+ batch = true;
+ break;
+ case 'u':
+ diff_type = UNI_DIFF;
+ break;
+ case 'v':
+ version();
+ break;
+ case 'V':
+ backup_type = get_version(optarg);
+ break;
+#ifdef DEBUGGING
+ case 'x':
+ debug = atoi(optarg);
+ break;
+#endif
+ case 1:
+ /* ignored */
+ break;
+ default:
+ if (ch != '\0')
+ usage();
+ break;
+ }
+ }
+ Argc -= optind;
+ Argv += optind;
+
+ if (Argc > 0) {
+ filearg[0] = savestr(*Argv++);
+ Argc--;
+ while (Argc > 0) {
+ if (++filec == MAXFILEC)
+ fatal("too many file arguments\n");
+ filearg[filec] = savestr(*Argv++);
+ Argc--;
+ }
+ }
+
+ if (getenv("POSIXLY_CORRECT") != NULL)
+ posix = 1;
+}
+
+static __dead void
+usage(void)
+{
+ fprintf(stderr,
+"usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory]\n"
+" [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n"
+" [-r rej-name] [-V t | nil | never] [-x number] [-z backup-ext]\n"
+" [--posix] [origfile [patchfile]]\n"
+" patch <patchfile\n");
+ my_exit(EXIT_SUCCESS);
+}
+
+/*
+ * Attempt to find the right place to apply this hunk of patch.
+ */
+static LINENUM
+locate_hunk(LINENUM fuzz)
+{
+ LINENUM first_guess = pch_first() + last_offset;
+ LINENUM offset;
+ LINENUM pat_lines = pch_ptrn_lines();
+ LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1;
+ LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context();
+
+ if (pat_lines == 0) { /* null range matches always */
+ if (verbose && fuzz == 0 && (diff_type == CONTEXT_DIFF
+ || diff_type == NEW_CONTEXT_DIFF
+ || diff_type == UNI_DIFF)) {
+ say("Empty context always matches.\n");
+ }
+ return (first_guess);
+ }
+ if (max_neg_offset >= first_guess) /* do not try lines < 0 */
+ max_neg_offset = first_guess - 1;
+ if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz))
+ return first_guess;
+ for (offset = 1; ; offset++) {
+ bool check_after = (offset <= max_pos_offset);
+ bool check_before = (offset <= max_neg_offset);
+
+ if (check_after && patch_match(first_guess, offset, fuzz)) {
+#ifdef DEBUGGING
+ if (debug & 1)
+ say("Offset changing from %ld to %ld\n",
+ last_offset, offset);
+#endif
+ last_offset = offset;
+ return first_guess + offset;
+ } else if (check_before && patch_match(first_guess, -offset, fuzz)) {
+#ifdef DEBUGGING
+ if (debug & 1)
+ say("Offset changing from %ld to %ld\n",
+ last_offset, -offset);
+#endif
+ last_offset = -offset;
+ return first_guess - offset;
+ } else if (!check_before && !check_after)
+ return 0;
+ }
+}
+
+/* We did not find the pattern, dump out the hunk so they can handle it. */
+
+static void
+abort_context_hunk(void)
+{
+ LINENUM i;
+ const LINENUM pat_end = pch_end();
+ /*
+ * add in last_offset to guess the same as the previous successful
+ * hunk
+ */
+ const LINENUM oldfirst = pch_first() + last_offset;
+ const LINENUM newfirst = pch_newfirst() + last_offset;
+ const LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
+ const LINENUM newlast = newfirst + pch_repl_lines() - 1;
+ const char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : "");
+ const char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----");
+
+ fprintf(rejfp, "***************\n");
+ for (i = 0; i <= pat_end; i++) {
+ switch (pch_char(i)) {
+ case '*':
+ if (oldlast < oldfirst)
+ fprintf(rejfp, "*** 0%s\n", stars);
+ else if (oldlast == oldfirst)
+ fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
+ else
+ fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst,
+ oldlast, stars);
+ break;
+ case '=':
+ if (newlast < newfirst)
+ fprintf(rejfp, "--- 0%s\n", minuses);
+ else if (newlast == newfirst)
+ fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
+ else
+ fprintf(rejfp, "--- %ld,%ld%s\n", newfirst,
+ newlast, minuses);
+ break;
+ case '\n':
+ fprintf(rejfp, "%s", pfetch(i));
+ break;
+ case ' ':
+ case '-':
+ case '+':
+ case '!':
+ fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
+ break;
+ default:
+ fatal("fatal internal error in abort_context_hunk\n");
+ }
+ }
+}
+
+static void
+rej_line(int ch, LINENUM i)
+{
+ size_t len;
+ const char *line = pfetch(i);
+
+ len = strlen(line);
+
+ fprintf(rejfp, "%c%s", ch, line);
+ if (len == 0 || line[len-1] != '\n')
+ fprintf(rejfp, "\n\\ No newline at end of file\n");
+}
+
+static void
+abort_hunk(void)
+{
+ LINENUM i, j, split;
+ int ch1, ch2;
+ const LINENUM pat_end = pch_end();
+ const LINENUM oldfirst = pch_first() + last_offset;
+ const LINENUM newfirst = pch_newfirst() + last_offset;
+
+ if (diff_type != UNI_DIFF) {
+ abort_context_hunk();
+ return;
+ }
+ split = -1;
+ for (i = 0; i <= pat_end; i++) {
+ if (pch_char(i) == '=') {
+ split = i;
+ break;
+ }
+ }
+ if (split == -1) {
+ fprintf(rejfp, "malformed hunk: no split found\n");
+ return;
+ }
+ i = 0;
+ j = split + 1;
+ fprintf(rejfp, "@@ -%ld,%ld +%ld,%ld @@\n",
+ pch_ptrn_lines() ? oldfirst : 0,
+ pch_ptrn_lines(), newfirst, pch_repl_lines());
+ while (i < split || j <= pat_end) {
+ ch1 = i < split ? pch_char(i) : -1;
+ ch2 = j <= pat_end ? pch_char(j) : -1;
+ if (ch1 == '-') {
+ rej_line('-', i);
+ i++;
+ } else if (ch1 == ' ' && ch2 == ' ') {
+ rej_line(' ', i);
+ i++;
+ j++;
+ } else if (ch1 == '!' && ch2 == '!') {
+ while (i < split && ch1 == '!') {
+ rej_line('-', i);
+ i++;
+ ch1 = i < split ? pch_char(i) : -1;
+ }
+ while (j <= pat_end && ch2 == '!') {
+ rej_line('+', j);
+ j++;
+ ch2 = j <= pat_end ? pch_char(j) : -1;
+ }
+ } else if (ch1 == '*') {
+ i++;
+ } else if (ch2 == '+' || ch2 == ' ') {
+ rej_line(ch2, j);
+ j++;
+ } else {
+ fprintf(rejfp, "internal error on (%ld %ld %ld)\n",
+ i, split, j);
+ rej_line(ch1, i);
+ rej_line(ch2, j);
+ return;
+ }
+ }
+}
+
+/* We found where to apply it (we hope), so do it. */
+
+static void
+apply_hunk(LINENUM where)
+{
+ LINENUM old = 1;
+ const LINENUM lastline = pch_ptrn_lines();
+ LINENUM new = lastline + 1;
+#define OUTSIDE 0
+#define IN_IFNDEF 1
+#define IN_IFDEF 2
+#define IN_ELSE 3
+ int def_state = OUTSIDE;
+ const LINENUM pat_end = pch_end();
+
+ where--;
+ while (pch_char(new) == '=' || pch_char(new) == '\n')
+ new++;
+
+ while (old <= lastline) {
+ if (pch_char(old) == '-') {
+ copy_till(where + old - 1, false);
+ if (do_defines) {
+ if (def_state == OUTSIDE) {
+ fputs(not_defined, ofp);
+ def_state = IN_IFNDEF;
+ } else if (def_state == IN_IFDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ fputs(pfetch(old), ofp);
+ }
+ last_frozen_line++;
+ old++;
+ } else if (new > pat_end) {
+ break;
+ } else if (pch_char(new) == '+') {
+ copy_till(where + old - 1, false);
+ if (do_defines) {
+ if (def_state == IN_IFNDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ } else if (def_state == OUTSIDE) {
+ fputs(if_defined, ofp);
+ def_state = IN_IFDEF;
+ }
+ }
+ fputs(pfetch(new), ofp);
+ new++;
+ } else if (pch_char(new) != pch_char(old)) {
+ say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
+ pch_hunk_beg() + old,
+ pch_hunk_beg() + new);
+#ifdef DEBUGGING
+ say("oldchar = '%c', newchar = '%c'\n",
+ pch_char(old), pch_char(new));
+#endif
+ my_exit(2);
+ } else if (pch_char(new) == '!') {
+ copy_till(where + old - 1, false);
+ if (do_defines) {
+ fputs(not_defined, ofp);
+ def_state = IN_IFNDEF;
+ }
+ while (pch_char(old) == '!') {
+ if (do_defines) {
+ fputs(pfetch(old), ofp);
+ }
+ last_frozen_line++;
+ old++;
+ }
+ if (do_defines) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ while (pch_char(new) == '!') {
+ fputs(pfetch(new), ofp);
+ new++;
+ }
+ } else {
+ if (pch_char(new) != ' ')
+ fatal("Internal error: expected ' '\n");
+ old++;
+ new++;
+ if (do_defines && def_state != OUTSIDE) {
+ fputs(end_defined, ofp);
+ def_state = OUTSIDE;
+ }
+ }
+ }
+ if (new <= pat_end && pch_char(new) == '+') {
+ copy_till(where + old - 1, false);
+ if (do_defines) {
+ if (def_state == OUTSIDE) {
+ fputs(if_defined, ofp);
+ def_state = IN_IFDEF;
+ } else if (def_state == IN_IFNDEF) {
+ fputs(else_defined, ofp);
+ def_state = IN_ELSE;
+ }
+ }
+ while (new <= pat_end && pch_char(new) == '+') {
+ fputs(pfetch(new), ofp);
+ new++;
+ }
+ }
+ if (do_defines && def_state != OUTSIDE) {
+ fputs(end_defined, ofp);
+ }
+}
+
+/*
+ * Open the new file.
+ */
+static void
+init_output(const char *name)
+{
+ ofp = fopen(name, "w");
+ if (ofp == NULL)
+ pfatal("can't create %s", name);
+}
+
+/*
+ * Open a file to put hunks we can't locate.
+ */
+static void
+init_reject(const char *name)
+{
+ rejfp = fopen(name, "w");
+ if (rejfp == NULL)
+ pfatal("can't create %s", name);
+}
+
+/*
+ * Copy input file to output, up to wherever hunk is to be applied.
+ * If endoffile is true, treat the last line specially since it may
+ * lack a newline.
+ */
+static void
+copy_till(LINENUM lastline, bool endoffile)
+{
+ if (last_frozen_line > lastline)
+ fatal("misordered hunks! output would be garbled\n");
+ while (last_frozen_line < lastline) {
+ if (++last_frozen_line == lastline && endoffile)
+ dump_line(last_frozen_line, !last_line_missing_eol);
+ else
+ dump_line(last_frozen_line, true);
+ }
+}
+
+/*
+ * Finish copying the input file to the output file.
+ */
+static void
+spew_output(void)
+{
+#ifdef DEBUGGING
+ if (debug & 256)
+ say("il=%ld lfl=%ld\n", input_lines, last_frozen_line);
+#endif
+ if (input_lines)
+ copy_till(input_lines, true); /* dump remainder of file */
+ fclose(ofp);
+ ofp = NULL;
+}
+
+/*
+ * Copy one line from input to output.
+ */
+static void
+dump_line(LINENUM line, bool write_newline)
+{
+ char *s;
+
+ s = ifetch(line, 0);
+ if (s == NULL)
+ return;
+ /* Note: string is not NUL terminated. */
+ for (; *s != '\n'; s++)
+ putc(*s, ofp);
+ if (write_newline)
+ putc('\n', ofp);
+}
+
+/*
+ * Does the patch pattern match at line base+offset?
+ */
+static bool
+patch_match(LINENUM base, LINENUM offset, LINENUM fuzz)
+{
+ LINENUM pline = 1 + fuzz;
+ LINENUM iline;
+ LINENUM pat_lines = pch_ptrn_lines() - fuzz;
+ const char *ilineptr;
+ const char *plineptr;
+ short plinelen;
+
+ for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) {
+ ilineptr = ifetch(iline, offset >= 0);
+ if (ilineptr == NULL)
+ return false;
+ plineptr = pfetch(pline);
+ plinelen = pch_line_len(pline);
+ if (canonicalize) {
+ if (!similar(ilineptr, plineptr, plinelen))
+ return false;
+ } else if (strnNE(ilineptr, plineptr, plinelen))
+ return false;
+ if (iline == input_lines) {
+ /*
+ * We are looking at the last line of the file.
+ * If the file has no eol, the patch line should
+ * not have one either and vice-versa. Note that
+ * plinelen > 0.
+ */
+ if (last_line_missing_eol) {
+ if (plineptr[plinelen - 1] == '\n')
+ return false;
+ } else {
+ if (plineptr[plinelen - 1] != '\n')
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/*
+ * Do two lines match with canonicalized white space?
+ */
+static bool
+similar(const char *a, const char *b, int len)
+{
+ while (len) {
+ if (isspace(*b)) { /* whitespace (or \n) to match? */
+ if (!isspace(*a)) /* no corresponding whitespace? */
+ return false;
+ while (len && isspace(*b) && *b != '\n')
+ b++, len--; /* skip pattern whitespace */
+ while (isspace(*a) && *a != '\n')
+ a++; /* skip target whitespace */
+ if (*a == '\n' || *b == '\n')
+ return (*a == *b); /* should end in sync */
+ } else if (*a++ != *b++) /* match non-whitespace chars */
+ return false;
+ else
+ len--; /* probably not necessary */
+ }
+ return true; /* actually, this is not reached */
+ /* since there is always a \n */
+}
diff --git a/patch_cmds/patch/pathnames.h b/patch_cmds/patch/pathnames.h
new file mode 100644
index 0000000..397e3fa
--- /dev/null
+++ b/patch_cmds/patch/pathnames.h
@@ -0,0 +1,11 @@
+/* $OpenBSD: pathnames.h,v 1.1 2003/07/29 20:10:17 millert Exp $ */
+
+/*
+ * Placed in the public domain by Todd C. Miller <Todd.Miller@courtesan.com>
+ * on July 29, 2003.
+ */
+
+#include <paths.h>
+
+#define _PATH_ED "/bin/ed"
+#define _PATH_MKDIR "/bin/mkdir"
diff --git a/patch_cmds/patch/pch.c b/patch_cmds/patch/pch.c
new file mode 100644
index 0000000..a689e2e
--- /dev/null
+++ b/patch_cmds/patch/pch.c
@@ -0,0 +1,1544 @@
+/* $OpenBSD: pch.c,v 1.38 2009/10/27 23:59:41 deraadt Exp $ */
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "util.h"
+#include "pch.h"
+#include "pathnames.h"
+
+/* Patch (diff listing) abstract type. */
+
+static long p_filesize; /* size of the patch file */
+static LINENUM p_first; /* 1st line number */
+static LINENUM p_newfirst; /* 1st line number of replacement */
+static LINENUM p_ptrn_lines; /* # lines in pattern */
+static LINENUM p_repl_lines; /* # lines in replacement text */
+static LINENUM p_end = -1; /* last line in hunk */
+static LINENUM p_max; /* max allowed value of p_end */
+static LINENUM p_context = 3; /* # of context lines */
+static LINENUM p_input_line = 0; /* current line # from patch file */
+static char **p_line = NULL;/* the text of the hunk */
+static short *p_len = NULL; /* length of each line */
+static char *p_char = NULL; /* +, -, and ! */
+static int hunkmax = INITHUNKMAX; /* size of above arrays to begin with */
+static int p_indent; /* indent to patch */
+static LINENUM p_base; /* where to intuit this time */
+static LINENUM p_bline; /* line # of p_base */
+static LINENUM p_start; /* where intuit found a patch */
+static LINENUM p_sline; /* and the line number for it */
+static LINENUM p_hunk_beg; /* line number of current hunk */
+static LINENUM p_efake = -1; /* end of faked up lines--don't free */
+static LINENUM p_bfake = -1; /* beg of faked up lines */
+static FILE *pfp = NULL; /* patch file pointer */
+static char *bestguess = NULL; /* guess at correct filename */
+
+static void grow_hunkmax(void);
+static int intuit_diff_type(void);
+static void next_intuit_at(LINENUM, LINENUM);
+static void skip_to(LINENUM, LINENUM);
+static char *pgets(char *, int, FILE *);
+static char *best_name(const struct file_name *, bool);
+static char *posix_name(const struct file_name *, bool);
+static size_t num_components(const char *);
+
+/*
+ * Prepare to look for the next patch in the patch file.
+ */
+void
+re_patch(void)
+{
+ p_first = 0;
+ p_newfirst = 0;
+ p_ptrn_lines = 0;
+ p_repl_lines = 0;
+ p_end = (LINENUM) - 1;
+ p_max = 0;
+ p_indent = 0;
+}
+
+/*
+ * Open the patch file at the beginning of time.
+ */
+void
+open_patch_file(const char *filename)
+{
+ struct stat filestat;
+
+ if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) {
+ pfp = fopen(TMPPATNAME, "w");
+ if (pfp == NULL)
+ pfatal("can't create %s", TMPPATNAME);
+ while (fgets(buf, sizeof buf, stdin) != NULL)
+ fputs(buf, pfp);
+ fclose(pfp);
+ filename = TMPPATNAME;
+ }
+ pfp = fopen(filename, "r");
+ if (pfp == NULL)
+ pfatal("patch file %s not found", filename);
+ fstat(fileno(pfp), &filestat);
+ p_filesize = filestat.st_size;
+ next_intuit_at(0L, 1L); /* start at the beginning */
+ set_hunkmax();
+}
+
+/*
+ * Make sure our dynamically realloced tables are malloced to begin with.
+ */
+void
+set_hunkmax(void)
+{
+ if (p_line == NULL)
+ p_line = calloc((size_t) hunkmax, sizeof(char *));
+ if (p_len == NULL)
+ p_len = calloc((size_t) hunkmax, sizeof(short));
+ if (p_char == NULL)
+ p_char = calloc((size_t) hunkmax, sizeof(char));
+}
+
+/*
+ * Enlarge the arrays containing the current hunk of patch.
+ */
+static void
+grow_hunkmax(void)
+{
+ int new_hunkmax;
+ char **new_p_line;
+ short *new_p_len;
+ char *new_p_char;
+
+ new_hunkmax = hunkmax * 2;
+
+ if (p_line == NULL || p_len == NULL || p_char == NULL)
+ fatal("Internal memory allocation error\n");
+
+ new_p_line = realloc(p_line, new_hunkmax * sizeof(char *));
+ if (new_p_line == NULL)
+ free(p_line);
+
+ new_p_len = realloc(p_len, new_hunkmax * sizeof(short));
+ if (new_p_len == NULL)
+ free(p_len);
+
+ new_p_char = realloc(p_char, new_hunkmax * sizeof(char));
+ if (new_p_char == NULL)
+ free(p_char);
+
+ p_char = new_p_char;
+ p_len = new_p_len;
+ p_line = new_p_line;
+
+ if (p_line != NULL && p_len != NULL && p_char != NULL) {
+ hunkmax = new_hunkmax;
+ return;
+ }
+
+ if (!using_plan_a)
+ fatal("out of memory\n");
+ out_of_mem = true; /* whatever is null will be allocated again */
+ /* from within plan_a(), of all places */
+}
+
+/* True if the remainder of the patch file contains a diff of some sort. */
+
+bool
+there_is_another_patch(void)
+{
+ bool exists = false;
+
+ if (p_base != 0L && p_base >= p_filesize) {
+ if (verbose)
+ say("done\n");
+ return false;
+ }
+ if (verbose)
+ say("Hmm...");
+ diff_type = intuit_diff_type();
+ if (!diff_type) {
+ if (p_base != 0L) {
+ if (verbose)
+ say(" Ignoring the trailing garbage.\ndone\n");
+ } else
+ say(" I can't seem to find a patch in there anywhere.\n");
+ return false;
+ }
+ if (verbose)
+ say(" %sooks like %s to me...\n",
+ (p_base == 0L ? "L" : "The next patch l"),
+ diff_type == UNI_DIFF ? "a unified diff" :
+ diff_type == CONTEXT_DIFF ? "a context diff" :
+ diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
+ diff_type == NORMAL_DIFF ? "a normal diff" :
+ "an ed script");
+ if (p_indent && verbose)
+ say("(Patch is indented %d space%s.)\n", p_indent,
+ p_indent == 1 ? "" : "s");
+ skip_to(p_start, p_sline);
+ while (filearg[0] == NULL) {
+ if (force || batch) {
+ say("No file to patch. Skipping...\n");
+ filearg[0] = savestr(bestguess);
+ skip_rest_of_patch = true;
+ return true;
+ }
+ ask("File to patch: ");
+ if (*buf != '\n') {
+ free(bestguess);
+ bestguess = savestr(buf);
+ filearg[0] = fetchname(buf, &exists, 0);
+ }
+ if (!exists) {
+ ask("No file found--skip this patch? [n] ");
+ if (*buf != 'y')
+ continue;
+ if (verbose)
+ say("Skipping patch...\n");
+ free(filearg[0]);
+ filearg[0] = fetchname(bestguess, &exists, 0);
+ skip_rest_of_patch = true;
+ return true;
+ }
+ }
+ return true;
+}
+
+/* Determine what kind of diff is in the remaining part of the patch file. */
+
+static int
+intuit_diff_type(void)
+{
+ long this_line = 0, previous_line;
+ long first_command_line = -1;
+ LINENUM fcl_line = -1;
+ bool last_line_was_command = false, this_is_a_command = false;
+ bool stars_last_line = false, stars_this_line = false;
+ char *s, *t;
+ int indent, retval;
+ struct file_name names[MAX_FILE];
+
+ memset(names, 0, sizeof(names));
+ ok_to_create_file = false;
+ fseek(pfp, p_base, SEEK_SET);
+ p_input_line = p_bline - 1;
+ for (;;) {
+ previous_line = this_line;
+ last_line_was_command = this_is_a_command;
+ stars_last_line = stars_this_line;
+ this_line = ftell(pfp);
+ indent = 0;
+ p_input_line++;
+ if (fgets(buf, sizeof buf, pfp) == NULL) {
+ if (first_command_line >= 0L) {
+ /* nothing but deletes!? */
+ p_start = first_command_line;
+ p_sline = fcl_line;
+ retval = ED_DIFF;
+ goto scan_exit;
+ } else {
+ p_start = this_line;
+ p_sline = p_input_line;
+ retval = 0;
+ goto scan_exit;
+ }
+ }
+ for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
+ if (*s == '\t')
+ indent += 8 - (indent % 8);
+ else
+ indent++;
+ }
+ for (t = s; isdigit(*t) || *t == ','; t++)
+ ;
+ this_is_a_command = (isdigit(*s) &&
+ (*t == 'd' || *t == 'c' || *t == 'a'));
+ if (first_command_line < 0L && this_is_a_command) {
+ first_command_line = this_line;
+ fcl_line = p_input_line;
+ p_indent = indent; /* assume this for now */
+ }
+ if (!stars_last_line && strnEQ(s, "*** ", 4))
+ names[OLD_FILE].path = fetchname(s + 4,
+ &names[OLD_FILE].exists, strippath);
+ else if (strnEQ(s, "--- ", 4))
+ names[NEW_FILE].path = fetchname(s + 4,
+ &names[NEW_FILE].exists, strippath);
+ else if (strnEQ(s, "+++ ", 4))
+ /* pretend it is the old name */
+ names[OLD_FILE].path = fetchname(s + 4,
+ &names[OLD_FILE].exists, strippath);
+ else if (strnEQ(s, "Index:", 6))
+ names[INDEX_FILE].path = fetchname(s + 6,
+ &names[INDEX_FILE].exists, strippath);
+ else if (strnEQ(s, "Prereq:", 7)) {
+ for (t = s + 7; isspace(*t); t++)
+ ;
+ revision = savestr(t);
+ for (t = revision; *t && !isspace(*t); t++)
+ ;
+ *t = '\0';
+ if (*revision == '\0') {
+ free(revision);
+ revision = NULL;
+ }
+ }
+ if ((!diff_type || diff_type == ED_DIFF) &&
+ first_command_line >= 0L &&
+ strEQ(s, ".\n")) {
+ p_indent = indent;
+ p_start = first_command_line;
+ p_sline = fcl_line;
+ retval = ED_DIFF;
+ goto scan_exit;
+ }
+ if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
+ if (strnEQ(s + 4, "0,0", 3))
+ ok_to_create_file = true;
+ p_indent = indent;
+ p_start = this_line;
+ p_sline = p_input_line;
+ retval = UNI_DIFF;
+ goto scan_exit;
+ }
+ stars_this_line = strnEQ(s, "********", 8);
+ if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
+ strnEQ(s, "*** ", 4)) {
+ if (atol(s + 4) == 0)
+ ok_to_create_file = true;
+ /*
+ * If this is a new context diff the character just
+ * before the newline is a '*'.
+ */
+ while (*s != '\n')
+ s++;
+ p_indent = indent;
+ p_start = previous_line;
+ p_sline = p_input_line - 1;
+ retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
+ goto scan_exit;
+ }
+ if ((!diff_type || diff_type == NORMAL_DIFF) &&
+ last_line_was_command &&
+ (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
+ p_start = previous_line;
+ p_sline = p_input_line - 1;
+ p_indent = indent;
+ retval = NORMAL_DIFF;
+ goto scan_exit;
+ }
+ }
+scan_exit:
+ if (retval == UNI_DIFF) {
+ /* unswap old and new */
+ struct file_name tmp = names[OLD_FILE];
+ names[OLD_FILE] = names[NEW_FILE];
+ names[NEW_FILE] = tmp;
+ }
+ if (filearg[0] == NULL) {
+ if (posix)
+ filearg[0] = posix_name(names, ok_to_create_file);
+ else {
+ /* Ignore the Index: name for context diffs, like GNU */
+ if (names[OLD_FILE].path != NULL ||
+ names[NEW_FILE].path != NULL) {
+ free(names[INDEX_FILE].path);
+ names[INDEX_FILE].path = NULL;
+ }
+ filearg[0] = best_name(names, ok_to_create_file);
+ }
+ }
+
+ free(bestguess);
+ bestguess = NULL;
+ if (filearg[0] != NULL)
+ bestguess = savestr(filearg[0]);
+ else if (!ok_to_create_file) {
+ /*
+ * We don't want to create a new file but we need a
+ * filename to set bestguess. Avoid setting filearg[0]
+ * so the file is not created automatically.
+ */
+ if (posix)
+ bestguess = posix_name(names, true);
+ else
+ bestguess = best_name(names, true);
+ }
+ free(names[OLD_FILE].path);
+ free(names[NEW_FILE].path);
+ free(names[INDEX_FILE].path);
+ return retval;
+}
+
+/*
+ * Remember where this patch ends so we know where to start up again.
+ */
+static void
+next_intuit_at(LINENUM file_pos, LINENUM file_line)
+{
+ p_base = file_pos;
+ p_bline = file_line;
+}
+
+/*
+ * Basically a verbose fseek() to the actual diff listing.
+ */
+static void
+skip_to(LINENUM file_pos, LINENUM file_line)
+{
+ char *ret;
+
+ if (p_base > file_pos)
+ fatal("Internal error: seek %ld>%ld\n", p_base, file_pos);
+ if (verbose && p_base < file_pos) {
+ fseek(pfp, p_base, SEEK_SET);
+ say("The text leading up to this was:\n--------------------------\n");
+ while (ftell(pfp) < file_pos) {
+ ret = fgets(buf, sizeof buf, pfp);
+ if (ret == NULL)
+ fatal("Unexpected end of file\n");
+ say("|%s", buf);
+ }
+ say("--------------------------\n");
+ } else
+ fseek(pfp, file_pos, SEEK_SET);
+ p_input_line = file_line - 1;
+}
+
+/* Make this a function for better debugging. */
+static void
+malformed(void)
+{
+ fatal("malformed patch at line %ld: %s", p_input_line, buf);
+ /* about as informative as "Syntax error" in C */
+}
+
+/*
+ * True if the line has been discarded (i.e. it is a line saying
+ * "\ No newline at end of file".)
+ */
+static bool
+remove_special_line(void)
+{
+ int c;
+
+ c = fgetc(pfp);
+ if (c == '\\') {
+ do {
+ c = fgetc(pfp);
+ } while (c != EOF && c != '\n');
+
+ return true;
+ }
+ if (c != EOF)
+ fseek(pfp, -1L, SEEK_CUR);
+
+ return false;
+}
+
+/*
+ * True if there is more of the current diff listing to process.
+ */
+bool
+another_hunk(void)
+{
+ long line_beginning; /* file pos of the current line */
+ LINENUM repl_beginning; /* index of --- line */
+ LINENUM fillcnt; /* #lines of missing ptrn or repl */
+ LINENUM fillsrc; /* index of first line to copy */
+ LINENUM filldst; /* index of first missing line */
+ bool ptrn_spaces_eaten; /* ptrn was slightly misformed */
+ bool repl_could_be_missing; /* no + or ! lines in this hunk */
+ bool repl_missing; /* we are now backtracking */
+ long repl_backtrack_position; /* file pos of first repl line */
+ LINENUM repl_patch_line; /* input line number for same */
+ LINENUM ptrn_copiable; /* # of copiable lines in ptrn */
+ char *s, *ret;
+ int context = 0;
+
+ while (p_end >= 0) {
+ if (p_end == p_efake)
+ p_end = p_bfake; /* don't free twice */
+ else
+ free(p_line[p_end]);
+ p_end--;
+ }
+ p_efake = -1;
+
+ p_max = hunkmax; /* gets reduced when --- found */
+ if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
+ line_beginning = ftell(pfp);
+ repl_beginning = 0;
+ fillcnt = 0;
+ ptrn_spaces_eaten = false;
+ repl_could_be_missing = true;
+ repl_missing = false;
+ repl_backtrack_position = 0;
+ ptrn_copiable = 0;
+
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == NULL || strnNE(buf, "********", 8)) {
+ next_intuit_at(line_beginning, p_input_line);
+ return false;
+ }
+ p_context = 100;
+ p_hunk_beg = p_input_line + 1;
+ while (p_end < p_max) {
+ line_beginning = ftell(pfp);
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == NULL) {
+ if (p_max - p_end < 4) {
+ /* assume blank lines got chopped */
+ strlcpy(buf, " \n", sizeof buf);
+ } else {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = true;
+ goto hunk_done;
+ }
+ fatal("unexpected end of file in patch\n");
+ }
+ }
+ p_end++;
+ if (p_end >= hunkmax)
+ fatal("Internal error: hunk larger than hunk "
+ "buffer size");
+ p_char[p_end] = *buf;
+ p_line[p_end] = NULL;
+ switch (*buf) {
+ case '*':
+ if (strnEQ(buf, "********", 8)) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = true;
+ goto hunk_done;
+ } else
+ fatal("unexpected end of hunk "
+ "at line %ld\n",
+ p_input_line);
+ }
+ if (p_end != 0) {
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = true;
+ goto hunk_done;
+ }
+ fatal("unexpected *** at line %ld: %s",
+ p_input_line, buf);
+ }
+ context = 0;
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return false;
+ }
+ for (s = buf; *s && !isdigit(*s); s++)
+ ;
+ if (!*s)
+ malformed();
+ if (strnEQ(s, "0,0", 3))
+ memmove(s, s + 2, strlen(s + 2) + 1);
+ p_first = (LINENUM) atol(s);
+ while (isdigit(*s))
+ s++;
+ if (*s == ',') {
+ for (; *s && !isdigit(*s); s++)
+ ;
+ if (!*s)
+ malformed();
+ p_ptrn_lines = ((LINENUM) atol(s)) - p_first + 1;
+ } else if (p_first)
+ p_ptrn_lines = 1;
+ else {
+ p_ptrn_lines = 0;
+ p_first = 1;
+ }
+
+ /* we need this much at least */
+ p_max = p_ptrn_lines + 6;
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ p_max = hunkmax;
+ break;
+ case '-':
+ if (buf[1] == '-') {
+ if (repl_beginning ||
+ (p_end != p_ptrn_lines + 1 +
+ (p_char[p_end - 1] == '\n'))) {
+ if (p_end == 1) {
+ /*
+ * `old' lines were omitted;
+ * set up to fill them in
+ * from 'new' context lines.
+ */
+ p_end = p_ptrn_lines + 1;
+ fillsrc = p_end + 1;
+ filldst = 1;
+ fillcnt = p_ptrn_lines;
+ } else {
+ if (repl_beginning) {
+ if (repl_could_be_missing) {
+ repl_missing = true;
+ goto hunk_done;
+ }
+ fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n",
+ p_input_line, p_hunk_beg + repl_beginning);
+ } else {
+ fatal("%s \"---\" at line %ld--check line numbers at line %ld\n",
+ (p_end <= p_ptrn_lines
+ ? "Premature"
+ : "Overdue"),
+ p_input_line, p_hunk_beg);
+ }
+ }
+ }
+ repl_beginning = p_end;
+ repl_backtrack_position = ftell(pfp);
+ repl_patch_line = p_input_line;
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return false;
+ }
+ p_char[p_end] = '=';
+ for (s = buf; *s && !isdigit(*s); s++)
+ ;
+ if (!*s)
+ malformed();
+ p_newfirst = (LINENUM) atol(s);
+ while (isdigit(*s))
+ s++;
+ if (*s == ',') {
+ for (; *s && !isdigit(*s); s++)
+ ;
+ if (!*s)
+ malformed();
+ p_repl_lines = ((LINENUM) atol(s)) -
+ p_newfirst + 1;
+ } else if (p_newfirst)
+ p_repl_lines = 1;
+ else {
+ p_repl_lines = 0;
+ p_newfirst = 1;
+ }
+ p_max = p_repl_lines + p_end;
+ if (p_max > MAXHUNKSIZE)
+ fatal("hunk too large (%ld lines) at line %ld: %s",
+ p_max, p_input_line, buf);
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ if (p_repl_lines != ptrn_copiable &&
+ (p_context != 0 || p_repl_lines != 1))
+ repl_could_be_missing = false;
+ break;
+ }
+ goto change_line;
+ case '+':
+ case '!':
+ repl_could_be_missing = false;
+ change_line:
+ if (buf[1] == '\n' && canonicalize)
+ strlcpy(buf + 1, " \n", sizeof buf - 1);
+ if (!isspace(buf[1]) && buf[1] != '>' &&
+ buf[1] != '<' &&
+ repl_beginning && repl_could_be_missing) {
+ repl_missing = true;
+ goto hunk_done;
+ }
+ if (context >= 0) {
+ if (context < p_context)
+ p_context = context;
+ context = -1000;
+ }
+ p_line[p_end] = savestr(buf + 2);
+ if (out_of_mem) {
+ p_end--;
+ return false;
+ }
+ if (p_end == p_ptrn_lines) {
+ if (remove_special_line()) {
+ int len;
+
+ len = strlen(p_line[p_end]) - 1;
+ (p_line[p_end])[len] = 0;
+ }
+ }
+ break;
+ case '\t':
+ case '\n': /* assume the 2 spaces got eaten */
+ if (repl_beginning && repl_could_be_missing &&
+ (!ptrn_spaces_eaten ||
+ diff_type == NEW_CONTEXT_DIFF)) {
+ repl_missing = true;
+ goto hunk_done;
+ }
+ p_line[p_end] = savestr(buf);
+ if (out_of_mem) {
+ p_end--;
+ return false;
+ }
+ if (p_end != p_ptrn_lines + 1) {
+ ptrn_spaces_eaten |= (repl_beginning != 0);
+ context++;
+ if (!repl_beginning)
+ ptrn_copiable++;
+ p_char[p_end] = ' ';
+ }
+ break;
+ case ' ':
+ if (!isspace(buf[1]) &&
+ repl_beginning && repl_could_be_missing) {
+ repl_missing = true;
+ goto hunk_done;
+ }
+ context++;
+ if (!repl_beginning)
+ ptrn_copiable++;
+ p_line[p_end] = savestr(buf + 2);
+ if (out_of_mem) {
+ p_end--;
+ return false;
+ }
+ break;
+ default:
+ if (repl_beginning && repl_could_be_missing) {
+ repl_missing = true;
+ goto hunk_done;
+ }
+ malformed();
+ }
+ /* set up p_len for strncmp() so we don't have to */
+ /* assume null termination */
+ if (p_line[p_end])
+ p_len[p_end] = strlen(p_line[p_end]);
+ else
+ p_len[p_end] = 0;
+ }
+
+hunk_done:
+ if (p_end >= 0 && !repl_beginning)
+ fatal("no --- found in patch at line %ld\n", pch_hunk_beg());
+
+ if (repl_missing) {
+
+ /* reset state back to just after --- */
+ p_input_line = repl_patch_line;
+ for (p_end--; p_end > repl_beginning; p_end--)
+ free(p_line[p_end]);
+ fseek(pfp, repl_backtrack_position, SEEK_SET);
+
+ /* redundant 'new' context lines were omitted - set */
+ /* up to fill them in from the old file context */
+ if (!p_context && p_repl_lines == 1) {
+ p_repl_lines = 0;
+ p_max--;
+ }
+ fillsrc = 1;
+ filldst = repl_beginning + 1;
+ fillcnt = p_repl_lines;
+ p_end = p_max;
+ } else if (!p_context && fillcnt == 1) {
+ /* the first hunk was a null hunk with no context */
+ /* and we were expecting one line -- fix it up. */
+ while (filldst < p_end) {
+ p_line[filldst] = p_line[filldst + 1];
+ p_char[filldst] = p_char[filldst + 1];
+ p_len[filldst] = p_len[filldst + 1];
+ filldst++;
+ }
+#if 0
+ repl_beginning--; /* this doesn't need to be fixed */
+#endif
+ p_end--;
+ p_first++; /* do append rather than insert */
+ fillcnt = 0;
+ p_ptrn_lines = 0;
+ }
+ if (diff_type == CONTEXT_DIFF &&
+ (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
+ if (verbose)
+ say("%s\n%s\n%s\n",
+ "(Fascinating--this is really a new-style context diff but without",
+ "the telltale extra asterisks on the *** line that usually indicate",
+ "the new style...)");
+ diff_type = NEW_CONTEXT_DIFF;
+ }
+ /* if there were omitted context lines, fill them in now */
+ if (fillcnt) {
+ p_bfake = filldst; /* remember where not to free() */
+ p_efake = filldst + fillcnt - 1;
+ while (fillcnt-- > 0) {
+ while (fillsrc <= p_end && p_char[fillsrc] != ' ')
+ fillsrc++;
+ if (fillsrc > p_end)
+ fatal("replacement text or line numbers mangled in hunk at line %ld\n",
+ p_hunk_beg);
+ p_line[filldst] = p_line[fillsrc];
+ p_char[filldst] = p_char[fillsrc];
+ p_len[filldst] = p_len[fillsrc];
+ fillsrc++;
+ filldst++;
+ }
+ while (fillsrc <= p_end && fillsrc != repl_beginning &&
+ p_char[fillsrc] != ' ')
+ fillsrc++;
+#ifdef DEBUGGING
+ if (debug & 64)
+ printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
+ fillsrc, filldst, repl_beginning, p_end + 1);
+#endif
+ if (fillsrc != p_end + 1 && fillsrc != repl_beginning)
+ malformed();
+ if (filldst != p_end + 1 && filldst != repl_beginning)
+ malformed();
+ }
+ if (p_line[p_end] != NULL) {
+ if (remove_special_line()) {
+ p_len[p_end] -= 1;
+ (p_line[p_end])[p_len[p_end]] = 0;
+ }
+ }
+ } else if (diff_type == UNI_DIFF) {
+ long line_beginning = ftell(pfp); /* file pos of the current line */
+ LINENUM fillsrc; /* index of old lines */
+ LINENUM filldst; /* index of new lines */
+ char ch;
+
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == NULL || strnNE(buf, "@@ -", 4)) {
+ next_intuit_at(line_beginning, p_input_line);
+ return false;
+ }
+ s = buf + 4;
+ if (!*s)
+ malformed();
+ p_first = (LINENUM) atol(s);
+ while (isdigit(*s))
+ s++;
+ if (*s == ',') {
+ p_ptrn_lines = (LINENUM) atol(++s);
+ while (isdigit(*s))
+ s++;
+ } else
+ p_ptrn_lines = 1;
+ if (*s == ' ')
+ s++;
+ if (*s != '+' || !*++s)
+ malformed();
+ p_newfirst = (LINENUM) atol(s);
+ while (isdigit(*s))
+ s++;
+ if (*s == ',') {
+ p_repl_lines = (LINENUM) atol(++s);
+ while (isdigit(*s))
+ s++;
+ } else
+ p_repl_lines = 1;
+ if (*s == ' ')
+ s++;
+ if (*s != '@')
+ malformed();
+ if (!p_ptrn_lines)
+ p_first++; /* do append rather than insert */
+ p_max = p_ptrn_lines + p_repl_lines + 1;
+ while (p_max >= hunkmax)
+ grow_hunkmax();
+ fillsrc = 1;
+ filldst = fillsrc + p_ptrn_lines;
+ p_end = filldst + p_repl_lines;
+ snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first,
+ p_first + p_ptrn_lines - 1);
+ p_line[0] = savestr(buf);
+ if (out_of_mem) {
+ p_end = -1;
+ return false;
+ }
+ p_char[0] = '*';
+ snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,
+ p_newfirst + p_repl_lines - 1);
+ p_line[filldst] = savestr(buf);
+ if (out_of_mem) {
+ p_end = 0;
+ return false;
+ }
+ p_char[filldst++] = '=';
+ p_context = 100;
+ context = 0;
+ p_hunk_beg = p_input_line + 1;
+ while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
+ line_beginning = ftell(pfp);
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == NULL) {
+ if (p_max - filldst < 3) {
+ /* assume blank lines got chopped */
+ strlcpy(buf, " \n", sizeof buf);
+ } else {
+ fatal("unexpected end of file in patch\n");
+ }
+ }
+ if (*buf == '\t' || *buf == '\n') {
+ ch = ' '; /* assume the space got eaten */
+ s = savestr(buf);
+ } else {
+ ch = *buf;
+ s = savestr(buf + 1);
+ }
+ if (out_of_mem) {
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc - 1;
+ return false;
+ }
+ switch (ch) {
+ case '-':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+ p_end = filldst - 1;
+ malformed();
+ }
+ p_char[fillsrc] = ch;
+ p_line[fillsrc] = s;
+ p_len[fillsrc++] = strlen(s);
+ if (fillsrc > p_ptrn_lines) {
+ if (remove_special_line()) {
+ p_len[fillsrc - 1] -= 1;
+ s[p_len[fillsrc - 1]] = 0;
+ }
+ }
+ break;
+ case '=':
+ ch = ' ';
+ /* FALL THROUGH */
+ case ' ':
+ if (fillsrc > p_ptrn_lines) {
+ free(s);
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc - 1;
+ malformed();
+ }
+ context++;
+ p_char[fillsrc] = ch;
+ p_line[fillsrc] = s;
+ p_len[fillsrc++] = strlen(s);
+ s = savestr(s);
+ if (out_of_mem) {
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc - 1;
+ return false;
+ }
+ if (fillsrc > p_ptrn_lines) {
+ if (remove_special_line()) {
+ p_len[fillsrc - 1] -= 1;
+ s[p_len[fillsrc - 1]] = 0;
+ }
+ }
+ /* FALL THROUGH */
+ case '+':
+ if (filldst > p_end) {
+ free(s);
+ while (--filldst > p_ptrn_lines)
+ free(p_line[filldst]);
+ p_end = fillsrc - 1;
+ malformed();
+ }
+ p_char[filldst] = ch;
+ p_line[filldst] = s;
+ p_len[filldst++] = strlen(s);
+ if (fillsrc > p_ptrn_lines) {
+ if (remove_special_line()) {
+ p_len[filldst - 1] -= 1;
+ s[p_len[filldst - 1]] = 0;
+ }
+ }
+ break;
+ default:
+ p_end = filldst;
+ malformed();
+ }
+ if (ch != ' ' && context > 0) {
+ if (context < p_context)
+ p_context = context;
+ context = -1000;
+ }
+ } /* while */
+ } else { /* normal diff--fake it up */
+ char hunk_type;
+ int i;
+ LINENUM min, max;
+ long line_beginning = ftell(pfp);
+
+ p_context = 0;
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == NULL || !isdigit(*buf)) {
+ next_intuit_at(line_beginning, p_input_line);
+ return false;
+ }
+ p_first = (LINENUM) atol(buf);
+ for (s = buf; isdigit(*s); s++)
+ ;
+ if (*s == ',') {
+ p_ptrn_lines = (LINENUM) atol(++s) - p_first + 1;
+ while (isdigit(*s))
+ s++;
+ } else
+ p_ptrn_lines = (*s != 'a');
+ hunk_type = *s;
+ if (hunk_type == 'a')
+ p_first++; /* do append rather than insert */
+ min = (LINENUM) atol(++s);
+ for (; isdigit(*s); s++)
+ ;
+ if (*s == ',')
+ max = (LINENUM) atol(++s);
+ else
+ max = min;
+ if (hunk_type == 'd')
+ min++;
+ p_end = p_ptrn_lines + 1 + max - min + 1;
+ if (p_end > MAXHUNKSIZE)
+ fatal("hunk too large (%ld lines) at line %ld: %s",
+ p_end, p_input_line, buf);
+ while (p_end >= hunkmax)
+ grow_hunkmax();
+ p_newfirst = min;
+ p_repl_lines = max - min + 1;
+ snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first,
+ p_first + p_ptrn_lines - 1);
+ p_line[0] = savestr(buf);
+ if (out_of_mem) {
+ p_end = -1;
+ return false;
+ }
+ p_char[0] = '*';
+ for (i = 1; i <= p_ptrn_lines; i++) {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == NULL)
+ fatal("unexpected end of file in patch at line %ld\n",
+ p_input_line);
+ if (*buf != '<')
+ fatal("< expected at line %ld of patch\n",
+ p_input_line);
+ p_line[i] = savestr(buf + 2);
+ if (out_of_mem) {
+ p_end = i - 1;
+ return false;
+ }
+ p_len[i] = strlen(p_line[i]);
+ p_char[i] = '-';
+ }
+
+ if (remove_special_line()) {
+ p_len[i - 1] -= 1;
+ (p_line[i - 1])[p_len[i - 1]] = 0;
+ }
+ if (hunk_type == 'c') {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == NULL)
+ fatal("unexpected end of file in patch at line %ld\n",
+ p_input_line);
+ if (*buf != '-')
+ fatal("--- expected at line %ld of patch\n",
+ p_input_line);
+ }
+ snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max);
+ p_line[i] = savestr(buf);
+ if (out_of_mem) {
+ p_end = i - 1;
+ return false;
+ }
+ p_char[i] = '=';
+ for (i++; i <= p_end; i++) {
+ ret = pgets(buf, sizeof buf, pfp);
+ p_input_line++;
+ if (ret == NULL)
+ fatal("unexpected end of file in patch at line %ld\n",
+ p_input_line);
+ if (*buf != '>')
+ fatal("> expected at line %ld of patch\n",
+ p_input_line);
+ p_line[i] = savestr(buf + 2);
+ if (out_of_mem) {
+ p_end = i - 1;
+ return false;
+ }
+ p_len[i] = strlen(p_line[i]);
+ p_char[i] = '+';
+ }
+
+ if (remove_special_line()) {
+ p_len[i - 1] -= 1;
+ (p_line[i - 1])[p_len[i - 1]] = 0;
+ }
+ }
+ if (reverse) /* backwards patch? */
+ if (!pch_swap())
+ say("Not enough memory to swap next hunk!\n");
+#ifdef DEBUGGING
+ if (debug & 2) {
+ int i;
+ char special;
+
+ for (i = 0; i <= p_end; i++) {
+ if (i == p_ptrn_lines)
+ special = '^';
+ else
+ special = ' ';
+ fprintf(stderr, "%3d %c %c %s", i, p_char[i],
+ special, p_line[i]);
+ fflush(stderr);
+ }
+ }
+#endif
+ if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
+ p_char[p_end + 1] = '^'; /* add a stopper for apply_hunk */
+ return true;
+}
+
+/*
+ * Input a line from the patch file, worrying about indentation.
+ */
+static char *
+pgets(char *bf, int sz, FILE *fp)
+{
+ char *s, *ret = fgets(bf, sz, fp);
+ int indent = 0;
+
+ if (p_indent && ret != NULL) {
+ for (s = buf;
+ indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X');
+ s++) {
+ if (*s == '\t')
+ indent += 8 - (indent % 7);
+ else
+ indent++;
+ }
+ if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
+ fatal("buffer too small in pgets()\n");
+ }
+ return ret;
+}
+
+/*
+ * Reverse the old and new portions of the current hunk.
+ */
+bool
+pch_swap(void)
+{
+ char **tp_line; /* the text of the hunk */
+ short *tp_len; /* length of each line */
+ char *tp_char; /* +, -, and ! */
+ LINENUM i;
+ LINENUM n;
+ bool blankline = false;
+ char *s;
+
+ i = p_first;
+ p_first = p_newfirst;
+ p_newfirst = i;
+
+ /* make a scratch copy */
+
+ tp_line = p_line;
+ tp_len = p_len;
+ tp_char = p_char;
+ p_line = NULL; /* force set_hunkmax to allocate again */
+ p_len = NULL;
+ p_char = NULL;
+ set_hunkmax();
+ if (p_line == NULL || p_len == NULL || p_char == NULL) {
+
+ free(p_line);
+ p_line = tp_line;
+ free(p_len);
+ p_len = tp_len;
+ free(p_char);
+ p_char = tp_char;
+ return false; /* not enough memory to swap hunk! */
+ }
+ /* now turn the new into the old */
+
+ i = p_ptrn_lines + 1;
+ if (tp_char[i] == '\n') { /* account for possible blank line */
+ blankline = true;
+ i++;
+ }
+ if (p_efake >= 0) { /* fix non-freeable ptr range */
+ if (p_efake <= i)
+ n = p_end - i + 1;
+ else
+ n = -i;
+ p_efake += n;
+ p_bfake += n;
+ }
+ for (n = 0; i <= p_end; i++, n++) {
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ if (p_char[n] == '+')
+ p_char[n] = '-';
+ p_len[n] = tp_len[i];
+ }
+ if (blankline) {
+ i = p_ptrn_lines + 1;
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ p_len[n] = tp_len[i];
+ n++;
+ }
+ if (p_char[0] != '=')
+ fatal("Malformed patch at line %ld: expected '=' found '%c'\n",
+ p_input_line, p_char[0]);
+ p_char[0] = '*';
+ for (s = p_line[0]; *s; s++)
+ if (*s == '-')
+ *s = '*';
+
+ /* now turn the old into the new */
+
+ if (p_char[0] != '*')
+ fatal("Malformed patch at line %ld: expected '*' found '%c'\n",
+ p_input_line, p_char[0]);
+ tp_char[0] = '=';
+ for (s = tp_line[0]; *s; s++)
+ if (*s == '*')
+ *s = '-';
+ for (i = 0; n <= p_end; i++, n++) {
+ p_line[n] = tp_line[i];
+ p_char[n] = tp_char[i];
+ if (p_char[n] == '-')
+ p_char[n] = '+';
+ p_len[n] = tp_len[i];
+ }
+
+ if (i != p_ptrn_lines + 1)
+ fatal("Malformed patch at line %ld: expected %ld lines, "
+ "got %ld\n",
+ p_input_line, p_ptrn_lines + 1, i);
+
+ i = p_ptrn_lines;
+ p_ptrn_lines = p_repl_lines;
+ p_repl_lines = i;
+
+ free(tp_line);
+ free(tp_len);
+ free(tp_char);
+
+ return true;
+}
+
+/*
+ * Return the specified line position in the old file of the old context.
+ */
+LINENUM
+pch_first(void)
+{
+ return p_first;
+}
+
+/*
+ * Return the number of lines of old context.
+ */
+LINENUM
+pch_ptrn_lines(void)
+{
+ return p_ptrn_lines;
+}
+
+/*
+ * Return the probable line position in the new file of the first line.
+ */
+LINENUM
+pch_newfirst(void)
+{
+ return p_newfirst;
+}
+
+/*
+ * Return the number of lines in the replacement text including context.
+ */
+LINENUM
+pch_repl_lines(void)
+{
+ return p_repl_lines;
+}
+
+/*
+ * Return the number of lines in the whole hunk.
+ */
+LINENUM
+pch_end(void)
+{
+ return p_end;
+}
+
+/*
+ * Return the number of context lines before the first changed line.
+ */
+LINENUM
+pch_context(void)
+{
+ return p_context;
+}
+
+/*
+ * Return the length of a particular patch line.
+ */
+short
+pch_line_len(LINENUM line)
+{
+ return p_len[line];
+}
+
+/*
+ * Return the control character (+, -, *, !, etc) for a patch line.
+ */
+char
+pch_char(LINENUM line)
+{
+ return p_char[line];
+}
+
+/*
+ * Return a pointer to a particular patch line.
+ */
+char *
+pfetch(LINENUM line)
+{
+ return p_line[line];
+}
+
+/*
+ * Return where in the patch file this hunk began, for error messages.
+ */
+LINENUM
+pch_hunk_beg(void)
+{
+ return p_hunk_beg;
+}
+
+/*
+ * Apply an ed script by feeding ed itself.
+ */
+void
+do_ed_script(void)
+{
+ char *t;
+ long beginning_of_this_line;
+ FILE *pipefp = NULL;
+
+ if (!skip_rest_of_patch) {
+ if (copy_file(filearg[0], TMPOUTNAME) < 0) {
+ unlink(TMPOUTNAME);
+ fatal("can't create temp file %s", TMPOUTNAME);
+ }
+ snprintf(buf, sizeof buf, "%s%s%s", _PATH_ED,
+ verbose ? " " : " -s ", TMPOUTNAME);
+ pipefp = popen(buf, "w");
+ }
+ for (;;) {
+ beginning_of_this_line = ftell(pfp);
+ if (pgets(buf, sizeof buf, pfp) == NULL) {
+ next_intuit_at(beginning_of_this_line, p_input_line);
+ break;
+ }
+ p_input_line++;
+ for (t = buf; isdigit(*t) || *t == ','; t++)
+ ;
+ /* POSIX defines allowed commands as {a,c,d,i,s} */
+ if (isdigit(*buf) && (*t == 'a' || *t == 'c' || *t == 'd' ||
+ *t == 'i' || *t == 's')) {
+ if (pipefp != NULL)
+ fputs(buf, pipefp);
+ if (*t != 'd') {
+ while (pgets(buf, sizeof buf, pfp) != NULL) {
+ p_input_line++;
+ if (pipefp != NULL)
+ fputs(buf, pipefp);
+ if (strEQ(buf, ".\n"))
+ break;
+ }
+ }
+ } else {
+ next_intuit_at(beginning_of_this_line, p_input_line);
+ break;
+ }
+ }
+ if (pipefp == NULL)
+ return;
+ fprintf(pipefp, "w\n");
+ fprintf(pipefp, "q\n");
+ fflush(pipefp);
+ pclose(pipefp);
+ ignore_signals();
+ if (!check_only) {
+ if (move_file(TMPOUTNAME, outname) < 0) {
+ toutkeep = true;
+ chmod(TMPOUTNAME, filemode);
+ } else
+ chmod(outname, filemode);
+ }
+ set_signals(1);
+}
+
+/*
+ * Choose the name of the file to be patched based on POSIX rules.
+ * NOTE: the POSIX rules are amazingly stupid and we only follow them
+ * if the user specified --posix or set POSIXLY_CORRECT.
+ */
+static char *
+posix_name(const struct file_name *names, bool assume_exists)
+{
+ char *path = NULL;
+ int i;
+
+ /*
+ * POSIX states that the filename will be chosen from one
+ * of the old, new and index names (in that order) if
+ * the file exists relative to CWD after -p stripping.
+ */
+ for (i = 0; i < MAX_FILE; i++) {
+ if (names[i].path != NULL && names[i].exists) {
+ path = names[i].path;
+ break;
+ }
+ }
+ if (path == NULL && !assume_exists) {
+ /*
+ * No files found, look for something we can checkout from
+ * RCS/SCCS dirs. Same order as above.
+ */
+ for (i = 0; i < MAX_FILE; i++) {
+ if (names[i].path != NULL &&
+ (path = checked_in(names[i].path)) != NULL)
+ break;
+ }
+ /*
+ * Still no match? Check to see if the diff could be creating
+ * a new file.
+ */
+ if (path == NULL && ok_to_create_file &&
+ names[NEW_FILE].path != NULL)
+ path = names[NEW_FILE].path;
+ }
+
+ return path ? savestr(path) : NULL;
+}
+
+/*
+ * Choose the name of the file to be patched based the "best" one
+ * available.
+ */
+static char *
+best_name(const struct file_name *names, bool assume_exists)
+{
+ size_t min_components, min_baselen, min_len, tmp;
+ char *best = NULL;
+ int i;
+
+ /*
+ * The "best" name is the one with the fewest number of path
+ * components, the shortest basename length, and the shortest
+ * overall length (in that order). We only use the Index: file
+ * if neither of the old or new files could be intuited from
+ * the diff header.
+ */
+ min_components = min_baselen = min_len = SIZE_MAX;
+ for (i = INDEX_FILE; i >= OLD_FILE; i--) {
+ if (names[i].path == NULL ||
+ (!names[i].exists && !assume_exists))
+ continue;
+ if ((tmp = num_components(names[i].path)) > min_components)
+ continue;
+ min_components = tmp;
+ if ((tmp = strlen(basename(names[i].path))) > min_baselen)
+ continue;
+ min_baselen = tmp;
+ if ((tmp = strlen(names[i].path)) > min_len)
+ continue;
+ min_len = tmp;
+ best = names[i].path;
+ }
+ if (best == NULL) {
+ /*
+ * No files found, look for something we can checkout from
+ * RCS/SCCS dirs. Logic is identical to that above...
+ */
+ min_components = min_baselen = min_len = SIZE_MAX;
+ for (i = INDEX_FILE; i >= OLD_FILE; i--) {
+ if (names[i].path == NULL ||
+ checked_in(names[i].path) == NULL)
+ continue;
+ if ((tmp = num_components(names[i].path)) > min_components)
+ continue;
+ min_components = tmp;
+ if ((tmp = strlen(basename(names[i].path))) > min_baselen)
+ continue;
+ min_baselen = tmp;
+ if ((tmp = strlen(names[i].path)) > min_len)
+ continue;
+ min_len = tmp;
+ best = names[i].path;
+ }
+ /*
+ * Still no match? Check to see if the diff could be creating
+ * a new file.
+ */
+ if (best == NULL && ok_to_create_file &&
+ names[NEW_FILE].path != NULL)
+ best = names[NEW_FILE].path;
+ }
+
+ return best ? savestr(best) : NULL;
+}
+
+static size_t
+num_components(const char *path)
+{
+ size_t n;
+ const char *cp;
+
+ for (n = 0, cp = path; (cp = strchr(cp, '/')) != NULL; n++, cp++) {
+ while (*cp == '/')
+ cp++; /* skip consecutive slashes */
+ }
+ return n;
+}
diff --git a/patch_cmds/patch/pch.h b/patch_cmds/patch/pch.h
new file mode 100644
index 0000000..b7bf8e8
--- /dev/null
+++ b/patch_cmds/patch/pch.h
@@ -0,0 +1,56 @@
+/* $OpenBSD: pch.h,v 1.9 2003/10/31 20:20:45 millert Exp $ */
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
+
+#define OLD_FILE 0
+#define NEW_FILE 1
+#define INDEX_FILE 2
+#define MAX_FILE 3
+
+struct file_name {
+ char *path;
+ bool exists;
+};
+
+void re_patch(void);
+void open_patch_file(const char *);
+void set_hunkmax(void);
+bool there_is_another_patch(void);
+bool another_hunk(void);
+bool pch_swap(void);
+char *pfetch(LINENUM);
+short pch_line_len(LINENUM);
+LINENUM pch_first(void);
+LINENUM pch_ptrn_lines(void);
+LINENUM pch_newfirst(void);
+LINENUM pch_repl_lines(void);
+LINENUM pch_end(void);
+LINENUM pch_context(void);
+LINENUM pch_hunk_beg(void);
+char pch_char(LINENUM);
+char *pfetch(LINENUM);
+void do_ed_script(void);
diff --git a/patch_cmds/patch/util.c b/patch_cmds/patch/util.c
new file mode 100644
index 0000000..d89d29c
--- /dev/null
+++ b/patch_cmds/patch/util.c
@@ -0,0 +1,420 @@
+/* $OpenBSD: util.c,v 1.33 2009/10/27 23:59:41 deraadt Exp $ */
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "util.h"
+#include "backupfile.h"
+#include "pathnames.h"
+
+/* Rename a file, copying it if necessary. */
+
+int
+move_file(const char *from, const char *to)
+{
+ int fromfd;
+ ssize_t i;
+
+ /* to stdout? */
+
+ if (strEQ(to, "-")) {
+#ifdef DEBUGGING
+ if (debug & 4)
+ say("Moving %s to stdout.\n", from);
+#endif
+ fromfd = open(from, O_RDONLY);
+ if (fromfd < 0)
+ pfatal("internal error, can't reopen %s", from);
+ while ((i = read(fromfd, buf, sizeof buf)) > 0)
+ if (write(STDOUT_FILENO, buf, i) != i)
+ pfatal("write failed");
+ close(fromfd);
+ return 0;
+ }
+ if (backup_file(to) < 0) {
+ say("Can't backup %s, output is in %s: %s\n", to, from,
+ strerror(errno));
+ return -1;
+ }
+#ifdef DEBUGGING
+ if (debug & 4)
+ say("Moving %s to %s.\n", from, to);
+#endif
+ if (rename(from, to) < 0) {
+ if (errno != EXDEV || copy_file(from, to) < 0) {
+ say("Can't create %s, output is in %s: %s\n",
+ to, from, strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/* Backup the original file. */
+
+int
+backup_file(const char *orig)
+{
+ struct stat filestat;
+ char bakname[MAXPATHLEN], *s, *simplename;
+ dev_t orig_device;
+ ino_t orig_inode;
+
+ if (backup_type == none || stat(orig, &filestat) != 0)
+ return 0; /* nothing to do */
+ orig_device = filestat.st_dev;
+ orig_inode = filestat.st_ino;
+
+ if (origprae) {
+ if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
+ strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname))
+ fatal("filename %s too long for buffer\n", origprae);
+ } else {
+ if ((s = find_backup_file_name(orig)) == NULL)
+ fatal("out of memory\n");
+ if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname))
+ fatal("filename %s too long for buffer\n", s);
+ free(s);
+ }
+
+ if ((simplename = strrchr(bakname, '/')) != NULL)
+ simplename = simplename + 1;
+ else
+ simplename = bakname;
+
+ /*
+ * Find a backup name that is not the same file. Change the
+ * first lowercase char into uppercase; if that isn't
+ * sufficient, chop off the first char and try again.
+ */
+ while (stat(bakname, &filestat) == 0 &&
+ orig_device == filestat.st_dev && orig_inode == filestat.st_ino) {
+ /* Skip initial non-lowercase chars. */
+ for (s = simplename; *s && !islower(*s); s++)
+ ;
+ if (*s)
+ *s = toupper(*s);
+ else
+ memmove(simplename, simplename + 1,
+ strlen(simplename + 1) + 1);
+ }
+#ifdef DEBUGGING
+ if (debug & 4)
+ say("Moving %s to %s.\n", orig, bakname);
+#endif
+ if (rename(orig, bakname) < 0) {
+ if (errno != EXDEV || copy_file(orig, bakname) < 0)
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Copy a file.
+ */
+int
+copy_file(const char *from, const char *to)
+{
+ int tofd, fromfd;
+ ssize_t i;
+
+ tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666);
+ if (tofd < 0)
+ return -1;
+ fromfd = open(from, O_RDONLY, 0);
+ if (fromfd < 0)
+ pfatal("internal error, can't reopen %s", from);
+ while ((i = read(fromfd, buf, sizeof buf)) > 0)
+ if (write(tofd, buf, i) != i)
+ pfatal("write to %s failed", to);
+ close(fromfd);
+ close(tofd);
+ return 0;
+}
+
+/*
+ * Allocate a unique area for a string.
+ */
+char *
+savestr(const char *s)
+{
+ char *rv;
+
+ if (!s)
+ s = "Oops";
+ rv = strdup(s);
+ if (rv == NULL) {
+ if (using_plan_a)
+ out_of_mem = true;
+ else
+ fatal("out of memory\n");
+ }
+ return rv;
+}
+
+/*
+ * Vanilla terminal output (buffered).
+ */
+void
+say(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fflush(stderr);
+}
+
+/*
+ * Terminal output, pun intended.
+ */
+void
+fatal(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fprintf(stderr, "patch: **** ");
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ my_exit(2);
+}
+
+/*
+ * Say something from patch, something from the system, then silence . . .
+ */
+void
+pfatal(const char *fmt, ...)
+{
+ va_list ap;
+ int errnum = errno;
+
+ fprintf(stderr, "patch: **** ");
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, ": %s\n", strerror(errnum));
+ my_exit(2);
+}
+
+/*
+ * Get a response from the user via /dev/tty
+ */
+void
+ask(const char *fmt, ...)
+{
+ va_list ap;
+ ssize_t nr;
+ static int ttyfd = -1;
+
+ va_start(ap, fmt);
+ vfprintf(stdout, fmt, ap);
+ va_end(ap);
+ fflush(stdout);
+ if (ttyfd < 0)
+ ttyfd = open(_PATH_TTY, O_RDONLY);
+ if (ttyfd >= 0) {
+ if ((nr = read(ttyfd, buf, sizeof(buf))) > 0 &&
+ buf[nr - 1] == '\n')
+ buf[nr - 1] = '\0';
+ }
+ if (ttyfd < 0 || nr <= 0) {
+ /* no tty or error reading, pretend user entered 'return' */
+ putchar('\n');
+ buf[0] = '\0';
+ }
+}
+
+/*
+ * How to handle certain events when not in a critical region.
+ */
+void
+set_signals(int reset)
+{
+ static sig_t hupval, intval;
+
+ if (!reset) {
+ hupval = signal(SIGHUP, SIG_IGN);
+ if (hupval != SIG_IGN)
+ hupval = (sig_t) my_exit;
+ intval = signal(SIGINT, SIG_IGN);
+ if (intval != SIG_IGN)
+ intval = (sig_t) my_exit;
+ }
+ signal(SIGHUP, hupval);
+ signal(SIGINT, intval);
+}
+
+/*
+ * How to handle certain events when in a critical region.
+ */
+void
+ignore_signals(void)
+{
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+}
+
+/*
+ * Make sure we'll have the directories to create a file. If `striplast' is
+ * true, ignore the last element of `filename'.
+ */
+
+void
+makedirs(const char *filename, bool striplast)
+{
+ char *tmpbuf;
+
+ if ((tmpbuf = strdup(filename)) == NULL)
+ fatal("out of memory\n");
+
+ if (striplast) {
+ char *s = strrchr(tmpbuf, '/');
+ if (s == NULL)
+ return; /* nothing to be done */
+ *s = '\0';
+ }
+ if (mkpath(tmpbuf) != 0)
+ pfatal("creation of %s failed", tmpbuf);
+ free(tmpbuf);
+}
+
+/*
+ * Make filenames more reasonable.
+ */
+char *
+fetchname(const char *at, bool *exists, int strip_leading)
+{
+ char *fullname, *name, *t;
+ int sleading, tab;
+ struct stat filestat;
+
+ if (at == NULL || *at == '\0')
+ return NULL;
+ while (isspace(*at))
+ at++;
+#ifdef DEBUGGING
+ if (debug & 128)
+ say("fetchname %s %d\n", at, strip_leading);
+#endif
+ /* So files can be created by diffing against /dev/null. */
+ if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
+ return NULL;
+ name = fullname = t = savestr(at);
+
+ tab = strchr(t, '\t') != NULL;
+ /* Strip off up to `strip_leading' path components and NUL terminate. */
+ for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
+ !isspace(*t)); t++) {
+ if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
+ if (--sleading >= 0)
+ name = t + 1;
+ }
+ *t = '\0';
+
+ /*
+ * If no -p option was given (957 is the default value!), we were
+ * given a relative pathname, and the leading directories that we
+ * just stripped off all exist, put them back on.
+ */
+ if (strip_leading == 957 && name != fullname && *fullname != '/') {
+ name[-1] = '\0';
+ if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
+ name[-1] = '/';
+ name = fullname;
+ }
+ }
+ name = savestr(name);
+ free(fullname);
+
+ *exists = stat(name, &filestat) == 0;
+ return name;
+}
+
+/*
+ * Takes the name returned by fetchname and looks in RCS/SCCS directories
+ * for a checked in version.
+ */
+char *
+checked_in(char *file)
+{
+ char *filebase, *filedir, tmpbuf[MAXPATHLEN];
+ struct stat filestat;
+
+ filebase = basename(file);
+ filedir = dirname(file);
+
+#define try(f, a1, a2, a3) \
+(snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
+
+ if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
+ try("%s/RCS/%s%s", filedir, filebase, "") ||
+ try("%s/%s%s", filedir, filebase, RCSSUFFIX) ||
+ try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
+ try("%s/%s%s", filedir, SCCSPREFIX, filebase))
+ return file;
+
+ return NULL;
+}
+
+void
+version(void)
+{
+ fprintf(stderr, "Patch version 2.0-12u8-Apple\n");
+ my_exit(EXIT_SUCCESS);
+}
+
+/*
+ * Exit with cleanup.
+ */
+void
+my_exit(int status)
+{
+ unlink(TMPINNAME);
+ if (!toutkeep)
+ unlink(TMPOUTNAME);
+ if (!trejkeep)
+ unlink(TMPREJNAME);
+ unlink(TMPPATNAME);
+ exit(status);
+}
diff --git a/patch_cmds/patch/util.h b/patch_cmds/patch/util.h
new file mode 100644
index 0000000..b27bbe3
--- /dev/null
+++ b/patch_cmds/patch/util.h
@@ -0,0 +1,50 @@
+/* $OpenBSD: util.h,v 1.15 2005/06/20 07:14:06 otto Exp $ */
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
+
+char *fetchname(const char *, bool *, int);
+char *checked_in(char *);
+int backup_file(const char *);
+int move_file(const char *, const char *);
+int copy_file(const char *, const char *);
+void say(const char *, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+void fatal(const char *, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+void pfatal(const char *, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+void ask(const char *, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+char *savestr(const char *);
+void set_signals(int);
+void ignore_signals(void);
+void makedirs(const char *, bool);
+void version(void);
+void my_exit(int) __attribute__((noreturn));
+
+/* in mkpath.c */
+extern int mkpath(char *);
diff --git a/patch_cmds/patch_cmds.plist b/patch_cmds/patch_cmds.plist
new file mode 100644
index 0000000..a6df14c
--- /dev/null
+++ b/patch_cmds/patch_cmds.plist
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>diffstat</string>
+ <key>OpenSourceVersion</key>
+ <string>1.55</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://invisible-island.net/diffstat/</string>
+ <key>OpenSourceURL</key>
+ <string>ftp://invisible-island.net/diffstat/diffstat-1.55.tgz</string>
+ <key>OpenSourceSHA1</key>
+ <string>625650a9f1a27edbb98316adb3013e57c8e2e23a</string>
+ <key>OpenSourceImportDate</key>
+ <string>2012-11-29</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Added manually-generated config.h file.</string>
+ <string>Build with -D_DARWIN_C_SOURCE to fix a warning.</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>MIT</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>patch_cmds.txt</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>patch</string>
+ <key>OpenSourceVersion</key>
+ <string>2009-10-27</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/patch/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d anoncvs@anoncvs1.usa.openbsd.org:/cvs co src/usr.bin/patch</string>
+ <key>OpenSourceImportDate</key>
+ <string>2009-11-05</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Correctly cast some arguments to basename/dirname.</string>
+ <string>Disable verbose mode by default, add --verbose option.</string>
+ <string>Print &quot;patching file&quot; message when not in verbose mode.</string>
+ <string>Change version output to Apple.</string>
+ <string>Add --binary option (ignored).</string>
+ <string>Add --dry-run option as an alias for -C/--check.</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>patch_cmds.txt</string>
+ </dict>
+</array>
+</plist>
diff --git a/patch_cmds/patch_cmds.txt b/patch_cmds/patch_cmds.txt
new file mode 100644
index 0000000..255365c
--- /dev/null
+++ b/patch_cmds/patch_cmds.txt
@@ -0,0 +1,50 @@
+diffstat:
+
+/******************************************************************************
+ * Copyright 1994-2008,2009 by Thomas E. Dickey *
+ * All Rights Reserved. *
+ * *
+ * Permission to use, copy, modify, and distribute this software and its *
+ * documentation for any purpose and without fee is hereby granted, provided *
+ * that the above copyright notice appear in all copies and that both that *
+ * copyright notice and this permission notice appear in supporting *
+ * documentation, and that the name of the above listed copyright holder(s) *
+ * not be used in advertising or publicity pertaining to distribution of the *
+ * software without specific, written prior permission. *
+ * *
+ * THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD *
+ * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND *
+ * FITNESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE *
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR *
+ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ******************************************************************************/
+
+patch:
+
+/*
+ * patch - a program to apply diffs to original files
+ *
+ * Copyright 1986, Larry Wall
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following condition is met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this condition and the following disclaimer.
+ *
+ * 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.
+ *
+ * -C option added in 1998, original code by Marc Espie, based on FreeBSD
+ * behaviour
+ */
diff --git a/patch_cmds/patch_cmds.xcodeproj/project.pbxproj b/patch_cmds/patch_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..42734f6
--- /dev/null
+++ b/patch_cmds/patch_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,398 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FDDB0E80109661D2003751DE /* Default */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDDB0E8B109661DB003751DE /* Build configuration list for PBXAggregateTarget "Default" */;
+ buildPhases = (
+ );
+ dependencies = (
+ FD50541B10A4CAEA0060248B /* PBXTargetDependency */,
+ FDDB0F00109665B7003751DE /* PBXTargetDependency */,
+ );
+ name = Default;
+ productName = Default;
+ };
+ FDDB0EFB1096659F003751DE /* Open Source Info */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FDDB0F0A109665C3003751DE /* Build configuration list for PBXAggregateTarget "Open Source Info" */;
+ buildPhases = (
+ FDDB0EFA1096659F003751DE /* OpenSourceVersions */,
+ FDDB0F09109665C3003751DE /* OpenSourceLicenses */,
+ );
+ dependencies = (
+ );
+ name = "Open Source Info";
+ productName = "Open Source Info";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ FD50541D10A4CB1F0060248B /* diffstat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD5052B210A4CABA0060248B /* diffstat.1 */; };
+ FD50541E10A4CB210060248B /* diffstat.c in Sources */ = {isa = PBXBuildFile; fileRef = FD5052B310A4CABA0060248B /* diffstat.c */; };
+ FDDB0E9D10966219003751DE /* backupfile.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB0E90109661FE003751DE /* backupfile.c */; };
+ FDDB0E9E10966219003751DE /* inp.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB0E93109661FE003751DE /* inp.c */; };
+ FDDB0E9F10966219003751DE /* mkpath.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB0E95109661FE003751DE /* mkpath.c */; };
+ FDDB0EA010966219003751DE /* patch.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB0E97109661FE003751DE /* patch.c */; };
+ FDDB0EA110966219003751DE /* pch.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB0E99109661FE003751DE /* pch.c */; };
+ FDDB0EA210966219003751DE /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FDDB0E9B109661FE003751DE /* util.c */; };
+ FDDB0ED710966403003751DE /* patch.1 in Install man1 */ = {isa = PBXBuildFile; fileRef = FDDB0E96109661FE003751DE /* patch.1 */; };
+ FDDB0F01109665BB003751DE /* patch_cmds.plist in OpenSourceVersions */ = {isa = PBXBuildFile; fileRef = FDDB0EF710966590003751DE /* patch_cmds.plist */; };
+ FDDB0F03109665C2003751DE /* patch_cmds.txt in OpenSourceLicenses */ = {isa = PBXBuildFile; fileRef = FDDB0EF810966590003751DE /* patch_cmds.txt */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ FD50541A10A4CAEA0060248B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDDB0E77109661C0003751DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD50541610A4CAE40060248B;
+ remoteInfo = diffstat;
+ };
+ FDDB0EFF109665B7003751DE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FDDB0E77109661C0003751DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDDB0EFB1096659F003751DE;
+ remoteInfo = "Open Source Info";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ FD50541F10A4CB270060248B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FD50541D10A4CB1F0060248B /* diffstat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDDB0EDB10966409003751DE /* Install man1 */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ FDDB0ED710966403003751DE /* patch.1 in Install man1 */,
+ );
+ name = "Install man1";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDDB0EFA1096659F003751DE /* OpenSourceVersions */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/OpenSourceVersions;
+ dstSubfolderSpec = 0;
+ files = (
+ FDDB0F01109665BB003751DE /* patch_cmds.plist in OpenSourceVersions */,
+ );
+ name = OpenSourceVersions;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDDB0F09109665C3003751DE /* OpenSourceLicenses */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/OpenSourceLicenses;
+ dstSubfolderSpec = 0;
+ files = (
+ FDDB0F03109665C2003751DE /* patch_cmds.txt in OpenSourceLicenses */,
+ );
+ name = OpenSourceLicenses;
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ FD5052B210A4CABA0060248B /* diffstat.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = diffstat.1; sourceTree = "<group>"; };
+ FD5052B310A4CABA0060248B /* diffstat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = diffstat.c; sourceTree = "<group>"; };
+ FD50541710A4CAE40060248B /* diffstat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = diffstat; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDDB0E86109661DB003751DE /* patch */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = patch; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDDB0E90109661FE003751DE /* backupfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = backupfile.c; sourceTree = "<group>"; };
+ FDDB0E91109661FE003751DE /* backupfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = backupfile.h; sourceTree = "<group>"; };
+ FDDB0E92109661FE003751DE /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
+ FDDB0E93109661FE003751DE /* inp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = inp.c; sourceTree = "<group>"; };
+ FDDB0E94109661FE003751DE /* inp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = inp.h; sourceTree = "<group>"; };
+ FDDB0E95109661FE003751DE /* mkpath.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mkpath.c; sourceTree = "<group>"; };
+ FDDB0E96109661FE003751DE /* patch.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = patch.1; sourceTree = "<group>"; };
+ FDDB0E97109661FE003751DE /* patch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = patch.c; sourceTree = "<group>"; };
+ FDDB0E98109661FE003751DE /* pathnames.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FDDB0E99109661FE003751DE /* pch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pch.c; sourceTree = "<group>"; };
+ FDDB0E9A109661FE003751DE /* pch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pch.h; sourceTree = "<group>"; };
+ FDDB0E9B109661FE003751DE /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FDDB0E9C109661FE003751DE /* util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = util.h; sourceTree = "<group>"; };
+ FDDB0EF710966590003751DE /* patch_cmds.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = patch_cmds.plist; sourceTree = "<group>"; };
+ FDDB0EF810966590003751DE /* patch_cmds.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = patch_cmds.txt; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FD50541510A4CAE40060248B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDDB0E84109661DB003751DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ FD5052A910A4CABA0060248B /* diffstat */ = {
+ isa = PBXGroup;
+ children = (
+ FD5052B210A4CABA0060248B /* diffstat.1 */,
+ FD5052B310A4CABA0060248B /* diffstat.c */,
+ );
+ path = diffstat;
+ sourceTree = "<group>";
+ };
+ FDDB0E75109661C0003751DE = {
+ isa = PBXGroup;
+ children = (
+ FDDB0EF710966590003751DE /* patch_cmds.plist */,
+ FDDB0EF810966590003751DE /* patch_cmds.txt */,
+ FD5052A910A4CABA0060248B /* diffstat */,
+ FDDB0E8D109661FE003751DE /* patch */,
+ FDDB0E87109661DB003751DE /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ FDDB0E87109661DB003751DE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FDDB0E86109661DB003751DE /* patch */,
+ FD50541710A4CAE40060248B /* diffstat */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FDDB0E8D109661FE003751DE /* patch */ = {
+ isa = PBXGroup;
+ children = (
+ FDDB0E90109661FE003751DE /* backupfile.c */,
+ FDDB0E91109661FE003751DE /* backupfile.h */,
+ FDDB0E92109661FE003751DE /* common.h */,
+ FDDB0E93109661FE003751DE /* inp.c */,
+ FDDB0E94109661FE003751DE /* inp.h */,
+ FDDB0E95109661FE003751DE /* mkpath.c */,
+ FDDB0E96109661FE003751DE /* patch.1 */,
+ FDDB0E97109661FE003751DE /* patch.c */,
+ FDDB0E98109661FE003751DE /* pathnames.h */,
+ FDDB0E99109661FE003751DE /* pch.c */,
+ FDDB0E9A109661FE003751DE /* pch.h */,
+ FDDB0E9B109661FE003751DE /* util.c */,
+ FDDB0E9C109661FE003751DE /* util.h */,
+ );
+ path = patch;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ FD50541610A4CAE40060248B /* diffstat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD50542010A4CB270060248B /* Build configuration list for PBXNativeTarget "diffstat" */;
+ buildPhases = (
+ FD50541410A4CAE40060248B /* Sources */,
+ FD50541510A4CAE40060248B /* Frameworks */,
+ FD50541F10A4CB270060248B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = diffstat;
+ productName = diffstat;
+ productReference = FD50541710A4CAE40060248B /* diffstat */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDDB0E85109661DB003751DE /* patch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDDB0E8C109661DB003751DE /* Build configuration list for PBXNativeTarget "patch" */;
+ buildPhases = (
+ FDDB0E83109661DB003751DE /* Sources */,
+ FDDB0E84109661DB003751DE /* Frameworks */,
+ FDDB0EDB10966409003751DE /* Install man1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = patch;
+ productName = patch;
+ productReference = FDDB0E86109661DB003751DE /* patch */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FDDB0E77109661C0003751DE /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = FDDB0E7A109661C0003751DE /* Build configuration list for PBXProject "patch_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ hasScannedForEncodings = 0;
+ mainGroup = FDDB0E75109661C0003751DE;
+ productRefGroup = FDDB0E87109661DB003751DE /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FDDB0E80109661D2003751DE /* Default */,
+ FD50541610A4CAE40060248B /* diffstat */,
+ FDDB0E85109661DB003751DE /* patch */,
+ FDDB0EFB1096659F003751DE /* Open Source Info */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FD50541410A4CAE40060248B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD50541E10A4CB210060248B /* diffstat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDDB0E83109661DB003751DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDDB0EA010966219003751DE /* patch.c in Sources */,
+ FDDB0EA110966219003751DE /* pch.c in Sources */,
+ FDDB0E9E10966219003751DE /* inp.c in Sources */,
+ FDDB0EA210966219003751DE /* util.c in Sources */,
+ FDDB0E9D10966219003751DE /* backupfile.c in Sources */,
+ FDDB0E9F10966219003751DE /* mkpath.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ FD50541B10A4CAEA0060248B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD50541610A4CAE40060248B /* diffstat */;
+ targetProxy = FD50541A10A4CAEA0060248B /* PBXContainerItemProxy */;
+ };
+ FDDB0F00109665B7003751DE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDDB0EFB1096659F003751DE /* Open Source Info */;
+ targetProxy = FDDB0EFF109665B7003751DE /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ FD50541910A4CAE50060248B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ HAVE_CONFIG_H,
+ "_XOPEN_SOURCE=500",
+ _DARWIN_C_SOURCE,
+ );
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/diffstat";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = diffstat;
+ };
+ name = Release;
+ };
+ FDDB0E79109661C0003751DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+ CODE_SIGN_IDENTITY = "-";
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEAD_CODE_STRIPPING = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ PREBINDING = NO;
+ USE_HEADERMAP = NO;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = __;
+ WARNING_CFLAGS = "-Wall";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ FDDB0E82109661D2003751DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = Default;
+ };
+ name = Release;
+ };
+ FDDB0E8A109661DB003751DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = patch;
+ };
+ name = Release;
+ };
+ FDDB0EFC1096659F003751DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "Open Source Info";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ FD50542010A4CB270060248B /* Build configuration list for PBXNativeTarget "diffstat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD50541910A4CAE50060248B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDDB0E7A109661C0003751DE /* Build configuration list for PBXProject "patch_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDDB0E79109661C0003751DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDDB0E8B109661DB003751DE /* Build configuration list for PBXAggregateTarget "Default" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDDB0E82109661D2003751DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDDB0E8C109661DB003751DE /* Build configuration list for PBXNativeTarget "patch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDDB0E8A109661DB003751DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDDB0F0A109665C3003751DE /* Build configuration list for PBXAggregateTarget "Open Source Info" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDDB0EFC1096659F003751DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FDDB0E77109661C0003751DE /* Project object */;
+}
diff --git a/remote_cmds/APPLE_LICENSE b/remote_cmds/APPLE_LICENSE
new file mode 100644
index 0000000..e7aa7d0
--- /dev/null
+++ b/remote_cmds/APPLE_LICENSE
@@ -0,0 +1,370 @@
+ APPLE PUBLIC SOURCE LICENSE
+ Version 1.0 - March 16, 1999
+
+Please read this License carefully before downloading this software.
+By downloading and using this software, you are agreeing to be bound
+by the terms of this License. If you do not or cannot agree to the
+terms of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+ work which Apple Computer, Inc. ("Apple") publicly announces as
+ subject to this Apple Public Source License and which contains a
+ notice placed by Apple identifying such program or work as "Original
+ Code" and stating that it is subject to the terms of this Apple
+ Public Source License version 1.0 (or subsequent version thereof),
+ as it may be revised from time to time by Apple ("License"). As
+ used in this License:
+
+1.1 "Applicable Patents" mean: (a) in the case where Apple is the
+ grantor of rights, (i) patents or patent applications that are now
+ or hereafter acquired, owned by or assigned to Apple and (ii) whose
+ claims cover subject matter contained in the Original Code, but only
+ to the extent necessary to use, reproduce and/or distribute the
+ Original Code without infringement; and (b) in the case where You
+ are the grantor of rights, (i) patents and patent applications that
+ are now or hereafter acquired, owned by or assigned to You and (ii)
+ whose claims cover subject matter in Your Modifications, taken alone
+ or in combination with Original Code.
+
+1.2 "Covered Code" means the Original Code, Modifications, the
+ combination of Original Code and any Modifications, and/or any
+ respective portions thereof.
+
+1.3 "Deploy" means to use, sublicense or distribute Covered Code other
+ than for Your internal research and development (R&D), and includes
+ without limitation, any and all internal use or distribution of
+ Covered Code within Your business or organization except for R&D
+ use, as well as direct or indirect sublicensing or distribution of
+ Covered Code by You to any third party in any form or manner.
+
+1.4 "Larger Work" means a work which combines Covered Code or portions
+ thereof with code not governed by the terms of this License.
+
+1.5 "Modifications" mean any addition to, deletion from, and/or change
+ to, the substance and/or structure of Covered Code. When code is
+ released as a series of files, a Modification is: (a) any addition
+ to or deletion from the contents of a file containing Covered Code;
+ and/or (b) any new file or other representation of computer program
+ statements that contains any part of Covered Code.
+
+1.6 "Original Code" means the Source Code of a program or other work
+ as originally made available by Apple under this License, including
+ the Source Code of any updates or upgrades to such programs or works
+ made available by Apple under this License, and that has been
+ expressly identified by Apple as such in the header file(s) of such
+ work.
+
+1.7 "Source Code" means the human readable form of a program or other
+ work that is suitable for making modifications to it, including all
+ modules it contains, plus any associated interface definition files,
+ scripts used to control compilation and installation of an
+ executable (object code).
+
+1.8 "You" or "Your" means an individual or a legal entity exercising
+ rights under this License. For legal entities, "You" or "Your"
+ includes any entity which controls, is controlled by, or is under
+ common control with, You, where "control" means (a) the power,
+ direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership of fifty
+ percent (50%) or more of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+ and conditions of this License, Apple hereby grants You, effective
+ on the date You accept this License and download the Original Code,
+ a world-wide, royalty-free, non-exclusive license, to the extent of
+ Apple's Applicable Patents and copyrights covering the Original
+ Code, to do the following:
+
+2.1 You may use, copy, modify and distribute Original Code, with or
+ without Modifications, solely for Your internal research and
+ development, provided that You must in each instance:
+
+(a) retain and reproduce in all copies of Original Code the copyright
+and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code
+that refer to this License;
+
+(b) include a copy of this License with every copy of Source Code of
+Covered Code and documentation You distribute, and You may not offer
+or impose any terms on such Source Code that alter or restrict this
+License or the recipients' rights hereunder, except as permitted under
+Section 6; and
+
+(c) completely and accurately document all Modifications that you have
+made and the date of each such Modification, designate the version of
+the Original Code you used, prominently include a file carrying such
+information with the Modifications, and duplicate the notice in
+Exhibit A in each file of the Source Code of all such Modifications.
+
+2.2 You may Deploy Covered Code, provided that You must in each
+ instance:
+
+(a) satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) make all Your Deployed Modifications publicly available in Source
+Code form via electronic distribution (e.g. download from a web site)
+under the terms of this License and subject to the license grants set
+forth in Section 3 below, and any additional terms You may choose to
+offer under Section 6. You must continue to make the Source Code of
+Your Deployed Modifications available for as long as you Deploy the
+Covered Code or twelve (12) months from the date of initial
+Deployment, whichever is longer;
+
+(c) must notify Apple and other third parties of how to obtain Your
+Deployed Modifications by filling out and submitting the required
+information found at
+http://www.apple.com/publicsource/modifications.html; and
+
+(d) if you Deploy Covered Code in object code, executable form only,
+include a prominent notice, in the code itself as well as in related
+documentation, stating that Source Code of the Covered Code is
+available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+ licenses granted to You under this License:
+
+(a) You hereby grant to Apple and all third parties a non-exclusive,
+royalty-free license, under Your Applicable Patents and other
+intellectual property rights owned or controlled by You, to use,
+reproduce, modify, distribute and Deploy Your Modifications of the
+same scope and extent as Apple's licenses under Sections 2.1 and 2.2;
+and
+
+(b) You hereby grant to Apple and its subsidiaries a non-exclusive,
+worldwide, royalty-free, perpetual and irrevocable license, under Your
+Applicable Patents and other intellectual property rights owned or
+controlled by You, to use, reproduce, execute, compile, display,
+perform, modify or have modified (for Apple and/or its subsidiaries),
+sublicense and distribute Your Modifications, in any form, through
+multiple tiers of distribution.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+ Code with other code not governed by the terms of this License and
+ distribute the Larger Work as a single product. In each such
+ instance, You must make sure the requirements of this License are
+ fulfilled for the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+ Section 2, no other patent rights, express or implied, are granted
+ by Apple herein. Modifications and/or Larger Works may require
+ additional patent licenses from Apple which Apple may grant in its
+ sole discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee
+ for, warranty, support, indemnity or liability obligations and/or
+ other rights consistent with the scope of the license granted herein
+ ("Additional Terms") to one or more recipients of Covered
+ Code. However, You may do so only on Your own behalf and as Your
+ sole responsibility, and not on behalf of Apple. You must obtain the
+ recipient's agreement that any such Additional Terms are offered by
+ You alone, and You hereby agree to indemnify, defend and hold Apple
+ harmless for any liability incurred by or claims asserted against
+ Apple by reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+ versions of this License from time to time. Each version will be
+ given a distinguishing version number. Once Original Code has been
+ published under a particular version of this License, You may
+ continue to use it under the terms of that version. You may also
+ choose to use such Original Code under the terms of any subsequent
+ version of this License published by Apple. No one other than Apple
+ has the right to modify the terms applicable to Covered Code created
+ under this License.
+
+8. NO WARRANTY OR SUPPORT. The Original Code may contain in whole or
+ in part pre-release, untested, or not fully tested works. The
+ Original Code may contain errors that could cause failures or loss
+ of data, and may be incomplete or contain inaccuracies. You
+ expressly acknowledge and agree that use of the Original Code, or
+ any portion thereof, is at Your sole and entire risk. THE ORIGINAL
+ CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT
+ OF ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF
+ SECTIONS 8 AND 9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY
+ REFERRED TO AS "APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR
+ CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY OR
+ SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE DOES NOT WARRANT THAT
+ THE FUNCTIONS CONTAINED IN THE ORIGINAL CODE WILL MEET YOUR
+ REQUIREMENTS, OR THAT THE OPERATION OF THE ORIGINAL CODE WILL BE
+ UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE ORIGINAL CODE
+ WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN
+ BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE SHALL CREATE A
+ WARRANTY OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY. You
+ acknowledge that the Original Code is not intended for use in the
+ operation of nuclear facilities, aircraft navigation, communication
+ systems, or air traffic control machines in which case the failure
+ of the Original Code could lead to death, personal injury, or severe
+ physical or environmental damage.
+
+9. Liability.
+
+9.1 Infringement. If any of the Original Code becomes the subject of
+ a claim of infringement ("Affected Original Code"), Apple may, at
+ its sole discretion and option: (a) attempt to procure the rights
+ necessary for You to continue using the Affected Original Code; (b)
+ modify the Affected Original Code so that it is no longer
+ infringing; or (c) terminate Your rights to use the Affected
+ Original Code, effective immediately upon Apple's posting of a
+ notice to such effect on the Apple web site that is used for
+ implementation of this License.
+
+9.2 LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES SHALL APPLE BE
+ LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR
+ INABILITY TO USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER
+ UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE),
+ PRODUCTS LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF
+ ESSENTIAL PURPOSE OF ANY REMEDY. In no event shall Apple's total
+ liability to You for all damages under this License exceed the
+ amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+ trademarks or trade names "Apple", "Apple Computer", "Mac OS X",
+ "Mac OS X Server" or any other trademarks or trade names belonging
+ to Apple (collectively "Apple Marks") and no Apple Marks may be
+ used to endorse or promote products derived from the Original Code
+ other than as permitted by and in strict compliance at all times
+ with Apple's third party trademark usage guidelines which are
+ posted at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Apple retains all rights, title and interest in and to
+ the Original Code and any Modifications made by or on behalf of
+ Apple ("Apple Modifications"), and such Apple Modifications will
+ not be automatically subject to this License. Apple may, at its
+ sole discretion, choose to license such Apple Modifications under
+ this License, or on different terms from those contained in this
+ License or may choose not to license them at all. Apple's
+ development, use, reproduction, modification, sublicensing and
+ distribution of Covered Code will not be subject to this License.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+ terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach; (b) immediately in the event of
+the circumstances described in Sections 9.1 and/or 13.6(b); or (c)
+automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement
+against Apple.
+
+12.2 Effect of Termination. Upon termination, You agree to
+ immediately stop any further use, reproduction, modification and
+ distribution of the Covered Code, or Affected Original Code in the
+ case of termination under Section 9.1, and to destroy all copies of
+ the Covered Code or Affected Original Code (in the case of
+ termination under Section 9.1) that are in your possession or
+ control. All sublicenses to the Covered Code which have been
+ properly granted prior to termination shall survive any termination
+ of this License. Provisions which, by their nature, should remain
+ in effect beyond the termination of this License shall survive,
+ including but not limited to Sections 3, 5, 8, 9, 10, 11, 12.2 and
+ 13. Neither party will be liable to the other for compensation,
+ indemnity or damages of any sort solely as a result of terminating
+ this License in accordance with its terms, and termination of this
+ License will be without prejudice to any other right or remedy of
+ either party.
+
+13. Miscellaneous.
+
+13.1 Export Law Assurances. You may not use or otherwise export or
+ re-export the Original Code except as authorized by United States
+ law and the laws of the jurisdiction in which the Original Code was
+ obtained. In particular, but without limitation, the Original Code
+ may not be exported or re-exported (a) into (or to a national or
+ resident of) any U.S. embargoed country or (b) to anyone on the
+ U.S. Treasury Department's list of Specially Designated Nationals
+ or the U.S. Department of Commerce's Table of Denial Orders. By
+ using the Original Code, You represent and warrant that You are not
+ located in, under control of, or a national or resident of any such
+ country or on any such list.
+
+13.2 Government End Users. The Covered Code is a "commercial item" as
+ defined in FAR 2.101. Government software and technical data
+ rights in the Covered Code include only those rights customarily
+ provided to the public as defined in this License. This customary
+ commercial license in technical data and software is provided in
+ accordance with FAR 12.211 (Technical Data) and 12.212 (Computer
+ Software) and, for Department of Defense purchases, DFAR
+ 252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3
+ (Rights in Commercial Computer Software or Computer Software
+ Documentation). Accordingly, all U.S. Government End Users acquire
+ Covered Code with only those rights set forth herein.
+
+13.3 Relationship of Parties. This License will not be construed as
+ creating an agency, partnership, joint venture or any other form of
+ legal association between You and Apple, and You will not represent
+ to the contrary, whether expressly, by implication, appearance or
+ otherwise.
+
+13.4 Independent Development. Nothing in this License will impair
+ Apple's right to acquire, license, develop, have others develop for
+ it, market and/or distribute technology or products that perform
+ the same or similar functions as, or otherwise compete with,
+ Modifications, Larger Works, technology or products that You may
+ develop, produce, market or distribute.
+
+13.5 Waiver; Construction. Failure by Apple to enforce any provision
+ of this License will not be deemed a waiver of future enforcement
+ of that or any other provision. Any law or regulation which
+ provides that the language of a contract shall be construed against
+ the drafter will not apply to this License.
+
+13.6 Severability. (a) If for any reason a court of competent
+ jurisdiction finds any provision of this License, or portion
+ thereof, to be unenforceable, that provision of the License will be
+ enforced to the maximum extent permissible so as to effect the
+ economic benefits and intent of the parties, and the remainder of
+ this License will continue in full force and effect. (b)
+ Notwithstanding the foregoing, if applicable law prohibits or
+ restricts You from fully and/or specifically complying with
+ Sections 2 and/or 3 or prevents the enforceability of either of
+ those Sections, this License will immediately terminate and You
+ must immediately discontinue any use of the Covered Code and
+ destroy all copies of it that are in your possession or control.
+
+13.7 Dispute Resolution. Any litigation or other dispute resolution
+ between You and Apple relating to this License shall take place in
+ the Northern District of California, and You and Apple hereby
+ consent to the personal jurisdiction of, and venue in, the state
+ and federal courts within that District with respect to this
+ License. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly
+ excluded.
+
+13.8 Entire Agreement; Governing Law. This License constitutes the
+ entire agreement between the parties with respect to the subject
+ matter hereof. This License shall be governed by the laws of the
+ United States and the State of California, except that body of
+ California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+Reserved. This file contains Original Code and/or Modifications of
+Original Code as defined in and that are subject to the Apple Public
+Source License Version 1.0 (the 'License'). You may not use this file
+except in compliance with the License. Please obtain a copy of the
+License at http://www.apple.com/publicsource and read it before using
+this file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+License for the specific language governing rights and limitations
+under the License."
diff --git a/remote_cmds/Makefile b/remote_cmds/Makefile
new file mode 100644
index 0000000..7347ea8
--- /dev/null
+++ b/remote_cmds/Makefile
@@ -0,0 +1,12 @@
+Project = remote_cmds
+
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+SubProjects = telnetd.tproj
+else
+SubProjects = \
+ logger.tproj\
+ talk.tproj talkd.tproj telnet.tproj telnetd.tproj tftp.tproj\
+ tftpd.tproj wall.tproj
+endif
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/logger.tproj/Makefile b/remote_cmds/logger.tproj/Makefile
new file mode 100644
index 0000000..002cb56
--- /dev/null
+++ b/remote_cmds/logger.tproj/Makefile
@@ -0,0 +1,11 @@
+Project = logger
+Install_Dir = /usr/bin
+
+CFILES = logger.c
+MANPAGES = logger.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/logger.tproj/logger.1 b/remote_cmds/logger.tproj/logger.1
new file mode 100644
index 0000000..3a942e8
--- /dev/null
+++ b/remote_cmds/logger.tproj/logger.1
@@ -0,0 +1,102 @@
+.\" $OpenBSD: logger.1,v 1.2 1996/06/26 05:35:58 deraadt Exp $
+.\" $NetBSD: logger.1,v 1.4 1994/12/22 06:26:59 jtc Exp $
+.\"
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)logger.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt LOGGER 1
+.Os BSD 4.3
+.Sh NAME
+.Nm logger
+.Nd make entries in the system log
+.Sh SYNOPSIS
+.Nm logger
+.Op Fl is
+.Op Fl f Ar file
+.Op Fl p Ar pri
+.Op Fl t Ar tag
+.Op Ar message ...
+.Sh DESCRIPTION
+.Nm Logger
+provides a shell command interface to the
+.Xr syslog 3
+system log module.
+.Pp
+Options:
+.Pp
+.Bl -tag -width "message"
+.It Fl i
+Log the process id of the logger process
+with each line.
+.It Fl s
+Log the message to standard error, as well as the system log.
+.It Fl f Ar file
+Log the specified file.
+.It Fl p Ar pri
+Enter the message with the specified priority.
+The priority may be specified numerically or as a ``facility.level''
+pair.
+For example, ``\-p local3.info'' logs the message(s) as
+.Ar info Ns rmational
+level in the
+.Ar local3
+facility.
+The default is ``user.notice.''
+.It Fl t Ar tag
+Mark every line in the log with the specified
+.Ar tag .
+.It Ar message
+Write the message to log; if not specified, and the
+.Fl f
+flag is not
+provided, standard input is logged.
+.El
+.Pp
+The
+.Nm logger
+utility exits 0 on success, and >0 if an error occurs.
+.Sh EXAMPLES
+.Bd -literal -offset indent -compact
+logger System rebooted
+
+logger \-p local0.notice \-t HOSTIDM \-f /dev/idmc
+.Ed
+.Sh SEE ALSO
+.Xr syslog 3 ,
+.Xr syslogd 8
+.Sh STANDARDS
+The
+.Nm logger
+utility conforms to
+.St -p1003.2-92 .
diff --git a/remote_cmds/logger.tproj/logger.c b/remote_cmds/logger.tproj/logger.c
new file mode 100644
index 0000000..e3d9203
--- /dev/null
+++ b/remote_cmds/logger.tproj/logger.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)logger.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/logger/logger.c,v 1.17 2008/02/05 17:34:44 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define SYSLOG_NAMES
+#include <syslog.h>
+
+int decode(char *, CODE *);
+int pencode(char *);
+#ifndef __APPLE__
+static void logmessage(int, const char *, const char *, const char *);
+#endif
+static void usage(void);
+
+struct socks {
+ int sock;
+ int addrlen;
+ struct sockaddr_storage addr;
+};
+
+#ifdef INET6
+int family = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
+#else
+int family = PF_INET; /* protocol family (IPv4 only) */
+#endif
+int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */
+
+/*
+ * logger -- read and log utility
+ *
+ * Reads from an input and arranges to write the result on the system
+ * log.
+ */
+int
+main(int argc, char *argv[])
+{
+ int ch, logflags, pri;
+ char *tag, *host, buf[1024];
+ const char *svcname;
+
+ tag = NULL;
+ host = NULL;
+ svcname = "syslog";
+ pri = LOG_USER | LOG_NOTICE;
+ logflags = 0;
+ unsetenv("TZ");
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "f:ip:st:")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "46Af:h:iP:p:st:")) != -1)
+#endif
+ switch((char)ch) {
+#ifndef __APPLE__
+ case '4':
+ family = PF_INET;
+ break;
+#ifdef INET6
+ case '6':
+ family = PF_INET6;
+ break;
+#endif
+ case 'A':
+ send_to_all++;
+ break;
+#endif /* __APPLE__ */
+ case 'f': /* file to log */
+ if (freopen(optarg, "r", stdin) == NULL)
+ err(1, "%s", optarg);
+ break;
+#ifndef __APPLE__
+ case 'h': /* hostname to deliver to */
+ host = optarg;
+ break;
+#endif /* __APPLE__ */
+ case 'i': /* log process id also */
+ logflags |= LOG_PID;
+ break;
+#ifndef __APPLE__
+ case 'P': /* service name or port number */
+ svcname = optarg;
+ break;
+#endif /* __APPLE__ */
+ case 'p': /* priority */
+ pri = pencode(optarg);
+ break;
+ case 's': /* log to standard error */
+ logflags |= LOG_PERROR;
+ break;
+ case 't': /* tag */
+ tag = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* setup for logging */
+ openlog(tag ? tag : getlogin(), logflags, 0);
+ (void) fclose(stdout);
+
+ /* log input line if appropriate */
+ if (argc > 0) {
+ char *p, *endp;
+ size_t len;
+
+ for (p = buf, endp = buf + sizeof(buf) - 2; *argv;) {
+ len = strlen(*argv);
+ if (p + len > endp && p > buf) {
+#ifdef __APPLE__
+ syslog(pri, "%s", buf);
+#else
+ logmessage(pri, host, svcname, buf);
+#endif
+ p = buf;
+ }
+ if (len > sizeof(buf) - 1)
+#ifdef __APPLE__
+ syslog(pri, "%s", *argv++);
+#else
+ logmessage(pri, host, svcname, *argv++);
+#endif
+ else {
+ if (p != buf)
+ *p++ = ' ';
+ bcopy(*argv++, p, len);
+ *(p += len) = '\0';
+ }
+ }
+ if (p != buf)
+#ifdef __APPLE__
+ syslog(pri, "%s", buf);
+#else
+ logmessage(pri, host, svcname, buf);
+#endif
+ } else
+ while (fgets(buf, sizeof(buf), stdin) != NULL)
+#ifdef __APPLE__
+ syslog(pri, "%s", buf);
+#else
+ logmessage(pri, host, svcname, buf);
+#endif
+ exit(0);
+}
+
+#ifndef __APPLE__
+/*
+ * Send the message to syslog, either on the local host, or on a remote host
+ */
+void
+logmessage(int pri, const char *host, const char *svcname, const char *buf)
+{
+ static struct socks *socks;
+ static int nsock = 0;
+ struct addrinfo hints, *res, *r;
+ char *line;
+ int maxs, len, sock, error, i, lsent;
+
+ if (host == NULL) {
+ syslog(pri, "%s", buf);
+ return;
+ }
+
+ if (nsock <= 0) { /* set up socket stuff */
+ /* resolve hostname */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_DGRAM;
+ error = getaddrinfo(host, svcname, &hints, &res);
+ if (error == EAI_SERVICE) {
+ warnx("%s/udp: unknown service", svcname);
+ error = getaddrinfo(host, "514", &hints, &res);
+ }
+ if (error)
+ errx(1, "%s: %s", gai_strerror(error), host);
+ /* count max number of sockets we may open */
+ for (maxs = 0, r = res; r; r = r->ai_next, maxs++);
+ socks = malloc(maxs * sizeof(struct socks));
+ if (!socks)
+ errx(1, "couldn't allocate memory for sockets");
+ for (r = res; r; r = r->ai_next) {
+ sock = socket(r->ai_family, r->ai_socktype,
+ r->ai_protocol);
+ if (sock < 0)
+ continue;
+ memcpy(&socks[nsock].addr, r->ai_addr, r->ai_addrlen);
+ socks[nsock].addrlen = r->ai_addrlen;
+ socks[nsock++].sock = sock;
+ }
+ freeaddrinfo(res);
+ if (nsock <= 0)
+ errx(1, "socket");
+ }
+
+ if ((len = asprintf(&line, "<%d>%s", pri, buf)) == -1)
+ errx(1, "asprintf");
+
+ lsent = -1;
+ for (i = 0; i < nsock; ++i) {
+ lsent = sendto(socks[i].sock, line, len, 0,
+ (struct sockaddr *)&socks[i].addr,
+ socks[i].addrlen);
+ if (lsent == len && !send_to_all)
+ break;
+ }
+ if (lsent != len) {
+ if (lsent == -1)
+ warn ("sendto");
+ else
+ warnx ("sendto: short send - %d bytes", lsent);
+ }
+
+ free(line);
+}
+#endif /* __APPLE__ */
+
+/*
+ * Decode a symbolic name to a numeric value
+ */
+int
+pencode(char *s)
+{
+ char *save;
+ int fac, lev;
+
+ for (save = s; *s && *s != '.'; ++s);
+ if (*s) {
+ *s = '\0';
+ fac = decode(save, facilitynames);
+ if (fac < 0)
+ errx(1, "unknown facility name: %s", save);
+ *s++ = '.';
+ }
+ else {
+ fac = 0;
+ s = save;
+ }
+ lev = decode(s, prioritynames);
+ if (lev < 0)
+ errx(1, "unknown priority name: %s", save);
+ return ((lev & LOG_PRIMASK) | (fac & LOG_FACMASK));
+}
+
+int
+decode(char *name, CODE *codetab)
+{
+ CODE *c;
+
+ if (isdigit(*name))
+ return (atoi(name));
+
+ for (c = codetab; c->c_name; c++)
+ if (!strcasecmp(name, c->c_name))
+ return (c->c_val);
+
+ return (-1);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: %s\n",
+#ifdef __APPLE__
+ "logger [-is] [-f file] [-p pri] [-t tag]\n"
+#else
+ "logger [-46Ais] [-f file] [-h host] [-P port] [-p pri] [-t tag]\n"
+#endif
+ " [message ...]"
+ );
+ exit(1);
+}
diff --git a/remote_cmds/talk.tproj/Makefile b/remote_cmds/talk.tproj/Makefile
new file mode 100644
index 0000000..47e3631
--- /dev/null
+++ b/remote_cmds/talk.tproj/Makefile
@@ -0,0 +1,14 @@
+Project = talk
+Install_Dir = /usr/bin
+
+HFILES = talk.h talk_ctl.h
+CFILES = ctl.c ctl_transact.c display.c get_addrs.c get_names.c\
+ get_iface.c init_disp.c invite.c io.c look_up.c msgs.c talk.c
+MANPAGES = talk.1
+
+Extra_CC_Flags = -Wall -Werror -fPIE
+Extra_LD_Flags = -dead_strip -pie
+
+Extra_LD_Libraries = -lcurses
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/talk.tproj/ctl.c b/remote_cmds/talk.tproj/ctl.c
new file mode 100644
index 0000000..a5b42cc
--- /dev/null
+++ b/remote_cmds/talk.tproj/ctl.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/ctl.c,v 1.10 2005/02/09 09:13:36 stefanf Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)ctl.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * This file handles haggling with the various talk daemons to
+ * get a socket to talk to. sockt is opened and connected in
+ * the progress
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <string.h>
+
+#include "talk.h"
+
+struct sockaddr_in daemon_addr = { sizeof(daemon_addr), AF_INET };
+struct sockaddr_in ctl_addr = { sizeof(ctl_addr), AF_INET };
+struct sockaddr_in my_addr = { sizeof(my_addr), AF_INET };
+
+ /* inet addresses of the two machines */
+struct in_addr my_machine_addr;
+struct in_addr his_machine_addr;
+
+u_short daemon_port; /* port number of the talk daemon */
+
+int ctl_sockt;
+int sockt;
+int invitation_waiting = 0;
+
+CTL_MSG msg;
+
+void
+open_sockt()
+{
+ socklen_t length;
+
+ (void)memset(&my_addr, 0, sizeof(my_addr));
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_len = sizeof(my_addr);
+ my_addr.sin_addr = my_machine_addr;
+ my_addr.sin_port = 0;
+ sockt = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockt == -1)
+ p_error("Bad socket");
+ if (bind(sockt, (struct sockaddr *)&my_addr, sizeof(my_addr)) != 0)
+ p_error("Binding local socket");
+ length = sizeof(my_addr);
+ if (getsockname(sockt, (struct sockaddr *)&my_addr, &length) == -1)
+ p_error("Bad address for socket");
+}
+
+/* open the ctl socket */
+void
+open_ctl()
+{
+ socklen_t length;
+
+ (void)memset(&ctl_addr, 0, sizeof(ctl_addr));
+ ctl_addr.sin_family = AF_INET;
+ ctl_addr.sin_len = sizeof(my_addr);
+ ctl_addr.sin_port = 0;
+ ctl_addr.sin_addr = my_machine_addr;
+ ctl_sockt = socket(AF_INET, SOCK_DGRAM, 0);
+ if (ctl_sockt == -1)
+ p_error("Bad socket");
+ if (bind(ctl_sockt,
+ (struct sockaddr *)&ctl_addr, sizeof(ctl_addr)) != 0)
+ p_error("Couldn't bind to control socket");
+ length = sizeof(ctl_addr);
+ if (getsockname(ctl_sockt,
+ (struct sockaddr *)&ctl_addr, &length) == -1)
+ p_error("Bad address for ctl socket");
+}
+
+/* print_addr is a debug print routine */
+void
+print_addr(addr)
+ struct sockaddr_in addr;
+{
+ int i;
+
+ printf("addr = %lx, port = %o, family = %o zero = ",
+ (u_long)addr.sin_addr.s_addr, addr.sin_port, addr.sin_family);
+ for (i = 0; i<8;i++)
+ printf("%o ", (int)addr.sin_zero[i]);
+ putchar('\n');
+}
diff --git a/remote_cmds/talk.tproj/ctl_transact.c b/remote_cmds/talk.tproj/ctl_transact.c
new file mode 100644
index 0000000..1679250
--- /dev/null
+++ b/remote_cmds/talk.tproj/ctl_transact.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifdef __APPLE__
+#include <sys/time.h>
+#endif
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/ctl_transact.c,v 1.7 2002/02/18 20:35:26 mike Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)ctl_transact.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "talk.h"
+#include "talk_ctl.h"
+
+#define CTL_WAIT 2 /* time to wait for a response, in seconds */
+
+/*
+ * SOCKDGRAM is unreliable, so we must repeat messages if we have
+ * not recieved an acknowledgement within a reasonable amount
+ * of time
+ */
+void
+ctl_transact(target, lmsg, type, rp)
+ struct in_addr target;
+ CTL_MSG lmsg;
+ int type;
+ CTL_RESPONSE *rp;
+{
+ fd_set read_mask, ctl_mask;
+ int nready = 0, cc;
+ struct timeval wait;
+
+ lmsg.type = type;
+ daemon_addr.sin_addr = target;
+ daemon_addr.sin_port = daemon_port;
+ FD_ZERO(&ctl_mask);
+ FD_SET(ctl_sockt, &ctl_mask);
+
+ /*
+ * Keep sending the message until a response of
+ * the proper type is obtained.
+ */
+ do {
+ wait.tv_sec = CTL_WAIT;
+ wait.tv_usec = 0;
+ /* resend message until a response is obtained */
+ do {
+ cc = sendto(ctl_sockt, (char *)&lmsg, sizeof (lmsg), 0,
+ (struct sockaddr *)&daemon_addr,
+ sizeof (daemon_addr));
+ if (cc != sizeof (lmsg)) {
+ if (errno == EINTR)
+ continue;
+ p_error("Error on write to talk daemon");
+ }
+ read_mask = ctl_mask;
+ nready = select(ctl_sockt + 1, &read_mask, 0, 0, &wait);
+ if (nready < 0) {
+ if (errno == EINTR)
+ continue;
+ p_error("Error waiting for daemon response");
+ }
+ } while (nready == 0);
+ /*
+ * Keep reading while there are queued messages
+ * (this is not necessary, it just saves extra
+ * request/acknowledgements being sent)
+ */
+ do {
+ cc = recv(ctl_sockt, (char *)rp, sizeof (*rp), 0);
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ p_error("Error on read from talk daemon");
+ }
+ read_mask = ctl_mask;
+ /* an immediate poll */
+ timerclear(&wait);
+ nready = select(ctl_sockt + 1, &read_mask, 0, 0, &wait);
+ } while (nready > 0 && (rp->vers != TALK_VERSION ||
+ rp->type != type));
+ } while (rp->vers != TALK_VERSION || rp->type != type);
+ rp->id_num = ntohl(rp->id_num);
+ rp->addr.sa_family = ntohs(rp->addr.sa_family);
+}
diff --git a/remote_cmds/talk.tproj/display.c b/remote_cmds/talk.tproj/display.c
new file mode 100644
index 0000000..2815ec1
--- /dev/null
+++ b/remote_cmds/talk.tproj/display.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/display.c,v 1.11 2003/07/04 20:44:25 luigi Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * The window 'manager', initializes curses and handles the actual
+ * displaying of text
+ */
+#include <ctype.h>
+
+#include "talk.h"
+
+xwin_t my_win;
+xwin_t his_win;
+WINDOW *line_win;
+
+int curses_initialized = 0;
+
+/*
+ * max HAS to be a function, it is called with
+ * an argument of the form --foo at least once.
+ */
+int
+max(a,b)
+ int a, b;
+{
+
+ return (a > b ? a : b);
+}
+
+/*
+ * Display some text on somebody's window, processing some control
+ * characters while we are at it.
+ */
+void
+display(win, text, size)
+ xwin_t *win;
+ char *text;
+ int size;
+{
+ int i;
+ char cch;
+
+ for (i = 0; i < size; i++) {
+ if (*text == '\n' || *text == '\r') {
+ waddch(win->x_win, '\n');
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ continue;
+ }
+ if (*text == 004 && win == &my_win) {
+ /* control-D clears the screen */
+ werase(my_win.x_win);
+ getyx(my_win.x_win, my_win.x_line, my_win.x_col);
+ wrefresh(my_win.x_win);
+ werase(his_win.x_win);
+ getyx(his_win.x_win, his_win.x_line, his_win.x_col);
+ wrefresh(his_win.x_win);
+ text++;
+ continue;
+ }
+
+ /* erase character */
+ if ( *text == win->cerase
+ || *text == 010 /* BS */
+ || *text == 0177 /* DEL */
+ ) {
+ wmove(win->x_win, win->x_line, max(--win->x_col, 0));
+ getyx(win->x_win, win->x_line, win->x_col);
+ waddch(win->x_win, ' ');
+ wmove(win->x_win, win->x_line, win->x_col);
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ continue;
+ }
+ /*
+ * On word erase search backwards until we find
+ * the beginning of a word or the beginning of
+ * the line.
+ */
+ if ( *text == win->werase
+ || *text == 027 /* ^W */
+ ) {
+ int endcol, xcol, ii, c;
+
+ endcol = win->x_col;
+ xcol = endcol - 1;
+ while (xcol >= 0) {
+ c = readwin(win->x_win, win->x_line, xcol);
+ if (c != ' ')
+ break;
+ xcol--;
+ }
+ while (xcol >= 0) {
+ c = readwin(win->x_win, win->x_line, xcol);
+ if (c == ' ')
+ break;
+ xcol--;
+ }
+ wmove(win->x_win, win->x_line, xcol + 1);
+ for (ii = xcol + 1; ii < endcol; ii++)
+ waddch(win->x_win, ' ');
+ wmove(win->x_win, win->x_line, xcol + 1);
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ continue;
+ }
+ /* line kill */
+ if ( *text == win->kill
+ || *text == 025 /* ^U */
+ ) {
+ wmove(win->x_win, win->x_line, 0);
+ wclrtoeol(win->x_win);
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ continue;
+ }
+ if (*text == '\f') {
+ if (win == &my_win)
+ wrefresh(curscr);
+ text++;
+ continue;
+ }
+ if (*text == '\7') {
+ write(STDOUT_FILENO, text, 1);
+ text++;
+ continue;
+ }
+ if (!isprint((unsigned char)*text) && *text != '\t') {
+ waddch(win->x_win, '^');
+ getyx(win->x_win, win->x_line, win->x_col);
+ cch = (*text & 63) + 64;
+ waddch(win->x_win, cch);
+ } else
+ waddch(win->x_win, (unsigned char)*text);
+ getyx(win->x_win, win->x_line, win->x_col);
+ text++;
+ }
+ wrefresh(win->x_win);
+}
+
+/*
+ * Read the character at the indicated position in win
+ */
+int
+readwin(win, line, col)
+ WINDOW *win;
+ int line;
+ int col;
+{
+ int oldline, oldcol;
+ int c;
+
+ getyx(win, oldline, oldcol);
+ wmove(win, line, col);
+ c = winch(win);
+ wmove(win, oldline, oldcol);
+ return (c);
+}
diff --git a/remote_cmds/talk.tproj/get_addrs.c b/remote_cmds/talk.tproj/get_addrs.c
new file mode 100644
index 0000000..e5a71ac
--- /dev/null
+++ b/remote_cmds/talk.tproj/get_addrs.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/get_addrs.c,v 1.5 2001/12/11 23:51:14 markm Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)get_addrs.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <err.h>
+#include <netdb.h>
+#include <string.h>
+
+#include "talk.h"
+#include "talk_ctl.h"
+
+void
+get_addrs(my_machine_name, his_machine_name)
+ char *my_machine_name __unused, *his_machine_name;
+{
+ struct hostent *hp;
+ struct servent *sp;
+
+ msg.pid = htonl(getpid());
+
+ hp = gethostbyname(his_machine_name);
+ if (hp == NULL)
+ errx(1, "%s: %s", his_machine_name, hstrerror(h_errno));
+ bcopy(hp->h_addr, (char *) &his_machine_addr, hp->h_length);
+ if (get_iface(&his_machine_addr, &my_machine_addr) == -1)
+ err(1, "failed to find my interface address");
+ /* find the server's port */
+ sp = getservbyname("ntalk", "udp");
+ if (sp == 0)
+ errx(1, "ntalk/udp: service is not registered");
+ daemon_port = sp->s_port;
+}
diff --git a/remote_cmds/talk.tproj/get_iface.c b/remote_cmds/talk.tproj/get_iface.c
new file mode 100644
index 0000000..79b7d30
--- /dev/null
+++ b/remote_cmds/talk.tproj/get_iface.c
@@ -0,0 +1,103 @@
+/*
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/get_iface.c,v 1.10 2005/03/11 14:17:12 stefanf Exp $");
+#endif
+
+/*
+ * From:
+ * Id: find_interface.c,v 1.1 1995/08/14 16:08:39 wollman Exp
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "talk.h"
+
+/*
+ * Try to find the interface address that is used to route an IP
+ * packet to a remote peer.
+ */
+
+int
+get_iface(dst, iface)
+ struct in_addr *dst;
+ struct in_addr *iface;
+{
+ static struct sockaddr_in local;
+ struct sockaddr_in remote;
+ socklen_t namelen;
+ int s, rv;
+
+ memcpy(&remote.sin_addr, dst, 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)
+ return -1;
+
+ 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) {
+ close(s);
+ return -1;
+ }
+
+ 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) {
+ close(s);
+ return -1;
+ }
+
+ namelen = sizeof local;
+ rv = getsockname(s, (struct sockaddr *)&local, &namelen);
+ close(s);
+ if (rv < 0)
+ return -1;
+
+ memcpy(iface, &local.sin_addr, sizeof local.sin_addr);
+ return 0;
+}
diff --git a/remote_cmds/talk.tproj/get_names.c b/remote_cmds/talk.tproj/get_names.c
new file mode 100644
index 0000000..24acab1
--- /dev/null
+++ b/remote_cmds/talk.tproj/get_names.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/get_names.c,v 1.9 2004/06/14 22:34:13 bms Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)get_names.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "talk.h"
+
+extern CTL_MSG msg;
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: talk person [ttyname]\n");
+ exit(1);
+}
+
+/*
+ * Determine the local and remote user, tty, and machines
+ */
+void
+get_names(argc, argv)
+ int argc;
+ char *argv[];
+{
+ char hostname[MAXHOSTNAMELEN];
+ char *his_name, *my_name;
+ char *my_machine_name, *his_machine_name;
+ const char *his_tty;
+ char *cp;
+
+ if (argc < 2 )
+ usage();
+ if (!isatty(0))
+ errx(1, "standard input must be a tty, not a pipe or a file");
+ if ((my_name = getlogin()) == NULL) {
+ struct passwd *pw;
+
+ if ((pw = getpwuid(getuid())) == NULL)
+ errx(1, "you don't exist. Go away");
+ my_name = pw->pw_name;
+ }
+ gethostname(hostname, sizeof (hostname));
+ my_machine_name = hostname;
+ /* check for, and strip out, the machine name of the target */
+ for (cp = argv[1]; *cp && !index("@:!", *cp); cp++)
+ ;
+ if (*cp == '\0') {
+ /* this is a local to local talk */
+ his_name = argv[1];
+ my_machine_name = his_machine_name = "localhost";
+ } else {
+ if (*cp++ == '@') {
+ /* user@host */
+ his_name = argv[1];
+ his_machine_name = cp;
+ } else {
+ /* host!user or host:user */
+ his_name = cp;
+ his_machine_name = argv[1];
+ }
+ *--cp = '\0';
+ }
+ if (argc > 2)
+ his_tty = argv[2]; /* tty name is arg 2 */
+ else
+ his_tty = "";
+ get_addrs(my_machine_name, his_machine_name);
+ /*
+ * Initialize the message template.
+ */
+ msg.vers = TALK_VERSION;
+ msg.addr.sa_family = htons(AF_INET);
+ msg.ctl_addr.sa_family = htons(AF_INET);
+ msg.id_num = htonl(0);
+ strncpy(msg.l_name, my_name, NAME_SIZE);
+ msg.l_name[NAME_SIZE - 1] = '\0';
+ strncpy(msg.r_name, his_name, NAME_SIZE);
+ msg.r_name[NAME_SIZE - 1] = '\0';
+ strncpy(msg.r_tty, his_tty, TTY_SIZE);
+ msg.r_tty[TTY_SIZE - 1] = '\0';
+}
diff --git a/remote_cmds/talk.tproj/init_disp.c b/remote_cmds/talk.tproj/init_disp.c
new file mode 100644
index 0000000..c6a02ef
--- /dev/null
+++ b/remote_cmds/talk.tproj/init_disp.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/init_disp.c,v 1.14 2004/04/19 21:37:28 cognet Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)init_disp.c 8.2 (Berkeley) 2/16/94";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * Initialization code for the display package,
+ * as well as the signal handling routines.
+ */
+
+#include <sys/stat.h>
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif
+
+#include <err.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <termios.h>
+
+#include "talk.h"
+
+extern volatile sig_atomic_t gotwinch;
+
+/*
+ * Make sure the callee can write to the screen
+ */
+void
+check_writeable()
+{
+ char *tty;
+ struct stat sb;
+
+ if ((tty = ttyname(STDERR_FILENO)) == NULL)
+ err(1, "ttyname");
+ if (stat(tty, &sb) < 0)
+ err(1, "%s", tty);
+ if (!(sb.st_mode & S_IWGRP))
+ errx(1, "The callee cannot write to this terminal, use \"mesg y\".");
+}
+
+/*
+ * Set up curses, catch the appropriate signals,
+ * and build the various windows.
+ */
+void
+init_display()
+{
+ struct sigaction sa;
+
+ if (initscr() == NULL)
+ errx(1, "Terminal type unset or lacking necessary features.");
+ (void) sigaction(SIGTSTP, (struct sigaction *)0, &sa);
+ sigaddset(&sa.sa_mask, SIGALRM);
+ (void) sigaction(SIGTSTP, &sa, (struct sigaction *)0);
+ curses_initialized = 1;
+ clear();
+ refresh();
+ noecho();
+ crmode();
+ signal(SIGINT, sig_sent);
+ signal(SIGPIPE, sig_sent);
+ signal(SIGWINCH, sig_winch);
+ /* curses takes care of ^Z */
+ my_win.x_nlines = LINES / 2;
+ my_win.x_ncols = COLS;
+ my_win.x_win = newwin(my_win.x_nlines, my_win.x_ncols, 0, 0);
+ idlok(my_win.x_win, TRUE);
+ scrollok(my_win.x_win, TRUE);
+ wclear(my_win.x_win);
+
+ his_win.x_nlines = LINES / 2 - 1;
+ his_win.x_ncols = COLS;
+ his_win.x_win = newwin(his_win.x_nlines, his_win.x_ncols,
+ my_win.x_nlines+1, 0);
+ idlok(my_win.x_win, TRUE);
+ scrollok(his_win.x_win, TRUE);
+ wclear(his_win.x_win);
+
+ line_win = newwin(1, COLS, my_win.x_nlines, 0);
+#if defined(hline) || defined(whline) || defined(NCURSES_VERSION)
+ whline(line_win, 0, COLS);
+#else
+ box(line_win, '-', '-');
+#endif
+ wrefresh(line_win);
+ /* let them know we are working on it */
+ current_state = "No connection yet";
+}
+
+/*
+ * Trade edit characters with the other talk. By agreement
+ * the first three characters each talk transmits after
+ * connection are the three edit characters.
+ */
+void
+set_edit_chars()
+{
+ char buf[3];
+ int cc;
+ struct termios tio;
+
+ tcgetattr(0, &tio);
+ my_win.cerase = tio.c_cc[VERASE];
+ my_win.kill = tio.c_cc[VKILL];
+ my_win.werase = tio.c_cc[VWERASE];
+ if (my_win.cerase == (char)_POSIX_VDISABLE)
+ my_win.kill = CERASE;
+ if (my_win.kill == (char)_POSIX_VDISABLE)
+ my_win.kill = CKILL;
+ if (my_win.werase == (char)_POSIX_VDISABLE)
+ my_win.werase = CWERASE;
+ buf[0] = my_win.cerase;
+ buf[1] = my_win.kill;
+ buf[2] = my_win.werase;
+ cc = write(sockt, buf, sizeof(buf));
+ if (cc != sizeof(buf) )
+ p_error("Lost the connection");
+ cc = read(sockt, buf, sizeof(buf));
+ if (cc != sizeof(buf) )
+ p_error("Lost the connection");
+ his_win.cerase = buf[0];
+ his_win.kill = buf[1];
+ his_win.werase = buf[2];
+}
+
+/* ARGSUSED */
+void
+sig_sent(signo)
+ int signo __unused;
+{
+
+ message("Connection closing. Exiting");
+ quit();
+}
+
+void
+sig_winch(int dummy)
+{
+
+ gotwinch = 1;
+}
+
+/*
+ * All done talking...hang up the phone and reset terminal thingy's
+ */
+void
+quit()
+{
+
+ if (curses_initialized) {
+ wmove(his_win.x_win, his_win.x_nlines-1, 0);
+ wclrtoeol(his_win.x_win);
+ wrefresh(his_win.x_win);
+ endwin();
+ }
+ if (invitation_waiting)
+ send_delete();
+ exit(0);
+}
+
+/*
+ * If we get SIGWINCH, recompute both window sizes and refresh things.
+ */
+void
+resize_display(void)
+{
+ struct winsize ws;
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0 ||
+ (ws.ws_row == LINES && ws.ws_col == COLS))
+ return;
+
+ /* Update curses' internal state with new window size. */
+ resizeterm(ws.ws_row, ws.ws_col);
+
+ /*
+ * Resize each window but wait to refresh the screen until
+ * everything has been drawn so the cursor is in the right spot.
+ */
+ my_win.x_nlines = LINES / 2;
+ my_win.x_ncols = COLS;
+ wresize(my_win.x_win, my_win.x_nlines, my_win.x_ncols);
+ mvwin(my_win.x_win, 0, 0);
+ clearok(my_win.x_win, TRUE);
+
+ his_win.x_nlines = LINES / 2 - 1;
+ his_win.x_ncols = COLS;
+ wresize(his_win.x_win, his_win.x_nlines, his_win.x_ncols);
+ mvwin(his_win.x_win, my_win.x_nlines + 1, 0);
+ clearok(his_win.x_win, TRUE);
+
+ wresize(line_win, 1, COLS);
+ mvwin(line_win, my_win.x_nlines, 0);
+#if defined(NCURSES_VERSION) || defined(whline)
+ whline(line_win, '-', COLS);
+#else
+ wmove(line_win, my_win.x_nlines, 0);
+ box(line_win, '-', '-');
+#endif
+
+ /* Now redraw the screen. */
+ wrefresh(his_win.x_win);
+ wrefresh(line_win);
+ wrefresh(my_win.x_win);
+}
diff --git a/remote_cmds/talk.tproj/invite.c b/remote_cmds/talk.tproj/invite.c
new file mode 100644
index 0000000..b8562b2
--- /dev/null
+++ b/remote_cmds/talk.tproj/invite.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/invite.c,v 1.9 2003/01/01 18:49:00 schweikh Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)invite.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <protocols/talkd.h>
+
+#include <err.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+
+#include "talk_ctl.h"
+#include "talk.h"
+
+/*
+ * There wasn't an invitation waiting, so send a request containing
+ * our sockt address to the remote talk daemon so it can invite
+ * him
+ */
+
+/*
+ * The msg.id's for the invitations
+ * on the local and remote machines.
+ * These are used to delete the
+ * invitations.
+ */
+int local_id, remote_id;
+jmp_buf invitebuf;
+
+void
+invite_remote()
+{
+ int new_sockt;
+ struct itimerval itimer;
+ CTL_RESPONSE response;
+
+ itimer.it_value.tv_sec = RING_WAIT;
+ itimer.it_value.tv_usec = 0;
+ itimer.it_interval = itimer.it_value;
+ if (listen(sockt, 5) != 0)
+ p_error("Error on attempt to listen for caller");
+#ifdef MSG_EOR
+ /* copy new style sockaddr to old, swap family (short in old) */
+ msg.addr = *(struct osockaddr *)&my_addr; /* XXX new to old style*/
+ msg.addr.sa_family = htons(my_addr.sin_family);
+#else
+ msg.addr = *(struct sockaddr *)&my_addr;
+#endif
+ msg.id_num = htonl(-1); /* an impossible id_num */
+ invitation_waiting = 1;
+ announce_invite();
+ /*
+ * Shut off the automatic messages for a while,
+ * so we can use the interupt timer to resend the invitation
+ */
+ end_msgs();
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+ message("Waiting for your party to respond");
+ signal(SIGALRM, re_invite);
+ (void) setjmp(invitebuf);
+ while ((new_sockt = accept(sockt, 0, 0)) < 0) {
+ if (errno == EINTR)
+ continue;
+ p_error("Unable to connect with your party");
+ }
+ close(sockt);
+ sockt = new_sockt;
+
+ /*
+ * Have the daemons delete the invitations now that we
+ * have connected.
+ */
+ current_state = "Waiting for your party to respond";
+ start_msgs();
+
+ msg.id_num = htonl(local_id);
+ ctl_transact(my_machine_addr, msg, DELETE, &response);
+ msg.id_num = htonl(remote_id);
+ ctl_transact(his_machine_addr, msg, DELETE, &response);
+ invitation_waiting = 0;
+}
+
+/*
+ * Routine called on interupt to re-invite the callee
+ */
+/* ARGSUSED */
+void
+re_invite(signo)
+ int signo __unused;
+{
+
+ message("Ringing your party again");
+ waddch(my_win.x_win, '\n');
+ if (current_line < my_win.x_nlines - 1)
+ current_line++;
+ /* force a re-announce */
+ msg.id_num = htonl(remote_id + 1);
+ announce_invite();
+ longjmp(invitebuf, 1);
+}
+
+static const char *answers[] = {
+ "answer #0", /* SUCCESS */
+ "Your party is not logged on", /* NOT_HERE */
+ "Target machine is too confused to talk to us", /* FAILED */
+ "Target machine does not recognize us", /* MACHINE_UNKNOWN */
+ "Your party is refusing messages", /* PERMISSION_REFUSED */
+ "Target machine can not handle remote talk", /* UNKNOWN_REQUEST */
+ "Target machine indicates protocol mismatch", /* BADVERSION */
+ "Target machine indicates protocol botch (addr)",/* BADADDR */
+ "Target machine indicates protocol botch (ctl_addr)",/* BADCTLADDR */
+};
+#define NANSWERS (sizeof (answers) / sizeof (answers[0]))
+
+/*
+ * Transmit the invitation and process the response
+ */
+void
+announce_invite()
+{
+ CTL_RESPONSE response;
+
+ current_state = "Trying to connect to your party's talk daemon";
+ ctl_transact(his_machine_addr, msg, ANNOUNCE, &response);
+ remote_id = response.id_num;
+ if (response.answer != SUCCESS) {
+ if (response.answer < NANSWERS)
+ message(answers[response.answer]);
+ quit();
+ }
+ /* leave the actual invitation on my talk daemon */
+ current_state = "Trying to connect to local talk daemon";
+ ctl_transact(my_machine_addr, msg, LEAVE_INVITE, &response);
+ local_id = response.id_num;
+}
+
+/*
+ * Tell the daemon to remove your invitation
+ */
+void
+send_delete()
+{
+
+ msg.type = DELETE;
+ /*
+ * This is just an extra clean up, so just send it
+ * and don't wait for an answer
+ */
+ msg.id_num = htonl(remote_id);
+ daemon_addr.sin_addr = his_machine_addr;
+ if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
+ (struct sockaddr *)&daemon_addr,
+ sizeof (daemon_addr)) != sizeof(msg))
+ warn("send_delete (remote)");
+ msg.id_num = htonl(local_id);
+ daemon_addr.sin_addr = my_machine_addr;
+ if (sendto(ctl_sockt, &msg, sizeof (msg), 0,
+ (struct sockaddr *)&daemon_addr,
+ sizeof (daemon_addr)) != sizeof (msg))
+ warn("send_delete (local)");
+}
diff --git a/remote_cmds/talk.tproj/io.c b/remote_cmds/talk.tproj/io.c
new file mode 100644
index 0000000..644c28b
--- /dev/null
+++ b/remote_cmds/talk.tproj/io.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/io.c,v 1.16 2004/05/10 15:52:16 cognet Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)io.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * This file contains the I/O handling and the exchange of
+ * edit characters. This connection itself is established in
+ * ctl.c
+ */
+
+#include <sys/filio.h>
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif
+
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "talk.h"
+#include "talk_ctl.h"
+
+#define A_LONG_TIME 10000000
+
+volatile sig_atomic_t gotwinch = 0;
+
+/*
+ * The routine to do the actual talking
+ */
+void
+talk()
+{
+ struct hostent *hp, *hp2;
+ int nb;
+ fd_set read_set, read_template;
+ char buf[BUFSIZ], **addr, *his_machine_name;
+ struct timeval wait;
+
+ his_machine_name = NULL;
+ hp = gethostbyaddr((const char *)&his_machine_addr.s_addr,
+ sizeof(his_machine_addr.s_addr), AF_INET);
+ if (hp != NULL) {
+ hp2 = gethostbyname(hp->h_name);
+ if (hp2 != NULL && hp2->h_addrtype == AF_INET &&
+ hp2->h_length == sizeof(his_machine_addr))
+ for (addr = hp2->h_addr_list; *addr != NULL; addr++)
+ if (memcmp(*addr, &his_machine_addr,
+ sizeof(his_machine_addr)) == 0) {
+ his_machine_name = strdup(hp->h_name);
+ break;
+ }
+ }
+ if (his_machine_name == NULL)
+ his_machine_name = strdup(inet_ntoa(his_machine_addr));
+ snprintf(buf, sizeof(buf), "Connection established with %s@%s.",
+ msg.r_name, his_machine_name);
+ free(his_machine_name);
+ message(buf);
+ write(STDOUT_FILENO, "\007\007\007", 3);
+
+ current_line = 0;
+
+ /*
+ * Wait on both the other process (sockt_mask) and
+ * standard input ( STDIN_MASK )
+ */
+ FD_ZERO(&read_template);
+ FD_SET(sockt, &read_template);
+ FD_SET(fileno(stdin), &read_template);
+ for (;;) {
+ read_set = read_template;
+ wait.tv_sec = A_LONG_TIME;
+ wait.tv_usec = 0;
+ nb = select(sockt + 1, &read_set, 0, 0, &wait);
+ if (gotwinch) {
+ resize_display();
+ gotwinch = 0;
+ }
+ if (nb <= 0) {
+ if (errno == EINTR) {
+ read_set = read_template;
+ continue;
+ }
+ /* panic, we don't know what happened */
+ p_error("Unexpected error from select");
+ quit();
+ }
+ if (FD_ISSET(sockt, &read_set)) {
+ /* There is data on sockt */
+ nb = read(sockt, buf, sizeof buf);
+ if (nb <= 0) {
+ message("Connection closed. Exiting");
+ quit();
+ }
+ display(&his_win, buf, nb);
+ }
+ if (FD_ISSET(fileno(stdin), &read_set)) {
+ /*
+ * We can't make the tty non_blocking, because
+ * curses's output routines would screw up
+ */
+ int i;
+ ioctl(0, FIONREAD, (void *) &nb);
+ if (nb > sizeof buf)
+ nb = sizeof buf;
+ nb = read(STDIN_FILENO, buf, nb);
+ display(&my_win, buf, nb);
+ /* might lose data here because sockt is non-blocking */
+ for (i = 0; i < nb; ++i)
+ if (buf[i] == '\r')
+ buf[i] = '\n';
+ write(sockt, buf, nb);
+ }
+ }
+}
+
+/*
+ * p_error prints the system error message on the standard location
+ * on the screen and then exits. (i.e. a curses version of perror)
+ */
+void
+p_error(string)
+ const char *string;
+{
+ wmove(my_win.x_win, current_line, 0);
+ wprintw(my_win.x_win, "[%s : %s (%d)]\n",
+ string, strerror(errno), errno);
+ wrefresh(my_win.x_win);
+ move(LINES-1, 0);
+ refresh();
+ quit();
+}
+
+/*
+ * Display string in the standard location
+ */
+void
+message(string)
+ const char *string;
+{
+ wmove(my_win.x_win, current_line, 0);
+ wprintw(my_win.x_win, "[%s]\n", string);
+ if (current_line < my_win.x_nlines - 1)
+ current_line++;
+ wrefresh(my_win.x_win);
+}
diff --git a/remote_cmds/talk.tproj/look_up.c b/remote_cmds/talk.tproj/look_up.c
new file mode 100644
index 0000000..3fd003f
--- /dev/null
+++ b/remote_cmds/talk.tproj/look_up.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/look_up.c,v 1.8 2005/02/09 09:13:36 stefanf Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)look_up.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <protocols/talkd.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "talk_ctl.h"
+#include "talk.h"
+
+/*
+ * See if the local daemon has an invitation for us.
+ */
+int
+check_local()
+{
+ CTL_RESPONSE response;
+ CTL_RESPONSE *rp = &response;
+ struct sockaddr addr;
+
+ /* the rest of msg was set up in get_names */
+#ifdef MSG_EOR
+ /* copy new style sockaddr to old, swap family (short in old) */
+ msg.ctl_addr = *(struct osockaddr *)&ctl_addr;
+ msg.ctl_addr.sa_family = htons(ctl_addr.sin_family);
+#else
+ msg.ctl_addr = *(struct sockaddr *)&ctl_addr;
+#endif
+ /* must be initiating a talk */
+ if (!look_for_invite(rp))
+ return (0);
+ /*
+ * There was an invitation waiting for us,
+ * so connect with the other (hopefully waiting) party
+ */
+ current_state = "Waiting to connect with caller";
+ do {
+ if (rp->addr.sa_family != AF_INET)
+ p_error("Response uses invalid network address");
+ (void)memcpy(&addr, &rp->addr.sa_family, sizeof(addr));
+ addr.sa_family = rp->addr.sa_family;
+ addr.sa_len = sizeof(addr);
+ errno = 0;
+ if (connect(sockt, &addr, sizeof(addr)) != -1)
+ return (1);
+ } while (errno == EINTR);
+ if (errno == ECONNREFUSED) {
+ /*
+ * The caller gave up, but his invitation somehow
+ * was not cleared. Clear it and initiate an
+ * invitation. (We know there are no newer invitations,
+ * the talkd works LIFO.)
+ */
+ ctl_transact(his_machine_addr, msg, DELETE, rp);
+ close(sockt);
+ open_sockt();
+ return (0);
+ }
+ p_error("Unable to connect with initiator");
+ /*NOTREACHED*/
+ return (0);
+}
+
+/*
+ * Look for an invitation on 'machine'
+ */
+int
+look_for_invite(rp)
+ CTL_RESPONSE *rp;
+{
+ current_state = "Checking for invitation on caller's machine";
+ ctl_transact(his_machine_addr, msg, LOOK_UP, rp);
+ /* the switch is for later options, such as multiple invitations */
+ switch (rp->answer) {
+
+ case SUCCESS:
+ msg.id_num = htonl(rp->id_num);
+ return (1);
+
+ default:
+ /* there wasn't an invitation waiting for us */
+ return (0);
+ }
+}
diff --git a/remote_cmds/talk.tproj/msgs.c b/remote_cmds/talk.tproj/msgs.c
new file mode 100644
index 0000000..f8cb59a
--- /dev/null
+++ b/remote_cmds/talk.tproj/msgs.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/msgs.c,v 1.6 2001/12/11 23:51:14 markm Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+/*
+ * A package to display what is happening every MSG_INTERVAL seconds
+ * if we are slow connecting.
+ */
+
+#include <signal.h>
+
+#include "talk.h"
+
+#define MSG_INTERVAL 4
+
+const char *current_state;
+int current_line = 0;
+
+/* ARGSUSED */
+void
+disp_msg(signo)
+ int signo __unused;
+{
+ message(current_state);
+}
+
+void
+start_msgs()
+{
+ struct itimerval itimer;
+
+ message(current_state);
+ signal(SIGALRM, disp_msg);
+ itimer.it_value.tv_sec = itimer.it_interval.tv_sec = MSG_INTERVAL;
+ itimer.it_value.tv_usec = itimer.it_interval.tv_usec = 0;
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+}
+
+void
+end_msgs()
+{
+ struct itimerval itimer;
+
+ timerclear(&itimer.it_value);
+ timerclear(&itimer.it_interval);
+ setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
+ signal(SIGALRM, SIG_DFL);
+}
diff --git a/remote_cmds/talk.tproj/talk.1 b/remote_cmds/talk.tproj/talk.1
new file mode 100644
index 0000000..bf105bb
--- /dev/null
+++ b/remote_cmds/talk.tproj/talk.1
@@ -0,0 +1,172 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)talk.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/talk/talk.1,v 1.20 2005/02/13 22:25:24 ru Exp $
+.\"
+.Dd August 21, 2008
+.Dt TALK 1
+.Os
+.Sh NAME
+.Nm talk
+.Nd talk to another user
+.Sh SYNOPSIS
+.Nm
+.Ar person
+.Op Ar ttyname
+.Sh DESCRIPTION
+The
+.Nm
+utility is a visual communication program which copies lines from your
+terminal to that of another user.
+.Pp
+Options available:
+.Bl -tag -width ttyname
+.It Ar person
+If you wish to talk to someone on your own machine, then
+.Ar person
+is just the person's login name.
+If you wish to talk to a user on
+another host, then
+.Ar person
+is of the form
+.Ql user@host
+or
+.Ql host!user
+or
+.Ql host:user .
+.It Ar ttyname
+If you wish to talk to a user who is logged in more than once, the
+.Ar ttyname
+argument may be used to indicate the appropriate terminal
+name, where
+.Ar ttyname
+is of the form
+.Ql ttyXX .
+.El
+.Pp
+When first called,
+.Nm
+sends the message
+.Bd -literal -offset indent -compact
+Message from TalkDaemon@his_machine...
+talk: connection requested by your_name@your_machine.
+talk: respond with: talk your_name@your_machine
+.Ed
+.Pp
+to the user you wish to talk to.
+At this point, the recipient
+of the message should reply by typing
+.Pp
+.Dl talk \ your_name@your_machine
+.Pp
+It does not matter from which machine the recipient replies, as
+long as his login-name is the same.
+Once communication is established,
+the two parties may type simultaneously, with their output appearing
+in separate windows.
+Typing control-L
+.Ql ^L
+will cause the screen to
+be reprinted.
+Typing control-D
+.Ql ^D
+will clear both parts of your screen to be cleared, while
+the control-D character will be sent to the remote side
+(and just displayed by this
+.Nm
+client).
+Your erase, kill, and word kill characters will
+behave normally.
+To exit, just type your interrupt character;
+.Nm
+then moves the cursor to the bottom of the screen and restores the
+terminal to its previous state.
+.Pp
+Permission to talk may be denied or granted by use of the
+.Xr mesg 1
+command.
+At the outset talking is allowed.
+.Sh CONFIGURATION
+The
+.Nm
+utility relies on the
+.Nm talkd
+system daemon. See
+.Xr talkd 8
+for information about enabling
+.Nm talkd .
+.Sh FILES
+.Bl -tag -width /var/run/utmpx -compact
+.It Pa /etc/hosts
+to find the recipient's machine
+.It Pa /var/run/utmpx
+to find the recipient's tty
+.El
+.Sh SEE ALSO
+.Xr mail 1 ,
+.Xr mesg 1 ,
+.Xr wall 1 ,
+.Xr who 1 ,
+.Xr write 1 ,
+.Xr talkd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+In
+.Fx 5.3 ,
+the default behaviour of
+.Nm
+was changed to treat local-to-local talk requests as originating
+and terminating at
+.Em localhost .
+Before this change, it was required that the hostname (as per
+.Xr gethostname 3 )
+resolved to a valid IPv4 address (via
+.Xr gethostbyname 3 ) ,
+making
+.Nm
+unsuitable for use in configurations where
+.Xr talkd 8
+was bound to the loopback interface (normally for security reasons).
+.Sh BUGS
+The version of
+.Nm
+released with
+.Bx 4.3
+uses a protocol that
+is incompatible with the protocol used in the version released with
+.Bx 4.2 .
+.Pp
+Multibyte characters are not recognized.
diff --git a/remote_cmds/talk.tproj/talk.c b/remote_cmds/talk.tproj/talk.c
new file mode 100644
index 0000000..d86e770
--- /dev/null
+++ b/remote_cmds/talk.tproj/talk.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/talk/talk.c,v 1.11 2002/08/19 03:07:56 jmallett Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)talk.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* __APPLE__ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#include <locale.h>
+
+#include "talk.h"
+
+/*
+ * talk: A visual form of write. Using sockets, a two way
+ * connection is set up between the two people talking.
+ * With the aid of curses, the screen is split into two
+ * windows, and each users text is added to the window,
+ * one character at a time...
+ *
+ * Written by Kipp Hickman
+ *
+ * Modified to run under 4.1a by Clem Cole and Peter Moore
+ * Modified to run between hosts by Peter Moore, 8/19/82
+ * Modified to run under 4.1c by Peter Moore 3/17/83
+ * Fixed to not run with unwriteable terminals MRVM 28/12/94
+ */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ (void) setlocale(LC_CTYPE, "");
+
+ get_names(argc, argv);
+#ifndef __APPLE__
+ setproctitle("");
+#endif
+ check_writeable();
+ init_display();
+ open_ctl();
+ open_sockt();
+ start_msgs();
+ if (!check_local())
+ invite_remote();
+ end_msgs();
+ set_edit_chars();
+ talk();
+ return 0;
+}
diff --git a/remote_cmds/talk.tproj/talk.h b/remote_cmds/talk.tproj/talk.h
new file mode 100644
index 0000000..7f3bcf4
--- /dev/null
+++ b/remote_cmds/talk.tproj/talk.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)talk.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/talk/talk.h,v 1.5 2004/04/19 21:37:29 cognet Exp $
+ */
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <protocols/talkd.h>
+#include <curses.h>
+#include <unistd.h>
+
+extern int sockt;
+extern int curses_initialized;
+extern int invitation_waiting;
+
+extern const char *current_state;
+extern int current_line;
+
+typedef struct xwin {
+ WINDOW *x_win;
+ int x_nlines;
+ int x_ncols;
+ int x_line;
+ int x_col;
+ char kill;
+ char cerase;
+ char werase;
+} xwin_t;
+
+extern xwin_t my_win;
+extern xwin_t his_win;
+extern WINDOW *line_win;
+
+extern void announce_invite(void);
+extern int check_local(void);
+extern void check_writeable(void);
+extern void ctl_transact(struct in_addr,CTL_MSG,int,CTL_RESPONSE *);
+extern void disp_msg(int);
+extern void display(xwin_t *, char *, int);
+extern void end_msgs(void);
+extern void get_addrs(char *, char *);
+extern int get_iface(struct in_addr *, struct in_addr *);
+extern void get_names(int, char **);
+extern void init_display(void);
+extern void invite_remote(void);
+extern int look_for_invite(CTL_RESPONSE *);
+extern int max(int, int);
+extern void message(const char *);
+extern void open_ctl(void);
+extern void open_sockt(void);
+extern void p_error(const char *);
+extern void print_addr(struct sockaddr_in);
+extern void quit(void);
+extern int readwin(WINDOW *, int, int);
+extern void re_invite(int);
+extern void send_delete(void);
+extern void set_edit_chars(void);
+extern void sig_sent(int);
+extern void sig_winch(int);
+extern void start_msgs(void);
+extern void talk(void);
+extern void resize_display(void);
diff --git a/remote_cmds/talk.tproj/talk_ctl.h b/remote_cmds/talk.tproj/talk_ctl.h
new file mode 100644
index 0000000..91c75d0
--- /dev/null
+++ b/remote_cmds/talk.tproj/talk_ctl.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)talk_ctl.h 8.1 (Berkeley) 6/6/93
+ */
+
+extern struct sockaddr_in daemon_addr;
+extern struct sockaddr_in ctl_addr;
+extern struct sockaddr_in my_addr;
+extern struct in_addr my_machine_addr;
+extern struct in_addr his_machine_addr;
+extern u_short daemon_port;
+extern int ctl_sockt;
+extern CTL_MSG msg;
diff --git a/remote_cmds/talkd.tproj/Makefile b/remote_cmds/talkd.tproj/Makefile
new file mode 100644
index 0000000..f67b40b
--- /dev/null
+++ b/remote_cmds/talkd.tproj/Makefile
@@ -0,0 +1,14 @@
+Project = ntalkd
+Install_Dir = /usr/libexec
+
+HFILES = talkd.h
+CFILES = announce.c print.c process.c table.c talkd.c ../wall.tproj/ttymsg.c
+MANPAGES = ntalkd.8
+LAUNCHD_PLISTS = ntalk.plist
+
+Extra_CC_Flags = -Wall -Werror -fPIE
+Extra_LD_Flags = -dead_strip -pie
+
+Extra_CC_Flags += -D__FBSDID=__RCSID
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/talkd.tproj/announce.c b/remote_cmds/talkd.tproj/announce.c
new file mode 100644
index 0000000..5091513
--- /dev/null
+++ b/remote_cmds/talkd.tproj/announce.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)announce.c 8.3 (Berkeley) 4/28/95";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/announce.c,v 1.16 2003/04/03 05:13:27 jmallett Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+
+#include <protocols/talkd.h>
+
+#include <errno.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <vis.h>
+
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include "ttymsg.h"
+#endif
+#include "extern.h"
+
+extern char hostname[];
+
+/*
+ * Announce an invitation to talk.
+ */
+
+/*
+ * See if the user is accepting messages. If so, announce that
+ * a talk is requested.
+ */
+int
+announce(CTL_MSG *request, const char *remote_machine)
+{
+ char full_tty[32];
+ struct stat stbuf;
+
+ (void)snprintf(full_tty, sizeof(full_tty),
+ "%s%s", _PATH_DEV, request->r_tty);
+ if (stat(full_tty, &stbuf) < 0 || (stbuf.st_mode&020) == 0)
+ return (PERMISSION_DENIED);
+ return (print_mesg(request->r_tty, request, remote_machine));
+}
+
+#define max(a,b) ( (a) > (b) ? (a) : (b) )
+#define N_LINES 5
+#define N_CHARS 256
+
+/*
+ * Build a block of characters containing the message.
+ * It is sent blank filled and in a single block to
+ * try to keep the message in one piece if the recipient
+ * in in vi at the time
+ */
+int
+print_mesg(const char *tty, CTL_MSG *request,
+ const char *remote_machine)
+{
+ struct timeval now;
+ time_t clock_sec;
+ struct timezone zone;
+ struct tm *localclock;
+ struct iovec iovec;
+ char line_buf[N_LINES][N_CHARS];
+ int sizes[N_LINES];
+ char big_buf[N_LINES*N_CHARS];
+ char *bptr, *lptr, *vis_user;
+ int i, j, max_size;
+
+ i = 0;
+ max_size = 0;
+ gettimeofday(&now, &zone);
+ clock_sec = now.tv_sec;
+ localclock = localtime(&clock_sec);
+ (void)snprintf(line_buf[i], N_CHARS, " ");
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+ (void)snprintf(line_buf[i], N_CHARS,
+ "Message from Talk_Daemon@%s at %d:%02d on %d/%.2d/%.2d ...",
+ hostname, localclock->tm_hour , localclock->tm_min,
+ localclock->tm_year + 1900, localclock->tm_mon + 1,
+ localclock->tm_mday);
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+
+ vis_user = malloc(strlen(request->l_name) * 4 + 1);
+ strvis(vis_user, request->l_name, VIS_CSTYLE);
+ (void)snprintf(line_buf[i], N_CHARS,
+ "talk: connection requested by %s@%s", vis_user, remote_machine);
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+ (void)snprintf(line_buf[i], N_CHARS, "talk: respond with: talk %s@%s",
+ vis_user, remote_machine);
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+ (void)snprintf(line_buf[i], N_CHARS, " ");
+ sizes[i] = strlen(line_buf[i]);
+ max_size = max(max_size, sizes[i]);
+ i++;
+ bptr = big_buf;
+ *bptr++ = '\007'; /* send something to wake them up */
+ *bptr++ = '\r'; /* add a \r in case of raw mode */
+ *bptr++ = '\n';
+ for (i = 0; i < N_LINES; i++) {
+ /* copy the line into the big buffer */
+ lptr = line_buf[i];
+ while (*lptr != '\0')
+ *(bptr++) = *(lptr++);
+ /* pad out the rest of the lines with blanks */
+ for (j = sizes[i]; j < max_size + 2; j++)
+ *(bptr++) = ' ';
+ *(bptr++) = '\r'; /* add a \r in case of raw mode */
+ *(bptr++) = '\n';
+ }
+ *bptr = '\0';
+ iovec.iov_base = big_buf;
+ iovec.iov_len = bptr - big_buf;
+ /*
+ * we choose a timeout of RING_WAIT-5 seconds so that we don't
+ * stack up processes trying to write messages to a tty
+ * that is permanently blocked.
+ */
+ if (ttymsg(&iovec, 1, tty, RING_WAIT - 5) != NULL)
+ return (FAILED);
+
+ return (SUCCESS);
+}
diff --git a/remote_cmds/talkd.tproj/extern.h b/remote_cmds/talkd.tproj/extern.h
new file mode 100644
index 0000000..3b73236
--- /dev/null
+++ b/remote_cmds/talkd.tproj/extern.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2002 M. Warner Losh. 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 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.
+ *
+ * $FreeBSD: src/libexec/talkd/extern.h,v 1.3 2003/04/03 05:13:27 jmallett Exp $
+ */
+
+int announce(CTL_MSG *, const char *);
+int delete_invite(u_int32_t);
+void do_announce(CTL_MSG *, CTL_RESPONSE *);
+CTL_MSG *find_match(CTL_MSG *request);
+CTL_MSG *find_request(CTL_MSG *request);
+int find_user(const char *name, char *tty);
+void insert_table(CTL_MSG *, CTL_RESPONSE *);
+int new_id(void);
+int print_mesg(const char *, CTL_MSG *, const char *);
+void print_request(const char *, CTL_MSG *);
+void print_response(const char *, CTL_RESPONSE *);
+void process_request(CTL_MSG *mp, CTL_RESPONSE *rp);
+void timeout(int sig);
diff --git a/remote_cmds/talkd.tproj/ntalk.plist b/remote_cmds/talkd.tproj/ntalk.plist
new file mode 100644
index 0000000..2e63da2
--- /dev/null
+++ b/remote_cmds/talkd.tproj/ntalk.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.ntalkd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/ntalkd</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <true/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>ntalk</string>
+ <key>SockType</key>
+ <string>dgram</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/remote_cmds/talkd.tproj/ntalkd.8 b/remote_cmds/talkd.tproj/ntalkd.8
new file mode 100644
index 0000000..7fe81a5
--- /dev/null
+++ b/remote_cmds/talkd.tproj/ntalkd.8
@@ -0,0 +1,98 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)talkd.8 8.2 (Berkeley) 12/11/93
+.\" $FreeBSD: src/libexec/talkd/talkd.8,v 1.7 2003/09/08 19:57:18 ru Exp $
+.\"
+.Dd August 21, 2008
+.Dt TALKD 8
+.Os
+.Sh NAME
+.Nm talkd
+.Nd remote user communication server
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility
+is the server that notifies a user that someone else wants to
+initiate a conversation.
+It acts as a repository of invitations, responding to requests
+by clients wishing to rendezvous to hold a conversation.
+In normal operation, a client, the caller,
+initiates a rendezvous by sending a
+.Tn CTL_MSG
+to the server of
+type
+.Tn LOOK_UP
+(see
+.In protocols/talkd.h ) .
+This causes the server to search its invitation
+tables to check if an invitation currently exists for the caller
+(to speak to the callee specified in the message).
+.Pp
+If the lookup fails,
+the caller then sends an
+.Tn ANNOUNCE
+message causing the server to
+broadcast an announcement on the callee's login ports requesting contact.
+.Pp
+When the callee responds, the local server uses the
+recorded invitation to respond with the appropriate rendezvous
+address and the caller and callee client programs establish a
+stream connection through which the conversation takes place.
+.Sh CONFIGURATION
+The
+.Nm
+utility is managed by
+.Xr launchd 8
+as specified in the
+.Pa ntalk.plist
+property list.
+By default the property list contains the
+.Em Disabled
+key set to true, so
+.Nm
+is never invoked.
+.Pp
+Execute the following command as root to enable
+.Nm talkd :
+.Dl "launchctl load -w /System/Library/LaunchDaemons/ntalk.plist"
+.Pp
+.Sh SEE ALSO
+.Xr talk 1 ,
+.Xr write 1
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 .
diff --git a/remote_cmds/talkd.tproj/print.c b/remote_cmds/talkd.tproj/print.c
new file mode 100644
index 0000000..add853c
--- /dev/null
+++ b/remote_cmds/talkd.tproj/print.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c 8.1 (Berkeley) 6/4/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/print.c,v 1.12 2003/04/03 05:13:27 jmallett Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/* debug print routines */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <protocols/talkd.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "extern.h"
+
+static const char *types[] =
+ { "leave_invite", "look_up", "delete", "announce" };
+#define NTYPES (sizeof (types) / sizeof (types[0]))
+static const char *answers[] =
+ { "success", "not_here", "failed", "machine_unknown", "permission_denied",
+ "unknown_request", "badversion", "badaddr", "badctladdr" };
+#define NANSWERS (sizeof (answers) / sizeof (answers[0]))
+
+void
+print_request(const char *cp, CTL_MSG *mp)
+{
+ const char *tp;
+ char tbuf[80];
+
+ if (mp->type > NTYPES) {
+ (void)snprintf(tbuf, sizeof(tbuf), "type %d", mp->type);
+ tp = tbuf;
+ } else
+ tp = types[mp->type];
+ syslog(LOG_DEBUG, "%s: %s: id %lu, l_user %s, r_user %s, r_tty %s",
+ cp, tp, (long)mp->id_num, mp->l_name, mp->r_name, mp->r_tty);
+}
+
+void
+print_response(const char *cp, CTL_RESPONSE *rp)
+{
+ const char *tp, *ap;
+ char tbuf[80], abuf[80];
+
+ if (rp->type > NTYPES) {
+ (void)snprintf(tbuf, sizeof(tbuf), "type %d", rp->type);
+ tp = tbuf;
+ } else
+ tp = types[rp->type];
+ if (rp->answer > NANSWERS) {
+ (void)snprintf(abuf, sizeof(abuf), "answer %d", rp->answer);
+ ap = abuf;
+ } else
+ ap = answers[rp->answer];
+ syslog(LOG_DEBUG, "%s: %s: %s, id %d", cp, tp, ap, ntohl(rp->id_num));
+}
diff --git a/remote_cmds/talkd.tproj/process.c b/remote_cmds/talkd.tproj/process.c
new file mode 100644
index 0000000..e17d69e
--- /dev/null
+++ b/remote_cmds/talkd.tproj/process.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)process.c 8.2 (Berkeley) 11/16/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/process.c,v 1.11 2005/05/06 15:28:54 delphij Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * process.c handles the requests, which can be of three types:
+ * ANNOUNCE - announce to a user that a talk is wanted
+ * LEAVE_INVITE - insert the request into the table
+ * LOOK_UP - look up to see if a request is waiting in
+ * in the table for the local user
+ * DELETE - delete invitation
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <protocols/talkd.h>
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <paths.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+
+#include "extern.h"
+
+extern int debug;
+
+void
+process_request(CTL_MSG *mp, CTL_RESPONSE *rp)
+{
+ CTL_MSG *ptr;
+ char *s;
+
+ rp->vers = TALK_VERSION;
+ rp->type = mp->type;
+ rp->id_num = htonl(0);
+ if (mp->vers != TALK_VERSION) {
+ syslog(LOG_WARNING, "bad protocol version %d", mp->vers);
+ rp->answer = BADVERSION;
+ return;
+ }
+ mp->id_num = ntohl(mp->id_num);
+ mp->addr.sa_family = ntohs(mp->addr.sa_family);
+ if (mp->addr.sa_family != AF_INET) {
+ syslog(LOG_WARNING, "bad address, family %d",
+ mp->addr.sa_family);
+ rp->answer = BADADDR;
+ return;
+ }
+ mp->ctl_addr.sa_family = ntohs(mp->ctl_addr.sa_family);
+ if (mp->ctl_addr.sa_family != AF_INET) {
+ syslog(LOG_WARNING, "bad control address, family %d",
+ mp->ctl_addr.sa_family);
+ rp->answer = BADCTLADDR;
+ return;
+ }
+ for (s = mp->l_name; *s; s++)
+ if (!isprint(*s)) {
+ syslog(LOG_NOTICE, "illegal user name. Aborting");
+ rp->answer = FAILED;
+ return;
+ }
+ mp->pid = ntohl(mp->pid);
+ if (debug)
+ print_request("process_request", mp);
+ switch (mp->type) {
+
+ case ANNOUNCE:
+ do_announce(mp, rp);
+ break;
+
+ case LEAVE_INVITE:
+ ptr = find_request(mp);
+ if (ptr != (CTL_MSG *)0) {
+ rp->id_num = htonl(ptr->id_num);
+ rp->answer = SUCCESS;
+ } else
+ insert_table(mp, rp);
+ break;
+
+ case LOOK_UP:
+ ptr = find_match(mp);
+ if (ptr != (CTL_MSG *)0) {
+ rp->id_num = htonl(ptr->id_num);
+ rp->addr = ptr->addr;
+ rp->addr.sa_family = htons(ptr->addr.sa_family);
+ rp->answer = SUCCESS;
+ } else
+ rp->answer = NOT_HERE;
+ break;
+
+ case DELETE:
+ rp->answer = delete_invite(mp->id_num);
+ break;
+
+ default:
+ rp->answer = UNKNOWN_REQUEST;
+ break;
+ }
+ if (debug)
+ print_response("process_request", rp);
+}
+
+void
+do_announce(CTL_MSG *mp, CTL_RESPONSE *rp)
+{
+ struct hostent *hp;
+ CTL_MSG *ptr;
+ int result;
+
+ /* see if the user is logged */
+ result = find_user(mp->r_name, mp->r_tty);
+ if (result != SUCCESS) {
+ rp->answer = result;
+ return;
+ }
+#define satosin(sa) ((struct sockaddr_in *)(sa))
+ hp = gethostbyaddr((char *)&satosin(&mp->ctl_addr)->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ if (hp == (struct hostent *)0) {
+ rp->answer = MACHINE_UNKNOWN;
+ return;
+ }
+ ptr = find_request(mp);
+ if (ptr == (CTL_MSG *) 0) {
+ insert_table(mp, rp);
+ rp->answer = announce(mp, hp->h_name);
+ return;
+ }
+ if (mp->id_num > ptr->id_num) {
+ /*
+ * This is an explicit re-announce, so update the id_num
+ * field to avoid duplicates and re-announce the talk.
+ */
+ ptr->id_num = new_id();
+ rp->id_num = htonl(ptr->id_num);
+ rp->answer = announce(mp, hp->h_name);
+ } else {
+ /* a duplicated request, so ignore it */
+ rp->id_num = htonl(ptr->id_num);
+ rp->answer = SUCCESS;
+ }
+}
+
+#ifdef __APPLE__
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+
+/*
+ * Search utmp for the local user
+ */
+int
+find_user(const char *name, char *tty)
+{
+#ifdef __APPLE__
+ struct utmpx *u;
+ int status;
+ struct stat statb;
+
+ char line[sizeof(u->ut_line) + 1];
+ char ftty[sizeof(_PATH_DEV) - 1 + sizeof(line)];
+
+ setutxent();
+#define SCMPN(a, b) strncmp(a, b, sizeof (a))
+ status = NOT_HERE;
+ (void) strcpy(ftty, _PATH_DEV);
+ while ((u = getutxent()) != NULL)
+ if (u->ut_type == USER_PROCESS && SCMPN(u->ut_user, name) == 0) {
+ strncpy(line, u->ut_line, sizeof(u->ut_line));
+ line[sizeof(u->ut_line)] = '\0';
+ if (*tty == '\0') {
+ status = PERMISSION_DENIED;
+ /* no particular tty was requested */
+ (void) strcpy(ftty + sizeof(_PATH_DEV) - 1,
+ line);
+ if (stat(ftty, &statb) == 0) {
+ if (!(statb.st_mode & 020))
+ continue;
+ (void) strcpy(tty, line);
+ status = SUCCESS;
+ break;
+ }
+ }
+ if (strcmp(line, tty) == 0) {
+ status = SUCCESS;
+ break;
+ }
+ }
+ endutxent();
+#else
+ struct utmp ubuf;
+ int status;
+ FILE *fd;
+ struct stat statb;
+ time_t best = 0;
+ char line[sizeof(ubuf.ut_line) + 1];
+ char ftty[sizeof(_PATH_DEV) - 1 + sizeof(line)];
+
+ if ((fd = fopen(_PATH_UTMP, "r")) == NULL) {
+ warnx("can't read %s", _PATH_UTMP);
+ return (FAILED);
+ }
+#define SCMPN(a, b) strncmp(a, b, sizeof (a))
+ status = NOT_HERE;
+ (void) strcpy(ftty, _PATH_DEV);
+ while (fread((char *) &ubuf, sizeof ubuf, 1, fd) == 1)
+ if (SCMPN(ubuf.ut_name, name) == 0) {
+ strncpy(line, ubuf.ut_line, sizeof(ubuf.ut_line));
+ line[sizeof(ubuf.ut_line)] = '\0';
+ if (*tty == '\0' || best != 0) {
+ if (best == 0)
+ status = PERMISSION_DENIED;
+ /* no particular tty was requested */
+ (void) strcpy(ftty + sizeof(_PATH_DEV) - 1,
+ line);
+ if (stat(ftty, &statb) == 0) {
+ if (!(statb.st_mode & 020))
+ continue;
+ if (statb.st_atime > best) {
+ best = statb.st_atime;
+ (void) strcpy(tty, line);
+ status = SUCCESS;
+ continue;
+ }
+ }
+ }
+ if (strcmp(line, tty) == 0) {
+ status = SUCCESS;
+ break;
+ }
+ }
+ fclose(fd);
+#endif
+ return (status);
+}
diff --git a/remote_cmds/talkd.tproj/table.c b/remote_cmds/talkd.tproj/table.c
new file mode 100644
index 0000000..77c7d33
--- /dev/null
+++ b/remote_cmds/talkd.tproj/table.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)table.c 8.1 (Berkeley) 6/4/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/table.c,v 1.9 2003/04/03 05:13:27 jmallett Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Routines to handle insertion, deletion, etc on the table
+ * of requests kept by the daemon. Nothing fancy here, linear
+ * search on a double-linked list. A time is kept with each
+ * entry so that overly old invitations can be eliminated.
+ *
+ * Consider this a mis-guided attempt at modularity
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <protocols/talkd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define MAX_ID 16000 /* << 2^15 so I don't have sign troubles */
+
+#define NIL ((TABLE_ENTRY *)0)
+
+extern int debug;
+struct timeval tp;
+struct timezone txp;
+
+typedef struct table_entry TABLE_ENTRY;
+
+struct table_entry {
+ CTL_MSG request;
+ long time;
+ TABLE_ENTRY *next;
+ TABLE_ENTRY *last;
+};
+
+static void delete(TABLE_ENTRY *);
+
+TABLE_ENTRY *table = NIL;
+
+/*
+ * Look in the table for an invitation that matches the current
+ * request looking for an invitation
+ */
+CTL_MSG *
+find_match(CTL_MSG *request)
+{
+ TABLE_ENTRY *ptr;
+ time_t current_time;
+
+ gettimeofday(&tp, &txp);
+ current_time = tp.tv_sec;
+ if (debug)
+ print_request("find_match", request);
+ for (ptr = table; ptr != NIL; ptr = ptr->next) {
+ if ((ptr->time - current_time) > MAX_LIFE) {
+ /* the entry is too old */
+ if (debug)
+ print_request("deleting expired entry",
+ &ptr->request);
+ delete(ptr);
+ continue;
+ }
+ if (debug)
+ print_request("", &ptr->request);
+ if (strcmp(request->l_name, ptr->request.r_name) == 0 &&
+ strcmp(request->r_name, ptr->request.l_name) == 0 &&
+ ptr->request.type == LEAVE_INVITE)
+ return (&ptr->request);
+ }
+ return ((CTL_MSG *)0);
+}
+
+/*
+ * Look for an identical request, as opposed to a complimentary
+ * one as find_match does
+ */
+CTL_MSG *
+find_request(CTL_MSG *request)
+{
+ TABLE_ENTRY *ptr;
+ time_t current_time;
+
+ gettimeofday(&tp, &txp);
+ current_time = tp.tv_sec;
+ /*
+ * See if this is a repeated message, and check for
+ * out of date entries in the table while we are it.
+ */
+ if (debug)
+ print_request("find_request", request);
+ for (ptr = table; ptr != NIL; ptr = ptr->next) {
+ if ((ptr->time - current_time) > MAX_LIFE) {
+ /* the entry is too old */
+ if (debug)
+ print_request("deleting expired entry",
+ &ptr->request);
+ delete(ptr);
+ continue;
+ }
+ if (debug)
+ print_request("", &ptr->request);
+ if (strcmp(request->r_name, ptr->request.r_name) == 0 &&
+ strcmp(request->l_name, ptr->request.l_name) == 0 &&
+ request->type == ptr->request.type &&
+ request->pid == ptr->request.pid) {
+ /* update the time if we 'touch' it */
+ ptr->time = current_time;
+ return (&ptr->request);
+ }
+ }
+ return ((CTL_MSG *)0);
+}
+
+void
+insert_table(CTL_MSG *request, CTL_RESPONSE *response)
+{
+ TABLE_ENTRY *ptr;
+ time_t current_time;
+
+ gettimeofday(&tp, &txp);
+ current_time = tp.tv_sec;
+ request->id_num = new_id();
+ response->id_num = htonl(request->id_num);
+ /* insert a new entry into the top of the list */
+ ptr = (TABLE_ENTRY *)malloc(sizeof(TABLE_ENTRY));
+ if (ptr == NIL) {
+ syslog(LOG_ERR, "insert_table: Out of memory");
+ _exit(1);
+ }
+ ptr->time = current_time;
+ ptr->request = *request;
+ ptr->next = table;
+ if (ptr->next != NIL)
+ ptr->next->last = ptr;
+ ptr->last = NIL;
+ table = ptr;
+}
+
+/*
+ * Generate a unique non-zero sequence number
+ */
+int
+new_id(void)
+{
+ static int current_id = 0;
+
+ current_id = (current_id + 1) % MAX_ID;
+ /* 0 is reserved, helps to pick up bugs */
+ if (current_id == 0)
+ current_id = 1;
+ return (current_id);
+}
+
+/*
+ * Delete the invitation with id 'id_num'
+ */
+int
+delete_invite(u_int32_t id_num)
+{
+ TABLE_ENTRY *ptr;
+
+ ptr = table;
+ if (debug)
+ syslog(LOG_DEBUG, "delete_invite(%d)", id_num);
+ for (ptr = table; ptr != NIL; ptr = ptr->next) {
+ if (ptr->request.id_num == id_num)
+ break;
+ if (debug)
+ print_request("", &ptr->request);
+ }
+ if (ptr != NIL) {
+ delete(ptr);
+ return (SUCCESS);
+ }
+ return (NOT_HERE);
+}
+
+/*
+ * Classic delete from a double-linked list
+ */
+static void
+delete(TABLE_ENTRY *ptr)
+{
+
+ if (debug)
+ print_request("delete", &ptr->request);
+ if (table == ptr)
+ table = ptr->next;
+ else if (ptr->last != NIL)
+ ptr->last->next = ptr->next;
+ if (ptr->next != NIL)
+ ptr->next->last = ptr->last;
+ free((char *)ptr);
+}
diff --git a/remote_cmds/talkd.tproj/talkd.c b/remote_cmds/talkd.tproj/talkd.c
new file mode 100644
index 0000000..1f28cb8
--- /dev/null
+++ b/remote_cmds/talkd.tproj/talkd.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)talkd.c 8.1 (Berkeley) 6/4/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/talkd/talkd.c,v 1.17 2004/06/14 22:44:13 bms Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * The top level of the daemon, the format is heavily borrowed
+ * from rwhod.c. Basically: find out who and where you are;
+ * disconnect all descriptors and ttys, and then endless
+ * loop on waiting for and processing requests
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <protocols/talkd.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+CTL_MSG request;
+CTL_RESPONSE response;
+
+int debug = 0;
+long lastmsgtime;
+
+char hostname[MAXHOSTNAMELEN + 1];
+
+#define TIMEOUT 30
+#define MAXIDLE 120
+
+int
+main(int argc, char *argv[])
+{
+ register CTL_MSG *mp = &request;
+ int cc;
+ struct sockaddr ctl_addr;
+
+ /*
+ * removed so ntalkd can run in tty sandbox
+ */
+ if (getuid())
+ errx(1, "getuid: not super-user");
+
+ openlog("talkd", LOG_PID, LOG_DAEMON);
+ if (gethostname(hostname, sizeof(hostname) - 1) < 0) {
+ syslog(LOG_ERR, "gethostname: %m");
+ _exit(1);
+ }
+ hostname[sizeof(hostname) - 1] = '\0';
+ if (chdir(_PATH_DEV) < 0) {
+ syslog(LOG_ERR, "chdir: %s: %m", _PATH_DEV);
+ _exit(1);
+ }
+ if (argc > 1 && strcmp(argv[1], "-d") == 0)
+ debug = 1;
+ signal(SIGALRM, timeout);
+ alarm(TIMEOUT);
+ for (;;) {
+ cc = recv(0, (char *)mp, sizeof(*mp), 0);
+ if (cc != sizeof (*mp)) {
+ if (cc < 0 && errno != EINTR)
+ syslog(LOG_WARNING, "recv: %m");
+ continue;
+ }
+ lastmsgtime = time(0);
+ (void)memcpy(&ctl_addr, &mp->ctl_addr, sizeof(ctl_addr));
+ ctl_addr.sa_family = ntohs(mp->ctl_addr.sa_family);
+ ctl_addr.sa_len = sizeof(ctl_addr);
+ process_request(mp, &response);
+ /* can block here, is this what I want? */
+ cc = sendto(STDIN_FILENO, (char *)&response,
+ sizeof(response), 0, &ctl_addr, sizeof(ctl_addr));
+ if (cc != sizeof (response))
+ syslog(LOG_WARNING, "sendto: %m");
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+void
+timeout(int sig __unused)
+{
+ int save_errno = errno;
+
+ if (time(0) - lastmsgtime >= MAXIDLE)
+ _exit(0);
+ alarm(TIMEOUT);
+ errno = save_errno;
+}
diff --git a/remote_cmds/telnet.tproj/Makefile b/remote_cmds/telnet.tproj/Makefile
new file mode 100644
index 0000000..dc8569b
--- /dev/null
+++ b/remote_cmds/telnet.tproj/Makefile
@@ -0,0 +1,18 @@
+Project = telnet
+Install_Dir = /usr/local/bin
+
+HFILES = externs.h fdset.h general.h krb4-proto.h ring.h types.h\
+ defines.h misc.h misc-proto.h
+CFILES = authenc.c commands.c main.c network.c ring.c sys_bsd.c\
+ telnet.c terminal.c tn3270.c utilities.c
+
+Extra_CC_Flags = -Wall -Werror -Wno-string-plus-int -fPIE
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -pie
+
+Extra_CC_Flags += -DTERMCAP -DKLUDGELINEMODE -DUSE_TERMIO -DENV_HACK \
+ -DAUTHENTICATION -DKRB5 -DSKEY -DIPSEC -DINET6 -DFORWARD
+ # -DENCRYPTION -DKRB4
+Extra_LD_Libraries = -lcurses -lkrb4 -lkrb5 -lipsec -ltelnet
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/telnet.tproj/authenc.c b/remote_cmds/telnet.tproj/authenc.c
new file mode 100644
index 0000000..258a013
--- /dev/null
+++ b/remote_cmds/telnet.tproj/authenc.c
@@ -0,0 +1,109 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)authenc.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/authenc.c,v 1.6 2003/05/04 02:54:48 obrien Exp $");
+
+#ifdef AUTHENTICATION
+#include <sys/types.h>
+#include <arpa/telnet.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <libtelnet/encrypt.h>
+#include <libtelnet/misc.h>
+
+#include "general.h"
+#include "ring.h"
+#include "externs.h"
+#include "defines.h"
+#include "types.h"
+
+int
+net_write(unsigned char *str, int len)
+{
+ if (NETROOM() > len) {
+ ring_supply_data(&netoring, str, len);
+ if (str[0] == IAC && str[1] == SE)
+ printsub('>', &str[2], len-2);
+ return(len);
+ }
+ return(0);
+}
+
+void
+net_encrypt(void)
+{
+#ifdef ENCRYPTION
+ if (encrypt_output)
+ ring_encrypt(&netoring, encrypt_output);
+ else
+ ring_clearto(&netoring);
+#endif /* ENCRYPTION */
+}
+
+int
+telnet_spin(void)
+{
+ return(-1);
+}
+
+char *
+telnet_getenv(char *val)
+{
+ return((char *)env_getvalue((unsigned char *)val));
+}
+
+char *
+telnet_gets(const char *prom, char *result, int length, int echo)
+{
+ extern int globalmode;
+ int om = globalmode;
+ char *res;
+
+ TerminalNewMode(-1);
+ if (echo) {
+ printf("%s", prom);
+ res = fgets(result, length, stdin);
+ } else if ((res = getpass(prom))) {
+ strncpy(result, res, length);
+ res = result;
+ }
+ TerminalNewMode(om);
+ return(res);
+}
+#endif /* AUTHENTICATION */
diff --git a/remote_cmds/telnet.tproj/commands.c b/remote_cmds/telnet.tproj/commands.c
new file mode 100644
index 0000000..56a0794
--- /dev/null
+++ b/remote_cmds/telnet.tproj/commands.c
@@ -0,0 +1,3063 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/commands.c,v 1.35 2005/02/28 12:46:52 tobez Exp $");
+
+/* Use RFC 2292 constants in <netinet6/in6.h> */
+#define __APPLE_USE_RFC_2292
+
+#include <sys/param.h>
+#include <sys/un.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <arpa/telnet.h>
+#include <arpa/inet.h>
+
+#include "general.h"
+
+#include "ring.h"
+
+#include "externs.h"
+#include "defines.h"
+#include "types.h"
+#include "misc.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif
+
+typedef int (*intrtn_t)(int, char **);
+
+#ifdef AUTHENTICATION
+extern int auth_togdebug(int);
+#endif
+#ifdef ENCRYPTION
+extern int EncryptAutoEnc(int);
+extern int EncryptAutoDec(int);
+extern int EncryptDebug(int);
+extern int EncryptVerbose(int);
+#endif /* ENCRYPTION */
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+int tos = -1;
+#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
+
+char *hostname;
+static char _hostname[MAXHOSTNAMELEN];
+
+static int help(int, char **);
+static int call(intrtn_t, ...);
+static void cmdrc(char *, char *);
+#ifdef INET6
+static int switch_af(struct addrinfo **);
+#endif
+static int togglehelp(void);
+static int send_tncmd(void (*)(int, int), const char *, char *);
+static int setmod(int);
+static int clearmode(int);
+static int modehelp(void);
+#ifndef __APPLE__
+static int sourceroute(struct addrinfo *, char *, char **, int *, int *, int *);
+#endif
+
+typedef struct {
+ const char *name; /* command name */
+ const char *help; /* help string (NULL for no help) */
+ int (*handler)(int, char **); /* routine which executes command */
+ int needconnect; /* Do we need to be connected to execute? */
+} Command;
+
+static char line[256];
+static char saveline[256];
+static int margc;
+static char *margv[20];
+
+#ifdef OPIE
+#include <sys/wait.h>
+#define PATH_OPIEKEY "/usr/bin/opiekey"
+static int
+opie_calc(int argc, char *argv[])
+{
+ int status;
+
+ if(argc != 3) {
+ printf("%s sequence challenge\n", argv[0]);
+ return (0);
+ }
+
+ switch(fork()) {
+ case 0:
+ execv(PATH_OPIEKEY, argv);
+ exit (1);
+ case -1:
+ perror("fork");
+ break;
+ default:
+ (void) wait(&status);
+ if (WIFEXITED(status))
+ return (WEXITSTATUS(status));
+ }
+ return (0);
+}
+#endif
+
+static void
+makeargv(void)
+{
+ char *cp, *cp2, c;
+ char **argp = margv;
+
+ margc = 0;
+ cp = line;
+ if (*cp == '!') { /* Special case shell escape */
+ strcpy(saveline, line); /* save for shell command */
+ *argp++ = strdup("!"); /* No room in string to get this */
+ margc++;
+ cp++;
+ }
+ while ((c = *cp)) {
+ int inquote = 0;
+ while (isspace(c))
+ c = *++cp;
+ if (c == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ for (cp2 = cp; c != '\0'; c = *++cp) {
+ if (inquote) {
+ if (c == inquote) {
+ inquote = 0;
+ continue;
+ }
+ } else {
+ if (c == '\\') {
+ if ((c = *++cp) == '\0')
+ break;
+ } else if (c == '"') {
+ inquote = '"';
+ continue;
+ } else if (c == '\'') {
+ inquote = '\'';
+ continue;
+ } else if (isspace(c))
+ break;
+ }
+ *cp2++ = c;
+ }
+ *cp2 = '\0';
+ if (c == '\0')
+ break;
+ cp++;
+ }
+ *argp++ = 0;
+}
+
+/*
+ * Make a character string into a number.
+ *
+ * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
+ */
+
+static int
+special(char *s)
+{
+ char c;
+ char b;
+
+ switch (*s) {
+ case '^':
+ b = *++s;
+ if (b == '?') {
+ c = b | 0x40; /* DEL */
+ } else {
+ c = b & 0x1f;
+ }
+ break;
+ default:
+ c = *s;
+ break;
+ }
+ return c;
+}
+
+/*
+ * Construct a control character sequence
+ * for a special character.
+ */
+static const char *
+control(cc_t c)
+{
+ static char buf[5];
+ /*
+ * The only way I could get the Sun 3.5 compiler
+ * to shut up about
+ * if ((unsigned int)c >= 0x80)
+ * was to assign "c" to an unsigned int variable...
+ * Arggg....
+ */
+ unsigned int uic = (unsigned int)c;
+
+ if (uic == 0x7f)
+ return ("^?");
+ if (c == (cc_t)_POSIX_VDISABLE) {
+ return "off";
+ }
+ if (uic >= 0x80) {
+ buf[0] = '\\';
+ buf[1] = ((c>>6)&07) + '0';
+ buf[2] = ((c>>3)&07) + '0';
+ buf[3] = (c&07) + '0';
+ buf[4] = 0;
+ } else if (uic >= 0x20) {
+ buf[0] = c;
+ buf[1] = 0;
+ } else {
+ buf[0] = '^';
+ buf[1] = '@'+c;
+ buf[2] = 0;
+ }
+ return (buf);
+}
+
+/*
+ * The following are data structures and routines for
+ * the "send" command.
+ *
+ */
+
+struct sendlist {
+ const char *name; /* How user refers to it (case independent) */
+ const char *help; /* Help information (0 ==> no help) */
+ int needconnect; /* Need to be connected */
+ int narg; /* Number of arguments */
+ int (*handler)(char *, ...); /* Routine to perform (for special ops) */
+ int nbyte; /* Number of bytes to send this command */
+ int what; /* Character to be sent (<0 ==> special) */
+};
+
+
+static int
+ send_esc(void),
+ send_help(void),
+ send_docmd(char *),
+ send_dontcmd(char *),
+ send_willcmd(char *),
+ send_wontcmd(char *);
+
+static struct sendlist Sendlist[] = {
+ { "ao", "Send Telnet Abort output", 1, 0, NULL, 2, AO },
+ { "ayt", "Send Telnet 'Are You There'", 1, 0, NULL, 2, AYT },
+ { "brk", "Send Telnet Break", 1, 0, NULL, 2, BREAK },
+ { "break", NULL, 1, 0, NULL, 2, BREAK },
+ { "ec", "Send Telnet Erase Character", 1, 0, NULL, 2, EC },
+ { "el", "Send Telnet Erase Line", 1, 0, NULL, 2, EL },
+ { "escape", "Send current escape character",1, 0, (int (*)(char *, ...))send_esc, 1, 0 },
+ { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, NULL, 2, GA },
+ { "ip", "Send Telnet Interrupt Process",1, 0, NULL, 2, IP },
+ { "intp", NULL, 1, 0, NULL, 2, IP },
+ { "interrupt", NULL, 1, 0, NULL, 2, IP },
+ { "intr", NULL, 1, 0, NULL, 2, IP },
+ { "nop", "Send Telnet 'No operation'", 1, 0, NULL, 2, NOP },
+ { "eor", "Send Telnet 'End of Record'", 1, 0, NULL, 2, EOR },
+ { "abort", "Send Telnet 'Abort Process'", 1, 0, NULL, 2, ABORT },
+ { "susp", "Send Telnet 'Suspend Process'",1, 0, NULL, 2, SUSP },
+ { "eof", "Send Telnet End of File Character", 1, 0, NULL, 2, xEOF },
+ { "synch", "Perform Telnet 'Synch operation'", 1, 0, (int (*)(char *, ...))dosynch, 2, 0 },
+ { "getstatus", "Send request for STATUS", 1, 0, (int (*)(char *, ...))get_status, 6, 0 },
+ { "?", "Display send options", 0, 0, (int (*)(char *, ...))send_help, 0, 0 },
+ { "help", NULL, 0, 0, (int (*)(char *, ...))send_help, 0, 0 },
+ { "do", NULL, 0, 1, (int (*)(char *, ...))send_docmd, 3, 0 },
+ { "dont", NULL, 0, 1, (int (*)(char *, ...))send_dontcmd, 3, 0 },
+ { "will", NULL, 0, 1, (int (*)(char *, ...))send_willcmd, 3, 0 },
+ { "wont", NULL, 0, 1, (int (*)(char *, ...))send_wontcmd, 3, 0 },
+ { NULL, NULL, 0, 0, NULL, 0, 0 }
+};
+
+#define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \
+ sizeof(struct sendlist)))
+
+static int
+sendcmd(int argc, char *argv[])
+{
+ int count; /* how many bytes we are going to need to send */
+ int i;
+ struct sendlist *s; /* pointer to current command */
+ int success = 0;
+ int needconnect = 0;
+
+ if (argc < 2) {
+ printf("need at least one argument for 'send' command\n");
+ printf("'send ?' for help\n");
+ return 0;
+ }
+ /*
+ * First, validate all the send arguments.
+ * In addition, we see how much space we are going to need, and
+ * whether or not we will be doing a "SYNCH" operation (which
+ * flushes the network queue).
+ */
+ count = 0;
+ for (i = 1; i < argc; i++) {
+ s = GETSEND(argv[i]);
+ if (s == 0) {
+ printf("Unknown send argument '%s'\n'send ?' for help.\n",
+ argv[i]);
+ return 0;
+ } else if (Ambiguous((void *)s)) {
+ printf("Ambiguous send argument '%s'\n'send ?' for help.\n",
+ argv[i]);
+ return 0;
+ }
+ if (i + s->narg >= argc) {
+ fprintf(stderr,
+ "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\n",
+ s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
+ return 0;
+ }
+ count += s->nbyte;
+ if ((void *)s->handler == (void *)send_help) {
+ send_help();
+ return 0;
+ }
+
+ i += s->narg;
+ needconnect += s->needconnect;
+ }
+ if (!connected && needconnect) {
+ printf("?Need to be connected first.\n");
+ printf("'send ?' for help\n");
+ return 0;
+ }
+ /* Now, do we have enough room? */
+ if (NETROOM() < count) {
+ printf("There is not enough room in the buffer TO the network\n");
+ printf("to process your request. Nothing will be done.\n");
+ printf("('send synch' will throw away most data in the network\n");
+ printf("buffer, if this might help.)\n");
+ return 0;
+ }
+ /* OK, they are all OK, now go through again and actually send */
+ count = 0;
+ for (i = 1; i < argc; i++) {
+ if ((s = GETSEND(argv[i])) == 0) {
+ fprintf(stderr, "Telnet 'send' error - argument disappeared!\n");
+ quit();
+ /*NOTREACHED*/
+ }
+ if (s->handler) {
+ count++;
+ success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
+ (s->narg > 1) ? argv[i+2] : 0);
+ i += s->narg;
+ } else {
+ NET2ADD(IAC, s->what);
+ printoption("SENT", IAC, s->what);
+ }
+ }
+ return (count == success);
+}
+
+static int
+send_esc(void)
+{
+ NETADD(escape);
+ return 1;
+}
+
+static int
+send_docmd(char *name)
+{
+ return(send_tncmd(send_do, "do", name));
+}
+
+static int
+send_dontcmd(name)
+ char *name;
+{
+ return(send_tncmd(send_dont, "dont", name));
+}
+
+static int
+send_willcmd(char *name)
+{
+ return(send_tncmd(send_will, "will", name));
+}
+
+static int
+send_wontcmd(char *name)
+{
+ return(send_tncmd(send_wont, "wont", name));
+}
+
+static int
+send_tncmd(void (*func)(int, int), const char *cmd, char *name)
+{
+ char **cpp;
+ extern char *telopts[];
+ int val = 0;
+
+ if (isprefix(name, "help") || isprefix(name, "?")) {
+ int col, len;
+
+ printf("usage: send %s <value|option>\n", cmd);
+ printf("\"value\" must be from 0 to 255\n");
+ printf("Valid options are:\n\t");
+
+ col = 8;
+ for (cpp = telopts; *cpp; cpp++) {
+ len = strlen(*cpp) + 3;
+ if (col + len > 65) {
+ printf("\n\t");
+ col = 8;
+ }
+ printf(" \"%s\"", *cpp);
+ col += len;
+ }
+ printf("\n");
+ return 0;
+ }
+ cpp = (char **)genget(name, telopts, sizeof(char *));
+ if (Ambiguous(cpp)) {
+ fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\n",
+ name, cmd);
+ return 0;
+ }
+ if (cpp) {
+ val = cpp - telopts;
+ } else {
+ char *cp = name;
+
+ while (*cp >= '0' && *cp <= '9') {
+ val *= 10;
+ val += *cp - '0';
+ cp++;
+ }
+ if (*cp != 0) {
+ fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\n",
+ name, cmd);
+ return 0;
+ } else if (val < 0 || val > 255) {
+ fprintf(stderr, "'%s': bad value ('send %s ?' for help).\n",
+ name, cmd);
+ return 0;
+ }
+ }
+ if (!connected) {
+ printf("?Need to be connected first.\n");
+ return 0;
+ }
+ (*func)(val, 1);
+ return 1;
+}
+
+static int
+send_help(void)
+{
+ struct sendlist *s; /* pointer to current command */
+ for (s = Sendlist; s->name; s++) {
+ if (s->help)
+ printf("%-15s %s\n", s->name, s->help);
+ }
+ return(0);
+}
+
+/*
+ * The following are the routines and data structures referred
+ * to by the arguments to the "toggle" command.
+ */
+
+static int
+lclchars(void)
+{
+ donelclchars = 1;
+ return 1;
+}
+
+static int
+togdebug(void)
+{
+#ifndef NOT43
+ if (net > 0 &&
+ (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, telnet_debug)) < 0) {
+ perror("setsockopt (SO_DEBUG)");
+ }
+#else /* NOT43 */
+ if (telnet_debug) {
+ if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0)
+ perror("setsockopt (SO_DEBUG)");
+ } else
+ printf("Cannot turn off socket debugging\n");
+#endif /* NOT43 */
+ return 1;
+}
+
+
+static int
+togcrlf(void)
+{
+ if (crlf) {
+ printf("Will send carriage returns as telnet <CR><LF>.\n");
+ } else {
+ printf("Will send carriage returns as telnet <CR><NUL>.\n");
+ }
+ return 1;
+}
+
+int binmode;
+
+static int
+togbinary(int val)
+{
+ donebinarytoggle = 1;
+
+ if (val >= 0) {
+ binmode = val;
+ } else {
+ if (my_want_state_is_will(TELOPT_BINARY) &&
+ my_want_state_is_do(TELOPT_BINARY)) {
+ binmode = 1;
+ } else if (my_want_state_is_wont(TELOPT_BINARY) &&
+ my_want_state_is_dont(TELOPT_BINARY)) {
+ binmode = 0;
+ }
+ val = binmode ? 0 : 1;
+ }
+
+ if (val == 1) {
+ if (my_want_state_is_will(TELOPT_BINARY) &&
+ my_want_state_is_do(TELOPT_BINARY)) {
+ printf("Already operating in binary mode with remote host.\n");
+ } else {
+ printf("Negotiating binary mode with remote host.\n");
+ tel_enter_binary(3);
+ }
+ } else {
+ if (my_want_state_is_wont(TELOPT_BINARY) &&
+ my_want_state_is_dont(TELOPT_BINARY)) {
+ printf("Already in network ascii mode with remote host.\n");
+ } else {
+ printf("Negotiating network ascii mode with remote host.\n");
+ tel_leave_binary(3);
+ }
+ }
+ return 1;
+}
+
+static int
+togrbinary(int val)
+{
+ donebinarytoggle = 1;
+
+ if (val == -1)
+ val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
+
+ if (val == 1) {
+ if (my_want_state_is_do(TELOPT_BINARY)) {
+ printf("Already receiving in binary mode.\n");
+ } else {
+ printf("Negotiating binary mode on input.\n");
+ tel_enter_binary(1);
+ }
+ } else {
+ if (my_want_state_is_dont(TELOPT_BINARY)) {
+ printf("Already receiving in network ascii mode.\n");
+ } else {
+ printf("Negotiating network ascii mode on input.\n");
+ tel_leave_binary(1);
+ }
+ }
+ return 1;
+}
+
+static int
+togxbinary(int val)
+{
+ donebinarytoggle = 1;
+
+ if (val == -1)
+ val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
+
+ if (val == 1) {
+ if (my_want_state_is_will(TELOPT_BINARY)) {
+ printf("Already transmitting in binary mode.\n");
+ } else {
+ printf("Negotiating binary mode on output.\n");
+ tel_enter_binary(2);
+ }
+ } else {
+ if (my_want_state_is_wont(TELOPT_BINARY)) {
+ printf("Already transmitting in network ascii mode.\n");
+ } else {
+ printf("Negotiating network ascii mode on output.\n");
+ tel_leave_binary(2);
+ }
+ }
+ return 1;
+}
+
+struct togglelist {
+ const char *name; /* name of toggle */
+ const char *help; /* help message */
+ int (*handler)(int); /* routine to do actual setting */
+ int *variable;
+ const char *actionexplanation;
+};
+
+static struct togglelist Togglelist[] = {
+ { "autoflush",
+ "flushing of output when sending interrupt characters",
+ 0,
+ &autoflush,
+ "flush output when sending interrupt characters" },
+ { "autosynch",
+ "automatic sending of interrupt characters in urgent mode",
+ 0,
+ &autosynch,
+ "send interrupt characters in urgent mode" },
+#ifdef AUTHENTICATION
+ { "autologin",
+ "automatic sending of login and/or authentication info",
+ 0,
+ &autologin,
+ "send login name and/or authentication information" },
+ { "authdebug",
+ "Toggle authentication debugging",
+ auth_togdebug,
+ 0,
+ "print authentication debugging information" },
+#endif
+#ifdef ENCRYPTION
+ { "autoencrypt",
+ "automatic encryption of data stream",
+ EncryptAutoEnc,
+ 0,
+ "automatically encrypt output" },
+ { "autodecrypt",
+ "automatic decryption of data stream",
+ EncryptAutoDec,
+ 0,
+ "automatically decrypt input" },
+ { "verbose_encrypt",
+ "Toggle verbose encryption output",
+ EncryptVerbose,
+ 0,
+ "print verbose encryption output" },
+ { "encdebug",
+ "Toggle encryption debugging",
+ EncryptDebug,
+ 0,
+ "print encryption debugging information" },
+#endif /* ENCRYPTION */
+ { "skiprc",
+ "don't read ~/.telnetrc file",
+ 0,
+ &skiprc,
+ "skip reading of ~/.telnetrc file" },
+ { "binary",
+ "sending and receiving of binary data",
+ togbinary,
+ 0,
+ 0 },
+ { "inbinary",
+ "receiving of binary data",
+ togrbinary,
+ 0,
+ 0 },
+ { "outbinary",
+ "sending of binary data",
+ togxbinary,
+ 0,
+ 0 },
+ { "crlf",
+ "sending carriage returns as telnet <CR><LF>",
+ (int (*)(int))togcrlf,
+ &crlf,
+ 0 },
+ { "crmod",
+ "mapping of received carriage returns",
+ 0,
+ &crmod,
+ "map carriage return on output" },
+ { "localchars",
+ "local recognition of certain control characters",
+ (int (*)(int))lclchars,
+ &localchars,
+ "recognize certain control characters" },
+ { " ", "", NULL, NULL, NULL }, /* empty line */
+ { "debug",
+ "debugging",
+ (int (*)(int))togdebug,
+ &telnet_debug,
+ "turn on socket level debugging" },
+ { "netdata",
+ "printing of hexadecimal network data (debugging)",
+ 0,
+ &netdata,
+ "print hexadecimal representation of network traffic" },
+ { "prettydump",
+ "output of \"netdata\" to user readable format (debugging)",
+ 0,
+ &prettydump,
+ "print user readable output for \"netdata\"" },
+ { "options",
+ "viewing of options processing (debugging)",
+ 0,
+ &showoptions,
+ "show option processing" },
+ { "termdata",
+ "(debugging) toggle printing of hexadecimal terminal data",
+ 0,
+ &termdata,
+ "print hexadecimal representation of terminal traffic" },
+ { "?",
+ NULL,
+ (int (*)(int))togglehelp,
+ NULL,
+ NULL },
+ { NULL, NULL, NULL, NULL, NULL },
+ { "help",
+ NULL,
+ (int (*)(int))togglehelp,
+ NULL,
+ NULL },
+ { NULL, NULL, NULL, NULL, NULL }
+};
+
+static int
+togglehelp(void)
+{
+ struct togglelist *c;
+
+ for (c = Togglelist; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s toggle %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+ printf("\n");
+ printf("%-15s %s\n", "?", "display help information");
+ return 0;
+}
+
+static void
+settogglehelp(int set)
+{
+ struct togglelist *c;
+
+ for (c = Togglelist; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s %s\n", c->name, set ? "enable" : "disable",
+ c->help);
+ else
+ printf("\n");
+ }
+ }
+}
+
+#define GETTOGGLE(name) (struct togglelist *) \
+ genget(name, (char **) Togglelist, sizeof(struct togglelist))
+
+static int
+toggle(int argc, char *argv[])
+{
+ int retval = 1;
+ char *name;
+ struct togglelist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'toggle' command. 'toggle ?' for help.\n");
+ return 0;
+ }
+ argc--;
+ argv++;
+ while (argc--) {
+ name = *argv++;
+ c = GETTOGGLE(name);
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\n",
+ name);
+ return 0;
+ } else if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\n",
+ name);
+ return 0;
+ } else {
+ if (c->variable) {
+ *c->variable = !*c->variable; /* invert it */
+ if (c->actionexplanation) {
+ printf("%s %s.\n", *c->variable? "Will" : "Won't",
+ c->actionexplanation);
+ }
+ }
+ if (c->handler) {
+ retval &= (*c->handler)(-1);
+ }
+ }
+ }
+ return retval;
+}
+
+/*
+ * The following perform the "set" command.
+ */
+
+#ifdef USE_TERMIO
+struct termio new_tc = { 0, 0, 0, 0, {}, 0, 0 };
+#endif
+
+struct setlist {
+ const char *name; /* name */
+ const char *help; /* help information */
+ void (*handler)(char *);
+ cc_t *charp; /* where it is located at */
+};
+
+static struct setlist Setlist[] = {
+#ifdef KLUDGELINEMODE
+ { "echo", "character to toggle local echoing on/off", NULL, &echoc },
+#endif
+ { "escape", "character to escape back to telnet command mode", NULL, &escape },
+ { "rlogin", "rlogin escape character", 0, &rlogin },
+ { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile},
+ { " ", "", NULL, NULL },
+ { " ", "The following need 'localchars' to be toggled true", NULL, NULL },
+ { "flushoutput", "character to cause an Abort Output", NULL, termFlushCharp },
+ { "interrupt", "character to cause an Interrupt Process", NULL, termIntCharp },
+ { "quit", "character to cause an Abort process", NULL, termQuitCharp },
+ { "eof", "character to cause an EOF ", NULL, termEofCharp },
+ { " ", "", NULL, NULL },
+ { " ", "The following are for local editing in linemode", NULL, NULL },
+ { "erase", "character to use to erase a character", NULL, termEraseCharp },
+ { "kill", "character to use to erase a line", NULL, termKillCharp },
+ { "lnext", "character to use for literal next", NULL, termLiteralNextCharp },
+ { "susp", "character to cause a Suspend Process", NULL, termSuspCharp },
+ { "reprint", "character to use for line reprint", NULL, termRprntCharp },
+ { "worderase", "character to use to erase a word", NULL, termWerasCharp },
+ { "start", "character to use for XON", NULL, termStartCharp },
+ { "stop", "character to use for XOFF", NULL, termStopCharp },
+ { "forw1", "alternate end of line character", NULL, termForw1Charp },
+ { "forw2", "alternate end of line character", NULL, termForw2Charp },
+ { "ayt", "alternate AYT character", NULL, termAytCharp },
+ { NULL, NULL, NULL, NULL }
+};
+
+static struct setlist *
+getset(char *name)
+{
+ return (struct setlist *)
+ genget(name, (char **) Setlist, sizeof(struct setlist));
+}
+
+void
+set_escape_char(char *s)
+{
+ if (rlogin != _POSIX_VDISABLE) {
+ rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
+ printf("Telnet rlogin escape character is '%s'.\n",
+ control(rlogin));
+ } else {
+ escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
+ printf("Telnet escape character is '%s'.\n", control(escape));
+ }
+}
+
+static int
+setcmd(int argc, char *argv[])
+{
+ int value;
+ struct setlist *ct;
+ struct togglelist *c;
+
+ if (argc < 2 || argc > 3) {
+ printf("Format is 'set Name Value'\n'set ?' for help.\n");
+ return 0;
+ }
+ if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
+ for (ct = Setlist; ct->name; ct++)
+ printf("%-15s %s\n", ct->name, ct->help);
+ printf("\n");
+ settogglehelp(1);
+ printf("%-15s %s\n", "?", "display help information");
+ return 0;
+ }
+
+ ct = getset(argv[1]);
+ if (ct == 0) {
+ c = GETTOGGLE(argv[1]);
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('set ?' for help).\n",
+ argv[1]);
+ return 0;
+ } else if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (c->variable) {
+ if ((argc == 2) || (strcmp("on", argv[2]) == 0))
+ *c->variable = 1;
+ else if (strcmp("off", argv[2]) == 0)
+ *c->variable = 0;
+ else {
+ printf("Format is 'set togglename [on|off]'\n'set ?' for help.\n");
+ return 0;
+ }
+ if (c->actionexplanation) {
+ printf("%s %s.\n", *c->variable? "Will" : "Won't",
+ c->actionexplanation);
+ }
+ }
+ if (c->handler)
+ (*c->handler)(1);
+ } else if (argc != 3) {
+ printf("Format is 'set Name Value'\n'set ?' for help.\n");
+ return 0;
+ } else if (Ambiguous((void *)ct)) {
+ fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\n",
+ argv[1]);
+ return 0;
+ } else if (ct->handler) {
+ (*ct->handler)(argv[2]);
+ printf("%s set to \"%s\".\n", ct->name, (char *)ct->charp);
+ } else {
+ if (strcmp("off", argv[2])) {
+ value = special(argv[2]);
+ } else {
+ value = _POSIX_VDISABLE;
+ }
+ *(ct->charp) = (cc_t)value;
+ printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
+ }
+ slc_check();
+ return 1;
+}
+
+static int
+unsetcmd(int argc, char *argv[])
+{
+ struct setlist *ct;
+ struct togglelist *c;
+ char *name;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'unset' command. 'unset ?' for help.\n");
+ return 0;
+ }
+ if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
+ for (ct = Setlist; ct->name; ct++)
+ printf("%-15s %s\n", ct->name, ct->help);
+ printf("\n");
+ settogglehelp(0);
+ printf("%-15s %s\n", "?", "display help information");
+ return 0;
+ }
+
+ argc--;
+ argv++;
+ while (argc--) {
+ name = *argv++;
+ ct = getset(name);
+ if (ct == 0) {
+ c = GETTOGGLE(name);
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\n",
+ name);
+ return 0;
+ } else if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
+ name);
+ return 0;
+ }
+ if (c->variable) {
+ *c->variable = 0;
+ if (c->actionexplanation) {
+ printf("%s %s.\n", *c->variable? "Will" : "Won't",
+ c->actionexplanation);
+ }
+ }
+ if (c->handler)
+ (*c->handler)(0);
+ } else if (Ambiguous((void *)ct)) {
+ fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\n",
+ name);
+ return 0;
+ } else if (ct->handler) {
+ (*ct->handler)(0);
+ printf("%s reset to \"%s\".\n", ct->name, (char *)ct->charp);
+ } else {
+ *(ct->charp) = _POSIX_VDISABLE;
+ printf("%s character is '%s'.\n", ct->name, control(*(ct->charp)));
+ }
+ }
+ return 1;
+}
+
+/*
+ * The following are the data structures and routines for the
+ * 'mode' command.
+ */
+#ifdef KLUDGELINEMODE
+extern int kludgelinemode;
+
+static int
+dokludgemode(void)
+{
+ kludgelinemode = 1;
+ send_wont(TELOPT_LINEMODE, 1);
+ send_dont(TELOPT_SGA, 1);
+ send_dont(TELOPT_ECHO, 1);
+ return 1;
+}
+#endif
+
+static int
+dolinemode(void)
+{
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode)
+ send_dont(TELOPT_SGA, 1);
+#endif
+ send_will(TELOPT_LINEMODE, 1);
+ send_dont(TELOPT_ECHO, 1);
+ return 1;
+}
+
+static int
+docharmode(void)
+{
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode)
+ send_do(TELOPT_SGA, 1);
+ else
+#endif
+ send_wont(TELOPT_LINEMODE, 1);
+ send_do(TELOPT_ECHO, 1);
+ return 1;
+}
+
+static int
+dolmmode(int bit, int on)
+{
+ unsigned char c;
+ extern int linemode;
+
+ if (my_want_state_is_wont(TELOPT_LINEMODE)) {
+ printf("?Need to have LINEMODE option enabled first.\n");
+ printf("'mode ?' for help.\n");
+ return 0;
+ }
+
+ if (on)
+ c = (linemode | bit);
+ else
+ c = (linemode & ~bit);
+ lm_mode(&c, 1, 1);
+ return 1;
+}
+
+static int
+setmod(int bit)
+{
+ return dolmmode(bit, 1);
+}
+
+static int
+clearmode(int bit)
+{
+ return dolmmode(bit, 0);
+}
+
+struct modelist {
+ const char *name; /* command name */
+ const char *help; /* help string */
+ int (*handler)(int);/* routine which executes command */
+ int needconnect; /* Do we need to be connected to execute? */
+ int arg1;
+};
+
+static struct modelist ModeList[] = {
+ { "character", "Disable LINEMODE option", (int (*)(int))docharmode, 1, 0 },
+#ifdef KLUDGELINEMODE
+ { "", "(or disable obsolete line-by-line mode)", NULL, 0, 0 },
+#endif
+ { "line", "Enable LINEMODE option", (int (*)(int))dolinemode, 1, 0 },
+#ifdef KLUDGELINEMODE
+ { "", "(or enable obsolete line-by-line mode)", NULL, 0, 0 },
+#endif
+ { "", "", NULL, 0, 0 },
+ { "", "These require the LINEMODE option to be enabled", NULL, 0, 0 },
+ { "isig", "Enable signal trapping", setmod, 1, MODE_TRAPSIG },
+ { "+isig", 0, setmod, 1, MODE_TRAPSIG },
+ { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG },
+ { "edit", "Enable character editing", setmod, 1, MODE_EDIT },
+ { "+edit", 0, setmod, 1, MODE_EDIT },
+ { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT },
+ { "softtabs", "Enable tab expansion", setmod, 1, MODE_SOFT_TAB },
+ { "+softtabs", 0, setmod, 1, MODE_SOFT_TAB },
+ { "-softtabs", "Disable character editing", clearmode, 1, MODE_SOFT_TAB },
+ { "litecho", "Enable literal character echo", setmod, 1, MODE_LIT_ECHO },
+ { "+litecho", 0, setmod, 1, MODE_LIT_ECHO },
+ { "-litecho", "Disable literal character echo", clearmode, 1, MODE_LIT_ECHO },
+ { "help", 0, (int (*)(int))modehelp, 0, 0 },
+#ifdef KLUDGELINEMODE
+ { "kludgeline", 0, (int (*)(int))dokludgemode, 1, 0 },
+#endif
+ { "", "", NULL, 0, 0 },
+ { "?", "Print help information", (int (*)(int))modehelp, 0, 0 },
+ { NULL, NULL, NULL, 0, 0 },
+};
+
+
+static int
+modehelp(void)
+{
+ struct modelist *mt;
+
+ printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
+ for (mt = ModeList; mt->name; mt++) {
+ if (mt->help) {
+ if (*mt->help)
+ printf("%-15s %s\n", mt->name, mt->help);
+ else
+ printf("\n");
+ }
+ }
+ return 0;
+}
+
+#define GETMODECMD(name) (struct modelist *) \
+ genget(name, (char **) ModeList, sizeof(struct modelist))
+
+static int
+modecmd(int argc, char *argv[])
+{
+ struct modelist *mt;
+
+ if (argc != 2) {
+ printf("'mode' command requires an argument\n");
+ printf("'mode ?' for help.\n");
+ } else if ((mt = GETMODECMD(argv[1])) == 0) {
+ fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
+ } else if (Ambiguous((void *)mt)) {
+ fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
+ } else if (mt->needconnect && !connected) {
+ printf("?Need to be connected first.\n");
+ printf("'mode ?' for help.\n");
+ } else if (mt->handler) {
+ return (*mt->handler)(mt->arg1);
+ }
+ return 0;
+}
+
+/*
+ * The following data structures and routines implement the
+ * "display" command.
+ */
+
+static int
+display(int argc, char *argv[])
+{
+ struct togglelist *tl;
+ struct setlist *sl;
+
+#define dotog(tl) if (tl->variable && tl->actionexplanation) { \
+ if (*tl->variable) { \
+ printf("will"); \
+ } else { \
+ printf("won't"); \
+ } \
+ printf(" %s.\n", tl->actionexplanation); \
+ }
+
+#define doset(sl) if (sl->name && *sl->name != ' ') { \
+ if (sl->handler == 0) \
+ printf("%-15s [%s]\n", sl->name, control(*sl->charp)); \
+ else \
+ printf("%-15s \"%s\"\n", sl->name, (char *)sl->charp); \
+ }
+
+ if (argc == 1) {
+ for (tl = Togglelist; tl->name; tl++) {
+ dotog(tl);
+ }
+ printf("\n");
+ for (sl = Setlist; sl->name; sl++) {
+ doset(sl);
+ }
+ } else {
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ sl = getset(argv[i]);
+ tl = GETTOGGLE(argv[i]);
+ if (Ambiguous((void *)sl) || Ambiguous((void *)tl)) {
+ printf("?Ambiguous argument '%s'.\n", argv[i]);
+ return 0;
+ } else if (!sl && !tl) {
+ printf("?Unknown argument '%s'.\n", argv[i]);
+ return 0;
+ } else {
+ if (tl) {
+ dotog(tl);
+ }
+ if (sl) {
+ doset(sl);
+ }
+ }
+ }
+ }
+/*@*/optionstatus();
+#ifdef ENCRYPTION
+ EncryptStatus();
+#endif /* ENCRYPTION */
+ return 1;
+#undef doset
+#undef dotog
+}
+
+/*
+ * The following are the data structures, and many of the routines,
+ * relating to command processing.
+ */
+
+/*
+ * Set the escape character.
+ */
+static int
+setescape(int argc, char *argv[])
+{
+ char *arg;
+ char buf[50];
+
+ printf(
+ "Deprecated usage - please use 'set escape%s%s' in the future.\n",
+ (argc > 2)? " ":"", (argc > 2)? argv[1]: "");
+ if (argc > 2)
+ arg = argv[1];
+ else {
+ printf("new escape character: ");
+ (void) fgets(buf, sizeof(buf), stdin);
+ arg = buf;
+ }
+ if (arg[0] != '\0')
+ escape = arg[0];
+ (void) fflush(stdout);
+ return 1;
+}
+
+static int
+togcrmod(void)
+{
+ crmod = !crmod;
+ printf("Deprecated usage - please use 'toggle crmod' in the future.\n");
+ printf("%s map carriage return on output.\n", crmod ? "Will" : "Won't");
+ (void) fflush(stdout);
+ return 1;
+}
+
+static int
+suspend(void)
+{
+#ifdef SIGTSTP
+ setcommandmode();
+ {
+ long oldrows, oldcols, newrows, newcols, err_;
+
+ err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
+ (void) kill(0, SIGTSTP);
+ /*
+ * If we didn't get the window size before the SUSPEND, but we
+ * can get them now (?), then send the NAWS to make sure that
+ * we are set up for the right window size.
+ */
+ if (TerminalWindowSize(&newrows, &newcols) && connected &&
+ (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
+ sendnaws();
+ }
+ }
+ /* reget parameters in case they were changed */
+ TerminalSaveState();
+ setconnmode(0);
+#else
+ printf("Suspend is not supported. Try the '!' command instead\n");
+#endif
+ return 1;
+}
+
+static int
+shell(int argc, char *argv[] __unused)
+{
+ long oldrows, oldcols, newrows, newcols, err_;
+
+ setcommandmode();
+
+ err_ = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
+ switch(vfork()) {
+ case -1:
+ perror("Fork failed\n");
+ break;
+
+ case 0:
+ {
+ /*
+ * Fire up the shell in the child.
+ */
+ const char *shellp, *shellname;
+
+ shellp = getenv("SHELL");
+ if (shellp == NULL)
+ shellp = "/bin/sh";
+ if ((shellname = strrchr(shellp, '/')) == 0)
+ shellname = shellp;
+ else
+ shellname++;
+ if (argc > 1)
+ execl(shellp, shellname, "-c", &saveline[1], (char *)0);
+ else
+ execl(shellp, shellname, (char *)0);
+ perror("Execl");
+ _exit(1);
+ }
+ default:
+ (void)wait((int *)0); /* Wait for the shell to complete */
+
+ if (TerminalWindowSize(&newrows, &newcols) && connected &&
+ (err_ || ((oldrows != newrows) || (oldcols != newcols)))) {
+ sendnaws();
+ }
+ break;
+ }
+ return 1;
+}
+
+static int
+bye(int argc, char *argv[])
+{
+ extern int resettermname;
+
+ if (connected) {
+ (void) shutdown(net, 2);
+ printf("Connection closed.\n");
+ (void) NetClose(net);
+ connected = 0;
+ resettermname = 1;
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+ auth_encrypt_connect(connected);
+#endif
+#endif
+ /* reset options */
+ tninit();
+ }
+ if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
+ longjmp(toplevel, 1);
+ /* NOTREACHED */
+ }
+ return 1; /* Keep lint, etc., happy */
+}
+
+void
+quit(void)
+{
+ (void) call(bye, "bye", "fromquit", 0);
+ Exit(0);
+}
+
+static int
+logout(void)
+{
+ send_do(TELOPT_LOGOUT, 1);
+ (void) netflush();
+ return 1;
+}
+
+
+/*
+ * The SLC command.
+ */
+
+struct slclist {
+ const char *name;
+ const char *help;
+ void (*handler)(int);
+ int arg;
+};
+
+static void slc_help(void);
+
+struct slclist SlcList[] = {
+ { "export", "Use local special character definitions",
+ (void (*)(int))slc_mode_export, 0 },
+ { "import", "Use remote special character definitions",
+ slc_mode_import, 1 },
+ { "check", "Verify remote special character definitions",
+ slc_mode_import, 0 },
+ { "help", NULL, (void (*)(int))slc_help, 0 },
+ { "?", "Print help information", (void (*)(int))slc_help, 0 },
+ { NULL, NULL, NULL, 0 },
+};
+
+static void
+slc_help(void)
+{
+ struct slclist *c;
+
+ for (c = SlcList; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+}
+
+static struct slclist *
+getslc(char *name)
+{
+ return (struct slclist *)
+ genget(name, (char **) SlcList, sizeof(struct slclist));
+}
+
+static int
+slccmd(int argc, char *argv[])
+{
+ struct slclist *c;
+
+ if (argc != 2) {
+ fprintf(stderr,
+ "Need an argument to 'slc' command. 'slc ?' for help.\n");
+ return 0;
+ }
+ c = getslc(argv[1]);
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ (*c->handler)(c->arg);
+ slcstate();
+ return 1;
+}
+
+/*
+ * The ENVIRON command.
+ */
+
+struct envlist {
+ const char *name;
+ const char *help;
+ void (*handler)(unsigned char *, unsigned char *);
+ int narg;
+};
+
+extern struct env_lst *
+ env_define(const unsigned char *, unsigned char *);
+extern void
+ env_undefine(unsigned char *),
+ env_export(const unsigned char *),
+ env_unexport(const unsigned char *),
+ env_send(unsigned char *),
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+ env_varval(unsigned char *),
+#endif
+ env_list(void);
+static void
+ env_help(void);
+
+struct envlist EnvList[] = {
+ { "define", "Define an environment variable",
+ (void (*)(unsigned char *, unsigned char *))env_define, 2 },
+ { "undefine", "Undefine an environment variable",
+ (void (*)(unsigned char *, unsigned char *))env_undefine, 1 },
+ { "export", "Mark an environment variable for automatic export",
+ (void (*)(unsigned char *, unsigned char *))env_export, 1 },
+ { "unexport", "Don't mark an environment variable for automatic export",
+ (void (*)(unsigned char *, unsigned char *))env_unexport, 1 },
+ { "send", "Send an environment variable", (void (*)(unsigned char *, unsigned char *))env_send, 1 },
+ { "list", "List the current environment variables",
+ (void (*)(unsigned char *, unsigned char *))env_list, 0 },
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+ { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
+ (void (*)(unsigned char *, unsigned char *))env_varval, 1 },
+#endif
+ { "help", NULL, (void (*)(unsigned char *, unsigned char *))env_help, 0 },
+ { "?", "Print help information", (void (*)(unsigned char *, unsigned char *))env_help, 0 },
+ { NULL, NULL, NULL, 0 },
+};
+
+static void
+env_help(void)
+{
+ struct envlist *c;
+
+ for (c = EnvList; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+}
+
+static struct envlist *
+getenvcmd(char *name)
+{
+ return (struct envlist *)
+ genget(name, (char **) EnvList, sizeof(struct envlist));
+}
+
+static int
+env_cmd(int argc, char *argv[])
+{
+ struct envlist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'environ' command. 'environ ?' for help.\n");
+ return 0;
+ }
+ c = getenvcmd(argv[1]);
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (c->narg + 2 != argc && strcasecmp(argv[1],"define")==0 && c->narg + 1 != argc) {
+ fprintf(stderr,
+ "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n",
+ c->narg < argc + 2 ? "only " : "",
+ c->narg, c->narg == 1 ? "" : "s", c->name);
+ return 0;
+ }
+ (*c->handler)((unsigned char *)argv[2], (unsigned char *)argv[3]);
+ return 1;
+}
+
+struct env_lst {
+ struct env_lst *next; /* pointer to next structure */
+ struct env_lst *prev; /* pointer to previous structure */
+ unsigned char *var; /* pointer to variable name */
+ unsigned char *value; /* pointer to variable value */
+ int export; /* 1 -> export with default list of variables */
+ int welldefined; /* A well defined variable */
+};
+
+struct env_lst envlisthead;
+
+static struct env_lst *
+env_find(const unsigned char *var)
+{
+ struct env_lst *ep;
+
+ for (ep = envlisthead.next; ep; ep = ep->next) {
+ if (strcmp((const char *)ep->var, (const char *)var) == 0)
+ return(ep);
+ }
+ return(NULL);
+}
+
+void
+env_init(void)
+{
+ char *ev;
+ struct env_lst *ep;
+ int i;
+
+ const char *safe_vars[]=
+ {"USER", "PRINTER", "DISPLAY", "TERM", "COLUMNS", "LINES"};
+
+ for(i=0;i<sizeof(safe_vars)/sizeof(const char *);i++) {
+ if((ev=getenv(safe_vars[i]))) {
+ ep=env_define((unsigned char *)safe_vars[i],(unsigned char *)ev);
+ ep->export=0;
+ }
+ }
+
+ /*
+ * Special case for DISPLAY variable. If it is ":0.0" or
+ * "unix:0.0", we have to get rid of "unix" and insert our
+ * hostname.
+ */
+ if ((ep = env_find((const unsigned char *)"DISPLAY"))
+ && ((*ep->value == ':')
+ || (strncmp((char *)ep->value, "unix:", 5) == 0))) {
+ char hbuf[256+1];
+ char *cp, *cp2 = strchr((char *)ep->value, ':');
+
+ gethostname(hbuf, 256);
+ hbuf[256] = '\0';
+ cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1);
+ sprintf((char *)cp, "%s%s", hbuf, cp2);
+ free(ep->value);
+ ep->value = (unsigned char *)cp;
+ }
+ /*
+ * If USER is not defined, but LOGNAME is, then add
+ * USER with the value from LOGNAME. By default, we
+ * don't export the USER variable.
+ */
+ if ((env_find((const unsigned char *)"USER") == NULL) && (ep = env_find((const unsigned char *)"LOGNAME"))) {
+ env_define((const unsigned char *)"USER", ep->value);
+ env_unexport((const unsigned char *)"USER");
+ }
+ env_export((const unsigned char *)"DISPLAY");
+ env_export((const unsigned char *)"PRINTER");
+}
+
+struct env_lst *
+env_define(const unsigned char *var, unsigned char *value)
+{
+ char *ev;
+ struct env_lst *ep;
+
+ if ((ep = env_find(var))) {
+ if (ep->var)
+ free(ep->var);
+ if (ep->value)
+ free(ep->value);
+ } else {
+ ep = (struct env_lst *)malloc(sizeof(struct env_lst));
+ ep->next = envlisthead.next;
+ envlisthead.next = ep;
+ ep->prev = &envlisthead;
+ if (ep->next)
+ ep->next->prev = ep;
+ }
+
+ ep->welldefined = opt_welldefined((const char *)var);
+ ep->export = 1;
+ ep->var = (unsigned char *)strdup((const char *)var);
+
+ if(value)
+ ep->value = (unsigned char *)strdup((const char *)value);
+ else if((ev=getenv((const char *)var)))
+ ep->value = (unsigned char *)strdup(ev);
+ else ep->value = (unsigned char *)strdup("");
+ return(ep);
+}
+
+void
+env_undefine(unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if ((ep = env_find(var))) {
+ ep->prev->next = ep->next;
+ if (ep->next)
+ ep->next->prev = ep->prev;
+ if (ep->var)
+ free(ep->var);
+ if (ep->value)
+ free(ep->value);
+ free(ep);
+ }
+}
+
+void
+env_export(const unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if ((ep = env_find(var)))
+ ep->export = 1;
+}
+
+void
+env_unexport(const unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if ((ep = env_find(var)))
+ ep->export = 0;
+}
+
+void
+env_send(unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if (my_state_is_wont(TELOPT_NEW_ENVIRON)
+#ifdef OLD_ENVIRON
+ && my_state_is_wont(TELOPT_OLD_ENVIRON)
+#endif
+ ) {
+ fprintf(stderr,
+ "Cannot send '%s': Telnet ENVIRON option not enabled\n",
+ var);
+ return;
+ }
+ ep = env_find(var);
+ if (ep == 0) {
+ fprintf(stderr, "Cannot send '%s': variable not defined\n",
+ var);
+ return;
+ }
+ env_opt_start_info();
+ env_opt_add(ep->var);
+ env_opt_end(0);
+}
+
+void
+env_list(void)
+{
+ struct env_lst *ep;
+
+ for (ep = envlisthead.next; ep; ep = ep->next) {
+ printf("%c %-20s %s\n", ep->export ? '*' : ' ',
+ ep->var, ep->value);
+ }
+}
+
+unsigned char *
+env_default(int init, int welldefined)
+{
+ static struct env_lst *nep = NULL;
+
+ if (init) {
+ nep = &envlisthead;
+ return(NULL);
+ }
+ if (nep) {
+ while ((nep = nep->next)) {
+ if (nep->export && (nep->welldefined == welldefined))
+ return(nep->var);
+ }
+ }
+ return(NULL);
+}
+
+unsigned char *
+env_getvalue(const unsigned char *var)
+{
+ struct env_lst *ep;
+
+ if ((ep = env_find(var)))
+ return(ep->value);
+ return(NULL);
+}
+
+#if defined(OLD_ENVIRON) && defined(ENV_HACK)
+void
+env_varval(unsigned char *what)
+{
+ extern int old_env_var, old_env_value, env_auto;
+ int len = strlen((char *)what);
+
+ if (len == 0)
+ goto unknown;
+
+ if (strncasecmp((char *)what, "status", len) == 0) {
+ if (env_auto)
+ printf("%s%s", "VAR and VALUE are/will be ",
+ "determined automatically\n");
+ if (old_env_var == OLD_ENV_VAR)
+ printf("VAR and VALUE set to correct definitions\n");
+ else
+ printf("VAR and VALUE definitions are reversed\n");
+ } else if (strncasecmp((char *)what, "auto", len) == 0) {
+ env_auto = 1;
+ old_env_var = OLD_ENV_VALUE;
+ old_env_value = OLD_ENV_VAR;
+ } else if (strncasecmp((char *)what, "right", len) == 0) {
+ env_auto = 0;
+ old_env_var = OLD_ENV_VAR;
+ old_env_value = OLD_ENV_VALUE;
+ } else if (strncasecmp((char *)what, "wrong", len) == 0) {
+ env_auto = 0;
+ old_env_var = OLD_ENV_VALUE;
+ old_env_value = OLD_ENV_VAR;
+ } else {
+unknown:
+ printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n");
+ }
+}
+#endif
+
+#ifdef AUTHENTICATION
+/*
+ * The AUTHENTICATE command.
+ */
+
+struct authlist {
+ const char *name;
+ const char *help;
+ int (*handler)(char *);
+ int narg;
+};
+
+extern int
+ auth_enable(char *),
+ auth_disable(char *),
+ auth_status(void);
+static int
+ auth_help(void);
+
+struct authlist AuthList[] = {
+ { "status", "Display current status of authentication information",
+ (int (*)(char *))auth_status, 0 },
+ { "disable", "Disable an authentication type ('auth disable ?' for more)",
+ auth_disable, 1 },
+ { "enable", "Enable an authentication type ('auth enable ?' for more)",
+ auth_enable, 1 },
+ { "help", NULL, (int (*)(char *))auth_help, 0 },
+ { "?", "Print help information", (int (*)(char *))auth_help, 0 },
+ { NULL, NULL, NULL, 0 },
+};
+
+static int
+auth_help(void)
+{
+ struct authlist *c;
+
+ for (c = AuthList; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+ return 0;
+}
+
+int
+auth_cmd(int argc, char *argv[])
+{
+ struct authlist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'auth' command. 'auth ?' for help.\n");
+ return 0;
+ }
+
+ c = (struct authlist *)
+ genget(argv[1], (char **) AuthList, sizeof(struct authlist));
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (c->narg + 2 != argc) {
+ fprintf(stderr,
+ "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n",
+ c->narg < argc + 2 ? "only " : "",
+ c->narg, c->narg == 1 ? "" : "s", c->name);
+ return 0;
+ }
+ return((*c->handler)(argv[2]));
+}
+#endif
+
+#ifdef ENCRYPTION
+/*
+ * The ENCRYPT command.
+ */
+
+struct encryptlist {
+ const char *name;
+ const char *help;
+ int (*handler)(char *, char *);
+ int needconnect;
+ int minarg;
+ int maxarg;
+};
+
+extern int
+ EncryptEnable(char *, char *),
+ EncryptDisable(char *, char *),
+ EncryptType(char *, char *),
+ EncryptStart(char *),
+ EncryptStartInput(void),
+ EncryptStartOutput(void),
+ EncryptStop(char *),
+ EncryptStopInput(void),
+ EncryptStopOutput(void),
+ EncryptStatus(void);
+static int
+ EncryptHelp(void);
+
+struct encryptlist EncryptList[] = {
+ { "enable", "Enable encryption. ('encrypt enable ?' for more)",
+ EncryptEnable, 1, 1, 2 },
+ { "disable", "Disable encryption. ('encrypt enable ?' for more)",
+ EncryptDisable, 0, 1, 2 },
+ { "type", "Set encryption type. ('encrypt type ?' for more)",
+ EncryptType, 0, 1, 1 },
+ { "start", "Start encryption. ('encrypt start ?' for more)",
+ (int (*)(char *, char *))EncryptStart, 1, 0, 1 },
+ { "stop", "Stop encryption. ('encrypt stop ?' for more)",
+ (int (*)(char *, char *))EncryptStop, 1, 0, 1 },
+ { "input", "Start encrypting the input stream",
+ (int (*)(char *, char *))EncryptStartInput, 1, 0, 0 },
+ { "-input", "Stop encrypting the input stream",
+ (int (*)(char *, char *))EncryptStopInput, 1, 0, 0 },
+ { "output", "Start encrypting the output stream",
+ (int (*)(char *, char *))EncryptStartOutput, 1, 0, 0 },
+ { "-output", "Stop encrypting the output stream",
+ (int (*)(char *, char *))EncryptStopOutput, 1, 0, 0 },
+
+ { "status", "Display current status of authentication information",
+ (int (*)(char *, char *))EncryptStatus, 0, 0, 0 },
+ { "help", NULL, (int (*)(char *, char *))EncryptHelp, 0, 0, 0 },
+ { "?", "Print help information", (int (*)(char *, char *))EncryptHelp, 0, 0, 0 },
+ { NULL, NULL, NULL, 0, 0, 0 },
+};
+
+static int
+EncryptHelp(void)
+{
+ struct encryptlist *c;
+
+ for (c = EncryptList; c->name; c++) {
+ if (c->help) {
+ if (*c->help)
+ printf("%-15s %s\n", c->name, c->help);
+ else
+ printf("\n");
+ }
+ }
+ return 0;
+}
+
+static int
+encrypt_cmd(int argc, char *argv[])
+{
+ struct encryptlist *c;
+
+ if (argc < 2) {
+ fprintf(stderr,
+ "Need an argument to 'encrypt' command. 'encrypt ?' for help.\n");
+ return 0;
+ }
+
+ c = (struct encryptlist *)
+ genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist));
+ if (c == 0) {
+ fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ if (Ambiguous((void *)c)) {
+ fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\n",
+ argv[1]);
+ return 0;
+ }
+ argc -= 2;
+ if (argc < c->minarg || argc > c->maxarg) {
+ if (c->minarg == c->maxarg) {
+ fprintf(stderr, "Need %s%d argument%s ",
+ c->minarg < argc ? "only " : "", c->minarg,
+ c->minarg == 1 ? "" : "s");
+ } else {
+ fprintf(stderr, "Need %s%d-%d arguments ",
+ c->maxarg < argc ? "only " : "", c->minarg, c->maxarg);
+ }
+ fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\n",
+ c->name);
+ return 0;
+ }
+ if (c->needconnect && !connected) {
+ if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
+ printf("?Need to be connected first.\n");
+ return 0;
+ }
+ }
+ return ((*c->handler)(argc > 0 ? argv[2] : 0,
+ argc > 1 ? argv[3] : 0));
+}
+#endif /* ENCRYPTION */
+
+/*
+ * Print status about the connection.
+ */
+/*ARGSUSED*/
+static int
+status(int argc, char *argv[])
+{
+ if (connected) {
+ printf("Connected to %s.\n", hostname);
+ if ((argc < 2) || strcmp(argv[1], "notmuch")) {
+ int mode = getconnmode();
+
+ if (my_want_state_is_will(TELOPT_LINEMODE)) {
+ printf("Operating with LINEMODE option\n");
+ printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No");
+ printf("%s catching of signals\n",
+ (mode&MODE_TRAPSIG) ? "Local" : "No");
+ slcstate();
+#ifdef KLUDGELINEMODE
+ } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) {
+ printf("Operating in obsolete linemode\n");
+#endif
+ } else {
+ printf("Operating in single character mode\n");
+ if (localchars)
+ printf("Catching signals locally\n");
+ }
+ printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote");
+ if (my_want_state_is_will(TELOPT_LFLOW))
+ printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No");
+#ifdef ENCRYPTION
+ encrypt_display();
+#endif /* ENCRYPTION */
+ }
+ } else {
+ printf("No connection.\n");
+ }
+ printf("Escape character is '%s'.\n", control(escape));
+ (void) fflush(stdout);
+ return 1;
+}
+
+#ifdef SIGINFO
+/*
+ * Function that gets called when SIGINFO is received.
+ */
+void
+ayt_status(void)
+{
+ (void) call(status, "status", "notmuch", 0);
+}
+#endif
+
+static const char *
+sockaddr_ntop(struct sockaddr *sa)
+{
+ void *addr;
+ static char addrbuf[INET6_ADDRSTRLEN];
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ addr = &((struct sockaddr_in *)sa)->sin_addr;
+ break;
+ case AF_UNIX:
+ addr = &((struct sockaddr_un *)sa)->sun_path;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ addr = &((struct sockaddr_in6 *)sa)->sin6_addr;
+ break;
+#endif
+ default:
+ return NULL;
+ }
+ inet_ntop(sa->sa_family, addr, addrbuf, sizeof(addrbuf));
+ return addrbuf;
+}
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+static int
+setpolicy(int lnet, struct addrinfo *res, char *policy)
+{
+ char *buf;
+ int level;
+ int optname;
+
+ if (policy == NULL)
+ return 0;
+
+ buf = ipsec_set_policy(policy, strlen(policy));
+ if (buf == NULL) {
+ printf("%s\n", ipsec_strerror());
+ return -1;
+ }
+ level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
+ optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY;
+ if (setsockopt(lnet, level, optname, buf, ipsec_get_policylen(buf)) < 0){
+ perror("setsockopt");
+ return -1;
+ }
+
+ free(buf);
+ return 0;
+}
+#endif
+
+#ifdef INET6
+/*
+ * When an Address Family related error happend, check if retry with
+ * another AF is possible or not.
+ * Return 1, if retry with another af is OK. Else, return 0.
+ */
+static int
+switch_af(struct addrinfo **aip)
+{
+ int nextaf;
+ struct addrinfo *ai;
+
+ ai = *aip;
+ nextaf = (ai->ai_family == AF_INET) ? AF_INET6 : AF_INET;
+ do
+ ai=ai->ai_next;
+ while (ai != NULL && ai->ai_family != nextaf);
+ *aip = ai;
+ if (*aip != NULL) {
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+int
+tn(int argc, char *argv[])
+{
+ char *srp = 0;
+ int proto = 0, opt = 0;
+ int srlen = 0;
+#ifndef __APPLE__
+ int srcroute = 0, result;
+#else
+ int srcroute = 0;
+#endif
+ char *cmd, *hostp = 0, *portp = 0, *user = 0;
+ char *src_addr = NULL;
+ struct addrinfo hints, *res, *res0 = NULL, *src_res, *src_res0 = NULL;
+ int error = 0, af_error = 0;
+
+ if (connected) {
+ printf("?Already connected to %s\n", hostname);
+ setuid(getuid());
+ return 0;
+ }
+ if (argc < 2) {
+ (void) strcpy(line, "open ");
+ printf("(to) ");
+ (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ cmd = *argv;
+ --argc; ++argv;
+ while (argc) {
+ if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
+ goto usage;
+ if (strcmp(*argv, "-l") == 0) {
+ --argc; ++argv;
+ if (argc == 0)
+ goto usage;
+ user = *argv++;
+ --argc;
+ continue;
+ }
+ if (strcmp(*argv, "-a") == 0) {
+ --argc; ++argv;
+ autologin = 1;
+ continue;
+ }
+ if (strcmp(*argv, "-s") == 0) {
+ --argc; ++argv;
+ if (argc == 0)
+ goto usage;
+ src_addr = *argv++;
+ --argc;
+ continue;
+ }
+ if (hostp == 0) {
+ hostp = *argv++;
+ --argc;
+ continue;
+ }
+ if (portp == 0) {
+ portp = *argv++;
+ --argc;
+ continue;
+ }
+ usage:
+ printf("usage: %s [-l user] [-a] [-s src_addr] host-name [port]\n", cmd);
+ setuid(getuid());
+ return 0;
+ }
+ if (hostp == 0)
+ goto usage;
+
+ if (src_addr != NULL) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(src_addr, 0, &hints, &src_res);
+#ifdef EAI_NODATA
+ if ((error == EAI_NODATA) || (error == EAI_NONAME))
+#else
+ if (error == EAI_NONAME)
+#endif
+ {
+ hints.ai_flags = 0;
+ error = getaddrinfo(src_addr, 0, &hints, &src_res);
+ }
+ if (error != 0) {
+ fprintf(stderr, "%s: %s\n", src_addr, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "%s: %s\n", src_addr, strerror(errno));
+ setuid(getuid());
+ return 0;
+ }
+ src_res0 = src_res;
+ }
+ if (hostp[0] == '/') {
+ struct sockaddr_un su;
+
+ if (strlen(hostp) >= sizeof(su.sun_path)) {
+ fprintf(stderr, "hostname too long for unix domain socket: %s",
+ hostp);
+ goto fail;
+ }
+ memset(&su, 0, sizeof su);
+ su.sun_family = AF_UNIX;
+ strncpy(su.sun_path, hostp, sizeof su.sun_path);
+ printf("Trying %s...\n", hostp);
+ net = socket(PF_UNIX, SOCK_STREAM, 0);
+ if ( net < 0) {
+ perror("socket");
+ goto fail;
+ }
+ if (connect(net, (struct sockaddr *)&su, sizeof su) == -1) {
+ perror(su.sun_path);
+ (void) NetClose(net);
+ goto fail;
+ }
+ goto af_unix;
+ } else if (hostp[0] == '@' || hostp[0] == '!') {
+ if (
+#ifdef INET6
+ family == AF_INET6 ||
+#endif
+ (hostname = strrchr(hostp, ':')) == NULL)
+ hostname = strrchr(hostp, '@');
+ if (hostname == NULL) {
+ hostname = hostp;
+ } else {
+ hostname++;
+ srcroute = 1;
+ }
+ } else
+ hostname = hostp;
+ if (!portp) {
+ telnetport = 1;
+ portp = strdup("telnet");
+ } else if (*portp == '-') {
+ portp++;
+ telnetport = 1;
+ } else if (*portp == '+') {
+ portp++;
+ telnetport = -1;
+ } else
+ telnetport = 0;
+
+#ifdef __APPLE__
+ {
+ /*
+ * 5760578: Attempt to convert service name to a
+ * numeric port before calling getaddrinfo().
+ */
+ struct servent *srv = getservbyname(portp, NULL);
+ if (srv != NULL) {
+ asprintf(&portp, "%d", ntohs(srv->s_port));
+ }
+ }
+#endif /* __APPLE__ */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_NUMERICHOST;
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(hostname, portp, &hints, &res);
+ if (error) {
+ hints.ai_flags = AI_CANONNAME;
+ error = getaddrinfo(hostname, portp, &hints, &res);
+ }
+ if (error != 0) {
+ fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "%s: %s\n", hostname, strerror(errno));
+ setuid(getuid());
+ goto fail;
+ }
+ if (hints.ai_flags == AI_NUMERICHOST) {
+ /* hostname has numeric */
+ int gni_err = 1;
+
+ if (doaddrlookup)
+ gni_err = getnameinfo(res->ai_addr, res->ai_addr->sa_len,
+ _hostname, sizeof(_hostname) - 1, NULL, 0,
+ NI_NAMEREQD);
+ if (gni_err != 0)
+ (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
+ _hostname[sizeof(_hostname)-1] = '\0';
+ hostname = _hostname;
+ } else {
+ /* hostname has FQDN */
+ if (srcroute != 0)
+ (void) strncpy(_hostname, hostname, sizeof(_hostname) - 1);
+ else if (res->ai_canonname != NULL)
+ strncpy(_hostname, res->ai_canonname, sizeof(_hostname) - 1);
+ else
+ (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);
+ _hostname[sizeof(_hostname)-1] = '\0';
+ hostname = _hostname;
+ }
+ res0 = res;
+ #ifdef INET6
+ af_again:
+ #endif
+#ifndef __APPLE__
+ if (srcroute != 0) {
+ static char hostbuf[BUFSIZ];
+
+ if (af_error == 0) { /* save intermediate hostnames for retry */
+ strncpy(hostbuf, hostp, BUFSIZ - 1);
+ hostbuf[BUFSIZ - 1] = '\0';
+ } else
+ hostp = hostbuf;
+ srp = 0;
+ result = sourceroute(res, hostp, &srp, &srlen, &proto, &opt);
+ if (result == 0) {
+#ifdef INET6
+ if (family == AF_UNSPEC && af_error == 0 &&
+ switch_af(&res) == 1) {
+ af_error = 1;
+ goto af_again;
+ }
+#endif
+ setuid(getuid());
+ goto fail;
+ } else if (result == -1) {
+ printf("Bad source route option: %s\n", hostp);
+ setuid(getuid());
+ goto fail;
+ }
+ }
+#endif
+ do {
+ printf("Trying %s...\n", sockaddr_ntop(res->ai_addr));
+ net = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ setuid(getuid());
+ if (net < 0) {
+#ifdef INET6
+ if (family == AF_UNSPEC && af_error == 0 &&
+ switch_af(&res) == 1) {
+ af_error = 1;
+ goto af_again;
+ }
+#endif
+ perror("telnet: socket");
+ goto fail;
+ }
+ if (srp && setsockopt(net, proto, opt, (char *)srp, srlen) < 0)
+ perror("setsockopt (source route)");
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ if (res->ai_family == PF_INET) {
+# if defined(HAS_GETTOS)
+ struct tosent *tp;
+ if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+ tos = tp->t_tos;
+# endif
+ if (tos < 0)
+ tos = IPTOS_LOWDELAY;
+ if (tos
+ && (setsockopt(net, IPPROTO_IP, IP_TOS,
+ (char *)&tos, sizeof(int)) < 0)
+ && (errno != ENOPROTOOPT))
+ perror("telnet: setsockopt (IP_TOS) (ignored)");
+ }
+#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
+
+ if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
+ perror("setsockopt (SO_DEBUG)");
+ }
+
+ if (src_addr != NULL) {
+ for (src_res = src_res0; src_res != 0; src_res = src_res->ai_next)
+ if (src_res->ai_family == res->ai_family)
+ break;
+ if (src_res == NULL)
+ src_res = src_res0;
+ if (bind(net, src_res->ai_addr, src_res->ai_addrlen) == -1) {
+#ifdef INET6
+ if (family == AF_UNSPEC && af_error == 0 &&
+ switch_af(&res) == 1) {
+ af_error = 1;
+ (void) NetClose(net);
+ goto af_again;
+ }
+#endif
+ perror("bind");
+ (void) NetClose(net);
+ goto fail;
+ }
+ }
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ if (setpolicy(net, res, ipsec_policy_in) < 0) {
+ (void) NetClose(net);
+ goto fail;
+ }
+ if (setpolicy(net, res, ipsec_policy_out) < 0) {
+ (void) NetClose(net);
+ goto fail;
+ }
+#endif
+
+ if (connect(net, res->ai_addr, res->ai_addrlen) < 0) {
+ struct addrinfo *next;
+
+ next = res->ai_next;
+ /* If already an af failed, only try same af. */
+ if (af_error != 0)
+ while (next != NULL && next->ai_family != res->ai_family)
+ next = next->ai_next;
+ warn("connect to address %s", sockaddr_ntop(res->ai_addr));
+ if (next != NULL) {
+ res = next;
+ (void) NetClose(net);
+ continue;
+ }
+ warnx("Unable to connect to remote host");
+ (void) NetClose(net);
+ goto fail;
+ }
+ connected++;
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+ auth_encrypt_connect(connected);
+#endif
+#endif
+ } while (connected == 0);
+ freeaddrinfo(res0);
+ if (src_res0 != NULL)
+ freeaddrinfo(src_res0);
+ cmdrc(hostp, hostname);
+ af_unix:
+ connected = 1;
+ if (autologin && user == NULL) {
+ struct passwd *pw;
+
+ user = getenv("USER");
+ if (user == NULL ||
+ ((pw = getpwnam(user)) && pw->pw_uid != getuid())) {
+ if ((pw = getpwuid(getuid())))
+ user = pw->pw_name;
+ else
+ user = NULL;
+ }
+ }
+ if (user) {
+ env_define((unsigned char*)"USER", (unsigned char*)user);
+ env_export((unsigned char*)"USER");
+ }
+ (void) call(status, "status", "notmuch", 0);
+ if (setjmp(peerdied) == 0)
+ telnet(user);
+ (void) NetClose(net);
+ ExitString("Connection closed by foreign host.\n",1);
+ /*NOTREACHED*/
+ fail:
+ if (res0 != NULL)
+ freeaddrinfo(res0);
+ if (src_res0 != NULL)
+ freeaddrinfo(src_res0);
+ return 0;
+}
+
+#define HELPINDENT (sizeof ("connect"))
+
+static char
+ openhelp[] = "connect to a site",
+ closehelp[] = "close current connection",
+ logouthelp[] = "forcibly logout remote user and close the connection",
+ quithelp[] = "exit telnet",
+ statushelp[] = "print status information",
+ helphelp[] = "print help information",
+ sendhelp[] = "transmit special characters ('send ?' for more)",
+ sethelp[] = "set operating parameters ('set ?' for more)",
+ unsethelp[] = "unset operating parameters ('unset ?' for more)",
+ togglestring[] ="toggle operating parameters ('toggle ?' for more)",
+ slchelp[] = "change state of special charaters ('slc ?' for more)",
+ displayhelp[] = "display operating parameters",
+#ifdef AUTHENTICATION
+ authhelp[] = "turn on (off) authentication ('auth ?' for more)",
+#endif
+#ifdef ENCRYPTION
+ encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)",
+#endif /* ENCRYPTION */
+ zhelp[] = "suspend telnet",
+#ifdef OPIE
+ opiehelp[] = "compute response to OPIE challenge",
+#endif
+ shellhelp[] = "invoke a subshell",
+ envhelp[] = "change environment variables ('environ ?' for more)",
+ modestring[] = "try to enter line or character mode ('mode ?' for more)";
+
+static Command cmdtab[] = {
+ { "close", closehelp, bye, 1 },
+ { "logout", logouthelp, (int (*)(int, char **))logout, 1 },
+ { "display", displayhelp, display, 0 },
+ { "mode", modestring, modecmd, 0 },
+ { "telnet", openhelp, tn, 0 },
+ { "open", openhelp, tn, 0 },
+ { "quit", quithelp, (int (*)(int, char **))quit, 0 },
+ { "send", sendhelp, sendcmd, 0 },
+ { "set", sethelp, setcmd, 0 },
+ { "unset", unsethelp, unsetcmd, 0 },
+ { "status", statushelp, status, 0 },
+ { "toggle", togglestring, toggle, 0 },
+ { "slc", slchelp, slccmd, 0 },
+#ifdef AUTHENTICATION
+ { "auth", authhelp, auth_cmd, 0 },
+#endif
+#ifdef ENCRYPTION
+ { "encrypt", encrypthelp, encrypt_cmd, 0 },
+#endif /* ENCRYPTION */
+ { "z", zhelp, (int (*)(int, char **))suspend, 0 },
+ { "!", shellhelp, shell, 1 },
+ { "environ", envhelp, env_cmd, 0 },
+ { "?", helphelp, help, 0 },
+#ifdef OPIE
+ { "opie", opiehelp, opie_calc, 0 },
+#endif
+ { NULL, NULL, NULL, 0 }
+};
+
+static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead";
+static char escapehelp[] = "deprecated command -- use 'set escape' instead";
+
+static Command cmdtab2[] = {
+ { "help", 0, help, 0 },
+ { "escape", escapehelp, setescape, 0 },
+ { "crmod", crmodhelp, (int (*)(int, char **))togcrmod, 0 },
+ { NULL, NULL, NULL, 0 }
+};
+
+
+/*
+ * Call routine with argc, argv set from args (terminated by 0).
+ */
+
+static int
+call(intrtn_t routine, ...)
+{
+ va_list ap;
+ char *args[100];
+ int argno = 0;
+
+ va_start(ap, routine);
+ while ((args[argno++] = va_arg(ap, char *)) != 0);
+ va_end(ap);
+ return (*routine)(argno-1, args);
+}
+
+
+static Command *
+getcmd(char *name)
+{
+ Command *cm;
+
+ if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))))
+ return cm;
+ return (Command *) genget(name, (char **) cmdtab2, sizeof(Command));
+}
+
+void
+command(int top, const char *tbuf, int cnt)
+{
+ Command *c;
+
+ setcommandmode();
+ if (!top) {
+ putchar('\n');
+ } else {
+ (void) signal(SIGINT, SIG_DFL);
+ (void) signal(SIGQUIT, SIG_DFL);
+ }
+ for (;;) {
+ if (rlogin == _POSIX_VDISABLE)
+ printf("%s> ", prompt);
+ if (tbuf) {
+ char *cp;
+ cp = line;
+ while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
+ cnt--;
+ tbuf = 0;
+ if (cp == line || *--cp != '\n' || cp == line)
+ goto getline;
+ *cp = '\0';
+ if (rlogin == _POSIX_VDISABLE)
+ printf("%s\n", line);
+ } else {
+ getline:
+ if (rlogin != _POSIX_VDISABLE)
+ printf("%s> ", prompt);
+ if (fgets(line, sizeof(line), stdin) == NULL) {
+ if (feof(stdin) || ferror(stdin)) {
+ (void) quit();
+ /*NOTREACHED*/
+ }
+ break;
+ }
+ }
+ if (line[0] == 0)
+ break;
+ makeargv();
+ if (margv[0] == 0) {
+ break;
+ }
+ c = getcmd(margv[0]);
+ if (Ambiguous((void *)c)) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ if (c->needconnect && !connected) {
+ printf("?Need to be connected first.\n");
+ continue;
+ }
+ if ((*c->handler)(margc, margv)) {
+ break;
+ }
+ }
+ if (!top) {
+ if (!connected) {
+ longjmp(toplevel, 1);
+ /*NOTREACHED*/
+ }
+ setconnmode(0);
+ }
+}
+
+/*
+ * Help command.
+ */
+static int
+help(int argc, char *argv[])
+{
+ Command *c;
+
+ if (argc == 1) {
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c->name; c++)
+ if (c->help) {
+ printf("%-*s\t%s\n", (int)HELPINDENT, c->name,
+ c->help);
+ }
+ return 0;
+ }
+ else while (--argc > 0) {
+ char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (Ambiguous((void *)c))
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (Command *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%s\n", c->help);
+ }
+ return 0;
+}
+
+static char *rcname = 0;
+static char rcbuf[128];
+
+void
+cmdrc(char *m1, char *m2)
+{
+ Command *c;
+ FILE *rcfile;
+ int gotmachine = 0;
+ int l1 = strlen(m1);
+ int l2 = strlen(m2);
+ char m1save[MAXHOSTNAMELEN];
+
+ if (skiprc)
+ return;
+
+ strlcpy(m1save, m1, sizeof(m1save));
+ m1 = m1save;
+
+ if (rcname == 0) {
+ rcname = getenv("HOME");
+ if (rcname && (strlen(rcname) + 10) < sizeof(rcbuf))
+ strcpy(rcbuf, rcname);
+ else
+ rcbuf[0] = '\0';
+ strcat(rcbuf, "/.telnetrc");
+ rcname = rcbuf;
+ }
+
+ if ((rcfile = fopen(rcname, "r")) == 0) {
+ return;
+ }
+
+ for (;;) {
+ if (fgets(line, sizeof(line), rcfile) == NULL)
+ break;
+ if (line[0] == 0)
+ break;
+ if (line[0] == '#')
+ continue;
+ if (gotmachine) {
+ if (!isspace(line[0]))
+ gotmachine = 0;
+ }
+ if (gotmachine == 0) {
+ if (isspace(line[0]))
+ continue;
+ if (strncasecmp(line, m1, l1) == 0)
+ strncpy(line, &line[l1], sizeof(line) - l1);
+ else if (strncasecmp(line, m2, l2) == 0)
+ strncpy(line, &line[l2], sizeof(line) - l2);
+ else if (strncasecmp(line, "DEFAULT", 7) == 0)
+ strncpy(line, &line[7], sizeof(line) - 7);
+ else
+ continue;
+ if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n')
+ continue;
+ gotmachine = 1;
+ }
+ makeargv();
+ if (margv[0] == 0)
+ continue;
+ c = getcmd(margv[0]);
+ if (Ambiguous((void *)c)) {
+ printf("?Ambiguous command: %s\n", margv[0]);
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command: %s\n", margv[0]);
+ continue;
+ }
+ /*
+ * This should never happen...
+ */
+ if (c->needconnect && !connected) {
+ printf("?Need to be connected first for %s.\n", margv[0]);
+ continue;
+ }
+ (*c->handler)(margc, margv);
+ }
+ fclose(rcfile);
+}
+
+#ifndef __APPLE__
+/*
+ * Source route is handed in as
+ * [!]@hop1@hop2...[@|:]dst
+ * If the leading ! is present, it is a
+ * strict source route, otherwise it is
+ * assmed to be a loose source route.
+ *
+ * We fill in the source route option as
+ * hop1,hop2,hop3...dest
+ * and return a pointer to hop1, which will
+ * be the address to connect() to.
+ *
+ * Arguments:
+ *
+ * res: ponter to addrinfo structure which contains sockaddr to
+ * the host to connect to.
+ *
+ * arg: pointer to route list to decipher
+ *
+ * cpp: If *cpp is not equal to NULL, this is a
+ * pointer to a pointer to a character array
+ * that should be filled in with the option.
+ *
+ * lenp: pointer to an integer that contains the
+ * length of *cpp if *cpp != NULL.
+ *
+ * protop: pointer to an integer that should be filled in with
+ * appropriate protocol for setsockopt, as socket
+ * protocol family.
+ *
+ * optp: pointer to an integer that should be filled in with
+ * appropriate option for setsockopt, as socket protocol
+ * family.
+ *
+ * Return values:
+ *
+ * If the return value is 1, then all operations are
+ * successful. If the
+ * return value is -1, there was a syntax error in the
+ * option, either unknown characters, or too many hosts.
+ * If the return value is 0, one of the hostnames in the
+ * path is unknown, and *cpp is set to point to the bad
+ * hostname.
+ *
+ * *cpp: If *cpp was equal to NULL, it will be filled
+ * in with a pointer to our static area that has
+ * the option filled in. This will be 32bit aligned.
+ *
+ * *lenp: This will be filled in with how long the option
+ * pointed to by *cpp is.
+ *
+ * *protop: This will be filled in with appropriate protocol for
+ * setsockopt, as socket protocol family.
+ *
+ * *optp: This will be filled in with appropriate option for
+ * setsockopt, as socket protocol family.
+ */
+static int
+sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *lenp, int *protop, int *optp)
+{
+ static char buf[1024 + ALIGNBYTES]; /*XXX*/
+ char *cp, *cp2, *lsrp, *ep;
+ struct sockaddr_in *_sin;
+#ifdef INET6
+ struct sockaddr_in6 *sin6;
+ struct cmsghdr *cmsg = NULL;
+#endif
+ struct addrinfo hints, *res;
+ int error;
+ char c;
+
+ /*
+ * Verify the arguments, and make sure we have
+ * at least 7 bytes for the option.
+ */
+ if (cpp == NULL || lenp == NULL)
+ return -1;
+ if (*cpp != NULL) {
+ switch (ai->ai_family) {
+ case AF_INET:
+ if (*lenp < 7)
+ return -1;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if (*lenp < (int)CMSG_SPACE(sizeof(struct ip6_rthdr) +
+ sizeof(struct in6_addr)))
+ return -1;
+ break;
+#endif
+ }
+ }
+ /*
+ * Decide whether we have a buffer passed to us,
+ * or if we need to use our own static buffer.
+ */
+ if (*cpp) {
+ lsrp = *cpp;
+ ep = lsrp + *lenp;
+ } else {
+ *cpp = lsrp = (char *)ALIGN(buf);
+ ep = lsrp + 1024;
+ }
+
+ cp = arg;
+
+#ifdef INET6
+ if (ai->ai_family == AF_INET6) {
+ cmsg = inet6_rthdr_init(*cpp, IPV6_RTHDR_TYPE_0);
+ if (*cp != '@')
+ return -1;
+ *protop = IPPROTO_IPV6;
+ *optp = IPV6_PKTOPTIONS;
+ } else
+#endif
+ {
+ /*
+ * Next, decide whether we have a loose source
+ * route or a strict source route, and fill in
+ * the begining of the option.
+ */
+ if (*cp == '!') {
+ cp++;
+ *lsrp++ = IPOPT_SSRR;
+ } else
+ *lsrp++ = IPOPT_LSRR;
+
+ if (*cp != '@')
+ return -1;
+
+ lsrp++; /* skip over length, we'll fill it in later */
+ *lsrp++ = 4;
+ *protop = IPPROTO_IP;
+ *optp = IP_OPTIONS;
+ }
+
+ cp++;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = ai->ai_family;
+ hints.ai_socktype = SOCK_STREAM;
+ for (c = 0;;) {
+ if (
+#ifdef INET6
+ ai->ai_family != AF_INET6 &&
+#endif
+ c == ':')
+ cp2 = 0;
+ else for (cp2 = cp; (c = *cp2); cp2++) {
+ if (c == ',') {
+ *cp2++ = '\0';
+ if (*cp2 == '@')
+ cp2++;
+ } else if (c == '@') {
+ *cp2++ = '\0';
+ } else if (
+#ifdef INET6
+ ai->ai_family != AF_INET6 &&
+#endif
+ c == ':') {
+ *cp2++ = '\0';
+ } else
+ continue;
+ break;
+ }
+ if (!c)
+ cp2 = 0;
+
+ hints.ai_flags = AI_NUMERICHOST;
+ error = getaddrinfo(cp, NULL, &hints, &res);
+#ifdef EAI_NODATA
+ if ((error == EAI_NODATA) || (error == EAI_NONAME))
+#else
+ if (error == EAI_NONAME)
+#endif
+ {
+ hints.ai_flags = 0;
+ error = getaddrinfo(cp, NULL, &hints, &res);
+ }
+ if (error != 0) {
+ fprintf(stderr, "%s: %s\n", cp, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ fprintf(stderr, "%s: %s\n", cp,
+ strerror(errno));
+ *cpp = cp;
+ return(0);
+ }
+#ifdef INET6
+ if (res->ai_family == AF_INET6) {
+ sin6 = (struct sockaddr_in6 *)res->ai_addr;
+ inet6_rthdr_add(cmsg, &sin6->sin6_addr,
+ IPV6_RTHDR_LOOSE);
+ } else
+#endif
+ {
+ _sin = (struct sockaddr_in *)res->ai_addr;
+ memcpy(lsrp, (char *)&_sin->sin_addr, 4);
+ lsrp += 4;
+ }
+ if (cp2)
+ cp = cp2;
+ else
+ break;
+ /*
+ * Check to make sure there is space for next address
+ */
+#ifdef INET6
+ if (res->ai_family == AF_INET6) {
+ if (((char *)CMSG_DATA(cmsg) +
+ sizeof(struct ip6_rthdr) +
+ ((inet6_rthdr_segments(cmsg) + 1) *
+ sizeof(struct in6_addr))) > ep)
+ return -1;
+ } else
+#endif
+ if (lsrp + 4 > ep)
+ return -1;
+ freeaddrinfo(res);
+ }
+#ifdef INET6
+ if (res->ai_family == AF_INET6) {
+ inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE);
+ *lenp = cmsg->cmsg_len;
+ } else
+#endif
+ {
+ if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
+ *cpp = 0;
+ *lenp = 0;
+ return -1;
+ }
+ *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
+ *lenp = lsrp - *cpp;
+ }
+ freeaddrinfo(res);
+ return 1;
+}
+#endif
diff --git a/remote_cmds/telnet.tproj/defines.h b/remote_cmds/telnet.tproj/defines.h
new file mode 100644
index 0000000..d49cb2d
--- /dev/null
+++ b/remote_cmds/telnet.tproj/defines.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)defines.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/contrib/telnet/telnet/defines.h,v 1.2 2001/11/30 21:06:35 markm Exp $
+ */
+
+#define settimer(x) clocks.x = clocks.system++
+
+#define NETADD(c) { *netoring.supply = c; ring_supplied(&netoring, 1); }
+#define NET2ADD(c1,c2) { NETADD(c1); NETADD(c2); }
+#define NETBYTES() (ring_full_count(&netoring))
+#define NETROOM() (ring_empty_count(&netoring))
+
+#define TTYADD(c) if (!(SYNCHing||flushout)) { \
+ *ttyoring.supply = c; \
+ ring_supplied(&ttyoring, 1); \
+ }
+#define TTYBYTES() (ring_full_count(&ttyoring))
+#define TTYROOM() (ring_empty_count(&ttyoring))
+
+/* Various modes */
+#define MODE_LOCAL_CHARS(m) ((m)&(MODE_EDIT|MODE_TRAPSIG))
+#define MODE_LOCAL_ECHO(m) ((m)&MODE_ECHO)
+#define MODE_COMMAND_LINE(m) ((m)==-1)
+
+#define CONTROL(x) ((x)&0x1f) /* CTRL(x) is not portable */
diff --git a/remote_cmds/telnet.tproj/externs.h b/remote_cmds/telnet.tproj/externs.h
new file mode 100644
index 0000000..bc450ec
--- /dev/null
+++ b/remote_cmds/telnet.tproj/externs.h
@@ -0,0 +1,495 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)externs.h 8.3 (Berkeley) 5/30/95
+ * $FreeBSD: src/contrib/telnet/telnet/externs.h,v 1.11 2007/07/01 12:08:04 gnn Exp $
+ */
+
+#ifndef BSD
+# define BSD 43
+#endif
+
+/*
+ * ucb stdio.h defines BSD as something weird
+ */
+#if defined(sun) && defined(__svr4__)
+#define BSD 43
+#endif
+
+#ifndef USE_TERMIO
+# if BSD > 43 || defined(SYSV_TERMIO)
+# define USE_TERMIO
+# endif
+#endif
+
+#include <stdio.h>
+#include <setjmp.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#ifdef USE_TERMIO
+# ifndef VINTR
+# include <sys/termios.h>
+# endif
+# define termio termios
+#endif
+#if defined(NO_CC_T) || !defined(USE_TERMIO)
+# if !defined(USE_TERMIO)
+typedef char cc_t;
+# else
+typedef unsigned char cc_t;
+# endif
+#endif
+
+#include <string.h>
+
+#if defined(IPSEC)
+#ifdef __APPLE__
+#include <netinet6/ipsec.h>
+#else
+#include <netipsec/ipsec.h>
+#endif
+#if defined(IPSEC_POLICY_IPSEC)
+extern char *ipsec_policy_in;
+extern char *ipsec_policy_out;
+#endif
+#endif
+
+#ifndef _POSIX_VDISABLE
+# ifdef sun
+# include <sys/param.h> /* pick up VDISABLE definition, mayby */
+# endif
+# ifdef VDISABLE
+# define _POSIX_VDISABLE VDISABLE
+# else
+# define _POSIX_VDISABLE ((cc_t)'\377')
+# endif
+#endif
+
+#define SUBBUFSIZE 256
+
+#if !defined(P)
+# ifdef __STDC__
+# define P(x) x
+# else
+# define P(x) ()
+# endif
+#endif
+
+extern int
+ autologin, /* Autologin enabled */
+ skiprc, /* Don't process the ~/.telnetrc file */
+ eight, /* use eight bit mode (binary in and/or out */
+ family, /* address family of peer */
+ flushout, /* flush output */
+ connected, /* Are we connected to the other side? */
+ globalmode, /* Mode tty should be in */
+ telnetport, /* Are we connected to the telnet port? */
+ localflow, /* Flow control handled locally */
+ restartany, /* If flow control, restart output on any character */
+ localchars, /* we recognize interrupt/quit */
+ donelclchars, /* the user has set "localchars" */
+ showoptions,
+ net, /* Network file descriptor */
+ tin, /* Terminal input file descriptor */
+ tout, /* Terminal output file descriptor */
+ crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
+ autoflush, /* flush output when interrupting? */
+ autosynch, /* send interrupt characters with SYNCH? */
+ SYNCHing, /* Is the stream in telnet SYNCH mode? */
+ donebinarytoggle, /* the user has put us in binary */
+ dontlecho, /* do we suppress local echoing right now? */
+ crmod,
+ netdata, /* Print out network data flow */
+ prettydump, /* Print "netdata" output in user readable format */
+ termdata, /* Print out terminal data flow */
+ telnet_debug, /* Debug level */
+ doaddrlookup, /* do a reverse lookup? */
+ clienteof; /* Client received EOF */
+
+extern cc_t escape; /* Escape to command mode */
+extern cc_t rlogin; /* Rlogin mode escape character */
+#ifdef KLUDGELINEMODE
+extern cc_t echoc; /* Toggle local echoing */
+#endif
+
+extern char
+ *prompt; /* Prompt for command. */
+
+extern char
+ doopt[],
+ dont[],
+ will[],
+ wont[],
+ options[], /* All the little options */
+ *hostname; /* Who are we connected to? */
+#ifdef ENCRYPTION
+extern void (*encrypt_output)(unsigned char *, int);
+extern int (*decrypt_input)(int);
+#endif /* ENCRYPTION */
+
+/*
+ * We keep track of each side of the option negotiation.
+ */
+
+#define MY_STATE_WILL 0x01
+#define MY_WANT_STATE_WILL 0x02
+#define MY_STATE_DO 0x04
+#define MY_WANT_STATE_DO 0x08
+
+/*
+ * Macros to check the current state of things
+ */
+
+#define my_state_is_do(opt) (options[opt]&MY_STATE_DO)
+#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL)
+#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO)
+#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL)
+
+#define my_state_is_dont(opt) (!my_state_is_do(opt))
+#define my_state_is_wont(opt) (!my_state_is_will(opt))
+#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt))
+#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt))
+
+#define set_my_state_do(opt) {options[opt] |= MY_STATE_DO;}
+#define set_my_state_will(opt) {options[opt] |= MY_STATE_WILL;}
+#define set_my_want_state_do(opt) {options[opt] |= MY_WANT_STATE_DO;}
+#define set_my_want_state_will(opt) {options[opt] |= MY_WANT_STATE_WILL;}
+
+#define set_my_state_dont(opt) {options[opt] &= ~MY_STATE_DO;}
+#define set_my_state_wont(opt) {options[opt] &= ~MY_STATE_WILL;}
+#define set_my_want_state_dont(opt) {options[opt] &= ~MY_WANT_STATE_DO;}
+#define set_my_want_state_wont(opt) {options[opt] &= ~MY_WANT_STATE_WILL;}
+
+/*
+ * Make everything symetrical
+ */
+
+#define HIS_STATE_WILL MY_STATE_DO
+#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO
+#define HIS_STATE_DO MY_STATE_WILL
+#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL
+
+#define his_state_is_do my_state_is_will
+#define his_state_is_will my_state_is_do
+#define his_want_state_is_do my_want_state_is_will
+#define his_want_state_is_will my_want_state_is_do
+
+#define his_state_is_dont my_state_is_wont
+#define his_state_is_wont my_state_is_dont
+#define his_want_state_is_dont my_want_state_is_wont
+#define his_want_state_is_wont my_want_state_is_dont
+
+#define set_his_state_do set_my_state_will
+#define set_his_state_will set_my_state_do
+#define set_his_want_state_do set_my_want_state_will
+#define set_his_want_state_will set_my_want_state_do
+
+#define set_his_state_dont set_my_state_wont
+#define set_his_state_wont set_my_state_dont
+#define set_his_want_state_dont set_my_want_state_wont
+#define set_his_want_state_wont set_my_want_state_dont
+
+#if defined(USE_TERMIO)
+#define SIG_FUNC_RET void
+#else
+#define SIG_FUNC_RET int
+#endif
+
+#ifdef SIGINFO
+extern SIG_FUNC_RET
+ ayt_status(void);
+#endif
+
+extern FILE
+ *NetTrace; /* Where debugging output goes */
+extern unsigned char
+ NetTraceFile[]; /* Name of file where debugging output goes */
+extern void
+ SetNetTrace(char *); /* Function to change where debugging goes */
+
+extern jmp_buf
+ peerdied,
+ toplevel; /* For error conditions. */
+
+extern void
+ command(int, const char *, int),
+ Dump(char, unsigned char *, int),
+ env_init(void),
+ Exit(int),
+ ExitString(const char *, int),
+ init_network(void),
+ init_sys(void),
+ init_telnet(void),
+ init_terminal(void),
+ intp(void),
+ optionstatus(void),
+ printoption(const char *, int, int),
+ printsub(char, unsigned char *, int),
+ quit(void),
+ sendabort(void),
+ sendbrk(void),
+ sendeof(void),
+ sendsusp(void),
+ sendnaws(void),
+ sendayt(void),
+ setconnmode(int),
+ setcommandmode(void),
+ set_escape_char(char *s),
+ setneturg(void),
+ sys_telnet_init(void),
+ telnet(char *),
+ tel_enter_binary(int),
+ tel_leave_binary(int),
+ TerminalFlushOutput(void),
+ TerminalNewMode(int),
+ TerminalRestoreState(void),
+ TerminalSaveState(void),
+ TerminalDefaultChars(void),
+ TerminalSpeeds(long *, long *),
+ tninit(void),
+ upcase(char *),
+ willoption(int),
+ wontoption(int);
+
+extern void
+ send_do(int, int),
+ send_dont(int, int),
+ send_will(int, int),
+ send_wont(int, int);
+
+extern void
+ lm_will(unsigned char *, int),
+ lm_wont(unsigned char *, int),
+ lm_do(unsigned char *, int),
+ lm_dont(unsigned char *, int),
+ lm_mode(unsigned char *, int, int);
+
+extern void
+ slc_init(void),
+ slcstate(void),
+ slc_mode_export(void),
+ slc_mode_import(int),
+ slc_import(int),
+ slc_export(void),
+ slc(unsigned char *, int),
+ slc_check(void),
+ slc_start_reply(void),
+ slc_add_reply(unsigned char, unsigned char, cc_t),
+ slc_end_reply(void);
+extern int
+ getconnmode(void),
+ opt_welldefined(const char *),
+ NetClose(int),
+ netflush(void),
+ process_rings(int, int, int, int, int, int),
+ rlogin_susp(void),
+ SetSockOpt(int, int, int, int),
+ slc_update(void),
+ stilloob(void),
+ telrcv(void),
+ TerminalRead(char *, int),
+ TerminalWrite(char *, int),
+ TerminalAutoFlush(void),
+ TerminalWindowSize(long *, long *),
+ TerminalSpecialChars(int),
+ tn(int, char **),
+ ttyflush(int);
+
+extern void
+ env_opt(unsigned char *, int),
+ env_opt_start(void),
+ env_opt_start_info(void),
+ env_opt_add(unsigned char *),
+ env_opt_end(int);
+
+extern unsigned char
+ *env_default(int, int),
+ *env_getvalue(const unsigned char *);
+
+extern int
+ get_status(char *),
+ dosynch(char *);
+
+extern cc_t
+ *tcval(int);
+
+#ifndef USE_TERMIO
+
+extern struct tchars ntc;
+extern struct ltchars nltc;
+extern struct sgttyb nttyb;
+
+# define termEofChar ntc.t_eofc
+# define termEraseChar nttyb.sg_erase
+# define termFlushChar nltc.t_flushc
+# define termIntChar ntc.t_intrc
+# define termKillChar nttyb.sg_kill
+# define termLiteralNextChar nltc.t_lnextc
+# define termQuitChar ntc.t_quitc
+# define termSuspChar nltc.t_suspc
+# define termRprntChar nltc.t_rprntc
+# define termWerasChar nltc.t_werasc
+# define termStartChar ntc.t_startc
+# define termStopChar ntc.t_stopc
+# define termForw1Char ntc.t_brkc
+extern cc_t termForw2Char;
+extern cc_t termAytChar;
+
+# define termEofCharp (cc_t *)&ntc.t_eofc
+# define termEraseCharp (cc_t *)&nttyb.sg_erase
+# define termFlushCharp (cc_t *)&nltc.t_flushc
+# define termIntCharp (cc_t *)&ntc.t_intrc
+# define termKillCharp (cc_t *)&nttyb.sg_kill
+# define termLiteralNextCharp (cc_t *)&nltc.t_lnextc
+# define termQuitCharp (cc_t *)&ntc.t_quitc
+# define termSuspCharp (cc_t *)&nltc.t_suspc
+# define termRprntCharp (cc_t *)&nltc.t_rprntc
+# define termWerasCharp (cc_t *)&nltc.t_werasc
+# define termStartCharp (cc_t *)&ntc.t_startc
+# define termStopCharp (cc_t *)&ntc.t_stopc
+# define termForw1Charp (cc_t *)&ntc.t_brkc
+# define termForw2Charp (cc_t *)&termForw2Char
+# define termAytCharp (cc_t *)&termAytChar
+
+# else
+
+extern struct termio new_tc;
+
+# define termEofChar new_tc.c_cc[VEOF]
+# define termEraseChar new_tc.c_cc[VERASE]
+# define termIntChar new_tc.c_cc[VINTR]
+# define termKillChar new_tc.c_cc[VKILL]
+# define termQuitChar new_tc.c_cc[VQUIT]
+
+# ifndef VSUSP
+extern cc_t termSuspChar;
+# else
+# define termSuspChar new_tc.c_cc[VSUSP]
+# endif
+# if defined(VFLUSHO) && !defined(VDISCARD)
+# define VDISCARD VFLUSHO
+# endif
+# ifndef VDISCARD
+extern cc_t termFlushChar;
+# else
+# define termFlushChar new_tc.c_cc[VDISCARD]
+# endif
+# ifndef VWERASE
+extern cc_t termWerasChar;
+# else
+# define termWerasChar new_tc.c_cc[VWERASE]
+# endif
+# ifndef VREPRINT
+extern cc_t termRprntChar;
+# else
+# define termRprntChar new_tc.c_cc[VREPRINT]
+# endif
+# ifndef VLNEXT
+extern cc_t termLiteralNextChar;
+# else
+# define termLiteralNextChar new_tc.c_cc[VLNEXT]
+# endif
+# ifndef VSTART
+extern cc_t termStartChar;
+# else
+# define termStartChar new_tc.c_cc[VSTART]
+# endif
+# ifndef VSTOP
+extern cc_t termStopChar;
+# else
+# define termStopChar new_tc.c_cc[VSTOP]
+# endif
+# ifndef VEOL
+extern cc_t termForw1Char;
+# else
+# define termForw1Char new_tc.c_cc[VEOL]
+# endif
+# ifndef VEOL2
+extern cc_t termForw2Char;
+# else
+# define termForw2Char new_tc.c_cc[VEOL]
+# endif
+# ifndef VSTATUS
+extern cc_t termAytChar;
+#else
+# define termAytChar new_tc.c_cc[VSTATUS]
+#endif
+
+# if defined(__STDC__)
+# define termEofCharp &termEofChar
+# define termEraseCharp &termEraseChar
+# define termIntCharp &termIntChar
+# define termKillCharp &termKillChar
+# define termQuitCharp &termQuitChar
+# define termSuspCharp &termSuspChar
+# define termFlushCharp &termFlushChar
+# define termWerasCharp &termWerasChar
+# define termRprntCharp &termRprntChar
+# define termLiteralNextCharp &termLiteralNextChar
+# define termStartCharp &termStartChar
+# define termStopCharp &termStopChar
+# define termForw1Charp &termForw1Char
+# define termForw2Charp &termForw2Char
+# define termAytCharp &termAytChar
+# else
+ /* Work around a compiler bug */
+# define termEofCharp 0
+# define termEraseCharp 0
+# define termIntCharp 0
+# define termKillCharp 0
+# define termQuitCharp 0
+# define termSuspCharp 0
+# define termFlushCharp 0
+# define termWerasCharp 0
+# define termRprntCharp 0
+# define termLiteralNextCharp 0
+# define termStartCharp 0
+# define termStopCharp 0
+# define termForw1Charp 0
+# define termForw2Charp 0
+# define termAytCharp 0
+# endif
+#endif
+
+
+/* Ring buffer structures which are shared */
+
+extern Ring
+ netoring,
+ netiring,
+ ttyoring,
+ ttyiring;
+
+extern void
+ xmitAO(void),
+ xmitEC(void),
+ xmitEL(void);
diff --git a/remote_cmds/telnet.tproj/fdset.h b/remote_cmds/telnet.tproj/fdset.h
new file mode 100644
index 0000000..045bb72
--- /dev/null
+++ b/remote_cmds/telnet.tproj/fdset.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fdset.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * The following is defined just in case someone should want to run
+ * this telnet on a 4.2 system.
+ *
+ */
+
+#ifndef FD_SETSIZE
+
+#define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
+#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
+#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
+#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
+
+#endif
diff --git a/remote_cmds/telnet.tproj/general.h b/remote_cmds/telnet.tproj/general.h
new file mode 100644
index 0000000..4efa951
--- /dev/null
+++ b/remote_cmds/telnet.tproj/general.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)general.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Some general definitions.
+ */
+
+
+#define numberof(x) (sizeof x/sizeof x[0])
+#define highestof(x) (numberof(x)-1)
+
+#define ClearElement(x) memset((char *)&x, 0, sizeof x)
+#define ClearArray(x) memset((char *)x, 0, sizeof x)
diff --git a/remote_cmds/telnet.tproj/krb4-proto.h b/remote_cmds/telnet.tproj/krb4-proto.h
new file mode 100644
index 0000000..9f3f0b0
--- /dev/null
+++ b/remote_cmds/telnet.tproj/krb4-proto.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#ifdef __STDC__
+# define P(s) s
+#else
+# define P(s) ()
+#endif
+
+/* add_ticket.c */
+int add_ticket P((KTEXT , int , char *, int , char *, char *, char *, int , KTEXT ));
+
+/* cr_err_reply.c */
+void cr_err_reply P((KTEXT , char *, char *, char *, u_long , u_long , char *));
+
+/* create_auth_reply.c */
+KTEXT create_auth_reply P((char *, char *, char *, long , int , unsigned long , int , KTEXT ));
+
+/* create_ciph.c */
+int create_ciph P((KTEXT , C_Block , char *, char *, char *, unsigned long , int , KTEXT , unsigned long , C_Block ));
+
+/* create_death_packet.c */
+KTEXT krb_create_death_packet P((char *));
+
+/* create_ticket.c */
+int krb_create_ticket P((KTEXT , unsigned int , char *, char *, char *, long , char *, int , long , char *, char *, C_Block ));
+
+/* debug_decl.c */
+
+/* decomp_ticket.c */
+int decomp_ticket P((KTEXT , unsigned char *, char *, char *, char *, unsigned long *, C_Block , int *, unsigned long *, char *, char *, C_Block , Key_schedule ));
+
+/* dest_tkt.c */
+int dest_tkt P((void ));
+
+/* extract_ticket.c */
+int extract_ticket P((KTEXT , int , char *, int *, int *, char *, KTEXT ));
+
+/* fgetst.c */
+int fgetst P((FILE *, char *, int ));
+
+/* get_ad_tkt.c */
+int get_ad_tkt P((char *, char *, char *, int ));
+
+/* get_admhst.c */
+int krb_get_admhst P((char *, char *, int ));
+
+/* get_cred.c */
+int krb_get_cred P((char *, char *, char *, CREDENTIALS *));
+
+/* get_in_tkt.c */
+int krb_get_pw_in_tkt P((char *, char *, char *, char *, char *, int , char *));
+int placebo_read_password P((des_cblock *, char *, int ));
+int placebo_read_pw_string P((char *, int , char *, int ));
+
+/* get_krbhst.c */
+int krb_get_krbhst P((char *, char *, int ));
+
+/* get_krbrlm.c */
+int krb_get_lrealm P((char *, int ));
+
+/* get_phost.c */
+char *krb_get_phost P((char *));
+
+/* get_pw_tkt.c */
+int get_pw_tkt P((char *, char *, char *, char *));
+
+/* get_request.c */
+int get_request P((KTEXT , int , char **, char **));
+
+/* get_svc_in_tkt.c */
+int krb_get_svc_in_tkt P((char *, char *, char *, char *, char *, int , char *));
+
+/* get_tf_fullname.c */
+int krb_get_tf_fullname P((char *, char *, char *, char *));
+
+/* get_tf_realm.c */
+int krb_get_tf_realm P((char *, char *));
+
+/* getopt.c */
+int getopt P((int , char **, char *));
+
+/* getrealm.c */
+char *krb_realmofhost P((char *));
+
+/* getst.c */
+int getst P((int , char *, int ));
+
+/* in_tkt.c */
+int in_tkt P((char *, char *));
+
+/* k_gethostname.c */
+int k_gethostname P((char *, int ));
+
+/* klog.c */
+char *klog P((int , char *, int , int , int , int , int , int , int , int , int , int ));
+int kset_logfile P((char *));
+
+/* kname_parse.c */
+int kname_parse P((char *, char *, char *, char *));
+int k_isname P((char *));
+int k_isinst P((char *));
+int k_isrealm P((char *));
+
+/* kntoln.c */
+int krb_kntoln P((AUTH_DAT *, char *));
+
+/* krb_err_txt.c */
+
+/* krb_get_in_tkt.c */
+int krb_get_in_tkt P((char *, char *, char *, char *, char *, int , int (*key_proc )(), int (*decrypt_proc )(), char *));
+
+/* kuserok.c */
+int kuserok P((AUTH_DAT *, char *));
+
+/* log.c */
+void log P((char *, int , int , int , int , int , int , int , int , int , int ));
+int set_logfile P((char *));
+int new_log P((long , char *));
+
+/* mk_err.c */
+long krb_mk_err P((u_char *, long , char *));
+
+/* mk_priv.c */
+long krb_mk_priv P((u_char *, u_char *, u_long , Key_schedule , C_Block , struct sockaddr_in *, struct sockaddr_in *));
+
+/* mk_req.c */
+int krb_mk_req P((KTEXT , char *, char *, char *, long ));
+int krb_set_lifetime P((int ));
+
+/* mk_safe.c */
+long krb_mk_safe P((u_char *, u_char *, u_long , C_Block *, struct sockaddr_in *, struct sockaddr_in *));
+
+/* month_sname.c */
+char *month_sname P((int ));
+
+/* netread.c */
+int krb_net_read P((int , char *, int ));
+
+/* netwrite.c */
+int krb_net_write P((int , char *, int ));
+
+/* one.c */
+
+/* pkt_cipher.c */
+KTEXT pkt_cipher P((KTEXT ));
+
+/* pkt_clen.c */
+int pkt_clen P((KTEXT ));
+
+/* rd_err.c */
+int krb_rd_err P((u_char *, u_long , long *, MSG_DAT *));
+
+/* rd_priv.c */
+long krb_rd_priv P((u_char *, u_long , Key_schedule , C_Block , struct sockaddr_in *, struct sockaddr_in *, MSG_DAT *));
+
+/* rd_req.c */
+int krb_set_key P((char *, int ));
+int krb_rd_req P((KTEXT , char *, char *, long , AUTH_DAT *, char *));
+
+/* rd_safe.c */
+long krb_rd_safe P((u_char *, u_long , C_Block *, struct sockaddr_in *, struct sockaddr_in *, MSG_DAT *));
+
+/* read_service_key.c */
+int read_service_key P((char *, char *, char *, int , char *, char *));
+
+/* recvauth.c */
+int krb_recvauth P((long , int , KTEXT , char *, char *, struct sockaddr_in *, struct sockaddr_in *, AUTH_DAT *, char *, Key_schedule , char *));
+
+/* save_credentials.c */
+int save_credentials P((char *, char *, char *, C_Block , int , int , KTEXT , long ));
+
+/* send_to_kdc.c */
+int send_to_kdc P((KTEXT , KTEXT , char *));
+
+/* sendauth.c */
+int krb_sendauth P((long , int , KTEXT , char *, char *, char *, u_long , MSG_DAT *, CREDENTIALS *, Key_schedule , struct sockaddr_in *, struct sockaddr_in *, char *));
+int krb_sendsvc P((int , char *));
+
+/* setenv.c */
+int setenv P((char *, char *, int ));
+void unsetenv P((char *));
+char *getenv P((char *));
+char *_findenv P((char *, int *));
+
+/* stime.c */
+char *stime P((long *));
+
+/* tf_shm.c */
+int krb_shm_create P((char *));
+int krb_is_diskless P((void ));
+int krb_shm_dest P((char *));
+
+/* tf_util.c */
+int tf_init P((char *, int ));
+int tf_get_pname P((char *));
+int tf_get_pinst P((char *));
+int tf_get_cred P((CREDENTIALS *));
+int tf_close P((void ));
+int tf_save_cred P((char *, char *, char *, C_Block , int , int , KTEXT , long ));
+
+/* tkt_string.c */
+char *tkt_string P((void ));
+void krb_set_tkt_string P((char *));
+
+/* util.c */
+int ad_print P((AUTH_DAT *));
+int placebo_cblock_print P((des_cblock ));
+
+#undef P
diff --git a/remote_cmds/telnet.tproj/main.c b/remote_cmds/telnet.tproj/main.c
new file mode 100644
index 0000000..fd01a30
--- /dev/null
+++ b/remote_cmds/telnet.tproj/main.c
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)main.c 8.3 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/main.c,v 1.20 2005/01/09 10:24:45 maxim Exp $");
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ring.h"
+#include "externs.h"
+#include "defines.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+/* These values need to be the same as defined in libtelnet/kerberos5.c */
+/* Either define them in both places, or put in some common header file. */
+#define OPTS_FORWARD_CREDS 0x00000002
+#define OPTS_FORWARDABLE_CREDS 0x00000001
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+char *ipsec_policy_in = NULL;
+char *ipsec_policy_out = NULL;
+#endif
+
+extern int tos;
+
+int family = AF_UNSPEC;
+
+/*
+ * Initialize variables.
+ */
+void
+tninit(void)
+{
+ init_terminal();
+
+ init_network();
+
+ init_telnet();
+
+ init_sys();
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s %s%s%s%s\n",
+ prompt,
+#ifdef AUTHENTICATION
+ "[-4] [-6] [-8] [-E] [-K] [-L] [-N] [-S tos] [-X atype] [-c] [-d]",
+ "\n\t[-e char] [-k realm] [-l user] [-f/-F] [-n tracefile] ",
+#else
+ "[-4] [-6] [-8] [-E] [-L] [-N] [-S tos] [-c] [-d]",
+ "\n\t[-e char] [-l user] [-n tracefile] ",
+#endif
+ "[-r] [-s src_addr] [-u] ",
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ "[-P policy] "
+#endif
+#ifdef ENCRYPTION
+ "[-y] [host-name [port]]"
+#else /* ENCRYPTION */
+ "[host-name [port]]"
+#endif /* ENCRYPTION */
+ );
+ exit(1);
+}
+
+/*
+ * main. Parse arguments, invoke the protocol or command parser.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ u_long ultmp;
+ int ch;
+ char *ep, *user;
+ char *src_addr = NULL;
+#ifdef FORWARD
+ extern int forward_flags;
+#endif /* FORWARD */
+
+ tninit(); /* Clear out things */
+
+ TerminalSaveState();
+
+ if ((prompt = strrchr(argv[0], '/')))
+ ++prompt;
+ else
+ prompt = argv[0];
+
+ user = NULL;
+
+ rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
+#ifdef AUTHENTICATION
+ autologin = 1;
+#else
+ autologin = -1;
+#endif
+
+#ifdef ENCRYPTION
+ encrypt_auto(1);
+ decrypt_auto(1);
+#endif
+
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+#define IPSECOPT "P:"
+#else
+#define IPSECOPT
+#endif
+ while ((ch = getopt(argc, argv,
+ "468EKLNS:X:acde:fFk:l:n:rs:uxy" IPSECOPT)) != -1)
+#undef IPSECOPT
+ {
+ switch(ch) {
+ case '4':
+ family = AF_INET;
+ break;
+#ifdef INET6
+ case '6':
+ family = AF_INET6;
+ break;
+#endif
+ case '8':
+ eight = 3; /* binary output and input */
+ break;
+ case 'E':
+ rlogin = escape = _POSIX_VDISABLE;
+ break;
+ case 'K':
+#ifdef AUTHENTICATION
+ autologin = 0;
+#endif
+ break;
+ case 'L':
+ eight |= 2; /* binary output only */
+ break;
+ case 'N':
+ doaddrlookup = 0;
+ break;
+ case 'S':
+#ifdef HAS_GETTOS
+
+ if ((tos = parsetos(optarg, "tcp")) < 0)
+ fprintf(stderr, "%s%s%s%s\n",
+ prompt, ": Bad TOS argument '",
+ optarg,
+ "; will try to use default TOS");
+#else
+#define MAXTOS 255
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > MAXTOS)
+ fprintf(stderr, "%s%s%s%s\n",
+ prompt, ": Bad TOS argument '",
+ optarg,
+ "; will try to use default TOS");
+ else
+ tos = ultmp;
+#endif
+ break;
+ case 'X':
+#ifdef AUTHENTICATION
+ auth_disable_name(optarg);
+#endif
+ break;
+ case 'a':
+#ifdef AUTHENTICATION
+ /* It's the default now, so ignore */
+#else
+ autologin = 1;
+#endif
+ break;
+ case 'c':
+ skiprc = 1;
+ break;
+ case 'd':
+ telnet_debug = 1;
+ break;
+ case 'e':
+ set_escape_char(optarg);
+ break;
+ case 'f':
+#ifdef AUTHENTICATION
+#if defined(KRB5) && defined(FORWARD)
+ if (forward_flags & OPTS_FORWARD_CREDS) {
+ fprintf(stderr,
+ "%s: Only one of -f and -F allowed.\n",
+ prompt);
+ usage();
+ }
+ forward_flags |= OPTS_FORWARD_CREDS;
+#else
+ fprintf(stderr,
+ "%s: Warning: -f ignored, no Kerberos V5 support.\n",
+ prompt);
+#endif
+#else
+ fprintf(stderr,
+ "%s: Warning: -f ignored, no Kerberos V5 support.\n",
+ prompt);
+#endif
+ break;
+ case 'F':
+#ifdef AUTHENTICATION
+#if defined(KRB5) && defined(FORWARD)
+ if (forward_flags & OPTS_FORWARD_CREDS) {
+ fprintf(stderr,
+ "%s: Only one of -f and -F allowed.\n",
+ prompt);
+ usage();
+ }
+ forward_flags |= OPTS_FORWARD_CREDS;
+ forward_flags |= OPTS_FORWARDABLE_CREDS;
+#else
+ fprintf(stderr,
+ "%s: Warning: -F ignored, no Kerberos V5 support.\n",
+ prompt);
+#endif
+#else
+ fprintf(stderr,
+ "%s: Warning: -F ignored, no Kerberos V5 support.\n",
+ prompt);
+#endif
+ break;
+ case 'k':
+#ifdef AUTHENTICATION
+#if defined(KRB4)
+ {
+ extern char *dest_realm, dst_realm_buf[], dst_realm_sz;
+ dest_realm = dst_realm_buf;
+ (void)strncpy(dest_realm, optarg, dst_realm_sz);
+ }
+#else
+ fprintf(stderr,
+ "%s: Warning: -k ignored, no Kerberos V4 support.\n",
+ prompt);
+#endif
+#else
+ fprintf(stderr,
+ "%s: Warning: -k ignored, no Kerberos V4 support.\n",
+ prompt);
+#endif
+ break;
+ case 'l':
+#ifdef AUTHENTICATION
+ /* This is the default now, so ignore it */
+#else
+ autologin = 1;
+#endif
+ user = optarg;
+ break;
+ case 'n':
+ SetNetTrace(optarg);
+ break;
+ case 'r':
+ rlogin = '~';
+ break;
+ case 's':
+ src_addr = optarg;
+ break;
+ case 'u':
+ family = AF_UNIX;
+ break;
+ case 'x':
+#ifndef ENCRYPTION
+ fprintf(stderr,
+ "%s: Warning: -x ignored, no ENCRYPT support.\n",
+ prompt);
+#endif /* ENCRYPTION */
+ break;
+ case 'y':
+#ifdef ENCRYPTION
+ encrypt_auto(0);
+ decrypt_auto(0);
+#else
+ fprintf(stderr,
+ "%s: Warning: -y ignored, no ENCRYPT support.\n",
+ prompt);
+#endif /* ENCRYPTION */
+ break;
+#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
+ case 'P':
+ if (!strncmp("in", optarg, 2))
+ ipsec_policy_in = strdup(optarg);
+ else if (!strncmp("out", optarg, 3))
+ ipsec_policy_out = strdup(optarg);
+ else
+ usage();
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ if (autologin == -1)
+ autologin = (rlogin == _POSIX_VDISABLE) ? 0 : 1;
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc) {
+ char *args[9], **argp = args;
+
+ if (argc > 2)
+ usage();
+ *argp++ = prompt;
+ if (user) {
+ *argp++ = strdup("-l");
+ *argp++ = user;
+ }
+ if (src_addr) {
+ *argp++ = strdup("-s");
+ *argp++ = src_addr;
+ }
+ *argp++ = argv[0]; /* host */
+ if (argc > 1)
+ *argp++ = argv[1]; /* port */
+ *argp = 0;
+
+ if (setjmp(toplevel) != 0)
+ Exit(0);
+ if (tn(argp - args, args) == 1)
+ return (0);
+ else
+ return (1);
+ }
+ (void)setjmp(toplevel);
+ for (;;) {
+ command(1, 0, 0);
+ }
+ return 0;
+}
diff --git a/remote_cmds/telnet.tproj/misc-proto.h b/remote_cmds/telnet.tproj/misc-proto.h
new file mode 100644
index 0000000..511a1bf
--- /dev/null
+++ b/remote_cmds/telnet.tproj/misc-proto.h
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc-proto.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/crypto/telnet/libtelnet/misc-proto.h,v 1.1.1.1.8.1 2002/04/13 10:59:07 markm Exp $
+ */
+
+/*
+ * Copyright (C) 1990 by the Massachusetts Institute of Technology
+ *
+ * Export of this software from the United States of America is assumed
+ * to require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in 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.
+ */
+
+#ifndef __MISC_PROTO__
+#define __MISC_PROTO__
+
+void auth_encrypt_init(char *, char *, const char *, int);
+void auth_encrypt_connect(int);
+void printd(const unsigned char *, int);
+
+int isprefix(char *, const char *);
+char **genget(char *, char **, int);
+int Ambiguous(char **);
+
+int getent(char *, const char *);
+char *Getstr(const char *, char **);
+
+/*
+ * These functions are imported from the application
+ */
+int net_write(unsigned char *, int);
+void net_encrypt(void);
+int telnet_spin(void);
+char *telnet_getenv(char *);
+char *telnet_gets(const char *, char *, int, int);
+void printsub(char, unsigned char *, int);
+#endif
diff --git a/remote_cmds/telnet.tproj/misc.h b/remote_cmds/telnet.tproj/misc.h
new file mode 100644
index 0000000..41ffa7f
--- /dev/null
+++ b/remote_cmds/telnet.tproj/misc.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc.h 8.1 (Berkeley) 6/4/93
+ */
+
+extern char *UserNameRequested;
+extern char *LocalHostName;
+extern char *RemoteHostName;
+extern int ConnectedCount;
+extern int ReservedPort;
+
+#include "misc-proto.h"
diff --git a/remote_cmds/telnet.tproj/network.c b/remote_cmds/telnet.tproj/network.c
new file mode 100644
index 0000000..e93345f
--- /dev/null
+++ b/remote_cmds/telnet.tproj/network.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)network.c 8.2 (Berkeley) 12/15/93";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/network.c,v 1.7 2003/05/04 02:54:48 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <stdlib.h>
+
+#include <arpa/telnet.h>
+#include <unistd.h>
+
+#include "ring.h"
+
+#include "defines.h"
+#include "externs.h"
+#include "fdset.h"
+
+Ring netoring, netiring;
+unsigned char netobuf[2*BUFSIZ], netibuf[BUFSIZ];
+
+/*
+ * Initialize internal network data structures.
+ */
+
+void
+init_network(void)
+{
+ if (ring_init(&netoring, netobuf, sizeof netobuf) != 1) {
+ exit(1);
+ }
+ if (ring_init(&netiring, netibuf, sizeof netibuf) != 1) {
+ exit(1);
+ }
+ NetTrace = stdout;
+}
+
+
+/*
+ * Check to see if any out-of-band data exists on a socket (for
+ * Telnet "synch" processing).
+ */
+
+int
+stilloob(void)
+{
+ static struct timeval timeout = { 0, 0 };
+ fd_set excepts;
+ int value;
+
+ do {
+ FD_ZERO(&excepts);
+ FD_SET(net, &excepts);
+ value = select(net+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
+ } while ((value == -1) && (errno == EINTR));
+
+ if (value < 0) {
+ perror("select");
+ (void) quit();
+ /* NOTREACHED */
+ }
+ if (FD_ISSET(net, &excepts)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/*
+ * setneturg()
+ *
+ * Sets "neturg" to the current location.
+ */
+
+void
+setneturg(void)
+{
+ ring_mark(&netoring);
+}
+
+
+/*
+ * netflush
+ * Send as much data as possible to the network,
+ * handling requests for urgent data.
+ *
+ * The return value indicates whether we did any
+ * useful work.
+ */
+
+int
+netflush(void)
+{
+ int n, n1;
+
+#ifdef ENCRYPTION
+ if (encrypt_output)
+ ring_encrypt(&netoring, encrypt_output);
+#endif /* ENCRYPTION */
+ if ((n1 = n = ring_full_consecutive(&netoring)) > 0) {
+ if (!ring_at_mark(&netoring)) {
+ n = send(net, (char *)netoring.consume, n, 0); /* normal write */
+ } else {
+ /*
+ * In 4.2 (and 4.3) systems, there is some question about
+ * what byte in a sendOOB operation is the "OOB" data.
+ * To make ourselves compatible, we only send ONE byte
+ * out of band, the one WE THINK should be OOB (though
+ * we really have more the TCP philosophy of urgent data
+ * rather than the Unix philosophy of OOB data).
+ */
+ n = send(net, (char *)netoring.consume, 1, MSG_OOB);/* URGENT data */
+ }
+ }
+ if (n < 0) {
+ if (errno != ENOBUFS && errno != EWOULDBLOCK) {
+ setcommandmode();
+ perror(hostname);
+ (void)NetClose(net);
+ ring_clear_mark(&netoring);
+ longjmp(peerdied, -1);
+ /*NOTREACHED*/
+ }
+ n = 0;
+ }
+ if (netdata && n) {
+ Dump('>', netoring.consume, n);
+ }
+ if (n) {
+ ring_consumed(&netoring, n);
+ /*
+ * If we sent all, and more to send, then recurse to pick
+ * up the other half.
+ */
+ if ((n1 == n) && ring_full_consecutive(&netoring)) {
+ (void) netflush();
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
diff --git a/remote_cmds/telnet.tproj/ring.c b/remote_cmds/telnet.tproj/ring.c
new file mode 100644
index 0000000..0706133
--- /dev/null
+++ b/remote_cmds/telnet.tproj/ring.c
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)ring.c 8.2 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/ring.c,v 1.7 2003/05/04 02:54:48 obrien Exp $");
+
+/*
+ * This defines a structure for a ring buffer.
+ *
+ * The circular buffer has two parts:
+ *(((
+ * full: [consume, supply)
+ * empty: [supply, consume)
+ *]]]
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef size_t
+#undef size_t
+#endif
+
+#include <sys/types.h>
+#ifndef FILIO_H
+#include <sys/ioctl.h>
+#endif
+#include <sys/socket.h>
+
+#include "ring.h"
+#include "general.h"
+
+/* Internal macros */
+
+#if !defined(MIN)
+#define MIN(a,b) (((a)<(b))? (a):(b))
+#endif /* !defined(MIN) */
+
+#define ring_subtract(d,a,b) (((a)-(b) >= 0)? \
+ (a)-(b): (((a)-(b))+(d)->size))
+
+#define ring_increment(d,a,c) (((a)+(c) < (d)->top)? \
+ (a)+(c) : (((a)+(c))-(d)->size))
+
+#define ring_decrement(d,a,c) (((a)-(c) >= (d)->bottom)? \
+ (a)-(c) : (((a)-(c))-(d)->size))
+
+
+/*
+ * The following is a clock, used to determine full, empty, etc.
+ *
+ * There is some trickiness here. Since the ring buffers are initialized
+ * to ZERO on allocation, we need to make sure, when interpreting the
+ * clock, that when the times are EQUAL, then the buffer is FULL.
+ */
+static u_long ring_clock = 0;
+
+
+#define ring_empty(d) (((d)->consume == (d)->supply) && \
+ ((d)->consumetime >= (d)->supplytime))
+#define ring_full(d) (((d)->supply == (d)->consume) && \
+ ((d)->supplytime > (d)->consumetime))
+
+/* Buffer state transition routines */
+
+int
+ring_init(Ring *ring, unsigned char *buffer, int count)
+{
+ memset((char *)ring, 0, sizeof *ring);
+
+ ring->size = count;
+
+ ring->supply = ring->consume = ring->bottom = buffer;
+
+ ring->top = ring->bottom+ring->size;
+
+#ifdef ENCRYPTION
+ ring->clearto = 0;
+#endif /* ENCRYPTION */
+
+ return 1;
+}
+
+/* Mark routines */
+
+/*
+ * Mark the most recently supplied byte.
+ */
+
+void
+ring_mark(Ring *ring)
+{
+ ring->mark = ring_decrement(ring, ring->supply, 1);
+}
+
+/*
+ * Is the ring pointing to the mark?
+ */
+
+int
+ring_at_mark(Ring *ring)
+{
+ if (ring->mark == ring->consume) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/*
+ * Clear any mark set on the ring.
+ */
+
+void
+ring_clear_mark(Ring *ring)
+{
+ ring->mark = 0;
+}
+
+/*
+ * Add characters from current segment to ring buffer.
+ */
+void
+ring_supplied(Ring *ring, int count)
+{
+ ring->supply = ring_increment(ring, ring->supply, count);
+ ring->supplytime = ++ring_clock;
+}
+
+/*
+ * We have just consumed "c" bytes.
+ */
+void
+ring_consumed(Ring *ring, int count)
+{
+ if (count == 0) /* don't update anything */
+ return;
+
+ if (ring->mark &&
+ (ring_subtract(ring, ring->mark, ring->consume) < count)) {
+ ring->mark = 0;
+ }
+#ifdef ENCRYPTION
+ if (ring->consume < ring->clearto &&
+ ring->clearto <= ring->consume + count)
+ ring->clearto = 0;
+ else if (ring->consume + count > ring->top &&
+ ring->bottom <= ring->clearto &&
+ ring->bottom + ((ring->consume + count) - ring->top))
+ ring->clearto = 0;
+#endif /* ENCRYPTION */
+ ring->consume = ring_increment(ring, ring->consume, count);
+ ring->consumetime = ++ring_clock;
+ /*
+ * Try to encourage "ring_empty_consecutive()" to be large.
+ */
+ if (ring_empty(ring)) {
+ ring->consume = ring->supply = ring->bottom;
+ }
+}
+
+
+
+/* Buffer state query routines */
+
+
+/* Number of bytes that may be supplied */
+int
+ring_empty_count(Ring *ring)
+{
+ if (ring_empty(ring)) { /* if empty */
+ return ring->size;
+ } else {
+ return ring_subtract(ring, ring->consume, ring->supply);
+ }
+}
+
+/* number of CONSECUTIVE bytes that may be supplied */
+int
+ring_empty_consecutive(Ring *ring)
+{
+ if ((ring->consume < ring->supply) || ring_empty(ring)) {
+ /*
+ * if consume is "below" supply, or empty, then
+ * return distance to the top
+ */
+ return ring_subtract(ring, ring->top, ring->supply);
+ } else {
+ /*
+ * else, return what we may.
+ */
+ return ring_subtract(ring, ring->consume, ring->supply);
+ }
+}
+
+/* Return the number of bytes that are available for consuming
+ * (but don't give more than enough to get to cross over set mark)
+ */
+
+int
+ring_full_count(Ring *ring)
+{
+ if ((ring->mark == 0) || (ring->mark == ring->consume)) {
+ if (ring_full(ring)) {
+ return ring->size; /* nothing consumed, but full */
+ } else {
+ return ring_subtract(ring, ring->supply, ring->consume);
+ }
+ } else {
+ return ring_subtract(ring, ring->mark, ring->consume);
+ }
+}
+
+/*
+ * Return the number of CONSECUTIVE bytes available for consuming.
+ * However, don't return more than enough to cross over set mark.
+ */
+int
+ring_full_consecutive(Ring *ring)
+{
+ if ((ring->mark == 0) || (ring->mark == ring->consume)) {
+ if ((ring->supply < ring->consume) || ring_full(ring)) {
+ return ring_subtract(ring, ring->top, ring->consume);
+ } else {
+ return ring_subtract(ring, ring->supply, ring->consume);
+ }
+ } else {
+ if (ring->mark < ring->consume) {
+ return ring_subtract(ring, ring->top, ring->consume);
+ } else { /* Else, distance to mark */
+ return ring_subtract(ring, ring->mark, ring->consume);
+ }
+ }
+}
+
+/*
+ * Move data into the "supply" portion of of the ring buffer.
+ */
+void
+ring_supply_data(Ring *ring, unsigned char *buffer, int count)
+{
+ int i;
+
+ while (count) {
+ i = MIN(count, ring_empty_consecutive(ring));
+ memcpy(ring->supply, buffer, i);
+ ring_supplied(ring, i);
+ count -= i;
+ buffer += i;
+ }
+}
+
+#ifdef ENCRYPTION
+void
+ring_encrypt(Ring *ring, void (*encryptor)(unsigned char *, int))
+{
+ unsigned char *s, *c;
+
+ if (ring_empty(ring) || ring->clearto == ring->supply)
+ return;
+
+ if (!(c = ring->clearto))
+ c = ring->consume;
+
+ s = ring->supply;
+
+ if (s <= c) {
+ (*encryptor)(c, ring->top - c);
+ (*encryptor)(ring->bottom, s - ring->bottom);
+ } else
+ (*encryptor)(c, s - c);
+
+ ring->clearto = ring->supply;
+}
+
+ void
+ring_clearto(ring)
+ Ring *ring;
+{
+ if (!ring_empty(ring))
+ ring->clearto = ring->supply;
+ else
+ ring->clearto = 0;
+}
+#endif /* ENCRYPTION */
diff --git a/remote_cmds/telnet.tproj/ring.h b/remote_cmds/telnet.tproj/ring.h
new file mode 100644
index 0000000..6b8d11d
--- /dev/null
+++ b/remote_cmds/telnet.tproj/ring.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ring.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/contrib/telnet/telnet/ring.h,v 1.4 2001/11/30 22:28:07 markm Exp $
+ */
+
+#if defined(P)
+# undef P
+#endif
+
+#if defined(__STDC__) || defined(LINT_ARGS)
+# define P(x) x
+#else
+# define P(x) ()
+#endif
+
+/*
+ * This defines a structure for a ring buffer.
+ *
+ * The circular buffer has two parts:
+ *(((
+ * full: [consume, supply)
+ * empty: [supply, consume)
+ *]]]
+ *
+ */
+typedef struct {
+ unsigned char *consume, /* where data comes out of */
+ *supply, /* where data comes in to */
+ *bottom, /* lowest address in buffer */
+ *top, /* highest address+1 in buffer */
+ *mark; /* marker (user defined) */
+#ifdef ENCRYPTION
+ unsigned char *clearto; /* Data to this point is clear text */
+ unsigned char *encryyptedto; /* Data is encrypted to here */
+#endif /* ENCRYPTION */
+ int size; /* size in bytes of buffer */
+ u_long consumetime, /* help us keep straight full, empty, etc. */
+ supplytime;
+} Ring;
+
+/* Here are some functions and macros to deal with the ring buffer */
+
+/* Initialization routine */
+extern int
+ ring_init(Ring *ring, unsigned char *buffer, int count);
+
+/* Data movement routines */
+extern void
+ ring_supply_data(Ring *ring, unsigned char *buffer, int count);
+#ifdef notdef
+extern void
+ ring_consume_data(Ring *ring, unsigned char *buffer, int count);
+#endif
+
+/* Buffer state transition routines */
+extern void
+ ring_supplied(Ring *ring, int count),
+ ring_consumed(Ring *ring, int count);
+
+/* Buffer state query routines */
+extern int
+ ring_at_mark(Ring *),
+ ring_empty_count(Ring *ring),
+ ring_empty_consecutive(Ring *ring),
+ ring_full_count(Ring *ring),
+ ring_full_consecutive(Ring *ring);
+
+#ifdef ENCRYPTION
+extern void
+ ring_encrypt(Ring *ring, void (*func)(unsigned char *, int)),
+ ring_clearto(Ring *ring);
+#endif /* ENCRYPTION */
+
+extern void
+ ring_clear_mark(Ring *),
+ ring_mark(Ring *);
diff --git a/remote_cmds/telnet.tproj/sys_bsd.c b/remote_cmds/telnet.tproj/sys_bsd.c
new file mode 100644
index 0000000..0c08223
--- /dev/null
+++ b/remote_cmds/telnet.tproj/sys_bsd.c
@@ -0,0 +1,1145 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)sys_bsd.c 8.4 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/sys_bsd.c,v 1.12 2003/05/04 02:54:48 obrien Exp $");
+
+/*
+ * The following routines try to encapsulate what is system dependent
+ * (at least between 4.x and dos) which is used in telnet.c.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/telnet.h>
+
+#include "ring.h"
+#include "fdset.h"
+#include "defines.h"
+#include "externs.h"
+#include "types.h"
+
+int
+ tout, /* Output file descriptor */
+ tin, /* Input file descriptor */
+ net;
+
+#ifndef USE_TERMIO
+struct tchars otc = { 0 }, ntc = { 0 };
+struct ltchars oltc = { 0 }, nltc = { 0 };
+struct sgttyb ottyb = { 0 }, nttyb = { 0 };
+int olmode = 0;
+# define cfgetispeed(ptr) (ptr)->sg_ispeed
+# define cfgetospeed(ptr) (ptr)->sg_ospeed
+# define old_tc ottyb
+
+#else /* USE_TERMIO */
+struct termio old_tc = { 0, 0, 0, 0, {}, 0, 0 };
+
+# ifndef TCSANOW
+# ifdef TCSETS
+# define TCSANOW TCSETS
+# define TCSADRAIN TCSETSW
+# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
+# else
+# ifdef TCSETA
+# define TCSANOW TCSETA
+# define TCSADRAIN TCSETAW
+# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
+# else
+# define TCSANOW TIOCSETA
+# define TCSADRAIN TIOCSETAW
+# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
+# endif
+# endif
+# define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
+# define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
+# ifdef CIBAUD
+# define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
+# else
+# define cfgetispeed(ptr) cfgetospeed(ptr)
+# endif
+# endif /* TCSANOW */
+# ifdef sysV88
+# define TIOCFLUSH TC_PX_DRAIN
+# endif
+#endif /* USE_TERMIO */
+
+static fd_set *ibitsp, *obitsp, *xbitsp;
+int fdsn;
+
+#ifdef SIGINT
+static SIG_FUNC_RET intr(int);
+#endif /* SIGINT */
+#ifdef SIGQUIT
+static SIG_FUNC_RET intr2(int);
+#endif /* SIGQUIT */
+#ifdef SIGTSTP
+static SIG_FUNC_RET susp(int);
+#endif /* SIGTSTP */
+#ifdef SIGINFO
+static SIG_FUNC_RET ayt(int);
+#endif
+
+void
+init_sys(void)
+{
+ tout = fileno(stdout);
+ tin = fileno(stdin);
+ errno = 0;
+}
+
+int
+TerminalWrite(char *buf, int n)
+{
+ return write(tout, buf, n);
+}
+
+int
+TerminalRead(char *buf, int n)
+{
+ return read(tin, buf, n);
+}
+
+/*
+ *
+ */
+
+int
+TerminalAutoFlush(void)
+{
+#if defined(LNOFLSH)
+ int flush;
+
+ ioctl(0, TIOCLGET, (char *)&flush);
+ return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */
+#else /* LNOFLSH */
+ return 1;
+#endif /* LNOFLSH */
+}
+
+#ifdef KLUDGELINEMODE
+extern int kludgelinemode;
+#endif
+/*
+ * TerminalSpecialChars()
+ *
+ * Look at an input character to see if it is a special character
+ * and decide what to do.
+ *
+ * Output:
+ *
+ * 0 Don't add this character.
+ * 1 Do add this character
+ */
+
+int
+TerminalSpecialChars(int c)
+{
+ if (c == termIntChar) {
+ intp();
+ return 0;
+ } else if (c == termQuitChar) {
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode)
+ sendbrk();
+ else
+#endif
+ sendabort();
+ return 0;
+ } else if (c == termEofChar) {
+ if (my_want_state_is_will(TELOPT_LINEMODE)) {
+ sendeof();
+ return 0;
+ }
+ return 1;
+ } else if (c == termSuspChar) {
+ sendsusp();
+ return(0);
+ } else if (c == termFlushChar) {
+ xmitAO(); /* Transmit Abort Output */
+ return 0;
+ } else if (!MODE_LOCAL_CHARS(globalmode)) {
+ if (c == termKillChar) {
+ xmitEL();
+ return 0;
+ } else if (c == termEraseChar) {
+ xmitEC(); /* Transmit Erase Character */
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+/*
+ * Flush output to the terminal
+ */
+
+void
+TerminalFlushOutput(void)
+{
+#ifdef TIOCFLUSH
+ (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
+#else
+ (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
+#endif
+}
+
+void
+TerminalSaveState(void)
+{
+#ifndef USE_TERMIO
+ ioctl(0, TIOCGETP, (char *)&ottyb);
+ ioctl(0, TIOCGETC, (char *)&otc);
+ ioctl(0, TIOCGLTC, (char *)&oltc);
+ ioctl(0, TIOCLGET, (char *)&olmode);
+
+ ntc = otc;
+ nltc = oltc;
+ nttyb = ottyb;
+
+#else /* USE_TERMIO */
+ tcgetattr(0, &old_tc);
+
+ new_tc = old_tc;
+
+#ifndef VDISCARD
+ termFlushChar = CONTROL('O');
+#endif
+#ifndef VWERASE
+ termWerasChar = CONTROL('W');
+#endif
+#ifndef VREPRINT
+ termRprntChar = CONTROL('R');
+#endif
+#ifndef VLNEXT
+ termLiteralNextChar = CONTROL('V');
+#endif
+#ifndef VSTART
+ termStartChar = CONTROL('Q');
+#endif
+#ifndef VSTOP
+ termStopChar = CONTROL('S');
+#endif
+#ifndef VSTATUS
+ termAytChar = CONTROL('T');
+#endif
+#endif /* USE_TERMIO */
+}
+
+cc_t *
+tcval(int func)
+{
+ switch(func) {
+ case SLC_IP: return(&termIntChar);
+ case SLC_ABORT: return(&termQuitChar);
+ case SLC_EOF: return(&termEofChar);
+ case SLC_EC: return(&termEraseChar);
+ case SLC_EL: return(&termKillChar);
+ case SLC_XON: return(&termStartChar);
+ case SLC_XOFF: return(&termStopChar);
+ case SLC_FORW1: return(&termForw1Char);
+#ifdef USE_TERMIO
+ case SLC_FORW2: return(&termForw2Char);
+# ifdef VDISCARD
+ case SLC_AO: return(&termFlushChar);
+# endif
+# ifdef VSUSP
+ case SLC_SUSP: return(&termSuspChar);
+# endif
+# ifdef VWERASE
+ case SLC_EW: return(&termWerasChar);
+# endif
+# ifdef VREPRINT
+ case SLC_RP: return(&termRprntChar);
+# endif
+# ifdef VLNEXT
+ case SLC_LNEXT: return(&termLiteralNextChar);
+# endif
+# ifdef VSTATUS
+ case SLC_AYT: return(&termAytChar);
+# endif
+#endif
+
+ case SLC_SYNCH:
+ case SLC_BRK:
+ case SLC_EOR:
+ default:
+ return((cc_t *)0);
+ }
+}
+
+void
+TerminalDefaultChars(void)
+{
+#ifndef USE_TERMIO
+ ntc = otc;
+ nltc = oltc;
+ nttyb.sg_kill = ottyb.sg_kill;
+ nttyb.sg_erase = ottyb.sg_erase;
+#else /* USE_TERMIO */
+ memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
+# ifndef VDISCARD
+ termFlushChar = CONTROL('O');
+# endif
+# ifndef VWERASE
+ termWerasChar = CONTROL('W');
+# endif
+# ifndef VREPRINT
+ termRprntChar = CONTROL('R');
+# endif
+# ifndef VLNEXT
+ termLiteralNextChar = CONTROL('V');
+# endif
+# ifndef VSTART
+ termStartChar = CONTROL('Q');
+# endif
+# ifndef VSTOP
+ termStopChar = CONTROL('S');
+# endif
+# ifndef VSTATUS
+ termAytChar = CONTROL('T');
+# endif
+#endif /* USE_TERMIO */
+}
+
+/*
+ * TerminalNewMode - set up terminal to a specific mode.
+ * MODE_ECHO: do local terminal echo
+ * MODE_FLOW: do local flow control
+ * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
+ * MODE_EDIT: do local line editing
+ *
+ * Command mode:
+ * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
+ * local echo
+ * local editing
+ * local xon/xoff
+ * local signal mapping
+ *
+ * Linemode:
+ * local/no editing
+ * Both Linemode and Single Character mode:
+ * local/remote echo
+ * local/no xon/xoff
+ * local/no signal mapping
+ */
+
+void
+TerminalNewMode(int f)
+{
+ static int prevmode = 0;
+#ifndef USE_TERMIO
+ struct tchars tc;
+ struct ltchars ltc;
+ struct sgttyb sb;
+ int lmode;
+#else /* USE_TERMIO */
+ struct termio tmp_tc;
+#endif /* USE_TERMIO */
+ int onoff;
+ int old;
+ cc_t esc;
+
+ globalmode = f&~MODE_FORCE;
+ if (prevmode == f)
+ return;
+
+ /*
+ * Write any outstanding data before switching modes
+ * ttyflush() returns 0 only when there is no more data
+ * left to write out, it returns -1 if it couldn't do
+ * anything at all, otherwise it returns 1 + the number
+ * of characters left to write.
+#ifndef USE_TERMIO
+ * We would really like ask the kernel to wait for the output
+ * to drain, like we can do with the TCSADRAIN, but we don't have
+ * that option. The only ioctl that waits for the output to
+ * drain, TIOCSETP, also flushes the input queue, which is NOT
+ * what we want (TIOCSETP is like TCSADFLUSH).
+#endif
+ */
+ old = ttyflush(SYNCHing|flushout);
+ if (old < 0 || old > 1) {
+#ifdef USE_TERMIO
+ tcgetattr(tin, &tmp_tc);
+#endif /* USE_TERMIO */
+ do {
+ /*
+ * Wait for data to drain, then flush again.
+ */
+#ifdef USE_TERMIO
+ tcsetattr(tin, TCSADRAIN, &tmp_tc);
+#endif /* USE_TERMIO */
+ old = ttyflush(SYNCHing|flushout);
+ } while (old < 0 || old > 1);
+ }
+
+ old = prevmode;
+ prevmode = f&~MODE_FORCE;
+#ifndef USE_TERMIO
+ sb = nttyb;
+ tc = ntc;
+ ltc = nltc;
+ lmode = olmode;
+#else
+ tmp_tc = new_tc;
+#endif
+
+ if (f&MODE_ECHO) {
+#ifndef USE_TERMIO
+ sb.sg_flags |= ECHO;
+#else
+ tmp_tc.c_lflag |= ECHO;
+ tmp_tc.c_oflag |= ONLCR;
+ if (crlf)
+ tmp_tc.c_iflag |= ICRNL;
+#endif
+ } else {
+#ifndef USE_TERMIO
+ sb.sg_flags &= ~ECHO;
+#else
+ tmp_tc.c_lflag &= ~ECHO;
+ tmp_tc.c_oflag &= ~ONLCR;
+#endif
+ }
+
+ if ((f&MODE_FLOW) == 0) {
+#ifndef USE_TERMIO
+ tc.t_startc = _POSIX_VDISABLE;
+ tc.t_stopc = _POSIX_VDISABLE;
+#else
+ tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */
+ } else {
+ if (restartany < 0) {
+ tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */
+ } else if (restartany > 0) {
+ tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
+ } else {
+ tmp_tc.c_iflag |= IXOFF|IXON;
+ tmp_tc.c_iflag &= ~IXANY;
+ }
+#endif
+ }
+
+ if ((f&MODE_TRAPSIG) == 0) {
+#ifndef USE_TERMIO
+ tc.t_intrc = _POSIX_VDISABLE;
+ tc.t_quitc = _POSIX_VDISABLE;
+ tc.t_eofc = _POSIX_VDISABLE;
+ ltc.t_suspc = _POSIX_VDISABLE;
+ ltc.t_dsuspc = _POSIX_VDISABLE;
+#else
+ tmp_tc.c_lflag &= ~ISIG;
+#endif
+ localchars = 0;
+ } else {
+#ifdef USE_TERMIO
+ tmp_tc.c_lflag |= ISIG;
+#endif
+ localchars = 1;
+ }
+
+ if (f&MODE_EDIT) {
+#ifndef USE_TERMIO
+ sb.sg_flags &= ~CBREAK;
+ sb.sg_flags |= CRMOD;
+#else
+ tmp_tc.c_lflag |= ICANON;
+#endif
+ } else {
+#ifndef USE_TERMIO
+ sb.sg_flags |= CBREAK;
+ if (f&MODE_ECHO)
+ sb.sg_flags |= CRMOD;
+ else
+ sb.sg_flags &= ~CRMOD;
+#else
+ tmp_tc.c_lflag &= ~ICANON;
+ tmp_tc.c_iflag &= ~ICRNL;
+ tmp_tc.c_cc[VMIN] = 1;
+ tmp_tc.c_cc[VTIME] = 0;
+#endif
+ }
+
+ if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
+#ifndef USE_TERMIO
+ ltc.t_lnextc = _POSIX_VDISABLE;
+#else
+# ifdef VLNEXT
+ tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
+# endif
+#endif
+ }
+
+ if (f&MODE_SOFT_TAB) {
+#ifndef USE_TERMIO
+ sb.sg_flags |= XTABS;
+#else
+# ifdef OXTABS
+ tmp_tc.c_oflag |= OXTABS;
+# endif
+# ifdef TABDLY
+ tmp_tc.c_oflag &= ~TABDLY;
+ tmp_tc.c_oflag |= TAB3;
+# endif
+#endif
+ } else {
+#ifndef USE_TERMIO
+ sb.sg_flags &= ~XTABS;
+#else
+# ifdef OXTABS
+ tmp_tc.c_oflag &= ~OXTABS;
+# endif
+# ifdef TABDLY
+ tmp_tc.c_oflag &= ~TABDLY;
+# endif
+#endif
+ }
+
+ if (f&MODE_LIT_ECHO) {
+#ifndef USE_TERMIO
+ lmode &= ~LCTLECH;
+#else
+# ifdef ECHOCTL
+ tmp_tc.c_lflag &= ~ECHOCTL;
+# endif
+#endif
+ } else {
+#ifndef USE_TERMIO
+ lmode |= LCTLECH;
+#else
+# ifdef ECHOCTL
+ tmp_tc.c_lflag |= ECHOCTL;
+# endif
+#endif
+ }
+
+ if (f == -1) {
+ onoff = 0;
+ } else {
+#ifndef USE_TERMIO
+ if (f & MODE_OUTBIN)
+ lmode |= LLITOUT;
+ else
+ lmode &= ~LLITOUT;
+
+ if (f & MODE_INBIN)
+ lmode |= LPASS8;
+ else
+ lmode &= ~LPASS8;
+#else
+ if (f & MODE_INBIN)
+ tmp_tc.c_iflag &= ~ISTRIP;
+ else
+ tmp_tc.c_iflag |= ISTRIP;
+ if (f & MODE_OUTBIN) {
+ tmp_tc.c_cflag &= ~(CSIZE|PARENB);
+ tmp_tc.c_cflag |= CS8;
+ tmp_tc.c_oflag &= ~OPOST;
+ } else {
+ tmp_tc.c_cflag &= ~(CSIZE|PARENB);
+ tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
+ tmp_tc.c_oflag |= OPOST;
+ }
+#endif
+ onoff = 1;
+ }
+
+ if (f != -1) {
+#ifdef SIGINT
+ (void) signal(SIGINT, intr);
+#endif
+#ifdef SIGQUIT
+ (void) signal(SIGQUIT, intr2);
+#endif
+#ifdef SIGTSTP
+ (void) signal(SIGTSTP, susp);
+#endif /* SIGTSTP */
+#ifdef SIGINFO
+ (void) signal(SIGINFO, ayt);
+#endif
+#if defined(USE_TERMIO) && defined(NOKERNINFO)
+ tmp_tc.c_lflag |= NOKERNINFO;
+#endif
+ /*
+ * We don't want to process ^Y here. It's just another
+ * character that we'll pass on to the back end. It has
+ * to process it because it will be processed when the
+ * user attempts to read it, not when we send it.
+ */
+#ifndef USE_TERMIO
+ ltc.t_dsuspc = _POSIX_VDISABLE;
+#else
+# ifdef VDSUSP
+ tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
+# endif
+#endif
+#ifdef USE_TERMIO
+ /*
+ * If the VEOL character is already set, then use VEOL2,
+ * otherwise use VEOL.
+ */
+ esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
+ if ((tmp_tc.c_cc[VEOL] != esc)
+# ifdef VEOL2
+ && (tmp_tc.c_cc[VEOL2] != esc)
+# endif
+ ) {
+ if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
+ tmp_tc.c_cc[VEOL] = esc;
+# ifdef VEOL2
+ else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
+ tmp_tc.c_cc[VEOL2] = esc;
+# endif
+ }
+#else
+ if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
+ tc.t_brkc = esc;
+#endif
+ } else {
+#ifdef SIGINFO
+ (void) signal(SIGINFO, (void (*)(int))ayt_status);
+#endif
+#ifdef SIGINT
+ (void) signal(SIGINT, SIG_DFL);
+#endif
+#ifdef SIGQUIT
+ (void) signal(SIGQUIT, SIG_DFL);
+#endif
+#ifdef SIGTSTP
+ (void) signal(SIGTSTP, SIG_DFL);
+# ifndef SOLARIS
+ (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
+# else /* SOLARIS */
+ (void) sigrelse(SIGTSTP);
+# endif /* SOLARIS */
+#endif /* SIGTSTP */
+#ifndef USE_TERMIO
+ ltc = oltc;
+ tc = otc;
+ sb = ottyb;
+ lmode = olmode;
+#else
+ tmp_tc = old_tc;
+#endif
+ }
+#ifndef USE_TERMIO
+ ioctl(tin, TIOCLSET, (char *)&lmode);
+ ioctl(tin, TIOCSLTC, (char *)&ltc);
+ ioctl(tin, TIOCSETC, (char *)&tc);
+ ioctl(tin, TIOCSETN, (char *)&sb);
+#else
+ if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
+ tcsetattr(tin, TCSANOW, &tmp_tc);
+#endif
+
+ ioctl(tin, FIONBIO, (char *)&onoff);
+ ioctl(tout, FIONBIO, (char *)&onoff);
+
+}
+
+/*
+ * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
+ */
+#if B4800 != 4800
+#define DECODE_BAUD
+#endif
+
+#ifdef DECODE_BAUD
+#ifndef B7200
+#define B7200 B4800
+#endif
+
+#ifndef B14400
+#define B14400 B9600
+#endif
+
+#ifndef B19200
+# define B19200 B14400
+#endif
+
+#ifndef B28800
+#define B28800 B19200
+#endif
+
+#ifndef B38400
+# define B38400 B28800
+#endif
+
+#ifndef B57600
+#define B57600 B38400
+#endif
+
+#ifndef B76800
+#define B76800 B57600
+#endif
+
+#ifndef B115200
+#define B115200 B76800
+#endif
+
+#ifndef B230400
+#define B230400 B115200
+#endif
+
+
+/*
+ * This code assumes that the values B0, B50, B75...
+ * are in ascending order. They do not have to be
+ * contiguous.
+ */
+struct termspeeds {
+ long speed;
+ long value;
+} termspeeds[] = {
+ { 0, B0 }, { 50, B50 }, { 75, B75 },
+ { 110, B110 }, { 134, B134 }, { 150, B150 },
+ { 200, B200 }, { 300, B300 }, { 600, B600 },
+ { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
+ { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 },
+ { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 },
+ { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 },
+ { 230400, B230400 }, { -1, B230400 }
+};
+#endif /* DECODE_BAUD */
+
+void
+TerminalSpeeds(long *ispeed, long *ospeed)
+{
+#ifdef DECODE_BAUD
+ struct termspeeds *tp;
+#endif /* DECODE_BAUD */
+ long in, out;
+
+ out = cfgetospeed(&old_tc);
+ in = cfgetispeed(&old_tc);
+ if (in == 0)
+ in = out;
+
+#ifdef DECODE_BAUD
+ tp = termspeeds;
+ while ((tp->speed != -1) && (tp->value < in))
+ tp++;
+ *ispeed = tp->speed;
+
+ tp = termspeeds;
+ while ((tp->speed != -1) && (tp->value < out))
+ tp++;
+ *ospeed = tp->speed;
+#else /* DECODE_BAUD */
+ *ispeed = in;
+ *ospeed = out;
+#endif /* DECODE_BAUD */
+}
+
+int
+TerminalWindowSize(long *rows, long *cols)
+{
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+
+ if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
+ *rows = ws.ws_row;
+ *cols = ws.ws_col;
+ return 1;
+ }
+#endif /* TIOCGWINSZ */
+ return 0;
+}
+
+int
+NetClose(int fd)
+{
+ return close(fd);
+}
+
+static void
+NetNonblockingIO(int fd, int onoff)
+{
+ ioctl(fd, FIONBIO, (char *)&onoff);
+}
+
+
+/*
+ * Various signal handling routines.
+ */
+
+/* ARGSUSED */
+static SIG_FUNC_RET
+deadpeer(int sig __unused)
+{
+ setcommandmode();
+ longjmp(peerdied, -1);
+}
+
+/* ARGSUSED */
+SIG_FUNC_RET
+intr(int sig __unused)
+{
+ if (localchars) {
+ intp();
+ return;
+ }
+ setcommandmode();
+ longjmp(toplevel, -1);
+}
+
+/* ARGSUSED */
+SIG_FUNC_RET
+intr2(int sig __unused)
+{
+ if (localchars) {
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode)
+ sendbrk();
+ else
+#endif
+ sendabort();
+ return;
+ }
+}
+
+#ifdef SIGTSTP
+/* ARGSUSED */
+SIG_FUNC_RET
+susp(int sig __unused)
+{
+ if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
+ return;
+ if (localchars)
+ sendsusp();
+}
+#endif
+
+#ifdef SIGWINCH
+/* ARGSUSED */
+static SIG_FUNC_RET
+sendwin(int sig __unused)
+{
+ if (connected) {
+ sendnaws();
+ }
+}
+#endif
+
+#ifdef SIGINFO
+/* ARGSUSED */
+SIG_FUNC_RET
+ayt(int sig __unused)
+{
+ if (connected)
+ sendayt();
+ else
+ ayt_status();
+}
+#endif
+
+
+void
+sys_telnet_init(void)
+{
+ (void) signal(SIGINT, intr);
+ (void) signal(SIGQUIT, intr2);
+ (void) signal(SIGPIPE, deadpeer);
+#ifdef SIGWINCH
+ (void) signal(SIGWINCH, sendwin);
+#endif
+#ifdef SIGTSTP
+ (void) signal(SIGTSTP, susp);
+#endif
+#ifdef SIGINFO
+ (void) signal(SIGINFO, ayt);
+#endif
+
+ setconnmode(0);
+
+ NetNonblockingIO(net, 1);
+
+#if defined(SO_OOBINLINE)
+ if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
+ perror("SetSockOpt");
+ }
+#endif /* defined(SO_OOBINLINE) */
+}
+
+/*
+ * Process rings -
+ *
+ * This routine tries to fill up/empty our various rings.
+ *
+ * The parameter specifies whether this is a poll operation,
+ * or a block-until-something-happens operation.
+ *
+ * The return value is 1 if something happened, 0 if not.
+ */
+
+int
+process_rings(int netin, int netout, int netex, int ttyin, int ttyout, int poll)
+{
+ int c;
+ int returnValue = 0;
+ static struct timeval TimeValue = { 0, 0 };
+ int maxfd = -1;
+ int tmp;
+
+ if ((netout || netin || netex) && net > maxfd)
+ maxfd = net;
+
+ if (ttyout && tout > maxfd)
+ maxfd = tout;
+ if (ttyin && tin > maxfd)
+ maxfd = tin;
+ tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
+ if (tmp > fdsn) {
+ if (ibitsp)
+ free(ibitsp);
+ if (obitsp)
+ free(obitsp);
+ if (xbitsp)
+ free(xbitsp);
+
+ fdsn = tmp;
+ if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL)
+ err(1, "malloc");
+ if ((obitsp = (fd_set *)malloc(fdsn)) == NULL)
+ err(1, "malloc");
+ if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL)
+ err(1, "malloc");
+ memset(ibitsp, 0, fdsn);
+ memset(obitsp, 0, fdsn);
+ memset(xbitsp, 0, fdsn);
+ }
+
+ if (netout)
+ FD_SET(net, obitsp);
+ if (ttyout)
+ FD_SET(tout, obitsp);
+ if (ttyin)
+ FD_SET(tin, ibitsp);
+ if (netin)
+ FD_SET(net, ibitsp);
+ if (netex)
+ FD_SET(net, xbitsp);
+ if ((c = select(maxfd + 1, ibitsp, obitsp, xbitsp,
+ (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
+ if (c == -1) {
+ /*
+ * we can get EINTR if we are in line mode,
+ * and the user does an escape (TSTP), or
+ * some other signal generator.
+ */
+ if (errno == EINTR) {
+ return 0;
+ }
+ /* I don't like this, does it ever happen? */
+ printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno));
+ sleep(5);
+ }
+ return 0;
+ }
+
+ /*
+ * Any urgent data?
+ */
+ if (FD_ISSET(net, xbitsp)) {
+ FD_CLR(net, xbitsp);
+ SYNCHing = 1;
+ (void) ttyflush(1); /* flush already enqueued data */
+ }
+
+ /*
+ * Something to read from the network...
+ */
+ if (FD_ISSET(net, ibitsp)) {
+ int canread;
+
+ FD_CLR(net, ibitsp);
+ canread = ring_empty_consecutive(&netiring);
+#if !defined(SO_OOBINLINE)
+ /*
+ * In 4.2 (and some early 4.3) systems, the
+ * OOB indication and data handling in the kernel
+ * is such that if two separate TCP Urgent requests
+ * come in, one byte of TCP data will be overlaid.
+ * This is fatal for Telnet, but we try to live
+ * with it.
+ *
+ * In addition, in 4.2 (and...), a special protocol
+ * is needed to pick up the TCP Urgent data in
+ * the correct sequence.
+ *
+ * What we do is: if we think we are in urgent
+ * mode, we look to see if we are "at the mark".
+ * If we are, we do an OOB receive. If we run
+ * this twice, we will do the OOB receive twice,
+ * but the second will fail, since the second
+ * time we were "at the mark", but there wasn't
+ * any data there (the kernel doesn't reset
+ * "at the mark" until we do a normal read).
+ * Once we've read the OOB data, we go ahead
+ * and do normal reads.
+ *
+ * There is also another problem, which is that
+ * since the OOB byte we read doesn't put us
+ * out of OOB state, and since that byte is most
+ * likely the TELNET DM (data mark), we would
+ * stay in the TELNET SYNCH (SYNCHing) state.
+ * So, clocks to the rescue. If we've "just"
+ * received a DM, then we test for the
+ * presence of OOB data when the receive OOB
+ * fails (and AFTER we did the normal mode read
+ * to clear "at the mark").
+ */
+ if (SYNCHing) {
+ int atmark;
+ static int bogus_oob = 0, first = 1;
+
+ ioctl(net, SIOCATMARK, (char *)&atmark);
+ if (atmark) {
+ c = recv(net, netiring.supply, canread, MSG_OOB);
+ if ((c == -1) && (errno == EINVAL)) {
+ c = recv(net, netiring.supply, canread, 0);
+ if (clocks.didnetreceive < clocks.gotDM) {
+ SYNCHing = stilloob(net);
+ }
+ } else if (first && c > 0) {
+ /*
+ * Bogosity check. Systems based on 4.2BSD
+ * do not return an error if you do a second
+ * recv(MSG_OOB). So, we do one. If it
+ * succeeds and returns exactly the same
+ * data, then assume that we are running
+ * on a broken system and set the bogus_oob
+ * flag. (If the data was different, then
+ * we probably got some valid new data, so
+ * increment the count...)
+ */
+ int i;
+ i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
+ if (i == c &&
+ memcmp(netiring.supply, netiring.supply + c, i) == 0) {
+ bogus_oob = 1;
+ first = 0;
+ } else if (i < 0) {
+ bogus_oob = 0;
+ first = 0;
+ } else
+ c += i;
+ }
+ if (bogus_oob && c > 0) {
+ int i;
+ /*
+ * Bogosity. We have to do the read
+ * to clear the atmark to get out of
+ * an infinate loop.
+ */
+ i = read(net, netiring.supply + c, canread - c);
+ if (i > 0)
+ c += i;
+ }
+ } else {
+ c = recv(net, netiring.supply, canread, 0);
+ }
+ } else {
+ c = recv(net, netiring.supply, canread, 0);
+ }
+ settimer(didnetreceive);
+#else /* !defined(SO_OOBINLINE) */
+ c = recv(net, (char *)netiring.supply, canread, 0);
+#endif /* !defined(SO_OOBINLINE) */
+ if (c < 0 && errno == EWOULDBLOCK) {
+ c = 0;
+ } else if (c <= 0) {
+ return -1;
+ }
+ if (netdata) {
+ Dump('<', netiring.supply, c);
+ }
+ if (c)
+ ring_supplied(&netiring, c);
+ returnValue = 1;
+ }
+
+ /*
+ * Something to read from the tty...
+ */
+ if (FD_ISSET(tin, ibitsp)) {
+ FD_CLR(tin, ibitsp);
+ c = TerminalRead((char*)ttyiring.supply, ring_empty_consecutive(&ttyiring));
+ if (c < 0 && errno == EIO)
+ c = 0;
+ if (c < 0 && errno == EWOULDBLOCK) {
+ c = 0;
+ } else {
+ /* EOF detection for line mode!!!! */
+ if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
+ /* must be an EOF... */
+ *ttyiring.supply = termEofChar;
+ c = 1;
+ }
+ if (c <= 0) {
+ return -1;
+ }
+ if (termdata) {
+ Dump('<', ttyiring.supply, c);
+ }
+ ring_supplied(&ttyiring, c);
+ }
+ returnValue = 1; /* did something useful */
+ }
+
+ if (FD_ISSET(net, obitsp)) {
+ FD_CLR(net, obitsp);
+ returnValue |= netflush();
+ }
+ if (FD_ISSET(tout, obitsp)) {
+ FD_CLR(tout, obitsp);
+ returnValue |= (ttyflush(SYNCHing|flushout) > 0);
+ }
+
+ return returnValue;
+}
diff --git a/remote_cmds/telnet.tproj/telnet.1 b/remote_cmds/telnet.tproj/telnet.1
new file mode 100644
index 0000000..46d129d
--- /dev/null
+++ b/remote_cmds/telnet.tproj/telnet.1
@@ -0,0 +1,1417 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)telnet.1 8.6 (Berkeley) 6/1/94
+.\" $FreeBSD: src/crypto/telnet/telnet/telnet.1,v 1.4.2.9 2002/04/13 10:59:08 markm Exp $
+.\"
+.Dd January 27, 2000
+.Dt TELNET 1
+.Os
+.Sh NAME
+.Nm telnet
+.Nd user interface to the
+.Tn TELNET
+protocol
+.Sh SYNOPSIS
+.Nm
+.Op Fl 468EFKLNacdfruxy
+.Op Fl S Ar tos
+.Op Fl X Ar authtype
+.Op Fl e Ar escapechar
+.Op Fl k Ar realm
+.Op Fl l Ar user
+.Op Fl n Ar tracefile
+.Op Fl s Ar src_addr
+.Oo
+.Ar host
+.Op Ar port
+.Oc
+.Sh DESCRIPTION
+The
+.Nm
+command
+is used to communicate with another host using the
+.Tn TELNET
+protocol.
+If
+.Nm
+is invoked without the
+.Ar host
+argument, it enters command mode,
+indicated by its prompt
+.Pq Dq Li telnet\&> .
+In this mode, it accepts and executes the commands listed below.
+If it is invoked with arguments, it performs an
+.Ic open
+command with those arguments.
+.Pp
+Options:
+.Bl -tag -width indent
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl 8
+Specifies an 8-bit data path. This causes an attempt to
+negotiate the
+.Dv TELNET BINARY
+option on both input and output.
+.It Fl E
+Stops any character from being recognized as an escape character.
+.It Fl F
+If Kerberos V5 authentication is being used, the
+.Fl F
+option allows the local credentials to be forwarded
+to the remote system, including any credentials that
+have already been forwarded into the local environment.
+.It Fl K
+Specifies no automatic login to the remote system.
+.It Fl L
+Specifies an 8-bit data path on output. This causes the
+.Dv BINARY
+option to be negotiated on output.
+.It Fl N
+Prevents IP address to name lookup when destination host is given
+as an IP address.
+.It Fl S Ar tos
+Sets the IP type-of-service (TOS) option for the telnet
+connection to the value
+.Ar tos ,
+which can be a numeric TOS value
+or, on systems that support it, a symbolic
+TOS name found in the
+.Pa /etc/iptos
+file.
+.It Fl X Ar atype
+Disables the
+.Ar atype
+type of authentication.
+.It Fl a
+Attempt automatic login.
+This is now the default, so this option is ignored.
+Currently, this sends the user name via the
+.Ev USER
+variable
+of the
+.Ev ENVIRON
+option if supported by the remote system.
+The name used is that of the current user as returned by
+.Xr getlogin 2
+if it agrees with the current user ID,
+otherwise it is the name associated with the user ID.
+.It Fl c
+Disables the reading of the user's
+.Pa \&.telnetrc
+file. (See the
+.Ic toggle skiprc
+command on this man page.)
+.It Fl d
+Sets the initial value of the
+.Ic debug
+toggle to
+.Dv TRUE .
+.It Fl e Ar escapechar
+Sets the initial
+.Nm
+escape character to
+.Ar escapechar .
+If
+.Ar escapechar
+is omitted, then
+there will be no escape character.
+.It Fl f
+If Kerberos V5 authentication is being used, the
+.Fl f
+option allows the local credentials to be forwarded to the remote system.
+.It Fl k Ar realm
+If Kerberos authentication is being used, the
+.Fl k
+option requests that
+.Nm
+obtain tickets for the remote host in
+realm
+.Ar realm
+instead of the remote host's realm, as determined by
+.Xr krb_realmofhost 3 .
+.It Fl l Ar user
+When connecting to the remote system, if the remote system
+understands the
+.Ev ENVIRON
+option, then
+.Ar user
+will be sent to the remote system as the value for the variable
+.Ev USER .
+This option implies the
+.Fl a
+option.
+This option may also be used with the
+.Ic open
+command.
+.It Fl n Ar tracefile
+Opens
+.Ar tracefile
+for recording trace information.
+See the
+.Ic set tracefile
+command below.
+.It Fl r
+Specifies a user interface similar to
+.Xr rlogin 1 .
+In this
+mode, the escape character is set to the tilde (~) character,
+unless modified by the
+.Fl e
+option.
+.It Fl s Ar src_addr
+Set the source IP address for the
+.Nm
+connection to
+.Ar src_addr ,
+which can be an IP address or a host name.
+.It Fl u
+Forces
+.Nm
+to use
+.Dv AF_UNIX
+addresses only (e.g.,
+.Ux
+domain sockets, accessed with a file path).
+.It Fl x
+Turns on encryption of the data stream if possible.
+This is now the default, so this option is ignored.
+.It Fl y
+Suppresses encryption of the data stream.
+.It Ar host
+Indicates the official name, an alias, or the Internet address
+of a remote host.
+If
+.Ar host
+starts with a
+.Ql / ,
+.Nm
+establishes a connection to the corresponding named socket.
+.It Ar port
+Indicates a port number (address of an application). If a number is
+not specified, the default
+.Nm
+port is used.
+.El
+.Pp
+When in rlogin mode, a line of the form ~. disconnects from the
+remote host; ~ is the
+.Nm
+escape character.
+Similarly, the line ~^Z suspends the
+.Nm
+session.
+The line ~^] escapes to the normal
+.Nm
+escape prompt.
+.Pp
+Once a connection has been opened,
+.Nm
+will attempt to enable the
+.Dv TELNET LINEMODE
+option.
+If this fails, then
+.Nm
+will revert to one of two input modes:
+either \*(Lqcharacter at a time\*(Rq
+or \*(Lqold line by line\*(Rq
+depending on what the remote system supports.
+.Pp
+When
+.Dv LINEMODE
+is enabled, character processing is done on the
+local system, under the control of the remote system. When input
+editing or character echoing is to be disabled, the remote system
+will relay that information. The remote system will also relay
+changes to any special characters that happen on the remote
+system, so that they can take effect on the local system.
+.Pp
+In \*(Lqcharacter at a time\*(Rq mode, most
+text typed is immediately sent to the remote host for processing.
+.Pp
+In \*(Lqold line by line\*(Rq mode, all text is echoed locally,
+and (normally) only completed lines are sent to the remote host.
+The \*(Lqlocal echo character\*(Rq (initially \*(Lq^E\*(Rq) may be used
+to turn off and on the local echo
+(this would mostly be used to enter passwords
+without the password being echoed).
+.Pp
+If the
+.Dv LINEMODE
+option is enabled, or if the
+.Ic localchars
+toggle is
+.Dv TRUE
+(the default for \*(Lqold line by line\*(Rq; see below),
+the user's
+.Ic quit ,
+.Ic intr ,
+and
+.Ic flush
+characters are trapped locally, and sent as
+.Tn TELNET
+protocol sequences to the remote side.
+If
+.Dv LINEMODE
+has ever been enabled, then the user's
+.Ic susp
+and
+.Ic eof
+are also sent as
+.Tn TELNET
+protocol sequences,
+and
+.Ic quit
+is sent as a
+.Dv TELNET ABORT
+instead of
+.Dv BREAK .
+There are options (see
+.Ic toggle
+.Ic autoflush
+and
+.Ic toggle
+.Ic autosynch
+below)
+which cause this action to flush subsequent output to the terminal
+(until the remote host acknowledges the
+.Tn TELNET
+sequence) and flush previous terminal input
+(in the case of
+.Ic quit
+and
+.Ic intr ) .
+.Pp
+While connected to a remote host,
+.Nm
+command mode may be entered by typing the
+.Nm
+\*(Lqescape character\*(Rq (initially \*(Lq^]\*(Rq).
+When in command mode, the normal terminal editing conventions are available.
+.Pp
+The following
+.Nm
+commands are available.
+Only enough of each command to uniquely identify it need be typed
+(this is also true for arguments to the
+.Ic mode ,
+.Ic set ,
+.Ic toggle ,
+.Ic unset ,
+.Ic slc ,
+.Ic environ ,
+and
+.Ic display
+commands).
+.Pp
+.Bl -tag -width "mode type"
+.It Ic auth Ar argument ...
+The auth command manipulates the information sent through the
+.Dv TELNET AUTHENTICATE
+option. Valid arguments for the
+.Ic auth
+command are:
+.Bl -tag -width "disable type"
+.It Ic disable Ar type
+Disables the specified type of authentication. To
+obtain a list of available types, use the
+.Ic auth disable ?\&
+command.
+.It Ic enable Ar type
+Enables the specified type of authentication. To
+obtain a list of available types, use the
+.Ic auth enable ?\&
+command.
+.It Ic status
+Lists the current status of the various types of
+authentication.
+.El
+.It Ic close
+Close a
+.Tn TELNET
+session and return to command mode.
+.It Ic display Ar argument ...
+Displays all, or some, of the
+.Ic set
+and
+.Ic toggle
+values (see below).
+.It Ic encrypt Ar argument ...
+The encrypt command manipulates the information sent through the
+.Dv TELNET ENCRYPT
+option.
+.Pp
+Valid arguments for the
+.Ic encrypt
+command are:
+.Bl -tag -width Ar
+.It Ic disable Ar type Xo
+.Op Cm input | output
+.Xc
+Disables the specified type of encryption. If you
+omit the input and output, both input and output
+are disabled. To obtain a list of available
+types, use the
+.Ic encrypt disable ?\&
+command.
+.It Ic enable Ar type Xo
+.Op Cm input | output
+.Xc
+Enables the specified type of encryption. If you
+omit input and output, both input and output are
+enabled. To obtain a list of available types, use the
+.Ic encrypt enable ?\&
+command.
+.It Ic input
+This is the same as the
+.Ic encrypt start input
+command.
+.It Ic -input
+This is the same as the
+.Ic encrypt stop input
+command.
+.It Ic output
+This is the same as the
+.Ic encrypt start output
+command.
+.It Ic -output
+This is the same as the
+.Ic encrypt stop output
+command.
+.It Ic start Op Cm input | output
+Attempts to start encryption. If you omit
+.Ic input
+and
+.Ic output ,
+both input and output are enabled. To
+obtain a list of available types, use the
+.Ic encrypt enable ?\&
+command.
+.It Ic status
+Lists the current status of encryption.
+.It Ic stop Op Cm input | output
+Stops encryption. If you omit input and output,
+encryption is on both input and output.
+.It Ic type Ar type
+Sets the default type of encryption to be used
+with later
+.Ic encrypt start
+or
+.Ic encrypt stop
+commands.
+.El
+.It Ic environ Ar arguments ...
+The
+.Ic environ
+command is used to manipulate the
+variables that may be sent through the
+.Dv TELNET ENVIRON
+option.
+The initial set of variables is populated with the
+contents of the following environment variables, if
+present:
+.Ev USER , PRINTER , DISPLAY , TERM , COLUMNS , LINES.
+Only the first three are exported, by default.
+.Pp
+Valid arguments for the
+.Ic environ
+command are:
+.Bl -tag -width Fl
+.It Ic define Ar variable [value]
+Define the variable
+.Ar variable
+to have a value of
+.Ar value .
+If value is empty, the value is taken from the environment variable.
+Any variables defined by this command are automatically exported.
+The
+.Ar value
+may be enclosed in single or double quotes so
+that tabs and spaces may be included.
+.It Ic undefine Ar variable
+Remove
+.Ar variable
+from the list of environment variables.
+.It Ic export Ar variable
+Mark the variable
+.Ar variable
+to be exported to the remote side.
+.It Ic unexport Ar variable
+Mark the variable
+.Ar variable
+to not be exported unless
+explicitly asked for by the remote side.
+.It Ic list
+List the current set of environment variables.
+Those marked with a
+.Cm *
+will be sent automatically,
+other variables will only be sent if explicitly requested.
+.It Ic ?\&
+Prints out help information for the
+.Ic environ
+command.
+.El
+.It Ic logout
+Sends the
+.Dv TELNET LOGOUT
+option to the remote side.
+This command is similar to a
+.Ic close
+command; however, if the remote side does not support the
+.Dv LOGOUT
+option, nothing happens.
+If, however, the remote side does support the
+.Dv LOGOUT
+option, this command should cause the remote side to close the
+.Tn TELNET
+connection.
+If the remote side also supports the concept of
+suspending a user's session for later reattachment,
+the logout argument indicates that you
+should terminate the session immediately.
+.It Ic mode Ar type
+.Ar Type
+is one of several options, depending on the state of the
+.Tn TELNET
+session.
+The remote host is asked for permission to go into the requested mode.
+If the remote host is capable of entering that mode, the requested
+mode will be entered.
+.Bl -tag -width Ar
+.It Ic character
+Disable the
+.Dv TELNET LINEMODE
+option, or, if the remote side does not understand the
+.Dv LINEMODE
+option, then enter \*(Lqcharacter at a time\*(Rq mode.
+.It Ic line
+Enable the
+.Dv TELNET LINEMODE
+option, or, if the remote side does not understand the
+.Dv LINEMODE
+option, then attempt to enter \*(Lqold-line-by-line\*(Rq mode.
+.It Ic isig Pq Ic \-isig
+Attempt to enable (disable) the
+.Dv TRAPSIG
+mode of the
+.Dv LINEMODE
+option.
+This requires that the
+.Dv LINEMODE
+option be enabled.
+.It Ic edit Pq Ic \-edit
+Attempt to enable (disable) the
+.Dv EDIT
+mode of the
+.Dv LINEMODE
+option.
+This requires that the
+.Dv LINEMODE
+option be enabled.
+.It Ic softtabs Pq Ic \-softtabs
+Attempt to enable (disable) the
+.Dv SOFT_TAB
+mode of the
+.Dv LINEMODE
+option.
+This requires that the
+.Dv LINEMODE
+option be enabled.
+.It Ic litecho Pq Ic \-litecho
+Attempt to enable (disable) the
+.Dv LIT_ECHO
+mode of the
+.Dv LINEMODE
+option.
+This requires that the
+.Dv LINEMODE
+option be enabled.
+.It Ic ?\&
+Prints out help information for the
+.Ic mode
+command.
+.El
+.It Xo
+.Ic open Ar host
+.Op Fl l Ar user
+.Op Oo Fl Oc Ns Ar port
+.Xc
+Open a connection to the named host.
+If no port number
+is specified,
+.Nm
+will attempt to contact a
+.Tn TELNET
+server at the default port.
+The host specification may be either a host name (see
+.Xr hosts 5 ) ,
+an Internet address specified in the \*(Lqdot notation\*(Rq (see
+.Xr inet 3 ) ,
+or IPv6 host name or IPv6 coloned-hexadecimal addreess.
+The
+.Fl l
+option may be used to specify the user name
+to be passed to the remote system via the
+.Ev ENVIRON
+option.
+When connecting to a non-standard port,
+.Nm
+omits any automatic initiation of
+.Tn TELNET
+options. When the port number is preceded by a minus sign,
+the initial option negotiation is done.
+After establishing a connection, the file
+.Pa \&.telnetrc
+in the
+users home directory is opened. Lines beginning with a # are
+comment lines. Blank lines are ignored. Lines that begin
+without white space are the start of a machine entry. The
+first thing on the line is the name of the machine that is
+being connected to. The rest of the line, and successive
+lines that begin with white space are assumed to be
+.Nm
+commands and are processed as if they had been typed
+in manually to the
+.Nm
+command prompt.
+.It Ic quit
+Close any open
+.Tn TELNET
+session and exit
+.Nm .
+An end of file (in command mode) will also close a session and exit.
+.It Ic send Ar arguments
+Sends one or more special character sequences to the remote host.
+The following are the arguments which may be specified
+(more than one argument may be specified at a time):
+.Pp
+.Bl -tag -width escape
+.It Ic abort
+Sends the
+.Dv TELNET ABORT
+(Abort
+processes)
+sequence.
+.It Ic ao
+Sends the
+.Dv TELNET AO
+(Abort Output) sequence, which should cause the remote system to flush
+all output
+.Em from
+the remote system
+.Em to
+the user's terminal.
+.It Ic ayt
+Sends the
+.Dv TELNET AYT
+(Are You There)
+sequence, to which the remote system may or may not choose to respond.
+.It Ic brk
+Sends the
+.Dv TELNET BRK
+(Break) sequence, which may have significance to the remote
+system.
+.It Ic ec
+Sends the
+.Dv TELNET EC
+(Erase Character)
+sequence, which should cause the remote system to erase the last character
+entered.
+.It Ic el
+Sends the
+.Dv TELNET EL
+(Erase Line)
+sequence, which should cause the remote system to erase the line currently
+being entered.
+.It Ic eof
+Sends the
+.Dv TELNET EOF
+(End Of File)
+sequence.
+.It Ic eor
+Sends the
+.Dv TELNET EOR
+(End of Record)
+sequence.
+.It Ic escape
+Sends the current
+.Nm
+escape character (initially \*(Lq^\*(Rq).
+.It Ic ga
+Sends the
+.Dv TELNET GA
+(Go Ahead)
+sequence, which likely has no significance to the remote system.
+.It Ic getstatus
+If the remote side supports the
+.Dv TELNET STATUS
+command,
+.Ic getstatus
+will send the subnegotiation to request that the server send
+its current option status.
+.It Ic ip
+Sends the
+.Dv TELNET IP
+(Interrupt Process) sequence, which should cause the remote
+system to abort the currently running process.
+.It Ic nop
+Sends the
+.Dv TELNET NOP
+(No OPeration)
+sequence.
+.It Ic susp
+Sends the
+.Dv TELNET SUSP
+(SUSPend process)
+sequence.
+.It Ic synch
+Sends the
+.Dv TELNET SYNCH
+sequence.
+This sequence causes the remote system to discard all previously typed
+(but not yet read) input.
+This sequence is sent as
+.Tn TCP
+urgent
+data (and may not work if the remote system is a
+.Bx 4.2
+system -- if
+it doesn't work, a lower case \*(Lqr\*(Rq may be echoed on the terminal).
+.It Ic do Ar cmd
+.It Ic dont Ar cmd
+.It Ic will Ar cmd
+.It Ic wont Ar cmd
+Sends the
+.Dv TELNET DO
+.Ar cmd
+sequence.
+.Ar Cmd
+can be either a decimal number between 0 and 255,
+or a symbolic name for a specific
+.Dv TELNET
+command.
+.Ar Cmd
+can also be either
+.Ic help
+or
+.Ic ?\&
+to print out help information, including
+a list of known symbolic names.
+.It Ic ?\&
+Prints out help information for the
+.Ic send
+command.
+.El
+.It Ic set Ar argument value
+.It Ic unset Ar argument value
+The
+.Ic set
+command will set any one of a number of
+.Nm
+variables to a specific value or to
+.Dv TRUE .
+The special value
+.Ic off
+turns off the function associated with
+the variable, this is equivalent to using the
+.Ic unset
+command.
+The
+.Ic unset
+command will disable or set to
+.Dv FALSE
+any of the specified functions.
+The values of variables may be interrogated with the
+.Ic display
+command.
+The variables which may be set or unset, but not toggled, are
+listed here. In addition, any of the variables for the
+.Ic toggle
+command may be explicitly set or unset using
+the
+.Ic set
+and
+.Ic unset
+commands.
+.Bl -tag -width escape
+.It Ic ayt
+If
+.Tn TELNET
+is in localchars mode, or
+.Dv LINEMODE
+is enabled, and the status character is typed, a
+.Dv TELNET AYT
+sequence (see
+.Ic send ayt
+preceding) is sent to the
+remote host. The initial value for the \*(LqAre You There\*(Rq
+character is the terminal's status character.
+.It Ic echo
+This is the value (initially \*(Lq^E\*(Rq) which, when in
+\*(Lqline by line\*(Rq mode, toggles between doing local echoing
+of entered characters (for normal processing), and suppressing
+echoing of entered characters (for entering, say, a password).
+.It Ic eof
+If
+.Nm
+is operating in
+.Dv LINEMODE
+or \*(Lqold line by line\*(Rq mode, entering this character
+as the first character on a line will cause this character to be
+sent to the remote system.
+The initial value of the eof character is taken to be the terminal's
+.Ic eof
+character.
+.It Ic erase
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below),
+.Sy and
+if
+.Nm
+is operating in \*(Lqcharacter at a time\*(Rq mode, then when this
+character is typed, a
+.Dv TELNET EC
+sequence (see
+.Ic send
+.Ic ec
+above)
+is sent to the remote system.
+The initial value for the erase character is taken to be
+the terminal's
+.Ic erase
+character.
+.It Ic escape
+This is the
+.Nm
+escape character (initially \*(Lq^[\*(Rq) which causes entry
+into
+.Nm
+command mode (when connected to a remote system).
+.It Ic flushoutput
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below)
+and the
+.Ic flushoutput
+character is typed, a
+.Dv TELNET AO
+sequence (see
+.Ic send
+.Ic ao
+above)
+is sent to the remote host.
+The initial value for the flush character is taken to be
+the terminal's
+.Ic flush
+character.
+.It Ic forw1
+.It Ic forw2
+If
+.Nm
+is operating in
+.Dv LINEMODE ,
+these are the
+characters that, when typed, cause partial lines to be
+forwarded to the remote system. The initial value for
+the forwarding characters are taken from the terminal's
+eol and eol2 characters.
+.It Ic interrupt
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below)
+and the
+.Ic interrupt
+character is typed, a
+.Dv TELNET IP
+sequence (see
+.Ic send
+.Ic ip
+above)
+is sent to the remote host.
+The initial value for the interrupt character is taken to be
+the terminal's
+.Ic intr
+character.
+.It Ic kill
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below),
+.Ic and
+if
+.Nm
+is operating in \*(Lqcharacter at a time\*(Rq mode, then when this
+character is typed, a
+.Dv TELNET EL
+sequence (see
+.Ic send
+.Ic el
+above)
+is sent to the remote system.
+The initial value for the kill character is taken to be
+the terminal's
+.Ic kill
+character.
+.It Ic lnext
+If
+.Nm
+is operating in
+.Dv LINEMODE
+or \*(Lqold line by line\*(Rq mode, then this character is taken to
+be the terminal's
+.Ic lnext
+character.
+The initial value for the lnext character is taken to be
+the terminal's
+.Ic lnext
+character.
+.It Ic quit
+If
+.Nm
+is in
+.Ic localchars
+mode (see
+.Ic toggle
+.Ic localchars
+below)
+and the
+.Ic quit
+character is typed, a
+.Dv TELNET BRK
+sequence (see
+.Ic send
+.Ic brk
+above)
+is sent to the remote host.
+The initial value for the quit character is taken to be
+the terminal's
+.Ic quit
+character.
+.It Ic reprint
+If
+.Nm
+is operating in
+.Dv LINEMODE
+or \*(Lqold line by line\*(Rq mode, then this character is taken to
+be the terminal's
+.Ic reprint
+character.
+The initial value for the reprint character is taken to be
+the terminal's
+.Ic reprint
+character.
+.It Ic rlogin
+This is the rlogin escape character.
+If set, the normal
+.Nm
+escape character is ignored unless it is
+preceded by this character at the beginning of a line.
+This character, at the beginning of a line followed by
+a "." closes the connection; when followed by a ^Z it
+suspends the
+.Nm
+command. The initial state is to
+disable the
+.Nm rlogin
+escape character.
+.It Ic start
+If the
+.Dv TELNET TOGGLE-FLOW-CONTROL
+option has been enabled,
+then this character is taken to
+be the terminal's
+.Ic start
+character.
+The initial value for the start character is taken to be
+the terminal's
+.Ic start
+character.
+.It Ic stop
+If the
+.Dv TELNET TOGGLE-FLOW-CONTROL
+option has been enabled,
+then this character is taken to
+be the terminal's
+.Ic stop
+character.
+The initial value for the stop character is taken to be
+the terminal's
+.Ic stop
+character.
+.It Ic susp
+If
+.Nm
+is in
+.Ic localchars
+mode, or
+.Dv LINEMODE
+is enabled, and the
+.Ic suspend
+character is typed, a
+.Dv TELNET SUSP
+sequence (see
+.Ic send
+.Ic susp
+above)
+is sent to the remote host.
+The initial value for the suspend character is taken to be
+the terminal's
+.Ic suspend
+character.
+.It Ic tracefile
+This is the file to which the output, caused by
+.Ic netdata
+or
+.Ic option
+tracing being
+.Dv TRUE ,
+will be written. If it is set to
+.Dq Fl ,
+then tracing information will be written to standard output (the default).
+.It Ic worderase
+If
+.Nm
+is operating in
+.Dv LINEMODE
+or \*(Lqold line by line\*(Rq mode, then this character is taken to
+be the terminal's
+.Ic worderase
+character.
+The initial value for the worderase character is taken to be
+the terminal's
+.Ic worderase
+character.
+.It Ic ?\&
+Displays the legal
+.Ic set
+.Pq Ic unset
+commands.
+.El
+.It Ic opie Ar sequence challenge
+The
+.Ic opie
+command computes a response to the OPIE challenge.
+.It Ic slc Ar state
+The
+.Ic slc
+command (Set Local Characters) is used to set
+or change the state of the special
+characters when the
+.Dv TELNET LINEMODE
+option has
+been enabled. Special characters are characters that get
+mapped to
+.Tn TELNET
+commands sequences (like
+.Ic ip
+or
+.Ic quit )
+or line editing characters (like
+.Ic erase
+and
+.Ic kill ) .
+By default, the local special characters are exported.
+.Bl -tag -width Fl
+.It Ic check
+Verify the current settings for the current special characters.
+The remote side is requested to send all the current special
+character settings, and if there are any discrepancies with
+the local side, the local side will switch to the remote value.
+.It Ic export
+Switch to the local defaults for the special characters. The
+local default characters are those of the local terminal at
+the time when
+.Nm
+was started.
+.It Ic import
+Switch to the remote defaults for the special characters.
+The remote default characters are those of the remote system
+at the time when the
+.Tn TELNET
+connection was established.
+.It Ic ?\&
+Prints out help information for the
+.Ic slc
+command.
+.El
+.It Ic status
+Show the current status of
+.Nm .
+This includes the peer one is connected to, as well
+as the current mode.
+.It Ic toggle Ar arguments ...
+Toggle (between
+.Dv TRUE
+and
+.Dv FALSE )
+various flags that control how
+.Nm
+responds to events.
+These flags may be set explicitly to
+.Dv TRUE
+or
+.Dv FALSE
+using the
+.Ic set
+and
+.Ic unset
+commands listed above.
+More than one argument may be specified.
+The state of these flags may be interrogated with the
+.Ic display
+command.
+Valid arguments are:
+.Bl -tag -width Ar
+.It Ic authdebug
+Turns on debugging information for the authentication code.
+.It Ic autoflush
+If
+.Ic autoflush
+and
+.Ic localchars
+are both
+.Dv TRUE ,
+then when the
+.Ic ao ,
+or
+.Ic quit
+characters are recognized (and transformed into
+.Tn TELNET
+sequences; see
+.Ic set
+above for details),
+.Nm
+refuses to display any data on the user's terminal
+until the remote system acknowledges (via a
+.Dv TELNET TIMING MARK
+option)
+that it has processed those
+.Tn TELNET
+sequences.
+The initial value for this toggle is
+.Dv TRUE
+if the terminal user had not
+done an "stty noflsh", otherwise
+.Dv FALSE
+(see
+.Xr stty 1 ) .
+.It Ic autodecrypt
+When the
+.Dv TELNET ENCRYPT
+option is negotiated, by
+default the actual encryption (decryption) of the data
+stream does not start automatically. The autoencrypt
+(autodecrypt) command states that encryption of the
+output (input) stream should be enabled as soon as
+possible.
+.It Ic autologin
+If the remote side supports the
+.Dv TELNET AUTHENTICATION
+option
+.Nm
+attempts to use it to perform automatic authentication. If the
+.Dv AUTHENTICATION
+option is not supported, the user's login
+name are propagated through the
+.Dv TELNET ENVIRON
+option.
+This command is the same as specifying
+.Fl a
+option on the
+.Ic open
+command.
+.It Ic autosynch
+If
+.Ic autosynch
+and
+.Ic localchars
+are both
+.Dv TRUE ,
+then when either the
+.Ic intr
+or
+.Ic quit
+characters is typed (see
+.Ic set
+above for descriptions of the
+.Ic intr
+and
+.Ic quit
+characters), the resulting
+.Tn TELNET
+sequence sent is followed by the
+.Dv TELNET SYNCH
+sequence.
+This procedure
+.Ic should
+cause the remote system to begin throwing away all previously
+typed input until both of the
+.Tn TELNET
+sequences have been read and acted upon.
+The initial value of this toggle is
+.Dv FALSE .
+.It Ic binary
+Enable or disable the
+.Dv TELNET BINARY
+option on both input and output.
+.It Ic inbinary
+Enable or disable the
+.Dv TELNET BINARY
+option on input.
+.It Ic outbinary
+Enable or disable the
+.Dv TELNET BINARY
+option on output.
+.It Ic crlf
+If this is
+.Dv TRUE ,
+then carriage returns will be sent as
+.Li <CR><LF> .
+If this is
+.Dv FALSE ,
+then carriage returns will be send as
+.Li <CR><NUL> .
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic crmod
+Toggle carriage return mode.
+When this mode is enabled, most carriage return characters received from
+the remote host will be mapped into a carriage return followed by
+a line feed.
+This mode does not affect those characters typed by the user, only
+those received from the remote host.
+This mode is not very useful unless the remote host
+only sends carriage return, but never line feed.
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic debug
+Toggles socket level debugging (useful only to the
+.Ic super user ) .
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic encdebug
+Turns on debugging information for the encryption code.
+.It Ic localchars
+If this is
+.Dv TRUE ,
+then the
+.Ic flush ,
+.Ic interrupt ,
+.Ic quit ,
+.Ic erase ,
+and
+.Ic kill
+characters (see
+.Ic set
+above) are recognized locally, and transformed into (hopefully) appropriate
+.Tn TELNET
+control sequences
+(respectively
+.Ic ao ,
+.Ic ip ,
+.Ic brk ,
+.Ic ec ,
+and
+.Ic el ;
+see
+.Ic send
+above).
+The initial value for this toggle is
+.Dv TRUE
+in \*(Lqold line by line\*(Rq mode,
+and
+.Dv FALSE
+in \*(Lqcharacter at a time\*(Rq mode.
+When the
+.Dv LINEMODE
+option is enabled, the value of
+.Ic localchars
+is ignored, and assumed to always be
+.Dv TRUE .
+If
+.Dv LINEMODE
+has ever been enabled, then
+.Ic quit
+is sent as
+.Ic abort ,
+and
+.Ic eof
+and
+.Ic suspend
+are sent as
+.Ic eof
+and
+.Ic susp
+(see
+.Ic send
+above).
+.It Ic netdata
+Toggles the display of all network data (in hexadecimal format).
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic options
+Toggles the display of some internal
+.Nm
+protocol processing (having to do with
+.Tn TELNET
+options).
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic prettydump
+When the
+.Ic netdata
+toggle is enabled, if
+.Ic prettydump
+is enabled the output from the
+.Ic netdata
+command will be formatted in a more user readable format.
+Spaces are put between each character in the output, and the
+beginning of any
+.Nm
+escape sequence is preceded by a '*' to aid in locating them.
+.It Ic skiprc
+When the skiprc toggle is
+.Dv TRUE ,
+.Nm
+skips the reading of the
+.Pa \&.telnetrc
+file in the users home
+directory when connections are opened. The initial
+value for this toggle is
+.Dv FALSE .
+.It Ic termdata
+Toggles the display of all terminal data (in hexadecimal format).
+The initial value for this toggle is
+.Dv FALSE .
+.It Ic verbose_encrypt
+When the
+.Ic verbose_encrypt
+toggle is
+.Dv TRUE ,
+.Nm
+prints out a message each time encryption is enabled or
+disabled. The initial value for this toggle is
+.Dv FALSE .
+.It Ic ?\&
+Displays the legal
+.Ic toggle
+commands.
+.El
+.It Ic z
+Suspend
+.Nm .
+This command only works when the user is using the
+.Xr csh 1 .
+.It Ic \&! Op Ar command
+Execute a single command in a subshell on the local
+system. If
+.Ar command
+is omitted, then an interactive
+subshell is invoked.
+.It Ic ?\& Op Ar command
+Get help. With no arguments,
+.Nm
+prints a help summary.
+If
+.Ar command
+is specified,
+.Nm
+will print the help information for just that command.
+.El
+.Sh ENVIRONMENT
+.Nm
+uses at least the
+.Ev HOME ,
+.Ev SHELL ,
+.Ev DISPLAY ,
+and
+.Ev TERM
+environment variables.
+Other environment variables may be propagated
+to the other side via the
+.Dv TELNET ENVIRON
+option.
+.Sh SEE ALSO
+.Xr rlogin 1 ,
+.Xr rsh 1 ,
+.Xr hosts 5 ,
+.Xr nologin 5 ,
+.Xr telnetd 8
+.Sh FILES
+.Bl -tag -width ~/.telnetrc -compact
+.It Pa ~/.telnetrc
+user customized telnet startup values
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+IPv6 support was added by WIDE/KAME project.
+.Sh NOTES
+On some remote systems, echo has to be turned off manually when in
+\*(Lqold line by line\*(Rq mode.
+.Pp
+In \*(Lqold line by line\*(Rq mode or
+.Dv LINEMODE
+the terminal's
+.Ic eof
+character is only recognized (and sent to the remote system)
+when it is the first character on a line.
diff --git a/remote_cmds/telnet.tproj/telnet.c b/remote_cmds/telnet.tproj/telnet.c
new file mode 100644
index 0000000..541cf9b
--- /dev/null
+++ b/remote_cmds/telnet.tproj/telnet.c
@@ -0,0 +1,2418 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/telnet.c,v 1.16 2005/03/28 14:45:12 nectar Exp $");
+
+#include <sys/types.h>
+
+/* By the way, we need to include curses.h before telnet.h since,
+ * among other things, telnet.h #defines 'DO', which is a variable
+ * declared in curses.h.
+ */
+
+#include <ctype.h>
+#include <curses.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <term.h>
+#include <unistd.h>
+#include <arpa/telnet.h>
+
+#include "ring.h"
+
+#include "defines.h"
+#include "externs.h"
+#include "types.h"
+#include "general.h"
+
+#ifdef TERMCAP
+#include <curses.h>
+#include <term.h>
+#endif /* TERMCAP */
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+#include <libtelnet/misc.h>
+
+#define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
+
+static unsigned char subbuffer[SUBBUFSIZE],
+ *subpointer, *subend; /* buffer for sub-options */
+#define SB_CLEAR() subpointer = subbuffer;
+#define SB_TERM() { subend = subpointer; SB_CLEAR(); }
+#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
+ *subpointer++ = (c); \
+ }
+
+#define SB_GET() ((*subpointer++)&0xff)
+#define SB_PEEK() ((*subpointer)&0xff)
+#define SB_EOF() (subpointer >= subend)
+#define SB_LEN() (subend - subpointer)
+
+char options[256]; /* The combined options */
+char do_dont_resp[256];
+char will_wont_resp[256];
+
+int
+ eight = 0,
+ autologin = 0, /* Autologin anyone? */
+ skiprc = 0,
+ connected,
+ showoptions,
+ ISend, /* trying to send network data in */
+ telnet_debug = 0,
+ crmod,
+ netdata, /* Print out network data flow */
+ crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
+ telnetport,
+ SYNCHing, /* we are in TELNET SYNCH mode */
+ flushout, /* flush output */
+ autoflush = 0, /* flush output when interrupting? */
+ autosynch, /* send interrupt characters with SYNCH? */
+ localflow, /* we handle flow control locally */
+ restartany, /* if flow control enabled, restart on any character */
+ localchars, /* we recognize interrupt/quit */
+ donelclchars, /* the user has set "localchars" */
+ donebinarytoggle, /* the user has put us in binary */
+ dontlecho, /* do we suppress local echoing right now? */
+ globalmode,
+ doaddrlookup = 1, /* do a reverse address lookup? */
+ clienteof = 0;
+
+char *prompt = 0;
+#ifdef ENCRYPTION
+char *line; /* hack around breakage in sra.c :-( !! */
+#endif
+
+cc_t escape;
+cc_t rlogin;
+#ifdef KLUDGELINEMODE
+cc_t echoc;
+#endif
+
+/*
+ * Telnet receiver states for fsm
+ */
+#define TS_DATA 0
+#define TS_IAC 1
+#define TS_WILL 2
+#define TS_WONT 3
+#define TS_DO 4
+#define TS_DONT 5
+#define TS_CR 6
+#define TS_SB 7 /* sub-option collection */
+#define TS_SE 8 /* looking for sub-option end */
+
+static int telrcv_state;
+#ifdef OLD_ENVIRON
+unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
+#else
+# define telopt_environ TELOPT_NEW_ENVIRON
+#endif
+
+jmp_buf toplevel;
+jmp_buf peerdied;
+
+int flushline;
+int linemode;
+
+#ifdef KLUDGELINEMODE
+int kludgelinemode = 1;
+#endif
+
+static int is_unique(char *, char **, char **);
+
+/*
+ * The following are some clocks used to decide how to interpret
+ * the relationship between various variables.
+ */
+
+Clocks clocks;
+
+/*
+ * Initialize telnet environment.
+ */
+
+void
+init_telnet(void)
+{
+ env_init();
+
+ SB_CLEAR();
+ ClearArray(options);
+
+ connected = ISend = localflow = donebinarytoggle = 0;
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+ auth_encrypt_connect(connected);
+#endif
+#endif
+ restartany = -1;
+
+ SYNCHing = 0;
+
+ /* Don't change NetTrace */
+
+ escape = CONTROL(']');
+ rlogin = _POSIX_VDISABLE;
+#ifdef KLUDGELINEMODE
+ echoc = CONTROL('E');
+#endif
+
+ flushline = 1;
+ telrcv_state = TS_DATA;
+}
+
+
+/*
+ * These routines are in charge of sending option negotiations
+ * to the other side.
+ *
+ * The basic idea is that we send the negotiation if either side
+ * is in disagreement as to what the current state should be.
+ */
+
+void
+send_do(int c, int init)
+{
+ if (init) {
+ if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
+ my_want_state_is_do(c))
+ return;
+ set_my_want_state_do(c);
+ do_dont_resp[c]++;
+ }
+ if (telnetport < 0)
+ return;
+ NET2ADD(IAC, DO);
+ NETADD(c);
+ printoption("SENT", DO, c);
+}
+
+void
+send_dont(int c, int init)
+{
+ if (init) {
+ if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
+ my_want_state_is_dont(c))
+ return;
+ set_my_want_state_dont(c);
+ do_dont_resp[c]++;
+ }
+ if (telnetport < 0)
+ return;
+ NET2ADD(IAC, DONT);
+ NETADD(c);
+ printoption("SENT", DONT, c);
+}
+
+void
+send_will(int c, int init)
+{
+ if (init) {
+ if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
+ my_want_state_is_will(c))
+ return;
+ set_my_want_state_will(c);
+ will_wont_resp[c]++;
+ }
+ if (telnetport < 0)
+ return;
+ NET2ADD(IAC, WILL);
+ NETADD(c);
+ printoption("SENT", WILL, c);
+}
+
+void
+send_wont(int c, int init)
+{
+ if (init) {
+ if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
+ my_want_state_is_wont(c))
+ return;
+ set_my_want_state_wont(c);
+ will_wont_resp[c]++;
+ }
+ if (telnetport < 0)
+ return;
+ NET2ADD(IAC, WONT);
+ NETADD(c);
+ printoption("SENT", WONT, c);
+}
+
+void
+willoption(int option)
+{
+ int new_state_ok = 0;
+
+ if (do_dont_resp[option]) {
+ --do_dont_resp[option];
+ if (do_dont_resp[option] && my_state_is_do(option))
+ --do_dont_resp[option];
+ }
+
+ if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
+
+ switch (option) {
+
+ case TELOPT_ECHO:
+ case TELOPT_BINARY:
+ case TELOPT_SGA:
+ settimer(modenegotiated);
+ /* FALLTHROUGH */
+ case TELOPT_STATUS:
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+#endif
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+#endif /* ENCRYPTION */
+ new_state_ok = 1;
+ break;
+
+ case TELOPT_TM:
+ if (flushout)
+ flushout = 0;
+ /*
+ * Special case for TM. If we get back a WILL,
+ * pretend we got back a WONT.
+ */
+ set_my_want_state_dont(option);
+ set_my_state_dont(option);
+ return; /* Never reply to TM will's/wont's */
+
+ case TELOPT_LINEMODE:
+ default:
+ break;
+ }
+
+ if (new_state_ok) {
+ set_my_want_state_do(option);
+ send_do(option, 0);
+ setconnmode(0); /* possibly set new tty mode */
+ } else {
+ do_dont_resp[option]++;
+ send_dont(option, 0);
+ }
+ }
+ set_my_state_do(option);
+#ifdef ENCRYPTION
+ if (option == TELOPT_ENCRYPT)
+ encrypt_send_support();
+#endif /* ENCRYPTION */
+}
+
+void
+wontoption(int option)
+{
+ if (do_dont_resp[option]) {
+ --do_dont_resp[option];
+ if (do_dont_resp[option] && my_state_is_dont(option))
+ --do_dont_resp[option];
+ }
+
+ if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
+
+ switch (option) {
+
+#ifdef KLUDGELINEMODE
+ case TELOPT_SGA:
+ if (!kludgelinemode)
+ break;
+ /* FALLTHROUGH */
+#endif
+ case TELOPT_ECHO:
+ settimer(modenegotiated);
+ break;
+
+ case TELOPT_TM:
+ if (flushout)
+ flushout = 0;
+ set_my_want_state_dont(option);
+ set_my_state_dont(option);
+ return; /* Never reply to TM will's/wont's */
+
+ default:
+ break;
+ }
+ set_my_want_state_dont(option);
+ if (my_state_is_do(option))
+ send_dont(option, 0);
+ setconnmode(0); /* Set new tty mode */
+ } else if (option == TELOPT_TM) {
+ /*
+ * Special case for TM.
+ */
+ if (flushout)
+ flushout = 0;
+ set_my_want_state_dont(option);
+ }
+ set_my_state_dont(option);
+}
+
+static void
+dooption(int option)
+{
+ int new_state_ok = 0;
+
+ if (will_wont_resp[option]) {
+ --will_wont_resp[option];
+ if (will_wont_resp[option] && my_state_is_will(option))
+ --will_wont_resp[option];
+ }
+
+ if (will_wont_resp[option] == 0) {
+ if (my_want_state_is_wont(option)) {
+
+ switch (option) {
+
+ case TELOPT_TM:
+ /*
+ * Special case for TM. We send a WILL, but pretend
+ * we sent WONT.
+ */
+ send_will(option, 0);
+ set_my_want_state_wont(TELOPT_TM);
+ set_my_state_wont(TELOPT_TM);
+ return;
+
+ case TELOPT_BINARY: /* binary mode */
+ case TELOPT_NAWS: /* window size */
+ case TELOPT_TSPEED: /* terminal speed */
+ case TELOPT_LFLOW: /* local flow control */
+ case TELOPT_TTYPE: /* terminal type option */
+ case TELOPT_SGA: /* no big deal */
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT: /* encryption variable option */
+#endif /* ENCRYPTION */
+ new_state_ok = 1;
+ break;
+
+ case TELOPT_NEW_ENVIRON: /* New environment variable option */
+#ifdef OLD_ENVIRON
+ if (my_state_is_will(TELOPT_OLD_ENVIRON))
+ send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
+ goto env_common;
+ case TELOPT_OLD_ENVIRON: /* Old environment variable option */
+ if (my_state_is_will(TELOPT_NEW_ENVIRON))
+ break; /* Don't enable if new one is in use! */
+ env_common:
+ telopt_environ = option;
+#endif
+ new_state_ok = 1;
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ if (autologin)
+ new_state_ok = 1;
+ break;
+#endif
+
+ case TELOPT_XDISPLOC: /* X Display location */
+ if (env_getvalue((const unsigned char *)"DISPLAY"))
+ new_state_ok = 1;
+ break;
+
+ case TELOPT_LINEMODE:
+#ifdef KLUDGELINEMODE
+ kludgelinemode = 0;
+ send_do(TELOPT_SGA, 1);
+#endif
+ set_my_want_state_will(TELOPT_LINEMODE);
+ send_will(option, 0);
+ set_my_state_will(TELOPT_LINEMODE);
+ slc_init();
+ return;
+
+ case TELOPT_ECHO: /* We're never going to echo... */
+ default:
+ break;
+ }
+
+ if (new_state_ok) {
+ set_my_want_state_will(option);
+ send_will(option, 0);
+ setconnmode(0); /* Set new tty mode */
+ } else {
+ will_wont_resp[option]++;
+ send_wont(option, 0);
+ }
+ } else {
+ /*
+ * Handle options that need more things done after the
+ * other side has acknowledged the option.
+ */
+ switch (option) {
+ case TELOPT_LINEMODE:
+#ifdef KLUDGELINEMODE
+ kludgelinemode = 0;
+ send_do(TELOPT_SGA, 1);
+#endif
+ set_my_state_will(option);
+ slc_init();
+ send_do(TELOPT_SGA, 0);
+ return;
+ }
+ }
+ }
+ set_my_state_will(option);
+}
+
+static void
+dontoption(int option)
+{
+
+ if (will_wont_resp[option]) {
+ --will_wont_resp[option];
+ if (will_wont_resp[option] && my_state_is_wont(option))
+ --will_wont_resp[option];
+ }
+
+ if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
+ switch (option) {
+ case TELOPT_LINEMODE:
+ linemode = 0; /* put us back to the default state */
+ break;
+#ifdef OLD_ENVIRON
+ case TELOPT_NEW_ENVIRON:
+ /*
+ * The new environ option wasn't recognized, try
+ * the old one.
+ */
+ send_will(TELOPT_OLD_ENVIRON, 1);
+ telopt_environ = TELOPT_OLD_ENVIRON;
+ break;
+#endif
+ }
+ /* we always accept a DONT */
+ set_my_want_state_wont(option);
+ if (my_state_is_will(option))
+ send_wont(option, 0);
+ setconnmode(0); /* Set new tty mode */
+ }
+ set_my_state_wont(option);
+}
+
+/*
+ * Given a buffer returned by tgetent(), this routine will turn
+ * the pipe separated list of names in the buffer into an array
+ * of pointers to null terminated names. We toss out any bad,
+ * duplicate, or verbose names (names with spaces).
+ */
+
+static const char *name_unknown = "UNKNOWN";
+static const char *unknown[] = { NULL, NULL };
+
+static const char **
+mklist(char *buf, char *name)
+{
+ int n;
+ char c, *cp, **argvp, *cp2, **argv, **avt;
+
+ if (name) {
+ if (strlen(name) > 40) {
+ name = 0;
+ unknown[0] = name_unknown;
+ } else {
+ unknown[0] = name;
+ upcase(name);
+ }
+ } else
+ unknown[0] = name_unknown;
+ /*
+ * Count up the number of names.
+ */
+ for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
+ if (*cp == '|')
+ n++;
+ }
+ /*
+ * Allocate an array to put the name pointers into
+ */
+ argv = (char **)malloc((n+3)*sizeof(char *));
+ if (argv == 0)
+ return(unknown);
+
+ /*
+ * Fill up the array of pointers to names.
+ */
+ *argv = 0;
+ argvp = argv+1;
+ n = 0;
+ for (cp = cp2 = buf; (c = *cp); cp++) {
+ if (c == '|' || c == ':') {
+ *cp++ = '\0';
+ /*
+ * Skip entries that have spaces or are over 40
+ * characters long. If this is our environment
+ * name, then put it up front. Otherwise, as
+ * long as this is not a duplicate name (case
+ * insensitive) add it to the list.
+ */
+ if (n || (cp - cp2 > 41))
+ ;
+ else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
+ *argv = cp2;
+ else if (is_unique(cp2, argv+1, argvp))
+ *argvp++ = cp2;
+ if (c == ':')
+ break;
+ /*
+ * Skip multiple delimiters. Reset cp2 to
+ * the beginning of the next name. Reset n,
+ * the flag for names with spaces.
+ */
+ while ((c = *cp) == '|')
+ cp++;
+ cp2 = cp;
+ n = 0;
+ }
+ /*
+ * Skip entries with spaces or non-ascii values.
+ * Convert lower case letters to upper case.
+ */
+ if ((c == ' ') || !isascii(c))
+ n = 1;
+ else if (islower(c))
+ *cp = toupper(c);
+ }
+
+ /*
+ * Check for an old V6 2 character name. If the second
+ * name points to the beginning of the buffer, and is
+ * only 2 characters long, move it to the end of the array.
+ */
+ if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
+ --argvp;
+ for (avt = &argv[1]; avt < argvp; avt++)
+ *avt = *(avt+1);
+ *argvp++ = buf;
+ }
+
+ /*
+ * Duplicate last name, for TTYPE option, and null
+ * terminate the array. If we didn't find a match on
+ * our terminal name, put that name at the beginning.
+ */
+ cp = *(argvp-1);
+ *argvp++ = cp;
+ *argvp = 0;
+
+ if (*argv == 0) {
+ if (name)
+ *argv = name;
+ else {
+ --argvp;
+ for (avt = argv; avt < argvp; avt++)
+ *avt = *(avt+1);
+ }
+ }
+ if (*argv)
+ return((const char **)argv);
+ else
+ return(unknown);
+}
+
+static int
+is_unique(char *name, char **as, char **ae)
+{
+ char **ap;
+ int n;
+
+ n = strlen(name) + 1;
+ for (ap = as; ap < ae; ap++)
+ if (strncasecmp(*ap, name, n) == 0)
+ return(0);
+ return (1);
+}
+
+#ifdef TERMCAP
+char termbuf[1024];
+
+/*ARGSUSED*/
+#ifdef __APPLE__
+__private_extern__ int
+#else
+static int
+#endif
+setupterm(char *tname, int fd, int *errp)
+{
+ if (tgetent(termbuf, tname) == 1) {
+ termbuf[1023] = '\0';
+ if (errp)
+ *errp = 1;
+ return(0);
+ }
+ if (errp)
+ *errp = 0;
+ return(-1);
+}
+#else
+#define termbuf ttytype
+extern char ttytype[];
+#endif
+
+int resettermname = 1;
+
+static const char *
+gettermname(void)
+{
+ char *tname;
+ static const char **tnamep = 0;
+ static const char **next;
+ int err;
+
+ if (resettermname) {
+ resettermname = 0;
+ if (tnamep && tnamep != unknown)
+ free(tnamep);
+ if ((tname = (char *)env_getvalue((const unsigned char *)"TERM")) &&
+ (setupterm(tname, 1, &err) == 0)) {
+ tnamep = mklist(termbuf, tname);
+ } else {
+ if (tname && (strlen(tname) <= 40)) {
+ unknown[0] = tname;
+ upcase(tname);
+ } else
+ unknown[0] = name_unknown;
+ tnamep = unknown;
+ }
+ next = tnamep;
+ }
+ if (*next == 0)
+ next = tnamep;
+ return(*next++);
+}
+/*
+ * suboption()
+ *
+ * Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ *
+ * Currently we recognize:
+ *
+ * Terminal type, send request.
+ * Terminal speed (send request).
+ * Local flow control (is request).
+ * Linemode
+ */
+
+static void
+suboption(void)
+{
+ unsigned char subchar;
+
+ printsub('<', subbuffer, SB_LEN()+2);
+ switch (subchar = SB_GET()) {
+ case TELOPT_TTYPE:
+ if (my_want_state_is_wont(TELOPT_TTYPE))
+ return;
+ if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
+ return;
+ } else {
+ const char *name;
+ unsigned char temp[50];
+ int len;
+
+ name = gettermname();
+ len = strlen(name) + 4 + 2;
+ if (len < NETROOM()) {
+ sprintf((char *)temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+ TELQUAL_IS, name, IAC, SE);
+ ring_supply_data(&netoring, temp, len);
+ printsub('>', &temp[2], len-2);
+ } else {
+ ExitString("No room in buffer for terminal type.\n", 1);
+ /*NOTREACHED*/
+ }
+ }
+ break;
+ case TELOPT_TSPEED:
+ if (my_want_state_is_wont(TELOPT_TSPEED))
+ return;
+ if (SB_EOF())
+ return;
+ if (SB_GET() == TELQUAL_SEND) {
+ long ospeed, ispeed;
+ unsigned char temp[50];
+ int len;
+
+ TerminalSpeeds(&ispeed, &ospeed);
+
+ sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
+ TELQUAL_IS, ospeed, ispeed, IAC, SE);
+ len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
+
+ if (len < NETROOM()) {
+ ring_supply_data(&netoring, temp, len);
+ printsub('>', temp+2, len - 2);
+ }
+/*@*/ else printf("lm_will: not enough room in buffer\n");
+ }
+ break;
+ case TELOPT_LFLOW:
+ if (my_want_state_is_wont(TELOPT_LFLOW))
+ return;
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case LFLOW_RESTART_ANY:
+ restartany = 1;
+ break;
+ case LFLOW_RESTART_XON:
+ restartany = 0;
+ break;
+ case LFLOW_ON:
+ localflow = 1;
+ break;
+ case LFLOW_OFF:
+ localflow = 0;
+ break;
+ default:
+ return;
+ }
+ setcommandmode();
+ setconnmode(0);
+ break;
+
+ case TELOPT_LINEMODE:
+ if (my_want_state_is_wont(TELOPT_LINEMODE))
+ return;
+ if (SB_EOF())
+ return;
+ switch (SB_GET()) {
+ case WILL:
+ lm_will(subpointer, SB_LEN());
+ break;
+ case WONT:
+ lm_wont(subpointer, SB_LEN());
+ break;
+ case DO:
+ lm_do(subpointer, SB_LEN());
+ break;
+ case DONT:
+ lm_dont(subpointer, SB_LEN());
+ break;
+ case LM_SLC:
+ slc(subpointer, SB_LEN());
+ break;
+ case LM_MODE:
+ lm_mode(subpointer, SB_LEN(), 0);
+ break;
+ default:
+ break;
+ }
+ break;
+
+#ifdef OLD_ENVIRON
+ case TELOPT_OLD_ENVIRON:
+#endif
+ case TELOPT_NEW_ENVIRON:
+ if (SB_EOF())
+ return;
+ switch(SB_PEEK()) {
+ case TELQUAL_IS:
+ case TELQUAL_INFO:
+ if (my_want_state_is_dont(subchar))
+ return;
+ break;
+ case TELQUAL_SEND:
+ if (my_want_state_is_wont(subchar)) {
+ return;
+ }
+ break;
+ default:
+ return;
+ }
+ env_opt(subpointer, SB_LEN());
+ break;
+
+ case TELOPT_XDISPLOC:
+ if (my_want_state_is_wont(TELOPT_XDISPLOC))
+ return;
+ if (SB_EOF())
+ return;
+ if (SB_GET() == TELQUAL_SEND) {
+ unsigned char temp[50], *dp;
+ int len;
+
+ if ((dp = env_getvalue((const unsigned char *)"DISPLAY")) == NULL ||
+ strlen((const char *)dp) > sizeof(temp) - 7) {
+ /*
+ * Something happened, we no longer have a DISPLAY
+ * variable. Or it is too long. So, turn off the option.
+ */
+ send_wont(TELOPT_XDISPLOC, 1);
+ break;
+ }
+ snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB,
+ TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
+ len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
+
+ if (len < NETROOM()) {
+ ring_supply_data(&netoring, temp, len);
+ printsub('>', temp+2, len - 2);
+ }
+/*@*/ else printf("lm_will: not enough room in buffer\n");
+ }
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION: {
+ if (!autologin)
+ break;
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case TELQUAL_IS:
+ if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
+ return;
+ auth_is(subpointer, SB_LEN());
+ break;
+ case TELQUAL_SEND:
+ if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+ return;
+ auth_send(subpointer, SB_LEN());
+ break;
+ case TELQUAL_REPLY:
+ if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
+ return;
+ auth_reply(subpointer, SB_LEN());
+ break;
+ case TELQUAL_NAME:
+ if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
+ return;
+ auth_name(subpointer, SB_LEN());
+ break;
+ }
+ }
+ break;
+#endif
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ if (SB_EOF())
+ return;
+ switch(SB_GET()) {
+ case ENCRYPT_START:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_END:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_end();
+ break;
+ case ENCRYPT_SUPPORT:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_support(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REQSTART:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_request_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REQEND:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ /*
+ * We can always send an REQEND so that we cannot
+ * get stuck encrypting. We should only get this
+ * if we have been able to get in the correct mode
+ * anyhow.
+ */
+ encrypt_request_end();
+ break;
+ case ENCRYPT_IS:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_is(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REPLY:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_reply(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_ENC_KEYID:
+ if (my_want_state_is_dont(TELOPT_ENCRYPT))
+ return;
+ encrypt_enc_keyid(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_DEC_KEYID:
+ if (my_want_state_is_wont(TELOPT_ENCRYPT))
+ return;
+ encrypt_dec_keyid(subpointer, SB_LEN());
+ break;
+ default:
+ break;
+ }
+ break;
+#endif /* ENCRYPTION */
+ default:
+ break;
+ }
+}
+
+static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
+
+void
+lm_will(unsigned char *cmd, int len)
+{
+ if (len < 1) {
+/*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
+ return;
+ }
+ switch(cmd[0]) {
+ case LM_FORWARDMASK: /* We shouldn't ever get this... */
+ default:
+ str_lm[3] = DONT;
+ str_lm[4] = cmd[0];
+ if (NETROOM() > (int)sizeof(str_lm)) {
+ ring_supply_data(&netoring, str_lm, sizeof(str_lm));
+ printsub('>', &str_lm[2], sizeof(str_lm)-2);
+ }
+/*@*/ else printf("lm_will: not enough room in buffer\n");
+ break;
+ }
+}
+
+void
+lm_wont(unsigned char *cmd, int len)
+{
+ if (len < 1) {
+/*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
+ return;
+ }
+ switch(cmd[0]) {
+ case LM_FORWARDMASK: /* We shouldn't ever get this... */
+ default:
+ /* We are always DONT, so don't respond */
+ return;
+ }
+}
+
+void
+lm_do(unsigned char *cmd, int len)
+{
+ if (len < 1) {
+/*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
+ return;
+ }
+ switch(cmd[0]) {
+ case LM_FORWARDMASK:
+ default:
+ str_lm[3] = WONT;
+ str_lm[4] = cmd[0];
+ if (NETROOM() > (int)sizeof(str_lm)) {
+ ring_supply_data(&netoring, str_lm, sizeof(str_lm));
+ printsub('>', &str_lm[2], sizeof(str_lm)-2);
+ }
+/*@*/ else printf("lm_do: not enough room in buffer\n");
+ break;
+ }
+}
+
+void
+lm_dont(unsigned char *cmd, int len)
+{
+ if (len < 1) {
+/*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
+ return;
+ }
+ switch(cmd[0]) {
+ case LM_FORWARDMASK:
+ default:
+ /* we are always WONT, so don't respond */
+ break;
+ }
+}
+
+static unsigned char str_lm_mode[] = {
+ IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
+};
+
+void
+lm_mode(unsigned char *cmd, int len, int init)
+{
+ if (len != 1)
+ return;
+ if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
+ return;
+ if (*cmd&MODE_ACK)
+ return;
+ linemode = *cmd&(MODE_MASK&~MODE_ACK);
+ str_lm_mode[4] = linemode;
+ if (!init)
+ str_lm_mode[4] |= MODE_ACK;
+ if (NETROOM() > (int)sizeof(str_lm_mode)) {
+ ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
+ printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
+ }
+/*@*/ else printf("lm_mode: not enough room in buffer\n");
+ setconnmode(0); /* set changed mode */
+}
+
+
+
+/*
+ * slc()
+ * Handle special character suboption of LINEMODE.
+ */
+
+struct spc {
+ cc_t val;
+ cc_t *valp;
+ char flags; /* Current flags & level */
+ char mylevel; /* Maximum level & flags */
+} spc_data[NSLC+1];
+
+#define SLC_IMPORT 0
+#define SLC_EXPORT 1
+#define SLC_RVALUE 2
+static int slc_mode = SLC_EXPORT;
+
+void
+slc_init(void)
+{
+ struct spc *spcp;
+
+ localchars = 1;
+ for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
+ spcp->val = 0;
+ spcp->valp = 0;
+ spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
+ }
+
+#define initfunc(func, flags) { \
+ spcp = &spc_data[func]; \
+ if ((spcp->valp = tcval(func))) { \
+ spcp->val = *spcp->valp; \
+ spcp->mylevel = SLC_VARIABLE|flags; \
+ } else { \
+ spcp->val = 0; \
+ spcp->mylevel = SLC_DEFAULT; \
+ } \
+ }
+
+ initfunc(SLC_SYNCH, 0);
+ /* No BRK */
+ initfunc(SLC_AO, 0);
+ initfunc(SLC_AYT, 0);
+ /* No EOR */
+ initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
+ initfunc(SLC_EOF, 0);
+#ifndef SYSV_TERMIO
+ initfunc(SLC_SUSP, SLC_FLUSHIN);
+#endif
+ initfunc(SLC_EC, 0);
+ initfunc(SLC_EL, 0);
+#ifndef SYSV_TERMIO
+ initfunc(SLC_EW, 0);
+ initfunc(SLC_RP, 0);
+ initfunc(SLC_LNEXT, 0);
+#endif
+ initfunc(SLC_XON, 0);
+ initfunc(SLC_XOFF, 0);
+#ifdef SYSV_TERMIO
+ spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
+ spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
+#endif
+ initfunc(SLC_FORW1, 0);
+#ifdef USE_TERMIO
+ initfunc(SLC_FORW2, 0);
+ /* No FORW2 */
+#endif
+
+ initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
+#undef initfunc
+
+ if (slc_mode == SLC_EXPORT)
+ slc_export();
+ else
+ slc_import(1);
+
+}
+
+void
+slcstate(void)
+{
+ printf("Special characters are %s values\n",
+ slc_mode == SLC_IMPORT ? "remote default" :
+ slc_mode == SLC_EXPORT ? "local" :
+ "remote");
+}
+
+void
+slc_mode_export(void)
+{
+ slc_mode = SLC_EXPORT;
+ if (my_state_is_will(TELOPT_LINEMODE))
+ slc_export();
+}
+
+void
+slc_mode_import(int def)
+{
+ slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
+ if (my_state_is_will(TELOPT_LINEMODE))
+ slc_import(def);
+}
+
+unsigned char slc_import_val[] = {
+ IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
+};
+unsigned char slc_import_def[] = {
+ IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
+};
+
+void
+slc_import(int def)
+{
+ if (NETROOM() > (int)sizeof(slc_import_val)) {
+ if (def) {
+ ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
+ printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
+ } else {
+ ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
+ printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
+ }
+ }
+/*@*/ else printf("slc_import: not enough room\n");
+}
+
+void
+slc_export(void)
+{
+ struct spc *spcp;
+
+ TerminalDefaultChars();
+
+ slc_start_reply();
+ for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+ if (spcp->mylevel != SLC_NOSUPPORT) {
+ if (spcp->val == (cc_t)(_POSIX_VDISABLE))
+ spcp->flags = SLC_NOSUPPORT;
+ else
+ spcp->flags = spcp->mylevel;
+ if (spcp->valp)
+ spcp->val = *spcp->valp;
+ slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
+ }
+ }
+ slc_end_reply();
+ (void)slc_update();
+ setconnmode(1); /* Make sure the character values are set */
+}
+
+void
+slc(unsigned char *cp, int len)
+{
+ struct spc *spcp;
+ int func,level;
+
+ slc_start_reply();
+
+ for (; len >= 3; len -=3, cp +=3) {
+
+ func = cp[SLC_FUNC];
+
+ if (func == 0) {
+ /*
+ * Client side: always ignore 0 function.
+ */
+ continue;
+ }
+ if (func > NSLC) {
+ if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
+ slc_add_reply(func, SLC_NOSUPPORT, 0);
+ continue;
+ }
+
+ spcp = &spc_data[func];
+
+ level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
+
+ if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
+ ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
+ continue;
+ }
+
+ if (level == (SLC_DEFAULT|SLC_ACK)) {
+ /*
+ * This is an error condition, the SLC_ACK
+ * bit should never be set for the SLC_DEFAULT
+ * level. Our best guess to recover is to
+ * ignore the SLC_ACK bit.
+ */
+ cp[SLC_FLAGS] &= ~SLC_ACK;
+ }
+
+ if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
+ spcp->val = (cc_t)cp[SLC_VALUE];
+ spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
+ continue;
+ }
+
+ level &= ~SLC_ACK;
+
+ if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
+ spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
+ spcp->val = (cc_t)cp[SLC_VALUE];
+ }
+ if (level == SLC_DEFAULT) {
+ if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
+ spcp->flags = spcp->mylevel;
+ else
+ spcp->flags = SLC_NOSUPPORT;
+ }
+ slc_add_reply(func, spcp->flags, spcp->val);
+ }
+ slc_end_reply();
+ if (slc_update())
+ setconnmode(1); /* set the new character values */
+}
+
+void
+slc_check(void)
+{
+ struct spc *spcp;
+
+ slc_start_reply();
+ for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+ if (spcp->valp && spcp->val != *spcp->valp) {
+ spcp->val = *spcp->valp;
+ if (spcp->val == (cc_t)(_POSIX_VDISABLE))
+ spcp->flags = SLC_NOSUPPORT;
+ else
+ spcp->flags = spcp->mylevel;
+ slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
+ }
+ }
+ slc_end_reply();
+ setconnmode(1);
+}
+
+unsigned char slc_reply[128];
+unsigned char const * const slc_reply_eom = &slc_reply[sizeof(slc_reply)];
+unsigned char *slc_replyp;
+
+void
+slc_start_reply(void)
+{
+ slc_replyp = slc_reply;
+ *slc_replyp++ = IAC;
+ *slc_replyp++ = SB;
+ *slc_replyp++ = TELOPT_LINEMODE;
+ *slc_replyp++ = LM_SLC;
+}
+
+void
+slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
+{
+ /* A sequence of up to 6 bytes my be written for this member of the SLC
+ * suboption list by this function. The end of negotiation command,
+ * which is written by slc_end_reply(), will require 2 additional
+ * bytes. Do not proceed unless there is sufficient space for these
+ * items.
+ */
+ if (&slc_replyp[6+2] > slc_reply_eom)
+ return;
+ if ((*slc_replyp++ = func) == IAC)
+ *slc_replyp++ = IAC;
+ if ((*slc_replyp++ = flags) == IAC)
+ *slc_replyp++ = IAC;
+ if ((*slc_replyp++ = (unsigned char)value) == IAC)
+ *slc_replyp++ = IAC;
+}
+
+void
+slc_end_reply(void)
+{
+ int len;
+
+ /* The end of negotiation command requires 2 bytes. */
+ if (&slc_replyp[2] > slc_reply_eom)
+ return;
+ *slc_replyp++ = IAC;
+ *slc_replyp++ = SE;
+ len = slc_replyp - slc_reply;
+ if (len <= 6)
+ return;
+ if (NETROOM() > len) {
+ ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
+ printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
+ }
+/*@*/else printf("slc_end_reply: not enough room\n");
+}
+
+int
+slc_update(void)
+{
+ struct spc *spcp;
+ int need_update = 0;
+
+ for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
+ if (!(spcp->flags&SLC_ACK))
+ continue;
+ spcp->flags &= ~SLC_ACK;
+ if (spcp->valp && (*spcp->valp != spcp->val)) {
+ *spcp->valp = spcp->val;
+ need_update = 1;
+ }
+ }
+ return(need_update);
+}
+
+#ifdef OLD_ENVIRON
+# ifdef ENV_HACK
+/*
+ * Earlier version of telnet/telnetd from the BSD code had
+ * the definitions of VALUE and VAR reversed. To ensure
+ * maximum interoperability, we assume that the server is
+ * an older BSD server, until proven otherwise. The newer
+ * BSD servers should be able to handle either definition,
+ * so it is better to use the wrong values if we don't
+ * know what type of server it is.
+ */
+int env_auto = 1;
+int old_env_var = OLD_ENV_VAR;
+int old_env_value = OLD_ENV_VALUE;
+# else
+# define old_env_var OLD_ENV_VAR
+# define old_env_value OLD_ENV_VALUE
+# endif
+#endif
+
+void
+env_opt(unsigned char *buf, int len)
+{
+ unsigned char *ep = 0, *epc = 0;
+ int i;
+
+ switch(buf[0]&0xff) {
+ case TELQUAL_SEND:
+ env_opt_start();
+ if (len == 1) {
+ env_opt_add(NULL);
+ } else for (i = 1; i < len; i++) {
+ switch (buf[i]&0xff) {
+#ifdef OLD_ENVIRON
+ case OLD_ENV_VAR:
+# ifdef ENV_HACK
+ if (telopt_environ == TELOPT_OLD_ENVIRON
+ && env_auto) {
+ /* Server has the same definitions */
+ old_env_var = OLD_ENV_VAR;
+ old_env_value = OLD_ENV_VALUE;
+ }
+ /* FALLTHROUGH */
+# endif
+ case OLD_ENV_VALUE:
+ /*
+ * Although OLD_ENV_VALUE is not legal, we will
+ * still recognize it, just in case it is an
+ * old server that has VAR & VALUE mixed up...
+ */
+ /* FALLTHROUGH */
+#else
+ case NEW_ENV_VAR:
+#endif
+ case ENV_USERVAR:
+ if (ep) {
+ *epc = 0;
+ env_opt_add(ep);
+ }
+ ep = epc = &buf[i+1];
+ break;
+ case ENV_ESC:
+ i++;
+ /*FALLTHROUGH*/
+ default:
+ if (epc)
+ *epc++ = buf[i];
+ break;
+ }
+ }
+ if (ep) {
+ *epc = 0;
+ env_opt_add(ep);
+ }
+ env_opt_end(1);
+ break;
+
+ case TELQUAL_IS:
+ case TELQUAL_INFO:
+ /* Ignore for now. We shouldn't get it anyway. */
+ break;
+
+ default:
+ break;
+ }
+}
+
+#define OPT_REPLY_SIZE (2 * SUBBUFSIZE)
+unsigned char *opt_reply = NULL;
+unsigned char *opt_replyp;
+unsigned char *opt_replyend;
+
+void
+env_opt_start(void)
+{
+ if (opt_reply)
+ opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
+ else
+ opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
+ if (opt_reply == NULL) {
+/*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ return;
+ }
+ opt_replyp = opt_reply;
+ opt_replyend = opt_reply + OPT_REPLY_SIZE;
+ *opt_replyp++ = IAC;
+ *opt_replyp++ = SB;
+ *opt_replyp++ = telopt_environ;
+ *opt_replyp++ = TELQUAL_IS;
+}
+
+void
+env_opt_start_info(void)
+{
+ env_opt_start();
+ if (opt_replyp)
+ opt_replyp[-1] = TELQUAL_INFO;
+}
+
+void
+env_opt_add(unsigned char *ep)
+{
+ unsigned char *vp, c;
+
+ if (opt_reply == NULL) /*XXX*/
+ return; /*XXX*/
+
+ if (ep == NULL || *ep == '\0') {
+ /* Send user defined variables first. */
+ env_default(1, 0);
+ while ((ep = env_default(0, 0)))
+ env_opt_add(ep);
+
+ /* Now add the list of well know variables. */
+ env_default(1, 1);
+ while ((ep = env_default(0, 1)))
+ env_opt_add(ep);
+ return;
+ }
+ vp = env_getvalue(ep);
+ if (opt_replyp + (vp ? 2 * strlen((char *)vp) : 0) +
+ 2 * strlen((char *)ep) + 6 > opt_replyend)
+ {
+ int len;
+#ifdef __APPLE__
+ // rdar://problem/4022837
+ opt_replyend += OPT_REPLY_SIZE + 2*strlen((char *)ep) + 2*(vp ? strlen((char *)vp) : 0);
+#else
+ opt_replyend += OPT_REPLY_SIZE;
+#endif
+ len = opt_replyend - opt_reply;
+ opt_reply = (unsigned char *)realloc(opt_reply, len);
+ if (opt_reply == NULL) {
+/*@*/ printf("env_opt_add: realloc() failed!!!\n");
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ return;
+ }
+ opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
+ opt_replyend = opt_reply + len;
+ }
+ if (opt_welldefined((const char *)ep))
+#ifdef OLD_ENVIRON
+ if (telopt_environ == TELOPT_OLD_ENVIRON)
+ *opt_replyp++ = old_env_var;
+ else
+#endif
+ *opt_replyp++ = NEW_ENV_VAR;
+ else
+ *opt_replyp++ = ENV_USERVAR;
+ for (;;) {
+ while ((c = *ep++)) {
+ if (opt_replyp + (2 + 2) > opt_replyend)
+ return;
+ switch(c&0xff) {
+ case IAC:
+ *opt_replyp++ = IAC;
+ break;
+ case NEW_ENV_VAR:
+ case NEW_ENV_VALUE:
+ case ENV_ESC:
+ case ENV_USERVAR:
+ *opt_replyp++ = ENV_ESC;
+ break;
+ }
+ *opt_replyp++ = c;
+ }
+ if ((ep = vp)) {
+ if (opt_replyp + (1 + 2 + 2) > opt_replyend)
+ return;
+#ifdef OLD_ENVIRON
+ if (telopt_environ == TELOPT_OLD_ENVIRON)
+ *opt_replyp++ = old_env_value;
+ else
+#endif
+ *opt_replyp++ = NEW_ENV_VALUE;
+ vp = NULL;
+ } else
+ break;
+ }
+}
+
+int
+opt_welldefined(const char *ep)
+{
+ if ((strcmp(ep, "USER") == 0) ||
+ (strcmp(ep, "DISPLAY") == 0) ||
+ (strcmp(ep, "PRINTER") == 0) ||
+ (strcmp(ep, "SYSTEMTYPE") == 0) ||
+ (strcmp(ep, "JOB") == 0) ||
+ (strcmp(ep, "ACCT") == 0))
+ return(1);
+ return(0);
+}
+
+void
+env_opt_end(int emptyok)
+{
+ int len;
+
+ if (opt_replyp + 2 > opt_replyend)
+ return;
+ len = opt_replyp + 2 - opt_reply;
+ if (emptyok || len > 6) {
+ *opt_replyp++ = IAC;
+ *opt_replyp++ = SE;
+ if (NETROOM() > len) {
+ ring_supply_data(&netoring, opt_reply, len);
+ printsub('>', &opt_reply[2], len - 2);
+ }
+/*@*/ else printf("slc_end_reply: not enough room\n");
+ }
+ if (opt_reply) {
+ free(opt_reply);
+ opt_reply = opt_replyp = opt_replyend = NULL;
+ }
+}
+
+
+
+int
+telrcv(void)
+{
+ int c;
+ int scc;
+ unsigned char *sbp = NULL;
+ int count;
+ int returnValue = 0;
+
+ scc = 0;
+ count = 0;
+ while (TTYROOM() > 2) {
+ if (scc == 0) {
+ if (count) {
+ ring_consumed(&netiring, count);
+ returnValue = 1;
+ count = 0;
+ }
+ sbp = netiring.consume;
+ scc = ring_full_consecutive(&netiring);
+ if (scc == 0) {
+ /* No more data coming in */
+ break;
+ }
+ }
+
+ c = *sbp++ & 0xff, scc--; count++;
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif /* ENCRYPTION */
+
+ switch (telrcv_state) {
+
+ case TS_CR:
+ telrcv_state = TS_DATA;
+ if (c == '\0') {
+ break; /* Ignore \0 after CR */
+ }
+ else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
+ TTYADD(c);
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case TS_DATA:
+ if (c == IAC && telnetport >= 0) {
+ telrcv_state = TS_IAC;
+ break;
+ }
+ /*
+ * The 'crmod' hack (see following) is needed
+ * since we can't * set CRMOD on output only.
+ * Machines like MULTICS like to send \r without
+ * \n; since we must turn off CRMOD to get proper
+ * input, the mapping is done here (sigh).
+ */
+ if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
+ if (scc > 0) {
+ c = *sbp&0xff;
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif /* ENCRYPTION */
+ if (c == 0) {
+ sbp++, scc--; count++;
+ /* a "true" CR */
+ TTYADD('\r');
+ } else if (my_want_state_is_dont(TELOPT_ECHO) &&
+ (c == '\n')) {
+ sbp++, scc--; count++;
+ TTYADD('\n');
+ } else {
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ (*decrypt_input)(-1);
+#endif /* ENCRYPTION */
+
+ TTYADD('\r');
+ if (crmod) {
+ TTYADD('\n');
+ }
+ }
+ } else {
+ telrcv_state = TS_CR;
+ TTYADD('\r');
+ if (crmod) {
+ TTYADD('\n');
+ }
+ }
+ } else {
+ TTYADD(c);
+ }
+ continue;
+
+ case TS_IAC:
+process_iac:
+ switch (c) {
+
+ case WILL:
+ telrcv_state = TS_WILL;
+ continue;
+
+ case WONT:
+ telrcv_state = TS_WONT;
+ continue;
+
+ case DO:
+ telrcv_state = TS_DO;
+ continue;
+
+ case DONT:
+ telrcv_state = TS_DONT;
+ continue;
+
+ case DM:
+ /*
+ * We may have missed an urgent notification,
+ * so make sure we flush whatever is in the
+ * buffer currently.
+ */
+ printoption("RCVD", IAC, DM);
+ SYNCHing = 1;
+ (void) ttyflush(1);
+ SYNCHing = stilloob();
+ settimer(gotDM);
+ break;
+
+ case SB:
+ SB_CLEAR();
+ telrcv_state = TS_SB;
+ continue;
+
+ case IAC:
+ TTYADD(IAC);
+ break;
+
+ case NOP:
+ case GA:
+ default:
+ printoption("RCVD", IAC, c);
+ break;
+ }
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_WILL:
+ printoption("RCVD", WILL, c);
+ willoption(c);
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_WONT:
+ printoption("RCVD", WONT, c);
+ wontoption(c);
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_DO:
+ printoption("RCVD", DO, c);
+ dooption(c);
+ if (c == TELOPT_NAWS) {
+ sendnaws();
+ } else if (c == TELOPT_LFLOW) {
+ localflow = 1;
+ setcommandmode();
+ setconnmode(0);
+ }
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_DONT:
+ printoption("RCVD", DONT, c);
+ dontoption(c);
+ flushline = 1;
+ setconnmode(0); /* set new tty mode (maybe) */
+ telrcv_state = TS_DATA;
+ continue;
+
+ case TS_SB:
+ if (c == IAC) {
+ telrcv_state = TS_SE;
+ } else {
+ SB_ACCUM(c);
+ }
+ continue;
+
+ case TS_SE:
+ if (c != SE) {
+ if (c != IAC) {
+ /*
+ * This is an error. We only expect to get
+ * "IAC IAC" or "IAC SE". Several things may
+ * have happend. An IAC was not doubled, the
+ * IAC SE was left off, or another option got
+ * inserted into the suboption are all possibilities.
+ * If we assume that the IAC was not doubled,
+ * and really the IAC SE was left off, we could
+ * get into an infinate loop here. So, instead,
+ * we terminate the suboption, and process the
+ * partial suboption if we can.
+ */
+ SB_ACCUM(IAC);
+ SB_ACCUM(c);
+ subpointer -= 2;
+ SB_TERM();
+
+ printoption("In SUBOPTION processing, RCVD", IAC, c);
+ suboption(); /* handle sub-option */
+ telrcv_state = TS_IAC;
+ goto process_iac;
+ }
+ SB_ACCUM(c);
+ telrcv_state = TS_SB;
+ } else {
+ SB_ACCUM(IAC);
+ SB_ACCUM(SE);
+ subpointer -= 2;
+ SB_TERM();
+ suboption(); /* handle sub-option */
+ telrcv_state = TS_DATA;
+ }
+ }
+ }
+ if (count)
+ ring_consumed(&netiring, count);
+ return returnValue||count;
+}
+
+static int bol = 1, local = 0;
+
+int
+rlogin_susp(void)
+{
+ if (local) {
+ local = 0;
+ bol = 1;
+ command(0, "z\n", 2);
+ return(1);
+ }
+ return(0);
+}
+
+static int
+telsnd(void)
+{
+ int tcc;
+ int count;
+ int returnValue = 0;
+ unsigned char *tbp = NULL;
+
+ tcc = 0;
+ count = 0;
+ while (NETROOM() > 2) {
+ int sc;
+ int c;
+
+ if (tcc == 0) {
+ if (count) {
+ ring_consumed(&ttyiring, count);
+ returnValue = 1;
+ count = 0;
+ }
+ tbp = ttyiring.consume;
+ tcc = ring_full_consecutive(&ttyiring);
+ if (tcc == 0) {
+ break;
+ }
+ }
+ c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
+ if (rlogin != _POSIX_VDISABLE) {
+ if (bol) {
+ bol = 0;
+ if (sc == rlogin) {
+ local = 1;
+ continue;
+ }
+ } else if (local) {
+ local = 0;
+ if (sc == '.' || c == termEofChar) {
+ bol = 1;
+ command(0, "close\n", 6);
+ continue;
+ }
+ if (sc == termSuspChar) {
+ bol = 1;
+ command(0, "z\n", 2);
+ continue;
+ }
+ if (sc == escape) {
+ command(0, (const char *)tbp, tcc);
+ bol = 1;
+ count += tcc;
+ tcc = 0;
+ flushline = 1;
+ break;
+ }
+ if (sc != rlogin) {
+ ++tcc;
+ --tbp;
+ --count;
+ c = sc = rlogin;
+ }
+ }
+ if ((sc == '\n') || (sc == '\r'))
+ bol = 1;
+ } else if (escape != _POSIX_VDISABLE && sc == escape) {
+ /*
+ * Double escape is a pass through of a single escape character.
+ */
+ if (tcc && strip(*tbp) == escape) {
+ tbp++;
+ tcc--;
+ count++;
+ bol = 0;
+ } else {
+ command(0, (char *)tbp, tcc);
+ bol = 1;
+ count += tcc;
+ tcc = 0;
+ flushline = 1;
+ break;
+ }
+ } else
+ bol = 0;
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
+ if (tcc > 0 && strip(*tbp) == echoc) {
+ tcc--; tbp++; count++;
+ } else {
+ dontlecho = !dontlecho;
+ settimer(echotoggle);
+ setconnmode(0);
+ flushline = 1;
+ break;
+ }
+ }
+#endif
+ if (MODE_LOCAL_CHARS(globalmode)) {
+ if (TerminalSpecialChars(sc) == 0) {
+ bol = 1;
+ break;
+ }
+ }
+ if (my_want_state_is_wont(TELOPT_BINARY)) {
+ switch (c) {
+ case '\n':
+ /*
+ * If we are in CRMOD mode (\r ==> \n)
+ * on our local machine, then probably
+ * a newline (unix) is CRLF (TELNET).
+ */
+ if (MODE_LOCAL_CHARS(globalmode)) {
+ NETADD('\r');
+ }
+ NETADD('\n');
+ bol = flushline = 1;
+ break;
+ case '\r':
+ if (!crlf) {
+ NET2ADD('\r', '\0');
+ } else {
+ NET2ADD('\r', '\n');
+ }
+ bol = flushline = 1;
+ break;
+ case IAC:
+ NET2ADD(IAC, IAC);
+ break;
+ default:
+ NETADD(c);
+ break;
+ }
+ } else if (c == IAC) {
+ NET2ADD(IAC, IAC);
+ } else {
+ NETADD(c);
+ }
+ }
+ if (count)
+ ring_consumed(&ttyiring, count);
+ return returnValue||count; /* Non-zero if we did anything */
+}
+
+/*
+ * Scheduler()
+ *
+ * Try to do something.
+ *
+ * If we do something useful, return 1; else return 0.
+ *
+ */
+
+static int
+Scheduler(int block)
+{
+ /* One wants to be a bit careful about setting returnValue
+ * to one, since a one implies we did some useful work,
+ * and therefore probably won't be called to block next
+ */
+ int returnValue;
+ int netin, netout, netex, ttyin, ttyout;
+
+ /* Decide which rings should be processed */
+
+ netout = ring_full_count(&netoring) &&
+ (flushline ||
+ (my_want_state_is_wont(TELOPT_LINEMODE)
+#ifdef KLUDGELINEMODE
+ && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
+#endif
+ ) ||
+ my_want_state_is_will(TELOPT_BINARY));
+ ttyout = ring_full_count(&ttyoring);
+
+ ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
+
+ netin = !ISend && ring_empty_count(&netiring);
+
+ netex = !SYNCHing;
+
+ /* Call to system code to process rings */
+
+ returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
+
+ /* Now, look at the input rings, looking for work to do. */
+
+ if (ring_full_count(&ttyiring)) {
+ returnValue |= telsnd();
+ }
+
+ if (ring_full_count(&netiring)) {
+ returnValue |= telrcv();
+ }
+ return returnValue;
+}
+
+#ifdef AUTHENTICATION
+#define __unusedhere
+#else
+#define __unusedhere __unused
+#endif
+/*
+ * Select from tty and network...
+ */
+void
+telnet(char *user __unusedhere)
+{
+ sys_telnet_init();
+
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+ {
+ static char local_host[256] = { 0 };
+
+ if (!local_host[0]) {
+ gethostname(local_host, sizeof(local_host));
+ local_host[sizeof(local_host)-1] = 0;
+ }
+ auth_encrypt_init(local_host, hostname, "TELNET", 0);
+ auth_encrypt_user(user);
+ }
+#endif
+#endif
+ if (telnetport > 0) {
+#ifdef AUTHENTICATION
+ if (autologin)
+ send_will(TELOPT_AUTHENTICATION, 1);
+#endif
+#ifdef ENCRYPTION
+ send_do(TELOPT_ENCRYPT, 1);
+ send_will(TELOPT_ENCRYPT, 1);
+#endif /* ENCRYPTION */
+ send_do(TELOPT_SGA, 1);
+ send_will(TELOPT_TTYPE, 1);
+ send_will(TELOPT_NAWS, 1);
+ send_will(TELOPT_TSPEED, 1);
+ send_will(TELOPT_LFLOW, 1);
+ send_will(TELOPT_LINEMODE, 1);
+ send_will(TELOPT_NEW_ENVIRON, 1);
+ send_do(TELOPT_STATUS, 1);
+ if (env_getvalue((const unsigned char *)"DISPLAY"))
+ send_will(TELOPT_XDISPLOC, 1);
+ if (eight)
+ tel_enter_binary(eight);
+ }
+
+ for (;;) {
+ int schedValue;
+
+ while ((schedValue = Scheduler(0)) != 0) {
+ if (schedValue == -1) {
+ setcommandmode();
+ return;
+ }
+ }
+
+ if (Scheduler(1) == -1) {
+ setcommandmode();
+ return;
+ }
+ }
+}
+
+#if 0 /* XXX - this not being in is a bug */
+/*
+ * nextitem()
+ *
+ * Return the address of the next "item" in the TELNET data
+ * stream. This will be the address of the next character if
+ * the current address is a user data character, or it will
+ * be the address of the character following the TELNET command
+ * if the current address is a TELNET IAC ("I Am a Command")
+ * character.
+ */
+
+static char *
+nextitem(char *current)
+{
+ if ((*current&0xff) != IAC) {
+ return current+1;
+ }
+ switch (*(current+1)&0xff) {
+ case DO:
+ case DONT:
+ case WILL:
+ case WONT:
+ return current+3;
+ case SB: /* loop forever looking for the SE */
+ {
+ char *look = current+2;
+
+ for (;;) {
+ if ((*look++&0xff) == IAC) {
+ if ((*look++&0xff) == SE) {
+ return look;
+ }
+ }
+ }
+ }
+ default:
+ return current+2;
+ }
+}
+#endif /* 0 */
+
+/*
+ * netclear()
+ *
+ * We are about to do a TELNET SYNCH operation. Clear
+ * the path to the network.
+ *
+ * Things are a bit tricky since we may have sent the first
+ * byte or so of a previous TELNET command into the network.
+ * So, we have to scan the network buffer from the beginning
+ * until we are up to where we want to be.
+ *
+ * A side effect of what we do, just to keep things
+ * simple, is to clear the urgent data pointer. The principal
+ * caller should be setting the urgent data pointer AFTER calling
+ * us in any case.
+ */
+
+static void
+netclear(void)
+{
+ /* Deleted */
+}
+
+/*
+ * These routines add various telnet commands to the data stream.
+ */
+
+static void
+doflush(void)
+{
+ NET2ADD(IAC, DO);
+ NETADD(TELOPT_TM);
+ flushline = 1;
+ flushout = 1;
+ (void) ttyflush(1); /* Flush/drop output */
+ /* do printoption AFTER flush, otherwise the output gets tossed... */
+ printoption("SENT", DO, TELOPT_TM);
+}
+
+void
+xmitAO(void)
+{
+ NET2ADD(IAC, AO);
+ printoption("SENT", IAC, AO);
+ if (autoflush) {
+ doflush();
+ }
+}
+
+void
+xmitEL(void)
+{
+ NET2ADD(IAC, EL);
+ printoption("SENT", IAC, EL);
+}
+
+void
+xmitEC(void)
+{
+ NET2ADD(IAC, EC);
+ printoption("SENT", IAC, EC);
+}
+
+int
+dosynch(char *ch __unused)
+{
+ netclear(); /* clear the path to the network */
+ NETADD(IAC);
+ setneturg();
+ NETADD(DM);
+ printoption("SENT", IAC, DM);
+ return 1;
+}
+
+int want_status_response = 0;
+
+int
+get_status(char *ch __unused)
+{
+ unsigned char tmp[16];
+ unsigned char *cp;
+
+ if (my_want_state_is_dont(TELOPT_STATUS)) {
+ printf("Remote side does not support STATUS option\n");
+ return 0;
+ }
+ cp = tmp;
+
+ *cp++ = IAC;
+ *cp++ = SB;
+ *cp++ = TELOPT_STATUS;
+ *cp++ = TELQUAL_SEND;
+ *cp++ = IAC;
+ *cp++ = SE;
+ if (NETROOM() >= cp - tmp) {
+ ring_supply_data(&netoring, tmp, cp-tmp);
+ printsub('>', tmp+2, cp - tmp - 2);
+ }
+ ++want_status_response;
+ return 1;
+}
+
+void
+intp(void)
+{
+ NET2ADD(IAC, IP);
+ printoption("SENT", IAC, IP);
+ flushline = 1;
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch(NULL);
+ }
+}
+
+void
+sendbrk(void)
+{
+ NET2ADD(IAC, BREAK);
+ printoption("SENT", IAC, BREAK);
+ flushline = 1;
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch(NULL);
+ }
+}
+
+void
+sendabort(void)
+{
+ NET2ADD(IAC, ABORT);
+ printoption("SENT", IAC, ABORT);
+ flushline = 1;
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch(NULL);
+ }
+}
+
+void
+sendsusp(void)
+{
+ NET2ADD(IAC, SUSP);
+ printoption("SENT", IAC, SUSP);
+ flushline = 1;
+ if (autoflush) {
+ doflush();
+ }
+ if (autosynch) {
+ dosynch(NULL);
+ }
+}
+
+void
+sendeof(void)
+{
+ NET2ADD(IAC, xEOF);
+ printoption("SENT", IAC, xEOF);
+}
+
+void
+sendayt(void)
+{
+ NET2ADD(IAC, AYT);
+ printoption("SENT", IAC, AYT);
+}
+
+/*
+ * Send a window size update to the remote system.
+ */
+
+void
+sendnaws(void)
+{
+ long rows, cols;
+ unsigned char tmp[16];
+ unsigned char *cp;
+
+ if (my_state_is_wont(TELOPT_NAWS))
+ return;
+
+#define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
+ if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
+
+ if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
+ return;
+ }
+
+ cp = tmp;
+
+ *cp++ = IAC;
+ *cp++ = SB;
+ *cp++ = TELOPT_NAWS;
+ PUTSHORT(cp, cols);
+ PUTSHORT(cp, rows);
+ *cp++ = IAC;
+ *cp++ = SE;
+ if (NETROOM() >= cp - tmp) {
+ ring_supply_data(&netoring, tmp, cp-tmp);
+ printsub('>', tmp+2, cp - tmp - 2);
+ }
+}
+
+void
+tel_enter_binary(int rw)
+{
+ if (rw&1)
+ send_do(TELOPT_BINARY, 1);
+ if (rw&2)
+ send_will(TELOPT_BINARY, 1);
+}
+
+void
+tel_leave_binary(int rw)
+{
+ if (rw&1)
+ send_dont(TELOPT_BINARY, 1);
+ if (rw&2)
+ send_wont(TELOPT_BINARY, 1);
+}
diff --git a/remote_cmds/telnet.tproj/terminal.c b/remote_cmds/telnet.tproj/terminal.c
new file mode 100644
index 0000000..96edc35
--- /dev/null
+++ b/remote_cmds/telnet.tproj/terminal.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)terminal.c 8.2 (Berkeley) 2/16/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/terminal.c,v 1.7 2003/05/04 02:54:48 obrien Exp $");
+
+#include <arpa/telnet.h>
+#include <sys/types.h>
+
+#include <stdlib.h>
+
+#include "ring.h"
+
+#include "externs.h"
+#include "types.h"
+
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+Ring ttyoring, ttyiring;
+unsigned char ttyobuf[2*BUFSIZ], ttyibuf[BUFSIZ];
+
+int termdata; /* Debugging flag */
+
+#ifdef USE_TERMIO
+# ifndef VDISCARD
+cc_t termFlushChar;
+# endif
+# ifndef VLNEXT
+cc_t termLiteralNextChar;
+# endif
+# ifndef VSUSP
+cc_t termSuspChar;
+# endif
+# ifndef VWERASE
+cc_t termWerasChar;
+# endif
+# ifndef VREPRINT
+cc_t termRprntChar;
+# endif
+# ifndef VSTART
+cc_t termStartChar;
+# endif
+# ifndef VSTOP
+cc_t termStopChar;
+# endif
+# ifndef VEOL
+cc_t termForw1Char;
+# endif
+# ifndef VEOL2
+cc_t termForw2Char;
+# endif
+# ifndef VSTATUS
+cc_t termAytChar;
+# endif
+#else
+cc_t termForw2Char;
+cc_t termAytChar;
+#endif
+
+/*
+ * initialize the terminal data structures.
+ */
+
+void
+init_terminal(void)
+{
+ if (ring_init(&ttyoring, ttyobuf, sizeof ttyobuf) != 1) {
+ exit(1);
+ }
+ if (ring_init(&ttyiring, ttyibuf, sizeof ttyibuf) != 1) {
+ exit(1);
+ }
+ autoflush = TerminalAutoFlush();
+}
+
+/*
+ * Send as much data as possible to the terminal.
+ *
+ * Return value:
+ * -1: No useful work done, data waiting to go out.
+ * 0: No data was waiting, so nothing was done.
+ * 1: All waiting data was written out.
+ * n: All data - n was written out.
+ */
+
+int
+ttyflush(int drop)
+{
+ int n, n0, n1;
+
+ n0 = ring_full_count(&ttyoring);
+ if ((n1 = n = ring_full_consecutive(&ttyoring)) > 0) {
+ if (drop) {
+ TerminalFlushOutput();
+ /* we leave 'n' alone! */
+ } else {
+ n = TerminalWrite((char *)ttyoring.consume, n);
+ }
+ }
+ if (n > 0) {
+ if (termdata && n) {
+ Dump('>', ttyoring.consume, n);
+ }
+ /*
+ * If we wrote everything, and the full count is
+ * larger than what we wrote, then write the
+ * rest of the buffer.
+ */
+ if (n1 == n && n0 > n) {
+ n1 = n0 - n;
+ if (!drop)
+ n1 = TerminalWrite((char *)ttyoring.bottom, n1);
+ if (n1 > 0)
+ n += n1;
+ }
+ ring_consumed(&ttyoring, n);
+ }
+ if (n < 0)
+ return -1;
+ if (n == n0) {
+ if (n0)
+ return -1;
+ return 0;
+ }
+ return n0 - n + 1;
+}
+
+
+/*
+ * These routines decides on what the mode should be (based on the values
+ * of various global variables).
+ */
+
+
+int
+getconnmode(void)
+{
+ extern int linemode;
+ int mode = 0;
+#ifdef KLUDGELINEMODE
+ extern int kludgelinemode;
+#endif
+
+ if (my_want_state_is_dont(TELOPT_ECHO))
+ mode |= MODE_ECHO;
+
+ if (localflow)
+ mode |= MODE_FLOW;
+
+ if (my_want_state_is_will(TELOPT_BINARY))
+ mode |= MODE_INBIN;
+
+ if (his_want_state_is_will(TELOPT_BINARY))
+ mode |= MODE_OUTBIN;
+
+#ifdef KLUDGELINEMODE
+ if (kludgelinemode) {
+ if (my_want_state_is_dont(TELOPT_SGA)) {
+ mode |= (MODE_TRAPSIG|MODE_EDIT);
+ if (dontlecho && (clocks.echotoggle > clocks.modenegotiated)) {
+ mode &= ~MODE_ECHO;
+ }
+ }
+ return(mode);
+ }
+#endif
+ if (my_want_state_is_will(TELOPT_LINEMODE))
+ mode |= linemode;
+ return(mode);
+}
+
+void
+setconnmode(int force)
+{
+#ifdef ENCRYPTION
+ static int enc_passwd = 0;
+#endif /* ENCRYPTION */
+ int newmode;
+
+ newmode = getconnmode()|(force?MODE_FORCE:0);
+
+ TerminalNewMode(newmode);
+
+#ifdef ENCRYPTION
+ if ((newmode & (MODE_ECHO|MODE_EDIT)) == MODE_EDIT) {
+ if (my_want_state_is_will(TELOPT_ENCRYPT)
+ && (enc_passwd == 0) && !encrypt_output) {
+ encrypt_request_start(0, 0);
+ enc_passwd = 1;
+ }
+ } else {
+ if (enc_passwd) {
+ encrypt_request_end();
+ enc_passwd = 0;
+ }
+ }
+#endif /* ENCRYPTION */
+
+}
+
+void
+setcommandmode(void)
+{
+ TerminalNewMode(-1);
+}
diff --git a/remote_cmds/telnet.tproj/tn3270.c b/remote_cmds/telnet.tproj/tn3270.c
new file mode 100644
index 0000000..c2bbd8f
--- /dev/null
+++ b/remote_cmds/telnet.tproj/tn3270.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static char sccsid[] = "@(#)tn3270.c 8.2 (Berkeley) 5/30/95";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <arpa/telnet.h>
+
+#include "general.h"
+
+#include "defines.h"
+#include "ring.h"
+#include "externs.h"
+#include "fdset.h"
+
+#if defined(TN3270)
+
+#include "../ctlr/screen.h"
+#include "../general/globals.h"
+
+#include "../sys_curses/telextrn.h"
+#include "../ctlr/externs.h"
+
+#if defined(unix) || defined(__APPLE__)
+int
+ HaveInput, /* There is input available to scan */
+ cursesdata, /* Do we dump curses data? */
+ sigiocount; /* Number of times we got a SIGIO */
+
+char tline[200];
+char *transcom = 0; /* transparent mode command (default: none) */
+#endif /* defined(unix) || defined(__APPLE__) */
+
+char Ibuf[8*BUFSIZ], *Ifrontp, *Ibackp;
+
+static char sb_terminal[] = { IAC, SB,
+ TELOPT_TTYPE, TELQUAL_IS,
+ 'I', 'B', 'M', '-', '3', '2', '7', '8', '-', '2',
+ IAC, SE };
+#define SBTERMMODEL 13
+
+static int
+ Sent3270TerminalType; /* Have we said we are a 3270? */
+
+#endif /* defined(TN3270) */
+
+
+ void
+init_3270()
+{
+#if defined(TN3270)
+#if defined(unix) || defined(__APPLE__)
+ HaveInput = 0;
+ sigiocount = 0;
+#endif /* defined(unix) || defined(__APPLE__) */
+ Sent3270TerminalType = 0;
+ Ifrontp = Ibackp = Ibuf;
+ init_ctlr(); /* Initialize some things */
+ init_keyboard();
+ init_screen();
+ init_system();
+#endif /* defined(TN3270) */
+}
+
+
+#if defined(TN3270)
+
+/*
+ * DataToNetwork - queue up some data to go to network. If "done" is set,
+ * then when last byte is queued, we add on an IAC EOR sequence (so,
+ * don't call us with "done" until you want that done...)
+ *
+ * We actually do send all the data to the network buffer, since our
+ * only client needs for us to do that.
+ */
+
+ int
+DataToNetwork(buffer, count, done)
+ register char *buffer; /* where the data is */
+ register int count; /* how much to send */
+ int done; /* is this the last of a logical block */
+{
+ register int loop, c;
+ int origCount;
+
+ origCount = count;
+
+ while (count) {
+ /* If not enough room for EORs, IACs, etc., wait */
+ if (NETROOM() < 6) {
+ fd_set o;
+
+ FD_ZERO(&o);
+ netflush();
+ while (NETROOM() < 6) {
+ FD_SET(net, &o);
+ (void) select(net+1, (fd_set *) 0, &o, (fd_set *) 0,
+ (struct timeval *) 0);
+ netflush();
+ }
+ }
+ c = ring_empty_count(&netoring);
+ if (c > count) {
+ c = count;
+ }
+ loop = c;
+ while (loop) {
+ if (((unsigned char)*buffer) == IAC) {
+ break;
+ }
+ buffer++;
+ loop--;
+ }
+ if ((c = c-loop)) {
+ ring_supply_data(&netoring, buffer-c, c);
+ count -= c;
+ }
+ if (loop) {
+ NET2ADD(IAC, IAC);
+ count--;
+ buffer++;
+ }
+ }
+
+ if (done) {
+ NET2ADD(IAC, EOR);
+ netflush(); /* try to move along as quickly as ... */
+ }
+ return(origCount - count);
+}
+
+
+#if defined(unix) || defined(__APPLE__)
+ void
+inputAvailable(signo)
+ int signo;
+{
+ HaveInput = 1;
+ sigiocount++;
+}
+#endif /* defined(unix) || defined(__APPLE__) */
+
+ void
+outputPurge()
+{
+ (void) ttyflush(1);
+}
+
+
+/*
+ * The following routines are places where the various tn3270
+ * routines make calls into telnet.c.
+ */
+
+/*
+ * DataToTerminal - queue up some data to go to terminal.
+ *
+ * Note: there are people who call us and depend on our processing
+ * *all* the data at one time (thus the select).
+ */
+
+ int
+DataToTerminal(buffer, count)
+ register char *buffer; /* where the data is */
+ register int count; /* how much to send */
+{
+ register int c;
+ int origCount;
+
+ origCount = count;
+
+ while (count) {
+ if (TTYROOM() == 0) {
+#if defined(unix) || defined(__APPLE__)
+ fd_set o;
+
+ FD_ZERO(&o);
+#endif /* defined(unix) || defined(__APPLE__) */
+ (void) ttyflush(0);
+ while (TTYROOM() == 0) {
+#if defined(unix) || defined(__APPLE__)
+ FD_SET(tout, &o);
+ (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+ (struct timeval *) 0);
+#endif /* defined(unix) || defined(__APPLE__) */
+ (void) ttyflush(0);
+ }
+ }
+ c = TTYROOM();
+ if (c > count) {
+ c = count;
+ }
+ ring_supply_data(&ttyoring, buffer, c);
+ count -= c;
+ buffer += c;
+ }
+ return(origCount);
+}
+
+
+/*
+ * Push3270 - Try to send data along the 3270 output (to screen) direction.
+ */
+
+ int
+Push3270()
+{
+ int save = ring_full_count(&netiring);
+
+ if (save) {
+ if (Ifrontp+save > Ibuf+sizeof Ibuf) {
+ if (Ibackp != Ibuf) {
+ memmove(Ibuf, Ibackp, Ifrontp-Ibackp);
+ Ifrontp -= (Ibackp-Ibuf);
+ Ibackp = Ibuf;
+ }
+ }
+ if (Ifrontp+save < Ibuf+sizeof Ibuf) {
+ (void)telrcv();
+ }
+ }
+ return save != ring_full_count(&netiring);
+}
+
+
+/*
+ * Finish3270 - get the last dregs of 3270 data out to the terminal
+ * before quitting.
+ */
+
+ void
+Finish3270()
+{
+ while (Push3270() || !DoTerminalOutput()) {
+#if defined(unix) || defined(__APPLE__)
+ HaveInput = 0;
+#endif /* defined(unix) || defined(__APPLE__) */
+ ;
+ }
+}
+
+
+/* StringToTerminal - output a null terminated string to the terminal */
+
+ void
+StringToTerminal(s)
+ char *s;
+{
+ int count;
+
+ count = strlen(s);
+ if (count) {
+ (void) DataToTerminal(s, count); /* we know it always goes... */
+ }
+}
+
+
+#if ((!defined(NOT43)) || defined(PUTCHAR))
+/* _putchar - output a single character to the terminal. This name is so that
+ * curses(3x) can call us to send out data.
+ */
+
+ void
+_putchar(c)
+ char c;
+{
+#if defined(sun) /* SunOS 4.0 bug */
+ c &= 0x7f;
+#endif /* defined(sun) */
+ if (cursesdata) {
+ Dump('>', &c, 1);
+ }
+ if (!TTYROOM()) {
+ (void) DataToTerminal(&c, 1);
+ } else {
+ TTYADD(c);
+ }
+}
+#endif /* ((!defined(NOT43)) || defined(PUTCHAR)) */
+
+ void
+SetIn3270()
+{
+ if (Sent3270TerminalType && my_want_state_is_will(TELOPT_BINARY)
+ && my_want_state_is_do(TELOPT_BINARY) && !donebinarytoggle) {
+ if (!In3270) {
+ In3270 = 1;
+ Init3270(); /* Initialize 3270 functions */
+ /* initialize terminal key mapping */
+ InitTerminal(); /* Start terminal going */
+ setconnmode(0);
+ }
+ } else {
+ if (In3270) {
+ StopScreen(1);
+ In3270 = 0;
+ Stop3270(); /* Tell 3270 we aren't here anymore */
+ setconnmode(0);
+ }
+ }
+}
+
+/*
+ * tn3270_ttype()
+ *
+ * Send a response to a terminal type negotiation.
+ *
+ * Return '0' if no more responses to send; '1' if a response sent.
+ */
+
+ int
+tn3270_ttype()
+{
+ /*
+ * Try to send a 3270 type terminal name. Decide which one based
+ * on the format of our screen, and (in the future) color
+ * capaiblities.
+ */
+ InitTerminal(); /* Sets MaxNumberColumns, MaxNumberLines */
+ if ((MaxNumberLines >= 24) && (MaxNumberColumns >= 80)) {
+ Sent3270TerminalType = 1;
+ if ((MaxNumberLines >= 27) && (MaxNumberColumns >= 132)) {
+ MaxNumberLines = 27;
+ MaxNumberColumns = 132;
+ sb_terminal[SBTERMMODEL] = '5';
+ } else if (MaxNumberLines >= 43) {
+ MaxNumberLines = 43;
+ MaxNumberColumns = 80;
+ sb_terminal[SBTERMMODEL] = '4';
+ } else if (MaxNumberLines >= 32) {
+ MaxNumberLines = 32;
+ MaxNumberColumns = 80;
+ sb_terminal[SBTERMMODEL] = '3';
+ } else {
+ MaxNumberLines = 24;
+ MaxNumberColumns = 80;
+ sb_terminal[SBTERMMODEL] = '2';
+ }
+ NumberLines = 24; /* before we start out... */
+ NumberColumns = 80;
+ ScreenSize = NumberLines*NumberColumns;
+ if ((MaxNumberLines*MaxNumberColumns) > MAXSCREENSIZE) {
+ ExitString("Programming error: MAXSCREENSIZE too small.\n",
+ 1);
+ /*NOTREACHED*/
+ }
+ printsub('>', sb_terminal+2, sizeof sb_terminal-2);
+ ring_supply_data(&netoring, sb_terminal, sizeof sb_terminal);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+#if defined(unix) || defined(__APPLE__)
+ int
+settranscom(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+
+ if (argc == 1 && transcom) {
+ transcom = 0;
+ }
+ if (argc == 1) {
+ return 1;
+ }
+ transcom = tline;
+ (void) strcpy(transcom, argv[1]);
+ for (i = 2; i < argc; ++i) {
+ (void) strcat(transcom, " ");
+ (void) strcat(transcom, argv[i]);
+ }
+ return 1;
+}
+#endif /* defined(unix) || defined(__APPLE__) */
+
+#endif /* defined(TN3270) */
diff --git a/remote_cmds/telnet.tproj/types.h b/remote_cmds/telnet.tproj/types.h
new file mode 100644
index 0000000..191d311
--- /dev/null
+++ b/remote_cmds/telnet.tproj/types.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)types.h 8.1 (Berkeley) 6/6/93
+ */
+
+typedef struct {
+ char *modedescriptions;
+ char modetype;
+} Modelist;
+
+extern Modelist modelist[];
+
+typedef struct {
+ int
+ system, /* what the current time is */
+ echotoggle, /* last time user entered echo character */
+ modenegotiated, /* last time operating mode negotiated */
+ didnetreceive, /* last time we read data from network */
+ gotDM; /* when did we last see a data mark */
+} Clocks;
+
+extern Clocks clocks;
diff --git a/remote_cmds/telnet.tproj/utilities.c b/remote_cmds/telnet.tproj/utilities.c
new file mode 100644
index 0000000..418c982
--- /dev/null
+++ b/remote_cmds/telnet.tproj/utilities.c
@@ -0,0 +1,912 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)utilities.c 8.3 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnet/utilities.c,v 1.8 2003/05/04 02:54:48 obrien Exp $");
+
+#define TELOPTS
+#define TELCMDS
+#define SLC_NAMES
+#include <arpa/telnet.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "general.h"
+
+#include "fdset.h"
+
+#include "ring.h"
+
+#include "defines.h"
+
+#include "externs.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+FILE *NetTrace = 0; /* Not in bss, since needs to stay */
+int prettydump;
+
+/*
+ * upcase()
+ *
+ * Upcase (in place) the argument.
+ */
+
+void
+upcase(char *argument)
+{
+ int c;
+
+ while ((c = *argument) != 0) {
+ if (islower(c)) {
+ *argument = toupper(c);
+ }
+ argument++;
+ }
+}
+
+/*
+ * SetSockOpt()
+ *
+ * Compensate for differences in 4.2 and 4.3 systems.
+ */
+
+int
+SetSockOpt(int fd, int level, int option, int yesno)
+{
+ return setsockopt(fd, level, option,
+ (char *)&yesno, sizeof yesno);
+}
+
+/*
+ * The following are routines used to print out debugging information.
+ */
+
+unsigned char NetTraceFile[256] = "(standard output)";
+
+void
+SetNetTrace(char *file)
+{
+ if (NetTrace && NetTrace != stdout)
+ fclose(NetTrace);
+ if (file && (strcmp(file, "-") != 0)) {
+ NetTrace = fopen(file, "w");
+ if (NetTrace) {
+ strcpy((char *)NetTraceFile, file);
+ return;
+ }
+ fprintf(stderr, "Cannot open %s.\n", file);
+ }
+ NetTrace = stdout;
+ strcpy((char *)NetTraceFile, "(standard output)");
+}
+
+void
+Dump(char direction, unsigned char *buffer, int length)
+{
+# define BYTES_PER_LINE 32
+# define min(x,y) ((x<y)? x:y)
+ unsigned char *pThis;
+ int offset;
+
+ offset = 0;
+
+ while (length) {
+ /* print one line */
+ fprintf(NetTrace, "%c 0x%x\t", direction, offset);
+ pThis = buffer;
+ if (prettydump) {
+ buffer = buffer + min(length, BYTES_PER_LINE/2);
+ while (pThis < buffer) {
+ fprintf(NetTrace, "%c%.2x",
+ (((*pThis)&0xff) == 0xff) ? '*' : ' ',
+ (*pThis)&0xff);
+ pThis++;
+ }
+ length -= BYTES_PER_LINE/2;
+ offset += BYTES_PER_LINE/2;
+ } else {
+ buffer = buffer + min(length, BYTES_PER_LINE);
+ while (pThis < buffer) {
+ fprintf(NetTrace, "%.2x", (*pThis)&0xff);
+ pThis++;
+ }
+ length -= BYTES_PER_LINE;
+ offset += BYTES_PER_LINE;
+ }
+ if (NetTrace == stdout) {
+ fprintf(NetTrace, "\r\n");
+ } else {
+ fprintf(NetTrace, "\n");
+ }
+ if (length < 0) {
+ fflush(NetTrace);
+ return;
+ }
+ /* find next unique line */
+ }
+ fflush(NetTrace);
+}
+
+
+void
+printoption(const char *direction, int cmd, int option)
+{
+ if (!showoptions)
+ return;
+ if (cmd == IAC) {
+ if (TELCMD_OK(option))
+ fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option));
+ else
+ fprintf(NetTrace, "%s IAC %d", direction, option);
+ } else {
+ const char *fmt;
+ fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
+ (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
+ if (fmt) {
+ fprintf(NetTrace, "%s %s ", direction, fmt);
+ if (TELOPT_OK(option))
+ fprintf(NetTrace, "%s", TELOPT(option));
+ else if (option == TELOPT_EXOPL)
+ fprintf(NetTrace, "EXOPL");
+ else
+ fprintf(NetTrace, "%d", option);
+ } else
+ fprintf(NetTrace, "%s %d %d", direction, cmd, option);
+ }
+ if (NetTrace == stdout) {
+ fprintf(NetTrace, "\r\n");
+ fflush(NetTrace);
+ } else {
+ fprintf(NetTrace, "\n");
+ }
+ return;
+}
+
+void
+optionstatus(void)
+{
+ int i;
+ extern char will_wont_resp[], do_dont_resp[];
+
+ for (i = 0; i < 256; i++) {
+ if (do_dont_resp[i]) {
+ if (TELOPT_OK(i))
+ printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]);
+ else if (TELCMD_OK(i))
+ printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]);
+ else
+ printf("resp DO_DONT %d: %d\n", i,
+ do_dont_resp[i]);
+ if (my_want_state_is_do(i)) {
+ if (TELOPT_OK(i))
+ printf("want DO %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("want DO %s\n", TELCMD(i));
+ else
+ printf("want DO %d\n", i);
+ } else {
+ if (TELOPT_OK(i))
+ printf("want DONT %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("want DONT %s\n", TELCMD(i));
+ else
+ printf("want DONT %d\n", i);
+ }
+ } else {
+ if (my_state_is_do(i)) {
+ if (TELOPT_OK(i))
+ printf(" DO %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf(" DO %s\n", TELCMD(i));
+ else
+ printf(" DO %d\n", i);
+ }
+ }
+ if (will_wont_resp[i]) {
+ if (TELOPT_OK(i))
+ printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]);
+ else if (TELCMD_OK(i))
+ printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]);
+ else
+ printf("resp WILL_WONT %d: %d\n",
+ i, will_wont_resp[i]);
+ if (my_want_state_is_will(i)) {
+ if (TELOPT_OK(i))
+ printf("want WILL %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("want WILL %s\n", TELCMD(i));
+ else
+ printf("want WILL %d\n", i);
+ } else {
+ if (TELOPT_OK(i))
+ printf("want WONT %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("want WONT %s\n", TELCMD(i));
+ else
+ printf("want WONT %d\n", i);
+ }
+ } else {
+ if (my_state_is_will(i)) {
+ if (TELOPT_OK(i))
+ printf(" WILL %s\n", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf(" WILL %s\n", TELCMD(i));
+ else
+ printf(" WILL %d\n", i);
+ }
+ }
+ }
+
+}
+
+void
+printsub(char direction, unsigned char *pointer, int length)
+{
+ int i;
+#ifdef AUTHENTICATION
+ char buf[512];
+#endif
+ extern int want_status_response;
+
+ if (showoptions || direction == 0 ||
+ (want_status_response && (pointer[0] == TELOPT_STATUS))) {
+ if (direction) {
+ fprintf(NetTrace, "%s IAC SB ",
+ (direction == '<')? "RCVD":"SENT");
+ if (length >= 3) {
+ int j;
+
+ i = pointer[length-2];
+ j = pointer[length-1];
+
+ if (i != IAC || j != SE) {
+ fprintf(NetTrace, "(terminated by ");
+ if (TELOPT_OK(i))
+ fprintf(NetTrace, "%s ", TELOPT(i));
+ else if (TELCMD_OK(i))
+ fprintf(NetTrace, "%s ", TELCMD(i));
+ else
+ fprintf(NetTrace, "%d ", i);
+ if (TELOPT_OK(j))
+ fprintf(NetTrace, "%s", TELOPT(j));
+ else if (TELCMD_OK(j))
+ fprintf(NetTrace, "%s", TELCMD(j));
+ else
+ fprintf(NetTrace, "%d", j);
+ fprintf(NetTrace, ", not IAC SE!) ");
+ }
+ }
+ length -= 2;
+ }
+ if (length < 1) {
+ fprintf(NetTrace, "(Empty suboption??\?)");
+ if (NetTrace == stdout)
+ fflush(NetTrace);
+ return;
+ }
+ switch (pointer[0]) {
+ case TELOPT_TTYPE:
+ fprintf(NetTrace, "TERMINAL-TYPE ");
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
+ break;
+ case TELQUAL_SEND:
+ fprintf(NetTrace, "SEND");
+ break;
+ default:
+ fprintf(NetTrace,
+ "- unknown qualifier %d (0x%x).",
+ pointer[1], pointer[1]);
+ }
+ break;
+ case TELOPT_TSPEED:
+ fprintf(NetTrace, "TERMINAL-SPEED");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ fprintf(NetTrace, " IS ");
+ fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2);
+ break;
+ default:
+ if (pointer[1] == 1)
+ fprintf(NetTrace, " SEND");
+ else
+ fprintf(NetTrace, " %d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+ }
+ break;
+
+ case TELOPT_LFLOW:
+ fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case LFLOW_OFF:
+ fprintf(NetTrace, " OFF"); break;
+ case LFLOW_ON:
+ fprintf(NetTrace, " ON"); break;
+ case LFLOW_RESTART_ANY:
+ fprintf(NetTrace, " RESTART-ANY"); break;
+ case LFLOW_RESTART_XON:
+ fprintf(NetTrace, " RESTART-XON"); break;
+ default:
+ fprintf(NetTrace, " %d (unknown)", pointer[1]);
+ }
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+
+ case TELOPT_NAWS:
+ fprintf(NetTrace, "NAWS");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ if (length == 2) {
+ fprintf(NetTrace, " ?%d?", pointer[1]);
+ break;
+ }
+ fprintf(NetTrace, " %d %d (%d)",
+ pointer[1], pointer[2],
+ (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
+ if (length == 4) {
+ fprintf(NetTrace, " ?%d?", pointer[3]);
+ break;
+ }
+ fprintf(NetTrace, " %d %d (%d)",
+ pointer[3], pointer[4],
+ (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
+ for (i = 5; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ fprintf(NetTrace, "AUTHENTICATION");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case TELQUAL_REPLY:
+ case TELQUAL_IS:
+ fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ?
+ "IS" : "REPLY");
+ if (AUTHTYPE_NAME_OK(pointer[2]))
+ fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2]));
+ else
+ fprintf(NetTrace, "%d ", pointer[2]);
+ if (length < 3) {
+ fprintf(NetTrace, "(partial suboption??\?)");
+ break;
+ }
+ fprintf(NetTrace, "%s|%s",
+ ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+ "CLIENT" : "SERVER",
+ ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+ "MUTUAL" : "ONE-WAY");
+
+ auth_printsub(&pointer[1], length - 1, (unsigned char *)buf, sizeof(buf));
+ fprintf(NetTrace, "%s", buf);
+ break;
+
+ case TELQUAL_SEND:
+ i = 2;
+ fprintf(NetTrace, " SEND ");
+ while (i < length) {
+ if (AUTHTYPE_NAME_OK(pointer[i]))
+ fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i]));
+ else
+ fprintf(NetTrace, "%d ", pointer[i]);
+ if (++i >= length) {
+ fprintf(NetTrace, "(partial suboption??\?)");
+ break;
+ }
+ fprintf(NetTrace, "%s|%s ",
+ ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+ "CLIENT" : "SERVER",
+ ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+ "MUTUAL" : "ONE-WAY");
+ ++i;
+ }
+ break;
+
+ case TELQUAL_NAME:
+ i = 2;
+ fprintf(NetTrace, " NAME \"");
+ while (i < length)
+ putc(pointer[i++], NetTrace);
+ putc('"', NetTrace);
+ break;
+
+ default:
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+ }
+ break;
+#endif
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ fprintf(NetTrace, "ENCRYPT");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case ENCRYPT_START:
+ fprintf(NetTrace, " START");
+ break;
+
+ case ENCRYPT_END:
+ fprintf(NetTrace, " END");
+ break;
+
+ case ENCRYPT_REQSTART:
+ fprintf(NetTrace, " REQUEST-START");
+ break;
+
+ case ENCRYPT_REQEND:
+ fprintf(NetTrace, " REQUEST-END");
+ break;
+
+ case ENCRYPT_IS:
+ case ENCRYPT_REPLY:
+ fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ?
+ "IS" : "REPLY");
+ if (length < 3) {
+ fprintf(NetTrace, " (partial suboption??\?)");
+ break;
+ }
+ if (ENCTYPE_NAME_OK(pointer[2]))
+ fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2]));
+ else
+ fprintf(NetTrace, " %d (unknown)", pointer[2]);
+
+ encrypt_printsub(&pointer[1], length - 1, (unsigned char *)buf, sizeof(buf));
+ fprintf(NetTrace, "%s", buf);
+ break;
+
+ case ENCRYPT_SUPPORT:
+ i = 2;
+ fprintf(NetTrace, " SUPPORT ");
+ while (i < length) {
+ if (ENCTYPE_NAME_OK(pointer[i]))
+ fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i]));
+ else
+ fprintf(NetTrace, "%d ", pointer[i]);
+ i++;
+ }
+ break;
+
+ case ENCRYPT_ENC_KEYID:
+ fprintf(NetTrace, " ENC_KEYID ");
+ goto encommon;
+
+ case ENCRYPT_DEC_KEYID:
+ fprintf(NetTrace, " DEC_KEYID ");
+ goto encommon;
+
+ default:
+ fprintf(NetTrace, " %d (unknown)", pointer[1]);
+ encommon:
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " %d", pointer[i]);
+ break;
+ }
+ break;
+#endif /* ENCRYPTION */
+
+ case TELOPT_LINEMODE:
+ fprintf(NetTrace, "LINEMODE ");
+ if (length < 2) {
+ fprintf(NetTrace, " (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case WILL:
+ fprintf(NetTrace, "WILL ");
+ goto common;
+ case WONT:
+ fprintf(NetTrace, "WONT ");
+ goto common;
+ case DO:
+ fprintf(NetTrace, "DO ");
+ goto common;
+ case DONT:
+ fprintf(NetTrace, "DONT ");
+ common:
+ if (length < 3) {
+ fprintf(NetTrace, "(no option??\?)");
+ break;
+ }
+ switch (pointer[2]) {
+ case LM_FORWARDMASK:
+ fprintf(NetTrace, "Forward Mask");
+ for (i = 3; i < length; i++)
+ fprintf(NetTrace, " %x", pointer[i]);
+ break;
+ default:
+ fprintf(NetTrace, "%d (unknown)", pointer[2]);
+ for (i = 3; i < length; i++)
+ fprintf(NetTrace, " %d", pointer[i]);
+ break;
+ }
+ break;
+
+ case LM_SLC:
+ fprintf(NetTrace, "SLC");
+ for (i = 2; i < length - 2; i += 3) {
+ if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
+ fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC]));
+ else
+ fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]);
+ switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
+ case SLC_NOSUPPORT:
+ fprintf(NetTrace, " NOSUPPORT"); break;
+ case SLC_CANTCHANGE:
+ fprintf(NetTrace, " CANTCHANGE"); break;
+ case SLC_VARIABLE:
+ fprintf(NetTrace, " VARIABLE"); break;
+ case SLC_DEFAULT:
+ fprintf(NetTrace, " DEFAULT"); break;
+ }
+ fprintf(NetTrace, "%s%s%s",
+ pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
+ pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
+ pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
+ if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
+ SLC_FLUSHOUT| SLC_LEVELBITS))
+ fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]);
+ fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]);
+ if ((pointer[i+SLC_VALUE] == IAC) &&
+ (pointer[i+SLC_VALUE+1] == IAC))
+ i++;
+ }
+ for (; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+
+ case LM_MODE:
+ fprintf(NetTrace, "MODE ");
+ if (length < 3) {
+ fprintf(NetTrace, "(no mode??\?)");
+ break;
+ }
+ {
+ char tbuf[64];
+ sprintf(tbuf, "%s%s%s%s%s",
+ pointer[2]&MODE_EDIT ? "|EDIT" : "",
+ pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
+ pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
+ pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
+ pointer[2]&MODE_ACK ? "|ACK" : "");
+ fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0");
+ }
+ if (pointer[2]&~(MODE_MASK))
+ fprintf(NetTrace, " (0x%x)", pointer[2]);
+ for (i = 3; i < length; i++)
+ fprintf(NetTrace, " ?0x%x?", pointer[i]);
+ break;
+ default:
+ fprintf(NetTrace, "%d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " %d", pointer[i]);
+ }
+ break;
+
+ case TELOPT_STATUS: {
+ const char *cp;
+ int j, k;
+
+ fprintf(NetTrace, "STATUS");
+
+ switch (pointer[1]) {
+ default:
+ if (pointer[1] == TELQUAL_SEND)
+ fprintf(NetTrace, " SEND");
+ else
+ fprintf(NetTrace, " %d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++)
+ fprintf(NetTrace, " ?%d?", pointer[i]);
+ break;
+ case TELQUAL_IS:
+ if (--want_status_response < 0)
+ want_status_response = 0;
+ if (NetTrace == stdout)
+ fprintf(NetTrace, " IS\r\n");
+ else
+ fprintf(NetTrace, " IS\n");
+
+ for (i = 2; i < length; i++) {
+ switch(pointer[i]) {
+ case DO: cp = "DO"; goto common2;
+ case DONT: cp = "DONT"; goto common2;
+ case WILL: cp = "WILL"; goto common2;
+ case WONT: cp = "WONT"; goto common2;
+ common2:
+ i++;
+ if (TELOPT_OK((int)pointer[i]))
+ fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i]));
+ else
+ fprintf(NetTrace, " %s %d", cp, pointer[i]);
+
+ if (NetTrace == stdout)
+ fprintf(NetTrace, "\r\n");
+ else
+ fprintf(NetTrace, "\n");
+ break;
+
+ case SB:
+ fprintf(NetTrace, " SB ");
+ i++;
+ j = k = i;
+ while (j < length) {
+ if (pointer[j] == SE) {
+ if (j+1 == length)
+ break;
+ if (pointer[j+1] == SE)
+ j++;
+ else
+ break;
+ }
+ pointer[k++] = pointer[j++];
+ }
+ printsub(0, &pointer[i], k - i);
+ if (i < length) {
+ fprintf(NetTrace, " SE");
+ i = j;
+ } else
+ i = j - 1;
+
+ if (NetTrace == stdout)
+ fprintf(NetTrace, "\r\n");
+ else
+ fprintf(NetTrace, "\n");
+
+ break;
+
+ default:
+ fprintf(NetTrace, " %d", pointer[i]);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ case TELOPT_XDISPLOC:
+ fprintf(NetTrace, "X-DISPLAY-LOCATION ");
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2);
+ break;
+ case TELQUAL_SEND:
+ fprintf(NetTrace, "SEND");
+ break;
+ default:
+ fprintf(NetTrace, "- unknown qualifier %d (0x%x).",
+ pointer[1], pointer[1]);
+ }
+ break;
+
+ case TELOPT_NEW_ENVIRON:
+ fprintf(NetTrace, "NEW-ENVIRON ");
+#ifdef OLD_ENVIRON
+ goto env_common1;
+ case TELOPT_OLD_ENVIRON:
+ fprintf(NetTrace, "OLD-ENVIRON");
+ env_common1:
+#endif
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ fprintf(NetTrace, "IS ");
+ goto env_common;
+ case TELQUAL_SEND:
+ fprintf(NetTrace, "SEND ");
+ goto env_common;
+ case TELQUAL_INFO:
+ fprintf(NetTrace, "INFO ");
+ env_common:
+ {
+ int noquote = 2;
+#if defined(ENV_HACK) && defined(OLD_ENVIRON)
+ extern int old_env_var, old_env_value;
+#endif
+ for (i = 2; i < length; i++ ) {
+ switch (pointer[i]) {
+ case NEW_ENV_VALUE:
+#ifdef OLD_ENVIRON
+ /* case NEW_ENV_OVAR: */
+ if (pointer[0] == TELOPT_OLD_ENVIRON) {
+# ifdef ENV_HACK
+ if (old_env_var == OLD_ENV_VALUE)
+ fprintf(NetTrace, "\" (VALUE) " + noquote);
+ else
+# endif
+ fprintf(NetTrace, "\" VAR " + noquote);
+ } else
+#endif /* OLD_ENVIRON */
+ fprintf(NetTrace, "%s", "\" VALUE " + noquote);
+ noquote = 2;
+ break;
+
+ case NEW_ENV_VAR:
+#ifdef OLD_ENVIRON
+ /* case OLD_ENV_VALUE: */
+ if (pointer[0] == TELOPT_OLD_ENVIRON) {
+# ifdef ENV_HACK
+ if (old_env_value == OLD_ENV_VAR)
+ fprintf(NetTrace, "\" (VAR) " + noquote);
+ else
+# endif
+ fprintf(NetTrace, "\" VALUE " + noquote);
+ } else
+#endif /* OLD_ENVIRON */
+ fprintf(NetTrace, "%s", "\" VAR " + noquote);
+ noquote = 2;
+ break;
+
+ case ENV_ESC:
+ fprintf(NetTrace, "%s", "\" ESC " + noquote);
+ noquote = 2;
+ break;
+
+ case ENV_USERVAR:
+ fprintf(NetTrace, "%s", "\" USERVAR " + noquote);
+ noquote = 2;
+ break;
+
+ default:
+ if (isprint(pointer[i]) && pointer[i] != '"') {
+ if (noquote) {
+ putc('"', NetTrace);
+ noquote = 0;
+ }
+ putc(pointer[i], NetTrace);
+ } else {
+ fprintf(NetTrace, "\" %03o " + noquote,
+ pointer[i]);
+ noquote = 2;
+ }
+ break;
+ }
+ }
+ if (!noquote)
+ putc('"', NetTrace);
+ break;
+ }
+ }
+ break;
+
+ default:
+ if (TELOPT_OK(pointer[0]))
+ fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
+ else
+ fprintf(NetTrace, "%d (unknown)", pointer[0]);
+ for (i = 1; i < length; i++)
+ fprintf(NetTrace, " %d", pointer[i]);
+ break;
+ }
+ if (direction) {
+ if (NetTrace == stdout)
+ fprintf(NetTrace, "\r\n");
+ else
+ fprintf(NetTrace, "\n");
+ }
+ if (NetTrace == stdout)
+ fflush(NetTrace);
+ }
+}
+
+/* EmptyTerminal - called to make sure that the terminal buffer is empty.
+ * Note that we consider the buffer to run all the
+ * way to the kernel (thus the select).
+ */
+
+static void
+EmptyTerminal(void)
+{
+ fd_set o;
+
+ FD_ZERO(&o);
+
+ if (TTYBYTES() == 0) {
+ FD_SET(tout, &o);
+ (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+ (struct timeval *) 0); /* wait for TTLOWAT */
+ } else {
+ while (TTYBYTES()) {
+ (void) ttyflush(0);
+ FD_SET(tout, &o);
+ (void) select(tout+1, (fd_set *) 0, &o, (fd_set *) 0,
+ (struct timeval *) 0); /* wait for TTLOWAT */
+ }
+ }
+}
+
+static void
+SetForExit(void)
+{
+ setconnmode(0);
+ do {
+ (void)telrcv(); /* Process any incoming data */
+ EmptyTerminal();
+ } while (ring_full_count(&netiring)); /* While there is any */
+ setcommandmode();
+ fflush(stdout);
+ fflush(stderr);
+ setconnmode(0);
+ EmptyTerminal(); /* Flush the path to the tty */
+ setcommandmode();
+}
+
+void
+Exit(int returnCode)
+{
+ SetForExit();
+ exit(returnCode);
+}
+
+void
+ExitString(const char *string, int returnCode)
+{
+ SetForExit();
+ fwrite(string, 1, strlen(string), stderr);
+ exit(returnCode);
+}
diff --git a/remote_cmds/telnetd.tproj/Makefile b/remote_cmds/telnetd.tproj/Makefile
new file mode 100644
index 0000000..c3f7feb
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/Makefile
@@ -0,0 +1,50 @@
+Project = telnetd
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+Install_Dir = /usr/libexec
+else
+Install_Dir = /usr/local/libexec
+endif
+
+HFILES = defs.h ext.h pathnames.h telnetd.h
+CFILES = global.c slc.c state.c sys_term.c telnetd.c\
+ termstat.c utility.c
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+LAUNCHD_PLISTS = telnet.plist
+endif
+
+Extra_CC_Flags = -Wall -Werror -Wno-string-plus-int -fPIE
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -pie
+
+Extra_CC_Flags += -DNO_UTMP -DLINEMODE -DKLUDGELINEMODE -DUSE_TERMIO \
+ -DDIAGNOSTICS -DOLD_ENVIRON -DENV_HACK -DINET6 \
+ # -DAUTHENTICATION -DENCRYPTION
+Extra_LD_Libraries = -lcurses -ltelnet
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
+
+after_install:
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+ /usr/libexec/PlistBuddy -x \
+ -c "Delete :Disabled" \
+ -c "Add :PosixSpawnType string Interactive" \
+ -c "Delete :SessionCreate" \
+ -c "Set :Sockets:Listeners:Bonjour false" \
+ -c "Add :Sockets:Listeners:SockFamily string IPv4" \
+ -c "Add :Sockets:Listeners:SockNodeName string localhost" \
+ "$(DSTROOT)/System/Library/LaunchDaemons/telnet.plist"
+ifeq "$(RC_PLATFORM_NAME)" "BridgeOS"
+ /usr/libexec/PlistBuddy -x \
+ -c "Delete :Sockets:Listeners:SockNodeName" \
+ -c "Delete :Sockets:Listeners:SockFamily" \
+ "$(DSTROOT)/System/Library/LaunchDaemons/telnet.plist"
+endif
+ plutil -convert binary1 "$(DSTROOT)/System/Library/LaunchDaemons/$(LAUNCHD_PLISTS)"
+endif
+ /usr/bin/codesign --force --sign - --entitlements entitlements.plist $(DSTROOT)$(Install_Dir)/$(Project)
+
+# Install a special launchd plist for the DebugDiskImage (38885624)
+ifeq "$(RC_TARGET_CONFIG)" "iPhone"
+ plutil -replace ProgramArguments -json '["/var/personalized_debug/usr/libexec/telnetd","-p","/var/personalized_debug/usr/bin/login"]' -o "$(DSTROOT)/System/Library/LaunchDaemons/telnet.debug.plist" "$(DSTROOT)/System/Library/LaunchDaemons/telnet.plist"
+ plutil -replace Label -string com.apple.telnetd.debug "$(DSTROOT)/System/Library/LaunchDaemons/telnet.debug.plist"
+endif
diff --git a/remote_cmds/telnetd.tproj/authenc.c b/remote_cmds/telnetd.tproj/authenc.c
new file mode 100644
index 0000000..10934ff
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/authenc.c
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)authenc.c 8.2 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/authenc.c,v 1.8 2003/05/04 02:54:49 obrien Exp $");
+
+#if defined(AUTHENTICATION) || defined(ENCRYPTION)
+#include "telnetd.h"
+#include <libtelnet/misc.h>
+
+int
+net_write(unsigned char *str, int len)
+{
+ if (nfrontp + len < netobuf + BUFSIZ) {
+ output_datalen(str, len);
+ return(len);
+ }
+ return(0);
+}
+
+void
+net_encrypt(void)
+{
+#ifdef ENCRYPTION
+ char *s = (nclearto > nbackp) ? nclearto : nbackp;
+ if (s < nfrontp && encrypt_output) {
+ (*encrypt_output)((unsigned char *)s, nfrontp - s);
+ }
+ nclearto = nfrontp;
+#endif /* ENCRYPTION */
+}
+
+int
+telnet_spin(void)
+{
+ ttloop();
+ return(0);
+}
+
+char *
+telnet_getenv(char *val)
+{
+ return(getenv(val));
+}
+
+char *
+telnet_gets(const char *prompt __unused, char *result __unused, int length __unused, int echo __unused)
+{
+ return(NULL);
+}
+#endif /* ENCRYPTION */
+#endif /* AUTHENTICATION */
diff --git a/remote_cmds/telnetd.tproj/defs.h b/remote_cmds/telnetd.tproj/defs.h
new file mode 100644
index 0000000..31ef2fb
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/defs.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)defs.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/contrib/telnet/telnetd/defs.h,v 1.2 2001/08/29 14:16:15 markm Exp $
+ */
+
+/*
+ * Telnet server defines
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifndef BSD
+# define BSD 43
+#endif
+
+#if defined(PRINTOPTIONS) && defined(DIAGNOSTICS)
+#define TELOPTS
+#define TELCMDS
+#define SLC_NAMES
+#endif
+
+#if defined(SYSV_TERMIO) && !defined(USE_TERMIO)
+# define USE_TERMIO
+#endif
+
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#ifndef FILIO_H
+#include <sys/ioctl.h>
+#else
+#include <sys/filio.h>
+#endif
+
+#include <netinet/in.h>
+
+#include <arpa/telnet.h>
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <signal.h>
+#include <errno.h>
+#include <netdb.h>
+#include <syslog.h>
+#ifndef LOG_DAEMON
+#define LOG_DAEMON 0
+#endif
+#ifndef LOG_ODELAY
+#define LOG_ODELAY 0
+#endif
+#include <ctype.h>
+#ifndef NO_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifndef USE_TERMIO
+#include <sgtty.h>
+#else
+# ifdef SYSV_TERMIO
+# include <termio.h>
+# else
+# include <termios.h>
+# endif
+#endif
+#if !defined(USE_TERMIO) || defined(NO_CC_T)
+typedef unsigned char cc_t;
+#endif
+
+#ifdef __STDC__
+#include <unistd.h>
+#endif
+
+#ifndef _POSIX_VDISABLE
+# ifdef VDISABLE
+# define _POSIX_VDISABLE VDISABLE
+# else
+# define _POSIX_VDISABLE ((unsigned char)'\377')
+# endif
+#endif
+
+#if !defined(TIOCSCTTY) && defined(TCSETCTTY)
+# define TIOCSCTTY TCSETCTTY
+#endif
+
+#ifndef FD_SET
+#ifndef HAVE_fd_set
+typedef struct fd_set { int fds_bits[1]; } fd_set;
+#endif
+
+#define FD_SET(n, p) ((p)->fds_bits[0] |= (1<<(n)))
+#define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1<<(n)))
+#define FD_ISSET(n, p) ((p)->fds_bits[0] & (1<<(n)))
+#define FD_ZERO(p) ((p)->fds_bits[0] = 0)
+#endif /* FD_SET */
+
+/*
+ * I/O data buffers defines
+ */
+#define NETSLOP 64
+
+#define NIACCUM(c) { *netip++ = c; \
+ ncc++; \
+ }
+
+/* clock manipulations */
+#define settimer(x) (clocks.x = ++clocks.system)
+#define sequenceIs(x,y) (clocks.x < clocks.y)
+
+/*
+ * Linemode support states, in decreasing order of importance
+ */
+#define REAL_LINEMODE 0x04
+#define KLUDGE_OK 0x03
+#define NO_AUTOKLUDGE 0x02
+#define KLUDGE_LINEMODE 0x01
+#define NO_LINEMODE 0x00
+
+/*
+ * Structures of information for each special character function.
+ */
+typedef struct {
+ unsigned char flag; /* the flags for this function */
+ cc_t val; /* the value of the special character */
+} slcent, *Slcent;
+
+typedef struct {
+ slcent defset; /* the default settings */
+ slcent current; /* the current settings */
+ cc_t *sptr; /* a pointer to the char in */
+ /* system data structures */
+} slcfun, *Slcfun;
+
+#ifdef DIAGNOSTICS
+/*
+ * Diagnostics capabilities
+ */
+#define TD_REPORT 0x01 /* Report operations to client */
+#define TD_EXERCISE 0x02 /* Exercise client's implementation */
+#define TD_NETDATA 0x04 /* Display received data stream */
+#define TD_PTYDATA 0x08 /* Display data passed to pty */
+#define TD_OPTIONS 0x10 /* Report just telnet options */
+#endif /* DIAGNOSTICS */
+
+/*
+ * We keep track of each side of the option negotiation.
+ */
+
+#define MY_STATE_WILL 0x01
+#define MY_WANT_STATE_WILL 0x02
+#define MY_STATE_DO 0x04
+#define MY_WANT_STATE_DO 0x08
+
+/*
+ * Macros to check the current state of things
+ */
+
+#define my_state_is_do(opt) (options[opt]&MY_STATE_DO)
+#define my_state_is_will(opt) (options[opt]&MY_STATE_WILL)
+#define my_want_state_is_do(opt) (options[opt]&MY_WANT_STATE_DO)
+#define my_want_state_is_will(opt) (options[opt]&MY_WANT_STATE_WILL)
+
+#define my_state_is_dont(opt) (!my_state_is_do(opt))
+#define my_state_is_wont(opt) (!my_state_is_will(opt))
+#define my_want_state_is_dont(opt) (!my_want_state_is_do(opt))
+#define my_want_state_is_wont(opt) (!my_want_state_is_will(opt))
+
+#define set_my_state_do(opt) (options[opt] |= MY_STATE_DO)
+#define set_my_state_will(opt) (options[opt] |= MY_STATE_WILL)
+#define set_my_want_state_do(opt) (options[opt] |= MY_WANT_STATE_DO)
+#define set_my_want_state_will(opt) (options[opt] |= MY_WANT_STATE_WILL)
+
+#define set_my_state_dont(opt) (options[opt] &= ~MY_STATE_DO)
+#define set_my_state_wont(opt) (options[opt] &= ~MY_STATE_WILL)
+#define set_my_want_state_dont(opt) (options[opt] &= ~MY_WANT_STATE_DO)
+#define set_my_want_state_wont(opt) (options[opt] &= ~MY_WANT_STATE_WILL)
+
+/*
+ * Tricky code here. What we want to know is if the MY_STATE_WILL
+ * and MY_WANT_STATE_WILL bits have the same value. Since the two
+ * bits are adjacent, a little arithmatic will show that by adding
+ * in the lower bit, the upper bit will be set if the two bits were
+ * different, and clear if they were the same.
+ */
+#define my_will_wont_is_changing(opt) \
+ ((options[opt]+MY_STATE_WILL) & MY_WANT_STATE_WILL)
+
+#define my_do_dont_is_changing(opt) \
+ ((options[opt]+MY_STATE_DO) & MY_WANT_STATE_DO)
+
+/*
+ * Make everything symetrical
+ */
+
+#define HIS_STATE_WILL MY_STATE_DO
+#define HIS_WANT_STATE_WILL MY_WANT_STATE_DO
+#define HIS_STATE_DO MY_STATE_WILL
+#define HIS_WANT_STATE_DO MY_WANT_STATE_WILL
+
+#define his_state_is_do my_state_is_will
+#define his_state_is_will my_state_is_do
+#define his_want_state_is_do my_want_state_is_will
+#define his_want_state_is_will my_want_state_is_do
+
+#define his_state_is_dont my_state_is_wont
+#define his_state_is_wont my_state_is_dont
+#define his_want_state_is_dont my_want_state_is_wont
+#define his_want_state_is_wont my_want_state_is_dont
+
+#define set_his_state_do set_my_state_will
+#define set_his_state_will set_my_state_do
+#define set_his_want_state_do set_my_want_state_will
+#define set_his_want_state_will set_my_want_state_do
+
+#define set_his_state_dont set_my_state_wont
+#define set_his_state_wont set_my_state_dont
+#define set_his_want_state_dont set_my_want_state_wont
+#define set_his_want_state_wont set_my_want_state_dont
+
+#define his_will_wont_is_changing my_do_dont_is_changing
+#define his_do_dont_is_changing my_will_wont_is_changing
diff --git a/remote_cmds/telnetd.tproj/entitlements.plist b/remote_cmds/telnetd.tproj/entitlements.plist
new file mode 100644
index 0000000..4d3ae68
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.network.server</key>
+ <true/>
+</dict>
+</plist>
diff --git a/remote_cmds/telnetd.tproj/ext.h b/remote_cmds/telnetd.tproj/ext.h
new file mode 100644
index 0000000..0905b61
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/ext.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ext.h 8.2 (Berkeley) 12/15/93
+ * $FreeBSD: src/contrib/telnet/telnetd/ext.h,v 1.11 2001/11/30 22:28:07 markm Exp $
+ */
+
+/*
+ * Telnet server variable declarations
+ */
+extern char options[256];
+extern char do_dont_resp[256];
+extern char will_wont_resp[256];
+extern int linemode; /* linemode on/off */
+#ifdef LINEMODE
+extern int uselinemode; /* what linemode to use (on/off) */
+extern int editmode; /* edit modes in use */
+extern int useeditmode; /* edit modes to use */
+extern int alwayslinemode; /* command line option */
+extern int lmodetype; /* Client support for linemode */
+#endif /* LINEMODE */
+extern int flowmode; /* current flow control state */
+extern int restartany; /* restart output on any character state */
+#ifdef DIAGNOSTICS
+extern int diagnostic; /* telnet diagnostic capabilities */
+#endif /* DIAGNOSTICS */
+#ifdef BFTPDAEMON
+extern int bftpd; /* behave as bftp daemon */
+#endif /* BFTPDAEMON */
+#ifdef AUTHENTICATION
+extern int auth_level;
+#endif
+
+extern slcfun slctab[NSLC + 1]; /* slc mapping table */
+
+extern char *terminaltype;
+
+/*
+ * I/O data buffers, pointers, and counters.
+ */
+extern char ptyobuf[BUFSIZ+NETSLOP], *pfrontp, *pbackp;
+
+extern char netibuf[BUFSIZ], *netip;
+
+extern char netobuf[BUFSIZ], *nfrontp, *nbackp;
+extern char *neturg; /* one past last bye of urgent data */
+
+extern int pcc, ncc;
+
+extern int mpty, spty, net;
+extern char line[16];
+extern int SYNCHing; /* we are in TELNET SYNCH mode */
+
+extern void
+ _termstat(void),
+ add_slc(char, char, cc_t),
+ check_slc(void),
+ change_slc(char, char, cc_t),
+ cleanup(int),
+ clientstat(int, int, int),
+ copy_termbuf(char *, size_t),
+ deferslc(void),
+ defer_terminit(void),
+ do_opt_slc(unsigned char *, int),
+ doeof(void),
+ dooption(int),
+ dontoption(int),
+ edithost(char *, char *),
+ fatal(int, const char *),
+ fatalperror(int, const char *),
+ get_slc_defaults(void),
+ init_env(void),
+ init_termbuf(void),
+ interrupt(void),
+ localstat(void),
+ flowstat(void),
+ netclear(void),
+ netflush(void),
+#ifdef DIAGNOSTICS
+ printoption(const char *, int),
+ printdata(const char *, char *, int),
+ printsub(char, unsigned char *, int),
+#endif
+ process_slc(unsigned char, unsigned char, cc_t),
+ ptyflush(void),
+ putchr(int),
+ putf(char *, char *),
+ recv_ayt(void),
+ send_do(int, int),
+ send_dont(int, int),
+ send_slc(void),
+ send_status(void),
+ send_will(int, int),
+ send_wont(int, int),
+ sendbrk(void),
+ sendsusp(void),
+ set_termbuf(void),
+ start_login(char *, int, char *),
+ start_slc(int),
+#ifdef AUTHENTICATION
+ start_slave(char *),
+#else
+ start_slave(char *, int, char *),
+#endif
+ suboption(void),
+ telrcv(void),
+ ttloop(void),
+ tty_binaryin(int),
+ tty_binaryout(int);
+
+extern int
+ end_slc(unsigned char **),
+ getnpty(void),
+#ifndef convex
+ getpty(int *, int *),
+#endif
+ login_tty(int),
+ spcset(int, cc_t *, cc_t **),
+ stilloob(int),
+ terminit(void),
+ termstat(void),
+ tty_flowmode(void),
+ tty_restartany(void),
+ tty_isbinaryin(void),
+ tty_isbinaryout(void),
+ tty_iscrnl(void),
+ tty_isecho(void),
+ tty_isediting(void),
+ tty_islitecho(void),
+ tty_isnewmap(void),
+ tty_israw(void),
+ tty_issofttab(void),
+ tty_istrapsig(void),
+ tty_linemode(void);
+
+extern void
+ tty_rspeed(int),
+ tty_setecho(int),
+ tty_setedit(int),
+ tty_setlinemode(int),
+ tty_setlitecho(int),
+ tty_setsig(int),
+ tty_setsofttab(int),
+ tty_tspeed(int),
+ willoption(int),
+ wontoption(int);
+
+int output_data(const char *, ...) __printflike(1, 2);
+void output_datalen(const char *, int);
+void startslave(char *, int, char *);
+
+#ifdef ENCRYPTION
+extern void (*encrypt_output)(unsigned char *, int);
+extern int (*decrypt_input)(int);
+extern char *nclearto;
+#endif /* ENCRYPTION */
+
+
+/*
+ * The following are some clocks used to decide how to interpret
+ * the relationship between various variables.
+ */
+
+extern struct {
+ int
+ system, /* what the current time is */
+ echotoggle, /* last time user entered echo character */
+ modenegotiated, /* last time operating mode negotiated */
+ didnetreceive, /* last time we read data from network */
+ ttypesubopt, /* ttype subopt is received */
+ tspeedsubopt, /* tspeed subopt is received */
+ environsubopt, /* environ subopt is received */
+ oenvironsubopt, /* old environ subopt is received */
+ xdisplocsubopt, /* xdisploc subopt is received */
+ baseline, /* time started to do timed action */
+ gotDM; /* when did we last see a data mark */
+} clocks;
+
+#ifndef DEFAULT_IM
+#ifdef __APPLE__
+# define DEFAULT_IM "\r\n\r\nFreeBSD (%h) (%t)\r\n\r\r\n\r"
+#else
+# ifdef ultrix
+# define DEFAULT_IM "\r\n\r\nULTRIX (%h) (%t)\r\n\r\r\n\r"
+# else
+# ifdef __FreeBSD__
+# define DEFAULT_IM "\r\n\r\nFreeBSD (%h) (%t)\r\n\r\r\n\r"
+# else
+# define DEFAULT_IM "\r\n\r\n4.4 BSD UNIX (%h) (%t)\r\n\r\r\n\r"
+# endif
+# endif
+#endif /* __APPLE__ */
+#endif
diff --git a/remote_cmds/telnetd.tproj/global.c b/remote_cmds/telnetd.tproj/global.c
new file mode 100644
index 0000000..eefd129
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/global.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)global.c 8.1 (Berkeley) 6/4/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/global.c,v 1.6 2003/05/04 02:54:49 obrien Exp $");
+
+/*
+ * Allocate global variables. We do this
+ * by including the header file that defines
+ * them all as externs, but first we define
+ * the keyword "extern" to be nothing, so that
+ * we will actually allocate the space.
+ */
+
+#include "defs.h"
+#define extern
+#include "ext.h"
diff --git a/remote_cmds/telnetd.tproj/pathnames.h b/remote_cmds/telnetd.tproj/pathnames.h
new file mode 100644
index 0000000..43fce7e
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/pathnames.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/contrib/telnet/telnetd/pathnames.h,v 1.3 2001/08/20 12:28:40 markm Exp $
+ */
+
+#if BSD > 43
+
+# include <paths.h>
+
+# ifndef _PATH_LOGIN
+# define _PATH_LOGIN "/usr/bin/login"
+# endif
+
+#else
+
+# define _PATH_TTY "/dev/tty"
+# ifndef _PATH_LOGIN
+# define _PATH_LOGIN "/bin/login"
+# endif
+
+#endif
+
+#ifdef BFTPDAEMON
+#define BFTPPATH "/usr/ucb/bftp"
+#endif /* BFTPDAEMON */
diff --git a/remote_cmds/telnetd.tproj/slc.c b/remote_cmds/telnetd.tproj/slc.c
new file mode 100644
index 0000000..eb31ef8
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/slc.c
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)slc.c 8.2 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/slc.c,v 1.9 2003/05/04 02:54:49 obrien Exp $");
+
+#include "telnetd.h"
+
+#ifdef LINEMODE
+/*
+ * local variables
+ */
+static unsigned char *def_slcbuf = (unsigned char *)0;
+static int def_slclen = 0;
+static int slcchange; /* change to slc is requested */
+static unsigned char *slcptr; /* pointer into slc buffer */
+static unsigned char slcbuf[NSLC*6]; /* buffer for slc negotiation */
+
+/*
+ * send_slc
+ *
+ * Write out the current special characters to the client.
+ */
+void
+send_slc(void)
+{
+ int i;
+
+ /*
+ * Send out list of triplets of special characters
+ * to client. We only send info on the characters
+ * that are currently supported.
+ */
+ for (i = 1; i <= NSLC; i++) {
+ if ((slctab[i].defset.flag & SLC_LEVELBITS) == SLC_NOSUPPORT)
+ continue;
+ add_slc((unsigned char)i, slctab[i].current.flag,
+ slctab[i].current.val);
+ }
+
+} /* end of send_slc */
+
+/*
+ * default_slc
+ *
+ * Set pty special characters to all the defaults.
+ */
+static void
+default_slc(void)
+{
+ int i;
+
+ for (i = 1; i <= NSLC; i++) {
+ slctab[i].current.val = slctab[i].defset.val;
+ if (slctab[i].current.val == (cc_t)(_POSIX_VDISABLE))
+ slctab[i].current.flag = SLC_NOSUPPORT;
+ else
+ slctab[i].current.flag = slctab[i].defset.flag;
+ if (slctab[i].sptr) {
+ *(slctab[i].sptr) = slctab[i].defset.val;
+ }
+ }
+ slcchange = 1;
+
+} /* end of default_slc */
+#endif /* LINEMODE */
+
+/*
+ * get_slc_defaults
+ *
+ * Initialize the slc mapping table.
+ */
+void
+get_slc_defaults(void)
+{
+ int i;
+
+ init_termbuf();
+
+ for (i = 1; i <= NSLC; i++) {
+ slctab[i].defset.flag =
+ spcset(i, &slctab[i].defset.val, &slctab[i].sptr);
+ slctab[i].current.flag = SLC_NOSUPPORT;
+ slctab[i].current.val = 0;
+ }
+
+} /* end of get_slc_defaults */
+
+#ifdef LINEMODE
+/*
+ * add_slc
+ *
+ * Add an slc triplet to the slc buffer.
+ */
+void
+add_slc(char func, char flag, cc_t val)
+{
+
+ if ((*slcptr++ = (unsigned char)func) == 0xff)
+ *slcptr++ = 0xff;
+
+ if ((*slcptr++ = (unsigned char)flag) == 0xff)
+ *slcptr++ = 0xff;
+
+ if ((*slcptr++ = (unsigned char)val) == 0xff)
+ *slcptr++ = 0xff;
+
+} /* end of add_slc */
+
+/*
+ * start_slc
+ *
+ * Get ready to process incoming slc's and respond to them.
+ *
+ * The parameter getit is non-zero if it is necessary to grab a copy
+ * of the terminal control structures.
+ */
+void
+start_slc(int getit)
+{
+
+ slcchange = 0;
+ if (getit)
+ init_termbuf();
+ (void) sprintf((char *)slcbuf, "%c%c%c%c",
+ IAC, SB, TELOPT_LINEMODE, LM_SLC);
+ slcptr = slcbuf + 4;
+
+} /* end of start_slc */
+
+/*
+ * end_slc
+ *
+ * Finish up the slc negotiation. If something to send, then send it.
+ */
+int
+end_slc(unsigned char **bufp)
+{
+ int len;
+
+ /*
+ * If a change has occured, store the new terminal control
+ * structures back to the terminal driver.
+ */
+ if (slcchange) {
+ set_termbuf();
+ }
+
+ /*
+ * If the pty state has not yet been fully processed and there is a
+ * deferred slc request from the client, then do not send any
+ * sort of slc negotiation now. We will respond to the client's
+ * request very soon.
+ */
+ if (def_slcbuf && (terminit() == 0)) {
+ return(0);
+ }
+
+ if (slcptr > (slcbuf + 4)) {
+ if (bufp) {
+ *bufp = &slcbuf[4];
+ return(slcptr - slcbuf - 4);
+ } else {
+ (void) sprintf((char *)slcptr, "%c%c", IAC, SE);
+ slcptr += 2;
+ len = slcptr - slcbuf;
+ output_datalen((const char*)slcbuf, len);
+ netflush(); /* force it out immediately */
+ DIAG(TD_OPTIONS, printsub('>', slcbuf+2, len-2););
+ }
+ }
+ return (0);
+
+} /* end of end_slc */
+
+/*
+ * process_slc
+ *
+ * Figure out what to do about the client's slc
+ */
+void
+process_slc(unsigned char func, unsigned char flag, cc_t val)
+{
+ int hislevel, mylevel, ack;
+
+ /*
+ * Ensure that we know something about this function
+ */
+ if (func > NSLC) {
+ add_slc(func, SLC_NOSUPPORT, 0);
+ return;
+ }
+
+ /*
+ * Process the special case requests of 0 SLC_DEFAULT 0
+ * and 0 SLC_VARIABLE 0. Be a little forgiving here, don't
+ * worry about whether the value is actually 0 or not.
+ */
+ if (func == 0) {
+ if ((flag = flag & SLC_LEVELBITS) == SLC_DEFAULT) {
+ default_slc();
+ send_slc();
+ } else if (flag == SLC_VARIABLE) {
+ send_slc();
+ }
+ return;
+ }
+
+ /*
+ * Appears to be a function that we know something about. So
+ * get on with it and see what we know.
+ */
+
+ hislevel = flag & SLC_LEVELBITS;
+ mylevel = slctab[func].current.flag & SLC_LEVELBITS;
+ ack = flag & SLC_ACK;
+ /*
+ * ignore the command if:
+ * the function value and level are the same as what we already have;
+ * or the level is the same and the ack bit is set
+ */
+ if (hislevel == mylevel && (val == slctab[func].current.val || ack)) {
+ return;
+ } else if (ack) {
+ /*
+ * If we get here, we got an ack, but the levels don't match.
+ * This shouldn't happen. If it does, it is probably because
+ * we have sent two requests to set a variable without getting
+ * a response between them, and this is the first response.
+ * So, ignore it, and wait for the next response.
+ */
+ return;
+ } else {
+ change_slc(func, flag, val);
+ }
+
+} /* end of process_slc */
+
+/*
+ * change_slc
+ *
+ * Process a request to change one of our special characters.
+ * Compare client's request with what we are capable of supporting.
+ */
+void
+change_slc(char func, char flag, cc_t val)
+{
+ int hislevel, mylevel;
+
+ hislevel = flag & SLC_LEVELBITS;
+ mylevel = slctab[(int)func].defset.flag & SLC_LEVELBITS;
+ /*
+ * If client is setting a function to NOSUPPORT
+ * or DEFAULT, then we can easily and directly
+ * accomodate the request.
+ */
+ if (hislevel == SLC_NOSUPPORT) {
+ slctab[(int)func].current.flag = flag;
+ slctab[(int)func].current.val = (cc_t)_POSIX_VDISABLE;
+ flag |= SLC_ACK;
+ add_slc(func, flag, val);
+ return;
+ }
+ if (hislevel == SLC_DEFAULT) {
+ /*
+ * Special case here. If client tells us to use
+ * the default on a function we don't support, then
+ * return NOSUPPORT instead of what we may have as a
+ * default level of DEFAULT.
+ */
+ if (mylevel == SLC_DEFAULT) {
+ slctab[(int)func].current.flag = SLC_NOSUPPORT;
+ } else {
+ slctab[(int)func].current.flag = slctab[(int)func].defset.flag;
+ }
+ slctab[(int)func].current.val = slctab[(int)func].defset.val;
+ add_slc(func, slctab[(int)func].current.flag,
+ slctab[(int)func].current.val);
+ return;
+ }
+
+ /*
+ * Client wants us to change to a new value or he
+ * is telling us that he can't change to our value.
+ * Some of the slc's we support and can change,
+ * some we do support but can't change,
+ * and others we don't support at all.
+ * If we can change it then we have a pointer to
+ * the place to put the new value, so change it,
+ * otherwise, continue the negotiation.
+ */
+ if (slctab[(int)func].sptr) {
+ /*
+ * We can change this one.
+ */
+ slctab[(int)func].current.val = val;
+ *(slctab[(int)func].sptr) = val;
+ slctab[(int)func].current.flag = flag;
+ flag |= SLC_ACK;
+ slcchange = 1;
+ add_slc(func, flag, val);
+ } else {
+ /*
+ * It is not possible for us to support this
+ * request as he asks.
+ *
+ * If our level is DEFAULT, then just ack whatever was
+ * sent.
+ *
+ * If he can't change and we can't change,
+ * then degenerate to NOSUPPORT.
+ *
+ * Otherwise we send our level back to him, (CANTCHANGE
+ * or NOSUPPORT) and if CANTCHANGE, send
+ * our value as well.
+ */
+ if (mylevel == SLC_DEFAULT) {
+ slctab[(int)func].current.flag = flag;
+ slctab[(int)func].current.val = val;
+ flag |= SLC_ACK;
+ } else if (hislevel == SLC_CANTCHANGE &&
+ mylevel == SLC_CANTCHANGE) {
+ flag &= ~SLC_LEVELBITS;
+ flag |= SLC_NOSUPPORT;
+ slctab[(int)func].current.flag = flag;
+ } else {
+ flag &= ~SLC_LEVELBITS;
+ flag |= mylevel;
+ slctab[(int)func].current.flag = flag;
+ if (mylevel == SLC_CANTCHANGE) {
+ slctab[(int)func].current.val =
+ slctab[(int)func].defset.val;
+ val = slctab[(int)func].current.val;
+ }
+ }
+ add_slc(func, flag, val);
+ }
+
+} /* end of change_slc */
+
+#if defined(USE_TERMIO) && (VEOF == VMIN)
+cc_t oldeofc = '\004';
+#endif
+
+/*
+ * check_slc
+ *
+ * Check the special characters in use and notify the client if any have
+ * changed. Only those characters that are capable of being changed are
+ * likely to have changed. If a local change occurs, kick the support level
+ * and flags up to the defaults.
+ */
+void
+check_slc(void)
+{
+ int i;
+
+ for (i = 1; i <= NSLC; i++) {
+#if defined(USE_TERMIO) && (VEOF == VMIN)
+ /*
+ * In a perfect world this would be a neat little
+ * function. But in this world, we should not notify
+ * client of changes to the VEOF char when
+ * ICANON is off, because it is not representing
+ * a special character.
+ */
+ if (i == SLC_EOF) {
+ if (!tty_isediting())
+ continue;
+ else if (slctab[i].sptr)
+ oldeofc = *(slctab[i].sptr);
+ }
+#endif /* defined(USE_TERMIO) && defined(SYSV_TERMIO) */
+ if (slctab[i].sptr &&
+ (*(slctab[i].sptr) != slctab[i].current.val)) {
+ slctab[i].current.val = *(slctab[i].sptr);
+ if (*(slctab[i].sptr) == (cc_t)_POSIX_VDISABLE)
+ slctab[i].current.flag = SLC_NOSUPPORT;
+ else
+ slctab[i].current.flag = slctab[i].defset.flag;
+ add_slc((unsigned char)i, slctab[i].current.flag,
+ slctab[i].current.val);
+ }
+ }
+} /* check_slc */
+
+/*
+ * do_opt_slc
+ *
+ * Process an slc option buffer. Defer processing of incoming slc's
+ * until after the terminal state has been processed. Save the first slc
+ * request that comes along, but discard all others.
+ *
+ * ptr points to the beginning of the buffer, len is the length.
+ */
+void
+do_opt_slc(unsigned char *ptr, int len)
+{
+ unsigned char func, flag;
+ cc_t val;
+ unsigned char *end = ptr + len;
+
+ if (terminit()) { /* go ahead */
+ while (ptr < end) {
+ func = *ptr++;
+ if (ptr >= end) break;
+ flag = *ptr++;
+ if (ptr >= end) break;
+ val = (cc_t)*ptr++;
+
+ process_slc(func, flag, val);
+
+ }
+ } else {
+ /*
+ * save this slc buffer if it is the first, otherwise dump
+ * it.
+ */
+ if (def_slcbuf == (unsigned char *)0) {
+ def_slclen = len;
+ def_slcbuf = (unsigned char *)malloc((unsigned)len);
+ if (def_slcbuf == (unsigned char *)0)
+ return; /* too bad */
+ memmove(def_slcbuf, ptr, len);
+ }
+ }
+
+} /* end of do_opt_slc */
+
+/*
+ * deferslc
+ *
+ * Do slc stuff that was deferred.
+ */
+void
+deferslc(void)
+{
+ if (def_slcbuf) {
+ start_slc(1);
+ do_opt_slc(def_slcbuf, def_slclen);
+ (void) end_slc(0);
+ free(def_slcbuf);
+ def_slcbuf = (unsigned char *)0;
+ def_slclen = 0;
+ }
+
+} /* end of deferslc */
+
+#endif /* LINEMODE */
diff --git a/remote_cmds/telnetd.tproj/state.c b/remote_cmds/telnetd.tproj/state.c
new file mode 100644
index 0000000..a4dc138
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/state.c
@@ -0,0 +1,1631 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/state.c,v 1.14 2003/05/04 02:54:49 obrien Exp $");
+
+#include <stdarg.h>
+#include "telnetd.h"
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+unsigned char doopt[] = { IAC, DO, '%', 'c', 0 };
+unsigned char dont[] = { IAC, DONT, '%', 'c', 0 };
+unsigned char will[] = { IAC, WILL, '%', 'c', 0 };
+unsigned char wont[] = { IAC, WONT, '%', 'c', 0 };
+int not42 = 1;
+
+/*
+ * Buffer for sub-options, and macros
+ * for suboptions buffer manipulations
+ */
+unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
+
+#define SB_CLEAR() subpointer = subbuffer
+#define SB_TERM() { subend = subpointer; SB_CLEAR(); }
+#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
+ *subpointer++ = (c); \
+ }
+#define SB_GET() ((*subpointer++)&0xff)
+#define SB_EOF() (subpointer >= subend)
+#define SB_LEN() (subend - subpointer)
+
+#ifdef ENV_HACK
+unsigned char *subsave;
+#define SB_SAVE() subsave = subpointer;
+#define SB_RESTORE() subpointer = subsave;
+#endif
+
+
+/*
+ * State for recv fsm
+ */
+#define TS_DATA 0 /* base state */
+#define TS_IAC 1 /* look for double IAC's */
+#define TS_CR 2 /* CR-LF ->'s CR */
+#define TS_SB 3 /* throw away begin's... */
+#define TS_SE 4 /* ...end's (suboption negotiation) */
+#define TS_WILL 5 /* will option negotiation */
+#define TS_WONT 6 /* wont " */
+#define TS_DO 7 /* do " */
+#define TS_DONT 8 /* dont " */
+
+static void doclientstat(void);
+
+void
+telrcv(void)
+{
+ int c;
+ static int state = TS_DATA;
+
+ while (ncc > 0) {
+ if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
+ break;
+ c = *netip++ & 0377, ncc--;
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ c = (*decrypt_input)(c);
+#endif /* ENCRYPTION */
+ switch (state) {
+
+ case TS_CR:
+ state = TS_DATA;
+ /* Strip off \n or \0 after a \r */
+ if ((c == 0) || (c == '\n')) {
+ break;
+ }
+ /* FALLTHROUGH */
+
+ case TS_DATA:
+ if (c == IAC) {
+ state = TS_IAC;
+ break;
+ }
+ /*
+ * We now map \r\n ==> \r for pragmatic reasons.
+ * Many client implementations send \r\n when
+ * the user hits the CarriageReturn key.
+ *
+ * We USED to map \r\n ==> \n, since \r\n says
+ * that we want to be in column 1 of the next
+ * printable line, and \n is the standard
+ * unix way of saying that (\r is only good
+ * if CRMOD is set, which it normally is).
+ */
+ if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
+ int nc = *netip;
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ nc = (*decrypt_input)(nc & 0xff);
+#endif /* ENCRYPTION */
+#ifdef LINEMODE
+ /*
+ * If we are operating in linemode,
+ * convert to local end-of-line.
+ */
+ if (linemode && (ncc > 0) && (('\n' == nc) ||
+ ((0 == nc) && tty_iscrnl())) ) {
+ netip++; ncc--;
+ c = '\n';
+ } else
+#endif
+ {
+#ifdef ENCRYPTION
+ if (decrypt_input)
+ (void)(*decrypt_input)(-1);
+#endif /* ENCRYPTION */
+ state = TS_CR;
+ }
+ }
+ *pfrontp++ = c;
+ break;
+
+ case TS_IAC:
+gotiac: switch (c) {
+
+ /*
+ * Send the process on the pty side an
+ * interrupt. Do this with a NULL or
+ * interrupt char; depending on the tty mode.
+ */
+ case IP:
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ interrupt();
+ break;
+
+ case BREAK:
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ sendbrk();
+ break;
+
+ /*
+ * Are You There?
+ */
+ case AYT:
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ recv_ayt();
+ break;
+
+ /*
+ * Abort Output
+ */
+ case AO:
+ {
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ ptyflush(); /* half-hearted */
+ init_termbuf();
+
+ if (slctab[SLC_AO].sptr &&
+ *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
+ *pfrontp++ =
+ (unsigned char)*slctab[SLC_AO].sptr;
+ }
+
+ netclear(); /* clear buffer back */
+ output_data("%c%c", IAC, DM);
+ neturg = nfrontp-1; /* off by one XXX */
+ DIAG(TD_OPTIONS,
+ printoption("td: send IAC", DM));
+ break;
+ }
+
+ /*
+ * Erase Character and
+ * Erase Line
+ */
+ case EC:
+ case EL:
+ {
+ cc_t ch;
+
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ ptyflush(); /* half-hearted */
+ init_termbuf();
+ if (c == EC)
+ ch = *slctab[SLC_EC].sptr;
+ else
+ ch = *slctab[SLC_EL].sptr;
+ if (ch != (cc_t)(_POSIX_VDISABLE))
+ *pfrontp++ = (unsigned char)ch;
+ break;
+ }
+
+ /*
+ * Check for urgent data...
+ */
+ case DM:
+ DIAG(TD_OPTIONS,
+ printoption("td: recv IAC", c));
+ SYNCHing = stilloob(net);
+ settimer(gotDM);
+ break;
+
+
+ /*
+ * Begin option subnegotiation...
+ */
+ case SB:
+ state = TS_SB;
+ SB_CLEAR();
+ continue;
+
+ case WILL:
+ state = TS_WILL;
+ continue;
+
+ case WONT:
+ state = TS_WONT;
+ continue;
+
+ case DO:
+ state = TS_DO;
+ continue;
+
+ case DONT:
+ state = TS_DONT;
+ continue;
+ case EOR:
+ if (his_state_is_will(TELOPT_EOR))
+ doeof();
+ break;
+
+ /*
+ * Handle RFC 10xx Telnet linemode option additions
+ * to command stream (EOF, SUSP, ABORT).
+ */
+ case xEOF:
+ doeof();
+ break;
+
+ case SUSP:
+ sendsusp();
+ break;
+
+ case ABORT:
+ sendbrk();
+ break;
+
+ case IAC:
+ *pfrontp++ = c;
+ break;
+ }
+ state = TS_DATA;
+ break;
+
+ case TS_SB:
+ if (c == IAC) {
+ state = TS_SE;
+ } else {
+ SB_ACCUM(c);
+ }
+ break;
+
+ case TS_SE:
+ if (c != SE) {
+ if (c != IAC) {
+ /*
+ * bad form of suboption negotiation.
+ * handle it in such a way as to avoid
+ * damage to local state. Parse
+ * suboption buffer found so far,
+ * then treat remaining stream as
+ * another command sequence.
+ */
+
+ /* for DIAGNOSTICS */
+ SB_ACCUM(IAC);
+ SB_ACCUM(c);
+ subpointer -= 2;
+
+ SB_TERM();
+ suboption();
+ state = TS_IAC;
+ goto gotiac;
+ }
+ SB_ACCUM(c);
+ state = TS_SB;
+ } else {
+ /* for DIAGNOSTICS */
+ SB_ACCUM(IAC);
+ SB_ACCUM(SE);
+ subpointer -= 2;
+
+ SB_TERM();
+ suboption(); /* handle sub-option */
+ state = TS_DATA;
+ }
+ break;
+
+ case TS_WILL:
+ willoption(c);
+ state = TS_DATA;
+ continue;
+
+ case TS_WONT:
+ wontoption(c);
+ state = TS_DATA;
+ continue;
+
+ case TS_DO:
+ dooption(c);
+ state = TS_DATA;
+ continue;
+
+ case TS_DONT:
+ dontoption(c);
+ state = TS_DATA;
+ continue;
+
+ default:
+ syslog(LOG_ERR, "panic state=%d", state);
+ printf("telnetd: panic state=%d\n", state);
+ exit(1);
+ }
+ }
+} /* end of telrcv */
+
+/*
+ * The will/wont/do/dont state machines are based on Dave Borman's
+ * Telnet option processing state machine.
+ *
+ * These correspond to the following states:
+ * my_state = the last negotiated state
+ * want_state = what I want the state to go to
+ * want_resp = how many requests I have sent
+ * All state defaults are negative, and resp defaults to 0.
+ *
+ * When initiating a request to change state to new_state:
+ *
+ * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
+ * do nothing;
+ * } else {
+ * want_state = new_state;
+ * send new_state;
+ * want_resp++;
+ * }
+ *
+ * When receiving new_state:
+ *
+ * if (want_resp) {
+ * want_resp--;
+ * if (want_resp && (new_state == my_state))
+ * want_resp--;
+ * }
+ * if ((want_resp == 0) && (new_state != want_state)) {
+ * if (ok_to_switch_to new_state)
+ * want_state = new_state;
+ * else
+ * want_resp++;
+ * send want_state;
+ * }
+ * my_state = new_state;
+ *
+ * Note that new_state is implied in these functions by the function itself.
+ * will and do imply positive new_state, wont and dont imply negative.
+ *
+ * Finally, there is one catch. If we send a negative response to a
+ * positive request, my_state will be the positive while want_state will
+ * remain negative. my_state will revert to negative when the negative
+ * acknowlegment arrives from the peer. Thus, my_state generally tells
+ * us not only the last negotiated state, but also tells us what the peer
+ * wants to be doing as well. It is important to understand this difference
+ * as we may wish to be processing data streams based on our desired state
+ * (want_state) or based on what the peer thinks the state is (my_state).
+ *
+ * This all works fine because if the peer sends a positive request, the data
+ * that we receive prior to negative acknowlegment will probably be affected
+ * by the positive state, and we can process it as such (if we can; if we
+ * can't then it really doesn't matter). If it is that important, then the
+ * peer probably should be buffering until this option state negotiation
+ * is complete.
+ *
+ */
+void
+send_do(int option, int init)
+{
+ if (init) {
+ if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
+ his_want_state_is_will(option))
+ return;
+ /*
+ * Special case for TELOPT_TM: We send a DO, but pretend
+ * that we sent a DONT, so that we can send more DOs if
+ * we want to.
+ */
+ if (option == TELOPT_TM)
+ set_his_want_state_wont(option);
+ else
+ set_his_want_state_will(option);
+ do_dont_resp[option]++;
+ }
+ output_data((const char *)doopt, option);
+
+ DIAG(TD_OPTIONS, printoption("td: send do", option));
+}
+
+void
+willoption(int option)
+{
+ int changeok = 0;
+ void (*func)(void) = 0;
+
+ /*
+ * process input from peer.
+ */
+
+ DIAG(TD_OPTIONS, printoption("td: recv will", option));
+
+ if (do_dont_resp[option]) {
+ do_dont_resp[option]--;
+ if (do_dont_resp[option] && his_state_is_will(option))
+ do_dont_resp[option]--;
+ }
+ if (do_dont_resp[option] == 0) {
+ if (his_want_state_is_wont(option)) {
+ switch (option) {
+
+ case TELOPT_BINARY:
+ init_termbuf();
+ tty_binaryin(1);
+ set_termbuf();
+ changeok++;
+ break;
+
+ case TELOPT_ECHO:
+ /*
+ * See comments below for more info.
+ */
+ not42 = 0; /* looks like a 4.2 system */
+ break;
+
+ case TELOPT_TM:
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ /*
+ * This telnetd implementation does not really
+ * support timing marks, it just uses them to
+ * support the kludge linemode stuff. If we
+ * receive a will or wont TM in response to our
+ * do TM request that may have been sent to
+ * determine kludge linemode support, process
+ * it, otherwise TM should get a negative
+ * response back.
+ */
+ /*
+ * Handle the linemode kludge stuff.
+ * If we are not currently supporting any
+ * linemode at all, then we assume that this
+ * is the client telling us to use kludge
+ * linemode in response to our query. Set the
+ * linemode type that is to be supported, note
+ * that the client wishes to use linemode, and
+ * eat the will TM as though it never arrived.
+ */
+ if (lmodetype < KLUDGE_LINEMODE) {
+ lmodetype = KLUDGE_LINEMODE;
+ clientstat(TELOPT_LINEMODE, WILL, 0);
+ send_wont(TELOPT_SGA, 1);
+ } else if (lmodetype == NO_AUTOKLUDGE) {
+ lmodetype = KLUDGE_OK;
+ }
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+ /*
+ * We never respond to a WILL TM, and
+ * we leave the state WONT.
+ */
+ return;
+
+ case TELOPT_LFLOW:
+ /*
+ * If we are going to support flow control
+ * option, then don't worry peer that we can't
+ * change the flow control characters.
+ */
+ slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
+ slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
+ slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
+ slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
+ case TELOPT_TTYPE:
+ case TELOPT_SGA:
+ case TELOPT_NAWS:
+ case TELOPT_TSPEED:
+ case TELOPT_XDISPLOC:
+ case TELOPT_NEW_ENVIRON:
+ case TELOPT_OLD_ENVIRON:
+ changeok++;
+ break;
+
+#ifdef LINEMODE
+ case TELOPT_LINEMODE:
+# ifdef KLUDGELINEMODE
+ /*
+ * Note client's desire to use linemode.
+ */
+ lmodetype = REAL_LINEMODE;
+# endif /* KLUDGELINEMODE */
+ func = doclientstat;
+ changeok++;
+ break;
+#endif /* LINEMODE */
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ func = auth_request;
+ changeok++;
+ break;
+#endif
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ func = encrypt_send_support;
+ changeok++;
+ break;
+#endif /* ENCRYPTION */
+
+ default:
+ break;
+ }
+ if (changeok) {
+ set_his_want_state_will(option);
+ send_do(option, 0);
+ } else {
+ do_dont_resp[option]++;
+ send_dont(option, 0);
+ }
+ } else {
+ /*
+ * Option processing that should happen when
+ * we receive conformation of a change in
+ * state that we had requested.
+ */
+ switch (option) {
+ case TELOPT_ECHO:
+ not42 = 0; /* looks like a 4.2 system */
+ /*
+ * Egads, he responded "WILL ECHO". Turn
+ * it off right now!
+ */
+ send_dont(option, 1);
+ /*
+ * "WILL ECHO". Kludge upon kludge!
+ * A 4.2 client is now echoing user input at
+ * the tty. This is probably undesireable and
+ * it should be stopped. The client will
+ * respond WONT TM to the DO TM that we send to
+ * check for kludge linemode. When the WONT TM
+ * arrives, linemode will be turned off and a
+ * change propogated to the pty. This change
+ * will cause us to process the new pty state
+ * in localstat(), which will notice that
+ * linemode is off and send a WILL ECHO
+ * so that we are properly in character mode and
+ * all is well.
+ */
+ break;
+#ifdef LINEMODE
+ case TELOPT_LINEMODE:
+# ifdef KLUDGELINEMODE
+ /*
+ * Note client's desire to use linemode.
+ */
+ lmodetype = REAL_LINEMODE;
+# endif /* KLUDGELINEMODE */
+ func = doclientstat;
+ break;
+#endif /* LINEMODE */
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ func = auth_request;
+ break;
+#endif
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ func = encrypt_send_support;
+ break;
+#endif /* ENCRYPTION */
+ case TELOPT_LFLOW:
+ func = flowstat;
+ break;
+ }
+ }
+ }
+ set_his_state_will(option);
+ if (func)
+ (*func)();
+} /* end of willoption */
+
+void
+send_dont(int option, int init)
+{
+ if (init) {
+ if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
+ his_want_state_is_wont(option))
+ return;
+ set_his_want_state_wont(option);
+ do_dont_resp[option]++;
+ }
+ output_data((const char *)dont, option);
+
+ DIAG(TD_OPTIONS, printoption("td: send dont", option));
+}
+
+void
+wontoption(int option)
+{
+ /*
+ * Process client input.
+ */
+
+ DIAG(TD_OPTIONS, printoption("td: recv wont", option));
+
+ if (do_dont_resp[option]) {
+ do_dont_resp[option]--;
+ if (do_dont_resp[option] && his_state_is_wont(option))
+ do_dont_resp[option]--;
+ }
+ if (do_dont_resp[option] == 0) {
+ if (his_want_state_is_will(option)) {
+ /* it is always ok to change to negative state */
+ switch (option) {
+ case TELOPT_ECHO:
+ not42 = 1; /* doesn't seem to be a 4.2 system */
+ break;
+
+ case TELOPT_BINARY:
+ init_termbuf();
+ tty_binaryin(0);
+ set_termbuf();
+ break;
+
+#ifdef LINEMODE
+ case TELOPT_LINEMODE:
+# ifdef KLUDGELINEMODE
+ /*
+ * If real linemode is supported, then client is
+ * asking to turn linemode off.
+ */
+ if (lmodetype != REAL_LINEMODE)
+ break;
+ lmodetype = KLUDGE_LINEMODE;
+# endif /* KLUDGELINEMODE */
+ clientstat(TELOPT_LINEMODE, WONT, 0);
+ break;
+#endif /* LINEMODE */
+
+ case TELOPT_TM:
+ /*
+ * If we get a WONT TM, and had sent a DO TM,
+ * don't respond with a DONT TM, just leave it
+ * as is. Short circut the state machine to
+ * achive this.
+ */
+ set_his_want_state_wont(TELOPT_TM);
+ return;
+
+ case TELOPT_LFLOW:
+ /*
+ * If we are not going to support flow control
+ * option, then let peer know that we can't
+ * change the flow control characters.
+ */
+ slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
+ slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
+ slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
+ slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ auth_finished(0, AUTH_REJECT);
+ break;
+#endif
+
+ /*
+ * For options that we might spin waiting for
+ * sub-negotiation, if the client turns off the
+ * option rather than responding to the request,
+ * we have to treat it here as if we got a response
+ * to the sub-negotiation, (by updating the timers)
+ * so that we'll break out of the loop.
+ */
+ case TELOPT_TTYPE:
+ settimer(ttypesubopt);
+ break;
+
+ case TELOPT_TSPEED:
+ settimer(tspeedsubopt);
+ break;
+
+ case TELOPT_XDISPLOC:
+ settimer(xdisplocsubopt);
+ break;
+
+ case TELOPT_OLD_ENVIRON:
+ settimer(oenvironsubopt);
+ break;
+
+ case TELOPT_NEW_ENVIRON:
+ settimer(environsubopt);
+ break;
+
+ default:
+ break;
+ }
+ set_his_want_state_wont(option);
+ if (his_state_is_will(option))
+ send_dont(option, 0);
+ } else {
+ switch (option) {
+ case TELOPT_TM:
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ if (lmodetype < NO_AUTOKLUDGE) {
+ lmodetype = NO_LINEMODE;
+ clientstat(TELOPT_LINEMODE, WONT, 0);
+ send_will(TELOPT_SGA, 1);
+ send_will(TELOPT_ECHO, 1);
+ }
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ auth_finished(0, AUTH_REJECT);
+ break;
+#endif
+ default:
+ break;
+ }
+ }
+ }
+ set_his_state_wont(option);
+
+} /* end of wontoption */
+
+void
+send_will(int option, int init)
+{
+ if (init) {
+ if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
+ my_want_state_is_will(option))
+ return;
+ set_my_want_state_will(option);
+ will_wont_resp[option]++;
+ }
+ output_data((const char *)will, option);
+
+ DIAG(TD_OPTIONS, printoption("td: send will", option));
+}
+
+#if !defined(LINEMODE) || !defined(KLUDGELINEMODE)
+/*
+ * When we get a DONT SGA, we will try once to turn it
+ * back on. If the other side responds DONT SGA, we
+ * leave it at that. This is so that when we talk to
+ * clients that understand KLUDGELINEMODE but not LINEMODE,
+ * we'll keep them in char-at-a-time mode.
+ */
+int turn_on_sga = 0;
+#endif
+
+void
+dooption(int option)
+{
+ int changeok = 0;
+
+ /*
+ * Process client input.
+ */
+
+ DIAG(TD_OPTIONS, printoption("td: recv do", option));
+
+ if (will_wont_resp[option]) {
+ will_wont_resp[option]--;
+ if (will_wont_resp[option] && my_state_is_will(option))
+ will_wont_resp[option]--;
+ }
+ if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
+ switch (option) {
+ case TELOPT_ECHO:
+#ifdef LINEMODE
+# ifdef KLUDGELINEMODE
+ if (lmodetype == NO_LINEMODE)
+# else
+ if (his_state_is_wont(TELOPT_LINEMODE))
+# endif
+#endif
+ {
+ init_termbuf();
+ tty_setecho(1);
+ set_termbuf();
+ }
+ changeok++;
+ break;
+
+ case TELOPT_BINARY:
+ init_termbuf();
+ tty_binaryout(1);
+ set_termbuf();
+ changeok++;
+ break;
+
+ case TELOPT_SGA:
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ /*
+ * If kludge linemode is in use, then we must
+ * process an incoming do SGA for linemode
+ * purposes.
+ */
+ if (lmodetype == KLUDGE_LINEMODE) {
+ /*
+ * Receipt of "do SGA" in kludge
+ * linemode is the peer asking us to
+ * turn off linemode. Make note of
+ * the request.
+ */
+ clientstat(TELOPT_LINEMODE, WONT, 0);
+ /*
+ * If linemode did not get turned off
+ * then don't tell peer that we did.
+ * Breaking here forces a wont SGA to
+ * be returned.
+ */
+ if (linemode)
+ break;
+ }
+#else
+ turn_on_sga = 0;
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+ changeok++;
+ break;
+
+ case TELOPT_STATUS:
+ changeok++;
+ break;
+
+ case TELOPT_TM:
+ /*
+ * Special case for TM. We send a WILL, but
+ * pretend we sent a WONT.
+ */
+ send_will(option, 0);
+ set_my_want_state_wont(option);
+ set_my_state_wont(option);
+ return;
+
+ case TELOPT_LOGOUT:
+ /*
+ * When we get a LOGOUT option, respond
+ * with a WILL LOGOUT, make sure that
+ * it gets written out to the network,
+ * and then just go away...
+ */
+ set_my_want_state_will(TELOPT_LOGOUT);
+ send_will(TELOPT_LOGOUT, 0);
+ set_my_state_will(TELOPT_LOGOUT);
+ (void)netflush();
+ cleanup(0);
+ /* NOT REACHED */
+ break;
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ changeok++;
+ break;
+#endif /* ENCRYPTION */
+ case TELOPT_LINEMODE:
+ case TELOPT_TTYPE:
+ case TELOPT_NAWS:
+ case TELOPT_TSPEED:
+ case TELOPT_LFLOW:
+ case TELOPT_XDISPLOC:
+#ifdef TELOPT_ENVIRON
+ case TELOPT_NEW_ENVIRON:
+#endif
+ case TELOPT_OLD_ENVIRON:
+ default:
+ break;
+ }
+ if (changeok) {
+ set_my_want_state_will(option);
+ send_will(option, 0);
+ } else {
+ will_wont_resp[option]++;
+ send_wont(option, 0);
+ }
+ }
+ set_my_state_will(option);
+
+} /* end of dooption */
+
+void
+send_wont(int option, int init)
+{
+ if (init) {
+ if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
+ my_want_state_is_wont(option))
+ return;
+ set_my_want_state_wont(option);
+ will_wont_resp[option]++;
+ }
+ output_data((const char *)wont, option);
+
+ DIAG(TD_OPTIONS, printoption("td: send wont", option));
+}
+
+void
+dontoption(int option)
+{
+ /*
+ * Process client input.
+ */
+
+
+ DIAG(TD_OPTIONS, printoption("td: recv dont", option));
+
+ if (will_wont_resp[option]) {
+ will_wont_resp[option]--;
+ if (will_wont_resp[option] && my_state_is_wont(option))
+ will_wont_resp[option]--;
+ }
+ if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
+ switch (option) {
+ case TELOPT_BINARY:
+ init_termbuf();
+ tty_binaryout(0);
+ set_termbuf();
+ break;
+
+ case TELOPT_ECHO: /* we should stop echoing */
+#ifdef LINEMODE
+# ifdef KLUDGELINEMODE
+ if ((lmodetype != REAL_LINEMODE) &&
+ (lmodetype != KLUDGE_LINEMODE))
+# else
+ if (his_state_is_wont(TELOPT_LINEMODE))
+# endif
+#endif
+ {
+ init_termbuf();
+ tty_setecho(0);
+ set_termbuf();
+ }
+ break;
+
+ case TELOPT_SGA:
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ /*
+ * If kludge linemode is in use, then we
+ * must process an incoming do SGA for
+ * linemode purposes.
+ */
+ if ((lmodetype == KLUDGE_LINEMODE) ||
+ (lmodetype == KLUDGE_OK)) {
+ /*
+ * The client is asking us to turn
+ * linemode on.
+ */
+ lmodetype = KLUDGE_LINEMODE;
+ clientstat(TELOPT_LINEMODE, WILL, 0);
+ /*
+ * If we did not turn line mode on,
+ * then what do we say? Will SGA?
+ * This violates design of telnet.
+ * Gross. Very Gross.
+ */
+ }
+ break;
+#else
+ set_my_want_state_wont(option);
+ if (my_state_is_will(option))
+ send_wont(option, 0);
+ set_my_state_wont(option);
+ if (turn_on_sga ^= 1)
+ send_will(option, 1);
+ return;
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+
+ default:
+ break;
+ }
+
+ set_my_want_state_wont(option);
+ if (my_state_is_will(option))
+ send_wont(option, 0);
+ }
+ set_my_state_wont(option);
+
+} /* end of dontoption */
+
+#ifdef ENV_HACK
+int env_ovar = -1;
+int env_ovalue = -1;
+#else /* ENV_HACK */
+# define env_ovar OLD_ENV_VAR
+# define env_ovalue OLD_ENV_VALUE
+#endif /* ENV_HACK */
+
+/*
+ * suboption()
+ *
+ * Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ *
+ * Currently we recognize:
+ *
+ * Terminal type is
+ * Linemode
+ * Window size
+ * Terminal speed
+ */
+void
+suboption(void)
+{
+ int subchar;
+
+ DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
+
+ subchar = SB_GET();
+ switch (subchar) {
+ case TELOPT_TSPEED: {
+ int xspeed, rspeed;
+
+ if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */
+ break;
+
+ settimer(tspeedsubopt);
+
+ if (SB_EOF() || SB_GET() != TELQUAL_IS)
+ return;
+
+ xspeed = atoi((char *)subpointer);
+
+ while (SB_GET() != ',' && !SB_EOF());
+ if (SB_EOF())
+ return;
+
+ rspeed = atoi((char *)subpointer);
+ clientstat(TELOPT_TSPEED, xspeed, rspeed);
+
+ break;
+
+ } /* end of case TELOPT_TSPEED */
+
+ case TELOPT_TTYPE: { /* Yaaaay! */
+ static char terminalname[41];
+
+ if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */
+ break;
+ settimer(ttypesubopt);
+
+ if (SB_EOF() || SB_GET() != TELQUAL_IS) {
+ return; /* ??? XXX but, this is the most robust */
+ }
+
+ terminaltype = terminalname;
+
+ while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
+ !SB_EOF()) {
+ int c;
+
+ c = SB_GET();
+ if (isupper(c)) {
+ c = tolower(c);
+ }
+ *terminaltype++ = c; /* accumulate name */
+ }
+ *terminaltype = 0;
+ terminaltype = terminalname;
+ break;
+ } /* end of case TELOPT_TTYPE */
+
+ case TELOPT_NAWS: {
+ int xwinsize, ywinsize;
+
+ if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */
+ break;
+
+ if (SB_EOF())
+ return;
+ xwinsize = SB_GET() << 8;
+ if (SB_EOF())
+ return;
+ xwinsize |= SB_GET();
+ if (SB_EOF())
+ return;
+ ywinsize = SB_GET() << 8;
+ if (SB_EOF())
+ return;
+ ywinsize |= SB_GET();
+ clientstat(TELOPT_NAWS, xwinsize, ywinsize);
+
+ break;
+
+ } /* end of case TELOPT_NAWS */
+
+#ifdef LINEMODE
+ case TELOPT_LINEMODE: {
+ int request;
+
+ if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */
+ break;
+ /*
+ * Process linemode suboptions.
+ */
+ if (SB_EOF())
+ break; /* garbage was sent */
+ request = SB_GET(); /* get will/wont */
+
+ if (SB_EOF())
+ break; /* another garbage check */
+
+ if (request == LM_SLC) { /* SLC is not preceded by WILL or WONT */
+ /*
+ * Process suboption buffer of slc's
+ */
+ start_slc(1);
+ do_opt_slc(subpointer, subend - subpointer);
+ (void) end_slc(0);
+ break;
+ } else if (request == LM_MODE) {
+ if (SB_EOF())
+ return;
+ useeditmode = SB_GET(); /* get mode flag */
+ clientstat(LM_MODE, 0, 0);
+ break;
+ }
+
+ if (SB_EOF())
+ break;
+ switch (SB_GET()) { /* what suboption? */
+ case LM_FORWARDMASK:
+ /*
+ * According to spec, only server can send request for
+ * forwardmask, and client can only return a positive response.
+ * So don't worry about it.
+ */
+
+ default:
+ break;
+ }
+ break;
+ } /* end of case TELOPT_LINEMODE */
+#endif
+ case TELOPT_STATUS: {
+ int mode;
+
+ if (SB_EOF())
+ break;
+ mode = SB_GET();
+ switch (mode) {
+ case TELQUAL_SEND:
+ if (my_state_is_will(TELOPT_STATUS))
+ send_status();
+ break;
+
+ case TELQUAL_IS:
+ break;
+
+ default:
+ break;
+ }
+ break;
+ } /* end of case TELOPT_STATUS */
+
+ case TELOPT_XDISPLOC: {
+ if (SB_EOF() || SB_GET() != TELQUAL_IS)
+ return;
+ settimer(xdisplocsubopt);
+ subpointer[SB_LEN()] = '\0';
+ (void)setenv("DISPLAY", (char *)subpointer, 1);
+ break;
+ } /* end of case TELOPT_XDISPLOC */
+
+#ifdef TELOPT_NEW_ENVIRON
+ case TELOPT_NEW_ENVIRON:
+#endif
+ case TELOPT_OLD_ENVIRON: {
+ int c;
+ char *cp, *varp, *valp;
+
+ if (SB_EOF())
+ return;
+ c = SB_GET();
+ if (c == TELQUAL_IS) {
+ if (subchar == TELOPT_OLD_ENVIRON)
+ settimer(oenvironsubopt);
+ else
+ settimer(environsubopt);
+ } else if (c != TELQUAL_INFO) {
+ return;
+ }
+
+#ifdef TELOPT_NEW_ENVIRON
+ if (subchar == TELOPT_NEW_ENVIRON) {
+ while (!SB_EOF()) {
+ c = SB_GET();
+ if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
+ break;
+ }
+ } else
+#endif
+ {
+#ifdef ENV_HACK
+ /*
+ * We only want to do this if we haven't already decided
+ * whether or not the other side has its VALUE and VAR
+ * reversed.
+ */
+ if (env_ovar < 0) {
+ int last = -1; /* invalid value */
+ int empty = 0;
+ int got_var = 0, got_value = 0, got_uservar = 0;
+
+ /*
+ * The other side might have its VALUE and VAR values
+ * reversed. To be interoperable, we need to determine
+ * which way it is. If the first recognized character
+ * is a VAR or VALUE, then that will tell us what
+ * type of client it is. If the fist recognized
+ * character is a USERVAR, then we continue scanning
+ * the suboption looking for two consecutive
+ * VAR or VALUE fields. We should not get two
+ * consecutive VALUE fields, so finding two
+ * consecutive VALUE or VAR fields will tell us
+ * what the client is.
+ */
+ SB_SAVE();
+ while (!SB_EOF()) {
+ c = SB_GET();
+ switch(c) {
+ case OLD_ENV_VAR:
+ if (last < 0 || last == OLD_ENV_VAR
+ || (empty && (last == OLD_ENV_VALUE)))
+ goto env_ovar_ok;
+ got_var++;
+ last = OLD_ENV_VAR;
+ break;
+ case OLD_ENV_VALUE:
+ if (last < 0 || last == OLD_ENV_VALUE
+ || (empty && (last == OLD_ENV_VAR)))
+ goto env_ovar_wrong;
+ got_value++;
+ last = OLD_ENV_VALUE;
+ break;
+ case ENV_USERVAR:
+ /* count strings of USERVAR as one */
+ if (last != ENV_USERVAR)
+ got_uservar++;
+ if (empty) {
+ if (last == OLD_ENV_VALUE)
+ goto env_ovar_ok;
+ if (last == OLD_ENV_VAR)
+ goto env_ovar_wrong;
+ }
+ last = ENV_USERVAR;
+ break;
+ case ENV_ESC:
+ if (!SB_EOF())
+ c = SB_GET();
+ /* FALLTHROUGH */
+ default:
+ empty = 0;
+ continue;
+ }
+ empty = 1;
+ }
+ if (empty) {
+ if (last == OLD_ENV_VALUE)
+ goto env_ovar_ok;
+ if (last == OLD_ENV_VAR)
+ goto env_ovar_wrong;
+ }
+ /*
+ * Ok, the first thing was a USERVAR, and there
+ * are not two consecutive VAR or VALUE commands,
+ * and none of the VAR or VALUE commands are empty.
+ * If the client has sent us a well-formed option,
+ * then the number of VALUEs received should always
+ * be less than or equal to the number of VARs and
+ * USERVARs received.
+ *
+ * If we got exactly as many VALUEs as VARs and
+ * USERVARs, the client has the same definitions.
+ *
+ * If we got exactly as many VARs as VALUEs and
+ * USERVARS, the client has reversed definitions.
+ */
+ if (got_uservar + got_var == got_value) {
+ env_ovar_ok:
+ env_ovar = OLD_ENV_VAR;
+ env_ovalue = OLD_ENV_VALUE;
+ } else if (got_uservar + got_value == got_var) {
+ env_ovar_wrong:
+ env_ovar = OLD_ENV_VALUE;
+ env_ovalue = OLD_ENV_VAR;
+ DIAG(TD_OPTIONS,
+ output_data("ENVIRON VALUE and VAR are reversed!\r\n"));
+
+ }
+ }
+ SB_RESTORE();
+#endif
+
+ while (!SB_EOF()) {
+ c = SB_GET();
+ if ((c == env_ovar) || (c == ENV_USERVAR))
+ break;
+ }
+ }
+
+ if (SB_EOF())
+ return;
+
+ cp = varp = (char *)subpointer;
+ valp = 0;
+
+ while (!SB_EOF()) {
+ c = SB_GET();
+ if (subchar == TELOPT_OLD_ENVIRON) {
+ if (c == env_ovar)
+ c = NEW_ENV_VAR;
+ else if (c == env_ovalue)
+ c = NEW_ENV_VALUE;
+ }
+ switch (c) {
+
+ case NEW_ENV_VALUE:
+ *cp = '\0';
+ cp = valp = (char *)subpointer;
+ break;
+
+ case NEW_ENV_VAR:
+ case ENV_USERVAR:
+ *cp = '\0';
+ if (valp)
+ (void)setenv(varp, valp, 1);
+ else
+ unsetenv(varp);
+ cp = varp = (char *)subpointer;
+ valp = 0;
+ break;
+
+ case ENV_ESC:
+ if (SB_EOF())
+ break;
+ c = SB_GET();
+ /* FALLTHROUGH */
+ default:
+ *cp++ = c;
+ break;
+ }
+ }
+ *cp = '\0';
+ if (valp)
+ (void)setenv(varp, valp, 1);
+ else
+ unsetenv(varp);
+ break;
+ } /* end of case TELOPT_NEW_ENVIRON */
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ if (SB_EOF())
+ break;
+ switch(SB_GET()) {
+ case TELQUAL_SEND:
+ case TELQUAL_REPLY:
+ /*
+ * These are sent by us and cannot be sent by
+ * the client.
+ */
+ break;
+ case TELQUAL_IS:
+ auth_is(subpointer, SB_LEN());
+ break;
+ case TELQUAL_NAME:
+ auth_name(subpointer, SB_LEN());
+ break;
+ }
+ break;
+#endif
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ if (SB_EOF())
+ break;
+ switch(SB_GET()) {
+ case ENCRYPT_SUPPORT:
+ encrypt_support(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_IS:
+ encrypt_is(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REPLY:
+ encrypt_reply(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_START:
+ encrypt_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_END:
+ encrypt_end();
+ break;
+ case ENCRYPT_REQSTART:
+ encrypt_request_start(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_REQEND:
+ /*
+ * We can always send an REQEND so that we cannot
+ * get stuck encrypting. We should only get this
+ * if we have been able to get in the correct mode
+ * anyhow.
+ */
+ encrypt_request_end();
+ break;
+ case ENCRYPT_ENC_KEYID:
+ encrypt_enc_keyid(subpointer, SB_LEN());
+ break;
+ case ENCRYPT_DEC_KEYID:
+ encrypt_dec_keyid(subpointer, SB_LEN());
+ break;
+ default:
+ break;
+ }
+ break;
+#endif /* ENCRYPTION */
+
+ default:
+ break;
+ } /* end of switch */
+
+} /* end of suboption */
+
+static void
+doclientstat(void)
+{
+ clientstat(TELOPT_LINEMODE, WILL, 0);
+}
+
+#define ADD(c) *ncp++ = c
+#define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
+void
+send_status(void)
+{
+ unsigned char statusbuf[256];
+ unsigned char *ncp;
+ unsigned char i;
+
+ ncp = statusbuf;
+
+ netflush(); /* get rid of anything waiting to go out */
+
+ ADD(IAC);
+ ADD(SB);
+ ADD(TELOPT_STATUS);
+ ADD(TELQUAL_IS);
+
+ /*
+ * We check the want_state rather than the current state,
+ * because if we received a DO/WILL for an option that we
+ * don't support, and the other side didn't send a DONT/WONT
+ * in response to our WONT/DONT, then the "state" will be
+ * WILL/DO, and the "want_state" will be WONT/DONT. We
+ * need to go by the latter.
+ */
+ for (i = 0; i < (unsigned char)NTELOPTS; i++) {
+ if (my_want_state_is_will(i)) {
+ ADD(WILL);
+ ADD_DATA(i);
+ if (i == IAC)
+ ADD(IAC);
+ }
+ if (his_want_state_is_will(i)) {
+ ADD(DO);
+ ADD_DATA(i);
+ if (i == IAC)
+ ADD(IAC);
+ }
+ }
+
+ if (his_want_state_is_will(TELOPT_LFLOW)) {
+ ADD(SB);
+ ADD(TELOPT_LFLOW);
+ if (flowmode) {
+ ADD(LFLOW_ON);
+ } else {
+ ADD(LFLOW_OFF);
+ }
+ ADD(SE);
+
+ if (restartany >= 0) {
+ ADD(SB);
+ ADD(TELOPT_LFLOW);
+ if (restartany) {
+ ADD(LFLOW_RESTART_ANY);
+ } else {
+ ADD(LFLOW_RESTART_XON);
+ }
+ ADD(SE);
+ }
+ }
+
+#ifdef LINEMODE
+ if (his_want_state_is_will(TELOPT_LINEMODE)) {
+ unsigned char *cp, *cpe;
+ int len;
+
+ ADD(SB);
+ ADD(TELOPT_LINEMODE);
+ ADD(LM_MODE);
+ ADD_DATA(editmode);
+ ADD(SE);
+
+ ADD(SB);
+ ADD(TELOPT_LINEMODE);
+ ADD(LM_SLC);
+ start_slc(0);
+ send_slc();
+ len = end_slc(&cp);
+ for (cpe = cp + len; cp < cpe; cp++)
+ ADD_DATA(*cp);
+ ADD(SE);
+ }
+#endif /* LINEMODE */
+
+ ADD(IAC);
+ ADD(SE);
+
+ output_datalen((const char *)statusbuf, ncp - statusbuf);
+ netflush(); /* Send it on its way */
+
+ DIAG(TD_OPTIONS,
+ {printsub('>', statusbuf, ncp - statusbuf); netflush();});
+}
+
+/*
+ * This function appends data to nfrontp and advances nfrontp.
+ * Returns the number of characters written altogether (the
+ * buffer may have been flushed in the process).
+ */
+
+int
+output_data(const char *format, ...)
+{
+ va_list args;
+ int len;
+ char *buf;
+
+ va_start(args, format);
+ if ((len = vasprintf(&buf, format, args)) == -1)
+ return -1;
+ output_datalen(buf, len);
+ va_end(args);
+ free(buf);
+ return (len);
+}
+
+void
+output_datalen(const char *buf, int len)
+{
+ int remaining, copied;
+
+ remaining = BUFSIZ - (nfrontp - netobuf);
+ while (len > 0) {
+ /* Free up enough space if the room is too low*/
+ if ((len > BUFSIZ ? BUFSIZ : len) > remaining) {
+ netflush();
+ remaining = BUFSIZ - (nfrontp - netobuf);
+ }
+
+ /* Copy out as much as will fit */
+ copied = remaining > len ? len : remaining;
+ memmove(nfrontp, buf, copied);
+ nfrontp += copied;
+ len -= copied;
+ remaining -= copied;
+ buf += copied;
+ }
+ return;
+}
diff --git a/remote_cmds/telnetd.tproj/strlcpy.c b/remote_cmds/telnetd.tproj/strlcpy.c
new file mode 100644
index 0000000..9b39b41
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/strlcpy.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.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.
+ * 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 ``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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/lib/libc/string/strlcpy.c,v 1.3 2001/05/24 08:47:41 obrien Exp $";
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/remote_cmds/telnetd.tproj/sys_term.c b/remote_cmds/telnetd.tproj/sys_term.c
new file mode 100644
index 0000000..23da55b
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/sys_term.c
@@ -0,0 +1,1410 @@
+ /*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/sys_term.c,v 1.18 2003/05/04 02:54:49 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/tty.h>
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#include <stdlib.h>
+#ifndef __APPLE__
+#include <utmp.h>
+#endif
+
+#include "telnetd.h"
+#include "pathnames.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+
+int cleanopen(char *);
+void scrub_env(void);
+
+#ifdef UTMPX
+#include <utmpx.h>
+struct utmpx wtmp;
+#endif /* UTMPX */
+
+#ifndef NO_UTMP
+# include <utmp.h>
+struct utmp wtmp;
+
+#ifdef _PATH_WTMP
+char wtmpf[] = _PATH_WTMP;
+#else
+char wtmpf[] = "/var/log/wtmp";
+#endif
+#ifdef _PATH_UTMP
+char utmpf[] = _PATH_UTMP;
+#else
+char utmpf[] = "/var/run/utmp";
+#endif
+#endif /* NO_UTMP */
+
+char *envinit[3];
+extern char **environ;
+
+#define SCPYN(a, b) (void) strncpy(a, b, sizeof(a))
+#define SCMPN(a, b) strncmp(a, b, sizeof(a))
+
+#ifdef t_erase
+#undef t_erase
+#undef t_kill
+#undef t_intrc
+#undef t_quitc
+#undef t_startc
+#undef t_stopc
+#undef t_eofc
+#undef t_brkc
+#undef t_suspc
+#undef t_dsuspc
+#undef t_rprntc
+#undef t_flushc
+#undef t_werasc
+#undef t_lnextc
+#endif
+
+#ifndef USE_TERMIO
+struct termbuf {
+ struct sgttyb sg;
+ struct tchars tc;
+ struct ltchars ltc;
+ int state;
+ int lflags;
+} termbuf, termbuf2;
+# define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val)
+# define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val)
+# define cfgetospeed(tp) (tp)->sg.sg_ospeed
+# define cfgetispeed(tp) (tp)->sg.sg_ispeed
+#else /* USE_TERMIO */
+# ifndef TCSANOW
+# ifdef TCSETS
+# define TCSANOW TCSETS
+# define TCSADRAIN TCSETSW
+# define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
+# else
+# ifdef TCSETA
+# define TCSANOW TCSETA
+# define TCSADRAIN TCSETAW
+# define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
+# else
+# define TCSANOW TIOCSETA
+# define TCSADRAIN TIOCSETAW
+# define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
+# endif
+# endif
+# define tcsetattr(f, a, t) ioctl(f, a, t)
+# define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
+ (tp)->c_cflag |= (val)
+# define cfgetospeed(tp) ((tp)->c_cflag & CBAUD)
+# ifdef CIBAUD
+# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \
+ (tp)->c_cflag |= ((val)<<IBSHIFT)
+# define cfgetispeed(tp) (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
+# else
+# define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \
+ (tp)->c_cflag |= (val)
+# define cfgetispeed(tp) ((tp)->c_cflag & CBAUD)
+# endif
+# endif /* TCSANOW */
+struct termios termbuf, termbuf2; /* pty control structure */
+#endif /* USE_TERMIO */
+
+#include <sys/types.h>
+#ifndef __APPLE__
+#include <libutil.h>
+#endif
+
+int cleanopen(char *);
+void scrub_env(void);
+static char **addarg(char **, const char *);
+
+/*
+ * init_termbuf()
+ * copy_termbuf(cp)
+ * set_termbuf()
+ *
+ * These three routines are used to get and set the "termbuf" structure
+ * to and from the kernel. init_termbuf() gets the current settings.
+ * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
+ * set_termbuf() writes the structure into the kernel.
+ */
+
+void
+init_termbuf(void)
+{
+#ifndef USE_TERMIO
+ if (ioctl(spty, TIOCGETP, (char *)&termbuf.sg) == -1)
+ perror("ioctl TIOCGETP");
+ if (ioctl(spty, TIOCGETC, (char *)&termbuf.tc) == -1)
+ perror("ioctl TIOCGETC");
+ if (ioctl(spty, TIOCGLTC, (char *)&termbuf.ltc) == -1)
+ perror("ioctl TIOCGLTC");
+# ifdef TIOCGSTATE
+ if (-1 == ioctl(spty, TIOCGSTATE, (char *)&termbuf.state))
+ perror("ioctl TIOCGSTATE");
+# endif
+#else
+ if (-1 == tcgetattr(spty, &termbuf))
+ perror("tcgetattr");
+#endif
+ termbuf2 = termbuf;
+}
+
+#if defined(LINEMODE) && defined(TIOCPKT_IOCTL)
+void
+copy_termbuf(char *cp, size_t len)
+{
+ if (len > sizeof(termbuf))
+ len = sizeof(termbuf);
+ memmove((char *)&termbuf, cp, len);
+ termbuf2 = termbuf;
+}
+#endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
+
+void
+set_termbuf(void)
+{
+ /*
+ * Only make the necessary changes.
+ */
+#ifndef USE_TERMIO
+ if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
+ sizeof(termbuf.sg))) {
+ if (-1 == ioctl(spty, TIOCSETN, (char *)&termbuf.sg))
+ perror("ioctl TIOSETN");
+ }
+ if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
+ sizeof(termbuf.tc))) {
+ if (-1 == ioctl(spty, TIOCSETC, (char *)&termbuf.tc))
+ perror("ioctl TIOSETC");
+ }
+ if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
+ sizeof(termbuf.ltc))) {
+ if (-1 == ioctl(spty, TIOCSLTC, (char *)&termbuf.ltc))
+ perror("ioctl TIOCSLTC");
+ }
+ if (termbuf.lflags != termbuf2.lflags) {
+ (void) ioctl(spty, TIOCLSET, (char *)&termbuf.lflags);
+ }
+#else /* USE_TERMIO */
+ if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) {
+ if (-1 == tcsetattr(spty, TCSANOW, &termbuf))
+ perror("tcsetattr");
+ }
+#endif /* USE_TERMIO */
+}
+
+
+/*
+ * spcset(func, valp, valpp)
+ *
+ * This function takes various special characters (func), and
+ * sets *valp to the current value of that character, and
+ * *valpp to point to where in the "termbuf" structure that
+ * value is kept.
+ *
+ * It returns the SLC_ level of support for this function.
+ */
+
+#ifndef USE_TERMIO
+int
+spcset(int func, cc_t *valp, cc_t **valpp)
+{
+ switch(func) {
+ case SLC_EOF:
+ *valp = termbuf.tc.t_eofc;
+ *valpp = (cc_t *)&termbuf.tc.t_eofc;
+ return(SLC_VARIABLE);
+ case SLC_EC:
+ *valp = termbuf.sg.sg_erase;
+ *valpp = (cc_t *)&termbuf.sg.sg_erase;
+ return(SLC_VARIABLE);
+ case SLC_EL:
+ *valp = termbuf.sg.sg_kill;
+ *valpp = (cc_t *)&termbuf.sg.sg_kill;
+ return(SLC_VARIABLE);
+ case SLC_IP:
+ *valp = termbuf.tc.t_intrc;
+ *valpp = (cc_t *)&termbuf.tc.t_intrc;
+ return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+ case SLC_ABORT:
+ *valp = termbuf.tc.t_quitc;
+ *valpp = (cc_t *)&termbuf.tc.t_quitc;
+ return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+ case SLC_XON:
+ *valp = termbuf.tc.t_startc;
+ *valpp = (cc_t *)&termbuf.tc.t_startc;
+ return(SLC_VARIABLE);
+ case SLC_XOFF:
+ *valp = termbuf.tc.t_stopc;
+ *valpp = (cc_t *)&termbuf.tc.t_stopc;
+ return(SLC_VARIABLE);
+ case SLC_AO:
+ *valp = termbuf.ltc.t_flushc;
+ *valpp = (cc_t *)&termbuf.ltc.t_flushc;
+ return(SLC_VARIABLE);
+ case SLC_SUSP:
+ *valp = termbuf.ltc.t_suspc;
+ *valpp = (cc_t *)&termbuf.ltc.t_suspc;
+ return(SLC_VARIABLE);
+ case SLC_EW:
+ *valp = termbuf.ltc.t_werasc;
+ *valpp = (cc_t *)&termbuf.ltc.t_werasc;
+ return(SLC_VARIABLE);
+ case SLC_RP:
+ *valp = termbuf.ltc.t_rprntc;
+ *valpp = (cc_t *)&termbuf.ltc.t_rprntc;
+ return(SLC_VARIABLE);
+ case SLC_LNEXT:
+ *valp = termbuf.ltc.t_lnextc;
+ *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
+ return(SLC_VARIABLE);
+ case SLC_FORW1:
+ *valp = termbuf.tc.t_brkc;
+ *valpp = (cc_t *)&termbuf.ltc.t_lnextc;
+ return(SLC_VARIABLE);
+ case SLC_BRK:
+ case SLC_SYNCH:
+ case SLC_AYT:
+ case SLC_EOR:
+ *valp = (cc_t)0;
+ *valpp = (cc_t *)0;
+ return(SLC_DEFAULT);
+ default:
+ *valp = (cc_t)0;
+ *valpp = (cc_t *)0;
+ return(SLC_NOSUPPORT);
+ }
+}
+
+#else /* USE_TERMIO */
+
+
+#define setval(a, b) *valp = termbuf.c_cc[a]; \
+ *valpp = &termbuf.c_cc[a]; \
+ return(b);
+#define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
+
+int
+spcset(int func, cc_t *valp, cc_t **valpp)
+{
+ switch(func) {
+ case SLC_EOF:
+ setval(VEOF, SLC_VARIABLE);
+ case SLC_EC:
+ setval(VERASE, SLC_VARIABLE);
+ case SLC_EL:
+ setval(VKILL, SLC_VARIABLE);
+ case SLC_IP:
+ setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+ case SLC_ABORT:
+ setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
+ case SLC_XON:
+#ifdef VSTART
+ setval(VSTART, SLC_VARIABLE);
+#else
+ defval(0x13);
+#endif
+ case SLC_XOFF:
+#ifdef VSTOP
+ setval(VSTOP, SLC_VARIABLE);
+#else
+ defval(0x11);
+#endif
+ case SLC_EW:
+#ifdef VWERASE
+ setval(VWERASE, SLC_VARIABLE);
+#else
+ defval(0);
+#endif
+ case SLC_RP:
+#ifdef VREPRINT
+ setval(VREPRINT, SLC_VARIABLE);
+#else
+ defval(0);
+#endif
+ case SLC_LNEXT:
+#ifdef VLNEXT
+ setval(VLNEXT, SLC_VARIABLE);
+#else
+ defval(0);
+#endif
+ case SLC_AO:
+#if !defined(VDISCARD) && defined(VFLUSHO)
+# define VDISCARD VFLUSHO
+#endif
+#ifdef VDISCARD
+ setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
+#else
+ defval(0);
+#endif
+ case SLC_SUSP:
+#ifdef VSUSP
+ setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
+#else
+ defval(0);
+#endif
+#ifdef VEOL
+ case SLC_FORW1:
+ setval(VEOL, SLC_VARIABLE);
+#endif
+#ifdef VEOL2
+ case SLC_FORW2:
+ setval(VEOL2, SLC_VARIABLE);
+#endif
+ case SLC_AYT:
+#ifdef VSTATUS
+ setval(VSTATUS, SLC_VARIABLE);
+#else
+ defval(0);
+#endif
+
+ case SLC_BRK:
+ case SLC_SYNCH:
+ case SLC_EOR:
+ defval(0);
+
+ default:
+ *valp = 0;
+ *valpp = 0;
+ return(SLC_NOSUPPORT);
+ }
+}
+#endif /* USE_TERMIO */
+
+/*
+ * getpty()
+ *
+ * Allocate a pty. As a side effect, the external character
+ * array "line" contains the name of the slave side.
+ *
+ * Returns the file descriptor of the opened pty.
+ */
+char alpha[] = "0123456789abcdefghijklmnopqrstuv";
+char line[16];
+
+int
+getpty(int *ptynum __unused, int *slavepty)
+{
+ int p;
+#ifdef __APPLE__
+ // rdar://problem/5169227
+ p = open("/dev/ptmx", 2);
+ if (p >= 0) {
+ grantpt(p);
+ unlockpt(p);
+ strcpy(line, ptsname(p));
+ *slavepty = cleanopen(line);
+ return(p);
+ }
+
+#else /* !__APPLE__ */
+ const char *cp;
+ char *p1, *p2;
+ int i;
+
+ (void) strcpy(line, _PATH_DEV);
+ (void) strcat(line, "ptyXX");
+ p1 = &line[8];
+ p2 = &line[9];
+
+ for (cp = "pqrsPQRS"; *cp; cp++) {
+ struct stat stb;
+
+ *p1 = *cp;
+ *p2 = '0';
+ /*
+ * This stat() check is just to keep us from
+ * looping through all 256 combinations if there
+ * aren't that many ptys available.
+ */
+ if (stat(line, &stb) < 0)
+ break;
+ for (i = 0; i < 32; i++) {
+ *p2 = alpha[i];
+ p = open(line, 2);
+ if (p > 0) {
+ line[5] = 't';
+ chown(line, 0, 0);
+ chmod(line, 0600);
+ return(p);
+ }
+ }
+ }
+#endif /* __APPLE__ */
+ return(-1);
+}
+
+#ifdef LINEMODE
+/*
+ * tty_flowmode() Find out if flow control is enabled or disabled.
+ * tty_linemode() Find out if linemode (external processing) is enabled.
+ * tty_setlinemod(on) Turn on/off linemode.
+ * tty_isecho() Find out if echoing is turned on.
+ * tty_setecho(on) Enable/disable character echoing.
+ * tty_israw() Find out if terminal is in RAW mode.
+ * tty_binaryin(on) Turn on/off BINARY on input.
+ * tty_binaryout(on) Turn on/off BINARY on output.
+ * tty_isediting() Find out if line editing is enabled.
+ * tty_istrapsig() Find out if signal trapping is enabled.
+ * tty_setedit(on) Turn on/off line editing.
+ * tty_setsig(on) Turn on/off signal trapping.
+ * tty_issofttab() Find out if tab expansion is enabled.
+ * tty_setsofttab(on) Turn on/off soft tab expansion.
+ * tty_islitecho() Find out if typed control chars are echoed literally
+ * tty_setlitecho() Turn on/off literal echo of control chars
+ * tty_tspeed(val) Set transmit speed to val.
+ * tty_rspeed(val) Set receive speed to val.
+ */
+
+
+int
+tty_linemode(void)
+{
+#ifndef USE_TERMIO
+ return(termbuf.state & TS_EXTPROC);
+#else
+ return(termbuf.c_lflag & EXTPROC);
+#endif
+}
+
+void
+tty_setlinemode(int on)
+{
+#ifdef TIOCEXT
+ set_termbuf();
+ if (-1 == ioctl(spty, TIOCEXT, (char *)&on))
+ perror("ioctl TIOCEXT");
+ init_termbuf();
+#else /* !TIOCEXT */
+# ifdef EXTPROC
+ if (on)
+ termbuf.c_lflag |= EXTPROC;
+ else
+ termbuf.c_lflag &= ~EXTPROC;
+# endif
+#endif /* TIOCEXT */
+}
+#endif /* LINEMODE */
+
+int
+tty_isecho(void)
+{
+#ifndef USE_TERMIO
+ return (termbuf.sg.sg_flags & ECHO);
+#else
+ return (termbuf.c_lflag & ECHO);
+#endif
+}
+
+int
+tty_flowmode(void)
+{
+#ifndef USE_TERMIO
+ return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
+#else
+ return((termbuf.c_iflag & IXON) ? 1 : 0);
+#endif
+}
+
+int
+tty_restartany(void)
+{
+#ifndef USE_TERMIO
+# ifdef DECCTQ
+ return((termbuf.lflags & DECCTQ) ? 0 : 1);
+# else
+ return(-1);
+# endif
+#else
+ return((termbuf.c_iflag & IXANY) ? 1 : 0);
+#endif
+}
+
+void
+tty_setecho(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.sg.sg_flags |= ECHO|CRMOD;
+ else
+ termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
+#else
+ if (on)
+ termbuf.c_lflag |= ECHO;
+ else
+ termbuf.c_lflag &= ~ECHO;
+#endif
+}
+
+int
+tty_israw(void)
+{
+#ifndef USE_TERMIO
+ return(termbuf.sg.sg_flags & RAW);
+#else
+ return(!(termbuf.c_lflag & ICANON));
+#endif
+}
+
+#ifdef AUTHENTICATION
+#if defined(NO_LOGIN_F) && defined(LOGIN_R)
+int
+tty_setraw(int on)
+{
+# ifndef USE_TERMIO
+ if (on)
+ termbuf.sg.sg_flags |= RAW;
+ else
+ termbuf.sg.sg_flags &= ~RAW;
+# else
+ if (on)
+ termbuf.c_lflag &= ~ICANON;
+ else
+ termbuf.c_lflag |= ICANON;
+# endif
+}
+#endif
+#endif /* AUTHENTICATION */
+
+void
+tty_binaryin(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.lflags |= LPASS8;
+ else
+ termbuf.lflags &= ~LPASS8;
+#else
+ if (on) {
+ termbuf.c_iflag &= ~ISTRIP;
+ } else {
+ termbuf.c_iflag |= ISTRIP;
+ }
+#endif
+}
+
+void
+tty_binaryout(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.lflags |= LLITOUT;
+ else
+ termbuf.lflags &= ~LLITOUT;
+#else
+ if (on) {
+ termbuf.c_cflag &= ~(CSIZE|PARENB);
+ termbuf.c_cflag |= CS8;
+ termbuf.c_oflag &= ~OPOST;
+ } else {
+ termbuf.c_cflag &= ~CSIZE;
+ termbuf.c_cflag |= CS7|PARENB;
+ termbuf.c_oflag |= OPOST;
+ }
+#endif
+}
+
+int
+tty_isbinaryin(void)
+{
+#ifndef USE_TERMIO
+ return(termbuf.lflags & LPASS8);
+#else
+ return(!(termbuf.c_iflag & ISTRIP));
+#endif
+}
+
+int
+tty_isbinaryout(void)
+{
+#ifndef USE_TERMIO
+ return(termbuf.lflags & LLITOUT);
+#else
+ return(!(termbuf.c_oflag&OPOST));
+#endif
+}
+
+#ifdef LINEMODE
+int
+tty_isediting(void)
+{
+#ifndef USE_TERMIO
+ return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
+#else
+ return(termbuf.c_lflag & ICANON);
+#endif
+}
+
+int
+tty_istrapsig(void)
+{
+#ifndef USE_TERMIO
+ return(!(termbuf.sg.sg_flags&RAW));
+#else
+ return(termbuf.c_lflag & ISIG);
+#endif
+}
+
+void
+tty_setedit(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.sg.sg_flags &= ~CBREAK;
+ else
+ termbuf.sg.sg_flags |= CBREAK;
+#else
+ if (on)
+ termbuf.c_lflag |= ICANON;
+ else
+ termbuf.c_lflag &= ~ICANON;
+#endif
+}
+
+void
+tty_setsig(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ ;
+#else
+ if (on)
+ termbuf.c_lflag |= ISIG;
+ else
+ termbuf.c_lflag &= ~ISIG;
+#endif
+}
+#endif /* LINEMODE */
+
+int
+tty_issofttab(void)
+{
+#ifndef USE_TERMIO
+ return (termbuf.sg.sg_flags & XTABS);
+#else
+# ifdef OXTABS
+ return (termbuf.c_oflag & OXTABS);
+# endif
+# ifdef TABDLY
+ return ((termbuf.c_oflag & TABDLY) == TAB3);
+# endif
+#endif
+}
+
+void
+tty_setsofttab(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.sg.sg_flags |= XTABS;
+ else
+ termbuf.sg.sg_flags &= ~XTABS;
+#else
+ if (on) {
+# ifdef OXTABS
+ termbuf.c_oflag |= OXTABS;
+# endif
+# ifdef TABDLY
+ termbuf.c_oflag &= ~TABDLY;
+ termbuf.c_oflag |= TAB3;
+# endif
+ } else {
+# ifdef OXTABS
+ termbuf.c_oflag &= ~OXTABS;
+# endif
+# ifdef TABDLY
+ termbuf.c_oflag &= ~TABDLY;
+ termbuf.c_oflag |= TAB0;
+# endif
+ }
+#endif
+}
+
+int
+tty_islitecho(void)
+{
+#ifndef USE_TERMIO
+ return (!(termbuf.lflags & LCTLECH));
+#else
+# ifdef ECHOCTL
+ return (!(termbuf.c_lflag & ECHOCTL));
+# endif
+# ifdef TCTLECH
+ return (!(termbuf.c_lflag & TCTLECH));
+# endif
+# if !defined(ECHOCTL) && !defined(TCTLECH)
+ return (0); /* assumes ctl chars are echoed '^x' */
+# endif
+#endif
+}
+
+void
+tty_setlitecho(int on)
+{
+#ifndef USE_TERMIO
+ if (on)
+ termbuf.lflags &= ~LCTLECH;
+ else
+ termbuf.lflags |= LCTLECH;
+#else
+# ifdef ECHOCTL
+ if (on)
+ termbuf.c_lflag &= ~ECHOCTL;
+ else
+ termbuf.c_lflag |= ECHOCTL;
+# endif
+# ifdef TCTLECH
+ if (on)
+ termbuf.c_lflag &= ~TCTLECH;
+ else
+ termbuf.c_lflag |= TCTLECH;
+# endif
+#endif
+}
+
+int
+tty_iscrnl(void)
+{
+#ifndef USE_TERMIO
+ return (termbuf.sg.sg_flags & CRMOD);
+#else
+ return (termbuf.c_iflag & ICRNL);
+#endif
+}
+
+/*
+ * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
+ */
+#if B4800 != 4800
+#define DECODE_BAUD
+#endif
+
+#ifdef DECODE_BAUD
+
+/*
+ * A table of available terminal speeds
+ */
+struct termspeeds {
+ int speed;
+ int value;
+} termspeeds[] = {
+ { 0, B0 }, { 50, B50 }, { 75, B75 },
+ { 110, B110 }, { 134, B134 }, { 150, B150 },
+ { 200, B200 }, { 300, B300 }, { 600, B600 },
+ { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
+ { 4800, B4800 },
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+ { 9600, B9600 },
+#ifdef B14400
+ { 14400, B14400 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B28800
+ { 28800, B28800 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+#ifdef B230400
+ { 230400, B230400 },
+#endif
+ { -1, 0 }
+};
+#endif /* DECODE_BAUD */
+
+void
+tty_tspeed(int val)
+{
+#ifdef DECODE_BAUD
+ struct termspeeds *tp;
+
+ for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
+ ;
+ if (tp->speed == -1) /* back up to last valid value */
+ --tp;
+ cfsetospeed(&termbuf, tp->value);
+#else /* DECODE_BAUD */
+ cfsetospeed(&termbuf, val);
+#endif /* DECODE_BAUD */
+}
+
+void
+tty_rspeed(int val)
+{
+#ifdef DECODE_BAUD
+ struct termspeeds *tp;
+
+ for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
+ ;
+ if (tp->speed == -1) /* back up to last valid value */
+ --tp;
+ cfsetispeed(&termbuf, tp->value);
+#else /* DECODE_BAUD */
+ cfsetispeed(&termbuf, val);
+#endif /* DECODE_BAUD */
+}
+
+/*
+ * getptyslave()
+ *
+ * Open the slave side of the pty, and do any initialization
+ * that is necessary.
+ */
+static void
+getptyslave(void)
+{
+ int t = -1;
+ char erase;
+
+# ifdef LINEMODE
+ int waslm;
+# endif
+# ifdef TIOCGWINSZ
+ struct winsize ws;
+ extern int def_row, def_col;
+# endif
+ extern int def_tspeed, def_rspeed;
+ /*
+ * Opening the slave side may cause initilization of the
+ * kernel tty structure. We need remember the state of
+ * if linemode was turned on
+ * terminal window size
+ * terminal speed
+ * erase character
+ * so that we can re-set them if we need to.
+ */
+# ifdef LINEMODE
+ waslm = tty_linemode();
+# endif
+ erase = termbuf.c_cc[VERASE];
+
+ /*
+ * Make sure that we don't have a controlling tty, and
+ * that we are the session (process group) leader.
+ */
+# ifdef TIOCNOTTY
+ t = open(_PATH_TTY, O_RDWR);
+ if (t >= 0) {
+ (void) ioctl(t, TIOCNOTTY, (char *)0);
+ (void) close(t);
+ }
+# endif
+
+ t = spty;
+ if (t < 0)
+ fatalperror(net, line);
+
+
+ /*
+ * set up the tty modes as we like them to be.
+ */
+ init_termbuf();
+# ifdef TIOCGWINSZ
+ if (def_row || def_col) {
+ memset((char *)&ws, 0, sizeof(ws));
+ ws.ws_col = def_col;
+ ws.ws_row = def_row;
+ (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
+ }
+# endif
+
+ /*
+ * Settings for sgtty based systems
+ */
+# ifndef USE_TERMIO
+ termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
+# endif /* USE_TERMIO */
+
+ /*
+ * Settings for all other termios/termio based
+ * systems, other than 4.4BSD. In 4.4BSD the
+ * kernel does the initial terminal setup.
+ */
+ tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
+ tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
+ if (erase)
+ termbuf.c_cc[VERASE] = erase;
+# ifdef LINEMODE
+ if (waslm)
+ tty_setlinemode(1);
+# endif /* LINEMODE */
+
+ /*
+ * Set the tty modes, and make this our controlling tty.
+ */
+ set_termbuf();
+ if (login_tty(t) == -1)
+ fatalperror(net, "login_tty");
+ if (net > 2)
+ (void) close(net);
+#ifdef AUTHENTICATION
+#if defined(NO_LOGIN_F) && defined(LOGIN_R)
+ /*
+ * Leave the pty open so that we can write out the rlogin
+ * protocol for /bin/login, if the authentication works.
+ */
+#else
+ if (pty > 2) {
+ (void) close(pty);
+ pty = -1;
+ }
+#endif
+#endif /* AUTHENTICATION */
+}
+
+#ifndef O_NOCTTY
+#define O_NOCTTY 0
+#endif
+/*
+ * Open the specified slave side of the pty,
+ * making sure that we have a clean tty.
+ */
+int
+cleanopen(char *li)
+{
+ int t;
+
+ /*
+ * Make sure that other people can't open the
+ * slave side of the connection.
+ */
+ (void) chown(li, 0, 0);
+ (void) chmod(li, 0600);
+
+ (void) revoke(li);
+
+ t = open(line, O_RDWR|O_NOCTTY);
+
+ if (t < 0)
+ return(-1);
+
+ return(t);
+}
+
+/*
+ * startslave(host)
+ *
+ * Given a hostname, do whatever
+ * is necessary to startup the login process on the slave side of the pty.
+ */
+
+/* ARGSUSED */
+void
+startslave(char *host, int autologin, char *autoname)
+{
+ int i;
+
+#ifdef AUTHENTICATION
+ if (!autoname || !autoname[0])
+ autologin = 0;
+
+ if (autologin < auth_level) {
+ fatal(net, "Authorization failed");
+ exit(1);
+ }
+#endif
+
+
+ if ((i = fork()) < 0)
+ fatalperror(net, "fork");
+ if (i) {
+ } else {
+ getptyslave();
+ start_login(host, autologin, autoname);
+ /*NOTREACHED*/
+ }
+}
+
+void
+init_env(void)
+{
+ char **envp;
+
+ envp = envinit;
+ if ((*envp = getenv("TZ")))
+ *envp++ -= 3;
+ *envp = 0;
+ environ = envinit;
+}
+
+
+/*
+ * start_login(host)
+ *
+ * Assuming that we are now running as a child processes, this
+ * function will turn us into the login process.
+ */
+
+#ifndef AUTHENTICATION
+#define undef1 __unused
+#else
+#define undef1
+#endif
+
+void
+start_login(char *host undef1, int autologin undef1, char *name undef1)
+{
+ char **argv;
+#ifdef UTMPX
+ // rdar://problem/4433603
+ int pid = getpid();
+ struct utmpx utmpx;
+
+ /*
+ * Create utmp entry for child
+ */
+
+ bzero(&utmpx, sizeof(utmpx));
+ SCPYN(utmpx.ut_user, ".telnet");
+ SCPYN(utmpx.ut_line, line + sizeof(_PATH_DEV) - 1);
+ utmpx.ut_pid = pid;
+ utmpx.ut_id[0] = 't';
+ utmpx.ut_id[1] = 'n';
+ utmpx.ut_id[2] = SC_WILDC;
+ utmpx.ut_id[3] = SC_WILDC;
+ utmpx.ut_type = LOGIN_PROCESS;
+ (void) time(&utmpx.ut_tv.tv_sec);
+ if (makeutx(&utmpx) == NULL)
+ fatal(net, "makeutx failed");
+#endif /* UTMPX */
+
+ scrub_env();
+
+ /*
+ * -h : pass on name of host.
+ * WARNING: -h is accepted by login if and only if
+ * getuid() == 0.
+ * -p : don't clobber the environment (so terminal type stays set).
+ *
+ * -f : force this login, he has already been authenticated
+ */
+ argv = addarg(0, "login");
+
+#if !defined(NO_LOGIN_H)
+#ifdef AUTHENTICATION
+# if defined(NO_LOGIN_F) && defined(LOGIN_R)
+ /*
+ * Don't add the "-h host" option if we are going
+ * to be adding the "-r host" option down below...
+ */
+ if ((auth_level < 0) || (autologin != AUTH_VALID))
+# endif
+ {
+ argv = addarg(argv, "-h");
+ argv = addarg(argv, host);
+ }
+#endif /* AUTHENTICATION */
+#endif
+#if !defined(NO_LOGIN_P)
+ argv = addarg(argv, "-p");
+#endif
+#ifdef LINEMODE
+ /*
+ * Set the environment variable "LINEMODE" to either
+ * "real" or "kludge" if we are operating in either
+ * real or kludge linemode.
+ */
+ if (lmodetype == REAL_LINEMODE)
+ setenv("LINEMODE", "real", 1);
+# ifdef KLUDGELINEMODE
+ else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
+ setenv("LINEMODE", "kludge", 1);
+# endif
+#endif
+#ifdef BFTPDAEMON
+ /*
+ * Are we working as the bftp daemon? If so, then ask login
+ * to start bftp instead of shell.
+ */
+ if (bftpd) {
+ argv = addarg(argv, "-e");
+ argv = addarg(argv, BFTPPATH);
+ } else
+#endif
+#ifdef AUTHENTICATION
+ if (auth_level >= 0 && autologin == AUTH_VALID) {
+# if !defined(NO_LOGIN_F)
+ argv = addarg(argv, "-f");
+ argv = addarg(argv, "--");
+ argv = addarg(argv, name);
+# else
+# if defined(LOGIN_R)
+ /*
+ * We don't have support for "login -f", but we
+ * can fool /bin/login into thinking that we are
+ * rlogind, and allow us to log in without a
+ * password. The rlogin protocol expects
+ * local-user\0remote-user\0term/speed\0
+ */
+
+ if (pty > 2) {
+ char *cp;
+ char speed[128];
+ int isecho, israw, xpty, len;
+ extern int def_rspeed;
+# ifndef LOGIN_HOST
+ /*
+ * Tell login that we are coming from "localhost".
+ * If we passed in the real host name, then the
+ * user would have to allow .rhost access from
+ * every machine that they want authenticated
+ * access to work from, which sort of defeats
+ * the purpose of an authenticated login...
+ * So, we tell login that the session is coming
+ * from "localhost", and the user will only have
+ * to have "localhost" in their .rhost file.
+ */
+# define LOGIN_HOST "localhost"
+# endif
+ argv = addarg(argv, "-r");
+ argv = addarg(argv, LOGIN_HOST);
+
+ xpty = pty;
+ pty = 0;
+ init_termbuf();
+ isecho = tty_isecho();
+ israw = tty_israw();
+ if (isecho || !israw) {
+ tty_setecho(0); /* Turn off echo */
+ tty_setraw(1); /* Turn on raw */
+ set_termbuf();
+ }
+ len = strlen(name)+1;
+ write(xpty, name, len);
+ write(xpty, name, len);
+ snprintf(speed, sizeof(speed),
+ "%s/%d", (cp = getenv("TERM")) ? cp : "",
+ (def_rspeed > 0) ? def_rspeed : 9600);
+ len = strlen(speed)+1;
+ write(xpty, speed, len);
+
+ if (isecho || !israw) {
+ init_termbuf();
+ tty_setecho(isecho);
+ tty_setraw(israw);
+ set_termbuf();
+ if (!israw) {
+ /*
+ * Write a newline to ensure
+ * that login will be able to
+ * read the line...
+ */
+ write(xpty, "\n", 1);
+ }
+ }
+ pty = xpty;
+ }
+# else
+ argv = addarg(argv, "--");
+ argv = addarg(argv, name);
+# endif
+# endif
+ } else
+#endif
+ if (getenv("USER")) {
+ argv = addarg(argv, "--");
+ argv = addarg(argv, getenv("USER"));
+#if defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
+ {
+ char **cpp;
+ for (cpp = environ; *cpp; cpp++)
+ argv = addarg(argv, *cpp);
+ }
+#endif
+ /*
+ * Assume that login will set the USER variable
+ * correctly. For SysV systems, this means that
+ * USER will no longer be set, just LOGNAME by
+ * login. (The problem is that if the auto-login
+ * fails, and the user then specifies a different
+ * account name, he can get logged in with both
+ * LOGNAME and USER in his environment, but the
+ * USER value will be wrong.
+ */
+ unsetenv("USER");
+ }
+#ifdef AUTHENTICATION
+#if defined(NO_LOGIN_F) && defined(LOGIN_R)
+ if (pty > 2)
+ close(pty);
+#endif
+#endif /* AUTHENTICATION */
+ closelog();
+
+ if (altlogin == NULL) {
+ altlogin = _PATH_LOGIN;
+ }
+ execv(altlogin, argv);
+
+ syslog(LOG_ERR, "%s: %m", altlogin);
+ fatalperror(net, altlogin);
+ /*NOTREACHED*/
+}
+
+static char **
+addarg(char **argv, const char *val)
+{
+ char **cpp;
+
+ if (argv == NULL) {
+ /*
+ * 10 entries, a leading length, and a null
+ */
+ argv = (char **)malloc(sizeof(*argv) * 12);
+ if (argv == NULL)
+ return(NULL);
+ *argv++ = (char *)10;
+ *argv = (char *)0;
+ }
+ for (cpp = argv; *cpp; cpp++)
+ ;
+ if (cpp == &argv[(long)argv[-1]]) {
+ --argv;
+ *argv = (char *)((long)(*argv) + 10);
+ argv = (char **)realloc(argv, sizeof(*argv)*((long)(*argv) + 2));
+ if (argv == NULL)
+ return(NULL);
+ argv++;
+ cpp = &argv[(long)argv[-1] - 10];
+ }
+ *cpp++ = strdup(val);
+ *cpp = 0;
+ return(argv);
+}
+
+/*
+ * scrub_env()
+ *
+ * We only accept the environment variables listed below.
+ */
+void
+scrub_env(void)
+{
+ static const char *rej[] = {
+ "TERMCAP=/",
+ NULL
+ };
+
+ static const char *acc[] = {
+ "XAUTH=", "XAUTHORITY=", "DISPLAY=",
+ "TERM=",
+ "EDITOR=",
+ "PAGER=",
+ "LOGNAME=",
+ "POSIXLY_CORRECT=",
+ "PRINTER=",
+ NULL
+ };
+
+ char **cpp, **cpp2;
+ const char **p;
+
+ for (cpp2 = cpp = environ; *cpp; cpp++) {
+ int reject_it = 0;
+
+ for(p = rej; *p; p++)
+ if(strncmp(*cpp, *p, strlen(*p)) == 0) {
+ reject_it = 1;
+ break;
+ }
+ if (reject_it)
+ continue;
+
+ for(p = acc; *p; p++)
+ if(strncmp(*cpp, *p, strlen(*p)) == 0)
+ break;
+ if(*p != NULL)
+ *cpp2++ = *cpp;
+ }
+ *cpp2 = NULL;
+}
+
+/*
+ * cleanup()
+ *
+ * This is the routine to call when we are all through, to
+ * clean up anything that needs to be cleaned up.
+ */
+/* ARGSUSED */
+void
+cleanup(int sig __unused)
+{
+#ifdef __APPLE__
+ // rdar://problem/5169227
+ (void) shutdown(net, SHUT_RDWR);
+#else /* !__APPLE__ */
+ char *p;
+ sigset_t mask;
+
+ p = line + sizeof(_PATH_DEV) - 1;
+ /*
+ * Block all signals before clearing the utmp entry. We don't want to
+ * be called again after calling logout() and then not add the wtmp
+ * entry because of not finding the corresponding entry in utmp.
+ */
+ sigfillset(&mask);
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+ if (logout(p))
+ logwtmp(p, "", "");
+ (void)chmod(line, 0666);
+ (void)chown(line, 0, 0);
+ *p = 'p';
+ (void)chmod(line, 0666);
+ (void)chown(line, 0, 0);
+ (void) shutdown(net, 2);
+#endif
+ _exit(1);
+}
diff --git a/remote_cmds/telnetd.tproj/telnet.plist b/remote_cmds/telnetd.tproj/telnet.plist
new file mode 100644
index 0000000..6dff1eb
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/telnet.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.telnetd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/telnetd</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <false/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>telnet</string>
+ <key>Bonjour</key>
+ <true/>
+ </dict>
+ </dict>
+ <key>SessionCreate</key>
+ <true/>
+ <key>EnablePressuredExit</key>
+ <false/>
+ <key>EnableTransactions</key>
+ <false/>
+</dict>
+</plist>
diff --git a/remote_cmds/telnetd.tproj/telnetd.8 b/remote_cmds/telnetd.tproj/telnetd.8
new file mode 100644
index 0000000..3bf2f51
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/telnetd.8
@@ -0,0 +1,607 @@
+.\" Copyright (c) 1983, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)telnetd.8 8.4 (Berkeley) 6/1/94
+.\" $FreeBSD: src/contrib/telnet/telnetd/telnetd.8,v 1.21 2005/01/21 21:57:05 ru Exp $
+.\"
+.Dd January 9, 2005
+.Dt TELNETD 8
+.Os
+.Sh NAME
+.Nm telnetd
+.Nd DARPA
+.Tn TELNET
+protocol server
+.Sh SYNOPSIS
+.Nm /usr/libexec/telnetd
+.Op Fl 46BUhlkns
+.Op Fl D Ar debugmode
+.Op Fl S Ar tos
+.Op Fl X Ar authtype
+.Op Fl a Ar authmode
+.Op Fl edebug
+.Op Fl p Ar loginprog
+.Op Fl u Ar len
+.Op Fl debug Op Ar port
+.Sh DESCRIPTION
+The
+.Nm
+command is a server which supports the
+.Tn DARPA
+standard
+.Tn TELNET
+virtual terminal protocol.
+.Nm Telnetd
+is normally invoked by the internet server (see
+.Xr inetd 8 )
+for requests to connect to the
+.Tn TELNET
+port as indicated by the
+.Pa /etc/services
+file (see
+.Xr services 5 ) .
+The
+.Fl debug
+option may be used to start up
+.Nm
+manually, instead of through
+.Xr inetd 8 .
+If started up this way,
+.Ar port
+may be specified to run
+.Nm
+on an alternate
+.Tn TCP
+port number.
+.Pp
+The
+.Nm
+command accepts the following options:
+.Bl -tag -width indent
+.It Fl 4
+Forces
+.Nm
+to use IPv4 addresses only.
+.It Fl 6
+Forces
+.Nm
+to use IPv6 addresses only.
+.It Fl a Ar authmode
+This option may be used for specifying what mode should
+be used for authentication.
+Note that this option is only useful if
+.Nm
+has been compiled with support for the
+.Dv AUTHENTICATION
+option.
+There are several valid values for
+.Ar authmode :
+.Bl -tag -width debug
+.It Cm debug
+Turn on authentication debugging code.
+.It Cm user
+Only allow connections when the remote user
+can provide valid authentication information
+to identify the remote user,
+and is allowed access to the specified account
+without providing a password.
+.It Cm valid
+Only allow connections when the remote user
+can provide valid authentication information
+to identify the remote user.
+The
+.Xr login 1
+command will provide any additional user verification
+needed if the remote user is not allowed automatic
+access to the specified account.
+.It Cm other
+Only allow connections that supply some authentication information.
+This option is currently not supported
+by any of the existing authentication mechanisms,
+and is thus the same as specifying
+.Fl a
+.Cm valid .
+.It Cm none
+This is the default state.
+Authentication information is not required.
+If no or insufficient authentication information
+is provided, then the
+.Xr login 1
+program will provide the necessary user
+verification.
+.It Cm off
+Disable the authentication code.
+All user verification will happen through the
+.Xr login 1
+program.
+.El
+.It Fl B
+Specify bftp server mode.
+In this mode,
+.Nm
+causes login to start a
+.Xr bftp 1
+session rather than the user's
+normal shell.
+In bftp daemon mode normal
+logins are not supported, and it must be used
+on a port other than the normal
+.Tn TELNET
+port.
+.It Fl D Ar debugmode
+This option may be used for debugging purposes.
+This allows
+.Nm
+to print out debugging information
+to the connection, allowing the user to see what
+.Nm
+is doing.
+There are several possible values for
+.Ar debugmode :
+.Bl -tag -width exercise
+.It Cm options
+Print information about the negotiation of
+.Tn TELNET
+options.
+.It Cm report
+Print the
+.Cm options
+information, plus some additional information
+about what processing is going on.
+.It Cm netdata
+Display the data stream received by
+.Nm .
+.It Cm ptydata
+Display data written to the pty.
+.It Cm exercise
+Has not been implemented yet.
+.El
+.It Fl debug
+Enable debugging on each socket created by
+.Nm
+(see
+.Dv SO_DEBUG
+in
+.Xr socket 2 ) .
+.It Fl edebug
+If
+.Nm
+has been compiled with support for data encryption, then the
+.Fl edebug
+option may be used to enable encryption debugging code.
+.It Fl p Ar loginprog
+Specify an alternate
+.Xr login 1
+command to run to complete the login. The alternate command must
+understand the same command arguments as the standard login.
+.It Fl h
+Disable the printing of host-specific information before
+login has been completed.
+.It Fl k
+This option is only useful if
+.Nm
+has been compiled with both linemode and kludge linemode
+support.
+If the
+.Fl k
+option is specified, then if the remote client does not
+support the
+.Dv LINEMODE
+option, then
+.Nm
+will operate in character at a time mode.
+It will still support kludge linemode, but will only
+go into kludge linemode if the remote client requests
+it.
+(This is done by the client sending
+.Dv DONT SUPPRESS-GO-AHEAD
+and
+.Dv DONT ECHO . )
+The
+.Fl k
+option is most useful when there are remote clients
+that do not support kludge linemode, but pass the heuristic
+(if they respond with
+.Dv WILL TIMING-MARK
+in response to a
+.Dv DO TIMING-MARK )
+for kludge linemode support.
+.It Fl l
+Specify line mode.
+Try to force clients to use line-at-a-time mode.
+If the
+.Dv LINEMODE
+option is not supported, it will go
+into kludge linemode.
+.It Fl n
+Disable
+.Dv TCP
+keep-alives.
+Normally
+.Nm
+enables the
+.Tn TCP
+keep-alive mechanism to probe connections that
+have been idle for some period of time to determine
+if the client is still there, so that idle connections
+from machines that have crashed or can no longer
+be reached may be cleaned up.
+.It Fl S Ar tos
+Sets the IP type-of-service (TOS) option for the telnet
+connection to the value
+.Ar tos ,
+which can be a numeric TOS value or, on systems that support it, a symbolic
+TOS name found in the
+.Pa /etc/iptos
+file.
+.It Fl u Ar len
+This option is used to specify the size of the field
+in the
+.Dv utmpx
+structure that holds the remote host name.
+If the resolved host name is longer than
+.Ar len ,
+the dotted decimal value will be used instead.
+This allows hosts with very long host names that
+overflow this field to still be uniquely identified.
+Specifying
+.Fl u0
+indicates that only dotted decimal addresses
+should be put into the
+.Pa utmpx
+file.
+.It Fl U
+This option causes
+.Nm
+to refuse connections from addresses that
+cannot be mapped back into a symbolic name
+via the
+.Xr gethostbyaddr 3
+routine.
+.It Fl X Ar authtype
+This option is only valid if
+.Nm
+has been built with support for the authentication option.
+It disables the use of
+.Ar authtype
+authentication, and
+can be used to temporarily disable
+a specific authentication type without having to recompile
+.Nm .
+.El
+.Pp
+.Nm Telnetd
+operates by allocating a pseudo-terminal device (see
+.Xr pty 4 )
+for a client, then creating a login process which has
+the slave side of the pseudo-terminal as
+.Dv stdin ,
+.Dv stdout
+and
+.Dv stderr .
+.Nm Telnetd
+manipulates the master side of the pseudo-terminal,
+implementing the
+.Tn TELNET
+protocol and passing characters
+between the remote client and the login process.
+.Pp
+When a
+.Tn TELNET
+session is started up,
+.Nm
+sends
+.Tn TELNET
+options to the client side indicating
+a willingness to do the
+following
+.Tn TELNET
+options, which are described in more detail below:
+.Bd -literal -offset indent
+DO AUTHENTICATION
+WILL ENCRYPT
+DO TERMINAL TYPE
+DO TSPEED
+DO XDISPLOC
+DO NEW-ENVIRON
+DO ENVIRON
+WILL SUPPRESS GO AHEAD
+DO ECHO
+DO LINEMODE
+DO NAWS
+WILL STATUS
+DO LFLOW
+DO TIMING-MARK
+.Ed
+.Pp
+The pseudo-terminal allocated to the client is configured
+to operate in
+.Dq cooked
+mode, and with
+.Dv XTABS and
+.Dv CRMOD
+enabled (see
+.Xr tty 4 ) .
+.Pp
+.Nm Telnetd
+has support for enabling locally the following
+.Tn TELNET
+options:
+.Bl -tag -width "DO AUTHENTICATION"
+.It "WILL ECHO"
+When the
+.Dv LINEMODE
+option is enabled, a
+.Dv WILL ECHO
+or
+.Dv WONT ECHO
+will be sent to the client to indicate the
+current state of terminal echoing.
+When terminal echo is not desired, a
+.Dv WILL ECHO
+is sent to indicate that
+.Nm
+will take care of echoing any data that needs to be
+echoed to the terminal, and then nothing is echoed.
+When terminal echo is desired, a
+.Dv WONT ECHO
+is sent to indicate that
+.Nm
+will not be doing any terminal echoing, so the
+client should do any terminal echoing that is needed.
+.It "WILL BINARY"
+Indicate that the client is willing to send a
+8 bits of data, rather than the normal 7 bits
+of the Network Virtual Terminal.
+.It "WILL SGA"
+Indicate that it will not be sending
+.Dv IAC GA ,
+go ahead, commands.
+.It "WILL STATUS"
+Indicate a willingness to send the client, upon
+request, of the current status of all
+.Tn TELNET
+options.
+.It "WILL TIMING-MARK"
+Whenever a
+.Dv DO TIMING-MARK
+command is received, it is always responded
+to with a
+.Dv WILL TIMING-MARK .
+.It "WILL LOGOUT"
+When a
+.Dv DO LOGOUT
+is received, a
+.Dv WILL LOGOUT
+is sent in response, and the
+.Tn TELNET
+session is shut down.
+.It "WILL ENCRYPT"
+Only sent if
+.Nm
+is compiled with support for data encryption, and
+indicates a willingness to decrypt
+the data stream.
+.El
+.Pp
+.Nm Telnetd
+has support for enabling remotely the following
+.Tn TELNET
+options:
+.Bl -tag -width "DO AUTHENTICATION"
+.It "DO BINARY"
+Sent to indicate that
+.Nm
+is willing to receive an 8 bit data stream.
+.It "DO LFLOW"
+Requests that the client handle flow control
+characters remotely.
+.It "DO ECHO"
+This is not really supported, but is sent to identify a
+.Bx 4.2
+.Xr telnet 1
+client, which will improperly respond with
+.Dv WILL ECHO .
+If a
+.Dv WILL ECHO
+is received, a
+.Dv DONT ECHO
+will be sent in response.
+.It "DO TERMINAL-TYPE"
+Indicate a desire to be able to request the
+name of the type of terminal that is attached
+to the client side of the connection.
+.It "DO SGA"
+Indicate that it does not need to receive
+.Dv IAC GA ,
+the go ahead command.
+.It "DO NAWS"
+Requests that the client inform the server when
+the window (display) size changes.
+.It "DO TERMINAL-SPEED"
+Indicate a desire to be able to request information
+about the speed of the serial line to which
+the client is attached.
+.It "DO XDISPLOC"
+Indicate a desire to be able to request the name
+of the X Window System display that is associated with
+the telnet client.
+.It "DO NEW-ENVIRON"
+Indicate a desire to be able to request environment
+variable information, as described in RFC 1572.
+.It "DO ENVIRON"
+Indicate a desire to be able to request environment
+variable information, as described in RFC 1408.
+.It "DO LINEMODE"
+Only sent if
+.Nm
+is compiled with support for linemode, and
+requests that the client do line by line processing.
+.It "DO TIMING-MARK"
+Only sent if
+.Nm
+is compiled with support for both linemode and
+kludge linemode, and the client responded with
+.Dv WONT LINEMODE .
+If the client responds with
+.Dv WILL TM ,
+the it is assumed that the client supports
+kludge linemode.
+Note that the
+.Op Fl k
+option can be used to disable this.
+.It "DO AUTHENTICATION"
+Only sent if
+.Nm
+is compiled with support for authentication, and
+indicates a willingness to receive authentication
+information for automatic login.
+.It "DO ENCRYPT"
+Only sent if
+.Nm
+is compiled with support for data encryption, and
+indicates a willingness to decrypt
+the data stream.
+.El
+.Sh NOTES
+By default
+.Nm
+will read the
+.Em \&he ,
+.Em \&hn ,
+and
+.Em \&im
+capabilities from
+.Pa /etc/gettytab
+and use that information (if present) to determine
+what to display before the login: prompt.
+You can
+also use a System V style
+.Pa /etc/issue
+file by using the
+.Em \&if
+capability, which will override
+.Em \&im .
+The information specified in either
+.Em \&im
+or
+.Em \&if
+will be displayed to both console and remote logins.
+.\" .Sh ENVIRONMENT
+.Sh FILES
+.Bl -tag -width /usr/ucb/bftp -compact
+.It Pa /etc/services
+.It Pa /etc/gettytab
+.It Pa /etc/iptos
+(if supported)
+.It Pa /usr/ucb/bftp
+(if supported)
+.El
+.Sh "SEE ALSO"
+.Xr bftp 1 ,
+.Xr login 1 ,
+.Xr telnet 1
+(if supported),
+.Xr gettytab 5
+.Sh STANDARDS
+.Bl -tag -compact -width RFC-1572
+.It Cm RFC-854
+.Tn TELNET
+PROTOCOL SPECIFICATION
+.It Cm RFC-855
+TELNET OPTION SPECIFICATIONS
+.It Cm RFC-856
+TELNET BINARY TRANSMISSION
+.It Cm RFC-857
+TELNET ECHO OPTION
+.It Cm RFC-858
+TELNET SUPPRESS GO AHEAD OPTION
+.It Cm RFC-859
+TELNET STATUS OPTION
+.It Cm RFC-860
+TELNET TIMING MARK OPTION
+.It Cm RFC-861
+TELNET EXTENDED OPTIONS - LIST OPTION
+.It Cm RFC-885
+TELNET END OF RECORD OPTION
+.It Cm RFC-1073
+Telnet Window Size Option
+.It Cm RFC-1079
+Telnet Terminal Speed Option
+.It Cm RFC-1091
+Telnet Terminal-Type Option
+.It Cm RFC-1096
+Telnet X Display Location Option
+.It Cm RFC-1123
+Requirements for Internet Hosts -- Application and Support
+.It Cm RFC-1184
+Telnet Linemode Option
+.It Cm RFC-1372
+Telnet Remote Flow Control Option
+.It Cm RFC-1416
+Telnet Authentication Option
+.It Cm RFC-1411
+Telnet Authentication: Kerberos Version 4
+.It Cm RFC-1412
+Telnet Authentication: SPX
+.It Cm RFC-1571
+Telnet Environment Option Interoperability Issues
+.It Cm RFC-1572
+Telnet Environment Option
+.El
+.Sh HISTORY
+IPv6 support was added by WIDE/KAME project.
+.Sh BUGS
+Some
+.Tn TELNET
+commands are only partially implemented.
+.Pp
+Because of bugs in the original
+.Bx 4.2
+.Xr telnet 1 ,
+.Nm
+performs some dubious protocol exchanges to try to discover if the remote
+client is, in fact, a
+.Bx 4.2
+.Xr telnet 1 .
+.Pp
+Binary mode
+has no common interpretation except between similar operating systems
+(Unix in this case).
+.Pp
+The terminal type name received from the remote client is converted to
+lower case.
+.Pp
+.Nm Telnetd
+never sends
+.Tn TELNET
+.Dv IAC GA
+(go ahead) commands.
diff --git a/remote_cmds/telnetd.tproj/telnetd.c b/remote_cmds/telnetd.tproj/telnetd.c
new file mode 100644
index 0000000..a952a93
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/telnetd.c
@@ -0,0 +1,1330 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)telnetd.c 8.4 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/telnetd.c,v 1.29 2006/09/26 21:46:11 ru Exp $");
+
+#include "telnetd.h"
+#include "pathnames.h"
+
+#include <sys/mman.h>
+#include <err.h>
+#ifndef __APPLE__
+#include <libutil.h>
+#endif
+#include <paths.h>
+#include <termcap.h>
+#ifndef __APPLE__
+#include <utmp.h>
+#endif
+
+#include <arpa/inet.h>
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+int auth_level = 0;
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+#include <libtelnet/misc.h>
+
+char remote_hostname[MAXHOSTNAMELEN];
+size_t utmp_len = sizeof(remote_hostname) - 1;
+int registerd_host_only = 0;
+
+
+/*
+ * I/O data buffers,
+ * pointers, and counters.
+ */
+char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
+char ptyibuf2[BUFSIZ];
+
+int readstream(int, char *, int);
+void doit(struct sockaddr *);
+int terminaltypeok(char *);
+
+int hostinfo = 1; /* do we print login banner? */
+
+static int debug = 0;
+int keepalive = 1;
+const char *altlogin;
+
+void doit(struct sockaddr *);
+int terminaltypeok(char *);
+void startslave(char *, int, char *);
+extern void usage(void);
+static void _gettermname(void);
+
+/*
+ * The string to pass to getopt(). We do it this way so
+ * that only the actual options that we support will be
+ * passed off to getopt().
+ */
+char valid_opts[] = {
+ 'd', ':', 'h', 'k', 'n', 'p', ':', 'S', ':', 'u', ':', 'U',
+ '4', '6',
+#ifdef AUTHENTICATION
+ 'a', ':', 'X', ':',
+#endif
+#ifdef BFTPDAEMON
+ 'B',
+#endif
+#ifdef DIAGNOSTICS
+ 'D', ':',
+#endif
+#ifdef ENCRYPTION
+ 'e', ':',
+#endif
+#ifdef LINEMODE
+ 'l',
+#endif
+ '\0'
+};
+
+int family = AF_INET;
+
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif /* MAXHOSTNAMELEN */
+
+char *hostname;
+char host_name[MAXHOSTNAMELEN];
+
+extern void telnet(int, int, char *);
+
+int level;
+char user_name[256];
+
+int
+main(int argc, char *argv[])
+{
+ u_long ultmp;
+ struct sockaddr_storage from;
+#ifdef __APPLE__
+ int on = 1;
+ socklen_t fromlen;
+#else
+ int on = 1, fromlen;
+#endif
+ int ch;
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ int tos = -1;
+#endif
+ char *ep;
+
+ // radar:17828581
+ (void)signal(SIGTERM, SIG_DFL);
+
+ pfrontp = pbackp = ptyobuf;
+ netip = netibuf;
+ nfrontp = nbackp = netobuf;
+#ifdef ENCRYPTION
+ nclearto = 0;
+#endif /* ENCRYPTION */
+
+ /*
+ * This initialization causes linemode to default to a configuration
+ * that works on all telnet clients, including the FreeBSD client.
+ * This is not quite the same as the telnet client issuing a "mode
+ * character" command, but has most of the same benefits, and is
+ * preferable since some clients (like usofts) don't have the
+ * mode character command anyway and linemode breaks things.
+ * The most notable symptom of fix is that csh "set filec" operations
+ * like <ESC> (filename completion) and ^D (choices) keys now work
+ * in telnet sessions and can be used more than once on the same line.
+ * CR/LF handling is also corrected in some termio modes. This
+ * change resolves problem reports bin/771 and bin/1037.
+ */
+
+ linemode=1; /*Default to mode that works on bulk of clients*/
+
+ while ((ch = getopt(argc, argv, valid_opts)) != -1) {
+ switch(ch) {
+
+#ifdef AUTHENTICATION
+ case 'a':
+ /*
+ * Check for required authentication level
+ */
+ if (strcmp(optarg, "debug") == 0) {
+ extern int auth_debug_mode;
+ auth_debug_mode = 1;
+ } else if (strcasecmp(optarg, "none") == 0) {
+ auth_level = 0;
+ } else if (strcasecmp(optarg, "other") == 0) {
+ auth_level = AUTH_OTHER;
+ } else if (strcasecmp(optarg, "user") == 0) {
+ auth_level = AUTH_USER;
+ } else if (strcasecmp(optarg, "valid") == 0) {
+ auth_level = AUTH_VALID;
+ } else if (strcasecmp(optarg, "off") == 0) {
+ /*
+ * This hack turns off authentication
+ */
+ auth_level = -1;
+ } else {
+ warnx("unknown authorization level for -a");
+ }
+ break;
+#endif /* AUTHENTICATION */
+
+#ifdef BFTPDAEMON
+ case 'B':
+ bftpd++;
+ break;
+#endif /* BFTPDAEMON */
+
+ case 'd':
+ if (strcmp(optarg, "ebug") == 0) {
+ debug++;
+ break;
+ }
+ usage();
+ /* NOTREACHED */
+ break;
+
+#ifdef DIAGNOSTICS
+ case 'D':
+ /*
+ * Check for desired diagnostics capabilities.
+ */
+ if (!strcmp(optarg, "report")) {
+ diagnostic |= TD_REPORT|TD_OPTIONS;
+ } else if (!strcmp(optarg, "exercise")) {
+ diagnostic |= TD_EXERCISE;
+ } else if (!strcmp(optarg, "netdata")) {
+ diagnostic |= TD_NETDATA;
+ } else if (!strcmp(optarg, "ptydata")) {
+ diagnostic |= TD_PTYDATA;
+ } else if (!strcmp(optarg, "options")) {
+ diagnostic |= TD_OPTIONS;
+ } else {
+ usage();
+ /* NOT REACHED */
+ }
+ break;
+#endif /* DIAGNOSTICS */
+
+#ifdef ENCRYPTION
+ case 'e':
+ if (strcmp(optarg, "debug") == 0) {
+ extern int encrypt_debug_mode;
+ encrypt_debug_mode = 1;
+ break;
+ }
+ usage();
+ /* NOTREACHED */
+ break;
+#endif /* ENCRYPTION */
+
+ case 'h':
+ hostinfo = 0;
+ break;
+
+#ifdef LINEMODE
+ case 'l':
+ alwayslinemode = 1;
+ break;
+#endif /* LINEMODE */
+
+ case 'k':
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ lmodetype = NO_AUTOKLUDGE;
+#else
+ /* ignore -k option if built without kludge linemode */
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+ break;
+
+ case 'n':
+ keepalive = 0;
+ break;
+
+ case 'p':
+ altlogin = optarg;
+ break;
+
+ case 'S':
+#ifdef HAS_GETTOS
+ if ((tos = parsetos(optarg, "tcp")) < 0)
+ warnx("%s%s%s",
+ "bad TOS argument '", optarg,
+ "'; will try to use default TOS");
+#else
+#define MAXTOS 255
+ ultmp = strtoul(optarg, &ep, 0);
+ if (*ep || ep == optarg || ultmp > MAXTOS)
+ warnx("%s%s%s",
+ "bad TOS argument '", optarg,
+ "'; will try to use default TOS");
+ else
+ tos = ultmp;
+#endif
+ break;
+
+ case 'u':
+ utmp_len = (size_t)atoi(optarg);
+ if (utmp_len >= sizeof(remote_hostname))
+ utmp_len = sizeof(remote_hostname) - 1;
+ break;
+
+ case 'U':
+ registerd_host_only = 1;
+ break;
+
+#ifdef AUTHENTICATION
+ case 'X':
+ /*
+ * Check for invalid authentication types
+ */
+ auth_disable_name(optarg);
+ break;
+#endif /* AUTHENTICATION */
+
+ case '4':
+ family = AF_INET;
+ break;
+
+#ifdef INET6
+ case '6':
+ family = AF_INET6;
+ break;
+#endif
+
+ default:
+ warnx("%c: unknown option", ch);
+ /* FALLTHROUGH */
+ case '?':
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (debug) {
+#ifdef __APPLE__
+ int s, ns, error;
+ socklen_t foo;
+#else
+ int s, ns, foo, error;
+#endif
+ const char *service = "telnet";
+ struct addrinfo hints, *res;
+
+ if (argc > 1) {
+ usage();
+ /* NOT REACHED */
+ } else if (argc == 1)
+ service = *argv;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_family = family;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ error = getaddrinfo(NULL, service, &hints, &res);
+
+ if (error) {
+ errx(1, "tcp/%s: %s\n", service, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ errx(1, "tcp/%s: %s\n", service, strerror(errno));
+ usage();
+ }
+
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s < 0)
+ err(1, "socket");
+ (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on));
+ if (debug > 1)
+ (void) setsockopt(s, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ if (bind(s, res->ai_addr, res->ai_addrlen) < 0)
+ err(1, "bind");
+ if (listen(s, 1) < 0)
+ err(1, "listen");
+ foo = res->ai_addrlen;
+ ns = accept(s, res->ai_addr, &foo);
+ if (ns < 0)
+ err(1, "accept");
+ (void) setsockopt(ns, SOL_SOCKET, SO_DEBUG,
+ (char *)&on, sizeof(on));
+ (void) dup2(ns, 0);
+ (void) close(ns);
+ (void) close(s);
+#ifdef convex
+ } else if (argc == 1) {
+ ; /* VOID*/ /* Just ignore the host/port name */
+#endif
+ } else if (argc > 0) {
+ usage();
+ /* NOT REACHED */
+ }
+
+ openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+ fromlen = sizeof (from);
+ if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ warn("getpeername");
+ _exit(1);
+ }
+ if (keepalive &&
+ setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof (on)) < 0) {
+ syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
+ }
+
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ if (from.ss_family == AF_INET) {
+# if defined(HAS_GETTOS)
+ struct tosent *tp;
+ if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+ tos = tp->t_tos;
+# endif
+ if (tos < 0)
+ tos = 020; /* Low Delay bit */
+ if (tos
+ && (setsockopt(0, IPPROTO_IP, IP_TOS,
+ (char *)&tos, sizeof(tos)) < 0)
+ && (errno != ENOPROTOOPT) )
+ syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+ }
+#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
+ net = 0;
+ doit((struct sockaddr *)&from);
+ /* NOTREACHED */
+ return(0);
+} /* end of main */
+
+ void
+usage()
+{
+ fprintf(stderr, "usage: telnetd");
+#ifdef AUTHENTICATION
+ fprintf(stderr,
+ " [-4] [-6] [-a (debug|other|user|valid|off|none)]\n\t");
+#endif
+#ifdef BFTPDAEMON
+ fprintf(stderr, " [-B]");
+#endif
+ fprintf(stderr, " [-debug]");
+#ifdef DIAGNOSTICS
+ fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
+#endif
+#ifdef AUTHENTICATION
+ fprintf(stderr, " [-edebug]");
+#endif
+ fprintf(stderr, " [-h]");
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ fprintf(stderr, " [-k]");
+#endif
+#ifdef LINEMODE
+ fprintf(stderr, " [-l]");
+#endif
+ fprintf(stderr, " [-n]");
+ fprintf(stderr, "\n\t");
+#ifdef HAS_GETTOS
+ fprintf(stderr, " [-S tos]");
+#endif
+#ifdef AUTHENTICATION
+ fprintf(stderr, " [-X auth-type]");
+#endif
+ fprintf(stderr, " [-u utmp_hostname_length] [-U]");
+ fprintf(stderr, " [port]\n");
+ exit(1);
+}
+
+/*
+ * getterminaltype
+ *
+ * Ask the other end to send along its terminal type and speed.
+ * Output is the variable terminaltype filled in.
+ */
+static unsigned char ttytype_sbbuf[] = {
+ IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE
+};
+
+
+#ifndef AUTHENTICATION
+#define undef2 __unused
+#else
+#define undef2
+#endif
+
+static int
+getterminaltype(char *name undef2)
+{
+ int retval = -1;
+
+ settimer(baseline);
+#ifdef AUTHENTICATION
+ /*
+ * Handle the Authentication option before we do anything else.
+ */
+ send_do(TELOPT_AUTHENTICATION, 1);
+ while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
+ ttloop();
+ if (his_state_is_will(TELOPT_AUTHENTICATION)) {
+ retval = auth_wait(name);
+ }
+#endif
+
+#ifdef ENCRYPTION
+ send_will(TELOPT_ENCRYPT, 1);
+#endif /* ENCRYPTION */
+ send_do(TELOPT_TTYPE, 1);
+ send_do(TELOPT_TSPEED, 1);
+ send_do(TELOPT_XDISPLOC, 1);
+ send_do(TELOPT_NEW_ENVIRON, 1);
+ send_do(TELOPT_OLD_ENVIRON, 1);
+ while (
+#ifdef ENCRYPTION
+ his_do_dont_is_changing(TELOPT_ENCRYPT) ||
+#endif /* ENCRYPTION */
+ his_will_wont_is_changing(TELOPT_TTYPE) ||
+ his_will_wont_is_changing(TELOPT_TSPEED) ||
+ his_will_wont_is_changing(TELOPT_XDISPLOC) ||
+ his_will_wont_is_changing(TELOPT_NEW_ENVIRON) ||
+ his_will_wont_is_changing(TELOPT_OLD_ENVIRON)) {
+ ttloop();
+ }
+#ifdef ENCRYPTION
+ /*
+ * Wait for the negotiation of what type of encryption we can
+ * send with. If autoencrypt is not set, this will just return.
+ */
+ if (his_state_is_will(TELOPT_ENCRYPT)) {
+ encrypt_wait();
+ }
+#endif /* ENCRYPTION */
+ if (his_state_is_will(TELOPT_TSPEED)) {
+ static unsigned char sb[] =
+ { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
+
+ output_datalen((char*)sb, sizeof sb);
+ DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+ }
+ if (his_state_is_will(TELOPT_XDISPLOC)) {
+ static unsigned char sb[] =
+ { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
+
+ output_datalen((char*)sb, sizeof sb);
+ DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+ }
+ if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
+ static unsigned char sb[] =
+ { IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+ output_datalen((char*)sb, sizeof sb);
+ DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+ }
+ else if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
+ static unsigned char sb[] =
+ { IAC, SB, TELOPT_OLD_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+ output_datalen((char*)sb, sizeof sb);
+ DIAG(TD_OPTIONS, printsub('>', sb + 2, sizeof sb - 2););
+ }
+ if (his_state_is_will(TELOPT_TTYPE)) {
+
+ output_datalen((char*)ttytype_sbbuf, sizeof ttytype_sbbuf);
+ DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
+ sizeof ttytype_sbbuf - 2););
+ }
+ if (his_state_is_will(TELOPT_TSPEED)) {
+ while (sequenceIs(tspeedsubopt, baseline))
+ ttloop();
+ }
+ if (his_state_is_will(TELOPT_XDISPLOC)) {
+ while (sequenceIs(xdisplocsubopt, baseline))
+ ttloop();
+ }
+ if (his_state_is_will(TELOPT_NEW_ENVIRON)) {
+ while (sequenceIs(environsubopt, baseline))
+ ttloop();
+ }
+ if (his_state_is_will(TELOPT_OLD_ENVIRON)) {
+ while (sequenceIs(oenvironsubopt, baseline))
+ ttloop();
+ }
+ if (his_state_is_will(TELOPT_TTYPE)) {
+ char first[256], last[256];
+
+ while (sequenceIs(ttypesubopt, baseline))
+ ttloop();
+
+ /*
+ * If the other side has already disabled the option, then
+ * we have to just go with what we (might) have already gotten.
+ */
+ if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
+ (void) strncpy(first, terminaltype, sizeof(first)-1);
+ first[sizeof(first)-1] = '\0';
+ for(;;) {
+ /*
+ * Save the unknown name, and request the next name.
+ */
+ (void) strncpy(last, terminaltype, sizeof(last)-1);
+ last[sizeof(last)-1] = '\0';
+ _gettermname();
+ if (terminaltypeok(terminaltype))
+ break;
+ if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
+ his_state_is_wont(TELOPT_TTYPE)) {
+ /*
+ * We've hit the end. If this is the same as
+ * the first name, just go with it.
+ */
+ if (strncmp(first, terminaltype, sizeof(first)) == 0)
+ break;
+ /*
+ * Get the terminal name one more time, so that
+ * RFC1091 compliant telnets will cycle back to
+ * the start of the list.
+ */
+ _gettermname();
+ if (strncmp(first, terminaltype, sizeof(first)) != 0) {
+ (void) strncpy(terminaltype, first, sizeof(terminaltype)-1);
+ terminaltype[sizeof(terminaltype)-1] = '\0';
+ }
+ break;
+ }
+ }
+ }
+ }
+ return(retval);
+} /* end of getterminaltype */
+
+static void
+_gettermname(void)
+{
+ /*
+ * If the client turned off the option,
+ * we can't send another request, so we
+ * just return.
+ */
+ if (his_state_is_wont(TELOPT_TTYPE))
+ return;
+ settimer(baseline);
+ output_datalen((char*)ttytype_sbbuf, sizeof ttytype_sbbuf);
+ DIAG(TD_OPTIONS, printsub('>', ttytype_sbbuf + 2,
+ sizeof ttytype_sbbuf - 2););
+ while (sequenceIs(ttypesubopt, baseline))
+ ttloop();
+}
+
+int
+terminaltypeok(char *s)
+{
+ char buf[1024];
+
+ if (terminaltype == NULL)
+ return(1);
+
+ /*
+ * tgetent() will return 1 if the type is known, and
+ * 0 if it is not known. If it returns -1, it couldn't
+ * open the database. But if we can't open the database,
+ * it won't help to say we failed, because we won't be
+ * able to verify anything else. So, we treat -1 like 1.
+ */
+ if (tgetent(buf, s) == 0)
+ return(0);
+ return(1);
+}
+
+#ifdef __APPLE__
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 256
+#endif /* MAXHOSTNAMELEN */
+
+char *hostname;
+char host_name[MAXHOSTNAMELEN];
+
+int level;
+char user_name[256];
+#endif /* __APPLE__ */
+
+/*
+ * Get a pty, scan input lines.
+ */
+void
+doit(struct sockaddr *who)
+{
+#ifndef __APPLE__
+ int err_; /* XXX */
+#else
+ char *host = NULL;
+ struct hostent *hp;
+#endif
+ int ptynum;
+
+ /*
+ * Find an available pty to use.
+ */
+#ifndef convex
+ spty = -1;
+ mpty = getpty(&ptynum, &spty);
+ if (mpty < 0)
+ fatal(net, "All network ports in use");
+#else
+ for (;;) {
+ char *lp;
+
+ if ((lp = getpty()) == NULL)
+ fatal(net, "Out of ptys");
+
+ if ((pty = open(lp, 2)) >= 0) {
+ strlcpy(line,lp,sizeof(line));
+ line[5] = 't';
+ break;
+ }
+ }
+#endif
+
+#ifdef __APPLE__
+ /* get name of connected client */
+ hp = gethostbyaddr((char *)&((struct sockaddr_in *)who)->sin_addr, sizeof (struct in_addr),
+ ((struct sockaddr_in *)who)->sin_family);
+
+ if (hp == NULL && registerd_host_only) {
+ fatal(net, "Couldn't resolve your address into a host name.\r\n\
+ Please contact your net administrator");
+ } else if (hp &&
+ (strlen(hp->h_name) <= utmp_len)) {
+ host = hp->h_name;
+ } else {
+ host = inet_ntoa(((struct sockaddr_in *)who)->sin_addr);
+ }
+ /*
+ * We must make a copy because Kerberos is probably going
+ * to also do a gethost* and overwrite the static data...
+ */
+ strncpy(remote_hostname, host, sizeof(remote_hostname)-1);
+ remote_hostname[sizeof(remote_hostname)-1] = 0;
+ host = remote_hostname;
+
+ (void) gethostname(host_name, sizeof(host_name) - 1);
+ host_name[sizeof(host_name) - 1] = '\0';
+ hostname = host_name;
+#else /* __APPLE__ */
+ /* get name of connected client */
+ if (realhostname_sa(remote_hostname, sizeof(remote_hostname) - 1,
+ who, who->sa_len) == HOSTNAME_INVALIDADDR && registerd_host_only)
+ fatal(net, "Couldn't resolve your address into a host name.\r\n\
+ Please contact your net administrator");
+ remote_hostname[sizeof(remote_hostname) - 1] = '\0';
+
+ trimdomain(remote_hostname, UT_HOSTSIZE);
+ if (!isdigit(remote_hostname[0]) && strlen(remote_hostname) > utmp_len)
+ err_ = getnameinfo(who, who->sa_len, remote_hostname,
+ sizeof(remote_hostname), NULL, 0,
+ NI_NUMERICHOST);
+ /* XXX: do 'err_' check */
+
+ (void) gethostname(host_name, sizeof(host_name) - 1);
+ host_name[sizeof(host_name) - 1] = '\0';
+ hostname = host_name;
+#endif /* __APPLE__ */
+
+#ifdef AUTHENTICATION
+#ifdef ENCRYPTION
+/* The above #ifdefs should actually be "or"'ed, not "and"'ed.
+ * This is a byproduct of needing "#ifdef" and not "#if defined()"
+ * for unifdef. XXX MarkM
+ */
+ auth_encrypt_init(hostname, remote_hostname, "TELNETD", 1);
+#endif
+#endif
+
+ init_env();
+ /*
+ * get terminal type.
+ */
+ *user_name = 0;
+ level = getterminaltype(user_name);
+ setenv("TERM", terminaltype ? terminaltype : "network", 1);
+
+ telnet(net, mpty, remote_hostname); /* begin server process */
+
+ /*NOTREACHED*/
+} /* end of doit */
+
+/*
+ * Main loop. Select from pty and network, and
+ * hand data to telnet receiver finite state machine.
+ */
+void
+telnet(int f, int p, char *host)
+{
+ int on = 1;
+#define TABBUFSIZ 512
+ char defent[TABBUFSIZ];
+ char defstrs[TABBUFSIZ];
+#undef TABBUFSIZ
+ char *HE;
+ char *HN;
+ char *IM;
+#ifdef __APPLE__
+ char *IF = NULL;
+ int if_fd = -1;
+ char *if_buf;
+ struct stat statbuf;
+#endif
+ int nfd;
+
+ /*
+ * Initialize the slc mapping table.
+ */
+ get_slc_defaults();
+
+ /*
+ * Do some tests where it is desireable to wait for a response.
+ * Rather than doing them slowly, one at a time, do them all
+ * at once.
+ */
+ if (my_state_is_wont(TELOPT_SGA))
+ send_will(TELOPT_SGA, 1);
+ /*
+ * Is the client side a 4.2 (NOT 4.3) system? We need to know this
+ * because 4.2 clients are unable to deal with TCP urgent data.
+ *
+ * To find out, we send out a "DO ECHO". If the remote system
+ * answers "WILL ECHO" it is probably a 4.2 client, and we note
+ * that fact ("WILL ECHO" ==> that the client will echo what
+ * WE, the server, sends it; it does NOT mean that the client will
+ * echo the terminal input).
+ */
+ send_do(TELOPT_ECHO, 1);
+
+#ifdef LINEMODE
+ if (his_state_is_wont(TELOPT_LINEMODE)) {
+ /* Query the peer for linemode support by trying to negotiate
+ * the linemode option.
+ */
+ linemode = 0;
+ editmode = 0;
+ send_do(TELOPT_LINEMODE, 1); /* send do linemode */
+ }
+#endif /* LINEMODE */
+
+ /*
+ * Send along a couple of other options that we wish to negotiate.
+ */
+ send_do(TELOPT_NAWS, 1);
+ send_will(TELOPT_STATUS, 1);
+ flowmode = 1; /* default flow control state */
+ restartany = -1; /* uninitialized... */
+ send_do(TELOPT_LFLOW, 1);
+
+ /*
+ * Spin, waiting for a response from the DO ECHO. However,
+ * some REALLY DUMB telnets out there might not respond
+ * to the DO ECHO. So, we spin looking for NAWS, (most dumb
+ * telnets so far seem to respond with WONT for a DO that
+ * they don't understand...) because by the time we get the
+ * response, it will already have processed the DO ECHO.
+ * Kludge upon kludge.
+ */
+ while (his_will_wont_is_changing(TELOPT_NAWS))
+ ttloop();
+
+ /*
+ * But...
+ * The client might have sent a WILL NAWS as part of its
+ * startup code; if so, we'll be here before we get the
+ * response to the DO ECHO. We'll make the assumption
+ * that any implementation that understands about NAWS
+ * is a modern enough implementation that it will respond
+ * to our DO ECHO request; hence we'll do another spin
+ * waiting for the ECHO option to settle down, which is
+ * what we wanted to do in the first place...
+ */
+ if (his_want_state_is_will(TELOPT_ECHO) &&
+ his_state_is_will(TELOPT_NAWS)) {
+ while (his_will_wont_is_changing(TELOPT_ECHO))
+ ttloop();
+ }
+ /*
+ * On the off chance that the telnet client is broken and does not
+ * respond to the DO ECHO we sent, (after all, we did send the
+ * DO NAWS negotiation after the DO ECHO, and we won't get here
+ * until a response to the DO NAWS comes back) simulate the
+ * receipt of a will echo. This will also send a WONT ECHO
+ * to the client, since we assume that the client failed to
+ * respond because it believes that it is already in DO ECHO
+ * mode, which we do not want.
+ */
+ if (his_want_state_is_will(TELOPT_ECHO)) {
+ DIAG(TD_OPTIONS, output_data("td: simulating recv\r\n"));
+ willoption(TELOPT_ECHO);
+ }
+
+ /*
+ * Finally, to clean things up, we turn on our echo. This
+ * will break stupid 4.2 telnets out of local terminal echo.
+ */
+
+ if (my_state_is_wont(TELOPT_ECHO))
+ send_will(TELOPT_ECHO, 1);
+
+ /*
+ * Turn on packet mode
+ */
+ (void) ioctl(p, TIOCPKT, (char *)&on);
+
+#if defined(LINEMODE) && defined(KLUDGELINEMODE)
+ /*
+ * Continuing line mode support. If client does not support
+ * real linemode, attempt to negotiate kludge linemode by sending
+ * the do timing mark sequence.
+ */
+ if (lmodetype < REAL_LINEMODE)
+ send_do(TELOPT_TM, 1);
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+
+ /*
+ * Call telrcv() once to pick up anything received during
+ * terminal type negotiation, 4.2/4.3 determination, and
+ * linemode negotiation.
+ */
+ telrcv();
+
+ (void) ioctl(f, FIONBIO, (char *)&on);
+ (void) ioctl(p, FIONBIO, (char *)&on);
+
+#if defined(SO_OOBINLINE)
+ (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
+ (char *)&on, sizeof on);
+#endif /* defined(SO_OOBINLINE) */
+
+#ifdef SIGTSTP
+ (void) signal(SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+ /*
+ * Ignoring SIGTTOU keeps the kernel from blocking us
+ * in ttioct() in /sys/tty.c.
+ */
+ (void) signal(SIGTTOU, SIG_IGN);
+#endif
+
+ (void) signal(SIGCHLD, cleanup);
+
+#ifdef TIOCNOTTY
+ {
+ int t;
+ t = open(_PATH_TTY, O_RDWR);
+ if (t >= 0) {
+ (void) ioctl(t, TIOCNOTTY, (char *)0);
+ (void) close(t);
+ }
+ }
+#endif
+
+ /*
+ * Show banner that getty never gave.
+ *
+ * We put the banner in the pty input buffer. This way, it
+ * gets carriage return null processing, etc., just like all
+ * other pty --> client data.
+ */
+
+#ifdef __APPLE__
+ if (getenv("USER"))
+ hostinfo = 0;
+#endif
+ if (getent(defent, "default") == 1) {
+ char *cp=defstrs;
+
+ HE = Getstr("he", &cp);
+ HN = Getstr("hn", &cp);
+ IM = Getstr("im", &cp);
+#ifdef __APPLE__
+ IF = Getstr("if", &cp);
+#endif
+ if (HN && *HN)
+ (void) strlcpy(host_name, HN, sizeof(host_name));
+#ifdef __APPLE__
+ if (IF && (if_fd = open(IF, O_RDONLY, 000)) != -1)
+ IM = 0;
+#endif
+ if (IM == 0)
+ IM = strdup("");
+ } else {
+ IM = strdup(DEFAULT_IM);
+ HE = 0;
+ }
+ edithost(HE, host_name);
+ if (hostinfo && *IM)
+ putf(IM, ptyibuf2);
+#ifdef __APPLE__
+ else if (IF && if_fd != -1) {
+ fstat (if_fd, &statbuf);
+ if_buf = (char *) mmap (0, statbuf.st_size, PROT_READ,
+ 0, if_fd, 0);
+ putf(if_buf, ptyibuf2);
+ munmap (if_buf, statbuf.st_size);
+ close (if_fd);
+ }
+#endif
+
+ if (pcc)
+ (void) strncat(ptyibuf2, ptyip, pcc+1);
+ ptyip = ptyibuf2;
+ pcc = strlen(ptyip);
+#ifdef LINEMODE
+ /*
+ * Last check to make sure all our states are correct.
+ */
+ init_termbuf();
+ localstat();
+#endif /* LINEMODE */
+
+ DIAG(TD_REPORT, output_data("td: Entering processing loop\r\n"));
+
+ /*
+ * Startup the login process on the slave side of the terminal
+ * now. We delay this until here to insure option negotiation
+ * is complete.
+ */
+ startslave(host, level, user_name);
+
+ nfd = ((f > p) ? f : p) + 1;
+ for (;;) {
+ fd_set ibits, obits, xbits;
+ int c;
+
+ if (ncc < 0 && pcc < 0)
+ break;
+
+ FD_ZERO(&ibits);
+ FD_ZERO(&obits);
+ FD_ZERO(&xbits);
+ /*
+ * Never look for input if there's still
+ * stuff in the corresponding output buffer
+ */
+ if (nfrontp - nbackp || pcc > 0) {
+ FD_SET(f, &obits);
+ } else {
+ FD_SET(p, &ibits);
+ }
+ if (pfrontp - pbackp || ncc > 0) {
+ FD_SET(p, &obits);
+ } else {
+ FD_SET(f, &ibits);
+ }
+ if (!SYNCHing) {
+ FD_SET(f, &xbits);
+ }
+ if ((c = select(nfd, &ibits, &obits, &xbits,
+ (struct timeval *)0)) < 1) {
+ if (c == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ }
+ sleep(5);
+ continue;
+ }
+
+ /*
+ * Any urgent data?
+ */
+ if (FD_ISSET(net, &xbits)) {
+ SYNCHing = 1;
+ }
+
+ /*
+ * Something to read from the network...
+ */
+ if (FD_ISSET(net, &ibits)) {
+#if !defined(SO_OOBINLINE)
+ /*
+ * In 4.2 (and 4.3 beta) systems, the
+ * OOB indication and data handling in the kernel
+ * is such that if two separate TCP Urgent requests
+ * come in, one byte of TCP data will be overlaid.
+ * This is fatal for Telnet, but we try to live
+ * with it.
+ *
+ * In addition, in 4.2 (and...), a special protocol
+ * is needed to pick up the TCP Urgent data in
+ * the correct sequence.
+ *
+ * What we do is: if we think we are in urgent
+ * mode, we look to see if we are "at the mark".
+ * If we are, we do an OOB receive. If we run
+ * this twice, we will do the OOB receive twice,
+ * but the second will fail, since the second
+ * time we were "at the mark", but there wasn't
+ * any data there (the kernel doesn't reset
+ * "at the mark" until we do a normal read).
+ * Once we've read the OOB data, we go ahead
+ * and do normal reads.
+ *
+ * There is also another problem, which is that
+ * since the OOB byte we read doesn't put us
+ * out of OOB state, and since that byte is most
+ * likely the TELNET DM (data mark), we would
+ * stay in the TELNET SYNCH (SYNCHing) state.
+ * So, clocks to the rescue. If we've "just"
+ * received a DM, then we test for the
+ * presence of OOB data when the receive OOB
+ * fails (and AFTER we did the normal mode read
+ * to clear "at the mark").
+ */
+ if (SYNCHing) {
+ int atmark;
+
+ (void) ioctl(net, SIOCATMARK, (char *)&atmark);
+ if (atmark) {
+ ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
+ if ((ncc == -1) && (errno == EINVAL)) {
+ ncc = read(net, netibuf, sizeof (netibuf));
+ if (sequenceIs(didnetreceive, gotDM)) {
+ SYNCHing = stilloob(net);
+ }
+ }
+ } else {
+ ncc = read(net, netibuf, sizeof (netibuf));
+ }
+ } else {
+ ncc = read(net, netibuf, sizeof (netibuf));
+ }
+ settimer(didnetreceive);
+#else /* !defined(SO_OOBINLINE)) */
+ ncc = read(net, netibuf, sizeof (netibuf));
+#endif /* !defined(SO_OOBINLINE)) */
+ if (ncc < 0 && errno == EWOULDBLOCK)
+ ncc = 0;
+ else {
+ if (ncc <= 0) {
+ break;
+ }
+ netip = netibuf;
+ }
+ DIAG((TD_REPORT | TD_NETDATA),
+ output_data("td: netread %d chars\r\n", ncc));
+ DIAG(TD_NETDATA, printdata("nd", netip, ncc));
+ }
+
+ /*
+ * Something to read from the pty...
+ */
+ if (FD_ISSET(p, &ibits)) {
+ pcc = read(p, ptyibuf, BUFSIZ);
+ /*
+ * On some systems, if we try to read something
+ * off the master side before the slave side is
+ * opened, we get EIO.
+ */
+ if (pcc < 0 && (errno == EWOULDBLOCK ||
+#ifdef EAGAIN
+ errno == EAGAIN ||
+#endif
+ errno == EIO)) {
+ pcc = 0;
+ } else {
+ if (pcc <= 0)
+ break;
+#ifdef LINEMODE
+ /*
+ * If ioctl from pty, pass it through net
+ */
+ if (ptyibuf[0] & TIOCPKT_IOCTL) {
+ copy_termbuf(ptyibuf+1, pcc-1);
+ localstat();
+ pcc = 1;
+ }
+#endif /* LINEMODE */
+ if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
+ netclear(); /* clear buffer back */
+#ifndef NO_URGENT
+ /*
+ * There are client telnets on some
+ * operating systems get screwed up
+ * royally if we send them urgent
+ * mode data.
+ */
+ output_data("%c%c", IAC, DM);
+ neturg = nfrontp-1; /* off by one XXX */
+ DIAG(TD_OPTIONS,
+ printoption("td: send IAC", DM));
+
+#endif
+ }
+ if (his_state_is_will(TELOPT_LFLOW) &&
+ (ptyibuf[0] &
+ (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
+ int newflow =
+ ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
+ if (newflow != flowmode) {
+ flowmode = newflow;
+ output_data("%c%c%c%c%c%c",
+ IAC, SB, TELOPT_LFLOW,
+ flowmode ? LFLOW_ON
+ : LFLOW_OFF,
+ IAC, SE);
+ DIAG(TD_OPTIONS, printsub('>',
+ (unsigned char *)nfrontp-4,
+ 4););
+ }
+ }
+ pcc--;
+ ptyip = ptyibuf+1;
+ }
+ }
+
+ while (pcc > 0) {
+ if ((&netobuf[BUFSIZ] - nfrontp) < 2)
+ break;
+ c = *ptyip++ & 0377, pcc--;
+ if (c == IAC)
+ output_data("%c", c);
+ output_data("%c", c);
+ if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
+ if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
+ output_data("%c", *ptyip++ & 0377);
+ pcc--;
+ } else
+ output_data("%c", '\0');
+ }
+ }
+
+ if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
+ netflush();
+ if (ncc > 0)
+ telrcv();
+ if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
+ ptyflush();
+ }
+ cleanup(0);
+} /* end of telnet */
+
+#ifndef TCSIG
+# ifdef TIOCSIG
+# define TCSIG TIOCSIG
+# endif
+#endif
+
+/*
+ * Send interrupt to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write intr char.
+ */
+void
+interrupt(void)
+{
+ ptyflush(); /* half-hearted */
+
+#ifdef TCSIG
+ (void) ioctl(mpty, TCSIG, (char *)SIGINT);
+#else /* TCSIG */
+ init_termbuf();
+ *pfrontp++ = slctab[SLC_IP].sptr ?
+ (unsigned char)*slctab[SLC_IP].sptr : '\177';
+#endif /* TCSIG */
+}
+
+/*
+ * Send quit to process on other side of pty.
+ * If it is in raw mode, just write NULL;
+ * otherwise, write quit char.
+ */
+void
+sendbrk(void)
+{
+ ptyflush(); /* half-hearted */
+#ifdef TCSIG
+ (void) ioctl(mpty, TCSIG, (char *)SIGQUIT);
+#else /* TCSIG */
+ init_termbuf();
+ *pfrontp++ = slctab[SLC_ABORT].sptr ?
+ (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
+#endif /* TCSIG */
+}
+
+void
+sendsusp(void)
+{
+#ifdef SIGTSTP
+ ptyflush(); /* half-hearted */
+# ifdef TCSIG
+ (void) ioctl(mpty, TCSIG, (char *)SIGTSTP);
+# else /* TCSIG */
+ *pfrontp++ = slctab[SLC_SUSP].sptr ?
+ (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
+# endif /* TCSIG */
+#endif /* SIGTSTP */
+}
+
+/*
+ * When we get an AYT, if ^T is enabled, use that. Otherwise,
+ * just send back "[Yes]".
+ */
+void
+recv_ayt(void)
+{
+#if defined(SIGINFO) && defined(TCSIG)
+ if (slctab[SLC_AYT].sptr && *slctab[SLC_AYT].sptr != _POSIX_VDISABLE) {
+ (void) ioctl(spty, TCSIG, (char *)SIGINFO);
+ return;
+ }
+#endif
+ output_data("\r\n[Yes]\r\n");
+}
+
+void
+doeof(void)
+{
+ init_termbuf();
+
+#if defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
+ if (!tty_isediting()) {
+ extern char oldeofc;
+ *pfrontp++ = oldeofc;
+ return;
+ }
+#endif
+ *pfrontp++ = slctab[SLC_EOF].sptr ?
+ (unsigned char)*slctab[SLC_EOF].sptr : '\004';
+}
diff --git a/remote_cmds/telnetd.tproj/telnetd.h b/remote_cmds/telnetd.tproj/telnetd.h
new file mode 100644
index 0000000..e99a7c9
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/telnetd.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)telnetd.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/contrib/telnet/telnetd/telnetd.h,v 1.2 2001/11/30 21:06:38 markm Exp $
+ */
+
+
+#include "defs.h"
+#include "ext.h"
+
+#ifdef DIAGNOSTICS
+#define DIAG(a,b) if (diagnostic & (a)) b
+#else
+#define DIAG(a,b)
+#endif
+
+/* other external variables */
+extern char **environ;
+extern const char *altlogin;
diff --git a/remote_cmds/telnetd.tproj/termstat.c b/remote_cmds/telnetd.tproj/termstat.c
new file mode 100644
index 0000000..e29e526
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/termstat.c
@@ -0,0 +1,632 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)termstat.c 8.2 (Berkeley) 5/30/95";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/termstat.c,v 1.13 2004/07/28 05:37:18 kan Exp $");
+
+#include "telnetd.h"
+
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+/*
+ * local variables
+ */
+int def_tspeed = -1, def_rspeed = -1;
+#ifdef TIOCSWINSZ
+int def_row = 0, def_col = 0;
+#endif
+#ifdef LINEMODE
+static int _terminit = 0;
+#endif /* LINEMODE */
+
+#ifdef LINEMODE
+/*
+ * localstat
+ *
+ * This function handles all management of linemode.
+ *
+ * Linemode allows the client to do the local editing of data
+ * and send only complete lines to the server. Linemode state is
+ * based on the state of the pty driver. If the pty is set for
+ * external processing, then we can use linemode. Further, if we
+ * can use real linemode, then we can look at the edit control bits
+ * in the pty to determine what editing the client should do.
+ *
+ * Linemode support uses the following state flags to keep track of
+ * current and desired linemode state.
+ * alwayslinemode : true if -l was specified on the telnetd
+ * command line. It means to have linemode on as much as
+ * possible.
+ *
+ * lmodetype: signifies whether the client can
+ * handle real linemode, or if use of kludgeomatic linemode
+ * is preferred. It will be set to one of the following:
+ * REAL_LINEMODE : use linemode option
+ * NO_KLUDGE : don't initiate kludge linemode.
+ * KLUDGE_LINEMODE : use kludge linemode
+ * NO_LINEMODE : client is ignorant of linemode
+ *
+ * linemode, uselinemode : linemode is true if linemode
+ * is currently on, uselinemode is the state that we wish
+ * to be in. If another function wishes to turn linemode
+ * on or off, it sets or clears uselinemode.
+ *
+ * editmode, useeditmode : like linemode/uselinemode, but
+ * these contain the edit mode states (edit and trapsig).
+ *
+ * The state variables correspond to some of the state information
+ * in the pty.
+ * linemode:
+ * In real linemode, this corresponds to whether the pty
+ * expects external processing of incoming data.
+ * In kludge linemode, this more closely corresponds to the
+ * whether normal processing is on or not. (ICANON in
+ * system V, or COOKED mode in BSD.)
+ * If the -l option was specified (alwayslinemode), then
+ * an attempt is made to force external processing on at
+ * all times.
+ *
+ * The following heuristics are applied to determine linemode
+ * handling within the server.
+ * 1) Early on in starting up the server, an attempt is made
+ * to negotiate the linemode option. If this succeeds
+ * then lmodetype is set to REAL_LINEMODE and all linemode
+ * processing occurs in the context of the linemode option.
+ * 2) If the attempt to negotiate the linemode option failed,
+ * and the "-k" (don't initiate kludge linemode) isn't set,
+ * then we try to use kludge linemode. We test for this
+ * capability by sending "do Timing Mark". If a positive
+ * response comes back, then we assume that the client
+ * understands kludge linemode (ech!) and the
+ * lmodetype flag is set to KLUDGE_LINEMODE.
+ * 3) Otherwise, linemode is not supported at all and
+ * lmodetype remains set to NO_LINEMODE (which happens
+ * to be 0 for convenience).
+ * 4) At any time a command arrives that implies a higher
+ * state of linemode support in the client, we move to that
+ * linemode support.
+ *
+ * A short explanation of kludge linemode is in order here.
+ * 1) The heuristic to determine support for kludge linemode
+ * is to send a do timing mark. We assume that a client
+ * that supports timing marks also supports kludge linemode.
+ * A risky proposition at best.
+ * 2) Further negotiation of linemode is done by changing the
+ * the server's state regarding SGA. If server will SGA,
+ * then linemode is off, if server won't SGA, then linemode
+ * is on.
+ */
+void
+localstat(void)
+{
+ int need_will_echo = 0;
+
+ /*
+ * Check for changes to flow control if client supports it.
+ */
+ flowstat();
+
+ /*
+ * Check linemode on/off state
+ */
+ uselinemode = tty_linemode();
+
+ /*
+ * If alwayslinemode is on, and pty is changing to turn it off, then
+ * force linemode back on.
+ */
+ if (alwayslinemode && linemode && !uselinemode) {
+ uselinemode = 1;
+ tty_setlinemode(uselinemode);
+ }
+
+ if (uselinemode) {
+ /*
+ * Check for state of BINARY options.
+ *
+ * We only need to do the binary dance if we are actually going
+ * to use linemode. As this confuses some telnet clients
+ * that don't support linemode, and doesn't gain us
+ * anything, we don't do it unless we're doing linemode.
+ * -Crh (henrich@msu.edu)
+ */
+
+ if (tty_isbinaryin()) {
+ if (his_want_state_is_wont(TELOPT_BINARY))
+ send_do(TELOPT_BINARY, 1);
+ } else {
+ if (his_want_state_is_will(TELOPT_BINARY))
+ send_dont(TELOPT_BINARY, 1);
+ }
+
+ if (tty_isbinaryout()) {
+ if (my_want_state_is_wont(TELOPT_BINARY))
+ send_will(TELOPT_BINARY, 1);
+ } else {
+ if (my_want_state_is_will(TELOPT_BINARY))
+ send_wont(TELOPT_BINARY, 1);
+ }
+ }
+
+#ifdef ENCRYPTION
+ /*
+ * If the terminal is not echoing, but editing is enabled,
+ * something like password input is going to happen, so
+ * if we the other side is not currently sending encrypted
+ * data, ask the other side to start encrypting.
+ */
+ if (his_state_is_will(TELOPT_ENCRYPT)) {
+ static int enc_passwd = 0;
+ if (uselinemode && !tty_isecho() && tty_isediting()
+ && (enc_passwd == 0) && !decrypt_input) {
+ encrypt_send_request_start();
+ enc_passwd = 1;
+ } else if (enc_passwd) {
+ encrypt_send_request_end();
+ enc_passwd = 0;
+ }
+ }
+#endif /* ENCRYPTION */
+
+ /*
+ * Do echo mode handling as soon as we know what the
+ * linemode is going to be.
+ * If the pty has echo turned off, then tell the client that
+ * the server will echo. If echo is on, then the server
+ * will echo if in character mode, but in linemode the
+ * client should do local echoing. The state machine will
+ * not send anything if it is unnecessary, so don't worry
+ * about that here.
+ *
+ * If we need to send the WILL ECHO (because echo is off),
+ * then delay that until after we have changed the MODE.
+ * This way, when the user is turning off both editing
+ * and echo, the client will get editing turned off first.
+ * This keeps the client from going into encryption mode
+ * and then right back out if it is doing auto-encryption
+ * when passwords are being typed.
+ */
+ if (uselinemode) {
+ if (tty_isecho())
+ send_wont(TELOPT_ECHO, 1);
+ else
+ need_will_echo = 1;
+#ifdef KLUDGELINEMODE
+ if (lmodetype == KLUDGE_OK)
+ lmodetype = KLUDGE_LINEMODE;
+#endif
+ }
+
+ /*
+ * If linemode is being turned off, send appropriate
+ * command and then we're all done.
+ */
+ if (!uselinemode && linemode) {
+# ifdef KLUDGELINEMODE
+ if (lmodetype == REAL_LINEMODE) {
+# endif /* KLUDGELINEMODE */
+ send_dont(TELOPT_LINEMODE, 1);
+# ifdef KLUDGELINEMODE
+ } else if (lmodetype == KLUDGE_LINEMODE)
+ send_will(TELOPT_SGA, 1);
+# endif /* KLUDGELINEMODE */
+ send_will(TELOPT_ECHO, 1);
+ linemode = uselinemode;
+ goto done;
+ }
+
+# ifdef KLUDGELINEMODE
+ /*
+ * If using real linemode check edit modes for possible later use.
+ * If we are in kludge linemode, do the SGA negotiation.
+ */
+ if (lmodetype == REAL_LINEMODE) {
+# endif /* KLUDGELINEMODE */
+ useeditmode = 0;
+ if (tty_isediting())
+ useeditmode |= MODE_EDIT;
+ if (tty_istrapsig())
+ useeditmode |= MODE_TRAPSIG;
+ if (tty_issofttab())
+ useeditmode |= MODE_SOFT_TAB;
+ if (tty_islitecho())
+ useeditmode |= MODE_LIT_ECHO;
+# ifdef KLUDGELINEMODE
+ } else if (lmodetype == KLUDGE_LINEMODE) {
+ if (tty_isediting() && uselinemode)
+ send_wont(TELOPT_SGA, 1);
+ else
+ send_will(TELOPT_SGA, 1);
+ }
+# endif /* KLUDGELINEMODE */
+
+ /*
+ * Negotiate linemode on if pty state has changed to turn it on.
+ * Send appropriate command and send along edit mode, then all done.
+ */
+ if (uselinemode && !linemode) {
+# ifdef KLUDGELINEMODE
+ if (lmodetype == KLUDGE_LINEMODE) {
+ send_wont(TELOPT_SGA, 1);
+ } else if (lmodetype == REAL_LINEMODE) {
+# endif /* KLUDGELINEMODE */
+ send_do(TELOPT_LINEMODE, 1);
+ /* send along edit modes */
+ output_data("%c%c%c%c%c%c%c", IAC, SB,
+ TELOPT_LINEMODE, LM_MODE, useeditmode,
+ IAC, SE);
+ editmode = useeditmode;
+# ifdef KLUDGELINEMODE
+ }
+# endif /* KLUDGELINEMODE */
+ linemode = uselinemode;
+ goto done;
+ }
+
+# ifdef KLUDGELINEMODE
+ /*
+ * None of what follows is of any value if not using
+ * real linemode.
+ */
+ if (lmodetype < REAL_LINEMODE)
+ goto done;
+# endif /* KLUDGELINEMODE */
+
+ if (linemode && his_state_is_will(TELOPT_LINEMODE)) {
+ /*
+ * If edit mode changed, send edit mode.
+ */
+ if (useeditmode != editmode) {
+ /*
+ * Send along appropriate edit mode mask.
+ */
+ output_data("%c%c%c%c%c%c%c", IAC, SB,
+ TELOPT_LINEMODE, LM_MODE, useeditmode,
+ IAC, SE);
+ editmode = useeditmode;
+ }
+
+
+ /*
+ * Check for changes to special characters in use.
+ */
+ start_slc(0);
+ check_slc();
+ (void) end_slc(0);
+ }
+
+done:
+ if (need_will_echo)
+ send_will(TELOPT_ECHO, 1);
+ /*
+ * Some things should be deferred until after the pty state has
+ * been set by the local process. Do those things that have been
+ * deferred now. This only happens once.
+ */
+ if (_terminit == 0) {
+ _terminit = 1;
+ defer_terminit();
+ }
+
+ netflush();
+ set_termbuf();
+ return;
+
+} /* end of localstat */
+#endif /* LINEMODE */
+
+/*
+ * flowstat
+ *
+ * Check for changes to flow control
+ */
+void
+flowstat(void)
+{
+ if (his_state_is_will(TELOPT_LFLOW)) {
+ if (tty_flowmode() != flowmode) {
+ flowmode = tty_flowmode();
+ output_data("%c%c%c%c%c%c",
+ IAC, SB, TELOPT_LFLOW,
+ flowmode ? LFLOW_ON : LFLOW_OFF,
+ IAC, SE);
+ }
+ if (tty_restartany() != restartany) {
+ restartany = tty_restartany();
+ output_data("%c%c%c%c%c%c",
+ IAC, SB, TELOPT_LFLOW,
+ restartany ? LFLOW_RESTART_ANY
+ : LFLOW_RESTART_XON,
+ IAC, SE);
+ }
+ }
+}
+
+/*
+ * clientstat
+ *
+ * Process linemode related requests from the client.
+ * Client can request a change to only one of linemode, editmode or slc's
+ * at a time, and if using kludge linemode, then only linemode may be
+ * affected.
+ */
+void
+clientstat(int code, int parm1, int parm2)
+{
+
+ /*
+ * Get a copy of terminal characteristics.
+ */
+ init_termbuf();
+
+ /*
+ * Process request from client. code tells what it is.
+ */
+ switch (code) {
+#ifdef LINEMODE
+ case TELOPT_LINEMODE:
+ /*
+ * Don't do anything unless client is asking us to change
+ * modes.
+ */
+ uselinemode = (parm1 == WILL);
+ if (uselinemode != linemode) {
+# ifdef KLUDGELINEMODE
+ /*
+ * If using kludge linemode, make sure that
+ * we can do what the client asks.
+ * We can not turn off linemode if alwayslinemode
+ * and the ICANON bit is set.
+ */
+ if (lmodetype == KLUDGE_LINEMODE) {
+ if (alwayslinemode && tty_isediting()) {
+ uselinemode = 1;
+ }
+ }
+
+ /*
+ * Quit now if we can't do it.
+ */
+ if (uselinemode == linemode)
+ return;
+
+ /*
+ * If using real linemode and linemode is being
+ * turned on, send along the edit mode mask.
+ */
+ if (lmodetype == REAL_LINEMODE && uselinemode)
+# else /* KLUDGELINEMODE */
+ if (uselinemode)
+# endif /* KLUDGELINEMODE */
+ {
+ useeditmode = 0;
+ if (tty_isediting())
+ useeditmode |= MODE_EDIT;
+ if (tty_istrapsig())
+ useeditmode |= MODE_TRAPSIG;
+ if (tty_issofttab())
+ useeditmode |= MODE_SOFT_TAB;
+ if (tty_islitecho())
+ useeditmode |= MODE_LIT_ECHO;
+ output_data("%c%c%c%c%c%c%c", IAC,
+ SB, TELOPT_LINEMODE, LM_MODE,
+ useeditmode, IAC, SE);
+ editmode = useeditmode;
+ }
+
+
+ tty_setlinemode(uselinemode);
+
+ linemode = uselinemode;
+
+ if (!linemode)
+ send_will(TELOPT_ECHO, 1);
+ }
+ break;
+
+ case LM_MODE:
+ {
+ int ack, changed;
+
+ /*
+ * Client has sent along a mode mask. If it agrees with
+ * what we are currently doing, ignore it; if not, it could
+ * be viewed as a request to change. Note that the server
+ * will change to the modes in an ack if it is different from
+ * what we currently have, but we will not ack the ack.
+ */
+ useeditmode &= MODE_MASK;
+ ack = (useeditmode & MODE_ACK);
+ useeditmode &= ~MODE_ACK;
+
+ if ((changed = (useeditmode ^ editmode))) {
+ /*
+ * This check is for a timing problem. If the
+ * state of the tty has changed (due to the user
+ * application) we need to process that info
+ * before we write in the state contained in the
+ * ack!!! This gets out the new MODE request,
+ * and when the ack to that command comes back
+ * we'll set it and be in the right mode.
+ */
+ if (ack)
+ localstat();
+ if (changed & MODE_EDIT)
+ tty_setedit(useeditmode & MODE_EDIT);
+
+ if (changed & MODE_TRAPSIG)
+ tty_setsig(useeditmode & MODE_TRAPSIG);
+
+ if (changed & MODE_SOFT_TAB)
+ tty_setsofttab(useeditmode & MODE_SOFT_TAB);
+
+ if (changed & MODE_LIT_ECHO)
+ tty_setlitecho(useeditmode & MODE_LIT_ECHO);
+
+ set_termbuf();
+
+ if (!ack) {
+ output_data("%c%c%c%c%c%c%c", IAC,
+ SB, TELOPT_LINEMODE, LM_MODE,
+ useeditmode|MODE_ACK,
+ IAC, SE);
+ }
+
+ editmode = useeditmode;
+ }
+
+ break;
+
+ } /* end of case LM_MODE */
+#endif /* LINEMODE */
+
+ case TELOPT_NAWS:
+#ifdef TIOCSWINSZ
+ {
+ struct winsize ws;
+
+ def_col = parm1;
+ def_row = parm2;
+#ifdef LINEMODE
+ /*
+ * Defer changing window size until after terminal is
+ * initialized.
+ */
+ if (terminit() == 0)
+ return;
+#endif /* LINEMODE */
+
+ /*
+ * Change window size as requested by client.
+ */
+
+ ws.ws_col = parm1;
+ ws.ws_row = parm2;
+ (void) ioctl(spty, TIOCSWINSZ, (char *)&ws);
+ }
+#endif /* TIOCSWINSZ */
+
+ break;
+
+ case TELOPT_TSPEED:
+ {
+ def_tspeed = parm1;
+ def_rspeed = parm2;
+#ifdef LINEMODE
+ /*
+ * Defer changing the terminal speed.
+ */
+ if (terminit() == 0)
+ return;
+#endif /* LINEMODE */
+ /*
+ * Change terminal speed as requested by client.
+ * We set the receive speed first, so that if we can't
+ * store separate receive and transmit speeds, the transmit
+ * speed will take precedence.
+ */
+ tty_rspeed(parm2);
+ tty_tspeed(parm1);
+ set_termbuf();
+
+ break;
+
+ } /* end of case TELOPT_TSPEED */
+
+ default:
+ /* What? */
+ break;
+ } /* end of switch */
+
+ netflush();
+
+} /* end of clientstat */
+
+#ifdef LINEMODE
+/*
+ * defer_terminit
+ *
+ * Some things should not be done until after the login process has started
+ * and all the pty modes are set to what they are supposed to be. This
+ * function is called when the pty state has been processed for the first time.
+ * It calls other functions that do things that were deferred in each module.
+ */
+void
+defer_terminit(void)
+{
+
+ /*
+ * local stuff that got deferred.
+ */
+ if (def_tspeed != -1) {
+ clientstat(TELOPT_TSPEED, def_tspeed, def_rspeed);
+ def_tspeed = def_rspeed = 0;
+ }
+
+#ifdef TIOCSWINSZ
+ if (def_col || def_row) {
+ struct winsize ws;
+
+ memset((char *)&ws, 0, sizeof(ws));
+ ws.ws_col = def_col;
+ ws.ws_row = def_row;
+ (void) ioctl(spty, TIOCSWINSZ, (char *)&ws);
+ }
+#endif
+
+ /*
+ * The only other module that currently defers anything.
+ */
+ deferslc();
+
+} /* end of defer_terminit */
+
+/*
+ * terminit
+ *
+ * Returns true if the pty state has been processed yet.
+ */
+int
+terminit(void)
+{
+ return(_terminit);
+
+} /* end of terminit */
+#endif /* LINEMODE */
diff --git a/remote_cmds/telnetd.tproj/utility.c b/remote_cmds/telnetd.tproj/utility.c
new file mode 100644
index 0000000..306c027
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/utility.c
@@ -0,0 +1,1081 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/contrib/telnet/telnetd/utility.c,v 1.13 2003/05/04 02:54:49 obrien Exp $");
+
+#ifdef __FreeBSD__
+#include <locale.h>
+#include <sys/utsname.h>
+#endif
+#include <string.h>
+#define PRINTOPTIONS
+#include "telnetd.h"
+
+#ifdef AUTHENTICATION
+#include <libtelnet/auth.h>
+#endif
+#ifdef ENCRYPTION
+#include <libtelnet/encrypt.h>
+#endif
+
+/*
+ * utility functions performing io related tasks
+ */
+
+/*
+ * ttloop
+ *
+ * A small subroutine to flush the network output buffer, get some data
+ * from the network, and pass it through the telnet state machine. We
+ * also flush the pty input buffer (by dropping its data) if it becomes
+ * too full.
+ */
+
+ void
+ttloop()
+{
+
+ DIAG(TD_REPORT, output_data("td: ttloop\r\n"));
+ if (nfrontp - nbackp > 0) {
+ netflush();
+ }
+ ncc = read(net, netibuf, sizeof netibuf);
+ if (ncc < 0) {
+ syslog(LOG_INFO, "ttloop: read: %m");
+ exit(1);
+ } else if (ncc == 0) {
+ syslog(LOG_INFO, "ttloop: peer died: %m");
+ exit(1);
+ }
+ DIAG(TD_REPORT, output_data("td: ttloop read %d chars\r\n", ncc));
+ netip = netibuf;
+ telrcv(); /* state machine */
+ if (ncc > 0) {
+ pfrontp = pbackp = ptyobuf;
+ telrcv();
+ }
+} /* end of ttloop */
+
+/*
+ * Check a descriptor to see if out of band data exists on it.
+ */
+int
+stilloob(int s)
+{
+ static struct timeval timeout = { 0, 0 };
+ fd_set excepts;
+ int value;
+
+ do {
+ FD_ZERO(&excepts);
+ FD_SET(s, &excepts);
+ memset((char *)&timeout, 0, sizeof timeout);
+ value = select(s+1, (fd_set *)0, (fd_set *)0, &excepts, &timeout);
+ } while ((value == -1) && (errno == EINTR));
+
+ if (value < 0) {
+ fatalperror(mpty, "select");
+ }
+ if (FD_ISSET(s, &excepts)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+void
+ptyflush(void)
+{
+ int n;
+
+ if ((n = pfrontp - pbackp) > 0) {
+ DIAG(TD_REPORT | TD_PTYDATA,
+ output_data("td: ptyflush %d chars\r\n", n));
+ DIAG(TD_PTYDATA, printdata("pd", pbackp, n));
+ n = write(mpty, pbackp, n);
+ }
+ if (n < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR)
+ return;
+ cleanup(0);
+ }
+ pbackp += n;
+ if (pbackp == pfrontp)
+ pbackp = pfrontp = ptyobuf;
+}
+
+/*
+ * nextitem()
+ *
+ * Return the address of the next "item" in the TELNET data
+ * stream. This will be the address of the next character if
+ * the current address is a user data character, or it will
+ * be the address of the character following the TELNET command
+ * if the current address is a TELNET IAC ("I Am a Command")
+ * character.
+ */
+static char *
+nextitem(char *current)
+{
+ if ((*current&0xff) != IAC) {
+ return current+1;
+ }
+ switch (*(current+1)&0xff) {
+ case DO:
+ case DONT:
+ case WILL:
+ case WONT:
+ return current+3;
+ case SB: /* loop forever looking for the SE */
+ {
+ char *look = current+2;
+
+ for (;;) {
+ if ((*look++&0xff) == IAC) {
+ if ((*look++&0xff) == SE) {
+ return look;
+ }
+ }
+ }
+ }
+ default:
+ return current+2;
+ }
+} /* end of nextitem */
+
+/*
+ * netclear()
+ *
+ * We are about to do a TELNET SYNCH operation. Clear
+ * the path to the network.
+ *
+ * Things are a bit tricky since we may have sent the first
+ * byte or so of a previous TELNET command into the network.
+ * So, we have to scan the network buffer from the beginning
+ * until we are up to where we want to be.
+ *
+ * A side effect of what we do, just to keep things
+ * simple, is to clear the urgent data pointer. The principal
+ * caller should be setting the urgent data pointer AFTER calling
+ * us in any case.
+ */
+void
+netclear(void)
+{
+ char *thisitem, *next;
+ char *good;
+#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
+ ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
+
+#ifdef ENCRYPTION
+ thisitem = nclearto > netobuf ? nclearto : netobuf;
+#else /* ENCRYPTION */
+ thisitem = netobuf;
+#endif /* ENCRYPTION */
+
+ while ((next = nextitem(thisitem)) <= nbackp) {
+ thisitem = next;
+ }
+
+ /* Now, thisitem is first before/at boundary. */
+
+#ifdef ENCRYPTION
+ good = nclearto > netobuf ? nclearto : netobuf;
+#else /* ENCRYPTION */
+ good = netobuf; /* where the good bytes go */
+#endif /* ENCRYPTION */
+
+ while (nfrontp > thisitem) {
+ if (wewant(thisitem)) {
+ int length;
+
+ next = thisitem;
+ do {
+ next = nextitem(next);
+ } while (wewant(next) && (nfrontp > next));
+ length = next-thisitem;
+ memmove(good, thisitem, length);
+ good += length;
+ thisitem = next;
+ } else {
+ thisitem = nextitem(thisitem);
+ }
+ }
+
+ nbackp = netobuf;
+ nfrontp = good; /* next byte to be sent */
+ neturg = 0;
+} /* end of netclear */
+
+/*
+ * netflush
+ * Send as much data as possible to the network,
+ * handling requests for urgent data.
+ */
+void
+netflush(void)
+{
+ int n;
+ extern int not42;
+
+ while ((n = nfrontp - nbackp) > 0) {
+#if 0
+ /* XXX This causes output_data() to recurse and die */
+ DIAG(TD_REPORT, {
+ n += output_data("td: netflush %d chars\r\n", n);
+ });
+#endif
+#ifdef ENCRYPTION
+ if (encrypt_output) {
+ char *s = nclearto ? nclearto : nbackp;
+ if (nfrontp - s > 0) {
+ (*encrypt_output)((unsigned char *)s, nfrontp-s);
+ nclearto = nfrontp;
+ }
+ }
+#endif /* ENCRYPTION */
+ /*
+ * if no urgent data, or if the other side appears to be an
+ * old 4.2 client (and thus unable to survive TCP urgent data),
+ * write the entire buffer in non-OOB mode.
+ */
+ if ((neturg == 0) || (not42 == 0)) {
+ n = write(net, nbackp, n); /* normal write */
+ } else {
+ n = neturg - nbackp;
+ /*
+ * In 4.2 (and 4.3) systems, there is some question about
+ * what byte in a sendOOB operation is the "OOB" data.
+ * To make ourselves compatible, we only send ONE byte
+ * out of band, the one WE THINK should be OOB (though
+ * we really have more the TCP philosophy of urgent data
+ * rather than the Unix philosophy of OOB data).
+ */
+ if (n > 1) {
+ n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */
+ } else {
+ n = send(net, nbackp, n, MSG_OOB); /* URGENT data */
+ }
+ }
+ if (n == -1) {
+ if (errno == EWOULDBLOCK || errno == EINTR)
+ continue;
+ cleanup(0);
+ /* NOTREACHED */
+ }
+ nbackp += n;
+#ifdef ENCRYPTION
+ if (nbackp > nclearto)
+ nclearto = 0;
+#endif /* ENCRYPTION */
+ if (nbackp >= neturg) {
+ neturg = 0;
+ }
+ if (nbackp == nfrontp) {
+ nbackp = nfrontp = netobuf;
+#ifdef ENCRYPTION
+ nclearto = 0;
+#endif /* ENCRYPTION */
+ }
+ }
+ return;
+} /* end of netflush */
+
+
+/*
+ * miscellaneous functions doing a variety of little jobs follow ...
+ */
+
+
+void
+fatal(int f, const char *msg)
+{
+ char buf[BUFSIZ];
+
+ (void) snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg);
+#ifdef ENCRYPTION
+ if (encrypt_output) {
+ /*
+ * Better turn off encryption first....
+ * Hope it flushes...
+ */
+ encrypt_send_end();
+ netflush();
+ }
+#endif /* ENCRYPTION */
+ (void) write(f, buf, (int)strlen(buf));
+ sleep(1); /*XXX*/
+ exit(1);
+}
+
+void
+fatalperror(int f, const char *msg)
+{
+ char buf[BUFSIZ];
+
+ (void) snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
+ fatal(f, buf);
+}
+
+char editedhost[32];
+
+void
+edithost(char *pat, char *host)
+{
+ char *res = editedhost;
+
+ if (!pat)
+ pat = strdup("");
+ while (*pat) {
+ switch (*pat) {
+
+ case '#':
+ if (*host)
+ host++;
+ break;
+
+ case '@':
+ if (*host)
+ *res++ = *host++;
+ break;
+
+ default:
+ *res++ = *pat;
+ break;
+ }
+ if (res == &editedhost[sizeof editedhost - 1]) {
+ *res = '\0';
+ return;
+ }
+ pat++;
+ }
+ if (*host)
+ (void) strncpy(res, host,
+ sizeof editedhost - (res - editedhost) -1);
+ else
+ *res = '\0';
+ editedhost[sizeof editedhost - 1] = '\0';
+}
+
+static char *putlocation;
+
+static void
+putstr(const char *s)
+{
+
+ while (*s)
+ putchr(*s++);
+}
+
+void
+putchr(int cc)
+{
+ *putlocation++ = cc;
+}
+
+#ifdef __FreeBSD__
+static char fmtstr[] = { "%+" };
+#else
+static char fmtstr[] = { "%l:%M%P on %A, %d %B %Y" };
+#endif
+
+void
+putf(char *cp, char *where)
+{
+ char *slash;
+ time_t t;
+ char db[100];
+#ifdef __FreeBSD__
+ static struct utsname kerninfo;
+
+ if (!*kerninfo.sysname)
+ uname(&kerninfo);
+#endif
+
+ putlocation = where;
+
+ while (*cp) {
+ if (*cp =='\n') {
+ putstr("\r\n");
+ cp++;
+ continue;
+ } else if (*cp != '%') {
+ putchr(*cp++);
+ continue;
+ }
+ switch (*++cp) {
+
+ case 't':
+#ifdef STREAMSPTY
+ /* names are like /dev/pts/2 -- we want pts/2 */
+ slash = strchr(line+1, '/');
+#else
+ slash = strrchr(line, '/');
+#endif
+ if (slash == (char *) 0)
+ putstr(line);
+ else
+ putstr(&slash[1]);
+ break;
+
+ case 'h':
+ putstr(editedhost);
+ break;
+
+ case 'd':
+#ifdef __FreeBSD__
+ setlocale(LC_TIME, "");
+#endif
+ (void)time(&t);
+ (void)strftime(db, sizeof(db), fmtstr, localtime(&t));
+ putstr(db);
+ break;
+
+#ifdef __FreeBSD__
+ case 's':
+ putstr(kerninfo.sysname);
+ break;
+
+ case 'm':
+ putstr(kerninfo.machine);
+ break;
+
+ case 'r':
+ putstr(kerninfo.release);
+ break;
+
+ case 'v':
+ putstr(kerninfo.version);
+ break;
+#endif
+
+ case '%':
+ putchr('%');
+ break;
+ }
+ cp++;
+ }
+}
+
+#ifdef DIAGNOSTICS
+/*
+ * Print telnet options and commands in plain text, if possible.
+ */
+void
+printoption(const char *fmt, int option)
+{
+ if (TELOPT_OK(option))
+ output_data("%s %s\r\n", fmt, TELOPT(option));
+ else if (TELCMD_OK(option))
+ output_data("%s %s\r\n", fmt, TELCMD(option));
+ else
+ output_data("%s %d\r\n", fmt, option);
+ return;
+}
+
+void
+printsub(char direction, unsigned char *pointer, int length)
+{
+ int i = 0;
+
+ if (!(diagnostic & TD_OPTIONS))
+ return;
+
+ if (direction) {
+ output_data("td: %s suboption ",
+ direction == '<' ? "recv" : "send");
+ if (length >= 3) {
+ int j;
+
+ i = pointer[length-2];
+ j = pointer[length-1];
+
+ if (i != IAC || j != SE) {
+ output_data("(terminated by ");
+ if (TELOPT_OK(i))
+ output_data("%s ", TELOPT(i));
+ else if (TELCMD_OK(i))
+ output_data("%s ", TELCMD(i));
+ else
+ output_data("%d ", i);
+ if (TELOPT_OK(j))
+ output_data("%s", TELOPT(j));
+ else if (TELCMD_OK(j))
+ output_data("%s", TELCMD(j));
+ else
+ output_data("%d", j);
+ output_data(", not IAC SE!) ");
+ }
+ }
+ length -= 2;
+ }
+ if (length < 1) {
+ output_data("(Empty suboption??\?)");
+ return;
+ }
+ switch (pointer[0]) {
+ case TELOPT_TTYPE:
+ output_data("TERMINAL-TYPE ");
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
+ break;
+ case TELQUAL_SEND:
+ output_data("SEND");
+ break;
+ default:
+ output_data(
+ "- unknown qualifier %d (0x%x).",
+ pointer[1], pointer[1]);
+ }
+ break;
+ case TELOPT_TSPEED:
+ output_data("TERMINAL-SPEED");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ output_data(" IS %.*s", length-2, (char *)pointer+2);
+ break;
+ default:
+ if (pointer[1] == 1)
+ output_data(" SEND");
+ else
+ output_data(" %d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+ }
+ break;
+
+ case TELOPT_LFLOW:
+ output_data("TOGGLE-FLOW-CONTROL");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case LFLOW_OFF:
+ output_data(" OFF"); break;
+ case LFLOW_ON:
+ output_data(" ON"); break;
+ case LFLOW_RESTART_ANY:
+ output_data(" RESTART-ANY"); break;
+ case LFLOW_RESTART_XON:
+ output_data(" RESTART-XON"); break;
+ default:
+ output_data(" %d (unknown)", pointer[1]);
+ }
+ for (i = 2; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+
+ case TELOPT_NAWS:
+ output_data("NAWS");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ if (length == 2) {
+ output_data(" ?%d?", pointer[1]);
+ break;
+ }
+ output_data(" %d %d (%d)",
+ pointer[1], pointer[2],
+ (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2])));
+ if (length == 4) {
+ output_data(" ?%d?", pointer[3]);
+ break;
+ }
+ output_data(" %d %d (%d)",
+ pointer[3], pointer[4],
+ (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4])));
+ for (i = 5; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+
+ case TELOPT_LINEMODE:
+ output_data("LINEMODE ");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case WILL:
+ output_data("WILL ");
+ goto common;
+ case WONT:
+ output_data("WONT ");
+ goto common;
+ case DO:
+ output_data("DO ");
+ goto common;
+ case DONT:
+ output_data("DONT ");
+ common:
+ if (length < 3) {
+ output_data("(no option??\?)");
+ break;
+ }
+ switch (pointer[2]) {
+ case LM_FORWARDMASK:
+ output_data("Forward Mask");
+ for (i = 3; i < length; i++) {
+ output_data(" %x", pointer[i]);
+ }
+ break;
+ default:
+ output_data("%d (unknown)", pointer[2]);
+ for (i = 3; i < length; i++) {
+ output_data(" %d", pointer[i]);
+ }
+ break;
+ }
+ break;
+
+ case LM_SLC:
+ output_data("SLC");
+ for (i = 2; i < length - 2; i += 3) {
+ if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
+ output_data(" %s", SLC_NAME(pointer[i+SLC_FUNC]));
+ else
+ output_data(" %d", pointer[i+SLC_FUNC]);
+ switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) {
+ case SLC_NOSUPPORT:
+ output_data(" NOSUPPORT"); break;
+ case SLC_CANTCHANGE:
+ output_data(" CANTCHANGE"); break;
+ case SLC_VARIABLE:
+ output_data(" VARIABLE"); break;
+ case SLC_DEFAULT:
+ output_data(" DEFAULT"); break;
+ }
+ output_data("%s%s%s",
+ pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "",
+ pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "",
+ pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : "");
+ if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN|
+ SLC_FLUSHOUT| SLC_LEVELBITS)) {
+ output_data("(0x%x)", pointer[i+SLC_FLAGS]);
+ }
+ output_data(" %d;", pointer[i+SLC_VALUE]);
+ if ((pointer[i+SLC_VALUE] == IAC) &&
+ (pointer[i+SLC_VALUE+1] == IAC))
+ i++;
+ }
+ for (; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+
+ case LM_MODE:
+ output_data("MODE ");
+ if (length < 3) {
+ output_data("(no mode??\?)");
+ break;
+ }
+ {
+ char tbuf[32];
+ sprintf(tbuf, "%s%s%s%s%s",
+ pointer[2]&MODE_EDIT ? "|EDIT" : "",
+ pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "",
+ pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "",
+ pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "",
+ pointer[2]&MODE_ACK ? "|ACK" : "");
+ output_data("%s", tbuf[1] ? &tbuf[1] : "0");
+ }
+ if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) {
+ output_data(" (0x%x)", pointer[2]);
+ }
+ for (i = 3; i < length; i++) {
+ output_data(" ?0x%x?", pointer[i]);
+ }
+ break;
+ default:
+ output_data("%d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++) {
+ output_data(" %d", pointer[i]);
+ }
+ }
+ break;
+
+ case TELOPT_STATUS: {
+ const char *cp;
+ int j, k;
+
+ output_data("STATUS");
+
+ switch (pointer[1]) {
+ default:
+ if (pointer[1] == TELQUAL_SEND)
+ output_data(" SEND");
+ else
+ output_data(" %d (unknown)", pointer[1]);
+ for (i = 2; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+ case TELQUAL_IS:
+ output_data(" IS\r\n");
+
+ for (i = 2; i < length; i++) {
+ switch(pointer[i]) {
+ case DO: cp = "DO"; goto common2;
+ case DONT: cp = "DONT"; goto common2;
+ case WILL: cp = "WILL"; goto common2;
+ case WONT: cp = "WONT"; goto common2;
+ common2:
+ i++;
+ if (TELOPT_OK(pointer[i]))
+ output_data(" %s %s", cp, TELOPT(pointer[i]));
+ else
+ output_data(" %s %d", cp, pointer[i]);
+
+ output_data("\r\n");
+ break;
+
+ case SB:
+ output_data(" SB ");
+ i++;
+ j = k = i;
+ while (j < length) {
+ if (pointer[j] == SE) {
+ if (j+1 == length)
+ break;
+ if (pointer[j+1] == SE)
+ j++;
+ else
+ break;
+ }
+ pointer[k++] = pointer[j++];
+ }
+ printsub(0, &pointer[i], k - i);
+ if (i < length) {
+ output_data(" SE");
+ i = j;
+ } else
+ i = j - 1;
+
+ output_data("\r\n");
+
+ break;
+
+ default:
+ output_data(" %d", pointer[i]);
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ case TELOPT_XDISPLOC:
+ output_data("X-DISPLAY-LOCATION ");
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ output_data("IS \"%.*s\"", length-2, (char *)pointer+2);
+ break;
+ case TELQUAL_SEND:
+ output_data("SEND");
+ break;
+ default:
+ output_data("- unknown qualifier %d (0x%x).",
+ pointer[1], pointer[1]);
+ }
+ break;
+
+ case TELOPT_NEW_ENVIRON:
+ output_data("NEW-ENVIRON ");
+ goto env_common1;
+ case TELOPT_OLD_ENVIRON:
+ output_data("OLD-ENVIRON");
+ env_common1:
+ switch (pointer[1]) {
+ case TELQUAL_IS:
+ output_data("IS ");
+ goto env_common;
+ case TELQUAL_SEND:
+ output_data("SEND ");
+ goto env_common;
+ case TELQUAL_INFO:
+ output_data("INFO ");
+ env_common:
+ {
+ int noquote = 2;
+ for (i = 2; i < length; i++ ) {
+ switch (pointer[i]) {
+ case NEW_ENV_VAR:
+ output_data("%s", "\" VAR " + noquote);
+ noquote = 2;
+ break;
+
+ case NEW_ENV_VALUE:
+ output_data("%s", "\" VALUE " + noquote);
+ noquote = 2;
+ break;
+
+ case ENV_ESC:
+ output_data("%s", "\" ESC " + noquote);
+ noquote = 2;
+ break;
+
+ case ENV_USERVAR:
+ output_data("%s", "\" USERVAR " + noquote);
+ noquote = 2;
+ break;
+
+ default:
+ if (isprint(pointer[i]) && pointer[i] != '"') {
+ if (noquote) {
+ output_data("\"");
+ noquote = 0;
+ }
+ output_data("%c", pointer[i]);
+ } else {
+ output_data("\" %03o " + noquote,
+ pointer[i]);
+ noquote = 2;
+ }
+ break;
+ }
+ }
+ if (!noquote)
+ output_data("\"");
+ break;
+ }
+ }
+ break;
+
+#ifdef AUTHENTICATION
+ case TELOPT_AUTHENTICATION:
+ output_data("AUTHENTICATION");
+
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case TELQUAL_REPLY:
+ case TELQUAL_IS:
+ output_data(" %s ", (pointer[1] == TELQUAL_IS) ?
+ "IS" : "REPLY");
+ if (AUTHTYPE_NAME_OK(pointer[2]))
+ output_data("%s ", AUTHTYPE_NAME(pointer[2]));
+ else
+ output_data("%d ", pointer[2]);
+ if (length < 3) {
+ output_data("(partial suboption??\?)");
+ break;
+ }
+ output_data("%s|%s",
+ ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+ "CLIENT" : "SERVER",
+ ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+ "MUTUAL" : "ONE-WAY");
+
+ {
+ char buf[512];
+ auth_printsub(&pointer[1], length - 1, (unsigned char*)buf, sizeof(buf));
+ output_data("%s", buf);
+ }
+ break;
+
+ case TELQUAL_SEND:
+ i = 2;
+ output_data(" SEND ");
+ while (i < length) {
+ if (AUTHTYPE_NAME_OK(pointer[i]))
+ output_data("%s ", AUTHTYPE_NAME(pointer[i]));
+ else
+ output_data("%d ", pointer[i]);
+ if (++i >= length) {
+ output_data("(partial suboption??\?)");
+ break;
+ }
+ output_data("%s|%s ",
+ ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ?
+ "CLIENT" : "SERVER",
+ ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ?
+ "MUTUAL" : "ONE-WAY");
+ ++i;
+ }
+ break;
+
+ case TELQUAL_NAME:
+ output_data(" NAME \"%.*s\"", length - 2, pointer + 2);
+ break;
+
+ default:
+ for (i = 2; i < length; i++) {
+ output_data(" ?%d?", pointer[i]);
+ }
+ break;
+ }
+ break;
+#endif
+
+#ifdef ENCRYPTION
+ case TELOPT_ENCRYPT:
+ output_data("ENCRYPT");
+ if (length < 2) {
+ output_data(" (empty suboption??\?)");
+ break;
+ }
+ switch (pointer[1]) {
+ case ENCRYPT_START:
+ output_data(" START");
+ break;
+
+ case ENCRYPT_END:
+ output_data(" END");
+ break;
+
+ case ENCRYPT_REQSTART:
+ output_data(" REQUEST-START");
+ break;
+
+ case ENCRYPT_REQEND:
+ output_data(" REQUEST-END");
+ break;
+
+ case ENCRYPT_IS:
+ case ENCRYPT_REPLY:
+ output_data(" %s ", (pointer[1] == ENCRYPT_IS) ?
+ "IS" : "REPLY");
+ if (length < 3) {
+ output_data(" (partial suboption??\?)");
+ break;
+ }
+ if (ENCTYPE_NAME_OK(pointer[2]))
+ output_data("%s ", ENCTYPE_NAME(pointer[2]));
+ else
+ output_data(" %d (unknown)", pointer[2]);
+
+ {
+ char buf[512];
+ encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf));
+ output_data("%s", buf);
+ }
+ break;
+
+ case ENCRYPT_SUPPORT:
+ i = 2;
+ output_data(" SUPPORT ");
+ while (i < length) {
+ if (ENCTYPE_NAME_OK(pointer[i]))
+ output_data("%s ", ENCTYPE_NAME(pointer[i]));
+ else
+ output_data("%d ", pointer[i]);
+ i++;
+ }
+ break;
+
+ case ENCRYPT_ENC_KEYID:
+ output_data(" ENC_KEYID");
+ goto encommon;
+
+ case ENCRYPT_DEC_KEYID:
+ output_data(" DEC_KEYID");
+ goto encommon;
+
+ default:
+ output_data(" %d (unknown)", pointer[1]);
+ encommon:
+ for (i = 2; i < length; i++) {
+ output_data(" %d", pointer[i]);
+ }
+ break;
+ }
+ break;
+#endif /* ENCRYPTION */
+
+ default:
+ if (TELOPT_OK(pointer[0]))
+ output_data("%s (unknown)", TELOPT(pointer[0]));
+ else
+ output_data("%d (unknown)", pointer[i]);
+ for (i = 1; i < length; i++) {
+ output_data(" %d", pointer[i]);
+ }
+ break;
+ }
+ output_data("\r\n");
+}
+
+/*
+ * Dump a data buffer in hex and ascii to the output data stream.
+ */
+void
+printdata(const char *tag, char *ptr, int cnt)
+{
+ int i;
+ char xbuf[30];
+
+ while (cnt) {
+ /* flush net output buffer if no room for new data) */
+ if ((&netobuf[BUFSIZ] - nfrontp) < 80) {
+ netflush();
+ }
+
+ /* add a line of output */
+ output_data("%s: ", tag);
+ for (i = 0; i < 20 && cnt; i++) {
+ output_data("%02x", *ptr);
+ if (isprint(*ptr)) {
+ xbuf[i] = *ptr;
+ } else {
+ xbuf[i] = '.';
+ }
+ if (i % 2) {
+ output_data(" ");
+ }
+ cnt--;
+ ptr++;
+ }
+ xbuf[i] = '\0';
+ output_data(" %s\r\n", xbuf );
+ }
+}
+#endif /* DIAGNOSTICS */
diff --git a/remote_cmds/telnetd.tproj/vasprintf.c b/remote_cmds/telnetd.tproj/vasprintf.c
new file mode 100644
index 0000000..ad4aed6
--- /dev/null
+++ b/remote_cmds/telnetd.tproj/vasprintf.c
@@ -0,0 +1,66 @@
+/* $OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $ */
+
+/*
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.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.
+ * 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 ``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.
+ */
+
+#if defined(LIBC_RCS) && !defined(lint)
+static char rcsid[] = "$FreeBSD: src/lib/libc/stdio/vasprintf.c,v 1.12 2001/01/24 13:00:47 deischen Exp $";
+#endif /* LIBC_RCS and not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+int
+vasprintf(str, fmt, ap)
+ char **str;
+ const char *fmt;
+ va_list ap;
+{
+ int ret;
+ FILE f;
+
+ f._file = -1;
+ f._flags = __SWR | __SSTR ;
+ f._bf._base = f._p = (unsigned char *)malloc(128);
+ if (f._bf._base == NULL) {
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+ }
+ f._bf._size = f._w = 127; /* Leave room for the NULL */
+ ret = vfprintf(&f, fmt, ap);
+ *f._p = '\0';
+ f._bf._base = realloc(f._bf._base, f._bf._size + 1);
+ if (f._bf._base == NULL) {
+ errno = ENOMEM;
+ ret = -1;
+ }
+ *str = (char *)f._bf._base;
+ return (ret);
+}
diff --git a/remote_cmds/tftp.tproj/Makefile b/remote_cmds/tftp.tproj/Makefile
new file mode 100644
index 0000000..6ed62a0
--- /dev/null
+++ b/remote_cmds/tftp.tproj/Makefile
@@ -0,0 +1,12 @@
+Project = tftp
+
+HFILES = extern.h tftpsubs.h
+CFILES = main.c tftp.c tftpsubs.c
+MANPAGES = tftp.1
+
+Extra_CC_Flags = -Wall -Werror -fPIE
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -pie
+Extra_LD_Flags += -ledit
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/remote_cmds/tftp.tproj/extern.h b/remote_cmds/tftp.tproj/extern.h
new file mode 100644
index 0000000..fdf3d31
--- /dev/null
+++ b/remote_cmds/tftp.tproj/extern.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/tftp/extern.h,v 1.3 2002/03/22 01:42:33 imp Exp $
+ */
+
+void recvfile(int, char *, char *);
+void xmitfile(int, char *, char *);
diff --git a/remote_cmds/tftp.tproj/main.c b/remote_cmds/tftp.tproj/main.c
new file mode 100644
index 0000000..f223726
--- /dev/null
+++ b/remote_cmds/tftp.tproj/main.c
@@ -0,0 +1,920 @@
+/* $NetBSD: main.c,v 1.19 2003/10/02 23:31:52 itojun Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tftp/main.c,v 1.22 2005/10/19 15:37:42 stefanf Exp $");
+
+/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
+
+/*
+ * TFTP User Program -- Command Interface.
+ */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/param.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <arpa/tftp.h>
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <err.h>
+#include <histedit.h>
+#include <netdb.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define MAXLINE 200
+#define TIMEOUT 5 /* secs between rexmt's */
+#define MAXSEGSIZE 65464
+struct sockaddr_storage peeraddr;
+int f;
+int trace;
+int verbose;
+int tsize=0;
+int tout=0;
+int def_blksize=SEGSIZE;
+int blksize=SEGSIZE;
+int connected;
+char mode[32];
+char line[MAXLINE];
+int margc;
+#define MAX_MARGV 20
+char *margv[MAX_MARGV];
+jmp_buf toplevel;
+volatile int txrx_error;
+
+void get(int, char **);
+void help(int, char **);
+void intr(int);
+void modecmd(int, char **);
+void put(int, char **);
+void quit(int, char **);
+void setascii(int, char **);
+void setbinary(int, char **);
+void setpeer0(char *, const char *);
+void setpeer(int, char **);
+void setrexmt(int, char **);
+void settimeout(int, char **);
+void settrace(int, char **);
+void setverbose(int, char **);
+#ifdef __APPLE__
+void setblksize(int, char **);
+void settsize(int, char **);
+void settimeoutopt(int, char **);
+#endif
+void status(int, char **);
+#ifdef __APPLE__
+char *tail(char *);
+int main(int, char *[]);
+void intr(int);
+struct cmd *getcmd(char *);
+#endif
+
+static void command(void) __dead2;
+static const char *command_prompt(void);
+
+static void getusage(char *);
+static void makeargv(void);
+static void putusage(char *);
+static void settftpmode(const char *);
+
+char *tail(char *);
+struct cmd *getcmd(char *);
+
+#define HELPINDENT (sizeof("connect"))
+
+struct cmd {
+ const char *name;
+ char *help;
+ void (*handler)(int, char **);
+};
+
+char vhelp[] = "toggle verbose mode";
+char thelp[] = "toggle packet tracing";
+#ifdef __APPLE__
+char tshelp[] = "toggle extended tsize option";
+char tohelp[] = "toggle extended timeout option";
+char blhelp[] = "set an alternative blocksize (def. 512)";
+#endif
+char chelp[] = "connect to remote tftp";
+char qhelp[] = "exit tftp";
+char hhelp[] = "print help information";
+char shelp[] = "send file";
+char rhelp[] = "receive file";
+char mhelp[] = "set file transfer mode";
+char sthelp[] = "show current status";
+char xhelp[] = "set per-packet retransmission timeout";
+char ihelp[] = "set total retransmission timeout";
+char ashelp[] = "set mode to netascii";
+char bnhelp[] = "set mode to octet";
+
+struct cmd cmdtab[] = {
+ { "connect", chelp, setpeer },
+ { "mode", mhelp, modecmd },
+ { "put", shelp, put },
+ { "get", rhelp, get },
+ { "quit", qhelp, quit },
+ { "verbose", vhelp, setverbose },
+#ifdef __APPLE__
+ { "blksize", blhelp, setblksize },
+ { "tsize", tshelp, settsize },
+#endif
+ { "trace", thelp, settrace },
+ { "status", sthelp, status },
+ { "binary", bnhelp, setbinary },
+ { "ascii", ashelp, setascii },
+ { "rexmt", xhelp, setrexmt },
+ { "timeout", ihelp, settimeout },
+#ifdef __APPLE__
+ { "tout", tohelp, settimeoutopt },
+#endif
+ { "?", hhelp, help },
+ { NULL, NULL, NULL }
+};
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+
+ f = -1;
+ strcpy(mode, "netascii");
+ signal(SIGINT, intr);
+
+ setprogname(argv[0]);
+ while ((c = getopt(argc, argv, "e")) != -1) {
+ switch (c) {
+ case 'e':
+ blksize = MAXSEGSIZE;
+ strcpy(mode, "octet");
+ tsize = 1;
+ tout = 1;
+ break;
+ default:
+ printf("usage: %s [-e] host-name [port]\n",
+ getprogname());
+ exit(1);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc >= 1) {
+ if (setjmp(toplevel) != 0)
+ exit(txrx_error);
+ argc++;
+ argv--;
+ setpeer(argc, argv);
+ }
+ if (setjmp(toplevel) != 0)
+ (void)putchar('\n');
+ command();
+ return (0);
+}
+
+char hostname[MAXHOSTNAMELEN];
+
+void
+setpeer0(host, port)
+ char *host;
+ const char *port;
+{
+ struct addrinfo hints, *res0, *res;
+ int error, soopt;
+ struct sockaddr_storage ss;
+ const char *cause = "unknown";
+
+ if (connected) {
+ close(f);
+ f = -1;
+ }
+ connected = 0;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ hints.ai_flags = AI_CANONNAME;
+ if (!port)
+ port = "tftp";
+ error = getaddrinfo(host, port, &hints, &res0);
+ if (error) {
+ warnx("%s", gai_strerror(error));
+ return;
+ }
+
+ for (res = res0; res; res = res->ai_next) {
+ if (res->ai_addrlen > sizeof(peeraddr))
+ continue;
+ f = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (f < 0) {
+ cause = "socket";
+ continue;
+ }
+
+ memset(&ss, 0, sizeof(ss));
+ ss.ss_family = res->ai_family;
+ ss.ss_len = res->ai_addrlen;
+ if (bind(f, (struct sockaddr *)&ss, ss.ss_len) < 0) {
+ cause = "bind";
+ close(f);
+ f = -1;
+ continue;
+ }
+
+ break;
+ }
+
+ if (f >= 0) {
+ soopt = 65536;
+ if (setsockopt(f, SOL_SOCKET, SO_SNDBUF, &soopt, sizeof(soopt))
+ < 0) {
+ close(f);
+ f = -1;
+ cause = "setsockopt SNDBUF";
+ }
+ if (setsockopt(f, SOL_SOCKET, SO_RCVBUF, &soopt, sizeof(soopt))
+ < 0) {
+ close(f);
+ f = -1;
+ cause = "setsockopt RCVBUF";
+ }
+ }
+
+ if (f < 0)
+ warn("%s", cause);
+ else {
+ /* res->ai_addr <= sizeof(peeraddr) is guaranteed */
+ memcpy(&peeraddr, res->ai_addr, res->ai_addrlen);
+ if (res->ai_canonname) {
+ (void) strlcpy(hostname, res->ai_canonname,
+ sizeof(hostname));
+ } else
+ (void) strlcpy(hostname, host, sizeof(hostname));
+ connected = 1;
+ }
+
+ freeaddrinfo(res0);
+}
+
+void
+setpeer(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ if (argc < 2) {
+ strcpy(line, "Connect ");
+ printf("(to) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if ((argc < 2) || (argc > 3)) {
+ printf("usage: %s [-e] host-name [port]\n", getprogname());
+ return;
+ }
+ if (argc == 3)
+ setpeer0(argv[1], argv[2]);
+ else
+ setpeer0(argv[1], NULL);
+}
+
+struct modes {
+ const char *m_name;
+ const char *m_mode;
+} modes[] = {
+ { "ascii", "netascii" },
+ { "netascii", "netascii" },
+ { "binary", "octet" },
+ { "image", "octet" },
+ { "octet", "octet" },
+/* { "mail", "mail" }, */
+ { 0, 0 }
+};
+
+void
+modecmd(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct modes *p;
+ const char *sep;
+
+ if (argc < 2) {
+ printf("Using %s mode to transfer files.\n", mode);
+ return;
+ }
+ if (argc == 2) {
+ for (p = modes; p->m_name; p++)
+ if (strcmp(argv[1], p->m_name) == 0)
+ break;
+ if (p->m_name) {
+ settftpmode(p->m_mode);
+ return;
+ }
+ printf("%s: unknown mode\n", argv[1]);
+ /* drop through and print usage message */
+ }
+
+ printf("usage: %s [", argv[0]);
+ sep = " ";
+ for (p = modes; p->m_name; p++) {
+ printf("%s%s", sep, p->m_name);
+ if (*sep == ' ')
+ sep = " | ";
+ }
+ printf(" ]\n");
+ return;
+}
+
+void
+setbinary(argc, argv)
+ int argc __unused;
+ char *argv[] __unused;
+{
+
+ settftpmode("octet");
+}
+
+void
+setascii(argc, argv)
+ int argc __unused;
+ char *argv[] __unused;
+{
+
+ settftpmode("netascii");
+}
+
+static void
+settftpmode(newmode)
+ const char *newmode;
+{
+ strcpy(mode, newmode);
+ if (verbose)
+ printf("mode set to %s\n", mode);
+}
+
+
+/*
+ * Send file(s).
+ */
+void
+put(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int fd;
+ int n;
+ char *cp, *targ;
+#ifdef __APPLE__
+ char targbuf[PATH_MAX];
+#endif /* __APPLE__ */
+
+ if (argc < 2) {
+ strcpy(line, "send ");
+ printf("(file) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc < 2) {
+ putusage(argv[0]);
+ return;
+ }
+ targ = argv[argc - 1];
+ if (rindex(argv[argc - 1], ':')) {
+ char *lcp;
+
+ for (n = 1; n < argc - 1; n++)
+ if (index(argv[n], ':')) {
+ putusage(argv[0]);
+ return;
+ }
+ lcp = argv[argc - 1];
+ targ = rindex(lcp, ':');
+ *targ++ = 0;
+ if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
+ lcp[strlen(lcp) - 1] = '\0';
+ lcp++;
+ }
+ setpeer0(lcp, NULL);
+ }
+ if (!connected) {
+ printf("No target machine specified.\n");
+ return;
+ }
+ if (argc < 4) {
+ cp = argc == 2 ? tail(targ) : argv[1];
+ fd = open(cp, O_RDONLY);
+ if (fd < 0) {
+ warn("%s", cp);
+ return;
+ }
+ if (verbose)
+ printf("putting %s to %s:%s [%s]\n",
+ cp, hostname, targ, mode);
+ xmitfile(fd, targ, mode);
+ return;
+ }
+ /* this assumes the target is a directory */
+ /* on a remote unix system. hmmmm. */
+#ifdef __APPLE__
+ snprintf(targbuf, sizeof(targbuf), "%s/", targ);
+ cp = targbuf + strlen(targbuf);
+#else /* !__APPLE__ */
+ cp = index(targ, '\0');
+ *cp++ = '/';
+#endif /* __APPLE__ */
+ for (n = 1; n < argc - 1; n++) {
+#ifdef __APPLE__
+ strlcpy(cp, tail(argv[n]), sizeof(targbuf) - (cp - targbuf));
+#else /* !__APPLE__ */
+ strcpy(cp, tail(argv[n]));
+#endif /* __APPLE__ */
+ fd = open(argv[n], O_RDONLY);
+ if (fd < 0) {
+ warn("%s", argv[n]);
+ continue;
+ }
+ if (verbose)
+ printf("putting %s to %s:%s [%s]\n",
+#ifdef __APPLE__
+ argv[n], hostname, targbuf, mode);
+#else /* !__APPLE__ */
+ argv[n], hostname, targ, mode);
+#endif /* __APPLE__ */
+ xmitfile(fd, targ, mode);
+ }
+}
+
+static void
+putusage(s)
+ char *s;
+{
+ printf("usage: %s file ... host:target, or\n", s);
+ printf(" %s file ... target (when already connected)\n", s);
+}
+
+/*
+ * Receive file(s).
+ */
+void
+get(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int fd;
+ int n;
+ char *cp;
+ char *src;
+
+ if (argc < 2) {
+ strcpy(line, "get ");
+ printf("(files) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc < 2) {
+ getusage(argv[0]);
+ return;
+ }
+ if (!connected) {
+ for (n = 1; n < argc ; n++)
+ if (rindex(argv[n], ':') == 0) {
+ getusage(argv[0]);
+ return;
+ }
+ }
+ for (n = 1; n < argc ; n++) {
+ src = rindex(argv[n], ':');
+ if (src == NULL)
+ src = argv[n];
+ else {
+ char *lcp;
+
+ *src++ = 0;
+ lcp = argv[n];
+ if (lcp[0] == '[' && lcp[strlen(lcp) - 1] == ']') {
+ lcp[strlen(lcp) - 1] = '\0';
+ lcp++;
+ }
+ setpeer0(lcp, NULL);
+ if (!connected)
+ continue;
+ }
+ if (argc < 4) {
+ cp = argc == 3 ? argv[2] : tail(src);
+ fd = creat(cp, 0644);
+ if (fd < 0) {
+ warn("%s", cp);
+ return;
+ }
+ if (verbose)
+ printf("getting from %s:%s to %s [%s]\n",
+ hostname, src, cp, mode);
+ recvfile(fd, src, mode);
+ break;
+ }
+ cp = tail(src); /* new .. jdg */
+ fd = creat(cp, 0644);
+ if (fd < 0) {
+ warn("%s", cp);
+ continue;
+ }
+ if (verbose)
+ printf("getting from %s:%s to %s [%s]\n",
+ hostname, src, cp, mode);
+ recvfile(fd, src, mode);
+ }
+}
+
+static void
+getusage(s)
+ char *s;
+{
+ printf("usage: %s host:file host:file ... file, or\n", s);
+ printf(" %s file file ... file if connected\n", s);
+}
+
+void
+setblksize(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int t;
+
+ if (argc < 2) {
+ strcpy(line, "blksize ");
+ printf("(blksize) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc != 2) {
+ printf("usage: %s value\n", argv[0]);
+ return;
+ }
+ t = atoi(argv[1]);
+ if (t < 8 || t > 65464)
+ printf("%s: bad value\n", argv[1]);
+ else
+ blksize = t;
+}
+
+int def_rexmtval = TIMEOUT;
+int rexmtval = TIMEOUT;
+
+void
+setrexmt(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int t;
+
+ if (argc < 2) {
+ strcpy(line, "Rexmt-timeout ");
+ printf("(value) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc != 2) {
+ printf("usage: %s value\n", argv[0]);
+ return;
+ }
+ t = atoi(argv[1]);
+ if (t < 0)
+ printf("%s: bad value\n", argv[1]);
+ else
+ rexmtval = t;
+}
+
+int maxtimeout = 5 * TIMEOUT;
+
+void
+settimeout(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int t;
+
+ if (argc < 2) {
+ strcpy(line, "Maximum-timeout ");
+ printf("(value) ");
+ fgets(&line[strlen(line)], sizeof line - strlen(line), stdin);
+ makeargv();
+ argc = margc;
+ argv = margv;
+ }
+ if (argc != 2) {
+ printf("usage: %s value\n", argv[0]);
+ return;
+ }
+ t = atoi(argv[1]);
+ if (t < 0)
+ printf("%s: bad value\n", argv[1]);
+ else
+ maxtimeout = t;
+}
+
+void
+status(argc, argv)
+ int argc __unused;
+ char *argv[] __unused;
+{
+ if (connected)
+ printf("Connected to %s.\n", hostname);
+ else
+ printf("Not connected.\n");
+ printf("Mode: %s Verbose: %s Tracing: %s\n", mode,
+ verbose ? "on" : "off", trace ? "on" : "off");
+ printf("Rexmt-interval: %d seconds, Max-timeout: %d seconds\n",
+ rexmtval, maxtimeout);
+}
+
+void
+intr(dummy)
+ int dummy __unused;
+{
+
+ signal(SIGALRM, SIG_IGN);
+ alarm(0);
+ longjmp(toplevel, -1);
+}
+
+char *
+tail(filename)
+ char *filename;
+{
+ char *s;
+
+ while (*filename) {
+ s = rindex(filename, '/');
+ if (s == NULL)
+ break;
+ if (s[1])
+ return (s + 1);
+ *s = '\0';
+ }
+ return (filename);
+}
+
+static const char *
+command_prompt()
+{
+
+ return ("tftp> ");
+}
+
+/*
+ * Command parser.
+ */
+static void
+command()
+{
+ HistEvent he;
+ struct cmd *c;
+ static EditLine *el;
+ static History *hist;
+ const char *bp;
+ char *cp;
+ int len, num, vrbose;
+
+ vrbose = isatty(0);
+ if (vrbose) {
+ el = el_init("tftp", stdin, stdout, stderr);
+ hist = history_init();
+ history(hist, &he, H_SETSIZE, 100);
+ el_set(el, EL_HIST, history, hist);
+ el_set(el, EL_EDITOR, "emacs");
+ el_set(el, EL_PROMPT, command_prompt);
+ el_set(el, EL_SIGNAL, 1);
+ el_source(el, NULL);
+ }
+ for (;;) {
+ if (vrbose) {
+ if ((bp = el_gets(el, &num)) == NULL || num == 0)
+ exit(0);
+ len = (num > MAXLINE) ? MAXLINE : num;
+ memcpy(line, bp, len);
+ line[len] = '\0';
+ history(hist, &he, H_ENTER, bp);
+ } else {
+ if (fgets(line, sizeof line , stdin) == 0) {
+ if (feof(stdin)) {
+ exit(txrx_error);
+ } else {
+ continue;
+ }
+ }
+ }
+ if ((cp = strchr(line, '\n')))
+ *cp = '\0';
+ if (line[0] == 0)
+ continue;
+ makeargv();
+ if (margc == 0)
+ continue;
+ c = getcmd(margv[0]);
+ if (c == (struct cmd *)-1) {
+ printf("?Ambiguous command\n");
+ continue;
+ }
+ if (c == 0) {
+ printf("?Invalid command\n");
+ continue;
+ }
+ (*c->handler)(margc, margv);
+ }
+}
+
+struct cmd *
+getcmd(name)
+ char *name;
+{
+ const char *p, *q;
+ struct cmd *c, *found;
+ int nmatches, longest;
+
+ longest = 0;
+ nmatches = 0;
+ found = 0;
+ for (c = cmdtab; (p = c->name) != NULL; c++) {
+ for (q = name; *q == *p++; q++)
+ if (*q == 0) /* exact match? */
+ return (c);
+ if (!*q) { /* the name was a prefix */
+ if (q - name > longest) {
+ longest = q - name;
+ nmatches = 1;
+ found = c;
+ } else if (q - name == longest)
+ nmatches++;
+ }
+ }
+ if (nmatches > 1)
+ return ((struct cmd *)-1);
+ return (found);
+}
+
+/*
+ * Slice a string up into argc/argv.
+ */
+static void
+makeargv()
+{
+ char *cp;
+ char **argp = margv;
+
+ margc = 0;
+ if ((cp = strchr(line, '\n')))
+ *cp = '\0';
+ for (cp = line; margc < MAX_MARGV - 1 && *cp;) {
+ while (isspace((unsigned char)*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *argp++ = cp;
+ margc += 1;
+ while (*cp != '\0' && !isspace((unsigned char)*cp))
+ cp++;
+ if (*cp == '\0')
+ break;
+ *cp++ = '\0';
+ }
+ *argp++ = 0;
+}
+
+void
+quit(argc, argv)
+ int argc __unused;
+ char *argv[] __unused;
+{
+ exit(txrx_error);
+}
+
+/*
+ * Help command.
+ */
+void
+help(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct cmd *c;
+
+ if (argc == 1) {
+ printf("Commands may be abbreviated. Commands are:\n\n");
+ for (c = cmdtab; c->name; c++)
+ printf("%-*s\t%s\n", (int)HELPINDENT, c->name, c->help);
+ return;
+ }
+ while (--argc > 0) {
+ char *arg;
+ arg = *++argv;
+ c = getcmd(arg);
+ if (c == (struct cmd *)-1)
+ printf("?Ambiguous help command %s\n", arg);
+ else if (c == (struct cmd *)0)
+ printf("?Invalid help command %s\n", arg);
+ else
+ printf("%s\n", c->help);
+ }
+}
+
+void
+settrace(argc, argv)
+ int argc __unused;
+ char **argv __unused;
+{
+ trace = !trace;
+ printf("Packet tracing %s.\n", trace ? "on" : "off");
+}
+
+void
+setverbose(argc, argv)
+ int argc __unused;
+ char **argv __unused;
+{
+ verbose = !verbose;
+ printf("Verbose mode %s.\n", verbose ? "on" : "off");
+}
+
+void
+settsize(argc, argv)
+ int argc __unused;
+ char **argv __unused;
+{
+ tsize = !tsize;
+ printf("Tsize mode %s.\n", tsize ? "on" : "off");
+}
+
+void
+settimeoutopt(argc, argv)
+ int argc __unused;
+ char **argv __unused;
+{
+ tout = !tout;
+ printf("Timeout option %s.\n", tout ? "on" : "off");
+}
diff --git a/remote_cmds/tftp.tproj/tftp.1 b/remote_cmds/tftp.tproj/tftp.1
new file mode 100644
index 0000000..fe867ca
--- /dev/null
+++ b/remote_cmds/tftp.tproj/tftp.1
@@ -0,0 +1,243 @@
+.\" $NetBSD: tftp.1,v 1.18 2003/08/07 11:16:14 agc Exp $
+.\"
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" @(#)tftp.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/tftp/tftp.1,v 1.20 2007/11/07 07:56:57 ru Exp $
+.\"
+.Dd June 11, 2003
+.Dt TFTP 1
+.Os
+.Sh NAME
+.Nm tftp
+.Nd "trivial file transfer program"
+.Sh SYNOPSIS
+.Nm
+.Op Fl e
+.Op Ar host
+.Op Ar port
+.Sh DESCRIPTION
+The
+.Nm
+utility is the user interface to the Internet
+.Tn TFTP
+(Trivial File Transfer Protocol),
+which allows users to transfer files to and from a remote machine.
+The remote
+.Ar host
+(and optional
+.Ar port )
+may be specified on the command line, in which case
+.Nm
+uses
+.Ar host
+(and
+.Ar port )
+as the default for future transfers (see the
+.Cm connect
+command below).
+.Pp
+The optional
+.Fl e
+argument sets a binary transfer mode as well as setting the extended options
+as if
+.Cm tout ,
+.Cm tsize ,
+and
+.Cm blksize 65464 ,
+had been given.
+.Sh COMMANDS
+Once
+.Nm
+is running, it issues the prompt
+.Ql tftp\*[Gt]
+and recognizes the following commands:
+.Pp
+.Bl -tag -width verbose -compact
+.It Cm \&? Ar command-name ...
+Print help information.
+.Pp
+.It Cm ascii
+Shorthand for
+.Ic mode Cm ascii .
+.Pp
+.It Cm binary
+Shorthand for
+.Ic mode Cm binary .
+.Pp
+.It Cm blksize Ar blk-size
+Set the tftp blksize option to
+.Ar blk-size
+octets (8-bit bytes). Since the number of blocks in a tftp
+.Cm get
+or
+.Cm put
+is 65535, the default block size of 512 bytes only allows a maximum of
+just under 32 megabytes to be transferred. The value given for
+.Ar blk-size
+must be between 8 and 65464, inclusive.
+Note that many servers will not respect this option.
+.Pp
+.It Cm connect Ar host-name Op Ar port
+Set the
+.Ar host
+(and optionally
+.Ar port )
+for transfers.
+Note that the
+.Tn TFTP
+protocol, unlike the
+.Tn FTP
+protocol,
+does not maintain connections between transfers; thus, the
+.Cm connect
+command does not actually create a connection,
+but merely remembers what host is to be used for transfers.
+You do not have to use the
+.Cm connect
+command; the remote host can be specified as part of the
+.Cm get
+or
+.Cm put
+commands.
+.Pp
+.It Cm get Ar filename
+.It Cm get Ar remotename localname
+.It Cm get Ar file1 file2 ... fileN
+Get one or more files from the remote host.
+When using the
+.Ar host
+argument, the
+.Ar host
+will be used as default host for future transfers.
+If
+.Ar localname
+is specified, the file is stored locally as
+.Ar localname ,
+otherwise the original filename is used.
+Note that it is not possible to download two files at a time, only
+one, three, or more than three files, at a time.
+.Pp
+To specify an IPv6 numeric address for a host, wrap it using square
+brackets like
+.Dq Li [3ffe:2900:e00c:ffee::1234] : Ns Ar file
+to disambiguate the
+colons used in the IPv6 address from the colon separating the host and
+the filename.
+.Pp
+.It Cm mode Ar transfer-mode
+Set the mode for transfers;
+.Ar transfer-mode
+may be one of
+.Cm ascii
+or
+.Cm binary .
+The default is
+.Cm ascii .
+.Pp
+.It Cm put Ar file
+.It Cm put Ar localfile remotefile
+.It Cm put Ar file1 file2 ... fileN remote-directory
+Put a file or set of files to the specified
+remote file or directory.
+The destination
+can be in one of two forms:
+a filename on the remote host, if the host has already been specified,
+or a string of the form
+.Ar hosts:filename
+to specify both a host and filename at the same time.
+If the latter form is used,
+the hostname specified becomes the default for future transfers.
+When
+.Ar remotename
+is specified, the file is stored remotely as
+.Ar remotename ,
+otherwise the original filename is used.
+If the
+.Ar remote-directory
+argument is used, the remote host is assumed to be a
+.Ux
+machine.
+To specify an IPv6 numeric address for a
+.Ar host ,
+see the example under the
+.Cm get
+command.
+.Pp
+.It Cm quit
+Exit
+.Nm .
+An end of file also exits.
+.Pp
+.It Cm rexmt Ar retransmission-timeout
+Set the per-packet retransmission timeout, in seconds.
+.Pp
+.It Cm status
+Show current status.
+.Pp
+.It Cm timeout Ar total-transmission-timeout
+Set the total transmission timeout, in seconds.
+.Pp
+.It Cm tout
+Toggle the tftp "timeout" option. If enabled, the client will pass its
+.Ar retransmission-timeout
+to the server.
+Note that many servers will not respect this option.
+.Pp
+.It Cm trace
+Toggle packet tracing.
+.Pp
+.It Cm tsize
+Toggle the tftp "tsize" option. If enabled, the client will pass and
+request the filesize of a file at the beginning of a file transfer.
+Note that many servers will not respect this option.
+.Pp
+.It Cm verbose
+Toggle verbose mode.
+.El
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
+IPv6 support was implemented by WIDE/KAME project in 1999.
+TFTP options were implemented by Wasabi Systems, Inc., in 2003,
+and first appeared in
+.Nx 2.0 .
+.Sh SECURITY CONSIDERATIONS
+Because there is no user-login or validation within
+the
+.Tn TFTP
+protocol, the remote site will probably have some
+sort of file-access restrictions in place.
+The
+exact methods are specific to each site and therefore
+difficult to document here.
+.Pp
+Files larger than 33488896 octets (65535 blocks) cannot be transferred
+without client and server supporting blocksize negotiation (RFC1783).
diff --git a/remote_cmds/tftp.tproj/tftp.c b/remote_cmds/tftp.tproj/tftp.c
new file mode 100644
index 0000000..56c9750
--- /dev/null
+++ b/remote_cmds/tftp.tproj/tftp.c
@@ -0,0 +1,742 @@
+/* $NetBSD: tftp.c,v 1.18 2003/08/07 11:16:14 agc Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tftp/tftp.c,v 1.13 2006/09/28 21:22:21 matteo Exp $");
+
+/* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
+
+/*
+ * TFTP User Program -- Protocol Machines
+ */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+#include <arpa/tftp.h>
+
+#include <err.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <signal.h>
+#ifdef __APPLE__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+#include "extern.h"
+#include "tftpsubs.h"
+
+extern struct sockaddr_storage peeraddr; /* filled in by main */
+extern int f; /* the opened socket */
+extern int trace;
+extern int verbose;
+extern int def_rexmtval;
+extern int rexmtval;
+extern int maxtimeout;
+extern volatile int txrx_error;
+#ifdef __APPLE__
+extern int tsize;
+extern int tout;
+extern int def_blksize;
+extern int blksize;
+#endif
+
+char ackbuf[PKTSIZE];
+int timeout;
+extern jmp_buf toplevel;
+jmp_buf timeoutbuf;
+
+static void nak(int, struct sockaddr *);
+#ifdef __APPLE__
+static int makerequest(int, const char *, struct tftphdr *, const char *, off_t);
+#else
+static int makerequest(int, const char *, struct tftphdr *, const char *);
+#endif
+static void printstats(const char *, unsigned long);
+static void startclock(void);
+static void stopclock(void);
+static void timer(int);
+static void tpacket(const char *, struct tftphdr *, int);
+static int sockaddrcmp(struct sockaddr *, struct sockaddr *);
+
+static void get_options(struct tftphdr *, int);
+
+static void
+get_options(struct tftphdr *ap, int size)
+{
+ unsigned long val;
+ char *opt, *endp, *nextopt, *valp;
+ int l;
+
+ size -= 2; /* skip over opcode */
+ opt = ap->th_stuff;
+ endp = opt + size - 1;
+ *endp = '\0';
+
+ while (opt < endp) {
+ l = strlen(opt) + 1;
+ valp = opt + l;
+ if (valp < endp) {
+ val = strtoul(valp, NULL, 10);
+ l = strlen(valp) + 1;
+ nextopt = valp + l;
+ if (val == ULONG_MAX && errno == ERANGE) {
+ /* Report illegal value */
+ opt = nextopt;
+ continue;
+ }
+ } else {
+ /* Badly formed OACK */
+ break;
+ }
+ if (strcmp(opt, "tsize") == 0) {
+ /* cool, but we'll ignore it */
+ } else if (strcmp(opt, "timeout") == 0) {
+ if (val >= 1 && val <= 255) {
+ rexmtval = val;
+ } else {
+ /* Report error? */
+ }
+ } else if (strcmp(opt, "blksize") == 0) {
+ if (val >= 8 && val <= MAXSEGSIZE) {
+ blksize = val;
+ } else {
+ /* Report error? */
+ }
+ } else {
+ /* unknown option */
+ }
+ opt = nextopt;
+ }
+}
+
+/*
+ * Send the requested file.
+ */
+void
+xmitfile(fd, name, mode)
+ int fd;
+ char *name;
+ char *mode;
+{
+ struct tftphdr *ap; /* data and ack packets */
+ struct tftphdr *dp;
+ int n;
+ volatile unsigned int block;
+ volatile int size, convert;
+ volatile unsigned long amount;
+ struct sockaddr_storage from;
+ struct stat sbuf;
+ off_t filesize=0;
+ socklen_t fromlen;
+ FILE *file;
+ struct sockaddr_storage peer;
+ struct sockaddr_storage serv; /* valid server port number */
+
+ startclock(); /* start stat's clock */
+ dp = r_init(); /* reset fillbuf/read-ahead code */
+ ap = (struct tftphdr *)ackbuf;
+ if (tsize) {
+ if (fstat(fd, &sbuf) == 0) {
+ filesize = sbuf.st_size;
+ } else {
+ filesize = -1ULL;
+ }
+ }
+ file = fdopen(fd, "r");
+ convert = !strcmp(mode, "netascii");
+ block = 0;
+ amount = 0;
+ memcpy(&peer, &peeraddr, peeraddr.ss_len);
+ memset(&serv, 0, sizeof(serv));
+
+ signal(SIGALRM, timer);
+ do {
+ if (block == 0)
+ size = makerequest(WRQ, name, dp, mode, filesize) - 4;
+ else {
+ /* size = read(fd, dp->th_data, SEGSIZE); */
+ size = readit(file, &dp, blksize, convert);
+ if (size < 0) {
+ nak(errno + 100, (struct sockaddr *)&peer);
+ break;
+ }
+ dp->th_opcode = htons((u_short)DATA);
+ dp->th_block = htons((u_short)block);
+ }
+ timeout = 0;
+ (void) setjmp(timeoutbuf);
+send_data:
+ if (trace)
+ tpacket("sent", dp, size + 4);
+ n = sendto(f, dp, size + 4, 0,
+ (struct sockaddr *)&peer, peer.ss_len);
+ if (n != size + 4) {
+ warn("sendto");
+ goto abort;
+ }
+ if (block)
+ read_ahead(file, blksize, convert);
+ for ( ; ; ) {
+ alarm(rexmtval);
+ do {
+ fromlen = sizeof(from);
+ n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ } while (n <= 0);
+ alarm(0);
+ if (n < 0) {
+ warn("recvfrom");
+ goto abort;
+ }
+ if (!serv.ss_family)
+ serv = from;
+ else if (!sockaddrcmp((struct sockaddr *)&serv,
+ (struct sockaddr *)&from)) {
+ warn("server address/port mismatch");
+ goto abort;
+ }
+ peer = from;
+ if (trace)
+ tpacket("received", ap, n);
+ /* should verify packet came from server */
+ ap->th_opcode = ntohs(ap->th_opcode);
+ if (ap->th_opcode == ERROR) {
+ printf("Error code %d: %s\n", ap->th_code,
+ ap->th_msg);
+ txrx_error = 1;
+ goto abort;
+ }
+ if (ap->th_opcode == ACK) {
+ int j;
+
+ ap->th_block = ntohs(ap->th_block);
+ if (ap->th_block == 0 && block == 0) {
+ /*
+ * If the extended options are enabled,
+ * the server just refused 'em all.
+ * The only one that _really_
+ * matters is blksize, but we'll
+ * clear timeout, too.
+ */
+ blksize = def_blksize;
+ rexmtval = def_rexmtval;
+ }
+ if (ap->th_block == (u_short)block) {
+ break;
+ }
+ /* On an error, try to synchronize
+ * both sides.
+ */
+ j = synchnet(f);
+ if (j && trace) {
+ printf("discarded %d packets\n",
+ j);
+ }
+ if (ap->th_block == (u_short)(block-1)) {
+ goto send_data;
+ }
+ }
+ if (ap->th_opcode == OACK) {
+ if (block == 0) {
+ blksize = def_blksize;
+ rexmtval = def_rexmtval;
+ get_options(ap, n);
+ break;
+ }
+ }
+ }
+ if (block > 0)
+ amount += size;
+ block++;
+ } while (size == blksize || block == 1);
+abort:
+ fclose(file);
+ stopclock();
+ if (amount > 0)
+ printstats("Sent", amount);
+ txrx_error = 1;
+}
+
+/*
+ * Receive a file.
+ */
+void
+recvfile(fd, name, mode)
+ int fd;
+ char *name;
+ char *mode;
+{
+ struct tftphdr *ap;
+ struct tftphdr *dp;
+ int n, oack=0;
+ volatile unsigned int block;
+ volatile int size, firsttrip;
+ volatile unsigned long amount;
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+ int readlen;
+ FILE *file;
+ volatile int convert; /* true if converting crlf -> lf */
+ struct sockaddr_storage peer;
+ struct sockaddr_storage serv; /* valid server port number */
+
+ startclock();
+ dp = w_init();
+ ap = (struct tftphdr *)ackbuf;
+ file = fdopen(fd, "w");
+ convert = !strcmp(mode, "netascii");
+ block = 1;
+ firsttrip = 1;
+ amount = 0;
+ memcpy(&peer, &peeraddr, peeraddr.ss_len);
+ memset(&serv, 0, sizeof(serv));
+
+ signal(SIGALRM, timer);
+ do {
+ short rx_opcode;
+
+ if (firsttrip) {
+ size = makerequest(RRQ, name, ap, mode, 0);
+ readlen = PKTSIZE;
+ firsttrip = 0;
+ } else {
+ ap->th_opcode = htons((u_short)ACK);
+ ap->th_block = htons((u_short)(block));
+ readlen = blksize+4;
+ size = 4;
+ block++;
+ }
+ timeout = 0;
+ (void) setjmp(timeoutbuf);
+send_ack:
+ if (trace)
+ tpacket("sent", ap, size);
+ if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer,
+ peer.ss_len) != size) {
+ alarm(0);
+ warn("sendto");
+ goto abort;
+ }
+ write_behind(file, convert);
+ for ( ; ; ) {
+ int j;
+ unsigned short rx_block;
+
+ alarm(rexmtval);
+ do {
+ fromlen = sizeof(from);
+ n = recvfrom(f, dp, readlen, 0,
+ (struct sockaddr *)&from, &fromlen);
+ } while (n <= 0);
+ alarm(0);
+ if (n < 0) {
+ warn("recvfrom");
+ goto abort;
+ }
+ if (serv.ss_family != AF_UNSPEC
+ && !sockaddrcmp((struct sockaddr *)&serv,
+ (struct sockaddr *)&from)) {
+ /* ignore this packet */
+ if (trace && verbose)
+ tpacket("ignored", dp, n);
+ continue;
+ }
+ if (trace)
+ tpacket("received", dp, n);
+ /* should verify client address */
+ rx_opcode = ntohs(dp->th_opcode);
+ switch (rx_opcode) {
+ case ERROR:
+ printf("Error code %d: %s\n", dp->th_code,
+ dp->th_msg);
+ txrx_error = 1;
+ if (serv.ss_family == AF_UNSPEC) {
+ peer = from;
+ }
+ goto abort;
+ case DATA:
+ rx_block = ntohs(dp->th_block);
+ if (rx_block == (u_short)block) {
+ if (block == 1 && !oack) {
+ /* no OACK, revert to defaults */
+ blksize = def_blksize;
+ rexmtval = def_rexmtval;
+ }
+ if (serv.ss_family == AF_UNSPEC) {
+ peer = serv = from;
+ }
+ goto next_packet;
+ }
+ /* On an error, try to synchronize
+ * both sides.
+ */
+ j = synchnet(f);
+ if (j && trace) {
+ printf("discarded %d packets\n", j);
+ }
+ if (rx_block == (u_short)(block - 1)
+ && serv.ss_family != AF_UNSPEC) {
+ goto send_ack; /* resend ack */
+ }
+ break;
+ case OACK:
+ if (block == 1) {
+ if (serv.ss_family == AF_UNSPEC) {
+ serv = peer = from;
+ }
+ oack = 1;
+ blksize = def_blksize;
+ rexmtval = def_rexmtval;
+ get_options(dp, n);
+ ap->th_opcode = htons(ACK);
+ ap->th_block = 0;
+ readlen = blksize+4;
+ size = 4;
+ goto send_ack;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+next_packet:
+ /* size = write(fd, dp->th_data, n - 4); */
+ size = writeit(file, &dp, n - 4, convert);
+ if (size < 0) {
+ nak(errno + 100, (struct sockaddr *)&peer);
+ break;
+ }
+ amount += size;
+ } while (size == blksize);
+abort: /* ok to ack, since user */
+ ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
+ ap->th_block = htons((u_short)block);
+ (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer,
+ peer.ss_len);
+ write_behind(file, convert); /* flush last buffer */
+ fclose(file);
+ stopclock();
+ if (amount > 0)
+ printstats("Received", amount);
+ txrx_error = 1;
+}
+
+static int
+#ifdef __APPLE__
+makerequest(request, name, tp, mode, filesize)
+#else
+makerequest(request, name, tp, mode)
+#endif
+ int request;
+ const char *name;
+ struct tftphdr *tp;
+ const char *mode;
+#ifdef __APPLE__
+ off_t filesize;
+#endif
+{
+ char *cp;
+
+ tp->th_opcode = htons((u_short)request);
+ cp = tp->th_stuff;
+ strcpy(cp, name);
+ cp += strlen(name);
+ *cp++ = '\0';
+ strcpy(cp, mode);
+ cp += strlen(mode);
+ *cp++ = '\0';
+#ifdef __APPLE__
+ if (tsize) {
+ strcpy(cp, "tsize");
+ cp += strlen(cp);
+ *cp++ = '\0';
+ sprintf(cp, "%lu", (unsigned long) filesize);
+ cp += strlen(cp);
+ *cp++ = '\0';
+ }
+ if (tout) {
+ strcpy(cp, "timeout");
+ cp += strlen(cp);
+ *cp++ = '\0';
+ sprintf(cp, "%d", rexmtval);
+ cp += strlen(cp);
+ *cp++ = '\0';
+ }
+ if (blksize != SEGSIZE) {
+ strcpy(cp, "blksize");
+ cp += strlen(cp);
+ *cp++ = '\0';
+ sprintf(cp, "%d", blksize);
+ cp += strlen(cp);
+ *cp++ = '\0';
+ }
+#endif
+ return (cp - (char *)tp);
+}
+
+struct errmsg {
+ int e_code;
+ const char *e_msg;
+} errmsgs[] = {
+ { EUNDEF, "Undefined error code" },
+ { ENOTFOUND, "File not found" },
+ { EACCESS, "Access violation" },
+ { ENOSPACE, "Disk full or allocation exceeded" },
+ { EBADOP, "Illegal TFTP operation" },
+ { EBADID, "Unknown transfer ID" },
+ { EEXISTS, "File already exists" },
+ { ENOUSER, "No such user" },
+ { EOPTNEG, "Option negotiation failed" },
+ { -1, 0 }
+};
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+static void
+nak(error, peer)
+ int error;
+ struct sockaddr *peer;
+{
+ struct errmsg *pe;
+ struct tftphdr *tp;
+ int length;
+ size_t msglen;
+
+ tp = (struct tftphdr *)ackbuf;
+ tp->th_opcode = htons((u_short)ERROR);
+ msglen = sizeof(ackbuf) - (&tp->th_msg[0] - ackbuf);
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ break;
+ if (pe->e_code < 0) {
+ tp->th_code = EUNDEF;
+ strlcpy(tp->th_msg, strerror(error - 100), msglen);
+ } else {
+ tp->th_code = htons((u_short)error);
+ strlcpy(tp->th_msg, pe->e_msg, msglen);
+ }
+ length = strlen(tp->th_msg);
+ msglen = &tp->th_msg[length + 1] - ackbuf;
+ if (trace)
+ tpacket("sent", tp, (int)msglen);
+ if (sendto(f, ackbuf, msglen, 0, peer, peer->sa_len) != msglen)
+ warn("nak");
+}
+
+static void
+tpacket(s, tp, n)
+ const char *s;
+ struct tftphdr *tp;
+ int n;
+{
+ static const char *opcodes[] =
+ { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR", "OACK" };
+ char *cp, *file, *endp, *opt = NULL, *spc;
+ u_short op = ntohs(tp->th_opcode);
+ int i, o;
+
+ if (op < RRQ || op > OACK)
+ printf("%s opcode=%x ", s, op);
+ else
+ printf("%s %s ", s, opcodes[op]);
+ switch (op) {
+
+ case RRQ:
+ case WRQ:
+ n -= 2;
+ cp = tp->th_stuff;
+ endp = cp + n - 1;
+ if (*endp != '\0') { /* Shouldn't happen, but... */
+ *endp = '\0';
+ }
+ file = cp;
+ cp = strchr(cp, '\0') + 1;
+ printf("<file=%s, mode=%s", file, cp);
+ cp = strchr(cp, '\0') + 1;
+ o = 0;
+ while (cp < endp) {
+ i = strlen(cp) + 1;
+ if (o) {
+ printf(", %s=%s", opt, cp);
+ } else {
+ opt = cp;
+ }
+ o = (o+1) % 2;
+ cp += i;
+ }
+ printf(">\n");
+ break;
+
+ case DATA:
+ printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
+ break;
+
+ case ACK:
+ printf("<block=%d>\n", ntohs(tp->th_block));
+ break;
+
+ case ERROR:
+ printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
+ break;
+
+ case OACK:
+ o = 0;
+ n -= 2;
+ cp = tp->th_stuff;
+ endp = cp + n - 1;
+ if (*endp != '\0') { /* Shouldn't happen, but... */
+ *endp = '\0';
+ }
+ printf("<");
+ spc = "";
+ while (cp < endp) {
+ i = strlen(cp) + 1;
+ if (o) {
+ printf("%s%s=%s", spc, opt, cp);
+ spc = ", ";
+ } else {
+ opt = cp;
+ }
+ o = (o+1) % 2;
+ cp += i;
+ }
+ printf(">\n");
+ break;
+ }
+}
+
+struct timeval tstart;
+struct timeval tstop;
+
+static void
+startclock()
+{
+
+ (void)gettimeofday(&tstart, NULL);
+}
+
+static void
+stopclock()
+{
+
+ (void)gettimeofday(&tstop, NULL);
+}
+
+static void
+printstats(direction, amount)
+ const char *direction;
+ unsigned long amount;
+{
+ double delta;
+ /* compute delta in 1/10's second units */
+ delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
+ ((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
+ delta = delta/10.; /* back to seconds */
+ printf("%s %ld bytes in %.1f seconds", direction, amount, delta);
+ if (verbose)
+ printf(" [%.0f bits/sec]", (amount*8.)/delta);
+ putchar('\n');
+}
+
+static void
+timer(sig)
+ int sig __unused;
+{
+
+ timeout += rexmtval;
+ if (timeout >= maxtimeout) {
+ printf("Transfer timed out.\n");
+ longjmp(toplevel, -1);
+ }
+ txrx_error = 1;
+ longjmp(timeoutbuf, 1);
+}
+
+typedef union {
+ struct sockaddr * addr;
+ struct sockaddr_in * in;
+ struct sockaddr_in6 * in6;
+} sockaddr_union;
+
+static int
+sockaddrcmp(struct sockaddr * sa, struct sockaddr * sb)
+{
+ sockaddr_union a;
+ sockaddr_union b;
+
+ if (sa->sa_len != sb->sa_len
+ || sa->sa_family != sb->sa_family) {
+ return 0;
+ }
+ a.addr = sa;
+ b.addr = sb;
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (a.in->sin_port != b.in->sin_port
+ || a.in->sin_addr.s_addr != b.in->sin_addr.s_addr) {
+ return 0;
+ }
+ break;
+ case AF_INET6:
+ if (a.in6->sin6_port != b.in6->sin6_port
+ || !IN6_ARE_ADDR_EQUAL(&a.in6->sin6_addr,
+ &b.in6->sin6_addr)) {
+ return 0;
+ }
+ break;
+ default:
+ if (bcmp(sa, sb, sa->sa_len) != 0) {
+ return 0;
+ }
+ break;
+ }
+ return 1;
+}
diff --git a/remote_cmds/tftp.tproj/tftpsubs.c b/remote_cmds/tftp.tproj/tftpsubs.c
new file mode 100644
index 0000000..5dbaa87
--- /dev/null
+++ b/remote_cmds/tftp.tproj/tftpsubs.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/tftp/tftpsubs.c,v 1.6 2005/02/14 17:42:58 stefanf Exp $");
+
+#ifndef lint
+__attribute__((__used__))
+static const char sccsid[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/* Simple minded read-ahead/write-behind subroutines for tftp user and
+ server. Written originally with multiple buffers in mind, but current
+ implementation has two buffer logic wired in.
+
+ Todo: add some sort of final error check so when the write-buffer
+ is finally flushed, the caller can detect if the disk filled up
+ (or had an i/o error) and return a nak to the other side.
+
+ Jim Guyton 10/85
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "tftpsubs.h"
+
+#ifdef __APPLE__
+struct bf {
+ int counter; /* size of data in buffer, or flag */
+ char buf[MAXPKTSIZE]; /* room for data packet */
+} bfs[2];
+#else
+#define PKTSIZE SEGSIZE+4 /* should be moved to tftp.h */
+
+struct bf {
+ int counter; /* size of data in buffer, or flag */
+ char buf[PKTSIZE]; /* room for data packet */
+} bfs[2];
+#endif
+
+ /* Values for bf.counter */
+#define BF_ALLOC -3 /* alloc'd but not yet filled */
+#define BF_FREE -2 /* free */
+/* [-1 .. SEGSIZE] = size of data in the data buffer */
+
+static int nextone; /* index of next buffer to use */
+static int current; /* index of buffer in use */
+
+ /* control flags for crlf conversions */
+int newline = 0; /* fillbuf: in middle of newline expansion */
+int prevchar = -1; /* putbuf: previous char (cr check) */
+
+static struct tftphdr *rw_init(int);
+
+struct tftphdr *w_init(void) { return rw_init(0); } /* write-behind */
+struct tftphdr *r_init(void) { return rw_init(1); } /* read-ahead */
+
+static struct tftphdr *
+rw_init(x) /* init for either read-ahead or write-behind */
+ int x; /* zero for write-behind, one for read-head */
+{
+ newline = 0; /* init crlf flag */
+ prevchar = -1;
+ bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
+ current = 0;
+ bfs[1].counter = BF_FREE;
+ nextone = x; /* ahead or behind? */
+ return (struct tftphdr *)bfs[0].buf;
+}
+
+
+/* Have emptied current buffer by sending to net and getting ack.
+ Free it and return next buffer filled with data.
+ */
+int
+readit(file, dpp, amt, convert)
+ FILE *file; /* file opened for read */
+ struct tftphdr **dpp;
+ int amt;
+ int convert; /* if true, convert to ascii */
+{
+ struct bf *b;
+
+ bfs[current].counter = BF_FREE; /* free old one */
+ current = !current; /* "incr" current */
+
+ b = &bfs[current]; /* look at new buffer */
+ if (b->counter == BF_FREE) /* if it's empty */
+ read_ahead(file, amt, convert); /* fill it */
+/* assert(b->counter != BF_FREE);*//* check */
+ *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
+ return b->counter;
+}
+
+/*
+ * fill the input buffer, doing ascii conversions if requested
+ * conversions are lf -> cr,lf and cr -> cr, nul
+ */
+void
+read_ahead(file, amt, convert)
+ FILE *file; /* file opened for read */
+ int amt; /* number of bytes to read */
+ int convert; /* if true, convert to ascii */
+{
+ int i;
+ char *p;
+ int c;
+ struct bf *b;
+ struct tftphdr *dp;
+
+ b = &bfs[nextone]; /* look at "next" buffer */
+ if (b->counter != BF_FREE) /* nop if not free */
+ return;
+ nextone = !nextone; /* "incr" next buffer ptr */
+
+ dp = (struct tftphdr *)b->buf;
+
+ if (convert == 0) {
+ b->counter = read(fileno(file), dp->th_data, amt);
+ return;
+ }
+
+ p = dp->th_data;
+ for (i = 0 ; i < amt; i++) {
+ if (newline) {
+ if (prevchar == '\n')
+ c = '\n'; /* lf to cr,lf */
+ else c = '\0'; /* cr to cr,nul */
+ newline = 0;
+ }
+ else {
+ c = getc(file);
+ if (c == EOF) break;
+ if (c == '\n' || c == '\r') {
+ prevchar = c;
+ c = '\r';
+ newline = 1;
+ }
+ }
+ *p++ = c;
+ }
+ b->counter = (int)(p - dp->th_data);
+}
+
+/* Update count associated with the buffer, get new buffer
+ from the queue. Calls write_behind only if next buffer not
+ available.
+ */
+int
+writeit(file, dpp, ct, convert)
+ FILE *file;
+ struct tftphdr **dpp;
+ int ct, convert;
+{
+ bfs[current].counter = ct; /* set size of data to write */
+ current = !current; /* switch to other buffer */
+ if (bfs[current].counter != BF_FREE) /* if not free */
+ (void)write_behind(file, convert); /* flush it */
+ bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
+ *dpp = (struct tftphdr *)bfs[current].buf;
+ return ct; /* this is a lie of course */
+}
+
+/*
+ * Output a buffer to a file, converting from netascii if requested.
+ * CR,NUL -> CR and CR,LF => LF.
+ * Note spec is undefined if we get CR as last byte of file or a
+ * CR followed by anything else. In this case we leave it alone.
+ */
+int
+write_behind(file, convert)
+ FILE *file;
+ int convert;
+{
+ char *buf;
+ int count;
+ int ct;
+ char *p;
+ int c; /* current character */
+ struct bf *b;
+ struct tftphdr *dp;
+
+ b = &bfs[nextone];
+ if (b->counter < -1) /* anything to flush? */
+ return 0; /* just nop if nothing to do */
+
+ count = b->counter; /* remember byte count */
+ b->counter = BF_FREE; /* reset flag */
+ dp = (struct tftphdr *)b->buf;
+ nextone = !nextone; /* incr for next time */
+ buf = dp->th_data;
+
+ if (count <= 0) return -1; /* nak logic? */
+
+ if (convert == 0)
+ return write(fileno(file), buf, count);
+
+ p = buf;
+ ct = count;
+ while (ct--) { /* loop over the buffer */
+ c = *p++; /* pick up a character */
+ if (prevchar == '\r') { /* if prev char was cr */
+ if (c == '\n') /* if have cr,lf then just */
+ fseek(file, -1, 1); /* smash lf on top of the cr */
+ else
+ if (c == '\0') /* if have cr,nul then */
+ goto skipit; /* just skip over the putc */
+ /* else just fall through and allow it */
+ }
+ putc(c, file);
+skipit:
+ prevchar = c;
+ }
+ return count;
+}
+
+
+/* When an error has occurred, it is possible that the two sides
+ * are out of synch. Ie: that what I think is the other side's
+ * response to packet N is really their response to packet N-1.
+ *
+ * So, to try to prevent that, we flush all the input queued up
+ * for us on the network connection on our host.
+ *
+ * We return the number of packets we flushed (mostly for reporting
+ * when trace is active).
+ */
+
+int
+synchnet(f)
+ int f; /* socket to flush */
+{
+ int i, j = 0;
+ char rbuf[PKTSIZE];
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+
+ while (1) {
+ (void) ioctl(f, FIONREAD, &i);
+ if (i) {
+ j++;
+ fromlen = sizeof from;
+ (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ } else {
+ return(j);
+ }
+ }
+}
diff --git a/remote_cmds/tftp.tproj/tftpsubs.h b/remote_cmds/tftp.tproj/tftpsubs.h
new file mode 100644
index 0000000..808acb2
--- /dev/null
+++ b/remote_cmds/tftp.tproj/tftpsubs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tftpsubs.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/tftp/tftpsubs.h,v 1.2 2002/03/22 01:42:34 imp Exp $
+ */
+
+/*
+ * Prototypes for read-ahead/write-behind subroutines for tftp user and
+ * server.
+ */
+struct tftphdr *r_init(void);
+#ifdef __APPLE__
+void read_ahead(FILE *, int, int);
+int readit(FILE *, struct tftphdr **, int, int);
+#else
+void read_ahead(FILE *, int);
+int readit(FILE *, struct tftphdr **, int);
+#endif
+
+int synchnet(int);
+
+struct tftphdr *w_init(void);
+int write_behind(FILE *, int);
+int writeit(FILE *, struct tftphdr **, int, int);
diff --git a/remote_cmds/tftpd.tproj/DERIVED_FILES b/remote_cmds/tftpd.tproj/DERIVED_FILES
new file mode 100644
index 0000000..6e6534d
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/DERIVED_FILES
@@ -0,0 +1,5 @@
+# The following files have been derived from another project. If you do any
+# changes to them here, make sure you mirror them there too.
+
+argon_usrbin/tftp/tftpsubs.h
+argon_usrbin/tftp/tftpsubs.c
diff --git a/remote_cmds/tftpd.tproj/Makefile b/remote_cmds/tftpd.tproj/Makefile
new file mode 100644
index 0000000..e48f484
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/Makefile
@@ -0,0 +1,16 @@
+Project = tftpd
+Install_Dir = /usr/libexec
+
+HFILES = tftpsubs.h
+CFILES = tftpd.c ../tftp.tproj/tftpsubs.c
+MANPAGES = tftpd.8
+LAUNCHD_PLISTS = tftp.plist
+
+Extra_CC_Flags = -Wall -Werror -fPIE
+Extra_CC_Flags += -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -pie
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
+
+after_install:
+ $(MKDIR) "$(DSTROOT)/private/tftpboot"
diff --git a/remote_cmds/tftpd.tproj/tftp.plist b/remote_cmds/tftpd.tproj/tftp.plist
new file mode 100644
index 0000000..e31e08b
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftp.plist
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.tftpd</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/tftpd</string>
+ <string>-i</string>
+ <string>/private/tftpboot</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <true/>
+ </dict>
+ <key>InitGroups</key>
+ <true/>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>tftp</string>
+ <key>SockType</key>
+ <string>dgram</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/remote_cmds/tftpd.tproj/tftpd.8 b/remote_cmds/tftpd.tproj/tftpd.8
new file mode 100644
index 0000000..14df0f1
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftpd.8
@@ -0,0 +1,233 @@
+.\" $NetBSD: tftpd.8,v 1.21 2003/08/07 09:46:53 agc Exp $
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" from: @(#)tftpd.8 8.1 (Berkeley) 6/4/93
+.\"
+.Dd June 11, 2003
+.Dt TFTPD 8
+.Os
+.Sh NAME
+.Nm tftpd
+.Nd
+.Tn DARPA
+Internet Trivial File Transfer Protocol server
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl g Ar group
+.Op Fl i
+.Op Fl l
+.Op Fl n
+.Op Fl s Ar directory
+.Op Fl u Ar user
+.Op Ar directory ...
+.Sh DESCRIPTION
+.Nm
+is a server which supports the
+.Tn DARPA
+Trivial File Transfer Protocol.
+The
+.Tn TFTP
+server operates at the port indicated in the
+.Ql tftp
+service description; see
+.Xr services 5 .
+This server should not be started manually; instead, it should be run using
+.Xr launchd 8
+using the plist
+.Pa /System/Library/LaunchDaemons/tftp.plist .
+It may be started using the
+.Xr launchctl 1
+load command; refer to the documentation for that utility for more information.
+.Pp
+The use of
+.Xr tftp 1
+does not require an account or password on the remote system.
+Due to the lack of authentication information,
+.Nm
+will allow only publicly readable files to be accessed.
+Filenames beginning in ``\|\fB.\|.\fP\|/'' or
+containing ``/\|\fB.\|.\fP\|/'' are not allowed.
+Files may be written to only if they already exist and are publicly writable.
+.Pp
+Note that this extends the concept of
+.Qq public
+to include
+all users on all hosts that can be reached through the network;
+this may not be appropriate on all systems, and its implications
+should be considered before enabling tftp service.
+The server should have the user ID with the lowest possible privilege.
+.Pp
+Access to files may be restricted by invoking
+.Nm
+with a list of directories by including up to 20 pathnames
+as server program arguments in
+.Pa /System/Library/LaunchDaemons/tftp.plist .
+In this case access is restricted to files whose
+names are prefixed by the one of the given directories.
+The given directories are also treated as a search path for
+relative filename requests.
+.Pp
+The options are:
+.Bl -tag -width "directory"
+.It Fl d
+Enable verbose debugging messages to
+.Xr syslogd 8 .
+.It Fl g Ar group
+Change gid to that of
+.Ar group
+on startup.
+If this isn't specified, the gid is set to that of the
+.Ar user
+specified with
+.Fl u .
+.It Fl i
+Enable insecure mode, no
+.Xr realpath 3 .
+.It Fl l
+Logs all requests using
+.Xr syslog 3 .
+.It Fl n
+Suppresses negative acknowledgement of requests for nonexistent
+relative filenames.
+.It Fl s Ar directory
+.Nm
+will
+.Xr chroot 2
+to
+.Ar directory
+on startup.
+This is recommended for security reasons (so that files other than
+those in the
+.Pa /tftpboot
+directory aren't accessible).
+If the remote host passes the directory name as part of the
+file name to transfer, you may have to create a symbolic link
+from
+.Sq tftpboot
+to
+.Sq \&.
+under
+.Pa /tftpboot .
+.It Fl u Ar user
+Change uid to that of
+.Ar user
+on startup.
+If
+.Fl u
+isn't given,
+.Ar user
+defaults to
+.Dq nobody .
+If
+.Fl g
+isn't also given, change the gid to that of
+.Ar user
+as well.
+.El
+.Sh SEE ALSO
+.Xr tftp 1 ,
+.Xr launchd 8 ,
+.Xr launchctl 1 ,
+.Xr launchd.plist 5
+.Rs
+.%R RFC
+.%N 1350
+.%D July 1992
+.%T "The TFTP Protocol (Revision 2)"
+.Re
+.Rs
+.%R RFC
+.%N 2347
+.%D May 1998
+.%T "TFTP Option Extension"
+.Re
+.Rs
+.%R RFC
+.%N 2348
+.%D May 1998
+.%T "TFTP Blocksize Option"
+.Re
+.Rs
+.%R RFC
+.%N 2349
+.%D May 1998
+.%T "TFTP Timeout Interval and Transfer Size Options"
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
+.Pp
+The
+.Fl s
+flag appeared in
+.Nx 1.0 .
+.Pp
+The
+.Fl g
+and
+.Fl u
+flags appeared in
+.Nx 1.4 .
+.Pp
+IPv6 support was implemented by WIDE/KAME project in 1999.
+.Pp
+TFTP options were implemented by Wasabi Systems, Inc., in 2003,
+and first appeared in
+NetBSD 2.0 .
+.Sh BUGS
+Files larger than 33488896 octets (65535 blocks) cannot be transferred
+without client and server supporting blocksize negotiation (RFCs
+2347 and 2348).
+.Pp
+Many tftp clients will not transfer files over 16744448 octets (32767 blocks).
+.Sh SECURITY CONSIDERATIONS
+You are
+.Em strongly
+advised to set up
+.Nm
+using the
+.Fl s
+flag in conjunction with the name of the directory that
+contains the files that
+.Nm
+will serve to remote hosts (e.g.,
+.Pa /tftpboot ) .
+This ensures that only the files that should be served
+to remote hosts can be accessed by them.
+.Pp
+Because there is no user-login or validation within
+the
+.Tn TFTP
+protocol, the remote site will probably have some
+sort of file-access restrictions in place.
+The exact methods are specific to each site and therefore
+difficult to document here.
diff --git a/remote_cmds/tftpd.tproj/tftpd.c b/remote_cmds/tftpd.tproj/tftpd.c
new file mode 100644
index 0000000..8e4c118
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftpd.c
@@ -0,0 +1,1238 @@
+/* $NetBSD: tftpd.c,v 1.28 2004/05/05 20:15:45 kleink Exp $ */
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tftpd.c 8.1 (Berkeley) 6/4/93";
+#endif
+__attribute__((__used__))
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/tftpd/tftpd.c,v 1.38 2007/11/23 00:05:29 edwin Exp $";
+#endif /* not lint */
+
+/*
+ * Trivial file transfer protocol server.
+ *
+ * This version includes many modifications by Jim Guyton
+ * <guyton@rand-unix>.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "tftpsubs.h"
+
+#define DEFAULTUSER "nobody"
+
+#define TIMEOUT 5
+#define MAX_TIMEOUTS 5
+
+int peer;
+int rexmtval = TIMEOUT;
+int maxtimeout = 5*TIMEOUT;
+
+char buf[MAXPKTSIZE];
+char ackbuf[PKTSIZE];
+char oackbuf[PKTSIZE];
+struct sockaddr_storage from;
+socklen_t fromlen;
+int debug;
+
+int tftp_opt_tsize = 0;
+int tftp_blksize = SEGSIZE;
+int tftp_tsize = 0;
+
+/*
+ * Null-terminated directory prefix list for absolute pathname requests and
+ * search list for relative pathname requests.
+ *
+ * MAXDIRS should be at least as large as the number of arguments that
+ * inetd allows (currently 20).
+ */
+#define MAXDIRS 20
+static struct dirlist {
+ const char *name;
+ int len;
+} dirs[MAXDIRS+1];
+static int suppress_naks;
+static int logging;
+static int insecure=0;
+static int secure;
+static char *securedir;
+
+struct formats;
+
+static const char *errtomsg(int);
+static void nak(int);
+#ifndef __APPLE__
+static void oack(void);
+#endif
+
+static void timer(int);
+static void justquit(int);
+
+static void tftp(struct tftphdr *, int);
+static void usage(void);
+static char *verifyhost(struct sockaddr *);
+int main(int, char **);
+void recvfile(struct formats *, int, int);
+void xmitfile(struct formats *, int, int);
+static const char *opcode(int);
+int validate_access(char **, int);
+
+struct formats {
+ const char *f_mode;
+ int (*f_validate)(char **, int);
+ void (*f_send)(struct formats *, int, int);
+ void (*f_recv)(struct formats *, int, int);
+ int f_convert;
+} formats[] = {
+ { "netascii", validate_access, xmitfile, recvfile, 1 },
+ { "octet", validate_access, xmitfile, recvfile, 0 },
+ { 0 }
+};
+
+static void
+usage(void)
+{
+
+ syslog(LOG_ERR,
+ "Usage: %s [-diln] [-u user] [-g group] [-s directory] [directory ...]",
+ getprogname());
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct sockaddr_storage me;
+ struct passwd *pwent;
+ struct group *grent;
+ struct tftphdr *tp;
+ char *tgtuser, *tgtgroup, *ep;
+ int n, ch, on, fd;
+ socklen_t len;
+ int soopt;
+ uid_t curuid, tgtuid;
+ gid_t curgid, tgtgid;
+ long nid;
+
+ n = 0;
+ fd = 0;
+ tzset();
+ openlog("tftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
+ tgtuser = DEFAULTUSER;
+ tgtgroup = NULL;
+ curuid = getuid();
+ curgid = getgid();
+
+ while ((ch = getopt(argc, argv, "dg:ilns:u:")) != -1)
+ switch (ch) {
+ case 'd':
+ debug++;
+ break;
+
+ case 'g':
+ tgtgroup = optarg;
+ break;
+
+ case 'i':
+ insecure = 1;
+ break;
+
+ case 'l':
+ logging = 1;
+ break;
+
+ case 'n':
+ suppress_naks = 1;
+ break;
+
+ case 's':
+ secure = 1;
+ securedir = optarg;
+ break;
+
+ case 'u':
+ tgtuser = optarg;
+ break;
+
+ default:
+ usage();
+ break;
+ }
+
+ if (optind < argc) {
+ struct dirlist *dirp;
+
+ /* Get list of directory prefixes. Skip relative pathnames. */
+ for (dirp = dirs; optind < argc && dirp < &dirs[MAXDIRS];
+ optind++) {
+ if (argv[optind][0] == '/') {
+ dirp->name = argv[optind];
+ dirp->len = strlen(dirp->name);
+ dirp++;
+ }
+ }
+ }
+
+ if (*tgtuser == '\0' || (tgtgroup != NULL && *tgtgroup == '\0'))
+ usage();
+
+ nid = (strtol(tgtuser, &ep, 10));
+ if (*ep == '\0') {
+ if (nid > UID_MAX) {
+ syslog(LOG_ERR, "uid %ld is too large", nid);
+ exit(1);
+ }
+ pwent = getpwuid((uid_t)nid);
+ } else
+ pwent = getpwnam(tgtuser);
+ if (pwent == NULL) {
+ syslog(LOG_ERR, "unknown user `%s'", tgtuser);
+ exit(1);
+ }
+ tgtuid = pwent->pw_uid;
+ tgtgid = pwent->pw_gid;
+
+ if (tgtgroup != NULL) {
+ nid = (strtol(tgtgroup, &ep, 10));
+ if (*ep == '\0') {
+ if (nid > GID_MAX) {
+ syslog(LOG_ERR, "gid %ld is too large", nid);
+ exit(1);
+ }
+ grent = getgrgid((gid_t)nid);
+ } else
+ grent = getgrnam(tgtgroup);
+ if (grent != NULL)
+ tgtgid = grent->gr_gid;
+ else {
+ syslog(LOG_ERR, "unknown group `%s'", tgtgroup);
+ exit(1);
+ }
+ }
+
+ if (secure) {
+ if (chdir(securedir) < 0) {
+ syslog(LOG_ERR, "chdir %s: %m", securedir);
+ exit(1);
+ }
+ if (chroot(".")) {
+ syslog(LOG_ERR, "chroot: %m");
+ exit(1);
+ }
+ }
+
+ if (logging)
+ syslog(LOG_DEBUG, "running as user `%s' (%d), group `%s' (%d)",
+ tgtuser, tgtuid, tgtgroup ? tgtgroup : "(unspecified)",
+ tgtgid);
+ if (curgid != tgtgid) {
+ if (setgid(tgtgid)) {
+ syslog(LOG_ERR, "setgid to %d: %m", (int)tgtgid);
+ exit(1);
+ }
+ if (setgroups(0, NULL)) {
+ syslog(LOG_ERR, "setgroups: %m");
+ exit(1);
+ }
+ }
+
+ if (curuid != tgtuid) {
+ if (setuid(tgtuid)) {
+ syslog(LOG_ERR, "setuid to %d: %m", (int)tgtuid);
+ exit(1);
+ }
+ }
+
+ on = 1;
+ if (ioctl(fd, FIONBIO, &on) < 0) {
+ syslog(LOG_ERR, "ioctl(FIONBIO): %m");
+ exit(1);
+ }
+ fromlen = sizeof (from);
+ n = recvfrom(fd, buf, sizeof (buf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ if (n < 0) {
+ syslog(LOG_ERR, "recvfrom: %m");
+ exit(1);
+ }
+ /*
+ * Now that we have read the message out of the UDP
+ * socket, we fork and exit. Thus, inetd will go back
+ * to listening to the tftp port, and the next request
+ * to come in will start up a new instance of tftpd.
+ *
+ * We do this so that inetd can run tftpd in "wait" mode.
+ * The problem with tftpd running in "nowait" mode is that
+ * inetd may get one or more successful "selects" on the
+ * tftp port before we do our receive, so more than one
+ * instance of tftpd may be started up. Worse, if tftpd
+ * break before doing the above "recvfrom", inetd would
+ * spawn endless instances, clogging the system.
+ */
+ {
+ int i, pid;
+ socklen_t j;
+
+ for (i = 1; i < 20; i++) {
+ pid = fork();
+ if (pid < 0) {
+ sleep(i);
+ /*
+ * flush out to most recently sent request.
+ *
+ * This may drop some request, but those
+ * will be resent by the clients when
+ * they timeout. The positive effect of
+ * this flush is to (try to) prevent more
+ * than one tftpd being started up to service
+ * a single request from a single client.
+ */
+ j = sizeof from;
+ i = recvfrom(fd, buf, sizeof (buf), 0,
+ (struct sockaddr *)&from, &j);
+ if (i > 0) {
+ n = i;
+ fromlen = j;
+ }
+ } else {
+ break;
+ }
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ exit(1);
+ } else if (pid != 0) {
+ exit(0);
+ }
+ }
+
+ /*
+ * remember what address this was sent to, so we can respond on the
+ * same interface
+ */
+ len = sizeof(me);
+ if (getsockname(fd, (struct sockaddr *)&me, &len) == 0) {
+ switch (me.ss_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)&me)->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)&me)->sin6_port = 0;
+ break;
+ default:
+ /* unsupported */
+ break;
+ }
+ } else {
+ memset(&me, 0, sizeof(me));
+ me.ss_family = from.ss_family;
+ me.ss_len = from.ss_len;
+ }
+ alarm(0);
+ close(fd);
+ close(1);
+ peer = socket(from.ss_family, SOCK_DGRAM, 0);
+ if (peer < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ exit(1);
+ }
+ if (bind(peer, (struct sockaddr *)&me, me.ss_len) < 0) {
+ syslog(LOG_ERR, "bind: %m");
+ exit(1);
+ }
+ if (connect(peer, (struct sockaddr *)&from, from.ss_len) < 0) {
+ syslog(LOG_ERR, "connect: %m");
+ exit(1);
+ }
+ soopt = 65536; /* larger than we'll ever need */
+ if (setsockopt(peer, SOL_SOCKET, SO_SNDBUF, (void *) &soopt, sizeof(soopt)) < 0) {
+ syslog(LOG_ERR, "set SNDBUF: %m");
+ exit(1);
+ }
+ if (setsockopt(peer, SOL_SOCKET, SO_RCVBUF, (void *) &soopt, sizeof(soopt)) < 0) {
+ syslog(LOG_ERR, "set RCVBUF: %m");
+ exit(1);
+ }
+
+ tp = (struct tftphdr *)buf;
+ tp->th_opcode = ntohs(tp->th_opcode);
+ if (tp->th_opcode == RRQ || tp->th_opcode == WRQ)
+ tftp(tp, n);
+ exit(1);
+}
+
+static int
+blk_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
+ int *ackl, int *ec)
+{
+ unsigned long bsize;
+ char *endp;
+ int l;
+
+ /*
+ * On these failures, we could just ignore the blocksize option.
+ * Perhaps that should be a command-line option.
+ */
+ errno = 0;
+ bsize = strtoul(val, &endp, 10);
+ if ((bsize == ULONG_MAX && errno == ERANGE) || *endp) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "illegal value %s for blksize option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+ if (bsize < 8 || bsize > 65464) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "out of range value %s for blksize option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+
+ tftp_blksize = bsize;
+ strcpy(ack + *ackl, "blksize");
+ *ackl += 8;
+ l = sprintf(ack + *ackl, "%lu", bsize);
+ *ackl += l + 1;
+
+ return 0;
+}
+
+static int
+timeout_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
+ int *ackl, int *ec)
+{
+ unsigned long tout;
+ char *endp;
+ int l;
+
+ errno = 0;
+ tout = strtoul(val, &endp, 10);
+ if ((tout == ULONG_MAX && errno == ERANGE) || *endp) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "illegal value %s for timeout option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+ if (tout < 1 || tout > 255) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "out of range value %s for timeout option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+
+ rexmtval = tout;
+ strcpy(ack + *ackl, "timeout");
+ *ackl += 8;
+ l = sprintf(ack + *ackl, "%lu", tout);
+ *ackl += l + 1;
+
+ /*
+ * Arbitrarily pick a maximum timeout on a request to 3
+ * retransmissions if the interval timeout is more than
+ * one minute. Longest possible timeout is therefore
+ * 3 * 255 - 1, or 764 seconds.
+ */
+ if (rexmtval > 60) {
+ maxtimeout = rexmtval * 3;
+ } else {
+ maxtimeout = rexmtval * 5;
+ }
+
+ return 0;
+}
+
+static int
+tsize_handler(struct tftphdr *tp, char *opt, char *val, char *ack,
+ int *ackl, int *ec)
+{
+ unsigned long fsize;
+ char *endp;
+
+ /*
+ * Maximum file even with extended tftp is 65535 blocks of
+ * length 65464, or 4290183240 octets (4784056 less than 2^32).
+ * unsigned long is at least 32 bits on all NetBSD archs.
+ */
+
+ errno = 0;
+ fsize = strtoul(val, &endp, 10);
+ if ((fsize == ULONG_MAX && errno == ERANGE) || *endp) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "illegal value %s for tsize option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+ if (fsize > (unsigned long) 65535 * 65464) {
+ syslog(LOG_NOTICE, "%s: %s request for %s: "
+ "out of range value %s for tsize option",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ tp->th_stuff, val);
+ return 0;
+ }
+
+ tftp_opt_tsize = 1;
+ tftp_tsize = fsize;
+ /*
+ * We will report this later -- either replying with the fsize (WRQ)
+ * or replying with the actual filesize (RRQ).
+ */
+
+ return 0;
+}
+
+struct tftp_options {
+ char *o_name;
+ int (*o_handler)(struct tftphdr *, char *, char *, char *,
+ int *, int *);
+} options[] = {
+ { "blksize", blk_handler },
+ { "timeout", timeout_handler },
+ { "tsize", tsize_handler },
+ { NULL, NULL }
+};
+
+enum opt_enum {
+ OPT_TSIZE = 0,
+ OPT_TIMEOUT,
+};
+
+/*
+ * Get options for an extended tftp session. Stuff the ones we
+ * recognize in oackbuf.
+ */
+static int
+get_options(struct tftphdr *tp, char *cp, int size, char *ackb,
+ int *alen, int *err)
+{
+ struct tftp_options *op;
+ char *option, *value, *endp;
+ int r, rv=0, ec=0;
+
+ endp = cp + size;
+ while (cp < endp) {
+ option = cp;
+ while (*cp && cp < endp) {
+ *cp = tolower(*cp);
+ cp++;
+ }
+ if (*cp) {
+ /* if we have garbage at the end, just ignore it */
+ break;
+ }
+ cp++; /* skip over NUL */
+ value = cp;
+ while (*cp && cp < endp) {
+ cp++;
+ }
+ if (*cp) {
+ /* if we have garbage at the end, just ignore it */
+ break;
+ }
+ cp++;
+ for (op = options; op->o_name; op++) {
+ if (strcmp(op->o_name, option) == 0)
+ break;
+ }
+ if (op->o_name) {
+ r = op->o_handler(tp, option, value, ackb, alen, &ec);
+ if (r < 0) {
+ rv = -1;
+ break;
+ }
+ rv++;
+ } /* else ignore unknown options */
+ }
+
+ if (rv < 0)
+ *err = ec;
+
+ return rv;
+}
+
+/*
+ * Handle initial connection protocol.
+ */
+static void
+tftp(struct tftphdr *tp, int size)
+{
+ struct formats *pf;
+ char *cp;
+ char *filename, *mode;
+ int first, ecode=0, alen, etftp=0, r;
+
+ first = 1;
+ mode = NULL;
+
+ filename = cp = tp->th_stuff;
+again:
+ while (cp < buf + size) {
+ if (*cp == '\0')
+ break;
+ cp++;
+ }
+ if (*cp != '\0') {
+ nak(EBADOP);
+ exit(1);
+ }
+ if (first) {
+ mode = ++cp;
+ first = 0;
+ goto again;
+ }
+ for (cp = mode; *cp; cp++)
+ if (isupper(*cp))
+ *cp = tolower(*cp);
+ for (pf = formats; pf->f_mode; pf++)
+ if (strcmp(pf->f_mode, mode) == 0)
+ break;
+ if (pf->f_mode == 0) {
+ nak(EBADOP);
+ exit(1);
+ }
+ /*
+ * cp currently points to the NUL byte following the mode.
+ *
+ * If we have some valid options, then let's assume that we're
+ * now dealing with an extended tftp session. Note that if we
+ * don't get any options, then we *must* assume that we do not
+ * have an extended tftp session. If we get options, we fill
+ * in the ack buf to acknowledge them. If we skip that, then
+ * the client *must* assume that we are not using an extended
+ * session.
+ */
+ size -= (++cp - (char *) tp);
+ if (size > 0 && *cp) {
+ alen = 2; /* Skip over opcode */
+ r = get_options(tp, cp, size, oackbuf, &alen, &ecode);
+ if (r > 0) {
+ etftp = 1;
+ } else if (r < 0) {
+ nak(ecode);
+ exit(1);
+ }
+ }
+ ecode = (*pf->f_validate)(&filename, tp->th_opcode);
+ if (logging) {
+ syslog(LOG_INFO, "%s: %s request for %s: %s",
+ verifyhost((struct sockaddr *)&from),
+ tp->th_opcode == WRQ ? "write" : "read",
+ filename, errtomsg(ecode));
+ }
+ if (ecode) {
+ /*
+ * Avoid storms of naks to a RRQ broadcast for a relative
+ * bootfile pathname from a diskless Sun.
+ */
+ if (suppress_naks && *filename != '/' && ecode == ENOTFOUND)
+ exit(0);
+ nak(ecode);
+ exit(1);
+ }
+
+ if (etftp) {
+ struct tftphdr *oack_h;
+
+ if (tftp_opt_tsize) {
+ int l;
+
+ strcpy(oackbuf + alen, "tsize");
+ alen += 6;
+ l = sprintf(oackbuf + alen, "%u", tftp_tsize);
+ alen += l + 1;
+ }
+ oack_h = (struct tftphdr *) oackbuf;
+ oack_h->th_opcode = htons(OACK);
+ }
+
+ if (tp->th_opcode == WRQ)
+ (*pf->f_recv)(pf, etftp, alen);
+ else
+ (*pf->f_send)(pf, etftp, alen);
+ exit(0);
+}
+
+
+FILE *file;
+
+/*
+ * Validate file access. Since we
+ * have no uid or gid, for now require
+ * file to exist and be publicly
+ * readable/writable.
+ * If we were invoked with arguments
+ * from inetd then the file must also be
+ * in one of the given directory prefixes.
+ */
+int
+validate_access(char **filep, int mode)
+{
+ struct stat stbuf;
+ struct dirlist *dirp;
+ static char pathname[MAXPATHLEN];
+ int fd;
+ char *filename;
+#ifdef __APPLE__
+ static char resolved_path[PATH_MAX+1];
+ bzero(resolved_path,PATH_MAX+1);
+ if(insecure) {
+ filename = *filep;
+ } else {
+ if (realpath(*filep, resolved_path)==NULL) {
+ return (EACCESS);
+ }
+ filename = resolved_path;
+ }
+#else
+ filename = *filep;
+#endif
+ /*
+ * Prevent tricksters from getting around the directory restrictions
+ */
+ if (strstr(filename, "/../"))
+ return (EACCESS);
+
+ if (*filename == '/') {
+ /*
+ * Allow the request if it's in one of the approved locations.
+ * Special case: check the null prefix ("/") by looking
+ * for length = 1 and relying on the arg. processing that
+ * it's a /.
+ */
+ for (dirp = dirs; dirp->name != NULL; dirp++) {
+ if (dirp->len == 1 ||
+ (!strncmp(filename, dirp->name, dirp->len) &&
+ filename[dirp->len] == '/'))
+ break;
+ }
+ /* If directory list is empty, allow access to any file */
+ if (dirp->name == NULL && dirp != dirs)
+ return (EACCESS);
+ if (stat(filename, &stbuf) < 0)
+ return (errno == ENOENT ? ENOTFOUND : EACCESS);
+ if (!S_ISREG(stbuf.st_mode))
+ return (ENOTFOUND);
+ if (mode == RRQ) {
+ if ((stbuf.st_mode & S_IROTH) == 0)
+ return (EACCESS);
+ } else {
+ if ((stbuf.st_mode & S_IWOTH) == 0)
+ return (EACCESS);
+ }
+ } else {
+ /*
+ * Relative file name: search the approved locations for it.
+ */
+
+ if (!strncmp(filename, "../", 3))
+ return (EACCESS);
+
+ /*
+ * Find the first file that exists in any of the directories,
+ * check access on it.
+ */
+ if (dirs[0].name != NULL) {
+ for (dirp = dirs; dirp->name != NULL; dirp++) {
+ snprintf(pathname, sizeof pathname, "%s/%s",
+ dirp->name, filename);
+ if (stat(pathname, &stbuf) == 0 &&
+ (stbuf.st_mode & S_IFMT) == S_IFREG) {
+ break;
+ }
+ }
+ if (dirp->name == NULL)
+ return (ENOTFOUND);
+ if (mode == RRQ && !(stbuf.st_mode & S_IROTH))
+ return (EACCESS);
+ if (mode == WRQ && !(stbuf.st_mode & S_IWOTH))
+ return (EACCESS);
+ filename = pathname;
+ *filep = filename;
+ } else {
+ /*
+ * If there's no directory list, take our cue from the
+ * absolute file request check above (*filename == '/'),
+ * and allow access to anything.
+ */
+ if (stat(filename, &stbuf) < 0)
+ return (errno == ENOENT ? ENOTFOUND : EACCESS);
+ if (!S_ISREG(stbuf.st_mode))
+ return (ENOTFOUND);
+ if (mode == RRQ) {
+ if ((stbuf.st_mode & S_IROTH) == 0)
+ return (EACCESS);
+ } else {
+ if ((stbuf.st_mode & S_IWOTH) == 0)
+ return (EACCESS);
+ }
+ *filep = filename;
+ }
+ }
+
+ if (tftp_opt_tsize && mode == RRQ)
+ tftp_tsize = (unsigned long) stbuf.st_size;
+
+ fd = open(filename, mode == RRQ ? O_RDONLY : O_WRONLY | O_TRUNC);
+ if (fd < 0)
+ return (errno + 100);
+ file = fdopen(fd, (mode == RRQ)? "r":"w");
+ if (file == NULL) {
+ close(fd);
+ return (errno + 100);
+ }
+ return (0);
+}
+
+int timeout;
+jmp_buf timeoutbuf;
+
+void
+timer(int dummy)
+{
+
+ timeout += rexmtval;
+ if (timeout >= maxtimeout)
+ exit(1);
+ longjmp(timeoutbuf, 1);
+}
+
+static const char *
+opcode(int code)
+{
+ static char buf[64];
+
+ switch (code) {
+ case RRQ:
+ return "RRQ";
+ case WRQ:
+ return "WRQ";
+ case DATA:
+ return "DATA";
+ case ACK:
+ return "ACK";
+ case ERROR:
+ return "ERROR";
+ case OACK:
+ return "OACK";
+ default:
+ (void)snprintf(buf, sizeof(buf), "*code %d*", code);
+ return buf;
+ }
+}
+
+/*
+ * Send the requested file.
+ */
+void
+xmitfile(struct formats *pf, int etftp, int acklength)
+{
+ volatile unsigned int block;
+ struct tftphdr *dp;
+ struct tftphdr *ap; /* ack packet */
+ int size, n;
+ int first = 1;
+ long amount = 0;
+
+ signal(SIGALRM, timer);
+ ap = (struct tftphdr *)ackbuf;
+ if (etftp) {
+ dp = (struct tftphdr *)oackbuf;
+ size = acklength - 4;
+ block = 0;
+ } else {
+ dp = r_init();
+ size = 0;
+ block = 1;
+ }
+
+ do {
+ if (block > 0) {
+ size = readit(file, &dp, tftp_blksize, pf->f_convert);
+ if (size < 0) {
+ nak(errno + 100);
+ goto abort;
+ }
+ dp->th_opcode = htons((u_short)DATA);
+ dp->th_block = htons((u_short)block);
+ }
+ timeout = 0;
+ (void)setjmp(timeoutbuf);
+
+send_data:
+ if (!etftp && debug)
+ syslog(LOG_DEBUG, "Send DATA %u", block);
+ if ((n = send(peer, dp, size + 4, 0)) != size + 4) {
+ if (errno != ENOBUFS) {
+ syslog(LOG_ERR, "tftpd: write: %m");
+ goto abort;
+ }
+ }
+ amount += size;
+ if (block)
+ read_ahead(file, tftp_blksize, pf->f_convert);
+ for ( ; ; ) {
+ alarm(rexmtval); /* read the ack */
+ n = recv(peer, ackbuf, tftp_blksize, 0);
+ alarm(0);
+ if (n < 0) {
+ syslog(LOG_ERR, "tftpd: read: %m");
+ goto abort;
+ }
+ ap->th_opcode = ntohs((u_short)ap->th_opcode);
+ ap->th_block = ntohs((u_short)ap->th_block);
+ switch (ap->th_opcode) {
+ case ERROR:
+ goto abort;
+
+ case ACK:
+ if (ap->th_block == 0 && first && block == 0) {
+ first = 0;
+ etftp = 0;
+ acklength = 0;
+ dp = r_init();
+ goto done;
+ }
+ if (ap->th_block == (u_short)block)
+ goto done;
+ if (debug)
+ syslog(LOG_DEBUG, "Resync ACK %u != %u",
+ (unsigned int)ap->th_block, block);
+ /* Re-synchronize with the other side */
+ (void) synchnet(peer, tftp_blksize);
+ if (ap->th_block == (u_short)(block-1))
+ goto send_data;
+ default:
+ syslog(LOG_INFO, "Received %s in sendfile\n",
+ opcode(dp->th_opcode));
+ }
+
+ }
+done:
+ if (debug)
+ syslog(LOG_DEBUG, "Received ACK for block %u", block);
+ block++;
+ } while (size == tftp_blksize || block == 1);
+abort:
+ if (logging) {
+ syslog(LOG_DEBUG, "%s: request completed (%ld bytes)",
+ verifyhost((struct sockaddr *)&from), amount);
+ }
+ (void) fclose(file);
+}
+
+void
+justquit(int dummy)
+{
+
+ exit(0);
+}
+
+/*
+ * Receive a file.
+ */
+void
+recvfile(struct formats *pf, int etftp, int acklength)
+{
+ volatile unsigned int block;
+ struct tftphdr *dp;
+ struct tftphdr *ap; /* ack buffer */
+ int n, size;
+
+ signal(SIGALRM, timer);
+ dp = w_init();
+ ap = (struct tftphdr *)oackbuf;
+ block = 0;
+ do {
+ timeout = 0;
+ if (etftp == 0) {
+ ap = (struct tftphdr *)ackbuf;
+ ap->th_opcode = htons((u_short)ACK);
+ ap->th_block = htons((u_short)block);
+ acklength = 4;
+ }
+ if (debug)
+ syslog(LOG_DEBUG, "Sending ACK for block %u\n", block);
+ block++;
+ (void) setjmp(timeoutbuf);
+send_ack:
+ if (send(peer, ap, acklength, 0) != acklength) {
+ syslog(LOG_ERR, "tftpd: write: %m");
+ goto abort;
+ }
+ write_behind(file, pf->f_convert);
+ for ( ; ; ) {
+ alarm(rexmtval);
+ n = recv(peer, dp, tftp_blksize + 4, 0);
+ alarm(0);
+ if (n < 0) { /* really? */
+ syslog(LOG_ERR, "tftpd: read: %m");
+ goto abort;
+ }
+ etftp = 0;
+ dp->th_opcode = ntohs((u_short)dp->th_opcode);
+ dp->th_block = ntohs((u_short)dp->th_block);
+ if (debug)
+ syslog(LOG_DEBUG, "Received %s for block %u",
+ opcode(dp->th_opcode),
+ (unsigned int)dp->th_block);
+
+ switch (dp->th_opcode) {
+ case ERROR:
+ goto abort;
+ case DATA:
+ if (dp->th_block == (u_short)block)
+ goto done; /* normal */
+ if (debug)
+ syslog(LOG_DEBUG, "Resync %u != %u",
+ (unsigned int)dp->th_block, block);
+ /* Re-synchronize with the other side */
+ (void) synchnet(peer, tftp_blksize);
+ if (dp->th_block == (u_short)(block-1))
+ goto send_ack; /* rexmit */
+ break;
+ default:
+ syslog(LOG_INFO, "Received %s in recvfile\n",
+ opcode(dp->th_opcode));
+ break;
+ }
+ }
+done:
+ if (debug)
+ syslog(LOG_DEBUG, "Got block %u", block);
+ /* size = write(file, dp->th_data, n - 4); */
+ size = writeit(file, &dp, n - 4, pf->f_convert);
+ if (size != (n-4)) { /* ahem */
+ if (size < 0) nak(errno + 100);
+ else nak(ENOSPACE);
+ goto abort;
+ }
+ } while (size == tftp_blksize);
+ write_behind(file, pf->f_convert);
+ if (logging) {
+ syslog(LOG_DEBUG, "%s: request completed",
+ verifyhost((struct sockaddr *)&from));
+ }
+ (void) fclose(file); /* close data file */
+
+ ap->th_opcode = htons((u_short)ACK); /* send the "final" ack */
+ ap->th_block = htons((u_short)(block));
+ if (debug)
+ syslog(LOG_DEBUG, "Send final ACK %u", block);
+ (void) send(peer, ackbuf, 4, 0);
+
+ signal(SIGALRM, justquit); /* just quit on timeout */
+ alarm(rexmtval);
+ n = recv(peer, buf, sizeof (buf), 0); /* normally times out and quits */
+ alarm(0);
+ if (n >= 4 && /* if read some data */
+ dp->th_opcode == DATA && /* and got a data block */
+ block == dp->th_block) { /* then my last ack was lost */
+ (void) send(peer, ackbuf, 4, 0); /* resend final ack */
+ }
+abort:
+ return;
+}
+
+const struct errmsg {
+ int e_code;
+ const char *e_msg;
+} errmsgs[] = {
+ { EUNDEF, "Undefined error code" },
+ { ENOTFOUND, "File not found" },
+ { EACCESS, "Access violation" },
+ { ENOSPACE, "Disk full or allocation exceeded" },
+ { EBADOP, "Illegal TFTP operation" },
+ { EBADID, "Unknown transfer ID" },
+ { EEXISTS, "File already exists" },
+ { ENOUSER, "No such user" },
+ { EOPTNEG, "Option negotiation failed" },
+ { -1, 0 }
+};
+
+static const char *
+errtomsg(int error)
+{
+ static char ebuf[20];
+ const struct errmsg *pe;
+
+ if (error == 0)
+ return ("success");
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ return (pe->e_msg);
+ snprintf(ebuf, sizeof(ebuf), "error %d", error);
+ return (ebuf);
+}
+
+/*
+ * Send a nak packet (error message).
+ * Error code passed in is one of the
+ * standard TFTP codes, or a UNIX errno
+ * offset by 100.
+ */
+static void
+nak(int error)
+{
+ const struct errmsg *pe;
+ struct tftphdr *tp;
+ int length;
+ size_t msglen;
+
+ tp = (struct tftphdr *)buf;
+ tp->th_opcode = htons((u_short)ERROR);
+ msglen = sizeof(buf) - (&tp->th_msg[0] - buf);
+ for (pe = errmsgs; pe->e_code >= 0; pe++)
+ if (pe->e_code == error)
+ break;
+ if (pe->e_code < 0) {
+ tp->th_code = EUNDEF; /* set 'undef' errorcode */
+ strlcpy(tp->th_msg, strerror(error - 100), msglen);
+ } else {
+ tp->th_code = htons((u_short)error);
+ strlcpy(tp->th_msg, pe->e_msg, msglen);
+ }
+ if (debug)
+ syslog(LOG_DEBUG, "Send NACK %s", tp->th_msg);
+ length = strlen(tp->th_msg);
+ msglen = &tp->th_msg[length + 1] - buf;
+ if (send(peer, buf, msglen, 0) != msglen)
+ syslog(LOG_ERR, "nak: %m");
+}
+
+static char *
+verifyhost(struct sockaddr *fromp)
+{
+ static char hbuf[MAXHOSTNAMELEN];
+
+ if (getnameinfo(fromp, fromp->sa_len, hbuf, sizeof(hbuf), NULL, 0, 0))
+ if (getnameinfo(fromp, fromp->sa_len, hbuf, sizeof(hbuf),
+ NULL, 0, NI_NUMERICHOST))
+ strlcpy(hbuf, "?", sizeof(hbuf));
+ return (hbuf);
+}
+
+#ifndef __APPLE__
+/*
+ * Send an oack packet (option acknowledgement).
+ */
+static void
+oack(void)
+{
+ struct tftphdr *tp, *ap;
+ int size, i, n;
+ char *bp;
+
+ tp = (struct tftphdr *)buf;
+ bp = buf + 2;
+ size = sizeof(buf) - 2;
+ tp->th_opcode = htons((u_short)OACK);
+ for (i = 0; options[i].o_type != NULL; i++) {
+ if (options[i].o_request) {
+ n = snprintf(bp, size, "%s%c%d", options[i].o_type,
+ 0, options[i].o_reply);
+ bp += n+1;
+ size -= n+1;
+ if (size < 0) {
+ syslog(LOG_ERR, "oack: buffer overflow");
+ exit(1);
+ }
+ }
+ }
+ size = bp - buf;
+ ap = (struct tftphdr *)ackbuf;
+ signal(SIGALRM, timer);
+ timeouts = 0;
+
+ (void)setjmp(timeoutbuf);
+ if (send(peer, buf, size, 0) != size) {
+ syslog(LOG_INFO, "oack: %m");
+ exit(1);
+ }
+
+ for (;;) {
+ alarm(rexmtval);
+ n = recv(peer, ackbuf, sizeof (ackbuf), 0);
+ alarm(0);
+ if (n < 0) {
+ syslog(LOG_ERR, "recv: %m");
+ exit(1);
+ }
+ ap->th_opcode = ntohs((u_short)ap->th_opcode);
+ ap->th_block = ntohs((u_short)ap->th_block);
+ if (ap->th_opcode == ERROR)
+ exit(1);
+ if (ap->th_opcode == ACK && ap->th_block == 0)
+ break;
+ }
+}
+#endif /* !__APPLE__ */
diff --git a/remote_cmds/tftpd.tproj/tftpsubs.c b/remote_cmds/tftpd.tproj/tftpsubs.c
new file mode 100644
index 0000000..90f75bb
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftpsubs.c
@@ -0,0 +1,285 @@
+/* $NetBSD: tftpsubs.c,v 1.8 2003/08/07 11:16:14 agc Exp $ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93";
+#else
+__RCSID("$NetBSD: tftpsubs.c,v 1.8 2003/08/07 11:16:14 agc Exp $");
+#endif
+#endif /* not lint */
+
+/* Simple minded read-ahead/write-behind subroutines for tftp user and
+ server. Written originally with multiple buffers in mind, but current
+ implementation has two buffer logic wired in.
+
+ Todo: add some sort of final error check so when the write-buffer
+ is finally flushed, the caller can detect if the disk filled up
+ (or had an i/o error) and return a nak to the other side.
+
+ Jim Guyton 10/85
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/tftp.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "tftpsubs.h"
+
+struct bf {
+ int counter; /* size of data in buffer, or flag */
+ char buf[MAXPKTSIZE]; /* room for data packet */
+} bfs[2];
+
+ /* Values for bf.counter */
+#define BF_ALLOC -3 /* alloc'd but not yet filled */
+#define BF_FREE -2 /* free */
+/* [-1 .. SEGSIZE] = size of data in the data buffer */
+
+static int nextone; /* index of next buffer to use */
+static int current; /* index of buffer in use */
+
+ /* control flags for crlf conversions */
+int newline = 0; /* fillbuf: in middle of newline expansion */
+int prevchar = -1; /* putbuf: previous char (cr check) */
+
+static struct tftphdr *rw_init __P((int));
+
+struct tftphdr *
+w_init() /* write-behind */
+{
+ return rw_init(0);
+}
+
+struct tftphdr *
+r_init() /* read-ahead */
+{
+ return rw_init(1);
+}
+
+static struct tftphdr *
+rw_init(x) /* init for either read-ahead or write-behind */
+ int x; /* zero for write-behind, one for read-head */
+{
+ newline = 0; /* init crlf flag */
+ prevchar = -1;
+ bfs[0].counter = BF_ALLOC; /* pass out the first buffer */
+ current = 0;
+ bfs[1].counter = BF_FREE;
+ nextone = x; /* ahead or behind? */
+ return (struct tftphdr *)bfs[0].buf;
+}
+
+/* Have emptied current buffer by sending to net and getting ack.
+ Free it and return next buffer filled with data.
+ */
+int
+readit(file, dpp, amt, convert)
+ FILE *file; /* file opened for read */
+ struct tftphdr **dpp;
+ int amt;
+ int convert; /* if true, convert to ascii */
+{
+ struct bf *b;
+
+ bfs[current].counter = BF_FREE; /* free old one */
+ current = !current; /* "incr" current */
+
+ b = &bfs[current]; /* look at new buffer */
+ if (b->counter == BF_FREE) /* if it's empty */
+ read_ahead(file, amt, convert); /* fill it */
+/* assert(b->counter != BF_FREE);*//* check */
+ *dpp = (struct tftphdr *)b->buf; /* set caller's ptr */
+ return b->counter;
+}
+
+/*
+ * fill the input buffer, doing ascii conversions if requested
+ * conversions are lf -> cr,lf and cr -> cr, nul
+ */
+void
+read_ahead(file, amt, convert)
+ FILE *file; /* file opened for read */
+ int amt; /* number of bytes to read */
+ int convert; /* if true, convert to ascii */
+{
+ int i;
+ char *p;
+ int c;
+ struct bf *b;
+ struct tftphdr *dp;
+
+ b = &bfs[nextone]; /* look at "next" buffer */
+ if (b->counter != BF_FREE) /* nop if not free */
+ return;
+ nextone = !nextone; /* "incr" next buffer ptr */
+
+ dp = (struct tftphdr *)b->buf;
+
+ if (convert == 0) {
+ b->counter = read(fileno(file), dp->th_data, amt);
+ return;
+ }
+
+ p = dp->th_data;
+ for (i = 0 ; i < amt; i++) {
+ if (newline) {
+ if (prevchar == '\n')
+ c = '\n'; /* lf to cr,lf */
+ else c = '\0'; /* cr to cr,nul */
+ newline = 0;
+ }
+ else {
+ c = getc(file);
+ if (c == EOF) break;
+ if (c == '\n' || c == '\r') {
+ prevchar = c;
+ c = '\r';
+ newline = 1;
+ }
+ }
+ *p++ = c;
+ }
+ b->counter = (int)(p - dp->th_data);
+}
+
+/* Update count associated with the buffer, get new buffer
+ from the queue. Calls write_behind only if next buffer not
+ available.
+ */
+int
+writeit(file, dpp, ct, convert)
+ FILE *file;
+ struct tftphdr **dpp;
+ int ct, convert;
+{
+ bfs[current].counter = ct; /* set size of data to write */
+ current = !current; /* switch to other buffer */
+ if (bfs[current].counter != BF_FREE) /* if not free */
+ (void)write_behind(file, convert); /* flush it */
+ bfs[current].counter = BF_ALLOC; /* mark as alloc'd */
+ *dpp = (struct tftphdr *)bfs[current].buf;
+ return ct; /* this is a lie of course */
+}
+
+/*
+ * Output a buffer to a file, converting from netascii if requested.
+ * CR,NUL -> CR and CR,LF => LF.
+ * Note spec is undefined if we get CR as last byte of file or a
+ * CR followed by anything else. In this case we leave it alone.
+ */
+int
+write_behind(file, convert)
+ FILE *file;
+ int convert;
+{
+ char *buf;
+ int count;
+ int ct;
+ char *p;
+ int c; /* current character */
+ struct bf *b;
+ struct tftphdr *dp;
+
+ b = &bfs[nextone];
+ if (b->counter < -1) /* anything to flush? */
+ return 0; /* just nop if nothing to do */
+
+ count = b->counter; /* remember byte count */
+ b->counter = BF_FREE; /* reset flag */
+ dp = (struct tftphdr *)b->buf;
+ nextone = !nextone; /* incr for next time */
+ buf = dp->th_data;
+
+ if (count <= 0) return -1; /* nak logic? */
+
+ if (convert == 0)
+ return write(fileno(file), buf, count);
+
+ p = buf;
+ ct = count;
+ while (ct--) { /* loop over the buffer */
+ c = *p++; /* pick up a character */
+ if (prevchar == '\r') { /* if prev char was cr */
+ if (c == '\n') /* if have cr,lf then just */
+ fseek(file, -1, 1); /* smash lf on top of the cr */
+ else
+ if (c == '\0') /* if have cr,nul then */
+ goto skipit; /* just skip over the putc */
+ /* else just fall through and allow it */
+ }
+ putc(c, file);
+skipit:
+ prevchar = c;
+ }
+ return count;
+}
+
+
+/* When an error has occurred, it is possible that the two sides
+ * are out of synch. Ie: that what I think is the other side's
+ * response to packet N is really their response to packet N-1.
+ *
+ * So, to try to prevent that, we flush all the input queued up
+ * for us on the network connection on our host.
+ *
+ * We return the number of packets we flushed (mostly for reporting
+ * when trace is active).
+ */
+
+int
+synchnet(f, bsize)
+ int f; /* socket to flush */
+ int bsize; /* size of buffer to sync */
+{
+ int i, j = 0;
+ char rbuf[PKTSIZE];
+ struct sockaddr_storage from;
+ socklen_t fromlen;
+
+ while (1) {
+ (void) ioctl(f, FIONREAD, &i);
+ if (i) {
+ j++;
+ fromlen = sizeof from;
+ (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
+ (struct sockaddr *)&from, &fromlen);
+ } else {
+ return(j);
+ }
+ }
+}
diff --git a/remote_cmds/tftpd.tproj/tftpsubs.h b/remote_cmds/tftpd.tproj/tftpsubs.h
new file mode 100644
index 0000000..98284f8
--- /dev/null
+++ b/remote_cmds/tftpd.tproj/tftpsubs.h
@@ -0,0 +1,48 @@
+/* $NetBSD: tftpsubs.h,v 1.4 2003/08/07 11:16:14 agc Exp $ */
+
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)tftpsubs.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Prototypes for read-ahead/write-behind subroutines for tftp user and
+ * server.
+ */
+
+
+struct tftphdr *r_init __P((void));
+void read_ahead __P((FILE *, int, int));
+int readit __P((FILE *, struct tftphdr **, int, int));
+
+int synchnet __P((int, int));
+
+struct tftphdr *w_init __P((void));
+int write_behind __P((FILE *, int));
+int writeit __P((FILE *, struct tftphdr **, int, int));
diff --git a/remote_cmds/wall.tproj/Makefile b/remote_cmds/wall.tproj/Makefile
new file mode 100644
index 0000000..08da621
--- /dev/null
+++ b/remote_cmds/wall.tproj/Makefile
@@ -0,0 +1,16 @@
+Project = wall
+Install_Dir = /usr/bin
+
+HFILES = ttymsg.h
+CFILES = ttymsg.c wall.c
+MANPAGES = wall.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+Extra_CC_Flags += -D__FBSDID=__RCSID
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
+
+#Install_Program_Mode = 02555
+#Install_Program_Group = tty
diff --git a/remote_cmds/wall.tproj/ttymsg.c b/remote_cmds/wall.tproj/ttymsg.c
new file mode 100644
index 0000000..ce94f87
--- /dev/null
+++ b/remote_cmds/wall.tproj/ttymsg.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/wall/ttymsg.c,v 1.12 2006/01/27 08:52:14 ume Exp $");
+
+#ifndef lint
+__attribute__((__used__))
+static const char sccsid[] = "@(#)ttymsg.c 8.2 (Berkeley) 11/16/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "ttymsg.h"
+
+/*
+ * Display the contents of a uio structure on a terminal. Used by wall(1),
+ * syslogd(8), and talkd(8). Forks and finishes in child if write would block,
+ * waiting up to tmout seconds. Returns pointer to error string on unexpected
+ * error; string is not newline-terminated. Various "normal" errors are
+ * ignored (exclusive-use, lack of permission, etc.).
+ */
+const char *
+ttymsg(struct iovec *iov, int iovcnt, const char *line, int tmout)
+{
+ struct iovec localiov[7];
+ ssize_t left, wret;
+ int cnt, fd;
+ static char device[MAXNAMLEN] = _PATH_DEV;
+ static char errbuf[1024];
+ char *p;
+ int forked;
+
+ forked = 0;
+ if (iovcnt > (int)(sizeof(localiov) / sizeof(localiov[0])))
+ return ("too many iov's (change code in wall/ttymsg.c)");
+
+ p = device + sizeof(_PATH_DEV) - 1;
+#ifdef __APPLE__
+ /* radar:13145432 */
+ strlcpy(p, line, sizeof(device) - (sizeof(_PATH_DEV) - 1));
+#else
+ strlcpy(p, line, sizeof(device));
+#endif
+ if (strncmp(p, "pts/", 4) == 0)
+ p += 4;
+ if (strchr(p, '/') != NULL) {
+ /* A slash is an attempt to break security... */
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "Too many '/' in \"%s\"", device);
+ return (errbuf);
+ }
+
+ /*
+ * open will fail on slip lines or exclusive-use lines
+ * if not running as root; not an error.
+ */
+ if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
+#ifndef __APPLE__
+ if (errno == EBUSY || errno == EACCES)
+ return (NULL);
+#endif /* !__APPLE__ */
+ (void) snprintf(errbuf, sizeof(errbuf), "%s: %s", device,
+ strerror(errno));
+ return (errbuf);
+ }
+
+ for (cnt = 0, left = 0; cnt < iovcnt; ++cnt)
+ left += iov[cnt].iov_len;
+
+ for (;;) {
+ wret = writev(fd, iov, iovcnt);
+ if (wret >= left)
+ break;
+ if (wret >= 0) {
+ left -= wret;
+ if (iov != localiov) {
+ bcopy(iov, localiov,
+ iovcnt * sizeof(struct iovec));
+ iov = localiov;
+ }
+ for (cnt = 0; (size_t)wret >= iov->iov_len; ++cnt) {
+ wret -= iov->iov_len;
+ ++iov;
+ --iovcnt;
+ }
+ if (wret) {
+ iov->iov_base = (char *)iov->iov_base + wret;
+ iov->iov_len -= wret;
+ }
+ continue;
+ }
+ if (errno == EWOULDBLOCK) {
+ int cpid;
+
+ if (forked) {
+ (void) close(fd);
+ _exit(1);
+ }
+ cpid = fork();
+ if (cpid < 0) {
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "fork: %s", strerror(errno));
+ (void) close(fd);
+ return (errbuf);
+ }
+ if (cpid) { /* parent */
+ (void) close(fd);
+ return (NULL);
+ }
+ forked++;
+ /* wait at most tmout seconds */
+ (void) signal(SIGALRM, SIG_DFL);
+ (void) signal(SIGTERM, SIG_DFL); /* XXX */
+ (void) sigsetmask(0);
+ (void) alarm((u_int)tmout);
+ (void) fcntl(fd, F_SETFL, 0); /* clear O_NONBLOCK */
+ continue;
+ }
+ /*
+ * We get ENODEV on a slip line if we're running as root,
+ * and EIO if the line just went away.
+ */
+ if (errno == ENODEV || errno == EIO)
+ break;
+ (void) close(fd);
+ if (forked)
+ _exit(1);
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "%s: %s", device, strerror(errno));
+ return (errbuf);
+ }
+
+ (void) close(fd);
+ if (forked)
+ _exit(0);
+ return (NULL);
+}
diff --git a/remote_cmds/wall.tproj/ttymsg.h b/remote_cmds/wall.tproj/ttymsg.h
new file mode 100644
index 0000000..625c22d
--- /dev/null
+++ b/remote_cmds/wall.tproj/ttymsg.h
@@ -0,0 +1,3 @@
+/* $FreeBSD: src/usr.bin/wall/ttymsg.h,v 1.1 2001/09/09 14:23:31 dd Exp $ */
+
+const char *ttymsg(struct iovec *, int, const char *, int);
diff --git a/remote_cmds/wall.tproj/wall.1 b/remote_cmds/wall.tproj/wall.1
new file mode 100644
index 0000000..7c92e63
--- /dev/null
+++ b/remote_cmds/wall.tproj/wall.1
@@ -0,0 +1,83 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)wall.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/wall/wall.1,v 1.11 2004/07/17 04:15:27 tjr Exp $
+.\"
+.Dd July 17, 2004
+.Dt WALL 1
+.Os
+.Sh NAME
+.Nm wall
+.Nd write a message to users
+.Sh SYNOPSIS
+.Nm
+.Op Fl g Ar group
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the contents of
+.Ar file
+or, by default, its standard input, on the terminals of all
+currently logged in users.
+.Pp
+Only the super-user can write on the
+terminals of users who have chosen
+to deny messages or are using a program which
+automatically denies messages.
+.Bl -tag -width indent
+.It Fl g
+Send messages to users in this group.
+This option may be specified
+multiple times, and any user in any of the specified groups will
+receive the message.
+.El
+.Sh SEE ALSO
+.Xr mesg 1 ,
+.Xr talk 1 ,
+.Xr write 1 ,
+.Xr shutdown 8
+.Sh HISTORY
+A
+.Nm
+command appeared in PWB UNIX.
+.Sh BUGS
+The sender's
+.Ev LC_CTYPE
+setting is used to determine which characters are safe to write to a
+terminal, not the receiver's (which
+.Nm
+has no way of knowing).
+.Pp
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/remote_cmds/wall.tproj/wall.c b/remote_cmds/wall.tproj/wall.c
new file mode 100644
index 0000000..b856f7b
--- /dev/null
+++ b/remote_cmds/wall.tproj/wall.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/wall/wall.c,v 1.25 2008/01/15 07:40:30 das Exp $");
+
+#ifndef lint
+__attribute__((__used__))
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+__attribute__((__used__))
+static const char sccsid[] = "@(#)wall.c 8.2 (Berkeley) 11/16/93";
+#endif
+
+/*
+ * This program is not related to David Wall, whose Stanford Ph.D. thesis
+ * is entitled "Mechanisms for Broadcast and Selective Broadcast".
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <grp.h>
+#include <locale.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <utmpx.h>
+#else
+#include <utmp.h>
+#endif
+
+#include "ttymsg.h"
+
+static void makemsg(char *);
+static void usage(void);
+
+struct wallgroup {
+ struct wallgroup *next;
+ char *name;
+ gid_t gid;
+} *grouplist;
+int nobanner;
+int mbufsize;
+char *mbuf;
+
+#ifndef __APPLE__
+static int
+ttystat(char *line, int sz)
+{
+ struct stat sb;
+ char ttybuf[MAXPATHLEN];
+
+ (void)snprintf(ttybuf, sizeof(ttybuf), "%s%.*s", _PATH_DEV, sz, line);
+ if (stat(ttybuf, &sb) == 0) {
+ return (0);
+ } else
+ return (-1);
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct iovec iov;
+#ifdef __APPLE__
+ // rdar://problem/4433603
+ struct utmpx *u;
+#else
+ struct utmp utmp;
+#endif
+ int ch;
+ int ingroup;
+#ifndef __APPLE__
+ FILE *fp;
+#endif
+ struct wallgroup *g;
+ struct group *grp;
+ char **np;
+ const char *p;
+ struct passwd *pw;
+#ifdef __APPLE__
+ char line[sizeof(u->ut_line) + 1];
+ char username[sizeof(u->ut_user) + 1];
+#else
+ char line[sizeof(utmp.ut_line) + 1];
+ char username[sizeof(utmp.ut_name) + 1];
+#endif
+
+ (void)setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc, argv, "g:n")) != -1)
+ switch (ch) {
+ case 'n':
+ /* undoc option for shutdown: suppress banner */
+ if (geteuid() == 0)
+ nobanner = 1;
+ break;
+ case 'g':
+ g = (struct wallgroup *)malloc(sizeof *g);
+ g->next = grouplist;
+ g->name = optarg;
+ g->gid = -1;
+ grouplist = g;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc > 1)
+ usage();
+
+ for (g = grouplist; g; g = g->next) {
+ grp = getgrnam(g->name);
+ if (grp != NULL)
+ g->gid = grp->gr_gid;
+ else
+ warnx("%s: no such group", g->name);
+ }
+
+ makemsg(*argv);
+
+#ifdef __APPLE__
+ setutxent();
+#else
+ if (!(fp = fopen(_PATH_UTMP, "r")))
+ err(1, "cannot read %s", _PATH_UTMP);
+#endif
+ iov.iov_base = mbuf;
+ iov.iov_len = mbufsize;
+ /* NOSTRICT */
+#ifdef __APPLE__
+ while ((u = getutxent()) != NULL) {
+ if (!u->ut_user[0] || u->ut_type != USER_PROCESS)
+ continue;
+#else
+ while (fread((char *)&utmp, sizeof(utmp), 1, fp) == 1) {
+ if (!utmp.ut_name[0])
+ continue;
+ if (ttystat(utmp.ut_line, UT_LINESIZE) != 0)
+ continue;
+#endif
+ if (grouplist) {
+ ingroup = 0;
+#ifdef __APPLE__
+ strlcpy(username, u->ut_user, sizeof(username));
+#else
+ strlcpy(username, utmp.ut_name, sizeof(utmp.ut_name));
+#endif
+ pw = getpwnam(username);
+ if (!pw)
+ continue;
+ for (g = grouplist; g && ingroup == 0; g = g->next) {
+ if (g->gid == (gid_t)-1)
+ continue;
+ if (g->gid == pw->pw_gid)
+ ingroup = 1;
+ else if ((grp = getgrgid(g->gid)) != NULL) {
+ for (np = grp->gr_mem; *np; np++) {
+ if (strcmp(*np, username) == 0) {
+ ingroup = 1;
+ break;
+ }
+ }
+ }
+ }
+ if (ingroup == 0)
+ continue;
+ }
+#ifdef __APPLE__
+ strlcpy(line, u->ut_line, sizeof(line));
+#else
+ strncpy(line, utmp.ut_line, sizeof(utmp.ut_line));
+ line[sizeof(utmp.ut_line)] = '\0';
+#endif
+ if ((p = ttymsg(&iov, 1, line, 60*5)) != NULL)
+ warnx("%s", p);
+ }
+ exit(0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: wall [-g group] [file]\n");
+ exit(1);
+}
+
+void
+makemsg(char *fname)
+{
+ int cnt;
+ unsigned char ch;
+ struct tm *lt;
+ struct passwd *pw;
+ struct stat sbuf;
+ time_t now;
+ FILE *fp;
+ int fd;
+ char *p, hostname[MAXHOSTNAMELEN], lbuf[256], tmpname[64];
+ const char *tty;
+ const char *whom;
+ gid_t egid;
+
+ (void)snprintf(tmpname, sizeof(tmpname), "%s/wall.XXXXXX", _PATH_TMP);
+ if ((fd = mkstemp(tmpname)) == -1 || !(fp = fdopen(fd, "r+")))
+ err(1, "can't open temporary file");
+ (void)unlink(tmpname);
+
+ if (!nobanner) {
+ tty = ttyname(STDERR_FILENO);
+ if (tty == NULL)
+ tty = "no tty";
+
+ if (!(whom = getlogin()))
+ whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
+ (void)gethostname(hostname, sizeof(hostname));
+ (void)time(&now);
+ lt = localtime(&now);
+
+ /*
+ * all this stuff is to blank out a square for the message;
+ * we wrap message lines at column 79, not 80, because some
+ * terminals wrap after 79, some do not, and we can't tell.
+ * Which means that we may leave a non-blank character
+ * in column 80, but that can't be helped.
+ */
+ (void)fprintf(fp, "\r%79s\r\n", " ");
+ (void)snprintf(lbuf, sizeof(lbuf),
+ "Broadcast Message from %s@%s",
+ whom, hostname);
+ (void)fprintf(fp, "%-79.79s\007\007\r\n", lbuf);
+ (void)snprintf(lbuf, sizeof(lbuf),
+ " (%s) at %d:%02d %s...", tty,
+ lt->tm_hour, lt->tm_min, lt->tm_zone);
+ (void)fprintf(fp, "%-79.79s\r\n", lbuf);
+ }
+ (void)fprintf(fp, "%79s\r\n", " ");
+
+ if (fname) {
+ egid = getegid();
+ setegid(getgid());
+ if (freopen(fname, "r", stdin) == NULL)
+ err(1, "can't read %s", fname);
+ setegid(egid);
+ }
+ while (fgets(lbuf, sizeof(lbuf), stdin)) {
+ for (cnt = 0, p = lbuf; (ch = *p) != '\0'; ++p, ++cnt) {
+ if (ch == '\r') {
+ putc('\r', fp);
+ cnt = 0;
+ continue;
+ } else if (ch == '\n') {
+ for (; cnt < 79; ++cnt)
+ putc(' ', fp);
+ putc('\r', fp);
+ putc('\n', fp);
+ break;
+ }
+ if (cnt == 79) {
+ putc('\r', fp);
+ putc('\n', fp);
+ cnt = 0;
+ }
+#ifdef __APPLE__
+ else // rdar://problem/3066405
+#endif
+ if (((ch & 0x80) && ch < 0xA0) ||
+ /* disable upper controls */
+ (!isprint(ch) && !isspace(ch) &&
+ ch != '\a' && ch != '\b')
+ ) {
+ if (ch & 0x80) {
+ ch &= 0x7F;
+ putc('M', fp);
+ if (++cnt == 79) {
+ putc('\r', fp);
+ putc('\n', fp);
+ cnt = 0;
+ }
+ putc('-', fp);
+ if (++cnt == 79) {
+ putc('\r', fp);
+ putc('\n', fp);
+ cnt = 0;
+ }
+ }
+ if (iscntrl(ch)) {
+ ch ^= 040;
+ putc('^', fp);
+ if (++cnt == 79) {
+ putc('\r', fp);
+ putc('\n', fp);
+ cnt = 0;
+ }
+ }
+ }
+#ifdef __APPLE__
+ // rdar://problem/4557295
+ if (ch != '\n')
+#endif
+ putc(ch, fp);
+ }
+ }
+ (void)fprintf(fp, "%79s\r\n", " ");
+ rewind(fp);
+
+ if (fstat(fd, &sbuf))
+ err(1, "can't stat temporary file");
+ mbufsize = sbuf.st_size;
+ if (!(mbuf = malloc((u_int)mbufsize)))
+ err(1, "out of memory");
+ if ((int)fread(mbuf, sizeof(*mbuf), mbufsize, fp) != mbufsize)
+ err(1, "can't read temporary file");
+ (void)close(fd);
+}
diff --git a/shell_cmds/.upstream_base_commits b/shell_cmds/.upstream_base_commits
new file mode 100644
index 0000000..23f2adb
--- /dev/null
+++ b/shell_cmds/.upstream_base_commits
@@ -0,0 +1,4 @@
+xargs/pathname.h freebsd usr.bin/xargs/pathname.h 872b698bd4a1bfc0bf008c09228e6fd238809c75
+xargs/strnsubst.c freebsd usr.bin/xargs/strnsubst.c 56640efcbe39386a0152f14fb18a314b85e7e014
+xargs/xargs.1 freebsd usr.bin/xargs/xargs.1 7e6cabd06e6caa6a02eeb86308dc0cb3f27e10da
+xargs/xargs.c freebsd usr.bin/xargs/xargs.c 872b698bd4a1bfc0bf008c09228e6fd238809c75
diff --git a/shell_cmds/alias/alias.1 b/shell_cmds/alias/alias.1
new file mode 100644
index 0000000..5a811f4
--- /dev/null
+++ b/shell_cmds/alias/alias.1
@@ -0,0 +1 @@
+.so man1/builtin.1
diff --git a/shell_cmds/alias/builtin.1 b/shell_cmds/alias/builtin.1
new file mode 100644
index 0000000..0fae99a
--- /dev/null
+++ b/shell_cmds/alias/builtin.1
@@ -0,0 +1,333 @@
+.\"
+.\" Copyright (c) 1999 Sheldon Hearn
+.\"
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: /repoman/r/ncvs/src/share/man/man1/builtin.1,v 1.25 2005/09/09 17:02:08 garys Exp $
+.\"
+.Dd February 23, 2005
+.Dt BUILTIN 1
+.Os
+.Sh NAME
+.Nm builtin ,
+.Nm \&! ,
+.Nm \&% ,
+.Nm \&. ,
+.Nm \&: ,
+.Nm \&@ ,
+.Nm \&{ ,
+.Nm \&} ,
+.Nm alias ,
+.Nm alloc ,
+.Nm bg ,
+.Nm bind ,
+.Nm bindkey ,
+.Nm break ,
+.Nm breaksw ,
+.Nm builtins ,
+.Nm case ,
+.Nm cd ,
+.Nm chdir ,
+.Nm command ,
+.Nm complete ,
+.Nm continue ,
+.Nm default ,
+.Nm dirs ,
+.Nm do ,
+.Nm done ,
+.Nm echo ,
+.Nm echotc ,
+.Nm elif ,
+.Nm else ,
+.Nm end ,
+.Nm endif ,
+.Nm endsw ,
+.Nm esac ,
+.Nm eval ,
+.Nm exec ,
+.Nm exit ,
+.Nm export ,
+.Nm false ,
+.Nm fc ,
+.Nm fg ,
+.Nm filetest ,
+.Nm fi ,
+.Nm for ,
+.Nm foreach ,
+.Nm getopts ,
+.Nm glob ,
+.Nm goto ,
+.Nm hash ,
+.Nm hashstat ,
+.Nm history ,
+.Nm hup ,
+.Nm if ,
+.Nm jobid ,
+.Nm jobs ,
+.Nm kill ,
+.Nm limit ,
+.Nm local ,
+.Nm log ,
+.Nm login ,
+.Nm logout ,
+.Nm ls-F ,
+.Nm nice ,
+.Nm nohup ,
+.Nm notify ,
+.Nm onintr ,
+.Nm popd ,
+.Nm printenv ,
+.Nm pushd ,
+.Nm pwd ,
+.Nm read ,
+.Nm readonly ,
+.Nm rehash ,
+.Nm repeat ,
+.Nm return ,
+.Nm sched ,
+.Nm set ,
+.Nm setenv ,
+.Nm settc ,
+.Nm setty ,
+.Nm setvar ,
+.Nm shift ,
+.Nm source ,
+.Nm stop ,
+.Nm suspend ,
+.Nm switch ,
+.Nm telltc ,
+.Nm test ,
+.Nm then ,
+.Nm time ,
+.Nm times ,
+.Nm trap ,
+.Nm true ,
+.Nm type ,
+.Nm ulimit ,
+.Nm umask ,
+.Nm unalias ,
+.Nm uncomplete ,
+.Nm unhash ,
+.Nm unlimit ,
+.Nm unset ,
+.Nm unsetenv ,
+.Nm until ,
+.Nm wait ,
+.Nm where ,
+.Nm which ,
+.Nm while
+.Nd shell built-in commands
+.Sh SYNOPSIS
+.Nm
+.Op Fl options
+.Op Ar args ...
+.Sh DESCRIPTION
+Shell builtin commands are commands that can be executed within the
+running shell's process.
+Note that, in the case of
+.Xr csh 1
+builtin commands, the command is executed in a subshell if it occurs as
+any component of a pipeline except the last.
+.Pp
+If a command specified to the shell contains a slash
+.Dq \&/ ,
+the shell will not execute a builtin command, even if the last component
+of the specified command matches the name of a builtin command.
+Thus, while specifying
+.Dq Ic echo
+causes a builtin command to be executed under shells that support the
+.Nm echo
+builtin command,
+specifying
+.Dq Ic /bin/echo
+or
+.Dq Ic ./echo
+does not.
+.Pp
+While some builtin commands may exist in more than one shell, their
+operation may be different under each shell which supports them.
+Below is a table which lists shell builtin commands, the standard shells
+that support them and whether they exist as standalone utilities.
+.Pp
+Only builtin commands for the
+.Xr csh 1
+and
+.Xr sh 1
+shells are listed here.
+Consult a shell's manual page for
+details on the operation of its builtin commands.
+Beware that the
+.Xr sh 1
+manual page, at least, calls some of these commands
+.Dq built-in commands
+and some of them
+.Dq reserved words .
+Users of other shells may need to consult an
+.Xr info 1
+page or other sources of documentation.
+.Pp
+Commands marked
+.Dq Li No**
+under
+.Em External
+do exist externally,
+but are implemented as scripts using a builtin command of the same name.
+.Bl -column ".Ic uncomplete" ".Em External" ".Xr csh 1" ".Xr sh 1" -offset indent
+.It Xo
+.Em "Command External" Ta Xr csh 1 Ta Xr sh 1
+.Xc
+.It Ic ! Ta \&No Ta \&No Ta \&Yes
+.It Ic % Ta \&No Ta Yes Ta \&No
+.It Ic . Ta \&No Ta \&No Ta Yes
+.It Ic : Ta \&No Ta Yes Ta Yes
+.It Ic @ Ta \&No Ta Yes Ta Yes
+.It Ic { Ta \&No Ta \&No Ta \&Yes
+.It Ic } Ta \&No Ta \&No Ta \&Yes
+.It Ic alias Ta \&No** Ta Yes Ta Yes
+.It Ic alloc Ta \&No Ta Yes Ta \&No
+.It Ic bg Ta No** Ta Yes Ta Yes
+.It Ic bind Ta \&No Ta \&No Ta Yes
+.It Ic bindkey Ta \&No Ta Yes Ta \&No
+.It Ic break Ta \&No Ta Yes Ta \&Yes
+.It Ic breaksw Ta \&No Ta Yes Ta \&No
+.It Ic builtin Ta \&No Ta \&No Ta Yes
+.It Ic builtins Ta \&No Ta Yes Ta \&No
+.It Ic case Ta \&No Ta Yes Ta Yes
+.It Ic cd Ta \&No** Ta Yes Ta Yes
+.It Ic chdir Ta \&No Ta Yes Ta \&Yes
+.It Ic command Ta \&No** Ta \&No Ta Yes
+.It Ic complete Ta \&No Ta Yes Ta \&No
+.It Ic continue Ta \&No Ta Yes Ta \&Yes
+.It Ic default Ta \&No Ta Yes Ta \&No
+.It Ic dirs Ta \&No Ta Yes Ta \&No
+.It Ic do Ta \&No Ta \&No Ta Yes
+.It Ic done Ta \&No Ta \&No Ta Yes
+.It Ic echo Ta Yes Ta Yes Ta Yes
+.It Ic echotc Ta \&No Ta Yes Ta \&No
+.It Ic elif Ta \&No Ta \&No Ta Yes
+.It Ic else Ta \&No Ta Yes Ta \&Yes
+.It Ic end Ta \&No Ta Yes Ta \&No
+.It Ic endif Ta \&No Ta Yes Ta \&No
+.It Ic endsw Ta \&No Ta Yes Ta \&No
+.It Ic esac Ta \&No Ta \&No Ta Yes
+.It Ic eval Ta \&No Ta Yes Ta Yes
+.It Ic exec Ta \&No Ta Yes Ta Yes
+.It Ic exit Ta \&No Ta Yes Ta Yes
+.It Ic export Ta \&No Ta \&No Ta Yes
+.It Ic false Ta Yes Ta \&No Ta Yes
+.It Ic fc Ta \&No** Ta \&No Ta Yes
+.It Ic fg Ta \&No** Ta Yes Ta Yes
+.It Ic filetest Ta \&No Ta Yes Ta \&No
+.It Ic fi Ta \&No Ta \&No Ta Yes
+.It Ic for Ta \&No Ta \&No Ta Yes
+.It Ic foreach Ta \&No Ta Yes Ta \&No
+.It Ic getopts Ta \&No** Ta \&No Ta Yes
+.It Ic glob Ta \&No Ta Yes Ta \&No
+.It Ic goto Ta \&No Ta Yes Ta \&No
+.It Ic hash Ta \&No Ta \&No Ta Yes
+.It Ic hashstat Ta \&No Ta Yes Ta \&No
+.It Ic history Ta \&No Ta Yes Ta \&No
+.It Ic hup Ta \&No Ta Yes Ta \&No
+.It Ic if Ta \&No Ta Yes Ta \&Yes
+.It Ic jobid Ta \&No Ta \&No Ta Yes
+.It Ic jobs Ta \&No** Ta Yes Ta Yes
+.It Ic kill Ta Yes Ta Yes Ta \&No
+.It Ic limit Ta \&No Ta Yes Ta \&No
+.It Ic local Ta \&No Ta \&No Ta Yes
+.It Ic log Ta \&No Ta Yes Ta \&No
+.It Ic login Ta Yes Ta Yes Ta \&No
+.It Ic logout Ta \&No Ta Yes Ta \&No
+.It Ic ls-F Ta \&No Ta Yes Ta \&No
+.It Ic nice Ta Yes Ta Yes Ta \&No
+.It Ic nohup Ta Yes Ta Yes Ta \&No
+.It Ic notify Ta \&No Ta Yes Ta \&No
+.It Ic onintr Ta \&No Ta Yes Ta \&No
+.It Ic popd Ta \&No Ta Yes Ta \&No
+.It Ic printenv Ta Yes Ta Yes Ta \&No
+.It Ic pushd Ta \&No Ta Yes Ta \&No
+.It Ic pwd Ta Yes Ta \&No Ta Yes
+.It Ic read Ta \&No** Ta \&No Ta Yes
+.It Ic readonly Ta \&No Ta \&No Ta Yes
+.It Ic rehash Ta \&No Ta Yes Ta \&No
+.It Ic repeat Ta \&No Ta Yes Ta \&No
+.It Ic return Ta \&No Ta \&No Ta Yes
+.It Ic sched Ta \&No Ta Yes Ta \&No
+.It Ic set Ta \&No Ta Yes Ta \&Yes
+.It Ic setenv Ta \&No Ta Yes Ta \&No
+.It Ic settc Ta \&No Ta Yes Ta \&No
+.It Ic setty Ta \&No Ta Yes Ta \&No
+.It Ic setvar Ta \&No Ta \&No Ta Yes
+.It Ic shift Ta \&No Ta Yes Ta Yes
+.It Ic source Ta \&No Ta Yes Ta \&No
+.It Ic stop Ta \&No Ta Yes Ta \&No
+.It Ic suspend Ta \&No Ta Yes Ta \&No
+.It Ic switch Ta \&No Ta Yes Ta \&No
+.It Ic telltc Ta \&No Ta Yes Ta \&No
+.It Ic test Ta Yes Ta \&No Ta Yes
+.It Ic then Ta \&No Ta \&No Ta Yes
+.It Ic time Ta Yes Ta Yes Ta \&No
+.It Ic times Ta \&No Ta \&No Ta Yes
+.It Ic trap Ta \&No Ta \&No Ta Yes
+.It Ic true Ta Yes Ta \&No Ta Yes
+.It Ic type Ta \&No Ta \&No Ta Yes
+.It Ic ulimit Ta \&No Ta \&No Ta Yes
+.It Ic umask Ta \&No** Ta Yes Ta Yes
+.It Ic unalias Ta \&No** Ta Yes Ta Yes
+.It Ic uncomplete Ta \&No Ta Yes Ta \&No
+.It Ic unhash Ta \&No Ta Yes Ta \&No
+.It Ic unlimit Ta \&No Ta Yes Ta \&No
+.It Ic unset Ta \&No Ta Yes Ta Yes
+.It Ic unsetenv Ta \&No Ta Yes Ta \&No
+.It Ic until Ta \&No Ta \&No Ta Yes
+.It Ic wait Ta \&No** Ta Yes Ta Yes
+.It Ic where Ta \&No Ta Yes Ta \&No
+.It Ic which Ta Yes Ta Yes Ta \&No
+.It Ic while Ta \&No Ta Yes Ta \&Yes
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr dash 1 ,
+.Xr echo 1 ,
+.Xr false 1 ,
+.Xr info 1 ,
+.Xr kill 1 ,
+.Xr login 1 ,
+.Xr nice 1 ,
+.Xr nohup 1 ,
+.Xr printenv 1 ,
+.Xr pwd 1 ,
+.Xr sh 1 ,
+.Xr test 1 ,
+.Xr time 1 ,
+.Xr true 1 ,
+.Xr which 1 ,
+.Xr zsh 1
+.Sh HISTORY
+The
+.Nm
+manual page first appeared in
+.Fx 3.4 .
+.Sh AUTHORS
+This manual page was written by
+.An Sheldon Hearn Aq sheldonh@FreeBSD.org .
diff --git a/shell_cmds/alias/generic.sh b/shell_cmds/alias/generic.sh
new file mode 100644
index 0000000..5948cc9
--- /dev/null
+++ b/shell_cmds/alias/generic.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+# $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
+# This file is in the public domain.
+builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"}
diff --git a/shell_cmds/apply/apply.1 b/shell_cmds/apply/apply.1
new file mode 100644
index 0000000..2eb1516
--- /dev/null
+++ b/shell_cmds/apply/apply.1
@@ -0,0 +1,140 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)apply.1 8.2 (Berkeley) 4/4/94
+.\" $FreeBSD: src/usr.bin/apply/apply.1,v 1.14 2002/04/19 23:16:06 charnier Exp $
+.\"
+.Dd April 4, 1994
+.Dt APPLY 1
+.Os
+.Sh NAME
+.Nm apply
+.Nd apply a command to a set of arguments
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar c
+.Op Fl d
+.Op Fl #
+.Ar command argument ...
+.Sh DESCRIPTION
+The
+.Nm
+utility runs the named
+.Ar command
+on each
+argument
+.Ar argument
+in turn.
+.Pp
+Character sequences of the form
+.Dq Li \&%d
+in
+.Ar command ,
+where
+.Sq Li d
+is a digit from 1 to 9, are replaced by the
+.Li d Ns \'th
+following unused
+.Ar argument .
+In this case, the largest digit number of arguments are discarded for
+each execution of
+.Ar command .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl #
+Normally arguments are taken singly; the optional number
+.Fl #
+specifies the number of arguments to be passed to
+.Ar command .
+If the number is zero,
+.Ar command
+is run, without arguments, once for each
+.Ar argument .
+.Pp
+If any sequences of
+.Dq Li \&%d
+occur in
+.Ar command ,
+the
+.Fl #
+option is ignored.
+.It Fl a Ar c
+The use of the character
+.Sq Li %
+as a magic character may be changed with the
+.Fl a
+option.
+.It Fl d
+Display the commands that would have been executed, but do not actually
+execute them.
+.El
+.Sh ENVIRONMENT
+The following environment variable affects the execution of
+.Nm :
+.Bl -tag -width SHELL
+.It Ev SHELL
+Pathname of shell to use.
+If this variable is not defined, the Bourne shell is used.
+.El
+.Sh EXAMPLES
+.Bl -tag -width apply -compact
+.It Li "apply echo a*"
+is similar to
+.Xr ls 1 ;
+.It Li "apply \-2 cmp a1 b1 a2 b2 a3 b3"
+compares the `a' files to the `b' files;
+.It Li "apply \-0 who 1 2 3 4 5"
+runs
+.Xr who 1
+5 times; and
+.It Li "apply \'ln %1 /usr/joe\'" *
+links all files in the current directory to the directory
+.Pa /usr/joe .
+.El
+.Sh FILES
+.Bl -tag -width /bin/sh -compact
+.It Pa /bin/sh
+default shell
+.El
+.Sh AUTHORS
+.An Rob Pike
+.Sh BUGS
+Shell metacharacters in
+.Ar command
+may have bizarre effects; it is best to enclose complicated
+commands in single quotes
+.Pq '' .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/shell_cmds/apply/apply.c b/shell_cmds/apply/apply.c
new file mode 100644
index 0000000..cf4e9c1
--- /dev/null
+++ b/shell_cmds/apply/apply.c
@@ -0,0 +1,267 @@
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)apply.c 8.4 (Berkeley) 4/4/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/apply/apply.c,v 1.22 2002/07/14 18:22:12 alfred Exp $");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define EXEC "exec "
+
+static int exec_shell(const char *, char *, char *);
+static void usage(void);
+
+int
+main(int argc, char *argv[]) {
+ int ch, debug, i, magic, n, nargs, offset, rval;
+ size_t clen, cmdsize, l;
+ char *c, *cmd, *name, *p, *q, *shell, *slashp, *tmpshell;
+
+ debug = 0;
+ magic = '%'; /* Default magic char is `%'. */
+ nargs = -1;
+ while ((ch = getopt(argc, argv, "a:d0123456789")) != -1)
+ switch (ch) {
+ case 'a':
+ if (optarg[1] != '\0')
+ errx(1,
+ "illegal magic character specification");
+ magic = optarg[0];
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (nargs != -1)
+ errx(1,
+ "only one -# argument may be specified");
+ nargs = optopt - '0';
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 2)
+ usage();
+
+ /*
+ * The command to run is argv[0], and the args are argv[1..].
+ * Look for %digit references in the command, remembering the
+ * largest one.
+ */
+ for (n = 0, p = argv[0]; *p != '\0'; ++p)
+ if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
+ ++p;
+ if (p[0] - '0' > n)
+ n = p[0] - '0';
+ }
+
+ /*
+ * Figure out the shell and name arguments to pass to execl()
+ * in exec_shell(). Always malloc() shell and just set name
+ * to point at the last part of shell if there are any backslashes,
+ * otherwise just set it to point at the space malloc()'d. If
+ * SHELL environment variable exists, replace contents of
+ * shell with it.
+ */
+ shell = name = NULL;
+ tmpshell = getenv("SHELL");
+ shell = (tmpshell != NULL) ? strdup(tmpshell) : strdup(_PATH_BSHELL);
+ if (shell == NULL)
+ err(1, "strdup() failed");
+ slashp = strrchr(shell, '/');
+ name = (slashp != NULL) ? slashp + 1 : shell;
+
+ /*
+ * If there were any %digit references, then use those, otherwise
+ * build a new command string with sufficient %digit references at
+ * the end to consume (nargs) arguments each time round the loop.
+ * Allocate enough space to hold the maximum command. Save the
+ * size to pass to snprintf().
+ */
+ cmdsize = sizeof(EXEC) - 1 + strlen(argv[0])
+ + 9 * (sizeof(" %1") - 1) + 1;
+ if ((cmd = malloc(cmdsize)) == NULL)
+ err(1, NULL);
+
+ if (n == 0) {
+ /* If nargs not set, default to a single argument. */
+ if (nargs == -1)
+ nargs = 1;
+
+ p = cmd;
+ offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]);
+ if ((size_t)offset >= cmdsize)
+ err(1, "snprintf() failed");
+ p += offset;
+ cmdsize -= offset;
+ for (i = 1; i <= nargs; i++) {
+ offset = snprintf(p, cmdsize, " %c%d", magic, i);
+ if ((size_t)offset >= cmdsize)
+ err(1, "snprintf() failed");
+ p += offset;
+ cmdsize -= offset;
+ }
+
+ /*
+ * If nargs set to the special value 0, eat a single
+ * argument for each command execution.
+ */
+ if (nargs == 0)
+ nargs = 1;
+ } else {
+ offset = snprintf(cmd, cmdsize, EXEC "%s", argv[0]);
+ if ((size_t)offset >= cmdsize)
+ err(1, "snprintf() failed");
+ nargs = n;
+ }
+
+ /*
+ * Grab some space in which to build the command. Allocate
+ * as necessary later, but no reason to build it up slowly
+ * for the normal case.
+ */
+ if ((c = malloc(clen = 1024)) == NULL)
+ err(1, NULL);
+
+ /*
+ * (argc) and (argv) are still offset by one to make it simpler to
+ * expand %digit references. At the end of the loop check for (argc)
+ * equals 1 means that all the (argv) has been consumed.
+ */
+ for (rval = 0; argc > nargs; argc -= nargs, argv += nargs) {
+ /*
+ * Find a max value for the command length, and ensure
+ * there's enough space to build it.
+ */
+ for (l = strlen(cmd), i = 0; i < nargs; i++)
+ l += strlen(argv[i+1]);
+ if (l > clen && (c = realloc(c, clen = l)) == NULL)
+ err(1, NULL);
+
+ /* Expand command argv references. */
+ for (p = cmd, q = c; *p != '\0'; ++p)
+ if (p[0] == magic && isdigit(p[1]) && p[1] != '0') {
+ offset = snprintf(q, l, "%s",
+ argv[(++p)[0] - '0']);
+ if ((size_t)offset >= l)
+ err(1, "snprintf() failed");
+ q += offset;
+ l -= offset;
+ } else
+ *q++ = *p;
+
+ /* Terminate the command string. */
+ *q = '\0';
+
+ /* Run the command. */
+ if (debug)
+ (void)printf("%s\n", c);
+ else
+ if (exec_shell(c, shell, name))
+ rval = 1;
+ }
+
+ if (argc != 1)
+ errx(1, "expecting additional argument%s after \"%s\"",
+ (nargs - argc) ? "s" : "", argv[argc - 1]);
+ free(cmd);
+ free(c);
+ free(shell);
+ exit(rval);
+}
+
+/*
+ * exec_shell --
+ * Execute a shell command using passed use_shell and use_name
+ * arguments.
+ */
+static int
+exec_shell(const char *command, char *use_shell, char *use_name)
+{
+ pid_t pid;
+ int omask, pstat;
+ sig_t intsave, quitsave;
+
+ if (!command) /* just checking... */
+ return(1);
+
+ omask = sigblock(sigmask(SIGCHLD));
+ switch(pid = vfork()) {
+ case -1: /* error */
+ err(1, "vfork");
+ case 0: /* child */
+ (void)sigsetmask(omask);
+ execl(use_shell, use_name, "-c", command, (char *)NULL);
+ warn("%s", use_shell);
+ _exit(1);
+ }
+ intsave = signal(SIGINT, SIG_IGN);
+ quitsave = signal(SIGQUIT, SIG_IGN);
+ pid = waitpid(pid, &pstat, 0);
+ (void)sigsetmask(omask);
+ (void)signal(SIGINT, intsave);
+ (void)signal(SIGQUIT, quitsave);
+ return(pid == -1 ? -1 : pstat);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: apply [-a magic] [-d] [-0123456789] command arguments ...\n");
+ exit(1);
+}
diff --git a/shell_cmds/basename/basename.1 b/shell_cmds/basename/basename.1
new file mode 100644
index 0000000..835d21a
--- /dev/null
+++ b/shell_cmds/basename/basename.1
@@ -0,0 +1,114 @@
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)basename.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/basename/basename.1,v 1.13 2002/06/30 13:40:35 jmallett Exp $
+.\"
+.Dd April 18, 1994
+.Dt BASENAME 1
+.Os
+.Sh NAME
+.Nm basename , dirname
+.Nd return filename or directory portion of pathname
+.Sh SYNOPSIS
+.Nm
+.Ar string
+.Op Ar suffix
+.Nm
+.Op Fl a
+.Op Fl s Ar suffix
+.Ar string
+.Op Ar ...
+.Nm dirname
+.Ar string
+.Sh DESCRIPTION
+The
+.Nm
+utility deletes any prefix ending with the last slash
+.Ql \&/
+character present in
+.Ar string
+(after first stripping trailing slashes),
+and a
+.Ar suffix ,
+if given.
+The
+.Ar suffix
+is not stripped if it is identical to the remaining characters in
+.Ar string .
+The resulting filename is written to the standard output.
+A non-existent suffix is ignored.
+If
+.Fl a
+is specified, then every argument is treated as a
+.Ar string
+as if
+.Nm
+were invoked with just one argument.
+If
+.Fl s
+is specified, then the
+.Ar suffix
+is taken as its argument, and all other arguments are treated as a
+.Ar string .
+.Pp
+The
+.Nm dirname
+utility deletes the filename portion, beginning
+with the last slash
+.Ql \&/
+character to the end of
+.Ar string
+(after first stripping trailing slashes),
+and writes the result to the standard output.
+.Sh EXAMPLES
+The following line sets the shell variable
+.Ev FOO
+to
+.Pa /usr/bin .
+.Pp
+.Dl FOO=`dirname /usr/bin/trail`
+.Sh DIAGNOSTICS
+.Ex -std basename dirname
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1
+.Sh STANDARDS
+The
+.Nm
+and
+.Nm dirname
+utilities are expected to be
+.St -p1003.2
+compatible.
diff --git a/shell_cmds/basename/basename.c b/shell_cmds/basename/basename.c
new file mode 100644
index 0000000..6bde858
--- /dev/null
+++ b/shell_cmds/basename/basename.c
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)basename.c 8.4 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/basename/basename.c,v 1.14 2002/09/04 23:28:52 dwmalone Exp $");
+
+#include <err.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ char *p, *q, *suffix;
+ size_t suffixlen;
+ int aflag, ch;
+
+ aflag = 0;
+ suffix = NULL;
+ suffixlen = 0;
+
+ while ((ch = getopt(argc, argv, "as:")) != -1)
+ switch(ch) {
+ case 'a':
+ aflag = 1;
+ break;
+ case 's':
+ suffix = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ if (!*argv[0]) {
+ printf("\n");
+ exit(0);
+ }
+ if ((p = basename(argv[0])) == NULL)
+ err(1, "%s", argv[0]);
+ if ((suffix == NULL && !aflag) && argc == 2) {
+ suffix = argv[1];
+ argc--;
+ }
+ if (suffix != NULL)
+ suffixlen = strlen(suffix);
+ while (argc--) {
+ if ((p = basename(*argv)) == NULL)
+ err(1, "%s", argv[0]);
+ if (suffixlen && (q = strchr(p, '\0') - suffixlen) > p &&
+ strcmp(suffix, q) == 0)
+ *q = '\0';
+ argv++;
+ (void)printf("%s\n", p);
+ }
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+"usage: basename string [suffix]\n"
+" basename [-a] [-s suffix] string [...]\n");
+ exit(1);
+}
diff --git a/shell_cmds/basename/dirname.1 b/shell_cmds/basename/dirname.1
new file mode 100644
index 0000000..ee3bc6f
--- /dev/null
+++ b/shell_cmds/basename/dirname.1
@@ -0,0 +1 @@
+.so man1/basename.1
diff --git a/shell_cmds/chroot/chroot.8 b/shell_cmds/chroot/chroot.8
new file mode 100644
index 0000000..fce026b
--- /dev/null
+++ b/shell_cmds/chroot/chroot.8
@@ -0,0 +1,102 @@
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)chroot.8 8.1 (Berkeley) 6/9/93
+.\" $NetBSD: chroot.8,v 1.7 1998/10/06 03:47:50 mrg Exp $
+.\"
+.Dd October 6, 1998
+.Dt CHROOT 8
+.Os BSD 4.3
+.Sh NAME
+.Nm chroot
+.Nd change root directory
+.Sh SYNOPSIS
+.Nm
+.Op Fl u user
+.Op Fl g group
+.Op Fl G group,group,...
+.Ar newroot
+.Op Ar command
+.Sh DESCRIPTION
+The
+.Nm
+command changes its root directory to the supplied directory
+.Ar newroot
+and exec's
+.Ar command ,
+if supplied, or an interactive copy of your shell.
+.Pp
+If the
+.Fl u ,
+.Fl g
+or
+.Fl G
+options are given, the user, group and group list of the process are
+set to these values after the chroot has taken place. See
+.Xr setgid 2 ,
+.Xr setgroups 2 ,
+.Xr setuid 2 ,
+.Xr getgrnam 3
+and
+.Xr getpwnam 3 .
+.Pp
+Note,
+.Ar command
+or the shell are run as your real-user-id.
+.Sh ENVIRONMENT
+The following environment variable is referenced by
+.Nm :
+.Bl -tag -width SHELL
+.It Ev SHELL
+If set,
+the string specified by
+.Ev SHELL
+is interpreted as the name of
+the shell to exec.
+If the variable
+.Ev SHELL
+is not set,
+.Pa /bin/sh
+is used.
+.El
+.Sh SEE ALSO
+.Xr chdir 2 ,
+.Xr chroot 2 ,
+.Xr environ 7
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Bx 4.4 .
+.Sh SECURITY CONSIDERATIONS
+.Nm
+should never be installed setuid root, as it would then be possible
+to exploit the program to gain root privileges.
diff --git a/shell_cmds/chroot/chroot.c b/shell_cmds/chroot/chroot.c
new file mode 100644
index 0000000..c9c38f5
--- /dev/null
+++ b/shell_cmds/chroot/chroot.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)chroot.c 8.1 (Berkeley) 6/9/93";
+#else
+__RCSID("$NetBSD: chroot.c,v 1.7 1998/10/06 03:47:51 mrg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int main __P((int, char **));
+void usage __P((void)) __attribute__((__noreturn__));
+
+char *user; /* user to switch to before running program */
+char *group; /* group to switch to ... */
+char *grouplist; /* group list to switch to ... */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct group *gp;
+ struct passwd *pw;
+ char *shell, *endp, *comma;
+ gid_t gid = 0, gidlist[NGROUPS_MAX];
+ uid_t uid = 0;
+ int ch, gids;
+
+ while ((ch = getopt(argc, argv, "G:g:u:")) != -1)
+ switch(ch) {
+ case 'u':
+ user = optarg;
+ break;
+ case 'g':
+ group = optarg;
+ break;
+ case 'G':
+ grouplist = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ if (group) {
+ if (isdigit(*group)) {
+ gid = (gid_t)strtol(group, &endp, 0);
+ if (endp == group)
+ goto getgroup;
+ } else {
+getgroup:
+ if ((gp = getgrnam(group)))
+ gid = gp->gr_gid;
+ else
+ errx(1, "no such group %s", group);
+ }
+ }
+
+ for (gids = 0; grouplist; ) {
+ comma = strchr(grouplist, ',');
+
+ if (comma)
+ *comma++ = '\0';
+
+ if (isdigit(*grouplist)) {
+ gidlist[gids] = (gid_t)strtol(grouplist, &endp, 0);
+ if (endp == grouplist)
+ goto getglist;
+ } else {
+getglist:
+ if ((gp = getgrnam(grouplist)))
+ gidlist[gids] = gp->gr_gid;
+ else
+ errx(1, "no such group %s", group);
+ }
+ gids++;
+ grouplist = comma;
+ }
+
+ if (user) {
+ if (isdigit(*user)) {
+ uid = (uid_t)strtol(user, &endp, 0);
+ if (endp == user)
+ goto getuser;
+ } else {
+getuser:
+ if ((pw = getpwnam(user)))
+ uid = pw->pw_uid;
+ else
+ errx(1, "no such user %s", user);
+ }
+ }
+
+ if (chdir(argv[0]) || chroot("."))
+ err(1, "%s", argv[0]);
+
+ if (gids && setgroups(gids, gidlist) < 0)
+ err(1, "setgroups");
+ if (group && setgid(gid) < 0)
+ err(1, "setgid");
+ if (user && setuid(uid) < 0)
+ err(1, "setuid");
+
+ if (argv[1]) {
+ execvp(argv[1], &argv[1]);
+ err(1, "%s", argv[1]);
+ }
+
+ if (!(shell = getenv("SHELL")))
+ shell = _PATH_BSHELL;
+ execlp(shell, shell, "-i", NULL);
+ err(1, "%s", shell);
+ /* NOTREACHED */
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: chroot [-g group] [-G group,group,...] "
+ "[-u user] newroot [command]\n");
+ exit(1);
+}
diff --git a/shell_cmds/date/date.1 b/shell_cmds/date/date.1
new file mode 100644
index 0000000..0cabb01
--- /dev/null
+++ b/shell_cmds/date/date.1
@@ -0,0 +1,472 @@
+.\"-
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)date.1 8.3 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd May 7, 2015
+.Dt DATE 1
+.Os
+.Sh NAME
+.Nm date
+.Nd display or set date and time
+.Sh SYNOPSIS
+.Nm
+.Op Fl jRu
+.Op Fl r Ar seconds | Ar filename
+.Oo
+.Fl v
+.Sm off
+.Op Cm + | -
+.Ar val Op Ar ymwdHMS
+.Sm on
+.Oc
+.Ar ...
+.Op Cm + Ns Ar output_fmt
+.Nm
+.Op Fl jnu
+.Sm off
+.Op Oo Oo Ar mm Oc Ar dd Oc Ar HH
+.Ar MM Oo Oo Ar cc Oc Ar yy Oc Op Ar .ss
+.Sm on
+.Nm
+.Op Fl jnRu
+.Fl f Ar input_fmt new_date
+.Op Cm + Ns Ar output_fmt
+.Nm
+.Op Fl d Ar dst
+.Op Fl t Ar minutes_west
+.Sh DESCRIPTION
+When invoked without arguments, the
+.Nm
+utility displays the current date and time.
+Otherwise, depending on the options specified,
+.Nm
+will set the date and time or print it in a user-defined way.
+.Pp
+The
+.Nm
+utility displays the date and time read from the kernel clock.
+When used to set the date and time,
+both the kernel clock and the hardware clock are updated.
+.Pp
+Only the superuser may set the date,
+and if the system securelevel (see
+.Xr securelevel 7 )
+is greater than 1,
+the time may not be changed by more than 1 second.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d Ar dst
+Set the kernel's value for daylight saving time.
+If
+.Ar dst
+is non-zero, future calls
+to
+.Xr gettimeofday 2
+will return a non-zero for
+.Fa tz_dsttime .
+.It Fl f
+Use
+.Ar input_fmt
+as the format string to parse the
+.Ar new_date
+provided rather than using the default
+.Sm off
+.Oo Oo Oo
+.Ar mm Oc
+.Ar dd Oc
+.Ar HH Oc
+.Ar MM
+.Oo Oo
+.Ar cc Oc
+.Ar yy Oc Oo
+.Ar .ss Oc
+.Sm on
+format.
+Parsing is done using
+.Xr strptime 3 .
+.It Fl j
+Do not try to set the date.
+This allows you to use the
+.Fl f
+flag in addition to the
+.Cm +
+option to convert one date format to another.
+.It Fl n
+By default, if the
+.Xr timed 8
+daemon is running,
+.Nm
+sets the time on all of the machines in the local group.
+The
+.Fl n
+option suppresses this behavior and causes the time to be set only on the
+current machine.
+.It Fl R
+Use RFC 2822 date and time output format. This is equivalent to use
+.Dq Li %a, %d %b %Y \&%T %z
+as
+.Ar output_fmt
+while
+.Ev LC_TIME
+is set to the
+.Dq C
+locale .
+.It Fl r Ar seconds
+Print the date and time represented by
+.Ar seconds ,
+where
+.Ar seconds
+is the number of seconds since the Epoch
+(00:00:00 UTC, January 1, 1970;
+see
+.Xr time 3 ) ,
+and can be specified in decimal, octal, or hex.
+.It Fl r Ar filename
+Print the date and time of the last modification of
+.Ar filename .
+.It Fl t Ar minutes_west
+Set the system's value for minutes west of
+.Tn GMT .
+.Ar minutes_west
+specifies the number of minutes returned in
+.Fa tz_minuteswest
+by future calls to
+.Xr gettimeofday 2 .
+.It Fl u
+Display or set the date in
+.Tn UTC
+(Coordinated Universal) time.
+.It Fl v
+Adjust (i.e., take the current date and display the result of the
+adjustment; not actually set the date) the second, minute, hour, month
+day, week day, month or year according to
+.Ar val .
+If
+.Ar val
+is preceded with a plus or minus sign,
+the date is adjusted forwards or backwards according to the remaining string,
+otherwise the relevant part of the date is set.
+The date can be adjusted as many times as required using these flags.
+Flags are processed in the order given.
+.Pp
+When setting values
+(rather than adjusting them),
+seconds are in the range 0-59, minutes are in the range 0-59, hours are
+in the range 0-23, month days are in the range 1-31, week days are in the
+range 0-6 (Sun-Sat),
+months are in the range 1-12 (Jan-Dec)
+and years are in the range 80-38 or 1980-2038.
+.Pp
+If
+.Ar val
+is numeric, one of either
+.Ar y ,
+.Ar m ,
+.Ar w ,
+.Ar d ,
+.Ar H ,
+.Ar M
+or
+.Ar S
+must be used to specify which part of the date is to be adjusted.
+.Pp
+The week day or month may be specified using a name rather than a
+number.
+If a name is used with the plus
+(or minus)
+sign, the date will be put forwards
+(or backwards)
+to the next
+(previous)
+date that matches the given week day or month.
+This will not adjust the date,
+if the given week day or month is the same as the current one.
+.Pp
+When a date is adjusted to a specific value or in units greater than hours,
+daylight savings time considerations are ignored.
+Adjustments in units of hours or less honor daylight saving time.
+So, assuming the current date is March 26, 0:30 and that the DST adjustment
+means that the clock goes forward at 01:00 to 02:00, using
+.Fl v No +1H
+will adjust the date to March 26, 2:30.
+Likewise, if the date is October 29, 0:30 and the DST adjustment means that
+the clock goes back at 02:00 to 01:00, using
+.Fl v No +3H
+will be necessary to reach October 29, 2:30.
+.Pp
+When the date is adjusted to a specific value that does not actually exist
+(for example March 26, 1:30 BST 2000 in the Europe/London timezone),
+the date will be silently adjusted forwards in units of one hour until it
+reaches a valid time.
+When the date is adjusted to a specific value that occurs twice
+(for example October 29, 1:30 2000),
+the resulting timezone will be set so that the date matches the earlier of
+the two times.
+.Pp
+It is not possible to adjust a date to an invalid absolute day, so using
+the switches
+.Fl v No 31d Fl v No 12m
+will simply fail five months of the year.
+It is therefore usual to set the month before setting the day; using
+.Fl v No 12m Fl v No 31d
+always works.
+.Pp
+Adjusting the date by months is inherently ambiguous because
+a month is a unit of variable length depending on the current date.
+This kind of date adjustment is applied in the most intuitive way.
+First of all,
+.Nm
+tries to preserve the day of the month.
+If it is impossible because the target month is shorter than the present one,
+the last day of the target month will be the result.
+For example, using
+.Fl v No +1m
+on May 31 will adjust the date to June 30, while using the same option
+on January 30 will result in the date adjusted to the last day of February.
+This approach is also believed to make the most sense for shell scripting.
+Nevertheless, be aware that going forth and back by the same number of
+months may take you to a different date.
+.Pp
+Refer to the examples below for further details.
+.El
+.Pp
+An operand with a leading plus
+.Pq Sq +
+sign signals a user-defined format string
+which specifies the format in which to display the date and time.
+The format string may contain any of the conversion specifications
+described in the
+.Xr strftime 3
+manual page, as well as any arbitrary text.
+A newline
+.Pq Ql \en
+character is always output after the characters specified by
+the format string.
+The format string for the default display is
+.Dq +%+ .
+.Pp
+If an operand does not have a leading plus sign, it is interpreted as
+a value for setting the system's notion of the current date and time.
+The canonical representation for setting the date and time is:
+.Pp
+.Bl -tag -width Ds -compact -offset indent
+.It Ar cc
+Century
+(either 19 or 20)
+prepended to the abbreviated year.
+.It Ar yy
+Year in abbreviated form
+(e.g., 89 for 1989, 06 for 2006).
+.It Ar mm
+Numeric month, a number from 1 to 12.
+.It Ar dd
+Day, a number from 1 to 31.
+.It Ar HH
+Hour, a number from 0 to 23.
+.It Ar MM
+Minutes, a number from 0 to 59.
+.It Ar ss
+Seconds, a number from 0 to 61
+(59 plus a maximum of two leap seconds).
+.El
+.Pp
+Everything but the minutes is optional.
+.Pp
+Time changes for Daylight Saving Time, standard time, leap seconds,
+and leap years are handled automatically.
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width Ds
+.It Ev TZ
+The timezone to use when displaying dates.
+The normal format is a pathname relative to
+.Pa /usr/share/zoneinfo .
+For example, the command
+.Dq TZ=America/Los_Angeles date
+displays the current time in California.
+See
+.Xr environ 7
+for more information.
+.El
+.Sh FILES
+.Bl -tag -width /var/log/messages -compact
+.It Pa /var/log/messages
+record of the user setting the time
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 on success, 1 if unable to set the date, and 2
+if able to set the local date, but unable to set it globally.
+.Sh EXAMPLES
+The command:
+.Pp
+.Dl "date ""+DATE: %Y-%m-%d%nTIME: %H:%M:%S"""
+.Pp
+will display:
+.Bd -literal -offset indent
+DATE: 1987-11-21
+TIME: 13:36:16
+.Ed
+.Pp
+In the Europe/London timezone, the command:
+.Pp
+.Dl "date -v1m -v+1y"
+.Pp
+will display:
+.Pp
+.Dl "Sun Jan 4 04:15:24 GMT 1998"
+.Pp
+where it is currently
+.Li "Mon Aug 4 04:15:24 BST 1997" .
+.Pp
+The command:
+.Pp
+.Dl "date -v1d -v3m -v0y -v-1d"
+.Pp
+will display the last day of February in the year 2000:
+.Pp
+.Dl "Tue Feb 29 03:18:00 GMT 2000"
+.Pp
+So will the command:
+.Pp
+.Dl "date -v3m -v30d -v0y -v-1m"
+.Pp
+because there is no such date as the 30th of February.
+.Pp
+The command:
+.Pp
+.Dl "date -v1d -v+1m -v-1d -v-fri"
+.Pp
+will display the last Friday of the month:
+.Pp
+.Dl "Fri Aug 29 04:31:11 BST 1997"
+.Pp
+where it is currently
+.Li "Mon Aug 4 04:31:11 BST 1997" .
+.Pp
+The command:
+.Pp
+.Dl "date 0613162785"
+.Pp
+sets the date to
+.Dq Li "June 13, 1985, 4:27 PM" .
+.Pp
+.Dl "date ""+%m%d%H%M%Y.%S"""
+.Pp
+may be used on one machine to print out the date
+suitable for setting on another.
+.Pp
+The command:
+.Pp
+.Dl "date 1432"
+.Pp
+sets the time to
+.Li "2:32 PM" ,
+without modifying the date.
+.Pp
+Finally the command:
+.Pp
+.Dl "date -j -f ""%a %b %d %T %Z %Y"" ""`date`"" ""+%s"""
+.Pp
+can be used to parse the output from
+.Nm
+and express it in Epoch time.
+.Sh DIAGNOSTICS
+Occasionally, when
+.Xr timed 8
+synchronizes the time on many hosts, the setting of a new time value may
+require more than a few seconds.
+On these occasions,
+.Nm
+prints:
+.Ql Network time being set .
+The message
+.Ql Communication error with timed
+occurs when the communication
+between
+.Nm
+and
+.Xr timed 8
+fails.
+.Sh LEGACY SYNOPSIS
+As above, except for the second line, which is:
+.Pp
+.Nm
+.Op Fl jnu
+.Sm off
+.Op Oo Oo Oo Oo Ar cc Oc Ar yy Oc Ar mm Oc Ar dd Oc Ar HH
+.Ar MM Op Ar .ss
+.Sm on
+.Sh LEGACY DIAGNOSTICS
+When invoked in legacy mode, the following exit values are returned:
+.Bl -tag -width X -compact
+.It 0
+The date was written successfully
+.It 1
+Unable to set the date
+.It 2
+Able to set the local date, but unable to set it globally
+.El
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr locale 1 ,
+.Xr gettimeofday 2 ,
+.Xr getutxent 3 ,
+.Xr strftime 3 ,
+.Xr strptime 3 ,
+.Xr timed 8
+.Rs
+.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
+.%A R. Gusella
+.%A S. Zatti
+.Re
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be compatible with
+.St -p1003.2 .
+The
+.Fl d , f , j , n , r , t ,
+and
+.Fl v
+options are all extensions to the standard.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/shell_cmds/date/date.c b/shell_cmds/date/date.c
new file mode 100644
index 0000000..a45e110
--- /dev/null
+++ b/shell_cmds/date/date.c
@@ -0,0 +1,365 @@
+/*-
+ * Copyright (c) 1985, 1987, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <utmpx.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+#include "extern.h"
+#include "vary.h"
+
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif
+
+#ifdef __APPLE__
+#define st_mtim st_mtimespec
+#endif
+
+static time_t tval;
+int retval;
+static int unix2003_std; /* to determine legacy vs std mode */
+
+static void setthetime(const char *, const char *, int, int);
+static void badformat(void);
+static void usage(void);
+
+static const char *rfc2822_format = "%a, %d %b %Y %T %z";
+
+int
+main(int argc, char *argv[])
+{
+ struct timezone tz;
+ int ch, rflag;
+ int jflag, nflag, Rflag;
+ const char *format;
+ char buf[1024];
+ char *endptr, *fmt;
+ char *tmp;
+ int set_timezone;
+ struct vary *v;
+ const struct vary *badv;
+ struct tm lt;
+ struct stat sb;
+
+ unix2003_std = COMPAT_MODE("bin/date", "unix2003"); /* Determine the STD */
+
+ v = NULL;
+ fmt = NULL;
+ (void) setlocale(LC_TIME, "");
+ tz.tz_dsttime = tz.tz_minuteswest = 0;
+ rflag = 0;
+ jflag = nflag = Rflag = 0;
+ set_timezone = 0;
+ while ((ch = getopt(argc, argv, "d:f:jnRr:t:uv:")) != -1)
+ switch((char)ch) {
+ case 'd': /* daylight savings time */
+ tz.tz_dsttime = strtol(optarg, &endptr, 10) ? 1 : 0;
+ if (endptr == optarg || *endptr != '\0')
+ usage();
+ set_timezone = 1;
+ break;
+ case 'f':
+ fmt = optarg;
+ break;
+ case 'j':
+ jflag = 1; /* don't set time */
+ break;
+ case 'n': /* don't set network */
+ nflag = 1;
+ break;
+ case 'R': /* RFC 2822 datetime format */
+ Rflag = 1;
+ break;
+ case 'r': /* user specified seconds */
+ rflag = 1;
+ tval = strtoq(optarg, &tmp, 0);
+ if (*tmp != 0) {
+ if (stat(optarg, &sb) == 0)
+ tval = sb.st_mtim.tv_sec;
+ else
+ usage();
+ }
+ break;
+ case 't': /* minutes west of UTC */
+ /* error check; don't allow "PST" */
+ tz.tz_minuteswest = strtol(optarg, &endptr, 10);
+ if (endptr == optarg || *endptr != '\0')
+ usage();
+ set_timezone = 1;
+ break;
+ case 'u': /* do everything in UTC */
+ (void)setenv("TZ", "UTC0", 1);
+ break;
+ case 'v':
+ v = vary_append(v, optarg);
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * If -d or -t, set the timezone or daylight savings time; this
+ * doesn't belong here; the kernel should not know about either.
+ */
+ if (set_timezone && settimeofday(NULL, &tz) != 0)
+ err(1, "settimeofday (timezone)");
+
+ if (!rflag && time(&tval) == -1)
+ err(1, "time");
+
+ format = "%+";
+
+ if (Rflag)
+ format = rfc2822_format;
+
+ /* allow the operands in any order */
+ if (*argv && **argv == '+') {
+ format = *argv + 1;
+ ++argv;
+ }
+
+ if (*argv) {
+ setthetime(fmt, *argv, jflag, nflag);
+ ++argv;
+ } else if (fmt != NULL)
+ usage();
+
+ if (*argv && **argv == '+')
+ format = *argv + 1;
+
+#ifdef __APPLE__
+ /* 7999711 */
+ struct tm *ltp = localtime(&tval);
+ if (ltp == NULL) {
+ err(1, "localtime");
+ }
+ lt = *ltp;
+#else
+ lt = *localtime(&tval);
+#endif
+ badv = vary_apply(v, &lt);
+ if (badv) {
+ fprintf(stderr, "%s: Cannot apply date adjustment\n",
+ badv->arg);
+ vary_destroy(v);
+ usage();
+ }
+ vary_destroy(v);
+
+ if (format == rfc2822_format)
+ /*
+ * When using RFC 2822 datetime format, don't honor the
+ * locale.
+ */
+ setlocale(LC_TIME, "C");
+
+ (void)strftime(buf, sizeof(buf), format, &lt);
+ (void)printf("%s\n", buf);
+ if (fflush(stdout))
+ err(1, "stdout");
+ /*
+ * If date/time could not be set/notified in the other hosts as
+ * determined by netsetval(), a return value 2 is set, which is
+ * only propagated back to shell in legacy mode.
+ */
+ if (unix2003_std)
+ exit(0);
+ exit(retval);
+}
+
+#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
+#define ATOI2_OFFSET(s, o) (((s)[o] - '0') * 10 + ((s)[o + 1] - '0'))
+
+static void
+setthetime(const char *fmt, const char *p, int jflag, int nflag)
+{
+ struct utmpx utx;
+ struct tm *lt;
+ struct timeval tv;
+ const char *dot, *t;
+ int century;
+ size_t length;
+
+ lt = localtime(&tval);
+ lt->tm_isdst = -1; /* divine correct DST */
+
+ if (fmt != NULL) {
+ t = strptime(p, fmt, lt);
+ if (t == NULL) {
+ fprintf(stderr, "Failed conversion of ``%s''"
+ " using format ``%s''\n", p, fmt);
+ badformat();
+ } else if (*t != '\0')
+ fprintf(stderr, "Warning: Ignoring %ld extraneous"
+ " characters in date string (%s)\n",
+ (long) strlen(t), t);
+ } else {
+ for (t = p, dot = NULL; *t; ++t) {
+ if (isdigit(*t))
+ continue;
+ if (*t == '.' && dot == NULL) {
+ dot = t;
+ continue;
+ }
+ badformat();
+ }
+
+ if (dot != NULL) { /* .ss */
+ dot++; /* *dot++ = '\0'; */
+ if (strlen(dot) != 2)
+ badformat();
+ lt->tm_sec = ATOI2(dot);
+ if (lt->tm_sec > 61)
+ badformat();
+ } else
+ lt->tm_sec = 0;
+
+ century = 0;
+ /* if p has a ".ss" field then let's pretend it's not there */
+ switch (length = strlen(p) - ((dot != NULL) ? 3 : 0)) {
+ case 12: /* cc */
+ lt->tm_year = (unix2003_std ? ATOI2_OFFSET(p, length - 4) : ATOI2(p)) * 100 - TM_YEAR_BASE;
+ century = 1;
+ /* FALLTHROUGH */
+ case 10: /* yy */
+ if (century)
+ lt->tm_year += (unix2003_std ? ATOI2_OFFSET(p, length - 2) : ATOI2(p));
+ else {
+ lt->tm_year = (unix2003_std ? ATOI2_OFFSET(p, length - 2) : ATOI2(p));
+ if (lt->tm_year < 69) /* hack for 2000 ;-} */
+ lt->tm_year += 2000 - TM_YEAR_BASE;
+ else
+ lt->tm_year += 1900 - TM_YEAR_BASE;
+ }
+ /* FALLTHROUGH */
+ case 8: /* mm */
+ lt->tm_mon = ATOI2(p);
+ if (lt->tm_mon > 12)
+ badformat();
+ --lt->tm_mon; /* time struct is 0 - 11 */
+ /* FALLTHROUGH */
+ case 6: /* dd */
+ lt->tm_mday = ATOI2(p);
+ if (lt->tm_mday > 31)
+ badformat();
+ /* FALLTHROUGH */
+ case 4: /* HH */
+ lt->tm_hour = ATOI2(p);
+ if (lt->tm_hour > 23)
+ badformat();
+ /* FALLTHROUGH */
+ case 2: /* MM */
+ lt->tm_min = ATOI2(p);
+ if (lt->tm_min > 59)
+ badformat();
+ break;
+ default:
+ badformat();
+ }
+ }
+
+ /* convert broken-down time to GMT clock time */
+ if ((tval = mktime(lt)) == -1)
+ errx(1, "nonexistent time");
+
+ if (!jflag) {
+ /* set the time */
+ if (nflag || netsettime(tval)) {
+ utx.ut_type = OLD_TIME;
+ (void)gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+ tv.tv_sec = tval;
+ tv.tv_usec = 0;
+ if (settimeofday(&tv, NULL) != 0)
+ err(1, "settimeofday (timeval)");
+ utx.ut_type = NEW_TIME;
+ (void)gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+ }
+
+ if ((p = getlogin()) == NULL)
+ p = "???";
+ syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
+ }
+}
+
+static void
+badformat(void)
+{
+ warnx("illegal time format");
+ usage();
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n",
+ "usage: date [-jnRu] [-d dst] [-r seconds] [-t west] "
+ "[-v[+|-]val[ymwdHMS]] ... ",
+ unix2003_std ?
+ " "
+ "[-f fmt date | [[[mm]dd]HH]MM[[cc]yy][.ss]] [+format]" :
+ " "
+ "[-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format]");
+ exit(1);
+}
diff --git a/shell_cmds/date/date.plist.part b/shell_cmds/date/date.plist.part
new file mode 100644
index 0000000..da97d84
--- /dev/null
+++ b/shell_cmds/date/date.plist.part
@@ -0,0 +1,22 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>date</string>
+ <key>OpenSourceVersion</key>
+ <string>2015-05-07</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/bin/date/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/bin/date/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2015-11-06</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>date.1: discuss conformance changes</string>
+ <string>date.1: remove bogus utmpx path</string>
+ <string>date.c: conformance changes for date format and exit value</string>
+ <string>date.c: fix crash on invalid dates (7999711)</string>
+ <string>date.c: st_mtim compatibility</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/date/extern.h b/shell_cmds/date/extern.h
new file mode 100644
index 0000000..91aeab2
--- /dev/null
+++ b/shell_cmds/date/extern.h
@@ -0,0 +1,35 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 5/31/93
+ * $FreeBSD$
+ */
+
+extern int retval;
+
+int netsettime(time_t);
diff --git a/shell_cmds/date/netdate.c b/shell_cmds/date/netdate.c
new file mode 100644
index 0000000..e506e6d
--- /dev/null
+++ b/shell_cmds/date/netdate.c
@@ -0,0 +1,181 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)netdate.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+#define TSPTYPES
+#include <protocols/timed.h>
+
+#include <err.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+#define WAITACK 2 /* seconds */
+#define WAITDATEACK 5 /* seconds */
+
+/*
+ * Set the date in the machines controlled by timedaemons by communicating the
+ * new date to the local timedaemon. If the timedaemon is in the master state,
+ * it performs the correction on all slaves. If it is in the slave state, it
+ * notifies the master that a correction is needed.
+ * Returns 0 on success. Returns > 0 on failure, setting retval to 2;
+ */
+int
+netsettime(time_t tval)
+{
+ struct timeval tout;
+ struct servent *sp;
+ struct tsp msg;
+ struct sockaddr_in lsin, dest, from;
+ fd_set ready;
+ long waittime;
+ int s, port, timed_ack, found, lerr;
+ socklen_t length;
+ char hostname[MAXHOSTNAMELEN];
+
+ if ((sp = getservbyname("timed", "udp")) == NULL) {
+ warnx("timed/udp: unknown service");
+ return (retval = 2);
+ }
+
+ dest.sin_port = sp->s_port;
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ if (errno != EAFNOSUPPORT)
+ warn("timed");
+ return (retval = 2);
+ }
+
+ memset(&lsin, 0, sizeof(lsin));
+ lsin.sin_family = AF_INET;
+ for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
+ lsin.sin_port = htons((u_short)port);
+ if (bind(s, (struct sockaddr *)&lsin, sizeof(lsin)) >= 0)
+ break;
+ if (errno == EADDRINUSE)
+ continue;
+ if (errno != EADDRNOTAVAIL)
+ warn("bind");
+ goto bad;
+ }
+ if (port == IPPORT_RESERVED / 2) {
+ warnx("all ports in use");
+ goto bad;
+ }
+ memset(&msg, 0, sizeof(msg));
+ msg.tsp_type = TSP_SETDATE;
+ msg.tsp_vers = TSPVERSION;
+ if (gethostname(hostname, sizeof(hostname))) {
+ warn("gethostname");
+ goto bad;
+ }
+ (void)strlcpy(msg.tsp_name, hostname, sizeof(msg.tsp_name));
+ msg.tsp_seq = htons((u_short)0);
+ msg.tsp_time.tv_sec = htonl((u_long)tval);
+ msg.tsp_time.tv_usec = htonl((u_long)0);
+ length = sizeof(struct sockaddr_in);
+ if (connect(s, (struct sockaddr *)&dest, length) < 0) {
+ warn("connect");
+ goto bad;
+ }
+ if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) {
+ if (errno != ECONNREFUSED)
+ warn("send");
+ goto bad;
+ }
+
+ timed_ack = -1;
+ waittime = WAITACK;
+loop:
+ tout.tv_sec = waittime;
+ tout.tv_usec = 0;
+
+ FD_ZERO(&ready);
+ FD_SET(s, &ready);
+ found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
+
+ length = sizeof(lerr);
+ if (!getsockopt(s,
+ SOL_SOCKET, SO_ERROR, (char *)&lerr, &length) && lerr) {
+ if (lerr != ECONNREFUSED)
+ warnc(lerr, "send (delayed error)");
+ goto bad;
+ }
+
+ if (found > 0 && FD_ISSET(s, &ready)) {
+ length = sizeof(struct sockaddr_in);
+ if (recvfrom(s, &msg, sizeof(struct tsp), 0,
+ (struct sockaddr *)&from, &length) < 0) {
+ if (errno != ECONNREFUSED)
+ warn("recvfrom");
+ goto bad;
+ }
+ msg.tsp_seq = ntohs(msg.tsp_seq);
+ msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
+ msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
+ switch (msg.tsp_type) {
+ case TSP_ACK:
+ timed_ack = TSP_ACK;
+ waittime = WAITDATEACK;
+ goto loop;
+ case TSP_DATEACK:
+ (void)close(s);
+ return (0);
+ default:
+ warnx("wrong ack received from timed: %s",
+ tsptype[msg.tsp_type]);
+ timed_ack = -1;
+ break;
+ }
+ }
+ if (timed_ack == -1)
+ warnx("can't reach time daemon, time set locally");
+
+bad:
+ (void)close(s);
+ return (retval = 2);
+}
diff --git a/shell_cmds/date/vary.c b/shell_cmds/date/vary.c
new file mode 100644
index 0000000..5f01231
--- /dev/null
+++ b/shell_cmds/date/vary.c
@@ -0,0 +1,506 @@
+/*-
+ * Copyright (c) 1997 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <time.h>
+#include <string.h>
+#include <stdlib.h>
+#include "vary.h"
+
+struct trans {
+ int val;
+ const char *str;
+};
+
+static struct trans trans_mon[] = {
+ { 1, "january" }, { 2, "february" }, { 3, "march" }, { 4, "april" },
+ { 5, "may"}, { 6, "june" }, { 7, "july" }, { 8, "august" },
+ { 9, "september" }, { 10, "october" }, { 11, "november" }, { 12, "december" },
+ { -1, NULL }
+};
+
+static struct trans trans_wday[] = {
+ { 0, "sunday" }, { 1, "monday" }, { 2, "tuesday" }, { 3, "wednesday" },
+ { 4, "thursday" }, { 5, "friday" }, { 6, "saturday" },
+ { -1, NULL }
+};
+
+static char digits[] = "0123456789";
+static int adjhour(struct tm *, char, int, int);
+
+static int
+domktime(struct tm *t, char type)
+{
+ time_t ret;
+
+ while ((ret = mktime(t)) == -1 && t->tm_year > 68 && t->tm_year < 138)
+ /* While mktime() fails, adjust by an hour */
+ adjhour(t, type == '-' ? type : '+', 1, 0);
+
+ return ret;
+}
+
+static int
+trans(const struct trans t[], const char *arg)
+{
+ int f;
+
+ for (f = 0; t[f].val != -1; f++)
+ if (!strncasecmp(t[f].str, arg, 3) ||
+ !strncasecmp(t[f].str, arg, strlen(t[f].str)))
+ return t[f].val;
+
+ return -1;
+}
+
+struct vary *
+vary_append(struct vary *v, char *arg)
+{
+ struct vary *result, **nextp;
+
+ if (v) {
+ result = v;
+ while (v->next)
+ v = v->next;
+ nextp = &v->next;
+ } else
+ nextp = &result;
+
+ if ((*nextp = (struct vary *)malloc(sizeof(struct vary))) == NULL)
+ err(1, "malloc");
+ (*nextp)->arg = arg;
+ (*nextp)->next = NULL;
+ return result;
+}
+
+static int mdays[12] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+static int
+daysinmonth(const struct tm *t)
+{
+ int year;
+
+ year = t->tm_year + 1900;
+
+ if (t->tm_mon == 1)
+ if (!(year % 400))
+ return 29;
+ else if (!(year % 100))
+ return 28;
+ else if (!(year % 4))
+ return 29;
+ else
+ return 28;
+ else if (t->tm_mon >= 0 && t->tm_mon < 12)
+ return mdays[t->tm_mon];
+
+ return 0;
+}
+
+
+static int
+adjyear(struct tm *t, char type, int val, int mk)
+{
+ switch (type) {
+ case '+':
+ t->tm_year += val;
+ break;
+ case '-':
+ t->tm_year -= val;
+ break;
+ default:
+ t->tm_year = val;
+ if (t->tm_year < 69)
+ t->tm_year += 100; /* as per date.c */
+ else if (t->tm_year > 1900)
+ t->tm_year -= 1900; /* struct tm holds years since 1900 */
+ break;
+ }
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjmon(struct tm *t, char type, int val, int istext, int mk)
+{
+ int lmdays;
+
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (istext) {
+ if (val <= t->tm_mon)
+ val += 11 - t->tm_mon; /* early next year */
+ else
+ val -= t->tm_mon + 1; /* later this year */
+ }
+ if (val) {
+ if (!adjyear(t, '+', (t->tm_mon + val) / 12, 0))
+ return 0;
+ val %= 12;
+ t->tm_mon += val;
+ if (t->tm_mon > 11)
+ t->tm_mon -= 12;
+ }
+ break;
+
+ case '-':
+ if (istext) {
+ if (val-1 > t->tm_mon)
+ val = 13 - val + t->tm_mon; /* later last year */
+ else
+ val = t->tm_mon - val + 1; /* early this year */
+ }
+ if (val) {
+ if (!adjyear(t, '-', val / 12, 0))
+ return 0;
+ val %= 12;
+ if (val > t->tm_mon) {
+ if (!adjyear(t, '-', 1, 0))
+ return 0;
+ val -= 12;
+ }
+ t->tm_mon -= val;
+ }
+ break;
+
+ default:
+ if (val > 12 || val < 1)
+ return 0;
+ t->tm_mon = --val;
+ }
+
+ /* e.g., -v-1m on March, 31 is the last day of February in common sense */
+ lmdays = daysinmonth(t);
+ if (t->tm_mday > lmdays)
+ t->tm_mday = lmdays;
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjday(struct tm *t, char type, int val, int mk)
+{
+ int lmdays;
+
+ switch (type) {
+ case '+':
+ while (val) {
+ lmdays = daysinmonth(t);
+ if (val > lmdays - t->tm_mday) {
+ val -= lmdays - t->tm_mday + 1;
+ t->tm_mday = 1;
+ if (!adjmon(t, '+', 1, 0, 0))
+ return 0;
+ } else {
+ t->tm_mday += val;
+ val = 0;
+ }
+ }
+ break;
+ case '-':
+ while (val)
+ if (val >= t->tm_mday) {
+ val -= t->tm_mday;
+ t->tm_mday = 1;
+ if (!adjmon(t, '-', 1, 0, 0))
+ return 0;
+ t->tm_mday = daysinmonth(t);
+ } else {
+ t->tm_mday -= val;
+ val = 0;
+ }
+ break;
+ default:
+ if (val > 0 && val <= daysinmonth(t))
+ t->tm_mday = val;
+ else
+ return 0;
+ break;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjwday(struct tm *t, char type, int val, int istext, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (istext)
+ if (val < t->tm_wday)
+ val = 7 - t->tm_wday + val; /* early next week */
+ else
+ val -= t->tm_wday; /* later this week */
+ else
+ val *= 7; /* "-v+5w" == "5 weeks in the future" */
+ return !val || adjday(t, '+', val, mk);
+ case '-':
+ if (istext) {
+ if (val > t->tm_wday)
+ val = 7 - val + t->tm_wday; /* later last week */
+ else
+ val = t->tm_wday - val; /* early this week */
+ } else
+ val *= 7; /* "-v-5w" == "5 weeks ago" */
+ return !val || adjday(t, '-', val, mk);
+ default:
+ if (val < t->tm_wday)
+ return adjday(t, '-', t->tm_wday - val, mk);
+ else if (val > 6)
+ return 0;
+ else if (val > t->tm_wday)
+ return adjday(t, '+', val - t->tm_wday, mk);
+ }
+ return 1;
+}
+
+static int
+adjhour(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ int days;
+
+ days = (t->tm_hour + val) / 24;
+ val %= 24;
+ t->tm_hour += val;
+ t->tm_hour %= 24;
+ if (!adjday(t, '+', days, 0))
+ return 0;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ int days;
+
+ days = val / 24;
+ val %= 24;
+ if (val > t->tm_hour) {
+ days++;
+ val -= 24;
+ }
+ t->tm_hour -= val;
+ if (!adjday(t, '-', days, 0))
+ return 0;
+ }
+ break;
+
+ default:
+ if (val > 23)
+ return 0;
+ t->tm_hour = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjmin(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ if (!adjhour(t, '+', (t->tm_min + val) / 60, 0))
+ return 0;
+ val %= 60;
+ t->tm_min += val;
+ if (t->tm_min > 59)
+ t->tm_min -= 60;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ if (!adjhour(t, '-', val / 60, 0))
+ return 0;
+ val %= 60;
+ if (val > t->tm_min) {
+ if (!adjhour(t, '-', 1, 0))
+ return 0;
+ val -= 60;
+ }
+ t->tm_min -= val;
+ }
+ break;
+
+ default:
+ if (val > 59)
+ return 0;
+ t->tm_min = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+static int
+adjsec(struct tm *t, char type, int val, int mk)
+{
+ if (val < 0)
+ return 0;
+
+ switch (type) {
+ case '+':
+ if (val) {
+ if (!adjmin(t, '+', (t->tm_sec + val) / 60, 0))
+ return 0;
+ val %= 60;
+ t->tm_sec += val;
+ if (t->tm_sec > 59)
+ t->tm_sec -= 60;
+ }
+ break;
+
+ case '-':
+ if (val) {
+ if (!adjmin(t, '-', val / 60, 0))
+ return 0;
+ val %= 60;
+ if (val > t->tm_sec) {
+ if (!adjmin(t, '-', 1, 0))
+ return 0;
+ val -= 60;
+ }
+ t->tm_sec -= val;
+ }
+ break;
+
+ default:
+ if (val > 59)
+ return 0;
+ t->tm_sec = val;
+ }
+
+ return !mk || domktime(t, type) != -1;
+}
+
+const struct vary *
+vary_apply(const struct vary *v, struct tm *t)
+{
+ char type;
+ char which;
+ char *arg;
+ size_t len;
+ int val;
+
+ for (; v; v = v->next) {
+ type = *v->arg;
+ arg = v->arg;
+ if (type == '+' || type == '-')
+ arg++;
+ else
+ type = '\0';
+ len = strlen(arg);
+ if (len < 2)
+ return v;
+
+ if (type == '\0')
+ t->tm_isdst = -1;
+
+ if (strspn(arg, digits) != len-1) {
+ val = trans(trans_wday, arg);
+ if (val != -1) {
+ if (!adjwday(t, type, val, 1, 1))
+ return v;
+ } else {
+ val = trans(trans_mon, arg);
+ if (val != -1) {
+ if (!adjmon(t, type, val, 1, 1))
+ return v;
+ } else
+ return v;
+ }
+ } else {
+ val = atoi(arg);
+ which = arg[len-1];
+
+ switch (which) {
+ case 'S':
+ if (!adjsec(t, type, val, 1))
+ return v;
+ break;
+ case 'M':
+ if (!adjmin(t, type, val, 1))
+ return v;
+ break;
+ case 'H':
+ if (!adjhour(t, type, val, 1))
+ return v;
+ break;
+ case 'd':
+ t->tm_isdst = -1;
+ if (!adjday(t, type, val, 1))
+ return v;
+ break;
+ case 'w':
+ t->tm_isdst = -1;
+ if (!adjwday(t, type, val, 0, 1))
+ return v;
+ break;
+ case 'm':
+ t->tm_isdst = -1;
+ if (!adjmon(t, type, val, 0, 1))
+ return v;
+ break;
+ case 'y':
+ t->tm_isdst = -1;
+ if (!adjyear(t, type, val, 1))
+ return v;
+ break;
+ default:
+ return v;
+ }
+ }
+ }
+ return 0;
+}
+
+void
+vary_destroy(struct vary *v)
+{
+ struct vary *n;
+
+ while (v) {
+ n = v->next;
+ free(v);
+ v = n;
+ }
+}
diff --git a/shell_cmds/date/vary.h b/shell_cmds/date/vary.h
new file mode 100644
index 0000000..b39306a
--- /dev/null
+++ b/shell_cmds/date/vary.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 1997 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.
+ *
+ * $FreeBSD$
+ */
+
+struct vary {
+ char *arg;
+ struct vary *next;
+};
+
+extern struct vary *vary_append(struct vary *v, char *arg);
+extern const struct vary *vary_apply(const struct vary *v, struct tm *t);
+extern void vary_destroy(struct vary *v);
diff --git a/shell_cmds/dirname/dirname.c b/shell_cmds/dirname/dirname.c
new file mode 100644
index 0000000..11b19b2
--- /dev/null
+++ b/shell_cmds/dirname/dirname.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static const char sccsid[] = "@(#)dirname.c 8.4 (Berkeley) 5/4/95";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/dirname/dirname.c,v 1.11 2002/07/28 15:43:56 dwmalone Exp $");
+
+#include <err.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ char *p;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ if ((p = dirname(*argv)) == NULL)
+ err(1, "%s", *argv);
+ (void)printf("%s\n", p);
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: dirname path\n");
+ exit(1);
+}
diff --git a/shell_cmds/echo/echo.1 b/shell_cmds/echo/echo.1
new file mode 100644
index 0000000..87bcc34
--- /dev/null
+++ b/shell_cmds/echo/echo.1
@@ -0,0 +1,101 @@
+.\"-
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)echo.1 8.1 (Berkeley) 7/22/93
+.\" $FreeBSD: src/bin/echo/echo.1,v 1.19 2005/01/16 16:41:56 ru Exp $
+.\"
+.Dd April 12, 2003
+.Dt ECHO 1
+.Os
+.Sh NAME
+.Nm echo
+.Nd write arguments to the standard output
+.Sh SYNOPSIS
+.Nm
+.Op Fl n
+.Op Ar string ...
+.Sh DESCRIPTION
+The
+.Nm
+utility writes any specified operands, separated by single blank
+.Pq Ql "\ "
+characters and followed by a newline
+.Pq Ql \en
+character, to the standard
+output.
+.Pp
+The following option is available:
+.Bl -tag -width flag
+.It Fl n
+Do not print the trailing newline character.
+This may also be achieved by appending
+.Ql \ec
+to the end of the string, as is done
+by iBCS2 compatible systems.
+Note that this option as well as the effect of
+.Ql \ec
+are implementation-defined in
+.St -p1003.1-2001
+as amended by Cor.\& 1-2002.
+Applications aiming for maximum
+portability are strongly encouraged to use
+.Xr printf 1
+to suppress the newline character.
+.El
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+.\" 4874742
+Most notably, the builtin
+.Nm
+in
+.Xr sh 1
+does not accept the
+.Fl n
+option.
+.\" 4874742
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr printf 1 ,
+.Xr sh 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001
+as amended by Cor.\& 1-2002.
diff --git a/shell_cmds/echo/echo.c b/shell_cmds/echo/echo.c
new file mode 100644
index 0000000..a994e6d
--- /dev/null
+++ b/shell_cmds/echo/echo.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)echo.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/echo/echo.c,v 1.18 2005/01/10 08:39:22 imp Exp $");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+static void
+flush_and_exit(void)
+{
+ if (fflush(stdout) != 0)
+ err(1, "fflush");
+ exit(0);
+}
+
+static char *
+print_one_char(char *cur, int posix, int *bytes_len_out)
+{
+ char *next;
+ wchar_t wc;
+ int bytes_len = mbtowc(&wc, cur, MB_CUR_MAX);
+ if (bytes_len <= 0) {
+ putchar(*cur);
+ bytes_len = 1;
+ goto out;
+ }
+
+ /* If this is not an escape sequence, just print the character */
+ if (wc != '\\') {
+ putwchar(wc);
+ goto out;
+ }
+
+ next = cur + bytes_len;
+
+ if (!posix) {
+ /* In non-POSIX mode, the only valid escape sequence is \c */
+ if (*next == 'c') {
+ flush_and_exit();
+ } else {
+ putchar(wc);
+ goto out;
+ }
+ } else {
+ cur = next;
+ bytes_len = 1;
+ }
+
+ switch (*cur) {
+ case 'a':
+ putchar('\a');
+ goto out;
+
+ case 'b':
+ putchar('\b');
+ goto out;
+
+ case 'c':
+ flush_and_exit();
+
+ case 'f':
+ putchar('\f');
+ goto out;
+
+ case 'n':
+ putchar('\n');
+ goto out;
+
+ case 'r':
+ putchar('\r');
+ goto out;
+
+ case 't':
+ putchar('\t');
+ goto out;
+
+ case 'v':
+ putchar('\v');
+ goto out;
+
+ case '\\':
+ putchar('\\');
+ goto out;
+
+ case '0': {
+ int j = 0, num = 0;
+ while ((*++cur >= '0' && *cur <= '7') &&
+ j++ < 3) {
+ num <<= 3;
+ num |= (*cur - '0');
+ }
+ putchar(num);
+ --cur;
+ goto out;
+ }
+ default:
+ --cur;
+ putchar(*cur);
+ goto out;
+ }
+
+ out:
+ if (bytes_len_out)
+ *bytes_len_out = bytes_len;
+ return cur;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int nflag = 0;
+ int posix = (getenv("POSIXLY_CORRECT") != NULL || getenv("POSIX_PEDANTIC") != NULL);
+
+ if (!posix && argv[1] && strcmp(argv[1], "-n") == 0)
+ nflag = 1;
+
+ for (int i = 0; i < argc; i++) {
+ /* argv[0] == progname */
+ int ignore_arg = (i == 0 || (i == 1 && nflag == 1));
+ int last_arg = (i == (argc - 1));
+ if (!ignore_arg) {
+ char *cur = argv[i];
+ size_t arg_len = strlen(cur);
+ int bytes_len = 0;
+
+ for (const char *end = cur + arg_len; cur < end; cur += bytes_len) {
+ cur = print_one_char(cur, posix, &bytes_len);
+ }
+ }
+ if (last_arg && !nflag)
+ putchar('\n');
+ else if (!last_arg && !ignore_arg)
+ putchar(' ');
+
+ if (fflush(stdout) != 0)
+ err(1, "fflush");
+ }
+
+ return 0;
+}
diff --git a/shell_cmds/env/env.1 b/shell_cmds/env/env.1
new file mode 100644
index 0000000..101f4eb
--- /dev/null
+++ b/shell_cmds/env/env.1
@@ -0,0 +1,482 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From @(#)printenv.1 8.1 (Berkeley) 6/6/93
+.\" From FreeBSD: src/usr.bin/printenv/printenv.1,v 1.17 2002/11/26 17:33:35 ru Exp
+.\" $FreeBSD$
+.\"
+.Dd April 17, 2008
+.Dt ENV 1
+.Os
+.Sh NAME
+.Nm env
+.Nd set environment and execute command, or print environment
+.Sh SYNOPSIS
+.Nm
+.Op Fl iv
+.Op Fl P Ar altpath
+.Op Fl S Ar string
+.Op Fl u Ar name
+.Op Ar name Ns = Ns Ar value ...
+.Op Ar utility Op Ar argument ...
+.Sh DESCRIPTION
+The
+.Nm
+utility executes another
+.Ar utility
+after modifying the environment as
+specified on the command line.
+Each
+.Ar name Ns = Ns Ar value
+option specifies the setting of an environment variable,
+.Ar name ,
+with a value of
+.Ar value .
+All such environment variables are set before the
+.Ar utility
+is executed.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl i
+Execute the
+.Ar utility
+with only those environment variables specified by
+.Ar name Ns = Ns Ar value
+options.
+The environment inherited
+by
+.Nm
+is ignored completely.
+.\" -P
+.It Fl P Ar altpath
+Search the set of directories as specified by
+.Ar altpath
+to locate the specified
+.Ar utility
+program, instead of using the value of the
+.Ev PATH
+environment variable.
+.\" -S
+.It Fl S Ar string
+Split apart the given
+.Ar string
+into multiple strings, and process each of the resulting strings
+as separate arguments to the
+.Nm
+utility.
+The
+.Fl S
+option recognizes some special character escape sequences and
+also supports environment-variable substitution, as described
+below.
+.\" -u
+.It Fl u Ar name
+If the environment variable
+.Ar name
+is in the environment, then remove it before processing the
+remaining options.
+This is similar to the
+.Ic unset
+command in
+.Xr sh 1 .
+The value for
+.Ar name
+must not include the
+.Ql =
+character.
+.\" -v
+.It Fl v
+Print verbose information for each step of processing done by the
+.Nm
+utility.
+Additional information will be printed if
+.Fl v
+is specified multiple times.
+.El
+.Pp
+The above options are only recognized when they are specified
+before any
+.Ar name Ns = Ns Ar value
+options.
+.Pp
+If no
+.Ar utility
+is specified,
+.Nm
+prints out the names and values
+of the variables in the environment, with one name/value pair per line.
+.\"
+.Ss Details of Fl S Ss (split-string) processing
+The processing of the
+.Fl S
+option will split the given
+.Ar string
+into separate arguments based on any space or <tab> characters found in the
+.Ar string .
+Each of those new arguments will then be treated as if it had been
+specified as a separate argument on the original
+.Nm
+command.
+.Pp
+Spaces and tabs may be embedded in one of those new arguments by using
+single
+.Pq Dq Li '
+or double
+.Pq Ql \&"
+quotes, or backslashes
+.Pq Ql \e .
+Single quotes will escape all non-single quote characters, up to
+the matching single quote.
+Double quotes will escape all non-double quote characters, up to
+the matching double quote.
+It is an error if the end of the
+.Ar string
+is reached before the matching quote character.
+.Pp
+If
+.Fl S
+would create a new argument that starts with the
+.Ql #
+character, then that argument and the remainder of the
+.Ar string
+will be ignored.
+The
+.Ql \e#
+sequence can be used when you want a new argument to start
+with a
+.Ql #
+character, without causing the remainder of the
+.Ar string
+to be skipped.
+.Pp
+While processing the
+.Ar string
+value,
+.Fl S
+processing will treat certain character combinations as escape
+sequences which represent some action to take.
+The character escape sequences are in backslash notation.
+The characters and their meanings are as follows:
+.Pp
+.Bl -tag -width indent -offset indent -compact
+.It Cm \ec
+Ignore the remaining characters in the
+.Ar string .
+This must not appear inside a double-quoted string.
+.It Cm \ef
+Replace with a <form-feed> character.
+.It Cm \en
+Replace with a <new-line> character.
+.It Cm \er
+Replace with a <carriage return> character.
+.It Cm \et
+Replace with a <tab> character.
+.It Cm \ev
+Replace with a <vertical tab> character.
+.It Cm \e#
+Replace with a
+.Ql #
+character.
+This would be useful when you need a
+.Ql #
+as the first character in one of the arguments created
+by splitting apart the given
+.Ar string .
+.It Cm \e$
+Replace with a
+.Ql $
+character.
+.It Cm \e_
+If this is found inside of a double-quoted string, then replace it
+with a single blank.
+If this is found outside of a quoted string, then treat this as the
+separator character between new arguments in the original
+.Ar string .
+.It Cm \e"
+Replace with a <double quote> character.
+.It Cm \e\'
+Replace with a <single quote> character.
+.It Cm \e\e
+Replace with a backslash character.
+.El
+.Pp
+The sequences for <single-quote> and backslash are the only sequences
+which are recognized inside of a single-quoted string.
+The other sequences have no special meaning inside a single-quoted
+string.
+All escape sequences are recognized inside of a double-quoted string.
+It is an error if a single
+.Ql \e
+character is followed by a character other than the ones listed above.
+.Pp
+The processing of
+.Fl S
+also supports substitution of values from environment variables.
+To do this, the name of the environment variable must be inside of
+.Ql ${} ,
+such as:
+.Li ${SOMEVAR} .
+The common shell syntax of
+.Li $SOMEVAR
+is not supported.
+All values substituted will be the values of the environment variables
+as they were when the
+.Nm
+utility was originally invoked.
+Those values will not be checked for any of the escape sequences as
+described above.
+And any settings of
+.Ar name Ns = Ns Ar value
+will not effect the values used for substitution in
+.Fl S
+processing.
+.Pp
+Also,
+.Fl S
+processing can not reference the value of the special parameters
+which are defined by most shells.
+For instance,
+.Fl S
+can not recognize special parameters such as:
+.Ql $* ,
+.Ql $@ ,
+.Ql $# ,
+.Ql $?
+or
+.Ql $$
+if they appear inside the given
+.Ar string .
+.\"
+.Ss Use in shell-scripts
+The
+.Nm
+utility is often used as the
+.Ar interpreter
+on the first line of interpreted scripts, as
+described in
+.Xr execve 2 .
+.Pp
+Note that the way the kernel parses the
+.Ql #!
+(first line) of an interpreted script has changed as of
+.Fx 6.0 .
+Prior to that, the
+.Fx
+kernel would split that first line into separate arguments based
+on any whitespace (space or <tab> characters) found in the line.
+So, if a script named
+.Pa /usr/local/bin/someport
+had a first line of:
+.Pp
+.Dl "#!/usr/local/bin/php -n -q -dsafe_mode=0"
+.Pp
+then the
+.Pa /usr/local/bin/php
+program would have been started with the arguments of:
+.Bd -literal -offset indent
+arg[0] = '/usr/local/bin/php'
+arg[1] = '-n'
+arg[2] = '-q'
+arg[3] = '-dsafe_mode=0'
+arg[4] = '/usr/local/bin/someport'
+.Ed
+.Pp
+plus any arguments the user specified when executing
+.Pa someport .
+However, this processing of multiple options on the
+.Ql #!
+line is not the way any other operating system parses the
+first line of an interpreted script.
+So after a change which was made for
+.Fx 6.0
+release, that script will result in
+.Pa /usr/local/bin/php
+being started with the arguments of:
+.Bd -literal -offset indent
+arg[0] = '/usr/local/bin/php'
+arg[1] = '-n -q -dsafe_mode=0'
+arg[2] = '/usr/local/bin/someport'
+.Ed
+.Pp
+plus any arguments the user specified.
+This caused a significant change in the behavior of a few scripts.
+In the case of above script, to have it behave the same way under
+.Fx 6.0
+as it did under earlier releases, the first line should be
+changed to:
+.Pp
+.Dl "#!/usr/bin/env -S /usr/local/bin/php -n -q -dsafe_mode=0"
+.Pp
+The
+.Nm
+utility will be started with the entire line as a single
+argument:
+.Pp
+.Dl "arg[1] = '-S /usr/local/bin/php -n -q -dsafe_mode=0'"
+.Pp
+and then
+.Fl S
+processing will split that line into separate arguments before
+executing
+.Pa /usr/local/bin/php .
+.\"
+.Sh ENVIRONMENT
+The
+.Nm
+utility uses the
+.Ev PATH
+environment variable to locate the requested
+.Ar utility
+if the name contains no
+.Ql /
+characters, unless the
+.Fl P
+option has been specified.
+.Sh EXIT STATUS
+.Ex -std
+An exit status of 126 indicates that
+.Ar utility
+was found, but could not be executed.
+An exit status of 127 indicates that
+.Ar utility
+could not be found.
+.Sh EXAMPLES
+Since the
+.Nm
+utility is often used as part of the first line of an interpreted script,
+the following examples show a number of ways that the
+.Nm
+utility can be useful in scripts.
+.Pp
+The kernel processing of an interpreted script does not allow a script
+to directly reference some other script as its own interpreter.
+As a way around this, the main difference between
+.Pp
+.Dl #!/usr/local/bin/foo
+and
+.Dl "#!/usr/bin/env /usr/local/bin/foo"
+.Pp
+is that the latter works even if
+.Pa /usr/local/bin/foo
+is itself an interpreted script.
+.Pp
+Probably the most common use of
+.Nm
+is to find the correct interpreter for a script, when the interpreter
+may be in different directories on different systems.
+The following example will find the
+.Ql perl
+interpreter by searching through the directories specified by
+.Ev PATH .
+.Pp
+.Dl "#!/usr/bin/env perl"
+.Pp
+One limitation of that example is that it assumes the user's value
+for
+.Ev PATH
+is set to a value which will find the interpreter you want
+to execute.
+The
+.Fl P
+option can be used to make sure a specific list of directories is
+used in the search for
+.Ar utility .
+Note that the
+.Fl S
+option is also required for this example to work correctly.
+.Pp
+.Dl "#!/usr/bin/env -S -P/usr/local/bin:/usr/bin perl"
+.Pp
+The above finds
+.Ql perl
+only if it is in
+.Pa /usr/local/bin
+or
+.Pa /usr/bin .
+That could be combined with the present value of
+.Ev PATH ,
+to provide more flexibility.
+Note that spaces are not required between the
+.Fl S
+and
+.Fl P
+options:
+.Pp
+.Dl "#!/usr/bin/env -S-P/usr/local/bin:/usr/bin:${PATH} perl"
+.Sh COMPATIBILITY
+The
+.Nm
+utility accepts the
+.Fl
+option as a synonym for
+.Fl i .
+.Sh SEE ALSO
+.Xr printenv 1 ,
+.Xr sh 1 ,
+.Xr execvp 3 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+The
+.Fl P , S , u
+and
+.Fl v
+options are non-standard extensions supported by
+.Fx ,
+but which may not be available on other operating systems.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
+The
+.Fl P , S
+and
+.Fl v
+options were added in
+.Fx 6.0 .
+.Sh BUGS
+The
+.Nm
+utility does not handle values of
+.Ar utility
+which have an equals sign
+.Pq Ql =
+in their name, for obvious reasons.
+.Pp
+The
+.Nm
+utility does not take multibyte characters into account when
+processing the
+.Fl S
+option, which may lead to incorrect results in some locales.
diff --git a/shell_cmds/env/env.c b/shell_cmds/env/env.c
new file mode 100644
index 0000000..3dc152a
--- /dev/null
+++ b/shell_cmds/env/env.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)env.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "envopts.h"
+
+extern char **environ;
+
+int env_verbosity;
+
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ char *altpath, **ep, *p, **parg;
+ char *cleanenv[1];
+ int ch, want_clear;
+ int rtrn;
+
+ altpath = NULL;
+ want_clear = 0;
+ while ((ch = getopt(argc, argv, "-iP:S:u:v")) != -1)
+ switch(ch) {
+ case '-':
+ case 'i':
+ want_clear = 1;
+ break;
+ case 'P':
+ altpath = strdup(optarg);
+ break;
+ case 'S':
+ /*
+ * The -S option, for "split string on spaces, with
+ * support for some simple substitutions"...
+ */
+ split_spaces(optarg, &optind, &argc, &argv);
+ break;
+ case 'u':
+ if (env_verbosity)
+ fprintf(stderr, "#env unset:\t%s\n", optarg);
+ rtrn = unsetenv(optarg);
+ if (rtrn == -1)
+ err(EXIT_FAILURE, "unsetenv %s", optarg);
+ break;
+ case 'v':
+ env_verbosity++;
+ if (env_verbosity > 1)
+ fprintf(stderr, "#env verbosity now at %d\n",
+ env_verbosity);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ if (want_clear) {
+ environ = cleanenv;
+ cleanenv[0] = NULL;
+ if (env_verbosity)
+ fprintf(stderr, "#env clearing environ\n");
+ }
+ for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) {
+ if (env_verbosity)
+ fprintf(stderr, "#env setenv:\t%s\n", *argv);
+ *p = '\0';
+ rtrn = setenv(*argv, p + 1, 1);
+ *p = '=';
+ if (rtrn == -1)
+ err(EXIT_FAILURE, "setenv %s", *argv);
+ }
+ if (*argv) {
+ if (altpath)
+ search_paths(altpath, argv);
+ if (env_verbosity) {
+ fprintf(stderr, "#env executing:\t%s\n", *argv);
+ for (parg = argv, argc = 0; *parg; parg++, argc++)
+ fprintf(stderr, "#env arg[%d]=\t'%s'\n",
+ argc, *parg);
+ if (env_verbosity > 1)
+ sleep(1);
+ }
+ execvp(*argv, argv);
+ err(errno == ENOENT ? 127 : 126, "%s", *argv);
+ }
+ for (ep = environ; *ep; ep++)
+ (void)printf("%s\n", *ep);
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: env [-iv] [-P utilpath] [-S string] [-u name]\n"
+ " [name=value ...] [utility [argument ...]]\n");
+ exit(1);
+}
diff --git a/shell_cmds/env/envopts.c b/shell_cmds/env/envopts.c
new file mode 100644
index 0000000..f821430
--- /dev/null
+++ b/shell_cmds/env/envopts.c
@@ -0,0 +1,468 @@
+/*-
+ * Copyright (c) 2005 - Garance Alistair Drosehn <gad@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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the FreeBSD Project.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <err.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "envopts.h"
+
+static const char *
+ expand_vars(int in_thisarg, char **thisarg_p, char **dest_p,
+ const char **src_p);
+static int is_there(char *candidate);
+
+/*
+ * The is*() routines take a parameter of 'int', but expect values in the range
+ * of unsigned char. Define some wrappers which take a value of type 'char',
+ * whether signed or unsigned, and ensure the value ends up in the right range.
+ */
+#define isalnumch(Anychar) isalnum((u_char)(Anychar))
+#define isalphach(Anychar) isalpha((u_char)(Anychar))
+#define isspacech(Anychar) isspace((u_char)(Anychar))
+
+/*
+ * Routine to determine if a given fully-qualified filename is executable.
+ * This is copied almost verbatim from FreeBSD's usr.bin/which/which.c.
+ */
+static int
+is_there(char *candidate)
+{
+ struct stat fin;
+
+ /* XXX work around access(2) false positives for superuser */
+ if (access(candidate, X_OK) == 0 &&
+ stat(candidate, &fin) == 0 &&
+ S_ISREG(fin.st_mode) &&
+ (getuid() != 0 ||
+ (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+ if (env_verbosity > 1)
+ fprintf(stderr, "#env matched:\t'%s'\n", candidate);
+ return (1);
+ }
+ return (0);
+}
+
+/**
+ * Routine to search through an alternate path-list, looking for a given
+ * filename to execute. If the file is found, replace the original
+ * unqualified name with a fully-qualified path. This allows `env' to
+ * execute programs from a specific strict list of possible paths, without
+ * changing the value of PATH seen by the program which will be executed.
+ * E.G.:
+ * #!/usr/bin/env -S-P/usr/local/bin:/usr/bin perl
+ * will execute /usr/local/bin/perl or /usr/bin/perl (whichever is found
+ * first), no matter what the current value of PATH is, and without
+ * changing the value of PATH that the script will see when it runs.
+ *
+ * This is similar to the print_matches() routine in usr.bin/which/which.c.
+ */
+void
+search_paths(char *path, char **argv)
+{
+ char candidate[PATH_MAX];
+ const char *d;
+ char *filename, *fqname;
+
+ /* If the file has a `/' in it, then no search is done */
+ filename = *argv;
+ if (strchr(filename, '/') != NULL)
+ return;
+
+ if (env_verbosity > 1) {
+ fprintf(stderr, "#env Searching:\t'%s'\n", path);
+ fprintf(stderr, "#env for file:\t'%s'\n", filename);
+ }
+
+ fqname = NULL;
+ while ((d = strsep(&path, ":")) != NULL) {
+ if (*d == '\0')
+ d = ".";
+ if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
+ filename) >= (int)sizeof(candidate))
+ continue;
+ if (is_there(candidate)) {
+ fqname = candidate;
+ break;
+ }
+ }
+
+ if (fqname == NULL) {
+ errno = ENOENT;
+ err(127, "%s", filename);
+ }
+ *argv = strdup(candidate);
+}
+
+/**
+ * Routine to split a string into multiple parameters, while recognizing a
+ * few special characters. It recognizes both single and double-quoted
+ * strings. This processing is designed entirely for the benefit of the
+ * parsing of "#!"-lines (aka "shebang" lines == the first line of an
+ * executable script). Different operating systems parse that line in very
+ * different ways, and this split-on-spaces processing is meant to provide
+ * ways to specify arbitrary arguments on that line, no matter how the OS
+ * parses it.
+ *
+ * Within a single-quoted string, the two characters "\'" are treated as
+ * a literal "'" character to add to the string, and "\\" are treated as
+ * a literal "\" character to add. Other than that, all characters are
+ * copied until the processing gets to a terminating "'".
+ *
+ * Within a double-quoted string, many more "\"-style escape sequences
+ * are recognized, mostly copied from what is recognized in the `printf'
+ * command. Some OS's will not allow a literal blank character to be
+ * included in the one argument that they recognize on a shebang-line,
+ * so a few additional escape-sequences are defined to provide ways to
+ * specify blanks.
+ *
+ * Within a double-quoted string "\_" is turned into a literal blank.
+ * (Inside of a single-quoted string, the two characters are just copied)
+ * Outside of a quoted string, "\_" is treated as both a blank, and the
+ * end of the current argument. So with a shelbang-line of:
+ * #!/usr/bin/env -SA=avalue\_perl
+ * the -S value would be broken up into arguments "A=avalue" and "perl".
+ */
+void
+split_spaces(const char *str, int *origind, int *origc, char ***origv)
+{
+ static const char *nullarg = "";
+ const char *bq_src, *copystr, *src;
+ char *dest, **newargv, *newstr, **nextarg, **oldarg;
+ int addcount, bq_destlen, copychar, found_sep, in_arg, in_dq, in_sq;
+
+ /*
+ * Ignore leading space on the string, and then malloc enough room
+ * to build a copy of it. The copy might end up shorter than the
+ * original, due to quoted strings and '\'-processing.
+ */
+ while (isspacech(*str))
+ str++;
+ if (*str == '\0')
+ return;
+ newstr = malloc(strlen(str) + 1);
+
+ /*
+ * Allocate plenty of space for the new array of arg-pointers,
+ * and start that array off with the first element of the old
+ * array.
+ */
+ newargv = malloc((*origc + (strlen(str) / 2) + 2) * sizeof(char *));
+ nextarg = newargv;
+ *nextarg++ = **origv;
+
+ /* Come up with the new args by splitting up the given string. */
+ addcount = 0;
+ bq_destlen = in_arg = in_dq = in_sq = 0;
+ bq_src = NULL;
+ for (src = str, dest = newstr; *src != '\0'; src++) {
+ /*
+ * This switch will look at a character in *src, and decide
+ * what should be copied to *dest. It only decides what
+ * character(s) to copy, it should not modify *dest. In some
+ * cases, it will look at multiple characters from *src.
+ */
+ copychar = found_sep = 0;
+ copystr = NULL;
+ switch (*src) {
+ case '"':
+ if (in_sq)
+ copychar = *src;
+ else if (in_dq)
+ in_dq = 0;
+ else {
+ /*
+ * Referencing nullarg ensures that a new
+ * argument is created, even if this quoted
+ * string ends up with zero characters.
+ */
+ copystr = nullarg;
+ in_dq = 1;
+ bq_destlen = dest - *(nextarg - 1);
+ bq_src = src;
+ }
+ break;
+ case '$':
+ if (in_sq)
+ copychar = *src;
+ else {
+ copystr = expand_vars(in_arg, (nextarg - 1),
+ &dest, &src);
+ }
+ break;
+ case '\'':
+ if (in_dq)
+ copychar = *src;
+ else if (in_sq)
+ in_sq = 0;
+ else {
+ /*
+ * Referencing nullarg ensures that a new
+ * argument is created, even if this quoted
+ * string ends up with zero characters.
+ */
+ copystr = nullarg;
+ in_sq = 1;
+ bq_destlen = dest - *(nextarg - 1);
+ bq_src = src;
+ }
+ break;
+ case '\\':
+ if (in_sq) {
+ /*
+ * Inside single-quoted strings, only the
+ * "\'" and "\\" are recognized as special
+ * strings.
+ */
+ copychar = *(src + 1);
+ if (copychar == '\'' || copychar == '\\')
+ src++;
+ else
+ copychar = *src;
+ break;
+ }
+ src++;
+ switch (*src) {
+ case '"':
+ case '#':
+ case '$':
+ case '\'':
+ case '\\':
+ copychar = *src;
+ break;
+ case '_':
+ /*
+ * Alternate way to get a blank, which allows
+ * that blank be used to separate arguments
+ * when it is not inside a quoted string.
+ */
+ if (in_dq)
+ copychar = ' ';
+ else {
+ found_sep = 1;
+ src++;
+ }
+ break;
+ case 'c':
+ /*
+ * Ignore remaining characters in the -S string.
+ * This would not make sense if found in the
+ * middle of a quoted string.
+ */
+ if (in_dq)
+ errx(1, "Sequence '\\%c' is not allowed"
+ " in quoted strings", *src);
+ goto str_done;
+ case 'f':
+ copychar = '\f';
+ break;
+ case 'n':
+ copychar = '\n';
+ break;
+ case 'r':
+ copychar = '\r';
+ break;
+ case 't':
+ copychar = '\t';
+ break;
+ case 'v':
+ copychar = '\v';
+ break;
+ default:
+ if (isspacech(*src))
+ copychar = *src;
+ else
+ errx(1, "Invalid sequence '\\%c' in -S",
+ *src);
+ }
+ break;
+ default:
+ if ((in_dq || in_sq) && in_arg)
+ copychar = *src;
+ else if (isspacech(*src))
+ found_sep = 1;
+ else {
+ /*
+ * If the first character of a new argument
+ * is `#', then ignore the remaining chars.
+ */
+ if (!in_arg && *src == '#')
+ goto str_done;
+ copychar = *src;
+ }
+ }
+ /*
+ * Now that the switch has determined what (if anything)
+ * needs to be copied, copy whatever that is to *dest.
+ */
+ if (copychar || copystr != NULL) {
+ if (!in_arg) {
+ /* This is the first byte of a new argument */
+ *nextarg++ = dest;
+ addcount++;
+ in_arg = 1;
+ }
+ if (copychar)
+ *dest++ = (char)copychar;
+ else if (copystr != NULL)
+ while (*copystr != '\0')
+ *dest++ = *copystr++;
+ } else if (found_sep) {
+ *dest++ = '\0';
+ while (isspacech(*src))
+ src++;
+ --src;
+ in_arg = 0;
+ }
+ }
+str_done:
+ *dest = '\0';
+ *nextarg = NULL;
+ if (in_dq || in_sq) {
+ errx(1, "No terminating quote for string: %.*s%s",
+ bq_destlen, *(nextarg - 1), bq_src);
+ }
+ if (env_verbosity > 1) {
+ fprintf(stderr, "#env split -S:\t'%s'\n", str);
+ oldarg = newargv + 1;
+ fprintf(stderr, "#env into:\t'%s'\n", *oldarg);
+ for (oldarg++; *oldarg; oldarg++)
+ fprintf(stderr, "#env &\t'%s'\n", *oldarg);
+ }
+
+ /* Copy the unprocessed arg-pointers from the original array */
+ for (oldarg = *origv + *origind; *oldarg; oldarg++)
+ *nextarg++ = *oldarg;
+ *nextarg = NULL;
+
+ /* Update optind/argc/argv in the calling routine */
+ *origind = 1;
+ *origc += addcount;
+ *origv = newargv;
+}
+
+/**
+ * Routine to split expand any environment variables referenced in the string
+ * that -S is processing. For now it only supports the form ${VARNAME}. It
+ * explicitly does not support $VARNAME, and obviously can not handle special
+ * shell-variables such as $?, $*, $1, etc. It is called with *src_p pointing
+ * at the initial '$', and if successful it will update *src_p, *dest_p, and
+ * possibly *thisarg_p in the calling routine.
+ */
+static const char *
+expand_vars(int in_thisarg, char **thisarg_p, char **dest_p, const char **src_p)
+{
+ const char *vbegin, *vend, *vvalue;
+ char *newstr, *vname;
+ int bad_reference;
+ size_t namelen, newlen;
+
+ bad_reference = 1;
+ vbegin = vend = (*src_p) + 1;
+ if (*vbegin++ == '{')
+ if (*vbegin == '_' || isalphach(*vbegin)) {
+ vend = vbegin + 1;
+ while (*vend == '_' || isalnumch(*vend))
+ vend++;
+ if (*vend == '}')
+ bad_reference = 0;
+ }
+ if (bad_reference)
+ errx(1, "Only ${VARNAME} expansion is supported, error at: %s",
+ *src_p);
+
+ /*
+ * We now know we have a valid environment variable name, so update
+ * the caller's source-pointer to the last character in that reference,
+ * and then pick up the matching value. If the variable is not found,
+ * or if it has a null value, then our work here is done.
+ */
+ *src_p = vend;
+ namelen = vend - vbegin + 1;
+ vname = malloc(namelen);
+ strlcpy(vname, vbegin, namelen);
+ vvalue = getenv(vname);
+ if (vvalue == NULL || *vvalue == '\0') {
+ if (env_verbosity > 2)
+ fprintf(stderr,
+ "#env replacing ${%s} with null string\n",
+ vname);
+ free(vname);
+ return (NULL);
+ }
+
+ if (env_verbosity > 2)
+ fprintf(stderr, "#env expanding ${%s} into '%s'\n", vname,
+ vvalue);
+
+ /*
+ * There is some value to copy to the destination. If the value is
+ * shorter than the ${VARNAME} reference that it replaces, then our
+ * caller can just copy the value to the existing destination.
+ */
+ if (strlen(vname) + 3 >= strlen(vvalue)) {
+ free(vname);
+ return (vvalue);
+ }
+
+ /*
+ * The value is longer than the string it replaces, which means the
+ * present destination area is too small to hold it. Create a new
+ * destination area, and update the caller's 'dest' variable to match.
+ * If the caller has already started copying some info for 'thisarg'
+ * into the present destination, then the new destination area must
+ * include a copy of that data, and the pointer to 'thisarg' must also
+ * be updated. Note that it is still the caller which copies this
+ * vvalue to the new *dest.
+ */
+ newlen = strlen(vvalue) + strlen(*src_p) + 1;
+ if (in_thisarg) {
+ **dest_p = '\0'; /* Provide terminator for 'thisarg' */
+ newlen += strlen(*thisarg_p);
+ newstr = malloc(newlen);
+ strcpy(newstr, *thisarg_p);
+ *thisarg_p = newstr;
+ } else {
+ newstr = malloc(newlen);
+ *newstr = '\0';
+ }
+ *dest_p = strchr(newstr, '\0');
+ free(vname);
+ return (vvalue);
+}
diff --git a/shell_cmds/env/envopts.h b/shell_cmds/env/envopts.h
new file mode 100644
index 0000000..1f15c69
--- /dev/null
+++ b/shell_cmds/env/envopts.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2005 - Garance Alistair Drosehn <gad@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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the FreeBSD Project.
+ *
+ * $FreeBSD$
+ */
+
+void search_paths(char *path, char **argv);
+void split_spaces(const char *str, int *origind, int *origc,
+ char ***origv);
+
+extern int env_verbosity;
diff --git a/shell_cmds/expr/expr.1 b/shell_cmds/expr/expr.1
new file mode 100644
index 0000000..9c8090c
--- /dev/null
+++ b/shell_cmds/expr/expr.1
@@ -0,0 +1,235 @@
+.\" -*- nroff -*-
+.\"-
+.\" Copyright (c) 1993 Winning Strategies, 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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Winning Strategies, Inc.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" 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.
+.\"
+.\" $FreeBSD: src/bin/expr/expr.1,v 1.31 2011/07/09 12:05:53 se Exp $
+.\"
+.Dd September 9, 2010
+.Dt EXPR 1
+.Os
+.Sh NAME
+.Nm expr
+.Nd evaluate expression
+.Sh SYNOPSIS
+.Nm
+.Ar expression
+.Sh DESCRIPTION
+The
+.Nm
+utility evaluates
+.Ar expression
+and writes the result on standard output.
+.Pp
+All operators and operands must be passed as separate arguments.
+Several of the operators have special meaning to command interpreters
+and must therefore be quoted appropriately.
+All integer operands are interpreted in base 10 and must consist of only
+an optional leading minus sign followed by one or more digits.
+.Pp
+Arithmetic operations are performed using signed integer math with a
+range according to the C
+.Vt intmax_t
+data type (the largest signed integral type available).
+All conversions and operations are checked for overflow.
+Overflow results in program termination with an error message on stdout
+and with an error status.
+.Pp
+Operators are listed below in order of increasing precedence; all
+are left-associative.
+Operators with equal precedence are grouped within symbols
+.Ql {
+and
+.Ql } .
+.Bl -tag -width indent
+.It Ar expr1 Li | Ar expr2
+Return the evaluation of
+.Ar expr1
+if it is neither an empty string nor zero;
+otherwise, returns the evaluation of
+.Ar expr2
+if it is not an empty string;
+otherwise, returns zero.
+.It Ar expr1 Li & Ar expr2
+Return the evaluation of
+.Ar expr1
+if neither expression evaluates to an empty string or zero;
+otherwise, returns zero.
+.It Ar expr1 Li "{=, >, >=, <, <=, !=}" Ar expr2
+Return the results of integer comparison if both arguments are integers;
+otherwise, returns the results of string comparison using the locale-specific
+collation sequence.
+The result of each comparison is 1 if the specified relation is true,
+or 0 if the relation is false.
+.It Ar expr1 Li "{+, -}" Ar expr2
+Return the results of addition or subtraction of integer-valued arguments.
+.It Ar expr1 Li "{*, /, %}" Ar expr2
+Return the results of multiplication, integer division, or remainder of integer-valued arguments.
+.It Ar expr1 Li : Ar expr2
+The
+.Dq Li \&:
+operator matches
+.Ar expr1
+against
+.Ar expr2 ,
+which must be a basic regular expression.
+The regular expression is anchored
+to the beginning of the string with an implicit
+.Dq Li ^ .
+.Pp
+If the match succeeds and the pattern contains at least one regular
+expression subexpression
+.Dq Li "\e(...\e)" ,
+the string corresponding to
+.Dq Li \e1
+is returned;
+otherwise the matching operator returns the number of characters matched.
+If the match fails and the pattern contains a regular expression subexpression
+the null string is returned;
+otherwise 0.
+.El
+.Pp
+Parentheses are used for grouping in the usual manner.
+.Pp
+The
+.Nm
+utility makes no lexical distinction between arguments which may be
+operators and arguments which may be operands.
+An operand which is lexically identical to an operator will be considered a
+syntax error.
+See the examples below for a work-around.
+.Pp
+The syntax of the
+.Nm
+command in general is historic and inconvenient.
+New applications are advised to use shell arithmetic rather than
+.Nm .
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width indent -compact
+.It 0
+the expression is neither an empty string nor 0.
+.It 1
+the expression is an empty string or 0.
+.It 2
+the expression is invalid.
+.El
+.Sh EXAMPLES
+.Bl -bullet
+.It
+The following example (in
+.Xr sh 1
+syntax) adds one to the variable
+.Va a :
+.Dl "a=$(expr $a + 1)"
+.It
+This will fail if the value of
+.Va a
+is a negative number.
+To protect negative values of
+.Va a
+from being interpreted as options to the
+.Nm
+command, one might rearrange the expression:
+.Dl "a=$(expr 1 + $a)"
+.It
+More generally, parenthesize possibly-negative values:
+.Dl "a=$(expr \e( $a \e) + 1)"
+.It
+With shell arithmetic, no escaping is required:
+.Dl "a=$((a + 1))"
+.It
+This example prints the filename portion of a pathname stored
+in variable
+.Va a .
+Since
+.Va a
+might represent the path
+.Pa / ,
+it is necessary to prevent it from being interpreted as the division operator.
+The
+.Li //
+characters resolve this ambiguity.
+.Dl "expr \*q//$a\*q \&: '.*/\e(.*\e)'"
+.It
+With modern
+.Xr sh 1
+syntax,
+.Dl "\*q${a##*/}\*q"
+expands to the same value.
+.El
+.Pp
+The following examples output the number of characters in variable
+.Va a .
+Again, if
+.Va a
+might begin with a hyphen, it is necessary to prevent it from being
+interpreted as an option to
+.Nm ,
+and
+.Va a
+might be interpreted as an operator.
+.Bl -bullet
+.It
+To deal with all of this, a complicated command
+is required:
+.Dl "expr \e( \*qX$a\*q \&: \*q.*\*q \e) - 1"
+.It
+With modern
+.Xr sh 1
+syntax, this can be done much more easily:
+.Dl "${#a}"
+expands to the required number.
+.El
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr test 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2008 .
+.Pp
+The extended arithmetic range and overflow checks do not conflict with
+POSIX's requirement that arithmetic be done using signed longs, since
+they only make a difference to the result in cases where using signed
+longs would give undefined behavior.
+.Pp
+According to the
+.Tn POSIX
+standard, the use of string arguments
+.Va length ,
+.Va substr ,
+.Va index ,
+or
+.Va match
+produces undefined results. In this version of
+.Nm ,
+these arguments are treated just as their respective string values.
diff --git a/shell_cmds/expr/expr.y b/shell_cmds/expr/expr.y
new file mode 100644
index 0000000..1aa9474
--- /dev/null
+++ b/shell_cmds/expr/expr.y
@@ -0,0 +1,571 @@
+%{
+/*-
+ * Written by Pace Willisson (pace@blitz.com)
+ * and placed in the public domain.
+ *
+ * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
+ *
+ * $FreeBSD: src/bin/expr/expr.y,v 1.28 2011/07/09 12:20:15 se Exp $
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+#include <unistd.h>
+
+/*
+ * POSIX specifies a specific error code for syntax errors. We exit
+ * with this code for all errors.
+ */
+#define ERR_EXIT 2
+
+enum valtype {
+ integer, numeric_string, string
+} ;
+
+struct val {
+ enum valtype type;
+ union {
+ char *s;
+ intmax_t i;
+ } u;
+} ;
+
+char **av;
+int nonposix;
+struct val *result;
+
+void assert_to_integer(struct val *);
+void assert_div(intmax_t, intmax_t);
+void assert_minus(intmax_t, intmax_t, intmax_t);
+void assert_plus(intmax_t, intmax_t, intmax_t);
+void assert_times(intmax_t, intmax_t, intmax_t);
+int compare_vals(struct val *, struct val *);
+void free_value(struct val *);
+int is_integer(const char *);
+int is_string(struct val *);
+int is_zero_or_null(struct val *);
+struct val *make_integer(intmax_t);
+struct val *make_str(const char *);
+struct val *op_and(struct val *, struct val *);
+struct val *op_colon(struct val *, struct val *);
+struct val *op_div(struct val *, struct val *);
+struct val *op_eq(struct val *, struct val *);
+struct val *op_ge(struct val *, struct val *);
+struct val *op_gt(struct val *, struct val *);
+struct val *op_le(struct val *, struct val *);
+struct val *op_lt(struct val *, struct val *);
+struct val *op_minus(struct val *, struct val *);
+struct val *op_ne(struct val *, struct val *);
+struct val *op_or(struct val *, struct val *);
+struct val *op_plus(struct val *, struct val *);
+struct val *op_rem(struct val *, struct val *);
+struct val *op_times(struct val *, struct val *);
+int to_integer(struct val *);
+void to_string(struct val *);
+int yyerror(const char *);
+int yylex(void);
+int yyparse(void);
+
+%}
+
+%union
+{
+ struct val *val;
+}
+
+%left <val> '|'
+%left <val> '&'
+%left <val> '=' '>' '<' GE LE NE
+%left <val> '+' '-'
+%left <val> '*' '/' '%'
+%left <val> ':'
+
+%token <val> TOKEN
+%type <val> start expr
+
+%%
+
+start: expr { result = $$; }
+
+expr: TOKEN
+ | '(' expr ')' { $$ = $2; }
+ | expr '|' expr { $$ = op_or($1, $3); }
+ | expr '&' expr { $$ = op_and($1, $3); }
+ | expr '=' expr { $$ = op_eq($1, $3); }
+ | expr '>' expr { $$ = op_gt($1, $3); }
+ | expr '<' expr { $$ = op_lt($1, $3); }
+ | expr GE expr { $$ = op_ge($1, $3); }
+ | expr LE expr { $$ = op_le($1, $3); }
+ | expr NE expr { $$ = op_ne($1, $3); }
+ | expr '+' expr { $$ = op_plus($1, $3); }
+ | expr '-' expr { $$ = op_minus($1, $3); }
+ | expr '*' expr { $$ = op_times($1, $3); }
+ | expr '/' expr { $$ = op_div($1, $3); }
+ | expr '%' expr { $$ = op_rem($1, $3); }
+ | expr ':' expr { $$ = op_colon($1, $3); }
+ ;
+
+%%
+
+struct val *
+make_integer(intmax_t i)
+{
+ struct val *vp;
+
+ vp = (struct val *)malloc(sizeof(*vp));
+ if (vp == NULL)
+ errx(ERR_EXIT, "malloc() failed");
+
+ vp->type = integer;
+ vp->u.i = i;
+ return (vp);
+}
+
+struct val *
+make_str(const char *s)
+{
+ struct val *vp;
+
+ vp = (struct val *)malloc(sizeof(*vp));
+ if (vp == NULL || ((vp->u.s = strdup(s)) == NULL))
+ errx(ERR_EXIT, "malloc() failed");
+
+ if (is_integer(s))
+ vp->type = numeric_string;
+ else
+ vp->type = string;
+
+ return (vp);
+}
+
+void
+free_value(struct val *vp)
+{
+ if (vp->type == string || vp->type == numeric_string)
+ free(vp->u.s);
+}
+
+int
+to_integer(struct val *vp)
+{
+ intmax_t i;
+
+ /* we can only convert numeric_string to integer, here */
+ if (vp->type == numeric_string) {
+ errno = 0;
+ i = strtoimax(vp->u.s, (char **)NULL, 10);
+ /* just keep as numeric_string, if the conversion fails */
+ if (errno != ERANGE) {
+ free(vp->u.s);
+ vp->u.i = i;
+ vp->type = integer;
+ }
+ }
+ return (vp->type == integer);
+}
+
+void
+assert_to_integer(struct val *vp)
+{
+ if (vp->type == string)
+ errx(ERR_EXIT, "not a decimal number: '%s'", vp->u.s);
+ if (!to_integer(vp))
+ errx(ERR_EXIT, "operand too large: '%s'", vp->u.s);
+}
+
+void
+to_string(struct val *vp)
+{
+ char *tmp;
+
+ if (vp->type == string || vp->type == numeric_string)
+ return;
+
+ /*
+ * log_10(x) ~= 0.3 * log_2(x). Rounding up gives the number
+ * of digits; add one each for the sign and terminating null
+ * character, respectively.
+ */
+#define NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1)
+ tmp = malloc(NDIGITS(vp->u.i));
+ if (tmp == NULL)
+ errx(ERR_EXIT, "malloc() failed");
+
+ sprintf(tmp, "%jd", vp->u.i);
+ vp->type = string;
+ vp->u.s = tmp;
+}
+
+int
+is_integer(const char *s)
+{
+ if (nonposix) {
+ if (*s == '\0')
+ return (1);
+ while (isspace((unsigned char)*s))
+ s++;
+ }
+ if (*s == '-' || (nonposix && *s == '+'))
+ s++;
+ if (*s == '\0')
+ return (0);
+ while (isdigit((unsigned char)*s))
+ s++;
+ return (*s == '\0');
+}
+
+int
+is_string(struct val *vp)
+{
+ /* only TRUE if this string is not a valid integer */
+ return (vp->type == string);
+}
+
+int
+yylex(void)
+{
+ char *p;
+
+ if (*av == NULL)
+ return (0);
+
+ p = *av++;
+
+ if (strlen(p) == 1) {
+ if (strchr("|&=<>+-*/%:()", *p))
+ return (*p);
+ } else if (strlen(p) == 2 && p[1] == '=') {
+ switch (*p) {
+ case '>': return (GE);
+ case '<': return (LE);
+ case '!': return (NE);
+ }
+ }
+
+ yylval.val = make_str(p);
+ return (TOKEN);
+}
+
+int
+is_zero_or_null(struct val *vp)
+{
+ if (vp->type == integer)
+ return (vp->u.i == 0);
+
+ return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0));
+}
+
+int
+main(int argc, char *argv[])
+{
+#ifndef __APPLE__
+ int c;
+#endif
+
+ setlocale(LC_ALL, "");
+#ifdef __APPLE__
+ av = argv + 1;
+ if (*av && !strcmp(*av, "--"))
+ av++;
+#else
+ if (getenv("EXPR_COMPAT") != NULL
+ || check_utility_compat("expr")) {
+ av = argv + 1;
+ nonposix = 1;
+ } else {
+ while ((c = getopt(argc, argv, "e")) != -1) {
+ switch (c) {
+ case 'e':
+ nonposix = 1;
+ break;
+ default:
+ errx(ERR_EXIT,
+ "usage: expr [-e] expression\n");
+ }
+ }
+ av = argv + optind;
+ }
+#endif
+
+ yyparse();
+
+#ifdef __APPLE__
+ if (to_integer(result))
+#else
+ if (result->type == integer)
+#endif
+ printf("%jd\n", result->u.i);
+ else
+ printf("%s\n", result->u.s);
+
+ return (is_zero_or_null(result));
+}
+
+int
+yyerror(const char *s __unused)
+{
+ errx(ERR_EXIT, "syntax error");
+}
+
+struct val *
+op_or(struct val *a, struct val *b)
+{
+ if (!is_zero_or_null(a)) {
+ free_value(b);
+ return (a);
+ }
+ free_value(a);
+ if (!is_zero_or_null(b))
+ return (b);
+ free_value(b);
+ return (make_integer((intmax_t)0));
+}
+
+struct val *
+op_and(struct val *a, struct val *b)
+{
+ if (is_zero_or_null(a) || is_zero_or_null(b)) {
+ free_value(a);
+ free_value(b);
+ return (make_integer((intmax_t)0));
+ } else {
+ free_value(b);
+ return (a);
+ }
+}
+
+int
+compare_vals(struct val *a, struct val *b)
+{
+ int r;
+
+ if (is_string(a) || is_string(b)) {
+ to_string(a);
+ to_string(b);
+ r = strcoll(a->u.s, b->u.s);
+ } else {
+ assert_to_integer(a);
+ assert_to_integer(b);
+ if (a->u.i > b->u.i)
+ r = 1;
+ else if (a->u.i < b->u.i)
+ r = -1;
+ else
+ r = 0;
+ }
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+struct val *
+op_eq(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) == 0)));
+}
+
+struct val *
+op_gt(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) > 0)));
+}
+
+struct val *
+op_lt(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) < 0)));
+}
+
+struct val *
+op_ge(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) >= 0)));
+}
+
+struct val *
+op_le(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) <= 0)));
+}
+
+struct val *
+op_ne(struct val *a, struct val *b)
+{
+ return (make_integer((intmax_t)(compare_vals(a, b) != 0)));
+}
+
+void
+assert_plus(intmax_t a, intmax_t b, intmax_t r)
+{
+ /*
+ * sum of two positive numbers must be positive,
+ * sum of two negative numbers must be negative
+ */
+ if ((a > 0 && b > 0 && r <= 0) ||
+ (a < 0 && b < 0 && r >= 0))
+ errx(ERR_EXIT, "overflow");
+}
+
+struct val *
+op_plus(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ r = make_integer(a->u.i + b->u.i);
+ assert_plus(a->u.i, b->u.i, r->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+void
+assert_minus(intmax_t a, intmax_t b, intmax_t r)
+{
+ /* special case subtraction of INTMAX_MIN */
+ if (b == INTMAX_MIN && a < 0)
+ errx(ERR_EXIT, "overflow");
+ /* check addition of negative subtrahend */
+ assert_plus(a, -b, r);
+}
+
+struct val *
+op_minus(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ r = make_integer(a->u.i - b->u.i);
+ assert_minus(a->u.i, b->u.i, r->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+void
+assert_times(intmax_t a, intmax_t b, intmax_t r)
+{
+ /*
+ * if first operand is 0, no overflow is possible,
+ * else result of division test must match second operand
+ */
+ if (a != 0 && r / a != b)
+ errx(ERR_EXIT, "overflow");
+}
+
+struct val *
+op_times(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ r = make_integer(a->u.i * b->u.i);
+ assert_times(a->u.i, b->u.i, r->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+void
+assert_div(intmax_t a, intmax_t b)
+{
+ if (b == 0)
+ errx(ERR_EXIT, "division by zero");
+ /* only INTMAX_MIN / -1 causes overflow */
+ if (a == INTMAX_MIN && b == -1)
+ errx(ERR_EXIT, "overflow");
+}
+
+struct val *
+op_div(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ /* assert based on operands only, not on result */
+ assert_div(a->u.i, b->u.i);
+ r = make_integer(a->u.i / b->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+struct val *
+op_rem(struct val *a, struct val *b)
+{
+ struct val *r;
+
+ assert_to_integer(a);
+ assert_to_integer(b);
+ /* pass a=1 to only check for div by zero */
+ assert_div(1, b->u.i);
+ r = make_integer(a->u.i % b->u.i);
+
+ free_value(a);
+ free_value(b);
+ return (r);
+}
+
+struct val *
+op_colon(struct val *a, struct val *b)
+{
+ regex_t rp;
+ regmatch_t rm[2];
+ char errbuf[256];
+ int eval;
+ struct val *v;
+
+ /* coerce both arguments to strings */
+ to_string(a);
+ to_string(b);
+
+ /* compile regular expression */
+ if ((eval = regcomp(&rp, b->u.s, 0)) != 0) {
+ regerror(eval, &rp, errbuf, sizeof(errbuf));
+ errx(ERR_EXIT, "%s", errbuf);
+ }
+
+ /* compare string against pattern */
+ /* remember that patterns are anchored to the beginning of the line */
+ if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0)
+ if (rm[1].rm_so >= 0) {
+ *(a->u.s + rm[1].rm_eo) = '\0';
+ v = make_str(a->u.s + rm[1].rm_so);
+#ifdef __APPLE__
+ v->type = string; /* 8319378 */
+#endif
+
+ } else
+ v = make_integer((intmax_t)(rm[0].rm_eo - rm[0].rm_so));
+ else
+ if (rp.re_nsub == 0)
+ v = make_integer((intmax_t)0);
+ else
+ v = make_str("");
+
+ /* free arguments and pattern buffer */
+ free_value(a);
+ free_value(b);
+ regfree(&rp);
+
+ return (v);
+}
diff --git a/shell_cmds/false/false.1 b/shell_cmds/false/false.1
new file mode 100644
index 0000000..f7b07eb
--- /dev/null
+++ b/shell_cmds/false/false.1
@@ -0,0 +1,60 @@
+.\" $NetBSD: false.1,v 1.5 1997/10/18 14:46:54 lukem Exp $
+.\"
+.\" Copyright (c) 1983, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)false.1 6.6 (Berkeley) 7/24/91
+.\" $NetBSD: false.1,v 1.5 1997/10/18 14:46:54 lukem Exp $
+.\"
+.Dd July 24, 1991
+.Dt FALSE 1
+.Os BSD 4.2
+.Sh NAME
+.Nm false
+.Nd Return false value.
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility always exits with a nonzero exit code.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr true 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
diff --git a/shell_cmds/false/false.c b/shell_cmds/false/false.c
new file mode 100644
index 0000000..3883d89
--- /dev/null
+++ b/shell_cmds/false/false.c
@@ -0,0 +1,2 @@
+#include <stdlib.h>
+int main () { exit(1); }
diff --git a/shell_cmds/false/false.sh b/shell_cmds/false/false.sh
new file mode 100644
index 0000000..2526efb
--- /dev/null
+++ b/shell_cmds/false/false.sh
@@ -0,0 +1,2 @@
+#! /bin/sh
+exit 1
diff --git a/shell_cmds/find/extern.h b/shell_cmds/find/extern.h
new file mode 100644
index 0000000..f4282f7
--- /dev/null
+++ b/shell_cmds/find/extern.h
@@ -0,0 +1,124 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.3 (Berkeley) 4/16/94
+ * $FreeBSD: src/usr.bin/find/extern.h,v 1.26 2010/12/11 08:32:16 joel Exp $
+ */
+
+#include <sys/cdefs.h>
+
+void brace_subst(char *, char **, char *, int);
+PLAN *find_create(char ***);
+int find_execute(PLAN *, char **);
+PLAN *find_formplan(char **);
+PLAN *not_squish(PLAN *);
+PLAN *or_squish(PLAN *);
+PLAN *paren_squish(PLAN *);
+time_t get_date(char *);
+struct stat;
+void printlong(char *, char *, struct stat *);
+int queryuser(char **);
+OPTION *lookup_option(const char *);
+void finish_execplus(void);
+
+creat_f c_Xmin;
+creat_f c_Xtime;
+creat_f c_acl;
+creat_f c_and;
+creat_f c_delete;
+creat_f c_depth;
+creat_f c_empty;
+creat_f c_exec;
+creat_f c_flags;
+creat_f c_follow;
+creat_f c_fstype;
+creat_f c_group;
+creat_f c_inum;
+creat_f c_links;
+creat_f c_ls;
+creat_f c_mXXdepth;
+creat_f c_name;
+creat_f c_newer;
+creat_f c_nogroup;
+creat_f c_nouser;
+creat_f c_perm;
+creat_f c_print;
+creat_f c_regex;
+creat_f c_samefile;
+creat_f c_simple;
+creat_f c_size;
+creat_f c_type;
+creat_f c_user;
+creat_f c_xdev;
+
+exec_f f_Xmin;
+exec_f f_Xtime;
+exec_f f_acl;
+exec_f f_always_true;
+exec_f f_closeparen;
+exec_f f_delete;
+exec_f f_depth;
+exec_f f_empty;
+exec_f f_exec;
+exec_f f_expr;
+exec_f f_false;
+exec_f f_flags;
+exec_f f_fstype;
+exec_f f_group;
+exec_f f_inum;
+exec_f f_links;
+exec_f f_ls;
+exec_f f_name;
+exec_f f_newer;
+exec_f f_nogroup;
+exec_f f_not;
+exec_f f_nouser;
+exec_f f_openparen;
+exec_f f_or;
+exec_f f_path;
+exec_f f_perm;
+exec_f f_print;
+exec_f f_print0;
+exec_f f_prune;
+exec_f f_quit;
+exec_f f_regex;
+exec_f f_size;
+exec_f f_type;
+exec_f f_user;
+#ifdef __APPLE__
+exec_f f_xattr;
+exec_f f_xattrname;
+#endif /* __APPLE__ */
+
+extern int ftsoptions, isdeprecated, isdepth, isoutput, issort, isxargs;
+extern int mindepth, maxdepth;
+extern int regexp_flags;
+extern time_t now;
+extern int dotfd;
+extern FTS *tree;
+extern int execplus_error;
diff --git a/shell_cmds/find/find.1 b/shell_cmds/find/find.1
new file mode 100644
index 0000000..c6bb28f
--- /dev/null
+++ b/shell_cmds/find/find.1
@@ -0,0 +1,1078 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)find.1 8.7 (Berkeley) 5/9/95
+.\" $FreeBSD: src/usr.bin/find/find.1,v 1.91 2011/09/28 18:53:36 ed Exp $
+.\"
+.Dd September 28, 2011
+.Dt FIND 1
+.Os
+.Sh NAME
+.Nm find
+.Nd walk a file hierarchy
+.Sh SYNOPSIS
+.Nm
+.Op Fl H | Fl L | Fl P
+.Op Fl EXdsx
+.Op Fl f Ar path
+.Ar path ...
+.Op Ar expression
+.Nm
+.Op Fl H | Fl L | Fl P
+.Op Fl EXdsx
+.Fl f Ar path
+.Op Ar path ...
+.Op Ar expression
+.Sh DESCRIPTION
+The
+.Nm
+utility recursively descends the directory tree for each
+.Ar path
+listed, evaluating an
+.Ar expression
+(composed of the
+.Dq primaries
+and
+.Dq operands
+listed below) in terms
+of each file in the tree.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl E
+Interpret regular expressions followed by
+.Ic -regex
+and
+.Ic -iregex
+primaries as extended (modern) regular expressions rather than basic
+regular expressions (BRE's).
+The
+.Xr re_format 7
+manual page fully describes both formats.
+.It Fl H
+Cause the file information and file type (see
+.Xr stat 2 )
+returned for each symbolic link specified on the command line to be
+those of the file referenced by the link, not the link itself.
+If the referenced file does not exist, the file information and type will
+be for the link itself.
+File information of all symbolic links not on
+the command line is that of the link itself.
+.It Fl L
+Cause the file information and file type (see
+.Xr stat 2 )
+returned for each symbolic link to be those of the file referenced by the
+link, not the link itself.
+If the referenced file does not exist, the file information and type will
+be for the link itself.
+.Pp
+This option is equivalent to the deprecated
+.Ic -follow
+primary.
+.It Fl P
+Cause the file information and file type (see
+.Xr stat 2 )
+returned for each symbolic link to be those of the link itself.
+This is the default.
+.It Fl X
+Permit
+.Nm
+to be safely used in conjunction with
+.Xr xargs 1 .
+If a file name contains any of the delimiting characters used by
+.Xr xargs 1 ,
+a diagnostic message is displayed on standard error, and the file
+is skipped.
+The delimiting characters include single
+.Pq Dq Li " ' "
+and double
+.Pq Dq Li " \*q "
+quotes, backslash
+.Pq Dq Li \e ,
+space, tab and newline characters.
+.Pp
+However, you may wish to consider the
+.Fl print0
+primary in conjunction with
+.Dq Nm xargs Fl 0
+as an effective alternative.
+.It Fl d
+Cause
+.Nm
+to perform a depth-first traversal, i.e., directories
+are visited in post-order and all entries in a directory will be acted
+on before the directory itself.
+By default,
+.Nm
+visits directories in pre-order, i.e., before their contents.
+Note, the default is
+.Em not
+a breadth-first traversal.
+.Pp
+This option is equivalent to the
+.Ic -depth
+primary of
+.St -p1003.1-2001 .
+The
+.Fl d
+option
+can be useful when
+.Nm
+is used with
+.Xr cpio 1
+to process files that are contained in directories with unusual permissions.
+It ensures that you have write permission while you are placing files in a
+directory, then sets the directory's permissions as the last thing.
+.It Fl f
+Specify a file hierarchy for
+.Nm
+to traverse.
+File hierarchies may also be specified as the operands immediately
+following the options.
+.It Fl s
+Cause
+.Nm
+to traverse the file hierarchies in lexicographical order,
+i.e., alphabetical order within each directory.
+Note:
+.Ql find -s
+and
+.Ql "find | sort"
+may give different results.
+.It Fl x
+Prevent
+.Nm
+from descending into directories that have a device number different
+than that of the file from which the descent began.
+.Pp
+This option is equivalent to the deprecated
+.Ic -xdev
+primary.
+.El
+.Sh PRIMARIES
+.Pp
+All primaries which take a numeric argument allow the number to be
+preceded by a plus sign
+.Pq Dq Li +
+or a minus sign
+.Pq Dq Li - .
+A preceding plus sign means
+.Dq more than n ,
+a preceding minus sign means
+.Dq less than n
+and neither means
+.Dq exactly n .
+.Bl -tag -width indent
+.It Ic -Bmin Ar n
+True if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -Bnewer Ar file
+Same as
+.Ic -newerBm .
+.It Ic -Btime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the time of a file's inode creation
+and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
+.It Ic -acl
+May be used in conjunction with other primaries to locate
+files with extended ACLs.
+See
+.Xr acl 3
+for more information.
+.It Ic -amin Ar n
+True if the difference between the file last access time and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -anewer Ar file
+Same as
+.Ic -neweram .
+.It Ic -atime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the file last access time and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the file last access time and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Possible time units are as follows:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm s
+second
+.It Cm m
+minute (60 seconds)
+.It Cm h
+hour (60 minutes)
+.It Cm d
+day (24 hours)
+.It Cm w
+week (7 days)
+.El
+.Pp
+Any number of units may be combined in one
+.Ic -atime
+argument, for example,
+.Dq Li "-atime -1h30m" .
+Units are probably only useful when used in conjunction with the
+.Cm +
+or
+.Cm -
+modifier.
+.It Ic -cmin Ar n
+True if the difference between the time of last change of file status
+information and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -cnewer Ar file
+Same as
+.Ic -newercm .
+.It Ic -ctime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the time of last change of file status
+information and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the time of last change of file status
+information and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
+.It Ic -d
+Same as
+.Ic depth .
+GNU find implements this as a primary in mistaken emulation of
+.Fx
+.Xr find 1 .
+.It Ic -delete
+Delete found files and/or directories.
+Always returns true.
+This executes
+from the current working directory as
+.Nm
+recurses down the tree.
+It will not attempt to delete a filename with a
+.Dq Pa /
+character in its pathname relative to
+.Dq Pa \&.
+for security reasons.
+Depth-first traversal processing is implied by this option.
+Following symlinks is incompatible with this option.
+.It Ic -depth
+Always true;
+same as the
+.Fl d
+option.
+.It Ic -depth Ar n
+True if the depth of the file relative to the starting point of the traversal
+is
+.Ar n .
+.It Ic -empty
+True if the current file or directory is empty.
+.It Ic -exec Ar utility Oo Ar argument ... Oc Li \&;
+True if the program named
+.Ar utility
+returns a zero value as its exit status.
+Optional
+.Ar arguments
+may be passed to the utility.
+The expression must be terminated by a semicolon
+.Pq Dq Li \&; .
+If you invoke
+.Nm
+from a shell you may need to quote the semicolon if the shell would
+otherwise treat it as a control operator.
+If the string
+.Dq Li {}
+appears anywhere in the utility name or the
+arguments it is replaced by the pathname of the current file.
+.Ar Utility
+will be executed from the directory from which
+.Nm
+was executed.
+.Ar Utility
+and
+.Ar arguments
+are not subject to the further expansion of shell patterns
+and constructs.
+.It Ic -exec Ar utility Oo Ar argument ... Oc Li {} +
+Same as
+.Ic -exec ,
+except that
+.Dq Li {}
+is replaced with as many pathnames as possible for each invocation of
+.Ar utility .
+This behaviour is similar to that of
+.Xr xargs 1 .
+.It Ic -execdir Ar utility Oo Ar argument ... Oc Li \&;
+The
+.Ic -execdir
+primary is identical to the
+.Ic -exec
+primary with the exception that
+.Ar utility
+will be executed from the directory that holds
+the current file.
+The filename substituted for
+the string
+.Dq Li {}
+is not qualified.
+.It Ic -execdir Ar utility Oo Ar argument ... Oc Li {} +
+Same as
+.Ic -execdir ,
+except that
+.Dq Li {}
+is replaced with as many pathnames as possible for each invocation of
+.Ar utility .
+This behaviour is similar to that of
+.Xr xargs 1 .
+.It Ic -flags Oo Cm - Ns | Ns Cm + Oc Ns Ar flags , Ns Ar notflags
+The flags are specified using symbolic names (see
+.Xr chflags 1 ) .
+Those with the
+.Qq Li no
+prefix (except
+.Qq Li nodump )
+are said to be
+.Ar notflags .
+Flags in
+.Ar flags
+are checked to be set, and flags in
+.Ar notflags
+are checked to be not set.
+Note that this is different from
+.Ic -perm ,
+which only allows the user to specify mode bits that are set.
+.Pp
+If flags are preceded by a dash
+.Pq Dq Li - ,
+this primary evaluates to true
+if at least all of the bits in
+.Ar flags
+and none of the bits in
+.Ar notflags
+are set in the file's flags bits.
+If flags are preceded by a plus
+.Pq Dq Li + ,
+this primary evaluates to true
+if any of the bits in
+.Ar flags
+is set in the file's flags bits,
+or any of the bits in
+.Ar notflags
+is not set in the file's flags bits.
+Otherwise,
+this primary evaluates to true
+if the bits in
+.Ar flags
+exactly match the file's flags bits,
+and none of the
+.Ar flags
+bits match those of
+.Ar notflags .
+.It Ic -fstype Ar type
+True if the file is contained in a file system of type
+.Ar type .
+The
+.Xr lsvfs 1
+command can be used to find out the types of file systems
+that are available on the system.
+In addition, there are two pseudo-types,
+.Dq Li local
+and
+.Dq Li rdonly .
+The former matches any file system physically mounted on the system where
+the
+.Nm
+is being executed and the latter matches any file system which is
+mounted read-only.
+.It Ic -gid Ar gname
+The same thing as
+.Ar -group Ar gname
+for compatibility with GNU find.
+GNU find imposes a restriction that
+.Ar gname
+is numeric, while
+.Xr find 1
+does not.
+.It Ic -group Ar gname
+True if the file belongs to the group
+.Ar gname .
+If
+.Ar gname
+is numeric and there is no such group name, then
+.Ar gname
+is treated as a group ID.
+.It Ic -ignore_readdir_race
+This option is for GNU find compatibility and is ignored.
+.It Ic -ilname Ar pattern
+Like
+.Ic -lname ,
+but the match is case insensitive.
+This is a GNU find extension.
+.It Ic -iname Ar pattern
+Like
+.Ic -name ,
+but the match is case insensitive.
+.It Ic -inum Ar n
+True if the file has inode number
+.Ar n .
+.It Ic -ipath Ar pattern
+Like
+.Ic -path ,
+but the match is case insensitive.
+.It Ic -iregex Ar pattern
+Like
+.Ic -regex ,
+but the match is case insensitive.
+.It Ic -iwholename Ar pattern
+The same thing as
+.Ic -ipath ,
+for GNU find compatibility.
+.It Ic -links Ar n
+True if the file has
+.Ar n
+links.
+.It Ic -lname Ar pattern
+Like
+.Ic -name ,
+but the contents of the symbolic link are matched instead of the file
+name.
+Note that this only matches broken symbolic links
+if symbolic links are being followed.
+This is a GNU find extension.
+.It Ic -ls
+This primary always evaluates to true.
+The following information for the current file is written to standard output:
+its inode number, size in 512-byte blocks, file permissions, number of hard
+links, owner, group, size in bytes, last modification time, and pathname.
+If the file is a block or character special file, the device number
+will be displayed instead of the size in bytes.
+If the file is a symbolic link, the pathname of the linked-to file will be
+displayed preceded by
+.Dq Li -> .
+The format is identical to that produced by
+.Bk -words
+.Dq Nm ls Fl dgils .
+.Ek
+.It Ic -maxdepth Ar n
+Always true; descend at most
+.Ar n
+directory levels below the command line arguments.
+If any
+.Ic -maxdepth
+primary is specified, it applies to the entire expression even if it would
+not normally be evaluated.
+.Dq Ic -maxdepth Li 0
+limits the whole search to the command line arguments.
+.It Ic -mindepth Ar n
+Always true; do not apply any tests or actions at levels less than
+.Ar n .
+If any
+.Ic -mindepth
+primary is specified, it applies to the entire expression even if it would
+not normally be evaluated.
+.Dq Ic -mindepth Li 1
+processes all but the command line arguments.
+.It Ic -mmin Ar n
+True if the difference between the file last modification time and the time
+.Nm
+was started, rounded up to the next full minute, is
+.Ar n
+minutes.
+.It Ic -mnewer Ar file
+Same as
+.Ic -newer .
+.It Ic -mount
+The same thing as
+.Ic -xdev ,
+for GNU find compatibility.
+.It Ic -mtime Ar n Ns Op Cm smhdw
+If no units are specified, this primary evaluates to
+true if the difference between the file last modification time and the time
+.Nm
+was started, rounded up to the next full 24-hour period, is
+.Ar n
+24-hour periods.
+.Pp
+If units are specified, this primary evaluates to
+true if the difference between the file last modification time and the time
+.Nm
+was started is exactly
+.Ar n
+units.
+Please refer to the
+.Ic -atime
+primary description for information on supported time units.
+.It Ic -name Ar pattern
+True if the last component of the pathname being examined matches
+.Ar pattern .
+Special shell pattern matching characters
+.Dq ( Li \&[ ,
+.Dq Li \&] ,
+.Dq Li * ,
+and
+.Dq Li \&? )
+may be used as part of
+.Ar pattern .
+These characters may be matched explicitly by escaping them with a
+backslash
+.Pq Dq Li \e .
+.It Ic -newer Ar file
+True if the current file has a more recent last modification time than
+.Ar file .
+.It Ic -newer Ns Ar X Ns Ar Y Ar file
+True if the current file has a more recent last access time
+.Pq Ar X Ns = Ns Cm a ,
+inode creation time
+.Pq Ar X Ns = Ns Cm B ,
+change time
+.Pq Ar X Ns = Ns Cm c ,
+or modification time
+.Pq Ar X Ns = Ns Cm m
+than the last access time
+.Pq Ar Y Ns = Ns Cm a ,
+inode creation time
+.Pq Ar Y Ns = Ns Cm B ,
+change time
+.Pq Ar Y Ns = Ns Cm c ,
+or modification time
+.Pq Ar Y Ns = Ns Cm m
+of
+.Ar file .
+In addition, if
+.Ar Y Ns = Ns Cm t ,
+then
+.Ar file
+is instead interpreted as a direct date specification of the form
+understood by
+.Xr cvs 1 .
+Note that
+.Ic -newermm
+is equivalent to
+.Ic -newer .
+.It Ic -nogroup
+True if the file belongs to an unknown group.
+.It Ic -noignore_readdir_race
+This option is for GNU find compatibility and is ignored.
+.It Ic -noleaf
+This option is for GNU find compatibility.
+In GNU find it disables an optimization not relevant to
+.Xr find 1 ,
+so it is ignored.
+.It Ic -nouser
+True if the file belongs to an unknown user.
+.It Ic -ok Ar utility Oo Ar argument ... Oc Li \&;
+The
+.Ic -ok
+primary is identical to the
+.Ic -exec
+primary with the exception that
+.Nm
+requests user affirmation for the execution of the
+.Ar utility
+by printing
+a message to the terminal and reading a response.
+If the response is not affirmative
+.Ql ( y
+in the
+.Dq Li POSIX
+locale),
+the command is not executed and the
+value of the
+.Ic -ok
+expression is false.
+.It Ic -okdir Ar utility Oo Ar argument ... Oc Li \&;
+The
+.Ic -okdir
+primary is identical to the
+.Ic -execdir
+primary with the same exception as described for the
+.Ic -ok
+primary.
+.It Ic -path Ar pattern
+True if the pathname being examined matches
+.Ar pattern .
+Special shell pattern matching characters
+.Dq ( Li \&[ ,
+.Dq Li \&] ,
+.Dq Li * ,
+and
+.Dq Li \&? )
+may be used as part of
+.Ar pattern .
+These characters may be matched explicitly by escaping them with a
+backslash
+.Pq Dq Li \e .
+Slashes
+.Pq Dq Li /
+are treated as normal characters and do not have to be
+matched explicitly.
+.It Ic -perm Oo Cm - Ns | Ns Cm + Oc Ns Ar mode
+The
+.Ar mode
+may be either symbolic (see
+.Xr chmod 1 )
+or an octal number.
+If the
+.Ar mode
+is symbolic, a starting value of zero is assumed and the
+.Ar mode
+sets or clears permissions without regard to the process' file mode
+creation mask.
+If the
+.Ar mode
+is octal, only bits 07777
+.Pq Dv S_ISUID | S_ISGID | S_ISTXT | S_IRWXU | S_IRWXG | S_IRWXO
+of the file's mode bits participate
+in the comparison.
+If the
+.Ar mode
+is preceded by a dash
+.Pq Dq Li - ,
+this primary evaluates to true
+if at least all of the bits in the
+.Ar mode
+are set in the file's mode bits.
+If the
+.Ar mode
+is preceded by a plus
+.Pq Dq Li + ,
+this primary evaluates to true
+if any of the bits in the
+.Ar mode
+are set in the file's mode bits.
+Otherwise, this primary evaluates to true if
+the bits in the
+.Ar mode
+exactly match the file's mode bits.
+Note, the first character of a symbolic mode may not be a dash
+.Pq Dq Li - .
+.It Ic -print
+This primary always evaluates to true.
+It prints the pathname of the current file to standard output.
+If none of
+.\" 4772561
+.Ic -exec , -ls , -print , -print0 ,
+or
+.Ic -ok
+is specified, the given expression shall be effectively replaced by
+.Cm \&( Ar "given expression" Cm \&) Ic -print .
+.It Ic -print0
+This primary always evaluates to true.
+It prints the pathname of the current file to standard output, followed by an
+.Tn ASCII
+.Dv NUL
+character (character code 0).
+.It Ic -prune
+This primary always evaluates to true.
+It causes
+.Nm
+to not descend into the current file.
+Note, the
+.Ic -prune
+primary has no effect if the
+.Fl d
+option was specified.
+.It Ic -regex Ar pattern
+True if the whole path of the file matches
+.Ar pattern
+using regular expression.
+To match a file named
+.Dq Pa ./foo/xyzzy ,
+you can use the regular expression
+.Dq Li ".*/[xyz]*"
+or
+.Dq Li ".*/foo/.*" ,
+but not
+.Dq Li xyzzy
+or
+.Dq Li /foo/ .
+.It Ic -samefile Ar name
+True if the file is a hard link to
+.Ar name .
+If the command option
+.Ic -L
+is specified, it is also true if the file is a symbolic link and
+points to
+.Ar name .
+.It Ic -size Ar n Ns Op Cm ckMGTP
+True if the file's size, rounded up, in 512-byte blocks is
+.Ar n .
+If
+.Ar n
+is followed by a
+.Cm c ,
+then the primary is true if the
+file's size is
+.Ar n
+bytes (characters).
+Similarly if
+.Ar n
+is followed by a scale indicator then the file's size is compared to
+.Ar n
+scaled as:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm k
+kilobytes (1024 bytes)
+.It Cm M
+megabytes (1024 kilobytes)
+.It Cm G
+gigabytes (1024 megabytes)
+.It Cm T
+terabytes (1024 gigabytes)
+.It Cm P
+petabytes (1024 terabytes)
+.El
+.It Ic -type Ar t
+True if the file is of the specified type.
+Possible file types are as follows:
+.Pp
+.Bl -tag -width indent -compact
+.It Cm b
+block special
+.It Cm c
+character special
+.It Cm d
+directory
+.It Cm f
+regular file
+.It Cm l
+symbolic link
+.It Cm p
+FIFO
+.It Cm s
+socket
+.El
+.It Ic -uid Ar uname
+The same thing as
+.Ar -user Ar uname
+for compatibility with GNU find.
+GNU find imposes a restriction that
+.Ar uname
+is numeric, while
+.Xr find 1
+does not.
+.It Ic -user Ar uname
+True if the file belongs to the user
+.Ar uname .
+If
+.Ar uname
+is numeric and there is no such user name, then
+.Ar uname
+is treated as a user ID.
+.It Ic -wholename Ar pattern
+The same thing as
+.Ic -path ,
+for GNU find compatibility.
+.It Ic -xattr
+True if the file has any extended attributes.
+.It Ic -xattrname Ar name
+True if the file has an extended attribute with the specified
+.Ar name .
+.El
+.Sh OPERATORS
+The primaries may be combined using the following operators.
+The operators are listed in order of decreasing precedence.
+.Pp
+.Bl -tag -width indent -compact
+.It Cm \&( Ar expression Cm \&)
+This evaluates to true if the parenthesized expression evaluates to
+true.
+.Pp
+.It Cm \&! Ar expression
+.It Cm -not Ar expression
+This is the unary
+.Tn NOT
+operator.
+It evaluates to true if the expression is false.
+.Pp
+.It Cm -false
+Always false.
+.It Cm -true
+Always true.
+.Pp
+.It Ar expression Cm -and Ar expression
+.It Ar expression expression
+The
+.Cm -and
+operator is the logical
+.Tn AND
+operator.
+As it is implied by the juxtaposition of two expressions it does not
+have to be specified.
+The expression evaluates to true if both expressions are true.
+The second expression is not evaluated if the first expression is false.
+.Pp
+.It Ar expression Cm -or Ar expression
+The
+.Cm -or
+operator is the logical
+.Tn OR
+operator.
+The expression evaluates to true if either the first or the second expression
+is true.
+The second expression is not evaluated if the first expression is true.
+.El
+.Pp
+All operands and primaries must be separate arguments to
+.Nm .
+Primaries which themselves take arguments expect each argument
+to be a separate argument to
+.Nm .
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_COLLATE , LC_CTYPE , LC_MESSAGES
+and
+.Ev LC_TIME
+environment variables affect the execution of the
+.Nm
+utility as described in
+.Xr environ 7 .
+.Sh EXAMPLES
+The following examples are shown as given to the shell:
+.Bl -tag -width indent
+.It Li "find / \e! -name \*q*.c\*q -print"
+Print out a list of all the files whose names do not end in
+.Pa .c .
+.It Li "find / -newer ttt -user wnj -print"
+Print out a list of all the files owned by user
+.Dq wnj
+that are newer
+than the file
+.Pa ttt .
+.It Li "find / \e! \e( -newer ttt -user wnj \e) -print"
+Print out a list of all the files which are not both newer than
+.Pa ttt
+and owned by
+.Dq wnj .
+.It Li "find / \e( -newer ttt -or -user wnj \e) -print"
+Print out a list of all the files that are either owned by
+.Dq wnj
+or that are newer than
+.Pa ttt .
+.It Li "find / -newerct '1 minute ago' -print"
+Print out a list of all the files whose inode change time is more
+recent than the current time minus one minute.
+.It Li "find / -type f -exec echo {} \e;"
+Use the
+.Xr echo 1
+command to print out a list of all the files.
+.It Li "find -L /usr/ports/packages -type l -exec rm -- {} +"
+Delete all broken symbolic links in
+.Pa /usr/ports/packages .
+.It Li "find /usr/src -name CVS -prune -o -depth +6 -print"
+Find files and directories that are at least seven levels deep
+in the working directory
+.Pa /usr/src .
+.It Li "find /usr/src -name CVS -prune -o -mindepth 7 -print"
+Is not equivalent to the previous example, since
+.Ic -prune
+is not evaluated below level seven.
+.El
+.Sh COMPATIBILITY
+The
+.Ic -follow
+primary is deprecated; the
+.Fl L
+option should be used instead.
+See the
+.Sx STANDARDS
+section below for details.
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chmod 1 ,
+.Xr cvs 1 ,
+.Xr locate 1 ,
+.Xr lsvfs 1 ,
+.Xr whereis 1 ,
+.Xr which 1 ,
+.Xr xargs 1 ,
+.Xr stat 2 ,
+.Xr acl 3 ,
+.Xr fts 3 ,
+.Xr getgrent 3 ,
+.Xr getpwent 3 ,
+.Xr strmode 3 ,
+.Xr re_format 7 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm
+utility syntax is a superset of the syntax specified by the
+.St -p1003.1-2001
+standard.
+.Pp
+All the single character options except
+.Fl H
+and
+.Fl L
+as well as
+.Ic -amin , -anewer , -cmin , -cnewer , -delete , -empty , -fstype ,
+.Ic -iname , -inum , -iregex , -ls , -maxdepth , -mindepth , -mmin ,
+.Ic -path , -print0 , -regex
+and all of the
+.Ic -B*
+birthtime related primaries are extensions to
+.St -p1003.1-2001 .
+.Pp
+Historically, the
+.Fl d , L
+and
+.Fl x
+options were implemented using the primaries
+.Ic -depth , -follow ,
+and
+.Ic -xdev .
+These primaries always evaluated to true.
+As they were really global variables that took effect before the traversal
+began, some legal expressions could have unexpected results.
+An example is the expression
+.Ic -print Cm -o Ic -depth .
+As
+.Ic -print
+always evaluates to true, the standard order of evaluation
+implies that
+.Ic -depth
+would never be evaluated.
+This is not the case.
+.Pp
+The operator
+.Cm -or
+was implemented as
+.Cm -o ,
+and the operator
+.Cm -and
+was implemented as
+.Cm -a .
+.Pp
+Historic implementations of the
+.Ic -exec
+and
+.Ic -ok
+primaries did not replace the string
+.Dq Li {}
+in the utility name or the
+utility arguments if it had preceding or following non-whitespace characters.
+This version replaces it no matter where in the utility name or arguments
+it appears.
+.Pp
+The
+.Fl E
+option was inspired by the equivalent
+.Xr grep 1
+and
+.Xr sed 1
+options.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
+.Sh BUGS
+The special characters used by
+.Nm
+are also special characters to many shell programs.
+In particular, the characters
+.Dq Li * ,
+.Dq Li \&[ ,
+.Dq Li \&] ,
+.Dq Li \&? ,
+.Dq Li \&( ,
+.Dq Li \&) ,
+.Dq Li \&! ,
+.Dq Li \e
+and
+.Dq Li \&;
+may have to be escaped from the shell.
+.Pp
+As there is no delimiter separating options and file names or file
+names and the
+.Ar expression ,
+it is difficult to specify files named
+.Pa -xdev
+or
+.Pa \&! .
+These problems are handled by the
+.Fl f
+option and the
+.Xr getopt 3
+.Dq Fl Fl
+construct.
+.Pp
+The
+.Ic -delete
+primary does not interact well with other options that cause the file system
+tree traversal options to be changed.
+.Pp
+The
+.Ic -mindepth
+and
+.Ic -maxdepth
+primaries are actually global options (as documented above).
+They should
+probably be replaced by options which look like options.
diff --git a/shell_cmds/find/find.c b/shell_cmds/find/find.c
new file mode 100644
index 0000000..c59a75a
--- /dev/null
+++ b/shell_cmds/find/find.c
@@ -0,0 +1,323 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)find.c 8.5 (Berkeley) 8/5/94";
+#else
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/find.c,v 1.23 2010/12/11 08:32:16 joel Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#include <unistd.h>
+#else
+#define COMPAT_MODE(func, mode) 1
+#endif
+
+#include "find.h"
+
+#ifdef __APPLE__
+static int find_compare(const FTSENT **s1, const FTSENT **s2);
+#else /* !__APPLE__ */
+static int find_compare(const FTSENT * const *s1, const FTSENT * const *s2);
+#endif /* __APPLE__ */
+
+/*
+ * find_compare --
+ * tell fts_open() how to order the traversal of the hierarchy.
+ * This variant gives lexicographical order, i.e., alphabetical
+ * order within each directory.
+ */
+static int
+#ifdef __APPLE__
+find_compare(const FTSENT **s1, const FTSENT **s2)
+#else /* !__APPLE__ */
+find_compare(const FTSENT * const *s1, const FTSENT * const *s2)
+#endif /* __APPLE__ */
+{
+
+ return (strcoll((*s1)->fts_name, (*s2)->fts_name));
+}
+
+/*
+ * find_formplan --
+ * process the command line and create a "plan" corresponding to the
+ * command arguments.
+ */
+PLAN *
+find_formplan(char *argv[])
+{
+ PLAN *plan, *tail, *new;
+
+ /*
+ * for each argument in the command line, determine what kind of node
+ * it is, create the appropriate node type and add the new plan node
+ * to the end of the existing plan. The resulting plan is a linked
+ * list of plan nodes. For example, the string:
+ *
+ * % find . -name foo -newer bar -print
+ *
+ * results in the plan:
+ *
+ * [-name foo]--> [-newer bar]--> [-print]
+ *
+ * in this diagram, `[-name foo]' represents the plan node generated
+ * by c_name() with an argument of foo and `-->' represents the
+ * plan->next pointer.
+ */
+ for (plan = tail = NULL; *argv;) {
+ if (!(new = find_create(&argv)))
+ continue;
+ if (plan == NULL)
+ tail = plan = new;
+ else {
+ tail->next = new;
+ tail = new;
+ }
+ }
+
+ /*
+ * if the user didn't specify one of -print, -ok or -exec, then -print
+ * is assumed so we bracket the current expression with parens, if
+ * necessary, and add a -print node on the end.
+ */
+ if (!isoutput) {
+ OPTION *p;
+ char **argv1 = 0;
+
+ if (plan == NULL) {
+ p = lookup_option("-print");
+ new = (p->create)(p, &argv1);
+ tail = plan = new;
+ } else {
+ p = lookup_option("(");
+ new = (p->create)(p, &argv1);
+ new->next = plan;
+ plan = new;
+ p = lookup_option(")");
+ new = (p->create)(p, &argv1);
+ tail->next = new;
+ tail = new;
+ p = lookup_option("-print");
+ new = (p->create)(p, &argv1);
+ tail->next = new;
+ tail = new;
+ }
+ }
+
+ /*
+ * the command line has been completely processed into a search plan
+ * except for the (, ), !, and -o operators. Rearrange the plan so
+ * that the portions of the plan which are affected by the operators
+ * are moved into operator nodes themselves. For example:
+ *
+ * [!]--> [-name foo]--> [-print]
+ *
+ * becomes
+ *
+ * [! [-name foo] ]--> [-print]
+ *
+ * and
+ *
+ * [(]--> [-depth]--> [-name foo]--> [)]--> [-print]
+ *
+ * becomes
+ *
+ * [expr [-depth]-->[-name foo] ]--> [-print]
+ *
+ * operators are handled in order of precedence.
+ */
+
+ plan = paren_squish(plan); /* ()'s */
+ plan = not_squish(plan); /* !'s */
+ plan = or_squish(plan); /* -o's */
+ return (plan);
+}
+
+/* addPath - helper function used to build a list of paths that were
+ * specified on the command line that we are allowed to search.
+ */
+static char **addPath(char **array, char *newPath)
+{
+ static int pathCounter = 0;
+
+ if (newPath == NULL) { /* initialize array */
+ if ((array = malloc(sizeof(char *))) == NULL)
+ err(2, "out of memory");
+ array[0] = NULL;
+ }
+ else {
+ array = realloc(array, (++pathCounter + 1) * sizeof(char *));
+ if (array == NULL)
+ err(2, "out of memory");
+ else {
+ array[pathCounter - 1] = newPath;
+ array[pathCounter] = NULL; /* ensure array is null terminated */
+ }
+ }
+ return (array);
+}
+
+FTS *tree; /* pointer to top of FTS hierarchy */
+
+/*
+ * find_execute --
+ * take a search plan and an array of search paths and executes the plan
+ * over all FTSENT's returned for the given search paths.
+ */
+int
+find_execute(PLAN *plan, char *paths[])
+{
+ FTSENT *entry;
+ PLAN *p;
+ int rval;
+ char **myPaths;
+ int nonSearchableDirFound = 0;
+ int pathIndex;
+ struct stat statInfo;
+
+ /* special-case directories specified on command line - explicitly examine
+ * mode bits, to ensure failure if the directory cannot be searched
+ * (whether or not it's empty). UNIX conformance... <sigh>
+ */
+
+ int strict_symlinks = (ftsoptions & (FTS_COMFOLLOW|FTS_LOGICAL))
+ && COMPAT_MODE("bin/find", "unix2003");
+
+ myPaths = addPath(NULL, NULL);
+ for (pathIndex = 0; paths[pathIndex] != NULL; ++pathIndex) {
+ int stat_ret = stat(paths[pathIndex], &statInfo);
+ int stat_errno = errno;
+ if (strict_symlinks && stat_ret < 0) {
+ if (stat_errno == ELOOP) {
+ errx(1, "Symlink loop resolving %s", paths[pathIndex]);
+ }
+ }
+
+ /* retrieve mode bits, and examine "searchable" bit of
+ directories, exempt root from POSIX conformance */
+ if (COMPAT_MODE("bin/find", "unix2003") && getuid()
+ && stat_ret == 0
+ && ((statInfo.st_mode & S_IFMT) == S_IFDIR)) {
+ if (access(paths[pathIndex], X_OK) == 0) {
+ myPaths = addPath(myPaths, paths[pathIndex]);
+ } else {
+ if (stat_errno != ENAMETOOLONG) { /* if name is too long, just let existing logic handle it */
+ warnx("%s: Permission denied", paths[pathIndex]);
+ nonSearchableDirFound = 1;
+ }
+ }
+ } else {
+ /* not a directory, so add path to array */
+ myPaths = addPath(myPaths, paths[pathIndex]);
+ }
+ }
+ if (myPaths[0] == NULL) { /* were any directories searchable? */
+ free(myPaths);
+ return(nonSearchableDirFound); /* no... */
+ }
+
+ tree = fts_open(myPaths, ftsoptions, (issort ? find_compare : NULL));
+ if (tree == NULL)
+ err(1, "ftsopen");
+
+ for (rval = nonSearchableDirFound; (entry = fts_read(tree)) != NULL;) {
+ if (maxdepth != -1 && entry->fts_level >= maxdepth) {
+ if (fts_set(tree, entry, FTS_SKIP))
+ err(1, "%s", entry->fts_path);
+ }
+
+ switch (entry->fts_info) {
+ case FTS_D:
+ if (isdepth)
+ continue;
+ break;
+ case FTS_DP:
+ if (!isdepth)
+ continue;
+ break;
+ case FTS_DNR:
+ case FTS_ERR:
+ case FTS_NS:
+ (void)fflush(stdout);
+ warnx("%s: %s",
+ entry->fts_path, strerror(entry->fts_errno));
+ rval = 1;
+ continue;
+#ifdef FTS_W
+ case FTS_W:
+ continue;
+#endif /* FTS_W */
+ }
+#define BADCH " \t\n\\'\""
+ if (isxargs && strpbrk(entry->fts_path, BADCH)) {
+ (void)fflush(stdout);
+ warnx("%s: illegal path", entry->fts_path);
+ rval = 1;
+ continue;
+ }
+
+ if (mindepth != -1 && entry->fts_level < mindepth)
+ continue;
+
+ /*
+ * Call all the functions in the execution plan until one is
+ * false or all have been executed. This is where we do all
+ * the work specified by the user on the command line.
+ */
+ for (p = plan; p && (p->execute)(p, entry); p = p->next);
+ }
+ free (myPaths);
+ finish_execplus();
+ if (execplus_error) {
+ exit(execplus_error);
+ }
+ if (errno)
+ err(1, "fts_read");
+ fts_close(tree);
+ return (rval);
+}
diff --git a/shell_cmds/find/find.h b/shell_cmds/find/find.h
new file mode 100644
index 0000000..8960a0b
--- /dev/null
+++ b/shell_cmds/find/find.h
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)find.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/find/find.h,v 1.21 2010/12/11 08:32:16 joel Exp $
+ */
+
+#include <regex.h>
+
+/* forward declarations */
+struct _plandata;
+struct _option;
+
+/* execute function */
+typedef int exec_f(struct _plandata *, FTSENT *);
+/* create function */
+typedef struct _plandata *creat_f(struct _option *, char ***);
+
+/* function modifiers */
+#define F_NEEDOK 0x00000001 /* -ok vs. -exec */
+#define F_EXECDIR 0x00000002 /* -execdir vs. -exec */
+#define F_TIME_A 0x00000004 /* one of -atime, -anewer, -newera* */
+#define F_TIME_C 0x00000008 /* one of -ctime, -cnewer, -newerc* */
+#define F_TIME2_A 0x00000010 /* one of -newer?a */
+#define F_TIME2_C 0x00000020 /* one of -newer?c */
+#define F_TIME2_T 0x00000040 /* one of -newer?t */
+#define F_MAXDEPTH F_TIME_A /* maxdepth vs. mindepth */
+#define F_DEPTH F_TIME_A /* -depth n vs. -d */
+/* command line function modifiers */
+#define F_EQUAL 0x00000000 /* [acm]min [acm]time inum links size */
+#define F_LESSTHAN 0x00000100
+#define F_GREATER 0x00000200
+#define F_ELG_MASK 0x00000300
+#define F_ATLEAST 0x00000400 /* flags perm */
+#define F_ANY 0x00000800 /* perm */
+#define F_MTMASK 0x00003000
+#define F_MTFLAG 0x00000000 /* fstype */
+#define F_MTTYPE 0x00001000
+#define F_MTUNKNOWN 0x00002000
+#define F_IGNCASE 0x00010000 /* iname ipath iregex */
+#define F_EXACTTIME F_IGNCASE /* -[acm]time units syntax */
+#define F_EXECPLUS 0x00020000 /* -exec ... {} + */
+#define F_TIME_B 0x00040000 /* one of -Btime, -Bnewer, -newerB* */
+#define F_TIME2_B 0x00080000 /* one of -newer?B */
+#define F_LINK 0x00100000 /* lname or ilname */
+
+/* node definition */
+typedef struct _plandata {
+ struct _plandata *next; /* next node */
+ exec_f *execute; /* node evaluation function */
+ int flags; /* private flags */
+ union {
+ gid_t _g_data; /* gid */
+ ino_t _i_data; /* inode */
+ mode_t _m_data; /* mode mask */
+ struct {
+ u_long _f_flags;
+ u_long _f_notflags;
+ } fl;
+ nlink_t _l_data; /* link count */
+ short _d_data; /* level depth (-1 to N) */
+ off_t _o_data; /* file size */
+ time_t _t_data; /* time value */
+ uid_t _u_data; /* uid */
+ short _mt_data; /* mount flags */
+ struct _plandata *_p_data[2]; /* PLAN trees */
+ struct _ex {
+ char **_e_argv; /* argv array */
+ char **_e_orig; /* original strings */
+ int *_e_len; /* allocated length */
+ int _e_pbnum; /* base num. of args. used */
+ int _e_ppos; /* number of arguments used */
+ int _e_pnummax; /* max. number of arguments */
+ int _e_psize; /* number of bytes of args. */
+ int _e_pbsize; /* base num. of bytes of args */
+ int _e_psizemax; /* max num. of bytes of args */
+ struct _plandata *_e_next;/* next F_EXECPLUS in tree */
+ } ex;
+ char *_a_data[2]; /* array of char pointers */
+ char *_c_data; /* char pointer */
+ regex_t *_re_data; /* regex */
+ } p_un;
+} PLAN;
+#define a_data p_un._a_data
+#define c_data p_un._c_data
+#define d_data p_un._d_data
+#define fl_flags p_un.fl._f_flags
+#define fl_notflags p_un.fl._f_notflags
+#define g_data p_un._g_data
+#define i_data p_un._i_data
+#define l_data p_un._l_data
+#define m_data p_un._m_data
+#define mt_data p_un._mt_data
+#define o_data p_un._o_data
+#define p_data p_un._p_data
+#define t_data p_un._t_data
+#define u_data p_un._u_data
+#define re_data p_un._re_data
+#define e_argv p_un.ex._e_argv
+#define e_orig p_un.ex._e_orig
+#define e_len p_un.ex._e_len
+#define e_pbnum p_un.ex._e_pbnum
+#define e_ppos p_un.ex._e_ppos
+#define e_pnummax p_un.ex._e_pnummax
+#define e_psize p_un.ex._e_psize
+#define e_pbsize p_un.ex._e_pbsize
+#define e_psizemax p_un.ex._e_psizemax
+#define e_next p_un.ex._e_next
+
+typedef struct _option {
+ const char *name; /* option name */
+ creat_f *create; /* create function */
+ exec_f *execute; /* execute function */
+ int flags;
+} OPTION;
+
+#include "extern.h"
diff --git a/shell_cmds/find/find.plist.part b/shell_cmds/find/find.plist.part
new file mode 100644
index 0000000..0148f95
--- /dev/null
+++ b/shell_cmds/find/find.plist.part
@@ -0,0 +1,30 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>find</string>
+ <key>OpenSourceVersion</key>
+ <string>2011-12-10</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/usr.bin/find/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/usr.bin/find/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2012-01-06</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Add -xattr and -xattrname options.</string>
+ <string>execplus conformance fixes.</string>
+ <string>Man page fix (4772561).</string>
+ <string>Adjust FTS usage due to API differences.</string>
+ <string>Avoid searching unsearchable directories (3849245).</string>
+ <string>Add missing call to fts_close (4608460).</string>
+ <string>Conformance fixes related to F_EXACTTIME.</string>
+ <string>Apple-specific implementation of -acl primary.</string>
+ <string>Conformance fix for f_name (6591280).</string>
+ <string>setmode conformance fix (3936046).</string>
+ <string>Use a saner MAXLOGNAME definition.</string>
+ <string>Workaround for lack of rpmatch function.</string>
+ <string>FreeBSD revisions 260336, 260355.</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/find/function.c b/shell_cmds/find/function.c
new file mode 100644
index 0000000..a673a02
--- /dev/null
+++ b/shell_cmds/find/function.c
@@ -0,0 +1,1772 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "@(#)function.c 8.10 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.71 2011/06/13 05:22:07 avatar Exp $");
+
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/acl.h>
+#include <sys/wait.h>
+#include <sys/mount.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#include <sys/xattr.h>
+#include <libgen.h>
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(func, mode) 1
+#endif
+
+#include "find.h"
+
+static PLAN *palloc(OPTION *);
+static long long find_parsenum(PLAN *, const char *, char *, char *);
+static long long find_parsetime(PLAN *, const char *, char *);
+static char *nextarg(OPTION *, char ***);
+
+extern char **environ;
+
+static PLAN *lastexecplus = NULL;
+int execplus_error;
+
+#define COMPARE(a, b) do { \
+ switch (plan->flags & F_ELG_MASK) { \
+ case F_EQUAL: \
+ return (a == b); \
+ case F_LESSTHAN: \
+ return (a < b); \
+ case F_GREATER: \
+ return (a > b); \
+ default: \
+ abort(); \
+ } \
+} while(0)
+
+static PLAN *
+palloc(OPTION *option)
+{
+ PLAN *new;
+
+ if ((new = malloc(sizeof(PLAN))) == NULL)
+ err(1, NULL);
+ new->execute = option->execute;
+ new->flags = option->flags;
+ new->next = NULL;
+ return new;
+}
+
+/*
+ * find_parsenum --
+ * Parse a string of the form [+-]# and return the value.
+ */
+static long long
+find_parsenum(PLAN *plan, const char *option, char *vp, char *endch)
+{
+ long long value;
+ char *endchar, *str; /* Pointer to character ending conversion. */
+
+ /* Determine comparison from leading + or -. */
+ str = vp;
+ switch (*str) {
+ case '+':
+ ++str;
+ plan->flags |= F_GREATER;
+ break;
+ case '-':
+ ++str;
+ plan->flags |= F_LESSTHAN;
+ break;
+ default:
+ plan->flags |= F_EQUAL;
+ break;
+ }
+
+ /*
+ * Convert the string with strtoq(). Note, if strtoq() returns zero
+ * and endchar points to the beginning of the string we know we have
+ * a syntax error.
+ */
+ value = strtoq(str, &endchar, 10);
+ if (value == 0 && endchar == str)
+ errx(1, "%s: %s: illegal numeric value", option, vp);
+ if (endchar[0] && endch == NULL)
+ errx(1, "%s: %s: illegal trailing character", option, vp);
+ if (endch)
+ *endch = endchar[0];
+ return value;
+}
+
+/*
+ * find_parsetime --
+ * Parse a string of the form [+-]([0-9]+[smhdw]?)+ and return the value.
+ */
+static long long
+find_parsetime(PLAN *plan, const char *option, char *vp)
+{
+ long long secs, value;
+ char *str, *unit; /* Pointer to character ending conversion. */
+
+ /* Determine comparison from leading + or -. */
+ str = vp;
+ switch (*str) {
+ case '+':
+ ++str;
+ plan->flags |= F_GREATER;
+ break;
+ case '-':
+ ++str;
+ plan->flags |= F_LESSTHAN;
+ break;
+ default:
+ plan->flags |= F_EQUAL;
+ break;
+ }
+
+ value = strtoq(str, &unit, 10);
+ if (value == 0 && unit == str) {
+ errx(1, "%s: %s: illegal time value", option, vp);
+ /* NOTREACHED */
+ }
+ if (*unit == '\0')
+ return value;
+
+ /* Units syntax. */
+ secs = 0;
+ for (;;) {
+ switch(*unit) {
+ case 's': /* seconds */
+ secs += value;
+ break;
+ case 'm': /* minutes */
+ secs += value * 60;
+ break;
+ case 'h': /* hours */
+ secs += value * 3600;
+ break;
+ case 'd': /* days */
+ secs += value * 86400;
+ break;
+ case 'w': /* weeks */
+ secs += value * 604800;
+ break;
+ default:
+ errx(1, "%s: %s: bad unit '%c'", option, vp, *unit);
+ /* NOTREACHED */
+ }
+ str = unit + 1;
+ if (*str == '\0') /* EOS */
+ break;
+ value = strtoq(str, &unit, 10);
+ if (value == 0 && unit == str) {
+ errx(1, "%s: %s: illegal time value", option, vp);
+ /* NOTREACHED */
+ }
+ if (*unit == '\0') {
+ errx(1, "%s: %s: missing trailing unit", option, vp);
+ /* NOTREACHED */
+ }
+ }
+ plan->flags |= F_EXACTTIME;
+ return secs;
+}
+
+/*
+ * nextarg --
+ * Check that another argument still exists, return a pointer to it,
+ * and increment the argument vector pointer.
+ */
+static char *
+nextarg(OPTION *option, char ***argvp)
+{
+ char *arg;
+
+ if ((arg = **argvp) == 0)
+ errx(1, "%s: requires additional arguments", option->name);
+ (*argvp)++;
+ return arg;
+} /* nextarg() */
+
+/*
+ * The value of n for the inode times (atime, birthtime, ctime, mtime) is a
+ * range, i.e. n matches from (n - 1) to n 24 hour periods. This interacts
+ * with -n, such that "-mtime -1" would be less than 0 days, which isn't what
+ * the user wanted. Correct so that -1 is "less than 1".
+ */
+#define TIME_CORRECT(p) \
+ if (((p)->flags & F_ELG_MASK) == F_LESSTHAN) \
+ ++((p)->t_data);
+
+/*
+ * -[acm]min n functions --
+ *
+ * True if the difference between the
+ * file access time (-amin)
+ * file birth time (-Bmin)
+ * last change of file status information (-cmin)
+ * file modification time (-mmin)
+ * and the current time is n min periods.
+ */
+int
+f_Xmin(PLAN *plan, FTSENT *entry)
+{
+ if (plan->flags & F_TIME_C) {
+ COMPARE((now - entry->fts_statp->st_ctime +
+ 60 - 1) / 60, plan->t_data);
+ } else if (plan->flags & F_TIME_A) {
+ COMPARE((now - entry->fts_statp->st_atime +
+ 60 - 1) / 60, plan->t_data);
+ } else if (plan->flags & F_TIME_B) {
+ COMPARE((now - entry->fts_statp->st_birthtime +
+ 60 - 1) / 60, plan->t_data);
+ } else {
+ COMPARE((now - entry->fts_statp->st_mtime +
+ 60 - 1) / 60, plan->t_data);
+ }
+}
+
+PLAN *
+c_Xmin(OPTION *option, char ***argvp)
+{
+ char *nmins;
+ PLAN *new;
+
+ nmins = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ new->t_data = find_parsenum(new, option->name, nmins, NULL);
+ TIME_CORRECT(new);
+ return new;
+}
+
+/*
+ * -[acm]time n functions --
+ *
+ * True if the difference between the
+ * file access time (-atime)
+ * file birth time (-Btime)
+ * last change of file status information (-ctime)
+ * file modification time (-mtime)
+ * and the current time is n 24 hour periods.
+ */
+
+int
+f_Xtime(PLAN *plan, FTSENT *entry)
+{
+ time_t xtime;
+
+ if (plan->flags & F_TIME_A)
+ xtime = entry->fts_statp->st_atime;
+ else if (plan->flags & F_TIME_B)
+ xtime = entry->fts_statp->st_birthtime;
+ else if (plan->flags & F_TIME_C)
+ xtime = entry->fts_statp->st_ctime;
+ else
+ xtime = entry->fts_statp->st_mtime;
+
+ if (plan->flags & F_EXACTTIME)
+ COMPARE(now - xtime, plan->t_data);
+ else
+ COMPARE((now - xtime + (COMPAT_MODE("bin/find", "unix2003") ? 0 : 86400 - 1)) / 86400, plan->t_data);
+}
+
+PLAN *
+c_Xtime(OPTION *option, char ***argvp)
+{
+ char *value;
+ PLAN *new;
+
+ value = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ new->t_data = find_parsetime(new, option->name, value);
+ if (!(new->flags & F_EXACTTIME) && !COMPAT_MODE("bin/find", "unix2003"))
+ TIME_CORRECT(new);
+ return new;
+}
+
+/*
+ * -maxdepth/-mindepth n functions --
+ *
+ * Does the same as -prune if the level of the current file is
+ * greater/less than the specified maximum/minimum depth.
+ *
+ * Note that -maxdepth and -mindepth are handled specially in
+ * find_execute() so their f_* functions are set to f_always_true().
+ */
+PLAN *
+c_mXXdepth(OPTION *option, char ***argvp)
+{
+ char *dstr;
+ PLAN *new;
+
+ dstr = nextarg(option, argvp);
+ if (dstr[0] == '-')
+ /* all other errors handled by find_parsenum() */
+ errx(1, "%s: %s: value must be positive", option->name, dstr);
+
+ new = palloc(option);
+ if (option->flags & F_MAXDEPTH)
+ maxdepth = find_parsenum(new, option->name, dstr, NULL);
+ else
+ mindepth = find_parsenum(new, option->name, dstr, NULL);
+ return new;
+}
+
+/*
+ * -acl function --
+ *
+ * Show files with EXTENDED ACL attributes.
+ */
+#ifdef __APPLE__
+int
+f_acl(PLAN *plan __unused, FTSENT *entry)
+{
+ acl_t facl;
+ int match;
+ acl_entry_t ae;
+
+ match = 0;
+ if ((facl = acl_get_link_np(entry->fts_accpath, ACL_TYPE_EXTENDED)) != NULL) {
+ if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 0) {
+ match = 1;
+ }
+ acl_free(facl);
+ }
+ return match;
+}
+#else /* !__APPLE__ */
+int
+f_acl(PLAN *plan __unused, FTSENT *entry)
+{
+ acl_t facl;
+ acl_type_t acl_type;
+ int acl_supported = 0, ret, trivial;
+
+ if (S_ISLNK(entry->fts_statp->st_mode))
+ return 0;
+ ret = pathconf(entry->fts_accpath, _PC_ACL_NFS4);
+ if (ret > 0) {
+ acl_supported = 1;
+ acl_type = ACL_TYPE_NFS4;
+ } else if (ret < 0 && errno != EINVAL) {
+ warn("%s", entry->fts_accpath);
+ return (0);
+ }
+ if (acl_supported == 0) {
+ ret = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED);
+ if (ret > 0) {
+ acl_supported = 1;
+ acl_type = ACL_TYPE_ACCESS;
+ } else if (ret < 0 && errno != EINVAL) {
+ warn("%s", entry->fts_accpath);
+ return (0);
+ }
+ }
+ if (acl_supported == 0)
+ return (0);
+
+ facl = acl_get_file(entry->fts_accpath, acl_type);
+ if (facl == NULL) {
+ warn("%s", entry->fts_accpath);
+ return (0);
+ }
+ ret = acl_is_trivial_np(facl, &trivial);
+ acl_free(facl);
+ if (ret) {
+ warn("%s", entry->fts_accpath);
+ acl_free(facl);
+ return (0);
+ }
+ if (trivial)
+ return (0);
+ return (1);
+}
+#endif /* __APPLE__ */
+
+PLAN *
+c_acl(OPTION *option, char ***argvp __unused)
+{
+#ifndef __APPLE__
+ ftsoptions &= ~FTS_NOSTAT;
+#endif /* !__APPLE__ */
+ return (palloc(option));
+}
+
+#ifdef __APPLE__
+int
+f_xattr(PLAN *plan __unused, FTSENT *entry)
+{
+ ssize_t xattr;
+ int match;
+
+ match = 0;
+ xattr = listxattr(entry->fts_accpath, NULL, 0, XATTR_NOFOLLOW);
+ if (xattr > 0) {
+ match = 1;
+ }
+ return match;
+}
+
+int
+f_xattrname(PLAN *plan, FTSENT *entry)
+{
+ ssize_t xattr;
+ int match;
+
+ match = 0;
+ xattr = getxattr(entry->fts_accpath, plan->c_data, NULL, 0, 0, XATTR_NOFOLLOW);
+ if (xattr > 0) {
+ match = 1;
+ }
+ return match;
+}
+#endif /* __APPLE__ */
+
+/*
+ * -delete functions --
+ *
+ * True always. Makes its best shot and continues on regardless.
+ */
+int
+f_delete(PLAN *plan __unused, FTSENT *entry)
+{
+ /* ignore these from fts */
+ if (strcmp(entry->fts_accpath, ".") == 0 ||
+ strcmp(entry->fts_accpath, "..") == 0)
+ return 1;
+
+ /* sanity check */
+ if (isdepth == 0 || /* depth off */
+ (ftsoptions & FTS_NOSTAT)) /* not stat()ing */
+ errx(1, "-delete: insecure options got turned on");
+
+ if (!(ftsoptions & FTS_PHYSICAL) || /* physical off */
+ (ftsoptions & FTS_LOGICAL)) /* or finally, logical on */
+ errx(1, "-delete: forbidden when symlinks are followed");
+
+ /* Potentially unsafe - do not accept relative paths whatsoever */
+ if (strchr(entry->fts_accpath, '/') != NULL)
+ errx(1, "-delete: %s: relative path potentially not safe",
+ entry->fts_accpath);
+
+ /* Turn off user immutable bits if running as root */
+ if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
+ !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
+ geteuid() == 0)
+ lchflags(entry->fts_accpath,
+ entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
+
+ /* rmdir directories, unlink everything else */
+ if (S_ISDIR(entry->fts_statp->st_mode)) {
+ if (rmdir(entry->fts_accpath) < 0 && errno != ENOTEMPTY)
+ warn("-delete: rmdir(%s)", entry->fts_path);
+ } else {
+ if (unlink(entry->fts_accpath) < 0)
+ warn("-delete: unlink(%s)", entry->fts_path);
+ }
+
+ /* "succeed" */
+ return 1;
+}
+
+PLAN *
+c_delete(OPTION *option, char ***argvp __unused)
+{
+
+ ftsoptions &= ~FTS_NOSTAT; /* no optimise */
+ isoutput = 1; /* possible output */
+ isdepth = 1; /* -depth implied */
+
+ return palloc(option);
+}
+
+
+/*
+ * always_true --
+ *
+ * Always true, used for -maxdepth, -mindepth, -xdev, -follow, and -true
+ */
+int
+f_always_true(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ return 1;
+}
+
+/*
+ * -depth functions --
+ *
+ * With argument: True if the file is at level n.
+ * Without argument: Always true, causes descent of the directory hierarchy
+ * to be done so that all entries in a directory are acted on before the
+ * directory itself.
+ */
+int
+f_depth(PLAN *plan, FTSENT *entry)
+{
+ if (plan->flags & F_DEPTH)
+ COMPARE(entry->fts_level, plan->d_data);
+ else
+ return 1;
+}
+
+PLAN *
+c_depth(OPTION *option, char ***argvp)
+{
+ PLAN *new;
+ char *str;
+
+ new = palloc(option);
+
+ str = **argvp;
+ if (str && !(new->flags & F_DEPTH)) {
+ /* skip leading + or - */
+ if (*str == '+' || *str == '-')
+ str++;
+ /* skip sign */
+ if (*str == '+' || *str == '-')
+ str++;
+ if (isdigit(*str))
+ new->flags |= F_DEPTH;
+ }
+
+ if (new->flags & F_DEPTH) { /* -depth n */
+ char *ndepth;
+
+ ndepth = nextarg(option, argvp);
+ new->d_data = find_parsenum(new, option->name, ndepth, NULL);
+ } else { /* -d */
+ isdepth = 1;
+ }
+
+ return new;
+}
+
+/*
+ * -empty functions --
+ *
+ * True if the file or directory is empty
+ */
+int
+f_empty(PLAN *plan __unused, FTSENT *entry)
+{
+ if (S_ISREG(entry->fts_statp->st_mode) &&
+ entry->fts_statp->st_size == 0)
+ return 1;
+ if (S_ISDIR(entry->fts_statp->st_mode)) {
+ struct dirent *dp;
+ int empty;
+ DIR *dir;
+
+ empty = 1;
+ dir = opendir(entry->fts_accpath);
+ if (dir == NULL)
+ return 0;
+ for (dp = readdir(dir); dp; dp = readdir(dir))
+ if (dp->d_name[0] != '.' ||
+ (dp->d_name[1] != '\0' &&
+ (dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) {
+ empty = 0;
+ break;
+ }
+ closedir(dir);
+ return empty;
+ }
+ return 0;
+}
+
+PLAN *
+c_empty(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+
+ return palloc(option);
+}
+
+/*
+ * [-exec | -execdir | -ok] utility [arg ... ] ; functions --
+ *
+ * True if the executed utility returns a zero value as exit status.
+ * The end of the primary expression is delimited by a semicolon. If
+ * "{}" occurs anywhere, it gets replaced by the current pathname,
+ * or, in the case of -execdir, the current basename (filename
+ * without leading directory prefix). For -exec and -ok,
+ * the current directory for the execution of utility is the same as
+ * the current directory when the find utility was started, whereas
+ * for -execdir, it is the directory the file resides in.
+ *
+ * The primary -ok differs from -exec in that it requests affirmation
+ * of the user before executing the utility.
+ */
+int
+f_exec(PLAN *plan, FTSENT *entry)
+{
+ int cnt;
+ pid_t pid;
+ int status;
+ char *file;
+
+ if (entry == NULL && plan->flags & F_EXECPLUS) {
+ if (plan->e_ppos == plan->e_pbnum)
+ return (1);
+ plan->e_argv[plan->e_ppos] = NULL;
+ goto doexec;
+ }
+
+ /* XXX - if file/dir ends in '/' this will not work -- can it? */
+ if ((plan->flags & F_EXECDIR) && \
+ (file = strrchr(entry->fts_path, '/')))
+ file++;
+ else
+ file = entry->fts_path;
+
+ if (plan->flags & F_EXECPLUS) {
+ if ((plan->e_argv[plan->e_ppos] = strdup(file)) == NULL)
+ err(1, NULL);
+ plan->e_len[plan->e_ppos] = strlen(file);
+ plan->e_psize += plan->e_len[plan->e_ppos];
+ if (++plan->e_ppos < plan->e_pnummax &&
+ plan->e_psize < plan->e_psizemax)
+ return (1);
+ plan->e_argv[plan->e_ppos] = NULL;
+ } else {
+ for (cnt = 0; plan->e_argv[cnt]; ++cnt)
+ if (plan->e_len[cnt])
+ brace_subst(plan->e_orig[cnt],
+ &plan->e_argv[cnt], file,
+ plan->e_len[cnt]);
+ }
+
+doexec: if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
+ return 0;
+
+ /* make sure find output is interspersed correctly with subprocesses */
+ fflush(stdout);
+ fflush(stderr);
+
+ switch (pid = fork()) {
+ case -1:
+ err(1, "fork");
+ /* NOTREACHED */
+ case 0:
+ /* change dir back from where we started */
+ if (!(plan->flags & F_EXECDIR) && fchdir(dotfd)) {
+ warn("chdir");
+ _exit(1);
+ }
+ execvp(plan->e_argv[0], plan->e_argv);
+ warn("%s", plan->e_argv[0]);
+ _exit(1);
+ }
+ if (plan->flags & F_EXECPLUS) {
+ while (--plan->e_ppos >= plan->e_pbnum)
+ free(plan->e_argv[plan->e_ppos]);
+ plan->e_ppos = plan->e_pbnum;
+ plan->e_psize = plan->e_pbsize;
+ }
+ pid = waitpid(pid, &status, 0);
+ if (plan->flags & F_EXECPLUS && WIFEXITED(status) && WEXITSTATUS(status) && !execplus_error) {
+ /* Test 140 (8907531, 10656525) */
+ execplus_error = WEXITSTATUS(status);
+ }
+ return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
+}
+
+/*
+ * c_exec, c_execdir, c_ok --
+ * build three parallel arrays, one with pointers to the strings passed
+ * on the command line, one with (possibly duplicated) pointers to the
+ * argv array, and one with integer values that are lengths of the
+ * strings, but also flags meaning that the string has to be massaged.
+ */
+PLAN *
+c_exec(OPTION *option, char ***argvp)
+{
+ PLAN *new; /* node returned */
+ long argmax;
+ int cnt, i;
+ char **argv, **ap, **ep, *p;
+
+ /* XXX - was in c_execdir, but seems unnecessary!?
+ ftsoptions &= ~FTS_NOSTAT;
+ */
+ isoutput = 1;
+
+ /* XXX - this is a change from the previous coding */
+ new = palloc(option);
+
+ for (ap = argv = *argvp;; ++ap) {
+ if (!*ap)
+ errx(1,
+ "%s: no terminating \";\" or \"+\"", option->name);
+ if (**ap == ';')
+ break;
+ if (**ap == '+' && ap != argv && strcmp(*(ap - 1), "{}") == 0) {
+ new->flags |= F_EXECPLUS;
+ break;
+ }
+ }
+
+ if (ap == argv)
+ errx(1, "%s: no command specified", option->name);
+
+ cnt = ap - *argvp + 1;
+ if (new->flags & F_EXECPLUS) {
+ new->e_ppos = new->e_pbnum = cnt - 2;
+ if ((argmax = sysconf(_SC_ARG_MAX)) == -1) {
+ warn("sysconf(_SC_ARG_MAX)");
+ argmax = _POSIX_ARG_MAX;
+ }
+ argmax -= 1024;
+ for (ep = environ; *ep != NULL; ep++)
+ argmax -= strlen(*ep) + 1 + sizeof(*ep);
+ argmax -= 1 + sizeof(*ep);
+ new->e_pnummax = argmax / 16;
+ argmax -= sizeof(char *) * new->e_pnummax;
+ if (argmax <= 0)
+ errx(1, "no space for arguments");
+ new->e_psizemax = argmax;
+ new->e_pbsize = 0;
+ cnt += new->e_pnummax + 1;
+ new->e_next = lastexecplus;
+ lastexecplus = new;
+ }
+ if ((new->e_argv = malloc(cnt * sizeof(char *))) == NULL)
+ err(1, NULL);
+ if ((new->e_orig = malloc(cnt * sizeof(char *))) == NULL)
+ err(1, NULL);
+ if ((new->e_len = malloc(cnt * sizeof(int))) == NULL)
+ err(1, NULL);
+
+ for (argv = *argvp, cnt = 0; argv < ap; ++argv, ++cnt) {
+ new->e_orig[cnt] = *argv;
+ if (new->flags & F_EXECPLUS)
+ new->e_pbsize += strlen(*argv) + 1;
+ for (p = *argv; *p; ++p)
+ if (!(new->flags & F_EXECPLUS) && p[0] == '{' &&
+ p[1] == '}') {
+ if ((new->e_argv[cnt] =
+ malloc(MAXPATHLEN)) == NULL)
+ err(1, NULL);
+ new->e_len[cnt] = MAXPATHLEN;
+ break;
+ }
+ if (!*p) {
+ new->e_argv[cnt] = *argv;
+ new->e_len[cnt] = 0;
+ }
+ }
+ if (new->flags & F_EXECPLUS) {
+ new->e_psize = new->e_pbsize;
+ cnt--;
+ for (i = 0; i < new->e_pnummax; i++) {
+ new->e_argv[cnt] = NULL;
+ new->e_len[cnt] = 0;
+ cnt++;
+ }
+ argv = ap;
+ goto done;
+ }
+ new->e_argv[cnt] = new->e_orig[cnt] = NULL;
+
+done: *argvp = argv + 1;
+ return new;
+}
+
+/* Finish any pending -exec ... {} + functions. */
+void
+finish_execplus(void)
+{
+ PLAN *p;
+
+ p = lastexecplus;
+ while (p != NULL) {
+ (p->execute)(p, NULL);
+ p = p->e_next;
+ }
+}
+
+int
+f_flags(PLAN *plan, FTSENT *entry)
+{
+ u_long flags;
+
+ flags = entry->fts_statp->st_flags;
+ if (plan->flags & F_ATLEAST)
+ return (flags | plan->fl_flags) == flags &&
+ !(flags & plan->fl_notflags);
+ else if (plan->flags & F_ANY)
+ return (flags & plan->fl_flags) ||
+ (flags | plan->fl_notflags) != flags;
+ else
+ return flags == plan->fl_flags &&
+ !(plan->fl_flags & plan->fl_notflags);
+}
+
+PLAN *
+c_flags(OPTION *option, char ***argvp)
+{
+ char *flags_str;
+ PLAN *new;
+ u_long flags, notflags;
+
+ flags_str = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+
+ if (*flags_str == '-') {
+ new->flags |= F_ATLEAST;
+ flags_str++;
+ } else if (*flags_str == '+') {
+ new->flags |= F_ANY;
+ flags_str++;
+ }
+ if (strtofflags(&flags_str, &flags, &notflags) == 1)
+ errx(1, "%s: %s: illegal flags string", option->name, flags_str);
+
+ new->fl_flags = flags;
+ new->fl_notflags = notflags;
+ return new;
+}
+
+/*
+ * -follow functions --
+ *
+ * Always true, causes symbolic links to be followed on a global
+ * basis.
+ */
+PLAN *
+c_follow(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+
+ return palloc(option);
+}
+
+/*
+ * -fstype functions --
+ *
+ * True if the file is of a certain type.
+ */
+int
+f_fstype(PLAN *plan, FTSENT *entry)
+{
+ static dev_t curdev; /* need a guaranteed illegal dev value */
+ static int first = 1;
+ struct statfs sb;
+ static int val_flags;
+ static char fstype[sizeof(sb.f_fstypename)];
+ char *p, save[2] = {0,0};
+
+ if ((plan->flags & F_MTMASK) == F_MTUNKNOWN)
+ return 0;
+
+ /* Only check when we cross mount point. */
+ if (first || curdev != entry->fts_statp->st_dev) {
+ curdev = entry->fts_statp->st_dev;
+
+ /*
+ * Statfs follows symlinks; find wants the link's filesystem,
+ * not where it points.
+ */
+ if (entry->fts_info == FTS_SL ||
+ entry->fts_info == FTS_SLNONE) {
+ if ((p = strrchr(entry->fts_accpath, '/')) != NULL)
+ ++p;
+ else
+ p = entry->fts_accpath;
+ save[0] = p[0];
+ p[0] = '.';
+ save[1] = p[1];
+ p[1] = '\0';
+ } else
+ p = NULL;
+
+ if (statfs(entry->fts_accpath, &sb))
+ err(1, "%s", entry->fts_accpath);
+
+ if (p) {
+ p[0] = save[0];
+ p[1] = save[1];
+ }
+
+ first = 0;
+
+ /*
+ * Further tests may need both of these values, so
+ * always copy both of them.
+ */
+ val_flags = sb.f_flags;
+ strlcpy(fstype, sb.f_fstypename, sizeof(fstype));
+ }
+ switch (plan->flags & F_MTMASK) {
+ case F_MTFLAG:
+ return val_flags & plan->mt_data;
+ case F_MTTYPE:
+ return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0);
+ default:
+ abort();
+ }
+}
+
+PLAN *
+c_fstype(OPTION *option, char ***argvp)
+{
+ char *fsname;
+ PLAN *new;
+
+ fsname = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ switch (*fsname) {
+ case 'l':
+ if (!strcmp(fsname, "local")) {
+ new->flags |= F_MTFLAG;
+ new->mt_data = MNT_LOCAL;
+ return new;
+ }
+ break;
+ case 'r':
+ if (!strcmp(fsname, "rdonly")) {
+ new->flags |= F_MTFLAG;
+ new->mt_data = MNT_RDONLY;
+ return new;
+ }
+ break;
+ }
+
+ new->flags |= F_MTTYPE;
+ new->c_data = fsname;
+ return new;
+}
+
+/*
+ * -group gname functions --
+ *
+ * True if the file belongs to the group gname. If gname is numeric and
+ * an equivalent of the getgrnam() function does not return a valid group
+ * name, gname is taken as a group ID.
+ */
+int
+f_group(PLAN *plan, FTSENT *entry)
+{
+ COMPARE(entry->fts_statp->st_gid, plan->g_data);
+}
+
+PLAN *
+c_group(OPTION *option, char ***argvp)
+{
+ char *gname;
+ PLAN *new;
+ struct group *g;
+ gid_t gid;
+
+ gname = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ g = getgrnam(gname);
+ if (g == NULL) {
+ char* cp = gname;
+ if (gname[0] == '-' || gname[0] == '+')
+ gname++;
+ gid = atoi(gname);
+ if (gid == 0 && gname[0] != '0')
+ errx(1, "%s: %s: no such group", option->name, gname);
+ gid = find_parsenum(new, option->name, cp, NULL);
+ } else
+ gid = g->gr_gid;
+
+ new->g_data = gid;
+ return new;
+}
+
+/*
+ * -inum n functions --
+ *
+ * True if the file has inode # n.
+ */
+int
+f_inum(PLAN *plan, FTSENT *entry)
+{
+ COMPARE(entry->fts_statp->st_ino, plan->i_data);
+}
+
+PLAN *
+c_inum(OPTION *option, char ***argvp)
+{
+ char *inum_str;
+ PLAN *new;
+
+ inum_str = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ new->i_data = find_parsenum(new, option->name, inum_str, NULL);
+ return new;
+}
+
+/*
+ * -samefile FN
+ *
+ * True if the file has the same inode (eg hard link) FN
+ */
+
+/* f_samefile is just f_inum */
+PLAN *
+c_samefile(OPTION *option, char ***argvp)
+{
+ char *fn;
+ PLAN *new;
+ struct stat sb;
+
+ fn = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ if (stat(fn, &sb))
+ err(1, "%s", fn);
+ new->i_data = sb.st_ino;
+ return new;
+}
+
+/*
+ * -links n functions --
+ *
+ * True if the file has n links.
+ */
+int
+f_links(PLAN *plan, FTSENT *entry)
+{
+ COMPARE(entry->fts_statp->st_nlink, plan->l_data);
+}
+
+PLAN *
+c_links(OPTION *option, char ***argvp)
+{
+ char *nlinks;
+ PLAN *new;
+
+ nlinks = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ new->l_data = (nlink_t)find_parsenum(new, option->name, nlinks, NULL);
+ return new;
+}
+
+/*
+ * -ls functions --
+ *
+ * Always true - prints the current entry to stdout in "ls" format.
+ */
+int
+f_ls(PLAN *plan __unused, FTSENT *entry)
+{
+ printlong(entry->fts_path, entry->fts_accpath, entry->fts_statp);
+ return 1;
+}
+
+PLAN *
+c_ls(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+ isoutput = 1;
+
+ return palloc(option);
+}
+
+/*
+ * -name functions --
+ *
+ * True if the basename of the filename being examined
+ * matches pattern using Pattern Matching Notation S3.14
+ */
+int
+f_name(PLAN *plan, FTSENT *entry)
+{
+ char fn[PATH_MAX];
+ const char *name;
+ ssize_t len;
+
+ if (plan->flags & F_LINK) {
+ /*
+ * The below test both avoids obviously useless readlink()
+ * calls and ensures that symlinks with existent target do
+ * not match if symlinks are being followed.
+ * Assumption: fts will stat all symlinks that are to be
+ * followed and will return the stat information.
+ */
+ if (entry->fts_info != FTS_NSOK && entry->fts_info != FTS_SL &&
+ entry->fts_info != FTS_SLNONE)
+ return 0;
+ len = readlink(entry->fts_accpath, fn, sizeof(fn) - 1);
+ if (len == -1)
+ return 0;
+ fn[len] = '\0';
+ name = fn;
+ } else if (entry->fts_namelen == 0) {
+ name = basename(entry->fts_path);
+ } else
+ name = entry->fts_name;
+ return !fnmatch(plan->c_data, name,
+ plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
+}
+
+PLAN *
+c_name(OPTION *option, char ***argvp)
+{
+ char *pattern;
+ PLAN *new;
+
+ pattern = nextarg(option, argvp);
+ new = palloc(option);
+ new->c_data = pattern;
+ return new;
+}
+
+/*
+ * -newer file functions --
+ *
+ * True if the current file has been modified more recently
+ * then the modification time of the file named by the pathname
+ * file.
+ */
+int
+f_newer(PLAN *plan, FTSENT *entry)
+{
+ if (plan->flags & F_TIME_C)
+ return entry->fts_statp->st_ctime > plan->t_data;
+ else if (plan->flags & F_TIME_A)
+ return entry->fts_statp->st_atime > plan->t_data;
+ else if (plan->flags & F_TIME_B)
+ return entry->fts_statp->st_birthtime > plan->t_data;
+ else
+ return entry->fts_statp->st_mtime > plan->t_data;
+}
+
+PLAN *
+c_newer(OPTION *option, char ***argvp)
+{
+ char *fn_or_tspec;
+ PLAN *new;
+ struct stat sb;
+
+ fn_or_tspec = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ /* compare against what */
+ if (option->flags & F_TIME2_T) {
+ new->t_data = get_date(fn_or_tspec);
+ if (new->t_data == (time_t) -1)
+ errx(1, "Can't parse date/time: %s", fn_or_tspec);
+ } else {
+ if (stat(fn_or_tspec, &sb))
+ err(1, "%s", fn_or_tspec);
+ if (option->flags & F_TIME2_C)
+ new->t_data = sb.st_ctime;
+ else if (option->flags & F_TIME2_A)
+ new->t_data = sb.st_atime;
+ else if (option->flags & F_TIME2_B)
+ new->t_data = sb.st_birthtime;
+ else
+ new->t_data = sb.st_mtime;
+ }
+ return new;
+}
+
+/*
+ * -nogroup functions --
+ *
+ * True if file belongs to a user ID for which the equivalent
+ * of the getgrnam() 9.2.1 [POSIX.1] function returns NULL.
+ */
+int
+f_nogroup(PLAN *plan __unused, FTSENT *entry)
+{
+ return group_from_gid(entry->fts_statp->st_gid, 1) == NULL;
+}
+
+PLAN *
+c_nogroup(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+
+ return palloc(option);
+}
+
+/*
+ * -nouser functions --
+ *
+ * True if file belongs to a user ID for which the equivalent
+ * of the getpwuid() 9.2.2 [POSIX.1] function returns NULL.
+ */
+int
+f_nouser(PLAN *plan __unused, FTSENT *entry)
+{
+ return user_from_uid(entry->fts_statp->st_uid, 1) == NULL;
+}
+
+PLAN *
+c_nouser(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions &= ~FTS_NOSTAT;
+
+ return palloc(option);
+}
+
+/*
+ * -path functions --
+ *
+ * True if the path of the filename being examined
+ * matches pattern using Pattern Matching Notation S3.14
+ */
+int
+f_path(PLAN *plan, FTSENT *entry)
+{
+ return !fnmatch(plan->c_data, entry->fts_path,
+ plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
+}
+
+/* c_path is the same as c_name */
+
+/*
+ * -perm functions --
+ *
+ * The mode argument is used to represent file mode bits. If it starts
+ * with a leading digit, it's treated as an octal mode, otherwise as a
+ * symbolic mode.
+ */
+int
+f_perm(PLAN *plan, FTSENT *entry)
+{
+ mode_t mode;
+
+ mode = entry->fts_statp->st_mode &
+ (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO);
+ if (plan->flags & F_ATLEAST)
+ return (plan->m_data | mode) == mode;
+ else if (plan->flags & F_ANY)
+ return (mode & plan->m_data);
+ else
+ return mode == plan->m_data;
+ /* NOTREACHED */
+}
+
+PLAN *
+c_perm(OPTION *option, char ***argvp)
+{
+ char *perm;
+ PLAN *new;
+ mode_t *set;
+
+ perm = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+
+ if (*perm == '-') {
+ new->flags |= F_ATLEAST;
+ ++perm;
+ } else if (*perm == '+') {
+ if ((set = setmode(perm + 1)) != NULL) {
+ new->flags |= F_ANY;
+ ++perm;
+ free(set);
+ }
+ }
+
+ if ((set = setmode(perm)) == NULL)
+ errx(1, "%s: %s: illegal mode string", option->name, perm);
+
+ new->m_data = getmode(set, 0);
+ free(set);
+ return new;
+}
+
+/*
+ * -print functions --
+ *
+ * Always true, causes the current pathname to be written to
+ * standard output.
+ */
+int
+f_print(PLAN *plan __unused, FTSENT *entry)
+{
+ (void)puts(entry->fts_path);
+ return 1;
+}
+
+PLAN *
+c_print(OPTION *option, char ***argvp __unused)
+{
+ isoutput = 1;
+
+ return palloc(option);
+}
+
+/*
+ * -print0 functions --
+ *
+ * Always true, causes the current pathname to be written to
+ * standard output followed by a NUL character
+ */
+int
+f_print0(PLAN *plan __unused, FTSENT *entry)
+{
+ fputs(entry->fts_path, stdout);
+ fputc('\0', stdout);
+ return 1;
+}
+
+/* c_print0 is the same as c_print */
+
+/*
+ * -prune functions --
+ *
+ * Prune a portion of the hierarchy.
+ */
+int
+f_prune(PLAN *plan __unused, FTSENT *entry)
+{
+ if (fts_set(tree, entry, FTS_SKIP))
+ err(1, "%s", entry->fts_path);
+ return 1;
+}
+
+/* c_prune == c_simple */
+
+/*
+ * -regex functions --
+ *
+ * True if the whole path of the file matches pattern using
+ * regular expression.
+ */
+int
+f_regex(PLAN *plan, FTSENT *entry)
+{
+ char *str;
+ int len;
+ regex_t *pre;
+ regmatch_t pmatch;
+ int errcode;
+ char errbuf[LINE_MAX];
+ int matched;
+
+ pre = plan->re_data;
+ str = entry->fts_path;
+ len = strlen(str);
+ matched = 0;
+
+ pmatch.rm_so = 0;
+ pmatch.rm_eo = len;
+
+ errcode = regexec(pre, str, 1, &pmatch, REG_STARTEND);
+
+ if (errcode != 0 && errcode != REG_NOMATCH) {
+ regerror(errcode, pre, errbuf, sizeof errbuf);
+ errx(1, "%s: %s",
+ plan->flags & F_IGNCASE ? "-iregex" : "-regex", errbuf);
+ }
+
+ if (errcode == 0 && pmatch.rm_so == 0 && pmatch.rm_eo == len)
+ matched = 1;
+
+ return matched;
+}
+
+PLAN *
+c_regex(OPTION *option, char ***argvp)
+{
+ PLAN *new;
+ char *pattern;
+ regex_t *pre;
+ int errcode;
+ char errbuf[LINE_MAX];
+
+ if ((pre = malloc(sizeof(regex_t))) == NULL)
+ err(1, NULL);
+
+ pattern = nextarg(option, argvp);
+
+ if ((errcode = regcomp(pre, pattern,
+ regexp_flags | (option->flags & F_IGNCASE ? REG_ICASE : 0))) != 0) {
+ regerror(errcode, pre, errbuf, sizeof errbuf);
+ errx(1, "%s: %s: %s",
+ option->flags & F_IGNCASE ? "-iregex" : "-regex",
+ pattern, errbuf);
+ }
+
+ new = palloc(option);
+ new->re_data = pre;
+
+ return new;
+}
+
+/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or, c_true, c_false */
+
+PLAN *
+c_simple(OPTION *option, char ***argvp __unused)
+{
+ return palloc(option);
+}
+
+/*
+ * -size n[c] functions --
+ *
+ * True if the file size in bytes, divided by an implementation defined
+ * value and rounded up to the next integer, is n. If n is followed by
+ * one of c k M G T P, the size is in bytes, kilobytes,
+ * megabytes, gigabytes, terabytes or petabytes respectively.
+ */
+#define FIND_SIZE 512
+static int divsize = 1;
+
+int
+f_size(PLAN *plan, FTSENT *entry)
+{
+ off_t size;
+
+ size = divsize ? (entry->fts_statp->st_size + FIND_SIZE - 1) /
+ FIND_SIZE : entry->fts_statp->st_size;
+ COMPARE(size, plan->o_data);
+}
+
+PLAN *
+c_size(OPTION *option, char ***argvp)
+{
+ char *size_str;
+ PLAN *new;
+ char endch;
+ off_t scale;
+
+ size_str = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ endch = 'c';
+ new->o_data = find_parsenum(new, option->name, size_str, &endch);
+ if (endch != '\0') {
+ divsize = 0;
+
+ switch (endch) {
+ case 'c': /* characters */
+ scale = 0x1LL;
+ break;
+ case 'k': /* kilobytes 1<<10 */
+ scale = 0x400LL;
+ break;
+ case 'M': /* megabytes 1<<20 */
+ scale = 0x100000LL;
+ break;
+ case 'G': /* gigabytes 1<<30 */
+ scale = 0x40000000LL;
+ break;
+ case 'T': /* terabytes 1<<40 */
+ scale = 0x1000000000LL;
+ break;
+ case 'P': /* petabytes 1<<50 */
+ scale = 0x4000000000000LL;
+ break;
+ default:
+ errx(1, "%s: %s: illegal trailing character",
+ option->name, size_str);
+ break;
+ }
+ if (new->o_data > QUAD_MAX / scale)
+ errx(1, "%s: %s: value too large",
+ option->name, size_str);
+ new->o_data *= scale;
+ }
+ return new;
+}
+
+/*
+ * -type c functions --
+ *
+ * True if the type of the file is c, where c is b, c, d, p, f or w
+ * for block special file, character special file, directory, FIFO,
+ * regular file or whiteout respectively.
+ */
+int
+f_type(PLAN *plan, FTSENT *entry)
+{
+ return (entry->fts_statp->st_mode & S_IFMT) == plan->m_data;
+}
+
+PLAN *
+c_type(OPTION *option, char ***argvp)
+{
+ char *typestring;
+ PLAN *new;
+ mode_t mask;
+
+ typestring = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ switch (typestring[0]) {
+ case 'b':
+ mask = S_IFBLK;
+ break;
+ case 'c':
+ mask = S_IFCHR;
+ break;
+ case 'd':
+ mask = S_IFDIR;
+ break;
+ case 'f':
+ mask = S_IFREG;
+ break;
+ case 'l':
+ mask = S_IFLNK;
+ break;
+ case 'p':
+ mask = S_IFIFO;
+ break;
+ case 's':
+ mask = S_IFSOCK;
+ break;
+#ifdef FTS_WHITEOUT
+ case 'w':
+ mask = S_IFWHT;
+ ftsoptions |= FTS_WHITEOUT;
+ break;
+#endif /* FTS_WHITEOUT */
+ default:
+ errx(1, "%s: %s: unknown type", option->name, typestring);
+ }
+
+ new = palloc(option);
+ new->m_data = mask;
+ return new;
+}
+
+/*
+ * -user uname functions --
+ *
+ * True if the file belongs to the user uname. If uname is numeric and
+ * an equivalent of the getpwnam() S9.2.2 [POSIX.1] function does not
+ * return a valid user name, uname is taken as a user ID.
+ */
+int
+f_user(PLAN *plan, FTSENT *entry)
+{
+ COMPARE(entry->fts_statp->st_uid, plan->u_data);
+}
+
+PLAN *
+c_user(OPTION *option, char ***argvp)
+{
+ char *username;
+ PLAN *new;
+ struct passwd *p;
+ uid_t uid;
+
+ username = nextarg(option, argvp);
+ ftsoptions &= ~FTS_NOSTAT;
+
+ new = palloc(option);
+ p = getpwnam(username);
+ if (p == NULL) {
+ char* cp = username;
+ if( username[0] == '-' || username[0] == '+' )
+ username++;
+ uid = atoi(username);
+ if (uid == 0 && username[0] != '0')
+ errx(1, "%s: %s: no such user", option->name, username);
+ uid = find_parsenum(new, option->name, cp, NULL);
+ } else
+ uid = p->pw_uid;
+
+ new->u_data = uid;
+ return new;
+}
+
+/*
+ * -xdev functions --
+ *
+ * Always true, causes find not to descend past directories that have a
+ * different device ID (st_dev, see stat() S5.6.2 [POSIX.1])
+ */
+PLAN *
+c_xdev(OPTION *option, char ***argvp __unused)
+{
+ ftsoptions |= FTS_XDEV;
+
+ return palloc(option);
+}
+
+/*
+ * ( expression ) functions --
+ *
+ * True if expression is true.
+ */
+int
+f_expr(PLAN *plan, FTSENT *entry)
+{
+ PLAN *p;
+ int state = 0;
+
+ for (p = plan->p_data[0];
+ p && (state = (p->execute)(p, entry)); p = p->next);
+ return state;
+}
+
+/*
+ * f_openparen and f_closeparen nodes are temporary place markers. They are
+ * eliminated during phase 2 of find_formplan() --- the '(' node is converted
+ * to a f_expr node containing the expression and the ')' node is discarded.
+ * The functions themselves are only used as constants.
+ */
+
+int
+f_openparen(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ abort();
+}
+
+int
+f_closeparen(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ abort();
+}
+
+/* c_openparen == c_simple */
+/* c_closeparen == c_simple */
+
+/*
+ * AND operator. Since AND is implicit, no node is allocated.
+ */
+PLAN *
+c_and(OPTION *option __unused, char ***argvp __unused)
+{
+ return NULL;
+}
+
+/*
+ * ! expression functions --
+ *
+ * Negation of a primary; the unary NOT operator.
+ */
+int
+f_not(PLAN *plan, FTSENT *entry)
+{
+ PLAN *p;
+ int state = 0;
+
+ for (p = plan->p_data[0];
+ p && (state = (p->execute)(p, entry)); p = p->next);
+ return !state;
+}
+
+/* c_not == c_simple */
+
+/*
+ * expression -o expression functions --
+ *
+ * Alternation of primaries; the OR operator. The second expression is
+ * not evaluated if the first expression is true.
+ */
+int
+f_or(PLAN *plan, FTSENT *entry)
+{
+ PLAN *p;
+ int state = 0;
+
+ for (p = plan->p_data[0];
+ p && (state = (p->execute)(p, entry)); p = p->next);
+
+ if (state)
+ return 1;
+
+ for (p = plan->p_data[1];
+ p && (state = (p->execute)(p, entry)); p = p->next);
+ return state;
+}
+
+/* c_or == c_simple */
+
+/*
+ * -false
+ *
+ * Always false.
+ */
+int
+f_false(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ return 0;
+}
+
+/* c_false == c_simple */
+
+/*
+ * -quit
+ *
+ * Exits the program
+ */
+int
+f_quit(PLAN *plan __unused, FTSENT *entry __unused)
+{
+ exit(0);
+}
+
+/* c_quit == c_simple */
diff --git a/shell_cmds/find/getdate.y b/shell_cmds/find/getdate.y
new file mode 100644
index 0000000..5a97c2c
--- /dev/null
+++ b/shell_cmds/find/getdate.y
@@ -0,0 +1,961 @@
+%{
+/*
+** Originally written by Steven M. Bellovin <smb@research.att.com> while
+** at the University of North Carolina at Chapel Hill. Later tweaked by
+** a couple of people on Usenet. Completely overhauled by Rich $alz
+** <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
+**
+** This grammar has 10 shift/reduce conflicts.
+**
+** This code is in the public domain and has no copyright.
+*/
+/* SUPPRESS 287 on yaccpar_sccsid *//* Unused static variable */
+/* SUPPRESS 288 on yyerrlab *//* Label unused */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/getdate.y,v 1.7 2010/02/09 21:24:41 ed Exp $");
+
+#include <stdio.h>
+#include <ctype.h>
+
+/* The code at the top of get_date which figures out the offset of the
+ current time zone checks various CPP symbols to see if special
+ tricks are need, but defaults to using the gettimeofday system call.
+ Include <sys/time.h> if that will be used. */
+
+#if defined(vms)
+# include <types.h>
+#else /* defined(vms) */
+# include <sys/types.h>
+# include <sys/time.h>
+#endif /* !defined(vms) */
+
+#if defined (__STDC__) || defined (USG)
+#include <string.h>
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+ That loses on systems that don't provide the function, so we have
+ to redefine it here. */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+#define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+#if defined (__STDC__)
+#include <stdlib.h>
+#endif
+
+/* NOTES on rebuilding getdate.c (particularly for inclusion in CVS
+ releases):
+
+ We don't want to mess with all the portability hassles of alloca.
+ In particular, most (all?) versions of bison will use alloca in
+ their parser. If bison works on your system (e.g. it should work
+ with gcc), then go ahead and use it, but the more general solution
+ is to use byacc instead of bison, which should generate a portable
+ parser. I played with adding "#define alloca dont_use_alloca", to
+ give an error if the parser generator uses alloca (and thus detect
+ unportable getdate.c's), but that seems to cause as many problems
+ as it solves. */
+
+#include <time.h>
+
+#define yyparse getdate_yyparse
+#define yylex getdate_yylex
+#define yyerror getdate_yyerror
+
+static int yyparse(void);
+static int yylex(void);
+static int yyerror(const char *);
+
+time_t get_date(char *);
+
+#define EPOCH 1970
+#define HOUR(x) ((time_t)(x) * 60)
+#define SECSPERDAY (24L * 60L * 60L)
+
+
+/*
+** An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+ const char *name;
+ int type;
+ time_t value;
+} TABLE;
+
+
+/*
+** Daylight-savings mode: on, off, or not yet known.
+*/
+typedef enum _DSTMODE {
+ DSTon, DSToff, DSTmaybe
+} DSTMODE;
+
+/*
+** Meridian: am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+ MERam, MERpm, MER24
+} MERIDIAN;
+
+
+/*
+** Global variables. We could get rid of most of these by using a good
+** union as the yacc stack. (This routine was originally written before
+** yacc had the %union construct.) Maybe someday; right now we only use
+** the %union very rarely.
+*/
+static char *yyInput;
+static DSTMODE yyDSTmode;
+static time_t yyDayOrdinal;
+static time_t yyDayNumber;
+static int yyHaveDate;
+static int yyHaveDay;
+static int yyHaveRel;
+static int yyHaveTime;
+static int yyHaveZone;
+static time_t yyTimezone;
+static time_t yyDay;
+static time_t yyHour;
+static time_t yyMinutes;
+static time_t yyMonth;
+static time_t yySeconds;
+static time_t yyYear;
+static MERIDIAN yyMeridian;
+static time_t yyRelMonth;
+static time_t yyRelSeconds;
+
+%}
+
+%union {
+ time_t Number;
+ enum _MERIDIAN Meridian;
+}
+
+%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
+%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
+
+%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
+%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE
+%type <Meridian> tMERIDIAN o_merid
+
+%%
+
+spec : /* NULL */
+ | spec item
+ ;
+
+item : time {
+ yyHaveTime++;
+ }
+ | zone {
+ yyHaveZone++;
+ }
+ | date {
+ yyHaveDate++;
+ }
+ | day {
+ yyHaveDay++;
+ }
+ | rel {
+ yyHaveRel++;
+ }
+ | number
+ ;
+
+time : tUNUMBER tMERIDIAN {
+ yyHour = $1;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = $2;
+ }
+ | tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = 0;
+ yyMeridian = $4;
+ }
+ | tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = $6;
+ }
+ | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
+ yyHour = $1;
+ yyMinutes = $3;
+ yySeconds = $5;
+ yyMeridian = MER24;
+ yyDSTmode = DSToff;
+ yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
+ }
+ ;
+
+zone : tZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSToff;
+ }
+ | tDAYZONE {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ |
+ tZONE tDST {
+ yyTimezone = $1;
+ yyDSTmode = DSTon;
+ }
+ ;
+
+day : tDAY {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tDAY ',' {
+ yyDayOrdinal = 1;
+ yyDayNumber = $1;
+ }
+ | tUNUMBER tDAY {
+ yyDayOrdinal = $1;
+ yyDayNumber = $2;
+ }
+ ;
+
+date : tUNUMBER '/' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $3;
+ }
+ | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
+ if ($1 >= 100) {
+ yyYear = $1;
+ yyMonth = $3;
+ yyDay = $5;
+ } else {
+ yyMonth = $1;
+ yyDay = $3;
+ yyYear = $5;
+ }
+ }
+ | tUNUMBER tSNUMBER tSNUMBER {
+ /* ISO 8601 format. yyyy-mm-dd. */
+ yyYear = $1;
+ yyMonth = -$2;
+ yyDay = -$3;
+ }
+ | tUNUMBER tMONTH tSNUMBER {
+ /* e.g. 17-JUN-1992. */
+ yyDay = $1;
+ yyMonth = $2;
+ yyYear = -$3;
+ }
+ | tMONTH tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ }
+ | tMONTH tUNUMBER ',' tUNUMBER {
+ yyMonth = $1;
+ yyDay = $2;
+ yyYear = $4;
+ }
+ | tUNUMBER tMONTH {
+ yyMonth = $2;
+ yyDay = $1;
+ }
+ | tUNUMBER tMONTH tUNUMBER {
+ yyMonth = $2;
+ yyDay = $1;
+ yyYear = $3;
+ }
+ ;
+
+rel : relunit tAGO {
+ yyRelSeconds = -yyRelSeconds;
+ yyRelMonth = -yyRelMonth;
+ }
+ | relunit
+ ;
+
+relunit : tUNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tSNUMBER tMINUTE_UNIT {
+ yyRelSeconds += $1 * $2 * 60L;
+ }
+ | tMINUTE_UNIT {
+ yyRelSeconds += $1 * 60L;
+ }
+ | tSNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tUNUMBER tSEC_UNIT {
+ yyRelSeconds += $1;
+ }
+ | tSEC_UNIT {
+ yyRelSeconds++;
+ }
+ | tSNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tUNUMBER tMONTH_UNIT {
+ yyRelMonth += $1 * $2;
+ }
+ | tMONTH_UNIT {
+ yyRelMonth += $1;
+ }
+ ;
+
+number : tUNUMBER {
+ if (yyHaveTime && yyHaveDate && !yyHaveRel)
+ yyYear = $1;
+ else {
+ if($1>10000) {
+ yyHaveDate++;
+ yyDay= ($1)%100;
+ yyMonth= ($1/100)%100;
+ yyYear = $1/10000;
+ }
+ else {
+ yyHaveTime++;
+ if ($1 < 100) {
+ yyHour = $1;
+ yyMinutes = 0;
+ }
+ else {
+ yyHour = $1 / 100;
+ yyMinutes = $1 % 100;
+ }
+ yySeconds = 0;
+ yyMeridian = MER24;
+ }
+ }
+ }
+ ;
+
+o_merid : /* NULL */ {
+ $$ = MER24;
+ }
+ | tMERIDIAN {
+ $$ = $1;
+ }
+ ;
+
+%%
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+ { "january", tMONTH, 1 },
+ { "february", tMONTH, 2 },
+ { "march", tMONTH, 3 },
+ { "april", tMONTH, 4 },
+ { "may", tMONTH, 5 },
+ { "june", tMONTH, 6 },
+ { "july", tMONTH, 7 },
+ { "august", tMONTH, 8 },
+ { "september", tMONTH, 9 },
+ { "sept", tMONTH, 9 },
+ { "october", tMONTH, 10 },
+ { "november", tMONTH, 11 },
+ { "december", tMONTH, 12 },
+ { "sunday", tDAY, 0 },
+ { "monday", tDAY, 1 },
+ { "tuesday", tDAY, 2 },
+ { "tues", tDAY, 2 },
+ { "wednesday", tDAY, 3 },
+ { "wednes", tDAY, 3 },
+ { "thursday", tDAY, 4 },
+ { "thur", tDAY, 4 },
+ { "thurs", tDAY, 4 },
+ { "friday", tDAY, 5 },
+ { "saturday", tDAY, 6 },
+ { NULL, 0, 0 }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+ { "year", tMONTH_UNIT, 12 },
+ { "month", tMONTH_UNIT, 1 },
+ { "fortnight", tMINUTE_UNIT, 14 * 24 * 60 },
+ { "week", tMINUTE_UNIT, 7 * 24 * 60 },
+ { "day", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "hour", tMINUTE_UNIT, 60 },
+ { "minute", tMINUTE_UNIT, 1 },
+ { "min", tMINUTE_UNIT, 1 },
+ { "second", tSEC_UNIT, 1 },
+ { "sec", tSEC_UNIT, 1 },
+ { NULL, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+ { "tomorrow", tMINUTE_UNIT, 1 * 24 * 60 },
+ { "yesterday", tMINUTE_UNIT, -1 * 24 * 60 },
+ { "today", tMINUTE_UNIT, 0 },
+ { "now", tMINUTE_UNIT, 0 },
+ { "last", tUNUMBER, -1 },
+ { "this", tMINUTE_UNIT, 0 },
+ { "next", tUNUMBER, 2 },
+ { "first", tUNUMBER, 1 },
+/* { "second", tUNUMBER, 2 }, */
+ { "third", tUNUMBER, 3 },
+ { "fourth", tUNUMBER, 4 },
+ { "fifth", tUNUMBER, 5 },
+ { "sixth", tUNUMBER, 6 },
+ { "seventh", tUNUMBER, 7 },
+ { "eighth", tUNUMBER, 8 },
+ { "ninth", tUNUMBER, 9 },
+ { "tenth", tUNUMBER, 10 },
+ { "eleventh", tUNUMBER, 11 },
+ { "twelfth", tUNUMBER, 12 },
+ { "ago", tAGO, 1 },
+ { NULL, 0, 0 }
+};
+
+/* The timezone table. */
+/* Some of these are commented out because a time_t can't store a float. */
+static TABLE const TimezoneTable[] = {
+ { "gmt", tZONE, HOUR( 0) }, /* Greenwich Mean */
+ { "ut", tZONE, HOUR( 0) }, /* Universal (Coordinated) */
+ { "utc", tZONE, HOUR( 0) },
+ { "wet", tZONE, HOUR( 0) }, /* Western European */
+ { "bst", tDAYZONE, HOUR( 0) }, /* British Summer */
+ { "wat", tZONE, HOUR( 1) }, /* West Africa */
+ { "at", tZONE, HOUR( 2) }, /* Azores */
+#if 0
+ /* For completeness. BST is also British Summer, and GST is
+ * also Guam Standard. */
+ { "bst", tZONE, HOUR( 3) }, /* Brazil Standard */
+ { "gst", tZONE, HOUR( 3) }, /* Greenland Standard */
+#endif
+#if 0
+ { "nft", tZONE, HOUR(3.5) }, /* Newfoundland */
+ { "nst", tZONE, HOUR(3.5) }, /* Newfoundland Standard */
+ { "ndt", tDAYZONE, HOUR(3.5) }, /* Newfoundland Daylight */
+#endif
+ { "ast", tZONE, HOUR( 4) }, /* Atlantic Standard */
+ { "adt", tDAYZONE, HOUR( 4) }, /* Atlantic Daylight */
+ { "est", tZONE, HOUR( 5) }, /* Eastern Standard */
+ { "edt", tDAYZONE, HOUR( 5) }, /* Eastern Daylight */
+ { "cst", tZONE, HOUR( 6) }, /* Central Standard */
+ { "cdt", tDAYZONE, HOUR( 6) }, /* Central Daylight */
+ { "mst", tZONE, HOUR( 7) }, /* Mountain Standard */
+ { "mdt", tDAYZONE, HOUR( 7) }, /* Mountain Daylight */
+ { "pst", tZONE, HOUR( 8) }, /* Pacific Standard */
+ { "pdt", tDAYZONE, HOUR( 8) }, /* Pacific Daylight */
+ { "yst", tZONE, HOUR( 9) }, /* Yukon Standard */
+ { "ydt", tDAYZONE, HOUR( 9) }, /* Yukon Daylight */
+ { "hst", tZONE, HOUR(10) }, /* Hawaii Standard */
+ { "hdt", tDAYZONE, HOUR(10) }, /* Hawaii Daylight */
+ { "cat", tZONE, HOUR(10) }, /* Central Alaska */
+ { "ahst", tZONE, HOUR(10) }, /* Alaska-Hawaii Standard */
+ { "nt", tZONE, HOUR(11) }, /* Nome */
+ { "idlw", tZONE, HOUR(12) }, /* International Date Line West */
+ { "cet", tZONE, -HOUR(1) }, /* Central European */
+ { "met", tZONE, -HOUR(1) }, /* Middle European */
+ { "mewt", tZONE, -HOUR(1) }, /* Middle European Winter */
+ { "mest", tDAYZONE, -HOUR(1) }, /* Middle European Summer */
+ { "swt", tZONE, -HOUR(1) }, /* Swedish Winter */
+ { "sst", tDAYZONE, -HOUR(1) }, /* Swedish Summer */
+ { "fwt", tZONE, -HOUR(1) }, /* French Winter */
+ { "fst", tDAYZONE, -HOUR(1) }, /* French Summer */
+ { "eet", tZONE, -HOUR(2) }, /* Eastern Europe, USSR Zone 1 */
+ { "bt", tZONE, -HOUR(3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+ { "it", tZONE, -HOUR(3.5) },/* Iran */
+#endif
+ { "zp4", tZONE, -HOUR(4) }, /* USSR Zone 3 */
+ { "zp5", tZONE, -HOUR(5) }, /* USSR Zone 4 */
+#if 0
+ { "ist", tZONE, -HOUR(5.5) },/* Indian Standard */
+#endif
+ { "zp6", tZONE, -HOUR(6) }, /* USSR Zone 5 */
+#if 0
+ /* For completeness. NST is also Newfoundland Stanard, and SST is
+ * also Swedish Summer. */
+ { "nst", tZONE, -HOUR(6.5) },/* North Sumatra */
+ { "sst", tZONE, -HOUR(7) }, /* South Sumatra, USSR Zone 6 */
+#endif /* 0 */
+ { "wast", tZONE, -HOUR(7) }, /* West Australian Standard */
+ { "wadt", tDAYZONE, -HOUR(7) }, /* West Australian Daylight */
+#if 0
+ { "jt", tZONE, -HOUR(7.5) },/* Java (3pm in Cronusland!) */
+#endif
+ { "cct", tZONE, -HOUR(8) }, /* China Coast, USSR Zone 7 */
+ { "jst", tZONE, -HOUR(9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+ { "cast", tZONE, -HOUR(9.5) },/* Central Australian Standard */
+ { "cadt", tDAYZONE, -HOUR(9.5) },/* Central Australian Daylight */
+#endif
+ { "east", tZONE, -HOUR(10) }, /* Eastern Australian Standard */
+ { "eadt", tDAYZONE, -HOUR(10) }, /* Eastern Australian Daylight */
+ { "gst", tZONE, -HOUR(10) }, /* Guam Standard, USSR Zone 9 */
+ { "nzt", tZONE, -HOUR(12) }, /* New Zealand */
+ { "nzst", tZONE, -HOUR(12) }, /* New Zealand Standard */
+ { "nzdt", tDAYZONE, -HOUR(12) }, /* New Zealand Daylight */
+ { "idle", tZONE, -HOUR(12) }, /* International Date Line East */
+ { NULL, 0, 0 }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+ { "a", tZONE, HOUR( 1) },
+ { "b", tZONE, HOUR( 2) },
+ { "c", tZONE, HOUR( 3) },
+ { "d", tZONE, HOUR( 4) },
+ { "e", tZONE, HOUR( 5) },
+ { "f", tZONE, HOUR( 6) },
+ { "g", tZONE, HOUR( 7) },
+ { "h", tZONE, HOUR( 8) },
+ { "i", tZONE, HOUR( 9) },
+ { "k", tZONE, HOUR( 10) },
+ { "l", tZONE, HOUR( 11) },
+ { "m", tZONE, HOUR( 12) },
+ { "n", tZONE, HOUR(- 1) },
+ { "o", tZONE, HOUR(- 2) },
+ { "p", tZONE, HOUR(- 3) },
+ { "q", tZONE, HOUR(- 4) },
+ { "r", tZONE, HOUR(- 5) },
+ { "s", tZONE, HOUR(- 6) },
+ { "t", tZONE, HOUR(- 7) },
+ { "u", tZONE, HOUR(- 8) },
+ { "v", tZONE, HOUR(- 9) },
+ { "w", tZONE, HOUR(-10) },
+ { "x", tZONE, HOUR(-11) },
+ { "y", tZONE, HOUR(-12) },
+ { "z", tZONE, HOUR( 0) },
+ { NULL, 0, 0 }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror(const char *s __unused)
+{
+ return 0;
+}
+
+
+static time_t
+ToSeconds(time_t Hours, time_t Minutes, time_t Seconds, MERIDIAN Meridian)
+{
+ if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
+ return -1;
+ switch (Meridian) {
+ case MER24:
+ if (Hours < 0 || Hours > 23)
+ return -1;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERam:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ if (Hours == 12)
+ Hours = 0;
+ return (Hours * 60L + Minutes) * 60L + Seconds;
+ case MERpm:
+ if (Hours < 1 || Hours > 12)
+ return -1;
+ if (Hours == 12)
+ Hours = 0;
+ return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
+ default:
+ abort ();
+ }
+ /* NOTREACHED */
+}
+
+
+/* Year is either
+ * A negative number, which means to use its absolute value (why?)
+ * A number from 0 to 99, which means a year from 1900 to 1999, or
+ * The actual year (>=100). */
+static time_t
+Convert(time_t Month, time_t Day, time_t Year,
+ time_t Hours, time_t Minutes, time_t Seconds,
+ MERIDIAN Meridian, DSTMODE DSTmode)
+{
+ static int DaysInMonth[12] = {
+ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ time_t tod;
+ time_t Julian;
+ int i;
+
+ if (Year < 0)
+ Year = -Year;
+ if (Year < 69)
+ Year += 2000;
+ else if (Year < 100)
+ Year += 1900;
+ DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
+ ? 29 : 28;
+ /* Checking for 2038 bogusly assumes that time_t is 32 bits. But
+ I'm too lazy to try to check for time_t overflow in another way. */
+ if (Year < EPOCH || Year > 2038
+ || Month < 1 || Month > 12
+ /* Lint fluff: "conversion from long may lose accuracy" */
+ || Day < 1 || Day > DaysInMonth[(int)--Month])
+ return -1;
+
+ for (Julian = Day - 1, i = 0; i < Month; i++)
+ Julian += DaysInMonth[i];
+ for (i = EPOCH; i < Year; i++)
+ Julian += 365 + (i % 4 == 0);
+ Julian *= SECSPERDAY;
+ Julian += yyTimezone * 60L;
+ if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
+ return -1;
+ Julian += tod;
+ if (DSTmode == DSTon
+ || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
+ Julian -= 60 * 60;
+ return Julian;
+}
+
+
+static time_t
+DSTcorrect(time_t Start, time_t Future)
+{
+ time_t StartDay;
+ time_t FutureDay;
+
+ StartDay = (localtime(&Start)->tm_hour + 1) % 24;
+ FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
+ return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
+}
+
+
+static time_t
+RelativeDate(time_t Start, time_t DayOrdinal, time_t DayNumber)
+{
+ struct tm *tm;
+ time_t now;
+
+ now = Start;
+ tm = localtime(&now);
+ now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
+ now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
+ return DSTcorrect(Start, now);
+}
+
+
+static time_t
+RelativeMonth(time_t Start, time_t RelMonth)
+{
+ struct tm *tm;
+ time_t Month;
+ time_t Year;
+
+ if (RelMonth == 0)
+ return 0;
+ tm = localtime(&Start);
+ Month = 12 * (tm->tm_year + 1900) + tm->tm_mon + RelMonth;
+ Year = Month / 12;
+ Month = Month % 12 + 1;
+ return DSTcorrect(Start,
+ Convert(Month, (time_t)tm->tm_mday, Year,
+ (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
+ MER24, DSTmaybe));
+}
+
+
+static int
+LookupWord(char *buff)
+{
+ char *p;
+ char *q;
+ const TABLE *tp;
+ int i;
+ int abbrev;
+
+ /* Make it lowercase. */
+ for (p = buff; *p; p++)
+ if (isupper(*p))
+ *p = tolower(*p);
+
+ if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
+ yylval.Meridian = MERam;
+ return tMERIDIAN;
+ }
+ if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
+ yylval.Meridian = MERpm;
+ return tMERIDIAN;
+ }
+
+ /* See if we have an abbreviation for a month. */
+ if (strlen(buff) == 3)
+ abbrev = 1;
+ else if (strlen(buff) == 4 && buff[3] == '.') {
+ abbrev = 1;
+ buff[3] = '\0';
+ }
+ else
+ abbrev = 0;
+
+ for (tp = MonthDayTable; tp->name; tp++) {
+ if (abbrev) {
+ if (strncmp(buff, tp->name, 3) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+ else if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ if (strcmp(buff, "dst") == 0)
+ return tDST;
+
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Strip off any plural and try the units table again. */
+ i = strlen(buff) - 1;
+ if (buff[i] == 's') {
+ buff[i] = '\0';
+ for (tp = UnitsTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ buff[i] = 's'; /* Put back for "this" in OtherTable. */
+ }
+
+ for (tp = OtherTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ /* Military timezones. */
+ if (buff[1] == '\0' && isalpha(*buff)) {
+ for (tp = MilitaryTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+ }
+
+ /* Drop out any periods and try the timezone table again. */
+ for (i = 0, p = q = buff; *q; q++)
+ if (*q != '.')
+ *p++ = *q;
+ else
+ i++;
+ *p = '\0';
+ if (i)
+ for (tp = TimezoneTable; tp->name; tp++)
+ if (strcmp(buff, tp->name) == 0) {
+ yylval.Number = tp->value;
+ return tp->type;
+ }
+
+ return tID;
+}
+
+
+static int
+yylex(void)
+{
+ char c;
+ char *p;
+ char buff[20];
+ int Count;
+ int sign;
+
+ for ( ; ; ) {
+ while (isspace(*yyInput))
+ yyInput++;
+
+ if (isdigit(c = *yyInput) || c == '-' || c == '+') {
+ if (c == '-' || c == '+') {
+ sign = c == '-' ? -1 : 1;
+ if (!isdigit(*++yyInput))
+ /* skip the '-' sign */
+ continue;
+ }
+ else
+ sign = 0;
+ for (yylval.Number = 0; isdigit(c = *yyInput++); )
+ yylval.Number = 10 * yylval.Number + c - '0';
+ yyInput--;
+ if (sign < 0)
+ yylval.Number = -yylval.Number;
+ return sign ? tSNUMBER : tUNUMBER;
+ }
+ if (isalpha(c)) {
+ for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
+ if (p < &buff[sizeof buff - 1])
+ *p++ = c;
+ *p = '\0';
+ yyInput--;
+ return LookupWord(buff);
+ }
+ if (c != '(')
+ return *yyInput++;
+ Count = 0;
+ do {
+ c = *yyInput++;
+ if (c == '\0')
+ return c;
+ if (c == '(')
+ Count++;
+ else if (c == ')')
+ Count--;
+ } while (Count > 0);
+ }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds. */
+static long
+difftm (struct tm *a, struct tm *b)
+{
+ int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+ int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+ int days = (
+ /* difference in day of year */
+ a->tm_yday - b->tm_yday
+ /* + intervening leap days */
+ + ((ay >> 2) - (by >> 2))
+ - (ay/100 - by/100)
+ + ((ay/100 >> 2) - (by/100 >> 2))
+ /* + difference in years * 365 */
+ + (long)(ay-by) * 365
+ );
+ return (60*(60*(24*days + (a->tm_hour - b->tm_hour))
+ + (a->tm_min - b->tm_min))
+ + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+get_date(char *p)
+{
+ struct tm *tm, *gmt_ptr, gmt;
+ int tzoff;
+ time_t Start;
+ time_t tod;
+ time_t nowtime;
+
+ bzero (&gmt, sizeof(struct tm));
+ yyInput = p;
+
+ (void)time (&nowtime);
+
+ gmt_ptr = gmtime (&nowtime);
+ if (gmt_ptr != NULL)
+ {
+ /* Make a copy, in case localtime modifies *tm (I think
+ that comment now applies to *gmt_ptr, but I am too
+ lazy to dig into how gmtime and locatime allocate the
+ structures they return pointers to). */
+ gmt = *gmt_ptr;
+ }
+
+ if (! (tm = localtime (&nowtime)))
+ return -1;
+
+ if (gmt_ptr != NULL)
+ tzoff = difftm (&gmt, tm) / 60;
+ else
+ /* We are on a system like VMS, where the system clock is
+ in local time and the system has no concept of timezones.
+ Hopefully we can fake this out (for the case in which the
+ user specifies no timezone) by just saying the timezone
+ is zero. */
+ tzoff = 0;
+
+ if(tm->tm_isdst)
+ tzoff += 60;
+
+ tm = localtime(&nowtime);
+ yyYear = tm->tm_year + 1900;
+ yyMonth = tm->tm_mon + 1;
+ yyDay = tm->tm_mday;
+ yyTimezone = tzoff;
+ yyDSTmode = DSTmaybe;
+ yyHour = 0;
+ yyMinutes = 0;
+ yySeconds = 0;
+ yyMeridian = MER24;
+ yyRelSeconds = 0;
+ yyRelMonth = 0;
+ yyHaveDate = 0;
+ yyHaveDay = 0;
+ yyHaveRel = 0;
+ yyHaveTime = 0;
+ yyHaveZone = 0;
+
+ if (yyparse()
+ || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
+ return -1;
+
+ if (yyHaveDate || yyHaveTime || yyHaveDay) {
+ Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
+ yyMeridian, yyDSTmode);
+ if (Start < 0)
+ return -1;
+ }
+ else {
+ Start = nowtime;
+ if (!yyHaveRel)
+ Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
+ }
+
+ Start += yyRelSeconds;
+ Start += RelativeMonth(Start, yyRelMonth);
+
+ if (yyHaveDay && !yyHaveDate) {
+ tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
+ Start += tod;
+ }
+
+ /* Have to do *something* with a legitimate -1 so it's distinguishable
+ * from the error return value. (Alternately could set errno on error.) */
+ return Start == -1 ? 0 : Start;
+}
+
+
+#if defined(TEST)
+
+/* ARGSUSED */
+int
+main(int ac, char *av[])
+{
+ char buff[128];
+ time_t d;
+
+ (void)printf("Enter date, or blank line to exit.\n\t> ");
+ (void)fflush(stdout);
+ while (gets(buff) && buff[0]) {
+ d = get_date(buff);
+ if (d == -1)
+ (void)printf("Bad format - couldn't convert.\n");
+ else
+ (void)printf("%s", ctime(&d));
+ (void)printf("\t> ");
+ (void)fflush(stdout);
+ }
+ exit(0);
+ /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/shell_cmds/find/ls.c b/shell_cmds/find/ls.c
new file mode 100644
index 0000000..f58d969
--- /dev/null
+++ b/shell_cmds/find/ls.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ls.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/ls.c,v 1.23 2011/09/28 18:53:36 ed Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <inttypes.h>
+#include <langinfo.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#undef MAXLOGNAME
+#define MAXLOGNAME 17
+#endif /* __APPLE__ */
+
+#include "find.h"
+
+/* Derived from the print routines in the ls(1) source code. */
+
+static void printlink(char *);
+static void printtime(time_t);
+
+void
+printlong(char *name, char *accpath, struct stat *sb)
+{
+ char modep[15];
+
+ (void)printf("%6lu %8"PRId64" ", (u_long) sb->st_ino, sb->st_blocks);
+ (void)strmode(sb->st_mode, modep);
+ (void)printf("%s %3u %-*s %-*s ", modep, sb->st_nlink, MAXLOGNAME - 1,
+ user_from_uid(sb->st_uid, 0), MAXLOGNAME - 1,
+ group_from_gid(sb->st_gid, 0));
+
+ if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode))
+ (void)printf("%#8jx ", (uintmax_t)sb->st_rdev);
+ else
+ (void)printf("%8"PRId64" ", sb->st_size);
+ printtime(sb->st_mtime);
+ (void)printf("%s", name);
+ if (S_ISLNK(sb->st_mode))
+ printlink(accpath);
+ (void)putchar('\n');
+}
+
+static void
+printtime(time_t ftime)
+{
+ char longstring[80];
+ static time_t lnow;
+ const char *format;
+ static int d_first = -1;
+
+ if (d_first < 0)
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ if (lnow == 0)
+ lnow = time(NULL);
+
+#define SIXMONTHS ((365 / 2) * 86400)
+ if (ftime + SIXMONTHS > lnow && ftime < lnow + SIXMONTHS)
+ /* mmm dd hh:mm || dd mmm hh:mm */
+ format = d_first ? "%e %b %R " : "%b %e %R ";
+ else
+ /* mmm dd yyyy || dd mmm yyyy */
+ format = d_first ? "%e %b %Y " : "%b %e %Y ";
+ strftime(longstring, sizeof(longstring), format, localtime(&ftime));
+ fputs(longstring, stdout);
+}
+
+static void
+printlink(char *name)
+{
+ int lnklen;
+ char path[MAXPATHLEN];
+
+ if ((lnklen = readlink(name, path, MAXPATHLEN - 1)) == -1) {
+ warn("%s", name);
+ return;
+ }
+ path[lnklen] = '\0';
+ (void)printf(" -> %s", path);
+}
diff --git a/shell_cmds/find/main.c b/shell_cmds/find/main.c
new file mode 100644
index 0000000..e95e648
--- /dev/null
+++ b/shell_cmds/find/main.c
@@ -0,0 +1,166 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/main.c,v 1.23 2011/12/10 18:11:06 ed Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "find.h"
+
+time_t now; /* time find was run */
+int dotfd; /* starting directory */
+int ftsoptions; /* options for the ftsopen(3) call */
+int isdeprecated; /* using deprecated syntax */
+int isdepth; /* do directories on post-order visit */
+int isoutput; /* user specified output operator */
+int issort; /* do hierarchies in lexicographical order */
+int isxargs; /* don't permit xargs delimiting chars */
+int mindepth = -1, maxdepth = -1; /* minimum and maximum depth */
+int regexp_flags = REG_BASIC; /* use the "basic" regexp by default*/
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ char **p, **start;
+ int Hflag, Lflag, ch;
+
+ (void)setlocale(LC_ALL, "");
+
+ (void)time(&now); /* initialize the time-of-day */
+
+ p = start = argv;
+ Hflag = Lflag = 0;
+ ftsoptions = FTS_NOSTAT | FTS_PHYSICAL;
+ while ((ch = getopt(argc, argv, "EHLPXdf:sx")) != -1)
+ switch (ch) {
+ case 'E':
+ regexp_flags |= REG_EXTENDED;
+ break;
+ case 'H':
+ Hflag = 1;
+ Lflag = 0;
+ break;
+ case 'L':
+ Lflag = 1;
+ Hflag = 0;
+ break;
+ case 'P':
+ Hflag = Lflag = 0;
+ break;
+ case 'X':
+ isxargs = 1;
+ break;
+ case 'd':
+ isdepth = 1;
+ break;
+ case 'f':
+ *p++ = optarg;
+ break;
+ case 's':
+ issort = 1;
+ break;
+ case 'x':
+ ftsoptions |= FTS_XDEV;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (Hflag)
+ ftsoptions |= FTS_COMFOLLOW;
+ if (Lflag) {
+ ftsoptions &= ~FTS_PHYSICAL;
+ ftsoptions |= FTS_LOGICAL;
+ }
+
+ /*
+ * Find first option to delimit the file list. The first argument
+ * that starts with a -, or is a ! or a ( must be interpreted as a
+ * part of the find expression, according to POSIX .2.
+ */
+ for (; *argv != NULL; *p++ = *argv++) {
+ if (argv[0][0] == '-')
+ break;
+ if ((argv[0][0] == '!' || argv[0][0] == '(') &&
+ argv[0][1] == '\0')
+ break;
+ }
+
+ if (p == start)
+ usage();
+ *p = NULL;
+
+ if ((dotfd = open(".", O_RDONLY, 0)) < 0)
+ err(1, ".");
+
+ exit(find_execute(find_formplan(argv), start));
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n",
+"usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]",
+" find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]");
+ exit(1);
+}
diff --git a/shell_cmds/find/misc.c b/shell_cmds/find/misc.c
new file mode 100644
index 0000000..a165c5e
--- /dev/null
+++ b/shell_cmds/find/misc.c
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)misc.c 8.2 (Berkeley) 4/1/94";
+#else
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/misc.c,v 1.13 2010/12/11 08:32:16 joel Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "find.h"
+
+/*
+ * brace_subst --
+ * Replace occurrences of {} in s1 with s2 and return the result string.
+ */
+void
+brace_subst(char *orig, char **store, char *path, int len)
+{
+ int plen;
+ char ch, *p;
+
+ plen = strlen(path);
+ for (p = *store; (ch = *orig) != '\0'; ++orig)
+ if (ch == '{' && orig[1] == '}') {
+ while ((p - *store) + plen > len)
+ if (!(*store = realloc(*store, len *= 2)))
+ err(1, NULL);
+ memmove(p, path, plen);
+ p += plen;
+ ++orig;
+ } else
+ *p++ = ch;
+ *p = '\0';
+}
+
+/*
+ * queryuser --
+ * print a message to standard error and then read input from standard
+ * input. If the input is an affirmative response (according to the
+ * current locale) then 1 is returned.
+ */
+int
+queryuser(char *argv[])
+{
+ char *p, resp[256];
+
+ (void)fprintf(stderr, "\"%s", *argv);
+ while (*++argv)
+ (void)fprintf(stderr, " %s", *argv);
+ (void)fprintf(stderr, "\"? ");
+ (void)fflush(stderr);
+
+ if (fgets(resp, sizeof(resp), stdin) == NULL)
+ *resp = '\0';
+ if ((p = strchr(resp, '\n')) != NULL)
+ *p = '\0';
+ else {
+ (void)fprintf(stderr, "\n");
+ (void)fflush(stderr);
+ }
+
+ return (rpmatch(resp) == 1);
+}
diff --git a/shell_cmds/find/operator.c b/shell_cmds/find/operator.c
new file mode 100644
index 0000000..1aa851e
--- /dev/null
+++ b/shell_cmds/find/operator.c
@@ -0,0 +1,273 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)operator.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/operator.c,v 1.17 2010/12/11 08:32:16 joel Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fts.h>
+#include <stdio.h>
+
+#include "find.h"
+
+static PLAN *yanknode(PLAN **);
+static PLAN *yankexpr(PLAN **);
+
+/*
+ * yanknode --
+ * destructively removes the top from the plan
+ */
+static PLAN *
+yanknode(PLAN **planp)
+{
+ PLAN *node; /* top node removed from the plan */
+
+ if ((node = (*planp)) == NULL)
+ return (NULL);
+ (*planp) = (*planp)->next;
+ node->next = NULL;
+ return (node);
+}
+
+/*
+ * yankexpr --
+ * Removes one expression from the plan. This is used mainly by
+ * paren_squish. In comments below, an expression is either a
+ * simple node or a f_expr node containing a list of simple nodes.
+ */
+static PLAN *
+yankexpr(PLAN **planp)
+{
+ PLAN *next; /* temp node holding subexpression results */
+ PLAN *node; /* pointer to returned node or expression */
+ PLAN *tail; /* pointer to tail of subplan */
+ PLAN *subplan; /* pointer to head of ( ) expression */
+
+ /* first pull the top node from the plan */
+ if ((node = yanknode(planp)) == NULL)
+ return (NULL);
+
+ /*
+ * If the node is an '(' then we recursively slurp up expressions
+ * until we find its associated ')'. If it's a closing paren we
+ * just return it and unwind our recursion; all other nodes are
+ * complete expressions, so just return them.
+ */
+ if (node->execute == f_openparen)
+ for (tail = subplan = NULL;;) {
+ if ((next = yankexpr(planp)) == NULL)
+ errx(1, "(: missing closing ')'");
+ /*
+ * If we find a closing ')' we store the collected
+ * subplan in our '(' node and convert the node to
+ * a f_expr. The ')' we found is ignored. Otherwise,
+ * we just continue to add whatever we get to our
+ * subplan.
+ */
+ if (next->execute == f_closeparen) {
+ if (subplan == NULL)
+ errx(1, "(): empty inner expression");
+ node->p_data[0] = subplan;
+ node->execute = f_expr;
+ break;
+ } else {
+ if (subplan == NULL)
+ tail = subplan = next;
+ else {
+ tail->next = next;
+ tail = next;
+ }
+ tail->next = NULL;
+ }
+ }
+ return (node);
+}
+
+/*
+ * paren_squish --
+ * replaces "parenthesized" plans in our search plan with "expr" nodes.
+ */
+PLAN *
+paren_squish(PLAN *plan)
+{
+ PLAN *expr; /* pointer to next expression */
+ PLAN *tail; /* pointer to tail of result plan */
+ PLAN *result; /* pointer to head of result plan */
+
+ result = tail = NULL;
+
+ /*
+ * the basic idea is to have yankexpr do all our work and just
+ * collect its results together.
+ */
+ while ((expr = yankexpr(&plan)) != NULL) {
+ /*
+ * if we find an unclaimed ')' it means there is a missing
+ * '(' someplace.
+ */
+ if (expr->execute == f_closeparen)
+ errx(1, "): no beginning '('");
+
+ /* add the expression to our result plan */
+ if (result == NULL)
+ tail = result = expr;
+ else {
+ tail->next = expr;
+ tail = expr;
+ }
+ tail->next = NULL;
+ }
+ return (result);
+}
+
+/*
+ * not_squish --
+ * compresses "!" expressions in our search plan.
+ */
+PLAN *
+not_squish(PLAN *plan)
+{
+ PLAN *next; /* next node being processed */
+ PLAN *node; /* temporary node used in f_not processing */
+ PLAN *tail; /* pointer to tail of result plan */
+ PLAN *result; /* pointer to head of result plan */
+
+ tail = result = NULL;
+
+ while ((next = yanknode(&plan))) {
+ /*
+ * if we encounter a ( expression ) then look for nots in
+ * the expr subplan.
+ */
+ if (next->execute == f_expr)
+ next->p_data[0] = not_squish(next->p_data[0]);
+
+ /*
+ * if we encounter a not, then snag the next node and place
+ * it in the not's subplan. As an optimization we compress
+ * several not's to zero or one not.
+ */
+ if (next->execute == f_not) {
+ int notlevel = 1;
+
+ node = yanknode(&plan);
+ while (node != NULL && node->execute == f_not) {
+ ++notlevel;
+ node = yanknode(&plan);
+ }
+ if (node == NULL)
+ errx(1, "!: no following expression");
+ if (node->execute == f_or)
+ errx(1, "!: nothing between ! and -o");
+ /*
+ * If we encounter ! ( expr ) then look for nots in
+ * the expr subplan.
+ */
+ if (node->execute == f_expr)
+ node->p_data[0] = not_squish(node->p_data[0]);
+ if (notlevel % 2 != 1)
+ next = node;
+ else
+ next->p_data[0] = node;
+ }
+
+ /* add the node to our result plan */
+ if (result == NULL)
+ tail = result = next;
+ else {
+ tail->next = next;
+ tail = next;
+ }
+ tail->next = NULL;
+ }
+ return (result);
+}
+
+/*
+ * or_squish --
+ * compresses -o expressions in our search plan.
+ */
+PLAN *
+or_squish(PLAN *plan)
+{
+ PLAN *next; /* next node being processed */
+ PLAN *tail; /* pointer to tail of result plan */
+ PLAN *result; /* pointer to head of result plan */
+
+ tail = result = next = NULL;
+
+ while ((next = yanknode(&plan)) != NULL) {
+ /*
+ * if we encounter a ( expression ) then look for or's in
+ * the expr subplan.
+ */
+ if (next->execute == f_expr)
+ next->p_data[0] = or_squish(next->p_data[0]);
+
+ /* if we encounter a not then look for or's in the subplan */
+ if (next->execute == f_not)
+ next->p_data[0] = or_squish(next->p_data[0]);
+
+ /*
+ * if we encounter an or, then place our collected plan in the
+ * or's first subplan and then recursively collect the
+ * remaining stuff into the second subplan and return the or.
+ */
+ if (next->execute == f_or) {
+ if (result == NULL)
+ errx(1, "-o: no expression before -o");
+ next->p_data[0] = result;
+ next->p_data[1] = or_squish(plan);
+ if (next->p_data[1] == NULL)
+ errx(1, "-o: no expression after -o");
+ return (next);
+ }
+
+ /* add the node to our result plan */
+ if (result == NULL)
+ tail = result = next;
+ else {
+ tail->next = next;
+ tail = next;
+ }
+ tail->next = NULL;
+ }
+ return (result);
+}
diff --git a/shell_cmds/find/option.c b/shell_cmds/find/option.c
new file mode 100644
index 0000000..5771da4
--- /dev/null
+++ b/shell_cmds/find/option.c
@@ -0,0 +1,201 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Cimarron D. Taylor of the University of California, Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+/*
+static char sccsid[] = "@(#)option.c 8.2 (Berkeley) 4/16/94";
+*/
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/find/option.c,v 1.32 2011/05/27 22:14:49 jilles Exp $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fts.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "find.h"
+
+static int typecompare(const void *, const void *);
+
+/* NB: the following table must be sorted lexically. */
+/* Options listed with C++ comments are in gnu find, but not our find */
+static OPTION const options[] = {
+ { "!", c_simple, f_not, 0 },
+ { "(", c_simple, f_openparen, 0 },
+ { ")", c_simple, f_closeparen, 0 },
+ { "-Bmin", c_Xmin, f_Xmin, F_TIME_B },
+ { "-Bnewer", c_newer, f_newer, F_TIME_B },
+ { "-Btime", c_Xtime, f_Xtime, F_TIME_B },
+ { "-a", c_and, NULL, 0 },
+ { "-acl", c_acl, f_acl, 0 },
+ { "-amin", c_Xmin, f_Xmin, F_TIME_A },
+ { "-and", c_and, NULL, 0 },
+ { "-anewer", c_newer, f_newer, F_TIME_A },
+ { "-atime", c_Xtime, f_Xtime, F_TIME_A },
+ { "-cmin", c_Xmin, f_Xmin, F_TIME_C },
+ { "-cnewer", c_newer, f_newer, F_TIME_C },
+ { "-ctime", c_Xtime, f_Xtime, F_TIME_C },
+ { "-d", c_depth, f_depth, 0 },
+// -daystart
+ { "-delete", c_delete, f_delete, 0 },
+ { "-depth", c_depth, f_depth, 0 },
+ { "-empty", c_empty, f_empty, 0 },
+ { "-exec", c_exec, f_exec, 0 },
+ { "-execdir", c_exec, f_exec, F_EXECDIR },
+ { "-false", c_simple, f_false, 0 },
+ { "-flags", c_flags, f_flags, 0 },
+// -fls
+ { "-follow", c_follow, f_always_true, 0 },
+// -fprint
+// -fprint0
+// -fprintf
+ { "-fstype", c_fstype, f_fstype, 0 },
+ { "-gid", c_group, f_group, 0 },
+ { "-group", c_group, f_group, 0 },
+ { "-ignore_readdir_race",c_simple, f_always_true,0 },
+ { "-ilname", c_name, f_name, F_LINK | F_IGNCASE },
+ { "-iname", c_name, f_name, F_IGNCASE },
+ { "-inum", c_inum, f_inum, 0 },
+ { "-ipath", c_name, f_path, F_IGNCASE },
+ { "-iregex", c_regex, f_regex, F_IGNCASE },
+ { "-iwholename",c_name, f_path, F_IGNCASE },
+ { "-links", c_links, f_links, 0 },
+ { "-lname", c_name, f_name, F_LINK },
+ { "-ls", c_ls, f_ls, 0 },
+ { "-maxdepth", c_mXXdepth, f_always_true, F_MAXDEPTH },
+ { "-mindepth", c_mXXdepth, f_always_true, 0 },
+ { "-mmin", c_Xmin, f_Xmin, 0 },
+ { "-mnewer", c_newer, f_newer, 0 },
+ { "-mount", c_xdev, f_always_true, 0 },
+ { "-mtime", c_Xtime, f_Xtime, 0 },
+ { "-name", c_name, f_name, 0 },
+ { "-newer", c_newer, f_newer, 0 },
+ { "-newerBB", c_newer, f_newer, F_TIME_B | F_TIME2_B },
+ { "-newerBa", c_newer, f_newer, F_TIME_B | F_TIME2_A },
+ { "-newerBc", c_newer, f_newer, F_TIME_B | F_TIME2_C },
+ { "-newerBm", c_newer, f_newer, F_TIME_B },
+ { "-newerBt", c_newer, f_newer, F_TIME_B | F_TIME2_T },
+ { "-neweraB", c_newer, f_newer, F_TIME_A | F_TIME2_B },
+ { "-neweraa", c_newer, f_newer, F_TIME_A | F_TIME2_A },
+ { "-newerac", c_newer, f_newer, F_TIME_A | F_TIME2_C },
+ { "-neweram", c_newer, f_newer, F_TIME_A },
+ { "-newerat", c_newer, f_newer, F_TIME_A | F_TIME2_T },
+ { "-newercB", c_newer, f_newer, F_TIME_C | F_TIME2_B },
+ { "-newerca", c_newer, f_newer, F_TIME_C | F_TIME2_A },
+ { "-newercc", c_newer, f_newer, F_TIME_C | F_TIME2_C },
+ { "-newercm", c_newer, f_newer, F_TIME_C },
+ { "-newerct", c_newer, f_newer, F_TIME_C | F_TIME2_T },
+ { "-newermB", c_newer, f_newer, F_TIME2_B },
+ { "-newerma", c_newer, f_newer, F_TIME2_A },
+ { "-newermc", c_newer, f_newer, F_TIME2_C },
+ { "-newermm", c_newer, f_newer, 0 },
+ { "-newermt", c_newer, f_newer, F_TIME2_T },
+ { "-nogroup", c_nogroup, f_nogroup, 0 },
+ { "-noignore_readdir_race",c_simple, f_always_true,0 },
+ { "-noleaf", c_simple, f_always_true, 0 },
+ { "-not", c_simple, f_not, 0 },
+ { "-nouser", c_nouser, f_nouser, 0 },
+ { "-o", c_simple, f_or, 0 },
+ { "-ok", c_exec, f_exec, F_NEEDOK },
+ { "-okdir", c_exec, f_exec, F_NEEDOK | F_EXECDIR },
+ { "-or", c_simple, f_or, 0 },
+ { "-path", c_name, f_path, 0 },
+ { "-perm", c_perm, f_perm, 0 },
+ { "-print", c_print, f_print, 0 },
+ { "-print0", c_print, f_print0, 0 },
+// -printf
+ { "-prune", c_simple, f_prune, 0 },
+ { "-quit", c_simple, f_quit, 0 },
+ { "-regex", c_regex, f_regex, 0 },
+ { "-samefile", c_samefile, f_inum, 0 },
+ { "-size", c_size, f_size, 0 },
+ { "-true", c_simple, f_always_true, 0 },
+ { "-type", c_type, f_type, 0 },
+ { "-uid", c_user, f_user, 0 },
+ { "-user", c_user, f_user, 0 },
+ { "-wholename", c_name, f_path, 0 },
+#ifdef __APPLE__
+ { "-xattr", c_simple, f_xattr, 0 },
+ { "-xattrname", c_name, f_xattrname, 0 },
+#endif /* __APPLE__ */
+ { "-xdev", c_xdev, f_always_true, 0 },
+// -xtype
+};
+
+/*
+ * find_create --
+ * create a node corresponding to a command line argument.
+ *
+ * TODO:
+ * add create/process function pointers to node, so we can skip
+ * this switch stuff.
+ */
+PLAN *
+find_create(char ***argvp)
+{
+ OPTION *p;
+ PLAN *new;
+ char **argv;
+
+ argv = *argvp;
+
+ if ((p = lookup_option(*argv)) == NULL)
+ errx(1, "%s: unknown primary or operator", *argv);
+ ++argv;
+
+ new = (p->create)(p, &argv);
+ *argvp = argv;
+ return (new);
+}
+
+OPTION *
+lookup_option(const char *name)
+{
+ OPTION tmp;
+
+ tmp.name = name;
+ return ((OPTION *)bsearch(&tmp, options,
+ sizeof(options)/sizeof(OPTION), sizeof(OPTION), typecompare));
+}
+
+static int
+typecompare(const void *a, const void *b)
+{
+ return (strcmp(((const OPTION *)a)->name, ((const OPTION *)b)->name));
+}
diff --git a/shell_cmds/getopt/getopt.1 b/shell_cmds/getopt/getopt.1
new file mode 100644
index 0000000..793c87a
--- /dev/null
+++ b/shell_cmds/getopt/getopt.1
@@ -0,0 +1,134 @@
+.\" $FreeBSD: src/usr.bin/getopt/getopt.1,v 1.15 2002/04/19 23:43:02 charnier Exp $
+.\"
+.Dd April 3, 1999
+.Dt GETOPT 1
+.Os
+.Sh NAME
+.Nm getopt
+.Nd parse command options
+.Sh SYNOPSIS
+.Nm args=\`getopt Ar optstring $*\`
+; errcode=$?; set \-\- $args
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to break up options in command lines for easy parsing by
+shell procedures, and to check for legal options.
+.Ar Optstring
+is a string of recognized option letters (see
+.Xr getopt 3 ) ;
+if a letter is followed by a colon, the option
+is expected to have an argument which may or may not be
+separated from it by white space.
+The special option
+.Ql \-\-
+is used to delimit the end of the options.
+The
+.Nm
+utility will place
+.Ql \-\-
+in the arguments at the end of the options,
+or recognize it if used explicitly.
+The shell arguments
+(\fB$1 $2\fR ...) are reset so that each option is
+preceded by a
+.Ql \-
+and in its own shell argument;
+each option argument is also in its own shell argument.
+.Sh EXAMPLES
+The following code fragment shows how one might process the arguments
+for a command that can take the options
+.Fl a
+and
+.Fl b ,
+and the option
+.Fl o ,
+which requires an argument.
+.Pp
+.Bd -literal -offset indent
+args=\`getopt abo: $*\`
+# you should not use \`getopt abo: "$@"\` since that would parse
+# the arguments differently from what the set command below does.
+if [ $? != 0 ]
+then
+ echo 'Usage: ...'
+ exit 2
+fi
+set \-\- $args
+# You cannot use the set command with a backquoted getopt directly,
+# since the exit code from getopt would be shadowed by those of set,
+# which is zero by definition.
+for i
+do
+ case "$i"
+ in
+ \-a|\-b)
+ echo flag $i set; sflags="${i#-}$sflags";
+ shift;;
+ \-o)
+ echo oarg is "'"$2"'"; oarg="$2"; shift;
+ shift;;
+ \-\-)
+ shift; break;;
+ esac
+done
+echo single-char flags: "'"$sflags"'"
+echo oarg is "'"$oarg"'"
+.Ed
+.Pp
+This code will accept any of the following as equivalent:
+.Pp
+.Bd -literal -offset indent
+cmd \-aoarg file file
+cmd \-a \-o arg file file
+cmd \-oarg -a file file
+cmd \-a \-oarg \-\- file file
+.Pp
+.Ed
+.Sh SEE ALSO
+.Xr sh 1 ,
+.Xr getopt 3
+.Sh DIAGNOSTICS
+The
+.Nm
+utility prints an error message on the standard error output and exits with
+status > 0 when it encounters an option letter not included in
+.Ar optstring .
+.Sh HISTORY
+Written by
+.An Henry Spencer ,
+working from a Bell Labs manual page.
+Behavior believed identical to the Bell version.
+Example changed in
+.Fx
+version 3.2 and 4.0.
+.Sh BUGS
+Whatever
+.Xr getopt 3
+has.
+.Pp
+Arguments containing white space or embedded shell metacharacters
+generally will not survive intact; this looks easy to fix but
+isn't. People trying to fix
+.Nm
+or the example in this manpage should check the history of this file
+in
+.Fx .
+.Pp
+The error message for an invalid option is identified as coming
+from
+.Nm
+rather than from the shell procedure containing the invocation
+of
+.Nm ;
+this again is hard to fix.
+.Pp
+The precise best way to use the
+.Nm set
+command to set the arguments without disrupting the value(s) of
+shell options varies from one shell version to another.
+.Pp
+Each shellscript has to carry complex code to parse arguments halfway
+correcty (like the example presented here). A better getopt-like tool
+would move much of the complexity into the tool and keep the client
+shell scripts simpler.
diff --git a/shell_cmds/getopt/getopt.c b/shell_cmds/getopt/getopt.c
new file mode 100644
index 0000000..5e8a743
--- /dev/null
+++ b/shell_cmds/getopt/getopt.c
@@ -0,0 +1,32 @@
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/getopt/getopt.c,v 1.10 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int status = 0;
+
+ optind = 2; /* Past the program name and the option letters. */
+ while ((c = getopt(argc, argv, argv[1])) != -1)
+ switch (c) {
+ case '?':
+ status = 1; /* getopt routine gave message */
+ break;
+ default:
+ if (optarg != NULL)
+ printf(" -%c %s", c, optarg);
+ else
+ printf(" -%c", c);
+ break;
+ }
+ printf(" --");
+ for (; optind < argc; optind++)
+ printf(" %s", argv[optind]);
+ printf("\n");
+ return status;
+}
diff --git a/shell_cmds/hexdump/conv.c b/shell_cmds/hexdump/conv.c
new file mode 100644
index 0000000..9eebc51
--- /dev/null
+++ b/shell_cmds/hexdump/conv.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char sccsid[] = "@(#)conv.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "hexdump.h"
+
+void
+conv_c(PR *pr, u_char *p, size_t bufsize)
+{
+ char buf[10];
+ char const *str;
+ wchar_t wc;
+ size_t clen, oclen;
+ int converr, pad, width;
+ u_char peekbuf[MB_LEN_MAX];
+
+ if (pr->mbleft > 0) {
+ str = "**";
+ pr->mbleft--;
+ goto strpr;
+ }
+
+ switch(*p) {
+ case '\0':
+ str = "\\0";
+ goto strpr;
+ /* case '\a': */
+ case '\007':
+ str = "\\a";
+ goto strpr;
+ case '\b':
+ str = "\\b";
+ goto strpr;
+ case '\f':
+ str = "\\f";
+ goto strpr;
+ case '\n':
+ str = "\\n";
+ goto strpr;
+ case '\r':
+ str = "\\r";
+ goto strpr;
+ case '\t':
+ str = "\\t";
+ goto strpr;
+ case '\v':
+ str = "\\v";
+ goto strpr;
+ default:
+ break;
+ }
+ /*
+ * Multibyte characters are disabled for hexdump(1) for backwards
+ * compatibility and consistency (none of its other output formats
+ * recognize them correctly).
+ */
+ converr = 0;
+ if (odmode && MB_CUR_MAX > 1) {
+ oclen = 0;
+retry:
+ clen = mbrtowc(&wc, (const char *)p, bufsize, &pr->mbstate);
+ if (clen == 0)
+ clen = 1;
+ else if (clen == (size_t)-1 || (clen == (size_t)-2 &&
+ p == peekbuf)) {
+ memset(&pr->mbstate, 0, sizeof(pr->mbstate));
+ wc = *p;
+ clen = 1;
+ converr = 1;
+ } else if (clen == (size_t)-2) {
+ /*
+ * Incomplete character; peek ahead and see if we
+ * can complete it.
+ */
+ oclen = bufsize;
+ bufsize = peek(p = peekbuf, MB_CUR_MAX);
+ goto retry;
+ }
+ clen += oclen;
+ } else {
+ wc = *p;
+ clen = 1;
+ }
+ if (!converr && iswprint(wc)) {
+ if (!odmode) {
+ *pr->cchar = 'c';
+ (void)printf(pr->fmt, (int)wc);
+ } else {
+ *pr->cchar = 'C';
+ assert(strcmp(pr->fmt, "%3C") == 0);
+ width = wcwidth(wc);
+ assert(width >= 0);
+ pad = 3 - width;
+ if (pad < 0)
+ pad = 0;
+ (void)printf("%*s%C", pad, "", wc);
+ pr->mbleft = clen - 1;
+ }
+ } else {
+ (void)sprintf(buf, "%03o", (int)*p);
+ str = buf;
+strpr: *pr->cchar = 's';
+ (void)printf(pr->fmt, str);
+ }
+}
+
+void
+conv_u(PR *pr, u_char *p)
+{
+ static char const * list[] = {
+ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
+ "bs", "ht", "lf", "vt", "ff", "cr", "so", "si",
+ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
+ "can", "em", "sub", "esc", "fs", "gs", "rs", "us",
+ };
+
+ /* od used nl, not lf */
+ if (*p <= 0x1f) {
+ *pr->cchar = 's';
+ if (odmode && *p == 0x0a)
+ (void)printf(pr->fmt, "nl");
+ else
+ (void)printf(pr->fmt, list[*p]);
+ } else if (*p == 0x7f) {
+ *pr->cchar = 's';
+ (void)printf(pr->fmt, "del");
+ } else if (odmode && *p == 0x20) { /* od replaced space with sp */
+ *pr->cchar = 's';
+ (void)printf(pr->fmt, " sp");
+ } else if (isprint(*p)) {
+ *pr->cchar = 'c';
+ (void)printf(pr->fmt, *p);
+ } else {
+ *pr->cchar = 'x';
+ (void)printf(pr->fmt, (int)*p);
+ }
+}
diff --git a/shell_cmds/hexdump/display.c b/shell_cmds/hexdump/display.c
new file mode 100644
index 0000000..978a50c
--- /dev/null
+++ b/shell_cmds/hexdump/display.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)display.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/display.c,v 1.19 2004/07/11 01:11:12 tjr Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "hexdump.h"
+
+enum _vflag vflag = FIRST;
+
+static off_t address; /* address/offset in stream */
+static off_t eaddress; /* end address */
+
+static __inline void print(PR *, u_char *);
+
+void
+display(void)
+{
+ FS *fs;
+ FU *fu;
+ PR *pr;
+ int cnt;
+ u_char *bp;
+ off_t saveaddress;
+ u_char savech=0, *savebp;
+
+ while ((bp = get()))
+ for (fs = fshead, savebp = bp, saveaddress = address; fs;
+ fs = fs->nextfs, bp = savebp, address = saveaddress)
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->flags&F_IGNORE)
+ break;
+ for (cnt = fu->reps; cnt; --cnt)
+ for (pr = fu->nextpr; pr; address += pr->bcnt,
+ bp += pr->bcnt, pr = pr->nextpr) {
+ if (eaddress && address >= eaddress &&
+ !(pr->flags & (F_TEXT|F_BPAD)))
+ bpad(pr);
+ if (cnt == 1 && pr->nospace) {
+ savech = *pr->nospace;
+ *pr->nospace = '\0';
+ }
+ print(pr, bp);
+ if (cnt == 1 && pr->nospace)
+ *pr->nospace = savech;
+ }
+ }
+ if (endfu) {
+ /*
+ * If eaddress not set, error or file size was multiple of
+ * blocksize, and no partial block ever found.
+ */
+ if (!eaddress) {
+ if (!address) {
+ return;
+ }
+ eaddress = address;
+ }
+ for (pr = endfu->nextpr; pr; pr = pr->nextpr)
+ switch(pr->flags) {
+ case F_ADDRESS:
+ (void)printf(pr->fmt, (quad_t)eaddress);
+ break;
+ case F_TEXT:
+ (void)printf("%s", pr->fmt);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static __inline void
+print(PR *pr, u_char *bp)
+{
+ long double ldbl;
+ double f8;
+ float f4;
+ int16_t s2;
+ int8_t s8;
+ int32_t s4;
+ u_int16_t u2;
+ u_int32_t u4;
+ u_int64_t u8;
+
+ switch(pr->flags) {
+ case F_ADDRESS:
+ (void)printf(pr->fmt, (quad_t)address);
+ break;
+ case F_BPAD:
+ (void)printf(pr->fmt, "");
+ break;
+ case F_C:
+ conv_c(pr, bp, eaddress ? eaddress - address :
+ blocksize - address % blocksize);
+ break;
+ case F_CHAR:
+ (void)printf(pr->fmt, *bp);
+ break;
+ case F_DBL:
+ switch(pr->bcnt) {
+ case 4:
+ bcopy(bp, &f4, sizeof(f4));
+ (void)printf(pr->fmt, f4);
+ break;
+ case 8:
+ bcopy(bp, &f8, sizeof(f8));
+ (void)printf(pr->fmt, f8);
+ break;
+ default:
+ if (pr->bcnt == sizeof(long double)) {
+ bcopy(bp, &ldbl, sizeof(ldbl));
+ (void)printf(pr->fmt, ldbl);
+ }
+ break;
+ }
+ break;
+ case F_INT:
+ switch(pr->bcnt) {
+ case 1:
+ (void)printf(pr->fmt, (quad_t)(signed char)*bp);
+ break;
+ case 2:
+ bcopy(bp, &s2, sizeof(s2));
+ (void)printf(pr->fmt, (quad_t)s2);
+ break;
+ case 4:
+ bcopy(bp, &s4, sizeof(s4));
+ (void)printf(pr->fmt, (quad_t)s4);
+ break;
+ case 8:
+ bcopy(bp, &s8, sizeof(s8));
+ (void)printf(pr->fmt, s8);
+ break;
+ }
+ break;
+ case F_P:
+ (void)printf(pr->fmt, isprint(*bp) && isascii(*bp) ? *bp : '.');
+ break;
+ case F_STR:
+ (void)printf(pr->fmt, (char *)bp);
+ break;
+ case F_TEXT:
+ (void)printf("%s", pr->fmt);
+ break;
+ case F_U:
+ conv_u(pr, bp);
+ break;
+ case F_UINT:
+ switch(pr->bcnt) {
+ case 1:
+ (void)printf(pr->fmt, (u_quad_t)*bp);
+ break;
+ case 2:
+ bcopy(bp, &u2, sizeof(u2));
+ (void)printf(pr->fmt, (u_quad_t)u2);
+ break;
+ case 4:
+ bcopy(bp, &u4, sizeof(u4));
+ (void)printf(pr->fmt, (u_quad_t)u4);
+ break;
+ case 8:
+ bcopy(bp, &u8, sizeof(u8));
+ (void)printf(pr->fmt, u8);
+ break;
+ }
+ break;
+ }
+}
+
+void
+bpad(PR *pr)
+{
+ static char const *spec = " -0+#";
+ char *p1, *p2;
+
+ /*
+ * Remove all conversion flags; '-' is the only one valid
+ * with %s, and it's not useful here.
+ */
+ pr->flags = F_BPAD;
+ pr->cchar[0] = 's';
+ pr->cchar[1] = '\0';
+ for (p1 = pr->fmt; *p1 != '%'; ++p1);
+ for (p2 = ++p1; *p1 && index(spec, *p1); ++p1);
+ while ((*p2++ = *p1++));
+}
+
+static char **_argv;
+
+u_char *
+get(void)
+{
+ static int ateof = 1;
+ static u_char *curp, *savp;
+ int n;
+ int need, nread;
+ int valid_save = 0;
+ u_char *tmpp;
+
+ if (!curp) {
+ if ((curp = calloc(1, blocksize)) == NULL)
+ err(1, NULL);
+ if ((savp = calloc(1, blocksize)) == NULL)
+ err(1, NULL);
+ } else {
+ tmpp = curp;
+ curp = savp;
+ savp = tmpp;
+ address += blocksize;
+ valid_save = 1;
+ }
+ for (need = blocksize, nread = 0;;) {
+ /*
+ * if read the right number of bytes, or at EOF for one file,
+ * and no other files are available, zero-pad the rest of the
+ * block and set the end flag.
+ */
+ if (!length || (ateof && !next((char **)NULL))) {
+ if (odmode && address < skip)
+ errx(1, "cannot skip past end of input");
+ if (need == blocksize)
+ return((u_char *)NULL);
+ /*
+ * XXX bcmp() is not quite right in the presence
+ * of multibyte characters.
+ */
+#ifdef __APPLE__
+ /* 5650060 */
+ if (!need && vflag != ALL &&
+#else
+ if (vflag != ALL &&
+#endif
+ valid_save &&
+ bcmp(curp, savp, nread) == 0) {
+ if (vflag != DUP)
+ (void)printf("*\n");
+ return((u_char *)NULL);
+ }
+ bzero((char *)curp + nread, need);
+ eaddress = address + nread;
+ if (length == 0)
+ lseek(STDIN_FILENO, ftell(stdin), SEEK_SET); /* rewind stdin for next process */
+ return(curp);
+ }
+ n = fread((char *)curp + nread, sizeof(u_char),
+ length == -1 ? need : MIN(length, need), stdin);
+ if (!n) {
+ if (ferror(stdin))
+ warn("%s", _argv[-1]);
+ ateof = 1;
+ continue;
+ }
+ ateof = 0;
+ if (length != -1)
+ length -= n;
+ if (!(need -= n)) {
+ /*
+ * XXX bcmp() is not quite right in the presence
+ * of multibyte characters.
+ */
+ if (vflag == ALL || vflag == FIRST ||
+ valid_save == 0 ||
+ bcmp(curp, savp, blocksize) != 0) {
+ if (vflag == DUP || vflag == FIRST)
+ vflag = WAIT;
+ return(curp);
+ }
+ if (vflag == WAIT)
+ (void)printf("*\n");
+ vflag = DUP;
+ address += blocksize;
+ need = blocksize;
+ nread = 0;
+ }
+ else
+ nread += n;
+ }
+}
+
+size_t
+peek(u_char *buf, size_t nbytes)
+{
+ size_t n, nread;
+ int c;
+
+ if (length != -1 && nbytes > length)
+ nbytes = length;
+ nread = 0;
+ while (nread < nbytes && (c = getchar()) != EOF) {
+ *buf++ = c;
+ nread++;
+ }
+ n = nread;
+ while (n-- > 0) {
+ c = *--buf;
+ ungetc(c, stdin);
+ }
+ return (nread);
+}
+
+int
+next(char **argv)
+{
+ static int done;
+ int statok;
+
+ if (argv) {
+ _argv = argv;
+ return(1);
+ }
+ for (;;) {
+ if (*_argv) {
+ if (!(freopen(*_argv, "r", stdin))) {
+ warn("%s", *_argv);
+ exitval = 1;
+ ++_argv;
+ continue;
+ }
+ statok = done = 1;
+ } else {
+ if (done++)
+ return(0);
+ statok = 0;
+ }
+ if (skip)
+ doskip(statok ? *_argv : "stdin", statok);
+ if (*_argv)
+ ++_argv;
+ if (!skip)
+ return(1);
+ }
+ /* NOTREACHED */
+}
+
+void
+doskip(const char *fname, int statok)
+{
+ int cnt;
+ struct stat sb;
+
+ if (statok) {
+ if (fstat(fileno(stdin), &sb))
+ err(1, "%s", fname);
+ if (S_ISREG(sb.st_mode) && skip >= sb.st_size) {
+ address += sb.st_size;
+ skip -= sb.st_size;
+ return;
+ }
+ }
+#ifdef __APPLE__
+ /* try to seek first; fall back on ESPIPE */
+ if (fseeko(stdin, skip, SEEK_SET) == 0) {
+#else /* !__APPLE__ */
+ if (S_ISREG(sb.st_mode)) {
+ if (fseeko(stdin, skip, SEEK_SET))
+ err(1, "%s", fname);
+#endif /* __APPLE__ */
+ address += skip;
+ skip = 0;
+ } else {
+#ifdef __APPLE__
+ if (errno != ESPIPE)
+ err(1, "%s", fname);
+#endif /* __APPLE__ */
+ for (cnt = 0; cnt < skip; ++cnt)
+ if (getchar() == EOF)
+ break;
+ address += cnt;
+ skip -= cnt;
+ }
+}
diff --git a/shell_cmds/hexdump/hexdump.1 b/shell_cmds/hexdump/hexdump.1
new file mode 100644
index 0000000..5e49a64
--- /dev/null
+++ b/shell_cmds/hexdump/hexdump.1
@@ -0,0 +1,342 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)hexdump.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/hexdump/hexdump.1,v 1.21 2004/07/10 13:11:00 tjr Exp $
+.\"
+.Dd July 10, 2004
+.Dt HEXDUMP 1
+.Os
+.Sh NAME
+.Nm hexdump
+.Nd ASCII, decimal, hexadecimal, octal dump
+.Sh SYNOPSIS
+.Nm
+.Op Fl bcCdovx
+.Op Fl e Ar format_string
+.Op Fl f Ar format_file
+.Op Fl n Ar length
+.Bk -words
+.Op Fl s Ar skip
+.Ek
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is a filter which displays the specified files, or
+the standard input, if no files are specified, in a user specified
+format.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl b
+.Em One-byte octal display .
+Display the input offset in hexadecimal, followed by sixteen
+space-separated, three column, zero-filled, bytes of input data,
+in octal, per line.
+.It Fl C
+.Em Canonical hex+ASCII display .
+Display the input offset in hexadecimal, followed by sixteen
+space-separated, two column, hexadecimal bytes, followed by the
+same sixteen bytes in %_p format enclosed in ``|'' characters.
+.It Fl c
+.Em One-byte character display .
+Display the input offset in hexadecimal, followed by sixteen
+space-separated, three column, space-filled, characters of input
+data per line.
+.It Fl d
+.Em Two-byte decimal display .
+Display the input offset in hexadecimal, followed by eight
+space-separated, five column, zero-filled, two-byte units
+of input data, in unsigned decimal, per line.
+.It Fl e Ar format_string
+Specify a format string to be used for displaying data.
+.It Fl f Ar format_file
+Specify a file that contains one or more newline separated format strings.
+Empty lines and lines whose first non-blank character is a hash mark
+.Pf ( Cm \&# )
+are ignored.
+.It Fl n Ar length
+Interpret only
+.Ar length
+bytes of input.
+.It Fl o
+.Em Two-byte octal display .
+Display the input offset in hexadecimal, followed by eight
+space-separated, six column, zero-filled, two byte quantities of
+input data, in octal, per line.
+.It Fl s Ar offset
+Skip
+.Ar offset
+bytes from the beginning of the input.
+By default,
+.Ar offset
+is interpreted as a decimal number.
+With a leading
+.Cm 0x
+or
+.Cm 0X ,
+.Ar offset
+is interpreted as a hexadecimal number,
+otherwise, with a leading
+.Cm 0 ,
+.Ar offset
+is interpreted as an octal number.
+Appending the character
+.Cm b ,
+.Cm k ,
+.Cm m ,
+or
+.Cm g
+to
+.Ar offset
+causes it to be interpreted as a multiple of
+.Li 512 ,
+.Li 1024 ,
+.Li 1048576 ,
+or
+.Li 1073741824 ,
+respectively.
+.It Fl v
+Cause
+.Nm
+to display all input data.
+Without the
+.Fl v
+option, any number of groups of output lines, which would be
+identical to the immediately preceding group of output lines (except
+for the input offsets), are replaced with a line comprised of a
+single asterisk.
+.It Fl x
+.Em Two-byte hexadecimal display .
+Display the input offset in hexadecimal, followed by eight, space
+separated, four column, zero-filled, two-byte quantities of input
+data, in hexadecimal, per line.
+.El
+.Pp
+For each input file,
+.Nm
+sequentially copies the input to standard output, transforming the
+data according to the format strings specified by the
+.Fl e
+and
+.Fl f
+options, in the order that they were specified.
+.Ss Formats
+A format string contains any number of format units, separated by
+whitespace.
+A format unit contains up to three items: an iteration count, a byte
+count, and a format.
+.Pp
+The iteration count is an optional positive integer, which defaults to
+one.
+Each format is applied iteration count times.
+.Pp
+The byte count is an optional positive integer.
+If specified it defines the number of bytes to be interpreted by
+each iteration of the format.
+.Pp
+If an iteration count and/or a byte count is specified, a single slash
+must be placed after the iteration count and/or before the byte count
+to disambiguate them.
+Any whitespace before or after the slash is ignored.
+.Pp
+The format is required and must be surrounded by double quote
+(" ") marks.
+It is interpreted as a fprintf-style format string (see
+.Xr fprintf 3 ) ,
+with the
+following exceptions:
+.Bl -bullet -offset indent
+.It
+An asterisk (*) may not be used as a field width or precision.
+.It
+A byte count or field precision
+.Em is
+required for each ``s'' conversion
+character (unlike the
+.Xr fprintf 3
+default which prints the entire string if the precision is unspecified).
+.It
+The conversion characters ``h'', ``l'', ``n'', ``p'' and ``q'' are
+not supported.
+.It
+The single character escape sequences
+described in the C standard are supported:
+.Bd -ragged -offset indent -compact
+.Bl -column <alert_character>
+.It "NUL \e0
+.It "<alert character> \ea
+.It "<backspace> \eb
+.It "<form-feed> \ef
+.It "<newline> \en
+.It "<carriage return> \er
+.It "<tab> \et
+.It "<vertical tab> \ev
+.El
+.Ed
+.El
+.Pp
+The
+.Nm
+utility also supports the following additional conversion strings:
+.Bl -tag -width Fl
+.It Cm \&_a Ns Op Cm dox
+Display the input offset, cumulative across input files, of the
+next byte to be displayed.
+The appended characters
+.Cm d ,
+.Cm o ,
+and
+.Cm x
+specify the display base
+as decimal, octal or hexadecimal respectively.
+.It Cm \&_A Ns Op Cm dox
+Identical to the
+.Cm \&_a
+conversion string except that it is only performed
+once, when all of the input data has been processed.
+.It Cm \&_c
+Output characters in the default character set.
+Nonprinting characters are displayed in three character, zero-padded
+octal, except for those representable by standard escape notation
+(see above),
+which are displayed as two character strings.
+.It Cm _p
+Output characters in the ASCII character set.
+Non-ASCII characters are displayed as a single
+.Dq Cm \&. .
+.It Cm _u
+Output US
+.Tn ASCII
+characters, with the exception that control characters are
+displayed using the following, lower-case, names.
+Characters greater than 0xff, hexadecimal, are displayed as hexadecimal
+strings.
+.Bl -column \&000_nu \&001_so \&002_st \&003_et \&004_eo
+.It "\&000\ NUL\t001\ SOH\t002\ STX\t003\ ETX\t004\ EOT\t005\ ENQ
+.It "\&006\ ACK\t007\ BEL\t008\ BS\t009\ HT\t00A\ LF\t00B\ VT
+.It "\&00C\ FF\t00D\ CR\t00E\ SO\t00F\ SI\t010\ DLE\t011\ DC1
+.It "\&012\ DC2\t013\ DC3\t014\ DC4\t015\ NAK\t016\ SYN\t017\ ETB
+.It "\&018\ CAN\t019\ EM\t01A\ SUB\t01B\ ESC\t01C\ FS\t01D\ GS
+.It "\&01E\ RS\t01F\ US\t0FF\ DEL
+.El
+.El
+.Pp
+The default and supported byte counts for the conversion characters
+are as follows:
+.Bl -tag -width "Xc,_Xc,_Xc,_Xc,_Xc,_Xc" -offset indent
+.It Li \&%_c , \&%_p , \&%_u , \&%c
+One byte counts only.
+.It Xo
+.Li \&%d , \&%i , \&%o ,
+.Li \&%u , \&%X , \&%x
+.Xc
+Four byte default, one, two and four byte counts supported.
+.It Xo
+.Li \&%E , \&%e , \&%f ,
+.Li \&%G , \&%g
+.Xc
+Eight byte default, four and twelve byte counts supported.
+.El
+.Pp
+The amount of data interpreted by each format string is the sum of the
+data required by each format unit, which is the iteration count times the
+byte count, or the iteration count times the number of bytes required by
+the format if the byte count is not specified.
+.Pp
+The input is manipulated in ``blocks'', where a block is defined as the
+largest amount of data specified by any format string.
+Format strings interpreting less than an input block's worth of data,
+whose last format unit both interprets some number of bytes and does
+not have a specified iteration count, have the iteration count
+incremented until the entire input block has been processed or there
+is not enough data remaining in the block to satisfy the format string.
+.Pp
+If, either as a result of user specification or
+.Nm
+modifying
+the iteration count as described above, an iteration count is
+greater than one, no trailing whitespace characters are output
+during the last iteration.
+.Pp
+It is an error to specify a byte count as well as multiple conversion
+characters or strings unless all but one of the conversion characters
+or strings is
+.Cm \&_a
+or
+.Cm \&_A .
+.Pp
+If, as a result of the specification of the
+.Fl n
+option or end-of-file being reached, input data only partially
+satisfies a format string, the input block is zero-padded sufficiently
+to display all available data (i.e., any format units overlapping the
+end of data will display some number of the zero bytes).
+.Pp
+Further output by such format strings is replaced by an equivalent
+number of spaces.
+An equivalent number of spaces is defined as the number of spaces
+output by an
+.Cm s
+conversion character with the same field width
+and precision as the original conversion character or conversion
+string but with any
+.Dq Li \&+ ,
+.Dq \&\ \& ,
+.Dq Li \&#
+conversion flag characters
+removed, and referencing a NULL string.
+.Pp
+If no format strings are specified, the default display is a
+one-byte hexadecimal display.
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh EXAMPLES
+Note that the following format strings, used with
+.Fl e ,
+must be enclosed in single quotes.
+.Pp
+Display the input in perusal format:
+.Bd -literal -offset indent
+"%06.6_ao " 12/1 "%3_u "
+"\et\et" "%_p "
+"\en"
+.Ed
+.Pp
+Implement the \-x option:
+.Bd -literal -offset indent
+"%07.7_Ax\en"
+"%07.7_ax " 8/2 "%04x " "\en"
+.Ed
+.Sh SEE ALSO
+.Xr gdb 1 ,
+.Xr od 1
diff --git a/shell_cmds/hexdump/hexdump.c b/shell_cmds/hexdump/hexdump.c
new file mode 100644
index 0000000..78df723
--- /dev/null
+++ b/shell_cmds/hexdump/hexdump.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)hexdump.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/hexdump.c,v 1.7 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <sys/types.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "hexdump.h"
+
+FS *fshead; /* head of format strings */
+int blocksize; /* data block size */
+int exitval; /* final exit value */
+int length = -1; /* max bytes to read */
+
+int
+main(int argc, char *argv[])
+{
+ FS *tfs;
+ char *p;
+
+ (void)setlocale(LC_ALL, "");
+
+ if (!(p = rindex(argv[0], 'o')) || strcmp(p, "od"))
+ newsyntax(argc, &argv);
+ else
+ oldsyntax(argc, &argv);
+
+ /* figure out the data block size */
+ for (blocksize = 0, tfs = fshead; tfs; tfs = tfs->nextfs) {
+ tfs->bcnt = size(tfs);
+ if (blocksize < tfs->bcnt)
+ blocksize = tfs->bcnt;
+ }
+ /* rewrite the rules, do syntax checking */
+ for (tfs = fshead; tfs; tfs = tfs->nextfs)
+ rewrite(tfs);
+
+ (void)next(argv);
+ display();
+ exit(exitval);
+}
diff --git a/shell_cmds/hexdump/hexdump.h b/shell_cmds/hexdump/hexdump.h
new file mode 100644
index 0000000..a984287
--- /dev/null
+++ b/shell_cmds/hexdump/hexdump.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)hexdump.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/hexdump/hexdump.h,v 1.9 2004/07/11 01:11:12 tjr Exp $
+ */
+
+#include <wchar.h>
+
+typedef struct _pr {
+ struct _pr *nextpr; /* next print unit */
+#define F_ADDRESS 0x001 /* print offset */
+#define F_BPAD 0x002 /* blank pad */
+#define F_C 0x004 /* %_c */
+#define F_CHAR 0x008 /* %c */
+#define F_DBL 0x010 /* %[EefGf] */
+#define F_INT 0x020 /* %[di] */
+#define F_P 0x040 /* %_p */
+#define F_STR 0x080 /* %s */
+#define F_U 0x100 /* %_u */
+#define F_UINT 0x200 /* %[ouXx] */
+#define F_TEXT 0x400 /* no conversions */
+ u_int flags; /* flag values */
+ int bcnt; /* byte count */
+ char *cchar; /* conversion character */
+ char *fmt; /* printf format */
+ char *nospace; /* no whitespace version */
+ int mbleft; /* bytes left of multibyte char. */
+ mbstate_t mbstate; /* conversion state */
+} PR;
+
+typedef struct _fu {
+ struct _fu *nextfu; /* next format unit */
+ struct _pr *nextpr; /* next print unit */
+#define F_IGNORE 0x01 /* %_A */
+#define F_SETREP 0x02 /* rep count set, not default */
+ u_int flags; /* flag values */
+ int reps; /* repetition count */
+ int bcnt; /* byte count */
+ char *fmt; /* format string */
+} FU;
+
+typedef struct _fs { /* format strings */
+ struct _fs *nextfs; /* linked list of format strings */
+ struct _fu *nextfu; /* linked list of format units */
+ int bcnt;
+} FS;
+
+extern FS *fshead; /* head of format strings list */
+extern FU *endfu; /* format at end-of-data */
+extern int blocksize; /* data block size */
+extern int exitval; /* final exit value */
+extern int odmode; /* are we acting as od(1)? */
+extern int length; /* amount of data to read */
+extern off_t skip; /* amount of data to skip at start */
+enum _vflag { ALL, DUP, FIRST, WAIT }; /* -v values */
+extern enum _vflag vflag;
+
+void add(const char *);
+void addfile(char *);
+void badcnt(char *);
+void badconv(char *);
+void badfmt(const char *);
+void badsfmt(void);
+void bpad(PR *);
+void conv_c(PR *, u_char *, size_t);
+void conv_u(PR *, u_char *);
+void display(void);
+void doskip(const char *, int);
+void escape(char *);
+u_char *get(void);
+void newsyntax(int, char ***);
+int next(char **);
+void nomem(void);
+void oldsyntax(int, char ***);
+size_t peek(u_char *, size_t);
+void rewrite(FS *);
+int size(FS *);
+void usage(void);
diff --git a/shell_cmds/hexdump/hexsyntax.c b/shell_cmds/hexdump/hexsyntax.c
new file mode 100644
index 0000000..9961f2f
--- /dev/null
+++ b/shell_cmds/hexdump/hexsyntax.c
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)hexsyntax.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/hexsyntax.c,v 1.12 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hexdump.h"
+
+off_t skip; /* bytes to skip */
+
+void
+newsyntax(int argc, char ***argvp)
+{
+ int ch;
+ char *p, **argv;
+
+ argv = *argvp;
+ if ((p = rindex(argv[0], 'h')) != NULL &&
+ strcmp(p, "hd") == 0) {
+ /* "Canonical" format, implies -C. */
+ add("\"%08.8_Ax\n\"");
+ add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
+ add("\" |\" 16/1 \"%_p\" \"|\\n\"");
+ }
+ while ((ch = getopt(argc, argv, "bcCde:f:n:os:vx")) != -1)
+ switch (ch) {
+ case 'b':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"");
+ break;
+ case 'c':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"");
+ break;
+ case 'C':
+ add("\"%08.8_Ax\n\"");
+ add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
+ add("\" |\" 16/1 \"%_p\" \"|\\n\"");
+ break;
+ case 'd':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"");
+ break;
+ case 'e':
+ add(optarg);
+ break;
+ case 'f':
+ addfile(optarg);
+ break;
+ case 'n':
+ if ((length = atoi(optarg)) < 0)
+ errx(1, "%s: bad length value", optarg);
+ break;
+ case 'o':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"");
+ break;
+ case 's':
+ if ((skip = strtoll(optarg, &p, 0)) < 0)
+ errx(1, "%s: bad skip value", optarg);
+ switch(*p) {
+ case 'b':
+ skip *= 512;
+ break;
+ case 'k':
+ skip *= 1024;
+ break;
+ case 'm':
+ skip *= 1048576;
+ break;
+ case 'g':
+ skip *= 1073741824;
+ break;
+ }
+ break;
+ case 'v':
+ vflag = ALL;
+ break;
+ case 'x':
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"");
+ break;
+ case '?':
+ usage();
+ }
+
+ if (!fshead) {
+ add("\"%07.7_Ax\n\"");
+ add("\"%07.7_ax \" 16/1 \"%02x \" \"\\n\"");
+ }
+
+ *argvp += optind;
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
+"usage: hexdump [-bcCdovx] [-e fmt] [-f fmt_file] [-n length]",
+" [-s skip] [file ...]",
+" hd [-bcdovx] [-e fmt] [-f fmt_file] [-n length]",
+" [-s skip] [file ...]");
+ exit(1);
+}
diff --git a/shell_cmds/hexdump/od.1 b/shell_cmds/hexdump/od.1
new file mode 100644
index 0000000..f827f6c
--- /dev/null
+++ b/shell_cmds/hexdump/od.1
@@ -0,0 +1,267 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)od.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/hexdump/od.1,v 1.17 2004/07/11 01:11:12 tjr Exp $
+.\"
+.Dd July 11, 2004
+.Os
+.Dt OD 1
+.Sh NAME
+.Nm od
+.Nd octal, decimal, hex, ASCII dump
+.Sh SYNOPSIS
+.Nm
+.Op Fl aBbcDdeFfHhIiLlOosvXx
+.Op Fl A Ar base
+.Op Fl j Ar skip
+.Op Fl N Ar length
+.Op Fl t Ar type
+.Sm off
+.Oo
+.Op Cm \&+
+.Li offset
+.Op Cm \&.
+.Op Cm Bb
+.Oc
+.Sm on
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is a filter which displays the specified files, or standard
+input if no files are specified, in a user specified format.
+.Pp
+The options are as follows:
+.Bl -tag -width ".Fl I , L , l"
+.It Fl A Ar base
+Specify the input address base.
+.Ar base
+may be one of
+.Cm d ,
+.Cm o ,
+.Cm x
+or
+.Cm n ,
+which specify decimal, octal, hexadecimal
+addresses or no address, respectively.
+.It Fl a
+Output named characters.
+Equivalent to
+.Fl t Ar a .
+.It Fl B , o
+Output octal shorts.
+Equivalent to
+.Fl t Ar o2 .
+.It Fl b
+Output octal bytes.
+Equivalent to
+.Fl t Ar o1 .
+.It Fl c
+Output C-style escaped characters.
+Equivalent to
+.Fl t Ar c .
+.It Fl D
+Output unsigned decimal ints.
+Equivalent to
+.Fl t Ar u4 .
+.It Fl e , F
+Output double-precision floating point numbers.
+Equivalent to
+.Fl t Ar fD .
+.It Fl f
+Output single-precision floating point numbers.
+Equivalent to
+.Fl t Ar fF .
+.It Fl H , X
+Output hexadecimal ints.
+Equivalent to
+.Fl t Ar x4 .
+.It Fl h , x
+Output hexadecimal shorts.
+Equivalent to
+.Fl t Ar x2 .
+.It Fl I , L , l
+Output signed decimal longs.
+Equivalent to
+.Fl t Ar dL .
+.It Fl i
+Output signed decimal ints.
+Equivalent to
+.Fl t Ar dI .
+.It Fl j Ar skip
+Skip
+.Ar skip
+bytes of the combined input before dumping.
+The number may be followed by one
+of
+.Cm b , k
+or
+.Cm m
+which specify the units of the number as blocks (512 bytes), kilobytes and
+megabytes, respectively.
+.It Fl N Ar length
+Dump at most
+.Ar length
+bytes of input.
+.It Fl O
+Output octal ints.
+Equivalent to
+.Fl t Ar o4 .
+.It Fl s
+Output signed decimal shorts.
+Equivalent to
+.Fl t Ar d2 .
+.It Fl t Ar type
+Specify the output format.
+.Ar type
+is a string containing one or more of the following kinds of type specifiers:
+.Bl -tag -width indent
+.It Cm a
+Named characters
+.Pq Tn ASCII .
+Control characters are displayed using the following names:
+.Bl -column "000 NUL" "001 SOH" "002 STX" "003 ETX" "004 EOT" "005 ENQ"
+.It "000 NUL 001 SOH 002 STX 003 ETX 004 EOT 005 ENQ"
+.It "006 ACK 007 BEL 008 BS 009 HT 00a NL 00b VT"
+.It "00c FF 00d CR 00e SO 00f SI 010 DLE 011 DC1"
+.It "012 DC2 013 DC3 014 DC4 015 NAK 016 SYN 017 ETB"
+.It "018 CAN 019 EM 01a SUB 01b ESC 01c FS 01d GS"
+.It "01e RS 01f US 020 SP 0ff DEL"
+.El
+.It Cm c
+Characters in the default character set.
+Non-printing characters are
+represented as 3-digit octal character codes, except the following
+characters, which are represented as C escapes:
+.Pp
+.Bl -tag -width carriage-return -compact
+.It NUL
+\e0
+.It alert
+\ea
+.It backspace
+\eb
+.It newline
+\en
+.It carriage-return
+\er
+.It tab
+\et
+.It vertical tab
+\ev
+.El
+.Pp
+Multi-byte characters are displayed in the area corresponding to the first
+byte of the character. The remaining bytes are shown as
+.Ql ** .
+.It Xo
+.Sm off
+.Op Cm d | o | u | x
+.Op Cm C | S | I | L | Ar n
+.Sm on
+.Xc
+Signed decimal
+.Pq Cm d ,
+octal
+.Pq Cm o ,
+unsigned decimal
+.Pq Cm u
+or
+hexadecimal
+.Pq Cm x .
+Followed by an optional size specifier, which may be either
+.Cm C
+.Pq Vt char ,
+.Cm S
+.Pq Vt short ,
+.Cm I
+.Pq Vt int ,
+.Cm L
+.Pq Vt long ,
+or a byte count as a decimal integer.
+.It Xo
+.Sm off
+.Cm f
+.Op Cm F | D | L | Ar n
+.Sm on
+.Xc
+Floating-point number.
+Followed by an optional size specifier, which may be either
+.Cm F
+.Pq Vt float ,
+.Cm D
+.Pq Vt double
+or
+.Cm L
+.Pq Vt "long double" .
+.El
+.It Fl v
+Write all input data, instead of replacing lines of duplicate values with a
+.Ql * .
+.El
+.Pp
+Multiple options that specify output format may be used; the output will
+contain one line for each format.
+.Pp
+If no output format is specified,
+.Fl t Ar oS
+is assumed.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh COMPATIBILITY
+The traditional
+.Fl s
+option to extract string constants is not supported; consider using
+.Xr strings 1
+instead.
+.Sh SEE ALSO
+.Xr hexdump 1 ,
+.Xr strings 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+An
+.Nm
+command appeared in
+.At v1 .
diff --git a/shell_cmds/hexdump/odsyntax.c b/shell_cmds/hexdump/odsyntax.c
new file mode 100644
index 0000000..6b9202e
--- /dev/null
+++ b/shell_cmds/hexdump/odsyntax.c
@@ -0,0 +1,447 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/odsyntax.c,v 1.16 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <float.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "hexdump.h"
+
+#define PADDING " "
+
+int odmode;
+
+static void odadd(const char *);
+static void odformat(const char *);
+static const char *odformatfp(char, const char *);
+static const char *odformatint(char, const char *);
+static void odoffset(int, char ***);
+static void odusage(void);
+
+void
+oldsyntax(int argc, char ***argvp)
+{
+ static char _n[] = "%_n", padding[] = PADDING;
+ int ch;
+ char **argv, *end;
+
+ /* Add initial (default) address format. -A may change it later. */
+#define TYPE_OFFSET 7
+ add("\"%07.7_Ao\n\"");
+ add("\"%07.7_ao \"");
+
+ odmode = 1;
+ argv = *argvp;
+ while ((ch = getopt(argc, argv, "A:aBbcDdeFfHhIij:LlN:Oost:vXx")) != -1)
+ switch (ch) {
+ case 'A':
+ switch (*optarg) {
+ case 'd': case 'o': case 'x':
+ fshead->nextfu->fmt[TYPE_OFFSET] = *optarg;
+ fshead->nextfs->nextfu->fmt[TYPE_OFFSET] =
+ *optarg;
+ break;
+ case 'n':
+ fshead->nextfu->fmt = _n; /* mimic regular output */
+ fshead->nextfs->nextfu->fmt = padding;
+ break;
+ default:
+ errx(1, "%s: invalid address base", optarg);
+ }
+ break;
+ case 'a':
+ odformat("a");
+ break;
+ case 'B':
+ case 'o':
+ odformat("o2");
+ break;
+ case 'b':
+ odformat("o1");
+ break;
+ case 'c':
+ odformat("c");
+ break;
+ case 'd':
+ odformat("u2");
+ break;
+ case 'D':
+ odformat("u4");
+ break;
+ case 'e': /* undocumented in od */
+ case 'F':
+ odformat("fD");
+ break;
+ case 'f':
+ odformat("fF");
+ break;
+ case 'H':
+ case 'X':
+ odformat("x4");
+ break;
+ case 'h':
+ case 'x':
+ odformat("x2");
+ break;
+ case 'I':
+ case 'L':
+ case 'l':
+ odformat("dL");
+ break;
+ case 'i':
+ odformat("dI");
+ break;
+ case 'j':
+ errno = 0;
+ skip = strtoll(optarg, &end, 0);
+ if (*end == 'b')
+ skip *= 512;
+ else if (*end == 'k')
+ skip *= 1024;
+ else if (*end == 'm')
+ skip *= 1048576L;
+ else if (*end == 'g')
+ skip *= 1073741824;
+ else if (*end != '\0')
+ skip = -1;
+ if (errno != 0 || skip < 0 || strlen(end) > 1)
+ errx(1, "%s: invalid skip amount", optarg);
+ break;
+ case 'N':
+ if ((length = atoi(optarg)) <= 0)
+ errx(1, "%s: invalid length", optarg);
+ break;
+ case 'O':
+ odformat("o4");
+ break;
+ case 's':
+ odformat("d2");
+ break;
+ case 't':
+ odformat(optarg);
+ break;
+ case 'v':
+ vflag = ALL;
+ break;
+ case '?':
+ default:
+ odusage();
+ }
+
+ if (fshead->nextfs->nextfs == NULL)
+ odformat("oS");
+
+ argc -= optind;
+ *argvp += optind;
+
+ if (argc)
+ odoffset(argc, argvp);
+}
+
+static void
+odusage(void)
+{
+
+ fprintf(stderr,
+"usage: od [-aBbcDdeFfHhIiLlOosvXx] [-A base] [-j skip] [-N length] [-t type]\n");
+ fprintf(stderr,
+" [[+]offset[.][Bb]] [file ...]\n");
+ exit(1);
+}
+
+static void
+odoffset(int argc, char ***argvp)
+{
+ unsigned char *p, *q, *num, *end;
+ int base;
+
+ /*
+ * The offset syntax of od(1) was genuinely bizarre. First, if
+ * it started with a plus it had to be an offset. Otherwise, if
+ * there were at least two arguments, a number or lower-case 'x'
+ * followed by a number makes it an offset. By default it was
+ * octal; if it started with 'x' or '0x' it was hex. If it ended
+ * in a '.', it was decimal. If a 'b' or 'B' was appended, it
+ * multiplied the number by 512 or 1024 byte units. There was
+ * no way to assign a block count to a hex offset.
+ *
+ * We assume it's a file if the offset is bad.
+ */
+ p = (unsigned char *)(argc == 1 ? (*argvp)[0] : (*argvp)[1]);
+
+ if (*p != '+' && (argc < 2 ||
+ (!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1])))))
+ return;
+
+ base = 0;
+ /*
+ * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
+ * set base.
+ */
+ if (p[0] == '+')
+ ++p;
+ if (p[0] == 'x' && isxdigit(p[1])) {
+ ++p;
+ base = 16;
+ } else if (p[0] == '0' && p[1] == 'x') {
+ p += 2;
+ base = 16;
+ }
+
+ /* skip over the number */
+ if (base == 16)
+ for (num = p; isxdigit(*p); ++p);
+ else
+ for (num = p; isdigit(*p); ++p);
+
+ /* check for no number */
+ if (num == p)
+ return;
+ q = p;
+ /* if terminates with a '.', base is decimal */
+ if (*q == '.') {
+ if (base)
+ return;
+ base = 10;
+ q++;
+ }
+
+ skip = strtoll((const char *)num, (char **)&end, base ? base : 8);
+
+ /* if end isn't the same as p, we got a non-octal digit */
+ if (end != p) {
+ skip = 0;
+ return;
+ }
+
+ if (*q) {
+ if (*q == 'B') {
+ skip *= 1024;
+ ++p;
+ } else if (*q == 'b') {
+ skip *= 512;
+ ++q;
+ }
+ }
+
+ if (*q) {
+ skip = 0;
+ return;
+ }
+
+ /*
+ * If the offset uses a non-octal base, the base of the offset
+ * is changed as well. This isn't pretty, but it's easy.
+ */
+ if (base == 16) {
+ fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
+ fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
+ } else if (base == 10) {
+ fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
+ fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
+ }
+
+ /* Terminate file list. */
+ (*argvp)[1] = NULL;
+}
+
+static void
+odformat(const char *fmt)
+{
+ char fchar;
+
+ while (*fmt != '\0') {
+ switch ((fchar = *fmt++)) {
+ case 'a':
+ odadd("16/1 \"%3_u \" \"\\n\"");
+ break;
+ case 'c':
+ odadd("16/1 \"%3_c \" \"\\n\"");
+ break;
+ case 'o': case 'u': case 'd': case 'x':
+ fmt = odformatint(fchar, fmt);
+ break;
+ case 'f':
+ fmt = odformatfp(fchar, fmt);
+ break;
+ default:
+ errx(1, "%c: unrecognised format character", fchar);
+ }
+ }
+}
+
+static const char *
+odformatfp(char fchar __unused, const char *fmt)
+{
+ size_t isize;
+ int digits;
+ char *end, *hdfmt;
+
+ isize = sizeof(double);
+ switch (*fmt) {
+ case 'F':
+ isize = sizeof(float);
+ fmt++;
+ break;
+ case 'D':
+ isize = sizeof(double);
+ fmt++;
+ break;
+ case 'L':
+ isize = sizeof(long double);
+ fmt++;
+ break;
+ default:
+ if (isdigit((unsigned char)*fmt)) {
+ errno = 0;
+ isize = (size_t)strtoul(fmt, &end, 10);
+ if (errno != 0 || isize == 0)
+ errx(1, "%s: invalid size", fmt);
+ fmt = (const char *)end;
+ }
+ }
+ switch (isize) {
+ case sizeof(float):
+ digits = FLT_DIG;
+ break;
+ case sizeof(double):
+ digits = DBL_DIG;
+ break;
+ default:
+ if (isize == sizeof(long double))
+ digits = LDBL_DIG;
+ else
+ errx(1, "unsupported floating point size %lu",
+ (u_long)isize);
+ }
+
+ asprintf(&hdfmt, "%lu/%lu \" %%%d.%de \" \"\\n\"",
+ 16UL / (u_long)isize, (u_long)isize, digits + 8, digits);
+ if (hdfmt == NULL)
+ err(1, NULL);
+ odadd(hdfmt);
+ free(hdfmt);
+
+ return (fmt);
+}
+
+static const char *
+odformatint(char fchar, const char *fmt)
+{
+ unsigned long long n;
+ size_t isize;
+ int digits;
+ char *end, *hdfmt;
+
+ isize = sizeof(int);
+ switch (*fmt) {
+ case 'C':
+ isize = sizeof(char);
+ fmt++;
+ break;
+ case 'I':
+ isize = sizeof(int);
+ fmt++;
+ break;
+ case 'L':
+ isize = sizeof(long);
+ fmt++;
+ break;
+ case 'S':
+ isize = sizeof(short);
+ fmt++;
+ break;
+ default:
+ if (isdigit((unsigned char)*fmt)) {
+ errno = 0;
+ isize = (size_t)strtoul(fmt, &end, 10);
+ if (errno != 0 || isize == 0)
+ errx(1, "%s: invalid size", fmt);
+ if (isize != sizeof(char) && isize != sizeof(short) &&
+ isize != sizeof(int) && isize != sizeof(long))
+ errx(1, "unsupported int size %lu",
+ (u_long)isize);
+ fmt = (const char *)end;
+ }
+ }
+
+ /*
+ * Calculate the maximum number of digits we need to
+ * fit the number. Overestimate for decimal with log
+ * base 8. We need one extra space for signed numbers
+ * to store the sign.
+ */
+ n = (1ULL << (8 * isize)) - 1;
+ digits = 0;
+ while (n != 0) {
+ digits++;
+ n >>= (fchar == 'x') ? 4 : 3;
+ }
+ if (fchar == 'd')
+ digits++;
+ asprintf(&hdfmt, "%lu/%lu \"%*s%%%s%d%c\" \"\\n\"",
+ 16UL / (u_long)isize, (u_long)isize, (int)(4 * isize - digits),
+ "", (fchar == 'd' || fchar == 'u') ? "" : "0", digits, fchar);
+ if (hdfmt == NULL)
+ err(1, NULL);
+ odadd(hdfmt);
+ free(hdfmt);
+
+ return (fmt);
+}
+
+static void
+odadd(const char *fmt)
+{
+ static int needpad;
+
+ if (needpad)
+ add("\""PADDING"\"");
+ add(fmt);
+ needpad = 1;
+}
diff --git a/shell_cmds/hexdump/parse.c b/shell_cmds/hexdump/parse.c
new file mode 100644
index 0000000..5445f18
--- /dev/null
+++ b/shell_cmds/hexdump/parse.c
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)parse.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/hexdump/parse.c,v 1.12 2002/09/04 23:29:01 dwmalone Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "hexdump.h"
+
+FU *endfu; /* format at end-of-data */
+
+void
+addfile(char *name)
+{
+ unsigned char *p;
+ FILE *fp;
+ int ch;
+ char buf[2048 + 1];
+
+ if ((fp = fopen(name, "r")) == NULL)
+ err(1, "%s", name);
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (!(p = (unsigned char *)index(buf, '\n'))) {
+ warnx("line too long");
+ while ((ch = getchar()) != '\n' && ch != EOF);
+ continue;
+ }
+ *p = '\0';
+ for (p = (unsigned char *)buf; *p && isspace(*p); ++p);
+ if (!*p || *p == '#')
+ continue;
+ add((const char *)p);
+ }
+ (void)fclose(fp);
+}
+
+void
+add(const char *fmt)
+{
+ unsigned const char *p, *savep;
+ static FS **nextfs;
+ FS *tfs;
+ FU *tfu, **nextfu;
+
+ /* start new linked list of format units */
+ if ((tfs = calloc(1, sizeof(FS))) == NULL)
+ err(1, NULL);
+ if (!fshead)
+ fshead = tfs;
+ else
+ *nextfs = tfs;
+ nextfs = &tfs->nextfs;
+ nextfu = &tfs->nextfu;
+
+ /* take the format string and break it up into format units */
+ for (p = (unsigned const char *)fmt;;) {
+ /* skip leading white space */
+ for (; isspace(*p); ++p);
+ if (!*p)
+ break;
+
+ /* allocate a new format unit and link it in */
+ if ((tfu = calloc(1, sizeof(FU))) == NULL)
+ err(1, NULL);
+ *nextfu = tfu;
+ nextfu = &tfu->nextfu;
+ tfu->reps = 1;
+
+ /* if leading digit, repetition count */
+ if (isdigit(*p)) {
+ for (savep = p; isdigit(*p); ++p);
+ if (!isspace(*p) && *p != '/')
+ badfmt(fmt);
+ /* may overwrite either white space or slash */
+ tfu->reps = atoi((const char *)savep);
+ tfu->flags = F_SETREP;
+ /* skip trailing white space */
+ for (++p; isspace(*p); ++p);
+ }
+
+ /* skip slash and trailing white space */
+ if (*p == '/')
+ while (isspace(*++p));
+
+ /* byte count */
+ if (isdigit(*p)) {
+ for (savep = p; isdigit(*p); ++p);
+ if (!isspace(*p))
+ badfmt(fmt);
+ tfu->bcnt = atoi((const char *)savep);
+ /* skip trailing white space */
+ for (++p; isspace(*p); ++p);
+ }
+
+ /* format */
+ if (*p != '"')
+ badfmt(fmt);
+ for (savep = ++p; *p != '"';)
+ if (*p++ == 0)
+ badfmt(fmt);
+ if (!(tfu->fmt = malloc(p - savep + 1)))
+ err(1, NULL);
+ (void) strncpy(tfu->fmt, (const char *)savep, p - savep);
+ tfu->fmt[p - savep] = '\0';
+ escape(tfu->fmt);
+ p++;
+ }
+}
+
+static const char *spec = ".#-+ 0123456789";
+
+int
+size(FS *fs)
+{
+ FU *fu;
+ int bcnt, cursize;
+ unsigned char *fmt;
+ int prec;
+
+ /* figure out the data block size needed for each format unit */
+ for (cursize = 0, fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (fu->bcnt) {
+ cursize += fu->bcnt * fu->reps;
+ continue;
+ }
+ for (bcnt = prec = 0, fmt = (unsigned char *)fu->fmt; *fmt; ++fmt) {
+ if (*fmt != '%')
+ continue;
+ /*
+ * skip any special chars -- save precision in
+ * case it's a %s format.
+ */
+ while (index(spec + 1, *++fmt));
+ if (*fmt == '.' && isdigit(*++fmt)) {
+ prec = atoi((const char *)fmt);
+ while (isdigit(*++fmt));
+ }
+ switch(*fmt) {
+ case 'c':
+ bcnt += 1;
+ break;
+ case 'd': case 'i': case 'o': case 'u':
+ case 'x': case 'X':
+ bcnt += 4;
+ break;
+ case 'e': case 'E': case 'f': case 'g': case 'G':
+ bcnt += 8;
+ break;
+ case 's':
+ bcnt += prec;
+ break;
+ case '_':
+ switch(*++fmt) {
+ case 'c': case 'p': case 'u':
+ bcnt += 1;
+ break;
+ }
+ }
+ }
+ cursize += bcnt * fu->reps;
+ }
+ return (cursize);
+}
+
+void
+rewrite(FS *fs)
+{
+ enum { NOTOKAY, USEBCNT, USEPREC } sokay;
+ PR *pr, **nextpr = NULL;
+ FU *fu;
+ unsigned char *p1, *p2, *fmtp;
+ char savech, cs[3];
+ int nconv, prec = 0;
+
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ /*
+ * Break each format unit into print units; each conversion
+ * character gets its own.
+ */
+ for (nconv = 0, fmtp = (unsigned char *)fu->fmt; *fmtp; nextpr = &pr->nextpr) {
+ if ((pr = calloc(1, sizeof(PR))) == NULL)
+ err(1, NULL);
+ if (!fu->nextpr)
+ fu->nextpr = pr;
+ else
+ *nextpr = pr;
+
+ /* Skip preceding text and up to the next % sign. */
+ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1);
+
+ /* Only text in the string. */
+ if (!*p1) {
+ pr->fmt = (char *)fmtp;
+ pr->flags = F_TEXT;
+ break;
+ }
+
+ /*
+ * Get precision for %s -- if have a byte count, don't
+ * need it.
+ */
+ if (fu->bcnt) {
+ sokay = USEBCNT;
+ /* Skip to conversion character. */
+ for (++p1; index(spec, *p1); ++p1);
+ } else {
+ /* Skip any special chars, field width. */
+ while (index(spec + 1, *++p1));
+ if (*p1 == '.' && isdigit(*++p1)) {
+ sokay = USEPREC;
+ prec = atoi((const char *)p1);
+ while (isdigit(*++p1));
+ } else
+ sokay = NOTOKAY;
+ }
+
+ p2 = p1 + 1; /* Set end pointer. */
+ cs[0] = *p1; /* Set conversion string. */
+ cs[1] = '\0';
+
+ /*
+ * Figure out the byte count for each conversion;
+ * rewrite the format as necessary, set up blank-
+ * padding for end of data.
+ */
+ switch(cs[0]) {
+ case 'c':
+ pr->flags = F_CHAR;
+ switch(fu->bcnt) {
+ case 0: case 1:
+ pr->bcnt = 1;
+ break;
+ default:
+ p1[1] = '\0';
+ badcnt((char *)p1);
+ }
+ break;
+ case 'd': case 'i':
+ pr->flags = F_INT;
+ goto isint;
+ case 'o': case 'u': case 'x': case 'X':
+ pr->flags = F_UINT;
+isint: cs[2] = '\0';
+ cs[1] = cs[0];
+ cs[0] = 'q';
+ switch(fu->bcnt) {
+ case 0: case 4:
+ pr->bcnt = 4;
+ break;
+ case 1:
+ pr->bcnt = 1;
+ break;
+ case 2:
+ pr->bcnt = 2;
+ break;
+#ifdef __APPLE__
+ case 8:
+ pr->bcnt = 8;
+ break;
+#endif /* __APPLE__ */
+ default:
+ p1[1] = '\0';
+ badcnt((char *)p1);
+ }
+ break;
+ case 'e': case 'E': case 'f': case 'g': case 'G':
+ pr->flags = F_DBL;
+ switch(fu->bcnt) {
+ case 0: case 8:
+ pr->bcnt = 8;
+ break;
+ case 4:
+ pr->bcnt = 4;
+ break;
+ default:
+ if (fu->bcnt == sizeof(long double)) {
+ cs[2] = '\0';
+ cs[1] = cs[0];
+ cs[0] = 'L';
+ pr->bcnt = sizeof(long double);
+ } else {
+ p1[1] = '\0';
+ badcnt((char *)p1);
+ }
+ }
+ break;
+ case 's':
+ pr->flags = F_STR;
+ switch(sokay) {
+ case NOTOKAY:
+ badsfmt();
+ case USEBCNT:
+ pr->bcnt = fu->bcnt;
+ break;
+ case USEPREC:
+ pr->bcnt = prec;
+ break;
+ }
+ break;
+ case '_':
+ ++p2;
+ switch(p1[1]) {
+ case 'A':
+ endfu = fu;
+ fu->flags |= F_IGNORE;
+ /* FALLTHROUGH */
+ case 'a':
+ pr->flags = F_ADDRESS;
+ ++p2;
+ switch(p1[2]) {
+ case 'd': case 'o': case'x':
+ cs[0] = 'q';
+ cs[1] = p1[2];
+ cs[2] = '\0';
+ break;
+ default:
+ p1[3] = '\0';
+ badconv((char *)p1);
+ }
+ break;
+ case 'c':
+ pr->flags = F_C;
+ /* cs[0] = 'c'; set in conv_c */
+ goto isint2;
+ case 'p':
+ pr->flags = F_P;
+ cs[0] = 'c';
+ goto isint2;
+ case 'u':
+ pr->flags = F_U;
+ /* cs[0] = 'c'; set in conv_u */
+isint2: switch(fu->bcnt) {
+ case 0: case 1:
+ pr->bcnt = 1;
+ break;
+ default:
+ p1[2] = '\0';
+ badcnt((char *)p1);
+ }
+ break;
+ case 'n': /* Force -A n to dump extra blank line like default od behavior */
+ endfu = fu;
+ fu->flags = F_IGNORE;
+ pr->flags = F_TEXT;
+ fmtp = (unsigned char *)"\n";
+ cs[0] = '\0';
+ break;
+ default:
+ p1[2] = '\0';
+ badconv((char *)p1);
+ }
+ break;
+ default:
+ p1[1] = '\0';
+ badconv((char *)p1);
+ }
+
+ /*
+ * Copy to PR format string, set conversion character
+ * pointer, update original.
+ */
+ savech = *p2;
+ p1[0] = '\0';
+ if ((pr->fmt = calloc(1, strlen((const char *)fmtp) + 2)) == NULL)
+ err(1, NULL);
+ (void)strcpy(pr->fmt, (const char *)fmtp);
+ (void)strcat(pr->fmt, cs);
+ *p2 = savech;
+ pr->cchar = pr->fmt + (p1 - fmtp);
+ fmtp = p2;
+
+ /* Only one conversion character if byte count. */
+ if (!(pr->flags&F_ADDRESS) && fu->bcnt && nconv++)
+ errx(1, "byte count with multiple conversion characters");
+ }
+ /*
+ * If format unit byte count not specified, figure it out
+ * so can adjust rep count later.
+ */
+ if (!fu->bcnt)
+ for (pr = fu->nextpr; pr; pr = pr->nextpr)
+ fu->bcnt += pr->bcnt;
+ }
+ /*
+ * If the format string interprets any data at all, and it's
+ * not the same as the blocksize, and its last format unit
+ * interprets any data at all, and has no iteration count,
+ * repeat it as necessary.
+ *
+ * If, rep count is greater than 1, no trailing whitespace
+ * gets output from the last iteration of the format unit.
+ */
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ if (!fu->nextfu && fs->bcnt < blocksize &&
+ !(fu->flags&F_SETREP) && fu->bcnt)
+ fu->reps += (blocksize - fs->bcnt) / fu->bcnt;
+ if (fu->reps > 1) {
+ for (pr = fu->nextpr;; pr = pr->nextpr)
+ if (!pr->nextpr)
+ break;
+ for (p1 = (unsigned char *)pr->fmt, p2 = NULL; *p1; ++p1)
+ p2 = isspace(*p1) ? p1 : NULL;
+ if (p2)
+ pr->nospace = (char *)p2;
+ }
+ }
+#ifdef DEBUG
+ for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ (void)printf("fmt:");
+ for (pr = fu->nextpr; pr; pr = pr->nextpr)
+ (void)printf(" {%s}", pr->fmt);
+ (void)printf("\n");
+ }
+#endif
+}
+
+void
+escape(char *p1)
+{
+ char *p2;
+
+ /* alphabetic escape sequences have to be done in place */
+ for (p2 = p1;; ++p1, ++p2) {
+ if (!*p1) {
+ *p2 = *p1;
+ break;
+ }
+ if (*p1 == '\\')
+ switch(*++p1) {
+ case 'a':
+ /* *p2 = '\a'; */
+ *p2 = '\007';
+ break;
+ case 'b':
+ *p2 = '\b';
+ break;
+ case 'f':
+ *p2 = '\f';
+ break;
+ case 'n':
+ *p2 = '\n';
+ break;
+ case 'r':
+ *p2 = '\r';
+ break;
+ case 't':
+ *p2 = '\t';
+ break;
+ case 'v':
+ *p2 = '\v';
+ break;
+ default:
+ *p2 = *p1;
+ break;
+ }
+ }
+}
+
+void
+badcnt(char *s)
+{
+ errx(1, "%s: bad byte count", s);
+}
+
+void
+badsfmt(void)
+{
+ errx(1, "%%s: requires a precision or a byte count");
+}
+
+void
+badfmt(const char *fmt)
+{
+ errx(1, "\"%s\": bad format", fmt);
+}
+
+void
+badconv(char *ch)
+{
+ errx(1, "%%%s: bad conversion character", ch);
+}
diff --git a/shell_cmds/hostname/hostname.1 b/shell_cmds/hostname/hostname.1
new file mode 100644
index 0000000..291b319
--- /dev/null
+++ b/shell_cmds/hostname/hostname.1
@@ -0,0 +1,67 @@
+.\"-
+.\" Copyright (c) 1983, 1988, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)hostname.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/bin/hostname/hostname.1,v 1.21 2006/12/08 07:47:08 kientzle Exp $
+.\"
+.Dd December 7, 2006
+.Dt HOSTNAME 1
+.Os
+.Sh NAME
+.Nm hostname
+.Nd set or print name of current host system
+.Sh SYNOPSIS
+.Nm
+.Op Fl fs
+.Op Ar name-of-host
+.Sh DESCRIPTION
+The
+.Nm
+utility prints the name of the current host.
+The super-user can
+set the hostname by supplying an argument.
+To keep the hostname between reboots, run
+.Sq scutil --set HostName Ar name-of-host .
+.Pp
+Options:
+.Bl -tag -width flag
+.It Fl f
+Include domain information in the printed name.
+This is the default behavior.
+.It Fl s
+Trim off any domain information from the printed
+name.
+.El
+.Sh SEE ALSO
+.Xr gethostname 3 ,
+.Xr scutil 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/shell_cmds/hostname/hostname.c b/shell_cmds/hostname/hostname.c
new file mode 100644
index 0000000..3df6542
--- /dev/null
+++ b/shell_cmds/hostname/hostname.c
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)hostname.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/hostname/hostname.c,v 1.19 2006/12/08 07:47:08 kientzle Exp $");
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, sflag;
+ char *p, hostname[MAXHOSTNAMELEN];
+
+ sflag = 0;
+ while ((ch = getopt(argc, argv, "fs")) != -1)
+ switch (ch) {
+ case 'f':
+ /*
+ * On Linux, "hostname -f" prints FQDN.
+ * BSD "hostname" always prints FQDN by
+ * default, so we accept but ignore -f.
+ */
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1)
+ usage();
+
+ if (*argv) {
+ if (sethostname(*argv, (int)strlen(*argv)))
+ err(1, "sethostname");
+ } else {
+ if (gethostname(hostname, (int)sizeof(hostname)))
+ err(1, "gethostname");
+ if (sflag) {
+ p = strchr(hostname, '.');
+ if (p != NULL)
+ *p = '\0';
+ }
+ (void)printf("%s\n", hostname);
+ }
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: hostname [-fs] [name-of-host]\n");
+ exit(1);
+}
diff --git a/shell_cmds/id/groups.1 b/shell_cmds/id/groups.1
new file mode 100644
index 0000000..00c030b
--- /dev/null
+++ b/shell_cmds/id/groups.1
@@ -0,0 +1,63 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)groups.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/id/groups.1,v 1.10 2006/12/23 17:14:01 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt GROUPS 1
+.Os
+.Sh NAME
+.Nm groups
+.Nd show group memberships
+.Sh SYNOPSIS
+.Nm
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility has been obsoleted by the
+.Xr id 1
+utility, and is equivalent to
+.Dq Nm id Fl Gn Op Ar user .
+The command
+.Dq Nm id Fl p
+is suggested for normal interactive use.
+.Pp
+The
+.Nm
+utility displays the groups to which you (or the optionally specified
+.Ar user )
+belong.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr id 1
diff --git a/shell_cmds/id/id.1 b/shell_cmds/id/id.1
new file mode 100644
index 0000000..1090c9a
--- /dev/null
+++ b/shell_cmds/id/id.1
@@ -0,0 +1,167 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)id.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/id/id.1,v 1.18 2006/09/26 22:28:12 ceri Exp $
+.\"
+.Dd September 26, 2006
+.Dt ID 1
+.Os
+.Sh NAME
+.Nm id
+.Nd return user identity
+.Sh SYNOPSIS
+.Nm
+.Op Ar user
+.Nm
+.Fl A
+.Nm
+.Fl F
+.Op Ar user
+.Nm
+.Fl G Op Fl n
+.Op Ar user
+.Nm
+.Fl M
+.Nm
+.Fl P
+.Op Ar user
+.Nm
+.Fl g Op Fl nr
+.Op Ar user
+.Nm
+.Fl p
+.Op Ar user
+.Nm
+.Fl u Op Fl nr
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the user and group names and numeric IDs, of the
+calling process, to the standard output.
+If the real and effective IDs are different, both are displayed,
+otherwise only the real ID is displayed.
+.Pp
+If a
+.Ar user
+(login name or user ID)
+is specified, the user and group IDs of that user are displayed.
+In this case, the real and effective IDs are assumed to be the same.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl A
+Display the process audit user ID and other process audit properties, which
+requires privilege.
+.It Fl F
+Display the full name of the user.
+.It Fl G
+Display the different group IDs (effective, real and supplementary)
+as white-space separated numbers, in no particular order.
+.It Fl M
+Display the MAC label of the current process.
+.It Fl P
+Display the id as a password file entry.
+.It Fl a
+Ignored for compatibility with other
+.Nm
+implementations.
+.It Fl g
+Display the effective group ID as a number.
+.It Fl n
+Display the name of the user or group ID for the
+.Fl G ,
+.Fl g
+and
+.Fl u
+options instead of the number.
+If any of the ID numbers cannot be mapped into names, the number will be
+displayed as usual.
+.It Fl p
+Make the output human-readable.
+If the user name returned by
+.Xr getlogin 2
+is different from the login name referenced by the user ID, the name
+returned by
+.Xr getlogin 2
+is displayed, preceded by the keyword
+.Dq login .
+The user ID as a name is displayed, preceded by the keyword
+.Dq uid .
+If the effective user ID is different from the real user ID, the real user
+ID is displayed as a name, preceded by the keyword
+.Dq euid .
+If the effective group ID is different from the real group ID, the real group
+ID is displayed as a name, preceded by the keyword
+.Dq rgid .
+The list of groups to which the user belongs is then displayed as names,
+preceded by the keyword
+.Dq groups .
+Each display is on a separate line.
+.It Fl r
+Display the real ID for the
+.Fl g
+and
+.Fl u
+options instead of the effective ID.
+.It Fl u
+Display the effective user ID as a number.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr who 1
+.Sh STANDARDS
+The
+.Nm
+function is expected to conform to
+.St -p1003.2 .
+.Sh HISTORY
+The
+historic
+.Xr groups 1
+command is equivalent to
+.Dq Nm id Fl Gn Op Ar user .
+.Pp
+The
+historic
+.Xr whoami 1
+command is equivalent to
+.Dq Nm id Fl un .
+.Pp
+The
+.Nm
+command appeared in
+.Bx 4.4 .
diff --git a/shell_cmds/id/id.c b/shell_cmds/id/id.c
new file mode 100644
index 0000000..2567770
--- /dev/null
+++ b/shell_cmds/id/id.c
@@ -0,0 +1,529 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)id.c 8.2 (Berkeley) 2/16/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/id/id.c,v 1.33 2006/12/29 12:28:34 stefanf Exp $");
+
+#include <sys/param.h>
+#ifndef __APPLE__
+#include <sys/mac.h>
+#endif /* !__APPLE__ */
+
+#ifdef USE_BSM_AUDIT
+#include <bsm/audit.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void id_print(struct passwd *, int, int, int);
+void pline(struct passwd *);
+void pretty(struct passwd *);
+void auditid(void);
+void fullname(struct passwd *);
+void group(struct passwd *, int);
+void maclabel(void);
+void usage(void);
+struct passwd *who(char *);
+
+int isgroups, iswhoami;
+
+#ifdef __APPLE__
+// SPI for 5235093
+int32_t getgrouplist_2(const char *, gid_t, gid_t **);
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ struct group *gr;
+ struct passwd *pw;
+ int Gflag, Mflag, Pflag, ch, gflag, id, nflag, pflag, rflag, uflag;
+ int Aflag;
+ int Fflag;
+ const char *myname;
+
+ Gflag = Mflag = Pflag = gflag = nflag = pflag = rflag = uflag = 0;
+ Aflag = 0;
+ Fflag = 0;
+
+ myname = strrchr(argv[0], '/');
+ myname = (myname != NULL) ? myname + 1 : argv[0];
+ if (strcmp(myname, "groups") == 0) {
+ isgroups = 1;
+ Gflag = nflag = 1;
+ }
+ else if (strcmp(myname, "whoami") == 0) {
+ iswhoami = 1;
+ uflag = nflag = 1;
+ }
+
+ while ((ch = getopt(argc, argv,
+ (isgroups || iswhoami) ? "" : "AFPGMagnpru")) != -1)
+ switch(ch) {
+#ifdef USE_BSM_AUDIT
+ case 'A':
+ Aflag = 1;
+ break;
+#endif
+ case 'F':
+ Fflag = 1;
+ break;
+ case 'G':
+ Gflag = 1;
+ break;
+ case 'M':
+ Mflag = 1;
+ break;
+ case 'P':
+ Pflag = 1;
+ break;
+ case 'a':
+ break;
+ case 'g':
+ gflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 'u':
+ uflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (iswhoami && argc > 0)
+ usage();
+
+ switch(Aflag + Fflag + Gflag + Mflag + Pflag + gflag + pflag + uflag) {
+ case 1:
+ break;
+ case 0:
+ if (!nflag && !rflag)
+ break;
+ /* FALLTHROUGH */
+ default:
+ usage();
+ }
+
+ pw = *argv ? who(*argv) : NULL;
+
+ if (Mflag && pw != NULL)
+ usage();
+
+#ifdef USE_BSM_AUDIT
+ if (Aflag) {
+ auditid();
+ exit(0);
+ }
+#endif
+
+ if (Fflag) {
+ fullname(pw);
+ exit(0);
+ }
+
+ if (gflag) {
+ id = pw ? pw->pw_gid : rflag ? getgid() : getegid();
+ if (nflag && (gr = getgrgid(id)))
+ (void)printf("%s\n", gr->gr_name);
+ else
+ (void)printf("%u\n", id);
+ exit(0);
+ }
+
+ if (uflag) {
+ id = pw ? pw->pw_uid : rflag ? getuid() : geteuid();
+ if (nflag && (pw = getpwuid(id)))
+ (void)printf("%s\n", pw->pw_name);
+ else
+ (void)printf("%u\n", id);
+ exit(0);
+ }
+
+ if (Gflag) {
+ group(pw, nflag);
+ exit(0);
+ }
+
+ if (Mflag) {
+ maclabel();
+ exit(0);
+ }
+
+ if (Pflag) {
+ pline(pw);
+ exit(0);
+ }
+
+ if (pflag) {
+ pretty(pw);
+ exit(0);
+ }
+
+ if (pw) {
+ id_print(pw, 1, 0, 0);
+ }
+ else {
+ id = getuid();
+ pw = getpwuid(id);
+ id_print(pw, 0, 1, 1);
+ }
+ exit(0);
+}
+
+void
+pretty(struct passwd *pw)
+{
+ struct group *gr;
+ u_int eid, rid;
+ char *login;
+
+ if (pw) {
+ (void)printf("uid\t%s\n", pw->pw_name);
+ (void)printf("groups\t");
+ group(pw, 1);
+ } else {
+ if ((login = getlogin()) == NULL)
+ err(1, "getlogin");
+
+ pw = getpwuid(rid = getuid());
+ if (pw == NULL || strcmp(login, pw->pw_name))
+ (void)printf("login\t%s\n", login);
+ if (pw)
+ (void)printf("uid\t%s\n", pw->pw_name);
+ else
+ (void)printf("uid\t%u\n", rid);
+
+ if ((eid = geteuid()) != rid) {
+ if ((pw = getpwuid(eid)))
+ (void)printf("euid\t%s\n", pw->pw_name);
+ else
+ (void)printf("euid\t%u\n", eid);
+ }
+ if ((rid = getgid()) != (eid = getegid())) {
+ if ((gr = getgrgid(rid)))
+ (void)printf("rgid\t%s\n", gr->gr_name);
+ else
+ (void)printf("rgid\t%u\n", rid);
+ }
+ (void)printf("groups\t");
+ group(NULL, 1);
+ }
+}
+
+void
+id_print(struct passwd *pw, int use_ggl, int p_euid, int p_egid)
+{
+ struct group *gr;
+ gid_t gid, egid, lastgid;
+ uid_t uid, euid;
+ int cnt, ngroups;
+#ifdef __APPLE__
+ gid_t *groups = NULL;
+#else
+ gid_t groups[NGROUPS + 1];
+#endif
+ const char *fmt;
+
+#ifdef __APPLE__
+ if (pw == NULL) {
+ pw = getpwuid(getuid());
+ }
+
+ use_ggl = 1;
+#endif
+
+ if (pw != NULL) {
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+ }
+ else {
+ uid = getuid();
+ gid = getgid();
+ }
+
+ if (use_ggl && pw != NULL) {
+#ifdef __APPLE__
+ // 5235093
+ ngroups = getgrouplist_2(pw->pw_name, gid, &groups);
+#else
+ ngroups = NGROUPS + 1;
+ getgrouplist(pw->pw_name, gid, groups, &ngroups);
+#endif
+ }
+ else {
+#ifdef __APPLE__
+ groups = malloc((NGROUPS + 1) * sizeof(gid_t));
+#endif
+ ngroups = getgroups(NGROUPS + 1, groups);
+ }
+
+#ifdef __APPLE__
+ if (ngroups < 0)
+ warn("failed to retrieve group list");
+#endif
+
+ if (pw != NULL)
+ printf("uid=%u(%s)", uid, pw->pw_name);
+ else
+ printf("uid=%u", getuid());
+ printf(" gid=%u", gid);
+ if ((gr = getgrgid(gid)))
+ (void)printf("(%s)", gr->gr_name);
+ if (p_euid && (euid = geteuid()) != uid) {
+ (void)printf(" euid=%u", euid);
+ if ((pw = getpwuid(euid)))
+ (void)printf("(%s)", pw->pw_name);
+ }
+ if (p_egid && (egid = getegid()) != gid) {
+ (void)printf(" egid=%u", egid);
+ if ((gr = getgrgid(egid)))
+ (void)printf("(%s)", gr->gr_name);
+ }
+ fmt = " groups=%u";
+ for (lastgid = -1, cnt = 0; cnt < ngroups; ++cnt) {
+ if (lastgid == (gid = groups[cnt]))
+ continue;
+ printf(fmt, gid);
+ fmt = ",%u";
+ if ((gr = getgrgid(gid)))
+ printf("(%s)", gr->gr_name);
+ lastgid = gid;
+ }
+ printf("\n");
+#ifdef __APPLE__
+ free(groups);
+#endif
+}
+
+#ifdef USE_BSM_AUDIT
+void
+auditid(void)
+{
+ auditinfo_addr_t auditinfo;
+
+ if (getaudit_addr(&auditinfo, sizeof(auditinfo)) < 0)
+ err(1, "getaudit");
+ printf("auid=%d\n", auditinfo.ai_auid);
+ printf("mask.success=0x%08x\n", auditinfo.ai_mask.am_success);
+ printf("mask.failure=0x%08x\n", auditinfo.ai_mask.am_failure);
+ printf("termid.port=0x%08x\n", auditinfo.ai_termid.at_port);
+ printf("asid=%d\n", auditinfo.ai_asid);
+}
+#endif
+
+void
+fullname(struct passwd *pw)
+{
+
+ if (!pw) {
+ if ((pw = getpwuid(getuid())) == NULL)
+ err(1, "getpwuid");
+ }
+
+ (void)printf("%s\n", pw->pw_gecos);
+}
+
+void
+group(struct passwd *pw, int nflag)
+{
+ struct group *gr;
+ int cnt, id, lastid, ngroups;
+#ifdef __APPLE__
+ gid_t *groups = NULL;
+#else
+ gid_t groups[NGROUPS + 1];
+#endif
+ const char *fmt;
+
+#ifdef __APPLE__
+ if (pw == NULL) {
+ pw = getpwuid(getuid());
+ }
+#endif
+
+ if (pw) {
+#ifdef __APPLE__
+ // 5235093
+ ngroups = getgrouplist_2(pw->pw_name, pw->pw_gid, &groups);
+#else
+ ngroups = NGROUPS + 1;
+ (void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
+#endif
+ } else {
+#ifdef __APPLE__
+ groups = malloc((NGROUPS + 1) * sizeof(gid_t));
+#endif
+ groups[0] = getgid();
+ ngroups = getgroups(NGROUPS, groups + 1) + 1;
+ }
+ fmt = nflag ? "%s" : "%u";
+ for (lastid = -1, cnt = 0; cnt < ngroups; ++cnt) {
+ if (lastid == (id = groups[cnt]))
+ continue;
+ if (nflag) {
+ if ((gr = getgrgid(id)))
+ (void)printf(fmt, gr->gr_name);
+ else
+ (void)printf(*fmt == ' ' ? " %u" : "%u",
+ id);
+ fmt = " %s";
+ } else {
+ (void)printf(fmt, id);
+ fmt = " %u";
+ }
+ lastid = id;
+ }
+ (void)printf("\n");
+#ifdef __APPLE__
+ free(groups);
+#endif
+}
+
+void
+maclabel(void)
+{
+#ifdef __APPLE__
+ errx(1, "-M unsupported");
+#else /* !__APPLE__ */
+ char *string;
+ mac_t label;
+ int error;
+
+ error = mac_prepare_process_label(&label);
+ if (error == -1)
+ errx(1, "mac_prepare_type: %s", strerror(errno));
+
+ error = mac_get_proc(label);
+ if (error == -1)
+ errx(1, "mac_get_proc: %s", strerror(errno));
+
+ error = mac_to_text(label, &string);
+ if (error == -1)
+ errx(1, "mac_to_text: %s", strerror(errno));
+
+ (void)printf("%s\n", string);
+ mac_free(label);
+ free(string);
+#endif /* __APPLE__ */
+}
+
+struct passwd *
+who(char *u)
+{
+ struct passwd *pw;
+ long id;
+ char *ep;
+
+ /*
+ * Translate user argument into a pw pointer. First, try to
+ * get it as specified. If that fails, try it as a number.
+ */
+ if ((pw = getpwnam(u)))
+ return(pw);
+ id = strtol(u, &ep, 10);
+ if (*u && !*ep && (pw = getpwuid(id)))
+ return(pw);
+ errx(1, "%s: no such user", u);
+ /* NOTREACHED */
+}
+
+void
+pline(struct passwd *pw)
+{
+
+ if (!pw) {
+ if ((pw = getpwuid(getuid())) == NULL)
+ err(1, "getpwuid");
+ }
+
+ (void)printf("%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n", pw->pw_name,
+ pw->pw_passwd, pw->pw_uid, pw->pw_gid, pw->pw_class,
+ (long)pw->pw_change, (long)pw->pw_expire, pw->pw_gecos,
+ pw->pw_dir, pw->pw_shell);
+}
+
+
+void
+usage(void)
+{
+
+ if (isgroups)
+ (void)fprintf(stderr, "usage: groups [user]\n");
+ else if (iswhoami)
+ (void)fprintf(stderr, "usage: whoami\n");
+ else
+ (void)fprintf(stderr, "%s\n%s%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
+ "usage: id [user]",
+#ifdef USE_BSM_AUDIT
+ " id -A\n",
+#else
+ "",
+#endif
+ " id -F [user]",
+ " id -G [-n] [user]",
+ " id -M",
+ " id -P [user]",
+ " id -g [-nr] [user]",
+ " id -p [user]",
+ " id -u [-nr] [user]");
+ exit(1);
+}
diff --git a/shell_cmds/id/open_directory.c b/shell_cmds/id/open_directory.c
new file mode 100644
index 0000000..fb34de9
--- /dev/null
+++ b/shell_cmds/id/open_directory.c
@@ -0,0 +1,229 @@
+#include <membership.h>
+
+#include "open_directory.h"
+
+ODNodeRef
+CreateNode(void)
+{
+ CFErrorRef error = NULL;
+ ODNodeRef node = NULL;
+
+ node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODTypeAuthenticationSearchNode, &error);
+
+ if (node == NULL) {
+ CFShow(error);
+ exit(1);
+ }
+
+ return node;
+}
+
+static ODRecordRef
+CopyRecordWithUUID(ODNodeRef node, CFStringRef type, uuid_t uuid)
+{
+ CFErrorRef error = NULL;
+ char uuidstr[37];
+ CFStringRef uuidref;
+ ODQueryRef query = NULL;
+ CFTypeRef vals[] = { CFSTR(kDSAttributesStandardAll) };
+ CFArrayRef attributes = CFArrayCreate(NULL, vals, 1, &kCFTypeArrayCallBacks);
+ CFArrayRef results = NULL;
+ ODRecordRef record = NULL;
+
+ uuid_unparse(uuid, uuidstr);
+ uuidref = CFStringCreateWithCString(NULL, uuidstr, kCFStringEncodingUTF8);
+
+ if (uuidref) {
+ query = ODQueryCreateWithNode(NULL, node, type, CFSTR(kDS1AttrGeneratedUID), kODMatchEqualTo, uuidref, attributes, 100, &error);
+
+ if (query) {
+ results = ODQueryCopyResults(query, false, &error);
+
+ if (results) {
+ if (CFArrayGetCount(results) == 1) {
+ record = (ODRecordRef)CFArrayGetValueAtIndex(results, 0);
+ CFRetain(record);
+ }
+
+ CFRelease(results);
+ }
+
+ CFRelease(query);
+ }
+
+ CFRelease(uuidref);
+ }
+
+ return record;
+}
+
+ODRecordRef
+CopyGroupRecordWithGID(ODNodeRef node, gid_t gid)
+{
+ uuid_t uuid;
+
+ mbr_gid_to_uuid(gid, uuid);
+
+ return CopyRecordWithUUID(node, CFSTR(kDSStdRecordTypeGroups), uuid);
+}
+
+ODRecordRef
+CopyUserRecordWithUID(ODNodeRef node, uid_t uid)
+{
+ uuid_t uuid;
+
+ mbr_uid_to_uuid(uid, uuid);
+
+ return CopyRecordWithUUID(node, CFSTR(kDSStdRecordTypeUsers), uuid);
+}
+
+ODRecordRef
+CopyUserRecordWithUsername(ODNodeRef node, char *name)
+{
+ CFStringRef nameref;
+ CFTypeRef vals[] = { CFSTR(kDSAttributesStandardAll) };
+ CFArrayRef attributes = CFArrayCreate(NULL, vals, 1, &kCFTypeArrayCallBacks);
+ CFErrorRef error;
+
+ nameref = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8);
+
+ if (nameref == NULL)
+ return NULL;
+
+ return ODNodeCopyRecord(node, CFSTR(kDSStdRecordTypeUsers), nameref, attributes, &error);
+}
+
+CFStringRef
+CopyAttrFromRecord(ODRecordRef record, CFStringRef attribute)
+{
+ CFErrorRef error = NULL;
+ CFArrayRef values = ODRecordCopyValues(record, attribute, &error);
+ CFStringRef result = NULL;
+
+ if (values) {
+ if (CFArrayGetCount(values) == 1) {
+ result = CFArrayGetValueAtIndex(values, 0);
+ CFRetain(result);
+ }
+ CFRelease(values);
+ }
+
+ return result;
+}
+
+int
+GetIntAttrFromRecord(ODRecordRef record, CFStringRef attribute, int *output)
+{
+ int status = 1;
+ CFStringRef str = CopyAttrFromRecord(record, attribute);
+
+ if (str) {
+ *output = CFStringGetIntValue(str);
+ status = 0;
+ CFRelease(str);
+ }
+
+ return status;
+}
+
+uid_t
+GetUIDFromRecord(ODRecordRef record)
+{
+ int uid = -1;
+
+ GetIntAttrFromRecord(record, CFSTR(kDS1AttrUniqueID), &uid);
+
+ return uid;
+}
+
+gid_t
+GetGIDFromRecord(ODRecordRef record)
+{
+ int gid = -1;
+
+ GetIntAttrFromRecord(record, CFSTR(kDS1AttrPrimaryGroupID), &gid);
+
+ return gid;
+}
+
+CFArrayRef
+CopyGroupRecordsForUser(ODNodeRef node, ODRecordRef user, CFIndex limit)
+{
+ CFMutableArrayRef groups;
+ gid_t primary_gid;
+ ODRecordRef primary_group;
+ CFErrorRef error = NULL;
+ ODQueryRef query;
+ CFArrayRef results;
+ int i;
+ ODRecordRef gr;
+
+ query = ODQueryCreateWithNode(NULL, node, CFSTR(kDSStdRecordTypeGroups),
+ CFSTR(kDSNAttrMember), kODMatchContains, ODRecordGetRecordName(user), NULL, limit, &error);
+ results = ODQueryCopyResults(query, false, &error);
+ CFRelease(query);
+
+ groups = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ primary_gid = GetGIDFromRecord(user);
+ primary_group = CopyGroupRecordWithGID(node, primary_gid);
+ CFArrayAppendValue(groups, primary_group);
+ CFRelease(primary_group);
+
+ for (i = 0; i < CFArrayGetCount(results); i++) {
+ gr = (ODRecordRef)CFArrayGetValueAtIndex(results, i);
+ if (GetGIDFromRecord(gr) != primary_gid) {
+ CFArrayAppendValue(groups, gr);
+ }
+ }
+
+ CFRelease(results);
+
+ return groups;
+}
+
+static int
+cvfprintf(FILE *file, const char *format, va_list args)
+{
+ char* cstr;
+ int result = 0;
+ CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull);
+ if (formatStr) {
+ CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args);
+ if (str) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
+ cstr = malloc(size);
+ if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) {
+ result = fprintf(file, "%s", cstr);
+ free(cstr);
+ }
+ CFRelease(str);
+ }
+ CFRelease(formatStr);
+ }
+ return result;
+}
+
+int
+cfprintf(FILE *file, const char *format, ...)
+{
+ int result;
+ va_list args;
+
+ va_start(args, format);
+ result = cvfprintf(file, format, args);
+ va_end(args);
+ return result;
+}
+
+int
+cprintf(const char *format, ...)
+{
+ int result;
+ va_list args;
+
+ va_start(args, format);
+ result = cvfprintf(stdout, format, args);
+ va_end(args);
+ return result;
+}
diff --git a/shell_cmds/id/open_directory.h b/shell_cmds/id/open_directory.h
new file mode 100644
index 0000000..2c79775
--- /dev/null
+++ b/shell_cmds/id/open_directory.h
@@ -0,0 +1,18 @@
+#include <OpenDirectory/OpenDirectory.h>
+
+ODNodeRef CreateNode(void);
+
+ODRecordRef CopyGroupRecordWithGID(ODNodeRef, gid_t);
+
+ODRecordRef CopyUserRecordWithUID(ODNodeRef, uid_t);
+ODRecordRef CopyUserRecordWithUsername(ODNodeRef, char *);
+
+CFArrayRef CopyGroupRecordsForUser(ODNodeRef, ODRecordRef, CFIndex);
+
+CFStringRef CopyAttrFromRecord(ODRecordRef record, CFStringRef attribute);
+int GetIntAttrFromRecord(ODRecordRef record, CFStringRef attribute, int *output);
+uid_t GetUIDFromRecord(ODRecordRef);
+gid_t GetGIDFromRecord(ODRecordRef);
+
+int cfprintf(FILE *file, const char *format, ...);
+int cprintf(const char *format, ...);
diff --git a/shell_cmds/id/whoami.1 b/shell_cmds/id/whoami.1
new file mode 100644
index 0000000..568fbaf
--- /dev/null
+++ b/shell_cmds/id/whoami.1
@@ -0,0 +1,60 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)whoami.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/id/whoami.1,v 1.9 2005/01/17 07:44:19 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt WHOAMI 1
+.Os
+.Sh NAME
+.Nm whoami
+.Nd display effective user id
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility has been obsoleted by the
+.Xr id 1
+utility, and is equivalent to
+.Dq Nm id Fl un .
+The command
+.Dq Nm id Fl p
+is suggested for normal interactive use.
+.Pp
+The
+.Nm
+utility displays your effective user ID as a name.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr id 1
diff --git a/shell_cmds/jot/jot.1 b/shell_cmds/jot/jot.1
new file mode 100644
index 0000000..b94fab4
--- /dev/null
+++ b/shell_cmds/jot/jot.1
@@ -0,0 +1,251 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)jot.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/jot/jot.1,v 1.24 2010/02/20 00:16:44 delphij Exp $
+.\"
+.Dd February 19, 2010
+.Dt JOT 1
+.Os
+.Sh NAME
+.Nm jot
+.Nd print sequential or random data
+.Sh SYNOPSIS
+.Nm
+.Op Fl cnr
+.Op Fl b Ar word
+.Op Fl w Ar word
+.Op Fl s Ar string
+.Op Fl p Ar precision
+.Op Ar reps Op Ar begin Op Ar end Op Ar s
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to print out increasing, decreasing, random,
+or redundant data, usually numbers, one per line.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl r
+Generate random data instead of the default sequential data.
+.It Fl b Ar word
+Just print
+.Ar word
+repetitively.
+.It Fl w Ar word
+Print
+.Ar word
+with the generated data appended to it.
+Octal, hexadecimal, exponential,
+.Tn ASCII ,
+zero padded,
+and right-adjusted representations
+are possible by using the appropriate
+.Xr printf 3
+conversion specification inside
+.Ar word ,
+in which case the data are inserted rather than appended.
+.It Fl c
+This is an abbreviation for
+.Fl w Ar %c .
+.It Fl s Ar string
+Print data separated by
+.Ar string .
+Normally, newlines separate data.
+.It Fl n
+Do not print the final newline normally appended to the output.
+.It Fl p Ar precision
+Print only as many digits or characters of the data
+as indicated by the integer
+.Ar precision .
+In the absence of
+.Fl p ,
+the precision is the greater of the precisions of
+.Ar begin
+and
+.Ar end .
+The
+.Fl p
+option is overridden by whatever appears in a
+.Xr printf 3
+conversion following
+.Fl w .
+.El
+.Pp
+The last four arguments indicate, respectively,
+the number of data, the lower bound, the upper bound,
+and the step size or, for random data, the seed.
+While at least one of them must appear,
+any of the other three may be omitted, and
+will be considered as such if given as
+.Fl ""
+or as an empty string.
+Any three of these arguments determines the fourth.
+If four are specified and the given and computed values of
+.Ar reps
+conflict, the lower value is used.
+If fewer than three are specified, defaults are assigned
+left to right, except for
+.Ar s ,
+which assumes a default of 1 or -1 if both
+.Ar begin
+and
+.Ar end
+are given.
+.Pp
+Defaults for the four arguments are, respectively,
+100, 1, 100, and 1, except that when random data are requested,
+the seed,
+.Ar s ,
+is picked randomly.
+The
+.Ar reps
+argument is expected to be an unsigned integer,
+and if given as zero is taken to be infinite.
+The
+.Ar begin
+and
+.Ar end
+arguments may be given as real numbers or as characters
+representing the corresponding value in
+.Tn ASCII .
+The last argument must be a real number.
+.Pp
+Random numbers are obtained through
+.Xr arc4random 3
+when no seed is specified,
+and through
+.Xr random 3
+when a seed is given.
+When
+.Nm
+is asked to generate random integers or characters with begin
+and end values in the range of the random number generator function
+and no format is specified with one of the
+.Fl w ,
+.Fl b ,
+or
+.Fl p
+options,
+.Nm
+will arrange for all the values in the range to appear in the output
+with an equal probability.
+In all other cases be careful to ensure that the output format's
+rounding or truncation will not skew the distribution of output
+values in an unintended way.
+.Pp
+The name
+.Nm
+derives in part from
+.Nm iota ,
+a function in APL.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The command
+.Dl jot - 1 10
+.Pp
+prints the integers from 1 to 10,
+while the command
+.Dl jot 21 -1 1.00
+.Pp
+prints 21 evenly spaced numbers increasing from -1 to 1.
+The
+.Tn ASCII
+character set is generated with
+.Dl jot -c 128 0
+.Pp
+and the strings xaa through xaz with
+.Dl jot -w xa%c 26 a
+.Pp
+while 20 random 8-letter strings are produced with
+.Dl "jot -r -c 160 a z | rs -g 0 8"
+.Pp
+Infinitely many
+.Em yes Ns 's
+may be obtained through
+.Dl jot -b yes 0
+.Pp
+and thirty
+.Xr ed 1
+substitution commands applying to lines 2, 7, 12, etc.\& is
+the result of
+.Dl jot -w %ds/old/new/ 30 2 - 5
+.Pp
+The stuttering sequence 9, 9, 8, 8, 7, etc.\& can be
+produced by suitable choice of step size,
+as in
+.Dl jot - 9 0 -.5
+.Pp
+and a file containing exactly 1024 bytes is created with
+.Dl jot -b x 512 > block
+.Pp
+Finally, to set tabs four spaces apart starting
+from column 10 and ending in column 132, use
+.Dl expand -`jot -s, - 10 132 4`
+.Pp
+and to print all lines 80 characters or longer,
+.Dl grep `jot -s \&"\&" -b \&. 80`
+.Sh DIAGNOSTICS
+The following diagnostic messages deserve special explanation:
+.Bl -diag
+.It "illegal or unsupported format '%s'"
+The requested conversion format specifier for
+.Xr printf 3
+was not of the form
+.Dl %[#][ ][{+,-}][0-9]*[.[0-9]*]?
+where
+.Dq ?\&
+must be one of
+.Dl [l]{d,i,o,u,x}
+or
+.Dl {c,e,f,g,D,E,G,O,U,X}
+.It "range error in conversion"
+A value to be printed fell outside the range of the data type
+associated with the requested output format.
+.It "too many conversions"
+More than one conversion format specifier has been supplied,
+but only one is allowed.
+.El
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr expand 1 ,
+.Xr rs 1 ,
+.Xr seq 1 ,
+.Xr yes 1 ,
+.Xr arc4random 3 ,
+.Xr printf 3 ,
+.Xr random 3
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Bx 4.2 .
diff --git a/shell_cmds/jot/jot.c b/shell_cmds/jot/jot.c
new file mode 100644
index 0000000..1438755
--- /dev/null
+++ b/shell_cmds/jot/jot.c
@@ -0,0 +1,490 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)jot.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/jot/jot.c,v 1.40 2009/12/13 03:14:06 delphij Exp $");
+
+/*
+ * jot - print sequential or random data
+ *
+ * Author: John Kunze, Office of Comp. Affairs, UCB
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+/* Defaults */
+#define REPS_DEF 100
+#define BEGIN_DEF 1
+#define ENDER_DEF 100
+#define STEP_DEF 1
+
+/* Flags of options that have been set */
+#define HAVE_STEP 1
+#define HAVE_ENDER 2
+#define HAVE_BEGIN 4
+#define HAVE_REPS 8
+
+#define is_default(s) (*(s) == 0 || strcmp((s), "-") == 0)
+
+static bool boring;
+static int prec;
+static bool longdata;
+static bool intdata;
+static bool chardata;
+static bool nosign;
+static const char *sepstring = "\n";
+static char format[BUFSIZ];
+
+static void getformat(void);
+static int getprec(const char *);
+static int putdata(double, bool);
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ bool have_format = false;
+ bool infinity = false;
+ bool nofinalnl = false;
+ bool randomize = false;
+ bool use_random = false;
+ int ch;
+ int mask = 0;
+ int n = 0;
+ double begin = BEGIN_DEF;
+ double divisor;
+ double ender = ENDER_DEF;
+ double s = STEP_DEF;
+ double x, y;
+ long i;
+ long reps = REPS_DEF;
+
+ while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1)
+ switch (ch) {
+ case 'b':
+ boring = true;
+ /* FALLTHROUGH */
+ case 'w':
+ if (strlcpy(format, optarg, sizeof(format)) >=
+ sizeof(format))
+ errx(1, "-%c word too long", ch);
+ have_format = true;
+ break;
+ case 'c':
+ chardata = true;
+ break;
+ case 'n':
+ nofinalnl = true;
+ break;
+ case 'p':
+ prec = atoi(optarg);
+ if (prec <= 0)
+ errx(1, "bad precision value");
+ have_format = true;
+ break;
+ case 'r':
+ randomize = true;
+ break;
+ case 's':
+ sepstring = optarg;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) { /* examine args right to left, falling thru cases */
+ case 4:
+ if (!is_default(argv[3])) {
+ if (!sscanf(argv[3], "%lf", &s))
+ errx(1, "bad s value: %s", argv[3]);
+ mask |= HAVE_STEP;
+ if (randomize)
+ use_random = true;
+ }
+ /* FALLTHROUGH */
+ case 3:
+ if (!is_default(argv[2])) {
+ if (!sscanf(argv[2], "%lf", &ender))
+ ender = argv[2][strlen(argv[2])-1];
+ mask |= HAVE_ENDER;
+ if (!prec)
+ n = getprec(argv[2]);
+ }
+ /* FALLTHROUGH */
+ case 2:
+ if (!is_default(argv[1])) {
+ if (!sscanf(argv[1], "%lf", &begin))
+ begin = argv[1][strlen(argv[1])-1];
+ mask |= HAVE_BEGIN;
+ if (!prec)
+ prec = getprec(argv[1]);
+ if (n > prec) /* maximum precision */
+ prec = n;
+ }
+ /* FALLTHROUGH */
+ case 1:
+ if (!is_default(argv[0])) {
+ if (!sscanf(argv[0], "%ld", &reps))
+ errx(1, "bad reps value: %s", argv[0]);
+ mask |= HAVE_REPS;
+ }
+ break;
+ case 0:
+ usage();
+ default:
+ errx(1, "too many arguments. What do you mean by %s?",
+ argv[4]);
+ }
+ getformat();
+ while (mask) /* 4 bit mask has 1's where last 4 args were given */
+ switch (mask) { /* fill in the 0's by default or computation */
+ case HAVE_STEP:
+ case HAVE_ENDER:
+ case HAVE_ENDER | HAVE_STEP:
+ case HAVE_BEGIN:
+ case HAVE_BEGIN | HAVE_STEP:
+ reps = REPS_DEF;
+ mask |= HAVE_REPS;
+ break;
+ case HAVE_BEGIN | HAVE_ENDER:
+ s = ender > begin ? 1 : -1;
+ mask |= HAVE_STEP;
+ break;
+ case HAVE_BEGIN | HAVE_ENDER | HAVE_STEP:
+ if (randomize)
+ reps = REPS_DEF;
+ else if (s == 0.0)
+ reps = 0;
+ else
+ reps = (ender - begin + s) / s;
+ if (reps <= 0)
+ errx(1, "impossible stepsize");
+ mask = 0;
+ break;
+ case HAVE_REPS:
+ case HAVE_REPS | HAVE_STEP:
+ begin = BEGIN_DEF;
+ mask |= HAVE_BEGIN;
+ break;
+ case HAVE_REPS | HAVE_ENDER:
+ s = STEP_DEF;
+ mask = HAVE_REPS | HAVE_ENDER | HAVE_STEP;
+ break;
+ case HAVE_REPS | HAVE_ENDER | HAVE_STEP:
+ if (randomize)
+ begin = BEGIN_DEF;
+ else if (reps == 0)
+ errx(1, "must specify begin if reps == 0");
+ begin = ender - reps * s + s;
+ mask = 0;
+ break;
+ case HAVE_REPS | HAVE_BEGIN:
+ s = STEP_DEF;
+ mask = HAVE_REPS | HAVE_BEGIN | HAVE_STEP;
+ break;
+ case HAVE_REPS | HAVE_BEGIN | HAVE_STEP:
+ if (randomize)
+ ender = ENDER_DEF;
+ else
+ ender = begin + reps * s - s;
+ mask = 0;
+ break;
+ case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER:
+ if (reps == 0)
+ errx(1, "infinite sequences cannot be bounded");
+ else if (reps == 1)
+ s = 0.0;
+ else
+ s = (ender - begin) / (reps - 1);
+ mask = 0;
+ break;
+ case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER | HAVE_STEP:
+ /* if reps given and implied, */
+ if (!randomize && s != 0.0) {
+ long t = (ender - begin + s) / s;
+ if (t <= 0)
+ errx(1, "impossible stepsize");
+ if (t < reps) /* take lesser */
+ reps = t;
+ }
+ mask = 0;
+ break;
+ default:
+ errx(1, "bad mask");
+ }
+ if (reps == 0)
+ infinity = true;
+ if (randomize) {
+ if (use_random) {
+ srandom((unsigned long)s);
+ divisor = (double)INT32_MAX + 1;
+ } else
+ divisor = (double)UINT32_MAX + 1;
+
+ /*
+ * Attempt to DWIM when the user has specified an
+ * integer range within that of the random number
+ * generator: distribute the numbers equally in
+ * the range [begin .. ender]. Jot's default %.0f
+ * format would make the appearance of the first and
+ * last specified value half as likely as the rest.
+ */
+ if (!have_format && prec == 0 &&
+ begin >= 0 && begin < divisor &&
+ ender >= 0 && ender < divisor) {
+ ender += 1;
+ nosign = true;
+ intdata = true;
+ (void)strlcpy(format,
+ chardata ? "%c" : "%u", sizeof(format));
+ }
+ x = (ender - begin) * (ender > begin ? 1 : -1);
+ for (i = 1; i <= reps || infinity; i++) {
+ if (use_random)
+ y = random() / divisor;
+ else
+ y = arc4random() / divisor;
+ if (putdata(y * x + begin, !(reps - i)))
+ errx(1, "range error in conversion");
+ }
+ } else
+ for (i = 1, x = begin; i <= reps || infinity; i++, x += s)
+ if (putdata(x, !(reps - i)))
+ errx(1, "range error in conversion");
+ if (!nofinalnl)
+ putchar('\n');
+ exit(0);
+}
+
+/*
+ * Send x to stdout using the specified format.
+ * Last is true if this is the set's last value.
+ * Return 0 if OK, or a positive number if the number passed was
+ * outside the range specified by the various flags.
+ */
+static int
+putdata(double x, bool last)
+{
+
+ if (boring)
+ printf("%s", format);
+ else if (longdata && nosign) {
+ if (x <= (double)ULONG_MAX && x >= (double)0)
+ printf(format, (unsigned long)x);
+ else
+ return (1);
+ } else if (longdata) {
+ if (x <= (double)LONG_MAX && x >= (double)LONG_MIN)
+ printf(format, (long)x);
+ else
+ return (1);
+ } else if (chardata || (intdata && !nosign)) {
+ if (x <= (double)INT_MAX && x >= (double)INT_MIN)
+ printf(format, (int)x);
+ else
+ return (1);
+ } else if (intdata) {
+ if (x <= (double)UINT_MAX && x >= (double)0)
+ printf(format, (unsigned int)x);
+ else
+ return (1);
+
+ } else
+ printf(format, x);
+ if (!last)
+ fputs(sepstring, stdout);
+
+ return (0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "%s\n%s\n",
+ "usage: jot [-cnr] [-b word] [-w word] [-s string] [-p precision]",
+ " [reps [begin [end [s]]]]");
+ exit(1);
+}
+
+/*
+ * Return the number of digits following the number's decimal point.
+ * Return 0 if no decimal point is found.
+ */
+static int
+getprec(const char *str)
+{
+ const char *p;
+ const char *q;
+
+ for (p = str; *p; p++)
+ if (*p == '.')
+ break;
+ if (!*p)
+ return (0);
+ for (q = ++p; *p; p++)
+ if (!isdigit((unsigned char)*p))
+ break;
+ return (p - q);
+}
+
+/*
+ * Set format, intdata, chardata, longdata, and nosign
+ * based on the command line arguments.
+ */
+static void
+getformat(void)
+{
+ char *p, *p2;
+ int dot, hash, space, sign, numbers = 0;
+ size_t sz;
+
+ if (boring) /* no need to bother */
+ return;
+ for (p = format; *p; p++) /* look for '%' */
+ if (*p == '%') {
+ if (p[1] == '%')
+ p++; /* leave %% alone */
+ else
+ break;
+ }
+ sz = sizeof(format) - strlen(format) - 1;
+ if (!*p && !chardata) {
+ if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
+ errx(1, "-w word too long");
+ } else if (!*p && chardata) {
+ if (strlcpy(p, "%c", sz) >= sz)
+ errx(1, "-w word too long");
+ intdata = true;
+ } else if (!*(p+1)) {
+ if (sz <= 0)
+ errx(1, "-w word too long");
+ strcat(format, "%"); /* cannot end in single '%' */
+ } else {
+ /*
+ * Allow conversion format specifiers of the form
+ * %[#][ ][{+,-}][0-9]*[.[0-9]*]? where ? must be one of
+ * [l]{d,i,o,u,x} or {f,e,g,E,G,d,o,x,D,O,U,X,c,u}
+ */
+ p2 = p++;
+ dot = hash = space = sign = numbers = 0;
+ while (!isalpha((unsigned char)*p)) {
+ if (isdigit((unsigned char)*p)) {
+ numbers++;
+ p++;
+ } else if ((*p == '#' && !(numbers|dot|sign|space|
+ hash++)) ||
+ (*p == ' ' && !(numbers|dot|space++)) ||
+ ((*p == '+' || *p == '-') && !(numbers|dot|sign++))
+ || (*p == '.' && !(dot++)))
+ p++;
+ else
+ goto fmt_broken;
+ }
+ if (*p == 'l') {
+ longdata = true;
+ if (*++p == 'l') {
+ if (p[1] != '\0')
+ p++;
+ goto fmt_broken;
+ }
+ }
+ switch (*p) {
+ case 'o': case 'u': case 'x': case 'X':
+ intdata = nosign = true;
+ break;
+ case 'd': case 'i':
+ intdata = true;
+ break;
+ case 'D':
+ if (!longdata) {
+ intdata = true;
+ break;
+ }
+ case 'O': case 'U':
+ if (!longdata) {
+ intdata = nosign = true;
+ break;
+ }
+ case 'c':
+ if (!(intdata | longdata)) {
+ chardata = true;
+ break;
+ }
+ case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
+ case '$': case '*':
+ goto fmt_broken;
+ case 'f': case 'e': case 'g': case 'E': case 'G':
+ if (!longdata)
+ break;
+ /* FALLTHROUGH */
+ default:
+fmt_broken:
+ *++p = '\0';
+ errx(1, "illegal or unsupported format '%s'", p2);
+ /* NOTREACHED */
+ }
+ while (*++p)
+ if (*p == '%' && *(p+1) && *(p+1) != '%')
+ errx(1, "too many conversions");
+ else if (*p == '%' && *(p+1) == '%')
+ p++;
+ else if (*p == '%' && !*(p+1)) {
+ if (strlcat(format, "%", sizeof(format)) >=
+ sizeof(format))
+ errx(1, "-w word too long");
+ break;
+ }
+ }
+}
diff --git a/shell_cmds/kill/kill.1 b/shell_cmds/kill/kill.1
new file mode 100644
index 0000000..07699e6
--- /dev/null
+++ b/shell_cmds/kill/kill.1
@@ -0,0 +1,152 @@
+.\"-
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)kill.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD$
+.\"
+.Dd April 28, 1995
+.Dt KILL 1
+.Os
+.Sh NAME
+.Nm kill
+.Nd terminate or signal a process
+.Sh SYNOPSIS
+.Nm
+.Op Fl s Ar signal_name
+.Ar pid ...
+.Nm
+.Fl l
+.Op Ar exit_status
+.Nm
+.Fl Ar signal_name
+.Ar pid ...
+.Nm
+.Fl Ar signal_number
+.Ar pid ...
+.Sh DESCRIPTION
+The
+.Nm
+utility sends a signal to the processes specified by the
+.Ar pid
+operands.
+.Pp
+Only the super-user may send signals to other users' processes.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl s Ar signal_name
+A symbolic signal name specifying the signal to be sent instead of the
+default
+.Dv TERM .
+.It Fl l Op Ar exit_status
+If no operand is given, list the signal names; otherwise, write
+the signal name corresponding to
+.Ar exit_status .
+.It Fl Ar signal_name
+A symbolic signal name specifying the signal to be sent instead of the
+default
+.Dv TERM .
+.It Fl Ar signal_number
+A non-negative decimal integer, specifying the signal to be sent instead
+of the default
+.Dv TERM .
+.El
+.Pp
+The following PIDs have special meanings:
+.Bl -tag -width indent
+.It -1
+If superuser, broadcast the signal to all processes; otherwise broadcast
+to all processes belonging to the user.
+.El
+.Pp
+Some of the more commonly used signals:
+.Pp
+.Bl -tag -width indent -compact
+.It 1
+HUP (hang up)
+.It 2
+INT (interrupt)
+.It 3
+QUIT (quit)
+.It 6
+ABRT (abort)
+.It 9
+KILL (non-catchable, non-ignorable kill)
+.It 14
+ALRM (alarm clock)
+.It 15
+TERM (software termination signal)
+.El
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Terminate
+the processes with PIDs 142 and 157:
+.Pp
+.Dl "kill 142 157"
+.Pp
+Send the hangup signal
+.Pq Dv SIGHUP
+to the process with PID 507:
+.Pp
+.Dl "kill -s HUP 507"
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr killall 1 ,
+.Xr ps 1 ,
+.Xr sh 1 ,
+.Xr kill 2 ,
+.Xr sigaction 2
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v3 .
+.Sh BUGS
+A replacement for the command
+.Dq Li kill 0
+for
+.Xr csh 1
+users should be provided.
diff --git a/shell_cmds/kill/kill.c b/shell_cmds/kill/kill.c
new file mode 100644
index 0000000..bd4d908
--- /dev/null
+++ b/shell_cmds/kill/kill.c
@@ -0,0 +1,230 @@
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Important: This file is used both as a standalone program /bin/kill and
+ * as a builtin for /bin/sh (#define SHELL).
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)kill.c 8.4 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef SHELL
+#define main killcmd
+#include "bltin/bltin.h"
+#endif
+
+static void nosig(const char *);
+static void printsignals(FILE *);
+static int signame_to_signum(const char *);
+static void usage(void);
+static void print_signum(int, FILE *, char);
+
+#ifdef __APPLE__
+#define sys_nsig NSIG
+#endif /* __APPLE__ */
+
+int
+main(int argc, char *argv[])
+{
+ int errors, numsig, pid, ret;
+ char *ep;
+
+ if (argc < 2)
+ usage();
+
+ numsig = SIGTERM;
+
+ argc--, argv++;
+ if (!strcmp(*argv, "-l")) {
+ argc--, argv++;
+ if (argc > 1)
+ usage();
+ if (argc == 1) {
+ if (!isdigit(**argv))
+ usage();
+ numsig = strtol(*argv, &ep, 10);
+ if (!**argv || *ep)
+ errx(2, "illegal signal number: %s", *argv);
+ if (numsig >= 128)
+ numsig -= 128;
+ if (numsig <= 0 || numsig >= sys_nsig)
+ nosig(*argv);
+ print_signum(numsig, stdout, '\n');
+ return (0);
+ }
+ printsignals(stdout);
+ return (0);
+ }
+
+ if (!strcmp(*argv, "-s")) {
+ argc--, argv++;
+ if (argc < 1) {
+ warnx("option requires an argument -- s");
+ usage();
+ }
+ if (strcmp(*argv, "0")) {
+ if ((numsig = signame_to_signum(*argv)) < 0)
+ nosig(*argv);
+ } else
+ numsig = 0;
+ argc--, argv++;
+ } else if (**argv == '-' && *(*argv + 1) != '-') {
+ ++*argv;
+ if (isalpha(**argv)) {
+ if ((numsig = signame_to_signum(*argv)) < 0)
+ nosig(*argv);
+ } else if (isdigit(**argv)) {
+ numsig = strtol(*argv, &ep, 10);
+ if (!**argv || *ep)
+ errx(2, "illegal signal number: %s", *argv);
+ if (numsig < 0)
+ nosig(*argv);
+ } else
+ nosig(*argv);
+ argc--, argv++;
+ }
+
+ if (argc > 0 && strncmp(*argv, "--", 2) == 0)
+ argc--, argv++;
+
+ if (argc == 0)
+ usage();
+
+ for (errors = 0; argc; argc--, argv++) {
+#ifdef SHELL
+ if (**argv == '%')
+ ret = killjob(*argv, numsig);
+ else
+#endif
+ {
+ pid = strtol(*argv, &ep, 10);
+ if (!**argv || *ep)
+ errx(2, "illegal process id: %s", *argv);
+ ret = kill(pid, numsig);
+ }
+ if (ret == -1) {
+ warn("%s", *argv);
+ errors = 1;
+ }
+ }
+
+ return (errors);
+}
+
+static void
+print_signum(int numsig, FILE *fp, char separator)
+{
+ char *signame;
+ int i;
+
+ signame = strdup(sys_signame[numsig]);
+
+ for(i = 0; signame[i] != '\0'; i++) {
+ char upper = toupper(signame[i]);
+ signame[i] = upper;
+ }
+ fprintf(fp, "%s%c", signame, separator);
+
+ free(signame);
+}
+
+static int
+signame_to_signum(const char *sig)
+{
+ int n;
+
+ if (strncasecmp(sig, "SIG", 3) == 0)
+ sig += 3;
+ for (n = 1; n < sys_nsig; n++) {
+ if (!strcasecmp(sys_signame[n], sig))
+ return (n);
+ }
+ return (-1);
+}
+
+static void
+nosig(const char *name)
+{
+
+ warnx("unknown signal %s; valid signals:", name);
+ printsignals(stderr);
+#ifdef SHELL
+ error(NULL);
+#else
+ exit(2);
+#endif
+}
+
+static void
+printsignals(FILE *fp)
+{
+ int n;
+
+ for (n = 1; n < sys_nsig; n++) {
+ char sep = ' ';
+ if (n == (sys_nsig / 2) || n == (sys_nsig - 1))
+ sep = '\n';
+ print_signum(n, fp, sep);
+ }
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
+ "usage: kill [-s signal_name] pid ...",
+ " kill -l [exit_status]",
+ " kill -signal_name pid ...",
+ " kill -signal_number pid ...");
+#ifdef SHELL
+ error(NULL);
+#else
+ exit(2);
+#endif
+}
diff --git a/shell_cmds/kill/kill.plist.part b/shell_cmds/kill/kill.plist.part
new file mode 100644
index 0000000..f7fcb9e
--- /dev/null
+++ b/shell_cmds/kill/kill.plist.part
@@ -0,0 +1,18 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>kill</string>
+ <key>OpenSourceVersion</key>
+ <string>2015-03-01</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/bin/kill/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/bin/kill/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2015-07-24</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>kill.c: sys_nsig</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/killall/killall.1 b/shell_cmds/killall/killall.1
new file mode 100644
index 0000000..7c7b59d
--- /dev/null
+++ b/shell_cmds/killall/killall.1
@@ -0,0 +1,159 @@
+.\" Copyright (C) 1995 by Joerg Wunsch, Dresden
+.\" 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(S) ``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(S) BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/killall/killall.1,v 1.34 2005/01/17 07:44:20 ru Exp $
+.\"
+.Dd January 26, 2004
+.Os
+.Dt KILLALL 1
+.Sh NAME
+.Nm killall
+.Nd kill processes by name
+.Sh SYNOPSIS
+.Nm
+.Op Fl delmsvz
+.Op Fl help
+.Op Fl u Ar user
+.Op Fl t Ar tty
+.Op Fl c Ar procname
+.Op Fl SIGNAL
+.Op Ar procname ...
+.Sh DESCRIPTION
+The
+.Nm
+utility kills processes selected by name, as opposed to the selection by pid
+as done by
+.Xr kill 1 .
+By default, it will send a
+.Dv TERM
+signal to all processes with a real UID identical to the
+caller of
+.Nm
+that match the name
+.Ar procname .
+The super-user is allowed to kill any process.
+.Pp
+The options are as follows:
+.Bl -tag -width 10n -offset indent
+.It Fl v
+Be more verbose about what will be done.
+.It Fl e
+Use the effective user ID instead of the (default) real user ID for matching
+processes specified with the
+.Fl u
+option.
+.It Fl help
+Give a help on the command usage and exit.
+.It Fl l
+List the names of the available signals and exit, like in
+.Xr kill 1 .
+.It Fl m
+Match the argument
+.Ar procname
+as a (case sensitive) regular expression against the names
+of processes found.
+CAUTION!
+This is dangerous, a single dot will match any process
+running under the real UID of the caller.
+.It Fl s
+Show only what would be done, but do not send any signal.
+.It Fl d
+Print detailed information about the processes matched,
+but do not send any signal.
+.It Fl SIGNAL
+Send a different signal instead of the default
+.Dv TERM .
+The signal may be specified either as a name
+(with or without a leading
+.Dv SIG ) ,
+or numerically.
+.It Fl u Ar user
+Limit potentially matching processes to those belonging to
+the specified
+.Ar user .
+.It Fl t Ar tty
+Limit potentially matching processes to those running on
+the specified
+.Ar tty .
+.It Fl c Ar procname
+When used with the
+.Fl u
+or
+.Fl t
+flags, limit potentially matching processes to those matching
+the specified
+.Ar procname .
+.It Fl z
+Do not skip zombies.
+This should not have any effect except to print a few error messages
+if there are zombie processes that match the specified pattern.
+.El
+.Sh ALL PROCESSES
+Sending a signal to all processes with uid
+.Em XYZ
+is already supported by
+.Xr kill 1 .
+So use
+.Xr kill 1
+for this job (e.g.\& $ kill -TERM -1 or
+as root $ echo kill -TERM -1 | su -m <user>)
+.Sh EXIT STATUS
+The
+.Nm
+command will respond with a short usage message and exit with a status
+of 2 in case of a command error.
+A status of 1 will be returned if
+either no matching process has been found or not all processes have
+been signalled successfully.
+Otherwise, a status of 0 will be
+returned.
+.Sh DIAGNOSTICS
+Diagnostic messages will only be printed if requested by
+.Fl d
+options.
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr sysctl 3
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 2.1 .
+It has been modeled after the
+.Nm
+command as available on other platforms.
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+program was originally written in Perl and was contributed by
+.An Wolfram Schneider ,
+this manual page has been written by
+.An J\(:org Wunsch .
+The current version of
+.Nm
+was rewritten in C by
+.An Peter Wemm
+using
+.Xr sysctl 3 .
diff --git a/shell_cmds/killall/killall.c b/shell_cmds/killall/killall.c
new file mode 100644
index 0000000..4ef96a9
--- /dev/null
+++ b/shell_cmds/killall/killall.c
@@ -0,0 +1,549 @@
+/*-
+ * Copyright (c) 2000 Peter Wemm <peter@FreeBSD.org>
+ * Copyright (c) 2000 Paul Saab <ps@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/killall/killall.c,v 1.31 2004/07/29 18:36:35 maxim Exp $");
+
+#include <sys/param.h>
+#ifndef __APPLE__
+#include <sys/jail.h>
+#endif /* !__APPLE__ */
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <sys/sysctl.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pwd.h>
+#include <signal.h>
+#include <regex.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+#include <locale.h>
+
+#include <getopt.h>
+#define OPTIONS ("c:dej:lmst:u:vz")
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+static void __dead2
+usage(void)
+{
+
+#ifdef __APPLE__
+ fprintf(stderr, "usage: killall [-delmsvz] [-help]\n");
+#else /* !__APPLE__ */
+ fprintf(stderr, "usage: killall [-delmsvz] [-help] [-j jid]\n");
+#endif /* __APPLE__ */
+ fprintf(stderr,
+ " [-u user] [-t tty] [-c cmd] [-SIGNAL] [cmd]...\n");
+ fprintf(stderr, "At least one option or argument to specify processes must be given.\n");
+ exit(1);
+}
+
+static char *
+upper(const char *str)
+{
+ static char buf[80];
+ char *s;
+
+ strncpy(buf, str, sizeof(buf));
+ buf[sizeof(buf) - 1] = '\0';
+ for (s = buf; *s; s++)
+ *s = toupper((unsigned char)*s);
+ return buf;
+}
+
+
+static void
+printsig(FILE *fp)
+{
+ const char *const * p;
+ int cnt;
+ int offset = 0;
+
+ for (cnt = NSIG, p = sys_signame + 1; --cnt; ++p) {
+ offset += fprintf(fp, "%s ", upper(*p));
+ if (offset >= 75 && cnt > 1) {
+ offset = 0;
+ fprintf(fp, "\n");
+ }
+ }
+ fprintf(fp, "\n");
+}
+
+static void
+nosig(char *name)
+{
+
+ warnx("unknown signal %s; valid signals:", name);
+ printsig(stderr);
+ exit(1);
+}
+
+/*
+ * kludge_signal_args - remove any signal option (-SIGXXX, -##) from the argv array.
+ */
+void
+kludge_signal_args(int *argc, char **argv, int *sig)
+{
+ int i;
+ int shift = 0;
+ int kludge = 1;
+ char *ptr;
+ const char *const *p;
+ char *ep;
+
+ /* i = 1, skip program name */
+ for (i = 1; i < *argc; i++) {
+ /* Stop kludging if we encounter -- */
+ if (strcmp(argv[i], "--") == 0)
+ kludge = 0;
+ ptr = argv[i] + 1;
+ /* Only process arguments that start with - and do not look like an existing option. */
+ if (kludge && *argv[i] == '-' && *ptr && strchr(OPTIONS, *ptr) == NULL) {
+ if (isalpha(*ptr)) {
+ if (strcmp(ptr, "help") == 0)
+ usage();
+ if (strncasecmp(ptr, "sig", 3) == 0)
+ ptr += 3;
+ for (*sig = NSIG, p = sys_signame + 1; --*sig; ++p)
+ if (strcasecmp(*p, ptr) == 0) {
+ *sig = p - sys_signame;
+ break;
+ }
+ if (!*sig)
+ nosig(ptr);
+ } else if (isdigit(*ptr)) {
+ *sig = strtol(ptr, &ep, 10);
+ if (*ep)
+ errx(1, "illegal signal number: %s", ptr);
+ if (*sig < 0 || *sig >= NSIG)
+ nosig(ptr);
+ } else
+ nosig(ptr);
+
+ shift++;
+ continue;
+ }
+
+ argv[i - shift] = argv[i];
+ }
+
+ for (i = *argc - shift; i < *argc; i++) {
+ argv[i] = NULL;
+ }
+
+ *argc -= shift;
+}
+
+int
+main(int ac, char **av)
+{
+ struct kinfo_proc *procs = NULL, *newprocs;
+ struct stat sb;
+ struct passwd *pw;
+ regex_t rgx;
+ regmatch_t pmatch;
+ int i, j;
+ char buf[256];
+ char *user = NULL;
+ char *tty = NULL;
+ char *cmd = NULL;
+ int vflag = 0;
+ int sflag = 0;
+ int dflag = 0;
+ int eflag = 0;
+#ifndef __APPLE__
+ int jflag = 0;
+#endif /* !__APPLE__*/
+ int mflag = 0;
+ int zflag = 0;
+ uid_t uid = 0;
+ dev_t tdev = 0;
+ pid_t mypid;
+#ifdef __APPLE__
+ char *thiscmd;
+#else /* !__APPLE__ */
+ char thiscmd[MAXCOMLEN + 1];
+#endif /* __APPLE__ */
+ pid_t thispid;
+#ifndef __APPLE__
+ uid_t thisuid;
+#endif /* !__APPLE__ */
+ dev_t thistdev;
+ int sig = SIGTERM;
+ char *ep;
+ int errors = 0;
+#ifndef __APPLE__
+ int jid;
+#endif /* !__APPLE__ */
+ int mib[4];
+ size_t miblen;
+ int st, nprocs;
+ size_t size;
+ int matched;
+ int killed = 0;
+ int ch;
+
+ setlocale(LC_ALL, "");
+
+ kludge_signal_args(&ac, av, &sig);
+
+ while ((ch = getopt(ac, av, OPTIONS)) != -1) {
+ switch (ch) {
+ case 'c':
+ cmd = optarg;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'e':
+ eflag++;
+ break;
+#ifndef __APPLE__
+ case 'j':
+ jflag++;
+ jid = strtol(optarg, &ep, 10);
+ if (*ep)
+ errx(1, "illegal jid: %s", optarg);
+ if (jail_attach(jid) == -1)
+ err(1, "jail_attach(): %d", jid);
+ break;
+#endif /* __APPLE__ */
+ case 'l':
+ printsig(stdout);
+ exit(0);
+ case 'm':
+ mflag++;
+ break;
+ case 's':
+ sflag++;
+ break;
+ case 't':
+ tty = optarg;
+ break;
+ case 'u':
+ user = optarg;
+ break;
+ case 'v':
+ vflag++;
+ break;
+ case 'z':
+ zflag++;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ ac -= optind;
+ av += optind;
+
+#ifdef __APPLE__
+ if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
+#else /* !__APPLE__*/
+ if (user == NULL && tty == NULL && cmd == NULL && !jflag && ac == 0)
+#endif /* __APPLE__ */
+ usage();
+
+ if (tty) {
+ if (strncmp(tty, "/dev/", 5) == 0)
+ snprintf(buf, sizeof(buf), "%s", tty);
+ else if (strncmp(tty, "tty", 3) == 0)
+ snprintf(buf, sizeof(buf), "/dev/%s", tty);
+ else
+ snprintf(buf, sizeof(buf), "/dev/tty%s", tty);
+ if (stat(buf, &sb) < 0)
+ err(1, "stat(%s)", buf);
+ if (!S_ISCHR(sb.st_mode))
+ errx(1, "%s: not a character device", buf);
+ tdev = sb.st_rdev;
+ if (dflag)
+ printf("ttydev:0x%x\n", tdev);
+ }
+ if (user) {
+ uid = strtol(user, &ep, 10);
+ if (*user == '\0' || *ep != '\0') { /* was it a number? */
+ pw = getpwnam(user);
+ if (pw == NULL)
+ errx(1, "user %s does not exist", user);
+ uid = pw->pw_uid;
+ if (dflag)
+ printf("uid:%d\n", uid);
+ }
+ } else {
+ uid = getuid();
+ if (uid != 0) {
+ pw = getpwuid(uid);
+ if (pw)
+ user = pw->pw_name;
+ if (dflag)
+ printf("uid:%d\n", uid);
+ }
+ }
+ size = 0;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+#ifdef __APPLE__
+ mib[2] = KERN_PROC_ALL;
+#else /* !__APPLE__ */
+ mib[2] = KERN_PROC_PROC;
+#endif /* __APPLE__ */
+ mib[3] = 0;
+ miblen = 3;
+
+ if (user) {
+ mib[2] = eflag ? KERN_PROC_UID : KERN_PROC_RUID;
+ mib[3] = uid;
+ miblen = 4;
+ } else if (tty) {
+ mib[2] = KERN_PROC_TTY;
+ mib[3] = tdev;
+ miblen = 4;
+ }
+
+ do {
+ st = sysctl(mib, miblen, NULL, &size, NULL, 0);
+ if (st == -1)
+ err(1, "could not sysctl(KERN_PROC)");
+ if (!size)
+ errx(1, "could not get size from sysctl(KERN_PROC)");
+ size += size / 10;
+ newprocs = realloc(procs, size);
+ if (newprocs == 0) {
+ if (procs)
+ free(procs);
+ errx(1, "could not reallocate memory");
+ }
+ procs = newprocs;
+ st = sysctl(mib, miblen, procs, &size, NULL, 0);
+ } while (st == -1 && errno == ENOMEM);
+ if (st == -1)
+ err(1, "could not sysctl(KERN_PROC)");
+ if (size % sizeof(struct kinfo_proc) != 0) {
+ fprintf(stderr, "proc size mismatch (%zu total, %zu chunks)\n",
+ size, sizeof(struct kinfo_proc));
+ fprintf(stderr, "userland out of sync with kernel, recompile libkvm etc\n");
+ exit(1);
+ }
+ nprocs = size / sizeof(struct kinfo_proc);
+ if (dflag)
+ printf("nprocs %d\n", nprocs);
+ mypid = getpid();
+
+ for (i = 0; i < nprocs; i++) {
+#ifdef __APPLE__
+ if (procs[i].kp_proc.p_stat == SZOMB && !zflag)
+ continue;
+ thispid = procs[i].kp_proc.p_pid;
+
+ int mib[3], argmax;
+ size_t syssize;
+ char *procargs, *cp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+
+ syssize = sizeof(argmax);
+ if (sysctl(mib, 2, &argmax, &syssize, NULL, 0) == -1)
+ continue;
+
+ procargs = malloc(argmax);
+ if (procargs == NULL)
+ continue;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS2;
+ mib[2] = thispid;
+
+ syssize = (size_t)argmax;
+ if (sysctl(mib, 3, procargs, &syssize, NULL, 0) == -1) {
+ free(procargs);
+ continue;
+ }
+
+ for (cp = procargs; cp < &procargs[syssize]; cp++) {
+ if (*cp == '\0') {
+ break;
+ }
+ }
+
+ if (cp == &procargs[syssize]) {
+ free(procargs);
+ continue;
+ }
+
+ for (; cp < &procargs[syssize]; cp++) {
+ if (*cp != '\0') {
+ break;
+ }
+ }
+
+ if (cp == &procargs[syssize]) {
+ free(procargs);
+ continue;
+ }
+
+ /* Strip off any path that was specified */
+ for (thiscmd = cp; (cp < &procargs[syssize]) && (*cp != '\0'); cp++) {
+ if (*cp == '/') {
+ thiscmd = cp + 1;
+ }
+ }
+
+ thistdev = procs[i].kp_eproc.e_tdev;
+#else /* !__APPLE__ */
+ if (procs[i].ki_stat == SZOMB && !zflag)
+ continue;
+ thispid = procs[i].ki_pid;
+ strncpy(thiscmd, procs[i].ki_comm, MAXCOMLEN);
+ thiscmd[MAXCOMLEN] = '\0';
+ thistdev = procs[i].ki_tdev;
+#endif /* __APPLE__ */
+#ifndef __APPLE__
+ if (eflag)
+ thisuid = procs[i].ki_uid; /* effective uid */
+ else
+ thisuid = procs[i].ki_ruid; /* real uid */
+#endif /* !__APPLE__ */
+
+ if (thispid == mypid) {
+#ifdef __APPLE__
+ free(procargs);
+#endif /* __APPLE__ */
+ continue;
+ }
+ matched = 1;
+#ifndef __APPLE__
+ if (user) {
+ if (thisuid != uid)
+ matched = 0;
+ }
+#endif /* !__APPLE__ */
+ if (tty) {
+ if (thistdev != tdev)
+ matched = 0;
+ }
+ if (cmd) {
+ if (mflag) {
+ if (regcomp(&rgx, cmd,
+ REG_EXTENDED|REG_NOSUB) != 0) {
+ mflag = 0;
+ warnx("%s: illegal regexp", cmd);
+ }
+ }
+ if (mflag) {
+ pmatch.rm_so = 0;
+ pmatch.rm_eo = strlen(thiscmd);
+ if (regexec(&rgx, thiscmd, 0, &pmatch,
+ REG_STARTEND) != 0)
+ matched = 0;
+ regfree(&rgx);
+ } else {
+ if (strncmp(thiscmd, cmd, MAXCOMLEN) != 0)
+ matched = 0;
+ }
+ }
+#ifndef __APPLE__
+ if (jflag && thispid == getpid())
+ matched = 0;
+#endif /* !__APPLE__ */
+ if (matched == 0) {
+#ifdef __APPLE__
+ free(procargs);
+#endif /* !__APPLE__ */
+ continue;
+ }
+ if (ac > 0)
+ matched = 0;
+ for (j = 0; j < ac; j++) {
+ if (mflag) {
+ if (regcomp(&rgx, av[j],
+ REG_EXTENDED|REG_NOSUB) != 0) {
+ mflag = 0;
+ warnx("%s: illegal regexp", av[j]);
+ }
+ }
+ if (mflag) {
+ pmatch.rm_so = 0;
+ pmatch.rm_eo = strlen(thiscmd);
+ if (regexec(&rgx, thiscmd, 0, &pmatch,
+ REG_STARTEND) == 0)
+ matched = 1;
+ regfree(&rgx);
+ } else {
+ if (strcmp(thiscmd, av[j]) == 0)
+ matched = 1;
+ }
+ if (matched)
+ break;
+ }
+ if (matched == 0) {
+#ifdef __APPLE__
+ free(procargs);
+#endif /* __APPLE__ */
+ continue;
+ }
+ if (dflag)
+#ifdef __APPLE__
+ printf("sig:%d, cmd:%s, pid:%d, dev:0x%x\n", sig,
+ thiscmd, thispid, thistdev);
+#else /* !__APPLE__ */
+ printf("sig:%d, cmd:%s, pid:%d, dev:0x%x uid:%d\n", sig,
+ thiscmd, thispid, thistdev, thisuid);
+#endif /* __APPLE__ */
+
+ if (vflag || sflag)
+ printf("kill -%s %d\n", upper(sys_signame[sig]),
+ thispid);
+
+ killed++;
+ if (!dflag && !sflag) {
+ if (kill(thispid, sig) < 0 /* && errno != ESRCH */ ) {
+ warn("warning: kill -%s %d",
+ upper(sys_signame[sig]), thispid);
+ errors = 1;
+ }
+ }
+#ifdef __APPLE__
+ free(procargs);
+#endif /* __APPLE__ */
+ }
+ if (killed == 0) {
+ fprintf(stderr, "No matching processes %swere found\n",
+ getuid() != 0 ? "belonging to you " : "");
+ errors = 1;
+ }
+ exit(errors);
+}
diff --git a/shell_cmds/lastcomm/lastcomm.1 b/shell_cmds/lastcomm/lastcomm.1
new file mode 100644
index 0000000..96f7638
--- /dev/null
+++ b/shell_cmds/lastcomm/lastcomm.1
@@ -0,0 +1,132 @@
+.\" $NetBSD: lastcomm.1,v 1.11 2006/12/22 08:00:20 ad Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" @(#)lastcomm.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd December 22, 2006
+.Dt LASTCOMM 1
+.Os
+.Sh NAME
+.Nm lastcomm
+.Nd show last commands executed in reverse order
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar file
+.Op Ar command ...
+.Op Ar user ...
+.Op Ar terminal ...
+.Sh DESCRIPTION
+.Nm
+gives information on previously executed commands.
+With no arguments,
+.Nm
+prints information about all the commands recorded
+during the current accounting file's lifetime.
+.Pp
+Option:
+.Pp
+.Bl -tag -width Fl
+.It Fl f Ar file
+Read from
+.Ar file
+rather than the default
+accounting file.
+.El
+.Pp
+If called with arguments, only accounting entries with a
+matching
+.Ar command
+name,
+.Ar user
+name,
+or
+.Ar terminal
+name
+are printed.
+So, for example:
+.Pp
+.Dl lastcomm a.out root ttyd0
+.Pp
+would produce a listing of all the
+executions of commands named
+.Pa a.out
+by user
+.Ar root
+on the terminal
+.Ar ttyd0 .
+.Pp
+For each process entry, the following are printed.
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+The name of the user who ran the process.
+.It
+Flags, as accumulated by the accounting facilities in the system.
+.It
+The command name under which the process was called.
+.It
+The amount of cpu time used by the process (in seconds).
+.It
+The time the process started.
+.It
+The elapsed time of the process.
+.El
+.Pp
+The flags are encoded as follows:
+.Dq S
+indicates the command was
+executed by the super-user,
+.Dq F
+indicates the command ran after
+a fork, but without a following
+.Xr exec 3 ,
+.Dq C
+indicates the command was run in PDP-11 compatibility mode
+(VAX only),
+.Dq D
+indicates the command terminated with the generation of a
+.Pa core
+file, and
+.Dq X
+indicates the command was terminated with a signal.
+.Sh FILES
+.Bl -tag -width /var/account/acct -compact
+.It Pa /var/account/acct
+Default accounting file.
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr sigaction 2 ,
+.Xr acct 5 ,
+.Xr core 5
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/lastcomm/lastcomm.c b/shell_cmds/lastcomm/lastcomm.c
new file mode 100644
index 0000000..e1d9b66
--- /dev/null
+++ b/shell_cmds/lastcomm/lastcomm.c
@@ -0,0 +1,235 @@
+/* $NetBSD: lastcomm.c,v 1.21 2009/04/12 13:08:31 lukem Exp $ */
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1993\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lastcomm.c 8.2 (Berkeley) 4/29/95";
+#endif
+__RCSID("$NetBSD: lastcomm.c,v 1.21 2009/04/12 13:08:31 lukem Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/acct.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <math.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <struct.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+/* definitions from utmp.h */
+#define UT_NAMESIZE 8
+#define UT_LINESIZE 8
+#include "pathnames.h"
+
+static time_t expand(u_int);
+static char *flagbits(int);
+static const char *getdev(dev_t);
+static int requested(char *[], struct acct *);
+static void usage(void) __dead;
+
+int main(int, char **);
+
+int
+main(int argc, char *argv[])
+{
+ char *p;
+ struct acct ab;
+ struct stat sb;
+ FILE *fp;
+ off_t size;
+ time_t t;
+ double delta;
+ int ch;
+ const char *acctfile = _PATH_ACCT;
+
+ setprogname(argv[0]);
+
+ while ((ch = getopt(argc, argv, "f:")) != -1)
+ switch((char)ch) {
+ case 'f':
+ acctfile = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* Open the file. */
+ if ((fp = fopen(acctfile, "r")) == NULL || fstat(fileno(fp), &sb))
+ err(1, "%s", acctfile);
+
+ /*
+ * Round off to integral number of accounting records, probably
+ * not necessary, but it doesn't hurt.
+ */
+ size = sb.st_size - sb.st_size % sizeof(struct acct);
+
+ /* Check if any records to display. */
+ if (size < (off_t)sizeof(struct acct))
+ exit(0);
+
+ /*
+ * Seek to before the last entry in the file; use lseek(2) in case
+ * the file is bigger than a "long".
+ */
+ size -= sizeof(struct acct);
+ if (lseek(fileno(fp), size, SEEK_SET) == -1)
+ err(1, "%s", acctfile);
+
+ for (;;) {
+ if (fread(&ab, sizeof(struct acct), 1, fp) != 1)
+ err(1, "%s", acctfile);
+
+ if (ab.ac_comm[0] == '\0') {
+ ab.ac_comm[0] = '?';
+ ab.ac_comm[1] = '\0';
+ } else
+ for (p = &ab.ac_comm[0];
+ p < &ab.ac_comm[fldsiz(acct, ac_comm)] && *p; ++p)
+ if (!isprint((unsigned char)*p))
+ *p = '?';
+ if (!*argv || requested(argv, &ab)) {
+
+ time_t timelong = ab.ac_btime;
+ t = expand(ab.ac_utime) + expand(ab.ac_stime);
+ (void)printf(
+ "%-*.*s %-7s %-*.*s %-*.*s %6.2f secs %.16s",
+ (int)fldsiz(acct, ac_comm),
+ (int)fldsiz(acct, ac_comm),
+ ab.ac_comm, flagbits(ab.ac_flag),
+ UT_NAMESIZE, UT_NAMESIZE,
+ user_from_uid(ab.ac_uid, 0), UT_LINESIZE,
+ UT_LINESIZE, getdev(ab.ac_tty),
+ t / (double)AHZ, ctime(&timelong));
+ delta = expand(ab.ac_etime) / (double)AHZ;
+ printf(" (%1.0f:%02.0f:%05.2f)\n",
+ floor(delta / SECSPERHOUR),
+ floor(fmod(delta, SECSPERHOUR) / SECSPERMIN),
+ fmod(delta, SECSPERMIN));
+ }
+ /* are we at the beginning of the file yet? */
+ if (size == 0)
+ break;
+ /* seek backward over the one we read and the next to read */
+ if (fseek(fp, 2 * -(long)sizeof(struct acct), SEEK_CUR) == -1)
+ err(1, "%s", acctfile);
+ /* and account for its size */
+ size -= sizeof(struct acct);
+ }
+ exit(0);
+}
+
+static time_t
+expand(u_int t)
+{
+ time_t nt;
+
+ nt = t & 017777;
+ t >>= 13;
+ while (t) {
+ t--;
+ nt <<= 3;
+ }
+ return (nt);
+}
+
+static char *
+flagbits(int f)
+{
+ static char flags[20] = "-";
+ char *p;
+
+#define BIT(flag, ch) if (f & flag) *p++ = ch
+
+ p = flags + 1;
+ BIT(ASU, 'S');
+ BIT(AFORK, 'F');
+ BIT(ACOMPAT, 'C');
+ BIT(ACORE, 'D');
+ BIT(AXSIG, 'X');
+ *p = '\0';
+ return (flags);
+}
+
+static int
+requested(char *argv[], struct acct *acp)
+{
+ do {
+ if (!strcmp(user_from_uid(acp->ac_uid, 0), *argv))
+ return (1);
+ if (!strcmp(getdev(acp->ac_tty), *argv))
+ return (1);
+ if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
+ return (1);
+ } while (*++argv);
+ return (0);
+}
+
+static const char *
+getdev(dev_t dev)
+{
+ static dev_t lastdev = (dev_t)-1;
+ static const char *lastname;
+
+ if (dev == NODEV) /* Special case. */
+ return ("__");
+ if (dev == lastdev) /* One-element cache. */
+ return (lastname);
+ lastdev = dev;
+ if ((lastname = devname(dev, S_IFCHR)) == NULL)
+ lastname = "??";
+ return (lastname);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "Usage: %s [ -f file ] [command ...] [user ...] [tty ...]\n",
+ getprogname());
+ exit(1);
+}
diff --git a/shell_cmds/lastcomm/pathnames.h b/shell_cmds/lastcomm/pathnames.h
new file mode 100644
index 0000000..6ca75d8
--- /dev/null
+++ b/shell_cmds/lastcomm/pathnames.h
@@ -0,0 +1,36 @@
+/* $NetBSD: pathnames.h,v 1.4 2003/08/07 11:14:18 agc Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+#define _PATH_ACCT "/var/account/acct"
diff --git a/shell_cmds/locate/bigram/locate.bigram.8 b/shell_cmds/locate/bigram/locate.bigram.8
new file mode 100644
index 0000000..129334c
--- /dev/null
+++ b/shell_cmds/locate/bigram/locate.bigram.8
@@ -0,0 +1 @@
+.so man8/locate.code.8
diff --git a/shell_cmds/locate/bigram/locate.bigram.c b/shell_cmds/locate/bigram/locate.bigram.c
new file mode 100644
index 0000000..a4ad2b1
--- /dev/null
+++ b/shell_cmds/locate/bigram/locate.bigram.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/locate/bigram/locate.bigram.c,v 1.12 2005/02/09 09:13:36 stefanf Exp $
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)locate.bigram.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * bigram < sorted_file_names | sort -nr |
+ * awk 'NR <= 128 { printf $2 }' > bigrams
+ *
+ * List bigrams for 'updatedb' script.
+ * Use 'code' to encode a file using this output.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h> /* for MAXPATHLEN */
+#include "locate.h"
+
+u_char buf1[MAXPATHLEN] = " ";
+u_char buf2[MAXPATHLEN];
+u_int bigram[UCHAR_MAX + 1][UCHAR_MAX + 1];
+
+int
+main(void)
+{
+ register u_char *cp;
+ register u_char *oldpath = buf1, *path = buf2;
+ register u_int i, j;
+
+ while (fgets(path, sizeof(buf2), stdin) != NULL) {
+
+ /*
+ * We don't need remove newline character '\n'.
+ * '\n' is less than ASCII_MIN and will be later
+ * ignored at output.
+ */
+
+
+ /* skip longest common prefix */
+ for (cp = path; *cp == *oldpath; cp++, oldpath++)
+ if (*cp == '\0')
+ break;
+
+ while (*cp != '\0' && *(cp + 1) != '\0') {
+ bigram[(u_char)*cp][(u_char)*(cp + 1)]++;
+ cp += 2;
+ }
+
+ /* swap pointers */
+ if (path == buf1) {
+ path = buf2;
+ oldpath = buf1;
+ } else {
+ path = buf1;
+ oldpath = buf2;
+ }
+ }
+
+ /* output, boundary check */
+ for (i = ASCII_MIN; i <= ASCII_MAX; i++)
+ for (j = ASCII_MIN; j <= ASCII_MAX; j++)
+ if (bigram[i][j] != 0)
+ (void)printf("%4u %c%c\n", bigram[i][j], i, j);
+
+ exit(0);
+}
diff --git a/shell_cmds/locate/code/locate.code.8 b/shell_cmds/locate/code/locate.code.8
new file mode 100644
index 0000000..64dcfea
--- /dev/null
+++ b/shell_cmds/locate/code/locate.code.8
@@ -0,0 +1,23 @@
+.Dd October 15, 2004
+.Dt LOCATE.CODE 8
+.Os Darwin
+.Sh NAME
+.Nm locate.code, locate.bigram
+.Nd sorted list compressor
+.Sh SYNOPSIS
+.Nm locate.code
+.Nm locate.bigram
+.Sh DESCRIPTION
+.Nm locate.code
+and
+.Nm locate.bigram
+are programs used by
+.Xr locate 1
+during the indexing process.
+.Nm locate.code
+and
+.Nm locate.bigram
+should not be run manually.
+.Sh SEE ALSO
+.Xr locate 1 ,
+.Xr locate.updatedb 8
diff --git a/shell_cmds/locate/code/locate.code.c b/shell_cmds/locate/code/locate.code.c
new file mode 100644
index 0000000..9f7850e
--- /dev/null
+++ b/shell_cmds/locate/code/locate.code.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/locate/code/locate.code.c,v 1.13 2002/03/22 01:22:47 imp Exp $
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)locate.code.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * PURPOSE: sorted list compressor (works with a modified 'find'
+ * to encode/decode a filename database)
+ *
+ * USAGE: bigram < list > bigrams
+ * process bigrams (see updatedb) > common_bigrams
+ * code common_bigrams < list > squozen_list
+ *
+ * METHOD: Uses 'front compression' (see ";login:", Volume 8, Number 1
+ * February/March 1983, p. 8). Output format is, per line, an
+ * offset differential count byte followed by a partially bigram-
+ * encoded ascii residue. A bigram is a two-character sequence,
+ * the first 128 most common of which are encoded in one byte.
+ *
+ * EXAMPLE: For simple front compression with no bigram encoding,
+ * if the input is... then the output is...
+ *
+ * /usr/src 0 /usr/src
+ * /usr/src/cmd/aardvark.c 8 /cmd/aardvark.c
+ * /usr/src/cmd/armadillo.c 14 armadillo.c
+ * /usr/tmp/zoo 5 tmp/zoo
+ *
+ * The codes are:
+ *
+ * 0-28 likeliest differential counts + offset to make nonnegative
+ * 30 switch code for out-of-range count to follow in next word
+ * 31 an 8 bit char followed
+ * 128-255 bigram codes (128 most common, as determined by 'updatedb')
+ * 32-127 single character (printable) ascii residue (ie, literal)
+ *
+ * The locate database store any character except newline ('\n')
+ * and NUL ('\0'). The 8-bit character support don't wast extra
+ * space until you have characters in file names less than 32
+ * or greather than 127.
+ *
+ *
+ * SEE ALSO: updatedb.sh, ../bigram/locate.bigram.c
+ *
+ * AUTHOR: James A. Woods, Informatics General Corp.,
+ * NASA Ames Research Center, 10/82
+ * 8-bit file names characters:
+ * Wolfram Schneider, Berlin September 1996
+ */
+
+#include <sys/param.h>
+#include <err.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "locate.h"
+
+#define BGBUFSIZE (NBG * 2) /* size of bigram buffer */
+
+u_char buf1[MAXPATHLEN] = " ";
+u_char buf2[MAXPATHLEN];
+u_char bigrams[BGBUFSIZE + 1] = { 0 };
+
+#define LOOKUP 1 /* use a lookup array instead a function, 3x faster */
+
+#ifdef LOOKUP
+#define BGINDEX(x) (big[(u_char)*x][(u_char)*(x + 1)])
+typedef short bg_t;
+bg_t big[UCHAR_MAX + 1][UCHAR_MAX + 1];
+#else
+#define BGINDEX(x) bgindex(x)
+typedef int bg_t;
+int bgindex(char *);
+#endif /* LOOKUP */
+
+
+void usage(void);
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register u_char *cp, *oldpath, *path;
+ int ch, code, count, diffcount, oldcount;
+ FILE *fp;
+ register int i, j;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ if ((fp = fopen(argv[0], "r")) == NULL)
+ err(1, "%s", argv[0]);
+
+ /* First copy bigram array to stdout. */
+ (void)fgets(bigrams, BGBUFSIZE + 1, fp);
+
+ if (fwrite(bigrams, 1, BGBUFSIZE, stdout) != BGBUFSIZE)
+ err(1, "stdout");
+ (void)fclose(fp);
+
+#ifdef LOOKUP
+ /* init lookup table */
+ for (i = 0; i < UCHAR_MAX + 1; i++)
+ for (j = 0; j < UCHAR_MAX + 1; j++)
+ big[i][j] = (bg_t)-1;
+
+ for (cp = bigrams, i = 0; *cp != '\0'; i += 2, cp += 2)
+ big[(u_char)*cp][(u_char)*(cp + 1)] = (bg_t)i;
+
+#endif /* LOOKUP */
+
+ oldpath = buf1;
+ path = buf2;
+ oldcount = 0;
+
+ while (fgets(path, sizeof(buf2), stdin) != NULL) {
+
+ /* skip empty lines */
+ if (*path == '\n')
+ continue;
+
+ /* remove newline */
+ for (cp = path; *cp != '\0'; cp++) {
+#ifndef LOCATE_CHAR30
+ /* old locate implementations core'd for char 30 */
+ if (*cp == SWITCH)
+ *cp = '?';
+ else
+#endif /* !LOCATE_CHAR30 */
+
+ /* chop newline */
+ if (*cp == '\n')
+ *cp = '\0';
+ }
+
+ /* Skip longest common prefix. */
+ for (cp = path; *cp == *oldpath; cp++, oldpath++)
+ if (*cp == '\0')
+ break;
+
+ count = cp - path;
+ diffcount = count - oldcount + OFFSET;
+ oldcount = count;
+ if (diffcount < 0 || diffcount > 2 * OFFSET) {
+ if (putchar(SWITCH) == EOF ||
+ putw(diffcount, stdout) == EOF)
+ err(1, "stdout");
+ } else
+ if (putchar(diffcount) == EOF)
+ err(1, "stdout");
+
+ while (*cp != '\0') {
+ /* print *two* characters */
+
+ if ((code = BGINDEX(cp)) != (bg_t)-1) {
+ /*
+ * print *one* as bigram
+ * Found, so mark byte with
+ * parity bit.
+ */
+ if (putchar((code / 2) | PARITY) == EOF)
+ err(1, "stdout");
+ cp += 2;
+ }
+
+ else {
+ for (i = 0; i < 2; i++) {
+ if (*cp == '\0')
+ break;
+
+ /* print umlauts in file names */
+ if (*cp < ASCII_MIN ||
+ *cp > ASCII_MAX) {
+ if (putchar(UMLAUT) == EOF ||
+ putchar(*cp++) == EOF)
+ err(1, "stdout");
+ }
+
+ else {
+ /* normal character */
+ if(putchar(*cp++) == EOF)
+ err(1, "stdout");
+ }
+ }
+
+ }
+ }
+
+ if (path == buf1) { /* swap pointers */
+ path = buf2;
+ oldpath = buf1;
+ } else {
+ path = buf1;
+ oldpath = buf2;
+ }
+ }
+ /* Non-zero status if there were errors */
+ if (fflush(stdout) != 0 || ferror(stdout))
+ exit(1);
+ exit(0);
+}
+
+#ifndef LOOKUP
+int
+bgindex(bg) /* Return location of bg in bigrams or -1. */
+ char *bg;
+{
+ register char bg0, bg1, *p;
+
+ bg0 = bg[0];
+ bg1 = bg[1];
+ for (p = bigrams; *p != NULL; p++)
+ if (*p++ == bg0 && *p == bg1)
+ break;
+ return (*p == NULL ? -1 : (--p - bigrams));
+}
+#endif /* !LOOKUP */
+
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: locate.code common_bigrams < list > squozen_list\n");
+ exit(1);
+}
diff --git a/shell_cmds/locate/locate/com.apple.locate.plist b/shell_cmds/locate/locate/com.apple.locate.plist
new file mode 100644
index 0000000..ceb9078
--- /dev/null
+++ b/shell_cmds/locate/locate/com.apple.locate.plist
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.locate</string>
+ <key>Disabled</key>
+ <true/>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/locate.updatedb</string>
+ </array>
+ <key>ProcessType</key>
+ <string>Background</string>
+ <key>KeepAlive</key>
+ <dict>
+ <key>PathState</key>
+ <dict>
+ <key>/var/db/locate.database</key>
+ <false/>
+ </dict>
+ </dict>
+ <key>StartCalendarInterval</key>
+ <dict>
+ <key>Hour</key>
+ <integer>3</integer>
+ <key>Minute</key>
+ <integer>15</integer>
+ <key>Weekday</key>
+ <integer>6</integer>
+ </dict>
+ <key>AbandonProcessGroup</key>
+ <true/>
+</dict>
+</plist>
diff --git a/shell_cmds/locate/locate/concatdb.sh b/shell_cmds/locate/locate/concatdb.sh
new file mode 100644
index 0000000..a236332
--- /dev/null
+++ b/shell_cmds/locate/locate/concatdb.sh
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# 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.
+#
+# concatdb - concatenate locate databases
+#
+# usage: concatdb database1 ... databaseN > newdb
+#
+# Sequence of databases is important.
+#
+# $FreeBSD: src/usr.bin/locate/locate/concatdb.sh,v 1.10 2000/01/12 08:01:00 kris Exp $
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR:=/usr/libexec}; export LIBEXECDIR
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+umask 077 # protect temp files
+
+: ${TMPDIR:=/var/tmp}; export TMPDIR;
+test -d "$TMPDIR" || TMPDIR=/var/tmp
+
+# utilities to built locate database
+: ${bigram:=locate.bigram}
+: ${code:=locate.code}
+: ${sort:=sort}
+: ${locate:=locate}
+
+
+case $# in
+ [01]) echo 'usage: concatdb databases1 ... databaseN > newdb'
+ exit 1
+ ;;
+esac
+
+
+bigrams=`mktemp ${TMPDIR=/tmp}/_bigrams.XXXXXXXXXX` || exit 1
+trap 'rm -f $bigrams' 0 1 2 3 5 10 15
+
+for db
+do
+ $locate -d $db /
+done | $bigram | $sort -nr | awk 'NR <= 128 { printf $2 }' > $bigrams
+
+for db
+do
+ $locate -d $db /
+done | $code $bigrams
diff --git a/shell_cmds/locate/locate/fastfind.c b/shell_cmds/locate/locate/fastfind.c
new file mode 100644
index 0000000..e683de7
--- /dev/null
+++ b/shell_cmds/locate/locate/fastfind.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/locate/locate/fastfind.c,v 1.14 2005/12/07 12:22:46 des Exp $
+ */
+
+
+#ifndef _LOCATE_STATISTIC_
+#define _LOCATE_STATISTIC_
+
+void
+statistic (fp, path_fcodes)
+ FILE *fp; /* open database */
+ char *path_fcodes; /* for error message */
+{
+ register int lines, chars, size, big, zwerg;
+ register u_char *p, *s;
+ register int c;
+ int count, umlaut;
+ u_char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN];
+
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++) {
+ p[c] = check_bigram_char(getc(fp));
+ s[c] = check_bigram_char(getc(fp));
+ }
+
+ lines = chars = big = zwerg = umlaut = 0;
+ size = NBG + NBG;
+
+ for (c = getc(fp), count = 0; c != EOF; size++) {
+ if (c == SWITCH) {
+ count += getwf(fp) - OFFSET;
+ size += sizeof(int);
+ zwerg++;
+ } else
+ count += c - OFFSET;
+
+ for (p = path + count; (c = getc(fp)) > SWITCH; size++)
+ if (c < PARITY) {
+ if (c == UMLAUT) {
+ c = getc(fp);
+ size++;
+ umlaut++;
+ }
+ p++;
+ } else {
+ /* bigram char */
+ big++;
+ p += 2;
+ }
+
+ p++;
+ lines++;
+ chars += (p - path);
+ }
+
+ (void)printf("\nDatabase: %s\n", path_fcodes);
+ (void)printf("Compression: Front: %2.2f%%, ",
+ (size + big - (2 * NBG)) / (chars / (float)100));
+ (void)printf("Bigram: %2.2f%%, ", (size - big) / (size / (float)100));
+ (void)printf("Total: %2.2f%%\n",
+ (size - (2 * NBG)) / (chars / (float)100));
+ (void)printf("Filenames: %d, ", lines);
+ (void)printf("Characters: %d, ", chars);
+ (void)printf("Database size: %d\n", size);
+ (void)printf("Bigram characters: %d, ", big);
+ (void)printf("Integers: %d, ", zwerg);
+ (void)printf("8-Bit characters: %d\n", umlaut);
+
+}
+#endif /* _LOCATE_STATISTIC_ */
+
+extern char separator;
+
+void
+#ifdef FF_MMAP
+
+
+#ifdef FF_ICASE
+fastfind_mmap_icase
+#else
+fastfind_mmap
+#endif /* FF_ICASE */
+(pathpart, paddr, len, database)
+ char *pathpart; /* search string */
+ caddr_t paddr; /* mmap pointer */
+ int len; /* length of database */
+ char *database; /* for error message */
+
+
+#else /* MMAP */
+
+
+#ifdef FF_ICASE
+fastfind_icase
+#else
+fastfind
+#endif /* FF_ICASE */
+
+(fp, pathpart, database)
+ FILE *fp; /* open database */
+ char *pathpart; /* search string */
+ char *database; /* for error message */
+
+
+#endif /* MMAP */
+
+{
+ register u_char *p, *s, *patend, *q, *foundchar;
+ register int c, cc;
+ int count, found, globflag;
+ u_char *cutoff;
+ u_char bigram1[NBG], bigram2[NBG], path[MAXPATHLEN];
+
+#ifdef FF_ICASE
+ /* use a lookup table for case insensitive search */
+ u_char table[UCHAR_MAX + 1];
+
+ tolower_word(pathpart);
+#endif /* FF_ICASE*/
+
+ /* init bigram table */
+#ifdef FF_MMAP
+ if (len < (2*NBG))
+ errx(1, "database too small: %s", database);
+
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++, len-= 2) {
+ p[c] = check_bigram_char(*paddr++);
+ s[c] = check_bigram_char(*paddr++);
+ }
+#else
+ for (c = 0, p = bigram1, s = bigram2; c < NBG; c++) {
+ p[c] = check_bigram_char(getc(fp));
+ s[c] = check_bigram_char(getc(fp));
+ }
+#endif /* FF_MMAP */
+
+ /* find optimal (last) char for searching */
+ for (p = pathpart; *p != '\0'; p++)
+ if (index(LOCATE_REG, *p) != NULL)
+ break;
+
+ if (*p == '\0')
+ globflag = 0;
+ else
+ globflag = 1;
+
+ p = pathpart;
+ patend = patprep(p);
+ cc = *patend;
+
+#ifdef FF_ICASE
+ /* set patend char to true */
+ for (c = 0; c < UCHAR_MAX + 1; c++)
+ table[c] = 0;
+
+ table[TOLOWER(*patend)] = 1;
+ table[toupper(*patend)] = 1;
+#endif /* FF_ICASE */
+
+
+ /* main loop */
+ found = count = 0;
+ foundchar = 0;
+
+#ifdef FF_MMAP
+ c = (u_char)*paddr++; len--;
+ for (; len > 0; ) {
+#else
+ c = getc(fp);
+ for (; c != EOF; ) {
+#endif /* FF_MMAP */
+
+ /* go forward or backward */
+ if (c == SWITCH) { /* big step, an integer */
+#ifdef FF_MMAP
+ count += getwm(paddr) - OFFSET;
+ len -= INTSIZE; paddr += INTSIZE;
+#else
+ count += getwf(fp) - OFFSET;
+#endif /* FF_MMAP */
+ } else { /* slow step, =< 14 chars */
+ count += c - OFFSET;
+ }
+
+#ifdef __APPLE__
+ if (count < 0) {
+ errx(1, "Your locate database appears to be corrupt. "
+ "Run 'sudo /usr/libexec/locate.updatedb' to "
+ "regenerate the database.");
+ }
+#endif /* __APPLE__ */
+
+ /* overlay old path */
+ p = path + count;
+ foundchar = p - 1;
+
+#ifdef FF_MMAP
+ for (; len > 0;) {
+ c = (u_char)*paddr++;
+ len--;
+#else
+ for (;;) {
+ c = getc(fp);
+#endif /* FF_MMAP */
+ /*
+ * == UMLAUT: 8 bit char followed
+ * <= SWITCH: offset
+ * >= PARITY: bigram
+ * rest: single ascii char
+ *
+ * offset < SWITCH < UMLAUT < ascii < PARITY < bigram
+ */
+ if (c < PARITY) {
+ if (c <= UMLAUT) {
+ if (c == UMLAUT) {
+#ifdef FF_MMAP
+ c = (u_char)*paddr++;
+ len--;
+#else
+ c = getc(fp);
+#endif /* FF_MMAP */
+
+ } else
+ break; /* SWITCH */
+ }
+#ifdef FF_ICASE
+ if (table[c])
+#else
+ if (c == cc)
+#endif /* FF_ICASE */
+ foundchar = p;
+ *p++ = c;
+ }
+ else {
+ /* bigrams are parity-marked */
+ TO7BIT(c);
+
+#ifndef FF_ICASE
+ if (bigram1[c] == cc ||
+ bigram2[c] == cc)
+#else
+
+ if (table[bigram1[c]] ||
+ table[bigram2[c]])
+#endif /* FF_ICASE */
+ foundchar = p + 1;
+
+ *p++ = bigram1[c];
+ *p++ = bigram2[c];
+ }
+ }
+
+ if (found) { /* previous line matched */
+ cutoff = path;
+ *p-- = '\0';
+ foundchar = p;
+ } else if (foundchar >= path + count) { /* a char matched */
+ *p-- = '\0';
+ cutoff = path + count;
+ } else /* nothing to do */
+ continue;
+
+ found = 0;
+ for (s = foundchar; s >= cutoff; s--) {
+ if (*s == cc
+#ifdef FF_ICASE
+ || TOLOWER(*s) == cc
+#endif /* FF_ICASE */
+ ) { /* fast first char check */
+ for (p = patend - 1, q = s - 1; *p != '\0';
+ p--, q--)
+ if (*q != *p
+#ifdef FF_ICASE
+ && TOLOWER(*q) != *p
+#endif /* FF_ICASE */
+ )
+ break;
+ if (*p == '\0') { /* fast match success */
+ found = 1;
+ if (!globflag ||
+#ifndef FF_ICASE
+ !fnmatch(pathpart, path, 0))
+#else
+ !fnmatch(pathpart, path,
+ FNM_CASEFOLD))
+#endif /* !FF_ICASE */
+ {
+ if (f_silent)
+ counter++;
+ else if (f_limit) {
+ counter++;
+ if (f_limit >= counter)
+ (void)printf("%s%c",path,separator);
+ else
+ errx(0, "[show only %d lines]", counter - 1);
+ } else
+ (void)printf("%s%c",path,separator);
+ }
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/shell_cmds/locate/locate/locate.1 b/shell_cmds/locate/locate/locate.1
new file mode 100644
index 0000000..cdde718
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.1
@@ -0,0 +1,276 @@
+.\" Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)locate.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/locate/locate/locate.1,v 1.34 2006/09/29 15:20:45 ru Exp $
+.\"
+.Dd August 17, 2006
+.Dt LOCATE 1
+.Os
+.Sh NAME
+.Nm locate
+.Nd find filenames quickly
+.Sh SYNOPSIS
+.Nm
+.Op Fl 0Scims
+.Op Fl l Ar limit
+.Op Fl d Ar database
+.Ar pattern ...
+.Sh DESCRIPTION
+The
+.Nm
+program searches a database for all pathnames which match the specified
+.Ar pattern .
+The database is recomputed periodically (usually weekly or daily),
+and contains the pathnames
+of all files which are publicly accessible.
+.Pp
+Shell globbing and quoting characters
+.Dq ( * ,
+.Dq \&? ,
+.Dq \e ,
+.Dq \&[
+and
+.Dq \&] )
+may be used in
+.Ar pattern ,
+although they will have to be escaped from the shell.
+Preceding any character with a backslash
+.Pq Dq \e
+eliminates any special
+meaning which it may have.
+The matching differs in that no characters must be matched explicitly,
+including slashes
+.Pq Dq / .
+.Pp
+As a special case, a pattern containing no globbing characters
+.Pq Dq foo
+is matched as though it were
+.Dq *foo* .
+.Pp
+Historically, locate only stored characters between 32 and 127.
+The
+current implementation store any character except newline
+.Pq Sq \en
+and
+.Dv NUL
+.Pq Sq \e0 .
+The 8-bit character support does not waste extra space for
+plain ASCII file names.
+Characters less than 32 or greater than 127
+are stored in 2 bytes.
+.Pp
+The following options are available:
+.Bl -tag -width 10n
+.It Fl 0
+Print pathnames separated by an
+.Tn ASCII
+.Dv NUL
+character (character code 0) instead of default NL
+(newline, character code 10).
+.It Fl S
+Print some statistics about the database and exit.
+.It Fl c
+Suppress normal output; instead print a count of matching file names.
+.It Fl d Ar database
+Search in
+.Ar database
+instead of the default file name database.
+Multiple
+.Fl d
+options are allowed.
+Each additional
+.Fl d
+option adds the specified database to the list
+of databases to be searched.
+.Pp
+The option
+.Ar database
+may be a colon-separated list of databases.
+A single colon is a reference
+to the default database.
+.Bd -literal
+$ locate -d $HOME/lib/mydb: foo
+.Ed
+.Pp
+will first search string
+.Dq foo
+in
+.Pa $HOME/lib/mydb
+and then in
+.Pa /var/db/locate.database .
+.Bd -literal
+$ locate -d $HOME/lib/mydb::/cdrom/locate.database foo
+.Ed
+.Pp
+will first search string
+.Dq foo
+in
+.Pa $HOME/lib/mydb
+and then in
+.Pa /var/db/locate.database
+and then in
+.Pa /cdrom/locate.database .
+.Pp
+.Dl "$ locate -d db1 -d db2 -d db3 pattern"
+.Pp
+is the same as
+.Pp
+.Dl "$ locate -d db1:db2:db3 pattern"
+.Pp
+or
+.Pp
+.Dl "$ locate -d db1:db2 -d db3 pattern"
+.Pp
+If
+.Fl
+is given as the database name, standard input will be read instead.
+For example, you can compress your database
+and use:
+.Bd -literal
+$ zcat database.gz | locate -d - pattern
+.Ed
+.Pp
+This might be useful on machines with a fast CPU and little RAM and slow
+I/O.
+Note: you can only use
+.Em one
+pattern for stdin.
+.It Fl i
+Ignore case distinctions in both the pattern and the database.
+.It Fl l Ar number
+Limit output to
+.Ar number
+of file names and exit.
+.It Fl m
+Use
+.Xr mmap 2
+instead of the
+.Xr stdio 3
+library.
+This is the default behavior
+and is faster in most cases.
+.It Fl s
+Use the
+.Xr stdio 3
+library instead of
+.Xr mmap 2 .
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width LOCATE_PATH -compact
+.It Pa LOCATE_PATH
+path to the locate database if set and not empty, ignored if the
+.Fl d
+option was specified.
+.El
+.Sh FILES
+.Bl -tag -width /System/Library/LaunchDaemons/com.apple.locate.plist -compact
+.It Pa /var/db/locate.database
+locate database
+.It Pa /usr/libexec/locate.updatedb
+Script to update the locate database
+.It Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+Job that starts the database rebuild
+.El
+.Sh SEE ALSO
+.Xr find 1 ,
+.Xr whereis 1 ,
+.Xr which 1 ,
+.Xr fnmatch 3 ,
+.Xr locate.updatedb 8
+.Rs
+.%A Woods, James A.
+.%D 1983
+.%T "Finding Files Fast"
+.%J ";login"
+.%V 8:1
+.%P pp. 8-10
+.Re
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Bx 4.4 .
+Many new features were
+added in
+.Fx 2.2 .
+.Sh BUGS
+The
+.Nm
+program may fail to list some files that are present, or may
+list files that have been removed from the system.
+This is because
+locate only reports files that are present in the database, which is
+typically only regenerated once a week by the
+.Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+job.
+Use
+.Xr find 1
+to locate files that are of a more transitory nature.
+.Pp
+The
+.Nm
+database is typically built by user
+.Dq nobody
+and the
+.Xr locate.updatedb 8
+utility skips directories
+which are not readable for user
+.Dq nobody ,
+group
+.Dq nobody ,
+or
+world.
+For example, if your HOME directory is not world-readable,
+.Em none
+of your files are
+in the database.
+.Pp
+The
+.Nm
+database is not byte order independent.
+It is not possible
+to share the databases between machines with different byte order.
+The current
+.Nm
+implementation understands databases in host byte order or
+network byte order if both architectures use the same integer size.
+So on a
+.Fx Ns /i386
+machine
+(little endian), you can read
+a locate database which was built on SunOS/sparc machine
+(big endian, net).
+.Pp
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/shell_cmds/locate/locate/locate.c b/shell_cmds/locate/locate/locate.c
new file mode 100644
index 0000000..315bfd3
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1995-1996 Wolfram Schneider, Berlin.\n\
+@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)locate.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/locate/locate/locate.c,v 1.17 2006/06/11 17:40:25 maxim Exp $";
+#endif /* not lint */
+
+/*
+ * Ref: Usenix ;login:, Vol 8, No 1, February/March, 1983, p. 8.
+ *
+ * Locate scans a file list for the full pathname of a file given only part
+ * of the name. The list has been processed with with "front-compression"
+ * and bigram coding. Front compression reduces space by a factor of 4-5,
+ * bigram coding by a further 20-25%.
+ *
+ * The codes are:
+ *
+ * 0-28 likeliest differential counts + offset to make nonnegative
+ * 30 switch code for out-of-range count to follow in next word
+ * 31 an 8 bit char followed
+ * 128-255 bigram codes (128 most common, as determined by 'updatedb')
+ * 32-127 single character (printable) ascii residue (ie, literal)
+ *
+ * A novel two-tiered string search technique is employed:
+ *
+ * First, a metacharacter-free subpattern and partial pathname is matched
+ * BACKWARDS to avoid full expansion of the pathname list. The time savings
+ * is 40-50% over forward matching, which cannot efficiently handle
+ * overlapped search patterns and compressed path residue.
+ *
+ * Then, the actual shell glob-style regular expression (if in this form) is
+ * matched against the candidate pathnames using the slower routines provided
+ * in the standard 'find'.
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <err.h>
+#ifdef __APPLE__
+#include <errno.h>
+#endif /* __APPLE__ */
+#include <fnmatch.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef MMAP
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/mman.h>
+# include <fcntl.h>
+#endif
+
+
+#include "locate.h"
+#include "pathnames.h"
+
+#ifdef DEBUG
+# include <sys/time.h>
+# include <sys/types.h>
+# include <sys/resource.h>
+#endif
+
+int f_mmap; /* use mmap */
+int f_icase; /* ignore case */
+int f_stdin; /* read database from stdin */
+int f_statistic; /* print statistic */
+int f_silent; /* suppress output, show only count of matches */
+int f_limit; /* limit number of output lines, 0 == infinite */
+u_int counter; /* counter for matches [-c] */
+char separator='\n'; /* line separator */
+#ifdef __APPLE__
+u_char myctype[UCHAR_MAX + 1];
+#endif /* __APPLE__ */
+
+
+void usage(void);
+void statistic(FILE *, char *);
+void fastfind(FILE *, char *, char *);
+void fastfind_icase(FILE *, char *, char *);
+void fastfind_mmap(char *, caddr_t, int, char *);
+void fastfind_mmap_icase(char *, caddr_t, int, char *);
+void search_mmap(char *, char **);
+void search_fopen(char *, char **);
+unsigned long cputime(void);
+
+extern char **colon(char **, char*, char*);
+extern void print_matches(u_int);
+extern int getwm(caddr_t);
+extern int getwf(FILE *);
+extern u_char *tolower_word(u_char *);
+extern int check_bigram_char(int);
+extern char *patprep(char *);
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register int ch;
+ char **dbv = NULL;
+ char *path_fcodes; /* locate database */
+#ifdef MMAP
+ f_mmap = 1; /* mmap is default */
+#endif
+ (void) setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "0Scd:il:ms")) != -1)
+ switch(ch) {
+ case '0': /* 'find -print0' style */
+ separator = '\0';
+ break;
+ case 'S': /* statistic lines */
+ f_statistic = 1;
+ break;
+ case 'l': /* limit number of output lines, 0 == infinite */
+ f_limit = atoi(optarg);
+ break;
+ case 'd': /* database */
+ dbv = colon(dbv, optarg, _PATH_FCODES);
+ break;
+ case 'i': /* ignore case */
+ f_icase = 1;
+ break;
+ case 'm': /* mmap */
+#ifdef MMAP
+ f_mmap = 1;
+#else
+ warnx("mmap(2) not implemented");
+#endif
+ break;
+ case 's': /* stdio lib */
+ f_mmap = 0;
+ break;
+ case 'c': /* suppress output, show only count of matches */
+ f_silent = 1;
+ break;
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ /* to few arguments */
+ if (argc < 1 && !(f_statistic))
+ usage();
+
+ /* no (valid) database as argument */
+ if (dbv == NULL || *dbv == NULL) {
+ /* try to read database from enviroment */
+ if ((path_fcodes = getenv("LOCATE_PATH")) == NULL ||
+ *path_fcodes == '\0')
+ /* use default database */
+ dbv = colon(dbv, _PATH_FCODES, _PATH_FCODES);
+ else /* $LOCATE_PATH */
+ dbv = colon(dbv, path_fcodes, _PATH_FCODES);
+ }
+
+ if (f_icase && UCHAR_MAX < 4096) /* init tolower lookup table */
+ for (ch = 0; ch < UCHAR_MAX + 1; ch++)
+ myctype[ch] = tolower(ch);
+
+ /* foreach database ... */
+ while((path_fcodes = *dbv) != NULL) {
+ dbv++;
+
+ if (!strcmp(path_fcodes, "-"))
+ f_stdin = 1;
+ else
+ f_stdin = 0;
+
+#ifndef MMAP
+ f_mmap = 0; /* be paranoid */
+#endif
+ if (!f_mmap || f_stdin || f_statistic)
+ search_fopen(path_fcodes, argv);
+ else
+ search_mmap(path_fcodes, argv);
+ }
+
+ if (f_silent)
+ print_matches(counter);
+ exit(0);
+}
+
+
+void
+search_fopen(db, s)
+ char *db; /* database */
+ char **s; /* search strings */
+{
+ FILE *fp;
+#ifdef DEBUG
+ long t0;
+#endif
+
+ /* can only read stdin once */
+ if (f_stdin) {
+ fp = stdin;
+ if (*(s+1) != NULL) {
+ warnx("read database from stdin, use only `%s' as pattern", *s);
+ *(s+1) = NULL;
+ }
+ }
+#ifdef __APPLE__
+ else if ((fp = fopen(db, "r")) == NULL) {
+ if (errno == ENOENT && !strcmp(db, _PATH_FCODES)) {
+ fprintf(stderr, "\n"
+ "WARNING: The locate database (%s) does not exist.\n"
+ "To create the database, run the following command:\n"
+ "\n"
+ " sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist\n"
+ "\n"
+ "Please be aware that the database can take some time to generate; once\n"
+ "the database has been created, this message will no longer appear.\n"
+ "\n",
+ db);
+ exit(1);
+ }
+ err(1, "`%s'", db);
+ }
+#else /* !__APPLE__ */
+ else if ((fp = fopen(db, "r")) == NULL)
+ err(1, "`%s'", db);
+#endif /* __APPLE__ */
+
+ /* count only chars or lines */
+ if (f_statistic) {
+ statistic(fp, db);
+ (void)fclose(fp);
+ return;
+ }
+
+ /* foreach search string ... */
+ while(*s != NULL) {
+#ifdef DEBUG
+ t0 = cputime();
+#endif
+ if (!f_stdin &&
+ fseek(fp, (long)0, SEEK_SET) == -1)
+ err(1, "fseek to begin of ``%s''\n", db);
+
+ if (f_icase)
+ fastfind_icase(fp, *s, db);
+ else
+ fastfind(fp, *s, db);
+#ifdef DEBUG
+ warnx("fastfind %ld ms", cputime () - t0);
+#endif
+ s++;
+ }
+ (void)fclose(fp);
+}
+
+#ifdef MMAP
+void
+search_mmap(db, s)
+ char *db; /* database */
+ char **s; /* search strings */
+{
+ struct stat sb;
+ int fd;
+ caddr_t p;
+ off_t len;
+#ifdef DEBUG
+ long t0;
+#endif
+ if ((fd = open(db, O_RDONLY)) == -1 ||
+ fstat(fd, &sb) == -1)
+ err(1, "`%s'", db);
+ len = sb.st_size;
+
+ if ((p = mmap((caddr_t)0, (size_t)len,
+ PROT_READ, MAP_SHARED,
+ fd, (off_t)0)) == MAP_FAILED)
+ err(1, "mmap ``%s''", db);
+
+ /* foreach search string ... */
+ while (*s != NULL) {
+#ifdef DEBUG
+ t0 = cputime();
+#endif
+ if (f_icase)
+ fastfind_mmap_icase(*s, p, (int)len, db);
+ else
+ fastfind_mmap(*s, p, (int)len, db);
+#ifdef DEBUG
+ warnx("fastfind %ld ms", cputime () - t0);
+#endif
+ s++;
+ }
+
+ if (munmap(p, (size_t)len) == -1)
+ warn("munmap %s\n", db);
+
+ (void)close(fd);
+}
+#endif /* MMAP */
+
+#ifdef DEBUG
+unsigned long
+cputime ()
+{
+ struct rusage rus;
+
+ getrusage(0, &rus);
+ return(rus.ru_utime.tv_sec * 1000 + rus.ru_utime.tv_usec / 1000);
+}
+#endif /* DEBUG */
+
+void
+usage ()
+{
+ (void)fprintf(stderr,
+ "usage: locate [-0Scims] [-l limit] [-d database] pattern ...\n\n");
+ (void)fprintf(stderr,
+ "default database: `%s' or $LOCATE_PATH\n", _PATH_FCODES);
+ exit(1);
+}
+
+
+/* load fastfind functions */
+
+/* statistic */
+/* fastfind_mmap, fastfind_mmap_icase */
+#ifdef MMAP
+#undef FF_MMAP
+#undef FF_ICASE
+
+#define FF_MMAP
+#include "fastfind.c"
+#define FF_ICASE
+#include "fastfind.c"
+#endif /* MMAP */
+
+/* fopen */
+/* fastfind, fastfind_icase */
+#undef FF_MMAP
+#undef FF_ICASE
+#include "fastfind.c"
+#define FF_ICASE
+#include "fastfind.c"
diff --git a/shell_cmds/locate/locate/locate.h b/shell_cmds/locate/locate/locate.h
new file mode 100644
index 0000000..d4aef46
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)locate.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/locate/locate/locate.h,v 1.7 1999/08/28 01:02:59 peter Exp $
+ */
+
+/* Symbolic constants shared by locate.c and code.c */
+
+#define NBG 128 /* number of bigrams considered */
+#define OFFSET 14 /* abs value of max likely diff */
+#define PARITY 0200 /* parity bit */
+#define SWITCH 30 /* switch code */
+#define UMLAUT 31 /* an 8 bit char followed */
+
+/* 0-28 likeliest differential counts + offset to make nonnegative */
+#define LDC_MIN 0
+#define LDC_MAX 28
+
+/* 128-255 bigram codes (128 most common, as determined by 'updatedb') */
+#define BIGRAM_MIN (UCHAR_MAX - CHAR_MAX)
+#define BIGRAM_MAX UCHAR_MAX
+
+/* 32-127 single character (printable) ascii residue (ie, literal) */
+#define ASCII_MIN 32
+#define ASCII_MAX CHAR_MAX
+
+/* #define TO7BIT(x) (x = ( ((u_char)x) & CHAR_MAX )) */
+#define TO7BIT(x) (x = x & CHAR_MAX )
+
+
+#if UCHAR_MAX >= 4096
+ define TOLOWER(ch) tolower(ch)
+#else
+
+#ifdef __APPLE__
+extern u_char myctype[UCHAR_MAX + 1];
+#else
+u_char myctype[UCHAR_MAX + 1];
+#endif
+#define TOLOWER(ch) (myctype[ch])
+#endif
+
+#define INTSIZE (sizeof(int))
+
+#define LOCATE_REG "*?[]\\" /* fnmatch(3) meta characters */
diff --git a/shell_cmds/locate/locate/locate.rc b/shell_cmds/locate/locate/locate.rc
new file mode 100644
index 0000000..09fbf0e
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.rc
@@ -0,0 +1,26 @@
+#
+# /etc/locate.rc - command script for updatedb(8)
+#
+# $FreeBSD: src/usr.bin/locate/locate/locate.rc,v 1.9 2005/08/22 08:22:48 cperciva Exp $
+
+#
+# All commented values are the defaults
+#
+# temp directory
+#TMPDIR="/tmp"
+
+# the actual database
+#FCODES="/var/db/locate.database"
+
+# directories to be put in the database
+#SEARCHPATHS="/"
+
+# directories unwanted in output
+#PRUNEPATHS="/tmp /var/tmp"
+
+# filesystems allowed. Beware: a non-listed filesystem will be pruned
+# and if the SEARCHPATHS starts in such a filesystem locate will build
+# an empty database.
+#
+# be careful if you add 'nfs'
+#FILESYSTEMS="hfs ufs apfs"
diff --git a/shell_cmds/locate/locate/locate.updatedb.8 b/shell_cmds/locate/locate/locate.updatedb.8
new file mode 100755
index 0000000..880668a
--- /dev/null
+++ b/shell_cmds/locate/locate/locate.updatedb.8
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1996
+.\" Mike Pritchard <mpp@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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Mike Pritchard.
+.\" 4. Neither the name of the author 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 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 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.
+.\"
+.\" $FreeBSD: src/usr.bin/locate/locate/locate.updatedb.8,v 1.12 2005/01/18 13:43:50 ru Exp $
+.\"
+.Dd February 11, 1996
+.Dt LOCATE.UPDATEDB 8
+.Os
+.Sh NAME
+.Nm locate.updatedb
+.Nd update locate database
+.Sh SYNOPSIS
+.Nm /usr/libexec/locate.updatedb
+.Sh DESCRIPTION
+The
+.Nm
+utility updates the database used by
+.Xr locate 1 .
+It is typically run once a week by the
+.Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+job.
+.Pp
+The contents of the newly built database can be controlled by the
+.Pa /etc/locate.rc
+file.
+.Sh ENVIRONMENT
+.Bl -tag -width /var/db/locate.database -compact
+.It Pa LOCATE_CONFIG
+path to the configuration file
+.El
+.Sh FILES
+.Bl -tag -width /var/db/locate.database -compact
+.It Pa /var/db/locate.database
+the default database
+.It Pa /etc/locate.rc
+the configuration file
+.El
+.Sh SEE ALSO
+.Xr locate 1 ,
+.Xr launchd 8
+.Rs
+.%A Woods, James A.
+.%D 1983
+.%T "Finding Files Fast"
+.%J ";login"
+.%V 8:1
+.%P pp. 8-10
+.Re
diff --git a/shell_cmds/locate/locate/mklocatedb.sh b/shell_cmds/locate/locate/mklocatedb.sh
new file mode 100644
index 0000000..7231eba
--- /dev/null
+++ b/shell_cmds/locate/locate/mklocatedb.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# 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.
+#
+# mklocatedb - build locate database
+#
+# usage: mklocatedb [-presort] < filelist > database
+#
+# $FreeBSD: src/usr.bin/locate/locate/mklocatedb.sh,v 1.13 2002/07/22 05:35:59 tjr Exp $
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR:=/usr/libexec}; export LIBEXECDIR
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+umask 077 # protect temp files
+
+: ${TMPDIR:=/tmp}; export TMPDIR
+test -d "$TMPDIR" || TMPDIR=/tmp
+if ! TMPDIR=`mktemp -d $TMPDIR/mklocateXXXXXXXXXX`; then
+ exit 1
+fi
+
+
+# utilities to built locate database
+: ${bigram:=locate.bigram}
+: ${code:=locate.code}
+: ${sort:=sort}
+
+
+sortopt="-u -T $TMPDIR"
+sortcmd=$sort
+
+
+bigrams=$TMPDIR/_mklocatedb$$.bigrams
+filelist=$TMPDIR/_mklocatedb$$.list
+
+trap 'rm -f $bigrams $filelist; rmdir $TMPDIR' 0 1 2 3 5 10 15
+
+
+# Input already sorted
+if [ X"$1" = "X-presort" ]; then
+ shift;
+
+ # create an empty file
+ true > $bigrams
+
+ # Locate database bootstrapping
+ # 1. first build a temp database without bigram compression
+ # 2. create the bigram from the temp database
+ # 3. create the real locate database with bigram compression.
+ #
+ # This scheme avoid large temporary files in /tmp
+
+ $code $bigrams > $filelist || exit 1
+ locate -d $filelist / | $bigram | $sort -nr | head -128 |
+ awk '{if (/^[ ]*[0-9]+[ ]+..$/) {printf("%s",$2)} else {exit 1}}' > $bigrams || exit 1
+ locate -d $filelist / | $code $bigrams || exit 1
+ exit
+
+else
+ if $sortcmd $sortopt > $filelist; then
+ $bigram < $filelist | $sort -nr |
+ awk '{if (/^[ ]*[0-9]+[ ]+..$/) {printf("%s",$2)} else {exit 1}}' > $bigrams || exit 1
+ $code $bigrams < $filelist || exit 1
+ else
+ echo "`basename $0`: cannot build locate database" >&2
+ exit 1
+ fi
+fi
diff --git a/shell_cmds/locate/locate/pathnames.h b/shell_cmds/locate/locate/pathnames.h
new file mode 100644
index 0000000..8fb0e8c
--- /dev/null
+++ b/shell_cmds/locate/locate/pathnames.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#define _PATH_FCODES "/var/db/locate.database"
diff --git a/shell_cmds/locate/locate/updatedb.sh b/shell_cmds/locate/locate/updatedb.sh
new file mode 100644
index 0000000..2506f22
--- /dev/null
+++ b/shell_cmds/locate/locate/updatedb.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Copyright (c) September 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# 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.
+#
+# updatedb - update locate database for local mounted filesystems
+#
+# $FreeBSD: src/usr.bin/locate/locate/updatedb.sh,v 1.20 2005/11/12 12:45:08 grog Exp $
+
+if [ "$(id -u)" = "0" ]; then
+ rc=0
+ export FCODES=`sudo -u nobody mktemp -t updatedb`
+ chown nobody $FCODES
+ tmpdb=`su -fm nobody -c "$0"` || rc=1
+ if [ $rc = 0 ]; then
+ install -m 0444 -o nobody -g wheel $FCODES /var/db/locate.database
+ fi
+ rm $FCODES
+ exit $rc
+fi
+: ${LOCATE_CONFIG="/etc/locate.rc"}
+if [ -f "$LOCATE_CONFIG" -a -r "$LOCATE_CONFIG" ]; then
+ . $LOCATE_CONFIG
+fi
+
+# The directory containing locate subprograms
+: ${LIBEXECDIR:=/usr/libexec}; export LIBEXECDIR
+: ${TMPDIR:=/tmp}; export TMPDIR
+if ! TMPDIR=`mktemp -d $TMPDIR/locateXXXXXXXXXX`; then
+ exit 1
+fi
+
+PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
+
+# 6497475
+set -o noglob
+
+: ${mklocatedb:=locate.mklocatedb} # make locate database program
+: ${FCODES:=/var/db/locate.database} # the database
+: ${SEARCHPATHS:="/"} # directories to be put in the database
+: ${PRUNEPATHS:="/private/tmp /private/var/folders /private/var/tmp */Backups.backupdb"} # unwanted directories
+: ${FILESYSTEMS:="hfs ufs apfs"} # allowed filesystems
+: ${find:=find}
+
+case X"$SEARCHPATHS" in
+ X) echo "$0: empty variable SEARCHPATHS"; exit 1;; esac
+case X"$FILESYSTEMS" in
+ X) echo "$0: empty variable FILESYSTEMS"; exit 1;; esac
+
+# Make a list a paths to exclude in the locate run
+excludes="! (" or=""
+for fstype in $FILESYSTEMS
+do
+ excludes="$excludes $or -fstype $fstype"
+ or="-or"
+done
+excludes="$excludes ) -prune"
+
+case X"$PRUNEPATHS" in
+ X) ;;
+ *) for path in $PRUNEPATHS
+ do
+ excludes="$excludes -or -path $path -prune"
+ done;;
+esac
+
+# Ignore the target of firmlinks
+while read firmlink; do
+ excludes="$excludes -or -path $firmlink -prune"
+done <<< "$(awk -F'\t' '{print "/System/Volumes/Data/" $2}' /usr/share/firmlinks)"
+
+tmp=$TMPDIR/_updatedb$$
+trap 'rm -f $tmp; rmdir $TMPDIR; exit' 0 1 2 3 5 10 15
+
+# search locally
+# echo $find $SEARCHPATHS $excludes -or -print && exit
+if $find -s $SEARCHPATHS $excludes -or -print 2>/dev/null |
+ $mklocatedb -presort > $tmp
+then
+ case X"`$find $tmp -size -257c -print`" in
+ X) cat $tmp > $FCODES;;
+ *) echo "updatedb: locate database $tmp is empty"
+ exit 1
+ esac
+fi
diff --git a/shell_cmds/locate/locate/util.c b/shell_cmds/locate/locate/util.c
new file mode 100644
index 0000000..0a94c9c
--- /dev/null
+++ b/shell_cmds/locate/locate/util.c
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 1995 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/locate/locate/util.c,v 1.10 2002/06/24 12:40:11 naddy Exp $
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <sys/param.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+#include "locate.h"
+
+char **colon(char **, char*, char*);
+char *patprep(char *);
+void print_matches(u_int);
+u_char *tolower_word(u_char *);
+int getwm(caddr_t);
+int getwf(FILE *);
+int check_bigram_char(int);
+
+/*
+ * Validate bigram chars. If the test failed the database is corrupt
+ * or the database is obviously not a locate database.
+ */
+int
+check_bigram_char(ch)
+ int ch;
+{
+ /* legal bigram: 0, ASCII_MIN ... ASCII_MAX */
+ if (ch == 0 ||
+ (ch >= ASCII_MIN && ch <= ASCII_MAX))
+ return(ch);
+
+ errx(1,
+ "locate database header corrupt, bigram char outside 0, %d-%d: %d",
+ ASCII_MIN, ASCII_MAX, ch);
+ exit(1);
+}
+
+/* split a colon separated string into a char vector
+ *
+ * "bla:foo" -> {"foo", "bla"}
+ * "bla:" -> {"foo", dot}
+ * "bla" -> {"bla"}
+ * "" -> do nothing
+ *
+ */
+char **
+colon(dbv, path, dot)
+ char **dbv;
+ char *path;
+ char *dot; /* default for single ':' */
+{
+ int vlen, slen;
+ char *c, *ch, *p;
+ char **pv;
+
+ if (dbv == NULL) {
+ if ((dbv = malloc(sizeof(char **))) == NULL)
+ err(1, "malloc");
+ *dbv = NULL;
+ }
+
+ /* empty string */
+ if (*path == '\0') {
+ warnx("empty database name, ignored");
+ return(dbv);
+ }
+
+ /* length of string vector */
+ for(vlen = 0, pv = dbv; *pv != NULL; pv++, vlen++);
+
+ for (ch = c = path; ; ch++) {
+ if (*ch == ':' ||
+ (!*ch && !(*(ch - 1) == ':' && ch == 1+ path))) {
+ /* single colon -> dot */
+ if (ch == c)
+ p = dot;
+ else {
+ /* a string */
+ slen = ch - c;
+ if ((p = malloc(sizeof(char) * (slen + 1)))
+ == NULL)
+ err(1, "malloc");
+ bcopy(c, p, slen);
+ *(p + slen) = '\0';
+ }
+ /* increase dbv with element p */
+ if ((dbv = realloc(dbv, sizeof(char **) * (vlen + 2)))
+ == NULL)
+ err(1, "realloc");
+ *(dbv + vlen) = p;
+ *(dbv + ++vlen) = NULL;
+ c = ch + 1;
+ }
+ if (*ch == '\0')
+ break;
+ }
+ return (dbv);
+}
+
+void
+print_matches(counter)
+ u_int counter;
+{
+ (void)printf("%d\n", counter);
+}
+
+
+/*
+ * extract last glob-free subpattern in name for fast pre-match; prepend
+ * '\0' for backwards match; return end of new pattern
+ */
+static char globfree[100];
+
+char *
+patprep(name)
+ char *name;
+{
+ register char *endmark, *p, *subp;
+
+ subp = globfree;
+ *subp++ = '\0'; /* set first element to '\0' */
+ p = name + strlen(name) - 1;
+
+ /* skip trailing metacharacters */
+ for (; p >= name; p--)
+ if (index(LOCATE_REG, *p) == NULL)
+ break;
+
+ /*
+ * check if maybe we are in a character class
+ *
+ * 'foo.[ch]'
+ * |----< p
+ */
+ if (p >= name &&
+ (index(p, '[') != NULL || index(p, ']') != NULL)) {
+ for (p = name; *p != '\0'; p++)
+ if (*p == ']' || *p == '[')
+ break;
+ p--;
+
+ /*
+ * cannot find a non-meta character, give up
+ * '*\*[a-z]'
+ * |-------< p
+ */
+ if (p >= name && index(LOCATE_REG, *p) != NULL)
+ p = name - 1;
+ }
+
+ if (p < name)
+ /* only meta chars: "???", force '/' search */
+ *subp++ = '/';
+
+ else {
+ for (endmark = p; p >= name; p--)
+ if (index(LOCATE_REG, *p) != NULL)
+ break;
+ for (++p;
+ (p <= endmark) && subp < (globfree + sizeof(globfree));)
+ *subp++ = *p++;
+ }
+ *subp = '\0';
+ return(--subp);
+}
+
+/* tolower word */
+u_char *
+tolower_word(word)
+ u_char *word;
+{
+ register u_char *p;
+
+ for(p = word; *p != '\0'; p++)
+ *p = TOLOWER(*p);
+
+ return(word);
+}
+
+
+/*
+ * Read integer from mmap pointer.
+ * Essential a simple ``return *(int *)p'' but avoid sigbus
+ * for integer alignment (SunOS 4.x, 5.x).
+ *
+ * Convert network byte order to host byte order if neccessary.
+ * So we can read on FreeBSD/i386 (little endian) a locate database
+ * which was built on SunOS/sparc (big endian).
+ */
+
+int
+getwm(p)
+ caddr_t p;
+{
+ union {
+ char buf[INTSIZE];
+ int i;
+ } u;
+ register int i;
+
+ for (i = 0; i < INTSIZE; i++)
+ u.buf[i] = *p++;
+
+ i = u.i;
+
+ if (i > MAXPATHLEN || i < -(MAXPATHLEN)) {
+ i = ntohl(i);
+ if (i > MAXPATHLEN || i < -(MAXPATHLEN))
+ errx(1, "integer out of +-MAXPATHLEN (%d): %d",
+ MAXPATHLEN, abs(i) < abs(htonl(i)) ? i : htonl(i));
+ }
+ return(i);
+}
+
+/*
+ * Read integer from stream.
+ *
+ * Convert network byte order to host byte order if neccessary.
+ * So we can read on FreeBSD/i386 (little endian) a locate database
+ * which was built on SunOS/sparc (big endian).
+ */
+
+int
+getwf(fp)
+ FILE *fp;
+{
+ register int word;
+
+ word = getw(fp);
+
+ if (word > MAXPATHLEN || word < -(MAXPATHLEN)) {
+ word = ntohl(word);
+ if (word > MAXPATHLEN || word < -(MAXPATHLEN))
+ errx(1, "integer out of +-MAXPATHLEN (%d): %d",
+ MAXPATHLEN, abs(word) < abs(htonl(word)) ? word :
+ htonl(word));
+ }
+ return(word);
+}
diff --git a/shell_cmds/logname/logname.1 b/shell_cmds/logname/logname.1
new file mode 100644
index 0000000..4d2a508
--- /dev/null
+++ b/shell_cmds/logname/logname.1
@@ -0,0 +1,78 @@
+.\" $NetBSD: logname.1,v 1.8 1997/10/19 04:20:06 lukem Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)logname.1 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.Dt LOGNAME 1
+.Os BSD 4.4
+.Sh NAME
+.Nm logname
+.Nd display user's login name
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility writes the user's login name to standard output followed by
+a newline.
+.Pp
+The
+.Nm
+utility explicitly ignores the
+.Ev LOGNAME
+and
+.Ev USER
+environment variables
+because the environment cannot be trusted.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr who 1 ,
+.Xr whoami 1 ,
+.Xr getlogin 2
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
diff --git a/shell_cmds/logname/logname.c b/shell_cmds/logname/logname.c
new file mode 100644
index 0000000..ed63ffe
--- /dev/null
+++ b/shell_cmds/logname/logname.c
@@ -0,0 +1,92 @@
+/* $NetBSD: logname.c,v 1.7 1997/10/19 04:20:06 lukem Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)logname.c 8.2 (Berkeley) 4/3/94";
+#endif
+__RCSID("$NetBSD: logname.c,v 1.7 1997/10/19 04:20:06 lukem Exp $");
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+#include <err.h>
+
+int main __P((int, char **));
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch;
+ char *p;
+
+ setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (argc != optind) {
+ usage();
+ /* NOTREACHED */
+ }
+
+ if ((p = getlogin()) == NULL)
+ err(1, "getlogin");
+ (void)printf("%s\n", p);
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: logname\n");
+ exit(1);
+}
diff --git a/shell_cmds/mktemp/mktemp.1 b/shell_cmds/mktemp/mktemp.1
new file mode 100644
index 0000000..921ffa3
--- /dev/null
+++ b/shell_cmds/mktemp/mktemp.1
@@ -0,0 +1,215 @@
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: $OpenBSD: mktemp.1,v 1.8 1998/03/19 06:13:37 millert Exp $
+.\" $FreeBSD$
+.\"
+.Dd December 30, 2005
+.Dt MKTEMP 1
+.Os
+.Sh NAME
+.Nm mktemp
+.Nd make temporary file name (unique)
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl q
+.Op Fl t Ar prefix
+.Op Fl u
+.Ar template ...
+.Nm
+.Op Fl d
+.Op Fl q
+.Op Fl u
+.Fl t Ar prefix
+.Sh DESCRIPTION
+The
+.Nm
+utility takes each of the given file name templates and overwrites a
+portion of it to create a file name.
+This file name is unique
+and suitable for use by the application.
+The template may be
+any file name with some number of
+.Ql X Ns s
+appended
+to it, for example
+.Pa /tmp/temp.XXXX .
+The trailing
+.Ql X Ns s
+are replaced with the current process number and/or a
+unique letter combination.
+The number of unique file names
+.Nm
+can return depends on the number of
+.Ql X Ns s
+provided; six
+.Ql X Ns s
+will
+result in
+.Nm
+selecting 1 of 56800235584 (62 ** 6) possible file names.
+On case-insensitive file systems, the effective number of unique
+names is significantly less; given six
+.Ql X Ns s ,
+.Nm
+will instead select 1 of 2176782336 (36 ** 6) possible unique file names.
+.Pp
+If
+.Nm
+can successfully generate a unique file name, the file
+is created with mode 0600 (unless the
+.Fl u
+flag is given) and the filename is printed
+to standard output.
+.Pp
+If the
+.Fl t Ar prefix
+option is given,
+.Nm
+will generate a template string based on the
+.Ar prefix
+and the
+.Dv _CS_DARWIN_USER_TEMP_DIR
+configuration variable if available.
+Fallback locations if
+.Dv _CS_DARWIN_USER_TEMP_DIR
+is not available are
+.Ev TMPDIR
+and
+.Pa /tmp .
+Care should
+be taken to ensure that it is appropriate to use an environment variable
+potentially supplied by the user.
+.Pp
+If no arguments are passed or if only the
+.Fl d
+flag is passed
+.Nm
+behaves as if
+.Fl t Li tmp
+was supplied.
+.Pp
+Any number of temporary files may be created in a single invocation,
+including one based on the internal template resulting from the
+.Fl t
+flag.
+.Pp
+The
+.Nm
+utility is provided to allow shell scripts to safely use temporary files.
+Traditionally, many shell scripts take the name of the program with
+the pid as a suffix and use that as a temporary file name.
+This
+kind of naming scheme is predictable and the race condition it creates
+is easy for an attacker to win.
+A safer, though still inferior, approach
+is to make a temporary directory using the same naming scheme.
+While
+this does allow one to guarantee that a temporary file will not be
+subverted, it still allows a simple denial of service attack.
+For these
+reasons it is suggested that
+.Nm
+be used instead.
+.Sh OPTIONS
+The available options are as follows:
+.Bl -tag -width indent
+.It Fl d
+Make a directory instead of a file.
+.It Fl q
+Fail silently if an error occurs.
+This is useful if
+a script does not want error output to go to standard error.
+.It Fl t Ar prefix
+Generate a template (using the supplied
+.Ar prefix
+and
+.Ev TMPDIR
+if set) to create a filename template.
+.It Fl u
+Operate in
+.Dq unsafe
+mode.
+The temp file will be unlinked before
+.Nm
+exits.
+This is slightly better than
+.Xr mktemp 3
+but still introduces a race condition.
+Use of this
+option is not encouraged.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The following
+.Xr sh 1
+fragment illustrates a simple use of
+.Nm
+where the script should quit if it cannot get a safe
+temporary file.
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp /tmp/${tempfoo}.XXXXXX` || exit 1
+echo "program output" >> $TMPFILE
+.Ed
+.Pp
+To allow the use of $TMPDIR:
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp -t ${tempfoo}` || exit 1
+echo "program output" >> $TMPFILE
+.Ed
+.Pp
+In this case, we want the script to catch the error itself.
+.Bd -literal -offset indent
+tempfoo=`basename $0`
+TMPFILE=`mktemp -q /tmp/${tempfoo}.XXXXXX`
+if [ $? -ne 0 ]; then
+ echo "$0: Can't create temp file, exiting..."
+ exit 1
+fi
+.Ed
+.Sh SEE ALSO
+.Xr mkdtemp 3 ,
+.Xr mkstemp 3 ,
+.Xr mktemp 3 ,
+.Xr confstr 3 ,
+.Xr environ 7
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.Ox 2.1 .
+This implementation was written independently based on the
+.Ox
+man page, and
+first appeared in
+.Fx 2.2.7 .
+This man page is taken from
+.Ox .
diff --git a/shell_cmds/mktemp/mktemp.c b/shell_cmds/mktemp/mktemp.c
new file mode 100644
index 0000000..11db17e
--- /dev/null
+++ b/shell_cmds/mktemp/mktemp.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 1994, 1995, 1996, 1998 Peter Wemm <peter@netplex.com.au>
+ * 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.
+ *
+ */
+
+/*
+ * This program was originally written long ago, originally for a non
+ * BSD-like OS without mkstemp(). It's been modified over the years
+ * to use mkstemp() rather than the original O_CREAT|O_EXCL/fstat/lstat
+ * etc style hacks.
+ * A cleanup, misc options and mkdtemp() calls were added to try and work
+ * more like the OpenBSD version - which was first to publish the interface.
+ */
+
+#include <err.h>
+#ifdef __APPLE__
+#include <limits.h>
+#endif
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ int c, fd, ret;
+ char *tmpdir;
+ const char *prefix;
+ char *name;
+ int dflag, qflag, tflag, uflag;
+#ifdef __APPLE__
+ char tmpbuf[PATH_MAX];
+ size_t len;
+#endif
+
+ ret = dflag = qflag = tflag = uflag = 0;
+ prefix = "mktemp";
+ name = NULL;
+
+ while ((c = getopt(argc, argv, "dqt:u")) != -1)
+ switch (c) {
+ case 'd':
+ dflag++;
+ break;
+
+ case 'q':
+ qflag++;
+ break;
+
+ case 't':
+ prefix = optarg;
+ tflag++;
+ break;
+
+ case 'u':
+ uflag++;
+ break;
+
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (!tflag && argc < 1) {
+ tflag = 1;
+ prefix = "tmp";
+ }
+
+ if (tflag) {
+#ifdef __APPLE__
+ if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmpbuf, sizeof(tmpbuf)) > 0) {
+ tmpdir = tmpbuf;
+ } else {
+ tmpdir = getenv("TMPDIR");
+ }
+
+ if (tmpdir == NULL) {
+ tmpdir = _PATH_TMP;
+ }
+
+ len = strlen(tmpdir);
+ if (len > 0 && tmpdir[len - 1] == '/') {
+ asprintf(&name, "%s%s.XXXXXXXX", tmpdir, prefix);
+ } else {
+ asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+ }
+#else
+ tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ asprintf(&name, "%s%s.XXXXXXXX", _PATH_TMP, prefix);
+ else
+ asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+#endif
+ /* if this fails, the program is in big trouble already */
+ if (name == NULL) {
+ if (qflag)
+ return (1);
+ else
+ errx(1, "cannot generate template");
+ }
+ }
+
+ /* generate all requested files */
+ while (name != NULL || argc > 0) {
+ if (name == NULL) {
+ name = strdup(argv[0]);
+ argv++;
+ argc--;
+ }
+
+ if (dflag) {
+ if (mkdtemp(name) == NULL) {
+ ret = 1;
+ if (!qflag)
+ warn("mkdtemp failed on %s", name);
+ } else {
+ printf("%s\n", name);
+ if (uflag)
+ rmdir(name);
+ }
+ } else {
+ fd = mkstemp(name);
+ if (fd < 0) {
+ ret = 1;
+ if (!qflag)
+ warn("mkstemp failed on %s", name);
+ } else {
+ close(fd);
+ if (uflag)
+ unlink(name);
+ printf("%s\n", name);
+ }
+ }
+ if (name)
+ free(name);
+ name = NULL;
+ }
+ return (ret);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: mktemp [-d] [-q] [-t prefix] [-u] template ...\n");
+ fprintf(stderr,
+ " mktemp [-d] [-q] [-u] -t prefix \n");
+ exit (1);
+}
diff --git a/shell_cmds/mktemp/mktemp.plist.part b/shell_cmds/mktemp/mktemp.plist.part
new file mode 100644
index 0000000..db10919
--- /dev/null
+++ b/shell_cmds/mktemp/mktemp.plist.part
@@ -0,0 +1,21 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>mktemp</string>
+ <key>OpenSourceVersion</key>
+ <string>2012-11-18</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/usr.bin/mktemp/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/usr.bin/mktemp/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2014-08-11</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Avoid double-slash in output. (5334050)</string>
+ <string>Document case-insensitive file system behavior. (14280248)</string>
+ <string>Prefer _CS_DARWIN_USER_TEMP_DIR over TMPDIR and _PATH_TMP. (14338140)</string>
+ <string>mktemp.1: Clarification of _CS_DARWIN_USER_TEMP_DIR/TMPDIR/_PATH_TMP behavior. (22954705)</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/nice/nice.1 b/shell_cmds/nice/nice.1
new file mode 100644
index 0000000..4dba5c9
--- /dev/null
+++ b/shell_cmds/nice/nice.1
@@ -0,0 +1,120 @@
+.\" $NetBSD: nice.1,v 1.8 1997/10/19 06:28:02 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nice.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt NICE 1
+.Os
+.Sh NAME
+.Nm nice
+.Nd execute a utility with an altered scheduling priority
+.Sh SYNOPSIS
+.Nm
+.Op Fl n Ar increment
+.Ar utility
+.Op Ar argument ...
+.Sh DESCRIPTION
+.Nm
+runs
+.Ar utility
+at an altered scheduling priority.
+If an
+.Ar increment
+is given, it is used; otherwise
+an increment of 10 is assumed.
+The super-user can run utilities with priorities higher than normal by using
+a negative
+.Ar increment .
+The priority can be adjusted over a
+range of -20 (the highest) to 20 (the lowest).
+.Pp
+Available options:
+.Bl -tag -width indent
+.It Fl n Ar increment
+A positive or negative decimal integer used to modify the system scheduling
+priority of
+.Ar utility.
+.El
+.Sh DIAGNOSTICS
+The
+.Nm
+utility shall exit with one of the following values:
+.Bl -tag -width indent
+.It 1-125
+An error occurred in the
+.Nm
+utility.
+.It 126
+The
+.Ar utility
+was found but could not be invoked.
+.It 127
+The
+.Ar utility
+could not be found.
+.El
+.Pp
+Otherwise, the exit status of
+.Nm
+shall be that of
+.Ar utility .
+.Sh COMPATIBILITY
+The historic
+.Fl Ns Ar increment
+option has been deprecated but is still supported in this implementation.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr getpriority 2 ,
+.Xr setpriority 2 ,
+.Xr renice 8
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
+.Sh BUGS
+.Nm
+is built into
+.Xr csh 1
+with a slightly different syntax than described here. The form
+.Ql nice +10
+nices to positive nice, and
+.Ql nice \-10
+can be used
+by the super-user to give a process more of the processor.
diff --git a/shell_cmds/nice/nice.c b/shell_cmds/nice/nice.c
new file mode 100644
index 0000000..62a197e
--- /dev/null
+++ b/shell_cmds/nice/nice.c
@@ -0,0 +1,122 @@
+/* $NetBSD: nice.c,v 1.10 1997/10/19 06:28:04 lukem Exp $ */
+
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT(
+ "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)nice.c 5.4 (Berkeley) 6/1/90";
+#endif
+__RCSID("$NetBSD: nice.c,v 1.10 1997/10/19 06:28:04 lukem Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <ctype.h>
+#include <errno.h>
+#include <err.h>
+#include <unistd.h>
+
+#define DEFNICE 10
+
+int main __P((int, char **));
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int niceness = DEFNICE;
+ int c;
+
+ setlocale(LC_ALL, "");
+
+ /* handle obsolete -number syntax */
+ if (argc > 1 && argv[1][0] == '-' && isdigit(argv[1][1])) {
+ niceness = atoi (argv[1] + 1);
+ argc--; argv++;
+ }
+
+ while ((c = getopt (argc, argv, "n:")) != -1) {
+ switch (c) {
+ case 'n':
+ niceness = atoi (optarg);
+ break;
+
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ argc -= optind; argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ errno = 0;
+ niceness += getpriority(PRIO_PROCESS, 0);
+ if (errno) {
+ err (1, "getpriority");
+ /* NOTREACHED */
+ }
+ if (setpriority(PRIO_PROCESS, 0, niceness)) {
+ warn ("setpriority");
+ }
+
+ execvp(argv[0], &argv[0]);
+ err ((errno == ENOENT) ? 127 : 126, "%s", argv[0]);
+ /* NOTREACHED */
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: nice [ -n increment ] utility [ argument ...]\n");
+
+ exit(1);
+}
diff --git a/shell_cmds/nohup/nohup.1 b/shell_cmds/nohup/nohup.1
new file mode 100644
index 0000000..34f19e6
--- /dev/null
+++ b/shell_cmds/nohup/nohup.1
@@ -0,0 +1,124 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nohup.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/nohup/nohup.1,v 1.13 2005/01/17 07:44:27 ru Exp $
+.\"
+.Dd July 19, 2001
+.Dt NOHUP 1
+.Os
+.Sh NAME
+.Nm nohup
+.Nd invoke a utility immune to hangups
+.Sh SYNOPSIS
+.Nm
+.Op Fl Fl
+.Ar utility
+.Op Ar arguments
+.Sh DESCRIPTION
+The
+.Nm
+utility invokes
+.Ar utility
+with its
+.Ar arguments
+and at this time sets the signal
+.Dv SIGHUP
+to be ignored.
+If the standard output is a terminal, the standard output is
+appended to the file
+.Pa nohup.out
+in the current directory.
+If standard error is a terminal, it is directed to the same place
+as the standard output.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh ENVIRONMENT
+The following variables are utilized by
+.Nm :
+.Bl -tag -width flag
+.It Ev HOME
+If the output file
+.Pa nohup.out
+cannot be created in the current directory, the
+.Nm
+utility uses the directory named by
+.Ev HOME
+to create the file.
+.It Ev PATH
+Used to locate the requested
+.Ar utility
+if the name contains no
+.Ql /
+characters.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width Ds
+.It 126
+The
+.Ar utility
+was found, but could not be invoked.
+.It 127
+The
+.Ar utility
+could not be found or an error occurred in
+.Nm .
+.El
+.Pp
+Otherwise, the exit status of
+.Nm
+will be that of
+.Ar utility .
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr signal 3
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh BUGS
+Two or more instances of
+.Nm
+can append to the same file, which makes for a confusing output.
diff --git a/shell_cmds/nohup/nohup.c b/shell_cmds/nohup/nohup.c
new file mode 100644
index 0000000..021361c
--- /dev/null
+++ b/shell_cmds/nohup/nohup.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)nohup.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/nohup/nohup.c,v 1.10 2003/05/03 19:44:46 obrien Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#include <vproc.h>
+#include <vproc_priv.h>
+#endif
+
+static void dofile(void);
+static void usage(void);
+
+#define FILENAME "nohup.out"
+/*
+ * POSIX mandates that we exit with:
+ * 126 - If the utility was found, but failed to execute.
+ * 127 - If any other error occurred.
+ */
+#define EXIT_NOEXEC 126
+#define EXIT_NOTFOUND 127
+#define EXIT_MISC 127
+
+int
+main(int argc, char *argv[])
+{
+ int exit_status;
+
+ while (getopt(argc, argv, "") != -1)
+ usage();
+ argc -= optind;
+ argv += optind;
+ if (argc < 1)
+ usage();
+
+ if (isatty(STDOUT_FILENO))
+ dofile();
+ if (isatty(STDERR_FILENO) && dup2(STDOUT_FILENO, STDERR_FILENO) == -1)
+ /* may have just closed stderr */
+ err(EXIT_MISC, "%s", argv[0]);
+
+ (void)signal(SIGHUP, SIG_IGN);
+
+#if defined(__APPLE__) && !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (_vprocmgr_detach_from_console(0) != NULL)
+ err(EXIT_MISC, "can't detach from console");
+#endif
+ execvp(*argv, argv);
+ exit_status = (errno == ENOENT) ? EXIT_NOTFOUND : EXIT_NOEXEC;
+ err(exit_status, "%s", argv[0]);
+}
+
+static void
+dofile(void)
+{
+ int fd;
+ char path[MAXPATHLEN];
+ const char *p;
+
+ /*
+ * POSIX mandates if the standard output is a terminal, the standard
+ * output is appended to nohup.out in the working directory. Failing
+ * that, it will be appended to nohup.out in the directory obtained
+ * from the HOME environment variable. If file creation is required,
+ * the mode_t is set to S_IRUSR | S_IWUSR.
+ */
+ p = FILENAME;
+ fd = open(p, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ goto dupit;
+ if ((p = getenv("HOME")) != NULL && *p != '\0' &&
+ (size_t)snprintf(path, sizeof(path), "%s/%s", p, FILENAME) <
+ sizeof(path)) {
+ fd = open(p = path, O_RDWR | O_CREAT | O_APPEND,
+ S_IRUSR | S_IWUSR);
+ if (fd != -1)
+ goto dupit;
+ }
+ errx(EXIT_MISC, "can't open a nohup.out file");
+
+dupit:
+#ifdef __APPLE__
+ (void)lseek(fd, 0L, SEEK_END);
+#endif
+ if (dup2(fd, STDOUT_FILENO) == -1)
+ err(EXIT_MISC, NULL);
+ (void)fprintf(stderr, "appending output to %s\n", p);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: nohup [--] utility [arguments]\n");
+ exit(EXIT_MISC);
+}
diff --git a/shell_cmds/path_helper/path_helper.8 b/shell_cmds/path_helper/path_helper.8
new file mode 100644
index 0000000..c86f2d7
--- /dev/null
+++ b/shell_cmds/path_helper/path_helper.8
@@ -0,0 +1,76 @@
+.\"
+.\" Copyright (c) 2007 Apple Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this
+.\" file.
+.\"
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd March 15, 2007
+.Dt path_helper 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm path_helper
+.Nd helper for constructing PATH environment variable
+.Sh SYNOPSIS
+.Nm
+.Op Fl c | Fl s
+.Sh DESCRIPTION
+The
+.Nm
+utility reads the contents of the files in the directories
+.Pa /etc/paths.d
+and
+.Pa /etc/manpaths.d
+and appends their contents to the
+.Ev PATH
+and
+.Ev MANPATH
+environment variables respectively.
+(The
+.Ev MANPATH
+environment variable will not be modified unless it is already set
+in the environment.)
+.Pp
+Files in these directories should contain one path element per line.
+.Pp
+Prior to reading these directories, default
+.Ev PATH
+and
+.Ev MANPATH
+values are obtained from the files
+.Pa /etc/paths
+and
+.Pa /etc/manpaths
+respectively.
+.Pp
+Options:
+.Bl -tag -width Ds
+.It Fl c
+Generate C-shell commands on stdout. This is the default if
+.Ev SHELL
+ends with "csh".
+.It Fl s
+Generate Bourne shell commands on stdout. This is the default if
+.Ev SHELL
+does not end with "csh".
+.El
+.Sh NOTE
+The
+.Nm
+utility should not be invoked directly.
+It is intended only for use by the shell profile.
diff --git a/shell_cmds/path_helper/path_helper.c b/shell_cmds/path_helper/path_helper.c
new file mode 100644
index 0000000..2313c99
--- /dev/null
+++ b/shell_cmds/path_helper/path_helper.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+static void usage() {
+ fprintf(stderr, "usage: path_helper [-c | -s]");
+ exit(1);
+}
+
+// Append path segment if it does not exist. Reallocate
+// the path buffer as necessary.
+
+int append_path_segment(char** path, const char* segment) {
+ if (*path == NULL || segment == NULL) return -1;
+
+ size_t pathlen = strlen(*path);
+ size_t seglen = strlen(segment);
+
+ if (seglen == 0) return 0;
+
+ // Does the segment already exist in the path?
+ // (^|:)segment(:|$)
+ char* match = strstr(*path, segment);
+ while (match) {
+ if ((match == *path || match[-1] == ':') &&
+ (match[seglen] == ':' || match[seglen] == 0)) {
+ return 0;
+ }
+ match = strstr(match+1, segment);
+ }
+
+ // size = pathlen + ':' + segment + '\0'
+ size_t size = pathlen + seglen + 2;
+ *path = reallocf(*path, size);
+ if (*path == NULL) return -1;
+
+ if (pathlen > 0) strlcat(*path, ":", size);
+ strlcat(*path, segment, size);
+ return 0;
+}
+
+// Convert fgetln output into a sanitized segment
+// escape quotes, dollars, etc.
+char* read_segment(const char* line, size_t len) {
+ int escapes = 0;
+ size_t i, j;
+
+ for (i = 0; i < len; ++i) {
+ char c = line[i];
+ if (c == '\"' || c == '\'' || c == '$') {
+ ++escapes;
+ }
+ }
+
+ size_t size = len + escapes + 1;
+
+ char* segment = calloc(1, size);
+ if (segment == NULL) return NULL;
+
+ for (i = 0, j = 0; i < len; ++i, ++j) {
+ char c = line[i];
+ if (c == '\"' || c == '\'' || c == '$') {
+ segment[j++] = '\\';
+ segment[j] = c;
+ } else if (c == '\n') {
+ segment[j] = 0;
+ break;
+ } else {
+ segment[j] = line[i];
+ }
+ }
+
+ return segment;
+}
+
+// Construct a path variable, starting with the contents
+// of the given environment variable, adding the contents
+// of the default file and files in the path directory.
+
+char* construct_path(char* env_var, char* defaults_path, char* dir_path) {
+ FTS* fts;
+ FTSENT* ent;
+
+ char* result = calloc(sizeof(char), 1);
+
+ char* dirpathv[] = { defaults_path, dir_path, NULL };
+ fts = fts_open(dirpathv, FTS_PHYSICAL | FTS_XDEV, NULL);
+ if (!fts) {
+ perror(dir_path);
+ return NULL;
+ }
+
+ while ((ent = fts_read(fts)) != NULL) {
+ // only interested in regular files, one level deep
+ if (ent->fts_info != FTS_F) {
+ if (ent->fts_level >= 1) fts_set(fts, ent, FTS_SKIP);
+ continue;
+ }
+
+ FILE* f = fopen(ent->fts_accpath, "r");
+ if (f == NULL) {
+ perror(ent->fts_accpath);
+ continue;
+ }
+
+ for (;;) {
+ size_t len;
+ char* line = fgetln(f, &len);
+ if (line == NULL) break;
+ char* segment = read_segment(line, len);
+
+ append_path_segment(&result, segment);
+ }
+
+ fclose(f);
+ }
+ fts_close(fts);
+
+ // merge in any existing custom PATH elemenets
+ char* str = getenv(env_var);
+ if (str) str = strdup(str);
+ while (str) {
+ char* sep = strchr(str, ':');
+ if (sep) *sep = 0;
+
+ append_path_segment(&result, str);
+ if (sep) {
+ str = sep + 1;
+ } else {
+ str = NULL;
+ }
+ }
+
+ return result;
+}
+
+enum {
+ STYLE_CSH,
+ STYLE_SH
+};
+
+int main(int argc, char* argv[]) {
+ int style = STYLE_SH;
+
+ if (argc > 2) usage();
+
+ // default to csh style, if $SHELL ends with "csh".
+ char* shell = getenv("SHELL");
+ if (shell) {
+ char* str = strstr(shell, "csh");
+ if (str) style = STYLE_CSH;
+ }
+
+ if (argc == 2 && strcmp(argv[1], "-c") == 0) style = STYLE_CSH;
+ if (argc == 2 && strcmp(argv[1], "-s") == 0) style = STYLE_SH;
+
+ char* path = construct_path("PATH", "/etc/paths", "/etc/paths.d");
+ char* manpath = NULL;
+
+ // only adjust manpath if already set
+ int do_manpath = (getenv("MANPATH") != NULL);
+ if (do_manpath) {
+ manpath = construct_path("MANPATH", "/etc/manpaths", "/etc/manpaths.d");
+ }
+
+ if (style == STYLE_CSH) {
+ printf("setenv PATH \"%s\";\n", path);
+ if (do_manpath) printf("setenv MANPATH \"%s\";\n", manpath);
+ } else {
+ printf("PATH=\"%s\"; export PATH;\n", path);
+ if (do_manpath) printf("MANPATH=\"%s\"; export MANPATH;\n", manpath);
+ }
+
+ return 0;
+}
diff --git a/shell_cmds/printenv/printenv.1 b/shell_cmds/printenv/printenv.1
new file mode 100644
index 0000000..4444375
--- /dev/null
+++ b/shell_cmds/printenv/printenv.1
@@ -0,0 +1,84 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)printenv.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd May 12, 2003
+.Dt PRINTENV 1
+.Os
+.Sh NAME
+.Nm printenv
+.Nd print out the environment
+.Sh SYNOPSIS
+.Nm
+.Op Ar name
+.Sh DESCRIPTION
+The
+.Nm
+utility prints out the names and values of the variables in the environment,
+with one name/value pair per line.
+If
+.Ar name
+is specified, only
+its value is printed.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr env 1 ,
+.Xr sh 1 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Nm
+utility is provided for compatibility with earlier
+.Bx
+and
+.Fx
+releases and is not specified by any standards.
+The functionality of
+.Nm
+can be duplicated with the
+.Xr echo 1
+and
+.Xr env 1
+utilities.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/printenv/printenv.c b/shell_cmds/printenv/printenv.c
new file mode 100644
index 0000000..315833e
--- /dev/null
+++ b/shell_cmds/printenv/printenv.c
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)printenv.c 8.2 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage(void);
+extern char **environ;
+
+/*
+ * printenv
+ *
+ * Bill Joy, UCB
+ * February, 1979
+ */
+int
+main(int argc, char *argv[])
+{
+ char *cp, **ep;
+ size_t len;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ for (ep = environ; *ep; ep++)
+ (void)printf("%s\n", *ep);
+ exit(0);
+ }
+ len = strlen(*argv);
+ for (ep = environ; *ep; ep++)
+ if (!memcmp(*ep, *argv, len)) {
+ cp = *ep + len;
+ if (!*cp || *cp == '=') {
+ (void)printf("%s\n", *cp ? cp + 1 : cp);
+ exit(0);
+ }
+ }
+ exit(1);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: printenv [name]\n");
+ exit(1);
+}
diff --git a/shell_cmds/printf/printf.1 b/shell_cmds/printf/printf.1
new file mode 100644
index 0000000..226b87b
--- /dev/null
+++ b/shell_cmds/printf/printf.1
@@ -0,0 +1,418 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)printf.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd July 1, 2020
+.Dt PRINTF 1
+.Os
+.Sh NAME
+.Nm printf
+.Nd formatted output
+.Sh SYNOPSIS
+.Nm
+.Ar format Op Ar arguments ...
+.Sh DESCRIPTION
+The
+.Nm
+utility formats and prints its arguments, after the first, under control
+of the
+.Ar format .
+The
+.Ar format
+is a character string which contains three types of objects: plain characters,
+which are simply copied to standard output, character escape sequences which
+are converted and copied to the standard output, and format specifications,
+each of which causes printing of the next successive
+.Ar argument .
+.Pp
+The
+.Ar arguments
+after the first are treated as strings if the corresponding format is
+either
+.Cm c , b
+or
+.Cm s ;
+otherwise it is evaluated as a C constant, with the following extensions:
+.Pp
+.Bl -bullet -offset indent -compact
+.It
+A leading plus or minus sign is allowed.
+.It
+If the leading character is a single or double quote, the value is the
+character code of the next character.
+.El
+.Pp
+The format string is reused as often as necessary to satisfy the
+.Ar arguments .
+Any extra format specifications are evaluated with zero or the null
+string.
+.Pp
+Character escape sequences are in backslash notation as defined in the
+.St -ansiC ,
+with extensions.
+The characters and their meanings
+are as follows:
+.Pp
+.Bl -tag -width Ds -offset indent -compact
+.It Cm \ea
+Write a <bell> character.
+.It Cm \eb
+Write a <backspace> character.
+.It Cm \ef
+Write a <form-feed> character.
+.It Cm \en
+Write a <new-line> character.
+.It Cm \er
+Write a <carriage return> character.
+.It Cm \et
+Write a <tab> character.
+.It Cm \ev
+Write a <vertical tab> character.
+.It Cm \e\'
+Write a <single quote> character.
+.It Cm \e\e
+Write a backslash character.
+.It Cm \e Ns Ar num
+Write a byte whose
+value is the 1-, 2-, or 3-digit
+octal number
+.Ar num .
+Multibyte characters can be constructed using multiple
+.Cm \e Ns Ar num
+sequences.
+.El
+.Pp
+Each format specification is introduced by the percent character
+(``%'').
+The remainder of the format specification includes,
+in the following order:
+.Bl -tag -width Ds
+.It "Zero or more of the following flags:"
+.Bl -tag -width Ds
+.It Cm #
+A `#' character
+specifying that the value should be printed in an ``alternate form''.
+For
+.Cm b , c , d , s
+and
+.Cm u
+formats, this option has no effect.
+For the
+.Cm o
+formats the precision of the number is increased to force the first
+character of the output string to a zero.
+For the
+.Cm x
+.Pq Cm X
+format, a non-zero result has the string
+.Li 0x
+.Pq Li 0X
+prepended to it.
+For
+.Cm a , A , e , E , f , F , g
+and
+.Cm G
+formats, the result will always contain a decimal point, even if no
+digits follow the point (normally, a decimal point only appears in the
+results of those formats if a digit follows the decimal point).
+For
+.Cm g
+and
+.Cm G
+formats, trailing zeros are not removed from the result as they
+would otherwise be;
+.It Cm \&\-
+A minus sign `\-' which specifies
+.Em left adjustment
+of the output in the indicated field;
+.It Cm \&+
+A `+' character specifying that there should always be
+a sign placed before the number when using signed formats.
+.It Sq \&\ \&
+A space specifying that a blank should be left before a positive number
+for a signed format.
+A `+' overrides a space if both are used;
+.It Cm \&0
+A zero `0' character indicating that zero-padding should be used
+rather than blank-padding.
+A `\-' overrides a `0' if both are used;
+.El
+.It "Field Width:"
+An optional digit string specifying a
+.Em field width ;
+if the output string has fewer bytes than the field width it will
+be blank-padded on the left (or right, if the left-adjustment indicator
+has been given) to make up the field width (note that a leading zero
+is a flag, but an embedded zero is part of a field width);
+.It Precision:
+An optional period,
+.Sq Cm \&.\& ,
+followed by an optional digit string giving a
+.Em precision
+which specifies the number of digits to appear after the decimal point,
+for
+.Cm e
+and
+.Cm f
+formats, or the maximum number of bytes to be printed
+from a string; if the digit string is missing, the precision is treated
+as zero;
+.It Format:
+A character which indicates the type of format to use (one of
+.Cm diouxXfFeEgGaAcsb ) .
+The uppercase formats differ from their lowercase counterparts only in
+that the output of the former is entirely in uppercase.
+The floating-point format specifiers
+.Pq Cm fFeEgGaA
+may be prefixed by an
+.Cm L
+to request that additional precision be used, if available.
+.El
+.Pp
+A field width or precision may be
+.Sq Cm \&*
+instead of a digit string.
+In this case an
+.Ar argument
+supplies the field width or precision.
+.Pp
+The format characters and their meanings are:
+.Bl -tag -width Fl
+.It Cm diouXx
+The
+.Ar argument
+is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
+or unsigned hexadecimal (X or x), respectively.
+.It Cm fF
+The
+.Ar argument
+is printed in the style `[\-]ddd.ddd' where the number of d's
+after the decimal point is equal to the precision specification for
+the argument.
+If the precision is missing, 6 digits are given; if the precision
+is explicitly 0, no digits and no decimal point are printed.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
+.It Cm eE
+The
+.Ar argument
+is printed in the style
+.Cm e
+.Sm off
+.Sq Op - Ar d.ddd No \(+- Ar dd
+.Sm on
+where there
+is one digit before the decimal point and the number after is equal to
+the precision specification for the argument; when the precision is
+missing, 6 digits are produced.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
+.It Cm gG
+The
+.Ar argument
+is printed in style
+.Cm f
+.Pq Cm F
+or in style
+.Cm e
+.Pq Cm E
+whichever gives full precision in minimum space.
+.It Cm aA
+The
+.Ar argument
+is printed in style
+.Sm off
+.Sq Op - Ar h.hhh No \(+- Li p Ar d
+.Sm on
+where there is one digit before the hexadecimal point and the number
+after is equal to the precision specification for the argument;
+when the precision is missing, enough digits are produced to convey
+the argument's exact double-precision floating-point representation.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
+.It Cm c
+The first byte of
+.Ar argument
+is printed.
+.It Cm s
+Bytes from the string
+.Ar argument
+are printed until the end is reached or until the number of bytes
+indicated by the precision specification is reached; however if the
+precision is 0 or missing, the string is printed entirely.
+.It Cm b
+As for
+.Cm s ,
+but interpret character escapes in backslash notation in the string
+.Ar argument .
+The permitted escape sequences are slightly different in that
+octal escapes are
+.Cm \e0 Ns Ar num
+instead of
+.Cm \e Ns Ar num
+and that an additional escape sequence
+.Cm \ec
+stops further output from this
+.Nm
+invocation.
+.It Cm n$
+Allows reordering of the output according to
+.Ar argument .
+.It Cm \&%
+Print a `%'; no argument is used.
+.El
+.Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Pp
+In no case does a non-existent or small field width cause truncation of
+a field; padding takes place only if the specified field width exceeds
+the actual width.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Print the string
+.Qq hello :
+.Bd -literal -offset indent
+$ printf "%s\en" hello
+hello
+.Ed
+.Pp
+Same as above, but notice that the format string is not quoted and hence we
+do not get the expected behavior:
+.Bd -literal -offset indent
+$ printf %s\en hello
+hellon$
+.Ed
+.Pp
+Print arguments forcing sign only for the first argument:
+.Bd -literal -offset indent
+$ printf "%+d\en%d\en%d\en" 1 -2 13
++1
+-2
+13
+.Ed
+.Pp
+Same as above, but the single format string will be applied to the three
+arguments:
+.Bd -literal -offset indent
+$ printf "%+d\en" 1 -2 13
++1
+-2
++13
+.Ed
+.Pp
+Print number using only two digits after the decimal point:
+.Bd -literal -offset indent
+$ printf "%.2f\en" 31.7456
+31.75
+.Ed
+.Sh COMPATIBILITY
+The traditional
+.Bx
+behavior of converting arguments of numeric formats not beginning
+with a digit to the ASCII
+code of the first character is not supported.
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr echo 1 ,
+.Xr sh 1 ,
+.Xr printf 3
+.Sh STANDARDS
+The
+.Nm
+command is expected to be compatible with the
+.St -p1003.2
+specification.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 Reno .
+It is modeled
+after the standard library function,
+.Xr printf 3 .
+.Sh CAVEATS
+ANSI hexadecimal character constants were deliberately not provided.
+.Pp
+Trying to print a dash ("-") as the first character causes
+.Nm
+to interpret the dash as a program argument.
+.Nm --
+must be used before
+.Ar format .
+.Pp
+If the locale contains multibyte characters
+(such as UTF-8),
+the
+.Cm c
+format and
+.Cm b
+and
+.Cm s
+formats with a precision
+may not operate as expected.
+.Sh BUGS
+Since the floating point numbers are translated from ASCII
+to floating-point and then back again, floating-point precision may be lost.
+(By default, the number is translated to an IEEE-754 double-precision
+value before being printed.
+The
+.Cm L
+modifier may produce additional precision, depending on the hardware platform.)
+.Pp
+The escape sequence \e000 is the string terminator.
+When present in the argument for the
+.Cm b
+format, the argument will be truncated at the \e000 character.
+.Pp
+Multibyte characters are not recognized in format strings (this is only
+a problem if
+.Ql %
+can appear inside a multibyte character).
diff --git a/shell_cmds/printf/printf.c b/shell_cmds/printf/printf.c
new file mode 100644
index 0000000..6cc09ae
--- /dev/null
+++ b/shell_cmds/printf/printf.c
@@ -0,0 +1,697 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright 2018 Staysail Systems, Inc. <info@staysail.tech>
+ * Copyright 2014 Garrett D'Amore <garrett@damore.org>
+ * Copyright 2010 Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ */
+/*
+ * Important: This file is used both as a standalone program /usr/bin/printf
+ * and as a builtin for /bin/sh (#define SHELL).
+ */
+
+#ifndef SHELL
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+#endif
+
+#ifndef lint
+#if 0
+static char const sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#ifdef SHELL
+#define main printfcmd
+#include "bltin/bltin.h"
+#include "options.h"
+#endif
+
+#define PF(f, func) do { \
+ if (havewidth) \
+ if (haveprec) \
+ (void)printf(f, fieldwidth, precision, func); \
+ else \
+ (void)printf(f, fieldwidth, func); \
+ else if (haveprec) \
+ (void)printf(f, precision, func); \
+ else \
+ (void)printf(f, func); \
+} while (0)
+
+static int asciicode(void);
+static char *printf_doformat(char *, int *);
+static int escape(char *, int, size_t *);
+static int getchr(void);
+static int getfloating(long double *, int);
+static int getint(int *);
+static int getnum(intmax_t *, uintmax_t *, int);
+static const char
+ *getstr(void);
+static char *mknum(char *, char);
+static void usage(void);
+
+static const char digits[] = "0123456789";
+
+static char end_fmt[1];
+
+static int myargc;
+static char **myargv;
+static char **gargv;
+static char **maxargv;
+
+int
+main(int argc, char *argv[])
+{
+ size_t len;
+ int end, rval;
+ char *format, *fmt, *start;
+#ifndef SHELL
+ int ch;
+
+ (void) setlocale(LC_ALL, "");
+#endif
+
+#ifdef SHELL
+ nextopt("");
+ argc -= argptr - argv;
+ argv = argptr;
+#else
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ return (1);
+ }
+ argc -= optind;
+ argv += optind;
+#endif
+
+ if (argc < 1) {
+ usage();
+ return (1);
+ }
+
+#ifdef SHELL
+ INTOFF;
+#endif
+ /*
+ * Basic algorithm is to scan the format string for conversion
+ * specifications -- once one is found, find out if the field
+ * width or precision is a '*'; if it is, gather up value. Note,
+ * format strings are reused as necessary to use up the provided
+ * arguments, arguments of zero/null string are provided to use
+ * up the format string.
+ */
+ fmt = format = *argv;
+ escape(fmt, 1, &len); /* backslash interpretation */
+ rval = end = 0;
+ gargv = ++argv;
+
+ for (;;) {
+ maxargv = gargv;
+
+ myargv = gargv;
+ for (myargc = 0; gargv[myargc]; myargc++)
+ /* nop */;
+ start = fmt;
+ while (fmt < format + len) {
+ if (fmt[0] == '%') {
+ fwrite(start, 1, fmt - start, stdout);
+ if (fmt[1] == '%') {
+ /* %% prints a % */
+ putchar('%');
+ fmt += 2;
+ } else {
+ fmt = printf_doformat(fmt, &rval);
+ if (fmt == NULL || fmt == end_fmt) {
+#ifdef SHELL
+ INTON;
+#endif
+ return (fmt == NULL ? 1 : rval);
+ }
+ end = 0;
+ }
+ start = fmt;
+ } else
+ fmt++;
+ if (gargv > maxargv)
+ maxargv = gargv;
+ }
+ gargv = maxargv;
+
+ if (end == 1) {
+ warnx("missing format character");
+#ifdef SHELL
+ INTON;
+#endif
+ return (1);
+ }
+ fwrite(start, 1, fmt - start, stdout);
+ if (!*gargv) {
+#ifdef SHELL
+ INTON;
+#endif
+ return (rval);
+ }
+ /* Restart at the beginning of the format string. */
+ fmt = format;
+ end = 1;
+ }
+ /* NOTREACHED */
+}
+
+
+static char *
+printf_doformat(char *fmt, int *rval)
+{
+ static const char skip1[] = "#'-+ 0";
+ int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
+ char convch, nextch;
+ char start[strlen(fmt) + 1];
+ char **fargv;
+ char *dptr;
+ int l;
+
+ dptr = start;
+ *dptr++ = '%';
+ *dptr = 0;
+
+ fmt++;
+
+ /* look for "n$" field index specifier */
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
+ if (idx <= myargc) {
+ gargv = &myargv[idx - 1];
+ } else {
+ gargv = &myargv[myargc];
+ }
+ if (gargv > maxargv)
+ maxargv = gargv;
+ fmt += l + 1;
+
+ /* save format argument */
+ fargv = gargv;
+ } else {
+ fargv = NULL;
+ }
+
+ /* skip to field width */
+ while (*fmt && strchr(skip1, *fmt) != NULL) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
+
+ if (*fmt == '*') {
+
+ fmt++;
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
+ if (fargv == NULL) {
+ warnx("incomplete use of n$");
+ return (NULL);
+ }
+ if (idx <= myargc) {
+ gargv = &myargv[idx - 1];
+ } else {
+ gargv = &myargv[myargc];
+ }
+ fmt += l + 1;
+ } else if (fargv != NULL) {
+ warnx("incomplete use of n$");
+ return (NULL);
+ }
+
+ if (getint(&fieldwidth))
+ return (NULL);
+ if (gargv > maxargv)
+ maxargv = gargv;
+ havewidth = 1;
+
+ *dptr++ = '*';
+ *dptr = 0;
+ } else {
+ havewidth = 0;
+
+ /* skip to possible '.', get following precision */
+ while (isdigit(*fmt)) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
+ }
+
+ if (*fmt == '.') {
+ /* precision present? */
+ fmt++;
+ *dptr++ = '.';
+
+ if (*fmt == '*') {
+
+ fmt++;
+ l = strspn(fmt, digits);
+ if ((l > 0) && (fmt[l] == '$')) {
+ int idx = atoi(fmt);
+ if (fargv == NULL) {
+ warnx("incomplete use of n$");
+ return (NULL);
+ }
+ if (idx <= myargc) {
+ gargv = &myargv[idx - 1];
+ } else {
+ gargv = &myargv[myargc];
+ }
+ fmt += l + 1;
+ } else if (fargv != NULL) {
+ warnx("incomplete use of n$");
+ return (NULL);
+ }
+
+ if (getint(&precision))
+ return (NULL);
+ if (gargv > maxargv)
+ maxargv = gargv;
+ haveprec = 1;
+ *dptr++ = '*';
+ *dptr = 0;
+ } else {
+ haveprec = 0;
+
+ /* skip to conversion char */
+ while (isdigit(*fmt)) {
+ *dptr++ = *fmt++;
+ *dptr = 0;
+ }
+ }
+ } else
+ haveprec = 0;
+ if (!*fmt) {
+ warnx("missing format character");
+ return (NULL);
+ }
+ *dptr++ = *fmt;
+ *dptr = 0;
+
+ /*
+ * Look for a length modifier. POSIX doesn't have these, so
+ * we only support them for floating-point conversions, which
+ * are extensions. This is useful because the L modifier can
+ * be used to gain extra range and precision, while omitting
+ * it is more likely to produce consistent results on different
+ * architectures. This is not so important for integers
+ * because overflow is the only bad thing that can happen to
+ * them, but consider the command printf %a 1.1
+ */
+ if (*fmt == 'L') {
+ mod_ldbl = 1;
+ fmt++;
+ if (!strchr("aAeEfFgG", *fmt)) {
+ warnx("bad modifier L for %%%c", *fmt);
+ return (NULL);
+ }
+ } else {
+ mod_ldbl = 0;
+ }
+
+ /* save the current arg offset, and set to the format arg */
+ if (fargv != NULL) {
+ gargv = fargv;
+ }
+
+ convch = *fmt;
+ nextch = *++fmt;
+
+ *fmt = '\0';
+ switch (convch) {
+ case 'b': {
+ size_t len;
+ char *p;
+ int getout;
+
+ /* Convert "b" to "s" for output. */
+ start[strlen(start) - 1] = 's';
+ if ((p = strdup(getstr())) == NULL) {
+ warnx("%s", strerror(ENOMEM));
+ return (NULL);
+ }
+ getout = escape(p, 0, &len);
+ /*
+ * Special-case conversion of zero; print it instead of
+ * feeding an empty string to printf("%s") which would not
+ * print anything.
+ */
+ if (len == 1 && p[0] == '\0') {
+ putchar(p[0]);
+ } else {
+ PF(start, p);
+ }
+ /* Restore format for next loop. */
+
+ free(p);
+ if (getout)
+ return (end_fmt);
+ break;
+ }
+ case 'c': {
+ char p;
+
+ p = getchr();
+ if (p != '\0')
+ PF(start, p);
+ break;
+ }
+ case 's': {
+ const char *p;
+
+ p = getstr();
+ PF(start, p);
+ break;
+ }
+ case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
+ char *f;
+ intmax_t val;
+ uintmax_t uval;
+ int signedconv;
+
+ signedconv = (convch == 'd' || convch == 'i');
+ if ((f = mknum(start, convch)) == NULL)
+ return (NULL);
+ if (getnum(&val, &uval, signedconv))
+ *rval = 1;
+ if (signedconv)
+ PF(f, val);
+ else
+ PF(f, uval);
+ break;
+ }
+ case 'e': case 'E':
+ case 'f': case 'F':
+ case 'g': case 'G':
+ case 'a': case 'A': {
+ long double p;
+
+ if (getfloating(&p, mod_ldbl))
+ *rval = 1;
+ if (mod_ldbl)
+ PF(start, p);
+ else
+ PF(start, (double)p);
+ break;
+ }
+ default:
+ warnx("illegal format character %c", convch);
+ return (NULL);
+ }
+ *fmt = nextch;
+ /* return the gargv to the next element */
+ return (fmt);
+}
+
+static char *
+mknum(char *str, char ch)
+{
+ static char *copy;
+ static size_t copy_size;
+ char *newcopy;
+ size_t len, newlen;
+
+ len = strlen(str) + 2;
+ if (len > copy_size) {
+ newlen = ((len + 1023) >> 10) << 10;
+ if ((newcopy = realloc(copy, newlen)) == NULL) {
+ warnx("%s", strerror(ENOMEM));
+ return (NULL);
+ }
+ copy = newcopy;
+ copy_size = newlen;
+ }
+
+ memmove(copy, str, len - 3);
+ copy[len - 3] = 'j';
+ copy[len - 2] = ch;
+ copy[len - 1] = '\0';
+ return (copy);
+}
+
+static int
+escape(char *fmt, int percent, size_t *len)
+{
+ char *save, *store, c;
+ int value;
+
+ for (save = store = fmt; ((c = *fmt) != 0); ++fmt, ++store) {
+ if (c != '\\') {
+ *store = c;
+ continue;
+ }
+ switch (*++fmt) {
+ case '\0': /* EOS, user error */
+ *store = '\\';
+ *++store = '\0';
+ *len = store - save;
+ return (0);
+ case '\\': /* backslash */
+ case '\'': /* single quote */
+ *store = *fmt;
+ break;
+ case 'a': /* bell/alert */
+ *store = '\a';
+ break;
+ case 'b': /* backspace */
+ *store = '\b';
+ break;
+ case 'c':
+ if (!percent) {
+ *store = '\0';
+ *len = store - save;
+ return (1);
+ }
+ *store = 'c';
+ break;
+ case 'f': /* form-feed */
+ *store = '\f';
+ break;
+ case 'n': /* newline */
+ *store = '\n';
+ break;
+ case 'r': /* carriage-return */
+ *store = '\r';
+ break;
+ case 't': /* horizontal tab */
+ *store = '\t';
+ break;
+ case 'v': /* vertical tab */
+ *store = '\v';
+ break;
+ /* octal constant */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c = (!percent && *fmt == '0') ? 4 : 3;
+ for (value = 0;
+ c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
+ value <<= 3;
+ value += *fmt - '0';
+ }
+ --fmt;
+ if (percent && value == '%') {
+ *store++ = '%';
+ *store = '%';
+ } else
+ *store = (char)value;
+ break;
+ default:
+ *store = *fmt;
+ break;
+ }
+ }
+ *store = '\0';
+ *len = store - save;
+ return (0);
+}
+
+static int
+getchr(void)
+{
+ if (!*gargv)
+ return ('\0');
+ return ((int)**gargv++);
+}
+
+static const char *
+getstr(void)
+{
+ if (!*gargv)
+ return ("");
+ return (*gargv++);
+}
+
+static int
+getint(int *ip)
+{
+ intmax_t val;
+ uintmax_t uval;
+ int rval;
+
+ if (getnum(&val, &uval, 1))
+ return (1);
+ rval = 0;
+ if (val < INT_MIN || val > INT_MAX) {
+ warnx("%s: %s", *gargv, strerror(ERANGE));
+ rval = 1;
+ }
+ *ip = (int)val;
+ return (rval);
+}
+
+static int
+getnum(intmax_t *ip, uintmax_t *uip, int signedconv)
+{
+ char *ep;
+ int rval;
+
+ if (!*gargv) {
+ *ip = *uip = 0;
+ return (0);
+ }
+ if (**gargv == '"' || **gargv == '\'') {
+ if (signedconv)
+ *ip = asciicode();
+ else
+ *uip = asciicode();
+ return (0);
+ }
+ rval = 0;
+ errno = 0;
+ if (signedconv)
+ *ip = strtoimax(*gargv, &ep, 0);
+ else
+ *uip = strtoumax(*gargv, &ep, 0);
+ if (ep == *gargv) {
+ warnx("%s: expected numeric value", *gargv);
+ rval = 1;
+ }
+ else if (*ep != '\0') {
+ warnx("%s: not completely converted", *gargv);
+ rval = 1;
+ }
+ if (errno == ERANGE) {
+ warnx("%s: %s", *gargv, strerror(ERANGE));
+ rval = 1;
+ }
+ ++gargv;
+ return (rval);
+}
+
+static int
+getfloating(long double *dp, int mod_ldbl)
+{
+ char *ep;
+ int rval;
+
+ if (!*gargv) {
+ *dp = 0.0;
+ return (0);
+ }
+ if (**gargv == '"' || **gargv == '\'') {
+ *dp = asciicode();
+ return (0);
+ }
+ rval = 0;
+ errno = 0;
+ if (mod_ldbl)
+ *dp = strtold(*gargv, &ep);
+ else
+ *dp = strtod(*gargv, &ep);
+ if (ep == *gargv) {
+ warnx("%s: expected numeric value", *gargv);
+ rval = 1;
+ } else if (*ep != '\0') {
+ warnx("%s: not completely converted", *gargv);
+ rval = 1;
+ }
+ if (errno == ERANGE) {
+ warnx("%s: %s", *gargv, strerror(ERANGE));
+ rval = 1;
+ }
+ ++gargv;
+ return (rval);
+}
+
+static int
+asciicode(void)
+{
+ int ch;
+ wchar_t wch;
+ mbstate_t mbs;
+
+ ch = (unsigned char)**gargv;
+ if (ch == '\'' || ch == '"') {
+ memset(&mbs, 0, sizeof(mbs));
+ switch (mbrtowc(&wch, *gargv + 1, MB_LEN_MAX, &mbs)) {
+ case (size_t)-2:
+ case (size_t)-1:
+ wch = (unsigned char)gargv[0][1];
+ break;
+ case 0:
+ wch = 0;
+ break;
+ }
+ ch = wch;
+ }
+ ++gargv;
+ return (ch);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: printf format [arguments ...]\n");
+}
diff --git a/shell_cmds/printf/printf.plist.part b/shell_cmds/printf/printf.plist.part
new file mode 100644
index 0000000..a040cf7
--- /dev/null
+++ b/shell_cmds/printf/printf.plist.part
@@ -0,0 +1,18 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>printf</string>
+ <key>OpenSourceVersion</key>
+ <string>2020-07-01</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>https://github.com/freebsd/freebsd/tree/master/usr.bin/printf</string>
+ <key>OpenSourceSCM</key>
+ <string>https://github.com/freebsd/freebsd/tree/master/usr.bin/printf</string>
+ <key>OpenSourceImportDate</key>
+ <string>2020-07-23</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>65959587: UNIX Conformance | /usr/bin/printf, multiple format assertion failures in VSC</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/printf/tests/Makefile b/shell_cmds/printf/tests/Makefile
new file mode 100644
index 0000000..b4ea79b
--- /dev/null
+++ b/shell_cmds/printf/tests/Makefile
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+PACKAGE= tests
+
+TAP_TESTS_SH= legacy_test
+
+${PACKAGE}FILES+= regress.b.out
+${PACKAGE}FILES+= regress.bwidth.out
+${PACKAGE}FILES+= regress.d.out
+${PACKAGE}FILES+= regress.f.out
+${PACKAGE}FILES+= regress.l1.out
+${PACKAGE}FILES+= regress.l2.out
+${PACKAGE}FILES+= regress.m1.out
+${PACKAGE}FILES+= regress.m2.out
+${PACKAGE}FILES+= regress.m3.out
+${PACKAGE}FILES+= regress.m4.out
+${PACKAGE}FILES+= regress.m5.out
+${PACKAGE}FILES+= regress.missingpos1.out
+${PACKAGE}FILES+= regress.s.out
+${PACKAGE}FILES+= regress.sh
+${PACKAGE}FILES+= regress.zero.out
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/printf/tests/Makefile.depend b/shell_cmds/printf/tests/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/shell_cmds/printf/tests/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/printf/tests/legacy_test.sh b/shell_cmds/printf/tests/legacy_test.sh
new file mode 100644
index 0000000..a919deb
--- /dev/null
+++ b/shell_cmds/printf/tests/legacy_test.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+# $FreeBSD$
+
+SRCDIR="$(dirname "${0}")"; export SRCDIR
+
+m4 /AppleInternal/Tests/shell_cmds/regress.m4 "${SRCDIR}/regress.sh" | sh
diff --git a/shell_cmds/printf/tests/regress.b.out b/shell_cmds/printf/tests/regress.b.out
new file mode 100644
index 0000000..0373d93
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.b.out
@@ -0,0 +1 @@
+abcdef
diff --git a/shell_cmds/printf/tests/regress.bwidth.out b/shell_cmds/printf/tests/regress.bwidth.out
new file mode 100644
index 0000000..9e2ff61
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.bwidth.out
@@ -0,0 +1 @@
+ a
diff --git a/shell_cmds/printf/tests/regress.d.out b/shell_cmds/printf/tests/regress.d.out
new file mode 100644
index 0000000..da83c08
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.d.out
@@ -0,0 +1 @@
+123, 123,00123,00123,00123
diff --git a/shell_cmds/printf/tests/regress.f.out b/shell_cmds/printf/tests/regress.f.out
new file mode 100644
index 0000000..127cb8a
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.f.out
@@ -0,0 +1 @@
+42.250000,-42.250 ,inf,nan
diff --git a/shell_cmds/printf/tests/regress.l1.out b/shell_cmds/printf/tests/regress.l1.out
new file mode 100644
index 0000000..9be0dc9
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.l1.out
@@ -0,0 +1 @@
+228
diff --git a/shell_cmds/printf/tests/regress.l2.out b/shell_cmds/printf/tests/regress.l2.out
new file mode 100644
index 0000000..9be0dc9
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.l2.out
@@ -0,0 +1 @@
+228
diff --git a/shell_cmds/printf/tests/regress.m1.out b/shell_cmds/printf/tests/regress.m1.out
new file mode 100644
index 0000000..a9e063e
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m1.out
Binary files differ
diff --git a/shell_cmds/printf/tests/regress.m2.out b/shell_cmds/printf/tests/regress.m2.out
new file mode 100644
index 0000000..cf14915
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m2.out
@@ -0,0 +1,2 @@
+abc
+cdef \ No newline at end of file
diff --git a/shell_cmds/printf/tests/regress.m3.out b/shell_cmds/printf/tests/regress.m3.out
new file mode 100644
index 0000000..bbe4e70
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m3.out
@@ -0,0 +1,4 @@
+%abc
+%def
+%ghi
+%jkl
diff --git a/shell_cmds/printf/tests/regress.m4.out b/shell_cmds/printf/tests/regress.m4.out
new file mode 100644
index 0000000..5e0b5d4
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m4.out
@@ -0,0 +1 @@
+0,0.000000,,
diff --git a/shell_cmds/printf/tests/regress.m5.out b/shell_cmds/printf/tests/regress.m5.out
new file mode 100644
index 0000000..2838468
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.m5.out
@@ -0,0 +1 @@
+-d
diff --git a/shell_cmds/printf/tests/regress.missingpos1.out b/shell_cmds/printf/tests/regress.missingpos1.out
new file mode 100644
index 0000000..3b04f03
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.missingpos1.out
@@ -0,0 +1 @@
+printf: incomplete use of n$
diff --git a/shell_cmds/printf/tests/regress.s.out b/shell_cmds/printf/tests/regress.s.out
new file mode 100644
index 0000000..3d572b9
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.s.out
@@ -0,0 +1 @@
+abc,abc
diff --git a/shell_cmds/printf/tests/regress.sh b/shell_cmds/printf/tests/regress.sh
new file mode 100644
index 0000000..a2cf5fb
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.sh
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+REGRESSION_START($1)
+
+echo '1..24'
+
+REGRESSION_TEST(`b', `printf "abc%b%b" "def\n" "\cghi"')
+REGRESSION_TEST(`d', `printf "%d,%5d,%.5d,%0*d,%.*d\n" 123 123 123 5 123 5 123')
+REGRESSION_TEST(`f', `printf "%f,%-8.3f,%f,%f\n" +42.25 -42.25 inf nan')
+REGRESSION_TEST(`l1', `LC_ALL=en_US.ISO8859-1 printf "%d\n" $(printf \"\\344)')
+REGRESSION_TEST(`l2', `LC_ALL=en_US.UTF-8 printf "%d\n" $(printf \"\\303\\244)')
+REGRESSION_TEST(`m1', `printf "%c%%%d\0\045\n" abc \"abc')
+REGRESSION_TEST(`m2', `printf "abc\n\cdef"')
+REGRESSION_TEST(`m3', `printf "%%%s\n" abc def ghi jkl')
+REGRESSION_TEST(`m4', `printf "%d,%f,%c,%s\n"')
+REGRESSION_TEST(`m5', `printf -- "-d\n"')
+REGRESSION_TEST(`s', `printf "%.3s,%-5s\n" abcd abc')
+REGRESSION_TEST('zero', `printf "%u%u\n" 15')
+REGRESSION_TEST('zero', `printf "%d%d\n" 15')
+REGRESSION_TEST('zero', `printf "%d%u\n" 15')
+REGRESSION_TEST('zero', `printf "%u%d\n" 15')
+REGRESSION_TEST(`missingpos1', `printf "%1\$*s" 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%*1\$s" 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%1\$*.*s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%*1\$.*s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%*.*1\$s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%1\$*2\$.*s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%*1\$.*2\$s" 1 1 1 2>&1')
+REGRESSION_TEST(`missingpos1', `printf "%1\$*.*2\$s" 1 1 1 2>&1')
+REGRESSION_TEST(`bwidth', `printf "%8.2b" "a\nb\n"')
+
+REGRESSION_END()
diff --git a/shell_cmds/printf/tests/regress.zero.out b/shell_cmds/printf/tests/regress.zero.out
new file mode 100644
index 0000000..fa8f08c
--- /dev/null
+++ b/shell_cmds/printf/tests/regress.zero.out
@@ -0,0 +1 @@
+150
diff --git a/shell_cmds/pwd/pwd.1 b/shell_cmds/pwd/pwd.1
new file mode 100644
index 0000000..929c4b3
--- /dev/null
+++ b/shell_cmds/pwd/pwd.1
@@ -0,0 +1,103 @@
+.\"-
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pwd.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/bin/pwd/pwd.1,v 1.26 2005/01/16 16:41:58 ru Exp $
+.\"
+.Dd April 12, 2003
+.Dt PWD 1
+.Os
+.Sh NAME
+.Nm pwd
+.Nd return working directory name
+.Sh SYNOPSIS
+.Nm
+.Op Fl L | P
+.Sh DESCRIPTION
+The
+.Nm
+utility writes the absolute pathname of the current working directory to
+the standard output.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl L
+Display the logical current working directory.
+.It Fl P
+Display the physical current working directory (all symbolic links resolved).
+.El
+.Pp
+If no options are specified, the
+.\" 4207130
+.Fl L
+option is assumed.
+.Sh ENVIRONMENT
+Environment variables used by
+.Nm :
+.Bl -tag -width ".Ev PWD"
+.It Ev PWD
+Logical current working directory.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr cd 1 ,
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr getcwd 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh BUGS
+In
+.Xr csh 1
+the command
+.Ic dirs
+is always faster because it is built into that shell.
+However, it can give a different answer in the rare case
+that the current directory or a containing directory was moved after
+the shell descended into it.
+.Pp
+The
+.Fl L
+option does not work unless the
+.Ev PWD
+environment variable is exported by the shell.
diff --git a/shell_cmds/pwd/pwd.c b/shell_cmds/pwd/pwd.c
new file mode 100644
index 0000000..c5788b1
--- /dev/null
+++ b/shell_cmds/pwd/pwd.c
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)pwd.c 8.3 (Berkeley) 4/1/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/pwd/pwd.c,v 1.25 2005/02/09 17:37:38 ru Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static char *getcwd_logical(void);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int physical;
+ int ch;
+ char *p;
+
+ // 4207130
+ physical = 0;
+ while ((ch = getopt(argc, argv, "LP")) != -1)
+ switch (ch) {
+ case 'L':
+ physical = 0;
+ break;
+ case 'P':
+ physical = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ /*
+ * If we're trying to find the logical current directory and that
+ * fails, behave as if -P was specified.
+ *
+ * 4701537: Only fall back if $PWD was actually wrong. We want to
+ * fail if the path is too long (errno == ENAMETOOLONG).
+ */
+ if ((!physical && (p = getcwd_logical()) != NULL) ||
+ ((physical || errno == ENOENT) && (p = getcwd(NULL, 0)) != NULL))
+ printf("%s\n", p);
+ else
+ err(1, ".");
+
+ exit(0);
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: pwd [-L | -P]\n");
+ exit(1);
+}
+
+static char *
+getcwd_logical(void)
+{
+ struct stat lg, phy;
+ char *pwd;
+
+ /*
+ * Check that $PWD is an absolute logical pathname referring to
+ * the current working directory.
+ */
+ if ((pwd = getenv("PWD")) != NULL && *pwd == '/') {
+ if (stat(pwd, &lg) == -1 || stat(".", &phy) == -1)
+ return (NULL);
+ if (lg.st_dev == phy.st_dev && lg.st_ino == phy.st_ino)
+ return (pwd);
+ }
+
+ errno = ENOENT;
+ return (NULL);
+}
diff --git a/shell_cmds/renice/renice.8 b/shell_cmds/renice/renice.8
new file mode 100644
index 0000000..5a03755
--- /dev/null
+++ b/shell_cmds/renice/renice.8
@@ -0,0 +1,138 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)renice.8 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD: src/usr.bin/renice/renice.8,v 1.16 2003/02/26 20:27:24 charnier Exp $
+.\"
+.Dd June 9, 1993
+.Dt RENICE 8
+.Os
+.Sh NAME
+.Nm renice
+.Nd alter priority of running processes
+.Sh SYNOPSIS
+.Nm
+.Ar priority
+.Op Oo Fl p Oc Ar pid ...
+.Op Oo Fl g Oc Ar pgrp ...
+.Op Oo Fl u Oc Ar user ...
+.Nm
+.Fl n Ar increment
+.Op Oo Fl p Oc Ar pid ...
+.Op Oo Fl g Oc Ar pgrp ...
+.Op Oo Fl u Oc Ar user ...
+.Sh DESCRIPTION
+The
+.Nm
+utility alters the
+scheduling priority of one or more running processes.
+The following
+.Ar who
+parameters are interpreted as process ID's, process group
+ID's, user ID's or user names.
+The
+.Nm Ns 'ing
+of a process group causes all processes in the process group
+to have their scheduling priority altered.
+The
+.Nm Ns 'ing
+of a user causes all processes owned by the user to have
+their scheduling priority altered.
+By default, the processes to be affected are specified by
+their process ID's.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl g
+Force
+.Ar who
+parameters to be interpreted as process group ID's.
+.It Fl n
+Instead of changing the specified processes to the given priority,
+interpret the following argument as an increment to be applied to
+the current priority of each process.
+.It Fl u
+Force the
+.Ar who
+parameters to be interpreted as user names or user ID's.
+.It Fl p
+Reset the
+.Ar who
+interpretation to be (the default) process ID's.
+.El
+.Pp
+For example,
+.Pp
+.Dl "renice +1 987 -u daemon root -p 32"
+.Pp
+would change the priority of process ID's 987 and 32, and
+all processes owned by users daemon and root.
+.Pp
+Users other than the super-user may only alter the priority of
+processes they own,
+and can only monotonically increase their ``nice value''
+within the range 0 to
+.Dv PRIO_MAX
+(20).
+(This prevents overriding administrative fiats.)
+The super-user
+may alter the priority of any process
+and set the priority to any value in the range
+.Dv PRIO_MIN
+(\-20)
+to
+.Dv PRIO_MAX .
+Useful priorities are:
+20 (the affected processes will run at the lowest priority),
+0 (the ``base'' scheduling priority),
+anything negative (lower values cause more favorable scheduling).
+.Sh FILES
+.Bl -tag -width /etc/passwd -compact
+.It Pa /etc/passwd
+to map user names to user ID's
+.El
+.Sh SEE ALSO
+.Xr nice 1 ,
+.Xr getpriority 2 ,
+.Xr setpriority 2
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.0 .
+.Sh BUGS
+Non super-users cannot increase scheduling priorities of their own processes,
+even if they were the ones that decreased the priorities in the first place.
diff --git a/shell_cmds/renice/renice.c b/shell_cmds/renice/renice.c
new file mode 100644
index 0000000..d7253e0
--- /dev/null
+++ b/shell_cmds/renice/renice.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 1983, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1983, 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)renice.c 8.1 (Berkeley) 6/9/93";
+#endif /* not lint */
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int donice(int, int, int, int);
+static int getnum(const char *, const char *, int *);
+static void usage(void);
+
+/*
+ * Change the priority (nice) of processes
+ * or groups of processes which are already
+ * running.
+ */
+int
+main(int argc, char *argv[])
+{
+ struct passwd *pwd;
+ int errs, incr, prio, which, who;
+ int delim;
+ int priflag;
+
+ errs = 0;
+ incr = 0;
+ which = PRIO_PROCESS;
+ who = 0;
+ argc--, argv++;
+ if (argc < 2)
+ usage();
+ delim = 0;
+ priflag = 0;
+
+ /* incrementing priflag here ensures we only process
+ the single priority arg if it is the very first arg */
+ for (; argc > 0; argc--, argv++, priflag++) {
+ /* once we've seen -- , don't process anymore switches */
+ if (0 == delim) {
+ /* -n must immediately be followed by the incremental
+ priority */
+ if (strcmp(*argv, "-n") == 0) {
+ incr = 1;
+ argc--, argv++;
+ if (getnum("priority", *argv, &prio))
+ return (1);
+ continue;
+ }
+ if (strcmp(*argv, "-g") == 0) {
+ which = PRIO_PGRP;
+ continue;
+ }
+ if (strcmp(*argv, "-u") == 0) {
+ which = PRIO_USER;
+ continue;
+ }
+ if (strcmp(*argv, "-p") == 0) {
+ which = PRIO_PROCESS;
+ continue;
+ }
+ if (strcmp(*argv, "--") == 0) {
+ delim = 1;
+ continue;
+ }
+ if (0 == priflag) {
+ /* if very first switch/arg and we've made it to
+ here, this must be the priority */
+ if (getnum("priority", *argv, &prio)) {
+ return(1);
+ }
+ continue;
+ }
+ }
+ if (which == PRIO_USER) {
+ if ((pwd = getpwnam(*argv)) != NULL)
+ who = pwd->pw_uid;
+ else if (getnum("uid", *argv, &who)) {
+ errs++;
+ continue;
+ } else if (who < 0) {
+ warnx("%s: bad value", *argv);
+ errs++;
+ continue;
+ }
+ } else {
+ if (getnum("pid", *argv, &who)) {
+ errs++;
+ continue;
+ }
+ if (who < 0) {
+ warnx("%s: bad value", *argv);
+ errs++;
+ continue;
+ }
+ }
+ errs += donice(which, who, prio, incr);
+ }
+ exit(errs != 0);
+}
+
+static int
+donice(int which, int who, int prio, int incr)
+{
+ int oldprio;
+
+ errno = 0;
+ oldprio = getpriority(which, who);
+ if (oldprio == -1 && errno) {
+ warn("%d: getpriority", who);
+ return (1);
+ }
+ if (incr)
+ prio = oldprio + prio;
+ if (prio > PRIO_MAX)
+ prio = PRIO_MAX;
+ if (prio < PRIO_MIN)
+ prio = PRIO_MIN;
+ if (setpriority(which, who, prio) < 0) {
+ warn("%d: setpriority", who);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+getnum(const char *com, const char *str, int *val)
+{
+ long v;
+ char *ep;
+
+ errno = 0;
+ v = strtol(str, &ep, 10);
+ if (v < INT_MIN || v > INT_MAX || errno == ERANGE) {
+ warnx("%s argument %s is out of range.", com, str);
+ return (1);
+ }
+ if (ep == str || *ep != '\0' || errno != 0) {
+ warnx("Bad %s argument: %s.", com, str);
+ return (1);
+ }
+
+ *val = (int)v;
+ return (0);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "%s\n%s\n",
+"usage: renice priority [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]",
+" renice -n increment [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]");
+ exit(1);
+}
diff --git a/shell_cmds/script/script.1 b/shell_cmds/script/script.1
new file mode 100644
index 0000000..ad12c53
--- /dev/null
+++ b/shell_cmds/script/script.1
@@ -0,0 +1,217 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)script.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd December 4, 2013
+.Dt SCRIPT 1
+.Os
+.Sh NAME
+.Nm script
+.Nd make typescript of terminal session
+.Sh SYNOPSIS
+.Nm
+.Op Fl adkpqr
+.Op Fl F Ar pipe
+.Op Fl t Ar time
+.Op Ar file Op Ar command ...
+.Sh DESCRIPTION
+The
+.Nm
+utility makes a typescript of everything printed on your terminal.
+It is useful for students who need a hardcopy record of an interactive
+session as proof of an assignment, as the typescript file
+can be printed out later with
+.Xr lpr 1 .
+.Pp
+If the argument
+.Ar file
+is given,
+.Nm
+saves all dialogue in
+.Ar file .
+If no file name is given, the typescript is saved in the file
+.Pa typescript .
+.Pp
+If the argument
+.Ar command
+is given,
+.Nm
+will run the specified command with an optional argument vector
+instead of an interactive shell.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+Append the output to
+.Ar file
+or
+.Pa typescript ,
+retaining the prior contents.
+.It Fl d
+When playing back a session with the
+.Fl p
+flag, do not sleep between records when playing back a timestamped session.
+.It Fl F Ar pipe
+Immediately flush output after each write.
+This will allow a user to create a named pipe using
+.Xr mkfifo 1
+and another user may watch the live session using a utility like
+.Xr cat 1 .
+.\".It Fl f
+.\"Create
+.\".Ar file.filemon
+.\"or
+.\".Pa typescript.filemon
+.\"using
+.\".Xr filemon 4 .
+.It Fl k
+Log keys sent to the program as well as output.
+.It Fl p
+Play back a session recorded with the
+.Fl r
+flag in real time.
+.It Fl q
+Run in quiet mode, omit the start, stop and command status messages.
+.It Fl r
+Record a session with input, output, and timestamping.
+.It Fl t Ar time
+Specify the interval at which the script output file will be flushed
+to disk, in seconds.
+A value of 0
+causes
+.Nm
+to flush after every character I/O event.
+The default interval is
+30 seconds.
+.El
+.Pp
+The script ends when the forked shell (or command) exits (a
+.Em control-D
+to exit
+the Bourne shell
+.Pf ( Xr sh 1 ) ,
+and
+.Em exit ,
+.Em logout
+or
+.Em control-D
+(if
+.Em ignoreeof
+is not set) for the
+C-shell,
+.Xr csh 1 ) .
+.Pp
+Certain interactive commands, such as
+.Xr vi 1 ,
+create garbage in the typescript file.
+The
+.Nm
+utility works best with commands that do not manipulate the screen.
+The results are meant to emulate a hardcopy terminal, not an addressable one.
+.Sh ENVIRONMENT
+The following environment variables are utilized by
+.Nm :
+.Bl -tag -width SHELL
+.It Ev SCRIPT
+The
+.Ev SCRIPT
+environment variable is added to the sub-shell.
+If
+.Ev SCRIPT
+already existed in the users environment,
+its value is overwritten within the sub-shell.
+The value of
+.Ev SCRIPT
+is the name of the
+.Ar typescript
+file.
+.It Ev SHELL
+If the variable
+.Ev SHELL
+exists, the shell forked by
+.Nm
+will be that shell.
+If
+.Ev SHELL
+is not set, the Bourne shell
+is assumed.
+.Pq Most shells set this variable automatically .
+.El
+.Sh SEE ALSO
+.Xr csh 1
+.\".Xr filemon 4
+.\".Po
+.\"for the
+.\".Em history
+.\"mechanism
+.\".Pc .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
+.Pp
+The
+.Fl d ,
+.Fl p
+and
+.Fl r
+options first appeared in
+.Nx 2.0
+and were ported to
+.Fx 9.2 .
+.Sh BUGS
+The
+.Nm
+utility places
+.Sy everything
+in the log file, including linefeeds and backspaces.
+This is not what the naive user expects.
+.Pp
+It is not possible to specify a command without also naming the script file
+because of argument parsing compatibility issues.
+.Pp
+When running in
+.Fl k
+mode, echo cancelling is far from ideal.
+The slave terminal mode is checked
+for ECHO mode to check when to avoid manual echo logging.
+This does not
+work when the terminal is in a raw mode where
+the program being run is doing manual echo.
+.Pp
+If
+.Nm
+reads zero bytes from the terminal, it switches to a mode when it
+only attempts to read
+once a second until there is data to read.
+This prevents
+.Nm
+from spinning on zero-byte reads, but might cause a 1-second delay in
+processing of user input.
diff --git a/shell_cmds/script/script.c b/shell_cmds/script/script.c
new file mode 100644
index 0000000..90e895e
--- /dev/null
+++ b/shell_cmds/script/script.c
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2010, 2012 David E. O'Brien
+ * Copyright (c) 1980, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+#ifndef lint
+static const char sccsid[] = "@(#)script.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#else
+#include <sys/endian.h>
+#endif
+#ifdef ENABLE_FILEMON
+#include <dev/filemon/filemon.h>
+#endif /* ENABLE_FILEMON */
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#define DEF_BUF 65536
+
+struct stamp {
+ uint64_t scr_len; /* amount of data */
+ uint64_t scr_sec; /* time it arrived in seconds... */
+ uint32_t scr_usec; /* ...and microseconds */
+ uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
+};
+
+static FILE *fscript;
+static int master, slave;
+static int child;
+static const char *fname;
+static char *fmfname;
+#ifdef ENABLE_FILEMON
+static int fflg, qflg, ttyflg;
+#else /* !ENABLE_FILEMON */
+static int qflg, ttyflg;
+#endif /* ENABLE_FILEMON */
+static int usesleep, rawout;
+
+static struct termios tt;
+
+static void done(int) __dead2;
+static void doshell(char **);
+static void fail(void);
+static void finish(void);
+static void record(FILE *, char *, size_t, int);
+static void consume(FILE *, off_t, char *, int);
+static void playback(FILE *) __dead2;
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int cc;
+ struct termios rtt, stt;
+ struct winsize win;
+ struct timeval tv, *tvp;
+ time_t tvec, start;
+ char obuf[BUFSIZ];
+ char ibuf[BUFSIZ];
+ fd_set rfd;
+ int aflg, Fflg, kflg, pflg, ch, k, n;
+ int flushtime, readstdin;
+#ifdef ENABLE_FILEMON
+ int fm_fd, fm_log;
+#endif /* ENABLE_FILEMON */
+
+ aflg = Fflg = kflg = pflg = 0;
+ usesleep = 1;
+ rawout = 0;
+ flushtime = 30;
+#ifdef ENABLE_FILEMON
+ fm_fd = -1; /* Shut up stupid "may be used uninitialized" GCC
+ warning. (not needed w/clang) */
+#endif /* ENABLE_FILEMON */
+
+#ifdef ENABLE_FILEMON
+ while ((ch = getopt(argc, argv, "adFfkpqrt:")) != -1)
+#else /* !ENABLE_FILEMON */
+ while ((ch = getopt(argc, argv, "adFkpqrt:")) != -1)
+#endif /* ENABLE_FILEMON */
+ switch(ch) {
+ case 'a':
+ aflg = 1;
+ break;
+ case 'd':
+ usesleep = 0;
+ break;
+ case 'F':
+ Fflg = 1;
+ break;
+#ifdef ENABLE_FILEMON
+ case 'f':
+ fflg = 1;
+ break;
+#endif /* ENABLE_FILEMON */
+ case 'k':
+ kflg = 1;
+ break;
+ case 'p':
+ pflg = 1;
+ break;
+ case 'q':
+ qflg = 1;
+ break;
+ case 'r':
+ rawout = 1;
+ break;
+ case 't':
+ flushtime = atoi(optarg);
+ if (flushtime < 0)
+ err(1, "invalid flush time %d", flushtime);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ fname = argv[0];
+ argv++;
+ argc--;
+ } else
+ fname = "typescript";
+
+ if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
+ err(1, "%s", fname);
+
+#ifdef ENABLE_FILEMON
+ if (fflg) {
+ asprintf(&fmfname, "%s.filemon", fname);
+ if (!fmfname)
+ err(1, "%s.filemon", fname);
+ if ((fm_fd = open("/dev/filemon", O_RDWR)) == -1)
+ err(1, "open(\"/dev/filemon\", O_RDWR)");
+ if ((fm_log = open(fmfname, O_WRONLY | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
+ err(1, "open(%s)", fmfname);
+ if (ioctl(fm_fd, FILEMON_SET_FD, &fm_log) < 0)
+ err(1, "Cannot set filemon log file descriptor");
+
+ /* Set up these two fd's to close on exec. */
+ (void)fcntl(fm_fd, F_SETFD, FD_CLOEXEC);
+ (void)fcntl(fm_log, F_SETFD, FD_CLOEXEC);
+ }
+#endif /* ENABLE_FILEMON */
+
+ if (pflg)
+ playback(fscript);
+
+ if ((ttyflg = isatty(STDIN_FILENO)) != 0) {
+ if (tcgetattr(STDIN_FILENO, &tt) == -1)
+ err(1, "tcgetattr");
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1)
+ err(1, "ioctl");
+ if (openpty(&master, &slave, NULL, &tt, &win) == -1)
+ err(1, "openpty");
+ } else {
+ if (openpty(&master, &slave, NULL, NULL, NULL) == -1)
+ err(1, "openpty");
+ }
+
+ if (rawout)
+ record(fscript, NULL, 0, 's');
+
+ if (!qflg) {
+ tvec = time(NULL);
+ (void)printf("Script started, output file is %s\n", fname);
+ if (!rawout) {
+ (void)fprintf(fscript, "Script started on %s",
+ ctime(&tvec));
+ if (argv[0]) {
+ fprintf(fscript, "command: ");
+ for (k = 0 ; argv[k] ; ++k)
+ fprintf(fscript, "%s%s", k ? " " : "",
+ argv[k]);
+ fprintf(fscript, "\n");
+ }
+ }
+ fflush(fscript);
+#ifdef ENABLE_FILEMON
+ if (fflg) {
+ (void)printf("Filemon started, output file is %s\n",
+ fmfname);
+ }
+#endif /* ENABLE_FILEMON */
+ }
+ if (ttyflg) {
+ rtt = tt;
+ cfmakeraw(&rtt);
+ rtt.c_lflag &= ~ECHO;
+ (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
+ }
+
+ child = fork();
+ if (child < 0) {
+ warn("fork");
+ done(1);
+ }
+ if (child == 0)
+ doshell(argv);
+ close(slave);
+
+#ifdef ENABLE_FILEMON
+ if (fflg && ioctl(fm_fd, FILEMON_SET_PID, &child) < 0)
+ err(1, "Cannot set filemon PID");
+#endif /* ENABLE_FILEMON */
+
+ start = tvec = time(0);
+ readstdin = 1;
+ for (;;) {
+ FD_ZERO(&rfd);
+ FD_SET(master, &rfd);
+ if (readstdin)
+ FD_SET(STDIN_FILENO, &rfd);
+ if (!readstdin && ttyflg) {
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ readstdin = 1;
+ } else if (flushtime > 0) {
+ tv.tv_sec = flushtime - (tvec - start);
+ tv.tv_usec = 0;
+ tvp = &tv;
+ } else {
+ tvp = NULL;
+ }
+ n = select(master + 1, &rfd, 0, 0, tvp);
+ if (n < 0 && errno != EINTR)
+ break;
+ if (n > 0 && FD_ISSET(STDIN_FILENO, &rfd)) {
+ cc = read(STDIN_FILENO, ibuf, BUFSIZ);
+ if (cc < 0)
+ break;
+ if (cc == 0) {
+ if (tcgetattr(master, &stt) == 0 &&
+ (stt.c_lflag & ICANON) != 0) {
+ (void)write(master, &stt.c_cc[VEOF], 1);
+ }
+ readstdin = 0;
+ }
+ if (cc > 0) {
+ if (rawout)
+ record(fscript, ibuf, cc, 'i');
+ (void)write(master, ibuf, cc);
+ if (kflg && tcgetattr(master, &stt) >= 0 &&
+ ((stt.c_lflag & ECHO) == 0)) {
+ (void)fwrite(ibuf, 1, cc, fscript);
+ }
+ }
+ }
+ if (n > 0 && FD_ISSET(master, &rfd)) {
+ cc = read(master, obuf, sizeof (obuf));
+ if (cc <= 0)
+ break;
+ (void)write(STDOUT_FILENO, obuf, cc);
+ if (rawout)
+ record(fscript, obuf, cc, 'o');
+ else
+ (void)fwrite(obuf, 1, cc, fscript);
+ }
+ tvec = time(0);
+ if (tvec - start >= flushtime) {
+ fflush(fscript);
+ start = tvec;
+ }
+ if (Fflg)
+ fflush(fscript);
+ }
+ finish();
+ done(0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+#ifdef ENABLE_FILEMON
+ "usage: script [-adfkpqr] [-t time] [file [command ...]]\n");
+#else /* !ENABLE_FILEMON */
+ "usage: script [-adkpqr] [-t time] [file [command ...]]\n");
+#endif /* ENABLE_FILEMON */
+ exit(1);
+}
+
+static void
+finish(void)
+{
+ int e, status;
+
+ if (waitpid(child, &status, 0) == child) {
+ if (WIFEXITED(status))
+ e = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ e = WTERMSIG(status);
+ else /* can't happen */
+ e = 1;
+ done(e);
+ }
+}
+
+static void
+doshell(char **av)
+{
+ const char *shell;
+
+ shell = getenv("SHELL");
+ if (shell == NULL)
+ shell = _PATH_BSHELL;
+
+ (void)close(master);
+ (void)fclose(fscript);
+ free(fmfname);
+ login_tty(slave);
+ setenv("SCRIPT", fname, 1);
+ if (av[0]) {
+ execvp(av[0], av);
+ warn("%s", av[0]);
+ } else {
+ execl(shell, shell, "-i", (char *)NULL);
+ warn("%s", shell);
+ }
+ fail();
+}
+
+static void
+fail(void)
+{
+ (void)kill(0, SIGTERM);
+ done(1);
+}
+
+static void
+done(int eno)
+{
+ time_t tvec;
+
+ if (ttyflg)
+ (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
+ tvec = time(NULL);
+ if (rawout)
+ record(fscript, NULL, 0, 'e');
+ if (!qflg) {
+ if (!rawout)
+ (void)fprintf(fscript,"\nScript done on %s",
+ ctime(&tvec));
+ (void)printf("\nScript done, output file is %s\n", fname);
+#ifdef ENABLE_FILEMON
+ if (fflg) {
+ (void)printf("Filemon done, output file is %s\n",
+ fmfname);
+ }
+#endif /* ENABLE_FILEMON */
+ }
+ (void)fclose(fscript);
+ (void)close(master);
+ exit(eno);
+}
+
+static void
+record(FILE *fp, char *buf, size_t cc, int direction)
+{
+ struct iovec iov[2];
+ struct stamp stamp;
+ struct timeval tv;
+
+ (void)gettimeofday(&tv, NULL);
+ stamp.scr_len = cc;
+ stamp.scr_sec = tv.tv_sec;
+ stamp.scr_usec = tv.tv_usec;
+ stamp.scr_direction = direction;
+ iov[0].iov_len = sizeof(stamp);
+ iov[0].iov_base = &stamp;
+ iov[1].iov_len = cc;
+ iov[1].iov_base = buf;
+ if (writev(fileno(fp), &iov[0], 2) == -1)
+ err(1, "writev");
+}
+
+static void
+consume(FILE *fp, off_t len, char *buf, int reg)
+{
+ size_t l;
+
+ if (reg) {
+ if (fseeko(fp, len, SEEK_CUR) == -1)
+ err(1, NULL);
+ }
+ else {
+ while (len > 0) {
+ l = MIN(DEF_BUF, len);
+ if (fread(buf, sizeof(char), l, fp) != l)
+ err(1, "cannot read buffer");
+ len -= l;
+ }
+ }
+}
+
+#ifdef __APPLE__
+#define bswap32 OSSwapInt32
+#define bswap64 OSSwapInt64
+#endif /* __APPLE__ */
+#define swapstamp(stamp) do { \
+ if (stamp.scr_direction > 0xff) { \
+ stamp.scr_len = bswap64(stamp.scr_len); \
+ stamp.scr_sec = bswap64(stamp.scr_sec); \
+ stamp.scr_usec = bswap32(stamp.scr_usec); \
+ stamp.scr_direction = bswap32(stamp.scr_direction); \
+ } \
+} while (0/*CONSTCOND*/)
+
+static void
+playback(FILE *fp)
+{
+ struct timespec tsi, tso;
+ struct stamp stamp;
+ struct stat pst;
+ char buf[DEF_BUF];
+ off_t nread, save_len;
+ size_t l;
+ time_t tclock;
+ int reg;
+
+ if (fstat(fileno(fp), &pst) == -1)
+ err(1, "fstat failed");
+
+ reg = S_ISREG(pst.st_mode);
+
+ for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
+ if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
+ if (reg)
+ err(1, "reading playback header");
+ else
+ break;
+ }
+ swapstamp(stamp);
+ save_len = sizeof(stamp);
+
+ if (reg && stamp.scr_len >
+ (uint64_t)(pst.st_size - save_len) - nread)
+ errx(1, "invalid stamp");
+
+ save_len += stamp.scr_len;
+ tclock = stamp.scr_sec;
+ tso.tv_sec = stamp.scr_sec;
+ tso.tv_nsec = stamp.scr_usec * 1000;
+
+ switch (stamp.scr_direction) {
+ case 's':
+ if (!qflg)
+ (void)printf("Script started on %s",
+ ctime(&tclock));
+ tsi = tso;
+ (void)consume(fp, stamp.scr_len, buf, reg);
+ break;
+ case 'e':
+ if (!qflg)
+ (void)printf("\nScript done on %s",
+ ctime(&tclock));
+ (void)consume(fp, stamp.scr_len, buf, reg);
+ break;
+ case 'i':
+ /* throw input away */
+ (void)consume(fp, stamp.scr_len, buf, reg);
+ break;
+ case 'o':
+ tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
+ tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
+ if (tsi.tv_nsec < 0) {
+ tsi.tv_sec -= 1;
+ tsi.tv_nsec += 1000000000;
+ }
+ if (usesleep)
+ (void)nanosleep(&tsi, NULL);
+ tsi = tso;
+ while (stamp.scr_len > 0) {
+ l = MIN(DEF_BUF, stamp.scr_len);
+ if (fread(buf, sizeof(char), l, fp) != l)
+ err(1, "cannot read buffer");
+
+ (void)write(STDOUT_FILENO, buf, l);
+ stamp.scr_len -= l;
+ }
+ break;
+ default:
+ errx(1, "invalid direction");
+ }
+ }
+ (void)fclose(fp);
+ exit(0);
+}
diff --git a/shell_cmds/script/script.plist.part b/shell_cmds/script/script.plist.part
new file mode 100644
index 0000000..b112d31
--- /dev/null
+++ b/shell_cmds/script/script.plist.part
@@ -0,0 +1,20 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>script</string>
+ <key>OpenSourceVersion</key>
+ <string>2014-01-17</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/usr.bin/script/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/usr.bin/script/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2014-09-22</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Use OSByteOrder swap functions.</string>
+ <string>Include util.h instead of libutil.h.</string>
+ <string>Disable -f (filemon) feature, guarded with ENABLE_FILEMON.</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/seq/seq.1 b/shell_cmds/seq/seq.1
new file mode 100644
index 0000000..4af7b99
--- /dev/null
+++ b/shell_cmds/seq/seq.1
@@ -0,0 +1,187 @@
+.\" $NetBSD: seq.1,v 1.6 2008/11/26 15:03:47 ginsbach Exp $
+.\"
+.\" Copyright (c) 2005 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Brian Ginsbach.
+.\"
+.\" 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.
+.\"
+.\" $FreeBSD: src/usr.bin/seq/seq.1,v 1.1 2010/02/19 23:54:12 delphij Exp $
+.\"
+.Dd February 19, 2010
+.Dt SEQ 1
+.Os
+.Sh NAME
+.Nm seq
+.Nd print sequences of numbers
+.Sh SYNOPSIS
+.Nm
+.Op Fl w
+.Op Fl f Ar format
+.Op Fl s Ar string
+.Op Fl t Ar string
+.Op Ar first Op Ar incr
+.Ar last
+.Sh DESCRIPTION
+The
+.Nm
+utility prints a sequence of numbers, one per line
+.Pq default ,
+from
+.Ar first
+.Pq default 1 ,
+to near
+.Ar last
+as possible, in increments of
+.Ar incr
+.Pq default 1 .
+When
+.Ar first
+is larger than
+.Ar last
+the default
+.Ar incr
+is -1.
+.Pp
+All numbers are interpreted as floating point.
+.Pp
+Normally integer values are printed as decimal integers.
+.Pp
+The
+.Nm
+utility accepts the following options:
+.Bl -tag -width Ar
+.It Fl f Ar format
+Use a
+.Xr printf 3
+style
+.Ar format
+to print each number.
+Only the
+.Cm E ,
+.Cm e ,
+.Cm f ,
+.Cm G ,
+.Cm g ,
+and
+.Cm %
+conversion characters are valid, along with any optional
+flags and an optional numeric minimum field width or precision.
+The
+.Ar format
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+The default is
+.Cm %g .
+.It Fl s Ar string
+Use
+.Ar string
+to separate numbers.
+The
+.Ar string
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+The default is
+.Cm \en .
+.It Fl t Ar string
+Use
+.Ar string
+to terminate sequence of numbers.
+The
+.Ar string
+can contain character escape sequences in backslash notation as
+defined in
+.St -ansiC .
+This option is useful when the default separator
+does not contain a
+.Cm \en .
+.It Fl w
+Equalize the widths of all numbers by padding with zeros as necessary.
+This option has no effect with the
+.Fl f
+option.
+If any sequence numbers will be printed in exponential notation,
+the default conversion is changed to
+.Cm %e .
+.El
+.Pp
+The
+.Nm
+utility exits 0 on success and non-zero if an error occurs.
+.Sh EXAMPLES
+.Bd -literal -offset indent
+# seq 1 3
+1
+2
+3
+
+# seq 3 1
+3
+2
+1
+
+# seq -w 0 .05 .1
+0.00
+0.05
+0.10
+.Ed
+.Sh SEE ALSO
+.Xr jot 1 ,
+.Xr printf 1 ,
+.Xr printf 3
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Tn "Plan 9 from Bell Labs" .
+A
+.Nm
+command appeared in
+.Nx 3.0 ,
+and ported to
+.Fx 9.0 .
+This command was based on the command of the same name in
+.Tn "Plan 9 from Bell Labs"
+and the
+.Tn GNU
+core utilities.
+The
+.Tn GNU
+.Nm
+command first appeared in the 1.13 shell utilities release.
+.Sh BUGS
+The
+.Fl w
+option does not handle the transition from pure floating point
+to exponent representation very well.
+The
+.Nm
+command is not bug for bug compatible with the
+.Tn "Plan 9 from Bell Labs"
+or
+.Tn GNU
+versions of
+.Nm .
diff --git a/shell_cmds/seq/seq.c b/shell_cmds/seq/seq.c
new file mode 100644
index 0000000..9c3623d
--- /dev/null
+++ b/shell_cmds/seq/seq.c
@@ -0,0 +1,453 @@
+/* $NetBSD: seq.c,v 1.5 2008/07/21 14:19:26 lukem Exp $ */
+/*
+ * Copyright (c) 2005 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Brian Ginsbach.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/seq/seq.c,v 1.2 2010/02/20 01:23:15 delphij Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <math.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ZERO '0'
+#define SPACE ' '
+
+#define MAX(a, b) (((a) < (b))? (b) : (a))
+#define ISSIGN(c) ((int)(c) == '-' || (int)(c) == '+')
+#define ISEXP(c) ((int)(c) == 'e' || (int)(c) == 'E')
+#define ISODIGIT(c) ((int)(c) >= '0' && (int)(c) <= '7')
+
+/* Globals */
+
+const char *decimal_point = "."; /* default */
+char default_format[] = { "%g" }; /* default */
+
+/* Prototypes */
+
+double e_atof(const char *);
+
+int decimal_places(const char *);
+int main(int, char *[]);
+int numeric(const char *);
+int valid_format(const char *);
+
+char *generate_format(double, double, double, int, char);
+char *unescape(char *);
+
+/*
+ * The seq command will print out a numeric sequence from 1, the default,
+ * to a user specified upper limit by 1. The lower bound and increment
+ * maybe indicated by the user on the command line. The sequence can
+ * be either whole, the default, or decimal numbers.
+ */
+int
+main(int argc, char *argv[])
+{
+ int c = 0, errflg = 0;
+ int equalize = 0;
+ double first = 1.0;
+ double last = 0.0;
+ double incr = 0.0;
+ struct lconv *locale;
+ char *fmt = NULL;
+ const char *sep = "\n";
+ const char *term = NULL;
+ char pad = ZERO;
+
+ /* Determine the locale's decimal point. */
+ locale = localeconv();
+ if (locale && locale->decimal_point && locale->decimal_point[0] != '\0')
+ decimal_point = locale->decimal_point;
+
+ /*
+ * Process options, but handle negative numbers separately
+ * least they trip up getopt(3).
+ */
+ while ((optind < argc) && !numeric(argv[optind]) &&
+ (c = getopt(argc, argv, "f:hs:t:w")) != -1) {
+
+ switch (c) {
+ case 'f': /* format (plan9) */
+ fmt = optarg;
+ equalize = 0;
+ break;
+ case 's': /* separator (GNU) */
+ sep = unescape(optarg);
+ break;
+ case 't': /* terminator (new) */
+ term = unescape(optarg);
+ break;
+ case 'w': /* equal width (plan9) */
+ if (!fmt)
+ if (equalize++)
+ pad = SPACE;
+ break;
+ case 'h': /* help (GNU) */
+ default:
+ errflg++;
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 1 || argc > 3)
+ errflg++;
+
+ if (errflg) {
+ fprintf(stderr,
+ "usage: %s [-w] [-f format] [-s string] [-t string] [first [incr]] last\n",
+ getprogname());
+ exit(1);
+ }
+
+ last = e_atof(argv[argc - 1]);
+
+ if (argc > 1)
+ first = e_atof(argv[0]);
+
+ if (argc > 2) {
+ incr = e_atof(argv[1]);
+ /* Plan 9/GNU don't do zero */
+ if (incr == 0.0)
+ errx(1, "zero %screment", (first < last)? "in" : "de");
+ }
+
+ /* default is one for Plan 9/GNU work alike */
+ if (incr == 0.0)
+ incr = (first < last) ? 1.0 : -1.0;
+
+ if (incr <= 0.0 && first < last)
+ errx(1, "needs positive increment");
+
+ if (incr >= 0.0 && first > last)
+ errx(1, "needs negative decrement");
+
+ if (fmt != NULL) {
+ if (!valid_format(fmt))
+ errx(1, "invalid format string: `%s'", fmt);
+ fmt = unescape(fmt);
+ /*
+ * XXX to be bug for bug compatible with Plan 9 add a
+ * newline if none found at the end of the format string.
+ */
+ } else
+ fmt = generate_format(first, incr, last, equalize, pad);
+
+ if (incr > 0) {
+ for (; first <= last; first += incr) {
+ printf(fmt, first);
+ fputs(sep, stdout);
+ }
+ } else {
+ for (; first >= last; first += incr) {
+ printf(fmt, first);
+ fputs(sep, stdout);
+ }
+ }
+ if (term != NULL)
+ fputs(term, stdout);
+
+ return (0);
+}
+
+/*
+ * numeric - verify that string is numeric
+ */
+int
+numeric(const char *s)
+{
+ int seen_decimal_pt, decimal_pt_len;
+
+ /* skip any sign */
+ if (ISSIGN((unsigned char)*s))
+ s++;
+
+ seen_decimal_pt = 0;
+ decimal_pt_len = strlen(decimal_point);
+ while (*s) {
+ if (!isdigit((unsigned char)*s)) {
+ if (!seen_decimal_pt &&
+ strncmp(s, decimal_point, decimal_pt_len) == 0) {
+ s += decimal_pt_len;
+ seen_decimal_pt = 1;
+ continue;
+ }
+ if (ISEXP((unsigned char)*s)) {
+ s++;
+ if (ISSIGN((unsigned char)*s) ||
+ isdigit((unsigned char)*s)) {
+ s++;
+ continue;
+ }
+ }
+ break;
+ }
+ s++;
+ }
+ return (*s == '\0');
+}
+
+/*
+ * valid_format - validate user specified format string
+ */
+int
+valid_format(const char *fmt)
+{
+ int conversions = 0;
+
+ while (*fmt != '\0') {
+ /* scan for conversions */
+ if (*fmt != '\0' && *fmt != '%') {
+ do {
+ fmt++;
+ } while (*fmt != '\0' && *fmt != '%');
+ }
+ /* scan a conversion */
+ if (*fmt != '\0') {
+ do {
+ fmt++;
+
+ /* ok %% */
+ if (*fmt == '%') {
+ fmt++;
+ break;
+ }
+ /* valid conversions */
+ if (strchr("eEfgG", *fmt) &&
+ conversions++ < 1) {
+ fmt++;
+ break;
+ }
+ /* flags, width and precsision */
+ if (isdigit((unsigned char)*fmt) ||
+ strchr("+- 0#.", *fmt))
+ continue;
+
+ /* oops! bad conversion format! */
+ return (0);
+ } while (*fmt != '\0');
+ }
+ }
+
+ return (conversions <= 1);
+}
+
+/*
+ * unescape - handle C escapes in a string
+ */
+char *
+unescape(char *orig)
+{
+ char c, *cp, *new = orig;
+ int i;
+
+ for (cp = orig; (*orig = *cp); cp++, orig++) {
+ if (*cp != '\\')
+ continue;
+
+ switch (*++cp) {
+ case 'a': /* alert (bell) */
+ *orig = '\a';
+ continue;
+ case 'b': /* backspace */
+ *orig = '\b';
+ continue;
+ case 'e': /* escape */
+ *orig = '\e';
+ continue;
+ case 'f': /* formfeed */
+ *orig = '\f';
+ continue;
+ case 'n': /* newline */
+ *orig = '\n';
+ continue;
+ case 'r': /* carriage return */
+ *orig = '\r';
+ continue;
+ case 't': /* horizontal tab */
+ *orig = '\t';
+ continue;
+ case 'v': /* vertical tab */
+ *orig = '\v';
+ continue;
+ case '\\': /* backslash */
+ *orig = '\\';
+ continue;
+ case '\'': /* single quote */
+ *orig = '\'';
+ continue;
+ case '\"': /* double quote */
+ *orig = '"';
+ continue;
+ case '0':
+ case '1':
+ case '2':
+ case '3': /* octal */
+ case '4':
+ case '5':
+ case '6':
+ case '7': /* number */
+ for (i = 0, c = 0;
+ ISODIGIT((unsigned char)*cp) && i < 3;
+ i++, cp++) {
+ c <<= 3;
+ c |= (*cp - '0');
+ }
+ *orig = c;
+ --cp;
+ continue;
+ case 'x': /* hexidecimal number */
+ cp++; /* skip 'x' */
+ for (i = 0, c = 0;
+ isxdigit((unsigned char)*cp) && i < 2;
+ i++, cp++) {
+ c <<= 4;
+ if (isdigit((unsigned char)*cp))
+ c |= (*cp - '0');
+ else
+ c |= ((toupper((unsigned char)*cp) -
+ 'A') + 10);
+ }
+ *orig = c;
+ --cp;
+ continue;
+ default:
+ --cp;
+ break;
+ }
+ }
+
+ return (new);
+}
+
+/*
+ * e_atof - convert an ASCII string to a double
+ * exit if string is not a valid double, or if converted value would
+ * cause overflow or underflow
+ */
+double
+e_atof(const char *num)
+{
+ char *endp;
+ double dbl;
+
+ errno = 0;
+ dbl = strtod(num, &endp);
+
+ if (errno == ERANGE)
+ /* under or overflow */
+ err(2, "%s", num);
+ else if (*endp != '\0')
+ /* "junk" left in number */
+ errx(2, "invalid floating point argument: %s", num);
+
+ /* zero shall have no sign */
+ if (dbl == -0.0)
+ dbl = 0;
+ return (dbl);
+}
+
+/*
+ * decimal_places - count decimal places in a number (string)
+ */
+int
+decimal_places(const char *number)
+{
+ int places = 0;
+ char *dp;
+
+ /* look for a decimal point */
+ if ((dp = strstr(number, decimal_point))) {
+ dp += strlen(decimal_point);
+
+ while (isdigit((unsigned char)*dp++))
+ places++;
+ }
+ return (places);
+}
+
+/*
+ * generate_format - create a format string
+ *
+ * XXX to be bug for bug compatable with Plan9 and GNU return "%g"
+ * when "%g" prints as "%e" (this way no width adjustments are made)
+ */
+char *
+generate_format(double first, double incr, double last, int equalize, char pad)
+{
+ static char buf[256];
+ char cc = '\0';
+ int precision, width1, width2, places;
+
+ if (equalize == 0)
+ return (default_format);
+
+ /* figure out "last" value printed */
+ if (first > last)
+ last = first - incr * floor((first - last) / incr);
+ else
+ last = first + incr * floor((last - first) / incr);
+
+ sprintf(buf, "%g", incr);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ precision = decimal_places(buf);
+
+ width1 = sprintf(buf, "%g", first);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ if ((places = decimal_places(buf)))
+ width1 -= (places + strlen(decimal_point));
+
+ precision = MAX(places, precision);
+
+ width2 = sprintf(buf, "%g", last);
+ if (strchr(buf, 'e'))
+ cc = 'e';
+ if ((places = decimal_places(buf)))
+ width2 -= (places + strlen(decimal_point));
+
+ if (precision) {
+ sprintf(buf, "%%%c%d.%d%c", pad,
+ MAX(width1, width2) + (int) strlen(decimal_point) +
+ precision, precision, (cc) ? cc : 'f');
+ } else {
+ sprintf(buf, "%%%c%d%c", pad, MAX(width1, width2),
+ (cc) ? cc : 'g');
+ }
+
+ return (buf);
+}
diff --git a/shell_cmds/sh/Makefile b/shell_cmds/sh/Makefile
new file mode 100644
index 0000000..8d08662
--- /dev/null
+++ b/shell_cmds/sh/Makefile
@@ -0,0 +1,70 @@
+# @(#)Makefile 8.4 (Berkeley) 5/5/95
+# $FreeBSD: head/bin/sh/Makefile 322515 2017-08-14 19:21:37Z ngie $
+
+.include <src.opts.mk>
+
+PACKAGE=runtime
+PROG= sh
+INSTALLFLAGS= -S
+SHSRCS= alias.c arith_yacc.c arith_yylex.c cd.c echo.c error.c eval.c \
+ exec.c expand.c \
+ histedit.c input.c jobs.c kill.c mail.c main.c memalloc.c miscbltin.c \
+ mystring.c options.c output.c parser.c printf.c redir.c show.c \
+ test.c trap.c var.c
+GENSRCS= builtins.c nodes.c syntax.c
+GENHDRS= builtins.h nodes.h syntax.h token.h
+SRCS= ${SHSRCS} ${GENSRCS} ${GENHDRS}
+
+# MLINKS for Shell built in commands for which there are no userland
+# utilities of the same name are handled with the associated manpage,
+# builtin.1 in share/man/man1/.
+
+LIBADD= edit
+
+CFLAGS+=-DSHELL -I. -I${.CURDIR}
+# for debug:
+# DEBUG_FLAGS+= -g -DDEBUG=2 -fno-inline
+WARNS?= 2
+WFORMAT=0
+
+.PATH: ${.CURDIR}/bltin \
+ ${.CURDIR:H}/kill \
+ ${.CURDIR:H}/test \
+ ${SRCTOP}/usr.bin/printf
+
+CLEANFILES+= mknodes mknodes.o \
+ mksyntax mksyntax.o
+CLEANFILES+= ${GENSRCS} ${GENHDRS}
+
+build-tools: mknodes mksyntax
+
+.ORDER: builtins.c builtins.h
+builtins.h: .NOMETA
+builtins.c builtins.h: mkbuiltins builtins.def
+ sh ${.CURDIR}/mkbuiltins ${.CURDIR}
+
+# XXX this is just to stop the default .c rule being used, so that the
+# intermediate object has a fixed name.
+# XXX we have a default .c rule, but no default .o rule.
+mknodes.o mksyntax.o: ${BUILD_TOOLS_META}
+ ${CC} ${CFLAGS} ${LDFLAGS} ${.IMPSRC} ${LDLIBS} -o ${.TARGET}
+mknodes: mknodes.o ${BUILD_TOOLS_META}
+mksyntax: mksyntax.o ${BUILD_TOOLS_META}
+
+.ORDER: nodes.c nodes.h
+nodes.h: .NOMETA
+nodes.c nodes.h: mknodes nodetypes nodes.c.pat
+ ${BTOOLSPATH:U.}/mknodes ${.CURDIR}/nodetypes ${.CURDIR}/nodes.c.pat
+
+.ORDER: syntax.c syntax.h
+syntax.h: .NOMETA
+syntax.c syntax.h: mksyntax
+ ${BTOOLSPATH:U.}/mksyntax
+
+token.h: mktokens
+ sh ${.CURDIR}/mktokens
+
+HAS_TESTS=
+SUBDIR.${MK_TESTS}+= tests
+
+.include <bsd.prog.mk>
diff --git a/shell_cmds/sh/Makefile.depend b/shell_cmds/sh/Makefile.depend
new file mode 100644
index 0000000..189c031
--- /dev/null
+++ b/shell_cmds/sh/Makefile.depend
@@ -0,0 +1,19 @@
+# $FreeBSD: head/bin/sh/Makefile.depend 325188 2017-10-31 00:07:04Z bdrewery $
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libedit \
+ lib/ncurses/ncursesw \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/shell_cmds/sh/TOUR b/shell_cmds/sh/TOUR
new file mode 100644
index 0000000..82215f3
--- /dev/null
+++ b/shell_cmds/sh/TOUR
@@ -0,0 +1,301 @@
+# @(#)TOUR 8.1 (Berkeley) 5/31/93
+# $FreeBSD: head/bin/sh/TOUR 317882 2017-05-06 13:28:42Z jilles $
+
+NOTE -- This is the original TOUR paper distributed with ash and
+does not represent the current state of the shell. It is provided anyway
+since it provides helpful information for how the shell is structured,
+but be warned that things have changed -- the current shell is
+still under development.
+
+================================================================
+
+ A Tour through Ash
+
+ Copyright 1989 by Kenneth Almquist.
+
+
+DIRECTORIES: The subdirectory bltin contains commands which can
+be compiled stand-alone. The rest of the source is in the main
+ash directory.
+
+SOURCE CODE GENERATORS: Files whose names begin with "mk" are
+programs that generate source code. A complete list of these
+programs is:
+
+ program input files generates
+ ------- ----------- ---------
+ mkbuiltins builtins.def builtins.h builtins.c
+ mknodes nodetypes nodes.h nodes.c
+ mksyntax - syntax.h syntax.c
+ mktokens - token.h
+
+There are undoubtedly too many of these.
+
+EXCEPTIONS: Code for dealing with exceptions appears in
+exceptions.c. The C language doesn't include exception handling,
+so I implement it using setjmp and longjmp. The global variable
+exception contains the type of exception. EXERROR is raised by
+calling error. EXINT is an interrupt.
+
+INTERRUPTS: In an interactive shell, an interrupt will cause an
+EXINT exception to return to the main command loop. (Exception:
+EXINT is not raised if the user traps interrupts using the trap
+command.) The INTOFF and INTON macros (defined in exception.h)
+provide uninterruptible critical sections. Between the execution
+of INTOFF and the execution of INTON, interrupt signals will be
+held for later delivery. INTOFF and INTON can be nested.
+
+MEMALLOC.C: Memalloc.c defines versions of malloc and realloc
+which call error when there is no memory left. It also defines a
+stack oriented memory allocation scheme. Allocating off a stack
+is probably more efficient than allocation using malloc, but the
+big advantage is that when an exception occurs all we have to do
+to free up the memory in use at the time of the exception is to
+restore the stack pointer. The stack is implemented using a
+linked list of blocks.
+
+STPUTC: If the stack were contiguous, it would be easy to store
+strings on the stack without knowing in advance how long the
+string was going to be:
+ p = stackptr;
+ *p++ = c; /* repeated as many times as needed */
+ stackptr = p;
+The following three macros (defined in memalloc.h) perform these
+operations, but grow the stack if you run off the end:
+ STARTSTACKSTR(p);
+ STPUTC(c, p); /* repeated as many times as needed */
+ grabstackstr(p);
+
+We now start a top-down look at the code:
+
+MAIN.C: The main routine performs some initialization, executes
+the user's profile if necessary, and calls cmdloop. Cmdloop
+repeatedly parses and executes commands.
+
+OPTIONS.C: This file contains the option processing code. It is
+called from main to parse the shell arguments when the shell is
+invoked, and it also contains the set builtin. The -i and -m op-
+tions (the latter turns on job control) require changes in signal
+handling. The routines setjobctl (in jobs.c) and setinteractive
+(in trap.c) are called to handle changes to these options.
+
+PARSING: The parser code is all in parser.c. A recursive des-
+cent parser is used. Syntax tables (generated by mksyntax) are
+used to classify characters during lexical analysis. There are
+four tables: one for normal use, one for use when inside single
+quotes and dollar single quotes, one for use when inside double
+quotes and one for use in arithmetic. The tables are machine
+dependent because they are indexed by character variables and
+the range of a char varies from machine to machine.
+
+PARSE OUTPUT: The output of the parser consists of a tree of
+nodes. The various types of nodes are defined in the file node-
+types.
+
+Nodes of type NARG are used to represent both words and the con-
+tents of here documents. An early version of ash kept the con-
+tents of here documents in temporary files, but keeping here do-
+cuments in memory typically results in significantly better per-
+formance. It would have been nice to make it an option to use
+temporary files for here documents, for the benefit of small
+machines, but the code to keep track of when to delete the tem-
+porary files was complex and I never fixed all the bugs in it.
+(AT&T has been maintaining the Bourne shell for more than ten
+years, and to the best of my knowledge they still haven't gotten
+it to handle temporary files correctly in obscure cases.)
+
+The text field of a NARG structure points to the text of the
+word. The text consists of ordinary characters and a number of
+special codes defined in parser.h. The special codes are:
+
+ CTLVAR Parameter expansion
+ CTLENDVAR End of parameter expansion
+ CTLBACKQ Command substitution
+ CTLBACKQ|CTLQUOTE Command substitution inside double quotes
+ CTLARI Arithmetic expansion
+ CTLENDARI End of arithmetic expansion
+ CTLESC Escape next character
+
+A variable substitution contains the following elements:
+
+ CTLVAR type name '=' [ alternative-text CTLENDVAR ]
+
+The type field is a single character specifying the type of sub-
+stitution. The possible types are:
+
+ VSNORMAL $var
+ VSMINUS ${var-text}
+ VSMINUS|VSNUL ${var:-text}
+ VSPLUS ${var+text}
+ VSPLUS|VSNUL ${var:+text}
+ VSQUESTION ${var?text}
+ VSQUESTION|VSNUL ${var:?text}
+ VSASSIGN ${var=text}
+ VSASSIGN|VSNUL ${var:=text}
+ VSTRIMLEFT ${var#text}
+ VSTRIMLEFTMAX ${var##text}
+ VSTRIMRIGHT ${var%text}
+ VSTRIMRIGHTMAX ${var%%text}
+ VSLENGTH ${#var}
+ VSERROR delayed error
+
+In addition, the type field will have the VSQUOTE flag set if the
+variable is enclosed in double quotes and the VSLINENO flag if
+LINENO is being expanded (the parameter name is the decimal line
+number). The parameter's name comes next, terminated by an equals
+sign. If the type is not VSNORMAL (including when it is VSLENGTH),
+then the text field in the substitution follows, terminated by a
+CTLENDVAR byte.
+
+The type VSERROR is used to allow parsing bad substitutions like
+${var[7]} and generate an error when they are expanded.
+
+Commands in back quotes are parsed and stored in a linked list.
+The locations of these commands in the string are indicated by
+CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether
+the back quotes were enclosed in double quotes.
+
+Arithmetic expansion starts with CTLARI and ends with CTLENDARI.
+
+The character CTLESC escapes the next character, so that in case
+any of the CTL characters mentioned above appear in the input,
+they can be passed through transparently. CTLESC is also used to
+escape '*', '?', '[', and '!' characters which were quoted by the
+user and thus should not be used for file name generation.
+
+CTLESC characters have proved to be particularly tricky to get
+right. In the case of here documents which are not subject to
+variable and command substitution, the parser doesn't insert any
+CTLESC characters to begin with (so the contents of the text
+field can be written without any processing). Other here docu-
+ments, and words which are not subject to file name generation,
+have the CTLESC characters removed during the variable and command
+substitution phase. Words which are subject to file name
+generation have the CTLESC characters removed as part of the file
+name phase.
+
+EXECUTION: Command execution is handled by the following files:
+ eval.c The top level routines.
+ redir.c Code to handle redirection of input and output.
+ jobs.c Code to handle forking, waiting, and job control.
+ exec.c Code to do path searches and the actual exec sys call.
+ expand.c Code to evaluate arguments.
+ var.c Maintains the variable symbol table. Called from expand.c.
+
+EVAL.C: Evaltree recursively executes a parse tree. The exit
+status is returned in the global variable exitstatus. The alter-
+native entry evalbackcmd is called to evaluate commands in back
+quotes. It saves the result in memory if the command is a buil-
+tin; otherwise it forks off a child to execute the command and
+connects the standard output of the child to a pipe.
+
+JOBS.C: To create a process, you call makejob to return a job
+structure, and then call forkshell (passing the job structure as
+an argument) to create the process. Waitforjob waits for a job
+to complete. These routines take care of process groups if job
+control is defined.
+
+REDIR.C: Ash allows file descriptors to be redirected and then
+restored without forking off a child process. This is accom-
+plished by duplicating the original file descriptors. The redir-
+tab structure records where the file descriptors have been dupli-
+cated to.
+
+EXEC.C: The routine find_command locates a command, and enters
+the command in the hash table if it is not already there. The
+third argument specifies whether it is to print an error message
+if the command is not found. (When a pipeline is set up,
+find_command is called for all the commands in the pipeline be-
+fore any forking is done, so to get the commands into the hash
+table of the parent process. But to make command hashing as
+transparent as possible, we silently ignore errors at that point
+and only print error messages if the command cannot be found
+later.)
+
+The routine shellexec is the interface to the exec system call.
+
+EXPAND.C: As the routine argstr generates words by parameter
+expansion, command substitution and arithmetic expansion, it
+performs word splitting on the result. As each word is output,
+the routine expandmeta performs file name generation (if enabled).
+
+VAR.C: Variables are stored in a hash table. Probably we should
+switch to extensible hashing. The variable name is stored in the
+same string as the value (using the format "name=value") so that
+no string copying is needed to create the environment of a com-
+mand. Variables which the shell references internally are preal-
+located so that the shell can reference the values of these vari-
+ables without doing a lookup.
+
+When a program is run, the code in eval.c sticks any environment
+variables which precede the command (as in "PATH=xxx command") in
+the variable table as the simplest way to strip duplicates, and
+then calls "environment" to get the value of the environment.
+
+BUILTIN COMMANDS: The procedures for handling these are scat-
+tered throughout the code, depending on which location appears
+most appropriate. They can be recognized because their names al-
+ways end in "cmd". The mapping from names to procedures is
+specified in the file builtins.def, which is processed by the
+mkbuiltins command.
+
+A builtin command is invoked with argc and argv set up like a
+normal program. A builtin command is allowed to overwrite its
+arguments. Builtin routines can call nextopt to do option pars-
+ing. This is kind of like getopt, but you don't pass argc and
+argv to it. Builtin routines can also call error. This routine
+normally terminates the shell (or returns to the main command
+loop if the shell is interactive), but when called from a non-
+special builtin command it causes the builtin command to
+terminate with an exit status of 2.
+
+The directory bltins contains commands which can be compiled in-
+dependently but can also be built into the shell for efficiency
+reasons. The header file bltin.h takes care of most of the
+differences between the ash and the stand-alone environment.
+The user should call the main routine "main", and #define main to
+be the name of the routine to use when the program is linked into
+ash. This #define should appear before bltin.h is included;
+bltin.h will #undef main if the program is to be compiled
+stand-alone. A similar approach is used for a few utilities from
+bin and usr.bin.
+
+CD.C: This file defines the cd and pwd builtins.
+
+SIGNALS: Trap.c implements the trap command. The routine set-
+signal figures out what action should be taken when a signal is
+received and invokes the signal system call to set the signal ac-
+tion appropriately. When a signal that a user has set a trap for
+is caught, the routine "onsig" sets a flag. The routine dotrap
+is called at appropriate points to actually handle the signal.
+When an interrupt is caught and no trap has been set for that
+signal, the routine "onint" in error.c is called.
+
+OUTPUT: Ash uses its own output routines. There are three out-
+put structures allocated. "Output" represents the standard out-
+put, "errout" the standard error, and "memout" contains output
+which is to be stored in memory. This last is used when a buil-
+tin command appears in backquotes, to allow its output to be col-
+lected without doing any I/O through the UNIX operating system.
+The variables out1 and out2 normally point to output and errout,
+respectively, but they are set to point to memout when appropri-
+ate inside backquotes.
+
+INPUT: The basic input routine is pgetc, which reads from the
+current input file. There is a stack of input files; the current
+input file is the top file on this stack. The code allows the
+input to come from a string rather than a file. (This is for the
+-c option and the "." and eval builtin commands.) The global
+variable plinno is saved and restored when files are pushed and
+popped from the stack. The parser routines store the number of
+the current line in this variable.
+
+DEBUGGING: If DEBUG is defined in shell.h, then the shell will
+write debugging information to the file $HOME/trace. Most of
+this is done using the TRACE macro, which takes a set of printf
+arguments inside two sets of parenthesis. Example:
+"TRACE(("n=%d0, n))". The double parenthesis are necessary be-
+cause the preprocessor can't handle functions with a variable
+number of arguments. Defining DEBUG also causes the shell to
+generate a core dump if it is sent a quit signal. The tracing
+code is in show.c.
diff --git a/shell_cmds/sh/alias.c b/shell_cmds/sh/alias.c
new file mode 100644
index 0000000..a8fe82c
--- /dev/null
+++ b/shell_cmds/sh/alias.c
@@ -0,0 +1,256 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/alias.c 317039 2017-04-16 22:10:02Z jilles $");
+
+#include <stdlib.h>
+#include "shell.h"
+#include "output.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "options.h"
+#include "builtins.h"
+
+#define ATABSIZE 39
+
+static struct alias *atab[ATABSIZE];
+static int aliases;
+
+static void setalias(const char *, const char *);
+static int unalias(const char *);
+static struct alias **hashalias(const char *);
+
+static
+void
+setalias(const char *name, const char *val)
+{
+ struct alias *ap, **app;
+
+ unalias(name);
+ app = hashalias(name);
+ INTOFF;
+ ap = ckmalloc(sizeof (struct alias));
+ ap->name = savestr(name);
+ ap->val = savestr(val);
+ ap->flag = 0;
+ ap->next = *app;
+ *app = ap;
+ aliases++;
+ INTON;
+}
+
+static void
+freealias(struct alias *ap)
+{
+ ckfree(ap->name);
+ ckfree(ap->val);
+ ckfree(ap);
+}
+
+static int
+unalias(const char *name)
+{
+ struct alias *ap, **app;
+
+ app = hashalias(name);
+
+ for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
+ if (equal(name, ap->name)) {
+ /*
+ * if the alias is currently in use (i.e. its
+ * buffer is being used by the input routine) we
+ * just null out the name instead of freeing it.
+ * We could clear it out later, but this situation
+ * is so rare that it hardly seems worth it.
+ */
+ if (ap->flag & ALIASINUSE)
+ *ap->name = '\0';
+ else {
+ INTOFF;
+ *app = ap->next;
+ freealias(ap);
+ INTON;
+ }
+ aliases--;
+ return (0);
+ }
+ }
+
+ return (1);
+}
+
+static void
+rmaliases(void)
+{
+ struct alias *ap, **app;
+ int i;
+
+ INTOFF;
+ for (i = 0; i < ATABSIZE; i++) {
+ app = &atab[i];
+ while (*app) {
+ ap = *app;
+ if (ap->flag & ALIASINUSE) {
+ *ap->name = '\0';
+ app = &(*app)->next;
+ } else {
+ *app = ap->next;
+ freealias(ap);
+ }
+ }
+ }
+ aliases = 0;
+ INTON;
+}
+
+struct alias *
+lookupalias(const char *name, int check)
+{
+ struct alias *ap;
+
+ if (aliases == 0)
+ return (NULL);
+ for (ap = *hashalias(name); ap; ap = ap->next) {
+ if (equal(name, ap->name)) {
+ if (check && (ap->flag & ALIASINUSE))
+ return (NULL);
+ return (ap);
+ }
+ }
+
+ return (NULL);
+}
+
+static int
+comparealiases(const void *p1, const void *p2)
+{
+ const struct alias *const *a1 = p1;
+ const struct alias *const *a2 = p2;
+
+ return strcmp((*a1)->name, (*a2)->name);
+}
+
+static void
+printalias(const struct alias *a)
+{
+ out1fmt("%s=", a->name);
+ out1qstr(a->val);
+ out1c('\n');
+}
+
+static void
+printaliases(void)
+{
+ int i, j;
+ struct alias **sorted, *ap;
+
+ INTOFF;
+ sorted = ckmalloc(aliases * sizeof(*sorted));
+ j = 0;
+ for (i = 0; i < ATABSIZE; i++)
+ for (ap = atab[i]; ap; ap = ap->next)
+ if (*ap->name != '\0')
+ sorted[j++] = ap;
+ qsort(sorted, aliases, sizeof(*sorted), comparealiases);
+ for (i = 0; i < aliases; i++) {
+ printalias(sorted[i]);
+ if (int_pending())
+ break;
+ }
+ ckfree(sorted);
+ INTON;
+}
+
+int
+aliascmd(int argc __unused, char **argv __unused)
+{
+ char *n, *v;
+ int ret = 0;
+ struct alias *ap;
+
+ nextopt("");
+
+ if (*argptr == NULL) {
+ printaliases();
+ return (0);
+ }
+ while ((n = *argptr++) != NULL) {
+ if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
+ if ((ap = lookupalias(n, 0)) == NULL) {
+ warning("%s: not found", n);
+ ret = 1;
+ } else
+ printalias(ap);
+ else {
+ *v++ = '\0';
+ setalias(n, v);
+ }
+ }
+
+ return (ret);
+}
+
+int
+unaliascmd(int argc __unused, char **argv __unused)
+{
+ int i;
+
+ while ((i = nextopt("a")) != '\0') {
+ if (i == 'a') {
+ rmaliases();
+ return (0);
+ }
+ }
+ for (i = 0; *argptr; argptr++)
+ i |= unalias(*argptr);
+
+ return (i);
+}
+
+static struct alias **
+hashalias(const char *p)
+{
+ unsigned int hashval;
+
+ hashval = (unsigned char)*p << 4;
+ while (*p)
+ hashval+= *p++;
+ return &atab[hashval % ATABSIZE];
+}
diff --git a/shell_cmds/sh/alias.h b/shell_cmds/sh/alias.h
new file mode 100644
index 0000000..e08a9e8
--- /dev/null
+++ b/shell_cmds/sh/alias.h
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)alias.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/alias.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+#define ALIASINUSE 1
+
+struct alias {
+ struct alias *next;
+ char *name;
+ char *val;
+ int flag;
+};
+
+struct alias *lookupalias(const char *, int);
diff --git a/shell_cmds/sh/arith.h b/shell_cmds/sh/arith.h
new file mode 100644
index 0000000..9c2ef39
--- /dev/null
+++ b/shell_cmds/sh/arith.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)arith.h 1.1 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/arith.h 315511 2017-03-18 20:41:07Z jilles $
+ */
+
+#include "shell.h"
+
+#define DIGITS(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
+
+arith_t arith(const char *);
diff --git a/shell_cmds/sh/arith_yacc.c b/shell_cmds/sh/arith_yacc.c
new file mode 100644
index 0000000..20e1e43
--- /dev/null
+++ b/shell_cmds/sh/arith_yacc.c
@@ -0,0 +1,381 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2007
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/arith_yacc.c 270246 2014-08-20 20:15:43Z jilles $");
+
+#include <limits.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "arith.h"
+#include "arith_yacc.h"
+#include "expand.h"
+#include "shell.h"
+#include "error.h"
+#include "memalloc.h"
+#include "output.h"
+#include "options.h"
+#include "var.h"
+
+#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
+#error Arithmetic tokens are out of order.
+#endif
+
+static const char *arith_startbuf;
+
+const char *arith_buf;
+union yystype yylval;
+
+static int last_token;
+
+#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
+
+static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
+ ARITH_PRECEDENCE(ARITH_MUL, 0),
+ ARITH_PRECEDENCE(ARITH_DIV, 0),
+ ARITH_PRECEDENCE(ARITH_REM, 0),
+ ARITH_PRECEDENCE(ARITH_ADD, 1),
+ ARITH_PRECEDENCE(ARITH_SUB, 1),
+ ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
+ ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
+ ARITH_PRECEDENCE(ARITH_LT, 3),
+ ARITH_PRECEDENCE(ARITH_LE, 3),
+ ARITH_PRECEDENCE(ARITH_GT, 3),
+ ARITH_PRECEDENCE(ARITH_GE, 3),
+ ARITH_PRECEDENCE(ARITH_EQ, 4),
+ ARITH_PRECEDENCE(ARITH_NE, 4),
+ ARITH_PRECEDENCE(ARITH_BAND, 5),
+ ARITH_PRECEDENCE(ARITH_BXOR, 6),
+ ARITH_PRECEDENCE(ARITH_BOR, 7),
+};
+
+#define ARITH_MAX_PREC 8
+
+int letcmd(int, char **);
+
+static __dead2 void yyerror(const char *s)
+{
+ error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
+ /* NOTREACHED */
+}
+
+static arith_t arith_lookupvarint(char *varname)
+{
+ const char *str;
+ char *p;
+ arith_t result;
+
+ str = lookupvar(varname);
+ if (uflag && str == NULL)
+ yyerror("variable not set");
+ if (str == NULL || *str == '\0')
+ str = "0";
+ errno = 0;
+ result = strtoarith_t(str, &p, 0);
+ if (errno != 0 || *p != '\0')
+ yyerror("variable conversion error");
+ return result;
+}
+
+static inline int arith_prec(int op)
+{
+ return prec[op - ARITH_BINOP_MIN];
+}
+
+static inline int higher_prec(int op1, int op2)
+{
+ return arith_prec(op1) < arith_prec(op2);
+}
+
+static arith_t do_binop(int op, arith_t a, arith_t b)
+{
+
+ switch (op) {
+ default:
+ case ARITH_REM:
+ case ARITH_DIV:
+ if (!b)
+ yyerror("division by zero");
+ if (a == ARITH_MIN && b == -1)
+ yyerror("divide error");
+ return op == ARITH_REM ? a % b : a / b;
+ case ARITH_MUL:
+ return (uintmax_t)a * (uintmax_t)b;
+ case ARITH_ADD:
+ return (uintmax_t)a + (uintmax_t)b;
+ case ARITH_SUB:
+ return (uintmax_t)a - (uintmax_t)b;
+ case ARITH_LSHIFT:
+ return (uintmax_t)a << (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
+ case ARITH_RSHIFT:
+ return a >> (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
+ case ARITH_LT:
+ return a < b;
+ case ARITH_LE:
+ return a <= b;
+ case ARITH_GT:
+ return a > b;
+ case ARITH_GE:
+ return a >= b;
+ case ARITH_EQ:
+ return a == b;
+ case ARITH_NE:
+ return a != b;
+ case ARITH_BAND:
+ return a & b;
+ case ARITH_BXOR:
+ return a ^ b;
+ case ARITH_BOR:
+ return a | b;
+ }
+}
+
+static arith_t assignment(int var, int noeval);
+
+static arith_t primary(int token, union yystype *val, int op, int noeval)
+{
+ arith_t result;
+
+again:
+ switch (token) {
+ case ARITH_LPAREN:
+ result = assignment(op, noeval);
+ if (last_token != ARITH_RPAREN)
+ yyerror("expecting ')'");
+ last_token = yylex();
+ return result;
+ case ARITH_NUM:
+ last_token = op;
+ return val->val;
+ case ARITH_VAR:
+ last_token = op;
+ return noeval ? val->val : arith_lookupvarint(val->name);
+ case ARITH_ADD:
+ token = op;
+ *val = yylval;
+ op = yylex();
+ goto again;
+ case ARITH_SUB:
+ *val = yylval;
+ return -primary(op, val, yylex(), noeval);
+ case ARITH_NOT:
+ *val = yylval;
+ return !primary(op, val, yylex(), noeval);
+ case ARITH_BNOT:
+ *val = yylval;
+ return ~primary(op, val, yylex(), noeval);
+ default:
+ yyerror("expecting primary");
+ }
+}
+
+static arith_t binop2(arith_t a, int op, int precedence, int noeval)
+{
+ for (;;) {
+ union yystype val;
+ arith_t b;
+ int op2;
+ int token;
+
+ token = yylex();
+ val = yylval;
+
+ b = primary(token, &val, yylex(), noeval);
+
+ op2 = last_token;
+ if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
+ higher_prec(op2, op)) {
+ b = binop2(b, op2, arith_prec(op), noeval);
+ op2 = last_token;
+ }
+
+ a = noeval ? b : do_binop(op, a, b);
+
+ if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
+ arith_prec(op2) >= precedence)
+ return a;
+
+ op = op2;
+ }
+}
+
+static arith_t binop(int token, union yystype *val, int op, int noeval)
+{
+ arith_t a = primary(token, val, op, noeval);
+
+ op = last_token;
+ if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
+ return a;
+
+ return binop2(a, op, ARITH_MAX_PREC, noeval);
+}
+
+static arith_t and(int token, union yystype *val, int op, int noeval)
+{
+ arith_t a = binop(token, val, op, noeval);
+ arith_t b;
+
+ op = last_token;
+ if (op != ARITH_AND)
+ return a;
+
+ token = yylex();
+ *val = yylval;
+
+ b = and(token, val, yylex(), noeval | !a);
+
+ return a && b;
+}
+
+static arith_t or(int token, union yystype *val, int op, int noeval)
+{
+ arith_t a = and(token, val, op, noeval);
+ arith_t b;
+
+ op = last_token;
+ if (op != ARITH_OR)
+ return a;
+
+ token = yylex();
+ *val = yylval;
+
+ b = or(token, val, yylex(), noeval | !!a);
+
+ return a || b;
+}
+
+static arith_t cond(int token, union yystype *val, int op, int noeval)
+{
+ arith_t a = or(token, val, op, noeval);
+ arith_t b;
+ arith_t c;
+
+ if (last_token != ARITH_QMARK)
+ return a;
+
+ b = assignment(yylex(), noeval | !a);
+
+ if (last_token != ARITH_COLON)
+ yyerror("expecting ':'");
+
+ token = yylex();
+ *val = yylval;
+
+ c = cond(token, val, yylex(), noeval | !!a);
+
+ return a ? b : c;
+}
+
+static arith_t assignment(int var, int noeval)
+{
+ union yystype val = yylval;
+ int op = yylex();
+ arith_t result;
+ char sresult[DIGITS(result) + 1];
+
+ if (var != ARITH_VAR)
+ return cond(var, &val, op, noeval);
+
+ if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
+ return cond(var, &val, op, noeval);
+
+ result = assignment(yylex(), noeval);
+ if (noeval)
+ return result;
+
+ if (op != ARITH_ASS)
+ result = do_binop(op - 11, arith_lookupvarint(val.name), result);
+ snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
+ setvar(val.name, sresult, 0);
+ return result;
+}
+
+arith_t arith(const char *s)
+{
+ struct stackmark smark;
+ arith_t result;
+
+ setstackmark(&smark);
+
+ arith_buf = arith_startbuf = s;
+
+ result = assignment(yylex(), 0);
+
+ if (last_token)
+ yyerror("expecting EOF");
+
+ popstackmark(&smark);
+
+ return result;
+}
+
+/*
+ * The exp(1) builtin.
+ */
+int
+letcmd(int argc, char **argv)
+{
+ const char *p;
+ char *concat;
+ char **ap;
+ arith_t i;
+
+ if (argc > 1) {
+ p = argv[1];
+ if (argc > 2) {
+ /*
+ * Concatenate arguments.
+ */
+ STARTSTACKSTR(concat);
+ ap = argv + 2;
+ for (;;) {
+ while (*p)
+ STPUTC(*p++, concat);
+ if ((p = *ap++) == NULL)
+ break;
+ STPUTC(' ', concat);
+ }
+ STPUTC('\0', concat);
+ p = grabstackstr(concat);
+ }
+ } else
+ p = "";
+
+ i = arith(p);
+
+ out1fmt(ARITH_FORMAT_STR "\n", i);
+ return !i;
+}
diff --git a/shell_cmds/sh/arith_yacc.h b/shell_cmds/sh/arith_yacc.h
new file mode 100644
index 0000000..d386886
--- /dev/null
+++ b/shell_cmds/sh/arith_yacc.h
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2007
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: head/bin/sh/arith_yacc.h 279503 2015-03-01 21:46:55Z jilles $
+ */
+
+#define ARITH_ASS 1
+
+#define ARITH_OR 2
+#define ARITH_AND 3
+#define ARITH_BAD 4
+#define ARITH_NUM 5
+#define ARITH_VAR 6
+#define ARITH_NOT 7
+
+#define ARITH_BINOP_MIN 8
+#define ARITH_LE 8
+#define ARITH_GE 9
+#define ARITH_LT 10
+#define ARITH_GT 11
+#define ARITH_EQ 12
+#define ARITH_REM 13
+#define ARITH_BAND 14
+#define ARITH_LSHIFT 15
+#define ARITH_RSHIFT 16
+#define ARITH_MUL 17
+#define ARITH_ADD 18
+#define ARITH_BOR 19
+#define ARITH_SUB 20
+#define ARITH_BXOR 21
+#define ARITH_DIV 22
+#define ARITH_NE 23
+#define ARITH_BINOP_MAX 24
+
+#define ARITH_ASS_MIN 24
+#define ARITH_REMASS 24
+#define ARITH_BANDASS 25
+#define ARITH_LSHIFTASS 26
+#define ARITH_RSHIFTASS 27
+#define ARITH_MULASS 28
+#define ARITH_ADDASS 29
+#define ARITH_BORASS 30
+#define ARITH_SUBASS 31
+#define ARITH_BXORASS 32
+#define ARITH_DIVASS 33
+#define ARITH_ASS_MAX 34
+
+#define ARITH_LPAREN 34
+#define ARITH_RPAREN 35
+#define ARITH_BNOT 36
+#define ARITH_QMARK 37
+#define ARITH_COLON 38
+
+extern const char *arith_buf;
+
+union yystype {
+ arith_t val;
+ char *name;
+};
+
+extern union yystype yylval;
+
+int yylex(void);
diff --git a/shell_cmds/sh/arith_yylex.c b/shell_cmds/sh/arith_yylex.c
new file mode 100644
index 0000000..9936852
--- /dev/null
+++ b/shell_cmds/sh/arith_yylex.c
@@ -0,0 +1,248 @@
+/*-
+ * Copyright (c) 2002
+ * Herbert Xu.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/arith_yylex.c 279503 2015-03-01 21:46:55Z jilles $");
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include "shell.h"
+#include "arith_yacc.h"
+#include "expand.h"
+#include "error.h"
+#include "memalloc.h"
+#include "parser.h"
+#include "syntax.h"
+
+#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
+#error Arithmetic tokens are out of order.
+#endif
+
+int
+yylex(void)
+{
+ int value;
+ const char *buf = arith_buf;
+ char *end;
+ const char *p;
+
+ for (;;) {
+ value = *buf;
+ switch (value) {
+ case ' ':
+ case '\t':
+ case '\n':
+ buf++;
+ continue;
+ default:
+ return ARITH_BAD;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ yylval.val = strtoarith_t(buf, &end, 0);
+ arith_buf = end;
+ return ARITH_NUM;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '_':
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ case 'q':
+ case 'r':
+ case 's':
+ case 't':
+ case 'u':
+ case 'v':
+ case 'w':
+ case 'x':
+ case 'y':
+ case 'z':
+ p = buf;
+ while (buf++, is_in_name(*buf))
+ ;
+ yylval.name = stalloc(buf - p + 1);
+ memcpy(yylval.name, p, buf - p);
+ yylval.name[buf - p] = '\0';
+ value = ARITH_VAR;
+ goto out;
+ case '=':
+ value += ARITH_ASS - '=';
+checkeq:
+ buf++;
+checkeqcur:
+ if (*buf != '=')
+ goto out;
+ value += 11;
+ break;
+ case '>':
+ switch (*++buf) {
+ case '=':
+ value += ARITH_GE - '>';
+ break;
+ case '>':
+ value += ARITH_RSHIFT - '>';
+ goto checkeq;
+ default:
+ value += ARITH_GT - '>';
+ goto out;
+ }
+ break;
+ case '<':
+ switch (*++buf) {
+ case '=':
+ value += ARITH_LE - '<';
+ break;
+ case '<':
+ value += ARITH_LSHIFT - '<';
+ goto checkeq;
+ default:
+ value += ARITH_LT - '<';
+ goto out;
+ }
+ break;
+ case '|':
+ if (*++buf != '|') {
+ value += ARITH_BOR - '|';
+ goto checkeqcur;
+ }
+ value += ARITH_OR - '|';
+ break;
+ case '&':
+ if (*++buf != '&') {
+ value += ARITH_BAND - '&';
+ goto checkeqcur;
+ }
+ value += ARITH_AND - '&';
+ break;
+ case '!':
+ if (*++buf != '=') {
+ value += ARITH_NOT - '!';
+ goto out;
+ }
+ value += ARITH_NE - '!';
+ break;
+ case 0:
+ goto out;
+ case '(':
+ value += ARITH_LPAREN - '(';
+ break;
+ case ')':
+ value += ARITH_RPAREN - ')';
+ break;
+ case '*':
+ value += ARITH_MUL - '*';
+ goto checkeq;
+ case '/':
+ value += ARITH_DIV - '/';
+ goto checkeq;
+ case '%':
+ value += ARITH_REM - '%';
+ goto checkeq;
+ case '+':
+ if (buf[1] == '+')
+ return ARITH_BAD;
+ value += ARITH_ADD - '+';
+ goto checkeq;
+ case '-':
+ if (buf[1] == '-')
+ return ARITH_BAD;
+ value += ARITH_SUB - '-';
+ goto checkeq;
+ case '~':
+ value += ARITH_BNOT - '~';
+ break;
+ case '^':
+ value += ARITH_BXOR - '^';
+ goto checkeq;
+ case '?':
+ value += ARITH_QMARK - '?';
+ break;
+ case ':':
+ value += ARITH_COLON - ':';
+ break;
+ }
+ break;
+ }
+
+ buf++;
+out:
+ arith_buf = buf;
+ return value;
+}
diff --git a/shell_cmds/sh/bltin/bltin.h b/shell_cmds/sh/bltin/bltin.h
new file mode 100644
index 0000000..b8c2087
--- /dev/null
+++ b/shell_cmds/sh/bltin/bltin.h
@@ -0,0 +1,81 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bltin.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/bltin/bltin.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+/*
+ * This file is included by programs which are optionally built into the
+ * shell. If SHELL is defined, we try to map the standard UNIX library
+ * routines to ash routines using defines.
+ */
+
+#include "../shell.h"
+#include "../mystring.h"
+#ifdef SHELL
+#include "../error.h"
+#include "../output.h"
+#include "builtins.h"
+#define FILE struct output
+#undef stdout
+#define stdout out1
+#undef stderr
+#define stderr out2
+#define printf out1fmt
+#undef putc
+#define putc(c, file) outc(c, file)
+#undef putchar
+#define putchar(c) out1c(c)
+#define fprintf outfmt
+#define fputs outstr
+#define fwrite(ptr, size, nmemb, file) outbin(ptr, (size) * (nmemb), file)
+#define fflush flushout
+#define INITARGS(argv)
+#define warnx warning
+#define warn(fmt, ...) warning(fmt ": %s", __VA_ARGS__, strerror(errno))
+#define errx(exitstatus, ...) error(__VA_ARGS__)
+
+#else
+#undef NULL
+#include <stdio.h>
+#undef main
+#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
+#endif
+
+#include <unistd.h>
+
+pointer stalloc(int);
+int killjob(const char *, int);
+
+extern char *commandname;
diff --git a/shell_cmds/sh/bltin/echo.c b/shell_cmds/sh/bltin/echo.c
new file mode 100644
index 0000000..1bb64c6
--- /dev/null
+++ b/shell_cmds/sh/bltin/echo.c
@@ -0,0 +1,109 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)echo.c 8.2 (Berkeley) 5/4/95
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/bltin/echo.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * Echo command.
+ */
+
+#define main echocmd
+
+#include "bltin.h"
+
+/* #define eflag 1 */
+
+int
+main(int argc, char *argv[])
+{
+ char **ap;
+ char *p;
+ char c;
+ int count;
+ int nflag = 0;
+#ifndef eflag
+ int eflag = 0;
+#endif
+
+ ap = argv;
+ if (argc)
+ ap++;
+ if ((p = *ap) != NULL) {
+ if (equal(p, "-n")) {
+ nflag++;
+ ap++;
+ } else if (equal(p, "-e")) {
+#ifndef eflag
+ eflag++;
+#endif
+ ap++;
+ }
+ }
+ while ((p = *ap++) != NULL) {
+ while ((c = *p++) != '\0') {
+ if (c == '\\' && eflag) {
+ switch (*p++) {
+ case 'a': c = '\a'; break;
+ case 'b': c = '\b'; break;
+ case 'c': return 0; /* exit */
+ case 'e': c = '\033'; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = '\v'; break;
+ case '\\': break; /* c = '\\' */
+ case '0':
+ c = 0;
+ count = 3;
+ while (--count >= 0 && (unsigned)(*p - '0') < 8)
+ c = (c << 3) + (*p++ - '0');
+ break;
+ default:
+ p--;
+ break;
+ }
+ }
+ putchar(c);
+ }
+ if (*ap)
+ putchar(' ');
+ }
+ if (! nflag)
+ putchar('\n');
+ return 0;
+}
diff --git a/shell_cmds/sh/builtins.def b/shell_cmds/sh/builtins.def
new file mode 100644
index 0000000..39cab13
--- /dev/null
+++ b/shell_cmds/sh/builtins.def
@@ -0,0 +1,96 @@
+#!/bin/sh -
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)builtins.def 8.4 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/builtins.def 319576 2017-06-04 21:02:48Z bdrewery $
+
+#
+# This file lists all the builtin commands. The first column is the name
+# of a C routine.
+# The -j flag specifies that this command is to be excluded from systems
+# without job control.
+# The -h flag specifies that this command is to be excluded from systems
+# based on the NO_HISTORY compile-time symbol.
+# The -n flag specifies that this command can safely be run in the same
+# process when it is the only command in a command substitution. Some
+# commands have special logic defined in safe_builtin().
+# The -s flag specifies that this is a POSIX 'special built-in' command.
+# The rest of the line specifies the command name or names used to run the
+# command. The entry for bltincmd, which is run when the user does not specify
+# a command, must come first.
+#
+# NOTE: bltincmd must come first!
+
+bltincmd -n builtin
+aliascmd alias
+bgcmd -j bg
+bindcmd bind
+breakcmd -s break -s continue
+cdcmd cd chdir
+commandcmd -n command
+dotcmd -s .
+echocmd -n echo
+evalcmd -s eval
+execcmd -s exec
+exitcmd -s exit
+letcmd let
+exportcmd -s export -s readonly
+#exprcmd expr
+falsecmd -n false
+fgcmd -j fg
+freebsd_wordexpcmd freebsd_wordexp
+getoptscmd getopts
+hashcmd hash
+histcmd -h fc
+jobidcmd -n jobid
+jobscmd -n jobs
+killcmd -n kill
+localcmd local
+printfcmd -n printf
+pwdcmd -n pwd
+readcmd read
+returncmd -s return
+setcmd -s set
+setvarcmd setvar
+shiftcmd -s shift
+testcmd -n test [
+timescmd -n -s times
+trapcmd -s trap
+truecmd -n -s : true
+typecmd -n type
+ulimitcmd ulimit
+umaskcmd umask
+unaliascmd unalias
+unsetcmd -s unset
+waitcmd wait
+wordexpcmd wordexp
diff --git a/shell_cmds/sh/cd.c b/shell_cmds/sh/cd.c
new file mode 100644
index 0000000..cf63681
--- /dev/null
+++ b/shell_cmds/sh/cd.c
@@ -0,0 +1,430 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/cd.c 320340 2017-06-25 21:53:08Z jilles $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+
+/*
+ * The cd and pwd commands.
+ */
+
+#include "shell.h"
+#include "var.h"
+#include "nodes.h" /* for jobs.h */
+#include "jobs.h"
+#include "options.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "exec.h"
+#include "redir.h"
+#include "mystring.h"
+#include "show.h"
+#include "cd.h"
+#include "builtins.h"
+
+static int cdlogical(char *);
+static int cdphysical(char *);
+static int docd(char *, int, int);
+static char *getcomponent(char **);
+static char *findcwd(char *);
+static void updatepwd(char *);
+static char *getpwd(void);
+static char *getpwd2(void);
+
+static char *curdir = NULL; /* current working directory */
+
+int
+cdcmd(int argc __unused, char **argv __unused)
+{
+ const char *dest;
+ const char *path;
+ char *p;
+ struct stat statb;
+ int ch, phys, print = 0, getcwderr = 0;
+ int rc;
+ int errno1 = ENOENT;
+
+ phys = Pflag;
+ while ((ch = nextopt("eLP")) != '\0') {
+ switch (ch) {
+ case 'e':
+ getcwderr = 1;
+ break;
+ case 'L':
+ phys = 0;
+ break;
+ case 'P':
+ phys = 1;
+ break;
+ }
+ }
+
+ if (*argptr != NULL && argptr[1] != NULL)
+ error("too many arguments");
+
+ if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL)
+ error("HOME not set");
+ if (*dest == '\0')
+ dest = ".";
+ if (dest[0] == '-' && dest[1] == '\0') {
+ dest = bltinlookup("OLDPWD", 1);
+ if (dest == NULL)
+ error("OLDPWD not set");
+ print = 1;
+ }
+ if (dest[0] == '/' ||
+ (dest[0] == '.' && (dest[1] == '/' || dest[1] == '\0')) ||
+ (dest[0] == '.' && dest[1] == '.' && (dest[2] == '/' || dest[2] == '\0')) ||
+ (path = bltinlookup("CDPATH", 1)) == NULL)
+ path = "";
+ while ((p = padvance(&path, dest)) != NULL) {
+ if (stat(p, &statb) < 0) {
+ if (errno != ENOENT)
+ errno1 = errno;
+ } else if (!S_ISDIR(statb.st_mode))
+ errno1 = ENOTDIR;
+ else {
+ if (!print) {
+ /*
+ * XXX - rethink
+ */
+ if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
+ print = strcmp(p + 2, dest);
+ else
+ print = strcmp(p, dest);
+ }
+ rc = docd(p, print, phys);
+ if (rc >= 0)
+ return getcwderr ? rc : 0;
+ if (errno != ENOENT)
+ errno1 = errno;
+ }
+ }
+ error("%s: %s", dest, strerror(errno1));
+ /*NOTREACHED*/
+ return 0;
+}
+
+
+/*
+ * Actually change the directory. In an interactive shell, print the
+ * directory name if "print" is nonzero.
+ */
+static int
+docd(char *dest, int print, int phys)
+{
+ int rc;
+
+ TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys));
+
+ /* If logical cd fails, fall back to physical. */
+ if ((phys || (rc = cdlogical(dest)) < 0) && (rc = cdphysical(dest)) < 0)
+ return (-1);
+
+ if (print && iflag && curdir) {
+ out1fmt("%s\n", curdir);
+ /*
+ * Ignore write errors to preserve the invariant that the
+ * current directory is changed iff the exit status is 0
+ * (or 1 if -e was given and the full pathname could not be
+ * determined).
+ */
+ flushout(out1);
+ outclearerror(out1);
+ }
+
+ return (rc);
+}
+
+static int
+cdlogical(char *dest)
+{
+ char *p;
+ char *q;
+ char *component;
+ char *path;
+ struct stat statb;
+ int first;
+ int badstat;
+
+ /*
+ * Check each component of the path. If we find a symlink or
+ * something we can't stat, clear curdir to force a getcwd()
+ * next time we get the value of the current directory.
+ */
+ badstat = 0;
+ path = stsavestr(dest);
+ STARTSTACKSTR(p);
+ if (*dest == '/') {
+ STPUTC('/', p);
+ path++;
+ }
+ first = 1;
+ while ((q = getcomponent(&path)) != NULL) {
+ if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0'))
+ continue;
+ if (! first)
+ STPUTC('/', p);
+ first = 0;
+ component = q;
+ STPUTS(q, p);
+ if (equal(component, ".."))
+ continue;
+ STACKSTRNUL(p);
+ if (lstat(stackblock(), &statb) < 0) {
+ badstat = 1;
+ break;
+ }
+ }
+
+ INTOFF;
+ if ((p = findcwd(badstat ? NULL : dest)) == NULL || chdir(p) < 0) {
+ INTON;
+ return (-1);
+ }
+ updatepwd(p);
+ INTON;
+ return (0);
+}
+
+static int
+cdphysical(char *dest)
+{
+ char *p;
+ int rc = 0;
+
+ INTOFF;
+ if (chdir(dest) < 0) {
+ INTON;
+ return (-1);
+ }
+ p = findcwd(NULL);
+ if (p == NULL) {
+ warning("warning: failed to get name of current directory");
+ rc = 1;
+ }
+ updatepwd(p);
+ INTON;
+ return (rc);
+}
+
+/*
+ * Get the next component of the path name pointed to by *path.
+ * This routine overwrites *path and the string pointed to by it.
+ */
+static char *
+getcomponent(char **path)
+{
+ char *p;
+ char *start;
+
+ if ((p = *path) == NULL)
+ return NULL;
+ start = *path;
+ while (*p != '/' && *p != '\0')
+ p++;
+ if (*p == '\0') {
+ *path = NULL;
+ } else {
+ *p++ = '\0';
+ *path = p;
+ }
+ return start;
+}
+
+
+static char *
+findcwd(char *dir)
+{
+ char *new;
+ char *p;
+ char *path;
+
+ /*
+ * If our argument is NULL, we don't know the current directory
+ * any more because we traversed a symbolic link or something
+ * we couldn't stat().
+ */
+ if (dir == NULL || curdir == NULL)
+ return getpwd2();
+ path = stsavestr(dir);
+ STARTSTACKSTR(new);
+ if (*dir != '/') {
+ STPUTS(curdir, new);
+ if (STTOPC(new) == '/')
+ STUNPUTC(new);
+ }
+ while ((p = getcomponent(&path)) != NULL) {
+ if (equal(p, "..")) {
+ while (new > stackblock() && (STUNPUTC(new), *new) != '/');
+ } else if (*p != '\0' && ! equal(p, ".")) {
+ STPUTC('/', new);
+ STPUTS(p, new);
+ }
+ }
+ if (new == stackblock())
+ STPUTC('/', new);
+ STACKSTRNUL(new);
+ return stackblock();
+}
+
+/*
+ * Update curdir (the name of the current directory) in response to a
+ * cd command. We also call hashcd to let the routines in exec.c know
+ * that the current directory has changed.
+ */
+static void
+updatepwd(char *dir)
+{
+ char *prevdir;
+
+ hashcd(); /* update command hash table */
+
+ setvar("PWD", dir, VEXPORT);
+ setvar("OLDPWD", curdir, VEXPORT);
+ prevdir = curdir;
+ curdir = dir ? savestr(dir) : NULL;
+ ckfree(prevdir);
+}
+
+int
+pwdcmd(int argc __unused, char **argv __unused)
+{
+ char *p;
+ int ch, phys;
+
+ phys = Pflag;
+ while ((ch = nextopt("LP")) != '\0') {
+ switch (ch) {
+ case 'L':
+ phys = 0;
+ break;
+ case 'P':
+ phys = 1;
+ break;
+ }
+ }
+
+ if (*argptr != NULL)
+ error("too many arguments");
+
+ if (!phys && getpwd()) {
+ out1str(curdir);
+ out1c('\n');
+ } else {
+ if ((p = getpwd2()) == NULL)
+ error(".: %s", strerror(errno));
+ out1str(p);
+ out1c('\n');
+ }
+
+ return 0;
+}
+
+/*
+ * Get the current directory and cache the result in curdir.
+ */
+static char *
+getpwd(void)
+{
+ char *p;
+
+ if (curdir)
+ return curdir;
+
+ p = getpwd2();
+ if (p != NULL)
+ curdir = savestr(p);
+
+ return curdir;
+}
+
+#define MAXPWD 256
+
+/*
+ * Return the current directory.
+ */
+static char *
+getpwd2(void)
+{
+ char *pwd;
+ int i;
+
+ for (i = MAXPWD;; i *= 2) {
+ pwd = stalloc(i);
+ if (getcwd(pwd, i) != NULL)
+ return pwd;
+ stunalloc(pwd);
+ if (errno != ERANGE)
+ break;
+ }
+
+ return NULL;
+}
+
+/*
+ * Initialize PWD in a new shell.
+ * If the shell is interactive, we need to warn if this fails.
+ */
+void
+pwd_init(int warn)
+{
+ char *pwd;
+ struct stat stdot, stpwd;
+
+ pwd = lookupvar("PWD");
+ if (pwd && *pwd == '/' && stat(".", &stdot) != -1 &&
+ stat(pwd, &stpwd) != -1 &&
+ stdot.st_dev == stpwd.st_dev &&
+ stdot.st_ino == stpwd.st_ino) {
+ if (curdir)
+ ckfree(curdir);
+ curdir = savestr(pwd);
+ }
+ if (getpwd() == NULL && warn)
+ out2fmt_flush("sh: cannot determine working directory\n");
+ setvar("PWD", curdir, VEXPORT);
+}
diff --git a/shell_cmds/sh/cd.h b/shell_cmds/sh/cd.h
new file mode 100644
index 0000000..0745d97
--- /dev/null
+++ b/shell_cmds/sh/cd.h
@@ -0,0 +1,32 @@
+/*-
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * $FreeBSD: head/bin/sh/cd.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+void pwd_init(int);
diff --git a/shell_cmds/sh/error.c b/shell_cmds/sh/error.c
new file mode 100644
index 0000000..7f184ac
--- /dev/null
+++ b/shell_cmds/sh/error.c
@@ -0,0 +1,199 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/error.c 314436 2017-02-28 23:42:47Z imp $");
+
+/*
+ * Errors and exceptions.
+ */
+
+#include "shell.h"
+#include "eval.h"
+#include "main.h"
+#include "options.h"
+#include "output.h"
+#include "error.h"
+#include "nodes.h" /* show.h needs nodes.h */
+#include "show.h"
+#include "trap.h"
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+/*
+ * Code to handle exceptions in C.
+ */
+
+struct jmploc *handler;
+volatile sig_atomic_t exception;
+volatile sig_atomic_t suppressint;
+volatile sig_atomic_t intpending;
+
+
+static void exverror(int, const char *, va_list) __printf0like(2, 0) __dead2;
+
+/*
+ * Called to raise an exception. Since C doesn't include exceptions, we
+ * just do a longjmp to the exception handler. The type of exception is
+ * stored in the global variable "exception".
+ *
+ * Interrupts are disabled; they should be reenabled when the exception is
+ * caught.
+ */
+
+void
+exraise(int e)
+{
+ INTOFF;
+ if (handler == NULL)
+ abort();
+ exception = e;
+ longjmp(handler->loc, 1);
+}
+
+
+/*
+ * Called from trap.c when a SIGINT is received and not suppressed, or when
+ * an interrupt is pending and interrupts are re-enabled using INTON.
+ * (If the user specifies that SIGINT is to be trapped or ignored using the
+ * trap builtin, then this routine is not called.) Suppressint is nonzero
+ * when interrupts are held using the INTOFF macro. If SIGINTs are not
+ * suppressed and the shell is not a root shell, then we want to be
+ * terminated if we get here, as if we were terminated directly by a SIGINT.
+ * Arrange for this here.
+ */
+
+void
+onint(void)
+{
+ sigset_t sigs;
+
+ intpending = 0;
+ sigemptyset(&sigs);
+ sigprocmask(SIG_SETMASK, &sigs, NULL);
+
+ /*
+ * This doesn't seem to be needed, since main() emits a newline.
+ */
+#if 0
+ if (tcgetpgrp(0) == getpid())
+ write(STDERR_FILENO, "\n", 1);
+#endif
+ if (rootshell && iflag)
+ exraise(EXINT);
+ else {
+ signal(SIGINT, SIG_DFL);
+ kill(getpid(), SIGINT);
+ _exit(128 + SIGINT);
+ }
+}
+
+
+static void
+vwarning(const char *msg, va_list ap)
+{
+ if (commandname)
+ outfmt(out2, "%s: ", commandname);
+ else if (arg0)
+ outfmt(out2, "%s: ", arg0);
+ doformat(out2, msg, ap);
+ out2fmt_flush("\n");
+}
+
+
+void
+warning(const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ vwarning(msg, ap);
+ va_end(ap);
+}
+
+
+/*
+ * Exverror is called to raise the error exception. If the first argument
+ * is not NULL then error prints an error message using printf style
+ * formatting. It then raises the error exception.
+ */
+static void
+exverror(int cond, const char *msg, va_list ap)
+{
+ /*
+ * An interrupt trumps an error. Certain places catch error
+ * exceptions or transform them to a plain nonzero exit code
+ * in child processes, and if an error exception can be handled,
+ * an interrupt can be handled as well.
+ *
+ * exraise() will disable interrupts for the exception handler.
+ */
+ FORCEINTON;
+
+#ifdef DEBUG
+ if (msg)
+ TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid()));
+ else
+ TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
+#endif
+ if (msg)
+ vwarning(msg, ap);
+ flushall();
+ exraise(cond);
+}
+
+
+void
+error(const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ exverror(EXERROR, msg, ap);
+ va_end(ap);
+}
+
+
+void
+exerror(int cond, const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ exverror(cond, msg, ap);
+ va_end(ap);
+}
diff --git a/shell_cmds/sh/error.h b/shell_cmds/sh/error.h
new file mode 100644
index 0000000..e962c4f
--- /dev/null
+++ b/shell_cmds/sh/error.h
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)error.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/error.h 319591 2017-06-04 21:58:02Z jilles $
+ */
+
+/*
+ * We enclose jmp_buf in a structure so that we can declare pointers to
+ * jump locations. The global variable handler contains the location to
+ * jump to when an exception occurs, and the global variable exception
+ * contains a code identifying the exception. To implement nested
+ * exception handlers, the user should save the value of handler on entry
+ * to an inner scope, set handler to point to a jmploc structure for the
+ * inner scope, and restore handler on exit from the scope.
+ */
+
+#include <setjmp.h>
+#include <signal.h>
+
+struct jmploc {
+ jmp_buf loc;
+};
+
+extern struct jmploc *handler;
+extern volatile sig_atomic_t exception;
+
+/* exceptions */
+#define EXINT 0 /* SIGINT received */
+#define EXERROR 1 /* a generic error */
+#define EXEXEC 2 /* command execution failed */
+#define EXEXIT 3 /* call exitshell(exitstatus) */
+
+
+/*
+ * These macros allow the user to suspend the handling of interrupt signals
+ * over a period of time. This is similar to SIGHOLD to or sigblock, but
+ * much more efficient and portable. (But hacking the kernel is so much
+ * more fun than worrying about efficiency and portability. :-))
+ */
+
+extern volatile sig_atomic_t suppressint;
+extern volatile sig_atomic_t intpending;
+
+#define INTOFF suppressint++
+#define INTON { if (--suppressint == 0 && intpending) onint(); }
+#define is_int_on() suppressint
+#define SETINTON(s) do { suppressint = (s); if (suppressint == 0 && intpending) onint(); } while (0)
+#define FORCEINTON {suppressint = 0; if (intpending) onint();}
+#define SET_PENDING_INT intpending = 1
+#define CLEAR_PENDING_INT intpending = 0
+#define int_pending() intpending
+
+void exraise(int) __dead2;
+void onint(void) __dead2;
+void warning(const char *, ...) __printflike(1, 2);
+void error(const char *, ...) __printf0like(1, 2) __dead2;
+void exerror(int, const char *, ...) __printf0like(2, 3) __dead2;
+
+
+/*
+ * BSD setjmp saves the signal mask, which violates ANSI C and takes time,
+ * so we use _setjmp instead.
+ */
+
+#define setjmp(jmploc) _setjmp(jmploc)
+#define longjmp(jmploc, val) _longjmp(jmploc, val)
diff --git a/shell_cmds/sh/eval.c b/shell_cmds/sh/eval.c
new file mode 100644
index 0000000..bb5f3cc
--- /dev/null
+++ b/shell_cmds/sh/eval.c
@@ -0,0 +1,1381 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/eval.c 327212 2017-12-26 16:23:18Z jilles $");
+
+#include <paths.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <errno.h>
+
+/*
+ * Evaluate a command.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "syntax.h"
+#include "expand.h"
+#include "parser.h"
+#include "jobs.h"
+#include "eval.h"
+#include "builtins.h"
+#include "options.h"
+#include "exec.h"
+#include "redir.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "show.h"
+#include "mystring.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
+
+
+int evalskip; /* set if we are skipping commands */
+int skipcount; /* number of levels to skip */
+static int loopnest; /* current loop nesting level */
+int funcnest; /* depth of function calls */
+static int builtin_flags; /* evalcommand flags for builtins */
+
+
+char *commandname;
+struct arglist *cmdenviron;
+int exitstatus; /* exit status of last command */
+int oexitstatus; /* saved exit status */
+
+
+static void evalloop(union node *, int);
+static void evalfor(union node *, int);
+static union node *evalcase(union node *);
+static void evalsubshell(union node *, int);
+static void evalredir(union node *, int);
+static void exphere(union node *, struct arglist *);
+static void expredir(union node *);
+static void evalpipe(union node *);
+static int is_valid_fast_cmdsubst(union node *n);
+static void evalcommand(union node *, int, struct backcmd *);
+static void prehash(union node *);
+
+
+/*
+ * Called to reset things after an exception.
+ */
+
+void
+reseteval(void)
+{
+ evalskip = 0;
+ loopnest = 0;
+}
+
+
+/*
+ * The eval command.
+ */
+
+int
+evalcmd(int argc, char **argv)
+{
+ char *p;
+ char *concat;
+ char **ap;
+
+ if (argc > 1) {
+ p = argv[1];
+ if (argc > 2) {
+ STARTSTACKSTR(concat);
+ ap = argv + 2;
+ for (;;) {
+ STPUTS(p, concat);
+ if ((p = *ap++) == NULL)
+ break;
+ STPUTC(' ', concat);
+ }
+ STPUTC('\0', concat);
+ p = grabstackstr(concat);
+ }
+ evalstring(p, builtin_flags);
+ } else
+ exitstatus = 0;
+ return exitstatus;
+}
+
+
+/*
+ * Execute a command or commands contained in a string.
+ */
+
+void
+evalstring(const char *s, int flags)
+{
+ union node *n;
+ struct stackmark smark;
+ int flags_exit;
+ int any;
+
+ flags_exit = flags & EV_EXIT;
+ flags &= ~EV_EXIT;
+ any = 0;
+ setstackmark(&smark);
+ setinputstring(s, 1);
+ while ((n = parsecmd(0)) != NEOF) {
+ if (n != NULL && !nflag) {
+ if (flags_exit && preadateof())
+ evaltree(n, flags | EV_EXIT);
+ else
+ evaltree(n, flags);
+ any = 1;
+ if (evalskip)
+ break;
+ }
+ popstackmark(&smark);
+ setstackmark(&smark);
+ }
+ popfile();
+ popstackmark(&smark);
+ if (!any)
+ exitstatus = 0;
+ if (flags_exit)
+ exraise(EXEXIT);
+}
+
+
+/*
+ * Evaluate a parse tree. The value is left in the global variable
+ * exitstatus.
+ */
+
+void
+evaltree(union node *n, int flags)
+{
+ int do_etest;
+ union node *next;
+ struct stackmark smark;
+
+ setstackmark(&smark);
+ do_etest = 0;
+ if (n == NULL) {
+ TRACE(("evaltree(NULL) called\n"));
+ exitstatus = 0;
+ goto out;
+ }
+ do {
+ next = NULL;
+#ifndef NO_HISTORY
+ displayhist = 1; /* show history substitutions done with fc */
+#endif
+ TRACE(("evaltree(%p: %d) called\n", (void *)n, n->type));
+ switch (n->type) {
+ case NSEMI:
+ evaltree(n->nbinary.ch1, flags & ~EV_EXIT);
+ if (evalskip)
+ goto out;
+ next = n->nbinary.ch2;
+ break;
+ case NAND:
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip || exitstatus != 0) {
+ goto out;
+ }
+ next = n->nbinary.ch2;
+ break;
+ case NOR:
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip || exitstatus == 0)
+ goto out;
+ next = n->nbinary.ch2;
+ break;
+ case NREDIR:
+ evalredir(n, flags);
+ break;
+ case NSUBSHELL:
+ evalsubshell(n, flags);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ case NBACKGND:
+ evalsubshell(n, flags);
+ break;
+ case NIF: {
+ evaltree(n->nif.test, EV_TESTED);
+ if (evalskip)
+ goto out;
+ if (exitstatus == 0)
+ next = n->nif.ifpart;
+ else if (n->nif.elsepart)
+ next = n->nif.elsepart;
+ else
+ exitstatus = 0;
+ break;
+ }
+ case NWHILE:
+ case NUNTIL:
+ evalloop(n, flags & ~EV_EXIT);
+ break;
+ case NFOR:
+ evalfor(n, flags & ~EV_EXIT);
+ break;
+ case NCASE:
+ next = evalcase(n);
+ break;
+ case NCLIST:
+ next = n->nclist.body;
+ break;
+ case NCLISTFALLTHRU:
+ if (n->nclist.body) {
+ evaltree(n->nclist.body, flags & ~EV_EXIT);
+ if (evalskip)
+ goto out;
+ }
+ next = n->nclist.next;
+ break;
+ case NDEFUN:
+ defun(n->narg.text, n->narg.next);
+ exitstatus = 0;
+ break;
+ case NNOT:
+ evaltree(n->nnot.com, EV_TESTED);
+ if (evalskip)
+ goto out;
+ exitstatus = !exitstatus;
+ break;
+
+ case NPIPE:
+ evalpipe(n);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ case NCMD:
+ evalcommand(n, flags, (struct backcmd *)NULL);
+ do_etest = !(flags & EV_TESTED);
+ break;
+ default:
+ out1fmt("Node type = %d\n", n->type);
+ flushout(&output);
+ break;
+ }
+ n = next;
+ popstackmark(&smark);
+ setstackmark(&smark);
+ } while (n != NULL);
+out:
+ popstackmark(&smark);
+ if (pendingsig)
+ dotrap();
+ if (eflag && exitstatus != 0 && do_etest)
+ exitshell(exitstatus);
+ if (flags & EV_EXIT)
+ exraise(EXEXIT);
+}
+
+
+static void
+evalloop(union node *n, int flags)
+{
+ int status;
+
+ loopnest++;
+ status = 0;
+ for (;;) {
+ if (!evalskip)
+ evaltree(n->nbinary.ch1, EV_TESTED);
+ if (evalskip) {
+ if (evalskip == SKIPCONT && --skipcount <= 0) {
+ evalskip = 0;
+ continue;
+ }
+ if (evalskip == SKIPBREAK && --skipcount <= 0)
+ evalskip = 0;
+ if (evalskip == SKIPRETURN)
+ status = exitstatus;
+ break;
+ }
+ if (n->type == NWHILE) {
+ if (exitstatus != 0)
+ break;
+ } else {
+ if (exitstatus == 0)
+ break;
+ }
+ evaltree(n->nbinary.ch2, flags);
+ status = exitstatus;
+ }
+ loopnest--;
+ exitstatus = status;
+}
+
+
+
+static void
+evalfor(union node *n, int flags)
+{
+ struct arglist arglist;
+ union node *argp;
+ int i;
+ int status;
+
+ emptyarglist(&arglist);
+ for (argp = n->nfor.args ; argp ; argp = argp->narg.next) {
+ oexitstatus = exitstatus;
+ expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ }
+
+ loopnest++;
+ status = 0;
+ for (i = 0; i < arglist.count; i++) {
+ setvar(n->nfor.var, arglist.args[i], 0);
+ evaltree(n->nfor.body, flags);
+ status = exitstatus;
+ if (evalskip) {
+ if (evalskip == SKIPCONT && --skipcount <= 0) {
+ evalskip = 0;
+ continue;
+ }
+ if (evalskip == SKIPBREAK && --skipcount <= 0)
+ evalskip = 0;
+ break;
+ }
+ }
+ loopnest--;
+ exitstatus = status;
+}
+
+
+/*
+ * Evaluate a case statement, returning the selected tree.
+ *
+ * The exit status needs care to get right.
+ */
+
+static union node *
+evalcase(union node *n)
+{
+ union node *cp;
+ union node *patp;
+ struct arglist arglist;
+
+ emptyarglist(&arglist);
+ oexitstatus = exitstatus;
+ expandarg(n->ncase.expr, &arglist, EXP_TILDE);
+ for (cp = n->ncase.cases ; cp ; cp = cp->nclist.next) {
+ for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) {
+ if (casematch(patp, arglist.args[0])) {
+ while (cp->nclist.next &&
+ cp->type == NCLISTFALLTHRU &&
+ cp->nclist.body == NULL)
+ cp = cp->nclist.next;
+ if (cp->nclist.next &&
+ cp->type == NCLISTFALLTHRU)
+ return (cp);
+ if (cp->nclist.body == NULL)
+ exitstatus = 0;
+ return (cp->nclist.body);
+ }
+ }
+ }
+ exitstatus = 0;
+ return (NULL);
+}
+
+
+
+/*
+ * Kick off a subshell to evaluate a tree.
+ */
+
+static void
+evalsubshell(union node *n, int flags)
+{
+ struct job *jp;
+ int backgnd = (n->type == NBACKGND);
+
+ oexitstatus = exitstatus;
+ expredir(n->nredir.redirect);
+ if ((!backgnd && flags & EV_EXIT && !have_traps()) ||
+ forkshell(jp = makejob(n, 1), n, backgnd) == 0) {
+ if (backgnd)
+ flags &=~ EV_TESTED;
+ redirect(n->nredir.redirect, 0);
+ evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */
+ } else if (! backgnd) {
+ INTOFF;
+ exitstatus = waitforjob(jp, (int *)NULL);
+ INTON;
+ } else
+ exitstatus = 0;
+}
+
+
+/*
+ * Evaluate a redirected compound command.
+ */
+
+static void
+evalredir(union node *n, int flags)
+{
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ volatile int in_redirect = 1;
+
+ oexitstatus = exitstatus;
+ expredir(n->nredir.redirect);
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ int e;
+
+ handler = savehandler;
+ e = exception;
+ popredir();
+ if (e == EXERROR || e == EXEXEC) {
+ if (in_redirect) {
+ exitstatus = 2;
+ FORCEINTON;
+ return;
+ }
+ }
+ longjmp(handler->loc, 1);
+ } else {
+ INTOFF;
+ handler = &jmploc;
+ redirect(n->nredir.redirect, REDIR_PUSH);
+ in_redirect = 0;
+ INTON;
+ evaltree(n->nredir.n, flags);
+ }
+ INTOFF;
+ handler = savehandler;
+ popredir();
+ INTON;
+}
+
+
+static void
+exphere(union node *redir, struct arglist *fn)
+{
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ struct localvar *savelocalvars;
+ int need_longjmp = 0;
+ unsigned char saveoptreset;
+
+ redir->nhere.expdoc = "";
+ savelocalvars = localvars;
+ localvars = NULL;
+ saveoptreset = shellparam.reset;
+ forcelocal++;
+ savehandler = handler;
+ if (setjmp(jmploc.loc))
+ need_longjmp = exception != EXERROR && exception != EXEXEC;
+ else {
+ handler = &jmploc;
+ expandarg(redir->nhere.doc, fn, 0);
+ redir->nhere.expdoc = fn->args[0];
+ INTOFF;
+ }
+ handler = savehandler;
+ forcelocal--;
+ poplocalvars();
+ localvars = savelocalvars;
+ shellparam.reset = saveoptreset;
+ if (need_longjmp)
+ longjmp(handler->loc, 1);
+ INTON;
+}
+
+
+/*
+ * Compute the names of the files in a redirection list.
+ */
+
+static void
+expredir(union node *n)
+{
+ union node *redir;
+
+ for (redir = n ; redir ; redir = redir->nfile.next) {
+ struct arglist fn;
+ emptyarglist(&fn);
+ switch (redir->type) {
+ case NFROM:
+ case NTO:
+ case NFROMTO:
+ case NAPPEND:
+ case NCLOBBER:
+ expandarg(redir->nfile.fname, &fn, EXP_TILDE);
+ redir->nfile.expfname = fn.args[0];
+ break;
+ case NFROMFD:
+ case NTOFD:
+ if (redir->ndup.vname) {
+ expandarg(redir->ndup.vname, &fn, EXP_TILDE);
+ fixredir(redir, fn.args[0], 1);
+ }
+ break;
+ case NXHERE:
+ exphere(redir, &fn);
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Evaluate a pipeline. All the processes in the pipeline are children
+ * of the process creating the pipeline. (This differs from some versions
+ * of the shell, which make the last process in a pipeline the parent
+ * of all the rest.)
+ */
+
+static void
+evalpipe(union node *n)
+{
+ struct job *jp;
+ struct nodelist *lp;
+ int pipelen;
+ int prevfd;
+ int pip[2];
+
+ TRACE(("evalpipe(%p) called\n", (void *)n));
+ pipelen = 0;
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next)
+ pipelen++;
+ INTOFF;
+ jp = makejob(n, pipelen);
+ prevfd = -1;
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+ prehash(lp->n);
+ pip[1] = -1;
+ if (lp->next) {
+ if (pipe(pip) < 0) {
+ if (prevfd >= 0)
+ close(prevfd);
+ error("Pipe call failed: %s", strerror(errno));
+ }
+ }
+ if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) {
+ INTON;
+ if (prevfd > 0) {
+ dup2(prevfd, 0);
+ close(prevfd);
+ }
+ if (pip[1] >= 0) {
+ if (!(prevfd >= 0 && pip[0] == 0))
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ }
+ evaltree(lp->n, EV_EXIT);
+ }
+ if (prevfd >= 0)
+ close(prevfd);
+ prevfd = pip[0];
+ if (pip[1] != -1)
+ close(pip[1]);
+ }
+ INTON;
+ if (n->npipe.backgnd == 0) {
+ INTOFF;
+ exitstatus = waitforjob(jp, (int *)NULL);
+ TRACE(("evalpipe: job done exit status %d\n", exitstatus));
+ INTON;
+ } else
+ exitstatus = 0;
+}
+
+
+
+static int
+is_valid_fast_cmdsubst(union node *n)
+{
+
+ return (n->type == NCMD);
+}
+
+/*
+ * Execute a command inside back quotes. If it's a builtin command, we
+ * want to save its output in a block obtained from malloc. Otherwise
+ * we fork off a subprocess and get the output of the command via a pipe.
+ * Should be called with interrupts off.
+ */
+
+void
+evalbackcmd(union node *n, struct backcmd *result)
+{
+ int pip[2];
+ struct job *jp;
+ struct stackmark smark;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ struct localvar *savelocalvars;
+ unsigned char saveoptreset;
+
+ result->fd = -1;
+ result->buf = NULL;
+ result->nleft = 0;
+ result->jp = NULL;
+ if (n == NULL) {
+ exitstatus = 0;
+ return;
+ }
+ setstackmark(&smark);
+ exitstatus = oexitstatus;
+ if (is_valid_fast_cmdsubst(n)) {
+ savelocalvars = localvars;
+ localvars = NULL;
+ saveoptreset = shellparam.reset;
+ forcelocal++;
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ if (exception == EXERROR || exception == EXEXEC)
+ exitstatus = 2;
+ else if (exception != 0) {
+ handler = savehandler;
+ forcelocal--;
+ poplocalvars();
+ localvars = savelocalvars;
+ shellparam.reset = saveoptreset;
+ longjmp(handler->loc, 1);
+ }
+ } else {
+ handler = &jmploc;
+ evalcommand(n, EV_BACKCMD, result);
+ }
+ handler = savehandler;
+ forcelocal--;
+ poplocalvars();
+ localvars = savelocalvars;
+ shellparam.reset = saveoptreset;
+ } else {
+ if (pipe(pip) < 0)
+ error("Pipe call failed: %s", strerror(errno));
+ jp = makejob(n, 1);
+ if (forkshell(jp, n, FORK_NOJOB) == 0) {
+ FORCEINTON;
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ evaltree(n, EV_EXIT);
+ }
+ close(pip[1]);
+ result->fd = pip[0];
+ result->jp = jp;
+ }
+ popstackmark(&smark);
+ TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
+ result->fd, result->buf, result->nleft, result->jp));
+}
+
+static int
+mustexpandto(const char *argtext, const char *mask)
+{
+ for (;;) {
+ if (*argtext == CTLQUOTEMARK || *argtext == CTLQUOTEEND) {
+ argtext++;
+ continue;
+ }
+ if (*argtext == CTLESC)
+ argtext++;
+ else if (BASESYNTAX[(int)*argtext] == CCTL)
+ return (0);
+ if (*argtext != *mask)
+ return (0);
+ if (*argtext == '\0')
+ return (1);
+ argtext++;
+ mask++;
+ }
+}
+
+static int
+isdeclarationcmd(struct narg *arg)
+{
+ int have_command = 0;
+
+ if (arg == NULL)
+ return (0);
+ while (mustexpandto(arg->text, "command")) {
+ have_command = 1;
+ arg = &arg->next->narg;
+ if (arg == NULL)
+ return (0);
+ /*
+ * To also allow "command -p" and "command --" as part of
+ * a declaration command, add code here.
+ * We do not do this, as ksh does not do it either and it
+ * is not required by POSIX.
+ */
+ }
+ return (mustexpandto(arg->text, "export") ||
+ mustexpandto(arg->text, "readonly") ||
+ (mustexpandto(arg->text, "local") &&
+ (have_command || !isfunc("local"))));
+}
+
+static void
+xtracecommand(struct arglist *varlist, int argc, char **argv)
+{
+ char sep = 0;
+ const char *text, *p, *ps4;
+ int i;
+
+ ps4 = expandstr(ps4val());
+ out2str(ps4 != NULL ? ps4 : ps4val());
+ for (i = 0; i < varlist->count; i++) {
+ text = varlist->args[i];
+ if (sep != 0)
+ out2c(' ');
+ p = strchr(text, '=');
+ if (p != NULL) {
+ p++;
+ outbin(text, p - text, out2);
+ out2qstr(p);
+ } else
+ out2qstr(text);
+ sep = ' ';
+ }
+ for (i = 0; i < argc; i++) {
+ text = argv[i];
+ if (sep != 0)
+ out2c(' ');
+ out2qstr(text);
+ sep = ' ';
+ }
+ out2c('\n');
+ flushout(&errout);
+}
+
+/*
+ * Check if a builtin can safely be executed in the same process,
+ * even though it should be in a subshell (command substitution).
+ * Note that jobid, jobs, times and trap can show information not
+ * available in a child process; this is deliberate.
+ * The arguments should already have been expanded.
+ */
+static int
+safe_builtin(int idx, int argc, char **argv)
+{
+ /* Generated from builtins.def. */
+ if (safe_builtin_always(idx))
+ return (1);
+ if (idx == EXPORTCMD || idx == TRAPCMD || idx == ULIMITCMD ||
+ idx == UMASKCMD)
+ return (argc <= 1 || (argc == 2 && argv[1][0] == '-'));
+ if (idx == SETCMD)
+ return (argc <= 1 || (argc == 2 && (argv[1][0] == '-' ||
+ argv[1][0] == '+') && argv[1][1] == 'o' &&
+ argv[1][2] == '\0'));
+ return (0);
+}
+
+/*
+ * Execute a simple command.
+ * Note: This may or may not return if (flags & EV_EXIT).
+ */
+
+static void
+evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
+{
+ union node *argp;
+ struct arglist arglist;
+ struct arglist varlist;
+ char **argv;
+ int argc;
+ char **envp;
+ int varflag;
+ int mode;
+ int pip[2];
+ struct cmdentry cmdentry;
+ struct job *jp;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ char *savecmdname;
+ struct shparam saveparam;
+ struct localvar *savelocalvars;
+ struct parsefile *savetopfile;
+ volatile int e;
+ char *lastarg;
+ int signaled;
+ int do_clearcmdentry;
+ const char *path = pathval();
+ int i;
+
+ /* First expand the arguments. */
+ TRACE(("evalcommand(%p, %d) called\n", (void *)cmd, flags));
+ emptyarglist(&arglist);
+ emptyarglist(&varlist);
+ varflag = 1;
+ jp = NULL;
+ do_clearcmdentry = 0;
+ oexitstatus = exitstatus;
+ exitstatus = 0;
+ /* Add one slot at the beginning for tryexec(). */
+ appendarglist(&arglist, nullstr);
+ for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
+ if (varflag && isassignment(argp->narg.text)) {
+ expandarg(argp, varflag == 1 ? &varlist : &arglist,
+ EXP_VARTILDE);
+ continue;
+ } else if (varflag == 1)
+ varflag = isdeclarationcmd(&argp->narg) ? 2 : 0;
+ expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
+ }
+ appendarglist(&arglist, nullstr);
+ expredir(cmd->ncmd.redirect);
+ argc = arglist.count - 2;
+ argv = &arglist.args[1];
+
+ argv[argc] = NULL;
+ lastarg = NULL;
+ if (iflag && funcnest == 0 && argc > 0)
+ lastarg = argv[argc - 1];
+
+ /* Print the command if xflag is set. */
+ if (xflag)
+ xtracecommand(&varlist, argc, argv);
+
+ /* Now locate the command. */
+ if (argc == 0) {
+ /* Variable assignment(s) without command */
+ cmdentry.cmdtype = CMDBUILTIN;
+ cmdentry.u.index = BLTINCMD;
+ cmdentry.special = 0;
+ } else {
+ static const char PATH[] = "PATH=";
+ int cmd_flags = 0, bltinonly = 0;
+
+ /*
+ * Modify the command lookup path, if a PATH= assignment
+ * is present
+ */
+ for (i = 0; i < varlist.count; i++)
+ if (strncmp(varlist.args[i], PATH, sizeof(PATH) - 1) == 0) {
+ path = varlist.args[i] + sizeof(PATH) - 1;
+ /*
+ * On `PATH=... command`, we need to make
+ * sure that the command isn't using the
+ * non-updated hash table of the outer PATH
+ * setting and we need to make sure that
+ * the hash table isn't filled with items
+ * from the temporary setting.
+ *
+ * It would be better to forbit using and
+ * updating the table while this command
+ * runs, by the command finding mechanism
+ * is heavily integrated with hash handling,
+ * so we just delete the hash before and after
+ * the command runs. Partly deleting like
+ * changepatch() does doesn't seem worth the
+ * bookinging effort, since most such runs add
+ * directories in front of the new PATH.
+ */
+ clearcmdentry();
+ do_clearcmdentry = 1;
+ }
+
+ for (;;) {
+ if (bltinonly) {
+ cmdentry.u.index = find_builtin(*argv, &cmdentry.special);
+ if (cmdentry.u.index < 0) {
+ cmdentry.u.index = BLTINCMD;
+ argv--;
+ argc++;
+ break;
+ }
+ } else
+ find_command(argv[0], &cmdentry, cmd_flags, path);
+ /* implement the bltin and command builtins here */
+ if (cmdentry.cmdtype != CMDBUILTIN)
+ break;
+ if (cmdentry.u.index == BLTINCMD) {
+ if (argc == 1)
+ break;
+ argv++;
+ argc--;
+ bltinonly = 1;
+ } else if (cmdentry.u.index == COMMANDCMD) {
+ if (argc == 1)
+ break;
+ if (!strcmp(argv[1], "-p")) {
+ if (argc == 2)
+ break;
+ if (argv[2][0] == '-') {
+ if (strcmp(argv[2], "--"))
+ break;
+ if (argc == 3)
+ break;
+ argv += 3;
+ argc -= 3;
+ } else {
+ argv += 2;
+ argc -= 2;
+ }
+ path = _PATH_STDPATH;
+ clearcmdentry();
+ do_clearcmdentry = 1;
+ } else if (!strcmp(argv[1], "--")) {
+ if (argc == 2)
+ break;
+ argv += 2;
+ argc -= 2;
+ } else if (argv[1][0] == '-')
+ break;
+ else {
+ argv++;
+ argc--;
+ }
+ cmd_flags |= DO_NOFUNC;
+ bltinonly = 0;
+ } else
+ break;
+ }
+ /*
+ * Special builtins lose their special properties when
+ * called via 'command'.
+ */
+ if (cmd_flags & DO_NOFUNC)
+ cmdentry.special = 0;
+ }
+
+ /* Fork off a child process if necessary. */
+ if (((cmdentry.cmdtype == CMDNORMAL || cmdentry.cmdtype == CMDUNKNOWN)
+ && ((flags & EV_EXIT) == 0 || have_traps()))
+ || ((flags & EV_BACKCMD) != 0
+ && (cmdentry.cmdtype != CMDBUILTIN ||
+ !safe_builtin(cmdentry.u.index, argc, argv)))) {
+ jp = makejob(cmd, 1);
+ mode = FORK_FG;
+ if (flags & EV_BACKCMD) {
+ mode = FORK_NOJOB;
+ if (pipe(pip) < 0)
+ error("Pipe call failed: %s", strerror(errno));
+ }
+ if (cmdentry.cmdtype == CMDNORMAL &&
+ cmd->ncmd.redirect == NULL &&
+ varlist.count == 0 &&
+ (mode == FORK_FG || mode == FORK_NOJOB) &&
+ !disvforkset() && !iflag && !mflag) {
+ vforkexecshell(jp, argv, environment(), path,
+ cmdentry.u.index, flags & EV_BACKCMD ? pip : NULL);
+ goto parent;
+ }
+ if (forkshell(jp, cmd, mode) != 0)
+ goto parent; /* at end of routine */
+ if (flags & EV_BACKCMD) {
+ FORCEINTON;
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ flags &= ~EV_BACKCMD;
+ }
+ flags |= EV_EXIT;
+ }
+
+ /* This is the child process if a fork occurred. */
+ /* Execute the command. */
+ if (cmdentry.cmdtype == CMDFUNCTION) {
+#ifdef DEBUG
+ trputs("Shell function: "); trargs(argv);
+#endif
+ saveparam = shellparam;
+ shellparam.malloc = 0;
+ shellparam.reset = 1;
+ shellparam.nparam = argc - 1;
+ shellparam.p = argv + 1;
+ shellparam.optp = NULL;
+ shellparam.optnext = NULL;
+ INTOFF;
+ savelocalvars = localvars;
+ localvars = NULL;
+ reffunc(cmdentry.u.func);
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ popredir();
+ unreffunc(cmdentry.u.func);
+ poplocalvars();
+ localvars = savelocalvars;
+ freeparam(&shellparam);
+ shellparam = saveparam;
+ funcnest--;
+ handler = savehandler;
+ longjmp(handler->loc, 1);
+ }
+ handler = &jmploc;
+ funcnest++;
+ redirect(cmd->ncmd.redirect, REDIR_PUSH);
+ INTON;
+ for (i = 0; i < varlist.count; i++)
+ mklocal(varlist.args[i]);
+ exitstatus = oexitstatus;
+ evaltree(getfuncnode(cmdentry.u.func),
+ flags & (EV_TESTED | EV_EXIT));
+ INTOFF;
+ unreffunc(cmdentry.u.func);
+ poplocalvars();
+ localvars = savelocalvars;
+ freeparam(&shellparam);
+ shellparam = saveparam;
+ handler = savehandler;
+ funcnest--;
+ popredir();
+ INTON;
+ if (evalskip == SKIPRETURN) {
+ evalskip = 0;
+ skipcount = 0;
+ }
+ if (jp)
+ exitshell(exitstatus);
+ } else if (cmdentry.cmdtype == CMDBUILTIN) {
+#ifdef DEBUG
+ trputs("builtin command: "); trargs(argv);
+#endif
+ mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH;
+ if (flags == EV_BACKCMD) {
+ memout.nextc = memout.buf;
+ mode |= REDIR_BACKQ;
+ }
+ savecmdname = commandname;
+ savetopfile = getcurrentfile();
+ cmdenviron = &varlist;
+ e = -1;
+ savehandler = handler;
+ if (setjmp(jmploc.loc)) {
+ e = exception;
+ if (e == EXINT)
+ exitstatus = SIGINT+128;
+ else if (e != EXEXIT)
+ exitstatus = 2;
+ goto cmddone;
+ }
+ handler = &jmploc;
+ redirect(cmd->ncmd.redirect, mode);
+ outclearerror(out1);
+ /*
+ * If there is no command word, redirection errors should
+ * not be fatal but assignment errors should.
+ */
+ if (argc == 0)
+ cmdentry.special = 1;
+ listsetvar(cmdenviron, cmdentry.special ? 0 : VNOSET);
+ if (argc > 0)
+ bltinsetlocale();
+ commandname = argv[0];
+ argptr = argv + 1;
+ nextopt_optptr = NULL; /* initialize nextopt */
+ builtin_flags = flags;
+ exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv);
+ flushall();
+ if (outiserror(out1)) {
+ warning("write error on stdout");
+ if (exitstatus == 0 || exitstatus == 1)
+ exitstatus = 2;
+ }
+cmddone:
+ if (argc > 0)
+ bltinunsetlocale();
+ cmdenviron = NULL;
+ out1 = &output;
+ out2 = &errout;
+ freestdout();
+ handler = savehandler;
+ commandname = savecmdname;
+ if (jp)
+ exitshell(exitstatus);
+ if (flags == EV_BACKCMD) {
+ backcmd->buf = memout.buf;
+ backcmd->nleft = memout.buf != NULL ?
+ memout.nextc - memout.buf : 0;
+ memout.buf = NULL;
+ memout.nextc = NULL;
+ memout.bufend = NULL;
+ memout.bufsize = 64;
+ }
+ if (cmdentry.u.index != EXECCMD)
+ popredir();
+ if (e != -1) {
+ if ((e != EXERROR && e != EXEXEC)
+ || cmdentry.special)
+ exraise(e);
+ popfilesupto(savetopfile);
+ if (flags != EV_BACKCMD)
+ FORCEINTON;
+ }
+ } else {
+#ifdef DEBUG
+ trputs("normal command: "); trargs(argv);
+#endif
+ redirect(cmd->ncmd.redirect, 0);
+ for (i = 0; i < varlist.count; i++)
+ setvareq(varlist.args[i], VEXPORT|VSTACK);
+ envp = environment();
+ shellexec(argv, envp, path, cmdentry.u.index);
+ /*NOTREACHED*/
+ }
+ goto out;
+
+parent: /* parent process gets here (if we forked) */
+ if (mode == FORK_FG) { /* argument to fork */
+ INTOFF;
+ exitstatus = waitforjob(jp, &signaled);
+ INTON;
+ if (iflag && loopnest > 0 && signaled) {
+ evalskip = SKIPBREAK;
+ skipcount = loopnest;
+ }
+ } else if (mode == FORK_NOJOB) {
+ backcmd->fd = pip[0];
+ close(pip[1]);
+ backcmd->jp = jp;
+ }
+
+out:
+ if (lastarg)
+ setvar("_", lastarg, 0);
+ if (do_clearcmdentry)
+ clearcmdentry();
+}
+
+
+
+/*
+ * Search for a command. This is called before we fork so that the
+ * location of the command will be available in the parent as well as
+ * the child. The check for "goodname" is an overly conservative
+ * check that the name will not be subject to expansion.
+ */
+
+static void
+prehash(union node *n)
+{
+ struct cmdentry entry;
+
+ if (n && n->type == NCMD && n->ncmd.args)
+ if (goodname(n->ncmd.args->narg.text))
+ find_command(n->ncmd.args->narg.text, &entry, 0,
+ pathval());
+}
+
+
+
+/*
+ * Builtin commands. Builtin commands whose functions are closely
+ * tied to evaluation are implemented here.
+ */
+
+/*
+ * No command given, a bltin command with no arguments, or a bltin command
+ * with an invalid name.
+ */
+
+int
+bltincmd(int argc, char **argv)
+{
+ if (argc > 1) {
+ out2fmt_flush("%s: not found\n", argv[1]);
+ return 127;
+ }
+ /*
+ * Preserve exitstatus of a previous possible command substitution
+ * as POSIX mandates
+ */
+ return exitstatus;
+}
+
+
+/*
+ * Handle break and continue commands. Break, continue, and return are
+ * all handled by setting the evalskip flag. The evaluation routines
+ * above all check this flag, and if it is set they start skipping
+ * commands rather than executing them. The variable skipcount is
+ * the number of loops to break/continue, or the number of function
+ * levels to return. (The latter is always 1.) It should probably
+ * be an error to break out of more loops than exist, but it isn't
+ * in the standard shell so we don't make it one here.
+ */
+
+int
+breakcmd(int argc, char **argv)
+{
+ long n;
+ char *end;
+
+ if (argc > 1) {
+ /* Allow arbitrarily large numbers. */
+ n = strtol(argv[1], &end, 10);
+ if (!is_digit(argv[1][0]) || *end != '\0')
+ error("Illegal number: %s", argv[1]);
+ } else
+ n = 1;
+ if (n > loopnest)
+ n = loopnest;
+ if (n > 0) {
+ evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK;
+ skipcount = n;
+ }
+ return 0;
+}
+
+/*
+ * The `command' command.
+ */
+int
+commandcmd(int argc __unused, char **argv __unused)
+{
+ const char *path;
+ int ch;
+ int cmd = -1;
+
+ path = bltinlookup("PATH", 1);
+
+ while ((ch = nextopt("pvV")) != '\0') {
+ switch (ch) {
+ case 'p':
+ path = _PATH_STDPATH;
+ break;
+ case 'v':
+ cmd = TYPECMD_SMALLV;
+ break;
+ case 'V':
+ cmd = TYPECMD_BIGV;
+ break;
+ }
+ }
+
+ if (cmd != -1) {
+ if (*argptr == NULL || argptr[1] != NULL)
+ error("wrong number of arguments");
+ return typecmd_impl(2, argptr - 1, cmd, path);
+ }
+ if (*argptr != NULL)
+ error("commandcmd bad call");
+
+ /*
+ * Do nothing successfully if no command was specified;
+ * ksh also does this.
+ */
+ return 0;
+}
+
+
+/*
+ * The return command.
+ */
+
+int
+returncmd(int argc, char **argv)
+{
+ int ret = argc > 1 ? number(argv[1]) : oexitstatus;
+
+ evalskip = SKIPRETURN;
+ skipcount = 1;
+ return ret;
+}
+
+
+int
+falsecmd(int argc __unused, char **argv __unused)
+{
+ return 1;
+}
+
+
+int
+truecmd(int argc __unused, char **argv __unused)
+{
+ return 0;
+}
+
+
+int
+execcmd(int argc, char **argv)
+{
+ int i;
+
+ /*
+ * Because we have historically not supported any options,
+ * only treat "--" specially.
+ */
+ if (argc > 1 && strcmp(argv[1], "--") == 0)
+ argc--, argv++;
+ if (argc > 1) {
+ iflag = 0; /* exit on error */
+ mflag = 0;
+ optschanged();
+ for (i = 0; i < cmdenviron->count; i++)
+ setvareq(cmdenviron->args[i], VEXPORT|VSTACK);
+ shellexec(argv + 1, environment(), pathval(), 0);
+
+ }
+ return 0;
+}
+
+
+int
+timescmd(int argc __unused, char **argv __unused)
+{
+ struct rusage ru;
+ long shumins, shsmins, chumins, chsmins;
+ double shusecs, shssecs, chusecs, chssecs;
+
+ if (getrusage(RUSAGE_SELF, &ru) < 0)
+ return 1;
+ shumins = ru.ru_utime.tv_sec / 60;
+ shusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
+ shsmins = ru.ru_stime.tv_sec / 60;
+ shssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
+ if (getrusage(RUSAGE_CHILDREN, &ru) < 0)
+ return 1;
+ chumins = ru.ru_utime.tv_sec / 60;
+ chusecs = ru.ru_utime.tv_sec % 60 + ru.ru_utime.tv_usec / 1000000.;
+ chsmins = ru.ru_stime.tv_sec / 60;
+ chssecs = ru.ru_stime.tv_sec % 60 + ru.ru_stime.tv_usec / 1000000.;
+ out1fmt("%ldm%.3fs %ldm%.3fs\n%ldm%.3fs %ldm%.3fs\n", shumins,
+ shusecs, shsmins, shssecs, chumins, chusecs, chsmins, chssecs);
+ return 0;
+}
diff --git a/shell_cmds/sh/eval.h b/shell_cmds/sh/eval.h
new file mode 100644
index 0000000..18b39f9
--- /dev/null
+++ b/shell_cmds/sh/eval.h
@@ -0,0 +1,70 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)eval.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/eval.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+extern char *commandname; /* currently executing command */
+extern int exitstatus; /* exit status of last command */
+extern int oexitstatus; /* saved exit status */
+extern struct arglist *cmdenviron; /* environment for builtin command */
+
+
+struct backcmd { /* result of evalbackcmd */
+ int fd; /* file descriptor to read from */
+ char *buf; /* buffer */
+ int nleft; /* number of chars in buffer */
+ struct job *jp; /* job structure for command */
+};
+
+void reseteval(void);
+
+/* flags in argument to evaltree/evalstring */
+#define EV_EXIT 01 /* exit after evaluating tree */
+#define EV_TESTED 02 /* exit status is checked; ignore -e flag */
+#define EV_BACKCMD 04 /* command executing within back quotes */
+
+void evalstring(const char *, int);
+union node; /* BLETCH for ansi C */
+void evaltree(union node *, int);
+void evalbackcmd(union node *, struct backcmd *);
+
+/* in_function returns nonzero if we are currently evaluating a function */
+#define in_function() funcnest
+extern int funcnest;
+extern int evalskip;
+extern int skipcount;
+
+/* reasons for skipping commands (see comment on breakcmd routine) */
+#define SKIPBREAK 1
+#define SKIPCONT 2
+#define SKIPRETURN 3
diff --git a/shell_cmds/sh/exec.c b/shell_cmds/sh/exec.c
new file mode 100644
index 0000000..ae3cf6e
--- /dev/null
+++ b/shell_cmds/sh/exec.c
@@ -0,0 +1,780 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/exec.c 317882 2017-05-06 13:28:42Z jilles $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+
+/*
+ * When commands are first encountered, they are entered in a hash table.
+ * This ensures that a full path search will not have to be done for them
+ * on each invocation.
+ *
+ * We should investigate converting to a linear search, even though that
+ * would make the command name "hash" a misnomer.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "parser.h"
+#include "redir.h"
+#include "eval.h"
+#include "exec.h"
+#include "builtins.h"
+#include "var.h"
+#include "options.h"
+#include "input.h"
+#include "output.h"
+#include "syntax.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "show.h"
+#include "jobs.h"
+#include "alias.h"
+
+
+#ifdef __APPLE__
+#define eaccess(path, mode) faccessat(AT_FDCWD, path, mode, AT_EACCESS)
+#endif /* __APPLE__ */
+
+#define CMDTABLESIZE 31 /* should be prime */
+
+
+
+struct tblentry {
+ struct tblentry *next; /* next entry in hash chain */
+ union param param; /* definition of builtin function */
+ int special; /* flag for special builtin commands */
+ signed char cmdtype; /* index identifying command */
+ char cmdname[]; /* name of command */
+};
+
+
+static struct tblentry *cmdtable[CMDTABLESIZE];
+static int cmdtable_cd = 0; /* cmdtable contains cd-dependent entries */
+int exerrno = 0; /* Last exec error */
+
+
+static void tryexec(char *, char **, char **);
+static void printentry(struct tblentry *, int);
+static struct tblentry *cmdlookup(const char *, int);
+static void delete_cmd_entry(void);
+static void addcmdentry(const char *, struct cmdentry *);
+
+
+
+/*
+ * Exec a program. Never returns. If you change this routine, you may
+ * have to change the find_command routine as well.
+ *
+ * The argv array may be changed and element argv[-1] should be writable.
+ */
+
+void
+shellexec(char **argv, char **envp, const char *path, int idx)
+{
+ char *cmdname;
+ int e;
+
+ if (strchr(argv[0], '/') != NULL) {
+ tryexec(argv[0], argv, envp);
+ e = errno;
+ } else {
+ e = ENOENT;
+ while ((cmdname = padvance(&path, argv[0])) != NULL) {
+ if (--idx < 0 && pathopt == NULL) {
+ tryexec(cmdname, argv, envp);
+ if (errno != ENOENT && errno != ENOTDIR)
+ e = errno;
+ if (e == ENOEXEC)
+ break;
+ }
+ stunalloc(cmdname);
+ }
+ }
+
+ /* Map to POSIX errors */
+ if (e == ENOENT || e == ENOTDIR) {
+ exerrno = 127;
+ exerror(EXEXEC, "%s: not found", argv[0]);
+ } else {
+ exerrno = 126;
+ exerror(EXEXEC, "%s: %s", argv[0], strerror(e));
+ }
+}
+
+
+static void
+tryexec(char *cmd, char **argv, char **envp)
+{
+ int e, in;
+ ssize_t n;
+ char buf[256];
+
+ execve(cmd, argv, envp);
+ e = errno;
+ if (e == ENOEXEC) {
+ INTOFF;
+ in = open(cmd, O_RDONLY | O_NONBLOCK);
+ if (in != -1) {
+ n = pread(in, buf, sizeof buf, 0);
+ close(in);
+ if (n > 0 && memchr(buf, '\0', n) != NULL) {
+ errno = ENOEXEC;
+ return;
+ }
+ }
+ *argv = cmd;
+ *--argv = __DECONST(char *, _PATH_BSHELL);
+ execve(_PATH_BSHELL, argv, envp);
+ }
+ errno = e;
+}
+
+/*
+ * Do a path search. The variable path (passed by reference) should be
+ * set to the start of the path before the first call; padvance will update
+ * this value as it proceeds. Successive calls to padvance will return
+ * the possible path expansions in sequence. If an option (indicated by
+ * a percent sign) appears in the path entry then the global variable
+ * pathopt will be set to point to it; otherwise pathopt will be set to
+ * NULL.
+ */
+
+const char *pathopt;
+
+char *
+padvance(const char **path, const char *name)
+{
+ const char *p, *start;
+ char *q;
+ size_t len, namelen;
+
+ if (*path == NULL)
+ return NULL;
+ start = *path;
+ for (p = start; *p && *p != ':' && *p != '%'; p++)
+ ; /* nothing */
+ namelen = strlen(name);
+ len = p - start + namelen + 2; /* "2" is for '/' and '\0' */
+ STARTSTACKSTR(q);
+ CHECKSTRSPACE(len, q);
+ if (p != start) {
+ memcpy(q, start, p - start);
+ q += p - start;
+ *q++ = '/';
+ }
+ memcpy(q, name, namelen + 1);
+ pathopt = NULL;
+ if (*p == '%') {
+ pathopt = ++p;
+ while (*p && *p != ':') p++;
+ }
+ if (*p == ':')
+ *path = p + 1;
+ else
+ *path = NULL;
+ return stalloc(len);
+}
+
+
+
+/*** Command hashing code ***/
+
+
+int
+hashcmd(int argc __unused, char **argv __unused)
+{
+ struct tblentry **pp;
+ struct tblentry *cmdp;
+ int c;
+ int verbose;
+ struct cmdentry entry;
+ char *name;
+ int errors;
+
+ errors = 0;
+ verbose = 0;
+ while ((c = nextopt("rv")) != '\0') {
+ if (c == 'r') {
+ clearcmdentry();
+ } else if (c == 'v') {
+ verbose++;
+ }
+ }
+ if (*argptr == NULL) {
+ for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
+ for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+ if (cmdp->cmdtype == CMDNORMAL)
+ printentry(cmdp, verbose);
+ }
+ }
+ return 0;
+ }
+ while ((name = *argptr) != NULL) {
+ if ((cmdp = cmdlookup(name, 0)) != NULL
+ && cmdp->cmdtype == CMDNORMAL)
+ delete_cmd_entry();
+ find_command(name, &entry, DO_ERR, pathval());
+ if (entry.cmdtype == CMDUNKNOWN)
+ errors = 1;
+ else if (verbose) {
+ cmdp = cmdlookup(name, 0);
+ if (cmdp != NULL)
+ printentry(cmdp, verbose);
+ else {
+ outfmt(out2, "%s: not found\n", name);
+ errors = 1;
+ }
+ flushall();
+ }
+ argptr++;
+ }
+ return errors;
+}
+
+
+static void
+printentry(struct tblentry *cmdp, int verbose)
+{
+ int idx;
+ const char *path;
+ char *name;
+
+ if (cmdp->cmdtype == CMDNORMAL) {
+ idx = cmdp->param.index;
+ path = pathval();
+ do {
+ name = padvance(&path, cmdp->cmdname);
+ stunalloc(name);
+ } while (--idx >= 0);
+ out1str(name);
+ } else if (cmdp->cmdtype == CMDBUILTIN) {
+ out1fmt("builtin %s", cmdp->cmdname);
+ } else if (cmdp->cmdtype == CMDFUNCTION) {
+ out1fmt("function %s", cmdp->cmdname);
+ if (verbose) {
+ INTOFF;
+ name = commandtext(getfuncnode(cmdp->param.func));
+ out1c(' ');
+ out1str(name);
+ ckfree(name);
+ INTON;
+ }
+#ifdef DEBUG
+ } else {
+ error("internal error: cmdtype %d", cmdp->cmdtype);
+#endif
+ }
+ out1c('\n');
+}
+
+
+
+/*
+ * Resolve a command name. If you change this routine, you may have to
+ * change the shellexec routine as well.
+ */
+
+void
+find_command(const char *name, struct cmdentry *entry, int act,
+ const char *path)
+{
+ struct tblentry *cmdp, loc_cmd;
+ int idx;
+ char *fullname;
+ struct stat statb;
+ int e;
+ int i;
+ int spec;
+ int cd;
+
+ /* If name contains a slash, don't use the hash table */
+ if (strchr(name, '/') != NULL) {
+ entry->cmdtype = CMDNORMAL;
+ entry->u.index = 0;
+ entry->special = 0;
+ return;
+ }
+
+ cd = 0;
+
+ /* If name is in the table, we're done */
+ if ((cmdp = cmdlookup(name, 0)) != NULL) {
+ if (cmdp->cmdtype == CMDFUNCTION && act & DO_NOFUNC)
+ cmdp = NULL;
+ else
+ goto success;
+ }
+
+ /* Check for builtin next */
+ if ((i = find_builtin(name, &spec)) >= 0) {
+ INTOFF;
+ cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION)
+ cmdp = &loc_cmd;
+ cmdp->cmdtype = CMDBUILTIN;
+ cmdp->param.index = i;
+ cmdp->special = spec;
+ INTON;
+ goto success;
+ }
+
+ /* We have to search path. */
+
+ e = ENOENT;
+ idx = -1;
+ for (;(fullname = padvance(&path, name)) != NULL; stunalloc(fullname)) {
+ idx++;
+ if (pathopt) {
+ if (strncmp(pathopt, "func", 4) == 0) {
+ /* handled below */
+ } else {
+ continue; /* ignore unimplemented options */
+ }
+ }
+ if (fullname[0] != '/')
+ cd = 1;
+ if (stat(fullname, &statb) < 0) {
+ if (errno != ENOENT && errno != ENOTDIR)
+ e = errno;
+ continue;
+ }
+ e = EACCES; /* if we fail, this will be the error */
+ if (!S_ISREG(statb.st_mode))
+ continue;
+ if (pathopt) { /* this is a %func directory */
+ readcmdfile(fullname);
+ if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
+ error("%s not defined in %s", name, fullname);
+ stunalloc(fullname);
+ goto success;
+ }
+#ifdef notdef
+ if (statb.st_uid == geteuid()) {
+ if ((statb.st_mode & 0100) == 0)
+ goto loop;
+ } else if (statb.st_gid == getegid()) {
+ if ((statb.st_mode & 010) == 0)
+ goto loop;
+ } else {
+ if ((statb.st_mode & 01) == 0)
+ goto loop;
+ }
+#endif
+ TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
+ INTOFF;
+ stunalloc(fullname);
+ cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION)
+ cmdp = &loc_cmd;
+ cmdp->cmdtype = CMDNORMAL;
+ cmdp->param.index = idx;
+ cmdp->special = 0;
+ INTON;
+ goto success;
+ }
+
+ if (act & DO_ERR) {
+ if (e == ENOENT || e == ENOTDIR)
+ outfmt(out2, "%s: not found\n", name);
+ else
+ outfmt(out2, "%s: %s\n", name, strerror(e));
+ }
+ entry->cmdtype = CMDUNKNOWN;
+ entry->u.index = 0;
+ entry->special = 0;
+ return;
+
+success:
+ if (cd)
+ cmdtable_cd = 1;
+ entry->cmdtype = cmdp->cmdtype;
+ entry->u = cmdp->param;
+ entry->special = cmdp->special;
+}
+
+
+
+/*
+ * Search the table of builtin commands.
+ */
+
+int
+find_builtin(const char *name, int *special)
+{
+ const unsigned char *bp;
+ size_t len;
+
+ len = strlen(name);
+ for (bp = builtincmd ; *bp ; bp += 2 + bp[0]) {
+ if (bp[0] == len && memcmp(bp + 2, name, len) == 0) {
+ *special = (bp[1] & BUILTIN_SPECIAL) != 0;
+ return bp[1] & ~BUILTIN_SPECIAL;
+ }
+ }
+ return -1;
+}
+
+
+
+/*
+ * Called when a cd is done. If any entry in cmdtable depends on the current
+ * directory, simply clear cmdtable completely.
+ */
+
+void
+hashcd(void)
+{
+ if (cmdtable_cd)
+ clearcmdentry();
+}
+
+
+
+/*
+ * Called before PATH is changed. The argument is the new value of PATH;
+ * pathval() still returns the old value at this point. Called with
+ * interrupts off.
+ */
+
+void
+changepath(const char *newval __unused)
+{
+ clearcmdentry();
+}
+
+
+/*
+ * Clear out cached utility locations.
+ */
+
+void
+clearcmdentry(void)
+{
+ struct tblentry **tblp;
+ struct tblentry **pp;
+ struct tblentry *cmdp;
+
+ INTOFF;
+ for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) {
+ pp = tblp;
+ while ((cmdp = *pp) != NULL) {
+ if (cmdp->cmdtype == CMDNORMAL) {
+ *pp = cmdp->next;
+ ckfree(cmdp);
+ } else {
+ pp = &cmdp->next;
+ }
+ }
+ }
+ cmdtable_cd = 0;
+ INTON;
+}
+
+
+/*
+ * Locate a command in the command hash table. If "add" is nonzero,
+ * add the command to the table if it is not already present. The
+ * variable "lastcmdentry" is set to point to the address of the link
+ * pointing to the entry, so that delete_cmd_entry can delete the
+ * entry.
+ */
+
+static struct tblentry **lastcmdentry;
+
+
+static struct tblentry *
+cmdlookup(const char *name, int add)
+{
+ unsigned int hashval;
+ const char *p;
+ struct tblentry *cmdp;
+ struct tblentry **pp;
+ size_t len;
+
+ p = name;
+ hashval = (unsigned char)*p << 4;
+ while (*p)
+ hashval += *p++;
+ pp = &cmdtable[hashval % CMDTABLESIZE];
+ for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
+ if (equal(cmdp->cmdname, name))
+ break;
+ pp = &cmdp->next;
+ }
+ if (add && cmdp == NULL) {
+ INTOFF;
+ len = strlen(name);
+ cmdp = *pp = ckmalloc(sizeof (struct tblentry) + len + 1);
+ cmdp->next = NULL;
+ cmdp->cmdtype = CMDUNKNOWN;
+ memcpy(cmdp->cmdname, name, len + 1);
+ INTON;
+ }
+ lastcmdentry = pp;
+ return cmdp;
+}
+
+/*
+ * Delete the command entry returned on the last lookup.
+ */
+
+static void
+delete_cmd_entry(void)
+{
+ struct tblentry *cmdp;
+
+ INTOFF;
+ cmdp = *lastcmdentry;
+ *lastcmdentry = cmdp->next;
+ ckfree(cmdp);
+ INTON;
+}
+
+
+
+/*
+ * Add a new command entry, replacing any existing command entry for
+ * the same name.
+ */
+
+static void
+addcmdentry(const char *name, struct cmdentry *entry)
+{
+ struct tblentry *cmdp;
+
+ INTOFF;
+ cmdp = cmdlookup(name, 1);
+ if (cmdp->cmdtype == CMDFUNCTION) {
+ unreffunc(cmdp->param.func);
+ }
+ cmdp->cmdtype = entry->cmdtype;
+ cmdp->param = entry->u;
+ cmdp->special = entry->special;
+ INTON;
+}
+
+
+/*
+ * Define a shell function.
+ */
+
+void
+defun(const char *name, union node *func)
+{
+ struct cmdentry entry;
+
+ INTOFF;
+ entry.cmdtype = CMDFUNCTION;
+ entry.u.func = copyfunc(func);
+ entry.special = 0;
+ addcmdentry(name, &entry);
+ INTON;
+}
+
+
+/*
+ * Delete a function if it exists.
+ * Called with interrupts off.
+ */
+
+int
+unsetfunc(const char *name)
+{
+ struct tblentry *cmdp;
+
+ if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
+ unreffunc(cmdp->param.func);
+ delete_cmd_entry();
+ return (0);
+ }
+ return (0);
+}
+
+
+/*
+ * Check if a function by a certain name exists.
+ */
+int
+isfunc(const char *name)
+{
+ struct tblentry *cmdp;
+ cmdp = cmdlookup(name, 0);
+ return (cmdp != NULL && cmdp->cmdtype == CMDFUNCTION);
+}
+
+
+/*
+ * Shared code for the following builtin commands:
+ * type, command -v, command -V
+ */
+
+int
+typecmd_impl(int argc, char **argv, int cmd, const char *path)
+{
+ struct cmdentry entry;
+ struct tblentry *cmdp;
+ const char *const *pp;
+ struct alias *ap;
+ int i;
+ int error1 = 0;
+
+ if (path != pathval())
+ clearcmdentry();
+
+ for (i = 1; i < argc; i++) {
+ /* First look at the keywords */
+ for (pp = parsekwd; *pp; pp++)
+ if (**pp == *argv[i] && equal(*pp, argv[i]))
+ break;
+
+ if (*pp) {
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", argv[i]);
+ else
+ out1fmt("%s is a shell keyword\n", argv[i]);
+ continue;
+ }
+
+ /* Then look at the aliases */
+ if ((ap = lookupalias(argv[i], 1)) != NULL) {
+ if (cmd == TYPECMD_SMALLV) {
+ out1fmt("alias %s=", argv[i]);
+ out1qstr(ap->val);
+ outcslow('\n', out1);
+ } else
+ out1fmt("%s is an alias for %s\n", argv[i],
+ ap->val);
+ continue;
+ }
+
+ /* Then check if it is a tracked alias */
+ if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
+ entry.cmdtype = cmdp->cmdtype;
+ entry.u = cmdp->param;
+ entry.special = cmdp->special;
+ }
+ else {
+ /* Finally use brute force */
+ find_command(argv[i], &entry, 0, path);
+ }
+
+ switch (entry.cmdtype) {
+ case CMDNORMAL: {
+ if (strchr(argv[i], '/') == NULL) {
+ const char *path2 = path;
+ char *name;
+ int j = entry.u.index;
+ do {
+ name = padvance(&path2, argv[i]);
+ stunalloc(name);
+ } while (--j >= 0);
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", name);
+ else
+ out1fmt("%s is%s %s\n", argv[i],
+ (cmdp && cmd == TYPECMD_TYPE) ?
+ " a tracked alias for" : "",
+ name);
+ } else {
+ if (eaccess(argv[i], X_OK) == 0) {
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", argv[i]);
+ else
+ out1fmt("%s is %s\n", argv[i],
+ argv[i]);
+ } else {
+ if (cmd != TYPECMD_SMALLV)
+ outfmt(out2, "%s: %s\n",
+ argv[i], strerror(errno));
+ error1 |= 127;
+ }
+ }
+ break;
+ }
+ case CMDFUNCTION:
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", argv[i]);
+ else
+ out1fmt("%s is a shell function\n", argv[i]);
+ break;
+
+ case CMDBUILTIN:
+ if (cmd == TYPECMD_SMALLV)
+ out1fmt("%s\n", argv[i]);
+ else if (entry.special)
+ out1fmt("%s is a special shell builtin\n",
+ argv[i]);
+ else
+ out1fmt("%s is a shell builtin\n", argv[i]);
+ break;
+
+ default:
+ if (cmd != TYPECMD_SMALLV)
+ outfmt(out2, "%s: not found\n", argv[i]);
+ error1 |= 127;
+ break;
+ }
+ }
+
+ if (path != pathval())
+ clearcmdentry();
+
+ return error1;
+}
+
+/*
+ * Locate and print what a word is...
+ */
+
+int
+typecmd(int argc, char **argv)
+{
+ if (argc > 2 && strcmp(argv[1], "--") == 0)
+ argc--, argv++;
+ return typecmd_impl(argc, argv, TYPECMD_TYPE, bltinlookup("PATH", 1));
+}
diff --git a/shell_cmds/sh/exec.h b/shell_cmds/sh/exec.h
new file mode 100644
index 0000000..352077f
--- /dev/null
+++ b/shell_cmds/sh/exec.h
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)exec.h 8.3 (Berkeley) 6/8/95
+ * $FreeBSD: head/bin/sh/exec.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+/* values of cmdtype */
+#define CMDUNKNOWN -1 /* no entry in table for command */
+#define CMDNORMAL 0 /* command is an executable program */
+#define CMDBUILTIN 1 /* command is a shell builtin */
+#define CMDFUNCTION 2 /* command is a shell function */
+
+/* values for typecmd_impl's third parameter */
+enum {
+ TYPECMD_SMALLV, /* command -v */
+ TYPECMD_BIGV, /* command -V */
+ TYPECMD_TYPE /* type */
+};
+
+union node;
+struct cmdentry {
+ int cmdtype;
+ union param {
+ int index;
+ struct funcdef *func;
+ } u;
+ int special;
+};
+
+
+/* action to find_command() */
+#define DO_ERR 0x01 /* prints errors */
+#define DO_NOFUNC 0x02 /* don't return shell functions, for command */
+
+extern const char *pathopt; /* set by padvance */
+extern int exerrno; /* last exec error */
+
+void shellexec(char **, char **, const char *, int) __dead2;
+char *padvance(const char **, const char *);
+void find_command(const char *, struct cmdentry *, int, const char *);
+int find_builtin(const char *, int *);
+void hashcd(void);
+void changepath(const char *);
+void defun(const char *, union node *);
+int unsetfunc(const char *);
+int isfunc(const char *);
+int typecmd_impl(int, char **, int, const char *);
+void clearcmdentry(void);
diff --git a/shell_cmds/sh/expand.c b/shell_cmds/sh/expand.c
new file mode 100644
index 0000000..7a31c95
--- /dev/null
+++ b/shell_cmds/sh/expand.c
@@ -0,0 +1,1550 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1997-2005
+ * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
+ * Copyright (c) 2010-2015
+ * Jilles Tjoelker <jilles@stack.nl>. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/expand.c 318269 2017-05-14 13:14:19Z jilles $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/*
+ * Routines to expand arguments to commands. We have to deal with
+ * backquotes, shell variables, and file metacharacters.
+ */
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h"
+#include "eval.h"
+#include "expand.h"
+#include "syntax.h"
+#include "parser.h"
+#include "jobs.h"
+#include "options.h"
+#include "var.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "arith.h"
+#include "show.h"
+#include "builtins.h"
+
+enum wordstate { WORD_IDLE, WORD_WS_DELIMITED, WORD_QUOTEMARK };
+
+struct worddest {
+ struct arglist *list;
+ enum wordstate state;
+};
+
+static char *expdest; /* output of current string */
+
+static const char *argstr(const char *, struct nodelist **restrict, int,
+ struct worddest *);
+static const char *exptilde(const char *, int);
+static const char *expari(const char *, struct nodelist **restrict, int,
+ struct worddest *);
+static void expbackq(union node *, int, int, struct worddest *);
+static const char *subevalvar_trim(const char *, struct nodelist **restrict,
+ int, int, int);
+static const char *subevalvar_misc(const char *, struct nodelist **restrict,
+ const char *, int, int, int);
+static const char *evalvar(const char *, struct nodelist **restrict, int,
+ struct worddest *);
+static int varisset(const char *, int);
+static void strtodest(const char *, int, int, int, struct worddest *);
+static void reprocess(int, int, int, int, struct worddest *);
+static void varvalue(const char *, int, int, int, struct worddest *);
+static void expandmeta(char *, struct arglist *);
+static void expmeta(char *, char *, struct arglist *);
+static int expsortcmp(const void *, const void *);
+static int patmatch(const char *, const char *);
+static void cvtnum(int, char *);
+static int collate_range_cmp(wchar_t, wchar_t);
+
+void
+emptyarglist(struct arglist *list)
+{
+
+ list->args = list->smallarg;
+ list->count = 0;
+ list->capacity = sizeof(list->smallarg) / sizeof(list->smallarg[0]);
+}
+
+void
+appendarglist(struct arglist *list, char *str)
+{
+ char **newargs;
+ int newcapacity;
+
+ if (list->count >= list->capacity) {
+ newcapacity = list->capacity * 2;
+ if (newcapacity < 16)
+ newcapacity = 16;
+ if (newcapacity > INT_MAX / (int)sizeof(newargs[0]))
+ error("Too many entries in arglist");
+ newargs = stalloc(newcapacity * sizeof(newargs[0]));
+ memcpy(newargs, list->args, list->count * sizeof(newargs[0]));
+ list->args = newargs;
+ list->capacity = newcapacity;
+ }
+ list->args[list->count++] = str;
+}
+
+static int
+collate_range_cmp(wchar_t c1, wchar_t c2)
+{
+ wchar_t s1[2], s2[2];
+
+ s1[0] = c1;
+ s1[1] = L'\0';
+ s2[0] = c2;
+ s2[1] = L'\0';
+ return (wcscoll(s1, s2));
+}
+
+static char *
+stputs_quotes(const char *data, const char *syntax, char *p)
+{
+ while (*data) {
+ CHECKSTRSPACE(2, p);
+ if (syntax[(int)*data] == CCTL)
+ USTPUTC(CTLESC, p);
+ USTPUTC(*data++, p);
+ }
+ return (p);
+}
+#define STPUTS_QUOTES(data, syntax, p) p = stputs_quotes((data), syntax, p)
+
+static char *
+nextword(char c, int flag, char *p, struct worddest *dst)
+{
+ int is_ws;
+
+ is_ws = c == '\t' || c == '\n' || c == ' ';
+ if (p != stackblock() || (is_ws ? dst->state == WORD_QUOTEMARK :
+ dst->state != WORD_WS_DELIMITED) || c == '\0') {
+ STPUTC('\0', p);
+ if (flag & EXP_GLOB)
+ expandmeta(grabstackstr(p), dst->list);
+ else
+ appendarglist(dst->list, grabstackstr(p));
+ dst->state = is_ws ? WORD_WS_DELIMITED : WORD_IDLE;
+ } else if (!is_ws && dst->state == WORD_WS_DELIMITED)
+ dst->state = WORD_IDLE;
+ /* Reserve space while the stack string is empty. */
+ appendarglist(dst->list, NULL);
+ dst->list->count--;
+ STARTSTACKSTR(p);
+ return p;
+}
+#define NEXTWORD(c, flag, p, dstlist) p = nextword(c, flag, p, dstlist)
+
+static char *
+stputs_split(const char *data, const char *syntax, int flag, char *p,
+ struct worddest *dst)
+{
+ const char *ifs;
+ char c;
+
+ ifs = ifsset() ? ifsval() : " \t\n";
+ while (*data) {
+ CHECKSTRSPACE(2, p);
+ c = *data++;
+ if (strchr(ifs, c) != NULL) {
+ NEXTWORD(c, flag, p, dst);
+ continue;
+ }
+ if (flag & EXP_GLOB && syntax[(int)c] == CCTL)
+ USTPUTC(CTLESC, p);
+ USTPUTC(c, p);
+ }
+ return (p);
+}
+#define STPUTS_SPLIT(data, syntax, flag, p, dst) p = stputs_split((data), syntax, flag, p, dst)
+
+/*
+ * Perform expansions on an argument, placing the resulting list of arguments
+ * in arglist. Parameter expansion, command substitution and arithmetic
+ * expansion are always performed; additional expansions can be requested
+ * via flag (EXP_*).
+ * The result is left in the stack string.
+ * When arglist is NULL, perform here document expansion.
+ *
+ * When doing something that may cause this to be re-entered, make sure
+ * the stack string is empty via grabstackstr() and do not assume expdest
+ * remains valid.
+ */
+void
+expandarg(union node *arg, struct arglist *arglist, int flag)
+{
+ struct worddest exparg;
+ struct nodelist *argbackq;
+
+ if (fflag)
+ flag &= ~EXP_GLOB;
+ argbackq = arg->narg.backquote;
+ exparg.list = arglist;
+ exparg.state = WORD_IDLE;
+ STARTSTACKSTR(expdest);
+ argstr(arg->narg.text, &argbackq, flag, &exparg);
+ if (arglist == NULL) {
+ STACKSTRNUL(expdest);
+ return; /* here document expanded */
+ }
+ if ((flag & EXP_SPLIT) == 0 || expdest != stackblock() ||
+ exparg.state == WORD_QUOTEMARK) {
+ STPUTC('\0', expdest);
+ if (flag & EXP_SPLIT) {
+ if (flag & EXP_GLOB)
+ expandmeta(grabstackstr(expdest), exparg.list);
+ else
+ appendarglist(exparg.list, grabstackstr(expdest));
+ }
+ }
+ if ((flag & EXP_SPLIT) == 0)
+ appendarglist(arglist, grabstackstr(expdest));
+}
+
+
+
+/*
+ * Perform parameter expansion, command substitution and arithmetic
+ * expansion, and tilde expansion if requested via EXP_TILDE/EXP_VARTILDE.
+ * Processing ends at a CTLENDVAR or CTLENDARI character as well as '\0'.
+ * This is used to expand word in ${var+word} etc.
+ * If EXP_GLOB or EXP_CASE are set, keep and/or generate CTLESC
+ * characters to allow for further processing.
+ *
+ * If EXP_SPLIT is set, dst receives any complete words produced.
+ */
+static const char *
+argstr(const char *p, struct nodelist **restrict argbackq, int flag,
+ struct worddest *dst)
+{
+ char c;
+ int quotes = flag & (EXP_GLOB | EXP_CASE); /* do CTLESC */
+ int firsteq = 1;
+ int split_lit;
+ int lit_quoted;
+
+ split_lit = flag & EXP_SPLIT_LIT;
+ lit_quoted = flag & EXP_LIT_QUOTED;
+ flag &= ~(EXP_SPLIT_LIT | EXP_LIT_QUOTED);
+ if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
+ p = exptilde(p, flag);
+ for (;;) {
+ CHECKSTRSPACE(2, expdest);
+ switch (c = *p++) {
+ case '\0':
+ return (p - 1);
+ case CTLENDVAR:
+ case CTLENDARI:
+ return (p);
+ case CTLQUOTEMARK:
+ lit_quoted = 1;
+ /* "$@" syntax adherence hack */
+ if (p[0] == CTLVAR && (p[1] & VSQUOTE) != 0 &&
+ p[2] == '@' && p[3] == '=')
+ break;
+ if ((flag & EXP_SPLIT) != 0 && expdest == stackblock())
+ dst->state = WORD_QUOTEMARK;
+ break;
+ case CTLQUOTEEND:
+ lit_quoted = 0;
+ break;
+ case CTLESC:
+ c = *p++;
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
+ if (quotes)
+ USTPUTC(CTLESC, expdest);
+ USTPUTC(c, expdest);
+ break;
+ case CTLVAR:
+ p = evalvar(p, argbackq, flag, dst);
+ break;
+ case CTLBACKQ:
+ case CTLBACKQ|CTLQUOTE:
+ expbackq((*argbackq)->n, c & CTLQUOTE, flag, dst);
+ *argbackq = (*argbackq)->next;
+ break;
+ case CTLARI:
+ p = expari(p, argbackq, flag, dst);
+ break;
+ case ':':
+ case '=':
+ /*
+ * sort of a hack - expand tildes in variable
+ * assignments (after the first '=' and after ':'s).
+ */
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
+ USTPUTC(c, expdest);
+ if (flag & EXP_VARTILDE && *p == '~' &&
+ (c != '=' || firsteq)) {
+ if (c == '=')
+ firsteq = 0;
+ p = exptilde(p, flag);
+ }
+ break;
+ default:
+ if (split_lit && !lit_quoted &&
+ strchr(ifsset() ? ifsval() : " \t\n", c) != NULL) {
+ NEXTWORD(c, flag, expdest, dst);
+ break;
+ }
+ USTPUTC(c, expdest);
+ }
+ }
+}
+
+/*
+ * Perform tilde expansion, placing the result in the stack string and
+ * returning the next position in the input string to process.
+ */
+static const char *
+exptilde(const char *p, int flag)
+{
+ char c;
+ const char *startp = p;
+ const char *user;
+ struct passwd *pw;
+ char *home;
+ int len;
+
+ for (;;) {
+ c = *p;
+ switch(c) {
+ case CTLESC: /* This means CTL* are always considered quoted. */
+ case CTLVAR:
+ case CTLBACKQ:
+ case CTLBACKQ | CTLQUOTE:
+ case CTLARI:
+ case CTLENDARI:
+ case CTLQUOTEMARK:
+ return (startp);
+ case ':':
+ if ((flag & EXP_VARTILDE) == 0)
+ break;
+ /* FALLTHROUGH */
+ case '\0':
+ case '/':
+ case CTLENDVAR:
+ len = p - startp - 1;
+ STPUTBIN(startp + 1, len, expdest);
+ STACKSTRNUL(expdest);
+ user = expdest - len;
+ if (*user == '\0') {
+ home = lookupvar("HOME");
+ } else {
+ pw = getpwnam(user);
+ home = pw != NULL ? pw->pw_dir : NULL;
+ }
+ STADJUST(-len, expdest);
+ if (home == NULL || *home == '\0')
+ return (startp);
+ strtodest(home, flag, VSNORMAL, 1, NULL);
+ return (p);
+ }
+ p++;
+ }
+}
+
+
+/*
+ * Expand arithmetic expression.
+ */
+static const char *
+expari(const char *p, struct nodelist **restrict argbackq, int flag,
+ struct worddest *dst)
+{
+ char *q, *start;
+ arith_t result;
+ int begoff;
+ int quoted;
+ int adj;
+
+ quoted = *p++ == '"';
+ begoff = expdest - stackblock();
+ p = argstr(p, argbackq, 0, NULL);
+ STPUTC('\0', expdest);
+ start = stackblock() + begoff;
+
+ q = grabstackstr(expdest);
+ result = arith(start);
+ ungrabstackstr(q, expdest);
+
+ start = stackblock() + begoff;
+ adj = start - expdest;
+ STADJUST(adj, expdest);
+
+ CHECKSTRSPACE((int)(DIGITS(result) + 1), expdest);
+ fmtstr(expdest, DIGITS(result), ARITH_FORMAT_STR, result);
+ adj = strlen(expdest);
+ STADJUST(adj, expdest);
+ /*
+ * If this is quoted, a '-' must not indicate a range in [...].
+ * If this is not quoted, splitting may occur.
+ */
+ if (quoted ?
+ result < 0 && begoff > 1 && flag & (EXP_GLOB | EXP_CASE) :
+ flag & EXP_SPLIT)
+ reprocess(expdest - adj - stackblock(), flag, VSNORMAL, quoted,
+ dst);
+ return p;
+}
+
+
+/*
+ * Perform command substitution.
+ */
+static void
+expbackq(union node *cmd, int quoted, int flag, struct worddest *dst)
+{
+ struct backcmd in;
+ int i;
+ char buf[128];
+ char *p;
+ char *dest = expdest;
+ char lastc;
+ char const *syntax = quoted? DQSYNTAX : BASESYNTAX;
+ int quotes = flag & (EXP_GLOB | EXP_CASE);
+ size_t nnl;
+ const char *ifs;
+ int startloc;
+
+ INTOFF;
+ p = grabstackstr(dest);
+ evalbackcmd(cmd, &in);
+ ungrabstackstr(p, dest);
+
+ p = in.buf;
+ startloc = dest - stackblock();
+ nnl = 0;
+ if (!quoted && flag & EXP_SPLIT)
+ ifs = ifsset() ? ifsval() : " \t\n";
+ else
+ ifs = "";
+ /* Remove trailing newlines */
+ for (;;) {
+ if (--in.nleft < 0) {
+ if (in.fd < 0)
+ break;
+ while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR)
+ ;
+ TRACE(("expbackq: read returns %d\n", i));
+ if (i <= 0)
+ break;
+ p = buf;
+ in.nleft = i - 1;
+ }
+ lastc = *p++;
+ if (lastc == '\0')
+ continue;
+ if (nnl > 0 && lastc != '\n') {
+ NEXTWORD('\n', flag, dest, dst);
+ nnl = 0;
+ }
+ if (strchr(ifs, lastc) != NULL) {
+ if (lastc == '\n')
+ nnl++;
+ else
+ NEXTWORD(lastc, flag, dest, dst);
+ } else {
+ CHECKSTRSPACE(2, dest);
+ if (quotes && syntax[(int)lastc] == CCTL)
+ USTPUTC(CTLESC, dest);
+ USTPUTC(lastc, dest);
+ }
+ }
+ while (dest > stackblock() + startloc && STTOPC(dest) == '\n')
+ STUNPUTC(dest);
+
+ if (in.fd >= 0)
+ close(in.fd);
+ if (in.buf)
+ ckfree(in.buf);
+ if (in.jp) {
+ p = grabstackstr(dest);
+ exitstatus = waitforjob(in.jp, (int *)NULL);
+ ungrabstackstr(p, dest);
+ }
+ TRACE(("expbackq: done\n"));
+ expdest = dest;
+ INTON;
+}
+
+
+
+static void
+recordleft(const char *str, const char *loc, char *startp)
+{
+ int amount;
+
+ amount = ((str - 1) - (loc - startp)) - expdest;
+ STADJUST(amount, expdest);
+ while (loc != str - 1)
+ *startp++ = *loc++;
+}
+
+static const char *
+subevalvar_trim(const char *p, struct nodelist **restrict argbackq, int strloc,
+ int subtype, int startloc)
+{
+ char *startp;
+ char *loc = NULL;
+ char *str;
+ int c = 0;
+ int amount;
+
+ p = argstr(p, argbackq, EXP_CASE | EXP_TILDE, NULL);
+ STACKSTRNUL(expdest);
+ startp = stackblock() + startloc;
+ str = stackblock() + strloc;
+
+ switch (subtype) {
+ case VSTRIMLEFT:
+ for (loc = startp; loc < str; loc++) {
+ c = *loc;
+ *loc = '\0';
+ if (patmatch(str, startp)) {
+ *loc = c;
+ recordleft(str, loc, startp);
+ return p;
+ }
+ *loc = c;
+ }
+ break;
+
+ case VSTRIMLEFTMAX:
+ for (loc = str - 1; loc >= startp;) {
+ c = *loc;
+ *loc = '\0';
+ if (patmatch(str, startp)) {
+ *loc = c;
+ recordleft(str, loc, startp);
+ return p;
+ }
+ *loc = c;
+ loc--;
+ }
+ break;
+
+ case VSTRIMRIGHT:
+ for (loc = str - 1; loc >= startp;) {
+ if (patmatch(str, loc)) {
+ amount = loc - expdest;
+ STADJUST(amount, expdest);
+ return p;
+ }
+ loc--;
+ }
+ break;
+
+ case VSTRIMRIGHTMAX:
+ for (loc = startp; loc < str - 1; loc++) {
+ if (patmatch(str, loc)) {
+ amount = loc - expdest;
+ STADJUST(amount, expdest);
+ return p;
+ }
+ }
+ break;
+
+
+ default:
+ abort();
+ }
+ amount = (expdest - stackblock() - strloc) + 1;
+ STADJUST(-amount, expdest);
+ return p;
+}
+
+
+static const char *
+subevalvar_misc(const char *p, struct nodelist **restrict argbackq,
+ const char *var, int subtype, int startloc, int varflags)
+{
+ char *startp;
+ int amount;
+
+ p = argstr(p, argbackq, EXP_TILDE, NULL);
+ STACKSTRNUL(expdest);
+ startp = stackblock() + startloc;
+
+ switch (subtype) {
+ case VSASSIGN:
+ setvar(var, startp, 0);
+ amount = startp - expdest;
+ STADJUST(amount, expdest);
+ return p;
+
+ case VSQUESTION:
+ if (*p != CTLENDVAR) {
+ outfmt(out2, "%s\n", startp);
+ error((char *)NULL);
+ }
+ error("%.*s: parameter %snot set", (int)(p - var - 1),
+ var, (varflags & VSNUL) ? "null or " : "");
+
+ default:
+ abort();
+ }
+}
+
+
+/*
+ * Expand a variable, and return a pointer to the next character in the
+ * input string.
+ */
+
+static const char *
+evalvar(const char *p, struct nodelist **restrict argbackq, int flag,
+ struct worddest *dst)
+{
+ int subtype;
+ int varflags;
+ const char *var;
+ const char *val;
+ int patloc;
+ int c;
+ int set;
+ int special;
+ int startloc;
+ int varlen;
+ int varlenb;
+ char buf[21];
+
+ varflags = (unsigned char)*p++;
+ subtype = varflags & VSTYPE;
+ var = p;
+ special = 0;
+ if (! is_name(*p))
+ special = 1;
+ p = strchr(p, '=') + 1;
+ if (varflags & VSLINENO) {
+ set = 1;
+ special = 1;
+ val = NULL;
+ } else if (special) {
+ set = varisset(var, varflags & VSNUL);
+ val = NULL;
+ } else {
+ val = bltinlookup(var, 1);
+ if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) {
+ val = NULL;
+ set = 0;
+ } else
+ set = 1;
+ }
+ varlen = 0;
+ startloc = expdest - stackblock();
+ if (!set && uflag && *var != '@' && *var != '*') {
+ switch (subtype) {
+ case VSNORMAL:
+ case VSTRIMLEFT:
+ case VSTRIMLEFTMAX:
+ case VSTRIMRIGHT:
+ case VSTRIMRIGHTMAX:
+ case VSLENGTH:
+ error("%.*s: parameter not set", (int)(p - var - 1),
+ var);
+ }
+ }
+ if (set && subtype != VSPLUS) {
+ /* insert the value of the variable */
+ if (special) {
+ if (varflags & VSLINENO) {
+ if (p - var > (ptrdiff_t)sizeof(buf))
+ abort();
+ memcpy(buf, var, p - var - 1);
+ buf[p - var - 1] = '\0';
+ strtodest(buf, flag, subtype,
+ varflags & VSQUOTE, dst);
+ } else
+ varvalue(var, varflags & VSQUOTE, subtype, flag,
+ dst);
+ if (subtype == VSLENGTH) {
+ varlenb = expdest - stackblock() - startloc;
+ varlen = varlenb;
+ if (localeisutf8) {
+ val = stackblock() + startloc;
+ for (;val != expdest; val++)
+ if ((*val & 0xC0) == 0x80)
+ varlen--;
+ }
+ STADJUST(-varlenb, expdest);
+ }
+ } else {
+ if (subtype == VSLENGTH) {
+ for (;*val; val++)
+ if (!localeisutf8 ||
+ (*val & 0xC0) != 0x80)
+ varlen++;
+ }
+ else
+ strtodest(val, flag, subtype,
+ varflags & VSQUOTE, dst);
+ }
+ }
+
+ if (subtype == VSPLUS)
+ set = ! set;
+
+ switch (subtype) {
+ case VSLENGTH:
+ cvtnum(varlen, buf);
+ strtodest(buf, flag, VSNORMAL, varflags & VSQUOTE, dst);
+ break;
+
+ case VSNORMAL:
+ return p;
+
+ case VSPLUS:
+ case VSMINUS:
+ if (!set) {
+ return argstr(p, argbackq,
+ flag | (flag & EXP_SPLIT ? EXP_SPLIT_LIT : 0) |
+ (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0), dst);
+ }
+ break;
+
+ case VSTRIMLEFT:
+ case VSTRIMLEFTMAX:
+ case VSTRIMRIGHT:
+ case VSTRIMRIGHTMAX:
+ if (!set)
+ break;
+ /*
+ * Terminate the string and start recording the pattern
+ * right after it
+ */
+ STPUTC('\0', expdest);
+ patloc = expdest - stackblock();
+ p = subevalvar_trim(p, argbackq, patloc, subtype, startloc);
+ reprocess(startloc, flag, VSNORMAL, varflags & VSQUOTE, dst);
+ if (flag & EXP_SPLIT && *var == '@' && varflags & VSQUOTE)
+ dst->state = WORD_QUOTEMARK;
+ return p;
+
+ case VSASSIGN:
+ case VSQUESTION:
+ if (!set) {
+ p = subevalvar_misc(p, argbackq, var, subtype,
+ startloc, varflags);
+ /* assert(subtype == VSASSIGN); */
+ val = lookupvar(var);
+ strtodest(val, flag, subtype, varflags & VSQUOTE, dst);
+ return p;
+ }
+ break;
+
+ case VSERROR:
+ c = p - var - 1;
+ error("${%.*s%s}: Bad substitution", c, var,
+ (c > 0 && *p != CTLENDVAR) ? "..." : "");
+
+ default:
+ abort();
+ }
+
+ { /* skip to end of alternative */
+ int nesting = 1;
+ for (;;) {
+ if ((c = *p++) == CTLESC)
+ p++;
+ else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE))
+ *argbackq = (*argbackq)->next;
+ else if (c == CTLVAR) {
+ if ((*p++ & VSTYPE) != VSNORMAL)
+ nesting++;
+ } else if (c == CTLENDVAR) {
+ if (--nesting == 0)
+ break;
+ }
+ }
+ }
+ return p;
+}
+
+
+
+/*
+ * Test whether a special or positional parameter is set.
+ */
+
+static int
+varisset(const char *name, int nulok)
+{
+
+ if (*name == '!')
+ return backgndpidset();
+ else if (*name == '@' || *name == '*') {
+ if (*shellparam.p == NULL)
+ return 0;
+
+ if (nulok) {
+ char **av;
+
+ for (av = shellparam.p; *av; av++)
+ if (**av != '\0')
+ return 1;
+ return 0;
+ }
+ } else if (is_digit(*name)) {
+ char *ap;
+ long num;
+
+ errno = 0;
+ num = strtol(name, NULL, 10);
+ if (errno != 0 || num > shellparam.nparam)
+ return 0;
+
+ if (num == 0)
+ ap = arg0;
+ else
+ ap = shellparam.p[num - 1];
+
+ if (nulok && (ap == NULL || *ap == '\0'))
+ return 0;
+ }
+ return 1;
+}
+
+static void
+strtodest(const char *p, int flag, int subtype, int quoted,
+ struct worddest *dst)
+{
+ if (subtype == VSLENGTH || subtype == VSTRIMLEFT ||
+ subtype == VSTRIMLEFTMAX || subtype == VSTRIMRIGHT ||
+ subtype == VSTRIMRIGHTMAX)
+ STPUTS(p, expdest);
+ else if (flag & EXP_SPLIT && !quoted && dst != NULL)
+ STPUTS_SPLIT(p, BASESYNTAX, flag, expdest, dst);
+ else if (flag & (EXP_GLOB | EXP_CASE))
+ STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest);
+ else
+ STPUTS(p, expdest);
+}
+
+static void
+reprocess(int startloc, int flag, int subtype, int quoted,
+ struct worddest *dst)
+{
+ static char *buf = NULL;
+ static size_t buflen = 0;
+ char *startp;
+ size_t len, zpos, zlen;
+
+ startp = stackblock() + startloc;
+ len = expdest - startp;
+ if (len >= SIZE_MAX / 2)
+ abort();
+ INTOFF;
+ if (len >= buflen) {
+ ckfree(buf);
+ buf = NULL;
+ }
+ if (buflen < 128)
+ buflen = 128;
+ while (len >= buflen)
+ buflen <<= 1;
+ if (buf == NULL)
+ buf = ckmalloc(buflen);
+ INTON;
+ memcpy(buf, startp, len);
+ buf[len] = '\0';
+ STADJUST(-len, expdest);
+ for (zpos = 0;;) {
+ zlen = strlen(buf + zpos);
+ strtodest(buf + zpos, flag, subtype, quoted, dst);
+ zpos += zlen + 1;
+ if (zpos == len + 1)
+ break;
+ if (flag & EXP_SPLIT && (quoted || (zlen > 0 && zpos < len)))
+ NEXTWORD('\0', flag, expdest, dst);
+ }
+}
+
+/*
+ * Add the value of a special or positional parameter to the stack string.
+ */
+
+static void
+varvalue(const char *name, int quoted, int subtype, int flag,
+ struct worddest *dst)
+{
+ int num;
+ char *p;
+ int i;
+ int splitlater;
+ char sep[2];
+ char **ap;
+ char buf[(NSHORTOPTS > 10 ? NSHORTOPTS : 10) + 1];
+
+ if (subtype == VSLENGTH)
+ flag &= ~EXP_FULL;
+ splitlater = subtype == VSTRIMLEFT || subtype == VSTRIMLEFTMAX ||
+ subtype == VSTRIMRIGHT || subtype == VSTRIMRIGHTMAX;
+
+ switch (*name) {
+ case '$':
+ num = rootpid;
+ break;
+ case '?':
+ num = oexitstatus;
+ break;
+ case '#':
+ num = shellparam.nparam;
+ break;
+ case '!':
+ num = backgndpidval();
+ break;
+ case '-':
+ p = buf;
+ for (i = 0 ; i < NSHORTOPTS ; i++) {
+ if (optval[i])
+ *p++ = optletter[i];
+ }
+ *p = '\0';
+ strtodest(buf, flag, subtype, quoted, dst);
+ return;
+ case '@':
+ if (flag & EXP_SPLIT && quoted) {
+ for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
+ strtodest(p, flag, subtype, quoted, dst);
+ if (*ap) {
+ if (splitlater)
+ STPUTC('\0', expdest);
+ else
+ NEXTWORD('\0', flag, expdest,
+ dst);
+ }
+ }
+ if (shellparam.nparam > 0)
+ dst->state = WORD_QUOTEMARK;
+ return;
+ }
+ /* FALLTHROUGH */
+ case '*':
+ if (ifsset())
+ sep[0] = ifsval()[0];
+ else
+ sep[0] = ' ';
+ sep[1] = '\0';
+ for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
+ strtodest(p, flag, subtype, quoted, dst);
+ if (!*ap)
+ break;
+ if (sep[0])
+ strtodest(sep, flag, subtype, quoted, dst);
+ else if (flag & EXP_SPLIT && !quoted && **ap != '\0') {
+ if (splitlater)
+ STPUTC('\0', expdest);
+ else
+ NEXTWORD('\0', flag, expdest, dst);
+ }
+ }
+ return;
+ default:
+ if (is_digit(*name)) {
+ num = atoi(name);
+ if (num == 0)
+ p = arg0;
+ else if (num > 0 && num <= shellparam.nparam)
+ p = shellparam.p[num - 1];
+ else
+ return;
+ strtodest(p, flag, subtype, quoted, dst);
+ }
+ return;
+ }
+ cvtnum(num, buf);
+ strtodest(buf, flag, subtype, quoted, dst);
+}
+
+
+
+static char expdir[PATH_MAX];
+#define expdir_end (expdir + sizeof(expdir))
+
+/*
+ * Perform pathname generation and remove control characters.
+ * At this point, the only control characters should be CTLESC.
+ * The results are stored in the list dstlist.
+ */
+static void
+expandmeta(char *pattern, struct arglist *dstlist)
+{
+ char *p;
+ int firstmatch;
+ char c;
+
+ firstmatch = dstlist->count;
+ p = pattern;
+ for (; (c = *p) != '\0'; p++) {
+ /* fast check for meta chars */
+ if (c == '*' || c == '?' || c == '[') {
+ INTOFF;
+ expmeta(expdir, pattern, dstlist);
+ INTON;
+ break;
+ }
+ }
+ if (dstlist->count == firstmatch) {
+ /*
+ * no matches
+ */
+ rmescapes(pattern);
+ appendarglist(dstlist, pattern);
+ } else {
+ qsort(&dstlist->args[firstmatch],
+ dstlist->count - firstmatch,
+ sizeof(dstlist->args[0]), expsortcmp);
+ }
+}
+
+
+/*
+ * Do metacharacter (i.e. *, ?, [...]) expansion.
+ */
+
+static void
+expmeta(char *enddir, char *name, struct arglist *arglist)
+{
+ const char *p;
+ const char *q;
+ const char *start;
+ char *endname;
+ int metaflag;
+ struct stat statb;
+ DIR *dirp;
+ struct dirent *dp;
+ int atend;
+ int matchdot;
+ int esc;
+ int namlen;
+
+ metaflag = 0;
+ start = name;
+ for (p = name; esc = 0, *p; p += esc + 1) {
+ if (*p == '*' || *p == '?')
+ metaflag = 1;
+ else if (*p == '[') {
+ q = p + 1;
+ if (*q == '!' || *q == '^')
+ q++;
+ for (;;) {
+ if (*q == CTLESC)
+ q++;
+ if (*q == '/' || *q == '\0')
+ break;
+ if (*++q == ']') {
+ metaflag = 1;
+ break;
+ }
+ }
+ } else if (*p == '\0')
+ break;
+ else {
+ if (*p == CTLESC)
+ esc++;
+ if (p[esc] == '/') {
+ if (metaflag)
+ break;
+ start = p + esc + 1;
+ }
+ }
+ }
+ if (metaflag == 0) { /* we've reached the end of the file name */
+ if (enddir != expdir)
+ metaflag++;
+ for (p = name ; ; p++) {
+ if (*p == CTLESC)
+ p++;
+ *enddir++ = *p;
+ if (*p == '\0')
+ break;
+ if (enddir == expdir_end)
+ return;
+ }
+ if (metaflag == 0 || lstat(expdir, &statb) >= 0)
+ appendarglist(arglist, stsavestr(expdir));
+ return;
+ }
+ endname = name + (p - name);
+ if (start != name) {
+ p = name;
+ while (p < start) {
+ if (*p == CTLESC)
+ p++;
+ *enddir++ = *p++;
+ if (enddir == expdir_end)
+ return;
+ }
+ }
+ if (enddir == expdir) {
+ p = ".";
+ } else if (enddir == expdir + 1 && *expdir == '/') {
+ p = "/";
+ } else {
+ p = expdir;
+ enddir[-1] = '\0';
+ }
+ if ((dirp = opendir(p)) == NULL)
+ return;
+ if (enddir != expdir)
+ enddir[-1] = '/';
+ if (*endname == 0) {
+ atend = 1;
+ } else {
+ atend = 0;
+ *endname = '\0';
+ endname += esc + 1;
+ }
+ matchdot = 0;
+ p = start;
+ if (*p == CTLESC)
+ p++;
+ if (*p == '.')
+ matchdot++;
+ while (! int_pending() && (dp = readdir(dirp)) != NULL) {
+ if (dp->d_name[0] == '.' && ! matchdot)
+ continue;
+ if (patmatch(start, dp->d_name)) {
+ namlen = dp->d_namlen;
+ if (enddir + namlen + 1 > expdir_end)
+ continue;
+ memcpy(enddir, dp->d_name, namlen + 1);
+ if (atend)
+ appendarglist(arglist, stsavestr(expdir));
+ else {
+ if (dp->d_type != DT_UNKNOWN &&
+ dp->d_type != DT_DIR &&
+ dp->d_type != DT_LNK)
+ continue;
+ if (enddir + namlen + 2 > expdir_end)
+ continue;
+ enddir[namlen] = '/';
+ enddir[namlen + 1] = '\0';
+ expmeta(enddir + namlen + 1, endname, arglist);
+ }
+ }
+ }
+ closedir(dirp);
+ if (! atend)
+ endname[-esc - 1] = esc ? CTLESC : '/';
+}
+
+
+static int
+expsortcmp(const void *p1, const void *p2)
+{
+ const char *s1 = *(const char * const *)p1;
+ const char *s2 = *(const char * const *)p2;
+
+ return (strcoll(s1, s2));
+}
+
+
+
+static wchar_t
+get_wc(const char **p)
+{
+ wchar_t c;
+ int chrlen;
+
+ chrlen = mbtowc(&c, *p, 4);
+ if (chrlen == 0)
+ return 0;
+ else if (chrlen == -1)
+ c = 0;
+ else
+ *p += chrlen;
+ return c;
+}
+
+
+/*
+ * See if a character matches a character class, starting at the first colon
+ * of "[:class:]".
+ * If a valid character class is recognized, a pointer to the next character
+ * after the final closing bracket is stored into *end, otherwise a null
+ * pointer is stored into *end.
+ */
+static int
+match_charclass(const char *p, wchar_t chr, const char **end)
+{
+ char name[20];
+ const char *nameend;
+ wctype_t cclass;
+
+ *end = NULL;
+ p++;
+ nameend = strstr(p, ":]");
+ if (nameend == NULL || (size_t)(nameend - p) >= sizeof(name) ||
+ nameend == p)
+ return 0;
+ memcpy(name, p, nameend - p);
+ name[nameend - p] = '\0';
+ *end = nameend + 2;
+ cclass = wctype(name);
+ /* An unknown class matches nothing but is valid nevertheless. */
+ if (cclass == 0)
+ return 0;
+ return iswctype(chr, cclass);
+}
+
+
+/*
+ * Returns true if the pattern matches the string.
+ */
+
+static int
+patmatch(const char *pattern, const char *string)
+{
+ const char *p, *q, *end;
+ const char *bt_p, *bt_q;
+ char c;
+ wchar_t wc, wc2;
+
+ p = pattern;
+ q = string;
+ bt_p = NULL;
+ bt_q = NULL;
+ for (;;) {
+ switch (c = *p++) {
+ case '\0':
+ if (*q != '\0')
+ goto backtrack;
+ return 1;
+ case CTLESC:
+ if (*q++ != *p++)
+ goto backtrack;
+ break;
+ case '?':
+ if (*q == '\0')
+ return 0;
+ if (localeisutf8) {
+ wc = get_wc(&q);
+ /*
+ * A '?' does not match invalid UTF-8 but a
+ * '*' does, so backtrack.
+ */
+ if (wc == 0)
+ goto backtrack;
+ } else
+ q++;
+ break;
+ case '*':
+ c = *p;
+ while (c == '*')
+ c = *++p;
+ /*
+ * If the pattern ends here, we know the string
+ * matches without needing to look at the rest of it.
+ */
+ if (c == '\0')
+ return 1;
+ /*
+ * First try the shortest match for the '*' that
+ * could work. We can forget any earlier '*' since
+ * there is no way having it match more characters
+ * can help us, given that we are already here.
+ */
+ bt_p = p;
+ bt_q = q;
+ break;
+ case '[': {
+ const char *savep, *saveq;
+ int invert, found;
+ wchar_t chr;
+
+ savep = p, saveq = q;
+ invert = 0;
+ if (*p == '!' || *p == '^') {
+ invert++;
+ p++;
+ }
+ found = 0;
+ if (*q == '\0')
+ return 0;
+ if (localeisutf8) {
+ chr = get_wc(&q);
+ if (chr == 0)
+ goto backtrack;
+ } else
+ chr = (unsigned char)*q++;
+ c = *p++;
+ do {
+ if (c == '\0') {
+ p = savep, q = saveq;
+ c = '[';
+ goto dft;
+ }
+ if (c == '[' && *p == ':') {
+ found |= match_charclass(p, chr, &end);
+ if (end != NULL)
+ p = end;
+ }
+ if (c == CTLESC)
+ c = *p++;
+ if (localeisutf8 && c & 0x80) {
+ p--;
+ wc = get_wc(&p);
+ if (wc == 0) /* bad utf-8 */
+ return 0;
+ } else
+ wc = (unsigned char)c;
+ if (*p == '-' && p[1] != ']') {
+ p++;
+ if (*p == CTLESC)
+ p++;
+ if (localeisutf8) {
+ wc2 = get_wc(&p);
+ if (wc2 == 0) /* bad utf-8 */
+ return 0;
+ } else
+ wc2 = (unsigned char)*p++;
+ if ( collate_range_cmp(chr, wc) >= 0
+ && collate_range_cmp(chr, wc2) <= 0
+ )
+ found = 1;
+ } else {
+ if (chr == wc)
+ found = 1;
+ }
+ } while ((c = *p++) != ']');
+ if (found == invert)
+ goto backtrack;
+ break;
+ }
+dft: default:
+ if (*q == '\0')
+ return 0;
+ if (*q++ == c)
+ break;
+backtrack:
+ /*
+ * If we have a mismatch (other than hitting the end
+ * of the string), go back to the last '*' seen and
+ * have it match one additional character.
+ */
+ if (bt_p == NULL)
+ return 0;
+ if (*bt_q == '\0')
+ return 0;
+ bt_q++;
+ p = bt_p;
+ q = bt_q;
+ break;
+ }
+ }
+}
+
+
+
+/*
+ * Remove any CTLESC and CTLQUOTEMARK characters from a string.
+ */
+
+void
+rmescapes(char *str)
+{
+ char *p, *q;
+
+ p = str;
+ while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLQUOTEEND) {
+ if (*p++ == '\0')
+ return;
+ }
+ q = p;
+ while (*p) {
+ if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) {
+ p++;
+ continue;
+ }
+ if (*p == CTLESC)
+ p++;
+ *q++ = *p++;
+ }
+ *q = '\0';
+}
+
+
+
+/*
+ * See if a pattern matches in a case statement.
+ */
+
+int
+casematch(union node *pattern, const char *val)
+{
+ struct stackmark smark;
+ struct nodelist *argbackq;
+ int result;
+ char *p;
+
+ setstackmark(&smark);
+ argbackq = pattern->narg.backquote;
+ STARTSTACKSTR(expdest);
+ argstr(pattern->narg.text, &argbackq, EXP_TILDE | EXP_CASE, NULL);
+ STPUTC('\0', expdest);
+ p = grabstackstr(expdest);
+ result = patmatch(p, val);
+ popstackmark(&smark);
+ return result;
+}
+
+/*
+ * Our own itoa().
+ */
+
+static void
+cvtnum(int num, char *buf)
+{
+ char temp[32];
+ int neg = num < 0;
+ char *p = temp + 31;
+
+ temp[31] = '\0';
+
+ do {
+ *--p = num % 10 + '0';
+ } while ((num /= 10) != 0);
+
+ if (neg)
+ *--p = '-';
+
+ memcpy(buf, p, temp + 32 - p);
+}
+
+/*
+ * Do most of the work for wordexp(3).
+ */
+
+int
+wordexpcmd(int argc, char **argv)
+{
+ size_t len;
+ int i;
+
+ out1fmt("%08x", argc - 1);
+ for (i = 1, len = 0; i < argc; i++)
+ len += strlen(argv[i]);
+ out1fmt("%08x", (int)len);
+ for (i = 1; i < argc; i++)
+ outbin(argv[i], strlen(argv[i]) + 1, out1);
+ return (0);
+}
+
+/*
+ * Do most of the work for wordexp(3), new version.
+ */
+
+int
+freebsd_wordexpcmd(int argc __unused, char **argv __unused)
+{
+ struct arglist arglist;
+ union node *args, *n;
+ size_t len;
+ int ch;
+ int protected = 0;
+ int fd = -1;
+ int i;
+
+ while ((ch = nextopt("f:p")) != '\0') {
+ switch (ch) {
+ case 'f':
+ fd = number(shoptarg);
+ break;
+ case 'p':
+ protected = 1;
+ break;
+ }
+ }
+ if (*argptr != NULL)
+ error("wrong number of arguments");
+ if (fd < 0)
+ error("missing fd");
+ INTOFF;
+ setinputfd(fd, 1);
+ INTON;
+ args = parsewordexp();
+ popfile(); /* will also close fd */
+ if (protected)
+ for (n = args; n != NULL; n = n->narg.next) {
+ if (n->narg.backquote != NULL) {
+ outcslow('C', out1);
+ error("command substitution disabled");
+ }
+ }
+ outcslow(' ', out1);
+ emptyarglist(&arglist);
+ for (n = args; n != NULL; n = n->narg.next)
+ expandarg(n, &arglist, EXP_FULL | EXP_TILDE);
+ for (i = 0, len = 0; i < arglist.count; i++)
+ len += strlen(arglist.args[i]);
+ out1fmt("%016x %016zx", arglist.count, len);
+ for (i = 0; i < arglist.count; i++)
+ outbin(arglist.args[i], strlen(arglist.args[i]) + 1, out1);
+ return (0);
+}
diff --git a/shell_cmds/sh/expand.h b/shell_cmds/sh/expand.h
new file mode 100644
index 0000000..e959174
--- /dev/null
+++ b/shell_cmds/sh/expand.h
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)expand.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/expand.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+struct arglist {
+ char **args;
+ int count;
+ int capacity;
+ char *smallarg[1];
+};
+
+/*
+ * expandarg() flags
+ */
+#define EXP_SPLIT 0x1 /* perform word splitting */
+#define EXP_TILDE 0x2 /* do normal tilde expansion */
+#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
+#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
+#define EXP_SPLIT_LIT 0x20 /* IFS split literal text ${v+-a b c} */
+#define EXP_LIT_QUOTED 0x40 /* for EXP_SPLIT_LIT, start off quoted */
+#define EXP_GLOB 0x80 /* perform file globbing */
+
+#define EXP_FULL (EXP_SPLIT | EXP_GLOB)
+
+
+void emptyarglist(struct arglist *);
+void appendarglist(struct arglist *, char *);
+union node;
+void expandarg(union node *, struct arglist *, int);
+void rmescapes(char *);
+int casematch(union node *, const char *);
diff --git a/shell_cmds/sh/funcs/cmv b/shell_cmds/sh/funcs/cmv
new file mode 100644
index 0000000..01728ca
--- /dev/null
+++ b/shell_cmds/sh/funcs/cmv
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)cmv 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/cmv 314436 2017-02-28 23:42:47Z imp $
+
+# Conditional move--don't replace an existing file.
+
+cmv() {
+ if test $# != 2
+ then echo "cmv: arg count"
+ return 2
+ fi
+ if test -f "$2" -o -w "$2"
+ then echo "$2 exists"
+ return 2
+ fi
+ /bin/mv "$1" "$2"
+}
diff --git a/shell_cmds/sh/funcs/dirs b/shell_cmds/sh/funcs/dirs
new file mode 100644
index 0000000..88c20f4
--- /dev/null
+++ b/shell_cmds/sh/funcs/dirs
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)dirs 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/dirs 314436 2017-02-28 23:42:47Z imp $
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/shell_cmds/sh/funcs/login b/shell_cmds/sh/funcs/login
new file mode 100644
index 0000000..e3c1154
--- /dev/null
+++ b/shell_cmds/sh/funcs/login
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)login 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/login 314436 2017-02-28 23:42:47Z imp $
+
+# replaces the login builtin in the BSD shell
+login () exec login "$@"
diff --git a/shell_cmds/sh/funcs/newgrp b/shell_cmds/sh/funcs/newgrp
new file mode 100644
index 0000000..5f9f861
--- /dev/null
+++ b/shell_cmds/sh/funcs/newgrp
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)newgrp 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/newgrp 314436 2017-02-28 23:42:47Z imp $
+
+newgrp() exec newgrp "$@"
diff --git a/shell_cmds/sh/funcs/popd b/shell_cmds/sh/funcs/popd
new file mode 100644
index 0000000..7a46b4e
--- /dev/null
+++ b/shell_cmds/sh/funcs/popd
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)popd 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/popd 314436 2017-02-28 23:42:47Z imp $
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/shell_cmds/sh/funcs/pushd b/shell_cmds/sh/funcs/pushd
new file mode 100644
index 0000000..8d4f10d
--- /dev/null
+++ b/shell_cmds/sh/funcs/pushd
@@ -0,0 +1,73 @@
+#!/bin/sh
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)pushd 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/pushd 314436 2017-02-28 23:42:47Z imp $
+
+# pushd, popd, and dirs --- written by Chris Bertin
+# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris
+# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW
+
+pushd () {
+ SAVE=`pwd`
+ if [ "$1" = "" ]
+ then if [ "$DSTACK" = "" ]
+ then echo "pushd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1 || return
+ shift 1
+ DSTACK="$*"
+ else cd $1 > /dev/null || return
+ fi
+ DSTACK="$SAVE $DSTACK"
+ dirs
+}
+
+popd () {
+ if [ "$DSTACK" = "" ]
+ then echo "popd: directory stack empty."
+ return 1
+ fi
+ set $DSTACK
+ cd $1
+ shift
+ DSTACK=$*
+ dirs
+}
+
+dirs () {
+ echo "`pwd` $DSTACK"
+ return 0
+}
diff --git a/shell_cmds/sh/funcs/suspend b/shell_cmds/sh/funcs/suspend
new file mode 100644
index 0000000..99d3109
--- /dev/null
+++ b/shell_cmds/sh/funcs/suspend
@@ -0,0 +1,39 @@
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)suspend 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/funcs/suspend 314436 2017-02-28 23:42:47Z imp $
+
+suspend() {
+ local -
+ set +m
+ kill -TSTP 0
+}
diff --git a/shell_cmds/sh/histedit.c b/shell_cmds/sh/histedit.c
new file mode 100644
index 0000000..f01cabd
--- /dev/null
+++ b/shell_cmds/sh/histedit.c
@@ -0,0 +1,502 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/histedit.c 319635 2017-06-06 21:08:05Z jilles $");
+
+#include <sys/param.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+/*
+ * Editline and history functions (and glue).
+ */
+#include "shell.h"
+#include "parser.h"
+#include "var.h"
+#include "options.h"
+#include "main.h"
+#include "output.h"
+#include "mystring.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#include "error.h"
+#include "eval.h"
+#include "memalloc.h"
+#include "builtins.h"
+
+#define MAXHISTLOOPS 4 /* max recursions through fc */
+#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */
+
+History *hist; /* history cookie */
+EditLine *el; /* editline cookie */
+int displayhist;
+static FILE *el_in, *el_out, *el_err;
+
+static char *fc_replace(const char *, char *, char *);
+static int not_fcnumber(const char *);
+static int str_to_event(const char *, int);
+
+/*
+ * Set history and editing status. Called whenever the status may
+ * have changed (figures out what to do).
+ */
+void
+histedit(void)
+{
+
+#define editing (Eflag || Vflag)
+
+ if (iflag) {
+ if (!hist) {
+ /*
+ * turn history on
+ */
+ INTOFF;
+ hist = history_init();
+ INTON;
+
+ if (hist != NULL)
+ sethistsize(histsizeval());
+ else
+ out2fmt_flush("sh: can't initialize history\n");
+ }
+ if (editing && !el && isatty(0)) { /* && isatty(2) ??? */
+ /*
+ * turn editing on
+ */
+ char *term;
+
+ INTOFF;
+ if (el_in == NULL)
+ el_in = fdopen(0, "r");
+ if (el_err == NULL)
+ el_err = fdopen(1, "w");
+ if (el_out == NULL)
+ el_out = fdopen(2, "w");
+ if (el_in == NULL || el_err == NULL || el_out == NULL)
+ goto bad;
+ term = lookupvar("TERM");
+ if (term)
+ setenv("TERM", term, 1);
+ else
+ unsetenv("TERM");
+ el = el_init(arg0, el_in, el_out, el_err);
+ if (el != NULL) {
+ if (hist)
+ el_set(el, EL_HIST, history, hist);
+ el_set(el, EL_PROMPT, getprompt);
+ el_set(el, EL_ADDFN, "sh-complete",
+ "Filename completion",
+ _el_fn_sh_complete);
+ } else {
+bad:
+ out2fmt_flush("sh: can't initialize editing\n");
+ }
+ INTON;
+ } else if (!editing && el) {
+ INTOFF;
+ el_end(el);
+ el = NULL;
+ INTON;
+ }
+ if (el) {
+ if (Vflag)
+ el_set(el, EL_EDITOR, "vi");
+ else if (Eflag)
+ el_set(el, EL_EDITOR, "emacs");
+ el_set(el, EL_BIND, "^I", "sh-complete", NULL);
+ el_source(el, NULL);
+ }
+ } else {
+ INTOFF;
+ if (el) { /* no editing if not interactive */
+ el_end(el);
+ el = NULL;
+ }
+ if (hist) {
+ history_end(hist);
+ hist = NULL;
+ }
+ INTON;
+ }
+}
+
+
+void
+sethistsize(const char *hs)
+{
+ int histsize;
+ HistEvent he;
+
+ if (hist != NULL) {
+ if (hs == NULL || !is_number(hs))
+ histsize = 100;
+ else
+ histsize = atoi(hs);
+ history(hist, &he, H_SETSIZE, histsize);
+ history(hist, &he, H_SETUNIQUE, 1);
+ }
+}
+
+void
+setterm(const char *term)
+{
+ if (rootshell && el != NULL && term != NULL)
+ el_set(el, EL_TERMINAL, term);
+}
+
+int
+histcmd(int argc, char **argv __unused)
+{
+ int ch;
+ const char *editor = NULL;
+ HistEvent he;
+ int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
+ int i, retval;
+ const char *firststr, *laststr;
+ int first, last, direction;
+ char *pat = NULL, *repl = NULL;
+ static int active = 0;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+ char editfilestr[PATH_MAX];
+ char *volatile editfile;
+ FILE *efp = NULL;
+ int oldhistnum;
+
+ if (hist == NULL)
+ error("history not active");
+
+ if (argc == 1)
+ error("missing history argument");
+
+ while (not_fcnumber(*argptr) && (ch = nextopt("e:lnrs")) != '\0')
+ switch ((char)ch) {
+ case 'e':
+ editor = shoptarg;
+ break;
+ case 'l':
+ lflg = 1;
+ break;
+ case 'n':
+ nflg = 1;
+ break;
+ case 'r':
+ rflg = 1;
+ break;
+ case 's':
+ sflg = 1;
+ break;
+ }
+
+ savehandler = handler;
+ /*
+ * If executing...
+ */
+ if (lflg == 0 || editor || sflg) {
+ lflg = 0; /* ignore */
+ editfile = NULL;
+ /*
+ * Catch interrupts to reset active counter and
+ * cleanup temp files.
+ */
+ if (setjmp(jmploc.loc)) {
+ active = 0;
+ if (editfile)
+ unlink(editfile);
+ handler = savehandler;
+ longjmp(handler->loc, 1);
+ }
+ handler = &jmploc;
+ if (++active > MAXHISTLOOPS) {
+ active = 0;
+ displayhist = 0;
+ error("called recursively too many times");
+ }
+ /*
+ * Set editor.
+ */
+ if (sflg == 0) {
+ if (editor == NULL &&
+ (editor = bltinlookup("FCEDIT", 1)) == NULL &&
+ (editor = bltinlookup("EDITOR", 1)) == NULL)
+ editor = DEFEDITOR;
+ if (editor[0] == '-' && editor[1] == '\0') {
+ sflg = 1; /* no edit */
+ editor = NULL;
+ }
+ }
+ }
+
+ /*
+ * If executing, parse [old=new] now
+ */
+ if (lflg == 0 && *argptr != NULL &&
+ ((repl = strchr(*argptr, '=')) != NULL)) {
+ pat = *argptr;
+ *repl++ = '\0';
+ argptr++;
+ }
+ /*
+ * determine [first] and [last]
+ */
+ if (*argptr == NULL) {
+ firststr = lflg ? "-16" : "-1";
+ laststr = "-1";
+ } else if (argptr[1] == NULL) {
+ firststr = argptr[0];
+ laststr = lflg ? "-1" : argptr[0];
+ } else if (argptr[2] == NULL) {
+ firststr = argptr[0];
+ laststr = argptr[1];
+ } else
+ error("too many arguments");
+ /*
+ * Turn into event numbers.
+ */
+ first = str_to_event(firststr, 0);
+ last = str_to_event(laststr, 1);
+
+ if (rflg) {
+ i = last;
+ last = first;
+ first = i;
+ }
+ /*
+ * XXX - this should not depend on the event numbers
+ * always increasing. Add sequence numbers or offset
+ * to the history element in next (diskbased) release.
+ */
+ direction = first < last ? H_PREV : H_NEXT;
+
+ /*
+ * If editing, grab a temp file.
+ */
+ if (editor) {
+ int fd;
+ INTOFF; /* easier */
+ sprintf(editfilestr, "%s/_shXXXXXX", _PATH_TMP);
+ if ((fd = mkstemp(editfilestr)) < 0)
+ error("can't create temporary file %s", editfile);
+ editfile = editfilestr;
+ if ((efp = fdopen(fd, "w")) == NULL) {
+ close(fd);
+ error("Out of space");
+ }
+ }
+
+ /*
+ * Loop through selected history events. If listing or executing,
+ * do it now. Otherwise, put into temp file and call the editor
+ * after.
+ *
+ * The history interface needs rethinking, as the following
+ * convolutions will demonstrate.
+ */
+ history(hist, &he, H_FIRST);
+ retval = history(hist, &he, H_NEXT_EVENT, first);
+ for (;retval != -1; retval = history(hist, &he, direction)) {
+ if (lflg) {
+ if (!nflg)
+ out1fmt("%5d ", he.num);
+ out1str(he.str);
+ } else {
+ const char *s = pat ?
+ fc_replace(he.str, pat, repl) : he.str;
+
+ if (sflg) {
+ if (displayhist) {
+ out2str(s);
+ flushout(out2);
+ }
+ evalstring(s, 0);
+ if (displayhist && hist) {
+ /*
+ * XXX what about recursive and
+ * relative histnums.
+ */
+ oldhistnum = he.num;
+ history(hist, &he, H_ENTER, s);
+ /*
+ * XXX H_ENTER moves the internal
+ * cursor, set it back to the current
+ * entry.
+ */
+ history(hist, &he,
+ H_NEXT_EVENT, oldhistnum);
+ }
+ } else
+ fputs(s, efp);
+ }
+ /*
+ * At end? (if we were to lose last, we'd sure be
+ * messed up).
+ */
+ if (he.num == last)
+ break;
+ }
+ if (editor) {
+ char *editcmd;
+
+ fclose(efp);
+ INTON;
+ editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
+ sprintf(editcmd, "%s %s", editor, editfile);
+ evalstring(editcmd, 0); /* XXX - should use no JC command */
+ readcmdfile(editfile); /* XXX - should read back - quick tst */
+ unlink(editfile);
+ }
+
+ if (lflg == 0 && active > 0)
+ --active;
+ if (displayhist)
+ displayhist = 0;
+ handler = savehandler;
+ return 0;
+}
+
+static char *
+fc_replace(const char *s, char *p, char *r)
+{
+ char *dest;
+ int plen = strlen(p);
+
+ STARTSTACKSTR(dest);
+ while (*s) {
+ if (*s == *p && strncmp(s, p, plen) == 0) {
+ STPUTS(r, dest);
+ s += plen;
+ *p = '\0'; /* so no more matches */
+ } else
+ STPUTC(*s++, dest);
+ }
+ STPUTC('\0', dest);
+ dest = grabstackstr(dest);
+
+ return (dest);
+}
+
+static int
+not_fcnumber(const char *s)
+{
+ if (s == NULL)
+ return (0);
+ if (*s == '-')
+ s++;
+ return (!is_number(s));
+}
+
+static int
+str_to_event(const char *str, int last)
+{
+ HistEvent he;
+ const char *s = str;
+ int relative = 0;
+ int i, retval;
+
+ retval = history(hist, &he, H_FIRST);
+ switch (*s) {
+ case '-':
+ relative = 1;
+ /*FALLTHROUGH*/
+ case '+':
+ s++;
+ }
+ if (is_number(s)) {
+ i = atoi(s);
+ if (relative) {
+ while (retval != -1 && i--) {
+ retval = history(hist, &he, H_NEXT);
+ }
+ if (retval == -1)
+ retval = history(hist, &he, H_LAST);
+ } else {
+ retval = history(hist, &he, H_NEXT_EVENT, i);
+ if (retval == -1) {
+ /*
+ * the notion of first and last is
+ * backwards to that of the history package
+ */
+ retval = history(hist, &he, last ? H_FIRST : H_LAST);
+ }
+ }
+ if (retval == -1)
+ error("history number %s not found (internal error)",
+ str);
+ } else {
+ /*
+ * pattern
+ */
+ retval = history(hist, &he, H_PREV_STR, str);
+ if (retval == -1)
+ error("history pattern not found: %s", str);
+ }
+ return (he.num);
+}
+
+int
+bindcmd(int argc, char **argv)
+{
+
+ if (el == NULL)
+ error("line editing is disabled");
+ return (el_parse(el, argc, __DECONST(const char **, argv)));
+}
+
+#else
+#include "error.h"
+
+int
+histcmd(int argc, char **argv)
+{
+
+ error("not compiled with history support");
+ /*NOTREACHED*/
+ return (0);
+}
+
+int
+bindcmd(int argc, char **argv)
+{
+
+ error("not compiled with line editing support");
+ return (0);
+}
+#endif
diff --git a/shell_cmds/sh/input.c b/shell_cmds/sh/input.c
new file mode 100644
index 0000000..53376f8
--- /dev/null
+++ b/shell_cmds/sh/input.c
@@ -0,0 +1,536 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/input.c 314436 2017-02-28 23:42:47Z imp $");
+
+#include <stdio.h> /* defines BUFSIZ */
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file implements the input routines used by the parser.
+ */
+
+#include "shell.h"
+#include "redir.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "options.h"
+#include "memalloc.h"
+#include "error.h"
+#include "alias.h"
+#include "parser.h"
+#include "myhistedit.h"
+#include "trap.h"
+
+#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
+
+struct strpush {
+ struct strpush *prev; /* preceding string on stack */
+ const char *prevstring;
+ int prevnleft;
+ int prevlleft;
+ struct alias *ap; /* if push was associated with an alias */
+};
+
+/*
+ * The parsefile structure pointed to by the global variable parsefile
+ * contains information about the current file being read.
+ */
+
+struct parsefile {
+ struct parsefile *prev; /* preceding file on stack */
+ int linno; /* current line */
+ int fd; /* file descriptor (or -1 if string) */
+ int nleft; /* number of chars left in this line */
+ int lleft; /* number of lines left in this buffer */
+ const char *nextc; /* next char in buffer */
+ char *buf; /* input buffer */
+ struct strpush *strpush; /* for pushing strings at this level */
+ struct strpush basestrpush; /* so pushing one is fast */
+};
+
+
+int plinno = 1; /* input line number */
+int parsenleft; /* copy of parsefile->nleft */
+static int parselleft; /* copy of parsefile->lleft */
+const char *parsenextc; /* copy of parsefile->nextc */
+static char basebuf[BUFSIZ + 1];/* buffer for top level input file */
+static struct parsefile basepf = { /* top level input file */
+ .nextc = basebuf,
+ .buf = basebuf
+};
+static struct parsefile *parsefile = &basepf; /* current input file */
+int whichprompt; /* 1 == PS1, 2 == PS2 */
+
+#ifndef __APPLE__
+EditLine *el; /* cookie for editline package */
+#endif /* !__APPLE__ */
+
+static void pushfile(void);
+static int preadfd(void);
+static void popstring(void);
+
+#ifdef __APPLE__
+// Remove when 28988691 is fixed. Added _ to avoid conflict with future libc definition.
+static char *
+strchrnul_(const char *p, int ch)
+{
+ char c;
+
+ c = ch;
+ for (;; ++p) {
+ if (*p == c || *p == '\0')
+ return ((char *)p);
+ }
+ /* NOTREACHED */
+}
+#endif /* __APPLE__ */
+
+void
+resetinput(void)
+{
+ popallfiles();
+ parselleft = parsenleft = 0; /* clear input buffer */
+}
+
+
+
+/*
+ * Read a character from the script, returning PEOF on end of file.
+ * Nul characters in the input are silently discarded.
+ */
+
+int
+pgetc(void)
+{
+ return pgetc_macro();
+}
+
+
+static int
+preadfd(void)
+{
+ int nr;
+ parsenextc = parsefile->buf;
+
+retry:
+#ifndef NO_HISTORY
+ if (parsefile->fd == 0 && el) {
+ static const char *rl_cp;
+ static int el_len;
+
+ if (rl_cp == NULL) {
+ el_resize(el);
+ rl_cp = el_gets(el, &el_len);
+ }
+ if (rl_cp == NULL)
+ nr = el_len == 0 ? 0 : -1;
+ else {
+ nr = el_len;
+ if (nr > BUFSIZ)
+ nr = BUFSIZ;
+ memcpy(parsefile->buf, rl_cp, nr);
+ if (nr != el_len) {
+ el_len -= nr;
+ rl_cp += nr;
+ } else
+ rl_cp = NULL;
+ }
+ } else
+#endif
+ nr = read(parsefile->fd, parsefile->buf, BUFSIZ);
+
+ if (nr <= 0) {
+ if (nr < 0) {
+ if (errno == EINTR)
+ goto retry;
+ if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
+ int flags = fcntl(0, F_GETFL, 0);
+ if (flags >= 0 && flags & O_NONBLOCK) {
+ flags &=~ O_NONBLOCK;
+ if (fcntl(0, F_SETFL, flags) >= 0) {
+ out2fmt_flush("sh: turning off NDELAY mode\n");
+ goto retry;
+ }
+ }
+ }
+ }
+ nr = -1;
+ }
+ return nr;
+}
+
+/*
+ * Refill the input buffer and return the next input character:
+ *
+ * 1) If a string was pushed back on the input, pop it;
+ * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading
+ * from a string so we can't refill the buffer, return EOF.
+ * 3) If there is more in this buffer, use it else call read to fill it.
+ * 4) Process input up to the next newline, deleting nul characters.
+ */
+
+int
+preadbuffer(void)
+{
+ char *p, *q, *r, *end;
+ char savec;
+
+ while (parsefile->strpush) {
+ /*
+ * Add a space to the end of an alias to ensure that the
+ * alias remains in use while parsing its last word.
+ * This avoids alias recursions.
+ */
+ if (parsenleft == -1 && parsefile->strpush->ap != NULL)
+ return ' ';
+ popstring();
+ if (--parsenleft >= 0)
+ return (*parsenextc++);
+ }
+ if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
+ return PEOF;
+
+again:
+ if (parselleft <= 0) {
+ if ((parselleft = preadfd()) == -1) {
+ parselleft = parsenleft = EOF_NLEFT;
+ return PEOF;
+ }
+ }
+
+ p = parsefile->buf + (parsenextc - parsefile->buf);
+ end = p + parselleft;
+ *end = '\0';
+ q = strchrnul_(p, '\n');
+ if (q != end && *q == '\0') {
+ /* delete nul characters */
+ for (r = q; q != end; q++) {
+ if (*q != '\0')
+ *r++ = *q;
+ }
+ parselleft -= end - r;
+ if (parselleft == 0)
+ goto again;
+ end = p + parselleft;
+ *end = '\0';
+ q = strchrnul_(p, '\n');
+ }
+ if (q == end) {
+ parsenleft = parselleft;
+ parselleft = 0;
+ } else /* *q == '\n' */ {
+ q++;
+ parsenleft = q - parsenextc;
+ parselleft -= parsenleft;
+ }
+ parsenleft--;
+
+ savec = *q;
+ *q = '\0';
+
+#ifndef NO_HISTORY
+ if (parsefile->fd == 0 && hist &&
+ parsenextc[strspn(parsenextc, " \t\n")] != '\0') {
+ HistEvent he;
+ INTOFF;
+ history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
+ parsenextc);
+ INTON;
+ }
+#endif
+
+ if (vflag) {
+ out2str(parsenextc);
+ flushout(out2);
+ }
+
+ *q = savec;
+
+ return *parsenextc++;
+}
+
+/*
+ * Returns if we are certain we are at EOF. Does not cause any more input
+ * to be read from the outside world.
+ */
+
+int
+preadateof(void)
+{
+ if (parsenleft > 0)
+ return 0;
+ if (parsefile->strpush)
+ return 0;
+ if (parsenleft == EOF_NLEFT || parsefile->buf == NULL)
+ return 1;
+ return 0;
+}
+
+/*
+ * Undo the last call to pgetc. Only one character may be pushed back.
+ * PEOF may be pushed back.
+ */
+
+void
+pungetc(void)
+{
+ parsenleft++;
+ parsenextc--;
+}
+
+/*
+ * Push a string back onto the input at this current parsefile level.
+ * We handle aliases this way.
+ */
+void
+pushstring(const char *s, int len, struct alias *ap)
+{
+ struct strpush *sp;
+
+ INTOFF;
+/*out2fmt_flush("*** calling pushstring: %s, %d\n", s, len);*/
+ if (parsefile->strpush) {
+ sp = ckmalloc(sizeof (struct strpush));
+ sp->prev = parsefile->strpush;
+ parsefile->strpush = sp;
+ } else
+ sp = parsefile->strpush = &(parsefile->basestrpush);
+ sp->prevstring = parsenextc;
+ sp->prevnleft = parsenleft;
+ sp->prevlleft = parselleft;
+ sp->ap = ap;
+ if (ap)
+ ap->flag |= ALIASINUSE;
+ parsenextc = s;
+ parsenleft = len;
+ INTON;
+}
+
+static void
+popstring(void)
+{
+ struct strpush *sp = parsefile->strpush;
+
+ INTOFF;
+ if (sp->ap) {
+ if (parsenextc != sp->ap->val &&
+ (parsenextc[-1] == ' ' || parsenextc[-1] == '\t'))
+ forcealias();
+ sp->ap->flag &= ~ALIASINUSE;
+ }
+ parsenextc = sp->prevstring;
+ parsenleft = sp->prevnleft;
+ parselleft = sp->prevlleft;
+/*out2fmt_flush("*** calling popstring: restoring to '%s'\n", parsenextc);*/
+ parsefile->strpush = sp->prev;
+ if (sp != &(parsefile->basestrpush))
+ ckfree(sp);
+ INTON;
+}
+
+/*
+ * Set the input to take input from a file. If push is set, push the
+ * old input onto the stack first.
+ */
+
+void
+setinputfile(const char *fname, int push)
+{
+ int fd;
+ int fd2;
+
+ INTOFF;
+ if ((fd = open(fname, O_RDONLY | O_CLOEXEC)) < 0)
+ error("cannot open %s: %s", fname, strerror(errno));
+ if (fd < 10) {
+ fd2 = fcntl(fd, F_DUPFD_CLOEXEC, 10);
+ close(fd);
+ if (fd2 < 0)
+ error("Out of file descriptors");
+ fd = fd2;
+ }
+ setinputfd(fd, push);
+ INTON;
+}
+
+
+/*
+ * Like setinputfile, but takes an open file descriptor (which should have
+ * its FD_CLOEXEC flag already set). Call this with interrupts off.
+ */
+
+void
+setinputfd(int fd, int push)
+{
+ if (push) {
+ pushfile();
+ parsefile->buf = ckmalloc(BUFSIZ + 1);
+ }
+ if (parsefile->fd > 0)
+ close(parsefile->fd);
+ parsefile->fd = fd;
+ if (parsefile->buf == NULL)
+ parsefile->buf = ckmalloc(BUFSIZ + 1);
+ parselleft = parsenleft = 0;
+ plinno = 1;
+}
+
+
+/*
+ * Like setinputfile, but takes input from a string.
+ */
+
+void
+setinputstring(const char *string, int push)
+{
+ INTOFF;
+ if (push)
+ pushfile();
+ parsenextc = string;
+ parselleft = parsenleft = strlen(string);
+ parsefile->buf = NULL;
+ plinno = 1;
+ INTON;
+}
+
+
+
+/*
+ * To handle the "." command, a stack of input files is used. Pushfile
+ * adds a new entry to the stack and popfile restores the previous level.
+ */
+
+static void
+pushfile(void)
+{
+ struct parsefile *pf;
+
+ parsefile->nleft = parsenleft;
+ parsefile->lleft = parselleft;
+ parsefile->nextc = parsenextc;
+ parsefile->linno = plinno;
+ pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile));
+ pf->prev = parsefile;
+ pf->fd = -1;
+ pf->strpush = NULL;
+ pf->basestrpush.prev = NULL;
+ parsefile = pf;
+}
+
+
+void
+popfile(void)
+{
+ struct parsefile *pf = parsefile;
+
+ INTOFF;
+ if (pf->fd >= 0)
+ close(pf->fd);
+ if (pf->buf)
+ ckfree(pf->buf);
+ while (pf->strpush)
+ popstring();
+ parsefile = pf->prev;
+ ckfree(pf);
+ parsenleft = parsefile->nleft;
+ parselleft = parsefile->lleft;
+ parsenextc = parsefile->nextc;
+ plinno = parsefile->linno;
+ INTON;
+}
+
+
+/*
+ * Return current file (to go back to it later using popfilesupto()).
+ */
+
+struct parsefile *
+getcurrentfile(void)
+{
+ return parsefile;
+}
+
+
+/*
+ * Pop files until the given file is on top again. Useful for regular
+ * builtins that read shell commands from files or strings.
+ * If the given file is not an active file, an error is raised.
+ */
+
+void
+popfilesupto(struct parsefile *file)
+{
+ while (parsefile != file && parsefile != &basepf)
+ popfile();
+ if (parsefile != file)
+ error("popfilesupto() misused");
+}
+
+/*
+ * Return to top level.
+ */
+
+void
+popallfiles(void)
+{
+ while (parsefile != &basepf)
+ popfile();
+}
+
+
+
+/*
+ * Close the file(s) that the shell is reading commands from. Called
+ * after a fork is done.
+ */
+
+void
+closescript(void)
+{
+ popallfiles();
+ if (parsefile->fd > 0) {
+ close(parsefile->fd);
+ parsefile->fd = 0;
+ }
+}
diff --git a/shell_cmds/sh/input.h b/shell_cmds/sh/input.h
new file mode 100644
index 0000000..5a47e4b
--- /dev/null
+++ b/shell_cmds/sh/input.h
@@ -0,0 +1,65 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)input.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/input.h 314436 2017-02-28 23:42:47Z imp $
+ */
+
+/* PEOF (the end of file marker) is defined in syntax.h */
+
+/*
+ * The input line number. Input.c just defines this variable, and saves
+ * and restores it when files are pushed and popped. The user of this
+ * package must set its value.
+ */
+extern int plinno;
+extern int parsenleft; /* number of characters left in input buffer */
+extern const char *parsenextc; /* next character in input buffer */
+
+struct alias;
+struct parsefile;
+
+void resetinput(void);
+int pgetc(void);
+int preadbuffer(void);
+int preadateof(void);
+void pungetc(void);
+void pushstring(const char *, int, struct alias *);
+void setinputfile(const char *, int);
+void setinputfd(int, int);
+void setinputstring(const char *, int);
+void popfile(void);
+struct parsefile *getcurrentfile(void);
+void popfilesupto(struct parsefile *);
+void popallfiles(void);
+void closescript(void);
+
+#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
diff --git a/shell_cmds/sh/jobs.c b/shell_cmds/sh/jobs.c
new file mode 100644
index 0000000..358153b
--- /dev/null
+++ b/shell_cmds/sh/jobs.c
@@ -0,0 +1,1552 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/jobs.c 328818 2018-02-02 22:53:58Z jilles $");
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "shell.h"
+#if JOBS
+#include <termios.h>
+#undef CEOF /* syntax.h redefines this */
+#endif
+#include "redir.h"
+#include "exec.h"
+#include "show.h"
+#include "main.h"
+#include "parser.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "options.h"
+#include "trap.h"
+#include "syntax.h"
+#include "input.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "var.h"
+#include "builtins.h"
+
+
+/*
+ * A job structure contains information about a job. A job is either a
+ * single process or a set of processes contained in a pipeline. In the
+ * latter case, pidlist will be non-NULL, and will point to a -1 terminated
+ * array of pids.
+ */
+
+struct procstat {
+ pid_t pid; /* process id */
+ int status; /* status flags (defined above) */
+ char *cmd; /* text of command being run */
+};
+
+
+/* states */
+#define JOBSTOPPED 1 /* all procs are stopped */
+#define JOBDONE 2 /* all procs are completed */
+
+
+struct job {
+ struct procstat ps0; /* status of process */
+ struct procstat *ps; /* status or processes when more than one */
+ short nprocs; /* number of processes */
+ pid_t pgrp; /* process group of this job */
+ char state; /* true if job is finished */
+ char used; /* true if this entry is in used */
+ char changed; /* true if status has changed */
+ char foreground; /* true if running in the foreground */
+ char remembered; /* true if $! referenced */
+#if JOBS
+ char jobctl; /* job running under job control */
+ struct job *next; /* job used after this one */
+#endif
+};
+
+
+static struct job *jobtab; /* array of jobs */
+static int njobs; /* size of array */
+static pid_t backgndpid = -1; /* pid of last background process */
+static struct job *bgjob = NULL; /* last background process */
+#if JOBS
+static struct job *jobmru; /* most recently used job list */
+static pid_t initialpgrp; /* pgrp of shell on invocation */
+#endif
+static int ttyfd = -1;
+
+/* mode flags for dowait */
+#define DOWAIT_BLOCK 0x1 /* wait until a child exits */
+#define DOWAIT_SIG 0x2 /* if DOWAIT_BLOCK, abort on signal */
+#define DOWAIT_SIG_TRAP 0x4 /* if DOWAIT_SIG, abort on trapped signal only */
+
+#if JOBS
+static void restartjob(struct job *);
+#endif
+static void freejob(struct job *);
+static int waitcmdloop(struct job *);
+static struct job *getjob_nonotfound(const char *);
+static struct job *getjob(const char *);
+pid_t killjob(const char *, int);
+static pid_t dowait(int, struct job *);
+static void checkzombies(void);
+static void cmdtxt(union node *);
+static void cmdputs(const char *);
+#if JOBS
+static void setcurjob(struct job *);
+static void deljob(struct job *);
+static struct job *getcurjob(struct job *);
+#endif
+static void printjobcmd(struct job *);
+static void showjob(struct job *, int);
+
+
+/*
+ * Turn job control on and off.
+ */
+
+static int jobctl;
+
+#if JOBS
+static void
+jobctl_notty(void)
+{
+ if (ttyfd >= 0) {
+ close(ttyfd);
+ ttyfd = -1;
+ }
+ if (!iflag) {
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ jobctl = 1;
+ return;
+ }
+ out2fmt_flush("sh: can't access tty; job control turned off\n");
+ mflag = 0;
+}
+
+void
+setjobctl(int on)
+{
+ int i;
+
+ if (on == jobctl || rootshell == 0)
+ return;
+ if (on) {
+ if (ttyfd != -1)
+ close(ttyfd);
+ if ((ttyfd = open(_PATH_TTY, O_RDWR | O_CLOEXEC)) < 0) {
+ i = 0;
+ while (i <= 2 && !isatty(i))
+ i++;
+ if (i > 2 ||
+ (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0) {
+ jobctl_notty();
+ return;
+ }
+ }
+ if (ttyfd < 10) {
+ /*
+ * Keep our TTY file descriptor out of the way of
+ * the user's redirections.
+ */
+ if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) {
+ jobctl_notty();
+ return;
+ }
+ close(ttyfd);
+ ttyfd = i;
+ }
+ do { /* while we are in the background */
+ initialpgrp = tcgetpgrp(ttyfd);
+ if (initialpgrp < 0) {
+ jobctl_notty();
+ return;
+ }
+ if (initialpgrp != getpgrp()) {
+ if (!iflag) {
+ initialpgrp = -1;
+ jobctl_notty();
+ return;
+ }
+ kill(0, SIGTTIN);
+ continue;
+ }
+ } while (0);
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ setpgid(0, rootpid);
+ tcsetpgrp(ttyfd, rootpid);
+ } else { /* turning job control off */
+ setpgid(0, initialpgrp);
+ if (ttyfd >= 0) {
+ tcsetpgrp(ttyfd, initialpgrp);
+ close(ttyfd);
+ ttyfd = -1;
+ }
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ }
+ jobctl = on;
+}
+#endif
+
+
+#if JOBS
+int
+fgcmd(int argc __unused, char **argv __unused)
+{
+ struct job *jp;
+ pid_t pgrp;
+ int status;
+
+ nextopt("");
+ jp = getjob(*argptr);
+ if (jp->jobctl == 0)
+ error("job not created under job control");
+ printjobcmd(jp);
+ flushout(&output);
+ pgrp = jp->ps[0].pid;
+ if (ttyfd >= 0)
+ tcsetpgrp(ttyfd, pgrp);
+ restartjob(jp);
+ jp->foreground = 1;
+ INTOFF;
+ status = waitforjob(jp, (int *)NULL);
+ INTON;
+ return status;
+}
+
+
+int
+bgcmd(int argc __unused, char **argv __unused)
+{
+ struct job *jp;
+
+ nextopt("");
+ do {
+ jp = getjob(*argptr);
+ if (jp->jobctl == 0)
+ error("job not created under job control");
+ if (jp->state == JOBDONE)
+ continue;
+ restartjob(jp);
+ jp->foreground = 0;
+ out1fmt("[%td] ", jp - jobtab + 1);
+ printjobcmd(jp);
+ } while (*argptr != NULL && *++argptr != NULL);
+ return 0;
+}
+
+
+static void
+restartjob(struct job *jp)
+{
+ struct procstat *ps;
+ int i;
+
+ if (jp->state == JOBDONE)
+ return;
+ setcurjob(jp);
+ INTOFF;
+ kill(-jp->ps[0].pid, SIGCONT);
+ for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
+ if (WIFSTOPPED(ps->status)) {
+ ps->status = -1;
+ jp->state = 0;
+ }
+ }
+ INTON;
+}
+#endif
+
+
+int
+jobscmd(int argc __unused, char *argv[] __unused)
+{
+ char *id;
+ int ch, mode;
+
+ mode = SHOWJOBS_DEFAULT;
+ while ((ch = nextopt("lps")) != '\0') {
+ switch (ch) {
+ case 'l':
+ mode = SHOWJOBS_VERBOSE;
+ break;
+ case 'p':
+ mode = SHOWJOBS_PGIDS;
+ break;
+ case 's':
+ mode = SHOWJOBS_PIDS;
+ break;
+ }
+ }
+
+ if (*argptr == NULL)
+ showjobs(0, mode);
+ else
+ while ((id = *argptr++) != NULL)
+ showjob(getjob(id), mode);
+
+ return (0);
+}
+
+static void
+printjobcmd(struct job *jp)
+{
+ struct procstat *ps;
+ int i;
+
+ for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) {
+ out1str(ps->cmd);
+ if (i > 0)
+ out1str(" | ");
+ }
+ out1c('\n');
+}
+
+static void
+showjob(struct job *jp, int mode)
+{
+ char s[64];
+ char statebuf[16];
+ const char *statestr, *coredump;
+ struct procstat *ps;
+ struct job *j;
+ int col, curr, i, jobno, prev, procno, status;
+ char c;
+
+ procno = (mode == SHOWJOBS_PGIDS) ? 1 : jp->nprocs;
+ jobno = jp - jobtab + 1;
+ curr = prev = 0;
+#if JOBS
+ if ((j = getcurjob(NULL)) != NULL) {
+ curr = j - jobtab + 1;
+ if ((j = getcurjob(j)) != NULL)
+ prev = j - jobtab + 1;
+ }
+#endif
+ coredump = "";
+ status = jp->ps[jp->nprocs - 1].status;
+ if (jp->state == 0) {
+ statestr = "Running";
+#if JOBS
+ } else if (jp->state == JOBSTOPPED) {
+ ps = jp->ps + jp->nprocs - 1;
+ while (!WIFSTOPPED(ps->status) && ps > jp->ps)
+ ps--;
+ if (WIFSTOPPED(ps->status))
+ i = WSTOPSIG(ps->status);
+ else
+ i = -1;
+ statestr = strsignal(i);
+ if (statestr == NULL)
+ statestr = "Suspended";
+#endif
+ } else if (WIFEXITED(status)) {
+ if (WEXITSTATUS(status) == 0)
+ statestr = "Done";
+ else {
+ fmtstr(statebuf, sizeof(statebuf), "Done(%d)",
+ WEXITSTATUS(status));
+ statestr = statebuf;
+ }
+ } else {
+ i = WTERMSIG(status);
+ statestr = strsignal(i);
+ if (statestr == NULL)
+ statestr = "Unknown signal";
+ if (WCOREDUMP(status))
+ coredump = " (core dumped)";
+ }
+
+ for (ps = jp->ps ; procno > 0 ; ps++, procno--) { /* for each process */
+ if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) {
+ out1fmt("%d\n", (int)ps->pid);
+ continue;
+ }
+ if (mode != SHOWJOBS_VERBOSE && ps != jp->ps)
+ continue;
+ if (jobno == curr && ps == jp->ps)
+ c = '+';
+ else if (jobno == prev && ps == jp->ps)
+ c = '-';
+ else
+ c = ' ';
+ if (ps == jp->ps)
+ fmtstr(s, 64, "[%d] %c ", jobno, c);
+ else
+ fmtstr(s, 64, " %c ", c);
+ out1str(s);
+ col = strlen(s);
+ if (mode == SHOWJOBS_VERBOSE) {
+ fmtstr(s, 64, "%d ", (int)ps->pid);
+ out1str(s);
+ col += strlen(s);
+ }
+ if (ps == jp->ps) {
+ out1str(statestr);
+ out1str(coredump);
+ col += strlen(statestr) + strlen(coredump);
+ }
+ do {
+ out1c(' ');
+ col++;
+ } while (col < 30);
+ if (mode == SHOWJOBS_VERBOSE) {
+ out1str(ps->cmd);
+ out1c('\n');
+ } else
+ printjobcmd(jp);
+ }
+}
+
+/*
+ * Print a list of jobs. If "change" is nonzero, only print jobs whose
+ * statuses have changed since the last call to showjobs.
+ *
+ * If the shell is interrupted in the process of creating a job, the
+ * result may be a job structure containing zero processes. Such structures
+ * will be freed here.
+ */
+
+void
+showjobs(int change, int mode)
+{
+ int jobno;
+ struct job *jp;
+
+ TRACE(("showjobs(%d) called\n", change));
+ checkzombies();
+ for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) {
+ if (! jp->used)
+ continue;
+ if (jp->nprocs == 0) {
+ freejob(jp);
+ continue;
+ }
+ if (change && ! jp->changed)
+ continue;
+ showjob(jp, mode);
+ if (mode == SHOWJOBS_DEFAULT || mode == SHOWJOBS_VERBOSE) {
+ jp->changed = 0;
+ /* Hack: discard jobs for which $! has not been
+ * referenced in interactive mode when they terminate.
+ */
+ if (jp->state == JOBDONE && !jp->remembered &&
+ (iflag || jp != bgjob)) {
+ freejob(jp);
+ }
+ }
+ }
+}
+
+
+/*
+ * Mark a job structure as unused.
+ */
+
+static void
+freejob(struct job *jp)
+{
+ struct procstat *ps;
+ int i;
+
+ INTOFF;
+ if (bgjob == jp)
+ bgjob = NULL;
+ for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) {
+ if (ps->cmd != nullstr)
+ ckfree(ps->cmd);
+ }
+ if (jp->ps != &jp->ps0)
+ ckfree(jp->ps);
+ jp->used = 0;
+#if JOBS
+ deljob(jp);
+#endif
+ INTON;
+}
+
+
+
+int
+waitcmd(int argc __unused, char **argv __unused)
+{
+ struct job *job;
+ int retval;
+
+ nextopt("");
+ if (*argptr == NULL)
+ return (waitcmdloop(NULL));
+
+ do {
+ job = getjob_nonotfound(*argptr);
+ if (job == NULL)
+ retval = 127;
+ else
+ retval = waitcmdloop(job);
+ argptr++;
+ } while (*argptr != NULL);
+
+ return (retval);
+}
+
+static int
+waitcmdloop(struct job *job)
+{
+ int status, retval, sig;
+ struct job *jp;
+
+ /*
+ * Loop until a process is terminated or stopped, or a SIGINT is
+ * received.
+ */
+
+ do {
+ if (job != NULL) {
+ if (job->state == JOBDONE) {
+ status = job->ps[job->nprocs - 1].status;
+ if (WIFEXITED(status))
+ retval = WEXITSTATUS(status);
+ else
+ retval = WTERMSIG(status) + 128;
+ if (! iflag || ! job->changed)
+ freejob(job);
+ else {
+ job->remembered = 0;
+ if (job == bgjob)
+ bgjob = NULL;
+ }
+ return retval;
+ }
+ } else {
+ for (jp = jobtab ; jp < jobtab + njobs; jp++)
+ if (jp->used && jp->state == JOBDONE) {
+ if (! iflag || ! jp->changed)
+ freejob(jp);
+ else {
+ jp->remembered = 0;
+ if (jp == bgjob)
+ bgjob = NULL;
+ }
+ }
+ for (jp = jobtab ; ; jp++) {
+ if (jp >= jobtab + njobs) { /* no running procs */
+ return 0;
+ }
+ if (jp->used && jp->state == 0)
+ break;
+ }
+ }
+ } while (dowait(DOWAIT_BLOCK | DOWAIT_SIG, (struct job *)NULL) != -1);
+
+ sig = pendingsig_waitcmd;
+ pendingsig_waitcmd = 0;
+ return sig + 128;
+}
+
+
+
+int
+jobidcmd(int argc __unused, char **argv __unused)
+{
+ struct job *jp;
+ int i;
+
+ nextopt("");
+ jp = getjob(*argptr);
+ for (i = 0 ; i < jp->nprocs ; ) {
+ out1fmt("%d", (int)jp->ps[i].pid);
+ out1c(++i < jp->nprocs? ' ' : '\n');
+ }
+ return 0;
+}
+
+
+
+/*
+ * Convert a job name to a job structure.
+ */
+
+static struct job *
+getjob_nonotfound(const char *name)
+{
+ int jobno;
+ struct job *found, *jp;
+ size_t namelen;
+ pid_t pid;
+ int i;
+
+ if (name == NULL) {
+#if JOBS
+ name = "%+";
+#else
+ error("No current job");
+#endif
+ }
+ if (name[0] == '%') {
+ if (is_digit(name[1])) {
+ jobno = number(name + 1);
+ if (jobno > 0 && jobno <= njobs
+ && jobtab[jobno - 1].used != 0)
+ return &jobtab[jobno - 1];
+#if JOBS
+ } else if ((name[1] == '%' || name[1] == '+') &&
+ name[2] == '\0') {
+ if ((jp = getcurjob(NULL)) == NULL)
+ error("No current job");
+ return (jp);
+ } else if (name[1] == '-' && name[2] == '\0') {
+ if ((jp = getcurjob(NULL)) == NULL ||
+ (jp = getcurjob(jp)) == NULL)
+ error("No previous job");
+ return (jp);
+#endif
+ } else if (name[1] == '?') {
+ found = NULL;
+ for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+ if (jp->used && jp->nprocs > 0
+ && strstr(jp->ps[0].cmd, name + 2) != NULL) {
+ if (found)
+ error("%s: ambiguous", name);
+ found = jp;
+ }
+ }
+ if (found != NULL)
+ return (found);
+ } else {
+ namelen = strlen(name);
+ found = NULL;
+ for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+ if (jp->used && jp->nprocs > 0
+ && strncmp(jp->ps[0].cmd, name + 1,
+ namelen - 1) == 0) {
+ if (found)
+ error("%s: ambiguous", name);
+ found = jp;
+ }
+ }
+ if (found)
+ return found;
+ }
+ } else if (is_number(name)) {
+ pid = (pid_t)number(name);
+ for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) {
+ if (jp->used && jp->nprocs > 0
+ && jp->ps[jp->nprocs - 1].pid == pid)
+ return jp;
+ }
+ }
+ return NULL;
+}
+
+
+static struct job *
+getjob(const char *name)
+{
+ struct job *jp;
+
+ jp = getjob_nonotfound(name);
+ if (jp == NULL)
+ error("No such job: %s", name);
+ return (jp);
+}
+
+
+int
+killjob(const char *name, int sig)
+{
+ struct job *jp;
+ int i, ret;
+
+ jp = getjob(name);
+ if (jp->state == JOBDONE)
+ return 0;
+ if (jp->jobctl)
+ return kill(-jp->ps[0].pid, sig);
+ ret = -1;
+ errno = ESRCH;
+ for (i = 0; i < jp->nprocs; i++)
+ if (jp->ps[i].status == -1 || WIFSTOPPED(jp->ps[i].status)) {
+ if (kill(jp->ps[i].pid, sig) == 0)
+ ret = 0;
+ } else
+ ret = 0;
+ return ret;
+}
+
+/*
+ * Return a new job structure,
+ */
+
+struct job *
+makejob(union node *node __unused, int nprocs)
+{
+ int i;
+ struct job *jp;
+
+ for (i = njobs, jp = jobtab ; ; jp++) {
+ if (--i < 0) {
+ INTOFF;
+ if (njobs == 0) {
+ jobtab = ckmalloc(4 * sizeof jobtab[0]);
+#if JOBS
+ jobmru = NULL;
+#endif
+ } else {
+ jp = ckmalloc((njobs + 4) * sizeof jobtab[0]);
+ memcpy(jp, jobtab, njobs * sizeof jp[0]);
+#if JOBS
+ /* Relocate `next' pointers and list head */
+ if (jobmru != NULL)
+ jobmru = &jp[jobmru - jobtab];
+ for (i = 0; i < njobs; i++)
+ if (jp[i].next != NULL)
+ jp[i].next = &jp[jp[i].next -
+ jobtab];
+#endif
+ if (bgjob != NULL)
+ bgjob = &jp[bgjob - jobtab];
+ /* Relocate `ps' pointers */
+ for (i = 0; i < njobs; i++)
+ if (jp[i].ps == &jobtab[i].ps0)
+ jp[i].ps = &jp[i].ps0;
+ ckfree(jobtab);
+ jobtab = jp;
+ }
+ jp = jobtab + njobs;
+ for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0)
+ ;
+ INTON;
+ break;
+ }
+ if (jp->used == 0)
+ break;
+ }
+ INTOFF;
+ jp->state = 0;
+ jp->used = 1;
+ jp->changed = 0;
+ jp->nprocs = 0;
+ jp->foreground = 0;
+ jp->remembered = 0;
+#if JOBS
+ jp->jobctl = jobctl;
+ jp->next = NULL;
+#endif
+ if (nprocs > 1) {
+ jp->ps = ckmalloc(nprocs * sizeof (struct procstat));
+ } else {
+ jp->ps = &jp->ps0;
+ }
+ INTON;
+ TRACE(("makejob(%p, %d) returns %%%td\n", (void *)node, nprocs,
+ jp - jobtab + 1));
+ return jp;
+}
+
+#if JOBS
+static void
+setcurjob(struct job *cj)
+{
+ struct job *jp, *prev;
+
+ for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
+ if (jp == cj) {
+ if (prev != NULL)
+ prev->next = jp->next;
+ else
+ jobmru = jp->next;
+ jp->next = jobmru;
+ jobmru = cj;
+ return;
+ }
+ }
+ cj->next = jobmru;
+ jobmru = cj;
+}
+
+static void
+deljob(struct job *j)
+{
+ struct job *jp, *prev;
+
+ for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) {
+ if (jp == j) {
+ if (prev != NULL)
+ prev->next = jp->next;
+ else
+ jobmru = jp->next;
+ return;
+ }
+ }
+}
+
+/*
+ * Return the most recently used job that isn't `nj', and preferably one
+ * that is stopped.
+ */
+static struct job *
+getcurjob(struct job *nj)
+{
+ struct job *jp;
+
+ /* Try to find a stopped one.. */
+ for (jp = jobmru; jp != NULL; jp = jp->next)
+ if (jp->used && jp != nj && jp->state == JOBSTOPPED)
+ return (jp);
+ /* Otherwise the most recently used job that isn't `nj' */
+ for (jp = jobmru; jp != NULL; jp = jp->next)
+ if (jp->used && jp != nj)
+ return (jp);
+
+ return (NULL);
+}
+
+#endif
+
+/*
+ * Fork of a subshell. If we are doing job control, give the subshell its
+ * own process group. Jp is a job structure that the job is to be added to.
+ * N is the command that will be evaluated by the child. Both jp and n may
+ * be NULL. The mode parameter can be one of the following:
+ * FORK_FG - Fork off a foreground process.
+ * FORK_BG - Fork off a background process.
+ * FORK_NOJOB - Like FORK_FG, but don't give the process its own
+ * process group even if job control is on.
+ *
+ * When job control is turned off, background processes have their standard
+ * input redirected to /dev/null (except for the second and later processes
+ * in a pipeline).
+ */
+
+pid_t
+forkshell(struct job *jp, union node *n, int mode)
+{
+ pid_t pid;
+ pid_t pgrp;
+
+ TRACE(("forkshell(%%%td, %p, %d) called\n", jp - jobtab, (void *)n,
+ mode));
+ INTOFF;
+ if (mode == FORK_BG && (jp == NULL || jp->nprocs == 0))
+ checkzombies();
+ flushall();
+ pid = fork();
+ if (pid == -1) {
+ TRACE(("Fork failed, errno=%d\n", errno));
+ INTON;
+ error("Cannot fork: %s", strerror(errno));
+ }
+ if (pid == 0) {
+ struct job *p;
+ int wasroot;
+ int i;
+
+ TRACE(("Child shell %d\n", (int)getpid()));
+ wasroot = rootshell;
+ rootshell = 0;
+ handler = &main_handler;
+ closescript();
+ INTON;
+ forcelocal = 0;
+ clear_traps();
+#if JOBS
+ jobctl = 0; /* do job control only in root shell */
+ if (wasroot && mode != FORK_NOJOB && mflag) {
+ if (jp == NULL || jp->nprocs == 0)
+ pgrp = getpid();
+ else
+ pgrp = jp->ps[0].pid;
+ if (setpgid(0, pgrp) == 0 && mode == FORK_FG &&
+ ttyfd >= 0) {
+ /*** this causes superfluous TIOCSPGRPS ***/
+ if (tcsetpgrp(ttyfd, pgrp) < 0)
+ error("tcsetpgrp failed, errno=%d", errno);
+ }
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ } else if (mode == FORK_BG) {
+ ignoresig(SIGINT);
+ ignoresig(SIGQUIT);
+ if ((jp == NULL || jp->nprocs == 0) &&
+ ! fd0_redirected_p ()) {
+ close(0);
+ if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+ error("cannot open %s: %s",
+ _PATH_DEVNULL, strerror(errno));
+ }
+ }
+#else
+ if (mode == FORK_BG) {
+ ignoresig(SIGINT);
+ ignoresig(SIGQUIT);
+ if ((jp == NULL || jp->nprocs == 0) &&
+ ! fd0_redirected_p ()) {
+ close(0);
+ if (open(_PATH_DEVNULL, O_RDONLY) != 0)
+ error("cannot open %s: %s",
+ _PATH_DEVNULL, strerror(errno));
+ }
+ }
+#endif
+ INTOFF;
+ for (i = njobs, p = jobtab ; --i >= 0 ; p++)
+ if (p->used)
+ freejob(p);
+ INTON;
+ if (wasroot && iflag) {
+ setsignal(SIGINT);
+ setsignal(SIGQUIT);
+ setsignal(SIGTERM);
+ }
+ return pid;
+ }
+ if (rootshell && mode != FORK_NOJOB && mflag) {
+ if (jp == NULL || jp->nprocs == 0)
+ pgrp = pid;
+ else
+ pgrp = jp->ps[0].pid;
+ setpgid(pid, pgrp);
+ }
+ if (mode == FORK_BG) {
+ if (bgjob != NULL && bgjob->state == JOBDONE &&
+ !bgjob->remembered && !iflag)
+ freejob(bgjob);
+ backgndpid = pid; /* set $! */
+ bgjob = jp;
+ }
+ if (jp) {
+ struct procstat *ps = &jp->ps[jp->nprocs++];
+ ps->pid = pid;
+ ps->status = -1;
+ ps->cmd = nullstr;
+ if (iflag && rootshell && n)
+ ps->cmd = commandtext(n);
+ jp->foreground = mode == FORK_FG;
+#if JOBS
+ setcurjob(jp);
+#endif
+ }
+ INTON;
+ TRACE(("In parent shell: child = %d\n", (int)pid));
+ return pid;
+}
+
+
+pid_t
+vforkexecshell(struct job *jp, char **argv, char **envp, const char *path, int idx, int pip[2])
+{
+ pid_t pid;
+ struct jmploc jmploc;
+ struct jmploc *savehandler;
+
+ TRACE(("vforkexecshell(%%%td, %s, %p) called\n", jp - jobtab, argv[0],
+ (void *)pip));
+ INTOFF;
+ flushall();
+ savehandler = handler;
+ pid = vfork();
+ if (pid == -1) {
+ TRACE(("Vfork failed, errno=%d\n", errno));
+ INTON;
+ error("Cannot fork: %s", strerror(errno));
+ }
+ if (pid == 0) {
+ TRACE(("Child shell %d\n", (int)getpid()));
+ if (setjmp(jmploc.loc))
+ _exit(exception == EXEXEC ? exerrno : 2);
+ if (pip != NULL) {
+ close(pip[0]);
+ if (pip[1] != 1) {
+ dup2(pip[1], 1);
+ close(pip[1]);
+ }
+ }
+ handler = &jmploc;
+ shellexec(argv, envp, path, idx);
+ }
+ handler = savehandler;
+ if (jp) {
+ struct procstat *ps = &jp->ps[jp->nprocs++];
+ ps->pid = pid;
+ ps->status = -1;
+ ps->cmd = nullstr;
+ jp->foreground = 1;
+#if JOBS
+ setcurjob(jp);
+#endif
+ }
+ INTON;
+ TRACE(("In parent shell: child = %d\n", (int)pid));
+ return pid;
+}
+
+
+/*
+ * Wait for job to finish.
+ *
+ * Under job control we have the problem that while a child process is
+ * running interrupts generated by the user are sent to the child but not
+ * to the shell. This means that an infinite loop started by an inter-
+ * active user may be hard to kill. With job control turned off, an
+ * interactive user may place an interactive program inside a loop. If
+ * the interactive program catches interrupts, the user doesn't want
+ * these interrupts to also abort the loop. The approach we take here
+ * is to have the shell ignore interrupt signals while waiting for a
+ * foreground process to terminate, and then send itself an interrupt
+ * signal if the child process was terminated by an interrupt signal.
+ * Unfortunately, some programs want to do a bit of cleanup and then
+ * exit on interrupt; unless these processes terminate themselves by
+ * sending a signal to themselves (instead of calling exit) they will
+ * confuse this approach.
+ */
+
+int
+waitforjob(struct job *jp, int *signaled)
+{
+#if JOBS
+ int propagate_int = jp->jobctl && jp->foreground;
+#endif
+ int status;
+ int st;
+
+ INTOFF;
+ TRACE(("waitforjob(%%%td) called\n", jp - jobtab + 1));
+ while (jp->state == 0)
+ if (dowait(DOWAIT_BLOCK | (Tflag ? DOWAIT_SIG |
+ DOWAIT_SIG_TRAP : 0), jp) == -1)
+ dotrap();
+#if JOBS
+ if (jp->jobctl) {
+ if (ttyfd >= 0 && tcsetpgrp(ttyfd, rootpid) < 0)
+ error("tcsetpgrp failed, errno=%d\n", errno);
+ }
+ if (jp->state == JOBSTOPPED)
+ setcurjob(jp);
+#endif
+ status = jp->ps[jp->nprocs - 1].status;
+ if (signaled != NULL)
+ *signaled = WIFSIGNALED(status);
+ /* convert to 8 bits */
+ if (WIFEXITED(status))
+ st = WEXITSTATUS(status);
+#if JOBS
+ else if (WIFSTOPPED(status))
+ st = WSTOPSIG(status) + 128;
+#endif
+ else
+ st = WTERMSIG(status) + 128;
+ if (! JOBS || jp->state == JOBDONE)
+ freejob(jp);
+ if (int_pending()) {
+ if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGINT)
+ CLEAR_PENDING_INT;
+ }
+#if JOBS
+ else if (rootshell && propagate_int &&
+ WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
+ kill(getpid(), SIGINT);
+#endif
+ INTON;
+ return st;
+}
+
+
+static void
+dummy_handler(int sig __unused)
+{
+}
+
+/*
+ * Wait for a process to terminate.
+ */
+
+static pid_t
+dowait(int mode, struct job *job)
+{
+ struct sigaction sa, osa;
+ sigset_t mask, omask;
+ pid_t pid;
+ int status;
+ struct procstat *sp;
+ struct job *jp;
+ struct job *thisjob;
+ const char *sigstr;
+ int done;
+ int stopped;
+ int sig;
+ int coredump;
+ int wflags;
+ int restore_sigchld;
+
+ TRACE(("dowait(%d, %p) called\n", mode, job));
+ restore_sigchld = 0;
+ if ((mode & DOWAIT_SIG) != 0) {
+ sigfillset(&mask);
+ sigprocmask(SIG_BLOCK, &mask, &omask);
+ INTOFF;
+ if (!issigchldtrapped()) {
+ restore_sigchld = 1;
+ sa.sa_handler = dummy_handler;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGCHLD, &sa, &osa);
+ }
+ }
+ do {
+#if JOBS
+ if (iflag)
+ wflags = WUNTRACED | WCONTINUED;
+ else
+#endif
+ wflags = 0;
+ if ((mode & (DOWAIT_BLOCK | DOWAIT_SIG)) != DOWAIT_BLOCK)
+ wflags |= WNOHANG;
+ pid = wait3(&status, wflags, (struct rusage *)NULL);
+ TRACE(("wait returns %d, status=%d\n", (int)pid, status));
+ if (pid == 0 && (mode & DOWAIT_SIG) != 0) {
+ pid = -1;
+ if (((mode & DOWAIT_SIG_TRAP) != 0 ?
+ pendingsig : pendingsig_waitcmd) != 0) {
+ errno = EINTR;
+ break;
+ }
+ sigsuspend(&omask);
+ if (int_pending())
+ break;
+ }
+ } while (pid == -1 && errno == EINTR);
+ if (pid == -1 && errno == ECHILD && job != NULL)
+ job->state = JOBDONE;
+ if ((mode & DOWAIT_SIG) != 0) {
+ if (restore_sigchld)
+ sigaction(SIGCHLD, &osa, NULL);
+ sigprocmask(SIG_SETMASK, &omask, NULL);
+ INTON;
+ }
+ if (pid <= 0)
+ return pid;
+ INTOFF;
+ thisjob = NULL;
+ for (jp = jobtab ; jp < jobtab + njobs ; jp++) {
+ if (jp->used && jp->nprocs > 0) {
+ done = 1;
+ stopped = 1;
+ for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) {
+ if (sp->pid == -1)
+ continue;
+ if (sp->pid == pid && (sp->status == -1 ||
+ WIFSTOPPED(sp->status))) {
+ TRACE(("Changing status of proc %d from 0x%x to 0x%x\n",
+ (int)pid, sp->status,
+ status));
+ if (WIFCONTINUED(status)) {
+ sp->status = -1;
+ jp->state = 0;
+ } else
+ sp->status = status;
+ thisjob = jp;
+ }
+ if (sp->status == -1)
+ stopped = 0;
+ else if (WIFSTOPPED(sp->status))
+ done = 0;
+ }
+ if (stopped) { /* stopped or done */
+ int state = done? JOBDONE : JOBSTOPPED;
+ if (jp->state != state) {
+ TRACE(("Job %td: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state));
+ jp->state = state;
+ if (jp != job) {
+ if (done && !jp->remembered &&
+ !iflag && jp != bgjob)
+ freejob(jp);
+#if JOBS
+ else if (done)
+ deljob(jp);
+#endif
+ }
+ }
+ }
+ }
+ }
+ INTON;
+ if (!thisjob || thisjob->state == 0)
+ ;
+ else if ((!rootshell || !iflag || thisjob == job) &&
+ thisjob->foreground && thisjob->state != JOBSTOPPED) {
+ sig = 0;
+ coredump = 0;
+ for (sp = thisjob->ps; sp < thisjob->ps + thisjob->nprocs; sp++)
+ if (WIFSIGNALED(sp->status)) {
+ sig = WTERMSIG(sp->status);
+ coredump = WCOREDUMP(sp->status);
+ }
+ if (sig > 0 && sig != SIGINT && sig != SIGPIPE) {
+ sigstr = strsignal(sig);
+ if (sigstr != NULL)
+ out2str(sigstr);
+ else
+ out2str("Unknown signal");
+ if (coredump)
+ out2str(" (core dumped)");
+ out2c('\n');
+ flushout(out2);
+ }
+ } else {
+ TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job));
+ thisjob->changed = 1;
+ }
+ return pid;
+}
+
+
+
+/*
+ * return 1 if there are stopped jobs, otherwise 0
+ */
+int job_warning = 0;
+int
+stoppedjobs(void)
+{
+ int jobno;
+ struct job *jp;
+
+ if (job_warning)
+ return (0);
+ for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) {
+ if (jp->used == 0)
+ continue;
+ if (jp->state == JOBSTOPPED) {
+ out2fmt_flush("You have stopped jobs.\n");
+ job_warning = 2;
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+
+static void
+checkzombies(void)
+{
+ while (njobs > 0 && dowait(0, NULL) > 0)
+ ;
+}
+
+
+int
+backgndpidset(void)
+{
+ return backgndpid != -1;
+}
+
+
+pid_t
+backgndpidval(void)
+{
+ if (bgjob != NULL && !forcelocal)
+ bgjob->remembered = 1;
+ return backgndpid;
+}
+
+/*
+ * Return a string identifying a command (to be printed by the
+ * jobs command.
+ */
+
+static char *cmdnextc;
+static int cmdnleft;
+#define MAXCMDTEXT 200
+
+char *
+commandtext(union node *n)
+{
+ char *name;
+
+ cmdnextc = name = ckmalloc(MAXCMDTEXT);
+ cmdnleft = MAXCMDTEXT - 4;
+ cmdtxt(n);
+ *cmdnextc = '\0';
+ return name;
+}
+
+
+static void
+cmdtxtdogroup(union node *n)
+{
+ cmdputs("; do ");
+ cmdtxt(n);
+ cmdputs("; done");
+}
+
+
+static void
+cmdtxtredir(union node *n, const char *op, int deffd)
+{
+ char s[2];
+
+ if (n->nfile.fd != deffd) {
+ s[0] = n->nfile.fd + '0';
+ s[1] = '\0';
+ cmdputs(s);
+ }
+ cmdputs(op);
+ if (n->type == NTOFD || n->type == NFROMFD) {
+ if (n->ndup.dupfd >= 0)
+ s[0] = n->ndup.dupfd + '0';
+ else
+ s[0] = '-';
+ s[1] = '\0';
+ cmdputs(s);
+ } else {
+ cmdtxt(n->nfile.fname);
+ }
+}
+
+
+static void
+cmdtxt(union node *n)
+{
+ union node *np;
+ struct nodelist *lp;
+
+ if (n == NULL)
+ return;
+ switch (n->type) {
+ case NSEMI:
+ cmdtxt(n->nbinary.ch1);
+ cmdputs("; ");
+ cmdtxt(n->nbinary.ch2);
+ break;
+ case NAND:
+ cmdtxt(n->nbinary.ch1);
+ cmdputs(" && ");
+ cmdtxt(n->nbinary.ch2);
+ break;
+ case NOR:
+ cmdtxt(n->nbinary.ch1);
+ cmdputs(" || ");
+ cmdtxt(n->nbinary.ch2);
+ break;
+ case NPIPE:
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+ cmdtxt(lp->n);
+ if (lp->next)
+ cmdputs(" | ");
+ }
+ break;
+ case NSUBSHELL:
+ cmdputs("(");
+ cmdtxt(n->nredir.n);
+ cmdputs(")");
+ break;
+ case NREDIR:
+ case NBACKGND:
+ cmdtxt(n->nredir.n);
+ break;
+ case NIF:
+ cmdputs("if ");
+ cmdtxt(n->nif.test);
+ cmdputs("; then ");
+ cmdtxt(n->nif.ifpart);
+ cmdputs("...");
+ break;
+ case NWHILE:
+ cmdputs("while ");
+ cmdtxt(n->nbinary.ch1);
+ cmdtxtdogroup(n->nbinary.ch2);
+ break;
+ case NUNTIL:
+ cmdputs("until ");
+ cmdtxt(n->nbinary.ch1);
+ cmdtxtdogroup(n->nbinary.ch2);
+ break;
+ case NFOR:
+ cmdputs("for ");
+ cmdputs(n->nfor.var);
+ cmdputs(" in ...");
+ break;
+ case NCASE:
+ cmdputs("case ");
+ cmdputs(n->ncase.expr->narg.text);
+ cmdputs(" in ...");
+ break;
+ case NDEFUN:
+ cmdputs(n->narg.text);
+ cmdputs("() ...");
+ break;
+ case NNOT:
+ cmdputs("! ");
+ cmdtxt(n->nnot.com);
+ break;
+ case NCMD:
+ for (np = n->ncmd.args ; np ; np = np->narg.next) {
+ cmdtxt(np);
+ if (np->narg.next)
+ cmdputs(" ");
+ }
+ for (np = n->ncmd.redirect ; np ; np = np->nfile.next) {
+ cmdputs(" ");
+ cmdtxt(np);
+ }
+ break;
+ case NARG:
+ cmdputs(n->narg.text);
+ break;
+ case NTO:
+ cmdtxtredir(n, ">", 1);
+ break;
+ case NAPPEND:
+ cmdtxtredir(n, ">>", 1);
+ break;
+ case NTOFD:
+ cmdtxtredir(n, ">&", 1);
+ break;
+ case NCLOBBER:
+ cmdtxtredir(n, ">|", 1);
+ break;
+ case NFROM:
+ cmdtxtredir(n, "<", 0);
+ break;
+ case NFROMTO:
+ cmdtxtredir(n, "<>", 0);
+ break;
+ case NFROMFD:
+ cmdtxtredir(n, "<&", 0);
+ break;
+ case NHERE:
+ case NXHERE:
+ cmdputs("<<...");
+ break;
+ default:
+ cmdputs("???");
+ break;
+ }
+}
+
+
+
+static void
+cmdputs(const char *s)
+{
+ const char *p;
+ char *q;
+ char c;
+ int subtype = 0;
+
+ if (cmdnleft <= 0)
+ return;
+ p = s;
+ q = cmdnextc;
+ while ((c = *p++) != '\0') {
+ if (c == CTLESC)
+ *q++ = *p++;
+ else if (c == CTLVAR) {
+ *q++ = '$';
+ if (--cmdnleft > 0)
+ *q++ = '{';
+ subtype = *p++;
+ if ((subtype & VSTYPE) == VSLENGTH && --cmdnleft > 0)
+ *q++ = '#';
+ } else if (c == '=' && subtype != 0) {
+ *q = "}-+?=##%%\0X"[(subtype & VSTYPE) - VSNORMAL];
+ if (*q)
+ q++;
+ else
+ cmdnleft++;
+ if (((subtype & VSTYPE) == VSTRIMLEFTMAX ||
+ (subtype & VSTYPE) == VSTRIMRIGHTMAX) &&
+ --cmdnleft > 0)
+ *q = q[-1], q++;
+ subtype = 0;
+ } else if (c == CTLENDVAR) {
+ *q++ = '}';
+ } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) {
+ cmdnleft -= 5;
+ if (cmdnleft > 0) {
+ *q++ = '$';
+ *q++ = '(';
+ *q++ = '.';
+ *q++ = '.';
+ *q++ = '.';
+ *q++ = ')';
+ }
+ } else if (c == CTLARI) {
+ cmdnleft -= 2;
+ if (cmdnleft > 0) {
+ *q++ = '$';
+ *q++ = '(';
+ *q++ = '(';
+ }
+ p++;
+ } else if (c == CTLENDARI) {
+ if (--cmdnleft > 0) {
+ *q++ = ')';
+ *q++ = ')';
+ }
+ } else if (c == CTLQUOTEMARK || c == CTLQUOTEEND)
+ cmdnleft++; /* ignore */
+ else
+ *q++ = c;
+ if (--cmdnleft <= 0) {
+ *q++ = '.';
+ *q++ = '.';
+ *q++ = '.';
+ break;
+ }
+ }
+ cmdnextc = q;
+}
diff --git a/shell_cmds/sh/jobs.h b/shell_cmds/sh/jobs.h
new file mode 100644
index 0000000..f6d90a8
--- /dev/null
+++ b/shell_cmds/sh/jobs.h
@@ -0,0 +1,67 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)jobs.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/jobs.h 327475 2018-01-01 22:31:52Z jilles $
+ */
+
+/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
+#define FORK_FG 0
+#define FORK_BG 1
+#define FORK_NOJOB 2
+
+#include <signal.h> /* for sig_atomic_t */
+
+struct job;
+
+enum {
+ SHOWJOBS_DEFAULT, /* job number, status, command */
+ SHOWJOBS_VERBOSE, /* job number, PID, status, command */
+ SHOWJOBS_PIDS, /* PID only */
+ SHOWJOBS_PGIDS /* PID of the group leader only */
+};
+
+extern int job_warning; /* user was warned about stopped jobs */
+
+void setjobctl(int);
+void showjobs(int, int);
+struct job *makejob(union node *, int);
+pid_t forkshell(struct job *, union node *, int);
+pid_t vforkexecshell(struct job *, char **, char **, const char *, int, int []);
+int waitforjob(struct job *, int *);
+int stoppedjobs(void);
+int backgndpidset(void);
+pid_t backgndpidval(void);
+char *commandtext(union node *);
+
+#if ! JOBS
+#define setjobctl(on) /* do nothing */
+#endif
diff --git a/shell_cmds/sh/mail.c b/shell_cmds/sh/mail.c
new file mode 100644
index 0000000..607b407
--- /dev/null
+++ b/shell_cmds/sh/mail.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mail.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/mail.c 314436 2017-02-28 23:42:47Z imp $");
+
+/*
+ * Routines to check for mail. (Perhaps make part of main.c?)
+ */
+
+#include "shell.h"
+#include "exec.h" /* defines padvance() */
+#include "mail.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+
+#define MAXMBOXES 10
+
+
+static int nmboxes; /* number of mailboxes */
+static time_t mailtime[MAXMBOXES]; /* times of mailboxes */
+
+
+
+/*
+ * Print appropriate message(s) if mail has arrived. If the argument is
+ * nozero, then the value of MAIL has changed, so we just update the
+ * values.
+ */
+
+void
+chkmail(int silent)
+{
+ int i;
+ const char *mpath;
+ char *p;
+ char *q;
+ struct stackmark smark;
+ struct stat statb;
+
+ if (silent)
+ nmboxes = 10;
+ if (nmboxes == 0)
+ return;
+ setstackmark(&smark);
+ mpath = mpathset()? mpathval() : mailval();
+ for (i = 0 ; i < nmboxes ; i++) {
+ p = padvance(&mpath, "");
+ if (p == NULL)
+ break;
+ if (*p == '\0')
+ continue;
+ for (q = p ; *q ; q++);
+ if (q[-1] != '/')
+ abort();
+ q[-1] = '\0'; /* delete trailing '/' */
+#ifdef notdef /* this is what the System V shell claims to do (it lies) */
+ if (stat(p, &statb) < 0)
+ statb.st_mtime = 0;
+ if (statb.st_mtime > mailtime[i] && ! silent) {
+ out2str(pathopt? pathopt : "you have mail");
+ out2c('\n');
+ }
+ mailtime[i] = statb.st_mtime;
+#else /* this is what it should do */
+ if (stat(p, &statb) < 0)
+ statb.st_size = 0;
+ if (statb.st_size > mailtime[i] && ! silent) {
+ out2str(pathopt? pathopt : "you have mail");
+ out2c('\n');
+ }
+ mailtime[i] = statb.st_size;
+#endif
+ }
+ nmboxes = i;
+ popstackmark(&smark);
+}
diff --git a/shell_cmds/sh/mail.h b/shell_cmds/sh/mail.h
new file mode 100644
index 0000000..509f11c
--- /dev/null
+++ b/shell_cmds/sh/mail.h
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mail.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/mail.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+void chkmail(int);
diff --git a/shell_cmds/sh/main.c b/shell_cmds/sh/main.c
new file mode 100644
index 0000000..338f97c
--- /dev/null
+++ b/shell_cmds/sh/main.c
@@ -0,0 +1,351 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/main.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <stdio.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <errno.h>
+
+#include "shell.h"
+#include "main.h"
+#include "mail.h"
+#include "options.h"
+#include "output.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h"
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "trap.h"
+#include "var.h"
+#include "show.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "exec.h"
+#include "cd.h"
+#include "redir.h"
+#include "builtins.h"
+
+int rootpid;
+int rootshell;
+struct jmploc main_handler;
+int localeisutf8, initial_localeisutf8;
+
+static void reset(void);
+static void cmdloop(int);
+static void read_profile(const char *);
+static char *find_dot_file(char *);
+
+/*
+ * Main routine. We initialize things, parse the arguments, execute
+ * profiles if we're a login shell, and then call cmdloop to execute
+ * commands. The setjmp call sets up the location to jump to when an
+ * exception occurs. When an exception occurs the variable "state"
+ * is used to figure out how far we had gotten.
+ */
+
+int
+main(int argc, char *argv[])
+{
+ struct stackmark smark, smark2;
+ volatile int state;
+ char *shinit;
+
+ (void) setlocale(LC_ALL, "");
+ initcharset();
+ state = 0;
+ if (setjmp(main_handler.loc)) {
+ switch (exception) {
+ case EXEXEC:
+ exitstatus = exerrno;
+ break;
+
+ case EXERROR:
+ exitstatus = 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (state == 0 || iflag == 0 || ! rootshell ||
+ exception == EXEXIT)
+ exitshell(exitstatus);
+ reset();
+ if (exception == EXINT)
+ out2fmt_flush("\n");
+ popstackmark(&smark);
+ FORCEINTON; /* enable interrupts */
+ if (state == 1)
+ goto state1;
+ else if (state == 2)
+ goto state2;
+ else if (state == 3)
+ goto state3;
+ else
+ goto state4;
+ }
+ handler = &main_handler;
+#ifdef DEBUG
+ opentrace();
+ trputs("Shell args: "); trargs(argv);
+#endif
+ rootpid = getpid();
+ rootshell = 1;
+ INTOFF;
+ initvar();
+ setstackmark(&smark);
+ setstackmark(&smark2);
+ procargs(argc, argv);
+ pwd_init(iflag);
+ INTON;
+ if (iflag)
+ chkmail(1);
+ if (argv[0] && argv[0][0] == '-') {
+ state = 1;
+ read_profile("/etc/profile");
+state1:
+ state = 2;
+ if (privileged == 0)
+ read_profile("${HOME-}/.profile");
+ else
+ read_profile("/etc/suid_profile");
+ }
+state2:
+ state = 3;
+ if (!privileged && iflag) {
+ if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
+ state = 3;
+ read_profile(shinit);
+ }
+ }
+state3:
+ state = 4;
+ popstackmark(&smark2);
+ if (minusc) {
+ evalstring(minusc, sflag ? 0 : EV_EXIT);
+ }
+state4:
+ if (sflag || minusc == NULL) {
+ cmdloop(1);
+ }
+ exitshell(exitstatus);
+ /*NOTREACHED*/
+ return 0;
+}
+
+static void
+reset(void)
+{
+ reseteval();
+ resetinput();
+}
+
+/*
+ * Read and execute commands. "Top" is nonzero for the top level command
+ * loop; it turns on prompting if the shell is interactive.
+ */
+
+static void
+cmdloop(int top)
+{
+ union node *n;
+ struct stackmark smark;
+ int inter;
+ int numeof = 0;
+
+ TRACE(("cmdloop(%d) called\n", top));
+ setstackmark(&smark);
+ for (;;) {
+ if (pendingsig)
+ dotrap();
+ inter = 0;
+ if (iflag && top) {
+ inter++;
+ showjobs(1, SHOWJOBS_DEFAULT);
+ chkmail(0);
+ flushout(&output);
+ }
+ n = parsecmd(inter);
+ /* showtree(n); DEBUG */
+ if (n == NEOF) {
+ if (!top || numeof >= 50)
+ break;
+ if (!stoppedjobs()) {
+ if (!Iflag)
+ break;
+ out2fmt_flush("\nUse \"exit\" to leave shell.\n");
+ }
+ numeof++;
+ } else if (n != NULL && nflag == 0) {
+ job_warning = (job_warning == 2) ? 1 : 0;
+ numeof = 0;
+ evaltree(n, 0);
+ }
+ popstackmark(&smark);
+ setstackmark(&smark);
+ if (evalskip != 0) {
+ if (evalskip == SKIPRETURN)
+ evalskip = 0;
+ break;
+ }
+ }
+ popstackmark(&smark);
+}
+
+
+
+/*
+ * Read /etc/profile or .profile. Return on error.
+ */
+
+static void
+read_profile(const char *name)
+{
+ int fd;
+ const char *expandedname;
+
+ expandedname = expandstr(name);
+ if (expandedname == NULL)
+ return;
+ INTOFF;
+ if ((fd = open(expandedname, O_RDONLY | O_CLOEXEC)) >= 0)
+ setinputfd(fd, 1);
+ INTON;
+ if (fd < 0)
+ return;
+ cmdloop(0);
+ popfile();
+}
+
+
+
+/*
+ * Read a file containing shell functions.
+ */
+
+void
+readcmdfile(const char *name)
+{
+ setinputfile(name, 1);
+ cmdloop(0);
+ popfile();
+}
+
+
+
+/*
+ * Take commands from a file. To be compatible we should do a path
+ * search for the file, which is necessary to find sub-commands.
+ */
+
+
+static char *
+find_dot_file(char *basename)
+{
+ char *fullname;
+ const char *path = pathval();
+ struct stat statb;
+
+ /* don't try this for absolute or relative paths */
+ if( strchr(basename, '/'))
+ return basename;
+
+ while ((fullname = padvance(&path, basename)) != NULL) {
+ if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
+ /*
+ * Don't bother freeing here, since it will
+ * be freed by the caller.
+ */
+ return fullname;
+ }
+ stunalloc(fullname);
+ }
+ return basename;
+}
+
+int
+dotcmd(int argc, char **argv)
+{
+ char *filename, *fullname;
+
+ if (argc < 2)
+ error("missing filename");
+
+ exitstatus = 0;
+
+ /*
+ * Because we have historically not supported any options,
+ * only treat "--" specially.
+ */
+ filename = argc > 2 && strcmp(argv[1], "--") == 0 ? argv[2] : argv[1];
+
+ fullname = find_dot_file(filename);
+ setinputfile(fullname, 1);
+ commandname = fullname;
+ cmdloop(0);
+ popfile();
+ return exitstatus;
+}
+
+
+int
+exitcmd(int argc, char **argv)
+{
+ if (stoppedjobs())
+ return 0;
+ if (argc > 1)
+ exitshell(number(argv[1]));
+ else
+ exitshell_savedstatus();
+}
diff --git a/shell_cmds/sh/main.h b/shell_cmds/sh/main.h
new file mode 100644
index 0000000..ed160cd
--- /dev/null
+++ b/shell_cmds/sh/main.h
@@ -0,0 +1,42 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)main.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/main.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+extern int rootpid; /* pid of main shell */
+extern int rootshell; /* true if we aren't a child of the main shell */
+extern struct jmploc main_handler; /* top level exception handler */
+
+void readcmdfile(const char *);
diff --git a/shell_cmds/sh/memalloc.c b/shell_cmds/sh/memalloc.c
new file mode 100644
index 0000000..7b5f325
--- /dev/null
+++ b/shell_cmds/sh/memalloc.c
@@ -0,0 +1,344 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/memalloc.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <sys/param.h>
+#include "shell.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "expand.h"
+#include <stdlib.h>
+#include <unistd.h>
+
+/*
+ * Like malloc, but returns an error when out of space.
+ */
+
+pointer
+ckmalloc(size_t nbytes)
+{
+ pointer p;
+
+ INTOFF;
+ p = malloc(nbytes);
+ INTON;
+ if (p == NULL)
+ error("Out of space");
+ return p;
+}
+
+
+/*
+ * Same for realloc.
+ */
+
+pointer
+ckrealloc(pointer p, int nbytes)
+{
+ INTOFF;
+ p = realloc(p, nbytes);
+ INTON;
+ if (p == NULL)
+ error("Out of space");
+ return p;
+}
+
+void
+ckfree(pointer p)
+{
+ INTOFF;
+ free(p);
+ INTON;
+}
+
+
+/*
+ * Make a copy of a string in safe storage.
+ */
+
+char *
+savestr(const char *s)
+{
+ char *p;
+ size_t len;
+
+ len = strlen(s);
+ p = ckmalloc(len + 1);
+ memcpy(p, s, len + 1);
+ return p;
+}
+
+
+/*
+ * Parse trees for commands are allocated in lifo order, so we use a stack
+ * to make this more efficient, and also to avoid all sorts of exception
+ * handling code to handle interrupts in the middle of a parse.
+ *
+ * The size 496 was chosen because with 16-byte alignment the total size
+ * for the allocated block is 512.
+ */
+
+#define MINSIZE 496 /* minimum size of a block. */
+
+
+struct stack_block {
+ struct stack_block *prev;
+ /* Data follows */
+};
+#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block)))
+
+static struct stack_block *stackp;
+char *stacknxt;
+int stacknleft;
+char *sstrend;
+
+
+static void
+stnewblock(int nbytes)
+{
+ struct stack_block *sp;
+ int allocsize;
+
+ if (nbytes < MINSIZE)
+ nbytes = MINSIZE;
+
+ allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes);
+
+ INTOFF;
+ sp = ckmalloc(allocsize);
+ sp->prev = stackp;
+ stacknxt = SPACE(sp);
+ stacknleft = allocsize - (stacknxt - (char*)sp);
+ sstrend = stacknxt + stacknleft;
+ stackp = sp;
+ INTON;
+}
+
+
+pointer
+stalloc(int nbytes)
+{
+ char *p;
+
+ nbytes = ALIGN(nbytes);
+ if (nbytes > stacknleft)
+ stnewblock(nbytes);
+ p = stacknxt;
+ stacknxt += nbytes;
+ stacknleft -= nbytes;
+ return p;
+}
+
+
+void
+stunalloc(pointer p)
+{
+ if (p == NULL) { /*DEBUG */
+ write(STDERR_FILENO, "stunalloc\n", 10);
+ abort();
+ }
+ stacknleft += stacknxt - (char *)p;
+ stacknxt = p;
+}
+
+
+char *
+stsavestr(const char *s)
+{
+ char *p;
+ size_t len;
+
+ len = strlen(s);
+ p = stalloc(len + 1);
+ memcpy(p, s, len + 1);
+ return p;
+}
+
+
+void
+setstackmark(struct stackmark *mark)
+{
+ mark->stackp = stackp;
+ mark->stacknxt = stacknxt;
+ mark->stacknleft = stacknleft;
+ /* Ensure this block stays in place. */
+ if (stackp != NULL && stacknxt == SPACE(stackp))
+ stalloc(1);
+}
+
+
+void
+popstackmark(struct stackmark *mark)
+{
+ struct stack_block *sp;
+
+ INTOFF;
+ while (stackp != mark->stackp) {
+ sp = stackp;
+ stackp = sp->prev;
+ ckfree(sp);
+ }
+ stacknxt = mark->stacknxt;
+ stacknleft = mark->stacknleft;
+ sstrend = stacknxt + stacknleft;
+ INTON;
+}
+
+
+/*
+ * When the parser reads in a string, it wants to stick the string on the
+ * stack and only adjust the stack pointer when it knows how big the
+ * string is. Stackblock (defined in stack.h) returns a pointer to a block
+ * of space on top of the stack and stackblocklen returns the length of
+ * this block. Growstackblock will grow this space by at least one byte,
+ * possibly moving it (like realloc). Grabstackblock actually allocates the
+ * part of the block that has been used.
+ */
+
+static void
+growstackblock(int min)
+{
+ char *p;
+ int newlen;
+ char *oldspace;
+ int oldlen;
+ struct stack_block *sp;
+ struct stack_block *oldstackp;
+
+ if (min < stacknleft)
+ min = stacknleft;
+ if ((unsigned int)min >=
+ INT_MAX / 2 - ALIGN(sizeof(struct stack_block)))
+ error("Out of space");
+ min += stacknleft;
+ min += ALIGN(sizeof(struct stack_block));
+ newlen = 512;
+ while (newlen < min)
+ newlen <<= 1;
+ oldspace = stacknxt;
+ oldlen = stacknleft;
+
+ if (stackp != NULL && stacknxt == SPACE(stackp)) {
+ INTOFF;
+ oldstackp = stackp;
+ stackp = oldstackp->prev;
+ sp = ckrealloc((pointer)oldstackp, newlen);
+ sp->prev = stackp;
+ stackp = sp;
+ stacknxt = SPACE(sp);
+ stacknleft = newlen - (stacknxt - (char*)sp);
+ sstrend = stacknxt + stacknleft;
+ INTON;
+ } else {
+ newlen -= ALIGN(sizeof(struct stack_block));
+ p = stalloc(newlen);
+ if (oldlen != 0)
+ memcpy(p, oldspace, oldlen);
+ stunalloc(p);
+ }
+}
+
+
+
+/*
+ * The following routines are somewhat easier to use that the above.
+ * The user declares a variable of type STACKSTR, which may be declared
+ * to be a register. The macro STARTSTACKSTR initializes things. Then
+ * the user uses the macro STPUTC to add characters to the string. In
+ * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
+ * grown as necessary. When the user is done, she can just leave the
+ * string there and refer to it using stackblock(). Or she can allocate
+ * the space for it using grabstackstr(). If it is necessary to allow
+ * someone else to use the stack temporarily and then continue to grow
+ * the string, the user should use grabstack to allocate the space, and
+ * then call ungrabstr(p) to return to the previous mode of operation.
+ *
+ * USTPUTC is like STPUTC except that it doesn't check for overflow.
+ * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
+ * is space for at least one character.
+ */
+
+static char *
+growstrstackblock(int n, int min)
+{
+ growstackblock(min);
+ return stackblock() + n;
+}
+
+char *
+growstackstr(void)
+{
+ int len;
+
+ len = stackblocksize();
+ return (growstrstackblock(len, 0));
+}
+
+
+/*
+ * Called from CHECKSTRSPACE.
+ */
+
+char *
+makestrspace(int min, char *p)
+{
+ int len;
+
+ len = p - stackblock();
+ return (growstrstackblock(len, min));
+}
+
+
+char *
+stputbin(const char *data, size_t len, char *p)
+{
+ CHECKSTRSPACE(len, p);
+ memcpy(p, data, len);
+ return (p + len);
+}
+
+char *
+stputs(const char *data, char *p)
+{
+ return (stputbin(data, strlen(data), p));
+}
diff --git a/shell_cmds/sh/memalloc.h b/shell_cmds/sh/memalloc.h
new file mode 100644
index 0000000..180abfd
--- /dev/null
+++ b/shell_cmds/sh/memalloc.h
@@ -0,0 +1,88 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)memalloc.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/memalloc.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#include <string.h>
+
+struct stackmark {
+ struct stack_block *stackp;
+ char *stacknxt;
+ int stacknleft;
+};
+
+
+extern char *stacknxt;
+extern int stacknleft;
+extern char *sstrend;
+
+pointer ckmalloc(size_t);
+pointer ckrealloc(pointer, int);
+void ckfree(pointer);
+char *savestr(const char *);
+pointer stalloc(int);
+void stunalloc(pointer);
+char *stsavestr(const char *);
+void setstackmark(struct stackmark *);
+void popstackmark(struct stackmark *);
+char *growstackstr(void);
+char *makestrspace(int, char *);
+char *stputbin(const char *data, size_t len, char *p);
+char *stputs(const char *data, char *p);
+
+
+
+#define stackblock() stacknxt
+#define stackblocksize() stacknleft
+#define grabstackblock(n) stalloc(n)
+#define STARTSTACKSTR(p) p = stackblock()
+#define STPUTC(c, p) do { if (p == sstrend) p = growstackstr(); *p++ = (c); } while(0)
+#define CHECKSTRSPACE(n, p) { if ((size_t)(sstrend - p) < n) p = makestrspace(n, p); }
+#define USTPUTC(c, p) (*p++ = (c))
+/*
+ * STACKSTRNUL's use is where we want to be able to turn a stack
+ * (non-sentinel, character counting string) into a C string,
+ * and later pretend the NUL is not there.
+ * Note: Because of STACKSTRNUL's semantics, STACKSTRNUL cannot be used
+ * on a stack that will grabstackstr()ed.
+ */
+#define STACKSTRNUL(p) (p == sstrend ? (p = growstackstr(), *p = '\0') : (*p = '\0'))
+#define STUNPUTC(p) (--p)
+#define STTOPC(p) p[-1]
+#define STADJUST(amount, p) (p += (amount))
+#define grabstackstr(p) stalloc((char *)p - stackblock())
+#define ungrabstackstr(s, p) stunalloc((s))
+#define STPUTBIN(s, len, p) p = stputbin((s), (len), p)
+#define STPUTS(s, p) p = stputs((s), p)
diff --git a/shell_cmds/sh/miscbltin.c b/shell_cmds/sh/miscbltin.c
new file mode 100644
index 0000000..52a810a
--- /dev/null
+++ b/shell_cmds/sh/miscbltin.c
@@ -0,0 +1,534 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/miscbltin.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * Miscellaneous builtins.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "options.h"
+#include "var.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "syntax.h"
+#include "trap.h"
+
+#undef eflag
+
+int readcmd(int, char **);
+int umaskcmd(int, char **);
+int ulimitcmd(int, char **);
+
+/*
+ * The read builtin. The -r option causes backslashes to be treated like
+ * ordinary characters.
+ *
+ * This uses unbuffered input, which may be avoidable in some cases.
+ *
+ * Note that if IFS=' :' then read x y should work so that:
+ * 'a b' x='a', y='b'
+ * ' a b ' x='a', y='b'
+ * ':b' x='', y='b'
+ * ':' x='', y=''
+ * '::' x='', y=''
+ * ': :' x='', y=''
+ * ':::' x='', y='::'
+ * ':b c:' x='', y='b c:'
+ */
+
+int
+readcmd(int argc __unused, char **argv __unused)
+{
+ char **ap;
+ int backslash;
+ char c;
+ int rflag;
+ char *prompt;
+ const char *ifs;
+ char *p;
+ int startword;
+ int status;
+ int i;
+ int is_ifs;
+ int saveall = 0;
+ ptrdiff_t lastnonifs, lastnonifsws;
+ struct timeval tv;
+ char *tvptr;
+ fd_set ifds;
+ ssize_t nread;
+ int sig;
+
+ rflag = 0;
+ prompt = NULL;
+ tv.tv_sec = -1;
+ tv.tv_usec = 0;
+ while ((i = nextopt("erp:t:")) != '\0') {
+ switch(i) {
+ case 'p':
+ prompt = shoptarg;
+ break;
+ case 'e':
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 't':
+ tv.tv_sec = strtol(shoptarg, &tvptr, 0);
+ if (tvptr == shoptarg)
+ error("timeout value");
+ switch(*tvptr) {
+ case 0:
+ case 's':
+ break;
+ case 'h':
+ tv.tv_sec *= 60;
+ /* FALLTHROUGH */
+ case 'm':
+ tv.tv_sec *= 60;
+ break;
+ default:
+ error("timeout unit");
+ }
+ break;
+ }
+ }
+ if (prompt && isatty(0)) {
+ out2str(prompt);
+ flushall();
+ }
+ if (*(ap = argptr) == NULL)
+ error("arg count");
+ if ((ifs = bltinlookup("IFS", 1)) == NULL)
+ ifs = " \t\n";
+
+ if (tv.tv_sec >= 0) {
+ /*
+ * Wait for something to become available.
+ */
+ FD_ZERO(&ifds);
+ FD_SET(0, &ifds);
+ status = select(1, &ifds, NULL, NULL, &tv);
+ /*
+ * If there's nothing ready, return an error.
+ */
+ if (status <= 0) {
+ sig = pendingsig;
+ return (128 + (sig != 0 ? sig : SIGALRM));
+ }
+ }
+
+ status = 0;
+ startword = 2;
+ backslash = 0;
+ STARTSTACKSTR(p);
+ lastnonifs = lastnonifsws = -1;
+ for (;;) {
+ nread = read(STDIN_FILENO, &c, 1);
+ if (nread == -1) {
+ if (errno == EINTR) {
+ sig = pendingsig;
+ if (sig == 0)
+ continue;
+ status = 128 + sig;
+ break;
+ }
+ warning("read error: %s", strerror(errno));
+ status = 2;
+ break;
+ } else if (nread != 1) {
+ status = 1;
+ break;
+ }
+ if (c == '\0')
+ continue;
+ CHECKSTRSPACE(1, p);
+ if (backslash) {
+ backslash = 0;
+ if (c != '\n') {
+ startword = 0;
+ lastnonifs = lastnonifsws = p - stackblock();
+ USTPUTC(c, p);
+ }
+ continue;
+ }
+ if (!rflag && c == '\\') {
+ backslash++;
+ continue;
+ }
+ if (c == '\n')
+ break;
+ if (strchr(ifs, c))
+ is_ifs = strchr(" \t\n", c) ? 1 : 2;
+ else
+ is_ifs = 0;
+
+ if (startword != 0) {
+ if (is_ifs == 1) {
+ /* Ignore leading IFS whitespace */
+ if (saveall)
+ USTPUTC(c, p);
+ continue;
+ }
+ if (is_ifs == 2 && startword == 1) {
+ /* Only one non-whitespace IFS per word */
+ startword = 2;
+ if (saveall) {
+ lastnonifsws = p - stackblock();
+ USTPUTC(c, p);
+ }
+ continue;
+ }
+ }
+
+ if (is_ifs == 0) {
+ /* append this character to the current variable */
+ startword = 0;
+ if (saveall)
+ /* Not just a spare terminator */
+ saveall++;
+ lastnonifs = lastnonifsws = p - stackblock();
+ USTPUTC(c, p);
+ continue;
+ }
+
+ /* end of variable... */
+ startword = is_ifs;
+
+ if (ap[1] == NULL) {
+ /* Last variable needs all IFS chars */
+ saveall++;
+ if (is_ifs == 2)
+ lastnonifsws = p - stackblock();
+ USTPUTC(c, p);
+ continue;
+ }
+
+ STACKSTRNUL(p);
+ setvar(*ap, stackblock(), 0);
+ ap++;
+ STARTSTACKSTR(p);
+ lastnonifs = lastnonifsws = -1;
+ }
+ STACKSTRNUL(p);
+
+ /*
+ * Remove trailing IFS chars: always remove whitespace, don't remove
+ * non-whitespace unless it was naked
+ */
+ if (saveall <= 1)
+ lastnonifsws = lastnonifs;
+ stackblock()[lastnonifsws + 1] = '\0';
+ setvar(*ap, stackblock(), 0);
+
+ /* Set any remaining args to "" */
+ while (*++ap != NULL)
+ setvar(*ap, "", 0);
+ return status;
+}
+
+
+
+int
+umaskcmd(int argc __unused, char **argv __unused)
+{
+ char *ap;
+ int mask;
+ int i;
+ int symbolic_mode = 0;
+
+ while ((i = nextopt("S")) != '\0') {
+ symbolic_mode = 1;
+ }
+
+ INTOFF;
+ mask = umask(0);
+ umask(mask);
+ INTON;
+
+ if ((ap = *argptr) == NULL) {
+ if (symbolic_mode) {
+ char u[4], g[4], o[4];
+
+ i = 0;
+ if ((mask & S_IRUSR) == 0)
+ u[i++] = 'r';
+ if ((mask & S_IWUSR) == 0)
+ u[i++] = 'w';
+ if ((mask & S_IXUSR) == 0)
+ u[i++] = 'x';
+ u[i] = '\0';
+
+ i = 0;
+ if ((mask & S_IRGRP) == 0)
+ g[i++] = 'r';
+ if ((mask & S_IWGRP) == 0)
+ g[i++] = 'w';
+ if ((mask & S_IXGRP) == 0)
+ g[i++] = 'x';
+ g[i] = '\0';
+
+ i = 0;
+ if ((mask & S_IROTH) == 0)
+ o[i++] = 'r';
+ if ((mask & S_IWOTH) == 0)
+ o[i++] = 'w';
+ if ((mask & S_IXOTH) == 0)
+ o[i++] = 'x';
+ o[i] = '\0';
+
+ out1fmt("u=%s,g=%s,o=%s\n", u, g, o);
+ } else {
+ out1fmt("%.4o\n", mask);
+ }
+ } else {
+ if (is_digit(*ap)) {
+ mask = 0;
+ do {
+ if (*ap >= '8' || *ap < '0')
+ error("Illegal number: %s", *argptr);
+ mask = (mask << 3) + (*ap - '0');
+ } while (*++ap != '\0');
+ umask(mask);
+ } else {
+ void *set;
+ INTOFF;
+ if ((set = setmode (ap)) == NULL)
+ error("Illegal number: %s", ap);
+
+ mask = getmode (set, ~mask & 0777);
+ umask(~mask & 0777);
+ free(set);
+ INTON;
+ }
+ }
+ return 0;
+}
+
+/*
+ * ulimit builtin
+ *
+ * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and
+ * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with
+ * ash by J.T. Conklin.
+ *
+ * Public domain.
+ */
+
+struct limits {
+ const char *name;
+ const char *units;
+ int cmd;
+ short factor; /* multiply by to get rlim_{cur,max} values */
+ char option;
+};
+
+static const struct limits limits[] = {
+#ifdef RLIMIT_CPU
+ { "cpu time", "seconds", RLIMIT_CPU, 1, 't' },
+#endif
+#ifdef RLIMIT_FSIZE
+ { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' },
+#endif
+#ifdef RLIMIT_DATA
+ { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' },
+#endif
+#ifdef RLIMIT_STACK
+ { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' },
+#endif
+#ifdef RLIMIT_CORE
+ { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' },
+#endif
+#ifdef RLIMIT_RSS
+ { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' },
+#endif
+#ifdef RLIMIT_MEMLOCK
+ { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' },
+#endif
+#ifdef RLIMIT_NPROC
+ { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' },
+#endif
+#ifdef RLIMIT_NOFILE
+ { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' },
+#endif
+#ifdef RLIMIT_VMEM
+ { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' },
+#endif
+#ifdef RLIMIT_SWAP
+ { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' },
+#endif
+#ifdef RLIMIT_SBSIZE
+ { "socket buffer size", "bytes", RLIMIT_SBSIZE, 1, 'b' },
+#endif
+#ifdef RLIMIT_NPTS
+ { "pseudo-terminals", (char *)0, RLIMIT_NPTS, 1, 'p' },
+#endif
+#ifdef RLIMIT_KQUEUES
+ { "kqueues", (char *)0, RLIMIT_KQUEUES, 1, 'k' },
+#endif
+#ifdef RLIMIT_UMTXP
+ { "umtx shared locks", (char *)0, RLIMIT_UMTXP, 1, 'o' },
+#endif
+ { (char *) 0, (char *)0, 0, 0, '\0' }
+};
+
+enum limithow { SOFT = 0x1, HARD = 0x2 };
+
+static void
+printlimit(enum limithow how, const struct rlimit *limit,
+ const struct limits *l)
+{
+ rlim_t val = 0;
+
+ if (how & SOFT)
+ val = limit->rlim_cur;
+ else if (how & HARD)
+ val = limit->rlim_max;
+ if (val == RLIM_INFINITY)
+ out1str("unlimited\n");
+ else
+ {
+ val /= l->factor;
+ out1fmt("%jd\n", (intmax_t)val);
+ }
+}
+
+int
+ulimitcmd(int argc __unused, char **argv __unused)
+{
+ rlim_t val = 0;
+ enum limithow how = SOFT | HARD;
+ const struct limits *l;
+ int set, all = 0;
+ int optc, what;
+ struct rlimit limit;
+
+ what = 'f';
+ while ((optc = nextopt("HSatfdsmcnuvlbpwko")) != '\0')
+ switch (optc) {
+ case 'H':
+ how = HARD;
+ break;
+ case 'S':
+ how = SOFT;
+ break;
+ case 'a':
+ all = 1;
+ break;
+ default:
+ what = optc;
+ }
+
+ for (l = limits; l->name && l->option != what; l++)
+ ;
+ if (!l->name)
+ error("internal error (%c)", what);
+
+ set = *argptr ? 1 : 0;
+ if (set) {
+ char *p = *argptr;
+
+ if (all || argptr[1])
+ error("too many arguments");
+ if (strcmp(p, "unlimited") == 0)
+ val = RLIM_INFINITY;
+ else {
+ char *end;
+ uintmax_t uval;
+
+ if (*p < '0' || *p > '9')
+ error("bad number");
+ errno = 0;
+ uval = strtoumax(p, &end, 10);
+ if (errno != 0 || *end != '\0')
+ error("bad number");
+ if (uval > UINTMAX_MAX / l->factor)
+ error("bad number");
+ uval *= l->factor;
+ val = (rlim_t)uval;
+ if ((uintmax_t)val != uval ||
+ val == RLIM_INFINITY)
+ error("bad number");
+ }
+ }
+ if (all) {
+ for (l = limits; l->name; l++) {
+ char optbuf[40];
+ if (getrlimit(l->cmd, &limit) < 0)
+ error("can't get limit: %s", strerror(errno));
+
+ if (l->units)
+ snprintf(optbuf, sizeof(optbuf),
+ "(%s, -%c) ", l->units, l->option);
+ else
+ snprintf(optbuf, sizeof(optbuf),
+ "(-%c) ", l->option);
+ out1fmt("%-18s %18s ", l->name, optbuf);
+ printlimit(how, &limit, l);
+ }
+ return 0;
+ }
+
+ if (getrlimit(l->cmd, &limit) < 0)
+ error("can't get limit: %s", strerror(errno));
+ if (set) {
+ if (how & SOFT)
+ limit.rlim_cur = val;
+ if (how & HARD)
+ limit.rlim_max = val;
+ if (setrlimit(l->cmd, &limit) < 0)
+ error("bad limit: %s", strerror(errno));
+ } else
+ printlimit(how, &limit, l);
+ return 0;
+}
diff --git a/shell_cmds/sh/mkbuiltins b/shell_cmds/sh/mkbuiltins
new file mode 100755
index 0000000..7c2cef1
--- /dev/null
+++ b/shell_cmds/sh/mkbuiltins
@@ -0,0 +1,137 @@
+#!/bin/sh -
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/mkbuiltins 328934 2018-02-06 15:41:35Z arichardson $
+
+temp=`mktemp -t ka`
+havehist=1
+if [ "X$1" = "X-h" ]; then
+ havehist=0
+ shift
+fi
+srcdir=$1
+havejobs=0
+if grep '^#define[ ]*JOBS[ ]*1' $srcdir/shell.h > /dev/null
+then havejobs=1
+fi
+exec > builtins.c
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+#include <stdlib.h>
+#include "shell.h"
+#include "builtins.h"
+
+!
+awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \
+ print $0}' $srcdir/builtins.def | sed 's/-[hj]//' > $temp
+echo 'int (*const builtinfunc[])(int, char **) = {'
+awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp
+echo '};
+
+const unsigned char builtincmd[] = {'
+awk '{ for (i = 2 ; i <= NF ; i++) {
+ if ($i == "-s") {
+ spc = 1;
+ } else if ($i == "-n") {
+ # Handled later for builtins.h
+ continue
+ } else {
+ printf "\t\"\\%03o\\%03o%s\"\n", length($i), (spc ? 128 : 0) + NR-1, $i
+ spc = 0;
+ }
+ }}' $temp
+echo '};'
+
+exec > builtins.h
+cat <<\!
+/*
+ * This file was generated by the mkbuiltins program.
+ */
+
+#include <sys/cdefs.h>
+!
+tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp |
+ awk '{ printf "#define %s %d\n", $1, NR-1}'
+echo '
+#define BUILTIN_SPECIAL 0x80
+
+extern int (*const builtinfunc[])(int, char **);
+extern const unsigned char builtincmd[];
+'
+awk '{ printf "int %s(int, char **);\n", $1}' $temp
+
+# Build safe_builtin_always()
+cat <<EOF
+
+static inline int
+safe_builtin_always(int idx)
+{
+EOF
+awk '
+BEGIN { printed = 0 }
+{
+ for (i = 2 ; i <= NF ; i++) {
+ if ($i == "-s") {
+ continue
+ } else if ($i == "-n") {
+ nofork = 1;
+ } else {
+ if (nofork == 0) {
+ continue
+ }
+ if (printed == 1) {
+ printf " || \n\t "
+ } else {
+ printf "\tif ("
+ }
+ printf "idx == " toupper($1)
+ printed = 1
+ nofork = 0;
+ # Only need to check each once
+ break
+ }
+ }
+}' $temp
+
+cat << EOF
+)
+ return (1);
+ return(0);
+}
+EOF
+
+rm -f $temp
diff --git a/shell_cmds/sh/mknodes.c b/shell_cmds/sh/mknodes.c
new file mode 100644
index 0000000..f289890
--- /dev/null
+++ b/shell_cmds/sh/mknodes.c
@@ -0,0 +1,467 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mknodes.c 8.2 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/mknodes.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * This program reads the nodetypes file and nodes.c.pat file. It generates
+ * the files nodes.h and nodes.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+// When building for iOS, we don't have a new enough OS X SDK.
+#ifndef __printf0like
+#define __printf0like(fmtarg, firstvararg) \
+__attribute__((__format__ (__printf0__, fmtarg, firstvararg)))
+#endif
+
+#define MAXTYPES 50 /* max number of node types */
+#define MAXFIELDS 20 /* max fields in a structure */
+#define BUFLEN 100 /* size of character buffers */
+
+/* field types */
+#define T_NODE 1 /* union node *field */
+#define T_NODELIST 2 /* struct nodelist *field */
+#define T_STRING 3
+#define T_INT 4 /* int field */
+#define T_OTHER 5 /* other */
+#define T_TEMP 6 /* don't copy this field */
+
+
+struct field { /* a structure field */
+ char *name; /* name of field */
+ int type; /* type of field */
+ char *decl; /* declaration of field */
+};
+
+
+struct str { /* struct representing a node structure */
+ char *tag; /* structure tag */
+ int nfields; /* number of fields in the structure */
+ struct field field[MAXFIELDS]; /* the fields of the structure */
+ int done; /* set if fully parsed */
+};
+
+
+static int ntypes; /* number of node types */
+static char *nodename[MAXTYPES]; /* names of the nodes */
+static struct str *nodestr[MAXTYPES]; /* type of structure used by the node */
+static int nstr; /* number of structures */
+static struct str str[MAXTYPES]; /* the structures */
+static struct str *curstr; /* current structure */
+static char line[1024];
+static int linno;
+static char *linep;
+
+static void parsenode(void);
+static void parsefield(void);
+static void output(char *);
+static void outsizes(FILE *);
+static void outfunc(FILE *, int);
+static void indent(int, FILE *);
+static int nextfield(char *);
+static void skipbl(void);
+static int readline(FILE *);
+static void error(const char *, ...) __printf0like(1, 2) __dead2;
+static char *savestr(const char *);
+
+
+int
+main(int argc, char *argv[])
+{
+ FILE *infp;
+
+ if (argc != 3)
+ error("usage: mknodes file");
+ if ((infp = fopen(argv[1], "r")) == NULL)
+ error("Can't open %s: %s", argv[1], strerror(errno));
+ while (readline(infp)) {
+ if (line[0] == ' ' || line[0] == '\t')
+ parsefield();
+ else if (line[0] != '\0')
+ parsenode();
+ }
+ fclose(infp);
+ output(argv[2]);
+ exit(0);
+}
+
+
+
+static void
+parsenode(void)
+{
+ char name[BUFLEN];
+ char tag[BUFLEN];
+ struct str *sp;
+
+ if (curstr && curstr->nfields > 0)
+ curstr->done = 1;
+ nextfield(name);
+ if (! nextfield(tag))
+ error("Tag expected");
+ if (*linep != '\0')
+ error("Garbage at end of line");
+ nodename[ntypes] = savestr(name);
+ for (sp = str ; sp < str + nstr ; sp++) {
+ if (strcmp(sp->tag, tag) == 0)
+ break;
+ }
+ if (sp >= str + nstr) {
+ sp->tag = savestr(tag);
+ sp->nfields = 0;
+ curstr = sp;
+ nstr++;
+ }
+ nodestr[ntypes] = sp;
+ ntypes++;
+}
+
+
+static void
+parsefield(void)
+{
+ char name[BUFLEN];
+ char type[BUFLEN];
+ char decl[2 * BUFLEN];
+ struct field *fp;
+
+ if (curstr == NULL || curstr->done)
+ error("No current structure to add field to");
+ if (! nextfield(name))
+ error("No field name");
+ if (! nextfield(type))
+ error("No field type");
+ fp = &curstr->field[curstr->nfields];
+ fp->name = savestr(name);
+ if (strcmp(type, "nodeptr") == 0) {
+ fp->type = T_NODE;
+ sprintf(decl, "union node *%s", name);
+ } else if (strcmp(type, "nodelist") == 0) {
+ fp->type = T_NODELIST;
+ sprintf(decl, "struct nodelist *%s", name);
+ } else if (strcmp(type, "string") == 0) {
+ fp->type = T_STRING;
+ sprintf(decl, "char *%s", name);
+ } else if (strcmp(type, "int") == 0) {
+ fp->type = T_INT;
+ sprintf(decl, "int %s", name);
+ } else if (strcmp(type, "other") == 0) {
+ fp->type = T_OTHER;
+ } else if (strcmp(type, "temp") == 0) {
+ fp->type = T_TEMP;
+ } else {
+ error("Unknown type %s", type);
+ }
+ if (fp->type == T_OTHER || fp->type == T_TEMP) {
+ skipbl();
+ fp->decl = savestr(linep);
+ } else {
+ if (*linep)
+ error("Garbage at end of line");
+ fp->decl = savestr(decl);
+ }
+ curstr->nfields++;
+}
+
+
+static const char writer[] = "\
+/*\n\
+ * This file was generated by the mknodes program.\n\
+ */\n\
+\n";
+
+static void
+output(char *file)
+{
+ FILE *hfile;
+ FILE *cfile;
+ FILE *patfile;
+ int i;
+ struct str *sp;
+ struct field *fp;
+ char *p;
+
+ if ((patfile = fopen(file, "r")) == NULL)
+ error("Can't open %s: %s", file, strerror(errno));
+ if ((hfile = fopen("nodes.h", "w")) == NULL)
+ error("Can't create nodes.h: %s", strerror(errno));
+ if ((cfile = fopen("nodes.c", "w")) == NULL)
+ error("Can't create nodes.c");
+ fputs(writer, hfile);
+ for (i = 0 ; i < ntypes ; i++)
+ fprintf(hfile, "#define %s %d\n", nodename[i], i);
+ fputs("\n\n\n", hfile);
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ fprintf(hfile, "struct %s {\n", sp->tag);
+ for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) {
+ fprintf(hfile, " %s;\n", fp->decl);
+ }
+ fputs("};\n\n\n", hfile);
+ }
+ fputs("union node {\n", hfile);
+ fprintf(hfile, " int type;\n");
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ fprintf(hfile, " struct %s %s;\n", sp->tag, sp->tag);
+ }
+ fputs("};\n\n\n", hfile);
+ fputs("struct nodelist {\n", hfile);
+ fputs("\tstruct nodelist *next;\n", hfile);
+ fputs("\tunion node *n;\n", hfile);
+ fputs("};\n\n\n", hfile);
+ fputs("struct funcdef;\n", hfile);
+ fputs("struct funcdef *copyfunc(union node *);\n", hfile);
+ fputs("union node *getfuncnode(struct funcdef *);\n", hfile);
+ fputs("void reffunc(struct funcdef *);\n", hfile);
+ fputs("void unreffunc(struct funcdef *);\n", hfile);
+ if (ferror(hfile))
+ error("Can't write to nodes.h");
+ if (fclose(hfile))
+ error("Can't close nodes.h");
+
+ fputs(writer, cfile);
+ while (fgets(line, sizeof line, patfile) != NULL) {
+ for (p = line ; *p == ' ' || *p == '\t' ; p++);
+ if (strcmp(p, "%SIZES\n") == 0)
+ outsizes(cfile);
+ else if (strcmp(p, "%CALCSIZE\n") == 0)
+ outfunc(cfile, 1);
+ else if (strcmp(p, "%COPY\n") == 0)
+ outfunc(cfile, 0);
+ else
+ fputs(line, cfile);
+ }
+ fclose(patfile);
+ if (ferror(cfile))
+ error("Can't write to nodes.c");
+ if (fclose(cfile))
+ error("Can't close nodes.c");
+}
+
+
+
+static void
+outsizes(FILE *cfile)
+{
+ int i;
+
+ fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes);
+ for (i = 0 ; i < ntypes ; i++) {
+ fprintf(cfile, " ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag);
+ }
+ fprintf(cfile, "};\n");
+}
+
+
+static void
+outfunc(FILE *cfile, int calcsize)
+{
+ struct str *sp;
+ struct field *fp;
+ int i;
+
+ fputs(" if (n == NULL)\n", cfile);
+ if (calcsize)
+ fputs(" return;\n", cfile);
+ else
+ fputs(" return NULL;\n", cfile);
+ if (calcsize)
+ fputs(" result->blocksize += nodesize[n->type];\n", cfile);
+ else {
+ fputs(" new = state->block;\n", cfile);
+ fputs(" state->block = (char *)state->block + nodesize[n->type];\n", cfile);
+ }
+ fputs(" switch (n->type) {\n", cfile);
+ for (sp = str ; sp < &str[nstr] ; sp++) {
+ for (i = 0 ; i < ntypes ; i++) {
+ if (nodestr[i] == sp)
+ fprintf(cfile, " case %s:\n", nodename[i]);
+ }
+ for (i = sp->nfields ; --i >= 1 ; ) {
+ fp = &sp->field[i];
+ switch (fp->type) {
+ case T_NODE:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "calcsize(n->%s.%s, result);\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = copynode(n->%s.%s, state);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_NODELIST:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "sizenodelist(n->%s.%s, result);\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s, state);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_STRING:
+ if (calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "result->stringsize += strlen(n->%s.%s) + 1;\n",
+ sp->tag, fp->name);
+ } else {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s, state);\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ case T_INT:
+ case T_OTHER:
+ if (! calcsize) {
+ indent(12, cfile);
+ fprintf(cfile, "new->%s.%s = n->%s.%s;\n",
+ sp->tag, fp->name, sp->tag, fp->name);
+ }
+ break;
+ }
+ }
+ indent(12, cfile);
+ fputs("break;\n", cfile);
+ }
+ fputs(" };\n", cfile);
+ if (! calcsize)
+ fputs(" new->type = n->type;\n", cfile);
+}
+
+
+static void
+indent(int amount, FILE *fp)
+{
+ while (amount >= 8) {
+ putc('\t', fp);
+ amount -= 8;
+ }
+ while (--amount >= 0) {
+ putc(' ', fp);
+ }
+}
+
+
+static int
+nextfield(char *buf)
+{
+ char *p, *q;
+
+ p = linep;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ q = buf;
+ while (*p != ' ' && *p != '\t' && *p != '\0')
+ *q++ = *p++;
+ *q = '\0';
+ linep = p;
+ return (q > buf);
+}
+
+
+static void
+skipbl(void)
+{
+ while (*linep == ' ' || *linep == '\t')
+ linep++;
+}
+
+
+static int
+readline(FILE *infp)
+{
+ char *p;
+
+ if (fgets(line, 1024, infp) == NULL)
+ return 0;
+ for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++);
+ while (p > line && (p[-1] == ' ' || p[-1] == '\t'))
+ p--;
+ *p = '\0';
+ linep = line;
+ linno++;
+ if (p - line > BUFLEN)
+ error("Line too long");
+ return 1;
+}
+
+
+
+static void
+error(const char *msg, ...)
+{
+ va_list va;
+ va_start(va, msg);
+
+ (void) fprintf(stderr, "line %d: ", linno);
+ (void) vfprintf(stderr, msg, va);
+ (void) fputc('\n', stderr);
+
+ va_end(va);
+
+ exit(2);
+}
+
+
+
+static char *
+savestr(const char *s)
+{
+ char *p;
+
+ if ((p = malloc(strlen(s) + 1)) == NULL)
+ error("Out of space");
+ (void) strcpy(p, s);
+ return p;
+}
diff --git a/shell_cmds/sh/mksyntax.c b/shell_cmds/sh/mksyntax.c
new file mode 100644
index 0000000..52c5631
--- /dev/null
+++ b/shell_cmds/sh/mksyntax.c
@@ -0,0 +1,331 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/mksyntax.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * This program creates syntax.h and syntax.c.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "parser.h"
+
+
+struct synclass {
+ const char *name;
+ const char *comment;
+};
+
+/* Syntax classes */
+static const struct synclass synclass[] = {
+ { "CWORD", "character is nothing special" },
+ { "CNL", "newline character" },
+ { "CBACK", "a backslash character" },
+ { "CSBACK", "a backslash character in single quotes" },
+ { "CSQUOTE", "single quote" },
+ { "CDQUOTE", "double quote" },
+ { "CENDQUOTE", "a terminating quote" },
+ { "CBQUOTE", "backwards single quote" },
+ { "CVAR", "a dollar sign" },
+ { "CENDVAR", "a '}' character" },
+ { "CLP", "a left paren in arithmetic" },
+ { "CRP", "a right paren in arithmetic" },
+ { "CEOF", "end of file" },
+ { "CCTL", "like CWORD, except it must be escaped" },
+ { "CSPCL", "these terminate a word" },
+ { "CIGN", "character should be ignored" },
+ { NULL, NULL }
+};
+
+
+/*
+ * Syntax classes for is_ functions. Warning: if you add new classes
+ * you may have to change the definition of the is_in_name macro.
+ */
+static const struct synclass is_entry[] = {
+ { "ISDIGIT", "a digit" },
+ { "ISUPPER", "an upper case letter" },
+ { "ISLOWER", "a lower case letter" },
+ { "ISUNDER", "an underscore" },
+ { "ISSPECL", "the name of a special parameter" },
+ { NULL, NULL }
+};
+
+static const char writer[] = "\
+/*\n\
+ * This file was generated by the mksyntax program.\n\
+ */\n\
+\n";
+
+
+static FILE *cfile;
+static FILE *hfile;
+
+static void add_default(void);
+static void finish(void);
+static void init(const char *);
+static void add(const char *, const char *);
+static void output_type_macros(void);
+
+int
+main(int argc __unused, char **argv __unused)
+{
+ int i;
+ char buf[80];
+ int pos;
+
+ /* Create output files */
+ if ((cfile = fopen("syntax.c", "w")) == NULL) {
+ perror("syntax.c");
+ exit(2);
+ }
+ if ((hfile = fopen("syntax.h", "w")) == NULL) {
+ perror("syntax.h");
+ exit(2);
+ }
+ fputs(writer, hfile);
+ fputs(writer, cfile);
+
+ fputs("#include <sys/cdefs.h>\n", hfile);
+ fputs("#include <limits.h>\n\n", hfile);
+
+ /* Generate the #define statements in the header file */
+ fputs("/* Syntax classes */\n", hfile);
+ for (i = 0 ; synclass[i].name ; i++) {
+ sprintf(buf, "#define %s %d", synclass[i].name, i);
+ fputs(buf, hfile);
+ for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+ putc('\t', hfile);
+ fprintf(hfile, "/* %s */\n", synclass[i].comment);
+ }
+ putc('\n', hfile);
+ fputs("/* Syntax classes for is_ functions */\n", hfile);
+ for (i = 0 ; is_entry[i].name ; i++) {
+ sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i);
+ fputs(buf, hfile);
+ for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07)
+ putc('\t', hfile);
+ fprintf(hfile, "/* %s */\n", is_entry[i].comment);
+ }
+ putc('\n', hfile);
+ fputs("#define SYNBASE (1 - CHAR_MIN)\n", hfile);
+ fputs("#define PEOF -SYNBASE\n\n", hfile);
+ putc('\n', hfile);
+ fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile);
+ fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile);
+ fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile);
+ fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile);
+ putc('\n', hfile);
+ output_type_macros(); /* is_digit, etc. */
+ putc('\n', hfile);
+
+ /* Generate the syntax tables. */
+ fputs("#include \"parser.h\"\n", cfile);
+ fputs("#include \"shell.h\"\n", cfile);
+ fputs("#include \"syntax.h\"\n\n", cfile);
+
+ fputs("/* syntax table used when not in quotes */\n", cfile);
+ init("basesyntax");
+ add_default();
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("'", "CSQUOTE");
+ add("\"", "CDQUOTE");
+ add("`", "CBQUOTE");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ add("<>();&| \t", "CSPCL");
+ finish();
+
+ fputs("\n/* syntax table used when in double quotes */\n", cfile);
+ init("dqsyntax");
+ add_default();
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("\"", "CENDQUOTE");
+ add("`", "CBQUOTE");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ /* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */
+ add("!*?[]=~:/-^", "CCTL");
+ finish();
+
+ fputs("\n/* syntax table used when in single quotes */\n", cfile);
+ init("sqsyntax");
+ add_default();
+ add("\n", "CNL");
+ add("\\", "CSBACK");
+ add("'", "CENDQUOTE");
+ /* ':/' for tilde expansion, '-^]' for [a\-x] pattern ranges */
+ add("!*?[]=~:/-^", "CCTL");
+ finish();
+
+ fputs("\n/* syntax table used when in arithmetic */\n", cfile);
+ init("arisyntax");
+ add_default();
+ add("\n", "CNL");
+ add("\\", "CBACK");
+ add("`", "CBQUOTE");
+ add("\"", "CIGN");
+ add("$", "CVAR");
+ add("}", "CENDVAR");
+ add("(", "CLP");
+ add(")", "CRP");
+ finish();
+
+ fputs("\n/* character classification table */\n", cfile);
+ init("is_type");
+ add("0123456789", "ISDIGIT");
+ add("abcdefghijklmnopqrstuvwxyz", "ISLOWER");
+ add("ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ISUPPER");
+ add("_", "ISUNDER");
+ add("#?$!-*@", "ISSPECL");
+ finish();
+
+ exit(0);
+}
+
+
+/*
+ * Output the header and declaration of a syntax table.
+ */
+
+static void
+init(const char *name)
+{
+ fprintf(hfile, "extern const char %s[];\n", name);
+ fprintf(cfile, "const char %s[SYNBASE + CHAR_MAX + 1] = {\n", name);
+}
+
+
+static void
+add_one(const char *key, const char *type)
+{
+ fprintf(cfile, "\t[SYNBASE + %s] = %s,\n", key, type);
+}
+
+
+/*
+ * Add default values to the syntax table.
+ */
+
+static void
+add_default(void)
+{
+ add_one("PEOF", "CEOF");
+ add_one("CTLESC", "CCTL");
+ add_one("CTLVAR", "CCTL");
+ add_one("CTLENDVAR", "CCTL");
+ add_one("CTLBACKQ", "CCTL");
+ add_one("CTLBACKQ + CTLQUOTE", "CCTL");
+ add_one("CTLARI", "CCTL");
+ add_one("CTLENDARI", "CCTL");
+ add_one("CTLQUOTEMARK", "CCTL");
+ add_one("CTLQUOTEEND", "CCTL");
+}
+
+
+/*
+ * Output the footer of a syntax table.
+ */
+
+static void
+finish(void)
+{
+ fputs("};\n", cfile);
+}
+
+
+/*
+ * Add entries to the syntax table.
+ */
+
+static void
+add(const char *p, const char *type)
+{
+ for (; *p; ++p) {
+ char c = *p;
+ switch (c) {
+ case '\t': c = 't'; break;
+ case '\n': c = 'n'; break;
+ case '\'': c = '\''; break;
+ case '\\': c = '\\'; break;
+
+ default:
+ fprintf(cfile, "\t[SYNBASE + '%c'] = %s,\n", c, type);
+ continue;
+ }
+ fprintf(cfile, "\t[SYNBASE + '\\%c'] = %s,\n", c, type);
+ }
+}
+
+
+/*
+ * Output character classification macros (e.g. is_digit). If digits are
+ * contiguous, we can test for them quickly.
+ */
+
+static const char *macro[] = {
+ "#define is_digit(c)\t((unsigned int)((c) - '0') <= 9)",
+ "#define is_eof(c)\t((c) == PEOF)",
+ "#define is_alpha(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER))",
+ "#define is_name(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER|ISUNDER))",
+ "#define is_in_name(c)\t((is_type+SYNBASE)[(int)c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))",
+ "#define is_special(c)\t((is_type+SYNBASE)[(int)c] & (ISSPECL|ISDIGIT))",
+ "#define digit_val(c)\t((c) - '0')",
+ NULL
+};
+
+static void
+output_type_macros(void)
+{
+ const char **pp;
+
+ for (pp = macro ; *pp ; pp++)
+ fprintf(hfile, "%s\n", *pp);
+}
diff --git a/shell_cmds/sh/mktokens b/shell_cmds/sh/mktokens
new file mode 100644
index 0000000..98bcc26
--- /dev/null
+++ b/shell_cmds/sh/mktokens
@@ -0,0 +1,93 @@
+#!/bin/sh -
+
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)mktokens 8.1 (Berkeley) 5/31/93
+# $FreeBSD: head/bin/sh/mktokens 328934 2018-02-06 15:41:35Z arichardson $
+
+# The following is a list of tokens. The second column is nonzero if the
+# token marks the end of a list. The third column is the name to print in
+# error messages.
+
+temp=`mktemp -t ka`
+cat > $temp <<\!
+TEOF 1 end of file
+TNL 0 newline
+TSEMI 0 ";"
+TBACKGND 0 "&"
+TAND 0 "&&"
+TOR 0 "||"
+TPIPE 0 "|"
+TLP 0 "("
+TRP 1 ")"
+TENDCASE 1 ";;"
+TFALLTHRU 1 ";&"
+TREDIR 0 redirection
+TWORD 0 word
+TIF 0 "if"
+TTHEN 1 "then"
+TELSE 1 "else"
+TELIF 1 "elif"
+TFI 1 "fi"
+TWHILE 0 "while"
+TUNTIL 0 "until"
+TFOR 0 "for"
+TDO 1 "do"
+TDONE 1 "done"
+TBEGIN 0 "{"
+TEND 1 "}"
+TCASE 0 "case"
+TESAC 1 "esac"
+TNOT 0 "!"
+!
+nl=`wc -l $temp`
+exec > token.h
+awk '{print "#define " $1 " " NR-1}' $temp
+echo '
+/* Array indicating which tokens mark the end of a list */
+static const char tokendlist[] = {'
+awk '{print "\t" $2 ","}' $temp
+echo '};
+
+static const char *const tokname[] = {'
+sed -e 's/"/\\"/g' \
+ -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
+ $temp
+echo '};
+'
+sed 's/"//g' $temp | awk '
+/TIF/{print "#define KWDOFFSET " NR-1; print ""; print "const char *const parsekwd[] = {"}
+/TIF/,/neverfound/{print " \"" $3 "\","}'
+echo ' 0
+};'
+
+rm $temp
diff --git a/shell_cmds/sh/myhistedit.h b/shell_cmds/sh/myhistedit.h
new file mode 100644
index 0000000..3dbad7e
--- /dev/null
+++ b/shell_cmds/sh/myhistedit.h
@@ -0,0 +1,44 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/myhistedit.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#include <histedit.h>
+
+extern History *hist;
+extern EditLine *el;
+extern int displayhist;
+
+void histedit(void);
+void sethistsize(const char *);
+void setterm(const char *);
+
diff --git a/shell_cmds/sh/mystring.c b/shell_cmds/sh/mystring.c
new file mode 100644
index 0000000..7e17e23
--- /dev/null
+++ b/shell_cmds/sh/mystring.c
@@ -0,0 +1,100 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/mystring.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * String functions.
+ *
+ * equal(s1, s2) Return true if strings are equal.
+ * number(s) Convert a string of digits to an integer.
+ * is_number(s) Return true if s is a string of digits.
+ */
+
+#include <stdlib.h>
+#include "shell.h"
+#include "syntax.h"
+#include "error.h"
+#include "mystring.h"
+
+
+char nullstr[1]; /* zero length string */
+
+/*
+ * equal - #defined in mystring.h
+ */
+
+
+/*
+ * Convert a string of digits to an integer, printing an error message on
+ * failure.
+ */
+
+int
+number(const char *s)
+{
+ if (! is_number(s))
+ error("Illegal number: %s", s);
+ return atoi(s);
+}
+
+
+
+/*
+ * Check for a valid number. This should be elsewhere.
+ */
+
+int
+is_number(const char *p)
+{
+ const char *q;
+
+ if (*p == '\0')
+ return 0;
+ while (*p == '0')
+ p++;
+ for (q = p; *q != '\0'; q++)
+ if (! is_digit(*q))
+ return 0;
+ if (q - p > 10 ||
+ (q - p == 10 && memcmp(p, "2147483647", 10) > 0))
+ return 0;
+ return 1;
+}
diff --git a/shell_cmds/sh/mystring.h b/shell_cmds/sh/mystring.h
new file mode 100644
index 0000000..31d7891
--- /dev/null
+++ b/shell_cmds/sh/mystring.h
@@ -0,0 +1,43 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mystring.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/mystring.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#include <string.h>
+
+int number(const char *);
+int is_number(const char *);
+
+#define equal(s1, s2) (strcmp(s1, s2) == 0)
diff --git a/shell_cmds/sh/nodes.c.pat b/shell_cmds/sh/nodes.c.pat
new file mode 100644
index 0000000..29d1563
--- /dev/null
+++ b/shell_cmds/sh/nodes.c.pat
@@ -0,0 +1,193 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/nodes.c.pat 314436 2017-02-28 23:42:47Z imp $
+ */
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <stddef.h>
+/*
+ * Routine for dealing with parsed shell commands.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "memalloc.h"
+#include "mystring.h"
+
+
+struct nodesize {
+ int blocksize; /* size of structures in function */
+ int stringsize; /* size of strings in node */
+};
+
+struct nodecopystate {
+ pointer block; /* block to allocate function from */
+ char *string; /* block to allocate strings from */
+};
+
+%SIZES
+
+
+static void calcsize(union node *, struct nodesize *);
+static void sizenodelist(struct nodelist *, struct nodesize *);
+static union node *copynode(union node *, struct nodecopystate *);
+static struct nodelist *copynodelist(struct nodelist *, struct nodecopystate *);
+static char *nodesavestr(const char *, struct nodecopystate *);
+
+
+struct funcdef {
+ unsigned int refcount;
+ union node n;
+};
+
+/*
+ * Make a copy of a parse tree.
+ */
+
+struct funcdef *
+copyfunc(union node *n)
+{
+ struct nodesize sz;
+ struct nodecopystate st;
+ struct funcdef *fn;
+
+ if (n == NULL)
+ return NULL;
+ sz.blocksize = offsetof(struct funcdef, n);
+ sz.stringsize = 0;
+ calcsize(n, &sz);
+ fn = ckmalloc(sz.blocksize + sz.stringsize);
+ fn->refcount = 1;
+ st.block = (char *)fn + offsetof(struct funcdef, n);
+ st.string = (char *)fn + sz.blocksize;
+ copynode(n, &st);
+ return fn;
+}
+
+
+union node *
+getfuncnode(struct funcdef *fn)
+{
+ return fn == NULL ? NULL : &fn->n;
+}
+
+
+static void
+calcsize(union node *n, struct nodesize *result)
+{
+ %CALCSIZE
+}
+
+
+
+static void
+sizenodelist(struct nodelist *lp, struct nodesize *result)
+{
+ while (lp) {
+ result->blocksize += ALIGN(sizeof(struct nodelist));
+ calcsize(lp->n, result);
+ lp = lp->next;
+ }
+}
+
+
+
+static union node *
+copynode(union node *n, struct nodecopystate *state)
+{
+ union node *new;
+
+ %COPY
+ return new;
+}
+
+
+static struct nodelist *
+copynodelist(struct nodelist *lp, struct nodecopystate *state)
+{
+ struct nodelist *start;
+ struct nodelist **lpp;
+
+ lpp = &start;
+ while (lp) {
+ *lpp = state->block;
+ state->block = (char *)state->block +
+ ALIGN(sizeof(struct nodelist));
+ (*lpp)->n = copynode(lp->n, state);
+ lp = lp->next;
+ lpp = &(*lpp)->next;
+ }
+ *lpp = NULL;
+ return start;
+}
+
+
+
+static char *
+nodesavestr(const char *s, struct nodecopystate *state)
+{
+ const char *p = s;
+ char *q = state->string;
+ char *rtn = state->string;
+
+ while ((*q++ = *p++) != '\0')
+ continue;
+ state->string = q;
+ return rtn;
+}
+
+
+void
+reffunc(struct funcdef *fn)
+{
+ if (fn)
+ fn->refcount++;
+}
+
+
+/*
+ * Decrement the reference count of a function definition, freeing it
+ * if it falls to 0.
+ */
+
+void
+unreffunc(struct funcdef *fn)
+{
+ if (fn) {
+ fn->refcount--;
+ if (fn->refcount > 0)
+ return;
+ ckfree(fn);
+ }
+}
diff --git a/shell_cmds/sh/nodetypes b/shell_cmds/sh/nodetypes
new file mode 100644
index 0000000..3ad95d6
--- /dev/null
+++ b/shell_cmds/sh/nodetypes
@@ -0,0 +1,145 @@
+#-
+# Copyright (c) 1991, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# This code is derived from software contributed to Berkeley by
+# Kenneth Almquist.
+#
+# 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 University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)nodetypes 8.2 (Berkeley) 5/4/95
+# $FreeBSD: head/bin/sh/nodetypes 314436 2017-02-28 23:42:47Z imp $
+
+# This file describes the nodes used in parse trees. Unindented lines
+# contain a node type followed by a structure tag. Subsequent indented
+# lines specify the fields of the structure. Several node types can share
+# the same structure, in which case the fields of the structure should be
+# specified only once.
+#
+# A field of a structure is described by the name of the field followed
+# by a type. The currently implemented types are:
+# nodeptr - a pointer to a node
+# nodelist - a pointer to a list of nodes
+# string - a pointer to a nul terminated string
+# int - an integer
+# other - any type that can be copied by assignment
+# temp - a field that doesn't have to be copied when the node is copied
+# The last two types should be followed by the text of a C declaration for
+# the field.
+
+NSEMI nbinary # two commands separated by a semicolon
+ type int
+ ch1 nodeptr # the first child
+ ch2 nodeptr # the second child
+
+NCMD ncmd # a simple command
+ type int
+ args nodeptr # the arguments
+ redirect nodeptr # list of file redirections
+
+NPIPE npipe # a pipeline
+ type int
+ backgnd int # set to run pipeline in background
+ cmdlist nodelist # the commands in the pipeline
+
+NREDIR nredir # redirection (of a compex command)
+ type int
+ n nodeptr # the command
+ redirect nodeptr # list of file redirections
+
+NBACKGND nredir # run command in background
+NSUBSHELL nredir # run command in a subshell
+
+NAND nbinary # the && operator
+NOR nbinary # the || operator
+
+NIF nif # the if statement. Elif clauses are handled
+ type int # using multiple if nodes.
+ test nodeptr # if test
+ ifpart nodeptr # then ifpart
+ elsepart nodeptr # else elsepart
+
+NWHILE nbinary # the while statement. First child is the test
+NUNTIL nbinary # the until statement
+
+NFOR nfor # the for statement
+ type int
+ args nodeptr # for var in args
+ body nodeptr # do body; done
+ var string # the for variable
+
+NCASE ncase # a case statement
+ type int
+ expr nodeptr # the word to switch on
+ cases nodeptr # the list of cases (NCLIST nodes)
+
+NCLIST nclist # a case ending with ;;
+ type int
+ next nodeptr # the next case in list
+ pattern nodeptr # list of patterns for this case
+ body nodeptr # code to execute for this case
+
+NCLISTFALLTHRU nclist # a case ending with ;&
+
+NDEFUN narg # define a function. The "next" field contains
+ # the body of the function.
+
+NARG narg # represents a word
+ type int
+ next nodeptr # next word in list
+ text string # the text of the word
+ backquote nodelist # list of commands in back quotes
+
+NTO nfile # fd> fname
+NFROM nfile # fd< fname
+NFROMTO nfile # fd<> fname
+NAPPEND nfile # fd>> fname
+NCLOBBER nfile # fd>| fname
+ type int
+ fd int # file descriptor being redirected
+ next nodeptr # next redirection in list
+ fname nodeptr # file name, in a NARG node
+ expfname temp char *expfname # actual file name
+
+NTOFD ndup # fd<&dupfd
+NFROMFD ndup # fd>&dupfd
+ type int
+ fd int # file descriptor being redirected
+ next nodeptr # next redirection in list
+ dupfd int # file descriptor to duplicate
+ vname nodeptr # file name if fd>&$var
+
+
+NHERE nhere # fd<<\!
+NXHERE nhere # fd<<!
+ type int
+ fd int # file descriptor being redirected
+ next nodeptr # next redirection in list
+ doc nodeptr # input to command (NARG node)
+ expdoc temp const char *expdoc # actual document (for NXHERE)
+
+NNOT nnot # ! command (actually pipeline)
+ type int
+ com nodeptr
diff --git a/shell_cmds/sh/options.c b/shell_cmds/sh/options.c
new file mode 100644
index 0000000..0628e73
--- /dev/null
+++ b/shell_cmds/sh/options.c
@@ -0,0 +1,594 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/options.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#define DEFINE_OPTIONS
+#include "options.h"
+#undef DEFINE_OPTIONS
+#include "nodes.h" /* for other header files */
+#include "eval.h"
+#include "jobs.h"
+#include "input.h"
+#include "output.h"
+#include "trap.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "builtins.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
+
+char *arg0; /* value of $0 */
+struct shparam shellparam; /* current positional parameters */
+char **argptr; /* argument list for builtin commands */
+char *shoptarg; /* set by nextopt (like getopt) */
+char *nextopt_optptr; /* used by nextopt */
+
+char *minusc; /* argument to -c option */
+
+
+static void options(int);
+static void minus_o(char *, int);
+static void setoption(int, int);
+static void setoptionbyindex(int, int);
+static void setparam(int, char **);
+static int getopts(char *, char *, char **, char ***, char **);
+
+
+/*
+ * Process the shell command line arguments.
+ */
+
+void
+procargs(int argc, char **argv)
+{
+ int i;
+ char *scriptname;
+
+ argptr = argv;
+ if (argc > 0)
+ argptr++;
+ for (i = 0; i < NOPTS; i++)
+ optval[i] = 2;
+ privileged = (getuid() != geteuid() || getgid() != getegid());
+ options(1);
+ if (*argptr == NULL && minusc == NULL)
+ sflag = 1;
+ if (iflag != 0 && sflag == 1 && isatty(0) && isatty(1)) {
+ iflag = 1;
+ if (Eflag == 2)
+ Eflag = 1;
+ }
+ if (mflag == 2)
+ mflag = iflag;
+ for (i = 0; i < NOPTS; i++)
+ if (optval[i] == 2)
+ optval[i] = 0;
+ arg0 = argv[0];
+ if (sflag == 0 && minusc == NULL) {
+ scriptname = *argptr++;
+ setinputfile(scriptname, 0);
+ commandname = arg0 = scriptname;
+ }
+ /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
+ if (argptr && minusc && *argptr)
+ arg0 = *argptr++;
+
+ shellparam.p = argptr;
+ shellparam.reset = 1;
+ /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */
+ while (*argptr) {
+ shellparam.nparam++;
+ argptr++;
+ }
+ optschanged();
+}
+
+
+void
+optschanged(void)
+{
+ setinteractive();
+#ifndef NO_HISTORY
+ histedit();
+#endif
+ setjobctl(mflag);
+}
+
+/*
+ * Process shell options. The global variable argptr contains a pointer
+ * to the argument list; we advance it past the options.
+ * If cmdline is true, process the shell's argv; otherwise, process arguments
+ * to the set special builtin.
+ */
+
+static void
+options(int cmdline)
+{
+ char *kp, *p;
+ int val;
+ int c;
+
+ if (cmdline)
+ minusc = NULL;
+ while ((p = *argptr) != NULL) {
+ argptr++;
+ if ((c = *p++) == '-') {
+ val = 1;
+ /* A "-" or "--" terminates options */
+ if (p[0] == '\0')
+ goto end_options1;
+ if (p[0] == '-' && p[1] == '\0')
+ goto end_options2;
+ /**
+ * For the benefit of `#!' lines in shell scripts,
+ * treat a string of '-- *#.*' the same as '--'.
+ * This is needed so that a script starting with:
+ * #!/bin/sh -- # -*- perl -*-
+ * will continue to work after a change is made to
+ * kern/imgact_shell.c to NOT token-ize the options
+ * specified on a '#!' line. A bit of a kludge,
+ * but that trick is recommended in documentation
+ * for some scripting languages, and we might as
+ * well continue to support it.
+ */
+ if (p[0] == '-') {
+ kp = p + 1;
+ while (*kp == ' ' || *kp == '\t')
+ kp++;
+ if (*kp == '#' || *kp == '\0')
+ goto end_options2;
+ }
+ } else if (c == '+') {
+ val = 0;
+ } else {
+ argptr--;
+ break;
+ }
+ while ((c = *p++) != '\0') {
+ if (c == 'c' && cmdline) {
+ char *q;
+
+ q = *argptr++;
+ if (q == NULL || minusc != NULL)
+ error("Bad -c option");
+ minusc = q;
+ } else if (c == 'o') {
+ minus_o(*argptr, val);
+ if (*argptr)
+ argptr++;
+ } else
+ setoption(c, val);
+ }
+ }
+ return;
+
+ /* When processing `set', a single "-" means turn off -x and -v */
+end_options1:
+ if (!cmdline) {
+ xflag = vflag = 0;
+ return;
+ }
+
+ /*
+ * When processing `set', a "--" means the remaining arguments
+ * replace the positional parameters in the active shell. If
+ * there are no remaining options, then all the positional
+ * parameters are cleared (equivalent to doing ``shift $#'').
+ */
+end_options2:
+ if (!cmdline) {
+ if (*argptr == NULL)
+ setparam(0, argptr);
+ return;
+ }
+
+ /*
+ * At this point we are processing options given to 'sh' on a command
+ * line. If an end-of-options marker ("-" or "--") is followed by an
+ * arg of "#", then skip over all remaining arguments. Some scripting
+ * languages (e.g.: perl) document that /bin/sh will implement this
+ * behavior, and they recommend that users take advantage of it to
+ * solve certain issues that can come up when writing a perl script.
+ * Yes, this feature is in /bin/sh to help users write perl scripts.
+ */
+ p = *argptr;
+ if (p != NULL && p[0] == '#' && p[1] == '\0') {
+ while (*argptr != NULL)
+ argptr++;
+ /* We need to keep the final argument */
+ argptr--;
+ }
+}
+
+static void
+minus_o(char *name, int val)
+{
+ int i;
+ const unsigned char *on;
+ size_t len;
+
+ if (name == NULL) {
+ if (val) {
+ /* "Pretty" output. */
+ out1str("Current option settings\n");
+ for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1)
+ out1fmt("%-16.*s%s\n", *on, on + 1,
+ optval[i] ? "on" : "off");
+ } else {
+ /* Output suitable for re-input to shell. */
+ for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1)
+ out1fmt("%s %co %.*s%s",
+ i % 6 == 0 ? "set" : "",
+ optval[i] ? '-' : '+',
+ *on, on + 1,
+ i % 6 == 5 || i == NOPTS - 1 ? "\n" : "");
+ }
+ } else {
+ len = strlen(name);
+ for (i = 0, on = optname; i < NOPTS; i++, on += *on + 1)
+ if (*on == len && memcmp(on + 1, name, len) == 0) {
+ setoptionbyindex(i, val);
+ return;
+ }
+ error("Illegal option -o %s", name);
+ }
+}
+
+
+static void
+setoptionbyindex(int idx, int val)
+{
+ if (&optval[idx] == &privileged && !val && privileged) {
+ if (setgid(getgid()) == -1)
+ error("setgid");
+ if (setuid(getuid()) == -1)
+ error("setuid");
+ }
+ optval[idx] = val;
+ if (val) {
+ /* #%$ hack for ksh semantics */
+ if (&optval[idx] == &Vflag)
+ Eflag = 0;
+ else if (&optval[idx] == &Eflag)
+ Vflag = 0;
+ }
+}
+
+static void
+setoption(int flag, int val)
+{
+ int i;
+
+ for (i = 0; i < NSHORTOPTS; i++)
+ if (optletter[i] == flag) {
+ setoptionbyindex(i, val);
+ return;
+ }
+ error("Illegal option -%c", flag);
+}
+
+
+/*
+ * Set the shell parameters.
+ */
+
+static void
+setparam(int argc, char **argv)
+{
+ char **newparam;
+ char **ap;
+
+ ap = newparam = ckmalloc((argc + 1) * sizeof *ap);
+ while (*argv) {
+ *ap++ = savestr(*argv++);
+ }
+ *ap = NULL;
+ freeparam(&shellparam);
+ shellparam.malloc = 1;
+ shellparam.nparam = argc;
+ shellparam.p = newparam;
+ shellparam.optp = NULL;
+ shellparam.reset = 1;
+ shellparam.optnext = NULL;
+}
+
+
+/*
+ * Free the list of positional parameters.
+ */
+
+void
+freeparam(struct shparam *param)
+{
+ char **ap;
+
+ if (param->malloc) {
+ for (ap = param->p ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(param->p);
+ }
+ if (param->optp) {
+ for (ap = param->optp ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(param->optp);
+ }
+}
+
+
+
+/*
+ * The shift builtin command.
+ */
+
+int
+shiftcmd(int argc, char **argv)
+{
+ int i, n;
+
+ n = 1;
+ if (argc > 1)
+ n = number(argv[1]);
+ if (n > shellparam.nparam)
+ return 1;
+ INTOFF;
+ shellparam.nparam -= n;
+ if (shellparam.malloc)
+ for (i = 0; i < n; i++)
+ ckfree(shellparam.p[i]);
+ memmove(shellparam.p, shellparam.p + n,
+ (shellparam.nparam + 1) * sizeof(shellparam.p[0]));
+ shellparam.reset = 1;
+ INTON;
+ return 0;
+}
+
+
+
+/*
+ * The set builtin command.
+ */
+
+int
+setcmd(int argc, char **argv)
+{
+ if (argc == 1)
+ return showvarscmd(argc, argv);
+ INTOFF;
+ options(0);
+ optschanged();
+ if (*argptr != NULL) {
+ setparam(argc - (argptr - argv), argptr);
+ }
+ INTON;
+ return 0;
+}
+
+
+void
+getoptsreset(const char *value)
+{
+ while (*value == '0')
+ value++;
+ if (strcmp(value, "1") == 0)
+ shellparam.reset = 1;
+}
+
+/*
+ * The getopts builtin. Shellparam.optnext points to the next argument
+ * to be processed. Shellparam.optptr points to the next character to
+ * be processed in the current argument. If shellparam.optnext is NULL,
+ * then it's the first time getopts has been called.
+ */
+
+int
+getoptscmd(int argc, char **argv)
+{
+ char **optbase = NULL, **ap;
+ int i;
+
+ if (argc < 3)
+ error("usage: getopts optstring var [arg]");
+
+ if (shellparam.reset == 1) {
+ INTOFF;
+ if (shellparam.optp) {
+ for (ap = shellparam.optp ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(shellparam.optp);
+ shellparam.optp = NULL;
+ }
+ if (argc > 3) {
+ shellparam.optp = ckmalloc((argc - 2) * sizeof *ap);
+ memset(shellparam.optp, '\0', (argc - 2) * sizeof *ap);
+ for (i = 0; i < argc - 3; i++)
+ shellparam.optp[i] = savestr(argv[i + 3]);
+ }
+ INTON;
+ optbase = argc == 3 ? shellparam.p : shellparam.optp;
+ shellparam.optnext = optbase;
+ shellparam.optptr = NULL;
+ shellparam.reset = 0;
+ } else
+ optbase = shellparam.optp ? shellparam.optp : shellparam.p;
+
+ return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
+ &shellparam.optptr);
+}
+
+static int
+getopts(char *optstr, char *optvar, char **optfirst, char ***optnext,
+ char **optptr)
+{
+ char *p, *q;
+ char c = '?';
+ int done = 0;
+ int ind = 0;
+ int err = 0;
+ char s[10];
+ const char *newoptarg = NULL;
+
+ if ((p = *optptr) == NULL || *p == '\0') {
+ /* Current word is done, advance */
+ if (*optnext == NULL)
+ return 1;
+ p = **optnext;
+ if (p == NULL || *p != '-' || *++p == '\0') {
+atend:
+ ind = *optnext - optfirst + 1;
+ *optnext = NULL;
+ p = NULL;
+ done = 1;
+ goto out;
+ }
+ (*optnext)++;
+ if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ goto atend;
+ }
+
+ c = *p++;
+ for (q = optstr; *q != c; ) {
+ if (*q == '\0') {
+ if (optstr[0] == ':') {
+ s[0] = c;
+ s[1] = '\0';
+ newoptarg = s;
+ }
+ else
+ out2fmt_flush("Illegal option -%c\n", c);
+ c = '?';
+ goto out;
+ }
+ if (*++q == ':')
+ q++;
+ }
+
+ if (*++q == ':') {
+ if (*p == '\0' && (p = **optnext) == NULL) {
+ if (optstr[0] == ':') {
+ s[0] = c;
+ s[1] = '\0';
+ newoptarg = s;
+ c = ':';
+ }
+ else {
+ out2fmt_flush("No arg for -%c option\n", c);
+ c = '?';
+ }
+ goto out;
+ }
+
+ if (p == **optnext)
+ (*optnext)++;
+ newoptarg = p;
+ p = NULL;
+ }
+
+out:
+ if (*optnext != NULL)
+ ind = *optnext - optfirst + 1;
+ *optptr = p;
+ if (newoptarg != NULL)
+ err |= setvarsafe("OPTARG", newoptarg, 0);
+ else {
+ INTOFF;
+ err |= unsetvar("OPTARG");
+ INTON;
+ }
+ fmtstr(s, sizeof(s), "%d", ind);
+ err |= setvarsafe("OPTIND", s, VNOFUNC);
+ s[0] = c;
+ s[1] = '\0';
+ err |= setvarsafe(optvar, s, 0);
+ if (err) {
+ *optnext = NULL;
+ *optptr = NULL;
+ flushall();
+ exraise(EXERROR);
+ }
+ return done;
+}
+
+/*
+ * Standard option processing (a la getopt) for builtin routines. The
+ * only argument that is passed to nextopt is the option string; the
+ * other arguments are unnecessary. It returns the option, or '\0' on
+ * end of input.
+ */
+
+int
+nextopt(const char *optstring)
+{
+ char *p;
+ const char *q;
+ char c;
+
+ if ((p = nextopt_optptr) == NULL || *p == '\0') {
+ p = *argptr;
+ if (p == NULL || *p != '-' || *++p == '\0')
+ return '\0';
+ argptr++;
+ if (p[0] == '-' && p[1] == '\0') /* check for "--" */
+ return '\0';
+ }
+ c = *p++;
+ for (q = optstring ; *q != c ; ) {
+ if (*q == '\0')
+ error("Illegal option -%c", c);
+ if (*++q == ':')
+ q++;
+ }
+ if (*++q == ':') {
+ if (*p == '\0' && (p = *argptr++) == NULL)
+ error("No arg for -%c option", c);
+ shoptarg = p;
+ p = NULL;
+ }
+ nextopt_optptr = p;
+ return c;
+}
diff --git a/shell_cmds/sh/options.h b/shell_cmds/sh/options.h
new file mode 100644
index 0000000..233e9c6
--- /dev/null
+++ b/shell_cmds/sh/options.h
@@ -0,0 +1,115 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)options.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/options.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+struct shparam {
+ int nparam; /* # of positional parameters (without $0) */
+ unsigned char malloc; /* if parameter list dynamically allocated */
+ unsigned char reset; /* if getopts has been reset */
+ char **p; /* parameter list */
+ char **optp; /* parameter list for getopts */
+ char **optnext; /* next parameter to be processed by getopts */
+ char *optptr; /* used by getopts */
+};
+
+
+
+#define eflag optval[0]
+#define fflag optval[1]
+#define Iflag optval[2]
+#define iflag optval[3]
+#define mflag optval[4]
+#define nflag optval[5]
+#define sflag optval[6]
+#define xflag optval[7]
+#define vflag optval[8]
+#define Vflag optval[9]
+#define Eflag optval[10]
+#define Cflag optval[11]
+#define aflag optval[12]
+#define bflag optval[13]
+#define uflag optval[14]
+#define privileged optval[15]
+#define Tflag optval[16]
+#define Pflag optval[17]
+#define hflag optval[18]
+#define nologflag optval[19]
+
+#define NSHORTOPTS 19
+#define NOPTS 20
+
+extern char optval[NOPTS];
+extern const char optletter[NSHORTOPTS];
+#ifdef DEFINE_OPTIONS
+char optval[NOPTS];
+const char optletter[NSHORTOPTS] = "efIimnsxvVECabupTPh";
+static const unsigned char optname[] =
+ "\007errexit"
+ "\006noglob"
+ "\011ignoreeof"
+ "\013interactive"
+ "\007monitor"
+ "\006noexec"
+ "\005stdin"
+ "\006xtrace"
+ "\007verbose"
+ "\002vi"
+ "\005emacs"
+ "\011noclobber"
+ "\011allexport"
+ "\006notify"
+ "\007nounset"
+ "\012privileged"
+ "\012trapsasync"
+ "\010physical"
+ "\010trackall"
+ "\005nolog"
+;
+#endif
+
+
+extern char *minusc; /* argument to -c option */
+extern char *arg0; /* $0 */
+extern struct shparam shellparam; /* $@ */
+extern char **argptr; /* argument list for builtin commands */
+extern char *shoptarg; /* set by nextopt */
+extern char *nextopt_optptr; /* used by nextopt */
+
+void procargs(int, char **);
+void optschanged(void);
+void freeparam(struct shparam *);
+int nextopt(const char *);
+void getoptsreset(const char *);
diff --git a/shell_cmds/sh/output.c b/shell_cmds/sh/output.c
new file mode 100644
index 0000000..737eb91
--- /dev/null
+++ b/shell_cmds/sh/output.c
@@ -0,0 +1,370 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/output.c 326025 2017-11-20 19:49:47Z pfg $");
+
+/*
+ * Shell output routines. We use our own output routines because:
+ * When a builtin command is interrupted we have to discard
+ * any pending output.
+ * When a builtin command appears in back quotes, we want to
+ * save the output of the command in a region obtained
+ * via malloc, rather than doing a fork and reading the
+ * output of the command via a pipe.
+ */
+
+#include <stdio.h> /* defines BUFSIZ */
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "shell.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "var.h"
+
+
+#define OUTBUFSIZ BUFSIZ
+#define MEM_OUT -2 /* output to dynamically allocated memory */
+#define OUTPUT_ERR 01 /* error occurred on output */
+
+static int doformat_wr(void *, const char *, int);
+
+struct output output = {NULL, NULL, NULL, OUTBUFSIZ, 1, 0};
+struct output errout = {NULL, NULL, NULL, 256, 2, 0};
+struct output memout = {NULL, NULL, NULL, 64, MEM_OUT, 0};
+struct output *out1 = &output;
+struct output *out2 = &errout;
+
+void
+outcslow(int c, struct output *file)
+{
+ outc(c, file);
+}
+
+void
+out1str(const char *p)
+{
+ outstr(p, out1);
+}
+
+void
+out1qstr(const char *p)
+{
+ outqstr(p, out1);
+}
+
+void
+out2str(const char *p)
+{
+ outstr(p, out2);
+}
+
+void
+out2qstr(const char *p)
+{
+ outqstr(p, out2);
+}
+
+void
+outstr(const char *p, struct output *file)
+{
+ outbin(p, strlen(p), file);
+}
+
+static void
+byteseq(int ch, struct output *file)
+{
+ char seq[4];
+
+ seq[0] = '\\';
+ seq[1] = (ch >> 6 & 0x3) + '0';
+ seq[2] = (ch >> 3 & 0x7) + '0';
+ seq[3] = (ch & 0x7) + '0';
+ outbin(seq, 4, file);
+}
+
+static void
+outdqstr(const char *p, struct output *file)
+{
+ const char *end;
+ mbstate_t mbs;
+ size_t clen;
+ wchar_t wc;
+
+ memset(&mbs, '\0', sizeof(mbs));
+ end = p + strlen(p);
+ outstr("$'", file);
+ while ((clen = mbrtowc(&wc, p, end - p + 1, &mbs)) != 0) {
+ if (clen == (size_t)-2) {
+ while (p < end)
+ byteseq(*p++, file);
+ break;
+ }
+ if (clen == (size_t)-1) {
+ memset(&mbs, '\0', sizeof(mbs));
+ byteseq(*p++, file);
+ continue;
+ }
+ if (wc == L'\n')
+ outcslow('\n', file), p++;
+ else if (wc == L'\r')
+ outstr("\\r", file), p++;
+ else if (wc == L'\t')
+ outstr("\\t", file), p++;
+ else if (!iswprint(wc)) {
+ for (; clen > 0; clen--)
+ byteseq(*p++, file);
+ } else {
+ if (wc == L'\'' || wc == L'\\')
+ outcslow('\\', file);
+ outbin(p, clen, file);
+ p += clen;
+ }
+ }
+ outcslow('\'', file);
+}
+
+/* Like outstr(), but quote for re-input into the shell. */
+void
+outqstr(const char *p, struct output *file)
+{
+ int i;
+
+ if (p[0] == '\0') {
+ outstr("''", file);
+ return;
+ }
+ for (i = 0; p[i] != '\0'; i++) {
+ if ((p[i] > '\0' && p[i] < ' ' && p[i] != '\n') ||
+ (p[i] & 0x80) != 0 || p[i] == '\'') {
+ outdqstr(p, file);
+ return;
+ }
+ }
+
+ if (p[strcspn(p, "|&;<>()$`\\\" \n*?[~#=")] == '\0' ||
+ strcmp(p, "[") == 0) {
+ outstr(p, file);
+ return;
+ }
+
+ outcslow('\'', file);
+ outstr(p, file);
+ outcslow('\'', file);
+}
+
+void
+outbin(const void *data, size_t len, struct output *file)
+{
+ const char *p;
+
+ p = data;
+ while (len-- > 0)
+ outc(*p++, file);
+}
+
+void
+emptyoutbuf(struct output *dest)
+{
+ int offset, newsize;
+
+ if (dest->buf == NULL) {
+ INTOFF;
+ dest->buf = ckmalloc(dest->bufsize);
+ dest->nextc = dest->buf;
+ dest->bufend = dest->buf + dest->bufsize;
+ INTON;
+ } else if (dest->fd == MEM_OUT) {
+ offset = dest->nextc - dest->buf;
+ newsize = dest->bufsize << 1;
+ INTOFF;
+ dest->buf = ckrealloc(dest->buf, newsize);
+ dest->bufsize = newsize;
+ dest->bufend = dest->buf + newsize;
+ dest->nextc = dest->buf + offset;
+ INTON;
+ } else {
+ flushout(dest);
+ }
+}
+
+
+void
+flushall(void)
+{
+ flushout(&output);
+ flushout(&errout);
+}
+
+
+void
+flushout(struct output *dest)
+{
+
+ if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
+ return;
+ if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
+ dest->flags |= OUTPUT_ERR;
+ dest->nextc = dest->buf;
+}
+
+
+void
+freestdout(void)
+{
+ output.nextc = output.buf;
+}
+
+
+int
+outiserror(struct output *file)
+{
+ return (file->flags & OUTPUT_ERR);
+}
+
+
+void
+outclearerror(struct output *file)
+{
+ file->flags &= ~OUTPUT_ERR;
+}
+
+
+void
+outfmt(struct output *file, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ doformat(file, fmt, ap);
+ va_end(ap);
+}
+
+
+void
+out1fmt(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ doformat(out1, fmt, ap);
+ va_end(ap);
+}
+
+void
+out2fmt_flush(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ doformat(out2, fmt, ap);
+ va_end(ap);
+ flushout(out2);
+}
+
+void
+fmtstr(char *outbuf, int length, const char *fmt, ...)
+{
+ va_list ap;
+
+ INTOFF;
+ va_start(ap, fmt);
+ vsnprintf(outbuf, length, fmt, ap);
+ va_end(ap);
+ INTON;
+}
+
+static int
+doformat_wr(void *cookie, const char *buf, int len)
+{
+ struct output *o;
+
+ o = (struct output *)cookie;
+ outbin(buf, len, o);
+
+ return (len);
+}
+
+void
+doformat(struct output *dest, const char *f, va_list ap)
+{
+ FILE *fp;
+
+ if ((fp = fwopen(dest, doformat_wr)) != NULL) {
+ vfprintf(fp, f, ap);
+ fclose(fp);
+ }
+}
+
+/*
+ * Version of write which resumes after a signal is caught.
+ */
+
+int
+xwrite(int fd, const char *buf, int nbytes)
+{
+ int ntry;
+ int i;
+ int n;
+
+ n = nbytes;
+ ntry = 0;
+ for (;;) {
+ i = write(fd, buf, n);
+ if (i > 0) {
+ if ((n -= i) <= 0)
+ return nbytes;
+ buf += i;
+ ntry = 0;
+ } else if (i == 0) {
+ if (++ntry > 10)
+ return nbytes - n;
+ } else if (errno != EINTR) {
+ return -1;
+ }
+ }
+}
diff --git a/shell_cmds/sh/output.h b/shell_cmds/sh/output.h
new file mode 100644
index 0000000..652187a
--- /dev/null
+++ b/shell_cmds/sh/output.h
@@ -0,0 +1,85 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)output.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/output.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#ifndef OUTPUT_INCL
+
+#include <stdarg.h>
+#include <stddef.h>
+
+struct output {
+ char *nextc;
+ char *bufend;
+ char *buf;
+ int bufsize;
+ short fd;
+ short flags;
+};
+
+extern struct output output; /* to fd 1 */
+extern struct output errout; /* to fd 2 */
+extern struct output memout;
+extern struct output *out1; /* &memout if backquote, otherwise &output */
+extern struct output *out2; /* &memout if backquote with 2>&1, otherwise
+ &errout */
+
+void outcslow(int, struct output *);
+void out1str(const char *);
+void out1qstr(const char *);
+void out2str(const char *);
+void out2qstr(const char *);
+void outstr(const char *, struct output *);
+void outqstr(const char *, struct output *);
+void outbin(const void *, size_t, struct output *);
+void emptyoutbuf(struct output *);
+void flushall(void);
+void flushout(struct output *);
+void freestdout(void);
+int outiserror(struct output *);
+void outclearerror(struct output *);
+void outfmt(struct output *, const char *, ...) __printflike(2, 3);
+void out1fmt(const char *, ...) __printflike(1, 2);
+void out2fmt_flush(const char *, ...) __printflike(1, 2);
+void fmtstr(char *, int, const char *, ...) __printflike(3, 4);
+void doformat(struct output *, const char *, va_list) __printflike(2, 0);
+int xwrite(int, const char *, int);
+
+#define outc(c, file) ((file)->nextc == (file)->bufend ? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
+#define out1c(c) outc(c, out1);
+#define out2c(c) outcslow(c, out2);
+
+#define OUTPUT_INCL
+#endif
diff --git a/shell_cmds/sh/parser.c b/shell_cmds/sh/parser.c
new file mode 100644
index 0000000..799e3b5
--- /dev/null
+++ b/shell_cmds/sh/parser.c
@@ -0,0 +1,2120 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/parser.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "expand.h" /* defines rmescapes() */
+#include "syntax.h"
+#include "options.h"
+#include "input.h"
+#include "output.h"
+#include "var.h"
+#include "error.h"
+#include "memalloc.h"
+#include "mystring.h"
+#include "alias.h"
+#include "show.h"
+#include "eval.h"
+#include "exec.h" /* to check for special builtins */
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
+
+/*
+ * Shell command parser.
+ */
+
+#define PROMPTLEN 128
+
+/* values of checkkwd variable */
+#define CHKALIAS 0x1
+#define CHKKWD 0x2
+#define CHKNL 0x4
+
+/* values returned by readtoken */
+#include "token.h"
+
+
+
+struct heredoc {
+ struct heredoc *next; /* next here document in list */
+ union node *here; /* redirection node */
+ char *eofmark; /* string indicating end of input */
+ int striptabs; /* if set, strip leading tabs */
+};
+
+struct parser_temp {
+ struct parser_temp *next;
+ void *data;
+};
+
+
+static struct heredoc *heredoclist; /* list of here documents to read */
+static int doprompt; /* if set, prompt the user */
+static int needprompt; /* true if interactive and at start of line */
+static int lasttoken; /* last token read */
+static int tokpushback; /* last token pushed back */
+static char *wordtext; /* text of last word returned by readtoken */
+static int checkkwd;
+static struct nodelist *backquotelist;
+static union node *redirnode;
+static struct heredoc *heredoc;
+static int quoteflag; /* set if (part of) last token was quoted */
+static int startlinno; /* line # where last token started */
+static int funclinno; /* line # where the current function started */
+static struct parser_temp *parser_temp;
+
+#define NOEOFMARK ((const char *)&heredoclist)
+
+
+static union node *list(int);
+static union node *andor(void);
+static union node *pipeline(void);
+static union node *command(void);
+static union node *simplecmd(union node **, union node *);
+static union node *makename(void);
+static union node *makebinary(int type, union node *n1, union node *n2);
+static void parsefname(void);
+static void parseheredoc(void);
+static int peektoken(void);
+static int readtoken(void);
+static int xxreadtoken(void);
+static int readtoken1(int, const char *, const char *, int);
+static int noexpand(char *);
+static void consumetoken(int);
+static void synexpect(int) __dead2;
+static void synerror(const char *) __dead2;
+static void setprompt(int);
+static int pgetc_linecont(void);
+
+
+static void *
+parser_temp_alloc(size_t len)
+{
+ struct parser_temp *t;
+
+ INTOFF;
+ t = ckmalloc(sizeof(*t));
+ t->data = NULL;
+ t->next = parser_temp;
+ parser_temp = t;
+ t->data = ckmalloc(len);
+ INTON;
+ return t->data;
+}
+
+
+static void *
+parser_temp_realloc(void *ptr, size_t len)
+{
+ struct parser_temp *t;
+
+ INTOFF;
+ t = parser_temp;
+ if (ptr != t->data)
+ error("bug: parser_temp_realloc misused");
+ t->data = ckrealloc(t->data, len);
+ INTON;
+ return t->data;
+}
+
+
+static void
+parser_temp_free_upto(void *ptr)
+{
+ struct parser_temp *t;
+ int done = 0;
+
+ INTOFF;
+ while (parser_temp != NULL && !done) {
+ t = parser_temp;
+ parser_temp = t->next;
+ done = t->data == ptr;
+ ckfree(t->data);
+ ckfree(t);
+ }
+ INTON;
+ if (!done)
+ error("bug: parser_temp_free_upto misused");
+}
+
+
+static void
+parser_temp_free_all(void)
+{
+ struct parser_temp *t;
+
+ INTOFF;
+ while (parser_temp != NULL) {
+ t = parser_temp;
+ parser_temp = t->next;
+ ckfree(t->data);
+ ckfree(t);
+ }
+ INTON;
+}
+
+
+/*
+ * Read and parse a command. Returns NEOF on end of file. (NULL is a
+ * valid parse tree indicating a blank line.)
+ */
+
+union node *
+parsecmd(int interact)
+{
+ int t;
+
+ /* This assumes the parser is not re-entered,
+ * which could happen if we add command substitution on PS1/PS2.
+ */
+ parser_temp_free_all();
+ heredoclist = NULL;
+
+ tokpushback = 0;
+ checkkwd = 0;
+ doprompt = interact;
+ if (doprompt)
+ setprompt(1);
+ else
+ setprompt(0);
+ needprompt = 0;
+ t = readtoken();
+ if (t == TEOF)
+ return NEOF;
+ if (t == TNL)
+ return NULL;
+ tokpushback++;
+ return list(1);
+}
+
+
+/*
+ * Read and parse words for wordexp.
+ * Returns a list of NARG nodes; NULL if there are no words.
+ */
+union node *
+parsewordexp(void)
+{
+ union node *n, *first = NULL, **pnext;
+ int t;
+
+ /* This assumes the parser is not re-entered,
+ * which could happen if we add command substitution on PS1/PS2.
+ */
+ parser_temp_free_all();
+ heredoclist = NULL;
+
+ tokpushback = 0;
+ checkkwd = 0;
+ doprompt = 0;
+ setprompt(0);
+ needprompt = 0;
+ pnext = &first;
+ while ((t = readtoken()) != TEOF) {
+ if (t != TWORD)
+ synexpect(TWORD);
+ n = makename();
+ *pnext = n;
+ pnext = &n->narg.next;
+ }
+ return first;
+}
+
+
+static union node *
+list(int nlflag)
+{
+ union node *ntop, *n1, *n2, *n3;
+ int tok;
+
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (!nlflag && tokendlist[peektoken()])
+ return NULL;
+ ntop = n1 = NULL;
+ for (;;) {
+ n2 = andor();
+ tok = readtoken();
+ if (tok == TBACKGND) {
+ if (n2 != NULL && n2->type == NPIPE) {
+ n2->npipe.backgnd = 1;
+ } else if (n2 != NULL && n2->type == NREDIR) {
+ n2->type = NBACKGND;
+ } else {
+ n3 = (union node *)stalloc(sizeof (struct nredir));
+ n3->type = NBACKGND;
+ n3->nredir.n = n2;
+ n3->nredir.redirect = NULL;
+ n2 = n3;
+ }
+ }
+ if (ntop == NULL)
+ ntop = n2;
+ else if (n1 == NULL) {
+ n1 = makebinary(NSEMI, ntop, n2);
+ ntop = n1;
+ }
+ else {
+ n3 = makebinary(NSEMI, n1->nbinary.ch2, n2);
+ n1->nbinary.ch2 = n3;
+ n1 = n3;
+ }
+ switch (tok) {
+ case TBACKGND:
+ case TSEMI:
+ tok = readtoken();
+ /* FALLTHROUGH */
+ case TNL:
+ if (tok == TNL) {
+ parseheredoc();
+ if (nlflag)
+ return ntop;
+ } else if (tok == TEOF && nlflag) {
+ parseheredoc();
+ return ntop;
+ } else {
+ tokpushback++;
+ }
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if (!nlflag && tokendlist[peektoken()])
+ return ntop;
+ break;
+ case TEOF:
+ if (heredoclist)
+ parseheredoc();
+ else
+ pungetc(); /* push back EOF on input */
+ return ntop;
+ default:
+ if (nlflag)
+ synexpect(-1);
+ tokpushback++;
+ return ntop;
+ }
+ }
+}
+
+
+
+static union node *
+andor(void)
+{
+ union node *n;
+ int t;
+
+ n = pipeline();
+ for (;;) {
+ if ((t = readtoken()) == TAND) {
+ t = NAND;
+ } else if (t == TOR) {
+ t = NOR;
+ } else {
+ tokpushback++;
+ return n;
+ }
+ n = makebinary(t, n, pipeline());
+ }
+}
+
+
+
+static union node *
+pipeline(void)
+{
+ union node *n1, *n2, *pipenode;
+ struct nodelist *lp, *prev;
+ int negate, t;
+
+ negate = 0;
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ TRACE(("pipeline: entered\n"));
+ while (readtoken() == TNOT)
+ negate = !negate;
+ tokpushback++;
+ n1 = command();
+ if (readtoken() == TPIPE) {
+ pipenode = (union node *)stalloc(sizeof (struct npipe));
+ pipenode->type = NPIPE;
+ pipenode->npipe.backgnd = 0;
+ lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ pipenode->npipe.cmdlist = lp;
+ lp->n = n1;
+ do {
+ prev = lp;
+ lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ t = readtoken();
+ tokpushback++;
+ if (t == TNOT)
+ lp->n = pipeline();
+ else
+ lp->n = command();
+ prev->next = lp;
+ } while (readtoken() == TPIPE);
+ lp->next = NULL;
+ n1 = pipenode;
+ }
+ tokpushback++;
+ if (negate) {
+ n2 = (union node *)stalloc(sizeof (struct nnot));
+ n2->type = NNOT;
+ n2->nnot.com = n1;
+ return n2;
+ } else
+ return n1;
+}
+
+
+
+static union node *
+command(void)
+{
+ union node *n1, *n2;
+ union node *ap, **app;
+ union node *cp, **cpp;
+ union node *redir, **rpp;
+ int t;
+ int is_subshell;
+
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ is_subshell = 0;
+ redir = NULL;
+ n1 = NULL;
+ rpp = &redir;
+
+ /* Check for redirection which may precede command */
+ while (readtoken() == TREDIR) {
+ *rpp = n2 = redirnode;
+ rpp = &n2->nfile.next;
+ parsefname();
+ }
+ tokpushback++;
+
+ switch (readtoken()) {
+ case TIF:
+ n1 = (union node *)stalloc(sizeof (struct nif));
+ n1->type = NIF;
+ if ((n1->nif.test = list(0)) == NULL)
+ synexpect(-1);
+ consumetoken(TTHEN);
+ n1->nif.ifpart = list(0);
+ n2 = n1;
+ while (readtoken() == TELIF) {
+ n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
+ n2 = n2->nif.elsepart;
+ n2->type = NIF;
+ if ((n2->nif.test = list(0)) == NULL)
+ synexpect(-1);
+ consumetoken(TTHEN);
+ n2->nif.ifpart = list(0);
+ }
+ if (lasttoken == TELSE)
+ n2->nif.elsepart = list(0);
+ else {
+ n2->nif.elsepart = NULL;
+ tokpushback++;
+ }
+ consumetoken(TFI);
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ case TWHILE:
+ case TUNTIL:
+ t = lasttoken;
+ if ((n1 = list(0)) == NULL)
+ synexpect(-1);
+ consumetoken(TDO);
+ n1 = makebinary((t == TWHILE)? NWHILE : NUNTIL, n1, list(0));
+ consumetoken(TDONE);
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ case TFOR:
+ if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
+ synerror("Bad for loop variable");
+ n1 = (union node *)stalloc(sizeof (struct nfor));
+ n1->type = NFOR;
+ n1->nfor.var = wordtext;
+ while (readtoken() == TNL)
+ ;
+ if (lasttoken == TWORD && ! quoteflag && equal(wordtext, "in")) {
+ app = &ap;
+ while (readtoken() == TWORD) {
+ n2 = makename();
+ *app = n2;
+ app = &n2->narg.next;
+ }
+ *app = NULL;
+ n1->nfor.args = ap;
+ if (lasttoken != TNL && lasttoken != TSEMI)
+ synexpect(-1);
+ } else {
+ static char argvars[5] = {
+ CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'
+ };
+ n2 = (union node *)stalloc(sizeof (struct narg));
+ n2->type = NARG;
+ n2->narg.text = argvars;
+ n2->narg.backquote = NULL;
+ n2->narg.next = NULL;
+ n1->nfor.args = n2;
+ /*
+ * Newline or semicolon here is optional (but note
+ * that the original Bourne shell only allowed NL).
+ */
+ if (lasttoken != TNL && lasttoken != TSEMI)
+ tokpushback++;
+ }
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if ((t = readtoken()) == TDO)
+ t = TDONE;
+ else if (t == TBEGIN)
+ t = TEND;
+ else
+ synexpect(-1);
+ n1->nfor.body = list(0);
+ consumetoken(t);
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ case TCASE:
+ n1 = (union node *)stalloc(sizeof (struct ncase));
+ n1->type = NCASE;
+ consumetoken(TWORD);
+ n1->ncase.expr = makename();
+ while (readtoken() == TNL);
+ if (lasttoken != TWORD || ! equal(wordtext, "in"))
+ synerror("expecting \"in\"");
+ cpp = &n1->ncase.cases;
+ checkkwd = CHKNL | CHKKWD, readtoken();
+ while (lasttoken != TESAC) {
+ *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
+ cp->type = NCLIST;
+ app = &cp->nclist.pattern;
+ if (lasttoken == TLP)
+ readtoken();
+ for (;;) {
+ *app = ap = makename();
+ checkkwd = CHKNL | CHKKWD;
+ if (readtoken() != TPIPE)
+ break;
+ app = &ap->narg.next;
+ readtoken();
+ }
+ ap->narg.next = NULL;
+ if (lasttoken != TRP)
+ synexpect(TRP);
+ cp->nclist.body = list(0);
+
+ checkkwd = CHKNL | CHKKWD | CHKALIAS;
+ if ((t = readtoken()) != TESAC) {
+ if (t == TENDCASE)
+ ;
+ else if (t == TFALLTHRU)
+ cp->type = NCLISTFALLTHRU;
+ else
+ synexpect(TENDCASE);
+ checkkwd = CHKNL | CHKKWD, readtoken();
+ }
+ cpp = &cp->nclist.next;
+ }
+ *cpp = NULL;
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ case TLP:
+ n1 = (union node *)stalloc(sizeof (struct nredir));
+ n1->type = NSUBSHELL;
+ n1->nredir.n = list(0);
+ n1->nredir.redirect = NULL;
+ consumetoken(TRP);
+ checkkwd = CHKKWD | CHKALIAS;
+ is_subshell = 1;
+ break;
+ case TBEGIN:
+ n1 = list(0);
+ consumetoken(TEND);
+ checkkwd = CHKKWD | CHKALIAS;
+ break;
+ /* A simple command must have at least one redirection or word. */
+ case TBACKGND:
+ case TSEMI:
+ case TAND:
+ case TOR:
+ case TPIPE:
+ case TENDCASE:
+ case TFALLTHRU:
+ case TEOF:
+ case TNL:
+ case TRP:
+ if (!redir)
+ synexpect(-1);
+ case TWORD:
+ tokpushback++;
+ n1 = simplecmd(rpp, redir);
+ return n1;
+ default:
+ synexpect(-1);
+ }
+
+ /* Now check for redirection which may follow command */
+ while (readtoken() == TREDIR) {
+ *rpp = n2 = redirnode;
+ rpp = &n2->nfile.next;
+ parsefname();
+ }
+ tokpushback++;
+ *rpp = NULL;
+ if (redir) {
+ if (!is_subshell) {
+ n2 = (union node *)stalloc(sizeof (struct nredir));
+ n2->type = NREDIR;
+ n2->nredir.n = n1;
+ n1 = n2;
+ }
+ n1->nredir.redirect = redir;
+ }
+
+ return n1;
+}
+
+
+static union node *
+simplecmd(union node **rpp, union node *redir)
+{
+ union node *args, **app;
+ union node **orig_rpp = rpp;
+ union node *n = NULL;
+ int special;
+ int savecheckkwd;
+
+ /* If we don't have any redirections already, then we must reset */
+ /* rpp to be the address of the local redir variable. */
+ if (redir == NULL)
+ rpp = &redir;
+
+ args = NULL;
+ app = &args;
+ /*
+ * We save the incoming value, because we need this for shell
+ * functions. There can not be a redirect or an argument between
+ * the function name and the open parenthesis.
+ */
+ orig_rpp = rpp;
+
+ savecheckkwd = CHKALIAS;
+
+ for (;;) {
+ checkkwd = savecheckkwd;
+ if (readtoken() == TWORD) {
+ n = makename();
+ *app = n;
+ app = &n->narg.next;
+ if (savecheckkwd != 0 && !isassignment(wordtext))
+ savecheckkwd = 0;
+ } else if (lasttoken == TREDIR) {
+ *rpp = n = redirnode;
+ rpp = &n->nfile.next;
+ parsefname(); /* read name of redirection file */
+ } else if (lasttoken == TLP && app == &args->narg.next
+ && rpp == orig_rpp) {
+ /* We have a function */
+ consumetoken(TRP);
+ funclinno = plinno;
+ /*
+ * - Require plain text.
+ * - Functions with '/' cannot be called.
+ * - Reject name=().
+ * - Reject ksh extended glob patterns.
+ */
+ if (!noexpand(n->narg.text) || quoteflag ||
+ strchr(n->narg.text, '/') ||
+ strchr("!%*+-=?@}~",
+ n->narg.text[strlen(n->narg.text) - 1]))
+ synerror("Bad function name");
+ rmescapes(n->narg.text);
+ if (find_builtin(n->narg.text, &special) >= 0 &&
+ special)
+ synerror("Cannot override a special builtin with a function");
+ n->type = NDEFUN;
+ n->narg.next = command();
+ funclinno = 0;
+ return n;
+ } else {
+ tokpushback++;
+ break;
+ }
+ }
+ *app = NULL;
+ *rpp = NULL;
+ n = (union node *)stalloc(sizeof (struct ncmd));
+ n->type = NCMD;
+ n->ncmd.args = args;
+ n->ncmd.redirect = redir;
+ return n;
+}
+
+static union node *
+makename(void)
+{
+ union node *n;
+
+ n = (union node *)stalloc(sizeof (struct narg));
+ n->type = NARG;
+ n->narg.next = NULL;
+ n->narg.text = wordtext;
+ n->narg.backquote = backquotelist;
+ return n;
+}
+
+static union node *
+makebinary(int type, union node *n1, union node *n2)
+{
+ union node *n;
+
+ n = (union node *)stalloc(sizeof (struct nbinary));
+ n->type = type;
+ n->nbinary.ch1 = n1;
+ n->nbinary.ch2 = n2;
+ return (n);
+}
+
+void
+forcealias(void)
+{
+ checkkwd |= CHKALIAS;
+}
+
+void
+fixredir(union node *n, const char *text, int err)
+{
+ TRACE(("Fix redir %s %d\n", text, err));
+ if (!err)
+ n->ndup.vname = NULL;
+
+ if (is_digit(text[0]) && text[1] == '\0')
+ n->ndup.dupfd = digit_val(text[0]);
+ else if (text[0] == '-' && text[1] == '\0')
+ n->ndup.dupfd = -1;
+ else {
+
+ if (err)
+ synerror("Bad fd number");
+ else
+ n->ndup.vname = makename();
+ }
+}
+
+
+static void
+parsefname(void)
+{
+ union node *n = redirnode;
+
+ consumetoken(TWORD);
+ if (n->type == NHERE) {
+ struct heredoc *here = heredoc;
+ struct heredoc *p;
+
+ if (quoteflag == 0)
+ n->type = NXHERE;
+ TRACE(("Here document %d\n", n->type));
+ if (here->striptabs) {
+ while (*wordtext == '\t')
+ wordtext++;
+ }
+ if (! noexpand(wordtext))
+ synerror("Illegal eof marker for << redirection");
+ rmescapes(wordtext);
+ here->eofmark = wordtext;
+ here->next = NULL;
+ if (heredoclist == NULL)
+ heredoclist = here;
+ else {
+ for (p = heredoclist ; p->next ; p = p->next);
+ p->next = here;
+ }
+ } else if (n->type == NTOFD || n->type == NFROMFD) {
+ fixredir(n, wordtext, 0);
+ } else {
+ n->nfile.fname = makename();
+ }
+}
+
+
+/*
+ * Input any here documents.
+ */
+
+static void
+parseheredoc(void)
+{
+ struct heredoc *here;
+ union node *n;
+
+ while (heredoclist) {
+ here = heredoclist;
+ heredoclist = here->next;
+ if (needprompt) {
+ setprompt(2);
+ needprompt = 0;
+ }
+ readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
+ here->eofmark, here->striptabs);
+ n = makename();
+ here->here->nhere.doc = n;
+ }
+}
+
+static int
+peektoken(void)
+{
+ int t;
+
+ t = readtoken();
+ tokpushback++;
+ return (t);
+}
+
+static int
+readtoken(void)
+{
+ int t;
+ struct alias *ap;
+#ifdef DEBUG
+ int alreadyseen = tokpushback;
+#endif
+
+ top:
+ t = xxreadtoken();
+
+ /*
+ * eat newlines
+ */
+ if (checkkwd & CHKNL) {
+ while (t == TNL) {
+ parseheredoc();
+ t = xxreadtoken();
+ }
+ }
+
+ /*
+ * check for keywords and aliases
+ */
+ if (t == TWORD && !quoteflag)
+ {
+ const char * const *pp;
+
+ if (checkkwd & CHKKWD)
+ for (pp = parsekwd; *pp; pp++) {
+ if (**pp == *wordtext && equal(*pp, wordtext))
+ {
+ lasttoken = t = pp - parsekwd + KWDOFFSET;
+ TRACE(("keyword %s recognized\n", tokname[t]));
+ goto out;
+ }
+ }
+ if (checkkwd & CHKALIAS &&
+ (ap = lookupalias(wordtext, 1)) != NULL) {
+ pushstring(ap->val, strlen(ap->val), ap);
+ goto top;
+ }
+ }
+out:
+ if (t != TNOT)
+ checkkwd = 0;
+
+#ifdef DEBUG
+ if (!alreadyseen)
+ TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+ else
+ TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
+#endif
+ return (t);
+}
+
+
+/*
+ * Read the next input token.
+ * If the token is a word, we set backquotelist to the list of cmds in
+ * backquotes. We set quoteflag to true if any part of the word was
+ * quoted.
+ * If the token is TREDIR, then we set redirnode to a structure containing
+ * the redirection.
+ * In all cases, the variable startlinno is set to the number of the line
+ * on which the token starts.
+ *
+ * [Change comment: here documents and internal procedures]
+ * [Readtoken shouldn't have any arguments. Perhaps we should make the
+ * word parsing code into a separate routine. In this case, readtoken
+ * doesn't need to have any internal procedures, but parseword does.
+ * We could also make parseoperator in essence the main routine, and
+ * have parseword (readtoken1?) handle both words and redirection.]
+ */
+
+#define RETURN(token) return lasttoken = token
+
+static int
+xxreadtoken(void)
+{
+ int c;
+
+ if (tokpushback) {
+ tokpushback = 0;
+ return lasttoken;
+ }
+ if (needprompt) {
+ setprompt(2);
+ needprompt = 0;
+ }
+ startlinno = plinno;
+ for (;;) { /* until token or start of word found */
+ c = pgetc_macro();
+ switch (c) {
+ case ' ': case '\t':
+ continue;
+ case '#':
+ while ((c = pgetc()) != '\n' && c != PEOF);
+ pungetc();
+ continue;
+ case '\\':
+ if (pgetc() == '\n') {
+ startlinno = ++plinno;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ continue;
+ }
+ pungetc();
+ /* FALLTHROUGH */
+ default:
+ return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
+ case '\n':
+ plinno++;
+ needprompt = doprompt;
+ RETURN(TNL);
+ case PEOF:
+ RETURN(TEOF);
+ case '&':
+ if (pgetc_linecont() == '&')
+ RETURN(TAND);
+ pungetc();
+ RETURN(TBACKGND);
+ case '|':
+ if (pgetc_linecont() == '|')
+ RETURN(TOR);
+ pungetc();
+ RETURN(TPIPE);
+ case ';':
+ c = pgetc_linecont();
+ if (c == ';')
+ RETURN(TENDCASE);
+ else if (c == '&')
+ RETURN(TFALLTHRU);
+ pungetc();
+ RETURN(TSEMI);
+ case '(':
+ RETURN(TLP);
+ case ')':
+ RETURN(TRP);
+ }
+ }
+#undef RETURN
+}
+
+
+#define MAXNEST_static 8
+struct tokenstate
+{
+ const char *syntax; /* *SYNTAX */
+ int parenlevel; /* levels of parentheses in arithmetic */
+ enum tokenstate_category
+ {
+ TSTATE_TOP,
+ TSTATE_VAR_OLD, /* ${var+-=?}, inherits dquotes */
+ TSTATE_VAR_NEW, /* other ${var...}, own dquote state */
+ TSTATE_ARITH
+ } category;
+};
+
+
+/*
+ * Check to see whether we are at the end of the here document. When this
+ * is called, c is set to the first character of the next input line. If
+ * we are at the end of the here document, this routine sets the c to PEOF.
+ * The new value of c is returned.
+ */
+
+static int
+checkend(int c, const char *eofmark, int striptabs)
+{
+ if (striptabs) {
+ while (c == '\t')
+ c = pgetc();
+ }
+ if (c == *eofmark) {
+ int c2;
+ const char *q;
+
+ for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++)
+ ;
+ if ((c2 == PEOF || c2 == '\n') && *q == '\0') {
+ c = PEOF;
+ if (c2 == '\n') {
+ plinno++;
+ needprompt = doprompt;
+ }
+ } else {
+ pungetc();
+ pushstring(eofmark + 1, q - (eofmark + 1), NULL);
+ }
+ } else if (c == '\n' && *eofmark == '\0') {
+ c = PEOF;
+ plinno++;
+ needprompt = doprompt;
+ }
+ return (c);
+}
+
+
+/*
+ * Parse a redirection operator. The variable "out" points to a string
+ * specifying the fd to be redirected. The variable "c" contains the
+ * first character of the redirection operator.
+ */
+
+static void
+parseredir(char *out, int c)
+{
+ char fd = *out;
+ union node *np;
+
+ np = (union node *)stalloc(sizeof (struct nfile));
+ if (c == '>') {
+ np->nfile.fd = 1;
+ c = pgetc_linecont();
+ if (c == '>')
+ np->type = NAPPEND;
+ else if (c == '&')
+ np->type = NTOFD;
+ else if (c == '|')
+ np->type = NCLOBBER;
+ else {
+ np->type = NTO;
+ pungetc();
+ }
+ } else { /* c == '<' */
+ np->nfile.fd = 0;
+ c = pgetc_linecont();
+ if (c == '<') {
+ if (sizeof (struct nfile) != sizeof (struct nhere)) {
+ np = (union node *)stalloc(sizeof (struct nhere));
+ np->nfile.fd = 0;
+ }
+ np->type = NHERE;
+ heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
+ heredoc->here = np;
+ if ((c = pgetc_linecont()) == '-') {
+ heredoc->striptabs = 1;
+ } else {
+ heredoc->striptabs = 0;
+ pungetc();
+ }
+ } else if (c == '&')
+ np->type = NFROMFD;
+ else if (c == '>')
+ np->type = NFROMTO;
+ else {
+ np->type = NFROM;
+ pungetc();
+ }
+ }
+ if (fd != '\0')
+ np->nfile.fd = digit_val(fd);
+ redirnode = np;
+}
+
+/*
+ * Called to parse command substitutions.
+ */
+
+static char *
+parsebackq(char *out, struct nodelist **pbqlist,
+ int oldstyle, int dblquote, int quoted)
+{
+ struct nodelist **nlpp;
+ union node *n;
+ char *volatile str;
+ struct jmploc jmploc;
+ struct jmploc *const savehandler = handler;
+ size_t savelen;
+ int saveprompt;
+ const int bq_startlinno = plinno;
+ char *volatile ostr = NULL;
+ struct parsefile *const savetopfile = getcurrentfile();
+ struct heredoc *const saveheredoclist = heredoclist;
+ struct heredoc *here;
+
+ str = NULL;
+ if (setjmp(jmploc.loc)) {
+ popfilesupto(savetopfile);
+ if (str)
+ ckfree(str);
+ if (ostr)
+ ckfree(ostr);
+ heredoclist = saveheredoclist;
+ handler = savehandler;
+ if (exception == EXERROR) {
+ startlinno = bq_startlinno;
+ synerror("Error in command substitution");
+ }
+ longjmp(handler->loc, 1);
+ }
+ INTOFF;
+ savelen = out - stackblock();
+ if (savelen > 0) {
+ str = ckmalloc(savelen);
+ memcpy(str, stackblock(), savelen);
+ }
+ handler = &jmploc;
+ heredoclist = NULL;
+ INTON;
+ if (oldstyle) {
+ /* We must read until the closing backquote, giving special
+ treatment to some slashes, and then push the string and
+ reread it as input, interpreting it normally. */
+ char *oout;
+ int c;
+ int olen;
+
+
+ STARTSTACKSTR(oout);
+ for (;;) {
+ if (needprompt) {
+ setprompt(2);
+ needprompt = 0;
+ }
+ CHECKSTRSPACE(2, oout);
+ c = pgetc_linecont();
+ if (c == '`')
+ break;
+ switch (c) {
+ case '\\':
+ c = pgetc();
+ if (c != '\\' && c != '`' && c != '$'
+ && (!dblquote || c != '"'))
+ USTPUTC('\\', oout);
+ break;
+
+ case '\n':
+ plinno++;
+ needprompt = doprompt;
+ break;
+
+ case PEOF:
+ startlinno = plinno;
+ synerror("EOF in backquote substitution");
+ break;
+
+ default:
+ break;
+ }
+ USTPUTC(c, oout);
+ }
+ USTPUTC('\0', oout);
+ olen = oout - stackblock();
+ INTOFF;
+ ostr = ckmalloc(olen);
+ memcpy(ostr, stackblock(), olen);
+ setinputstring(ostr, 1);
+ INTON;
+ }
+ nlpp = pbqlist;
+ while (*nlpp)
+ nlpp = &(*nlpp)->next;
+ *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
+ (*nlpp)->next = NULL;
+
+ if (oldstyle) {
+ saveprompt = doprompt;
+ doprompt = 0;
+ }
+
+ n = list(0);
+
+ if (oldstyle) {
+ if (peektoken() != TEOF)
+ synexpect(-1);
+ doprompt = saveprompt;
+ } else
+ consumetoken(TRP);
+
+ (*nlpp)->n = n;
+ if (oldstyle) {
+ /*
+ * Start reading from old file again, ignoring any pushed back
+ * tokens left from the backquote parsing
+ */
+ popfile();
+ tokpushback = 0;
+ }
+ STARTSTACKSTR(out);
+ CHECKSTRSPACE(savelen + 1, out);
+ INTOFF;
+ if (str) {
+ memcpy(out, str, savelen);
+ STADJUST(savelen, out);
+ ckfree(str);
+ str = NULL;
+ }
+ if (ostr) {
+ ckfree(ostr);
+ ostr = NULL;
+ }
+ here = saveheredoclist;
+ if (here != NULL) {
+ while (here->next != NULL)
+ here = here->next;
+ here->next = heredoclist;
+ heredoclist = saveheredoclist;
+ }
+ handler = savehandler;
+ INTON;
+ if (quoted)
+ USTPUTC(CTLBACKQ | CTLQUOTE, out);
+ else
+ USTPUTC(CTLBACKQ, out);
+ return out;
+}
+
+
+/*
+ * Called to parse a backslash escape sequence inside $'...'.
+ * The backslash has already been read.
+ */
+static char *
+readcstyleesc(char *out)
+{
+ int c, vc, i, n;
+ unsigned int v;
+
+ c = pgetc();
+ switch (c) {
+ case '\0':
+ synerror("Unterminated quoted string");
+ case '\n':
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ return out;
+ case '\\':
+ case '\'':
+ case '"':
+ v = c;
+ break;
+ case 'a': v = '\a'; break;
+ case 'b': v = '\b'; break;
+ case 'e': v = '\033'; break;
+ case 'f': v = '\f'; break;
+ case 'n': v = '\n'; break;
+ case 'r': v = '\r'; break;
+ case 't': v = '\t'; break;
+ case 'v': v = '\v'; break;
+ case 'x':
+ v = 0;
+ for (;;) {
+ c = pgetc();
+ if (c >= '0' && c <= '9')
+ v = (v << 4) + c - '0';
+ else if (c >= 'A' && c <= 'F')
+ v = (v << 4) + c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ v = (v << 4) + c - 'a' + 10;
+ else
+ break;
+ }
+ pungetc();
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ v = c - '0';
+ c = pgetc();
+ if (c >= '0' && c <= '7') {
+ v <<= 3;
+ v += c - '0';
+ c = pgetc();
+ if (c >= '0' && c <= '7') {
+ v <<= 3;
+ v += c - '0';
+ } else
+ pungetc();
+ } else
+ pungetc();
+ break;
+ case 'c':
+ c = pgetc();
+ if (c < 0x3f || c > 0x7a || c == 0x60)
+ synerror("Bad escape sequence");
+ if (c == '\\' && pgetc() != '\\')
+ synerror("Bad escape sequence");
+ if (c == '?')
+ v = 127;
+ else
+ v = c & 0x1f;
+ break;
+ case 'u':
+ case 'U':
+ n = c == 'U' ? 8 : 4;
+ v = 0;
+ for (i = 0; i < n; i++) {
+ c = pgetc();
+ if (c >= '0' && c <= '9')
+ v = (v << 4) + c - '0';
+ else if (c >= 'A' && c <= 'F')
+ v = (v << 4) + c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ v = (v << 4) + c - 'a' + 10;
+ else
+ synerror("Bad escape sequence");
+ }
+ if (v == 0 || (v >= 0xd800 && v <= 0xdfff))
+ synerror("Bad escape sequence");
+ /* We really need iconv here. */
+ if (initial_localeisutf8 && v > 127) {
+ CHECKSTRSPACE(4, out);
+ /*
+ * We cannot use wctomb() as the locale may have
+ * changed.
+ */
+ if (v <= 0x7ff) {
+ USTPUTC(0xc0 | v >> 6, out);
+ USTPUTC(0x80 | (v & 0x3f), out);
+ return out;
+ } else if (v <= 0xffff) {
+ USTPUTC(0xe0 | v >> 12, out);
+ USTPUTC(0x80 | ((v >> 6) & 0x3f), out);
+ USTPUTC(0x80 | (v & 0x3f), out);
+ return out;
+ } else if (v <= 0x10ffff) {
+ USTPUTC(0xf0 | v >> 18, out);
+ USTPUTC(0x80 | ((v >> 12) & 0x3f), out);
+ USTPUTC(0x80 | ((v >> 6) & 0x3f), out);
+ USTPUTC(0x80 | (v & 0x3f), out);
+ return out;
+ }
+ }
+ if (v > 127)
+ v = '?';
+ break;
+ default:
+ synerror("Bad escape sequence");
+ }
+ vc = (char)v;
+ /*
+ * We can't handle NUL bytes.
+ * POSIX says we should skip till the closing quote.
+ */
+ if (vc == '\0') {
+ while ((c = pgetc()) != '\'') {
+ if (c == '\\')
+ c = pgetc();
+ if (c == PEOF)
+ synerror("Unterminated quoted string");
+ if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ }
+ }
+ pungetc();
+ return out;
+ }
+ if (SQSYNTAX[vc] == CCTL)
+ USTPUTC(CTLESC, out);
+ USTPUTC(vc, out);
+ return out;
+}
+
+
+/*
+ * If eofmark is NULL, read a word or a redirection symbol. If eofmark
+ * is not NULL, read a here document. In the latter case, eofmark is the
+ * word which marks the end of the document and striptabs is true if
+ * leading tabs should be stripped from the document. The argument firstc
+ * is the first character of the input token or document.
+ *
+ * Because C does not have internal subroutines, I have simulated them
+ * using goto's to implement the subroutine linkage. The following macros
+ * will run code that appears at the end of readtoken1.
+ */
+
+#define PARSESUB() {goto parsesub; parsesub_return:;}
+#define PARSEARITH() {goto parsearith; parsearith_return:;}
+
+static int
+readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
+ int striptabs)
+{
+ int c = firstc;
+ char *out;
+ int len;
+ struct nodelist *bqlist;
+ int quotef;
+ int newvarnest;
+ int level;
+ int synentry;
+ struct tokenstate state_static[MAXNEST_static];
+ int maxnest = MAXNEST_static;
+ struct tokenstate *state = state_static;
+ int sqiscstyle = 0;
+
+ startlinno = plinno;
+ quotef = 0;
+ bqlist = NULL;
+ newvarnest = 0;
+ level = 0;
+ state[level].syntax = initialsyntax;
+ state[level].parenlevel = 0;
+ state[level].category = TSTATE_TOP;
+
+ STARTSTACKSTR(out);
+ loop: { /* for each line, until end of word */
+ if (eofmark && eofmark != NOEOFMARK)
+ /* set c to PEOF if at end of here document */
+ c = checkend(c, eofmark, striptabs);
+ for (;;) { /* until end of line or end of word */
+ CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
+
+ synentry = state[level].syntax[c];
+
+ switch(synentry) {
+ case CNL: /* '\n' */
+ if (state[level].syntax == BASESYNTAX)
+ goto endword; /* exit outer loop */
+ USTPUTC(c, out);
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ c = pgetc();
+ goto loop; /* continue outer loop */
+ case CSBACK:
+ if (sqiscstyle) {
+ out = readcstyleesc(out);
+ break;
+ }
+ /* FALLTHROUGH */
+ case CWORD:
+ USTPUTC(c, out);
+ break;
+ case CCTL:
+ if (eofmark == NULL || initialsyntax != SQSYNTAX)
+ USTPUTC(CTLESC, out);
+ USTPUTC(c, out);
+ break;
+ case CBACK: /* backslash */
+ c = pgetc();
+ if (c == PEOF) {
+ USTPUTC('\\', out);
+ pungetc();
+ } else if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ } else {
+ if (state[level].syntax == DQSYNTAX &&
+ c != '\\' && c != '`' && c != '$' &&
+ (c != '"' || (eofmark != NULL &&
+ newvarnest == 0)) &&
+ (c != '}' || state[level].category != TSTATE_VAR_OLD))
+ USTPUTC('\\', out);
+ if ((eofmark == NULL ||
+ newvarnest > 0) &&
+ state[level].syntax == BASESYNTAX)
+ USTPUTC(CTLQUOTEMARK, out);
+ if (SQSYNTAX[c] == CCTL)
+ USTPUTC(CTLESC, out);
+ USTPUTC(c, out);
+ if ((eofmark == NULL ||
+ newvarnest > 0) &&
+ state[level].syntax == BASESYNTAX &&
+ state[level].category == TSTATE_VAR_OLD)
+ USTPUTC(CTLQUOTEEND, out);
+ quotef++;
+ }
+ break;
+ case CSQUOTE:
+ USTPUTC(CTLQUOTEMARK, out);
+ state[level].syntax = SQSYNTAX;
+ sqiscstyle = 0;
+ break;
+ case CDQUOTE:
+ USTPUTC(CTLQUOTEMARK, out);
+ state[level].syntax = DQSYNTAX;
+ break;
+ case CENDQUOTE:
+ if (eofmark != NULL && newvarnest == 0)
+ USTPUTC(c, out);
+ else {
+ if (state[level].category == TSTATE_VAR_OLD)
+ USTPUTC(CTLQUOTEEND, out);
+ state[level].syntax = BASESYNTAX;
+ quotef++;
+ }
+ break;
+ case CVAR: /* '$' */
+ PARSESUB(); /* parse substitution */
+ break;
+ case CENDVAR: /* '}' */
+ if (level > 0 &&
+ ((state[level].category == TSTATE_VAR_OLD &&
+ state[level].syntax ==
+ state[level - 1].syntax) ||
+ (state[level].category == TSTATE_VAR_NEW &&
+ state[level].syntax == BASESYNTAX))) {
+ if (state[level].category == TSTATE_VAR_NEW)
+ newvarnest--;
+ level--;
+ USTPUTC(CTLENDVAR, out);
+ } else {
+ USTPUTC(c, out);
+ }
+ break;
+ case CLP: /* '(' in arithmetic */
+ state[level].parenlevel++;
+ USTPUTC(c, out);
+ break;
+ case CRP: /* ')' in arithmetic */
+ if (state[level].parenlevel > 0) {
+ USTPUTC(c, out);
+ --state[level].parenlevel;
+ } else {
+ if (pgetc_linecont() == ')') {
+ if (level > 0 &&
+ state[level].category == TSTATE_ARITH) {
+ level--;
+ USTPUTC(CTLENDARI, out);
+ } else
+ USTPUTC(')', out);
+ } else {
+ /*
+ * unbalanced parens
+ * (don't 2nd guess - no error)
+ */
+ pungetc();
+ USTPUTC(')', out);
+ }
+ }
+ break;
+ case CBQUOTE: /* '`' */
+ out = parsebackq(out, &bqlist, 1,
+ state[level].syntax == DQSYNTAX &&
+ (eofmark == NULL || newvarnest > 0),
+ state[level].syntax == DQSYNTAX || state[level].syntax == ARISYNTAX);
+ break;
+ case CEOF:
+ goto endword; /* exit outer loop */
+ case CIGN:
+ break;
+ default:
+ if (level == 0)
+ goto endword; /* exit outer loop */
+ USTPUTC(c, out);
+ }
+ c = pgetc_macro();
+ }
+ }
+endword:
+ if (state[level].syntax == ARISYNTAX)
+ synerror("Missing '))'");
+ if (state[level].syntax != BASESYNTAX && eofmark == NULL)
+ synerror("Unterminated quoted string");
+ if (state[level].category == TSTATE_VAR_OLD ||
+ state[level].category == TSTATE_VAR_NEW) {
+ startlinno = plinno;
+ synerror("Missing '}'");
+ }
+ if (state != state_static)
+ parser_temp_free_upto(state);
+ USTPUTC('\0', out);
+ len = out - stackblock();
+ out = stackblock();
+ if (eofmark == NULL) {
+ if ((c == '>' || c == '<')
+ && quotef == 0
+ && len <= 2
+ && (*out == '\0' || is_digit(*out))) {
+ parseredir(out, c);
+ return lasttoken = TREDIR;
+ } else {
+ pungetc();
+ }
+ }
+ quoteflag = quotef;
+ backquotelist = bqlist;
+ grabstackblock(len);
+ wordtext = out;
+ return lasttoken = TWORD;
+/* end of readtoken routine */
+
+
+/*
+ * Parse a substitution. At this point, we have read the dollar sign
+ * and nothing else.
+ */
+
+parsesub: {
+ int subtype;
+ int typeloc;
+ int flags;
+ char *p;
+ static const char types[] = "}-+?=";
+ int linno;
+ int length;
+ int c1;
+
+ c = pgetc_linecont();
+ if (c == '(') { /* $(command) or $((arith)) */
+ if (pgetc_linecont() == '(') {
+ PARSEARITH();
+ } else {
+ pungetc();
+ out = parsebackq(out, &bqlist, 0,
+ state[level].syntax == DQSYNTAX &&
+ (eofmark == NULL || newvarnest > 0),
+ state[level].syntax == DQSYNTAX ||
+ state[level].syntax == ARISYNTAX);
+ }
+ } else if (c == '{' || is_name(c) || is_special(c)) {
+ USTPUTC(CTLVAR, out);
+ typeloc = out - stackblock();
+ USTPUTC(VSNORMAL, out);
+ subtype = VSNORMAL;
+ flags = 0;
+ if (c == '{') {
+ c = pgetc_linecont();
+ subtype = 0;
+ }
+varname:
+ if (!is_eof(c) && is_name(c)) {
+ length = 0;
+ do {
+ STPUTC(c, out);
+ c = pgetc_linecont();
+ length++;
+ } while (!is_eof(c) && is_in_name(c));
+ if (length == 6 &&
+ strncmp(out - length, "LINENO", length) == 0) {
+ /* Replace the variable name with the
+ * current line number. */
+ STADJUST(-6, out);
+ CHECKSTRSPACE(11, out);
+ linno = plinno;
+ if (funclinno != 0)
+ linno -= funclinno - 1;
+ length = snprintf(out, 11, "%d", linno);
+ if (length > 10)
+ length = 10;
+ out += length;
+ flags |= VSLINENO;
+ }
+ } else if (is_digit(c)) {
+ if (subtype != VSNORMAL) {
+ do {
+ STPUTC(c, out);
+ c = pgetc_linecont();
+ } while (is_digit(c));
+ } else {
+ USTPUTC(c, out);
+ c = pgetc_linecont();
+ }
+ } else if (is_special(c)) {
+ c1 = c;
+ c = pgetc_linecont();
+ if (subtype == 0 && c1 == '#') {
+ subtype = VSLENGTH;
+ if (strchr(types, c) == NULL && c != ':' &&
+ c != '#' && c != '%')
+ goto varname;
+ c1 = c;
+ c = pgetc_linecont();
+ if (c1 != '}' && c == '}') {
+ pungetc();
+ c = c1;
+ goto varname;
+ }
+ pungetc();
+ c = c1;
+ c1 = '#';
+ subtype = 0;
+ }
+ USTPUTC(c1, out);
+ } else {
+ subtype = VSERROR;
+ if (c == '}')
+ pungetc();
+ else if (c == '\n' || c == PEOF)
+ synerror("Unexpected end of line in substitution");
+ else if (BASESYNTAX[c] != CCTL)
+ USTPUTC(c, out);
+ }
+ if (subtype == 0) {
+ switch (c) {
+ case ':':
+ flags |= VSNUL;
+ c = pgetc_linecont();
+ /*FALLTHROUGH*/
+ default:
+ p = strchr(types, c);
+ if (p == NULL) {
+ if (c == '\n' || c == PEOF)
+ synerror("Unexpected end of line in substitution");
+ if (flags == VSNUL)
+ STPUTC(':', out);
+ if (BASESYNTAX[c] != CCTL)
+ STPUTC(c, out);
+ subtype = VSERROR;
+ } else
+ subtype = p - types + VSNORMAL;
+ break;
+ case '%':
+ case '#':
+ {
+ int cc = c;
+ subtype = c == '#' ? VSTRIMLEFT :
+ VSTRIMRIGHT;
+ c = pgetc_linecont();
+ if (c == cc)
+ subtype++;
+ else
+ pungetc();
+ break;
+ }
+ }
+ } else if (subtype != VSERROR) {
+ if (subtype == VSLENGTH && c != '}')
+ subtype = VSERROR;
+ pungetc();
+ }
+ STPUTC('=', out);
+ if (state[level].syntax == DQSYNTAX ||
+ state[level].syntax == ARISYNTAX)
+ flags |= VSQUOTE;
+ *(stackblock() + typeloc) = subtype | flags;
+ if (subtype != VSNORMAL) {
+ if (level + 1 >= maxnest) {
+ maxnest *= 2;
+ if (state == state_static) {
+ state = parser_temp_alloc(
+ maxnest * sizeof(*state));
+ memcpy(state, state_static,
+ MAXNEST_static * sizeof(*state));
+ } else
+ state = parser_temp_realloc(state,
+ maxnest * sizeof(*state));
+ }
+ level++;
+ state[level].parenlevel = 0;
+ if (subtype == VSMINUS || subtype == VSPLUS ||
+ subtype == VSQUESTION || subtype == VSASSIGN) {
+ /*
+ * For operators that were in the Bourne shell,
+ * inherit the double-quote state.
+ */
+ state[level].syntax = state[level - 1].syntax;
+ state[level].category = TSTATE_VAR_OLD;
+ } else {
+ /*
+ * The other operators take a pattern,
+ * so go to BASESYNTAX.
+ * Also, ' and " are now special, even
+ * in here documents.
+ */
+ state[level].syntax = BASESYNTAX;
+ state[level].category = TSTATE_VAR_NEW;
+ newvarnest++;
+ }
+ }
+ } else if (c == '\'' && state[level].syntax == BASESYNTAX) {
+ /* $'cstylequotes' */
+ USTPUTC(CTLQUOTEMARK, out);
+ state[level].syntax = SQSYNTAX;
+ sqiscstyle = 1;
+ } else {
+ USTPUTC('$', out);
+ pungetc();
+ }
+ goto parsesub_return;
+}
+
+
+/*
+ * Parse an arithmetic expansion (indicate start of one and set state)
+ */
+parsearith: {
+
+ if (level + 1 >= maxnest) {
+ maxnest *= 2;
+ if (state == state_static) {
+ state = parser_temp_alloc(
+ maxnest * sizeof(*state));
+ memcpy(state, state_static,
+ MAXNEST_static * sizeof(*state));
+ } else
+ state = parser_temp_realloc(state,
+ maxnest * sizeof(*state));
+ }
+ level++;
+ state[level].syntax = ARISYNTAX;
+ state[level].parenlevel = 0;
+ state[level].category = TSTATE_ARITH;
+ USTPUTC(CTLARI, out);
+ if (state[level - 1].syntax == DQSYNTAX)
+ USTPUTC('"',out);
+ else
+ USTPUTC(' ',out);
+ goto parsearith_return;
+}
+
+} /* end of readtoken */
+
+
+/*
+ * Returns true if the text contains nothing to expand (no dollar signs
+ * or backquotes).
+ */
+
+static int
+noexpand(char *text)
+{
+ char *p;
+ char c;
+
+ p = text;
+ while ((c = *p++) != '\0') {
+ if ( c == CTLQUOTEMARK)
+ continue;
+ if (c == CTLESC)
+ p++;
+ else if (BASESYNTAX[(int)c] == CCTL)
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ * Return true if the argument is a legal variable name (a letter or
+ * underscore followed by zero or more letters, underscores, and digits).
+ */
+
+int
+goodname(const char *name)
+{
+ const char *p;
+
+ p = name;
+ if (! is_name(*p))
+ return 0;
+ while (*++p) {
+ if (! is_in_name(*p))
+ return 0;
+ }
+ return 1;
+}
+
+
+int
+isassignment(const char *p)
+{
+ if (!is_name(*p))
+ return 0;
+ p++;
+ for (;;) {
+ if (*p == '=')
+ return 1;
+ else if (!is_in_name(*p))
+ return 0;
+ p++;
+ }
+}
+
+
+static void
+consumetoken(int token)
+{
+ if (readtoken() != token)
+ synexpect(token);
+}
+
+
+/*
+ * Called when an unexpected token is read during the parse. The argument
+ * is the token that is expected, or -1 if more than one type of token can
+ * occur at this point.
+ */
+
+static void
+synexpect(int token)
+{
+ char msg[64];
+
+ if (token >= 0) {
+ fmtstr(msg, 64, "%s unexpected (expecting %s)",
+ tokname[lasttoken], tokname[token]);
+ } else {
+ fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
+ }
+ synerror(msg);
+}
+
+
+static void
+synerror(const char *msg)
+{
+ if (commandname)
+ outfmt(out2, "%s: %d: ", commandname, startlinno);
+ else if (arg0)
+ outfmt(out2, "%s: ", arg0);
+ outfmt(out2, "Syntax error: %s\n", msg);
+ error((char *)NULL);
+}
+
+static void
+setprompt(int which)
+{
+ whichprompt = which;
+ if (which == 0)
+ return;
+
+#ifndef NO_HISTORY
+ if (!el)
+#endif
+ {
+ out2str(getprompt(NULL));
+ flushout(out2);
+ }
+}
+
+static int
+pgetc_linecont(void)
+{
+ int c;
+
+ while ((c = pgetc_macro()) == '\\') {
+ c = pgetc();
+ if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ } else {
+ pungetc();
+ /* Allow the backslash to be pushed back. */
+ pushstring("\\", 1, NULL);
+ return (pgetc());
+ }
+ }
+ return (c);
+}
+
+/*
+ * called by editline -- any expansions to the prompt
+ * should be added here.
+ */
+char *
+getprompt(void *unused __unused)
+{
+ static char ps[PROMPTLEN];
+ const char *fmt;
+ const char *pwd;
+ int i, trim;
+ static char internal_error[] = "??";
+
+ /*
+ * Select prompt format.
+ */
+ switch (whichprompt) {
+ case 0:
+ fmt = "";
+ break;
+ case 1:
+ fmt = ps1val();
+ break;
+ case 2:
+ fmt = ps2val();
+ break;
+ default:
+ return internal_error;
+ }
+
+ /*
+ * Format prompt string.
+ */
+ for (i = 0; (i < PROMPTLEN - 1) && (*fmt != '\0'); i++, fmt++)
+ if (*fmt == '\\')
+ switch (*++fmt) {
+
+ /*
+ * Hostname.
+ *
+ * \h specifies just the local hostname,
+ * \H specifies fully-qualified hostname.
+ */
+ case 'h':
+ case 'H':
+ ps[i] = '\0';
+ gethostname(&ps[i], PROMPTLEN - i - 1);
+ ps[PROMPTLEN - 1] = '\0';
+ /* Skip to end of hostname. */
+ trim = (*fmt == 'h') ? '.' : '\0';
+ while ((ps[i] != '\0') && (ps[i] != trim))
+ i++;
+ --i;
+ break;
+
+ /*
+ * Working directory.
+ *
+ * \W specifies just the final component,
+ * \w specifies the entire path.
+ */
+ case 'W':
+ case 'w':
+ pwd = lookupvar("PWD");
+ if (pwd == NULL || *pwd == '\0')
+ pwd = "?";
+ if (*fmt == 'W' &&
+ *pwd == '/' && pwd[1] != '\0')
+ strlcpy(&ps[i], strrchr(pwd, '/') + 1,
+ PROMPTLEN - i);
+ else
+ strlcpy(&ps[i], pwd, PROMPTLEN - i);
+ /* Skip to end of path. */
+ while (ps[i + 1] != '\0')
+ i++;
+ break;
+
+ /*
+ * Superuser status.
+ *
+ * '$' for normal users, '#' for root.
+ */
+ case '$':
+ ps[i] = (geteuid() != 0) ? '$' : '#';
+ break;
+
+ /*
+ * A literal \.
+ */
+ case '\\':
+ ps[i] = '\\';
+ break;
+
+ /*
+ * Emit unrecognized formats verbatim.
+ */
+ default:
+ ps[i] = '\\';
+ if (i < PROMPTLEN - 2)
+ ps[++i] = *fmt;
+ break;
+ }
+ else
+ ps[i] = *fmt;
+ ps[i] = '\0';
+ return (ps);
+}
+
+
+const char *
+expandstr(const char *ps)
+{
+ union node n;
+ struct jmploc jmploc;
+ struct jmploc *const savehandler = handler;
+ const int saveprompt = doprompt;
+ struct parsefile *const savetopfile = getcurrentfile();
+ struct parser_temp *const saveparser_temp = parser_temp;
+ const char *result = NULL;
+
+ if (!setjmp(jmploc.loc)) {
+ handler = &jmploc;
+ parser_temp = NULL;
+ setinputstring(ps, 1);
+ doprompt = 0;
+ readtoken1(pgetc(), DQSYNTAX, NOEOFMARK, 0);
+ if (backquotelist != NULL)
+ error("Command substitution not allowed here");
+
+ n.narg.type = NARG;
+ n.narg.next = NULL;
+ n.narg.text = wordtext;
+ n.narg.backquote = backquotelist;
+
+ expandarg(&n, NULL, 0);
+ result = stackblock();
+ INTOFF;
+ }
+ handler = savehandler;
+ doprompt = saveprompt;
+ popfilesupto(savetopfile);
+ if (parser_temp != saveparser_temp) {
+ parser_temp_free_all();
+ parser_temp = saveparser_temp;
+ }
+ if (result != NULL) {
+ INTON;
+ } else if (exception == EXINT)
+ raise(SIGINT);
+ return result;
+}
diff --git a/shell_cmds/sh/parser.h b/shell_cmds/sh/parser.h
new file mode 100644
index 0000000..210726b
--- /dev/null
+++ b/shell_cmds/sh/parser.h
@@ -0,0 +1,87 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)parser.h 8.3 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/parser.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+/* control characters in argument strings */
+#define CTLESC '\300'
+#define CTLVAR '\301'
+#define CTLENDVAR '\371'
+#define CTLBACKQ '\372'
+#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
+/* CTLBACKQ | CTLQUOTE == '\373' */
+#define CTLARI '\374'
+#define CTLENDARI '\375'
+#define CTLQUOTEMARK '\376'
+#define CTLQUOTEEND '\377' /* only for ${v+-...} */
+
+/* variable substitution byte (follows CTLVAR) */
+#define VSTYPE 0x0f /* type of variable substitution */
+#define VSNUL 0x10 /* colon--treat the empty string as unset */
+#define VSLINENO 0x20 /* expansion of $LINENO, the line number \
+ follows immediately */
+#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
+
+/* values of VSTYPE field */
+#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
+#define VSMINUS 0x2 /* ${var-text} */
+#define VSPLUS 0x3 /* ${var+text} */
+#define VSQUESTION 0x4 /* ${var?message} */
+#define VSASSIGN 0x5 /* ${var=text} */
+#define VSTRIMLEFT 0x6 /* ${var#pattern} */
+#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */
+#define VSTRIMRIGHT 0x8 /* ${var%pattern} */
+#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */
+#define VSLENGTH 0xa /* ${#var} */
+#define VSERROR 0xb /* Syntax error, issue when expanded */
+
+
+/*
+ * NEOF is returned by parsecmd when it encounters an end of file. It
+ * must be distinct from NULL.
+ */
+#define NEOF ((union node *)-1)
+extern int whichprompt; /* 1 == PS1, 2 == PS2 */
+extern const char *const parsekwd[];
+
+
+union node *parsecmd(int);
+union node *parsewordexp(void);
+void forcealias(void);
+void fixredir(union node *, const char *, int);
+int goodname(const char *);
+int isassignment(const char *);
+char *getprompt(void *);
+const char *expandstr(const char *);
diff --git a/shell_cmds/sh/redir.c b/shell_cmds/sh/redir.c
new file mode 100644
index 0000000..8f415a6
--- /dev/null
+++ b/shell_cmds/sh/redir.c
@@ -0,0 +1,365 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/redir.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/*
+ * Code for dealing with input/output redirection.
+ */
+
+#include "shell.h"
+#include "nodes.h"
+#include "jobs.h"
+#include "expand.h"
+#include "redir.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "options.h"
+
+
+#define EMPTY -2 /* marks an unused slot in redirtab */
+#define CLOSED -1 /* fd was not open before redir */
+
+
+struct redirtab {
+ struct redirtab *next;
+ int renamed[10];
+ int fd0_redirected;
+ unsigned int empty_redirs;
+};
+
+
+static struct redirtab *redirlist;
+
+/*
+ * We keep track of whether or not fd0 has been redirected. This is for
+ * background commands, where we want to redirect fd0 to /dev/null only
+ * if it hasn't already been redirected.
+*/
+static int fd0_redirected = 0;
+
+/* Number of redirtabs that have not been allocated. */
+static unsigned int empty_redirs = 0;
+
+static void openredirect(union node *, char[10 ]);
+static int openhere(union node *);
+
+
+/*
+ * Process a list of redirection commands. If the REDIR_PUSH flag is set,
+ * old file descriptors are stashed away so that the redirection can be
+ * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
+ * standard output, and the standard error if it becomes a duplicate of
+ * stdout, is saved in memory.
+*
+ * We suppress interrupts so that we won't leave open file
+ * descriptors around. Because the signal handler remains
+ * installed and we do not use system call restart, interrupts
+ * will still abort blocking opens such as fifos (they will fail
+ * with EINTR). There is, however, a race condition if an interrupt
+ * arrives after INTOFF and before open blocks.
+ */
+
+void
+redirect(union node *redir, int flags)
+{
+ union node *n;
+ struct redirtab *sv = NULL;
+ int i;
+ int fd;
+ char memory[10]; /* file descriptors to write to memory */
+
+ INTOFF;
+ for (i = 10 ; --i >= 0 ; )
+ memory[i] = 0;
+ memory[1] = flags & REDIR_BACKQ;
+ if (flags & REDIR_PUSH) {
+ empty_redirs++;
+ if (redir != NULL) {
+ sv = ckmalloc(sizeof (struct redirtab));
+ for (i = 0 ; i < 10 ; i++)
+ sv->renamed[i] = EMPTY;
+ sv->fd0_redirected = fd0_redirected;
+ sv->empty_redirs = empty_redirs - 1;
+ sv->next = redirlist;
+ redirlist = sv;
+ empty_redirs = 0;
+ }
+ }
+ for (n = redir ; n ; n = n->nfile.next) {
+ fd = n->nfile.fd;
+ if (fd == 0)
+ fd0_redirected = 1;
+ if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
+ n->ndup.dupfd == fd)
+ continue; /* redirect from/to same file descriptor */
+
+ if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
+ INTOFF;
+ if ((i = fcntl(fd, F_DUPFD_CLOEXEC, 10)) == -1) {
+ switch (errno) {
+ case EBADF:
+ i = CLOSED;
+ break;
+ default:
+ INTON;
+ error("%d: %s", fd, strerror(errno));
+ break;
+ }
+ }
+ sv->renamed[fd] = i;
+ INTON;
+ }
+ openredirect(n, memory);
+ INTON;
+ INTOFF;
+ }
+ if (memory[1])
+ out1 = &memout;
+ if (memory[2])
+ out2 = &memout;
+ INTON;
+}
+
+
+static void
+openredirect(union node *redir, char memory[10])
+{
+ struct stat sb;
+ int fd = redir->nfile.fd;
+ const char *fname;
+ int f;
+ int e;
+
+ memory[fd] = 0;
+ switch (redir->nfile.type) {
+ case NFROM:
+ fname = redir->nfile.expfname;
+ if ((f = open(fname, O_RDONLY)) < 0)
+ error("cannot open %s: %s", fname, strerror(errno));
+ break;
+ case NFROMTO:
+ fname = redir->nfile.expfname;
+ if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ break;
+ case NTO:
+ if (Cflag) {
+ fname = redir->nfile.expfname;
+ if (stat(fname, &sb) == -1) {
+ if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ } else if (!S_ISREG(sb.st_mode)) {
+ if ((f = open(fname, O_WRONLY, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ if (fstat(f, &sb) != -1 && S_ISREG(sb.st_mode)) {
+ close(f);
+ error("cannot create %s: %s", fname,
+ strerror(EEXIST));
+ }
+ } else
+ error("cannot create %s: %s", fname,
+ strerror(EEXIST));
+ break;
+ }
+ /* FALLTHROUGH */
+ case NCLOBBER:
+ fname = redir->nfile.expfname;
+ if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ break;
+ case NAPPEND:
+ fname = redir->nfile.expfname;
+ if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
+ error("cannot create %s: %s", fname, strerror(errno));
+ break;
+ case NTOFD:
+ case NFROMFD:
+ if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
+ if (memory[redir->ndup.dupfd])
+ memory[fd] = 1;
+ else {
+ if (dup2(redir->ndup.dupfd, fd) < 0)
+ error("%d: %s", redir->ndup.dupfd,
+ strerror(errno));
+ }
+ } else {
+ close(fd);
+ }
+ return;
+ case NHERE:
+ case NXHERE:
+ f = openhere(redir);
+ break;
+ default:
+ abort();
+ }
+ if (f != fd) {
+ if (dup2(f, fd) == -1) {
+ e = errno;
+ close(f);
+ error("%d: %s", fd, strerror(e));
+ }
+ close(f);
+ }
+}
+
+
+/*
+ * Handle here documents. Normally we fork off a process to write the
+ * data to a pipe. If the document is short, we can stuff the data in
+ * the pipe without forking.
+ */
+
+static int
+openhere(union node *redir)
+{
+ const char *p;
+ int pip[2];
+ size_t len = 0;
+ int flags;
+ ssize_t written = 0;
+
+ if (pipe(pip) < 0)
+ error("Pipe call failed: %s", strerror(errno));
+
+ if (redir->type == NXHERE)
+ p = redir->nhere.expdoc;
+ else
+ p = redir->nhere.doc->narg.text;
+ len = strlen(p);
+ if (len == 0)
+ goto out;
+ flags = fcntl(pip[1], F_GETFL, 0);
+ if (flags != -1 && fcntl(pip[1], F_SETFL, flags | O_NONBLOCK) != -1) {
+ written = write(pip[1], p, len);
+ if (written < 0)
+ written = 0;
+ if ((size_t)written == len)
+ goto out;
+ fcntl(pip[1], F_SETFL, flags);
+ }
+
+ if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
+ close(pip[0]);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGPIPE, SIG_DFL);
+ xwrite(pip[1], p + written, len - written);
+ _exit(0);
+ }
+out:
+ close(pip[1]);
+ return pip[0];
+}
+
+
+
+/*
+ * Undo the effects of the last redirection.
+ */
+
+void
+popredir(void)
+{
+ struct redirtab *rp = redirlist;
+ int i;
+
+ INTOFF;
+ if (empty_redirs > 0) {
+ empty_redirs--;
+ INTON;
+ return;
+ }
+ for (i = 0 ; i < 10 ; i++) {
+ if (rp->renamed[i] != EMPTY) {
+ if (rp->renamed[i] >= 0) {
+ dup2(rp->renamed[i], i);
+ close(rp->renamed[i]);
+ } else {
+ close(i);
+ }
+ }
+ }
+ fd0_redirected = rp->fd0_redirected;
+ empty_redirs = rp->empty_redirs;
+ redirlist = rp->next;
+ ckfree(rp);
+ INTON;
+}
+
+/* Return true if fd 0 has already been redirected at least once. */
+int
+fd0_redirected_p(void)
+{
+ return fd0_redirected != 0;
+}
+
+/*
+ * Discard all saved file descriptors.
+ */
+
+void
+clearredir(void)
+{
+ struct redirtab *rp;
+ int i;
+
+ for (rp = redirlist ; rp ; rp = rp->next) {
+ for (i = 0 ; i < 10 ; i++) {
+ if (rp->renamed[i] >= 0) {
+ close(rp->renamed[i]);
+ }
+ rp->renamed[i] = EMPTY;
+ }
+ }
+}
diff --git a/shell_cmds/sh/redir.h b/shell_cmds/sh/redir.h
new file mode 100644
index 0000000..74d17b1
--- /dev/null
+++ b/shell_cmds/sh/redir.h
@@ -0,0 +1,47 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)redir.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/redir.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+/* flags passed to redirect */
+#define REDIR_PUSH 01 /* save previous values of file descriptors */
+#define REDIR_BACKQ 02 /* save the command output in memory */
+
+union node;
+void redirect(union node *, int);
+void popredir(void);
+int fd0_redirected_p(void);
+void clearredir(void);
+
diff --git a/shell_cmds/sh/sh.1 b/shell_cmds/sh/sh.1
new file mode 100644
index 0000000..5c2e87d
--- /dev/null
+++ b/shell_cmds/sh/sh.1
@@ -0,0 +1,2879 @@
+.\"-
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Kenneth Almquist.
+.\"
+.\" 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 University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
+.\" $FreeBSD: head/bin/sh/sh.1 327121 2017-12-23 22:58:19Z jilles $
+.\"
+.Dd October 8, 2016
+.Dt SH 1
+.Os
+.Sh NAME
+.Nm sh
+.Nd command interpreter (shell)
+.Sh SYNOPSIS
+.Nm
+.Op Fl /+abCEefhIimnPpTuVvx
+.Op Fl /+o Ar longname
+.Oo
+.Ar script
+.Op Ar arg ...
+.Oc
+.Nm
+.Op Fl /+abCEefhIimnPpTuVvx
+.Op Fl /+o Ar longname
+.Fl c Ar string
+.Oo
+.Ar name
+.Op Ar arg ...
+.Oc
+.Nm
+.Op Fl /+abCEefhIimnPpTuVvx
+.Op Fl /+o Ar longname
+.Fl s
+.Op Ar arg ...
+.Sh DESCRIPTION
+The
+.Nm
+utility is the standard command interpreter for the system.
+The current version of
+.Nm
+is close to the
+.St -p1003.1
+specification for the shell.
+It only supports features
+designated by
+.Tn POSIX ,
+plus a few Berkeley extensions.
+This man page is not intended to be a tutorial nor a complete
+specification of the shell.
+.Ss Overview
+The shell is a command that reads lines from
+either a file or the terminal, interprets them, and
+generally executes other commands.
+It is the program that is started when a user logs into the system,
+although a user can select a different shell with the
+.Xr chsh 1
+command.
+The shell
+implements a language that has flow control constructs,
+a macro facility that provides a variety of features in
+addition to data storage, along with built-in history and line
+editing capabilities.
+It incorporates many features to
+aid interactive use and has the advantage that the interpretative
+language is common to both interactive and non-interactive
+use (shell scripts).
+That is, commands can be typed directly
+to the running shell or can be put into a file,
+which can be executed directly by the shell.
+.Ss Invocation
+.\"
+.\" XXX This next sentence is incredibly confusing.
+.\"
+If no arguments are present and if the standard input of the shell
+is connected to a terminal
+(or if the
+.Fl i
+option is set),
+the shell is considered an interactive shell.
+An interactive shell
+generally prompts before each command and handles programming
+and command errors differently (as described below).
+When first starting, the shell inspects argument 0, and
+if it begins with a dash
+.Pq Ql - ,
+the shell is also considered a login shell.
+This is normally done automatically by the system
+when the user first logs in.
+A login shell first reads commands
+from the files
+.Pa /etc/profile
+and then
+.Pa .profile
+in a user's home directory,
+if they exist.
+If the environment variable
+.Ev ENV
+is set on entry to a shell, or is set in the
+.Pa .profile
+of a login shell, the shell then subjects its value to parameter expansion
+and arithmetic expansion and reads commands from the named file.
+Therefore, a user should place commands that are to be executed only
+at login time in the
+.Pa .profile
+file, and commands that are executed for every shell inside the
+.Ev ENV
+file.
+The user can set the
+.Ev ENV
+variable to some file by placing the following line in the file
+.Pa .profile
+in the home directory,
+substituting for
+.Pa .shrc
+the filename desired:
+.Pp
+.Dl "ENV=$HOME/.shrc; export ENV"
+.Pp
+The first non-option argument specified on the command line
+will be treated as the
+name of a file from which to read commands (a shell script), and
+the remaining arguments are set as the positional parameters
+of the shell
+.Li ( $1 , $2 ,
+etc.).
+Otherwise, the shell reads commands
+from its standard input.
+.Pp
+Unlike older versions of
+.Nm
+the
+.Ev ENV
+script is only sourced on invocation of interactive shells.
+This
+closes a well-known, and sometimes easily exploitable security
+hole related to poorly thought out
+.Ev ENV
+scripts.
+.Ss Argument List Processing
+All of the single letter options to
+.Nm
+have a corresponding long name,
+with the exception of
+.Fl c
+and
+.Fl /+o .
+These long names are provided next to the single letter options
+in the descriptions below.
+The long name for an option may be specified as an argument to the
+.Fl /+o
+option of
+.Nm .
+Once the shell is running,
+the long name for an option may be specified as an argument to the
+.Fl /+o
+option of the
+.Ic set
+built-in command
+(described later in the section called
+.Sx Built-in Commands ) .
+Introducing an option with a dash
+.Pq Ql -
+enables the option,
+while using a plus
+.Pq Ql +
+disables the option.
+A
+.Dq Li --
+or plain
+.Ql -
+will stop option processing and will force the remaining
+words on the command line to be treated as arguments.
+The
+.Fl /+o
+and
+.Fl c
+options do not have long names.
+They take arguments and are described after the single letter options.
+.Bl -tag -width indent
+.It Fl a Li allexport
+Flag variables for export when assignments are made to them.
+.It Fl b Li notify
+Enable asynchronous notification of background job
+completion.
+(UNIMPLEMENTED)
+.It Fl C Li noclobber
+Do not overwrite existing files with
+.Ql > .
+.It Fl E Li emacs
+Enable the built-in
+.Xr emacs 1
+command line editor (disables the
+.Fl V
+option if it has been set;
+set automatically when interactive on terminals).
+.It Fl e Li errexit
+Exit immediately if any untested command fails in non-interactive mode.
+The exit status of a command is considered to be
+explicitly tested if the command is part of the list used to control
+an
+.Ic if , elif , while ,
+or
+.Ic until ;
+if the command is the left
+hand operand of an
+.Dq Li &&
+or
+.Dq Li ||
+operator; or if the command is a pipeline preceded by the
+.Ic !\&
+keyword.
+If a shell function is executed and its exit status is explicitly
+tested, all commands of the function are considered to be tested as
+well.
+.Pp
+It is recommended to check for failures explicitly
+instead of relying on
+.Fl e
+because it tends to behave in unexpected ways,
+particularly in larger scripts.
+.It Fl f Li noglob
+Disable pathname expansion.
+.It Fl h Li trackall
+A do-nothing option for
+.Tn POSIX
+compliance.
+.It Fl I Li ignoreeof
+Ignore
+.Dv EOF Ap s
+from input when in interactive mode.
+.It Fl i Li interactive
+Force the shell to behave interactively.
+.It Fl m Li monitor
+Turn on job control (set automatically when interactive).
+A new process group is created for each pipeline (called a job).
+It is possible to suspend jobs or to have them run in the foreground or
+in the background.
+In a non-interactive shell,
+this option can be set even if no terminal is available
+and is useful to place processes in separate process groups.
+.It Fl n Li noexec
+If not interactive, read commands but do not
+execute them.
+This is useful for checking the
+syntax of shell scripts.
+.It Fl P Li physical
+Change the default for the
+.Ic cd
+and
+.Ic pwd
+commands from
+.Fl L
+(logical directory layout)
+to
+.Fl P
+(physical directory layout).
+.It Fl p Li privileged
+Turn on privileged mode.
+This mode is enabled on startup
+if either the effective user or group ID is not equal to the
+real user or group ID.
+Turning this mode off sets the
+effective user and group IDs to the real user and group IDs.
+When this mode is enabled for interactive shells, the file
+.Pa /etc/suid_profile
+is sourced instead of
+.Pa ~/.profile
+after
+.Pa /etc/profile
+is sourced, and the contents of the
+.Ev ENV
+variable are ignored.
+.It Fl s Li stdin
+Read commands from standard input (set automatically
+if no file arguments are present).
+This option has
+no effect when set after the shell has already started
+running (i.e., when set with the
+.Ic set
+command).
+.It Fl T Li trapsasync
+When waiting for a child, execute traps immediately.
+If this option is not set,
+traps are executed after the child exits,
+as specified in
+.St -p1003.2 .
+This nonstandard option is useful for putting guarding shells around
+children that block signals.
+The surrounding shell may kill the child
+or it may just return control to the tty and leave the child alone,
+like this:
+.Bd -literal -offset indent
+sh -T -c "trap 'exit 1' 2 ; some-blocking-program"
+.Ed
+.It Fl u Li nounset
+Write a message to standard error when attempting
+to expand a variable, a positional parameter or
+the special parameter
+.Va \&!
+that is not set, and if the
+shell is not interactive, exit immediately.
+.It Fl V Li vi
+Enable the built-in
+.Xr vi 1
+command line editor (disables
+.Fl E
+if it has been set).
+.It Fl v Li verbose
+The shell writes its input to standard error
+as it is read.
+Useful for debugging.
+.It Fl x Li xtrace
+Write each command
+(preceded by the value of the
+.Va PS4
+variable subjected to parameter expansion and arithmetic expansion)
+to standard error before it is executed.
+Useful for debugging.
+.It Li nolog
+Another do-nothing option for
+.Tn POSIX
+compliance.
+It only has a long name.
+.El
+.Pp
+The
+.Fl c
+option causes the commands to be read from the
+.Ar string
+operand instead of from the standard input.
+Keep in mind that this option only accepts a single string as its
+argument, hence multi-word strings must be quoted.
+.Pp
+The
+.Fl /+o
+option takes as its only argument the long name of an option
+to be enabled or disabled.
+For example, the following two invocations of
+.Nm
+both enable the built-in
+.Xr emacs 1
+command line editor:
+.Bd -literal -offset indent
+set -E
+set -o emacs
+.Ed
+.Pp
+If used without an argument, the
+.Fl o
+option displays the current option settings in a human-readable format.
+If
+.Cm +o
+is used without an argument, the current option settings are output
+in a format suitable for re-input into the shell.
+.Ss Lexical Structure
+The shell reads input in terms of lines from a file and breaks
+it up into words at whitespace (blanks and tabs), and at
+certain sequences of
+characters called
+.Dq operators ,
+which are special to the shell.
+There are two types of operators: control operators and
+redirection operators (their meaning is discussed later).
+The following is a list of valid operators:
+.Bl -tag -width indent
+.It Control operators:
+.Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
+.It Li & Ta Li && Ta Li \&( Ta Li \&) Ta Li \en
+.It Li ;; Ta Li ;& Ta Li \&; Ta Li \&| Ta Li ||
+.El
+.It Redirection operators:
+.Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
+.It Li < Ta Li > Ta Li << Ta Li >> Ta Li <>
+.It Li <& Ta Li >& Ta Li <<- Ta Li >| Ta \&
+.El
+.El
+.Pp
+The character
+.Ql #
+introduces a comment if used at the beginning of a word.
+The word starting with
+.Ql #
+and the rest of the line are ignored.
+.Pp
+.Tn ASCII
+.Dv NUL
+characters (character code 0) are not allowed in shell input.
+.Ss Quoting
+Quoting is used to remove the special meaning of certain characters
+or words to the shell, such as operators, whitespace, keywords,
+or alias names.
+.Pp
+There are four types of quoting: matched single quotes,
+dollar-single quotes,
+matched double quotes, and backslash.
+.Bl -tag -width indent
+.It Single Quotes
+Enclosing characters in single quotes preserves the literal
+meaning of all the characters (except single quotes, making
+it impossible to put single-quotes in a single-quoted string).
+.It Dollar-Single Quotes
+Enclosing characters between
+.Li $'
+and
+.Li '
+preserves the literal meaning of all characters
+except backslashes and single quotes.
+A backslash introduces a C-style escape sequence:
+.Bl -tag -width xUnnnnnnnn
+.It \ea
+Alert (ring the terminal bell)
+.It \eb
+Backspace
+.It \ec Ns Ar c
+The control character denoted by
+.Li ^ Ns Ar c
+in
+.Xr stty 1 .
+If
+.Ar c
+is a backslash, it must be doubled.
+.It \ee
+The ESC character
+.Tn ( ASCII
+0x1b)
+.It \ef
+Formfeed
+.It \en
+Newline
+.It \er
+Carriage return
+.It \et
+Horizontal tab
+.It \ev
+Vertical tab
+.It \e\e
+Literal backslash
+.It \e\&'
+Literal single-quote
+.It \e\&"
+Literal double-quote
+.It \e Ns Ar nnn
+The byte whose octal value is
+.Ar nnn
+(one to three digits)
+.It \ex Ns Ar nn
+The byte whose hexadecimal value is
+.Ar nn
+(one or more digits only the last two of which are used)
+.It \eu Ns Ar nnnn
+The Unicode code point
+.Ar nnnn
+(four hexadecimal digits)
+.It \eU Ns Ar nnnnnnnn
+The Unicode code point
+.Ar nnnnnnnn
+(eight hexadecimal digits)
+.El
+.Pp
+The sequences for Unicode code points are currently only useful with
+UTF-8 locales.
+They reject code point 0 and UTF-16 surrogates.
+.Pp
+If an escape sequence would produce a byte with value 0,
+that byte and the rest of the string until the matching single-quote
+are ignored.
+.Pp
+Any other string starting with a backslash is an error.
+.It Double Quotes
+Enclosing characters within double quotes preserves the literal
+meaning of all characters except dollar sign
+.Pq Ql $ ,
+backquote
+.Pq Ql ` ,
+and backslash
+.Pq Ql \e .
+The backslash inside double quotes is historically weird.
+It remains literal unless it precedes the following characters,
+which it serves to quote:
+.Pp
+.Bl -column "XXX" "XXX" "XXX" "XXX" "XXX" -offset center -compact
+.It Li $ Ta Li ` Ta Li \&" Ta Li \e Ta Li \en
+.El
+.It Backslash
+A backslash preserves the literal meaning of the following
+character, with the exception of the newline character
+.Pq Ql \en .
+A backslash preceding a newline is treated as a line continuation.
+.El
+.Ss Keywords
+Keywords or reserved words are words that have special meaning to the
+shell and are recognized at the beginning of a line and
+after a control operator.
+The following are keywords:
+.Bl -column "doneXX" "elifXX" "elseXX" "untilXX" "whileX" -offset center
+.It Li \&! Ta { Ta } Ta Ic case Ta Ic do
+.It Ic done Ta Ic elif Ta Ic else Ta Ic esac Ta Ic fi
+.It Ic for Ta Ic if Ta Ic then Ta Ic until Ta Ic while
+.El
+.Ss Aliases
+An alias is a name and corresponding value set using the
+.Ic alias
+built-in command.
+Wherever the command word of a simple command may occur,
+and after checking for keywords if a keyword may occur, the shell
+checks the word to see if it matches an alias.
+If it does, it replaces it in the input stream with its value.
+For example, if there is an alias called
+.Dq Li lf
+with the value
+.Dq Li "ls -F" ,
+then the input
+.Pp
+.Dl "lf foobar"
+.Pp
+would become
+.Pp
+.Dl "ls -F foobar"
+.Pp
+Aliases are also recognized after an alias
+whose value ends with a space or tab.
+For example, if there is also an alias called
+.Dq Li nohup
+with the value
+.Dq Li "nohup " ,
+then the input
+.Pp
+.Dl "nohup lf foobar"
+.Pp
+would become
+.Pp
+.Dl "nohup ls -F foobar"
+.Pp
+Aliases provide a convenient way for naive users to
+create shorthands for commands without having to learn how
+to create functions with arguments.
+Using aliases in scripts is discouraged
+because the command that defines them must be executed
+before the code that uses them is parsed.
+This is fragile and not portable.
+.Pp
+An alias name may be escaped in a command line, so that it is not
+replaced by its alias value, by using quoting characters within or
+adjacent to the alias name.
+This is most often done by prefixing
+an alias name with a backslash to execute a function, built-in, or
+normal program with the same name.
+See the
+.Sx Quoting
+subsection.
+.Ss Commands
+The shell interprets the words it reads according to a
+language, the specification of which is outside the scope
+of this man page (refer to the BNF in the
+.St -p1003.2
+document).
+Essentially though, a line is read and if
+the first word of the line (or after a control operator)
+is not a keyword, then the shell has recognized a
+simple command.
+Otherwise, a complex command or some
+other special construct may have been recognized.
+.Ss Simple Commands
+If a simple command has been recognized, the shell performs
+the following actions:
+.Bl -enum
+.It
+Leading words of the form
+.Dq Li name=value
+are stripped off and assigned to the environment of
+the simple command
+(they do not affect expansions).
+Redirection operators and
+their arguments (as described below) are stripped
+off and saved for processing.
+.It
+The remaining words are expanded as described in
+the section called
+.Sx Word Expansions ,
+and the first remaining word is considered the command
+name and the command is located.
+The remaining
+words are considered the arguments of the command.
+If no command name resulted, then the
+.Dq Li name=value
+variable assignments recognized in 1) affect the
+current shell.
+.It
+Redirections are performed as described in
+the next section.
+.El
+.Ss Redirections
+Redirections are used to change where a command reads its input
+or sends its output.
+In general, redirections open, close, or
+duplicate an existing reference to a file.
+The overall format
+used for redirection is:
+.Pp
+.D1 Oo Ar n Oc Ar redir-op file
+.Pp
+The
+.Ar redir-op
+is one of the redirection operators mentioned
+previously.
+The following gives some examples of how these
+operators can be used.
+Note that stdin and stdout are commonly used abbreviations
+for standard input and standard output respectively.
+.Bl -tag -width "1234567890XX" -offset indent
+.It Oo Ar n Oc Ns Li > Ar file
+redirect stdout (or file descriptor
+.Ar n )
+to
+.Ar file
+.It Oo Ar n Oc Ns Li >| Ar file
+same as above, but override the
+.Fl C
+option
+.It Oo Ar n Oc Ns Li >> Ar file
+append stdout (or file descriptor
+.Ar n )
+to
+.Ar file
+.It Oo Ar n Oc Ns Li < Ar file
+redirect stdin (or file descriptor
+.Ar n )
+from
+.Ar file
+.It Oo Ar n Oc Ns Li <> Ar file
+redirect stdin (or file descriptor
+.Ar n )
+to and from
+.Ar file
+.It Oo Ar n1 Oc Ns Li <& Ns Ar n2
+duplicate stdin (or file descriptor
+.Ar n1 )
+from file descriptor
+.Ar n2
+.It Oo Ar n Oc Ns Li <&-
+close stdin (or file descriptor
+.Ar n )
+.It Oo Ar n1 Oc Ns Li >& Ns Ar n2
+duplicate stdout (or file descriptor
+.Ar n1 )
+to file descriptor
+.Ar n2
+.It Oo Ar n Oc Ns Li >&-
+close stdout (or file descriptor
+.Ar n )
+.El
+.Pp
+The following redirection is often called a
+.Dq here-document .
+.Bd -unfilled -offset indent
+.Oo Ar n Oc Ns Li << Ar delimiter
+.Ar here-doc-text
+.Ar ...
+.Ar delimiter
+.Ed
+.Pp
+All the text on successive lines up to the delimiter is
+saved away and made available to the command on standard
+input, or file descriptor
+.Ar n
+if it is specified.
+If the
+.Ar delimiter
+as specified on the initial line is quoted, then the
+.Ar here-doc-text
+is treated literally, otherwise the text is subjected to
+parameter expansion, command substitution, and arithmetic
+expansion (as described in the section on
+.Sx Word Expansions ) .
+If the operator is
+.Dq Li <<-
+instead of
+.Dq Li << ,
+then leading tabs
+in the
+.Ar here-doc-text
+are stripped.
+.Ss Search and Execution
+There are three types of commands: shell functions,
+built-in commands, and normal programs.
+The command is searched for (by name) in that order.
+The three types of commands are all executed in a different way.
+.Pp
+When a shell function is executed, all of the shell positional
+parameters (except
+.Li $0 ,
+which remains unchanged) are
+set to the arguments of the shell function.
+The variables which are explicitly placed in the environment of
+the command (by placing assignments to them before the
+function name) are made local to the function and are set
+to the values given.
+Then the command given in the function definition is executed.
+The positional parameters are restored to their original values
+when the command completes.
+This all occurs within the current shell.
+.Pp
+Shell built-in commands are executed internally to the shell, without
+spawning a new process.
+There are two kinds of built-in commands: regular and special.
+Assignments before special builtins persist after they finish
+executing and assignment errors, redirection errors and certain
+operand errors cause a script to be aborted.
+Special builtins cannot be overridden with a function.
+Both regular and special builtins can affect the shell in ways
+normal programs cannot.
+.Pp
+Otherwise, if the command name does not match a function
+or built-in command, the command is searched for as a normal
+program in the file system (as described in the next section).
+When a normal program is executed, the shell runs the program,
+passing the arguments and the environment to the program.
+If the program is not a normal executable file
+(i.e., if it does not begin with the
+.Dq "magic number"
+whose
+.Tn ASCII
+representation is
+.Dq Li #! ,
+resulting in an
+.Er ENOEXEC
+return value from
+.Xr execve 2 )
+but appears to be a text file,
+the shell will run a new instance of
+.Nm
+to interpret it.
+.Pp
+Note that previous versions of this document
+and the source code itself misleadingly and sporadically
+refer to a shell script without a magic number
+as a
+.Dq "shell procedure" .
+.Ss Path Search
+When locating a command, the shell first looks to see if
+it has a shell function by that name.
+Then it looks for a
+built-in command by that name.
+If a built-in command is not found,
+one of two things happen:
+.Bl -enum
+.It
+Command names containing a slash are simply executed without
+performing any searches.
+.It
+The shell searches each entry in the
+.Va PATH
+variable
+in turn for the command.
+The value of the
+.Va PATH
+variable should be a series of
+entries separated by colons.
+Each entry consists of a
+directory name.
+The current directory
+may be indicated implicitly by an empty directory name,
+or explicitly by a single period.
+.El
+.Ss Command Exit Status
+Each command has an exit status that can influence the behavior
+of other shell commands.
+The paradigm is that a command exits
+with zero for normal or success, and non-zero for failure,
+error, or a false indication.
+The man page for each command
+should indicate the various exit codes and what they mean.
+Additionally, the built-in commands return exit codes, as does
+an executed shell function.
+.Pp
+If a command is terminated by a signal, its exit status is greater than 128.
+The signal name can be found by passing the exit status to
+.Li kill -l .
+.Pp
+If there is no command word,
+the exit status is the exit status of the last command substitution executed,
+or zero if the command does not contain any command substitutions.
+.Ss Complex Commands
+Complex commands are combinations of simple commands
+with control operators or keywords, together creating a larger complex
+command.
+More generally, a command is one of the following:
+.Bl -item -offset indent
+.It
+simple command
+.It
+pipeline
+.It
+list or compound-list
+.It
+compound command
+.It
+function definition
+.El
+.Pp
+Unless otherwise stated, the exit status of a command is
+that of the last simple command executed by the command,
+or zero if no simple command was executed.
+.Ss Pipelines
+A pipeline is a sequence of one or more commands separated
+by the control operator
+.Ql \&| .
+The standard output of all but
+the last command is connected to the standard input
+of the next command.
+The standard output of the last
+command is inherited from the shell, as usual.
+.Pp
+The format for a pipeline is:
+.Pp
+.D1 Oo Li \&! Oc Ar command1 Op Li \&| Ar command2 ...
+.Pp
+The standard output of
+.Ar command1
+is connected to the standard input of
+.Ar command2 .
+The standard input, standard output, or
+both of a command is considered to be assigned by the
+pipeline before any redirection specified by redirection
+operators that are part of the command.
+.Pp
+Note that unlike some other shells,
+.Nm
+executes each process in a pipeline with more than one command
+in a subshell environment and as a child of the
+.Nm
+process.
+.Pp
+If the pipeline is not in the background (discussed later),
+the shell waits for all commands to complete.
+.Pp
+If the keyword
+.Ic !\&
+does not precede the pipeline, the
+exit status is the exit status of the last command specified
+in the pipeline.
+Otherwise, the exit status is the logical
+NOT of the exit status of the last command.
+That is, if
+the last command returns zero, the exit status is 1; if
+the last command returns greater than zero, the exit status
+is zero.
+.Pp
+Because pipeline assignment of standard input or standard
+output or both takes place before redirection, it can be
+modified by redirection.
+For example:
+.Pp
+.Dl "command1 2>&1 | command2"
+.Pp
+sends both the standard output and standard error of
+.Ar command1
+to the standard input of
+.Ar command2 .
+.Pp
+A
+.Ql \&;
+or newline terminator causes the preceding
+AND-OR-list
+(described below in the section called
+.Sx Short-Circuit List Operators )
+to be executed sequentially;
+an
+.Ql &
+causes asynchronous execution of the preceding AND-OR-list.
+.Ss Background Commands (&)
+If a command is terminated by the control operator ampersand
+.Pq Ql & ,
+the shell executes the command in a subshell environment (see
+.Sx Grouping Commands Together
+below) and asynchronously;
+the shell does not wait for the command to finish
+before executing the next command.
+.Pp
+The format for running a command in background is:
+.Pp
+.D1 Ar command1 Li & Op Ar command2 Li & Ar ...
+.Pp
+If the shell is not interactive, the standard input of an
+asynchronous command is set to
+.Pa /dev/null .
+.Pp
+The exit status is zero.
+.Ss Lists (Generally Speaking)
+A list is a sequence of zero or more commands separated by
+newlines, semicolons, or ampersands,
+and optionally terminated by one of these three characters.
+The commands in a
+list are executed in the order they are written.
+If command is followed by an ampersand, the shell starts the
+command and immediately proceeds onto the next command;
+otherwise it waits for the command to terminate before
+proceeding to the next one.
+.Ss Short-Circuit List Operators
+.Dq Li &&
+and
+.Dq Li ||
+are AND-OR list operators.
+.Dq Li &&
+executes the first command, and then executes the second command
+if the exit status of the first command is zero.
+.Dq Li ||
+is similar, but executes the second command if the exit
+status of the first command is nonzero.
+.Dq Li &&
+and
+.Dq Li ||
+both have the same priority.
+.Ss Flow-Control Constructs (if, while, for, case)
+The syntax of the
+.Ic if
+command is:
+.Bd -unfilled -offset indent -compact
+.Ic if Ar list
+.Ic then Ar list
+.Oo Ic elif Ar list
+.Ic then Ar list Oc Ar ...
+.Op Ic else Ar list
+.Ic fi
+.Ed
+.Pp
+The exit status is that of selected
+.Ic then
+or
+.Ic else
+list,
+or zero if no list was selected.
+.Pp
+The syntax of the
+.Ic while
+command is:
+.Bd -unfilled -offset indent -compact
+.Ic while Ar list
+.Ic do Ar list
+.Ic done
+.Ed
+.Pp
+The two lists are executed repeatedly while the exit status of the
+first list is zero.
+The
+.Ic until
+command is similar, but has the word
+.Ic until
+in place of
+.Ic while ,
+which causes it to
+repeat until the exit status of the first list is zero.
+.Pp
+The exit status is that of the last execution of the second list,
+or zero if it was never executed.
+.Pp
+The syntax of the
+.Ic for
+command is:
+.Bd -unfilled -offset indent -compact
+.Ic for Ar variable Op Ic in Ar word ...
+.Ic do Ar list
+.Ic done
+.Ed
+.Pp
+If
+.Ic in
+and the following words are omitted,
+.Ic in Li \&"$@\&"
+is used instead.
+The words are expanded, and then the list is executed
+repeatedly with the variable set to each word in turn.
+The
+.Ic do
+and
+.Ic done
+commands may be replaced with
+.Ql {
+and
+.Ql } .
+.Pp
+The syntax of the
+.Ic break
+and
+.Ic continue
+commands is:
+.D1 Ic break Op Ar num
+.D1 Ic continue Op Ar num
+.Pp
+The
+.Ic break
+command terminates the
+.Ar num
+innermost
+.Ic for
+or
+.Ic while
+loops.
+The
+.Ic continue
+command continues with the next iteration of the innermost loop.
+These are implemented as special built-in commands.
+.Pp
+The syntax of the
+.Ic case
+command is:
+.Bd -unfilled -offset indent -compact
+.Ic case Ar word Ic in
+.Ar pattern ) Ar list Li ;;
+.Ar ...
+.Ic esac
+.Ed
+.Pp
+The pattern can actually be one or more patterns
+(see
+.Sx Shell Patterns
+described later),
+separated by
+.Ql \&|
+characters.
+Tilde expansion, parameter expansion, command substitution,
+arithmetic expansion and quote removal are applied to the word.
+Then, each pattern is expanded in turn using tilde expansion,
+parameter expansion, command substitution and arithmetic expansion and
+the expanded form of the word is checked against it.
+If a match is found, the corresponding list is executed.
+If the selected list is terminated by the control operator
+.Ql ;&
+instead of
+.Ql ;; ,
+execution continues with the next list,
+continuing until a list terminated with
+.Ql ;;
+or the end of the
+.Ic case
+command.
+.Ss Grouping Commands Together
+Commands may be grouped by writing either
+.Pp
+.D1 Li \&( Ns Ar list Ns Li \%)
+.Pp
+or
+.Pp
+.D1 Li { Ar list Ns Li \&; }
+.Pp
+The first form executes the commands in a subshell environment.
+A subshell environment has its own copy of:
+.Bl -enum
+.It
+The current working directory as set by
+.Ic cd .
+.It
+The file creation mask as set by
+.Ic umask .
+.It
+Resource limits as set by
+.Ic ulimit .
+.It
+References to open files.
+.It
+Traps as set by
+.Ic trap .
+.It
+Known jobs.
+.It
+Positional parameters and variables.
+.It
+Shell options.
+.It
+Shell functions.
+.It
+Shell aliases.
+.El
+.Pp
+These are copied from the parent shell environment,
+except that trapped (but not ignored) signals are reset to the default action
+and known jobs are cleared.
+Any changes do not affect the parent shell environment.
+.Pp
+A subshell environment may be implemented as a child process or differently.
+If job control is enabled in an interactive shell,
+commands grouped in parentheses can be suspended and continued as a unit.
+.Pp
+For compatibility with other shells,
+two open parentheses in sequence should be separated by whitespace.
+.Pp
+The second form never forks another shell,
+so it is slightly more efficient.
+Grouping commands together this way allows the user to
+redirect their output as though they were one program:
+.Bd -literal -offset indent
+{ echo -n "hello"; echo " world"; } > greeting
+.Ed
+.Ss Functions
+The syntax of a function definition is
+.Pp
+.D1 Ar name Li \&( \&) Ar command
+.Pp
+A function definition is an executable statement; when
+executed it installs a function named
+.Ar name
+and returns an
+exit status of zero.
+The
+.Ar command
+is normally a list
+enclosed between
+.Ql {
+and
+.Ql } .
+.Pp
+Variables may be declared to be local to a function by
+using the
+.Ic local
+command.
+This should appear as the first statement of a function,
+and the syntax is:
+.Pp
+.D1 Ic local Oo Ar variable ... Oc Op Fl
+.Pp
+The
+.Ic local
+command is implemented as a built-in command.
+The exit status is zero
+unless the command is not in a function or a variable name is invalid.
+.Pp
+When a variable is made local, it inherits the initial
+value and exported and readonly flags from the variable
+with the same name in the surrounding scope, if there is
+one.
+Otherwise, the variable is initially unset.
+The shell
+uses dynamic scoping, so that if the variable
+.Va x
+is made local to function
+.Em f ,
+which then calls function
+.Em g ,
+references to the variable
+.Va x
+made inside
+.Em g
+will refer to the variable
+.Va x
+declared inside
+.Em f ,
+not to the global variable named
+.Va x .
+.Pp
+The only special parameter that can be made local is
+.Ql - .
+Making
+.Ql -
+local causes any shell options
+(including those that only have long names)
+that are
+changed via the
+.Ic set
+command inside the function to be
+restored to their original values when the function
+returns.
+.Pp
+The syntax of the
+.Ic return
+command is
+.Pp
+.D1 Ic return Op Ar exitstatus
+.Pp
+It terminates the current executional scope, returning from the closest
+nested function or sourced script;
+if no function or sourced script is being executed,
+it exits the shell instance.
+The
+.Ic return
+command is implemented as a special built-in command.
+.Ss Variables and Parameters
+The shell maintains a set of parameters.
+A parameter
+denoted by a name
+(consisting solely
+of alphabetics, numerics, and underscores,
+and starting with an alphabetic or an underscore)
+is called a variable.
+When starting up,
+the shell turns all environment variables with valid names into shell
+variables.
+New variables can be set using the form
+.Pp
+.D1 Ar name Ns = Ns Ar value
+.Pp
+A parameter can also be denoted by a number
+or a special character as explained below.
+.Pp
+Assignments are expanded differently from other words:
+tilde expansion is also performed after the equals sign and after any colon
+and usernames are also terminated by colons,
+and field splitting and pathname expansion are not performed.
+.Pp
+This special expansion applies not only to assignments that form a simple
+command by themselves or precede a command word,
+but also to words passed to the
+.Ic export ,
+.Ic local
+or
+.Ic readonly
+built-in commands that have this form.
+For this, the builtin's name must be literal
+(not the result of an expansion)
+and may optionally be preceded by one or more literal instances of
+.Ic command
+without options.
+.Ss Positional Parameters
+A positional parameter is a parameter denoted by a number greater than zero.
+The shell sets these initially to the values of its command line
+arguments that follow the name of the shell script.
+The
+.Ic set
+built-in command can also be used to set or reset them.
+.Ss Special Parameters
+Special parameters are parameters denoted by a single special character
+or the digit zero.
+They are shown in the following list, exactly as they would appear in input
+typed by the user or in the source of a shell script.
+.Bl -hang
+.It Li $*
+Expands to the positional parameters, starting from one.
+When
+the expansion occurs within a double-quoted string
+it expands to a single field with the value of each parameter
+separated by the first character of the
+.Va IFS
+variable,
+or by a space if
+.Va IFS
+is unset.
+.It Li $@
+Expands to the positional parameters, starting from one.
+When
+the expansion occurs within double-quotes, each positional
+parameter expands as a separate argument.
+If there are no positional parameters, the
+expansion of
+.Li @
+generates zero arguments, even when
+.Li @
+is double-quoted.
+What this basically means, for example, is
+if
+.Li $1
+is
+.Dq Li abc
+and
+.Li $2
+is
+.Dq Li "def ghi" ,
+then
+.Li \&"$@\&"
+expands to
+the two arguments:
+.Bd -literal -offset indent
+"abc" "def ghi"
+.Ed
+.It Li $#
+Expands to the number of positional parameters.
+.It Li $?
+Expands to the exit status of the most recent pipeline.
+.It Li $-
+(hyphen) Expands to the current option flags (the single-letter
+option names concatenated into a string) as specified on
+invocation, by the
+.Ic set
+built-in command, or implicitly
+by the shell.
+.It Li $$
+Expands to the process ID of the invoked shell.
+A subshell
+retains the same value of
+.Va $
+as its parent.
+.It Li $!
+Expands to the process ID of the most recent background
+command executed from the current shell.
+For a
+pipeline, the process ID is that of the last command in the
+pipeline.
+If this parameter is referenced, the shell will remember
+the process ID and its exit status until the
+.Ic wait
+built-in command reports completion of the process.
+.It Li $0
+(zero) Expands to the name of the shell script if passed on the command line,
+the
+.Ar name
+operand if given (with
+.Fl c )
+or otherwise argument 0 passed to the shell.
+.El
+.Ss Special Variables
+The following variables are set by the shell or
+have special meaning to it:
+.Bl -tag -width ".Va HISTSIZE"
+.It Va CDPATH
+The search path used with the
+.Ic cd
+built-in.
+.It Va EDITOR
+The fallback editor used with the
+.Ic fc
+built-in.
+If not set, the default editor is
+.Xr ed 1 .
+.It Va FCEDIT
+The default editor used with the
+.Ic fc
+built-in.
+.It Va HISTSIZE
+The number of previous commands that are accessible.
+.It Va HOME
+The user's home directory,
+used in tilde expansion and as a default directory for the
+.Ic cd
+built-in.
+.It Va IFS
+Input Field Separators.
+This is initialized at startup to
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline
+in that order.
+This value also applies if
+.Va IFS
+is unset, but not if it is set to the empty string.
+See the
+.Sx White Space Splitting
+section for more details.
+.It Va LINENO
+The current line number in the script or function.
+.It Va MAIL
+The name of a mail file, that will be checked for the arrival of new
+mail.
+Overridden by
+.Va MAILPATH .
+.It Va MAILPATH
+A colon
+.Pq Ql \&:
+separated list of file names, for the shell to check for incoming
+mail.
+This variable overrides the
+.Va MAIL
+setting.
+There is a maximum of 10 mailboxes that can be monitored at once.
+.It Va OPTIND
+The index of the next argument to be processed by
+.Ic getopts .
+This is initialized to 1 at startup.
+.It Va PATH
+The default search path for executables.
+See the
+.Sx Path Search
+section for details.
+.It Va PPID
+The parent process ID of the invoked shell.
+This is set at startup
+unless this variable is in the environment.
+A later change of parent process ID is not reflected.
+A subshell retains the same value of
+.Va PPID .
+.It Va PS1
+The primary prompt string, which defaults to
+.Dq Li "$ " ,
+unless you are the superuser, in which case it defaults to
+.Dq Li "# " .
+.Va PS1
+may include any of the following formatting sequences,
+which are replaced by the given information:
+.Bl -tag -width indent
+.It Li \eH
+This system's fully-qualified hostname (FQDN).
+.It Li \eh
+This system's hostname.
+.It Li \eW
+The final component of the current working directory.
+.It Li \ew
+The entire path of the current working directory.
+.It Li \e$
+Superuser status.
+.Dq Li "$ "
+for normal users and
+.Dq Li "# "
+for superusers.
+.It Li \e\e
+A literal backslash.
+.El
+.It Va PS2
+The secondary prompt string, which defaults to
+.Dq Li "> " .
+.Va PS2
+may include any of the formatting sequences from
+.Va PS1 .
+.It Va PS4
+The prefix for the trace output (if
+.Fl x
+is active).
+The default is
+.Dq Li "+ " .
+.El
+.Ss Word Expansions
+This clause describes the various expansions that are
+performed on words.
+Not all expansions are performed on
+every word, as explained later.
+.Pp
+Tilde expansions, parameter expansions, command substitutions,
+arithmetic expansions, and quote removals that occur within
+a single word expand to a single field.
+It is only field
+splitting or pathname expansion that can create multiple
+fields from a single word.
+The single exception to this rule is
+the expansion of the special parameter
+.Va @
+within double-quotes,
+as was described above.
+.Pp
+The order of word expansion is:
+.Bl -enum
+.It
+Tilde Expansion, Parameter Expansion, Command Substitution,
+Arithmetic Expansion (these all occur at the same time).
+.It
+Field Splitting is performed on fields generated by step (1)
+unless the
+.Va IFS
+variable is null.
+.It
+Pathname Expansion (unless the
+.Fl f
+option is in effect).
+.It
+Quote Removal.
+.El
+.Pp
+The
+.Ql $
+character is used to introduce parameter expansion, command
+substitution, or arithmetic expansion.
+.Ss Tilde Expansion (substituting a user's home directory)
+A word beginning with an unquoted tilde character
+.Pq Ql ~
+is
+subjected to tilde expansion.
+All the characters up to a slash
+.Pq Ql /
+or the end of the word are treated as a username
+and are replaced with the user's home directory.
+If the
+username is missing (as in
+.Pa ~/foobar ) ,
+the tilde is replaced with the value of the
+.Va HOME
+variable (the current user's home directory).
+.Ss Parameter Expansion
+The format for parameter expansion is as follows:
+.Pp
+.D1 Li ${ Ns Ar expression Ns Li }
+.Pp
+where
+.Ar expression
+consists of all characters until the matching
+.Ql } .
+Any
+.Ql }
+escaped by a backslash or within a single-quoted or double-quoted
+string, and characters in
+embedded arithmetic expansions, command substitutions, and variable
+expansions, are not examined in determining the matching
+.Ql } .
+If the variants with
+.Ql + ,
+.Ql - ,
+.Ql =
+or
+.Ql ?\&
+occur within a double-quoted string,
+as an extension there may be unquoted parts
+(via double-quotes inside the expansion);
+.Ql }
+within such parts are also not examined in determining the matching
+.Ql } .
+.Pp
+The simplest form for parameter expansion is:
+.Pp
+.D1 Li ${ Ns Ar parameter Ns Li }
+.Pp
+The value, if any, of
+.Ar parameter
+is substituted.
+.Pp
+The parameter name or symbol can be enclosed in braces, which are
+optional except for positional parameters with more than one digit or
+when parameter is followed by a character that could be interpreted as
+part of the name.
+If a parameter expansion occurs inside double-quotes:
+.Bl -enum
+.It
+Field splitting is not performed on the results of the
+expansion, with the exception of the special parameter
+.Va @ .
+.It
+Pathname expansion is not performed on the results of the
+expansion.
+.El
+.Pp
+In addition, a parameter expansion can be modified by using one of the
+following formats.
+.Bl -tag -width indent
+.It Li ${ Ns Ar parameter Ns Li :- Ns Ar word Ns Li }
+Use Default Values.
+If
+.Ar parameter
+is unset or null, the expansion of
+.Ar word
+is substituted; otherwise, the value of
+.Ar parameter
+is substituted.
+.It Li ${ Ns Ar parameter Ns Li := Ns Ar word Ns Li }
+Assign Default Values.
+If
+.Ar parameter
+is unset or null, the expansion of
+.Ar word
+is assigned to
+.Ar parameter .
+In all cases, the
+final value of
+.Ar parameter
+is substituted.
+Quoting inside
+.Ar word
+does not prevent field splitting or pathname expansion.
+Only variables, not positional
+parameters or special parameters, can be
+assigned in this way.
+.It Li ${ Ns Ar parameter Ns Li :? Ns Oo Ar word Oc Ns Li }
+Indicate Error if Null or Unset.
+If
+.Ar parameter
+is unset or null, the expansion of
+.Ar word
+(or a message indicating it is unset if
+.Ar word
+is omitted) is written to standard
+error and the shell exits with a nonzero
+exit status.
+Otherwise, the value of
+.Ar parameter
+is substituted.
+An
+interactive shell need not exit.
+.It Li ${ Ns Ar parameter Ns Li :+ Ns Ar word Ns Li }
+Use Alternate Value.
+If
+.Ar parameter
+is unset or null, null is substituted;
+otherwise, the expansion of
+.Ar word
+is substituted.
+.El
+.Pp
+In the parameter expansions shown previously, use of the colon in the
+format results in a test for a parameter that is unset or null; omission
+of the colon results in a test for a parameter that is only unset.
+.Pp
+The
+.Ar word
+inherits the type of quoting
+(unquoted, double-quoted or here-document)
+from the surroundings,
+with the exception that a backslash that quotes a closing brace is removed
+during quote removal.
+.Bl -tag -width indent
+.It Li ${# Ns Ar parameter Ns Li }
+String Length.
+The length in characters of
+the value of
+.Ar parameter .
+.El
+.Pp
+The following four varieties of parameter expansion provide for substring
+processing.
+In each case, pattern matching notation
+(see
+.Sx Shell Patterns ) ,
+rather than regular expression notation,
+is used to evaluate the patterns.
+If parameter is one of the special parameters
+.Va *
+or
+.Va @ ,
+the result of the expansion is unspecified.
+Enclosing the full parameter expansion string in double-quotes does not
+cause the following four varieties of pattern characters to be quoted,
+whereas quoting characters within the braces has this effect.
+.Bl -tag -width indent
+.It Li ${ Ns Ar parameter Ns Li % Ns Ar word Ns Li }
+Remove Smallest Suffix Pattern.
+The
+.Ar word
+is expanded to produce a pattern.
+The
+parameter expansion then results in
+.Ar parameter ,
+with the smallest portion of the
+suffix matched by the pattern deleted.
+.It Li ${ Ns Ar parameter Ns Li %% Ns Ar word Ns Li }
+Remove Largest Suffix Pattern.
+The
+.Ar word
+is expanded to produce a pattern.
+The
+parameter expansion then results in
+.Ar parameter ,
+with the largest portion of the
+suffix matched by the pattern deleted.
+.It Li ${ Ns Ar parameter Ns Li # Ns Ar word Ns Li }
+Remove Smallest Prefix Pattern.
+The
+.Ar word
+is expanded to produce a pattern.
+The
+parameter expansion then results in
+.Ar parameter ,
+with the smallest portion of the
+prefix matched by the pattern deleted.
+.It Li ${ Ns Ar parameter Ns Li ## Ns Ar word Ns Li }
+Remove Largest Prefix Pattern.
+The
+.Ar word
+is expanded to produce a pattern.
+The
+parameter expansion then results in
+.Ar parameter ,
+with the largest portion of the
+prefix matched by the pattern deleted.
+.El
+.Ss Command Substitution
+Command substitution allows the output of a command to be substituted in
+place of the command name itself.
+Command substitution occurs when
+the command is enclosed as follows:
+.Pp
+.D1 Li $( Ns Ar command Ns Li )\&
+.Pp
+or the backquoted version:
+.Pp
+.D1 Li ` Ns Ar command Ns Li `
+.Pp
+The shell expands the command substitution by executing command
+and replacing the command substitution
+with the standard output of the command,
+removing sequences of one or more newlines at the end of the substitution.
+Embedded newlines before the end of the output are not removed;
+however, during field splitting, they may be translated into spaces
+depending on the value of
+.Va IFS
+and the quoting that is in effect.
+The command is executed in a subshell environment,
+except that the built-in commands
+.Ic jobid ,
+.Ic jobs ,
+and
+.Ic trap
+return information about the parent shell environment
+and
+.Ic times
+returns information about the same process
+if they are the only command in a command substitution.
+.Pp
+If a command substitution of the
+.Li $(
+form begins with a subshell,
+the
+.Li $(
+and
+.Li (\&
+must be separated by whitespace
+to avoid ambiguity with arithmetic expansion.
+.Ss Arithmetic Expansion
+Arithmetic expansion provides a mechanism for evaluating an arithmetic
+expression and substituting its value.
+The format for arithmetic expansion is as follows:
+.Pp
+.D1 Li $(( Ns Ar expression Ns Li ))
+.Pp
+The
+.Ar expression
+is treated as if it were in double-quotes, except
+that a double-quote inside the expression is not treated specially.
+The
+shell expands all tokens in the
+.Ar expression
+for parameter expansion,
+command substitution,
+arithmetic expansion
+and quote removal.
+.Pp
+The allowed expressions are a subset of C expressions,
+summarized below.
+.Bl -tag -width "Variables" -offset indent
+.It Values
+All values are of type
+.Ft intmax_t .
+.It Constants
+Decimal, octal (starting with
+.Li 0 )
+and hexadecimal (starting with
+.Li 0x )
+integer constants.
+.It Variables
+Shell variables can be read and written
+and contain integer constants.
+.It Unary operators
+.Li "! ~ + -"
+.It Binary operators
+.Li "* / % + - << >> < <= > >= == != & ^ | && ||"
+.It Assignment operators
+.Li "= += -= *= /= %= <<= >>= &= ^= |="
+.It Conditional operator
+.Li "? :"
+.El
+.Pp
+The result of the expression is substituted in decimal.
+.Ss White Space Splitting (Field Splitting)
+In certain contexts,
+after parameter expansion, command substitution, and
+arithmetic expansion the shell scans the results of
+expansions and substitutions that did not occur in double-quotes for
+field splitting and multiple fields can result.
+.Pp
+Characters in
+.Va IFS
+that are whitespace
+.Po
+.Aq space ,
+.Aq tab ,
+and
+.Aq newline
+.Pc
+are treated differently from other characters in
+.Va IFS .
+.Pp
+Whitespace in
+.Va IFS
+at the beginning or end of a word is discarded.
+.Pp
+Subsequently, a field is delimited by either
+.Bl -enum
+.It
+a non-whitespace character in
+.Va IFS
+with any whitespace in
+.Va IFS
+surrounding it, or
+.It
+one or more whitespace characters in
+.Va IFS .
+.El
+.Pp
+If a word ends with a non-whitespace character in
+.Va IFS ,
+there is no empty field after this character.
+.Pp
+If no field is delimited, the word is discarded.
+In particular, if a word consists solely of an unquoted substitution
+and the result of the substitution is null,
+it is removed by field splitting even if
+.Va IFS
+is null.
+.Ss Pathname Expansion (File Name Generation)
+Unless the
+.Fl f
+option is set,
+file name generation is performed
+after word splitting is complete.
+Each word is
+viewed as a series of patterns, separated by slashes.
+The
+process of expansion replaces the word with the names of
+all existing files whose names can be formed by replacing
+each pattern with a string that matches the specified pattern.
+There are two restrictions on this: first, a pattern cannot match
+a string containing a slash, and second,
+a pattern cannot match a string starting with a period
+unless the first character of the pattern is a period.
+The next section describes the patterns used for
+Pathname Expansion,
+the four varieties of parameter expansion for substring processing and the
+.Ic case
+command.
+.Ss Shell Patterns
+A pattern consists of normal characters, which match themselves,
+and meta-characters.
+The meta-characters are
+.Ql * ,
+.Ql \&? ,
+and
+.Ql \&[ .
+These characters lose their special meanings if they are quoted.
+When command or variable substitution is performed and the dollar sign
+or back quotes are not double-quoted, the value of the
+variable or the output of the command is scanned for these
+characters and they are turned into meta-characters.
+.Pp
+An asterisk
+.Pq Ql *
+matches any string of characters.
+A question mark
+.Pq Ql \&?
+matches any single character.
+A left bracket
+.Pq Ql \&[
+introduces a character class.
+The end of the character class is indicated by a
+.Ql \&] ;
+if the
+.Ql \&]
+is missing then the
+.Ql \&[
+matches a
+.Ql \&[
+rather than introducing a character class.
+A character class matches any of the characters between the square brackets.
+A locale-dependent range of characters may be specified using a minus sign.
+A named class of characters (see
+.Xr wctype 3 )
+may be specified by surrounding the name with
+.Ql \&[:
+and
+.Ql :\&] .
+For example,
+.Ql \&[\&[:alpha:\&]\&]
+is a shell pattern that matches a single letter.
+The character class may be complemented by making an exclamation point
+.Pq Ql !\&
+the first character of the character class.
+A caret
+.Pq Ql ^
+has the same effect but is non-standard.
+.Pp
+To include a
+.Ql \&]
+in a character class, make it the first character listed
+(after the
+.Ql \&!
+or
+.Ql ^ ,
+if any).
+To include a
+.Ql - ,
+make it the first or last character listed.
+.Ss Built-in Commands
+This section lists the built-in commands.
+.Bl -tag -width indent
+.It Ic \&:
+A null command that returns a 0 (true) exit value.
+.It Ic \&. Ar file
+The commands in the specified file are read and executed by the shell.
+The
+.Ic return
+command may be used to return to the
+.Ic \&.
+command's caller.
+If
+.Ar file
+contains any
+.Ql /
+characters, it is used as is.
+Otherwise, the shell searches the
+.Va PATH
+for the file.
+If it is not found in the
+.Va PATH ,
+it is sought in the current working directory.
+.It Ic \&[
+A built-in equivalent of
+.Xr test 1 .
+.It Ic alias Oo Ar name Ns Oo = Ns Ar string Oc ... Oc
+If
+.Ar name Ns = Ns Ar string
+is specified, the shell defines the alias
+.Ar name
+with value
+.Ar string .
+If just
+.Ar name
+is specified, the value of the alias
+.Ar name
+is printed.
+With no arguments, the
+.Ic alias
+built-in command prints the names and values of all defined aliases
+(see
+.Ic unalias ) .
+Alias values are written with appropriate quoting so that they are
+suitable for re-input to the shell.
+Also see the
+.Sx Aliases
+subsection.
+.It Ic bg Op Ar job ...
+Continue the specified jobs
+(or the current job if no jobs are given)
+in the background.
+.It Ic bind Oo Fl aeklrsv Oc Oo Ar key Oo Ar command Oc Oc
+List or alter key bindings for the line editor.
+This command is documented in
+.Xr editrc 5 .
+.It Ic break Op Ar num
+See the
+.Sx Flow-Control Constructs
+subsection.
+.It Ic builtin Ar cmd Op Ar arg ...
+Execute the specified built-in command,
+.Ar cmd .
+This is useful when the user wishes to override a shell function
+with the same name as a built-in command.
+.It Ic cd Oo Fl L | P Oc Oo Fl e Oc Op Ar directory
+.It Ic cd Fl
+Switch to the specified
+.Ar directory ,
+to the directory specified in the
+.Va HOME
+environment variable if no
+.Ar directory
+is specified or
+to the directory specified in the
+.Va OLDPWD
+environment variable if
+.Ar directory
+is
+.Fl .
+If
+.Ar directory
+does not begin with
+.Pa / , \&. ,
+or
+.Pa .. ,
+then the directories listed in the
+.Va CDPATH
+variable will be
+searched for the specified
+.Ar directory .
+If
+.Va CDPATH
+is unset, the current directory is searched.
+The format of
+.Va CDPATH
+is the same as that of
+.Va PATH .
+In an interactive shell,
+the
+.Ic cd
+command will print out the name of the directory
+that it actually switched to
+if the
+.Va CDPATH
+mechanism was used or if
+.Ar directory
+was
+.Fl .
+.Pp
+If the
+.Fl P
+option is specified,
+.Pa ..
+is handled physically and symbolic links are resolved before
+.Pa ..
+components are processed.
+If the
+.Fl L
+option is specified,
+.Pa ..
+is handled logically.
+This is the default.
+.Pp
+The
+.Fl e
+option causes
+.Ic cd
+to return exit status 1 if the full pathname of the new directory
+cannot be determined reliably or at all.
+Normally this is not considered an error,
+although a warning is printed.
+.Pp
+If changing the directory fails, the exit status is greater than 1.
+If the directory is changed, the exit status is 0, or also 1 if
+.Fl e
+was given.
+.It Ic chdir
+A synonym for the
+.Ic cd
+built-in command.
+.It Ic command Oo Fl p Oc Op Ar utility Op Ar argument ...
+.It Ic command Oo Fl p Oc Fl v Ar utility
+.It Ic command Oo Fl p Oc Fl V Ar utility
+The first form of invocation executes the specified
+.Ar utility ,
+ignoring shell functions in the search.
+If
+.Ar utility
+is a special builtin,
+it is executed as if it were a regular builtin.
+.Pp
+If the
+.Fl p
+option is specified, the command search is performed using a
+default value of
+.Va PATH
+that is guaranteed to find all of the standard utilities.
+.Pp
+If the
+.Fl v
+option is specified,
+.Ar utility
+is not executed but a description of its interpretation by the shell is
+printed.
+For ordinary commands the output is the path name; for shell built-in
+commands, shell functions and keywords only the name is written.
+Aliases are printed as
+.Dq Ic alias Ar name Ns = Ns Ar value .
+.Pp
+The
+.Fl V
+option is identical to
+.Fl v
+except for the output.
+It prints
+.Dq Ar utility Ic is Ar description
+where
+.Ar description
+is either
+the path name to
+.Ar utility ,
+a special shell builtin,
+a shell builtin,
+a shell function,
+a shell keyword
+or
+an alias for
+.Ar value .
+.It Ic continue Op Ar num
+See the
+.Sx Flow-Control Constructs
+subsection.
+.It Ic echo Oo Fl e | n Oc Op Ar string ...
+Print a space-separated list of the arguments to the standard output
+and append a newline character.
+.Bl -tag -width indent
+.It Fl n
+Suppress the output of the trailing newline.
+.It Fl e
+Process C-style backslash escape sequences.
+The
+.Ic echo
+command understands the following character escapes:
+.Bl -tag -width indent
+.It \ea
+Alert (ring the terminal bell)
+.It \eb
+Backspace
+.It \ec
+Suppress the trailing newline (this has the side-effect of truncating the
+line if it is not the last character)
+.It \ee
+The ESC character
+.Tn ( ASCII
+0x1b)
+.It \ef
+Formfeed
+.It \en
+Newline
+.It \er
+Carriage return
+.It \et
+Horizontal tab
+.It \ev
+Vertical tab
+.It \e\e
+Literal backslash
+.It \e0nnn
+(Zero) The character whose octal value is
+.Ar nnn
+.El
+.Pp
+If
+.Ar string
+is not enclosed in quotes then the backslash itself must be escaped
+with a backslash to protect it from the shell.
+For example
+.Bd -literal -offset indent
+$ echo -e "a\evb"
+a
+ b
+$ echo -e a\e\evb
+a
+ b
+$ echo -e "a\e\eb"
+a\eb
+$ echo -e a\e\e\e\eb
+a\eb
+.Ed
+.El
+.Pp
+Only one of the
+.Fl e
+and
+.Fl n
+options may be specified.
+.It Ic eval Ar string ...
+Concatenate all the arguments with spaces.
+Then re-parse and execute the command.
+.It Ic exec Op Ar command Op arg ...
+Unless
+.Ar command
+is omitted,
+the shell process is replaced with the specified program
+(which must be a real program, not a shell built-in command or function).
+Any redirections on the
+.Ic exec
+command are marked as permanent,
+so that they are not undone when the
+.Ic exec
+command finishes.
+.It Ic exit Op Ar exitstatus
+Terminate the shell process.
+If
+.Ar exitstatus
+is given
+it is used as the exit status of the shell.
+Otherwise, if the shell is executing an
+.Cm EXIT
+trap, the exit status of the last command before the trap is used;
+if the shell is executing a trap for a signal,
+the shell exits by resending the signal to itself.
+Otherwise, the exit status of the preceding command is used.
+The exit status should be an integer between 0 and 255.
+.It Ic export Ar name ...
+.It Ic export Op Fl p
+The specified names are exported so that they will
+appear in the environment of subsequent commands.
+The only way to un-export a variable is to
+.Ic unset
+it.
+The shell allows the value of a variable to be set
+at the same time as it is exported by writing
+.Pp
+.D1 Ic export Ar name Ns = Ns Ar value
+.Pp
+With no arguments the
+.Ic export
+command lists the names
+of all exported variables.
+If the
+.Fl p
+option is specified, the exported variables are printed as
+.Dq Ic export Ar name Ns = Ns Ar value
+lines, suitable for re-input to the shell.
+.It Ic false
+A null command that returns a non-zero (false) exit value.
+.It Ic fc Oo Fl e Ar editor Oc Op Ar first Op Ar last
+.It Ic fc Fl l Oo Fl nr Oc Op Ar first Op Ar last
+.It Ic fc Fl s Oo Ar old Ns = Ns Ar new Oc Op Ar first
+The
+.Ic fc
+built-in command lists, or edits and re-executes,
+commands previously entered to an interactive shell.
+.Bl -tag -width indent
+.It Fl e Ar editor
+Use the editor named by
+.Ar editor
+to edit the commands.
+The
+.Ar editor
+string is a command name,
+subject to search via the
+.Va PATH
+variable.
+The value in the
+.Va FCEDIT
+variable is used as a default when
+.Fl e
+is not specified.
+If
+.Va FCEDIT
+is null or unset, the value of the
+.Va EDITOR
+variable is used.
+If
+.Va EDITOR
+is null or unset,
+.Xr ed 1
+is used as the editor.
+.It Fl l No (ell)
+List the commands rather than invoking
+an editor on them.
+The commands are written in the
+sequence indicated by the
+.Ar first
+and
+.Ar last
+operands, as affected by
+.Fl r ,
+with each command preceded by the command number.
+.It Fl n
+Suppress command numbers when listing with
+.Fl l .
+.It Fl r
+Reverse the order of the commands listed
+(with
+.Fl l )
+or edited
+(with neither
+.Fl l
+nor
+.Fl s ) .
+.It Fl s
+Re-execute the command without invoking an editor.
+.It Ar first
+.It Ar last
+Select the commands to list or edit.
+The number of previous commands that can be accessed
+are determined by the value of the
+.Va HISTSIZE
+variable.
+The value of
+.Ar first
+or
+.Ar last
+or both are one of the following:
+.Bl -tag -width indent
+.It Oo Cm + Oc Ns Ar num
+A positive number representing a command number;
+command numbers can be displayed with the
+.Fl l
+option.
+.It Fl Ar num
+A negative decimal number representing the
+command that was executed
+.Ar num
+of
+commands previously.
+For example, \-1 is the immediately previous command.
+.It Ar string
+A string indicating the most recently entered command
+that begins with that string.
+If the
+.Ar old Ns = Ns Ar new
+operand is not also specified with
+.Fl s ,
+the string form of the first operand cannot contain an embedded equal sign.
+.El
+.El
+.Pp
+The following variables affect the execution of
+.Ic fc :
+.Bl -tag -width ".Va HISTSIZE"
+.It Va FCEDIT
+Name of the editor to use for history editing.
+.It Va HISTSIZE
+The number of previous commands that are accessible.
+.El
+.It Ic fg Op Ar job
+Move the specified
+.Ar job
+or the current job to the foreground.
+.It Ic getopts Ar optstring var
+The
+.Tn POSIX
+.Ic getopts
+command.
+The
+.Ic getopts
+command deprecates the older
+.Xr getopt 1
+command.
+The first argument should be a series of letters, each possibly
+followed by a colon which indicates that the option takes an argument.
+The specified variable is set to the parsed option.
+The index of
+the next argument is placed into the shell variable
+.Va OPTIND .
+If an option takes an argument, it is placed into the shell variable
+.Va OPTARG .
+If an invalid option is encountered,
+.Ar var
+is set to
+.Ql \&? .
+It returns a false value (1) when it encounters the end of the options.
+A new set of arguments may be parsed by assigning
+.Li OPTIND=1 .
+.It Ic hash Oo Fl rv Oc Op Ar command ...
+The shell maintains a hash table which remembers the locations of commands.
+With no arguments whatsoever, the
+.Ic hash
+command prints out the contents of this table.
+.Pp
+With arguments, the
+.Ic hash
+command removes each specified
+.Ar command
+from the hash table (unless they are functions) and then locates it.
+With the
+.Fl v
+option,
+.Ic hash
+prints the locations of the commands as it finds them.
+The
+.Fl r
+option causes the
+.Ic hash
+command to delete all the entries in the hash table except for functions.
+.It Ic jobid Op Ar job
+Print the process IDs of the processes in the specified
+.Ar job .
+If the
+.Ar job
+argument is omitted, use the current job.
+.It Ic jobs Oo Fl lps Oc Op Ar job ...
+Print information about the specified jobs, or all jobs if no
+.Ar job
+argument is given.
+The information printed includes job ID, status and command name.
+.Pp
+If the
+.Fl l
+option is specified, the PID of each job is also printed.
+If the
+.Fl p
+option is specified, only the process IDs for the process group leaders
+are printed, one per line.
+If the
+.Fl s
+option is specified, only the PIDs of the job commands are printed, one per
+line.
+.It Ic kill
+A built-in equivalent of
+.Xr kill 1
+that additionally supports sending signals to jobs.
+.It Ic local Oo Ar variable ... Oc Op Fl
+See the
+.Sx Functions
+subsection.
+.It Ic printf
+A built-in equivalent of
+.Xr printf 1 .
+.It Ic pwd Op Fl L | P
+Print the path of the current directory.
+The built-in command may
+differ from the program of the same name because the
+built-in command remembers what the current directory
+is rather than recomputing it each time.
+This makes
+it faster.
+However, if the current directory is
+renamed,
+the built-in version of
+.Xr pwd 1
+will continue to print the old name for the directory.
+.Pp
+If the
+.Fl P
+option is specified, symbolic links are resolved.
+If the
+.Fl L
+option is specified, the shell's notion of the current directory
+is printed (symbolic links are not resolved).
+This is the default.
+.It Ic read Oo Fl p Ar prompt Oc Oo
+.Fl t Ar timeout Oc Oo Fl er Oc Ar variable ...
+The
+.Ar prompt
+is printed if the
+.Fl p
+option is specified
+and the standard input is a terminal.
+Then a line is
+read from the standard input.
+The trailing newline
+is deleted from the line and the line is split as
+described in the section on
+.Sx White Space Splitting (Field Splitting)
+above, and
+the pieces are assigned to the variables in order.
+If there are more pieces than variables, the remaining
+pieces (along with the characters in
+.Va IFS
+that separated them)
+are assigned to the last variable.
+If there are more variables than pieces, the remaining
+variables are assigned the null string.
+.Pp
+Backslashes are treated specially, unless the
+.Fl r
+option is
+specified.
+If a backslash is followed by
+a newline, the backslash and the newline will be
+deleted.
+If a backslash is followed by any other
+character, the backslash will be deleted and the following
+character will be treated as though it were not in
+.Va IFS ,
+even if it is.
+.Pp
+If the
+.Fl t
+option is specified and the
+.Ar timeout
+elapses before a complete line of input is supplied,
+the
+.Ic read
+command will return an exit status as if terminated by
+.Dv SIGALRM
+without assigning any values.
+The
+.Ar timeout
+value may optionally be followed by one of
+.Ql s ,
+.Ql m
+or
+.Ql h
+to explicitly specify seconds, minutes or hours.
+If none is supplied,
+.Ql s
+is assumed.
+.Pp
+The
+.Fl e
+option exists only for backward compatibility with older scripts.
+.Pp
+The exit status is 0 on success, 1 on end of file,
+between 2 and 128 if an error occurs
+and greater than 128 if a trapped signal interrupts
+.Ic read .
+.It Ic readonly Oo Fl p Oc Op Ar name ...
+Each specified
+.Ar name
+is marked as read only,
+so that it cannot be subsequently modified or unset.
+The shell allows the value of a variable to be set
+at the same time as it is marked read only
+by using the following form:
+.Pp
+.D1 Ic readonly Ar name Ns = Ns Ar value
+.Pp
+With no arguments the
+.Ic readonly
+command lists the names of all read only variables.
+If the
+.Fl p
+option is specified, the read-only variables are printed as
+.Dq Ic readonly Ar name Ns = Ns Ar value
+lines, suitable for re-input to the shell.
+.It Ic return Op Ar exitstatus
+See the
+.Sx Functions
+subsection.
+.It Ic set Oo Fl /+abCEefIimnpTuVvx Oc Oo Fl /+o Ar longname Oc Oo
+.Fl c Ar string Oc Op Fl - Ar arg ...
+The
+.Ic set
+command performs three different functions:
+.Bl -item
+.It
+With no arguments, it lists the values of all shell variables.
+.It
+If options are given,
+either in short form or using the long
+.Dq Fl /+o Ar longname
+form,
+it sets or clears the specified options as described in the section called
+.Sx Argument List Processing .
+.It
+If the
+.Dq Fl -
+option is specified,
+.Ic set
+will replace the shell's positional parameters with the subsequent
+arguments.
+If no arguments follow the
+.Dq Fl -
+option,
+all the positional parameters will be cleared,
+which is equivalent to executing the command
+.Dq Li "shift $#" .
+The
+.Dq Fl -
+flag may be omitted when specifying arguments to be used
+as positional replacement parameters.
+This is not recommended,
+because the first argument may begin with a dash
+.Pq Ql -
+or a plus
+.Pq Ql + ,
+which the
+.Ic set
+command will interpret as a request to enable or disable options.
+.El
+.It Ic setvar Ar variable value
+Assigns the specified
+.Ar value
+to the specified
+.Ar variable .
+The
+.Ic setvar
+command is intended to be used in functions that
+assign values to variables whose names are passed as parameters.
+In general it is better to write
+.Dq Ar variable Ns = Ns Ar value
+rather than using
+.Ic setvar .
+.It Ic shift Op Ar n
+Shift the positional parameters
+.Ar n
+times, or once if
+.Ar n
+is not specified.
+A shift sets the value of
+.Li $1
+to the value of
+.Li $2 ,
+the value of
+.Li $2
+to the value of
+.Li $3 ,
+and so on,
+decreasing the value of
+.Li $#
+by one.
+For portability, shifting if there are zero positional parameters
+should be avoided, since the shell may abort.
+.It Ic test
+A built-in equivalent of
+.Xr test 1 .
+.It Ic times
+Print the amount of time spent executing the shell process and its children.
+The first output line shows the user and system times for the shell process
+itself, the second one contains the user and system times for the
+children.
+.It Ic trap Oo Ar action Oc Ar signal ...
+.It Ic trap Fl l
+Cause the shell to parse and execute
+.Ar action
+when any specified
+.Ar signal
+is received.
+The signals are specified by name or number.
+In addition, the pseudo-signal
+.Cm EXIT
+may be used to specify an
+.Ar action
+that is performed when the shell terminates.
+The
+.Ar action
+may be an empty string or a dash
+.Pq Ql - ;
+the former causes the specified signal to be ignored
+and the latter causes the default action to be taken.
+Omitting the
+.Ar action
+and using only signal numbers is another way to request the default action.
+In a subshell or utility environment,
+the shell resets trapped (but not ignored) signals to the default action.
+The
+.Ic trap
+command has no effect on signals that were ignored on entry to the shell.
+.Pp
+Option
+.Fl l
+causes the
+.Ic trap
+command to display a list of valid signal names.
+.It Ic true
+A null command that returns a 0 (true) exit value.
+.It Ic type Op Ar name ...
+Interpret each
+.Ar name
+as a command and print the resolution of the command search.
+Possible resolutions are:
+shell keyword, alias, special shell builtin, shell builtin, command,
+tracked alias
+and not found.
+For aliases the alias expansion is printed;
+for commands and tracked aliases
+the complete pathname of the command is printed.
+.It Ic ulimit Oo Fl HSabcdfklmnopstuvw Oc Op Ar limit
+Set or display resource limits (see
+.Xr getrlimit 2 ) .
+If
+.Ar limit
+is specified, the named resource will be set;
+otherwise the current resource value will be displayed.
+.Pp
+If
+.Fl H
+is specified, the hard limits will be set or displayed.
+While everybody is allowed to reduce a hard limit,
+only the superuser can increase it.
+The
+.Fl S
+option
+specifies the soft limits instead.
+When displaying limits,
+only one of
+.Fl S
+or
+.Fl H
+can be given.
+The default is to display the soft limits,
+and to set both the hard and the soft limits.
+.Pp
+Option
+.Fl a
+causes the
+.Ic ulimit
+command to display all resources.
+The parameter
+.Ar limit
+is not acceptable in this mode.
+.Pp
+The remaining options specify which resource value is to be
+displayed or modified.
+They are mutually exclusive.
+.Bl -tag -width indent
+.It Fl b Ar sbsize
+The maximum size of socket buffer usage, in bytes.
+.It Fl c Ar coredumpsize
+The maximal size of core dump files, in 512-byte blocks.
+.It Fl d Ar datasize
+The maximal size of the data segment of a process, in kilobytes.
+.It Fl f Ar filesize
+The maximal size of a file, in 512-byte blocks.
+.It Fl k Ar kqueues
+The maximal number of kqueues
+(see
+.Xr kqueue 2 )
+for this user ID.
+.It Fl l Ar lockedmem
+The maximal size of memory that can be locked by a process, in
+kilobytes.
+.It Fl m Ar memoryuse
+The maximal resident set size of a process, in kilobytes.
+.It Fl n Ar nofiles
+The maximal number of descriptors that could be opened by a process.
+.It Fl o Ar umtxp
+The maximal number of process-shared locks
+(see
+.Xr pthread 3 )
+for this user ID.
+.It Fl p Ar pseudoterminals
+The maximal number of pseudo-terminals for this user ID.
+.It Fl s Ar stacksize
+The maximal size of the stack segment, in kilobytes.
+.It Fl t Ar time
+The maximal amount of CPU time to be used by each process, in seconds.
+.It Fl u Ar userproc
+The maximal number of simultaneous processes for this user ID.
+.It Fl v Ar virtualmem
+The maximal virtual size of a process, in kilobytes.
+.It Fl w Ar swapuse
+The maximum amount of swap space reserved or used for this user ID,
+in kilobytes.
+.El
+.It Ic umask Oo Fl S Oc Op Ar mask
+Set the file creation mask (see
+.Xr umask 2 )
+to the octal or symbolic (see
+.Xr chmod 1 )
+value specified by
+.Ar mask .
+If the argument is omitted, the current mask value is printed.
+If the
+.Fl S
+option is specified, the output is symbolic, otherwise the output is octal.
+.It Ic unalias Oo Fl a Oc Op Ar name ...
+The specified alias names are removed.
+If
+.Fl a
+is specified, all aliases are removed.
+.It Ic unset Oo Fl fv Oc Ar name ...
+The specified variables or functions are unset and unexported.
+If the
+.Fl v
+option is specified or no options are given, the
+.Ar name
+arguments are treated as variable names.
+If the
+.Fl f
+option is specified, the
+.Ar name
+arguments are treated as function names.
+.It Ic wait Op Ar job ...
+Wait for each specified
+.Ar job
+to complete and return the exit status of the last process in the
+last specified
+.Ar job .
+If any
+.Ar job
+specified is unknown to the shell, it is treated as if it
+were a known job that exited with exit status 127.
+If no operands are given, wait for all jobs to complete
+and return an exit status of zero.
+.El
+.Ss Command Line Editing
+When
+.Nm
+is being used interactively from a terminal, the current command
+and the command history
+(see
+.Ic fc
+in
+.Sx Built-in Commands )
+can be edited using
+.Nm vi Ns -mode
+command line editing.
+This mode uses commands similar
+to a subset of those described in the
+.Xr vi 1
+man page.
+The command
+.Dq Li "set -o vi"
+(or
+.Dq Li "set -V" )
+enables
+.Nm vi Ns -mode
+editing and places
+.Nm
+into
+.Nm vi
+insert mode.
+With
+.Nm vi Ns -mode
+enabled,
+.Nm
+can be switched between insert mode and command mode by typing
+.Aq ESC .
+Hitting
+.Aq return
+while in command mode will pass the line to the shell.
+.Pp
+Similarly, the
+.Dq Li "set -o emacs"
+(or
+.Dq Li "set -E" )
+command can be used to enable a subset of
+.Nm emacs Ns -style
+command line editing features.
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width ".Ev LANGXXXXXX"
+.It Ev ENV
+Initialization file for interactive shells.
+.It Ev LANG , Ev LC_*
+Locale settings.
+These are inherited by children of the shell,
+and is used in a limited manner by the shell itself.
+.It Ev OLDPWD
+The previous current directory.
+This is used and updated by
+.Ic cd .
+.It Ev PWD
+An absolute pathname for the current directory,
+possibly containing symbolic links.
+This is used and updated by the shell.
+.It Ev TERM
+The default terminal setting for the shell.
+This is inherited by children of the shell, and is used in the history
+editing modes.
+.El
+.Pp
+Additionally, environment variables are turned into shell variables
+at startup,
+which may affect the shell as described under
+.Sx Special Variables .
+.Sh FILES
+.Bl -tag -width "/etc/suid_profileXX" -compact
+.It Pa ~/.profile
+User's login profile.
+.It Pa /etc/profile
+System login profile.
+.It Pa /etc/shells
+Shell database.
+.It Pa /etc/suid_profile
+Privileged shell profile.
+.El
+.Sh EXIT STATUS
+Errors that are detected by the shell, such as a syntax error, will
+cause the shell to exit with a non-zero exit status.
+If the shell is not an interactive shell, the execution of the shell
+file will be aborted.
+Otherwise the shell will return the exit status of the last command
+executed, or if the
+.Ic exit
+builtin is used with a numeric argument, it
+will return the argument.
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr chsh 1 ,
+.Xr echo 1 ,
+.Xr ed 1 ,
+.Xr emacs 1 ,
+.Xr kill 1 ,
+.Xr printf 1 ,
+.Xr pwd 1 ,
+.Xr test 1 ,
+.Xr vi 1 ,
+.Xr execve 2 ,
+.Xr getrlimit 2 ,
+.Xr umask 2 ,
+.Xr wctype 3 ,
+.Xr editrc 5 ,
+.Xr shells 5
+.Sh HISTORY
+A
+.Nm
+command, the Thompson shell, appeared in
+.At v1 .
+It was superseded in
+.At v7
+by the Bourne shell, which inherited the name
+.Nm .
+.Pp
+This version of
+.Nm
+was rewritten in 1989 under the
+.Bx
+license after the Bourne shell from
+.At V.4 .
+.Sh AUTHORS
+This version of
+.Nm
+was originally written by
+.An Kenneth Almquist .
+.Sh BUGS
+The
+.Nm
+utility does not recognize multibyte characters other than UTF-8.
+Splitting using
+.Va IFS
+does not recognize multibyte characters.
diff --git a/shell_cmds/sh/sh.plist.part b/shell_cmds/sh/sh.plist.part
new file mode 100644
index 0000000..f023fca
--- /dev/null
+++ b/shell_cmds/sh/sh.plist.part
@@ -0,0 +1,23 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>sh</string>
+ <key>OpenSourceVersion</key>
+ <string>2016-10-08</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/bin/sh/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/bin/sh/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2016-10-27</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>exec.c: eaccess</string>
+ <string>input.c: remove multiple definition</string>
+ <string>input.c: strchrnul</string>
+ <string>miscbltin.c: warning fix</string>
+ <string>mknodes.c: __printf0like</string>
+ <string>trap.c: sys_nsig</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/sh/shell.h b/shell_cmds/sh/shell.h
new file mode 100644
index 0000000..1c7a766
--- /dev/null
+++ b/shell_cmds/sh/shell.h
@@ -0,0 +1,79 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)shell.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/shell.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+#ifndef SHELL_H_
+#define SHELL_H_
+
+#include <inttypes.h>
+
+/*
+ * The follow should be set to reflect the type of system you have:
+ * JOBS -> 1 if you have Berkeley job control, 0 otherwise.
+ * define DEBUG=1 to compile in debugging (set global "debug" to turn on)
+ * define DEBUG=2 to compile in and turn on debugging.
+ *
+ * When debugging is on, debugging info will be written to ./trace and
+ * a quit signal will generate a core dump.
+ */
+
+
+#define JOBS 1
+/* #define DEBUG 1 */
+
+/*
+ * Type of used arithmetics. SUSv3 requires us to have at least signed long.
+ */
+typedef intmax_t arith_t;
+#define ARITH_FORMAT_STR "%" PRIdMAX
+#define atoarith_t(arg) strtoimax(arg, NULL, 0)
+#define strtoarith_t(nptr, endptr, base) strtoimax(nptr, endptr, base)
+#define ARITH_MIN INTMAX_MIN
+#define ARITH_MAX INTMAX_MAX
+
+typedef void *pointer;
+
+#include <sys/cdefs.h>
+
+extern char nullstr[1]; /* null string */
+
+#ifdef DEBUG
+#define TRACE(param) sh_trace param
+#else
+#define TRACE(param)
+#endif
+
+#endif /* !SHELL_H_ */
diff --git a/shell_cmds/sh/show.c b/shell_cmds/sh/show.c
new file mode 100644
index 0000000..9b55708
--- /dev/null
+++ b/shell_cmds/sh/show.c
@@ -0,0 +1,410 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/show.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include "shell.h"
+#include "parser.h"
+#include "nodes.h"
+#include "mystring.h"
+#include "show.h"
+
+
+#ifdef DEBUG
+static void shtree(union node *, int, char *, FILE*);
+static void shcmd(union node *, FILE *);
+static void sharg(union node *, FILE *);
+static void indent(int, char *, FILE *);
+static void trstring(char *);
+
+
+void
+showtree(union node *n)
+{
+ trputs("showtree called\n");
+ shtree(n, 1, NULL, stdout);
+}
+
+
+static void
+shtree(union node *n, int ind, char *pfx, FILE *fp)
+{
+ struct nodelist *lp;
+ char *s;
+
+ if (n == NULL)
+ return;
+
+ indent(ind, pfx, fp);
+ switch(n->type) {
+ case NSEMI:
+ s = "; ";
+ goto binop;
+ case NAND:
+ s = " && ";
+ goto binop;
+ case NOR:
+ s = " || ";
+binop:
+ shtree(n->nbinary.ch1, ind, NULL, fp);
+ /* if (ind < 0) */
+ fputs(s, fp);
+ shtree(n->nbinary.ch2, ind, NULL, fp);
+ break;
+ case NCMD:
+ shcmd(n, fp);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ case NPIPE:
+ for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) {
+ shcmd(lp->n, fp);
+ if (lp->next)
+ fputs(" | ", fp);
+ }
+ if (n->npipe.backgnd)
+ fputs(" &", fp);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ default:
+ fprintf(fp, "<node type %d>", n->type);
+ if (ind >= 0)
+ putc('\n', fp);
+ break;
+ }
+}
+
+
+
+static void
+shcmd(union node *cmd, FILE *fp)
+{
+ union node *np;
+ int first;
+ char *s;
+ int dftfd;
+
+ first = 1;
+ for (np = cmd->ncmd.args ; np ; np = np->narg.next) {
+ if (! first)
+ putchar(' ');
+ sharg(np, fp);
+ first = 0;
+ }
+ for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) {
+ if (! first)
+ putchar(' ');
+ switch (np->nfile.type) {
+ case NTO: s = ">"; dftfd = 1; break;
+ case NAPPEND: s = ">>"; dftfd = 1; break;
+ case NTOFD: s = ">&"; dftfd = 1; break;
+ case NCLOBBER: s = ">|"; dftfd = 1; break;
+ case NFROM: s = "<"; dftfd = 0; break;
+ case NFROMTO: s = "<>"; dftfd = 0; break;
+ case NFROMFD: s = "<&"; dftfd = 0; break;
+ case NHERE: s = "<<"; dftfd = 0; break;
+ case NXHERE: s = "<<"; dftfd = 0; break;
+ default: s = "*error*"; dftfd = 0; break;
+ }
+ if (np->nfile.fd != dftfd)
+ fprintf(fp, "%d", np->nfile.fd);
+ fputs(s, fp);
+ if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) {
+ if (np->ndup.dupfd >= 0)
+ fprintf(fp, "%d", np->ndup.dupfd);
+ else
+ fprintf(fp, "-");
+ } else if (np->nfile.type == NHERE) {
+ fprintf(fp, "HERE");
+ } else if (np->nfile.type == NXHERE) {
+ fprintf(fp, "XHERE");
+ } else {
+ sharg(np->nfile.fname, fp);
+ }
+ first = 0;
+ }
+}
+
+
+
+static void
+sharg(union node *arg, FILE *fp)
+{
+ char *p;
+ struct nodelist *bqlist;
+ int subtype;
+
+ if (arg->type != NARG) {
+ printf("<node type %d>\n", arg->type);
+ fflush(stdout);
+ abort();
+ }
+ bqlist = arg->narg.backquote;
+ for (p = arg->narg.text ; *p ; p++) {
+ switch (*p) {
+ case CTLESC:
+ putc(*++p, fp);
+ break;
+ case CTLVAR:
+ putc('$', fp);
+ putc('{', fp);
+ subtype = *++p;
+ if (subtype == VSLENGTH)
+ putc('#', fp);
+
+ while (*p != '=')
+ putc(*p++, fp);
+
+ if (subtype & VSNUL)
+ putc(':', fp);
+
+ switch (subtype & VSTYPE) {
+ case VSNORMAL:
+ putc('}', fp);
+ break;
+ case VSMINUS:
+ putc('-', fp);
+ break;
+ case VSPLUS:
+ putc('+', fp);
+ break;
+ case VSQUESTION:
+ putc('?', fp);
+ break;
+ case VSASSIGN:
+ putc('=', fp);
+ break;
+ case VSTRIMLEFT:
+ putc('#', fp);
+ break;
+ case VSTRIMLEFTMAX:
+ putc('#', fp);
+ putc('#', fp);
+ break;
+ case VSTRIMRIGHT:
+ putc('%', fp);
+ break;
+ case VSTRIMRIGHTMAX:
+ putc('%', fp);
+ putc('%', fp);
+ break;
+ case VSLENGTH:
+ break;
+ default:
+ printf("<subtype %d>", subtype);
+ }
+ break;
+ case CTLENDVAR:
+ putc('}', fp);
+ break;
+ case CTLBACKQ:
+ case CTLBACKQ|CTLQUOTE:
+ putc('$', fp);
+ putc('(', fp);
+ shtree(bqlist->n, -1, NULL, fp);
+ putc(')', fp);
+ break;
+ default:
+ putc(*p, fp);
+ break;
+ }
+ }
+}
+
+
+static void
+indent(int amount, char *pfx, FILE *fp)
+{
+ int i;
+
+ for (i = 0 ; i < amount ; i++) {
+ if (pfx && i == amount - 1)
+ fputs(pfx, fp);
+ putc('\t', fp);
+ }
+}
+
+
+/*
+ * Debugging stuff.
+ */
+
+
+FILE *tracefile;
+
+#if DEBUG >= 2
+int debug = 1;
+#else
+int debug = 0;
+#endif
+
+
+void
+trputc(int c)
+{
+ if (tracefile == NULL)
+ return;
+ putc(c, tracefile);
+ if (c == '\n')
+ fflush(tracefile);
+}
+
+
+void
+sh_trace(const char *fmt, ...)
+{
+ va_list va;
+ va_start(va, fmt);
+ if (tracefile != NULL) {
+ (void) vfprintf(tracefile, fmt, va);
+ if (strchr(fmt, '\n'))
+ (void) fflush(tracefile);
+ }
+ va_end(va);
+}
+
+
+void
+trputs(const char *s)
+{
+ if (tracefile == NULL)
+ return;
+ fputs(s, tracefile);
+ if (strchr(s, '\n'))
+ fflush(tracefile);
+}
+
+
+static void
+trstring(char *s)
+{
+ char *p;
+ char c;
+
+ if (tracefile == NULL)
+ return;
+ putc('"', tracefile);
+ for (p = s ; *p ; p++) {
+ switch (*p) {
+ case '\n': c = 'n'; goto backslash;
+ case '\t': c = 't'; goto backslash;
+ case '\r': c = 'r'; goto backslash;
+ case '"': c = '"'; goto backslash;
+ case '\\': c = '\\'; goto backslash;
+ case CTLESC: c = 'e'; goto backslash;
+ case CTLVAR: c = 'v'; goto backslash;
+ case CTLVAR+CTLQUOTE: c = 'V'; goto backslash;
+ case CTLBACKQ: c = 'q'; goto backslash;
+ case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash;
+backslash: putc('\\', tracefile);
+ putc(c, tracefile);
+ break;
+ default:
+ if (*p >= ' ' && *p <= '~')
+ putc(*p, tracefile);
+ else {
+ putc('\\', tracefile);
+ putc(*p >> 6 & 03, tracefile);
+ putc(*p >> 3 & 07, tracefile);
+ putc(*p & 07, tracefile);
+ }
+ break;
+ }
+ }
+ putc('"', tracefile);
+}
+
+
+void
+trargs(char **ap)
+{
+ if (tracefile == NULL)
+ return;
+ while (*ap) {
+ trstring(*ap++);
+ if (*ap)
+ putc(' ', tracefile);
+ else
+ putc('\n', tracefile);
+ }
+ fflush(tracefile);
+}
+
+
+void
+opentrace(void)
+{
+ char s[100];
+ int flags;
+
+ if (!debug)
+ return;
+#ifdef not_this_way
+ {
+ char *p;
+ if ((p = getenv("HOME")) == NULL) {
+ if (geteuid() == 0)
+ p = "/";
+ else
+ p = "/tmp";
+ }
+ strcpy(s, p);
+ strcat(s, "/trace");
+ }
+#else
+ strcpy(s, "./trace");
+#endif /* not_this_way */
+ if ((tracefile = fopen(s, "a")) == NULL) {
+ fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
+ return;
+ }
+ if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
+ fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
+ fputs("\nTracing started.\n", tracefile);
+ fflush(tracefile);
+}
+#endif /* DEBUG */
diff --git a/shell_cmds/sh/show.h b/shell_cmds/sh/show.h
new file mode 100644
index 0000000..fc5ef76
--- /dev/null
+++ b/shell_cmds/sh/show.h
@@ -0,0 +1,42 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)show.h 1.1 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/show.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+void showtree(union node *);
+#ifdef DEBUG
+void sh_trace(const char *, ...) __printflike(1, 2);
+void trargs(char **);
+void trputc(int);
+void trputs(const char *);
+void opentrace(void);
+#endif
diff --git a/shell_cmds/sh/tests/Makefile b/shell_cmds/sh/tests/Makefile
new file mode 100644
index 0000000..b7d7b7d
--- /dev/null
+++ b/shell_cmds/sh/tests/Makefile
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/Makefile 322438 2017-08-12 19:17:48Z jilles $
+
+.include <bsd.own.mk>
+
+TESTS_SUBDIRS+= builtins
+TESTS_SUBDIRS+= errors
+TESTS_SUBDIRS+= execution
+TESTS_SUBDIRS+= expansion
+TESTS_SUBDIRS+= invocation
+TESTS_SUBDIRS+= parameters
+TESTS_SUBDIRS+= parser
+TESTS_SUBDIRS+= set-e
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/Makefile.depend b/shell_cmds/sh/tests/Makefile.depend
new file mode 100644
index 0000000..9ff4aed
--- /dev/null
+++ b/shell_cmds/sh/tests/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# 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/shell_cmds/sh/tests/builtins/Makefile b/shell_cmds/sh/tests/builtins/Makefile
new file mode 100644
index 0000000..98c3841
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/Makefile
@@ -0,0 +1,185 @@
+# $FreeBSD: head/bin/sh/tests/builtins/Makefile 320340 2017-06-25 21:53:08Z jilles $
+
+PACKAGE= tests
+
+.include <src.opts.mk>
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= alias.0 alias.0.stdout
+${PACKAGE}FILES+= alias.1 alias.1.stderr
+${PACKAGE}FILES+= alias3.0 alias3.0.stdout
+${PACKAGE}FILES+= alias4.0
+${PACKAGE}FILES+= break1.0
+${PACKAGE}FILES+= break2.0 break2.0.stdout
+${PACKAGE}FILES+= break3.0
+${PACKAGE}FILES+= break4.4
+${PACKAGE}FILES+= break5.4
+${PACKAGE}FILES+= break6.0
+${PACKAGE}FILES+= builtin1.0
+${PACKAGE}FILES+= case1.0
+${PACKAGE}FILES+= case2.0
+${PACKAGE}FILES+= case3.0
+${PACKAGE}FILES+= case4.0
+${PACKAGE}FILES+= case5.0
+${PACKAGE}FILES+= case6.0
+${PACKAGE}FILES+= case7.0
+${PACKAGE}FILES+= case8.0
+${PACKAGE}FILES+= case9.0
+${PACKAGE}FILES+= case10.0
+${PACKAGE}FILES+= case11.0
+${PACKAGE}FILES+= case12.0
+${PACKAGE}FILES+= case13.0
+${PACKAGE}FILES+= case14.0
+${PACKAGE}FILES+= case15.0
+${PACKAGE}FILES+= case16.0
+${PACKAGE}FILES+= case17.0
+${PACKAGE}FILES+= case18.0
+${PACKAGE}FILES+= case19.0
+${PACKAGE}FILES+= case20.0
+${PACKAGE}FILES+= case21.0
+${PACKAGE}FILES+= case22.0
+${PACKAGE}FILES+= cd1.0
+${PACKAGE}FILES+= cd2.0
+${PACKAGE}FILES+= cd3.0
+${PACKAGE}FILES+= cd4.0
+${PACKAGE}FILES+= cd5.0
+${PACKAGE}FILES+= cd6.0
+${PACKAGE}FILES+= cd7.0
+${PACKAGE}FILES+= cd8.0
+${PACKAGE}FILES+= cd9.0 cd9.0.stdout
+${PACKAGE}FILES+= cd10.0
+${PACKAGE}FILES+= command1.0
+${PACKAGE}FILES+= command2.0
+${PACKAGE}FILES+= command3.0
+${PACKAGE}FILES+= command3.0.stdout
+${PACKAGE}FILES+= command4.0
+${PACKAGE}FILES+= command5.0
+${PACKAGE}FILES+= command5.0.stdout
+${PACKAGE}FILES+= command6.0
+${PACKAGE}FILES+= command6.0.stdout
+${PACKAGE}FILES+= command7.0
+${PACKAGE}FILES+= command8.0
+${PACKAGE}FILES+= command9.0
+${PACKAGE}FILES+= command10.0
+${PACKAGE}FILES+= command11.0
+${PACKAGE}FILES+= command12.0
+${PACKAGE}FILES+= dot1.0
+${PACKAGE}FILES+= dot2.0
+${PACKAGE}FILES+= dot3.0
+${PACKAGE}FILES+= dot4.0
+${PACKAGE}FILES+= echo1.0
+${PACKAGE}FILES+= echo2.0
+${PACKAGE}FILES+= echo3.0
+${PACKAGE}FILES+= eval1.0
+${PACKAGE}FILES+= eval2.0
+${PACKAGE}FILES+= eval3.0
+${PACKAGE}FILES+= eval4.0
+${PACKAGE}FILES+= eval5.0
+${PACKAGE}FILES+= eval6.0
+${PACKAGE}FILES+= eval7.0
+${PACKAGE}FILES+= eval8.7
+${PACKAGE}FILES+= exec1.0
+${PACKAGE}FILES+= exec2.0
+${PACKAGE}FILES+= exit1.0
+${PACKAGE}FILES+= exit2.8
+${PACKAGE}FILES+= exit3.0
+${PACKAGE}FILES+= export1.0
+${PACKAGE}FILES+= fc1.0
+${PACKAGE}FILES+= fc2.0
+${PACKAGE}FILES+= for1.0
+${PACKAGE}FILES+= for2.0
+${PACKAGE}FILES+= for3.0
+${PACKAGE}FILES+= getopts1.0 getopts1.0.stdout
+${PACKAGE}FILES+= getopts2.0 getopts2.0.stdout
+${PACKAGE}FILES+= getopts3.0
+${PACKAGE}FILES+= getopts4.0
+${PACKAGE}FILES+= getopts5.0
+${PACKAGE}FILES+= getopts6.0
+${PACKAGE}FILES+= getopts7.0
+${PACKAGE}FILES+= getopts8.0 getopts8.0.stdout
+${PACKAGE}FILES+= getopts9.0 getopts9.0.stdout
+${PACKAGE}FILES+= getopts10.0
+${PACKAGE}FILES+= hash1.0 hash1.0.stdout
+${PACKAGE}FILES+= hash2.0 hash2.0.stdout
+${PACKAGE}FILES+= hash3.0 hash3.0.stdout
+${PACKAGE}FILES+= hash4.0
+${PACKAGE}FILES+= jobid1.0
+${PACKAGE}FILES+= jobid2.0
+${PACKAGE}FILES+= kill1.0 kill2.0
+${PACKAGE}FILES+= lineno.0 lineno.0.stdout
+${PACKAGE}FILES+= lineno2.0
+${PACKAGE}FILES+= lineno3.0 lineno3.0.stdout
+${PACKAGE}FILES+= local1.0
+${PACKAGE}FILES+= local2.0
+${PACKAGE}FILES+= local3.0
+${PACKAGE}FILES+= local4.0
+${PACKAGE}FILES+= local5.0
+${PACKAGE}FILES+= local6.0
+${PACKAGE}FILES+= local7.0
+.if ${MK_NLS} != "no"
+${PACKAGE}FILES+= locale1.0
+.endif
+${PACKAGE}FILES+= locale2.0
+${PACKAGE}FILES+= printf1.0
+${PACKAGE}FILES+= printf2.0
+${PACKAGE}FILES+= printf3.0
+${PACKAGE}FILES+= printf4.0
+${PACKAGE}FILES+= read1.0 read1.0.stdout
+${PACKAGE}FILES+= read2.0
+${PACKAGE}FILES+= read3.0 read3.0.stdout
+${PACKAGE}FILES+= read4.0 read4.0.stdout
+${PACKAGE}FILES+= read5.0
+${PACKAGE}FILES+= read6.0
+${PACKAGE}FILES+= read7.0
+${PACKAGE}FILES+= read8.0
+${PACKAGE}FILES+= read9.0
+${PACKAGE}FILES+= return1.0
+${PACKAGE}FILES+= return2.1
+${PACKAGE}FILES+= return3.1
+${PACKAGE}FILES+= return4.0
+${PACKAGE}FILES+= return5.0
+${PACKAGE}FILES+= return6.4
+${PACKAGE}FILES+= return7.4
+${PACKAGE}FILES+= return8.0
+${PACKAGE}FILES+= set1.0
+${PACKAGE}FILES+= set2.0
+${PACKAGE}FILES+= set3.0
+${PACKAGE}FILES+= trap1.0
+${PACKAGE}FILES+= trap10.0
+${PACKAGE}FILES+= trap11.0
+${PACKAGE}FILES+= trap12.0
+${PACKAGE}FILES+= trap13.0
+${PACKAGE}FILES+= trap14.0
+${PACKAGE}FILES+= trap15.0
+${PACKAGE}FILES+= trap16.0
+${PACKAGE}FILES+= trap17.0
+${PACKAGE}FILES+= trap2.0
+${PACKAGE}FILES+= trap3.0
+${PACKAGE}FILES+= trap4.0
+${PACKAGE}FILES+= trap5.0
+${PACKAGE}FILES+= trap6.0
+${PACKAGE}FILES+= trap7.0
+${PACKAGE}FILES+= trap8.0
+${PACKAGE}FILES+= trap9.0
+${PACKAGE}FILES+= type1.0 type1.0.stderr
+${PACKAGE}FILES+= type2.0
+${PACKAGE}FILES+= type3.0
+${PACKAGE}FILES+= unalias.0
+${PACKAGE}FILES+= var-assign.0
+${PACKAGE}FILES+= var-assign2.0
+${PACKAGE}FILES+= wait1.0
+${PACKAGE}FILES+= wait2.0
+${PACKAGE}FILES+= wait3.0
+${PACKAGE}FILES+= wait4.0
+${PACKAGE}FILES+= wait5.0
+${PACKAGE}FILES+= wait6.0
+${PACKAGE}FILES+= wait7.0
+${PACKAGE}FILES+= wait8.0
+${PACKAGE}FILES+= wait9.127
+${PACKAGE}FILES+= wait10.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/builtins/Makefile.depend b/shell_cmds/sh/tests/builtins/Makefile.depend
new file mode 100644
index 0000000..21c5642
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/builtins/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# 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/shell_cmds/sh/tests/builtins/alias.0 b/shell_cmds/sh/tests/builtins/alias.0
new file mode 100644
index 0000000..067a890
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/alias.0 190285 2009-03-22 21:12:00Z stefanf $
+set -e
+
+unalias -a
+alias foo=bar
+alias bar=
+alias quux="1 2 3"
+alias
+alias foo
diff --git a/shell_cmds/sh/tests/builtins/alias.0.stdout b/shell_cmds/sh/tests/builtins/alias.0.stdout
new file mode 100644
index 0000000..52efaf0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias.0.stdout
@@ -0,0 +1,4 @@
+bar=''
+foo=bar
+quux='1 2 3'
+foo=bar
diff --git a/shell_cmds/sh/tests/builtins/alias.1 b/shell_cmds/sh/tests/builtins/alias.1
new file mode 100644
index 0000000..22093dd
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias.1
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/alias.1 149781 2005-09-04 11:59:59Z stefanf $
+unalias -a
+alias foo
diff --git a/shell_cmds/sh/tests/builtins/alias.1.stderr b/shell_cmds/sh/tests/builtins/alias.1.stderr
new file mode 100644
index 0000000..c9f4011
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias.1.stderr
@@ -0,0 +1 @@
+alias: foo: not found
diff --git a/shell_cmds/sh/tests/builtins/alias3.0 b/shell_cmds/sh/tests/builtins/alias3.0
new file mode 100644
index 0000000..e2e215a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias3.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/alias3.0 242767 2012-11-08 13:36:19Z jilles $
+set -e
+
+unalias -a
+alias foo=bar
+alias bar=
+alias quux="1 2 3"
+alias foo=bar
+alias bar=
+alias quux="1 2 3"
+alias
+alias foo
diff --git a/shell_cmds/sh/tests/builtins/alias3.0.stdout b/shell_cmds/sh/tests/builtins/alias3.0.stdout
new file mode 100644
index 0000000..52efaf0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias3.0.stdout
@@ -0,0 +1,4 @@
+bar=''
+foo=bar
+quux='1 2 3'
+foo=bar
diff --git a/shell_cmds/sh/tests/builtins/alias4.0 b/shell_cmds/sh/tests/builtins/alias4.0
new file mode 100644
index 0000000..d86559b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/alias4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/alias4.0 254849 2013-08-25 11:42:53Z jilles $
+
+unalias -a
+alias --
diff --git a/shell_cmds/sh/tests/builtins/break1.0 b/shell_cmds/sh/tests/builtins/break1.0
new file mode 100644
index 0000000..219cbf2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break1.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break1.0 211349 2010-08-15 21:06:53Z jilles $
+
+if [ "$1" != nested ]; then
+ while :; do
+ set -- nested
+ . "$0"
+ echo bad2
+ exit 2
+ done
+ exit 0
+fi
+# To trigger the bug, the following commands must be at the top level,
+# with newlines in between.
+break
+echo bad1
+exit 1
diff --git a/shell_cmds/sh/tests/builtins/break2.0 b/shell_cmds/sh/tests/builtins/break2.0
new file mode 100644
index 0000000..f836e31
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break2.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break2.0 211467 2010-08-18 20:26:50Z jilles $
+
+# It is not immediately obvious that this should work, and someone probably
+# relies on it.
+
+while :; do
+ trap 'break' USR1
+ kill -USR1 $$
+ echo bad
+ exit 1
+done
+echo good
diff --git a/shell_cmds/sh/tests/builtins/break2.0.stdout b/shell_cmds/sh/tests/builtins/break2.0.stdout
new file mode 100644
index 0000000..12799cc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break2.0.stdout
@@ -0,0 +1 @@
+good
diff --git a/shell_cmds/sh/tests/builtins/break3.0 b/shell_cmds/sh/tests/builtins/break3.0
new file mode 100644
index 0000000..1a6985c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break3.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break3.0 211612 2010-08-22 11:07:46Z jilles $
+
+# We accept this and people might rely on it.
+# However, various other shells do not accept it.
+
+f() {
+ break
+ echo bad1
+}
+
+while :; do
+ f
+ echo bad2
+ exit 2
+done
diff --git a/shell_cmds/sh/tests/builtins/break4.4 b/shell_cmds/sh/tests/builtins/break4.4
new file mode 100644
index 0000000..3b1bb0c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break4.4
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break4.4 251180 2013-05-31 14:45:25Z jilles $
+
+# Although this is not specified by POSIX, some configure scripts (gawk 4.1.0)
+# appear to depend on it.
+
+break
+exit 4
diff --git a/shell_cmds/sh/tests/builtins/break5.4 b/shell_cmds/sh/tests/builtins/break5.4
new file mode 100644
index 0000000..a29f317
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break5.4
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break5.4 251180 2013-05-31 14:45:25Z jilles $
+
+# Although this is not specified by POSIX, some configure scripts (gawk 4.1.0)
+# appear to depend on it.
+# In some uncommitted code, the subshell environment corrupted the outer
+# shell environment's state.
+
+(for i in a b c; do
+ exit 3
+done)
+break
+exit 4
diff --git a/shell_cmds/sh/tests/builtins/break6.0 b/shell_cmds/sh/tests/builtins/break6.0
new file mode 100644
index 0000000..b5fc63b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/break6.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/break6.0 268927 2014-07-20 20:29:09Z jilles $
+# Per POSIX, this need only work if LONG_MAX > 4294967295.
+
+while :; do
+ break 4294967296
+ echo bad
+ exit 3
+done
diff --git a/shell_cmds/sh/tests/builtins/builtin1.0 b/shell_cmds/sh/tests/builtins/builtin1.0
new file mode 100644
index 0000000..dd77422
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/builtin1.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/builtins/builtin1.0 201431 2010-01-03 15:01:38Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+builtin : || echo "Bad return code at $LINENO"
+builtin true || echo "Bad return code at $LINENO"
+builtin ls 2>/dev/null && echo "Bad return code at $LINENO"
+check '"$(builtin pwd)" = "$(pwd)"'
+check '-z "$(builtin :)"'
+check '-z "$(builtin true)"'
+check '-z "$( (builtin nosuchtool) 2>/dev/null)"'
+check '-z "$(builtin nosuchtool 2>/dev/null)"'
+check '-z "$(builtin nosuchtool 2>/dev/null; :)"'
+check '-z "$( (builtin ls) 2>/dev/null)"'
+check '-z "$(builtin ls 2>/dev/null)"'
+check '-z "$(builtin ls 2>/dev/null; :)"'
+check '-n "$( (builtin nosuchtool) 2>&1)"'
+check '-n "$(builtin nosuchtool 2>&1)"'
+check '-n "$(builtin nosuchtool 2>&1; :)"'
+check '-n "$( (builtin ls) 2>&1)"'
+check '-n "$(builtin ls 2>&1)"'
+check '-n "$(builtin ls 2>&1; :)"'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/case1.0 b/shell_cmds/sh/tests/builtins/case1.0
new file mode 100644
index 0000000..b8e8d9b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case1.0
@@ -0,0 +1,13 @@
+#$FreeBSD: head/bin/sh/tests/builtins/case1.0 172440 2007-10-04 16:14:48Z stefanf $
+f()
+{
+ false
+ case $1 in
+ foo) true ;;
+ bar) false ;;
+ esac
+}
+
+f foo || exit 1
+f bar && exit 1
+f quux || exit 1
diff --git a/shell_cmds/sh/tests/builtins/case10.0 b/shell_cmds/sh/tests/builtins/case10.0
new file mode 100644
index 0000000..e8cd933
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case10.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case10.0 223546 2011-06-25 20:37:43Z jilles $
+
+case ! in
+[\!!]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ! in
+['!'!]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ! in
+["!"!]) ;;
+*) echo Failed at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case11.0 b/shell_cmds/sh/tests/builtins/case11.0
new file mode 100644
index 0000000..afcfa43
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case11.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case11.0 228007 2011-11-26 22:28:25Z jilles $
+
+false
+case x in
+*)
+esac
diff --git a/shell_cmds/sh/tests/builtins/case12.0 b/shell_cmds/sh/tests/builtins/case12.0
new file mode 100644
index 0000000..630bee5
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case12.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case12.0 228007 2011-11-26 22:28:25Z jilles $
+
+false
+case x in
+y)
+esac
diff --git a/shell_cmds/sh/tests/builtins/case13.0 b/shell_cmds/sh/tests/builtins/case13.0
new file mode 100644
index 0000000..669ce62
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case13.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case13.0 228943 2011-12-28 23:51:17Z jilles $
+
+case ^ in
+[\^^]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case s in
+[\^^]) echo Failed at $LINENO ;;
+[s\]]) ;;
+*) echo Failed at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case14.0 b/shell_cmds/sh/tests/builtins/case14.0
new file mode 100644
index 0000000..f6a68cb
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case14.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case14.0 230154 2012-01-15 20:04:05Z jilles $
+
+case `false` in
+no) exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case15.0 b/shell_cmds/sh/tests/builtins/case15.0
new file mode 100644
index 0000000..083aaa6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case15.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case15.0 230154 2012-01-15 20:04:05Z jilles $
+
+case x in
+`false`) exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case16.0 b/shell_cmds/sh/tests/builtins/case16.0
new file mode 100644
index 0000000..7031a92
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case16.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case16.0 230154 2012-01-15 20:04:05Z jilles $
+
+f() { return 42; }
+f
+case x in
+x) [ $? = 42 ] ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case17.0 b/shell_cmds/sh/tests/builtins/case17.0
new file mode 100644
index 0000000..10d8d9c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case17.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case17.0 230161 2012-01-15 21:39:38Z jilles $
+
+! case x in x) false ;& y) esac
diff --git a/shell_cmds/sh/tests/builtins/case18.0 b/shell_cmds/sh/tests/builtins/case18.0
new file mode 100644
index 0000000..b0e601f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case18.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case18.0 230161 2012-01-15 21:39:38Z jilles $
+
+case x$(false) in
+x) ;&
+y) [ $? != 0 ] ;;
+z) false ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case19.0 b/shell_cmds/sh/tests/builtins/case19.0
new file mode 100644
index 0000000..1a9b09a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case19.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case19.0 230161 2012-01-15 21:39:38Z jilles $
+
+[ "`case x in
+x) false ;&
+y) ;&
+z) echo $? ;;
+esac`" != 0 ]
diff --git a/shell_cmds/sh/tests/builtins/case2.0 b/shell_cmds/sh/tests/builtins/case2.0
new file mode 100644
index 0000000..ae3f356
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case2.0
@@ -0,0 +1,106 @@
+# Generated by ./test-fnmatch -s 1, do not edit.
+# $FreeBSD: head/bin/sh/tests/builtins/case2.0 207821 2010-05-09 16:15:40Z jilles $
+failures=
+failed() { printf '%s\n' "Failed: $1 '$2' '$3'"; failures=x$failures; }
+testmatch() { eval "case \$2 in ''$1) ;; *) failed testmatch \"\$@\";; esac"; }
+testnomatch() { eval "case \$2 in ''$1) failed testnomatch \"\$@\";; esac"; }
+testmatch '' ''
+testmatch 'a' 'a'
+testnomatch 'a' 'b'
+testnomatch 'a' 'A'
+testmatch '*' 'a'
+testmatch '*' 'aa'
+testmatch '*a' 'a'
+testnomatch '*a' 'b'
+testnomatch '*a*' 'b'
+testmatch '*a*b*' 'ab'
+testmatch '*a*b*' 'qaqbq'
+testmatch '*a*bb*' 'qaqbqbbq'
+testmatch '*a*bc*' 'qaqbqbcq'
+testmatch '*a*bb*' 'qaqbqbb'
+testmatch '*a*bc*' 'qaqbqbc'
+testmatch '*a*bb' 'qaqbqbb'
+testmatch '*a*bc' 'qaqbqbc'
+testnomatch '*a*bb' 'qaqbqbbq'
+testnomatch '*a*bc' 'qaqbqbcq'
+testnomatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaa'
+testmatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaaa'
+testmatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaaaa'
+testnomatch '.*.*.*.*.*.*.*.*.*.*' '.........'
+testmatch '.*.*.*.*.*.*.*.*.*.*' '..........'
+testmatch '.*.*.*.*.*.*.*.*.*.*' '...........'
+testnomatch '*?*?*?*?*?*?*?*?*?*?*' '123456789'
+testnomatch '??????????*' '123456789'
+testnomatch '*??????????' '123456789'
+testmatch '*?*?*?*?*?*?*?*?*?*?*' '1234567890'
+testmatch '??????????*' '1234567890'
+testmatch '*??????????' '1234567890'
+testmatch '*?*?*?*?*?*?*?*?*?*?*' '12345678901'
+testmatch '??????????*' '12345678901'
+testmatch '*??????????' '12345678901'
+testmatch '[x]' 'x'
+testmatch '[*]' '*'
+testmatch '[?]' '?'
+testmatch '[' '['
+testmatch '[[]' '['
+testnomatch '[[]' 'x'
+testnomatch '[*]' ''
+testnomatch '[*]' 'x'
+testnomatch '[?]' 'x'
+testmatch '*[*]*' 'foo*foo'
+testnomatch '*[*]*' 'foo'
+testmatch '[0-9]' '0'
+testmatch '[0-9]' '5'
+testmatch '[0-9]' '9'
+testnomatch '[0-9]' '/'
+testnomatch '[0-9]' ':'
+testnomatch '[0-9]' '*'
+testnomatch '[!0-9]' '0'
+testnomatch '[!0-9]' '5'
+testnomatch '[!0-9]' '9'
+testmatch '[!0-9]' '/'
+testmatch '[!0-9]' ':'
+testmatch '[!0-9]' '*'
+testmatch '*[0-9]' 'a0'
+testmatch '*[0-9]' 'a5'
+testmatch '*[0-9]' 'a9'
+testnomatch '*[0-9]' 'a/'
+testnomatch '*[0-9]' 'a:'
+testnomatch '*[0-9]' 'a*'
+testnomatch '*[!0-9]' 'a0'
+testnomatch '*[!0-9]' 'a5'
+testnomatch '*[!0-9]' 'a9'
+testmatch '*[!0-9]' 'a/'
+testmatch '*[!0-9]' 'a:'
+testmatch '*[!0-9]' 'a*'
+testmatch '*[0-9]' 'a00'
+testmatch '*[0-9]' 'a55'
+testmatch '*[0-9]' 'a99'
+testmatch '*[0-9]' 'a0a0'
+testmatch '*[0-9]' 'a5a5'
+testmatch '*[0-9]' 'a9a9'
+testmatch '\*' '*'
+testmatch '\?' '?'
+testmatch '\[x]' '[x]'
+testmatch '\[' '['
+testmatch '\\' '\'
+testmatch '*\**' 'foo*foo'
+testnomatch '*\**' 'foo'
+testmatch '*\\*' 'foo\foo'
+testnomatch '*\\*' 'foo'
+testmatch '\(' '('
+testmatch '\a' 'a'
+testnomatch '\*' 'a'
+testnomatch '\?' 'a'
+testnomatch '\*' '\*'
+testnomatch '\?' '\?'
+testnomatch '\[x]' '\[x]'
+testnomatch '\[x]' '\x'
+testnomatch '\[' '\['
+testnomatch '\(' '\('
+testnomatch '\a' '\a'
+testmatch '.*' '.'
+testmatch '.*' '..'
+testmatch '.*' '.a'
+testmatch 'a*' 'a.'
+[ -z "$failures" ]
diff --git a/shell_cmds/sh/tests/builtins/case20.0 b/shell_cmds/sh/tests/builtins/case20.0
new file mode 100644
index 0000000..bd91e5b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case20.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case20.0 287148 2015-08-25 21:55:15Z jilles $
+
+# Shells do not agree about what this pattern should match, but it is
+# certain that it must not crash and the missing close bracket must not
+# be simply ignored.
+
+case B in
+[[:alpha:]) echo bad ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case21.0 b/shell_cmds/sh/tests/builtins/case21.0
new file mode 100644
index 0000000..7d865f0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case21.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case21.0 318258 2017-05-13 20:28:32Z jilles $
+
+case 5 in
+[0$((-9))]) ;;
+*) echo bad1 ;;
+esac
+
+case - in
+[0$((-9))]) echo bad2 ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case22.0 b/shell_cmds/sh/tests/builtins/case22.0
new file mode 100644
index 0000000..a89c0bd
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case22.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case22.0 318269 2017-05-14 13:14:19Z jilles $
+
+case 5 in
+[0"$((-9))"]) echo bad1 ;;
+esac
+
+case - in
+[0"$((-9))"]) ;;
+*) echo bad2 ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case3.0 b/shell_cmds/sh/tests/builtins/case3.0
new file mode 100644
index 0000000..a2efd87
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case3.0
@@ -0,0 +1,95 @@
+# Generated by ./test-fnmatch -s 2, do not edit.
+# $FreeBSD: head/bin/sh/tests/builtins/case3.0 207821 2010-05-09 16:15:40Z jilles $
+failures=
+failed() { printf '%s\n' "Failed: $1 '$2' '$3'"; failures=x$failures; }
+# We do not treat a backslash specially in this case,
+# but this is not the case in all shells.
+netestmatch() { case $2 in $1) ;; *) failed netestmatch "$@";; esac; }
+netestnomatch() { case $2 in $1) failed netestnomatch "$@";; esac; }
+netestmatch '' ''
+netestmatch 'a' 'a'
+netestnomatch 'a' 'b'
+netestnomatch 'a' 'A'
+netestmatch '*' 'a'
+netestmatch '*' 'aa'
+netestmatch '*a' 'a'
+netestnomatch '*a' 'b'
+netestnomatch '*a*' 'b'
+netestmatch '*a*b*' 'ab'
+netestmatch '*a*b*' 'qaqbq'
+netestmatch '*a*bb*' 'qaqbqbbq'
+netestmatch '*a*bc*' 'qaqbqbcq'
+netestmatch '*a*bb*' 'qaqbqbb'
+netestmatch '*a*bc*' 'qaqbqbc'
+netestmatch '*a*bb' 'qaqbqbb'
+netestmatch '*a*bc' 'qaqbqbc'
+netestnomatch '*a*bb' 'qaqbqbbq'
+netestnomatch '*a*bc' 'qaqbqbcq'
+netestnomatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaa'
+netestmatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaaa'
+netestmatch '*a*a*a*a*a*a*a*a*a*a*' 'aaaaaaaaaaa'
+netestnomatch '.*.*.*.*.*.*.*.*.*.*' '.........'
+netestmatch '.*.*.*.*.*.*.*.*.*.*' '..........'
+netestmatch '.*.*.*.*.*.*.*.*.*.*' '...........'
+netestnomatch '*?*?*?*?*?*?*?*?*?*?*' '123456789'
+netestnomatch '??????????*' '123456789'
+netestnomatch '*??????????' '123456789'
+netestmatch '*?*?*?*?*?*?*?*?*?*?*' '1234567890'
+netestmatch '??????????*' '1234567890'
+netestmatch '*??????????' '1234567890'
+netestmatch '*?*?*?*?*?*?*?*?*?*?*' '12345678901'
+netestmatch '??????????*' '12345678901'
+netestmatch '*??????????' '12345678901'
+netestmatch '[x]' 'x'
+netestmatch '[*]' '*'
+netestmatch '[?]' '?'
+netestmatch '[' '['
+netestmatch '[[]' '['
+netestnomatch '[[]' 'x'
+netestnomatch '[*]' ''
+netestnomatch '[*]' 'x'
+netestnomatch '[?]' 'x'
+netestmatch '*[*]*' 'foo*foo'
+netestnomatch '*[*]*' 'foo'
+netestmatch '[0-9]' '0'
+netestmatch '[0-9]' '5'
+netestmatch '[0-9]' '9'
+netestnomatch '[0-9]' '/'
+netestnomatch '[0-9]' ':'
+netestnomatch '[0-9]' '*'
+netestnomatch '[!0-9]' '0'
+netestnomatch '[!0-9]' '5'
+netestnomatch '[!0-9]' '9'
+netestmatch '[!0-9]' '/'
+netestmatch '[!0-9]' ':'
+netestmatch '[!0-9]' '*'
+netestmatch '*[0-9]' 'a0'
+netestmatch '*[0-9]' 'a5'
+netestmatch '*[0-9]' 'a9'
+netestnomatch '*[0-9]' 'a/'
+netestnomatch '*[0-9]' 'a:'
+netestnomatch '*[0-9]' 'a*'
+netestnomatch '*[!0-9]' 'a0'
+netestnomatch '*[!0-9]' 'a5'
+netestnomatch '*[!0-9]' 'a9'
+netestmatch '*[!0-9]' 'a/'
+netestmatch '*[!0-9]' 'a:'
+netestmatch '*[!0-9]' 'a*'
+netestmatch '*[0-9]' 'a00'
+netestmatch '*[0-9]' 'a55'
+netestmatch '*[0-9]' 'a99'
+netestmatch '*[0-9]' 'a0a0'
+netestmatch '*[0-9]' 'a5a5'
+netestmatch '*[0-9]' 'a9a9'
+netestmatch '\*' '\*'
+netestmatch '\?' '\?'
+netestmatch '\' '\'
+netestnomatch '\\' '\'
+netestmatch '\\' '\\'
+netestmatch '*\*' 'foo\foo'
+netestnomatch '*\*' 'foo'
+netestmatch '.*' '.'
+netestmatch '.*' '..'
+netestmatch '.*' '.a'
+netestmatch 'a*' 'a.'
+[ -z "$failures" ]
diff --git a/shell_cmds/sh/tests/builtins/case4.0 b/shell_cmds/sh/tests/builtins/case4.0
new file mode 100644
index 0000000..7ba29ee
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case4.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case4.0 220654 2011-04-15 15:14:58Z jilles $
+
+set -- "*"
+case x in
+"$1") echo failed ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case5.0 b/shell_cmds/sh/tests/builtins/case5.0
new file mode 100644
index 0000000..e8b141a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case5.0
@@ -0,0 +1,57 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case5.0 221646 2011-05-08 11:32:20Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.UTF-8
+export LC_CTYPE
+
+c1=e
+# a umlaut
+c2=$(printf '\303\244')
+# euro sign
+c3=$(printf '\342\202\254')
+# some sort of 't' outside BMP
+c4=$(printf '\360\235\225\245')
+
+ok=0
+case $c1$c2$c3$c4 in
+*) ok=1 ;;
+esac
+if [ $ok = 0 ]; then
+ echo wrong at $LINENO
+ exit 3
+fi
+
+case $c1$c2$c3$c4 in
+$c1$c2$c3$c4) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+"$c1$c2$c3$c4") ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+????) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1.$c2.$c3.$c4 in
+?.?.?.?) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+[!a][!b][!c][!d]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+[$c1][$c2][$c3][$c4]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+["$c1"]["$c2"]["$c3"]["$c4"]) ;;
+*) echo wrong at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case6.0 b/shell_cmds/sh/tests/builtins/case6.0
new file mode 100644
index 0000000..7bc1da8
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case6.0
@@ -0,0 +1,52 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case6.0 223007 2011-06-12 12:27:17Z jilles $
+
+unset LC_ALL
+LC_CTYPE=de_DE.ISO8859-1
+export LC_CTYPE
+
+c1=e
+# o umlaut
+c2=$(printf '\366')
+# non-break space
+c3=$(printf '\240')
+c4=$(printf '\240')
+# $c2$c3$c4 form one utf-8 character
+
+ok=0
+case $c1$c2$c3$c4 in
+*) ok=1 ;;
+esac
+if [ $ok = 0 ]; then
+ echo wrong at $LINENO
+ exit 3
+fi
+
+case $c1$c2$c3$c4 in
+$c1$c2$c3$c4) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+"$c1$c2$c3$c4") ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+????) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+[!$c2][!b][!c][!d]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+[$c1][$c2][$c3][$c4]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2$c3$c4 in
+["$c1"]["$c2"]["$c3"]["$c4"]) ;;
+*) echo wrong at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case7.0 b/shell_cmds/sh/tests/builtins/case7.0
new file mode 100644
index 0000000..b351ad5
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case7.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case7.0 302829 2016-07-14 09:34:42Z ache $
+
+# Character ranges in a locale other than the POSIX locale, not specified
+# by POSIX.
+
+unset LC_ALL
+LC_CTYPE=de_DE.ISO8859-1
+export LC_CTYPE
+LC_COLLATE=de_DE.ISO8859-1
+export LC_COLLATE
+
+c1=e
+# o umlaut
+c2=$(printf '\366')
+
+case $c1$c2 in
+[a-z][a-z]) ;;
+*) echo wrong at $LINENO ;;
+esac
+
+case $c1$c2 in
+[a-f][n-p]) ;;
+*) echo wrong at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case8.0 b/shell_cmds/sh/tests/builtins/case8.0
new file mode 100644
index 0000000..c63c6e7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case8.0
@@ -0,0 +1,32 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case8.0 223120 2011-06-15 21:48:10Z jilles $
+
+case aZ_ in
+[[:alpha:]_][[:upper:]_][[:alpha:]_]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ' ' in
+[[:alpha:][:digit:]]) echo Failed at $LINENO ;;
+[![:alpha:][:digit:]]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case '.X.' in
+*[[:lower:]]*) echo Failed at $LINENO ;;
+*[[:upper:]]*) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case ' ' in
+[![:print:]]) echo Failed at $LINENO ;;
+[![:alnum:][:punct:]]) ;;
+*) echo Failed at $LINENO ;;
+esac
+
+case '
+' in
+[[:print:]]) echo Failed at $LINENO ;;
+['
+'[:digit:]]) ;;
+*) echo Failed at $LINENO ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/case9.0 b/shell_cmds/sh/tests/builtins/case9.0
new file mode 100644
index 0000000..e374ef0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/case9.0
@@ -0,0 +1,39 @@
+# $FreeBSD: head/bin/sh/tests/builtins/case9.0 223186 2011-06-17 13:03:49Z jilles $
+
+errors=0
+
+f() {
+ result=
+ case $1 in
+ a) result=${result}a ;;
+ b) result=${result}b ;&
+ c) result=${result}c ;&
+ d) result=${result}d ;;
+ e) result=${result}e ;&
+ esac
+}
+
+check() {
+ f "$1"
+ if [ "$result" != "$2" ]; then
+ printf "For %s, expected %s got %s\n" "$1" "$2" "$result"
+ errors=$((errors + 1))
+ fi
+}
+
+check '' ''
+check a a
+check b bcd
+check c cd
+check d d
+check e e
+
+if ! (case 1 in
+ 1) false ;&
+ 2) true ;;
+esac) then
+ echo "Subshell bad"
+ errors=$((errors + 1))
+fi
+
+exit $((errors != 0))
diff --git a/shell_cmds/sh/tests/builtins/cd1.0 b/shell_cmds/sh/tests/builtins/cd1.0
new file mode 100644
index 0000000..d797157
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd1.0
@@ -0,0 +1,30 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd1.0 228975 2011-12-30 00:04:11Z uqs $
+set -e
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+
+chmod 0 $T
+if [ `id -u` -ne 0 ]; then
+ # Root can always cd, regardless of directory permissions.
+ cd -L $T 2>/dev/null && exit 1
+ [ "$PWD" = "$P" ]
+ [ "$(pwd)" = "$P" ]
+ cd -P $T 2>/dev/null && exit 1
+ [ "$PWD" = "$P" ]
+ [ "$(pwd)" = "$P" ]
+fi
+
+chmod 755 $T
+cd $T
+mkdir -p 1/2/3
+ln -s 1/2 link1
+ln -s 2/3 1/link2
+(cd -L 1/../1 && [ "$(pwd -L)" = "$P/$T/1" ])
+(cd -L link1 && [ "$(pwd -L)" = "$P/$T/link1" ])
+(cd -L link1 && [ "$(pwd -P)" = "$P/$T/1/2" ])
+(cd -P link1 && [ "$(pwd -L)" = "$P/$T/1/2" ])
+(cd -P link1 && [ "$(pwd -P)" = "$P/$T/1/2" ])
+
+rm -rf ${P}/${T}
diff --git a/shell_cmds/sh/tests/builtins/cd10.0 b/shell_cmds/sh/tests/builtins/cd10.0
new file mode 100644
index 0000000..79d540f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd10.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd10.0 320340 2017-06-25 21:53:08Z jilles $
+
+# Precondition
+(cd /bin) || exit
+# Verify write error is ignored.
+$SH +m -ic 'CDPATH=/:; cd bin 1</dev/null'
diff --git a/shell_cmds/sh/tests/builtins/cd2.0 b/shell_cmds/sh/tests/builtins/cd2.0
new file mode 100644
index 0000000..b7d39f3
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd2.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd2.0 216019 2010-11-28 22:49:58Z jilles $
+set -e
+
+L=$(getconf PATH_MAX / 2>/dev/null) || L=4096
+[ "$L" -lt 100000 ] 2>/dev/null || L=4096
+L=$((L+100))
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf ${T}' 0
+cd $T
+D=$T
+while [ ${#D} -lt $L ]; do
+ mkdir veryverylongdirectoryname
+ cd veryverylongdirectoryname
+ D=$D/veryverylongdirectoryname
+done
+[ $(pwd | wc -c) -eq $((${#D} + 1)) ] # +\n
diff --git a/shell_cmds/sh/tests/builtins/cd3.0 b/shell_cmds/sh/tests/builtins/cd3.0
new file mode 100644
index 0000000..aab8bc0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd3.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd3.0 222154 2011-05-20 22:55:18Z jilles $
+
+# If fully successful, cd -Pe must be like cd -P.
+
+set -e
+
+cd "${TMPDIR:-/tmp}"
+cd -Pe /
+[ "$PWD" = / ]
+[ "$(pwd)" = / ]
+cd "${TMPDIR:-/tmp}"
+cd -eP /
+[ "$PWD" = / ]
+[ "$(pwd)" = / ]
+
+set +e
+
+# If cd -Pe cannot chdir, the exit status must be greater than 1.
+
+v=$( (cd -Pe /var/empty/nonexistent) 2>&1 >/dev/null)
+[ $? -gt 1 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/builtins/cd4.0 b/shell_cmds/sh/tests/builtins/cd4.0
new file mode 100644
index 0000000..da01b31
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd4.0
@@ -0,0 +1,38 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd4.0 222154 2011-05-20 22:55:18Z jilles $
+
+# This test assumes that whatever mechanism cd -P uses to determine the
+# pathname to the current directory if it is longer than PATH_MAX requires
+# read permission on all parent directories. It also works if this
+# requirement always applies.
+
+set -e
+L=$(getconf PATH_MAX / 2>/dev/null) || L=4096
+[ "$L" -lt 100000 ] 2>/dev/null || L=4096
+L=$((L+100))
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'chmod u+r ${T}; rm -rf ${T}' 0
+cd -Pe $T
+D=$(pwd)
+chmod u-r "$D"
+if [ -r "$D" ]; then
+ # Running as root, cannot test.
+ exit 0
+fi
+set +e
+while [ ${#D} -lt $L ]; do
+ mkdir veryverylongdirectoryname || exit
+ cd -Pe veryverylongdirectoryname 2>/dev/null
+ r=$?
+ [ $r -gt 1 ] && exit $r
+ if [ $r -eq 1 ]; then
+ # Verify that the directory was changed correctly.
+ cd -Pe .. || exit
+ [ "$(pwd)" = "$D" ] || exit
+ # Verify that omitting -e results in success.
+ cd -P veryverylongdirectoryname 2>/dev/null || exit
+ exit 0
+ fi
+ D=$D/veryverylongdirectoryname
+done
+echo "cd -Pe never returned 1"
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/cd5.0 b/shell_cmds/sh/tests/builtins/cd5.0
new file mode 100644
index 0000000..8a285e0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd5.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd5.0 222379 2011-05-27 19:36:07Z jilles $
+
+set -e
+T=$(mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXX")
+trap 'rm -rf "$T"' 0
+
+cd -P "$T"
+D=$(pwd)
+
+mkdir a a/1 b b/1 b/2
+
+CDPATH=$D/a:
+# Basic test.
+cd 1 >/dev/null
+[ "$(pwd)" = "$D/a/1" ]
+# Test that the current directory is not checked before CDPATH.
+cd "$D/b"
+cd 1 >/dev/null
+[ "$(pwd)" = "$D/a/1" ]
+# Test not using a CDPATH entry.
+cd "$D/b"
+cd 2
+[ "$(pwd)" = "$D/b/2" ]
diff --git a/shell_cmds/sh/tests/builtins/cd6.0 b/shell_cmds/sh/tests/builtins/cd6.0
new file mode 100644
index 0000000..171c996
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd6.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd6.0 222381 2011-05-27 20:01:46Z jilles $
+
+set -e
+cd -P /bin
+d=$PWD
+CDPATH=/:
+cd -P .
+[ "$d" = "$PWD" ]
+cd -P ./
+[ "$d" = "$PWD" ]
diff --git a/shell_cmds/sh/tests/builtins/cd7.0 b/shell_cmds/sh/tests/builtins/cd7.0
new file mode 100644
index 0000000..d4cae39
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd7.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd7.0 222381 2011-05-27 20:01:46Z jilles $
+
+set -e
+cd /usr/bin
+[ "$PWD" = /usr/bin ]
+CDPATH=/:
+cd .
+[ "$PWD" = /usr/bin ]
+cd ./
+[ "$PWD" = /usr/bin ]
+cd ..
+[ "$PWD" = /usr ]
+cd /usr/bin
+cd ../
+[ "$PWD" = /usr ]
diff --git a/shell_cmds/sh/tests/builtins/cd8.0 b/shell_cmds/sh/tests/builtins/cd8.0
new file mode 100644
index 0000000..ab17d38
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd8.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd8.0 230095 2012-01-13 23:32:27Z jilles $
+
+# The exact wording of the error message is not standardized, but giving
+# a description of the errno is useful.
+
+LC_ALL=C
+export LC_ALL
+r=0
+
+t() {
+ exec 3>&1
+ errmsg=`cd "$1" 2>&1 >&3 3>&-`
+ exec 3>&-
+ case $errmsg in
+ *[Nn]ot\ a\ directory*)
+ ;;
+ *)
+ printf "Wrong error message for %s: %s\n" "$1" "$errmsg"
+ r=3
+ ;;
+ esac
+}
+
+t /dev/tty
+t /dev/tty/x
+exit $r
diff --git a/shell_cmds/sh/tests/builtins/cd9.0 b/shell_cmds/sh/tests/builtins/cd9.0
new file mode 100644
index 0000000..e929878
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd9.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/cd9.0 293371 2016-01-07 21:46:07Z jilles $
+
+cd /dev
+cd /bin
+cd - >/dev/null
+pwd
+cd - >/dev/null
+pwd
diff --git a/shell_cmds/sh/tests/builtins/cd9.0.stdout b/shell_cmds/sh/tests/builtins/cd9.0.stdout
new file mode 100644
index 0000000..dac16a7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/cd9.0.stdout
@@ -0,0 +1,2 @@
+/dev
+/bin
diff --git a/shell_cmds/sh/tests/builtins/command1.0 b/shell_cmds/sh/tests/builtins/command1.0
new file mode 100644
index 0000000..5454c3f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command1.0 151797 2005-10-28 14:02:42Z stefanf $
+true() {
+ false
+}
+command true
diff --git a/shell_cmds/sh/tests/builtins/command10.0 b/shell_cmds/sh/tests/builtins/command10.0
new file mode 100644
index 0000000..08bddaf
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command10.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command10.0 204802 2010-03-06 17:31:09Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(f() { shift x; }; { command eval f 2>/dev/null; } >/dev/null; echo hi)" = hi'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/command11.0 b/shell_cmds/sh/tests/builtins/command11.0
new file mode 100644
index 0000000..0eb2047
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command11.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command11.0 205154 2010-03-14 14:24:35Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$({ command eval \{ shift x\; \} 2\>/dev/null; } >/dev/null; echo hi)" = hi'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/command12.0 b/shell_cmds/sh/tests/builtins/command12.0
new file mode 100644
index 0000000..6d9e8e7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command12.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command12.0 257929 2013-11-10 23:00:39Z jilles $
+
+alias aa=echo\ \'\"\'
+cmd=$(command -v aa)
+alias aa=echo\ bad
+eval "$cmd"
+[ "$(eval aa)" = \" ]
diff --git a/shell_cmds/sh/tests/builtins/command2.0 b/shell_cmds/sh/tests/builtins/command2.0
new file mode 100644
index 0000000..7b49092
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command2.0 151797 2005-10-28 14:02:42Z stefanf $
+PATH=
+command -p cat < /dev/null
diff --git a/shell_cmds/sh/tests/builtins/command3.0 b/shell_cmds/sh/tests/builtins/command3.0
new file mode 100644
index 0000000..6d6355d
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command3.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command3.0 211399 2010-08-16 17:18:08Z jilles $
+command -v ls
+command -v true
+command -v /bin/ls
+
+fun() {
+ :
+}
+command -v fun
+command -v break
+command -v if
+
+alias foo=bar
+command -v foo
diff --git a/shell_cmds/sh/tests/builtins/command3.0.stdout b/shell_cmds/sh/tests/builtins/command3.0.stdout
new file mode 100644
index 0000000..67b8691
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command3.0.stdout
@@ -0,0 +1,7 @@
+/bin/ls
+true
+/bin/ls
+fun
+break
+if
+alias foo=bar
diff --git a/shell_cmds/sh/tests/builtins/command4.0 b/shell_cmds/sh/tests/builtins/command4.0
new file mode 100644
index 0000000..2349669
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command4.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command4.0 211973 2010-08-29 20:53:24Z jilles $
+! command -v nonexisting
diff --git a/shell_cmds/sh/tests/builtins/command5.0 b/shell_cmds/sh/tests/builtins/command5.0
new file mode 100644
index 0000000..7c99b52
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command5.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command5.0 211399 2010-08-16 17:18:08Z jilles $
+command -V ls
+command -V true
+command -V /bin/ls
+
+fun() {
+ :
+}
+command -V fun
+command -V break
+command -V if
+command -V {
+
+alias foo=bar
+command -V foo
diff --git a/shell_cmds/sh/tests/builtins/command5.0.stdout b/shell_cmds/sh/tests/builtins/command5.0.stdout
new file mode 100644
index 0000000..523f7b2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command5.0.stdout
@@ -0,0 +1,8 @@
+ls is /bin/ls
+true is a shell builtin
+/bin/ls is /bin/ls
+fun is a shell function
+break is a special shell builtin
+if is a shell keyword
+{ is a shell keyword
+foo is an alias for bar
diff --git a/shell_cmds/sh/tests/builtins/command6.0 b/shell_cmds/sh/tests/builtins/command6.0
new file mode 100644
index 0000000..d1902ed
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command6.0
@@ -0,0 +1,22 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command6.0 218356 2011-02-05 23:00:24Z jilles $
+PATH=/var/empty
+case $(command -pV ls) in
+*/var/empty/ls*)
+ echo "Failed: \$(command -pV ls) should not match */var/empty/ls*" ;;
+"ls is"*" "/*/ls) ;;
+*)
+ echo "Failed: \$(command -pV ls) match \"ls is\"*\" \"/*/ls" ;;
+esac
+command -pV true
+command -pV /bin/ls
+
+fun() {
+ :
+}
+command -pV fun
+command -pV break
+command -pV if
+command -pV {
+
+alias foo=bar
+command -pV foo
diff --git a/shell_cmds/sh/tests/builtins/command6.0.stdout b/shell_cmds/sh/tests/builtins/command6.0.stdout
new file mode 100644
index 0000000..3180207
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command6.0.stdout
@@ -0,0 +1,7 @@
+true is a shell builtin
+/bin/ls is /bin/ls
+fun is a shell function
+break is a special shell builtin
+if is a shell keyword
+{ is a shell keyword
+foo is an alias for bar
diff --git a/shell_cmds/sh/tests/builtins/command7.0 b/shell_cmds/sh/tests/builtins/command7.0
new file mode 100644
index 0000000..b8351f2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command7.0
@@ -0,0 +1,34 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command7.0 218356 2011-02-05 23:00:24Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(PATH=/libexec command -V ld-elf.so.1)" = "ld-elf.so.1 is /libexec/ld-elf.so.1"'
+check '"$(PATH=/libexec command -V ld-elf.so.1; :)" = "ld-elf.so.1 is /libexec/ld-elf.so.1"'
+check '"$(PATH=/libexec command -pv ld-elf.so.1)" = ""'
+check '"$(PATH=/libexec command -pv ld-elf.so.1; :)" = ""'
+
+PATH=/libexec:$PATH
+
+check '"$(command -V ld-elf.so.1)" = "ld-elf.so.1 is /libexec/ld-elf.so.1"'
+check '"$(command -V ld-elf.so.1; :)" = "ld-elf.so.1 is /libexec/ld-elf.so.1"'
+check '"$(command -pv ld-elf.so.1)" = ""'
+check '"$(command -pv ld-elf.so.1; :)" = ""'
+
+PATH=/libexec
+
+check '"$(command -v ls)" = ""'
+case $(command -pv ls) in
+/*/ls) ;;
+*)
+ echo "Failed: \$(command -pv ls) match /*/ls"
+ : $((failures += 1)) ;;
+esac
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/command8.0 b/shell_cmds/sh/tests/builtins/command8.0
new file mode 100644
index 0000000..54848d1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command8.0
@@ -0,0 +1,45 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command8.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,\
+ eval,\
+ exec,\
+ export -p,\
+ readonly -p,\
+ set,\
+ shift 0,\
+ times,\
+ trap,\
+ unset foo"
+
+set -e
+
+# Check that special builtins can be executed via "command".
+
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "v=:; while \$v; do v=false; command ${cmd}; done" >/dev/null
+done
+
+while :; do
+ command break
+ echo Error on line $LINENO
+done
+
+set p q r
+command shift 2
+if [ $# -ne 1 ]; then
+ echo Error on line $LINENO
+fi
+
+(
+ command exec >/dev/null
+ echo Error on line $LINENO
+)
+
+set +e
+! command shift 2 2>/dev/null
diff --git a/shell_cmds/sh/tests/builtins/command9.0 b/shell_cmds/sh/tests/builtins/command9.0
new file mode 100644
index 0000000..40f98c1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/command9.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/builtins/command9.0 204801 2010-03-06 17:09:22Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$({ command eval shift x 2>/dev/null; } >/dev/null; echo hi)" = hi'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/dot1.0 b/shell_cmds/sh/tests/builtins/dot1.0
new file mode 100644
index 0000000..0aa69a8
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/dot1.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/dot1.0 208629 2010-05-28 22:08:34Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX) || exit
+trap 'rm -rf $T' 0
+cd $T || exit 3
+unset x
+echo 'x=2' >testscript
+. ./testscript
+[ "$x" = 2 ] || failure $LINENO
+cd / || exit 3
+x=1
+PATH=$T:$PATH . testscript
+[ "$x" = 2 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/dot2.0 b/shell_cmds/sh/tests/builtins/dot2.0
new file mode 100644
index 0000000..dba591e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/dot2.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/dot2.0 208630 2010-05-28 22:40:24Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX) || exit
+trap 'rm -rf $T' 0
+cd $T || exit 3
+unset x
+echo 'x=2' >testscript
+. -- ./testscript
+[ "$x" = 2 ] || failure $LINENO
+cd / || exit 3
+x=1
+PATH=$T:$PATH . -- testscript
+[ "$x" = 2 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/dot3.0 b/shell_cmds/sh/tests/builtins/dot3.0
new file mode 100644
index 0000000..d1589a0
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/dot3.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/dot3.0 219390 2011-03-07 23:52:23Z jilles $
+
+# . should return 0 if no command was executed.
+
+if false; then
+ exit 3
+else
+ . /dev/null
+ exit $?
+fi
diff --git a/shell_cmds/sh/tests/builtins/dot4.0 b/shell_cmds/sh/tests/builtins/dot4.0
new file mode 100644
index 0000000..d280f35
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/dot4.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/dot4.0 222174 2011-05-22 12:15:14Z jilles $
+
+v=abcd
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+r=$( (
+ trap 'exit 0' 0
+ . "$v"
+) 2>&1 >/dev/null) && [ -n "$r" ]
diff --git a/shell_cmds/sh/tests/builtins/echo1.0 b/shell_cmds/sh/tests/builtins/echo1.0
new file mode 100644
index 0000000..34d75a6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/echo1.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/echo1.0 305305 2016-09-02 21:13:46Z jilles $
+
+# Not specified by POSIX.
+
+[ "`echo -n a b; echo c d; echo e f`" = "a bc d
+e f" ]
diff --git a/shell_cmds/sh/tests/builtins/echo2.0 b/shell_cmds/sh/tests/builtins/echo2.0
new file mode 100644
index 0000000..3eae51b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/echo2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/echo2.0 305305 2016-09-02 21:13:46Z jilles $
+
+# Not specified by POSIX.
+
+a=`echo -e '\a\b\e\f\n\r\t\v\\\\\0041\c'; echo .`
+b=`printf '\a\b\033\f\n\r\t\v\\\\!.'`
+[ "$a" = "$b" ]
diff --git a/shell_cmds/sh/tests/builtins/echo3.0 b/shell_cmds/sh/tests/builtins/echo3.0
new file mode 100644
index 0000000..aa86443
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/echo3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/echo3.0 305305 2016-09-02 21:13:46Z jilles $
+
+# Not specified by POSIX.
+
+[ "`echo -e 'a\cb' c; echo d`" = "ad" ]
diff --git a/shell_cmds/sh/tests/builtins/eval1.0 b/shell_cmds/sh/tests/builtins/eval1.0
new file mode 100644
index 0000000..ad099ce
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval1.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval1.0 193178 2009-05-31 17:23:27Z stefanf $
+set -e
+
+eval
+eval "" ""
+eval "true"
+! eval "false
+
+"
diff --git a/shell_cmds/sh/tests/builtins/eval2.0 b/shell_cmds/sh/tests/builtins/eval2.0
new file mode 100644
index 0000000..4df41ea
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval2.0 194897 2009-06-24 20:22:54Z jilles $
+
+eval '
+false
+
+' && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/eval3.0 b/shell_cmds/sh/tests/builtins/eval3.0
new file mode 100644
index 0000000..04f9720
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval3.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval3.0 196607 2009-08-27 22:23:23Z jilles $
+
+eval 'false;' && exit 1
+eval 'true;' || exit 1
+eval 'false;
+' && exit 1
+eval 'true;
+' || exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/eval4.0 b/shell_cmds/sh/tests/builtins/eval4.0
new file mode 100644
index 0000000..82c3ea9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval4.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval4.0 210738 2010-08-01 22:39:07Z jilles $
+
+# eval should preserve $? from command substitutions when starting
+# the parsed command.
+[ $(eval 'echo $?' $(false)) = 1 ]
diff --git a/shell_cmds/sh/tests/builtins/eval5.0 b/shell_cmds/sh/tests/builtins/eval5.0
new file mode 100644
index 0000000..89e79b8
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval5.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval5.0 210829 2010-08-03 22:17:29Z jilles $
+
+# eval should return 0 if no command was executed.
+eval $(false)
diff --git a/shell_cmds/sh/tests/builtins/eval6.0 b/shell_cmds/sh/tests/builtins/eval6.0
new file mode 100644
index 0000000..bfce89f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval6.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval6.0 249220 2013-04-06 22:30:46Z jilles $
+
+# eval should preserve $? from command substitutions when starting
+# the parsed command.
+[ $(false; eval 'echo $?' $(:)) = 0 ]
diff --git a/shell_cmds/sh/tests/builtins/eval7.0 b/shell_cmds/sh/tests/builtins/eval7.0
new file mode 100644
index 0000000..f694e73
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval7.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval7.0 272983 2014-10-12 13:12:06Z jilles $
+# Assumes that break can break out of a loop outside eval.
+
+while :; do
+ eval "break
+echo bad1"
+ echo bad2
+ exit 3
+done
diff --git a/shell_cmds/sh/tests/builtins/eval8.7 b/shell_cmds/sh/tests/builtins/eval8.7
new file mode 100644
index 0000000..30902cc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/eval8.7
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/eval8.7 272983 2014-10-12 13:12:06Z jilles $
+
+f() {
+ eval "return 7
+echo bad2"
+}
+f
diff --git a/shell_cmds/sh/tests/builtins/exec1.0 b/shell_cmds/sh/tests/builtins/exec1.0
new file mode 100644
index 0000000..8c5bb01
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exec1.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exec1.0 213738 2010-10-12 18:20:38Z obrien $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+(
+ exec >/dev/null
+ echo bad
+)
+[ $? = 0 ] || failure $LINENO
+(
+ exec ${SH} -c 'exit 42'
+ echo bad
+)
+[ $? = 42 ] || failure $LINENO
+(
+ exec /var/empty/nosuch
+ echo bad
+) 2>/dev/null
+[ $? = 127 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/exec2.0 b/shell_cmds/sh/tests/builtins/exec2.0
new file mode 100644
index 0000000..5395ba6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exec2.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exec2.0 213738 2010-10-12 18:20:38Z obrien $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+(
+ exec -- >/dev/null
+ echo bad
+)
+[ $? = 0 ] || failure $LINENO
+(
+ exec -- ${SH} -c 'exit 42'
+ echo bad
+)
+[ $? = 42 ] || failure $LINENO
+(
+ exec -- /var/empty/nosuch
+ echo bad
+) 2>/dev/null
+[ $? = 127 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/exit1.0 b/shell_cmds/sh/tests/builtins/exit1.0
new file mode 100644
index 0000000..4c378f2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exit1.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exit1.0 216871 2011-01-01 15:25:15Z jilles $
+
+# exit with an argument should overwrite the exit status in an EXIT trap.
+
+trap 'true; exit $?' 0
+false
diff --git a/shell_cmds/sh/tests/builtins/exit2.8 b/shell_cmds/sh/tests/builtins/exit2.8
new file mode 100644
index 0000000..51d38f7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exit2.8
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exit2.8 217172 2011-01-08 23:00:38Z jilles $
+
+# exit without arguments is the same as exit $? outside a trap.
+
+trap 'true; true' 0
+(exit 8)
+exit
diff --git a/shell_cmds/sh/tests/builtins/exit3.0 b/shell_cmds/sh/tests/builtins/exit3.0
new file mode 100644
index 0000000..4e0c96c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/exit3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/exit3.0 217175 2011-01-08 23:08:13Z jilles $
+
+# exit without arguments differs from exit $? in an EXIT trap.
+
+trap 'false; exit' 0
diff --git a/shell_cmds/sh/tests/builtins/export1.0 b/shell_cmds/sh/tests/builtins/export1.0
new file mode 100644
index 0000000..a09263a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/export1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/export1.0 223183 2011-06-17 10:21:24Z jilles $
+
+env @badness=1 ${SH} -c 'v=`export -p`; eval "$v"'
diff --git a/shell_cmds/sh/tests/builtins/fc1.0 b/shell_cmds/sh/tests/builtins/fc1.0
new file mode 100644
index 0000000..042cb33
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/fc1.0
@@ -0,0 +1,27 @@
+# $FreeBSD: head/bin/sh/tests/builtins/fc1.0 213738 2010-10-12 18:20:38Z obrien $
+set -e
+trap 'echo Broken pipe -- test failed' PIPE
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+mkfifo input output error
+HISTFILE=/dev/null ${SH} +m -i <input >output 2>error &
+{
+ # Syntax error
+ echo ')' >&3
+ # Read error message, shell will read new input now
+ read dummy <&5
+ # Execute bad command again
+ echo 'fc -e true' >&3
+ # Verify that the shell is still running
+ echo 'echo continued' >&3 || rc=3
+ echo 'exit' >&3 || rc=3
+ read line <&4 && [ "$line" = continued ] && : ${rc:=0}
+} 3>input 4<output 5<error
+
+rm input output error
+rmdir ${P}/${T}
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/builtins/fc2.0 b/shell_cmds/sh/tests/builtins/fc2.0
new file mode 100644
index 0000000..a6151f7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/fc2.0
@@ -0,0 +1,34 @@
+# $FreeBSD: head/bin/sh/tests/builtins/fc2.0 213738 2010-10-12 18:20:38Z obrien $
+set -e
+trap 'echo Broken pipe -- test failed' PIPE
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+mkfifo input output error
+HISTFILE=/dev/null ${SH} +m -i <input >output 2>error &
+exec 3>input
+{
+ # Command not found, containing slash
+ echo '/var/empty/nonexistent' >&3
+ # Read error message, shell will read new input now
+ read dummy <&5
+ # Execute bad command again
+ echo 'fc -e true; echo continued' >&3
+ read dummy <&5
+ read line <&4 && [ "$line" = continued ] && : ${rc:=0}
+ exec 3>&-
+ # Old sh duplicates itself after the fc, producing another line
+ # of output.
+ if read line <&4; then
+ echo "Extraneous output: $line"
+ rc=1
+ fi
+} 4<output 5<error
+exec 3>&-
+
+rm input output error
+rmdir ${P}/${T}
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/builtins/for1.0 b/shell_cmds/sh/tests/builtins/for1.0
new file mode 100644
index 0000000..276cb0a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/for1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/for1.0 226892 2011-10-28 23:02:21Z jilles $
+
+false
+for i in `false`; do exit 3; done
diff --git a/shell_cmds/sh/tests/builtins/for2.0 b/shell_cmds/sh/tests/builtins/for2.0
new file mode 100644
index 0000000..2b702ce
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/for2.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/for2.0 230463 2012-01-22 14:00:33Z jilles $
+
+r=x
+f() { return 42; }
+f
+for i in x; do
+ r=$?
+done
+[ "$r" = 42 ]
diff --git a/shell_cmds/sh/tests/builtins/for3.0 b/shell_cmds/sh/tests/builtins/for3.0
new file mode 100644
index 0000000..a345caa
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/for3.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/for3.0 230463 2012-01-22 14:00:33Z jilles $
+
+r=x
+f() { return 42; }
+for i in x`f`; do
+ r=$?
+done
+[ "$r" = 42 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts1.0 b/shell_cmds/sh/tests/builtins/getopts1.0
new file mode 100644
index 0000000..d3e7415
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts1.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts1.0 297752 2016-04-09 16:06:13Z jilles $
+
+printf -- '-1-\n'
+set -- -abc
+getopts "ab:" OPTION
+printf '%s\n' "${OPTION}"
+
+# In this case 'getopts' should realize that we have not provided the
+# required argument for "-b".
+# Note that Solaris 10's (UNIX 03) /usr/xpg4/bin/sh, /bin/sh, and /bin/ksh;
+# ksh93 20090505; pdksh 5.2.14p2; mksh R39c; bash 4.1 PL7; and zsh 4.3.10.
+# all recognize that "b" is missing its argument on the *first* iteration
+# of 'getopts' and do not produce the "a" in $OPTION.
+printf -- '-2-\n'
+set -- -ab
+getopts "ab:" OPTION
+printf '%s\n' "${OPTION}"
+getopts "ab:" OPTION 3>&2 2>&1 >&3 3>&-
+printf '%s\n' "${OPTION}"
+
+# The 'shift' is aimed at causing an error.
+printf -- '-3-\n'
+shift 1
+getopts "ab:" OPTION
+printf '%s\n' "${OPTION}"
diff --git a/shell_cmds/sh/tests/builtins/getopts1.0.stdout b/shell_cmds/sh/tests/builtins/getopts1.0.stdout
new file mode 100644
index 0000000..a0a347e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts1.0.stdout
@@ -0,0 +1,8 @@
+-1-
+a
+-2-
+a
+No arg for -b option
+?
+-3-
+?
diff --git a/shell_cmds/sh/tests/builtins/getopts10.0 b/shell_cmds/sh/tests/builtins/getopts10.0
new file mode 100644
index 0000000..7d34ddc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts10.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts10.0 293359 2016-01-07 20:48:24Z jilles $
+
+set -- -x arg
+opt=not
+getopts x opt
+r1=$? OPTIND1=$OPTIND opt1=$opt
+: $(: $((OPTIND = 1)))
+getopts x opt
+r2=$? OPTIND2=$OPTIND
+[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] &&
+ [ "$OPTIND2" = 2 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts2.0 b/shell_cmds/sh/tests/builtins/getopts2.0
new file mode 100644
index 0000000..607d35e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts2.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts2.0 297752 2016-04-09 16:06:13Z jilles $
+set - -ax
+getopts ax option
+set -C
+getopts ax option
+printf '%s\n' "$option"
diff --git a/shell_cmds/sh/tests/builtins/getopts2.0.stdout b/shell_cmds/sh/tests/builtins/getopts2.0.stdout
new file mode 100644
index 0000000..587be6b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts2.0.stdout
@@ -0,0 +1 @@
+x
diff --git a/shell_cmds/sh/tests/builtins/getopts3.0 b/shell_cmds/sh/tests/builtins/getopts3.0
new file mode 100644
index 0000000..6087d73
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts3.0 265616 2014-05-07 21:45:25Z jilles $
+
+shift $#
+getopts x opt
+r=$?
+[ "$r" != 0 ] && [ "$OPTIND" = 1 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts4.0 b/shell_cmds/sh/tests/builtins/getopts4.0
new file mode 100644
index 0000000..ea8cc3f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts4.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts4.0 265616 2014-05-07 21:45:25Z jilles $
+
+set -- -x
+opt=not
+getopts x opt
+r1=$? OPTIND1=$OPTIND opt1=$opt
+getopts x opt
+r2=$? OPTIND2=$OPTIND
+[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] &&
+ [ "$OPTIND2" = 2 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts5.0 b/shell_cmds/sh/tests/builtins/getopts5.0
new file mode 100644
index 0000000..cd4eca6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts5.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts5.0 265616 2014-05-07 21:45:25Z jilles $
+
+set -- -x arg
+opt=not
+getopts x opt
+r1=$? OPTIND1=$OPTIND opt1=$opt
+getopts x opt
+r2=$? OPTIND2=$OPTIND
+[ "$r1" = 0 ] && [ "$OPTIND1" = 2 ] && [ "$opt1" = x ] && [ "$r2" != 0 ] &&
+ [ "$OPTIND2" = 2 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts6.0 b/shell_cmds/sh/tests/builtins/getopts6.0
new file mode 100644
index 0000000..c415eda
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts6.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts6.0 265844 2014-05-10 17:42:21Z jilles $
+
+set -- -x -y
+getopts :x var || echo "First getopts bad: $?"
+getopts :x var
+r=$?
+[ r != 0 ] && [ "$OPTIND" = 3 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts7.0 b/shell_cmds/sh/tests/builtins/getopts7.0
new file mode 100644
index 0000000..58afa50
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts7.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts7.0 265844 2014-05-10 17:42:21Z jilles $
+
+set -- -x
+getopts :x: var
+r=$?
+[ r != 0 ] && [ "$OPTIND" = 2 ]
diff --git a/shell_cmds/sh/tests/builtins/getopts8.0 b/shell_cmds/sh/tests/builtins/getopts8.0
new file mode 100644
index 0000000..35814b9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts8.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts8.0 265849 2014-05-10 19:18:49Z jilles $
+
+set -- -yz -wx
+opt=wrong1 OPTARG=wrong2
+while getopts :x opt; do
+ echo "$opt:${OPTARG-unset}"
+done
+echo "OPTIND=$OPTIND"
diff --git a/shell_cmds/sh/tests/builtins/getopts8.0.stdout b/shell_cmds/sh/tests/builtins/getopts8.0.stdout
new file mode 100644
index 0000000..f10cefc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts8.0.stdout
@@ -0,0 +1,5 @@
+?:y
+?:z
+?:w
+x:unset
+OPTIND=3
diff --git a/shell_cmds/sh/tests/builtins/getopts9.0 b/shell_cmds/sh/tests/builtins/getopts9.0
new file mode 100644
index 0000000..aa4abbc
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts9.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/getopts9.0 297752 2016-04-09 16:06:13Z jilles $
+
+args='-ab'
+getopts ab opt $args
+printf '%s\n' "$?:$opt:$OPTARG"
+for dummy in dummy1 dummy2; do
+ getopts ab opt $args
+ printf '%s\n' "$?:$opt:$OPTARG"
+done
diff --git a/shell_cmds/sh/tests/builtins/getopts9.0.stdout b/shell_cmds/sh/tests/builtins/getopts9.0.stdout
new file mode 100644
index 0000000..4d32063
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/getopts9.0.stdout
@@ -0,0 +1,3 @@
+0:a:
+0:b:
+1:?:
diff --git a/shell_cmds/sh/tests/builtins/hash1.0 b/shell_cmds/sh/tests/builtins/hash1.0
new file mode 100644
index 0000000..a5cae20
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/hash1.0 149791 2005-09-05 09:42:10Z stefanf $
+cat /dev/null
+hash
+hash -r
+hash
diff --git a/shell_cmds/sh/tests/builtins/hash1.0.stdout b/shell_cmds/sh/tests/builtins/hash1.0.stdout
new file mode 100644
index 0000000..3afc3e7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash1.0.stdout
@@ -0,0 +1 @@
+/bin/cat
diff --git a/shell_cmds/sh/tests/builtins/hash2.0 b/shell_cmds/sh/tests/builtins/hash2.0
new file mode 100644
index 0000000..4ef151a
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/hash2.0 149791 2005-09-05 09:42:10Z stefanf $
+hash
+hash cat
+hash
diff --git a/shell_cmds/sh/tests/builtins/hash2.0.stdout b/shell_cmds/sh/tests/builtins/hash2.0.stdout
new file mode 100644
index 0000000..3afc3e7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash2.0.stdout
@@ -0,0 +1 @@
+/bin/cat
diff --git a/shell_cmds/sh/tests/builtins/hash3.0 b/shell_cmds/sh/tests/builtins/hash3.0
new file mode 100644
index 0000000..6a155f4
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash3.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/hash3.0 149791 2005-09-05 09:42:10Z stefanf $
+hash -v cat
+hash
diff --git a/shell_cmds/sh/tests/builtins/hash3.0.stdout b/shell_cmds/sh/tests/builtins/hash3.0.stdout
new file mode 100644
index 0000000..a34864c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash3.0.stdout
@@ -0,0 +1,2 @@
+/bin/cat
+/bin/cat
diff --git a/shell_cmds/sh/tests/builtins/hash4.0 b/shell_cmds/sh/tests/builtins/hash4.0
new file mode 100644
index 0000000..9e85f92
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/hash4.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/hash4.0 231535 2012-02-11 21:06:45Z jilles $
+
+exec 3>&1
+m=`hash nosuchtool 2>&1 >&3`
+r=$?
+[ "$r" != 0 ] && [ -n "$m" ]
diff --git a/shell_cmds/sh/tests/builtins/jobid1.0 b/shell_cmds/sh/tests/builtins/jobid1.0
new file mode 100644
index 0000000..8ba11c1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/jobid1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/jobid1.0 254412 2013-08-16 13:48:11Z jilles $
+# Non-standard builtin.
+
+: &
+p1=$!
+p2=$(jobid)
+[ "${p1:?}" = "${p2:?}" ]
diff --git a/shell_cmds/sh/tests/builtins/jobid2.0 b/shell_cmds/sh/tests/builtins/jobid2.0
new file mode 100644
index 0000000..4aca7d5
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/jobid2.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/jobid2.0 254413 2013-08-16 13:56:43Z jilles $
+
+: &
+p1=$(jobid)
+p2=$(jobid --)
+p3=$(jobid %+)
+p4=$(jobid -- %+)
+[ "${p1:?}" = "${p2:?}" ] && [ "${p2:?}" = "${p3:?}" ] &&
+[ "${p3:?}" = "${p4:?}" ] && [ "${p4:?}" = "${p1:?}" ]
diff --git a/shell_cmds/sh/tests/builtins/kill1.0 b/shell_cmds/sh/tests/builtins/kill1.0
new file mode 100644
index 0000000..c15c86d
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/kill1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/kill1.0 262931 2014-03-08 19:44:34Z jilles $
+
+: &
+p1=$!
+: &
+p2=$!
+wait $p2
+kill %1
diff --git a/shell_cmds/sh/tests/builtins/kill2.0 b/shell_cmds/sh/tests/builtins/kill2.0
new file mode 100644
index 0000000..3b2360b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/kill2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/kill2.0 263206 2014-03-15 14:58:48Z jilles $
+
+sleep 1 | sleep 1 &
+kill %+
+wait "$!"
+r=$?
+[ "$r" -gt 128 ] && [ "$(kill -l "$r")" = TERM ]
diff --git a/shell_cmds/sh/tests/builtins/lineno.0 b/shell_cmds/sh/tests/builtins/lineno.0
new file mode 100644
index 0000000..e678ad8
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/lineno.0 179023 2008-05-15 19:58:44Z stefanf $
+echo $LINENO
+echo $LINENO
+
+f() {
+ echo $LINENO
+ echo $LINENO
+}
+
+f
+
+echo ${LINENO:-foo}
+echo ${LINENO=foo}
+echo ${LINENO:+foo}
+echo ${LINENO+foo}
+echo ${#LINENO}
diff --git a/shell_cmds/sh/tests/builtins/lineno.0.stdout b/shell_cmds/sh/tests/builtins/lineno.0.stdout
new file mode 100644
index 0000000..82583a9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno.0.stdout
@@ -0,0 +1,9 @@
+2
+3
+2
+3
+12
+13
+foo
+foo
+2
diff --git a/shell_cmds/sh/tests/builtins/lineno2.0 b/shell_cmds/sh/tests/builtins/lineno2.0
new file mode 100644
index 0000000..f60ed11
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno2.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/lineno2.0 262565 2014-02-27 16:54:43Z jilles $
+
+f() {
+ : ${LINENO+${x?}}
+}
+
+unset -v x
+command eval f 2>/dev/null && exit 3
+x=1
+f
diff --git a/shell_cmds/sh/tests/builtins/lineno3.0 b/shell_cmds/sh/tests/builtins/lineno3.0
new file mode 100644
index 0000000..3271262
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/lineno3.0 272482 2014-10-03 20:24:56Z jilles $
+
+echo before: $LINENO
+dummy=$'a\0
+'
+echo after: $LINENO
diff --git a/shell_cmds/sh/tests/builtins/lineno3.0.stdout b/shell_cmds/sh/tests/builtins/lineno3.0.stdout
new file mode 100644
index 0000000..6e0e4ac
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/lineno3.0.stdout
@@ -0,0 +1,2 @@
+before: 3
+after: 6
diff --git a/shell_cmds/sh/tests/builtins/local1.0 b/shell_cmds/sh/tests/builtins/local1.0
new file mode 100644
index 0000000..6100274
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local1.0
@@ -0,0 +1,13 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local1.0 238469 2012-07-15 10:22:13Z jilles $
+# A commonly used but non-POSIX builtin.
+
+f() {
+ local x
+ x=2
+ [ "$x" = 2 ]
+}
+x=1
+f || exit 3
+[ "$x" = 1 ] || exit 3
+f || exit 3
+[ "$x" = 1 ] || exit 3
diff --git a/shell_cmds/sh/tests/builtins/local2.0 b/shell_cmds/sh/tests/builtins/local2.0
new file mode 100644
index 0000000..ed78d93
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local2.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local2.0 251797 2013-06-15 22:22:03Z jilles $
+
+f() {
+ local -
+ set -a
+ case $- in
+ *a*) : ;;
+ *) echo In-function \$- bad
+ esac
+}
+case $- in
+*a*) echo Initial \$- bad
+esac
+f
+case $- in
+*a*) echo Final \$- bad
+esac
diff --git a/shell_cmds/sh/tests/builtins/local3.0 b/shell_cmds/sh/tests/builtins/local3.0
new file mode 100644
index 0000000..f1d135d
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local3.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local3.0 251797 2013-06-15 22:22:03Z jilles $
+
+f() {
+ local "$@"
+ set -a
+ x=7
+ case $- in
+ *a*) : ;;
+ *) echo In-function \$- bad
+ esac
+ [ "$x" = 7 ] || echo In-function \$x bad
+}
+x=1
+case $- in
+*a*) echo Initial \$- bad
+esac
+f x -
+case $- in
+*a*) echo Intermediate \$- bad
+esac
+[ "$x" = 1 ] || echo Intermediate \$x bad
+f - x
+case $- in
+*a*) echo Final \$- bad
+esac
+[ "$x" = 1 ] || echo Final \$x bad
diff --git a/shell_cmds/sh/tests/builtins/local4.0 b/shell_cmds/sh/tests/builtins/local4.0
new file mode 100644
index 0000000..7d35e6e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local4.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local4.0 254339 2013-08-14 21:59:48Z jilles $
+
+f() {
+ local -- x
+ x=2
+ [ "$x" = 2 ]
+}
+x=1
+f || exit 3
+[ "$x" = 1 ] || exit 3
+f || exit 3
+[ "$x" = 1 ] || exit 3
diff --git a/shell_cmds/sh/tests/builtins/local5.0 b/shell_cmds/sh/tests/builtins/local5.0
new file mode 100644
index 0000000..912a77b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local5.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local5.0 293635 2016-01-10 16:31:28Z jilles $
+
+f() {
+ local PATH IFS elem
+ IFS=:
+ for elem in ''$PATH''; do
+ PATH=/var/empty/$elem:$PATH
+ done
+ ls -d / >/dev/null
+}
+
+p1=$(command -v ls)
+f
+p2=$(command -v ls)
+[ "$p1" = "$p2" ]
diff --git a/shell_cmds/sh/tests/builtins/local6.0 b/shell_cmds/sh/tests/builtins/local6.0
new file mode 100644
index 0000000..b2e4c68
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local6.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local6.0 294582 2016-01-22 18:10:36Z jilles $
+
+f() {
+ local x
+ readonly x=2
+}
+x=3
+f
+x=4
+[ "$x" = 4 ]
diff --git a/shell_cmds/sh/tests/builtins/local7.0 b/shell_cmds/sh/tests/builtins/local7.0
new file mode 100644
index 0000000..3819442
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/local7.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/local7.0 294593 2016-01-22 20:10:08Z jilles $
+
+f() {
+ local x
+ readonly x=2
+}
+unset x
+f
+x=4
+[ "$x" = 4 ]
diff --git a/shell_cmds/sh/tests/builtins/locale1.0 b/shell_cmds/sh/tests/builtins/locale1.0
new file mode 100644
index 0000000..a560232
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/locale1.0
@@ -0,0 +1,134 @@
+# $FreeBSD: head/bin/sh/tests/builtins/locale1.0 218819 2011-02-18 20:37:09Z jilles $
+# Note: this test depends on strerror() using locale.
+
+failures=0
+
+check() {
+ if ! eval "[ $1 ]"; then
+ echo "Failed: $1 at $2"
+ : $((failures += 1))
+ fi
+}
+
+unset LANG LC_ALL LC_COLLATE LC_CTYPE LC_MONETARY LC_NUMERIC LC_TIME LC_MESSAGES
+unset LANGUAGE
+
+msgeng="No such file or directory"
+msgdut="Bestand of map niet gevonden"
+
+# Verify C locale error message.
+case $(command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Various locale variables that should not affect the message.
+case $(LC_ALL=C command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_ALL=C LANG=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_ALL=C LC_MESSAGES=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_CTYPE=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Verify Dutch message.
+case $(export LANG=nl_NL.ISO8859-1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(export LC_MESSAGES=nl_NL.ISO8859-1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(export LC_ALL=nl_NL.ISO8859-1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LANG=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_MESSAGES=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_ALL=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Verify that command assignments do not set the locale persistently.
+case $(command . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LANG=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_MESSAGES=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(LC_ALL=nl_NL.ISO8859-1 command . /var/empty/foo 2>&1; command . /var/empty/foo 2>&1) in
+ *"$msgdut"*"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Check special builtin; add colon invocation to avoid depending on certain fix.
+case $(LC_ALL=nl_NL.ISO8859-1 . /var/empty/foo 2>&1; :) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+# Assignments on special builtins are exported to that builtin; the export
+# is not persistent.
+case $(LC_ALL=nl_NL.ISO8859-1 . /dev/null; . /var/empty/foo 2>&1) in
+ *"$msgeng"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+case $(export LC_ALL; LC_ALL=nl_NL.ISO8859-1 . /dev/null; . /var/empty/foo 2>&1) in
+ *"$msgdut"*) ok=1 ;;
+ *) ok=0 ;;
+esac
+check '$ok -eq 1' $LINENO
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/locale2.0 b/shell_cmds/sh/tests/builtins/locale2.0
new file mode 100644
index 0000000..fc1b432
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/locale2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/locale2.0 317912 2017-05-07 19:49:46Z jilles $
+
+$SH -c 'LC_ALL=C true; kill -INT $$; echo continued'
+r=$?
+[ "$r" -gt 128 ] && [ "$(kill -l "$r")" = INT ]
diff --git a/shell_cmds/sh/tests/builtins/printf1.0 b/shell_cmds/sh/tests/builtins/printf1.0
new file mode 100644
index 0000000..5730c5b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/printf1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/printf1.0 214853 2010-11-05 21:47:58Z jilles $
+
+[ "$(printf '%c\0%s%d' x '\' 010 | tr '\0' Z)" = 'xZ\8' ]
diff --git a/shell_cmds/sh/tests/builtins/printf2.0 b/shell_cmds/sh/tests/builtins/printf2.0
new file mode 100644
index 0000000..7084db7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/printf2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/printf2.0 214853 2010-11-05 21:47:58Z jilles $
+
+[ "$(printf '%cZ%s%d' x '\' 010)" = 'xZ\8' ]
diff --git a/shell_cmds/sh/tests/builtins/printf3.0 b/shell_cmds/sh/tests/builtins/printf3.0
new file mode 100644
index 0000000..ba54866
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/printf3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/printf3.0 216606 2010-12-20 23:06:57Z jilles $
+
+set -e
+v=$(! printf "%d" @wrong 2>/dev/null)
+[ "$v" = "0" ]
diff --git a/shell_cmds/sh/tests/builtins/printf4.0 b/shell_cmds/sh/tests/builtins/printf4.0
new file mode 100644
index 0000000..5213dd6
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/printf4.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/printf4.0 216606 2010-12-20 23:06:57Z jilles $
+
+set -e
+v=$(! printf "%d" 4wrong 2>/dev/null)
+[ "$v" = "4" ]
diff --git a/shell_cmds/sh/tests/builtins/read1.0 b/shell_cmds/sh/tests/builtins/read1.0
new file mode 100644
index 0000000..b32272c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read1.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read1.0 190300 2009-03-22 23:00:52Z stefanf $
+set -e
+
+echo "1 2 3" | { read a; echo "x${a}x"; }
+echo "1 2 3" | { read a b; echo "x${a}x${b}x"; }
+echo "1 2 3" | { read a b c; echo "x${a}x${b}x${c}x"; }
+echo "1 2 3" | { read a b c d; echo "x${a}x${b}x${c}x${d}x"; }
+
+echo " 1 2 3 " | { read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 2 3 " | { unset IFS; read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 2 3 " | { IFS=$(printf ' \t\n') read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 2 3 " | { IFS= read a b; echo "x${a}x${b}x"; }
+
+echo " 1,2 3 " | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo ", 2 ,3" | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,,3" | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 , , 3" | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,2 3," | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,2 3,," | { IFS=' ,' read a b c; echo "x${a}x${b}x${c}x"; }
+
+echo " 1,2 3 " | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo ", 2 ,3" | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,,3" | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 , , 3" | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,2 3," | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
+echo " 1 ,2 3,," | { IFS=', ' read a b c; echo "x${a}x${b}x${c}x"; }
diff --git a/shell_cmds/sh/tests/builtins/read1.0.stdout b/shell_cmds/sh/tests/builtins/read1.0.stdout
new file mode 100644
index 0000000..dbcb1af
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read1.0.stdout
@@ -0,0 +1,20 @@
+x1 2 3x
+x1x2 3x
+x1x2x3x
+x1x2x3xx
+x1x2x3x
+x1x2x3x
+x1x2x3x
+x 1 2 3 xx
+x1x2x3x
+xx2x3x
+x1xx3x
+x1xx3x
+x1x2x3x
+x1x2x3,,x
+x1x2x3x
+xx2x3x
+x1xx3x
+x1xx3x
+x1x2x3x
+x1x2x3,,x
diff --git a/shell_cmds/sh/tests/builtins/read2.0 b/shell_cmds/sh/tests/builtins/read2.0
new file mode 100644
index 0000000..3255a48
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read2.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read2.0 212187 2010-09-03 21:17:33Z jilles $
+
+set -e
+{
+ echo 1
+ echo two
+ echo three
+} | {
+ read x
+ [ "$x" = 1 ]
+ (read x
+ [ "$x" = two ])
+ read x
+ [ "$x" = three ]
+}
+
+T=`mktemp sh-test.XXXXXX`
+trap 'rm -f "$T"' 0
+{
+ echo 1
+ echo two
+ echo three
+} >$T
+{
+ read x
+ [ "$x" = 1 ]
+ (read x
+ [ "$x" = two ])
+ read x
+ [ "$x" = three ]
+} <$T
diff --git a/shell_cmds/sh/tests/builtins/read3.0 b/shell_cmds/sh/tests/builtins/read3.0
new file mode 100644
index 0000000..7cd5b4b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read3.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read3.0 212330 2010-09-08 18:32:23Z jilles $
+
+printf '%s\n' 'a\ b c' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' 'a b\ c' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' 'a\:b:c' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' 'a:b\:c' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\ a' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\:a' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\\ a' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\\ a' | { read -r a b; printf '%s\n' "x${a}x${b}x"; }
diff --git a/shell_cmds/sh/tests/builtins/read3.0.stdout b/shell_cmds/sh/tests/builtins/read3.0.stdout
new file mode 100644
index 0000000..8ed98ca
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read3.0.stdout
@@ -0,0 +1,9 @@
+xa bxcx
+xaxb cx
+xa:bxcx
+xaxb:cx
+x axx
+x:axx
+x\xx
+x\ axx
+x\\\xax
diff --git a/shell_cmds/sh/tests/builtins/read4.0 b/shell_cmds/sh/tests/builtins/read4.0
new file mode 100644
index 0000000..abd08af
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read4.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read4.0 212339 2010-09-08 20:35:43Z jilles $
+
+printf '%s\n' '\a\ b c' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\a b\ c' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\a\:b:c' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\a:b\:c' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\ a' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\:a' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\\ a' | { read a b; printf '%s\n' "x${a}x${b}x"; }
+printf '%s\n' '\\\:a' | { IFS=: read a b; printf '%s\n' "x${a}x${b}x"; }
diff --git a/shell_cmds/sh/tests/builtins/read4.0.stdout b/shell_cmds/sh/tests/builtins/read4.0.stdout
new file mode 100644
index 0000000..a8747a4
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read4.0.stdout
@@ -0,0 +1,8 @@
+xa bxcx
+xaxb cx
+xa:bxcx
+xaxb:cx
+x\xax
+x\xax
+x\ axx
+x\:axx
diff --git a/shell_cmds/sh/tests/builtins/read5.0 b/shell_cmds/sh/tests/builtins/read5.0
new file mode 100644
index 0000000..659aebb
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read5.0
@@ -0,0 +1,32 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read5.0 218821 2011-02-18 20:51:13Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+# Note: the first and last characters are not whitespace.
+# Exclude backslash and newline.
+bad1=`printf %03o \'\\\\`
+bad2=`printf %03o \''
+'`
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000|$bad1|$bad2) continue ;;
+ esac
+ e="$e\\$i$j$k"
+ done
+ done
+done
+e=`printf "$e"`
+[ "${#e}" = 253 ] || echo length bad
+
+r1=`printf '%s\n' "$e" | { read -r x; printf '%s' "$x"; }`
+[ "$r1" = "$e" ] || echo "read with -r bad"
+r2=`printf '%s\n' "$e" | { read x; printf '%s' "$x"; }`
+[ "$r2" = "$e" ] || echo "read without -r bad 1"
+IFS=
+r3=`printf '%s\n' "$e" | { read x; printf '%s' "$x"; }`
+[ "$r3" = "$e" ] || echo "read without -r bad 2"
diff --git a/shell_cmds/sh/tests/builtins/read6.0 b/shell_cmds/sh/tests/builtins/read6.0
new file mode 100644
index 0000000..3f78ee1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read6.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read6.0 247190 2013-02-23 15:15:41Z jilles $
+
+: | read x
+r=$?
+[ "$r" = 1 ]
diff --git a/shell_cmds/sh/tests/builtins/read7.0 b/shell_cmds/sh/tests/builtins/read7.0
new file mode 100644
index 0000000..a01082d
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read7.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read7.0 250214 2013-05-03 15:28:31Z jilles $
+
+{ errmsg=`read x <&- 2>&1 >&3`; } 3>&1
+r=$?
+[ "$r" -ge 2 ] && [ "$r" -le 128 ] && [ -n "$errmsg" ]
diff --git a/shell_cmds/sh/tests/builtins/read8.0 b/shell_cmds/sh/tests/builtins/read8.0
new file mode 100644
index 0000000..b488279
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read8.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read8.0 286826 2015-08-16 12:57:17Z jilles $
+
+read a b c <<\EOF
+\
+A\
+ \
+ \
+ \
+B\
+ \
+ \
+C\
+ \
+ \
+ \
+EOF
+[ "$a.$b.$c" = "A.B.C" ]
diff --git a/shell_cmds/sh/tests/builtins/read9.0 b/shell_cmds/sh/tests/builtins/read9.0
new file mode 100644
index 0000000..16f0687
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/read9.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/read9.0 287308 2015-08-30 17:24:22Z jilles $
+
+empty=''
+read a b c <<EOF
+\ \ A B\ \ B C\ \ $empty
+EOF
+read d e <<EOF
+D\ $empty
+EOF
+[ "$a.$b.$c.$d.$e" = " A.B B.C .D ." ]
diff --git a/shell_cmds/sh/tests/builtins/return1.0 b/shell_cmds/sh/tests/builtins/return1.0
new file mode 100644
index 0000000..46de0ae
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return1.0 149791 2005-09-05 09:42:10Z stefanf $
+f() {
+ return 0
+ exit 1
+}
+
+f
diff --git a/shell_cmds/sh/tests/builtins/return2.1 b/shell_cmds/sh/tests/builtins/return2.1
new file mode 100644
index 0000000..4da86f5
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return2.1
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return2.1 149791 2005-09-05 09:42:10Z stefanf $
+f() {
+ true && return 1
+ return 0
+}
+
+f
diff --git a/shell_cmds/sh/tests/builtins/return3.1 b/shell_cmds/sh/tests/builtins/return3.1
new file mode 100644
index 0000000..bc65c1f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return3.1
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return3.1 149791 2005-09-05 09:42:10Z stefanf $
+return 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/return4.0 b/shell_cmds/sh/tests/builtins/return4.0
new file mode 100644
index 0000000..1a702ef
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return4.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return4.0 208629 2010-05-28 22:08:34Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX) || exit
+trap 'rm -rf $T' 0
+cd $T || exit 3
+echo 'return 42; exit 4' >testscript
+. ./testscript
+[ "$?" = 42 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/return5.0 b/shell_cmds/sh/tests/builtins/return5.0
new file mode 100644
index 0000000..476ae7b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return5.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return5.0 211349 2010-08-15 21:06:53Z jilles $
+
+if [ "$1" != nested ]; then
+ f() {
+ set -- nested
+ . "$0"
+ # Allow return to return from the function or the dot script.
+ return 4
+ }
+ f
+ exit $(($? ^ 4))
+fi
+# To trigger the bug, the following commands must be at the top level,
+# with newlines in between.
+return 4
+echo bad
+exit 1
diff --git a/shell_cmds/sh/tests/builtins/return6.4 b/shell_cmds/sh/tests/builtins/return6.4
new file mode 100644
index 0000000..1bddbeb
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return6.4
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return6.4 212475 2010-09-11 15:07:40Z jilles $
+
+while return 4; do exit 3; done
diff --git a/shell_cmds/sh/tests/builtins/return7.4 b/shell_cmds/sh/tests/builtins/return7.4
new file mode 100644
index 0000000..3efdd7f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return7.4
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return7.4 212475 2010-09-11 15:07:40Z jilles $
+
+f() {
+ while return 4; do exit 3; done
+}
+f
diff --git a/shell_cmds/sh/tests/builtins/return8.0 b/shell_cmds/sh/tests/builtins/return8.0
new file mode 100644
index 0000000..025f068
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/return8.0
@@ -0,0 +1,13 @@
+# $FreeBSD: head/bin/sh/tests/builtins/return8.0 255215 2013-09-04 22:10:16Z jilles $
+
+if [ "$1" = nested ]; then
+ return 17
+fi
+
+f() {
+ set -- nested
+ . "$0"
+ return $(($? ^ 1))
+}
+f
+exit $(($? ^ 16))
diff --git a/shell_cmds/sh/tests/builtins/set1.0 b/shell_cmds/sh/tests/builtins/set1.0
new file mode 100644
index 0000000..fc39fad
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/set1.0
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+set +C
+set +f
+set -e
+
+settings=$(set +o)
+set -C
+set -f
+set +e
+case $- in
+*C*) ;;
+*) echo missing C ;;
+esac
+case $- in
+*f*) ;;
+*) echo missing C ;;
+esac
+case $- in
+*e*) echo bad e ;;
+esac
+eval "$settings"
+case $- in
+*C*) echo bad C ;;
+esac
+case $- in
+*f*) echo bad f ;;
+esac
+case $- in
+*e*) ;;
+*) echo missing e ;;
+esac
diff --git a/shell_cmds/sh/tests/builtins/set2.0 b/shell_cmds/sh/tests/builtins/set2.0
new file mode 100644
index 0000000..844da91
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/set2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/set2.0 223183 2011-06-17 10:21:24Z jilles $
+
+! env @badness=1 ${SH} -c 'v=`set`; eval "$v"' 2>&1 | grep @badness
diff --git a/shell_cmds/sh/tests/builtins/set3.0 b/shell_cmds/sh/tests/builtins/set3.0
new file mode 100644
index 0000000..419f702
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/set3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/set3.0 296578 2016-03-09 21:05:21Z jilles $
+
+settings1=$(set +o) && set -o nolog && settings2=$(set +o) &&
+[ "$settings1" != "$settings2" ]
diff --git a/shell_cmds/sh/tests/builtins/trap1.0 b/shell_cmds/sh/tests/builtins/trap1.0
new file mode 100644
index 0000000..9f60be4
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap1.0
@@ -0,0 +1,22 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap1.0 213738 2010-10-12 18:20:38Z obrien $
+
+test "$(trap 'echo trapped' EXIT; :)" = trapped || exit 1
+
+test "$(trap 'echo trapped' EXIT; /usr/bin/true)" = trapped || exit 1
+
+result=$(${SH} -c 'trap "echo trapped" EXIT; /usr/bin/false')
+test $? -eq 1 || exit 1
+test "$result" = trapped || exit 1
+
+result=$(${SH} -c 'trap "echo trapped" EXIT; exec /usr/bin/false')
+test $? -eq 1 || exit 1
+test -z "$result" || exit 1
+
+result=0
+trap 'result=$((result+1))' INT
+kill -INT $$
+test "$result" -eq 1 || exit 1
+(kill -INT $$)
+test "$result" -eq 2 || exit 1
+
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/trap10.0 b/shell_cmds/sh/tests/builtins/trap10.0
new file mode 100644
index 0000000..66c5106
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap10.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap10.0 230212 2012-01-16 11:07:46Z dumbbell $
+
+# Check that the return statement will not break the EXIT trap, ie. all
+# trap commands are executed before the script exits.
+
+test "$(trap 'printf trap; echo ped' EXIT; f() { return; }; f)" = trapped || exit 1
diff --git a/shell_cmds/sh/tests/builtins/trap11.0 b/shell_cmds/sh/tests/builtins/trap11.0
new file mode 100644
index 0000000..acb4d0f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap11.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap11.0 230212 2012-01-16 11:07:46Z dumbbell $
+
+# Check that the return statement will not break the USR1 trap, ie. all
+# trap commands are executed before the script resumes.
+
+result=$(${SH} -c 'trap "printf trap; echo ped" USR1; f() { return $(kill -USR1 $$); }; f')
+test $? -eq 0 || exit 1
+test "$result" = trapped || exit 1
diff --git a/shell_cmds/sh/tests/builtins/trap12.0 b/shell_cmds/sh/tests/builtins/trap12.0
new file mode 100644
index 0000000..a7a953c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap12.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap12.0 247720 2013-03-03 17:33:59Z jilles $
+
+f() {
+ trap 'return 42' USR1
+ kill -USR1 $$
+ return 3
+}
+f
+r=$?
+[ "$r" = 42 ]
diff --git a/shell_cmds/sh/tests/builtins/trap13.0 b/shell_cmds/sh/tests/builtins/trap13.0
new file mode 100644
index 0000000..1069b8f
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap13.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap13.0 257399 2013-10-30 21:36:15Z jilles $
+
+{
+ trap 'exit 0' INT
+ ${SH} -c 'kill -INT $PPID'
+ exit 3
+} &
+wait $!
diff --git a/shell_cmds/sh/tests/builtins/trap14.0 b/shell_cmds/sh/tests/builtins/trap14.0
new file mode 100644
index 0000000..8c982b2
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap14.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap14.0 257399 2013-10-30 21:36:15Z jilles $
+
+{
+ trap - INT
+ ${SH} -c 'kill -INT $PPID' &
+ wait
+} &
+wait $!
+r=$?
+[ "$r" -gt 128 ] && [ "$(kill -l "$r")" = INT ]
diff --git a/shell_cmds/sh/tests/builtins/trap15.0 b/shell_cmds/sh/tests/builtins/trap15.0
new file mode 100644
index 0000000..eaf8e8e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap15.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap15.0 281718 2015-04-18 23:49:57Z bdrewery $
+
+(${SH} -c 'term(){ exit 5;}; trap term TERM; kill -TERM $$') &
+wait >/dev/null 2>&1 $!
+[ $? -eq 5 ]
diff --git a/shell_cmds/sh/tests/builtins/trap16.0 b/shell_cmds/sh/tests/builtins/trap16.0
new file mode 100644
index 0000000..b72fa11
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap16.0
@@ -0,0 +1,20 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap16.0 281718 2015-04-18 23:49:57Z bdrewery $
+
+traps=$(${SH} -c 'trap "echo bad" 0; trap - 0; trap')
+[ -z "$traps" ] || exit 1
+traps=$(${SH} -c 'trap "echo bad" 0; trap "" 0; trap')
+expected_traps=$(${SH} -c 'trap "" EXIT; trap')
+[ "$traps" = "$expected_traps" ] || exit 2
+traps=$(${SH} -c 'trap "echo bad" 0; trap 0; trap')
+[ -z "$traps" ] || exit 3
+traps=$(${SH} -c 'trap "echo bad" 0; trap -- 0; trap')
+[ -z "$traps" ] || exit 4
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap - 0 1 2; trap')
+[ -z "$traps" ] || exit 5
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap "" 0 1 2; trap')
+expected_traps=$(${SH} -c 'trap "" EXIT HUP INT; trap')
+[ "$traps" = "$expected_traps" ] || exit 6
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap 0 1 2; trap')
+[ -z "$traps" ] || exit 7
+traps=$(${SH} -c 'trap "echo bad" 0 1 2; trap -- 0 1 2; trap')
+[ -z "$traps" ] || exit 8
diff --git a/shell_cmds/sh/tests/builtins/trap17.0 b/shell_cmds/sh/tests/builtins/trap17.0
new file mode 100644
index 0000000..35aafe7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap17.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap17.0 297360 2016-03-28 18:58:40Z jilles $
+# This use-after-free bug probably needs non-default settings to show up.
+
+v1=nothing v2=nothing
+trap 'trap "echo bad" USR1
+v1=trap_received
+v2=trap_invoked
+:' USR1
+kill -USR1 "$$"
+[ "$v1.$v2" = trap_received.trap_invoked ]
diff --git a/shell_cmds/sh/tests/builtins/trap2.0 b/shell_cmds/sh/tests/builtins/trap2.0
new file mode 100644
index 0000000..b64bb24
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap2.0
@@ -0,0 +1,52 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap2.0 194517 2009-06-19 22:15:59Z jilles $
+# This is really a test for outqstr(), which is readily accessible via trap.
+
+runtest()
+{
+ teststring=$1
+ trap -- "$teststring" USR1
+ traps=$(trap)
+ if [ "$teststring" != "-" ] && [ -z "$traps" ]; then
+ # One possible reading of POSIX requires the above to return an
+ # empty string because backquote commands are executed in a
+ # subshell and subshells shall reset traps. However, an example
+ # in the normative description of the trap builtin shows the
+ # same usage as here, it is useful and our /bin/sh allows it.
+ echo '$(trap) is broken'
+ exit 1
+ fi
+ trap - USR1
+ eval "$traps"
+ traps2=$(trap)
+ if [ "$traps" != "$traps2" ]; then
+ echo "Mismatch for '$teststring'"
+ exit 1
+ fi
+}
+
+runtest 'echo'
+runtest 'echo hi'
+runtest "'echo' 'hi'"
+runtest '"echo" $PATH'
+runtest '\echo "$PATH"'
+runtest ' 0'
+runtest '0 '
+runtest ' 1'
+runtest '1 '
+i=1
+while [ $i -le 127 ]; do
+ c=$(printf \\"$(printf %o $i)")
+ if [ $i -lt 48 ] || [ $i -gt 57 ]; then
+ runtest "$c"
+ fi
+ runtest " $c$c"
+ runtest "a$c"
+ i=$((i+1))
+done
+IFS=,
+runtest ' '
+runtest ','
+unset IFS
+runtest ' '
+
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/trap3.0 b/shell_cmds/sh/tests/builtins/trap3.0
new file mode 100644
index 0000000..d442f8b
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap3.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap3.0 218889 2011-02-20 14:18:58Z jilles $
+
+{
+ trap '' garbage && exit 3
+ trap - garbage && exit 3
+ trap true garbage && exit 3
+ trap '' 99999 && exit 3
+ trap - 99999 && exit 3
+ trap true 99999 && exit 3
+} 2>/dev/null
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/trap4.0 b/shell_cmds/sh/tests/builtins/trap4.0
new file mode 100644
index 0000000..9fdab81
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap4.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap4.0 217035 2011-01-05 23:17:29Z jilles $
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd $T || exit 3
+mkfifo fifo1
+
+v=$(
+ exec 3>&1
+ : <fifo1 &
+ {
+ wait $!
+ trap 'trap "" PIPE; echo trapped >&3 2>/dev/null' PIPE
+ echo x 2>/dev/null
+ } >fifo1
+)
+test "$v" = trapped
diff --git a/shell_cmds/sh/tests/builtins/trap5.0 b/shell_cmds/sh/tests/builtins/trap5.0
new file mode 100644
index 0000000..26eeb50
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap5.0
@@ -0,0 +1,19 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap5.0 217461 2011-01-15 21:09:00Z jilles $
+
+set -e
+trap - USR1
+initial=$(trap)
+trap -- -l USR1
+added=$(trap)
+[ -n "$added" ]
+trap - USR1
+second=$(trap)
+[ "$initial" = "$second" ]
+eval "$added"
+added2=$(trap)
+added3=$(trap --)
+[ "$added" = "$added2" ]
+[ "$added2" = "$added3" ]
+trap -- - USR1
+third=$(trap)
+[ "$initial" = "$third" ]
diff --git a/shell_cmds/sh/tests/builtins/trap6.0 b/shell_cmds/sh/tests/builtins/trap6.0
new file mode 100644
index 0000000..1e79ae7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap6.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap6.0 217472 2011-01-16 13:56:41Z jilles $
+
+v=$(
+ ${SH} -c 'trap "echo ok; exit" USR1; kill -USR1 $$' &
+ # Suppress possible message about exit on signal
+ wait $! >/dev/null 2>&1
+)
+r=$(kill -l $?)
+[ "$v" = "ok" ] && { [ "$r" = "USR1" ] || [ "$r" = "usr1" ]; }
diff --git a/shell_cmds/sh/tests/builtins/trap7.0 b/shell_cmds/sh/tests/builtins/trap7.0
new file mode 100644
index 0000000..b62ffb7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap7.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap7.0 217996 2011-01-27 23:08:20Z jilles $
+
+[ "$(trap 'echo trapped' EXIT)" = trapped ]
diff --git a/shell_cmds/sh/tests/builtins/trap8.0 b/shell_cmds/sh/tests/builtins/trap8.0
new file mode 100644
index 0000000..24752b1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap8.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap8.0 218889 2011-02-20 14:18:58Z jilles $
+
+# I am not sure if POSIX requires the shell to continue processing
+# further trap names in the same trap command after an invalid one.
+
+test -n "$(trap true garbage TERM 2>/dev/null || trap)" || exit 3
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/trap9.0 b/shell_cmds/sh/tests/builtins/trap9.0
new file mode 100644
index 0000000..bbc35e9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/trap9.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/trap9.0 230211 2012-01-16 10:59:44Z dumbbell $
+
+test "$(trap 'printf trap; echo ped' EXIT; f() { :; }; f)" = trapped || exit 1
diff --git a/shell_cmds/sh/tests/builtins/type1.0 b/shell_cmds/sh/tests/builtins/type1.0
new file mode 100644
index 0000000..2f04997
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/type1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/builtins/type1.0 165931 2007-01-11 00:25:20Z stefanf $
+command -v not-here && exit 1
+command -v /not-here && exit 1
+command -V not-here && exit 1
+command -V /not-here && exit 1
+type not-here && exit 1
+type /not-here && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/type1.0.stderr b/shell_cmds/sh/tests/builtins/type1.0.stderr
new file mode 100644
index 0000000..7853418
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/type1.0.stderr
@@ -0,0 +1,4 @@
+not-here: not found
+/not-here: No such file or directory
+not-here: not found
+/not-here: No such file or directory
diff --git a/shell_cmds/sh/tests/builtins/type2.0 b/shell_cmds/sh/tests/builtins/type2.0
new file mode 100644
index 0000000..7e0581e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/type2.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/builtins/type2.0 201344 2009-12-31 17:44:24Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "$*"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check 'PATH=/libexec type ld-elf.so.1 >/dev/null'
+check '! PATH=/libexec type ls 2>/dev/null'
+
+PATH=/libexec:$PATH
+
+check 'type ld-elf.so.1 >/dev/null'
+
+PATH=/libexec
+
+check 'type ld-elf.so.1 >/dev/null'
+check '! type ls 2>/dev/null'
+check 'PATH=/bin type ls >/dev/null'
+check '! PATH=/bin type ld-elf.so.1 2>/dev/null'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/builtins/type3.0 b/shell_cmds/sh/tests/builtins/type3.0
new file mode 100644
index 0000000..dad07e9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/type3.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/type3.0 255072 2013-08-30 12:09:59Z jilles $
+
+[ "$(type type)" = "$(type -- type)" ]
diff --git a/shell_cmds/sh/tests/builtins/unalias.0 b/shell_cmds/sh/tests/builtins/unalias.0
new file mode 100644
index 0000000..ffdc756
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/unalias.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/unalias.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+
+alias false=true
+false
+unalias false
+false && exit 1
+unalias false && exit 1
+
+alias a1=foo a2=bar
+unalias a1 a2
+unalias a1 && exit 1
+unalias a2 && exit 1
+alias a2=bar
+unalias a1 a2 && exit 1
+
+alias a1=foo a2=bar
+unalias -a
+unalias a1 && exit 1
+unalias a2 && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/builtins/var-assign.0 b/shell_cmds/sh/tests/builtins/var-assign.0
new file mode 100644
index 0000000..41b59b1
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/var-assign.0
@@ -0,0 +1,55 @@
+# $FreeBSD: head/bin/sh/tests/builtins/var-assign.0 327281 2017-12-28 08:22:26Z eadler $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,
+ eval,
+ exec,
+ export -p,
+ readonly -p,
+ set,
+ shift 0,
+ times,
+ trap,
+ unset foo"
+
+UTILS="alias,\
+ bg,\
+ bind,\
+ cd,\
+ command echo,\
+ echo,\
+ false,\
+ fc -l,\
+ fg,\
+ getopts a var,\
+ hash,\
+ jobs,\
+ printf a,\
+ pwd,\
+ read var < /dev/null,\
+ test,\
+ true,\
+ type ls,\
+ ulimit,\
+ umask,\
+ unalias -a,\
+ wait"
+
+set -e
+
+# For special built-ins variable assignments affect the shell environment.
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "VAR=1; VAR=0 ${cmd}; exit \${VAR}" >/dev/null 2>&1
+done
+
+# For other built-ins and utilities they do not.
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "VAR=0; VAR=1 ${cmd}; exit \${VAR}" >/dev/null 2>&1
+done
diff --git a/shell_cmds/sh/tests/builtins/var-assign2.0 b/shell_cmds/sh/tests/builtins/var-assign2.0
new file mode 100644
index 0000000..b9afb55
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/var-assign2.0
@@ -0,0 +1,55 @@
+# $FreeBSD: head/bin/sh/tests/builtins/var-assign2.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,\
+ eval,\
+ exec,\
+ export -p,\
+ readonly -p,\
+ set,\
+ shift 0,\
+ times,\
+ trap,\
+ unset foo"
+
+UTILS="alias,\
+ bg,\
+ bind,\
+ cd,\
+ command echo,\
+ echo,\
+ false,\
+ fc -l,\
+ fg,\
+ getopts a var,\
+ hash,\
+ jobs,\
+ printf a,\
+ pwd,\
+ read var < /dev/null,\
+ test,\
+ true,\
+ type ls,\
+ ulimit,\
+ umask,\
+ unalias -a,\
+ wait"
+
+set -e
+
+# With 'command', variable assignments do not affect the shell environment.
+
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "VAR=0; VAR=1 command ${cmd}; exit \${VAR}" >/dev/null 2>&1
+done
+
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "VAR=0; VAR=1 command ${cmd}; exit \${VAR}" >/dev/null 2>&1
+done
diff --git a/shell_cmds/sh/tests/builtins/wait1.0 b/shell_cmds/sh/tests/builtins/wait1.0
new file mode 100644
index 0000000..8538415
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait1.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait1.0 208476 2010-05-23 22:10:20Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+exit 4 & p4=$!
+exit 8 & p8=$!
+wait $p4
+[ $? = 4 ] || failure $LINENO
+wait $p8
+[ $? = 8 ] || failure $LINENO
+
+exit 3 & p3=$!
+exit 7 & p7=$!
+wait $p7
+[ $? = 7 ] || failure $LINENO
+wait $p3
+[ $? = 3 ] || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/wait10.0 b/shell_cmds/sh/tests/builtins/wait10.0
new file mode 100644
index 0000000..c7e3975
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait10.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait10.0 251430 2013-06-05 19:40:52Z jilles $
+# Init cannot be a child of the shell.
+exit 49 & p49=$!
+wait 1 "$p49"
+[ "$?" = 49 ]
diff --git a/shell_cmds/sh/tests/builtins/wait2.0 b/shell_cmds/sh/tests/builtins/wait2.0
new file mode 100644
index 0000000..71adfde
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait2.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait2.0 208476 2010-05-23 22:10:20Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ exit $i &
+done
+wait || failure $LINENO
+wait || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/wait3.0 b/shell_cmds/sh/tests/builtins/wait3.0
new file mode 100644
index 0000000..d3561ae
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait3.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait3.0 236771 2012-06-08 22:54:25Z jilles $
+
+failures=
+failure() {
+ echo "Error at line $1" >&2
+ failures=x$failures
+}
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd $T || exit 3
+mkfifo fifo1
+for i in 1 2 3 4 5 6 7 8 9 10; do
+ exit $i 4<fifo1 &
+done
+exec 3>fifo1
+wait || failure $LINENO
+(${SH} -c echo >&3) 2>/dev/null && failure $LINENO
+wait || failure $LINENO
+
+test -z "$failures"
diff --git a/shell_cmds/sh/tests/builtins/wait4.0 b/shell_cmds/sh/tests/builtins/wait4.0
new file mode 100644
index 0000000..358513c
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait4.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait4.0 247206 2013-02-23 22:50:57Z jilles $
+
+T=`mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX`
+trap 'rm -rf $T' 0
+cd $T || exit 3
+mkfifo fifo1
+trapped=
+trap trapped=1 QUIT
+{ kill -QUIT $$; sleep 1; exit 4; } >fifo1 &
+wait $! <fifo1
+r=$?
+[ "$r" -gt 128 ] && [ -n "$trapped" ]
diff --git a/shell_cmds/sh/tests/builtins/wait5.0 b/shell_cmds/sh/tests/builtins/wait5.0
new file mode 100644
index 0000000..48e1d2e
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait5.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait5.0 247206 2013-02-23 22:50:57Z jilles $
+
+T=`mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX`
+trap 'rm -rf $T' 0
+cd $T || exit 3
+mkfifo fifo1
+trapped=
+trap trapped=1 QUIT
+{ kill -QUIT $$; sleep 1; exit 4; } >fifo1 &
+wait <fifo1
+r=$?
+[ "$r" -gt 128 ] && [ -n "$trapped" ]
diff --git a/shell_cmds/sh/tests/builtins/wait6.0 b/shell_cmds/sh/tests/builtins/wait6.0
new file mode 100644
index 0000000..e87b9c9
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait6.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait6.0 248349 2013-03-15 20:29:31Z jilles $
+
+wait --
diff --git a/shell_cmds/sh/tests/builtins/wait7.0 b/shell_cmds/sh/tests/builtins/wait7.0
new file mode 100644
index 0000000..2c50674
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait7.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait7.0 248349 2013-03-15 20:29:31Z jilles $
+
+: &
+wait -- $!
diff --git a/shell_cmds/sh/tests/builtins/wait8.0 b/shell_cmds/sh/tests/builtins/wait8.0
new file mode 100644
index 0000000..15e23b7
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait8.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait8.0 251429 2013-06-05 19:08:22Z jilles $
+
+exit 44 & p44=$!
+exit 45 & p45=$!
+exit 7 & p7=$!
+wait "$p44" "$p7" "$p45"
+[ "$?" = 45 ]
diff --git a/shell_cmds/sh/tests/builtins/wait9.127 b/shell_cmds/sh/tests/builtins/wait9.127
new file mode 100644
index 0000000..9bed737
--- /dev/null
+++ b/shell_cmds/sh/tests/builtins/wait9.127
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/builtins/wait9.127 251430 2013-06-05 19:40:52Z jilles $
+# Init cannot be a child of the shell.
+wait 1
diff --git a/shell_cmds/sh/tests/errors/Makefile b/shell_cmds/sh/tests/errors/Makefile
new file mode 100644
index 0000000..a234a05
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/Makefile
@@ -0,0 +1,35 @@
+# $FreeBSD: head/bin/sh/tests/errors/Makefile 319575 2017-06-04 20:52:55Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= assignment-error1.0
+${PACKAGE}FILES+= assignment-error2.0
+${PACKAGE}FILES+= backquote-error1.0
+${PACKAGE}FILES+= backquote-error2.0
+${PACKAGE}FILES+= bad-binary1.126
+${PACKAGE}FILES+= bad-keyword1.0
+${PACKAGE}FILES+= bad-parm-exp1.0
+${PACKAGE}FILES+= bad-parm-exp2.2 bad-parm-exp2.2.stderr
+${PACKAGE}FILES+= bad-parm-exp3.2 bad-parm-exp3.2.stderr
+${PACKAGE}FILES+= bad-parm-exp4.2 bad-parm-exp4.2.stderr
+${PACKAGE}FILES+= bad-parm-exp5.2 bad-parm-exp5.2.stderr
+${PACKAGE}FILES+= bad-parm-exp6.2 bad-parm-exp6.2.stderr
+${PACKAGE}FILES+= bad-parm-exp7.0
+${PACKAGE}FILES+= bad-parm-exp8.0
+${PACKAGE}FILES+= option-error.0
+${PACKAGE}FILES+= redirection-error.0
+${PACKAGE}FILES+= redirection-error2.2
+${PACKAGE}FILES+= redirection-error3.0
+${PACKAGE}FILES+= redirection-error4.0
+${PACKAGE}FILES+= redirection-error5.0
+${PACKAGE}FILES+= redirection-error6.0
+${PACKAGE}FILES+= redirection-error7.0
+${PACKAGE}FILES+= redirection-error8.0
+${PACKAGE}FILES+= write-error1.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/errors/Makefile.depend b/shell_cmds/sh/tests/errors/Makefile.depend
new file mode 100644
index 0000000..dbfdc34
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/errors/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# 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/shell_cmds/sh/tests/errors/assignment-error1.0 b/shell_cmds/sh/tests/errors/assignment-error1.0
new file mode 100644
index 0000000..2106b5a
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/assignment-error1.0
@@ -0,0 +1,30 @@
+# $FreeBSD: head/bin/sh/tests/errors/assignment-error1.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,\
+ eval,\
+ exec,\
+ export -p,\
+ readonly -p,\
+ set,\
+ shift,\
+ times,\
+ trap,\
+ unset foo"
+
+# If there is no command word, the shell must abort on an assignment error.
+${SH} -c "readonly a=0; a=2; exit 0" 2>/dev/null && exit 1
+
+# Special built-in utilities must abort on an assignment error.
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "readonly a=0; a=2 ${cmd}; exit 0" 2>/dev/null && exit 1
+done
+
+# Other utilities must not abort; we currently still execute them.
+${SH} -c 'readonly a=0; a=1 true; exit $a' 2>/dev/null || exit 1
+${SH} -c 'readonly a=0; a=1 command :; exit $a' 2>/dev/null || exit 1
diff --git a/shell_cmds/sh/tests/errors/assignment-error2.0 b/shell_cmds/sh/tests/errors/assignment-error2.0
new file mode 100644
index 0000000..68f2d48
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/assignment-error2.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/errors/assignment-error2.0 216870 2011-01-01 13:26:18Z jilles $
+
+set -e
+HOME=/
+readonly HOME
+cd /sbin
+{ HOME=/bin cd; } 2>/dev/null || :
+[ "$(pwd)" != /bin ]
diff --git a/shell_cmds/sh/tests/errors/backquote-error1.0 b/shell_cmds/sh/tests/errors/backquote-error1.0
new file mode 100644
index 0000000..d35d0b7
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/backquote-error1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/backquote-error1.0 213738 2010-10-12 18:20:38Z obrien $
+
+echo 'echo `for` echo ".BAD"CODE.' | ${SH} +m -i 2>&1 | grep -q BADCODE && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/errors/backquote-error2.0 b/shell_cmds/sh/tests/errors/backquote-error2.0
new file mode 100644
index 0000000..a5955dd
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/backquote-error2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/errors/backquote-error2.0 213738 2010-10-12 18:20:38Z obrien $
+
+${SH} -c 'echo `echo .BA"DCODE.`
+echo ".BAD"CODE.' 2>&1 | grep -q BADCODE && exit 1
+echo '`"`' | ${SH} -n 2>/dev/null && exit 1
+echo '`'"'"'`' | ${SH} -n 2>/dev/null && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/errors/bad-binary1.126 b/shell_cmds/sh/tests/errors/bad-binary1.126
new file mode 100644
index 0000000..7c7c67f
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-binary1.126
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-binary1.126 218320 2011-02-05 12:54:59Z jilles $
+# Checking for binary "scripts" without magic number is permitted but not
+# required by POSIX. However, it is preferable to getting errors like
+# Syntax error: word unexpected (expecting ")")
+# from trying to execute ELF binaries for the wrong architecture.
+
+T=`mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX"` || exit
+trap 'rm -rf "${T}"' 0
+printf '\0echo bad\n' >"$T/testshellproc"
+chmod 755 "$T/testshellproc"
+PATH=$T:$PATH
+testshellproc 2>/dev/null
diff --git a/shell_cmds/sh/tests/errors/bad-keyword1.0 b/shell_cmds/sh/tests/errors/bad-keyword1.0
new file mode 100644
index 0000000..d2680d6
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-keyword1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-keyword1.0 216398 2010-12-12 21:18:16Z jilles $
+
+echo ':; fi' | ${SH} -n 2>/dev/null && exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp1.0 b/shell_cmds/sh/tests/errors/bad-parm-exp1.0
new file mode 100644
index 0000000..f288294
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp1.0 164004 2006-11-05 18:41:23Z stefanf $
+false && {
+ ${}
+ ${foo/}
+ ${foo@bar}
+}
+:
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp2.2 b/shell_cmds/sh/tests/errors/bad-parm-exp2.2
new file mode 100644
index 0000000..7424840
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp2.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp2.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp2.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp2.2.stderr
new file mode 100644
index 0000000..51ea69c
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp2.2.stderr
@@ -0,0 +1 @@
+eval: ${}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp3.2 b/shell_cmds/sh/tests/errors/bad-parm-exp3.2
new file mode 100644
index 0000000..56a52df
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp3.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp3.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${foo/}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp3.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp3.2.stderr
new file mode 100644
index 0000000..70473f9
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp3.2.stderr
@@ -0,0 +1 @@
+eval: ${foo/}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp4.2 b/shell_cmds/sh/tests/errors/bad-parm-exp4.2
new file mode 100644
index 0000000..e0a7099
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp4.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp4.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${foo:@abc}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp4.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp4.2.stderr
new file mode 100644
index 0000000..3363f51
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp4.2.stderr
@@ -0,0 +1 @@
+eval: ${foo:@...}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp5.2 b/shell_cmds/sh/tests/errors/bad-parm-exp5.2
new file mode 100644
index 0000000..fa26259
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp5.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp5.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${/}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp5.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp5.2.stderr
new file mode 100644
index 0000000..13763f8
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp5.2.stderr
@@ -0,0 +1 @@
+eval: ${/}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp6.2 b/shell_cmds/sh/tests/errors/bad-parm-exp6.2
new file mode 100644
index 0000000..51858e8
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp6.2
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp6.2 270101 2014-08-17 14:26:12Z jilles $
+eval '${#foo^}'
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp6.2.stderr b/shell_cmds/sh/tests/errors/bad-parm-exp6.2.stderr
new file mode 100644
index 0000000..cc56f65
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp6.2.stderr
@@ -0,0 +1 @@
+eval: ${foo...}: Bad substitution
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp7.0 b/shell_cmds/sh/tests/errors/bad-parm-exp7.0
new file mode 100644
index 0000000..d7bff92
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp7.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp7.0 287081 2015-08-23 20:44:53Z jilles $
+
+v=1
+eval ": $(printf '${v-${\372}}')"
diff --git a/shell_cmds/sh/tests/errors/bad-parm-exp8.0 b/shell_cmds/sh/tests/errors/bad-parm-exp8.0
new file mode 100644
index 0000000..24f6bff
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/bad-parm-exp8.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/bad-parm-exp8.0 287081 2015-08-23 20:44:53Z jilles $
+
+v=1
+eval ": $(printf '${v-${w\372}}')"
diff --git a/shell_cmds/sh/tests/errors/option-error.0 b/shell_cmds/sh/tests/errors/option-error.0
new file mode 100644
index 0000000..473c0b9
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/option-error.0
@@ -0,0 +1,46 @@
+# $FreeBSD: head/bin/sh/tests/errors/option-error.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break abc,\
+ continue abc,\
+ .,
+ exit abc,
+ export -x,
+ readonly -x,
+ return abc,
+ set -z,
+ shift abc,
+ trap -y,
+ unset -y"
+
+UTILS="alias -y,\
+ cat -z,\
+ cd abc def,\
+ command break abc,\
+ expr 1 +,\
+ fc -z,\
+ getopts,\
+ hash -z,\
+ jobs -z,\
+ printf,\
+ pwd abc,\
+ read,\
+ test abc =,\
+ ulimit -z,\
+ umask -z,\
+ unalias -z,\
+ wait abc"
+
+# Special built-in utilities must abort on an option or operand error.
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "${cmd}; exit 0" 2>/dev/null && exit 1
+done
+
+# Other utilities must not abort.
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "${cmd}; exit 0" 2>/dev/null || exit 1
+done
diff --git a/shell_cmds/sh/tests/errors/redirection-error.0 b/shell_cmds/sh/tests/errors/redirection-error.0
new file mode 100644
index 0000000..2a67698
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error.0
@@ -0,0 +1,53 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,
+ eval,
+ exec,
+ export -p,
+ readonly -p,
+ set,
+ shift,
+ times,
+ trap,
+ unset foo"
+
+UTILS="alias,\
+ bg,\
+ bind,\
+ cd,\
+ command echo,\
+ echo,\
+ false,\
+ fc -l,\
+ fg,\
+ getopts a -a,\
+ hash,\
+ jobs,\
+ printf a,\
+ pwd,\
+ read var < /dev/null,\
+ test,\
+ true,\
+ type ls,\
+ ulimit,\
+ umask,\
+ unalias -a,\
+ wait"
+
+# Special built-in utilities must abort on a redirection error.
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "${cmd} > /; exit 0" 2>/dev/null && exit 1
+done
+
+# Other utilities must not abort.
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "${cmd} > /; exit 0" 2>/dev/null || exit 1
+done
diff --git a/shell_cmds/sh/tests/errors/redirection-error2.2 b/shell_cmds/sh/tests/errors/redirection-error2.2
new file mode 100644
index 0000000..595e959
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error2.2
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error2.2 213738 2010-10-12 18:20:38Z obrien $
+
+# sh should fail gracefully on this bad redirect
+${SH} -c 'echo 1 >&$a' 2>/dev/null
diff --git a/shell_cmds/sh/tests/errors/redirection-error3.0 b/shell_cmds/sh/tests/errors/redirection-error3.0
new file mode 100644
index 0000000..fd7a334
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error3.0
@@ -0,0 +1,54 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error3.0 213738 2010-10-12 18:20:38Z obrien $
+IFS=,
+
+SPECIAL="break,\
+ :,\
+ continue,\
+ . /dev/null,\
+ eval,\
+ exec,\
+ export -p,\
+ readonly -p,\
+ set,\
+ shift,\
+ times,\
+ trap,\
+ unset foo"
+
+UTILS="alias,\
+ bg,\
+ bind,\
+ cd,\
+ command echo,\
+ echo,\
+ false,\
+ fc -l,\
+ fg,\
+ getopts a -a,\
+ hash,\
+ jobs,\
+ printf a,\
+ pwd,\
+ read var < /dev/null,\
+ test,\
+ true,\
+ type ls,\
+ ulimit,\
+ umask,\
+ unalias -a,\
+ wait"
+
+# When used with 'command', neither special built-in utilities nor other
+# utilities must abort on a redirection error.
+
+set -- ${SPECIAL}
+for cmd in "$@"
+do
+ ${SH} -c "command ${cmd} > /; exit 0" 2>/dev/null || exit 1
+done
+
+set -- ${UTILS}
+for cmd in "$@"
+do
+ ${SH} -c "command ${cmd} > /; exit 0" 2>/dev/null || exit 1
+done
diff --git a/shell_cmds/sh/tests/errors/redirection-error4.0 b/shell_cmds/sh/tests/errors/redirection-error4.0
new file mode 100644
index 0000000..ed58499
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error4.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error4.0 205138 2010-03-13 22:53:17Z jilles $
+# A redirection error should not abort the shell if there is no command word.
+exec 2>/dev/null
+</var/empty/x
+</var/empty/x y=2
+y=2 </var/empty/x
+exit 0
diff --git a/shell_cmds/sh/tests/errors/redirection-error5.0 b/shell_cmds/sh/tests/errors/redirection-error5.0
new file mode 100644
index 0000000..b96c14e
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error5.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error5.0 205153 2010-03-14 13:51:12Z jilles $
+# A redirection error on a subshell should not abort the shell.
+exec 2>/dev/null
+( echo bad ) </var/empty/x
+exit 0
diff --git a/shell_cmds/sh/tests/errors/redirection-error6.0 b/shell_cmds/sh/tests/errors/redirection-error6.0
new file mode 100644
index 0000000..1d84e6c
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error6.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error6.0 205154 2010-03-14 14:24:35Z jilles $
+# A redirection error on a compound command should not abort the shell.
+exec 2>/dev/null
+{ echo bad; } </var/empty/x
+if :; then echo bad; fi </var/empty/x
+for i in 1; do echo bad; done </var/empty/x
+i=0
+while [ $i = 0 ]; do echo bad; i=1; done </var/empty/x
+i=0
+until [ $i != 0 ]; do echo bad; i=1; done </var/empty/x
+case i in *) echo bad ;; esac </var/empty/x
+exit 0
diff --git a/shell_cmds/sh/tests/errors/redirection-error7.0 b/shell_cmds/sh/tests/errors/redirection-error7.0
new file mode 100644
index 0000000..ef56434
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error7.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error7.0 216851 2010-12-31 18:20:17Z jilles $
+
+! dummy=$(
+ exec 3>&1 >&2 2>&3
+ ulimit -n 9
+ exec 9<.
+) && [ -n "$dummy" ]
diff --git a/shell_cmds/sh/tests/errors/redirection-error8.0 b/shell_cmds/sh/tests/errors/redirection-error8.0
new file mode 100644
index 0000000..97364ac
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/redirection-error8.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/errors/redirection-error8.0 319575 2017-06-04 20:52:55Z jilles $
+
+$SH -c '{ { :; } </var/empty/x; } 2>/dev/null || kill -INT $$; echo continued'
+r=$?
+[ "$r" -gt 128 ] && [ "$(kill -l "$r")" = INT ]
diff --git a/shell_cmds/sh/tests/errors/write-error1.0 b/shell_cmds/sh/tests/errors/write-error1.0
new file mode 100644
index 0000000..3001e5c
--- /dev/null
+++ b/shell_cmds/sh/tests/errors/write-error1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/errors/write-error1.0 244924 2013-01-01 12:48:24Z jilles $
+
+! echo >&- 2>/dev/null
diff --git a/shell_cmds/sh/tests/execution/Makefile b/shell_cmds/sh/tests/execution/Makefile
new file mode 100644
index 0000000..6e80719
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/Makefile
@@ -0,0 +1,57 @@
+# $FreeBSD: head/bin/sh/tests/execution/Makefile 308229 2016-11-02 22:33:37Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= bg1.0
+${PACKAGE}FILES+= bg2.0
+${PACKAGE}FILES+= bg3.0
+${PACKAGE}FILES+= bg4.0
+${PACKAGE}FILES+= bg5.0
+${PACKAGE}FILES+= bg6.0 bg6.0.stdout
+${PACKAGE}FILES+= bg7.0
+${PACKAGE}FILES+= bg8.0
+${PACKAGE}FILES+= bg9.0
+${PACKAGE}FILES+= bg10.0 bg10.0.stdout
+${PACKAGE}FILES+= fork1.0
+${PACKAGE}FILES+= fork2.0
+${PACKAGE}FILES+= fork3.0
+${PACKAGE}FILES+= func1.0
+${PACKAGE}FILES+= func2.0
+${PACKAGE}FILES+= func3.0
+${PACKAGE}FILES+= hash1.0
+${PACKAGE}FILES+= int-cmd1.0
+${PACKAGE}FILES+= killed1.0
+${PACKAGE}FILES+= killed2.0
+${PACKAGE}FILES+= not1.0
+${PACKAGE}FILES+= not2.0
+${PACKAGE}FILES+= path1.0
+${PACKAGE}FILES+= redir1.0
+${PACKAGE}FILES+= redir2.0
+${PACKAGE}FILES+= redir3.0
+${PACKAGE}FILES+= redir4.0
+${PACKAGE}FILES+= redir5.0
+${PACKAGE}FILES+= redir6.0
+${PACKAGE}FILES+= redir7.0
+${PACKAGE}FILES+= set-C1.0
+${PACKAGE}FILES+= set-n1.0
+${PACKAGE}FILES+= set-n2.0
+${PACKAGE}FILES+= set-n3.0
+${PACKAGE}FILES+= set-n4.0
+${PACKAGE}FILES+= set-x1.0
+${PACKAGE}FILES+= set-x2.0
+${PACKAGE}FILES+= set-x3.0
+${PACKAGE}FILES+= set-x4.0
+${PACKAGE}FILES+= shellproc1.0
+${PACKAGE}FILES+= subshell1.0 subshell1.0.stdout
+${PACKAGE}FILES+= subshell2.0
+${PACKAGE}FILES+= subshell3.0
+${PACKAGE}FILES+= subshell4.0
+${PACKAGE}FILES+= unknown1.0
+${PACKAGE}FILES+= var-assign1.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/execution/Makefile.depend b/shell_cmds/sh/tests/execution/Makefile.depend
new file mode 100644
index 0000000..fac3607
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/execution/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# 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/shell_cmds/sh/tests/execution/bg1.0 b/shell_cmds/sh/tests/execution/bg1.0
new file mode 100644
index 0000000..95b51c6
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg1.0 221027 2011-04-25 20:54:12Z jilles $
+
+: `false` &
diff --git a/shell_cmds/sh/tests/execution/bg10.0 b/shell_cmds/sh/tests/execution/bg10.0
new file mode 100644
index 0000000..06a27f4
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg10.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg10.0 258535 2013-11-24 23:12:13Z jilles $
+# The redirection overrides the </dev/null implicit in a background command.
+
+echo yes | ${SH} -c '{ cat & wait; } <&0'
diff --git a/shell_cmds/sh/tests/execution/bg10.0.stdout b/shell_cmds/sh/tests/execution/bg10.0.stdout
new file mode 100644
index 0000000..7cfab5b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg10.0.stdout
@@ -0,0 +1 @@
+yes
diff --git a/shell_cmds/sh/tests/execution/bg2.0 b/shell_cmds/sh/tests/execution/bg2.0
new file mode 100644
index 0000000..74ee54a
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg2.0 221027 2011-04-25 20:54:12Z jilles $
+
+f() { return 42; }
+f
+: | : &
diff --git a/shell_cmds/sh/tests/execution/bg3.0 b/shell_cmds/sh/tests/execution/bg3.0
new file mode 100644
index 0000000..95f37d3
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg3.0 221027 2011-04-25 20:54:12Z jilles $
+
+f() { return 42; }
+f
+(:) &
diff --git a/shell_cmds/sh/tests/execution/bg4.0 b/shell_cmds/sh/tests/execution/bg4.0
new file mode 100644
index 0000000..1220fd3
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg4.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg4.0 223283 2011-06-19 00:00:36Z jilles $
+
+x=''
+: ${x:=1} &
+wait
+exit ${x:-0}
diff --git a/shell_cmds/sh/tests/execution/bg5.0 b/shell_cmds/sh/tests/execution/bg5.0
new file mode 100644
index 0000000..e820035
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg5.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg5.0 258489 2013-11-22 21:50:13Z jilles $
+# A background command has an implicit </dev/null redirection.
+
+echo bad | ${SH} -c '{ cat & wait; }'
diff --git a/shell_cmds/sh/tests/execution/bg6.0 b/shell_cmds/sh/tests/execution/bg6.0
new file mode 100644
index 0000000..466adc2
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg6.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg6.0 258489 2013-11-22 21:50:13Z jilles $
+# The redirection overrides the </dev/null implicit in a background command.
+
+echo yes | ${SH} -c '{ cat & wait; } </dev/stdin'
diff --git a/shell_cmds/sh/tests/execution/bg6.0.stdout b/shell_cmds/sh/tests/execution/bg6.0.stdout
new file mode 100644
index 0000000..7cfab5b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg6.0.stdout
@@ -0,0 +1 @@
+yes
diff --git a/shell_cmds/sh/tests/execution/bg7.0 b/shell_cmds/sh/tests/execution/bg7.0
new file mode 100644
index 0000000..788161e
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg7.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg7.0 258533 2013-11-24 22:45:49Z jilles $
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c '</dev/null; { cat & wait; }'
diff --git a/shell_cmds/sh/tests/execution/bg8.0 b/shell_cmds/sh/tests/execution/bg8.0
new file mode 100644
index 0000000..aa571dc
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg8.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg8.0 258533 2013-11-24 22:45:49Z jilles $
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c 'command eval \) </dev/null 2>/dev/null; { cat & wait; }'
diff --git a/shell_cmds/sh/tests/execution/bg9.0 b/shell_cmds/sh/tests/execution/bg9.0
new file mode 100644
index 0000000..4af1bae
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/bg9.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/bg9.0 258533 2013-11-24 22:45:49Z jilles $
+# The redirection does not apply to the background command, and therefore
+# does not override the implicit </dev/null.
+
+echo bad | ${SH} -c 'command eval eval \\\) \</dev/null 2>/dev/null; { cat & wait; }'
diff --git a/shell_cmds/sh/tests/execution/fork1.0 b/shell_cmds/sh/tests/execution/fork1.0
new file mode 100644
index 0000000..80b013b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/fork1.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/execution/fork1.0 218850 2011-02-19 13:22:18Z jilles $
+
+shname=${SH%% *}
+shname=${shname##*/}
+
+result=$(${SH} -c 'ps -p $$ -o comm=')
+test "$result" = "ps" || exit 1
+
+result=$(${SH} -c 'ps -p $$ -o comm=; :')
+test "$result" = "$shname" || exit 1
diff --git a/shell_cmds/sh/tests/execution/fork2.0 b/shell_cmds/sh/tests/execution/fork2.0
new file mode 100644
index 0000000..2639165
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/fork2.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/execution/fork2.0 213738 2010-10-12 18:20:38Z obrien $
+
+result=$(${SH} -c '(/bin/sleep 1)& sleep 0.1; ps -p $! -o comm=; kill $!')
+test "$result" = sleep || exit 1
+
+result=$(${SH} -c '{ trap "echo trapped" EXIT; (/usr/bin/true); } & wait')
+test "$result" = trapped || exit 1
+
+exit 0
diff --git a/shell_cmds/sh/tests/execution/fork3.0 b/shell_cmds/sh/tests/execution/fork3.0
new file mode 100644
index 0000000..008be7b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/fork3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/fork3.0 220978 2011-04-23 22:28:56Z jilles $
+
+result=$(${SH} -c 'f() { ps -p $$ -o comm=; }; f')
+test "$result" = "ps"
diff --git a/shell_cmds/sh/tests/execution/func1.0 b/shell_cmds/sh/tests/execution/func1.0
new file mode 100644
index 0000000..1af5495
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/func1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/func1.0 213738 2010-10-12 18:20:38Z obrien $
+
+MALLOC_OPTIONS=J ${SH} -c 'g() { g() { :; }; :; }; g' &&
+MALLOC_OPTIONS=J ${SH} -c 'g() { unset -f g; :; }; g'
diff --git a/shell_cmds/sh/tests/execution/func2.0 b/shell_cmds/sh/tests/execution/func2.0
new file mode 100644
index 0000000..eb48cc8
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/func2.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/execution/func2.0 211399 2010-08-16 17:18:08Z jilles $
+# The empty pairs of braces here are to test that this does not cause a crash.
+
+f() { }
+f
+hash -v f >/dev/null
+f() { { }; }
+f
+hash -v f >/dev/null
+f() { { } }
+f
+hash -v f >/dev/null
diff --git a/shell_cmds/sh/tests/execution/func3.0 b/shell_cmds/sh/tests/execution/func3.0
new file mode 100644
index 0000000..209e255
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/func3.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/execution/func3.0 216398 2010-12-12 21:18:16Z jilles $
+
+# This may fail when parsing or when defining the function, or the definition
+# may silently do nothing. In no event may the function be executed.
+
+${SH} -c 'unset() { echo overriding function executed, bad; }; v=1; unset v; exit "${v-0}"' 2>/dev/null
+:
diff --git a/shell_cmds/sh/tests/execution/hash1.0 b/shell_cmds/sh/tests/execution/hash1.0
new file mode 100644
index 0000000..d019296
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/hash1.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/execution/hash1.0 218323 2011-02-05 14:01:46Z jilles $
+
+T=`mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX"` || exit
+trap 'rm -rf "${T}"' 0
+PATH=$T:$PATH
+ls -ld . >/dev/null
+cat <<EOF >"$T/ls"
+:
+EOF
+chmod 755 "$T/ls"
+PATH=$PATH
+ls -ld .
diff --git a/shell_cmds/sh/tests/execution/int-cmd1.0 b/shell_cmds/sh/tests/execution/int-cmd1.0
new file mode 100644
index 0000000..e980461
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/int-cmd1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/int-cmd1.0 253271 2013-07-12 15:29:41Z jilles $
+
+! echo echo bad | $SH -ic 'fi' 2>/dev/null
diff --git a/shell_cmds/sh/tests/execution/killed1.0 b/shell_cmds/sh/tests/execution/killed1.0
new file mode 100644
index 0000000..ef9221d
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/killed1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/execution/killed1.0 217557 2011-01-18 21:18:31Z jilles $
+# Sometimes the "Killed" message is not flushed soon enough and it
+# is redirected along with the output of a builtin.
+# Do not change the semicolon to a newline as it would hide the bug.
+
+exec 3>&1
+exec >/dev/null 2>&1
+${SH} -c 'kill -9 $$'; : >&3 2>&3
diff --git a/shell_cmds/sh/tests/execution/killed2.0 b/shell_cmds/sh/tests/execution/killed2.0
new file mode 100644
index 0000000..4d6de16
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/killed2.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/execution/killed2.0 218105 2011-01-30 22:57:52Z jilles $
+# Most shells print a message when a foreground job is killed by a signal.
+# POSIX allows this, provided the message is sent to stderr, not stdout.
+# Some trickery is needed to capture the message as redirecting stderr of
+# the command itself does not affect it. The colon command ensures that
+# the subshell forks for ${SH}.
+
+exec 3>&1
+r=`(${SH} -c 'kill $$'; :) 2>&1 >&3`
+[ -n "$r" ]
diff --git a/shell_cmds/sh/tests/execution/not1.0 b/shell_cmds/sh/tests/execution/not1.0
new file mode 100644
index 0000000..c825e13
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/not1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/not1.0 249407 2013-04-12 15:19:35Z jilles $
+
+f() { ! return $1; }
+f 0 && ! f 1
diff --git a/shell_cmds/sh/tests/execution/not2.0 b/shell_cmds/sh/tests/execution/not2.0
new file mode 100644
index 0000000..e4155a9
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/not2.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/execution/not2.0 249407 2013-04-12 15:19:35Z jilles $
+
+while :; do
+ ! break
+ exit 3
+done
diff --git a/shell_cmds/sh/tests/execution/path1.0 b/shell_cmds/sh/tests/execution/path1.0
new file mode 100644
index 0000000..3d5c67b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/path1.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/execution/path1.0 217206 2011-01-09 21:07:30Z jilles $
+# Some builtins should not be overridable via PATH.
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf ${T}' 0
+echo '#!/bin/sh
+echo bad' >"$T/cd"
+chmod 755 "$T/cd"
+cd /bin
+oPATH=$PATH
+PATH=$T:$PATH:%builtin
+cd /
+PATH=$oPATH
+[ "$(pwd)" = / ]
diff --git a/shell_cmds/sh/tests/execution/redir1.0 b/shell_cmds/sh/tests/execution/redir1.0
new file mode 100644
index 0000000..6310478
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir1.0
@@ -0,0 +1,27 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir1.0 211408 2010-08-16 22:23:19Z jilles $
+trap ': $((brokenpipe+=1))' PIPE
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+brokenpipe=0
+mkfifo fifo1 fifo2
+read dummy >fifo2 <fifo1 &
+{
+ exec 4>fifo2
+} 3<fifo2 # Formerly, sh would keep fd 3 and a duplicate of it open.
+echo dummy >fifo1
+if [ $brokenpipe -ne 0 ]; then
+ rc=3
+fi
+wait
+echo dummy >&4 2>/dev/null
+if [ $brokenpipe -eq 1 ]; then
+ : ${rc:=0}
+fi
+
+rm fifo1 fifo2
+rmdir ${P}/${T}
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/execution/redir2.0 b/shell_cmds/sh/tests/execution/redir2.0
new file mode 100644
index 0000000..27509c7
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir2.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir2.0 213738 2010-10-12 18:20:38Z obrien $
+trap ': $((brokenpipe+=1))' PIPE
+
+P=${TMPDIR:-/tmp}
+cd $P
+T=$(mktemp -d sh-test.XXXXXX)
+cd $T
+
+brokenpipe=0
+mkfifo fifo1 fifo2
+{
+ {
+ exec ${SH} -c 'exec <fifo1; read dummy'
+ } 7<&- # fifo2 should be kept open, but not passed to programs
+ true
+} 7<fifo2 &
+
+exec 4>fifo2
+exec 3>fifo1
+echo dummy >&4 2>/dev/null
+if [ $brokenpipe -eq 1 ]; then
+ : ${rc:=0}
+fi
+echo dummy >&3
+wait
+
+rm fifo1 fifo2
+rmdir ${P}/${T}
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/execution/redir3.0 b/shell_cmds/sh/tests/execution/redir3.0
new file mode 100644
index 0000000..1b72098
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir3.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir3.0 214289 2010-10-24 19:56:34Z jilles $
+
+3>&- 3>&-
diff --git a/shell_cmds/sh/tests/execution/redir4.0 b/shell_cmds/sh/tests/execution/redir4.0
new file mode 100644
index 0000000..01b1f87
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir4.0 214290 2010-10-24 20:09:49Z jilles $
+
+{ echo bad 0>&3; } 2>/dev/null 3>/dev/null 3>&-
+exit 0
diff --git a/shell_cmds/sh/tests/execution/redir5.0 b/shell_cmds/sh/tests/execution/redir5.0
new file mode 100644
index 0000000..346c132
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir5.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir5.0 218325 2011-02-05 15:02:19Z jilles $
+
+{ (echo bad) >/dev/null; } </dev/null
diff --git a/shell_cmds/sh/tests/execution/redir6.0 b/shell_cmds/sh/tests/execution/redir6.0
new file mode 100644
index 0000000..f663e51
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir6.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir6.0 220978 2011-04-23 22:28:56Z jilles $
+
+failures=0
+
+check() {
+ if [ "$2" != "$3" ]; then
+ echo "Failure at $1" >&2
+ failures=$((failures + 1))
+ fi
+}
+
+check $LINENO "$(trap "echo bye" EXIT; : >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; { :; } >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; (:) >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; (: >/dev/null))" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; : >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; { :; } >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; (:) >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; (: >/dev/null)')" bye
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/execution/redir7.0 b/shell_cmds/sh/tests/execution/redir7.0
new file mode 100644
index 0000000..0e309a7
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/redir7.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/execution/redir7.0 220978 2011-04-23 22:28:56Z jilles $
+
+failures=0
+
+check() {
+ if [ "$2" != "$3" ]; then
+ echo "Failure at $1" >&2
+ failures=$((failures + 1))
+ fi
+}
+
+check $LINENO "$(trap "echo bye" EXIT; f() { :; }; f >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; f() { :; }; { f; } >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; f() { :; }; (f) >/dev/null)" bye
+check $LINENO "$(trap "echo bye" EXIT; f() { :; }; (f >/dev/null))" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; f >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; { f; } >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; (f) >/dev/null')" bye
+check $LINENO "$(${SH} -c 'trap "echo bye" EXIT; f() { :; }; (f >/dev/null)')" bye
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/execution/set-C1.0 b/shell_cmds/sh/tests/execution/set-C1.0
new file mode 100644
index 0000000..b7d5a4c
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-C1.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-C1.0 308229 2016-11-02 22:33:37Z jilles $
+
+T=$(mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX") || exit
+trap 'rm -rf "$T"' 0
+
+set -C
+echo . >"$T/a" &&
+[ -s "$T/a" ] &&
+{ ! true >"$T/a"; } 2>/dev/null &&
+[ -s "$T/a" ] &&
+ln -s /dev/null "$T/b" &&
+true >"$T/b"
diff --git a/shell_cmds/sh/tests/execution/set-n1.0 b/shell_cmds/sh/tests/execution/set-n1.0
new file mode 100644
index 0000000..95eb98c
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-n1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-n1.0 222661 2011-06-03 21:17:42Z jilles $
+
+v=$( ($SH -n <<'EOF'
+for
+EOF
+) 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/execution/set-n2.0 b/shell_cmds/sh/tests/execution/set-n2.0
new file mode 100644
index 0000000..d64fcca
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-n2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-n2.0 222661 2011-06-03 21:17:42Z jilles $
+
+$SH -n <<'EOF'
+echo bad
+EOF
diff --git a/shell_cmds/sh/tests/execution/set-n3.0 b/shell_cmds/sh/tests/execution/set-n3.0
new file mode 100644
index 0000000..5af1bc4
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-n3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-n3.0 222661 2011-06-03 21:17:42Z jilles $
+
+v=$( ($SH -nc 'for') 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/execution/set-n4.0 b/shell_cmds/sh/tests/execution/set-n4.0
new file mode 100644
index 0000000..2904a34
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-n4.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-n4.0 222676 2011-06-04 11:28:42Z jilles $
+
+$SH -nc 'echo bad'
diff --git a/shell_cmds/sh/tests/execution/set-x1.0 b/shell_cmds/sh/tests/execution/set-x1.0
new file mode 100644
index 0000000..e498a3f
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-x1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-x1.0 222882 2011-06-08 21:58:19Z jilles $
+
+key='must_contain_this'
+{ r=`set -x; { : "$key"; } 2>&1 >/dev/null`; } 2>/dev/null
+case $r in
+*"$key"*) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/execution/set-x2.0 b/shell_cmds/sh/tests/execution/set-x2.0
new file mode 100644
index 0000000..42c66a6
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-x2.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-x2.0 222882 2011-06-08 21:58:19Z jilles $
+
+key='must contain this'
+PS4="$key+ "
+{ r=`set -x; { :; } 2>&1 >/dev/null`; } 2>/dev/null
+case $r in
+*"$key"*) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/execution/set-x3.0 b/shell_cmds/sh/tests/execution/set-x3.0
new file mode 100644
index 0000000..29a917e
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-x3.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-x3.0 222907 2011-06-09 23:12:23Z jilles $
+
+key='must contain this'
+PS4='$key+ '
+{ r=`set -x; { :; } 2>&1 >/dev/null`; } 2>/dev/null
+case $r in
+*"$key"*) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/execution/set-x4.0 b/shell_cmds/sh/tests/execution/set-x4.0
new file mode 100644
index 0000000..90dd59a
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/set-x4.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/execution/set-x4.0 275766 2014-12-14 16:26:19Z jilles $
+
+key=`printf '\r\t\001\200\300'`
+r=`{ set -x; : "$key"; } 2>&1 >/dev/null`
+case $r in
+*[![:print:]]*) echo fail; exit 3
+esac
diff --git a/shell_cmds/sh/tests/execution/shellproc1.0 b/shell_cmds/sh/tests/execution/shellproc1.0
new file mode 100644
index 0000000..5150b73
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/shellproc1.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/execution/shellproc1.0 218205 2011-02-02 22:03:18Z jilles $
+
+T=`mktemp -d "${TMPDIR:-/tmp}/sh-test.XXXXXXXX"` || exit
+trap 'rm -rf "${T}"' 0
+cat <<EOF >"$T/testshellproc"
+printf 'this '
+echo is a test
+EOF
+chmod 755 "$T/testshellproc"
+PATH=$T:$PATH
+[ "`testshellproc`" = "this is a test" ]
diff --git a/shell_cmds/sh/tests/execution/subshell1.0 b/shell_cmds/sh/tests/execution/subshell1.0
new file mode 100644
index 0000000..68b0123
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell1.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/execution/subshell1.0 245383 2013-01-13 19:39:13Z jilles $
+
+(eval "cd /
+v=$(printf %0100000d 1)
+echo \${#v}")
+echo end
diff --git a/shell_cmds/sh/tests/execution/subshell1.0.stdout b/shell_cmds/sh/tests/execution/subshell1.0.stdout
new file mode 100644
index 0000000..8c71af3
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell1.0.stdout
@@ -0,0 +1,2 @@
+100000
+end
diff --git a/shell_cmds/sh/tests/execution/subshell2.0 b/shell_cmds/sh/tests/execution/subshell2.0
new file mode 100644
index 0000000..2d87730
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell2.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/execution/subshell2.0 245383 2013-01-13 19:39:13Z jilles $
+
+f() {
+ x=2
+}
+(
+ x=1
+ f
+ [ "$x" = 2 ]
+)
diff --git a/shell_cmds/sh/tests/execution/subshell3.0 b/shell_cmds/sh/tests/execution/subshell3.0
new file mode 100644
index 0000000..697ee0b
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/execution/subshell3.0 245383 2013-01-13 19:39:13Z jilles $
+
+(false; exit) && exit 3
+exit 0
diff --git a/shell_cmds/sh/tests/execution/subshell4.0 b/shell_cmds/sh/tests/execution/subshell4.0
new file mode 100644
index 0000000..009db3d
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/subshell4.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/subshell4.0 245383 2013-01-13 19:39:13Z jilles $
+
+(eval "set v=1"; false) && echo bad; :
diff --git a/shell_cmds/sh/tests/execution/unknown1.0 b/shell_cmds/sh/tests/execution/unknown1.0
new file mode 100644
index 0000000..dd4149e
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/unknown1.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/execution/unknown1.0 197820 2009-10-06 22:00:14Z jilles $
+
+nosuchtool 2>/dev/null
+[ $? -ne 127 ] && exit 1
+/var/empty/nosuchtool 2>/dev/null
+[ $? -ne 127 ] && exit 1
+(nosuchtool) 2>/dev/null
+[ $? -ne 127 ] && exit 1
+(/var/empty/nosuchtool) 2>/dev/null
+[ $? -ne 127 ] && exit 1
+/ 2>/dev/null
+[ $? -ne 126 ] && exit 1
+PATH=/usr bin 2>/dev/null
+[ $? -ne 126 ] && exit 1
+
+dummy=$(nosuchtool 2>/dev/null)
+[ $? -ne 127 ] && exit 1
+dummy=$(/var/empty/nosuchtool 2>/dev/null)
+[ $? -ne 127 ] && exit 1
+dummy=$( (nosuchtool) 2>/dev/null)
+[ $? -ne 127 ] && exit 1
+dummy=$( (/var/empty/nosuchtool) 2>/dev/null)
+[ $? -ne 127 ] && exit 1
+dummy=$(/ 2>/dev/null)
+[ $? -ne 126 ] && exit 1
+dummy=$(PATH=/usr bin 2>/dev/null)
+[ $? -ne 126 ] && exit 1
+
+exit 0
diff --git a/shell_cmds/sh/tests/execution/var-assign1.0 b/shell_cmds/sh/tests/execution/var-assign1.0
new file mode 100644
index 0000000..b75f969
--- /dev/null
+++ b/shell_cmds/sh/tests/execution/var-assign1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/execution/var-assign1.0 212467 2010-09-11 14:15:50Z jilles $
+
+[ "$(HOME=/etc HOME=/ cd && pwd)" = / ]
diff --git a/shell_cmds/sh/tests/expansion/Makefile b/shell_cmds/sh/tests/expansion/Makefile
new file mode 100644
index 0000000..1c44a55
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/Makefile
@@ -0,0 +1,105 @@
+# $FreeBSD: head/bin/sh/tests/expansion/Makefile 317514 2017-04-27 18:52:18Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= arith1.0
+${PACKAGE}FILES+= arith2.0
+${PACKAGE}FILES+= arith3.0
+${PACKAGE}FILES+= arith4.0
+${PACKAGE}FILES+= arith5.0
+${PACKAGE}FILES+= arith6.0
+${PACKAGE}FILES+= arith7.0
+${PACKAGE}FILES+= arith8.0
+${PACKAGE}FILES+= arith9.0
+${PACKAGE}FILES+= arith10.0
+${PACKAGE}FILES+= arith11.0
+${PACKAGE}FILES+= arith12.0
+${PACKAGE}FILES+= arith13.0
+${PACKAGE}FILES+= arith14.0
+${PACKAGE}FILES+= assign1.0
+${PACKAGE}FILES+= cmdsubst1.0
+${PACKAGE}FILES+= cmdsubst2.0
+${PACKAGE}FILES+= cmdsubst3.0
+${PACKAGE}FILES+= cmdsubst4.0
+${PACKAGE}FILES+= cmdsubst5.0
+${PACKAGE}FILES+= cmdsubst6.0
+${PACKAGE}FILES+= cmdsubst7.0
+${PACKAGE}FILES+= cmdsubst8.0
+${PACKAGE}FILES+= cmdsubst9.0
+${PACKAGE}FILES+= cmdsubst10.0
+${PACKAGE}FILES+= cmdsubst11.0
+${PACKAGE}FILES+= cmdsubst12.0
+${PACKAGE}FILES+= cmdsubst13.0
+${PACKAGE}FILES+= cmdsubst14.0
+${PACKAGE}FILES+= cmdsubst15.0
+${PACKAGE}FILES+= cmdsubst16.0
+${PACKAGE}FILES+= cmdsubst17.0
+${PACKAGE}FILES+= cmdsubst18.0
+${PACKAGE}FILES+= cmdsubst19.0
+${PACKAGE}FILES+= cmdsubst20.0
+${PACKAGE}FILES+= cmdsubst21.0
+${PACKAGE}FILES+= cmdsubst22.0
+${PACKAGE}FILES+= cmdsubst23.0
+${PACKAGE}FILES+= cmdsubst24.0
+${PACKAGE}FILES+= cmdsubst25.0
+${PACKAGE}FILES+= cmdsubst26.0
+${PACKAGE}FILES+= export1.0
+${PACKAGE}FILES+= export2.0
+${PACKAGE}FILES+= export3.0
+${PACKAGE}FILES+= heredoc1.0
+${PACKAGE}FILES+= heredoc2.0
+${PACKAGE}FILES+= ifs1.0
+${PACKAGE}FILES+= ifs2.0
+${PACKAGE}FILES+= ifs3.0
+${PACKAGE}FILES+= ifs4.0
+${PACKAGE}FILES+= ifs5.0
+${PACKAGE}FILES+= ifs6.0
+${PACKAGE}FILES+= ifs7.0
+${PACKAGE}FILES+= length1.0
+${PACKAGE}FILES+= length2.0
+${PACKAGE}FILES+= length3.0
+${PACKAGE}FILES+= length4.0
+${PACKAGE}FILES+= length5.0
+${PACKAGE}FILES+= length6.0
+${PACKAGE}FILES+= length7.0
+${PACKAGE}FILES+= length8.0
+${PACKAGE}FILES+= local1.0
+${PACKAGE}FILES+= local2.0
+${PACKAGE}FILES+= pathname1.0
+${PACKAGE}FILES+= pathname2.0
+${PACKAGE}FILES+= pathname3.0
+${PACKAGE}FILES+= pathname4.0
+${PACKAGE}FILES+= pathname5.0
+${PACKAGE}FILES+= pathname6.0
+${PACKAGE}FILES+= plus-minus1.0
+${PACKAGE}FILES+= plus-minus2.0
+${PACKAGE}FILES+= plus-minus3.0
+${PACKAGE}FILES+= plus-minus4.0
+${PACKAGE}FILES+= plus-minus5.0
+${PACKAGE}FILES+= plus-minus6.0
+${PACKAGE}FILES+= plus-minus7.0
+${PACKAGE}FILES+= plus-minus8.0
+${PACKAGE}FILES+= question1.0
+${PACKAGE}FILES+= readonly1.0
+${PACKAGE}FILES+= redir1.0
+${PACKAGE}FILES+= set-u1.0
+${PACKAGE}FILES+= set-u2.0
+${PACKAGE}FILES+= set-u3.0
+${PACKAGE}FILES+= tilde1.0
+${PACKAGE}FILES+= tilde2.0
+${PACKAGE}FILES+= trim1.0
+${PACKAGE}FILES+= trim2.0
+${PACKAGE}FILES+= trim3.0
+${PACKAGE}FILES+= trim4.0
+${PACKAGE}FILES+= trim5.0
+${PACKAGE}FILES+= trim6.0
+${PACKAGE}FILES+= trim7.0
+${PACKAGE}FILES+= trim8.0
+${PACKAGE}FILES+= trim9.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/expansion/Makefile.depend b/shell_cmds/sh/tests/expansion/Makefile.depend
new file mode 100644
index 0000000..547cbb3
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/expansion/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# 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/shell_cmds/sh/tests/expansion/arith1.0 b/shell_cmds/sh/tests/expansion/arith1.0
new file mode 100644
index 0000000..c301600
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith1.0
@@ -0,0 +1,30 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith1.0 201259 2009-12-30 15:59:40Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+check "0&&0" 0
+check "1&&0" 0
+check "0&&1" 0
+check "1&&1" 1
+check "2&&2" 1
+check "1&&2" 1
+check "1<<40&&1<<40" 1
+check "1<<40&&4" 1
+
+check "0||0" 0
+check "1||0" 1
+check "0||1" 1
+check "1||1" 1
+check "2||2" 1
+check "1||2" 1
+check "1<<40||1<<40" 1
+check "1<<40||4" 1
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith10.0 b/shell_cmds/sh/tests/expansion/arith10.0
new file mode 100644
index 0000000..9e3db28
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith10.0
@@ -0,0 +1,35 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith10.0 218469 2011-02-08 23:23:55Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+readonly ro=4
+rw=1
+check "0 && 0 / 0" 0
+check "1 || 0 / 0" 1
+check "0 && (ro = 2)" 0
+check "ro" 4
+check "1 || (ro = -1)" 1
+check "ro" 4
+check "0 && (rw += 1)" 0
+check "rw" 1
+check "1 || (rw += 1)" 1
+check "rw" 1
+check "0 ? 44 / 0 : 51" 51
+check "0 ? ro = 3 : 52" 52
+check "ro" 4
+check "0 ? rw += 1 : 52" 52
+check "rw" 1
+check "1 ? 68 : 30 / 0" 68
+check "2 ? 1 : (ro += 2)" 1
+check "ro" 4
+check "4 ? 1 : (rw += 1)" 1
+check "rw" 1
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith11.0 b/shell_cmds/sh/tests/expansion/arith11.0
new file mode 100644
index 0000000..4a33831
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith11.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith11.0 218626 2011-02-12 23:44:05Z jilles $
+# Try to divide the smallest integer by -1.
+# On amd64 this causes SIGFPE, so make sure the shell checks.
+
+# Calculate the minimum possible value, assuming two's complement and
+# a certain interpretation of overflow when shifting left.
+minint=1
+while [ $((minint <<= 1)) -gt 0 ]; do
+ :
+done
+v=$( eval ': $((minint / -1))' 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/expansion/arith12.0 b/shell_cmds/sh/tests/expansion/arith12.0
new file mode 100644
index 0000000..7d79d7e
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith12.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith12.0 232839 2012-03-11 22:12:05Z jilles $
+
+_x=4 y_=5 z_z=6
+[ "$((_x*100+y_*10+z_z))" = 456 ]
diff --git a/shell_cmds/sh/tests/expansion/arith13.0 b/shell_cmds/sh/tests/expansion/arith13.0
new file mode 100644
index 0000000..5421cb0
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith13.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith13.0 254806 2013-08-24 20:06:00Z jilles $
+# Pre-increment and pre-decrement in arithmetic expansion are not in POSIX.
+# Require either an error or a correct implementation.
+
+! (eval 'x=4; [ $((++x)) != 5 ] || [ $x != 5 ]') 2>/dev/null &&
+! (eval 'x=2; [ $((--x)) != 1 ] || [ $x != 1 ]') 2>/dev/null
diff --git a/shell_cmds/sh/tests/expansion/arith14.0 b/shell_cmds/sh/tests/expansion/arith14.0
new file mode 100644
index 0000000..a51e916
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith14.0
@@ -0,0 +1,40 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith14.0 270029 2014-08-15 22:36:41Z jilles $
+# Check that <</>> use the low bits of the shift count.
+
+if [ $((1<<16<<16)) = 0 ]; then
+ width=32
+elif [ $((1<<32<<32)) = 0 ]; then
+ width=64
+elif [ $((1<<64<<64)) = 0 ]; then
+ width=128
+elif [ $((1<<64>>64)) = 1 ]; then
+ # Integers are wider than 128 bits; assume arbitrary precision.
+ # Nothing to test here.
+ exit 0
+else
+ echo "Cannot determine integer width"
+ exit 2
+fi
+
+twowidth=$((width * 2))
+j=43 k=$((1 << (width - 2))) r=0
+
+i=0
+while [ $i -lt $twowidth ]; do
+ if [ "$((j << i))" != "$((j << (i + width)))" ]; then
+ echo "Problem with $j << $i"
+ r=2
+ fi
+ i=$((i + 1))
+done
+
+i=0
+while [ $i -lt $twowidth ]; do
+ if [ "$((k >> i))" != "$((k >> (i + width)))" ]; then
+ echo "Problem with $k >> $i"
+ r=2
+ fi
+ i=$((i + 1))
+done
+
+exit $r
diff --git a/shell_cmds/sh/tests/expansion/arith2.0 b/shell_cmds/sh/tests/expansion/arith2.0
new file mode 100644
index 0000000..b5874e5
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith2.0
@@ -0,0 +1,77 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith2.0 209652 2010-07-02 21:31:24Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+# variables
+unset v
+check "v=2" 2
+check "v" 2
+check "$(($v))" 2
+check "v+=1" 3
+check "v" 3
+
+# constants
+check "4611686018427387904" 4611686018427387904
+check "0x4000000000000000" 4611686018427387904
+check "0400000000000000000000" 4611686018427387904
+check "0x4Ab0000000000000" 5381801554707742720
+check "010" 8
+
+# try out all operators
+v=42
+check "!v" 0
+check "!!v" 1
+check "!0" 1
+check "~0" -1
+check "~(-1)" 0
+check "-0" 0
+check "-v" -42
+check "v*v" 1764
+check "v/2" 21
+check "v%10" 2
+check "v+v" 84
+check "v-4" 38
+check "v<<1" 84
+check "v>>1" 21
+check "v<43" 1
+check "v>42" 0
+check "v<=43" 1
+check "v>=43" 0
+check "v==41" 0
+check "v!=42" 0
+check "v&3" 2
+check "v^3" 41
+check "v|3" 43
+check "v>=40&&v<=44" 1
+check "v<40||v>44" 0
+check "(v=42)&&(v+=1)==43" 1
+check "v" 43
+check "(v=42)&&(v-=1)==41" 1
+check "v" 41
+check "(v=42)&&(v*=2)==84" 1
+check "v" 84
+check "(v=42)&&(v/=10)==4" 1
+check "v" 4
+check "(v=42)&&(v%=10)==2" 1
+check "v" 2
+check "(v=42)&&(v<<=1)==84" 1
+check "v" 84
+check "(v=42)&&(v>>=2)==10" 1
+check "v" 10
+check "(v=42)&&(v&=32)==32" 1
+check "v" 32
+check "(v=42)&&(v^=32)==10" 1
+check "v" 10
+check "(v=42)&&(v|=32)==42" 1
+check "v" 42
+
+# missing: ternary
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith3.0 b/shell_cmds/sh/tests/expansion/arith3.0
new file mode 100644
index 0000000..6b60b51
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith3.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith3.0 204017 2010-02-17 22:25:22Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+check "1 << 1 + 1 | 1" 5
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith4.0 b/shell_cmds/sh/tests/expansion/arith4.0
new file mode 100644
index 0000000..a41a0f7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith4.0
@@ -0,0 +1,20 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith4.0 206167 2010-04-04 16:29:48Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+check '20 / 2 / 2' 5
+check '20 - 2 - 2' 16
+unset a b c d
+check "a = b = c = d = 1" 1
+check "a == 1 && b == 1 && c == 1 && d == 1" 1
+check "a += b += c += d" 4
+check "a == 4 && b == 3 && c == 2 && d == 1" 1
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith5.0 b/shell_cmds/sh/tests/expansion/arith5.0
new file mode 100644
index 0000000..1cd021f
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith5.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith5.0 206168 2010-04-04 16:48:33Z jilles $
+
+failures=0
+
+check() {
+ if [ "$2" != "$3" ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $3 actual $2"
+ fi
+}
+
+unset a
+check '$((1+${a:-$((7+2))}))' "$((1+${a:-$((7+2))}))" 10
+check '$((1+${a:=$((2+2))}))' "$((1+${a:=$((2+2))}))" 5
+check '$a' "$a" 4
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/arith6.0 b/shell_cmds/sh/tests/expansion/arith6.0
new file mode 100644
index 0000000..528f4e8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith6.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith6.0 215550 2010-11-19 22:25:32Z jilles $
+
+v1=1\ +\ 1
+v2=D
+v3=C123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+f() { v4="$*"; }
+
+while [ ${#v2} -lt 1250 ]; do
+ eval $v2=$((3+${#v2})) $v3=$((4-${#v2}))
+ eval f $(($v2+ $v1 +$v3))
+ if [ $v4 -ne 9 ]; then
+ echo bad: $v4 -ne 9 at ${#v2}
+ fi
+ v2=x$v2
+ v3=y$v3
+done
diff --git a/shell_cmds/sh/tests/expansion/arith7.0 b/shell_cmds/sh/tests/expansion/arith7.0
new file mode 100644
index 0000000..f31dba1
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith7.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith7.0 216395 2010-12-12 16:56:16Z jilles $
+
+v=1+
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+[ "$(cat <<EOF
+$(($v 1))
+EOF
+)" = 1025 ]
diff --git a/shell_cmds/sh/tests/expansion/arith8.0 b/shell_cmds/sh/tests/expansion/arith8.0
new file mode 100644
index 0000000..e0739f8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith8.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith8.0 216547 2010-12-18 23:03:51Z jilles $
+
+v=$( (eval ': $((08))') 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/expansion/arith9.0 b/shell_cmds/sh/tests/expansion/arith9.0
new file mode 100644
index 0000000..e47d003
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/arith9.0
@@ -0,0 +1,20 @@
+# $FreeBSD: head/bin/sh/tests/expansion/arith9.0 218469 2011-02-08 23:23:55Z jilles $
+
+failures=0
+
+check() {
+ if [ $(($1)) != $2 ]; then
+ failures=$((failures+1))
+ echo "For $1, expected $2 actual $(($1))"
+ fi
+}
+
+check "0 ? 44 : 51" 51
+check "1 ? 68 : 30" 68
+check "2 ? 1 : -5" 1
+check "0 ? 4 : 0 ? 5 : 6" 6
+check "0 ? 4 : 1 ? 5 : 6" 5
+check "1 ? 4 : 0 ? 5 : 6" 4
+check "1 ? 4 : 1 ? 5 : 6" 4
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/assign1.0 b/shell_cmds/sh/tests/expansion/assign1.0
new file mode 100644
index 0000000..ee4c0d8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/assign1.0
@@ -0,0 +1,37 @@
+# $FreeBSD: head/bin/sh/tests/expansion/assign1.0 204842 2010-03-07 18:43:29Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'v=; set -- ${v=a b} $v' '0|'
+testcase 'unset v; set -- ${v=a b} $v' '4|a|b|a|b'
+testcase 'v=; set -- ${v:=a b} $v' '4|a|b|a|b'
+testcase 'v=; set -- "${v:=a b}" "$v"' '2|a b|a b'
+# expect sensible behaviour, although it disagrees with POSIX
+testcase 'v=; set -- ${v:=a\ b} $v' '4|a|b|a|b'
+testcase 'v=; set -- ${v:=$p} $v' '2|/etc/|/etc/'
+testcase 'v=; set -- "${v:=$p}" "$v"' '2|/et[c]/|/et[c]/'
+testcase 'v=; set -- "${v:=a\ b}" "$v"' '2|a\ b|a\ b'
+testcase 'v=; set -- ${v:="$p"} $v' '2|/etc/|/etc/'
+# whether $p is quoted or not shouldn't really matter
+testcase 'v=; set -- "${v:="$p"}" "$v"' '2|/et[c]/|/et[c]/'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst1.0 b/shell_cmds/sh/tests/expansion/cmdsubst1.0
new file mode 100644
index 0000000..ea89f42
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst1.0
@@ -0,0 +1,48 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst1.0 201366 2010-01-01 18:17:46Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(echo abcde)" = "abcde"'
+check '"$(echo abcde; :)" = "abcde"'
+
+check '"$(printf abcde)" = "abcde"'
+check '"$(printf abcde; :)" = "abcde"'
+
+# regular
+check '-n "$(umask)"'
+check '-n "$(umask; :)"'
+check '-n "$(umask 2>&1)"'
+check '-n "$(umask 2>&1; :)"'
+
+# special
+check '-n "$(times)"'
+check '-n "$(times; :)"'
+check '-n "$(times 2>&1)"'
+check '-n "$(times 2>&1; :)"'
+
+# regular
+check '".$(umask -@ 2>&1)." = ".umask: Illegal option -@."'
+check '".$(umask -@ 2>&1; :)." = ".umask: Illegal option -@."'
+check '".$({ umask -@; } 2>&1)." = ".umask: Illegal option -@."'
+
+# special
+check '".$(shift xyz 2>&1)." = ".shift: Illegal number: xyz."'
+check '".$(shift xyz 2>&1; :)." = ".shift: Illegal number: xyz."'
+check '".$({ shift xyz; } 2>&1)." = ".shift: Illegal number: xyz."'
+
+v=1
+check '-z "$(v=2 :)"'
+check '"$v" = 1'
+check '-z "$(v=3)"'
+check '"$v" = 1'
+check '"$(v=4 eval echo \$v)" = 4'
+check '"$v" = 1'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst10.0 b/shell_cmds/sh/tests/expansion/cmdsubst10.0
new file mode 100644
index 0000000..dc13d39
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst10.0
@@ -0,0 +1,51 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst10.0 216826 2010-12-30 22:33:55Z jilles $
+
+a1=$(alias)
+: $(alias testalias=abcd)
+a2=$(alias)
+[ "$a1" = "$a2" ] || echo Error at line $LINENO
+
+alias testalias2=abcd
+a1=$(alias)
+: $(unalias testalias2)
+a2=$(alias)
+[ "$a1" = "$a2" ] || echo Error at line $LINENO
+
+[ "$(command -V pwd)" = "$(command -V pwd; exit $?)" ] || echo Error at line $LINENO
+
+v=1
+: $(export v=2)
+[ "$v" = 1 ] || echo Error at line $LINENO
+
+rotest=1
+: $(readonly rotest=2)
+[ "$rotest" = 1 ] || echo Error at line $LINENO
+
+set +u
+: $(set -u)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+set +u
+: $(set -o nounset)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+set +u
+: $(command set -u)
+case $- in
+*u*) echo Error at line $LINENO ;;
+esac
+set +u
+
+umask 77
+u1=$(umask)
+: $(umask 022)
+u2=$(umask)
+[ "$u1" = "$u2" ] || echo Error at line $LINENO
+
+dummy=$(exit 3); [ $? -eq 3 ] || echo Error at line $LINENO
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst11.0 b/shell_cmds/sh/tests/expansion/cmdsubst11.0
new file mode 100644
index 0000000..cb035ae
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst11.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst11.0 223163 2011-06-16 21:50:28Z jilles $
+
+# Not required by POSIX but useful for efficiency.
+
+[ $$ = $(eval '${SH} -c echo\ \$PPID') ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst12.0 b/shell_cmds/sh/tests/expansion/cmdsubst12.0
new file mode 100644
index 0000000..4d330ef
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst12.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst12.0 230121 2012-01-14 23:10:18Z jilles $
+
+f() {
+ echo x$(printf foo >&2)y
+}
+[ "$(f 2>&1)" = "fooxy" ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst13.0 b/shell_cmds/sh/tests/expansion/cmdsubst13.0
new file mode 100644
index 0000000..d3fc399
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst13.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst13.0 230121 2012-01-14 23:10:18Z jilles $
+
+x=1 y=2
+[ "$(
+ case $((x+=1)) in
+ ($((y+=1))) echo bad1 ;;
+ ($((y-1))) echo $x.$y ;;
+ ($((y=2))) echo bad2 ;;
+ (*) echo bad3 ;;
+ esac
+)" = "2.3" ] || echo "Error at $LINENO"
+[ "$x.$y" = "1.2" ] || echo "Error at $LINENO"
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst14.0 b/shell_cmds/sh/tests/expansion/cmdsubst14.0
new file mode 100644
index 0000000..8a916af
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst14.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst14.0 245381 2013-01-13 19:19:40Z jilles $
+
+! v=`false
+
+`
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst15.0 b/shell_cmds/sh/tests/expansion/cmdsubst15.0
new file mode 100644
index 0000000..9599ef8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst15.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst15.0 245381 2013-01-13 19:19:40Z jilles $
+
+! v=`false;
+
+`
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst16.0 b/shell_cmds/sh/tests/expansion/cmdsubst16.0
new file mode 100644
index 0000000..2483601
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst16.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst16.0 245392 2013-01-13 22:35:51Z jilles $
+
+f() { return 3; }
+f
+[ `echo $?` = 3 ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst17.0 b/shell_cmds/sh/tests/expansion/cmdsubst17.0
new file mode 100644
index 0000000..d3a2b54
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst17.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst17.0 245422 2013-01-14 12:20:55Z jilles $
+
+f() { return 3; }
+f
+[ `echo $?; :` = 3 ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst18.0 b/shell_cmds/sh/tests/expansion/cmdsubst18.0
new file mode 100644
index 0000000..2c3a1be
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst18.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst18.0 314637 2017-03-03 22:46:20Z jilles $
+
+x=X
+unset n
+r=${x+$(echo a)}${x-$(echo b)}${n+$(echo c)}${n-$(echo d)}$(echo e)
+[ "$r" = aXde ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst19.0 b/shell_cmds/sh/tests/expansion/cmdsubst19.0
new file mode 100644
index 0000000..7813c88
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst19.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst19.0 314637 2017-03-03 22:46:20Z jilles $
+
+b=200 c=30 d=5 x=4
+r=$(echo a)$(($(echo b) + ${x+$(echo c)} + ${x-$(echo d)}))$(echo e)
+[ "$r" = a234e ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst2.0 b/shell_cmds/sh/tests/expansion/cmdsubst2.0
new file mode 100644
index 0000000..35453be
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst2.0
@@ -0,0 +1,43 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst2.0 205105 2010-03-12 23:23:46Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '`echo /et[c]/` = "/etc/"'
+check '`printf /var/empty%s /et[c]/` = "/var/empty/etc/"'
+check '"`echo /et[c]/`" = "/etc/"'
+check '`echo "/et[c]/"` = "/etc/"'
+check '`printf /var/empty%s "/et[c]/"` = "/var/empty/et[c]/"'
+check '`printf /var/empty/%s \"/et[c]/\"` = "/var/empty/\"/et[c]/\""'
+check '"`echo \"/et[c]/\"`" = "/et[c]/"'
+check '"`echo "/et[c]/"`" = "/et[c]/"'
+check '`echo $$` = $$'
+check '"`echo $$`" = $$'
+check '`echo \$\$` = $$'
+check '"`echo \$\$`" = $$'
+
+# Command substitutions consisting of a single builtin may be treated
+# differently.
+check '`:; echo /et[c]/` = "/etc/"'
+check '`:; printf /var/empty%s /et[c]/` = "/var/empty/etc/"'
+check '"`:; echo /et[c]/`" = "/etc/"'
+check '`:; echo "/et[c]/"` = "/etc/"'
+check '`:; printf /var/empty%s "/et[c]/"` = "/var/empty/et[c]/"'
+check '`:; printf /var/empty/%s \"/et[c]/\"` = "/var/empty/\"/et[c]/\""'
+check '"`:; echo \"/et[c]/\"`" = "/et[c]/"'
+check '"`:; echo "/et[c]/"`" = "/et[c]/"'
+check '`:; echo $$` = $$'
+check '"`:; echo $$`" = $$'
+check '`:; echo \$\$` = $$'
+check '"`:; echo \$\$`" = $$'
+
+check '`set -f; echo /et[c]/` = "/etc/"'
+check '"`set -f; echo /et[c]/`" = "/et[c]/"'
+
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst20.0 b/shell_cmds/sh/tests/expansion/cmdsubst20.0
new file mode 100644
index 0000000..a92eaac
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst20.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst20.0 314637 2017-03-03 22:46:20Z jilles $
+
+set -T
+trapped=''
+trap "trapped=x$trapped" USR1
+[ "x$(kill -USR1 $$)y" = xy ] && [ "$trapped" = x ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst21.0 b/shell_cmds/sh/tests/expansion/cmdsubst21.0
new file mode 100644
index 0000000..02f938f
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst21.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst21.0 314686 2017-03-04 22:58:34Z jilles $
+
+set -T
+trapped=''
+trap "trapped=x$trapped" TERM
+[ "x$($SH -c "kill $$")y" = xy ] && [ "$trapped" = x ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst22.0 b/shell_cmds/sh/tests/expansion/cmdsubst22.0
new file mode 100644
index 0000000..b33f6d5
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst22.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst22.0 314686 2017-03-04 22:58:34Z jilles $
+
+set -T
+trapped=''
+trap "trapped=x$trapped" TERM
+[ "x$(:; kill $$)y" = xy ] && [ "$trapped" = x ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst23.0 b/shell_cmds/sh/tests/expansion/cmdsubst23.0
new file mode 100644
index 0000000..54b087e
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst23.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst23.0 315005 2017-03-10 16:04:00Z jilles $
+
+unset n
+x=abcd
+[ "X${n#$(echo a)}X${x#$(echo ab)}X$(echo abc)X" = XXcdXabcX ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst24.0 b/shell_cmds/sh/tests/expansion/cmdsubst24.0
new file mode 100644
index 0000000..60da04a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst24.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst24.0 317347 2017-04-23 21:58:17Z jilles $
+# POSIX leaves the effect of NUL bytes in command substitution output
+# unspecified but we have always discarded them.
+
+failures=0
+
+check() {
+ if [ "$2" != "$3" ]; then
+ printf "Failed at line %s: got \"%s\" expected \"%s\"\n" "$1" "$2" "$3"
+ : $((failures += 1))
+ fi
+}
+
+fmt='\0a\0 \0b\0c d\0'
+assign_builtin=$(printf "$fmt")
+check "$LINENO" "$assign_builtin" "a bc d"
+assign_pipeline=$(printf "$fmt" | cat)
+check "$LINENO" "$assign_pipeline" "a bc d"
+set -- $(printf "$fmt") $(printf "$fmt" | cat) "$(printf "$fmt")" "$(printf "$fmt" | cat)"
+IFS=@
+splits="$*"
+check "$LINENO" "$splits" "a@bc@d@a@bc@d@a bc d@a bc d"
+
+[ "$failures" = 0 ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst25.0 b/shell_cmds/sh/tests/expansion/cmdsubst25.0
new file mode 100644
index 0000000..0654847
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst25.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst25.0 317514 2017-04-27 18:52:18Z jilles $
+
+IFS=' '
+set -- `printf '\n '`
+IFS=:
+[ "$*" = '
+' ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst26.0 b/shell_cmds/sh/tests/expansion/cmdsubst26.0
new file mode 100644
index 0000000..c0d600a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst26.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst26.0 317514 2017-04-27 18:52:18Z jilles $
+
+nl='
+'
+v=$nl`printf '\n'`
+[ "$v" = "$nl" ]
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst3.0 b/shell_cmds/sh/tests/expansion/cmdsubst3.0
new file mode 100644
index 0000000..221b11b
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst3.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst3.0 218819 2011-02-18 20:37:09Z jilles $
+
+unset LC_ALL
+export LC_CTYPE=en_US.ISO8859-1
+
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ e="$e\n\\$i$j$k"
+ done
+ done
+done
+e1=$(printf "$e")
+e2="$(printf "$e")"
+[ "${#e1}" = 510 ] || echo length bad
+[ "$e1" = "$e2" ] || echo e1 != e2
+[ "$e1" = "$(printf "$e")" ] || echo quoted bad
+IFS=
+[ "$e1" = $(printf "$e") ] || echo unquoted bad
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst4.0 b/shell_cmds/sh/tests/expansion/cmdsubst4.0
new file mode 100644
index 0000000..4d5a134
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst4.0 216747 2010-12-27 23:56:03Z jilles $
+
+exec 2>/dev/null
+! y=$(: </var/empty/nonexistent)
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst5.0 b/shell_cmds/sh/tests/expansion/cmdsubst5.0
new file mode 100644
index 0000000..70b4298
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst5.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst5.0 216761 2010-12-28 13:28:24Z jilles $
+
+unset v
+exec 2>/dev/null
+! y=$(: ${v?})
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst6.0 b/shell_cmds/sh/tests/expansion/cmdsubst6.0
new file mode 100644
index 0000000..0e47bce
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst6.0
@@ -0,0 +1,53 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst6.0 216763 2010-12-28 14:58:08Z jilles $
+# This tests if the cmdsubst optimization is still used if possible.
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+
+ unset v
+ eval "pid=\$(dummy=$code echo \$(\$SH -c echo\ \\\$PPID))"
+
+ if [ "$pid" = "$$" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "Failure for $code"
+ fi
+}
+
+unset v
+w=1
+testcase '$w'
+testcase '1${w+1}'
+testcase '1${w-1}'
+testcase '1${v+1}'
+testcase '1${v-1}'
+testcase '1${w:+1}'
+testcase '1${w:-1}'
+testcase '1${v:+1}'
+testcase '1${v:-1}'
+testcase '${w?}'
+testcase '${w:?}'
+testcase '${w#x}'
+testcase '${w##x}'
+testcase '${w%x}'
+testcase '${w%%x}'
+
+testcase '$((w))'
+testcase '$(((w+4)*2/3))'
+testcase '$((w==1))'
+testcase '$((w>=0 && w<=5 && w!=2))'
+testcase '$((${#w}))'
+testcase '$((${#IFS}))'
+testcase '$((${#w}>=1))'
+testcase '$(($$))'
+testcase '$(($#))'
+testcase '$(($?))'
+
+testcase '$(: $((w=4)))'
+testcase '$(: ${v=2})'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst7.0 b/shell_cmds/sh/tests/expansion/cmdsubst7.0
new file mode 100644
index 0000000..6b4cd1d
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst7.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst7.0 216778 2010-12-28 21:27:08Z jilles $
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+
+ unset v
+ eval ": \$($code)"
+
+ if [ "${v:+bad}" = "" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "Failure for $code"
+ fi
+}
+
+testcase ': ${v=0}'
+testcase ': ${v:=0}'
+testcase ': $((v=1))'
+testcase ': $((v+=1))'
+w='v=1'
+testcase ': $(($w))'
+testcase ': $((${$+v=1}))'
+testcase ': $((v${$+=1}))'
+testcase ': $((v $(echo =) 1))'
+testcase ': $(($(echo $w)))'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst8.0 b/shell_cmds/sh/tests/expansion/cmdsubst8.0
new file mode 100644
index 0000000..19ff803
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst8.0
@@ -0,0 +1,17 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst8.0 216819 2010-12-30 15:04:59Z jilles $
+# Not required by POSIX (although referenced in a non-normative section),
+# but possibly useful.
+
+: hi there &
+p=$!
+q=$(jobs -l $p)
+
+# Change tabs to spaces.
+set -f
+set -- $q
+r="$*"
+
+case $r in
+*" $p "*) ;;
+*) echo Pid missing; exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/expansion/cmdsubst9.0 b/shell_cmds/sh/tests/expansion/cmdsubst9.0
new file mode 100644
index 0000000..8bbf2b9
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/cmdsubst9.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/expansion/cmdsubst9.0 216819 2010-12-30 15:04:59Z jilles $
+
+set -e
+
+cd /
+dummy=$(cd /bin)
+[ "$(pwd)" = / ]
+
+v=1
+dummy=$(eval v=2)
+[ "$v" = 1 ]
diff --git a/shell_cmds/sh/tests/expansion/export1.0 b/shell_cmds/sh/tests/expansion/export1.0
new file mode 100644
index 0000000..3286fb9
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/export1.0
@@ -0,0 +1,13 @@
+# $FreeBSD: head/bin/sh/tests/expansion/export1.0 238430 2012-07-13 22:29:02Z jilles $
+
+w='@ vv=6'
+
+v=0 vv=0
+export \v=$w
+[ "$v" = "@" ] || echo "Expected @ got $v"
+[ "$vv" = "6" ] || echo "Expected 6 got $vv"
+
+HOME=/known/value
+
+export \v=~
+[ "$v" = \~ ] || echo "Expected ~ got $v"
diff --git a/shell_cmds/sh/tests/expansion/export2.0 b/shell_cmds/sh/tests/expansion/export2.0
new file mode 100644
index 0000000..e8862b8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/export2.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/expansion/export2.0 238468 2012-07-15 10:19:43Z jilles $
+
+w='@ @'
+check() {
+ [ "$v" = "$w" ] || echo "Expected $w got $v"
+}
+
+export v=$w
+check
+
+HOME=/known/value
+check() {
+ [ "$v" = ~ ] || echo "Expected $HOME got $v"
+}
+
+export v=~
+check
+
+check() {
+ [ "$v" = "x:$HOME" ] || echo "Expected x:$HOME got $v"
+}
+
+export v=x:~
+check
diff --git a/shell_cmds/sh/tests/expansion/export3.0 b/shell_cmds/sh/tests/expansion/export3.0
new file mode 100644
index 0000000..b82fcc1
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/export3.0
@@ -0,0 +1,30 @@
+# $FreeBSD: head/bin/sh/tests/expansion/export3.0 238468 2012-07-15 10:19:43Z jilles $
+
+w='@ @'
+check() {
+ [ "$v" = "$w" ] || echo "Expected $w got $v"
+}
+
+command export v=$w
+check
+command command export v=$w
+check
+
+HOME=/known/value
+check() {
+ [ "$v" = ~ ] || echo "Expected $HOME got $v"
+}
+
+command export v=~
+check
+command command export v=~
+check
+
+check() {
+ [ "$v" = "x:$HOME" ] || echo "Expected x:$HOME got $v"
+}
+
+command export v=x:~
+check
+command command export v=x:~
+check
diff --git a/shell_cmds/sh/tests/expansion/heredoc1.0 b/shell_cmds/sh/tests/expansion/heredoc1.0
new file mode 100644
index 0000000..94328c0
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/heredoc1.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/expansion/heredoc1.0 222715 2011-06-05 12:46:26Z jilles $
+
+f() { return $1; }
+
+[ `f 42; { cat; } <<EOF
+$?
+EOF
+` = 42 ] || echo compound command bad
+
+[ `f 42; (cat) <<EOF
+$?
+EOF
+` = 42 ] || echo subshell bad
+
+long=`printf %08192d 0`
+
+[ `f 42; { cat; } <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long compound command bad
+
+[ `f 42; (cat) <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long subshell bad
diff --git a/shell_cmds/sh/tests/expansion/heredoc2.0 b/shell_cmds/sh/tests/expansion/heredoc2.0
new file mode 100644
index 0000000..24c4cc6
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/heredoc2.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/expansion/heredoc2.0 222716 2011-06-05 14:13:15Z jilles $
+
+f() { return $1; }
+
+[ `f 42; cat <<EOF
+$?
+EOF
+` = 42 ] || echo simple command bad
+
+long=`printf %08192d 0`
+
+[ `f 42; cat <<EOF
+$long.$?
+EOF
+` = $long.42 ] || echo long simple command bad
diff --git a/shell_cmds/sh/tests/expansion/ifs1.0 b/shell_cmds/sh/tests/expansion/ifs1.0
new file mode 100644
index 0000000..4d5157a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs1.0
@@ -0,0 +1,35 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs1.0 194981 2009-06-25 17:36:08Z jilles $
+
+c=: e= s=' '
+failures=''
+ok=''
+
+check_result() {
+ if [ "x$2" = "x$3" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $1, expected $3 actual $2"
+ fi
+}
+
+IFS='
+'
+set -- a ''
+set -- "$@"
+check_result 'set -- "$@"' "($#)($1)($2)" "(2)(a)()"
+
+set -- a ''
+set -- "$@"$e
+check_result 'set -- "$@"$e' "($#)($1)($2)" "(2)(a)()"
+
+set -- a ''
+set -- "$@"$s
+check_result 'set -- "$@"$s' "($#)($1)($2)" "(2)(a)()"
+
+IFS="$c"
+set -- a ''
+set -- "$@"$c
+check_result 'set -- "$@"$c' "($#)($1)($2)" "(2)(a)()"
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/ifs2.0 b/shell_cmds/sh/tests/expansion/ifs2.0
new file mode 100644
index 0000000..3d71b52
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs2.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs2.0 211341 2010-08-15 17:14:05Z jilles $
+
+failures=0
+i=1
+set -f
+while [ "$i" -le 127 ]; do
+ # A different byte still in the range 1..127.
+ i2=$((i^2+(i==2)))
+ # Add a character to work around command substitution's removal of
+ # final newlines, then remove it again.
+ c=$(printf \\"$(printf %o@ "$i")")
+ c=${c%@}
+ c2=$(printf \\"$(printf %o@ "$i2")")
+ c2=${c2%@}
+ IFS=$c
+ set -- $c2$c$c2$c$c2
+ if [ "$#" -ne 3 ] || [ "$1" != "$c2" ] || [ "$2" != "$c2" ] ||
+ [ "$3" != "$c2" ]; then
+ echo "Bad results for separator $i (word $i2)" >&2
+ : $((failures += 1))
+ fi
+ i=$((i+1))
+done
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/ifs3.0 b/shell_cmds/sh/tests/expansion/ifs3.0
new file mode 100644
index 0000000..d034654
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs3.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs3.0 211622 2010-08-22 13:09:12Z jilles $
+
+failures=0
+unset LC_ALL
+export LC_CTYPE=en_US.ISO8859-1
+i=128
+set -f
+while [ "$i" -le 255 ]; do
+ i2=$((i^2))
+ c=$(printf \\"$(printf %o "$i")")
+ c2=$(printf \\"$(printf %o "$i2")")
+ IFS=$c
+ set -- $c2$c$c2$c$c2
+ if [ "$#" -ne 3 ] || [ "$1" != "$c2" ] || [ "$2" != "$c2" ] ||
+ [ "$3" != "$c2" ]; then
+ echo "Bad results for separator $i (word $i2)" >&2
+ : $((failures += 1))
+ fi
+ i=$((i+1))
+done
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/ifs4.0 b/shell_cmds/sh/tests/expansion/ifs4.0
new file mode 100644
index 0000000..a307ec5
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs4.0
@@ -0,0 +1,39 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs4.0 222361 2011-05-27 15:56:13Z jilles $
+
+c=: e= s=' '
+failures=''
+ok=''
+
+check_result() {
+ if [ "x$2" = "x$3" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $1, expected $3 actual $2"
+ fi
+}
+
+IFS='
+'
+set -- a b '' c
+set -- $@
+check_result 'set -- $@' "($#)($1)($2)($3)($4)" "(3)(a)(b)(c)()"
+
+IFS=''
+set -- a b '' c
+set -- $@
+check_result 'set -- $@' "($#)($1)($2)($3)($4)" "(3)(a)(b)(c)()"
+
+set -- a b '' c
+set -- $*
+check_result 'set -- $*' "($#)($1)($2)($3)($4)" "(3)(a)(b)(c)()"
+
+set -- a b '' c
+set -- "$@"
+check_result 'set -- "$@"' "($#)($1)($2)($3)($4)" "(4)(a)(b)()(c)"
+
+set -- a b '' c
+set -- "$*"
+check_result 'set -- "$*"' "($#)($1)($2)($3)($4)" "(1)(abc)()()()"
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/ifs5.0 b/shell_cmds/sh/tests/expansion/ifs5.0
new file mode 100644
index 0000000..fc5b4b7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs5.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs5.0 278806 2015-02-15 19:48:29Z jilles $
+
+set -- $(echo a b c d)
+[ "$#" = 4 ]
diff --git a/shell_cmds/sh/tests/expansion/ifs6.0 b/shell_cmds/sh/tests/expansion/ifs6.0
new file mode 100644
index 0000000..3ec5dbc
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs6.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs6.0 280920 2015-03-31 20:59:37Z jilles $
+
+IFS=': '
+x=': :'
+set -- $x
+[ "$#|$1|$2|$3" = "2|||" ]
diff --git a/shell_cmds/sh/tests/expansion/ifs7.0 b/shell_cmds/sh/tests/expansion/ifs7.0
new file mode 100644
index 0000000..a59f313
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/ifs7.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/ifs7.0 280920 2015-03-31 20:59:37Z jilles $
+
+IFS=2
+set -- $((123))
+[ "$#|$1|$2|$3" = "2|1|3|" ]
diff --git a/shell_cmds/sh/tests/expansion/length1.0 b/shell_cmds/sh/tests/expansion/length1.0
new file mode 100644
index 0000000..cee5808
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length1.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length1.0 219611 2011-03-13 16:20:38Z jilles $
+
+v=abcd
+[ "${#v}" = 4 ] || echo '${#v} wrong'
+v=$$
+[ "${#$}" = "${#v}" ] || echo '${#$} wrong'
+[ "${#!}" = 0 ] || echo '${#!} wrong'
+set -- 01 2 3 4 5 6 7 8 9 10 11 12 0013
+[ "${#1}" = 2 ] || echo '${#1} wrong'
+[ "${#13}" = 4 ] || echo '${#13} wrong'
+v=$0
+[ "${#0}" = "${#v}" ] || echo '${#0} wrong'
diff --git a/shell_cmds/sh/tests/expansion/length2.0 b/shell_cmds/sh/tests/expansion/length2.0
new file mode 100644
index 0000000..77fd6ad
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length2.0 219611 2011-03-13 16:20:38Z jilles $
+
+v=$-
+[ "${#-}" = "${#v}" ] || echo '${#-} wrong'
diff --git a/shell_cmds/sh/tests/expansion/length3.0 b/shell_cmds/sh/tests/expansion/length3.0
new file mode 100644
index 0000000..27045b7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length3.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length3.0 219611 2011-03-13 16:20:38Z jilles $
+
+set -- 1 2 3 4 5 6 7 8 9 10 11 12 13
+[ "$#" = 13 ] || echo '$# wrong'
+[ "${#}" = 13 ] || echo '${#} wrong'
+[ "${##}" = 2 ] || echo '${##} wrong'
+set --
+[ "$#" = 0 ] || echo '$# wrong'
+[ "${#}" = 0 ] || echo '${#} wrong'
+[ "${##}" = 1 ] || echo '${##} wrong'
diff --git a/shell_cmds/sh/tests/expansion/length4.0 b/shell_cmds/sh/tests/expansion/length4.0
new file mode 100644
index 0000000..c1ff021
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length4.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length4.0 220655 2011-04-15 15:26:05Z jilles $
+
+# The construct ${#?} is ambiguous in POSIX.1-2008: it could be the length
+# of $? or it could be $# giving an error in the (impossible) case that it
+# is not set.
+# We use the former interpretation; it seems more useful.
+
+:
+[ "${#?}" = 1 ] || echo '${#?} wrong'
+(exit 42)
+[ "${#?}" = 2 ] || echo '${#?} wrong'
diff --git a/shell_cmds/sh/tests/expansion/length5.0 b/shell_cmds/sh/tests/expansion/length5.0
new file mode 100644
index 0000000..da8ebb5
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length5.0
@@ -0,0 +1,27 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length5.0 220656 2011-04-15 15:33:24Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ e="$e\\$i$j$k"
+ done
+ done
+done
+ee=`printf "$e"`
+[ ${#ee} = 255 ] || echo bad 1
+[ "${#ee}" = 255 ] || echo bad 2
+[ $((${#ee})) = 255 ] || echo bad 3
+[ "$((${#ee}))" = 255 ] || echo bad 4
+set -- "$ee"
+[ ${#1} = 255 ] || echo bad 5
+[ "${#1}" = 255 ] || echo bad 6
+[ $((${#1})) = 255 ] || echo bad 7
+[ "$((${#1}))" = 255 ] || echo bad 8
diff --git a/shell_cmds/sh/tests/expansion/length6.0 b/shell_cmds/sh/tests/expansion/length6.0
new file mode 100644
index 0000000..8da2da8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length6.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length6.0 220903 2011-04-20 22:24:54Z jilles $
+
+x='!@#$%^&*()[]'
+[ ${#x} = 12 ] || echo bad 1
+[ "${#x}" = 12 ] || echo bad 2
+IFS=2
+[ ${#x} = 1 ] || echo bad 3
+[ "${#x}" = 12 ] || echo bad 4
diff --git a/shell_cmds/sh/tests/expansion/length7.0 b/shell_cmds/sh/tests/expansion/length7.0
new file mode 100644
index 0000000..500b7e7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length7.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length7.0 221602 2011-05-07 14:32:16Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.UTF-8
+export LC_CTYPE
+
+# a umlaut
+s=$(printf '\303\244')
+# euro sign
+s=$s$(printf '\342\202\254')
+# some sort of 't' outside BMP
+s=$s$(printf '\360\235\225\245')
+set -- "$s"
+[ ${#s} = 3 ] && [ ${#1} = 3 ]
diff --git a/shell_cmds/sh/tests/expansion/length8.0 b/shell_cmds/sh/tests/expansion/length8.0
new file mode 100644
index 0000000..d4f91d8
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/length8.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/expansion/length8.0 221602 2011-05-07 14:32:16Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+# a umlaut
+s=$(printf '\303\244')
+# euro sign
+s=$s$(printf '\342\202\254')
+# some sort of 't' outside BMP
+s=$s$(printf '\360\235\225\245')
+set -- "$s"
+[ ${#s} = 9 ] && [ ${#1} = 9 ]
diff --git a/shell_cmds/sh/tests/expansion/local1.0 b/shell_cmds/sh/tests/expansion/local1.0
new file mode 100644
index 0000000..9f16eb0
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/local1.0
@@ -0,0 +1,28 @@
+# $FreeBSD: head/bin/sh/tests/expansion/local1.0 238468 2012-07-15 10:19:43Z jilles $
+
+run_test() {
+ w='@ @'
+ check() {
+ [ "$v" = "$w" ] || echo "Expected $w got $v"
+ }
+
+ local v=$w
+ check
+
+ HOME=/known/value
+ check() {
+ [ "$v" = ~ ] || echo "Expected $HOME got $v"
+ }
+
+ local v=~
+ check
+
+ check() {
+ [ "$v" = "x:$HOME" ] || echo "Expected x:$HOME got $v"
+ }
+
+ local v=x:~
+ check
+}
+
+run_test
diff --git a/shell_cmds/sh/tests/expansion/local2.0 b/shell_cmds/sh/tests/expansion/local2.0
new file mode 100644
index 0000000..9d1a38a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/local2.0
@@ -0,0 +1,34 @@
+# $FreeBSD: head/bin/sh/tests/expansion/local2.0 238468 2012-07-15 10:19:43Z jilles $
+
+run_test() {
+ w='@ @'
+ check() {
+ [ "$v" = "$w" ] || echo "Expected $w got $v"
+ }
+
+ command local v=$w
+ check
+ command command local v=$w
+ check
+
+ HOME=/known/value
+ check() {
+ [ "$v" = ~ ] || echo "Expected $HOME got $v"
+ }
+
+ command local v=~
+ check
+ command command local v=~
+ check
+
+ check() {
+ [ "$v" = "x:$HOME" ] || echo "Expected x:$HOME got $v"
+ }
+
+ command local v=x:~
+ check
+ command command local v=x:~
+ check
+}
+
+run_test
diff --git a/shell_cmds/sh/tests/expansion/pathname1.0 b/shell_cmds/sh/tests/expansion/pathname1.0
new file mode 100644
index 0000000..6f40004
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname1.0
@@ -0,0 +1,65 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname1.0 302937 2016-07-16 13:26:18Z ache $
+
+unset LC_ALL
+LC_COLLATE=C
+export LC_COLLATE
+
+failures=0
+
+check() {
+ testcase=$1
+ expect=$2
+ eval "set -- $testcase"
+ actual="$*"
+ if [ "$actual" != "$expect" ]; then
+ failures=$((failures+1))
+ printf '%s\n' "For $testcase, expected $expect actual $actual"
+ fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+mkdir testdir testdir2 'testdir/*' 'testdir/?' testdir/a testdir/b testdir2/b
+mkdir testdir2/.c
+touch testf 'testdir/*/1' 'testdir/?/1' testdir/a/1 testdir/b/1 testdir2/b/.a
+
+check '' ''
+check 'testdir/b' 'testdir/b'
+check 'testdir/c' 'testdir/c'
+check '\*' '*'
+check '\?' '?'
+check '*' 'testdir testdir2 testf'
+check '*""' 'testdir testdir2 testf'
+check '""*' 'testdir testdir2 testf'
+check '*/' 'testdir/ testdir2/'
+check 'testdir*/a' 'testdir/a'
+check 'testdir*/b' 'testdir/b testdir2/b'
+check '*/.c' 'testdir2/.c'
+check 'testdir2/*' 'testdir2/b'
+check 'testdir2/b/*' 'testdir2/b/*'
+check 'testdir/*' 'testdir/* testdir/? testdir/a testdir/b'
+check 'testdir/*/1' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir/"*/1' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check 'testdir/\*/*' 'testdir/*/1'
+check 'testdir/\?/*' 'testdir/?/1'
+check 'testdir/"?"/*' 'testdir/?/1'
+check '"testdir"/"?"/*' 'testdir/?/1'
+check '"testdir"/"?"*/*' 'testdir/?/1'
+check '"testdir"/*"?"/*' 'testdir/?/1'
+check '"testdir/?"*/*' 'testdir/?/1'
+check 'testdir/\*/' 'testdir/*/'
+check 'testdir/\?/' 'testdir/?/'
+check 'testdir/"?"/' 'testdir/?/'
+check '"testdir"/"?"/' 'testdir/?/'
+check '"testdir"/"?"*/' 'testdir/?/'
+check '"testdir"/*"?"/' 'testdir/?/'
+check '"testdir/?"*/' 'testdir/?/'
+check 'testdir/[*]/' 'testdir/*/'
+check 'testdir/[?]/' 'testdir/?/'
+check 'testdir/[*?]/' 'testdir/*/ testdir/?/'
+check '[tz]estdir/[*]/' 'testdir/*/'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/pathname2.0 b/shell_cmds/sh/tests/expansion/pathname2.0
new file mode 100644
index 0000000..3efffb7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname2.0
@@ -0,0 +1,35 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname2.0 302937 2016-07-16 13:26:18Z ache $
+
+unset LC_ALL
+LC_COLLATE=C
+export LC_COLLATE
+
+failures=0
+
+check() {
+ testcase=$1
+ expect=$2
+ eval "set -- $testcase"
+ actual="$*"
+ if [ "$actual" != "$expect" ]; then
+ failures=$((failures+1))
+ printf '%s\n' "For $testcase, expected $expect actual $actual"
+ fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+mkdir testdir testdir2 'testdir/*' 'testdir/?' testdir/a testdir/b testdir2/b
+mkdir testdir2/.c
+touch testf 'testdir/*/1' 'testdir/?/1' testdir/a/1 testdir/b/1 testdir2/b/.a
+
+check '*\/' 'testdir/ testdir2/'
+check '"testdir/"*"/1"' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir/"*"/"*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir/"*\/*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+check '"testdir"*"/"*"/"*' 'testdir/*/1 testdir/?/1 testdir/a/1 testdir/b/1'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/pathname3.0 b/shell_cmds/sh/tests/expansion/pathname3.0
new file mode 100644
index 0000000..80d6478
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname3.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname3.0 211155 2010-08-10 22:45:59Z jilles $
+
+v=12345678
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+v=$v$v$v$v
+# 8192 bytes
+v=${v##???}
+[ /*/$v = "/*/$v" ] || exit 1
+
+s=////
+s=$s$s$s$s
+s=$s$s$s$s
+s=$s$s$s$s
+s=$s$s$s$s
+# 1024 bytes
+s=${s##??????????}
+[ /var/empt[y]/$s/$v = "/var/empt[y]/$s/$v" ] || exit 2
+while [ ${#s} -lt 1034 ]; do
+ set -- /.${s}et[c]
+ [ ${#s} -gt 1018 ] || [ "$1" = /.${s}etc ] || exit 3
+ set -- /.${s}et[c]/
+ [ ${#s} -gt 1017 ] || [ "$1" = /.${s}etc/ ] || exit 4
+ set -- /.${s}et[c]/.
+ [ ${#s} -gt 1016 ] || [ "$1" = /.${s}etc/. ] || exit 5
+ s=$s/
+done
diff --git a/shell_cmds/sh/tests/expansion/pathname4.0 b/shell_cmds/sh/tests/expansion/pathname4.0
new file mode 100644
index 0000000..d316c0a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname4.0
@@ -0,0 +1,28 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname4.0 211646 2010-08-22 21:18:21Z jilles $
+
+failures=0
+
+check() {
+ testcase=$1
+ expect=$2
+ eval "set -- $testcase"
+ actual="$*"
+ if [ "$actual" != "$expect" ]; then
+ failures=$((failures+1))
+ printf '%s\n' "For $testcase, expected $expect actual $actual"
+ fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+mkdir !!a
+touch !!a/fff
+
+chmod u-r .
+check '!!a/ff*' '!!a/fff'
+chmod u+r .
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/pathname5.0 b/shell_cmds/sh/tests/expansion/pathname5.0
new file mode 100644
index 0000000..42cd119
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname5.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname5.0 278806 2015-02-15 19:48:29Z jilles $
+
+[ `echo '/[e]tc'` = /etc ]
diff --git a/shell_cmds/sh/tests/expansion/pathname6.0 b/shell_cmds/sh/tests/expansion/pathname6.0
new file mode 100644
index 0000000..e763c6a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/pathname6.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/expansion/pathname6.0 302937 2016-07-16 13:26:18Z ache $
+
+unset LC_ALL
+LC_COLLATE=en_US.US-ASCII
+export LC_COLLATE
+
+failures=0
+
+check() {
+ testcase=$1
+ expect=$2
+ eval "set -- $testcase"
+ actual="$*"
+ if [ "$actual" != "$expect" ]; then
+ failures=$((failures+1))
+ printf '%s\n' "For $testcase, expected $expect actual $actual"
+ fi
+}
+
+set -e
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+
+touch A B a b
+
+check '*' 'a A b B'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/expansion/plus-minus1.0 b/shell_cmds/sh/tests/expansion/plus-minus1.0
new file mode 100644
index 0000000..088ed7f
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus1.0
@@ -0,0 +1,76 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus1.0 216738 2010-12-27 15:57:41Z emaste $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- a b' '2|a|b'
+testcase 'set --' '0|'
+testcase 'set -- ${e}' '0|'
+testcase 'set -- "${e}"' '1|'
+
+testcase 'set -- $p' '1|/etc/'
+testcase 'set -- "$p"' '1|/et[c]/'
+testcase 'set -- ${s+$p}' '1|/etc/'
+testcase 'set -- "${s+$p}"' '1|/et[c]/'
+testcase 'set -- ${s+"$p"}' '1|/et[c]/'
+# Dquotes in dquotes is undefined for Bourne shell operators
+#testcase 'set -- "${s+"$p"}"' '1|/et[c]/'
+testcase 'set -- ${e:-$p}' '1|/etc/'
+testcase 'set -- "${e:-$p}"' '1|/et[c]/'
+testcase 'set -- ${e:-"$p"}' '1|/et[c]/'
+# Dquotes in dquotes is undefined for Bourne shell operators
+#testcase 'set -- "${e:-"$p"}"' '1|/et[c]/'
+testcase 'set -- ${e:+"$e"}' '0|'
+testcase 'set -- ${e:+$w"$e"}' '0|'
+testcase 'set -- ${w:+"$w"}' '1|a b c'
+testcase 'set -- ${w:+$w"$w"}' '3|a|b|ca b c'
+
+testcase 'set -- "${s+a b}"' '1|a b'
+testcase 'set -- "${e:-a b}"' '1|a b'
+testcase 'set -- ${e:-\}}' '1|}'
+testcase 'set -- ${e:+{}}' '1|}'
+testcase 'set -- "${e:+{}}"' '1|}'
+
+testcase 'set -- ${e+x}${e+x}' '1|xx'
+testcase 'set -- "${e+x}"${e+x}' '1|xx'
+testcase 'set -- ${e+x}"${e+x}"' '1|xx'
+testcase 'set -- "${e+x}${e+x}"' '1|xx'
+testcase 'set -- "${e+x}""${e+x}"' '1|xx'
+
+testcase 'set -- ${e:-${e:-$p}}' '1|/etc/'
+testcase 'set -- "${e:-${e:-$p}}"' '1|/et[c]/'
+testcase 'set -- ${e:-"${e:-$p}"}' '1|/et[c]/'
+testcase 'set -- ${e:-${e:-"$p"}}' '1|/et[c]/'
+testcase 'set -- ${e:-${e:-${e:-$w}}}' '3|a|b|c'
+testcase 'set -- ${e:-${e:-${e:-"$w"}}}' '1|a b c'
+testcase 'set -- ${e:-${e:-"${e:-$w}"}}' '1|a b c'
+testcase 'set -- ${e:-"${e:-${e:-$w}}"}' '1|a b c'
+testcase 'set -- "${e:-${e:-${e:-$w}}}"' '1|a b c'
+
+testcase 'shift $#; set -- ${1+"$@"}' '0|'
+testcase 'set -- ""; set -- ${1+"$@"}' '1|'
+testcase 'set -- "" a; set -- ${1+"$@"}' '2||a'
+testcase 'set -- a ""; set -- ${1+"$@"}' '2|a|'
+testcase 'set -- a b; set -- ${1+"$@"}' '2|a|b'
+testcase 'set -- a\ b; set -- ${1+"$@"}' '1|a b'
+testcase 'set -- " " ""; set -- ${1+"$@"}' '2| |'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus2.0 b/shell_cmds/sh/tests/expansion/plus-minus2.0
new file mode 100644
index 0000000..2f22988
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus2.0 206145 2010-04-03 20:55:56Z jilles $
+
+e=
+test "${e:-\}}" = '}'
diff --git a/shell_cmds/sh/tests/expansion/plus-minus3.0 b/shell_cmds/sh/tests/expansion/plus-minus3.0
new file mode 100644
index 0000000..d7fc923
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus3.0
@@ -0,0 +1,44 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus3.0 206817 2010-04-18 22:13:45Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+# We follow original ash behaviour for quoted ${var+-=?} expansions:
+# a double-quote in one switches back to unquoted state.
+# This allows expanding a variable as a single word if it is set
+# and substituting multiple words otherwise.
+# It is also close to the Bourne and Korn shells.
+# POSIX leaves this undefined, and various other shells treat
+# such double-quotes as introducing a second level of quoting
+# which does not do much except quoting close braces.
+
+testcase 'set -- "${p+"/et[c]/"}"' '1|/etc/'
+testcase 'set -- "${p-"/et[c]/"}"' '1|/et[c]/'
+testcase 'set -- "${p+"$p"}"' '1|/etc/'
+testcase 'set -- "${p-"$p"}"' '1|/et[c]/'
+testcase 'set -- "${p+"""/et[c]/"}"' '1|/etc/'
+testcase 'set -- "${p-"""/et[c]/"}"' '1|/et[c]/'
+testcase 'set -- "${p+"""$p"}"' '1|/etc/'
+testcase 'set -- "${p-"""$p"}"' '1|/et[c]/'
+testcase 'set -- "${p+"\@"}"' '1|@'
+testcase 'set -- "${p+"'\''/et[c]/'\''"}"' '1|/et[c]/'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus4.0 b/shell_cmds/sh/tests/expansion/plus-minus4.0
new file mode 100644
index 0000000..4d2d37d
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus4.0
@@ -0,0 +1,38 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus4.0 211080 2010-08-08 17:03:23Z jilles $
+
+# These may be a bit unclear in the POSIX spec or the proposed revisions,
+# and conflict with bash's interpretation, but I think ksh93's interpretation
+# makes most sense. In particular, it makes no sense to me that single-quotes
+# must match but are not removed.
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${e:-'"'"'}'"'"'}' '1|}'
+testcase "set -- \${e:-\\'}" "1|'"
+testcase "set -- \${e:-\\'\\'}" "1|''"
+testcase "set -- \"\${e:-'}\"" "1|'"
+testcase "set -- \"\${e:-'}'}\"" "1|''}"
+testcase "set -- \"\${e:-''}\"" "1|''"
+testcase 'set -- ${e:-\a}' '1|a'
+testcase 'set -- "${e:-\a}"' '1|\a'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus5.0 b/shell_cmds/sh/tests/expansion/plus-minus5.0
new file mode 100644
index 0000000..02db26c
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus5.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus5.0 214492 2010-10-28 22:34:49Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${e:-"{x}"}' '1|{x}'
+testcase 'set -- "${e:-"{x}"}"' '1|{x}'
+testcase 'set -- ${h+"{x}"}' '1|{x}'
+testcase 'set -- "${h+"{x}"}"' '1|{x}'
+testcase 'set -- ${h:-"{x}"}' '1|##'
+testcase 'set -- "${h:-"{x}"}"' '1|##'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus6.0 b/shell_cmds/sh/tests/expansion/plus-minus6.0
new file mode 100644
index 0000000..1bd3f7a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus6.0
@@ -0,0 +1,34 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus6.0 214512 2010-10-29 13:42:18Z jilles $
+
+failures=0
+unset LC_ALL
+export LC_CTYPE=en_US.ISO8859-1
+nl='
+'
+i=1
+set -f
+while [ "$i" -le 255 ]; do
+ # A different byte still in the range 1..255.
+ i2=$((i^2+(i==2)))
+ # Add a character to work around command substitution's removal of
+ # final newlines, then remove it again.
+ c=$(printf \\"$(printf %o@ "$i")")
+ c=${c%@}
+ c2=$(printf \\"$(printf %o@ "$i2")")
+ c2=${c2%@}
+ case $c in
+ [\'$nl'$}();&|\"`']) c=M
+ esac
+ case $c2 in
+ [\'$nl'$}();&|\"`']) c2=N
+ esac
+ IFS=$c
+ command eval "set -- \${\$+$c2$c$c2$c$c2}"
+ if [ "$#" -ne 3 ] || [ "$1" != "$c2" ] || [ "$2" != "$c2" ] ||
+ [ "$3" != "$c2" ]; then
+ echo "Bad results for separator $i (word $i2)" >&2
+ : $((failures += 1))
+ fi
+ i=$((i+1))
+done
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/expansion/plus-minus7.0 b/shell_cmds/sh/tests/expansion/plus-minus7.0
new file mode 100644
index 0000000..440cfdd
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus7.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus7.0 216738 2010-12-27 15:57:41Z emaste $
+
+e= s='foo'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${s+a b}' '2|a|b'
+testcase 'set -- ${e:-a b}' '2|a|b'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/plus-minus8.0 b/shell_cmds/sh/tests/expansion/plus-minus8.0
new file mode 100644
index 0000000..dd7e770
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/plus-minus8.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/expansion/plus-minus8.0 219623 2011-03-13 20:02:39Z jilles $
+
+set -- 1 2 3 4 5 6 7 8 9 10 11 12 13
+[ "${#+hi}" = hi ] || echo '${#+hi} wrong'
+[ "${#-hi}" = 13 ] || echo '${#-hi} wrong'
diff --git a/shell_cmds/sh/tests/expansion/question1.0 b/shell_cmds/sh/tests/expansion/question1.0
new file mode 100644
index 0000000..2f07597
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/question1.0
@@ -0,0 +1,22 @@
+# $FreeBSD: head/bin/sh/tests/expansion/question1.0 213738 2010-10-12 18:20:38Z obrien $
+
+x=a\ b
+[ "$x" = "${x?}" ] || exit 1
+set -- ${x?}
+{ [ "$#" = 2 ] && [ "$1" = a ] && [ "$2" = b ]; } || exit 1
+unset x
+(echo ${x?abcdefg}) 2>&1 | grep -q abcdefg || exit 1
+${SH} -c 'unset foo; echo ${foo?}' 2>/dev/null && exit 1
+${SH} -c 'foo=; echo ${foo:?}' 2>/dev/null && exit 1
+${SH} -c 'foo=; echo ${foo?}' >/dev/null || exit 1
+${SH} -c 'foo=1; echo ${foo:?}' >/dev/null || exit 1
+${SH} -c 'echo ${!?}' 2>/dev/null && exit 1
+${SH} -c ':& echo ${!?}' >/dev/null || exit 1
+${SH} -c 'echo ${#?}' >/dev/null || exit 1
+${SH} -c 'echo ${*?}' 2>/dev/null && exit 1
+${SH} -c 'echo ${*?}' ${SH} x >/dev/null || exit 1
+${SH} -c 'echo ${1?}' 2>/dev/null && exit 1
+${SH} -c 'echo ${1?}' ${SH} x >/dev/null || exit 1
+${SH} -c 'echo ${2?}' ${SH} x 2>/dev/null && exit 1
+${SH} -c 'echo ${2?}' ${SH} x y >/dev/null || exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/expansion/readonly1.0 b/shell_cmds/sh/tests/expansion/readonly1.0
new file mode 100644
index 0000000..e1e950a
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/readonly1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/expansion/readonly1.0 238468 2012-07-15 10:19:43Z jilles $
+
+w='@ @'
+
+v=0 HOME=/known/value
+readonly v=~:~/:$w
+[ "$v" = "$HOME:$HOME/:$w" ] || echo "Expected $HOME/:$w got $v"
diff --git a/shell_cmds/sh/tests/expansion/redir1.0 b/shell_cmds/sh/tests/expansion/redir1.0
new file mode 100644
index 0000000..fd5c981
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/redir1.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/expansion/redir1.0 273920 2014-10-31 22:28:10Z jilles $
+
+bad=0
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ set -- "$(printf \\$i$j$k@)"
+ set -- "${1%@}"
+ ff=
+ for f in /dev/null /dev/zero /; do
+ if [ -e "$f" ] && [ ! -e "$f$1" ]; then
+ ff=$f
+ fi
+ done
+ [ -n "$ff" ] || continue
+ if { true <$ff$1; } 2>/dev/null; then
+ echo "Bad: $i$j$k ($ff)" >&2
+ : $((bad += 1))
+ fi
+ done
+ done
+done
+exit $((bad ? 2 : 0))
diff --git a/shell_cmds/sh/tests/expansion/set-u1.0 b/shell_cmds/sh/tests/expansion/set-u1.0
new file mode 100644
index 0000000..045d6ad
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/set-u1.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/expansion/set-u1.0 213738 2010-10-12 18:20:38Z obrien $
+
+${SH} -uc 'unset foo; echo $foo' 2>/dev/null && exit 1
+${SH} -uc 'foo=; echo $foo' >/dev/null || exit 1
+${SH} -uc 'foo=1; echo $foo' >/dev/null || exit 1
+# -/+/= are unaffected by set -u
+${SH} -uc 'unset foo; echo ${foo-}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo+}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo=}' >/dev/null || exit 1
+# length/trimming are affected
+${SH} -uc 'unset foo; echo ${#foo}' 2>/dev/null && exit 1
+${SH} -uc 'foo=; echo ${#foo}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo#?}' 2>/dev/null && exit 1
+${SH} -uc 'foo=1; echo ${foo#?}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo##?}' 2>/dev/null && exit 1
+${SH} -uc 'foo=1; echo ${foo##?}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo%?}' 2>/dev/null && exit 1
+${SH} -uc 'foo=1; echo ${foo%?}' >/dev/null || exit 1
+${SH} -uc 'unset foo; echo ${foo%%?}' 2>/dev/null && exit 1
+${SH} -uc 'foo=1; echo ${foo%%?}' >/dev/null || exit 1
+
+${SH} -uc 'echo $!' 2>/dev/null && exit 1
+${SH} -uc ':& echo $!' >/dev/null || exit 1
+${SH} -uc 'echo $#' >/dev/null || exit 1
+${SH} -uc 'echo $1' 2>/dev/null && exit 1
+${SH} -uc 'echo $1' ${SH} x >/dev/null || exit 1
+${SH} -uc 'echo $2' ${SH} x 2>/dev/null && exit 1
+${SH} -uc 'echo $2' ${SH} x y >/dev/null || exit 1
+exit 0
diff --git a/shell_cmds/sh/tests/expansion/set-u2.0 b/shell_cmds/sh/tests/expansion/set-u2.0
new file mode 100644
index 0000000..55da8aa
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/set-u2.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/expansion/set-u2.0 198454 2009-10-24 21:20:04Z jilles $
+
+set -u
+: $* $@ "$@" "$*"
+set -- x
+: $* $@ "$@" "$*"
+shift $#
+: $* $@ "$@" "$*"
+set -- y
+set --
+: $* $@ "$@" "$*"
+exit 0
diff --git a/shell_cmds/sh/tests/expansion/set-u3.0 b/shell_cmds/sh/tests/expansion/set-u3.0
new file mode 100644
index 0000000..ea848f7
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/set-u3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/expansion/set-u3.0 221463 2011-05-04 22:12:22Z jilles $
+
+set -u
+unset x
+v=$( (eval ': $((x))') 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/expansion/tilde1.0 b/shell_cmds/sh/tests/expansion/tilde1.0
new file mode 100644
index 0000000..c0a7f5b
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/tilde1.0
@@ -0,0 +1,56 @@
+# $FreeBSD: head/bin/sh/tests/expansion/tilde1.0 206149 2010-04-03 21:56:24Z jilles $
+
+HOME=/tmp
+roothome=~root
+if [ "$roothome" = "~root" ]; then
+ echo "~root is not expanded!"
+ exit 2
+fi
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ~' '1|/tmp'
+testcase 'set -- ~/foo' '1|/tmp/foo'
+testcase 'set -- x~' '1|x~'
+testcase 'set -- ~root' "1|$roothome"
+h=~
+testcase 'set -- "$h"' '1|/tmp'
+ooIFS=$IFS
+IFS=m
+testcase 'set -- ~' '1|/tmp'
+testcase 'set -- ~/foo' '1|/tmp/foo'
+testcase 'set -- $h' '2|/t|p'
+IFS=$ooIFS
+t=\~
+testcase 'set -- $t' '1|~'
+r=$(cat <<EOF
+~
+EOF
+)
+testcase 'set -- $r' '1|~'
+r=$(cat <<EOF
+${t+~}
+EOF
+)
+testcase 'set -- $r' '1|~'
+r=$(cat <<EOF
+${t+~/.}
+EOF
+)
+testcase 'set -- $r' '1|~/.'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/tilde2.0 b/shell_cmds/sh/tests/expansion/tilde2.0
new file mode 100644
index 0000000..7827c22
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/tilde2.0
@@ -0,0 +1,90 @@
+# $FreeBSD: head/bin/sh/tests/expansion/tilde2.0 206150 2010-04-03 22:04:44Z jilles $
+
+HOME=/tmp
+roothome=~root
+if [ "$roothome" = "~root" ]; then
+ echo "~root is not expanded!"
+ exit 2
+fi
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${$+~}' '1|/tmp'
+testcase 'set -- ${$+~/}' '1|/tmp/'
+testcase 'set -- ${$+~/foo}' '1|/tmp/foo'
+testcase 'set -- ${$+x~}' '1|x~'
+testcase 'set -- ${$+~root}' "1|$roothome"
+testcase 'set -- ${$+"~"}' '1|~'
+testcase 'set -- ${$+"~/"}' '1|~/'
+testcase 'set -- ${$+"~/foo"}' '1|~/foo'
+testcase 'set -- ${$+"x~"}' '1|x~'
+testcase 'set -- ${$+"~root"}' "1|~root"
+testcase 'set -- "${$+~}"' '1|~'
+testcase 'set -- "${$+~/}"' '1|~/'
+testcase 'set -- "${$+~/foo}"' '1|~/foo'
+testcase 'set -- "${$+x~}"' '1|x~'
+testcase 'set -- "${$+~root}"' "1|~root"
+testcase 'set -- ${HOME#~}' '0|'
+h=~
+testcase 'set -- "$h"' '1|/tmp'
+f=~/foo
+testcase 'set -- "$f"' '1|/tmp/foo'
+testcase 'set -- ${f#~}' '1|/foo'
+testcase 'set -- ${f#~/}' '1|foo'
+
+ooIFS=$IFS
+IFS=m
+testcase 'set -- ${$+~}' '1|/tmp'
+testcase 'set -- ${$+~/foo}' '1|/tmp/foo'
+testcase 'set -- ${$+$h}' '2|/t|p'
+testcase 'set -- ${HOME#~}' '0|'
+IFS=$ooIFS
+
+t=\~
+testcase 'set -- ${$+$t}' '1|~'
+r=$(cat <<EOF
+${HOME#~}
+EOF
+)
+testcase 'set -- $r' '0|'
+r=$(cat <<EOF
+${HOME#'~'}
+EOF
+)
+testcase 'set -- $r' '1|/tmp'
+r=$(cat <<EOF
+${t#'~'}
+EOF
+)
+testcase 'set -- $r' '0|'
+r=$(cat <<EOF
+${roothome#~root}
+EOF
+)
+testcase 'set -- $r' '0|'
+r=$(cat <<EOF
+${f#~}
+EOF
+)
+testcase 'set -- $r' '1|/foo'
+r=$(cat <<EOF
+${f#~/}
+EOF
+)
+testcase 'set -- $r' '1|foo'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim1.0 b/shell_cmds/sh/tests/expansion/trim1.0
new file mode 100644
index 0000000..16dd838
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim1.0
@@ -0,0 +1,85 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim1.0 206143 2010-04-03 20:14:10Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- ${t%t}' '1|texttex'
+testcase 'set -- "${t%t}"' '1|texttex'
+testcase 'set -- ${t%e*}' '1|textt'
+testcase 'set -- "${t%e*}"' '1|textt'
+testcase 'set -- ${t%%e*}' '1|t'
+testcase 'set -- "${t%%e*}"' '1|t'
+testcase 'set -- ${t%%*}' '0|'
+testcase 'set -- "${t%%*}"' '1|'
+testcase 'set -- ${t#t}' '1|exttext'
+testcase 'set -- "${t#t}"' '1|exttext'
+testcase 'set -- ${t#*x}' '1|ttext'
+testcase 'set -- "${t#*x}"' '1|ttext'
+testcase 'set -- ${t##*x}' '1|t'
+testcase 'set -- "${t##*x}"' '1|t'
+testcase 'set -- ${t##*}' '0|'
+testcase 'set -- "${t##*}"' '1|'
+testcase 'set -- ${t%e$a}' '1|textt'
+
+set -f
+testcase 'set -- ${s%[?]*}' '1|ast*que'
+testcase 'set -- "${s%[?]*}"' '1|ast*que'
+testcase 'set -- ${s%[*]*}' '1|ast'
+testcase 'set -- "${s%[*]*}"' '1|ast'
+set +f
+
+testcase 'set -- $b' '1|{{(#)}}'
+testcase 'set -- ${b%\}}' '1|{{(#)}'
+testcase 'set -- ${b#{}' '1|{(#)}}'
+testcase 'set -- "${b#{}"' '1|{(#)}}'
+# Parentheses are special in ksh, check that they can be escaped
+testcase 'set -- ${b%\)*}' '1|{{(#'
+testcase 'set -- ${b#{}' '1|{(#)}}'
+testcase 'set -- $h' '1|##'
+testcase 'set -- ${h#\#}' '1|#'
+testcase 'set -- ${h###}' '1|#'
+testcase 'set -- "${h###}"' '1|#'
+testcase 'set -- ${h%#}' '1|#'
+testcase 'set -- "${h%#}"' '1|#'
+
+set -f
+testcase 'set -- ${s%"${s#?}"}' '1|a'
+testcase 'set -- ${s%"${s#????}"}' '1|ast*'
+testcase 'set -- ${s%"${s#????????}"}' '1|ast*que?'
+testcase 'set -- ${s#"${s%?}"}' '1|n'
+testcase 'set -- ${s#"${s%????}"}' '1|?non'
+testcase 'set -- ${s#"${s%????????}"}' '1|*que?non'
+set +f
+testcase 'set -- "${s%"${s#?}"}"' '1|a'
+testcase 'set -- "${s%"${s#????}"}"' '1|ast*'
+testcase 'set -- "${s%"${s#????????}"}"' '1|ast*que?'
+testcase 'set -- "${s#"${s%?}"}"' '1|n'
+testcase 'set -- "${s#"${s%????}"}"' '1|?non'
+testcase 'set -- "${s#"${s%????????}"}"' '1|*que?non'
+testcase 'set -- ${p#${p}}' '1|/etc/'
+testcase 'set -- "${p#${p}}"' '1|/et[c]/'
+testcase 'set -- ${p#*[[]}' '1|c]/'
+testcase 'set -- "${p#*[[]}"' '1|c]/'
+testcase 'set -- ${p#*\[}' '1|c]/'
+testcase 'set -- ${p#*"["}' '1|c]/'
+testcase 'set -- "${p#*"["}"' '1|c]/'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim2.0 b/shell_cmds/sh/tests/expansion/trim2.0
new file mode 100644
index 0000000..15651b9
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim2.0
@@ -0,0 +1,55 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim2.0 206147 2010-04-03 21:07:50Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+set -f
+testcase 'set -- $s' '1|ast*que?non'
+testcase 'set -- ${s%\?*}' '1|ast*que'
+testcase 'set -- "${s%\?*}"' '1|ast*que'
+testcase 'set -- ${s%\**}' '1|ast'
+testcase 'set -- "${s%\**}"' '1|ast'
+testcase 'set -- ${s%"$q"*}' '1|ast*que'
+testcase 'set -- "${s%"$q"*}"' '1|ast*que'
+testcase 'set -- ${s%"$a"*}' '1|ast'
+testcase 'set -- "${s%"$a"*}"' '1|ast'
+testcase 'set -- ${s%"$q"$a}' '1|ast*que'
+testcase 'set -- "${s%"$q"$a}"' '1|ast*que'
+testcase 'set -- ${s%"$a"$a}' '1|ast'
+testcase 'set -- "${s%"$a"$a}"' '1|ast'
+set +f
+
+testcase 'set -- "${b%\}}"' '1|{{(#)}'
+# Parentheses are special in ksh, check that they can be escaped
+testcase 'set -- "${b%\)*}"' '1|{{(#'
+testcase 'set -- "${h#\#}"' '1|#'
+
+testcase 'set -- ${p%"${p#?}"}' '1|/'
+testcase 'set -- ${p%"${p#??????}"}' '1|/etc'
+testcase 'set -- ${p%"${p#???????}"}' '1|/etc/'
+testcase 'set -- "${p%"${p#?}"}"' '1|/'
+testcase 'set -- "${p%"${p#??????}"}"' '1|/et[c]'
+testcase 'set -- "${p%"${p#???????}"}"' '1|/et[c]/'
+testcase 'set -- ${p#"${p}"}' '0|'
+testcase 'set -- "${p#"${p}"}"' '1|'
+testcase 'set -- "${p#*\[}"' '1|c]/'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim3.0 b/shell_cmds/sh/tests/expansion/trim3.0
new file mode 100644
index 0000000..28c59ae
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim3.0
@@ -0,0 +1,46 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim3.0 207127 2010-04-23 17:26:49Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##' c='\\\\'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+# This doesn't make much sense, but it fails in dash so I'm adding it here:
+testcase 'set -- "${w%${w#???}}"' '1|a b'
+
+testcase 'set -- ${p#/et[}' '1|c]/'
+testcase 'set -- "${p#/et[}"' '1|c]/'
+testcase 'set -- "${p%${p#????}}"' '1|/et['
+
+testcase 'set -- ${b%'\'}\''}' '1|{{(#)}'
+
+testcase 'set -- ${c#\\}' '1|\\\'
+testcase 'set -- ${c#\\\\}' '1|\\'
+testcase 'set -- ${c#\\\\\\}' '1|\'
+testcase 'set -- ${c#\\\\\\\\}' '0|'
+testcase 'set -- "${c#\\}"' '1|\\\'
+testcase 'set -- "${c#\\\\}"' '1|\\'
+testcase 'set -- "${c#\\\\\\}"' '1|\'
+testcase 'set -- "${c#\\\\\\\\}"' '1|'
+testcase 'set -- "${c#"$c"}"' '1|'
+testcase 'set -- ${c#"$c"}' '0|'
+testcase 'set -- "${c%"$c"}"' '1|'
+testcase 'set -- ${c%"$c"}' '0|'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim4.0 b/shell_cmds/sh/tests/expansion/trim4.0
new file mode 100644
index 0000000..f79b6fd
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim4.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim4.0 213814 2010-10-13 23:29:09Z obrien $
+
+v1=/homes/SOME_USER
+v2=
+v3=C123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+
+# Trigger bug in VSTRIMRIGHT processing STADJUST() call in expand.c:subevalvar()
+while [ ${#v2} -lt 2000 ]; do
+ v4="${v2} ${v1%/*} $v3"
+ if [ ${#v4} -ne $((${#v2} + ${#v3} + 8)) ]; then
+ echo bad: ${#v4} -ne $((${#v2} + ${#v3} + 8))
+ fi
+ v2=x$v2
+ v3=y$v3
+done
diff --git a/shell_cmds/sh/tests/expansion/trim5.0 b/shell_cmds/sh/tests/expansion/trim5.0
new file mode 100644
index 0000000..8045eb6
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim5.0
@@ -0,0 +1,28 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim5.0 214490 2010-10-28 21:51:14Z jilles $
+
+e= q='?' a='*' t=texttext s='ast*que?non' p='/et[c]/' w='a b c' b='{{(#)}}'
+h='##'
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- "${b%'\'}\''}"' '1|{{(#)}'
+testcase 'set -- ${b%"}"}' '1|{{(#)}'
+testcase 'set -- "${b%"}"}"' '1|{{(#)}'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim6.0 b/shell_cmds/sh/tests/expansion/trim6.0
new file mode 100644
index 0000000..e34a09f
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim6.0
@@ -0,0 +1,22 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim6.0 214524 2010-10-29 19:34:57Z jilles $
+
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ e="$e\\$i$j$k"
+ done
+ done
+done
+e=$(printf "$e")
+v=@$e@$e@
+y=${v##*"$e"}
+yq="${v##*"$e"}"
+[ "$y" = @ ] || echo "error when unquoted in non-splitting context"
+[ "$yq" = @ ] || echo "error when quoted in non-splitting context"
+[ "${v##*"$e"}" = @ ] || echo "error when quoted in splitting context"
+IFS=
+[ ${v##*"$e"} = @ ] || echo "error when unquoted in splitting context"
diff --git a/shell_cmds/sh/tests/expansion/trim7.0 b/shell_cmds/sh/tests/expansion/trim7.0
new file mode 100644
index 0000000..4f237cc
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim7.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim7.0 219623 2011-03-13 20:02:39Z jilles $
+
+set -- 1 2 3 4 5 6 7 8 9 10 11 12 13
+[ "${##1}" = 3 ] || echo '${##1} wrong'
+[ "${###1}" = 3 ] || echo '${###1} wrong'
+[ "${###}" = 13 ] || echo '${###} wrong'
+[ "${#%3}" = 1 ] || echo '${#%3} wrong'
+[ "${#%%3}" = 1 ] || echo '${#%%3} wrong'
+[ "${#%%}" = 13 ] || echo '${#%%} wrong'
+set --
+[ "${##0}" = "" ] || echo '${##0} wrong'
+[ "${###0}" = "" ] || echo '${###0} wrong'
+[ "${###}" = 0 ] || echo '${###} wrong'
+[ "${#%0}" = "" ] || echo '${#%0} wrong'
+[ "${#%%0}" = "" ] || echo '${#%%0} wrong'
+[ "${#%%}" = 0 ] || echo '${#%%} wrong'
diff --git a/shell_cmds/sh/tests/expansion/trim8.0 b/shell_cmds/sh/tests/expansion/trim8.0
new file mode 100644
index 0000000..c4b6ce4
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim8.0
@@ -0,0 +1,75 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim8.0 221646 2011-05-08 11:32:20Z jilles $
+
+unset LC_ALL
+LC_CTYPE=en_US.UTF-8
+export LC_CTYPE
+
+c1=e
+# a umlaut
+c2=$(printf '\303\244')
+# euro sign
+c3=$(printf '\342\202\254')
+# some sort of 't' outside BMP
+c4=$(printf '\360\235\225\245')
+
+s=$c1$c2$c3$c4
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- "$s"' "1|$s"
+testcase 'set -- "${s#$c2}"' "1|$s"
+testcase 'set -- "${s#*}"' "1|$s"
+testcase 'set -- "${s#$c1}"' "1|$c2$c3$c4"
+testcase 'set -- "${s#$c1$c2}"' "1|$c3$c4"
+testcase 'set -- "${s#$c1$c2$c3}"' "1|$c4"
+testcase 'set -- "${s#$c1$c2$c3$c4}"' "1|"
+testcase 'set -- "${s#?}"' "1|$c2$c3$c4"
+testcase 'set -- "${s#??}"' "1|$c3$c4"
+testcase 'set -- "${s#???}"' "1|$c4"
+testcase 'set -- "${s#????}"' "1|"
+testcase 'set -- "${s#*$c3}"' "1|$c4"
+testcase 'set -- "${s%$c4}"' "1|$c1$c2$c3"
+testcase 'set -- "${s%$c3$c4}"' "1|$c1$c2"
+testcase 'set -- "${s%$c2$c3$c4}"' "1|$c1"
+testcase 'set -- "${s%$c1$c2$c3$c4}"' "1|"
+testcase 'set -- "${s%?}"' "1|$c1$c2$c3"
+testcase 'set -- "${s%??}"' "1|$c1$c2"
+testcase 'set -- "${s%???}"' "1|$c1"
+testcase 'set -- "${s%????}"' "1|"
+testcase 'set -- "${s%$c2*}"' "1|$c1"
+testcase 'set -- "${s##$c2}"' "1|$s"
+testcase 'set -- "${s##*}"' "1|"
+testcase 'set -- "${s##$c1}"' "1|$c2$c3$c4"
+testcase 'set -- "${s##$c1$c2}"' "1|$c3$c4"
+testcase 'set -- "${s##$c1$c2$c3}"' "1|$c4"
+testcase 'set -- "${s##$c1$c2$c3$c4}"' "1|"
+testcase 'set -- "${s##?}"' "1|$c2$c3$c4"
+testcase 'set -- "${s##??}"' "1|$c3$c4"
+testcase 'set -- "${s##???}"' "1|$c4"
+testcase 'set -- "${s##????}"' "1|"
+testcase 'set -- "${s##*$c3}"' "1|$c4"
+testcase 'set -- "${s%%$c4}"' "1|$c1$c2$c3"
+testcase 'set -- "${s%%$c3$c4}"' "1|$c1$c2"
+testcase 'set -- "${s%%$c2$c3$c4}"' "1|$c1"
+testcase 'set -- "${s%%$c1$c2$c3$c4}"' "1|"
+testcase 'set -- "${s%%?}"' "1|$c1$c2$c3"
+testcase 'set -- "${s%%??}"' "1|$c1$c2"
+testcase 'set -- "${s%%???}"' "1|$c1"
+testcase 'set -- "${s%%????}"' "1|"
+testcase 'set -- "${s%%$c2*}"' "1|$c1"
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/expansion/trim9.0 b/shell_cmds/sh/tests/expansion/trim9.0
new file mode 100644
index 0000000..f0b08ab
--- /dev/null
+++ b/shell_cmds/sh/tests/expansion/trim9.0
@@ -0,0 +1,61 @@
+# $FreeBSD: head/bin/sh/tests/expansion/trim9.0 292758 2015-12-26 22:27:48Z jilles $
+
+# POSIX does not specify these but they occasionally occur in the wild.
+# This just serves to keep working what currently works.
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'shift $#; set -- "${*#Q}"' '1|'
+testcase 'shift $#; set -- "${*##Q}"' '1|'
+testcase 'shift $#; set -- "${*%Q}"' '1|'
+testcase 'shift $#; set -- "${*%%Q}"' '1|'
+testcase 'set -- Q R; set -- "${*#Q}"' '1| R'
+testcase 'set -- Q R; set -- "${*##Q}"' '1| R'
+testcase 'set -- Q R; set -- "${*%R}"' '1|Q '
+testcase 'set -- Q R; set -- "${*%%R}"' '1|Q '
+testcase 'set -- Q R; set -- "${*#S}"' '1|Q R'
+testcase 'set -- Q R; set -- "${*##S}"' '1|Q R'
+testcase 'set -- Q R; set -- "${*%S}"' '1|Q R'
+testcase 'set -- Q R; set -- "${*%%S}"' '1|Q R'
+testcase 'set -- Q R; set -- ${*#Q}' '1|R'
+testcase 'set -- Q R; set -- ${*##Q}' '1|R'
+testcase 'set -- Q R; set -- ${*%R}' '1|Q'
+testcase 'set -- Q R; set -- ${*%%R}' '1|Q'
+testcase 'set -- Q R; set -- ${*#S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${*##S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${*%S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${*%%S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${@#Q}' '1|R'
+testcase 'set -- Q R; set -- ${@##Q}' '1|R'
+testcase 'set -- Q R; set -- ${@%R}' '1|Q'
+testcase 'set -- Q R; set -- ${@%%R}' '1|Q'
+testcase 'set -- Q R; set -- ${@#S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${@##S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${@%S}' '2|Q|R'
+testcase 'set -- Q R; set -- ${@%%S}' '2|Q|R'
+testcase 'set -- Q R; set -- "${@#Q}"' '2||R'
+testcase 'set -- Q R; set -- "${@%R}"' '2|Q|'
+testcase 'set -- Q R; set -- "${@%%R}"' '2|Q|'
+testcase 'set -- Q R; set -- "${@#S}"' '2|Q|R'
+testcase 'set -- Q R; set -- "${@##S}"' '2|Q|R'
+testcase 'set -- Q R; set -- "${@%S}"' '2|Q|R'
+testcase 'set -- Q R; set -- "${@%%S}"' '2|Q|R'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/functional_test.sh b/shell_cmds/sh/tests/functional_test.sh
new file mode 100755
index 0000000..c2a1f81
--- /dev/null
+++ b/shell_cmds/sh/tests/functional_test.sh
@@ -0,0 +1,72 @@
+#
+# Copyright 2014 EMC Corp.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD: head/bin/sh/tests/functional_test.sh 270101 2014-08-17 14:26:12Z jilles $
+
+SRCDIR=$(atf_get_srcdir)
+
+check()
+{
+ local tc=${1}; shift
+
+ export SH=$(atf_config_get bin.sh.test_shell /bin/sh)
+
+ local err_file="${SRCDIR}/${tc}.stderr"
+ [ -f "${err_file}" ] && err_flag="-e file:${err_file}"
+ local out_file="${SRCDIR}/${tc}.stdout"
+ [ -f "${out_file}" ] && out_flag="-o file:${out_file}"
+
+ atf_check -s exit:${tc##*.} ${err_flag} ${out_flag} ${SH} "${SRCDIR}/${tc}"
+}
+
+add_testcase()
+{
+ local tc=${1}
+ local tc_escaped word
+
+ case "${tc%.*}" in
+ *-*)
+ local IFS="-"
+ for word in ${tc%.*}; do
+ tc_escaped="${tc_escaped:+${tc_escaped}_}${word}"
+ done
+ ;;
+ *)
+ tc_escaped=${tc%.*}
+ ;;
+ esac
+
+ atf_test_case ${tc_escaped}
+ eval "${tc_escaped}_body() { check ${tc}; }"
+ atf_add_test_case ${tc_escaped}
+}
+
+atf_init_test_cases()
+{
+ for path in $(find -Es "${SRCDIR}" -regex '.*\.[0-9]+$'); do
+ add_testcase ${path##*/}
+ done
+}
diff --git a/shell_cmds/sh/tests/invocation/Makefile b/shell_cmds/sh/tests/invocation/Makefile
new file mode 100644
index 0000000..473990b
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/Makefile
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/invocation/Makefile 322455 2017-08-13 14:36:10Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= sh-ac1.0
+${PACKAGE}FILES+= sh-c-missing1.0
+${PACKAGE}FILES+= sh-c1.0
+${PACKAGE}FILES+= sh-ca1.0
+${PACKAGE}FILES+= sh-fca1.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/invocation/Makefile.depend b/shell_cmds/sh/tests/invocation/Makefile.depend
new file mode 100644
index 0000000..d01d96a
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/invocation/Makefile.depend 325187 2017-10-31 00:04:07Z bdrewery $
+# 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/shell_cmds/sh/tests/invocation/sh-ac1.0 b/shell_cmds/sh/tests/invocation/sh-ac1.0
new file mode 100644
index 0000000..fa7bdac
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-ac1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-ac1.0 322438 2017-08-12 19:17:48Z jilles $
+# Test that attached options before c are processed
+
+case `${SH} -ac 'echo $-:$0' moo` in
+*a*:moo) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/invocation/sh-c-missing1.0 b/shell_cmds/sh/tests/invocation/sh-c-missing1.0
new file mode 100644
index 0000000..8f6a850
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-c-missing1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-c-missing1.0 322455 2017-08-13 14:36:10Z jilles $
+
+! echo echo bad | ${SH} -c 2>/dev/null
diff --git a/shell_cmds/sh/tests/invocation/sh-c1.0 b/shell_cmds/sh/tests/invocation/sh-c1.0
new file mode 100644
index 0000000..6142225
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-c1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-c1.0 322438 2017-08-12 19:17:48Z jilles $
+# Test that -c executes command_string with the given name and arg
+
+${SH} -c 'echo $0 $@' moo foo | grep -qx -- "moo foo"
diff --git a/shell_cmds/sh/tests/invocation/sh-ca1.0 b/shell_cmds/sh/tests/invocation/sh-ca1.0
new file mode 100644
index 0000000..c743a1e
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-ca1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-ca1.0 322438 2017-08-12 19:17:48Z jilles $
+# Test that attached options after c are processed
+
+case `${SH} -ca 'echo $-:$0' moo` in
+*a*:moo) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/invocation/sh-fca1.0 b/shell_cmds/sh/tests/invocation/sh-fca1.0
new file mode 100644
index 0000000..f28b761
--- /dev/null
+++ b/shell_cmds/sh/tests/invocation/sh-fca1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/invocation/sh-fca1.0 322438 2017-08-12 19:17:48Z jilles $
+# Test that attached options before and after c are processed
+
+case `${SH} -fca 'echo $-:$-:$0:$@' foo -bar` in
+*f*:*a*:foo:-bar) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/parameters/Makefile b/shell_cmds/sh/tests/parameters/Makefile
new file mode 100644
index 0000000..30708db
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/Makefile
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/parameters/Makefile 306843 2016-10-08 13:40:12Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= env1.0
+${PACKAGE}FILES+= exitstatus1.0
+${PACKAGE}FILES+= ifs1.0
+${PACKAGE}FILES+= mail1.0
+${PACKAGE}FILES+= mail2.0
+${PACKAGE}FILES+= optind1.0
+${PACKAGE}FILES+= optind2.0
+${PACKAGE}FILES+= positional1.0
+${PACKAGE}FILES+= positional2.0
+${PACKAGE}FILES+= positional3.0
+${PACKAGE}FILES+= positional4.0
+${PACKAGE}FILES+= positional5.0
+${PACKAGE}FILES+= positional6.0
+${PACKAGE}FILES+= positional7.0
+${PACKAGE}FILES+= positional8.0
+${PACKAGE}FILES+= positional9.0
+${PACKAGE}FILES+= pwd1.0
+${PACKAGE}FILES+= pwd2.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/parameters/Makefile.depend b/shell_cmds/sh/tests/parameters/Makefile.depend
new file mode 100644
index 0000000..41114a3
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/parameters/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# 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/shell_cmds/sh/tests/parameters/env1.0 b/shell_cmds/sh/tests/parameters/env1.0
new file mode 100644
index 0000000..0842856
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/env1.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/parameters/env1.0 222957 2011-06-10 22:42:00Z jilles $
+
+export key='must contain this'
+unset x
+r=$(ENV="\${x?\$key}" ${SH} -i +m 2>&1 >/dev/null <<\EOF
+exit 0
+EOF
+) && case $r in
+*"$key"*) true ;;
+*) false ;;
+esac
diff --git a/shell_cmds/sh/tests/parameters/exitstatus1.0 b/shell_cmds/sh/tests/parameters/exitstatus1.0
new file mode 100644
index 0000000..709600e
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/exitstatus1.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/parameters/exitstatus1.0 185232 2008-11-23 20:27:03Z stefanf $
+f() {
+ [ $? = $1 ] || exit 1
+}
+
+true
+f 0
+false
+f 1
diff --git a/shell_cmds/sh/tests/parameters/ifs1.0 b/shell_cmds/sh/tests/parameters/ifs1.0
new file mode 100644
index 0000000..e88d7a4
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/ifs1.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/parameters/ifs1.0 306843 2016-10-08 13:40:12Z jilles $
+
+env IFS=_ ${SH} -c '
+rc=2
+nosuchtool_function() {
+ rc=0
+}
+v=nosuchtool_function
+$v && exit "$rc"
+'
diff --git a/shell_cmds/sh/tests/parameters/mail1.0 b/shell_cmds/sh/tests/parameters/mail1.0
new file mode 100644
index 0000000..af69211
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/mail1.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/parameters/mail1.0 213738 2010-10-12 18:20:38Z obrien $
+# Test that a non-interactive shell does not access $MAIL.
+
+goodfile=/var/empty/sh-test-goodfile
+mailfile=/var/empty/sh-test-mailfile
+T=$(mktemp sh-test.XXXXXX) || exit
+MAIL=$mailfile ktrace -i -f "$T" ${SH} -c "[ -s $goodfile ]" 2>/dev/null
+if ! grep -q $goodfile "$T"; then
+ # ktrace problem
+ rc=0
+elif ! grep -q $mailfile "$T"; then
+ rc=0
+fi
+rm "$T"
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/parameters/mail2.0 b/shell_cmds/sh/tests/parameters/mail2.0
new file mode 100644
index 0000000..74dc416
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/mail2.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/parameters/mail2.0 213738 2010-10-12 18:20:38Z obrien $
+# Test that an interactive shell accesses $MAIL.
+
+goodfile=/var/empty/sh-test-goodfile
+mailfile=/var/empty/sh-test-mailfile
+T=$(mktemp sh-test.XXXXXX) || exit
+ENV=$goodfile MAIL=$mailfile ktrace -i -f "$T" ${SH} +m -i </dev/null >/dev/null 2>&1
+if ! grep -q $goodfile "$T"; then
+ # ktrace problem
+ rc=0
+elif grep -q $mailfile "$T"; then
+ rc=0
+fi
+rm "$T"
+exit ${rc:-3}
diff --git a/shell_cmds/sh/tests/parameters/optind1.0 b/shell_cmds/sh/tests/parameters/optind1.0
new file mode 100644
index 0000000..30fc9d8
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/optind1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parameters/optind1.0 227773 2011-11-20 21:48:50Z jilles $
+
+unset OPTIND && [ -z "$OPTIND" ]
diff --git a/shell_cmds/sh/tests/parameters/optind2.0 b/shell_cmds/sh/tests/parameters/optind2.0
new file mode 100644
index 0000000..0837a17
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/optind2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parameters/optind2.0 259846 2013-12-24 22:38:24Z jilles $
+
+[ "$(OPTIND=42 ${SH} -c 'printf %s "$OPTIND"')" = 1 ]
diff --git a/shell_cmds/sh/tests/parameters/positional1.0 b/shell_cmds/sh/tests/parameters/positional1.0
new file mode 100644
index 0000000..ef95be3
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional1.0
@@ -0,0 +1,13 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional1.0 222158 2011-05-21 14:52:26Z jilles $
+
+set -- a b c d e f g h i j
+[ "$1" = a ] || echo "error at line $LINENO"
+[ "${1}" = a ] || echo "error at line $LINENO"
+[ "${1-foo}" = a ] || echo "error at line $LINENO"
+[ "${1+foo}" = foo ] || echo "error at line $LINENO"
+[ "$1+foo" = a+foo ] || echo "error at line $LINENO"
+[ "$10" = a0 ] || echo "error at line $LINENO"
+[ "$100" = a00 ] || echo "error at line $LINENO"
+[ "${10}" = j ] || echo "error at line $LINENO"
+[ "${10-foo}" = j ] || echo "error at line $LINENO"
+[ "${100-foo}" = foo ] || echo "error at line $LINENO"
diff --git a/shell_cmds/sh/tests/parameters/positional2.0 b/shell_cmds/sh/tests/parameters/positional2.0
new file mode 100644
index 0000000..ea29250
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional2.0
@@ -0,0 +1,65 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional2.0 228873 2011-12-25 13:24:48Z jilles $
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'set -- a b; set -- p$@q' '2|pa|bq'
+testcase 'set -- a b; set -- $@q' '2|a|bq'
+testcase 'set -- a b; set -- p$@' '2|pa|b'
+testcase 'set -- a b; set -- p$@q' '2|pa|bq'
+testcase 'set -- a b; set -- $@q' '2|a|bq'
+testcase 'set -- a b; set -- p$@' '2|pa|b'
+testcase 'set -- a b; set -- p$*q' '2|pa|bq'
+testcase 'set -- a b; set -- $*q' '2|a|bq'
+testcase 'set -- a b; set -- p$*' '2|pa|b'
+testcase 'set -- a b; set -- p$*q' '2|pa|bq'
+testcase 'set -- a b; set -- $*q' '2|a|bq'
+testcase 'set -- a b; set -- p$*' '2|pa|b'
+testcase 'set -- a b; set -- "p$@q"' '2|pa|bq'
+testcase 'set -- a b; set -- "$@q"' '2|a|bq'
+testcase 'set -- a b; set -- "p$@"' '2|pa|b'
+testcase 'set -- a b; set -- p"$@"q' '2|pa|bq'
+testcase 'set -- a b; set -- "$@"q' '2|a|bq'
+testcase 'set -- a b; set -- p"$@"' '2|pa|b'
+testcase 'set -- "" a b; set -- "p$@q"' '3|p|a|bq'
+testcase 'set -- "" a b; set -- "$@q"' '3||a|bq'
+testcase 'set -- "" a b; set -- "p$@"' '3|p|a|b'
+testcase 'set -- "" a b; set -- p"$@"q' '3|p|a|bq'
+testcase 'set -- "" a b; set -- "$@"q' '3||a|bq'
+testcase 'set -- "" a b; set -- p"$@"' '3|p|a|b'
+testcase 'set -- a; set -- p$@q' '1|paq'
+testcase 'set -- a; set -- $@q' '1|aq'
+testcase 'set -- a; set -- p$@' '1|pa'
+testcase 'set -- a; set -- p$@q' '1|paq'
+testcase 'set -- a; set -- $@q' '1|aq'
+testcase 'set -- a; set -- p$@' '1|pa'
+testcase 'set -- a; set -- p$*q' '1|paq'
+testcase 'set -- a; set -- $*q' '1|aq'
+testcase 'set -- a; set -- p$*' '1|pa'
+testcase 'set -- a; set -- p$*q' '1|paq'
+testcase 'set -- a; set -- $*q' '1|aq'
+testcase 'set -- a; set -- p$*' '1|pa'
+testcase 'set -- a; set -- "p$@q"' '1|paq'
+testcase 'set -- a; set -- "$@q"' '1|aq'
+testcase 'set -- a; set -- "p$@"' '1|pa'
+testcase 'set -- a; set -- p"$@"q' '1|paq'
+testcase 'set -- a; set -- "$@"q' '1|aq'
+testcase 'set -- a; set -- p"$@"' '1|pa'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/parameters/positional3.0 b/shell_cmds/sh/tests/parameters/positional3.0
new file mode 100644
index 0000000..d164ed9
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional3.0 268436 2014-07-08 22:04:44Z jilles $
+
+r=$(${SH} -c 'echo ${01:+yes}${010:+yes}' '' a '' '' '' '' '' '' '' '' b)
+[ "$r" = yesyes ]
diff --git a/shell_cmds/sh/tests/parameters/positional4.0 b/shell_cmds/sh/tests/parameters/positional4.0
new file mode 100644
index 0000000..48c2f01
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional4.0 268568 2014-07-12 10:27:30Z jilles $
+
+set -- "x$0" 2 3 4 5 6 7 8 9 "y$0"
+[ "${01}.${010}" = "$1.${10}" ]
diff --git a/shell_cmds/sh/tests/parameters/positional5.0 b/shell_cmds/sh/tests/parameters/positional5.0
new file mode 100644
index 0000000..80ef805
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional5.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional5.0 268576 2014-07-12 21:54:11Z jilles $
+
+i=1
+r=0
+while [ $i -lt $((0x100000000)) ]; do
+ t=
+ eval t=\${$i-x}
+ case $t in
+ x) ;;
+ *) echo "Problem with \${$i}" >&2; r=1 ;;
+ esac
+ i=$((i + 0x10000000))
+done
+exit $r
diff --git a/shell_cmds/sh/tests/parameters/positional6.0 b/shell_cmds/sh/tests/parameters/positional6.0
new file mode 100644
index 0000000..c1d5e4c
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional6.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional6.0 273802 2014-10-28 22:14:31Z jilles $
+
+IFS=?
+set p r
+v=pqrs
+r=${v#"$*"}
+[ "$r" = pqrs ]
diff --git a/shell_cmds/sh/tests/parameters/positional7.0 b/shell_cmds/sh/tests/parameters/positional7.0
new file mode 100644
index 0000000..df36b6f
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional7.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional7.0 273802 2014-10-28 22:14:31Z jilles $
+
+set -- / ''
+IFS=*
+set -- "$*"
+IFS=:
+args="$*"
+[ "$#:$args" = "1:/*" ]
diff --git a/shell_cmds/sh/tests/parameters/positional8.0 b/shell_cmds/sh/tests/parameters/positional8.0
new file mode 100644
index 0000000..69717ce
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional8.0
@@ -0,0 +1,31 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional8.0 291025 2015-11-18 21:09:03Z jilles $
+
+failures=''
+ok=''
+
+testcase() {
+ code="$1"
+ expected="$2"
+ oIFS="$IFS"
+ eval "$code"
+ IFS='|'
+ result="$#|$*"
+ IFS="$oIFS"
+ if [ "x$result" = "x$expected" ]; then
+ ok=x$ok
+ else
+ failures=x$failures
+ echo "For $code, expected $expected actual $result"
+ fi
+}
+
+testcase 'shift $#; set -- ""$*' '1|'
+testcase 'shift $#; set -- $*""' '1|'
+testcase 'shift $#; set -- ""$@' '1|'
+testcase 'shift $#; set -- $@""' '1|'
+testcase 'shift $#; set -- """$*"' '1|'
+testcase 'shift $#; set -- "$*"""' '1|'
+testcase 'shift $#; set -- """$@"' '1|'
+testcase 'shift $#; set -- "$@"""' '1|'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/parameters/positional9.0 b/shell_cmds/sh/tests/parameters/positional9.0
new file mode 100644
index 0000000..c353e85
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/positional9.0
@@ -0,0 +1,18 @@
+# $FreeBSD: head/bin/sh/tests/parameters/positional9.0 291903 2015-12-06 14:09:31Z jilles $
+# Although POSIX leaves the result of expanding ${#@} and ${#*} unspecified,
+# make sure it is at least numeric.
+
+set -- bb cc ddd
+set -f
+lengths=${#*}${#@}"${#*}${#@}"$(echo ${#*}${#@}"${#*}${#@}")
+IFS=
+lengths=$lengths${#*}${#@}"${#*}${#@}"$(echo ${#*}${#@}"${#*}${#@}")
+case $lengths in
+*[!0-9]*)
+ printf 'bad: %s\n' "$lengths"
+ exit 3 ;;
+????????????????*) ;;
+*)
+ printf 'too short: %s\n' "$lengths"
+ exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/parameters/pwd1.0 b/shell_cmds/sh/tests/parameters/pwd1.0
new file mode 100644
index 0000000..8393ef6
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/pwd1.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/parameters/pwd1.0 213738 2010-10-12 18:20:38Z obrien $
+# Check that bogus PWD values are not accepted from the environment.
+
+cd / || exit 3
+failures=0
+[ "$(PWD=foo ${SH} -c 'pwd')" = / ] || : $((failures += 1))
+[ "$(PWD=/var/empty ${SH} -c 'pwd')" = / ] || : $((failures += 1))
+[ "$(PWD=/var/empty/foo ${SH} -c 'pwd')" = / ] || : $((failures += 1))
+[ "$(PWD=/bin/ls ${SH} -c 'pwd')" = / ] || : $((failures += 1))
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parameters/pwd2.0 b/shell_cmds/sh/tests/parameters/pwd2.0
new file mode 100644
index 0000000..d0cecf5
--- /dev/null
+++ b/shell_cmds/sh/tests/parameters/pwd2.0
@@ -0,0 +1,24 @@
+# $FreeBSD: head/bin/sh/tests/parameters/pwd2.0 213738 2010-10-12 18:20:38Z obrien $
+# Check that PWD is exported and accepted from the environment.
+set -e
+
+T=$(mktemp -d ${TMPDIR:-/tmp}/sh-test.XXXXXX)
+trap 'rm -rf $T' 0
+cd -P $T
+TP=$(pwd)
+mkdir test1
+ln -s test1 link
+cd link
+[ "$PWD" = "$TP/link" ]
+[ "$(pwd)" = "$TP/link" ]
+[ "$(pwd -P)" = "$TP/test1" ]
+[ "$(${SH} -c pwd)" = "$TP/link" ]
+[ "$(${SH} -c pwd\ -P)" = "$TP/test1" ]
+cd ..
+[ "$(pwd)" = "$TP" ]
+cd -P link
+[ "$PWD" = "$TP/test1" ]
+[ "$(pwd)" = "$TP/test1" ]
+[ "$(pwd -P)" = "$TP/test1" ]
+[ "$(${SH} -c pwd)" = "$TP/test1" ]
+[ "$(${SH} -c pwd\ -P)" = "$TP/test1" ]
diff --git a/shell_cmds/sh/tests/parser/Makefile b/shell_cmds/sh/tests/parser/Makefile
new file mode 100644
index 0000000..cd83a50
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/Makefile
@@ -0,0 +1,88 @@
+# $FreeBSD: head/bin/sh/tests/parser/Makefile 317039 2017-04-16 22:10:02Z jilles $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= alias1.0
+${PACKAGE}FILES+= alias2.0
+${PACKAGE}FILES+= alias3.0
+${PACKAGE}FILES+= alias4.0
+${PACKAGE}FILES+= alias5.0
+${PACKAGE}FILES+= alias6.0
+${PACKAGE}FILES+= alias7.0
+${PACKAGE}FILES+= alias8.0
+${PACKAGE}FILES+= alias9.0
+${PACKAGE}FILES+= alias10.0
+${PACKAGE}FILES+= alias11.0
+${PACKAGE}FILES+= alias12.0
+${PACKAGE}FILES+= alias13.0
+${PACKAGE}FILES+= alias14.0
+${PACKAGE}FILES+= alias15.0 alias15.0.stdout
+${PACKAGE}FILES+= alias16.0
+${PACKAGE}FILES+= alias17.0
+${PACKAGE}FILES+= alias18.0
+${PACKAGE}FILES+= and-pipe-not.0
+${PACKAGE}FILES+= case1.0
+${PACKAGE}FILES+= case2.0
+${PACKAGE}FILES+= comment1.0
+${PACKAGE}FILES+= comment2.42
+${PACKAGE}FILES+= dollar-quote1.0
+${PACKAGE}FILES+= dollar-quote2.0
+${PACKAGE}FILES+= dollar-quote3.0
+${PACKAGE}FILES+= dollar-quote4.0
+${PACKAGE}FILES+= dollar-quote5.0
+${PACKAGE}FILES+= dollar-quote6.0
+${PACKAGE}FILES+= dollar-quote7.0
+${PACKAGE}FILES+= dollar-quote8.0
+${PACKAGE}FILES+= dollar-quote9.0
+${PACKAGE}FILES+= dollar-quote10.0
+${PACKAGE}FILES+= dollar-quote11.0
+${PACKAGE}FILES+= dollar-quote12.0
+${PACKAGE}FILES+= dollar-quote13.0
+${PACKAGE}FILES+= empty-braces1.0
+${PACKAGE}FILES+= empty-cmd1.0
+${PACKAGE}FILES+= for1.0
+${PACKAGE}FILES+= for2.0
+${PACKAGE}FILES+= func1.0
+${PACKAGE}FILES+= func2.0
+${PACKAGE}FILES+= func3.0
+${PACKAGE}FILES+= heredoc1.0
+${PACKAGE}FILES+= heredoc2.0
+${PACKAGE}FILES+= heredoc3.0
+${PACKAGE}FILES+= heredoc4.0
+${PACKAGE}FILES+= heredoc5.0
+${PACKAGE}FILES+= heredoc6.0
+${PACKAGE}FILES+= heredoc7.0
+${PACKAGE}FILES+= heredoc8.0
+${PACKAGE}FILES+= heredoc9.0
+${PACKAGE}FILES+= heredoc10.0
+${PACKAGE}FILES+= heredoc11.0
+${PACKAGE}FILES+= heredoc12.0
+${PACKAGE}FILES+= heredoc13.0
+${PACKAGE}FILES+= line-cont1.0
+${PACKAGE}FILES+= line-cont2.0
+${PACKAGE}FILES+= line-cont3.0
+${PACKAGE}FILES+= line-cont4.0
+${PACKAGE}FILES+= line-cont5.0
+${PACKAGE}FILES+= line-cont6.0
+${PACKAGE}FILES+= line-cont7.0
+${PACKAGE}FILES+= line-cont8.0
+${PACKAGE}FILES+= line-cont9.0
+${PACKAGE}FILES+= line-cont10.0
+${PACKAGE}FILES+= line-cont11.0
+${PACKAGE}FILES+= no-space1.0
+${PACKAGE}FILES+= no-space2.0
+${PACKAGE}FILES+= nul1.0
+${PACKAGE}FILES+= only-redir1.0
+${PACKAGE}FILES+= only-redir2.0
+${PACKAGE}FILES+= only-redir3.0
+${PACKAGE}FILES+= only-redir4.0
+${PACKAGE}FILES+= pipe-not1.0
+${PACKAGE}FILES+= set-v1.0 set-v1.0.stderr
+${PACKAGE}FILES+= var-assign1.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/parser/Makefile.depend b/shell_cmds/sh/tests/parser/Makefile.depend
new file mode 100644
index 0000000..af589a4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/parser/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# 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/shell_cmds/sh/tests/parser/alias1.0 b/shell_cmds/sh/tests/parser/alias1.0
new file mode 100644
index 0000000..9b67211
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias1.0 214280 2010-10-24 16:55:17Z jilles $
+
+alias alias0=exit
+eval 'alias0 0'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias10.0 b/shell_cmds/sh/tests/parser/alias10.0
new file mode 100644
index 0000000..b8684f4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias10.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias10.0 243252 2012-11-18 23:15:22Z jilles $
+
+# This test may start consuming memory indefinitely if it fails.
+ulimit -t 5 2>/dev/null
+ulimit -v 100000 2>/dev/null
+
+alias echo='echo'
+alias echo='echo'
+[ "`eval echo b`" = b ]
diff --git a/shell_cmds/sh/tests/parser/alias11.0 b/shell_cmds/sh/tests/parser/alias11.0
new file mode 100644
index 0000000..10fd827
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias11.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias11.0 261141 2014-01-24 23:00:35Z jilles $
+
+alias alias0=alias1
+alias alias1=exit
+eval 'alias0 0'
+exit 3
diff --git a/shell_cmds/sh/tests/parser/alias12.0 b/shell_cmds/sh/tests/parser/alias12.0
new file mode 100644
index 0000000..52cc4b0
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias12.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias12.0 261160 2014-01-25 14:59:08Z jilles $
+
+unalias -a
+alias alias0=command
+alias true='echo bad'
+eval 'alias0 true'
diff --git a/shell_cmds/sh/tests/parser/alias13.0 b/shell_cmds/sh/tests/parser/alias13.0
new file mode 100644
index 0000000..9f45067
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias13.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias13.0 261160 2014-01-25 14:59:08Z jilles $
+
+unalias -a
+alias command=command
+alias true='echo bad'
+eval 'command true'
diff --git a/shell_cmds/sh/tests/parser/alias14.0 b/shell_cmds/sh/tests/parser/alias14.0
new file mode 100644
index 0000000..2d1bc51
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias14.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias14.0 261192 2014-01-26 21:19:33Z jilles $
+
+alias command='command '
+alias alias0=exit
+eval 'command alias0 0'
+exit 3
diff --git a/shell_cmds/sh/tests/parser/alias15.0 b/shell_cmds/sh/tests/parser/alias15.0
new file mode 100644
index 0000000..c2e6117
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias15.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias15.0 261192 2014-01-26 21:19:33Z jilles $
+
+f_echoanddo() {
+ printf '%s\n' "$*"
+ "$@"
+}
+
+alias echoanddo='f_echoanddo '
+alias alias0='echo test2'
+eval 'echoanddo echo test1'
+eval 'echoanddo alias0'
+exit 0
diff --git a/shell_cmds/sh/tests/parser/alias15.0.stdout b/shell_cmds/sh/tests/parser/alias15.0.stdout
new file mode 100644
index 0000000..6dd179c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias15.0.stdout
@@ -0,0 +1,4 @@
+echo test1
+test1
+echo test2
+test2
diff --git a/shell_cmds/sh/tests/parser/alias16.0 b/shell_cmds/sh/tests/parser/alias16.0
new file mode 100644
index 0000000..b551216
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias16.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias16.0 316646 2017-04-08 21:57:59Z jilles $
+
+v=1
+alias a='unalias a
+v=2'
+eval a
+[ "$v" = 2 ]
diff --git a/shell_cmds/sh/tests/parser/alias17.0 b/shell_cmds/sh/tests/parser/alias17.0
new file mode 100644
index 0000000..fd233ef
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias17.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias17.0 317037 2017-04-16 21:42:43Z jilles $
+
+v=1
+alias a='unalias -a
+v=2'
+eval a
+[ "$v" = 2 ]
diff --git a/shell_cmds/sh/tests/parser/alias18.0 b/shell_cmds/sh/tests/parser/alias18.0
new file mode 100644
index 0000000..4b072e8
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias18.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias18.0 317039 2017-04-16 22:10:02Z jilles $
+
+v=1
+alias a='alias a=v=2
+v=3
+a'
+eval a
+[ "$v" = 2 ]
diff --git a/shell_cmds/sh/tests/parser/alias2.0 b/shell_cmds/sh/tests/parser/alias2.0
new file mode 100644
index 0000000..f412756
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias2.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias2.0 214280 2010-10-24 16:55:17Z jilles $
+
+alias alias0=exit
+x=alias0
+eval 'case $x in alias0) exit 0;; esac'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias3.0 b/shell_cmds/sh/tests/parser/alias3.0
new file mode 100644
index 0000000..97aac19
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias3.0 214709 2010-11-02 23:44:29Z jilles $
+
+alias alias0=exit
+x=alias0
+eval 'case $x in "alias0") alias0 0;; esac'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias4.0 b/shell_cmds/sh/tests/parser/alias4.0
new file mode 100644
index 0000000..4c82c6c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias4.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias4.0 222165 2011-05-21 22:03:06Z jilles $
+
+alias alias0=exit
+eval 'x=1 alias0 0'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias5.0 b/shell_cmds/sh/tests/parser/alias5.0
new file mode 100644
index 0000000..c649562
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias5.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias5.0 222165 2011-05-21 22:03:06Z jilles $
+
+alias alias0=exit
+eval '</dev/null alias0 0'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/alias6.0 b/shell_cmds/sh/tests/parser/alias6.0
new file mode 100644
index 0000000..86e1bfb
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias6.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias6.0 224104 2011-07-16 16:14:14Z jilles $
+
+alias alias0='| cat >/dev/null'
+
+eval '{ echo bad; } alias0'
+eval '(echo bad)alias0'
diff --git a/shell_cmds/sh/tests/parser/alias7.0 b/shell_cmds/sh/tests/parser/alias7.0
new file mode 100644
index 0000000..a5b9077
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias7.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias7.0 240825 2012-09-22 12:52:41Z jilles $
+
+alias echo='echo a'
+[ "`eval echo b`" = "a b" ]
diff --git a/shell_cmds/sh/tests/parser/alias8.0 b/shell_cmds/sh/tests/parser/alias8.0
new file mode 100644
index 0000000..f22dfd4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias8.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias8.0 240825 2012-09-22 12:52:41Z jilles $
+
+alias echo='echo'
+[ "`eval echo b`" = b ]
diff --git a/shell_cmds/sh/tests/parser/alias9.0 b/shell_cmds/sh/tests/parser/alias9.0
new file mode 100644
index 0000000..bbcb4ce
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/alias9.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/alias9.0 242721 2012-11-07 23:15:36Z jilles $
+
+alias alias0=:
+alias alias0=exit
+eval 'alias0 0'
+exit 1
diff --git a/shell_cmds/sh/tests/parser/and-pipe-not.0 b/shell_cmds/sh/tests/parser/and-pipe-not.0
new file mode 100644
index 0000000..fffb1d4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/and-pipe-not.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/parser/and-pipe-not.0 191010 2009-04-13 19:12:28Z stefanf $
+true && ! true | false
diff --git a/shell_cmds/sh/tests/parser/case1.0 b/shell_cmds/sh/tests/parser/case1.0
new file mode 100644
index 0000000..d146399
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/case1.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/parser/case1.0 207824 2010-05-09 17:10:50Z jilles $
+
+keywords='if then else elif fi while until for do done { } case esac ! in'
+
+# Keywords can be used unquoted in case statements, except the keyword
+# esac as the first pattern of a '|' alternation without a starting '('.
+# (POSIX doesn't seem to require (esac) to work.)
+for k in $keywords; do
+ eval "case $k in (foo|$k) ;; *) echo bad ;; esac"
+ eval "case $k in ($k) ;; *) echo bad ;; esac"
+ eval "case $k in foo|$k) ;; *) echo bad ;; esac"
+ [ "$k" = esac ] && continue
+ eval "case $k in $k) ;; *) echo bad ;; esac"
+done
diff --git a/shell_cmds/sh/tests/parser/case2.0 b/shell_cmds/sh/tests/parser/case2.0
new file mode 100644
index 0000000..df5a319
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/case2.0
@@ -0,0 +1,32 @@
+# $FreeBSD: head/bin/sh/tests/parser/case2.0 207824 2010-05-09 17:10:50Z jilles $
+
+# Pretty much only ash derivatives can parse all of this.
+
+f1() {
+ x=$(case x in
+ (x|esac) ;;
+ (*) echo bad >&2 ;;
+ esac)
+}
+f1
+f2() {
+ x=$(case x in
+ (x|esac) ;;
+ (*) echo bad >&2
+ esac)
+}
+f2
+f3() {
+ x=$(case x in
+ x|esac) ;;
+ *) echo bad >&2 ;;
+ esac)
+}
+f3
+f4() {
+ x=$(case x in
+ x|esac) ;;
+ *) echo bad >&2
+ esac)
+}
+f4
diff --git a/shell_cmds/sh/tests/parser/comment1.0 b/shell_cmds/sh/tests/parser/comment1.0
new file mode 100644
index 0000000..bdf9c3b
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/comment1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parser/comment1.0 295818 2016-02-19 16:56:07Z jilles $
+
+${SH} -c '#'
diff --git a/shell_cmds/sh/tests/parser/comment2.42 b/shell_cmds/sh/tests/parser/comment2.42
new file mode 100644
index 0000000..7e623c9
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/comment2.42
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parser/comment2.42 295818 2016-02-19 16:56:07Z jilles $
+
+${SH} -c '#
+exit 42'
diff --git a/shell_cmds/sh/tests/parser/dollar-quote1.0 b/shell_cmds/sh/tests/parser/dollar-quote1.0
new file mode 100644
index 0000000..1206141
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote1.0
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+set -e
+
+[ $'hi' = hi ]
+[ $'hi
+there' = 'hi
+there' ]
+[ $'\"\'\\\a\b\f\t\v' = "\"'\\$(printf "\a\b\f\t\v")" ]
+[ $'hi\nthere' = 'hi
+there' ]
+[ $'a\rb' = "$(printf "a\rb")" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote10.0 b/shell_cmds/sh/tests/parser/dollar-quote10.0
new file mode 100644
index 0000000..745d3aa
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote10.0
@@ -0,0 +1,10 @@
+# $FreeBSD: head/bin/sh/tests/parser/dollar-quote10.0 221669 2011-05-08 17:40:10Z jilles $
+
+# a umlaut
+s=$(printf '\303\244')
+# euro sign
+s=$s$(printf '\342\202\254')
+
+# Start a new shell so the locale change is picked up.
+ss="$(LC_ALL=en_US.UTF-8 ${SH} -c "printf %s \$'\u00e4\u20ac'")"
+[ "$s" = "$ss" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote11.0 b/shell_cmds/sh/tests/parser/dollar-quote11.0
new file mode 100644
index 0000000..b9db067
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote11.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/dollar-quote11.0 221669 2011-05-08 17:40:10Z jilles $
+
+# some sort of 't' outside BMP
+s=$s$(printf '\360\235\225\245')
+
+# Start a new shell so the locale change is picked up.
+ss="$(LC_ALL=en_US.UTF-8 ${SH} -c "printf %s \$'\U0001d565'")"
+[ "$s" = "$ss" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote12.0 b/shell_cmds/sh/tests/parser/dollar-quote12.0
new file mode 100644
index 0000000..bb06e3c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote12.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/dollar-quote12.0 286971 2015-08-20 21:31:36Z jilles $
+
+# \u without any digits at all remains invalid.
+# Our choice is a parse error.
+
+v=$( (eval ": \$'\u'") 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote13.0 b/shell_cmds/sh/tests/parser/dollar-quote13.0
new file mode 100644
index 0000000..fe31d9d
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote13.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/dollar-quote13.0 286973 2015-08-20 22:05:55Z jilles $
+
+# This Unicode escape sequence that has never been in range should either
+# fail to expand or expand to a fallback.
+
+c=$(eval printf %s \$\'\\Uffffff41\' 2>/dev/null)
+r=$(($? != 0))
+[ "$r.$c" = '1.' ] || [ "$r.$c" = '0.?' ] || [ "$r.$c" = $'0.\u2222' ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote2.0 b/shell_cmds/sh/tests/parser/dollar-quote2.0
new file mode 100644
index 0000000..4617ed8
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote2.0
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+# This depends on the ASCII character set.
+
+[ $'\e' = "$(printf "\033")" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote3.0 b/shell_cmds/sh/tests/parser/dollar-quote3.0
new file mode 100644
index 0000000..a7e6852
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote3.0
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+e=
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ e="$e\\$i$j$k"
+ done
+ done
+done
+ee=`printf "$e"`
+[ "${#ee}" = 255 ] || echo length bad
+
+# Start a new shell so the locale change is picked up.
+[ "$(${SH} -c "printf %s \$'$e'")" = "$ee" ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote4.0 b/shell_cmds/sh/tests/parser/dollar-quote4.0
new file mode 100644
index 0000000..f620af5
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote4.0
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+unset LC_ALL
+LC_CTYPE=en_US.ISO8859-1
+export LC_CTYPE
+
+e=
+for i in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
+ for j in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
+ case $i$j in
+ 00) continue ;;
+ esac
+ e="$e\x$i$j"
+ done
+done
+
+# Start a new shell so the locale change is picked up.
+ee="$(${SH} -c "printf %s \$'$e'")"
+[ "${#ee}" = 255 ] || echo length bad
diff --git a/shell_cmds/sh/tests/parser/dollar-quote5.0 b/shell_cmds/sh/tests/parser/dollar-quote5.0
new file mode 100644
index 0000000..c2c44ca
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote5.0
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+# This depends on the ASCII character set.
+
+set -e
+
+[ $'\ca\cb\cc\cd\ce\cf\cg\ch\ci\cj\ck\cl\cm\cn\co\cp\cq\cr\cs\ct\cu\cv\cw\cx\cy\cz' = $'\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032' ]
+[ $'\cA\cB\cC\cD\cE\cF\cG\cH\cI\cJ\cK\cL\cM\cN\cO\cP\cQ\cR\cS\cT\cU\cV\cW\cX\cY\cZ' = $'\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032' ]
+[ $'\c[' = $'\033' ]
+[ $'\c]' = $'\035' ]
+[ $'\c^' = $'\036' ]
+[ $'\c_' = $'\037' ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote6.0 b/shell_cmds/sh/tests/parser/dollar-quote6.0
new file mode 100644
index 0000000..a4b1e3f
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote6.0
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+# This depends on the ASCII character set.
+
+[ $'\c\\' = $'\034' ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote7.0 b/shell_cmds/sh/tests/parser/dollar-quote7.0
new file mode 100644
index 0000000..c866b1a
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote7.0
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+set -e
+
+[ $'\u0024\u0040\u0060' = '$@`' ]
+[ $'\U00000024\U00000040\U00000060' = '$@`' ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote8.0 b/shell_cmds/sh/tests/parser/dollar-quote8.0
new file mode 100644
index 0000000..8f0b41a
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote8.0
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+[ $'hello\0' = hello ]
+[ $'hello\0world' = hello ]
+[ $'hello\0'$'world' = helloworld ]
+[ $'hello\000' = hello ]
+[ $'hello\000world' = hello ]
+[ $'hello\000'$'world' = helloworld ]
+[ $'hello\x00' = hello ]
+[ $'hello\x00world' = hello ]
+[ $'hello\x00'$'world' = helloworld ]
diff --git a/shell_cmds/sh/tests/parser/dollar-quote9.0 b/shell_cmds/sh/tests/parser/dollar-quote9.0
new file mode 100644
index 0000000..df64b7d
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/dollar-quote9.0
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+# POSIX and C99 say D800-DFFF are undefined in a universal character name.
+# We reject this but many other shells expand to something that looks like
+# CESU-8.
+
+v=$( (eval ": \$'\uD800'") 2>&1 >/dev/null)
+[ $? -ne 0 ] && [ -n "$v" ]
diff --git a/shell_cmds/sh/tests/parser/empty-braces1.0 b/shell_cmds/sh/tests/parser/empty-braces1.0
new file mode 100644
index 0000000..4aac806
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/empty-braces1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/empty-braces1.0 245382 2013-01-13 19:26:33Z jilles $
+
+# Unfortunately, some scripts depend on the extension of allowing an empty
+# pair of braces.
+
+{ } &
+wait $!
diff --git a/shell_cmds/sh/tests/parser/empty-cmd1.0 b/shell_cmds/sh/tests/parser/empty-cmd1.0
new file mode 100644
index 0000000..60aaa00
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/empty-cmd1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parser/empty-cmd1.0 254843 2013-08-25 10:57:48Z jilles $
+
+! (eval ': || f()') 2>/dev/null
diff --git a/shell_cmds/sh/tests/parser/for1.0 b/shell_cmds/sh/tests/parser/for1.0
new file mode 100644
index 0000000..d863f0a
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/for1.0
@@ -0,0 +1,29 @@
+# $FreeBSD: head/bin/sh/tests/parser/for1.0 218889 2011-02-20 14:18:58Z jilles $
+
+nl='
+'
+list=' a b c'
+for s1 in "$nl" " "; do
+ for s2 in "$nl" ";" ";$nl"; do
+ for s3 in "$nl" " "; do
+ r=''
+ eval "for i${s1}in ${list}${s2}do${s3}r=\"\$r \$i\"; done"
+ [ "$r" = "$list" ] || exit 1
+ done
+ done
+done
+set -- $list
+for s2 in "$nl" " "; do
+ for s3 in "$nl" " "; do
+ r=''
+ eval "for i${s2}do${s3}r=\"\$r \$i\"; done"
+ [ "$r" = "$list" ] || exit 1
+ done
+done
+for s1 in "$nl" " "; do
+ for s2 in "$nl" ";" ";$nl"; do
+ for s3 in "$nl" " "; do
+ eval "for i${s1}in${s2}do${s3}exit 1; done"
+ done
+ done
+done
diff --git a/shell_cmds/sh/tests/parser/for2.0 b/shell_cmds/sh/tests/parser/for2.0
new file mode 100644
index 0000000..8ed92dc
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/for2.0
@@ -0,0 +1,15 @@
+# $FreeBSD: head/bin/sh/tests/parser/for2.0 218889 2011-02-20 14:18:58Z jilles $
+
+# Common extensions to the 'for' syntax.
+
+nl='
+'
+list=' a b c'
+set -- $list
+for s2 in ";" ";$nl"; do
+ for s3 in "$nl" " "; do
+ r=''
+ eval "for i${s2}do${s3}r=\"\$r \$i\"; done"
+ [ "$r" = "$list" ] || exit 1
+ done
+done
diff --git a/shell_cmds/sh/tests/parser/func1.0 b/shell_cmds/sh/tests/parser/func1.0
new file mode 100644
index 0000000..4e82da4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/func1.0
@@ -0,0 +1,25 @@
+# $FreeBSD: head/bin/sh/tests/parser/func1.0 214291 2010-10-24 20:45:13Z jilles $
+# POSIX does not require these bytes to work in function names,
+# but making them all work seems a good goal.
+
+failures=0
+unset LC_ALL
+export LC_CTYPE=en_US.ISO8859-1
+i=128
+set -f
+while [ "$i" -le 255 ]; do
+ c=$(printf \\"$(printf %o "$i")")
+ ok=0
+ eval "$c() { ok=1; }"
+ $c
+ ok1=$ok
+ ok=0
+ "$c"
+ if [ "$ok" != 1 ] || [ "$ok1" != 1 ]; then
+ echo "Bad results for character $i" >&2
+ : $((failures += 1))
+ fi
+ unset -f $c
+ i=$((i+1))
+done
+exit $((failures > 0))
diff --git a/shell_cmds/sh/tests/parser/func2.0 b/shell_cmds/sh/tests/parser/func2.0
new file mode 100644
index 0000000..5b86522
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/func2.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/func2.0 222512 2011-05-30 21:49:59Z jilles $
+
+f() { return 42; }
+f() { return 3; } &
+f
+[ $? -eq 42 ]
diff --git a/shell_cmds/sh/tests/parser/func3.0 b/shell_cmds/sh/tests/parser/func3.0
new file mode 100644
index 0000000..c4f4922
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/func3.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/func3.0 222512 2011-05-30 21:49:59Z jilles $
+
+name=/var/empty/nosuch
+f() { true; } <$name
+name=/dev/null
+f
diff --git a/shell_cmds/sh/tests/parser/heredoc1.0 b/shell_cmds/sh/tests/parser/heredoc1.0
new file mode 100644
index 0000000..4020249
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc1.0
@@ -0,0 +1,85 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc1.0 204836 2010-03-07 15:08:42Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(cat <<EOF
+hi
+EOF
+)" = hi'
+
+check '"$(cat <<EOF
+${$+hi}
+EOF
+)" = hi'
+
+unset yy
+check '"$(cat <<EOF
+${yy-hi}
+EOF
+)" = hi'
+
+check '"$(cat <<EOF
+${$+hi
+there}
+EOF
+)" = "hi
+there"'
+
+check '"$(cat <<EOF
+$((1+1))
+EOF
+)" = 2'
+
+check '"$(cat <<EOF
+$(echo hi)
+EOF
+)" = hi'
+
+check '"$(cat <<EOF
+`echo hi`
+EOF
+)" = hi'
+
+check '"$(cat <<\EOF
+${$+hi}
+EOF
+)" = "\${\$+hi}"'
+
+check '"$(cat <<\EOF
+$(
+EOF
+)" = \$\('
+
+check '"$(cat <<\EOF
+`
+EOF
+)" = \`'
+
+check '"$(cat <<EOF
+"
+EOF
+)" = \"'
+
+check '"$(cat <<\EOF
+"
+EOF
+)" = \"'
+
+check '"$(cat <<esac
+'"'"'
+esac
+)" = "'"'"'"'
+
+check '"$(cat <<\)
+'"'"'
+)
+)" = "'"'"'"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc10.0 b/shell_cmds/sh/tests/parser/heredoc10.0
new file mode 100644
index 0000000..f5133b9
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc10.0
@@ -0,0 +1,49 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc10.0 221887 2011-05-14 14:19:30Z jilles $
+
+# It may be argued that
+# x=$(cat <<EOF
+# foo
+# EOF)
+# is a valid complete command that sets x to foo, because
+# cat <<EOF
+# foo
+# EOF
+# is a valid script even without the final newline.
+# However, if the here-document is not within a new-style command substitution
+# or there are other constructs nested inside the command substitution that
+# need terminators, the delimiter at the start of a line followed by a close
+# parenthesis is clearly a literal part of the here-document.
+
+# This file contains tests that may not work with simplistic $(...) parsers.
+# The open parentheses in comments help mksh, but not zsh.
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(cat <<EOF # (
+EOF )
+EOF
+)" = "EOF )"'
+
+check '"$({ cat <<EOF # (
+EOF)
+EOF
+})" = "EOF)"'
+
+check '"$(if :; then cat <<EOF # (
+EOF)
+EOF
+fi)" = "EOF)"'
+
+check '"$( (cat <<EOF # (
+EOF)
+EOF
+))" = "EOF)"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc11.0 b/shell_cmds/sh/tests/parser/heredoc11.0
new file mode 100644
index 0000000..3e74aea
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc11.0
@@ -0,0 +1,26 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc11.0 222134 2011-05-20 16:03:36Z jilles $
+
+failures=''
+
+check() {
+ if eval "[ $* ]"; then
+ :
+ else
+ echo "Failed: $*"
+ failures=x$failures
+ fi
+}
+
+check '`cat <<EOF
+foo
+EOF` = foo'
+
+check '"`cat <<EOF
+foo
+EOF`" = foo'
+
+check '`eval "cat <<EOF
+foo
+EOF"` = foo'
+
+test "x$failures" = x
diff --git a/shell_cmds/sh/tests/parser/heredoc12.0 b/shell_cmds/sh/tests/parser/heredoc12.0
new file mode 100644
index 0000000..644cae1
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc12.0
@@ -0,0 +1,47 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc12.0 271593 2014-09-14 16:46:30Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+longmark=`printf %01000d 4`
+longmarkstripped=`printf %0999d 0`
+
+check '"$(cat <<'"$longmark
+$longmark"'
+echo yes)" = "yes"'
+
+check '"$(cat <<\'"$longmark
+$longmark"'
+echo yes)" = "yes"'
+
+check '"$(cat <<'"$longmark
+yes
+$longmark"'
+)" = "yes"'
+
+check '"$(cat <<\'"$longmark
+yes
+$longmark"'
+)" = "yes"'
+
+check '"$(cat <<'"$longmark
+$longmarkstripped
+$longmark.
+$longmark"'
+)" = "'"$longmarkstripped
+$longmark."'"'
+
+check '"$(cat <<\'"$longmark
+$longmarkstripped
+$longmark.
+$longmark"'
+)" = "'"$longmarkstripped
+$longmark."'"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc13.0 b/shell_cmds/sh/tests/parser/heredoc13.0
new file mode 100644
index 0000000..4eb45e0
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc13.0
@@ -0,0 +1,21 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc13.0 287408 2015-09-02 19:49:55Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '"$(cat <<""
+
+echo yes)" = "yes"'
+
+check '"$(cat <<""
+yes
+
+)" = "yes"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc2.0 b/shell_cmds/sh/tests/parser/heredoc2.0
new file mode 100644
index 0000000..f07f5d4
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc2.0
@@ -0,0 +1,39 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc2.0 211405 2010-08-16 21:14:49Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+s='ast*que?non' sq=\' dq=\"
+
+check '"$(cat <<EOF
+${s}
+EOF
+)" = "ast*que?non"'
+
+check '"$(cat <<EOF
+${s+'$sq'x'$sq'}
+EOF
+)" = ${sq}x${sq}'
+
+check '"$(cat <<EOF
+${s#ast}
+EOF
+)" = "*que?non"'
+
+check '"$(cat <<EOF
+${s##"ast"}
+EOF
+)" = "*que?non"'
+
+check '"$(cat <<EOF
+${s##'$sq'ast'$sq'}
+EOF
+)" = "*que?non"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc3.0 b/shell_cmds/sh/tests/parser/heredoc3.0
new file mode 100644
index 0000000..15c0a1c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc3.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc3.0 207824 2010-05-09 17:10:50Z jilles $
+
+# This may be expected to work, but pretty much only ash derivatives allow it.
+
+test "$(cat <<EOF)" = "hi there"
+hi there
+EOF
diff --git a/shell_cmds/sh/tests/parser/heredoc4.0 b/shell_cmds/sh/tests/parser/heredoc4.0
new file mode 100644
index 0000000..a544354
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc4.0
@@ -0,0 +1,44 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc4.0 208655 2010-05-30 14:11:27Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+f() {
+ cat <<EOF && echo `echo bar`
+foo
+EOF
+}
+check '"`f`" = "foo
+bar"'
+
+f() {
+ cat <<EOF && echo $(echo bar)
+foo
+EOF
+}
+check '"$(f)" = "foo
+bar"'
+
+f() {
+ echo `echo bar` && cat <<EOF
+foo
+EOF
+}
+check '"`f`" = "bar
+foo"'
+
+f() {
+ echo $(echo bar) && cat <<EOF
+foo
+EOF
+}
+check '"$(f)" = "bar
+foo"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc5.0 b/shell_cmds/sh/tests/parser/heredoc5.0
new file mode 100644
index 0000000..0bcc617
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc5.0
@@ -0,0 +1,56 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc5.0 208655 2010-05-30 14:11:27Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+f() {
+ cat <<EOF && echo `cat <<EOF
+bar
+EOF
+`
+foo
+EOF
+}
+check '"`f`" = "foo
+bar"'
+
+f() {
+ cat <<EOF && echo $(cat <<EOF
+bar
+EOF
+)
+foo
+EOF
+}
+check '"$(f)" = "foo
+bar"'
+
+f() {
+ echo `cat <<EOF
+bar
+EOF
+` && cat <<EOF
+foo
+EOF
+}
+check '"`f`" = "bar
+foo"'
+
+f() {
+ echo $(cat <<EOF
+bar
+EOF
+) && cat <<EOF
+foo
+EOF
+}
+check '"$(f)" = "bar
+foo"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc6.0 b/shell_cmds/sh/tests/parser/heredoc6.0
new file mode 100644
index 0000000..003f548
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc6.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc6.0 208656 2010-05-30 14:20:32Z jilles $
+
+r=
+! command eval ": <<EOF; )" 2>/dev/null; command eval : hi \${r:=0}
+exit ${r:-3}
diff --git a/shell_cmds/sh/tests/parser/heredoc7.0 b/shell_cmds/sh/tests/parser/heredoc7.0
new file mode 100644
index 0000000..28d867c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc7.0
@@ -0,0 +1,19 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc7.0 210488 2010-07-25 22:25:52Z jilles $
+
+# Some of these created malformed parse trees with null pointers for here
+# documents, causing the here document writing process to segfault.
+eval ': <<EOF'
+eval ': <<EOF;'
+eval '`: <<EOF`'
+eval '`: <<EOF;`'
+eval '`: <<EOF`;'
+eval '`: <<EOF;`;'
+
+# Some of these created malformed parse trees with null pointers for here
+# documents, causing sh to segfault.
+eval ': <<\EOF'
+eval ': <<\EOF;'
+eval '`: <<\EOF`'
+eval '`: <<\EOF;`'
+eval '`: <<\EOF`;'
+eval '`: <<\EOF;`;'
diff --git a/shell_cmds/sh/tests/parser/heredoc8.0 b/shell_cmds/sh/tests/parser/heredoc8.0
new file mode 100644
index 0000000..482c060
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc8.0
@@ -0,0 +1,20 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc8.0 211405 2010-08-16 21:14:49Z jilles $
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+s='ast*que?non' sq=\' dq=\"
+
+# This is possibly useful but differs from other shells.
+check '"$(cat <<EOF
+${s+"x"}
+EOF
+)" = ${dq}x${dq}'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/heredoc9.0 b/shell_cmds/sh/tests/parser/heredoc9.0
new file mode 100644
index 0000000..bb4a04c
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/heredoc9.0
@@ -0,0 +1,58 @@
+# $FreeBSD: head/bin/sh/tests/parser/heredoc9.0 221887 2011-05-14 14:19:30Z jilles $
+
+# It may be argued that
+# x=$(cat <<EOF
+# foo
+# EOF)
+# is a valid complete command that sets x to foo, because
+# cat <<EOF
+# foo
+# EOF
+# is a valid script even without the final newline.
+# However, if the here-document is not within a new-style command substitution
+# or there are other constructs nested inside the command substitution that
+# need terminators, the delimiter at the start of a line followed by a close
+# parenthesis is clearly a literal part of the here-document.
+
+# This file contains tests that also work with simplistic $(...) parsers.
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+check '`${SH} -c "cat <<EOF
+EOF)
+EOF
+"` = "EOF)"'
+
+check '`${SH} -c "(cat <<EOF
+EOF)
+EOF
+)"` = "EOF)"'
+
+check '"`cat <<EOF
+EOF x
+EOF
+`" = "EOF x"'
+
+check '"`cat <<EOF
+EOF )
+EOF
+`" = "EOF )"'
+
+check '"`cat <<EOF
+EOF)
+EOF
+`" = "EOF)"'
+
+check '"$(cat <<EOF
+EOF x
+EOF
+)" = "EOF x"'
+
+exit $((failures != 0))
diff --git a/shell_cmds/sh/tests/parser/line-cont1.0 b/shell_cmds/sh/tests/parser/line-cont1.0
new file mode 100644
index 0000000..717c2c2
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont1.0
@@ -0,0 +1,16 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont1.0 273243 2014-10-17 21:52:57Z jilles $
+
+i\
+f
+t\
+r\
+u\
+e
+t\
+h\
+e\
+n
+:
+\
+f\
+i
diff --git a/shell_cmds/sh/tests/parser/line-cont10.0 b/shell_cmds/sh/tests/parser/line-cont10.0
new file mode 100644
index 0000000..dbb064b
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont10.0
@@ -0,0 +1,18 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont10.0 273276 2014-10-19 11:59:15Z jilles $
+
+v=XaaaXbbbX
+[ "${v\
+#\
+*\
+a}.${v\
+#\
+#\
+*\
+a}.${v\
+%\
+b\
+*}.${v\
+%\
+%\
+b\
+*}" = aaXbbbX.XbbbX.XaaaXbb.XaaaX ]
diff --git a/shell_cmds/sh/tests/parser/line-cont11.0 b/shell_cmds/sh/tests/parser/line-cont11.0
new file mode 100644
index 0000000..f398a98
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont11.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont11.0 273276 2014-10-19 11:59:15Z jilles $
+
+T=$(mktemp "${TMPDIR:-/tmp}/sh-test.XXXXXXXX") || exit
+trap 'rm -f -- "$T"' 0
+w='#A'
+# A naive pgetc_linecont() would push back two characters here, which
+# fails if a new buffer is read between the two characters.
+c='${w#\#}'
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+printf 'v=%s\n' "$c" >"$T"
+. "$T"
+if [ "${#v}" != 4096 ]; then
+ echo "Length is bad (${#v})"
+ exit 3
+fi
+case $v in
+*[!A]*) echo "Content is bad"; exit 3 ;;
+esac
diff --git a/shell_cmds/sh/tests/parser/line-cont2.0 b/shell_cmds/sh/tests/parser/line-cont2.0
new file mode 100644
index 0000000..83928cf
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont2.0 273243 2014-10-17 21:52:57Z jilles $
+
+[ "a\
+b" = ab ]
diff --git a/shell_cmds/sh/tests/parser/line-cont3.0 b/shell_cmds/sh/tests/parser/line-cont3.0
new file mode 100644
index 0000000..cc2af7b
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont3.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont3.0 273243 2014-10-17 21:52:57Z jilles $
+
+v=`printf %s 'a\
+b'`
+w="`printf %s 'c\
+d'`"
+[ "$v$w" = abcd ]
diff --git a/shell_cmds/sh/tests/parser/line-cont4.0 b/shell_cmds/sh/tests/parser/line-cont4.0
new file mode 100644
index 0000000..7d59c19
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont4.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont4.0 273276 2014-10-19 11:59:15Z jilles $
+
+v=abcd
+[ "$\
+v.$\
+{v}.${\
+v}.${v\
+}" = abcd.abcd.abcd.abcd ]
diff --git a/shell_cmds/sh/tests/parser/line-cont5.0 b/shell_cmds/sh/tests/parser/line-cont5.0
new file mode 100644
index 0000000..23a4d94
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont5.0
@@ -0,0 +1,14 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont5.0 273276 2014-10-19 11:59:15Z jilles $
+
+bad=1
+case x in
+x\
+) ;\
+; *) exit 7
+esac &\
+& bad= &\
+& : >\
+>/dev/null
+
+false |\
+| [ -z "$bad" ]
diff --git a/shell_cmds/sh/tests/parser/line-cont6.0 b/shell_cmds/sh/tests/parser/line-cont6.0
new file mode 100644
index 0000000..66838e1
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont6.0
@@ -0,0 +1,23 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont6.0 273276 2014-10-19 11:59:15Z jilles $
+
+v0\
+=abc
+
+v=$(cat <\
+<\
+E\
+O\
+F
+${v0}d
+EOF
+)
+
+w=$(cat <\
+<\
+-\
+EOF
+ efgh
+EOF
+)
+
+[ "$v.$w" = "abcd.efgh" ]
diff --git a/shell_cmds/sh/tests/parser/line-cont7.0 b/shell_cmds/sh/tests/parser/line-cont7.0
new file mode 100644
index 0000000..6c48642
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont7.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont7.0 273276 2014-10-19 11:59:15Z jilles $
+
+[ "$(\
+(
+1\
++ 1)\
+)" = 2 ]
diff --git a/shell_cmds/sh/tests/parser/line-cont8.0 b/shell_cmds/sh/tests/parser/line-cont8.0
new file mode 100644
index 0000000..8fc84bb
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont8.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont8.0 273276 2014-10-19 11:59:15Z jilles $
+
+set -- a b c d e f g h i j
+[ "${1\
+0\
+}" = j ]
diff --git a/shell_cmds/sh/tests/parser/line-cont9.0 b/shell_cmds/sh/tests/parser/line-cont9.0
new file mode 100644
index 0000000..9618ae2
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/line-cont9.0
@@ -0,0 +1,6 @@
+# $FreeBSD: head/bin/sh/tests/parser/line-cont9.0 273276 2014-10-19 11:59:15Z jilles $
+
+[ "${$\
+:\
++\
+xyz}" = xyz ]
diff --git a/shell_cmds/sh/tests/parser/no-space1.0 b/shell_cmds/sh/tests/parser/no-space1.0
new file mode 100644
index 0000000..5b15bfe
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/no-space1.0
@@ -0,0 +1,18 @@
+# $FreeBSD: head/bin/sh/tests/parser/no-space1.0 218891 2011-02-20 17:28:58Z jilles $
+
+# These are ugly but are required to work.
+
+set -e
+
+while(false)do(:)done
+if(false)then(:)fi
+if(false)then(:)else(:)fi
+(:&&:)||:
+until(:)do(:)done
+case x in(x);;*)exit 1;(:)esac
+case x in(x);;*)exit 1;;esac
+for i do(:)done
+{(:)}
+f(){(:)}
+:|:
+(:)|(:)
diff --git a/shell_cmds/sh/tests/parser/no-space2.0 b/shell_cmds/sh/tests/parser/no-space2.0
new file mode 100644
index 0000000..0f63e6e
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/no-space2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/parser/no-space2.0 218891 2011-02-20 17:28:58Z jilles $
+
+# This conflicts with ksh extended patterns but occurs in the wild.
+
+set -e
+
+!(false)
diff --git a/shell_cmds/sh/tests/parser/nul1.0 b/shell_cmds/sh/tests/parser/nul1.0
new file mode 100644
index 0000000..bb5442e
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/nul1.0
@@ -0,0 +1,12 @@
+# $FreeBSD: head/bin/sh/tests/parser/nul1.0 295825 2016-02-19 21:53:12Z jilles $
+# Although POSIX does not specify the effect of NUL bytes in scripts,
+# we ignore them.
+
+{
+ printf 'v=%03000d\0%02000d' 7 2
+ dd if=/dev/zero bs=1000 count=1 status=none
+ printf '1 w=%03000d%02000d1\0\n' 7 2
+ printf '\0l\0v\0=\0$\0{\0#\0v\0}\n'
+ printf '\0l\0w\0=\0\0$\0{\0#\0w}\0\0\0\n'
+ printf '[ "$lv.$lw.$v" = "5001.5001.$w" ]\n'
+} | ${SH}
diff --git a/shell_cmds/sh/tests/parser/only-redir1.0 b/shell_cmds/sh/tests/parser/only-redir1.0
new file mode 100644
index 0000000..7aedde7
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/only-redir1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parser/only-redir1.0 210221 2010-07-18 12:45:31Z jilles $
+</dev/null &
+wait $!
diff --git a/shell_cmds/sh/tests/parser/only-redir2.0 b/shell_cmds/sh/tests/parser/only-redir2.0
new file mode 100644
index 0000000..b55be16
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/only-redir2.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/parser/only-redir2.0 254335 2013-08-14 19:34:13Z jilles $
+</dev/null | :
diff --git a/shell_cmds/sh/tests/parser/only-redir3.0 b/shell_cmds/sh/tests/parser/only-redir3.0
new file mode 100644
index 0000000..f51617b
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/only-redir3.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/parser/only-redir3.0 254335 2013-08-14 19:34:13Z jilles $
+case x in x) </dev/null ;; esac
diff --git a/shell_cmds/sh/tests/parser/only-redir4.0 b/shell_cmds/sh/tests/parser/only-redir4.0
new file mode 100644
index 0000000..a3ce893
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/only-redir4.0
@@ -0,0 +1,2 @@
+# $FreeBSD: head/bin/sh/tests/parser/only-redir4.0 254335 2013-08-14 19:34:13Z jilles $
+case x in x) </dev/null ;& esac
diff --git a/shell_cmds/sh/tests/parser/pipe-not1.0 b/shell_cmds/sh/tests/parser/pipe-not1.0
new file mode 100644
index 0000000..421e235
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/pipe-not1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/parser/pipe-not1.0 214281 2010-10-24 17:06:49Z jilles $
+
+: | ! : | false
diff --git a/shell_cmds/sh/tests/parser/set-v1.0 b/shell_cmds/sh/tests/parser/set-v1.0
new file mode 100644
index 0000000..c5ed944
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/set-v1.0
@@ -0,0 +1,8 @@
+# $FreeBSD: head/bin/sh/tests/parser/set-v1.0 295937 2016-02-23 22:44:01Z jilles $
+
+${SH} <<\EOF
+echo one >&2
+set -v
+echo two >&2
+echo three >&2
+EOF
diff --git a/shell_cmds/sh/tests/parser/set-v1.0.stderr b/shell_cmds/sh/tests/parser/set-v1.0.stderr
new file mode 100644
index 0000000..d904fa5
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/set-v1.0.stderr
@@ -0,0 +1,5 @@
+one
+echo two >&2
+two
+echo three >&2
+three
diff --git a/shell_cmds/sh/tests/parser/var-assign1.0 b/shell_cmds/sh/tests/parser/var-assign1.0
new file mode 100644
index 0000000..4949bfd
--- /dev/null
+++ b/shell_cmds/sh/tests/parser/var-assign1.0
@@ -0,0 +1,19 @@
+# $FreeBSD: head/bin/sh/tests/parser/var-assign1.0 257920 2013-11-10 18:46:59Z jilles $
+# In a variable assignment, both the name and the equals sign must be entirely
+# unquoted. Therefore, there is only one assignment below; the other words
+# containing equals signs are command words.
+
+abc=0
+\abc=1 2>/dev/null
+a\bc=2 2>/dev/null
+abc\=3 2>/dev/null
+a\bc\=4 2>/dev/null
+'abc'=5 2>/dev/null
+a'b'c=6 2>/dev/null
+abc'='7 2>/dev/null
+'abc=8' 2>/dev/null
+"abc"=9 2>/dev/null
+a"b"c=10 2>/dev/null
+abc"="11 2>/dev/null
+"abc=12" 2>/dev/null
+[ "$abc" = 0 ]
diff --git a/shell_cmds/sh/tests/set-e/Makefile b/shell_cmds/sh/tests/set-e/Makefile
new file mode 100644
index 0000000..2f13991
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/Makefile
@@ -0,0 +1,46 @@
+# $FreeBSD: head/bin/sh/tests/set-e/Makefile 299094 2016-05-04 23:20:53Z ngie $
+
+PACKAGE= tests
+
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+${PACKAGE}FILES+= and1.0
+${PACKAGE}FILES+= and2.1
+${PACKAGE}FILES+= and3.0
+${PACKAGE}FILES+= and4.0
+${PACKAGE}FILES+= background1.0
+${PACKAGE}FILES+= cmd1.0
+${PACKAGE}FILES+= cmd2.1
+${PACKAGE}FILES+= elif1.0
+${PACKAGE}FILES+= elif2.0
+${PACKAGE}FILES+= eval1.0
+${PACKAGE}FILES+= eval2.1
+${PACKAGE}FILES+= for1.0
+${PACKAGE}FILES+= func1.0
+${PACKAGE}FILES+= func2.1
+${PACKAGE}FILES+= if1.0
+${PACKAGE}FILES+= if2.0
+${PACKAGE}FILES+= if3.0
+${PACKAGE}FILES+= not1.0
+${PACKAGE}FILES+= not2.0
+${PACKAGE}FILES+= or1.0
+${PACKAGE}FILES+= or2.0
+${PACKAGE}FILES+= or3.1
+${PACKAGE}FILES+= pipe1.1
+${PACKAGE}FILES+= pipe2.0
+${PACKAGE}FILES+= return1.0
+${PACKAGE}FILES+= semi1.1
+${PACKAGE}FILES+= semi2.1
+${PACKAGE}FILES+= subshell1.0
+${PACKAGE}FILES+= subshell2.1
+${PACKAGE}FILES+= until1.0
+${PACKAGE}FILES+= until2.0
+${PACKAGE}FILES+= until3.0
+${PACKAGE}FILES+= while1.0
+${PACKAGE}FILES+= while2.0
+${PACKAGE}FILES+= while3.0
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/sh/tests/set-e/Makefile.depend b/shell_cmds/sh/tests/set-e/Makefile.depend
new file mode 100644
index 0000000..ea8dbbe
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/set-e/Makefile.depend 296587 2016-03-09 22:46:01Z bdrewery $
+# 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/shell_cmds/sh/tests/set-e/and1.0 b/shell_cmds/sh/tests/set-e/and1.0
new file mode 100644
index 0000000..4518124
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/and1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/and1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true && true
diff --git a/shell_cmds/sh/tests/set-e/and2.1 b/shell_cmds/sh/tests/set-e/and2.1
new file mode 100644
index 0000000..2067f10
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/and2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/and2.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true && false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/and3.0 b/shell_cmds/sh/tests/set-e/and3.0
new file mode 100644
index 0000000..59dccce
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/and3.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/and3.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false && true
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/and4.0 b/shell_cmds/sh/tests/set-e/and4.0
new file mode 100644
index 0000000..fd1cc72
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/and4.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/and4.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false && false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/background1.0 b/shell_cmds/sh/tests/set-e/background1.0
new file mode 100644
index 0000000..e31b7a3
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/background1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/background1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false &
diff --git a/shell_cmds/sh/tests/set-e/cmd1.0 b/shell_cmds/sh/tests/set-e/cmd1.0
new file mode 100644
index 0000000..7c6c843
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/cmd1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/cmd1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true
diff --git a/shell_cmds/sh/tests/set-e/cmd2.1 b/shell_cmds/sh/tests/set-e/cmd2.1
new file mode 100644
index 0000000..05a4243
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/cmd2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/cmd2.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/elif1.0 b/shell_cmds/sh/tests/set-e/elif1.0
new file mode 100644
index 0000000..38ccaec
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/elif1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/elif1.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+if false; then
+ :
+elif false; then
+ :
+fi
diff --git a/shell_cmds/sh/tests/set-e/elif2.0 b/shell_cmds/sh/tests/set-e/elif2.0
new file mode 100644
index 0000000..694b3f0
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/elif2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/elif2.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+if false; then
+ :
+elif false; false; then
+ :
+fi
diff --git a/shell_cmds/sh/tests/set-e/eval1.0 b/shell_cmds/sh/tests/set-e/eval1.0
new file mode 100644
index 0000000..cefaf91
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/eval1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/eval1.0 193178 2009-05-31 17:23:27Z stefanf $
+set -e
+eval false || true
diff --git a/shell_cmds/sh/tests/set-e/eval2.1 b/shell_cmds/sh/tests/set-e/eval2.1
new file mode 100644
index 0000000..e396e1c
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/eval2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/eval2.1 193178 2009-05-31 17:23:27Z stefanf $
+set -e
+eval false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/for1.0 b/shell_cmds/sh/tests/set-e/for1.0
new file mode 100644
index 0000000..d0f7d8f
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/for1.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/set-e/for1.0 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ for i in a b c; do
+ false
+ true
+ done
+}
+f || true
diff --git a/shell_cmds/sh/tests/set-e/func1.0 b/shell_cmds/sh/tests/set-e/func1.0
new file mode 100644
index 0000000..c76d689
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/func1.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/func1.0 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ false
+ true
+}
+f || true
diff --git a/shell_cmds/sh/tests/set-e/func2.1 b/shell_cmds/sh/tests/set-e/func2.1
new file mode 100644
index 0000000..267966d
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/func2.1
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/func2.1 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ false
+ exit 0
+}
+f
diff --git a/shell_cmds/sh/tests/set-e/if1.0 b/shell_cmds/sh/tests/set-e/if1.0
new file mode 100644
index 0000000..5697e2f
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/if1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/if1.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+if false; then
+ :
+fi
diff --git a/shell_cmds/sh/tests/set-e/if2.0 b/shell_cmds/sh/tests/set-e/if2.0
new file mode 100644
index 0000000..188361b
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/if2.0
@@ -0,0 +1,7 @@
+# $FreeBSD: head/bin/sh/tests/set-e/if2.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+# PR 28852
+if true; then
+ false && true
+fi
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/if3.0 b/shell_cmds/sh/tests/set-e/if3.0
new file mode 100644
index 0000000..e3d8d6e
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/if3.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/if3.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+if false; false; then
+ :
+fi
diff --git a/shell_cmds/sh/tests/set-e/not1.0 b/shell_cmds/sh/tests/set-e/not1.0
new file mode 100644
index 0000000..b694be8
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/not1.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/not1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+! true
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/not2.0 b/shell_cmds/sh/tests/set-e/not2.0
new file mode 100644
index 0000000..d9ea5e9
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/not2.0
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/not2.0 193178 2009-05-31 17:23:27Z stefanf $
+set -e
+! false
+! eval false
diff --git a/shell_cmds/sh/tests/set-e/or1.0 b/shell_cmds/sh/tests/set-e/or1.0
new file mode 100644
index 0000000..5000f0b
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/or1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/or1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true || false
diff --git a/shell_cmds/sh/tests/set-e/or2.0 b/shell_cmds/sh/tests/set-e/or2.0
new file mode 100644
index 0000000..6964220
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/or2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/or2.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false || true
diff --git a/shell_cmds/sh/tests/set-e/or3.1 b/shell_cmds/sh/tests/set-e/or3.1
new file mode 100644
index 0000000..29af2c2
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/or3.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/or3.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false || false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/pipe1.1 b/shell_cmds/sh/tests/set-e/pipe1.1
new file mode 100644
index 0000000..122af07
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/pipe1.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/pipe1.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true | false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/pipe2.0 b/shell_cmds/sh/tests/set-e/pipe2.0
new file mode 100644
index 0000000..d80fd93
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/pipe2.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/pipe2.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false | true
diff --git a/shell_cmds/sh/tests/set-e/return1.0 b/shell_cmds/sh/tests/set-e/return1.0
new file mode 100644
index 0000000..d157059
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/return1.0
@@ -0,0 +1,11 @@
+# $FreeBSD: head/bin/sh/tests/set-e/return1.0 149788 2005-09-04 21:29:09Z stefanf $
+set -e
+
+# PR 77067, 85267
+f() {
+ return 1
+ true
+}
+
+f || true
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/semi1.1 b/shell_cmds/sh/tests/set-e/semi1.1
new file mode 100644
index 0000000..5991f8d
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/semi1.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/semi1.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+false; true
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/semi2.1 b/shell_cmds/sh/tests/set-e/semi2.1
new file mode 100644
index 0000000..6851700
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/semi2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/semi2.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+true; false
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/subshell1.0 b/shell_cmds/sh/tests/set-e/subshell1.0
new file mode 100644
index 0000000..fa2ec82
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/subshell1.0
@@ -0,0 +1,3 @@
+# $FreeBSD: head/bin/sh/tests/set-e/subshell1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+(true)
diff --git a/shell_cmds/sh/tests/set-e/subshell2.1 b/shell_cmds/sh/tests/set-e/subshell2.1
new file mode 100644
index 0000000..03b09dc
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/subshell2.1
@@ -0,0 +1,4 @@
+# $FreeBSD: head/bin/sh/tests/set-e/subshell2.1 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+(false)
+exit 0
diff --git a/shell_cmds/sh/tests/set-e/until1.0 b/shell_cmds/sh/tests/set-e/until1.0
new file mode 100644
index 0000000..c4d2edd
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/until1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/until1.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+until false; do
+ break
+done
diff --git a/shell_cmds/sh/tests/set-e/until2.0 b/shell_cmds/sh/tests/set-e/until2.0
new file mode 100644
index 0000000..d19a740
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/until2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/until2.0 149781 2005-09-04 11:59:59Z stefanf $
+set -e
+until false; false; do
+ break
+done
diff --git a/shell_cmds/sh/tests/set-e/until3.0 b/shell_cmds/sh/tests/set-e/until3.0
new file mode 100644
index 0000000..2f77903
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/until3.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/set-e/until3.0 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ until false; do
+ false
+ break
+ done
+}
+f || true
diff --git a/shell_cmds/sh/tests/set-e/while1.0 b/shell_cmds/sh/tests/set-e/while1.0
new file mode 100644
index 0000000..6d7fe0a
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/while1.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/while1.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+while false; do
+ :
+done
diff --git a/shell_cmds/sh/tests/set-e/while2.0 b/shell_cmds/sh/tests/set-e/while2.0
new file mode 100644
index 0000000..fe2f2ba
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/while2.0
@@ -0,0 +1,5 @@
+# $FreeBSD: head/bin/sh/tests/set-e/while2.0 211399 2010-08-16 17:18:08Z jilles $
+set -e
+while false; false; do
+ :
+done
diff --git a/shell_cmds/sh/tests/set-e/while3.0 b/shell_cmds/sh/tests/set-e/while3.0
new file mode 100644
index 0000000..bf87175
--- /dev/null
+++ b/shell_cmds/sh/tests/set-e/while3.0
@@ -0,0 +1,9 @@
+# $FreeBSD: head/bin/sh/tests/set-e/while3.0 149791 2005-09-05 09:42:10Z stefanf $
+set -e
+f() {
+ while true; do
+ false
+ break
+ done
+}
+f || true
diff --git a/shell_cmds/sh/trap.c b/shell_cmds/sh/trap.c
new file mode 100644
index 0000000..0f84892
--- /dev/null
+++ b/shell_cmds/sh/trap.c
@@ -0,0 +1,556 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/trap.c 326025 2017-11-20 19:49:47Z pfg $");
+
+#include <signal.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "shell.h"
+#include "main.h"
+#include "nodes.h" /* for other headers */
+#include "eval.h"
+#include "jobs.h"
+#include "show.h"
+#include "options.h"
+#include "syntax.h"
+#include "output.h"
+#include "memalloc.h"
+#include "error.h"
+#include "trap.h"
+#include "mystring.h"
+#include "builtins.h"
+#include "myhistedit.h"
+
+#ifdef __APPLE__
+#define sys_nsig (NSIG)
+#endif /* __APPLE__ */
+
+/*
+ * Sigmode records the current value of the signal handlers for the various
+ * modes. A value of zero means that the current handler is not known.
+ * S_HARD_IGN indicates that the signal was ignored on entry to the shell,
+ */
+
+#define S_DFL 1 /* default signal handling (SIG_DFL) */
+#define S_CATCH 2 /* signal is caught */
+#define S_IGN 3 /* signal is ignored (SIG_IGN) */
+#define S_HARD_IGN 4 /* signal is ignored permanently */
+#define S_RESET 5 /* temporary - to reset a hard ignored sig */
+
+
+static char sigmode[NSIG]; /* current value of signal */
+volatile sig_atomic_t pendingsig; /* indicates some signal received */
+volatile sig_atomic_t pendingsig_waitcmd; /* indicates wait builtin should be interrupted */
+static int in_dotrap; /* do we execute in a trap handler? */
+static char *volatile trap[NSIG]; /* trap handler commands */
+static volatile sig_atomic_t gotsig[NSIG];
+ /* indicates specified signal received */
+static int ignore_sigchld; /* Used while handling SIGCHLD traps. */
+static int last_trapsig;
+
+static int exiting; /* exitshell() has been called */
+static int exiting_exitstatus; /* value passed to exitshell() */
+
+static int getsigaction(int, sig_t *);
+
+
+/*
+ * Map a string to a signal number.
+ *
+ * Note: the signal number may exceed NSIG.
+ */
+static int
+sigstring_to_signum(char *sig)
+{
+
+ if (is_number(sig)) {
+ int signo;
+
+ signo = atoi(sig);
+ return ((signo >= 0 && signo < NSIG) ? signo : (-1));
+ } else if (strcasecmp(sig, "EXIT") == 0) {
+ return (0);
+ } else {
+ int n;
+
+ if (strncasecmp(sig, "SIG", 3) == 0)
+ sig += 3;
+ for (n = 1; n < sys_nsig; n++)
+ if (sys_signame[n] &&
+ strcasecmp(sys_signame[n], sig) == 0)
+ return (n);
+ }
+ return (-1);
+}
+
+
+/*
+ * Print a list of valid signal names.
+ */
+static void
+printsignals(void)
+{
+ int n, outlen;
+
+ outlen = 0;
+ for (n = 1; n < sys_nsig; n++) {
+ if (sys_signame[n]) {
+ out1fmt("%s", sys_signame[n]);
+ outlen += strlen(sys_signame[n]);
+ } else {
+ out1fmt("%d", n);
+ outlen += 3; /* good enough */
+ }
+ ++outlen;
+ if (outlen > 71 || n == sys_nsig - 1) {
+ out1str("\n");
+ outlen = 0;
+ } else {
+ out1c(' ');
+ }
+ }
+}
+
+
+/*
+ * The trap builtin.
+ */
+int
+trapcmd(int argc __unused, char **argv)
+{
+ char *action;
+ int signo;
+ int errors = 0;
+ int i;
+
+ while ((i = nextopt("l")) != '\0') {
+ switch (i) {
+ case 'l':
+ printsignals();
+ return (0);
+ }
+ }
+ argv = argptr;
+
+ if (*argv == NULL) {
+ for (signo = 0 ; signo < sys_nsig ; signo++) {
+ if (signo < NSIG && trap[signo] != NULL) {
+ out1str("trap -- ");
+ out1qstr(trap[signo]);
+ if (signo == 0) {
+ out1str(" EXIT\n");
+ } else if (sys_signame[signo]) {
+ out1fmt(" %s\n", sys_signame[signo]);
+ } else {
+ out1fmt(" %d\n", signo);
+ }
+ }
+ }
+ return 0;
+ }
+ action = NULL;
+ if (*argv && !is_number(*argv)) {
+ if (strcmp(*argv, "-") == 0)
+ argv++;
+ else {
+ action = *argv;
+ argv++;
+ }
+ }
+ for (; *argv; argv++) {
+ if ((signo = sigstring_to_signum(*argv)) == -1) {
+ warning("bad signal %s", *argv);
+ errors = 1;
+ continue;
+ }
+ INTOFF;
+ if (action)
+ action = savestr(action);
+ if (trap[signo])
+ ckfree(trap[signo]);
+ trap[signo] = action;
+ if (signo != 0)
+ setsignal(signo);
+ INTON;
+ }
+ return errors;
+}
+
+
+/*
+ * Clear traps on a fork.
+ */
+void
+clear_traps(void)
+{
+ char *volatile *tp;
+
+ for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
+ if (*tp && **tp) { /* trap not NULL or SIG_IGN */
+ INTOFF;
+ ckfree(*tp);
+ *tp = NULL;
+ if (tp != &trap[0])
+ setsignal(tp - trap);
+ INTON;
+ }
+ }
+}
+
+
+/*
+ * Check if we have any traps enabled.
+ */
+int
+have_traps(void)
+{
+ char *volatile *tp;
+
+ for (tp = trap ; tp <= &trap[NSIG - 1] ; tp++) {
+ if (*tp && **tp) /* trap not NULL or SIG_IGN */
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Set the signal handler for the specified signal. The routine figures
+ * out what it should be set to.
+ */
+void
+setsignal(int signo)
+{
+ int action;
+ sig_t sigact = SIG_DFL;
+ struct sigaction sa;
+ char *t;
+
+ if ((t = trap[signo]) == NULL)
+ action = S_DFL;
+ else if (*t != '\0')
+ action = S_CATCH;
+ else
+ action = S_IGN;
+ if (action == S_DFL) {
+ switch (signo) {
+ case SIGINT:
+ action = S_CATCH;
+ break;
+ case SIGQUIT:
+#ifdef DEBUG
+ {
+ extern int debug;
+
+ if (debug)
+ break;
+ }
+#endif
+ action = S_CATCH;
+ break;
+ case SIGTERM:
+ if (rootshell && iflag)
+ action = S_IGN;
+ break;
+#if JOBS
+ case SIGTSTP:
+ case SIGTTOU:
+ if (rootshell && mflag)
+ action = S_IGN;
+ break;
+#endif
+ }
+ }
+
+ t = &sigmode[signo];
+ if (*t == 0) {
+ /*
+ * current setting unknown
+ */
+ if (!getsigaction(signo, &sigact)) {
+ /*
+ * Pretend it worked; maybe we should give a warning
+ * here, but other shells don't. We don't alter
+ * sigmode, so that we retry every time.
+ */
+ return;
+ }
+ if (sigact == SIG_IGN) {
+ if (mflag && (signo == SIGTSTP ||
+ signo == SIGTTIN || signo == SIGTTOU)) {
+ *t = S_IGN; /* don't hard ignore these */
+ } else
+ *t = S_HARD_IGN;
+ } else {
+ *t = S_RESET; /* force to be set */
+ }
+ }
+ if (*t == S_HARD_IGN || *t == action)
+ return;
+ switch (action) {
+ case S_DFL: sigact = SIG_DFL; break;
+ case S_CATCH: sigact = onsig; break;
+ case S_IGN: sigact = SIG_IGN; break;
+ }
+ *t = action;
+ sa.sa_handler = sigact;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(signo, &sa, NULL);
+}
+
+
+/*
+ * Return the current setting for sig w/o changing it.
+ */
+static int
+getsigaction(int signo, sig_t *sigact)
+{
+ struct sigaction sa;
+
+ if (sigaction(signo, (struct sigaction *)0, &sa) == -1)
+ return 0;
+ *sigact = (sig_t) sa.sa_handler;
+ return 1;
+}
+
+
+/*
+ * Ignore a signal.
+ */
+void
+ignoresig(int signo)
+{
+
+ if (sigmode[signo] == 0)
+ setsignal(signo);
+ if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) {
+ signal(signo, SIG_IGN);
+ sigmode[signo] = S_IGN;
+ }
+}
+
+
+int
+issigchldtrapped(void)
+{
+
+ return (trap[SIGCHLD] != NULL && *trap[SIGCHLD] != '\0');
+}
+
+
+/*
+ * Signal handler.
+ */
+void
+onsig(int signo)
+{
+
+ if (signo == SIGINT && trap[SIGINT] == NULL) {
+ /*
+ * The !in_dotrap here is safe. The only way we can arrive
+ * here with in_dotrap set is that a trap handler set SIGINT to
+ * SIG_DFL and killed itself.
+ */
+ if (suppressint && !in_dotrap)
+ SET_PENDING_INT;
+ else
+ onint();
+ return;
+ }
+
+ /* If we are currently in a wait builtin, prepare to break it */
+ if (signo == SIGINT || signo == SIGQUIT)
+ pendingsig_waitcmd = signo;
+
+ if (trap[signo] != NULL && trap[signo][0] != '\0' &&
+ (signo != SIGCHLD || !ignore_sigchld)) {
+ gotsig[signo] = 1;
+ pendingsig = signo;
+ pendingsig_waitcmd = signo;
+ }
+}
+
+
+/*
+ * Called to execute a trap. Perhaps we should avoid entering new trap
+ * handlers while we are executing a trap handler.
+ */
+void
+dotrap(void)
+{
+ struct stackmark smark;
+ int i;
+ int savestatus, prev_evalskip, prev_skipcount;
+
+ in_dotrap++;
+ for (;;) {
+ pendingsig = 0;
+ pendingsig_waitcmd = 0;
+ for (i = 1; i < NSIG; i++) {
+ if (gotsig[i]) {
+ gotsig[i] = 0;
+ if (trap[i]) {
+ /*
+ * Ignore SIGCHLD to avoid infinite
+ * recursion if the trap action does
+ * a fork.
+ */
+ if (i == SIGCHLD)
+ ignore_sigchld++;
+
+ /*
+ * Backup current evalskip
+ * state and reset it before
+ * executing a trap, so that the
+ * trap is not disturbed by an
+ * ongoing break/continue/return
+ * statement.
+ */
+ prev_evalskip = evalskip;
+ prev_skipcount = skipcount;
+ evalskip = 0;
+
+ last_trapsig = i;
+ savestatus = exitstatus;
+ setstackmark(&smark);
+ evalstring(stsavestr(trap[i]), 0);
+ popstackmark(&smark);
+
+ /*
+ * If such a command was not
+ * already in progress, allow a
+ * break/continue/return in the
+ * trap action to have an effect
+ * outside of it.
+ */
+ if (evalskip == 0 ||
+ prev_evalskip != 0) {
+ evalskip = prev_evalskip;
+ skipcount = prev_skipcount;
+ exitstatus = savestatus;
+ }
+
+ if (i == SIGCHLD)
+ ignore_sigchld--;
+ }
+ break;
+ }
+ }
+ if (i >= NSIG)
+ break;
+ }
+ in_dotrap--;
+}
+
+
+/*
+ * Controls whether the shell is interactive or not based on iflag.
+ */
+void
+setinteractive(void)
+{
+ setsignal(SIGINT);
+ setsignal(SIGQUIT);
+ setsignal(SIGTERM);
+}
+
+
+/*
+ * Called to exit the shell.
+ */
+void
+exitshell(int status)
+{
+ TRACE(("exitshell(%d) pid=%d\n", status, getpid()));
+ exiting = 1;
+ exiting_exitstatus = status;
+ exitshell_savedstatus();
+}
+
+void
+exitshell_savedstatus(void)
+{
+ struct jmploc loc1, loc2;
+ char *p;
+ int sig = 0;
+ sigset_t sigs;
+
+ if (!exiting) {
+ if (in_dotrap && last_trapsig) {
+ sig = last_trapsig;
+ exiting_exitstatus = sig + 128;
+ } else
+ exiting_exitstatus = oexitstatus;
+ }
+ exitstatus = oexitstatus = exiting_exitstatus;
+ if (!setjmp(loc1.loc)) {
+ handler = &loc1;
+ if ((p = trap[0]) != NULL && *p != '\0') {
+ /*
+ * Reset evalskip, or the trap on EXIT could be
+ * interrupted if the last command was a "return".
+ */
+ evalskip = 0;
+ trap[0] = NULL;
+ FORCEINTON;
+ evalstring(p, 0);
+ }
+ }
+ if (!setjmp(loc2.loc)) {
+ handler = &loc2; /* probably unnecessary */
+ FORCEINTON;
+ flushall();
+#if JOBS
+ setjobctl(0);
+#endif
+ }
+ if (sig != 0 && sig != SIGSTOP && sig != SIGTSTP && sig != SIGTTIN &&
+ sig != SIGTTOU) {
+ signal(sig, SIG_DFL);
+ sigemptyset(&sigs);
+ sigaddset(&sigs, sig);
+ sigprocmask(SIG_UNBLOCK, &sigs, NULL);
+ kill(getpid(), sig);
+ /* If the default action is to ignore, fall back to _exit(). */
+ }
+ _exit(exiting_exitstatus);
+}
diff --git a/shell_cmds/sh/trap.h b/shell_cmds/sh/trap.h
new file mode 100644
index 0000000..90ba054
--- /dev/null
+++ b/shell_cmds/sh/trap.h
@@ -0,0 +1,50 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trap.h 8.3 (Berkeley) 6/5/95
+ * $FreeBSD: head/bin/sh/trap.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+extern volatile sig_atomic_t pendingsig;
+extern volatile sig_atomic_t pendingsig_waitcmd;
+
+void clear_traps(void);
+int have_traps(void);
+void setsignal(int);
+void ignoresig(int);
+int issigchldtrapped(void);
+void onsig(int);
+void dotrap(void);
+void setinteractive(void);
+void exitshell(int) __dead2;
+void exitshell_savedstatus(void) __dead2;
diff --git a/shell_cmds/sh/var.c b/shell_cmds/sh/var.c
new file mode 100644
index 0000000..feeea03
--- /dev/null
+++ b/shell_cmds/sh/var.c
@@ -0,0 +1,971 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/bin/sh/var.c 329221 2018-02-13 16:48:57Z bdrewery $");
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <paths.h>
+
+/*
+ * Shell variables.
+ */
+
+#include <locale.h>
+#include <langinfo.h>
+
+#include "shell.h"
+#include "output.h"
+#include "expand.h"
+#include "nodes.h" /* for other headers */
+#include "eval.h" /* defines cmdenviron */
+#include "exec.h"
+#include "syntax.h"
+#include "options.h"
+#include "mail.h"
+#include "var.h"
+#include "memalloc.h"
+#include "error.h"
+#include "mystring.h"
+#include "parser.h"
+#include "builtins.h"
+#ifndef NO_HISTORY
+#include "myhistedit.h"
+#endif
+
+
+#ifndef VTABSIZE
+#define VTABSIZE 39
+#endif
+
+
+struct varinit {
+ struct var *var;
+ int flags;
+ const char *text;
+ void (*func)(const char *);
+};
+
+
+#ifndef NO_HISTORY
+struct var vhistsize;
+struct var vterm;
+#endif
+struct var vifs;
+struct var vmail;
+struct var vmpath;
+struct var vpath;
+struct var vps1;
+struct var vps2;
+struct var vps4;
+static struct var voptind;
+struct var vdisvfork;
+
+struct localvar *localvars;
+int forcelocal;
+
+static const struct varinit varinit[] = {
+#ifndef NO_HISTORY
+ { &vhistsize, VUNSET, "HISTSIZE=",
+ sethistsize },
+#endif
+ { &vifs, 0, "IFS= \t\n",
+ NULL },
+ { &vmail, VUNSET, "MAIL=",
+ NULL },
+ { &vmpath, VUNSET, "MAILPATH=",
+ NULL },
+ { &vpath, 0, "PATH=" _PATH_DEFPATH,
+ changepath },
+ /*
+ * vps1 depends on uid
+ */
+ { &vps2, 0, "PS2=> ",
+ NULL },
+ { &vps4, 0, "PS4=+ ",
+ NULL },
+#ifndef NO_HISTORY
+ { &vterm, VUNSET, "TERM=",
+ setterm },
+#endif
+ { &voptind, 0, "OPTIND=1",
+ getoptsreset },
+ { &vdisvfork, VUNSET, "SH_DISABLE_VFORK=",
+ NULL },
+ { NULL, 0, NULL,
+ NULL }
+};
+
+static struct var *vartab[VTABSIZE];
+
+static const char *const locale_names[7] = {
+ "LC_COLLATE", "LC_CTYPE", "LC_MONETARY",
+ "LC_NUMERIC", "LC_TIME", "LC_MESSAGES", NULL
+};
+static const int locale_categories[7] = {
+ LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME, LC_MESSAGES, 0
+};
+
+static int varequal(const char *, const char *);
+static struct var *find_var(const char *, struct var ***, int *);
+static int localevar(const char *);
+static void setvareq_const(const char *s, int flags);
+
+extern char **environ;
+
+/*
+ * This routine initializes the builtin variables and imports the environment.
+ * It is called when the shell is initialized.
+ */
+
+void
+initvar(void)
+{
+ char ppid[20];
+ const struct varinit *ip;
+ struct var *vp;
+ struct var **vpp;
+ char **envp;
+
+ for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
+ if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
+ continue;
+ vp->next = *vpp;
+ *vpp = vp;
+ vp->text = __DECONST(char *, ip->text);
+ vp->flags = ip->flags | VSTRFIXED | VTEXTFIXED;
+ vp->func = ip->func;
+ }
+ /*
+ * PS1 depends on uid
+ */
+ if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
+ vps1.next = *vpp;
+ *vpp = &vps1;
+ vps1.text = __DECONST(char *, geteuid() ? "PS1=$ " : "PS1=# ");
+ vps1.flags = VSTRFIXED|VTEXTFIXED;
+ }
+ fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
+ setvarsafe("PPID", ppid, 0);
+ for (envp = environ ; *envp ; envp++) {
+ if (strchr(*envp, '=')) {
+ setvareq(*envp, VEXPORT|VTEXTFIXED);
+ }
+ }
+ setvareq_const("OPTIND=1", 0);
+ setvareq_const("IFS= \t\n", 0);
+}
+
+/*
+ * Safe version of setvar, returns 1 on success 0 on failure.
+ */
+
+int
+setvarsafe(const char *name, const char *val, int flags)
+{
+ struct jmploc jmploc;
+ struct jmploc *const savehandler = handler;
+ int err = 0;
+ int inton;
+
+ inton = is_int_on();
+ if (setjmp(jmploc.loc))
+ err = 1;
+ else {
+ handler = &jmploc;
+ setvar(name, val, flags);
+ }
+ handler = savehandler;
+ SETINTON(inton);
+ return err;
+}
+
+/*
+ * Set the value of a variable. The flags argument is stored with the
+ * flags of the variable. If val is NULL, the variable is unset.
+ */
+
+void
+setvar(const char *name, const char *val, int flags)
+{
+ const char *p;
+ size_t len;
+ size_t namelen;
+ size_t vallen;
+ char *nameeq;
+ int isbad;
+
+ isbad = 0;
+ p = name;
+ if (! is_name(*p))
+ isbad = 1;
+ p++;
+ for (;;) {
+ if (! is_in_name(*p)) {
+ if (*p == '\0' || *p == '=')
+ break;
+ isbad = 1;
+ }
+ p++;
+ }
+ namelen = p - name;
+ if (isbad)
+ error("%.*s: bad variable name", (int)namelen, name);
+ len = namelen + 2; /* 2 is space for '=' and '\0' */
+ if (val == NULL) {
+ flags |= VUNSET;
+ vallen = 0;
+ } else {
+ vallen = strlen(val);
+ len += vallen;
+ }
+ INTOFF;
+ nameeq = ckmalloc(len);
+ memcpy(nameeq, name, namelen);
+ nameeq[namelen] = '=';
+ if (val)
+ memcpy(nameeq + namelen + 1, val, vallen + 1);
+ else
+ nameeq[namelen + 1] = '\0';
+ setvareq(nameeq, flags);
+ INTON;
+}
+
+static int
+localevar(const char *s)
+{
+ const char *const *ss;
+
+ if (*s != 'L')
+ return 0;
+ if (varequal(s + 1, "ANG"))
+ return 1;
+ if (strncmp(s + 1, "C_", 2) != 0)
+ return 0;
+ if (varequal(s + 3, "ALL"))
+ return 1;
+ for (ss = locale_names; *ss ; ss++)
+ if (varequal(s + 3, *ss + 3))
+ return 1;
+ return 0;
+}
+
+
+/*
+ * Sets/unsets an environment variable from a pointer that may actually be a
+ * pointer into environ where the string should not be manipulated.
+ */
+static void
+change_env(const char *s, int set)
+{
+ char *eqp;
+ char *ss;
+
+ INTOFF;
+ ss = savestr(s);
+ if ((eqp = strchr(ss, '=')) != NULL)
+ *eqp = '\0';
+ if (set && eqp != NULL)
+ (void) setenv(ss, eqp + 1, 1);
+ else
+ (void) unsetenv(ss);
+ ckfree(ss);
+ INTON;
+
+ return;
+}
+
+
+/*
+ * Same as setvar except that the variable and value are passed in
+ * the first argument as name=value. Since the first argument will
+ * be actually stored in the table, it should not be a string that
+ * will go away.
+ */
+
+void
+setvareq(char *s, int flags)
+{
+ struct var *vp, **vpp;
+ int nlen;
+
+ if (aflag)
+ flags |= VEXPORT;
+ if (forcelocal && !(flags & (VNOSET | VNOLOCAL)))
+ mklocal(s);
+ vp = find_var(s, &vpp, &nlen);
+ if (vp != NULL) {
+ if (vp->flags & VREADONLY) {
+ if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(s);
+ error("%.*s: is read only", vp->name_len, vp->text);
+ }
+ if (flags & VNOSET) {
+ if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(s);
+ return;
+ }
+ INTOFF;
+
+ if (vp->func && (flags & VNOFUNC) == 0)
+ (*vp->func)(s + vp->name_len + 1);
+
+ if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(vp->text);
+
+ vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
+ vp->flags |= flags;
+ vp->text = s;
+
+ /*
+ * We could roll this to a function, to handle it as
+ * a regular variable function callback, but why bother?
+ *
+ * Note: this assumes iflag is not set to 1 initially.
+ * As part of initvar(), this is called before arguments
+ * are looked at.
+ */
+ if ((vp == &vmpath || (vp == &vmail && ! mpathset())) &&
+ iflag == 1)
+ chkmail(1);
+ if ((vp->flags & VEXPORT) && localevar(s)) {
+ change_env(s, 1);
+ (void) setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ INTON;
+ return;
+ }
+ /* not found */
+ if (flags & VNOSET) {
+ if ((flags & (VTEXTFIXED|VSTACK)) == 0)
+ ckfree(s);
+ return;
+ }
+ INTOFF;
+ vp = ckmalloc(sizeof (*vp));
+ vp->flags = flags;
+ vp->text = s;
+ vp->name_len = nlen;
+ vp->next = *vpp;
+ vp->func = NULL;
+ *vpp = vp;
+ if ((vp->flags & VEXPORT) && localevar(s)) {
+ change_env(s, 1);
+ (void) setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ INTON;
+}
+
+
+static void
+setvareq_const(const char *s, int flags)
+{
+ setvareq(__DECONST(char *, s), flags | VTEXTFIXED);
+}
+
+
+/*
+ * Process a linked list of variable assignments.
+ */
+
+void
+listsetvar(struct arglist *list, int flags)
+{
+ int i;
+
+ INTOFF;
+ for (i = 0; i < list->count; i++)
+ setvareq(savestr(list->args[i]), flags);
+ INTON;
+}
+
+
+
+/*
+ * Find the value of a variable. Returns NULL if not set.
+ */
+
+char *
+lookupvar(const char *name)
+{
+ struct var *v;
+
+ v = find_var(name, NULL, NULL);
+ if (v == NULL || v->flags & VUNSET)
+ return NULL;
+ return v->text + v->name_len + 1;
+}
+
+
+
+/*
+ * Search the environment of a builtin command. If the second argument
+ * is nonzero, return the value of a variable even if it hasn't been
+ * exported.
+ */
+
+char *
+bltinlookup(const char *name, int doall)
+{
+ struct var *v;
+ char *result;
+ int i;
+
+ result = NULL;
+ if (cmdenviron) for (i = 0; i < cmdenviron->count; i++) {
+ if (varequal(cmdenviron->args[i], name))
+ result = strchr(cmdenviron->args[i], '=') + 1;
+ }
+ if (result != NULL)
+ return result;
+
+ v = find_var(name, NULL, NULL);
+ if (v == NULL || v->flags & VUNSET ||
+ (!doall && (v->flags & VEXPORT) == 0))
+ return NULL;
+ return v->text + v->name_len + 1;
+}
+
+
+/*
+ * Set up locale for a builtin (LANG/LC_* assignments).
+ */
+void
+bltinsetlocale(void)
+{
+ int act = 0;
+ char *loc, *locdef;
+ int i;
+
+ if (cmdenviron) for (i = 0; i < cmdenviron->count; i++) {
+ if (localevar(cmdenviron->args[i])) {
+ act = 1;
+ break;
+ }
+ }
+ if (!act)
+ return;
+ loc = bltinlookup("LC_ALL", 0);
+ INTOFF;
+ if (loc != NULL) {
+ setlocale(LC_ALL, loc);
+ INTON;
+ updatecharset();
+ return;
+ }
+ locdef = bltinlookup("LANG", 0);
+ for (i = 0; locale_names[i] != NULL; i++) {
+ loc = bltinlookup(locale_names[i], 0);
+ if (loc == NULL)
+ loc = locdef;
+ if (loc != NULL)
+ setlocale(locale_categories[i], loc);
+ }
+ INTON;
+ updatecharset();
+}
+
+/*
+ * Undo the effect of bltinlocaleset().
+ */
+void
+bltinunsetlocale(void)
+{
+ int i;
+
+ INTOFF;
+ if (cmdenviron) for (i = 0; i < cmdenviron->count; i++) {
+ if (localevar(cmdenviron->args[i])) {
+ setlocale(LC_ALL, "");
+ updatecharset();
+ break;
+ }
+ }
+ INTON;
+}
+
+/*
+ * Update the localeisutf8 flag.
+ */
+void
+updatecharset(void)
+{
+ char *charset;
+
+ charset = nl_langinfo(CODESET);
+ localeisutf8 = !strcmp(charset, "UTF-8");
+}
+
+void
+initcharset(void)
+{
+ updatecharset();
+ initial_localeisutf8 = localeisutf8;
+}
+
+/*
+ * Generate a list of exported variables. This routine is used to construct
+ * the third argument to execve when executing a program.
+ */
+
+char **
+environment(void)
+{
+ int nenv;
+ struct var **vpp;
+ struct var *vp;
+ char **env, **ep;
+
+ nenv = 0;
+ for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
+ for (vp = *vpp ; vp ; vp = vp->next)
+ if (vp->flags & VEXPORT)
+ nenv++;
+ }
+ ep = env = stalloc((nenv + 1) * sizeof *env);
+ for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
+ for (vp = *vpp ; vp ; vp = vp->next)
+ if (vp->flags & VEXPORT)
+ *ep++ = vp->text;
+ }
+ *ep = NULL;
+ return env;
+}
+
+
+static int
+var_compare(const void *a, const void *b)
+{
+ const char *const *sa, *const *sb;
+
+ sa = a;
+ sb = b;
+ /*
+ * This compares two var=value strings which creates a different
+ * order from what you would probably expect. POSIX is somewhat
+ * ambiguous on what should be sorted exactly.
+ */
+ return strcoll(*sa, *sb);
+}
+
+
+/*
+ * Command to list all variables which are set. This is invoked from the
+ * set command when it is called without any options or operands.
+ */
+
+int
+showvarscmd(int argc __unused, char **argv __unused)
+{
+ struct var **vpp;
+ struct var *vp;
+ const char *s;
+ const char **vars;
+ int i, n;
+
+ /*
+ * POSIX requires us to sort the variables.
+ */
+ n = 0;
+ for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
+ for (vp = *vpp; vp; vp = vp->next) {
+ if (!(vp->flags & VUNSET))
+ n++;
+ }
+ }
+
+ INTOFF;
+ vars = ckmalloc(n * sizeof(*vars));
+ i = 0;
+ for (vpp = vartab; vpp < vartab + VTABSIZE; vpp++) {
+ for (vp = *vpp; vp; vp = vp->next) {
+ if (!(vp->flags & VUNSET))
+ vars[i++] = vp->text;
+ }
+ }
+
+ qsort(vars, n, sizeof(*vars), var_compare);
+ for (i = 0; i < n; i++) {
+ /*
+ * Skip improper variable names so the output remains usable as
+ * shell input.
+ */
+ if (!isassignment(vars[i]))
+ continue;
+ s = strchr(vars[i], '=');
+ s++;
+ outbin(vars[i], s - vars[i], out1);
+ out1qstr(s);
+ out1c('\n');
+ }
+ ckfree(vars);
+ INTON;
+
+ return 0;
+}
+
+
+
+/*
+ * The export and readonly commands.
+ */
+
+int
+exportcmd(int argc __unused, char **argv)
+{
+ struct var **vpp;
+ struct var *vp;
+ char **ap;
+ char *name;
+ char *p;
+ char *cmdname;
+ int ch, values;
+ int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
+
+ cmdname = argv[0];
+ values = 0;
+ while ((ch = nextopt("p")) != '\0') {
+ switch (ch) {
+ case 'p':
+ values = 1;
+ break;
+ }
+ }
+
+ if (values && *argptr != NULL)
+ error("-p requires no arguments");
+ if (*argptr != NULL) {
+ for (ap = argptr; (name = *ap) != NULL; ap++) {
+ if ((p = strchr(name, '=')) != NULL) {
+ p++;
+ } else {
+ vp = find_var(name, NULL, NULL);
+ if (vp != NULL) {
+ vp->flags |= flag;
+ if ((vp->flags & VEXPORT) && localevar(vp->text)) {
+ change_env(vp->text, 1);
+ (void) setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ continue;
+ }
+ }
+ setvar(name, p, flag);
+ }
+ } else {
+ for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
+ for (vp = *vpp ; vp ; vp = vp->next) {
+ if (vp->flags & flag) {
+ if (values) {
+ /*
+ * Skip improper variable names
+ * so the output remains usable
+ * as shell input.
+ */
+ if (!isassignment(vp->text))
+ continue;
+ out1str(cmdname);
+ out1c(' ');
+ }
+ if (values && !(vp->flags & VUNSET)) {
+ outbin(vp->text,
+ vp->name_len + 1, out1);
+ out1qstr(vp->text +
+ vp->name_len + 1);
+ } else
+ outbin(vp->text, vp->name_len,
+ out1);
+ out1c('\n');
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * The "local" command.
+ */
+
+int
+localcmd(int argc __unused, char **argv __unused)
+{
+ char *name;
+
+ nextopt("");
+ if (! in_function())
+ error("Not in a function");
+ while ((name = *argptr++) != NULL) {
+ mklocal(name);
+ }
+ return 0;
+}
+
+
+/*
+ * Make a variable a local variable. When a variable is made local, it's
+ * value and flags are saved in a localvar structure. The saved values
+ * will be restored when the shell function returns. We handle the name
+ * "-" as a special case.
+ */
+
+void
+mklocal(char *name)
+{
+ struct localvar *lvp;
+ struct var **vpp;
+ struct var *vp;
+
+ INTOFF;
+ lvp = ckmalloc(sizeof (struct localvar));
+ if (name[0] == '-' && name[1] == '\0') {
+ lvp->text = ckmalloc(sizeof optval);
+ memcpy(lvp->text, optval, sizeof optval);
+ vp = NULL;
+ } else {
+ vp = find_var(name, &vpp, NULL);
+ if (vp == NULL) {
+ if (strchr(name, '='))
+ setvareq(savestr(name), VSTRFIXED | VNOLOCAL);
+ else
+ setvar(name, NULL, VSTRFIXED | VNOLOCAL);
+ vp = *vpp; /* the new variable */
+ lvp->text = NULL;
+ lvp->flags = VUNSET;
+ } else {
+ lvp->text = vp->text;
+ lvp->flags = vp->flags;
+ vp->flags |= VSTRFIXED|VTEXTFIXED;
+ if (name[vp->name_len] == '=')
+ setvareq(savestr(name), VNOLOCAL);
+ }
+ }
+ lvp->vp = vp;
+ lvp->next = localvars;
+ localvars = lvp;
+ INTON;
+}
+
+
+/*
+ * Called after a function returns.
+ */
+
+void
+poplocalvars(void)
+{
+ struct localvar *lvp;
+ struct var *vp;
+ int islocalevar;
+
+ INTOFF;
+ while ((lvp = localvars) != NULL) {
+ localvars = lvp->next;
+ vp = lvp->vp;
+ if (vp == NULL) { /* $- saved */
+ memcpy(optval, lvp->text, sizeof optval);
+ ckfree(lvp->text);
+ optschanged();
+ } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
+ vp->flags &= ~VREADONLY;
+ (void)unsetvar(vp->text);
+ } else {
+ islocalevar = (vp->flags | lvp->flags) & VEXPORT &&
+ localevar(lvp->text);
+ if ((vp->flags & VTEXTFIXED) == 0)
+ ckfree(vp->text);
+ vp->flags = lvp->flags;
+ vp->text = lvp->text;
+ if (vp->func)
+ (*vp->func)(vp->text + vp->name_len + 1);
+ if (islocalevar) {
+ change_env(vp->text, vp->flags & VEXPORT &&
+ (vp->flags & VUNSET) == 0);
+ setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ }
+ ckfree(lvp);
+ }
+ INTON;
+}
+
+
+int
+setvarcmd(int argc, char **argv)
+{
+ if (argc <= 2)
+ return unsetcmd(argc, argv);
+ else if (argc == 3)
+ setvar(argv[1], argv[2], 0);
+ else
+ error("too many arguments");
+ return 0;
+}
+
+
+/*
+ * The unset builtin command.
+ */
+
+int
+unsetcmd(int argc __unused, char **argv __unused)
+{
+ char **ap;
+ int i;
+ int flg_func = 0;
+ int flg_var = 0;
+ int ret = 0;
+
+ while ((i = nextopt("vf")) != '\0') {
+ if (i == 'f')
+ flg_func = 1;
+ else
+ flg_var = 1;
+ }
+ if (flg_func == 0 && flg_var == 0)
+ flg_var = 1;
+
+ INTOFF;
+ for (ap = argptr; *ap ; ap++) {
+ if (flg_func)
+ ret |= unsetfunc(*ap);
+ if (flg_var)
+ ret |= unsetvar(*ap);
+ }
+ INTON;
+ return ret;
+}
+
+
+/*
+ * Unset the specified variable.
+ * Called with interrupts off.
+ */
+
+int
+unsetvar(const char *s)
+{
+ struct var **vpp;
+ struct var *vp;
+
+ vp = find_var(s, &vpp, NULL);
+ if (vp == NULL)
+ return (0);
+ if (vp->flags & VREADONLY)
+ return (1);
+ if (vp->text[vp->name_len + 1] != '\0')
+ setvar(s, "", 0);
+ if ((vp->flags & VEXPORT) && localevar(vp->text)) {
+ change_env(s, 0);
+ setlocale(LC_ALL, "");
+ updatecharset();
+ }
+ vp->flags &= ~VEXPORT;
+ vp->flags |= VUNSET;
+ if ((vp->flags & VSTRFIXED) == 0) {
+ if ((vp->flags & VTEXTFIXED) == 0)
+ ckfree(vp->text);
+ *vpp = vp->next;
+ ckfree(vp);
+ }
+ return (0);
+}
+
+
+
+/*
+ * Returns true if the two strings specify the same variable. The first
+ * variable name is terminated by '='; the second may be terminated by
+ * either '=' or '\0'.
+ */
+
+static int
+varequal(const char *p, const char *q)
+{
+ while (*p == *q++) {
+ if (*p++ == '=')
+ return 1;
+ }
+ if (*p == '=' && *(q - 1) == '\0')
+ return 1;
+ return 0;
+}
+
+/*
+ * Search for a variable.
+ * 'name' may be terminated by '=' or a NUL.
+ * vppp is set to the pointer to vp, or the list head if vp isn't found
+ * lenp is set to the number of characters in 'name'
+ */
+
+static struct var *
+find_var(const char *name, struct var ***vppp, int *lenp)
+{
+ unsigned int hashval;
+ int len;
+ struct var *vp, **vpp;
+ const char *p = name;
+
+ hashval = 0;
+ while (*p && *p != '=')
+ hashval = 2 * hashval + (unsigned char)*p++;
+ len = p - name;
+
+ if (lenp)
+ *lenp = len;
+ vpp = &vartab[hashval % VTABSIZE];
+ if (vppp)
+ *vppp = vpp;
+
+ for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
+ if (vp->name_len != len)
+ continue;
+ if (memcmp(vp->text, name, len) != 0)
+ continue;
+ if (vppp)
+ *vppp = vpp;
+ return vp;
+ }
+ return NULL;
+}
diff --git a/shell_cmds/sh/var.h b/shell_cmds/sh/var.h
new file mode 100644
index 0000000..c9b5a99
--- /dev/null
+++ b/shell_cmds/sh/var.h
@@ -0,0 +1,132 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kenneth Almquist.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)var.h 8.2 (Berkeley) 5/4/95
+ * $FreeBSD: head/bin/sh/var.h 326025 2017-11-20 19:49:47Z pfg $
+ */
+
+/*
+ * Shell variables.
+ */
+
+/* flags */
+#define VEXPORT 0x01 /* variable is exported */
+#define VREADONLY 0x02 /* variable cannot be modified */
+#define VSTRFIXED 0x04 /* variable struct is statically allocated */
+#define VTEXTFIXED 0x08 /* text is statically allocated */
+#define VSTACK 0x10 /* text is allocated on the stack */
+#define VUNSET 0x20 /* the variable is not set */
+#define VNOFUNC 0x40 /* don't call the callback function */
+#define VNOSET 0x80 /* do not set variable - just readonly test */
+#define VNOLOCAL 0x100 /* ignore forcelocal */
+
+
+struct var {
+ struct var *next; /* next entry in hash list */
+ int flags; /* flags are defined above */
+ int name_len; /* length of name */
+ char *text; /* name=value */
+ void (*func)(const char *);
+ /* function to be called when */
+ /* the variable gets set/unset */
+};
+
+
+struct localvar {
+ struct localvar *next; /* next local variable in list */
+ struct var *vp; /* the variable that was made local */
+ int flags; /* saved flags */
+ char *text; /* saved text */
+};
+
+
+extern struct localvar *localvars;
+extern int forcelocal;
+
+extern struct var vifs;
+extern struct var vmail;
+extern struct var vmpath;
+extern struct var vpath;
+extern struct var vps1;
+extern struct var vps2;
+extern struct var vps4;
+extern struct var vdisvfork;
+#ifndef NO_HISTORY
+extern struct var vhistsize;
+extern struct var vterm;
+#endif
+
+extern int localeisutf8;
+/* The parser uses the locale that was in effect at startup. */
+extern int initial_localeisutf8;
+
+/*
+ * The following macros access the values of the above variables.
+ * They have to skip over the name. They return the null string
+ * for unset variables.
+ */
+
+#define ifsval() (vifs.text + 4)
+#define ifsset() ((vifs.flags & VUNSET) == 0)
+#define mailval() (vmail.text + 5)
+#define mpathval() (vmpath.text + 9)
+#define pathval() (vpath.text + 5)
+#define ps1val() (vps1.text + 4)
+#define ps2val() (vps2.text + 4)
+#define ps4val() (vps4.text + 4)
+#define optindval() (voptind.text + 7)
+#ifndef NO_HISTORY
+#define histsizeval() (vhistsize.text + 9)
+#define termval() (vterm.text + 5)
+#endif
+
+#define mpathset() ((vmpath.flags & VUNSET) == 0)
+#define disvforkset() ((vdisvfork.flags & VUNSET) == 0)
+
+void initvar(void);
+void setvar(const char *, const char *, int);
+void setvareq(char *, int);
+struct arglist;
+void listsetvar(struct arglist *, int);
+char *lookupvar(const char *);
+char *bltinlookup(const char *, int);
+void bltinsetlocale(void);
+void bltinunsetlocale(void);
+void updatecharset(void);
+void initcharset(void);
+char **environment(void);
+int showvarscmd(int, char **);
+void mklocal(char *);
+void poplocalvars(void);
+int unsetvar(const char *);
+int setvarsafe(const char *, const char *, int);
diff --git a/shell_cmds/shell_cmds.xcodeproj/project.pbxproj b/shell_cmds/shell_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..9a52eeb
--- /dev/null
+++ b/shell_cmds/shell_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,5903 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FCBA14FD14A144EC00AA698B /* All_OSX */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FCBA14FE14A144EC00AA698B /* Build configuration list for PBXAggregateTarget "All_OSX" */;
+ buildPhases = (
+ FCE30EB814B531EC00CC0294 /* ShellScript */,
+ );
+ dependencies = (
+ C6868583154725A30025D623 /* PBXTargetDependency */,
+ FCBA150114A144F700AA698B /* PBXTargetDependency */,
+ FCBA150314A144F700AA698B /* PBXTargetDependency */,
+ FCBA150514A144F700AA698B /* PBXTargetDependency */,
+ FCBA150714A144F700AA698B /* PBXTargetDependency */,
+ FCBA150914A144F700AA698B /* PBXTargetDependency */,
+ FCBA150B14A144F700AA698B /* PBXTargetDependency */,
+ FCBA150D14A144F700AA698B /* PBXTargetDependency */,
+ FCBA165514A146D000AA698B /* PBXTargetDependency */,
+ FCBA165714A146D000AA698B /* PBXTargetDependency */,
+ FCBA165914A146D000AA698B /* PBXTargetDependency */,
+ FCBA165B14A146D000AA698B /* PBXTargetDependency */,
+ FC5D63A214B9864400123E48 /* PBXTargetDependency */,
+ FCBA165D14A146D000AA698B /* PBXTargetDependency */,
+ FCBA165F14A146D000AA698B /* PBXTargetDependency */,
+ FCBA166114A146D000AA698B /* PBXTargetDependency */,
+ FCBA166314A146D000AA698B /* PBXTargetDependency */,
+ FCBA166514A146D000AA698B /* PBXTargetDependency */,
+ FCBA166714A146D000AA698B /* PBXTargetDependency */,
+ FCBA166914A146D000AA698B /* PBXTargetDependency */,
+ FCE30EE314B539BF00CC0294 /* PBXTargetDependency */,
+ FCE30EE514B539BF00CC0294 /* PBXTargetDependency */,
+ FCBA166B14A146D000AA698B /* PBXTargetDependency */,
+ FCBA166F14A146D000AA698B /* PBXTargetDependency */,
+ FCBA167114A146D000AA698B /* PBXTargetDependency */,
+ FCBA167314A146D000AA698B /* PBXTargetDependency */,
+ FCBA167514A146D000AA698B /* PBXTargetDependency */,
+ FCBA167714A146D000AA698B /* PBXTargetDependency */,
+ FCBA167914A146D000AA698B /* PBXTargetDependency */,
+ FCBA167B14A146D000AA698B /* PBXTargetDependency */,
+ FCBA167D14A146D000AA698B /* PBXTargetDependency */,
+ FCBA167F14A146D000AA698B /* PBXTargetDependency */,
+ FCBA168114A146D000AA698B /* PBXTargetDependency */,
+ FD6060BB1B7C03BC004BCA6A /* PBXTargetDependency */,
+ FCBA168314A146D000AA698B /* PBXTargetDependency */,
+ FCBA168514A146D000AA698B /* PBXTargetDependency */,
+ FCBA168714A146D000AA698B /* PBXTargetDependency */,
+ FCBA168914A146D000AA698B /* PBXTargetDependency */,
+ FCBA168B14A146D000AA698B /* PBXTargetDependency */,
+ FCBA168D14A146D000AA698B /* PBXTargetDependency */,
+ FCBA168F14A146D000AA698B /* PBXTargetDependency */,
+ FCBA169114A146D000AA698B /* PBXTargetDependency */,
+ FCBA169314A146D000AA698B /* PBXTargetDependency */,
+ FCBA169514A146D000AA698B /* PBXTargetDependency */,
+ FC5D63A414B9864400123E48 /* PBXTargetDependency */,
+ FCBA169714A146D000AA698B /* PBXTargetDependency */,
+ FCBA169914A146D000AA698B /* PBXTargetDependency */,
+ FCBA169B14A146D000AA698B /* PBXTargetDependency */,
+ FCBA169D14A146D000AA698B /* PBXTargetDependency */,
+ FCBA169F14A146D000AA698B /* PBXTargetDependency */,
+ );
+ name = All_OSX;
+ productName = executables;
+ };
+ FCE30F4A14B619B000CC0294 /* All_iOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FCE30F4B14B619B000CC0294 /* Build configuration list for PBXAggregateTarget "All_iOS" */;
+ buildPhases = (
+ FCE30F4D14B619C900CC0294 /* Run Script */,
+ );
+ dependencies = (
+ C6868581154725990025D623 /* PBXTargetDependency */,
+ FCE30F4F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5314B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5514B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5714B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F5F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6314B619E600CC0294 /* PBXTargetDependency */,
+ FC5D63A614B9866500123E48 /* PBXTargetDependency */,
+ FCE30F6514B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6714B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F6F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7314B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7514B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7714B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F7F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8314B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8514B619E600CC0294 /* PBXTargetDependency */,
+ FD6060B91B7C03B3004BCA6A /* PBXTargetDependency */,
+ FCE30F8714B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F8F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9114B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9314B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9514B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9714B619E600CC0294 /* PBXTargetDependency */,
+ FC5D63A814B9866500123E48 /* PBXTargetDependency */,
+ FCE30F9914B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9B14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9D14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30F9F14B619E600CC0294 /* PBXTargetDependency */,
+ FCE30FA114B619E600CC0294 /* PBXTargetDependency */,
+ );
+ name = All_iOS;
+ productName = embedded;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ C686857A154725700025D623 /* systime.c in Sources */ = {isa = PBXBuildFile; fileRef = C6868579154725700025D623 /* systime.c */; };
+ C686857C154725700025D623 /* systime.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C686857B154725700025D623 /* systime.1 */; };
+ FC2B5BFB14B3CCC600ECF511 /* uname.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA140914A141A300AA698B /* uname.c */; };
+ FC2B5BFD14B3CCD200ECF511 /* uname.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA140814A141A300AA698B /* uname.1 */; };
+ FC2B5BFE14B3CCD700ECF511 /* true.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA140414A141A300AA698B /* true.c */; };
+ FC2B5BFF14B3CCEF00ECF511 /* true.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA140314A141A300AA698B /* true.1 */; };
+ FC2B5C0014B3CCF800ECF511 /* time.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA140014A141A300AA698B /* time.c */; };
+ FC2B5C0114B3CD0300ECF511 /* time.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13FF14A141A300AA698B /* time.1 */; };
+ FC2B5C0214B3CD0C00ECF511 /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13FB14A141A300AA698B /* test.c */; };
+ FC2B5C0314B3CD1400ECF511 /* [.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13F814A141A300AA698B /* [.1 */; };
+ FC2B5C0414B3CD1400ECF511 /* test.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13FA14A141A300AA698B /* test.1 */; };
+ FC2B5C0514B3CD1D00ECF511 /* tee.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13F514A141A300AA698B /* tee.1 */; };
+ FC2B5C0614B3CD2800ECF511 /* tee.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13F614A141A300AA698B /* tee.c */; };
+ FC2B5C0714B3CD2F00ECF511 /* su.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13F114A141A300AA698B /* su.c */; };
+ FC2B5C0814B3CD3500ECF511 /* su.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13F014A141A300AA698B /* su.1 */; };
+ FC2B5C0914B3CD3E00ECF511 /* sleep.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13EC14A141A300AA698B /* sleep.1 */; };
+ FC2B5C0A14B3CD4400ECF511 /* sleep.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13ED14A141A300AA698B /* sleep.c */; };
+ FC2B5C0B14B3CD4F00ECF511 /* shlock.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13E914A141A300AA698B /* shlock.c */; };
+ FC2B5C0C14B3CD5B00ECF511 /* shlock.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13E814A141A300AA698B /* shlock.1 */; };
+ FC5D638D14B981D200123E48 /* what.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D637314B9808E00123E48 /* what.c */; };
+ FC5D638E14B981D800123E48 /* what.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC5D637214B9808E00123E48 /* what.1 */; };
+ FC5D639914B9825B00123E48 /* hexdump.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC5D636A14B9808E00123E48 /* hexdump.1 */; };
+ FC5D639A14B9825B00123E48 /* od.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC5D636E14B9808E00123E48 /* od.1 */; };
+ FC5D639B14B9826500123E48 /* conv.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636814B9808E00123E48 /* conv.c */; };
+ FC5D639C14B9826500123E48 /* display.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636914B9808E00123E48 /* display.c */; };
+ FC5D639D14B9826500123E48 /* hexdump.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636B14B9808E00123E48 /* hexdump.c */; };
+ FC5D639E14B9826500123E48 /* hexsyntax.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636D14B9808E00123E48 /* hexsyntax.c */; };
+ FC5D639F14B9826500123E48 /* odsyntax.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D636F14B9808E00123E48 /* odsyntax.c */; };
+ FC5D63A014B9826500123E48 /* parse.c in Sources */ = {isa = PBXBuildFile; fileRef = FC5D637014B9808E00123E48 /* parse.c */; };
+ FCBA02E714B5061B0030BEB3 /* seq.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13E414A141A300AA698B /* seq.1 */; };
+ FCBA02E814B506230030BEB3 /* seq.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13E514A141A300AA698B /* seq.c */; };
+ FCBA02E914B5062E0030BEB3 /* script.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13E014A141A300AA698B /* script.1 */; };
+ FCBA02EA14B506340030BEB3 /* script.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13E114A141A300AA698B /* script.c */; };
+ FCBA02EB14B5063E0030BEB3 /* renice.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13DC14A141A300AA698B /* renice.8 */; };
+ FCBA02EC14B5064C0030BEB3 /* renice.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13DD14A141A300AA698B /* renice.c */; };
+ FCBA02ED14B506530030BEB3 /* pwd.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13D914A141A300AA698B /* pwd.c */; };
+ FCBA02EF14B5065D0030BEB3 /* printf.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13D414A141A300AA698B /* printf.1 */; };
+ FCBA02F014B506660030BEB3 /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13D514A141A300AA698B /* printf.c */; };
+ FCBA02F114B506720030BEB3 /* printenv.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13D114A141A300AA698B /* printenv.c */; };
+ FCBA02F214B5067C0030BEB3 /* printenv.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13D014A141A300AA698B /* printenv.1 */; };
+ FCBA02F314B506840030BEB3 /* path_helper.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13CD14A141A300AA698B /* path_helper.c */; };
+ FCBA02F414B5068C0030BEB3 /* path_helper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13CC14A141A300AA698B /* path_helper.8 */; };
+ FCBA02F514B506940030BEB3 /* nohup.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13C914A141A300AA698B /* nohup.c */; };
+ FCBA02F614B5069C0030BEB3 /* nohup.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13C814A141A300AA698B /* nohup.1 */; };
+ FCBA02F714B506B10030BEB3 /* nice.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13C414A141A300AA698B /* nice.1 */; };
+ FCBA02F814B506BB0030BEB3 /* nice.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13C514A141A300AA698B /* nice.c */; };
+ FCBA02F914B506CB0030BEB3 /* mktemp.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13C114A141A300AA698B /* mktemp.c */; };
+ FCBA02FA14B506DA0030BEB3 /* mktemp.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13C014A141A300AA698B /* mktemp.1 */; };
+ FCBA02FD14B506FA0030BEB3 /* logname.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13B514A141A300AA698B /* logname.c */; };
+ FCBA02FE14B506FF0030BEB3 /* logname.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13B414A141A300AA698B /* logname.1 */; };
+ FCBA02FF14B507130030BEB3 /* expr.y in Sources */ = {isa = PBXBuildFile; fileRef = FCBA136714A141A300AA698B /* expr.y */; };
+ FCBA030014B5071A0030BEB3 /* expr.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA136614A141A300AA698B /* expr.1 */; };
+ FCBA030114B507220030BEB3 /* false.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA136B14A141A300AA698B /* false.c */; };
+ FCBA030214B5072C0030BEB3 /* false.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA136A14A141A300AA698B /* false.1 */; };
+ FCBA030314B5073F0030BEB3 /* find.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137114A141A300AA698B /* find.c */; };
+ FCBA030414B5073F0030BEB3 /* function.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137314A141A300AA698B /* function.c */; };
+ FCBA030514B5073F0030BEB3 /* getdate.y in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137414A141A300AA698B /* getdate.y */; };
+ FCBA030614B5073F0030BEB3 /* ls.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137514A141A300AA698B /* ls.c */; };
+ FCBA030714B5073F0030BEB3 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137614A141A300AA698B /* main.c */; };
+ FCBA030814B5073F0030BEB3 /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137814A141A300AA698B /* misc.c */; };
+ FCBA030914B5073F0030BEB3 /* operator.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137914A141A300AA698B /* operator.c */; };
+ FCBA030A14B5073F0030BEB3 /* option.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137A14A141A300AA698B /* option.c */; };
+ FCBA030B14B507450030BEB3 /* find.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA137014A141A300AA698B /* find.1 */; };
+ FCBA030C14B5074D0030BEB3 /* getopt.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA137D14A141A300AA698B /* getopt.c */; };
+ FCBA030D14B507580030BEB3 /* getopt.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA137C14A141A300AA698B /* getopt.1 */; };
+ FCBA030E14B5076A0030BEB3 /* hostname.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA138114A141A300AA698B /* hostname.c */; };
+ FCBA030F14B507700030BEB3 /* hostname.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138014A141A300AA698B /* hostname.1 */; };
+ FCBA031014B507790030BEB3 /* id.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA138614A141A300AA698B /* id.c */; };
+ FCBA031214B507870030BEB3 /* groups.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138414A141A300AA698B /* groups.1 */; };
+ FCBA031314B507870030BEB3 /* id.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138514A141A300AA698B /* id.1 */; };
+ FCBA031414B507870030BEB3 /* whoami.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138A14A141A300AA698B /* whoami.1 */; };
+ FCBA031514B507900030BEB3 /* jot.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA138D14A141A300AA698B /* jot.c */; };
+ FCBA031614B507950030BEB3 /* jot.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA138C14A141A300AA698B /* jot.1 */; };
+ FCBA031714B507A10030BEB3 /* kill.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139114A141A300AA698B /* kill.c */; };
+ FCBA031814B507A50030BEB3 /* kill.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA139014A141A300AA698B /* kill.1 */; };
+ FCBA031914B507B00030BEB3 /* killall.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139514A141A300AA698B /* killall.c */; };
+ FCBA031A14B507B60030BEB3 /* killall.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA139414A141A300AA698B /* killall.1 */; };
+ FCBA031B14B507BD0030BEB3 /* lastcomm.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139914A141A300AA698B /* lastcomm.c */; };
+ FCBA031C14B507C40030BEB3 /* lastcomm.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA139814A141A300AA698B /* lastcomm.1 */; };
+ FCBA031E14B507D10030BEB3 /* locate.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13A814A141A300AA698B /* locate.c */; };
+ FCBA031F14B507D10030BEB3 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13B014A141A300AA698B /* util.c */; };
+ FCBA032014B507E50030BEB3 /* locate.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13A714A141A300AA698B /* locate.1 */; };
+ FCBA14EB14A1444900AA698B /* apply.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA134714A141A300AA698B /* apply.c */; };
+ FCBA14ED14A1444E00AA698B /* apply.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA134614A141A300AA698B /* apply.1 */; };
+ FCBA14EE14A1446700AA698B /* basename.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA134B14A141A300AA698B /* basename.c */; };
+ FCBA14EF14A1446B00AA698B /* basename.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA134A14A141A300AA698B /* basename.1 */; };
+ FCBA14F114A1448C00AA698B /* chroot.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135014A141A300AA698B /* chroot.c */; };
+ FCBA14F214A1448F00AA698B /* chroot.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA134F14A141A300AA698B /* chroot.8 */; };
+ FCBA14F314A1449A00AA698B /* date.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA135314A141A300AA698B /* date.1 */; };
+ FCBA14F414A1449C00AA698B /* date.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135414A141A300AA698B /* date.c */; };
+ FCBA14F514A144AF00AA698B /* netdate.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135714A141A300AA698B /* netdate.c */; };
+ FCBA14F614A144B200AA698B /* vary.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135814A141A300AA698B /* vary.c */; };
+ FCBA14F714A144C700AA698B /* dirname.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135B14A141A300AA698B /* dirname.c */; };
+ FCBA14F814A144CB00AA698B /* dirname.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA134C14A141A300AA698B /* dirname.1 */; };
+ FCBA14F914A144D000AA698B /* echo.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA135E14A141A300AA698B /* echo.1 */; };
+ FCBA14FA14A144D300AA698B /* echo.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA135F14A141A300AA698B /* echo.c */; };
+ FCBA14FB14A144E300AA698B /* env.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA136214A141A300AA698B /* env.1 */; };
+ FCBA14FC14A144E500AA698B /* env.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA136314A141A300AA698B /* env.c */; };
+ FCBA163E14A1466500AA698B /* yes.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA142D14A141A300AA698B /* yes.1 */; };
+ FCBA163F14A1466900AA698B /* yes.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142E14A141A300AA698B /* yes.c */; };
+ FCBA164014A1466F00AA698B /* xargs.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142A14A141A300AA698B /* xargs.c */; };
+ FCBA164114A1467200AA698B /* strnsubst.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142814A141A300AA698B /* strnsubst.c */; };
+ FCBA164214A1467500AA698B /* xargs.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA142914A141A300AA698B /* xargs.1 */; };
+ FCBA164314A1467A00AA698B /* utmpentry.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142114A141A300AA698B /* utmpentry.c */; };
+ FCBA164414A1467D00AA698B /* who.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA142414A141A300AA698B /* who.c */; };
+ FCBA164514A1468000AA698B /* who.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA142314A141A300AA698B /* who.1 */; };
+ FCBA164614A1468600AA698B /* which.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141E14A141A300AA698B /* which.c */; };
+ FCBA164714A1468900AA698B /* which.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA141D14A141A300AA698B /* which.1 */; };
+ FCBA164814A1469000AA698B /* whereis.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141A14A141A300AA698B /* whereis.c */; };
+ FCBA164914A1469300AA698B /* whereis.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA141914A141A300AA698B /* whereis.1 */; };
+ FCBA164A14A1469A00AA698B /* fmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141014A141A300AA698B /* fmt.c */; };
+ FCBA164B14A1469D00AA698B /* pr_time.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141214A141A300AA698B /* pr_time.c */; };
+ FCBA164C14A1469F00AA698B /* proc_compare.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141314A141A300AA698B /* proc_compare.c */; };
+ FCBA164D14A146A200AA698B /* w.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA141614A141A300AA698B /* w.c */; };
+ FCBA164E14A146A500AA698B /* uptime.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA141414A141A300AA698B /* uptime.1 */; };
+ FCBA164F14A146A700AA698B /* w.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA141514A141A300AA698B /* w.1 */; };
+ FCBA165014A146BE00AA698B /* users.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA140D14A141A300AA698B /* users.c */; };
+ FCBA165114A146C100AA698B /* users.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA140C14A141A300AA698B /* users.1 */; };
+ FCE30EA814B5105200CC0294 /* pwd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13D814A141A300AA698B /* pwd.1 */; };
+ FCE30EBA14B532D900CC0294 /* com.apple.locate.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13A414A141A300AA698B /* com.apple.locate.plist */; };
+ FCE30EBD14B533A200CC0294 /* locate.rc in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13AA14A141A300AA698B /* locate.rc */; };
+ FCE30EBF14B533E200CC0294 /* locate.updatedb.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13AB14A141A300AA698B /* locate.updatedb.8 */; };
+ FCE30ED414B536A600CC0294 /* locate.bigram.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139E14A141A300AA698B /* locate.bigram.c */; };
+ FCE30ED514B536B200CC0294 /* locate.bigram.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCE30EC114B5347A00CC0294 /* locate.bigram.8 */; };
+ FCE30EE014B536F200CC0294 /* locate.code.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13A114A141A300AA698B /* locate.code.c */; };
+ FCE30EE114B536F800CC0294 /* locate.code.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13B114A141A300AA698B /* locate.code.8 */; };
+ FCED3AF614B4FC1800C313C3 /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FCED3AF514B4FC1800C313C3 /* libpam.dylib */; };
+ FD155C751D6E37E5005A53CA /* legacy_test.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C721D6E37B5005A53CA /* legacy_test.sh */; };
+ FD155C891D6E38C0005A53CA /* legacy_test.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C771D6E3847005A53CA /* legacy_test.sh */; };
+ FD155C8A1D6E38C0005A53CA /* regress.b.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7A1D6E3847005A53CA /* regress.b.out */; };
+ FD155C8B1D6E38C0005A53CA /* regress.d.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7B1D6E3847005A53CA /* regress.d.out */; };
+ FD155C8C1D6E38C0005A53CA /* regress.f.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7C1D6E3847005A53CA /* regress.f.out */; };
+ FD155C8D1D6E38C0005A53CA /* regress.l1.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7D1D6E3847005A53CA /* regress.l1.out */; };
+ FD155C8E1D6E38C0005A53CA /* regress.l2.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7E1D6E3847005A53CA /* regress.l2.out */; };
+ FD155C8F1D6E38C0005A53CA /* regress.m1.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C7F1D6E3847005A53CA /* regress.m1.out */; };
+ FD155C901D6E38C0005A53CA /* regress.m2.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C801D6E3847005A53CA /* regress.m2.out */; };
+ FD155C911D6E38C0005A53CA /* regress.m3.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C811D6E3847005A53CA /* regress.m3.out */; };
+ FD155C921D6E38C0005A53CA /* regress.m4.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C821D6E3847005A53CA /* regress.m4.out */; };
+ FD155C931D6E38C0005A53CA /* regress.m5.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C831D6E3847005A53CA /* regress.m5.out */; };
+ FD155C941D6E38C0005A53CA /* regress.missingpos1.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C841D6E3847005A53CA /* regress.missingpos1.out */; };
+ FD155C951D6E38C0005A53CA /* regress.s.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C851D6E3847005A53CA /* regress.s.out */; };
+ FD155C961D6E38C0005A53CA /* regress.sh in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C861D6E3847005A53CA /* regress.sh */; };
+ FD155C971D6E38C0005A53CA /* regress.zero.out in CopyFiles */ = {isa = PBXBuildFile; fileRef = FD155C871D6E3847005A53CA /* regress.zero.out */; };
+ FD6060B51B7C0388004BCA6A /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060B41B7C0388004BCA6A /* main.c */; };
+ FD6060D21B7C0471004BCA6A /* alias.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060BC1B7C0471004BCA6A /* alias.c */; };
+ FD6060D31B7C0471004BCA6A /* arith_yacc.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060BD1B7C0471004BCA6A /* arith_yacc.c */; };
+ FD6060D41B7C0471004BCA6A /* arith_yylex.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060BE1B7C0471004BCA6A /* arith_yylex.c */; };
+ FD6060D51B7C0471004BCA6A /* cd.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060BF1B7C0471004BCA6A /* cd.c */; };
+ FD6060D61B7C0471004BCA6A /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C01B7C0471004BCA6A /* error.c */; };
+ FD6060D71B7C0471004BCA6A /* eval.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C11B7C0471004BCA6A /* eval.c */; };
+ FD6060D81B7C0471004BCA6A /* exec.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C21B7C0471004BCA6A /* exec.c */; };
+ FD6060D91B7C0471004BCA6A /* expand.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C31B7C0471004BCA6A /* expand.c */; };
+ FD6060DA1B7C0471004BCA6A /* histedit.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C41B7C0471004BCA6A /* histedit.c */; };
+ FD6060DB1B7C0471004BCA6A /* input.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C51B7C0471004BCA6A /* input.c */; };
+ FD6060DC1B7C0471004BCA6A /* jobs.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C61B7C0471004BCA6A /* jobs.c */; };
+ FD6060DD1B7C0471004BCA6A /* mail.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C71B7C0471004BCA6A /* mail.c */; };
+ FD6060DE1B7C0471004BCA6A /* memalloc.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C81B7C0471004BCA6A /* memalloc.c */; };
+ FD6060DF1B7C0471004BCA6A /* miscbltin.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060C91B7C0471004BCA6A /* miscbltin.c */; };
+ FD6060E01B7C0471004BCA6A /* mystring.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CA1B7C0471004BCA6A /* mystring.c */; };
+ FD6060E11B7C0471004BCA6A /* options.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CB1B7C0471004BCA6A /* options.c */; };
+ FD6060E21B7C0471004BCA6A /* output.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CC1B7C0471004BCA6A /* output.c */; };
+ FD6060E31B7C0471004BCA6A /* parser.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CD1B7C0471004BCA6A /* parser.c */; };
+ FD6060E41B7C0471004BCA6A /* redir.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CE1B7C0471004BCA6A /* redir.c */; };
+ FD6060E51B7C0471004BCA6A /* show.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060CF1B7C0471004BCA6A /* show.c */; };
+ FD6060E61B7C0471004BCA6A /* trap.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060D01B7C0471004BCA6A /* trap.c */; };
+ FD6060E71B7C0471004BCA6A /* var.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060D11B7C0471004BCA6A /* var.c */; };
+ FD6060EB1B7C04E4004BCA6A /* echo.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060EA1B7C04E4004BCA6A /* echo.c */; };
+ FD6060EC1B7C0506004BCA6A /* kill.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA139114A141A300AA698B /* kill.c */; };
+ FD6060ED1B7C0518004BCA6A /* printf.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13D514A141A300AA698B /* printf.c */; };
+ FD6060EE1B7C0521004BCA6A /* test.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13FB14A141A300AA698B /* test.c */; };
+ FD6060FD1B7C0CAF004BCA6A /* builtins.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060FA1B7C0CAF004BCA6A /* builtins.c */; };
+ FD6060FE1B7C0CAF004BCA6A /* nodes.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060FB1B7C0CAF004BCA6A /* nodes.c */; };
+ FD6060FF1B7C0CAF004BCA6A /* syntax.c in Sources */ = {isa = PBXBuildFile; fileRef = FD6060FC1B7C0CAF004BCA6A /* syntax.c */; };
+ FD88EB03198C5257006B7EFD /* envopts.c in Sources */ = {isa = PBXBuildFile; fileRef = FD88EB01198C5257006B7EFD /* envopts.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ C6868580154725990025D623 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C6868575154725700025D623;
+ remoteInfo = systime;
+ };
+ C6868582154725A30025D623 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C6868575154725700025D623;
+ remoteInfo = systime;
+ };
+ FC5D63A114B9864400123E48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC5D638F14B9822D00123E48;
+ remoteInfo = hexdump;
+ };
+ FC5D63A314B9864400123E48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC5D637F14B9819E00123E48;
+ remoteInfo = what;
+ };
+ FC5D63A514B9866500123E48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC5D638F14B9822D00123E48;
+ remoteInfo = hexdump;
+ };
+ FC5D63A714B9866500123E48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC5D637F14B9819E00123E48;
+ remoteInfo = what;
+ };
+ FCBA150014A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA149814A141FF00AA698B;
+ remoteInfo = apply;
+ };
+ FCBA150214A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14AE14A1422D00AA698B;
+ remoteInfo = basename;
+ };
+ FCBA150414A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14B714A1423E00AA698B;
+ remoteInfo = chroot;
+ };
+ FCBA150614A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14BF14A1426800AA698B;
+ remoteInfo = date;
+ };
+ FCBA150814A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14C714A1428000AA698B;
+ remoteInfo = dirname;
+ };
+ FCBA150A14A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14CF14A1433F00AA698B;
+ remoteInfo = echo;
+ };
+ FCBA150C14A144F700AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14D714A1434A00AA698B;
+ remoteInfo = env;
+ };
+ FCBA165414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA150E14A1453A00AA698B;
+ remoteInfo = expr;
+ };
+ FCBA165614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA151614A1454D00AA698B;
+ remoteInfo = false;
+ };
+ FCBA165814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA151E14A1455600AA698B;
+ remoteInfo = find;
+ };
+ FCBA165A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA152614A1455900AA698B;
+ remoteInfo = getopt;
+ };
+ FCBA165C14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA152E14A1455C00AA698B;
+ remoteInfo = hostname;
+ };
+ FCBA165E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA153614A1455F00AA698B;
+ remoteInfo = id;
+ };
+ FCBA166014A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA153E14A1456100AA698B;
+ remoteInfo = jot;
+ };
+ FCBA166214A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA154614A1456400AA698B;
+ remoteInfo = kill;
+ };
+ FCBA166414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA154E14A1456700AA698B;
+ remoteInfo = killall;
+ };
+ FCBA166614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA155614A1456A00AA698B;
+ remoteInfo = lastcomm;
+ };
+ FCBA166814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA155E14A1456E00AA698B;
+ remoteInfo = locate;
+ };
+ FCBA166A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA156614A1457100AA698B;
+ remoteInfo = logname;
+ };
+ FCBA166E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA157614A1457B00AA698B;
+ remoteInfo = mktemp;
+ };
+ FCBA167014A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA157E14A1457F00AA698B;
+ remoteInfo = nice;
+ };
+ FCBA167214A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA158614A1458500AA698B;
+ remoteInfo = nohup;
+ };
+ FCBA167414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA158E14A1458800AA698B;
+ remoteInfo = path_helper;
+ };
+ FCBA167614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA159614A1458C00AA698B;
+ remoteInfo = printenv;
+ };
+ FCBA167814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA159E14A1459000AA698B;
+ remoteInfo = printf;
+ };
+ FCBA167A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15A614A1459500AA698B;
+ remoteInfo = pwd;
+ };
+ FCBA167C14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15AE14A1459700AA698B;
+ remoteInfo = renice;
+ };
+ FCBA167E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15B614A1459900AA698B;
+ remoteInfo = script;
+ };
+ FCBA168014A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15BE14A1459E00AA698B;
+ remoteInfo = seq;
+ };
+ FCBA168214A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15C614A145A200AA698B;
+ remoteInfo = shlock;
+ };
+ FCBA168414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15CE14A145A500AA698B;
+ remoteInfo = sleep;
+ };
+ FCBA168614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15D614A145A700AA698B;
+ remoteInfo = su;
+ };
+ FCBA168814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15DE14A145A900AA698B;
+ remoteInfo = tee;
+ };
+ FCBA168A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15E614A145AE00AA698B;
+ remoteInfo = test;
+ };
+ FCBA168C14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15EE14A145B000AA698B;
+ remoteInfo = time;
+ };
+ FCBA168E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15F614A145B200AA698B;
+ remoteInfo = true;
+ };
+ FCBA169014A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15FE14A145B500AA698B;
+ remoteInfo = uname;
+ };
+ FCBA169214A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA160614A145B800AA698B;
+ remoteInfo = users;
+ };
+ FCBA169414A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA160E14A145BA00AA698B;
+ remoteInfo = w;
+ };
+ FCBA169614A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA161614A145BC00AA698B;
+ remoteInfo = whereis;
+ };
+ FCBA169814A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA161E14A145C000AA698B;
+ remoteInfo = which;
+ };
+ FCBA169A14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA162614A145C500AA698B;
+ remoteInfo = who;
+ };
+ FCBA169C14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA162E14A145C700AA698B;
+ remoteInfo = xargs;
+ };
+ FCBA169E14A146D000AA698B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA163614A145CA00AA698B;
+ remoteInfo = yes;
+ };
+ FCE30EE214B539BF00CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCE30EC214B5368A00CC0294;
+ remoteInfo = locate.bigram;
+ };
+ FCE30EE414B539BF00CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCE30ED614B536C900CC0294;
+ remoteInfo = locate.code;
+ };
+ FCE30F4E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA149814A141FF00AA698B;
+ remoteInfo = apply;
+ };
+ FCE30F5014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14AE14A1422D00AA698B;
+ remoteInfo = basename;
+ };
+ FCE30F5214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14B714A1423E00AA698B;
+ remoteInfo = chroot;
+ };
+ FCE30F5414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14BF14A1426800AA698B;
+ remoteInfo = date;
+ };
+ FCE30F5614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14C714A1428000AA698B;
+ remoteInfo = dirname;
+ };
+ FCE30F5814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14CF14A1433F00AA698B;
+ remoteInfo = echo;
+ };
+ FCE30F5A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA14D714A1434A00AA698B;
+ remoteInfo = env;
+ };
+ FCE30F5C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA150E14A1453A00AA698B;
+ remoteInfo = expr;
+ };
+ FCE30F5E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA151614A1454D00AA698B;
+ remoteInfo = false;
+ };
+ FCE30F6014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA151E14A1455600AA698B;
+ remoteInfo = find;
+ };
+ FCE30F6214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA152614A1455900AA698B;
+ remoteInfo = getopt;
+ };
+ FCE30F6414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA152E14A1455C00AA698B;
+ remoteInfo = hostname;
+ };
+ FCE30F6614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA153614A1455F00AA698B;
+ remoteInfo = id;
+ };
+ FCE30F6814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA153E14A1456100AA698B;
+ remoteInfo = jot;
+ };
+ FCE30F6A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA154614A1456400AA698B;
+ remoteInfo = kill;
+ };
+ FCE30F6C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA154E14A1456700AA698B;
+ remoteInfo = killall;
+ };
+ FCE30F6E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA155614A1456A00AA698B;
+ remoteInfo = lastcomm;
+ };
+ FCE30F7014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA156614A1457100AA698B;
+ remoteInfo = logname;
+ };
+ FCE30F7214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA157614A1457B00AA698B;
+ remoteInfo = mktemp;
+ };
+ FCE30F7414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA157E14A1457F00AA698B;
+ remoteInfo = nice;
+ };
+ FCE30F7614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA158614A1458500AA698B;
+ remoteInfo = nohup;
+ };
+ FCE30F7814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA158E14A1458800AA698B;
+ remoteInfo = path_helper;
+ };
+ FCE30F7A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA159614A1458C00AA698B;
+ remoteInfo = printenv;
+ };
+ FCE30F7C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA159E14A1459000AA698B;
+ remoteInfo = printf;
+ };
+ FCE30F7E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15A614A1459500AA698B;
+ remoteInfo = pwd;
+ };
+ FCE30F8014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15AE14A1459700AA698B;
+ remoteInfo = renice;
+ };
+ FCE30F8214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15B614A1459900AA698B;
+ remoteInfo = script;
+ };
+ FCE30F8414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15BE14A1459E00AA698B;
+ remoteInfo = seq;
+ };
+ FCE30F8614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15C614A145A200AA698B;
+ remoteInfo = shlock;
+ };
+ FCE30F8814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15CE14A145A500AA698B;
+ remoteInfo = sleep;
+ };
+ FCE30F8A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15DE14A145A900AA698B;
+ remoteInfo = tee;
+ };
+ FCE30F8C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15E614A145AE00AA698B;
+ remoteInfo = test;
+ };
+ FCE30F8E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15EE14A145B000AA698B;
+ remoteInfo = time;
+ };
+ FCE30F9014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15F614A145B200AA698B;
+ remoteInfo = true;
+ };
+ FCE30F9214B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA15FE14A145B500AA698B;
+ remoteInfo = uname;
+ };
+ FCE30F9414B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA160614A145B800AA698B;
+ remoteInfo = users;
+ };
+ FCE30F9614B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA160E14A145BA00AA698B;
+ remoteInfo = w;
+ };
+ FCE30F9814B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA161614A145BC00AA698B;
+ remoteInfo = whereis;
+ };
+ FCE30F9A14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA161E14A145C000AA698B;
+ remoteInfo = which;
+ };
+ FCE30F9C14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA162614A145C500AA698B;
+ remoteInfo = who;
+ };
+ FCE30F9E14B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA162E14A145C700AA698B;
+ remoteInfo = xargs;
+ };
+ FCE30FA014B619E600CC0294 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FCBA163614A145CA00AA698B;
+ remoteInfo = yes;
+ };
+ FD6060B81B7C03B3004BCA6A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD6060B11B7C0388004BCA6A;
+ remoteInfo = sh;
+ };
+ FD6060BA1B7C03BC004BCA6A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD6060B11B7C0388004BCA6A;
+ remoteInfo = sh;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ C6868574154725700025D623 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ C686857C154725700025D623 /* systime.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC5D638614B9819E00123E48 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC5D638E14B981D800123E48 /* what.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC5D639314B9822D00123E48 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC5D639914B9825B00123E48 /* hexdump.1 in CopyFiles */,
+ FC5D639A14B9825B00123E48 /* od.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA149B14A141FF00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14ED14A1444E00AA698B /* apply.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14B114A1422D00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14EF14A1446B00AA698B /* basename.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14BA14A1423E00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14F214A1448F00AA698B /* chroot.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14C214A1426800AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14F314A1449A00AA698B /* date.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14CA14A1428000AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14F814A144CB00AA698B /* dirname.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14D214A1433F00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14F914A144D000AA698B /* echo.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA14DA14A1434A00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA14FB14A144E300AA698B /* env.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA151114A1453A00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030014B5071A0030BEB3 /* expr.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA151914A1454D00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030214B5072C0030BEB3 /* false.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA152114A1455600AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030B14B507450030BEB3 /* find.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA152914A1455900AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030D14B507580030BEB3 /* getopt.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA153114A1455C00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA030F14B507700030BEB3 /* hostname.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA153914A1455F00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031214B507870030BEB3 /* groups.1 in CopyFiles */,
+ FCBA031314B507870030BEB3 /* id.1 in CopyFiles */,
+ FCBA031414B507870030BEB3 /* whoami.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA154114A1456100AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031614B507950030BEB3 /* jot.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA154914A1456400AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031814B507A50030BEB3 /* kill.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA155114A1456700AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031A14B507B60030BEB3 /* killall.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA155914A1456A00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA031C14B507C40030BEB3 /* lastcomm.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA156114A1456E00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA032014B507E50030BEB3 /* locate.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA156914A1457100AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02FE14B506FF0030BEB3 /* logname.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA157914A1457B00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02FA14B506DA0030BEB3 /* mktemp.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA158114A1457F00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02F714B506B10030BEB3 /* nice.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA158914A1458500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02F614B5069C0030BEB3 /* nohup.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA159114A1458800AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02F414B5068C0030BEB3 /* path_helper.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA159914A1458C00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02F214B5067C0030BEB3 /* printenv.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15A114A1459000AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02EF14B5065D0030BEB3 /* printf.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15A914A1459500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EA814B5105200CC0294 /* pwd.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15B114A1459700AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02EB14B5063E0030BEB3 /* renice.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15B914A1459900AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02E914B5062E0030BEB3 /* script.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15C114A1459E00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA02E714B5061B0030BEB3 /* seq.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15C914A145A200AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0C14B3CD5B00ECF511 /* shlock.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15D114A145A500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0914B3CD3E00ECF511 /* sleep.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15D914A145A700AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0814B3CD3500ECF511 /* su.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15E114A145A900AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0514B3CD1D00ECF511 /* tee.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15E914A145AE00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0314B3CD1400ECF511 /* [.1 in CopyFiles */,
+ FC2B5C0414B3CD1400ECF511 /* test.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15F114A145B000AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5C0114B3CD0300ECF511 /* time.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA15F914A145B200AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5BFF14B3CCEF00ECF511 /* true.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA160114A145B500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC2B5BFD14B3CCD200ECF511 /* uname.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA160914A145B800AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA165114A146C100AA698B /* users.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA161114A145BA00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164F14A146A700AA698B /* w.1 in CopyFiles */,
+ FCBA164E14A146A500AA698B /* uptime.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA161914A145BC00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164914A1469300AA698B /* whereis.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA162114A145C000AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164714A1468900AA698B /* which.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA162914A145C500AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164514A1468000AA698B /* who.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA163114A145C700AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA164214A1467500AA698B /* xargs.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCBA163914A145CA00AA698B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCBA163E14A1466500AA698B /* yes.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EB914B532C700CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EBA14B532D900CC0294 /* com.apple.locate.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EBC14B5339000CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EBD14B533A200CC0294 /* locate.rc in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EBE14B533B500CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EBF14B533E200CC0294 /* locate.updatedb.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EC714B5368A00CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30ED514B536B200CC0294 /* locate.bigram.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FCE30EDA14B536C900CC0294 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCE30EE114B536F800CC0294 /* locate.code.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD155C741D6E37D7005A53CA /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /AppleInternal/Tests/shell_cmds/test;
+ dstSubfolderSpec = 0;
+ files = (
+ FD155C751D6E37E5005A53CA /* legacy_test.sh in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD155C881D6E38AB005A53CA /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /AppleInternal/Tests/shell_cmds/printf;
+ dstSubfolderSpec = 0;
+ files = (
+ FD155C891D6E38C0005A53CA /* legacy_test.sh in CopyFiles */,
+ FD155C8A1D6E38C0005A53CA /* regress.b.out in CopyFiles */,
+ FD155C8B1D6E38C0005A53CA /* regress.d.out in CopyFiles */,
+ FD155C8C1D6E38C0005A53CA /* regress.f.out in CopyFiles */,
+ FD155C8D1D6E38C0005A53CA /* regress.l1.out in CopyFiles */,
+ FD155C8E1D6E38C0005A53CA /* regress.l2.out in CopyFiles */,
+ FD155C8F1D6E38C0005A53CA /* regress.m1.out in CopyFiles */,
+ FD155C901D6E38C0005A53CA /* regress.m2.out in CopyFiles */,
+ FD155C911D6E38C0005A53CA /* regress.m3.out in CopyFiles */,
+ FD155C921D6E38C0005A53CA /* regress.m4.out in CopyFiles */,
+ FD155C931D6E38C0005A53CA /* regress.m5.out in CopyFiles */,
+ FD155C941D6E38C0005A53CA /* regress.missingpos1.out in CopyFiles */,
+ FD155C951D6E38C0005A53CA /* regress.s.out in CopyFiles */,
+ FD155C961D6E38C0005A53CA /* regress.sh in CopyFiles */,
+ FD155C971D6E38C0005A53CA /* regress.zero.out in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 6C1C283E22FB822900E0AC67 /* su_entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = su_entitlements.plist; sourceTree = "<group>"; };
+ C6868576154725700025D623 /* systime */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = systime; sourceTree = BUILT_PRODUCTS_DIR; };
+ C6868579154725700025D623 /* systime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = systime.c; sourceTree = "<group>"; };
+ C686857B154725700025D623 /* systime.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = systime.1; sourceTree = "<group>"; };
+ CE799E6024AD3B1B00E73238 /* test_time.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = test_time.sh; sourceTree = "<group>"; usesTabs = 1; };
+ CE799E6224B3982200E73238 /* install-files.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-files.sh"; sourceTree = "<group>"; };
+ CE799E6324B3982200E73238 /* builtins.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = builtins.txt; sourceTree = "<group>"; };
+ CE799E6424B3982200E73238 /* builtins-manpages.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "builtins-manpages.txt"; sourceTree = "<group>"; };
+ FC5D636814B9808E00123E48 /* conv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = conv.c; sourceTree = "<group>"; };
+ FC5D636914B9808E00123E48 /* display.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = display.c; sourceTree = "<group>"; };
+ FC5D636A14B9808E00123E48 /* hexdump.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = hexdump.1; sourceTree = "<group>"; };
+ FC5D636B14B9808E00123E48 /* hexdump.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hexdump.c; sourceTree = "<group>"; };
+ FC5D636C14B9808E00123E48 /* hexdump.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = hexdump.h; sourceTree = "<group>"; };
+ FC5D636D14B9808E00123E48 /* hexsyntax.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hexsyntax.c; sourceTree = "<group>"; };
+ FC5D636E14B9808E00123E48 /* od.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = od.1; sourceTree = "<group>"; };
+ FC5D636F14B9808E00123E48 /* odsyntax.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = odsyntax.c; sourceTree = "<group>"; };
+ FC5D637014B9808E00123E48 /* parse.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = parse.c; sourceTree = "<group>"; };
+ FC5D637214B9808E00123E48 /* what.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = what.1; sourceTree = "<group>"; };
+ FC5D637314B9808E00123E48 /* what.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = what.c; sourceTree = "<group>"; };
+ FC5D638B14B9819E00123E48 /* what */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = what; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC5D639714B9822D00123E48 /* hexdump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hexdump; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA02E514B505A50030BEB3 /* libresolv.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libresolv.dylib; path = /usr/lib/libresolv.dylib; sourceTree = "<absolute>"; };
+ FCBA134114A141A300AA698B /* alias.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = alias.1; sourceTree = "<group>"; };
+ FCBA134314A141A300AA698B /* generic.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = generic.sh; sourceTree = "<group>"; };
+ FCBA134614A141A300AA698B /* apply.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = apply.1; sourceTree = "<group>"; };
+ FCBA134714A141A300AA698B /* apply.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = apply.c; sourceTree = "<group>"; };
+ FCBA134A14A141A300AA698B /* basename.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = basename.1; sourceTree = "<group>"; };
+ FCBA134B14A141A300AA698B /* basename.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = basename.c; sourceTree = "<group>"; };
+ FCBA134C14A141A300AA698B /* dirname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; name = dirname.1; path = ../basename/dirname.1; sourceTree = "<group>"; };
+ FCBA134F14A141A300AA698B /* chroot.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = chroot.8; sourceTree = "<group>"; };
+ FCBA135014A141A300AA698B /* chroot.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chroot.c; sourceTree = "<group>"; };
+ FCBA135314A141A300AA698B /* date.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = date.1; sourceTree = "<group>"; };
+ FCBA135414A141A300AA698B /* date.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = date.c; sourceTree = "<group>"; };
+ FCBA135514A141A300AA698B /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCBA135714A141A300AA698B /* netdate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = netdate.c; sourceTree = "<group>"; };
+ FCBA135814A141A300AA698B /* vary.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vary.c; sourceTree = "<group>"; };
+ FCBA135914A141A300AA698B /* vary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = vary.h; sourceTree = "<group>"; };
+ FCBA135B14A141A300AA698B /* dirname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dirname.c; sourceTree = "<group>"; };
+ FCBA135E14A141A300AA698B /* echo.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = echo.1; sourceTree = "<group>"; };
+ FCBA135F14A141A300AA698B /* echo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = echo.c; sourceTree = "<group>"; };
+ FCBA136214A141A300AA698B /* env.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = env.1; sourceTree = "<group>"; };
+ FCBA136314A141A300AA698B /* env.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = env.c; sourceTree = "<group>"; };
+ FCBA136614A141A300AA698B /* expr.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = expr.1; sourceTree = "<group>"; };
+ FCBA136714A141A300AA698B /* expr.y */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.yacc; path = expr.y; sourceTree = "<group>"; };
+ FCBA136A14A141A300AA698B /* false.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = false.1; sourceTree = "<group>"; };
+ FCBA136B14A141A300AA698B /* false.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = false.c; sourceTree = "<group>"; };
+ FCBA136F14A141A300AA698B /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCBA137014A141A300AA698B /* find.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = find.1; sourceTree = "<group>"; };
+ FCBA137114A141A300AA698B /* find.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = find.c; sourceTree = "<group>"; };
+ FCBA137214A141A300AA698B /* find.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = find.h; sourceTree = "<group>"; };
+ FCBA137314A141A300AA698B /* function.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = function.c; sourceTree = "<group>"; };
+ FCBA137414A141A300AA698B /* getdate.y */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.yacc; path = getdate.y; sourceTree = "<group>"; };
+ FCBA137514A141A300AA698B /* ls.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ls.c; sourceTree = "<group>"; };
+ FCBA137614A141A300AA698B /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ FCBA137814A141A300AA698B /* misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+ FCBA137914A141A300AA698B /* operator.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = operator.c; sourceTree = "<group>"; };
+ FCBA137A14A141A300AA698B /* option.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = option.c; sourceTree = "<group>"; };
+ FCBA137C14A141A300AA698B /* getopt.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = getopt.1; sourceTree = "<group>"; };
+ FCBA137D14A141A300AA698B /* getopt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = getopt.c; sourceTree = "<group>"; };
+ FCBA138014A141A300AA698B /* hostname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = hostname.1; sourceTree = "<group>"; };
+ FCBA138114A141A300AA698B /* hostname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hostname.c; sourceTree = "<group>"; };
+ FCBA138414A141A300AA698B /* groups.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = groups.1; sourceTree = "<group>"; };
+ FCBA138514A141A300AA698B /* id.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = id.1; sourceTree = "<group>"; };
+ FCBA138614A141A300AA698B /* id.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = id.c; sourceTree = "<group>"; };
+ FCBA138A14A141A300AA698B /* whoami.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = whoami.1; sourceTree = "<group>"; };
+ FCBA138C14A141A300AA698B /* jot.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = jot.1; sourceTree = "<group>"; };
+ FCBA138D14A141A300AA698B /* jot.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = jot.c; sourceTree = "<group>"; };
+ FCBA139014A141A300AA698B /* kill.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = kill.1; sourceTree = "<group>"; };
+ FCBA139114A141A300AA698B /* kill.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = kill.c; sourceTree = "<group>"; };
+ FCBA139414A141A300AA698B /* killall.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = killall.1; sourceTree = "<group>"; };
+ FCBA139514A141A300AA698B /* killall.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = killall.c; sourceTree = "<group>"; };
+ FCBA139814A141A300AA698B /* lastcomm.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = lastcomm.1; sourceTree = "<group>"; };
+ FCBA139914A141A300AA698B /* lastcomm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = lastcomm.c; sourceTree = "<group>"; };
+ FCBA139B14A141A300AA698B /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FCBA139E14A141A300AA698B /* locate.bigram.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = locate.bigram.c; sourceTree = "<group>"; };
+ FCBA13A114A141A300AA698B /* locate.code.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = locate.code.c; sourceTree = "<group>"; };
+ FCBA13A414A141A300AA698B /* com.apple.locate.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.locate.plist; sourceTree = "<group>"; };
+ FCBA13A514A141A300AA698B /* concatdb.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = concatdb.sh; sourceTree = "<group>"; };
+ FCBA13A714A141A300AA698B /* locate.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = locate.1; sourceTree = "<group>"; };
+ FCBA13A814A141A300AA698B /* locate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = locate.c; sourceTree = "<group>"; };
+ FCBA13A914A141A300AA698B /* locate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = locate.h; sourceTree = "<group>"; };
+ FCBA13AA14A141A300AA698B /* locate.rc */ = {isa = PBXFileReference; lastKnownFileType = text; path = locate.rc; sourceTree = "<group>"; };
+ FCBA13AB14A141A300AA698B /* locate.updatedb.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = locate.updatedb.8; sourceTree = "<group>"; };
+ FCBA13AD14A141A300AA698B /* mklocatedb.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = mklocatedb.sh; sourceTree = "<group>"; };
+ FCBA13AE14A141A300AA698B /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FCBA13AF14A141A300AA698B /* updatedb.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = updatedb.sh; sourceTree = "<group>"; };
+ FCBA13B014A141A300AA698B /* util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FCBA13B114A141A300AA698B /* locate.code.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = locate.code.8; sourceTree = "<group>"; };
+ FCBA13B414A141A300AA698B /* logname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = logname.1; sourceTree = "<group>"; };
+ FCBA13B514A141A300AA698B /* logname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = logname.c; sourceTree = "<group>"; };
+ FCBA13C014A141A300AA698B /* mktemp.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = mktemp.1; sourceTree = "<group>"; };
+ FCBA13C114A141A300AA698B /* mktemp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mktemp.c; sourceTree = "<group>"; };
+ FCBA13C414A141A300AA698B /* nice.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = nice.1; sourceTree = "<group>"; };
+ FCBA13C514A141A300AA698B /* nice.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nice.c; sourceTree = "<group>"; };
+ FCBA13C814A141A300AA698B /* nohup.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = nohup.1; sourceTree = "<group>"; };
+ FCBA13C914A141A300AA698B /* nohup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nohup.c; sourceTree = "<group>"; };
+ FCBA13CC14A141A300AA698B /* path_helper.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = path_helper.8; sourceTree = "<group>"; };
+ FCBA13CD14A141A300AA698B /* path_helper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = path_helper.c; sourceTree = "<group>"; };
+ FCBA13D014A141A300AA698B /* printenv.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = printenv.1; sourceTree = "<group>"; };
+ FCBA13D114A141A300AA698B /* printenv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = printenv.c; sourceTree = "<group>"; };
+ FCBA13D414A141A300AA698B /* printf.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = printf.1; sourceTree = "<group>"; };
+ FCBA13D514A141A300AA698B /* printf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = printf.c; sourceTree = "<group>"; };
+ FCBA13D814A141A300AA698B /* pwd.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = pwd.1; sourceTree = "<group>"; };
+ FCBA13D914A141A300AA698B /* pwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pwd.c; sourceTree = "<group>"; };
+ FCBA13DC14A141A300AA698B /* renice.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = renice.8; sourceTree = "<group>"; };
+ FCBA13DD14A141A300AA698B /* renice.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = renice.c; sourceTree = "<group>"; };
+ FCBA13E014A141A300AA698B /* script.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = script.1; sourceTree = "<group>"; };
+ FCBA13E114A141A300AA698B /* script.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = script.c; sourceTree = "<group>"; };
+ FCBA13E414A141A300AA698B /* seq.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = seq.1; sourceTree = "<group>"; };
+ FCBA13E514A141A300AA698B /* seq.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = seq.c; sourceTree = "<group>"; };
+ FCBA13E814A141A300AA698B /* shlock.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = shlock.1; sourceTree = "<group>"; };
+ FCBA13E914A141A300AA698B /* shlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = shlock.c; sourceTree = "<group>"; };
+ FCBA13EC14A141A300AA698B /* sleep.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = sleep.1; sourceTree = "<group>"; };
+ FCBA13ED14A141A300AA698B /* sleep.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sleep.c; sourceTree = "<group>"; };
+ FCBA13F014A141A300AA698B /* su.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = su.1; sourceTree = "<group>"; };
+ FCBA13F114A141A300AA698B /* su.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = su.c; sourceTree = "<group>"; };
+ FCBA13F214A141A300AA698B /* su.pam */ = {isa = PBXFileReference; lastKnownFileType = text; path = su.pam; sourceTree = "<group>"; };
+ FCBA13F514A141A300AA698B /* tee.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = tee.1; sourceTree = "<group>"; };
+ FCBA13F614A141A300AA698B /* tee.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tee.c; sourceTree = "<group>"; };
+ FCBA13F814A141A300AA698B /* [.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = "[.1"; sourceTree = "<group>"; };
+ FCBA13FA14A141A300AA698B /* test.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = test.1; sourceTree = "<group>"; };
+ FCBA13FB14A141A300AA698B /* test.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = test.c; sourceTree = "<group>"; };
+ FCBA13FF14A141A300AA698B /* time.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = time.1; sourceTree = "<group>"; };
+ FCBA140014A141A300AA698B /* time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = time.c; sourceTree = "<group>"; usesTabs = 1; };
+ FCBA140314A141A300AA698B /* true.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = true.1; sourceTree = "<group>"; };
+ FCBA140414A141A300AA698B /* true.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = true.c; sourceTree = "<group>"; };
+ FCBA140814A141A300AA698B /* uname.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = uname.1; sourceTree = "<group>"; };
+ FCBA140914A141A300AA698B /* uname.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = uname.c; sourceTree = "<group>"; };
+ FCBA140C14A141A300AA698B /* users.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = users.1; sourceTree = "<group>"; };
+ FCBA140D14A141A300AA698B /* users.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = users.c; sourceTree = "<group>"; };
+ FCBA140F14A141A300AA698B /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FCBA141014A141A300AA698B /* fmt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fmt.c; sourceTree = "<group>"; };
+ FCBA141214A141A300AA698B /* pr_time.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pr_time.c; sourceTree = "<group>"; };
+ FCBA141314A141A300AA698B /* proc_compare.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = proc_compare.c; sourceTree = "<group>"; };
+ FCBA141414A141A300AA698B /* uptime.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = uptime.1; sourceTree = "<group>"; };
+ FCBA141514A141A300AA698B /* w.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = w.1; sourceTree = "<group>"; };
+ FCBA141614A141A300AA698B /* w.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = w.c; sourceTree = "<group>"; };
+ FCBA141914A141A300AA698B /* whereis.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = whereis.1; sourceTree = "<group>"; };
+ FCBA141A14A141A300AA698B /* whereis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = whereis.c; sourceTree = "<group>"; };
+ FCBA141D14A141A300AA698B /* which.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = which.1; sourceTree = "<group>"; };
+ FCBA141E14A141A300AA698B /* which.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = which.c; sourceTree = "<group>"; };
+ FCBA142114A141A300AA698B /* utmpentry.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = utmpentry.c; sourceTree = "<group>"; };
+ FCBA142214A141A300AA698B /* utmpentry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = utmpentry.h; sourceTree = "<group>"; };
+ FCBA142314A141A300AA698B /* who.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = who.1; sourceTree = "<group>"; };
+ FCBA142414A141A300AA698B /* who.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = who.c; sourceTree = "<group>"; };
+ FCBA142714A141A300AA698B /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FCBA142814A141A300AA698B /* strnsubst.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = strnsubst.c; sourceTree = "<group>"; };
+ FCBA142914A141A300AA698B /* xargs.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = xargs.1; sourceTree = "<group>"; };
+ FCBA142A14A141A300AA698B /* xargs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xargs.c; sourceTree = "<group>"; };
+ FCBA142D14A141A300AA698B /* yes.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = yes.1; sourceTree = "<group>"; };
+ FCBA142E14A141A300AA698B /* yes.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = yes.c; sourceTree = "<group>"; };
+ FCBA149E14A141FF00AA698B /* apply */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = apply; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14B414A1422D00AA698B /* basename */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = basename; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14BD14A1423E00AA698B /* chroot */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chroot; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14C514A1426800AA698B /* date */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = date; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14CD14A1428000AA698B /* dirname */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dirname; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14D514A1433F00AA698B /* echo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = echo; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA14DD14A1434A00AA698B /* env */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = env; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA151414A1453A00AA698B /* expr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = expr; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA151C14A1454D00AA698B /* false */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = false; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA152414A1455600AA698B /* find */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = find; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA152C14A1455900AA698B /* getopt */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = getopt; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA153414A1455C00AA698B /* hostname */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hostname; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA153C14A1455F00AA698B /* id */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = id; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA154414A1456100AA698B /* jot */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = jot; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA154C14A1456400AA698B /* kill */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = kill; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA155414A1456700AA698B /* killall */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = killall; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA155C14A1456A00AA698B /* lastcomm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lastcomm; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA156414A1456E00AA698B /* locate */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locate; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA156C14A1457100AA698B /* logname */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = logname; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA157C14A1457B00AA698B /* mktemp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mktemp; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA158414A1457F00AA698B /* nice */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nice; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA158C14A1458500AA698B /* nohup */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nohup; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA159414A1458800AA698B /* path_helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = path_helper; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA159C14A1458C00AA698B /* printenv */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = printenv; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15A414A1459000AA698B /* printf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = printf; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15AC14A1459500AA698B /* pwd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pwd; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15B414A1459700AA698B /* renice */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = renice; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15BC14A1459900AA698B /* script */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = script; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15C414A1459E00AA698B /* seq */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = seq; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15CC14A145A200AA698B /* shlock */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = shlock; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15D414A145A500AA698B /* sleep */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sleep; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15DC14A145A700AA698B /* su */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = su; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15E414A145A900AA698B /* tee */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tee; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15EC14A145AE00AA698B /* test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15F414A145B000AA698B /* time */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = time; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA15FC14A145B200AA698B /* true */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = true; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA160414A145B500AA698B /* uname */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = uname; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA160C14A145B800AA698B /* users */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = users; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA161414A145BA00AA698B /* w */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = w; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA161C14A145BC00AA698B /* whereis */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = whereis; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA162414A145C000AA698B /* which */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = which; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA162C14A145C500AA698B /* who */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = who; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA163414A145C700AA698B /* xargs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = xargs; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCBA163C14A145CA00AA698B /* yes */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = yes; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCE30EC114B5347A00CC0294 /* locate.bigram.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = locate.bigram.8; sourceTree = "<group>"; };
+ FCE30ED214B5368A00CC0294 /* locate.bigram */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locate.bigram; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCE30EDE14B536C900CC0294 /* locate.code */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locate.code; sourceTree = BUILT_PRODUCTS_DIR; };
+ FCED3AF514B4FC1800C313C3 /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = /usr/lib/libpam.dylib; sourceTree = "<absolute>"; };
+ FD155C721D6E37B5005A53CA /* legacy_test.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = legacy_test.sh; sourceTree = "<group>"; };
+ FD155C771D6E3847005A53CA /* legacy_test.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = legacy_test.sh; sourceTree = "<group>"; };
+ FD155C7A1D6E3847005A53CA /* regress.b.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.b.out; sourceTree = "<group>"; };
+ FD155C7B1D6E3847005A53CA /* regress.d.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.d.out; sourceTree = "<group>"; };
+ FD155C7C1D6E3847005A53CA /* regress.f.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.f.out; sourceTree = "<group>"; };
+ FD155C7D1D6E3847005A53CA /* regress.l1.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.l1.out; sourceTree = "<group>"; };
+ FD155C7E1D6E3847005A53CA /* regress.l2.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.l2.out; sourceTree = "<group>"; };
+ FD155C7F1D6E3847005A53CA /* regress.m1.out */ = {isa = PBXFileReference; lastKnownFileType = file; path = regress.m1.out; sourceTree = "<group>"; };
+ FD155C801D6E3847005A53CA /* regress.m2.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.m2.out; sourceTree = "<group>"; };
+ FD155C811D6E3847005A53CA /* regress.m3.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.m3.out; sourceTree = "<group>"; };
+ FD155C821D6E3847005A53CA /* regress.m4.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.m4.out; sourceTree = "<group>"; };
+ FD155C831D6E3847005A53CA /* regress.m5.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.m5.out; sourceTree = "<group>"; };
+ FD155C841D6E3847005A53CA /* regress.missingpos1.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.missingpos1.out; sourceTree = "<group>"; };
+ FD155C851D6E3847005A53CA /* regress.s.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.s.out; sourceTree = "<group>"; };
+ FD155C861D6E3847005A53CA /* regress.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = regress.sh; sourceTree = "<group>"; };
+ FD155C871D6E3847005A53CA /* regress.zero.out */ = {isa = PBXFileReference; lastKnownFileType = text; path = regress.zero.out; sourceTree = "<group>"; };
+ FD6060B21B7C0388004BCA6A /* ash */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ash; sourceTree = BUILT_PRODUCTS_DIR; };
+ FD6060B41B7C0388004BCA6A /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ FD6060BC1B7C0471004BCA6A /* alias.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alias.c; sourceTree = "<group>"; };
+ FD6060BD1B7C0471004BCA6A /* arith_yacc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arith_yacc.c; sourceTree = "<group>"; };
+ FD6060BE1B7C0471004BCA6A /* arith_yylex.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = arith_yylex.c; sourceTree = "<group>"; };
+ FD6060BF1B7C0471004BCA6A /* cd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = cd.c; sourceTree = "<group>"; };
+ FD6060C01B7C0471004BCA6A /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = "<group>"; };
+ FD6060C11B7C0471004BCA6A /* eval.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = eval.c; sourceTree = "<group>"; };
+ FD6060C21B7C0471004BCA6A /* exec.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = exec.c; sourceTree = "<group>"; };
+ FD6060C31B7C0471004BCA6A /* expand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = expand.c; sourceTree = "<group>"; };
+ FD6060C41B7C0471004BCA6A /* histedit.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = histedit.c; sourceTree = "<group>"; };
+ FD6060C51B7C0471004BCA6A /* input.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = input.c; sourceTree = "<group>"; };
+ FD6060C61B7C0471004BCA6A /* jobs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jobs.c; sourceTree = "<group>"; };
+ FD6060C71B7C0471004BCA6A /* mail.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mail.c; sourceTree = "<group>"; };
+ FD6060C81B7C0471004BCA6A /* memalloc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memalloc.c; sourceTree = "<group>"; };
+ FD6060C91B7C0471004BCA6A /* miscbltin.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = miscbltin.c; sourceTree = "<group>"; };
+ FD6060CA1B7C0471004BCA6A /* mystring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mystring.c; sourceTree = "<group>"; };
+ FD6060CB1B7C0471004BCA6A /* options.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = options.c; sourceTree = "<group>"; };
+ FD6060CC1B7C0471004BCA6A /* output.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = output.c; sourceTree = "<group>"; };
+ FD6060CD1B7C0471004BCA6A /* parser.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = parser.c; sourceTree = "<group>"; };
+ FD6060CE1B7C0471004BCA6A /* redir.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = redir.c; sourceTree = "<group>"; };
+ FD6060CF1B7C0471004BCA6A /* show.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = show.c; sourceTree = "<group>"; };
+ FD6060D01B7C0471004BCA6A /* trap.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = trap.c; sourceTree = "<group>"; };
+ FD6060D11B7C0471004BCA6A /* var.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = var.c; sourceTree = "<group>"; };
+ FD6060EA1B7C04E4004BCA6A /* echo.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = echo.c; sourceTree = "<group>"; };
+ FD6060FA1B7C0CAF004BCA6A /* builtins.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = builtins.c; sourceTree = "<group>"; };
+ FD6060FB1B7C0CAF004BCA6A /* nodes.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nodes.c; sourceTree = "<group>"; };
+ FD6060FC1B7C0CAF004BCA6A /* syntax.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = syntax.c; sourceTree = "<group>"; };
+ FD6061011B7D2B6D004BCA6A /* builtins.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = builtins.h; sourceTree = "<group>"; };
+ FD6061021B7D2B6D004BCA6A /* nodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nodes.h; sourceTree = "<group>"; };
+ FD6061031B7D2B6D004BCA6A /* syntax.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = syntax.h; sourceTree = "<group>"; };
+ FD6061041B7D2B6D004BCA6A /* token.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = token.h; sourceTree = "<group>"; };
+ FD6061051B7D2BF8004BCA6A /* bltin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bltin.h; sourceTree = "<group>"; };
+ FD6061061B7D2C8C004BCA6A /* alias.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alias.h; sourceTree = "<group>"; };
+ FD6061071B7D2C8C004BCA6A /* arith_yacc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arith_yacc.h; sourceTree = "<group>"; };
+ FD6061081B7D2C8C004BCA6A /* arith.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = arith.h; sourceTree = "<group>"; };
+ FD6061091B7D2C8C004BCA6A /* builtins.def */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = builtins.def; sourceTree = "<group>"; };
+ FD60610A1B7D2C8C004BCA6A /* cd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cd.h; sourceTree = "<group>"; };
+ FD60610B1B7D2C8C004BCA6A /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = "<group>"; };
+ FD60610C1B7D2C8C004BCA6A /* eval.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = eval.h; sourceTree = "<group>"; };
+ FD60610D1B7D2C8C004BCA6A /* exec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = exec.h; sourceTree = "<group>"; };
+ FD60610E1B7D2C8C004BCA6A /* expand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = expand.h; sourceTree = "<group>"; };
+ FD60610F1B7D2C8C004BCA6A /* input.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = input.h; sourceTree = "<group>"; };
+ FD6061101B7D2C8C004BCA6A /* jobs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = jobs.h; sourceTree = "<group>"; };
+ FD6061111B7D2C8C004BCA6A /* mail.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mail.h; sourceTree = "<group>"; };
+ FD6061121B7D2C8C004BCA6A /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = "<group>"; };
+ FD6061131B7D2C8C004BCA6A /* memalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = memalloc.h; sourceTree = "<group>"; };
+ FD6061141B7D2C8C004BCA6A /* mkbuiltins */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = mkbuiltins; sourceTree = "<group>"; };
+ FD6061151B7D2C8C004BCA6A /* mknodes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mknodes.c; sourceTree = "<group>"; };
+ FD6061161B7D2C8C004BCA6A /* mksyntax.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mksyntax.c; sourceTree = "<group>"; };
+ FD6061171B7D2C8C004BCA6A /* mktokens */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = mktokens; sourceTree = "<group>"; };
+ FD6061181B7D2C8C004BCA6A /* myhistedit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = myhistedit.h; sourceTree = "<group>"; };
+ FD6061191B7D2C8C004BCA6A /* mystring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mystring.h; sourceTree = "<group>"; };
+ FD60611A1B7D2C8C004BCA6A /* nodes.c.pat */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = nodes.c.pat; sourceTree = "<group>"; };
+ FD60611B1B7D2C8C004BCA6A /* nodetypes */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = nodetypes; sourceTree = "<group>"; };
+ FD60611C1B7D2C8C004BCA6A /* options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = options.h; sourceTree = "<group>"; };
+ FD60611D1B7D2C8C004BCA6A /* output.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = output.h; sourceTree = "<group>"; };
+ FD60611E1B7D2C8C004BCA6A /* parser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = parser.h; sourceTree = "<group>"; };
+ FD60611F1B7D2C8C004BCA6A /* redir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = redir.h; sourceTree = "<group>"; };
+ FD6061201B7D2C8C004BCA6A /* sh.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = sh.1; sourceTree = "<group>"; };
+ FD6061211B7D2C8C004BCA6A /* shell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = shell.h; sourceTree = "<group>"; };
+ FD6061221B7D2C8C004BCA6A /* show.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = show.h; sourceTree = "<group>"; };
+ FD6061231B7D2C8C004BCA6A /* trap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = trap.h; sourceTree = "<group>"; };
+ FD6061241B7D2C8C004BCA6A /* var.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = var.h; sourceTree = "<group>"; };
+ FD6061281B7D2D1D004BCA6A /* cmv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = cmv; sourceTree = "<group>"; };
+ FD6061291B7D2D1D004BCA6A /* dirs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = dirs; sourceTree = "<group>"; };
+ FD60612A1B7D2D1D004BCA6A /* login */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = login; sourceTree = "<group>"; };
+ FD60612B1B7D2D1D004BCA6A /* newgrp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = newgrp; sourceTree = "<group>"; };
+ FD60612C1B7D2D1D004BCA6A /* popd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = popd; sourceTree = "<group>"; };
+ FD60612D1B7D2D1D004BCA6A /* pushd */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = pushd; sourceTree = "<group>"; };
+ FD60612E1B7D2D1D004BCA6A /* suspend */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = suspend; sourceTree = "<group>"; };
+ FD6061301B7D2DDE004BCA6A /* base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
+ FD6061311B7D2DDE004BCA6A /* sh.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = sh.xcconfig; sourceTree = "<group>"; };
+ FD88EB01198C5257006B7EFD /* envopts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = envopts.c; sourceTree = "<group>"; };
+ FD88EB02198C5257006B7EFD /* envopts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = envopts.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ C6868573154725700025D623 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC5D638514B9819E00123E48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC5D639214B9822D00123E48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA149A14A141FF00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14B014A1422D00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14B914A1423E00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14C114A1426800AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14C914A1428000AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14D114A1433F00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14D914A1434A00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA151014A1453A00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA151814A1454D00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA152014A1455600AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA152814A1455900AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA153014A1455C00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA153814A1455F00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA154014A1456100AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA154814A1456400AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA155014A1456700AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA155814A1456A00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA156014A1456E00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA156814A1457100AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA157814A1457B00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA158014A1457F00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA158814A1458500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA159014A1458800AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA159814A1458C00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15A014A1459000AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15A814A1459500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15B014A1459700AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15B814A1459900AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15C014A1459E00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15C814A145A200AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15D014A145A500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15D814A145A700AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCED3AF614B4FC1800C313C3 /* libpam.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15E014A145A900AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15E814A145AE00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15F014A145B000AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15F814A145B200AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA160014A145B500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA160814A145B800AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA161014A145BA00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA161814A145BC00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA162014A145C000AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA162814A145C500AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA163014A145C700AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA163814A145CA00AA698B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCE30EC614B5368A00CC0294 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCE30ED914B536C900CC0294 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD6060AF1B7C0388004BCA6A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ C6868578154725700025D623 /* systime */ = {
+ isa = PBXGroup;
+ children = (
+ C6868579154725700025D623 /* systime.c */,
+ C686857B154725700025D623 /* systime.1 */,
+ );
+ path = systime;
+ sourceTree = "<group>";
+ };
+ CE799E5F24AD3B1B00E73238 /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ CE799E6024AD3B1B00E73238 /* test_time.sh */,
+ );
+ path = tests;
+ sourceTree = "<group>";
+ };
+ CE799E6124B3982200E73238 /* xcodescripts */ = {
+ isa = PBXGroup;
+ children = (
+ CE799E6224B3982200E73238 /* install-files.sh */,
+ CE799E6324B3982200E73238 /* builtins.txt */,
+ CE799E6424B3982200E73238 /* builtins-manpages.txt */,
+ );
+ path = xcodescripts;
+ sourceTree = "<group>";
+ };
+ FC5D636714B9808E00123E48 /* hexdump */ = {
+ isa = PBXGroup;
+ children = (
+ FC5D636814B9808E00123E48 /* conv.c */,
+ FC5D636914B9808E00123E48 /* display.c */,
+ FC5D636A14B9808E00123E48 /* hexdump.1 */,
+ FC5D636B14B9808E00123E48 /* hexdump.c */,
+ FC5D636C14B9808E00123E48 /* hexdump.h */,
+ FC5D636D14B9808E00123E48 /* hexsyntax.c */,
+ FC5D636E14B9808E00123E48 /* od.1 */,
+ FC5D636F14B9808E00123E48 /* odsyntax.c */,
+ FC5D637014B9808E00123E48 /* parse.c */,
+ );
+ path = hexdump;
+ sourceTree = "<group>";
+ };
+ FC5D637114B9808E00123E48 /* what */ = {
+ isa = PBXGroup;
+ children = (
+ FC5D637214B9808E00123E48 /* what.1 */,
+ FC5D637314B9808E00123E48 /* what.c */,
+ );
+ path = what;
+ sourceTree = "<group>";
+ };
+ FC80BF5514A05A2F00C6F7F5 = {
+ isa = PBXGroup;
+ children = (
+ CE799E6124B3982200E73238 /* xcodescripts */,
+ FD60612F1B7D2DDE004BCA6A /* xcconfigs */,
+ FCBA134014A141A300AA698B /* alias */,
+ FCBA134514A141A300AA698B /* apply */,
+ FCBA134914A141A300AA698B /* basename */,
+ FCBA134E14A141A300AA698B /* chroot */,
+ FCBA135214A141A300AA698B /* date */,
+ FCBA135A14A141A300AA698B /* dirname */,
+ FCBA135D14A141A300AA698B /* echo */,
+ FCBA136114A141A300AA698B /* env */,
+ FCBA136514A141A300AA698B /* expr */,
+ FCBA136914A141A300AA698B /* false */,
+ FCBA136E14A141A300AA698B /* find */,
+ FCBA137B14A141A300AA698B /* getopt */,
+ FC5D636714B9808E00123E48 /* hexdump */,
+ FCBA137F14A141A300AA698B /* hostname */,
+ FCBA138314A141A300AA698B /* id */,
+ FCBA138B14A141A300AA698B /* jot */,
+ FCBA138F14A141A300AA698B /* kill */,
+ FCBA139314A141A300AA698B /* killall */,
+ FCBA139714A141A300AA698B /* lastcomm */,
+ FCBA139C14A141A300AA698B /* locate */,
+ FCBA13B314A141A300AA698B /* logname */,
+ FCBA13BE14A141A300AA698B /* mktemp */,
+ FCBA13C214A141A300AA698B /* nice */,
+ FCBA13C614A141A300AA698B /* nohup */,
+ FCBA13CA14A141A300AA698B /* path_helper */,
+ FCBA13CE14A141A300AA698B /* printenv */,
+ FCBA13D214A141A300AA698B /* printf */,
+ FCBA13D614A141A300AA698B /* pwd */,
+ FCBA13DA14A141A300AA698B /* renice */,
+ FCBA13DE14A141A300AA698B /* script */,
+ FCBA13E214A141A300AA698B /* seq */,
+ FD6060B31B7C0388004BCA6A /* sh */,
+ FCBA13E614A141A300AA698B /* shlock */,
+ FCBA13EA14A141A300AA698B /* sleep */,
+ FCBA13EE14A141A300AA698B /* su */,
+ C6868578154725700025D623 /* systime */,
+ FCBA13F314A141A300AA698B /* tee */,
+ FCBA13F714A141A300AA698B /* test */,
+ FCBA13FD14A141A300AA698B /* time */,
+ FCBA140114A141A300AA698B /* true */,
+ FCBA140614A141A300AA698B /* uname */,
+ FCBA140A14A141A300AA698B /* users */,
+ FCBA140E14A141A300AA698B /* w */,
+ FC5D637114B9808E00123E48 /* what */,
+ FCBA141714A141A300AA698B /* whereis */,
+ FCBA141B14A141A300AA698B /* which */,
+ FCBA141F14A141A300AA698B /* who */,
+ FCBA142514A141A300AA698B /* xargs */,
+ FCBA142B14A141A300AA698B /* yes */,
+ FC80BF6114A05A2F00C6F7F5 /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ FC80BF6114A05A2F00C6F7F5 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA149E14A141FF00AA698B /* apply */,
+ FCBA14B414A1422D00AA698B /* basename */,
+ FCBA14BD14A1423E00AA698B /* chroot */,
+ FCBA14C514A1426800AA698B /* date */,
+ FCBA14CD14A1428000AA698B /* dirname */,
+ FCBA14D514A1433F00AA698B /* echo */,
+ FCBA14DD14A1434A00AA698B /* env */,
+ FCBA151414A1453A00AA698B /* expr */,
+ FCBA151C14A1454D00AA698B /* false */,
+ FCBA152414A1455600AA698B /* find */,
+ FCBA152C14A1455900AA698B /* getopt */,
+ FCBA153414A1455C00AA698B /* hostname */,
+ FCBA153C14A1455F00AA698B /* id */,
+ FCBA154414A1456100AA698B /* jot */,
+ FCBA154C14A1456400AA698B /* kill */,
+ FCBA155414A1456700AA698B /* killall */,
+ FCBA155C14A1456A00AA698B /* lastcomm */,
+ FCBA156414A1456E00AA698B /* locate */,
+ FCBA156C14A1457100AA698B /* logname */,
+ FCBA157C14A1457B00AA698B /* mktemp */,
+ FCBA158414A1457F00AA698B /* nice */,
+ FCBA158C14A1458500AA698B /* nohup */,
+ FCBA159414A1458800AA698B /* path_helper */,
+ FCBA159C14A1458C00AA698B /* printenv */,
+ FCBA15A414A1459000AA698B /* printf */,
+ FCBA15AC14A1459500AA698B /* pwd */,
+ FCBA15B414A1459700AA698B /* renice */,
+ FCBA15BC14A1459900AA698B /* script */,
+ FCBA15C414A1459E00AA698B /* seq */,
+ FD6060B21B7C0388004BCA6A /* ash */,
+ FCBA15CC14A145A200AA698B /* shlock */,
+ FCBA15D414A145A500AA698B /* sleep */,
+ FCBA15DC14A145A700AA698B /* su */,
+ FCBA15E414A145A900AA698B /* tee */,
+ FCBA15EC14A145AE00AA698B /* test */,
+ FCBA15F414A145B000AA698B /* time */,
+ FCBA15FC14A145B200AA698B /* true */,
+ FCBA160414A145B500AA698B /* uname */,
+ FCBA160C14A145B800AA698B /* users */,
+ FCBA161414A145BA00AA698B /* w */,
+ FCBA161C14A145BC00AA698B /* whereis */,
+ FCBA162414A145C000AA698B /* which */,
+ FCBA162C14A145C500AA698B /* who */,
+ FCBA163414A145C700AA698B /* xargs */,
+ FCBA163C14A145CA00AA698B /* yes */,
+ FCE30ED214B5368A00CC0294 /* locate.bigram */,
+ FCE30EDE14B536C900CC0294 /* locate.code */,
+ FC5D638B14B9819E00123E48 /* what */,
+ FC5D639714B9822D00123E48 /* hexdump */,
+ C6868576154725700025D623 /* systime */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FCBA134014A141A300AA698B /* alias */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA134114A141A300AA698B /* alias.1 */,
+ FCBA134314A141A300AA698B /* generic.sh */,
+ );
+ path = alias;
+ sourceTree = "<group>";
+ };
+ FCBA134514A141A300AA698B /* apply */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA134614A141A300AA698B /* apply.1 */,
+ FCBA134714A141A300AA698B /* apply.c */,
+ );
+ path = apply;
+ sourceTree = "<group>";
+ };
+ FCBA134914A141A300AA698B /* basename */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA134A14A141A300AA698B /* basename.1 */,
+ FCBA134B14A141A300AA698B /* basename.c */,
+ );
+ path = basename;
+ sourceTree = "<group>";
+ };
+ FCBA134E14A141A300AA698B /* chroot */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA134F14A141A300AA698B /* chroot.8 */,
+ FCBA135014A141A300AA698B /* chroot.c */,
+ );
+ path = chroot;
+ sourceTree = "<group>";
+ };
+ FCBA135214A141A300AA698B /* date */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA135314A141A300AA698B /* date.1 */,
+ FCBA135414A141A300AA698B /* date.c */,
+ FCBA135514A141A300AA698B /* extern.h */,
+ FCBA135714A141A300AA698B /* netdate.c */,
+ FCBA135814A141A300AA698B /* vary.c */,
+ FCBA135914A141A300AA698B /* vary.h */,
+ );
+ path = date;
+ sourceTree = "<group>";
+ };
+ FCBA135A14A141A300AA698B /* dirname */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA135B14A141A300AA698B /* dirname.c */,
+ FCBA134C14A141A300AA698B /* dirname.1 */,
+ );
+ path = dirname;
+ sourceTree = "<group>";
+ };
+ FCBA135D14A141A300AA698B /* echo */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA135E14A141A300AA698B /* echo.1 */,
+ FCBA135F14A141A300AA698B /* echo.c */,
+ );
+ path = echo;
+ sourceTree = "<group>";
+ };
+ FCBA136114A141A300AA698B /* env */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA136214A141A300AA698B /* env.1 */,
+ FCBA136314A141A300AA698B /* env.c */,
+ FD88EB01198C5257006B7EFD /* envopts.c */,
+ FD88EB02198C5257006B7EFD /* envopts.h */,
+ );
+ path = env;
+ sourceTree = "<group>";
+ };
+ FCBA136514A141A300AA698B /* expr */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA136614A141A300AA698B /* expr.1 */,
+ FCBA136714A141A300AA698B /* expr.y */,
+ );
+ path = expr;
+ sourceTree = "<group>";
+ };
+ FCBA136914A141A300AA698B /* false */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA136A14A141A300AA698B /* false.1 */,
+ FCBA136B14A141A300AA698B /* false.c */,
+ );
+ path = false;
+ sourceTree = "<group>";
+ };
+ FCBA136E14A141A300AA698B /* find */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA136F14A141A300AA698B /* extern.h */,
+ FCBA137014A141A300AA698B /* find.1 */,
+ FCBA137114A141A300AA698B /* find.c */,
+ FCBA137214A141A300AA698B /* find.h */,
+ FCBA137314A141A300AA698B /* function.c */,
+ FCBA137414A141A300AA698B /* getdate.y */,
+ FCBA137514A141A300AA698B /* ls.c */,
+ FCBA137614A141A300AA698B /* main.c */,
+ FCBA137814A141A300AA698B /* misc.c */,
+ FCBA137914A141A300AA698B /* operator.c */,
+ FCBA137A14A141A300AA698B /* option.c */,
+ );
+ path = find;
+ sourceTree = "<group>";
+ };
+ FCBA137B14A141A300AA698B /* getopt */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA137C14A141A300AA698B /* getopt.1 */,
+ FCBA137D14A141A300AA698B /* getopt.c */,
+ );
+ path = getopt;
+ sourceTree = "<group>";
+ };
+ FCBA137F14A141A300AA698B /* hostname */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA138014A141A300AA698B /* hostname.1 */,
+ FCBA138114A141A300AA698B /* hostname.c */,
+ );
+ path = hostname;
+ sourceTree = "<group>";
+ };
+ FCBA138314A141A300AA698B /* id */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA138414A141A300AA698B /* groups.1 */,
+ FCBA138514A141A300AA698B /* id.1 */,
+ FCBA138614A141A300AA698B /* id.c */,
+ FCBA138A14A141A300AA698B /* whoami.1 */,
+ );
+ path = id;
+ sourceTree = "<group>";
+ };
+ FCBA138B14A141A300AA698B /* jot */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA138C14A141A300AA698B /* jot.1 */,
+ FCBA138D14A141A300AA698B /* jot.c */,
+ );
+ path = jot;
+ sourceTree = "<group>";
+ };
+ FCBA138F14A141A300AA698B /* kill */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA139014A141A300AA698B /* kill.1 */,
+ FCBA139114A141A300AA698B /* kill.c */,
+ );
+ path = kill;
+ sourceTree = "<group>";
+ };
+ FCBA139314A141A300AA698B /* killall */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA139414A141A300AA698B /* killall.1 */,
+ FCBA139514A141A300AA698B /* killall.c */,
+ );
+ path = killall;
+ sourceTree = "<group>";
+ };
+ FCBA139714A141A300AA698B /* lastcomm */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA139814A141A300AA698B /* lastcomm.1 */,
+ FCBA139914A141A300AA698B /* lastcomm.c */,
+ FCBA139B14A141A300AA698B /* pathnames.h */,
+ );
+ path = lastcomm;
+ sourceTree = "<group>";
+ };
+ FCBA139C14A141A300AA698B /* locate */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA139D14A141A300AA698B /* bigram */,
+ FCBA13A014A141A300AA698B /* code */,
+ FCBA13A314A141A300AA698B /* locate */,
+ );
+ path = locate;
+ sourceTree = "<group>";
+ };
+ FCBA139D14A141A300AA698B /* bigram */ = {
+ isa = PBXGroup;
+ children = (
+ FCE30EC114B5347A00CC0294 /* locate.bigram.8 */,
+ FCBA139E14A141A300AA698B /* locate.bigram.c */,
+ );
+ path = bigram;
+ sourceTree = "<group>";
+ };
+ FCBA13A014A141A300AA698B /* code */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13B114A141A300AA698B /* locate.code.8 */,
+ FCBA13A114A141A300AA698B /* locate.code.c */,
+ );
+ path = code;
+ sourceTree = "<group>";
+ };
+ FCBA13A314A141A300AA698B /* locate */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13A414A141A300AA698B /* com.apple.locate.plist */,
+ FCBA13A514A141A300AA698B /* concatdb.sh */,
+ FCBA13A714A141A300AA698B /* locate.1 */,
+ FCBA13A814A141A300AA698B /* locate.c */,
+ FCBA13A914A141A300AA698B /* locate.h */,
+ FCBA13AA14A141A300AA698B /* locate.rc */,
+ FCBA13AB14A141A300AA698B /* locate.updatedb.8 */,
+ FCBA13AD14A141A300AA698B /* mklocatedb.sh */,
+ FCBA13AE14A141A300AA698B /* pathnames.h */,
+ FCBA13AF14A141A300AA698B /* updatedb.sh */,
+ FCBA13B014A141A300AA698B /* util.c */,
+ );
+ path = locate;
+ sourceTree = "<group>";
+ };
+ FCBA13B314A141A300AA698B /* logname */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13B414A141A300AA698B /* logname.1 */,
+ FCBA13B514A141A300AA698B /* logname.c */,
+ );
+ path = logname;
+ sourceTree = "<group>";
+ };
+ FCBA13BE14A141A300AA698B /* mktemp */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13C014A141A300AA698B /* mktemp.1 */,
+ FCBA13C114A141A300AA698B /* mktemp.c */,
+ );
+ path = mktemp;
+ sourceTree = "<group>";
+ };
+ FCBA13C214A141A300AA698B /* nice */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13C414A141A300AA698B /* nice.1 */,
+ FCBA13C514A141A300AA698B /* nice.c */,
+ );
+ path = nice;
+ sourceTree = "<group>";
+ };
+ FCBA13C614A141A300AA698B /* nohup */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13C814A141A300AA698B /* nohup.1 */,
+ FCBA13C914A141A300AA698B /* nohup.c */,
+ );
+ path = nohup;
+ sourceTree = "<group>";
+ };
+ FCBA13CA14A141A300AA698B /* path_helper */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13CC14A141A300AA698B /* path_helper.8 */,
+ FCBA13CD14A141A300AA698B /* path_helper.c */,
+ );
+ path = path_helper;
+ sourceTree = "<group>";
+ };
+ FCBA13CE14A141A300AA698B /* printenv */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13D014A141A300AA698B /* printenv.1 */,
+ FCBA13D114A141A300AA698B /* printenv.c */,
+ );
+ path = printenv;
+ sourceTree = "<group>";
+ };
+ FCBA13D214A141A300AA698B /* printf */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13D414A141A300AA698B /* printf.1 */,
+ FCBA13D514A141A300AA698B /* printf.c */,
+ FD155C761D6E3847005A53CA /* tests */,
+ );
+ path = printf;
+ sourceTree = "<group>";
+ };
+ FCBA13D614A141A300AA698B /* pwd */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13D814A141A300AA698B /* pwd.1 */,
+ FCBA13D914A141A300AA698B /* pwd.c */,
+ );
+ path = pwd;
+ sourceTree = "<group>";
+ };
+ FCBA13DA14A141A300AA698B /* renice */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13DC14A141A300AA698B /* renice.8 */,
+ FCBA13DD14A141A300AA698B /* renice.c */,
+ );
+ path = renice;
+ sourceTree = "<group>";
+ };
+ FCBA13DE14A141A300AA698B /* script */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13E014A141A300AA698B /* script.1 */,
+ FCBA13E114A141A300AA698B /* script.c */,
+ );
+ path = script;
+ sourceTree = "<group>";
+ };
+ FCBA13E214A141A300AA698B /* seq */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13E414A141A300AA698B /* seq.1 */,
+ FCBA13E514A141A300AA698B /* seq.c */,
+ );
+ path = seq;
+ sourceTree = "<group>";
+ };
+ FCBA13E614A141A300AA698B /* shlock */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13E814A141A300AA698B /* shlock.1 */,
+ FCBA13E914A141A300AA698B /* shlock.c */,
+ );
+ path = shlock;
+ sourceTree = "<group>";
+ };
+ FCBA13EA14A141A300AA698B /* sleep */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13EC14A141A300AA698B /* sleep.1 */,
+ FCBA13ED14A141A300AA698B /* sleep.c */,
+ );
+ path = sleep;
+ sourceTree = "<group>";
+ };
+ FCBA13EE14A141A300AA698B /* su */ = {
+ isa = PBXGroup;
+ children = (
+ 6C1C283E22FB822900E0AC67 /* su_entitlements.plist */,
+ FCBA13F014A141A300AA698B /* su.1 */,
+ FCBA13F114A141A300AA698B /* su.c */,
+ FCBA13F214A141A300AA698B /* su.pam */,
+ FCED3AF514B4FC1800C313C3 /* libpam.dylib */,
+ );
+ path = su;
+ sourceTree = "<group>";
+ };
+ FCBA13F314A141A300AA698B /* tee */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13F514A141A300AA698B /* tee.1 */,
+ FCBA13F614A141A300AA698B /* tee.c */,
+ );
+ path = tee;
+ sourceTree = "<group>";
+ };
+ FCBA13F714A141A300AA698B /* test */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA13F814A141A300AA698B /* [.1 */,
+ FCBA13FA14A141A300AA698B /* test.1 */,
+ FCBA13FB14A141A300AA698B /* test.c */,
+ FD155C711D6E37B5005A53CA /* tests */,
+ );
+ path = test;
+ sourceTree = "<group>";
+ };
+ FCBA13FD14A141A300AA698B /* time */ = {
+ isa = PBXGroup;
+ children = (
+ CE799E5F24AD3B1B00E73238 /* tests */,
+ FCBA13FF14A141A300AA698B /* time.1 */,
+ FCBA140014A141A300AA698B /* time.c */,
+ );
+ path = time;
+ sourceTree = "<group>";
+ };
+ FCBA140114A141A300AA698B /* true */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA140314A141A300AA698B /* true.1 */,
+ FCBA140414A141A300AA698B /* true.c */,
+ );
+ path = true;
+ sourceTree = "<group>";
+ };
+ FCBA140614A141A300AA698B /* uname */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA140814A141A300AA698B /* uname.1 */,
+ FCBA140914A141A300AA698B /* uname.c */,
+ );
+ path = uname;
+ sourceTree = "<group>";
+ };
+ FCBA140A14A141A300AA698B /* users */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA140C14A141A300AA698B /* users.1 */,
+ FCBA140D14A141A300AA698B /* users.c */,
+ );
+ path = users;
+ sourceTree = "<group>";
+ };
+ FCBA140E14A141A300AA698B /* w */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA140F14A141A300AA698B /* extern.h */,
+ FCBA141014A141A300AA698B /* fmt.c */,
+ FCBA141214A141A300AA698B /* pr_time.c */,
+ FCBA141314A141A300AA698B /* proc_compare.c */,
+ FCBA141414A141A300AA698B /* uptime.1 */,
+ FCBA141514A141A300AA698B /* w.1 */,
+ FCBA141614A141A300AA698B /* w.c */,
+ );
+ path = w;
+ sourceTree = "<group>";
+ };
+ FCBA141714A141A300AA698B /* whereis */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA141914A141A300AA698B /* whereis.1 */,
+ FCBA141A14A141A300AA698B /* whereis.c */,
+ );
+ path = whereis;
+ sourceTree = "<group>";
+ };
+ FCBA141B14A141A300AA698B /* which */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA141D14A141A300AA698B /* which.1 */,
+ FCBA141E14A141A300AA698B /* which.c */,
+ );
+ path = which;
+ sourceTree = "<group>";
+ };
+ FCBA141F14A141A300AA698B /* who */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA142114A141A300AA698B /* utmpentry.c */,
+ FCBA142214A141A300AA698B /* utmpentry.h */,
+ FCBA142314A141A300AA698B /* who.1 */,
+ FCBA142414A141A300AA698B /* who.c */,
+ FCBA02E514B505A50030BEB3 /* libresolv.dylib */,
+ );
+ path = who;
+ sourceTree = "<group>";
+ };
+ FCBA142514A141A300AA698B /* xargs */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA142714A141A300AA698B /* pathnames.h */,
+ FCBA142814A141A300AA698B /* strnsubst.c */,
+ FCBA142914A141A300AA698B /* xargs.1 */,
+ FCBA142A14A141A300AA698B /* xargs.c */,
+ );
+ path = xargs;
+ sourceTree = "<group>";
+ };
+ FCBA142B14A141A300AA698B /* yes */ = {
+ isa = PBXGroup;
+ children = (
+ FCBA142D14A141A300AA698B /* yes.1 */,
+ FCBA142E14A141A300AA698B /* yes.c */,
+ );
+ path = yes;
+ sourceTree = "<group>";
+ };
+ FD155C711D6E37B5005A53CA /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ FD155C721D6E37B5005A53CA /* legacy_test.sh */,
+ );
+ path = tests;
+ sourceTree = "<group>";
+ };
+ FD155C761D6E3847005A53CA /* tests */ = {
+ isa = PBXGroup;
+ children = (
+ FD155C771D6E3847005A53CA /* legacy_test.sh */,
+ FD155C7A1D6E3847005A53CA /* regress.b.out */,
+ FD155C7B1D6E3847005A53CA /* regress.d.out */,
+ FD155C7C1D6E3847005A53CA /* regress.f.out */,
+ FD155C7D1D6E3847005A53CA /* regress.l1.out */,
+ FD155C7E1D6E3847005A53CA /* regress.l2.out */,
+ FD155C7F1D6E3847005A53CA /* regress.m1.out */,
+ FD155C801D6E3847005A53CA /* regress.m2.out */,
+ FD155C811D6E3847005A53CA /* regress.m3.out */,
+ FD155C821D6E3847005A53CA /* regress.m4.out */,
+ FD155C831D6E3847005A53CA /* regress.m5.out */,
+ FD155C841D6E3847005A53CA /* regress.missingpos1.out */,
+ FD155C851D6E3847005A53CA /* regress.s.out */,
+ FD155C861D6E3847005A53CA /* regress.sh */,
+ FD155C871D6E3847005A53CA /* regress.zero.out */,
+ );
+ path = tests;
+ sourceTree = "<group>";
+ };
+ FD6060B31B7C0388004BCA6A /* sh */ = {
+ isa = PBXGroup;
+ children = (
+ FD6061001B7C0D01004BCA6A /* BUILT */,
+ FD6060BC1B7C0471004BCA6A /* alias.c */,
+ FD6061061B7D2C8C004BCA6A /* alias.h */,
+ FD6061081B7D2C8C004BCA6A /* arith.h */,
+ FD6060BD1B7C0471004BCA6A /* arith_yacc.c */,
+ FD6061071B7D2C8C004BCA6A /* arith_yacc.h */,
+ FD6060BE1B7C0471004BCA6A /* arith_yylex.c */,
+ FD6060E81B7C04E4004BCA6A /* bltin */,
+ FD6061091B7D2C8C004BCA6A /* builtins.def */,
+ FD6060BF1B7C0471004BCA6A /* cd.c */,
+ FD60610A1B7D2C8C004BCA6A /* cd.h */,
+ FD6060C01B7C0471004BCA6A /* error.c */,
+ FD60610B1B7D2C8C004BCA6A /* error.h */,
+ FD6060C11B7C0471004BCA6A /* eval.c */,
+ FD60610C1B7D2C8C004BCA6A /* eval.h */,
+ FD6060C21B7C0471004BCA6A /* exec.c */,
+ FD60610D1B7D2C8C004BCA6A /* exec.h */,
+ FD6060C31B7C0471004BCA6A /* expand.c */,
+ FD60610E1B7D2C8C004BCA6A /* expand.h */,
+ FD6061271B7D2D1D004BCA6A /* funcs */,
+ FD6060C41B7C0471004BCA6A /* histedit.c */,
+ FD6060C51B7C0471004BCA6A /* input.c */,
+ FD60610F1B7D2C8C004BCA6A /* input.h */,
+ FD6060C61B7C0471004BCA6A /* jobs.c */,
+ FD6061101B7D2C8C004BCA6A /* jobs.h */,
+ FD6060C71B7C0471004BCA6A /* mail.c */,
+ FD6061111B7D2C8C004BCA6A /* mail.h */,
+ FD6060B41B7C0388004BCA6A /* main.c */,
+ FD6061121B7D2C8C004BCA6A /* main.h */,
+ FD6060C81B7C0471004BCA6A /* memalloc.c */,
+ FD6061131B7D2C8C004BCA6A /* memalloc.h */,
+ FD6060C91B7C0471004BCA6A /* miscbltin.c */,
+ FD6061141B7D2C8C004BCA6A /* mkbuiltins */,
+ FD6061151B7D2C8C004BCA6A /* mknodes.c */,
+ FD6061161B7D2C8C004BCA6A /* mksyntax.c */,
+ FD6061171B7D2C8C004BCA6A /* mktokens */,
+ FD6061181B7D2C8C004BCA6A /* myhistedit.h */,
+ FD6060CA1B7C0471004BCA6A /* mystring.c */,
+ FD6061191B7D2C8C004BCA6A /* mystring.h */,
+ FD60611A1B7D2C8C004BCA6A /* nodes.c.pat */,
+ FD60611B1B7D2C8C004BCA6A /* nodetypes */,
+ FD6060CB1B7C0471004BCA6A /* options.c */,
+ FD60611C1B7D2C8C004BCA6A /* options.h */,
+ FD6060CC1B7C0471004BCA6A /* output.c */,
+ FD60611D1B7D2C8C004BCA6A /* output.h */,
+ FD6060CD1B7C0471004BCA6A /* parser.c */,
+ FD60611E1B7D2C8C004BCA6A /* parser.h */,
+ FD6060CE1B7C0471004BCA6A /* redir.c */,
+ FD60611F1B7D2C8C004BCA6A /* redir.h */,
+ FD6061201B7D2C8C004BCA6A /* sh.1 */,
+ FD6061211B7D2C8C004BCA6A /* shell.h */,
+ FD6060CF1B7C0471004BCA6A /* show.c */,
+ FD6061221B7D2C8C004BCA6A /* show.h */,
+ FD6060D01B7C0471004BCA6A /* trap.c */,
+ FD6061231B7D2C8C004BCA6A /* trap.h */,
+ FD6060D11B7C0471004BCA6A /* var.c */,
+ FD6061241B7D2C8C004BCA6A /* var.h */,
+ );
+ path = sh;
+ sourceTree = "<group>";
+ };
+ FD6060E81B7C04E4004BCA6A /* bltin */ = {
+ isa = PBXGroup;
+ children = (
+ FD6061051B7D2BF8004BCA6A /* bltin.h */,
+ FD6060EA1B7C04E4004BCA6A /* echo.c */,
+ );
+ path = bltin;
+ sourceTree = "<group>";
+ };
+ FD6061001B7C0D01004BCA6A /* BUILT */ = {
+ isa = PBXGroup;
+ children = (
+ FD6060FA1B7C0CAF004BCA6A /* builtins.c */,
+ FD6061011B7D2B6D004BCA6A /* builtins.h */,
+ FD6060FB1B7C0CAF004BCA6A /* nodes.c */,
+ FD6061021B7D2B6D004BCA6A /* nodes.h */,
+ FD6060FC1B7C0CAF004BCA6A /* syntax.c */,
+ FD6061031B7D2B6D004BCA6A /* syntax.h */,
+ FD6061041B7D2B6D004BCA6A /* token.h */,
+ );
+ name = BUILT;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+ FD6061271B7D2D1D004BCA6A /* funcs */ = {
+ isa = PBXGroup;
+ children = (
+ FD6061281B7D2D1D004BCA6A /* cmv */,
+ FD6061291B7D2D1D004BCA6A /* dirs */,
+ FD60612A1B7D2D1D004BCA6A /* login */,
+ FD60612B1B7D2D1D004BCA6A /* newgrp */,
+ FD60612C1B7D2D1D004BCA6A /* popd */,
+ FD60612D1B7D2D1D004BCA6A /* pushd */,
+ FD60612E1B7D2D1D004BCA6A /* suspend */,
+ );
+ path = funcs;
+ sourceTree = "<group>";
+ };
+ FD60612F1B7D2DDE004BCA6A /* xcconfigs */ = {
+ isa = PBXGroup;
+ children = (
+ FD6061301B7D2DDE004BCA6A /* base.xcconfig */,
+ FD6061311B7D2DDE004BCA6A /* sh.xcconfig */,
+ );
+ path = xcconfigs;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ C6868575154725700025D623 /* systime */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C686857E154725700025D623 /* Build configuration list for PBXNativeTarget "systime" */;
+ buildPhases = (
+ C6868572154725700025D623 /* Sources */,
+ C6868573154725700025D623 /* Frameworks */,
+ C6868574154725700025D623 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = systime;
+ productName = systime;
+ productReference = C6868576154725700025D623 /* systime */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC5D637F14B9819E00123E48 /* what */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC5D638914B9819E00123E48 /* Build configuration list for PBXNativeTarget "what" */;
+ buildPhases = (
+ FC5D638014B9819E00123E48 /* Sources */,
+ FC5D638514B9819E00123E48 /* Frameworks */,
+ FC5D638614B9819E00123E48 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = what;
+ productName = shell_cmds;
+ productReference = FC5D638B14B9819E00123E48 /* what */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC5D638F14B9822D00123E48 /* hexdump */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC5D639514B9822D00123E48 /* Build configuration list for PBXNativeTarget "hexdump" */;
+ buildPhases = (
+ FC5D639014B9822D00123E48 /* Sources */,
+ FC5D639214B9822D00123E48 /* Frameworks */,
+ FC5D639314B9822D00123E48 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = hexdump;
+ productName = shell_cmds;
+ productReference = FC5D639714B9822D00123E48 /* hexdump */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA149814A141FF00AA698B /* apply */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA149C14A141FF00AA698B /* Build configuration list for PBXNativeTarget "apply" */;
+ buildPhases = (
+ FCBA149914A141FF00AA698B /* Sources */,
+ FCBA149A14A141FF00AA698B /* Frameworks */,
+ FCBA149B14A141FF00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = apply;
+ productName = shell_cmds;
+ productReference = FCBA149E14A141FF00AA698B /* apply */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14AE14A1422D00AA698B /* basename */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14B214A1422D00AA698B /* Build configuration list for PBXNativeTarget "basename" */;
+ buildPhases = (
+ FCBA14AF14A1422D00AA698B /* Sources */,
+ FCBA14B014A1422D00AA698B /* Frameworks */,
+ FCBA14B114A1422D00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = basename;
+ productName = shell_cmds;
+ productReference = FCBA14B414A1422D00AA698B /* basename */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14B714A1423E00AA698B /* chroot */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14BB14A1423E00AA698B /* Build configuration list for PBXNativeTarget "chroot" */;
+ buildPhases = (
+ FCBA14B814A1423E00AA698B /* Sources */,
+ FCBA14B914A1423E00AA698B /* Frameworks */,
+ FCBA14BA14A1423E00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chroot;
+ productName = shell_cmds;
+ productReference = FCBA14BD14A1423E00AA698B /* chroot */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14BF14A1426800AA698B /* date */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14C314A1426800AA698B /* Build configuration list for PBXNativeTarget "date" */;
+ buildPhases = (
+ FCBA14C014A1426800AA698B /* Sources */,
+ FCBA14C114A1426800AA698B /* Frameworks */,
+ FCBA14C214A1426800AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = date;
+ productName = shell_cmds;
+ productReference = FCBA14C514A1426800AA698B /* date */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14C714A1428000AA698B /* dirname */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14CB14A1428000AA698B /* Build configuration list for PBXNativeTarget "dirname" */;
+ buildPhases = (
+ FCBA14C814A1428000AA698B /* Sources */,
+ FCBA14C914A1428000AA698B /* Frameworks */,
+ FCBA14CA14A1428000AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dirname;
+ productName = shell_cmds;
+ productReference = FCBA14CD14A1428000AA698B /* dirname */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14CF14A1433F00AA698B /* echo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14D314A1433F00AA698B /* Build configuration list for PBXNativeTarget "echo" */;
+ buildPhases = (
+ FCBA14D014A1433F00AA698B /* Sources */,
+ FCBA14D114A1433F00AA698B /* Frameworks */,
+ FCBA14D214A1433F00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = echo;
+ productName = shell_cmds;
+ productReference = FCBA14D514A1433F00AA698B /* echo */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA14D714A1434A00AA698B /* env */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA14DB14A1434A00AA698B /* Build configuration list for PBXNativeTarget "env" */;
+ buildPhases = (
+ FCBA14D814A1434A00AA698B /* Sources */,
+ FCBA14D914A1434A00AA698B /* Frameworks */,
+ FCBA14DA14A1434A00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = env;
+ productName = shell_cmds;
+ productReference = FCBA14DD14A1434A00AA698B /* env */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA150E14A1453A00AA698B /* expr */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA151214A1453A00AA698B /* Build configuration list for PBXNativeTarget "expr" */;
+ buildPhases = (
+ FCBA150F14A1453A00AA698B /* Sources */,
+ FCBA151014A1453A00AA698B /* Frameworks */,
+ FCBA151114A1453A00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = expr;
+ productName = shell_cmds;
+ productReference = FCBA151414A1453A00AA698B /* expr */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA151614A1454D00AA698B /* false */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA151A14A1454D00AA698B /* Build configuration list for PBXNativeTarget "false" */;
+ buildPhases = (
+ FCBA151714A1454D00AA698B /* Sources */,
+ FCBA151814A1454D00AA698B /* Frameworks */,
+ FCBA151914A1454D00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = false;
+ productName = shell_cmds;
+ productReference = FCBA151C14A1454D00AA698B /* false */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA151E14A1455600AA698B /* find */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA152214A1455600AA698B /* Build configuration list for PBXNativeTarget "find" */;
+ buildPhases = (
+ FCBA151F14A1455600AA698B /* Sources */,
+ FCBA152014A1455600AA698B /* Frameworks */,
+ FCBA152114A1455600AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = find;
+ productName = shell_cmds;
+ productReference = FCBA152414A1455600AA698B /* find */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA152614A1455900AA698B /* getopt */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA152A14A1455900AA698B /* Build configuration list for PBXNativeTarget "getopt" */;
+ buildPhases = (
+ FCBA152714A1455900AA698B /* Sources */,
+ FCBA152814A1455900AA698B /* Frameworks */,
+ FCBA152914A1455900AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = getopt;
+ productName = shell_cmds;
+ productReference = FCBA152C14A1455900AA698B /* getopt */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA152E14A1455C00AA698B /* hostname */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA153214A1455C00AA698B /* Build configuration list for PBXNativeTarget "hostname" */;
+ buildPhases = (
+ FCBA152F14A1455C00AA698B /* Sources */,
+ FCBA153014A1455C00AA698B /* Frameworks */,
+ FCBA153114A1455C00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = hostname;
+ productName = shell_cmds;
+ productReference = FCBA153414A1455C00AA698B /* hostname */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA153614A1455F00AA698B /* id */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA153A14A1455F00AA698B /* Build configuration list for PBXNativeTarget "id" */;
+ buildPhases = (
+ FCBA153714A1455F00AA698B /* Sources */,
+ FCBA153814A1455F00AA698B /* Frameworks */,
+ FCBA153914A1455F00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = id;
+ productName = shell_cmds;
+ productReference = FCBA153C14A1455F00AA698B /* id */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA153E14A1456100AA698B /* jot */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA154214A1456100AA698B /* Build configuration list for PBXNativeTarget "jot" */;
+ buildPhases = (
+ FCBA153F14A1456100AA698B /* Sources */,
+ FCBA154014A1456100AA698B /* Frameworks */,
+ FCBA154114A1456100AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = jot;
+ productName = shell_cmds;
+ productReference = FCBA154414A1456100AA698B /* jot */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA154614A1456400AA698B /* kill */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA154A14A1456400AA698B /* Build configuration list for PBXNativeTarget "kill" */;
+ buildPhases = (
+ FCBA154714A1456400AA698B /* Sources */,
+ FCBA154814A1456400AA698B /* Frameworks */,
+ FCBA154914A1456400AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = kill;
+ productName = shell_cmds;
+ productReference = FCBA154C14A1456400AA698B /* kill */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA154E14A1456700AA698B /* killall */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA155214A1456700AA698B /* Build configuration list for PBXNativeTarget "killall" */;
+ buildPhases = (
+ FCBA154F14A1456700AA698B /* Sources */,
+ FCBA155014A1456700AA698B /* Frameworks */,
+ FCBA155114A1456700AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = killall;
+ productName = shell_cmds;
+ productReference = FCBA155414A1456700AA698B /* killall */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA155614A1456A00AA698B /* lastcomm */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA155A14A1456A00AA698B /* Build configuration list for PBXNativeTarget "lastcomm" */;
+ buildPhases = (
+ FCBA155714A1456A00AA698B /* Sources */,
+ FCBA155814A1456A00AA698B /* Frameworks */,
+ FCBA155914A1456A00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lastcomm;
+ productName = shell_cmds;
+ productReference = FCBA155C14A1456A00AA698B /* lastcomm */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA155E14A1456E00AA698B /* locate */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA156214A1456E00AA698B /* Build configuration list for PBXNativeTarget "locate" */;
+ buildPhases = (
+ FCBA155F14A1456E00AA698B /* Sources */,
+ FCBA156014A1456E00AA698B /* Frameworks */,
+ FCBA156114A1456E00AA698B /* CopyFiles */,
+ FCE30EBE14B533B500CC0294 /* CopyFiles */,
+ FCE30EB914B532C700CC0294 /* CopyFiles */,
+ FCE30EBC14B5339000CC0294 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = locate;
+ productName = shell_cmds;
+ productReference = FCBA156414A1456E00AA698B /* locate */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA156614A1457100AA698B /* logname */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA156A14A1457100AA698B /* Build configuration list for PBXNativeTarget "logname" */;
+ buildPhases = (
+ FCBA156714A1457100AA698B /* Sources */,
+ FCBA156814A1457100AA698B /* Frameworks */,
+ FCBA156914A1457100AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = logname;
+ productName = shell_cmds;
+ productReference = FCBA156C14A1457100AA698B /* logname */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA157614A1457B00AA698B /* mktemp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA157A14A1457B00AA698B /* Build configuration list for PBXNativeTarget "mktemp" */;
+ buildPhases = (
+ FCBA157714A1457B00AA698B /* Sources */,
+ FCBA157814A1457B00AA698B /* Frameworks */,
+ FCBA157914A1457B00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mktemp;
+ productName = shell_cmds;
+ productReference = FCBA157C14A1457B00AA698B /* mktemp */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA157E14A1457F00AA698B /* nice */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA158214A1457F00AA698B /* Build configuration list for PBXNativeTarget "nice" */;
+ buildPhases = (
+ FCBA157F14A1457F00AA698B /* Sources */,
+ FCBA158014A1457F00AA698B /* Frameworks */,
+ FCBA158114A1457F00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nice;
+ productName = shell_cmds;
+ productReference = FCBA158414A1457F00AA698B /* nice */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA158614A1458500AA698B /* nohup */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA158A14A1458500AA698B /* Build configuration list for PBXNativeTarget "nohup" */;
+ buildPhases = (
+ FCBA158714A1458500AA698B /* Sources */,
+ FCBA158814A1458500AA698B /* Frameworks */,
+ FCBA158914A1458500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nohup;
+ productName = shell_cmds;
+ productReference = FCBA158C14A1458500AA698B /* nohup */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA158E14A1458800AA698B /* path_helper */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA159214A1458800AA698B /* Build configuration list for PBXNativeTarget "path_helper" */;
+ buildPhases = (
+ FCBA158F14A1458800AA698B /* Sources */,
+ FCBA159014A1458800AA698B /* Frameworks */,
+ FCBA159114A1458800AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = path_helper;
+ productName = shell_cmds;
+ productReference = FCBA159414A1458800AA698B /* path_helper */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA159614A1458C00AA698B /* printenv */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA159A14A1458C00AA698B /* Build configuration list for PBXNativeTarget "printenv" */;
+ buildPhases = (
+ FCBA159714A1458C00AA698B /* Sources */,
+ FCBA159814A1458C00AA698B /* Frameworks */,
+ FCBA159914A1458C00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = printenv;
+ productName = shell_cmds;
+ productReference = FCBA159C14A1458C00AA698B /* printenv */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA159E14A1459000AA698B /* printf */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15A214A1459000AA698B /* Build configuration list for PBXNativeTarget "printf" */;
+ buildPhases = (
+ FCBA159F14A1459000AA698B /* Sources */,
+ FCBA15A014A1459000AA698B /* Frameworks */,
+ FCBA15A114A1459000AA698B /* CopyFiles */,
+ FD155C881D6E38AB005A53CA /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = printf;
+ productName = shell_cmds;
+ productReference = FCBA15A414A1459000AA698B /* printf */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15A614A1459500AA698B /* pwd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15AA14A1459500AA698B /* Build configuration list for PBXNativeTarget "pwd" */;
+ buildPhases = (
+ FCBA15A714A1459500AA698B /* Sources */,
+ FCBA15A814A1459500AA698B /* Frameworks */,
+ FCBA15A914A1459500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pwd;
+ productName = shell_cmds;
+ productReference = FCBA15AC14A1459500AA698B /* pwd */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15AE14A1459700AA698B /* renice */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15B214A1459700AA698B /* Build configuration list for PBXNativeTarget "renice" */;
+ buildPhases = (
+ FCBA15AF14A1459700AA698B /* Sources */,
+ FCBA15B014A1459700AA698B /* Frameworks */,
+ FCBA15B114A1459700AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = renice;
+ productName = shell_cmds;
+ productReference = FCBA15B414A1459700AA698B /* renice */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15B614A1459900AA698B /* script */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15BA14A1459900AA698B /* Build configuration list for PBXNativeTarget "script" */;
+ buildPhases = (
+ FCBA15B714A1459900AA698B /* Sources */,
+ FCBA15B814A1459900AA698B /* Frameworks */,
+ FCBA15B914A1459900AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = script;
+ productName = shell_cmds;
+ productReference = FCBA15BC14A1459900AA698B /* script */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15BE14A1459E00AA698B /* seq */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15C214A1459E00AA698B /* Build configuration list for PBXNativeTarget "seq" */;
+ buildPhases = (
+ FCBA15BF14A1459E00AA698B /* Sources */,
+ FCBA15C014A1459E00AA698B /* Frameworks */,
+ FCBA15C114A1459E00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = seq;
+ productName = shell_cmds;
+ productReference = FCBA15C414A1459E00AA698B /* seq */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15C614A145A200AA698B /* shlock */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15CA14A145A200AA698B /* Build configuration list for PBXNativeTarget "shlock" */;
+ buildPhases = (
+ FCBA15C714A145A200AA698B /* Sources */,
+ FCBA15C814A145A200AA698B /* Frameworks */,
+ FCBA15C914A145A200AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = shlock;
+ productName = shell_cmds;
+ productReference = FCBA15CC14A145A200AA698B /* shlock */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15CE14A145A500AA698B /* sleep */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15D214A145A500AA698B /* Build configuration list for PBXNativeTarget "sleep" */;
+ buildPhases = (
+ FCBA15CF14A145A500AA698B /* Sources */,
+ FCBA15D014A145A500AA698B /* Frameworks */,
+ FCBA15D114A145A500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sleep;
+ productName = shell_cmds;
+ productReference = FCBA15D414A145A500AA698B /* sleep */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15D614A145A700AA698B /* su */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15DA14A145A700AA698B /* Build configuration list for PBXNativeTarget "su" */;
+ buildPhases = (
+ FCBA15D714A145A700AA698B /* Sources */,
+ FCBA15D814A145A700AA698B /* Frameworks */,
+ FCBA15D914A145A700AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = su;
+ productName = shell_cmds;
+ productReference = FCBA15DC14A145A700AA698B /* su */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15DE14A145A900AA698B /* tee */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15E214A145A900AA698B /* Build configuration list for PBXNativeTarget "tee" */;
+ buildPhases = (
+ FCBA15DF14A145A900AA698B /* Sources */,
+ FCBA15E014A145A900AA698B /* Frameworks */,
+ FCBA15E114A145A900AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tee;
+ productName = shell_cmds;
+ productReference = FCBA15E414A145A900AA698B /* tee */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15E614A145AE00AA698B /* test */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15EA14A145AE00AA698B /* Build configuration list for PBXNativeTarget "test" */;
+ buildPhases = (
+ FCBA15E714A145AE00AA698B /* Sources */,
+ FCBA15E814A145AE00AA698B /* Frameworks */,
+ FCBA15E914A145AE00AA698B /* CopyFiles */,
+ FD155C741D6E37D7005A53CA /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = test;
+ productName = shell_cmds;
+ productReference = FCBA15EC14A145AE00AA698B /* test */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15EE14A145B000AA698B /* time */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15F214A145B000AA698B /* Build configuration list for PBXNativeTarget "time" */;
+ buildPhases = (
+ FCBA15EF14A145B000AA698B /* Sources */,
+ FCBA15F014A145B000AA698B /* Frameworks */,
+ FCBA15F114A145B000AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = time;
+ productName = shell_cmds;
+ productReference = FCBA15F414A145B000AA698B /* time */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15F614A145B200AA698B /* true */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA15FA14A145B200AA698B /* Build configuration list for PBXNativeTarget "true" */;
+ buildPhases = (
+ FCBA15F714A145B200AA698B /* Sources */,
+ FCBA15F814A145B200AA698B /* Frameworks */,
+ FCBA15F914A145B200AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = true;
+ productName = shell_cmds;
+ productReference = FCBA15FC14A145B200AA698B /* true */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA15FE14A145B500AA698B /* uname */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA160214A145B500AA698B /* Build configuration list for PBXNativeTarget "uname" */;
+ buildPhases = (
+ FCBA15FF14A145B500AA698B /* Sources */,
+ FCBA160014A145B500AA698B /* Frameworks */,
+ FCBA160114A145B500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = uname;
+ productName = shell_cmds;
+ productReference = FCBA160414A145B500AA698B /* uname */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA160614A145B800AA698B /* users */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA160A14A145B800AA698B /* Build configuration list for PBXNativeTarget "users" */;
+ buildPhases = (
+ FCBA160714A145B800AA698B /* Sources */,
+ FCBA160814A145B800AA698B /* Frameworks */,
+ FCBA160914A145B800AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = users;
+ productName = shell_cmds;
+ productReference = FCBA160C14A145B800AA698B /* users */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA160E14A145BA00AA698B /* w */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA161214A145BA00AA698B /* Build configuration list for PBXNativeTarget "w" */;
+ buildPhases = (
+ FCBA160F14A145BA00AA698B /* Sources */,
+ FCBA161014A145BA00AA698B /* Frameworks */,
+ FCBA161114A145BA00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = w;
+ productName = shell_cmds;
+ productReference = FCBA161414A145BA00AA698B /* w */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA161614A145BC00AA698B /* whereis */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA161A14A145BC00AA698B /* Build configuration list for PBXNativeTarget "whereis" */;
+ buildPhases = (
+ FCBA161714A145BC00AA698B /* Sources */,
+ FCBA161814A145BC00AA698B /* Frameworks */,
+ FCBA161914A145BC00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = whereis;
+ productName = shell_cmds;
+ productReference = FCBA161C14A145BC00AA698B /* whereis */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA161E14A145C000AA698B /* which */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA162214A145C000AA698B /* Build configuration list for PBXNativeTarget "which" */;
+ buildPhases = (
+ FCBA161F14A145C000AA698B /* Sources */,
+ FCBA162014A145C000AA698B /* Frameworks */,
+ FCBA162114A145C000AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = which;
+ productName = shell_cmds;
+ productReference = FCBA162414A145C000AA698B /* which */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA162614A145C500AA698B /* who */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA162A14A145C500AA698B /* Build configuration list for PBXNativeTarget "who" */;
+ buildPhases = (
+ FCBA162714A145C500AA698B /* Sources */,
+ FCBA162814A145C500AA698B /* Frameworks */,
+ FCBA162914A145C500AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = who;
+ productName = shell_cmds;
+ productReference = FCBA162C14A145C500AA698B /* who */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA162E14A145C700AA698B /* xargs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA163214A145C700AA698B /* Build configuration list for PBXNativeTarget "xargs" */;
+ buildPhases = (
+ FCBA162F14A145C700AA698B /* Sources */,
+ FCBA163014A145C700AA698B /* Frameworks */,
+ FCBA163114A145C700AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = xargs;
+ productName = shell_cmds;
+ productReference = FCBA163414A145C700AA698B /* xargs */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCBA163614A145CA00AA698B /* yes */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCBA163A14A145CA00AA698B /* Build configuration list for PBXNativeTarget "yes" */;
+ buildPhases = (
+ FCBA163714A145CA00AA698B /* Sources */,
+ FCBA163814A145CA00AA698B /* Frameworks */,
+ FCBA163914A145CA00AA698B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = yes;
+ productName = shell_cmds;
+ productReference = FCBA163C14A145CA00AA698B /* yes */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCE30EC214B5368A00CC0294 /* locate.bigram */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCE30ED014B5368A00CC0294 /* Build configuration list for PBXNativeTarget "locate.bigram" */;
+ buildPhases = (
+ FCE30EC314B5368A00CC0294 /* Sources */,
+ FCE30EC614B5368A00CC0294 /* Frameworks */,
+ FCE30EC714B5368A00CC0294 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = locate.bigram;
+ productName = shell_cmds;
+ productReference = FCE30ED214B5368A00CC0294 /* locate.bigram */;
+ productType = "com.apple.product-type.tool";
+ };
+ FCE30ED614B536C900CC0294 /* locate.code */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FCE30EDC14B536C900CC0294 /* Build configuration list for PBXNativeTarget "locate.code" */;
+ buildPhases = (
+ FCE30ED714B536C900CC0294 /* Sources */,
+ FCE30ED914B536C900CC0294 /* Frameworks */,
+ FCE30EDA14B536C900CC0294 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = locate.code;
+ productName = shell_cmds;
+ productReference = FCE30EDE14B536C900CC0294 /* locate.code */;
+ productType = "com.apple.product-type.tool";
+ };
+ FD6060B11B7C0388004BCA6A /* sh */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD6060B71B7C0388004BCA6A /* Build configuration list for PBXNativeTarget "sh" */;
+ buildPhases = (
+ FD6060EF1B7C0590004BCA6A /* mkbuiltins */,
+ FD6060F11B7C0742004BCA6A /* mknodes */,
+ FD6060F21B7C0744004BCA6A /* mksyntax */,
+ FD6060F31B7C0964004BCA6A /* mktokens */,
+ FD6060AE1B7C0388004BCA6A /* Sources */,
+ FD6060AF1B7C0388004BCA6A /* Frameworks */,
+ FD6061321B7D32AD004BCA6A /* sh.1 */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sh;
+ productName = sh;
+ productReference = FD6060B21B7C0388004BCA6A /* ash */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FC80BF5714A05A2F00C6F7F5 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1100;
+ ORGANIZATIONNAME = "Apple Inc.";
+ TargetAttributes = {
+ FD6060B11B7C0388004BCA6A = {
+ CreatedOnToolsVersion = 7.0;
+ };
+ };
+ };
+ buildConfigurationList = FC80BF5A14A05A2F00C6F7F5 /* Build configuration list for PBXProject "shell_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = FC80BF5514A05A2F00C6F7F5;
+ productRefGroup = FC80BF6114A05A2F00C6F7F5 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FCBA14FD14A144EC00AA698B /* All_OSX */,
+ FCE30F4A14B619B000CC0294 /* All_iOS */,
+ FCBA149814A141FF00AA698B /* apply */,
+ FCBA14AE14A1422D00AA698B /* basename */,
+ FCBA14B714A1423E00AA698B /* chroot */,
+ FCBA14BF14A1426800AA698B /* date */,
+ FCBA14C714A1428000AA698B /* dirname */,
+ FCBA14CF14A1433F00AA698B /* echo */,
+ FCBA14D714A1434A00AA698B /* env */,
+ FCBA150E14A1453A00AA698B /* expr */,
+ FCBA151614A1454D00AA698B /* false */,
+ FCBA151E14A1455600AA698B /* find */,
+ FCBA152614A1455900AA698B /* getopt */,
+ FC5D638F14B9822D00123E48 /* hexdump */,
+ FCBA152E14A1455C00AA698B /* hostname */,
+ FCBA153614A1455F00AA698B /* id */,
+ FCBA153E14A1456100AA698B /* jot */,
+ FCBA154614A1456400AA698B /* kill */,
+ FCBA154E14A1456700AA698B /* killall */,
+ FCBA155614A1456A00AA698B /* lastcomm */,
+ FCBA155E14A1456E00AA698B /* locate */,
+ FCE30EC214B5368A00CC0294 /* locate.bigram */,
+ FCE30ED614B536C900CC0294 /* locate.code */,
+ FCBA156614A1457100AA698B /* logname */,
+ FCBA157614A1457B00AA698B /* mktemp */,
+ FCBA157E14A1457F00AA698B /* nice */,
+ FCBA158614A1458500AA698B /* nohup */,
+ FCBA158E14A1458800AA698B /* path_helper */,
+ FCBA159614A1458C00AA698B /* printenv */,
+ FCBA159E14A1459000AA698B /* printf */,
+ FCBA15A614A1459500AA698B /* pwd */,
+ FCBA15AE14A1459700AA698B /* renice */,
+ FCBA15B614A1459900AA698B /* script */,
+ FCBA15BE14A1459E00AA698B /* seq */,
+ FD6060B11B7C0388004BCA6A /* sh */,
+ FCBA15C614A145A200AA698B /* shlock */,
+ FCBA15CE14A145A500AA698B /* sleep */,
+ FCBA15D614A145A700AA698B /* su */,
+ C6868575154725700025D623 /* systime */,
+ FCBA15DE14A145A900AA698B /* tee */,
+ FCBA15E614A145AE00AA698B /* test */,
+ FCBA15EE14A145B000AA698B /* time */,
+ FCBA15F614A145B200AA698B /* true */,
+ FCBA15FE14A145B500AA698B /* uname */,
+ FCBA160614A145B800AA698B /* users */,
+ FCBA160E14A145BA00AA698B /* w */,
+ FC5D637F14B9819E00123E48 /* what */,
+ FCBA161614A145BC00AA698B /* whereis */,
+ FCBA161E14A145C000AA698B /* which */,
+ FCBA162614A145C500AA698B /* who */,
+ FCBA162E14A145C700AA698B /* xargs */,
+ FCBA163614A145CA00AA698B /* yes */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FCE30EB814B531EC00CC0294 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh\n";
+ showEnvVarsInLog = 0;
+ };
+ FCE30F4D14B619C900CC0294 /* Run Script */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Run Script";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-files.sh\n";
+ showEnvVarsInLog = 0;
+ };
+ FD6060EF1B7C0590004BCA6A /* mkbuiltins */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/mkbuiltins",
+ "$(SRCROOT)/sh/builtins.def",
+ );
+ name = mkbuiltins;
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/builtins.c",
+ "$(BUILT_PRODUCTS_DIR)/builtins.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd ${BUILT_PRODUCTS_DIR} && sh ${SRCROOT}/sh/mkbuiltins ${SRCROOT}/sh";
+ };
+ FD6060F11B7C0742004BCA6A /* mknodes */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/mknodes.c",
+ "$(SRCROOT)/sh/nodetypes",
+ "$(SRCROOT)/sh/nodes.c.get",
+ );
+ name = mknodes;
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/nodes.c",
+ "$(BUILT_PRODUCTS_DIR)/nodes.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "mkdir -p ${DERIVED_FILE_DIR}\nenv -i xcrun -sdk macosx cc ${SRCROOT}/sh/mknodes.c -o ${DERIVED_FILE_DIR}/mknodes\ncd ${BUILT_PRODUCTS_DIR} && ${DERIVED_FILE_DIR}/mknodes ${SRCROOT}/sh/nodetypes ${SRCROOT}/sh/nodes.c.pat\n";
+ };
+ FD6060F21B7C0744004BCA6A /* mksyntax */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/mksyntax.c",
+ );
+ name = mksyntax;
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/syntax.c",
+ "$(BUILT_PRODUCTS_DIR)/syntax.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "env -i xcrun -sdk macosx cc ${SRCROOT}/sh/mksyntax.c -o ${DERIVED_FILE_DIR}/mksyntax\ncd ${BUILT_PRODUCTS_DIR} && ${DERIVED_FILE_DIR}/mksyntax";
+ };
+ FD6060F31B7C0964004BCA6A /* mktokens */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/mktokens",
+ );
+ name = mktokens;
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/token.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "cd ${BUILT_PRODUCTS_DIR} && sh ${SRCROOT}/sh/mktokens";
+ };
+ FD6061321B7D32AD004BCA6A /* sh.1 */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/sh/sh.1",
+ );
+ name = sh.1;
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "install -d -m 0755 ${DSTROOT}${SH_MAN_PREFIX}/share/man/man1\ninstall -m 0644 ${SRCROOT}/sh/sh.1 ${DSTROOT}${SH_MAN_PREFIX}/share/man/man1/${PRODUCT_NAME}.1";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ C6868572154725700025D623 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C686857A154725700025D623 /* systime.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC5D638014B9819E00123E48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC5D638D14B981D200123E48 /* what.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC5D639014B9822D00123E48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC5D639B14B9826500123E48 /* conv.c in Sources */,
+ FC5D639C14B9826500123E48 /* display.c in Sources */,
+ FC5D639D14B9826500123E48 /* hexdump.c in Sources */,
+ FC5D639E14B9826500123E48 /* hexsyntax.c in Sources */,
+ FC5D639F14B9826500123E48 /* odsyntax.c in Sources */,
+ FC5D63A014B9826500123E48 /* parse.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA149914A141FF00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14EB14A1444900AA698B /* apply.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14AF14A1422D00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14EE14A1446700AA698B /* basename.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14B814A1423E00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14F114A1448C00AA698B /* chroot.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14C014A1426800AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14F614A144B200AA698B /* vary.c in Sources */,
+ FCBA14F514A144AF00AA698B /* netdate.c in Sources */,
+ FCBA14F414A1449C00AA698B /* date.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14C814A1428000AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14F714A144C700AA698B /* dirname.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14D014A1433F00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14FA14A144D300AA698B /* echo.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA14D814A1434A00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA14FC14A144E500AA698B /* env.c in Sources */,
+ FD88EB03198C5257006B7EFD /* envopts.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA150F14A1453A00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02FF14B507130030BEB3 /* expr.y in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA151714A1454D00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA030114B507220030BEB3 /* false.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA151F14A1455600AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA030314B5073F0030BEB3 /* find.c in Sources */,
+ FCBA030414B5073F0030BEB3 /* function.c in Sources */,
+ FCBA030514B5073F0030BEB3 /* getdate.y in Sources */,
+ FCBA030614B5073F0030BEB3 /* ls.c in Sources */,
+ FCBA030714B5073F0030BEB3 /* main.c in Sources */,
+ FCBA030814B5073F0030BEB3 /* misc.c in Sources */,
+ FCBA030914B5073F0030BEB3 /* operator.c in Sources */,
+ FCBA030A14B5073F0030BEB3 /* option.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA152714A1455900AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA030C14B5074D0030BEB3 /* getopt.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA152F14A1455C00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA030E14B5076A0030BEB3 /* hostname.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA153714A1455F00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031014B507790030BEB3 /* id.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA153F14A1456100AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031514B507900030BEB3 /* jot.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA154714A1456400AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031714B507A10030BEB3 /* kill.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA154F14A1456700AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031914B507B00030BEB3 /* killall.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA155714A1456A00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031B14B507BD0030BEB3 /* lastcomm.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA155F14A1456E00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA031E14B507D10030BEB3 /* locate.c in Sources */,
+ FCBA031F14B507D10030BEB3 /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA156714A1457100AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02FD14B506FA0030BEB3 /* logname.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA157714A1457B00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F914B506CB0030BEB3 /* mktemp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA157F14A1457F00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F814B506BB0030BEB3 /* nice.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA158714A1458500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F514B506940030BEB3 /* nohup.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA158F14A1458800AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F314B506840030BEB3 /* path_helper.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA159714A1458C00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F114B506720030BEB3 /* printenv.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA159F14A1459000AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02F014B506660030BEB3 /* printf.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15A714A1459500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02ED14B506530030BEB3 /* pwd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15AF14A1459700AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02EC14B5064C0030BEB3 /* renice.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15B714A1459900AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02EA14B506340030BEB3 /* script.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15BF14A1459E00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA02E814B506230030BEB3 /* seq.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15C714A145A200AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0B14B3CD4F00ECF511 /* shlock.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15CF14A145A500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0A14B3CD4400ECF511 /* sleep.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15D714A145A700AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0714B3CD2F00ECF511 /* su.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15DF14A145A900AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0614B3CD2800ECF511 /* tee.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15E714A145AE00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0214B3CD0C00ECF511 /* test.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15EF14A145B000AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5C0014B3CCF800ECF511 /* time.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15F714A145B200AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5BFE14B3CCD700ECF511 /* true.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA15FF14A145B500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC2B5BFB14B3CCC600ECF511 /* uname.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA160714A145B800AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA165014A146BE00AA698B /* users.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA160F14A145BA00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164D14A146A200AA698B /* w.c in Sources */,
+ FCBA164C14A1469F00AA698B /* proc_compare.c in Sources */,
+ FCBA164B14A1469D00AA698B /* pr_time.c in Sources */,
+ FCBA164A14A1469A00AA698B /* fmt.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA161714A145BC00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164814A1469000AA698B /* whereis.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA161F14A145C000AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164614A1468600AA698B /* which.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA162714A145C500AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164414A1467D00AA698B /* who.c in Sources */,
+ FCBA164314A1467A00AA698B /* utmpentry.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA162F14A145C700AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA164114A1467200AA698B /* strnsubst.c in Sources */,
+ FCBA164014A1466F00AA698B /* xargs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCBA163714A145CA00AA698B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCBA163F14A1466900AA698B /* yes.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCE30EC314B5368A00CC0294 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCE30ED414B536A600CC0294 /* locate.bigram.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FCE30ED714B536C900CC0294 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FCE30EE014B536F200CC0294 /* locate.code.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD6060AE1B7C0388004BCA6A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD6060D21B7C0471004BCA6A /* alias.c in Sources */,
+ FD6060D31B7C0471004BCA6A /* arith_yacc.c in Sources */,
+ FD6060D41B7C0471004BCA6A /* arith_yylex.c in Sources */,
+ FD6060D51B7C0471004BCA6A /* cd.c in Sources */,
+ FD6060EB1B7C04E4004BCA6A /* echo.c in Sources */,
+ FD6060D61B7C0471004BCA6A /* error.c in Sources */,
+ FD6060D71B7C0471004BCA6A /* eval.c in Sources */,
+ FD6060D81B7C0471004BCA6A /* exec.c in Sources */,
+ FD6060D91B7C0471004BCA6A /* expand.c in Sources */,
+ FD6060DA1B7C0471004BCA6A /* histedit.c in Sources */,
+ FD6060DB1B7C0471004BCA6A /* input.c in Sources */,
+ FD6060DC1B7C0471004BCA6A /* jobs.c in Sources */,
+ FD6060EC1B7C0506004BCA6A /* kill.c in Sources */,
+ FD6060DD1B7C0471004BCA6A /* mail.c in Sources */,
+ FD6060B51B7C0388004BCA6A /* main.c in Sources */,
+ FD6060DE1B7C0471004BCA6A /* memalloc.c in Sources */,
+ FD6060DF1B7C0471004BCA6A /* miscbltin.c in Sources */,
+ FD6060E01B7C0471004BCA6A /* mystring.c in Sources */,
+ FD6060E11B7C0471004BCA6A /* options.c in Sources */,
+ FD6060E21B7C0471004BCA6A /* output.c in Sources */,
+ FD6060E31B7C0471004BCA6A /* parser.c in Sources */,
+ FD6060ED1B7C0518004BCA6A /* printf.c in Sources */,
+ FD6060E41B7C0471004BCA6A /* redir.c in Sources */,
+ FD6060E51B7C0471004BCA6A /* show.c in Sources */,
+ FD6060EE1B7C0521004BCA6A /* test.c in Sources */,
+ FD6060E61B7C0471004BCA6A /* trap.c in Sources */,
+ FD6060E71B7C0471004BCA6A /* var.c in Sources */,
+ FD6060FD1B7C0CAF004BCA6A /* builtins.c in Sources */,
+ FD6060FE1B7C0CAF004BCA6A /* nodes.c in Sources */,
+ FD6060FF1B7C0CAF004BCA6A /* syntax.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ C6868581154725990025D623 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C6868575154725700025D623 /* systime */;
+ targetProxy = C6868580154725990025D623 /* PBXContainerItemProxy */;
+ };
+ C6868583154725A30025D623 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C6868575154725700025D623 /* systime */;
+ targetProxy = C6868582154725A30025D623 /* PBXContainerItemProxy */;
+ };
+ FC5D63A214B9864400123E48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC5D638F14B9822D00123E48 /* hexdump */;
+ targetProxy = FC5D63A114B9864400123E48 /* PBXContainerItemProxy */;
+ };
+ FC5D63A414B9864400123E48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC5D637F14B9819E00123E48 /* what */;
+ targetProxy = FC5D63A314B9864400123E48 /* PBXContainerItemProxy */;
+ };
+ FC5D63A614B9866500123E48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC5D638F14B9822D00123E48 /* hexdump */;
+ targetProxy = FC5D63A514B9866500123E48 /* PBXContainerItemProxy */;
+ };
+ FC5D63A814B9866500123E48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC5D637F14B9819E00123E48 /* what */;
+ targetProxy = FC5D63A714B9866500123E48 /* PBXContainerItemProxy */;
+ };
+ FCBA150114A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA149814A141FF00AA698B /* apply */;
+ targetProxy = FCBA150014A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150314A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14AE14A1422D00AA698B /* basename */;
+ targetProxy = FCBA150214A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150514A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14B714A1423E00AA698B /* chroot */;
+ targetProxy = FCBA150414A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150714A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14BF14A1426800AA698B /* date */;
+ targetProxy = FCBA150614A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150914A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14C714A1428000AA698B /* dirname */;
+ targetProxy = FCBA150814A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150B14A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14CF14A1433F00AA698B /* echo */;
+ targetProxy = FCBA150A14A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA150D14A144F700AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14D714A1434A00AA698B /* env */;
+ targetProxy = FCBA150C14A144F700AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA150E14A1453A00AA698B /* expr */;
+ targetProxy = FCBA165414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA151614A1454D00AA698B /* false */;
+ targetProxy = FCBA165614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA151E14A1455600AA698B /* find */;
+ targetProxy = FCBA165814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA152614A1455900AA698B /* getopt */;
+ targetProxy = FCBA165A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165D14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA152E14A1455C00AA698B /* hostname */;
+ targetProxy = FCBA165C14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA165F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA153614A1455F00AA698B /* id */;
+ targetProxy = FCBA165E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166114A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA153E14A1456100AA698B /* jot */;
+ targetProxy = FCBA166014A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166314A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA154614A1456400AA698B /* kill */;
+ targetProxy = FCBA166214A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA154E14A1456700AA698B /* killall */;
+ targetProxy = FCBA166414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA155614A1456A00AA698B /* lastcomm */;
+ targetProxy = FCBA166614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA155E14A1456E00AA698B /* locate */;
+ targetProxy = FCBA166814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA156614A1457100AA698B /* logname */;
+ targetProxy = FCBA166A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA166F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA157614A1457B00AA698B /* mktemp */;
+ targetProxy = FCBA166E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167114A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA157E14A1457F00AA698B /* nice */;
+ targetProxy = FCBA167014A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167314A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA158614A1458500AA698B /* nohup */;
+ targetProxy = FCBA167214A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA158E14A1458800AA698B /* path_helper */;
+ targetProxy = FCBA167414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA159614A1458C00AA698B /* printenv */;
+ targetProxy = FCBA167614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA159E14A1459000AA698B /* printf */;
+ targetProxy = FCBA167814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15A614A1459500AA698B /* pwd */;
+ targetProxy = FCBA167A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167D14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15AE14A1459700AA698B /* renice */;
+ targetProxy = FCBA167C14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA167F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15B614A1459900AA698B /* script */;
+ targetProxy = FCBA167E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168114A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15BE14A1459E00AA698B /* seq */;
+ targetProxy = FCBA168014A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168314A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15C614A145A200AA698B /* shlock */;
+ targetProxy = FCBA168214A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15CE14A145A500AA698B /* sleep */;
+ targetProxy = FCBA168414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15D614A145A700AA698B /* su */;
+ targetProxy = FCBA168614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15DE14A145A900AA698B /* tee */;
+ targetProxy = FCBA168814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15E614A145AE00AA698B /* test */;
+ targetProxy = FCBA168A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168D14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15EE14A145B000AA698B /* time */;
+ targetProxy = FCBA168C14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA168F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15F614A145B200AA698B /* true */;
+ targetProxy = FCBA168E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169114A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15FE14A145B500AA698B /* uname */;
+ targetProxy = FCBA169014A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169314A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA160614A145B800AA698B /* users */;
+ targetProxy = FCBA169214A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169514A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA160E14A145BA00AA698B /* w */;
+ targetProxy = FCBA169414A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169714A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA161614A145BC00AA698B /* whereis */;
+ targetProxy = FCBA169614A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169914A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA161E14A145C000AA698B /* which */;
+ targetProxy = FCBA169814A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169B14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA162614A145C500AA698B /* who */;
+ targetProxy = FCBA169A14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169D14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA162E14A145C700AA698B /* xargs */;
+ targetProxy = FCBA169C14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCBA169F14A146D000AA698B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA163614A145CA00AA698B /* yes */;
+ targetProxy = FCBA169E14A146D000AA698B /* PBXContainerItemProxy */;
+ };
+ FCE30EE314B539BF00CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCE30EC214B5368A00CC0294 /* locate.bigram */;
+ targetProxy = FCE30EE214B539BF00CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30EE514B539BF00CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCE30ED614B536C900CC0294 /* locate.code */;
+ targetProxy = FCE30EE414B539BF00CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F4F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA149814A141FF00AA698B /* apply */;
+ targetProxy = FCE30F4E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14AE14A1422D00AA698B /* basename */;
+ targetProxy = FCE30F5014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14B714A1423E00AA698B /* chroot */;
+ targetProxy = FCE30F5214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14BF14A1426800AA698B /* date */;
+ targetProxy = FCE30F5414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14C714A1428000AA698B /* dirname */;
+ targetProxy = FCE30F5614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14CF14A1433F00AA698B /* echo */;
+ targetProxy = FCE30F5814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA14D714A1434A00AA698B /* env */;
+ targetProxy = FCE30F5A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA150E14A1453A00AA698B /* expr */;
+ targetProxy = FCE30F5C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F5F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA151614A1454D00AA698B /* false */;
+ targetProxy = FCE30F5E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA151E14A1455600AA698B /* find */;
+ targetProxy = FCE30F6014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA152614A1455900AA698B /* getopt */;
+ targetProxy = FCE30F6214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA152E14A1455C00AA698B /* hostname */;
+ targetProxy = FCE30F6414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA153614A1455F00AA698B /* id */;
+ targetProxy = FCE30F6614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA153E14A1456100AA698B /* jot */;
+ targetProxy = FCE30F6814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA154614A1456400AA698B /* kill */;
+ targetProxy = FCE30F6A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA154E14A1456700AA698B /* killall */;
+ targetProxy = FCE30F6C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F6F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA155614A1456A00AA698B /* lastcomm */;
+ targetProxy = FCE30F6E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA156614A1457100AA698B /* logname */;
+ targetProxy = FCE30F7014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA157614A1457B00AA698B /* mktemp */;
+ targetProxy = FCE30F7214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA157E14A1457F00AA698B /* nice */;
+ targetProxy = FCE30F7414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA158614A1458500AA698B /* nohup */;
+ targetProxy = FCE30F7614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA158E14A1458800AA698B /* path_helper */;
+ targetProxy = FCE30F7814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA159614A1458C00AA698B /* printenv */;
+ targetProxy = FCE30F7A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA159E14A1459000AA698B /* printf */;
+ targetProxy = FCE30F7C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F7F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15A614A1459500AA698B /* pwd */;
+ targetProxy = FCE30F7E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15AE14A1459700AA698B /* renice */;
+ targetProxy = FCE30F8014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15B614A1459900AA698B /* script */;
+ targetProxy = FCE30F8214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15BE14A1459E00AA698B /* seq */;
+ targetProxy = FCE30F8414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15C614A145A200AA698B /* shlock */;
+ targetProxy = FCE30F8614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15CE14A145A500AA698B /* sleep */;
+ targetProxy = FCE30F8814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15DE14A145A900AA698B /* tee */;
+ targetProxy = FCE30F8A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15E614A145AE00AA698B /* test */;
+ targetProxy = FCE30F8C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F8F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15EE14A145B000AA698B /* time */;
+ targetProxy = FCE30F8E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15F614A145B200AA698B /* true */;
+ targetProxy = FCE30F9014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9314B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA15FE14A145B500AA698B /* uname */;
+ targetProxy = FCE30F9214B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9514B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA160614A145B800AA698B /* users */;
+ targetProxy = FCE30F9414B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9714B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA160E14A145BA00AA698B /* w */;
+ targetProxy = FCE30F9614B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9914B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA161614A145BC00AA698B /* whereis */;
+ targetProxy = FCE30F9814B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9B14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA161E14A145C000AA698B /* which */;
+ targetProxy = FCE30F9A14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9D14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA162614A145C500AA698B /* who */;
+ targetProxy = FCE30F9C14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30F9F14B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA162E14A145C700AA698B /* xargs */;
+ targetProxy = FCE30F9E14B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FCE30FA114B619E600CC0294 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FCBA163614A145CA00AA698B /* yes */;
+ targetProxy = FCE30FA014B619E600CC0294 /* PBXContainerItemProxy */;
+ };
+ FD6060B91B7C03B3004BCA6A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD6060B11B7C0388004BCA6A /* sh */;
+ targetProxy = FD6060B81B7C03B3004BCA6A /* PBXContainerItemProxy */;
+ };
+ FD6060BB1B7C03BC004BCA6A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD6060B11B7C0388004BCA6A /* sh */;
+ targetProxy = FD6060BA1B7C03BC004BCA6A /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ C686857D154725700025D623 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC5D638A14B9819E00123E48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC5D639614B9822D00123E48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC80BF6914A05A2F00C6F7F5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ APPLY_RULES_IN_COPY_FILES = YES;
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/bin;
+ SDKROOT = macosx.internal;
+ VERSIONING_SYSTEM = "apple-generic";
+ };
+ name = Release;
+ };
+ FCBA149D14A141FF00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14B314A1422D00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14BC14A1423E00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14C414A1426800AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14CC14A1428000AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14D414A1433F00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14DC14A1434A00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA14FF14A144EC00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA151314A1453A00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA151B14A1454D00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA152314A1455600AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ _DARWIN_USE_64_BIT_INODE,
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA152B14A1455900AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA153314A1455C00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA153B14A1455F00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ USE_BSM_AUDIT,
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA154314A1456100AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA154B14A1456400AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA155314A1456700AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA155B14A1456A00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA156314A1456E00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA156B14A1457100AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA157B14A1457B00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA158314A1457F00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA158B14A1458500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA159314A1458800AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA159B14A1458C00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15A314A1459000AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15AB14A1459500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15B314A1459700AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15BB14A1459900AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15C314A1459E00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15CB14A145A200AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15D314A145A500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15DB14A145A700AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CODE_SIGN_ENTITLEMENTS = su/su_entitlements.plist;
+ INSTALL_MODE_FLAG = "u+s,u+w,go-w,a+rX";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15E314A145A900AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15EB14A145AE00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15F314A145B000AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA15FB14A145B200AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA160314A145B500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA160B14A145B800AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA161314A145BA00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ "HAVE_KVM=0",
+ "HAVE_UTMPX=1",
+ );
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = "-lresolv";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA161B14A145BC00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA162314A145C000AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA162B14A145C500AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "__FBSDID=__RCSID",
+ _UTMPX_COMPAT,
+ SUPPORT_UTMPX,
+ );
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA163314A145C700AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCBA163B14A145CA00AA698B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCE30ED114B5368A00CC0294 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCE30EDD14B536C900CC0294 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FCE30F4C14B619B000CC0294 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FD6060B61B7C0388004BCA6A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FD6061311B7D2DDE004BCA6A /* sh.xcconfig */;
+ buildSettings = {
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ C686857E154725700025D623 /* Build configuration list for PBXNativeTarget "systime" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C686857D154725700025D623 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC5D638914B9819E00123E48 /* Build configuration list for PBXNativeTarget "what" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC5D638A14B9819E00123E48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC5D639514B9822D00123E48 /* Build configuration list for PBXNativeTarget "hexdump" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC5D639614B9822D00123E48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC80BF5A14A05A2F00C6F7F5 /* Build configuration list for PBXProject "shell_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC80BF6914A05A2F00C6F7F5 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA149C14A141FF00AA698B /* Build configuration list for PBXNativeTarget "apply" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA149D14A141FF00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14B214A1422D00AA698B /* Build configuration list for PBXNativeTarget "basename" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14B314A1422D00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14BB14A1423E00AA698B /* Build configuration list for PBXNativeTarget "chroot" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14BC14A1423E00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14C314A1426800AA698B /* Build configuration list for PBXNativeTarget "date" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14C414A1426800AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14CB14A1428000AA698B /* Build configuration list for PBXNativeTarget "dirname" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14CC14A1428000AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14D314A1433F00AA698B /* Build configuration list for PBXNativeTarget "echo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14D414A1433F00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14DB14A1434A00AA698B /* Build configuration list for PBXNativeTarget "env" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14DC14A1434A00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA14FE14A144EC00AA698B /* Build configuration list for PBXAggregateTarget "All_OSX" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA14FF14A144EC00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA151214A1453A00AA698B /* Build configuration list for PBXNativeTarget "expr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA151314A1453A00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA151A14A1454D00AA698B /* Build configuration list for PBXNativeTarget "false" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA151B14A1454D00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA152214A1455600AA698B /* Build configuration list for PBXNativeTarget "find" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA152314A1455600AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA152A14A1455900AA698B /* Build configuration list for PBXNativeTarget "getopt" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA152B14A1455900AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA153214A1455C00AA698B /* Build configuration list for PBXNativeTarget "hostname" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA153314A1455C00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA153A14A1455F00AA698B /* Build configuration list for PBXNativeTarget "id" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA153B14A1455F00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA154214A1456100AA698B /* Build configuration list for PBXNativeTarget "jot" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA154314A1456100AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA154A14A1456400AA698B /* Build configuration list for PBXNativeTarget "kill" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA154B14A1456400AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA155214A1456700AA698B /* Build configuration list for PBXNativeTarget "killall" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA155314A1456700AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA155A14A1456A00AA698B /* Build configuration list for PBXNativeTarget "lastcomm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA155B14A1456A00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA156214A1456E00AA698B /* Build configuration list for PBXNativeTarget "locate" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA156314A1456E00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA156A14A1457100AA698B /* Build configuration list for PBXNativeTarget "logname" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA156B14A1457100AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA157A14A1457B00AA698B /* Build configuration list for PBXNativeTarget "mktemp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA157B14A1457B00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA158214A1457F00AA698B /* Build configuration list for PBXNativeTarget "nice" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA158314A1457F00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA158A14A1458500AA698B /* Build configuration list for PBXNativeTarget "nohup" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA158B14A1458500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA159214A1458800AA698B /* Build configuration list for PBXNativeTarget "path_helper" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA159314A1458800AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA159A14A1458C00AA698B /* Build configuration list for PBXNativeTarget "printenv" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA159B14A1458C00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15A214A1459000AA698B /* Build configuration list for PBXNativeTarget "printf" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15A314A1459000AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15AA14A1459500AA698B /* Build configuration list for PBXNativeTarget "pwd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15AB14A1459500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15B214A1459700AA698B /* Build configuration list for PBXNativeTarget "renice" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15B314A1459700AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15BA14A1459900AA698B /* Build configuration list for PBXNativeTarget "script" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15BB14A1459900AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15C214A1459E00AA698B /* Build configuration list for PBXNativeTarget "seq" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15C314A1459E00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15CA14A145A200AA698B /* Build configuration list for PBXNativeTarget "shlock" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15CB14A145A200AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15D214A145A500AA698B /* Build configuration list for PBXNativeTarget "sleep" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15D314A145A500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15DA14A145A700AA698B /* Build configuration list for PBXNativeTarget "su" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15DB14A145A700AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15E214A145A900AA698B /* Build configuration list for PBXNativeTarget "tee" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15E314A145A900AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15EA14A145AE00AA698B /* Build configuration list for PBXNativeTarget "test" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15EB14A145AE00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15F214A145B000AA698B /* Build configuration list for PBXNativeTarget "time" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15F314A145B000AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA15FA14A145B200AA698B /* Build configuration list for PBXNativeTarget "true" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA15FB14A145B200AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA160214A145B500AA698B /* Build configuration list for PBXNativeTarget "uname" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA160314A145B500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA160A14A145B800AA698B /* Build configuration list for PBXNativeTarget "users" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA160B14A145B800AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA161214A145BA00AA698B /* Build configuration list for PBXNativeTarget "w" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA161314A145BA00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA161A14A145BC00AA698B /* Build configuration list for PBXNativeTarget "whereis" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA161B14A145BC00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA162214A145C000AA698B /* Build configuration list for PBXNativeTarget "which" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA162314A145C000AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA162A14A145C500AA698B /* Build configuration list for PBXNativeTarget "who" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA162B14A145C500AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA163214A145C700AA698B /* Build configuration list for PBXNativeTarget "xargs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA163314A145C700AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCBA163A14A145CA00AA698B /* Build configuration list for PBXNativeTarget "yes" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCBA163B14A145CA00AA698B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCE30ED014B5368A00CC0294 /* Build configuration list for PBXNativeTarget "locate.bigram" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCE30ED114B5368A00CC0294 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCE30EDC14B536C900CC0294 /* Build configuration list for PBXNativeTarget "locate.code" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCE30EDD14B536C900CC0294 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FCE30F4B14B619B000CC0294 /* Build configuration list for PBXAggregateTarget "All_iOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FCE30F4C14B619B000CC0294 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD6060B71B7C0388004BCA6A /* Build configuration list for PBXNativeTarget "sh" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD6060B61B7C0388004BCA6A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FC80BF5714A05A2F00C6F7F5 /* Project object */;
+}
diff --git a/shell_cmds/shell_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/shell_cmds/shell_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/shell_cmds/shell_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/shell_cmds/shlock/shlock.1 b/shell_cmds/shlock/shlock.1
new file mode 100644
index 0000000..9b1667d
--- /dev/null
+++ b/shell_cmds/shlock/shlock.1
@@ -0,0 +1,147 @@
+.\" $NetBSD: shlock.1,v 1.11 2008/04/30 13:11:01 martin Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Erik E. Fair.
+.\"
+.\" 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.
+.\"
+.Dd June 29, 1997
+.Dt SHLOCK 1
+.Os
+.Sh NAME
+.Nm shlock
+.Nd create or verify a lock file for shell scripts
+.Sh SYNOPSIS
+.Nm
+.Op Fl du
+.Op Fl p Ar PID
+.Fl f
+.Ar lockfile
+.Sh DESCRIPTION
+The
+.Nm
+command can create or verify a lock file on behalf of a shell or
+other script program.
+When it attempts to create a lock file, if one already exists,
+.Nm
+verifies that it is or is not valid.
+If valid,
+.Nm
+will exit with a non-zero exit code.
+If invalid,
+.Nm
+will remove the lock file, and
+create a new one.
+.Pp
+.Nm
+uses the
+.Xr link 2
+system call to make the final target lock file, which is an atomic
+operation (i.e. "dot locking", so named for this mechanism's original
+use for locking system mailboxes).
+It puts the process ID ("PID") from the command line into the
+requested lock file.
+.Pp
+.Nm
+verifies that an extant lock file is still valid by
+using
+.Xr kill 2
+with a zero signal to check for the existence of the process that
+holds the lock.
+.Pp
+The
+.Fl d
+option causes
+.Nm
+to be verbose about what it is doing.
+.Pp
+The
+.Fl f
+argument with
+.Ar lockfile
+is always required.
+.Pp
+The
+.Fl p
+option with
+.Ar PID
+is given when the program is to create a lock file; when absent,
+.Nm
+will simply check for the validity of the lock file.
+.Pp
+The
+.Fl u
+option causes
+.Nm
+to read and write the PID as a binary pid_t, instead of as ASCII,
+to be compatible with the locks created by UUCP.
+.Sh EXIT STATUS
+A zero exit code indicates a valid lock file.
+.Sh EXAMPLES
+.Ss BOURNE SHELL
+.Bd -literal
+#!/bin/sh
+lckfile=/tmp/foo.lock
+if shlock -f ${lckfile} -p $$
+then
+# do what required the lock
+ rm ${lckfile}
+else
+ echo Lock ${lckfile} already held by `cat ${lckfile}`
+fi
+.Ed
+.Ss C SHELL
+.Bd -literal
+#!/bin/csh -f
+set lckfile=/tmp/foo.lock
+shlock -f ${lckfile} -p $$
+if ($status == 0) then
+# do what required the lock
+ rm ${lckfile}
+else
+ echo Lock ${lckfile} already held by `cat ${lckfile}`
+endif
+.Ed
+.Pp
+The examples assume that the file system where the lock file is to
+be created is writable by the user, and has space available.
+.Sh HISTORY
+.Nm
+was written for the first Network News Transfer Protocol (NNTP)
+software distribution, released in March 1986.
+The algorithm was suggested by Peter Honeyman,
+from work he did on HoneyDanBer UUCP.
+.Sh AUTHORS
+.An Erik E. Fair Aq fair@clock.org
+.Sh BUGS
+Does not work on NFS or other network file system on different
+systems because the disparate systems have disjoint PID spaces.
+.Pp
+Cannot handle the case where a lock file was not deleted, the
+process that created it has exited, and the system has created a
+new process with the same PID as in the dead lock file.
+The lock file will appear to be valid even though the process is
+unrelated to the one that created the lock in the first place.
+Always remove your lock files after you're done.
diff --git a/shell_cmds/shlock/shlock.c b/shell_cmds/shlock/shlock.c
new file mode 100644
index 0000000..9dcb645
--- /dev/null
+++ b/shell_cmds/shlock/shlock.c
@@ -0,0 +1,364 @@
+/* $NetBSD: shlock.c,v 1.10 2008/04/28 20:24:14 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Erik E. Fair.
+ *
+ * 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.
+ */
+
+/*
+** Program to produce reliable locks for shell scripts.
+** Algorithm suggested by Peter Honeyman, January 1984,
+** in connection with HoneyDanBer UUCP.
+**
+** I tried extending this to handle shared locks in November 1987,
+** and ran into to some fundamental problems:
+**
+** Neither 4.3 BSD nor System V have an open(2) with locking,
+** so that you can open a file and have it locked as soon as
+** it's real; you have to make two system calls, and there's
+** a race...
+**
+** When removing dead process id's from a list in a file,
+** you need to truncate the file (you don't want to create a
+** new one; see above); unfortunately for the portability of
+** this program, only 4.3 BSD has ftruncate(2).
+**
+** Erik E. Fair <fair@ucbarpa.berkeley.edu>, November 8, 1987
+**
+** Extensions for UUCP style locks (i.e. pid is an int in the file,
+** rather than an ASCII string). Also fix long standing bug with
+** full file systems and temporary files.
+**
+** Erik E. Fair <fair@apple.com>, November 12, 1989
+**
+** ANSIfy the code somewhat to make gcc -Wall happy with the code.
+** Submit to NetBSD
+**
+** Erik E. Fair <fair@clock.org>, May 20, 1997
+*/
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__RCSID("$NetBSD: shlock.c,v 1.10 2008/04/28 20:24:14 martin Exp $");
+#endif
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <fcntl.h> /* Needed on hpux */
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#define LOCK_SET 0
+#define LOCK_FAIL 1
+
+#define LOCK_GOOD 0
+#define LOCK_BAD 1
+
+#define FAIL (-1)
+
+#define TRUE 1
+#define FALSE 0
+
+int Debug = FALSE;
+char *Pname;
+const char USAGE[] = "%s: USAGE: %s [-du] [-p PID] -f file\n";
+const char E_unlk[] = "%s: unlink(%s): %s\n";
+const char E_open[] = "%s: open(%s): %s\n";
+
+#define dprintf if (Debug) printf
+
+/*
+** Prototypes to make the ANSI compilers happy
+** Didn't lint used to do type and argument checking?
+** (and wasn't that sufficient?)
+*/
+
+/* the following is in case you need to make the prototypes go away. */
+char *xtmpfile(char *, pid_t, int);
+int p_exists(pid_t);
+int cklock(char *, int);
+int mklock(char *, pid_t, int);
+void bad_usage(void);
+int main(int, char **);
+
+/*
+** Create a temporary file, all ready to lock with.
+** The file arg is so we get the filename right, if he
+** gave us a full path, instead of using the current directory
+** which might not be in the same filesystem.
+*/
+char *
+xtmpfile(char *file, pid_t pid, int uucpstyle)
+{
+ int fd;
+ int len;
+ char *cp, buf[BUFSIZ];
+ static char tempname[BUFSIZ];
+
+ sprintf(buf, "shlock%ld", (u_long)getpid());
+ if ((cp = strrchr(strcpy(tempname, file), '/')) != (char *)NULL) {
+ *++cp = '\0';
+ (void) strcat(tempname, buf);
+ } else
+ (void) strcpy(tempname, buf);
+ dprintf("%s: temporary filename: %s\n", Pname, tempname);
+
+ sprintf(buf, "%ld\n", (u_long)pid);
+ len = strlen(buf);
+openloop:
+ if ((fd = open(tempname, O_RDWR|O_CREAT|O_EXCL, 0644)) < 0) {
+ switch(errno) {
+ case EEXIST:
+ dprintf("%s: file %s exists already.\n",
+ Pname, tempname);
+ if (unlink(tempname) < 0) {
+ fprintf(stderr, E_unlk,
+ Pname, tempname, strerror(errno));
+ return((char *)NULL);
+ }
+ /*
+ ** Further profanity
+ */
+ goto openloop;
+ default:
+ fprintf(stderr, E_open,
+ Pname, tempname, strerror(errno));
+ return((char *)NULL);
+ }
+ }
+
+ /*
+ ** Write the PID into the temporary file before attempting to link
+ ** to the actual lock file. That way we have a valid lock the instant
+ ** the link succeeds.
+ */
+ if (uucpstyle ?
+ (write(fd, &pid, sizeof(pid)) != sizeof(pid)) :
+ (write(fd, buf, len) < 0))
+ {
+ fprintf(stderr, "%s: write(%s,%ld): %s\n",
+ Pname, tempname, (u_long)pid, strerror(errno));
+ (void) close(fd);
+ if (unlink(tempname) < 0) {
+ fprintf(stderr, E_unlk,
+ Pname, tempname, strerror(errno));
+ }
+ return((char *)NULL);
+ }
+ (void) close(fd);
+ return(tempname);
+}
+
+/*
+** Does the PID exist?
+** Send null signal to find out.
+*/
+int
+p_exists(pid_t pid)
+{
+ dprintf("%s: process %ld is ", Pname, (u_long)pid);
+ if (pid <= 0) {
+ dprintf("invalid\n");
+ return(FALSE);
+ }
+ if (kill(pid, 0) < 0) {
+ switch(errno) {
+ case ESRCH:
+ dprintf("dead\n");
+ return(FALSE); /* pid does not exist */
+ case EPERM:
+ dprintf("alive\n");
+ return(TRUE); /* pid exists */
+ default:
+ dprintf("state unknown: %s\n", strerror(errno));
+ return(TRUE); /* be conservative */
+ }
+ }
+ dprintf("alive\n");
+ return(TRUE); /* pid exists */
+}
+
+/*
+** Check the validity of an existing lock file.
+**
+** Read the PID out of the lock
+** Send a null signal to determine whether that PID still exists
+** Existence (or not) determines the validity of the lock.
+**
+** Two bigs wins to this algorithm:
+**
+** o Locks do not survive crashes of either the system or the
+** application by any appreciable period of time.
+**
+** o No clean up to do if the system or application crashes.
+**
+*/
+int
+cklock(char *file, int uucpstyle)
+{
+ int fd = open(file, O_RDONLY);
+ ssize_t len;
+ pid_t pid;
+ char buf[BUFSIZ];
+
+ dprintf("%s: checking extant lock <%s>\n", Pname, file);
+ if (fd < 0) {
+ if (errno != ENOENT)
+ fprintf(stderr, E_open, Pname, file, strerror(errno));
+ return(TRUE); /* might or might not; conservatism */
+ }
+
+ if (uucpstyle ?
+ ((len = read(fd, &pid, sizeof(pid))) != sizeof(pid)) :
+ ((len = read(fd, buf, sizeof(buf))) <= 0))
+ {
+ close(fd);
+ dprintf("%s: lock file format error\n", Pname);
+ return(FALSE);
+ }
+ close(fd);
+ buf[len + 1] = '\0';
+ return(p_exists(uucpstyle ? pid : atoi(buf)));
+}
+
+int
+mklock(char *file, pid_t pid, int uucpstyle)
+{
+ char *tmp;
+ int retcode = FALSE;
+
+ dprintf("%s: trying lock <%s> for process %ld\n", Pname, file,
+ (u_long)pid);
+ if ((tmp = xtmpfile(file, pid, uucpstyle)) == (char *)NULL)
+ return(FALSE);
+
+linkloop:
+ if (link(tmp, file) < 0) {
+ switch(errno) {
+ case EEXIST:
+ dprintf("%s: lock <%s> already exists\n", Pname, file);
+ if (cklock(file, uucpstyle)) {
+ dprintf("%s: extant lock is valid\n", Pname);
+ break;
+ } else {
+ dprintf("%s: lock is invalid, removing\n",
+ Pname);
+ if (unlink(file) < 0) {
+ fprintf(stderr, E_unlk,
+ Pname, file, strerror(errno));
+ break;
+ }
+ }
+ /*
+ ** I hereby profane the god of structured programming,
+ ** Edsgar Dijkstra
+ */
+ goto linkloop;
+ default:
+ fprintf(stderr, "%s: link(%s, %s): %s\n",
+ Pname, tmp, file, strerror(errno));
+ break;
+ }
+ } else {
+ dprintf("%s: got lock <%s>\n", Pname, file);
+ retcode = TRUE;
+ }
+ if (unlink(tmp) < 0) {
+ fprintf(stderr, E_unlk, Pname, tmp, strerror(errno));
+ }
+ return(retcode);
+}
+
+void
+bad_usage(void)
+{
+ fprintf(stderr, USAGE, Pname, Pname);
+ exit(LOCK_FAIL);
+}
+
+int
+main(int ac, char **av)
+{
+ int x;
+ char *file = (char *)NULL;
+ pid_t pid = 0;
+ int uucpstyle = FALSE; /* indicating UUCP style locks */
+ int only_check = TRUE; /* don't make a lock */
+
+ Pname = ((Pname = strrchr(av[0], '/')) ? Pname + 1 : av[0]);
+
+ for(x = 1; x < ac; x++) {
+ if (av[x][0] == '-') {
+ switch(av[x][1]) {
+ case 'u':
+ uucpstyle = TRUE;
+ break;
+ case 'd':
+ Debug = TRUE;
+ break;
+ case 'p':
+ if (strlen(av[x]) > 2) {
+ pid = atoi(&av[x][2]);
+ } else {
+ if (++x >= ac) {
+ bad_usage();
+ }
+ pid = atoi(av[x]);
+ }
+ only_check = FALSE; /* wants one */
+ break;
+ case 'f':
+ if (strlen(av[x]) > 2) {
+ file = &av[x][2];
+ } else {
+ if (++x >= ac) {
+ bad_usage();
+ }
+ file = av[x];
+ }
+ break;
+ default:
+ bad_usage();
+ }
+ }
+ }
+
+ if (file == (char *)NULL || (!only_check && pid <= 0)) {
+ bad_usage();
+ }
+
+ if (only_check) {
+ exit(cklock(file, uucpstyle) ? LOCK_GOOD : LOCK_BAD);
+ }
+
+ exit(mklock(file, pid, uucpstyle) ? LOCK_SET : LOCK_FAIL);
+}
diff --git a/shell_cmds/sleep/sleep.1 b/shell_cmds/sleep/sleep.1
new file mode 100644
index 0000000..f5215be
--- /dev/null
+++ b/shell_cmds/sleep/sleep.1
@@ -0,0 +1,124 @@
+.\"-
+.\" Copyright (c) 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sleep.1 8.3 (Berkeley) 4/18/94
+.\" $FreeBSD: src/bin/sleep/sleep.1,v 1.22 2005/01/16 16:41:59 ru Exp $
+.\"
+.Dd April 18, 1994
+.Dt SLEEP 1
+.Os
+.Sh NAME
+.Nm sleep
+.Nd suspend execution for an interval of time
+.Sh SYNOPSIS
+.Nm
+.Ar seconds
+.Sh DESCRIPTION
+The
+.Nm
+command
+suspends execution for a minimum of
+.Ar seconds .
+.Pp
+If the
+.Nm
+command receives a signal, it takes the standard action.
+.Sh IMPLEMENTATION NOTES
+The
+.Dv SIGALRM
+signal is not handled specially by this implementation.
+.Pp
+The
+.Nm
+command will accept and honor a non-integer number of specified seconds
+(with a
+.Ql .\&
+character as a decimal point).
+.Bf Sy
+This is a non-portable extension, and its use will nearly guarantee that
+a shell script will not execute properly on another system.
+.Ef
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+To schedule the execution of a command for
+.Va x
+number seconds later (with
+.Xr csh 1 ) :
+.Pp
+.Dl (sleep 1800; sh command_file >& errors)&
+.Pp
+This incantation would wait a half hour before
+running the script command_file.
+(See the
+.Xr at 1
+utility.)
+.Pp
+To reiteratively run a command (with the
+.Xr csh 1 ) :
+.Pp
+.Bd -literal -offset indent -compact
+while (1)
+ if (! -r zzz.rawdata) then
+ sleep 300
+ else
+ foreach i (`ls *.rawdata`)
+ sleep 70
+ awk -f collapse_data $i >> results
+ end
+ break
+ endif
+end
+.Ed
+.Pp
+The scenario for a script such as this might be: a program currently
+running is taking longer than expected to process a series of
+files, and it would be nice to have
+another program start processing the files created by the first
+program as soon as it is finished (when zzz.rawdata is created).
+The script checks every five minutes for the file zzz.rawdata,
+when the file is found, then another portion processing
+is done courteously by sleeping for 70 seconds in between each
+awk job.
+.Sh SEE ALSO
+.Xr nanosleep 2 ,
+.Xr sleep 3
+.Sh STANDARDS
+The
+.Nm
+command is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v4 .
diff --git a/shell_cmds/sleep/sleep.c b/shell_cmds/sleep/sleep.c
new file mode 100644
index 0000000..d41556c
--- /dev/null
+++ b/shell_cmds/sleep/sleep.c
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)sleep.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sleep/sleep.c,v 1.20 2005/08/07 09:11:38 stefanf Exp $");
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct timespec time_to_sleep;
+ long l;
+ int neg;
+ char *p;
+
+ if (argc == 2) {
+ p = argv[1];
+ } else if (argc == 3 && !strcmp("--", argv[1])) {
+ // POSIX issue: "sleep -- 3" should be the same as "sleep 3",
+ // normally getopt makes this kind of thing work, but sleep has
+ // no options, so we do it "the easy way"
+ p = argv[2];
+ } else {
+ usage();
+ return(1);
+ }
+
+ /* Skip over leading whitespaces. */
+ while (isspace((unsigned char)*p))
+ ++p;
+
+ /* Check for optional `+' or `-' sign. */
+ neg = 0;
+ if (*p == '-') {
+ neg = 1;
+ ++p;
+ if (!isdigit((unsigned char)*p) && *p != '.') {
+ usage();
+ return(1);
+ }
+ }
+ else if (*p == '+')
+ ++p;
+
+ /* Calculate seconds. */
+ if (isdigit((unsigned char)*p)) {
+ l = strtol(p, &p, 10);
+ if (l > INT_MAX) {
+ /*
+ * Avoid overflow when `seconds' is huge. This assumes
+ * that the maximum value for a time_t is <= INT_MAX.
+ */
+ l = INT_MAX;
+ }
+ } else
+ l = 0;
+ time_to_sleep.tv_sec = (time_t)l;
+
+ /* Calculate nanoseconds. */
+ time_to_sleep.tv_nsec = 0;
+
+ if (*p == '.') { /* Decimal point. */
+ l = 100000000L;
+ do {
+ if (isdigit((unsigned char)*++p))
+ time_to_sleep.tv_nsec += (*p - '0') * l;
+ else
+ break;
+ l /= 10;
+ } while (l);
+ }
+
+ if (!neg && (time_to_sleep.tv_sec > 0 || time_to_sleep.tv_nsec > 0))
+ (void)nanosleep(&time_to_sleep, (struct timespec *)NULL);
+
+ return(0);
+}
+
+void
+usage(void)
+{
+ const char msg[] = "usage: sleep seconds\n";
+
+ write(STDERR_FILENO, msg, sizeof(msg) - 1);
+}
diff --git a/shell_cmds/su/su.1 b/shell_cmds/su/su.1
new file mode 100644
index 0000000..014a567
--- /dev/null
+++ b/shell_cmds/su/su.1
@@ -0,0 +1,213 @@
+.\" Copyright (c) 1988, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)su.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/su/su.1,v 1.40 2007/07/24 06:41:07 delphij Exp $
+.\"
+.Dd September 13, 2006
+.Dt SU 1
+.Os
+.Sh NAME
+.Nm su
+.Nd substitute user identity
+.Sh SYNOPSIS
+.Nm
+.Op Fl
+.Op Fl flm
+.Op Ar login Op Ar args
+.Sh DESCRIPTION
+The
+.Nm
+utility requests appropriate user credentials via PAM
+and switches to that user ID
+(the default user is the superuser).
+A shell is then executed.
+.Pp
+PAM is used to set the policy
+.Xr su 1
+will use.
+In particular, by default only users in the
+.Dq Li admin
+or
+.Dq Li wheel
+groups can switch to UID 0
+.Pq Dq Li root .
+This group requirement may be changed by modifying the
+.Dq Li pam_group
+section of
+.Pa /etc/pam.d/su .
+See
+.Xr pam_group 8
+for details on how to modify this setting.
+.Pp
+By default, the environment is unmodified with the exception of
+.Ev USER ,
+.Ev HOME ,
+and
+.Ev SHELL .
+.Ev HOME
+and
+.Ev SHELL
+are set to the target login's default values.
+.Ev USER
+is set to the target login, unless the target login has a user ID of 0,
+in which case it is unmodified.
+The invoked shell is the one belonging to the target login.
+This is the traditional behavior of
+.Nm .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl f
+If the invoked shell is
+.Xr csh 1 ,
+this option prevents it from reading the
+.Dq Pa .cshrc
+file.
+.It Fl l
+Simulate a full login.
+The environment is discarded except for
+.Ev HOME ,
+.Ev SHELL ,
+.Ev PATH ,
+.Ev TERM ,
+and
+.Ev USER .
+.Ev HOME
+and
+.Ev SHELL
+are modified as above.
+.Ev USER
+is set to the target login.
+.Ev PATH
+is set to
+.Dq Pa /bin:/usr/bin .
+.Ev TERM
+is imported from your current environment.
+The invoked shell is the target login's, and
+.Nm
+will change directory to the target login's home directory.
+.It Fl
+(no letter) The same as
+.Fl l .
+.It Fl m
+Leave the environment unmodified.
+The invoked shell is your login shell, and no directory changes are made.
+As a security precaution, if the target user's shell is a non-standard
+shell (as defined by
+.Xr getusershell 3 )
+and the caller's real uid is
+non-zero,
+.Nm
+will fail.
+.El
+.Pp
+The
+.Fl l
+(or
+.Fl )
+and
+.Fl m
+options are mutually exclusive; the last one specified
+overrides any previous ones.
+.Pp
+If the optional
+.Ar args
+are provided on the command line, they are passed to the login shell of
+the target login.
+Note that all command line arguments before the target login name are
+processed by
+.Nm
+itself, everything after the target login name gets passed to the login
+shell.
+.Pp
+By default (unless the prompt is reset by a startup file) the super-user
+prompt is set to
+.Dq Sy \&#
+to remind one of its awesome power.
+.Sh ENVIRONMENT
+Environment variables used by
+.Nm :
+.Bl -tag -width HOME
+.It Ev HOME
+Default home directory of real user ID unless modified as
+specified above.
+.It Ev PATH
+Default search path of real user ID unless modified as specified above.
+.It Ev TERM
+Provides terminal type which may be retained for the substituted
+user ID.
+.It Ev USER
+The user ID is always the effective ID (the target user ID) after an
+.Nm
+unless the user ID is 0 (root).
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/pam.d/su" -compact
+.It Pa /etc/pam.d/su
+PAM configuration for
+.Nm .
+.El
+.Sh EXAMPLES
+.Bl -tag -width 5n -compact
+.It Li "su man -c catman"
+Runs the command
+.Li catman
+as user
+.Li man .
+You will be asked for man's password unless your real UID is 0.
+.It Li "su man -c 'catman /usr/share/man /usr/local/man'"
+Same as above, but the target command consists of more than a
+single word and hence is quoted for use with the
+.Fl c
+option being passed to the shell.
+(Most shells expect the argument to
+.Fl c
+to be a single word).
+.It Li "su -l foo"
+Simulate a login for user foo.
+.It Li "su - foo"
+Same as above.
+.It Li "su -"
+Simulate a login for root.
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr environ 7 ,
+.Xr pam_group 8
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/shell_cmds/su/su.c b/shell_cmds/su/su.c
new file mode 100644
index 0000000..8ad7434
--- /dev/null
+++ b/shell_cmds/su/su.c
@@ -0,0 +1,737 @@
+/*
+ * Copyright (c) 2002, 2005 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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.
+ */
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)su.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/su/su.c,v 1.91 2009/12/13 03:14:06 delphij Exp $");
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#ifdef USE_BSM_AUDIT
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#ifndef __APPLE__
+#include <login_cap.h>
+#endif /* !__APPLE__ */
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+
+#ifdef __APPLE__
+#include <bsm/audit_session.h>
+#endif /* __APPLE__ */
+
+#define PAM_END() do { \
+ int local_ret; \
+ if (pamh != NULL) { \
+ local_ret = pam_setcred(pamh, PAM_DELETE_CRED); \
+ if (local_ret != PAM_SUCCESS) \
+ syslog(LOG_ERR, "pam_setcred: %s", \
+ pam_strerror(pamh, local_ret)); \
+ if (asthem) { \
+ local_ret = pam_close_session(pamh, 0); \
+ if (local_ret != PAM_SUCCESS) \
+ syslog(LOG_ERR, "pam_close_session: %s",\
+ pam_strerror(pamh, local_ret)); \
+ } \
+ local_ret = pam_end(pamh, local_ret); \
+ if (local_ret != PAM_SUCCESS) \
+ syslog(LOG_ERR, "pam_end: %s", \
+ pam_strerror(pamh, local_ret)); \
+ } \
+} while (0)
+
+
+#define PAM_SET_ITEM(what, item) do { \
+ int local_ret; \
+ local_ret = pam_set_item(pamh, what, item); \
+ if (local_ret != PAM_SUCCESS) { \
+ syslog(LOG_ERR, "pam_set_item(" #what "): %s", \
+ pam_strerror(pamh, local_ret)); \
+ errx(1, "pam_set_item(" #what "): %s", \
+ pam_strerror(pamh, local_ret)); \
+ /* NOTREACHED */ \
+ } \
+} while (0)
+
+enum tristate { UNSET, YES, NO };
+
+static pam_handle_t *pamh = NULL;
+static char **environ_pam;
+
+static char *ontty(void);
+static int chshell(const char *);
+static void usage(void) __dead2;
+static void export_pam_environment(void);
+static int ok_to_export(const char *);
+
+extern char **environ;
+
+int
+main(int argc, char *argv[])
+{
+ static char *cleanenv;
+ struct passwd *pwd;
+ struct pam_conv conv = { openpam_ttyconv, NULL };
+ enum tristate iscsh;
+#ifndef __APPLE__
+ login_cap_t *lc;
+#endif /* !__APPLE__ */
+ union {
+ const char **a;
+ char * const *b;
+ } np;
+ uid_t ruid;
+ pid_t child_pid, child_pgrp, pid;
+ int asme, ch, asthem, fastlogin, prio, i, retcode,
+ statusp, setmaclabel;
+#ifndef __APPLE__
+ u_int setwhat;
+#endif /* !__APPLE__ */
+ char *username, *class, shellbuf[MAXPATHLEN];
+ const char *p, *user, *shell, *mytty, **nargv;
+ const void *v;
+ struct sigaction sa, sa_int, sa_quit, sa_pipe;
+ int temp, fds[2];
+#ifdef USE_BSM_AUDIT
+ const char *aerr;
+ au_id_t auid;
+#endif
+#ifdef __APPLE__
+ /* 4043304 */
+ const char *avshell;
+ char avshellbuf[MAXPATHLEN];
+#endif /* __APPLE__ */
+
+ shell = class = cleanenv = NULL;
+ asme = asthem = fastlogin = statusp = 0;
+ user = "root";
+ iscsh = UNSET;
+ setmaclabel = 0;
+
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "-flm")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "-flmsc:")) != -1)
+#endif /* __APPLE__ */
+ switch ((char)ch) {
+ case 'f':
+ fastlogin = 1;
+ break;
+ case '-':
+ case 'l':
+ asme = 0;
+ asthem = 1;
+ break;
+ case 'm':
+ asme = 1;
+ asthem = 0;
+ break;
+#ifndef __APPLE__
+ case 's':
+ setmaclabel = 1;
+ break;
+ case 'c':
+ class = optarg;
+ break;
+#endif /* !__APPLE__ */
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (optind < argc)
+ user = argv[optind++];
+
+ if (user == NULL)
+ usage();
+ /* NOTREACHED */
+
+ /*
+ * Try to provide more helpful debugging output if su(1) is running
+ * non-setuid, or was run from a file system not mounted setuid.
+ */
+ if (geteuid() != 0)
+ errx(1, "not running setuid");
+
+#ifdef USE_BSM_AUDIT
+ if (getauid(&auid) < 0 && errno != ENOSYS) {
+ syslog(LOG_AUTH | LOG_ERR, "getauid: %s", strerror(errno));
+ errx(1, "Permission denied");
+ }
+#endif
+ if (strlen(user) > MAXLOGNAME - 1) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid,
+ EPERM, 1, "username too long: '%s'", user))
+ errx(1, "Permission denied");
+#endif
+ errx(1, "username too long");
+ }
+
+ nargv = malloc(sizeof(char *) * (size_t)(argc + 4));
+ if (nargv == NULL)
+ errx(1, "malloc failure");
+
+ nargv[argc + 3] = NULL;
+ for (i = argc; i >= optind; i--)
+ nargv[i + 3] = argv[i];
+ np.a = &nargv[i + 3];
+
+ argv += optind;
+
+ errno = 0;
+ prio = getpriority(PRIO_PROCESS, 0);
+ if (errno)
+ prio = 0;
+
+ setpriority(PRIO_PROCESS, 0, -2);
+ openlog("su", LOG_CONS, LOG_AUTH);
+
+ /* get current login name, real uid and shell */
+ ruid = getuid();
+ username = getlogin();
+ pwd = getpwnam(username);
+ if (username == NULL || pwd == NULL || pwd->pw_uid != ruid)
+ pwd = getpwuid(ruid);
+ if (pwd == NULL) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1,
+ "unable to determine invoking subject: '%s'", username))
+ errx(1, "Permission denied");
+#endif
+ errx(1, "who are you?");
+ }
+
+ username = strdup(pwd->pw_name);
+ if (username == NULL)
+ err(1, "strdup failure");
+
+ if (asme) {
+ if (pwd->pw_shell != NULL && *pwd->pw_shell != '\0') {
+ /* must copy - pwd memory is recycled */
+ shell = strncpy(shellbuf, pwd->pw_shell,
+ sizeof(shellbuf));
+ shellbuf[sizeof(shellbuf) - 1] = '\0';
+ }
+ else {
+ shell = _PATH_BSHELL;
+ iscsh = NO;
+ }
+ }
+
+ /* Do the whole PAM startup thing */
+ retcode = pam_start("su", user, &conv, &pamh);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, retcode));
+ errx(1, "pam_start: %s", pam_strerror(pamh, retcode));
+ }
+
+ PAM_SET_ITEM(PAM_RUSER, username);
+
+ mytty = ttyname(STDERR_FILENO);
+ if (!mytty)
+ mytty = "tty";
+ PAM_SET_ITEM(PAM_TTY, mytty);
+
+ retcode = pam_authenticate(pamh, 0);
+ if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1, "bad su %s to %s on %s",
+ username, user, mytty))
+ errx(1, "Permission denied");
+#endif
+ syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s",
+ username, user, mytty);
+ errx(1, "Sorry");
+ }
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, 0, 0, "successful authentication"))
+ errx(1, "Permission denied");
+#endif
+ retcode = pam_get_item(pamh, PAM_USER, &v);
+ if (retcode == PAM_SUCCESS)
+ user = v;
+ else
+ syslog(LOG_ERR, "pam_get_item(PAM_USER): %s",
+ pam_strerror(pamh, retcode));
+ pwd = getpwnam(user);
+ if (pwd == NULL) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1,
+ "unknown subject: %s", user))
+ errx(1, "Permission denied");
+#endif
+ errx(1, "unknown login: %s", user);
+ }
+
+ retcode = pam_acct_mgmt(pamh, 0);
+ if (retcode == PAM_NEW_AUTHTOK_REQD) {
+ retcode = pam_chauthtok(pamh,
+ PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+ aerr = pam_strerror(pamh, retcode);
+ if (aerr == NULL)
+ aerr = "Unknown PAM error";
+ if (audit_submit(AUE_su, auid, EPERM, 1,
+ "pam_chauthtok: %s", aerr))
+ errx(1, "Permission denied");
+#endif
+ syslog(LOG_ERR, "pam_chauthtok: %s",
+ pam_strerror(pamh, retcode));
+ errx(1, "Sorry");
+ }
+ }
+ if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1, "pam_acct_mgmt: %s",
+ pam_strerror(pamh, retcode)))
+ errx(1, "Permission denied");
+#endif
+ syslog(LOG_ERR, "pam_acct_mgmt: %s",
+ pam_strerror(pamh, retcode));
+ errx(1, "Sorry");
+ }
+
+#ifndef __APPLE__
+ /* get target login information */
+ if (class == NULL)
+ lc = login_getpwclass(pwd);
+ else {
+ if (ruid != 0) {
+#ifdef USE_BSM_AUDIT
+ if (audit_submit(AUE_su, auid, EPERM, 1,
+ "only root may use -c"))
+ errx(1, "Permission denied");
+#endif
+ errx(1, "only root may use -c");
+ }
+ lc = login_getclass(class);
+ if (lc == NULL)
+ errx(1, "unknown class: %s", class);
+ }
+#endif /* !__APPLE__ */
+
+ /* if asme and non-standard target shell, must be root */
+ if (asme) {
+ if (ruid != 0 && !chshell(pwd->pw_shell))
+ errx(1, "permission denied (shell)");
+ }
+ else if (pwd->pw_shell && *pwd->pw_shell) {
+#ifdef __APPLE__
+ /* 3825554 */
+ shell = strncpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
+ shellbuf[sizeof(shellbuf) - 1] = '\0';
+#else
+ shell = pwd->pw_shell;
+#endif /* __APPLE__ */
+ iscsh = UNSET;
+ }
+ else {
+ shell = _PATH_BSHELL;
+ iscsh = NO;
+ }
+
+ /* if we're forking a csh, we want to slightly muck the args */
+ if (iscsh == UNSET) {
+ p = strrchr(shell, '/');
+ if (p)
+ ++p;
+ else
+ p = shell;
+ iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES;
+ }
+ setpriority(PRIO_PROCESS, 0, prio);
+
+ /*
+ * PAM modules might add supplementary groups in pam_setcred(), so
+ * initialize them first.
+ */
+#ifdef __APPLE__
+ if (initgroups(user, pwd->pw_gid))
+ err(1, "initgroups");
+#else
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0)
+ err(1, "setusercontext");
+#endif /* __APPLE__ */
+
+#ifdef __APPLE__
+ /* 8530846 */
+ if (asthem) {
+ auditinfo_addr_t auinfo = {
+ .ai_termid = { .at_type = AU_IPv4 },
+ .ai_asid = AU_ASSIGN_ASID,
+ .ai_auid = getuid(),
+ .ai_flags = 0,
+ };
+ if (setaudit_addr(&auinfo, sizeof(auinfo)) == 0) {
+ char session[16];
+ snprintf(session, sizeof(session), "%x", auinfo.ai_asid);
+ setenv("SECURITYSESSIONID", session, 1);
+ } else {
+ errx(1, "failed to create session.");
+ }
+ }
+#endif /* __APPLE__ */
+
+ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_setcred: %s",
+ pam_strerror(pamh, retcode));
+ errx(1, "failed to establish credentials.");
+ }
+ if (asthem) {
+ retcode = pam_open_session(pamh, 0);
+ if (retcode != PAM_SUCCESS) {
+ syslog(LOG_ERR, "pam_open_session: %s",
+ pam_strerror(pamh, retcode));
+ errx(1, "failed to open session.");
+ }
+ }
+
+ /*
+ * We must fork() before setuid() because we need to call
+ * pam_setcred(pamh, PAM_DELETE_CRED) as root.
+ */
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGINT, &sa, &sa_int);
+ sigaction(SIGQUIT, &sa, &sa_quit);
+ sigaction(SIGPIPE, &sa, &sa_pipe);
+ sa.sa_handler = SIG_DFL;
+ sigaction(SIGTSTP, &sa, NULL);
+ statusp = 1;
+ if (pipe(fds) == -1) {
+ PAM_END();
+ err(1, "pipe");
+ }
+ child_pid = fork();
+ switch (child_pid) {
+ default:
+ sa.sa_handler = SIG_IGN;
+ sigaction(SIGTTOU, &sa, NULL);
+ close(fds[0]);
+ setpgid(child_pid, child_pid);
+ if (tcgetpgrp(STDERR_FILENO) == getpgrp())
+ tcsetpgrp(STDERR_FILENO, child_pid);
+ close(fds[1]);
+ sigaction(SIGPIPE, &sa_pipe, NULL);
+ while ((pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) {
+ if (WIFSTOPPED(statusp)) {
+ child_pgrp = getpgid(child_pid);
+ if (tcgetpgrp(STDERR_FILENO) == child_pgrp)
+ tcsetpgrp(STDERR_FILENO, getpgrp());
+ kill(getpid(), SIGSTOP);
+ if (tcgetpgrp(STDERR_FILENO) == getpgrp()) {
+ child_pgrp = getpgid(child_pid);
+ tcsetpgrp(STDERR_FILENO, child_pgrp);
+ }
+ kill(child_pid, SIGCONT);
+ statusp = 1;
+ continue;
+ }
+ break;
+ }
+ tcsetpgrp(STDERR_FILENO, getpgrp());
+ if (pid == -1)
+ err(1, "waitpid");
+ PAM_END();
+ exit(WEXITSTATUS(statusp));
+ case -1:
+ PAM_END();
+ err(1, "fork");
+ case 0:
+ close(fds[1]);
+ read(fds[0], &temp, 1);
+ close(fds[0]);
+ sigaction(SIGPIPE, &sa_pipe, NULL);
+ sigaction(SIGINT, &sa_int, NULL);
+ sigaction(SIGQUIT, &sa_quit, NULL);
+
+#ifdef __APPLE__
+ if (setgid(pwd->pw_gid))
+ err(1, "setgid");
+ /* Call initgroups(2) after setgid(2) to re-establish memberd */
+ if (initgroups(user, pwd->pw_gid))
+ err(1, "initgroups");
+ if (setuid(pwd->pw_uid))
+ err(1, "setuid");
+#else
+ /*
+ * Set all user context except for: Environmental variables
+ * Umask Login records (wtmp, etc) Path
+ */
+ setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK |
+ LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP |
+ LOGIN_SETMAC);
+ /*
+ * If -s is present, also set the MAC label.
+ */
+ if (setmaclabel)
+ setwhat |= LOGIN_SETMAC;
+ /*
+ * Don't touch resource/priority settings if -m has been used
+ * or -l and -c hasn't, and we're not su'ing to root.
+ */
+ if ((asme || (!asthem && class == NULL)) && pwd->pw_uid)
+ setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
+ if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0)
+ err(1, "setusercontext");
+#endif /* __APPLE__ */
+
+ if (!asme) {
+ if (asthem) {
+ p = getenv("TERM");
+ environ = &cleanenv;
+ }
+
+ if (asthem || pwd->pw_uid)
+ setenv("USER", pwd->pw_name, 1);
+ setenv("HOME", pwd->pw_dir, 1);
+ setenv("SHELL", shell, 1);
+#ifdef __APPLE__
+ unsetenv("TMPDIR");
+#endif /* __APPLE__ */
+
+ if (asthem) {
+ /*
+ * Add any environmental variables that the
+ * PAM modules may have set.
+ */
+ environ_pam = pam_getenvlist(pamh);
+ if (environ_pam)
+ export_pam_environment();
+
+#ifdef __APPLE__
+ /* 5276965: As documented, set $PATH. */
+ setenv("PATH", "/bin:/usr/bin", 1);
+#else
+ /* set the su'd user's environment & umask */
+ setusercontext(lc, pwd, pwd->pw_uid,
+ LOGIN_SETPATH | LOGIN_SETUMASK |
+ LOGIN_SETENV);
+#endif /* __APPLE__ */
+ if (p)
+ setenv("TERM", p, 1);
+
+ p = pam_getenv(pamh, "HOME");
+ if (chdir(p ? p : pwd->pw_dir) < 0)
+ errx(1, "no directory");
+ }
+ }
+#ifndef __APPLE__
+ login_close(lc);
+#endif /* !__APPLE__ */
+
+ if (iscsh == YES) {
+ if (fastlogin)
+ *np.a-- = "-f";
+ if (asme)
+ *np.a-- = "-m";
+ }
+#ifdef __APPLE__
+ /* 4043304 */
+ if ((p = strrchr(shell, '/')) != NULL)
+ avshell = p + 1;
+ else
+ avshell = shell;
+
+ if (asthem) {
+ avshellbuf[0] = '-';
+ strlcpy(avshellbuf+1, avshell, sizeof(avshellbuf) - 1);
+ avshell = avshellbuf;
+ }
+
+ /* csh *no longer* strips the first character... */
+ *np.a = avshell;
+#else
+ /* csh strips the first character... */
+ *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su";
+#endif /* __APPLE__ */
+
+ if (ruid != 0)
+ syslog(LOG_NOTICE, "%s to %s%s", username, user,
+ ontty());
+
+ execv(shell, np.b);
+ err(1, "%s", shell);
+ }
+}
+
+static void
+export_pam_environment(void)
+{
+ char **pp;
+ char *p;
+
+ for (pp = environ_pam; *pp != NULL; pp++) {
+ if (ok_to_export(*pp)) {
+ p = strchr(*pp, '=');
+ *p = '\0';
+ setenv(*pp, p + 1, 1);
+ }
+ free(*pp);
+ }
+}
+
+/*
+ * Sanity checks on PAM environmental variables:
+ * - Make sure there is an '=' in the string.
+ * - Make sure the string doesn't run on too long.
+ * - Do not export certain variables. This list was taken from the
+ * Solaris pam_putenv(3) man page.
+ * Note that if the user is chrooted, PAM may have a better idea than we
+ * do of where her home directory is.
+ */
+static int
+ok_to_export(const char *s)
+{
+ static const char *noexport[] = {
+ "SHELL", /* "HOME", */ "LOGNAME", "MAIL", "CDPATH",
+ "IFS", "PATH", NULL
+ };
+ const char **pp;
+ size_t n;
+
+ if (strlen(s) > 1024 || strchr(s, '=') == NULL)
+ return 0;
+ if (strncmp(s, "LD_", 3) == 0)
+ return 0;
+ for (pp = noexport; *pp != NULL; pp++) {
+ n = strlen(*pp);
+ if (s[n] == '=' && strncmp(s, *pp, n) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+static void
+usage(void)
+{
+
+#ifdef __APPLE__
+ fprintf(stderr, "usage: su [-] [-flm] [login [args]]\n");
+#else
+ fprintf(stderr, "usage: su [-] [-flms] [-c class] [login [args]]\n");
+#endif /* __APPLE__ */
+ exit(1);
+ /* NOTREACHED */
+}
+
+static int
+chshell(const char *sh)
+{
+ int r;
+ char *cp;
+
+ r = 0;
+ setusershell();
+ while ((cp = getusershell()) != NULL && !r)
+ r = (strcmp(cp, sh) == 0);
+ endusershell();
+ return r;
+}
+
+static char *
+ontty(void)
+{
+ char *p;
+ static char buf[MAXPATHLEN + 4];
+
+ buf[0] = 0;
+ p = ttyname(STDERR_FILENO);
+ if (p)
+ snprintf(buf, sizeof(buf), " on %s", p);
+ return buf;
+}
diff --git a/shell_cmds/su/su.pam b/shell_cmds/su/su.pam
new file mode 100644
index 0000000..fd8a789
--- /dev/null
+++ b/shell_cmds/su/su.pam
@@ -0,0 +1,7 @@
+# su: auth account session
+auth sufficient pam_rootok.so
+auth required pam_opendirectory.so
+account required pam_group.so no_warn group=admin,wheel ruser root_only fail_safe
+account required pam_opendirectory.so no_check_shell
+password required pam_opendirectory.so
+session required pam_launchd.so
diff --git a/shell_cmds/su/su_entitlements.plist b/shell_cmds/su/su_entitlements.plist
new file mode 100644
index 0000000..a96cb44
--- /dev/null
+++ b/shell_cmds/su/su_entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.keystore.console</key>
+ <true/>
+ <key>com.apple.private.security.clear-library-validation</key>
+ <true/>
+</dict>
+</plist>
diff --git a/shell_cmds/systime/systime.1 b/shell_cmds/systime/systime.1
new file mode 100644
index 0000000..ce296b6
--- /dev/null
+++ b/shell_cmds/systime/systime.1
@@ -0,0 +1,76 @@
+.Dd April 24, 2012
+.Dt systime 1
+.Os Darwin
+.Sh NAME
+.Nm systime
+.Nd gather system-wide time during program execution
+.Sh SYNOPSIS
+.Nm
+.Op Fl P
+.Op Fl r
+.Op Fl t Ar sleep_time
+.Ar utility Op Ar argument ...
+.Nm
+.Fl p
+.Op Fl r
+.Op Fl t Ar sleep_time
+.Nm
+.Op Fl P
+.Fl u Ar user
+.Fl s Ar sys
+.Fl i Ar idle
+.Nm
+.Op Fl P
+.Op Fl r
+.Op Fl t Ar sleep_time
+.Fl T Ar target_pid
+.Sh DESCRIPTION
+.Nm
+is similar to
+.Xr time 1
+in that it allows you to execute a utility program. However after execution
+completes, it reports the system-wide time that was spent
+during that time period, instead of just the portion directly caused
+by the utility. This can be used to gather information about CPU
+utilization by kernel threads (AIO, networking) and interrupt routines
+on behalf of a program, but not directly attributed to it.
+.Pp
+The
+.Nm
+program can also be used to snapshot counters with
+.Fl p
+and then later used with
+.Fl u Fl s Fl i
+to calculate time spent during a time interval that doesn't correlate
+to a specific command execution. For example:
+.Pp
+.Bd -ragged -offset indent
+$ eval `systime -p`
+.Pp
+$ ... time passes ...
+.Pp
+$ systime -u $systime_user -s $systime_sys -i $systime_idle
+.Pp
+18.79 real 2.03 user 1.04 sys
+.Ed
+.Pp
+The
+.Nm
+program can also be used to print the usage of a process with
+.Fl T Ar target_pid
+, also printing the system wide usage
+.Pp
+.Fl P
+can be used to print time spent as a percentage of overall CPU capacity
+of the system (capped at 100%)
+.Pp
+.Fl r
+can be used to print the usage iteratively with
+.Ar sleep_time
+seconds sleep between iterations
+.Pp
+.Fl t Ar sleep_time
+can be used to specify sleep_time between iterations, defaults to 1 second if not specified.
+.Sh SEE ALSO
+.Xr time 1 ,
+.Xr top 1
diff --git a/shell_cmds/systime/systime.c b/shell_cmds/systime/systime.c
new file mode 100644
index 0000000..37cee8b
--- /dev/null
+++ b/shell_cmds/systime/systime.c
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <err.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <libproc.h>
+#include <mach/mach_time.h>
+
+static void usage(void);
+static void do_print(void);
+static void do_difftime(bool usepercent, uint64_t *olduser, uint64_t *oldsystem, uint64_t *oldidle);
+static void do_piddifftime(bool userpercent, int pid, uint64_t *old_pid_user, uint64_t *old_pid_system, uint64_t *old_pid_time);
+static kern_return_t get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle);
+static kern_return_t get_processor_count(int *ncpu);
+static mach_timebase_info_data_t timebase_info;
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ const char *optu = NULL;
+ const char *opts = NULL;
+ const char *opti = NULL;
+ const char *tpid = NULL;
+ const char *opt_sleep_time = NULL;
+ int sleep_time = 1;
+ int target_pid;
+ bool systemwide_time = false;
+ int pid;
+ int status;
+ uint64_t olduser, oldsystem, oldidle;
+ uint64_t old_pid_time;
+ uint64_t old_pid_user, old_pid_system;
+ kern_return_t kret;
+ bool usepercent = false;
+ bool recurring = false;
+
+ while ((ch = getopt(argc, argv, "PrT:t:pu:s:i:")) != -1) {
+ switch (ch) {
+ case 'P':
+ usepercent = true;
+ break;
+ case 'r':
+ recurring = true;
+ break;
+ case 't':
+ opt_sleep_time = optarg;
+ break;
+ case 'T':
+ tpid = optarg;
+ break;
+ case 'p':
+ systemwide_time = true;
+ break;
+ case 'u':
+ optu = optarg;
+ break;
+ case 's':
+ opts = optarg;
+ break;
+ case 'i':
+ opti = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ mach_timebase_info(&timebase_info);
+
+ if (opt_sleep_time) {
+ char *endstr;
+ sleep_time = (int)strtoul(opt_sleep_time, &endstr, 0);
+ if (opt_sleep_time[0] == '\0' || endstr[0] != '\0')
+ usage();
+ }
+
+ if (systemwide_time) {
+ bool first_pass = true;
+ olduser = oldsystem = oldidle = 0;
+
+ if (recurring != true) {
+ do_print();
+ exit(0);
+ }
+ do {
+ if (first_pass) {
+ do_difftime(false, &olduser, &oldsystem, &oldidle);
+ first_pass = false;
+ } else {
+ do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+ }
+ sleep(sleep_time);
+ } while (recurring);
+
+ exit(0);
+ }
+
+
+ if (tpid) {
+ char *endstr;
+ bool first_pass = true;
+
+ target_pid = (int)strtoul(tpid, &endstr, 0);
+ if (tpid[0] == '\0' || endstr[0] != '\0')
+ usage();
+
+ olduser = oldsystem = oldidle = 0;
+ old_pid_user = old_pid_system = old_pid_time = 0;
+
+ do {
+ if (first_pass) {
+ do_difftime(false, &olduser, &oldsystem, &oldidle);
+ do_piddifftime(false, target_pid, &old_pid_user, &old_pid_system, &old_pid_time);
+ first_pass = false;
+ } else {
+ do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+ do_piddifftime(usepercent, target_pid, &old_pid_user, &old_pid_system, &old_pid_time);
+ }
+
+ sleep(sleep_time);
+ } while (recurring);
+ exit(0);
+ }
+
+ if (optu || opts || opti) {
+ char *endstr;
+
+ if (!optu)
+ usage();
+ olduser = strtoull(optu, &endstr, 0);
+ if (optu[0] == '\0' || endstr[0] != '\0')
+ usage();
+
+ if (!opts)
+ usage();
+ oldsystem = strtoull(opts, &endstr, 0);
+ if (opts[0] == '\0' || endstr[0] != '\0')
+ usage();
+
+ if (!opti)
+ usage();
+ oldidle = strtoull(opti, &endstr, 0);
+ if (opti[0] == '\0' || endstr[0] != '\0')
+ usage();
+
+ do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+ exit(0);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ do {
+ kret = get_processor_time(&olduser, &oldsystem, &oldidle);
+ if (kret)
+ errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
+
+ switch(pid = vfork()) {
+ case -1: /* error */
+ perror("time");
+ exit(1);
+ /* NOTREACHED */
+ case 0: /* child */
+ execvp(*argv, argv);
+ perror(*argv);
+ _exit((errno == ENOENT) ? 127 : 126);
+ /* NOTREACHED */
+ }
+
+ /* parent */
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ while (wait(&status) != pid);
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
+
+ do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+
+ sleep(sleep_time);
+ } while (recurring);
+
+ exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
+
+ return 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: systime [-P] [-r] [-t sleep_time] utility [argument ...]\n"
+ " systime -p [-r] [-t sleep_time]\n"
+ " systime [-P] -u user -s sys -i idle\n"
+ " systime [-P] [-r] [-t sleep_time] -T target_pid\n");
+ exit(1);
+}
+
+static void
+do_print(void)
+{
+ uint64_t user, system, idle;
+ kern_return_t kret;
+
+ kret = get_processor_time(&user, &system, &idle);
+ if (kret)
+ errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
+
+ printf("systime_user=%llu\n", user);
+ printf("systime_sys=%llu\n", system);
+ printf("systime_idle=%llu\n", idle);
+}
+
+static void
+do_difftime(bool usepercent, uint64_t *olduser, uint64_t *oldsystem, uint64_t *oldidle)
+{
+ uint64_t user, system, idle;
+ uint64_t userelapsed, systemelapsed, idleelapsed, totalelapsed;
+ kern_return_t kret;
+
+ kret = get_processor_time(&user, &system, &idle);
+ if (kret)
+ errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
+
+ userelapsed = user - *olduser;
+ systemelapsed = system - *oldsystem;
+ idleelapsed = idle - *oldidle;
+ totalelapsed = userelapsed + systemelapsed + idleelapsed;
+
+ if (usepercent) {
+ fprintf(stderr, "%1.02f%% user %1.02f%% sys %1.02f%% idle\n",
+ ((double)userelapsed * 100)/totalelapsed,
+ ((double)systemelapsed * 100)/totalelapsed,
+ ((double)idleelapsed * 100)/totalelapsed);
+ } else {
+ int ncpu;
+
+ kret = get_processor_count(&ncpu);
+ if (kret)
+ errx(1, "Error getting processor count: %s (%d)", mach_error_string(kret), kret);
+
+ fprintf(stderr, "%1.02f real %1.02f user %1.02f sys\n",
+ ((double)totalelapsed) / 1000 /* ms per sec */ / ncpu,
+ ((double)userelapsed) / 1000,
+ ((double)systemelapsed) / 1000);
+ }
+ *olduser = user;
+ *oldsystem = system;
+ *oldidle = idle;
+}
+
+static void
+do_piddifftime(bool usepercent, int pid, uint64_t *old_pid_user, uint64_t *old_pid_system, uint64_t *old_pid_time)
+{
+ uint64_t pid_user, pid_system, pid_time;
+ uint64_t userelapsed, systemelapsed, totalelapsed;
+ struct proc_taskinfo info;
+ int size;
+
+ size = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &info, sizeof(info));
+ if (size == PROC_PIDTASKINFO_SIZE) {
+ pid_user = info.pti_total_user;
+ pid_system = info.pti_total_system;
+ } else {
+ fprintf(stderr, "Error in proc_pidinfo(): %s",
+ strerror(errno));
+ exit(1);
+ }
+
+ pid_time = mach_absolute_time();
+
+ userelapsed = pid_user - *old_pid_user;
+ systemelapsed = pid_system - *old_pid_system;
+ totalelapsed = pid_time - *old_pid_time;
+
+ if (usepercent) {
+ fprintf(stderr, "Pid %d: %1.02f%% user %1.02f%% sys\n",
+ pid,
+ ((double)userelapsed * 100)/totalelapsed,
+ ((double)systemelapsed * 100)/totalelapsed);
+ } else {
+ fprintf(stderr, "Pid %d: %1.02f user %1.02f sys\n",
+ pid,
+ (((double)userelapsed) * timebase_info.numer / timebase_info.denom) / 1000000000,
+ (((double)systemelapsed) * timebase_info.numer / timebase_info.denom) / 1000000000);
+ }
+
+ *old_pid_user = pid_user;
+ *old_pid_system = pid_system;
+ *old_pid_time = pid_time;
+
+}
+
+static kern_return_t
+get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle)
+{
+ host_name_port_t host;
+ kern_return_t kret;
+ host_cpu_load_info_data_t host_load;
+ mach_msg_type_number_t count;
+
+ host = mach_host_self();
+
+ count = HOST_CPU_LOAD_INFO_COUNT;
+
+ kret = host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)&host_load, &count);
+ if (kret)
+ return kret;
+
+ *user = ((uint64_t)host_load.cpu_ticks[CPU_STATE_USER]) * 10 /* ms per tick */;
+ *sys = ((uint64_t)host_load.cpu_ticks[CPU_STATE_SYSTEM]) * 10;
+ *idle = ((uint64_t)host_load.cpu_ticks[CPU_STATE_IDLE]) * 10;
+
+ return KERN_SUCCESS;
+}
+
+static kern_return_t
+get_processor_count(int *ncpu)
+{
+ host_name_port_t host;
+ kern_return_t kret;
+ host_basic_info_data_t hi;
+ mach_msg_type_number_t count;
+
+ host = mach_host_self();
+
+ count = HOST_BASIC_INFO_COUNT;
+
+ kret = host_info(host, HOST_BASIC_INFO, (host_info_t)&hi, &count);
+ if (kret)
+ return kret;
+
+ *ncpu = hi.avail_cpus;
+
+ return KERN_SUCCESS;
+}
diff --git a/shell_cmds/tee/tee.1 b/shell_cmds/tee/tee.1
new file mode 100644
index 0000000..19d2d40
--- /dev/null
+++ b/shell_cmds/tee/tee.1
@@ -0,0 +1,90 @@
+.\" $NetBSD: tee.1,v 1.5 1997/10/20 00:37:11 lukem Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tee.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt TEE 1
+.Os
+.Sh NAME
+.Nm tee
+.Nd pipe fitting
+.Sh SYNOPSIS
+.Nm
+.Op Fl ai
+.Op Ar file ...
+.Sh DESCRIPTION
+The
+.Nm
+utility copies standard input to standard output,
+making a copy in zero or more files.
+The output is unbuffered.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl a
+Append the output to the files rather than
+overwriting them.
+.It Fl i
+Ignore the
+.Dv SIGINT
+signal.
+.El
+.Pp
+The following operands are available:
+.Bl -tag -width file
+.It file
+A pathname of an output
+.Ar file .
+.El
+.Pp
+The
+.Nm
+utility takes the default action for all signals,
+except in the event of the
+.Fl i
+option.
+.Pp
+The
+.Nm
+utility exits 0 on success, and >0 if an error occurs.
+.Sh STANDARDS
+The
+.Nm
+function is expected to be
+.Tn POSIX
+.St -p1003.2
+compatible.
diff --git a/shell_cmds/tee/tee.c b/shell_cmds/tee/tee.c
new file mode 100644
index 0000000..e916d90
--- /dev/null
+++ b/shell_cmds/tee/tee.c
@@ -0,0 +1,156 @@
+/* $NetBSD: tee.c,v 1.6 1997/10/20 00:37:11 lukem Exp $ */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tee.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: tee.c,v 1.6 1997/10/20 00:37:11 lukem Exp $");
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <err.h>
+
+typedef struct _list {
+ struct _list *next;
+ int fd;
+ char *name;
+} LIST;
+LIST *head;
+
+void add __P((int, char *));
+int main __P((int, char **));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ LIST *p;
+ int n, fd, rval, wval;
+ char *bp;
+ int append, ch, exitval;
+ char *buf;
+#define BSIZE (8 * 1024)
+
+ setlocale(LC_ALL, "");
+
+ append = 0;
+ while ((ch = getopt(argc, argv, "ai")) != -1)
+ switch((char)ch) {
+ case 'a':
+ append = 1;
+ break;
+ case 'i':
+ (void)signal(SIGINT, SIG_IGN);
+ break;
+ case '?':
+ default:
+ (void)fprintf(stderr, "usage: tee [-ai] [file ...]\n");
+ exit(1);
+ }
+ argv += optind;
+ argc -= optind;
+
+ if ((buf = malloc((size_t)BSIZE)) == NULL)
+ err(1, "malloc");
+
+ add(STDOUT_FILENO, "stdout");
+
+ for (exitval = 0; *argv; ++argv)
+ if ((fd = open(*argv, append ? O_WRONLY|O_CREAT|O_APPEND :
+ O_WRONLY|O_CREAT|O_TRUNC, DEFFILEMODE)) < 0) {
+ warn("%s", *argv);
+ exitval = 1;
+ } else
+ add(fd, *argv);
+
+ while ((rval = read(STDIN_FILENO, buf, BSIZE)) > 0)
+ for (p = head; p; p = p->next) {
+ n = rval;
+ bp = buf;
+ do {
+ if ((wval = write(p->fd, bp, n)) == -1) {
+ warn("%s", p->name);
+ exitval = 1;
+ break;
+ }
+ bp += wval;
+ } while (n -= wval);
+ }
+ if (rval < 0) {
+ warn("read");
+ exitval = 1;
+ }
+
+ for (p = head; p; p = p->next) {
+ if (close(p->fd) == -1) {
+ warn("%s", p->name);
+ exitval = 1;
+ }
+ }
+
+ exit(exitval);
+}
+
+void
+add(fd, name)
+ int fd;
+ char *name;
+{
+ LIST *p;
+
+ if ((p = malloc((size_t)sizeof(LIST))) == NULL)
+ err(1, "malloc");
+ p->fd = fd;
+ p->name = name;
+ p->next = head;
+ head = p;
+}
diff --git a/shell_cmds/test/[.1 b/shell_cmds/test/[.1
new file mode 100644
index 0000000..84e0568
--- /dev/null
+++ b/shell_cmds/test/[.1
@@ -0,0 +1 @@
+.so man1/test.1
diff --git a/shell_cmds/test/test.1 b/shell_cmds/test/test.1
new file mode 100644
index 0000000..136ee57
--- /dev/null
+++ b/shell_cmds/test/test.1
@@ -0,0 +1,390 @@
+.\"-
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)test.1 8.1 (Berkeley) 5/31/93
+.\" $FreeBSD$
+.\"
+.Dd June 1, 2013
+.Dt TEST 1
+.Os
+.Sh NAME
+.Nm test ,
+.Nm \&[
+.Nd condition evaluation utility
+.Sh SYNOPSIS
+.Nm
+.Ar expression
+.Nm \&[
+.Ar expression Cm \&]
+.Sh DESCRIPTION
+The
+.Nm
+utility evaluates the expression and, if it evaluates
+to true, returns a zero (true) exit status; otherwise
+it returns 1 (false).
+If there is no expression,
+.Nm
+also
+returns 1 (false).
+.Pp
+All operators and flags are separate arguments to the
+.Nm
+utility.
+.Pp
+The following primaries are used to construct expression:
+.Bl -tag -width Ar
+.It Fl b Ar file
+True if
+.Ar file
+exists and is a block special
+file.
+.It Fl c Ar file
+True if
+.Ar file
+exists and is a character
+special file.
+.It Fl d Ar file
+True if
+.Ar file
+exists and is a directory.
+.It Fl e Ar file
+True if
+.Ar file
+exists (regardless of type).
+.It Fl f Ar file
+True if
+.Ar file
+exists and is a regular file.
+.It Fl g Ar file
+True if
+.Ar file
+exists and its set group ID flag
+is set.
+.It Fl h Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+This operator is retained for compatibility with previous versions of
+this program.
+Do not rely on its existence; use
+.Fl L
+instead.
+.It Fl k Ar file
+True if
+.Ar file
+exists and its sticky bit is set.
+.It Fl n Ar string
+True if the length of
+.Ar string
+is nonzero.
+.It Fl p Ar file
+True if
+.Ar file
+is a named pipe
+.Pq Tn FIFO .
+.It Fl r Ar file
+True if
+.Ar file
+exists and is readable.
+.It Fl s Ar file
+True if
+.Ar file
+exists and has a size greater
+than zero.
+.It Fl t Ar file_descriptor
+True if the file whose file descriptor number
+is
+.Ar file_descriptor
+is open and is associated with a terminal.
+.It Fl u Ar file
+True if
+.Ar file
+exists and its set user ID flag
+is set.
+.It Fl w Ar file
+True if
+.Ar file
+exists and is writable.
+True
+indicates only that the write flag is on.
+The file is not writable on a read-only file
+system even if this test indicates true.
+.It Fl x Ar file
+True if
+.Ar file
+exists and is executable.
+True
+indicates only that the execute flag is on.
+If
+.Ar file
+is a directory, true indicates that
+.Ar file
+can be searched.
+.It Fl z Ar string
+True if the length of
+.Ar string
+is zero.
+.It Fl L Ar file
+True if
+.Ar file
+exists and is a symbolic link.
+.It Fl O Ar file
+True if
+.Ar file
+exists and its owner matches the effective user id of this process.
+.It Fl G Ar file
+True if
+.Ar file
+exists and its group matches the effective group id of this process.
+.It Fl S Ar file
+True if
+.Ar file
+exists and is a socket.
+.It Ar file1 Fl nt Ar file2
+True if
+.Ar file1
+exists and is newer than
+.Ar file2 .
+.It Ar file1 Fl ot Ar file2
+True if
+.Ar file1
+exists and is older than
+.Ar file2 .
+.It Ar file1 Fl ef Ar file2
+True if
+.Ar file1
+and
+.Ar file2
+exist and refer to the same file.
+.It Ar string
+True if
+.Ar string
+is not the null
+string.
+.It Ar s1 Cm = Ar s2
+True if the strings
+.Ar s1
+and
+.Ar s2
+are identical.
+.It Ar s1 Cm != Ar s2
+True if the strings
+.Ar s1
+and
+.Ar s2
+are not identical.
+.It Ar s1 Cm < Ar s2
+True if string
+.Ar s1
+comes before
+.Ar s2
+based on the binary value of their characters.
+.It Ar s1 Cm > Ar s2
+True if string
+.Ar s1
+comes after
+.Ar s2
+based on the binary value of their characters.
+.It Ar n1 Fl eq Ar n2
+True if the integers
+.Ar n1
+and
+.Ar n2
+are algebraically
+equal.
+.It Ar n1 Fl ne Ar n2
+True if the integers
+.Ar n1
+and
+.Ar n2
+are not
+algebraically equal.
+.It Ar n1 Fl gt Ar n2
+True if the integer
+.Ar n1
+is algebraically
+greater than the integer
+.Ar n2 .
+.It Ar n1 Fl ge Ar n2
+True if the integer
+.Ar n1
+is algebraically
+greater than or equal to the integer
+.Ar n2 .
+.It Ar n1 Fl lt Ar n2
+True if the integer
+.Ar n1
+is algebraically less
+than the integer
+.Ar n2 .
+.It Ar n1 Fl le Ar n2
+True if the integer
+.Ar n1
+is algebraically less
+than or equal to the integer
+.Ar n2 .
+.El
+.Pp
+If
+.Ar file
+is a symbolic link,
+.Nm
+will fully dereference it and then evaluate the expression
+against the file referenced, except for the
+.Fl h
+and
+.Fl L
+primaries.
+.Pp
+These primaries can be combined with the following operators:
+.Bl -tag -width Ar
+.It Cm \&! Ar expression
+True if
+.Ar expression
+is false.
+.It Ar expression1 Fl a Ar expression2
+True if both
+.Ar expression1
+and
+.Ar expression2
+are true.
+.It Ar expression1 Fl o Ar expression2
+True if either
+.Ar expression1
+or
+.Ar expression2
+are true.
+.It Cm \&( Ar expression Cm \&)
+True if expression is true.
+.El
+.Pp
+The
+.Fl a
+operator has higher precedence than the
+.Fl o
+operator.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh GRAMMAR AMBIGUITY
+The
+.Nm
+grammar is inherently ambiguous.
+In order to assure a degree of consistency,
+the cases described in the
+.St -p1003.2 ,
+section D11.2/4.62.4, standard
+are evaluated consistently according to the rules specified in the
+standards document.
+All other cases are subject to the ambiguity in the
+command semantics.
+.Pp
+In particular, only expressions containing
+.Fl a ,
+.Fl o ,
+.Cm \&(
+or
+.Cm \&)
+can be ambiguous.
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width indent
+.It 0
+expression evaluated to true.
+.It 1
+expression evaluated to false or expression was
+missing.
+.It >1
+An error occurred.
+.El
+.Sh EXAMPLES
+Implement
+.Li test FILE1 -nt FILE2
+using only
+.Tn POSIX
+functionality:
+.Pp
+.Dl test -n \&"$(find -L -- FILE1 -prune -newer FILE2 2>/dev/null)\&"
+.Pp
+This can be modified using non-standard
+.Xr find 1
+primaries like
+.Cm -newerca
+to compare other timestamps.
+.Sh COMPATIBILITY
+For compatibility with some other implementations,
+the
+.Cm =
+primary can be substituted with
+.Cm ==
+with the same meaning.
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr expr 1 ,
+.Xr find 1 ,
+.Xr sh 1 ,
+.Xr stat 1 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm
+utility implements a superset of the
+.St -p1003.2
+specification.
+The primaries
+.Cm < ,
+.Cm == ,
+.Cm > ,
+.Fl ef ,
+.Fl nt ,
+.Fl ot ,
+.Fl G ,
+and
+.Fl O
+are extensions.
+.Sh BUGS
+Both sides are always evaluated in
+.Fl a
+and
+.Fl o .
+For instance, the writable status of
+.Pa file
+will be tested by the following command even though the former expression
+indicated false, which results in a gratuitous access to the file system:
+.Dl "[ -z abc -a -w file ]"
+To avoid this, write
+.Dl "[ -z abc ] && [ -w file ]"
diff --git a/shell_cmds/test/test.c b/shell_cmds/test/test.c
new file mode 100644
index 0000000..14bd3a3
--- /dev/null
+++ b/shell_cmds/test/test.c
@@ -0,0 +1,611 @@
+/* $NetBSD: test.c,v 1.21 1999/04/05 09:48:38 kleink Exp $ */
+
+/*-
+ * test(1); version 7-like -- author Erik Baalbergen
+ * modified by Eric Gisin to be used as built-in.
+ * modified by Arnold Robbins to add SVR3 compatibility
+ * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
+ * modified by J.T. Conklin for NetBSD.
+ *
+ * This program is in the Public Domain.
+ */
+/*
+ * Important: This file is used both as a standalone program /bin/test and
+ * as a builtin for /bin/sh (#define SHELL).
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#ifdef __APPLE__
+#include <fcntl.h>
+#endif /* __APPLE__ */
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#define eaccess(path, mode) faccessat(AT_FDCWD, path, mode, AT_EACCESS)
+#define st_mtim st_mtimespec
+#endif /* __APPLE__ */
+
+#ifdef SHELL
+#define main testcmd
+#include "bltin/bltin.h"
+#else
+#include <locale.h>
+
+static void error(const char *, ...) __dead2 __printf0like(1, 2);
+
+static void
+error(const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ verrx(2, msg, ap);
+ /*NOTREACHED*/
+ va_end(ap);
+}
+#endif
+
+/* test(1) accepts the following grammar:
+ oexpr ::= aexpr | aexpr "-o" oexpr ;
+ aexpr ::= nexpr | nexpr "-a" aexpr ;
+ nexpr ::= primary | "!" primary
+ primary ::= unary-operator operand
+ | operand binary-operator operand
+ | operand
+ | "(" oexpr ")"
+ ;
+ unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
+ "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
+
+ binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
+ "-nt"|"-ot"|"-ef";
+ operand ::= <any legal UNIX file name>
+*/
+
+enum token_types {
+ UNOP = 0x100,
+ BINOP = 0x200,
+ BUNOP = 0x300,
+ BBINOP = 0x400,
+ PAREN = 0x500
+};
+
+enum token {
+ EOI,
+ OPERAND,
+ FILRD = UNOP + 1,
+ FILWR,
+ FILEX,
+ FILEXIST,
+ FILREG,
+ FILDIR,
+ FILCDEV,
+ FILBDEV,
+ FILFIFO,
+ FILSOCK,
+ FILSYM,
+ FILGZ,
+ FILTT,
+ FILSUID,
+ FILSGID,
+ FILSTCK,
+ STREZ,
+ STRNZ,
+ FILUID,
+ FILGID,
+ FILNT = BINOP + 1,
+ FILOT,
+ FILEQ,
+ STREQ,
+ STRNE,
+ STRLT,
+ STRGT,
+ INTEQ,
+ INTNE,
+ INTGE,
+ INTGT,
+ INTLE,
+ INTLT,
+ UNOT = BUNOP + 1,
+ BAND = BBINOP + 1,
+ BOR,
+ LPAREN = PAREN + 1,
+ RPAREN
+};
+
+#define TOKEN_TYPE(token) ((token) & 0xff00)
+
+static struct t_op {
+ char op_text[4];
+ short op_num;
+} const ops [] = {
+ {"-r", FILRD},
+ {"-w", FILWR},
+ {"-x", FILEX},
+ {"-e", FILEXIST},
+ {"-f", FILREG},
+ {"-d", FILDIR},
+ {"-c", FILCDEV},
+ {"-b", FILBDEV},
+ {"-p", FILFIFO},
+ {"-u", FILSUID},
+ {"-g", FILSGID},
+ {"-k", FILSTCK},
+ {"-s", FILGZ},
+ {"-t", FILTT},
+ {"-z", STREZ},
+ {"-n", STRNZ},
+ {"-h", FILSYM}, /* for backwards compat */
+ {"-O", FILUID},
+ {"-G", FILGID},
+ {"-L", FILSYM},
+ {"-S", FILSOCK},
+ {"=", STREQ},
+ {"==", STREQ},
+ {"!=", STRNE},
+ {"<", STRLT},
+ {">", STRGT},
+ {"-eq", INTEQ},
+ {"-ne", INTNE},
+ {"-ge", INTGE},
+ {"-gt", INTGT},
+ {"-le", INTLE},
+ {"-lt", INTLT},
+ {"-nt", FILNT},
+ {"-ot", FILOT},
+ {"-ef", FILEQ},
+ {"!", UNOT},
+ {"-a", BAND},
+ {"-o", BOR},
+ {"(", LPAREN},
+ {")", RPAREN},
+ {"", 0}
+};
+
+static int nargc;
+static char **t_wp;
+static int parenlevel;
+
+static int aexpr(enum token);
+static int binop(enum token);
+static int equalf(const char *, const char *);
+static int filstat(char *, enum token);
+static int getn(const char *);
+static intmax_t getq(const char *);
+static int intcmp(const char *, const char *);
+static int isunopoperand(void);
+static int islparenoperand(void);
+static int isrparenoperand(void);
+static int newerf(const char *, const char *);
+static int nexpr(enum token);
+static int oexpr(enum token);
+static int olderf(const char *, const char *);
+static int primary(enum token);
+static void syntax(const char *, const char *);
+static enum token t_lex(char *);
+
+int
+main(int argc, char **argv)
+{
+ int res;
+ char *p;
+
+ /* radar:4689479 */
+ if (argc == 0)
+ return 1;
+
+ if ((p = strrchr(argv[0], '/')) == NULL)
+ p = argv[0];
+ else
+ p++;
+ if (strcmp(p, "[") == 0) {
+ if (strcmp(argv[--argc], "]") != 0)
+ error("missing ]");
+ argv[argc] = NULL;
+ }
+
+ /* no expression => false */
+ if (--argc <= 0)
+ return 1;
+
+#ifndef SHELL
+ (void)setlocale(LC_CTYPE, "");
+#endif
+ nargc = argc;
+ t_wp = &argv[1];
+ parenlevel = 0;
+ if (nargc == 4 && strcmp(*t_wp, "!") == 0) {
+ /* Things like ! "" -o x do not fit in the normal grammar. */
+ --nargc;
+ ++t_wp;
+ res = oexpr(t_lex(*t_wp));
+ } else
+ res = !oexpr(t_lex(*t_wp));
+
+ if (--nargc > 0)
+ syntax(*t_wp, "unexpected operator");
+
+ return res;
+}
+
+static void
+syntax(const char *op, const char *msg)
+{
+
+ if (op && *op)
+ error("%s: %s", op, msg);
+ else
+ error("%s", msg);
+}
+
+static int
+oexpr(enum token n)
+{
+ int res;
+
+ res = aexpr(n);
+ if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) == BOR)
+ return oexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) ||
+ res;
+ t_wp--;
+ nargc++;
+ return res;
+}
+
+static int
+aexpr(enum token n)
+{
+ int res;
+
+ res = nexpr(n);
+ if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) == BAND)
+ return aexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) &&
+ res;
+ t_wp--;
+ nargc++;
+ return res;
+}
+
+static int
+nexpr(enum token n)
+{
+ if (n == UNOT)
+ return !nexpr(t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL));
+ return primary(n);
+}
+
+static int
+primary(enum token n)
+{
+ enum token nn;
+ int res;
+
+ if (n == EOI)
+ return 0; /* missing expression */
+ if (n == LPAREN) {
+ parenlevel++;
+ if ((nn = t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) ==
+ RPAREN) {
+ parenlevel--;
+ return 0; /* missing expression */
+ }
+ res = oexpr(nn);
+ if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) != RPAREN)
+ syntax(NULL, "closing paren expected");
+ parenlevel--;
+ return res;
+ }
+ if (TOKEN_TYPE(n) == UNOP) {
+ /* unary expression */
+ if (--nargc == 0)
+ syntax(NULL, "argument expected"); /* impossible */
+ switch (n) {
+ case STREZ:
+ return strlen(*++t_wp) == 0;
+ case STRNZ:
+ return strlen(*++t_wp) != 0;
+ case FILTT:
+ return isatty(getn(*++t_wp));
+ default:
+ return filstat(*++t_wp, n);
+ }
+ }
+
+ nn = t_lex(nargc > 0 ? t_wp[1] : NULL);
+ if (TOKEN_TYPE(nn) == BINOP)
+ return binop(nn);
+
+ return strlen(*t_wp) > 0;
+}
+
+static int
+binop(enum token n)
+{
+ const char *opnd1, *op, *opnd2;
+
+ opnd1 = *t_wp;
+ op = nargc > 0 ? (--nargc, *++t_wp) : NULL;
+
+ if ((opnd2 = nargc > 0 ? (--nargc, *++t_wp) : NULL) == NULL)
+ syntax(op, "argument expected");
+
+ switch (n) {
+ case STREQ:
+ return strcmp(opnd1, opnd2) == 0;
+ case STRNE:
+ return strcmp(opnd1, opnd2) != 0;
+ case STRLT:
+ return strcmp(opnd1, opnd2) < 0;
+ case STRGT:
+ return strcmp(opnd1, opnd2) > 0;
+ case INTEQ:
+ return intcmp(opnd1, opnd2) == 0;
+ case INTNE:
+ return intcmp(opnd1, opnd2) != 0;
+ case INTGE:
+ return intcmp(opnd1, opnd2) >= 0;
+ case INTGT:
+ return intcmp(opnd1, opnd2) > 0;
+ case INTLE:
+ return intcmp(opnd1, opnd2) <= 0;
+ case INTLT:
+ return intcmp(opnd1, opnd2) < 0;
+ case FILNT:
+ return newerf (opnd1, opnd2);
+ case FILOT:
+ return olderf (opnd1, opnd2);
+ case FILEQ:
+ return equalf (opnd1, opnd2);
+ default:
+ abort();
+ /* NOTREACHED */
+ }
+}
+
+static int
+filstat(char *nm, enum token mode)
+{
+ struct stat s;
+
+ if (mode == FILSYM ? lstat(nm, &s) : stat(nm, &s))
+ return 0;
+
+ switch (mode) {
+ case FILRD:
+ return (eaccess(nm, R_OK) == 0);
+ case FILWR:
+ return (eaccess(nm, W_OK) == 0);
+ case FILEX:
+ /* XXX work around eaccess(2) false positives for superuser */
+ if (eaccess(nm, X_OK) != 0)
+ return 0;
+ if (S_ISDIR(s.st_mode) || geteuid() != 0)
+ return 1;
+ return (s.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0;
+ case FILEXIST:
+ return (eaccess(nm, F_OK) == 0);
+ case FILREG:
+ return S_ISREG(s.st_mode);
+ case FILDIR:
+ return S_ISDIR(s.st_mode);
+ case FILCDEV:
+ return S_ISCHR(s.st_mode);
+ case FILBDEV:
+ return S_ISBLK(s.st_mode);
+ case FILFIFO:
+ return S_ISFIFO(s.st_mode);
+ case FILSOCK:
+ return S_ISSOCK(s.st_mode);
+ case FILSYM:
+ return S_ISLNK(s.st_mode);
+ case FILSUID:
+ return (s.st_mode & S_ISUID) != 0;
+ case FILSGID:
+ return (s.st_mode & S_ISGID) != 0;
+ case FILSTCK:
+ return (s.st_mode & S_ISVTX) != 0;
+ case FILGZ:
+ return s.st_size > (off_t)0;
+ case FILUID:
+ return s.st_uid == geteuid();
+ case FILGID:
+ return s.st_gid == getegid();
+ default:
+ return 1;
+ }
+}
+
+static enum token
+t_lex(char *s)
+{
+ struct t_op const *op = ops;
+
+ if (s == 0) {
+ return EOI;
+ }
+ while (*op->op_text) {
+ if (strcmp(s, op->op_text) == 0) {
+ if (((TOKEN_TYPE(op->op_num) == UNOP ||
+ TOKEN_TYPE(op->op_num) == BUNOP)
+ && isunopoperand()) ||
+ (op->op_num == LPAREN && islparenoperand()) ||
+ (op->op_num == RPAREN && isrparenoperand()))
+ break;
+ return op->op_num;
+ }
+ op++;
+ }
+ return OPERAND;
+}
+
+static int
+isunopoperand(void)
+{
+ struct t_op const *op = ops;
+ char *s;
+ char *t;
+
+ if (nargc == 1)
+ return 1;
+ s = *(t_wp + 1);
+ if (nargc == 2)
+ return parenlevel == 1 && strcmp(s, ")") == 0;
+ t = *(t_wp + 2);
+ while (*op->op_text) {
+ if (strcmp(s, op->op_text) == 0)
+ return TOKEN_TYPE(op->op_num) == BINOP &&
+ (parenlevel == 0 || t[0] != ')' || t[1] != '\0');
+ op++;
+ }
+ return 0;
+}
+
+static int
+islparenoperand(void)
+{
+ struct t_op const *op = ops;
+ char *s;
+
+ if (nargc == 1)
+ return 1;
+ s = *(t_wp + 1);
+ if (nargc == 2)
+ return parenlevel == 1 && strcmp(s, ")") == 0;
+ if (nargc != 3)
+ return 0;
+ while (*op->op_text) {
+ if (strcmp(s, op->op_text) == 0)
+ return TOKEN_TYPE(op->op_num) == BINOP;
+ op++;
+ }
+ return 0;
+}
+
+static int
+isrparenoperand(void)
+{
+ char *s;
+
+ if (nargc == 1)
+ return 0;
+ s = *(t_wp + 1);
+ if (nargc == 2)
+ return parenlevel == 1 && strcmp(s, ")") == 0;
+ return 0;
+}
+
+/* atoi with error detection */
+static int
+getn(const char *s)
+{
+ char *p;
+ long r;
+
+ errno = 0;
+ r = strtol(s, &p, 10);
+
+ if (s == p)
+ error("%s: bad number", s);
+
+ if (errno != 0)
+ error((errno == EINVAL) ? "%s: bad number" :
+ "%s: out of range", s);
+
+ while (isspace((unsigned char)*p))
+ p++;
+
+ if (*p)
+ error("%s: bad number", s);
+
+ return (int) r;
+}
+
+/* atoi with error detection and 64 bit range */
+static intmax_t
+getq(const char *s)
+{
+ char *p;
+ intmax_t r;
+
+ errno = 0;
+ r = strtoimax(s, &p, 10);
+
+ if (s == p)
+ error("%s: bad number", s);
+
+ if (errno != 0)
+ error((errno == EINVAL) ? "%s: bad number" :
+ "%s: out of range", s);
+
+ while (isspace((unsigned char)*p))
+ p++;
+
+ if (*p)
+ error("%s: bad number", s);
+
+ return r;
+}
+
+static int
+intcmp (const char *s1, const char *s2)
+{
+ intmax_t q1, q2;
+
+
+ q1 = getq(s1);
+ q2 = getq(s2);
+
+ if (q1 > q2)
+ return 1;
+
+ if (q1 < q2)
+ return -1;
+
+ return 0;
+}
+
+static int
+newerf (const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ if (stat(f1, &b1) != 0 || stat(f2, &b2) != 0)
+ return 0;
+
+ if (b1.st_mtim.tv_sec > b2.st_mtim.tv_sec)
+ return 1;
+ if (b1.st_mtim.tv_sec < b2.st_mtim.tv_sec)
+ return 0;
+
+ return (b1.st_mtim.tv_nsec > b2.st_mtim.tv_nsec);
+}
+
+static int
+olderf (const char *f1, const char *f2)
+{
+ return (newerf(f2, f1));
+}
+
+static int
+equalf (const char *f1, const char *f2)
+{
+ struct stat b1, b2;
+
+ return (stat (f1, &b1) == 0 &&
+ stat (f2, &b2) == 0 &&
+ b1.st_dev == b2.st_dev &&
+ b1.st_ino == b2.st_ino);
+}
diff --git a/shell_cmds/test/test.plist.part b/shell_cmds/test/test.plist.part
new file mode 100644
index 0000000..e645422
--- /dev/null
+++ b/shell_cmds/test/test.plist.part
@@ -0,0 +1,19 @@
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>test</string>
+ <key>OpenSourceVersion</key>
+ <string>2013-12-05</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/bin/test/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/bin/test/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2015-07-31</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>4689479</string>
+ <string>compatibility for eaccess, st_mtim</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
diff --git a/shell_cmds/test/tests/Makefile b/shell_cmds/test/tests/Makefile
new file mode 100644
index 0000000..5ee337a
--- /dev/null
+++ b/shell_cmds/test/tests/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/bin/test
+
+TAP_TESTS_SH= legacy_test
+# Some tests in here are silently not run when the tests are executed as
+# root. Explicitly tell Kyua to drop privileges.
+#
+# TODO(jmmv): Kyua needs to do this by default, not only when explicitly
+# requested. See https://code.google.com/p/kyua/issues/detail?id=6
+TEST_METADATA.legacy_test+= required_user="unprivileged"
+
+.include <bsd.test.mk>
diff --git a/shell_cmds/test/tests/legacy_test.sh b/shell_cmds/test/tests/legacy_test.sh
new file mode 100644
index 0000000..21c74a8
--- /dev/null
+++ b/shell_cmds/test/tests/legacy_test.sh
@@ -0,0 +1,203 @@
+#!/bin/sh
+
+#-
+# Copyright (c) June 1996 Wolfram Schneider <wosch@FreeBSD.org>. Berlin.
+# 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.
+
+#
+# TEST.sh - check if test(1) or builtin test works
+#
+# $FreeBSD$
+
+enable -n test
+
+# force a specified test program, e.g. `env test=/bin/test sh regress.sh'
+: ${test=test}
+
+t ()
+{
+ # $1 -> exit code
+ # $2 -> $test expression
+
+ count=$((count+1))
+ printf "[BEGIN] test $count\n"
+ # check for syntax errors
+ syntax="`eval $test $2 2>&1`"
+ ret=$?
+ if test -n "$syntax"; then
+ printf "not ok %s - (syntax error)\n" "$count $2"
+ printf "[FAIL] test $count\n"
+ elif [ "$ret" != "$1" ]; then
+ printf "not ok %s - (got $ret, expected $1)\n" "$count $2"
+ printf "[FAIL] test $count\n"
+ else
+ printf "ok %s\n" "$count $2"
+ printf "[PASS] test $count\n"
+ fi
+}
+
+count=0
+echo "1..130"
+printf "[TEST] shell_cmds: test\n"
+
+t 0 'b = b'
+t 0 'b == b'
+t 1 'b != b'
+t 0 '\( b = b \)'
+t 0 '\( b == b \)'
+t 1 '! \( b = b \)'
+t 1 '! \( b == b \)'
+t 1 '! -f /etc/passwd'
+
+t 0 '-h = -h'
+t 0 '-o = -o'
+t 1 '-f = h'
+t 1 '-h = f'
+t 1 '-o = f'
+t 1 'f = -o'
+t 0 '\( -h = -h \)'
+t 1 '\( a = -h \)'
+t 1 '\( -f = h \)'
+t 0 '-h = -h -o a'
+t 0 '\( -h = -h \) -o 1'
+t 0 '-h = -h -o -h = -h'
+t 0 '\( -h = -h \) -o \( -h = -h \)'
+t 0 'roedelheim = roedelheim'
+t 1 'potsdam = berlin-dahlem'
+
+t 0 '-d /'
+t 0 '-d / -a a != b'
+t 1 '-z "-z"'
+t 0 '-n -n'
+
+t 0 '0'
+t 0 '\( 0 \)'
+t 0 '-E'
+t 0 '-X -a -X'
+t 0 '-XXX'
+t 0 '\( -E \)'
+t 0 'true -o X'
+t 0 'true -o -X'
+t 0 '\( \( \( a = a \) -o 1 \) -a 1 \) -a true'
+t 1 '-h /'
+t 0 '-r /'
+t 1 '-w /'
+t 0 '-x /bin/sh'
+t 0 '-c /dev/null'
+t 0 '-f /etc/passwd'
+t 0 '-s /etc/passwd'
+
+t 1 '! \( 700 -le 1000 -a -n "1" -a "20" = "20" \)'
+t 0 '100 -eq 100'
+t 0 '100 -lt 200'
+t 1 '1000 -lt 200'
+t 0 '1000 -gt 200'
+t 0 '1000 -ge 200'
+t 0 '1000 -ge 1000'
+t 1 '2 -ne 2'
+t 0 '0 -eq 0'
+t 1 '-5 -eq 5'
+t 0 '\( 0 -eq 0 \)'
+t 1 '1 -eq 0 -o a = a -a 1 -eq 0 -o a = aa'
+
+t 1 '"" -o ""'
+t 1 '"" -a ""'
+t 1 '"a" -a ""'
+t 0 '"a" -a ! ""'
+t 1 '""'
+t 0 '! ""'
+
+t 0 '!'
+t 0 '\('
+t 0 '\)'
+
+t 1 '\( = \)'
+t 0 '\( != \)'
+t 0 '\( ! \)'
+t 0 '\( \( \)'
+t 0 '\( \) \)'
+t 0 '! = !'
+t 1 '! != !'
+t 1 '-n = \)'
+t 0 '! != \)'
+t 1 '! = a'
+t 0 '! != -n'
+t 0 '! -c /etc/passwd'
+
+t 1 '! = = ='
+t 0 '! = = \)'
+t 0 '! "" -o ""'
+t 1 '! "x" -o ""'
+t 1 '! "" -o "x"'
+t 1 '! "x" -o "x"'
+t 0 '\( -f /etc/passwd \)'
+t 0 '\( ! "" \)'
+t 1 '\( ! -e \)'
+
+t 0 '0 -eq 0 -a -d /'
+t 0 '-s = "" -o "" = ""'
+t 0 '"" = "" -o -s = ""'
+t 1 '-s = "" -o -s = ""'
+t 0 '-z x -o x = "#" -o x = x'
+t 1 '-z y -o y = "#" -o y = x'
+t 0 '0 -ne 0 -o ! -f /'
+t 0 '1 -ne 0 -o ! -f /etc/passwd'
+t 1 '0 -ne 0 -o ! -f /etc/passwd'
+
+t 0 '-n ='
+t 1 '-z ='
+t 1 '! ='
+t 0 '-n -eq'
+t 1 '-z -eq'
+t 1 '! -eq'
+t 0 '-n -a'
+t 1 '-z -a'
+t 1 '! -a'
+t 0 '-n -o'
+t 1 '-z -o'
+t 1 '! -o'
+t 1 '! -n ='
+t 0 '! -z ='
+t 0 '! ! ='
+t 1 '! -n -eq'
+t 0 '! -z -eq'
+t 0 '! ! -eq'
+t 1 '! -n -a'
+t 0 '! -z -a'
+t 0 '! ! -a'
+t 1 '! -n -o'
+t 0 '! -z -o'
+t 0 '! ! -o'
+t 0 '\( -n = \)'
+t 1 '\( -z = \)'
+t 1 '\( ! = \)'
+t 0 '\( -n -eq \)'
+t 1 '\( -z -eq \)'
+t 1 '\( ! -eq \)'
+t 0 '\( -n -a \)'
+t 1 '\( -z -a \)'
+t 1 '\( ! -a \)'
+t 0 '\( -n -o \)'
+t 1 '\( -z -o \)'
+t 1 '\( ! -o \)'
diff --git a/shell_cmds/tests/regress.m4 b/shell_cmds/tests/regress.m4
new file mode 100644
index 0000000..c06caa1
--- /dev/null
+++ b/shell_cmds/tests/regress.m4
@@ -0,0 +1,59 @@
+# $FreeBSD: head/usr.bin/tests/regress.m4 263227 2014-03-16 08:04:06Z jmmv $
+
+dnl A library of routines for doing regression tests for userland utilities.
+
+dnl Start up. We initialise the exit status to 0 (no failure) and change
+dnl into the directory specified by our first argument, which is the
+dnl directory to run the tests inside.
+define(`REGRESSION_START',
+TESTDIR=$1
+if [ -z "$TESTDIR" ]; then
+ TESTDIR=.
+fi
+cd $TESTDIR
+
+STATUS=0)
+
+dnl Check $? to see if we passed or failed. The first parameter is the test
+dnl which passed or failed. It may be nil.
+define(`REGRESSION_PASSFAIL',
+if [ $? -eq 0 ]; then
+ echo "ok - $1 # Test detected no regression. (in $TESTDIR)"
+else
+ STATUS=$?
+ echo "not ok - $1 # Test failed: regression detected. See above. (in $TESTDIR)"
+fi)
+
+dnl An actual test. The first parameter is the test name. The second is the
+dnl command/commands to execute for the actual test. Their exit status is
+dnl checked. It is assumed that the test will output to stdout, and that the
+dnl output to be used to check for regression will be in regress.TESTNAME.out.
+define(`REGRESSION_TEST',
+$2 | diff -u ${SRCDIR:-.}/regress.$1.out -
+REGRESSION_PASSFAIL($1))
+
+dnl A freeform regression test. Only exit status is checked.
+define(`REGRESSION_TEST_FREEFORM',
+$2
+REGRESSION_PASSFAIL($1))
+
+dnl A regression test like REGRESSION_TEST, except only regress.out is used
+dnl for checking output differences. The first argument is the command, the
+dnl second argument (which may be empty) is the test name.
+define(`REGRESSION_TEST_ONE',
+$1 | diff -u ${SRCDIR:-.}/regress.out -
+REGRESSION_PASSFAIL($2))
+
+dnl A fatal error. This will exit with the given status (first argument) and
+dnl print the message (second argument) prefixed with the string "FATAL :" to
+dnl the error stream.
+define(`REGRESSION_FATAL',
+echo "Bail out! $2 (in $TESTDIR)" > /dev/stderr
+exit $1)
+
+dnl Cleanup. Exit with the status code of the last failure. Should probably
+dnl be the number of failed tests, but hey presto, this is what it does. This
+dnl could also clean up potential droppings, if some forms of regression tests
+dnl end up using mktemp(1) or such.
+define(`REGRESSION_END',
+exit $STATUS)
diff --git a/shell_cmds/tests/shell_cmds.plist b/shell_cmds/tests/shell_cmds.plist
new file mode 100644
index 0000000..bdeb182
--- /dev/null
+++ b/shell_cmds/tests/shell_cmds.plist
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Project</key>
+ <string>libutil</string>
+ <key>Tests</key>
+ <array>
+ <dict>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/shell_cmds/printf/legacy_test.sh</string>
+ </array>
+ <key>IgnoreOutput</key><true/>
+ <key>TestName</key><string>shell_cmds.printf</string>
+ <key>WhenToRun</key>
+ <array>
+ <string>PRESUBMISSION</string>
+ <string>NIGHTLY</string>
+ </array>
+ </dict>
+ <dict>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/shell_cmds/test/legacy_test.sh</string>
+ </array>
+ <key>TestName</key><string>shell_cmds.test</string>
+ <key>WhenToRun</key>
+ <array>
+ <string>PRESUBMISSION</string>
+ <string>NIGHTLY</string>
+ </array>
+ </dict>
+ <dict>
+ <key>Command</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>/AppleInternal/Tests/shell_cmds/time/test_time.sh</string>
+ </array>
+ <key>TestName</key><string>shell_cmds.time</string>
+ <key>WhenToRun</key>
+ <array>
+ <string>PRESUBMISSION</string>
+ <string>NIGHTLY</string>
+ </array>
+ </dict>
+ </array>
+ <key>Timeout</key>
+ <integer>30</integer>
+</dict>
+</plist>
diff --git a/shell_cmds/time/tests/test_time.sh b/shell_cmds/time/tests/test_time.sh
new file mode 100755
index 0000000..6cf002d
--- /dev/null
+++ b/shell_cmds/time/tests/test_time.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+
+set -o nounset
+
+TIME="${TIME-/usr/bin/time}"
+echo "SUITE: time(1)"
+what $TIME
+echo
+
+EXIT=0
+
+echo TEST: check real time
+
+TIME_SLEEP=`$TIME 2>&1 sleep 1 | sed -n -E 's/[ ]+([0-9]+).*/\1/p'`
+TIME_STATUS=$?
+
+if [ "$TIME_STATUS" -ne "0" ]; then
+ echo FAIL: time failed with "$TIME_STATUS"
+ EXIT=1
+fi
+
+if [ "$TIME_SLEEP" -lt "0" ]; then
+ echo FAIL: time mis-timed sleep
+ EXIT=2
+fi
+
+MONOTONIC=`sysctl -n kern.monotonic.task_thread_counting`
+if [ "$MONOTONIC" -ne "0" ]; then
+ echo TEST: check instructions retired
+
+ TIME_INSTRS=`$TIME -l 2>&1 sleep 1 | sed -E -n '/instructions/p'`
+ if [ -z "$TIME_INSTRS" ]; then
+ echo FAIL: time is not showing instructions retired
+ EXIT=3
+ fi
+else
+ echo SKIP: check instructions retired
+fi
+
+# NB: SIGINT and SIGQUIT work locally, but the automated test harnesses tries to
+# handle those signals itself before the fork.
+
+echo TEST: check child SIGUSR1
+
+TIME_USR1=`$TIME 2>&1 sh -c 'kill -USR1 $$ && sleep 5 && true'`
+TIME_STATUS=$?
+if [ "$TIME_STATUS" -eq "0" ]; then
+ echo FAIL: time should allow child to receive SIGUSR1
+ EXIT=4
+fi
+
+echo TEST: check non-existent binary
+TIME_NONEXIST=`$TIME 2>&1 ./this-wont-exist`
+TIME_STATUS=$?
+if [ "$TIME_STATUS" -ne "127" ]; then
+ echo FAIL: time should error when measuring a non-existent command
+ EXIT=5
+fi
+
+exit $EXIT
diff --git a/shell_cmds/time/time.1 b/shell_cmds/time/time.1
new file mode 100644
index 0000000..b4e7017
--- /dev/null
+++ b/shell_cmds/time/time.1
@@ -0,0 +1,116 @@
+.\" $NetBSD: time.1,v 1.7 1997/10/20 03:28:20 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)time.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt TIME 1
+.Os
+.Sh NAME
+.Nm time
+.Nd time command execution
+.Sh SYNOPSIS
+.Nm
+.Op Fl lp
+.Ar utility
+.Sh DESCRIPTION
+The
+.Nm
+utility
+executes and
+times
+.Ar utility .
+After the
+.Ar utility
+finishes,
+.Nm
+writes the total time elapsed,
+the time consumed by system overhead,
+and the time used to execute
+.Ar utility
+to the standard error stream.
+Times are reported in seconds.
+.Pp
+Available options:
+.Bl -tag -width Ds
+.It Fl l
+The contents of the
+.Em rusage
+structure are printed.
+.It Fl p
+The output is formatted as specified by
+.St -p1003.2-92 .
+.El
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh DIAGNOSTICS
+The
+.Nm
+utility shall exit with one of the following values:
+.Bl -tag -width indent
+.It 1-125
+An error occurred in the
+.Nm
+utility.
+.It 126
+The
+.Ar utility
+was found but could not be invoked.
+.It 127
+The
+.Ar utility
+could not be found.
+.El
+.Pp
+Otherwise, the exit status of
+.Nm
+shall be that of
+.Ar utility .
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr getrusage 2
+.Sh FILES
+.Bl -tag -width /usr/include/sys/resource.h -compact
+.It Pa /usr/include/sys/resource.h
+.El
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
diff --git a/shell_cmds/time/time.c b/shell_cmds/time/time.c
new file mode 100644
index 0000000..afaaed0
--- /dev/null
+++ b/shell_cmds/time/time.c
@@ -0,0 +1,245 @@
+/* $NetBSD: time.c,v 1.9 1997/10/20 03:28:21 lukem Exp $ */
+
+/*
+ * Copyright (c) 1987, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <err.h>
+#include <inttypes.h>
+#include <langinfo.h>
+#include <libproc.h>
+#include <locale.h>
+#include <sys/cdefs.h>
+#include <sysexits.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+int lflag;
+int portableflag;
+bool child_running = true;
+
+void
+child_handler(int sig)
+{
+ child_running = false;
+}
+
+int
+main(int argc, char **argv)
+{
+ int pid;
+ int ch, status, rusage_ret = -1;
+ uint64_t before_ns, after_ns, duration_ns, duration_secs, duration_frac_ns;
+ struct rusage ru;
+ struct rusage_info_v4 ruinfo;
+ sigset_t sigmask, suspmask, origmask;
+
+ lflag = 0;
+ while ((ch = getopt(argc, argv, "lp")) != -1) {
+ switch((char)ch) {
+ case 'p':
+ portableflag = 1;
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case '?':
+ default:
+ fprintf(stderr, "usage: time [-lp] <command>\n");
+ exit(1);
+ }
+ }
+
+ if (!(argc -= optind)) {
+ exit(0);
+ }
+ argv += optind;
+
+ sigemptyset(&sigmask);
+ /*
+ * Block SIGCHLD so that the check for `child_running` doesn't miss the
+ * handler before calling `sigsuspend` and blocking forever.
+ */
+ sigaddset(&sigmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigmask, &origmask);
+
+ /*
+ * Ensure child signals are handled by the parent prior to fork; otherwise,
+ * they could be missed between the child forking and calling `sigsuspend`.
+ */
+ (void)signal(SIGCHLD, child_handler);
+
+ sigemptyset(&suspmask);
+
+ before_ns = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+ /*
+ * NB: Don't add anything between these two lines -- measurement is
+ * happening now.
+ */
+ switch (pid = vfork()) {
+ case -1: /* error */
+ err(EX_OSERR, "time");
+ __builtin_unreachable();
+ case 0: /* child */
+ /*
+ * Allow the child to respond to signals by resetting to the original
+ * signal handling behavior.
+ */
+ (void)sigprocmask(SIG_SETMASK, &origmask, NULL);
+ execvp(*argv, argv);
+ perror(*argv);
+ _exit((errno == ENOENT) ? 127 : 126);
+ __builtin_unreachable();
+ default: /* parent */
+ break;
+ }
+
+ /*
+ * Let the child handle signals that normally exit.
+ */
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+
+ while (child_running) {
+ /*
+ * This would be racy, but SIGCHLD is blocked above (as part of
+ * `sigmask`.
+ */
+ sigsuspend(&suspmask);
+ }
+ /*
+ * NB: Minimize what's added between these statements to preserve the
+ * accuracy of the time measurement.
+ */
+ after_ns = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
+ if (lflag) {
+ rusage_ret = proc_pid_rusage(pid, RUSAGE_INFO_V4, (void **)&ruinfo);
+ }
+ while (wait3(&status, 0, &ru) != pid) {
+ }
+ if (!WIFEXITED(status)) {
+ fprintf(stderr, "Command terminated abnormally.\n");
+ }
+ duration_ns = after_ns - before_ns;
+ duration_secs = duration_ns / (1000 * 1000 * 1000);
+ duration_frac_ns = duration_ns - (duration_secs * 1000 * 1000 * 1000);
+
+ if (portableflag) {
+ char *radix = NULL;
+
+ setlocale(LC_ALL, "");
+
+ radix = nl_langinfo(RADIXCHAR);
+ if (!radix || radix[0] == '\0') {
+ radix = ".";
+ }
+
+ fprintf(stderr, "real %9" PRIu64 "%s%02" PRIu64 "\n",
+ duration_secs, radix, duration_frac_ns / (10 * 1000 * 1000));
+ fprintf(stderr, "user %9ld%s%02ld\n",
+ (long)ru.ru_utime.tv_sec, radix, (long)ru.ru_utime.tv_usec/10000);
+ fprintf(stderr, "sys %9ld%s%02ld\n",
+ (long)ru.ru_stime.tv_sec, radix, (long)ru.ru_stime.tv_usec/10000);
+ } else {
+ fprintf(stderr, "%9" PRIu64 ".%02" PRIu64 " real ",
+ duration_secs, duration_frac_ns / (10 * 1000 * 1000));
+ fprintf(stderr, "%9ld.%02ld user ",
+ (long)ru.ru_utime.tv_sec, (long)ru.ru_utime.tv_usec/10000);
+ fprintf(stderr, "%9ld.%02ld sys\n",
+ (long)ru.ru_stime.tv_sec, (long)ru.ru_stime.tv_usec/10000);
+ }
+
+ if (lflag) {
+ int hz = 100; /* XXX */
+ long ticks;
+
+ ticks = hz * (ru.ru_utime.tv_sec + ru.ru_stime.tv_sec) +
+ hz * (ru.ru_utime.tv_usec + ru.ru_stime.tv_usec) / 1000000;
+
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_maxrss, "maximum resident set size");
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_ixrss / ticks : 0,
+ "average shared memory size");
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_idrss / ticks : 0,
+ "average unshared data size");
+ fprintf(stderr, "%20ld %s\n", ticks ? ru.ru_isrss / ticks : 0,
+ "average unshared stack size");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_minflt, "page reclaims");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_majflt, "page faults");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_nswap, "swaps");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_inblock, "block input operations");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_oublock, "block output operations");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_msgsnd, "messages sent");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_msgrcv, "messages received");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_nsignals, "signals received");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_nvcsw, "voluntary context switches");
+ fprintf(stderr, "%20ld %s\n",
+ ru.ru_nivcsw, "involuntary context switches");
+
+ if (rusage_ret >= 0) {
+ if (ruinfo.ri_instructions > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n", ruinfo.ri_instructions,
+ "instructions retired");
+ }
+ if (ruinfo.ri_cycles > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n", ruinfo.ri_cycles,
+ "cycles elapsed");
+ }
+ if (ruinfo.ri_lifetime_max_phys_footprint > 0) {
+ fprintf(stderr, "%20" PRIu64 " %s\n",
+ ruinfo.ri_lifetime_max_phys_footprint,
+ "peak memory footprint");
+ }
+ }
+ }
+
+ exit(WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
+}
diff --git a/shell_cmds/true/true.1 b/shell_cmds/true/true.1
new file mode 100644
index 0000000..b022042
--- /dev/null
+++ b/shell_cmds/true/true.1
@@ -0,0 +1,60 @@
+.\" $NetBSD: true.1,v 1.5 1997/10/20 01:00:41 lukem Exp $
+.\"
+.\" Copyright (c) 1983, 1985, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)true.1 6.4 (Berkeley) 6/27/91
+.\" $NetBSD: true.1,v 1.5 1997/10/20 01:00:41 lukem Exp $
+.\"
+.Dd June 27, 1991
+.Dt TRUE 1
+.Os
+.Sh NAME
+.Nm true
+.Nd Return true value.
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility always returns with exit code zero.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr false 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
diff --git a/shell_cmds/true/true.c b/shell_cmds/true/true.c
new file mode 100644
index 0000000..d973485
--- /dev/null
+++ b/shell_cmds/true/true.c
@@ -0,0 +1,2 @@
+#include <stdlib.h>
+int main () { exit(0); }
diff --git a/shell_cmds/true/true.sh b/shell_cmds/true/true.sh
new file mode 100644
index 0000000..20f87ef
--- /dev/null
+++ b/shell_cmds/true/true.sh
@@ -0,0 +1,2 @@
+#! /bin/sh
+exit 0
diff --git a/shell_cmds/uname/uname.1 b/shell_cmds/uname/uname.1
new file mode 100644
index 0000000..0c62868
--- /dev/null
+++ b/shell_cmds/uname/uname.1
@@ -0,0 +1,87 @@
+.\" $NetBSD: uname.1,v 1.12 2005/03/27 18:41:22 peter Exp $
+.\"
+.\" Copyright (c) 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" from: @(#)du.1 6.13 (Berkeley) 6/20/91
+.\" $NetBSD: uname.1,v 1.12 2005/03/27 18:41:22 peter Exp $
+.\"
+.Dd November 9, 1998
+.Dt UNAME 1
+.Os
+.Sh NAME
+.Nm uname
+.Nd Print operating system name
+.Sh SYNOPSIS
+.Nm
+.Op Fl amnprsv
+.Sh DESCRIPTION
+The
+.Nm
+utility writes symbols representing one or more system characteristics
+to the standard output.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+Behave as though all of the options
+.Fl mnrsv
+were specified.
+.It Fl m
+print the machine hardware name.
+.It Fl n
+print the nodename (the nodename may be a name
+that the system is known by to a communications
+network).
+.It Fl p
+print the machine processor architecture name.
+.It Fl r
+print the operating system release.
+.It Fl s
+print the operating system name.
+.It Fl v
+print the operating system version.
+.El
+.Pp
+If no options are specified,
+.Nm
+prints the operating system name as if the
+.Fl s
+option had been specified.
+.Sh SEE ALSO
+.Xr hostname 1 ,
+.Xr machine 1 ,
+.Xr sw_vers 1 ,
+.Xr uname 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+The
+.Fl p
+option is an extension to the standard.
diff --git a/shell_cmds/uname/uname.c b/shell_cmds/uname/uname.c
new file mode 100644
index 0000000..7dadd52
--- /dev/null
+++ b/shell_cmds/uname/uname.c
@@ -0,0 +1,208 @@
+/* $NetBSD: uname.c,v 1.10 1998/11/09 13:24:05 kleink Exp $ */
+
+/*
+ * Copyright (c) 1994 Winning Strategies, 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Winning Strategies, Inc.
+ * 4. The name of Winning Strategies, Inc. 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/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: uname.c,v 1.10 1998/11/09 13:24:05 kleink Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#ifdef __APPLE__
+#include <string.h>
+#endif /* __APPLE__ */
+
+#include <sys/sysctl.h>
+#include <sys/utsname.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else /* !__APPLE__ */
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+int main __P((int, char **));
+static void usage __P((void));
+
+/* Note that PRINT_MACHINE_ARCH is excluded from PRINT_ALL! */
+#define PRINT_SYSNAME 0x01
+#define PRINT_NODENAME 0x02
+#define PRINT_RELEASE 0x04
+#define PRINT_VERSION 0x08
+#define PRINT_MACHINE 0x10
+#define PRINT_MACHINE_ARCH 0x20
+#define PRINT_ALL \
+ (PRINT_SYSNAME|PRINT_NODENAME|PRINT_RELEASE|PRINT_VERSION|PRINT_MACHINE)
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct utsname u;
+#ifndef __APPLE__
+ char machine_arch[SYS_NMLN];
+#endif /* !__APPLE__ */
+ int c;
+ int space = 0;
+ int print_mask = 0;
+
+ (void)setlocale(LC_ALL, "");
+
+ while ((c = getopt(argc,argv,"amnprsv")) != -1) {
+ switch (c) {
+ case 'a':
+ print_mask |= PRINT_ALL;
+#ifdef __APPLE__
+ if (!COMPAT_MODE("bin/uname", "Unix2003")) {
+ print_mask |= PRINT_MACHINE_ARCH;
+ }
+#endif /* __APPLE__ */
+ break;
+ case 'm':
+ print_mask |= PRINT_MACHINE;
+ break;
+ case 'n':
+ print_mask |= PRINT_NODENAME;
+ break;
+ case 'p':
+ print_mask |= PRINT_MACHINE_ARCH;
+ break;
+ case 'r':
+ print_mask |= PRINT_RELEASE;
+ break;
+ case 's':
+ print_mask |= PRINT_SYSNAME;
+ break;
+ case 'v':
+ print_mask |= PRINT_VERSION;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ if (optind != argc) {
+ usage();
+ /* NOTREACHED */
+ }
+
+ if (!print_mask) {
+ print_mask = PRINT_SYSNAME;
+ }
+
+ if (uname(&u) != 0) {
+ err(EXIT_FAILURE, "uname");
+ /* NOTREACHED */
+ }
+#ifndef __APPLE__
+ if (print_mask & PRINT_MACHINE_ARCH) {
+ int mib[2] = { CTL_HW, HW_MACHINE_ARCH };
+ size_t len = sizeof (machine_arch);
+
+ if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), machine_arch,
+ &len, NULL, 0) < 0)
+ err(EXIT_FAILURE, "sysctl");
+ }
+#endif /* !__APPLE__ */
+
+#ifdef __APPLE__
+ /*
+ * Let's allow the user to override the output of uname via the shell environment.
+ * This is a useful feature for cross-compiling (eg. during an OS bringup).
+ * Otherwise, you have to hack your kernel with the desired strings.
+ */
+ {
+ char *s;
+ s = getenv ("UNAME_SYSNAME"); if (s) strncpy (u.sysname, s, sizeof (u.sysname));
+ s = getenv ("UNAME_NODENAME"); if (s) strncpy (u.nodename, s, sizeof (u.nodename));
+ s = getenv ("UNAME_RELEASE"); if (s) strncpy (u.release, s, sizeof (u.release));
+ s = getenv ("UNAME_VERSION"); if (s) strncpy (u.version, s, sizeof (u.version));
+ s = getenv ("UNAME_MACHINE"); if (s) strncpy (u.machine, s, sizeof (u.machine));
+ }
+#endif /* __APPLE__ */
+
+ if (print_mask & PRINT_SYSNAME) {
+ space++;
+ fputs(u.sysname, stdout);
+ }
+ if (print_mask & PRINT_NODENAME) {
+ if (space++) putchar(' ');
+ fputs(u.nodename, stdout);
+ }
+ if (print_mask & PRINT_RELEASE) {
+ if (space++) putchar(' ');
+ fputs(u.release, stdout);
+ }
+ if (print_mask & PRINT_VERSION) {
+ if (space++) putchar(' ');
+ fputs(u.version, stdout);
+ }
+ if (print_mask & PRINT_MACHINE) {
+ if (space++) putchar(' ');
+ fputs(u.machine, stdout);
+ }
+ if (print_mask & PRINT_MACHINE_ARCH) {
+ if (space++) putchar(' ');
+#ifndef __APPLE__
+ fputs(machine_arch, stdout);
+#else
+#if defined(__ppc__) || defined(__ppc64__)
+ fputs("powerpc", stdout);
+#elif defined(__i386__) || defined(__x86_64__)
+ fputs("i386", stdout);
+#elif defined(__arm__) || defined(__arm64__)
+ fputs("arm", stdout);
+#else
+ fputs("unknown", stdout);
+#endif
+#endif /* __APPLE__ */
+ }
+ putchar('\n');
+
+ exit(EXIT_SUCCESS);
+ /* NOTREACHED */
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: uname [-amnprsv]\n");
+ exit(EXIT_FAILURE);
+}
diff --git a/shell_cmds/users/users.1 b/shell_cmds/users/users.1
new file mode 100644
index 0000000..5c4f872
--- /dev/null
+++ b/shell_cmds/users/users.1
@@ -0,0 +1,61 @@
+.\" $NetBSD: users.1,v 1.5 1997/10/20 02:41:21 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)users.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt USERS 1
+.Os BSD 3
+.Sh NAME
+.Nm users
+.Nd list current users
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+.Nm
+lists the login names of the users currently on the system,
+in sorted order, space separated, on a single line.
+.Sh FILES
+.Bl -tag -width /var/run/utmpx
+.It Pa /var/run/utmpx
+.El
+.Sh SEE ALSO
+.Xr finger 1 ,
+.Xr last 1 ,
+.Xr who 1 ,
+.Xr utmpx 5
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/users/users.c b/shell_cmds/users/users.c
new file mode 100644
index 0000000..ff24ecb
--- /dev/null
+++ b/shell_cmds/users/users.c
@@ -0,0 +1,123 @@
+/* $NetBSD: users.c,v 1.7 1998/02/03 04:19:15 perry Exp $ */
+
+/*
+ * Copyright (c) 1980, 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)users.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: users.c,v 1.7 1998/02/03 04:19:15 perry Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmpx.h>
+
+typedef char namebuf[_UTX_USERSIZE];
+
+int main __P((int, char **));
+int scmp __P((const void *, const void *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ namebuf *names = NULL;
+ int ncnt = 0;
+ int nmax = 0;
+ int cnt;
+ struct utmpx *ux;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ (void)fprintf(stderr, "usage: users\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+
+ setutxent();
+
+ while ((ux = getutxent()) != NULL) {
+ if (*ux->ut_user && ux->ut_type == USER_PROCESS)
+ {
+ if (ncnt >= nmax) {
+ nmax += 32;
+ names = realloc(names,
+ sizeof (*names) * nmax);
+
+ if (!names) {
+ err(1, "realloc");
+ /* NOTREACHED */
+ }
+ }
+
+ (void)strncpy(names[ncnt], ux->ut_user, _UTX_USERSIZE);
+ ++ncnt;
+ }
+ }
+
+ if (ncnt) {
+ qsort(names, ncnt, _UTX_USERSIZE, scmp);
+ (void)printf("%.*s", _UTX_USERSIZE, names[0]);
+ for (cnt = 1; cnt < ncnt; ++cnt)
+ if (strncmp(names[cnt], names[cnt - 1], _UTX_USERSIZE))
+ (void)printf(" %.*s", _UTX_USERSIZE, names[cnt]);
+ (void)printf("\n");
+ }
+ exit(0);
+}
+
+int
+scmp(p, q)
+ const void *p, *q;
+{
+ return(strncmp((char *) p, (char *) q, _UTX_USERSIZE));
+}
diff --git a/shell_cmds/w/extern.h b/shell_cmds/w/extern.h
new file mode 100644
index 0000000..8fe24bb
--- /dev/null
+++ b/shell_cmds/w/extern.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/w/extern.h,v 1.5 2002/03/22 01:42:43 imp Exp $
+ */
+
+
+extern int use_ampm;
+
+struct kinfo_proc;
+
+#ifdef __APPLE__
+#define KI_PROC(ki) (&(ki)->kp->kp_proc)
+#endif
+
+void pr_attime(time_t *, time_t *);
+int pr_idle(time_t);
+int proc_compare(struct kinfo_proc *, struct kinfo_proc *);
diff --git a/shell_cmds/w/fmt.c b/shell_cmds/w/fmt.c
new file mode 100644
index 0000000..31a6e50
--- /dev/null
+++ b/shell_cmds/w/fmt.c
@@ -0,0 +1,129 @@
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)fmt.c 8.4 (Berkeley) 4/15/94";
+#endif
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+
+//#include "ps.h"
+
+static char *cmdpart(char *);
+static char *shquote(char **);
+
+/*
+ * XXX
+ * This is a stub until marc does the real one.
+ */
+static char *
+shquote(char **argv)
+{
+ static long arg_max = -1;
+ size_t len;
+ char **p, *dst, *src;
+ static char *buf = NULL;
+
+ if (buf == NULL) {
+ if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
+ errx(1, "sysconf _SC_ARG_MAX failed");
+ if ((buf = malloc((u_int)(4 * arg_max) + 1)) == NULL)
+ errx(1, "malloc failed");
+ }
+
+ if (*argv == 0) {
+ buf[0] = 0;
+ return (buf);
+ }
+ dst = buf;
+ for (p = argv; (src = *p++) != 0; ) {
+ if (*src == 0)
+ continue;
+ len = (size_t)(4 * arg_max - (dst - buf)) / 4;
+ strvisx(dst, src, strlen(src) < len ? strlen(src) : len,
+ VIS_NL | VIS_CSTYLE);
+ while (*dst)
+ dst++;
+ if ((4 * arg_max - (dst - buf)) / 4 > 0)
+ *dst++ = ' ';
+ }
+ /* Chop off trailing space */
+ if (dst != buf && dst[-1] == ' ')
+ dst--;
+ *dst = '\0';
+ return (buf);
+}
+
+static char *
+cmdpart(char *arg0)
+{
+ char *cp;
+
+ return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
+}
+
+const char *
+fmt_argv(char **argv, char *cmd, size_t maxlen)
+{
+ size_t len;
+ char *ap, *cp;
+
+ if (argv == NULL || argv[0] == NULL) {
+ if (cmd == NULL)
+ return ("");
+ ap = NULL;
+ len = maxlen + 3;
+ } else {
+ ap = shquote(argv);
+ len = strlen(ap) + maxlen + 4;
+ }
+ cp = malloc(len);
+ if (cp == NULL)
+ return (NULL);
+ if (ap == NULL)
+ sprintf(cp, " (%.*s)", (int)maxlen, cmd);
+ else if (strncmp(cmdpart(argv[0]), cmd, maxlen) != 0)
+ sprintf(cp, "%s (%.*s)", ap, (int)maxlen, cmd);
+ else
+ (void) strcpy(cp, ap);
+ return (cp);
+}
diff --git a/shell_cmds/w/pr_time.c b/shell_cmds/w/pr_time.c
new file mode 100644
index 0000000..77d506d
--- /dev/null
+++ b/shell_cmds/w/pr_time.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/pr_time.c,v 1.19 2002/06/07 01:41:54 jmallett Exp $");
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)pr_time.c 8.2 (Berkeley) 4/4/94";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "extern.h"
+
+/*
+ * pr_attime --
+ * Print the time since the user logged in.
+ */
+void
+pr_attime(time_t *started, time_t *now)
+{
+ static char buf[256];
+ struct tm tp, tm;
+ time_t diff;
+ char fmt[20];
+
+ tp = *localtime(started);
+ tm = *localtime(now);
+ diff = *now - *started;
+
+ /* If more than a week, use day-month-year. */
+ if (diff > 86400 * 7)
+ (void)strcpy(fmt, "%d%b%y");
+
+ /* If not today, use day-hour-am/pm. */
+ else if (tm.tm_mday != tp.tm_mday ||
+ tm.tm_mon != tp.tm_mon ||
+ tm.tm_year != tp.tm_year) {
+ /* The line below does not take DST into consideration */
+ /* else if (*now / 86400 != *started / 86400) { */
+ (void)strcpy(fmt, use_ampm ? "%a%I%p" : "%a%H");
+ }
+
+ /* Default is hh:mm{am,pm}. */
+ else {
+ (void)strcpy(fmt, use_ampm ? "%l:%M%p" : "%k:%M");
+ }
+
+ (void)strftime(buf, sizeof(buf), fmt, &tp);
+ (void)printf("%-7.7s", buf);
+}
+
+/*
+ * pr_idle --
+ * Display the idle time.
+ * Returns number of excess characters that were used for long idle time.
+ */
+int
+pr_idle(time_t idle)
+{
+ /* If idle more than 36 hours, print as a number of days. */
+ if (idle >= 36 * 3600) {
+ int days = idle / 86400;
+ (void)printf(" %dday%s ", days, days > 1 ? "s" : " " );
+ if (days >= 100)
+ return (2);
+ if (days >= 10)
+ return (1);
+ }
+
+ /* If idle more than an hour, print as HH:MM. */
+ else if (idle >= 3600)
+ (void)printf(" %2d:%02d ",
+ (int)(idle / 3600), (int)((idle % 3600) / 60));
+
+ else if (idle / 60 == 0)
+ (void)printf(" - ");
+
+ /* Else print the minutes idle. */
+ else
+ (void)printf(" %2d ", (int)(idle / 60));
+
+ return (0); /* not idle longer than 9 days */
+}
diff --git a/shell_cmds/w/proc_compare.c b/shell_cmds/w/proc_compare.c
new file mode 100644
index 0000000..806f571
--- /dev/null
+++ b/shell_cmds/w/proc_compare.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)proc_compare.c 8.2 (Berkeley) 9/23/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/proc_compare.c,v 1.9 2004/04/14 09:34:17 bde Exp $");
+#endif
+
+#include <sys/param.h>
+#ifdef __APPLE__
+#include <sys/time.h>
+#endif
+#include <sys/proc.h>
+#include <sys/time.h>
+#include <sys/user.h>
+
+#include "extern.h"
+
+/*
+ * Returns 1 if p2 is "better" than p1
+ *
+ * The algorithm for picking the "interesting" process is thus:
+ *
+ * 1) Only foreground processes are eligible - implied.
+ * 2) Runnable processes are favored over anything else. The runner
+ * with the highest cpu utilization is picked (p_estcpu). Ties are
+ * broken by picking the highest pid.
+ * 3) The sleeper with the shortest sleep time is next. With ties,
+ * we pick out just "short-term" sleepers (TDF_SINTR == 0).
+ * 4) Further ties are broken by picking the highest pid.
+ *
+ * If you change this, be sure to consider making the change in the kernel
+ * too (^T in kern/tty.c).
+ *
+ * TODO - consider whether pctcpu should be used.
+ */
+
+#if !HAVE_KVM
+#define ki_estcpu p_estcpu
+#define ki_pid p_pid
+#define ki_slptime p_slptime
+#define ki_stat p_stat
+#define ki_tdflags p_tdflags
+#endif
+
+#define ISRUN(p) (((p)->ki_stat == SRUN) || ((p)->ki_stat == SIDL))
+#define TESTAB(a, b) ((a)<<1 | (b))
+#define ONLYA 2
+#define ONLYB 1
+#define BOTH 3
+
+#if HAVE_KVM
+int
+proc_compare(struct kinfo_proc *p1, struct kinfo_proc *p2)
+{
+#else
+int
+proc_compare(struct kinfo_proc *arg1, struct kinfo_proc *arg2)
+{
+ struct extern_proc* p1 = &arg1->kp_proc;
+ struct extern_proc* p2 = &arg2->kp_proc;
+#endif
+
+ if (p1 == NULL)
+ return (1);
+ /*
+ * see if at least one of them is runnable
+ */
+ switch (TESTAB(ISRUN(p1), ISRUN(p2))) {
+ case ONLYA:
+ return (0);
+ case ONLYB:
+ return (1);
+ case BOTH:
+ /*
+ * tie - favor one with highest recent cpu utilization
+ */
+ if (p2->ki_estcpu > p1->ki_estcpu)
+ return (1);
+ if (p1->ki_estcpu > p2->ki_estcpu)
+ return (0);
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
+ }
+ /*
+ * weed out zombies
+ */
+ switch (TESTAB(p1->ki_stat == SZOMB, p2->ki_stat == SZOMB)) {
+ case ONLYA:
+ return (1);
+ case ONLYB:
+ return (0);
+ case BOTH:
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
+ }
+ /*
+ * pick the one with the smallest sleep time
+ */
+ if (p2->ki_slptime > p1->ki_slptime)
+ return (0);
+ if (p1->ki_slptime > p2->ki_slptime)
+ return (1);
+#ifndef __APPLE__
+ /*
+ * favor one sleeping in a non-interruptible sleep
+ */
+ if (p1->ki_tdflags & TDF_SINTR && (p2->ki_tdflags & TDF_SINTR) == 0)
+ return (1);
+ if (p2->ki_tdflags & TDF_SINTR && (p1->ki_tdflags & TDF_SINTR) == 0)
+ return (0);
+#endif
+ return (p2->ki_pid > p1->ki_pid); /* tie - return highest pid */
+}
diff --git a/shell_cmds/w/uptime.1 b/shell_cmds/w/uptime.1
new file mode 100644
index 0000000..a2c372a
--- /dev/null
+++ b/shell_cmds/w/uptime.1
@@ -0,0 +1,52 @@
+.\" Copyright (c) 1980, 1990, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" @(#)uptime.1 8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/w/uptime.1,v 1.8 2002/05/09 11:47:40 joe Exp $
+.\"
+.Dd April 18, 1994
+.Dt UPTIME 1
+.Os
+.Sh NAME
+.Nm uptime
+.Nd show how long system has been running
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the current time,
+the length of time the system has been up,
+the number of users, and the load average of the system over the last
+1, 5, and 15 minutes.
+.Sh SEE ALSO
+.Xr w 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/w/w.1 b/shell_cmds/w/w.1
new file mode 100644
index 0000000..e94c39b
--- /dev/null
+++ b/shell_cmds/w/w.1
@@ -0,0 +1,127 @@
+.\" Copyright (c) 1980, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)w.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/w/w.1,v 1.20 2005/02/13 22:25:25 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt W 1
+.Os
+.Sh NAME
+.Nm w
+.Nd "display who is logged in and what they are doing"
+.Sh SYNOPSIS
+.Nm
+.Op Fl hin
+.Op Ar user ...
+.Sh DESCRIPTION
+The
+.Nm
+utility prints a summary of the current activity on the system,
+including what each user is doing.
+The first line displays the current time of day, how long the system has
+been running, the number of users logged into the system, and the load
+averages.
+The load average numbers give the number of jobs in the run queue averaged
+over 1, 5 and 15 minutes.
+.Pp
+The fields output are the user's login name, the name of the terminal the
+user is on, the host from which the user is logged in, the time the user
+logged on, the time since the user last typed anything,
+and the name and arguments of the current process.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl h
+Suppress the heading.
+.It Fl i
+Output is sorted by idle time.
+.El
+.Pp
+If one or more
+.Ar user
+names are specified, the output is restricted to those users.
+.Sh COMPATIBILITY
+The
+.Fl M ,
+.FL N ,
+.Fl d ,
+.Fl f ,
+.Fl l ,
+.Fl n ,
+.Fl s ,
+and
+.Fl w
+flags are no longer supported.
+.Sh SEE ALSO
+.Xr finger 1 ,
+.Xr ps 1 ,
+.Xr uptime 1 ,
+.Xr who 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
+.Sh BUGS
+The notion of the
+.Dq current process
+is muddy.
+The current algorithm is ``the highest numbered process on the terminal
+that is not ignoring interrupts, or, if there is none, the highest numbered
+process on the terminal''.
+This fails, for example, in critical sections of programs like the shell
+and editor, or when faulty programs running in the background fork and fail
+to ignore interrupts.
+(In cases where no process can be found,
+.Nm
+prints
+.Dq \- . )
+.Pp
+The
+.Tn CPU
+time is only an estimate, in particular, if someone leaves a background
+process running after logging out, the person currently on that terminal is
+.Dq charged
+with the time.
+.Pp
+Background processes are not shown, even though they account for
+much of the load on the system.
+.Pp
+Sometimes processes, typically those in the background, are printed with
+null or garbaged arguments.
+In these cases, the name of the command is printed in parentheses.
+.Pp
+The
+.Nm
+utility does not know about the new conventions for detection of background
+jobs.
+It will sometimes find a background job instead of the right one.
+.Pp
+Long hostnames and IPv6 addresses may be truncated; however, the
+.Xr who 1
+utility will display full hostnames.
diff --git a/shell_cmds/w/w.c b/shell_cmds/w/w.c
new file mode 100644
index 0000000..e493734
--- /dev/null
+++ b/shell_cmds/w/w.c
@@ -0,0 +1,776 @@
+/*-
+ * Copyright (c) 1980, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/usr.bin/w/w.c,v 1.58 2005/06/04 23:40:09 gad Exp $");
+#endif
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94";
+#endif
+
+/*
+ * w - print system status (who and what)
+ *
+ * This program is similar to the systat command on Tenex/Tops 10/20
+ *
+ */
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/tty.h>
+
+#ifndef __APPLE__
+#include <machine/cpu.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#if HAVE_KVM
+#include <kvm.h>
+#endif
+#include <langinfo.h>
+#include <libutil.h>
+#include <limits.h>
+#include <locale.h>
+#include <netdb.h>
+#include <nlist.h>
+#include <paths.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <timeconv.h>
+#include <unistd.h>
+#if HAVE_UTMPX
+#include <utmpx.h>
+/* use utmp values so formatting is the same */
+#define UT_NAMESIZE 8
+#define UT_LINESIZE 8
+#else /* HAVE_UTMPX */
+#include <utmp.h>
+#endif /* HAVE_UTMPX */
+#include <vis.h>
+
+#include <TargetConditionals.h>
+
+#include "extern.h"
+
+struct timeval boottime;
+#if !HAVE_UTMPX
+struct utmp utmp;
+#endif
+struct winsize ws;
+#if HAVE_KVM
+kvm_t *kd;
+#endif
+time_t now; /* the current time of day */
+int ttywidth; /* width of tty */
+int argwidth; /* width of tty */
+int header = 1; /* true if -h flag: don't print heading */
+#if !HAVE_UTMPX
+int nflag; /* true if -n flag: don't convert addrs */
+#endif
+#ifndef __APPLE__
+int dflag; /* true if -d flag: output debug info */
+#endif
+int sortidle; /* sort by idle time */
+int use_ampm; /* use AM/PM time */
+int use_comma; /* use comma as floats separator */
+char **sel_users; /* login array of particular users selected */
+
+/*
+ * One of these per active utmp entry.
+ */
+struct entry {
+ struct entry *next;
+#if HAVE_UTMPX
+ struct utmpx utmp;
+#else
+ struct utmp utmp;
+#endif
+ dev_t tdev; /* dev_t of terminal */
+ time_t idle; /* idle time of terminal in seconds */
+ struct kinfo_proc *kp; /* `most interesting' proc */
+ char *args; /* arg list of interesting process */
+ struct kinfo_proc *dkp; /* debug option proc list */
+} *ep, *ehead = NULL, **nextp = &ehead;
+
+#ifndef __APPLE__
+#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_udata)
+#else
+#define debugproc(p) *((struct kinfo_proc **)&(p)->ki_spare[0])
+#endif
+
+/* W_DISPHOSTSIZE should not be greater than UT_HOSTSIZE */
+#define W_DISPHOSTSIZE 16
+
+static void pr_header(time_t *, int);
+static struct stat *ttystat(char *, int);
+static void usage(int);
+static int this_is_uptime(const char *s);
+#if !HAVE_KVM
+static void w_getargv(void);
+#endif
+
+char *fmt_argv(char **, char *, int); /* ../../bin/ps/fmt.c */
+
+int
+main(int argc, char *argv[])
+{
+ struct kinfo_proc *kp;
+ struct kinfo_proc *kprocbuf;
+ struct kinfo_proc *dkp;
+ struct stat *stp;
+#if HAVE_UTMPX
+ struct utmpx *ux;
+#else
+ FILE *ut;
+#endif
+ time_t touched;
+#if HAVE_KVM
+ int ch, i, nentries, nusers, wcmd, longidle, dropgid;
+ const char *memf, *nlistf, *p;
+#else
+ int ch, i, nentries, nusers, wcmd, longidle;
+ const char *p;
+#endif /* HAVE_KVM */
+ char *x_suffix;
+#ifdef __APPLE__
+ char buf[MAXHOSTNAMELEN];
+#else
+ char buf[MAXHOSTNAMELEN], errbuf[_POSIX2_LINE_MAX];
+ char fn[MAXHOSTNAMELEN];
+#endif /* __APPLE__ */
+ char *dot;
+#if !HAVE_KVM
+ int local_error = 0, retry_count = 0;
+ size_t bufSize = 0;
+ size_t orig_bufSize = 0;
+ int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
+#endif
+
+ (void)setlocale(LC_ALL, "");
+#ifndef __APPLE__
+ use_ampm = (*nl_langinfo(T_FMT_AMPM) != '\0');
+ use_comma = (*nl_langinfo(RADIXCHAR) != ',');
+#endif
+
+ /* Are we w(1) or uptime(1)? */
+ if (this_is_uptime(argv[0]) == 0) {
+ wcmd = 0;
+ p = "";
+ } else {
+ wcmd = 1;
+ p = "dhiflM:N:nsuw";
+ }
+
+#if HAVE_KVM
+ dropgid = 0;
+ memf = nlistf = _PATH_DEVNULL;
+#endif
+ while ((ch = getopt(argc, argv, p)) != -1)
+ switch (ch) {
+#ifndef __APPLE__
+ case 'd':
+ dflag = 1;
+ break;
+#endif
+ case 'h':
+ header = 0;
+ break;
+ case 'i':
+ sortidle = 1;
+ break;
+#if HAVE_KVM
+ case 'M':
+ header = 0;
+ memf = optarg;
+ dropgid = 1;
+ break;
+ case 'N':
+ nlistf = optarg;
+ dropgid = 1;
+ break;
+#endif /* HAVE_KVM */
+#if !HAVE_UTMPX
+ case 'n':
+ nflag = 1;
+ break;
+#else /* !HAVE_UTMPX */
+ case 'n':
+#endif /* !HAVE_UTMPX */
+ case 'f': case 'l': case 's': case 'u': case 'w':
+#if !HAVE_KVM
+ case 'M': case 'N':
+#endif
+#ifdef __APPLE__
+ case 'd':
+ warnx("[-MNdflnsuw] no longer supported");
+#else
+ warnx("[-flsuw] no longer supported");
+#endif
+ /* FALLTHROUGH */
+ case '?':
+ default:
+ usage(wcmd);
+ }
+ argc -= optind;
+ argv += optind;
+
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (!(_res.options & RES_INIT))
+ res_init();
+ _res.retrans = 2; /* resolver timeout to 2 seconds per try */
+ _res.retry = 1; /* only try once.. */
+#endif
+
+#if HAVE_KVM
+ /*
+ * Discard setgid privileges if not the running kernel so that bad
+ * guys can't print interesting stuff from kernel memory.
+ */
+ if (dropgid)
+ setgid(getgid());
+
+ if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == NULL)
+ errx(1, "%s", errbuf);
+#endif
+
+ (void)time(&now);
+#if HAVE_UTMPX
+ setutxent();
+#else
+ if ((ut = fopen(_PATH_UTMP, "r")) == NULL)
+ err(1, "%s", _PATH_UTMP);
+#endif
+
+ if (*argv)
+ sel_users = argv;
+
+#if HAVE_UTMPX
+ for (nusers = 0; (ux = getutxent());) {
+ if (ux->ut_user[0] == '\0' || ux->ut_type != USER_PROCESS)
+ continue;
+ if (!(stp = ttystat(ux->ut_line, sizeof(ux->ut_line))))
+ continue; /* corrupted record */
+#else
+ for (nusers = 0; fread(&utmp, sizeof(utmp), 1, ut);) {
+ if (utmp.ut_name[0] == '\0')
+ continue;
+ if (!(stp = ttystat(utmp.ut_line, UT_LINESIZE)))
+ continue; /* corrupted record */
+#endif
+ ++nusers;
+ if (wcmd == 0)
+ continue;
+ if (sel_users) {
+ int usermatch;
+ char **user;
+
+ usermatch = 0;
+ for (user = sel_users; !usermatch && *user; user++)
+#if HAVE_UTMPX
+ if (!strncmp(ux->ut_user, *user, sizeof(ux->ut_user)))
+#else
+ if (!strncmp(utmp.ut_name, *user, UT_NAMESIZE))
+#endif
+ usermatch = 1;
+ if (!usermatch)
+ continue;
+ }
+ if ((ep = calloc(1, sizeof(struct entry))) == NULL)
+ errx(1, "calloc");
+ *nextp = ep;
+ nextp = &ep->next;
+#if HAVE_UTMPX
+ memmove(&ep->utmp, ux, sizeof(*ux));
+#else
+ memmove(&ep->utmp, &utmp, sizeof(struct utmp));
+#endif
+ ep->tdev = stp->st_rdev;
+#ifdef CPU_CONSDEV
+ /*
+ * If this is the console device, attempt to ascertain
+ * the true console device dev_t.
+ */
+ if (ep->tdev == 0) {
+ int mib[2];
+ size_t size;
+
+ mib[0] = CTL_MACHDEP;
+ mib[1] = CPU_CONSDEV;
+ size = sizeof(dev_t);
+ (void)sysctl(mib, 2, &ep->tdev, &size, NULL, 0);
+ }
+#endif
+ touched = stp->st_atime;
+#ifdef __APPLE__
+ if (touched < ep->utmp.ut_tv.tv_sec) {
+ /* tty untouched since before login */
+ touched = ep->utmp.ut_tv.tv_sec;
+ }
+#else
+ if (touched < ep->utmp.ut_time) {
+ /* tty untouched since before login */
+ touched = ep->utmp.ut_time;
+ }
+#endif
+ if ((ep->idle = now - touched) < 0)
+ ep->idle = 0;
+ }
+#if HAVE_UTMPX
+ endutxent();
+#else
+ (void)fclose(ut);
+#endif
+
+ if (header || wcmd == 0) {
+ pr_header(&now, nusers);
+ if (wcmd == 0) {
+#if HAVE_KVM
+ (void)kvm_close(kd);
+#endif
+ exit(0);
+ }
+
+#define HEADER_USER "USER"
+#define HEADER_TTY "TTY"
+#define HEADER_FROM "FROM"
+#define HEADER_LOGIN_IDLE "LOGIN@ IDLE "
+#define HEADER_WHAT "WHAT\n"
+#define WUSED (UT_NAMESIZE + UT_LINESIZE + W_DISPHOSTSIZE + \
+ sizeof(HEADER_LOGIN_IDLE) + 3) /* header width incl. spaces */
+ (void)printf("%-*.*s %-*.*s %-*.*s %s",
+ UT_NAMESIZE, UT_NAMESIZE, HEADER_USER,
+ UT_LINESIZE, UT_LINESIZE, HEADER_TTY,
+ W_DISPHOSTSIZE, W_DISPHOSTSIZE, HEADER_FROM,
+ HEADER_LOGIN_IDLE HEADER_WHAT);
+ }
+
+#if HAVE_KVM
+ if ((kp = kvm_getprocs(kd, KERN_PROC_ALL, 0, &nentries)) == NULL)
+ err(1, "%s", kvm_geterr(kd));
+#else
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ mib[3] = 0;
+
+ if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0) {
+ perror("Failure calling sysctl");
+ exit(1);
+ }
+
+ kprocbuf = kp = (struct kinfo_proc *)malloc(bufSize);
+
+ retry_count = 0;
+ orig_bufSize = bufSize;
+ for (retry_count = 0; ; retry_count++) {
+ local_error = 0;
+ bufSize = orig_bufSize;
+ if ((local_error = sysctl(mib, 4, kp, &bufSize, NULL, 0)) < 0) {
+ if (retry_count < 1000) {
+ sleep(1);
+ continue;
+ }
+ perror("Failure calling sysctl");
+ exit(1);
+ } else if (local_error == 0) {
+ break;
+ }
+ sleep(1);
+ }
+ nentries = bufSize / sizeof(struct kinfo_proc);
+#endif /* !HAVE_KVM */
+
+#if !HAVE_KVM
+#define ki_stat kp_proc.p_stat
+#define ki_pgid kp_eproc.e_pgid
+#define ki_tpgid kp_eproc.e_tpgid
+#define ki_tdev kp_eproc.e_tdev
+#endif /* !HAVE_KVM */
+ for (i = 0; i < nentries; i++, kp++) {
+ if (kp->ki_stat == SIDL || kp->ki_stat == SZOMB)
+ continue;
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+ if (ep->tdev == kp->ki_tdev) {
+ /*
+ * proc is associated with this terminal
+ */
+ if (ep->kp == NULL && kp->ki_pgid == kp->ki_tpgid) {
+ /*
+ * Proc is 'most interesting'
+ */
+ if (proc_compare(ep->kp, kp))
+ ep->kp = kp;
+ }
+ /*
+ * Proc debug option info; add to debug
+ * list using kinfo_proc ki_spare[0]
+ * as next pointer; ptr to ptr avoids the
+ * ptr = long assumption.
+ */
+ dkp = ep->dkp;
+ ep->dkp = kp;
+#ifndef __APPLE__
+ debugproc(kp) = dkp;
+#endif
+ }
+ }
+ }
+ if ((ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == -1 &&
+ ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) == -1 &&
+ ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1) || ws.ws_col == 0)
+ ttywidth = 79;
+ else
+ ttywidth = ws.ws_col - 1;
+ argwidth = ttywidth - WUSED;
+ if (argwidth < 4)
+ argwidth = 8;
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+ if (ep->kp == NULL) {
+ ep->args = strdup("-");
+ continue;
+ }
+#if HAVE_KVM
+ ep->args = fmt_argv(kvm_getargv(kd, ep->kp, argwidth),
+ ep->kp->ki_comm, MAXCOMLEN);
+#else
+ w_getargv();
+#endif /* HAVE_KVM */
+ if (ep->args == NULL)
+ err(1, NULL);
+ }
+ /* sort by idle time */
+ if (sortidle && ehead != NULL) {
+ struct entry *from, *save;
+
+ from = ehead;
+ ehead = NULL;
+ while (from != NULL) {
+ for (nextp = &ehead;
+ (*nextp) && from->idle >= (*nextp)->idle;
+ nextp = &(*nextp)->next)
+ continue;
+ save = from;
+ from = from->next;
+ save->next = *nextp;
+ *nextp = save;
+ }
+ }
+
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+#if HAVE_UTMPX
+ char host_buf[sizeof(ep->utmp.ut_host) + 1];
+ strlcpy(host_buf, ep->utmp.ut_host, sizeof(host_buf));
+#else
+ char host_buf[UT_HOSTSIZE + 1];
+ struct sockaddr_storage ss;
+ struct sockaddr *sa = (struct sockaddr *)&ss;
+ struct sockaddr_in *lsin = (struct sockaddr_in *)&ss;
+ struct sockaddr_in6 *lsin6 = (struct sockaddr_in6 *)&ss;
+ time_t t;
+ int isaddr;
+
+ host_buf[UT_HOSTSIZE] = '\0';
+ strncpy(host_buf, ep->utmp.ut_host, UT_HOSTSIZE);
+#endif /* HAVE_UTMPX */
+ p = *host_buf ? host_buf : "-";
+ if ((x_suffix = strrchr(p, ':')) != NULL) {
+ if ((dot = strchr(x_suffix, '.')) != NULL &&
+ strchr(dot+1, '.') == NULL)
+ *x_suffix++ = '\0';
+ else
+ x_suffix = NULL;
+ }
+#if !HAVE_UTMPX
+ if (!nflag) {
+ /* Attempt to change an IP address into a name */
+ isaddr = 0;
+ memset(&ss, '\0', sizeof(ss));
+ if (inet_pton(AF_INET6, p, &lsin6->sin6_addr) == 1) {
+ lsin6->sin6_len = sizeof(*lsin6);
+ lsin6->sin6_family = AF_INET6;
+ isaddr = 1;
+ } else if (inet_pton(AF_INET, p, &lsin->sin_addr) == 1) {
+ lsin->sin_len = sizeof(*lsin);
+ lsin->sin_family = AF_INET;
+ isaddr = 1;
+ }
+ if (isaddr && realhostname_sa(fn, sizeof(fn), sa,
+ sa->sa_len) == HOSTNAME_FOUND)
+ p = fn;
+ }
+#endif /* !HAVE_UTMPX */
+ if (x_suffix) {
+ (void)snprintf(buf, sizeof(buf), "%s:%s", p, x_suffix);
+ p = buf;
+ }
+#ifndef __APPLE__
+ if (dflag) {
+ for (dkp = ep->dkp; dkp != NULL; dkp = debugproc(dkp)) {
+ const char *ptr;
+
+ ptr = fmt_argv(kvm_getargv(kd, dkp, argwidth),
+ dkp->ki_comm, MAXCOMLEN);
+ if (ptr == NULL)
+ ptr = "-";
+ (void)printf("\t\t%-9d %s\n",
+ dkp->ki_pid, ptr);
+ }
+ }
+#endif /* !__APPLE__ */
+ (void)printf("%-*.*s %-*.*s %-*.*s ",
+#if HAVE_UTMPX
+ UT_NAMESIZE, (int)sizeof(ep->utmp.ut_user), ep->utmp.ut_user,
+ UT_LINESIZE, (int)sizeof(ep->utmp.ut_line),
+#else
+ UT_NAMESIZE, UT_NAMESIZE, ep->utmp.ut_name,
+ UT_LINESIZE, UT_LINESIZE,
+#endif
+ strncmp(ep->utmp.ut_line, "tty", 3) &&
+ strncmp(ep->utmp.ut_line, "cua", 3) ?
+ ep->utmp.ut_line : ep->utmp.ut_line + 3,
+ W_DISPHOSTSIZE, W_DISPHOSTSIZE, *p ? p : "-");
+#ifdef __APPLE__
+ pr_attime(&ep->utmp.ut_tv.tv_sec, &now);
+#else
+ t = _time_to_time32(ep->utmp.ut_time);
+ pr_attime(&t, &now);
+#endif
+ longidle = pr_idle(ep->idle);
+ (void)printf("%.*s\n", argwidth - longidle, ep->args);
+#ifdef __APPLE__
+ free(ep->args);
+#endif
+ }
+#if HAVE_KVM
+ (void)kvm_close(kd);
+#else
+ free(kprocbuf);
+#endif /* HAVE_KVM */
+ exit(0);
+}
+
+static void
+pr_header(time_t *nowp, int nusers)
+{
+ double avenrun[3];
+ time_t uptime;
+ int days, hrs, i, mins, secs;
+ int mib[2];
+ size_t size;
+ char buf[256];
+
+ /*
+ * Print time of day.
+ */
+ if (strftime(buf, sizeof(buf),
+ use_ampm ? "%l:%M%p" : "%k:%M", localtime(nowp)) != 0)
+ (void)printf("%s ", buf);
+ /*
+ * Print how long system has been up.
+ * (Found by looking getting "boottime" from the kernel)
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_BOOTTIME;
+ size = sizeof(boottime);
+ if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
+ boottime.tv_sec != 0) {
+ uptime = now - boottime.tv_sec;
+ if (uptime > 60)
+ uptime += 30;
+ days = uptime / 86400;
+ uptime %= 86400;
+ hrs = uptime / 3600;
+ uptime %= 3600;
+ mins = uptime / 60;
+ secs = uptime % 60;
+ (void)printf(" up");
+ if (days > 0)
+ (void)printf(" %d day%s,", days, days > 1 ? "s" : "");
+ if (hrs > 0 && mins > 0)
+ (void)printf(" %2d:%02d,", hrs, mins);
+ else if (hrs > 0)
+ (void)printf(" %d hr%s,", hrs, hrs > 1 ? "s" : "");
+ else if (mins > 0)
+ (void)printf(" %d min%s,", mins, mins > 1 ? "s" : "");
+ else
+ (void)printf(" %d sec%s,", secs, secs > 1 ? "s" : "");
+ }
+
+ /* Print number of users logged in to system */
+ (void)printf(" %d user%s", nusers, nusers == 1 ? "" : "s");
+
+ /*
+ * Print 1, 5, and 15 minute load averages.
+ */
+ if (getloadavg(avenrun, sizeof(avenrun) / sizeof(avenrun[0])) == -1)
+ (void)printf(", no load average information available\n");
+ else {
+ (void)printf(", load averages:");
+ for (i = 0; i < (int)(sizeof(avenrun) / sizeof(avenrun[0])); i++) {
+ if (use_comma && i > 0)
+ (void)printf(",");
+ (void)printf(" %.2f", avenrun[i]);
+ }
+ (void)printf("\n");
+ }
+}
+
+static struct stat *
+ttystat(char *line, int sz)
+{
+ static struct stat sb;
+ char ttybuf[MAXPATHLEN];
+
+ (void)snprintf(ttybuf, sizeof(ttybuf), "%s%.*s", _PATH_DEV, sz, line);
+ if (stat(ttybuf, &sb) == 0) {
+ return (&sb);
+ } else {
+ warn("%s", ttybuf);
+ return (NULL);
+ }
+}
+
+static void
+usage(int wcmd)
+{
+ if (wcmd)
+ (void)fprintf(stderr,
+ "usage: w [hi] [user ...]\n");
+ else
+ (void)fprintf(stderr, "usage: uptime\n");
+ exit(1);
+}
+
+static int
+this_is_uptime(const char *s)
+{
+ const char *u;
+
+ if ((u = strrchr(s, '/')) != NULL)
+ ++u;
+ else
+ u = s;
+ if (strcmp(u, "uptime") == 0)
+ return (0);
+ return (-1);
+}
+
+#if !HAVE_KVM
+static void
+w_getargv(void)
+{
+ int mib[3], argmax;
+ size_t size;
+ char *procargs, *sp, *np, *cp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_ARGMAX;
+
+ size = sizeof(argmax);
+ if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) {
+ goto ERROR;
+ }
+
+ procargs = malloc(argmax);
+ if (procargs == NULL) {
+ goto ERROR;
+ }
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROCARGS;
+ mib[2] = KI_PROC(ep)->p_pid;
+
+ size = (size_t)argmax;
+ if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
+ goto ERROR_FREE;
+ }
+
+ for (cp = procargs; cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ break;
+ }
+ }
+ if (cp == &procargs[size]) {
+ goto ERROR_FREE;
+ }
+
+ sp = cp;
+
+ for (np = NULL; cp < &procargs[size]; cp++) {
+ if (*cp == '\0') {
+ if (np != NULL) {
+ *np = ' ';
+ }
+ np = cp;
+ } else if (*cp == '=') {
+ break;
+ }
+ }
+
+ for (np = sp; (np < &procargs[size]) && (*np == ' '); np++);
+
+ ep->args = strdup(np);
+ free(procargs);
+ return;
+
+ERROR_FREE:
+ free(procargs);
+ERROR:
+/*
+ ep->args = malloc(2);
+ ep->args[0] = '-';
+ ep->args[1] = '\0';
+*/
+ asprintf(&ep->args, "%s", KI_PROC(ep)->p_comm);
+ return;
+}
+#endif /* HAVE_KVM */
diff --git a/shell_cmds/what/what.1 b/shell_cmds/what/what.1
new file mode 100644
index 0000000..fff56be
--- /dev/null
+++ b/shell_cmds/what/what.1
@@ -0,0 +1,70 @@
+.\" $NetBSD: what.1,v 1.4 1997/10/20 03:16:30 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)what.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt WHAT 1
+.Os BSD 4
+.Sh NAME
+.Nm what
+.Nd "show what versions of object modules were used to construct a file"
+.Sh SYNOPSIS
+.Nm
+.Ar name Ar ...
+.Sh DESCRIPTION
+.Nm
+reads each file
+.Ar name
+and searches for sequences of the form
+.Dq \&@(#) ,
+as inserted by the source code control system. It prints the remainder
+of the string following this marker, up to a null character, newline, double
+quote, or
+.Dq \&> character.
+.Sh BUGS
+As
+.Bx
+is not licensed to distribute
+.Tn SCCS .
+This is a rewrite of the
+.Nm
+command which is part of
+.Tn SCCS ;
+it may not behave in exactly the same manner as that
+command does.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/shell_cmds/what/what.c b/shell_cmds/what/what.c
new file mode 100644
index 0000000..2f70e2d
--- /dev/null
+++ b/shell_cmds/what/what.c
@@ -0,0 +1,97 @@
+/* $NetBSD: what.c,v 1.6 1997/10/20 03:16:31 lukem Exp $ */
+
+/*
+ * Copyright (c) 1980, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)what.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: what.c,v 1.6 1997/10/20 03:16:31 lukem Exp $");
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void search __P((void));
+int main __P((int, char **));
+
+/*
+ * what
+ */
+/* ARGSUSED */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ if (!*++argv)
+ search();
+ else do {
+ if (!freopen(*argv, "r", stdin)) {
+ perror(*argv);
+ exit(1);
+ }
+ printf("%s\n", *argv);
+ search();
+ } while(*++argv);
+ exit(0);
+}
+
+void
+search()
+{
+ int c;
+
+ while ((c = getchar()) != EOF) {
+loop: if (c != '@')
+ continue;
+ if ((c = getchar()) != '(')
+ goto loop;
+ if ((c = getchar()) != '#')
+ goto loop;
+ if ((c = getchar()) != ')')
+ goto loop;
+ putchar('\t');
+ while ((c = getchar()) != EOF && c && c != '"' &&
+ c != '>' && c != '\n')
+ putchar(c);
+ putchar('\n');
+ }
+}
diff --git a/shell_cmds/whereis/whereis.1 b/shell_cmds/whereis/whereis.1
new file mode 100644
index 0000000..4df4b27
--- /dev/null
+++ b/shell_cmds/whereis/whereis.1
@@ -0,0 +1,70 @@
+.\" $NetBSD: whereis.1,v 1.7 1998/02/06 06:20:06 perry Exp $
+.\"
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)whereis.1 8.3 (Berkeley) 4/27/95
+.\"
+.Dd April 27, 1995
+.Dt WHEREIS 1
+.Os
+.Sh NAME
+.Nm whereis
+.Nd locate programs
+.Sh SYNOPSIS
+.Nm
+.Op Ar program ...
+.Sh DESCRIPTION
+The
+.Nm
+utility checks the standard binary directories for the specified programs,
+printing out the paths of any it finds.
+.Pp
+The path searched is the string returned by the
+.Xr sysctl 8
+utility for the
+.Dq user.cs_path
+string.
+.Sh SEE ALSO
+.Xr find 1 ,
+.Xr locate 1 ,
+.Xr man 1 ,
+.Xr which 1 ,
+.Xr sysctl 8
+.Sh COMPATIBILITY
+The historic flags and arguments for the
+.Nm
+utility are no longer available in this version.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/shell_cmds/whereis/whereis.c b/shell_cmds/whereis/whereis.c
new file mode 100644
index 0000000..680f1f3
--- /dev/null
+++ b/shell_cmds/whereis/whereis.c
@@ -0,0 +1,128 @@
+/* $NetBSD: whereis.c,v 1.8 1997/10/20 02:22:55 mrg Exp $ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)whereis.c 8.3 (Berkeley) 5/4/95";
+#endif
+__RCSID("$NetBSD: whereis.c,v 1.8 1997/10/20 02:22:55 mrg Exp $");
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void usage __P((void));
+int main __P((int, char *[]));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct stat sb;
+ size_t len;
+ int ch, sverrno, mib[2];
+ char *p, *t, *std, path[MAXPATHLEN];
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ /* Retrieve the standard path. */
+ mib[0] = CTL_USER;
+ mib[1] = USER_CS_PATH;
+ if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1)
+ return (-1);
+ if (len == 0)
+ err(1, "user_cs_path: sysctl: zero length\n");
+ if ((std = malloc(len)) == NULL)
+ err(1, "%s", "");
+ if (sysctl(mib, 2, std, &len, NULL, 0) == -1) {
+ sverrno = errno;
+ free(std);
+ errno = sverrno;
+ err(1, "sysctl: user_cs_path");
+ }
+
+ /* For each path, for each program... */
+ for (; *argv; ++argv)
+ for (p = std;; *p++ = ':') {
+ t = p;
+ if ((p = strchr(p, ':')) != NULL) {
+ *p = '\0';
+ if (t == p)
+ t = ".";
+ } else
+ if (strlen(t) == 0)
+ t = ".";
+ (void)snprintf(path, sizeof(path), "%s/%s", t, *argv);
+ if (!stat(path, &sb))
+ (void)printf("%s\n", path);
+ if (p == NULL)
+ break;
+ }
+
+ return (0);
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: whereis program [...]\n");
+ exit (1);
+}
diff --git a/shell_cmds/which/which.1 b/shell_cmds/which/which.1
new file mode 100644
index 0000000..d0f2fcb
--- /dev/null
+++ b/shell_cmds/which/which.1
@@ -0,0 +1,85 @@
+.\" Manpage Copyright (c) 1995, Jordan Hubbard <jkh@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the FreeBSD Project
+.\" its contributors.
+.\" 4. Neither the name of the FreeBSD Project 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 CONTRIBUTOR ``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 CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+.\" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: head/usr.bin/which/which.1 267773 2014-06-23 08:23:05Z bapt $
+.\"
+.Dd December 13, 2006
+.Dt WHICH 1
+.Os
+.Sh NAME
+.Nm which
+.Nd "locate a program file in the user's path"
+.Sh SYNOPSIS
+.Nm
+.Op Fl as
+.Ar program ...
+.Sh DESCRIPTION
+The
+.Nm
+utility
+takes a list of command names and searches the path for each executable
+file that would be run had these commands actually been invoked.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+List all instances of executables found (instead of just the first one
+of each).
+.It Fl s
+No output, just return 0 if all of the executables are found, or 1 if
+some were not found.
+.El
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
+.Xr find 1 ,
+.Xr locate 1 ,
+.Xr whereis 1
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Fx 2.1 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was originally written in Perl and was contributed by
+.An Wolfram Schneider Aq Mt wosch@FreeBSD.org .
+The current version of
+.Nm
+was rewritten in C by
+.An Daniel Papasian Aq Mt dpapasia@andrew.cmu.edu .
diff --git a/shell_cmds/which/which.c b/shell_cmds/which/which.c
new file mode 100644
index 0000000..7e9d662
--- /dev/null
+++ b/shell_cmds/which/which.c
@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2000 Dan Papasian. 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. 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/cdefs.h>
+
+__FBSDID("$FreeBSD: head/usr.bin/which/which.c 227245 2011-11-06 18:50:26Z ed $");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void usage(void);
+static int print_matches(char *, char *);
+
+static int silent;
+static int allpaths;
+
+int
+main(int argc, char **argv)
+{
+ char *p, *path;
+ ssize_t pathlen;
+ int opt, status;
+
+ status = EXIT_SUCCESS;
+
+ while ((opt = getopt(argc, argv, "as")) != -1) {
+ switch (opt) {
+ case 'a':
+ allpaths = 1;
+ break;
+ case 's':
+ silent = 1;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argv += optind;
+ argc -= optind;
+
+ if (argc == 0)
+ usage();
+
+ if ((p = getenv("PATH")) == NULL)
+ exit(EXIT_FAILURE);
+ pathlen = strlen(p) + 1;
+ path = malloc(pathlen);
+ if (path == NULL)
+ err(EXIT_FAILURE, NULL);
+
+ while (argc > 0) {
+ memcpy(path, p, pathlen);
+
+ if (strlen(*argv) >= FILENAME_MAX ||
+ print_matches(path, *argv) == -1)
+ status = EXIT_FAILURE;
+
+ argv++;
+ argc--;
+ }
+
+ exit(status);
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: which [-as] program ...\n");
+ exit(EXIT_FAILURE);
+}
+
+static int
+is_there(char *candidate)
+{
+ struct stat fin;
+
+ /* XXX work around access(2) false positives for superuser */
+ if (access(candidate, X_OK) == 0 &&
+ stat(candidate, &fin) == 0 &&
+ S_ISREG(fin.st_mode) &&
+ (getuid() != 0 ||
+ (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+ if (!silent)
+ printf("%s\n", candidate);
+ return (1);
+ }
+ return (0);
+}
+
+static int
+print_matches(char *path, char *filename)
+{
+ char candidate[PATH_MAX];
+ const char *d;
+ int found;
+
+ if (strchr(filename, '/') != NULL)
+ return (is_there(filename) ? 0 : -1);
+ found = 0;
+ while ((d = strsep(&path, ":")) != NULL) {
+ if (*d == '\0')
+ d = ".";
+ if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
+ filename) >= (int)sizeof(candidate))
+ continue;
+ if (is_there(candidate)) {
+ found = 1;
+ if (!allpaths)
+ break;
+ }
+ }
+ return (found ? 0 : -1);
+}
+
diff --git a/shell_cmds/who/utmpentry.c b/shell_cmds/who/utmpentry.c
new file mode 100644
index 0000000..b0e0914
--- /dev/null
+++ b/shell_cmds/who/utmpentry.c
@@ -0,0 +1,348 @@
+/* $NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland Exp $");
+#endif
+
+#include <sys/stat.h>
+
+#include <time.h>
+#include <string.h>
+#include <err.h>
+#include <stdlib.h>
+#ifdef __APPLE__
+#include <stdint.h>
+#endif /* __APPLE__ */
+
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+
+#include "utmpentry.h"
+
+#ifdef __APPLE__
+#define timespecclear(tsp) (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
+#define timespeccmp(tsp, usp, cmp) \
+ (((tsp)->tv_sec == (usp)->tv_sec) ? \
+ ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
+ ((tsp)->tv_sec cmp (usp)->tv_sec))
+#endif /* __APPLE__ */
+
+/* Fail the compile if x is not true, by constructing an illegal type. */
+#define COMPILE_ASSERT(x) ((void)sizeof(struct { unsigned : ((x) ? 1 : -1); }))
+
+
+#ifdef SUPPORT_UTMP
+static void getentry(struct utmpentry *, struct utmp *);
+static struct timespec utmptime = {0, 0};
+#endif
+#ifdef SUPPORT_UTMPX
+static void getentryx(struct utmpentry *, struct utmpx *);
+static struct timespec utmpxtime = {0, 0};
+#endif
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static int setup(const char *);
+static void adjust_size(struct utmpentry *e);
+#endif
+
+int maxname = 8, maxline = 8, maxhost = 16;
+int etype = 1 << USER_PROCESS;
+static int numutmp = 0;
+static struct utmpentry *ehead;
+
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static void
+adjust_size(struct utmpentry *e)
+{
+ int max;
+
+ if ((max = strlen(e->name)) > maxname)
+ maxname = max;
+ if ((max = strlen(e->line)) > maxline)
+ maxline = max;
+ if ((max = strlen(e->host)) > maxhost)
+ maxhost = max;
+}
+
+static int
+setup(const char *fname)
+{
+ int what = 3;
+ struct stat st;
+ const char *sfname;
+
+ if (fname == NULL) {
+#ifdef SUPPORT_UTMPX
+ setutxent();
+#endif
+#ifdef SUPPORT_UTMP
+ setutent();
+#endif
+ } else {
+ size_t len = strlen(fname);
+ if (len == 0)
+ errx(1, "Filename cannot be 0 length.");
+#ifdef __APPLE__
+ what = 1;
+#else /* !__APPLE__ */
+ what = fname[len - 1] == 'x' ? 1 : 2;
+#endif /* __APPLE__ */
+ if (what == 1) {
+#ifdef SUPPORT_UTMPX
+ if (utmpxname(fname) == 0)
+ warnx("Cannot set utmpx file to `%s'",
+ fname);
+#else
+ warnx("utmpx support not compiled in");
+#endif
+ } else {
+#ifdef SUPPORT_UTMP
+ if (utmpname(fname) == 0)
+ warnx("Cannot set utmp file to `%s'",
+ fname);
+#else
+ warnx("utmp support not compiled in");
+#endif
+ }
+ }
+#ifdef SUPPORT_UTMPX
+ if (what & 1) {
+ sfname = fname ? fname : _PATH_UTMPX;
+ if (stat(sfname, &st) == -1) {
+ warn("Cannot stat `%s'", sfname);
+ what &= ~1;
+ } else {
+ if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
+ utmpxtime = st.st_mtimespec;
+ else
+ what &= ~1;
+ }
+ }
+#endif
+#ifdef SUPPORT_UTMP
+ if (what & 2) {
+ sfname = fname ? fname : _PATH_UTMP;
+ if (stat(sfname, &st) == -1) {
+ warn("Cannot stat `%s'", sfname);
+ what &= ~2;
+ } else {
+ if (timespeccmp(&st.st_mtimespec, &utmptime, >))
+ utmptime = st.st_mtimespec;
+ else
+ what &= ~2;
+ }
+ }
+#endif
+ return what;
+}
+#endif
+
+void
+endutentries(void)
+{
+ struct utmpentry *ep;
+
+#ifdef SUPPORT_UTMP
+ timespecclear(&utmptime);
+#endif
+#ifdef SUPPORT_UTMPX
+ timespecclear(&utmpxtime);
+#endif
+ ep = ehead;
+ while (ep) {
+ struct utmpentry *sep = ep;
+ ep = ep->next;
+ free(sep);
+ }
+ ehead = NULL;
+ numutmp = 0;
+}
+
+int
+getutentries(const char *fname, struct utmpentry **epp)
+{
+#ifdef SUPPORT_UTMPX
+ struct utmpx *utx;
+#endif
+#ifdef SUPPORT_UTMP
+ struct utmp *ut;
+#endif
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+ struct utmpentry *ep;
+ int what = setup(fname);
+ struct utmpentry **nextp = &ehead;
+ switch (what) {
+ case 0:
+ /* No updates */
+ *epp = ehead;
+ return numutmp;
+ default:
+ /* Need to re-scan */
+ ehead = NULL;
+ numutmp = 0;
+ }
+#endif
+
+#ifdef SUPPORT_UTMPX
+ while ((what & 1) && (utx = getutxent()) != NULL) {
+#ifdef __APPLE__
+ if (((1 << utx->ut_type) & etype) == 0)
+#else /* !__APPLE__ */
+ if (fname == NULL && ((1 << utx->ut_type) & etype) == 0)
+#endif /* __APPLE__ */
+ continue;
+ if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
+ warn(NULL);
+ return 0;
+ }
+ getentryx(ep, utx);
+ *nextp = ep;
+ nextp = &(ep->next);
+ }
+#endif
+
+#ifdef SUPPORT_UTMP
+ if ((etype & (1 << USER_PROCESS)) != 0) {
+ while ((what & 2) && (ut = getutent()) != NULL) {
+ if (fname == NULL && (*ut->ut_name == '\0' ||
+ *ut->ut_line == '\0'))
+ continue;
+ /* Don't process entries that we have utmpx for */
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+ if (strncmp(ep->line, ut->ut_line,
+ sizeof(ut->ut_line)) == 0)
+ break;
+ }
+ if (ep != NULL)
+ continue;
+ if ((ep = calloc(1, sizeof(*ep))) == NULL) {
+ warn(NULL);
+ return 0;
+ }
+ getentry(ep, ut);
+ *nextp = ep;
+ nextp = &(ep->next);
+ }
+ }
+#endif
+ numutmp = 0;
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+ if (ehead != NULL) {
+ struct utmpentry *from = ehead, *save;
+
+ ehead = NULL;
+ while (from != NULL) {
+ for (nextp = &ehead;
+ (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
+ nextp = &(*nextp)->next)
+ continue;
+ save = from;
+ from = from->next;
+ save->next = *nextp;
+ *nextp = save;
+ numutmp++;
+ }
+ }
+ *epp = ehead;
+ return numutmp;
+#else
+ *epp = NULL;
+ return 0;
+#endif
+}
+
+#ifdef SUPPORT_UTMP
+static void
+getentry(struct utmpentry *e, struct utmp *up)
+{
+ COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
+ COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
+ COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
+
+ /*
+ * e has just been calloc'd. We don't need to clear it or
+ * append null-terminators, because its length is strictly
+ * greater than the source string. Use strncpy to _read_
+ * up->ut_* because they may not be terminated. For this
+ * reason we use the size of the _source_ as the length
+ * argument.
+ */
+ (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
+ (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
+ (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
+
+ e->tv.tv_sec = up->ut_time;
+ e->tv.tv_usec = 0;
+ e->pid = 0;
+ e->term = 0;
+ e->exit = 0;
+ e->sess = 0;
+ e->type = USER_PROCESS;
+ adjust_size(e);
+}
+#endif
+
+#ifdef SUPPORT_UTMPX
+static void
+getentryx(struct utmpentry *e, struct utmpx *up)
+{
+ COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
+ COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
+ COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
+
+ /*
+ * e has just been calloc'd. We don't need to clear it or
+ * append null-terminators, because its length is strictly
+ * greater than the source string. Use strncpy to _read_
+ * up->ut_* because they may not be terminated. For this
+ * reason we use the size of the _source_ as the length
+ * argument.
+ */
+ (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
+ (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
+ (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
+
+ e->tv = up->ut_tv;
+ e->pid = up->ut_pid;
+#ifndef __APPLE__
+ e->term = up->ut_exit.e_termination;
+ e->exit = up->ut_exit.e_exit;
+ e->sess = up->ut_session;
+#endif /* !__APPLE__ */
+ e->type = up->ut_type;
+ adjust_size(e);
+}
+#endif
diff --git a/shell_cmds/who/utmpentry.h b/shell_cmds/who/utmpentry.h
new file mode 100644
index 0000000..012478a
--- /dev/null
+++ b/shell_cmds/who/utmpentry.h
@@ -0,0 +1,78 @@
+/* $NetBSD: utmpentry.h,v 1.7 2008/07/13 20:07:49 dholland Exp $ */
+
+/*-
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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.
+ */
+
+#if defined(SUPPORT_UTMPX)
+# include <utmpx.h>
+# define WHO_NAME_LEN _UTX_USERSIZE
+# define WHO_LINE_LEN _UTX_LINESIZE
+# define WHO_HOST_LEN _UTX_HOSTSIZE
+#elif defined(SUPPORT_UTMP)
+# include <utmp.h>
+# define WHO_NAME_LEN UT_NAMESIZE
+# define WHO_LINE_LEN UT_LINESIZE
+# define WHO_HOST_LEN UT_HOSTSIZE
+#else
+# error Either SUPPORT_UTMPX or SUPPORT_UTMP must be defined!
+#endif
+
+
+struct utmpentry {
+ char name[WHO_NAME_LEN + 1];
+ char line[WHO_LINE_LEN + 1];
+ char host[WHO_HOST_LEN + 1];
+ struct timeval tv;
+ pid_t pid;
+#ifndef __APPLE__
+ uint16_t term;
+ uint16_t exit;
+ uint16_t sess;
+#endif /* !__APPLE__ */
+ uint16_t type;
+ struct utmpentry *next;
+};
+
+extern int maxname, maxline, maxhost;
+extern int etype;
+
+/*
+ * getutentries provides a linked list of struct utmpentry and returns
+ * the number of entries. The first argument, if not null, names an
+ * alternate utmp(x) file to look in.
+ *
+ * The memory returned by getutentries belongs to getutentries. The
+ * list returned (or elements of it) may be returned again later if
+ * utmp hasn't changed in the meantime.
+ *
+ * endutentries clears and frees the cached data.
+ */
+
+int getutentries(const char *, struct utmpentry **);
+void endutentries(void);
diff --git a/shell_cmds/who/who.1 b/shell_cmds/who/who.1
new file mode 100644
index 0000000..dbcbdf1
--- /dev/null
+++ b/shell_cmds/who/who.1
@@ -0,0 +1,130 @@
+.\" $NetBSD: who.1,v 1.22 2007/01/18 00:15:05 wiz Exp $
+.\"
+.\" Copyright (c) 1986, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" @(#)who.1 8.2 (Berkeley) 12/30/93
+.\"
+.Dd January 17, 2007
+.Dt WHO 1
+.Os
+.Sh NAME
+.Nm who
+.Nd display who is logged in
+.Sh SYNOPSIS
+.Nm
+.Op Fl abdHlmpqrsTtu
+.Op Ar file
+.Nm
+.Ar am i
+.Sh DESCRIPTION
+The
+.Nm
+utility displays a list of all users currently logged on, showing for
+each user the login name, tty name, the date and time of login, and
+hostname if not local.
+.Pp
+Available options:
+.Pp
+.Bl -tag -width file
+.It Fl a
+Same as
+.Fl bdlprTtu .
+.It Fl b
+Time of last system boot.
+.It Fl d
+Print dead processes.
+.It Fl H
+Write column headings above the regular output.
+.It Fl l
+Print system login processes (unsupported).
+.It Fl m
+Only print information about the current terminal.
+This is the
+.Tn POSIX
+way of saying
+.Nm
+.Ar am i .
+.It Fl p
+Print active processes spawned by
+.Xr launchd 8
+(unsupported).
+.It Fl q
+.Dq Quick mode :
+List only the names and the number of users currently logged on.
+When this option is used, all other options are ignored.
+.It Fl r
+Print the current runlevel.
+This is meaningless on Mac OS X.
+.It Fl s
+List only the name, line and time fields.
+This is the default.
+.It Fl T
+Print a character after the user name indicating the state of the
+terminal line:
+.Sq +
+if the terminal is writable;
+.Sq -
+if it is not;
+and
+.Sq \&?
+if a bad line is encountered.
+.It Fl t
+Print last system clock change (unsupported).
+.It Fl u
+Print the idle time for each user, and the associated process ID.
+.It Ar \&am I
+Returns the invoker's real user name.
+.It Ar file
+By default,
+.Nm
+gathers information from the file
+.Pa /var/run/utmpx .
+An alternative
+.Ar file
+may be specified.
+.El
+.Sh FILES
+.Bl -tag -width /var/run/utmpx -compact
+.It Pa /var/run/utmpx
+.El
+.Sh SEE ALSO
+.Xr last 1 ,
+.Xr mesg 1 ,
+.Xr users 1 ,
+.Xr getuid 2 ,
+.Xr utmpx 5
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
diff --git a/shell_cmds/who/who.c b/shell_cmds/who/who.c
new file mode 100644
index 0000000..f0e356f
--- /dev/null
+++ b/shell_cmds/who/who.c
@@ -0,0 +1,453 @@
+/* $NetBSD: who.c,v 1.23 2008/07/24 15:35:41 christos Exp $ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993\
+ The Regents of the University of California. All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)who.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: who.c,v 1.23 2008/07/24 15:35:41 christos Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <locale.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+#ifdef __APPLE__
+#include <limits.h>
+#include <paths.h>
+#include <stdint.h>
+#endif /* __APPLE__ */
+
+#include "utmpentry.h"
+
+#ifdef __APPLE__
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+#endif /* __APPLE__ */
+
+static void output_labels(void);
+static void who_am_i(const char *, int);
+static void usage(void) __dead;
+static void process(const char *, int);
+static void eprint(const struct utmpentry *);
+static void print(const char *, const char *, time_t, const char *, pid_t pid,
+ uint16_t term, uint16_t xit, uint16_t sess, uint16_t type);
+static void quick(const char *);
+
+static int show_term; /* show term state */
+static int show_idle; /* show idle time */
+#ifndef __APPLE__
+static int show_details; /* show exit status etc. */
+#endif /* !__APPLE__ */
+
+struct ut_type_names {
+ int type;
+ const char *name;
+} ut_type_names[] = {
+#ifdef SUPPORT_UTMPX
+ { EMPTY, "empty" },
+ { RUN_LVL, "run level" },
+ { BOOT_TIME, "boot time" },
+ { OLD_TIME, "old time" },
+ { NEW_TIME, "new time" },
+ { INIT_PROCESS, "init process" },
+ { LOGIN_PROCESS, "login process" },
+ { USER_PROCESS, "user process" },
+ { DEAD_PROCESS, "dead process" },
+#if defined(_NETBSD_SOURCE)
+ { ACCOUNTING, "accounting" },
+ { SIGNATURE, "signature" },
+ { DOWN_TIME, "down time" },
+#endif /* _NETBSD_SOURCE */
+#endif /* SUPPORT_UTMPX */
+ { -1, "unknown" }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int c, only_current_term, show_labels, quick_mode, default_mode;
+ int et = 0;
+
+ setlocale(LC_ALL, "");
+
+ only_current_term = show_term = show_idle = show_labels = 0;
+ quick_mode = default_mode = 0;
+
+ while ((c = getopt(argc, argv, "abdHlmpqrsTtuv")) != -1) {
+ switch (c) {
+ case 'a':
+ et = -1;
+#ifdef __APPLE__
+ show_idle = 1;
+#else /* !__APPLE__ */
+ show_idle = show_details = 1;
+#endif /* __APPLE__ */
+ break;
+ case 'b':
+ et |= (1 << BOOT_TIME);
+ break;
+ case 'd':
+ et |= (1 << DEAD_PROCESS);
+ break;
+ case 'H':
+ show_labels = 1;
+ break;
+ case 'l':
+ et |= (1 << LOGIN_PROCESS);
+ break;
+ case 'm':
+ only_current_term = 1;
+ break;
+ case 'p':
+ et |= (1 << INIT_PROCESS);
+ break;
+ case 'q':
+ quick_mode = 1;
+ break;
+ case 'r':
+ et |= (1 << RUN_LVL);
+ break;
+ case 's':
+ default_mode = 1;
+ break;
+ case 'T':
+ show_term = 1;
+ break;
+ case 't':
+ et |= (1 << NEW_TIME);
+ break;
+ case 'u':
+ show_idle = 1;
+ break;
+#ifndef __APPLE__
+ case 'v':
+ show_details = 1;
+ break;
+#endif /* !__APPLE__ */
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (et != 0)
+ etype = et;
+
+#ifndef __APPLE__
+ if (chdir("/dev")) {
+ err(EXIT_FAILURE, "cannot change directory to /dev");
+ /* NOTREACHED */
+ }
+#endif /* !__APPLE__ */
+
+ if (default_mode)
+ only_current_term = show_term = show_idle = 0;
+
+ switch (argc) {
+ case 0: /* who */
+ if (quick_mode) {
+ quick(NULL);
+ } else if (only_current_term) {
+ who_am_i(NULL, show_labels);
+ } else {
+ process(NULL, show_labels);
+ }
+ break;
+ case 1: /* who utmp_file */
+ if (quick_mode) {
+ quick(*argv);
+ } else if (only_current_term) {
+ who_am_i(*argv, show_labels);
+ } else {
+ process(*argv, show_labels);
+ }
+ break;
+ case 2: /* who am i */
+ who_am_i(NULL, show_labels);
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ return 0;
+}
+
+static char *
+strrstr(const char *str, const char *pat)
+{
+ const char *estr;
+ size_t len;
+ if (*pat == '\0')
+ return __UNCONST(str);
+
+ len = strlen(pat);
+
+ for (estr = str + strlen(str); str < estr; estr--)
+ if (strncmp(estr, pat, len) == 0)
+ return __UNCONST(estr);
+ return NULL;
+}
+
+static void
+who_am_i(const char *fname, int show_labels)
+{
+ struct passwd *pw;
+ const char *p;
+ char *t;
+ time_t now;
+ struct utmpentry *ehead, *ep;
+
+ /* search through the utmp and find an entry for this tty */
+ if ((p = ttyname(STDIN_FILENO)) != NULL) {
+
+ /* strip directory prefixes for ttys */
+ if ((t = strrstr(p, "/pts/")) != NULL ||
+ (t = strrchr(p, '/')) != NULL)
+ p = t + 1;
+
+ (void)getutentries(fname, &ehead);
+ for (ep = ehead; ep; ep = ep->next)
+ if (strcmp(ep->line, p) == 0) {
+ if (show_labels)
+ output_labels();
+ eprint(ep);
+ return;
+ }
+ } else
+ p = "tty??";
+
+ (void)time(&now);
+ pw = getpwuid(getuid());
+ if (show_labels)
+ output_labels();
+ print(pw ? pw->pw_name : "?", p, now, "", getpid(), 0, 0, 0, 0);
+}
+
+static void
+process(const char *fname, int show_labels)
+{
+ struct utmpentry *ehead, *ep;
+ (void)getutentries(fname, &ehead);
+ if (show_labels)
+ output_labels();
+ for (ep = ehead; ep != NULL; ep = ep->next)
+ eprint(ep);
+#ifdef __APPLE__
+ if ((etype & (1 << RUN_LVL)) != 0) {
+ printf(" . run-level 3\n");
+ }
+#endif /* __APPLE__ */
+}
+
+static void
+eprint(const struct utmpentry *ep)
+{
+ print(ep->name, ep->line, (time_t)ep->tv.tv_sec, ep->host, ep->pid,
+#ifdef __APPLE__
+ 0, 0, 0, ep->type);
+#else /* !__APPLE__ */
+ ep->term, ep->exit, ep->sess, ep->type);
+#endif /* __APPLE__ */
+}
+
+static void
+print(const char *name, const char *line, time_t t, const char *host,
+ pid_t pid, uint16_t term, uint16_t xit, uint16_t sess, uint16_t type)
+{
+ struct stat sb;
+ char state;
+ static time_t now = 0;
+ time_t idle;
+ const char *types = NULL;
+ size_t i;
+
+ state = '?';
+ idle = 0;
+
+ for (i = 0; ut_type_names[i].type >= 0; i++) {
+ types = ut_type_names[i].name;
+ if (ut_type_names[i].type == type)
+ break;
+ }
+
+ if (show_term || show_idle) {
+ if (now == 0)
+ time(&now);
+
+#ifdef __APPLE__
+ char tty[PATH_MAX + 1];
+ snprintf(tty, sizeof(tty), "%s%s", _PATH_DEV, line);
+ if (stat(tty, &sb) == 0) {
+#else /* !__APPLE__ */
+ if (stat(line, &sb) == 0) {
+#endif /* __APPLE__ */
+ state = (sb.st_mode & 020) ? '+' : '-';
+ idle = now - sb.st_atime;
+ }
+
+ }
+
+#ifdef __APPLE__
+ switch (type) {
+ case LOGIN_PROCESS:
+ (void)printf("%-*.*s ", maxname, maxname, "LOGIN");
+ break;
+ case BOOT_TIME:
+ (void)printf("%-*.*s ", maxname, maxname, "reboot");
+ break;
+ default:
+ (void)printf("%-*.*s ", maxname, maxname, name);
+ break;
+ }
+#else /* !__APPLE__ */
+ (void)printf("%-*.*s ", maxname, maxname, name);
+#endif /* __APPLE__ */
+
+ if (show_term)
+ (void)printf("%c ", state);
+
+#ifdef __APPLE__
+ (void)printf("%-*.*s ", maxline, maxline, type == BOOT_TIME ? "~" : line);
+#else /* !__APPLE__ */
+ (void)printf("%-*.*s ", maxline, maxline, line);
+#endif /* __APPLE__ */
+ (void)printf("%.12s ", ctime(&t) + 4);
+
+ if (show_idle) {
+ if (idle < 60)
+ (void)printf(" . ");
+ else if (idle < (24 * 60 * 60))
+ (void)printf("%02ld:%02ld ",
+ (long)(idle / (60 * 60)),
+ (long)(idle % (60 * 60)) / 60);
+ else
+ (void)printf(" old ");
+
+ (void)printf("\t%6d", pid);
+
+#ifndef __APPLE__
+ if (show_details) {
+ if (type == RUN_LVL)
+ (void)printf("\tnew=%c old=%c", term, xit);
+ else
+ (void)printf("\tterm=%d exit=%d", term, xit);
+ (void)printf(" sess=%d", sess);
+ (void)printf(" type=%s ", types);
+ }
+#endif /* !__APPLE__ */
+ }
+
+#ifdef __APPLE__
+ /* 6179576 */
+ if (type == DEAD_PROCESS)
+ (void)printf("\tterm=%d exit=%d", 0, 0);
+#endif /* __APPLE__ */
+
+ if (*host)
+ (void)printf("\t(%.*s)", maxhost, host);
+ (void)putchar('\n');
+}
+
+static void
+output_labels(void)
+{
+ (void)printf("%-*.*s ", maxname, maxname, "USER");
+
+ if (show_term)
+ (void)printf("S ");
+
+ (void)printf("%-*.*s ", maxline, maxline, "LINE");
+ (void)printf("WHEN ");
+
+ if (show_idle) {
+ (void)printf("IDLE ");
+ (void)printf("\t PID");
+
+ (void)printf("\tCOMMENT");
+ }
+
+ (void)putchar('\n');
+}
+
+static void
+quick(const char *fname)
+{
+ struct utmpentry *ehead, *ep;
+ int num = 0;
+
+ (void)getutentries(fname, &ehead);
+ for (ep = ehead; ep != NULL; ep = ep->next) {
+ (void)printf("%-*s ", maxname, ep->name);
+ if ((++num % 8) == 0)
+ (void)putchar('\n');
+ }
+ if (num % 8)
+ (void)putchar('\n');
+
+ (void)printf("# users = %d\n", num);
+}
+
+static void
+usage(void)
+{
+#ifdef __APPLE__
+ (void)fprintf(stderr, "Usage: %s [-abdHlmpqrsTtu] [file]\n\t%s am i\n",
+#else /* !__APPLE__ */
+ (void)fprintf(stderr, "Usage: %s [-abdHlmqrsTtuv] [file]\n\t%s am i\n",
+#endif /* __APPLE__ */
+ getprogname(), getprogname());
+ exit(EXIT_FAILURE);
+}
diff --git a/shell_cmds/xargs/pathnames.h b/shell_cmds/xargs/pathnames.h
new file mode 100644
index 0000000..45c0fff
--- /dev/null
+++ b/shell_cmds/xargs/pathnames.h
@@ -0,0 +1,36 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#define _PATH_ECHO "/bin/echo"
diff --git a/shell_cmds/xargs/strnsubst.c b/shell_cmds/xargs/strnsubst.c
new file mode 100644
index 0000000..b00b319
--- /dev/null
+++ b/shell_cmds/xargs/strnsubst.c
@@ -0,0 +1,109 @@
+/* $xMach: strnsubst.c,v 1.3 2002/02/23 02:10:24 jmallett Exp $ */
+
+/*
+ * Copyright (c) 2002 J. Mallett. All rights reserved.
+ * You may do whatever you want with this file as long as
+ * the above copyright and this notice remain intact, along
+ * with the following statement:
+ * For the man who taught me vi, and who got too old, too young.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/xargs/strnsubst.c,v 1.7 2004/10/18 15:40:47 cperciva Exp $");
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void strnsubst(char **, const char *, const char *, size_t);
+
+/*
+ * Replaces str with a string consisting of str with match replaced with
+ * replstr as many times as can be done before the constructed string is
+ * maxsize bytes large. It does not free the string pointed to by str, it
+ * is up to the calling program to be sure that the original contents of
+ * str as well as the new contents are handled in an appropriate manner.
+ * If replstr is NULL, then that internally is changed to a nil-string, so
+ * that we can still pretend to do somewhat meaningful substitution.
+ * No value is returned.
+ */
+void
+strnsubst(char **str, const char *match, const char *replstr, size_t maxsize)
+{
+ char *s1, *s2, *this;
+
+ s1 = *str;
+ if (s1 == NULL)
+ return;
+ /*
+ * If maxsize is 0 then set it to the length of s1, because we have
+ * to duplicate s1. XXX we maybe should double-check whether the match
+ * appears in s1. If it doesn't, then we also have to set the length
+ * to the length of s1, to avoid modifying the argument. It may make
+ * sense to check if maxsize is <= strlen(s1), because in that case we
+ * want to return the unmodified string, too.
+ */
+ if (maxsize == 0) {
+ match = NULL;
+ maxsize = strlen(s1) + 1;
+ }
+ s2 = calloc(1, maxsize);
+ if (s2 == NULL)
+ err(1, "calloc");
+
+ if (replstr == NULL)
+ replstr = "";
+
+ if (match == NULL || replstr == NULL || maxsize == strlen(s1)) {
+ strlcpy(s2, s1, maxsize);
+ goto done;
+ }
+
+ for (;;) {
+ this = strstr(s1, match);
+ if (this == NULL)
+ break;
+ if ((strlen(s2) + strlen(s1) + strlen(replstr) -
+ strlen(match) + 1) > maxsize) {
+ strlcat(s2, s1, maxsize);
+ goto done;
+ }
+ strncat(s2, s1, (uintptr_t)this - (uintptr_t)s1);
+ strcat(s2, replstr);
+ s1 = this + strlen(match);
+ }
+ strcat(s2, s1);
+done:
+ *str = s2;
+ return;
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+int
+main(void)
+{
+ char *x, *y, *z, *za;
+
+ x = "{}%$";
+ strnsubst(&x, "%$", "{} enpury!", 255);
+ y = x;
+ strnsubst(&y, "}{}", "ybir", 255);
+ z = y;
+ strnsubst(&z, "{", "v ", 255);
+ za = z;
+ strnsubst(&z, NULL, za, 255);
+ if (strcmp(z, "v ybir enpury!") == 0)
+ printf("strnsubst() seems to work!\n");
+ else
+ printf("strnsubst() is broken.\n");
+ printf("%s\n", z);
+ free(x);
+ free(y);
+ free(z);
+ free(za);
+ return 0;
+}
+#endif
diff --git a/shell_cmds/xargs/xargs.1 b/shell_cmds/xargs/xargs.1
new file mode 100644
index 0000000..b9d5add
--- /dev/null
+++ b/shell_cmds/xargs/xargs.1
@@ -0,0 +1,389 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" John B. Roll Jr. and the Institute of Electrical and Electronics
+.\" Engineers, Inc.
+.\"
+.\" 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 University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)xargs.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/xargs/xargs.1,v 1.34 2005/05/21 09:55:09 ru Exp $
+.\" $xMach: xargs.1,v 1.2 2002/02/23 05:23:37 tim Exp $
+.\"
+.Dd August 4, 2015
+.Dt XARGS 1
+.Os
+.Sh NAME
+.Nm xargs
+.Nd "construct argument list(s) and execute utility"
+.Sh SYNOPSIS
+.Nm
+.Op Fl 0oprt
+.Op Fl E Ar eofstr
+.Oo
+.Fl I Ar replstr
+.Op Fl R Ar replacements
+.Op Fl S Ar replsize
+.Oc
+.Op Fl J Ar replstr
+.Op Fl L Ar number
+.Oo
+.Fl n Ar number
+.Op Fl x
+.Oc
+.Op Fl P Ar maxprocs
+.Op Fl s Ar size
+.Op Ar utility Op Ar argument ...
+.Sh DESCRIPTION
+The
+.Nm
+utility reads space, tab, newline and end-of-file delimited strings
+from the standard input and executes
+.Ar utility
+with the strings as
+arguments.
+.Pp
+Any arguments specified on the command line are given to
+.Ar utility
+upon each invocation, followed by some number of the arguments read
+from the standard input of
+.Nm .
+This is repeated until standard input is exhausted.
+.Pp
+Spaces, tabs and newlines may be embedded in arguments using single
+(``\ '\ '')
+or double (``"'') quotes or backslashes (``\e'').
+Single quotes escape all non-single quote characters, excluding newlines,
+up to the matching single quote.
+Double quotes escape all non-double quote characters, excluding newlines,
+up to the matching double quote.
+Any single character, including newlines, may be escaped by a backslash.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl 0
+Change
+.Nm
+to expect NUL
+(``\\0'')
+characters as separators, instead of spaces and newlines.
+This is expected to be used in concert with the
+.Fl print0
+function in
+.Xr find 1 .
+.It Fl E Ar eofstr
+Use
+.Ar eofstr
+as a logical EOF marker.
+.It Fl I Ar replstr
+Execute
+.Ar utility
+for each input line, replacing one or more occurrences of
+.Ar replstr
+in up to
+.Ar replacements
+(or 5 if no
+.Fl R
+flag is specified) arguments to
+.Ar utility
+with the entire line of input.
+The resulting arguments, after replacement is done, will not be allowed to grow
+beyond
+.Ar replsize
+(or 255 if no
+.Fl S
+flag is specified)
+bytes; this is implemented by concatenating as much of the argument
+containing
+.Ar replstr
+as possible, to the constructed arguments to
+.Ar utility ,
+up to
+.Ar replsize
+bytes.
+The size limit does not apply to arguments to
+.Ar utility
+which do not contain
+.Ar replstr ,
+and furthermore, no replacement will be done on
+.Ar utility
+itself.
+Implies
+.Fl x .
+.It Fl J Ar replstr
+If this option is specified,
+.Nm
+will use the data read from standard input to replace the first occurrence of
+.Ar replstr
+instead of appending that data after all other arguments.
+This option will not affect how many arguments will be read from input
+.Pq Fl n ,
+or the size of the command(s)
+.Nm
+will generate
+.Pq Fl s .
+The option just moves where those arguments will be placed in the command(s)
+that are executed.
+The
+.Ar replstr
+must show up as a distinct
+.Ar argument
+to
+.Nm .
+It will not be recognized if, for instance, it is in the middle of a
+quoted string.
+Furthermore, only the first occurrence of the
+.Ar replstr
+will be replaced.
+For example, the following command will copy the list of files and
+directories which start with an uppercase letter in the current
+directory to
+.Pa destdir :
+.Pp
+.Dl /bin/ls -1d [A-Z]* | xargs -J % cp -Rp % destdir
+.It Fl L Ar number
+Call
+.Ar utility
+for every
+.Ar number
+non-empty lines read.
+A line ending with a space continues to the next non-empty line.
+If EOF is reached and fewer lines have been read than
+.Ar number
+then
+.Ar utility
+will be called with the available lines.
+The
+.Fl L
+and
+.Fl n
+options are mutually-exclusive; the last one given will be used.
+.It Fl n Ar number
+Set the maximum number of arguments taken from standard input for each
+invocation of
+.Ar utility .
+An invocation of
+.Ar utility
+will use less than
+.Ar number
+standard input arguments if the number of bytes accumulated (see the
+.Fl s
+option) exceeds the specified
+.Ar size
+or there are fewer than
+.Ar number
+arguments remaining for the last invocation of
+.Ar utility .
+The current default value for
+.Ar number
+is 5000.
+.It Fl o
+Reopen stdin as
+.Pa /dev/tty
+in the child process before executing the command.
+This is useful if you want
+.Nm
+to run an interactive application.
+.It Fl P Ar maxprocs
+Parallel mode: run at most
+.Ar maxprocs
+invocations of
+.Ar utility
+at once.
+If
+.Ar maxprocs
+is set to 0,
+.Nm
+will run as many processes as possible.
+.It Fl p
+Echo each command to be executed and ask the user whether it should be
+executed.
+An affirmative response,
+.Ql y
+in the POSIX locale,
+causes the command to be executed, any other response causes it to be
+skipped.
+No commands are executed if the process is not attached to a terminal.
+.It Fl r
+Compatibility with GNU
+.Nm .
+The GNU version of
+.Nm
+runs the
+.Ar utility
+argument at least once, even if
+.Nm
+input is empty, and it supports a
+.Fl r
+option to inhibit this behavior.
+The
+.Fx
+version of
+.Nm
+does not run the
+.Ar utility
+argument on empty input, but it supports the
+.Fl r
+option for command-line compatibility with GNU
+.Nm ,
+but the
+.Fl r
+option does nothing in the
+.Fx
+version of
+.Nm .
+.It Fl R Ar replacements
+Specify the maximum number of arguments that
+.Fl I
+will do replacement in.
+If
+.Ar replacements
+is negative, the number of arguments in which to replace is unbounded.
+.It Fl S Ar replsize
+Specify the amount of space (in bytes) that
+.Fl I
+can use for replacements.
+The default for
+.Ar replsize
+is 255.
+.It Fl s Ar size
+Set the maximum number of bytes for the command line length provided to
+.Ar utility .
+The sum of the length of the utility name, the arguments passed to
+.Ar utility
+(including
+.Dv NULL
+terminators) and the current environment will be less than or equal to
+this number.
+The current default value for
+.Ar size
+is
+.Dv ARG_MAX
+- 4096.
+.It Fl t
+Echo the command to be executed to standard error immediately before it
+is executed.
+.It Fl x
+Force
+.Nm
+to terminate immediately if a command line containing
+.Ar number
+arguments will not fit in the specified (or default) command line length.
+.El
+.Pp
+If
+.Ar utility
+is omitted,
+.Xr echo 1
+is used.
+.Pp
+Undefined behavior may occur if
+.Ar utility
+reads from the standard input.
+.Pp
+The
+.Nm
+utility exits immediately (without processing any further input) if a
+command line cannot be assembled,
+.Ar utility
+cannot be invoked, an invocation of
+.Ar utility
+is terminated by a signal,
+or an invocation of
+.Ar utility
+exits with a value of 255, the
+.Nm
+utility stops processing input and exits after all invocations of
+.Ar utility
+finish processing.
+.Sh LEGACY DESCRIPTION
+In legacy mode, the
+.Fl L
+option treats all newlines as end-of-line, regardless of whether
+the line is empty or ends with a space.
+In addition, the
+.Fl L
+and
+.Fl n
+options are not mutually-exclusive.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh EXIT STATUS
+The
+.Nm
+utility exits with a value of 0 if no error occurs.
+If
+.Ar utility
+cannot be found,
+.Nm
+exits with a value of 127, otherwise if
+.Ar utility
+cannot be executed,
+.Nm
+exits with a value of 126.
+If any other error occurs,
+.Nm
+exits with a value of 1.
+.Sh SEE ALSO
+.Xr echo 1 ,
+.Xr find 1 ,
+.Xr execvp 3 ,
+.Xr compat 5
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compliant.
+The
+.Fl J , o , P, R
+and
+.Fl S
+options are non-standard
+.Fx
+extensions which may not be available on other operating systems.
+.Sh HISTORY
+The
+.Nm
+utility appeared in PWB UNIX.
+.Sh BUGS
+If
+.Ar utility
+attempts to invoke another command such that the number of arguments or the
+size of the environment is increased, it risks
+.Xr execvp 3
+failing with
+.Er E2BIG .
+.Pp
+The
+.Nm
+utility does not take multibyte characters into account when performing
+string comparisons for the
+.Fl I
+and
+.Fl J
+options, which may lead to incorrect results in some locales.
diff --git a/shell_cmds/xargs/xargs.c b/shell_cmds/xargs/xargs.c
new file mode 100644
index 0000000..a1ee480
--- /dev/null
+++ b/shell_cmds/xargs/xargs.c
@@ -0,0 +1,840 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * John B. Roll Jr.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $xMach: xargs.c,v 1.6 2002/02/23 05:27:47 tim Exp $
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)xargs.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <paths.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+static void parse_input(int, char *[]);
+static void prerun(int, char *[]);
+static int prompt(void);
+static void run(char **);
+static void usage(void);
+void strnsubst(char **, const char *, const char *, size_t);
+static pid_t xwait(int block, int *status);
+static void xexit(const char *, const int);
+static void waitchildren(const char *, int);
+static void pids_init(void);
+static int pids_empty(void);
+static int pids_full(void);
+static void pids_add(pid_t pid);
+static int pids_remove(pid_t pid);
+static int findslot(pid_t pid);
+static int findfreeslot(void);
+static void clearslot(int slot);
+
+static int last_was_newline = 1;
+static int last_was_blank = 0;
+
+static char echo[] = _PATH_ECHO;
+static char **av, **bxp, **ep, **endxp, **xp;
+static char *argp, *bbp, *ebp, *inpline, *p, *replstr;
+static const char *eofstr;
+static int count, insingle, indouble, oflag, pflag, tflag, Rflag, rval, zflag;
+static int cnt, Iflag, jfound, Lflag, Sflag, wasquoted, xflag;
+static int curprocs, maxprocs;
+static size_t pad9314053;
+static pid_t *childpids;
+
+static volatile int childerr;
+
+extern char **environ;
+
+int
+main(int argc, char *argv[])
+{
+ long arg_max;
+ int ch, Jflag, nflag, nline;
+ size_t nargs;
+ size_t linelen;
+ struct rlimit rl;
+ char *endptr;
+ const char *errstr;
+
+ inpline = replstr = NULL;
+ ep = environ;
+ eofstr = "";
+ Jflag = nflag = 0;
+
+ (void)setlocale(LC_ALL, "");
+
+ /*
+ * POSIX.2 limits the exec line length to ARG_MAX - 2K. Running that
+ * caused some E2BIG errors, so it was changed to ARG_MAX - 4K. Given
+ * that the smallest argument is 2 bytes in length, this means that
+ * the number of arguments is limited to:
+ *
+ * (ARG_MAX - 4K - LENGTH(utility + arguments)) / 2.
+ *
+ * We arbitrarily limit the number of arguments to 5000. This is
+ * allowed by POSIX.2 as long as the resulting minimum exec line is
+ * at least LINE_MAX. Realloc'ing as necessary is possible, but
+ * probably not worthwhile.
+ */
+ nargs = 5000;
+ if ((arg_max = sysconf(_SC_ARG_MAX)) == -1)
+ errx(1, "sysconf(_SC_ARG_MAX) failed");
+ nline = arg_max - MAXPATHLEN; /* for argv[0] from execvp() */
+ pad9314053 = sizeof(char *); /* reserve for string area rounding */
+ while (*ep != NULL) {
+ /* 1 byte for each '\0' */
+ nline -= strlen(*ep++) + 1 + sizeof(*ep);
+ }
+ nline -= pad9314053;
+ maxprocs = 1;
+ while ((ch = getopt(argc, argv, "0E:I:J:L:n:oP:pR:S:s:rtx")) != -1)
+ switch (ch) {
+ case 'E':
+ eofstr = optarg;
+ break;
+ case 'I':
+ Jflag = 0;
+ Iflag = 1;
+ Lflag = 1;
+ replstr = optarg;
+ break;
+ case 'J':
+ Iflag = 0;
+ Jflag = 1;
+ replstr = optarg;
+ break;
+ case 'L':
+ Lflag = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-L %s: %s", optarg, errstr);
+ if (COMPAT_MODE("bin/xargs", "Unix2003")) {
+ nflag = 0; /* Override */
+ nargs = 5000;
+ }
+ break;
+ case 'n':
+ nflag = 1;
+ if ((nargs = strtol(optarg, NULL, 10)) <= 0)
+ errx(1, "illegal argument count");
+ if (COMPAT_MODE("bin/xargs", "Unix2003")) {
+ Lflag = 0; /* Override */
+ }
+ break;
+ case 'o':
+ oflag = 1;
+ break;
+ case 'P':
+ maxprocs = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-P %s: %s", optarg, errstr);
+ if (getrlimit(RLIMIT_NPROC, &rl) != 0)
+ errx(1, "getrlimit failed");
+ if (maxprocs == 0 || maxprocs > rl.rlim_cur)
+ maxprocs = rl.rlim_cur;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+ case 'R':
+ Rflag = strtol(optarg, &endptr, 10);
+ if (*endptr != '\0')
+ errx(1, "replacements must be a number");
+ break;
+ case 'r':
+ /* GNU compatibility */
+ break;
+ case 'S':
+ Sflag = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0')
+ errx(1, "replsize must be a number");
+ break;
+ case 's':
+ nline = strtonum(optarg, 0, INT_MAX, &errstr);
+ if (errstr)
+ errx(1, "-s %s: %s", optarg, errstr);
+ pad9314053 = 0; /* assume the -s value is valid */
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ case '0':
+ zflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!Iflag && Rflag)
+ usage();
+ if (!Iflag && Sflag)
+ usage();
+ if (Iflag && !Rflag)
+ Rflag = 5;
+ if (Iflag && !Sflag)
+ Sflag = 255;
+ if (xflag && !nflag)
+ usage();
+ if (Iflag || Lflag)
+ xflag = 1;
+ if (replstr != NULL && *replstr == '\0')
+ errx(1, "replstr may not be empty");
+
+ pids_init();
+
+ /*
+ * Allocate pointers for the utility name, the utility arguments,
+ * the maximum arguments to be read from stdin and the trailing
+ * NULL.
+ */
+ linelen = 1 + argc + nargs + 1;
+ if ((av = bxp = malloc(linelen * sizeof(char *))) == NULL)
+ errx(1, "malloc failed");
+
+ /*
+ * Use the user's name for the utility as argv[0], just like the
+ * shell. Echo is the default. Set up pointers for the user's
+ * arguments.
+ */
+ if (*argv == NULL)
+ cnt = strlen(*bxp++ = echo) + pad9314053;
+ else {
+ do {
+ if (Jflag && strcmp(*argv, replstr) == 0) {
+ char **avj;
+ jfound = 1;
+ argv++;
+ for (avj = argv; *avj; avj++)
+ cnt += strlen(*avj) + 1 + pad9314053;
+ break;
+ }
+ cnt += strlen(*bxp++ = *argv) + 1 + pad9314053;
+ } while (*++argv != NULL);
+ }
+
+ /*
+ * Set up begin/end/traversing pointers into the array. The -n
+ * count doesn't include the trailing NULL pointer, so the malloc
+ * added in an extra slot.
+ */
+ endxp = (xp = bxp) + nargs;
+
+ /*
+ * Allocate buffer space for the arguments read from stdin and the
+ * trailing NULL. Buffer space is defined as the default or specified
+ * space, minus the length of the utility name and arguments. Set up
+ * begin/end/traversing pointers into the array. The -s count does
+ * include the trailing NULL, so the malloc didn't add in an extra
+ * slot.
+ */
+ nline -= cnt;
+ if (nline <= 0)
+ errx(1, "insufficient space for command");
+
+ if ((bbp = malloc((size_t)(nline + 1))) == NULL)
+ errx(1, "malloc failed");
+ ebp = (argp = p = bbp) + nline - 1;
+ for (;;)
+ parse_input(argc, argv);
+}
+
+static void
+parse_input(int argc, char *argv[])
+{
+ int ch, foundeof;
+ char **avj;
+ int last_was_backslashed = 0;
+
+ foundeof = 0;
+
+ switch (ch = getchar()) {
+ case EOF:
+ /* No arguments since last exec. */
+ if (p == bbp)
+ xexit(*av, rval);
+ goto arg1;
+ case ' ':
+ last_was_blank = 1;
+ case '\t':
+ /* Quotes escape tabs and spaces. */
+ if (insingle || indouble || zflag)
+ goto addch;
+ goto arg2;
+ case '\0':
+ if (zflag) {
+ /*
+ * Increment 'count', so that nulls will be treated
+ * as end-of-line, as well as end-of-argument. This
+ * is needed so -0 works properly with -I and -L.
+ */
+ count++;
+ goto arg2;
+ }
+ goto addch;
+ case '\n':
+ if (zflag)
+ goto addch;
+ if (COMPAT_MODE("bin/xargs", "Unix2003")) {
+ if (last_was_newline) {
+ /* don't count empty line */
+ break;
+ }
+ if (!last_was_blank ) {
+ /* only count if NOT continuation line */
+ count++;
+ }
+ } else {
+ count++;
+ }
+ last_was_newline = 1;
+
+ /* Quotes do not escape newlines. */
+arg1: if (insingle || indouble) {
+ warnx("unterminated quote");
+ xexit(*av, 1);
+ }
+arg2:
+ foundeof = *eofstr != '\0' &&
+ strncmp(argp, eofstr, p - argp) == 0;
+
+#ifdef __APPLE__
+ /* 6591323: -I specifies that it processes the entire line,
+ * so only recognize eofstr at the end of a line. */
+ if (Iflag && !last_was_newline)
+ foundeof = 0;
+
+ /* 6591323: Essentially the same as the EOF handling above. */
+ if (foundeof && (p - strlen(eofstr) == bbp)) {
+ waitchildren(*argv, 1);
+ exit(rval);
+ }
+#endif
+
+ /* Do not make empty args unless they are quoted */
+ if ((argp != p || wasquoted) && !foundeof) {
+ *p++ = '\0';
+ *xp++ = argp;
+ if (Iflag) {
+ size_t curlen;
+
+ if (inpline == NULL)
+ curlen = 0;
+ else {
+ /*
+ * If this string is not zero
+ * length, append a space for
+ * separation before the next
+ * argument.
+ */
+ if ((curlen = strlen(inpline)))
+ strcat(inpline, " ");
+ }
+ curlen++;
+ /*
+ * Allocate enough to hold what we will
+ * be holding in a second, and to append
+ * a space next time through, if we have
+ * to.
+ */
+ inpline = realloc(inpline, curlen + 2 +
+ strlen(argp));
+ if (inpline == NULL) {
+ warnx("realloc failed");
+ xexit(*av, 1);
+ }
+ if (curlen == 1)
+ strcpy(inpline, argp);
+ else
+ strcat(inpline, argp);
+ }
+ }
+
+ /*
+ * If max'd out on args or buffer, or reached EOF,
+ * run the command. If xflag and max'd out on buffer
+ * but not on args, object. Having reached the limit
+ * of input lines, as specified by -L is the same as
+ * maxing out on arguments.
+ */
+ if (xp == endxp || p + (count * pad9314053) > ebp || ch == EOF ||
+ (Lflag <= count && xflag) || foundeof) {
+ if (xflag && xp != endxp && p + (count * pad9314053) > ebp) {
+ warnx("insufficient space for arguments");
+ xexit(*av, 1);
+ }
+ if (jfound) {
+ for (avj = argv; *avj; avj++)
+ *xp++ = *avj;
+ }
+ prerun(argc, av);
+ if (ch == EOF || foundeof)
+ xexit(*av, rval);
+ p = bbp;
+ xp = bxp;
+ count = 0;
+ }
+ argp = p;
+ wasquoted = 0;
+ break;
+ case '\'':
+ if (indouble || zflag)
+ goto addch;
+ insingle = !insingle;
+ wasquoted = 1;
+ break;
+ case '"':
+ if (insingle || zflag)
+ goto addch;
+ indouble = !indouble;
+ wasquoted = 1;
+ break;
+ case '\\':
+ last_was_backslashed = 1;
+ if (zflag)
+ goto addch;
+ /* Backslash escapes anything, is escaped by quotes. */
+ if (!insingle && !indouble && (ch = getchar()) == EOF) {
+ warnx("backslash at EOF");
+ xexit(*av, 1);
+ }
+ /* FALLTHROUGH */
+ default:
+addch: if (p < ebp) {
+ *p++ = ch;
+ break;
+ }
+
+ /* If only one argument, not enough buffer space. */
+ if (bxp == xp) {
+ warnx("insufficient space for argument");
+ xexit(*av, 1);
+ }
+ /* Didn't hit argument limit, so if xflag object. */
+ if (xflag) {
+ warnx("insufficient space for arguments");
+ xexit(*av, 1);
+ }
+
+ if (jfound) {
+ for (avj = argv; *avj; avj++)
+ *xp++ = *avj;
+ }
+ prerun(argc, av);
+ xp = bxp;
+ cnt = ebp - argp;
+ memcpy(bbp, argp, (size_t)cnt);
+ p = (argp = bbp) + cnt;
+ *p++ = ch;
+ break;
+ }
+ if (ch != ' ')
+ last_was_blank = 0;
+ if (ch != '\n' || last_was_backslashed)
+ last_was_newline = 0;
+}
+
+/*
+ * Do things necessary before run()'ing, such as -I substitution,
+ * and then call run().
+ */
+static void
+prerun(int argc, char *argv[])
+{
+ char **tmp, **tmp2, **avj;
+ int repls;
+
+ repls = Rflag;
+
+ if (argc == 0 || repls == 0) {
+ *xp = NULL;
+ run(argv);
+ return;
+ }
+
+ avj = argv;
+
+ /*
+ * Allocate memory to hold the argument list, and
+ * a NULL at the tail.
+ */
+ tmp = malloc((argc + 1) * sizeof(char *));
+ if (tmp == NULL) {
+ warnx("malloc failed");
+ xexit(*argv, 1);
+ }
+ tmp2 = tmp;
+
+ /*
+ * Save the first argument and iterate over it, we
+ * cannot do strnsubst() to it.
+ */
+ if ((*tmp++ = strdup(*avj++)) == NULL) {
+ warnx("strdup failed");
+ xexit(*argv, 1);
+ }
+
+ /*
+ * For each argument to utility, if we have not used up
+ * the number of replacements we are allowed to do, and
+ * if the argument contains at least one occurrence of
+ * replstr, call strnsubst(), else just save the string.
+ * Iterations over elements of avj and tmp are done
+ * where appropriate.
+ */
+ while (--argc) {
+ *tmp = *avj++;
+ if (repls && strstr(*tmp, replstr) != NULL) {
+ strnsubst(tmp++, replstr, inpline, (size_t)Sflag);
+ if (repls > 0)
+ repls--;
+ } else {
+ if ((*tmp = strdup(*tmp)) == NULL) {
+ warnx("strdup failed");
+ xexit(*argv, 1);
+ }
+ tmp++;
+ }
+ }
+
+ /*
+ * Run it.
+ */
+ *tmp = NULL;
+ run(tmp2);
+
+ /*
+ * Walk from the tail to the head, free along the way.
+ */
+ for (; tmp2 != tmp; tmp--)
+ free(*tmp);
+ /*
+ * Now free the list itself.
+ */
+ free(tmp2);
+
+ /*
+ * Free the input line buffer, if we have one.
+ */
+ if (inpline != NULL) {
+ free(inpline);
+ inpline = NULL;
+ }
+}
+
+static void
+run(char **argv)
+{
+ pid_t pid;
+ int fd;
+ char **avec;
+
+ /*
+ * If the user wants to be notified of each command before it is
+ * executed, notify them. If they want the notification to be
+ * followed by a prompt, then prompt them.
+ */
+ if (tflag || pflag) {
+ (void)fprintf(stderr, "%s", *argv);
+ for (avec = argv + 1; *avec != NULL; ++avec)
+ (void)fprintf(stderr, " %s", *avec);
+ /*
+ * If the user has asked to be prompted, do so.
+ */
+ if (pflag)
+ /*
+ * If they asked not to exec, return without execution
+ * but if they asked to, go to the execution. If we
+ * could not open their tty, break the switch and drop
+ * back to -t behaviour.
+ */
+ switch (prompt()) {
+ case 0:
+ return;
+ case 1:
+ goto exec;
+ case 2:
+ break;
+ }
+ (void)fprintf(stderr, "\n");
+ (void)fflush(stderr);
+ }
+exec:
+ childerr = 0;
+ switch (pid = vfork()) {
+ case -1:
+ warn("vfork");
+ xexit(*argv, 1);
+ case 0:
+ if (oflag) {
+ if ((fd = open(_PATH_TTY, O_RDONLY)) == -1)
+ err(1, "can't open /dev/tty");
+ } else {
+ fd = open(_PATH_DEVNULL, O_RDONLY);
+ }
+ if (fd > STDIN_FILENO) {
+ if (dup2(fd, STDIN_FILENO) != 0)
+ err(1, "can't dup2 to stdin");
+ close(fd);
+ }
+ execvp(argv[0], argv);
+ childerr = errno;
+ _exit(1);
+ }
+ pids_add(pid);
+ waitchildren(*argv, 0);
+}
+
+/*
+ * Wait for a tracked child to exit and return its pid and exit status.
+ *
+ * Ignores (discards) all untracked child processes.
+ * Returns -1 and sets errno to ECHILD if no tracked children exist.
+ * If block is set, waits indefinitely for a child process to exit.
+ * If block is not set and no children have exited, returns 0 immediately.
+ */
+static pid_t
+xwait(int block, int *status) {
+ pid_t pid;
+
+ if (pids_empty()) {
+ errno = ECHILD;
+ return (-1);
+ }
+
+ while ((pid = waitpid(-1, status, block ? 0 : WNOHANG)) > 0)
+ if (pids_remove(pid))
+ break;
+
+ return (pid);
+}
+
+static void
+xexit(const char *name, const int exit_code) {
+ waitchildren(name, 1);
+ exit(exit_code);
+}
+
+static void
+waitchildren(const char *name, int waitall)
+{
+ pid_t pid;
+ int status;
+ int cause_exit = 0;
+
+ while ((pid = xwait(waitall || pids_full(), &status)) > 0) {
+ /*
+ * If we couldn't invoke the utility or if utility exited
+ * because of a signal or with a value of 255, warn (per
+ * POSIX), and then wait until all other children have
+ * exited before exiting 1-125. POSIX requires us to stop
+ * reading if child exits because of a signal or with 255,
+ * but it does not require us to exit immediately; waiting
+ * is preferable to orphaning.
+ */
+ if (childerr != 0 && cause_exit == 0) {
+ errno = childerr;
+ waitall = 1;
+ cause_exit = errno == ENOENT ? 127 : 126;
+ warn("%s", name);
+ } else if (WIFSIGNALED(status)) {
+ waitall = cause_exit = 1;
+ warnx("%s: terminated with signal %d; aborting",
+ name, WTERMSIG(status));
+ } else if (WEXITSTATUS(status) == 255) {
+ waitall = cause_exit = 1;
+ warnx("%s: exited with status 255; aborting", name);
+ } else if (WEXITSTATUS(status))
+ rval = 1;
+ }
+
+ if (cause_exit)
+ exit(cause_exit);
+ if (pid == -1 && errno != ECHILD)
+ err(1, "waitpid");
+}
+
+#define NOPID (0)
+
+static void
+pids_init(void)
+{
+ int i;
+
+ if ((childpids = malloc(maxprocs * sizeof(*childpids))) == NULL)
+ errx(1, "malloc failed");
+
+ for (i = 0; i < maxprocs; i++)
+ clearslot(i);
+}
+
+static int
+pids_empty(void)
+{
+
+ return (curprocs == 0);
+}
+
+static int
+pids_full(void)
+{
+
+ return (curprocs >= maxprocs);
+}
+
+static void
+pids_add(pid_t pid)
+{
+ int slot;
+
+ slot = findfreeslot();
+ childpids[slot] = pid;
+ curprocs++;
+}
+
+static int
+pids_remove(pid_t pid)
+{
+ int slot;
+
+ if ((slot = findslot(pid)) < 0)
+ return (0);
+
+ clearslot(slot);
+ curprocs--;
+ return (1);
+}
+
+static int
+findfreeslot(void)
+{
+ int slot;
+
+ if ((slot = findslot(NOPID)) < 0)
+ errx(1, "internal error: no free pid slot");
+ return (slot);
+}
+
+static int
+findslot(pid_t pid)
+{
+ int slot;
+
+ for (slot = 0; slot < maxprocs; slot++)
+ if (childpids[slot] == pid)
+ return (slot);
+ return (-1);
+}
+
+static void
+clearslot(int slot)
+{
+
+ childpids[slot] = NOPID;
+}
+
+/*
+ * Prompt the user about running a command.
+ */
+static int
+prompt(void)
+{
+ regex_t cre;
+ size_t rsize;
+ int match;
+ char *response;
+ FILE *ttyfp;
+
+ if ((ttyfp = fopen(_PATH_TTY, "r")) == NULL)
+ return (2); /* Indicate that the TTY failed to open. */
+ (void)fprintf(stderr, "?...");
+ (void)fflush(stderr);
+ if ((response = fgetln(ttyfp, &rsize)) == NULL ||
+ regcomp(&cre, nl_langinfo(YESEXPR), REG_BASIC) != 0) {
+ (void)fclose(ttyfp);
+ return (0);
+ }
+ response[rsize - 1] = '\0';
+ match = regexec(&cre, response, 0, NULL, 0);
+ (void)fclose(ttyfp);
+ regfree(&cre);
+ return (match == 0);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr,
+"usage: xargs [-0opt] [-E eofstr] [-I replstr [-R replacements] [-S replsize]]\n"
+" [-J replstr] [-L number] [-n number [-x]] [-P maxprocs]\n"
+" [-s size] [utility [argument ...]]\n");
+ exit(1);
+}
diff --git a/shell_cmds/xcconfigs/base.xcconfig b/shell_cmds/xcconfigs/base.xcconfig
new file mode 100644
index 0000000..72c716a
--- /dev/null
+++ b/shell_cmds/xcconfigs/base.xcconfig
@@ -0,0 +1,59 @@
+// Build Options
+DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
+
+// Code Signing
+CODE_SIGN_IDENTITY = -
+
+// Deployment
+COPY_PHASE_STRIP = YES
+
+// Packaging
+APPLY_RULES_IN_COPY_FILES = YES
+
+// Search Paths
+ALWAYS_SEARCH_USER_PATHS = NO
+USE_HEADERMAP = NO
+
+// Versioning
+CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion)
+VERSIONING_SYSTEM = apple-generic
+VERSION_INFO_PREFIX = __
+
+// Warning Policies
+GCC_TREAT_WARNINGS_AS_ERRORS = YES
+
+// Warnings - All languages
+CLANG_WARN_ASSIGN_ENUM = YES
+CLANG_WARN_BOOL_CONVERSION = YES
+CLANG_WARN_CONSTANT_CONVERSION = YES
+CLANG_WARN_DOCUMENTATION_COMMENTS = YES
+CLANG_WARN_EMPTY_BODY = YES
+CLANG_WARN_ENUM_CONVERSION = YES
+CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES
+CLANG_WARN_INT_CONVERSION = YES
+CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES
+CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
+CLANG_WARN_UNREACHABLE_CODE = YES
+GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
+GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES
+GCC_WARN_64_TO_32_BIT_CONVERSION = YES
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES
+GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
+GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
+GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
+GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
+GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
+GCC_WARN_MISSING_PARENTHESES = YES
+GCC_WARN_SHADOW = YES
+GCC_WARN_SIGN_COMPARE = YES
+GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES
+GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE
+GCC_WARN_UNKNOWN_PRAGMAS = YES
+GCC_WARN_UNUSED_FUNCTION = YES
+GCC_WARN_UNUSED_LABEL = YES
+GCC_WARN_UNUSED_PARAMETER = YES
+GCC_WARN_UNUSED_VALUE = YES
+GCC_WARN_UNUSED_VARIABLE = YES
diff --git a/shell_cmds/xcconfigs/sh.xcconfig b/shell_cmds/xcconfigs/sh.xcconfig
new file mode 100644
index 0000000..f068b26
--- /dev/null
+++ b/shell_cmds/xcconfigs/sh.xcconfig
@@ -0,0 +1,33 @@
+#include "base.xcconfig"
+
+// TODO: change to /bin, sh, /usr
+SH_INSTALL_PATH = /usr/local/bin
+SH_PRODUCT_NAME = ash
+SH_MAN_PREFIX = /usr/local
+
+// Architectures
+SUPPORTED_PLATFORMS = iphoneos iphonesimulator macosx
+
+// Deployment
+INSTALL_PATH = $(SH_INSTALL_PATH)
+
+// Linking
+OTHER_LDFLAGS = -ledit
+
+// Packaging
+PRODUCT_NAME = $(SH_PRODUCT_NAME)
+
+// Search Paths
+USER_HEADER_SEARCH_PATHS = $(BUILT_PRODUCTS_DIR) $(SRCROOT)/sh
+
+// Preprocessing
+GCC_PREPROCESSOR_DEFINITIONS = SHELL
+
+// Warnings - All languages
+GCC_WARN_64_TO_32_BIT_CONVERSION = NO
+GCC_WARN_UNINITIALIZED_AUTOS = YES
+GCC_WARN_UNUSED_VARIABLE = NO
+CLANG_WARN_ASSIGN_ENUM = NO
+CLANG_WARN_EMPTY_BODY = NO
+CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO
+CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO
diff --git a/shell_cmds/xcodescripts/builtins-manpages.txt b/shell_cmds/xcodescripts/builtins-manpages.txt
new file mode 100644
index 0000000..ffc6f4e
--- /dev/null
+++ b/shell_cmds/xcodescripts/builtins-manpages.txt
@@ -0,0 +1,85 @@
+alias.1
+alloc.1
+bg.1
+bind.1
+bindkey.1
+break.1
+breaksw.1
+builtins.1
+case.1
+cd.1
+chdir.1
+command.1
+complete.1
+continue.1
+default.1
+dirs.1
+do.1
+done.1
+echotc.1
+elif.1
+else.1
+end.1
+endif.1
+endsw.1
+esac.1
+eval.1
+exec.1
+exit.1
+export.1
+fc.1
+fg.1
+fi.1
+filetest.1
+for.1
+foreach.1
+getopts.1
+glob.1
+goto.1
+hash.1
+hashstat.1
+history.1
+hup.1
+if.1
+jobid.1
+jobs.1
+limit.1
+logout.1
+ls-F.1
+notify.1
+onintr.1
+popd.1
+pushd.1
+read.1
+readonly.1
+rehash.1
+repeat.1
+return.1
+sched.1
+set.1
+setenv.1
+settc.1
+setty.1
+setvar.1
+shift.1
+source.1
+stop.1
+suspend.1
+switch.1
+telltc.1
+then.1
+times.1
+trap.1
+type.1
+ulimit.1
+umask.1
+unalias.1
+uncomplete.1
+unhash.1
+unlimit.1
+unset.1
+unsetenv.1
+until.1
+wait.1
+where.1
+while.1
diff --git a/shell_cmds/xcodescripts/builtins.txt b/shell_cmds/xcodescripts/builtins.txt
new file mode 100644
index 0000000..55cb408
--- /dev/null
+++ b/shell_cmds/xcodescripts/builtins.txt
@@ -0,0 +1,14 @@
+bg
+cd
+command
+fc
+fg
+getopts
+hash
+jobs
+read
+type
+ulimit
+umask
+unalias
+wait
diff --git a/shell_cmds/xcodescripts/install-files.sh b/shell_cmds/xcodescripts/install-files.sh
new file mode 100644
index 0000000..3710fcb
--- /dev/null
+++ b/shell_cmds/xcodescripts/install-files.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+set -e -x
+
+BINDIR="$DSTROOT"/usr/bin
+LIBEXECDIR="$DSTROOT"/usr/libexec
+MANDIR="$DSTROOT"/usr/share/man
+PAMDIR="$DSTROOT"/private/etc/pam.d
+
+ln -f "$BINDIR/hexdump" "$BINDIR/od"
+ln -f "$BINDIR/id" "$BINDIR/groups"
+ln -f "$BINDIR/id" "$BINDIR/whoami"
+ln -f "$BINDIR/w" "$BINDIR/uptime"
+ln -f "$DSTROOT/bin/test" "$DSTROOT/bin/["
+
+install -d -o root -g wheel -m 0755 "$BINDIR"
+install -d -o root -g wheel -m 0755 "$MANDIR"/man1
+install -d -o root -g wheel -m 0755 "$MANDIR"/man8
+
+install -c -o root -g wheel -m 0755 "$SRCROOT"/alias/generic.sh "$BINDIR"/alias
+install -c -o root -g wheel -m 0644 "$SRCROOT"/alias/builtin.1 "$MANDIR"/man1
+
+set +x
+for builtin in `cat "$SRCROOT/xcodescripts/builtins.txt"`; do
+ echo ... linking $builtin
+ ln -f "$BINDIR"/alias "$BINDIR/$builtin"
+done
+
+for manpage in `cat "$SRCROOT/xcodescripts/builtins-manpages.txt"`; do
+ echo ... linking $manpage
+ echo ".so man1/builtin.1" > "$MANDIR/man1/$manpage"
+done
+set -x
+
+install -d -o root -g wheel -m 0755 "$DSTROOT"/AppleInternal/Tests/shell_cmds
+install -o root -g wheel -m 0644 "$SRCROOT"/tests/regress.m4 \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds
+
+install -d -o root -g wheel -m 0755 \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds/time
+install -o root -g wheel -m 0644 "$SRCROOT"/time/tests/test_time.sh \
+ "$DSTROOT"/AppleInternal/Tests/shell_cmds/time
+
+install -d -o root -g wheel -m 0755 \
+ "$DSTROOT"/AppleInternal/CoreOS/BATS/unit_tests
+install -o root -g wheel -m 0644 "$SRCROOT"/tests/shell_cmds.plist \
+ "$DSTROOT"/AppleInternal/CoreOS/BATS/unit_tests
+
+# Skip locate and su targets for iOS
+if [ "$TARGET_NAME" = "All_iOS" ]; then
+ exit 0
+fi
+
+install -d -o root -g wheel -m 0755 "$LIBEXECDIR"
+install -c -o root -g wheel -m 0755 "$SRCROOT"/locate/locate/updatedb.sh \
+ "$LIBEXECDIR"/locate.updatedb
+install -c -o root -g wheel -m 0644 "$SRCROOT"/locate/locate/locate.updatedb.8 \
+ "$MANDIR"/man8
+install -c -o root -g wheel -m 0755 "$SRCROOT"/locate/locate/concatdb.sh \
+ "$LIBEXECDIR"/locate.concatdb
+echo ".so man8/locate.updatedb.8" > "$MANDIR"/man8/locate.concatdb.8
+install -c -o root -g wheel -m 0755 "$SRCROOT"/locate/locate/mklocatedb.sh \
+ "$LIBEXECDIR"/locate.mklocatedb
+echo ".so man8/locate.updatedb.8" > "$MANDIR"/man8/locate.mklocatedb.8
+
+install -d -o root -g wheel -m 0755 "$PAMDIR"
+install -c -o root -g wheel -m 0644 "$SRCROOT"/su/su.pam "$PAMDIR"/su
diff --git a/shell_cmds/yes/yes.1 b/shell_cmds/yes/yes.1
new file mode 100644
index 0000000..eab3795
--- /dev/null
+++ b/shell_cmds/yes/yes.1
@@ -0,0 +1,56 @@
+.\" $NetBSD: yes.1,v 1.4 1997/10/20 03:42:10 lukem Exp $
+.\"
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)yes.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt YES 1
+.Os BSD 4
+.Sh NAME
+.Nm yes
+.Nd be repetitively affirmative
+.Sh SYNOPSIS
+.Nm
+.Op Ar expletive
+.Sh DESCRIPTION
+.Nm
+outputs
+.Ar expletive ,
+or, by default,
+.Dq y ,
+forever.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/shell_cmds/yes/yes.c b/shell_cmds/yes/yes.c
new file mode 100644
index 0000000..863f363
--- /dev/null
+++ b/shell_cmds/yes/yes.c
@@ -0,0 +1,63 @@
+/* $NetBSD: yes.c,v 1.5 1997/10/19 14:28:27 mrg Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)yes.c 8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: yes.c,v 1.5 1997/10/19 14:28:27 mrg Exp $");
+#endif /* not lint */
+
+#include <stdio.h>
+
+int main __P((int, char **));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ if (argc > 1)
+ for(;;)
+ (void)puts(argv[1]);
+ else for (;;)
+ (void)puts("y");
+}
diff --git a/system_cmds/.upstream_base_commits b/system_cmds/.upstream_base_commits
new file mode 100644
index 0000000..886f2e2
--- /dev/null
+++ b/system_cmds/.upstream_base_commits
@@ -0,0 +1,2 @@
+#freebsd = https://github.com/freebsd/freebsd.git
+iostat.tproj/iostat.8 freebsd usr.sbin/iostat/iostat.8 4724d1448f7e7698308a1e05a7bb9b2069d68234
diff --git a/system_cmds/APPLE_LICENSE b/system_cmds/APPLE_LICENSE
new file mode 100644
index 0000000..e7aa7d0
--- /dev/null
+++ b/system_cmds/APPLE_LICENSE
@@ -0,0 +1,370 @@
+ APPLE PUBLIC SOURCE LICENSE
+ Version 1.0 - March 16, 1999
+
+Please read this License carefully before downloading this software.
+By downloading and using this software, you are agreeing to be bound
+by the terms of this License. If you do not or cannot agree to the
+terms of this License, please do not download or use the software.
+
+1. General; Definitions. This License applies to any program or other
+ work which Apple Computer, Inc. ("Apple") publicly announces as
+ subject to this Apple Public Source License and which contains a
+ notice placed by Apple identifying such program or work as "Original
+ Code" and stating that it is subject to the terms of this Apple
+ Public Source License version 1.0 (or subsequent version thereof),
+ as it may be revised from time to time by Apple ("License"). As
+ used in this License:
+
+1.1 "Applicable Patents" mean: (a) in the case where Apple is the
+ grantor of rights, (i) patents or patent applications that are now
+ or hereafter acquired, owned by or assigned to Apple and (ii) whose
+ claims cover subject matter contained in the Original Code, but only
+ to the extent necessary to use, reproduce and/or distribute the
+ Original Code without infringement; and (b) in the case where You
+ are the grantor of rights, (i) patents and patent applications that
+ are now or hereafter acquired, owned by or assigned to You and (ii)
+ whose claims cover subject matter in Your Modifications, taken alone
+ or in combination with Original Code.
+
+1.2 "Covered Code" means the Original Code, Modifications, the
+ combination of Original Code and any Modifications, and/or any
+ respective portions thereof.
+
+1.3 "Deploy" means to use, sublicense or distribute Covered Code other
+ than for Your internal research and development (R&D), and includes
+ without limitation, any and all internal use or distribution of
+ Covered Code within Your business or organization except for R&D
+ use, as well as direct or indirect sublicensing or distribution of
+ Covered Code by You to any third party in any form or manner.
+
+1.4 "Larger Work" means a work which combines Covered Code or portions
+ thereof with code not governed by the terms of this License.
+
+1.5 "Modifications" mean any addition to, deletion from, and/or change
+ to, the substance and/or structure of Covered Code. When code is
+ released as a series of files, a Modification is: (a) any addition
+ to or deletion from the contents of a file containing Covered Code;
+ and/or (b) any new file or other representation of computer program
+ statements that contains any part of Covered Code.
+
+1.6 "Original Code" means the Source Code of a program or other work
+ as originally made available by Apple under this License, including
+ the Source Code of any updates or upgrades to such programs or works
+ made available by Apple under this License, and that has been
+ expressly identified by Apple as such in the header file(s) of such
+ work.
+
+1.7 "Source Code" means the human readable form of a program or other
+ work that is suitable for making modifications to it, including all
+ modules it contains, plus any associated interface definition files,
+ scripts used to control compilation and installation of an
+ executable (object code).
+
+1.8 "You" or "Your" means an individual or a legal entity exercising
+ rights under this License. For legal entities, "You" or "Your"
+ includes any entity which controls, is controlled by, or is under
+ common control with, You, where "control" means (a) the power,
+ direct or indirect, to cause the direction or management of such
+ entity, whether by contract or otherwise, or (b) ownership of fifty
+ percent (50%) or more of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. Permitted Uses; Conditions & Restrictions. Subject to the terms
+ and conditions of this License, Apple hereby grants You, effective
+ on the date You accept this License and download the Original Code,
+ a world-wide, royalty-free, non-exclusive license, to the extent of
+ Apple's Applicable Patents and copyrights covering the Original
+ Code, to do the following:
+
+2.1 You may use, copy, modify and distribute Original Code, with or
+ without Modifications, solely for Your internal research and
+ development, provided that You must in each instance:
+
+(a) retain and reproduce in all copies of Original Code the copyright
+and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code
+that refer to this License;
+
+(b) include a copy of this License with every copy of Source Code of
+Covered Code and documentation You distribute, and You may not offer
+or impose any terms on such Source Code that alter or restrict this
+License or the recipients' rights hereunder, except as permitted under
+Section 6; and
+
+(c) completely and accurately document all Modifications that you have
+made and the date of each such Modification, designate the version of
+the Original Code you used, prominently include a file carrying such
+information with the Modifications, and duplicate the notice in
+Exhibit A in each file of the Source Code of all such Modifications.
+
+2.2 You may Deploy Covered Code, provided that You must in each
+ instance:
+
+(a) satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code;
+
+(b) make all Your Deployed Modifications publicly available in Source
+Code form via electronic distribution (e.g. download from a web site)
+under the terms of this License and subject to the license grants set
+forth in Section 3 below, and any additional terms You may choose to
+offer under Section 6. You must continue to make the Source Code of
+Your Deployed Modifications available for as long as you Deploy the
+Covered Code or twelve (12) months from the date of initial
+Deployment, whichever is longer;
+
+(c) must notify Apple and other third parties of how to obtain Your
+Deployed Modifications by filling out and submitting the required
+information found at
+http://www.apple.com/publicsource/modifications.html; and
+
+(d) if you Deploy Covered Code in object code, executable form only,
+include a prominent notice, in the code itself as well as in related
+documentation, stating that Source Code of the Covered Code is
+available under the terms of this License with information on how and
+where to obtain such Source Code.
+
+3. Your Grants. In consideration of, and as a condition to, the
+ licenses granted to You under this License:
+
+(a) You hereby grant to Apple and all third parties a non-exclusive,
+royalty-free license, under Your Applicable Patents and other
+intellectual property rights owned or controlled by You, to use,
+reproduce, modify, distribute and Deploy Your Modifications of the
+same scope and extent as Apple's licenses under Sections 2.1 and 2.2;
+and
+
+(b) You hereby grant to Apple and its subsidiaries a non-exclusive,
+worldwide, royalty-free, perpetual and irrevocable license, under Your
+Applicable Patents and other intellectual property rights owned or
+controlled by You, to use, reproduce, execute, compile, display,
+perform, modify or have modified (for Apple and/or its subsidiaries),
+sublicense and distribute Your Modifications, in any form, through
+multiple tiers of distribution.
+
+4. Larger Works. You may create a Larger Work by combining Covered
+ Code with other code not governed by the terms of this License and
+ distribute the Larger Work as a single product. In each such
+ instance, You must make sure the requirements of this License are
+ fulfilled for the Covered Code or any portion thereof.
+
+5. Limitations on Patent License. Except as expressly stated in
+ Section 2, no other patent rights, express or implied, are granted
+ by Apple herein. Modifications and/or Larger Works may require
+ additional patent licenses from Apple which Apple may grant in its
+ sole discretion.
+
+6. Additional Terms. You may choose to offer, and to charge a fee
+ for, warranty, support, indemnity or liability obligations and/or
+ other rights consistent with the scope of the license granted herein
+ ("Additional Terms") to one or more recipients of Covered
+ Code. However, You may do so only on Your own behalf and as Your
+ sole responsibility, and not on behalf of Apple. You must obtain the
+ recipient's agreement that any such Additional Terms are offered by
+ You alone, and You hereby agree to indemnify, defend and hold Apple
+ harmless for any liability incurred by or claims asserted against
+ Apple by reason of any such Additional Terms.
+
+7. Versions of the License. Apple may publish revised and/or new
+ versions of this License from time to time. Each version will be
+ given a distinguishing version number. Once Original Code has been
+ published under a particular version of this License, You may
+ continue to use it under the terms of that version. You may also
+ choose to use such Original Code under the terms of any subsequent
+ version of this License published by Apple. No one other than Apple
+ has the right to modify the terms applicable to Covered Code created
+ under this License.
+
+8. NO WARRANTY OR SUPPORT. The Original Code may contain in whole or
+ in part pre-release, untested, or not fully tested works. The
+ Original Code may contain errors that could cause failures or loss
+ of data, and may be incomplete or contain inaccuracies. You
+ expressly acknowledge and agree that use of the Original Code, or
+ any portion thereof, is at Your sole and entire risk. THE ORIGINAL
+ CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT
+ OF ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (FOR THE PURPOSES OF
+ SECTIONS 8 AND 9, APPLE AND APPLE'S LICENSOR(S) ARE COLLECTIVELY
+ REFERRED TO AS "APPLE") EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR
+ CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY OR
+ SATISFACTORY QUALITY AND FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE DOES NOT WARRANT THAT
+ THE FUNCTIONS CONTAINED IN THE ORIGINAL CODE WILL MEET YOUR
+ REQUIREMENTS, OR THAT THE OPERATION OF THE ORIGINAL CODE WILL BE
+ UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE ORIGINAL CODE
+ WILL BE CORRECTED. NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN
+ BY APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE SHALL CREATE A
+ WARRANTY OR IN ANY WAY INCREASE THE SCOPE OF THIS WARRANTY. You
+ acknowledge that the Original Code is not intended for use in the
+ operation of nuclear facilities, aircraft navigation, communication
+ systems, or air traffic control machines in which case the failure
+ of the Original Code could lead to death, personal injury, or severe
+ physical or environmental damage.
+
+9. Liability.
+
+9.1 Infringement. If any of the Original Code becomes the subject of
+ a claim of infringement ("Affected Original Code"), Apple may, at
+ its sole discretion and option: (a) attempt to procure the rights
+ necessary for You to continue using the Affected Original Code; (b)
+ modify the Affected Original Code so that it is no longer
+ infringing; or (c) terminate Your rights to use the Affected
+ Original Code, effective immediately upon Apple's posting of a
+ notice to such effect on the Apple web site that is used for
+ implementation of this License.
+
+9.2 LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES SHALL APPLE BE
+ LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR CONSEQUENTIAL
+ DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR YOUR USE OR
+ INABILITY TO USE THE ORIGINAL CODE, OR ANY PORTION THEREOF, WHETHER
+ UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE),
+ PRODUCTS LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF
+ THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF
+ ESSENTIAL PURPOSE OF ANY REMEDY. In no event shall Apple's total
+ liability to You for all damages under this License exceed the
+ amount of fifty dollars ($50.00).
+
+10. Trademarks. This License does not grant any rights to use the
+ trademarks or trade names "Apple", "Apple Computer", "Mac OS X",
+ "Mac OS X Server" or any other trademarks or trade names belonging
+ to Apple (collectively "Apple Marks") and no Apple Marks may be
+ used to endorse or promote products derived from the Original Code
+ other than as permitted by and in strict compliance at all times
+ with Apple's third party trademark usage guidelines which are
+ posted at http://www.apple.com/legal/guidelinesfor3rdparties.html.
+
+11. Ownership. Apple retains all rights, title and interest in and to
+ the Original Code and any Modifications made by or on behalf of
+ Apple ("Apple Modifications"), and such Apple Modifications will
+ not be automatically subject to this License. Apple may, at its
+ sole discretion, choose to license such Apple Modifications under
+ this License, or on different terms from those contained in this
+ License or may choose not to license them at all. Apple's
+ development, use, reproduction, modification, sublicensing and
+ distribution of Covered Code will not be subject to this License.
+
+12. Termination.
+
+12.1 Termination. This License and the rights granted hereunder will
+ terminate:
+
+(a) automatically without notice from Apple if You fail to comply with
+any term(s) of this License and fail to cure such breach within 30
+days of becoming aware of such breach; (b) immediately in the event of
+the circumstances described in Sections 9.1 and/or 13.6(b); or (c)
+automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement
+against Apple.
+
+12.2 Effect of Termination. Upon termination, You agree to
+ immediately stop any further use, reproduction, modification and
+ distribution of the Covered Code, or Affected Original Code in the
+ case of termination under Section 9.1, and to destroy all copies of
+ the Covered Code or Affected Original Code (in the case of
+ termination under Section 9.1) that are in your possession or
+ control. All sublicenses to the Covered Code which have been
+ properly granted prior to termination shall survive any termination
+ of this License. Provisions which, by their nature, should remain
+ in effect beyond the termination of this License shall survive,
+ including but not limited to Sections 3, 5, 8, 9, 10, 11, 12.2 and
+ 13. Neither party will be liable to the other for compensation,
+ indemnity or damages of any sort solely as a result of terminating
+ this License in accordance with its terms, and termination of this
+ License will be without prejudice to any other right or remedy of
+ either party.
+
+13. Miscellaneous.
+
+13.1 Export Law Assurances. You may not use or otherwise export or
+ re-export the Original Code except as authorized by United States
+ law and the laws of the jurisdiction in which the Original Code was
+ obtained. In particular, but without limitation, the Original Code
+ may not be exported or re-exported (a) into (or to a national or
+ resident of) any U.S. embargoed country or (b) to anyone on the
+ U.S. Treasury Department's list of Specially Designated Nationals
+ or the U.S. Department of Commerce's Table of Denial Orders. By
+ using the Original Code, You represent and warrant that You are not
+ located in, under control of, or a national or resident of any such
+ country or on any such list.
+
+13.2 Government End Users. The Covered Code is a "commercial item" as
+ defined in FAR 2.101. Government software and technical data
+ rights in the Covered Code include only those rights customarily
+ provided to the public as defined in this License. This customary
+ commercial license in technical data and software is provided in
+ accordance with FAR 12.211 (Technical Data) and 12.212 (Computer
+ Software) and, for Department of Defense purchases, DFAR
+ 252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3
+ (Rights in Commercial Computer Software or Computer Software
+ Documentation). Accordingly, all U.S. Government End Users acquire
+ Covered Code with only those rights set forth herein.
+
+13.3 Relationship of Parties. This License will not be construed as
+ creating an agency, partnership, joint venture or any other form of
+ legal association between You and Apple, and You will not represent
+ to the contrary, whether expressly, by implication, appearance or
+ otherwise.
+
+13.4 Independent Development. Nothing in this License will impair
+ Apple's right to acquire, license, develop, have others develop for
+ it, market and/or distribute technology or products that perform
+ the same or similar functions as, or otherwise compete with,
+ Modifications, Larger Works, technology or products that You may
+ develop, produce, market or distribute.
+
+13.5 Waiver; Construction. Failure by Apple to enforce any provision
+ of this License will not be deemed a waiver of future enforcement
+ of that or any other provision. Any law or regulation which
+ provides that the language of a contract shall be construed against
+ the drafter will not apply to this License.
+
+13.6 Severability. (a) If for any reason a court of competent
+ jurisdiction finds any provision of this License, or portion
+ thereof, to be unenforceable, that provision of the License will be
+ enforced to the maximum extent permissible so as to effect the
+ economic benefits and intent of the parties, and the remainder of
+ this License will continue in full force and effect. (b)
+ Notwithstanding the foregoing, if applicable law prohibits or
+ restricts You from fully and/or specifically complying with
+ Sections 2 and/or 3 or prevents the enforceability of either of
+ those Sections, this License will immediately terminate and You
+ must immediately discontinue any use of the Covered Code and
+ destroy all copies of it that are in your possession or control.
+
+13.7 Dispute Resolution. Any litigation or other dispute resolution
+ between You and Apple relating to this License shall take place in
+ the Northern District of California, and You and Apple hereby
+ consent to the personal jurisdiction of, and venue in, the state
+ and federal courts within that District with respect to this
+ License. The application of the United Nations Convention on
+ Contracts for the International Sale of Goods is expressly
+ excluded.
+
+13.8 Entire Agreement; Governing Law. This License constitutes the
+ entire agreement between the parties with respect to the subject
+ matter hereof. This License shall be governed by the laws of the
+ United States and the State of California, except that body of
+ California law concerning conflicts of law.
+
+Where You are located in the province of Quebec, Canada, the following
+clause applies: The parties hereby confirm that they have requested
+that this License and all related documents be drafted in English. Les
+parties ont exige que le present contrat et tous les documents
+connexes soient rediges en anglais.
+
+EXHIBIT A.
+
+"Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+Reserved. This file contains Original Code and/or Modifications of
+Original Code as defined in and that are subject to the Apple Public
+Source License Version 1.0 (the 'License'). You may not use this file
+except in compliance with the License. Please obtain a copy of the
+License at http://www.apple.com/publicsource and read it before using
+this file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+License for the specific language governing rights and limitations
+under the License."
diff --git a/system_cmds/ac.tproj/ac.8 b/system_cmds/ac.tproj/ac.8
new file mode 100644
index 0000000..dd40a55
--- /dev/null
+++ b/system_cmds/ac.tproj/ac.8
@@ -0,0 +1,86 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ac.8 8.2 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.Dt AC 8
+.Os BSD 4
+.Sh NAME
+.Nm ac
+.Nd display connect-time accounting
+.Sh SYNOPSIS
+.Nm ac
+.Op Fl d
+.Op Fl p
+.Op Fl w Ar file
+.Op Ar users ...
+.Sh DESCRIPTION
+A record of individual
+login and logout times are written to the system log by
+.Xr login 8
+and
+.Xr launchd 8 ,
+respectively.
+The program
+.Nm ac
+examines these records
+and writes the accumulated connect time (in decimal hours)
+for all logins to the standard output.
+.Pp
+Options available:
+.Bl -tag -width people
+.It Fl d
+Display the connect times in 24 hour chunks.
+.It Fl p
+Display individual user totals.
+.It Fl w Ar file
+Read raw connect time data from
+.Ar file ,
+instead of the system log.
+.It Ar users ...
+Display totals for the given individuals
+only.
+.El
+.Pp
+If no arguments are given,
+.Nm ac
+displays the total amount of login time
+for all active accounts on the system.
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr utmpx 5 ,
+.Xr launchd 8 ,
+.Xr sa 8
+.Sh HISTORY
+An
+.Nm ac
+command appeared in Version 6 AT&T UNIX.
diff --git a/system_cmds/ac.tproj/ac.c b/system_cmds/ac.tproj/ac.c
new file mode 100644
index 0000000..00aaa06
--- /dev/null
+++ b/system_cmds/ac.tproj/ac.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou.
+ * @(#)Copyright (c) 1994, Simon J. Gerraty.
+ *
+ * This is free software. It comes with NO WARRANTY.
+ * Permission to use, modify and distribute this source code
+ * is granted subject to the following conditions.
+ * 1/ that the above copyright notice and this notice
+ * are preserved in all copies and that due credit be given
+ * to the author.
+ * 2/ that any changes to this code are clearly commented
+ * as such so that the author does not get blamed for bugs
+ * other than his own.
+ */
+
+#ifndef lint
+#include <sys/cdefs.h>
+__unused static char rcsid[] = "$Id: ac.c,v 1.2 2006/02/07 05:51:22 lindak Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <utmpx.h>
+#include <unistd.h>
+
+#define UT_NAMESIZE 8 /* from utmp.h; only for formatting */
+
+/*
+ * this is for our list of currently logged in sessions
+ */
+struct utmp_list {
+ struct utmp_list *next;
+ struct utmpx usr;
+};
+
+/*
+ * this is for our list of users that are accumulating time.
+ */
+struct user_list {
+ struct user_list *next;
+ char name[_UTX_USERSIZE+1];
+ time_t secs;
+};
+
+/*
+ * this is for chosing whether to ignore a login
+ */
+struct tty_list {
+ struct tty_list *next;
+ char name[_UTX_USERSIZE+3];
+ int len;
+ int ret;
+};
+
+/*
+ * globals - yes yuk
+ */
+#ifdef CONSOLE_TTY
+static char *Console = CONSOLE_TTY;
+#endif
+static time_t Total = 0;
+static time_t FirstTime = 0;
+static int Flags = 0;
+static struct user_list *Users = NULL;
+static struct tty_list *Ttys = NULL;
+
+#define NEW(type) (type *)malloc(sizeof (type))
+
+#define AC_W 1 /* not _PATH_WTMP */
+#define AC_D 2 /* daily totals (ignore -p) */
+#define AC_P 4 /* per-user totals */
+#define AC_U 8 /* specified users only */
+#define AC_T 16 /* specified ttys only */
+
+#ifdef DEBUG
+static int Debug = 0;
+#endif
+
+int main __P((int, char **));
+int ac __P((void));
+struct tty_list *add_tty __P((char *));
+int do_tty __P((char *));
+struct utmp_list *log_in __P((struct utmp_list *, struct utmpx *));
+struct utmp_list *log_out __P((struct utmp_list *, struct utmpx *));
+int on_console __P((struct utmp_list *));
+void show __P((char *, time_t));
+void show_today __P((struct user_list *, struct utmp_list *,
+ time_t));
+void show_users __P((struct user_list *));
+struct user_list *update_user __P((struct user_list *, char *, time_t));
+void usage __P((void));
+
+struct tty_list *
+add_tty(char *name)
+{
+ struct tty_list *tp;
+ register char *rcp;
+
+ Flags |= AC_T;
+
+ if ((tp = NEW(struct tty_list)) == NULL)
+ err(1, "malloc");
+ tp->len = 0; /* full match */
+ tp->ret = 1; /* do if match */
+ if (*name == '!') { /* don't do if match */
+ tp->ret = 0;
+ name++;
+ }
+ (void)strncpy(tp->name, name, sizeof (tp->name) - 1);
+ tp->name[sizeof (tp->name) - 1] = '\0';
+ if ((rcp = strchr(tp->name, '*')) != NULL) { /* wild card */
+ *rcp = '\0';
+ tp->len = (int)strlen(tp->name); /* match len bytes only */
+ }
+ tp->next = Ttys;
+ Ttys = tp;
+ return Ttys;
+}
+
+/*
+ * should we process the named tty?
+ */
+int
+do_tty(char *name)
+{
+ struct tty_list *tp;
+ int def_ret = 0;
+
+ for (tp = Ttys; tp != NULL; tp = tp->next) {
+ if (tp->ret == 0) /* specific don't */
+ def_ret = 1; /* default do */
+ if (tp->len != 0) {
+ if (strncmp(name, tp->name, tp->len) == 0)
+ return tp->ret;
+ } else {
+ if (strncmp(name, tp->name, sizeof (tp->name)) == 0)
+ return tp->ret;
+ }
+ }
+ return def_ret;
+}
+
+#ifdef CONSOLE_TTY
+/*
+ * is someone logged in on Console?
+ */
+int
+on_console(struct utmp_list *head)
+{
+ struct utmp_list *up;
+
+ for (up = head; up; up = up->next) {
+ if (strncmp(up->usr.ut_line, Console,
+ sizeof (up->usr.ut_line)) == 0)
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * update user's login time
+ */
+struct user_list *
+update_user(struct user_list *head, char *name, time_t secs)
+{
+ struct user_list *up;
+
+ for (up = head; up != NULL; up = up->next) {
+ if (strncmp(up->name, name, sizeof (up->name)) == 0) {
+ up->secs += secs;
+ Total += secs;
+ return head;
+ }
+ }
+ /*
+ * not found so add new user unless specified users only
+ */
+ if (Flags & AC_U)
+ return head;
+
+ if ((up = NEW(struct user_list)) == NULL)
+ err(1, "malloc");
+ up->next = head;
+ (void)strncpy(up->name, name, sizeof (up->name) - 1);
+ up->name[sizeof (up->name) - 1] = '\0'; /* paranoid! */
+ up->secs = secs;
+ Total += secs;
+ return up;
+}
+
+int
+main(int argc, char **argv)
+{
+ FILE *fp;
+ int c;
+
+ fp = NULL;
+ while ((c = getopt(argc, argv, "Dc:dpt:w:")) != EOF) {
+ switch (c) {
+#ifdef DEBUG
+ case 'D':
+ Debug++;
+ break;
+#endif
+ case 'c':
+#ifdef CONSOLE_TTY
+ Console = optarg;
+#else
+ usage(); /* XXX */
+#endif
+ break;
+ case 'd':
+ Flags |= AC_D;
+ break;
+ case 'p':
+ Flags |= AC_P;
+ break;
+ case 't': /* only do specified ttys */
+ add_tty(optarg);
+ break;
+ case 'w':
+ wtmpxname(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ if (optind < argc) {
+ /*
+ * initialize user list
+ */
+ for (; optind < argc; optind++) {
+ Users = update_user(Users, argv[optind], 0L);
+ }
+ Flags |= AC_U; /* freeze user list */
+ }
+ if (Flags & AC_D)
+ Flags &= ~AC_P;
+ ac();
+
+ return 0;
+}
+
+/*
+ * print login time in decimal hours
+ */
+void
+show(char *name, time_t secs)
+{
+ (void)printf("\t%-*s %8.2f\n", UT_NAMESIZE, name,
+ ((double)secs / 3600));
+}
+
+void
+show_users(struct user_list *list)
+{
+ struct user_list *lp;
+
+ for (lp = list; lp; lp = lp->next)
+ show(lp->name, lp->secs);
+}
+
+/*
+ * print total login time for 24hr period in decimal hours
+ */
+void
+show_today(struct user_list *users, struct utmp_list *logins, time_t secs)
+{
+ struct user_list *up;
+ struct utmp_list *lp;
+ char date[64];
+ time_t yesterday = secs - 1;
+
+ (void)strftime(date, sizeof (date), "%b %e total",
+ localtime(&yesterday));
+
+ /* restore the missing second */
+ yesterday++;
+
+ for (lp = logins; lp != NULL; lp = lp->next) {
+ secs = yesterday - lp->usr.ut_tv.tv_sec;
+ Users = update_user(Users, lp->usr.ut_user, secs);
+ lp->usr.ut_tv.tv_sec = yesterday; /* as if they just logged in */
+ }
+ secs = 0;
+ for (up = users; up != NULL; up = up->next) {
+ secs += up->secs;
+ up->secs = 0; /* for next day */
+ }
+ if (secs)
+ (void)printf("%s %11.2f\n", date, ((double)secs / 3600));
+}
+
+/*
+ * log a user out and update their times.
+ * if ut_line is "~", we log all users out as the system has
+ * been shut down.
+ */
+struct utmp_list *
+log_out(struct utmp_list *head, struct utmpx *up)
+{
+ struct utmp_list *lp, *lp2, *tlp;
+ time_t secs;
+
+ for (lp = head, lp2 = NULL; lp != NULL; )
+ if (up->ut_type == BOOT_TIME || up->ut_type == SHUTDOWN_TIME || strncmp(lp->usr.ut_line, up->ut_line,
+ sizeof (up->ut_line)) == 0) {
+ secs = up->ut_tv.tv_sec - lp->usr.ut_tv.tv_sec;
+ Users = update_user(Users, lp->usr.ut_user, secs);
+#ifdef DEBUG
+ if (Debug)
+ printf("%-.*s %-.*s: %-.*s logged out (%2d:%02d:%02d)\n",
+ 19, ctime(&up->ut_tv.tv_sec),
+ (int)sizeof (lp->usr.ut_line), lp->usr.ut_line,
+ (int)sizeof (lp->usr.ut_user), lp->usr.ut_user,
+ secs / 3600, (secs % 3600) / 60, secs % 60);
+#endif
+ /*
+ * now lose it
+ */
+ tlp = lp;
+ lp = lp->next;
+ if (tlp == head)
+ head = lp;
+ else if (lp2 != NULL)
+ lp2->next = lp;
+ free(tlp);
+ } else {
+ lp2 = lp;
+ lp = lp->next;
+ }
+ return head;
+}
+
+
+/*
+ * if do_tty says ok, login a user
+ */
+struct utmp_list *
+log_in(struct utmp_list *head, struct utmpx *up)
+{
+ struct utmp_list *lp;
+
+ /*
+ * this could be a login. if we're not dealing with
+ * the console name, say it is.
+ *
+ * If we are, and if ut_host==":0.0" we know that it
+ * isn't a real login. _But_ if we have not yet recorded
+ * someone being logged in on Console - due to the wtmp
+ * file starting after they logged in, we'll pretend they
+ * logged in, at the start of the wtmp file.
+ */
+
+#ifdef CONSOLE_TTY
+ if (up->ut_host[0] == ':') {
+ /*
+ * SunOS 4.0.2 does not treat ":0.0" as special but we
+ * do.
+ */
+ if (on_console(head))
+ return head;
+ /*
+ * ok, no recorded login, so they were here when wtmp
+ * started! Adjust ut_tv.tv_sec!
+ */
+ up->ut_tv.tv_sec = FirstTime;
+ /*
+ * this allows us to pick the right logout
+ */
+ (void)strncpy(up->ut_line, Console, sizeof (up->ut_line) - 1);
+ up->ut_line[sizeof (up->ut_line) - 1] = '\0'; /* paranoid! */
+ }
+#endif
+ /*
+ * If we are doing specified ttys only, we ignore
+ * anything else.
+ */
+ if (Flags & AC_T)
+ if (!do_tty(up->ut_line))
+ return head;
+
+ /*
+ * go ahead and log them in
+ */
+ if ((lp = NEW(struct utmp_list)) == NULL)
+ err(1, "malloc");
+ lp->next = head;
+ head = lp;
+ memmove((char *)&lp->usr, (char *)up, sizeof (struct utmpx));
+#ifdef DEBUG
+ if (Debug) {
+ printf("%-.*s %-.*s: %-.*s logged in", 19,
+ ctime(&lp->usr.ut_tv.tv_sec), (int)sizeof (up->ut_line),
+ up->ut_line, (int)sizeof (up->ut_user), up->ut_user);
+ if (*up->ut_host)
+ printf(" (%-.*s)", (int)sizeof (up->ut_host), up->ut_host);
+ putchar('\n');
+ }
+#endif
+ return head;
+}
+
+int
+ac(void)
+{
+ struct utmp_list *lp, *head = NULL;
+ struct utmpx *u, end;
+ struct tm *ltm;
+ time_t secs = 0;
+ int day = -1;
+
+ setutxent_wtmp(1); /* read in forward direction */
+ while ((u = getutxent_wtmp()) != NULL) {
+ if (!FirstTime)
+ FirstTime = u->ut_tv.tv_sec;
+ if (Flags & AC_D) {
+ ltm = localtime(&u->ut_tv.tv_sec);
+ if (day >= 0 && day != ltm->tm_yday) {
+ day = ltm->tm_yday;
+ /*
+ * print yesterday's total
+ */
+ secs = u->ut_tv.tv_sec;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ } else
+ day = ltm->tm_yday;
+ }
+ switch(u->ut_type) {
+ case OLD_TIME:
+ secs = u->ut_tv.tv_sec;
+ break;
+ case NEW_TIME:
+ secs -= u->ut_tv.tv_sec;
+ /*
+ * adjust time for those logged in
+ */
+ for (lp = head; lp != NULL; lp = lp->next)
+ lp->usr.ut_tv.tv_sec -= secs;
+ break;
+ case BOOT_TIME: /* reboot or shutdown */
+ case SHUTDOWN_TIME:
+ head = log_out(head, u);
+ FirstTime = u->ut_tv.tv_sec; /* shouldn't be needed */
+ break;
+ case USER_PROCESS:
+ /*
+ * if they came in on tty[p-y]*, then it is only
+ * a login session if the ut_host field is non-empty
+ */
+ if (strncmp(u->ut_line, "tty", 3) != 0 ||
+ strchr("pqrstuvwxy", u->ut_line[3]) == 0 ||
+ *u->ut_host != '\0')
+ head = log_in(head, u);
+ break;
+ case DEAD_PROCESS:
+ head = log_out(head, u);
+ break;
+ }
+ }
+ endutxent_wtmp();
+ bzero(&end, sizeof(end));
+ end.ut_tv.tv_sec = time((time_t *)0);
+ end.ut_type = SHUTDOWN_TIME;
+
+ if (Flags & AC_D) {
+ ltm = localtime(&end.ut_tv.tv_sec);
+ if (day >= 0 && day != ltm->tm_yday) {
+ /*
+ * print yesterday's total
+ */
+ secs = end.ut_tv.tv_sec;
+ secs -= ltm->tm_sec;
+ secs -= 60 * ltm->tm_min;
+ secs -= 3600 * ltm->tm_hour;
+ show_today(Users, head, secs);
+ }
+ }
+ /*
+ * anyone still logged in gets time up to now
+ */
+ head = log_out(head, &end);
+
+ if (Flags & AC_D)
+ show_today(Users, head, time((time_t *)0));
+ else {
+ if (Flags & AC_P)
+ show_users(Users);
+ show("total", Total);
+ }
+ return 0;
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr,
+#ifdef CONSOLE_TTY
+ "ac [-dp] [-c console] [-t tty] [-w wtmp] [users ...]\n");
+#else
+ "ac [-dp] [-t tty] [-w wtmp] [users ...]\n");
+#endif
+ exit(1);
+}
diff --git a/system_cmds/accton.tproj/accton.8 b/system_cmds/accton.tproj/accton.8
new file mode 100644
index 0000000..039b257
--- /dev/null
+++ b/system_cmds/accton.tproj/accton.8
@@ -0,0 +1,42 @@
+.\" $FreeBSD: src/usr.sbin/accton/accton.8,v 1.13 2004/04/16 09:31:17 brueffer Exp $
+.\"
+.Dd May 21, 1993
+.Dt ACCTON 8
+.Os
+.Sh NAME
+.Nm accton
+.Nd enable/disable system accounting
+.Sh SYNOPSIS
+.Nm
+.Op Ar acctfile
+.Sh DESCRIPTION
+The
+.Nm
+utility is used
+for switching system accounting on or off.
+If called with the argument
+.Ar acctfile ,
+system accounting is enabled.
+The
+.Ar acctfile
+specified must exist prior to starting system accounting, or
+.Nm
+will return an error.
+A record of every process that is started by the
+.Xr execve 2
+system call and then later exits the system is stored in
+.Ar acctfile .
+The
+.Xr sa 8
+command may be used to examine the accounting records.
+If no arguments are given, system accounting is disabled.
+.Sh FILES
+.Bl -tag -width /var/account/acct
+.It Pa /var/account/acct
+default accounting file
+.El
+.Sh SEE ALSO
+.Xr lastcomm 1 ,
+.Xr acct 2 ,
+.Xr acct 5 ,
+.Xr sa 8
diff --git a/system_cmds/accton.tproj/accton.c b/system_cmds/accton.tproj/accton.c
new file mode 100644
index 0000000..dcb7e83
--- /dev/null
+++ b/system_cmds/accton.tproj/accton.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)accton.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/accton/accton.c,v 1.8 2004/08/07 04:19:37 imp Exp $");
+
+#include <sys/types.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch(argc) {
+ case 0:
+ if (acct(NULL))
+ err(1, NULL);
+ break;
+ case 1:
+ if (acct(*argv))
+ err(1, "%s", *argv);
+ break;
+ default:
+ usage();
+ }
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: accton [file]\n");
+ exit(1);
+}
diff --git a/system_cmds/arch.tproj/arch.1 b/system_cmds/arch.tproj/arch.1
new file mode 100644
index 0000000..234b339
--- /dev/null
+++ b/system_cmds/arch.tproj/arch.1
@@ -0,0 +1,245 @@
+.\" Copyright (c) 1994 SigmaSoft, Th. Lockert
+.\" 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 SigmaSoft, Th. Lockert.
+.\" 4. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" 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.
+.\"
+.\" $OpenBSD: arch.1,v 1.2 1996/06/29 20:29:34 tholo Exp $
+.\"
+.\" Modifications made 8/20/97 (c) Apple Computer, Inc.
+.\" Modifications made 11/12/06 (c) Apple Computer, Inc.
+
+.Dd July 8, 2010
+.Dt ARCH 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm arch
+.Nd print architecture type or run selected architecture of a universal binary
+.Sh SYNOPSIS
+.Nm arch
+.Nm arch
+.Op Fl 32
+.Op Fl 64
+.Oo
+.Oo Fl Ns Ar arch_name | Fl arch Ar arch_name Oc Ns ...
+.Oc
+.Op Fl c
+.Oo Fl d Ar envname Oc Ns ...
+.Oo Fl e Ar envname=value Oc Ns ...
+.Op Fl h
+.Ar prog
+.Op Ar args No ...
+.Sh DESCRIPTION
+The
+.Nm arch
+command with no arguments, displays the machine's architecture type.
+.Pp
+The other use of the
+.Nm arch
+command is to run a selected architecture of a universal binary.
+A universal binary contains code that can run on different architectures.
+By default, the operating system will select the architecture that most closely
+matches the processor type.
+A 64-bit architecture is preferred over a 32-bit architecture on a 64-bit
+processor, while only 32-bit architectures can run on a 32-bit processor.
+.Pp
+When the most natural architecture is unavailable, the operating system will
+try to pick another architecture.
+On 64-bit processors, a 32-bit architecture is tried.
+Otherwise, no architecture is run, and an error results.
+.Pp
+The
+.Nm arch
+command can be used to alter the operating system's normal selection order.
+The most common use is to select the 32-bit architecture on a 64-bit processor,
+even if a 64-bit architecture is available.
+.Pp
+The
+.Ar arch_name
+argument must be one of the currently supported architectures:
+.Bl -tag -width x86_64h -offset indent
+.It i386
+32-bit intel
+.It x86_64
+64-bit intel
+.It x86_64h
+64-bit intel (haswell)
+.It arm64
+64-bit arm
+.It arm64e
+64-bit arm (Apple Silicon)
+.El
+.Pp
+If the binary does not contain code for
+.Ar arch_name ,
+the
+.Nm arch
+command may try to select a close match. If arm64 is specified and not found,
+arm64e will be tried next. If this happens, the order the architectures will
+be tried is not guaranteed.
+.Pp
+Either prefix the architecture with a hyphen, or (for compatibility with
+other commands), use
+.Fl arch
+followed by the architecture.
+.Pp
+If more than one architecture is specified, the operating system will try each
+one in order, skipping an architecture that is not supported on the current
+processor, or is unavailable in the universal binary.
+.Pp
+The other options are:
+.Bl -tag -width ".Fl e Ar envname=value"
+.It Fl 32
+Add the native 32-bit architecture to the list of architectures.
+.It Fl 64
+Add the native 64-bit architecture to the list of architectures.
+.It Fl c
+Clears the environment that will be passed to the command to be run.
+.It Fl d Ar envname
+Deletes the named environment variable from the environment that will be passed
+to the command to be run.
+.It Fl e Ar envname=value
+Assigns the given value to the named environment variable in the environment
+that will be passed to the command to be run.
+Any existing environment variable with the same name will be replaced.
+.It Fl h
+Prints a usage message and exits.
+.El
+.Pp
+The
+.Ar prog
+argument is the command to run, followed by any arguments to pass to the
+command.
+It can be a full or partial path, while a lone name will be looked up in the user's
+command search path.
+.Pp
+If no architectures are specified on the command line, the
+.Nm arch
+command takes the basename of the
+.Ar prog
+argument and searches for the first property list file with that basename and
+the
+.Pa \&.plist
+suffix, in the
+.Pa archSettings
+sub-directory in each of the standard domains, in the following order:
+.Bl -tag -width ".Pa /Network/Library/archSettings" -offset indent
+.It ~/Library/archSettings
+User settings
+.It /Library/archSettings
+Local settings
+.It /Network/Library/archSettings
+Network settings
+.It /System/Library/archSettings
+System settings
+.El
+.Pp
+This property list contains the architecture order preferences, as well
+as the full path to the real executable.
+For examples of the property list format, look at the files in
+.Pa /System/Library/archSettings .
+.Ss Example
+On an intel processor:
+.Bd -literal -offset indent
+% perl -MConfig -e 'printf "%s\\n", $Config{byteorder}'
+1234
+.Ed
+.Pp
+shows the intel little endian byte order.
+.Ss Making links to the arch command
+When a link is made to
+.Nm arch
+command with a different name, that name is used to find
+the corresponding property list file.
+Thus, other commands can be wrapped so that they have custom architecture
+selection order.
+.Pp
+Because of some internal logic in the code, hard links to the
+.Nm arch
+command may not work quite right.
+It is best to avoid using hard links, and only use symbolic links to the
+.Nm arch
+command.
+.Ss Environment
+The environment variable
+.Ev ARCHPREFERENCE
+can be used to provide architecture order preferences.
+It is checked before looking for the corresponding property list file.
+.Pp
+The value of the environment variable
+.Ev ARCHPREFERENCE
+is composed of one or more specifiers, separated by semicolons.
+A specifier is made up of one, two or three fields, separated by colons.
+Architectures specified in order, are separated by commas and make up the last
+(mandatory) field.
+The first field, if specified, is a name of a program, which selects this
+specifier if that name matches the program name in question.
+If the name field is empty or there is no name field, the specifier matches
+any program name.
+Thus, ordering of specifiers is important, and the one with no name should
+be last.
+.Pp
+When the
+.Nm arch
+command is called directly, the
+.Ar prog
+name provides the path information to the executable (possibly via the command
+search path).
+When a name is specified in a
+.Ev ARCHPREFERENCE
+specifier, the path information can alternately be specified as a second
+field following the name.
+When the
+.Nm arch
+command is called indirectly via a link, this path information must be
+specified.
+If not specified as a second field in a specifier, the executable path will
+be looked up in the corresponding property list file.
+.Ss Example ARCHPREFERENCE Values
+.Bl -tag -width " "
+.It i386,x86_64,x86_64h,arm64,arm64e
+A specifier that matches any name.
+.It foo:i386,x86_64,x86_64h,arm64,arm64e
+A specifier that matches the program named
+.Nm foo
+(the full executable path is in the
+.Pa foo.plist
+file).
+.It foo:/op/bin/boo:i386,x86_64,x86_64h,arm64,arm64e
+A specifier with all fields specified.
+.It baz:i386;x86_64;x86_64h,arm64,arm64e
+A specifier for
+.Nm baz
+and a second specifier that would match any other name.
+.El
+.Sh BUGS
+Running the
+.Nm arch
+command on an interpreter script may not work if the interpreter is a link
+to the arch command, especially if a 64-bit architecture is specified (since the
+.Nm arch
+command is 2-way universal, 32-bit only).
+.Sh SEE ALSO
+.Xr machine 1
diff --git a/system_cmds/arch.tproj/arch.c b/system_cmds/arch.tproj/arch.c
new file mode 100644
index 0000000..b522ce8
--- /dev/null
+++ b/system_cmds/arch.tproj/arch.c
@@ -0,0 +1,802 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/cdefs.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <spawn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <paths.h>
+#include <err.h>
+#include <mach/mach.h>
+#include <mach-o/arch.h>
+#include <limits.h>
+#include <sys/fcntl.h>
+#include <glob.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <NSSystemDirectories.h>
+#include <sysdir.h>
+
+#if defined(__x86_64__)
+#include <System/i386/cpu_capabilities.h>
+#endif
+
+#if TARGET_OS_OSX
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#endif
+
+#ifndef ARCH_PROG
+#define ARCH_PROG "arch"
+#endif
+#ifndef MACHINE_PROG
+#define MACHINE_PROG "machine"
+#endif
+
+#define kKeyExecPath "ExecutablePath"
+#define kKeyPlistVersion "PropertyListVersion"
+#define kKeyPrefOrder "PreferredOrder"
+#define kPlistExtension ".plist"
+#define kSettingsDir "archSettings"
+
+static const char envname[] = "ARCHPREFERENCE";
+
+/* The CPU struct contains the argument buffer to posix_spawnattr_setbinpref_np */
+
+typedef struct {
+ cpu_type_t *types;
+ cpu_subtype_t *subtypes;
+ int errs;
+ size_t count;
+ size_t capacity;
+} CPU;
+
+typedef struct {
+ const char *arch;
+ cpu_type_t cpu;
+ cpu_subtype_t cpusubtype;
+} CPUTypes;
+
+static const CPUTypes knownArchs[] = {
+ {"i386", CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL},
+ {"x86_64", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL},
+ {"x86_64h", CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_H},
+ {"arm", CPU_TYPE_ARM, CPU_SUBTYPE_ARM_ALL},
+ {"arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64_ALL},
+ /* rdar://65725144 ("arch -arm64" command should launch arm64e slice for 2-way fat x86_64+arm64e binaries) */
+ /* This will modify the order if someone, for whatever reason, specifies -arch arm64 -arch x86_64 -arch arm64e */
+ {"arm64", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E},
+ {"arm64e", CPU_TYPE_ARM64, CPU_SUBTYPE_ARM64E},
+ {"arm64_32", CPU_TYPE_ARM64_32, CPU_SUBTYPE_ARM64_32_ALL},
+};
+
+/* environment SPI */
+char **_copyenv(char **env);
+int _setenvp(const char *name, const char *value, int rewrite, char ***envp, void *state);
+int _unsetenvp(const char *name, char ***envp, void *state);
+
+/* copy of environment */
+char **envCopy = NULL;
+extern char **environ;
+
+/*
+ * The native 32 and 64-bit architectures (this is relative to the architecture
+ * the arch command is running). NULL means unsupported.
+ */
+
+static const char*
+native32(void)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ return "i386";
+#elif defined(__arm64__) && !defined(__LP64__)
+ return "arm64_32";
+#elif defined(__arm__)
+ return "arm";
+#else
+ return NULL;
+#endif
+}
+
+static const char*
+native64(void)
+{
+#if defined(__x86_64__)
+ // FIXME: It is not clear if we should do this check, given the comment above which states "this is relative to the architecture the arch command is running".
+ if (((*(uint64_t*)_COMM_PAGE_CPU_CAPABILITIES64) & kIsTranslated))
+ return "arm64";
+ return "x86_64";
+#elif defined(__i386__)
+ return "x86_64";
+#elif defined(__arm64__) && defined(__LP64__)
+ return "arm64";
+#elif defined(__arm64__)
+ return "arm64_32";
+#else
+ return NULL;
+#endif
+}
+
+static bool
+isSupportedCPU(cpu_type_t cpu)
+{
+#if defined(__x86_64__)
+ if (((*(uint64_t*)_COMM_PAGE_CPU_CAPABILITIES64) & kIsTranslated))
+ return cpu == CPU_TYPE_X86_64 || cpu == CPU_TYPE_ARM64;
+ return cpu == CPU_TYPE_X86_64;
+#elif defined(__i386__)
+ return cpu == CPU_TYPE_I386 || cpu == CPU_TYPE_X86_64;
+#elif defined(__arm64__) && defined(__LP64__) && TARGET_OS_OSX
+ return cpu == CPU_TYPE_X86_64 || cpu == CPU_TYPE_ARM64;
+#elif defined(__arm64__) && defined(__LP64__)
+ return cpu == CPU_TYPE_ARM64;
+#elif defined(__arm64__)
+ return cpu == CPU_TYPE_ARM64_32;
+#elif defined(__arm__)
+ return cpu == CPU_TYPE_ARM;
+#else
+ #error "Unsupported architecture"
+#endif
+}
+
+bool unrecognizednative32seen = false;
+bool unrecognizednative64seen = false;
+
+/*
+ * arch - perform the original behavior of the arch and machine commands.
+ * The archcmd flag is non-zero for the arch command, zero for the machine
+ * command. This routine never returns.
+ */
+static void __dead2
+arch(int archcmd)
+{
+ const NXArchInfo *arch = NXGetLocalArchInfo();
+
+ if(!arch)
+ errx(-1, "Unknown architecture.");
+ if(archcmd) {
+ arch = NXGetArchInfoFromCpuType(arch->cputype, CPU_SUBTYPE_MULTIPLE);
+ if(!arch)
+ errx(-1, "Unknown architecture.");
+ }
+ printf("%s%s", arch->name, (isatty(STDIN_FILENO) ? "\n" : ""));
+ exit(0);
+}
+
+/*
+ * spawnIt - run the posix_spawn command. cpu is the auto-sizing CPU structure.
+ * pflag is non-zero to call posix_spawnp; zero means to call posix_spawn.
+ * str is the name/path to pass to posix_spawn{,p}, and argv are
+ * the argument arrays to pass. This routine never returns.
+ */
+static void __dead2
+spawnIt(CPU *cpu, int pflag, const char *str, char **argv)
+{
+ posix_spawnattr_t attr;
+ pid_t pid;
+ int ret;
+ size_t copied;
+ size_t count = cpu->count;
+ cpu_type_t *prefs = cpu->types;
+ cpu_subtype_t *subprefs = cpu->subtypes;
+
+ if(count == 0) {
+ if(unrecognizednative32seen)
+ warnx("Unsupported native 32-bit architecture");
+ if(unrecognizednative64seen)
+ warnx("Unsupported native 64-bit architecture");
+ exit(1);
+ }
+
+ if(unrecognizednative32seen)
+ fprintf(stderr, "warning: unsupported native 32-bit architecture\n");
+ if(unrecognizednative64seen)
+ fprintf(stderr, "warning: unsupported native 64-bit architecture\n");
+
+ if((ret = posix_spawnattr_init(&attr)) != 0)
+ errc(1, ret, "posix_spawnattr_init");
+ /* do the equivalent of exec, rather than creating a separate process */
+ if((ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC)) != 0)
+ errc(1, ret, "posix_spawnattr_setflags");
+ if((ret = posix_spawnattr_setarchpref_np(&attr, count, prefs, subprefs, &copied)) != 0)
+ errc(1, ret, "posix_spawnattr_setbinpref_np");
+
+#if TARGET_OS_OSX
+ for (size_t i = 0; i < copied; i++) {
+ if (prefs[i] == CPU_TYPE_ARM64) {
+ int affinity = 0;
+ size_t asize = sizeof(affinity);
+ sysctlbyname("kern.curproc_arch_affinity", NULL, NULL, &affinity, asize);
+ }
+ }
+#endif /* TARGET_OS_OSX */
+
+ if(copied != count)
+ errx(1, "posix_spawnattr_setbinpref_np only copied %lu of %lu", copied, count);
+ if(pflag)
+ ret = posix_spawnp(&pid, str, NULL, &attr, argv, envCopy ? envCopy : environ);
+ else
+ ret = posix_spawn(&pid, str, NULL, &attr, argv, envCopy ? envCopy : environ);
+ errc(1, ret, "posix_spawn%s: %s", (pflag ? "p" : ""), str);
+}
+
+/*
+ * initCPU - initialize a CPU structure, a dynamically expanding CPU types
+ * array.
+ */
+static void
+initCPU(CPU *cpu)
+{
+ cpu->errs = 0;
+ cpu->count = 0;
+ cpu->capacity = 1;
+ cpu->types = (cpu_type_t *)malloc(cpu->capacity * sizeof(cpu_type_t));
+ if(!cpu->types)
+ err(1, "Failed to malloc CPU type buffer");
+ cpu->subtypes = (cpu_subtype_t *)malloc(cpu->capacity * sizeof(cpu_subtype_t));
+ if(!cpu->subtypes)
+ err(1, "Failed to malloc CPU subtype buffer");
+}
+
+/*
+ * addCPU - add a new CPU type value to the CPU structure, expanding
+ * the array as necessary.
+ */
+static void
+addCPU(CPU *cpu, cpu_type_t n, cpu_subtype_t s)
+{
+ if(cpu->count == cpu->capacity) {
+ cpu_type_t *newcpubuf;
+ cpu_subtype_t *newcpusubbuf;
+
+ cpu->capacity *= 2;
+ newcpubuf = (cpu_type_t *)realloc(cpu->types, cpu->capacity * sizeof(cpu_type_t));
+ if(!newcpubuf)
+ err(1, "Out of memory realloc-ing CPU types structure");
+ cpu->types = newcpubuf;
+ newcpusubbuf = (cpu_subtype_t *)realloc(cpu->subtypes, cpu->capacity * sizeof(cpu_subtype_t));
+ if(!newcpusubbuf)
+ err(1, "Out of memory realloc-ing CPU subtypes structure");
+ cpu->subtypes = newcpusubbuf;
+
+ }
+ cpu->types[cpu->count] = n;
+ cpu->subtypes[cpu->count++] = s;
+}
+
+/*
+ * addCPUbyname - add a new CPU type, given by name, to the CPU structure,
+ * expanding the array as necessary. The name is converted to a type value
+ * by the ArchDict dictionary.
+ */
+static void
+addCPUbyname(CPU *cpu, const char *name)
+{
+ int i;
+ size_t numKnownArchs = sizeof(knownArchs)/sizeof(knownArchs[0]);
+
+ for (i=0; i < numKnownArchs; i++) {
+ if (!isSupportedCPU(knownArchs[i].cpu))
+ continue;
+ int start = i;
+ /* rdar://65725144 ("arch -arm64" command should launch arm64e slice for 2-way fat x86_64+arm64e binaries) */
+ /* Add subtypes that closely match the specified name */
+ while ( i < numKnownArchs &&
+ 0 == strcasecmp(name, knownArchs[i].arch) ) {
+ addCPU(cpu, knownArchs[i].cpu, knownArchs[i].cpusubtype);
+ i++;
+ }
+ if (start != i)
+ return;
+ }
+
+ /* Didn't match a string in knownArchs */
+ warnx("Unknown architecture: %s", name);
+ cpu->errs++;
+}
+
+/*
+ * useEnv - parse the environment variable for CPU preferences. Use name
+ * to look for program-specific preferences, and append any CPU types to cpu.
+ * Returns the number of CPU types. Returns any specified execute path in
+ * execpath.
+ *
+ * The environment variable ARCHPREFERENCE has the format:
+ * spec[;spec]...
+ * a semicolon separated list of specifiers. Each specifier has the format:
+ * [prog:[execpath:]]type[,type]...
+ * a comma separate list of CPU type names, optionally proceeded by a program
+ * name and an execpath. If program name exist, that types only apply to that
+ * program. If execpath is specified, it is returned. If no program name
+ * exists, then it applies to all programs. So ordering of the specifiers is
+ * important, as the default (no program name) specifier must be last.
+ */
+static size_t
+useEnv(CPU *cpu, const char *name, char **execpath)
+{
+ char *val = getenv(envname);
+ if(!val)
+ return 0;
+
+ /* cp will point to the basename of name */
+ const char *cp = strrchr(name, '/');
+ if(cp) {
+ cp++;
+ if(!*cp)
+ errx(1, "%s: no name after last slash", name);
+ } else
+ cp = name;
+ /* make a copy of the environment variable value, so we can modify it */
+ val = strdup(val);
+ if(!val)
+ err(1, "Can't copy environment %s", envname);
+ char *str = val;
+ char *blk;
+ /* for each specifier */
+ while((blk = strsep(&str, ";")) != NULL) {
+ if(*blk == 0)
+ continue; /* two adjacent semicolons */
+ /* now split on colons */
+ char *n = strsep(&blk, ":");
+ if(blk) {
+ char *p = strsep(&blk, ":");
+ if(!blk) { /* there is only one colon, so no execpath */
+ blk = p;
+ p = NULL;
+ } else if(!*p) /* two consecutive colons, so no execpath */
+ p = NULL;
+ if(!*blk)
+ continue; /* no cpu list, so skip */
+ /* if the name matches, or there is no name, process the cpus */
+ if(!*n || strcmp(n, cp) == 0) {
+ if(cpu->count == 0) { /* only if we haven't processed architectures */
+ char *t;
+ while((t = strsep(&blk, ",")) != NULL)
+ addCPUbyname(cpu, t);
+ }
+ *execpath = (*n ? p : NULL); /* only use the exec path is name is set */
+ break;
+ }
+ } else { /* no colons at all, so process as default */
+ if(cpu->count == 0) { /* only if we haven't processed architectures */
+ blk = n;
+ while((n = strsep(&blk, ",")) != NULL)
+ addCPUbyname(cpu, n);
+ }
+ *execpath = NULL;
+ break;
+ }
+ }
+ if(cpu->errs) /* errors during addCPUbyname are fatal */
+ exit(1);
+ return cpu->count; /* return count of architectures */
+}
+
+/*
+ * spawnFromPreference - called when argv[0] is not "arch" or "machine", or
+ * argv[0] was arch, but no commandline architectures were specified.
+ * If the environment variable ARCHPREFERENCE is specified, and there is a
+ * match to argv[0], use the specified cpu preferences. If no exec path
+ * is specified in ARCHPREFERENCE, or no match is found in ARCHPREFERENCE,
+ * get any additional information from a .plist file with the name of argv[0].
+ * This routine never returns.
+ */
+static void __dead2
+spawnFromPreferences(CPU *cpu, int needexecpath, char **argv)
+{
+ char *epath = NULL;
+ char fpath[PATH_MAX];
+ char execpath2[PATH_MAX];
+ CFDictionaryRef plist = NULL;
+ sysdir_search_path_enumeration_state state;
+ size_t count, i;
+ const char *prog = strrchr(*argv, '/');
+
+ if(prog)
+ prog++;
+ else
+ prog = *argv;
+ if(!*prog)
+ errx(1, "Not program name specified");
+
+ /* check the environment variable first */
+ if((count = useEnv(cpu, prog, &epath)) > 0) {
+ /* if we were called as arch, use posix_spawnp */
+ if(!needexecpath)
+ spawnIt(cpu, 1, (epath ? epath : *argv), argv);
+ /* otherwise, if we have the executable path, call posix_spawn */
+ if(epath)
+ spawnIt(cpu, 0, epath, argv);
+ }
+
+ state = sysdir_start_search_path_enumeration(SYSDIR_DIRECTORY_LIBRARY, SYSDIR_DOMAIN_MASK_ALL);
+ while ((state = sysdir_get_next_search_path_enumeration(state, fpath))) {
+
+ if (fpath[0] == '~') {
+ glob_t pglob;
+ int gret;
+
+ bzero(&pglob, sizeof(pglob));
+
+ gret = glob(fpath, GLOB_TILDE, NULL, &pglob);
+ if (gret == 0) {
+ int i;
+ for (i=0; i < pglob.gl_pathc; i++) {
+ /* take the first glob expansion */
+ strlcpy(fpath, pglob.gl_pathv[i], sizeof(fpath));
+ break;
+ }
+ }
+ globfree(&pglob);
+ }
+
+ // Handle path
+ strlcat(fpath, "/" kSettingsDir "/", sizeof(fpath));
+ strlcat(fpath, prog, sizeof(fpath));
+ strlcat(fpath, kPlistExtension, sizeof(fpath));
+ // printf("component: %s\n", fpath);
+
+ int fd, ret;
+ size_t length;
+ ssize_t rsize;
+ struct stat sb;
+ void *buffer;
+ fd = open(fpath, O_RDONLY, 0);
+ if (fd >= 0) {
+ ret = fstat(fd, &sb);
+ if (ret == 0) {
+ if (sb.st_size <= SIZE_T_MAX) {
+ length = (size_t)sb.st_size;
+ buffer = malloc(length); /* ownership transferred to CFData */
+ if (buffer) {
+ rsize = read(fd, buffer, length);
+ if (rsize == length) {
+ CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, length, kCFAllocatorMalloc);
+ if (data) {
+ buffer = NULL;
+ plist = CFPropertyListCreateWithData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, NULL);
+ CFRelease(data);
+ }
+ }
+ if (buffer) {
+ free(buffer);
+ }
+ }
+ }
+ }
+ close(fd);
+ }
+
+ if (plist) {
+ break;
+ }
+ }
+
+ if (plist) {
+ if (CFGetTypeID(plist) != CFDictionaryGetTypeID())
+ errx(1, "%s: plist not a dictionary", fpath);
+ } else {
+ errx(1, "Can't find any plists for %s", prog);
+ }
+
+ int errs = 0; /* scan for all errors and fail later */
+ do { /* begin block */
+ /* check the plist version */
+ CFStringRef vers = CFDictionaryGetValue(plist, CFSTR(kKeyPlistVersion));
+ if(!vers) {
+ warnx("%s: No key %s", fpath, kKeyPlistVersion);
+ errs++;
+ } else if(CFGetTypeID(vers) != CFStringGetTypeID()) {
+ warnx("%s: %s is not a string", fpath, kKeyPlistVersion);
+ errs++;
+ } else if(!CFEqual(vers, CFSTR("1.0"))) {
+ warnx("%s: %s not 1.0", fpath, kKeyPlistVersion);
+ errs++;
+ }
+ /* get the execpath */
+ CFStringRef execpath = CFDictionaryGetValue(plist, CFSTR(kKeyExecPath));
+ if(!execpath) {
+ warnx("%s: No key %s", fpath, kKeyExecPath);
+ errs++;
+ } else if(CFGetTypeID(execpath) != CFStringGetTypeID()) {
+ warnx("%s: %s is not a string", fpath, kKeyExecPath);
+ errs++;
+ }
+ if (!CFStringGetFileSystemRepresentation(execpath, execpath2, sizeof(execpath2))) {
+ warnx("%s: could not get exec path", fpath);
+ errs++;
+ }
+ /* if we already got cpu preferences from ARCHPREFERENCE, we are done */
+ if(count > 0)
+ break;
+ /* otherwise, parse the cpu preferences from the plist */
+ CFArrayRef p = CFDictionaryGetValue(plist, CFSTR(kKeyPrefOrder));
+ if(!p) {
+ warnx("%s: No key %s", fpath, kKeyPrefOrder);
+ errs++;
+ } else if(CFGetTypeID(p) != CFArrayGetTypeID()) {
+ warnx("%s: %s is not an array", fpath, kKeyPrefOrder);
+ errs++;
+ } else if((count = CFArrayGetCount(p)) == 0) {
+ warnx("%s: no entries in %s", fpath, kKeyPrefOrder);
+ errs++;
+ } else {
+ /* finally build the cpu type array */
+ for(i = 0; i < count; i++) {
+ CFStringRef a = CFArrayGetValueAtIndex(p, i);
+ if(CFGetTypeID(a) != CFStringGetTypeID()) {
+ warnx("%s: entry %lu of %s is not a string", fpath, i, kKeyPrefOrder);
+ errs++;
+ } else {
+ char astr[128];
+ if (CFStringGetCString(a, astr, sizeof(astr), kCFStringEncodingASCII)) {
+ addCPUbyname(cpu, astr);
+ }
+ }
+ }
+ }
+ } while(0); /* end block */
+ if(errs) /* exit if there were any reported errors */
+ exit(1);
+
+ CFRelease(plist);
+
+ /* call posix_spawn */
+ spawnIt(cpu, 0, execpath2, argv);
+}
+
+static void __dead2
+usage(int ret)
+{
+ fprintf(stderr,
+ "Usage: %s\n"
+ " Display the machine's architecture type\n"
+ "Usage: %s {-arch_name | -arch arch_name} ... [-c] [-d envname] ... [-e envname=value] ... [-h] prog [arg ...]\n"
+ " Run prog with any arguments, using the given architecture\n"
+ " order. If no architectures are specified, use the\n"
+ " ARCHPREFERENCE environment variable, or a property list file.\n"
+ " -c will clear out all environment variables before running prog.\n"
+ " -d will delete the given environment variable before running prog.\n"
+ " -e will add the given environment variable/value before running prog.\n"
+ " -h will print usage message and exit.\n",
+ ARCH_PROG, ARCH_PROG);
+ exit(ret);
+}
+
+/*
+ * wrapped - check the path to see if it is a link to /usr/bin/arch.
+ */
+static int
+wrapped(const char *name)
+{
+ size_t lp, ln;
+ char *p;
+ char *bp = NULL;
+ char *cur, *path;
+ char buf[MAXPATHLEN], rpbuf[MAXPATHLEN];
+ struct stat sb;
+
+ ln = strlen(name);
+
+ do { /* begin block */
+ /* If it's an absolute or relative path name, it's easy. */
+ if(index(name, '/')) {
+ if(stat(name, &sb) == 0 && S_ISREG(sb.st_mode) && access(name, X_OK) == 0) {
+ bp = (char *)name;
+ break;
+ }
+ errx(1, "%s isn't executable", name);
+ }
+
+ /* search the PATH, looking for name */
+ if((path = getenv("PATH")) == NULL)
+ path = _PATH_DEFPATH;
+
+ cur = alloca(strlen(path) + 1);
+ if(cur == NULL)
+ err(1, "alloca");
+ strcpy(cur, path);
+ while((p = strsep(&cur, ":")) != NULL) {
+ /*
+ * It's a SHELL path -- double, leading and trailing colons
+ * mean the current directory.
+ */
+ if(*p == '\0') {
+ p = ".";
+ lp = 1;
+ } else
+ lp = strlen(p);
+
+ /*
+ * If the path is too long complain. This is a possible
+ * security issue; given a way to make the path too long
+ * the user may execute the wrong program.
+ */
+ if(lp + ln + 2 > sizeof(buf)) {
+ warn("%s: path too long", p);
+ continue;
+ }
+ bcopy(p, buf, lp);
+ buf[lp] = '/';
+ bcopy(name, buf + lp + 1, ln);
+ buf[lp + ln + 1] = '\0';
+ if(stat(buf, &sb) == 0 && S_ISREG(sb.st_mode) && access(buf, X_OK) == 0) {
+ bp = buf;
+ break;
+ }
+ }
+ if(p == NULL)
+ errx(1, "Can't find %s in PATH", name);
+ } while(0); /* end block */
+ if(realpath(bp, rpbuf) == NULL)
+ errx(1, "realpath failed on %s", bp);
+ return (strcmp(rpbuf, "/usr/bin/" ARCH_PROG) == 0);
+}
+
+/*
+ * spawnFromArgs - called when arch has arguments specified. The arch command
+ * line arguments are:
+ * % arch [[{-xxx | -arch xxx}]...] prog [arg]...
+ * where xxx is a cpu name, and the command to execute and its arguments follow.
+ * If no commandline cpu names are given, the environment variable
+ * ARCHPREFERENCE is used. This routine never returns.
+ */
+
+#define MATCHARG(a,m) ({ \
+ const char *arg = *(a); \
+ if(arg[1] == '-') arg++; \
+ strcmp(arg, (m)) == 0; \
+})
+
+#define MATCHARGWITHVALUE(a,m,n,e) ({ \
+ const char *ret = NULL; \
+ const char *arg = *(a); \
+ if(arg[1] == '-') arg++; \
+ if(strcmp(arg, (m)) == 0) { \
+ if(*++(a) == NULL) { \
+ warnx(e); \
+ usage(1); \
+ } \
+ ret = *(a); \
+ } else if(strncmp(arg, (m), (n)) == 0 && arg[n] == '=') { \
+ ret = arg + (n) + 1; \
+ } \
+ ret; \
+})
+
+#define MAKEENVCOPY(e) \
+ if(!envCopy) { \
+ envCopy = _copyenv(environ); \
+ if(envCopy == NULL) \
+ errx(1, (e)); \
+ }
+
+static void __dead2
+spawnFromArgs(CPU *cpu, char **argv)
+{
+ const char *ap, *ret;
+
+ /* process arguments */
+ for(argv++; *argv && **argv == '-'; argv++) {
+ if((ret = MATCHARGWITHVALUE(argv, "-arch", 5, "-arch without architecture"))) {
+ ap = ret;
+ } else if(MATCHARG(argv, "-32")) {
+ ap = native32();
+ if(!ap) {
+ unrecognizednative32seen = true;
+ continue;
+ }
+ } else if(MATCHARG(argv, "-64")) {
+ ap = native64();
+ if(!ap) {
+ unrecognizednative64seen = true;
+ continue;
+ }
+ } else if(MATCHARG(argv, "-c")) {
+ free(envCopy);
+ envCopy = _copyenv(NULL); // create empty environment
+ if(!envCopy)
+ errx(1, "Out of memory processing -c");
+ continue;
+ } else if((ret = MATCHARGWITHVALUE(argv, "-d", 2, "-d without envname"))) {
+ MAKEENVCOPY("Out of memory processing -d");
+ _unsetenvp(ret, &envCopy, NULL);
+ continue;
+ } else if((ret = MATCHARGWITHVALUE(argv, "-e", 2, "-e without envname=value"))) {
+ MAKEENVCOPY("Out of memory processing -e");
+ const char *cp = strchr(ret, '=');
+ if(!cp) {
+ warnx("-e %s: no equal sign", ret);
+ usage(1);
+ }
+ cp++; // skip to value
+ /*
+ * _setenvp() only uses the name before any equal sign found in
+ * the first argument.
+ */
+ _setenvp(ret, cp, 1, &envCopy, NULL);
+ continue;
+ } else if(MATCHARG(argv, "-h")) {
+ usage(0);
+ } else {
+ ap = *argv + 1;
+ if(*ap == '-') ap++;
+ }
+ addCPUbyname(cpu, ap);
+ }
+ if(cpu->errs)
+ exit(1);
+ if(!*argv || !**argv) {
+ warnx("No command to execute");
+ usage(1);
+ }
+ /* if the program is already a link to arch, then force execpath */
+ int needexecpath = wrapped(*argv);
+
+ /*
+ * If we don't have any architecutures, try ARCHPREFERENCE and plist
+ * files.
+ */
+ if((cpu->count == 0) || needexecpath)
+ spawnFromPreferences(cpu, needexecpath, argv); /* doesn't return */
+
+ /*
+ * Call posix_spawnp on the program name.
+ */
+ spawnIt(cpu, 1, *argv, argv);
+}
+
+
+/* the main() routine */
+int
+main(int argc, char **argv)
+{
+ const char *prog = getprogname();
+ int my_name_is_arch;
+ CPU cpu;
+
+ if(strcmp(prog, MACHINE_PROG) == 0) {
+ if(argc > 1)
+ errx(-1, "no arguments accepted");
+ arch(0); /* the "machine" command was called */
+ } else if((my_name_is_arch = (strcmp(prog, ARCH_PROG) == 0))) {
+ if(argc == 1)
+ arch(1); /* the "arch" command with no arguments was called */
+ }
+
+ initCPU(&cpu);
+
+ if(my_name_is_arch)
+ spawnFromArgs(&cpu, argv);
+ else
+ spawnFromPreferences(&cpu, 1, argv);
+
+ /* should never get here */
+ errx(1, "returned from spawn");
+}
diff --git a/system_cmds/arch.tproj/machine.1 b/system_cmds/arch.tproj/machine.1
new file mode 100644
index 0000000..139c2ec
--- /dev/null
+++ b/system_cmds/arch.tproj/machine.1
@@ -0,0 +1,49 @@
+.\" $OpenBSD: machine.1,v 1.2 1996/06/26 05:36:23 deraadt Exp $
+.\" Copyright (c) 1980, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)machine.1 5.5 (Berkeley) 7/26/91
+.\"
+.Dd July 26, 1991
+.Dt MACHINE 1
+.Os
+.Sh NAME
+.Nm machine
+.Nd print machine type
+.Sh SYNOPSIS
+.Nm machine
+.Sh DESCRIPTION
+The
+.Nm machine
+command displays the machine type.
+.Sh SEE ALSO
+.Xr arch 1 ,
+.Xr make 1
diff --git a/system_cmds/at.tproj/LEGAL b/system_cmds/at.tproj/LEGAL
new file mode 100644
index 0000000..92b1b49
--- /dev/null
+++ b/system_cmds/at.tproj/LEGAL
@@ -0,0 +1,29 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+
+Sorry for the long wait, but there still were a few things to
+be ironed out in at, which I've finally done :-)
+
+The FreeBSD team does have my permission to use at, version 2.9,
+under the BSD license.
+
+You'll find it on sunsite.unc.edu's Incoming, hopefully; the
+md5 checksum is
+
+3ba2ca3c0e87e1a04feae2c6c1376b0d at-2.9.tgz
+
+Best regards
+ Thomas
+- --
+Thomas Koenig, Thomas.Koenig@ciw.uni-karlsruhe.de, ig25@dkauni2.bitnet.
+The joy of engineering is to find a straight line on a double
+logarithmic diagram.
+
+-----BEGIN PGP SIGNATURE-----
+Version: 2.6.2i
+
+iQCVAwUBMCjVrPBu+cbJcKCVAQFNiQP/dpWP57s/E8plVGUD3zfgOXDmKUvg8U7a
+VwRzJrIMuSgnSJs0wkpvcomc3NLicipfX7hhWLh/xatPM2YbF7O5HZoNdvWvexD2
+1Y67zJ+0HFb1mPnSBOrS5RFiQAe3KqmGec6E14Rih/qNoFQZBVRFXZ4xxuwP+0Rs
+e2U+TVTUz6A=
+=TvyW
+-----END PGP SIGNATURE-----
diff --git a/system_cmds/at.tproj/at.1 b/system_cmds/at.tproj/at.1
new file mode 100644
index 0000000..1a06d66
--- /dev/null
+++ b/system_cmds/at.tproj/at.1
@@ -0,0 +1,369 @@
+.\" $FreeBSD: src/usr.bin/at/at.man,v 1.34 2003/03/26 02:38:18 keramida Exp $
+.Dd January 13, 2002
+.Dt "AT" 1
+.Os
+.Sh NAME
+.Nm at ,
+.Nm batch ,
+.Nm atq ,
+.Nm atrm
+.Nd queue, examine, or delete jobs for later execution
+.Sh SYNOPSIS
+.Nm at
+.Op Fl q Ar queue
+.Op Fl f Ar file
+.Op Fl mldbv
+.Ar time
+.Nm at
+.Op Fl q Ar queue
+.Op Fl f Ar file
+.Op Fl mldbv
+.Fl t
+.Sm off
+.Op Oo Ar CC Oc Ar YY
+.Ar MM DD hh mm Op . Ar SS
+.Sm on
+.Nm at
+.Fl c Ar job Op Ar job ...
+.Nm at
+.Fl l Op Ar job ...
+.Nm at
+.Fl l
+.Fl q Ar queue
+.Nm at
+.Fl r Ar job Op Ar job ...
+.Pp
+.Nm atq
+.Op Fl q Ar queue
+.Op Fl v
+.Pp
+.Nm atrm
+.Ar job
+.Op Ar job ...
+.Pp
+.Nm batch
+.Op Fl q Ar queue
+.Op Fl f Ar file
+.Op Fl mv
+.Op Ar time
+.Sh DESCRIPTION
+The
+.Nm at
+and
+.Nm batch
+utilities
+read commands from standard input or a specified file.
+The commands are executed at a later time, using
+.Xr sh 1 .
+.Bl -tag -width indent
+.It Nm at
+executes commands at a specified time;
+.It Nm atq
+lists the user's pending jobs, unless the user is the superuser; in that
+case, everybody's jobs are listed;
+.It Nm atrm
+deletes jobs;
+.It Nm batch
+executes commands when system load levels permit; in other words, when the load average
+drops below _LOADAVG_MX (1.5), or the value specified in the invocation of
+.Nm atrun .
+.El
+.Pp
+The
+.Nm at
+utility allows some moderately complex
+.Ar time
+specifications.
+It accepts times of the form
+.Ar HHMM
+or
+.Ar HH:MM
+to run a job at a specific time of day.
+(If that time is already past, the next day is assumed.)
+As an alternative, the following keywords may be specified:
+.Em midnight ,
+.Em noon ,
+or
+.Em teatime
+(4pm)
+and time-of-day may be suffixed with
+.Em AM
+or
+.Em PM
+for running in the morning or the evening.
+The day on which the job is to be run may also be specified
+by giving a date in the form
+.Ar \%month-name day
+with an optional
+.Ar year ,
+or giving a date of the forms
+.Ar DD.MM.YYYY ,
+.Ar DD.MM.YY ,
+.Ar MM/DD/YYYY ,
+.Ar MM/DD/YY ,
+.Ar MMDDYYYY , or
+.Ar MMDDYY .
+The specification of a date must follow the specification of
+the time of day.
+Time can also be specified as:
+.Op Em now
+.Em + Ar count \%time-units ,
+where the time-units can be
+.Em minutes ,
+.Em hours ,
+.Em days ,
+.Em weeks ,
+.Em months
+or
+.Em years
+and
+.Nm at
+may be told to run the job today by suffixing the time with
+.Em today
+and to run the job tomorrow by suffixing the time with
+.Em tomorrow .
+The shortcut
+.Em next
+can be used instead of
+.Em + 1 .
+.Pp
+For example, to run a job at 4pm three days from now, use
+.Nm at Ar 4pm + 3 days ,
+to run a job at 10:00am on July 31, use
+.Nm at Ar 10am Jul 31
+and to run a job at 1am tomorrow, use
+.Nm at Ar 1am tomorrow .
+.Pp
+The
+.Nm at
+utility also supports the
+.Tn POSIX
+time format (see
+.Fl t
+option).
+.Pp
+For both
+.Nm at
+and
+.Nm batch ,
+commands are read from standard input or the file specified
+with the
+.Fl f
+option.
+The working directory, the environment (except for the variables
+.Ev TERM ,
+.Ev TERMCAP ,
+.Ev DISPLAY
+and
+.Em _ ) ,
+and the
+.Ar umask
+are retained from the time of invocation.
+An
+.Nm at
+or
+.Nm batch
+command invoked from a
+.Xr su 1
+shell will retain the current userid.
+The user will be mailed standard error and standard output from his
+commands, if any.
+Mail will be sent using the command
+.Xr sendmail 8 .
+If
+.Nm at
+is executed from a
+.Xr su 1
+shell, the owner of the login shell will receive the mail.
+.Pp
+The superuser may use these commands in any case.
+For other users, permission to use
+.Nm at
+is determined by the files
+.Pa _PERM_PATH/at.allow
+and
+.Pa _PERM_PATH/at.deny .
+.Pp
+If the file
+.Pa _PERM_PATH/at.allow
+exists, only usernames mentioned in it are allowed to use
+.Nm at .
+In these two files,
+a user is considered to be listed
+only if the user name has no blank or other characters
+before it on its line and a newline character immediately after the name,
+even at the end of the file.
+Other lines are ignored and may be used for comments.
+.Pp
+If
+.Pa _PERM_PATH/at.allow
+does not exist,
+.Pa _PERM_PATH/at.deny
+is checked, every username not mentioned in it is then allowed
+to use
+.Nm at .
+.Pp
+If neither exists, only the superuser is allowed use of
+.Nm at .
+.Sh IMPLEMENTATION NOTES
+Note that
+.Nm at
+is implemented through the
+.Xr launchd 8
+daemon periodically invoking
+.Xr atrun 8 ,
+which is disabled by default.
+See
+.Xr atrun 8
+for information about enabling
+.Nm atrun .
+.Sh OPTIONS
+.Bl -tag -width indent
+.It Fl b
+Is an alias for
+.Nm batch .
+.It Fl c
+Cat the jobs listed on the command line to standard output.
+.It Fl d
+Is an alias for
+.Nm atrm
+(this option is deprecated; use
+.Fl r
+instead).
+.It Fl f Ar file
+Read the job from
+.Ar file
+rather than standard input.
+.It Fl l
+With no arguments, list all jobs for the invoking user.
+If one or more
+job numbers are given, list only those jobs.
+.It Fl m
+Send mail to the user when the job has completed even if there was no
+output.
+.It Fl q Ar queue
+Use the specified queue.
+A queue designation consists of a single letter; valid queue designations
+range from
+.Ar a
+to
+.Ar z
+and
+.Ar A
+to
+.Ar Z .
+The
+.Ar _DEFAULT_AT_QUEUE
+queue (a) is the default for
+.Nm at
+and the
+.Ar _DEFAULT_BATCH_QUEUE
+queue (b) is the default for
+.Nm batch .
+Queues with higher letters run with increased niceness.
+If a job is submitted to a queue designated with an uppercase letter, it
+is treated as if it had been submitted to batch at that time.
+If
+.Nm atq
+is given a specific queue, it will only show jobs pending in that queue.
+.It Fl r
+Remove the specified jobs.
+.It Fl t
+Specify the job time using the \*[Px] time format.
+The argument should be in the form
+.Sm off
+.Op Oo Ar CC Oc Ar YY
+.Ar MM DD hh mm Op . Ar SS
+.Sm on
+where each pair of letters represents the following:
+.Pp
+.Bl -tag -width indent -compact -offset indent
+.It Ar CC
+The first two digits of the year (the century).
+.It Ar YY
+The second two digits of the year.
+.It Ar MM
+The month of the year, from 1 to 12.
+.It Ar DD
+the day of the month, from 1 to 31.
+.It Ar hh
+The hour of the day, from 0 to 23.
+.It Ar mm
+The minute of the hour, from 0 to 59.
+.It Ar SS
+The second of the minute, from 0 to 61.
+.El
+.Pp
+If the
+.Ar CC
+and
+.Ar YY
+letter pairs are not specified, the values default to the current
+year.
+If the
+.Ar SS
+letter pair is not specified, the value defaults to 0.
+.It Fl v
+For
+.Nm atq ,
+shows completed but not yet deleted jobs in the queue; otherwise
+shows the time the job will be executed.
+.El
+.Sh FILES
+.Bl -tag -width _ATJOB_DIR/_LOCKFILE -compact
+.It Pa _ATJOB_DIR
+directory containing job files
+(/usr/lib/cron/jobs/)
+.It Pa _ATJOB_DIR/_LOCKFILE
+job-creation lock file
+(/usr/lib/cron/jobs/...)
+.It Pa _ATSPOOL_DIR
+directory containing output spool files
+(/usr/lib/cron/spool/)
+.It Pa _PERM_PATH/at.allow
+allow permission control
+(/usr/lib/cron/at.allow)
+.It Pa _PERM_PATH/at.deny
+deny permission control
+(/usr/lib/cron/at.deny)
+.It Pa /var/run/utmpx
+login records
+.El
+.Sh SEE ALSO
+.Xr nice 1 ,
+.Xr sh 1 ,
+.Xr umask 2 ,
+.Xr compat 5 ,
+.Xr atrun 8 ,
+.Xr cron 8 ,
+.Xr sendmail 8
+.Sh BUGS
+If the file
+.Pa /var/run/utmpx
+is not available or corrupted,
+or if the user is not logged on at the time
+.Nm at
+is invoked, the mail is sent to the userid found
+in the environment variable
+.Ev LOGNAME .
+If that is undefined or empty, the current userid is assumed.
+.Pp
+The
+.Nm at
+and
+.Nm batch
+utilities
+as presently implemented are not suitable when users are competing for
+resources.
+If this is the case, another batch system such as
+.Em nqs
+may be more suitable.
+.Pp
+Specifying a date past 2038 may not work on some systems.
+.Sh AUTHORS
+At was mostly written by
+.An Thomas Koenig Aq ig25@rz.uni-karlsruhe.de .
+The time parsing routines are by
+.An David Parsons Aq orc@pell.chi.il.us ,
+with minor enhancements by
+.An Joe Halpin Aq joe.halpin@attbi.com .
diff --git a/system_cmds/at.tproj/at.c b/system_cmds/at.tproj/at.c
new file mode 100644
index 0000000..9b9b67c
--- /dev/null
+++ b/system_cmds/at.tproj/at.c
@@ -0,0 +1,960 @@
+/*
+ * at.c : Put file into atrun queue
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * Atrun & Atq modifications
+ * Copyright (C) 1993 David Parsons
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/usr.bin/at/at.c,v 1.34 2011/11/06 20:30:21 ed Exp $");
+
+#define _USE_BSD 1
+
+/* System Headers */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifndef __FreeBSD__
+#include <getopt.h>
+#endif
+#include <glob.h>
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
+#include <pwd.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else /* !__APPLE */
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+/* Local headers */
+
+#include "at.h"
+#include "panic.h"
+#include "parsetime.h"
+#include "pathnames.h"
+#include "perm.h"
+
+#define MAIN
+#include "privs.h"
+
+/* Macros */
+
+#ifndef ATJOB_DIR
+#define ATJOB_DIR _PATH_ATJOBS
+#endif
+
+#ifndef LFILE
+#define LFILE ATJOB_DIR ".lockfile"
+#endif
+
+#ifndef ATJOB_MX
+#define ATJOB_MX 255
+#endif
+
+#define ALARMC 10 /* Number of seconds to wait for timeout */
+
+#define SIZE 255
+#define TIMESIZE 50
+
+enum { ATQ, ATRM, AT, BATCH, CAT }; /* what program we want to run */
+
+/* File scope variables */
+
+static const char *no_export[] = {
+ "TERM", "TERMCAP", "DISPLAY", "_"
+};
+static int send_mail = 0;
+static char *atinput = NULL; /* where to get input from */
+static char atqueue = 0; /* which queue to examine for jobs (atq) */
+
+/* External variables */
+
+extern char **environ;
+int fcreated;
+char atfile[] = ATJOB_DIR "12345678901234";
+char atverify = 0; /* verify time instead of queuing job */
+char *namep;
+int posixly_correct; /* Behave as per POSIX */
+/* http://www.opengroup.org/onlinepubs/009695399/utilities/at.html */
+
+/* Function declarations */
+
+static void sigc(int signo);
+static void alarmc(int signo);
+static char *cwdname(void);
+static void writefile(time_t runtimer, char queue);
+static void list_jobs(long *, int);
+static long nextjob(void);
+static time_t ttime(const char *arg);
+static int in_job_list(long, long *, int);
+static long *get_job_list(int, char *[], int *);
+
+/* Signal catching functions */
+
+static void
+sigc(int signo __unused)
+{
+/* If the user presses ^C, remove the spool file and exit
+ */
+ if (fcreated)
+ {
+ PRIV_START
+ unlink(atfile);
+ PRIV_END
+ }
+
+ _exit(EXIT_FAILURE);
+}
+
+static void
+alarmc(int signo __unused)
+{
+ char buf[1024];
+
+ /* Time out after some seconds. */
+ strlcpy(buf, namep, sizeof(buf));
+ strlcat(buf, ": file locking timed out\n", sizeof(buf));
+ write(STDERR_FILENO, buf, strlen(buf));
+ sigc(0);
+}
+
+/* Local functions */
+
+static char *
+cwdname(void)
+{
+/* Read in the current directory; the name will be overwritten on
+ * subsequent calls.
+ */
+ static char *ptr = NULL;
+ static size_t size = SIZE;
+
+ if (ptr == NULL)
+ if ((ptr = malloc(size)) == NULL)
+ errx(EXIT_FAILURE, "virtual memory exhausted");
+
+ while (1)
+ {
+ if (ptr == NULL)
+ panic("out of memory");
+
+ if (getcwd(ptr, size-1) != NULL)
+ return ptr;
+
+ if (errno != ERANGE)
+ perr("cannot get directory");
+
+ free (ptr);
+ size += SIZE;
+ if ((ptr = malloc(size)) == NULL)
+ errx(EXIT_FAILURE, "virtual memory exhausted");
+ }
+}
+
+static long
+nextjob(void)
+{
+ long jobno;
+ FILE *fid;
+
+ if ((fid = fopen(ATJOB_DIR ".SEQ", "r+")) != NULL) {
+ if (fscanf(fid, "%5lx", &jobno) == 1) {
+ rewind(fid);
+ jobno = (1+jobno) % 0xfffff; /* 2^20 jobs enough? */
+ fprintf(fid, "%05lx\n", jobno);
+ }
+ else
+ jobno = EOF;
+ fclose(fid);
+ return jobno;
+ }
+ else if ((fid = fopen(ATJOB_DIR ".SEQ", "w")) != NULL) {
+ fprintf(fid, "%05lx\n", jobno = 1);
+ fclose(fid);
+ return 1;
+ }
+ return EOF;
+}
+
+static void
+writefile(time_t runtimer, char queue)
+{
+/* This does most of the work if at or batch are invoked for writing a job.
+ */
+ long jobno;
+ char *ap, *ppos, *mailname;
+ struct passwd *pass_entry;
+ struct stat statbuf;
+ int fdes, lockdes, fd2;
+ FILE *fp, *fpin;
+ struct sigaction act;
+ char **atenv;
+ int ch;
+ mode_t cmask;
+ struct flock lock;
+ char * oldpwd_str = NULL;
+
+#ifdef __FreeBSD__
+ (void) setlocale(LC_TIME, "");
+#endif
+
+/* Install the signal handler for SIGINT; terminate after removing the
+ * spool file if necessary
+ */
+ act.sa_handler = sigc;
+ sigemptyset(&(act.sa_mask));
+ act.sa_flags = 0;
+
+ sigaction(SIGINT, &act, NULL);
+
+ ppos = atfile + strlen(ATJOB_DIR);
+
+ /* Loop over all possible file names for running something at this
+ * particular time, see if a file is there; the first empty slot at any
+ * particular time is used. Lock the file LFILE first to make sure
+ * we're alone when doing this.
+ */
+
+ PRIV_START
+
+ if ((lockdes = open(LFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0)
+ perr("cannot open lockfile " LFILE);
+
+ lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0;
+ lock.l_len = 0;
+
+ act.sa_handler = alarmc;
+ sigemptyset(&(act.sa_mask));
+ act.sa_flags = 0;
+
+ /* Set an alarm so a timeout occurs after ALARMC seconds, in case
+ * something is seriously broken.
+ */
+ sigaction(SIGALRM, &act, NULL);
+ alarm(ALARMC);
+ fcntl(lockdes, F_SETLKW, &lock);
+ alarm(0);
+
+ if ((jobno = nextjob()) == EOF)
+ perr("cannot generate job number");
+
+ sprintf(ppos, "%c%5lx%8lx", queue,
+ jobno, (unsigned long) (runtimer/60));
+
+ for(ap=ppos; *ap != '\0'; ap ++)
+ if (*ap == ' ')
+ *ap = '0';
+
+ if (stat(atfile, &statbuf) != 0)
+ if (errno != ENOENT)
+ perr("cannot access " ATJOB_DIR);
+
+ /* Create the file. The x bit is only going to be set after it has
+ * been completely written out, to make sure it is not executed in the
+ * meantime. To make sure they do not get deleted, turn off their r
+ * bit. Yes, this is a kluge.
+ */
+ cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR);
+ if ((fdes = creat(atfile, O_WRONLY)) == -1)
+ perr("cannot create atjob file");
+
+ if ((fd2 = dup(fdes)) <0)
+ perr("error in dup() of job file");
+
+ if(fchown(fd2, real_uid, real_gid) != 0)
+ perr("cannot give away file");
+
+ PRIV_END
+
+ /* We no longer need suid root; now we just need to be able to write
+ * to the directory, if necessary.
+ */
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ /* We've successfully created the file; let's set the flag so it
+ * gets removed in case of an interrupt or error.
+ */
+ fcreated = 1;
+
+ /* Now we can release the lock, so other people can access it
+ */
+ lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = 0;
+ lock.l_len = 0;
+ fcntl(lockdes, F_SETLKW, &lock);
+ close(lockdes);
+
+ if((fp = fdopen(fdes, "w")) == NULL)
+ panic("cannot reopen atjob file");
+
+ /* Get the userid to mail to, first by trying getlogin(),
+ * then from LOGNAME, finally from getpwuid().
+ */
+ mailname = getlogin();
+ if (mailname == NULL)
+ mailname = getenv("LOGNAME");
+
+ if ((mailname == NULL) || (mailname[0] == '\0')
+ || (strlen(mailname) >= MAXLOGNAME) || (getpwnam(mailname)==NULL))
+ {
+ pass_entry = getpwuid(real_uid);
+ if (pass_entry != NULL)
+ mailname = pass_entry->pw_name;
+ }
+
+ if (atinput != (char *) NULL)
+ {
+ fpin = freopen(atinput, "r", stdin);
+ if (fpin == NULL)
+ perr("cannot open input file");
+ }
+ fprintf(fp, "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %.*s %d\n",
+ (long) real_uid, (long) real_gid, MAXLOGNAME - 1, mailname,
+ send_mail);
+
+ /* Write out the umask at the time of invocation
+ */
+ fprintf(fp, "umask %lo\n", (unsigned long) cmask);
+
+ /* Write out the environment. Anything that may look like a
+ * special character to the shell is quoted, except for \n, which is
+ * done with a pair of "'s. Don't export the no_export list (such
+ * as TERM or DISPLAY) because we don't want these.
+ */
+ for (atenv= environ; *atenv != NULL; atenv++)
+ {
+ int export = 1;
+ char *eqp;
+
+ eqp = strchr(*atenv, '=');
+ if (ap == NULL)
+ eqp = *atenv;
+ else
+ {
+ size_t i;
+
+ if(strncmp(*atenv, "OLDPWD", (size_t) (eqp-*atenv)) == 0) {
+ oldpwd_str = *atenv;
+ }
+ if (!posixly_correct) {
+ /* Test 891 expects TERM, etc. to show up in "at" env
+ so exclude them only when not posixly_correct */
+ for (i=0; i<sizeof(no_export)/sizeof(no_export[0]); i++)
+ {
+ export = export
+ && (strncmp(*atenv, no_export[i],
+ (size_t) (eqp-*atenv)) != 0);
+ }
+ }
+ eqp++;
+ }
+
+ if (export)
+ {
+ fwrite(*atenv, sizeof(char), eqp-*atenv, fp);
+ for(ap = eqp;*ap != '\0'; ap++)
+ {
+ if (*ap == '\n')
+ fprintf(fp, "\"\n\"");
+ else
+ {
+ if (!isalnum(*ap)) {
+ switch (*ap) {
+ case '%': case '/': case '{': case '[':
+ case ']': case '=': case '}': case '@':
+ case '+': case '#': case ',': case '.':
+ case ':': case '-': case '_':
+ break;
+ default:
+ fputc('\\', fp);
+ break;
+ }
+ }
+ fputc(*ap, fp);
+ }
+ }
+ fputs("; export ", fp);
+ fwrite(*atenv, sizeof(char), eqp-*atenv -1, fp);
+ fputc('\n', fp);
+
+ }
+ }
+ /* Cd to the directory at the time and write out all the
+ * commands the user supplies from stdin.
+ */
+ fprintf(fp, "cd ");
+ for (ap = cwdname(); *ap != '\0'; ap++)
+ {
+ if (*ap == '\n')
+ fprintf(fp, "\"\n\"");
+ else
+ {
+ if (*ap != '/' && !isalnum(*ap))
+ fputc('\\', fp);
+
+ fputc(*ap, fp);
+ }
+ }
+ /* Test cd's exit status: die if the original directory has been
+ * removed, become unreadable or whatever
+ */
+ fprintf(fp, " || {\n\t echo 'Execution directory "
+ "inaccessible' >&2\n\t exit 1\n}\n");
+
+ /* Put OLDPWD back, since the cd has set it */
+ /* Although this is added to fix conformance test at.ex 891, it seems like */
+ /* the right thing to do always, so the code is not posix_pedantic only */
+ if (oldpwd_str) {
+ fprintf(fp, "%s; export OLDPWD\n", oldpwd_str);
+ } else {
+ fprintf(fp, "unset OLDPWD\n");
+ }
+
+ while((ch = getchar()) != EOF)
+ fputc(ch, fp);
+
+ fprintf(fp, "\n");
+ if (ferror(fp))
+ panic("output error");
+
+ if (ferror(stdin))
+ panic("input error");
+
+ fclose(fp);
+
+ /* Set the x bit so that we're ready to start executing
+ */
+
+ if (fchmod(fd2, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
+ perr("cannot give away file");
+
+ close(fd2);
+ if (posixly_correct) {
+ struct tm runtime;
+ char timestr[TIMESIZE];
+ runtime = *localtime(&runtimer);
+ strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime);
+ fprintf(stderr, "job %ld at %s\n", jobno, timestr);
+ } else
+ fprintf(stderr, "Job %ld will be executed using /bin/sh\n", jobno);
+}
+
+static int
+in_job_list(long job, long *joblist, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (job == joblist[i])
+ return 1;
+
+ return 0;
+}
+
+static void
+list_one_job(char *name, long *joblist, int len, int *first)
+{
+ struct stat buf;
+ struct tm runtime;
+ unsigned long ctm;
+ char queue;
+ long jobno;
+ time_t runtimer;
+ char timestr[TIMESIZE];
+
+ if (stat(name, &buf) != 0)
+ perr("cannot stat in " ATJOB_DIR);
+
+ /* See it's a regular file and has its x bit turned on and
+ * is the user's
+ */
+ if (!S_ISREG(buf.st_mode)
+ || ((buf.st_uid != real_uid) && ! (real_uid == 0))
+ || !(S_IXUSR & buf.st_mode || atverify))
+ return;
+
+ if(sscanf(name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ return;
+
+ /* If jobs are given, only list those jobs */
+ if (joblist && !in_job_list(jobno, joblist, len))
+ return;
+
+ if (atqueue && (queue != atqueue))
+ return;
+
+ runtimer = 60*(time_t) ctm;
+ runtime = *localtime(&runtimer);
+ strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime);
+ if (*first) {
+ if (!posixly_correct)
+ printf("Date\t\t\t\tOwner\t\tQueue\tJob#\n");
+ *first=0;
+ }
+ if (posixly_correct)
+ printf("%ld\t%s\n", jobno, timestr);
+ else {
+ struct passwd *pw = getpwuid(buf.st_uid);
+
+ printf("%s\t%s\t%c%s\t%s\n",
+ timestr,
+ pw ? pw->pw_name : "???",
+ queue,
+ (S_IXUSR & buf.st_mode) ? "":"(done)",
+ name);
+ }
+}
+
+static void
+list_jobs(long *joblist, int len)
+{
+ /* List all a user's jobs in the queue, by looping through ATJOB_DIR,
+ * or everybody's if we are root
+ */
+ DIR *spool;
+ struct dirent *dirent;
+ int first=1;
+
+#ifdef __FreeBSD__
+ (void) setlocale(LC_TIME, "");
+#endif
+
+ PRIV_START
+
+ if (chdir(ATJOB_DIR) != 0)
+ perr("cannot change to " ATJOB_DIR);
+
+ if (joblist) { /* Force order to match POSIX */
+ char jobglob[32];
+ glob_t g;
+ int i;
+
+ sprintf(jobglob, "?%05lx*", joblist[0]);
+ g.gl_offs = 0;
+ glob(jobglob, GLOB_DOOFFS, NULL, &g);
+ for (i = 1; i < len; i++) {
+ sprintf(jobglob, "?%05lx*", joblist[i]);
+ glob(jobglob, GLOB_DOOFFS | GLOB_APPEND, NULL, &g);
+ }
+ for (i = 0; i < g.gl_pathc; i++) {
+ list_one_job(g.gl_pathv[i], joblist, len, &first);
+ }
+ globfree(&g);
+ } else {
+ if ((spool = opendir(".")) == NULL)
+ perr("cannot open " ATJOB_DIR);
+
+ /* Loop over every file in the directory
+ */
+ while((dirent = readdir(spool)) != NULL) {
+ list_one_job(dirent->d_name, joblist, len, &first);
+ }
+ closedir(spool);
+ }
+ PRIV_END
+}
+
+static void
+process_jobs(int argc, char **argv, int what)
+{
+ /* Delete every argument (job - ID) given
+ */
+ int i;
+ struct stat buf;
+ DIR *spool;
+ struct dirent *dirent;
+ unsigned long ctm;
+ char queue;
+ long jobno;
+
+ PRIV_START
+
+ if (chdir(ATJOB_DIR) != 0)
+ perr("cannot change to " ATJOB_DIR);
+
+ if ((spool = opendir(".")) == NULL)
+ perr("cannot open " ATJOB_DIR);
+
+ PRIV_END
+
+ /* Loop over every file in the directory
+ */
+ while((dirent = readdir(spool)) != NULL) {
+
+ PRIV_START
+ if (stat(dirent->d_name, &buf) != 0)
+ perr("cannot stat in " ATJOB_DIR);
+ PRIV_END
+
+ if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3)
+ continue;
+
+ for (i=optind; i < argc; i++) {
+ if (atoi(argv[i]) == jobno || strcmp(argv[i], dirent->d_name)==0) {
+ if ((buf.st_uid != real_uid) && !(real_uid == 0))
+ errx(EXIT_FAILURE, "%s: not owner", argv[i]);
+ switch (what) {
+ case ATRM:
+
+ PRIV_START
+
+ if (unlink(dirent->d_name) != 0)
+ perr(dirent->d_name);
+
+ PRIV_END
+
+ break;
+
+ case CAT:
+ {
+ FILE *fp;
+ int ch;
+
+ PRIV_START
+
+ fp = fopen(dirent->d_name,"r");
+
+ PRIV_END
+
+ if (!fp) {
+ perr("cannot open file");
+ }
+ while((ch = getc(fp)) != EOF) {
+ putchar(ch);
+ }
+ fclose(fp);
+ }
+ break;
+
+ default:
+ errx(EXIT_FAILURE, "internal error, process_jobs = %d",
+ what);
+ }
+ }
+ }
+ }
+ closedir(spool);
+} /* process_jobs */
+
+#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
+
+static time_t
+ttime(const char *arg)
+{
+ /*
+ * This is pretty much a copy of stime_arg1() from touch.c. I changed
+ * the return value and the argument list because it's more convenient
+ * (IMO) to do everything in one place. - Joe Halpin
+ */
+ struct timeval tv[2];
+ time_t now;
+ struct tm *t;
+ int yearset;
+ char *p;
+
+ if (gettimeofday(&tv[0], NULL))
+ panic("Cannot get current time");
+
+ /* Start with the current time. */
+ now = tv[0].tv_sec;
+ if ((t = localtime(&now)) == NULL)
+ panic("localtime");
+ /* [[CC]YY]MMDDhhmm[.SS] */
+ if ((p = strchr(arg, '.')) == NULL)
+ t->tm_sec = 0; /* Seconds defaults to 0. */
+ else {
+ if (strlen(p + 1) != 2)
+ goto terr;
+ *p++ = '\0';
+ t->tm_sec = ATOI2(p);
+ }
+
+ yearset = 0;
+ switch(strlen(arg)) {
+ case 12: /* CCYYMMDDhhmm */
+ t->tm_year = ATOI2(arg);
+ t->tm_year *= 100;
+ yearset = 1;
+ /* FALLTHROUGH */
+ case 10: /* YYMMDDhhmm */
+ if (yearset) {
+ yearset = ATOI2(arg);
+ t->tm_year += yearset;
+ } else {
+ yearset = ATOI2(arg);
+ t->tm_year = yearset + 2000;
+ }
+ t->tm_year -= 1900; /* Convert to UNIX time. */
+ /* FALLTHROUGH */
+ case 8: /* MMDDhhmm */
+ t->tm_mon = ATOI2(arg);
+ --t->tm_mon; /* Convert from 01-12 to 00-11 */
+ t->tm_mday = ATOI2(arg);
+ t->tm_hour = ATOI2(arg);
+ t->tm_min = ATOI2(arg);
+ break;
+ default:
+ goto terr;
+ }
+
+ t->tm_isdst = -1; /* Figure out DST. */
+ tv[0].tv_sec = tv[1].tv_sec = mktime(t);
+ if (tv[0].tv_sec != -1)
+ return tv[0].tv_sec;
+ else
+terr:
+ panic(
+ "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]");
+}
+
+static long *
+get_job_list(int argc, char *argv[], int *joblen)
+{
+ int i, len;
+ long *joblist;
+ char *ep;
+
+ joblist = NULL;
+ len = argc;
+ if (len > 0) {
+ if ((joblist = malloc(len * sizeof(*joblist))) == NULL)
+ panic("out of memory");
+
+ for (i = 0; i < argc; i++) {
+ errno = 0;
+ if ((joblist[i] = strtol(argv[i], &ep, 10)) < 0 ||
+ ep == argv[i] || *ep != '\0' || errno)
+ panic("invalid job number");
+ }
+ }
+
+ *joblen = len;
+ return joblist;
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ char queue = DEFAULT_AT_QUEUE;
+ char queue_set = 0;
+ char *pgm;
+
+ int program = AT; /* our default program */
+ const char *options = "q:f:t:rmvldbc"; /* default options for at */
+ time_t timer;
+ long *joblist;
+ int joblen;
+
+ posixly_correct = COMPAT_MODE("bin/at", "Unix2003");
+ joblist = NULL;
+ joblen = 0;
+ timer = -1;
+ RELINQUISH_PRIVS
+
+ if (argv[0] == NULL)
+ usage();
+ /* Eat any leading paths
+ */
+ if ((pgm = strrchr(argv[0], '/')) == NULL)
+ pgm = argv[0];
+ else
+ pgm++;
+
+ namep = pgm;
+
+ /* find out what this program is supposed to do
+ */
+ if (strcmp(pgm, "atq") == 0) {
+ program = ATQ;
+ options = "q:v";
+ }
+ else if (strcmp(pgm, "atrm") == 0) {
+ program = ATRM;
+ options = "";
+ }
+ else if (strcmp(pgm, "batch") == 0) {
+ program = BATCH;
+ options = "f:q:mv";
+ }
+
+ /* process whatever options we can process
+ */
+ opterr=1;
+ while ((c=getopt(argc, argv, options)) != -1)
+ switch (c) {
+ case 'v': /* verify time settings */
+ atverify = 1;
+ break;
+
+ case 'm': /* send mail when job is complete */
+ send_mail = 1;
+ break;
+
+ case 'f':
+ atinput = optarg;
+ break;
+
+ case 'q': /* specify queue */
+ if (strlen(optarg) > 1)
+ usage();
+
+ atqueue = queue = *optarg;
+ if (!(islower(queue)||isupper(queue)))
+ usage();
+
+ queue_set = 1;
+ break;
+
+ case 'd':
+ warnx("-d is deprecated; use -r instead");
+ /* fall through to 'r' */
+
+ case 'r':
+ if (program != AT)
+ usage();
+
+ program = ATRM;
+ options = "";
+ break;
+
+ case 't':
+ if (program != AT)
+ usage();
+ timer = ttime(optarg);
+ break;
+
+ case 'l':
+ if (program != AT)
+ usage();
+
+ program = ATQ;
+ options = "q:";
+ break;
+
+ case 'b':
+ if (program != AT)
+ usage();
+
+ program = BATCH;
+ options = "f:q:mv";
+ break;
+
+ case 'c':
+ program = CAT;
+ options = "";
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ /* end of options eating
+ */
+
+ /* select our program
+ */
+ if(!check_permission())
+ errx(EXIT_FAILURE, "you do not have permission to use this program");
+ switch (program) {
+ case ATQ:
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ if (queue_set == 0)
+ joblist = get_job_list(argc - optind, argv + optind, &joblen);
+ list_jobs(joblist, joblen);
+ break;
+
+ case ATRM:
+
+ REDUCE_PRIV(DAEMON_UID, DAEMON_GID)
+
+ process_jobs(argc, argv, ATRM);
+ break;
+
+ case CAT:
+
+ process_jobs(argc, argv, CAT);
+ break;
+
+ case AT:
+ /*
+ * If timer is > -1, then the user gave the time with -t. In that
+ * case, it's already been set. If not, set it now.
+ */
+ if (timer == -1)
+ timer = parsetime(argc, argv);
+
+ if (atverify)
+ {
+ struct tm *tm = localtime(&timer);
+ fprintf(stderr, "%s\n", asctime(tm));
+ }
+ writefile(timer, queue);
+ break;
+
+ case BATCH:
+ if (queue_set)
+ queue = toupper(queue);
+ else
+ queue = DEFAULT_BATCH_QUEUE;
+
+ if (argc > optind)
+ timer = parsetime(argc, argv);
+ else
+ timer = time(NULL);
+
+ if (atverify)
+ {
+ struct tm *tm = localtime(&timer);
+ fprintf(stderr, "%s\n", asctime(tm));
+ }
+
+ writefile(timer, queue);
+ break;
+
+ default:
+ panic("internal error");
+ break;
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/system_cmds/at.tproj/at.h b/system_cmds/at.tproj/at.h
new file mode 100644
index 0000000..a3dc18a
--- /dev/null
+++ b/system_cmds/at.tproj/at.h
@@ -0,0 +1,31 @@
+/*
+ * at.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/at/at.h,v 1.5 2001/07/24 14:15:51 obrien Exp $
+ */
+
+extern int fcreated;
+extern char *namep;
+extern char atfile[];
+extern char atverify;
diff --git a/system_cmds/at.tproj/panic.c b/system_cmds/at.tproj/panic.c
new file mode 100644
index 0000000..b1d99d8
--- /dev/null
+++ b/system_cmds/at.tproj/panic.c
@@ -0,0 +1,92 @@
+/*
+ * panic.c - terminate fast in case of error
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/at/panic.c,v 1.17 2002/05/16 00:47:14 tjr Exp $");
+
+/* System Headers */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Local headers */
+
+#include "panic.h"
+#include "privs.h"
+#include "at.h"
+
+/* External variables */
+
+/* Global functions */
+
+void
+panic(const char *a)
+{
+/* Something fatal has happened, print error message and exit.
+ */
+ if (fcreated) {
+ PRIV_START
+ unlink(atfile);
+ PRIV_END
+ }
+
+ errx(EXIT_FAILURE, "%s", a);
+}
+
+void
+perr(const char *a)
+{
+/* Some operating system error; print error message and exit.
+ */
+ int serrno = errno;
+
+ if (fcreated) {
+ PRIV_START
+ unlink(atfile);
+ PRIV_END
+ }
+
+ errno = serrno;
+ err(EXIT_FAILURE, "%s", a);
+}
+
+void
+usage(void)
+{
+ /* Print usage and exit. */
+ fprintf(stderr, "usage: at [-q x] [-f file] [-m] time\n"
+ " at -c job [job ...]\n"
+ " at [-f file] -t [[CC]YY]MMDDhhmm[.SS]\n"
+ " at -r job [job ...]\n"
+ " at -l -q queuename\n"
+ " at -l [job ...]\n"
+ " atq [-q x] [-v]\n"
+ " atrm job [job ...]\n"
+ " batch [-f file] [-m]\n");
+ exit(EXIT_FAILURE);
+}
diff --git a/system_cmds/at.tproj/panic.h b/system_cmds/at.tproj/panic.h
new file mode 100644
index 0000000..d50405e
--- /dev/null
+++ b/system_cmds/at.tproj/panic.h
@@ -0,0 +1,32 @@
+/*
+ * panic.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/at/panic.h,v 1.6 2002/01/13 20:21:08 mike Exp $
+ */
+
+#include <sys/cdefs.h>
+
+void panic(const char *a) __dead2;
+void perr(const char *a) __dead2;
+void usage(void) __dead2;
diff --git a/system_cmds/at.tproj/parsetime.c b/system_cmds/at.tproj/parsetime.c
new file mode 100644
index 0000000..3aeea6c
--- /dev/null
+++ b/system_cmds/at.tproj/parsetime.c
@@ -0,0 +1,736 @@
+/*
+ * parsetime.c - parse time for at(1)
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * modifications for English-language times
+ * Copyright (C) 1993 David Parsons
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ *
+ * at [NOW] PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS
+ * DOT ::= ':'|'.'
+ * /NUMBER [DOT NUMBER] [AM|PM]\ /[MONTH NUMBER [NUMBER]] \
+ * |NOON | |[TOMORROW] |
+ * |MIDNIGHT | |[DAY OF WEEK] |
+ * \TEATIME / |NUMBER [SLASH NUMBER [SLASH NUMBER]]|
+ * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/usr.bin/at/parsetime.c,v 1.28 2011/11/06 17:32:29 ed Exp $");
+
+/* System Headers */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#ifndef __FreeBSD__
+#include <getopt.h>
+#endif
+
+/* Local headers */
+
+#include "at.h"
+#include "panic.h"
+#include "parsetime.h"
+
+
+/* Structures and unions */
+
+enum { /* symbols */
+ MIDNIGHT, NOON, TEATIME,
+ PM, AM, TOMORROW, TODAY, NOW,
+ MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS,
+ NUMBER, PLUS, DOT, COMMA, SLASH, ID, JUNK,
+ JAN, FEB, MAR, APR, MAY, JUN,
+ JUL, AUG, SEP, OCT, NOV, DEC,
+ SUN, MON, TUE, WED, THU, FRI, SAT,
+ UTC, NEXT
+ };
+
+/* parse translation table - table driven parsers can be your FRIEND!
+ */
+static const struct {
+ const char *name; /* token name */
+ int value; /* token id */
+ int plural; /* is this plural? */
+} Specials[] = {
+ { "midnight", MIDNIGHT,0 }, /* 00:00:00 of today or tomorrow */
+ { "noon", NOON,0 }, /* 12:00:00 of today or tomorrow */
+ { "teatime", TEATIME,0 }, /* 16:00:00 of today or tomorrow */
+ { "am", AM,0 }, /* morning times for 0-12 clock */
+ { "pm", PM,0 }, /* evening times for 0-12 clock */
+ { "tomorrow", TOMORROW,0 }, /* execute 24 hours from time */
+ { "today", TODAY, 0 }, /* execute today - don't advance time */
+ { "now", NOW,0 }, /* opt prefix for PLUS */
+
+ { "minute", MINUTES,0 }, /* minutes multiplier */
+ { "minutes", MINUTES,1 }, /* (pluralized) */
+ { "hour", HOURS,0 }, /* hours ... */
+ { "hours", HOURS,1 }, /* (pluralized) */
+ { "day", DAYS,0 }, /* days ... */
+ { "days", DAYS,1 }, /* (pluralized) */
+ { "week", WEEKS,0 }, /* week ... */
+ { "weeks", WEEKS,1 }, /* (pluralized) */
+ { "month", MONTHS,0 }, /* month ... */
+ { "months", MONTHS,1 }, /* (pluralized) */
+ { "year", YEARS,0 }, /* year ... */
+ { "years", YEARS,1 }, /* (pluralized) */
+ { "jan", JAN,0 },
+ { "feb", FEB,0 },
+ { "mar", MAR,0 },
+ { "apr", APR,0 },
+ { "may", MAY,0 },
+ { "jun", JUN,0 },
+ { "jul", JUL,0 },
+ { "aug", AUG,0 },
+ { "sep", SEP,0 },
+ { "oct", OCT,0 },
+ { "nov", NOV,0 },
+ { "dec", DEC,0 },
+ { "january", JAN,0 },
+ { "february", FEB,0 },
+ { "march", MAR,0 },
+ { "april", APR,0 },
+ { "may", MAY,0 },
+ { "june", JUN,0 },
+ { "july", JUL,0 },
+ { "august", AUG,0 },
+ { "september", SEP,0 },
+ { "october", OCT,0 },
+ { "november", NOV,0 },
+ { "december", DEC,0 },
+ { "sunday", SUN, 0 },
+ { "sun", SUN, 0 },
+ { "monday", MON, 0 },
+ { "mon", MON, 0 },
+ { "tuesday", TUE, 0 },
+ { "tue", TUE, 0 },
+ { "wednesday", WED, 0 },
+ { "wed", WED, 0 },
+ { "thursday", THU, 0 },
+ { "thu", THU, 0 },
+ { "friday", FRI, 0 },
+ { "fri", FRI, 0 },
+ { "saturday", SAT, 0 },
+ { "sat", SAT, 0 },
+ { "utc", UTC, 0 },
+ { "next", NEXT, 0 },
+} ;
+
+/* File scope variables */
+
+static char **scp; /* scanner - pointer at arglist */
+static char scc; /* scanner - count of remaining arguments */
+static char *sct; /* scanner - next char pointer in current argument */
+static int need; /* scanner - need to advance to next argument */
+
+static char *sc_token; /* scanner - token buffer */
+static size_t sc_len; /* scanner - length of token buffer */
+static int sc_tokid; /* scanner - token id */
+static int sc_tokplur; /* scanner - is token plural? */
+
+/* Local functions */
+
+/*
+ * parse a token, checking if it's something special to us
+ */
+static int
+parse_token(char *arg)
+{
+ size_t i;
+
+ for (i=0; i<(sizeof Specials/sizeof Specials[0]); i++)
+ if (strcasecmp(Specials[i].name, arg) == 0) {
+ sc_tokplur = Specials[i].plural;
+ return sc_tokid = Specials[i].value;
+ }
+
+ /* not special - must be some random id */
+ return sc_tokid = ID;
+} /* parse_token */
+
+
+/*
+ * init_scanner() sets up the scanner to eat arguments
+ */
+static void
+init_scanner(int argc, char **argv)
+{
+ scp = argv;
+ scc = argc;
+ need = 1;
+ sc_len = 1;
+ while (argc-- > 0)
+ sc_len += strlen(*argv++);
+
+ if ((sc_token = malloc(sc_len)) == NULL)
+ errx(EXIT_FAILURE, "virtual memory exhausted");
+} /* init_scanner */
+
+/*
+ * token() fetches a token from the input stream
+ */
+static int
+token(void)
+{
+ int idx;
+
+ while (1) {
+ memset(sc_token, 0, sc_len);
+ sc_tokid = EOF;
+ sc_tokplur = 0;
+ idx = 0;
+
+ /* if we need to read another argument, walk along the argument list;
+ * when we fall off the arglist, we'll just return EOF forever
+ */
+ if (need) {
+ if (scc < 1)
+ return sc_tokid;
+ sct = *scp;
+ scp++;
+ scc--;
+ need = 0;
+ }
+ /* eat whitespace now - if we walk off the end of the argument,
+ * we'll continue, which puts us up at the top of the while loop
+ * to fetch the next argument in
+ */
+ while (isspace(*sct))
+ ++sct;
+ if (!*sct) {
+ need = 1;
+ continue;
+ }
+
+ /* preserve the first character of the new token
+ */
+ sc_token[0] = *sct++;
+
+ /* then see what it is
+ */
+ if (isdigit(sc_token[0])) {
+ while (isdigit(*sct))
+ sc_token[++idx] = *sct++;
+ sc_token[++idx] = 0;
+ return sc_tokid = NUMBER;
+ }
+ else if (isalpha(sc_token[0])) {
+ while (isalpha(*sct))
+ sc_token[++idx] = *sct++;
+ sc_token[++idx] = 0;
+ return parse_token(sc_token);
+ }
+ else if (sc_token[0] == ':' || sc_token[0] == '.')
+ return sc_tokid = DOT;
+ else if (sc_token[0] == '+')
+ return sc_tokid = PLUS;
+ else if (sc_token[0] == '/')
+ return sc_tokid = SLASH;
+ else if (sc_token[0] == ',')
+ return sc_tokid = COMMA;
+ else
+ return sc_tokid = JUNK;
+ } /* while (1) */
+} /* token */
+
+
+/*
+ * plonk() gives an appropriate error message if a token is incorrect
+ */
+static void
+plonk(int tok)
+{
+ panic((tok == EOF) ? "incomplete time"
+ : "garbled time");
+} /* plonk */
+
+
+/*
+ * expect() gets a token and dies most horribly if it's not the token we want
+ */
+static void
+expect(int desired)
+{
+ if (token() != desired)
+ plonk(sc_tokid); /* and we die here... */
+} /* expect */
+
+
+/*
+ * plus() parses a now + time
+ *
+ * at [NOW] PLUS NUMBER [MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS]
+ *
+ */
+
+static void
+plus(struct tm *tm)
+{
+ int delay;
+ int expectplur;
+
+ expect(NUMBER);
+
+ delay = atoi(sc_token);
+ expectplur = (delay != 1) ? 1 : 0;
+
+ switch (token()) {
+ case YEARS:
+ tm->tm_year += delay;
+ break;
+ case MONTHS:
+ tm->tm_mon += delay;
+ break;
+ case WEEKS:
+ delay *= 7;
+ case DAYS:
+ tm->tm_mday += delay;
+ break;
+ case HOURS:
+ tm->tm_hour += delay;
+ break;
+ case MINUTES:
+ tm->tm_min += delay;
+ break;
+ default:
+ plonk(sc_tokid);
+ break;
+ }
+
+ if (expectplur != sc_tokplur)
+ warnx("pluralization is wrong");
+
+ tm->tm_isdst = -1;
+ if (mktime(tm) < 0)
+ plonk(sc_tokid);
+
+} /* plus */
+
+/*
+ * at [NOW] NEXT [MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS]
+ */
+static void
+next(struct tm *tm)
+{
+ switch (token()) {
+ case YEARS:
+ tm->tm_year++;
+ break;
+
+ case MONTHS:
+ tm->tm_mon++;
+ break;
+
+ case WEEKS:
+ tm->tm_mday += 7;
+ break;
+
+ case DAYS:
+ tm->tm_mday++;
+ break;
+
+ case HOURS:
+ tm->tm_hour++;
+ break;
+
+ case MINUTES:
+ tm->tm_min++;
+ break;
+
+ default:
+ plonk(sc_tokid);
+ break;
+ }
+
+ if (sc_tokplur) {
+ warnx("pluralization is wrong");
+ }
+ tm->tm_isdst = -1;
+ if (mktime(tm) < 0) {
+ plonk(sc_tokid);
+ }
+} /* next */
+
+/*
+ * tod() computes the time of day
+ * [NUMBER [DOT NUMBER] [AM|PM]] [UTC]
+ */
+static void
+tod(struct tm *tm)
+{
+ int hour, minute = 0;
+ size_t tlen;
+
+ hour = atoi(sc_token);
+ tlen = strlen(sc_token);
+
+ /* first pick out the time of day - if it's 4 digits, we assume
+ * a HHMM time, otherwise it's HH DOT MM time
+ */
+ if (token() == DOT) {
+ expect(NUMBER);
+ minute = atoi(sc_token);
+ if (minute > 59)
+ panic("garbled time");
+ token();
+ }
+ else if (tlen == 4) {
+ minute = hour%100;
+ if (minute > 59)
+ panic("garbled time");
+ hour = hour/100;
+ }
+
+ /* check if an AM or PM specifier was given
+ */
+ switch (sc_tokid) {
+ case AM:
+ case PM:
+ if (hour > 12)
+ panic("garbled time");
+
+ if (sc_tokid == PM) {
+ if (hour != 12) /* 12:xx PM is 12:xx, not 24:xx */
+ hour += 12;
+ } else {
+ if (hour == 12) /* 12:xx AM is 00:xx, not 12:xx */
+ hour = 0;
+ }
+ if (UTC != token())
+ break; /* else fallthrough */
+
+ case UTC:
+ hour += tm->tm_gmtoff/(60*60);
+ while (hour < 0)
+ hour += 24;
+ minute += (tm->tm_gmtoff/60);
+ while (minute < 0)
+ minute += 60;
+ tm->tm_gmtoff = 0;
+ token();
+ break;
+ default:
+ if (hour > 23)
+ panic("garbled time");
+ break;
+ }
+
+ /* if we specify an absolute time, we don't want to bump the day even
+ * if we've gone past that time - but if we're specifying a time plus
+ * a relative offset, it's okay to bump things
+ * If minutes are the same assume tomorrow was meant
+ */
+ if ((sc_tokid == EOF || sc_tokid == PLUS) &&
+ ((tm->tm_hour > hour) || ((tm->tm_hour == hour) && (tm->tm_min >= minute)))) {
+ tm->tm_mday++;
+ tm->tm_wday++;
+ }
+
+ tm->tm_hour = hour;
+ tm->tm_min = minute;
+ if (tm->tm_hour == 24) {
+ tm->tm_hour = 0;
+ tm->tm_mday++;
+ }
+} /* tod */
+
+
+/*
+ * assign_date() assigns a date, wrapping to next year if needed
+ */
+static void
+assign_date(struct tm *tm, int mday, int mon, int year)
+{
+ /*
+ * Convert year into tm_year format (year - 1900).
+ * We may be given the year in 2 digit, 4 digit, or tm_year format.
+ */
+ if (year != -1) {
+ if (year >= TM_YEAR_BASE)
+ year -= TM_YEAR_BASE; /* convert from 4 digit year */
+ else if (year < 100) {
+ /* convert from 2 digit year */
+ struct tm *lt;
+ time_t now;
+
+ time(&now);
+ lt = localtime(&now);
+
+ /* Convert to tm_year assuming current century */
+ year += (lt->tm_year / 100) * 100;
+
+ if (year == lt->tm_year - 1) year++;
+ else if (year < lt->tm_year)
+ year += 100; /* must be in next century */
+ }
+ }
+
+ if (year < 0 &&
+ (tm->tm_mon > mon ||(tm->tm_mon == mon && tm->tm_mday > mday)))
+ year = tm->tm_year + 1;
+
+ tm->tm_mday = mday;
+ tm->tm_mon = mon;
+
+ if (year >= 0)
+ tm->tm_year = year;
+} /* assign_date */
+
+
+/*
+ * month() picks apart a month specification
+ *
+ * /[<month> NUMBER [NUMBER]] \
+ * |[TOMORROW] |
+ * |[DAY OF WEEK] |
+ * |NUMBER [SLASH NUMBER [SLASH NUMBER]]|
+ * |NEXT MINUTES|HOURS|DAYS|WEEKS|MONTHS|YEARS|
+ * \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/
+ */
+static void
+month(struct tm *tm)
+{
+ int year= (-1);
+ int mday = 0, wday, mon;
+ int tlen;
+
+ switch (sc_tokid) {
+ case PLUS:
+ plus(tm);
+ break;
+
+ case NEXT:
+ next(tm);
+ break;
+
+ case TOMORROW:
+ /* do something tomorrow */
+ tm->tm_mday ++;
+ tm->tm_wday ++;
+ case TODAY: /* force ourselves to stay in today - no further processing */
+ token();
+ break;
+
+ case JAN: case FEB: case MAR: case APR: case MAY: case JUN:
+ case JUL: case AUG: case SEP: case OCT: case NOV: case DEC:
+ /* do month mday [,year]
+ */
+ mon = (sc_tokid-JAN);
+ expect(NUMBER);
+ mday = atoi(sc_token);
+ if (token() == COMMA) {
+ if (token() == NUMBER) {
+ year = atoi(sc_token);
+ token();
+ }
+ }
+ assign_date(tm, mday, mon, year);
+ if (sc_tokid == PLUS)
+ plus(tm);
+ break;
+
+ case SUN: case MON: case TUE:
+ case WED: case THU: case FRI:
+ case SAT:
+ /* do a particular day of the week
+ */
+ wday = (sc_tokid-SUN);
+
+ mday = tm->tm_mday;
+
+ /* if this day is < today, then roll to next week
+ */
+ if (wday < tm->tm_wday)
+ mday += 7 - (tm->tm_wday - wday);
+ else
+ mday += (wday - tm->tm_wday);
+
+ tm->tm_wday = wday;
+
+ assign_date(tm, mday, tm->tm_mon, tm->tm_year);
+ break;
+
+ case NUMBER:
+ /* get numeric MMDDYY, mm/dd/yy, or dd.mm.yy
+ */
+ tlen = (int)strlen(sc_token);
+ mon = atoi(sc_token);
+ token();
+
+ if (sc_tokid == SLASH || sc_tokid == DOT) {
+ int sep;
+
+ sep = sc_tokid;
+ expect(NUMBER);
+ mday = atoi(sc_token);
+ if (token() == sep) {
+ expect(NUMBER);
+ year = atoi(sc_token);
+ token();
+ }
+
+ /* flip months and days for European timing
+ */
+ if (sep == DOT) {
+ int x = mday;
+ mday = mon;
+ mon = x;
+ }
+ }
+ else if (tlen == 6 || tlen == 8) {
+ if (tlen == 8) {
+ year = (mon % 10000) - TM_YEAR_BASE;
+ mon /= 10000;
+ }
+ else {
+ year = mon % 100;
+ mon /= 100;
+ }
+ mday = mon % 100;
+ mon /= 100;
+ }
+ else
+ panic("garbled time");
+
+ mon--;
+ if (mon < 0 || mon > 11 || mday < 1 || mday > 31)
+ panic("garbled time");
+
+ assign_date(tm, mday, mon, year);
+ break;
+
+ case EOF:
+ break;
+
+ default:
+ plonk(sc_tokid);
+ break;
+ } /* case */
+} /* month */
+
+
+/* Global functions */
+
+time_t
+parsetime(int argc, char **argv)
+{
+ /* Do the argument parsing, die if necessary, and return the time the job
+ * should be run.
+ */
+ time_t nowtimer, runtimer;
+ struct tm nowtime, runtime;
+ int hr = 0;
+ /* this MUST be initialized to zero for midnight/noon/teatime */
+
+ nowtimer = time(NULL);
+ nowtime = *localtime(&nowtimer);
+
+ runtime = nowtime;
+ runtime.tm_sec = 0;
+ runtime.tm_isdst = 0;
+
+ if (argc <= optind)
+ usage();
+
+ init_scanner(argc-optind, argv+optind);
+
+ switch (token()) {
+ case NOW:
+ if (scc < 1) {
+ return nowtimer;
+ }
+ /* now is optional prefix for PLUS/NEXT tree */
+ switch (token()) {
+ case PLUS:
+ plus(&runtime);
+ break;
+
+ case NEXT:
+ next(&runtime);
+ break;
+
+ default:
+ plonk(sc_token);
+ break;
+ }
+ break;
+
+ case PLUS:
+ plus(&runtime);
+ break;
+
+ case NEXT:
+ next(&runtime);
+ break;
+
+ case NUMBER:
+ tod(&runtime);
+ month(&runtime);
+ break;
+
+ /* evil coding for TEATIME|NOON|MIDNIGHT - we've initialised
+ * hr to zero up above, then fall into this case in such a
+ * way so we add +12 +4 hours to it for teatime, +12 hours
+ * to it for noon, and nothing at all for midnight, then
+ * set our runtime to that hour before leaping into the
+ * month scanner
+ */
+ case TEATIME:
+ hr += 4;
+ case NOON:
+ hr += 12;
+ case MIDNIGHT:
+ if (runtime.tm_hour >= hr) {
+ runtime.tm_mday++;
+ runtime.tm_wday++;
+ }
+ runtime.tm_hour = hr;
+ runtime.tm_min = 0;
+ token();
+ /* FALLTHROUGH to month setting */
+ default:
+ month(&runtime);
+ break;
+ } /* ugly case statement */
+ expect(EOF);
+
+ /* convert back to time_t
+ */
+ runtime.tm_isdst = -1;
+ runtimer = mktime(&runtime);
+
+ if (runtimer < 0)
+ panic("garbled time");
+
+ if (nowtimer > runtimer)
+ panic("trying to travel back in time");
+
+ return runtimer;
+} /* parsetime */
diff --git a/system_cmds/at.tproj/parsetime.h b/system_cmds/at.tproj/parsetime.h
new file mode 100644
index 0000000..cf426bb
--- /dev/null
+++ b/system_cmds/at.tproj/parsetime.h
@@ -0,0 +1,26 @@
+/*
+ * at.h - header for at(1)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+time_t parsetime(int argc, char **argv);
diff --git a/system_cmds/at.tproj/pathnames.h b/system_cmds/at.tproj/pathnames.h
new file mode 100644
index 0000000..c409b6e
--- /dev/null
+++ b/system_cmds/at.tproj/pathnames.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Copyright (c) 1993 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ *
+ * $Id: pathnames.h,v 1.2 2005/07/30 01:30:01 lindak Exp $
+ */
+
+#ifndef _PATHNAMES_H_
+#define _PATHNAMES_H_
+
+#include <paths.h>
+
+#define _PATH_ATJOBS "/usr/lib/cron/jobs/"
+#define _PATH_ATSPOOL "/usr/lib/cron/spool/"
+/* Note: _PATH_LOCKFILE appears to be unused; /usr/lib/cron/jobs/.lockfile
+ is the file currently being used by at.*/
+#define _PATH_LOCKFILE "/usr/lib/cron/.lockfile"
+#define _PATH_AT "/usr/lib/cron/"
+
+#endif /* !_PATHNAMES_H_ */
diff --git a/system_cmds/at.tproj/perm.c b/system_cmds/at.tproj/perm.c
new file mode 100644
index 0000000..82bab87
--- /dev/null
+++ b/system_cmds/at.tproj/perm.c
@@ -0,0 +1,125 @@
+/*
+ * perm.c - check user permission for at(1)
+ * Copyright (C) 1994 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/at/perm.c,v 1.13 2001/12/10 21:13:01 dwmalone Exp $");
+
+/* System Headers */
+
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Local headers */
+
+#include "at.h"
+#include "panic.h"
+#include "perm.h"
+#include "privs.h"
+
+/* Macros */
+
+#define MAXUSERID 10
+
+/* Structures and unions */
+
+/* Function declarations */
+
+static int check_for_user(FILE *fp,const char *name);
+
+/* Local functions */
+
+static int check_for_user(FILE *fp,const char *name)
+{
+ char *buffer;
+ int len;
+ int found = 0;
+
+ len = (int)strlen(name);
+ if ((buffer = malloc(len+2)) == NULL)
+ errx(EXIT_FAILURE, "virtual memory exhausted");
+
+ while(fgets(buffer, len+2, fp) != NULL)
+ {
+ if ((strncmp(name, buffer, len) == 0) &&
+ (buffer[len] == '\n'))
+ {
+ found = 1;
+ break;
+ }
+ }
+ fclose(fp);
+ free(buffer);
+ return found;
+}
+/* Global functions */
+int check_permission(void)
+{
+ FILE *fp;
+ uid_t uid = geteuid();
+ struct passwd *pentry;
+
+ if (uid==0)
+ return 1;
+
+ if ((pentry = getpwuid(uid)) == NULL)
+ err(EXIT_FAILURE, "cannot access user database");
+
+ PRIV_START
+
+ fp=fopen(PERM_PATH "at.allow","r");
+
+ PRIV_END
+
+ if (fp != NULL)
+ {
+ return check_for_user(fp, pentry->pw_name);
+ }
+ else if (errno == ENOENT)
+ {
+
+ PRIV_START
+
+ fp=fopen(PERM_PATH "at.deny", "r");
+
+ PRIV_END
+
+ if (fp != NULL)
+ {
+ return !check_for_user(fp, pentry->pw_name);
+ }
+ else if (errno != ENOENT)
+ warn("at.deny");
+ }
+ else
+ warn("at.allow");
+ return 0;
+}
diff --git a/system_cmds/at.tproj/perm.h b/system_cmds/at.tproj/perm.h
new file mode 100644
index 0000000..9781ef8
--- /dev/null
+++ b/system_cmds/at.tproj/perm.h
@@ -0,0 +1,28 @@
+/*
+ * perm.h - header for at(1)
+ * Copyright (C) 1994 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/at/perm.h,v 1.4 2001/12/02 12:26:18 markm Exp $
+ */
+
+int check_permission(void);
diff --git a/system_cmds/at.tproj/privs.h b/system_cmds/at.tproj/privs.h
new file mode 100644
index 0000000..4a43b6c
--- /dev/null
+++ b/system_cmds/at.tproj/privs.h
@@ -0,0 +1,110 @@
+/*
+ * privs.h - header for privileged operations
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD: /usr/local/www/cvsroot/FreeBSD/src/usr.bin/at/privs.h,v 1.10 2011/11/06 20:30:21 ed Exp $
+ */
+
+#ifndef _PRIVS_H
+#define _PRIVS_H
+
+#include <unistd.h>
+
+/* Relinquish privileges temporarily for a setuid or setgid program
+ * with the option of getting them back later. This is done by
+ * utilizing POSIX saved user and group IDs. Call RELINQUISH_PRIVS once
+ * at the beginning of the main program. This will cause all operations
+ * to be executed with the real userid. When you need the privileges
+ * of the setuid/setgid invocation, call PRIV_START; when you no longer
+ * need it, call PRIV_END. Note that it is an error to call PRIV_START
+ * and not PRIV_END within the same function.
+ *
+ * Use RELINQUISH_PRIVS_ROOT(a,b) if your program started out running
+ * as root, and you want to drop back the effective userid to a
+ * and the effective group id to b, with the option to get them back
+ * later.
+ *
+ * If you no longer need root privileges, but those of some other
+ * userid/groupid, you can call REDUCE_PRIV(a,b) when your effective
+ * is the user's.
+ *
+ * Problems: Do not use return between PRIV_START and PRIV_END; this
+ * will cause the program to continue running in an unprivileged
+ * state.
+ *
+ * It is NOT safe to call exec(), system() or popen() with a user-
+ * supplied program (i.e. without carefully checking PATH and any
+ * library load paths) with relinquished privileges; the called program
+ * can acquire them just as easily. Set both effective and real userid
+ * to the real userid before calling any of them.
+ */
+
+#ifndef MAIN
+extern
+#endif
+uid_t real_uid, effective_uid;
+
+#ifndef MAIN
+extern
+#endif
+gid_t real_gid, effective_gid;
+
+#define RELINQUISH_PRIVS { \
+ real_uid = getuid(); \
+ effective_uid = geteuid(); \
+ real_gid = getgid(); \
+ effective_gid = getegid(); \
+ if (setegid(real_gid)<0) perr("cannot setegid"); \
+ if (seteuid(real_uid)<0) perr("cannot seteuid"); \
+}
+
+#define RELINQUISH_PRIVS_ROOT(a, b) { \
+ real_uid = (a); \
+ effective_uid = geteuid(); \
+ real_gid = (b); \
+ effective_gid = getegid(); \
+ if (setegid(real_gid)<0) perr("cannot setegid"); \
+ if (seteuid(real_uid)<0) perr("cannot seteuid"); \
+}
+
+#define PRIV_START { \
+ if (seteuid(0)<0) perr("cannot regain privs"); \
+ if (setegid(effective_gid)<0) perr("cannot reset gid"); \
+ if (seteuid(effective_uid)<0) perr("cannot reset uid"); \
+}
+
+#define PRIV_END { \
+ if (seteuid(0)<0) perr("cannot regain privs"); \
+ if (setegid(real_gid)<0) perr("cannot reset gid"); \
+ if (seteuid(real_uid)<0) perr("cannot reset uid"); \
+}
+
+#define REDUCE_PRIV(a, b) { \
+ PRIV_START \
+ effective_uid = (a); \
+ effective_gid = (b); \
+ if (setegid(effective_gid)<0) perr("cannot setegid"); \
+ if (seteuid(effective_uid)<0) perr("cannot seteuid"); \
+ PRIV_END \
+}
+#endif
diff --git a/system_cmds/atrun.tproj/atrun.8 b/system_cmds/atrun.tproj/atrun.8
new file mode 100644
index 0000000..bc80f6b
--- /dev/null
+++ b/system_cmds/atrun.tproj/atrun.8
@@ -0,0 +1,75 @@
+.\"
+.\" Copyright (c) 1993 Christopher G. Demetriou
+.\" 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 Christopher G. Demetriou.
+.\" 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.
+.\"
+.\" $Id: atrun.8,v 1.1 1999/05/02 04:21:19 wsanchez Exp $
+.\"
+.Dd March 9, 2008
+.Dt ATRUN 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm atrun
+.Nd run jobs queued for later execution
+.Sh SYNOPSIS
+.Nm atrun
+.Sh DESCRIPTION
+The
+.Nm atrun
+utility runs commands queued by
+.Xr at 1 .
+It is invoked periodically by
+.Xr launchd 8
+as specified in the
+.Pa com.apple.atrun.plist
+property list.
+By default the property list contains the
+.Em Disabled
+key set to true, so
+.Nm atrun
+is never invoked.
+.Pp
+Execute the following command as root to enable
+.Nm atrun :
+.Dl "launchctl load -w /System/Library/LaunchDaemons/com.apple.atrun.plist"
+.Pp
+.Sh FILES
+.Bl -tag -width /var/at/lockfile -compact
+.It Pa /var/at/jobs
+Directory containing job files
+.It Pa /var/at/spool
+Directory containing output spool files
+.It Pa /var/at/lockfile
+Job-creation lock file.
+.El
+.Sh SEE ALSO
+.Xr at 1 ,
+.Xr launchd 8
+.Sh AUTHOR
+.Bl -tag
+Thomas Koenig, ig25@rz.uni-karlsruhe.de
+.El
diff --git a/system_cmds/atrun.tproj/atrun.c b/system_cmds/atrun.tproj/atrun.c
new file mode 100644
index 0000000..0981614
--- /dev/null
+++ b/system_cmds/atrun.tproj/atrun.c
@@ -0,0 +1,571 @@
+/*
+ * atrun.c - run jobs queued by at; run with root privileges.
+ * Copyright (C) 1993, 1994 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__FBSDID("$FreeBSD: src/libexec/atrun/atrun.c,v 1.27 2009/12/25 10:30:54 ed Exp $");
+#endif /* not lint */
+
+/* System Headers */
+
+#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+#include <unistd.h>
+#if 1
+#include <paths.h>
+#else
+#include <getopt.h>
+#endif
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#endif
+#ifdef PAM
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+#endif
+
+/* Local headers */
+
+#define MAIN
+#include "privs.h"
+#include "pathnames.h"
+
+/* Macros */
+
+#ifndef ATJOB_DIR
+#define ATJOB_DIR _PATH_ATJOBS
+#endif
+
+#ifndef ATSPOOL_DIR
+#define ATSPOOL_DIR _PATH_ATSPOOL
+#endif
+
+#ifndef LOADAVG_MX
+#define LOADAVG_MX 1.5
+#endif
+
+/* File scope variables */
+
+static const char * const atrun = "atrun"; /* service name for syslog etc. */
+static int debug = 0;
+
+void perr(const char *fmt, ...);
+void perrx(const char *fmt, ...);
+static void usage(void);
+
+/* Local functions */
+static ssize_t
+write_string(int fd, const char* a)
+{
+ return write(fd, a, strlen(a));
+}
+
+#undef DEBUG_FORK
+#ifdef DEBUG_FORK
+static pid_t
+myfork(void)
+{
+ pid_t res;
+ res = fork();
+ if (res == 0)
+ kill(getpid(),SIGSTOP);
+ return res;
+}
+
+#define fork myfork
+#endif
+
+static void
+run_file(const char *filename, uid_t uid, gid_t gid)
+{
+/* Run a file by spawning off a process which redirects I/O,
+ * spawns a subshell, then waits for it to complete and sends
+ * mail to the user.
+ */
+ pid_t pid;
+ int fd_out, fd_in;
+ int queue;
+ char mailbuf[MAXLOGNAME], fmt[64];
+ char *mailname = NULL;
+ FILE *stream;
+ int send_mail = 0;
+ struct stat buf, lbuf;
+ off_t size;
+ struct passwd *pentry;
+ int fflags;
+ long nuid;
+ long ngid;
+#ifdef PAM
+ pam_handle_t *pamh = NULL;
+ int pam_err;
+ struct pam_conv pamc = {
+ .conv = openpam_nullconv,
+ .appdata_ptr = NULL
+ };
+#endif
+
+ PRIV_START
+
+ if (chmod(filename, S_IRUSR) != 0)
+ {
+ perr("cannot change file permissions");
+ }
+
+ PRIV_END
+
+ pid = fork();
+ if (pid == -1)
+ perr("cannot fork");
+
+ else if (pid != 0)
+ return;
+
+#ifdef __APPLE__
+ {
+ pid_t pg = setsid();
+ if (pg == -1) syslog(LOG_ERR,"setsid() failed: %m");
+ }
+#endif
+
+ /* Let's see who we mail to. Hopefully, we can read it from
+ * the command file; if not, send it to the owner, or, failing that,
+ * to root.
+ */
+
+ pentry = getpwuid(uid);
+ if (pentry == NULL)
+ perrx("Userid %lu not found - aborting job %s",
+ (unsigned long) uid, filename);
+
+#ifdef PAM
+ PRIV_START
+
+ pam_err = pam_start(atrun, pentry->pw_name, &pamc, &pamh);
+ if (pam_err != PAM_SUCCESS)
+ perrx("cannot start PAM: %s", pam_strerror(pamh, pam_err));
+
+ pam_err = pam_acct_mgmt(pamh, PAM_SILENT);
+ /* Expired password shouldn't prevent the job from running. */
+ if (pam_err != PAM_SUCCESS && pam_err != PAM_NEW_AUTHTOK_REQD)
+ perrx("Account %s (userid %lu) unavailable for job %s: %s",
+ pentry->pw_name, (unsigned long)uid,
+ filename, pam_strerror(pamh, pam_err));
+
+ pam_end(pamh, pam_err);
+
+ PRIV_END
+#endif /* PAM */
+
+ PRIV_START
+
+ stream=fopen(filename, "r");
+
+ PRIV_END
+
+ if (stream == NULL)
+ perr("cannot open input file");
+
+ if ((fd_in = dup(fileno(stream))) <0)
+ perr("error duplicating input file descriptor");
+
+ if (fstat(fd_in, &buf) == -1)
+ perr("error in fstat of input file descriptor");
+
+ if (lstat(filename, &lbuf) == -1)
+ perr("error in fstat of input file");
+
+ if (S_ISLNK(lbuf.st_mode))
+ perrx("Symbolic link encountered in job %s - aborting", filename);
+
+ if ((lbuf.st_dev != buf.st_dev) || (lbuf.st_ino != buf.st_ino) ||
+ (lbuf.st_uid != buf.st_uid) || (lbuf.st_gid != buf.st_gid) ||
+ (lbuf.st_size!=buf.st_size))
+ perrx("Somebody changed files from under us for job %s - aborting",
+ filename);
+
+ if (buf.st_nlink > 1)
+ perrx("Somebody is trying to run a linked script for job %s", filename);
+
+ if ((fflags = fcntl(fd_in, F_GETFD)) <0)
+ perr("error in fcntl");
+
+ fcntl(fd_in, F_SETFD, fflags & ~FD_CLOEXEC);
+
+ snprintf(fmt, sizeof(fmt),
+ "#!/bin/sh\n# atrun uid=%%ld gid=%%ld\n# mail %%%ds %%d",
+ MAXLOGNAME - 1);
+
+ if (fscanf(stream, fmt, &nuid, &ngid, mailbuf, &send_mail) != 4)
+ perrx("File %s is in wrong format - aborting", filename);
+
+ if (mailbuf[0] == '-')
+ perrx("Illegal mail name %s in %s", mailbuf, filename);
+
+ mailname = mailbuf;
+
+ if (nuid != uid)
+ perrx("Job %s - userid %ld does not match file uid %lu",
+ filename, nuid, (unsigned long)uid);
+
+ if (ngid != gid)
+ perrx("Job %s - groupid %ld does not match file gid %lu",
+ filename, ngid, (unsigned long)gid);
+
+ fclose(stream);
+
+ if (chdir(ATSPOOL_DIR) < 0)
+ perr("cannot chdir to %s", ATSPOOL_DIR);
+
+ /* Create a file to hold the output of the job we are about to run.
+ * Write the mail header.
+ */
+ if((fd_out=open(filename,
+ O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) < 0)
+ perr("cannot create output file");
+
+ write_string(fd_out, "Subject: Output from your job ");
+ write_string(fd_out, filename);
+ write_string(fd_out, "\n\n");
+ fstat(fd_out, &buf);
+ size = buf.st_size;
+
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+
+ pid = fork();
+ if (pid < 0)
+ perr("error in fork");
+
+ else if (pid == 0)
+ {
+ char *nul = NULL;
+ char **nenvp = &nul;
+
+ /* Set up things for the child; we want standard input from the input file,
+ * and standard output and error sent to our output file.
+ */
+
+ if (lseek(fd_in, (off_t) 0, SEEK_SET) < 0)
+ perr("error in lseek");
+
+ if (dup(fd_in) != STDIN_FILENO)
+ perr("error in I/O redirection");
+
+ if (dup(fd_out) != STDOUT_FILENO)
+ perr("error in I/O redirection");
+
+ if (dup(fd_out) != STDERR_FILENO)
+ perr("error in I/O redirection");
+
+ close(fd_in);
+ close(fd_out);
+ if (chdir(ATJOB_DIR) < 0)
+ perr("cannot chdir to %s", ATJOB_DIR);
+
+ queue = *filename;
+
+ PRIV_START
+
+ nice(tolower(queue) - 'a');
+
+#ifdef LOGIN_CAP
+ /*
+ * For simplicity and safety, set all aspects of the user context
+ * except for a selected subset: Don't set priority, which was
+ * set based on the queue file name according to the tradition.
+ * Don't bother to set environment, including path vars, either
+ * because it will be discarded anyway. Although the job file
+ * should set umask, preset it here just in case.
+ */
+ if (setusercontext(NULL, pentry, uid, LOGIN_SETALL &
+ ~(LOGIN_SETPRIORITY | LOGIN_SETPATH | LOGIN_SETENV)) != 0)
+ exit(EXIT_FAILURE); /* setusercontext() logged the error */
+#else /* LOGIN_CAP */
+ if (setgid(gid) < 0 || setegid(pentry->pw_gid) < 0)
+ perr("cannot change group");
+
+ if (initgroups(pentry->pw_name,pentry->pw_gid))
+ perr("cannot init group access list");
+
+ if (setlogin(pentry->pw_name))
+ perr("cannot set login name");
+
+ if (setuid(uid) < 0 || seteuid(uid) < 0)
+ perr("cannot set user id");
+#endif /* LOGIN_CAP */
+
+ if (chdir(pentry->pw_dir))
+ chdir("/");
+
+ if(execle("/bin/sh","sh",(char *) NULL, nenvp) != 0)
+ perr("exec failed for /bin/sh");
+
+ PRIV_END
+ }
+ /* We're the parent. Let's wait.
+ */
+ close(fd_in);
+ close(fd_out);
+ waitpid(pid, (int *) NULL, 0);
+
+ /* Send mail. Unlink the output file first, so it is deleted after
+ * the run.
+ */
+ stat(filename, &buf);
+ if (open(filename, O_RDONLY) != STDIN_FILENO)
+ perr("open of jobfile failed");
+
+ unlink(filename);
+ if ((buf.st_size != size) || send_mail)
+ {
+ PRIV_START
+
+#ifdef LOGIN_CAP
+ /*
+ * This time set full context to run the mailer.
+ */
+ if (setusercontext(NULL, pentry, uid, LOGIN_SETALL) != 0)
+ exit(EXIT_FAILURE); /* setusercontext() logged the error */
+#else /* LOGIN_CAP */
+ if (setgid(gid) < 0 || setegid(pentry->pw_gid) < 0)
+ perr("cannot change group");
+
+ if (initgroups(pentry->pw_name,pentry->pw_gid))
+ perr("cannot init group access list");
+
+ if (setlogin(pentry->pw_name))
+ perr("cannot set login name");
+
+ if (setuid(uid) < 0 || seteuid(uid) < 0)
+ perr("cannot set user id");
+#endif /* LOGIN_CAP */
+
+ if (chdir(pentry->pw_dir))
+ chdir("/");
+
+#if 1
+ execl(_PATH_SENDMAIL, "sendmail", "-F", "Atrun Service",
+ "-odi", "-oem",
+ mailname, (char *) NULL);
+#else
+ execl(MAIL_CMD, MAIL_CMD, mailname, (char *) NULL);
+#endif
+ perr("exec failed for mail command");
+
+ PRIV_END
+ }
+ exit(EXIT_SUCCESS);
+}
+
+/* Global functions */
+
+/* Needed in gloadavg.c */
+void
+perr(const char *fmt, ...)
+{
+ const char * const fmtadd = ": %m";
+ char nfmt[strlen(fmt) + strlen(fmtadd) + 1];
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (debug)
+ {
+ vwarn(fmt, ap);
+ }
+ else
+ {
+ snprintf(nfmt, sizeof(nfmt), "%s%s", fmt, fmtadd);
+ vsyslog(LOG_ERR, nfmt, ap);
+ }
+ va_end(ap);
+
+ exit(EXIT_FAILURE);
+}
+
+void
+perrx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ if (debug)
+ vwarnx(fmt, ap);
+ else
+ vsyslog(LOG_ERR, fmt, ap);
+ va_end(ap);
+
+ exit(EXIT_FAILURE);
+}
+
+int
+main(int argc, char *argv[])
+{
+/* Browse through ATJOB_DIR, checking all the jobfiles wether they should
+ * be executed and or deleted. The queue is coded into the first byte of
+ * the job filename, the date (in minutes since Eon) as a hex number in the
+ * following eight bytes, followed by a dot and a serial number. A file
+ * which has not been executed yet is denoted by its execute - bit set.
+ * For those files which are to be executed, run_file() is called, which forks
+ * off a child which takes care of I/O redirection, forks off another child
+ * for execution and yet another one, optionally, for sending mail.
+ * Files which already have run are removed during the next invocation.
+ */
+ DIR *spool;
+ struct dirent *dirent;
+ struct stat buf;
+ unsigned long ctm;
+ unsigned long jobno;
+ char queue;
+ time_t now, run_time;
+ char batch_name[] = "Z2345678901234";
+ uid_t batch_uid;
+ gid_t batch_gid;
+ int c;
+ int run_batch;
+ double load_avg = LOADAVG_MX, la;
+
+/* We don't need root privileges all the time; running under uid and gid daemon
+ * is fine.
+ */
+
+ RELINQUISH_PRIVS_ROOT(DAEMON_UID, DAEMON_GID)
+
+ openlog(atrun, LOG_PID, LOG_CRON);
+
+ opterr = 0;
+ while((c=getopt(argc, argv, "dl:"))!= -1)
+ {
+ switch (c)
+ {
+ case 'l':
+ if (sscanf(optarg, "%lf", &load_avg) != 1)
+ perr("garbled option -l");
+ if (load_avg <= 0.)
+ load_avg = LOADAVG_MX;
+ break;
+
+ case 'd':
+ debug ++;
+ break;
+
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ if (chdir(ATJOB_DIR) != 0)
+ perr("cannot change to %s", ATJOB_DIR);
+
+ /* Main loop. Open spool directory for reading and look over all the
+ * files in there. If the filename indicates that the job should be run
+ * and the x bit is set, fork off a child which sets its user and group
+ * id to that of the files and exec a /bin/sh which executes the shell
+ * script. Unlink older files if they should no longer be run. For
+ * deletion, their r bit has to be turned on.
+ *
+ * Also, pick the oldest batch job to run, at most one per invocation of
+ * atrun.
+ */
+ if ((spool = opendir(".")) == NULL)
+ perr("cannot read %s", ATJOB_DIR);
+
+ now = time(NULL);
+ run_batch = 0;
+ batch_uid = (uid_t) -1;
+ batch_gid = (gid_t) -1;
+
+ while ((dirent = readdir(spool)) != NULL) {
+ if (stat(dirent->d_name,&buf) != 0)
+ perr("cannot stat in %s", ATJOB_DIR);
+
+ /* We don't want directories
+ */
+ if (!S_ISREG(buf.st_mode))
+ continue;
+
+ if (sscanf(dirent->d_name,"%c%5lx%8lx",&queue,&jobno,&ctm) != 3)
+ continue;
+
+ run_time = (time_t) ctm*60;
+
+ if ((S_IXUSR & buf.st_mode) && (run_time <=now)) {
+ if ((isupper(queue) || queue == 'b') && (strcmp(batch_name,dirent->d_name) > 0)) {
+ run_batch = 1;
+ strlcpy(batch_name, dirent->d_name, sizeof(batch_name));
+ batch_uid = buf.st_uid;
+ batch_gid = buf.st_gid;
+ }
+
+ /* The file is executable and old enough
+ */
+ if (islower(queue))
+ run_file(dirent->d_name, buf.st_uid, buf.st_gid);
+ }
+ /* Delete older files
+ */
+ if ((run_time < now) && !(S_IXUSR & buf.st_mode) && (S_IRUSR & buf.st_mode))
+ unlink(dirent->d_name);
+ }
+ /* run the single batch file, if any
+ */
+ if (run_batch && (getloadavg(&la, 1) == 1) && la < load_avg)
+ run_file(batch_name, batch_uid, batch_gid);
+
+ closelog();
+#if __APPLE__
+ // allow enough time for child processes to call setsid(2)
+ sleep(1);
+#endif
+ exit(EXIT_SUCCESS);
+}
+
+static void
+usage(void)
+{
+ if (debug)
+ fprintf(stderr, "usage: atrun [-l load_avg] [-d]\n");
+ else
+ syslog(LOG_ERR, "usage: atrun [-l load_avg] [-d]");
+
+ exit(EXIT_FAILURE);
+}
diff --git a/system_cmds/atrun.tproj/com.apple.atrun.plist b/system_cmds/atrun.tproj/com.apple.atrun.plist
new file mode 100644
index 0000000..bdb53c0
--- /dev/null
+++ b/system_cmds/atrun.tproj/com.apple.atrun.plist
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Label</key>
+ <string>com.apple.atrun</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/atrun</string>
+ </array>
+ <key>StartInterval</key>
+ <integer>30</integer>
+ <key>Disabled</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/atrun.tproj/gloadavg.c b/system_cmds/atrun.tproj/gloadavg.c
new file mode 100644
index 0000000..267a8c8
--- /dev/null
+++ b/system_cmds/atrun.tproj/gloadavg.c
@@ -0,0 +1,72 @@
+/*
+ * gloadavg.c - get load average for Linux
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/libexec/atrun/gloadavg.c,v 1.5 1999/08/28 00:09:12 peter Exp $";
+#endif /* not lint */
+
+#ifndef __FreeBSD__
+#define _POSIX_SOURCE 1
+
+/* System Headers */
+
+#include <stdio.h>
+#else
+#include <stdlib.h>
+#endif
+
+/* Local headers */
+
+#include "gloadavg.h"
+
+/* Global functions */
+
+void perr(const char *a);
+
+double
+gloadavg(void)
+/* return the current load average as a floating point number, or <0 for
+ * error
+ */
+{
+ double result;
+#ifndef __FreeBSD__
+ FILE *fp;
+
+ if((fp=fopen(PROC_DIR "loadavg","r")) == NULL)
+ result = -1.0;
+ else
+ {
+ if(fscanf(fp,"%lf",&result) != 1)
+ result = -1.0;
+ fclose(fp);
+ }
+#else
+ if (getloadavg(&result, 1) != 1)
+ perr("error in getloadavg");
+#endif
+ return result;
+}
diff --git a/system_cmds/atrun.tproj/gloadavg.h b/system_cmds/atrun.tproj/gloadavg.h
new file mode 100644
index 0000000..b81a4fc
--- /dev/null
+++ b/system_cmds/atrun.tproj/gloadavg.h
@@ -0,0 +1,29 @@
+/*
+ * gloadavg.h - header for atrun(8)
+ * Copyright (C) 1993 Thomas Koenig
+ *
+ * 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. The name of the author(s) 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(S) ``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(S) 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, WETHER 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.
+ */
+
+double gloadavg(void);
+#if 0
+static char atrun_h_rcsid[] = "$FreeBSD: src/libexec/atrun/gloadavg.h,v 1.4 1999/08/28 00:09:12 peter Exp $";
+#endif
diff --git a/system_cmds/base.xcconfig b/system_cmds/base.xcconfig
new file mode 100644
index 0000000..5cd52d0
--- /dev/null
+++ b/system_cmds/base.xcconfig
@@ -0,0 +1,9 @@
+CODE_SIGN_IDENTITY = -;
+CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion);
+DEAD_CODE_STRIPPING = YES;
+DEBUG_INFORMATION_FORMAT = dwarf-with-dsym;
+PREBINDING = NO;
+// Current macOS
+SDKROOT = macosx.internal;
+VERSION_INFO_PREFIX = __attribute__((visibility("hidden"))) __
+VERSIONING_SYSTEM = apple-generic;
diff --git a/system_cmds/chkpasswd.tproj/chkpasswd.8 b/system_cmds/chkpasswd.tproj/chkpasswd.8
new file mode 100644
index 0000000..fd6c4f2
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/chkpasswd.8
@@ -0,0 +1,59 @@
+.Dd July 20, 2004
+.Dt CHKPASSWD 8
+.Os Darwin
+.Sh NAME
+.Nm chkpasswd
+.Nd verifies user password against various systems
+.Sh SYNOPSIS
+.Nm chkpasswd
+.Op Fl i Ar infosystem Op Fl l Ar location
+.Op Fl c
+.Op Ar name
+.Sh DESCRIPTION
+.Nm chkpasswd
+verifies a supplied username and password against file, NIS,
+or OpenDirectory infosystems.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl c
+The supplied password is compared verbatim without first being encrypted.
+.\" ==========
+.It Fl i Ar infosystem
+Specify the system against which to check the password
+(default is PAM). Valid systems:
+.Bl -tag -width "opendirectory"
+.It Ar file
+File-based passwords
+.It Ar nis
+NIS/YP authentication
+.It Ar opendirectory
+OpenDirectory (Directory Services) authentication.
+If no
+.Fl l
+option is specified, the search node is used.
+.It Ar PAM
+Pluggable Authentication Modules
+.El
+.Pp
+.\" ==========
+.It Fl l Ar location
+Specify a location; varies based on infosystem type:
+.Bl -tag -width "for opendirectory"
+.It for file
+Filename (default: /etc/master.passwd).
+.It for nis
+NIS domainname.
+.It for opendirectory
+A directory node name such as /Local/Default.
+.It for PAM
+Unused.
+.El
+.Pp
+.El
+.Ar name
+username
+.Sh SEE ALSO
+.Xr dscl 1 ,
+.Xr passwd 5
diff --git a/system_cmds/chkpasswd.tproj/chkpasswd.pam b/system_cmds/chkpasswd.tproj/chkpasswd.pam
new file mode 100644
index 0000000..18404e6
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/chkpasswd.pam
@@ -0,0 +1,5 @@
+# chkpasswd: auth account
+auth required pam_opendirectory.so
+account required pam_opendirectory.so
+password required pam_permit.so
+session required pam_permit.so
diff --git a/system_cmds/chkpasswd.tproj/file_passwd.c b/system_cmds/chkpasswd.tproj/file_passwd.c
new file mode 100644
index 0000000..90f54f2
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/file_passwd.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <string.h>
+#include "stringops.h"
+
+#define TEMP_FILE "/tmp/.pwtmp"
+
+#define _PASSWD_FILE "/etc/master.passwd"
+#define _COMPAT_FILE "/etc/passwd"
+#define _PASSWD_FIELDS 10
+#define BUFSIZE 8192
+
+#include "passwd.h"
+
+static char *
+_getline(FILE *fp)
+{
+ static char s[BUFSIZE];
+ size_t len;
+
+ s[0] = '\0';
+
+ fgets(s, BUFSIZE, fp);
+ if (s[0] == '\0') return NULL;
+
+ if (s[0] == '#') return s;
+
+ len = strlen(s) - 1;
+ s[len] = '\0';
+
+ return s;
+}
+
+static struct passwd *
+parse_user(char *line)
+{
+ static struct passwd pw = {0};
+ char **tokens;
+ int i, len;
+
+ if (pw.pw_name != NULL) free(pw.pw_name);
+ pw.pw_name = NULL;
+ if (pw.pw_passwd != NULL) free(pw.pw_passwd);
+ pw.pw_passwd = NULL;
+ if (pw.pw_gecos != NULL) free(pw.pw_gecos);
+ pw.pw_gecos = NULL;
+ if (pw.pw_dir != NULL) free(pw.pw_dir);
+ pw.pw_dir = NULL;
+ if (pw.pw_shell != NULL) free(pw.pw_shell);
+ pw.pw_shell = NULL;
+
+ if (pw.pw_class != NULL) free(pw.pw_class);
+ pw.pw_class = NULL;
+
+ if (line == NULL) return (struct passwd *)NULL;
+ tokens = explode(line, ':');
+ len = listLength(tokens);
+
+ if (len != _PASSWD_FIELDS)
+ {
+ freeList(tokens);
+ return (struct passwd *)NULL;
+ }
+
+ i = 0;
+ pw.pw_name = tokens[i++];
+ pw.pw_passwd = tokens[i++];
+ pw.pw_uid = atoi(tokens[i]);
+ free(tokens[i++]);
+ pw.pw_gid = atoi(tokens[i]);
+ free(tokens[i++]);
+ pw.pw_class = tokens[i++];
+ pw.pw_change = atoi(tokens[i]);
+ free(tokens[i++]);
+ pw.pw_expire = atoi(tokens[i]);
+ free(tokens[i++]);
+ pw.pw_gecos = tokens[i++];
+ pw.pw_dir = tokens[i++];
+ pw.pw_shell = tokens[i++];
+
+ return &pw;
+}
+
+static struct passwd *
+find_user(char *uname, FILE *fp)
+{
+ char *line;
+ struct passwd *pw;
+
+ rewind(fp);
+
+ while (NULL != (line = _getline(fp)))
+ {
+ if (line[0] == '#') continue;
+ pw = parse_user(line);
+ if (pw == (struct passwd *)NULL) continue;
+ if (!strcmp(uname, pw->pw_name)) return pw;
+ }
+
+ pw = parse_user(NULL);
+ return (struct passwd *)NULL;
+}
+
+#if 0
+static void
+rewrite_file(char *pwname, FILE *fp, struct passwd *newpw)
+{
+ char *line;
+ struct passwd *pw;
+ FILE *tfp, *cfp;
+ char fname[256];
+
+ sprintf(fname, "%s.%d", TEMP_FILE, getpid());
+
+ tfp = fopen(fname, "w+");
+ if (tfp == NULL)
+ {
+ fprintf(stderr, "can't write temporary file \"%s\": ", fname);
+ perror("");
+ exit(1);
+ }
+
+ cfp = NULL;
+ if (!strcmp(pwname, _PASSWD_FILE))
+ {
+ cfp = fopen(_COMPAT_FILE, "w");
+ if (cfp == NULL)
+ {
+ fprintf(stderr, "warning: can't write compatability file \"%s\": ",
+ _COMPAT_FILE);
+ perror("");
+ }
+ }
+
+ if (cfp != NULL)
+ {
+ fprintf(cfp, "#\n");
+ fprintf(cfp, "# 4.3BSD-compatable User Database\n");
+ fprintf(cfp, "#\n");
+ fprintf(cfp, "# Note that this file is not consulted for login.\n");
+ fprintf(cfp, "# It only exisits for compatability with 4.3BSD utilities.\n");
+ fprintf(cfp, "#\n");
+ fprintf(cfp, "# This file is automatically re-written by various system utilities.\n");
+ fprintf(cfp, "# Do not edit this file. Changes will be lost.\n");
+ fprintf(cfp, "#\n");
+ }
+
+ rewind(fp);
+
+ while (NULL != (line = _getline(fp)))
+ {
+ if (line[0] == '#')
+ {
+ fprintf(tfp, "%s", line);
+ continue;
+ }
+
+ pw = parse_user(line);
+ if (pw == (struct passwd *)NULL)
+ {
+ fprintf(stderr, "warning: bad format for entry: \"%s\"\n", line);
+ fprintf(tfp, "%s\n", line);
+ if (cfp != NULL) fprintf(cfp, "%s\n", line);
+ continue;
+ }
+
+ if (strcmp(newpw->pw_name, pw->pw_name))
+ {
+ fprintf(tfp, "%s\n", line);
+ if (cfp != NULL) fprintf(cfp, "%s\n", line);
+ continue;
+ }
+
+ fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ newpw->pw_name, newpw->pw_passwd, newpw->pw_uid, newpw->pw_gid,
+ newpw->pw_class, newpw->pw_change, newpw->pw_expire,
+ newpw->pw_gecos, newpw->pw_dir, newpw->pw_shell);
+ if (cfp != NULL)
+ {
+ fprintf(cfp, "%s:",newpw->pw_name);
+ if ((newpw->pw_passwd == NULL) || (newpw->pw_passwd[0] == '\0'))
+ fprintf(cfp, ":");
+ else
+ fprintf(cfp, "*:");
+ fprintf(cfp, "%d:%d:%s:%s:%s\n",
+ newpw->pw_uid, newpw->pw_gid, newpw->pw_gecos,
+ newpw->pw_dir, newpw->pw_shell);
+ }
+ }
+
+ if (cfp != NULL) fclose(cfp);
+ fclose(fp);
+ if (unlink(pwname) < 0)
+ {
+ fprintf(stderr, "can't update \"%s\": ", pwname);
+ perror("");
+ }
+
+ rewind(tfp);
+
+ fp = fopen(pwname, "w");
+ if (fp == NULL)
+ {
+ fprintf(stderr, "ERROR: lost file \"%s\"\n", pwname);
+ fprintf(stderr, "new passwd file is \"%s\"\n", fname);
+ perror("open");
+ exit(1);
+ }
+
+ while (NULL != (line = _getline(tfp)))
+ {
+ fprintf(fp, "%s", line);
+ if (line[0] != '#') fprintf(fp, "\n");
+ }
+ fclose(fp);
+ fclose(tfp);
+ unlink(fname);
+}
+#endif /* 0 */
+
+int
+file_check_passwd(char *uname, char *locn)
+{
+ FILE *fp;
+ char *fname;
+ struct passwd *pw;
+
+ fname = _PASSWD_FILE;
+ if (locn != NULL) fname = locn;
+
+ if (access(fname,R_OK) || (fp = fopen(fname, "r")) == NULL)
+ {
+ fprintf(stderr, "can't read file \"%s\": ", fname);
+ perror("");
+ exit(1);
+ }
+
+
+ pw = find_user(uname, fp);
+ if (pw == (struct passwd *)NULL)
+ {
+ fprintf(stderr, "user %s not found in file %s\n", uname, fname);
+ exit(1);
+ }
+
+ checkpasswd(uname, pw->pw_passwd);
+ fclose(fp);
+
+ return 0;
+}
diff --git a/system_cmds/chkpasswd.tproj/nis_passwd.c b/system_cmds/chkpasswd.tproj/nis_passwd.c
new file mode 100644
index 0000000..c2e6e4f
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/nis_passwd.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1998 by Apple Computer, Inc.
+ * Portions Copyright (c) 1988 by Sun Microsystems, Inc.
+ * Portions Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+/* update a user's password in NIS. This was based on the Sun implementation
+ * we used in NEXTSTEP, although I've added some stuff from OpenBSD. And
+ * it uses the API to support Rhapsody's proprietry infosystem switch.
+ * lukeh
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <netinet/in.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_clnt.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+
+#include "passwd.h"
+
+static struct passwd *ypgetpwnam(char *name, char *domain);
+
+int
+nis_check_passwd(char *uname, char *domain)
+{
+ int port;
+ char *master;
+ struct passwd *pwd;
+
+ if (domain == NULL)
+ {
+ if (yp_get_default_domain(&domain) != 0)
+ {
+ (void)fprintf(stderr, "can't get domain\n");
+ exit(1);
+ }
+ }
+
+ if (yp_master(domain, "passwd.byname", &master) != 0)
+ {
+ (void)fprintf(stderr, "can't get master for passwd file\n");
+ exit(1);
+ }
+
+ port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE,
+ IPPROTO_UDP);
+ if (port == 0)
+ {
+ (void)fprintf(stderr, "%s is not running yppasswd daemon\n",
+ master);
+ exit(1);
+ }
+ if (port >= IPPORT_RESERVED)
+ {
+ (void)fprintf(stderr,
+ "yppasswd daemon is not running on privileged port\n");
+ exit(1);
+ }
+
+ pwd = ypgetpwnam(uname, domain);
+ if (pwd == NULL)
+ {
+ (void)fprintf(stderr, "user %s not found\n", uname);
+ exit(1);
+ }
+
+ checkpasswd(uname, pwd->pw_passwd);
+ return(0);
+}
+
+static char *
+pwskip(register char *p)
+{
+ while (*p && *p != ':' && *p != '\n')
+ ++p;
+ if (*p)
+ *p++ = 0;
+ return (p);
+}
+
+static struct passwd *
+interpret(struct passwd *pwent, char *line)
+{
+ register char *p = line;
+
+ pwent->pw_passwd = "*";
+ pwent->pw_uid = 0;
+ pwent->pw_gid = 0;
+ pwent->pw_gecos = "";
+ pwent->pw_dir = "";
+ pwent->pw_shell = "";
+#ifndef __SLICK__
+ pwent->pw_change = 0;
+ pwent->pw_expire = 0;
+ pwent->pw_class = "";
+#endif
+
+ /* line without colon separators is no good, so ignore it */
+ if(!strchr(p, ':'))
+ return(NULL);
+
+ pwent->pw_name = p;
+ p = pwskip(p);
+ pwent->pw_passwd = p;
+ p = pwskip(p);
+ pwent->pw_uid = (uid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gid = (gid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gecos = p;
+ p = pwskip(p);
+ pwent->pw_dir = p;
+ p = pwskip(p);
+ pwent->pw_shell = p;
+ while (*p && *p != '\n')
+ p++;
+ *p = '\0';
+ return (pwent);
+}
+
+static struct passwd *
+ypgetpwnam(char *nam, char *domain)
+{
+ static struct passwd pwent;
+ char *val;
+ int reason, vallen;
+ static char *__yplin = NULL;
+
+ reason = yp_match(domain, "passwd.byname", nam, (int)strlen(nam),
+ &val, &vallen);
+ switch(reason) {
+ case 0:
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+ val[vallen] = '\0';
+ if (__yplin)
+ free(__yplin);
+ __yplin = (char *)malloc(vallen + 1);
+ strcpy(__yplin, val);
+ free(val);
+
+ return(interpret(&pwent, __yplin));
+}
diff --git a/system_cmds/chkpasswd.tproj/od_passwd.c b/system_cmds/chkpasswd.tproj/od_passwd.c
new file mode 100644
index 0000000..2ea724f
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/od_passwd.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 1998-2016 Apple Inc. All rights reserved.
+ * Portions Copyright (c) 1988 by Sun Microsystems, Inc.
+ * Portions Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <netinet/in.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+
+#include <OpenDirectory/OpenDirectory.h>
+
+#include "passwd.h"
+
+//-------------------------------------------------------------------------------------
+// od_check_passwd
+//-------------------------------------------------------------------------------------
+
+int
+od_check_passwd(const char *uname, const char *domain)
+{
+ int authenticated = 0;
+
+ ODSessionRef session = NULL;
+ ODNodeRef node = NULL;
+ ODRecordRef rec = NULL;
+ CFStringRef user = NULL;
+ CFStringRef location = NULL;
+ CFStringRef password = NULL;
+
+ if (uname) user = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8);
+ if (domain) location = CFStringCreateWithCString(NULL, domain, kCFStringEncodingUTF8);
+
+ if (user) {
+ printf("Checking password for %s.\n", uname);
+ char* p = getpass("Password:");
+ if (p) password = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ }
+
+ if (password) {
+ session = ODSessionCreate(NULL, NULL, NULL);
+ if (session) {
+ if (location) {
+ node = ODNodeCreateWithName(NULL, session, location, NULL);
+ } else {
+ node = ODNodeCreateWithNodeType(NULL, session, kODNodeTypeAuthentication, NULL);
+ }
+ if (node) {
+ rec = ODNodeCopyRecord(node, kODRecordTypeUsers, user, NULL, NULL);
+ }
+ if (rec) {
+ authenticated = ODRecordVerifyPassword(rec, password, NULL);
+ }
+ }
+ }
+
+ if (!authenticated) {
+ fprintf(stderr, "Sorry\n");
+ exit(1);
+ }
+
+ return 0;
+}
diff --git a/system_cmds/chkpasswd.tproj/pam_passwd.c b/system_cmds/chkpasswd.tproj/pam_passwd.c
new file mode 100644
index 0000000..07d9919
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/pam_passwd.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+
+#include <security/pam_appl.h>
+#include <security/openpam.h> /* for openpam_ttyconv() */
+
+#include "passwd.h"
+
+extern char* progname;
+static pam_handle_t *pamh;
+static struct pam_conv pamc;
+
+//-------------------------------------------------------------------------------------
+// pam_check_passwd
+//-------------------------------------------------------------------------------------
+
+int
+pam_check_passwd(char* uname)
+{
+ int retval = PAM_SUCCESS;
+
+ /* Initialize PAM. */
+ pamc.conv = &openpam_ttyconv;
+ pam_start(progname, uname, &pamc, &pamh);
+
+ printf("Checking password for %s.\n", uname);
+
+ /* Authenticate. */
+ if (PAM_SUCCESS != (retval = pam_authenticate(pamh, 0)))
+ goto pamerr;
+
+ /* Authorize. */
+ if (PAM_SUCCESS != (retval = pam_acct_mgmt(pamh, 0)) && PAM_NEW_AUTHTOK_REQD != retval)
+ goto pamerr;
+
+ /* Change the password. */
+ if (PAM_NEW_AUTHTOK_REQD == retval && PAM_SUCCESS != (retval = pam_chauthtok(pamh, 0)))
+ goto pamerr;
+
+ /* Set the credentials. */
+ if (PAM_SUCCESS != (retval = pam_setcred(pamh, PAM_ESTABLISH_CRED)))
+ goto pamerr;
+
+ /* Open the session. */
+ if (PAM_SUCCESS != (retval = pam_open_session(pamh, 0)))
+ goto pamerr;
+
+ /* Close the session. */
+ if (PAM_SUCCESS != (retval = pam_close_session(pamh, 0)))
+ goto pamerr;
+
+pamerr:
+ /* Print an error, if needed. */
+ if (PAM_SUCCESS != retval)
+ fprintf(stderr, "Sorry\n");
+
+ /* Terminate PAM. */
+ pam_end(pamh, retval);
+ return retval;
+}
diff --git a/system_cmds/chkpasswd.tproj/passwd.c b/system_cmds/chkpasswd.tproj/passwd.c
new file mode 100644
index 0000000..bff8280
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/passwd.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#define INFO_FILE 1
+#define INFO_NIS 2
+#define INFO_OPEN_DIRECTORY 3
+#define INFO_PAM 4
+
+#ifndef __SLICK__
+#define _PASSWD_FILE "/etc/master.passwd"
+#else
+#define _PASSWD_FILE "/etc/passwd"
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <libc.h>
+#include <ctype.h>
+#include <string.h>
+#include <pwd.h>
+#include "stringops.h"
+
+#ifdef __SLICK__
+#define _PASSWORD_LEN 8
+#endif
+
+#include "passwd.h"
+
+const char* progname = "chkpasswd";
+
+static int literal = 0;
+
+void
+checkpasswd(char *name, char *old_pw)
+{
+ int isNull;
+ char *p;
+
+ printf("Checking password for %s.\n", name);
+
+ p = "";
+ isNull = 0;
+ if (old_pw == NULL) isNull = 1;
+ if ((isNull == 0) && (old_pw[0] == '\0')) isNull = 1;
+ if (isNull == 0)
+ {
+ p = getpass("Password:");
+ sleep(1); // make sure this doesn't go too quickly
+ if (strcmp(literal ? p : crypt(p, old_pw), old_pw))
+ {
+ errno = EACCES;
+ fprintf(stderr, "Sorry\n");
+ exit(1);
+ }
+ }
+ return;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: chkpasswd [-i infosystem] [-l location] [-c] [name]\n");
+ fprintf(stderr, " infosystem:\n");
+ fprintf(stderr, " file\n");
+ fprintf(stderr, " NIS\n");
+ fprintf(stderr, " OpenDirectory\n");
+ fprintf(stderr, " location (for infosystem):\n");
+ fprintf(stderr, " file location is path to file (default is %s)\n", _PASSWD_FILE);
+ fprintf(stderr, " NIS location is NIS domain name\n");
+ fprintf(stderr, " OpenDirectory location is directory node name\n");
+ fprintf(stderr, " -c: supplied password is compared verbatim without first\n");
+ fprintf(stderr, " being crypted\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char* user = NULL;
+ char* locn = NULL;
+ int infosystem, ch;
+
+ infosystem = INFO_PAM;
+
+ while ((ch = getopt(argc, argv, "ci:l:")) != -1) {
+ switch(ch) {
+ case 'i':
+ if (!strcasecmp(optarg, "file")) {
+ infosystem = INFO_FILE;
+ } else if (!strcasecmp(optarg, "NIS")) {
+ infosystem = INFO_NIS;
+ } else if (!strcasecmp(optarg, "YP")) {
+ infosystem = INFO_NIS;
+ } else if (!strcasecmp(optarg, "opendirectory")) {
+ infosystem = INFO_OPEN_DIRECTORY;
+ } else if (!strcasecmp(optarg, "PAM")) {
+ infosystem = INFO_PAM;
+ } else {
+ fprintf(stderr, "%s: Unknown info system \'%s\'.\n",
+ progname, optarg);
+ usage();
+ }
+ break;
+ case 'l':
+ locn = optarg;
+ break;
+ case 'c':
+ literal++;
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1) {
+ usage();
+ } else if (argc == 1) {
+ user = argv[0];
+ }
+
+ if (user == NULL) {
+ struct passwd* pw = getpwuid(getuid());
+ if (pw != NULL && pw->pw_name != NULL) {
+ user = strdup(pw->pw_name);
+ }
+ if (user == NULL) {
+ fprintf(stderr, "you don't have a login name\n");
+ exit(1);
+ }
+ }
+
+ switch (infosystem)
+ {
+ case INFO_FILE:
+ file_check_passwd(user, locn);
+ break;
+ case INFO_NIS:
+ nis_check_passwd(user, locn);
+ break;
+ case INFO_OPEN_DIRECTORY:
+ od_check_passwd(user, locn);
+ break;
+ case INFO_PAM:
+ pam_check_passwd(user);
+ break;
+ }
+
+ exit(0);
+}
diff --git a/system_cmds/chkpasswd.tproj/passwd.h b/system_cmds/chkpasswd.tproj/passwd.h
new file mode 100644
index 0000000..692722b
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/passwd.h
@@ -0,0 +1,5 @@
+int file_check_passwd(char *, char *);
+int nis_check_passwd(char *, char *);
+int od_check_passwd(const char *, const char *);
+int pam_check_passwd(char *);
+void checkpasswd(char *, char *);
diff --git a/system_cmds/chkpasswd.tproj/stringops.c b/system_cmds/chkpasswd.tproj/stringops.c
new file mode 100644
index 0000000..960ce19
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/stringops.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#import <string.h>
+#import <stdlib.h>
+#import <stdio.h>
+#import <stdarg.h>
+#import "stringops.h"
+
+char *
+copyString(char *s)
+{
+ size_t len;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ len = strlen(s) + 1;
+ t = malloc(len);
+ bcopy(s, t, len);
+ return t;
+}
+
+char *
+concatString(char *s, char *t)
+{
+ size_t len;
+
+ if (t == NULL) return s;
+
+ len = strlen(s) + strlen(t) + 1;
+ s = realloc(s, len);
+ strcat(s, t);
+ return s;
+}
+
+char **
+insertString(char *s, char **l, unsigned int x)
+{
+ int i, len;
+
+ if (s == NULL) return l;
+ if (l == NULL)
+ {
+ l = (char **)malloc(2 * sizeof(char *));
+ l[0] = copyString(s);
+ l[1] = NULL;
+ return l;
+ }
+
+ for (i = 0; l[i] != NULL; i++);
+ len = i + 1; /* count the NULL on the end of the list too! */
+
+ l = (char **)realloc(l, (len + 1) * sizeof(char *));
+
+ if ((x >= (len - 1)) || (x == IndexNull))
+ {
+ l[len - 1] = copyString(s);
+ l[len] = NULL;
+ return l;
+ }
+
+ for (i = len; i > x; i--) l[i] = l[i - 1];
+ l[x] = copyString(s);
+ return l;
+}
+
+char **
+appendString(char *s, char **l)
+{
+ return insertString(s, l, IndexNull);
+}
+
+void
+freeList(char **l)
+{
+ int i;
+
+ if (l == NULL) return;
+ for (i = 0; l[i] != NULL; i++)
+ {
+ if (l[i] != NULL) free(l[i]);
+ l[i] = NULL;
+ }
+ if (l != NULL) free(l);
+}
+
+void
+freeString(char *s)
+{
+ if (s == NULL) return;
+ free(s);
+}
+
+unsigned int
+listLength(char **l)
+{
+ int i;
+
+ if (l == NULL) return 0;
+ for (i = 0; l[i] != NULL; i++);
+ return i;
+}
+
+unsigned int
+listIndex(char *s,char **l)
+{
+ int i;
+
+ if (l == NULL) return IndexNull;
+ for (i = 0; l[i] != NULL; i++)
+ {
+ if (strcmp(s, l[i]) == 0) return i;
+ }
+ return IndexNull;
+}
+
+char *
+prefix(char *s, char c)
+{
+ int i;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ for (i = 0; ((s[i] != '\0') && (s[i] != c)); i++);
+ if (i == 0) return NULL;
+ if (s[i] == '\0') return copyString(s);
+
+ t = malloc(i + 1);
+ bcopy(s, t, i);
+ t[i] = '\0';
+ return t;
+}
+
+char *
+postfix(char *s, char c)
+{
+ int i;
+ size_t len;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ for (i = 0; ((s[i] != '\0') && (s[i] != c)); i++);
+ if (s[i] == '\0') return NULL;
+ len = strlen(s) - i;
+ if (len == 1) return NULL;
+
+ t = malloc(len);
+ len--;
+ bcopy((s + i + 1), t, len);
+ t[len] = '\0';
+ return t;
+}
+
+char *
+presuffix(char *s, char c)
+{
+ ssize_t i;
+ size_t len;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ len = strlen(s);
+ for (i = len - 1; ((i >= 0) && (s[i] != c)); i--);
+ if (i == 0) return NULL;
+ if (s[0] == '\0') return NULL;
+
+ t = malloc(i + 1);
+ bcopy(s, t, i);
+ t[i] = '\0';
+ return t;
+}
+
+char *
+suffix(char *s, char c)
+{
+ ssize_t i;
+ size_t len;
+ char *t;
+
+ if (s == NULL) return NULL;
+
+ len = strlen(s);
+ for (i = len - 1; ((i >= 0) && (s[i] != c)); i--);
+ if (i == 0) return NULL;
+ len -= i;
+ if (len == 1) return NULL;
+ t = malloc(len);
+ len--;
+ bcopy((s + i + 1), t, len);
+ t[len] = '\0';
+ return t;
+}
+
+char *
+lowerCase(char *s)
+{
+ int i;
+ char *t;
+
+ if (s == NULL) return NULL;
+ t = malloc(strlen(s) + 1);
+
+ for (i = 0; s[i] != '\0'; i++)
+ {
+ if ((s[i] >= 'A') && (s[i] <= 'Z')) t[i] = s[i] + 32;
+ else t[i] = s[i];
+ }
+ t[i] = '\0';
+ return t;
+}
+
+char **
+explode(char *s, char c)
+{
+ char **l = NULL;
+ char *p, *t;
+ int i, n;
+
+ if (s == NULL) return NULL;
+
+ p = s;
+ while (p[0] != '\0')
+ {
+ for (i = 0; ((p[i] != '\0') && p[i] != c); i++);
+ n = i;
+ t = malloc(n + 1);
+ for (i = 0; i < n; i++) t[i] = p[i];
+ t[n] = '\0';
+ l = appendString(t, l);
+ free(t);
+ t = NULL;
+ if (p[i] == '\0') return l;
+ if (p[i + 1] == '\0') l = appendString("", l);
+ p = p + i + 1;
+ }
+ return l;
+}
diff --git a/system_cmds/chkpasswd.tproj/stringops.h b/system_cmds/chkpasswd.tproj/stringops.h
new file mode 100644
index 0000000..776adf6
--- /dev/null
+++ b/system_cmds/chkpasswd.tproj/stringops.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#define streq(A, B) (strcmp(A, B) == 0)
+#define IndexNull (unsigned int)-1
+char *copyString(char *);
+char *concatString(char *, char *);
+char **insertString(char *, char **, unsigned int);
+char **appendString(char *, char **);
+void freeList(char **);
+void freeString(char *);
+unsigned int listLength(char **);
+unsigned int listIndex(char *,char **);
+char *prefix(char *, char);
+char *postfix(char *, char);
+char *presuffix(char *, char);
+char *suffix(char *, char);
+char *lowerCase(char *);
+char **explode(char *, char);
diff --git a/system_cmds/chpass.tproj/IMPORT_NOTES b/system_cmds/chpass.tproj/IMPORT_NOTES
new file mode 100644
index 0000000..457907b
--- /dev/null
+++ b/system_cmds/chpass.tproj/IMPORT_NOTES
@@ -0,0 +1 @@
+chpass.1 - FreeBSD file with references to yp items deleted
diff --git a/system_cmds/chpass.tproj/chpass.1 b/system_cmds/chpass.tproj/chpass.1
new file mode 100644
index 0000000..7ee45ae
--- /dev/null
+++ b/system_cmds/chpass.tproj/chpass.1
@@ -0,0 +1,315 @@
+.\" Copyright (c) 1988, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" @(#)chpass.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD: src/usr.bin/chpass/chpass.1,v 1.38.2.1 2005/09/24 01:59:39 keramida Exp $
+.\"
+.Dd December 30, 1993
+.Dt CHPASS 1
+.Os
+.Sh NAME
+.Nm chpass ,
+.Nm chfn ,
+.Nm chsh
+.\".Nm ypchpass ,
+.\".Nm ypchfn ,
+.\".Nm ypchsh
+.Nd add or change user database information
+.Sh SYNOPSIS
+.Nm
+.\".Op Fl a Ar list
+.\".Op Fl p Ar encpass
+.\".Op Fl e Ar expiretime
+.Op Fl l Ar location
+.Op Fl u Ar authname
+.Op Fl s Ar newshell
+.Op user
+.Sh DESCRIPTION
+The
+.Nm
+utility
+allows editing of the user database information associated
+with
+.Ar user
+or, by default, the current user.
+.Pp
+The
+.Nm
+utility
+.Em cannot
+change the user's password on Open Directory
+systems. Use the
+.Xr passwd 1
+utility instead.
+.Pp
+The
+.Nm chfn ,
+and
+.Nm chsh
+.\".Nm ypchpass ,
+.\".Nm ypchfn
+.\"and
+.\".Nm ypchsh
+utilities behave identically to
+.Nm .
+(There is only one program.)
+.Pp
+The information is formatted and supplied to an editor for changes.
+.Pp
+Only the information that the user is allowed to change is displayed.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.\".It Fl a
+.\"The super-user is allowed to directly supply a user database
+.\"entry, in the format specified by
+.\".Xr passwd 5 ,
+.\"as an argument.
+.\"This argument must be a colon
+.\".Pq Dq \&:
+.\"separated list of all the
+.\"user database fields, although they may be empty.
+.\".It Fl p
+.\"The super-user is allowed to directly supply an encrypted password field,
+.\"in the format used by
+.\".Xr crypt 3 ,
+.\"as an argument.
+.\".It Fl e Ar expiretime
+.\"Change the account expire time.
+.\"This option is used to set the expire time
+.\"from a script as if it were done in the interactive editor.
+.It Fl l Ar location
+If not specified,
+.Nm
+will perform a search for the user record on all available
+Open Directory nodes.
+When specified,
+.Nm
+will edit the user record on the directory node at the given
+.Ar location .
+.It Fl u Ar authname
+The user name to use when authenticating to the directory node containing the
+user.
+.It Fl s Ar newshell
+Attempt to change the user's shell to
+.Ar newshell .
+.El
+.Pp
+Possible display items are as follows:
+.Pp
+.Bl -tag -width "Other Information:" -compact -offset indent
+.It Login:
+user's login name
+.\".It Password:
+.\"user's encrypted password
+.It Uid:
+user's login
+.It Gid:
+user's login group
+.It Generated uid:
+user's UUID
+.\".It Class:
+.\"user's general classification
+.\".It Change:
+.\"password change time
+.\".It Expire:
+.\"account expiration time
+.It Full Name:
+user's real name
+.It Office Location:
+user's office location
+.It Office Phone:
+user's office phone
+.It Home Phone:
+user's home phone
+.\".It Other Information:
+.\"any locally defined parameters for user
+.It Home Directory:
+user's home directory
+.It Shell:
+user's login shell
+.Pp
+.\".It NOTE(1) -
+.\"In the actual master.passwd file, these fields are comma-delimited
+.\"fields embedded in the FullName field.
+.El
+.Pp
+The
+.Ar login
+field is the user name used to access the computer account.
+.\".Pp
+.\"The
+.\".Ar password
+.\"field contains the encrypted form of the user's password.
+.Pp
+The
+.Ar uid
+field is the number associated with the
+.Ar login
+field.
+Both of these fields should be unique across the system (and often
+across a group of systems) as they control file access.
+.Pp
+While it is possible to have multiple entries with identical login names
+and/or identical user id's, it is usually a mistake to do so.
+Routines
+that manipulate these files will often return only one of the multiple
+entries, and that one by random selection.
+.Pp
+The
+.Ar group
+field is the group that the user will be placed in at login.
+Since
+.Bx
+supports multiple groups (see
+.Xr groups 1 )
+this field currently has little special meaning.
+This field may be filled in with either a number or a group name (see
+.Xr group 5 ) .
+.Pp
+The
+.Ar generated uid
+field is the globally unique identifier (UUID) for the user.
+.\".Pp
+.\"The
+.\".Ar class
+.\"field references class descriptions in
+.\".Pa /etc/login.conf
+.\"and is typically used to initialize the user's system resource limits
+.\"when they login.
+.\".Pp
+.\"The
+.\".Ar change
+.\"field is the date by which the password must be changed.
+.\".Pp
+.\"The
+.\".Ar expire
+.\"field is the date on which the account expires.
+.\".Pp
+.\"Both the
+.\".Ar change
+.\"and
+.\".Ar expire
+.\"fields should be entered in the form
+.\".Dq month day year
+.\"where
+.\".Ar month
+.\"is the month name (the first three characters are sufficient),
+.\".Ar day
+.\"is the day of the month, and
+.\".Ar year
+.\"is the year.
+.\".Pp
+.\"Five fields are available for storing the user's
+.\".Ar full name , office location ,
+.\".Ar work
+.\"and
+.\".Ar home telephone
+.\"numbers and finally
+.\".Ar other information
+.\"which is a single comma delimited string to represent any additional
+.\"gcos fields (typically used for site specific user information).
+.\"Note that
+.\".Xr finger 1
+.\"will display the office location and office phone together under the
+.\"heading
+.\".Ar Office: .
+The
+.Ar full name
+field contains the full name of the user.
+.Pp
+The user's
+.Ar home directory
+is the full
+.Ux
+path name where the user
+will be placed at login.
+.Pp
+The
+.Ar shell
+field is the command interpreter the user prefers.
+If the
+.Ar shell
+field is empty, the Bourne shell,
+.Pa /bin/sh ,
+is assumed.
+When altering a login shell, and not the super-user, the user
+may not change from a non-standard shell or to a non-standard
+shell.
+Non-standard is defined as a shell not found in
+.Pa /etc/shells .
+.Pp
+The
+.Ar picture
+field is the path to a picture to be displayed for the user.
+.Sh OPEN DIRECTORY
+User database entries are under the control of
+.Xr DirectoryService 8
+and may be physically located in many different places,
+including the local Directory Service node,
+and remote LDAP servers.
+This version of
+.Nm
+uses Open Directory to change user database information.
+It does not interact with the historic flat file
+database
+.Pa /etc/master.passwd
+.
+.Sh ENVIRONMENT
+The
+.Xr vi 1
+editor will be used unless the environment variable
+.Ev EDITOR
+is set to
+an alternate editor.
+When the editor terminates, the information is re-read and used to
+update the user database itself.
+Only the user, or the super-user, may edit the information associated
+with the user.
+.Sh FILES
+.Bl -tag -width /etc/chpass.XXXXXX -compact
+.It Pa /etc/chpass.XXXXXX
+temporary copy of the data to edit
+.It Pa /etc/shells
+the list of approved shells
+.El
+.Sh SEE ALSO
+.\".Xr finger 1 ,
+.Xr login 1 ,
+.Xr passwd 1 ,
+.Xr getusershell 3 ,
+.Xr passwd 5
+.Rs
+.%A Robert Morris
+.%A Ken Thompson
+.%T "UNIX Password security"
+.Re
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.3 Reno .
diff --git a/system_cmds/chpass.tproj/chpass.c b/system_cmds/chpass.tproj/chpass.c
new file mode 100644
index 0000000..6b265c0
--- /dev/null
+++ b/system_cmds/chpass.tproj/chpass.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/chpass.c,v 1.27.8.1 2006/09/29 06:13:20 marck Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef YP
+#include <ypclnt.h>
+#endif
+
+#ifndef OPEN_DIRECTORY
+#include <pw_scan.h>
+#include <libutil.h>
+#endif
+
+#include "chpass.h"
+
+int master_mode;
+
+#ifdef OPEN_DIRECTORY
+#include "open_directory.h"
+char *progname = NULL;
+CFStringRef DSPath = NULL;
+#endif /* OPEN_DIRECTORY */
+
+static void baduser(void);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op;
+#ifndef OPEN_DIRECTORY
+ struct passwd lpw, *old_pw, *pw;
+ int ch, pfd, tfd;
+ const char *password;
+#else
+ struct passwd *old_pw, *pw;
+ int ch, tfd;
+ char tfn[MAXPATHLEN];
+ char *tmpdir;
+#endif
+ char *arg = NULL;
+ uid_t uid;
+#ifdef YP
+ struct ypclnt *ypclnt;
+ const char *yp_domain = NULL, *yp_host = NULL;
+#endif
+#ifdef OPEN_DIRECTORY
+ CFStringRef username = NULL;
+ CFStringRef authname = NULL;
+ CFStringRef location = NULL;
+
+ progname = strrchr(argv[0], '/');
+ if (progname) progname++;
+ else progname = argv[0];
+#endif /* OPEN_DIRECTORY */
+
+ pw = old_pw = NULL;
+ op = EDITENTRY;
+#ifdef OPEN_DIRECTORY
+ while ((ch = getopt(argc, argv, "a:s:l:u:")) != -1)
+#else /* OPEN_DIRECTORY */
+#ifdef YP
+ while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1)
+#endif
+#endif /* OPEN_DIRECTORY */
+ switch (ch) {
+ case 'a':
+ op = LOADENTRY;
+ arg = optarg;
+ break;
+ case 's':
+ op = NEWSH;
+ arg = optarg;
+ break;
+#ifndef OPEN_DIRECTORY
+ case 'p':
+ op = NEWPW;
+ arg = optarg;
+ break;
+ case 'e':
+ op = NEWEXP;
+ arg = optarg;
+ break;
+#ifdef YP
+ case 'd':
+ yp_domain = optarg;
+ break;
+ case 'h':
+ yp_host = optarg;
+ break;
+ case 'l':
+ case 'o':
+ case 'y':
+ /* compatibility */
+ break;
+#endif
+#else /* OPEN_DIRECTORY */
+ case 'l':
+ location = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ break;
+ case 'u':
+ authname = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8);
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1)
+ usage();
+
+ uid = getuid();
+
+ if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) {
+ if (argc == 0) {
+ if ((pw = getpwuid(uid)) == NULL)
+ errx(1, "unknown user: uid %lu",
+ (unsigned long)uid);
+ } else {
+ if ((pw = getpwnam(*argv)) == NULL)
+ errx(1, "unknown user: %s", *argv);
+#ifndef OPEN_DIRECTORY
+ if (uid != 0 && uid != pw->pw_uid)
+ baduser();
+#endif
+ }
+
+#ifndef OPEN_DIRECTORY
+ /* Make a copy for later verification */
+ if ((pw = pw_dup(pw)) == NULL ||
+ (old_pw = pw_dup(pw)) == NULL)
+ err(1, "pw_dup");
+#endif
+ }
+
+#if OPEN_DIRECTORY
+ master_mode = (uid == 0);
+
+ /*
+ * Find the user record and copy its details.
+ */
+ username = CFStringCreateWithCString(NULL, pw->pw_name, kCFStringEncodingUTF8);
+
+ if (strcmp(progname, "chsh") == 0 || op == NEWSH) {
+ cfprintf(stderr, "Changing shell for %@.\n", username);
+ } else if (strcmp(progname, "chfn") == 0) {
+ cfprintf(stderr, "Changing finger information for %@.\n", username);
+ } else if (strcmp(progname, "chpass") == 0) {
+ cfprintf(stderr, "Changing account information for %@.\n", username);
+ }
+
+ /*
+ * odGetUser updates DSPath global variable, performs authentication
+ * if necessary, and extracts the attributes.
+ */
+ CFDictionaryRef attrs_orig = NULL;
+ CFDictionaryRef attrs = NULL;
+ ODRecordRef rec = odGetUser(location, authname, username, &attrs_orig);
+
+ if (!rec || !attrs_orig) exit(1);
+#endif /* OPEN_DIRECTORY */
+
+#ifdef YP
+ if (pw != NULL && (pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) {
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
+ master_mode = (ypclnt != NULL &&
+ ypclnt_connect(ypclnt) != -1 &&
+ ypclnt_havepasswdd(ypclnt) == 1);
+ ypclnt_free(ypclnt);
+ } else
+#endif
+ master_mode = (uid == 0);
+
+ if (op == NEWSH) {
+ /* protect p_shell -- it thinks NULL is /bin/sh */
+ if (!arg[0])
+ usage();
+ if (p_shell(arg, pw, (ENTRY *)NULL) == -1)
+ exit(1);
+#ifdef OPEN_DIRECTORY
+ else {
+ ENTRY* ep;
+
+ setrestricted(attrs_orig);
+
+ for (ep = list; ep->prompt; ep++) {
+ if (strncasecmp(ep->prompt, "shell", ep->len) == 0) {
+ if (!ep->restricted) {
+ CFStringRef shell = CFStringCreateWithCString(NULL, arg, kCFStringEncodingUTF8);
+ if (shell) {
+ attrs = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (attrs) CFDictionarySetValue((CFMutableDictionaryRef)attrs, kODAttributeTypeUserShell, shell);
+ CFRelease(shell);
+ }
+ } else {
+ warnx("shell is restricted");
+ exit(1);
+ }
+ }
+ }
+ }
+#endif
+ }
+
+#ifndef OPEN_DIRECTORY
+ if (op == NEWEXP) {
+ if (uid) /* only root can change expire */
+ baduser();
+ if (p_expire(arg, pw, (ENTRY *)NULL) == -1)
+ exit(1);
+ }
+#endif
+
+ if (op == LOADENTRY) {
+ if (uid)
+ baduser();
+#ifdef OPEN_DIRECTORY
+ warnx("-a is not supported for Open Directory.");
+ exit(1);
+#else
+ pw = &lpw;
+ old_pw = NULL;
+ if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER))
+ exit(1);
+#endif /* OPEN_DIRECTORY */
+ }
+
+#ifndef OPEN_DIRECTORY
+ if (op == NEWPW) {
+ if (uid)
+ baduser();
+
+ if (strchr(arg, ':'))
+ errx(1, "invalid format for password");
+ pw->pw_passwd = arg;
+ }
+#endif /* OPEN_DIRECTORY */
+
+ if (op == EDITENTRY) {
+#ifdef OPEN_DIRECTORY
+ setrestricted(attrs_orig);
+ tmpdir = getenv("TMPDIR");
+ if (!tmpdir)
+ tmpdir = P_tmpdir; // defined in the system headers, defaults to /tmp
+ snprintf(tfn, sizeof(tfn), "%s/%s.XXXXXX", tmpdir, progname);
+ if ((tfd = mkstemp(tfn)) == -1)
+ err(1, "%s", tfn);
+ attrs = (CFMutableDictionaryRef)edit(tfn, attrs_orig);
+ (void)unlink(tfn);
+#else
+ /*
+ * We don't really need pw_*() here, but pw_edit() (used
+ * by edit()) is just too useful...
+ */
+ if (pw_init(NULL, NULL))
+ err(1, "pw_init()");
+ if ((tfd = pw_tmp(-1)) == -1) {
+ pw_fini();
+ err(1, "pw_tmp()");
+ }
+ free(pw);
+ pw = edit(pw_tempname(), old_pw);
+ pw_fini();
+ if (pw == NULL)
+ err(1, "edit()");
+ /*
+ * pw_equal does not check for crypted passwords, so we
+ * should do it explicitly
+ */
+ if (pw_equal(old_pw, pw) &&
+ strcmp(old_pw->pw_passwd, pw->pw_passwd) == 0)
+ errx(0, "user information unchanged");
+#endif /* OPEN_DIRECTORY */
+ }
+
+#ifndef OPEN_DIRECTORY
+ if (old_pw && !master_mode) {
+ password = getpass("Password: ");
+ if (strcmp(crypt(password, old_pw->pw_passwd),
+ old_pw->pw_passwd) != 0)
+ baduser();
+ } else {
+ password = "";
+ }
+#endif
+
+#ifdef OPEN_DIRECTORY
+ odUpdateUser(rec, attrs_orig, attrs);
+
+ if (rec) CFRelease(rec);
+
+ exit(0);
+ return 0;
+#else /* OPEN_DIRECTORY */
+ exit(0);
+ if (old_pw != NULL)
+ pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE);
+ switch (pw->pw_fields & _PWF_SOURCE) {
+#ifdef YP
+ case _PWF_NIS:
+ ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host);
+ if (ypclnt == NULL ||
+ ypclnt_connect(ypclnt) == -1 ||
+ ypclnt_passwd(ypclnt, pw, password) == -1) {
+ warnx("%s", ypclnt->error);
+ ypclnt_free(ypclnt);
+ exit(1);
+ }
+ ypclnt_free(ypclnt);
+ errx(0, "NIS user information updated");
+#endif /* YP */
+ case 0:
+ case _PWF_FILES:
+ if (pw_init(NULL, NULL))
+ err(1, "pw_init()");
+ if ((pfd = pw_lock()) == -1) {
+ pw_fini();
+ err(1, "pw_lock()");
+ }
+ if ((tfd = pw_tmp(-1)) == -1) {
+ pw_fini();
+ err(1, "pw_tmp()");
+ }
+ if (pw_copy(pfd, tfd, pw, old_pw) == -1) {
+ pw_fini();
+ err(1, "pw_copy");
+ }
+ if (pw_mkdb(pw->pw_name) == -1) {
+ pw_fini();
+ err(1, "pw_mkdb()");
+ }
+ pw_fini();
+ errx(0, "user information updated");
+ break;
+ default:
+ errx(1, "unsupported passwd source");
+ }
+#endif /* OPEN_DIRECTORY */
+}
+
+static void
+baduser(void)
+{
+ errx(1, "%s", strerror(EACCES));
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: chpass%s %s [user]\n",
+#ifdef OPEN_DIRECTORY
+ "",
+ "[-l location] [-u authname] [-s shell]");
+#else /* OPEN_DIRECTORY */
+#ifdef YP
+ " [-d domain] [-h host]",
+#else
+ "",
+#endif
+ "[-a list] [-p encpass] [-s shell] [-e mmm dd yy]");
+#endif /* OPEN_DIRECTORY */
+ exit(1);
+}
diff --git a/system_cmds/chpass.tproj/chpass.h b/system_cmds/chpass.tproj/chpass.h
new file mode 100644
index 0000000..739601f
--- /dev/null
+++ b/system_cmds/chpass.tproj/chpass.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)chpass.h 8.4 (Berkeley) 4/2/94
+ * $FreeBSD: src/usr.bin/chpass/chpass.h,v 1.7 2004/01/18 21:46:39 charnier Exp $
+ */
+
+#ifdef OPEN_DIRECTORY
+#include "open_directory.h"
+
+extern char* progname;
+extern CFStringRef DSPath;
+#endif /* OPEN_DIRECTORY */
+
+struct passwd;
+
+typedef struct _entry {
+ const char *prompt;
+#ifdef OPEN_DIRECTORY
+ void (*display)();
+#endif
+ int (*func)(char *, struct passwd *, struct _entry *);
+ int restricted;
+ size_t len;
+#if OPEN_DIRECTORY
+ char *except;
+ const CFStringRef *attrName;
+#else /* OPEN_DIRECTORY */
+ char *except, *save;
+#endif /* OPEN_DIRECTORY */
+} ENTRY;
+
+/* Field numbers. */
+#define E_BPHONE 8
+#define E_HPHONE 9
+#define E_LOCATE 10
+#define E_NAME 7
+#define E_OTHER 11
+#define E_SHELL 13
+
+extern ENTRY list[];
+extern int master_mode;
+
+#ifdef OPEN_DIRECTORY
+/* edit.c */
+void display_time(CFDictionaryRef, CFStringRef, const char*, FILE *);
+void display_string(CFDictionaryRef, CFStringRef, const char*, FILE *);
+CFDictionaryRef edit(const char *tfn, CFDictionaryRef pw);
+
+/* util.c */
+int cfprintf(FILE* file, const char* format, ...);
+int editfile(const char* tfn);
+#endif /* OPEN_DIRECTORY */
+
+int atot(char *, time_t *);
+#ifndef OPEN_DIRECTORY
+struct passwd *edit(const char *, struct passwd *);
+#endif /* OPEN_DIRECTORY */
+int ok_shell(char *);
+char *dup_shell(char *);
+int p_change(char *, struct passwd *, ENTRY *);
+int p_class(char *, struct passwd *, ENTRY *);
+int p_expire(char *, struct passwd *, ENTRY *);
+int p_gecos(char *, struct passwd *, ENTRY *);
+int p_gid(char *, struct passwd *, ENTRY *);
+int p_hdir(char *, struct passwd *, ENTRY *);
+int p_login(char *, struct passwd *, ENTRY *);
+int p_passwd(char *, struct passwd *, ENTRY *);
+int p_shell(char *, struct passwd *, ENTRY *);
+int p_uid(char *, struct passwd *, ENTRY *);
+#ifdef OPEN_DIRECTORY
+int p_uuid(char *, struct passwd *, ENTRY *);
+#endif /* OPEN_DIRECTORY */
+char *ttoa(time_t);
diff --git a/system_cmds/chpass.tproj/edit.c b/system_cmds/chpass.tproj/edit.c
new file mode 100644
index 0000000..7c87050
--- /dev/null
+++ b/system_cmds/chpass.tproj/edit.c
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)edit.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/edit.c,v 1.23 2003/04/09 18:18:42 des Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef OPEN_DIRECTORY
+#include <pw_scan.h>
+#include <libutil.h>
+#endif
+
+#include "chpass.h"
+
+#ifdef OPEN_DIRECTORY
+static int display(const char *tfn, CFDictionaryRef attrs);
+static CFDictionaryRef verify(const char *tfn, CFDictionaryRef attrs);
+#else
+static int display(const char *tfn, struct passwd *pw);
+static struct passwd *verify(const char *tfn, struct passwd *pw);
+#endif
+
+#ifdef OPEN_DIRECTORY
+CFDictionaryRef
+edit(const char *tfn, CFDictionaryRef pw)
+#else
+struct passwd *
+edit(const char *tfn, struct passwd *pw)
+#endif
+{
+#ifdef OPEN_DIRECTORY
+ CFDictionaryRef npw;
+#else
+ struct passwd *npw;
+#endif
+ char *line;
+ size_t len;
+
+ if (display(tfn, pw) == -1)
+ return (NULL);
+ for (;;) {
+#ifdef OPEN_DIRECTORY
+ switch (editfile(tfn)) {
+#else
+ switch (pw_edit(1)) {
+#endif
+ case -1:
+ return (NULL);
+ case 0:
+#ifdef OPEN_DIRECTORY
+ return (NULL);
+#else
+ return (pw_dup(pw));
+#endif
+ default:
+ break;
+ }
+ if ((npw = verify(tfn, pw)) != NULL)
+ return (npw);
+#ifndef OPEN_DIRECTORY
+ free(npw);
+#endif
+ printf("re-edit the password file? ");
+ fflush(stdout);
+ if ((line = fgetln(stdin, &len)) == NULL) {
+ warn("fgetln()");
+ return (NULL);
+ }
+ if (len > 0 && (*line == 'N' || *line == 'n'))
+ return (NULL);
+ }
+}
+
+/*
+ * display --
+ * print out the file for the user to edit; strange side-effect:
+ * set conditional flag if the user gets to edit the shell.
+ */
+#if OPEN_DIRECTORY
+static int
+display(const char *tfn, CFDictionaryRef attrs)
+#else
+static int
+display(const char *tfn, struct passwd *pw)
+#endif
+{
+ FILE *fp;
+#ifndef OPEN_DIRECTORY
+ char *bp, *gecos, *p;
+#endif
+
+ if ((fp = fopen(tfn, "w")) == NULL) {
+ warn("%s", tfn);
+ return (-1);
+ }
+
+#ifdef OPEN_DIRECTORY
+ CFArrayRef values = CFDictionaryGetValue(attrs, kODAttributeTypeRecordName);
+ CFStringRef username = (values && CFArrayGetCount(values)) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL;
+
+ (void)cfprintf(fp,
+ "# Changing user information for %@.\n"
+ "# Use \"passwd\" to change the password.\n"
+ "##\n"
+ "# Open Directory%s%@\n"
+ "##\n",
+ username,
+ DSPath ? ": " : "",
+ DSPath ? DSPath : CFSTR(""));
+
+ int ndisplayed = 0;
+ ENTRY* ep;
+ for (ep = list; ep->prompt; ep++)
+ if (!ep->restricted) {
+ ep->display(attrs, *ep->attrName, ep->prompt, fp);
+ ndisplayed++;
+ }
+ if(!ndisplayed) {
+ (void)fprintf(fp, "###################################\n");
+ (void)fprintf(fp, "# No fields are available to change\n");
+ (void)fprintf(fp, "###################################\n");
+ }
+#else /* OPEN_DIRECTORY */
+ (void)fprintf(fp,
+ "#Changing user information for %s.\n", pw->pw_name);
+ if (master_mode) {
+ (void)fprintf(fp, "Login: %s\n", pw->pw_name);
+ (void)fprintf(fp, "Password: %s\n", pw->pw_passwd);
+ (void)fprintf(fp, "Uid [#]: %lu\n", (unsigned long)pw->pw_uid);
+ (void)fprintf(fp, "Gid [# or name]: %lu\n",
+ (unsigned long)pw->pw_gid);
+ (void)fprintf(fp, "Change [month day year]: %s\n",
+ ttoa(pw->pw_change));
+ (void)fprintf(fp, "Expire [month day year]: %s\n",
+ ttoa(pw->pw_expire));
+ (void)fprintf(fp, "Class: %s\n", pw->pw_class);
+ (void)fprintf(fp, "Home directory: %s\n", pw->pw_dir);
+ (void)fprintf(fp, "Shell: %s\n",
+ *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
+ }
+ /* Only admin can change "restricted" shells. */
+#if 0
+ else if (ok_shell(pw->pw_shell))
+ /*
+ * Make shell a restricted field. Ugly with a
+ * necklace, but there's not much else to do.
+ */
+#else
+ else if ((!list[E_SHELL].restricted && ok_shell(pw->pw_shell)) ||
+ master_mode)
+ /*
+ * If change not restrict (table.c) and standard shell
+ * OR if root, then allow editing of shell.
+ */
+#endif
+ (void)fprintf(fp, "Shell: %s\n",
+ *pw->pw_shell ? pw->pw_shell : _PATH_BSHELL);
+ else
+ list[E_SHELL].restricted = 1;
+
+ if ((bp = gecos = strdup(pw->pw_gecos)) == NULL) {
+ warn(NULL);
+ fclose(fp);
+ return (-1);
+ }
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_NAME].save = p;
+ if (!list[E_NAME].restricted || master_mode)
+ (void)fprintf(fp, "Full Name: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_LOCATE].save = p;
+ if (!list[E_LOCATE].restricted || master_mode)
+ (void)fprintf(fp, "Office Location: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_BPHONE].save = p;
+ if (!list[E_BPHONE].restricted || master_mode)
+ (void)fprintf(fp, "Office Phone: %s\n", p);
+
+ p = strsep(&bp, ",");
+ p = strdup(p ? p : "");
+ list[E_HPHONE].save = p;
+ if (!list[E_HPHONE].restricted || master_mode)
+ (void)fprintf(fp, "Home Phone: %s\n", p);
+
+ bp = strdup(bp ? bp : "");
+ list[E_OTHER].save = bp;
+ if (!list[E_OTHER].restricted || master_mode)
+ (void)fprintf(fp, "Other information: %s\n", bp);
+
+ free(gecos);
+#endif /* OPEN_DIRECTORY */
+
+ (void)fchown(fileno(fp), getuid(), getgid());
+ (void)fclose(fp);
+ return (0);
+}
+
+#ifdef OPEN_DIRECTORY
+static CFDictionaryRef
+verify(const char* tfn, CFDictionaryRef pw)
+#else
+static struct passwd *
+verify(const char *tfn, struct passwd *pw)
+#endif
+{
+#ifdef OPEN_DIRECTORY
+ CFMutableDictionaryRef npw;
+#else
+ struct passwd *npw;
+#endif
+ ENTRY *ep;
+ char *buf, *p, *val;
+ struct stat sb;
+ FILE *fp;
+ int line;
+ size_t len;
+
+#ifdef OPEN_DIRECTORY
+ if ((npw = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)) == NULL)
+ return (NULL);
+#else
+ if ((pw = pw_dup(pw)) == NULL)
+ return (NULL);
+#endif
+ if ((fp = fopen(tfn, "r")) == NULL ||
+ fstat(fileno(fp), &sb) == -1) {
+ warn("%s", tfn);
+#ifndef OPEN_DIRECTORY
+ free(pw);
+#endif
+ return (NULL);
+ }
+ if (sb.st_size == 0) {
+ warnx("corrupted temporary file");
+ fclose(fp);
+#ifndef OPEN_DIRECTORY
+ free(pw);
+#endif
+ return (NULL);
+ }
+ val = NULL;
+ for (line = 1; (buf = fgetln(fp, &len)) != NULL; ++line) {
+ if (*buf == '\0' || *buf == '#')
+ continue;
+ while (len > 0 && isspace(buf[len - 1]))
+ --len;
+ for (ep = list;; ++ep) {
+ if (!ep->prompt) {
+ warnx("%s: unrecognized field on line %d",
+ tfn, line);
+ goto bad;
+ }
+ if (ep->len > len)
+ continue;
+ if (strncasecmp(buf, ep->prompt, ep->len) != 0)
+ continue;
+ if (ep->restricted && !master_mode) {
+ warnx("%s: you may not change the %s field",
+ tfn, ep->prompt);
+ goto bad;
+ }
+ for (p = buf; p < buf + len && *p != ':'; ++p)
+ /* nothing */ ;
+ if (*p != ':') {
+ warnx("%s: line %d corrupted", tfn, line);
+ goto bad;
+ }
+ while (++p < buf + len && isspace(*p))
+ /* nothing */ ;
+ free(val);
+ asprintf(&val, "%.*s", (int)(buf + len - p), p);
+ if (val == NULL)
+ goto bad;
+ if (ep->except && strpbrk(val, ep->except)) {
+ warnx("%s: invalid character in \"%s\" field '%s'",
+ tfn, ep->prompt, val);
+ goto bad;
+ }
+#ifdef OPEN_DIRECTORY
+ if ((ep->func)(val, NULL, NULL))
+ goto bad;
+ {
+ CFStringRef str = CFStringCreateWithCString(NULL, val, kCFStringEncodingUTF8);
+ if (str) {
+ CFDictionarySetValue(npw, *ep->attrName, str);
+ CFRelease(str);
+ }
+ }
+#else
+ if ((ep->func)(val, pw, ep))
+ goto bad;
+#endif
+ break;
+ }
+ }
+ free(val);
+ fclose(fp);
+
+#ifndef OPEN_DIRECTORY
+ /* Build the gecos field. */
+ len = asprintf(&p, "%s,%s,%s,%s,%s", list[E_NAME].save,
+ list[E_LOCATE].save, list[E_BPHONE].save,
+ list[E_HPHONE].save, list[E_OTHER].save);
+ if (p == NULL) {
+ warn("asprintf()");
+ free(pw);
+ return (NULL);
+ }
+ while (len > 0 && p[len - 1] == ',')
+ p[--len] = '\0';
+ pw->pw_gecos = p;
+ buf = pw_make(pw);
+ free(pw);
+ free(p);
+ if (buf == NULL) {
+ warn("pw_make()");
+ return (NULL);
+ }
+ npw = pw_scan(buf, PWSCAN_WARN|PWSCAN_MASTER);
+#endif /* !OPEN_DIRECTORY */
+ free(buf);
+ return (npw);
+bad:
+#ifndef OPEN_DIRECTORY
+ free(pw);
+#endif
+ free(val);
+ fclose(fp);
+ return (NULL);
+}
diff --git a/system_cmds/chpass.tproj/field.c b/system_cmds/chpass.tproj/field.c
new file mode 100644
index 0000000..5ae326a
--- /dev/null
+++ b/system_cmds/chpass.tproj/field.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1988, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)field.c 8.4 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/field.c,v 1.9 2004/01/18 21:46:39 charnier Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <paths.h>
+#include <pwd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "chpass.h"
+
+/* ARGSUSED */
+int
+p_login(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!*p) {
+ warnx("empty login field");
+ return (-1);
+ }
+ if (*p == '-') {
+ warnx("login names may not begin with a hyphen");
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ if (!(pw->pw_name = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+ if (strchr(p, '.'))
+ warnx("\'.\' is dangerous in a login name");
+ for (; *p; ++p)
+ if (isupper(*p)) {
+ warnx("upper-case letters are dangerous in a login name");
+ break;
+ }
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_passwd(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+#ifndef OPEN_DIRECTORY
+ if (!(pw->pw_passwd = strdup(p))) {
+ warnx("can't save password entry");
+ return (-1);
+ }
+#endif
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_uid(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ uid_t id;
+ char *np;
+
+ if (!*p) {
+ warnx("empty uid field");
+ return (-1);
+ }
+ if (!isdigit(*p)) {
+ warnx("illegal uid");
+ return (-1);
+ }
+ errno = 0;
+ id = (uid_t)strtoul(p, &np, 10);
+ if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) {
+ warnx("illegal uid");
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ pw->pw_uid = id;
+#endif
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_gid(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ struct group *gr;
+ gid_t id;
+ char *np;
+
+ if (!*p) {
+ warnx("empty gid field");
+ return (-1);
+ }
+ if (!isdigit(*p)) {
+ if (!(gr = getgrnam(p))) {
+ warnx("unknown group %s", p);
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ pw->pw_gid = gr->gr_gid;
+#endif
+ return (0);
+ }
+ errno = 0;
+ id = (gid_t)strtoul(p, &np, 10);
+ if (*np || (id == (uid_t)ULONG_MAX && errno == ERANGE)) {
+ warnx("illegal gid");
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ pw->pw_gid = id;
+#endif
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_class(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+#ifndef OPEN_DIRECTORY
+ if (!(pw->pw_class = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_change(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+#ifndef OPEN_DIRECTORY
+ if (!atot(p, &pw->pw_change))
+ return (0);
+ warnx("illegal date for change field");
+#endif
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+p_expire(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+#ifndef OPEN_DIRECTORY
+ if (!atot(p, &pw->pw_expire))
+ return (0);
+ warnx("illegal date for expire field");
+#endif
+ return (-1);
+}
+
+/* ARGSUSED */
+int
+p_gecos(char *p, struct passwd *pw __unused, ENTRY *ep)
+{
+#ifndef OPEN_DIRECTORY
+ if (!(ep->save = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+ return (0);
+}
+
+/* ARGSUSED */
+int
+p_hdir(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ if (!*p) {
+ warnx("empty home directory field");
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ if (!(pw->pw_dir = strdup(p))) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+ return (0);
+}
+
+
+/* ARGSUSED */
+int
+p_shell(char *p, struct passwd *pw, ENTRY *ep __unused)
+{
+ struct stat sbuf;
+#ifdef OPEN_DIRECTORY
+ struct passwd lpw;
+ pw = &lpw;
+ memset(pw, 0, sizeof(lpw));
+ pw->pw_shell = p;
+#endif
+
+#ifndef OPEN_DIRECTORY
+ if (!*p) {
+ pw->pw_shell = strdup(_PATH_BSHELL);
+ return (0);
+ }
+ /* only admin can change from or to "restricted" shells */
+ if (!master_mode && pw->pw_shell && !ok_shell(pw->pw_shell)) {
+ warnx("%s: current shell non-standard", pw->pw_shell);
+ return (-1);
+ }
+#endif /* !OPEN_DIRECTORY */
+ if (!ok_shell(p)) {
+ if (!master_mode) {
+ warnx("%s: non-standard shell", p);
+ return (-1);
+ }
+#ifndef OPEN_DIRECTORY
+ pw->pw_shell = strdup(p);
+#endif
+ }
+#ifndef OPEN_DIRECTORY
+ else
+ pw->pw_shell = dup_shell(p);
+ if (!pw->pw_shell) {
+ warnx("can't save entry");
+ return (-1);
+ }
+#endif
+ if (stat(pw->pw_shell, &sbuf) < 0) {
+ if (errno == ENOENT)
+ warnx("WARNING: shell '%s' does not exist",
+ pw->pw_shell);
+ else
+ warn("WARNING: can't stat shell '%s'", pw->pw_shell);
+ return (0);
+ }
+ if (!S_ISREG(sbuf.st_mode)) {
+ warnx("WARNING: shell '%s' is not a regular file",
+ pw->pw_shell);
+ return (0);
+ }
+ if ((sbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) == 0) {
+ warnx("WARNING: shell '%s' is not executable", pw->pw_shell);
+ return (0);
+ }
+ return (0);
+}
+
+#ifdef OPEN_DIRECTORY
+#include <uuid/uuid.h>
+/* ARGSUSED */
+int
+p_uuid(char *p, struct passwd *pw __unused, ENTRY *ep)
+{
+ uuid_t uu;
+ if (uuid_parse(p, uu) != 0) {
+ warnx("invalid UUID");
+ return (-1);
+ }
+ return (0);
+}
+
+void
+display_string(CFDictionaryRef attrs, CFStringRef attrName, const char* prompt, FILE *fp)
+{
+ CFTypeRef value = CFSTR("");
+ CFArrayRef values = CFDictionaryGetValue(attrs, attrName);
+ if (values) {
+ value = CFArrayGetCount(values) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL;
+ if (value && CFGetTypeID(value) != CFStringGetTypeID()) value = NULL;
+ }
+ cfprintf(fp, "%s: %@\n", prompt, value);
+}
+#endif /* OPEN_DIRECTORY */
diff --git a/system_cmds/chpass.tproj/open_directory.c b/system_cmds/chpass.tproj/open_directory.c
new file mode 100644
index 0000000..5949eac
--- /dev/null
+++ b/system_cmds/chpass.tproj/open_directory.c
@@ -0,0 +1,205 @@
+#ifdef OPEN_DIRECTORY
+#include "open_directory.h"
+#include "chpass.h"
+#include <err.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <OpenDirectory/OpenDirectory.h>
+#include <OpenDirectory/OpenDirectoryPriv.h>
+
+/*---------------------------------------------------------------------------
+ * PUBLIC setrestricted - sets the restricted flag
+ *---------------------------------------------------------------------------*/
+void
+setrestricted(CFDictionaryRef attrs)
+{
+ const char* user_allowed[] = { "shell", "full name", "office location", "office phone", "home phone", "picture", NULL };
+ const char* root_restricted[] = { "password", "change", "expire", "class", NULL };
+ ENTRY* ep;
+ const char** pp;
+ int restrict_by_default = !master_mode;
+
+ // for ordinary users, everything is restricted except for the values
+ // expressly permitted above
+ // for root, everything is permitted except for the values expressly
+ // restricted above
+
+ for (ep = list; ep->prompt; ep++) {
+ ep->restricted = restrict_by_default;
+ pp = restrict_by_default ? user_allowed : root_restricted;
+ for (; *pp; pp++) {
+ if (strncasecmp(ep->prompt, *pp, ep->len) == 0) {
+ ep->restricted = !restrict_by_default;
+ break;
+ }
+ }
+
+ // If not root, then it is only permitted to change the shell
+ // when the original value is one of the approved shells.
+ // Otherwise, the assumption is that root has given this user
+ // a restricted shell which they must not change away from.
+ if (restrict_by_default && strcmp(ep->prompt, "shell") == 0) {
+ ep->restricted = 1;
+ CFArrayRef values = CFDictionaryGetValue(attrs, kODAttributeTypeUserShell);
+ CFTypeRef value = values && CFArrayGetCount(values) > 0 ? CFArrayGetValueAtIndex(values, 0) : NULL;
+ if (value && CFGetTypeID(value) == CFStringGetTypeID()) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value), kCFStringEncodingUTF8)+1;
+ char* shell = malloc(size);
+ if (CFStringGetCString(value, shell, size, kCFStringEncodingUTF8)) {
+ if (ok_shell(shell)) {
+ ep->restricted = 0;
+ }
+ }
+ }
+ }
+ }
+}
+
+static CFStringRef
+prompt_passwd(CFStringRef user)
+{
+ CFStringRef result = NULL;
+ CFStringRef prompt = CFStringCreateWithFormat(NULL, NULL, CFSTR("Password for %@: "), user);
+ size_t prompt_size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(prompt), kCFStringEncodingUTF8);
+ char* buf = malloc(prompt_size);
+ CFStringGetCString(prompt, buf, prompt_size, kCFStringEncodingUTF8);
+ char* pass = getpass(buf);
+ result = CFStringCreateWithCString(NULL, pass, kCFStringEncodingUTF8);
+ memset(pass, 0, strlen(pass));
+ free(buf);
+ CFRelease(prompt);
+ return result;
+}
+
+static void
+show_error(CFErrorRef error) {
+ if (error) {
+ CFStringRef desc = CFErrorCopyDescription(error);
+ if (desc) {
+ cfprintf(stderr, "%s: %@", progname, desc);
+ CFRelease(desc);
+ }
+ desc = CFErrorCopyFailureReason(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ desc = CFErrorCopyRecoverySuggestion(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ fprintf(stderr, "\n");
+ }
+}
+
+ODRecordRef
+odGetUser(CFStringRef location, CFStringRef authname, CFStringRef user, CFDictionaryRef* attrs)
+{
+ ODNodeRef node = NULL;
+ ODRecordRef rec = NULL;
+ CFErrorRef error = NULL;
+
+ assert(attrs);
+
+ /*
+ * Open the specified node, or perform a search.
+ * Copy the record and put the record's location into DSPath.
+ */
+ if (location) {
+ node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error);
+ } else {
+ node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error);
+ }
+ if (node) {
+ CFTypeRef vals[] = { kODAttributeTypeStandardOnly };
+ CFArrayRef desiredAttrs = CFArrayCreate(NULL, vals, 1, &kCFTypeArrayCallBacks);
+ rec = ODNodeCopyRecord(node, kODRecordTypeUsers, user, desiredAttrs, &error);
+ if (desiredAttrs) CFRelease(desiredAttrs);
+ CFRelease(node);
+ }
+ if (rec) {
+ *attrs = ODRecordCopyDetails(rec, NULL, &error);
+ if (*attrs) {
+ CFArrayRef values = CFDictionaryGetValue(*attrs, kODAttributeTypeMetaNodeLocation);
+ DSPath = (values && CFArrayGetCount(values) > 0) ? CFArrayGetValueAtIndex(values, 0) : NULL;
+ }
+
+ /*
+ * Prompt for a password if -u was specified,
+ * or if we are not root,
+ * or if we are updating something not on the
+ * local node.
+ */
+ if (authname || !master_mode ||
+ (DSPath && CFStringCompareWithOptions(DSPath, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo)) {
+
+ CFStringRef password = NULL;
+
+ if (!authname) authname = user;
+
+ password = prompt_passwd(authname);
+ if (!ODRecordSetNodeCredentials(rec, authname, password, &error)) {
+ CFRelease(rec);
+ rec = NULL;
+ }
+ }
+ }
+
+ if (error) show_error(error);
+ return rec;
+}
+
+void
+odUpdateUser(ODRecordRef rec, CFDictionaryRef attrs_orig, CFDictionaryRef attrs)
+{
+ CFErrorRef error = NULL;
+ int updated = 0;
+ ENTRY* ep;
+
+ for (ep = list; ep->prompt; ep++) {
+
+ // Nothing to update
+ if (!rec || !attrs_orig || !attrs) break;
+
+ // No need to update if entry is restricted
+ if (ep->restricted) continue;
+
+ CFArrayRef values_orig = CFDictionaryGetValue(attrs_orig, *ep->attrName);
+ CFTypeRef value_orig = values_orig && CFArrayGetCount(values_orig) ? CFArrayGetValueAtIndex(values_orig, 0) : NULL;
+ CFTypeRef value = CFDictionaryGetValue(attrs, *ep->attrName);
+
+ // No need to update if both values are the same
+ if (value == value_orig) continue;
+
+ // No need to update if strings are equal
+ if (value && value_orig) {
+ if (CFGetTypeID(value_orig) == CFStringGetTypeID() &&
+ CFStringCompare(value_orig, value, 0) == kCFCompareEqualTo) continue;
+ }
+
+ // No need to update if empty string replaces NULL
+ if (!value_orig && value) {
+ if (CFStringGetLength(value) == 0) continue;
+ }
+
+ // Needs update
+ if (value) {
+ // if new value is an empty string, send an empty dictionary which will delete the property.
+ CFIndex count = CFEqual(value, CFSTR("")) ? 0 : 1;
+ CFTypeRef vals[] = { value };
+ CFArrayRef values = CFArrayCreate(NULL, vals, count, &kCFTypeArrayCallBacks);
+ if (values && ODRecordSetValue(rec, *ep->attrName, values, &error)) {
+ updated = 1;
+ }
+ if (values) CFRelease(values);
+ if (error) show_error(error);
+ }
+ }
+
+ if (updated) {
+ updated = ODRecordSynchronize(rec, &error);
+ if (error) show_error(error);
+ }
+ if (!updated) {
+ fprintf(stderr, "%s: no changes made\n", progname);
+ }
+}
+#endif /* OPEN_DIRECTORY */
diff --git a/system_cmds/chpass.tproj/open_directory.h b/system_cmds/chpass.tproj/open_directory.h
new file mode 100644
index 0000000..e6011b7
--- /dev/null
+++ b/system_cmds/chpass.tproj/open_directory.h
@@ -0,0 +1,13 @@
+#ifndef _OPEN_DIRECTORY_H_
+#define _OPEN_DIRECTORY_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <OpenDirectory/OpenDirectory.h>
+
+extern void setrestricted(CFDictionaryRef attrs);
+
+ODRecordRef odGetUser(CFStringRef location, CFStringRef authname, CFStringRef user, CFDictionaryRef* attrs);
+
+void odUpdateUser(ODRecordRef rec, CFDictionaryRef attrs_orig, CFDictionaryRef attrs);
+
+#endif /* _OPEN_DIRECTORY_H_ */
diff --git a/system_cmds/chpass.tproj/pw_copy.c b/system_cmds/chpass.tproj/pw_copy.c
new file mode 100644
index 0000000..8aa74a6
--- /dev/null
+++ b/system_cmds/chpass.tproj/pw_copy.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This module is used to copy the master password file, replacing a single
+ * record, by chpass(1) and passwd(1).
+ */
+
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pw_util.h"
+#include "pw_copy.h"
+
+extern char *tempname;
+
+void
+pw_copy(int ffd, int tfd, struct passwd *pw)
+{
+ FILE *from, *to;
+ int done;
+ char *p, buf[8192];
+
+ if (!(from = fdopen(ffd, "r")))
+ pw_error(_PATH_MASTERPASSWD, 1, 1);
+ if (!(to = fdopen(tfd, "w")))
+ pw_error(tempname, 1, 1);
+
+ for (done = 0; fgets(buf, sizeof(buf), from);) {
+ if (!strchr(buf, '\n')) {
+ warnx("%s: line too long", _PATH_MASTERPASSWD);
+ pw_error(NULL, 0, 1);
+ }
+#if defined(__APPLE__)
+ if (done || (buf[0] == '#')) {
+#else
+ if (done) {
+#endif
+ (void)fprintf(to, "%s", buf);
+ if (ferror(to))
+ goto err;
+ continue;
+ }
+ if (!(p = strchr(buf, ':'))) {
+ warnx("%s: corrupted entry", _PATH_MASTERPASSWD);
+ pw_error(NULL, 0, 1);
+ }
+ *p = '\0';
+ if (strcmp(buf, pw->pw_name)) {
+ *p = ':';
+ (void)fprintf(to, "%s", buf);
+ if (ferror(to))
+ goto err;
+ continue;
+ }
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
+ pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
+ pw->pw_dir, pw->pw_shell);
+ done = 1;
+ if (ferror(to))
+ goto err;
+ }
+ if (!done)
+ (void)fprintf(to, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
+ pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
+ pw->pw_dir, pw->pw_shell);
+
+ if (ferror(to))
+err: pw_error(NULL, 1, 1);
+ (void)fclose(to);
+}
diff --git a/system_cmds/chpass.tproj/pw_copy.h b/system_cmds/chpass.tproj/pw_copy.h
new file mode 100644
index 0000000..7c7af0a
--- /dev/null
+++ b/system_cmds/chpass.tproj/pw_copy.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+void pw_copy __P((int, int, struct passwd *));
diff --git a/system_cmds/chpass.tproj/table.c b/system_cmds/chpass.tproj/table.c
new file mode 100644
index 0000000..ba1523d
--- /dev/null
+++ b/system_cmds/chpass.tproj/table.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#if 0
+#ifndef lint
+static const char sccsid[] = "@(#)table.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/table.c,v 1.10 2003/05/03 19:44:45 obrien Exp $");
+#endif
+
+#include <sys/types.h>
+#include <stddef.h>
+#include "chpass.h"
+
+char e1[] = ": ";
+char e2[] = ":,";
+
+#ifdef OPEN_DIRECTORY
+#include "open_directory.h"
+
+ENTRY list[] = {
+ { "Login", display_string, p_login, 1, 5, e1, &kODAttributeTypeRecordName, },
+ { "Password", display_string, p_passwd, 1, 8, e1, &kODAttributeTypePassword, },
+ { "Uid [#]", display_string, p_uid, 1, 3, e1, &kODAttributeTypeUniqueID, },
+ { "Gid [# or name]", display_string, p_gid, 1, 3, e1, &kODAttributeTypePrimaryGroupID, },
+ { "Generated uid", display_string, p_uuid, 1, 13, NULL, &kODAttributeTypeGUID, },
+#if 0
+ { "Change [month day year]", display_time, p_change, 1, 6, NULL, CFSTR(kDS1AttrChange), },
+ { "Expire [month day year]", display_time, p_expire, 1, 6, NULL, kODAttributeTypeExpire, },
+ { "Class", display_string, p_class, 0, 5, e1, CFSTR(""), "Class" },
+#endif
+ { "Home directory", display_string, p_hdir, 1, 14, e1, &kODAttributeTypeNFSHomeDirectory, },
+ { "Shell", display_string, p_shell, 1, 5, e1, &kODAttributeTypeUserShell, },
+ { "Full Name", display_string, p_gecos, 1, 9, e2, &kODAttributeTypeFullName, },
+ { "Office Location", display_string, p_gecos, 1, 8, e2, &kODAttributeTypeBuilding, },
+ { "Office Phone", display_string, p_gecos, 1, 12, e2, &kODAttributeTypePhoneNumber, },
+ { "Home Phone", display_string, p_gecos, 1, 10, e2, &kODAttributeTypeHomePhoneNumber, },
+ { NULL, NULL, NULL, 0, 0, NULL, NULL,},
+};
+#else /* OPEN_DIRECTORY */
+ENTRY list[] = {
+ { "login", p_login, 1, 5, e1, NULL },
+ { "password", p_passwd, 1, 8, e1, NULL },
+ { "uid", p_uid, 1, 3, e1, NULL },
+ { "gid", p_gid, 1, 3, e1, NULL },
+ { "class", p_class, 1, 5, e1, NULL },
+ { "change", p_change, 1, 6, NULL, NULL },
+ { "expire", p_expire, 1, 6, NULL, NULL },
+#ifdef RESTRICT_FULLNAME_CHANGE /* do not allow fullname changes */
+ { "full name", p_gecos, 1, 9, e2, NULL },
+#else
+ { "full name", p_gecos, 0, 9, e2, NULL },
+#endif
+ { "office phone", p_gecos, 0, 12, e2, NULL },
+ { "home phone", p_gecos, 0, 10, e2, NULL },
+ { "office location", p_gecos, 0, 15, e2, NULL },
+ { "other information", p_gecos, 0, 11, e1, NULL },
+ { "home directory", p_hdir, 1, 14, e1, NULL },
+ { "shell", p_shell, 0, 5, e1, NULL },
+ { NULL, NULL, 0, 0, NULL, NULL },
+};
+#endif /* OPEN_DIRECTORY */
diff --git a/system_cmds/chpass.tproj/util.c b/system_cmds/chpass.tproj/util.c
new file mode 100644
index 0000000..d3ab03f
--- /dev/null
+++ b/system_cmds/chpass.tproj/util.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)util.c 8.4 (Berkeley) 4/2/94";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/chpass/util.c,v 1.13 2004/01/18 21:46:39 charnier Exp $");
+#endif
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+
+#include "chpass.h"
+
+#if OPEN_DIRECTORY
+#include <err.h>
+#include <paths.h>
+#include <sys/stat.h>
+#include "open_directory.h"
+
+char* tempname;
+#endif /* OPEN_DIRECTORY */
+
+static const char *months[] =
+ { "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November",
+ "December", NULL };
+
+char *
+ttoa(time_t tval)
+{
+ struct tm *tp;
+ static char tbuf[50];
+
+ if (tval) {
+ tp = localtime(&tval);
+ (void)sprintf(tbuf, "%s %d, %d", months[tp->tm_mon],
+ tp->tm_mday, tp->tm_year + TM_YEAR_BASE);
+ }
+ else
+ *tbuf = '\0';
+ return (tbuf);
+}
+
+int
+atot(char *p, time_t *store)
+{
+ static struct tm *lt;
+ char *t;
+ const char **mp;
+ time_t tval;
+ int day, month, year;
+
+ if (!*p) {
+ *store = 0;
+ return (0);
+ }
+ if (!lt) {
+ unsetenv("TZ");
+ (void)time(&tval);
+ lt = localtime(&tval);
+ }
+ if (!(t = strtok(p, " \t")))
+ goto bad;
+ if (isdigit(*t)) {
+ month = atoi(t);
+ } else {
+ for (mp = months;; ++mp) {
+ if (!*mp)
+ goto bad;
+ if (!strncasecmp(*mp, t, 3)) {
+ month = (int)(mp - months + 1);
+ break;
+ }
+ }
+ }
+ if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t))
+ goto bad;
+ day = atoi(t);
+ if (!(t = strtok((char *)NULL, " \t,")) || !isdigit(*t))
+ goto bad;
+ year = atoi(t);
+ if (day < 1 || day > 31 || month < 1 || month > 12)
+ goto bad;
+ /* Allow two digit years 1969-2068 */
+ if (year < 69)
+ year += 2000;
+ else if (year < 100)
+ year += TM_YEAR_BASE;
+ if (year < EPOCH_YEAR)
+bad: return (1);
+ lt->tm_year = year - TM_YEAR_BASE;
+ lt->tm_mon = month - 1;
+ lt->tm_mday = day;
+ lt->tm_hour = 0;
+ lt->tm_min = 0;
+ lt->tm_sec = 0;
+ lt->tm_isdst = -1;
+ if ((tval = mktime(lt)) < 0)
+ return (1);
+ *store = tval;
+ return (0);
+}
+
+int
+ok_shell(char *name)
+{
+#ifdef __APPLE__
+ char *sh;
+#else
+ char *p, *sh;
+#endif
+
+ setusershell();
+ while ((sh = getusershell())) {
+ if (!strcmp(name, sh)) {
+ endusershell();
+ return (1);
+ }
+#ifndef __APPLE__
+ /* allow just shell name, but use "real" path */
+ if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) {
+ endusershell();
+ return (1);
+ }
+#endif
+ }
+ endusershell();
+ return (0);
+}
+
+char *
+dup_shell(char *name)
+{
+ char *p, *sh, *ret;
+
+ setusershell();
+ while ((sh = getusershell())) {
+ if (!strcmp(name, sh)) {
+ endusershell();
+ return (strdup(name));
+ }
+ /* allow just shell name, but use "real" path */
+ if ((p = strrchr(sh, '/')) && strcmp(name, p + 1) == 0) {
+ ret = strdup(sh);
+ endusershell();
+ return (ret);
+ }
+ }
+ endusershell();
+ return (NULL);
+}
+
+#if OPEN_DIRECTORY
+int
+cfprintf(FILE* file, const char* format, ...)
+{
+ char* cstr;
+ int result = 0;
+ va_list args;
+ va_start(args, format);
+ CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull);
+ if (formatStr) {
+ CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args);
+ if (str) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
+ va_end(args);
+ cstr = malloc(size);
+ if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) {
+ result = fprintf(file, "%s", cstr);
+ free(cstr);
+ }
+ CFRelease(str);
+ }
+ CFRelease(formatStr);
+ }
+ return result;
+}
+
+/*
+ * Edit the temp file. Return -1 on error, >0 if the file was modified, 0
+ * if it was not.
+ */
+int
+editfile(const char* tfn)
+{
+ struct sigaction sa, sa_int, sa_quit;
+ sigset_t oldsigset, sigset;
+ struct stat st1, st2;
+ const char *p, *editor;
+ int pstat;
+ pid_t editpid;
+
+ if ((editor = getenv("EDITOR")) == NULL)
+ editor = _PATH_VI;
+ if ((p = strrchr(editor, '/')))
+ ++p;
+ else
+ p = editor;
+
+ if (stat(tfn, &st1) == -1)
+ return (-1);
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sigaction(SIGINT, &sa, &sa_int);
+ sigaction(SIGQUIT, &sa, &sa_quit);
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigset, &oldsigset);
+ switch ((editpid = fork())) {
+ case -1:
+ return (-1);
+ case 0:
+ sigaction(SIGINT, &sa_int, NULL);
+ sigaction(SIGQUIT, &sa_quit, NULL);
+ sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ errno = 0;
+ if (!master_mode) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+ execlp(editor, p, tfn, (char *)NULL);
+ _exit(errno);
+ default:
+ /* parent */
+ break;
+ }
+ for (;;) {
+ if (waitpid(editpid, &pstat, WUNTRACED) == -1) {
+ if (errno == EINTR)
+ continue;
+ unlink(tfn);
+ editpid = -1;
+ break;
+ } else if (WIFSTOPPED(pstat)) {
+ raise(WSTOPSIG(pstat));
+ } else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0) {
+ editpid = -1;
+ break;
+ } else {
+ unlink(tfn);
+ editpid = -1;
+ break;
+ }
+ }
+ sigaction(SIGINT, &sa_int, NULL);
+ sigaction(SIGQUIT, &sa_quit, NULL);
+ sigprocmask(SIG_SETMASK, &oldsigset, NULL);
+ if (stat(tfn, &st2) == -1)
+ return (-1);
+ return (st1.st_mtime != st2.st_mtime);
+}
+
+#if 0
+static void
+pw_error(char *name, int err, int eval)
+{
+ if (err)
+ warn("%s", name);
+ exit(eval);
+}
+#endif
+
+#endif /* OPEN_DIRECTORY */
diff --git a/system_cmds/cpuctl.tproj/cpuctl.8 b/system_cmds/cpuctl.tproj/cpuctl.8
new file mode 100644
index 0000000..f52f514
--- /dev/null
+++ b/system_cmds/cpuctl.tproj/cpuctl.8
@@ -0,0 +1,67 @@
+.\" Darwin cpuctl man page adapted from NetBSD (credits below):
+.\"
+.\" $NetBSD: cpuctl.8,v 1.18 2018/01/14 00:45:54 mrg Exp $
+.\"
+.\" Copyright (c) 2007, 2008, 2012, 2015 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Andrew Doran.
+.\"
+.\" 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.
+.\"
+.Dd March 18, 2019
+.Dt CPUCTL 8
+.Os Darwin
+.Sh NAME
+.Nm cpuctl
+.Nd program to control CPUs
+.Sh SYNOPSIS
+.Nm cpuctl
+.Ar command
+.Op Ar arguments
+.Sh DESCRIPTION
+The
+.Nm
+command can be used to control and inspect the state of CPUs in the system.
+.Pp
+The first argument,
+.Ar command ,
+specifies the action to take.
+Valid commands are:
+.Bl -tag -width offline
+.It list
+For each CPU in the system, display the current state and time of the last
+state change.
+.It offline Ar cpu Op Ar cpu ...
+Set the specified CPUs off line.
+.Pp
+At least one CPU in the system must remain on line.
+.It online Ar cpu Op Ar cpu ...
+Set the specified CPUs on line.
+.El
+.Sh EXAMPLES
+Run
+.Dl cpuctl offline 2
+and then
+.Dl cpuctl list
+The output should reflect the fact that CPU#2 was taken offline.
diff --git a/system_cmds/cpuctl.tproj/cpuctl.c b/system_cmds/cpuctl.tproj/cpuctl.c
new file mode 100644
index 0000000..4821878
--- /dev/null
+++ b/system_cmds/cpuctl.tproj/cpuctl.c
@@ -0,0 +1,145 @@
+//
+// cpuctl.c
+// system_cmds
+//
+// Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#include <err.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <mach/mach.h>
+
+static void usage()
+{
+ printf("usage: cpuctl [ list ]\n");
+ printf(" cpuctl { offline | online } <cpu> [ <cpu>... ]\n");
+ exit(EX_USAGE);
+}
+
+static void fetch_cpu_info(host_t *priv_port,
+ processor_port_array_t proc_ports,
+ mach_msg_type_number_t proc_count,
+ processor_basic_info_data_t *cpus)
+{
+ for (int i = 0; i < proc_count; i++) {
+ mach_msg_type_number_t info_count = PROCESSOR_BASIC_INFO_COUNT;
+
+ if (processor_info(proc_ports[i], PROCESSOR_BASIC_INFO, priv_port,
+ (processor_info_t)&cpus[i], &info_count) != KERN_SUCCESS) {
+ errx(EX_OSERR, "processor_info(%d) failed", i);
+ }
+ }
+}
+
+static int do_cmd_list(mach_msg_type_number_t proc_count, processor_basic_info_data_t *cpus)
+{
+ int prev_lowest = -1;
+ for (int i = 0; i < proc_count; i++) {
+ int lowest_slot = INT_MAX;
+ int lowest_idx = -1;
+ for (int j = 0; j < proc_count; j++) {
+ int slot = cpus[j].slot_num;
+ if (slot > prev_lowest && slot < lowest_slot) {
+ lowest_slot = slot;
+ lowest_idx = j;
+ }
+ }
+ if (lowest_idx == -1)
+ errx(EX_OSERR, "slot numbers are out of range");
+
+ processor_basic_info_data_t *cpu = &cpus[lowest_idx];
+ printf("CPU%d: %-7s type=%x,%x master=%d\n",
+ cpu->slot_num,
+ cpu->running ? "online" : "offline",
+ cpu->cpu_type,
+ cpu->cpu_subtype,
+ cpu->is_master);
+
+ prev_lowest = lowest_slot;
+ }
+ return 0;
+}
+
+static int find_cpu_by_slot(mach_msg_type_number_t proc_count,
+ processor_basic_info_data_t *cpus,
+ int slot)
+{
+ for (int i = 0; i < proc_count; i++) {
+ if (cpus[i].slot_num == slot)
+ return i;
+ }
+ return -1;
+}
+
+int main(int argc, char **argv)
+{
+ int opt;
+
+ while ((opt = getopt(argc, argv, "h")) != -1) {
+ switch (opt) {
+ case 'h':
+ usage();
+ }
+ }
+
+ host_t priv_port;
+ if (host_get_host_priv_port(mach_host_self(), &priv_port) != KERN_SUCCESS)
+ errx(EX_OSERR, "host_get_host_priv_port() failed");
+
+ processor_port_array_t proc_ports;
+ mach_msg_type_number_t proc_count;
+ if (host_processors(priv_port, &proc_ports, &proc_count) != KERN_SUCCESS)
+ errx(EX_OSERR, "host_processors() failed");
+
+ processor_basic_info_data_t *cpus = calloc(proc_count, sizeof(*cpus));
+ if (!cpus)
+ errx(EX_OSERR, "calloc() failed");
+ fetch_cpu_info(&priv_port, proc_ports, proc_count, cpus);
+
+ if (optind == argc)
+ return do_cmd_list(proc_count, cpus);
+
+ const char *cmd = argv[optind];
+ optind++;
+
+ if (!strcmp(cmd, "list"))
+ return do_cmd_list(proc_count, cpus);
+
+ bool up = true;
+ if (!strncmp(cmd, "off", 3))
+ up = false;
+ else if (strncmp(cmd, "on", 2))
+ usage();
+
+ if (optind == argc)
+ usage();
+
+ int ret = 0;
+ for (; optind < argc; optind++) {
+ char *endp = NULL;
+ int slot = (int)strtoul(argv[optind], &endp, 0);
+ if (*endp != 0)
+ usage();
+
+ int cpu = find_cpu_by_slot(proc_count, cpus, slot);
+ if (cpu == -1)
+ errx(EX_USAGE, "Invalid CPU ID %d", slot);
+
+ if (up) {
+ if (processor_start(proc_ports[cpu]) != KERN_SUCCESS)
+ errx(EX_OSERR, "processor_start(%u) failed", cpu);
+ } else {
+ if (processor_exit(proc_ports[cpu]) != KERN_SUCCESS)
+ errx(EX_OSERR, "processor_exit(%u) failed", cpu);
+ }
+ }
+
+ return ret;
+}
diff --git a/system_cmds/dmesg.tproj/dmesg.8 b/system_cmds/dmesg.tproj/dmesg.8
new file mode 100644
index 0000000..ca3758b
--- /dev/null
+++ b/system_cmds/dmesg.tproj/dmesg.8
@@ -0,0 +1,55 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)dmesg.8 8.1 (Berkeley) 6/5/93
+.\"
+.Dd June 5, 1993
+.Dt DMESG 8
+.Os BSD 4
+.Sh NAME
+.Nm dmesg
+.Nd "display the system message buffer"
+.Sh SYNOPSIS
+.Nm dmesg
+.Op Fl M Ar core
+.Op Fl N Ar system
+.Sh DESCRIPTION
+.Nm Dmesg
+displays the contents of the system message buffer.
+This command needs to be run as root.
+.Pp
+.Sh SEE ALSO
+.Xr syslogd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/system_cmds/dmesg.tproj/dmesg.c b/system_cmds/dmesg.tproj/dmesg.c
new file mode 100644
index 0000000..ed62442
--- /dev/null
+++ b/system_cmds/dmesg.tproj/dmesg.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <vis.h>
+#include <sys/sysctl.h>
+#include <libproc.h>
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: sudo dmesg\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ char *msgbuf, *visbuf;
+ int msgbufsize;
+ size_t sysctlsize = sizeof(msgbufsize);
+ long data_size;
+
+ if (argc > 1)
+ usage();
+
+ if (sysctlbyname("kern.msgbuf", &msgbufsize, &sysctlsize, NULL, 0)) {
+ perror("Unable to size kernel buffer");
+ }
+
+ msgbuf = malloc(msgbufsize);
+ if (msgbuf == NULL) {
+ perror("Unable to allocate a message buffer");
+ }
+
+ if ((data_size = proc_kmsgbuf(msgbuf, msgbufsize)) == 0){
+ perror("Unable to obtain kernel buffer");
+ usage();
+ }
+
+ visbuf = malloc(data_size*4);
+ strvis(visbuf, msgbuf, 0);
+ printf("%s", visbuf);
+ free(visbuf);
+ free(msgbuf);
+ exit(0);
+}
diff --git a/system_cmds/dynamic_pager.tproj/com.apple.dynamic_pager.plist b/system_cmds/dynamic_pager.tproj/com.apple.dynamic_pager.plist
new file mode 100644
index 0000000..4214037
--- /dev/null
+++ b/system_cmds/dynamic_pager.tproj/com.apple.dynamic_pager.plist
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>EnableTransactions</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.dynamic_pager</string>
+ <key>KeepAlive</key>
+ <dict>
+ <key>SuccessfulExit</key>
+ <false/>
+ </dict>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/sbin/dynamic_pager</string>
+ </array>
+</dict>
+</plist>
diff --git a/system_cmds/dynamic_pager.tproj/dynamic_pager.8 b/system_cmds/dynamic_pager.tproj/dynamic_pager.8
new file mode 100644
index 0000000..7d5bfc2
--- /dev/null
+++ b/system_cmds/dynamic_pager.tproj/dynamic_pager.8
@@ -0,0 +1,32 @@
+.\" Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+.\"
+.Dd July 8, 2003
+.Dt dynamic_pager 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm dynamic_pager
+.Nd swap configuration daemon
+.Sh SYNOPSIS
+.Nm dynamic_pager
+.Op Fl F Ar filename
+.Sh DESCRIPTION
+The
+.Nm dynamic_pager
+daemon can be used to specify a base name for swapfile names using the "-F" command line option or by modifying the configuration plist file.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.\" ==========
+.It Fl F
+The base name of the
+.Ar filename
+to use for the swapfiles. By default this is
+.Pa /private/var/vm/swapfile .
+.\" ==========
+.Sh FILES
+.Bl -tag -width /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist -compact
+.It Pa /private/var/vm/swapfile*
+Swapfiles.
+
+.It Pa /System/Library/LaunchDaemons/com.apple.dynamic_pager.plist
+Configuration file.
+.El
diff --git a/system_cmds/dynamic_pager.tproj/dynamic_pager.c b/system_cmds/dynamic_pager.tproj/dynamic_pager.c
new file mode 100644
index 0000000..deb9379
--- /dev/null
+++ b/system_cmds/dynamic_pager.tproj/dynamic_pager.c
@@ -0,0 +1,114 @@
+#define mig_external
+
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+
+/*
+ * We don't exit with a non-zero status anywhere here for 2 reasons:
+ * - the kernel can continue to create swapfiles in "/private/var/vm/swapfile<index>"
+ * - we want this job to run only once at boot and exit regardless of whether:
+ * -- it could clean up the swap directory
+ * -- it could set the prefix for the swapfile name.
+ */
+
+static void
+clean_swap_directory(const char *path)
+{
+ DIR *dir;
+ struct dirent *entry;
+ char buf[1024];
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ fprintf(stderr,"dynamic_pager: cannot open swap directory %s\n", path);
+ exit(0);
+ }
+
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_namlen>= 4 && strncmp(entry->d_name, "swap", 4) == 0) {
+ snprintf(buf, sizeof buf, "%s/%s", path, entry->d_name);
+ unlink(buf);
+ }
+ }
+
+ closedir(dir);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ static char tmp[1024];
+ struct statfs sfs;
+ char *q;
+ char fileroot[512];
+
+ seteuid(getuid());
+ fileroot[0] = '\0';
+
+ while ((ch = getopt(argc, argv, "F:")) != EOF) {
+ switch((char)ch) {
+
+ case 'F':
+ strncpy(fileroot, optarg, 500);
+ break;
+
+ default:
+ (void)fprintf(stderr,
+ "usage: dynamic_pager [-F filename]\n");
+ exit(0);
+ }
+ }
+
+ /*
+ * set vm.swapfileprefix if a fileroot was passed from the command
+ * line, otherwise get the value from the kernel
+ */
+ if (fileroot[0] != '\0') {
+ if (sysctlbyname("vm.swapfileprefix", NULL, 0, fileroot, sizeof(fileroot)) == -1) {
+ perror("Failed to set swapfile name prefix");
+ }
+ } else {
+ size_t fileroot_len = sizeof(fileroot);
+ if (sysctlbyname("vm.swapfileprefix", fileroot, &fileroot_len, NULL, 0) == -1) {
+ perror("Failed to get swapfile name prefix");
+ /*
+ * can't continue without a fileroot
+ */
+ return (0);
+ }
+ }
+
+ /*
+ * get rid of the filename at the end of the swap file specification
+ * we only want the portion of the pathname that should already exist
+ */
+ strcpy(tmp, fileroot);
+ if ((q = strrchr(tmp, '/')))
+ *q = 0;
+
+ /*
+ * Remove all files in the swap directory.
+ */
+ clean_swap_directory(tmp);
+
+ if (statfs(tmp, &sfs) == -1) {
+ /*
+ * Setup the swap directory.
+ */
+
+ if (mkdir(tmp, 0755) == -1) {
+ (void)fprintf(stderr, "dynamic_pager: cannot create swap directory %s\n", tmp);
+ }
+ }
+
+ chown(tmp, 0, 0);
+
+ return (0);
+}
diff --git a/system_cmds/dynamic_pager.tproj/entitlements.plist b/system_cmds/dynamic_pager.tproj/entitlements.plist
new file mode 100644
index 0000000..2e0c44d
--- /dev/null
+++ b/system_cmds/dynamic_pager.tproj/entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.rootless.volume.VM</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/dynamic_pager.tproj/generate_plist.sh b/system_cmds/dynamic_pager.tproj/generate_plist.sh
new file mode 100644
index 0000000..290a550
--- /dev/null
+++ b/system_cmds/dynamic_pager.tproj/generate_plist.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -e
+set -x
+
+cp "${SCRIPT_INPUT_FILE_0}" "${SCRIPT_OUTPUT_FILE_0}"
+case "$PLATFORM_NAME" in
+iphone*|appletv*|watch*|bridge*)
+ /usr/libexec/PlistBuddy -c "Add :LaunchOnlyOnce bool true" "${SCRIPT_OUTPUT_FILE_0}"
+ ;;
+macosx)
+ ;;
+*)
+ echo "Unsupported platform: $PLATFORM_NAME"
+ exit 1
+ ;;
+esac
diff --git a/system_cmds/fs_usage.tproj/fs_usage.1 b/system_cmds/fs_usage.tproj/fs_usage.1
new file mode 100644
index 0000000..3ab0cff
--- /dev/null
+++ b/system_cmds/fs_usage.tproj/fs_usage.1
@@ -0,0 +1,178 @@
+.\" Copyright (c) 2000, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd November 7, 2002
+.Dt FS_USAGE 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm fs_usage
+.Nd report system calls and page faults related to filesystem activity in
+real-time
+.Sh SYNOPSIS
+.Nm fs_usage [-e] [-w] [-f mode] [-b] [-t seconds] [-R rawfile [-S start_time] [-E end_time]] [pid | cmd [pid | cmd] ...]
+.Sh DESCRIPTION
+The
+.Nm fs_usage
+utility presents an ongoing display of system call usage information
+pertaining to filesystem activity.
+It requires root privileges due to the kernel tracing facility it uses to
+operate.
+By default, the activity monitored includes all system processes except the
+running
+.Nm fs_usage
+process, Terminal, telnetd, telnet, sshd, rlogind, tcsh, csh, sh, and zsh.
+These defaults can be overridden such that output is limited to include or
+exclude a list of processes specified by the user.
+.Pp
+The output presented by
+.Nm fs_usage
+is formatted according to the size of your window.
+A narrow window will display fewer columns of data.
+Use a wide window for maximum data display.
+You may override the window formatting restrictions
+by forcing a wide display with the
+.Fl w
+option.
+In this case, the data displayed will wrap
+when the window is not wide enough.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl e
+Specifying the
+.Fl e
+option generates output that excludes sampling
+of the running fs_usage tool.
+If a list of process IDs or commands is also given,
+then those processes are also excluded from the sampled output.
+.\" ==========
+.It Fl w
+Specifying the
+.Fl w
+option forces a wider, more detailed output,
+regardless of the window size.
+.\" ==========
+.It Fl f
+Specifying the
+.Fl f
+option turns on output filtering based on the
+.Pa mode
+provided.
+Multiple filtering options can be specified.
+By default, no output filtering occurs.
+The supported modes are:
+.Pp
+.Pa network
+Network-related events are displayed.
+.Pp
+.Pa filesys
+Filesystem-related events are displayed.
+.Pp
+.Pa pathname
+Pathname-related events are displayed.
+.Pp
+.Pa exec
+Exec and spawn events are displayed.
+.Pp
+.Pa diskio
+Disk I/O events are displayed.
+.Pp
+.Pa cachehit
+In addition, show cache hits.
+.\" ==========
+.It Fl b
+Specifying the
+.Fl b
+option annotates disk I/O events with BootCache info (if available).
+.\" ==========
+.It Fl t Ar seconds
+Specifies a run timeout in seconds.
+.Nm fs_usage
+will run for no longer than the timeout specified.
+.\" ==========
+.It Fl R Ar raw_file
+Specifies a raw trace file to process.
+.\" ==========
+.It Fl S Ar start_time
+If
+.Fl R
+is selected, specifies the start time in microseconds to
+begin processing entries from the raw trace file. Entries
+with timestamps before the specified start time will be
+skipped.
+.\" ==========
+.It Fl E Ar end_time
+If
+.Fl R
+is selected, specifies the ending time in microseconds to
+stop processing entries from the raw trace file. Entries
+with timestamps beyond the specified ending time will be
+skipped.
+.\" ==========
+.It pid | cmd
+The sampled data can be limited to a list of process IDs or commands.
+When a command name is given, all processes with that name will be sampled.
+Using the
+.Fl e
+option has the opposite effect,
+excluding sampled data relating to the given list
+of process IDs or commands.
+.El
+.Pp
+The data columns displayed are as follows:
+.Bl -tag -width Ds
+.Pp
+.It TIMESTAMP
+TOD when call occurred.
+Wide mode will have microsecond granularity.
+.It CALL
+The name of the network or filesystem related call, page-in, page-out,
+or physical disk access.
+.It FILE DESCRIPTOR
+Of the form F=x, x is a file descriptor.
+Depending on the type of system call,
+this will be either an input value or a return value.
+.It BYTE COUNT
+Of the form B=x, x is the number of bytes requested by the call.
+.It [ERRNO]
+On error, the errno is displayed in brackets.
+.It PATHNAME
+Pathname of the file accessed (up to the last 28 bytes).
+.It FAULT ADDRESS
+Of the form A=0xnnnnnnnn,
+where 0xnnnnnnnn is the address being faulted.
+.It DISK BLOCK NUMBER
+Of the form D=0xnnnnnnnn,
+where 0xnnnnnnnn is the block number
+of the physical disk block being read or written.
+.It OFFSET
+Of the form O=0xnnnnnnnn, where 0xnnnnnnnn is a file offset.
+.It SELECT RETURN
+Of the form S=x, x is the number of ready descriptors returned
+by the select() system call.
+If S=0, the time limit expired.
+.It TIME INTERVAL(W)
+The elapsed time spent in the system call.
+A
+.Sq Li W
+after the elapsed time indicates the process was scheduled out
+during this file activity.
+In this case, the elapsed time includes the wait time.
+.It PROCESS NAME
+The process that made the system call. Wide mode will append the
+thread id to the process name (i.e Mail.nnn).
+.El
+.Pp
+.Sh SAMPLE USAGE
+.Pp
+fs_usage -w -f filesys Mail
+.Pp
+.Nm fs_usage
+will display file system related data
+for all instances of processes named Mail.
+Maximum data output will be displayed in the window.
+.Sh SEE ALSO
+.Xr dyld 1 ,
+.Xr latency 1 ,
+.Xr sc_usage 1 ,
+.Xr top 1
diff --git a/system_cmds/fs_usage.tproj/fs_usage.c b/system_cmds/fs_usage.tproj/fs_usage.c
new file mode 100644
index 0000000..ef81b48
--- /dev/null
+++ b/system_cmds/fs_usage.tproj/fs_usage.c
@@ -0,0 +1,3922 @@
+/*
+ * Copyright (c) 1999-2020 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * SDKROOT=macosx.internal cc -I`xcrun -sdk macosx.internal --show-sdk-path`/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -Os -lktrace -lutil -o fs_usage fs_usage.c
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+#include <fcntl.h>
+#include <aio.h>
+#include <string.h>
+#include <dirent.h>
+#include <libc.h>
+#include <termios.h>
+#include <errno.h>
+#include <err.h>
+#include <libutil.h>
+#include <TargetConditionals.h>
+
+#include <ktrace/session.h>
+#include <System/sys/kdebug.h>
+#include <os/assumes.h>
+
+#include <sys/disk.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/syslimits.h>
+#include <sys/time.h>
+#include <sys/types.h>
+
+#import <mach/clock_types.h>
+#import <mach/mach_time.h>
+
+/*
+ * MAXCOLS controls when extra data kicks in.
+ * MAX_WIDE_MODE_COLS controls -w mode to get even wider data in path.
+ */
+#define MAXCOLS 132
+#define MAX_WIDE_MODE_COLS 264
+#define MAXWIDTH MAX_WIDE_MODE_COLS + 64
+
+typedef struct th_info {
+ struct th_info *next;
+ uint64_t thread;
+
+ /* this is needed for execve()/posix_spawn(), because the command name at the end probe is the new name, which we don't want */
+ char command[MAXCOMLEN + 1];
+
+ /*
+ * sometimes a syscall can cause multiple VFS_LOOKUPs of the same vnode with multiple paths
+ * (e.g., one absolute, one relative). traditional fs_usage behavior was to display the
+ * *first* lookup, so we need to save it off once we see it.
+ */
+ uint64_t vnodeid; /* the vp of the VFS_LOOKUP we're currently in, 0 if we are not in one */
+ char pathname[MAXPATHLEN];
+ char pathname2[MAXPATHLEN];
+ char *newest_pathname; /* points to pathname2 if it's filled, otherwise pathname if it's filled, otherwise NULL */
+
+ int pid;
+ int type;
+ uint64_t arg1;
+ uint64_t arg2;
+ uint64_t arg3;
+ uint64_t arg4;
+ uint64_t arg5;
+ uint64_t arg6;
+ uint64_t arg7;
+ uint64_t arg8;
+ int waited;
+ uint64_t stime;
+} *th_info_t;
+
+struct diskio {
+ struct diskio *next;
+ struct diskio *prev;
+ uint64_t type;
+ uint64_t bp;
+ uint64_t dev;
+ uint64_t blkno;
+ uint64_t iosize;
+ uint64_t io_errno;
+ uint64_t is_meta;
+ uint64_t vnodeid;
+ uint64_t issuing_thread;
+ pid_t issuing_pid;
+ uint64_t completion_thread;
+ char issuing_command[MAXCOMLEN + 1];
+ uint64_t issued_time;
+ uint64_t completed_time;
+ struct timeval completed_walltime;
+ uint32_t bc_info;
+};
+
+#define HASH_SIZE 1024
+#define HASH_MASK (HASH_SIZE - 1)
+
+void setup_ktrace_callbacks(void);
+void extend_syscall(uint64_t thread, int type, ktrace_event_t event);
+
+/* printing routines */
+bool check_filter_mode(pid_t pid, th_info_t ti, uint64_t type, int error, int retval, char *sc_name);
+void format_print(th_info_t ti, char *sc_name, ktrace_event_t event, uint64_t type, int format, uint64_t now, uint64_t stime, int waited, const char *pathname, struct diskio *dio);
+int print_open(ktrace_event_t event, uint64_t flags);
+
+/* metadata info hash routines */
+void meta_add_name(uint64_t blockno, const char *pathname);
+const char *meta_find_name(uint64_t blockno);
+void meta_delete_all(void);
+
+/* event ("thread info") routines */
+void event_enter(int type, ktrace_event_t event);
+void event_exit(char *sc_name, int type, ktrace_event_t event, int format);
+th_info_t event_find(uint64_t thread, int type);
+void event_delete(th_info_t ti_to_delete);
+void event_delete_all(void);
+void event_mark_thread_waited(uint64_t);
+
+/* network fd set routines */
+void fd_set_is_network(pid_t pid, uint64_t fd, bool set);
+bool fd_is_network(pid_t pid, uint64_t fd);
+void fd_clear_pid(pid_t pid);
+void fd_clear_all(void);
+
+/* shared region address lookup routines */
+void init_shared_cache_mapping(void);
+void lookup_name(uint64_t user_addr, char **type, char **name);
+
+/* disk I/O tracking routines */
+struct diskio *diskio_start(uint64_t type, uint64_t bp, uint64_t dev, uint64_t blkno, uint64_t iosize, ktrace_event_t event);
+struct diskio *diskio_find(uint64_t bp);
+struct diskio *diskio_complete(uint64_t bp, uint64_t io_errno, uint64_t resid, uint64_t thread, uint64_t curtime, struct timeval curtime_wall);
+void diskio_print(struct diskio *dio);
+void diskio_free(struct diskio *dio);
+
+/* disk name routines */
+#define NFS_DEV -1
+#define CS_DEV -2
+char *generate_cs_disk_name(uint64_t dev, char *s);
+char *find_disk_name(uint64_t dev);
+void cache_disk_names(void);
+
+#define CLASS_MASK 0xff000000
+#define CSC_MASK 0xffff0000
+#define BSC_INDEX(type) ((type >> 2) & 0x3fff)
+
+#define MACH_vmfault 0x01300008
+#define MACH_pageout 0x01300004
+#define MACH_sched 0x01400000
+#define MACH_stkhandoff 0x01400008
+#define MACH_idle 0x01400024
+
+#define BSC_thread_terminate 0x040c05a4
+
+#define HFS_update 0x3018000
+#define HFS_modify_block_end 0x3018004
+
+#define Throttled 0x3010184
+#define SPEC_ioctl 0x3060000
+#define SPEC_unmap_info 0x3060004
+#define proc_exit 0x4010004
+
+#define BC_IO_HIT 0x03070010
+#define BC_IO_HIT_STALLED 0x03070020
+#define BC_IO_MISS 0x03070040
+#define BC_IO_MISS_CUT_THROUGH 0x03070080
+#define BC_PLAYBACK_IO 0x03070100
+#define BC_STR(s) ( \
+ (s == BC_IO_HIT) ? "HIT" : \
+ (s == BC_IO_HIT_STALLED) ? "STALL" : \
+ (s == BC_IO_MISS) ? "MISS" : \
+ (s == BC_IO_MISS_CUT_THROUGH) ? "CUT" : \
+ (s == BC_PLAYBACK_IO) ? "PLBK" : \
+ (s == 0x0) ? "NONE" : "UNKN" )
+
+#define P_DISKIO_READ (DKIO_READ << 2)
+#define P_DISKIO_ASYNC (DKIO_ASYNC << 2)
+#define P_DISKIO_META (DKIO_META << 2)
+#define P_DISKIO_PAGING (DKIO_PAGING << 2)
+#define P_DISKIO_THROTTLE (DKIO_THROTTLE << 2)
+#define P_DISKIO_PASSIVE (DKIO_PASSIVE << 2)
+#define P_DISKIO_NOCACHE (DKIO_NOCACHE << 2)
+#define P_DISKIO_TIER_MASK (DKIO_TIER_MASK << 2)
+#define P_DISKIO_TIER_SHIFT (DKIO_TIER_SHIFT + 2)
+#define P_DISKIO_TIER_UPGRADE (DKIO_TIER_UPGRADE << 2)
+
+#define P_DISKIO (FSDBG_CODE(DBG_DKRW, 0))
+#define P_DISKIO_DONE (P_DISKIO | (DKIO_DONE << 2))
+#define P_DISKIO_TYPE (P_DISKIO | P_DISKIO_READ | P_DISKIO_META | P_DISKIO_PAGING)
+#define P_DISKIO_MASK (CSC_MASK | 0x4)
+
+#define P_WrData (P_DISKIO)
+#define P_RdData (P_DISKIO | P_DISKIO_READ)
+#define P_WrMeta (P_DISKIO | P_DISKIO_META)
+#define P_RdMeta (P_DISKIO | P_DISKIO_META | P_DISKIO_READ)
+#define P_PgOut (P_DISKIO | P_DISKIO_PAGING)
+#define P_PgIn (P_DISKIO | P_DISKIO_PAGING | P_DISKIO_READ)
+
+#define P_CS_Class 0x0a000000 // DBG_CORESTORAGE
+#define P_CS_Type_Mask 0xfffffff0
+#define P_CS_IO_Done 0x00000004
+
+#define P_CS_ReadChunk 0x0a000200 // chopped up request
+#define P_CS_WriteChunk 0x0a000210
+#define P_CS_MetaRead 0x0a000300 // meta data
+#define P_CS_MetaWrite 0x0a000310
+#define P_CS_TransformRead 0x0a000500 // background transform
+#define P_CS_TransformWrite 0x0a000510
+#define P_CS_MigrationRead 0x0a000600 // composite disk block migration
+#define P_CS_MigrationWrite 0x0a000610
+#define P_CS_SYNC_DISK 0x0a010000
+
+#define MSC_map_fd 0x010c00ac
+
+#define BSC_BASE 0x040C0000
+
+// Network related codes
+#define BSC_recvmsg 0x040C006C
+#define BSC_sendmsg 0x040C0070
+#define BSC_recvfrom 0x040C0074
+#define BSC_accept 0x040C0078
+#define BSC_select 0x040C0174
+#define BSC_socket 0x040C0184
+#define BSC_connect 0x040C0188
+#define BSC_bind 0x040C01A0
+#define BSC_listen 0x040C01A8
+#define BSC_sendto 0x040C0214
+#define BSC_socketpair 0x040C021C
+#define BSC_recvmsg_nocancel 0x040c0644
+#define BSC_sendmsg_nocancel 0x040c0648
+#define BSC_recvfrom_nocancel 0x040c064c
+#define BSC_accept_nocancel 0x040c0650
+#define BSC_connect_nocancel 0x040c0664
+#define BSC_sendto_nocancel 0x040c0674
+
+#define BSC_exit 0x040C0004
+#define BSC_read 0x040C000C
+#define BSC_write 0x040C0010
+#define BSC_open 0x040C0014
+#define BSC_close 0x040C0018
+#define BSC_link 0x040C0024
+#define BSC_unlink 0x040C0028
+#define BSC_chdir 0x040c0030
+#define BSC_fchdir 0x040c0034
+#define BSC_mknod 0x040C0038
+#define BSC_chmod 0x040C003C
+#define BSC_chown 0x040C0040
+#define BSC_getfsstat 0x040C0048
+#define BSC_access 0x040C0084
+#define BSC_chflags 0x040C0088
+#define BSC_fchflags 0x040C008C
+#define BSC_sync 0x040C0090
+#define BSC_dup 0x040C00A4
+#define BSC_ioctl 0x040C00D8
+#define BSC_revoke 0x040C00E0
+#define BSC_symlink 0x040C00E4
+#define BSC_readlink 0x040C00E8
+#define BSC_execve 0x040C00EC
+#define BSC_umask 0x040C00F0
+#define BSC_chroot 0x040C00F4
+#define BSC_msync 0x040C0104
+#define BSC_dup2 0x040C0168
+#define BSC_fcntl 0x040C0170
+#define BSC_fsync 0x040C017C
+#define BSC_readv 0x040C01E0
+#define BSC_writev 0x040C01E4
+#define BSC_fchown 0x040C01EC
+#define BSC_fchmod 0x040C01F0
+#define BSC_rename 0x040C0200
+#define BSC_flock 0x040C020C
+#define BSC_mkfifo 0x040C0210
+#define BSC_mkdir 0x040C0220
+#define BSC_rmdir 0x040C0224
+#define BSC_utimes 0x040C0228
+#define BSC_futimes 0x040C022C
+#define BSC_pread 0x040C0264
+#define BSC_pwrite 0x040C0268
+#define BSC_statfs 0x040C0274
+#define BSC_fstatfs 0x040C0278
+#define BSC_unmount 0x040C027C
+#define BSC_mount 0x040C029C
+#define BSC_fdatasync 0x040C02EC
+#define BSC_stat 0x040C02F0
+#define BSC_fstat 0x040C02F4
+#define BSC_lstat 0x040C02F8
+#define BSC_pathconf 0x040C02FC
+#define BSC_fpathconf 0x040C0300
+#define BSC_getdirentries 0x040C0310
+#define BSC_mmap 0x040c0314
+#define BSC_lseek 0x040c031c
+#define BSC_truncate 0x040C0320
+#define BSC_ftruncate 0x040C0324
+#define BSC_undelete 0x040C0334
+#define BSC_open_dprotected_np 0x040C0360
+#define BSC_getattrlist 0x040C0370
+#define BSC_setattrlist 0x040C0374
+#define BSC_getdirentriesattr 0x040C0378
+#define BSC_exchangedata 0x040C037C
+#define BSC_checkuseraccess 0x040C0380
+#define BSC_searchfs 0x040C0384
+#define BSC_delete 0x040C0388
+#define BSC_copyfile 0x040C038C
+#define BSC_fgetattrlist 0x040C0390
+#define BSC_fsetattrlist 0x040C0394
+#define BSC_getxattr 0x040C03A8
+#define BSC_fgetxattr 0x040C03AC
+#define BSC_setxattr 0x040C03B0
+#define BSC_fsetxattr 0x040C03B4
+#define BSC_removexattr 0x040C03B8
+#define BSC_fremovexattr 0x040C03BC
+#define BSC_listxattr 0x040C03C0
+#define BSC_flistxattr 0x040C03C4
+#define BSC_fsctl 0x040C03C8
+#define BSC_posix_spawn 0x040C03D0
+#define BSC_ffsctl 0x040C03D4
+#define BSC_open_extended 0x040C0454
+#define BSC_umask_extended 0x040C0458
+#define BSC_stat_extended 0x040C045C
+#define BSC_lstat_extended 0x040C0460
+#define BSC_fstat_extended 0x040C0464
+#define BSC_chmod_extended 0x040C0468
+#define BSC_fchmod_extended 0x040C046C
+#define BSC_access_extended 0x040C0470
+#define BSC_mkfifo_extended 0x040C048C
+#define BSC_mkdir_extended 0x040C0490
+#define BSC_aio_fsync 0x040C04E4
+#define BSC_aio_return 0x040C04E8
+#define BSC_aio_suspend 0x040C04EC
+#define BSC_aio_cancel 0x040C04F0
+#define BSC_aio_error 0x040C04F4
+#define BSC_aio_read 0x040C04F8
+#define BSC_aio_write 0x040C04FC
+#define BSC_lio_listio 0x040C0500
+#define BSC_sendfile 0x040C0544
+#define BSC_stat64 0x040C0548
+#define BSC_fstat64 0x040C054C
+#define BSC_lstat64 0x040C0550
+#define BSC_stat64_extended 0x040C0554
+#define BSC_lstat64_extended 0x040C0558
+#define BSC_fstat64_extended 0x040C055C
+#define BSC_getdirentries64 0x040C0560
+#define BSC_statfs64 0x040C0564
+#define BSC_fstatfs64 0x040C0568
+#define BSC_getfsstat64 0x040C056C
+#define BSC_pthread_chdir 0x040C0570
+#define BSC_pthread_fchdir 0x040C0574
+#define BSC_lchown 0x040C05B0
+
+#define BSC_read_nocancel 0x040c0630
+#define BSC_write_nocancel 0x040c0634
+#define BSC_open_nocancel 0x040c0638
+#define BSC_close_nocancel 0x040c063c
+#define BSC_msync_nocancel 0x040c0654
+#define BSC_fcntl_nocancel 0x040c0658
+#define BSC_select_nocancel 0x040c065c
+#define BSC_fsync_nocancel 0x040c0660
+#define BSC_readv_nocancel 0x040c066c
+#define BSC_writev_nocancel 0x040c0670
+#define BSC_pread_nocancel 0x040c0678
+#define BSC_pwrite_nocancel 0x040c067c
+#define BSC_aio_suspend_nocancel 0x40c0694
+#define BSC_guarded_open_np 0x040c06e4
+#define BSC_guarded_open_dprotected_np 0x040c0790
+#define BSC_guarded_close_np 0x040c06e8
+#define BSC_guarded_write_np 0x040c0794
+#define BSC_guarded_pwrite_np 0x040c0798
+#define BSC_guarded_writev_np 0x040c079c
+
+#define BSC_fsgetpath 0x040c06ac
+
+#define BSC_getattrlistbulk 0x040c0734
+
+#define BSC_openat 0x040c073c
+#define BSC_openat_nocancel 0x040c0740
+#define BSC_renameat 0x040c0744
+#define BSC_chmodat 0x040c074c
+#define BSC_chownat 0x040c0750
+#define BSC_fstatat 0x040c0754
+#define BSC_fstatat64 0x040c0758
+#define BSC_linkat 0x040c075c
+#define BSC_unlinkat 0x040c0760
+#define BSC_readlinkat 0x040c0764
+#define BSC_symlinkat 0x040c0768
+#define BSC_mkdirat 0x040c076c
+#define BSC_getattrlistat 0x040c0770
+
+#define BSC_msync_extended 0x040e0104
+#define BSC_pread_extended 0x040e0264
+#define BSC_pwrite_extended 0x040e0268
+#define BSC_guarded_pwrite_extended 0x040e0798
+#define BSC_mmap_extended 0x040e0314
+#define BSC_mmap_extended2 0x040f0314
+
+#define FMT_NOTHING -1
+#define FMT_DEFAULT 0
+#define FMT_FD 1
+#define FMT_FD_IO 2
+#define FMT_FD_2 3
+#define FMT_SOCKET 4
+#define FMT_PGIN 5
+#define FMT_PGOUT 6
+#define FMT_CACHEHIT 7
+#define FMT_DISKIO 8
+#define FMT_LSEEK 9
+#define FMT_PREAD 10
+#define FMT_FTRUNC 11
+#define FMT_TRUNC 12
+#define FMT_SELECT 13
+#define FMT_OPEN 14
+#define FMT_AIO_FSYNC 15
+#define FMT_AIO_RETURN 16
+#define FMT_AIO_SUSPEND 17
+#define FMT_AIO_CANCEL 18
+#define FMT_AIO 19
+#define FMT_LIO_LISTIO 20
+#define FMT_MSYNC 21
+#define FMT_FCNTL 22
+#define FMT_ACCESS 23
+#define FMT_CHMOD 24
+#define FMT_FCHMOD 25
+#define FMT_CHMOD_EXT 26
+#define FMT_FCHMOD_EXT 27
+#define FMT_CHFLAGS 28
+#define FMT_FCHFLAGS 29
+#define FMT_IOCTL 30
+#define FMT_MMAP 31
+#define FMT_UMASK 32
+#define FMT_SENDFILE 33
+#define FMT_IOCTL_SYNC 34
+#define FMT_MOUNT 35
+#define FMT_UNMOUNT 36
+#define FMT_DISKIO_CS 37
+#define FMT_SYNC_DISK_CS 38
+#define FMT_IOCTL_UNMAP 39
+#define FMT_UNMAP_INFO 40
+#define FMT_HFS_update 41
+#define FMT_FLOCK 42
+#define FMT_AT 43
+#define FMT_CHMODAT 44
+#define FMT_OPENAT 45
+#define FMT_RENAMEAT 46
+#define FMT_IOCTL_SYNCCACHE 47
+#define FMT_GUARDED_OPEN 48
+
+#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
+
+#pragma mark global state
+
+ktrace_session_t s;
+bool BC_flag = false;
+bool RAW_flag = false;
+bool wideflag = false;
+bool include_waited_flag = false;
+bool want_kernel_task = true;
+dispatch_source_t stop_timer, sigquit_source, sigpipe_source, sighup_source, sigterm_source, sigwinch_source;
+uint64_t mach_time_of_first_event;
+uint64_t start_time_ns = 0;
+uint64_t end_time_ns = UINT64_MAX;
+unsigned int columns = 0;
+
+/*
+ * Network only or filesystem only output filter
+ * Default of zero means report all activity - no filtering
+ */
+#define FILESYS_FILTER 0x01
+#define NETWORK_FILTER 0x02
+#define EXEC_FILTER 0x08
+#define PATHNAME_FILTER 0x10
+#define DISKIO_FILTER 0x20
+#define DEFAULT_DO_NOT_FILTER 0x00
+
+int filter_mode = DEFAULT_DO_NOT_FILTER;
+bool show_cachehits = false;
+
+#pragma mark syscall lookup table
+
+#define MAX_BSD_SYSCALL 526
+
+struct bsd_syscall {
+ char *sc_name;
+ int sc_format;
+};
+
+#define NORMAL_SYSCALL(name) \
+ [BSC_INDEX(BSC_##name)] = {#name, FMT_DEFAULT}
+
+#define SYSCALL(name, format) \
+ [BSC_INDEX(BSC_##name)] = {#name, format}
+
+#define SYSCALL_NAMED(name, displayname, format) \
+ [BSC_INDEX(BSC_##name)] = {#displayname, format}
+
+#define SYSCALL_WITH_NOCANCEL(name, format) \
+ [BSC_INDEX(BSC_##name)] = {#name, format}, \
+ [BSC_INDEX(BSC_##name##_nocancel)] = {#name, format}
+
+const struct bsd_syscall bsd_syscalls[MAX_BSD_SYSCALL] = {
+ SYSCALL(sendfile, FMT_FD), /* this should be changed to FMT_SENDFILE once we add an extended info trace event */
+ SYSCALL_WITH_NOCANCEL(recvmsg, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(sendmsg, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(recvfrom, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(sendto, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(select, FMT_SELECT),
+ SYSCALL_WITH_NOCANCEL(accept, FMT_FD_2),
+ SYSCALL(socket, FMT_SOCKET),
+ SYSCALL_WITH_NOCANCEL(connect, FMT_FD),
+ SYSCALL(bind, FMT_FD),
+ SYSCALL(listen, FMT_FD),
+ SYSCALL(mmap, FMT_MMAP),
+ NORMAL_SYSCALL(socketpair),
+ NORMAL_SYSCALL(getxattr),
+ NORMAL_SYSCALL(setxattr),
+ NORMAL_SYSCALL(removexattr),
+ NORMAL_SYSCALL(listxattr),
+ NORMAL_SYSCALL(stat),
+ NORMAL_SYSCALL(stat64),
+ NORMAL_SYSCALL(stat_extended),
+ SYSCALL_NAMED(stat64_extended, stat_extended64, FMT_DEFAULT), /* should be stat64_extended ? */
+ SYSCALL(mount, FMT_MOUNT),
+ SYSCALL(unmount, FMT_UNMOUNT),
+ NORMAL_SYSCALL(exit),
+ NORMAL_SYSCALL(execve),
+ NORMAL_SYSCALL(posix_spawn),
+ SYSCALL_WITH_NOCANCEL(open, FMT_OPEN),
+ SYSCALL(open_extended, FMT_OPEN),
+ SYSCALL(guarded_open_np, FMT_GUARDED_OPEN),
+ SYSCALL_NAMED(open_dprotected_np, open_dprotected, FMT_OPEN),
+ SYSCALL(guarded_open_dprotected_np, FMT_GUARDED_OPEN),
+ SYSCALL(dup, FMT_FD_2),
+ SYSCALL(dup2, FMT_FD_2),
+ SYSCALL_WITH_NOCANCEL(close, FMT_FD),
+ SYSCALL(guarded_close_np, FMT_FD),
+ SYSCALL_WITH_NOCANCEL(read, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(write, FMT_FD_IO),
+ SYSCALL(guarded_write_np, FMT_FD_IO),
+ SYSCALL(guarded_pwrite_np, FMT_PREAD),
+ SYSCALL(guarded_writev_np, FMT_FD_IO),
+ SYSCALL(fgetxattr, FMT_FD),
+ SYSCALL(fsetxattr, FMT_FD),
+ SYSCALL(fremovexattr, FMT_FD),
+ SYSCALL(flistxattr, FMT_FD),
+ SYSCALL(fstat, FMT_FD),
+ SYSCALL(fstat64, FMT_FD),
+ SYSCALL(fstat_extended, FMT_FD),
+ SYSCALL(fstat64_extended, FMT_FD),
+ NORMAL_SYSCALL(lstat),
+ NORMAL_SYSCALL(lstat64),
+ NORMAL_SYSCALL(lstat_extended),
+ SYSCALL_NAMED(lstat64_extended, lstat_extended64, FMT_DEFAULT),
+ NORMAL_SYSCALL(link),
+ NORMAL_SYSCALL(unlink),
+ NORMAL_SYSCALL(mknod),
+ SYSCALL(umask, FMT_UMASK),
+ SYSCALL(umask_extended, FMT_UMASK),
+ SYSCALL(chmod, FMT_CHMOD),
+ SYSCALL(chmod_extended, FMT_CHMOD_EXT),
+ SYSCALL(fchmod, FMT_FCHMOD),
+ SYSCALL(fchmod_extended, FMT_FCHMOD_EXT),
+ NORMAL_SYSCALL(chown),
+ NORMAL_SYSCALL(lchown),
+ SYSCALL(fchown, FMT_FD),
+ SYSCALL(access, FMT_ACCESS),
+ NORMAL_SYSCALL(access_extended),
+ NORMAL_SYSCALL(chdir),
+ NORMAL_SYSCALL(pthread_chdir),
+ NORMAL_SYSCALL(chroot),
+ NORMAL_SYSCALL(utimes),
+ SYSCALL_NAMED(delete, delete-Carbon, FMT_DEFAULT),
+ NORMAL_SYSCALL(undelete),
+ NORMAL_SYSCALL(revoke),
+ NORMAL_SYSCALL(fsctl),
+ SYSCALL(ffsctl, FMT_FD),
+ SYSCALL(chflags, FMT_CHFLAGS),
+ SYSCALL(fchflags, FMT_FCHFLAGS),
+ SYSCALL(fchdir, FMT_FD),
+ SYSCALL(pthread_fchdir, FMT_FD),
+ SYSCALL(futimes, FMT_FD),
+ NORMAL_SYSCALL(sync),
+ NORMAL_SYSCALL(symlink),
+ NORMAL_SYSCALL(readlink),
+ SYSCALL_WITH_NOCANCEL(fsync, FMT_FD),
+ SYSCALL(fdatasync, FMT_FD),
+ SYSCALL_WITH_NOCANCEL(readv, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(writev, FMT_FD_IO),
+ SYSCALL_WITH_NOCANCEL(pread, FMT_PREAD),
+ SYSCALL_WITH_NOCANCEL(pwrite, FMT_PREAD),
+ NORMAL_SYSCALL(mkdir),
+ NORMAL_SYSCALL(mkdir_extended),
+ NORMAL_SYSCALL(mkfifo),
+ NORMAL_SYSCALL(mkfifo_extended),
+ NORMAL_SYSCALL(rmdir),
+ NORMAL_SYSCALL(statfs),
+ NORMAL_SYSCALL(statfs64),
+ NORMAL_SYSCALL(getfsstat),
+ NORMAL_SYSCALL(getfsstat64),
+ SYSCALL(fstatfs, FMT_FD),
+ SYSCALL(fstatfs64, FMT_FD),
+ NORMAL_SYSCALL(pathconf),
+ SYSCALL(fpathconf, FMT_FD),
+ SYSCALL(getdirentries, FMT_FD_IO),
+ SYSCALL(getdirentries64, FMT_FD_IO),
+ SYSCALL(lseek, FMT_LSEEK),
+ SYSCALL(truncate, FMT_TRUNC),
+ SYSCALL(ftruncate, FMT_FTRUNC),
+ SYSCALL(flock, FMT_FLOCK),
+ NORMAL_SYSCALL(getattrlist),
+ NORMAL_SYSCALL(setattrlist),
+ SYSCALL(fgetattrlist, FMT_FD),
+ SYSCALL(fsetattrlist, FMT_FD),
+ SYSCALL(getdirentriesattr, FMT_FD),
+ NORMAL_SYSCALL(exchangedata),
+ NORMAL_SYSCALL(rename),
+ NORMAL_SYSCALL(copyfile),
+ NORMAL_SYSCALL(checkuseraccess),
+ NORMAL_SYSCALL(searchfs),
+ SYSCALL(aio_fsync, FMT_AIO_FSYNC),
+ SYSCALL(aio_return, FMT_AIO_RETURN),
+ SYSCALL_WITH_NOCANCEL(aio_suspend, FMT_AIO_SUSPEND),
+ SYSCALL(aio_cancel, FMT_AIO_CANCEL),
+ SYSCALL(aio_error, FMT_AIO),
+ SYSCALL(aio_read, FMT_AIO),
+ SYSCALL(aio_write, FMT_AIO),
+ SYSCALL(lio_listio, FMT_LIO_LISTIO),
+ SYSCALL_WITH_NOCANCEL(msync, FMT_MSYNC),
+ SYSCALL_WITH_NOCANCEL(fcntl, FMT_FCNTL),
+ SYSCALL(ioctl, FMT_IOCTL),
+ NORMAL_SYSCALL(fsgetpath),
+ NORMAL_SYSCALL(getattrlistbulk),
+ SYSCALL_WITH_NOCANCEL(openat, FMT_OPENAT), /* open_nocancel() was previously shown as "open_nocanel" (note spelling) */
+ SYSCALL(renameat, FMT_RENAMEAT),
+ SYSCALL(chmodat, FMT_CHMODAT),
+ SYSCALL(chownat, FMT_AT),
+ SYSCALL(fstatat, FMT_AT),
+ SYSCALL(fstatat64, FMT_AT),
+ SYSCALL(linkat, FMT_AT),
+ SYSCALL(unlinkat, FMT_AT),
+ SYSCALL(readlinkat, FMT_AT),
+ SYSCALL(symlinkat, FMT_AT),
+ SYSCALL(mkdirat, FMT_AT),
+ SYSCALL(getattrlistat, FMT_AT),
+};
+
+static void
+get_screenwidth(void)
+{
+ struct winsize size;
+
+ columns = MAXCOLS;
+
+ if (isatty(STDOUT_FILENO)) {
+ if (ioctl(1, TIOCGWINSZ, &size) != -1) {
+ columns = size.ws_col;
+
+ if (columns > MAXWIDTH)
+ columns = MAXWIDTH;
+ }
+ }
+}
+
+static uint64_t
+mach_to_nano(uint64_t mach)
+{
+ uint64_t nanoseconds = 0;
+ os_assert(ktrace_convert_timestamp_to_nanoseconds(s, mach, &nanoseconds) == 0);
+
+ return nanoseconds;
+}
+
+static void
+exit_usage(void)
+{
+ const char *myname;
+
+ myname = getprogname();
+
+ fprintf(stderr, "Usage: %s [-e] [-w] [-f mode] [-b] [-t seconds] [-R rawfile [-S start_time] [-E end_time]] [pid | cmd [pid | cmd] ...]\n", myname);
+ fprintf(stderr, " -e exclude the specified list of pids from the sample\n");
+ fprintf(stderr, " and exclude fs_usage by default\n");
+ fprintf(stderr, " -w force wider, detailed, output\n");
+ fprintf(stderr, " -f output is based on the mode provided\n");
+ fprintf(stderr, " mode = \"network\" Show network-related events\n");
+ fprintf(stderr, " mode = \"filesys\" Show filesystem-related events\n");
+ fprintf(stderr, " mode = \"pathname\" Show only pathname-related events\n");
+ fprintf(stderr, " mode = \"exec\" Show only exec and spawn events\n");
+ fprintf(stderr, " mode = \"diskio\" Show only disk I/O events\n");
+ fprintf(stderr, " mode = \"cachehit\" In addition, show cache hits\n");
+ fprintf(stderr, " -b annotate disk I/O events with BootCache info (if available)\n");
+ fprintf(stderr, " -t specifies timeout in seconds (for use in automated tools)\n");
+ fprintf(stderr, " -R specifies a raw trace file to process\n");
+ fprintf(stderr, " -S if -R is specified, selects a start point in microseconds\n");
+ fprintf(stderr, " -E if -R is specified, selects an end point in microseconds\n");
+ fprintf(stderr, " pid selects process(s) to sample\n");
+ fprintf(stderr, " cmd selects process(s) matching command string to sample\n");
+ fprintf(stderr, "By default (no options) the following processes are excluded from the output:\n");
+ fprintf(stderr, "fs_usage, Terminal, telnetd, sshd, rlogind, tcsh, csh, sh\n\n");
+
+ exit(1);
+}
+
+static void fs_usage_cleanup(const char *message)
+{
+ if (s){
+ ktrace_session_destroy(s);
+ }
+
+ fprintf(stderr, "Cleaning up tracing state because of %s\n", message);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char ch;
+ int rv;
+ bool exclude_pids = false;
+ uint64_t time_limit_ns = 0;
+
+ os_set_crash_callback(&fs_usage_cleanup);
+
+ get_screenwidth();
+
+ s = ktrace_session_create();
+ os_assert(s != NULL);
+ (void)ktrace_ignore_process_filter_for_event(s, P_WrData);
+ (void)ktrace_ignore_process_filter_for_event(s, P_RdData);
+ (void)ktrace_ignore_process_filter_for_event(s, P_WrMeta);
+ (void)ktrace_ignore_process_filter_for_event(s, P_RdMeta);
+ (void)ktrace_ignore_process_filter_for_event(s, P_PgOut);
+ (void)ktrace_ignore_process_filter_for_event(s, P_PgIn);
+
+ while ((ch = getopt(argc, argv, "bewf:R:S:E:t:W")) != -1) {
+ switch (ch) {
+ case 'e':
+ exclude_pids = true;
+ break;
+
+ case 'w':
+ wideflag = 1;
+ columns = MAX_WIDE_MODE_COLS;
+ break;
+
+ case 'W':
+ include_waited_flag = true;
+ break;
+
+ case 'f':
+ if (!strcmp(optarg, "network"))
+ filter_mode |= NETWORK_FILTER;
+ else if (!strcmp(optarg, "filesys"))
+ filter_mode |= FILESYS_FILTER;
+ else if (!strcmp(optarg, "cachehit"))
+ show_cachehits = true;
+ else if (!strcmp(optarg, "exec"))
+ filter_mode |= EXEC_FILTER;
+ else if (!strcmp(optarg, "pathname"))
+ filter_mode |= PATHNAME_FILTER;
+ else if (!strcmp(optarg, "diskio"))
+ filter_mode |= DISKIO_FILTER;
+
+ break;
+
+ case 'b':
+ BC_flag = true;
+ break;
+
+ case 't':
+ time_limit_ns = (uint64_t)(NSEC_PER_SEC * atof(optarg));
+ if (time_limit_ns == 0) {
+ fprintf(stderr, "ERROR: could not set time limit to %s\n",
+ optarg);
+ exit(1);
+ }
+ break;
+
+ case 'R':
+ RAW_flag = true;
+ rv = ktrace_set_file(s, optarg);
+ if (rv) {
+ fprintf(stderr, "ERROR: reading trace from '%s' failed (%s)\n", optarg, strerror(errno));
+ exit(1);
+ }
+ break;
+
+ case 'S':
+ start_time_ns = NSEC_PER_SEC * atof(optarg);
+ break;
+
+ case 'E':
+ end_time_ns = NSEC_PER_SEC * atof(optarg);
+ break;
+
+ default:
+ exit_usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (time_limit_ns > 0 && RAW_flag) {
+ fprintf(stderr, "NOTE: time limit ignored when a raw file is specified\n");
+ time_limit_ns = 0;
+ }
+
+ if (!RAW_flag) {
+ if (geteuid() != 0) {
+ fprintf(stderr, "'fs_usage' must be run as root...\n");
+ exit(1);
+ }
+
+ /*
+ * ktrace can't both *in*clude and *ex*clude pids, so: if we are
+ * already excluding pids, or if we are not explicitly including
+ * or excluding any pids, then exclude the defaults.
+ *
+ * if on the other hand we are explicitly including pids, we'll
+ * filter the defaults out naturally.
+ */
+ if (exclude_pids || argc == 0) {
+ ktrace_exclude_process(s, "fs_usage");
+ ktrace_exclude_process(s, "Terminal");
+ ktrace_exclude_process(s, "telnetd");
+ ktrace_exclude_process(s, "telnet");
+ ktrace_exclude_process(s, "sshd");
+ ktrace_exclude_process(s, "rlogind");
+ ktrace_exclude_process(s, "tcsh");
+ ktrace_exclude_process(s, "csh");
+ ktrace_exclude_process(s, "sh");
+ ktrace_exclude_process(s, "zsh");
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ ktrace_exclude_process(s, "dropbear");
+#endif /* (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) */
+ }
+ }
+
+ /*
+ * If we're *in*cluding processes, also *in*clude the kernel_task, which
+ * issues trace points when disk I/Os complete. But set a flag for us to
+ * avoid showing events attributed to the kernel_task.
+ *
+ * If the user actually wants to those events, we'll change that flag in
+ * the loop below.
+ */
+ if (argc > 0 && !exclude_pids) {
+ ktrace_filter_pid(s, 0);
+ want_kernel_task = false;
+ }
+
+ /*
+ * Process the list of specified pids, and in/exclude them as
+ * appropriate.
+ */
+ while (argc > 0) {
+ pid_t pid;
+ char *name;
+ char *endptr;
+
+ name = argv[0];
+ pid = (pid_t)strtoul(name, &endptr, 10);
+
+ if (*name != '\0' && *endptr == '\0') {
+ if (exclude_pids) {
+ rv = ktrace_exclude_pid(s, pid);
+ } else {
+ if (pid == 0)
+ want_kernel_task = true;
+ else
+ rv = ktrace_filter_pid(s, pid);
+ }
+ } else {
+ if (exclude_pids) {
+ rv = ktrace_exclude_process(s, name);
+ } else {
+ if (!strcmp(name, "kernel_task"))
+ want_kernel_task = true;
+ else
+ rv = ktrace_filter_process(s, name);
+ }
+ }
+
+ if (rv == EINVAL) {
+ fprintf(stderr, "ERROR: cannot both include and exclude simultaneously\n");
+ exit(1);
+ } else {
+ os_assert(!rv);
+ }
+
+ argc--;
+ argv++;
+ }
+
+ /* provides SIGINT, SIGHUP, SIGPIPE, SIGTERM handlers */
+ ktrace_set_signal_handler(s);
+
+ ktrace_set_completion_handler(s, ^{
+ exit(0);
+ });
+
+ signal(SIGWINCH, SIG_IGN);
+ sigwinch_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGWINCH, 0, dispatch_get_main_queue());
+ dispatch_source_set_event_handler(sigwinch_source, ^{
+ if (!wideflag)
+ get_screenwidth();
+ });
+ dispatch_activate(sigwinch_source);
+
+ init_shared_cache_mapping();
+
+ cache_disk_names();
+
+ setup_ktrace_callbacks();
+
+ ktrace_set_dropped_events_handler(s, ^{
+ fprintf(stderr, "fs_usage: buffer overrun, events generated too quickly\n");
+
+ /* clear any state that is now potentially invalid */
+
+ event_delete_all();
+ fd_clear_all();
+ meta_delete_all();
+ });
+
+ ktrace_set_default_event_names_enabled(KTRACE_FEATURE_DISABLED);
+ ktrace_set_execnames_enabled(s, KTRACE_FEATURE_LAZY);
+ ktrace_set_vnode_paths_enabled(s, true);
+ /* no need to symbolicate addresses */
+ ktrace_set_uuid_map_enabled(s, KTRACE_FEATURE_DISABLED);
+
+ rv = ktrace_start(s, dispatch_get_main_queue());
+
+ if (rv) {
+ perror("ktrace_start");
+ exit(1);
+ }
+
+ if (time_limit_ns > 0) {
+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, time_limit_ns),
+ dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0),
+ ^{
+ ktrace_end(s, 0);
+ });
+ }
+
+ dispatch_main();
+
+ return 0;
+}
+
+void
+setup_ktrace_callbacks(void)
+{
+ ktrace_events_subclass(s, DBG_MACH, DBG_MACH_EXCP_SC, ^(ktrace_event_t event) {
+ int type;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ if (type == MSC_map_fd) {
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ event_exit("map_fd", type, event, FMT_FD);
+ }
+ }
+ });
+
+ ktrace_events_subclass(s, DBG_MACH, DBG_MACH_VM, ^(ktrace_event_t event) {
+ th_info_t ti;
+ unsigned int type;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ if (type != MACH_pageout && type != MACH_vmfault)
+ return;
+
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ switch (type) {
+ case MACH_pageout:
+ if (event->arg2)
+ event_exit("PAGE_OUT_ANON", type, event, FMT_PGOUT);
+ else
+ event_exit("PAGE_OUT_FILE", type, event, FMT_PGOUT);
+
+ break;
+
+ case MACH_vmfault:
+ if (event->arg4 == DBG_PAGEIN_FAULT)
+ event_exit("PAGE_IN", type, event, FMT_PGIN);
+ else if (event->arg4 == DBG_PAGEINV_FAULT)
+ event_exit("PAGE_IN_FILE", type, event, FMT_PGIN);
+ else if (event->arg4 == DBG_PAGEIND_FAULT)
+ event_exit("PAGE_IN_ANON", type, event, FMT_PGIN);
+ else if (event->arg4 == DBG_CACHE_HIT_FAULT)
+ event_exit("CACHE_HIT", type, event, FMT_CACHEHIT);
+ else if ((ti = event_find(event->threadid, type)))
+ event_delete(ti);
+
+ break;
+
+ default:
+ abort();
+ }
+ }
+ });
+
+ if (include_waited_flag || RAW_flag) {
+ ktrace_events_subclass(s, DBG_MACH, DBG_MACH_SCHED, ^(ktrace_event_t event) {
+ int type;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ switch (type) {
+ case MACH_idle:
+ case MACH_sched:
+ case MACH_stkhandoff:
+ event_mark_thread_waited(event->threadid);
+ }
+ });
+ }
+
+ ktrace_events_subclass(s, DBG_FSYSTEM, DBG_FSRW, ^(ktrace_event_t event) {
+ th_info_t ti;
+ int type;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ switch (type) {
+ case HFS_modify_block_end:
+ /*
+ * the expected path here is as follows:
+ * enter syscall
+ * look up a path, which gets stored in ti->vnode / ti->pathname
+ * modify a metadata block -- we assume the modification has something to do with the path that was looked up
+ * leave syscall
+ * ...
+ * later, someone writes that metadata block; the last path associated with it is attributed
+ */
+ if ((ti = event_find(event->threadid, 0))) {
+ if (ti->newest_pathname)
+ meta_add_name(event->arg2, ti->newest_pathname);
+ }
+
+ break;
+
+ case VFS_LOOKUP:
+ if (event->debugid & DBG_FUNC_START) {
+ if ((ti = event_find(event->threadid, 0)) && !ti->vnodeid) {
+ ti->vnodeid = event->arg1;
+ }
+ }
+
+ /* it can be both start and end */
+
+ if (event->debugid & DBG_FUNC_END) {
+ if ((ti = event_find(event->threadid, 0)) && ti->vnodeid) {
+ const char *pathname;
+
+ pathname = ktrace_get_path_for_vp(s, ti->vnodeid);
+
+ ti->vnodeid = 0;
+
+ if (pathname) {
+ if (ti->pathname[0] == '\0') {
+ strncpy(ti->pathname, pathname, MAXPATHLEN);
+ ti->newest_pathname = ti->pathname;
+ } else if (ti->pathname2[0] == '\0') {
+ strncpy(ti->pathname2, pathname, MAXPATHLEN);
+ ti->newest_pathname = ti->pathname2;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+
+ if (type != Throttled && type != HFS_update)
+ return;
+
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ switch (type) {
+ case Throttled:
+ event_exit(" THROTTLED", type, event, FMT_NOTHING);
+ break;
+
+ case HFS_update:
+ event_exit(" HFS_update", type, event, FMT_HFS_update);
+ break;
+
+ default:
+ abort();
+ }
+ }
+ });
+
+ ktrace_events_subclass(s, DBG_FSYSTEM, DBG_DKRW, ^(ktrace_event_t event) {
+ struct diskio *dio;
+ unsigned int type;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ if ((type & P_DISKIO_MASK) == P_DISKIO) {
+ diskio_start(type, event->arg1, event->arg2, event->arg3, event->arg4, event);
+ } else if ((type & P_DISKIO_MASK) == P_DISKIO_DONE) {
+ if ((dio = diskio_complete(event->arg1, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
+ dio->vnodeid = event->arg2;
+ diskio_print(dio);
+ diskio_free(dio);
+ }
+ }
+ });
+
+ ktrace_events_subclass(s, DBG_FSYSTEM, DBG_IOCTL, ^(ktrace_event_t event) {
+ th_info_t ti;
+ int type;
+ pid_t pid;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ switch (type) {
+ case SPEC_unmap_info:
+ pid = ktrace_get_pid_for_thread(s, event->threadid);
+
+ if (check_filter_mode(pid, NULL, SPEC_unmap_info, 0, 0, "SPEC_unmap_info"))
+ format_print(NULL, " TrimExtent", event, type, FMT_UNMAP_INFO, event->timestamp, event->timestamp, 0, "", NULL);
+
+ break;
+
+ case SPEC_ioctl:
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ if (event->arg2 == DKIOCSYNCHRONIZECACHE)
+ event_exit("IOCTL", type, event, FMT_IOCTL_SYNCCACHE);
+ else if (event->arg2 == DKIOCUNMAP)
+ event_exit("IOCTL", type, event, FMT_IOCTL_UNMAP);
+ else if (event->arg2 == DKIOCSYNCHRONIZE && (event->debugid & DBG_FUNC_ALL) == DBG_FUNC_NONE)
+ event_exit("IOCTL", type, event, FMT_IOCTL_SYNC);
+ else if ((ti = event_find(event->threadid, type)))
+ event_delete(ti);
+ }
+
+ break;
+ }
+ });
+
+ if (BC_flag || RAW_flag) {
+ ktrace_events_subclass(s, DBG_FSYSTEM, DBG_BOOTCACHE, ^(ktrace_event_t event) {
+ struct diskio *dio;
+ unsigned int type;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ switch (type) {
+ case BC_IO_HIT:
+ case BC_IO_HIT_STALLED:
+ case BC_IO_MISS:
+ case BC_IO_MISS_CUT_THROUGH:
+ case BC_PLAYBACK_IO:
+ if ((dio = diskio_find(event->arg1)) != NULL)
+ dio->bc_info = type;
+ }
+ });
+ }
+
+ void (^bsd_sc_proc_cb)(ktrace_event_t event) = ^(ktrace_event_t event) {
+ int type, index;
+ pid_t pid;
+
+ type = event->debugid & KDBG_EVENTID_MASK;
+
+ switch (type) {
+ case BSC_exit: /* see below */
+ return;
+
+ case proc_exit:
+ event->arg1 = event->arg2 >> 8;
+ type = BSC_exit;
+
+ pid = ktrace_get_pid_for_thread(s, event->threadid);
+ fd_clear_pid(pid);
+
+ break;
+
+ case BSC_mmap:
+ if (event->arg4 & MAP_ANON)
+ return;
+
+ break;
+ }
+
+ if ((index = BSC_INDEX(type)) >= MAX_BSD_SYSCALL)
+ return;
+
+ if (!bsd_syscalls[index].sc_name)
+ return;
+
+ if (event->debugid & DBG_FUNC_START) {
+ event_enter(type, event);
+ } else {
+ event_exit(bsd_syscalls[index].sc_name, type, event, bsd_syscalls[index].sc_format);
+ }
+ };
+
+ ktrace_events_subclass(s, DBG_BSD, DBG_BSD_EXCP_SC, bsd_sc_proc_cb);
+ ktrace_events_subclass(s, DBG_BSD, DBG_BSD_PROC, bsd_sc_proc_cb);
+
+ ktrace_events_range(s, KDBG_EVENTID(DBG_BSD, DBG_BSD_SC_EXTENDED_INFO, 0), KDBG_EVENTID(DBG_BSD, DBG_BSD_SC_EXTENDED_INFO2 + 1, 0), ^(ktrace_event_t event) {
+ extend_syscall(event->threadid, event->debugid & KDBG_EVENTID_MASK, event);
+ });
+
+ ktrace_events_subclass(s, DBG_CORESTORAGE, DBG_CS_IO, ^(ktrace_event_t event) {
+ // the usual DBG_FUNC_START/END does not work for i/o since it will
+ // return on a different thread, this code uses the P_CS_IO_Done (0x4) bit
+ // instead. the trace command doesn't know how handle either method
+ // (unmatched start/end or 0x4) but works a little better this way.
+
+ struct diskio *dio;
+ int cs_type = event->debugid & P_CS_Type_Mask; // strip out the done bit
+ bool start = (event->debugid & P_CS_IO_Done) != P_CS_IO_Done;
+
+ switch (cs_type) {
+ case P_CS_ReadChunk:
+ case P_CS_WriteChunk:
+ case P_CS_MetaRead:
+ case P_CS_MetaWrite:
+ if (start) {
+ diskio_start(cs_type, event->arg2, event->arg1, event->arg3, event->arg4, event);
+ } else {
+ if ((dio = diskio_complete(event->arg2, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
+ diskio_print(dio);
+ diskio_free(dio);
+ }
+ }
+
+ break;
+ case P_CS_TransformRead:
+ case P_CS_TransformWrite:
+ case P_CS_MigrationRead:
+ case P_CS_MigrationWrite:
+ if (start) {
+ diskio_start(cs_type, event->arg2, CS_DEV, event->arg3, event->arg4, event);
+ } else {
+ if ((dio = diskio_complete(event->arg2, event->arg4, event->arg3, event->threadid, event->timestamp, event->walltime))) {
+ diskio_print(dio);
+ diskio_free(dio);
+ }
+ }
+
+ break;
+ }
+ });
+
+ ktrace_events_subclass(s, DBG_CORESTORAGE, 1 /* DBG_CS_SYNC */, ^(ktrace_event_t event) {
+ int cs_type = event->debugid & P_CS_Type_Mask; // strip out the done bit
+ bool start = (event->debugid & P_CS_IO_Done) != P_CS_IO_Done;
+
+ if (cs_type == P_CS_SYNC_DISK) {
+ if (start) {
+ event_enter(cs_type, event);
+ } else {
+ event_exit(" SyncCacheCS", cs_type, event, FMT_SYNC_DISK_CS);
+ }
+ }
+ });
+}
+
+static void
+extend_syscall_rw(th_info_t ti, ktrace_event_t event)
+{
+ ti->arg1 = event->arg1; /* the fd */
+ ti->arg2 = event->arg2; /* nbytes */
+ ti->arg3 = event->arg3; /* top half offset */
+ ti->arg4 = event->arg4; /* bottom half offset */
+}
+
+/*
+ * Handle system call extended trace data.
+ * pread and pwrite:
+ * Wipe out the kd args that were collected upon syscall_entry
+ * because it is the extended info that we really want, and it
+ * is all we really need.
+ */
+void
+extend_syscall(uint64_t thread, int type, ktrace_event_t event)
+{
+ th_info_t ti;
+
+ switch (type) {
+ case BSC_mmap_extended:
+ if ((ti = event_find(thread, BSC_mmap)) == NULL) {
+ return;
+ }
+
+ ti->arg8 = ti->arg3; /* save protection */
+ ti->arg1 = event->arg1; /* the fd */
+ ti->arg3 = event->arg2; /* bottom half address */
+ ti->arg5 = event->arg3; /* bottom half size */
+ break;
+
+ case BSC_mmap_extended2:
+ if ((ti = event_find(thread, BSC_mmap)) == NULL)
+ return;
+
+ ti->arg2 = event->arg1; /* top half address */
+ ti->arg4 = event->arg2; /* top half size */
+ ti->arg6 = event->arg3; /* top half file offset */
+ ti->arg7 = event->arg4; /* bottom half file offset */
+ break;
+
+ case BSC_msync_extended:
+ if ((ti = event_find(thread, BSC_msync)) == NULL) {
+ if ((ti = event_find(thread, BSC_msync_nocancel)) == NULL) {
+ return;
+ }
+ }
+
+ ti->arg4 = event->arg1; /* top half address */
+ ti->arg5 = event->arg2; /* top half size */
+ break;
+
+ case BSC_pread_extended:
+ if ((ti = event_find(thread, BSC_pread)) == NULL) {
+ if ((ti = event_find(thread, BSC_pread_nocancel)) == NULL) {
+ return;
+ }
+ }
+
+ extend_syscall_rw(ti, event);
+ break;
+
+ case BSC_pwrite_extended:
+ if ((ti = event_find(thread, BSC_pwrite)) == NULL) {
+ if ((ti = event_find(thread, BSC_pwrite_nocancel)) == NULL) {
+ return;
+ }
+ }
+
+ extend_syscall_rw(ti, event);
+ break;
+
+ case BSC_guarded_pwrite_extended:
+ if ((ti = event_find(thread, BSC_guarded_pwrite_np)) == NULL) {
+ return;
+ }
+
+ extend_syscall_rw(ti, event);
+ break;
+ }
+}
+
+#pragma mark printing routines
+
+static void
+get_mode_nibble(char *buf, uint64_t smode, uint64_t special, char x_on, char x_off)
+{
+ if (smode & 04)
+ buf[0] = 'r';
+
+ if (smode & 02)
+ buf[1] = 'w';
+
+ if (smode & 01) {
+ if (special)
+ buf[2] = x_on;
+ else
+ buf[2] = 'x';
+ } else {
+ if (special)
+ buf[2] = x_off;
+ }
+}
+
+static void
+get_mode_string(uint64_t mode, char *buf)
+{
+ memset(buf, '-', 9);
+ buf[9] = '\0';
+
+ get_mode_nibble(&buf[6], mode, (mode & 01000), 't', 'T');
+ get_mode_nibble(&buf[3], (mode>>3), (mode & 02000), 's', 'S');
+ get_mode_nibble(&buf[0], (mode>>6), (mode & 04000), 's', 'S');
+}
+
+static int
+clip_64bit(char *s, uint64_t value)
+{
+ int clen = 0;
+
+ if ( (value & 0xff00000000000000LL) )
+ clen = printf("%s0x%16.16qx", s, value);
+ else if ( (value & 0x00ff000000000000LL) )
+ clen = printf("%s0x%14.14qx ", s, value);
+ else if ( (value & 0x0000ff0000000000LL) )
+ clen = printf("%s0x%12.12qx ", s, value);
+ else if ( (value & 0x000000ff00000000LL) )
+ clen = printf("%s0x%10.10qx ", s, value);
+ else
+ clen = printf("%s0x%8.8qx ", s, value);
+
+ return clen;
+}
+
+/*
+ * ret = 1 means print the entry
+ * ret = 0 means don't print the entry
+ */
+
+/*
+ * meaning of filter flags:
+ * cachehit turn on display of CACHE_HIT events (which are filtered out by default)
+ *
+ * exec show exec/posix_spawn
+ * pathname show events with a pathname and close()
+ * diskio show disk I/Os
+ * filesys show filesystem events
+ * network show network events
+ *
+ * filters may be combined; default is all filters on (except cachehit)
+ */
+bool
+check_filter_mode(pid_t pid, th_info_t ti, uint64_t type, int error, int retval, char *sc_name)
+{
+ bool ret = false;
+ int network_fd_isset = 0;
+ uint64_t fd;
+
+ /* cachehit is special -- it's not on by default */
+ if (sc_name[0] == 'C' && !strcmp(sc_name, "CACHE_HIT")) {
+ return show_cachehits;
+ }
+
+ if (filter_mode == DEFAULT_DO_NOT_FILTER)
+ return true;
+
+ if (filter_mode & DISKIO_FILTER) {
+ if ((type & P_DISKIO_MASK) == P_DISKIO)
+ return true;
+
+ if (type == Throttled)
+ return true;
+ }
+
+ if (filter_mode & EXEC_FILTER) {
+ if (type == BSC_execve || type == BSC_posix_spawn)
+ return true;
+ }
+
+ if (filter_mode & PATHNAME_FILTER) {
+ if (ti && ti->pathname[0])
+ return true;
+
+ if (type == BSC_close || type == BSC_close_nocancel ||
+ type == BSC_guarded_close_np)
+ return true;
+ }
+
+ if (!ti) {
+ if (filter_mode & FILESYS_FILTER)
+ return true;
+
+ return 0;
+ }
+
+ switch (type) {
+ case BSC_close:
+ case BSC_close_nocancel:
+ case BSC_guarded_close_np:
+ fd = ti->arg1;
+ network_fd_isset = fd_is_network(pid, fd);
+
+ if (error == 0)
+ fd_set_is_network(pid, fd, false);
+
+ if (network_fd_isset) {
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
+ } else {
+ if (filter_mode & FILESYS_FILTER)
+ ret = true;
+ }
+
+ break;
+
+ case BSC_read:
+ case BSC_write:
+ case BSC_read_nocancel:
+ case BSC_write_nocancel:
+ /*
+ * we don't care about error in these cases
+ */
+ fd = ti->arg1;
+
+ if (fd_is_network(pid, fd)) {
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
+ } else if (filter_mode & FILESYS_FILTER) {
+ ret = true;
+ }
+
+ break;
+
+ case BSC_accept:
+ case BSC_accept_nocancel:
+ case BSC_socket:
+ fd = retval;
+
+ if (error == 0)
+ fd_set_is_network(pid, fd, true);
+
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
+
+ break;
+
+ case BSC_recvfrom:
+ case BSC_sendto:
+ case BSC_recvmsg:
+ case BSC_sendmsg:
+ case BSC_connect:
+ case BSC_bind:
+ case BSC_listen:
+ case BSC_sendto_nocancel:
+ case BSC_recvfrom_nocancel:
+ case BSC_recvmsg_nocancel:
+ case BSC_sendmsg_nocancel:
+ case BSC_connect_nocancel:
+ fd = ti->arg1;
+
+ if (error == 0)
+ fd_set_is_network(pid, fd, true);
+
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
+
+ break;
+
+ case BSC_select:
+ case BSC_select_nocancel:
+ case BSC_socketpair:
+ /*
+ * Cannot determine info about file descriptors
+ */
+ if (filter_mode & NETWORK_FILTER)
+ ret = true;
+
+ break;
+
+ case BSC_dup:
+ case BSC_dup2:
+ /*
+ * We track these cases for fd state only
+ */
+ fd = ti->arg1;
+
+ if (error == 0 && fd_is_network(pid, fd)) {
+ /*
+ * then we are duping a socket descriptor
+ */
+ fd = retval; /* the new fd */
+ fd_set_is_network(pid, fd, true);
+ }
+
+ break;
+
+ default:
+ if (filter_mode & FILESYS_FILTER)
+ ret = true;
+
+ break;
+ }
+
+ return ret;
+}
+
+int
+print_open(ktrace_event_t event, uint64_t flags)
+{
+ char mode[] = {
+ '_',
+ '_',
+ (flags & O_CREAT) ? 'C' : '_',
+ (flags & O_APPEND) ? 'A' : '_',
+ (flags & O_TRUNC) ? 'T' : '_',
+ (flags & O_EXCL) ? 'E' : '_',
+ (flags & O_NONBLOCK) ? 'N' : '_',
+ (flags & O_SHLOCK) ? 'l' : (flags & O_EXLOCK) ? 'L' : '_',
+ (flags & O_NOFOLLOW) ? 'F' : '_',
+ (flags & O_SYMLINK) ? 'S' : '_',
+ (flags & O_EVTONLY) ? 'V' : '_',
+ (flags & O_CLOEXEC) ? 'X' : '_',
+ '\0',
+ };
+
+ if (flags & O_RDWR) {
+ mode[0] = 'R';
+ mode[1] = 'W';
+ } else if (flags & O_WRONLY) {
+ mode[1] = 'W';
+ } else {
+ mode[0] = 'R';
+ }
+
+ if (event->arg1) {
+ return printf(" [%3d] (%s) ", (int)event->arg1, mode);
+ } else {
+ return printf(" F=%-3d (%s) ", (int)event->arg2, mode);
+ }
+}
+
+/*
+ * called from:
+ *
+ * exit_event() (syscalls etc.)
+ * print_diskio() (disk I/Os)
+ * block callback for TrimExtent
+ */
+void
+format_print(th_info_t ti, char *sc_name, ktrace_event_t event,
+ uint64_t type, int format, uint64_t now, uint64_t stime,
+ int waited, const char *pathname, struct diskio *dio)
+{
+ uint64_t secs, usecs;
+ int nopadding = 0;
+ static time_t last_walltime_secs = -1;
+ const char *command_name;
+ pid_t pid;
+ int len = 0;
+ int clen = 0;
+ size_t tlen = 0;
+ uint64_t class;
+ uint64_t user_addr;
+ uint64_t user_size;
+ char *framework_name;
+ char *framework_type;
+ char *p1;
+ char *p2;
+ char buf[2 * PATH_MAX + 64];
+ char cs_diskname[32];
+ uint64_t threadid;
+ struct timeval now_walltime;
+
+ static char timestamp[32];
+ static size_t timestamp_len = 0;
+
+ if (!mach_time_of_first_event)
+ mach_time_of_first_event = now;
+
+ if (format == FMT_DISKIO || format == FMT_DISKIO_CS) {
+ os_assert(dio);
+ } else {
+ os_assert(event);
+
+ if (format != FMT_UNMAP_INFO)
+ os_assert(ti);
+ }
+
+ /* <rdar://problem/19852325> Filter out WindowServer/xcpm ioctls in fs_usage */
+ if (type == BSC_ioctl && ti->arg2 == 0xffffffffc030581dUL)
+ return;
+
+ /* honor -S and -E */
+ if (RAW_flag) {
+ uint64_t relative_time_ns;
+
+ relative_time_ns = mach_to_nano(now - mach_time_of_first_event);
+
+ if (relative_time_ns < start_time_ns || relative_time_ns > end_time_ns)
+ return;
+ }
+
+ class = KDBG_EXTRACT_CLASS(type);
+
+ if (dio) {
+ command_name = dio->issuing_command;
+ threadid = dio->issuing_thread;
+ pid = dio->issuing_pid;
+ now_walltime = dio->completed_walltime;
+ } else {
+ if (ti && ti->command[0] != '\0') {
+ command_name = ti->command;
+ threadid = ti->thread;
+ pid = ti->pid;
+ } else {
+ command_name = ktrace_get_execname_for_thread(s, event->threadid);
+ threadid = event->threadid;
+ pid = ktrace_get_pid_for_thread(s, event->threadid);
+ }
+
+ now_walltime = event->walltime;
+ }
+
+ if (!want_kernel_task && pid == 0)
+ return;
+
+ if (!command_name)
+ command_name = "";
+
+ os_assert(now_walltime.tv_sec || now_walltime.tv_usec);
+
+ /* try and reuse the timestamp string */
+ if (last_walltime_secs != now_walltime.tv_sec) {
+ timestamp_len = strftime(timestamp, sizeof (timestamp), "%H:%M:%S", localtime(&now_walltime.tv_sec));
+ last_walltime_secs = now_walltime.tv_sec;
+ }
+
+ if (columns > MAXCOLS || wideflag) {
+ tlen = timestamp_len;
+ nopadding = 0;
+
+ sprintf(&timestamp[tlen], ".%06d", now_walltime.tv_usec);
+ tlen += 7;
+
+ timestamp[tlen] = '\0';
+ } else {
+ nopadding = 1;
+ }
+
+ clen = printf("%s %-17.17s", timestamp, sc_name);
+
+ framework_name = NULL;
+
+ if (columns > MAXCOLS || wideflag) {
+ off_t offset_reassembled = 0LL;
+
+ switch (format) {
+ case FMT_NOTHING:
+ clen += printf(" ");
+ break;
+
+ case FMT_AT:
+ case FMT_RENAMEAT:
+ case FMT_DEFAULT:
+ /*
+ * pathname based system calls or
+ * calls with no fd or pathname (i.e. sync)
+ */
+ if (event->arg1)
+ clen += printf(" [%3d] ", (int)event->arg1);
+ else
+ clen += printf(" ");
+
+ break;
+
+ case FMT_FD:
+ /*
+ * fd based system call... no I/O
+ */
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
+
+ break;
+
+ case FMT_FD_2:
+ /*
+ * accept, dup, dup2
+ */
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d F=%-3d", (int)ti->arg1, (int)event->arg2);
+
+ break;
+
+ case FMT_FD_IO:
+ /*
+ * system calls with fd's that return an I/O completion count
+ */
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d B=0x%-6" PRIx64, (int)ti->arg1, (uint64_t)event->arg2);
+
+ break;
+
+ case FMT_PGIN:
+ /*
+ * pagein
+ */
+ user_addr = ((uint64_t)event->arg1 << 32) | (uint32_t)event->arg2;
+
+ lookup_name(user_addr, &framework_type, &framework_name);
+ clen += clip_64bit(" A=", user_addr);
+ break;
+
+ case FMT_CACHEHIT:
+ /*
+ * cache hit
+ */
+ user_addr = ((uint64_t)event->arg1 << 32) | (uint32_t)event->arg2;
+
+ lookup_name(user_addr, &framework_type, &framework_name);
+ clen += clip_64bit(" A=", user_addr);
+ break;
+
+ case FMT_PGOUT:
+ /*
+ * pageout
+ */
+ clen += printf(" B=0x%-8" PRIx64, (uint64_t)event->arg1);
+ break;
+
+ case FMT_HFS_update:
+ {
+ static const struct {
+ int flag;
+ char ch;
+ } hfsflags[] = {
+ { DBG_HFS_UPDATE_SKIPPED, 'S' },
+ { DBG_HFS_UPDATE_FORCE, 'F' },
+ { DBG_HFS_UPDATE_MODIFIED, 'M' },
+ { DBG_HFS_UPDATE_MINOR, 'N' },
+ { DBG_HFS_UPDATE_DATEADDED, 'd' },
+ { DBG_HFS_UPDATE_CHGTIME, 'c' },
+ { DBG_HFS_UPDATE_ACCTIME, 'a' },
+ { DBG_HFS_UPDATE_MODTIME, 'm' },
+ };
+ size_t i;
+ int flagcount;
+ char *sbuf;
+ int sflag = (int)event->arg2;
+
+ flagcount = sizeof (hfsflags) / sizeof (*hfsflags);
+ sbuf = malloc(flagcount + 1);
+
+ for (i = 0; i < flagcount; i++) {
+ if (sflag & hfsflags[i].flag) {
+ sbuf[i] = hfsflags[i].ch;
+ } else {
+ sbuf[i] = '_';
+ }
+ }
+
+ sbuf[flagcount] = '\0';
+
+ clen += printf(" %*s(%s) ", 17 - flagcount, "", sbuf);
+
+ free(sbuf);
+
+ pathname = ktrace_get_path_for_vp(s, event->arg1);
+
+ if (!pathname)
+ pathname = "";
+
+ nopadding = 1;
+
+ break;
+ }
+
+ case FMT_DISKIO:
+ /*
+ * physical disk I/O
+ */
+ if (dio->io_errno) {
+ clen += printf(" D=0x%8.8" PRIx64 " [%3d]", dio->blkno, (int)dio->io_errno);
+ } else {
+ if (BC_flag)
+ clen += printf(" D=0x%8.8" PRIx64 " B=0x%-6" PRIx64 " BC:%s /dev/%s ", dio->blkno, dio->iosize, BC_STR(dio->bc_info), find_disk_name(dio->dev));
+ else
+ clen += printf(" D=0x%8.8" PRIx64 " B=0x%-6" PRIx64 " /dev/%s ", dio->blkno, dio->iosize, find_disk_name(dio->dev));
+
+ if (dio->is_meta) {
+ if (!(type & P_DISKIO_READ)) {
+ pathname = meta_find_name(dio->blkno);
+ }
+ } else {
+ pathname = ktrace_get_path_for_vp(s, dio->vnodeid);
+
+ if (!pathname)
+ pathname = "";
+ }
+
+ nopadding = 1;
+ }
+
+ break;
+
+ case FMT_DISKIO_CS:
+ /*
+ * physical disk I/O
+ */
+ if (dio->io_errno)
+ clen += printf(" D=0x%8.8" PRIx64 " [%3" PRIu64 "]", dio->blkno, dio->io_errno);
+ else
+ clen += printf(" D=0x%8.8" PRIx64 " B=0x%-6" PRIx64 " /dev/%s", dio->blkno, dio->iosize, generate_cs_disk_name(dio->dev, cs_diskname));
+
+ break;
+
+ case FMT_SYNC_DISK_CS:
+ /*
+ * physical disk sync cache
+ */
+ clen += printf(" /dev/%s", generate_cs_disk_name(event->arg1, cs_diskname));
+
+ break;
+
+ case FMT_MSYNC:
+ {
+ /*
+ * msync
+ */
+ int mlen = 0;
+
+ buf[0] = '\0';
+
+ if (ti->arg3 & MS_ASYNC)
+ mlen += sprintf(&buf[mlen], "MS_ASYNC | ");
+ else
+ mlen += sprintf(&buf[mlen], "MS_SYNC | ");
+
+ if (ti->arg3 & MS_INVALIDATE)
+ mlen += sprintf(&buf[mlen], "MS_INVALIDATE | ");
+ if (ti->arg3 & MS_KILLPAGES)
+ mlen += sprintf(&buf[mlen], "MS_KILLPAGES | ");
+ if (ti->arg3 & MS_DEACTIVATE)
+ mlen += sprintf(&buf[mlen], "MS_DEACTIVATE | ");
+
+ if (ti->arg3 & ~(MS_ASYNC | MS_SYNC | MS_INVALIDATE | MS_KILLPAGES | MS_DEACTIVATE))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
+
+ if (mlen)
+ buf[mlen - 3] = '\0';
+
+ if (event->arg1)
+ clen += printf(" [%3d]", (int)event->arg1);
+
+ user_addr = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg1);
+ clen += clip_64bit(" A=", user_addr);
+
+ user_size = (((off_t)(unsigned int)(ti->arg5)) << 32) | (unsigned int)(ti->arg2);
+
+ clen += printf(" B=0x%-16qx <%s>", user_size, buf);
+
+ break;
+ }
+
+ case FMT_FLOCK:
+ {
+ /*
+ * flock
+ */
+ int mlen = 0;
+
+ buf[0] = '\0';
+
+ if (ti->arg2 & LOCK_SH)
+ mlen += sprintf(&buf[mlen], "LOCK_SH | ");
+ if (ti->arg2 & LOCK_EX)
+ mlen += sprintf(&buf[mlen], "LOCK_EX | ");
+ if (ti->arg2 & LOCK_NB)
+ mlen += sprintf(&buf[mlen], "LOCK_NB | ");
+ if (ti->arg2 & LOCK_UN)
+ mlen += sprintf(&buf[mlen], "LOCK_UN | ");
+
+ if (ti->arg2 & ~(LOCK_SH | LOCK_EX | LOCK_NB | LOCK_UN))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
+
+ if (mlen)
+ buf[mlen - 3] = '\0';
+
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d] <%s>", (int)ti->arg1, (int)event->arg1, buf);
+ else
+ clen += printf(" F=%-3d <%s>", (int)ti->arg1, buf);
+
+ break;
+ }
+
+ case FMT_FCNTL:
+ {
+ /*
+ * fcntl
+ */
+ char *p = NULL;
+ int fd = -1;
+
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
+
+ switch(ti->arg2) {
+ case F_DUPFD:
+ p = "DUPFD";
+ break;
+
+ case F_GETFD:
+ p = "GETFD";
+ break;
+
+ case F_SETFD:
+ p = "SETFD";
+ break;
+
+ case F_GETFL:
+ p = "GETFL";
+ break;
+
+ case F_SETFL:
+ p = "SETFL";
+ break;
+
+ case F_GETOWN:
+ p = "GETOWN";
+ break;
+
+ case F_SETOWN:
+ p = "SETOWN";
+ break;
+
+ case F_GETLK:
+ p = "GETLK";
+ break;
+
+ case F_SETLK:
+ p = "SETLK";
+ break;
+
+ case F_SETLKW:
+ p = "SETLKW";
+ break;
+
+ case F_SETLKWTIMEOUT:
+ p = "SETLKWTIMEOUT";
+ break;
+
+ case F_GETLKPID:
+ p = "GETLKPID";
+ break;
+
+ case F_OFD_GETLK:
+ p = "OFD_GETLK";
+ break;
+
+ case F_OFD_SETLK:
+ p = "OFD_SETLK";
+ break;
+
+ case F_OFD_SETLKW:
+ p = "OFD_SETLKW";
+ break;
+
+ case F_OFD_SETLKWTIMEOUT:
+ p = "OFD_SETLKWTIMEOUT";
+ break;
+
+ case F_OFD_GETLKPID:
+ p = "OFD_GETLKPID";
+ break;
+
+ case F_PREALLOCATE:
+ p = "PREALLOCATE";
+ break;
+
+ case F_SETSIZE:
+ p = "SETSIZE";
+ break;
+
+ case F_RDADVISE:
+ p = "RDADVISE";
+ break;
+
+ case F_GETPATH:
+ p = "GETPATH";
+ break;
+
+ case F_FULLFSYNC:
+ p = "FULLFSYNC";
+ break;
+
+ case F_PATHPKG_CHECK:
+ p = "PATHPKG_CHECK";
+ break;
+
+ case F_OPENFROM:
+ p = "OPENFROM";
+
+ if (event->arg1 == 0)
+ fd = (int)event->arg2;
+ break;
+
+ case F_UNLINKFROM:
+ p = "UNLINKFROM";
+ break;
+
+ case F_CHECK_OPENEVT:
+ p = "CHECK_OPENEVT";
+ break;
+
+ case F_NOCACHE:
+ if (ti->arg3)
+ p = "CACHING OFF";
+ else
+ p = "CACHING ON";
+ break;
+
+ case F_GLOBAL_NOCACHE:
+ if (ti->arg3)
+ p = "CACHING OFF (GLOBAL)";
+ else
+ p = "CACHING ON (GLOBAL)";
+ break;
+
+ case F_FLUSH_DATA:
+ p = "FLUSH_DATA";
+ break;
+
+ case F_CHKCLEAN:
+ p = "CHKCLEAN";
+ break;
+
+ case F_RDAHEAD:
+ if (ti->arg3) {
+ p = "RDAHEAD ON";
+ } else {
+ p = "RDAHEAD OFF";
+ }
+ break;
+
+ case F_LOG2PHYS:
+ p = "LOG2PHYS";
+ break;
+
+ case F_FREEZE_FS:
+ p = "FREEZE_FS";
+ break;
+
+ case F_THAW_FS:
+ p = "THAW_FS";
+ break;
+
+ case F_ADDSIGS:
+ p = "ADDSIGS";
+ break;
+
+ case F_MARKDEPENDENCY:
+ p = "MARKDEPENDENCY";
+ break;
+
+ case F_ADDFILESIGS:
+ p = "ADDFILESIGS";
+ break;
+
+ case F_NODIRECT:
+ p = "NODIRECT";
+ break;
+
+ case F_GETPROTECTIONCLASS:
+ p = "GETPROTECTIONCLASS";
+ break;
+
+ case F_SETPROTECTIONCLASS:
+ p = "SETPROTECTIONCLASS";
+ break;
+
+ case F_LOG2PHYS_EXT:
+ p = "LOG2PHYS_EXT";
+ break;
+
+ case F_SETSTATICCONTENT:
+ if (ti->arg3) {
+ p = "STATICCONTENT ON";
+ } else {
+ p = "STATICCONTENT OFF";
+ }
+ break;
+
+ case F_MOVEDATAEXTENTS:
+ p = "MOVEDATAEXTENTS";
+ break;
+
+ case F_DUPFD_CLOEXEC:
+ p = "DUPFD_CLOEXEC";
+ break;
+
+ case F_SETBACKINGSTORE:
+ p = "SETBACKINGSTORE";
+ break;
+
+ case F_GETPATH_MTMINFO:
+ p = "GETPATH_MTMINFO";
+ break;
+
+ case F_GETCODEDIR:
+ p = "GETCODEDIR";
+ break;
+
+ case F_SETNOSIGPIPE:
+ p = "SETNOSIGPIPE";
+ break;
+
+ case F_GETNOSIGPIPE:
+ p = "GETNOSIGPIPE";
+ break;
+
+ case F_TRANSCODEKEY:
+ p = "TRANSCODEKEY";
+ break;
+
+ case F_SINGLE_WRITER:
+ p = "SINGLE_WRITER";
+ break;
+
+ case F_GETPROTECTIONLEVEL:
+ p = "GETPROTECTIONLEVEL";
+ break;
+
+ case F_FINDSIGS:
+ p = "FINDSIGS";
+ break;
+
+ case F_GETDEFAULTPROTLEVEL:
+ p = "GETDEFAULTPROTLEVEL";
+ break;
+
+ case F_MAKECOMPRESSED:
+ p = "MAKECOMPRESSED";
+ break;
+
+ case F_SET_GREEDY_MODE:
+ if (ti->arg3) {
+ p = "GREEDY_MODE ON";
+ } else {
+ p = "GREEDY_MODE OFF";
+ }
+ break;
+
+ case F_SETIOTYPE:
+ p = "SETIOTYPE";
+ break;
+
+ case F_ADDFILESIGS_FOR_DYLD_SIM:
+ p = "ADDFILESIGS_FOR_DYLD_SIM";
+ break;
+
+ case F_RECYCLE:
+ p = "RECYCLE";
+ break;
+
+ case F_BARRIERFSYNC:
+ p = "BARRIERFSYNC";
+ break;
+
+ case F_SETCONFINED:
+ p = "SETCONFINED";
+ break;
+
+ case F_GETCONFINED:
+ p = "GETCONFINED";
+ break;
+
+ case F_ADDFILESIGS_RETURN:
+ p = "ADDFILESIGS_RETURN";
+ break;
+
+ case F_CHECK_LV:
+ p = "CHECK_LV";
+ break;
+
+ case F_PUNCHHOLE:
+ p = "PUNCHHOLE";
+ break;
+
+ case F_TRIM_ACTIVE_FILE:
+ p = "TRIM_ACTIVE_FILE";
+ break;
+
+ case F_SPECULATIVE_READ:
+ p = "SPECULATIVE_READ";
+ break;
+
+ case F_GETPATH_NOFIRMLINK:
+ p = "GETPATH_NOFIRMLINK";
+ break;
+
+ case F_ADDFILESIGS_INFO:
+ p = "ADDFILESIGS_INFO";
+ break;
+
+ case F_ADDFILESUPPL:
+ p = "ADDFILESUPPL";
+ break;
+
+#ifdef F_GETSIGSINFO
+ case F_GETSIGSINFO:
+ p = "GETSIGSINFO";
+ break;
+#endif // F_GETSIGSINFO
+ }
+
+ if (p) {
+ if (fd == -1)
+ clen += printf(" <%s>", p);
+ else
+ clen += printf(" <%s> F=%d", p, fd);
+ } else {
+ clen += printf(" <CMD=%d>", (int)ti->arg2);
+ }
+
+ break;
+ }
+
+ case FMT_IOCTL:
+ {
+ /*
+ * ioctl
+ */
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
+
+ clen += printf(" <CMD=0x%x>", (int)ti->arg2);
+
+ break;
+ }
+
+ case FMT_IOCTL_SYNC:
+ {
+ /*
+ * ioctl
+ */
+ clen += printf(" <DKIOCSYNCHRONIZE> B=%" PRIu64 " /dev/%s", (uint64_t)event->arg3, find_disk_name(event->arg1));
+
+ break;
+ }
+
+ case FMT_IOCTL_SYNCCACHE:
+ {
+ /*
+ * ioctl
+ */
+ clen += printf(" <DKIOCSYNCHRONIZECACHE> /dev/%s", find_disk_name(event->arg1));
+
+ break;
+ }
+
+ case FMT_IOCTL_UNMAP:
+ {
+ /*
+ * ioctl
+ */
+ clen += printf(" <DKIOCUNMAP> /dev/%s", find_disk_name(event->arg1));
+
+ break;
+ }
+
+ case FMT_UNMAP_INFO:
+ {
+ clen += printf(" D=0x%8.8" PRIx64 " B=0x%-6" PRIx64 " /dev/%s", (uint64_t)event->arg2, (uint64_t)event->arg3, find_disk_name(event->arg1));
+
+ break;
+ }
+
+ case FMT_SELECT:
+ /*
+ * select
+ */
+ if (event->arg1)
+ clen += printf(" [%3d]", (int)event->arg1);
+ else
+ clen += printf(" S=%-3d", (int)event->arg2);
+
+ break;
+
+ case FMT_LSEEK:
+ case FMT_PREAD:
+ /*
+ * pread, pwrite, lseek
+ */
+ clen += printf(" F=%-3d", (int)ti->arg1);
+
+ if (event->arg1) {
+ clen += printf("[%3d] ", (int)event->arg1);
+ } else {
+ if (format == FMT_PREAD)
+ clen += printf(" B=0x%-8" PRIx64 " ", (uint64_t)event->arg2);
+ else
+ clen += printf(" ");
+ }
+
+ if (format == FMT_PREAD)
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg4);
+ else
+#ifdef __ppc__
+ offset_reassembled = (((off_t)(unsigned int)(arg2)) << 32) | (unsigned int)(arg3);
+#else
+ offset_reassembled = (((off_t)(unsigned int)(event->arg3)) << 32) | (unsigned int)(event->arg2);
+#endif
+
+ clen += clip_64bit("O=", offset_reassembled);
+
+ if (format == FMT_LSEEK) {
+ char *mode;
+
+ if (ti->arg3 == SEEK_SET)
+ mode = "SEEK_SET";
+ else if (ti->arg3 == SEEK_CUR)
+ mode = "SEEK_CUR";
+ else if (ti->arg3 == SEEK_END)
+ mode = "SEEK_END";
+ else
+ mode = "UNKNOWN";
+
+ clen += printf(" <%s>", mode);
+ }
+
+ break;
+
+ case FMT_MMAP:
+ /*
+ * mmap
+ */
+ clen += printf(" F=%-3d ", (int)ti->arg1);
+
+ if (event->arg1) {
+ clen += printf("[%3d] ", (int)event->arg1);
+ } else {
+ user_addr = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
+
+ clen += clip_64bit("A=", user_addr);
+
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg6)) << 32) | (unsigned int)(ti->arg7);
+
+ clen += clip_64bit("O=", offset_reassembled);
+
+ user_size = (((off_t)(unsigned int)(ti->arg4)) << 32) | (unsigned int)(ti->arg5);
+
+ clen += printf("B=0x%-16qx", user_size);
+
+ clen += printf(" <");
+
+ if (ti->arg8 & PROT_READ)
+ clen += printf("READ");
+
+ if (ti->arg8 & PROT_WRITE)
+ clen += printf("|WRITE");
+
+ if (ti->arg8 & PROT_EXEC)
+ clen += printf("|EXEC");
+
+ clen += printf(">");
+ }
+
+ break;
+
+ case FMT_TRUNC:
+ case FMT_FTRUNC:
+ /*
+ * ftruncate, truncate
+ */
+ if (format == FMT_FTRUNC)
+ clen += printf(" F=%-3d", (int)ti->arg1);
+ else
+ clen += printf(" ");
+
+ if (event->arg1)
+ clen += printf("[%3d]", (int)event->arg1);
+
+#ifdef __ppc__
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg2)) << 32) | (unsigned int)(ti->arg3);
+#else
+ offset_reassembled = (((off_t)(unsigned int)(ti->arg3)) << 32) | (unsigned int)(ti->arg2);
+#endif
+ clen += clip_64bit(" O=", offset_reassembled);
+
+ nopadding = 1;
+ break;
+
+ case FMT_FCHFLAGS:
+ case FMT_CHFLAGS:
+ {
+ /*
+ * fchflags, chflags
+ */
+ int mlen = 0;
+
+ if (format == FMT_FCHFLAGS) {
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
+ } else {
+ if (event->arg1)
+ clen += printf(" [%3d] ", (int)event->arg1);
+ }
+
+ buf[mlen++] = ' ';
+ buf[mlen++] = '<';
+
+ if (ti->arg2 & UF_NODUMP)
+ mlen += sprintf(&buf[mlen], "UF_NODUMP | ");
+ if (ti->arg2 & UF_IMMUTABLE)
+ mlen += sprintf(&buf[mlen], "UF_IMMUTABLE | ");
+ if (ti->arg2 & UF_APPEND)
+ mlen += sprintf(&buf[mlen], "UF_APPEND | ");
+ if (ti->arg2 & UF_OPAQUE)
+ mlen += sprintf(&buf[mlen], "UF_OPAQUE | ");
+ if (ti->arg2 & SF_ARCHIVED)
+ mlen += sprintf(&buf[mlen], "SF_ARCHIVED | ");
+ if (ti->arg2 & SF_IMMUTABLE)
+ mlen += sprintf(&buf[mlen], "SF_IMMUTABLE | ");
+ if (ti->arg2 & SF_APPEND)
+ mlen += sprintf(&buf[mlen], "SF_APPEND | ");
+
+ if (ti->arg2 == 0)
+ mlen += sprintf(&buf[mlen], "CLEAR_ALL_FLAGS | ");
+ else if (ti->arg2 & ~(UF_NODUMP | UF_IMMUTABLE | UF_APPEND | SF_ARCHIVED | SF_IMMUTABLE | SF_APPEND))
+ mlen += sprintf(&buf[mlen], "UNKNOWN | ");
+
+ if (mlen >= 3)
+ mlen -= 3;
+
+ buf[mlen++] = '>';
+ buf[mlen] = '\0';
+
+ if (mlen < 19) {
+ memset(&buf[mlen], ' ', 19 - mlen);
+ mlen = 19;
+ buf[mlen] = '\0';
+ }
+
+ clen += printf("%s", buf);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_UMASK:
+ case FMT_FCHMOD:
+ case FMT_FCHMOD_EXT:
+ case FMT_CHMOD:
+ case FMT_CHMOD_EXT:
+ case FMT_CHMODAT:
+ {
+ /*
+ * fchmod, fchmod_extended, chmod, chmod_extended
+ */
+ uint64_t mode;
+
+ if (format == FMT_FCHMOD || format == FMT_FCHMOD_EXT) {
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d] ", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d ", (int)ti->arg1);
+ } else {
+ if (event->arg1)
+ clen += printf(" [%3d] ", (int)event->arg1);
+ else
+ clen += printf(" ");
+ }
+
+ if (format == FMT_UMASK)
+ mode = ti->arg1;
+ else if (format == FMT_FCHMOD || format == FMT_CHMOD || format == FMT_CHMODAT)
+ mode = ti->arg2;
+ else
+ mode = ti->arg4;
+
+ get_mode_string(mode, &buf[0]);
+
+ if (event->arg1 == 0)
+ clen += printf("<%s> ", buf);
+ else
+ clen += printf("<%s>", buf);
+ break;
+ }
+
+ case FMT_ACCESS:
+ {
+ /*
+ * access
+ */
+ char mode[5];
+
+ memset(mode, '_', 4);
+ mode[4] = '\0';
+
+ if (ti->arg2 & R_OK)
+ mode[0] = 'R';
+ if (ti->arg2 & W_OK)
+ mode[1] = 'W';
+ if (ti->arg2 & X_OK)
+ mode[2] = 'X';
+ if (ti->arg2 == F_OK)
+ mode[3] = 'F';
+
+ if (event->arg1)
+ clen += printf(" [%3d] (%s) ", (int)event->arg1, mode);
+ else
+ clen += printf(" (%s) ", mode);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_MOUNT:
+ {
+ if (event->arg1)
+ clen += printf(" [%3d] <FLGS=0x%" PRIx64 "> ", (int)event->arg1, ti->arg3);
+ else
+ clen += printf(" <FLGS=0x%" PRIx64 "> ", ti->arg3);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_UNMOUNT:
+ {
+ char *mountflag;
+
+ if (ti->arg2 & MNT_FORCE)
+ mountflag = "<FORCE>";
+ else
+ mountflag = "";
+
+ if (event->arg1)
+ clen += printf(" [%3d] %s ", (int)event->arg1, mountflag);
+ else
+ clen += printf(" %s ", mountflag);
+
+ nopadding = 1;
+ break;
+ }
+
+ case FMT_OPEN:
+ clen += print_open(event, ti->arg2);
+ nopadding = 1;
+ break;
+
+ case FMT_OPENAT:
+ clen += print_open(event, ti->arg3);
+ nopadding = 1;
+ break;
+
+ case FMT_GUARDED_OPEN:
+ clen += print_open(event, ti->arg4);
+ nopadding = 1;
+ break;
+
+ case FMT_SOCKET:
+ {
+ /*
+ * socket
+ *
+ */
+ char *domain;
+ char *type;
+
+ switch (ti->arg1) {
+ case AF_UNIX:
+ domain = "AF_UNIX";
+ break;
+
+ case AF_INET:
+ domain = "AF_INET";
+ break;
+
+ case AF_ISO:
+ domain = "AF_ISO";
+ break;
+
+ case AF_NS:
+ domain = "AF_NS";
+ break;
+
+ case AF_IMPLINK:
+ domain = "AF_IMPLINK";
+ break;
+
+ default:
+ domain = "UNKNOWN";
+ break;
+ }
+
+ switch (ti->arg2) {
+ case SOCK_STREAM:
+ type = "SOCK_STREAM";
+ break;
+ case SOCK_DGRAM:
+ type = "SOCK_DGRAM";
+ break;
+ case SOCK_RAW:
+ type = "SOCK_RAW";
+ break;
+ default:
+ type = "UNKNOWN";
+ break;
+ }
+
+ if (event->arg1)
+ clen += printf(" [%3d] <%s, %s, 0x%" PRIx64 ">", (int)event->arg1, domain, type, ti->arg3);
+ else
+ clen += printf(" F=%-3d <%s, %s, 0x%" PRIx64 ">", (int)event->arg2, domain, type, ti->arg3);
+
+ break;
+ }
+
+ case FMT_AIO_FSYNC:
+ {
+ /*
+ * aio_fsync [errno] AIOCBP OP
+ */
+ char *op;
+
+ if (ti->arg1 == O_SYNC || ti->arg1 == 0)
+ op = "AIO_FSYNC";
+#if O_DSYNC
+ else if (ti->arg1 == O_DSYNC)
+ op = "AIO_DSYNC";
+#endif
+ else
+ op = "UNKNOWN";
+
+ if (event->arg1)
+ clen += printf(" [%3d] P=0x%8.8" PRIx64 " <%s>", (int)event->arg1, ti->arg2, op);
+ else
+ clen += printf(" P=0x%8.8" PRIx64 " <%s>", ti->arg2, op);
+
+ break;
+ }
+
+ case FMT_AIO_RETURN:
+ /*
+ * aio_return [errno] AIOCBP IOSIZE
+ */
+ if (event->arg1)
+ clen += printf(" [%3d] P=0x%8.8" PRIx64, (int)event->arg1, ti->arg1);
+ else
+ clen += printf(" P=0x%8.8" PRIx64 " B=0x%-8" PRIx64, ti->arg1, (uint64_t)event->arg2);
+
+ break;
+
+ case FMT_AIO_SUSPEND:
+ /*
+ * aio_suspend [errno] NENTS
+ */
+ if (event->arg1)
+ clen += printf(" [%3d] N=%d", (int)event->arg1, (int)ti->arg2);
+ else
+ clen += printf(" N=%d", (int)ti->arg2);
+
+ break;
+
+ case FMT_AIO_CANCEL:
+ /*
+ * aio_cancel [errno] FD or AIOCBP (if non-null)
+ */
+ if (ti->arg2) {
+ if (event->arg1)
+ clen += printf(" [%3d] P=0x%8." PRIx64, (int)event->arg1, ti->arg2);
+ else
+ clen += printf(" P=0x%8.8" PRIx64, ti->arg2);
+ } else {
+ if (event->arg1)
+ clen += printf(" F=%-3d[%3d]", (int)ti->arg1, (int)event->arg1);
+ else
+ clen += printf(" F=%-3d", (int)ti->arg1);
+ }
+
+ break;
+
+ case FMT_AIO:
+ /*
+ * aio_error, aio_read, aio_write [errno] AIOCBP
+ */
+ if (event->arg1)
+ clen += printf(" [%3d] P=0x%8.8" PRIx64, (int)event->arg1, ti->arg1);
+ else
+ clen += printf(" P=0x%8.8" PRIx64, ti->arg1);
+
+ break;
+
+ case FMT_LIO_LISTIO: {
+ /*
+ * lio_listio [errno] NENTS MODE
+ */
+ char *op;
+
+ if (ti->arg1 == LIO_NOWAIT)
+ op = "LIO_NOWAIT";
+ else if (ti->arg1 == LIO_WAIT)
+ op = "LIO_WAIT";
+ else
+ op = "UNKNOWN";
+
+ if (event->arg1)
+ clen += printf(" [%3d] N=%d <%s>", (int)event->arg1, (int)ti->arg3, op);
+ else
+ clen += printf(" N=%d <%s>", (int)ti->arg3, op);
+
+ break;
+ }
+ }
+ }
+
+ /*
+ * Calculate space available to print pathname
+ */
+ if (columns > MAXCOLS || wideflag)
+ clen = columns - (clen + 14 + 20 + 11);
+ else
+ clen = columns - (clen + 14 + 12);
+
+ if (!nopadding)
+ clen -= 3;
+
+ if (framework_name) {
+ len = sprintf(&buf[0], " %s %s ", framework_type, framework_name);
+ } else if (*pathname != '\0') {
+ switch(format) {
+ case FMT_AT:
+ case FMT_OPENAT:
+ case FMT_CHMODAT:
+ len = sprintf(&buf[0], " [%d]/%s ", (int)ti->arg1, pathname);
+ break;
+ case FMT_RENAMEAT:
+ len = sprintf(&buf[0], " [%d]/%s ", (int)ti->arg3, pathname);
+ break;
+ default:
+ len = sprintf(&buf[0], " %s ", pathname);
+ }
+
+ if (format == FMT_MOUNT && ti->pathname2[0] != '\0') {
+ int len2;
+
+ memset(&buf[len], ' ', 2);
+
+ len2 = sprintf(&buf[len+2], " %s ", ti->pathname2);
+ len = len + 2 + len2;
+ }
+ } else {
+ len = 0;
+ }
+
+ if (clen > len) {
+ /*
+ * Add null padding if column length
+ * is wider than the pathname length.
+ */
+ memset(&buf[len], ' ', clen - len);
+ buf[clen] = '\0';
+
+ pathname = buf;
+ } else if (clen == len) {
+ pathname = buf;
+ } else if ((clen > 0) && (clen < len)) {
+ /*
+ * This prints the tail end of the pathname
+ */
+ buf[len-clen] = ' ';
+
+ pathname = &buf[len - clen];
+ } else {
+ pathname = "";
+ }
+
+ /*
+ * fudge some additional system call overhead
+ * that currently isn't tracked... this also
+ * insures that we see a minimum of 1 us for
+ * an elapsed time
+ */
+ usecs = (mach_to_nano(now - stime) + (NSEC_PER_USEC - 1)) / NSEC_PER_USEC;
+ secs = usecs / USEC_PER_SEC;
+ usecs -= secs * USEC_PER_SEC;
+
+ if (!nopadding)
+ p1 = " ";
+ else
+ p1 = "";
+
+ if (waited)
+ p2 = " W";
+ else
+ p2 = " ";
+
+ if (columns > MAXCOLS || wideflag)
+ printf("%s%s %3llu.%06llu%s %s.%" PRIu64 "\n", p1, pathname, secs, usecs, p2, command_name, threadid);
+ else
+ printf("%s%s %3llu.%06llu%s %-12.12s\n", p1, pathname, secs, usecs, p2, command_name);
+
+ if (!RAW_flag)
+ fflush(stdout);
+}
+
+#pragma mark metadata info hash routines
+
+#define VN_HASH_SIZE 16384
+#define VN_HASH_MASK (VN_HASH_SIZE - 1)
+
+typedef struct meta_info {
+ struct meta_info *m_next;
+ uint64_t m_blkno;
+ char m_name[MAXPATHLEN];
+} *meta_info_t;
+
+meta_info_t m_info_hash[VN_HASH_SIZE];
+
+void
+meta_add_name(uint64_t blockno, const char *pathname)
+{
+ meta_info_t mi;
+ int hashid;
+
+ hashid = blockno & VN_HASH_MASK;
+
+ for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
+ if (mi->m_blkno == blockno)
+ break;
+ }
+
+ if (mi == NULL) {
+ mi = malloc(sizeof (struct meta_info));
+
+ mi->m_next = m_info_hash[hashid];
+ m_info_hash[hashid] = mi;
+ mi->m_blkno = blockno;
+ }
+
+ strncpy(mi->m_name, pathname, sizeof (mi->m_name));
+}
+
+const char *
+meta_find_name(uint64_t blockno)
+{
+ meta_info_t mi;
+ int hashid;
+
+ hashid = blockno & VN_HASH_MASK;
+
+ for (mi = m_info_hash[hashid]; mi; mi = mi->m_next) {
+ if (mi->m_blkno == blockno)
+ return mi->m_name;
+ }
+
+ return "";
+}
+
+void
+meta_delete_all(void)
+{
+ meta_info_t mi, next;
+ int i;
+
+ for (i = 0; i < HASH_MASK; i++) {
+ for (mi = m_info_hash[i]; mi; mi = next) {
+ next = mi->m_next;
+
+ free(mi);
+ }
+
+ m_info_hash[i] = NULL;
+ }
+}
+
+#pragma mark event ("thread info") routines
+
+th_info_t th_info_hash[HASH_SIZE];
+th_info_t th_info_freelist;
+
+static th_info_t
+add_event(ktrace_event_t event, int type)
+{
+ th_info_t ti;
+ int hashid;
+ uint64_t eventid;
+
+ if ((ti = th_info_freelist))
+ th_info_freelist = ti->next;
+ else
+ ti = malloc(sizeof (struct th_info));
+
+ bzero(ti, sizeof (struct th_info));
+
+ hashid = event->threadid & HASH_MASK;
+
+ ti->next = th_info_hash[hashid];
+ th_info_hash[hashid] = ti;
+
+ eventid = event->debugid & KDBG_EVENTID_MASK;
+
+ if (eventid == BSC_execve || eventid == BSC_posix_spawn) {
+ const char *command;
+
+ command = ktrace_get_execname_for_thread(s, event->threadid);
+
+ if (!command)
+ command = "";
+
+ strncpy(ti->command, command, sizeof (ti->command));
+ ti->command[MAXCOMLEN] = '\0';
+ }
+
+ ti->thread = event->threadid;
+ ti->type = type;
+
+ return ti;
+}
+
+th_info_t
+event_find(uint64_t thread, int type)
+{
+ th_info_t ti;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
+ if (ti->thread == thread) {
+ if (type == ti->type)
+ return ti;
+
+ if (type == 0)
+ return ti;
+ }
+ }
+
+ return NULL;
+}
+
+void
+event_delete(th_info_t ti_to_delete)
+{
+ th_info_t ti;
+ th_info_t ti_prev;
+ int hashid;
+
+ hashid = ti_to_delete->thread & HASH_MASK;
+
+ if ((ti = th_info_hash[hashid])) {
+ if (ti == ti_to_delete)
+ th_info_hash[hashid] = ti->next;
+ else {
+ ti_prev = ti;
+
+ for (ti = ti->next; ti; ti = ti->next) {
+ if (ti == ti_to_delete) {
+ ti_prev->next = ti->next;
+ break;
+ }
+ ti_prev = ti;
+ }
+ }
+ if (ti) {
+ ti->next = th_info_freelist;
+ th_info_freelist = ti;
+ }
+ }
+}
+
+void
+event_delete_all(void)
+{
+ th_info_t ti = 0;
+ th_info_t ti_next = 0;
+ int i;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+
+ for (ti = th_info_hash[i]; ti; ti = ti_next) {
+ ti_next = ti->next;
+ ti->next = th_info_freelist;
+ th_info_freelist = ti;
+ }
+ th_info_hash[i] = 0;
+ }
+}
+
+void
+event_enter(int type, ktrace_event_t event)
+{
+ th_info_t ti;
+
+#if DEBUG
+ int index;
+ bool found;
+
+ found = false;
+
+ switch (type) {
+ case P_CS_SYNC_DISK:
+ case MACH_pageout:
+ case MACH_vmfault:
+ case MSC_map_fd:
+ case SPEC_ioctl:
+ case Throttled:
+ case HFS_update:
+ found = true;
+ }
+
+ if ((type & CSC_MASK) == BSC_BASE) {
+ if ((index = BSC_INDEX(type)) < MAX_BSD_SYSCALL && bsd_syscalls[index].sc_name)
+ found = true;
+ }
+
+ os_assert(found);
+#endif /* DEBUG */
+
+ if ((ti = add_event(event, type)) == NULL)
+ return;
+
+ ti->stime = event->timestamp;
+ ti->arg1 = event->arg1;
+ ti->arg2 = event->arg2;
+ ti->arg3 = event->arg3;
+ ti->arg4 = event->arg4;
+}
+
+void
+event_exit(char *sc_name, int type, ktrace_event_t event, int format)
+{
+ th_info_t ti;
+ pid_t pid;
+
+ if ((ti = event_find(event->threadid, type)) == NULL)
+ return;
+
+ pid = ktrace_get_pid_for_thread(s, event->threadid);
+
+ if (check_filter_mode(pid, ti, type, (int)event->arg1, (int)event->arg2, sc_name)) {
+ const char *pathname;
+
+ pathname = NULL;
+
+ /* most things are just interested in the first lookup */
+ if (ti->pathname[0] != '\0')
+ pathname = ti->pathname;
+
+ if (!pathname)
+ pathname = "";
+
+ format_print(ti, sc_name, event, type, format, event->timestamp, ti->stime, ti->waited, pathname, NULL);
+ }
+
+ event_delete(ti);
+}
+
+void
+event_mark_thread_waited(uint64_t thread)
+{
+ th_info_t ti;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (ti = th_info_hash[hashid]; ti; ti = ti->next) {
+ if (ti->thread == thread)
+ ti->waited = 1;
+ }
+}
+
+#pragma mark network fd set routines
+
+struct pid_fd_set {
+ struct pid_fd_set *next;
+ pid_t pid;
+ char *set;
+ size_t setsize; /* number of *bytes*, not bits */
+};
+
+struct pid_fd_set *pfs_hash[HASH_SIZE];
+
+static struct pid_fd_set *
+pfs_get(pid_t pid)
+{
+ struct pid_fd_set *pfs;
+ int hashid;
+
+ os_assert(pid >= 0);
+
+ hashid = pid & HASH_MASK;
+
+ for (pfs = pfs_hash[hashid]; pfs; pfs = pfs->next) {
+ if (pfs->pid == pid) {
+ return pfs;
+ }
+ }
+
+ pfs = calloc(1, sizeof (struct pid_fd_set));
+
+ pfs->pid = pid;
+ pfs->set = NULL;
+ pfs->setsize = 0;
+ pfs->next = pfs_hash[hashid];
+ pfs_hash[hashid] = pfs;
+
+ return pfs;
+}
+
+void
+fd_clear_pid(pid_t pid)
+{
+ struct pid_fd_set *pfs, *prev;
+ int hashid;
+
+ if (pid < 0)
+ return;
+
+ hashid = pid & HASH_MASK;
+
+ pfs = pfs_hash[hashid];
+ prev = NULL;
+
+ while (pfs) {
+ if (pfs->pid == pid) {
+ if (prev) {
+ prev->next = pfs->next;
+ } else {
+ pfs_hash[hashid] = pfs->next;
+ }
+
+ free(pfs->set);
+ free(pfs);
+
+ break;
+ } else {
+ prev = pfs;
+ pfs = pfs->next;
+ }
+ }
+}
+
+void
+fd_clear_all(void)
+{
+ struct pid_fd_set *pfs, *next;
+ int i;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+ for (pfs = pfs_hash[i]; pfs; pfs = next) {
+ next = pfs->next;
+
+ free(pfs->set);
+ free(pfs);
+ }
+
+ pfs_hash[i] = NULL;
+ }
+}
+
+void
+fd_set_is_network(pid_t pid, uint64_t fd, bool set)
+{
+ struct pid_fd_set *pfs;
+
+ if (pid < 0)
+ return;
+ if (fd > OPEN_MAX)
+ return;
+
+ pfs = pfs_get(pid);
+
+ if (fd >= pfs->setsize * CHAR_BIT) {
+ size_t newsize;
+
+ if (!set) return;
+
+ newsize = MAX(((size_t)fd + CHAR_BIT) / CHAR_BIT, 2 * pfs->setsize);
+ pfs->set = reallocf(pfs->set, newsize);
+ os_assert(pfs->set != NULL);
+
+ bzero(pfs->set + pfs->setsize, newsize - pfs->setsize);
+ pfs->setsize = newsize;
+ }
+
+ if (set)
+ setbit(pfs->set, fd);
+ else
+ clrbit(pfs->set, fd);
+}
+
+bool
+fd_is_network(pid_t pid, uint64_t fd)
+{
+ struct pid_fd_set *pfs;
+
+ if (pid < 0)
+ return false;
+
+ pfs = pfs_get(pid);
+
+ if (fd >= pfs->setsize * CHAR_BIT) {
+ return false;
+ }
+
+ return isset(pfs->set, fd);
+}
+
+#pragma mark shared region address lookup routines
+
+#define MAXINDEX 2048
+
+struct library_range {
+ uint64_t b_address;
+ uint64_t e_address;
+};
+
+struct library_info {
+ uint64_t b_address;
+ uint64_t e_address;
+ int r_type;
+ char *name;
+};
+
+struct library_range frameworkArm64e = {0, 0};
+struct library_range framework64 = {0, 0};
+struct library_range framework64h = {0, 0};
+
+struct library_info library_infos[MAXINDEX];
+int num_libraries = 0;
+
+#define TEXT_R 0
+#define DATA_R 1
+#define OBJC_R 2
+#define IMPORT_R 3
+#define UNICODE_R 4
+#define IMAGE_R 5
+#define LINKEDIT_R 6
+
+static void
+sort_library_addresses(void)
+{
+ library_infos[num_libraries].b_address = library_infos[num_libraries - 1].b_address + 0x800000;
+ library_infos[num_libraries].e_address = library_infos[num_libraries].b_address;
+ library_infos[num_libraries].name = NULL;
+
+ qsort_b(library_infos, num_libraries, sizeof (struct library_info), ^int(const void *aa, const void *bb) {
+ struct library_info *a = (struct library_info *)aa;
+ struct library_info *b = (struct library_info *)bb;
+
+ if (a->b_address < b->b_address) return -1;
+ if (a->b_address == b->b_address) return 0;
+ return 1;
+ });
+}
+
+static int
+scanline(char *inputstring, char **argv, int maxtokens)
+{
+ int n = 0;
+ char **ap = argv, *p, *val;
+
+ for (p = inputstring; n < maxtokens && p != NULL; ) {
+ while ((val = strsep(&p, " \t")) != NULL && *val == '\0') ;
+
+ *ap++ = val;
+ n++;
+ }
+
+ *ap = 0;
+
+ return n;
+}
+
+static int
+read_shared_cache_map(const char *path, struct library_range *lr, char *linkedit_name)
+{
+ uint64_t b_address, e_address;
+ char buf[1024];
+ char *fnp, *fn_tofree;
+ FILE *fd;
+ char frameworkName[256];
+ char *tokens[64];
+ int ntokens;
+ int type;
+ int linkedit_found = 0;
+ char *substring, *ptr;
+
+ bzero(buf, sizeof(buf));
+ bzero(tokens, sizeof(tokens));
+
+ lr->b_address = 0;
+ lr->e_address = 0;
+
+ if ((fd = fopen(path, "r")) == 0)
+ return 0;
+
+ while (fgets(buf, 1023, fd)) {
+ if (strncmp(buf, "mapping", 7))
+ break;
+ }
+
+ buf[strlen(buf)-1] = 0;
+
+ frameworkName[0] = 0;
+
+ for (;;) {
+ /*
+ * Extract lib name from path name
+ */
+ if ((substring = strrchr(buf, '.'))) {
+ /*
+ * There is a ".": name is whatever is between the "/" around the "."
+ */
+ while ( *substring != '/') /* find "/" before "." */
+ substring--;
+
+ substring++;
+
+ strncpy(frameworkName, substring, 256); /* copy path from "/" */
+ frameworkName[255] = 0;
+ substring = frameworkName;
+
+ while ( *substring != '/' && *substring) /* find "/" after "." and stop string there */
+ substring++;
+
+ *substring = 0;
+ } else {
+ /*
+ * No ".": take segment after last "/"
+ */
+ ptr = buf;
+ substring = ptr;
+
+ while (*ptr) {
+ if (*ptr == '/')
+ substring = ptr + 1;
+ ptr++;
+ }
+
+ strncpy(frameworkName, substring, 256);
+ frameworkName[255] = 0;
+ }
+
+ fnp = malloc(strlen(frameworkName) + 1);
+ fn_tofree = fnp;
+ strcpy(fnp, frameworkName);
+
+ while (fgets(buf, 1023, fd) && num_libraries < (MAXINDEX - 2)) {
+ /*
+ * Get rid of EOL
+ */
+ buf[strlen(buf)-1] = 0;
+
+ ntokens = scanline(buf, tokens, 64);
+
+ if (ntokens < 4)
+ continue;
+
+ if (strncmp(tokens[0], "__TEXT", 6) == 0)
+ type = TEXT_R;
+ else if (strncmp(tokens[0], "__DATA", 6) == 0)
+ type = DATA_R;
+ else if (strncmp(tokens[0], "__OBJC", 6) == 0)
+ type = OBJC_R;
+ else if (strncmp(tokens[0], "__IMPORT", 8) == 0)
+ type = IMPORT_R;
+ else if (strncmp(tokens[0], "__UNICODE", 9) == 0)
+ type = UNICODE_R;
+ else if (strncmp(tokens[0], "__IMAGE", 7) == 0)
+ type = IMAGE_R;
+ else if (strncmp(tokens[0], "__LINKEDIT", 10) == 0)
+ type = LINKEDIT_R;
+ else
+ type = -1;
+
+ if (type == LINKEDIT_R && linkedit_found)
+ break;
+
+ if (type != -1) {
+ b_address = strtoull(tokens[1], 0, 16);
+ e_address = strtoull(tokens[3], 0, 16);
+
+ library_infos[num_libraries].b_address = b_address;
+ library_infos[num_libraries].e_address = e_address;
+ library_infos[num_libraries].r_type = type;
+
+ if (type == LINKEDIT_R) {
+ library_infos[num_libraries].name = linkedit_name;
+ linkedit_found = 1;
+ } else {
+ library_infos[num_libraries].name = fnp;
+ fn_tofree = NULL;
+ }
+#if 0
+ printf("%s(%d): %qx-%qx\n", frameworkInfo[numFrameworks].name, type, b_address, e_address);
+#endif
+ if (lr->b_address == 0 || b_address < lr->b_address)
+ lr->b_address = b_address;
+
+ if (lr->e_address == 0 || e_address > lr->e_address)
+ lr->e_address = e_address;
+
+ num_libraries++;
+ }
+
+ if (type == LINKEDIT_R)
+ break;
+ }
+
+ free(fn_tofree);
+
+ if (fgets(buf, 1023, fd) == 0)
+ break;
+
+ buf[strlen(buf)-1] = 0;
+ }
+
+ fclose(fd);
+
+#if 0
+ printf("%s range, %qx-%qx\n", path, lr->b_address, lr->e_address);
+#endif
+ return 1;
+}
+
+#define DYLD_SHARED_CACHE_LOCATION "/System/Library/dyld/"
+
+void
+init_shared_cache_mapping(void)
+{
+#if TARGET_OS_OSX
+#if TARGET_CPU_ARM64
+ read_shared_cache_map(DYLD_SHARED_CACHE_LOCATION"dyld_shared_cache_arm64e.map", &frameworkArm64e, DYLD_SHARED_CACHE_LOCATION"dyld_shared_cache_arm64e");
+#else //!TARGET_CPU_ARM64
+ if (0 == read_shared_cache_map(DYLD_SHARED_CACHE_LOCATION"dyld_shared_cache_x86_64h.map", &framework64h, DYLD_SHARED_CACHE_LOCATION"dyld_shared_cache_x86_64h")) {
+ read_shared_cache_map(DYLD_SHARED_CACHE_LOCATION"dyld_shared_cache_x86_64.map", &framework64, DYLD_SHARED_CACHE_LOCATION"dyld_shared_cache_x86_64");
+ }
+#endif //TARGET_CPU_ARM64
+ sort_library_addresses();
+#endif //TARGET_OS_OSX
+}
+
+void
+lookup_name(uint64_t user_addr, char **type, char **name)
+{
+ int i;
+ int start, last;
+
+ static char *frameworkType[] = {
+ "<TEXT> ",
+ "<DATA> ",
+ "<OBJC> ",
+ "<IMPORT> ",
+ "<UNICODE> ",
+ "<IMAGE> ",
+ "<LINKEDIT>",
+ };
+
+ *name = NULL;
+ *type = NULL;
+
+ if (num_libraries) {
+ if ((user_addr >= frameworkArm64e.b_address && user_addr < frameworkArm64e.e_address) ||
+ (user_addr >= framework64.b_address && user_addr < framework64.e_address) ||
+ (user_addr >= framework64h.b_address && user_addr < framework64h.e_address)) {
+
+ start = 0;
+ last = num_libraries;
+
+ for (i = num_libraries / 2; start < last; i = start + ((last - start) / 2)) {
+ if (user_addr > library_infos[i].e_address)
+ start = i+1;
+ else
+ last = i;
+ }
+
+ if (start < num_libraries &&
+ user_addr >= library_infos[start].b_address && user_addr < library_infos[start].e_address) {
+ *type = frameworkType[library_infos[start].r_type];
+ *name = library_infos[start].name;
+ }
+ }
+ }
+}
+
+#pragma mark disk I/O tracking routines
+
+struct diskio *free_diskios = NULL;
+struct diskio *busy_diskios = NULL;
+
+struct diskio *
+diskio_start(uint64_t type, uint64_t bp, uint64_t dev,
+ uint64_t blkno, uint64_t iosize, ktrace_event_t event)
+{
+ const char *command;
+ struct diskio *dio;
+
+ if ((dio = free_diskios)) {
+ free_diskios = dio->next;
+ } else {
+ dio = malloc(sizeof (struct diskio));
+ }
+
+ dio->prev = NULL;
+
+ dio->type = type;
+ dio->bp = bp;
+ dio->dev = dev;
+ dio->blkno = blkno;
+ dio->iosize = iosize;
+ dio->issued_time = event->timestamp;
+ dio->issuing_thread = event->threadid;
+ dio->issuing_pid = ktrace_get_pid_for_thread(s, event->threadid);
+
+ dio->bc_info = 0x0;
+
+ command = ktrace_get_execname_for_thread(s, event->threadid);
+
+ if (!command)
+ command = "";
+
+ strncpy(dio->issuing_command, command, MAXCOMLEN);
+ dio->issuing_command[MAXCOMLEN] = '\0';
+
+ dio->next = busy_diskios;
+
+ if (dio->next)
+ dio->next->prev = dio;
+
+ busy_diskios = dio;
+
+ return dio;
+}
+
+struct diskio *
+diskio_find(uint64_t bp)
+{
+ struct diskio *dio;
+
+ for (dio = busy_diskios; dio; dio = dio->next) {
+ if (dio->bp == bp)
+ return dio;
+ }
+
+ return NULL;
+}
+
+struct diskio *
+diskio_complete(uint64_t bp, uint64_t io_errno, uint64_t resid,
+ uint64_t thread, uint64_t curtime, struct timeval curtime_wall)
+{
+ struct diskio *dio;
+
+ if ((dio = diskio_find(bp)) == NULL) return NULL;
+
+ if (dio == busy_diskios) {
+ if ((busy_diskios = dio->next))
+ dio->next->prev = NULL;
+ } else {
+ if (dio->next)
+ dio->next->prev = dio->prev;
+ dio->prev->next = dio->next;
+ }
+
+ dio->iosize -= resid;
+ dio->io_errno = io_errno;
+ dio->completed_time = curtime;
+ dio->completed_walltime = curtime_wall;
+ dio->completion_thread = thread;
+
+ return dio;
+}
+
+void
+diskio_free(struct diskio *dio)
+{
+ dio->next = free_diskios;
+ free_diskios = dio;
+}
+
+void
+diskio_print(struct diskio *dio)
+{
+ char *p = NULL;
+ int len = 0;
+ uint64_t type;
+ int format = FMT_DISKIO;
+ char buf[64];
+
+ type = dio->type;
+ dio->is_meta = 0;
+
+ if ((type & P_CS_Class) == P_CS_Class) {
+ switch (type) {
+ case P_CS_ReadChunk:
+ p = " RdChunkCS";
+ len = 13;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_WriteChunk:
+ p = " WrChunkCS";
+ len = 13;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_MetaRead:
+ p = " RdMetaCS";
+ len = 10;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_MetaWrite:
+ p = " WrMetaCS";
+ len = 10;
+ format = FMT_DISKIO_CS;
+ break;
+ case P_CS_TransformRead:
+ p = " RdBgTfCS";
+ len = 10;
+ break;
+ case P_CS_TransformWrite:
+ p = " WrBgTfCS";
+ len = 10;
+ break;
+ case P_CS_MigrationRead:
+ p = " RdBgMigrCS";
+ len = 12;
+ break;
+ case P_CS_MigrationWrite:
+ p = " WrBgMigrCS";
+ len = 12;
+ break;
+ default:
+ p = " CS";
+ len = 4;
+ break;
+ }
+
+ strncpy(buf, p, len);
+ } else {
+ switch (type & P_DISKIO_TYPE) {
+ case P_RdMeta:
+ dio->is_meta = 1;
+ p = " RdMeta";
+ len = 8;
+ break;
+ case P_WrMeta:
+ dio->is_meta = 1;
+ p = " WrMeta";
+ len = 8;
+ break;
+ case P_RdData:
+ p = " RdData";
+ len = 8;
+ break;
+ case P_WrData:
+ p = " WrData";
+ len = 8;
+ break;
+ case P_PgIn:
+ p = " PgIn";
+ len = 6;
+ break;
+ case P_PgOut:
+ p = " PgOut";
+ len = 7;
+ break;
+ default:
+ p = " ";
+ len = 2;
+ break;
+ }
+
+ strncpy(buf, p, len);
+
+ buf[len++] = '[';
+
+ if (type & P_DISKIO_ASYNC)
+ buf[len++] = 'A';
+ else
+ buf[len++] = 'S';
+
+ if (type & P_DISKIO_NOCACHE)
+ buf[len++] = 'N';
+
+ int tier = (type & P_DISKIO_TIER_MASK) >> P_DISKIO_TIER_SHIFT;
+
+ if (tier > 0) {
+ buf[len++] = 'T';
+ if (tier > 0 && tier < 10)
+ buf[len++] = '0' + tier;
+
+ if (type & P_DISKIO_TIER_UPGRADE) {
+ buf[len++] = 'U';
+ }
+ }
+
+ if (type & P_DISKIO_PASSIVE)
+ buf[len++] = 'P';
+
+ buf[len++] = ']';
+ }
+
+ buf[len] = 0;
+
+ if (check_filter_mode(-1, NULL, type, 0, 0, buf)) {
+ const char *pathname = ktrace_get_path_for_vp(s, dio->vnodeid);
+ format_print(NULL, buf, NULL, type, format, dio->completed_time,
+ dio->issued_time, 1, pathname ? pathname : "", dio);
+ }
+}
+
+#pragma mark disk name routines
+
+struct diskrec {
+ struct diskrec *next;
+ char *diskname;
+ int dev;
+};
+
+struct diskrec *disk_list = NULL;
+
+void
+cache_disk_names(void)
+{
+ struct stat st;
+ DIR *dirp = NULL;
+ struct dirent *dir;
+ struct diskrec *dnp;
+
+ if ((dirp = opendir("/dev")) == NULL)
+ return;
+
+ while ((dir = readdir(dirp)) != NULL) {
+ char nbuf[MAXPATHLEN];
+
+ if (dir->d_namlen < 5 || strncmp("disk", dir->d_name, 4))
+ continue;
+
+ snprintf(nbuf, MAXPATHLEN, "%s/%s", "/dev", dir->d_name);
+
+ if (stat(nbuf, &st) < 0)
+ continue;
+
+ if ((dnp = malloc(sizeof(struct diskrec))) == NULL)
+ continue;
+
+ if ((dnp->diskname = malloc(dir->d_namlen + 1)) == NULL) {
+ free(dnp);
+ continue;
+ }
+ strncpy(dnp->diskname, dir->d_name, dir->d_namlen);
+ dnp->diskname[dir->d_namlen] = 0;
+ dnp->dev = st.st_rdev;
+
+ dnp->next = disk_list;
+ disk_list = dnp;
+ }
+
+ closedir(dirp);
+}
+
+static void
+recache_disk_names(void)
+{
+ struct diskrec *dnp, *next_dnp;
+
+ for (dnp = disk_list; dnp; dnp = next_dnp) {
+ next_dnp = dnp->next;
+
+ free(dnp->diskname);
+ free(dnp);
+ }
+
+ disk_list = NULL;
+ cache_disk_names();
+}
+
+char *
+find_disk_name(uint64_t dev)
+{
+ struct diskrec *dnp;
+ int i;
+
+ if (dev == NFS_DEV)
+ return ("NFS");
+
+ if (dev == CS_DEV)
+ return ("CS");
+
+ for (i = 0; i < 2; i++) {
+ for (dnp = disk_list; dnp; dnp = dnp->next) {
+ if (dnp->dev == dev)
+ return (dnp->diskname);
+ }
+ recache_disk_names();
+ }
+
+ return "NOTFOUND";
+}
+
+char *
+generate_cs_disk_name(uint64_t dev, char *s)
+{
+ if (dev == -1)
+ return "UNKNOWN";
+
+ sprintf(s, "disk%" PRIu64 "s%" PRIu64, (dev >> 16) & 0xffff, dev & 0xffff);
+
+ return (s);
+}
diff --git a/system_cmds/gcore.tproj/convert.c b/system_cmds/gcore.tproj/convert.c
new file mode 100644
index 0000000..b945733
--- /dev/null
+++ b/system_cmds/gcore.tproj/convert.c
@@ -0,0 +1,1117 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "convert.h"
+#include "corefile.h"
+#include "vanilla.h"
+#include "threads.h"
+#include "vm.h"
+#include "dyld_shared_cache.h"
+#include "utils.h"
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+#include <mach-o/fat.h>
+#include <uuid/uuid.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <err.h>
+#include <sysexits.h>
+#include <time.h>
+#include <glob.h>
+#include <spawn.h>
+#include <signal.h>
+#include <xpc/xpc.h>
+#include <xpc/private.h>
+#include <sys/event.h>
+#include <sys/time.h>
+
+#if defined(CONFIG_GCORE_MAP) || defined(CONFIG_GCORE_CONV) || defined(CONFIG_GCORE_FREF)
+
+static const void *
+mmapfile(int fd, off_t off, off_t *filesize)
+{
+ struct stat st;
+ if (-1 == fstat(fd, &st))
+ errc(EX_OSERR, errno, "can't stat input file");
+
+ const size_t size = (size_t)(st.st_size - off);
+ if ((off_t)size != (st.st_size - off))
+ errc(EX_OSERR, EOVERFLOW, "input file too large?");
+
+ const void *addr = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, off);
+ if ((void *)-1 == addr)
+ errc(EX_OSERR, errno, "can't mmap input file");
+ *filesize = st.st_size;
+ return addr;
+}
+
+static void
+walkcore(
+ const native_mach_header_t *mh,
+ void (^coreinfo)(const struct proto_coreinfo_command *),
+ void (^frefdata)(const struct proto_fileref_command *),
+ void (^coredata)(const struct proto_coredata_command *),
+ void (^segdata)(const native_segment_command_t *),
+ void (^thrdata)(const struct thread_command *))
+{
+ const struct load_command *lc = (const void *)(mh + 1);
+ for (unsigned i = 0; i < mh->ncmds; i++) {
+ switch (lc->cmd) {
+ case proto_LC_COREINFO:
+ if (coreinfo)
+ coreinfo((const void *)lc);
+ break;
+ case proto_LC_FILEREF:
+ if (frefdata)
+ frefdata((const void *)lc);
+ break;
+ case proto_LC_COREDATA:
+ if (coredata)
+ coredata((const void *)lc);
+ break;
+ case NATIVE_LC_SEGMENT:
+ if (segdata)
+ segdata((const void *)lc);
+ break;
+ case LC_THREAD:
+ if (thrdata)
+ thrdata((const void *)lc);
+ break;
+ default:
+ break;
+ }
+ if (NULL == (lc = next_lc(lc)))
+ break;
+ }
+}
+
+#endif
+
+#ifdef CONFIG_GCORE_FREF
+
+int
+gcore_fref(int fd)
+{
+ off_t filesize;
+ const void *corebase = mmapfile(fd, 0, &filesize);
+
+ close(fd);
+ struct flist {
+ STAILQ_ENTRY(flist) f_linkage;
+ const char *f_nm;
+ unsigned long f_nmhash;
+ };
+ STAILQ_HEAD(flisthead, flist) __flh, *flh = &__flh;
+ STAILQ_INIT(flh);
+
+ walkcore(corebase, NULL, ^(const struct proto_fileref_command *fc) {
+ const char *nm = fc->filename.offset + (const char *)fc;
+ const unsigned long nmhash = simple_namehash(nm);
+ struct flist *f;
+ STAILQ_FOREACH(f, flh, f_linkage) {
+ if (nmhash == f->f_nmhash && 0 == strcmp(f->f_nm, nm))
+ return; /* skip duplicates */
+ }
+ struct flist *nf = calloc(1, sizeof (*nf));
+ nf->f_nm = nm;
+ nf->f_nmhash = nmhash;
+ STAILQ_INSERT_TAIL(flh, nf, f_linkage);
+ }, NULL, NULL, NULL);
+
+ struct flist *f, *tf;
+ STAILQ_FOREACH_SAFE(f, flh, f_linkage, tf) {
+ printf("%s\n", f->f_nm);
+ free(f);
+ f = NULL;
+ }
+
+ munmap((void *)corebase, (size_t)filesize);
+ return 0;
+}
+
+#endif /* CONFIG_GCORE_FREF */
+
+#ifdef CONFIG_GCORE_MAP
+
+/*
+ * A pale imitation of vmmap, but for core files
+ */
+int
+gcore_map(int fd)
+{
+ off_t filesize;
+ const void *corebase = mmapfile(fd, 0, &filesize);
+
+ __block int coreversion = 0;
+
+ walkcore(corebase, ^(const struct proto_coreinfo_command *ci) {
+ coreversion = ci->version;
+ }, NULL, NULL, NULL, NULL);
+
+ if (0 == coreversion) {
+ const char titlfmt[] = "%16s-%-16s [%7s] %3s/%3s\n";
+ const char *segcfmt = "%016llx-%016llx [%7s] %3s/%3s\n";
+
+ printf(titlfmt, "start ", " end", "vsize", "prt", "max");
+ walkcore(corebase, NULL, NULL, NULL, ^(const native_segment_command_t *sc) {
+ hsize_str_t vstr;
+ printf(segcfmt, (mach_vm_offset_t)sc->vmaddr, (mach_vm_offset_t)sc->vmaddr + sc->vmsize, str_hsize(vstr, sc->vmsize), str_prot(sc->initprot), str_prot(sc->maxprot));
+ }, NULL);
+ } else {
+ const char titlfmt[] = "%-23s %16s-%-16s [%7s] %3s/%3s %6s %4s %-14s\n";
+ const char *freffmt = "%-23s %016llx-%016llx [%7s] %3s/%3s %6s %4s %-14s @%lld\n";
+ const char *datafmt = "%-23s %016llx-%016llx [%7s] %3s/%3s %6s %4s %-14s\n";
+
+ printf(titlfmt, "region type", "start ", " end", "vsize", "prt", "max", "shrmod", "purge", "region detail");
+ walkcore(corebase, NULL, ^(const struct proto_fileref_command *fc) {
+ const char *nm = fc->filename.offset + (const char *)fc;
+ tag_str_t tstr;
+ hsize_str_t vstr;
+ printf(freffmt, str_tag(tstr, fc->tag, fc->share_mode, fc->prot, fc->extp),
+ fc->vmaddr, fc->vmaddr + fc->vmsize,
+ str_hsize(vstr, fc->vmsize), str_prot(fc->prot),
+ str_prot(fc->maxprot), str_shared(fc->share_mode),
+ str_purgable(fc->purgable, fc->share_mode), nm, fc->fileoff);
+ }, ^(const struct proto_coredata_command *cc) {
+ tag_str_t tstr;
+ hsize_str_t vstr;
+ printf(datafmt, str_tag(tstr, cc->tag, cc->share_mode, cc->prot, cc->extp),
+ cc->vmaddr, cc->vmaddr + cc->vmsize,
+ str_hsize(vstr, cc->vmsize), str_prot(cc->prot),
+ str_prot(cc->maxprot), str_shared(cc->share_mode),
+ str_purgable(cc->purgable, cc->share_mode),
+ cc->vmsize && 0 == cc->filesize ? "(zfod)" : "");
+ }, ^(const native_segment_command_t *sc) {
+ hsize_str_t vstr;
+ printf(datafmt, "", (mach_vm_offset_t)sc->vmaddr,
+ (mach_vm_offset_t)sc->vmaddr + sc->vmsize,
+ str_hsize(vstr, sc->vmsize), str_prot(sc->initprot),
+ str_prot(sc->maxprot), "", "",
+ sc->vmsize && 0 == sc->filesize ? "(zfod)" : "");
+ }, NULL);
+ }
+ close(fd);
+ munmap((void *)corebase, (size_t)filesize);
+ return 0;
+}
+
+#endif
+
+#ifdef CONFIG_GCORE_CONV
+
+/*
+ * Convert an input core file into an "old" format core file
+ * (a) convert all fileref segments into regular segments
+ * (b) uncompress anything we find compressed.
+ * This should be equivalent to a copy for an "old" format core file.
+ */
+
+static int
+machocmp(const native_mach_header_t *tmh, const native_mach_header_t *mh, const struct proto_fileref_command *fr)
+{
+ if (tmh->magic == mh->magic) {
+ const struct load_command *lc = (const void *)(tmh + 1);
+ for (unsigned i = 0; i < tmh->ncmds; i++) {
+ if (LC_UUID == lc->cmd && lc->cmdsize >= sizeof (struct uuid_command)) {
+ const struct uuid_command *uc = (const void *)lc;
+ return uuid_compare(uc->uuid, fr->id);
+ }
+ if (NULL == (lc = next_lc(lc)))
+ break;
+ }
+ }
+ return -1;
+}
+
+static int
+fat_machocmp(const struct fat_header *fh, const native_mach_header_t *mh, const struct proto_fileref_command *fr, off_t *reloff)
+{
+ const uint32_t (^get32)(uint32_t);
+
+ if (FAT_MAGIC == fh->magic) {
+ get32 = ^(uint32_t val) {
+ return val;
+ };
+ } else {
+ get32 = ^(uint32_t val) {
+ uint32_t result = 0;
+ for (unsigned i = 0; i < sizeof (uint32_t); i++)
+ ((uint8_t *)&result)[i] = ((uint8_t *)&val)[3-i];
+ return result;
+ };
+ }
+
+ assert(FAT_MAGIC == get32(fh->magic));
+ assert(kFREF_ID_UUID == FREF_ID_TYPE(fr->flags) && !uuid_is_null(fr->id));
+
+ const struct fat_arch *fa = (const struct fat_arch *)(fh + 1);
+ uint32_t narch = get32(fh->nfat_arch);
+ for (unsigned n = 0; n < narch; n++, fa++) {
+ const native_mach_header_t *tmh = (const void *)(((const char *)fh) + get32(fa->offset));
+ if (tmh->magic == mh->magic && 0 == machocmp(tmh, mh, fr)) {
+ *reloff = get32(fa->offset);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+struct output_info {
+ int oi_fd;
+ off_t oi_foffset;
+ bool oi_nocache;
+};
+
+static struct convstats {
+ int64_t copied;
+ int64_t added;
+ int64_t compressed;
+ int64_t uncompressed;
+} cstat, *cstats = &cstat;
+
+/*
+ * A fileref segment references a read-only file that contains pages from
+ * the image. The file may be a Mach binary or dylib identified with a uuid.
+ */
+static int
+convert_fileref_with_file(const char *filename, const native_mach_header_t *inmh, const struct proto_fileref_command *infr, const struct vm_range *invr, struct load_command *lc, struct output_info *oi)
+{
+ assert(invr->addr == infr->vmaddr && invr->size == infr->vmsize);
+
+ struct stat st;
+ const int rfd = open(filename, O_RDONLY);
+ if (-1 == rfd || -1 == fstat(rfd, &st)) {
+ warnc(errno, "%s: open", filename);
+ return EX_IOERR;
+ }
+ const size_t rlen = (size_t)st.st_size;
+ void *raddr = mmap(NULL, rlen, PROT_READ, MAP_PRIVATE, rfd, 0);
+ if ((void *)-1 == raddr) {
+ warnc(errno, "%s: mmap", filename);
+ close(rfd);
+ return EX_IOERR;
+ }
+ close(rfd);
+
+ off_t fatoff = 0; /* for FAT objects */
+ int ecode = EX_DATAERR;
+
+ switch (FREF_ID_TYPE(infr->flags)) {
+ case kFREF_ID_UUID: {
+ /* file should be a mach binary: check that uuid matches */
+ const uint32_t magic = *(uint32_t *)raddr;
+ switch (magic) {
+ case FAT_MAGIC:
+ case FAT_CIGAM:
+ if (0 == fat_machocmp(raddr, inmh, infr, &fatoff))
+ ecode = 0;
+ break;
+ case NATIVE_MH_MAGIC:
+ if (0 == machocmp(raddr, inmh, infr))
+ ecode = 0;
+ break;
+ default: {
+ /*
+ * Maybe this is the shared cache?
+ */
+ uuid_t uu;
+ if (get_uuid_from_shared_cache_mapping(raddr, rlen, uu) && uuid_compare(uu, infr->id) == 0)
+ ecode = 0;
+ break;
+ }
+ }
+ break;
+ }
+ case kFREF_ID_MTIMESPEC_LE:
+ /* file should have the same mtime */
+ if (0 == memcmp(&st.st_mtimespec, infr->id, sizeof (infr->id)))
+ ecode = 0;
+ break;
+ case kFREF_ID_NONE:
+ /* file has no uniquifier, copy it anyway */
+ break;
+ }
+
+ if (0 != ecode) {
+ munmap(raddr, rlen);
+ warnx("%s doesn't match corefile content", filename);
+ return ecode;
+ }
+
+ const off_t fileoff = fatoff + infr->fileoff;
+ const void *start = (const char *)raddr + fileoff;
+ const size_t len = (size_t)infr->filesize;
+ void *zaddr = NULL;
+ size_t zlen = 0;
+
+ if (fileoff + (off_t)infr->filesize > (off_t)rlen) {
+ /*
+ * the file content needed (as described on machine with
+ * larger pagesize) extends beyond the end of the mapped
+ * file using our smaller pagesize. Zero pad it.
+ */
+ const size_t pagesize_host = 1ul << pageshift_host;
+ void *endaddr = (caddr_t)raddr + roundup(rlen, pagesize_host);
+ zlen = (size_t)(fileoff + infr->filesize - rlen);
+ zaddr = mmap(endaddr, zlen, PROT_READ, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
+ if ((void *)-1 == zaddr) {
+ hsize_str_t hstr;
+ warnc(errno, "cannot zero-pad %s mapping for %s", str_hsize(hstr, zlen),filename);
+ munmap(raddr, rlen);
+ return EX_IOERR;
+ }
+ }
+
+ if (-1 == madvise((void *)start, len, MADV_SEQUENTIAL))
+ warnc(errno, "%s: madvise", filename);
+
+ const int error = bounded_pwrite(oi->oi_fd, start, len, oi->oi_foffset, &oi->oi_nocache, NULL);
+
+ if (zlen) {
+ if (-1 == munmap(zaddr, zlen))
+ warnc(errno, "%s: munmap zero pad", filename);
+ }
+ if (-1 == munmap(raddr, rlen))
+ warnc(errno, "%s: munmap", filename);
+ if (error) {
+ warnc(error, "while copying %s to core file", filename);
+ return EX_IOERR;
+ }
+
+ const struct file_range fr = {
+ .off = oi->oi_foffset,
+ .size = infr->filesize,
+ };
+ make_native_segment_command(lc, invr, &fr, infr->maxprot, infr->prot);
+ oi->oi_foffset += fr.size;
+ cstats->added += infr->filesize;
+ return 0;
+}
+
+/*
+ * expanduser tries to expand the leading '~' (if there is any) in the given
+ * path and returns a copy of the expanded path; it returns NULL on failures.
+ * The caller is responsible for freeing the returned string.
+ */
+static char *
+expanduser(const char *path)
+{
+ if (path == NULL) {
+ return NULL;
+ }
+ if (path[0] != '~') {
+ /*
+ * For consistency, still dup the string so that the caller always
+ * needs to free the string.
+ */
+ return strdup(path);
+ }
+
+ char *expanded = NULL;
+ glob_t globbuf = {};
+ if (OPTIONS_DEBUG(opt, 1)) {
+ printf("Expanding %s\n", path);
+ }
+ int rc = glob(path, GLOB_TILDE, NULL, &globbuf);
+ if (rc == 0) {
+ if (OPTIONS_DEBUG(opt, 3)) {
+ printf("expanduser - gl_pathc: %zu\n", globbuf.gl_pathc);
+ for (size_t i = 0; i < globbuf.gl_pathc; i++) {
+ printf("expanduser - gl_pathv[%zu]: %s\n", i, globbuf.gl_pathv[i]);
+ }
+ }
+ if (globbuf.gl_pathc == 1) {
+ expanded = strdup(globbuf.gl_pathv[0]);
+ if (OPTIONS_DEBUG(opt, 1)) {
+ printf("Expanded path: %s\n", expanded);
+ }
+ }
+ globfree(&globbuf);
+ }
+
+ return expanded;
+}
+
+#define RESPONSE_BUFF_SIZE (2048)
+
+/*
+ * read_response dynamically allocates buffer for reading bytes from the given
+ * fd. Upon success, this function sets response to point to the buffer and
+ * returns bytes being read; otherwise, it returns -1. The caller is
+ * responsible for freeing the response buffer.
+ */
+static ssize_t
+read_response(int fd, char **response)
+{
+ if (response == NULL || *response) {
+ warnx("Invalid response buffer pointer");
+ return -1;
+ }
+
+ ssize_t bytes_read = 0;
+ size_t buff_size = RESPONSE_BUFF_SIZE;
+
+ if (OPTIONS_DEBUG(opt, 3)) {
+ printf("Allocating response buffer (%zu)\n", buff_size);
+ }
+ char *buff = malloc(buff_size);
+ if (buff == NULL) {
+ warn("Failed to allocate response buffer (%zu)", buff_size);
+ return -1;
+ }
+
+ size_t total = 0;
+ bool failed = false;
+
+ do {
+ bytes_read = read(fd, buff + total, buff_size - total);
+ if (bytes_read == -1) {
+ if (errno == EINTR) {
+ continue;
+ }
+ failed = true;
+ break;
+ }
+
+ total += (size_t)bytes_read;
+ if (total == buff_size) {
+ size_t new_buff_size = buff_size * 2;
+ if (OPTIONS_DEBUG(opt, 3)) {
+ printf("Reallocating response buffer (%zu)\n", new_buff_size);
+ }
+ char *new_buff = realloc(buff, new_buff_size);
+ if (new_buff == NULL) {
+ warn("Failed to reallocate response buffer (%zu)", new_buff_size);
+ failed = true;
+ break;
+ }
+ buff_size = new_buff_size;
+ buff = new_buff;
+ }
+ } while (bytes_read != 0);
+
+ if (failed) {
+ if (buff != NULL) {
+ free(buff);
+ }
+ return -1;
+ }
+
+ assert(total < buff_size);
+ buff[total] = '\0';
+ *response = buff;
+
+ return (ssize_t)total;
+}
+
+#define WAITPID_WTO_SIGALRM (100) /* alternative for SIGALRM for kevent timeout */
+#define WAITPID_WTO_SIGERR (101) /* sig for error when waiting for pid */
+
+/*
+ * waitpid_with_timeout returns true if the process exits successfully within
+ * timeout; otherwise, it returns false along with setting exitstatus and
+ * signal_no if the pointers are given.
+ */
+static bool
+waitpid_with_timeout(pid_t pid, int *exitstatus, int *signal_no, int timeout)
+{
+ int status;
+ int kq = -1;
+
+ if (timeout > 0) {
+ kq = kqueue();
+ struct kevent64_s event = {
+ .ident = (uint64_t)pid,
+ .filter = EVFILT_PROC,
+ .flags = EV_ADD | EV_ONESHOT,
+ .fflags = NOTE_EXIT
+ };
+ struct timespec tmout = {
+ .tv_sec = timeout
+ };
+ int ret = kevent64(kq, &event, 1, &event, 1, 0, &tmout);
+ int kevent64_errno = errno;
+
+ close(kq);
+ if (ret == 0) { /* timeout */
+ if (exitstatus) {
+ *exitstatus = 0;
+ }
+ if (signal_no) {
+ *signal_no = WAITPID_WTO_SIGALRM;
+ }
+ return false;
+ }
+
+ if (ret == -1) {
+ warnx("kevent64(): errno=%d (%s)\n", kevent64_errno, strerror(kevent64_errno));
+ goto waitpid_error;
+ }
+
+ if (event.flags == EV_ERROR && event.data != ESRCH) {
+ warnx("event.data (%lld) is not ESRCH when event.flags is EV_ERROR\n", event.data);
+ goto waitpid_error;
+ }
+
+ if (event.ident != (uint64_t)pid) {
+ warnx("event.ident is %lld (should be pid %d)\n", event.ident, pid);
+ goto waitpid_error;
+ }
+
+ if (event.filter != EVFILT_PROC) {
+ warnx("event.filter (%d) is not EVFILT_PROC\n", event.filter);
+ goto waitpid_error;
+ }
+ }
+
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ warnx("waitpid(): errno=%d (%s)\n", errno, strerror(errno));
+ goto waitpid_error;
+ }
+ if (WIFEXITED(status)) {
+ if (exitstatus) {
+ *exitstatus = WEXITSTATUS(status);
+ }
+ if (signal_no) {
+ *signal_no = 0;
+ }
+ return WEXITSTATUS(status) == 0;
+ }
+ if (WIFSIGNALED(status)) {
+ if (exitstatus) {
+ *exitstatus = 0;
+ }
+ if (signal_no) {
+ *signal_no = WTERMSIG(status);
+ }
+ return false;
+ }
+
+waitpid_error:
+ if (exitstatus) *exitstatus = 0;
+ if (signal_no) *signal_no = WAITPID_WTO_SIGERR;
+ return false;
+}
+
+#define DSYMFORUUID_PATH "/usr/local/bin/dsymForUUID"
+
+/*
+ * exec_dsymForUUID spawns dsymForUUID to query dsym UUID info and responds the
+ * result plist. Upon success, this function sets response point to the buffer
+ * and returns bytes being read; otherwise, it returns -1. The caller is
+ * responsible for freeing the response buffer.
+ */
+static ssize_t
+exec_dsymForUUID(uuid_string_t id, char **response)
+{
+ int pipe_fds[2] = {-1, -1};
+ bool file_actions_inited = false;
+ ssize_t bytes_read = -1;
+ int rc;
+
+ rc = pipe(pipe_fds);
+ if (rc == -1) {
+ goto cleanup;
+ }
+
+ posix_spawn_file_actions_t file_actions;
+ rc = posix_spawn_file_actions_init(&file_actions);
+ if (rc) {
+ goto cleanup;
+ }
+ file_actions_inited = true;
+
+ rc = posix_spawn_file_actions_addclose(&file_actions, pipe_fds[0]);
+ if (rc) {
+ goto cleanup;
+ }
+
+ rc = posix_spawn_file_actions_adddup2(&file_actions, pipe_fds[1], STDOUT_FILENO);
+ if (rc) {
+ goto cleanup;
+ }
+
+ rc = posix_spawn_file_actions_addclose(&file_actions, pipe_fds[1]);
+ if (rc) {
+ goto cleanup;
+ }
+
+ char *command[] = {DSYMFORUUID_PATH, id, NULL};
+ pid_t child;
+ rc = posix_spawn(&child, command[0], &file_actions, NULL, command, NULL);
+ if (rc) {
+ goto cleanup;
+ }
+
+ close(pipe_fds[1]);
+ pipe_fds[1] = -1;
+
+ bytes_read = read_response(pipe_fds[0], response);
+
+ waitpid_with_timeout(child, NULL, NULL, 3);
+
+cleanup:
+ if (pipe_fds[1] != -1) {
+ close(pipe_fds[1]);
+ }
+ if (pipe_fds[0] != -1) {
+ close(pipe_fds[0]);
+ }
+ if (file_actions_inited) {
+ posix_spawn_file_actions_destroy(&file_actions);
+ }
+
+ return bytes_read;
+}
+
+/*
+ * get_symbol_rich_executable_path_via_dsymForUUID spawns dsymForUUID to query
+ * dsym uuid info for the given uuid and returns the string of
+ * DBGSymbolRichExecutable; otherwise, it returns NULL on failures. The caller
+ * is responsible for freeing the returned string.
+ */
+static char *
+get_symbol_rich_executable_path_via_dsymForUUID(const uuid_t uuid)
+{
+ char *response;
+ ssize_t size;
+ uuid_string_t uuid_str;
+ xpc_object_t plist = NULL;
+ xpc_object_t uuid_info = NULL;
+ xpc_object_t exec_path = NULL;
+ char *expanded_exec_path = NULL;
+
+ uuid_unparse_upper(uuid, uuid_str);
+
+ size = exec_dsymForUUID(uuid_str, &response);
+ if (size <= 0) {
+ goto cleanup;
+ }
+
+ if (OPTIONS_DEBUG(opt, 3)) {
+ printf("dsymForUUID response:\n%s\n", response);
+ }
+
+ plist = xpc_create_from_plist(response, (size_t)size);
+ if (plist == NULL) {
+ goto cleanup;
+ }
+ if (xpc_get_type(plist) != XPC_TYPE_DICTIONARY) {
+ goto cleanup;
+ }
+
+ uuid_info = xpc_dictionary_get_value(plist, uuid_str);
+ if (uuid_info == NULL) {
+ goto cleanup;
+ }
+ if (xpc_get_type(uuid_info) != XPC_TYPE_DICTIONARY) {
+ goto cleanup;
+ }
+
+ exec_path = xpc_dictionary_get_value(uuid_info, "DBGSymbolRichExecutable");
+ if (exec_path == NULL) {
+ goto cleanup;
+ }
+ if (xpc_get_type(exec_path) != XPC_TYPE_STRING) {
+ goto cleanup;
+ }
+
+ expanded_exec_path = expanduser(xpc_string_get_string_ptr(exec_path));
+
+cleanup:
+ if (plist) {
+ xpc_release(plist);
+ }
+ if (response) {
+ free(response);
+ }
+
+ return expanded_exec_path;
+}
+
+/*
+ * bind the file reference into the output core file.
+ * filename optionally prefixed with names from a ':'-separated PATH variable
+ */
+static int
+convert_fileref(const char *path, bool zf, const native_mach_header_t *inmh, const struct proto_fileref_command *infr, struct load_command *lc, struct output_info *oi)
+{
+ const char *nm = infr->filename.offset + (const char *)infr;
+ uuid_string_t uustr;
+ const struct vm_range invr = {
+ .addr = infr->vmaddr,
+ .size = infr->vmsize,
+ };
+
+ if (opt->verbose) {
+ hsize_str_t hstr;
+ printvr(&invr, "adding %s from '%s'",
+ str_hsize(hstr, (off_t)infr->filesize), nm);
+ switch (FREF_ID_TYPE(infr->flags)) {
+ case kFREF_ID_NONE:
+ break;
+ case kFREF_ID_UUID:
+ uuid_unparse_lower(infr->id, uustr);
+ printf(" (%s)", uustr);
+ break;
+ case kFREF_ID_MTIMESPEC_LE: {
+ struct timespec mts;
+ struct tm tm;
+ char tbuf[4 + 2 + 2 + 2 + 2 + 1 + 2 + 1]; /* touch -t */
+ memcpy(&mts, &infr->id, sizeof (mts));
+ localtime_r(&mts.tv_sec, &tm);
+ strftime(tbuf, sizeof (tbuf), "%Y%m%d%H%M.%S", &tm);
+ printf(" (%s)", tbuf);
+ } break;
+ }
+ printf("\n");
+ }
+
+ int ecode = 0;
+ if (opt->dsymforuuid && (FREF_ID_TYPE(infr->flags) == kFREF_ID_UUID)) {
+ /* Try to use dsymForUUID to get the symbol-rich executable */
+ char *symrich_filepath = get_symbol_rich_executable_path_via_dsymForUUID(infr->id);
+ if (symrich_filepath) {
+ if (opt->verbose) {
+ printf("\tTrying %s from dsymForUUID\n", symrich_filepath);
+ }
+ ecode = convert_fileref_with_file(symrich_filepath, inmh, infr, &invr, lc, oi);
+ free(symrich_filepath);
+ if (ecode == 0) {
+ return (ecode);
+ }
+ warnx("Failed to convert fileref with dsymForUUID. Fall back to local paths");
+ }
+ }
+
+ const size_t pathsize = path ? strlen(path) : 0;
+ ecode = EX_DATAERR;
+ if (0 == pathsize)
+ ecode = convert_fileref_with_file(nm, inmh, infr, &invr, lc, oi);
+ else {
+ /* search the : separated path (-L) for possible matches */
+ char *pathcopy = strdup(path);
+ char *searchpath = pathcopy;
+ const char *token;
+
+ while ((token = strsep(&searchpath, ":")) != NULL) {
+ const size_t buflen = strlen(token) + 1 + strlen(nm) + 1;
+ char *buf = malloc(buflen);
+ snprintf(buf, buflen, "%s%s%s", token, '/' == nm[0] ? "" : "/", nm);
+ if (opt->verbose)
+ printf("\tTrying '%s'", buf);
+ if (0 == access(buf, R_OK)) {
+ if (opt->verbose)
+ printf("\n");
+ ecode = convert_fileref_with_file(buf, inmh, infr, &invr, lc, oi);
+ if (0 == ecode) {
+ free(buf);
+ break;
+ }
+ } else if (opt->verbose)
+ printf(": %s.\n",
+ 0 == access(buf, F_OK) ? "Unreadable" : "Not present");
+ free(buf);
+ }
+ free(pathcopy);
+ }
+
+ if (0 != ecode && zf) {
+ /*
+ * Failed to find the file reference. If this was a fileref that uses
+ * a file metadata tagging method (e.g. mtime), allow the user to subsitute a
+ * zfod region: assumes that it's better to have something to debug
+ * vs. nothing. UUID-tagged filerefs are Mach-O tags, and are
+ * assumed to be never substitutable.
+ */
+ switch (FREF_ID_TYPE(infr->flags)) {
+ case kFREF_ID_NONE:
+ case kFREF_ID_MTIMESPEC_LE: { // weak tagging, allow zfod substitution
+ const struct file_range outfr = {
+ .off = oi->oi_foffset,
+ .size = 0,
+ };
+ if (opt->verbose)
+ printf("\tWARNING: no file matched. Missing content is now zfod\n");
+ else
+ printvr(&invr, "WARNING: missing content (%s) now zfod\n", nm);
+ make_native_segment_command(lc, &invr, &outfr, infr->maxprot, infr->prot);
+ ecode = 0;
+ } break;
+ default:
+ break;
+ }
+ }
+
+ return (ecode);
+}
+
+static int
+segment_uncompflags(unsigned algnum, compression_algorithm *ca)
+{
+ switch (algnum) {
+ case kCOMP_LZ4:
+ *ca = COMPRESSION_LZ4;
+ break;
+ case kCOMP_ZLIB:
+ *ca = COMPRESSION_ZLIB;
+ break;
+ case kCOMP_LZMA:
+ *ca = COMPRESSION_LZMA;
+ break;
+ case kCOMP_LZFSE:
+ *ca = COMPRESSION_LZFSE;
+ break;
+ default:
+ warnx("unknown compression flavor %d", algnum);
+ return EX_DATAERR;
+ }
+ return 0;
+}
+
+static int
+convert_region(const void *inbase, const struct vm_range *invr, const struct file_range *infr, const vm_prot_t prot, const vm_prot_t maxprot, const int flavor, struct load_command *lc, struct output_info *oi)
+{
+ int ecode = 0;
+
+ if (F_SIZE(infr)) {
+ void *input = (const caddr_t)inbase + F_OFF(infr);
+ void *buf;
+
+ if (0 == flavor) {
+ buf = input;
+ if (opt->verbose) {
+ hsize_str_t hstr;
+ printvr(invr, "copying %s\n", str_hsize(hstr, F_SIZE(infr)));
+ }
+ } else {
+ compression_algorithm ca;
+
+ if (0 != (ecode = segment_uncompflags(flavor, &ca)))
+ return ecode;
+ if (opt->verbose) {
+ hsize_str_t hstr1, hstr2;
+ printvr(invr, "uncompressing %s to %s\n",
+ str_hsize(hstr1, F_SIZE(infr)), str_hsize(hstr2, V_SIZE(invr)));
+ }
+ const size_t buflen = V_SIZEOF(invr);
+ buf = malloc(buflen);
+ const size_t dstsize = compression_decode_buffer(buf, buflen, input, (size_t)F_SIZE(infr), NULL, ca);
+ if (buflen != dstsize) {
+ warnx("failed to uncompress segment");
+ free(buf);
+ return EX_DATAERR;
+ }
+ cstats->compressed += F_SIZE(infr);
+ }
+ const int error = bounded_pwrite(oi->oi_fd, buf, V_SIZEOF(invr), oi->oi_foffset, &oi->oi_nocache, NULL);
+ if (error) {
+ warnc(error, "failed to write data to core file");
+ ecode = EX_IOERR;
+ }
+ if (buf != input)
+ free(buf);
+ if (ecode)
+ return ecode;
+
+ const struct file_range outfr = {
+ .off = oi->oi_foffset,
+ .size = V_SIZE(invr),
+ };
+ make_native_segment_command(lc, invr, &outfr, maxprot, prot);
+ oi->oi_foffset += outfr.size;
+
+ if (0 == flavor)
+ cstats->copied += outfr.size;
+ else
+ cstats->uncompressed += outfr.size;
+ } else {
+ if (opt->verbose) {
+ hsize_str_t hstr;
+ printvr(invr, "%s remains zfod\n", str_hsize(hstr, V_SIZE(invr)));
+ }
+ const struct file_range outfr = {
+ .off = oi->oi_foffset,
+ .size = 0,
+ };
+ make_native_segment_command(lc, invr, &outfr, maxprot, prot);
+ }
+ return ecode;
+}
+
+static int
+convert_coredata(const void *inbase, const native_mach_header_t *__unused inmh, const struct proto_coredata_command *cc, struct load_command *lc, struct output_info *oi)
+{
+ const struct vm_range vr = {
+ .addr = cc->vmaddr,
+ .size = cc->vmsize,
+ };
+ const struct file_range fr = {
+ .off = cc->fileoff,
+ .size = cc->filesize,
+ };
+ return convert_region(inbase, &vr, &fr, cc->prot, cc->maxprot, COMP_ALG_TYPE(cc->flags), lc, oi);
+}
+
+static int
+convert_segment(const void *inbase, const native_mach_header_t *__unused inmh, const native_segment_command_t *sc, struct load_command *lc, struct output_info *oi)
+{
+ const struct vm_range vr = {
+ .addr = sc->vmaddr,
+ .size = sc->vmsize,
+ };
+ const struct file_range fr = {
+ .off = sc->fileoff,
+ .size = sc->filesize,
+ };
+ return convert_region(inbase, &vr, &fr, sc->initprot, sc->maxprot, 0, lc, oi);
+}
+
+/* pass-through - content is all in the header */
+
+static int
+convert_thread(struct thread_command *dst, const struct thread_command *src)
+{
+ assert(LC_THREAD == src->cmd);
+ memcpy(dst, src, src->cmdsize);
+ cstats->copied += src->cmdsize;
+ return 0;
+}
+
+int
+gcore_conv(int infd, const char *searchpath, bool zf, int fd)
+{
+ off_t filesize;
+ const void *corebase = mmapfile(infd, 0, &filesize);
+ close(infd);
+ /*
+ * Check to see if the input file is "sane" as far as we're concerned.
+ * XXX Note that this -won't- necessarily work for other ISAs than
+ * our own!
+ */
+ const native_mach_header_t *inmh = corebase;
+ validate_core_header(inmh, filesize);
+
+ /*
+ * The sparse file may have created many more segments, but there's no
+ * attempt to change their numbers here. Just count all the segment
+ * types needed to figure out the size of the output file header.
+ *
+ * (Size assertions to be deleted once data structures stable!)
+ */
+ __block size_t headersize = sizeof (native_mach_header_t);
+ __block unsigned pageshift_target = pageshift_host;
+
+ walkcore(inmh, ^(const struct proto_coreinfo_command *ci) {
+ assert(sizeof (*ci) == ci->cmdsize);
+ if (opt->verbose)
+ printf("Converting version %d core file to pre-versioned format\n", ci->version);
+ if (0 < ci->pageshift && ci->pageshift < 31)
+ pageshift_target = ci->pageshift;
+ else if (CPU_TYPE_ARM64 == inmh->cputype)
+ pageshift_target = 14; // compatibility hack, should go soon
+ }, ^(const struct proto_fileref_command *__unused fc) {
+ const char *nm = fc->filename.offset + (const char *)fc;
+ size_t nmlen = strlen(nm) + 1;
+ size_t cmdsize = sizeof (*fc) + roundup(nmlen, sizeof (long));
+ assert(cmdsize == fc->cmdsize);
+
+ headersize += sizeof (native_segment_command_t);
+ }, ^(const struct proto_coredata_command *__unused cc) {
+ assert(sizeof (*cc) == cc->cmdsize);
+ headersize += sizeof (native_segment_command_t);
+ }, ^(const native_segment_command_t *sc) {
+ headersize += sc->cmdsize;
+ }, ^(const struct thread_command *tc) {
+ headersize += tc->cmdsize;
+ });
+
+ void *header = calloc(1, headersize);
+ if (NULL == header)
+ errx(EX_OSERR, "out of memory for header");
+
+ native_mach_header_t *mh = memcpy(header, inmh, sizeof (*mh));
+ mh->ncmds = 0;
+ mh->sizeofcmds = 0;
+
+ assert(0 < pageshift_target && pageshift_target < 31);
+ const vm_offset_t pagesize_target = ((vm_offset_t)1 << pageshift_target);
+ const vm_offset_t pagemask_target = pagesize_target - 1;
+
+ const struct load_command *inlc = (const void *)(inmh + 1);
+ struct load_command *lc = (void *)(mh + 1);
+ int ecode = 0;
+
+ struct output_info oi = {
+ .oi_fd = fd,
+ .oi_foffset = ((vm_offset_t)headersize + pagemask_target) & ~pagemask_target,
+ .oi_nocache = false,
+ };
+
+ for (unsigned i = 0; i < inmh->ncmds; i++) {
+ switch (inlc->cmd) {
+ case proto_LC_FILEREF:
+ ecode = convert_fileref(searchpath, zf, inmh, (const void *)inlc, lc, &oi);
+ break;
+ case proto_LC_COREDATA:
+ ecode = convert_coredata(corebase, inmh, (const void *)inlc, lc, &oi);
+ break;
+ case NATIVE_LC_SEGMENT:
+ ecode = convert_segment(corebase, inmh, (const void *)inlc, lc, &oi);
+ break;
+ case LC_THREAD:
+ ecode = convert_thread((void *)lc, (const void *)inlc);
+ break;
+ default:
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("discarding load command %d\n", inlc->cmd);
+ break;
+ }
+ if (0 != ecode)
+ break;
+ if (NATIVE_LC_SEGMENT == lc->cmd || LC_THREAD == lc->cmd) {
+ mach_header_inc_ncmds(mh, 1);
+ mach_header_inc_sizeofcmds(mh, lc->cmdsize);
+ lc = (void *)next_lc(lc);
+ }
+ if (NULL == (inlc = next_lc(inlc)))
+ break;
+ }
+
+ /*
+ * Even if we've encountered an error, try and write out the header
+ */
+ if (0 != bounded_pwrite(fd, header, headersize, 0, &oi.oi_nocache, NULL))
+ ecode = EX_IOERR;
+ if (0 == ecode && sizeof (*mh) + mh->sizeofcmds != headersize)
+ ecode = EX_SOFTWARE;
+ validate_core_header(mh, oi.oi_foffset);
+ if (ecode)
+ warnx("failed to write new core file correctly");
+ else if (opt->verbose) {
+ hsize_str_t hstr;
+ printf("Conversion complete: %s copied", str_hsize(hstr, cstats->copied));
+ const int64_t delta = cstats->uncompressed - cstats->compressed;
+ if (delta > 0)
+ printf(", %s uncompressed", str_hsize(hstr, delta));
+ const int64_t added = cstats->added + ((int)mh->sizeofcmds - (int)inmh->sizeofcmds);
+ if (added > 0)
+ printf(", %s added", str_hsize(hstr, added));
+ printf("\n");
+ }
+ free(header);
+ munmap((void *)corebase, (size_t)filesize);
+ return ecode;
+}
+#endif
diff --git a/system_cmds/gcore.tproj/convert.h b/system_cmds/gcore.tproj/convert.h
new file mode 100644
index 0000000..03854b8
--- /dev/null
+++ b/system_cmds/gcore.tproj/convert.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+
+#include <stdbool.h>
+
+#ifndef _CONVERT_H
+#define _CONVERT_H
+
+#ifdef CONFIG_GCORE_FREF
+extern int gcore_fref(int);
+#endif
+
+#ifdef CONFIG_GCORE_MAP
+extern int gcore_map(int);
+#endif
+
+#ifdef CONFIG_GCORE_CONV
+extern int gcore_conv(int, const char *, bool, int);
+#endif
+
+#endif /* _CONVERT_H */
diff --git a/system_cmds/gcore.tproj/corefile.c b/system_cmds/gcore.tproj/corefile.c
new file mode 100644
index 0000000..b1e4421
--- /dev/null
+++ b/system_cmds/gcore.tproj/corefile.c
@@ -0,0 +1,852 @@
+/*
+ * Copyright (c) 2016-2018 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "corefile.h"
+#include "sparse.h"
+#include "utils.h"
+#include "vm.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <compression.h>
+#include <sys/param.h>
+#include <libgen.h>
+#include <sys/stat.h>
+
+native_mach_header_t *
+make_corefile_mach_header(void *data)
+{
+ native_mach_header_t *mh = data;
+ mh->magic = NATIVE_MH_MAGIC;
+ mh->filetype = MH_CORE;
+#if defined(__LP64__)
+ const int is64 = 1;
+#else
+ const int is64 = 0;
+#endif
+#if defined(__i386__) || defined(__x86_64__)
+ mh->cputype = is64 ? CPU_TYPE_X86_64 : CPU_TYPE_I386;
+ mh->cpusubtype = is64 ? CPU_SUBTYPE_X86_64_ALL : CPU_SUBTYPE_I386_ALL;
+#elif defined(__arm__) || defined(__arm64__)
+ mh->cputype = is64 ? CPU_TYPE_ARM64 : CPU_TYPE_ARM;
+ mh->cpusubtype = is64 ? CPU_SUBTYPE_ARM64_ALL : CPU_SUBTYPE_ARM_ALL;
+#else
+#error undefined
+#endif
+ return mh;
+}
+
+struct proto_coreinfo_command *
+make_coreinfo_command(native_mach_header_t *mh, void *data, const uuid_t aoutid, uint64_t address, uint64_t dyninfo)
+{
+ struct proto_coreinfo_command *cc = data;
+ cc->cmd = proto_LC_COREINFO;
+ cc->cmdsize = sizeof (*cc);
+ cc->version = 1;
+ cc->type = proto_CORETYPE_USER;
+ cc->pageshift = (uint16_t)pageshift_host;
+ cc->address = address;
+ uuid_copy(cc->uuid, aoutid);
+ cc->dyninfo = dyninfo;
+ mach_header_inc_ncmds(mh, 1);
+ mach_header_inc_sizeofcmds(mh, cc->cmdsize);
+ return cc;
+}
+
+native_segment_command_t *
+make_native_segment_command(void *data, const struct vm_range *vr, const struct file_range *fr, vm_prot_t maxprot, vm_prot_t initprot)
+{
+ native_segment_command_t *sc = data;
+ sc->cmd = NATIVE_LC_SEGMENT;
+ sc->cmdsize = sizeof (*sc);
+ assert(V_SIZE(vr));
+ sc->vmaddr = (unsigned long)V_ADDR(vr);
+ sc->vmsize = (unsigned long)V_SIZE(vr);
+ sc->fileoff = (unsigned long)F_OFF(fr);
+ sc->filesize = (unsigned long)F_SIZE(fr);
+ sc->maxprot = maxprot;
+ sc->initprot = initprot;
+ sc->nsects = 0;
+ sc->flags = 0;
+ return sc;
+}
+
+static struct proto_coredata_command *
+make_coredata_command(void *data, const struct vm_range *vr, const struct file_range *fr, const vm_region_submap_info_data_64_t *info, unsigned comptype, unsigned purgable)
+{
+ struct proto_coredata_command *cc = data;
+ cc->cmd = proto_LC_COREDATA;
+ cc->cmdsize = sizeof (*cc);
+ assert(V_SIZE(vr));
+ cc->vmaddr = V_ADDR(vr);
+ cc->vmsize = V_SIZE(vr);
+ cc->fileoff = F_OFF(fr);
+ cc->filesize = F_SIZE(fr);
+ cc->maxprot = info->max_protection;
+ cc->prot = info->protection;
+ cc->flags = COMP_MAKE_FLAGS(comptype);
+ cc->share_mode = info->share_mode;
+ assert(purgable <= UINT8_MAX);
+ cc->purgable = (uint8_t)purgable;
+ assert(info->user_tag <= UINT8_MAX);
+ cc->tag = (uint8_t)info->user_tag;
+ cc->extp = info->external_pager;
+ return cc;
+}
+
+static size_t
+sizeof_segment_command(void) {
+ return opt->extended ?
+ sizeof (struct proto_coredata_command) : sizeof (native_segment_command_t);
+}
+
+static struct load_command *
+make_segment_command(void *data, const struct vm_range *vr, const struct file_range *fr, const vm_region_submap_info_data_64_t *info, unsigned comptype, int purgable)
+{
+ if (opt->extended)
+ make_coredata_command(data, vr, fr, info, comptype, purgable);
+ else
+ make_native_segment_command(data, vr, fr, info->max_protection, info->protection);
+ return data;
+}
+
+/*
+ * Increment the mach-o header data when we succeed
+ */
+static void
+commit_load_command(struct write_segment_data *wsd, const struct load_command *lc)
+{
+ wsd->wsd_lc = (caddr_t)lc + lc->cmdsize;
+ native_mach_header_t *mh = wsd->wsd_mh;
+ mach_header_inc_ncmds(mh, 1);
+ mach_header_inc_sizeofcmds(mh, lc->cmdsize);
+}
+
+#pragma mark -- Regions written as "file references" --
+
+static size_t
+cmdsize_fileref_command(const char *nm)
+{
+ size_t cmdsize = sizeof (struct proto_fileref_command);
+ size_t len;
+ if (0 != (len = strlen(nm))) {
+ len++; // NUL-terminated for mmap sanity
+ cmdsize += roundup(len, sizeof (long));
+ }
+ return cmdsize;
+}
+
+static void
+size_fileref_subregion(const struct subregion *s, struct size_core *sc)
+{
+ assert(S_LIBENT(s));
+
+ size_t cmdsize = cmdsize_fileref_command(S_PATHNAME(s));
+ sc->headersize += cmdsize;
+ sc->count++;
+ sc->memsize += S_SIZE(s);
+}
+
+static void
+size_fileref_region(const struct region *r, struct size_core *sc)
+{
+ assert(0 == r->r_nsubregions);
+ assert(!r->r_inzfodregion);
+
+ size_t cmdsize = cmdsize_fileref_command(r->r_fileref->fr_pathname);
+ sc->headersize += cmdsize;
+ sc->count++;
+ sc->memsize += R_SIZE(r);
+}
+
+static struct proto_fileref_command *
+make_fileref_command(void *data, const char *pathname, const uuid_t uuid,
+ const struct vm_range *vr, const struct file_range *fr,
+ const vm_region_submap_info_data_64_t *info, unsigned purgable)
+{
+ struct proto_fileref_command *fc = data;
+ size_t len;
+
+ fc->cmd = proto_LC_FILEREF;
+ fc->cmdsize = sizeof (*fc);
+ if (0 != (len = strlen(pathname))) {
+ /*
+ * Strings live immediately after the
+ * command, and are included in the cmdsize
+ */
+ fc->filename.offset = sizeof (*fc);
+ void *s = fc + 1;
+ strlcpy(s, pathname, ++len); // NUL-terminated for mmap sanity
+ fc->cmdsize += roundup(len, sizeof (long));
+ assert(cmdsize_fileref_command(pathname) == fc->cmdsize);
+ }
+
+ /*
+ * A file reference allows different kinds of identifiers for
+ * the reference to be reconstructed.
+ */
+ assert(info->external_pager);
+
+ if (!uuid_is_null(uuid)) {
+ uuid_copy(fc->id, uuid);
+ fc->flags = FREF_MAKE_FLAGS(kFREF_ID_UUID);
+ } else {
+ struct stat st;
+ if (-1 != stat(pathname, &st) && 0 != st.st_mtimespec.tv_sec) {
+ /* "little-endian format timespec structure" */
+ struct timespec ts = st.st_mtimespec;
+ ts.tv_nsec = 0; // allow touch(1) to fix things
+ memset(fc->id, 0, sizeof(fc->id));
+ memcpy(fc->id, &ts, sizeof(ts));
+ fc->flags = FREF_MAKE_FLAGS(kFREF_ID_MTIMESPEC_LE);
+ } else
+ fc->flags = FREF_MAKE_FLAGS(kFREF_ID_NONE);
+ }
+
+ fc->vmaddr = V_ADDR(vr);
+ assert(V_SIZE(vr));
+ fc->vmsize = V_SIZE(vr);
+
+ assert(F_OFF(fr) >= 0);
+ fc->fileoff = F_OFF(fr);
+ fc->filesize = F_SIZE(fr);
+
+ assert(info->max_protection & VM_PROT_READ);
+ fc->maxprot = info->max_protection;
+ fc->prot = info->protection;
+
+ fc->share_mode = info->share_mode;
+ assert(purgable <= UINT8_MAX);
+ fc->purgable = (uint8_t)purgable;
+ assert(info->user_tag <= UINT8_MAX);
+ fc->tag = (uint8_t)info->user_tag;
+ fc->extp = info->external_pager;
+ return fc;
+}
+
+/*
+ * It's almost always more efficient to write out a reference to the
+ * data than write out the data itself.
+ */
+static walk_return_t
+write_fileref_subregion(const struct region *r, const struct subregion *s, struct write_segment_data *wsd)
+{
+ assert(S_LIBENT(s));
+ if (OPTIONS_DEBUG(opt, 1) && !issubregiontype(s, SEG_TEXT) && !issubregiontype(s, SEG_LINKEDIT))
+ printf("%s: unusual segment type %s from %s\n", __func__, S_MACHO_TYPE(s), S_FILENAME(s));
+ assert((r->r_info.max_protection & VM_PROT_READ) == VM_PROT_READ);
+ assert((r->r_info.protection & VM_PROT_WRITE) == 0);
+
+ const struct libent *le = S_LIBENT(s);
+ const struct file_range fr = {
+ .off = S_MACHO_FILEOFF(s),
+ .size = S_SIZE(s),
+ };
+ const struct proto_fileref_command *fc = make_fileref_command(wsd->wsd_lc, le->le_pathname, le->le_uuid, S_RANGE(s), &fr, &r->r_info, r->r_purgable);
+
+ commit_load_command(wsd, (const void *)fc);
+ if (OPTIONS_DEBUG(opt, 3)) {
+ hsize_str_t hstr;
+ printr(r, "ref '%s' %s (vm %llx-%llx, file offset %lld for %s)\n", S_FILENAME(s), S_MACHO_TYPE(s), (uint64_t)fc->vmaddr, (uint64_t)fc->vmaddr + fc->vmsize, (int64_t)fc->fileoff, str_hsize(hstr, fc->filesize));
+ }
+ return WALK_CONTINUE;
+}
+
+/*
+ * Note that we may be asked to write reference segments whose protections
+ * are rw- -- this -should- be ok as we don't convert the region to a file
+ * reference unless we know it hasn't been modified.
+ */
+static walk_return_t
+write_fileref_region(const struct region *r, struct write_segment_data *wsd)
+{
+ assert(0 == r->r_nsubregions);
+ assert(r->r_info.user_tag != VM_MEMORY_IOKIT);
+ assert((r->r_info.max_protection & VM_PROT_READ) == VM_PROT_READ);
+ assert(!r->r_inzfodregion);
+
+ const struct libent *le = r->r_fileref->fr_libent;
+ const char *pathname = r->r_fileref->fr_pathname;
+ const struct file_range fr = {
+ .off = r->r_fileref->fr_offset,
+ .size = R_SIZE(r),
+ };
+ const struct proto_fileref_command *fc = make_fileref_command(wsd->wsd_lc, pathname, le ? le->le_uuid : UUID_NULL, R_RANGE(r), &fr, &r->r_info, r->r_purgable);
+
+ commit_load_command(wsd, (const void *)fc);
+ if (OPTIONS_DEBUG(opt, 3)) {
+ hsize_str_t hstr;
+ printr(r, "ref '%s' %s (vm %llx-%llx, file offset %lld for %s)\n", pathname, "(type?)", (uint64_t)fc->vmaddr, (uint64_t)fc->vmaddr + fc->vmsize, (int64_t)fc->fileoff, str_hsize(hstr, fc->filesize));
+ }
+ return WALK_CONTINUE;
+}
+
+const struct regionop fileref_ops = {
+ print_memory_region,
+ write_fileref_region,
+ del_fileref_region,
+};
+
+
+#pragma mark -- ZFOD segments written only to the header --
+
+static void
+size_zfod_region(const struct region *r, struct size_core *sc)
+{
+ assert(0 == r->r_nsubregions);
+ assert(r->r_inzfodregion);
+ sc->headersize += sizeof_segment_command();
+ sc->count++;
+ sc->memsize += R_SIZE(r);
+}
+
+static walk_return_t
+write_zfod_region(const struct region *r, struct write_segment_data *wsd)
+{
+ assert(r->r_info.user_tag != VM_MEMORY_IOKIT);
+ assert((r->r_info.max_protection & VM_PROT_READ) == VM_PROT_READ);
+
+ const struct file_range fr = {
+ .off = wsd->wsd_foffset,
+ .size = 0,
+ };
+ make_segment_command(wsd->wsd_lc, R_RANGE(r), &fr, &r->r_info, 0, VM_PURGABLE_EMPTY);
+ commit_load_command(wsd, wsd->wsd_lc);
+ return WALK_CONTINUE;
+}
+
+const struct regionop zfod_ops = {
+ print_memory_region,
+ write_zfod_region,
+ del_zfod_region,
+};
+
+#pragma mark -- Regions containing data --
+
+static walk_return_t
+pwrite_memory(struct write_segment_data *wsd, const void *addr, size_t size, const struct vm_range *vr)
+{
+ assert(size);
+
+ ssize_t nwritten;
+ const int error = bounded_pwrite(wsd->wsd_fd, addr, size, wsd->wsd_foffset, &wsd->wsd_nocache, &nwritten);
+
+ if (error || OPTIONS_DEBUG(opt, 3)) {
+ hsize_str_t hsz;
+ printvr(vr, "writing %ld bytes at offset %lld -> ", size, wsd->wsd_foffset);
+ if (error)
+ printf("err #%d - %s ", error, strerror(error));
+ else {
+ printf("%s ", str_hsize(hsz, nwritten));
+ if (size != (size_t)nwritten)
+ printf("[%zd - incomplete write!] ", nwritten);
+ else if (size != V_SIZE(vr))
+ printf("(%s in memory) ",
+ str_hsize(hsz, V_SIZE(vr)));
+ }
+ printf("\n");
+ }
+
+ walk_return_t step = WALK_CONTINUE;
+ switch (error) {
+ case 0:
+ if (size != (size_t)nwritten)
+ step = WALK_ERROR;
+ else {
+ wsd->wsd_foffset += nwritten;
+ wsd->wsd_nwritten += nwritten;
+ }
+ break;
+ case EFAULT: // transient mapping failure?
+ break;
+ default: // EROFS, ENOSPC, EFBIG etc. */
+ step = WALK_ERROR;
+ break;
+ }
+ return step;
+}
+
+
+/*
+ * Write a contiguous range of memory into the core file.
+ * Apply compression, and chunk if necessary.
+ */
+static int
+segment_compflags(compression_algorithm ca, unsigned *algnum)
+{
+ switch (ca) {
+ case COMPRESSION_LZ4:
+ *algnum = kCOMP_LZ4;
+ break;
+ case COMPRESSION_ZLIB:
+ *algnum = kCOMP_ZLIB;
+ break;
+ case COMPRESSION_LZMA:
+ *algnum = kCOMP_LZMA;
+ break;
+ case COMPRESSION_LZFSE:
+ *algnum = kCOMP_LZFSE;
+ break;
+ default:
+ err(EX_SOFTWARE, "unsupported compression algorithm %x", ca);
+ }
+ return 0;
+}
+
+static bool
+is_file_mapped_shared(const struct region *r)
+{
+ if (r->r_info.external_pager)
+ switch (r->r_info.share_mode) {
+ case SM_TRUESHARED: // sm=shm
+ case SM_SHARED: // sm=ali
+ case SM_SHARED_ALIASED: // sm=s/a
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+static walk_return_t
+map_memory_range(struct write_segment_data *wsd, const struct region *r, const struct vm_range *vr, struct vm_range *dp)
+{
+ if (r->r_incommregion) {
+ /*
+ * Special case: for commpage access, copy from our own address space.
+ */
+ V_SETADDR(dp, 0);
+ V_SETSIZE(dp, V_SIZE(vr));
+
+ kern_return_t kr = mach_vm_allocate(mach_task_self(), &dp->addr, dp->size, VM_FLAGS_ANYWHERE);
+ if (KERN_SUCCESS != kr || 0 == dp->addr) {
+ err_mach(kr, r, "mach_vm_allocate c %llx-%llx", V_ADDR(vr), V_ENDADDR(vr));
+ print_one_memory_region(r);
+ return WALK_ERROR;
+ }
+ if (OPTIONS_DEBUG(opt, 3))
+ printr(r, "copying from self %llx-%llx\n", V_ADDR(vr), V_ENDADDR(vr));
+ memcpy((void *)dp->addr, (const void *)V_ADDR(vr), V_SIZE(vr));
+ return WALK_CONTINUE;
+ }
+
+ if (!r->r_insharedregion && 0 == (r->r_info.protection & VM_PROT_READ)) {
+ assert(0 != (r->r_info.max_protection & VM_PROT_READ)); // simple_region_optimization()
+
+ /*
+ * Special case: region that doesn't currently have read permission.
+ * (e.g. --x/r-x permissions with tag 64 - JS JIT generated code
+ * from com.apple.WebKit.WebContent)
+ */
+ const mach_vm_offset_t pagesize_host = 1u << pageshift_host;
+ if (OPTIONS_DEBUG(opt, 3))
+ printr(r, "unreadable (%s/%s), remap with read permission\n",
+ str_prot(r->r_info.protection), str_prot(r->r_info.max_protection));
+ V_SETADDR(dp, 0);
+ V_SETSIZE(dp, V_SIZE(vr));
+ vm_prot_t cprot, mprot;
+ kern_return_t kr = mach_vm_remap(mach_task_self(), &dp->addr, V_SIZE(dp), pagesize_host - 1, true, wsd->wsd_task, V_ADDR(vr), true, &cprot, &mprot, VM_INHERIT_NONE);
+ if (KERN_SUCCESS != kr) {
+ err_mach(kr, r, "mach_vm_remap() %llx-%llx", V_ADDR(vr), V_ENDADDR(vr));
+ return WALK_ERROR;
+ }
+ assert(r->r_info.protection == cprot && r->r_info.max_protection == mprot);
+ kr = mach_vm_protect(mach_task_self(), V_ADDR(dp), V_SIZE(dp), false, VM_PROT_READ);
+ if (KERN_SUCCESS != kr) {
+ err_mach(kr, r, "mach_vm_protect() %llx-%llx", V_ADDR(vr), V_ENDADDR(vr));
+ mach_vm_deallocate(mach_task_self(), V_ADDR(dp), V_SIZE(dp));
+ return WALK_ERROR;
+ }
+ return WALK_CONTINUE;
+ }
+
+ /*
+ * Most segments with data are read here
+ */
+ vm_offset_t data32 = 0;
+ mach_msg_type_number_t data32_count;
+ kern_return_t kr = mach_vm_read(wsd->wsd_task, V_ADDR(vr), V_SIZE(vr), &data32, &data32_count);
+ switch (kr) {
+ case KERN_SUCCESS:
+ V_SETADDR(dp, data32);
+ V_SETSIZE(dp, data32_count);
+ break;
+ case KERN_INVALID_ADDRESS:
+ if (!r->r_insharedregion &&
+ (VM_MEMORY_SKYWALK == r->r_info.user_tag || is_file_mapped_shared(r))) {
+ if (OPTIONS_DEBUG(opt, 1)) {
+ /* not necessarily an error: mitigation below */
+ tag_str_t tstr;
+ printr(r, "mach_vm_read() failed (%s) -- substituting zeroed region\n", str_tagr(tstr, r));
+ if (OPTIONS_DEBUG(opt, 2))
+ print_one_memory_region(r);
+ }
+ V_SETSIZE(dp, V_SIZE(vr));
+ kr = mach_vm_allocate(mach_task_self(), &dp->addr, V_SIZE(dp), VM_FLAGS_ANYWHERE);
+ if (KERN_SUCCESS != kr || 0 == V_ADDR(dp))
+ err_mach(kr, r, "mach_vm_allocate() z %llx-%llx", V_ADDR(vr), V_ENDADDR(vr));
+ break;
+ }
+ /*FALLTHROUGH*/
+ default:
+ err_mach(kr, r, "mach_vm_read() %llx-%llx", V_ADDR(vr), V_SIZE(vr));
+ if (OPTIONS_DEBUG(opt, 1))
+ print_one_memory_region(r);
+ break;
+ }
+ if (kr != KERN_SUCCESS) {
+ V_SETADDR(dp, 0);
+ return WALK_ERROR;
+ }
+
+ /*
+ * Sometimes (e.g. searchd) we may not be able to fetch all the pages
+ * from the underlying mapped file, in which case replace those pages
+ * with zfod pages (at least they compress efficiently) rather than
+ * taking a SIGBUS when compressing them.
+ *
+ * XXX Perhaps we should just catch the SIGBUS, and if the faulting address
+ * is in the right range, substitute zfod pages and rerun region compression?
+ * Complex though, because the compression code may be multithreaded.
+ */
+ if (!r->r_insharedregion && is_file_mapped_shared(r)) {
+ const mach_vm_offset_t pagesize_host = 1u << pageshift_host;
+
+ if (r->r_info.pages_resident * pagesize_host == V_SIZE(dp))
+ return WALK_CONTINUE; // all pages resident, so skip ..
+
+ if (OPTIONS_DEBUG(opt, 2))
+ printr(r, "probing %llu pages in mapped-shared file\n", V_SIZE(dp) / pagesize_host);
+
+ kr = KERN_SUCCESS;
+ for (mach_vm_offset_t a = V_ADDR(dp); a < V_ENDADDR(dp); a += pagesize_host) {
+
+ mach_msg_type_number_t pCount = VM_PAGE_INFO_BASIC_COUNT;
+ vm_page_info_basic_data_t pInfo;
+
+ kr = mach_vm_page_info(mach_task_self(), a, VM_PAGE_INFO_BASIC, (vm_page_info_t)&pInfo, &pCount);
+ if (KERN_SUCCESS != kr) {
+ err_mach(kr, NULL, "mach_vm_page_info() at %llx", a);
+ break;
+ }
+ /* If the VM has the page somewhere, assume we can bring it back */
+ if (pInfo.disposition & (VM_PAGE_QUERY_PAGE_PRESENT | VM_PAGE_QUERY_PAGE_REF | VM_PAGE_QUERY_PAGE_DIRTY))
+ continue;
+
+ /* Force the page to be fetched to see if it faults */
+ mach_vm_size_t tsize = pagesize_host;
+ void *tmp = valloc((size_t)tsize);
+ const mach_vm_address_t vtmp = (mach_vm_address_t)tmp;
+
+ switch (kr = mach_vm_read_overwrite(mach_task_self(), a, tsize, vtmp, &tsize)) {
+ case KERN_SUCCESS:
+ break;
+ case KERN_INVALID_ADDRESS: {
+ /* Content can't be found: replace it and the rest of the region with zero-fill pages */
+ if (OPTIONS_DEBUG(opt, 2)) {
+ printr(r, "mach_vm_read_overwrite() failed after %llu pages -- substituting zfod\n", (a - V_ADDR(dp)) / pagesize_host);
+ print_one_memory_region(r);
+ }
+ mach_vm_address_t va = a;
+ kr = mach_vm_allocate(mach_task_self(), &va, V_ENDADDR(dp) - va, VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE);
+ if (KERN_SUCCESS != kr) {
+ err_mach(kr, r, "mach_vm_allocate() %llx", a);
+ } else {
+ assert(a == va);
+ a = V_ENDADDR(dp); // no need to look any further
+ }
+ break;
+ }
+ default:
+ err_mach(kr, r, "mach_vm_overwrite() %llx", a);
+ break;
+ }
+ free(tmp);
+ if (KERN_SUCCESS != kr)
+ break;
+ }
+ if (KERN_SUCCESS != kr) {
+ kr = mach_vm_deallocate(mach_task_self(), V_ADDR(dp), V_SIZE(dp));
+ if (KERN_SUCCESS != kr && OPTIONS_DEBUG(opt, 1))
+ err_mach(kr, r, "mach_vm_deallocate() pre %llx-%llx", V_ADDR(dp), V_ENDADDR(dp));
+ V_SETADDR(dp, 0);
+ return WALK_ERROR;
+ }
+ }
+
+ return WALK_CONTINUE;
+}
+
+static walk_return_t
+write_memory_range(struct write_segment_data *wsd, const struct region *r, mach_vm_offset_t vmaddr, mach_vm_offset_t vmsize)
+{
+ assert(R_ADDR(r) <= vmaddr && R_ENDADDR(r) >= vmaddr + vmsize);
+
+ mach_vm_offset_t resid = vmsize;
+ walk_return_t step = WALK_CONTINUE;
+
+ do {
+ vmsize = resid;
+
+ /*
+ * Since some regions can be inconveniently large,
+ * chop them into multiple chunks as we compress them.
+ * (mach_vm_read has 32-bit limitations too).
+ */
+ vmsize = vmsize > INT32_MAX ? INT32_MAX : vmsize;
+ if (opt->chunksize > 0 && vmsize > opt->chunksize)
+ vmsize = opt->chunksize;
+ assert(vmsize <= INT32_MAX);
+
+ const struct vm_range vr = {
+ .addr = vmaddr,
+ .size = vmsize,
+ };
+ struct vm_range d, *dp = &d;
+
+ step = map_memory_range(wsd, r, &vr, dp);
+ if (WALK_CONTINUE != step)
+ break;
+ assert(0 != V_ADDR(dp) && 0 != V_SIZE(dp));
+ const void *srcaddr = (const void *)V_ADDR(dp);
+
+ mach_vm_behavior_set(mach_task_self(), V_ADDR(dp), V_SIZE(dp), VM_BEHAVIOR_SEQUENTIAL);
+
+ void *dstbuf = NULL;
+ unsigned algorithm = 0;
+ size_t filesize;
+
+ if (opt->extended) {
+ dstbuf = malloc(V_SIZEOF(dp));
+ if (dstbuf) {
+ filesize = compression_encode_buffer(dstbuf, V_SIZEOF(dp), srcaddr, V_SIZEOF(dp), NULL, opt->calgorithm);
+ if (filesize > 0 && filesize < V_SIZEOF(dp)) {
+ srcaddr = dstbuf; /* the data source is now heap, compressed */
+ mach_vm_deallocate(mach_task_self(), V_ADDR(dp), V_SIZE(dp));
+ V_SETADDR(dp, 0);
+ if (segment_compflags(opt->calgorithm, &algorithm) != 0) {
+ free(dstbuf);
+ mach_vm_deallocate(mach_task_self(), V_ADDR(dp), V_SIZE(dp));
+ V_SETADDR(dp, 0);
+ step = WALK_ERROR;
+ break;
+ }
+ } else {
+ free(dstbuf);
+ dstbuf = NULL;
+ filesize = V_SIZEOF(dp);
+ }
+ } else
+ filesize = V_SIZEOF(dp);
+ assert(filesize <= V_SIZEOF(dp));
+ } else
+ filesize = V_SIZEOF(dp);
+
+ assert(filesize);
+
+ const struct file_range fr = {
+ .off = wsd->wsd_foffset,
+ .size = filesize,
+ };
+ make_segment_command(wsd->wsd_lc, &vr, &fr, &r->r_info, algorithm, r->r_purgable);
+ step = pwrite_memory(wsd, srcaddr, filesize, &vr);
+ if (dstbuf)
+ free(dstbuf);
+ if (V_ADDR(dp)) {
+ kern_return_t kr = mach_vm_deallocate(mach_task_self(), V_ADDR(dp), V_SIZE(dp));
+ if (KERN_SUCCESS != kr && OPTIONS_DEBUG(opt, 1))
+ err_mach(kr, r, "mach_vm_deallocate() post %llx-%llx", V_ADDR(dp), V_SIZE(dp));
+ }
+
+ if (WALK_ERROR == step)
+ break;
+ commit_load_command(wsd, wsd->wsd_lc);
+ resid -= vmsize;
+ vmaddr += vmsize;
+ } while (resid);
+
+ return step;
+}
+
+#ifdef RDAR_23744374
+/*
+ * Sigh. This is a workaround.
+ * Find the vmsize as if the VM system manages ranges in host pagesize units
+ * rather than application pagesize units.
+ */
+static mach_vm_size_t
+getvmsize_host(const task_t task, const struct region *r)
+{
+ mach_vm_size_t vmsize_host = R_SIZE(r);
+
+ if (pageshift_host != pageshift_app) {
+ is_actual_size(task, r, &vmsize_host);
+ if (OPTIONS_DEBUG(opt, 1) && R_SIZE(r) != vmsize_host)
+ printr(r, "(region size tweak: was %llx, is %llx)\n", R_SIZE(r), vmsize_host);
+ }
+ return vmsize_host;
+}
+#else
+static __inline mach_vm_size_t
+getvmsize_host(__unused const task_t task, const struct region *r)
+{
+ return R_SIZE(r);
+}
+#endif
+
+static walk_return_t
+write_sparse_region(const struct region *r, struct write_segment_data *wsd)
+{
+ assert(r->r_nsubregions);
+ assert(!r->r_inzfodregion);
+ assert(NULL == r->r_fileref);
+
+ const mach_vm_size_t vmsize_host = getvmsize_host(wsd->wsd_task, r);
+ walk_return_t step = WALK_CONTINUE;
+
+ for (unsigned i = 0; i < r->r_nsubregions; i++) {
+ const struct subregion *s = r->r_subregions[i];
+
+ if (s->s_isuuidref)
+ step = write_fileref_subregion(r, s, wsd);
+ else {
+ /* Write this one out as real data */
+ mach_vm_size_t vmsize = S_SIZE(s);
+ if (R_SIZE(r) != vmsize_host) {
+ if (S_ADDR(s) + vmsize > R_ADDR(r) + vmsize_host) {
+ vmsize = R_ADDR(r) + vmsize_host - S_ADDR(s);
+ if (OPTIONS_DEBUG(opt, 3))
+ printr(r, "(subregion size tweak: was %llx, is %llx)\n",
+ S_SIZE(s), vmsize);
+ }
+ }
+ step = write_memory_range(wsd, r, S_ADDR(s), vmsize);
+ }
+ if (WALK_ERROR == step)
+ break;
+ }
+ return step;
+}
+
+static walk_return_t
+write_vanilla_region(const struct region *r, struct write_segment_data *wsd)
+{
+ assert(0 == r->r_nsubregions);
+ assert(!r->r_inzfodregion);
+ assert(NULL == r->r_fileref);
+
+ const mach_vm_size_t vmsize_host = getvmsize_host(wsd->wsd_task, r);
+ return write_memory_range(wsd, r, R_ADDR(r), vmsize_host);
+}
+
+walk_return_t
+region_write_memory(struct region *r, void *arg)
+{
+ assert(r->r_info.user_tag != VM_MEMORY_IOKIT); // elided in walk_regions()
+ assert((r->r_info.max_protection & VM_PROT_READ) == VM_PROT_READ);
+ return ROP_WRITE(r, arg);
+}
+
+/*
+ * Handles the cases where segments are broken into chunks i.e. when
+ * writing compressed segments.
+ */
+static unsigned long
+count_memory_range(mach_vm_offset_t vmsize)
+{
+ unsigned long count;
+ if (opt->chunksize) {
+ count = (size_t)vmsize / opt->chunksize;
+ if (vmsize != (mach_vm_offset_t)count * opt->chunksize)
+ count++;
+ } else
+ count = 1;
+ return count;
+}
+
+/*
+ * A sparse region is likely a writable data segment described by
+ * native_segment_command_t somewhere in the address space.
+ */
+static void
+size_sparse_subregion(const struct subregion *s, struct size_core *sc)
+{
+ const unsigned long count = count_memory_range(S_SIZE(s));
+ sc->headersize += sizeof_segment_command() * count;
+ sc->count += count;
+ sc->memsize += S_SIZE(s);
+}
+
+static void
+size_sparse_region(const struct region *r, struct size_core *sc_sparse, struct size_core *sc_fileref)
+{
+ assert(0 != r->r_nsubregions);
+
+ unsigned long entry_total = sc_sparse->count + sc_fileref->count;
+ for (unsigned i = 0; i < r->r_nsubregions; i++) {
+ const struct subregion *s = r->r_subregions[i];
+ if (s->s_isuuidref)
+ size_fileref_subregion(s, sc_fileref);
+ else
+ size_sparse_subregion(s, sc_sparse);
+ }
+ if (OPTIONS_DEBUG(opt, 3)) {
+ /* caused by compression breaking a large region into chunks */
+ entry_total = (sc_fileref->count + sc_sparse->count) - entry_total;
+ if (entry_total > r->r_nsubregions)
+ printr(r, "range contains %u subregions requires %lu segment commands\n",
+ r->r_nsubregions, entry_total);
+ }
+}
+
+const struct regionop sparse_ops = {
+ print_memory_region,
+ write_sparse_region,
+ del_sparse_region,
+};
+
+static void
+size_vanilla_region(const struct region *r, struct size_core *sc)
+{
+ assert(0 == r->r_nsubregions);
+
+ const unsigned long count = count_memory_range(R_SIZE(r));
+ sc->headersize += sizeof_segment_command() * count;
+ sc->count += count;
+ sc->memsize += R_SIZE(r);
+
+ if (OPTIONS_DEBUG(opt, 3) && count != 1)
+ printr(r, "range with 1 region, but requires %lu segment commands\n", count);
+}
+
+const struct regionop vanilla_ops = {
+ print_memory_region,
+ write_vanilla_region,
+ del_vanilla_region,
+};
+
+walk_return_t
+region_size_memory(struct region *r, void *arg)
+{
+ struct size_segment_data *ssd = arg;
+
+ if (&zfod_ops == r->r_op)
+ size_zfod_region(r, &ssd->ssd_zfod);
+ else if (&fileref_ops == r->r_op)
+ size_fileref_region(r, &ssd->ssd_fileref);
+ else if (&sparse_ops == r->r_op)
+ size_sparse_region(r, &ssd->ssd_sparse, &ssd->ssd_fileref);
+ else if (&vanilla_ops == r->r_op)
+ size_vanilla_region(r, &ssd->ssd_vanilla);
+ else
+ errx(EX_SOFTWARE, "%s: bad op", __func__);
+
+ return WALK_CONTINUE;
+}
diff --git a/system_cmds/gcore.tproj/corefile.h b/system_cmds/gcore.tproj/corefile.h
new file mode 100644
index 0000000..2bdc43e
--- /dev/null
+++ b/system_cmds/gcore.tproj/corefile.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "loader_additions.h"
+#include "dyld_shared_cache.h"
+#include "region.h"
+
+#include <mach-o/loader.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <sys/types.h>
+
+#ifndef _COREFILE_H
+#define _COREFILE_H
+
+#if defined(__LP64__)
+typedef struct mach_header_64 native_mach_header_t;
+typedef struct segment_command_64 native_segment_command_t;
+#define NATIVE_MH_MAGIC MH_MAGIC_64
+#define NATIVE_LC_SEGMENT LC_SEGMENT_64
+#else
+typedef struct mach_header native_mach_header_t;
+typedef struct segment_command native_segment_command_t;
+#define NATIVE_MH_MAGIC MH_MAGIC
+#define NATIVE_LC_SEGMENT LC_SEGMENT
+#endif
+
+static __inline const struct load_command *next_lc(const struct load_command *lc) {
+ if (lc->cmdsize && (lc->cmdsize & 3) == 0)
+ return (const void *)((caddr_t)lc + lc->cmdsize);
+ return NULL;
+}
+
+extern native_segment_command_t *make_native_segment_command(void *, const struct vm_range *, const struct file_range *, vm_prot_t, vm_prot_t);
+
+extern native_mach_header_t *make_corefile_mach_header(void *);
+extern struct proto_coreinfo_command *make_coreinfo_command(native_mach_header_t *, void *, const uuid_t, uint64_t, uint64_t);
+
+static __inline void mach_header_inc_ncmds(native_mach_header_t *mh, uint32_t inc) {
+ mh->ncmds += inc;
+}
+
+static __inline void mach_header_inc_sizeofcmds(native_mach_header_t *mh, uint32_t inc) {
+ mh->sizeofcmds += inc;
+}
+
+struct size_core {
+ unsigned long count; /* number-of-objects */
+ size_t headersize; /* size in mach header */
+ mach_vm_offset_t memsize; /* size in memory */
+};
+
+struct size_segment_data {
+ struct size_core ssd_vanilla; /* full segments with data */
+ struct size_core ssd_sparse; /* sparse segments with data */
+ struct size_core ssd_fileref; /* full & sparse segments with uuid file references */
+ struct size_core ssd_zfod; /* full segments with zfod pages */
+};
+
+struct write_segment_data {
+ task_t wsd_task;
+ native_mach_header_t *wsd_mh;
+ void *wsd_lc;
+ int wsd_fd;
+ bool wsd_nocache;
+ off_t wsd_foffset;
+ off_t wsd_nwritten;
+};
+
+#endif /* _COREFILE_H */
diff --git a/system_cmds/gcore.tproj/dyld.c b/system_cmds/gcore.tproj/dyld.c
new file mode 100644
index 0000000..92aeac1
--- /dev/null
+++ b/system_cmds/gcore.tproj/dyld.c
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "dyld.h"
+#include "utils.h"
+#include "corefile.h"
+#include "vm.h"
+
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/dyld_process_info.h>
+
+#include <mach/mach.h>
+#include <mach/task.h>
+#include <mach/mach_vm.h>
+#include <mach/shared_region.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <libgen.h>
+#include <sys/stat.h>
+
+/*
+ * WARNING WARNING WARNING
+ *
+ * Do not trust any of the data from the target task.
+ *
+ * A broken program may have damaged it, or a malicious
+ * program may have deliberately constructed something to
+ * cause us harm.
+ */
+
+static const char warn_dyld_info[] = "dyld information is incomplete or damaged";
+
+dyld_process_info
+get_task_dyld_info(const task_t task)
+{
+ kern_return_t kret;
+ dyld_process_info dpi = _dyld_process_info_create(task, 0, &kret);
+ if (NULL == dpi) {
+ err_mach(kret, NULL, "_dlyd_process_info_create");
+ } else {
+ dyld_process_state_info stateInfo;
+
+ _dyld_process_info_get_state(dpi, &stateInfo);
+ switch (stateInfo.dyldState) {
+ case dyld_process_state_not_started:
+ warnx("%s: dyld state %d", warn_dyld_info, stateInfo.dyldState);
+ _dyld_process_info_release(dpi);
+ dpi = NULL;
+ break;
+ default:
+ break;
+ }
+ }
+ return dpi;
+}
+
+/*
+ * Get the shared cache UUID iff it's in use and is the system one
+ */
+bool
+get_sc_uuid(dyld_process_info dpi, uuid_t uu)
+{
+ dyld_process_cache_info cacheInfo;
+
+ _dyld_process_info_get_cache(dpi, &cacheInfo);
+ if (!cacheInfo.noCache && !cacheInfo.privateCache) {
+ uuid_copy(uu, cacheInfo.cacheUUID);
+ return true;
+ }
+ return false;
+}
+
+void
+free_task_dyld_info(dyld_process_info dpi)
+{
+ _dyld_process_info_release(dpi);
+}
+
+/*
+ * This routine collects both the Mach-O header and the commands
+ * "below" it, assuming they're in contiguous memory.
+ */
+static native_mach_header_t *
+copy_dyld_image_mh(task_t task, mach_vm_address_t targetmh, const char *path)
+{
+ vm_offset_t mhaddr = 0;
+ mach_msg_type_number_t mhlen = sizeof (native_mach_header_t);
+
+ for (int attempts = 0; attempts < 2; attempts++) {
+
+ const kern_return_t ret = mach_vm_read(task, targetmh, mhlen, &mhaddr, &mhlen);
+ if (KERN_SUCCESS != ret) {
+ err_mach(ret, NULL, "mach_vm_read() at 0x%llx for image %s\n", targetmh, path);
+ mhaddr = 0;
+ break;
+ }
+ const native_mach_header_t *mh = (void *)mhaddr;
+ if (mhlen < mh->sizeofcmds + sizeof (*mh)) {
+ const mach_msg_type_number_t newmhlen = sizeof (*mh) + mh->sizeofcmds;
+ mach_vm_deallocate(mach_task_self(), mhaddr, mhlen);
+ mhlen = newmhlen;
+ } else
+ break;
+ }
+
+ native_mach_header_t *result = NULL;
+
+ if (mhaddr) {
+ if (NULL != (result = malloc(mhlen)))
+ memcpy(result, (void *)mhaddr, mhlen);
+ mach_vm_deallocate(mach_task_self(), mhaddr, mhlen);
+ }
+ return result;
+}
+
+/*
+ * This table (list) describes libraries and the executable in the address space
+ */
+struct liblist {
+ STAILQ_ENTRY(liblist) ll_linkage;
+ unsigned long ll_namehash;
+ struct libent ll_entry;
+};
+static STAILQ_HEAD(, liblist) libhead = STAILQ_HEAD_INITIALIZER(libhead);
+
+static const struct libent *
+libent_lookup_bypathname_withhash(const char *nm, const unsigned long hash)
+{
+ struct liblist *ll;
+ STAILQ_FOREACH(ll, &libhead, ll_linkage) {
+ if (hash != ll->ll_namehash)
+ continue;
+ struct libent *le = &ll->ll_entry;
+ if (strcmp(nm, le->le_pathname) == 0)
+ return le;
+ }
+ return NULL;
+}
+
+const struct libent *
+libent_lookup_byuuid(const uuid_t uuid)
+{
+ struct liblist *ll;
+ STAILQ_FOREACH(ll, &libhead, ll_linkage) {
+ struct libent *le = &ll->ll_entry;
+ if (uuid_compare(uuid, le->le_uuid) == 0)
+ return le;
+ }
+ return NULL;
+}
+
+const struct libent *
+libent_lookup_first_bytype(uint32_t mhtype)
+{
+ struct liblist *ll;
+ STAILQ_FOREACH(ll, &libhead, ll_linkage) {
+ struct libent *le = &ll->ll_entry;
+ if (mhtype == le->le_mh->filetype)
+ return le;
+ }
+ return NULL;
+}
+
+const struct libent *
+libent_insert(const char *rawnm, const uuid_t uuid, uint64_t mhaddr, const native_mach_header_t *mh, const struct vm_range *vr, mach_vm_offset_t objoff)
+{
+ const struct libent *le = libent_lookup_byuuid(uuid);
+ if (NULL != le)
+ return le; // disallow multiple names for the same uuid
+
+ char *nm = realpath(rawnm, NULL);
+ if (NULL == nm)
+ nm = strdup(rawnm);
+ const unsigned long nmhash = simple_namehash(nm);
+ le = libent_lookup_bypathname_withhash(nm, nmhash);
+ if (NULL != le) {
+ free(nm);
+ return le;
+ }
+
+ if (OPTIONS_DEBUG(opt, 3)) {
+ uuid_string_t uustr;
+ uuid_unparse_lower(uuid, uustr);
+ printf("[adding <'%s', %s, 0x%llx, %p", nm, uustr, mhaddr, mh);
+ if (vr)
+ printf(" (%llx-%llx)", V_ADDR(vr), V_ENDADDR(vr));
+ printf(">]\n");
+ }
+ struct liblist *ll = malloc(sizeof (*ll));
+ ll->ll_namehash = nmhash;
+ ll->ll_entry.le_pathname = nm;
+ ll->ll_entry.le_filename = strrchr(ll->ll_entry.le_pathname, '/');
+ if (NULL == ll->ll_entry.le_filename)
+ ll->ll_entry.le_filename = ll->ll_entry.le_pathname;
+ else
+ ll->ll_entry.le_filename++;
+ uuid_copy(ll->ll_entry.le_uuid, uuid);
+ ll->ll_entry.le_mhaddr = mhaddr;
+ ll->ll_entry.le_mh = mh;
+ if (vr)
+ ll->ll_entry.le_vr = *vr;
+ else {
+ V_SETADDR(&ll->ll_entry.le_vr, MACH_VM_MAX_ADDRESS);
+ V_SETSIZE(&ll->ll_entry.le_vr, 0);
+ }
+ ll->ll_entry.le_objoff = objoff;
+ STAILQ_INSERT_HEAD(&libhead, ll, ll_linkage);
+
+ return &ll->ll_entry;
+}
+
+bool
+libent_build_nametable(task_t task, dyld_process_info dpi)
+{
+ __block bool valid = true;
+
+ _dyld_process_info_for_each_image(dpi, ^(uint64_t mhaddr, const uuid_t uuid, const char *path) {
+ if (valid) {
+ native_mach_header_t *mh = copy_dyld_image_mh(task, mhaddr, path);
+ if (mh) {
+ /*
+ * Validate the rest of the mach information in the header before attempting optimizations
+ */
+ const size_t mhlen = sizeof (*mh) + mh->sizeofcmds;
+ const struct load_command *lc = (const void *)(mh + 1);
+ struct vm_range vr = {
+ .addr = MACH_VM_MAX_ADDRESS,
+ .size = 0
+ };
+ mach_vm_offset_t objoff = MACH_VM_MAX_ADDRESS;
+
+ for (unsigned n = 0; n < mh->ncmds; n++) {
+ if (((uintptr_t)lc & 0x3) != 0 ||
+ (uintptr_t)lc < (uintptr_t)mh || (uintptr_t)lc > (uintptr_t)mh + mhlen) {
+ warnx("%s, %d", warn_dyld_info, __LINE__);
+ valid = false;
+ break;
+ }
+ switch (lc->cmd) {
+ case NATIVE_LC_SEGMENT: {
+ const native_segment_command_t *sc = (const void *)lc;
+
+ char scsegname[17];
+ strlcpy(scsegname, sc->segname, sizeof (scsegname));
+
+ if (0 == sc->vmaddr &&
+ strcmp(scsegname, SEG_PAGEZERO) == 0)
+ break;
+
+ /*
+ * -Depends- on finding a __TEXT segment first
+ * which implicitly maps the mach header too
+ */
+
+ if (MACH_VM_MAX_ADDRESS == objoff) {
+ if (strcmp(scsegname, SEG_TEXT) == 0) {
+ objoff = mhaddr - sc->vmaddr;
+ V_SETADDR(&vr, mhaddr);
+ V_SETSIZE(&vr, sc->vmsize);
+ } else {
+ printf("%s: expected %s segment, found %s\n", path, SEG_TEXT, scsegname);
+ valid = false;
+ break;
+ }
+ }
+
+ mach_vm_offset_t lo = sc->vmaddr + objoff;
+ mach_vm_offset_t hi = lo + sc->vmsize;
+
+ if (V_SIZE(&vr)) {
+ if (lo < V_ADDR(&vr)) {
+ mach_vm_offset_t newsize = V_SIZE(&vr) + (V_ADDR(&vr) - lo);
+ V_SETSIZE(&vr, newsize);
+ V_SETADDR(&vr, lo);
+ }
+ if (hi > V_ENDADDR(&vr)) {
+ V_SETSIZE(&vr, (hi - V_ADDR(&vr)));
+ }
+ } else {
+ V_SETADDR(&vr, lo);
+ V_SETSIZE(&vr, hi - lo);
+ }
+ assert(lo >= V_ADDR(&vr) && hi <= V_ENDADDR(&vr));
+ } break;
+#if defined(RDAR_28040018)
+ case LC_ID_DYLINKER:
+ if (MH_DYLINKER == mh->filetype) {
+ /* workaround: the API doesn't always return the right name */
+ const struct dylinker_command *dc = (const void *)lc;
+ path = dc->name.offset + (const char *)dc;
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+ if (NULL == (lc = next_lc(lc)))
+ break;
+ }
+ if (valid)
+ (void) libent_insert(path, uuid, mhaddr, mh, &vr, objoff);
+ }
+ }
+ });
+ if (OPTIONS_DEBUG(opt, 3))
+ printf("nametable %sconstructed\n", valid ? "" : "NOT ");
+ return valid;
+}
diff --git a/system_cmds/gcore.tproj/dyld.h b/system_cmds/gcore.tproj/dyld.h
new file mode 100644
index 0000000..02ded2a
--- /dev/null
+++ b/system_cmds/gcore.tproj/dyld.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "corefile.h"
+#include "utils.h"
+
+#include <mach-o/dyld_images.h>
+#include <mach-o/dyld_process_info.h>
+#include <uuid/uuid.h>
+
+#ifndef _DYLD_H
+#define _DYLD_H
+
+struct libent {
+ const char *le_filename; // (points into le_pathname!)
+ char *le_pathname;
+ uuid_t le_uuid;
+ uint64_t le_mhaddr; // address in target process
+ const native_mach_header_t *le_mh; // copy mapped into this address space
+ struct vm_range le_vr; // vmaddr, vmsize bounds in target process
+ mach_vm_offset_t le_objoff; // offset from le_mhaddr to first __TEXT seg
+};
+
+extern const struct libent *libent_lookup_byuuid(const uuid_t);
+extern const struct libent *libent_lookup_first_bytype(uint32_t);
+extern const struct libent *libent_insert(const char *, const uuid_t, uint64_t, const native_mach_header_t *, const struct vm_range *, mach_vm_offset_t);
+extern bool libent_build_nametable(task_t, dyld_process_info);
+
+extern dyld_process_info get_task_dyld_info(task_t);
+extern bool get_sc_uuid(dyld_process_info, uuid_t);
+extern void free_task_dyld_info(dyld_process_info);
+
+#endif /* _DYLD_H */
diff --git a/system_cmds/gcore.tproj/dyld_shared_cache.c b/system_cmds/gcore.tproj/dyld_shared_cache.c
new file mode 100644
index 0000000..0e21163
--- /dev/null
+++ b/system_cmds/gcore.tproj/dyld_shared_cache.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "dyld_shared_cache.h"
+#include "utils.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fts.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <TargetConditionals.h>
+
+static const size_t dyld_cache_header_size = sizeof (struct copied_dyld_cache_header);
+
+/*
+ * The shared cache must both contain the magic ID and
+ * match the uuid we discovered via dyld's information.
+ * Assumes that the dyld_cache_header grows in a binary compatible fashion.
+ */
+bool
+get_uuid_from_shared_cache_mapping(const void *addr, size_t size, uuid_t out)
+{
+ const struct copied_dyld_cache_header *ch = addr;
+ if (size < sizeof (*ch))
+ return false;
+ static const char prefix[] = "dyld_v";
+ if (strncmp(ch->magic, prefix, strlen(prefix)) != 0)
+ return false;
+ uuid_copy(out, ch->uuid);
+ return true;
+}
+
+/*
+ * Look in the known places to see if we can find this one ..
+ */
+char *
+shared_cache_filename(const uuid_t uu)
+{
+ assert(!uuid_is_null(uu));
+ static char *sc_argv[] = {
+#if TARGET_OS_OSX
+ "/System/Library/dyld",
+#elif TARGET_OS_IPHONE
+ "/System/Library/Caches/com.apple.dyld",
+#else
+#error undefined
+#endif
+ NULL
+ };
+ char *nm = NULL;
+ FTS *fts = fts_open(sc_argv, FTS_NOCHDIR | FTS_LOGICAL | FTS_XDEV, NULL);
+ if (NULL != fts) {
+ FTSENT *fe;
+ while (NULL != (fe = fts_read(fts))) {
+ if ((fe->fts_info & FTS_F) == 0 ||
+ (fe->fts_info & FTS_ERR) != 0)
+ continue;
+
+ static const char prefix[] = "dyld_shared_cache_";
+ if (strncmp(fe->fts_name, prefix, strlen(prefix)) != 0)
+ continue;
+
+ if (fe->fts_statp->st_size < (off_t)dyld_cache_header_size)
+ continue;
+
+ int d = open(fe->fts_accpath, O_RDONLY);
+ if (-1 == d) {
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("%s: cannot open - %s\n", fe->fts_accpath, strerror(errno));
+ continue;
+ }
+ void *addr = mmap(NULL, dyld_cache_header_size, PROT_READ, MAP_PRIVATE, d, 0);
+ close(d);
+ if ((void *)-1 == addr) {
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("%s: cannot mmap - %s\n", fe->fts_accpath, strerror(errno));
+ continue;
+ }
+ uuid_t scuuid;
+ uuid_clear(scuuid);
+ if (get_uuid_from_shared_cache_mapping(addr, dyld_cache_header_size, scuuid)) {
+ if (uuid_compare(uu, scuuid) == 0)
+ nm = strdup(fe->fts_accpath);
+ else if (OPTIONS_DEBUG(opt, 3)) {
+ uuid_string_t scstr;
+ uuid_unparse_lower(scuuid, scstr);
+ printf("%s: shared cache mismatch (%s)\n", fe->fts_accpath, scstr);
+ }
+ }
+ munmap(addr, dyld_cache_header_size);
+ if (NULL != nm)
+ break;
+ }
+ }
+ if (fts)
+ fts_close(fts);
+ return nm;
+}
diff --git a/system_cmds/gcore.tproj/dyld_shared_cache.h b/system_cmds/gcore.tproj/dyld_shared_cache.h
new file mode 100644
index 0000000..1fe0fac
--- /dev/null
+++ b/system_cmds/gcore.tproj/dyld_shared_cache.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ */
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <uuid/uuid.h>
+#include <sys/types.h>
+
+#ifndef _DYLD_SHARED_CACHE_H
+#define _DYLD_SHARED_CACHE_H
+
+/*
+ * Guilty knowledge of dyld shared cache internals, used to verify shared cache
+ */
+struct copied_dyld_cache_header {
+ char magic[16]; // e.g. "dyld_v0 i386"
+ uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info
+ uint32_t mappingCount; // number of dyld_cache_mapping_info entries
+ uint32_t imagesOffset; // file offset to first dyld_cache_image_info
+ uint32_t imagesCount; // number of dyld_cache_image_info entries
+ uint64_t dyldBaseAddress; // base address of dyld when cache was built
+ uint64_t codeSignatureOffset; // file offset of code signature blob
+ uint64_t codeSignatureSize; // size of code signature blob (zero means to end of file)
+ uint64_t slideInfoOffset; // file offset of kernel slid info
+ uint64_t slideInfoSize; // size of kernel slid info
+ uint64_t localSymbolsOffset; // file offset of where local symbols are stored
+ uint64_t localSymbolsSize; // size of local symbols information
+ uint8_t uuid[16]; // unique value for each shared cache file
+ uint64_t cacheType; // 1 for development, 0 for optimized
+};
+
+extern bool get_uuid_from_shared_cache_mapping(const void *, size_t, uuid_t);
+extern char *shared_cache_filename(const uuid_t);
+
+#endif /* _DYLD_SHARED_CACHE_H */
diff --git a/system_cmds/gcore.tproj/gcore-entitlements.plist b/system_cmds/gcore.tproj/gcore-entitlements.plist
new file mode 100644
index 0000000..39c14ef
--- /dev/null
+++ b/system_cmds/gcore.tproj/gcore-entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.cs.debugger.root</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/gcore.tproj/gcore-internal.1 b/system_cmds/gcore.tproj/gcore-internal.1
new file mode 100644
index 0000000..923f3e9
--- /dev/null
+++ b/system_cmds/gcore.tproj/gcore-internal.1
@@ -0,0 +1,201 @@
+.Dd 9/29/16
+.Dt gcore-internal 1
+.Os Darwin
+.Sh NAME
+.Nm gcore
+.Nd get core images of running processes and corpses
+.Sh SYNOPSIS
+.Nm
+.Op Fl x
+.Op Fl F
+.Op Fl C
+.Op Fl Z Ar compopts
+.Op Fl t Ar threshold
+.Op Fl d
+.Ar args ...
+.Nm
+.Sy conv
+.Op Fl L Ar searchpath
+.Op Fl z
+.Op Fl s
+.Op Fl v
+.Op Fl d
+.Ar incore outcore
+.Nm
+.Sy map
+.Ar corefile
+.Nm
+.Sy fref
+.Ar corefile
+.Sh DESCRIPTION
+For an introduction to this command and its options, see
+.Xr gcore 1 .
+This page describes various experimental capabilities
+of the
+.Nm
+command intended, for the moment, for internal use only.
+.Pp
+The following set of additional flags are available:
+.Bl -tag -width Fl
+.It Fl x
+Create extended (compact) core files. With this flag,
+.Nm
+elides empty and unmapped regions from the dump, and uses
+metadata from the VM system and
+.Xr dyld 1
+to minimize the size of the dump, writing compressed versions of
+the active regions of the address space into the dump file.
+.Nm
+also records file references to the various files mapped into the
+address space, potentially including the shared cache, to
+avoid duplicating content already present on the filesystem.
+Taken together, these techniques can lead to very significant
+space savings for the core file, particularly for smaller programs.
+.It Fl F
+Normally when
+.Fl x
+is specified,
+.Nm
+makes conservative assumptions about which files should be
+incorporated into the dump as file references so that the
+full core file can be recreated later. This flag attempts to make
+.Em every
+mapped file into a file reference. While this can occasionally
+be useful for applications that map many files into their address space,
+it may be
+.Em extremely
+difficult to recreate the process image as a result.
+Use cautiously!
+.El
+.Pp
+The remaining options are more relevant to the
+.Nm
+maintainers:
+.Bl -tag -width Fl
+.It Fl C
+Forcibly generate a corpse for the process, even if the process is suspended.
+.It Fl Z Ar compopts
+Specify compression options e.g. algorithm and chunksize.
+.It Fl t Ar threshold
+Set the threshold at which I/O caching is disabled to
+.Ar threshold
+KiBytes.
+.It Fl d
+Enable debugging of the
+.Nm
+command.
+.El
+.Pp
+If the
+.Ar pid
+value is specified as 0,
+.Nm
+assumes it has been passed a corpse port by its parent;
+if so it will generate a core dump for that corpse. The
+.Fl c
+flag may not be used in this case, as the process context may no longer exist.
+.Pp
+The
+.Nm
+command supports several sub-commands that can be
+used with extended core files created using the
+.Fl x
+flag. These are:
+.Bl -tag -width frefs
+.\" -compact -offset indent
+.Pp
+.It Sy conv
+Copy and convert a core file to the "pre-coreinfo" format
+compatible with
+.Xr lldb(1) .
+This operation reads the input core file dereferencing any file
+references it contains by copying the content
+and decompressing any compressed data into the output core file.
+This conversion usually makes the core file substantially larger.
+.Pp
+By default, files to be dereferenced must be accessible on the
+local filesystem by the same relative paths as they were originally recorded
+when the dump was taken.
+Files that are Mach-O objects containing UUIDs are required to match
+the UUIDs recorded at the time the core dump was taken.
+Files are otherwise only checked for matching modification times, and
+thus can easily be "forged" using
+.Xr touch 1 .
+.Pp
+Several flags can be used with the conversion:
+.Pp
+.Bl -tag -width Fl
+.It Fl L Ar searchpath
+When processing file references,
+look for the pathnames in the directories specified in
+.Ar searchpath .
+These should be specified as a colon-separated
+list of base directories which will be prepended to each pathname in turn
+for each file reference.
+.It Fl z
+During conversion, if any mapped file
+identified by modification time
+cannot be located, substitute zeroed memory.
+.It Fl s
+When processing file references,
+try looking for the pathname through
+.Xr dsymForUUID 1
+before searching locally.
+.It Fl v
+Report progress on the conversion as it proceeds.
+.It Fl d
+Enable debugging of the
+.Sy conv
+subcommand.
+.El
+.It Sy map
+Print a representation of the address space contained in the core file.
+.Pp
+.It Sy frefs
+Print a list of files corresponding to the file references
+in the core file.
+Can be used to capture the set of files needed to bind the file references
+into the core file at a later time.
+.El
+.Sh BUGS
+.Pp
+When using the
+.Fl x
+flag,
+.Nm
+will likely incorporate a reference to the shared cache into
+.Ar corefile
+including the UUID of that cache.
+On some platforms, the cache is created when the release is built
+and since it resides on a read-only root filesystem it should
+generally be easy to retrieve.
+However on the desktop, the lifecycle of this cache is managed locally
+e.g. with
+.Xr update_dyld_shared_cache 1 .
+When this cache is recreated it is given a new UUID, the directory
+entry for the old cache is removed, and the same filename
+is used for the new cache.
+Thus when the last named copy of the shared cache is removed from the
+filesystem, extended core files that contain references to that cache
+can no longer be converted.
+.Pp
+When using the
+.Fl x
+flag,
+.Nm
+may be unable to locate the currently mapped shared cache in the filesystem.
+In this case
+.Nm
+does not generate any file references to the content of the
+shared cache; it just copies as much of the content
+as is needed from the memory image into the core file.
+This may lead to substantially larger core files than expected.
+.Pp
+It would be nice if
+.Xr lldb 1
+could examine extended core files directly i.e. without the conversion step.
+.Pp
+.Sh SEE ALSO
+.Xr dyld 1 ,
+.Xr update_dyld_shared_cache 1 ,
+.Xr dsymForUUID 1
diff --git a/system_cmds/gcore.tproj/gcore.1 b/system_cmds/gcore.tproj/gcore.1
new file mode 100644
index 0000000..48b360d
--- /dev/null
+++ b/system_cmds/gcore.tproj/gcore.1
@@ -0,0 +1,105 @@
+.Dd 2/10/16
+.Dt gcore 1
+.Os Darwin
+.Sh NAME
+.Nm gcore
+.Nd get core images of running processes
+.Sh SYNOPSIS
+.Nm
+.Op Fl s
+.Op Fl v
+.Op Fl b Ar size
+.Op Fl o Ar path | Fl c Ar pathformat
+.Ar pid
+.Sh DESCRIPTION
+The
+.Nm gcore
+program creates a core file image of the process specified by
+.Ar pid .
+The resulting core file can be used with a debugger, e.g.
+.Xr lldb(1) ,
+to examine the state of the process.
+.Pp
+The following options are available:
+.Bl -tag -width Fl
+.It Fl s
+Suspend the process while the core file is captured.
+.It Fl v
+Report progress on the dump as it proceeds.
+.It Fl b Ar size
+Limit the size of the core file to
+.Ar size
+MiBytes.
+.El
+.Pp
+The following options control the name of the core file:
+.Bl -tag -width flag
+.It Fl o Ar path
+Write the core file to
+.Ar path .
+.It Fl c Ar pathformat
+Write the core file to
+.Ar pathformat .
+The
+.Ar pathformat
+string is treated as a pathname that may contain various special
+characters which cause the interpolation of strings representing
+specific attributes of the process into the name.
+.Pp
+Each special character is introduced by the
+.Cm %
+character. The format characters and their meanings are:
+.Bl -tag -width Fl
+.It Cm N
+The name of the program being dumped, as reported by
+.Xr ps 1 .
+.It Cm U
+The uid of the process being dumped, converted to a string.
+.It Cm P
+The pid of the process being dumped, converted to a string.
+.It Cm T
+The time when the core file was taken, converted to ISO 8601 format.
+.It Cm %
+Output a percent character.
+.El
+.El
+.Pp
+The default file name used by
+.Nm gcore
+is
+.Ar %N-%P-%T .
+By default, the core file will be written to a directory whose
+name is determined from the
+.Ar kern.corefile
+MIB. This can be printed or modified using
+.Xr sysctl 8 .
+.Pp
+The directory where the core file is to be written must be
+accessible to the owner of the target process.
+.Pp
+.Nm gcore
+will not overwrite an existing file,
+nor will it create missing directories in the path.
+.Sh EXIT_STATUS
+.Ex -std
+.Pp
+.Sh FILES
+.Bl -tag -width "/cores/%N-%P-%T plus" -compact
+.It Pa /cores/%N-%P-%T
+default pathname for the corefile.
+.El
+.Sh BUGS
+With the
+.Fl b
+flag,
+.Nm gcore
+writes out as much data as it can up to the specified limit,
+even if that results in an incomplete core image.
+Such a partial core dump may confuse subsequent
+programs that attempt to parse the contents of such files.
+.Sh SEE ALSO
+.Xr lldb 1 ,
+.Xr core 5 ,
+.Xr Mach-O 5 ,
+.Xr sysctl 8 ,
+.Xr sudo 8 .
diff --git a/system_cmds/gcore.tproj/loader_additions.h b/system_cmds/gcore.tproj/loader_additions.h
new file mode 100644
index 0000000..16cf5b5
--- /dev/null
+++ b/system_cmds/gcore.tproj/loader_additions.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ */
+
+#include <mach-o/loader.h>
+
+#ifndef _LOADER_ADDITIONS_H
+#define _LOADER_ADDITIONS_H
+
+/*
+ * Something like this should end up in <mach-o/loader.h>
+ */
+
+#define proto_LC_COREINFO 0x140 /* unofficial value!! */
+
+#define proto_CORETYPE_KERNEL 1
+#define proto_CORETYPE_USER 2
+#define proto_CORETYPE_IBOOT 3
+
+struct proto_coreinfo_command {
+ uint32_t cmd; /* LC_COREINFO */
+ uint32_t cmdsize; /* total size of this command */
+ uint32_t version; /* currently 1 */
+ uint16_t type; /* CORETYPE_KERNEL, CORETYPE_USER etc. */
+ uint16_t pageshift; /* log2 host pagesize */
+ /* content & interpretation depends on 'type' field */
+ uint64_t address; /* load address of "main binary" */
+ uint8_t uuid[16]; /* uuid of "main binary" */
+ uint64_t dyninfo; /* dynamic modules info */
+};
+
+#define proto_LC_FILEREF 0x141 /* unofficial value! */
+
+#define FREF_ID_SHIFT 0
+#define FREF_ID_MASK 0x7 /* up to 8 flavors */
+
+typedef enum {
+ kFREF_ID_NONE = 0, /* file has no available verifying ID */
+ kFREF_ID_UUID = 1, /* file has an associated UUID */
+ kFREF_ID_MTIMESPEC_LE = 2, /* file has a specific mtime */
+ /* one day: file has a computed hash? */
+} fref_type_t;
+
+#define FREF_ID_TYPE(f) ((fref_type_t)(((f) >> FREF_ID_SHIFT) & FREF_ID_MASK))
+#define FREF_MAKE_FLAGS(t) (((t) & FREF_ID_MASK) << FREF_ID_SHIFT)
+
+struct proto_fileref_command {
+ uint32_t cmd; /* LC_FILEREF */
+ uint32_t cmdsize;
+ union lc_str filename; /* filename these bits come from */
+ uint8_t id[16]; /* uuid, size or hash etc. */
+ uint64_t vmaddr; /* memory address of this segment */
+ uint64_t vmsize; /* memory size of this segment */
+ uint64_t fileoff; /* file offset of this segment */
+ uint64_t filesize; /* amount to map from the file */
+ vm_prot_t maxprot; /* maximum VM protection */
+ vm_prot_t prot; /* current VM protection */
+ uint32_t flags;
+ uint8_t share_mode; /* SM_COW etc. */
+ uint8_t purgable; /* VM_PURGABLE_NONVOLATILE etc. */
+ uint8_t tag; /* VM_MEMORY_MALLOC etc. */
+ uint8_t extp; /* external pager */
+};
+
+#define proto_LC_COREDATA 0x142 /* unofficial value! */
+
+/*
+ * These are flag bits for the segment_command 'flags' field.
+ */
+
+#define COMP_ALG_MASK 0x7
+/* carve out 3 bits for an enum i.e. allow for 7 flavors */
+#define COMP_ALG_SHIFT 4 /* (bottom 4 bits taken) */
+
+/* zero -> no compression */
+typedef enum {
+ kCOMP_NONE = 0,
+ kCOMP_LZ4 = 1, /* 0x100 */
+ kCOMP_ZLIB = 2, /* 0x205 */
+ kCOMP_LZMA = 3, /* 0x306 */
+ kCOMP_LZFSE = 4, /* 0x801 */
+} compression_flavor_t;
+
+#define COMP_ALG_TYPE(f) ((compression_flavor_t)((f) >> COMP_ALG_SHIFT) & COMP_ALG_MASK)
+#define COMP_MAKE_FLAGS(t) (((t) & COMP_ALG_MASK) << COMP_ALG_SHIFT)
+
+struct proto_coredata_command {
+ uint32_t cmd; /* LC_COREDATA */
+ uint32_t cmdsize;
+ uint64_t vmaddr; /* memory address of this segment */
+ uint64_t vmsize; /* memory size of this segment */
+ uint64_t fileoff; /* file offset of this segment */
+ uint64_t filesize; /* amount to map from the file */
+ vm_prot_t maxprot; /* maximum VM protection */
+ vm_prot_t prot; /* current VM protection */
+ uint32_t flags;
+ uint8_t share_mode; /* SM_COW etc. */
+ uint8_t purgable; /* VM_PURGABLE_NONVOLATILE etc. */
+ uint8_t tag; /* VM_MEMORY_MALLOC etc. */
+ uint8_t extp; /* external pager */
+};
+
+#endif /* _LOADER_ADDITIONS_H */
diff --git a/system_cmds/gcore.tproj/main.c b/system_cmds/gcore.tproj/main.c
new file mode 100644
index 0000000..abefa14
--- /dev/null
+++ b/system_cmds/gcore.tproj/main.c
@@ -0,0 +1,863 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "utils.h"
+#include "corefile.h"
+#include "vanilla.h"
+#include "sparse.h"
+#include "convert.h"
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <libproc.h>
+
+#include <sys/kauth.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <libutil.h>
+
+#include <mach/mach.h>
+
+static char *
+kern_corefile(void)
+{
+ char *(^sysc_string)(const char *name) = ^(const char *name) {
+ char *p = NULL;
+ size_t len = 0;
+
+ if (-1 == sysctlbyname(name, NULL, &len, NULL, 0)) {
+ warnc(errno, "sysctl: %s", name);
+ } else if (0 != len) {
+ p = malloc(len);
+ if (-1 == sysctlbyname(name, p, &len, NULL, 0)) {
+ warnc(errno, "sysctl: %s", name);
+ free(p);
+ p = NULL;
+ }
+ }
+ return p;
+ };
+
+ char *s = sysc_string("kern.corefile");
+ if (NULL == s)
+ s = strdup("/cores/core.%P");
+ return s;
+}
+
+static const struct proc_bsdinfo *
+get_bsdinfo(pid_t pid)
+{
+ if (0 == pid)
+ return NULL;
+ struct proc_bsdinfo *pbi = calloc(1, sizeof (*pbi));
+ if (0 != proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, pbi, sizeof (*pbi)))
+ return pbi;
+ free(pbi);
+ return NULL;
+}
+
+static char *
+format_gcore_name(const char *fmt, pid_t pid, uid_t uid, const char *nm)
+{
+ __block size_t resid = MAXPATHLEN;
+ __block char *p = calloc(1, resid);
+ char *out = p;
+
+ int (^outchar)(int c) = ^(int c) {
+ if (resid > 1) {
+ *p++ = (char)c;
+ resid--;
+ return 1;
+ } else
+ return 0;
+ };
+
+ ptrdiff_t (^outstr)(const char *str) = ^(const char *str) {
+ const char *s = str;
+ while (*s && 0 != outchar(*s++))
+ ;
+ return s - str;
+ };
+
+ ptrdiff_t (^outint)(int value) = ^(int value) {
+ char id[11];
+ snprintf(id, sizeof (id), "%u", value);
+ return outstr(id);
+ };
+
+ ptrdiff_t (^outtstamp)(void) = ^(void) {
+ time_t now;
+ time(&now);
+ struct tm tm;
+ gmtime_r(&now, &tm);
+ char tstamp[50];
+ strftime(tstamp, sizeof (tstamp), "%Y%m%dT%H%M%SZ", &tm);
+ return outstr(tstamp);
+ };
+
+ int c;
+
+ for (int i = 0; resid > 0; i++)
+ switch (c = fmt[i]) {
+ default:
+ outchar(c);
+ break;
+ case '%':
+ i++;
+ switch (c = fmt[i]) {
+ case '%':
+ outchar(c);
+ break;
+ case 'P':
+ outint(pid);
+ break;
+ case 'U':
+ outint(uid);
+ break;
+ case 'N':
+ outstr(nm);
+ break;
+ case 'T':
+ outtstamp(); // ISO 8601 format
+ break;
+ default:
+ if (isprint(c))
+ err(EX_DATAERR, "unknown format char: %%%c", c);
+ else if (c != 0)
+ err(EX_DATAERR, "bad format char %%\\%03o", c);
+ else
+ err(EX_DATAERR, "bad format specifier");
+ }
+ break;
+ case 0:
+ outchar(c);
+ goto done;
+ }
+done:
+ return out;
+}
+
+static char *
+make_gcore_path(char **corefmtp, pid_t pid, uid_t uid, const char *nm)
+{
+ char *corefmt = *corefmtp;
+ if (NULL == corefmt) {
+ const char defcore[] = "%N-%P-%T";
+ if (NULL == (corefmt = kern_corefile()))
+ corefmt = strdup(defcore);
+ else {
+ // use the same directory as kern.corefile
+ char *p = strrchr(corefmt, '/');
+ if (NULL != p) {
+ *p = '\0';
+ size_t len = strlen(corefmt) + strlen(defcore) + 2;
+ char *buf = malloc(len);
+ snprintf(buf, len, "%s/%s", corefmt, defcore);
+ free(corefmt);
+ corefmt = buf;
+ }
+ if (OPTIONS_DEBUG(opt, 3))
+ printf("corefmt '%s'\n", corefmt);
+ }
+ }
+ char *path = format_gcore_name(corefmt, pid, uid, nm);
+ free(corefmt);
+ *corefmtp = NULL;
+ return path;
+}
+
+static bool proc_same_data_model(const struct proc_bsdinfo *pbi) {
+#if defined(__LP64__)
+ return (pbi->pbi_flags & PROC_FLAG_LP64) != 0;
+#else
+ return (pbi->pbi_flags & PROC_FLAG_LP64) == 0;
+#endif
+}
+
+static bool task_same_data_model(const task_flags_info_data_t *tfid) {
+#if defined(__LP64__)
+ return (tfid->flags & TF_LP64) != 0;
+#else
+ return (tfid->flags & TF_LP64) == 0;
+#endif
+}
+
+/*
+ * Change credentials for writing out the file
+ */
+static void
+change_credentials(gid_t uid, uid_t gid)
+{
+ if ((getgid() != gid && -1 == setgid(gid)) ||
+ (getuid() != uid && -1 == setuid(uid)))
+ errc(EX_NOPERM, errno, "insufficient privilege");
+ if (uid != getuid() || gid != getgid())
+ err(EX_OSERR, "wrong credentials");
+}
+
+static int
+openout(const char *corefname, char **coretname, struct stat *st)
+{
+ const int tfd = open(corefname, O_WRONLY);
+ if (-1 == tfd) {
+ if (ENOENT == errno) {
+ /*
+ * Arrange for a core file to appear "atomically": write the data
+ * to the file + ".tmp" suffix, then fchmod and rename it into
+ * place once the dump completes successfully.
+ */
+ const size_t nmlen = strlen(corefname) + 4 + 1;
+ char *tnm = malloc(nmlen);
+ snprintf(tnm, nmlen, "%s.tmp", corefname);
+ const int fd = open(tnm, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+ if (-1 == fd || -1 == fstat(fd, st))
+ errc(EX_CANTCREAT, errno, "%s", tnm);
+ if (!S_ISREG(st->st_mode) || 1 != st->st_nlink)
+ errx(EX_CANTCREAT, "%s: invalid attributes", tnm);
+ *coretname = tnm;
+ return fd;
+ } else
+ errc(EX_CANTCREAT, errno, "%s", corefname);
+ } else if (-1 == fstat(tfd, st)) {
+ close(tfd);
+ errx(EX_CANTCREAT, "%s: fstat", corefname);
+ } else if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
+ /*
+ * Write dump to a device, no rename!
+ */
+ *coretname = NULL;
+ return tfd;
+ } else {
+ close(tfd);
+ errc(EX_CANTCREAT, EEXIST, "%s", corefname);
+ }
+}
+
+static int
+closeout(int fd, int ecode, char *corefname, char *coretname, const struct stat *st)
+{
+ if (0 != ecode && !opt->preserve && S_ISREG(st->st_mode))
+ ftruncate(fd, 0); // limit large file clutter
+ if (0 == ecode && S_ISREG(st->st_mode))
+ fchmod(fd, 0400); // protect core files
+ if (-1 == close(fd)) {
+ warnc(errno, "%s: close", coretname ? coretname : corefname);
+ ecode = EX_OSERR;
+ }
+ if (NULL != coretname) {
+ if (0 == ecode && -1 == rename(coretname, corefname)) {
+ warnc(errno, "cannot rename %s to %s", coretname, corefname);
+ ecode = EX_NOPERM;
+ }
+ free(coretname);
+ }
+ if (corefname)
+ free(corefname);
+ return ecode;
+}
+
+const char *pgm;
+const struct options *opt;
+
+static const size_t oneK = 1024;
+static const size_t oneM = oneK * oneK;
+
+#define LARGEST_CHUNKSIZE INT32_MAX
+#define DEFAULT_COMPRESSION_CHUNKSIZE (16 * oneM)
+#define DEFAULT_NC_THRESHOLD (17 * oneK)
+
+static struct options options = {
+ .corpsify = 0,
+ .suspend = 0,
+ .preserve = 0,
+ .verbose = 0,
+#ifdef CONFIG_DEBUG
+ .debug = 0,
+#endif
+ .extended = 0,
+ .sizebound = 0,
+ .chunksize = 0,
+ .calgorithm = COMPRESSION_LZFSE,
+ .ncthresh = DEFAULT_NC_THRESHOLD,
+ .dsymforuuid = 0,
+};
+
+static int
+gcore_main(int argc, char *const *argv)
+{
+#define ZOPT_ALG (0)
+#define ZOPT_CHSIZE (ZOPT_ALG + 1)
+
+ static char *const zoptkeys[] = {
+ [ZOPT_ALG] = "algorithm",
+ [ZOPT_CHSIZE] = "chunksize",
+ NULL
+ };
+
+ err_set_exit_b(^(int eval) {
+ if (EX_USAGE == eval) {
+ fprintf(stderr,
+ "usage:\t%s [-s] [-v] [[-o file] | [-c pathfmt ]] [-b size] "
+#if DEBUG
+#ifdef CONFIG_DEBUG
+ "[-d] "
+#endif
+ "[-x] [-C] "
+ "[-Z compression-options] "
+ "[-t size] "
+ "[-F] "
+#endif
+ "pid\n", pgm);
+#if DEBUG
+ fprintf(stderr, "where compression-options:\n");
+ const char zvalfmt[] = "\t%s=%s\t\t%s\n";
+ fprintf(stderr, zvalfmt, zoptkeys[ZOPT_ALG], "alg",
+ "set compression algorithm");
+ fprintf(stderr, zvalfmt, zoptkeys[ZOPT_CHSIZE], "size",
+ "set compression chunksize, Mib");
+#endif
+ }
+ });
+
+ char *corefmt = NULL;
+ char *corefname = NULL;
+
+ int c;
+ char *sopts, *value;
+
+ while ((c = getopt(argc, argv, "vdsxCFZ:o:c:b:t:")) != -1) {
+ switch (c) {
+
+ /*
+ * documented options
+ */
+ case 's': /* FreeBSD compat: stop while gathering */
+ options.suspend = 1;
+ break;
+ case 'o': /* Linux (& SunOS) compat: basic name */
+ corefname = strdup(optarg);
+ break;
+ case 'c': /* FreeBSD compat: basic name */
+ /* (also allows pattern-based naming) */
+ corefmt = strdup(optarg);
+ break;
+
+ case 'b': /* bound the size of the core file */
+ if (NULL != optarg) {
+ off_t bsize = atoi(optarg) * oneM;
+ if (bsize > 0)
+ options.sizebound = bsize;
+ else
+ errx(EX_USAGE, "invalid bound");
+ } else
+ errx(EX_USAGE, "no bound specified");
+ break;
+ case 'v': /* verbose output */
+ options.verbose++;
+ break;
+
+ /*
+ * dev and debugging help
+ */
+#ifdef CONFIG_DEBUG
+ case 'd': /* debugging */
+ options.debug++;
+ options.verbose++;
+ options.preserve++;
+ break;
+#endif
+ /*
+ * Remaining options are experimental and/or
+ * affect the content of the core file
+ */
+ case 'x': /* write extended format (small) core files */
+ options.extended++;
+ options.chunksize = DEFAULT_COMPRESSION_CHUNKSIZE;
+ break;
+ case 'C': /* forcibly corpsify rather than suspend */
+ options.corpsify++;
+ break;
+ case 'Z': /* control compression options */
+ /*
+ * Only LZFSE and LZ4 seem practical.
+ * (Default to LZ4 compression when the
+ * process is suspended, LZFSE when corpsed?)
+ */
+ if (0 == options.extended)
+ errx(EX_USAGE, "illegal flag combination");
+ sopts = optarg;
+ while (*sopts) {
+ size_t chsize;
+
+ switch (getsubopt(&sopts, zoptkeys, &value)) {
+ case ZOPT_ALG: /* change the algorithm */
+ if (NULL == value)
+ errx(EX_USAGE, "missing algorithm for "
+ "%s suboption",
+ zoptkeys[ZOPT_ALG]);
+ if (strcmp(value, "lz4") == 0)
+ options.calgorithm = COMPRESSION_LZ4;
+ else if (strcmp(value, "zlib") == 0)
+ options.calgorithm = COMPRESSION_ZLIB;
+ else if (strcmp(value, "lzma") == 0)
+ options.calgorithm = COMPRESSION_LZMA;
+ else if (strcmp(value, "lzfse") == 0)
+ options.calgorithm = COMPRESSION_LZFSE;
+ else
+ errx(EX_USAGE, "unknown algorithm '%s'"
+ " for %s suboption",
+ value, zoptkeys[ZOPT_ALG]);
+ break;
+ case ZOPT_CHSIZE: /* set the chunksize */
+ if (NULL == value)
+ errx(EX_USAGE, "no value specified for "
+ "%s suboption",
+ zoptkeys[ZOPT_CHSIZE]);
+ if ((chsize = atoi(value)) < 1)
+ errx(EX_USAGE, "chunksize %lu too small", chsize);
+ if (chsize > (LARGEST_CHUNKSIZE / oneM))
+ errx(EX_USAGE, "chunksize %lu too large", chsize);
+ options.chunksize = chsize * oneM;
+ break;
+ default:
+ if (suboptarg)
+ errx(EX_USAGE, "illegal suboption '%s'",
+ suboptarg);
+ else
+ errx(EX_USAGE, "missing suboption");
+ }
+ }
+ break;
+ case 't': /* set the F_NOCACHE threshold */
+ if (NULL != optarg) {
+ size_t tsize = atoi(optarg) * oneK;
+ if (tsize > 0)
+ options.ncthresh = tsize;
+ else
+ errx(EX_USAGE, "invalid nc threshold");
+ } else
+ errx(EX_USAGE, "no threshold specified");
+ break;
+ case 'F': /* maximize filerefs */
+ options.allfilerefs++;
+ break;
+ default:
+ errx(EX_USAGE, "unknown flag");
+ }
+ }
+
+ if (optind == argc)
+ errx(EX_USAGE, "no pid specified");
+ if (optind < argc-1)
+ errx(EX_USAGE, "too many arguments");
+
+ opt = &options;
+ if (NULL != corefname && NULL != corefmt)
+ errx(EX_USAGE, "specify only one of -o and -c");
+ if (!opt->extended && opt->allfilerefs)
+ errx(EX_USAGE, "unknown flag");
+
+ setpageshift();
+
+ if (opt->ncthresh < ((vm_offset_t)1 << pageshift_host))
+ errx(EX_USAGE, "threshold %lu less than host pagesize", opt->ncthresh);
+
+ const pid_t apid = atoi(argv[optind]);
+ pid_t pid = apid;
+ mach_port_t corpse = MACH_PORT_NULL;
+ kern_return_t ret;
+
+ if (0 == apid) {
+ /* look for corpse - dead or alive */
+ mach_port_array_t parray = NULL;
+ mach_msg_type_number_t pcount = 0;
+ ret = mach_ports_lookup(mach_task_self(), &parray, &pcount);
+ if (KERN_SUCCESS == ret && pcount > 0) {
+ task_t tcorpse = parray[0];
+ mig_deallocate((vm_address_t)parray, pcount * sizeof (*parray));
+ pid_t tpid = 0;
+ ret = pid_for_task(tcorpse, &tpid);
+ if (KERN_SUCCESS == ret && tpid != getpid()) {
+ corpse = tcorpse;
+ pid = tpid;
+ }
+ }
+ }
+
+ if (pid < 1 || getpid() == pid)
+ errx(EX_DATAERR, "invalid pid: %d", pid);
+
+ if (0 == apid && MACH_PORT_NULL == corpse)
+ errx(EX_DATAERR, "missing or bad corpse from parent");
+
+ task_t task = TASK_NULL;
+ const struct proc_bsdinfo *pbi = NULL;
+ const int rc = kill(pid, 0);
+
+ if (rc == 0) {
+ /* process or corpse that may respond to signals */
+ pbi = get_bsdinfo(pid);
+ }
+
+ if (rc == 0 && pbi != NULL) {
+ /* process or corpse that responds to signals */
+
+ /* make our data model match the data model of the target */
+ if (-1 == reexec_to_match_lp64ness(pbi->pbi_flags & PROC_FLAG_LP64))
+ errc(1, errno, "cannot match data model of %d", pid);
+
+ if (!proc_same_data_model(pbi))
+ errx(EX_OSERR, "cannot match data model of %d", pid);
+
+ if (pbi->pbi_ruid != pbi->pbi_svuid ||
+ pbi->pbi_rgid != pbi->pbi_svgid)
+ errx(EX_NOPERM, "pid %d - not dumping a set-id process", pid);
+
+ if (NULL == corefname)
+ corefname = make_gcore_path(&corefmt, pbi->pbi_pid, pbi->pbi_uid, pbi->pbi_name[0] ? pbi->pbi_name : pbi->pbi_comm);
+
+ if (MACH_PORT_NULL == corpse) {
+ ret = task_for_pid(mach_task_self(), pid, &task);
+ if (KERN_SUCCESS != ret) {
+ if (KERN_FAILURE == ret)
+ errx(EX_NOPERM, "insufficient privilege");
+ else
+ errx(EX_NOPERM, "task_for_pid: %s", mach_error_string(ret));
+ }
+ }
+
+ /*
+ * Have either the corpse port or the task port so adopt the
+ * credentials of the target process, *before* opening the
+ * core file, and analyzing the address space.
+ *
+ * If we are unable to match the target credentials, bail out.
+ */
+ change_credentials(pbi->pbi_uid, pbi->pbi_gid);
+ } else {
+ if (MACH_PORT_NULL == corpse) {
+ if (rc == 0) {
+ errx(EX_OSERR, "cannot get process info for %d", pid);
+ }
+ switch (errno) {
+ case ESRCH:
+ errc(EX_DATAERR, errno, "no process with pid %d", pid);
+ default:
+ errc(EX_DATAERR, errno, "pid %d", pid);
+ }
+ }
+ /* a corpse with no live process backing it */
+
+ assert(0 == apid && TASK_NULL == task);
+
+ task_flags_info_data_t tfid;
+ mach_msg_type_number_t count = TASK_FLAGS_INFO_COUNT;
+ ret = task_info(corpse, TASK_FLAGS_INFO, (task_info_t)&tfid, &count);
+ if (KERN_SUCCESS != ret)
+ err_mach(ret, NULL, "task_info");
+ if (!task_same_data_model(&tfid))
+ errx(EX_OSERR, "data model mismatch for target corpse");
+
+ if (opt->suspend || opt->corpsify)
+ errx(EX_USAGE, "cannot use -s or -C option with a corpse");
+ if (NULL != corefmt)
+ errx(EX_USAGE, "cannot use -c with a corpse");
+ if (NULL == corefname)
+ corefname = make_gcore_path(&corefmt, pid, -2, "corpse");
+
+ /*
+ * Only have a corpse, thus no process credentials.
+ * Switch to nobody.
+ */
+ change_credentials(-2, -2);
+ }
+
+ struct stat cst;
+ char *coretname = NULL;
+ const int fd = openout(corefname, &coretname, &cst);
+
+ if (opt->verbose) {
+ printf("Dumping core ");
+ if (OPTIONS_DEBUG(opt, 1)) {
+ printf("(%s", opt->extended ? "extended" : "vanilla");
+ if (0 != opt->sizebound) {
+ hsize_str_t hstr;
+ printf(", <= %s", str_hsize(hstr, opt->sizebound));
+ }
+ printf(") ");
+ }
+ printf("for pid %d to %s\n", pid, corefname);
+ }
+
+ int ecode;
+
+ if (MACH_PORT_NULL == corpse) {
+ assert(TASK_NULL != task);
+
+ /*
+ * The "traditional" way to capture a consistent core dump is to
+ * suspend the process while examining it and writing it out.
+ * Yet suspending a large process for a long time can have
+ * unpleasant side-effects. Alternatively dumping from the live
+ * process can lead to an inconsistent state in the core file.
+ *
+ * Instead we can ask xnu to create a 'corpse' - the process is transiently
+ * suspended while a COW snapshot of the address space is constructed
+ * in the kernel and dump from that. This vastly reduces the suspend
+ * time, but it is more resource hungry and thus may fail.
+ *
+ * The -s flag (opt->suspend) causes a task_suspend/task_resume
+ * The -C flag (opt->corpse) causes a corpse be taken, exiting if that fails.
+ * Both flags can be specified, in which case corpse errors are ignored.
+ *
+ * With no flags, we imitate traditional behavior though more
+ * efficiently: we try to take a corpse-based dump, in the event that
+ * fails, dump the live process.
+ */
+
+ int trycorpse = 1; /* default: use corpses */
+ int badcorpse_is_fatal = 1; /* default: failure to create is an error */
+
+ if (!opt->suspend && !opt->corpsify) {
+ /* try a corpse dump, else dump the live process */
+ badcorpse_is_fatal = 0;
+ } else if (opt->suspend) {
+ trycorpse = opt->corpsify;
+ /* if suspended anyway, ignore corpse-creation errors */
+ badcorpse_is_fatal = 0;
+ }
+
+ if (opt->suspend)
+ task_suspend(task);
+
+ if (trycorpse) {
+ /*
+ * Create a corpse from the image before dumping it
+ */
+ ret = task_generate_corpse(task, &corpse);
+ switch (ret) {
+ case KERN_SUCCESS:
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("Corpse generated on port %x, task %x\n",
+ corpse, task);
+ ecode = coredump(corpse, fd, pbi);
+ mach_port_deallocate(mach_task_self(), corpse);
+ break;
+ default:
+ if (badcorpse_is_fatal || opt->verbose) {
+ warnx("failed to snapshot pid %d: %s\n",
+ pid, mach_error_string(ret));
+ if (badcorpse_is_fatal) {
+ ecode = KERN_RESOURCE_SHORTAGE == ret ? EX_TEMPFAIL : EX_OSERR;
+ goto out;
+ }
+ }
+ ecode = coredump(task, fd, pbi);
+ break;
+ }
+ } else {
+ /*
+ * Examine the task directly
+ */
+ ecode = coredump(task, fd, pbi);
+ }
+
+ out:
+ if (opt->suspend)
+ task_resume(task);
+ } else {
+ /*
+ * Handed a corpse by our parent.
+ */
+ ecode = coredump(corpse, fd, pbi);
+ mach_port_deallocate(mach_task_self(), corpse);
+ }
+
+ ecode = closeout(fd, ecode, corefname, coretname, &cst);
+ if (ecode)
+ errx(ecode, "failed to dump core for pid %d", pid);
+ return 0;
+}
+
+#if defined(CONFIG_GCORE_FREF) || defined(CONFIG_GCORE_MAP) || defined(GCONFIG_GCORE_CONV)
+
+static int
+getcorefd(const char *infile)
+{
+ const int fd = open(infile, O_RDONLY | O_CLOEXEC);
+ if (-1 == fd)
+ errc(EX_DATAERR, errno, "cannot open %s", infile);
+
+ struct mach_header mh;
+ if (-1 == pread(fd, &mh, sizeof (mh), 0))
+ errc(EX_OSERR, errno, "cannot read mach header from %s", infile);
+
+ static const char cant_match_data_model[] = "cannot match the data model of %s";
+
+ if (-1 == reexec_to_match_lp64ness(MH_MAGIC_64 == mh.magic))
+ errc(1, errno, cant_match_data_model, infile);
+
+ if (NATIVE_MH_MAGIC != mh.magic)
+ errx(EX_OSERR, cant_match_data_model, infile);
+ if (MH_CORE != mh.filetype)
+ errx(EX_DATAERR, "%s is not a mach core file", infile);
+ return fd;
+}
+
+#endif
+
+#ifdef CONFIG_GCORE_FREF
+
+static int
+gcore_fref_main(int argc, char *argv[])
+{
+ err_set_exit_b(^(int eval) {
+ if (EX_USAGE == eval) {
+ fprintf(stderr, "usage:\t%s %s corefile\n", pgm, argv[1]);
+ }
+ });
+ if (2 == argc)
+ errx(EX_USAGE, "no input corefile");
+ if (argc > 3)
+ errx(EX_USAGE, "too many arguments");
+ opt = &options;
+ return gcore_fref(getcorefd(argv[2]));
+}
+
+#endif /* CONFIG_GCORE_FREF */
+
+#ifdef CONFIG_GCORE_MAP
+
+static int
+gcore_map_main(int argc, char *argv[])
+{
+ err_set_exit_b(^(int eval) {
+ if (EX_USAGE == eval) {
+ fprintf(stderr, "usage:\t%s %s corefile\n", pgm, argv[1]);
+ }
+ });
+ if (2 == argc)
+ errx(EX_USAGE, "no input corefile");
+ if (argc > 3)
+ errx(EX_USAGE, "too many arguments");
+ opt = &options;
+ return gcore_map(getcorefd(argv[2]));
+}
+
+#endif
+
+#ifdef CONFIG_GCORE_CONV
+
+static int
+gcore_conv_main(int argc, char *argv[])
+{
+ err_set_exit_b(^(int eval) {
+ if (EX_USAGE == eval)
+ fprintf(stderr,
+ "usage:\t%s %s [-v] [-L searchpath] [-z] [-s] incore outcore\n", pgm, argv[1]);
+ });
+
+ char *searchpath = NULL;
+ bool zf = false;
+
+ int c;
+ optind = 2;
+ while ((c = getopt(argc, argv, "dzvL:s")) != -1) {
+ switch (c) {
+ /*
+ * likely documented options
+ */
+ case 'L':
+ searchpath = strdup(optarg);
+ break;
+ case 'z':
+ zf = true;
+ break;
+ case 'v':
+ options.verbose++;
+ break;
+ case 's':
+ options.dsymforuuid++;
+ break;
+ /*
+ * dev and debugging help
+ */
+#ifdef CONFIG_DEBUG
+ case 'd':
+ options.debug++;
+ options.verbose++;
+ options.preserve++;
+ break;
+#endif
+ default:
+ errx(EX_USAGE, "unknown flag");
+ }
+ }
+ if (optind == argc)
+ errx(EX_USAGE, "no input corefile");
+ if (optind == argc - 1)
+ errx(EX_USAGE, "no output corefile");
+ if (optind < argc - 2)
+ errx(EX_USAGE, "too many arguments");
+
+ const char *incore = argv[optind];
+ char *corefname = strdup(argv[optind+1]);
+
+ opt = &options;
+
+ setpageshift();
+
+ if (opt->ncthresh < ((vm_offset_t)1 << pageshift_host))
+ errx(EX_USAGE, "threshold %lu less than host pagesize", opt->ncthresh);
+
+ const int infd = getcorefd(incore);
+ struct stat cst;
+ char *coretname = NULL;
+ const int fd = openout(corefname, &coretname, &cst);
+ int ecode = gcore_conv(infd, searchpath, zf, fd);
+ ecode = closeout(fd, ecode, corefname, coretname, &cst);
+ if (ecode)
+ errx(ecode, "failed to convert core file successfully");
+ return 0;
+}
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ if (NULL == (pgm = strrchr(*argv, '/')))
+ pgm = *argv;
+ else
+ pgm++;
+#ifdef CONFIG_GCORE_FREF
+ if (argc > 1 && 0 == strcmp(argv[1], "fref")) {
+ return gcore_fref_main(argc, argv);
+ }
+#endif
+#ifdef CONFIG_GCORE_MAP
+ if (argc > 1 && 0 == strcmp(argv[1], "map")) {
+ return gcore_map_main(argc, argv);
+ }
+#endif
+#ifdef CONFIG_GCORE_CONV
+ if (argc > 1 && 0 == strcmp(argv[1], "conv")) {
+ return gcore_conv_main(argc, argv);
+ }
+#endif
+ return gcore_main(argc, argv);
+}
diff --git a/system_cmds/gcore.tproj/options.h b/system_cmds/gcore.tproj/options.h
new file mode 100644
index 0000000..71481fa
--- /dev/null
+++ b/system_cmds/gcore.tproj/options.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <compression.h>
+
+#include <assert.h>
+
+#ifndef _OPTIONS_H
+#define _OPTIONS_H
+
+#if defined(__arm__) || defined(__arm64__)
+#define RDAR_23744374 1 /* 'true' while not fixed i.e. enable workarounds */
+#define RDAR_28040018 1 /* 'true' while not fixed i.e. enable workarounds */
+#endif
+
+//#define CONFIG_SUBMAP 1 /* include submaps (debugging output) */
+#define CONFIG_GCORE_MAP 1 /* support 'gcore map' */
+#define CONFIG_GCORE_CONV 1 /* support 'gcore conv' - new -> old core files */
+#define CONFIG_GCORE_FREF 1 /* support 'gcore fref' - referenced file list */
+#define CONFIG_DEBUG 1 /* support '-d' option */
+
+#ifdef NDEBUG
+#define poison(a, p, s) /* do nothing */
+#else
+#define poison(a, p, s) memset(a, p, s) /* scribble on dying memory */
+#endif
+
+struct options {
+ int corpsify; // make a corpse to dump from
+ int suspend; // suspend while dumping
+ int preserve; // preserve the core file, even if there are errors
+ int verbose; // be chatty
+#ifdef CONFIG_DEBUG
+ int debug; // internal debugging: options accumulate. noisy.
+#endif
+ int extended; // avoid writing out ro mapped files, compress regions
+ off_t sizebound; // maximum size of the dump
+ size_t chunksize; // max size of a compressed subregion
+ compression_algorithm calgorithm; // algorithm in use
+ size_t ncthresh; // F_NOCACHE enabled *above* this value
+ int allfilerefs; // if set, every mapped file on the root fs is a fileref
+ int dsymforuuid; // Try dsysForUUID to retrieve symbol-rich executable
+};
+
+extern const struct options *opt;
+
+/*
+ * == 0 - not verbose
+ * >= 1 - verbose plus chatty
+ * >= 2 - tabular summaries
+ * >= 3 - all
+ */
+
+#ifdef CONFIG_DEBUG
+#define OPTIONS_DEBUG(opt, lvl) ((opt)->debug && (opt)->debug >= (lvl))
+#else
+#define OPTIONS_DEBUG(opt, lvl) 0
+#endif
+
+#endif /* _OPTIONS_H */
diff --git a/system_cmds/gcore.tproj/region.h b/system_cmds/gcore.tproj/region.h
new file mode 100644
index 0000000..77853b2
--- /dev/null
+++ b/system_cmds/gcore.tproj/region.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <mach/mach.h>
+#include <uuid/uuid.h>
+
+#ifndef _REGION_H
+#define _REGION_H
+
+/*
+ * A range of virtual memory
+ */
+struct vm_range {
+ mach_vm_offset_t addr;
+ mach_vm_offset_t size;
+};
+
+#define _V_ADDR(g) ((g)->addr)
+#define _V_SIZE(g) ((g)->size)
+#define V_SETADDR(g, a) ((g)->addr = (a))
+#define V_SETSIZE(g, z) ((g)->size = (z))
+#define V_ENDADDR(g) (_V_ADDR(g) + _V_SIZE(g))
+
+static __inline const mach_vm_offset_t V_ADDR(const struct vm_range *vr) {
+ return _V_ADDR(vr);
+}
+static __inline const mach_vm_offset_t V_SIZE(const struct vm_range *vr) {
+ return _V_SIZE(vr);
+}
+static __inline const size_t V_SIZEOF(const struct vm_range *vr) {
+ assert((typeof (vr->size))(size_t)_V_SIZE(vr) == _V_SIZE(vr));
+ return (size_t)_V_SIZE(vr);
+}
+
+/*
+ * A range of offsets into a file
+ */
+struct file_range {
+ off_t off;
+ off_t size;
+};
+
+#define F_OFF(f) ((f)->off)
+#define F_SIZE(f) ((f)->size)
+
+struct regionop;
+struct subregion;
+
+struct region {
+ STAILQ_ENTRY(region) r_linkage;
+
+ struct vm_range r_range;
+
+#define R_RANGE(r) (&(r)->r_range)
+#define _R_ADDR(r) _V_ADDR(R_RANGE(r))
+#define _R_SIZE(r) _V_SIZE(R_RANGE(r))
+#define R_SIZEOF(r) V_SIZEOF(R_RANGE(r))
+#define R_SETADDR(r, a) V_SETADDR(R_RANGE(r), (a))
+#define R_SETSIZE(r, z) V_SETSIZE(R_RANGE(r), (z))
+#define R_ENDADDR(r) (_R_ADDR(r) + _R_SIZE(r))
+
+ vm_region_submap_info_data_64_t r_info;
+ vm_page_info_basic_data_t r_pageinfo;
+
+ int r_purgable;
+
+#ifdef CONFIG_SUBMAP
+ int r_depth;
+#endif
+ boolean_t r_insharedregion, r_inzfodregion, r_incommregion;
+
+ /*
+ * This field may be non-NULL if the region is a read-only part
+ * of a mapped file (i.e. the shared cache) and thus
+ * doesn't need to be copied.
+ */
+ struct {
+ const struct libent *fr_libent;
+ const char *fr_pathname;
+ off_t fr_offset;
+ } *r_fileref;
+
+ /*
+ * These (optional) fields are filled in after we parse the information
+ * about the dylibs we've mapped, as provided by dyld.
+ */
+ struct subregion **r_subregions;
+ unsigned r_nsubregions;
+
+ const struct regionop *r_op;
+};
+
+static __inline const mach_vm_offset_t R_ADDR(const struct region *r) {
+ return _R_ADDR(r);
+}
+static __inline const mach_vm_offset_t R_SIZE(const struct region *r) {
+ return _R_SIZE(r);
+}
+
+/*
+ * Describes the disposition of the region after a walker returns
+ */
+typedef enum {
+ WALK_CONTINUE, // press on ..
+ WALK_DELETE_REGION, // discard this region, then continue
+ WALK_TERMINATE, // early termination, no error
+ WALK_ERROR, // early termination, error
+} walk_return_t;
+
+struct size_core;
+struct write_segment_data;
+
+typedef walk_return_t walk_region_cbfn_t(struct region *, void *);
+
+struct regionop {
+ void (*rop_print)(const struct region *);
+ walk_return_t (*rop_write)(const struct region *, struct write_segment_data *);
+ void (*rop_delete)(struct region *);
+};
+
+#define ROP_PRINT(r) (((r)->r_op->rop_print)(r))
+#define ROP_WRITE(r, w) (((r)->r_op->rop_write)(r, w))
+#define ROP_DELETE(r) (((r)->r_op->rop_delete)(r))
+
+extern const struct regionop vanilla_ops, sparse_ops, zfod_ops;
+extern const struct regionop fileref_ops;
+
+struct regionhead;
+
+#endif /* _REGION_H */
diff --git a/system_cmds/gcore.tproj/sparse.c b/system_cmds/gcore.tproj/sparse.c
new file mode 100644
index 0000000..c62b9f3
--- /dev/null
+++ b/system_cmds/gcore.tproj/sparse.c
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "vm.h"
+#include "region.h"
+#include "utils.h"
+#include "dyld.h"
+#include "threads.h"
+#include "sparse.h"
+#include "vanilla.h"
+#include "corefile.h"
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <libproc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include <mach/mach.h>
+
+static struct subregion *
+new_subregion(
+ const mach_vm_offset_t vmaddr,
+ const mach_vm_offset_t vmsize,
+ const native_segment_command_t *sc,
+ const struct libent *le)
+{
+ struct subregion *s = malloc(sizeof (*s));
+
+ assert(vmaddr != 0 && vmsize != 0);
+ assert(vmaddr < vmaddr + vmsize);
+ s->s_segcmd = *sc;
+
+ S_SETADDR(s, vmaddr);
+ S_SETSIZE(s, vmsize);
+
+ s->s_libent = le;
+ s->s_isuuidref = false;
+ return s;
+}
+
+static void
+del_subregion(struct subregion *s)
+{
+ poison(s, 0xfacefac1, sizeof (*s));
+ free(s);
+}
+
+static walk_return_t
+clean_subregions(struct region *r)
+{
+ if (r->r_nsubregions) {
+ assert(r->r_subregions);
+ for (unsigned i = 0; i < r->r_nsubregions; i++)
+ del_subregion(r->r_subregions[i]);
+ poison(r->r_subregions, 0xfac1fac1, sizeof (r->r_subregions[0]) * r->r_nsubregions);
+ free(r->r_subregions);
+ r->r_nsubregions = 0;
+ r->r_subregions = NULL;
+ } else {
+ assert(NULL == r->r_subregions);
+ }
+ return WALK_CONTINUE;
+}
+
+void
+del_sparse_region(struct region *r)
+{
+ clean_subregions(r);
+ poison(r, 0xcafecaff, sizeof (*r));
+ free(r);
+}
+
+#define NULLsc ((native_segment_command_t *)0)
+
+static bool
+issamesubregiontype(const struct subregion *s0, const struct subregion *s1) {
+ return 0 == strncmp(S_MACHO_TYPE(s0), S_MACHO_TYPE(s1), sizeof (NULLsc->segname));
+}
+
+bool
+issubregiontype(const struct subregion *s, const char *sctype) {
+ return 0 == strncmp(S_MACHO_TYPE(s), sctype, sizeof (NULLsc->segname));
+}
+
+static void
+elide_subregion(struct region *r, unsigned ind)
+{
+ del_subregion(r->r_subregions[ind]);
+ for (unsigned j = ind; j < r->r_nsubregions - 1; j++)
+ r->r_subregions[j] = r->r_subregions[j+1];
+ assert(r->r_nsubregions != 0);
+ r->r_subregions[--r->r_nsubregions] = NULL;
+}
+
+struct subregionlist {
+ STAILQ_ENTRY(subregionlist) srl_linkage;
+ struct subregion *srl_s;
+};
+typedef STAILQ_HEAD(, subregionlist) subregionlisthead_t;
+
+static walk_return_t
+add_subregions_for_libent(
+ subregionlisthead_t *srlh,
+ const struct region *r,
+ const native_mach_header_t *mh,
+ const mach_vm_offset_t __unused mh_taddr, // address in target
+ const struct libent *le)
+{
+ const struct load_command *lc = (const void *)(mh + 1);
+ mach_vm_offset_t objoff = le->le_objoff;
+ for (unsigned n = 0; n < mh->ncmds; n++) {
+
+ const native_segment_command_t *sc;
+
+ switch (lc->cmd) {
+ case NATIVE_LC_SEGMENT:
+ sc = (const void *)lc;
+
+ if (0 == sc->vmaddr && strcmp(sc->segname, SEG_PAGEZERO) == 0)
+ break;
+ mach_vm_offset_t lo = sc->vmaddr + objoff;
+ mach_vm_offset_t hi = lo + sc->vmsize;
+
+ /* Eliminate non-overlapping sections first */
+
+ if (R_ENDADDR(r) - 1 < lo)
+ break;
+ if (hi - 1 < R_ADDR(r))
+ break;
+
+ /*
+ * Some part of this segment is in the region.
+ * Trim the edges in the case where we span regions.
+ */
+ if (lo < R_ADDR(r))
+ lo = R_ADDR(r);
+ if (hi > R_ENDADDR(r))
+ hi = R_ENDADDR(r);
+
+ struct subregionlist *srl = calloc(1, sizeof (*srl));
+ struct subregion *s = new_subregion(lo, hi - lo, sc, le);
+ assert(sc->fileoff >= 0);
+ srl->srl_s = s;
+ STAILQ_INSERT_HEAD(srlh, srl, srl_linkage);
+
+ if (OPTIONS_DEBUG(opt, 2)) {
+ hsize_str_t hstr;
+ printr(r, "subregion %llx-%llx %7s %12s\t%s [%s off %lu for %lu nsects %u flags %x]\n",
+ S_ADDR(s), S_ENDADDR(s),
+ str_hsize(hstr, S_SIZE(s)),
+ sc->segname,
+ S_FILENAME(s),
+ str_prot(sc->initprot),
+ (unsigned long)sc->fileoff,
+ (unsigned long)sc->filesize,
+ sc->nsects, sc->flags);
+ }
+ break;
+ default:
+ break;
+ }
+ if (lc->cmdsize)
+ lc = (const void *)((caddr_t)lc + lc->cmdsize);
+ else
+ break;
+ }
+ return WALK_CONTINUE;
+}
+
+/*
+ * Because we aggregate information from multiple sources, there may
+ * be duplicate subregions. Eliminate them here.
+ *
+ * Note that the each library in the shared cache points
+ * separately at a single, unified (large!) __LINKEDIT section; these
+ * get removed here too.
+ *
+ * Assumes the subregion array is sorted by address!
+ */
+static void
+eliminate_duplicate_subregions(struct region *r)
+{
+ unsigned i = 1;
+ while (i < r->r_nsubregions) {
+ struct subregion *s0 = r->r_subregions[i-1];
+ struct subregion *s1 = r->r_subregions[i];
+
+ if (S_ADDR(s0) != S_ADDR(s1) || S_SIZE(s0) != S_SIZE(s1)) {
+ i++;
+ continue;
+ }
+ if (memcmp(&s0->s_segcmd, &s1->s_segcmd, sizeof (s0->s_segcmd)) != 0) {
+ i++;
+ continue;
+ }
+ if (OPTIONS_DEBUG(opt, 3))
+ printr(r, "eliding duplicate %s subregion (%llx-%llx) file %s\n",
+ S_MACHO_TYPE(s1), S_ADDR(s1), S_ENDADDR(s1), S_FILENAME(s1));
+ /* If the duplicate subregions aren't mapping the same file (?), forget the name */
+ if (s0->s_libent != s1->s_libent)
+ s0->s_libent = s1->s_libent = NULL;
+ elide_subregion(r, i);
+ }
+}
+
+/*
+ * See if any of the dyld information we have can better describe this
+ * region of the target address space.
+ */
+walk_return_t
+decorate_memory_region(struct region *r, void *arg)
+{
+ if (r->r_inzfodregion || r->r_incommregion)
+ return WALK_CONTINUE;
+
+ const dyld_process_info dpi = arg;
+
+ __block walk_return_t retval = WALK_CONTINUE;
+ __block subregionlisthead_t srlhead = STAILQ_HEAD_INITIALIZER(srlhead);
+
+ _dyld_process_info_for_each_image(dpi, ^(uint64_t __unused mhaddr, const uuid_t uuid, __unused const char *path) {
+ if (WALK_CONTINUE == retval) {
+ const struct libent *le = libent_lookup_byuuid(uuid);
+ assert(le->le_mhaddr == mhaddr);
+ bool shouldskip = false;
+ if (V_SIZE(&le->le_vr))
+ shouldskip = (R_ENDADDR(r) < V_ADDR(&le->le_vr) ||
+ R_ADDR(r) > V_ENDADDR(&le->le_vr));
+ if (!shouldskip)
+ retval = add_subregions_for_libent(&srlhead, r, le->le_mh, le->le_mhaddr, le);
+ }
+ });
+ if (WALK_CONTINUE != retval)
+ goto done;
+
+ /*
+ * Take the unsorted list of subregions, if any,
+ * and hang a sorted array of ranges on the region structure.
+ */
+ if (!STAILQ_EMPTY(&srlhead)) {
+ struct subregionlist *srl;
+ STAILQ_FOREACH(srl, &srlhead, srl_linkage) {
+ r->r_nsubregions++;
+ }
+ assert(r->r_nsubregions);
+
+ r->r_subregions = calloc(r->r_nsubregions, sizeof (void *));
+ unsigned i = 0;
+ STAILQ_FOREACH(srl, &srlhead, srl_linkage) {
+ r->r_subregions[i++] = srl->srl_s;
+ }
+ qsort_b(r->r_subregions, r->r_nsubregions, sizeof (void *),
+ ^(const void *a, const void *b) {
+ const struct subregion *lhs = *(struct subregion **)a;
+ const struct subregion *rhs = *(struct subregion **)b;
+ if (S_ADDR(lhs) > S_ADDR(rhs))
+ return 1;
+ if (S_ADDR(lhs) < S_ADDR(rhs))
+ return -1;
+ return 0;
+ });
+
+ eliminate_duplicate_subregions(r);
+
+ if (r->r_info.external_pager) {
+ /*
+ * Only very specific segment types get to be filerefs
+ */
+ for (i = 0; i < r->r_nsubregions; i++) {
+ struct subregion *s = r->r_subregions[i];
+ /*
+ * Anything marked writable is trivially disqualified; we're
+ * going to copy it anyway.
+ */
+ if (s->s_segcmd.initprot & VM_PROT_WRITE)
+ continue;
+
+ /* __TEXT and __LINKEDIT are our real targets */
+ if (!issubregiontype(s, SEG_TEXT) && !issubregiontype(s, SEG_LINKEDIT) && !issubregiontype(s, "__UNICODE")) {
+ if (OPTIONS_DEBUG(opt, 3)) {
+ hsize_str_t hstr;
+ printvr(S_RANGE(s), "skipping read-only %s segment %s\n", S_MACHO_TYPE(s), str_hsize(hstr, S_SIZE(s)));
+ }
+ continue;
+ }
+ if (r->r_insharedregion) {
+ /*
+ * Part of the shared region: things get more complicated.
+ */
+ if (r->r_fileref) {
+ /*
+ * There's a file reference here for the whole region.
+ * For __TEXT subregions, we could, in principle (though
+ * see below) generate references to the individual
+ * dylibs that dyld reports in the region. If the
+ * debugger could then use the __LINKEDIT info in the
+ * file, then we'd be done. But as long as the dump
+ * includes __LINKEDIT sections, we're going to
+ * end up generating a file reference to the combined
+ * __LINKEDIT section in the shared cache anyway, so
+ * we might as well do that for the __TEXT regions as
+ * well.
+ */
+ s->s_libent = r->r_fileref->fr_libent;
+ s->s_isuuidref = true;
+ } else {
+ /*
+ * If we get here, it's likely that the shared cache
+ * name can't be found e.g. update_dyld_shared_cache(1).
+ * For __TEXT subregions, we could generate refs to
+ * the individual dylibs, but note that the mach header
+ * and segment commands in memory are still pointing
+ * into the shared cache so any act of reconstruction
+ * is fiendishly complex. So copy it.
+ */
+ assert(!s->s_isuuidref);
+ }
+ } else {
+ /* Just a regular dylib? */
+ if (s->s_libent)
+ s->s_isuuidref = true;
+ }
+ }
+ }
+ }
+ assert(WALK_CONTINUE == retval);
+
+done:
+ if (!STAILQ_EMPTY(&srlhead)) {
+ struct subregionlist *srl, *trl;
+ STAILQ_FOREACH_SAFE(srl, &srlhead, srl_linkage, trl) {
+ free(srl);
+ }
+ }
+ return retval;
+}
+
+/*
+ * Strip region of all decoration
+ *
+ * Invoked (on every region!) after an error during the initial
+ * 'decoration' phase to discard potentially incomplete information.
+ */
+walk_return_t
+undecorate_memory_region(struct region *r, __unused void *arg)
+{
+ assert(&sparse_ops != r->r_op);
+ return r->r_nsubregions ? clean_subregions(r) : WALK_CONTINUE;
+}
+
+/*
+ * This optimization occurs -after- the vanilla_region_optimizations(),
+ * and -after- we've tagged zfod and first-pass fileref's.
+ */
+walk_return_t
+sparse_region_optimization(struct region *r, __unused void *arg)
+{
+ assert(&sparse_ops != r->r_op);
+
+ if (r->r_inzfodregion) {
+ /*
+ * Pure zfod region: almost certainly a more compact
+ * representation - keep it that way.
+ */
+ if (OPTIONS_DEBUG(opt, 3))
+ printr(r, "retaining zfod region\n");
+ assert(&zfod_ops == r->r_op);
+ return clean_subregions(r);
+ }
+
+ if (r->r_insharedregion && 0 == r->r_nsubregions) {
+ /*
+ * A segment in the shared region needs to be
+ * identified with an LC_SEGMENT that dyld claims,
+ * otherwise (we assert) it's not useful to the dump.
+ */
+ if (OPTIONS_DEBUG(opt, 2)) {
+ hsize_str_t hstr;
+ printr(r, "not referenced in dyld info => "
+ "eliding %s range in shared region\n",
+ str_hsize(hstr, R_SIZE(r)));
+ }
+ if (0 == r->r_info.pages_dirtied && 0 == r->r_info.pages_swapped_out)
+ return WALK_DELETE_REGION;
+ if (OPTIONS_DEBUG(opt, 2)) {
+ hsize_str_t hstr;
+ printr(r, "dirty pages, but not referenced in dyld info => "
+ "NOT eliding %s range in shared region\n",
+ str_hsize(hstr, R_SIZE(r)));
+ }
+ }
+
+ if (r->r_fileref) {
+ /*
+ * Already have a fileref for the whole region: already
+ * a more compact representation - keep it that way.
+ */
+ if (OPTIONS_DEBUG(opt, 3))
+ printr(r, "retaining fileref region\n");
+ assert(&fileref_ops == r->r_op);
+ return clean_subregions(r);
+ }
+
+ if (r->r_nsubregions > 1) {
+ /*
+ * Merge adjacent or identical subregions that have no file reference
+ * (Reducing the number of subregions reduces header overhead and
+ * improves compressability)
+ */
+ unsigned i = 1;
+ while (i < r->r_nsubregions) {
+ struct subregion *s0 = r->r_subregions[i-1];
+ struct subregion *s1 = r->r_subregions[i];
+
+ if (s0->s_isuuidref) {
+ i++;
+ continue; /* => destined to be a fileref */
+ }
+ if (!issamesubregiontype(s0, s1)) {
+ i++;
+ continue; /* merge-able subregions must have same "type" */
+ }
+
+ if (S_ENDADDR(s0) == S_ADDR(s1)) {
+ /* directly adjacent subregions */
+ if (OPTIONS_DEBUG(opt, 2))
+ printr(r, "merging subregions (%llx-%llx + %llx-%llx) -- adjacent\n",
+ S_ADDR(s0), S_ENDADDR(s0), S_ADDR(s1), S_ENDADDR(s1));
+ S_SETSIZE(s0, S_ENDADDR(s1) - S_ADDR(s0));
+ elide_subregion(r, i);
+ continue;
+ }
+
+ const mach_vm_size_t pfn[2] = {
+ S_ADDR(s0) >> pageshift_host,
+ S_ADDR(s1) >> pageshift_host
+ };
+ const mach_vm_size_t endpfn[2] = {
+ (S_ENDADDR(s0) - 1) >> pageshift_host,
+ (S_ENDADDR(s1) - 1) >> pageshift_host
+ };
+
+ if (pfn[0] == pfn[1] && pfn[0] == endpfn[0] && pfn[0] == endpfn[1]) {
+ /* two small subregions share a host page */
+ if (OPTIONS_DEBUG(opt, 2))
+ printr(r, "merging subregions (%llx-%llx + %llx-%llx) -- same page\n",
+ S_ADDR(s0), S_ENDADDR(s0), S_ADDR(s1), S_ENDADDR(s1));
+ S_SETSIZE(s0, S_ENDADDR(s1) - S_ADDR(s0));
+ elide_subregion(r, i);
+ continue;
+ }
+
+ if (pfn[1] == 1 + endpfn[0]) {
+ /* subregions are pagewise-adjacent: bigger chunks to compress */
+ if (OPTIONS_DEBUG(opt, 2))
+ printr(r, "merging subregions (%llx-%llx + %llx-%llx) -- adjacent pages\n",
+ S_ADDR(s0), S_ENDADDR(s0), S_ADDR(s1), S_ENDADDR(s1));
+ S_SETSIZE(s0, S_ENDADDR(s1) - S_ADDR(s0));
+ elide_subregion(r, i);
+ continue;
+ }
+
+ i++; /* this isn't the subregion we're looking for */
+ }
+ }
+
+ if (1 == r->r_nsubregions) {
+ struct subregion *s = r->r_subregions[0];
+ if (!s->s_isuuidref &&
+ R_ADDR(r) == S_ADDR(s) && R_ENDADDR(r) == S_ENDADDR(s)) {
+ if (OPTIONS_DEBUG(opt, 3))
+ printr(r, "subregion (%llx-%llx) reverts to region\n",
+ S_ADDR(s), S_ENDADDR(s));
+ return clean_subregions(r);
+ }
+ }
+
+ if (r->r_nsubregions)
+ r->r_op = &sparse_ops;
+
+ return WALK_CONTINUE;
+}
diff --git a/system_cmds/gcore.tproj/sparse.h b/system_cmds/gcore.tproj/sparse.h
new file mode 100644
index 0000000..cf920ff
--- /dev/null
+++ b/system_cmds/gcore.tproj/sparse.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "region.h"
+#include "dyld.h"
+
+#ifndef _SPARSE_H
+#define _SPARSE_H
+
+struct subregion {
+ struct vm_range s_range;
+ native_segment_command_t s_segcmd;
+ const struct libent *s_libent;
+ bool s_isuuidref;
+};
+
+#define S_RANGE(s) (&(s)->s_range)
+
+static __inline void S_SETADDR(struct subregion *s, mach_vm_offset_t a) {
+ V_SETADDR(S_RANGE(s), a);
+}
+
+static __inline void S_SETSIZE(struct subregion *s, mach_vm_offset_t sz) {
+ V_SETSIZE(S_RANGE(s), sz);
+}
+
+static __inline const mach_vm_offset_t S_ADDR(const struct subregion *s) {
+ return V_ADDR(S_RANGE(s));
+}
+
+static __inline const mach_vm_offset_t S_SIZE(const struct subregion *s) {
+ return V_SIZE(S_RANGE(s));
+}
+
+static __inline const mach_vm_offset_t S_ENDADDR(const struct subregion *s) {
+ return S_ADDR(s) + S_SIZE(s);
+}
+
+static __inline const char *S_MACHO_TYPE(const struct subregion *s) {
+ return s->s_segcmd.segname;
+}
+
+static __inline off_t S_MACHO_FILEOFF(const struct subregion *s) {
+ return s->s_segcmd.fileoff;
+}
+
+static __inline off_t S_MACHO_FILESIZE(const struct subregion *s) {
+ return s->s_segcmd.filesize;
+}
+
+static __inline const struct libent *S_LIBENT(const struct subregion *s) {
+ return s->s_libent;
+}
+
+static __inline const char *S_PATHNAME(const struct subregion *s) {
+ const struct libent *le = S_LIBENT(s);
+ return le ? le->le_pathname : "(unknown)";
+}
+
+static __inline const char *S_FILENAME(const struct subregion *s) {
+ const struct libent *le = S_LIBENT(s);
+ return le ? le->le_filename : S_PATHNAME(s);
+}
+
+extern bool issubregiontype(const struct subregion *, const char *);
+
+extern walk_region_cbfn_t decorate_memory_region;
+extern walk_region_cbfn_t undecorate_memory_region;
+extern walk_region_cbfn_t sparse_region_optimization;
+
+#endif /* _SPARSE_H */
diff --git a/system_cmds/gcore.tproj/threads.c b/system_cmds/gcore.tproj/threads.c
new file mode 100644
index 0000000..b1b3d6f
--- /dev/null
+++ b/system_cmds/gcore.tproj/threads.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "utils.h"
+#include "threads.h"
+#include "corefile.h"
+
+#include <sys/types.h>
+#include <mach/mach.h>
+#include <mach/task.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+
+typedef struct {
+ int flavor;
+ mach_msg_type_number_t count;
+} threadflavor_t;
+
+static threadflavor_t thread_flavor[] = {
+#if defined(__i386__) || defined(__x86_64__)
+ { x86_THREAD_STATE, x86_THREAD_STATE_COUNT },
+ { x86_FLOAT_STATE, x86_FLOAT_STATE_COUNT },
+ { x86_EXCEPTION_STATE, x86_EXCEPTION_STATE_COUNT },
+#elif defined(__arm__)
+ { ARM_THREAD_STATE, ARM_THREAD_STATE_COUNT },
+ { ARM_VFP_STATE, ARM_VFP_STATE_COUNT },
+ { ARM_EXCEPTION_STATE, ARM_EXCEPTION_STATE_COUNT },
+#elif defined(__arm64__)
+ { ARM_THREAD_STATE64, ARM_THREAD_STATE64_COUNT },
+ /* ARM64_TODO: NEON? */
+ { ARM_EXCEPTION_STATE64, ARM_EXCEPTION_STATE64_COUNT },
+#else
+#error architecture not supported
+#endif
+};
+
+static const int nthread_flavors = sizeof (thread_flavor) / sizeof (thread_flavor[0]);
+
+size_t
+sizeof_LC_THREAD()
+{
+ size_t cmdsize = sizeof (struct thread_command);
+ for (int i = 0; i < nthread_flavors; i++) {
+ cmdsize += sizeof (thread_flavor[i]) +
+ thread_flavor[i].count * sizeof (int);
+ }
+ return cmdsize;
+}
+
+void
+dump_thread_state(native_mach_header_t *mh, struct thread_command *tc, mach_port_t thread)
+{
+ tc->cmd = LC_THREAD;
+ tc->cmdsize = (uint32_t) sizeof_LC_THREAD();
+
+ uint32_t *wbuf = (void *)(tc + 1);
+
+ for (int f = 0; f < nthread_flavors; f++) {
+
+ memcpy(wbuf, &thread_flavor[f], sizeof (thread_flavor[f]));
+ wbuf += sizeof (thread_flavor[f]) / sizeof (*wbuf);
+
+ const kern_return_t kr = thread_get_state(thread, thread_flavor[f].flavor, (thread_state_t)wbuf, &thread_flavor[f].count);
+ if (KERN_SUCCESS != kr) {
+ err_mach(kr, NULL, "getting flavor %d of thread",
+ thread_flavor[f].flavor);
+ bzero(wbuf, thread_flavor[f].count * sizeof (int));
+ }
+
+ wbuf += thread_flavor[f].count;
+ }
+ assert((ptrdiff_t)tc->cmdsize == ((caddr_t)wbuf - (caddr_t)tc));
+
+ mach_header_inc_ncmds(mh, 1);
+ mach_header_inc_sizeofcmds(mh, tc->cmdsize);
+}
diff --git a/system_cmds/gcore.tproj/threads.h b/system_cmds/gcore.tproj/threads.h
new file mode 100644
index 0000000..c5605ce
--- /dev/null
+++ b/system_cmds/gcore.tproj/threads.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ */
+
+#include "corefile.h"
+#include <mach/task.h>
+
+#ifndef _THREADS_H
+#define _THREADS_H
+
+extern size_t sizeof_LC_THREAD(void);
+extern void dump_thread_state(native_mach_header_t *, struct thread_command *, mach_port_t);
+
+#endif /* _THREADS_H */
diff --git a/system_cmds/gcore.tproj/utils.c b/system_cmds/gcore.tproj/utils.c
new file mode 100644
index 0000000..f0edcf8
--- /dev/null
+++ b/system_cmds/gcore.tproj/utils.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "utils.h"
+#include "region.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <libutil.h>
+#include <errno.h>
+
+void
+err_mach(kern_return_t kr, const struct region *r, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ if (0 != kr)
+ printf("%s: ", pgm);
+ if (NULL != r)
+ printf("%016llx-%016llx ", R_ADDR(r), R_ENDADDR(r));
+ vprintf(fmt, ap);
+ va_end(ap);
+
+ if (0 != kr) {
+ printf(": failed: %s (0x%x)", mach_error_string(kr), kr);
+ switch (err_get_system(kr)) {
+ case err_get_system(err_mach_ipc):
+ /* 0x10000000 == (4 << 26) */
+ printf(" => fatal\n");
+ exit(127);
+ default:
+ putchar('\n');
+ break;
+ }
+ } else
+ putchar('\n');
+}
+
+static void
+vprintvr(const struct vm_range *vr, const char *restrict fmt, va_list ap)
+{
+ if (NULL != vr)
+ printf("%016llx-%016llx ", V_ADDR(vr), V_ENDADDR(vr));
+ vprintf(fmt, ap);
+}
+
+void
+printvr(const struct vm_range *vr, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vprintvr(vr, fmt, ap);
+ va_end(ap);
+}
+
+void
+printr(const struct region *r, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vprintvr(R_RANGE(r), fmt, ap);
+ va_end(ap);
+}
+
+/*
+ * Print power-of-1024 sizes in human-readable form
+ */
+const char *
+str_hsize(hsize_str_t hstr, uint64_t size)
+{
+ humanize_number(hstr, sizeof (hsize_str_t) - 1, size, "",
+ HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL | HN_IEC_PREFIXES);
+ return hstr;
+}
+
+/*
+ * Print VM protections in human-readable form
+ */
+const char *
+str_prot(const vm_prot_t prot)
+{
+ static const char *pstr[] = {
+ [0] = "---",
+ [VM_PROT_READ] = "r--",
+ [VM_PROT_WRITE] = "-w-",
+ [VM_PROT_READ|VM_PROT_WRITE] = "rw-",
+ [VM_PROT_EXECUTE] = "--x",
+ [VM_PROT_READ|VM_PROT_EXECUTE] = "r-x",
+ [VM_PROT_WRITE|VM_PROT_EXECUTE] = "-wx",
+ [VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE] = "rwx"
+ };
+ return pstr[prot & 7];
+}
+
+// c.f. VMUVMRegion.m
+
+const char *
+str_shared(int sm)
+{
+ static const char *sstr[] = {
+ [0] = " ",
+ [SM_COW] = "sm=cow",
+ [SM_PRIVATE] = "sm=prv",
+ [SM_EMPTY] = "sm=nul",
+ [SM_SHARED] = "sm=ali",
+ [SM_TRUESHARED] = "sm=shm",
+ [SM_PRIVATE_ALIASED] = "sm=zer",
+ [SM_SHARED_ALIASED] = "sm=s/a",
+ [SM_LARGE_PAGE] = "sm=lpg",
+ };
+ if ((unsigned)sm < sizeof (sstr) / sizeof (sstr[0]))
+ return sstr[sm];
+ return "sm=???";
+}
+
+const char *
+str_purgable(int pu, int sm)
+{
+ if (SM_EMPTY == sm)
+ return " ";
+ static const char *pstr[] = {
+ [VM_PURGABLE_NONVOLATILE] = "p=n",
+ [VM_PURGABLE_VOLATILE] = "p=v",
+ [VM_PURGABLE_EMPTY] = "p=e",
+ [VM_PURGABLE_DENY] = " ",
+ };
+ if ((unsigned)pu < sizeof (pstr) / sizeof (pstr[0]))
+ return pstr[pu];
+ return "p=?";
+}
+
+/*
+ * c.f. VMURegionTypeDescriptionForTagShareProtAndPager.
+ */
+const char *
+str_tag(tag_str_t tstr, int tag, int share_mode, vm_prot_t curprot, int external_pager)
+{
+ const char *rtype;
+
+ switch (tag) {
+ case 0:
+ if (external_pager)
+ rtype = "mapped file";
+ else if (SM_TRUESHARED == share_mode)
+ rtype = "shared memory";
+ else
+ rtype = "VM_allocate";
+ break;
+ case VM_MEMORY_MALLOC:
+ if (VM_PROT_NONE == curprot)
+ rtype = "MALLOC guard page";
+ else if (SM_EMPTY == share_mode)
+ rtype = "MALLOC";
+ else
+ rtype = "MALLOC metadata";
+ break;
+ case VM_MEMORY_STACK:
+ if (VM_PROT_NONE == curprot)
+ rtype = "Stack guard";
+ else
+ rtype = "Stack";
+ break;
+#if defined(CONFIG_DEBUG) || defined(CONFIG_GCORE_MAP)
+ case VM_MEMORY_MALLOC_SMALL:
+ rtype = "MALLOC_SMALL";
+ break;
+ case VM_MEMORY_MALLOC_LARGE:
+ rtype = "MALLOC_LARGE";
+ break;
+ case VM_MEMORY_MALLOC_HUGE:
+ rtype = "MALLOC_HUGE";
+ break;
+ case VM_MEMORY_SBRK:
+ rtype = "SBRK";
+ break;
+ case VM_MEMORY_REALLOC:
+ rtype = "MALLOC_REALLOC";
+ break;
+ case VM_MEMORY_MALLOC_TINY:
+ rtype = "MALLOC_TINY";
+ break;
+ case VM_MEMORY_MALLOC_LARGE_REUSABLE:
+ rtype = "MALLOC_LARGE_REUSABLE";
+ break;
+ case VM_MEMORY_MALLOC_LARGE_REUSED:
+ rtype = "MALLOC_LARGE";
+ break;
+ case VM_MEMORY_ANALYSIS_TOOL:
+ rtype = "Performance tool data";
+ break;
+ case VM_MEMORY_MALLOC_NANO:
+ rtype = "MALLOC_NANO";
+ break;
+ case VM_MEMORY_MACH_MSG:
+ rtype = "Mach message";
+ break;
+ case VM_MEMORY_IOKIT:
+ rtype = "IOKit";
+ break;
+ case VM_MEMORY_GUARD:
+ rtype = "Guard";
+ break;
+ case VM_MEMORY_SHARED_PMAP:
+ rtype = "shared pmap";
+ break;
+ case VM_MEMORY_DYLIB:
+ rtype = "dylib";
+ break;
+ case VM_MEMORY_OBJC_DISPATCHERS:
+ rtype = "ObjC dispatching code";
+ break;
+ case VM_MEMORY_UNSHARED_PMAP:
+ rtype = "unshared pmap";
+ break;
+ case VM_MEMORY_APPKIT:
+ rtype = "AppKit";
+ break;
+ case VM_MEMORY_FOUNDATION:
+ rtype = "Foundation";
+ break;
+ case VM_MEMORY_COREGRAPHICS:
+ rtype = "CoreGraphics";
+ break;
+ case VM_MEMORY_CORESERVICES:
+ rtype = "CoreServices";
+ break;
+ case VM_MEMORY_JAVA:
+ rtype = "Java";
+ break;
+ case VM_MEMORY_COREDATA:
+ rtype = "CoreData";
+ break;
+ case VM_MEMORY_COREDATA_OBJECTIDS:
+ rtype = "CoreData Object IDs";
+ break;
+ case VM_MEMORY_ATS:
+ rtype = "ATS (font support)";
+ break;
+ case VM_MEMORY_LAYERKIT:
+ rtype = "CoreAnimation";
+ break;
+ case VM_MEMORY_CGIMAGE:
+ rtype = "CG image";
+ break;
+ case VM_MEMORY_TCMALLOC:
+ rtype = "WebKit Malloc";
+ break;
+ case VM_MEMORY_COREGRAPHICS_DATA:
+ rtype = "CG raster data";
+ break;
+ case VM_MEMORY_COREGRAPHICS_SHARED:
+ rtype = "CG shared images";
+ break;
+ case VM_MEMORY_COREGRAPHICS_FRAMEBUFFERS:
+ rtype = "CG framebuffers";
+ break;
+ case VM_MEMORY_COREGRAPHICS_BACKINGSTORES:
+ rtype = "CG backingstores";
+ break;
+ case VM_MEMORY_DYLD:
+ rtype = "dyld private memory";
+ break;
+ case VM_MEMORY_DYLD_MALLOC:
+ rtype = "dyld malloc memory";
+ break;
+ case VM_MEMORY_SQLITE:
+ rtype = "SQlite page cache";
+ break;
+ case VM_MEMORY_JAVASCRIPT_CORE:
+ rtype = "WebAssembly memory";
+ break;
+ case VM_MEMORY_JAVASCRIPT_JIT_EXECUTABLE_ALLOCATOR:
+ rtype = "JS JIT generated code";
+ break;
+ case VM_MEMORY_JAVASCRIPT_JIT_REGISTER_FILE:
+ rtype = "JS VM register file";
+ break;
+ case VM_MEMORY_GLSL:
+ rtype = "OpenGL GLSL";
+ break;
+ case VM_MEMORY_OPENCL:
+ rtype = "OpenCL";
+ break;
+ case VM_MEMORY_COREIMAGE:
+ rtype = "CoreImage";
+ break;
+ case VM_MEMORY_WEBCORE_PURGEABLE_BUFFERS:
+ rtype = "WebCore purgable data";
+ break;
+ case VM_MEMORY_IMAGEIO:
+ rtype = "Image IO";
+ break;
+ case VM_MEMORY_COREPROFILE:
+ rtype = "CoreProfile";
+ break;
+ case VM_MEMORY_ASSETSD:
+ rtype = "Assets Library";
+ break;
+ case VM_MEMORY_OS_ALLOC_ONCE:
+ rtype = "OS Alloc Once";
+ break;
+ case VM_MEMORY_LIBDISPATCH:
+ rtype = "Dispatch continuations";
+ break;
+ case VM_MEMORY_ACCELERATE:
+ rtype = "Accelerate framework";
+ break;
+ case VM_MEMORY_COREUI:
+ rtype = "CoreUI image data";
+ break;
+ case VM_MEMORY_COREUIFILE:
+ rtype = "CoreUI image file";
+ break;
+ case VM_MEMORY_GENEALOGY:
+ rtype = "Activity Tracing";
+ break;
+ case VM_MEMORY_RAWCAMERA:
+ rtype = "RawCamera";
+ break;
+ case VM_MEMORY_CORPSEINFO:
+ rtype = "Process Corpse Info";
+ break;
+ case VM_MEMORY_ASL:
+ rtype = "Apple System Log";
+ break;
+ case VM_MEMORY_SWIFT_RUNTIME:
+ rtype = "Swift runtime";
+ break;
+ case VM_MEMORY_SWIFT_METADATA:
+ rtype = "Swift metadata";
+ break;
+ case VM_MEMORY_DHMM:
+ rtype = "DHMM";
+ break;
+ case VM_MEMORY_SCENEKIT:
+ rtype = "SceneKit";
+ break;
+ case VM_MEMORY_SKYWALK:
+ rtype = "Skywalk Networking";
+ break;
+#endif
+ default:
+ rtype = NULL;
+ break;
+ }
+ if (rtype)
+ snprintf(tstr, sizeof (tag_str_t), "%s", rtype);
+ else
+ snprintf(tstr, sizeof (tag_str_t), "tag #%d", tag);
+ return tstr;
+}
+
+const char *
+str_tagr(tag_str_t tstr, const struct region *r) {
+ return str_tag(tstr, r->r_info.user_tag, r->r_info.share_mode, r->r_info.protection, r->r_info.external_pager);
+}
+
+/*
+ * Put two strings together separated by a '+' sign
+ * If the string gets too long, then add an ellipsis and
+ * stop concatenating it.
+ */
+char *
+strconcat(const char *s0, const char *s1, size_t maxlen)
+{
+ const char ellipsis[] = "...";
+ const char junction[] = ", ";
+ const size_t s0len = strlen(s0);
+ size_t nmlen = s0len + strlen(s1) + strlen(junction) + 1;
+ if (maxlen > strlen(ellipsis) && nmlen > maxlen) {
+ if (strcmp(s0 + s0len - strlen(ellipsis), ellipsis) == 0)
+ return strdup(s0);
+ s1 = ellipsis;
+ nmlen = s0len + strlen(s1) + strlen(junction) + 1;
+ }
+ char *p = malloc(nmlen);
+ if (p) {
+ strlcpy(p, s0, nmlen);
+ strlcat(p, junction, nmlen);
+ strlcat(p, s1, nmlen);
+ }
+ return p;
+}
+
+unsigned long
+simple_namehash(const char *nm)
+{
+ unsigned long result = 5381;
+ int c;
+ while (0 != (c = *nm++))
+ result = (result * 33) ^ c;
+ return result; /* modified djb2 */
+}
+
+int
+bounded_pwrite(int fd, const void *addr, size_t size, off_t off, bool *nocache, ssize_t *nwrittenp)
+{
+ if (opt->sizebound && off + (off_t)size > opt->sizebound)
+ return EFBIG;
+
+ bool oldnocache = *nocache;
+ if (size >= opt->ncthresh && !oldnocache)
+ *nocache = 0 == fcntl(fd, F_NOCACHE, 1);
+ else if (size < opt->ncthresh && oldnocache)
+ *nocache = 0 != fcntl(fd, F_NOCACHE, 0);
+ if (OPTIONS_DEBUG(opt, 3) && oldnocache ^ *nocache)
+ printf("F_NOCACHE now %sabled on fd %d\n", *nocache ? "en" : "dis", fd);
+
+ const ssize_t nwritten = pwrite(fd, addr, size, off);
+ if (-1 == nwritten)
+ return errno;
+ if (nwrittenp)
+ *nwrittenp = nwritten;
+ return 0;
+}
diff --git a/system_cmds/gcore.tproj/utils.h b/system_cmds/gcore.tproj/utils.h
new file mode 100644
index 0000000..37eda58
--- /dev/null
+++ b/system_cmds/gcore.tproj/utils.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <uuid/uuid.h>
+#include <mach/mach_types.h>
+#include <sysexits.h>
+#include <err.h>
+#include <fcntl.h>
+
+#ifndef _UTILS_H
+#define _UTILS_H
+
+extern const char *pgm;
+
+struct vm_range;
+struct region;
+
+extern void err_mach(kern_return_t, const struct region *, const char *, ...) __printflike(3, 4);
+extern void printvr(const struct vm_range *, const char *, ...) __printflike(2, 3);
+extern void printr(const struct region *, const char *, ...) __printflike(2, 3);
+
+typedef char hsize_str_t[7]; /* e.g. 1008Mib */
+
+extern const char *str_hsize(hsize_str_t hstr, uint64_t);
+extern const char *str_prot(vm_prot_t);
+extern const char *str_shared(int);
+extern const char *str_purgable(int, int);
+
+typedef char tag_str_t[24];
+
+extern const char *str_tag(tag_str_t, int, int, vm_prot_t, int);
+extern const char *str_tagr(tag_str_t, const struct region *);
+
+extern char *strconcat(const char *, const char *, size_t);
+extern unsigned long simple_namehash(const char *);
+extern int bounded_pwrite(int, const void *, size_t, off_t, bool *, ssize_t *);
+
+#endif /* _UTILS_H */
diff --git a/system_cmds/gcore.tproj/vanilla.c b/system_cmds/gcore.tproj/vanilla.c
new file mode 100644
index 0000000..2253bff
--- /dev/null
+++ b/system_cmds/gcore.tproj/vanilla.c
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "vm.h"
+#include "region.h"
+#include "utils.h"
+#include "dyld.h"
+#include "threads.h"
+#include "vanilla.h"
+#include "sparse.h"
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <libproc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <sysexits.h>
+
+#include <mach/mach.h>
+
+/*
+ * (Another optimization to consider is merging adjacent regions with
+ * the same properties.)
+ */
+
+static walk_return_t
+simple_region_optimization(struct region *r, __unused void *arg)
+{
+ assert(0 != R_SIZE(r));
+
+ /*
+ * Elide unreadable regions
+ */
+ if ((r->r_info.max_protection & VM_PROT_READ) != VM_PROT_READ) {
+ if (OPTIONS_DEBUG(opt, 2))
+ printr(r, "eliding unreadable region\n");
+ return WALK_DELETE_REGION;
+ }
+#ifdef CONFIG_SUBMAP
+ /*
+ * Elide submaps (here for debugging purposes?)
+ */
+ if (r->r_info.is_submap) {
+ if (OPTIONS_DEBUG(opt))
+ printr(r, "eliding submap\n");
+ return WALK_DELETE_REGION;
+ }
+#endif
+ /*
+ * Elide guard regions
+ */
+ if (r->r_info.protection == VM_PROT_NONE &&
+ (VM_MEMORY_STACK == r->r_info.user_tag ||
+ VM_MEMORY_MALLOC == r->r_info.user_tag)) {
+ if (OPTIONS_DEBUG(opt, 2)) {
+ hsize_str_t hstr;
+ tag_str_t tstr;
+ printr(r, "elide %s - %s\n", str_hsize(hstr, R_SIZE(r)), str_tagr(tstr, r));
+ }
+ return WALK_DELETE_REGION;
+ }
+
+ /*
+ * Regions full of clean zfod data e.g. VM_MEMORY_MALLOC_LARGE can be recorded as zfod
+ */
+ if (r->r_info.share_mode == SM_PRIVATE &&
+ 0 == r->r_info.external_pager &&
+ 0 == r->r_info.pages_dirtied) {
+ if (OPTIONS_DEBUG(opt, 2)) {
+ hsize_str_t hstr;
+ tag_str_t tstr;
+ printr(r, "convert to zfod %s - %s\n", str_hsize(hstr, R_SIZE(r)), str_tagr(tstr, r));
+ }
+ r->r_inzfodregion = true;
+ r->r_op = &zfod_ops;
+ }
+
+ return WALK_CONTINUE;
+}
+
+/*
+ * (Paranoid validation + debugging assistance.)
+ */
+void
+validate_core_header(const native_mach_header_t *mh, off_t corefilesize)
+{
+ assert(NATIVE_MH_MAGIC == mh->magic);
+ assert(MH_CORE == mh->filetype);
+
+ if (OPTIONS_DEBUG(opt, 2))
+ printf("%s: core file: mh %p ncmds %u sizeofcmds %u\n",
+ __func__, mh, mh->ncmds, mh->sizeofcmds);
+
+ unsigned sizeofcmds = 0;
+ off_t corefilemaxoff = 0;
+ const struct load_command *lc = (const void *)(mh + 1);
+ for (unsigned i = 0; i < mh->ncmds; i++) {
+
+ if ((uintptr_t)lc < (uintptr_t)mh ||
+ (uintptr_t)lc > (uintptr_t)mh + mh->sizeofcmds) {
+ warnx("load command %p outside mach header range [%p, 0x%lx]?",
+ lc, mh, (uintptr_t)mh + mh->sizeofcmds);
+ abort();
+ }
+ if (OPTIONS_DEBUG(opt, 2))
+ printf("lc %p cmd %3u size %3u ", lc, lc->cmd, lc->cmdsize);
+ sizeofcmds += lc->cmdsize;
+
+ switch (lc->cmd) {
+ case NATIVE_LC_SEGMENT: {
+ const native_segment_command_t *sc = (const void *)lc;
+ if (OPTIONS_DEBUG(opt, 2)) {
+ printf("%8s: mem %llx-%llx file %lld-%lld %s/%s nsect %u flags %x\n",
+ "SEGMENT",
+ (mach_vm_offset_t)sc->vmaddr,
+ (mach_vm_offset_t)sc->vmaddr + sc->vmsize,
+ (off_t)sc->fileoff,
+ (off_t)sc->fileoff + (off_t)sc->filesize,
+ str_prot(sc->initprot), str_prot(sc->maxprot),
+ sc->nsects, sc->flags);
+ }
+ if ((off_t)sc->fileoff < mh->sizeofcmds ||
+ (off_t)sc->filesize < 0) {
+ warnx("bad segment command");
+ abort();
+ }
+ const off_t endoff = (off_t)sc->fileoff + (off_t)sc->filesize;
+ if ((off_t)sc->fileoff > corefilesize || endoff > corefilesize) {
+ /*
+ * We may have run out of space to write the data
+ */
+ warnx("segment command points beyond end of file");
+ }
+ corefilemaxoff = MAX(corefilemaxoff, endoff);
+ break;
+ }
+ case proto_LC_COREINFO: {
+ const struct proto_coreinfo_command *cic = (const void *)lc;
+ if (OPTIONS_DEBUG(opt, 2)) {
+ uuid_string_t uustr;
+ uuid_unparse_lower(cic->uuid, uustr);
+ printf("%8s: version %d type %d uuid %s addr %llx dyninfo %llx\n",
+ "COREINFO", cic->version, cic->type, uustr, cic->address, cic->dyninfo);
+ }
+ if (cic->version < 1 ||
+ cic->type != proto_CORETYPE_USER) {
+ warnx("bad coreinfo command");
+ abort();
+ }
+ break;
+ }
+ case proto_LC_FILEREF: {
+ const struct proto_fileref_command *frc = (const void *)lc;
+ const char *nm = frc->filename.offset + (char *)lc;
+ if (OPTIONS_DEBUG(opt, 2)) {
+ printf("%8s: mem %llx-%llx file %lld-%lld %s/%s '%s'\n",
+ "FREF",
+ frc->vmaddr, frc->vmaddr + frc->vmsize,
+ (off_t)frc->fileoff,
+ (off_t)frc->fileoff + (off_t)frc->filesize,
+ str_prot(frc->prot), str_prot(frc->maxprot), nm);
+ }
+ switch (FREF_ID_TYPE(frc->flags)) {
+ case kFREF_ID_UUID:
+ case kFREF_ID_MTIMESPEC_LE:
+ case kFREF_ID_NONE:
+ break;
+ default:
+ warnx("unknown fref id type: flags %x", frc->flags);
+ abort();
+ }
+ if (nm <= (caddr_t)lc ||
+ nm > (caddr_t)lc + lc->cmdsize ||
+ (off_t)frc->fileoff < 0 || (off_t)frc->filesize < 0) {
+ warnx("bad fileref command");
+ abort();
+ }
+ break;
+ }
+ case proto_LC_COREDATA: {
+ const struct proto_coredata_command *cc = (const void *)lc;
+ if (OPTIONS_DEBUG(opt, 2)) {
+ printf("%8s: mem %llx-%llx file %lld-%lld %s/%s flags %x\n",
+ "COREDATA",
+ cc->vmaddr, cc->vmaddr + cc->vmsize,
+ (off_t)cc->fileoff,
+ (off_t)cc->fileoff + (off_t)cc->filesize,
+ str_prot(cc->prot), str_prot(cc->maxprot), cc->flags);
+ }
+ if ((off_t)cc->fileoff < mh->sizeofcmds ||
+ (off_t)cc->filesize < 0) {
+ warnx("bad COREDATA command");
+ abort();
+ }
+ const off_t endoff = (off_t)cc->fileoff + (off_t)cc->filesize;
+ if ((off_t)cc->fileoff > corefilesize || endoff > corefilesize) {
+ /*
+ * We may have run out of space to write the data
+ */
+ warnx("segment command points beyond end of file");
+ }
+ corefilemaxoff = MAX(corefilemaxoff, endoff);
+ break;
+ }
+ case LC_THREAD: {
+ const struct thread_command *tc = (const void *)lc;
+ if (OPTIONS_DEBUG(opt, 2))
+ printf("%8s:\n", "THREAD");
+ uint32_t *wbuf = (void *)(tc + 1);
+ do {
+ const uint32_t flavor = *wbuf++;
+ const uint32_t count = *wbuf++;
+
+ if (OPTIONS_DEBUG(opt, 2)) {
+ printf(" flavor %u count %u\n", flavor, count);
+ if (count) {
+ bool nl = false;
+ for (unsigned k = 0; k < count; k++) {
+ if (0 == (k & 7))
+ printf(" [%3u] ", k);
+ printf("%08x ", *wbuf++);
+ if (7 == (k & 7)) {
+ printf("\n");
+ nl = true;
+ } else
+ nl = false;
+ }
+ if (!nl)
+ printf("\n");
+ }
+ } else
+ wbuf += count;
+
+ if (!VALID_THREAD_STATE_FLAVOR(flavor)) {
+ warnx("bad thread state flavor");
+ abort();
+ }
+ } while ((caddr_t) wbuf < (caddr_t)tc + tc->cmdsize);
+ break;
+ }
+ default:
+ warnx("unknown cmd %u in header", lc->cmd);
+ abort();
+ }
+ if (lc->cmdsize)
+ lc = (const void *)((caddr_t)lc + lc->cmdsize);
+ else
+ break;
+ }
+ if (corefilemaxoff < corefilesize)
+ warnx("unused data after corefile offset %lld", corefilemaxoff);
+ if (sizeofcmds != mh->sizeofcmds) {
+ warnx("inconsistent mach header %u vs. %u", sizeofcmds, mh->sizeofcmds);
+ abort();
+ }
+}
+
+/*
+ * The vanilla Mach-O core file consists of:
+ *
+ * - A Mach-O header of type MH_CORE
+ *
+ * A set of load commands of the following types:
+ *
+ * - LC_SEGMENT{,_64} pointing at memory content in the file,
+ * each chunk consisting of a contiguous region. Regions may be zfod
+ * (no file content present).
+ *
+ * - proto_LC_COREDATA pointing at memory content in the file,
+ * each chunk consisting of a contiguous region. Regions may be zfod
+ * (no file content present) or content may be compressed (experimental)
+ *
+ * - proto_LC_COREINFO (experimental), pointing at dyld (10.12 onwards)
+ *
+ * - proto_LC_FILEREF (experimental) pointing at memory
+ * content to be mapped in from another uuid-tagged file at various offsets
+ *
+ * - LC_THREAD commands with state for each thread
+ *
+ * These load commands are followed by the relevant contents of memory,
+ * pointed to by the various commands.
+ */
+
+int
+coredump_write(
+ const task_t task,
+ const int fd,
+ struct regionhead *rhead,
+ const uuid_t aout_uuid,
+ mach_vm_offset_t aout_load_addr,
+ mach_vm_offset_t dyld_aii_addr)
+{
+ struct size_segment_data ssda;
+ bzero(&ssda, sizeof (ssda));
+
+ if (walk_region_list(rhead, region_size_memory, &ssda) < 0) {
+ warnx(0, "cannot count segments");
+ return EX_OSERR;
+ }
+
+ unsigned thread_count = 0;
+ mach_port_t *threads = NULL;
+ kern_return_t ret = task_threads(task, &threads, &thread_count);
+ if (KERN_SUCCESS != ret || thread_count < 1) {
+ err_mach(ret, NULL, "cannot retrieve threads");
+ thread_count = 0;
+ }
+
+ if (OPTIONS_DEBUG(opt, 3)) {
+ print_memory_region_header();
+ walk_region_list(rhead, region_print_memory, NULL);
+ printf("\nmach header %lu\n", sizeof (native_mach_header_t));
+ printf("threadcount %u threadsize %lu\n", thread_count, thread_count * sizeof_LC_THREAD());
+ printf("fileref %lu %lu %llu\n", ssda.ssd_fileref.count, ssda.ssd_fileref.headersize, ssda.ssd_fileref.memsize);
+ printf("zfod %lu %lu %llu\n", ssda.ssd_zfod.count, ssda.ssd_zfod.headersize, ssda.ssd_zfod.memsize);
+ printf("vanilla %lu %lu %llu\n", ssda.ssd_vanilla.count, ssda.ssd_vanilla.headersize, ssda.ssd_vanilla.memsize);
+ printf("sparse %lu %lu %llu\n", ssda.ssd_sparse.count, ssda.ssd_sparse.headersize, ssda.ssd_sparse.memsize);
+ }
+
+ size_t headersize = sizeof (native_mach_header_t) +
+ thread_count * sizeof_LC_THREAD() +
+ ssda.ssd_fileref.headersize +
+ ssda.ssd_zfod.headersize +
+ ssda.ssd_vanilla.headersize +
+ ssda.ssd_sparse.headersize;
+ if (opt->extended)
+ headersize += sizeof (struct proto_coreinfo_command);
+
+ void *header = calloc(1, headersize);
+ if (NULL == header)
+ errx(EX_OSERR, "out of memory for header");
+
+ native_mach_header_t *mh = make_corefile_mach_header(header);
+ struct load_command *lc = (void *)(mh + 1);
+
+ if (opt->extended) {
+ const struct proto_coreinfo_command *cc =
+ make_coreinfo_command(mh, lc, aout_uuid, aout_load_addr, dyld_aii_addr);
+ lc = (void *)((caddr_t)cc + cc->cmdsize);
+ }
+
+ if (opt->verbose) {
+ const unsigned long fileref_count = ssda.ssd_fileref.count;
+ const unsigned long segment_count = fileref_count +
+ ssda.ssd_zfod.count + ssda.ssd_vanilla.count + ssda.ssd_sparse.count;
+ printf("Writing %lu segments", segment_count);
+ if (0 != fileref_count)
+ printf(" (including %lu file reference%s (%lu bytes))",
+ fileref_count, 1 == fileref_count ? "" : "s",
+ ssda.ssd_fileref.headersize);
+ printf("\n");
+ }
+
+ mach_vm_offset_t pagesize = ((mach_vm_offset_t)1 << pageshift_host);
+ mach_vm_offset_t pagemask = pagesize - 1;
+
+ struct write_segment_data wsda = {
+ .wsd_task = task,
+ .wsd_mh = mh,
+ .wsd_lc = lc,
+ .wsd_fd = fd,
+ .wsd_nocache = false,
+ .wsd_foffset = ((mach_vm_offset_t)headersize + pagemask) & ~pagemask,
+ .wsd_nwritten = 0,
+ };
+
+ int ecode = 0;
+ if (0 != walk_region_list(rhead, region_write_memory, &wsda))
+ ecode = EX_IOERR;
+
+ del_region_list(rhead);
+
+ struct thread_command *tc = (void *)wsda.wsd_lc;
+
+ for (unsigned t = 0; t < thread_count; t++) {
+ dump_thread_state(mh, tc, threads[t]);
+ mach_port_deallocate(mach_task_self(), threads[t]);
+ tc = (void *)((caddr_t)tc + tc->cmdsize);
+ }
+
+ /*
+ * Even if we've run out of space, try our best to
+ * write out the header.
+ */
+ if (0 != bounded_pwrite(fd, header, headersize, 0, &wsda.wsd_nocache, NULL))
+ ecode = EX_IOERR;
+ if (0 == ecode && headersize != sizeof (*mh) + mh->sizeofcmds)
+ ecode = EX_SOFTWARE;
+ if (0 == ecode)
+ wsda.wsd_nwritten += headersize;
+
+ validate_core_header(mh, wsda.wsd_foffset);
+
+ if (ecode)
+ warnx("failed to write core file correctly");
+ else if (opt->verbose) {
+ hsize_str_t hsz;
+ printf("Wrote %s to corefile ", str_hsize(hsz, wsda.wsd_nwritten));
+ printf("(memory image %s", str_hsize(hsz, ssda.ssd_vanilla.memsize));
+ if (ssda.ssd_sparse.memsize)
+ printf("+%s", str_hsize(hsz, ssda.ssd_sparse.memsize));
+ if (ssda.ssd_fileref.memsize)
+ printf(", referenced %s", str_hsize(hsz, ssda.ssd_fileref.memsize));
+ if (ssda.ssd_zfod.memsize)
+ printf(", zfod %s", str_hsize(hsz, ssda.ssd_zfod.memsize));
+ printf(")\n");
+ }
+ free(header);
+ return ecode;
+}
+
+static void
+addfileref(struct region *r, const struct libent *le, const char *nm)
+{
+ r->r_fileref = calloc(1, sizeof (*r->r_fileref));
+ if (r->r_fileref) {
+ if (le) {
+ assert(NULL == nm);
+ r->r_fileref->fr_libent = le;
+ r->r_fileref->fr_pathname = le->le_pathname;
+ } else {
+ assert(NULL == le);
+ r->r_fileref->fr_pathname = strdup(nm);
+ }
+ r->r_fileref->fr_offset = r->r_pageinfo.offset;
+ r->r_op = &fileref_ops;
+ }
+}
+
+/*
+ * Once all the info about the shared cache (filerefs) and the information from
+ * dyld (filerefs and subregions), take one last look for mappings
+ * of filesystem content to convert to additional filerefs.
+ *
+ * By default we are pessimistic: read-only mappings on read-only root.
+ */
+static walk_return_t
+label_mapped_files(struct region *r, void *arg)
+{
+ const struct proc_bsdinfo *pbi = arg;
+
+ if (r->r_fileref || r->r_insharedregion || r->r_incommregion || r->r_inzfodregion)
+ return WALK_CONTINUE;
+ if (r->r_nsubregions)
+ return WALK_CONTINUE;
+ if (!r->r_info.external_pager)
+ return WALK_CONTINUE;
+ if (!opt->allfilerefs) {
+ /* must be mapped without write permission */
+ if (0 != (r->r_info.protection & VM_PROT_WRITE))
+ return WALK_CONTINUE;
+ }
+
+ char pathbuf[MAXPATHLEN+1];
+ pathbuf[0] = '\0';
+ int len = proc_regionfilename(pbi->pbi_pid, R_ADDR(r), pathbuf, sizeof (pathbuf)-1);
+ if (len <= 0 || len > MAXPATHLEN)
+ return WALK_CONTINUE;
+ pathbuf[len] = 0;
+
+#if 0
+ /*
+ * On the desktop, only refer to files beginning with particular
+ * prefixes to increase the likelihood that we'll be able to
+ * find the content later on.
+ *
+ * XXX Not practical with a writable root, but helpful for testing.
+ */
+ static const char *white[] = {
+ "/System",
+ "/Library",
+ "/usr",
+ };
+ const unsigned nwhite = sizeof (white) / sizeof (white[0]);
+ bool skip = true;
+ for (unsigned i = 0; skip && i < nwhite; i++)
+ skip = 0 != strncmp(white[i], pathbuf, strlen(white[i]));
+ if (skip) {
+ if (OPTIONS_DEBUG(opt, 3))
+ printf("\t(%s not included)\n", pathbuf);
+ return WALK_CONTINUE;
+ }
+ static const char *black[] = {
+ "/System/Library/Caches",
+ "/Library/Caches",
+ "/usr/local",
+ };
+ const unsigned nblack = sizeof (black) / sizeof (black[0]);
+ for (unsigned i = 0; !skip && i < nblack; i++)
+ skip = 0 == strncmp(black[i], pathbuf, strlen(black[i]));
+ if (skip) {
+ if (OPTIONS_DEBUG(opt, 3))
+ printf("\t(%s excluded)\n", pathbuf);
+ return WALK_CONTINUE;
+ }
+#endif
+
+ struct statfs stfs;
+ if (-1 == statfs(pathbuf, &stfs)) {
+ switch (errno) {
+ case EACCES:
+ case EPERM:
+ case ENOENT:
+ break;
+ default:
+ warnc(errno, "statfs: %s", pathbuf);
+ break;
+ }
+ return WALK_CONTINUE;
+ }
+
+ do {
+ if (OPTIONS_DEBUG(opt, 2))
+ printr(r, "found mapped file %s\n", pathbuf);
+ if (!opt->allfilerefs) {
+ if ((stfs.f_flags & MNT_ROOTFS) != MNT_ROOTFS)
+ break; // must be on the root filesystem
+ if ((stfs.f_flags & MNT_RDONLY) != MNT_RDONLY)
+ break; // must be on a read-only filesystem
+ }
+ if (OPTIONS_DEBUG(opt, 2))
+ print_memory_region(r);
+ addfileref(r, NULL, pathbuf);
+ } while (0);
+
+ return WALK_CONTINUE;
+}
+
+int
+coredump(task_t task, int fd, const struct proc_bsdinfo *__unused pbi)
+{
+ /* this is the shared cache id, if any */
+ uuid_t sc_uuid;
+ uuid_clear(sc_uuid);
+
+ dyld_process_info dpi = NULL;
+ if (opt->extended) {
+ dpi = get_task_dyld_info(task);
+ if (dpi) {
+ get_sc_uuid(dpi, sc_uuid);
+ }
+ }
+
+ /* this group is for LC_COREINFO */
+ mach_vm_offset_t dyld_addr = 0; // all_image_infos -or- dyld mach header
+ mach_vm_offset_t aout_load_addr = 0;
+ uuid_t aout_uuid;
+ uuid_clear(aout_uuid);
+
+ /*
+ * Walk the address space
+ */
+ int ecode = 0;
+ struct regionhead *rhead = coredump_prepare(task, sc_uuid);
+ if (NULL == rhead) {
+ ecode = EX_OSERR;
+ goto done;
+ }
+
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("Optimizing dump content\n");
+ walk_region_list(rhead, simple_region_optimization, NULL);
+
+ if (dpi) {
+ /*
+ * Snapshot dyld's info ..
+ */
+ if (!libent_build_nametable(task, dpi))
+ warnx("error parsing dyld data => ignored");
+ else {
+ /*
+ * Find the a.out load address and uuid, and the dyld mach header for the coreinfo
+ */
+ const struct libent *le;
+ if (NULL != (le = libent_lookup_first_bytype(MH_EXECUTE))) {
+ aout_load_addr = le->le_mhaddr;
+ uuid_copy(aout_uuid, le->le_uuid);
+ }
+ if (NULL != (le = libent_lookup_first_bytype(MH_DYLINKER))) {
+ dyld_addr = le->le_mhaddr;
+ }
+
+ /*
+ * Use dyld's view of what's being used in the address
+ * space to shrink the dump.
+ */
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("Decorating dump with dyld-derived data\n");
+ if (0 == walk_region_list(rhead, decorate_memory_region, (void *)dpi)) {
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("Sparse dump optimization(s)\n");
+ walk_region_list(rhead, sparse_region_optimization, NULL);
+ } else {
+ walk_region_list(rhead, undecorate_memory_region, NULL);
+ warnx("error parsing dyld data => ignored");
+ }
+ }
+ free_task_dyld_info(dpi);
+ }
+
+ /*
+ * Hunt for any memory mapped files that we can include by reference
+ * Depending on whether the bsd part of the task is still present
+ * we might be able to determine filenames of other regions mapping
+ * them here - this allows fonts, images, and other read-only content
+ * to be converted into file references, further reducing the size
+ * of the dump.
+ *
+ * NOTE: Even though the corpse snapshots the VM, the filesystem is
+ * not correspondingly snapshotted and thus may mutate while the dump
+ * proceeds - so be pessimistic about inclusion.
+ */
+ if (opt->extended && NULL != pbi) {
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("Mapped file optimization\n");
+ walk_region_list(rhead, label_mapped_files, (void *)pbi);
+ }
+
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("Optimization(s) done\n");
+
+done:
+ if (0 == ecode)
+ ecode = coredump_write(task, fd, rhead, aout_uuid, aout_load_addr, dyld_addr);
+ return ecode;
+}
+
+struct find_shared_cache_args {
+ task_t fsc_task;
+ vm_object_id_t fsc_object_id;
+ vm32_object_id_t fsc_region_object_id;
+ uuid_t fsc_uuid;
+ const struct libent *fsc_le;
+ int fsc_fd;
+};
+
+/*
+ * This is "find the objid of the first shared cache" in the shared region.
+ */
+static walk_return_t
+find_shared_cache(struct region *r, void *arg)
+{
+ struct find_shared_cache_args *fsc = arg;
+
+ if (!r->r_insharedregion)
+ return WALK_CONTINUE; /* wrong address range! */
+ if (0 != r->r_info.user_tag)
+ return WALK_CONTINUE; /* must be tag zero */
+ if ((VM_PROT_READ | VM_PROT_EXECUTE) != r->r_info.protection ||
+ r->r_info.protection != r->r_info.max_protection)
+ return WALK_CONTINUE; /* must be r-x / r-x */
+ if (r->r_pageinfo.offset != 0)
+ return WALK_CONTINUE; /* must map beginning of file */
+
+ if (OPTIONS_DEBUG(opt, 1)) {
+ hsize_str_t hstr;
+ printr(r, "examining %s shared cache candidate\n", str_hsize(hstr, R_SIZE(r)));
+ }
+
+ struct copied_dyld_cache_header *ch;
+ mach_msg_type_number_t chlen = sizeof (*ch);
+ kern_return_t ret = mach_vm_read(fsc->fsc_task, R_ADDR(r), sizeof (*ch), (vm_offset_t *)&ch, &chlen);
+
+ if (KERN_SUCCESS != ret) {
+ err_mach(ret, NULL, "mach_vm_read() candidate shared region header");
+ return WALK_CONTINUE;
+ }
+
+ uuid_t scuuid;
+ if (get_uuid_from_shared_cache_mapping(ch, chlen, scuuid) &&
+ uuid_compare(scuuid, fsc->fsc_uuid) == 0) {
+ if (OPTIONS_DEBUG(opt, 1)) {
+ uuid_string_t uustr;
+ uuid_unparse_lower(fsc->fsc_uuid, uustr);
+ printr(r, "found shared cache %s here\n", uustr);
+ }
+ if (!r->r_info.external_pager) {
+ if (OPTIONS_DEBUG(opt, 1))
+ printf("Hmm. Found shared cache magic# + uuid, but not externally paged?\n");
+#if 0
+ return WALK_CONTINUE; /* should be "paged" from a file */
+#endif
+ }
+ // This is the ID associated with the first page of the mapping
+ fsc->fsc_object_id = r->r_pageinfo.object_id;
+ // This is the ID associated with the region
+ fsc->fsc_region_object_id = r->r_info.object_id;
+ }
+ mach_vm_deallocate(mach_task_self(), (vm_offset_t)ch, chlen);
+ if (fsc->fsc_object_id) {
+ if (OPTIONS_DEBUG(opt, 3)) {
+ uuid_string_t uu;
+ uuid_unparse_lower(fsc->fsc_uuid, uu);
+ printf("Shared cache objid %llx uuid %s\n",
+ fsc->fsc_object_id, uu);
+ }
+ return WALK_TERMINATE;
+ }
+ return WALK_CONTINUE;
+}
+
+static bool
+compare_region_with_shared_cache(const struct region *r, struct find_shared_cache_args *fsc)
+{
+ struct stat st;
+ if (-1 == fstat(fsc->fsc_fd, &st)) {
+ if (OPTIONS_DEBUG(opt, 1))
+ printr(r, "cannot fstat %s - %s\n",
+ fsc->fsc_le->le_filename, strerror(errno));
+ return false;
+ }
+ void *file = mmap(NULL, R_SIZEOF(r), PROT_READ, MAP_PRIVATE, fsc->fsc_fd, r->r_pageinfo.offset);
+ if ((void *)-1L == file) {
+ if (OPTIONS_DEBUG(opt, 1))
+ printr(r, "mmap %s - %s\n", fsc->fsc_le->le_filename, strerror(errno));
+ return false;
+ }
+ madvise(file, R_SIZEOF(r), MADV_SEQUENTIAL);
+
+ vm_offset_t data = 0;
+ mach_msg_type_number_t data_count;
+ const kern_return_t kr = mach_vm_read(fsc->fsc_task, R_ADDR(r), R_SIZE(r), &data, &data_count);
+
+ if (KERN_SUCCESS != kr || data_count < R_SIZE(r)) {
+ err_mach(kr, r, "mach_vm_read()");
+ munmap(file, R_SIZEOF(r));
+ return false;
+ }
+
+ mach_vm_size_t cmpsize = data_count;
+
+#ifdef RDAR_23744374
+ /*
+ * Now we have the corresponding regions mapped, we should be
+ * able to compare them. There's just one last twist that relates
+ * to heterogenous pagesize systems: rdar://23744374
+ */
+ if (st.st_size < (off_t)(r->r_pageinfo.offset + cmpsize) &&
+ pageshift_host < pageshift_app) {
+ /*
+ * Looks like we're about to map close to the end of the object.
+ * Check what's really mapped there and reduce the size accordingly.
+ */
+ if (!is_actual_size(fsc->fsc_task, r, &cmpsize)) {
+ if (OPTIONS_DEBUG(opt, 3))
+ printr(r, "narrowing the comparison (%llu "
+ "-> %llu)\n", R_SIZE(r), cmpsize);
+ }
+ }
+#endif
+
+ mach_vm_behavior_set(mach_task_self(), data, data_count, VM_BEHAVIOR_SEQUENTIAL);
+
+ const bool thesame = memcmp(file, (void *)data, (size_t)cmpsize) == 0;
+#if 0
+ if (!thesame) {
+ int diffcount = 0;
+ int samecount = 0;
+ const char *f = file;
+ const char *d = (void *)data;
+ for (mach_vm_size_t off = 0; off < cmpsize; off += 4096) {
+ if (memcmp(f, d, 4096) != 0) {
+ diffcount++;
+ } else samecount++;
+ f += 4096;
+ d += 4096;
+ }
+ if (diffcount)
+ printr(r, "%d of %d pages different\n", diffcount, diffcount + samecount);
+ }
+#endif
+ mach_vm_deallocate(mach_task_self(), data, data_count);
+ munmap(file, R_SIZEOF(r));
+
+ if (!thesame && OPTIONS_DEBUG(opt, 3))
+ printr(r, "mapped file (%s) region is modified\n", fsc->fsc_le->le_filename);
+ return thesame;
+}
+
+static walk_return_t
+label_shared_cache(struct region *r, void *arg)
+{
+ struct find_shared_cache_args *fsc = arg;
+
+ if (!r->r_insharedregion)
+ return WALK_CONTINUE;
+ if (!r->r_info.external_pager)
+ return WALK_CONTINUE;
+ if (r->r_pageinfo.object_id != fsc->fsc_object_id) {
+ /* wrong object, or first page already modified */
+ return WALK_CONTINUE;
+ }
+ if (((r->r_info.protection | r->r_info.max_protection) & VM_PROT_WRITE) != 0) {
+ /* potentially writable, but was it written? */
+ if (0 != r->r_info.pages_dirtied)
+ return WALK_CONTINUE;
+ if (0 != r->r_info.pages_swapped_out)
+ return WALK_CONTINUE;
+ if (0 != r->r_info.pages_resident && !r->r_info.external_pager)
+ return WALK_CONTINUE;
+ if (OPTIONS_DEBUG(opt, 1))
+ printr(r, "verifying shared cache content against memory image\n");
+ if (!compare_region_with_shared_cache(r, fsc)) {
+ /* bits don't match */
+ if (OPTIONS_DEBUG(opt, 1))
+ printr(r, "hmm .. mismatch: using memory image\n");
+ return WALK_CONTINUE;
+ }
+ }
+
+ /*
+ * This mapped file segment will be represented as a reference
+ * to the file, rather than as a copy of the mapped file.
+ */
+ addfileref(r, libent_lookup_byuuid(fsc->fsc_uuid), NULL);
+ return WALK_CONTINUE;
+}
+
+struct regionhead *
+coredump_prepare(task_t task, uuid_t sc_uuid)
+{
+ struct regionhead *rhead = build_region_list(task);
+
+ if (OPTIONS_DEBUG(opt, 2)) {
+ printf("Region list built\n");
+ print_memory_region_header();
+ walk_region_list(rhead, region_print_memory, NULL);
+ }
+
+ if (uuid_is_null(sc_uuid))
+ return rhead;
+
+ /*
+ * Name the shared cache, if we can
+ */
+ char *nm = shared_cache_filename(sc_uuid);
+ const struct libent *le;
+
+ if (NULL != nm)
+ le = libent_insert(nm, sc_uuid, 0, NULL, NULL, 0);
+ else {
+ libent_insert("(anonymous shared cache)", sc_uuid, 0, NULL, NULL, 0);
+ if (opt->verbose){
+ printf("Warning: cannot name the shared cache ");
+ if (OPTIONS_DEBUG(opt, 1)) {
+ uuid_string_t uustr;
+ uuid_unparse_lower(sc_uuid, uustr);
+ printf("(%s) ", uustr);
+ }
+ printf("- dump may be large!\n");
+ }
+ return rhead;
+ }
+
+ if (opt->extended) {
+ /*
+ * See if we can replace entire regions with references to the shared cache
+ * by looking at the VM meta-data about those regions.
+ */
+ if (OPTIONS_DEBUG(opt, 1)) {
+ uuid_string_t uustr;
+ uuid_unparse_lower(sc_uuid, uustr);
+ printf("Searching for shared cache with uuid %s\n", uustr);
+ }
+
+ /*
+ * Identify the regions mapping the shared cache by comparing the UUID via
+ * dyld with the UUID of likely-looking mappings in the right address range
+ */
+ struct find_shared_cache_args fsca;
+ bzero(&fsca, sizeof (fsca));
+ fsca.fsc_task = task;
+ uuid_copy(fsca.fsc_uuid, sc_uuid);
+ fsca.fsc_fd = -1;
+
+ walk_region_list(rhead, find_shared_cache, &fsca);
+
+ if (0 == fsca.fsc_object_id) {
+ printf("Cannot identify the shared cache region(s) => ignored\n");
+ } else {
+ if (opt->verbose)
+ printf("Referenced %s\n", nm);
+ fsca.fsc_le = le;
+ fsca.fsc_fd = open(fsca.fsc_le->le_pathname, O_RDONLY);
+ if (-1 == fsca.fsc_fd)
+ errc(EX_SOFTWARE, errno, "open %s", fsca.fsc_le->le_pathname);
+ else {
+ walk_region_list(rhead, label_shared_cache, &fsca);
+ close(fsca.fsc_fd);
+ }
+ free(nm);
+ }
+ }
+
+ return rhead;
+}
diff --git a/system_cmds/gcore.tproj/vanilla.h b/system_cmds/gcore.tproj/vanilla.h
new file mode 100644
index 0000000..721c653
--- /dev/null
+++ b/system_cmds/gcore.tproj/vanilla.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "vm.h"
+
+#ifndef _VANILLA_H
+#define _VANILLA_H
+
+struct proc_bsdinfo;
+
+extern void validate_core_header(const native_mach_header_t *, off_t);
+extern int coredump(task_t, int, const struct proc_bsdinfo *);
+extern int coredump_write(task_t, int, struct regionhead *, const uuid_t, mach_vm_offset_t, mach_vm_offset_t);
+extern struct regionhead *coredump_prepare(task_t, uuid_t);
+
+#endif /* _VANILLA_H */
diff --git a/system_cmds/gcore.tproj/vm.c b/system_cmds/gcore.tproj/vm.c
new file mode 100644
index 0000000..22b0efe
--- /dev/null
+++ b/system_cmds/gcore.tproj/vm.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include "options.h"
+#include "vm.h"
+#include "utils.h"
+#include "region.h"
+#include "sparse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <sys/queue.h>
+
+/*
+ * There should be better APIs to describe the shared region
+ * For now, some hackery.
+ */
+
+#include <mach/shared_region.h>
+
+static __inline boolean_t
+in_shared_region(mach_vm_address_t addr)
+{
+ const mach_vm_address_t base = SHARED_REGION_BASE;
+ const mach_vm_address_t size = SHARED_REGION_SIZE;
+ return addr >= base && addr < (base + size);
+}
+
+/*
+ * On both x64 and arm, there's a globallly-shared
+ * read-only page at _COMM_PAGE_START_ADDRESS
+ * which low-level library routines reference.
+ *
+ * On x64, somewhere randomly chosen between _COMM_PAGE_TEXT_ADDRESS
+ * and the top of the user address space, there's the
+ * pre-emption-free-zone read-execute page.
+ */
+
+#include <System/machine/cpu_capabilities.h>
+
+static __inline boolean_t
+in_comm_region(const mach_vm_address_t addr, const vm_region_submap_info_data_64_t *info)
+{
+ return addr >= _COMM_PAGE_START_ADDRESS &&
+ SM_TRUESHARED == info->share_mode &&
+ VM_INHERIT_SHARE == info->inheritance &&
+ !info->external_pager && (info->max_protection & VM_PROT_WRITE) == 0;
+}
+
+static __inline boolean_t
+in_zfod_region(const vm_region_submap_info_data_64_t *info)
+{
+ return info->share_mode == SM_EMPTY && !info->is_submap &&
+ 0 == info->object_id && !info->external_pager &&
+ 0 == info->pages_dirtied + info->pages_resident + info->pages_swapped_out;
+}
+
+static struct region *
+new_region(mach_vm_offset_t vmaddr, mach_vm_size_t vmsize, const vm_region_submap_info_data_64_t *infop)
+{
+ struct region *r = calloc(1, sizeof (*r));
+ assert(vmaddr != 0 && vmsize != 0);
+ R_SETADDR(r, vmaddr);
+ R_SETSIZE(r, vmsize);
+ r->r_info = *infop;
+ r->r_purgable = VM_PURGABLE_DENY;
+ r->r_insharedregion = in_shared_region(vmaddr);
+ r->r_incommregion = in_comm_region(vmaddr, &r->r_info);
+ r->r_inzfodregion = in_zfod_region(&r->r_info);
+
+ if (r->r_inzfodregion)
+ r->r_op = &zfod_ops;
+ else
+ r->r_op = &vanilla_ops;
+ return r;
+}
+
+void
+del_fileref_region(struct region *r)
+{
+ assert(&fileref_ops == r->r_op);
+ /* r->r_fileref->fr_libent is a reference into the name table */
+ poison(r->r_fileref, 0xdeadbee9, sizeof (*r->r_fileref));
+ free(r->r_fileref);
+ poison(r, 0xdeadbeeb, sizeof (*r));
+ free(r);
+}
+
+void
+del_zfod_region(struct region *r)
+{
+ assert(&zfod_ops == r->r_op);
+ assert(r->r_inzfodregion && 0 == r->r_nsubregions);
+ assert(NULL == r->r_fileref);
+ poison(r, 0xdeadbeed, sizeof (*r));
+ free(r);
+}
+
+void
+del_vanilla_region(struct region *r)
+{
+ assert(&vanilla_ops == r->r_op);
+ assert(!r->r_inzfodregion && 0 == r->r_nsubregions);
+ assert(NULL == r->r_fileref);
+ poison(r, 0xdeadbeef, sizeof (*r));
+ free(r);
+}
+
+/*
+ * "does any part of this address range match the tag?"
+ */
+int
+is_tagged(task_t task, mach_vm_offset_t addr, mach_vm_offset_t size, unsigned tag)
+{
+ mach_vm_offset_t vm_addr = addr;
+ mach_vm_offset_t vm_size = 0;
+ natural_t depth = 0;
+ size_t pgsize = (1u << pageshift_host);
+
+ do {
+ mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
+ vm_region_submap_info_data_64_t info;
+
+ kern_return_t ret = mach_vm_region_recurse(task, &vm_addr, &vm_size, &depth, (vm_region_recurse_info_t)&info, &count);
+
+ if (KERN_FAILURE == ret) {
+ err_mach(ret, NULL, "error inspecting task at %llx", vm_addr);
+ return -1;
+ } else if (KERN_INVALID_ADDRESS == ret) {
+ err_mach(ret, NULL, "invalid address at %llx", vm_addr);
+ return -1;
+ } else if (KERN_SUCCESS != ret) {
+ err_mach(ret, NULL, "error inspecting task at %llx", vm_addr);
+ return -1;
+ }
+ if (info.is_submap) {
+ depth++;
+ continue;
+ }
+ if (info.user_tag == tag)
+ return 1;
+ if (vm_addr + vm_size > addr + size)
+ return 0;
+ vm_addr += pgsize;
+ } while (1);
+}
+
+STAILQ_HEAD(regionhead, region);
+
+/*
+ * XXX Need something like mach_vm_shared_region_recurse()
+ * to properly identify the shared region address ranges as
+ * we go.
+ */
+
+static int
+walk_regions(task_t task, struct regionhead *rhead)
+{
+ mach_vm_offset_t vm_addr = MACH_VM_MIN_ADDRESS;
+ natural_t depth = 0;
+
+ if (OPTIONS_DEBUG(opt, 3)) {
+ printf("Building raw region list\n");
+ print_memory_region_header();
+ }
+ while (1) {
+ vm_region_submap_info_data_64_t info;
+ mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
+ mach_vm_size_t vm_size;
+
+ kern_return_t ret = mach_vm_region_recurse(task, &vm_addr, &vm_size, &depth, (vm_region_recurse_info_t)&info, &count);
+
+ if (KERN_FAILURE == ret) {
+ err_mach(ret, NULL, "error inspecting task at %llx", vm_addr);
+ goto bad;
+ } else if (KERN_INVALID_ADDRESS == ret) {
+ break; /* loop termination */
+ } else if (KERN_SUCCESS != ret) {
+ err_mach(ret, NULL, "error inspecting task at %llx", vm_addr);
+ goto bad;
+ }
+
+ if (OPTIONS_DEBUG(opt, 3)) {
+ struct region *d = new_region(vm_addr, vm_size, &info);
+ ROP_PRINT(d);
+ ROP_DELETE(d);
+ }
+
+ if (info.is_submap) {
+#ifdef CONFIG_SUBMAP
+ /* We also want to see submaps -- for debugging purposes. */
+ struct region *r = new_region(vm_addr, vm_size, &info);
+ r->r_depth = depth;
+ STAILQ_INSERT_TAIL(rhead, r, r_linkage);
+#endif
+ depth++;
+ continue;
+ }
+
+ if (VM_MEMORY_IOKIT == info.user_tag) {
+ vm_addr += vm_size;
+ continue; // ignore immediately: IO memory has side-effects
+ }
+
+ struct region *r = new_region(vm_addr, vm_size, &info);
+#ifdef CONFIG_SUBMAP
+ r->r_depth = depth;
+#endif
+ /* grab the page info of the first page in the mapping */
+
+ mach_msg_type_number_t pageinfoCount = VM_PAGE_INFO_BASIC_COUNT;
+ ret = mach_vm_page_info(task, R_ADDR(r), VM_PAGE_INFO_BASIC, (vm_page_info_t)&r->r_pageinfo, &pageinfoCount);
+ if (KERN_SUCCESS != ret)
+ err_mach(ret, r, "getting pageinfo at %llx", R_ADDR(r));
+
+ /* record the purgability */
+
+ ret = mach_vm_purgable_control(task, vm_addr, VM_PURGABLE_GET_STATE, &r->r_purgable);
+ if (KERN_SUCCESS != ret)
+ r->r_purgable = VM_PURGABLE_DENY;
+
+ STAILQ_INSERT_TAIL(rhead, r, r_linkage);
+
+ vm_addr += vm_size;
+ }
+
+ return 0;
+bad:
+ return EX_OSERR;
+}
+
+void
+del_region_list(struct regionhead *rhead)
+{
+ struct region *r, *t;
+
+ STAILQ_FOREACH_SAFE(r, rhead, r_linkage, t) {
+ STAILQ_REMOVE(rhead, r, region, r_linkage);
+ ROP_DELETE(r);
+ }
+ free(rhead);
+}
+
+struct regionhead *
+build_region_list(task_t task)
+{
+ struct regionhead *rhead = malloc(sizeof (*rhead));
+ STAILQ_INIT(rhead);
+ if (0 != walk_regions(task, rhead)) {
+ del_region_list(rhead);
+ return NULL;
+ }
+ return rhead;
+}
+
+int
+walk_region_list(struct regionhead *rhead, walk_region_cbfn_t cbfn, void *arg)
+{
+ struct region *r, *t;
+
+ STAILQ_FOREACH_SAFE(r, rhead, r_linkage, t) {
+ switch (cbfn(r, arg)) {
+ case WALK_CONTINUE:
+ break;
+ case WALK_DELETE_REGION:
+ STAILQ_REMOVE(rhead, r, region, r_linkage);
+ ROP_DELETE(r);
+ break;
+ case WALK_TERMINATE:
+ goto done;
+ case WALK_ERROR:
+ return -1;
+ }
+ }
+done:
+ return 0;
+}
+
+int pageshift_host;
+int pageshift_app;
+
+void
+setpageshift(void)
+{
+ if (0 == pageshift_host) {
+ vm_size_t hps = 0;
+ kern_return_t ret = host_page_size(MACH_PORT_NULL, &hps);
+ if (KERN_SUCCESS != ret || hps == 0)
+ err_mach(ret, NULL, "host page size");
+ int pshift = 0;
+ while (((vm_offset_t)1 << pshift) != hps)
+ pshift++;
+ pageshift_host = pshift;
+ }
+ if (OPTIONS_DEBUG(opt, 3))
+ printf("host page size: %lu\n", 1ul << pageshift_host);
+
+ if (0 == pageshift_app) {
+ size_t psz = getpagesize();
+ int pshift = 0;
+ while ((1ul << pshift) != psz)
+ pshift++;
+ pageshift_app = pshift;
+ }
+ if (OPTIONS_DEBUG(opt, 3) && pageshift_app != pageshift_host)
+ printf("app page size: %lu\n", 1ul << pageshift_app);
+}
+
+void
+print_memory_region_header(void)
+{
+ printf("%-33s %c %-7s %-7s %8s %16s ",
+ "Address Range", 'S', "Size", "Cur/Max", "Obj32", "FirstPgObjectID");
+ printf("%9s %-3s %-11s %5s ",
+ "Offset", "Tag", "Mode", "Refc");
+#ifdef CONFIG_SUBMAP
+ printf("%5s ", "Depth");
+#endif
+ printf("%5s %5s %5s %3s ",
+ "Res", "SNP", "Dirty", "Pgr");
+ printf("\n");
+}
+
+static __inline char
+region_type(const struct region *r)
+{
+ if (r->r_fileref)
+ return 'f';
+ if (r->r_inzfodregion)
+ return 'z';
+ if (r->r_incommregion)
+ return 'c';
+ if (r->r_insharedregion)
+ return 's';
+ return ' ';
+}
+
+void
+print_memory_region(const struct region *r)
+{
+ hsize_str_t hstr;
+ tag_str_t tstr;
+
+ printf("%016llx-%016llx %c %-7s %s/%s %8x %16llx ",
+ R_ADDR(r), R_ENDADDR(r), region_type(r),
+ str_hsize(hstr, R_SIZE(r)),
+ str_prot(r->r_info.protection),
+ str_prot(r->r_info.max_protection),
+ r->r_info.object_id, r->r_pageinfo.object_id
+ );
+
+ printf("%9lld %3d %-11s %5u ",
+ r->r_info.external_pager ?
+ r->r_pageinfo.offset : r->r_info.offset,
+ r->r_info.user_tag,
+ str_shared(r->r_info.share_mode),
+ r->r_info.ref_count
+ );
+#ifdef CONFIG_SUBMAP
+ printf("%5u ", r->r_depth);
+#endif
+
+ if (!r->r_info.is_submap) {
+ printf("%5u %5u %5u %3s ",
+ r->r_info.pages_resident,
+ r->r_info.pages_shared_now_private,
+ r->r_info.pages_dirtied,
+ r->r_info.external_pager ? "ext" : "");
+ if (r->r_fileref)
+ printf("\n %s at %lld ",
+ r->r_fileref->fr_pathname,
+ r->r_fileref->fr_offset);
+ else
+ printf("%s", str_tagr(tstr, r));
+ printf("\n");
+ if (r->r_nsubregions) {
+ printf(" %-33s %7s %12s\t%s\n",
+ "Address Range", "Size", "Type(s)", "Filename(s)");
+ for (unsigned i = 0; i < r->r_nsubregions; i++) {
+ struct subregion *s = r->r_subregions[i];
+ printf(" %016llx-%016llx %7s %12s\t%s\n",
+ S_ADDR(s), S_ENDADDR(s),
+ str_hsize(hstr, S_SIZE(s)),
+ S_MACHO_TYPE(s),
+ S_FILENAME(s));
+ }
+ }
+ } else {
+ printf("%5s %5s %5s %3s %s\n", "", "", "", "", str_tagr(tstr, r));
+ }
+}
+
+walk_return_t
+region_print_memory(struct region *r, __unused void *arg)
+{
+ ROP_PRINT(r);
+ return WALK_CONTINUE;
+}
+
+void
+print_one_memory_region(const struct region *r)
+{
+ print_memory_region_header();
+ ROP_PRINT(r);
+}
+
+#ifdef RDAR_23744374
+/*
+ * The reported size of a mapping to a file object gleaned from
+ * mach_vm_region_recurse() can exceed the underlying size of the file.
+ * If we attempt to write out the full reported size, we find that we
+ * error (EFAULT) or if we compress it, we die with the SIGBUS.
+ *
+ * See rdar://23744374
+ *
+ * Figure out what the "non-faulting" size of the object is to
+ * *host* page size resolution.
+ */
+bool
+is_actual_size(const task_t task, const struct region *r, mach_vm_size_t *hostvmsize)
+{
+ if (!r->r_info.external_pager ||
+ (r->r_info.max_protection & VM_PROT_READ) == VM_PROT_NONE)
+ return true;
+
+ const size_t pagesize_host = 1ul << pageshift_host;
+ const unsigned filepages = r->r_info.pages_resident +
+ r->r_info.pages_swapped_out;
+
+ if (pagesize_host * filepages == R_SIZE(r))
+ return true;
+
+ /*
+ * Verify that the last couple of host-pagesize pages
+ * of a file backed mapping are actually pageable in the
+ * underlying object by walking backwards from the end
+ * of the application-pagesize mapping.
+ */
+ *hostvmsize = R_SIZE(r);
+
+ const long npagemax = 1ul << (pageshift_app - pageshift_host);
+ for (long npage = 0; npage < npagemax; npage++) {
+
+ const mach_vm_address_t taddress =
+ R_ENDADDR(r) - pagesize_host * (npage + 1);
+ if (taddress < R_ADDR(r) || taddress >= R_ENDADDR(r))
+ break;
+
+ mach_msg_type_number_t pCount = VM_PAGE_INFO_BASIC_COUNT;
+ vm_page_info_basic_data_t pInfo;
+
+ kern_return_t ret = mach_vm_page_info(task, taddress, VM_PAGE_INFO_BASIC, (vm_page_info_t)&pInfo, &pCount);
+ if (KERN_SUCCESS != ret) {
+ err_mach(ret, NULL, "getting pageinfo at %llx", taddress);
+ break; /* bail */
+ }
+
+ /*
+ * If this page has been in memory before, assume it can
+ * be brought back again
+ */
+ if (pInfo.disposition & (VM_PAGE_QUERY_PAGE_PRESENT | VM_PAGE_QUERY_PAGE_REF | VM_PAGE_QUERY_PAGE_DIRTY | VM_PAGE_QUERY_PAGE_PAGED_OUT))
+ continue;
+
+ /*
+ * Force the page to be fetched to see if it faults
+ */
+ mach_vm_size_t tsize = 1ul << pageshift_host;
+ void *tmp = valloc((size_t)tsize);
+ const mach_vm_address_t vtmp = (mach_vm_address_t)tmp;
+
+ switch (ret = mach_vm_read_overwrite(task,
+ taddress, tsize, vtmp, &tsize)) {
+ case KERN_INVALID_ADDRESS:
+ *hostvmsize = taddress - R_ADDR(r);
+ break;
+ case KERN_SUCCESS:
+ break;
+ default:
+ err_mach(ret, NULL, "mach_vm_overwrite()");
+ break;
+ }
+ free(tmp);
+ }
+ return R_SIZE(r) == *hostvmsize;
+}
+#endif
diff --git a/system_cmds/gcore.tproj/vm.h b/system_cmds/gcore.tproj/vm.h
new file mode 100644
index 0000000..b912782
--- /dev/null
+++ b/system_cmds/gcore.tproj/vm.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_port.h>
+#include <mach/task.h>
+#include <mach/mach_vm.h>
+#include <stdbool.h>
+
+#include "corefile.h"
+#include "region.h"
+
+#ifndef _VM_H
+#define _VM_H
+
+extern void setpageshift(void);
+extern int pageshift_host;
+extern int pageshift_app;
+
+struct region;
+struct regionhead;
+
+extern void del_fileref_region(struct region *);
+extern void del_zfod_region(struct region *);
+extern void del_sparse_region(struct region *);
+extern void del_vanilla_region(struct region *);
+
+extern struct regionhead *build_region_list(task_t);
+extern int walk_region_list(struct regionhead *, walk_region_cbfn_t, void *);
+extern void del_region_list(struct regionhead *);
+
+extern void print_memory_region_header(void);
+extern void print_memory_region(const struct region *);
+extern void print_one_memory_region(const struct region *);
+
+extern walk_region_cbfn_t region_print_memory;
+extern walk_region_cbfn_t region_write_memory;
+extern walk_region_cbfn_t region_size_memory;
+
+extern int is_tagged(task_t, mach_vm_offset_t, mach_vm_offset_t, unsigned);
+
+#ifdef RDAR_23744374
+extern bool is_actual_size(const task_t, const struct region *, mach_vm_size_t *);
+#endif
+
+#endif /* _VM_H */
diff --git a/system_cmds/getconf.tproj/confstr.gperf b/system_cmds/getconf.tproj/confstr.gperf
new file mode 100644
index 0000000..4e79502
--- /dev/null
+++ b/system_cmds/getconf.tproj/confstr.gperf
@@ -0,0 +1,73 @@
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/confstr.gperf,v 1.5 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+/*
+ * The Standard seems a bit ambiguous over whether the POSIX_V6_*
+ * are specified with or without a leading underscore, so we just
+ * use both.
+ */
+%}
+struct map { const char *name; int key; int valid; };
+%%
+PATH, _CS_PATH
+POSIX_V6_ILP32_OFF32_CFLAGS, _CS_POSIX_V6_ILP32_OFF32_CFLAGS
+POSIX_V6_ILP32_OFF32_LDFLAGS, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS
+POSIX_V6_ILP32_OFF32_LIBS, _CS_POSIX_V6_ILP32_OFF32_LIBS
+POSIX_V6_ILP32_OFFBIG_CFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS
+POSIX_V6_ILP32_OFFBIG_LDFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS
+POSIX_V6_ILP32_OFFBIG_LIBS, _CS_POSIX_V6_ILP32_OFFBIG_LIBS
+POSIX_V6_LP64_OFF64_CFLAGS, _CS_POSIX_V6_LP64_OFF64_CFLAGS
+POSIX_V6_LP64_OFF64_LDFLAGS, _CS_POSIX_V6_LP64_OFF64_LDFLAGS
+POSIX_V6_LP64_OFF64_LIBS, _CS_POSIX_V6_LP64_OFF64_LIBS
+POSIX_V6_LPBIG_OFFBIG_CFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS
+POSIX_V6_LPBIG_OFFBIG_LDFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS
+POSIX_V6_LPBIG_OFFBIG_LIBS, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS
+POSIX_V6_WIDTH_RESTRICTED_ENVS, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS
+_POSIX_V6_ILP32_OFF32_CFLAGS, _CS_POSIX_V6_ILP32_OFF32_CFLAGS
+_POSIX_V6_ILP32_OFF32_LDFLAGS, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS
+_POSIX_V6_ILP32_OFF32_LIBS, _CS_POSIX_V6_ILP32_OFF32_LIBS
+_POSIX_V6_ILP32_OFFBIG_CFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS
+_POSIX_V6_ILP32_OFFBIG_LDFLAGS, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS
+_POSIX_V6_ILP32_OFFBIG_LIBS, _CS_POSIX_V6_ILP32_OFFBIG_LIBS
+_POSIX_V6_LP64_OFF64_CFLAGS, _CS_POSIX_V6_LP64_OFF64_CFLAGS
+_POSIX_V6_LP64_OFF64_LDFLAGS, _CS_POSIX_V6_LP64_OFF64_LDFLAGS
+_POSIX_V6_LP64_OFF64_LIBS, _CS_POSIX_V6_LP64_OFF64_LIBS
+_POSIX_V6_LPBIG_OFFBIG_CFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS
+_POSIX_V6_LPBIG_OFFBIG_LDFLAGS, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS
+_POSIX_V6_LPBIG_OFFBIG_LIBS, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS
+_POSIX_V6_WIDTH_RESTRICTED_ENVS, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS
+DARWIN_USER_DIR, _CS_DARWIN_USER_DIR
+DARWIN_USER_TEMP_DIR, _CS_DARWIN_USER_TEMP_DIR
+DARWIN_USER_CACHE_DIR, _CS_DARWIN_USER_CACHE_DIR
+%%
+int
+find_confstr(const char *name, int *key)
+{
+ const struct map *rv;
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+}
diff --git a/system_cmds/getconf.tproj/fake-gperf.awk b/system_cmds/getconf.tproj/fake-gperf.awk
new file mode 100644
index 0000000..b3107fe
--- /dev/null
+++ b/system_cmds/getconf.tproj/fake-gperf.awk
@@ -0,0 +1,66 @@
+#!/usr/bin/awk -f
+# $FreeBSD: src/usr.bin/getconf/fake-gperf.awk,v 1.3 2003/08/22 17:32:07 markm Exp $
+BEGIN {
+ state = 0;
+ struct_seen = "";
+}
+/^%{$/ && state == 0 {
+ state = 1;
+ next;
+}
+/^%}$/ && state == 1 {
+ state = 0;
+ next;
+}
+state == 1 { print; next; }
+/^struct/ && state == 0 {
+ print;
+ struct_seen = $2;
+ next;
+}
+/^%%$/ && state == 0 {
+ state = 2;
+ if (struct_seen !~ /^$/) {
+ print "static const struct", struct_seen, "wordlist[] = {";
+ } else {
+ print "static const struct map {";
+ print "\tconst char *name;";
+ print "\tint key;";
+ print "\tint valid;";
+ print "} wordlist[] = {";
+ struct_seen = "map";
+ }
+ next;
+}
+/^%%$/ && state == 2 {
+ state = 3;
+ print "\t{ NULL, 0, 0 }";
+ print "};";
+ print "#define\tNWORDS\t(sizeof(wordlist)/sizeof(wordlist[0]) - 1)";
+ print "static const struct map *";
+ print "in_word_set(const char *word)";
+ print "{";
+ print "\tconst struct", struct_seen, "*mp;";
+ print "";
+ print "\tfor (mp = wordlist; mp < &wordlist[NWORDS]; mp++) {";
+ print "\t\tif (strcmp(word, mp->name) == 0)";
+ print "\t\t\treturn (mp);";
+ print "\t}";
+ print "\treturn (NULL);";
+ print "}";
+ print "";
+ next;
+}
+state == 2 && NF == 2 {
+ name = substr($1, 1, length($1) - 1);
+ printf "#ifdef %s\n", $2;
+ printf "\t{ \"%s\", %s, 1 },\n", name, $2;
+ print "#else";
+ printf "\t{ \"%s\", 0, 0 },\n", name, $2;
+ print "#endif"
+ next;
+}
+state == 3 { print; next; }
+{
+ # eat anything not matched.
+}
diff --git a/system_cmds/getconf.tproj/getconf.1 b/system_cmds/getconf.tproj/getconf.1
new file mode 100644
index 0000000..384f780
--- /dev/null
+++ b/system_cmds/getconf.tproj/getconf.1
@@ -0,0 +1,212 @@
+.\"
+.\" Copyright 2000 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.
+.\"
+.\" $FreeBSD: src/usr.bin/getconf/getconf.1,v 1.14 2005/01/18 13:43:49 ru Exp $
+.\"
+.Dd September 18, 2002
+.Dt GETCONF 1
+.Os
+.Sh NAME
+.Nm getconf
+.Nd retrieve standard configuration variables
+.Sh SYNOPSIS
+.Nm
+.Op Fl v Ar environment
+.Ar path_var
+.Ar file
+.Nm
+.Op Fl v Ar environment
+.Ar system_var
+.Sh DESCRIPTION
+The
+.Nm
+utility prints the value of a
+.Tn POSIX
+or
+.Tn X/Open
+path or system configuration variable to the standard output.
+If the specified variable is undefined, the string
+.Dq Li undefined
+is output.
+.Pp
+The first form of the command, with two mandatory
+arguments, retrieves file- and file system-specific
+configuration variables using
+.Xr pathconf 2 .
+The second form, with a single argument, retrieves system
+configuration variables using
+.Xr confstr 3
+and
+.Xr sysconf 3 ,
+depending on the type of variable.
+As an extension, the second form can also be used to query static limits from
+.In limits.h .
+.Pp
+All
+.Xr sysconf 3
+and
+.Xr pathconf 2
+variables use the same name as the manifest constants defined in
+the relevant standard C-language bindings, including any leading
+underscore or prefix.
+That is to say,
+.Ar system_var
+might be
+.Dv ARG_MAX
+or
+.Dv _POSIX_VERSION ,
+as opposed to the
+.Xr sysconf 3
+names
+.Dv _SC_ARG_MAX
+or
+.Dv _SC_POSIX_VERSION .
+Variables retrieved from
+.Xr confstr 3
+have the leading
+.Ql _CS_
+stripped off; thus,
+.Dv _CS_PATH
+is queried by a
+.Ar system_var
+of
+.Dq Li PATH .
+.Ss Programming Environments
+The
+.Fl v Ar environment
+option specifies a
+.St -p1003.1-2001
+programming environment under which the values are to be queried.
+This option currently does nothing, but may in the future be used
+to select between 32-bit and 64-bit execution environments on platforms
+which support both.
+Specifying an environment which is not supported on the current execution
+platform gives undefined results.
+.Pp
+The standard programming environments are as follows:
+.Bl -tag -width ".Li POSIX_V6_LPBIG_OFFBIG" -offset indent
+.It Li POSIX_V6_ILP32_OFF32
+Exactly 32-bit integer, long, pointer, and file offset.
+.Sy Supported platforms :
+None.
+.It Li POSIX_V6_ILP32_OFFBIG
+Exactly 32-bit integer, long, and pointer; at least 64-bit file offset.
+.Sy Supported platforms :
+.Tn IA32 ,
+.Tn PowerPC .
+.It Li POSIX_V6_LP64_OFF64
+Exactly 32-bit integer; exactly 64-bit long, pointer, and file offset.
+.Sy Supported platforms :
+.Tn Alpha ,
+.Tn SPARC64 .
+.It Li POSIX_V6_LPBIG_OFFBIG
+At least 32-bit integer; at least 64-bit long, pointer, and file offset.
+.Sy Supported platforms :
+None.
+.El
+.Pp
+The command:
+.Pp
+.Dl "getconf POSIX_V6_WIDTH_RESTRICTED_ENVS"
+.Pp
+returns a newline-separated list of environments in which the width
+of certain fundamental types is no greater than the width of the native
+C type
+.Vt long .
+At present, all programming environments supported by
+.Fx
+have this property.
+Several of the
+.Xr confstr 3
+variables provide information on the necessary compiler and linker flags
+to use the standard programming environments described above.
+.Pp
+Many of these values are also available through the
+.Xr sysctl 8
+mechanism.
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The command:
+.Pp
+.Dl "getconf PATH"
+.Pp
+will display the system default setting for the
+.Ev PATH
+environment variable.
+.Pp
+The command:
+.Pp
+.Dl "getconf NAME_MAX /tmp"
+.Pp
+will display the maximum length of a filename in the
+.Pa /tmp
+directory.
+.Pp
+The command:
+.Pp
+.Dl "getconf -v POSIX_V6_LPBIG_OFFBIG LONG_MAX"
+.Pp
+will display the maximum value of the C type
+.Vt long
+in the
+.Li POSIX_V6_LPBIG_OFFBIG
+programming environment,
+if the system supports that environment.
+.Sh DIAGNOSTICS
+Use of a
+.Ar system_var
+or
+.Ar path_var
+which is completely unrecognized is considered an error,
+causing a diagnostic message to be written to standard error.
+One
+which is known but merely undefined does not result in an error
+indication.
+The
+.Nm
+utility recognizes all of the variables defined for
+.St -p1003.1-2001 ,
+including those which are not currently implemented.
+.Sh SEE ALSO
+.Xr pathconf 2 ,
+.Xr confstr 3 ,
+.Xr sysconf 3 ,
+.Xr sysctl 8
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be compliant with
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 5.0 .
+.Sh AUTHORS
+.An Garrett A. Wollman Aq wollman@lcs.mit.edu
diff --git a/system_cmds/getconf.tproj/getconf.c b/system_cmds/getconf.tproj/getconf.c
new file mode 100644
index 0000000..b2a2752
--- /dev/null
+++ b/system_cmds/getconf.tproj/getconf.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2000 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/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/getconf/getconf.c,v 1.10 2006/12/06 12:00:26 maxim Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "getconf.h"
+
+static void do_confstr(const char *name, int key);
+static void do_sysconf(const char *name, int key);
+static void do_pathconf(const char *name, int key, const char *path);
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+"usage: getconf [-v prog_env] system_var\n"
+" getconf [-v prog_env] path_var pathname\n");
+ exit(EX_USAGE);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c, key, valid;
+ const char *name, *vflag, *alt_path;
+ intmax_t limitval;
+
+ vflag = NULL;
+ while ((c = getopt(argc, argv, "v:")) != -1) {
+ switch (c) {
+ case 'v':
+ vflag = optarg;
+ break;
+
+ default:
+ usage();
+ }
+ }
+
+ if ((name = argv[optind]) == NULL)
+ usage();
+
+ if (vflag != NULL) {
+ if ((valid = find_progenv(vflag, &alt_path)) == 0)
+ errx(EX_USAGE, "invalid programming environment %s",
+ vflag);
+ if (valid > 0 && alt_path != NULL) {
+ if (argv[optind + 1] == NULL)
+ execl(alt_path, "getconf", argv[optind],
+ (char *)NULL);
+ else
+ execl(alt_path, "getconf", argv[optind],
+ argv[optind + 1], (char *)NULL);
+
+ err(EX_OSERR, "execl: %s", alt_path);
+ }
+ if (valid < 0)
+ errx(EX_UNAVAILABLE, "environment %s is not available",
+ vflag);
+ }
+
+ if (argv[optind + 1] == NULL) { /* confstr or sysconf */
+ if ((valid = find_limit(name, &limitval)) != 0) {
+ if (valid > 0)
+ printf("%" PRIdMAX "\n", limitval);
+ else
+ printf("undefined\n");
+
+ return 0;
+ }
+ if ((valid = find_confstr(name, &key)) != 0) {
+ if (valid > 0)
+ do_confstr(name, key);
+ else
+ printf("undefined\n");
+ } else {
+ valid = find_sysconf(name, &key);
+ if (valid > 0) {
+ do_sysconf(name, key);
+ } else if (valid < 0) {
+ printf("undefined\n");
+ } else
+ errx(EX_USAGE,
+ "no such configuration parameter `%s'",
+ name);
+ }
+ } else {
+ valid = find_pathconf(name, &key);
+ if (valid != 0) {
+ if (valid > 0)
+ do_pathconf(name, key, argv[optind + 1]);
+ else
+ printf("undefined\n");
+ } else
+ errx(EX_USAGE,
+ "no such path configuration parameter `%s'",
+ name);
+ }
+ return 0;
+}
+
+static void
+do_confstr(const char *name, int key)
+{
+ size_t len;
+ int savederr;
+
+ savederr = errno;
+ errno = 0;
+ len = confstr(key, 0, 0);
+ if (len == 0) {
+ if (errno)
+ err(EX_OSERR, "confstr: %s", name);
+ else
+ printf("undefined\n");
+ } else {
+ char buf[len + 1];
+
+ confstr(key, buf, len);
+ printf("%s\n", buf);
+ }
+ errno = savederr;
+}
+
+static void
+do_sysconf(const char *name, int key)
+{
+ long value;
+
+ errno = 0;
+ value = sysconf(key);
+ if (value == -1 && errno != 0)
+ err(EX_OSERR, "sysconf: %s", name);
+ else if (value == -1)
+ printf("undefined\n");
+ else
+ printf("%ld\n", value);
+}
+
+static void
+do_pathconf(const char *name, int key, const char *path)
+{
+ long value;
+
+ errno = 0;
+ value = pathconf(path, key);
+ if (value == -1 && errno != 0)
+ err(EX_OSERR, "pathconf: %s", name);
+ else if (value == -1)
+ printf("undefined\n");
+ else
+ printf("%ld\n", value);
+}
diff --git a/system_cmds/getconf.tproj/getconf.h b/system_cmds/getconf.tproj/getconf.h
new file mode 100644
index 0000000..3f7e412
--- /dev/null
+++ b/system_cmds/getconf.tproj/getconf.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000 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.
+ *
+ * $FreeBSD: src/usr.bin/getconf/getconf.h,v 1.4 2002/10/27 04:14:08 wollman Exp $
+ */
+
+#ifdef STABLE
+typedef long long intmax_t;
+#define PRIdMAX "lld"
+#else
+#include <inttypes.h>
+#endif
+
+int find_confstr(const char *name, int *key);
+int find_limit(const char *name, intmax_t *value);
+int find_pathconf(const char *name, int *key);
+int find_progenv(const char *name, const char **alt_path);
+int find_sysconf(const char *name, int *key);
diff --git a/system_cmds/getconf.tproj/limits.gperf b/system_cmds/getconf.tproj/limits.gperf
new file mode 100644
index 0000000..e94a8c7
--- /dev/null
+++ b/system_cmds/getconf.tproj/limits.gperf
@@ -0,0 +1,142 @@
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/limits.gperf,v 1.2 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <limits.h>
+#ifdef APPLE_GETCONF_UNDERSCORE
+#include <alloca.h>
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+%}
+struct map { const char *name; intmax_t value; int valid; };
+%%
+_POSIX_AIO_LISTIO_MAX, _POSIX_AIO_LISTIO_MAX
+_POSIX_AIO_MAX, _POSIX_AIO_MAX
+_POSIX_ARG_MAX, _POSIX_ARG_MAX
+_POSIX_CHILD_MAX, _POSIX_CHILD_MAX
+_POSIX_CLOCKRES_MIN, _POSIX_CLOCKRES_MIN
+_POSIX_DELAYTIMER_MAX, _POSIX_DELAYTIMER_MAX
+_POSIX_HOST_NAME_MAX, _POSIX_HOST_NAME_MAX
+_POSIX_LINK_MAX, _POSIX_LINK_MAX
+_POSIX_LOGIN_NAME_MAX, _POSIX_LOGIN_NAME_MAX
+_POSIX_MAX_CANON, _POSIX_MAX_CANON
+_POSIX_MAX_INPUT, _POSIX_MAX_INPUT
+_POSIX_MQ_OPEN_MAX, _POSIX_MQ_OPEN_MAX
+_POSIX_MQ_PRIO_MAX, _POSIX_MQ_PRIO_MAX
+_POSIX_NAME_MAX, _POSIX_NAME_MAX
+_POSIX_NGROUPS_MAX, _POSIX_NGROUPS_MAX
+_POSIX_OPEN_MAX, _POSIX_OPEN_MAX
+_POSIX_PATH_MAX, _POSIX_PATH_MAX
+_POSIX_PIPE_BUF, _POSIX_PIPE_BUF
+_POSIX_RE_DUP_MAX, _POSIX_RE_DUP_MAX
+_POSIX_RTSIG_MAX, _POSIX_RTSIG_MAX
+_POSIX_SEM_NSEMS_MAX, _POSIX_SEM_NSEMS_MAX
+_POSIX_SEM_VALUE_MAX, _POSIX_SEM_VALUE_MAX
+_POSIX_SIGQUEUE_MAX, _POSIX_SIGQUEUE_MAX
+_POSIX_SSIZE_MAX, _POSIX_SSIZE_MAX
+_POSIX_STREAM_MAX, _POSIX_STREAM_MAX
+_POSIX_SS_REPL_MAX, _POSIX_SS_REPL_MAX
+_POSIX_SYMLINK_MAX, _POSIX_SYMLINK_MAX
+_POSIX_SYMLOOP_MAX, _POSIX_SYMLOOP_MAX
+_POSIX_THREAD_DESTRUCTOR_ITERATIONS, _POSIX_THREAD_DESTRUCTOR_ITERATIONS
+_POSIX_THREAD_KEYS_MAX, _POSIX_THREAD_KEYS_MAX
+_POSIX_THREAD_THREADS_MAX, _POSIX_THREAD_THREADS_MAX
+_POSIX_TIMER_MAX, _POSIX_TIMER_MAX
+_POSIX_TRACE_EVENT_NAME_MAX, _POSIX_TRACE_EVENT_NAME_MAX
+_POSIX_TRACE_NAME_MAX, _POSIX_TRACE_NAME_MAX
+_POSIX_TRACE_SYS_MAX, _POSIX_TRACE_SYS_MAX
+_POSIX_TRACE_USER_EVENT_MAX, _POSIX_TRACE_USER_EVENT_MAX
+_POSIX_TTY_NAME_MAX, _POSIX_TTY_NAME_MAX
+_POSIX_TZNAME_MAX, _POSIX_TZNAME_MAX
+_POSIX2_BC_BASE_MAX, _POSIX2_BC_BASE_MAX
+_POSIX2_BC_DIM_MAX, _POSIX2_BC_DIM_MAX
+_POSIX2_BC_SCALE_MAX, _POSIX2_BC_SCALE_MAX
+_POSIX2_BC_STRING_MAX, _POSIX2_BC_STRING_MAX
+_POSIX2_CHARCLASS_NAME_MAX, _POSIX2_CHARCLASS_NAME_MAX
+_POSIX2_COLL_WEIGHTS_MAX, _POSIX2_COLL_WEIGHTS_MAX
+_POSIX2_EXPR_NEST_MAX, _POSIX2_EXPR_NEST_MAX
+_POSIX2_LINE_MAX, _POSIX2_LINE_MAX
+_POSIX2_RE_DUP_MAX, _POSIX2_RE_DUP_MAX
+_XOPEN_IOV_MAX, _XOPEN_IOV_MAX
+_XOPEN_NAME_MAX, _XOPEN_NAME_MAX
+_XOPEN_PATH_MAX, _XOPEN_PATH_MAX
+CHAR_BIT, CHAR_BIT
+CHAR_MAX, CHAR_MAX
+CHAR_MIN, CHAR_MIN
+INT_MAX, INT_MAX
+INT_MIN, INT_MIN
+LLONG_MIN, LLONG_MIN
+LLONG_MAX, LLONG_MAX
+LONG_BIT, LONG_BIT
+LONG_MAX, LONG_MAX
+LONG_MIN, LONG_MIN
+MB_LEN_MAX, MB_LEN_MAX
+SCHAR_MAX, SCHAR_MAX
+SCHAR_MIN, SCHAR_MIN
+SHRT_MAX, SHRT_MAX
+SHRT_MIN, SHRT_MIN
+SSIZE_MAX, SSIZE_MAX
+UCHAR_MAX, UCHAR_MAX
+UINT_MAX, UINT_MAX
+ULLONG_MAX, ULLONG_MAX
+ULONG_MAX, ULONG_MAX
+USHRT_MAX, USHRT_MAX
+WORD_BIT, WORD_BIT
+CHARCLASS_NAME_MAX, CHARCLASS_NAME_MAX
+NL_ARGMAX, NL_ARGMAX
+ML_LANGMAX, NL_LANGMAX
+NL_MSGMAX, NL_MSGMAX
+NL_NMAX, NL_NMAX
+NL_SETMAX, NL_SETMAX
+NL_TEXTMAX, NL_TEXTMAX
+NZERO, NZERO
+%%
+int
+find_limit(const char *name, intmax_t *value)
+{
+ const struct map *rv;
+#ifdef APPLE_GETCONF_UNDERSCORE
+ char *alt;
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *value = rv->value;
+ return 1;
+ }
+ return -1;
+ }
+#ifdef APPLE_GETCONF_UNDERSCORE
+ if(*name == '_')
+ alt = (char *)name + 1;
+ else {
+ if((alt = (char *)alloca(strlen(name) + 2)) == NULL)
+ return 0;
+ *alt = '_';
+ strcpy(alt + 1, name);
+ }
+ rv = in_word_set(alt);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *value = rv->value;
+ return 1;
+ }
+ return -1;
+ }
+#endif /* APPLE_GETCONF_UNDERSCORE */
+ return 0;
+}
diff --git a/system_cmds/getconf.tproj/pathconf.gperf b/system_cmds/getconf.tproj/pathconf.gperf
new file mode 100644
index 0000000..ebb317f
--- /dev/null
+++ b/system_cmds/getconf.tproj/pathconf.gperf
@@ -0,0 +1,88 @@
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/pathconf.gperf,v 1.4 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <unistd.h>
+#ifdef APPLE_GETCONF_UNDERSCORE
+#include <alloca.h>
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+%}
+struct map { const char *name; int key; int valid; };
+%%
+FILESIZEBITS, _PC_FILESIZEBITS
+LINK_MAX, _PC_LINK_MAX
+MAX_CANON, _PC_MAX_CANON
+MAX_INPUT, _PC_MAX_INPUT
+NAME_MAX, _PC_NAME_MAX
+PATH_MAX, _PC_PATH_MAX
+PIPE_BUF, _PC_PIPE_BUF
+POSIX_ALLOC_SIZE_MIN, _PC_ALLOC_SIZE_MIN
+POSIX_REC_INCR_XFER_SIZE, _PC_REC_INCR_XFER_SIZE
+POSIX_REC_MAX_XFER_SIZE, _PC_REC_MAX_XFER_SIZE
+POSIX_REC_MIN_XFER_SIZE, _PC_REC_MIN_XFER_SIZE
+POSIX_REC_XFER_ALIGN, _PC_REC_XFER_ALIGN
+POSIX2_SYMLINKS, _PC_2_SYMLINKS
+SYMLINK_MAX, _PC_SYMLINK_MAX
+TRUSTEDBSD_ACL_EXTENDED, _PC_ACL_EXTENDED
+TRUSTEDBSD_ACL_PATH_MAX, _PC_ACL_PATH_MAX
+TRUSTEDBSD_CAP_PRESENT, _PC_CAP_PRESENT
+TRUSTEDBSD_INF_PRESENT, _PC_INF_PRESENT
+TRUSTEDBSD_MAC_PRESENT, _PC_MAC_PRESENT
+_POSIX_ASYNC_IO, _PC_ASYNC_IO
+_POSIX_CHOWN_RESTRICTED, _PC_CHOWN_RESTRICTED
+_POSIX_NO_TRUNC, _PC_NO_TRUNC
+_POSIX_PATH_MAX, _PC_PATH_MAX
+_POSIX_PRIO_IO, _PC_PRIO_IO
+_POSIX_SYNC_IO, _PC_SYNC_IO
+_POSIX_VDISABLE, _PC_VDISABLE
+%%
+int
+find_pathconf(const char *name, int *key)
+{
+ const struct map *rv;
+#ifdef APPLE_GETCONF_UNDERSCORE
+ char *alt;
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+#ifdef APPLE_GETCONF_UNDERSCORE
+ if(*name == '_')
+ alt = (char *)name + 1;
+ else {
+ if((alt = (char *)alloca(strlen(name) + 2)) == NULL)
+ return 0;
+ *alt = '_';
+ strcpy(alt + 1, name);
+ }
+ rv = in_word_set(alt);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+#endif /* APPLE_GETCONF_UNDERSCORE */
+ return 0;
+}
diff --git a/system_cmds/getconf.tproj/progenv.gperf b/system_cmds/getconf.tproj/progenv.gperf
new file mode 100644
index 0000000..4e3245a
--- /dev/null
+++ b/system_cmds/getconf.tproj/progenv.gperf
@@ -0,0 +1,70 @@
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/progenv.gperf,v 1.2 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+/*
+ * The Standard seems a bit ambiguous over whether the POSIX_V6_*
+ * are specified with or without a leading underscore, so we just
+ * use both.
+ */
+/*
+ * The alt_path member gives the path containing another `getconf'
+ * executable which was compiled using the specified programming
+ * environment. If it is NULL, the current executable is good enough.
+ * If we ever support multiple environments, this table will need to
+ * be updated. (We cheat here and define the supported environments
+ * statically.)
+ */
+#if defined(__alpha__) || defined(__sparc64__)
+#define have_LP64_OFF64 NULL
+#elif defined(__APPLE__)
+#define have_LP64_OFF64 NULL
+#define have_LPBIG_OFFBIG NULL
+#endif
+
+#if defined(__i386__) || defined(__powerpc__) || defined(__x86_64__)
+#define have_ILP32_OFFBIG NULL
+#endif
+
+%}
+struct map { const char *name; const char *alt_path; int valid; };
+%%
+POSIX_V6_ILP32_OFF32, notdef
+POSIX_V6_ILP32_OFFBIG, have_ILP32_OFFBIG
+POSIX_V6_LP64_OFF64, have_LP64_OFF64
+POSIX_V6_LPBIG_OFFBIG, have_LPBIG_OFFBIG
+_POSIX_V6_ILP32_OFF32, notdef
+_POSIX_V6_ILP32_OFFBIG, have_ILP32_OFFBIG
+_POSIX_V6_LP64_OFF64, have_LP64_OFF64
+_POSIX_V6_LPBIG_OFFBIG, have_LPBIG_OFFBIG
+%%
+int
+find_progenv(const char *name, const char **alt_path)
+{
+ const struct map *rv;
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *alt_path = rv->alt_path;
+ return 1;
+ }
+ return -1;
+ }
+ return 0;
+}
diff --git a/system_cmds/getconf.tproj/sysconf.gperf b/system_cmds/getconf.tproj/sysconf.gperf
new file mode 100644
index 0000000..9bc3866
--- /dev/null
+++ b/system_cmds/getconf.tproj/sysconf.gperf
@@ -0,0 +1,187 @@
+%{
+/*
+ * Copyright is disclaimed as to the contents of this file.
+ *
+ * $FreeBSD: src/usr.bin/getconf/sysconf.gperf,v 1.5 2003/08/22 17:32:07 markm Exp $
+ */
+
+#include <sys/types.h>
+
+#include <string.h>
+#include <unistd.h>
+#ifdef APPLE_GETCONF_UNDERSCORE
+#include <alloca.h>
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+#include "getconf.h"
+
+/*
+ * Override gperf's built-in external scope.
+ */
+static const struct map *in_word_set(const char *str);
+
+%}
+struct map { const char *name; int key; int valid; };
+%%
+AIO_LISTIO_MAX, _SC_AIO_LISTIO_MAX
+AIO_MAX, _SC_AIO_MAX
+AIO_PRIO_DELTA_MAX, _SC_AIO_PRIO_DELTA_MAX
+ARG_MAX, _SC_ARG_MAX
+ATEXIT_MAX, _SC_ATEXIT_MAX
+BC_BASE_MAX, _SC_BC_BASE_MAX
+BC_DIM_MAX, _SC_BC_DIM_MAX
+BC_SCALE_MAX, _SC_BC_SCALE_MAX
+BC_STRING_MAX, _SC_BC_STRING_MAX
+CHILD_MAX, _SC_CHILD_MAX
+CLK_TCK, _SC_CLK_TCK
+COLL_WEIGHTS_MAX, _SC_COLL_WEIGHTS_MAX
+DELAYTIMER_MAX, _SC_DELAYTIMER_MAX
+EXPR_NEST_MAX, _SC_EXPR_NEST_MAX
+GETGR_R_SIZE_MAX, _SC_GETGR_R_SIZE_MAX
+GETPW_R_SIZE_MAX, _SC_GETPW_R_SIZE_MAX
+HOST_NAME_MAX, _SC_HOST_NAME_MAX
+IOV_MAX, _SC_IOV_MAX
+LINE_MAX, _SC_LINE_MAX
+LOGIN_NAME_MAX, _SC_LOGIN_NAME_MAX
+MQ_OPEN_MAX, _SC_MQ_OPEN_MAX
+MQ_PRIO_MAX, _SC_MQ_PRIO_MAX
+NGROUPS_MAX, _SC_NGROUPS_MAX
+NPROCESSORS_CONF, _SC_NPROCESSORS_CONF
+NPROCESSORS_ONLN, _SC_NPROCESSORS_ONLN
+OPEN_MAX, _SC_OPEN_MAX
+PAGESIZE, _SC_PAGESIZE
+PAGE_SIZE, _SC_PAGESIZE
+PASS_MAX, _SC_PASS_MAX
+PTHREAD_DESTRUCTOR_ITERATIONS, _SC_THREAD_DESTRUCTOR_ITERATIONS
+PTHREAD_KEYS_MAX, _SC_THREAD_KEYS_MAX
+PTHREAD_STACK_MIN, _SC_THREAD_STACK_MIN
+PTHREAD_THREADS_MAX, _SC_THREAD_THREADS_MAX
+RE_DUP_MAX, _SC_RE_DUP_MAX
+RTSIG_MAX, _SC_RTSIG_MAX
+SEM_NSEMS_MAX, _SC_SEM_NSEMS_MAX
+SEM_VALUE_MAX, _SC_SEM_VALUE_MAX
+SIGQUEUE_MAX, _SC_SIGQUEUE_MAX
+STREAM_MAX, _SC_STREAM_MAX
+SYMLOOP_MAX, _SC_SYMLOOP_MAX
+TIMER_MAX, _SC_TIMER_MAX
+TTY_NAME_MAX, _SC_TTY_NAME_MAX
+TZNAME_MAX, _SC_TZNAME_MAX
+_POSIX2_CHAR_TERM, _SC_2_CHAR_TERM
+_POSIX2_C_BIND, _SC_2_C_BIND
+_POSIX2_C_DEV, _SC_2_C_DEV
+_POSIX2_C_VERSION, _SC_2_C_VERSION
+_POSIX2_FORT_DEV, _SC_2_FORT_DEV
+_POSIX2_FORT_RUN, _SC_2_FORT_RUN
+_POSIX2_LOCALEDEF, _SC_2_LOCALEDEF
+_POSIX2_PBS, _SC_PBS
+_POSIX2_PBS_ACCOUNTING, _SC_PBS_ACCOUNTING
+_POSIX2_PBS_CHECKPOINT, _SC_PBS_CHECKPOINT
+_POSIX2_PBS_LOCATE, _SC_PBS_LOCATE
+_POSIX2_PBS_MESSAGE, _SC_PBS_MESSAGE
+_POSIX2_PBS_TRACK, _SC_PBS_TRACK
+_POSIX2_SW_DEV, _SC_2_SW_DEV
+_POSIX2_UPE, _SC_2_UPE
+_POSIX2_VERSION, _SC_2_VERSION
+_POSIX_ADVISORY_INFO, _SC_ADVISORY_INFO
+_POSIX_ASYNCHRONOUS_IO, _SC_ASYNCHRONOUS_IO
+_POSIX_BARRIERS, _SC_BARRIERS
+_POSIX_CLOCK_SELECTION, _SC_CLOCK_SELECTION
+_POSIX_CPUTIME, _SC_CPUTIME
+_POSIX_FILE_LOCKING, _SC_FILE_LOCKING
+_POSIX_FSYNC, _SC_FSYNC
+_POSIX_IPV6, _SC_IPV6
+_POSIX_JOB_CONTROL, _SC_JOB_CONTROL
+_POSIX_MAPPED_FILES, _SC_MAPPED_FILES
+_POSIX_MEMLOCK, _SC_MEMLOCK
+_POSIX_MEMLOCK_RANGE, _SC_MEMLOCK_RANGE
+_POSIX_MEMORY_PROTECTION, _SC_MEMORY_PROTECTION
+_POSIX_MESSAGE_PASSING, _SC_MESSAGE_PASSING
+_POSIX_MONOTONIC_CLOCK, _SC_MONOTONIC_CLOCK
+_POSIX_PRIORITIZED_IO, _SC_PRIORITIZED_IO
+_POSIX_PRIORITY_SCHEDULING, _SC_PRIORITY_SCHEDULING
+_POSIX_RAW_SOCKETS, _SC_RAW_SOCKETS
+_POSIX_READER_WRITER_LOCKS, _SC_READER_WRITER_LOCKS
+_POSIX_REALTIME_SIGNALS, _SC_REALTIME_SIGNALS
+_POSIX_REGEXP, _SC_REGEXP
+_POSIX_SAVED_IDS, _SC_SAVED_IDS
+_POSIX_SEMAPHORES, _SC_SEMAPHORES
+_POSIX_SHARED_MEMORY_OBJECTS, _SC_SHARED_MEMORY_OBJECTS
+_POSIX_SHELL, _SC_SHELL
+_POSIX_SPAWN, _SC_SPAWN
+_POSIX_SPIN_LOCKS, _SC_SPIN_LOCKS
+_POSIX_SPORADIC_SERVER, _SC_SPORADIC_SERVER
+_POSIX_SS_REPL_MAX, _SC_SS_REPL_MAX
+_POSIX_SYNCHRONIZED_IO, _SC_SYNCHRONIZED_IO
+_POSIX_THREADS, _SC_THREADS
+_POSIX_THREAD_ATTR_STACKADDR, _SC_THREAD_ATTR_STACKADDR
+_POSIX_THREAD_ATTR_STACKSIZE, _SC_THREAD_ATTR_STACKSIZE
+_POSIX_THREAD_CPUTIME, _SC_THREAD_CPUTIME
+_POSIX_THREAD_PRIORITY_SCHEDULING, _SC_THREAD_PRIORITY_SCHEDULING
+_POSIX_THREAD_PRIO_INHERIT, _SC_THREAD_PRIO_INHERIT
+_POSIX_THREAD_PRIO_PROTECT, _SC_THREAD_PRIO_PROTECT
+_POSIX_THREAD_PROCESS_SHARED, _SC_THREAD_PROCESS_SHARED
+_POSIX_THREAD_SAFE_FUNCTIONS, _SC_THREAD_SAFE_FUNCTIONS
+_POSIX_THREAD_SPORADIC_SERVER, _SC_THREAD_SPORADIC_SERVER
+_POSIX_TIMEOUTS, _SC_TIMEOUTS
+_POSIX_TIMERS, _SC_TIMERS
+_POSIX_TRACE, _SC_TRACE
+_POSIX_TRACE_EVENT_FILTER, _SC_TRACE_EVENT_FILTER
+_POSIX_TRACE_EVENT_NAME_MAX, _SC_TRACE_EVENT_NAME_MAX
+_POSIX_TRACE_INHERIT, _SC_TRACE_INHERIT
+_POSIX_TRACE_LOG, _SC_TRACE_LOG
+_POSIX_TRACE_NAME_MAX, _SC_TRACE_NAME_MAX
+_POSIX_TRACE_SYS_MAX, _SC_TRACE_SYS_MAX
+_POSIX_TRACE_USER_EVENT_MAX, _SC_TRACE_USER_EVENT_MAX
+_POSIX_TYPED_MEMORY_OBJECTS, _SC_TYPED_MEMORY_OBJECTS
+_POSIX_V6_ILP32_OFF32, _SC_V6_ILP32_OFF32
+_POSIX_V6_ILP32_OFFBIG, _SC_V6_ILP32_OFFBIG
+_POSIX_V6_LP64_OFF64, _SC_V6_LP64_OFF64
+_POSIX_V6_LPBIG_OFFBIG, _SC_V6_LPBIG_OFFBIG
+_POSIX_VERSION, _SC_VERSION
+_XOPEN_CRYPT, _SC_XOPEN_CRYPT
+_XOPEN_ENH_I18N, _SC_XOPEN_ENH_I18N
+_XOPEN_LEGACY, _SC_XOPEN_LEGACY
+_XOPEN_REALTIME, _SC_XOPEN_REALTIME
+_XOPEN_REALTIME_THREADS, _SC_XOPEN_REALTIME_THREADS
+_XOPEN_SHM, _SC_XOPEN_SHM
+_XOPEN_STREAMS, _SC_XOPEN_STREAMS
+_XOPEN_UNIX, _SC_XOPEN_UNIX
+_XOPEN_VERSION, _SC_XOPEN_VERSION
+_XOPEN_XCU_VERSION, _SC_XCU_VERSION
+%%
+int
+find_sysconf(const char *name, int *key)
+{
+ const struct map *rv;
+#ifdef APPLE_GETCONF_UNDERSCORE
+ char *alt;
+#endif /* APPLE_GETCONF_UNDERSCORE */
+
+ rv = in_word_set(name);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+#ifdef APPLE_GETCONF_UNDERSCORE
+ if(*name == '_')
+ alt = (char *)name + 1;
+ else {
+ if((alt = (char *)alloca(strlen(name) + 2)) == NULL)
+ return 0;
+ *alt = '_';
+ strcpy(alt + 1, name);
+ }
+ rv = in_word_set(alt);
+ if (rv != NULL) {
+ if (rv->valid) {
+ *key = rv->key;
+ return 1;
+ }
+ return -1;
+ }
+#endif /* APPLE_GETCONF_UNDERSCORE */
+ return 0;
+}
diff --git a/system_cmds/getty.tproj/chat.c b/system_cmds/getty.tproj/chat.c
new file mode 100644
index 0000000..d79aae7
--- /dev/null
+++ b/system_cmds/getty.tproj/chat.c
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 1997
+ * David L Nugent <davidn@blaze.net.au>.
+ * All rights reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, is permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice immediately at the beginning of the file, without modification,
+ * 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. This work was done expressly for inclusion into FreeBSD. Other use
+ * is permitted provided this notation is included.
+ * 4. Absolutely no warranty of function or purpose is made by the authors.
+ * 5. Modifications may be freely made to this file providing the above
+ * conditions are met.
+ *
+ * Modem chat module - send/expect style functions for getty
+ * For semi-intelligent modem handling.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char rcsid[] =
+ "$FreeBSD: src/libexec/getty/chat.c,v 1.11 2005/04/06 17:42:24 stefanf Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/utsname.h>
+
+#include <ctype.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "gettytab.h"
+#include "extern.h"
+
+#define PAUSE_CH (unsigned char)'\xff' /* pause kludge */
+
+#define CHATDEBUG_RECEIVE 0x01
+#define CHATDEBUG_SEND 0x02
+#define CHATDEBUG_EXPECT 0x04
+#define CHATDEBUG_MISC 0x08
+
+#define CHATDEBUG_DEFAULT 0
+#define CHAT_DEFAULT_TIMEOUT 10
+
+
+static int chat_debug = CHATDEBUG_DEFAULT;
+static int chat_alarm = CHAT_DEFAULT_TIMEOUT; /* Default */
+
+static volatile int alarmed = 0;
+
+
+static void chat_alrm(int);
+static int chat_unalarm(void);
+static int getdigit(unsigned char **, int, int);
+static char **read_chat(char **);
+static char *cleanchr(char **, unsigned char);
+static char *cleanstr(const char *, int);
+static const char *result(int);
+static int chat_expect(const char *);
+static int chat_send(char const *);
+
+
+/*
+ * alarm signal handler
+ * handle timeouts in read/write
+ * change stdin to non-blocking mode to prevent
+ * possible hang in read().
+ */
+
+static void
+chat_alrm(int signo)
+{
+ int on = 1;
+
+ alarm(1);
+ alarmed = 1;
+ signal(SIGALRM, chat_alrm);
+ ioctl(STDIN_FILENO, FIONBIO, &on);
+}
+
+
+/*
+ * Turn back on blocking mode reset by chat_alrm()
+ */
+
+static int
+chat_unalarm(void)
+{
+ int off = 0;
+ return ioctl(STDIN_FILENO, FIONBIO, &off);
+}
+
+
+/*
+ * convert a string of a given base (octal/hex) to binary
+ */
+
+static int
+getdigit(unsigned char **ptr, int base, int max)
+{
+ int i, val = 0;
+ unsigned char * q;
+
+ static const char xdigits[] = "0123456789abcdef";
+
+ for (i = 0, q = *ptr; i++ < max; ++q) {
+ int sval;
+ const char * s = strchr(xdigits, tolower(*q));
+
+ if (s == NULL || (sval = s - xdigits) >= base)
+ break;
+ val = (val * base) + sval;
+ }
+ *ptr = q;
+ return val;
+}
+
+
+/*
+ * read_chat()
+ * Convert a whitespace delimtied string into an array
+ * of strings, being expect/send pairs
+ */
+
+static char **
+read_chat(char **chatstr)
+{
+ char *str = *chatstr;
+ char **res = NULL;
+
+ if (str != NULL) {
+ char *tmp = NULL;
+ int l;
+
+ if ((l=strlen(str)) > 0 && (tmp=malloc(l + 1)) != NULL &&
+ (res=malloc((l / 2 + 1) * sizeof(char *))) != NULL) {
+ static char ws[] = " \t";
+ char * p;
+
+ for (l = 0, p = strtok(strcpy(tmp, str), ws);
+ p != NULL;
+ p = strtok(NULL, ws))
+ {
+ unsigned char *q, *r;
+
+ /* Read escapes */
+ for (q = r = (unsigned char *)p; *r; ++q)
+ {
+ if (*q == '\\')
+ {
+ /* handle special escapes */
+ switch (*++q)
+ {
+ case 'a': /* bell */
+ *r++ = '\a';
+ break;
+ case 'r': /* cr */
+ *r++ = '\r';
+ break;
+ case 'n': /* nl */
+ *r++ = '\n';
+ break;
+ case 'f': /* ff */
+ *r++ = '\f';
+ break;
+ case 'b': /* bs */
+ *r++ = '\b';
+ break;
+ case 'e': /* esc */
+ *r++ = 27;
+ break;
+ case 't': /* tab */
+ *r++ = '\t';
+ break;
+ case 'p': /* pause */
+ *r++ = PAUSE_CH;
+ break;
+ case 's':
+ case 'S': /* space */
+ *r++ = ' ';
+ break;
+ case 'x': /* hexdigit */
+ ++q;
+ *r++ = getdigit(&q, 16, 2);
+ --q;
+ break;
+ case '0': /* octal */
+ ++q;
+ *r++ = getdigit(&q, 8, 3);
+ --q;
+ break;
+ default: /* literal */
+ *r++ = *q;
+ break;
+ case 0: /* not past eos */
+ --q;
+ break;
+ }
+ } else {
+ /* copy standard character */
+ *r++ = *q;
+ }
+ }
+
+ /* Remove surrounding quotes, if any
+ */
+ if (*p == '"' || *p == '\'') {
+ q = (unsigned char*)strrchr(p+1, *p);
+ if (q != NULL && *q == *p && q[1] == '\0') {
+ *q = '\0';
+ strcpy(p, p+1);
+ }
+ }
+
+ res[l++] = p;
+ }
+ res[l] = NULL;
+ *chatstr = tmp;
+ return res;
+ }
+ free(tmp);
+ }
+ return res;
+}
+
+
+/*
+ * clean a character for display (ctrl/meta character)
+ */
+
+static char *
+cleanchr(char **buf, unsigned char ch)
+{
+ int l;
+ static char tmpbuf[5];
+ char * tmp = buf ? *buf : tmpbuf;
+
+ if (ch & 0x80) {
+ strcpy(tmp, "M-");
+ l = 2;
+ ch &= 0x7f;
+ } else
+ l = 0;
+
+ if (ch < 32) {
+ tmp[l++] = '^';
+ tmp[l++] = ch + '@';
+ } else if (ch == 127) {
+ tmp[l++] = '^';
+ tmp[l++] = '?';
+ } else
+ tmp[l++] = ch;
+ tmp[l] = '\0';
+
+ if (buf)
+ *buf = tmp + l;
+ return tmp;
+}
+
+
+/*
+ * clean a string for display (ctrl/meta characters)
+ */
+
+static char *
+cleanstr(const char *s, int l)
+{
+ static char * tmp = NULL;
+ static int tmplen = 0;
+
+ if (tmplen < l * 4 + 1)
+ tmp = realloc(tmp, tmplen = l * 4 + 1);
+
+ if (tmp == NULL) {
+ tmplen = 0;
+ return (char *)"(mem alloc error)";
+ } else {
+ int i = 0;
+ char * p = tmp;
+
+ while (i < l)
+ cleanchr(&p, s[i++]);
+ *p = '\0';
+ }
+
+ return tmp;
+}
+
+
+/*
+ * return result as a pseudo-english word
+ */
+
+static const char *
+result(int r)
+{
+ static const char * results[] = {
+ "OK", "MEMERROR", "IOERROR", "TIMEOUT"
+ };
+ return results[r & 3];
+}
+
+
+/*
+ * chat_expect()
+ * scan input for an expected string
+ */
+
+static int
+chat_expect(const char *str)
+{
+ int len, r = 0;
+
+ if (chat_debug & CHATDEBUG_EXPECT)
+ syslog(LOG_DEBUG, "chat_expect '%s'", cleanstr(str, strlen(str)));
+
+ if ((len = strlen(str)) > 0) {
+ int i = 0;
+ char * got;
+
+ if ((got = malloc(len + 1)) == NULL)
+ r = 1;
+ else {
+
+ memset(got, 0, len+1);
+ alarm(chat_alarm);
+ alarmed = 0;
+
+ while (r == 0 && i < len) {
+ if (alarmed)
+ r = 3;
+ else {
+ unsigned char ch;
+
+ if (read(STDIN_FILENO, &ch, 1) == 1) {
+
+ if (chat_debug & CHATDEBUG_RECEIVE)
+ syslog(LOG_DEBUG, "chat_recv '%s' m=%d",
+ cleanchr(NULL, ch), i);
+
+ if (ch == str[i])
+ got[i++] = ch;
+ else if (i > 0) {
+ int j = 1;
+
+ /* See if we can resync on a
+ * partial match in our buffer
+ */
+ while (j < i && memcmp(got + j, str, i - j) != 0)
+ j++;
+ if (j < i)
+ memcpy(got, got + j, i - j);
+ i -= j;
+ }
+ } else
+ r = alarmed ? 3 : 2;
+ }
+ }
+ alarm(0);
+ chat_unalarm();
+ alarmed = 0;
+ free(got);
+ }
+ }
+
+ if (chat_debug & CHATDEBUG_EXPECT)
+ syslog(LOG_DEBUG, "chat_expect %s", result(r));
+
+ return r;
+}
+
+
+/*
+ * chat_send()
+ * send a chat string
+ */
+
+static int
+chat_send(char const *str)
+{
+ int r = 0;
+
+ if (chat_debug & CHATDEBUG_SEND)
+ syslog(LOG_DEBUG, "chat_send '%s'", cleanstr(str, strlen(str)));
+
+ if (*str) {
+ alarm(chat_alarm);
+ alarmed = 0;
+ while (r == 0 && *str)
+ {
+ unsigned char ch = (unsigned char)*str++;
+
+ if (alarmed)
+ r = 3;
+ else if (ch == PAUSE_CH)
+ usleep(500000); /* 1/2 second */
+ else {
+ usleep(10000); /* be kind to modem */
+ if (write(STDOUT_FILENO, &ch, 1) != 1)
+ r = alarmed ? 3 : 2;
+ }
+ }
+ alarm(0);
+ chat_unalarm();
+ alarmed = 0;
+ }
+
+ if (chat_debug & CHATDEBUG_SEND)
+ syslog(LOG_DEBUG, "chat_send %s", result(r));
+
+ return r;
+}
+
+
+/*
+ * getty_chat()
+ *
+ * Termination codes:
+ * -1 - no script supplied
+ * 0 - script terminated correctly
+ * 1 - invalid argument, expect string too large, etc.
+ * 2 - error on an I/O operation or fatal error condition
+ * 3 - timeout waiting for a simple string
+ *
+ * Parameters:
+ * char *scrstr - unparsed chat script
+ * timeout - seconds timeout
+ * debug - debug value (bitmask)
+ */
+
+int
+getty_chat(char *scrstr, int timeout, int debug)
+{
+ int r = -1;
+
+ chat_alarm = timeout ? timeout : CHAT_DEFAULT_TIMEOUT;
+ chat_debug = debug;
+
+ if (scrstr != NULL) {
+ char **script;
+
+ if (chat_debug & CHATDEBUG_MISC)
+ syslog(LOG_DEBUG, "getty_chat script='%s'", scrstr);
+
+ if ((script = read_chat(&scrstr)) != NULL) {
+ int i = r = 0;
+ int off = 0;
+ sig_t old_alarm;
+
+ /*
+ * We need to be in raw mode for all this
+ * Rely on caller...
+ */
+
+ old_alarm = signal(SIGALRM, chat_alrm);
+ chat_unalarm(); /* Force blocking mode at start */
+
+ /*
+ * This is the send/expect loop
+ */
+ while (r == 0 && script[i] != NULL)
+ if ((r = chat_expect(script[i++])) == 0 && script[i] != NULL)
+ r = chat_send(script[i++]);
+
+ signal(SIGALRM, old_alarm);
+ free(script);
+ free(scrstr);
+
+ /*
+ * Ensure stdin is in blocking mode
+ */
+ ioctl(STDIN_FILENO, FIONBIO, &off);
+ }
+
+ if (chat_debug & CHATDEBUG_MISC)
+ syslog(LOG_DEBUG, "getty_chat %s", result(r));
+
+ }
+ return r;
+}
diff --git a/system_cmds/getty.tproj/com.apple.getty.internal.plist b/system_cmds/getty.tproj/com.apple.getty.internal.plist
new file mode 100644
index 0000000..bbd8345
--- /dev/null
+++ b/system_cmds/getty.tproj/com.apple.getty.internal.plist
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>EnablePressuredExit</key>
+ <false/>
+ <key>EnableTransactions</key>
+ <false/>
+ <key>KeepAlive</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.getty</string>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
+ <key>_LimitLoadFromVariant</key>
+ <string>IsBaseSystem</string>
+ <key>LimitLoadToHardware</key>
+ <dict>
+ <key>serialdebugmode</key>
+ <array>
+ <integer>1</integer>
+ </array>
+ </dict>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/getty</string>
+ <string>std.9600</string>
+ <string>console</string>
+ </array>
+ <key>SessionCreate</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/getty.tproj/com.apple.getty.plist b/system_cmds/getty.tproj/com.apple.getty.plist
new file mode 100644
index 0000000..45b748f
--- /dev/null
+++ b/system_cmds/getty.tproj/com.apple.getty.plist
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>EnablePressuredExit</key>
+ <false/>
+ <key>EnableTransactions</key>
+ <false/>
+ <key>KeepAlive</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.getty</string>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/getty</string>
+ <string>std.9600</string>
+ <string>console</string>
+ </array>
+ <key>SessionCreate</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/getty.tproj/com.apple.serialdebugconsole.plist b/system_cmds/getty.tproj/com.apple.serialdebugconsole.plist
new file mode 100644
index 0000000..9be51e9
--- /dev/null
+++ b/system_cmds/getty.tproj/com.apple.serialdebugconsole.plist
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>EnablePressuredExit</key>
+ <false/>
+ <key>EnableTransactions</key>
+ <false/>
+ <key>KeepAlive</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.serialdebugconsole</string>
+ <key>POSIXSpawnType</key>
+ <string>Interactive</string>
+ <key>_LimitLoadToVariant</key>
+ <string>AllowsInternalSecurityPolicies</string>
+ <key>LimitLoadToHardware</key>
+ <dict>
+ <key>serialdebugmode</key>
+ <array>
+ <integer>2</integer>
+ </array>
+ </dict>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/bin/sh</string>
+ <string>-i</string>
+ <string>-l</string>
+ </array>
+ <key>StandardInPath</key>
+ <string>/dev/console</string>
+ <key>StandardOutPath</key>
+ <string>/dev/console</string>
+ <key>StandardErrorPath</key>
+ <string>/dev/console</string>
+ <key>SessionCreate</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/getty.tproj/extern.h b/system_cmds/getty.tproj/extern.h
new file mode 100644
index 0000000..34bc85d
--- /dev/null
+++ b/system_cmds/getty.tproj/extern.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)extern.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/libexec/getty/extern.h,v 1.9 2005/04/06 17:42:24 stefanf Exp $
+ */
+
+struct delayval;
+struct termios;
+
+extern char hostname[];
+extern int hopcount;
+extern struct termios tmode, omode;
+extern struct gettyflags gettyflags[];
+extern struct gettynums gettynums[];
+extern struct gettystrs gettystrs[];
+
+int adelay(int, struct delayval *);
+const char *autobaud(void);
+int delaybits(void);
+void edithost(const char *);
+void gendefaults(void);
+void gettable(const char *);
+void makeenv(char *[]);
+const char *portselector(void);
+void set_ttydefaults(int);
+void setchars(void);
+void setdefaults(void);
+void set_flags(int);
+int speed(int);
+int getty_chat(char *, int, int);
diff --git a/system_cmds/getty.tproj/generate_plist.sh b/system_cmds/getty.tproj/generate_plist.sh
new file mode 100644
index 0000000..ef42607
--- /dev/null
+++ b/system_cmds/getty.tproj/generate_plist.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+set -e
+set -x
+
+cp "${SCRIPT_INPUT_FILE_0}" "${SCRIPT_OUTPUT_FILE_0}"
+case "$PLATFORM_NAME" in
+iphone*|appletv*|watch*|bridge*)
+ ;;
+macosx)
+ /usr/libexec/PlistBuddy -c "Add :Disabled bool true" "${SCRIPT_OUTPUT_FILE_0}"
+ ;;
+*)
+ echo "Unsupported platform: $PLATFORM_NAME"
+ exit 1
+ ;;
+esac
diff --git a/system_cmds/getty.tproj/getty.8 b/system_cmds/getty.tproj/getty.8
new file mode 100644
index 0000000..159b14a
--- /dev/null
+++ b/system_cmds/getty.tproj/getty.8
@@ -0,0 +1,128 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)getty.8 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/libexec/getty/getty.8,v 1.16 2005/01/18 09:29:39 ru Exp $
+.\" "
+.Dd June 4, 1993
+.Dt GETTY 8
+.Os
+.Sh NAME
+.Nm getty
+.Nd set terminal mode
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Ar type
+.Op Ar tty
+.Oc
+.Sh DESCRIPTION
+The
+.Nm
+utility is called by
+.Xr launchd 8
+to open and initialize the tty line, read a login name, and invoke
+.Xr login 1 .
+.Pp
+The argument
+.Ar tty
+is the special device file in
+.Pa /dev
+to open for the terminal (for example, ``ttyh0'').
+If there is no argument or the argument is
+.Sq Fl ,
+the tty line is assumed to be open as file descriptor 0.
+.Pp
+The
+.Ar type
+argument can be used to make
+.Nm
+treat the terminal line specially.
+This argument is used as an index into the
+.Xr gettytab 5
+database, to determine the characteristics of the line.
+If there is no argument, or there is no such table, the
+.Em default
+table is used.
+If there is no
+.Pa /etc/gettytab
+a set of system defaults is used.
+If indicated by the table located,
+.Nm
+will clear the terminal screen,
+print a banner heading,
+and prompt for a login name.
+Usually either the banner or the login prompt will include
+the system hostname.
+.Pp
+Most of the default actions of
+.Nm
+can be circumvented, or modified, by a suitable
+.Pa gettytab
+table.
+.Pp
+The
+.Nm
+utility can be set to timeout after some interval,
+which will cause dial up lines to hang up
+if the login name is not entered reasonably quickly.
+.Sh FILES
+.Bl -tag -width /etc/gettytab -compact
+.It Pa /etc/gettytab
+.It Pa /etc/ttys
+.El
+.Sh DIAGNOSTICS
+.Bl -diag
+.It "ttyxx: No such device or address."
+.It "ttyxx: No such file or address."
+.Pp
+A terminal which is turned
+on in the
+.Pa ttys
+file cannot be opened, likely because the requisite
+lines are either not configured into the system, the associated device
+was not attached during boot-time system configuration,
+or the special file in
+.Pa /dev
+does not exist.
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr ioctl 2 ,
+.Xr tty 4 ,
+.Xr gettytab 5 ,
+.Xr ttys 5 ,
+.Xr launchd 8
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
diff --git a/system_cmds/getty.tproj/gettytab.5 b/system_cmds/getty.tproj/gettytab.5
new file mode 100644
index 0000000..c2efc88
--- /dev/null
+++ b/system_cmds/getty.tproj/gettytab.5
@@ -0,0 +1,546 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)gettytab.5 8.4 (Berkeley) 4/19/94
+.\" $FreeBSD: src/libexec/getty/gettytab.5,v 1.41 2005/01/18 09:29:39 ru Exp $
+.\" "
+.Dd April 19, 1994
+.Dt GETTYTAB 5
+.Os
+.Sh NAME
+.Nm gettytab
+.Nd terminal configuration data base
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+file
+is a simplified version of the
+.Xr termcap 5
+data base
+used to describe terminal lines.
+The initial terminal login process
+.Xr getty 8
+accesses the
+.Nm
+file each time it starts, allowing simpler
+reconfiguration of terminal characteristics.
+Each entry in the data base
+is used to describe one class of terminals.
+.Pp
+There is a default terminal class,
+.Va default ,
+that is used to set global defaults for all other classes.
+(That is, the
+.Va default
+entry is read, then the entry for the class required
+is used to override particular settings.)
+.Sh CAPABILITIES
+Refer to
+.Xr termcap 5
+for a description of the file layout.
+The
+.Va default
+column below lists defaults obtained if there is
+no entry in the table obtained, nor one in the special
+.Va default
+table.
+.Bl -column Name Type /usr/bin/login
+.It Sy "Name Type Default Description
+.It "ac str unused expect-send chat script for modem answer"
+.It "al str unused user to auto-login instead of prompting"
+.It "ap bool false terminal uses any parity"
+.It "bk str 0377 alternate end of line character (input break)"
+.It "c0 num unused tty control flags to write messages"
+.It "c1 num unused tty control flags to read login name"
+.It "c2 num unused tty control flags to leave terminal as"
+.It "ce bool false use crt erase algorithm"
+.It "ck bool false use crt kill algorithm"
+.It "cl str" Ta Dv NULL Ta
+.No "screen clear sequence"
+.It "co bool false console - add"
+.Ql \en
+after login prompt
+.It "ct num 10 chat timeout for"
+.Va \&ac
+and
+.Va \&ic
+scripts
+.It "dc num 0 chat debug bitmask"
+.It "de num 0 delay secs and flush input before writing first prompt"
+.It "df str %+ the" Xr strftime 3 "format used for \&%d in the banner message"
+.It "ds str" Ta So Li ^Y Sc Ta
+.No "delayed suspend character"
+.It "dx bool false set"
+.Dv DECCTLQ
+.It "ec bool false leave echo"
+.Em OFF
+.It "ep bool false terminal uses even parity"
+.It "er str" Ta So Li ^? Sc Ta
+.No "erase character"
+.It "et str" Ta So Li ^D Sc Ta
+.No "end of text"
+.Pq Dv EOF
+character
+.It "ev str" Ta Dv NULL Ta
+.No "initial environment"
+.It "f0 num unused tty mode flags to write messages"
+.It "f1 num unused tty mode flags to read login name"
+.It "f2 num unused tty mode flags to leave terminal as"
+.It "fl str" Ta So Li ^O Sc Ta
+.No "output flush character"
+.It "hc bool false do"
+.Em NOT
+hangup line on last close
+.It "he str" Ta Dv NULL Ta
+.No "hostname editing string"
+.It "hn str hostname hostname"
+.It "ht bool false terminal has real tabs"
+.It "hw bool false do cts/rts hardware flow control"
+.It "i0 num unused tty input flags to write messages"
+.It "i1 num unused tty input flags to read login name"
+.It "i2 num unused tty input flags to leave terminal as"
+.It "ic str unused expect-send chat script for modem initialization"
+.It "if str unused display named file before prompt, like /etc/issue"
+.It "ig bool false ignore garbage characters in login name"
+.It "im str" Ta Dv NULL Ta
+.No "initial (banner) message"
+.It "in str" Ta So Li ^C Sc Ta
+.No "interrupt character"
+.It "is num unused input speed"
+.It "kl str" Ta So Li ^U Sc Ta
+.No "kill character"
+.It "l0 num unused tty local flags to write messages"
+.It "l1 num unused tty local flags to read login name"
+.It "l2 num unused tty local flags to leave terminal as"
+.It "lm str login: login prompt"
+.It "ln str" Ta So Li ^V Sc Ta
+.No "``literal next'' character"
+.It "lo str" Ta Pa /usr/bin/login Ta
+.No "program to exec when name obtained"
+.It "mb bool false do flow control based on carrier"
+.It "nc bool false terminal does not supply carrier (set clocal)"
+.It "nl bool false terminal has (or might have) a newline character"
+.It "np bool false terminal uses no parity (i.e. 8-bit characters)"
+.It "nx str default next table (for auto speed selection)"
+.It "o0 num unused tty output flags to write messages"
+.It "o1 num unused tty output flags to read login name"
+.It "o2 num unused tty output flags to leave terminal as"
+.It "op bool false terminal uses odd parity"
+.It "os num unused output speed"
+.It "pc str" Ta So Li \e0 Sc Ta
+.No "pad character"
+.It "pe bool false use printer (hard copy) erase algorithm"
+.It "pf num 0 delay"
+between first prompt and following flush (seconds)
+.It "pl bool false start PPP login program unconditionally if"
+.Va \&pp
+is specified
+.It "pp str unused PPP login program"
+.It "ps bool false line connected to a"
+.Tn MICOM
+port selector
+.It "qu str" Ta So Li \&^\e Sc Ta
+.No "quit character"
+.It "rp str" Ta So Li ^R Sc Ta
+.No "line retype character"
+.It "rt num unused ring timeout when using"
+.Va \&ac
+.It "rw bool false do"
+.Em NOT
+use raw for input, use cbreak
+.It "sp num unused line speed (input and output)"
+.It "su str" Ta So Li ^Z Sc Ta
+.No "suspend character"
+.It "tc str none table continuation"
+.It "to num 0 timeout (seconds)"
+.It "tt str" Ta Dv NULL Ta
+.No "terminal type (for environment)"
+.It "ub bool false do unbuffered output (of prompts etc)"
+.It "we str" Ta So Li ^W Sc Ta
+.No "word erase character"
+.It "xc bool false do
+.Em NOT
+echo control chars as
+.Ql ^X
+.It "xf str" Ta So Li ^S Sc Ta Dv XOFF
+(stop output) character
+.It "xn str" Ta So Li ^Q Sc Ta Dv XON
+(start output) character
+.It "Lo str C the locale name used for \&%d in the banner message"
+.El
+.Pp
+The following capabilities are no longer supported by
+.Xr getty 8 :
+.Bl -column Name Type /usr/bin/login
+.It "bd num 0 backspace delay"
+.It "cb bool false use crt backspace mode"
+.It "cd num 0 carriage-return delay"
+.It "fd num 0 form-feed (vertical motion) delay"
+.It "lc bool false terminal has lower case"
+.It "nd num 0 newline (line-feed) delay"
+.It "uc bool false terminal is known upper case only"
+.El
+.Pp
+If no line speed is specified, speed will not be altered
+from that which prevails when getty is entered.
+Specifying an input or output speed will override
+line speed for stated direction only.
+.Pp
+Terminal modes to be used for the output of the message,
+for input of the login name,
+and to leave the terminal set as upon completion,
+are derived from the boolean flags specified.
+If the derivation should prove inadequate,
+any (or all) of these three may be overridden
+with one of the
+.Va \&c0 ,
+.Va \&c1 ,
+.Va \&c2 ,
+.Va \&i0 ,
+.Va \&i1 ,
+.Va \&i2 ,
+.Va \&l0 ,
+.Va \&l1 ,
+.Va \&l2 ,
+.Va \&o0 ,
+.Va \&o1 ,
+or
+.Va \&o2
+numeric specifications, which can be used to specify
+(usually in octal, with a leading '0')
+the exact values of the flags.
+These flags correspond to the termios
+.Va c_cflag ,
+.Va c_iflag ,
+.Va c_lflag ,
+and
+.Va c_oflag
+fields, respectively.
+Each of these sets must be completely specified to be effective.
+.Pp
+The
+.Va \&f0 ,
+.Va \&f1 ,
+and
+.Va \&f2
+are excepted for backwards compatibility with a previous incarnation of
+the TTY sub-system.
+In these flags the bottom 16 bits of the (32 bits)
+value contain the sgttyb
+.Va sg_flags
+field, while the top 16 bits represent the local mode word.
+.Pp
+Should
+.Xr getty 8
+receive a null character
+(presumed to indicate a line break)
+it will restart using the table indicated by the
+.Va \&nx
+entry.
+If there is none, it will re-use its original table.
+.Pp
+Delays are specified in milliseconds, the nearest possible
+delay available in the tty driver will be used.
+Should greater certainty be desired, delays
+with values 0, 1, 2, and 3 are interpreted as
+choosing that particular delay algorithm from the driver.
+.Pp
+The
+.Va \&cl
+screen clear string may be preceded by a (decimal) number
+of milliseconds of delay required (a la termcap).
+This delay is simulated by repeated use of the pad character
+.Va \&pc .
+.Pp
+The initial message, login message, and initial file;
+.Va \&im ,
+.Va \&lm
+and
+.Va \&if
+may include any of the following character sequences, which expand to
+information about the environment in which
+.Xr getty 8
+is running.
+.Pp
+.Bl -tag -offset indent -width \&%xxxxxxxxxxxxxx
+.It \&%d
+The current date and time formatted according to the
+.Va \&Lo
+and
+.Va \&df
+strings.
+.It \&%h
+The hostname of the machine, which is normally obtained from the
+system using
+.Xr gethostname 3 ,
+but may also be overridden by the
+.Va \&hn
+table entry.
+In either case it may be edited with the
+.Va \&he
+string.
+A '@' in the
+.Va \&he
+string causes one character from the real hostname to
+be copied to the final hostname.
+A '#' in the
+.Va \&he
+string causes the next character of the real hostname
+to be skipped.
+Each character that
+is neither '@' nor '#' is copied into the final hostname.
+Surplus '@' and '#' characters are ignored.
+.It \&%t
+The tty name.
+.It "\&%m, \&%r, \&%s, \&%v"
+The type of machine, release of the operating system, name of the
+operating system, and version of the kernel, respectively, as
+returned by
+.Xr uname 3 .
+.It \&%%
+A
+.Dq %
+character.
+.El
+.Pp
+When getty execs the login process, given
+in the
+.Va \&lo
+string (usually
+.Dq Pa /usr/bin/login ) ,
+it will have set
+the environment to include the terminal type, as indicated
+by the
+.Va \&tt
+string (if it exists).
+The
+.Va \&ev
+string, can be used to enter additional data into
+the environment.
+It is a list of comma separated strings, each of which
+will presumably be of the form
+.Li name=value .
+.Pp
+If a non-zero timeout is specified, with
+.Va \&to ,
+then getty will exit within the indicated
+number of seconds, either having
+received a login name and passed control
+to
+.Xr login 1 ,
+or having received an alarm signal, and exited.
+This may be useful to hangup dial in lines.
+.Pp
+Output from
+.Xr getty 8
+is even parity unless
+.Va \&op
+or
+.Va \&np
+is specified.
+The
+.Va \&op
+string
+may be specified with
+.Va \&ap
+to allow any parity on input, but generate odd parity output.
+Note: this only applies while getty is being run,
+terminal driver limitations prevent a more complete
+implementation.
+The
+.Xr getty 8
+utility does not check parity of input characters in
+.Dv RAW
+mode.
+.Pp
+If a
+.Va \&pp
+string is specified and a PPP link bring-up sequence is recognized,
+getty will invoke the program referenced by the
+.Va \&pp
+option.
+This can be used to handle incoming PPP calls.
+If the
+.Va \&pl
+option is true as well,
+.Xr getty 8
+will skip the user name prompt and the PPP detection phase, and will
+invoke the program specified by
+.Va \&pp
+instantly.
+.Pp
+.Nm Getty
+provides some basic intelligent modem handling by providing a chat
+script feature available via two capabilities:
+.Pp
+.Bl -tag -offset indent -width \&xxxxxxxx -compact
+.It ic
+Chat script to initialize modem.
+.It ac
+Chat script to answer a call.
+.El
+.Pp
+A chat script is a set of expect/send string pairs.
+When a chat string starts,
+.Nm getty
+will wait for the first string, and if it finds it, will send the
+second, and so on.
+Strings specified are separated by one or more tabs or spaces.
+Strings may contain standard ASCII characters and special 'escapes',
+which consist of a backslash character followed by one or more
+characters which are interpreted as follows:
+.Pp
+.Bl -tag -offset indent -width \&xxxxxxxx -compact
+.It \ea
+bell character.
+.It \eb
+backspace.
+.It \en
+newline.
+.It \ee
+escape.
+.It \ef
+formfeed.
+.It \ep
+half-second pause.
+.It \er
+carriage return.
+.It \eS , \es
+space character.
+.It \et
+tab.
+.It \exNN
+hexadecimal byte value.
+.It \e0NNN
+octal byte value.
+.El
+.Pp
+Note that the
+.Ql \ep
+sequence is only valid for send strings and causes a half-second
+pause between sending the previous and next characters.
+Hexadecimal values are, at most, 2 hex digits long, and octal
+values are a maximum of 3 octal digits.
+.Pp
+The
+.Va \&ic
+chat sequence is used to initialize a modem or similar device.
+A typical example of an init chat script for a modem with a
+hayes compatible command set might look like this:
+.Pp
+.Dl :ic="" ATE0Q0V1\er OK\er ATS0=0\er OK\er:
+.Pp
+This script waits for nothing (which always succeeds), sends
+a sequence to ensure that the modem is in the correct mode
+(suppress command echo, send responses in verbose mode),
+and then disables auto-answer.
+It waits for an "OK" response before it terminates.
+The init sequence is used to check modem responses to ensure that
+the modem is functioning correctly.
+If the init script fails to complete,
+.Nm getty
+considers this to be fatal, and results in an error logged via
+.Xr syslogd 8 ,
+and exiting.
+.Pp
+Similarly, an answer chat script is used to manually answer the
+phone in response to (usually) a "RING".
+When run with an answer script,
+.Nm getty
+opens the port in non-blocking mode, clears any extraneous input
+and waits for data on the port.
+As soon as any data is available, the answer chat script is
+started and scanned for a string, and responds according to
+the answer chat script.
+With a hayes compatible modem, this would normally look something
+like:
+.Pp
+.Dl :ac=RING\er ATA\er CONNECT:
+.Pp
+This causes the modem to answer the call via the "ATA" command,
+then scans input for a "CONNECT" string.
+If this is received before a
+.Va \&ct
+timeout, then a normal login sequence commences.
+.Pp
+The
+.Va \&ct
+capability specifies a timeout for all send and expect strings.
+This timeout is set individually for each expect wait and send
+string and must be at least as long as the time it takes for
+a connection to be established between a remote and local
+modem (usually around 10 seconds).
+.Pp
+In most situations, you will want to flush any additional
+input after the connection has been detected, and the
+.Va \&de
+capability may be used to do that, as well as delay for a
+short time after the connection has been established during
+which all of the connection data has been sent by the modem.
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr gethostname 3 ,
+.Xr uname 3 ,
+.Xr termcap 5 ,
+.Xr getty 8 ,
+.Xr telnetd 8
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.2 .
+.Sh BUGS
+The special characters (erase, kill, etc.) are reset to system defaults
+by
+.Xr login 1 .
+In
+.Em all
+cases, '#' or '^H' typed in a login name will be treated as
+an erase character, and '@' will be treated as a kill character.
+.Pp
+The delay stuff is a real crock.
+Apart form its general lack of flexibility, some
+of the delay algorithms are not implemented.
+The terminal driver should support sane delay settings.
+.Pp
+The
+.Va \&he
+capability is stupid.
+.Pp
+The
+.Xr termcap 5
+format is horrid, something more rational should
+have been chosen.
+.Pp
+This should be converted to use
+.Xr termios 4 .
diff --git a/system_cmds/getty.tproj/gettytab.h b/system_cmds/getty.tproj/gettytab.h
new file mode 100644
index 0000000..3addfe3
--- /dev/null
+++ b/system_cmds/getty.tproj/gettytab.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 1983, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)gettytab.h 8.2 (Berkeley) 3/30/94
+ * $FreeBSD: src/libexec/getty/gettytab.h,v 1.14 2003/06/10 18:30:41 yar Exp $
+ */
+
+/*
+ * Getty description definitions.
+ */
+struct gettystrs {
+ const char *field; /* name to lookup in gettytab */
+ char *defalt; /* value we find by looking in defaults */
+ char *value; /* value that we find there */
+};
+
+struct gettynums {
+ const char *field; /* name to lookup */
+ long defalt; /* number we find in defaults */
+ long value; /* number we find there */
+ int set; /* we actually got this one */
+};
+
+struct gettyflags {
+ const char *field; /* name to lookup */
+ char invrt; /* name existing in gettytab --> false */
+ char defalt; /* true/false in defaults */
+ char value; /* true/false flag */
+ char set; /* we found it */
+};
+
+/*
+ * String values.
+ */
+#define NX gettystrs[0].value
+#define CL gettystrs[1].value
+#define IM gettystrs[2].value
+#define LM gettystrs[3].value
+#define ER gettystrs[4].value
+#define KL gettystrs[5].value
+#define ET gettystrs[6].value
+#define PC gettystrs[7].value
+#define TT gettystrs[8].value
+#define EV gettystrs[9].value
+#define LO gettystrs[10].value
+#define HN gettystrs[11].value
+#define HE gettystrs[12].value
+#define IN gettystrs[13].value
+#define QU gettystrs[14].value
+#define XN gettystrs[15].value
+#define XF gettystrs[16].value
+#define BK gettystrs[17].value
+#define SU gettystrs[18].value
+#define DS gettystrs[19].value
+#define RP gettystrs[20].value
+#define FL gettystrs[21].value
+#define WE gettystrs[22].value
+#define LN gettystrs[23].value
+#define Lo gettystrs[24].value
+#define PP gettystrs[25].value
+#define IF gettystrs[26].value
+#define IC gettystrs[27].value
+#define AC gettystrs[28].value
+#define AL gettystrs[29].value
+#define DF gettystrs[30].value
+
+/*
+ * Numeric definitions.
+ */
+#define IS gettynums[0].value
+#define OS gettynums[1].value
+#define SP gettynums[2].value
+#define ND gettynums[3].value
+#define CD gettynums[4].value
+#define TD gettynums[5].value
+#define FD gettynums[6].value
+#define BD gettynums[7].value
+#define TO gettynums[8].value
+#define F0 gettynums[9].value
+#define F0set gettynums[9].set
+#define F1 gettynums[10].value
+#define F1set gettynums[10].set
+#define F2 gettynums[11].value
+#define F2set gettynums[11].set
+#define PF gettynums[12].value
+#define C0 gettynums[13].value
+#define C0set gettynums[13].set
+#define C1 gettynums[14].value
+#define C1set gettynums[14].set
+#define C2 gettynums[15].value
+#define C2set gettynums[15].set
+#define I0 gettynums[16].value
+#define I0set gettynums[16].set
+#define I1 gettynums[17].value
+#define I1set gettynums[17].set
+#define I2 gettynums[18].value
+#define I2set gettynums[18].set
+#define L0 gettynums[19].value
+#define L0set gettynums[19].set
+#define L1 gettynums[20].value
+#define L1set gettynums[20].set
+#define L2 gettynums[21].value
+#define L2set gettynums[21].set
+#define O0 gettynums[22].value
+#define O0set gettynums[22].set
+#define O1 gettynums[23].value
+#define O1set gettynums[23].set
+#define O2 gettynums[24].value
+#define O2set gettynums[24].set
+#define DE gettynums[25].value
+#define RTset gettynums[26].set
+#define RT gettynums[26].value
+#define CT gettynums[27].value
+#define DC gettynums[28].value
+
+/*
+ * Boolean values.
+ */
+#define HT gettyflags[0].value
+#define NL gettyflags[1].value
+#define EP gettyflags[2].value
+#define EPset gettyflags[2].set
+#define OP gettyflags[3].value
+#define OPset gettyflags[3].set
+#define AP gettyflags[4].value
+#define APset gettyflags[4].set
+#define EC gettyflags[5].value
+#define CO gettyflags[6].value
+#define CB gettyflags[7].value
+#define CK gettyflags[8].value
+#define CE gettyflags[9].value
+#define PE gettyflags[10].value
+#define RW gettyflags[11].value
+#define XC gettyflags[12].value
+#define LC gettyflags[13].value
+#define UC gettyflags[14].value
+#define IG gettyflags[15].value
+#define PS gettyflags[16].value
+#define HC gettyflags[17].value
+#define UB gettyflags[18].value
+#define AB gettyflags[19].value
+#define DX gettyflags[20].value
+#define NP gettyflags[21].value
+#define NPset gettyflags[21].set
+#define MB gettyflags[22].value
+#define HW gettyflags[23].value
+#define NC gettyflags[24].value
+#define PL gettyflags[25].value
diff --git a/system_cmds/getty.tproj/init.c b/system_cmds/getty.tproj/init.c
new file mode 100644
index 0000000..a0d69d2
--- /dev/null
+++ b/system_cmds/getty.tproj/init.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from: init.c 8.1 (Berkeley) 6/4/93";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD: src/libexec/getty/init.c,v 1.16 2005/04/06 17:42:24 stefanf Exp $";
+#endif /* not lint */
+
+/*
+ * Getty table initializations.
+ *
+ * Melbourne getty.
+ */
+#include <termios.h>
+#include "gettytab.h"
+#include "extern.h"
+#include "pathnames.h"
+
+static char loginmsg[] = "login: ";
+static char nullstr[] = "";
+static char loginprg[] = _PATH_LOGIN;
+static char datefmt[] = "%+";
+
+struct gettystrs gettystrs[] = {
+ { "nx" }, /* next table */
+ { "cl" }, /* screen clear characters */
+ { "im" }, /* initial message */
+ { "lm", loginmsg }, /* login message */
+ { "er", (char*)&omode.c_cc[VERASE] }, /* erase character */
+ { "kl", (char*)&omode.c_cc[VKILL] }, /* kill character */
+ { "et", (char*)&omode.c_cc[VEOF] }, /* eof chatacter (eot) */
+ { "pc", nullstr }, /* pad character */
+ { "tt" }, /* terminal type */
+ { "ev" }, /* enviroment */
+ { "lo", loginprg }, /* login program */
+ { "hn", hostname }, /* host name */
+ { "he" }, /* host name edit */
+ { "in", (char*)&omode.c_cc[VINTR] }, /* interrupt char */
+ { "qu", (char*)&omode.c_cc[VQUIT] }, /* quit char */
+ { "xn", (char*)&omode.c_cc[VSTART] }, /* XON (start) char */
+ { "xf", (char*)&omode.c_cc[VSTOP] }, /* XOFF (stop) char */
+ { "bk", (char*)&omode.c_cc[VEOL] }, /* brk char (alt \n) */
+ { "su", (char*)&omode.c_cc[VSUSP] }, /* suspend char */
+ { "ds", (char*)&omode.c_cc[VDSUSP] }, /* delayed suspend */
+ { "rp", (char*)&omode.c_cc[VREPRINT] },/* reprint char */
+ { "fl", (char*)&omode.c_cc[VDISCARD] },/* flush output */
+ { "we", (char*)&omode.c_cc[VWERASE] }, /* word erase */
+ { "ln", (char*)&omode.c_cc[VLNEXT] }, /* literal next */
+ { "Lo" }, /* locale for strftime() */
+ { "pp" }, /* ppp login program */
+ { "if" }, /* sysv-like 'issue' filename */
+ { "ic" }, /* modem init-chat */
+ { "ac" }, /* modem answer-chat */
+ { "al" }, /* user to auto-login */
+ { "df", datefmt}, /* format for strftime() */
+ { 0 }
+};
+
+struct gettynums gettynums[] = {
+ { "is" }, /* input speed */
+ { "os" }, /* output speed */
+ { "sp" }, /* both speeds */
+ { "nd" }, /* newline delay */
+ { "cd" }, /* carriage-return delay */
+ { "td" }, /* tab delay */
+ { "fd" }, /* form-feed delay */
+ { "bd" }, /* backspace delay */
+ { "to" }, /* timeout */
+ { "f0" }, /* output flags */
+ { "f1" }, /* input flags */
+ { "f2" }, /* user mode flags */
+ { "pf" }, /* delay before flush at 1st prompt */
+ { "c0" }, /* output c_flags */
+ { "c1" }, /* input c_flags */
+ { "c2" }, /* user mode c_flags */
+ { "i0" }, /* output i_flags */
+ { "i1" }, /* input i_flags */
+ { "i2" }, /* user mode i_flags */
+ { "l0" }, /* output l_flags */
+ { "l1" }, /* input l_flags */
+ { "l2" }, /* user mode l_flags */
+ { "o0" }, /* output o_flags */
+ { "o1" }, /* input o_flags */
+ { "o2" }, /* user mode o_flags */
+ { "de" }, /* delay before sending 1st prompt */
+ { "rt" }, /* reset timeout */
+ { "ct" }, /* chat script timeout */
+ { "dc" }, /* debug chat script value */
+ { 0 }
+};
+
+
+struct gettyflags gettyflags[] = {
+ { "ht", 0 }, /* has tabs */
+ { "nl", 1 }, /* has newline char */
+ { "ep", 0 }, /* even parity */
+ { "op", 0 }, /* odd parity */
+ { "ap", 0 }, /* any parity */
+ { "ec", 1 }, /* no echo */
+ { "co", 0 }, /* console special */
+ { "cb", 0 }, /* crt backspace */
+ { "ck", 0 }, /* crt kill */
+ { "ce", 0 }, /* crt erase */
+ { "pe", 0 }, /* printer erase */
+ { "rw", 1 }, /* don't use raw */
+ { "xc", 1 }, /* don't ^X ctl chars */
+ { "lc", 0 }, /* terminal las lower case */
+ { "uc", 0 }, /* terminal has no lower case */
+ { "ig", 0 }, /* ignore garbage */
+ { "ps", 0 }, /* do port selector speed select */
+ { "hc", 1 }, /* don't set hangup on close */
+ { "ub", 0 }, /* unbuffered output */
+ { "ab", 0 }, /* auto-baud detect with '\r' */
+ { "dx", 0 }, /* set decctlq */
+ { "np", 0 }, /* no parity at all (8bit chars) */
+ { "mb", 0 }, /* do MDMBUF flow control */
+ { "hw", 0 }, /* do CTSRTS flow control */
+ { "nc", 0 }, /* set clocal (no carrier) */
+ { "pl", 0 }, /* use PPP instead of login(1) */
+ { 0 }
+};
diff --git a/system_cmds/getty.tproj/main.c b/system_cmds/getty.tproj/main.c
new file mode 100644
index 0000000..ba501fb
--- /dev/null
+++ b/system_cmds/getty.tproj/main.c
@@ -0,0 +1,858 @@
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from: main.c 8.1 (Berkeley) 6/20/93";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD: src/libexec/getty/main.c,v 1.47 2005/04/06 17:42:24 stefanf Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/ttydefaults.h>
+#include <sys/utsname.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#include "gettytab.h"
+#include "extern.h"
+#include "pathnames.h"
+
+/*
+ * Set the amount of running time that getty should accumulate
+ * before deciding that something is wrong and exit.
+ */
+#define GETTY_TIMEOUT 60 /* seconds */
+
+#undef CTRL
+#define CTRL(x) (x&037)
+
+/* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
+
+#define PPP_FRAME 0x7e /* PPP Framing character */
+#define PPP_STATION 0xff /* "All Station" character */
+#define PPP_ESCAPE 0x7d /* Escape Character */
+#define PPP_CONTROL 0x03 /* PPP Control Field */
+#define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */
+#define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */
+#define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */
+
+/* original mode; flags've been reset using values from <sys/ttydefaults.h> */
+struct termios omode;
+/* current mode */
+struct termios tmode;
+
+int crmod, digit, lower, upper;
+
+char hostname[MAXHOSTNAMELEN];
+char name[MAXLOGNAME*3];
+char dev[] = _PATH_DEV;
+char ttyn[32];
+
+#define OBUFSIZ 128
+#define TABBUFSIZ 512
+
+const char *tname;
+
+char *env[128];
+
+char partab[] = {
+ 0001,0201,0201,0001,0201,0001,0001,0201,
+ 0202,0004,0003,0205,0005,0206,0201,0001,
+ 0201,0001,0001,0201,0001,0201,0201,0001,
+ 0001,0201,0201,0001,0201,0001,0001,0201,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0200,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0200,0000,0000,0200,0000,0200,0200,0000,
+ 0000,0200,0200,0000,0200,0000,0000,0201
+};
+
+#define ERASE tmode.c_cc[VERASE]
+#define KILL tmode.c_cc[VKILL]
+#define EOT tmode.c_cc[VEOF]
+
+#define puts Gputs
+
+static void defttymode(void);
+static void dingdong(int);
+static void dogettytab(void);
+static int getname(void);
+static void interrupt(int);
+static void oflush(void);
+static void prompt(void);
+static void putchr(int);
+static void putf(const char *);
+static void putpad(const char *);
+static void puts(const char *);
+static void timeoverrun(int);
+static char *getty_getline(int);
+static void setttymode(int);
+static int opentty(const char *, int);
+
+jmp_buf timeout;
+
+static void
+dingdong(int signo __unused)
+{
+ alarm(0);
+ longjmp(timeout, 1);
+}
+
+jmp_buf intrupt;
+
+static void
+interrupt(int signo __unused)
+{
+ longjmp(intrupt, 1);
+}
+
+/*
+ * Action to take when getty is running too long.
+ */
+static void
+timeoverrun(int signo __unused)
+{
+
+ syslog(LOG_ERR, "getty exiting due to excessive running time");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ extern char **environ;
+ int first_sleep = 1, first_time = 1;
+ struct rlimit limit;
+ int rval;
+#ifdef __APPLE__
+ int ttyopenmode = O_RDWR;
+#endif
+
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+
+ openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
+ gethostname(hostname, sizeof(hostname) - 1);
+ hostname[sizeof(hostname) - 1] = '\0';
+ if (hostname[0] == '\0')
+ strcpy(hostname, "Amnesiac");
+
+ /*
+ * Limit running time to deal with broken or dead lines.
+ */
+ (void)signal(SIGXCPU, timeoverrun);
+ limit.rlim_max = RLIM_INFINITY;
+ limit.rlim_cur = GETTY_TIMEOUT;
+ (void)setrlimit(RLIMIT_CPU, &limit);
+
+ gettable("default");
+ gendefaults();
+ tname = "default";
+ if (argc > 1)
+ tname = argv[1];
+
+ /*
+ * The following is a work around for vhangup interactions
+ * which cause great problems getting window systems started.
+ * If the tty line is "-", we do the old style getty presuming
+ * that the file descriptors are already set up for us.
+ * J. Gettys - MIT Project Athena.
+ */
+ if (argc <= 2 || strcmp(argv[2], "-") == 0)
+#ifdef __APPLE__
+ {
+ // <rdar://problem/5178373>
+ char* n = ttyname(STDIN_FILENO);
+ if (n) {
+ strlcpy(ttyn, n, sizeof(ttyn));
+ } else {
+ syslog(LOG_ERR, "ttyname %m");
+ exit(1);
+ }
+ }
+#else
+ strcpy(ttyn, ttyname(STDIN_FILENO));
+#endif
+ else {
+ strcpy(ttyn, dev);
+ strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
+ if (strcmp(argv[0], "+") != 0) {
+ chown(ttyn, 0, 0);
+ chmod(ttyn, 0600);
+ revoke(ttyn);
+
+ /*
+ * Do the first scan through gettytab.
+ * Terminal mode parameters will be wrong until
+ * defttymode() called, but they're irrelevant for
+ * the initial setup of the terminal device.
+ */
+ dogettytab();
+
+#if defined(__APPLE__) && !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (strncmp(ttyn, _PATH_CONSOLE, sizeof(ttyn)) == 0)
+ ttyopenmode |= O_POPUP;
+#endif
+ /*
+ * Init or answer modem sequence has been specified.
+ */
+ if (IC || AC) {
+#ifdef __APPLE__
+ if (!opentty(ttyn, ttyopenmode))
+#else
+ if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
+#endif
+ exit(1);
+ defttymode();
+ setttymode(1);
+ }
+
+ if (IC) {
+ if (getty_chat(IC, CT, DC) > 0) {
+ syslog(LOG_ERR, "modem init problem on %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ }
+
+ if (AC) {
+ int i, rfds;
+ struct timeval to;
+
+ rfds = 1 << 0; /* FD_SET */
+ to.tv_sec = RT;
+ to.tv_usec = 0;
+ i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
+ (fd_set*)NULL, RT ? &to : NULL);
+ if (i < 0) {
+ syslog(LOG_ERR, "select %s: %m", ttyn);
+ } else if (i == 0) {
+ syslog(LOG_NOTICE, "recycle tty %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(0); /* recycle for init */
+ }
+ i = getty_chat(AC, CT, DC);
+ if (i > 0) {
+ syslog(LOG_ERR, "modem answer problem on %s", ttyn);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ } else { /* maybe blocking open */
+#ifdef __APPLE__
+ if (!opentty(ttyn, ttyopenmode | (NC ? O_NONBLOCK : 0 )))
+#else
+ if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
+#endif
+ exit(1);
+ }
+ }
+ }
+
+ defttymode();
+ for (;;) {
+
+ /*
+ * if a delay was specified then sleep for that
+ * number of seconds before writing the initial prompt
+ */
+ if (first_sleep && DE) {
+ sleep(DE);
+ /* remove any noise */
+ (void)tcflush(STDIN_FILENO, TCIOFLUSH);
+ }
+ first_sleep = 0;
+
+ setttymode(0);
+ if (AB) {
+ tname = autobaud();
+ dogettytab();
+ continue;
+ }
+ if (PS) {
+ tname = portselector();
+ dogettytab();
+ continue;
+ }
+ if (CL && *CL)
+ putpad(CL);
+ edithost(HE);
+
+ /* if this is the first time through this, and an
+ issue file has been given, then send it */
+ if (first_time && IF) {
+ int fd;
+
+ if ((fd = open(IF, O_RDONLY)) != -1) {
+ char * cp;
+
+ while ((cp = getty_getline(fd)) != NULL) {
+ putf(cp);
+ }
+ close(fd);
+ }
+ }
+ first_time = 0;
+
+ if (IM && *IM && !(PL && PP))
+ putf(IM);
+ if (setjmp(timeout)) {
+ cfsetispeed(&tmode, B0);
+ cfsetospeed(&tmode, B0);
+ (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
+ exit(1);
+ }
+ if (TO) {
+ signal(SIGALRM, dingdong);
+ alarm(TO);
+ }
+
+ rval = 0;
+ if (AL) {
+ const char *p = AL;
+ char *q = name;
+
+ while (*p && q < &name[sizeof name - 1]) {
+ if (isupper(*p))
+ upper = 1;
+ else if (islower(*p))
+ lower = 1;
+ else if (isdigit(*p))
+ digit = 1;
+ *q++ = *p++;
+ }
+ } else if (!(PL && PP))
+ rval = getname();
+ if (rval == 2 || (PL && PP)) {
+ oflush();
+ alarm(0);
+ limit.rlim_max = RLIM_INFINITY;
+ limit.rlim_cur = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &limit);
+ execle(PP, "ppplogin", ttyn, (char *) 0, env);
+ syslog(LOG_ERR, "%s: %m", PP);
+ exit(1);
+ } else if (rval || AL) {
+ int i;
+
+ oflush();
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ if (name[0] == '\0')
+ continue;
+ if (name[0] == '-') {
+ puts("user names may not start with '-'.");
+ continue;
+ }
+ if (!(upper || lower || digit)) {
+ if (AL) {
+ syslog(LOG_ERR,
+ "invalid auto-login name: %s", AL);
+ exit(1);
+ } else
+ continue;
+ }
+ set_flags(2);
+ if (crmod) {
+ tmode.c_iflag |= ICRNL;
+ tmode.c_oflag |= ONLCR;
+ }
+#if REALLY_OLD_TTYS
+ if (upper || UC)
+ tmode.sg_flags |= LCASE;
+ if (lower || LC)
+ tmode.sg_flags &= ~LCASE;
+#endif
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
+ exit(1);
+ }
+ signal(SIGINT, SIG_DFL);
+ for (i = 0; environ[i] != (char *)0; i++)
+ env[i] = environ[i];
+ makeenv(&env[i]);
+
+ limit.rlim_max = RLIM_INFINITY;
+ limit.rlim_cur = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &limit);
+#ifdef __APPLE__
+ // <rdar://problem/3205179>
+ execle(LO, "login", AL ? "-fp1" : "-p1", name,
+#else
+ execle(LO, "login", AL ? "-fp" : "-p", name,
+#endif
+ (char *) 0, env);
+ syslog(LOG_ERR, "%s: %m", LO);
+ exit(1);
+ }
+ alarm(0);
+ signal(SIGALRM, SIG_DFL);
+ signal(SIGINT, SIG_IGN);
+ if (NX && *NX) {
+ tname = NX;
+ dogettytab();
+ }
+ }
+}
+
+static int
+opentty(const char *tty, int flags)
+{
+ int i;
+ int failopenlogged = 0;
+
+ while ((i = open(tty, flags)) == -1)
+ {
+ if (!failopenlogged) {
+ syslog(LOG_ERR, "open %s: %m", tty);
+ failopenlogged = 1;
+ }
+ sleep(60);
+ }
+ if (login_tty(i) < 0) {
+#ifndef __APPLE__
+ if (daemon(0,0) < 0) {
+ syslog(LOG_ERR,"daemon: %m");
+ close(i);
+ return 0;
+ }
+#endif
+ if (login_tty(i) < 0) {
+ syslog(LOG_ERR, "login_tty %s: %m", tty);
+ close(i);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void
+defttymode(void)
+{
+
+ /* Start with default tty settings. */
+ if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
+ syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
+ exit(1);
+ }
+ omode = tmode; /* fill c_cc for dogettytab() */
+ dogettytab();
+ /*
+ * Don't rely on the driver too much, and initialize crucial
+ * things according to <sys/ttydefaults.h>. Avoid clobbering
+ * the c_cc[] settings however, the console drivers might wish
+ * to leave their idea of the preferred VERASE key value
+ * there.
+ */
+ tmode.c_iflag = TTYDEF_IFLAG;
+ tmode.c_oflag = TTYDEF_OFLAG;
+ tmode.c_lflag = TTYDEF_LFLAG;
+ tmode.c_cflag = TTYDEF_CFLAG;
+ if (NC)
+ tmode.c_cflag |= CLOCAL;
+ omode = tmode;
+}
+
+static void
+setttymode(int raw)
+{
+ int off = 0;
+
+ (void)tcflush(STDIN_FILENO, TCIOFLUSH); /* clear out the crap */
+ ioctl(STDIN_FILENO, FIONBIO, &off); /* turn off non-blocking mode */
+ ioctl(STDIN_FILENO, FIOASYNC, &off); /* ditto for async mode */
+
+ if (IS)
+ cfsetispeed(&tmode, speed(IS));
+ else if (SP)
+ cfsetispeed(&tmode, speed(SP));
+ if (OS)
+ cfsetospeed(&tmode, speed(OS));
+ else if (SP)
+ cfsetospeed(&tmode, speed(SP));
+ set_flags(0);
+ setchars();
+ if (raw)
+ cfmakeraw(&tmode);
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
+ exit(1);
+ }
+}
+
+
+static int
+getname(void)
+{
+ int c;
+ char *np;
+ unsigned char cs;
+ int ppp_state = 0;
+ int ppp_connection = 0;
+
+ /*
+ * Interrupt may happen if we use CBREAK mode
+ */
+ if (setjmp(intrupt)) {
+ signal(SIGINT, SIG_IGN);
+ return (0);
+ }
+ signal(SIGINT, interrupt);
+ set_flags(1);
+ prompt();
+ oflush();
+ if (PF > 0) {
+ sleep(PF);
+ PF = 0;
+ }
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
+ syslog(LOG_ERR, "%s: %m", ttyn);
+ exit(1);
+ }
+ crmod = digit = lower = upper = 0;
+ np = name;
+ for (;;) {
+ oflush();
+ if (read(STDIN_FILENO, &cs, 1) <= 0)
+ exit(0);
+ if ((c = cs&0177) == 0)
+ return (0);
+
+ /* PPP detection state machine..
+ Look for sequences:
+ PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
+ PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
+ See RFC1662.
+ Derived from code from Michael Hancock, <michaelh@cet.co.jp>
+ and Erik 'PPP' Olson, <eriko@wrq.com>
+ */
+
+ if (PP && (cs == PPP_FRAME)) {
+ ppp_state = 1;
+ } else if (ppp_state == 1 && cs == PPP_STATION) {
+ ppp_state = 2;
+ } else if (ppp_state == 2 && cs == PPP_ESCAPE) {
+ ppp_state = 3;
+ } else if ((ppp_state == 2 && cs == PPP_CONTROL)
+ || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
+ ppp_state = 4;
+ } else if (ppp_state == 4 && cs == PPP_LCP_HI) {
+ ppp_state = 5;
+ } else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
+ ppp_connection = 1;
+ break;
+ } else {
+ ppp_state = 0;
+ }
+
+ if (c == EOT || c == CTRL('d'))
+ exit(0);
+ if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
+ putf("\r\n");
+ break;
+ }
+ if (islower(c))
+ lower = 1;
+ else if (isupper(c))
+ upper = 1;
+ else if (c == ERASE || c == '\b' || c == 0177) {
+ if (np > name) {
+ np--;
+ if (cfgetospeed(&tmode) >= 1200)
+ puts("\b \b");
+ else
+ putchr(cs);
+ }
+ continue;
+ } else if (c == KILL || c == CTRL('u')) {
+ putchr('\r');
+ if (cfgetospeed(&tmode) < 1200)
+ putchr('\n');
+ /* this is the way they do it down under ... */
+ else if (np > name)
+ puts(" \r");
+ prompt();
+ digit = lower = upper = 0;
+ np = name;
+ continue;
+ } else if (isdigit(c))
+ digit = 1;
+ if (IG && (c <= ' ' || c > 0176))
+ continue;
+ *np++ = c;
+ putchr(cs);
+ }
+ signal(SIGINT, SIG_IGN);
+ *np = 0;
+ if (c == '\r')
+ crmod = 1;
+ if ((upper && !lower && !LC) || UC)
+ for (np = name; *np; np++)
+ if (isupper(*np))
+ *np = tolower(*np);
+ return (1 + ppp_connection);
+}
+
+static void
+putpad(const char *s)
+{
+ int pad = 0;
+ speed_t ospeed = cfgetospeed(&tmode);
+
+ if (isdigit(*s)) {
+ while (isdigit(*s)) {
+ pad *= 10;
+ pad += *s++ - '0';
+ }
+ pad *= 10;
+ if (*s == '.' && isdigit(s[1])) {
+ pad += s[1] - '0';
+ s += 2;
+ }
+ }
+
+ puts(s);
+ /*
+ * If no delay needed, or output speed is
+ * not comprehensible, then don't try to delay.
+ */
+ if (pad == 0 || ospeed <= 0)
+ return;
+
+ /*
+ * Round up by a half a character frame, and then do the delay.
+ * Too bad there are no user program accessible programmed delays.
+ * Transmitting pad characters slows many terminals down and also
+ * loads the system.
+ */
+ pad = (pad * ospeed + 50000) / 100000;
+ while (pad--)
+ putchr(*PC);
+}
+
+static void
+puts(const char *s)
+{
+ while (*s)
+ putchr(*s++);
+}
+
+char outbuf[OBUFSIZ];
+int obufcnt = 0;
+
+static void
+putchr(int cc)
+{
+ char c;
+
+ c = cc;
+ if (!NP) {
+ c |= partab[c&0177] & 0200;
+ if (OP)
+ c ^= 0200;
+ }
+ if (!UB) {
+ outbuf[obufcnt++] = c;
+ if (obufcnt >= OBUFSIZ)
+ oflush();
+ } else
+ write(STDOUT_FILENO, &c, 1);
+}
+
+static void
+oflush(void)
+{
+ if (obufcnt)
+ write(STDOUT_FILENO, outbuf, obufcnt);
+ obufcnt = 0;
+}
+
+static void
+prompt(void)
+{
+
+ putf(LM);
+ if (CO)
+ putchr('\n');
+}
+
+
+static char *
+getty_getline(int fd)
+{
+ int i = 0;
+ static char linebuf[512];
+
+ /*
+ * This is certainly slow, but it avoids having to include
+ * stdio.h unnecessarily. Issue files should be small anyway.
+ */
+ while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
+ if (linebuf[i] == '\n') {
+ /* Don't rely on newline mode, assume raw */
+ linebuf[i++] = '\r';
+ linebuf[i++] = '\n';
+ linebuf[i] = '\0';
+ return linebuf;
+ }
+ ++i;
+ }
+ linebuf[i] = '\0';
+ return i ? linebuf : 0;
+}
+
+static void
+putf(const char *cp)
+{
+ extern char editedhost[];
+ time_t t;
+ char *slash, db[100];
+
+ static struct utsname kerninfo;
+
+ if (!*kerninfo.sysname)
+ uname(&kerninfo);
+
+ while (*cp) {
+ if (*cp != '%') {
+ putchr(*cp++);
+ continue;
+ }
+ switch (*++cp) {
+
+ case 't':
+ slash = strrchr(ttyn, '/');
+ if (slash == (char *) 0)
+ puts(ttyn);
+ else
+ puts(&slash[1]);
+ break;
+
+ case 'h':
+ puts(editedhost);
+ break;
+
+ case 'd': {
+ t = (time_t)0;
+ (void)time(&t);
+ if (Lo)
+ (void)setlocale(LC_TIME, Lo);
+ (void)strftime(db, sizeof(db), DF, localtime(&t));
+ puts(db);
+ break;
+
+ case 's':
+ puts(kerninfo.sysname);
+ break;
+
+ case 'm':
+ puts(kerninfo.machine);
+ break;
+
+ case 'r':
+ puts(kerninfo.release);
+ break;
+
+ case 'v':
+ puts(kerninfo.version);
+ break;
+ }
+
+ case '%':
+ putchr('%');
+ break;
+ }
+ cp++;
+ }
+}
+
+/*
+ * Read a gettytab database entry and perform necessary quirks.
+ */
+static void
+dogettytab()
+{
+ /* Read the database entry. */
+ gettable(tname);
+
+ /*
+ * Avoid inheriting the parity values from the default entry
+ * if any of them is set in the current entry.
+ * Mixing different parity settings is unreasonable.
+ */
+ if (OPset || EPset || APset || NPset)
+ OPset = EPset = APset = NPset = 1;
+
+ /* Fill in default values for unset capabilities. */
+ setdefaults();
+}
diff --git a/system_cmds/getty.tproj/pathnames.h b/system_cmds/getty.tproj/pathnames.h
new file mode 100644
index 0000000..2c64fd1
--- /dev/null
+++ b/system_cmds/getty.tproj/pathnames.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: @(#)pathnames.h 8.1 (Berkeley) 6/4/93
+ * $FreeBSD: src/libexec/getty/pathnames.h,v 1.7 1999/08/28 00:09:36 peter Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_GETTYTAB "/etc/gettytab"
+#define _PATH_LOGIN "/usr/bin/login"
diff --git a/system_cmds/getty.tproj/subr.c b/system_cmds/getty.tproj/subr.c
new file mode 100644
index 0000000..2bff200
--- /dev/null
+++ b/system_cmds/getty.tproj/subr.c
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from: subr.c 8.1 (Berkeley) 6/4/93";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD: src/libexec/getty/subr.c,v 1.19 2004/06/25 10:11:28 phk Exp $";
+#endif /* not lint */
+
+/*
+ * Melbourne getty.
+ */
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "gettytab.h"
+#include "pathnames.h"
+#include "extern.h"
+
+/*
+ * Get a table entry.
+ */
+void
+gettable(const char *name)
+{
+ char *buf = NULL;
+ struct gettystrs *sp;
+ struct gettynums *np;
+ struct gettyflags *fp;
+ long n;
+ int l;
+ char *p;
+ char *msg = NULL;
+ const char *dba[2];
+
+ static int firsttime = 1;
+
+ dba[0] = _PATH_GETTYTAB;
+ dba[1] = 0;
+
+ if (firsttime) {
+ /*
+ * we need to strdup() anything in the strings array
+ * initially in order to simplify things later
+ */
+ for (sp = gettystrs; sp->field; sp++)
+ if (sp->value != NULL) {
+ /* handle these ones more carefully */
+ if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
+ l = 2;
+ else
+ l = (int)strlen(sp->value) + 1;
+ if ((p = malloc(l)) != NULL) {
+ strncpy(p, sp->value, l);
+ p[l-1] = '\0';
+ }
+ /*
+ * replace, even if NULL, else we'll
+ * have problems with free()ing static mem
+ */
+ sp->value = p;
+ }
+ firsttime = 0;
+ }
+
+ switch (cgetent(&buf, (char **)dba, (char *)name)) {
+ case 1:
+ msg = "%s: couldn't resolve 'tc=' in gettytab '%s'";
+ case 0:
+ break;
+ case -1:
+ msg = "%s: unknown gettytab entry '%s'";
+ break;
+ case -2:
+ msg = "%s: retrieving gettytab entry '%s': %m";
+ break;
+ case -3:
+ msg = "%s: recursive 'tc=' reference gettytab entry '%s'";
+ break;
+ default:
+ msg = "%s: unexpected cgetent() error for entry '%s'";
+ break;
+ }
+
+ if (msg != NULL) {
+ syslog(LOG_ERR, msg, "getty", name);
+ return;
+ }
+
+ for (sp = gettystrs; sp->field; sp++) {
+ if ((l = cgetstr(buf, (char*)sp->field, &p)) >= 0) {
+ if (sp->value) {
+ /* prefer existing value */
+ if (strcmp(p, sp->value) != 0)
+ free(sp->value);
+ else {
+ free(p);
+ p = sp->value;
+ }
+ }
+ sp->value = p;
+ } else if (l == -1) {
+ free(sp->value);
+ sp->value = NULL;
+ }
+ }
+
+ for (np = gettynums; np->field; np++) {
+ if (cgetnum(buf, (char*)np->field, &n) == -1)
+ np->set = 0;
+ else {
+ np->set = 1;
+ np->value = n;
+ }
+ }
+
+ for (fp = gettyflags; fp->field; fp++) {
+ if (cgetcap(buf, (char *)fp->field, ':') == NULL)
+ fp->set = 0;
+ else {
+ fp->set = 1;
+ fp->value = 1 ^ fp->invrt;
+ }
+ }
+
+#ifdef DEBUG
+ printf("name=\"%s\", buf=\"%s\"\r\n", name, buf);
+ for (sp = gettystrs; sp->field; sp++)
+ printf("cgetstr: %s=%s\r\n", sp->field, sp->value);
+ for (np = gettynums; np->field; np++)
+ printf("cgetnum: %s=%d\r\n", np->field, np->value);
+ for (fp = gettyflags; fp->field; fp++)
+ printf("cgetflags: %s='%c' set='%c'\r\n", fp->field,
+ fp->value + '0', fp->set + '0');
+#endif /* DEBUG */
+
+ free(buf);
+}
+
+void
+gendefaults(void)
+{
+ struct gettystrs *sp;
+ struct gettynums *np;
+ struct gettyflags *fp;
+
+ for (sp = gettystrs; sp->field; sp++)
+ if (sp->value)
+ sp->defalt = strdup(sp->value);
+ for (np = gettynums; np->field; np++)
+ if (np->set)
+ np->defalt = np->value;
+ for (fp = gettyflags; fp->field; fp++)
+ if (fp->set)
+ fp->defalt = fp->value;
+ else
+ fp->defalt = fp->invrt;
+}
+
+void
+setdefaults(void)
+{
+ struct gettystrs *sp;
+ struct gettynums *np;
+ struct gettyflags *fp;
+
+ for (sp = gettystrs; sp->field; sp++)
+ if (!sp->value)
+ sp->value = !sp->defalt ? sp->defalt
+ : strdup(sp->defalt);
+ for (np = gettynums; np->field; np++)
+ if (!np->set)
+ np->value = np->defalt;
+ for (fp = gettyflags; fp->field; fp++)
+ if (!fp->set)
+ fp->value = fp->defalt;
+}
+
+static char **
+charnames[] = {
+ &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
+ &SU, &DS, &RP, &FL, &WE, &LN, 0
+};
+
+static char *
+charvars[] = {
+ (char*)&tmode.c_cc[VERASE],
+ (char*)&tmode.c_cc[VKILL],
+ (char*)&tmode.c_cc[VINTR],
+ (char*)&tmode.c_cc[VQUIT],
+ (char*)&tmode.c_cc[VSTART],
+ (char*)&tmode.c_cc[VSTOP],
+ (char*)&tmode.c_cc[VEOF],
+ (char*)&tmode.c_cc[VEOL],
+ (char*)&tmode.c_cc[VSUSP],
+ (char*)&tmode.c_cc[VDSUSP],
+ (char*)&tmode.c_cc[VREPRINT],
+ (char*)&tmode.c_cc[VDISCARD],
+ (char*)&tmode.c_cc[VWERASE],
+ (char*)&tmode.c_cc[VLNEXT],
+ 0
+};
+
+void
+setchars(void)
+{
+ int i;
+ const char *p;
+
+ for (i = 0; charnames[i]; i++) {
+ p = *charnames[i];
+ if (p && *p)
+ *charvars[i] = *p;
+ else
+ *charvars[i] = _POSIX_VDISABLE;
+ }
+}
+
+/* Macros to clear/set/test flags. */
+#define SET(t, f) (t) |= (f)
+#define CLR(t, f) (t) &= ~(f)
+#define ISSET(t, f) ((t) & (f))
+
+void
+set_flags(int n)
+{
+ tcflag_t iflag, oflag, cflag, lflag;
+
+
+ switch (n) {
+ case 0:
+ if (C0set && I0set && L0set && O0set) {
+ tmode.c_cflag = C0;
+ tmode.c_iflag = I0;
+ tmode.c_lflag = L0;
+ tmode.c_oflag = O0;
+ return;
+ }
+ break;
+ case 1:
+ if (C1set && I1set && L1set && O1set) {
+ tmode.c_cflag = C1;
+ tmode.c_iflag = I1;
+ tmode.c_lflag = L1;
+ tmode.c_oflag = O1;
+ return;
+ }
+ break;
+ default:
+ if (C2set && I2set && L2set && O2set) {
+ tmode.c_cflag = C2;
+ tmode.c_iflag = I2;
+ tmode.c_lflag = L2;
+ tmode.c_oflag = O2;
+ return;
+ }
+ break;
+ }
+
+ iflag = omode.c_iflag;
+ oflag = omode.c_oflag;
+ cflag = omode.c_cflag;
+ lflag = omode.c_lflag;
+
+ if (NP) {
+ CLR(cflag, CSIZE|PARENB);
+ SET(cflag, CS8);
+ CLR(iflag, ISTRIP|INPCK|IGNPAR);
+ } else if (AP || EP || OP) {
+ CLR(cflag, CSIZE);
+ SET(cflag, CS7|PARENB);
+ SET(iflag, ISTRIP);
+ if (OP && !EP) {
+ SET(iflag, INPCK|IGNPAR);
+ SET(cflag, PARODD);
+ if (AP)
+ CLR(iflag, INPCK);
+ } else if (EP && !OP) {
+ SET(iflag, INPCK|IGNPAR);
+ CLR(cflag, PARODD);
+ if (AP)
+ CLR(iflag, INPCK);
+ } else if (AP || (EP && OP)) {
+ CLR(iflag, INPCK|IGNPAR);
+ CLR(cflag, PARODD);
+ }
+ } /* else, leave as is */
+
+#if 0
+ if (UC)
+ f |= LCASE;
+#endif
+
+ if (HC)
+ SET(cflag, HUPCL);
+ else
+ CLR(cflag, HUPCL);
+
+ if (MB)
+ SET(cflag, MDMBUF);
+ else
+ CLR(cflag, MDMBUF);
+
+ if (HW)
+ SET(cflag, CRTSCTS);
+ else
+ CLR(cflag, CRTSCTS);
+
+ if (NL) {
+ SET(iflag, ICRNL);
+ SET(oflag, ONLCR|OPOST);
+ } else {
+ CLR(iflag, ICRNL);
+ CLR(oflag, ONLCR);
+ }
+
+ if (!HT)
+ SET(oflag, OXTABS|OPOST);
+ else
+ CLR(oflag, OXTABS);
+
+#ifdef XXX_DELAY
+ SET(f, delaybits());
+#endif
+
+ if (n == 1) { /* read mode flags */
+ if (RW) {
+ iflag = 0;
+ CLR(oflag, OPOST);
+ CLR(cflag, CSIZE|PARENB);
+ SET(cflag, CS8);
+ lflag = 0;
+ } else {
+ CLR(lflag, ICANON);
+ }
+ goto out;
+ }
+
+ if (n == 0)
+ goto out;
+
+#if 0
+ if (CB)
+ SET(f, CRTBS);
+#endif
+
+ if (CE)
+ SET(lflag, ECHOE);
+ else
+ CLR(lflag, ECHOE);
+
+ if (CK)
+ SET(lflag, ECHOKE);
+ else
+ CLR(lflag, ECHOKE);
+
+ if (PE)
+ SET(lflag, ECHOPRT);
+ else
+ CLR(lflag, ECHOPRT);
+
+ if (EC)
+ SET(lflag, ECHO);
+ else
+ CLR(lflag, ECHO);
+
+ if (XC)
+ SET(lflag, ECHOCTL);
+ else
+ CLR(lflag, ECHOCTL);
+
+ if (DX)
+ SET(lflag, IXANY);
+ else
+ CLR(lflag, IXANY);
+
+out:
+ tmode.c_iflag = iflag;
+ tmode.c_oflag = oflag;
+ tmode.c_cflag = cflag;
+ tmode.c_lflag = lflag;
+}
+
+
+#ifdef XXX_DELAY
+struct delayval {
+ unsigned delay; /* delay in ms */
+ int bits;
+};
+
+/*
+ * below are random guesses, I can't be bothered checking
+ */
+
+struct delayval crdelay[] = {
+ { 1, CR1 },
+ { 2, CR2 },
+ { 3, CR3 },
+ { 83, CR1 },
+ { 166, CR2 },
+ { 0, CR3 },
+};
+
+struct delayval nldelay[] = {
+ { 1, NL1 }, /* special, calculated */
+ { 2, NL2 },
+ { 3, NL3 },
+ { 100, NL2 },
+ { 0, NL3 },
+};
+
+struct delayval bsdelay[] = {
+ { 1, BS1 },
+ { 0, 0 },
+};
+
+struct delayval ffdelay[] = {
+ { 1, FF1 },
+ { 1750, FF1 },
+ { 0, FF1 },
+};
+
+struct delayval tbdelay[] = {
+ { 1, TAB1 },
+ { 2, TAB2 },
+ { 3, XTABS }, /* this is expand tabs */
+ { 100, TAB1 },
+ { 0, TAB2 },
+};
+
+int
+delaybits(void)
+{
+ int f;
+
+ f = adelay(CD, crdelay);
+ f |= adelay(ND, nldelay);
+ f |= adelay(FD, ffdelay);
+ f |= adelay(TD, tbdelay);
+ f |= adelay(BD, bsdelay);
+ return (f);
+}
+
+int
+adelay(int ms, struct delayval *dp)
+{
+ if (ms == 0)
+ return (0);
+ while (dp->delay && ms > dp->delay)
+ dp++;
+ return (dp->bits);
+}
+#endif
+
+char editedhost[MAXHOSTNAMELEN];
+
+void
+edithost(const char *pat)
+{
+ const char *host = HN;
+ char *res = editedhost;
+
+ if (!pat)
+ pat = "";
+ while (*pat) {
+ switch (*pat) {
+
+ case '#':
+ if (*host)
+ host++;
+ break;
+
+ case '@':
+ if (*host)
+ *res++ = *host++;
+ break;
+
+ default:
+ *res++ = *pat;
+ break;
+
+ }
+ if (res == &editedhost[sizeof editedhost - 1]) {
+ *res = '\0';
+ return;
+ }
+ pat++;
+ }
+ if (*host)
+ strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
+ else
+ *res = '\0';
+ editedhost[sizeof editedhost - 1] = '\0';
+}
+
+static struct speedtab {
+ int speed;
+ int uxname;
+} speedtab[] = {
+ { 50, B50 },
+ { 75, B75 },
+ { 110, B110 },
+ { 134, B134 },
+ { 150, B150 },
+ { 200, B200 },
+ { 300, B300 },
+ { 600, B600 },
+ { 1200, B1200 },
+ { 1800, B1800 },
+ { 2400, B2400 },
+ { 4800, B4800 },
+ { 9600, B9600 },
+ { 19200, EXTA },
+ { 19, EXTA }, /* for people who say 19.2K */
+ { 38400, EXTB },
+ { 38, EXTB },
+ { 7200, EXTB }, /* alternative */
+ { 57600, B57600 },
+ { 115200, B115200 },
+ { 230400, B230400 },
+ { 0 }
+};
+
+int
+speed(int val)
+{
+ struct speedtab *sp;
+
+ if (val <= B230400)
+ return (val);
+
+ for (sp = speedtab; sp->speed; sp++)
+ if (sp->speed == val)
+ return (sp->uxname);
+
+ return (B300); /* default in impossible cases */
+}
+
+void
+makeenv(char *env[])
+{
+ static char termbuf[128] = "TERM=";
+ char *p, *q;
+ char **ep;
+
+ ep = env;
+ if (TT && *TT) {
+ strlcat(termbuf, TT, sizeof(termbuf));
+ *ep++ = termbuf;
+ }
+ if ((p = EV)) {
+ q = p;
+ while ((q = strchr(q, ','))) {
+ *q++ = '\0';
+ *ep++ = p;
+ p = q;
+ }
+ if (*p)
+ *ep++ = p;
+ }
+ *ep = (char *)0;
+}
+
+/*
+ * This speed select mechanism is written for the Develcon DATASWITCH.
+ * The Develcon sends a string of the form "B{speed}\n" at a predefined
+ * baud rate. This string indicates the user's actual speed.
+ * The routine below returns the terminal type mapped from derived speed.
+ */
+struct portselect {
+ const char *ps_baud;
+ const char *ps_type;
+} portspeeds[] = {
+ { "B110", "std.110" },
+ { "B134", "std.134" },
+ { "B150", "std.150" },
+ { "B300", "std.300" },
+ { "B600", "std.600" },
+ { "B1200", "std.1200" },
+ { "B2400", "std.2400" },
+ { "B4800", "std.4800" },
+ { "B9600", "std.9600" },
+ { "B19200", "std.19200" },
+ { 0 }
+};
+
+const char *
+portselector(void)
+{
+ char c, baud[20];
+ const char *type = "default";
+ struct portselect *ps;
+ int len;
+
+ alarm(5*60);
+ for (len = 0; len < sizeof (baud) - 1; len++) {
+ if (read(STDIN_FILENO, &c, 1) <= 0)
+ break;
+ c &= 0177;
+ if (c == '\n' || c == '\r')
+ break;
+ if (c == 'B')
+ len = 0; /* in case of leading garbage */
+ baud[len] = c;
+ }
+ baud[len] = '\0';
+ for (ps = portspeeds; ps->ps_baud; ps++)
+ if (strcmp(ps->ps_baud, baud) == 0) {
+ type = ps->ps_type;
+ break;
+ }
+ sleep(2); /* wait for connection to complete */
+ return (type);
+}
+
+/*
+ * This auto-baud speed select mechanism is written for the Micom 600
+ * portselector. Selection is done by looking at how the character '\r'
+ * is garbled at the different speeds.
+ */
+const char *
+autobaud(void)
+{
+ int rfds;
+ struct timeval timeout;
+ char c;
+ const char *type = "9600-baud";
+
+ (void)tcflush(0, TCIOFLUSH);
+ rfds = 1 << 0;
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
+ (fd_set *)NULL, &timeout) <= 0)
+ return (type);
+ if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
+ return (type);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 20;
+ (void) select(32, (fd_set *)NULL, (fd_set *)NULL,
+ (fd_set *)NULL, &timeout);
+ (void)tcflush(0, TCIOFLUSH);
+ switch (c & 0377) {
+
+ case 0200: /* 300-baud */
+ type = "300-baud";
+ break;
+
+ case 0346: /* 1200-baud */
+ type = "1200-baud";
+ break;
+
+ case 015: /* 2400-baud */
+ case 0215:
+ type = "2400-baud";
+ break;
+
+ default: /* 4800-baud */
+ type = "4800-baud";
+ break;
+
+ case 0377: /* 9600-baud */
+ type = "9600-baud";
+ break;
+ }
+ return (type);
+}
diff --git a/system_cmds/getty.tproj/ttys.5 b/system_cmds/getty.tproj/ttys.5
new file mode 100644
index 0000000..9a0a77c
--- /dev/null
+++ b/system_cmds/getty.tproj/ttys.5
@@ -0,0 +1,168 @@
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)ttys.5 8.1 (Berkeley) 6/4/93
+.\" $FreeBSD: src/libexec/getty/ttys.5,v 1.18 2005/06/14 08:40:10 ru Exp $
+.\" "
+.Dd May 27, 2005
+.Dt TTYS 5
+.Os
+.Sh NAME
+.Nm ttys
+.Nd terminal initialization information
+.Sh DESCRIPTION
+The file
+.Nm
+contains information that is used by various routines to initialize
+and control the use of terminal special files.
+This information is read with the
+.Xr getttyent 3
+library routines.
+There is one line in the
+.Nm
+file per special device file.
+Fields are separated by tabs and/or spaces.
+Fields comprised of more than one word should be enclosed in double
+quotes (``"'').
+Blank lines and comments may appear anywhere in the file; comments
+are delimited by hash marks (``#'') and new lines.
+Any unspecified fields will default to null.
+.Pp
+The first field is normally the
+name of the terminal special file as it is found in
+.Pa /dev .
+However, it can be any arbitrary string
+when the associated command is not related to a tty.
+.Pp
+The second field of the file is the command to execute for the line,
+usually
+.Xr getty 8 ,
+which initializes and opens the line, setting the speed, waiting for
+a user name and executing the
+.Xr login 1
+program.
+It can be, however, any desired command, for example
+the start up for a window system terminal emulator or some other
+daemon process, and can contain multiple words if quoted.
+.Pp
+The third field is the type of terminal usually connected to that
+tty line, normally the one found in the
+.Xr termcap 5
+data base file.
+The environment variable
+.Ev TERM
+is initialized with the value by
+either
+.Xr getty 8
+or
+.Xr login 1 .
+.Pp
+The remaining fields set flags in the
+.Fa ty_status
+entry (see
+.Xr getttyent 3 ) ,
+specify a window system process that
+.Xr launchd 8
+will maintain for the terminal line.
+.Pp
+As flag values, the strings ``on'' and ``off'' specify that
+.Xr launchd 8
+should (should not) execute the command given in the second field,
+while ``secure'' (if ``on'' is also specified) allows users with a
+uid of 0 to login on
+this line.
+The flags ``local'', ``rtscts'', ``mdmbuf'', and ``softcar''
+modify the default behaviour of the terminal line, and their actions
+are driver dependent.
+The ``local'' flag causes the driver to
+treat the line as if it locally connected.
+The ``rtscts'' flag
+instructs the driver to use RTS/CTS hardware flow control, if
+possible.
+The ``mdmbuf'' flag instructs the driver to use
+DTR/DCD flow control, if possible.
+The ``softcar'' flag causes the driver to ignore
+hardware carrier on the line.
+These flag fields should not be quoted.
+.Pp
+The string ``window='' may be followed by a quoted command
+string which
+.Xr launchd 8
+will execute
+.Em before
+starting the command specified by the second field.
+.Sh FILES
+.Bl -tag -width /etc/ttys -compact
+.It Pa /etc/ttys
+.El
+.Sh NUMERIC SEQUENCES
+Numeric sequences of terminals can be represented in a more compact format.
+A matching pair of square bracket may enclose two numbers (the start and
+stop values), separated by a hyphen.
+The numbers are assumed to be decimal, unless prefixed with ``0x'', in which
+case they are interpreted as hexadecimal.
+The number of characters (not including any ``0x'') in the starting value gives
+the minimum width; sequence values are zero padded up to this width.
+Thus ``tty[00-07]'' represents the eight terminals ``tty00'' through ``tty07''.
+.Sh EXAMPLES
+.Bd -literal
+# root login on console at 1200 baud
+console "/usr/libexec/getty std.1200" vt100 on secure
+# dialup at 1200 baud, no root logins
+ttyd0 "/usr/libexec/getty d1200" dialup on # 555-1234
+# Mike's terminal: hp2621
+ttyh0 "/usr/libexec/getty std.9600" hp2621-nl on # 457 Evans
+# John's terminal: vt100
+ttyh1 "/usr/libexec/getty std.9600" vt100 on # 459 Evans
+# terminal emulate/window system
+ttyv0 "/usr/X11/bin/xterm -display :0" xterm on window="/usr/X11/bin/X :0"
+# the sequence of eight terminals tty00 through tty07
+tty[00-07] "/usr/libexec/getty std.9600" vt100 on
+# Network pseudo ttys -- don't enable getty
+ttyp0 none network
+ttyp1 none network off
+# All sixteen of a pseudo tty sequence
+ttyq[0x0-0xf] none network
+.Ed
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr getttyent 3 ,
+.Xr ttyslot 3 ,
+.Xr gettytab 5 ,
+.Xr termcap 5 ,
+.Xr getty 8 ,
+.Xr launchd 8
+.\" .Xr ttyflags 8
+.Sh HISTORY
+A
+.Nm
+file appeared in
+.At v6 .
diff --git a/system_cmds/hostinfo.tproj/hostinfo.8 b/system_cmds/hostinfo.tproj/hostinfo.8
new file mode 100644
index 0000000..c24e7ab
--- /dev/null
+++ b/system_cmds/hostinfo.tproj/hostinfo.8
@@ -0,0 +1,89 @@
+.\" Copyright (c) 2003-2009 Apple Inc. All rights reserved.
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @(#)hostinfo.1
+.Dd October 30, 2003 \" DATE
+.Dt hostinfo 8 \" Program name and manual section number
+.Os "Mac OS X"
+.Sh NAME \" Section Header - required - don't modify
+.Nm hostinfo
+.\" The following lines are read in generating the apropos(man -k) database. Use only key
+.\" words here as the database is built based on the words here and in the .ND line.
+.\" Use .Nm macro to designate other names for the documented program.
+.Nd host information
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm
+.Sh DESCRIPTION \" Section Header - required - don't modify
+The
+.Nm
+command displays information about the host system on which the command is executing.
+The output includes
+a kernel version description,
+processor configuration data,
+available physical memory,
+and various scheduling statistics.
+.Pp
+.Sh OPTIONS
+There are no options.
+.Sh DISPLAY
+.Pp
+.Bl -ohang -width Primary_memory_available_ -offset indent
+.It Mach kernel version:
+The version string compiled into the kernel executing on the host system.
+.Pp
+.It Processor Configuration:
+The maximum possible processors for which the kernel is configured,
+followed by the number of physical and logical processors available.
+.Pp
+Note: on Intel architectures, physical processors are referred to as cores, and
+logical processors are referred to as hardware threads; there may be multiple
+logical processors per core and multiple cores per processor package.
+This command does not report the number of processor packages.
+.Pp
+.It Processor type:
+The host's processor type and subtype.
+.Pp
+.It Processor active:
+A list of active processors on the host system.
+Active processors are members of a processor set and are ready to
+dispatch threads.
+On a single processor system, the active processor, is processor 0.
+.Pp
+.It Primary memory available:
+The amount of physical memory that is configured for use on the host system.
+.Pp
+.It Default processor set:
+Displays the number of tasks currently assigned to the host processor set,
+the number of threads currently assigned to the host processor set,
+and the number of processors included in the host processor set.
+.Pp
+.It Load average:
+Measures the average number of threads in the run queue.
+.Pp
+.It Mach factor:
+A variant of the load average which measures
+the processing resources available to a new thread.
+Mach factor is based on the number of CPUs divided by (1 + the number of runnablethreads)
+or
+the number of CPUs minus the number of runnable threads when the number of runnable threads
+is less than the number of CPUs.
+The closer the Mach factor value is to zero, the higher the load.
+On an idle system with a fixed number of active processors, the mach factor will be equal to the number of CPUs.
+.El
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.Xr sysctl 8
+.\" .Sh BUGS \" Document known, unremedied bugs
diff --git a/system_cmds/hostinfo.tproj/hostinfo.c b/system_cmds/hostinfo.tproj/hostinfo.c
new file mode 100644
index 0000000..1828583
--- /dev/null
+++ b/system_cmds/hostinfo.tproj/hostinfo.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1990 Carnegie-Mellon University
+ * All rights reserved. The CMU software License Agreement specifies
+ * the terms and conditions for use and redistribution.
+ */
+/*
+ * File: hostinfo.c
+ * Author: Avadis Tevanian, Jr.
+ *
+ * Copyright (C) 1987, Avadis Tevanian, Jr.
+ *
+ * Display information about the host this program is
+ * execting on.
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct host_basic_info hi;
+kernel_version_t version;
+int slots[1024];
+
+int
+main(int argc, char *argv[])
+{
+ kern_return_t ret;
+ unsigned int size, count;
+ char *cpu_name, *cpu_subname;
+ int mib[2];
+ size_t len;
+ uint64_t memsize;
+ processor_set_name_port_t default_pset;
+ host_name_port_t host;
+ struct processor_set_basic_info basic_info;
+ struct processor_set_load_info load_info;
+
+ host = mach_host_self();
+ ret = host_kernel_version(host, version);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+ printf("Mach kernel version:\n\t %s\n", version);
+ size = sizeof(hi)/sizeof(int);
+ ret = host_info(host, HOST_BASIC_INFO, (host_info_t)&hi, &size);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ ret = processor_set_default(host, &default_pset);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ count = PROCESSOR_SET_BASIC_INFO_COUNT;
+ ret = processor_set_info(default_pset, PROCESSOR_SET_BASIC_INFO,
+ &host, (processor_set_info_t)&basic_info, &count);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ count = PROCESSOR_SET_LOAD_INFO_COUNT;
+ ret = processor_set_statistics(default_pset, PROCESSOR_SET_LOAD_INFO,
+ (processor_set_info_t)&load_info, &count);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ unsigned int cpu_count = 0;
+ unsigned int data_count = 0;
+ struct processor_basic_info *processor_basic_infop = NULL;
+ ret = host_processor_info(host,
+ PROCESSOR_BASIC_INFO,
+ &cpu_count,
+ (processor_info_array_t *)&processor_basic_infop,
+ &data_count);
+ if (ret != KERN_SUCCESS) {
+ mach_error(argv[0], ret);
+ exit(EXIT_FAILURE);
+ }
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_MEMSIZE;
+ len = sizeof(memsize);
+ memsize = 0L;
+ if(sysctl(mib, 2, &memsize, &len, NULL, 0 ) == -1)
+ {
+ perror("sysctl");
+ exit(EXIT_FAILURE);
+ }
+
+ if (hi.max_cpus > 1)
+ printf("Kernel configured for up to %d processors.\n",
+ hi.max_cpus);
+ else
+ printf("Kernel configured for a single processor only.\n");
+ printf("%d processor%s physically available.\n", hi.physical_cpu,
+ (hi.physical_cpu > 1) ? "s are" : " is");
+
+ printf("%d processor%s logically available.\n", hi.logical_cpu,
+ (hi.logical_cpu > 1) ? "s are" : " is");
+
+ printf("Processor type:");
+ slot_name(hi.cpu_type, hi.cpu_subtype, &cpu_name, &cpu_subname);
+ printf(" %s (%s)\n", cpu_name, cpu_subname);
+
+ printf("Processor%s active:", (hi.avail_cpus > 1) ? "s" : "");
+ for (int i = 0; i < cpu_count; i++) {
+ if (processor_basic_infop[i].running) {
+ printf(" %d", i);
+ }
+ }
+ printf("\n");
+
+ if (((float)memsize / (1024.0 * 1024.0)) >= 1024.0)
+ printf("Primary memory available: %.2f gigabytes\n",
+ (float)memsize/(1024.0*1024.0*1024.0));
+ else
+ printf("Primary memory available: %.2f megabytes\n",
+ (float)memsize/(1024.0*1024.0));
+
+ printf("Default processor set: %d tasks, %d threads, %d processors\n",
+ load_info.task_count, load_info.thread_count, basic_info.processor_count);
+ printf("Load average: %d.%02d, Mach factor: %d.%02d\n",
+ load_info.load_average/LOAD_SCALE,
+ (load_info.load_average%LOAD_SCALE)/10,
+ load_info.mach_factor/LOAD_SCALE,
+ (load_info.mach_factor%LOAD_SCALE)/10);
+
+ exit(0);
+}
diff --git a/system_cmds/iosim.tproj/iosim.1 b/system_cmds/iosim.tproj/iosim.1
new file mode 100644
index 0000000..a3e8719
--- /dev/null
+++ b/system_cmds/iosim.tproj/iosim.1
@@ -0,0 +1,100 @@
+.\" Copyright (c) 2013, Apple Inc. All rights reserved.
+.\"
+.Dd Oct 9, 2013
+.Dt IOSIM 1
+.Sh NAME
+.Nm iosim
+.Nd A performance tool to simulate I/O workloads.
+.Sh SYNOPSIS
+.Pp
+.Nm iosim
+.Ar -c <number>
+Burst Count. No. of I/Os performed in an I/O burst.
+Default Value: 10
+Valid Range: [0, INT_MAX]
+.Pp
+.Nm iosim
+.Ar -i <msecs>
+Inter Burst Duration. Amount of time each thread sleeps between bursts (-1 indicates random durations between 0-100 msecs)
+Default Value: 0
+Valid Range: [-1, INT_MAX]
+.Pp
+.Nm iosim
+.Ar -d <msecs>
+Inter I/O delay. Amount of time thread sleeps between issuing I/Os
+Default Value: 0
+Valid Range: [0, INT_MAX]
+.Pp
+.Nm iosim
+.Ar -t <number>
+Thread count
+Default Value: 1
+Valid Range: [0, 1000]
+.Pp
+.Nm iosim
+.Ar -f <number>
+Workload Type (0/1/2 : Read-Only/Write-Only/Mixed RW)
+Default Value: 0
+Valid Range: [0, 2]
+.Pp
+.Nm iosim
+.Ar -m <number>
+I/O Pattern (0/1 : Sequential/Random)
+Default Value: 0
+Valid Range: [0, 1]
+.Pp
+.Nm iosim
+.Ar -j <bytes>
+Size of I/O in bytes
+Default Value: 4096
+Valid Range: [0, INT_MAX]
+.Pp
+.Nm iosim
+.Ar -s <msecs>
+Frequency of sync() calls
+Default Value: 5000
+Valid Range: [0, INT_MAX]
+.Pp
+.Nm iosim
+.Ar -l <number>
+I/O Tier (0/1/2/3)
+Default Value: 0
+Valid Range: [0, 3]
+.Pp
+.Nm iosim
+.Ar -z <number>
+Size of the file created specified in pages (Only used when the file is being created by the tool)
+Default Value: 1 GB
+Valid Range: [0, INT_MAX]
+.Pp
+.Nm iosim
+.Ar -x <secs>
+Test duration (0 indicates that the tool would wait for a Ctrl-C)
+Default Value: 0
+Valid Range: [0, INT_MAX]
+.Pp
+.Nm iosim
+.Ar -a number
+I/O Caching behavior (0/1 : Non-cached/Cached)
+Default Value: 0
+Valid Range: [0, 1]
+.Pp
+.Nm iosim
+.Ar -n <filename>
+Filename for I/Os (If this option is not specified, the tool would create files on its own)
+Valid Range: Valid filename
+.Sh DESCRIPTION
+The
+.Nm iosim
+tool allows simulating workloads for I/O performance evaluation. The tool spawns 'n' threads which issue non-cached I/Os. If specified, it also creates a sync thread which issues system wide sync() calls to flush data and metadata to disk (emulates launchd behavior). The I/Os are issued at the specified I/O tier and the tool reports latency and throughput numbers.
+.P
+.nf
+Following is an explanation of the results:
+Avg. Latency : Avg. latency experienced by the I/Os.
+Low Latency Histogram: Frequency distribution of I/O latency for low latency I/Os.
+Latency Histogram: Frequency distribution of I/O latency.
+Burst Avg. Latency Histogram: Frequency distribution of burst avg. latency.
+Throughput timeline: Time windowed throughput distrbution.
+.fi
+.Sh SEE ALSO
+.Xr fs_usage 1
diff --git a/system_cmds/iosim.tproj/iosim.c b/system_cmds/iosim.tproj/iosim.c
new file mode 100644
index 0000000..7a0efce
--- /dev/null
+++ b/system_cmds/iosim.tproj/iosim.c
@@ -0,0 +1,673 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <math.h>
+#include <signal.h>
+#include <libkern/OSAtomic.h>
+#include <limits.h>
+#include <errno.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include "panic.h"
+#include <IOKit/IOKitLib.h>
+#include <spawn.h>
+
+#define IO_MODE_SEQ 0
+#define IO_MODE_RANDOM 1
+
+#define WORKLOAD_TYPE_RO 0
+#define WORKLOAD_TYPE_WO 1
+#define WORKLOAD_TYPE_RW 2
+
+#define MAX_THREADS 1000
+#define MAX_FILENAME 64
+#define MAX_ITERATIONS 10000
+#define LATENCY_BIN_SIZE 1000
+#define LATENCY_BINS 31
+#define LOW_LATENCY_BIN_SIZE 50
+#define LOW_LATENCY_BINS 21
+#define THROUGHPUT_INTERVAL 5000
+#define DEFAULT_FILE_SIZE (262144)
+#define BLOCKSIZE 1024
+#define MAX_CMD_SIZE 256
+#define PG_MASK ~(0xFFF)
+#define kIONVMeANS2ControllerString "AppleANS2Controller"
+#define kIONVMeANS2EmbeddedControllerString "AppleANS2NVMeController"
+#define kIONVMeControllerString "AppleNVMeController"
+
+typedef enum {
+ kDefaultDevice = 0,
+ kNVMeDevice = 1,
+ kNVMeDeviceANS2 = 2,
+} qos_device_type_t;
+
+int burst_count = 10; /* Unit: Number ; Desc.: I/O Burst Count */
+int inter_burst_duration = 0; /* Unit: msecs ; Desc.: I/O Inter-Burst Duration (-1: Random value [0,100]) */
+int inter_io_delay_ms = 0; /* Unit: msecs ; Desc.: Inter I/O Delay */
+int thread_count = 1; /* Unit: Number ; Desc.: Thread Count */
+int workload_type = WORKLOAD_TYPE_RO; /* Unit: 0/1/2 ; Desc.: Workload Type */
+int io_size = 4096; /* Unit: Bytes ; Desc.: I/O Unit Size */
+int sync_frequency_ms = 0; /* Unit: msecs ; Desc.: Sync thread frequency (0: Indicates no sync) */
+int io_mode = 0; /* Unit: 0/1 ; Desc.: I/O Mode (Seq./Rand.) */
+int test_duration = 0; /* Unit: secs ; Desc.: Total Test Duration (0 indicates wait for Ctrl+C signal) */
+int io_tier = 0; /* Unit: 0/1/2/3; Desc.: I/O Tier */
+int file_size = DEFAULT_FILE_SIZE; /* Unit: pages ; Desc.: File Size in 4096 byte blocks */
+int cached_io_flag = 0; /* Unit: 0/1 ; Desc.: I/O Caching behavior (no-cached/cached) */
+int io_qos_timeout_ms = 0; /* Unit: msecs ; Desc.: I/O QOS timeout */
+char *user_fname;
+int user_specified_file = 0;
+qos_device_type_t qos_device = 0;
+
+int64_t total_io_count = 0;
+int64_t total_io_size = 0;
+int64_t total_io_time = 0;
+int64_t max_io_time = 0;
+int64_t total_burst_count = 0;
+int64_t latency_histogram[LATENCY_BINS];
+int64_t burst_latency_histogram[LATENCY_BINS];
+int64_t low_latency_histogram[LOW_LATENCY_BINS];
+int64_t throughput_histogram[MAX_ITERATIONS];
+int64_t throughput_index;
+CFRunLoopTimerRef runLoopTimer = NULL;
+
+void print_usage(void);
+void print_data_percentage(double percent);
+void print_stats(void);
+unsigned int find_io_bin(int64_t latency, int latency_bin_size, int latency_bins);
+void signalHandler(int sig);
+void assertASP(CFRunLoopTimerRef timer, void *info );
+void start_qos_timer(void);
+void stop_qos_timer(void);
+void perform_io(int fd, char *buf, int size, int type);
+void *sync_routine(void *arg);
+void *calculate_throughput(void *arg);
+void *io_routine(void *arg);
+void validate_option(int value, int min, int max, char *option, char *units);
+void print_test_setup(int value, char *option, char *units, char *comment);
+void setup_process_io_policy(int io_tier);
+void setup_qos_device(void);
+void print_latency_histogram(int64_t *data, int latency_bins, int latency_bin_size, double io_count);
+int system_cmd(char *command);
+
+void
+print_usage(void)
+{
+ printf("Usage: ./iosim [options]\n");
+ printf("Options:\n");
+ printf("-c: (number) Burst Count. No. of I/Os performed in an I/O burst\n");
+ printf("-i: (msecs) Inter Burst Duration. Amount of time the thread sleeps between bursts (-1 indicates random durations between 0-100 msecs)\n");
+ printf("-d: (msecs) Inter I/O delay. Amount of time between issuing I/Os\n");
+ printf("-t: (number) Thread count\n");
+ printf("-f: (0/1/2 : Read-Only/Write-Only/Mixed RW) Workload Type\n");
+ printf("-m: (0/1 : Sequential/Random) I/O pattern\n");
+ printf("-j: (number) Size of I/O in bytes\n");
+ printf("-s: (msecs) Frequency of sync() calls\n");
+ printf("-x: (secs) Test duration (0 indicates that the tool would wait for a Ctrl-C)\n");
+ printf("-l: (0/1/2/3) I/O Tier\n");
+ printf("-z: (number) File Size in pages (1 page = 4096 bytes) \n");
+ printf("-n: (string) File name used for tests (the tool would create files if this option is not specified)\n");
+ printf("-a: (0/1 : Non-cached/Cached) I/O Caching behavior\n");
+ printf("-q: (msecs) I/O QoS timeout. Time of I/O before drive assert and system panic\n");
+}
+
+void print_data_percentage(double percent)
+{
+ int count = (int)(round(percent / 5.0));
+ int spaces = 20 - count;
+ printf("| ");
+ for(; count > 0; count--)
+ printf("*");
+ for(; spaces > 0; spaces--)
+ printf(" ");
+ printf("|");
+}
+
+void print_latency_histogram(int64_t *data, int latency_bins, int latency_bin_size, double io_count)
+{
+ double percentage;
+ char label[MAX_FILENAME];
+ int i;
+
+ for (i = 0; i < latency_bins; i++) {
+ if (i == (latency_bins - 1))
+ snprintf(label, MAX_FILENAME, "> %d usecs", i * latency_bin_size);
+ else
+ snprintf(label, MAX_FILENAME, "%d - %d usecs", i * latency_bin_size, (i+1) * latency_bin_size);
+ printf("%25s ", label);
+ percentage = ((double)data[i] * 100.000000) / io_count;
+ print_data_percentage(percentage);
+ printf(" %.6lf%%\n", percentage);
+ }
+ printf("\n");
+}
+
+void print_stats()
+{
+ int i;
+ double percentage;
+ char label[MAX_FILENAME];
+
+ printf("I/O Statistics:\n");
+
+ printf("Total I/Os : %lld\n", total_io_count);
+ printf("Avg. Latency : %.2lf usecs\n", ((double)total_io_time) / ((double)total_io_count));
+ printf("Max. Latency : %.2lf usecs\n", ((double)max_io_time));
+
+ printf("Low Latency Histogram: \n");
+ print_latency_histogram(low_latency_histogram, LOW_LATENCY_BINS, LOW_LATENCY_BIN_SIZE, (double)total_io_count);
+ printf("Latency Histogram: \n");
+ print_latency_histogram(latency_histogram, LATENCY_BINS, LATENCY_BIN_SIZE, (double)total_io_count);
+ printf("Burst Avg. Latency Histogram: \n");
+ print_latency_histogram(burst_latency_histogram, LATENCY_BINS, LATENCY_BIN_SIZE, (double)total_burst_count);
+
+ printf("Throughput Timeline: \n");
+
+ int64_t max_throughput = 0;
+ for (i = 0; i < throughput_index; i++) {
+ if (max_throughput < throughput_histogram[i])
+ max_throughput = throughput_histogram[i];
+ }
+
+ for (i = 0; i < throughput_index; i++) {
+ snprintf(label, MAX_FILENAME, "T=%d msecs", (i+1) * THROUGHPUT_INTERVAL);
+ printf("%25s ", label);
+ percentage = ((double)throughput_histogram[i] * 100) / (double)max_throughput;
+ print_data_percentage((int)percentage);
+ printf("%.2lf MBps\n", ((double)throughput_histogram[i] / 1048576.0) / ((double)THROUGHPUT_INTERVAL / 1000.0));
+ }
+ printf("\n");
+}
+
+unsigned int find_io_bin(int64_t latency, int latency_bin_size, int latency_bins)
+{
+ int bin = (int) (latency / latency_bin_size);
+ if (bin >= latency_bins)
+ bin = latency_bins - 1;
+ return bin;
+}
+
+void signalHandler(int sig)
+{
+ printf("\n");
+ print_stats();
+ exit(0);
+}
+
+void setup_qos_device(void)
+{
+ kern_return_t status = kIOReturnError;
+ io_iterator_t iterator = IO_OBJECT_NULL;
+
+ if(io_qos_timeout_ms <= 0)
+ return;
+
+ printf ( "*** setup_qos_device *** \n" );
+
+ status = IOServiceGetMatchingServices ( kIOMasterPortDefault, IOServiceMatching ( kIONVMeANS2ControllerString ), &iterator );
+
+ if ( status != kIOReturnSuccess )
+ return;
+
+ if ( iterator != IO_OBJECT_NULL ) {
+ printf ( "Found NVMe ANS2 Device \n" );
+ qos_device = kNVMeDeviceANS2;
+ return;
+ }
+
+ status = IOServiceGetMatchingServices ( kIOMasterPortDefault, IOServiceMatching ( kIONVMeANS2EmbeddedControllerString ), &iterator );
+
+ if ( status != kIOReturnSuccess )
+ return;
+
+ if ( iterator != IO_OBJECT_NULL ) {
+ printf ( "Found NVMe ANS2 Embedded Device \n" );
+ qos_device = kNVMeDeviceANS2;
+ return;
+ }
+
+ status= IOServiceGetMatchingServices ( kIOMasterPortDefault, IOServiceMatching ( kIONVMeControllerString ), &iterator );
+
+ if ( status != kIOReturnSuccess )
+ return;
+
+ if ( iterator != IO_OBJECT_NULL ) {
+ printf ( "Found NVMe Device \n" );
+ qos_device = kNVMeDevice;
+ return;
+ }
+
+ printf ( "NVMe Device not found, not setting qos timeout\n" );
+ qos_device = kDefaultDevice;
+ return;
+}
+
+void assertASP(CFRunLoopTimerRef timer, void *info )
+{
+ char command [ 1024 ];
+
+ if(qos_device == kDefaultDevice)
+ return;
+
+ printf("assertASP. Timeout of IO exceeds = %d msec\n", io_qos_timeout_ms);
+
+ // kNVMe_ANS2_Force_Assert_offset = 0x13EC, // GP59
+ // kNVMe_Force_Assert_Offset = 0x550,
+
+ if(qos_device == kNVMeDeviceANS2)
+ snprintf ( command, sizeof ( command ), "/usr/local/bin/nvmectl-tool.py -a WriteRegister32 $((0x13EC)) 0xFFFF" );
+ else if(qos_device == kNVMeDevice)
+ snprintf ( command, sizeof ( command ), "/usr/local/bin/nvmectl-tool.py -a WriteRegister32 $((0x550)) 0xFFFF" );
+ else
+ return;
+
+ // Assert ASP
+ printf("Command : %s\n", command);
+ system_cmd(command);
+
+ // Panic the system as well
+ panic("IO time > QoS timeout");
+
+ return;
+}
+
+void start_qos_timer(void)
+{
+ float timeout_sec;
+
+ if(io_qos_timeout_ms <= 0)
+ return;
+
+ timeout_sec = (float)io_qos_timeout_ms/1000;
+
+ // Schedule a "timeout" delayed task that checks IO's which take > timeout sec to complete
+ runLoopTimer = CFRunLoopTimerCreate(NULL, CFAbsoluteTimeGetCurrent()+timeout_sec, 0, 0, 0, assertASP, NULL);
+ CFRunLoopAddTimer(CFRunLoopGetMain(), runLoopTimer, kCFRunLoopDefaultMode);
+}
+
+void stop_qos_timer(void)
+{
+ if(runLoopTimer == NULL)
+ return;
+
+ CFRunLoopTimerInvalidate(runLoopTimer);
+ CFRunLoopRemoveTimer(CFRunLoopGetMain(), runLoopTimer, kCFRunLoopDefaultMode);
+ CFRelease(runLoopTimer);
+}
+
+void perform_io(int fd, char *buf, int size, int type)
+{
+ long ret;
+
+ if (type == WORKLOAD_TYPE_RW)
+ type = (rand() % 2) ? WORKLOAD_TYPE_WO : WORKLOAD_TYPE_RO;
+
+ while(size > 0) {
+
+ if (type == WORKLOAD_TYPE_RO)
+ ret = read(fd, buf, size);
+ else
+ ret = write(fd, buf, size);
+
+ if (ret == 0) {
+ if (lseek(fd, 0, SEEK_SET) < 0) {
+ perror("lseek() to reset file offset to zero failed!\n");
+ goto error;
+ }
+ }
+
+ if (ret < 0) {
+ perror("read/write syscall failed!\n");
+ goto error;
+ }
+ size -= ret;
+ }
+
+ return;
+
+error:
+ print_stats();
+ exit(1);
+}
+
+void *sync_routine(void *arg)
+{
+ while(1) {
+ usleep(sync_frequency_ms * 1000);
+ sync();
+ }
+ pthread_exit(NULL);
+}
+
+void *calculate_throughput(void *arg)
+{
+ int64_t prev_total_io_size = 0;
+ int64_t size;
+
+ while(1) {
+ usleep(THROUGHPUT_INTERVAL * 1000);
+ size = total_io_size - prev_total_io_size;
+ throughput_histogram[throughput_index] = size;
+ prev_total_io_size = total_io_size;
+ throughput_index++;
+ }
+ pthread_exit(NULL);
+}
+
+void *io_routine(void *arg)
+{
+ struct timeval start_tv;
+ struct timeval end_tv;
+ int64_t elapsed;
+ int64_t burst_elapsed;
+ char *data;
+ char test_filename[MAX_FILENAME];
+ struct stat filestat;
+ int i, fd, io_thread_id;
+
+ io_thread_id = (int)arg;
+ if (user_specified_file)
+ strlcpy(test_filename, user_fname, MAX_FILENAME);
+ else
+ snprintf(test_filename, MAX_FILENAME, "iosim-%d-%d", (int)getpid(), io_thread_id);
+
+ if (0 > (fd = open(test_filename, O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
+ printf("Error opening file %s!\n", test_filename);
+ exit(1);
+ }
+
+ if (fstat(fd, &filestat) < 0) {
+ printf("Error stat()ing file %s!\n", test_filename);
+ exit(1);
+ }
+
+ if (filestat.st_size < io_size) {
+ printf("%s: File size (%lld) smaller than I/O size (%d)!\n", test_filename, filestat.st_size, io_size);
+ exit(1);
+ }
+
+ if (!cached_io_flag)
+ fcntl(fd, F_NOCACHE, 1);
+
+ fcntl(fd, F_RDAHEAD, 0);
+
+ if(!(data = (char *)calloc(io_size, 1))) {
+ perror("Error allocating buffers for I/O!\n");
+ exit(1);
+ }
+ memset(data, '\0', io_size);
+
+ while(1) {
+ burst_elapsed = 0;
+
+ for(i = 0; i < burst_count; i++) {
+ if (io_mode == IO_MODE_RANDOM) {
+ if (lseek(fd, (rand() % (filestat.st_size - io_size)) & PG_MASK, SEEK_SET) < 0) {
+ perror("Error lseek()ing to random location in file!\n");
+ exit(1);
+ }
+ }
+
+ start_qos_timer();
+
+ gettimeofday(&start_tv, NULL);
+ perform_io(fd, data, io_size, workload_type);
+ gettimeofday(&end_tv, NULL);
+
+ stop_qos_timer();
+
+ OSAtomicIncrement64(&total_io_count);
+ OSAtomicAdd64(io_size, &total_io_size);
+ elapsed = ((end_tv.tv_sec - start_tv.tv_sec) * 1000000) + (end_tv.tv_usec - start_tv.tv_usec);
+
+ if (elapsed > max_io_time) {
+ max_io_time = elapsed;
+ }
+
+ OSAtomicAdd64(elapsed, &total_io_time);
+ OSAtomicIncrement64(&(latency_histogram[find_io_bin(elapsed, LATENCY_BIN_SIZE, LATENCY_BINS)]));
+ OSAtomicIncrement64(&(low_latency_histogram[find_io_bin(elapsed, LOW_LATENCY_BIN_SIZE, LOW_LATENCY_BINS)]));
+ burst_elapsed += elapsed;
+
+ if (inter_io_delay_ms)
+ usleep(inter_io_delay_ms * 1000);
+ }
+
+ burst_elapsed /= burst_count;
+ OSAtomicIncrement64(&(burst_latency_histogram[find_io_bin(burst_elapsed, LATENCY_BIN_SIZE, LATENCY_BINS)]));
+ OSAtomicIncrement64(&total_burst_count);
+
+ if(inter_burst_duration == -1)
+ usleep((rand() % 100) * 1000);
+ else
+ usleep(inter_burst_duration * 1000);
+ }
+
+ free(data);
+ close(fd);
+ pthread_exit(NULL);
+}
+
+void validate_option(int value, int min, int max, char *option, char *units)
+{
+ if (value < min || value > max) {
+ printf("Illegal option value %d for %s (Min value: %d %s, Max value: %d %s).\n", value, option, min, units, max, units);
+ exit(1);
+ }
+}
+
+void print_test_setup(int value, char *option, char *units, char *comment)
+{
+ if (comment == NULL)
+ printf("%32s: %16d %-16s\n", option, value, units);
+ else
+ printf("%32s: %16d %-16s (%s)\n", option, value, units, comment);
+}
+
+void setup_process_io_policy(int io_tier)
+{
+ switch(io_tier)
+ {
+ case 0:
+ if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_IMPORTANT))
+ goto iopol_error;
+ break;
+ case 1:
+ if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_STANDARD))
+ goto iopol_error;
+ break;
+ case 2:
+ if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_UTILITY))
+ goto iopol_error;
+ break;
+ case 3:
+ if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE))
+ goto iopol_error;
+ break;
+ }
+ return;
+
+iopol_error:
+ printf("Error setting process-wide I/O policy to %d\n", io_tier);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int i, option = 0;
+ pthread_t thread_list[MAX_THREADS];
+ pthread_t sync_thread;
+ pthread_t throughput_thread;
+ char fname[MAX_FILENAME];
+
+ while((option = getopt(argc, argv,"hc:i:d:t:f:m:j:s:x:l:z:n:a:q:")) != -1) {
+ switch(option) {
+ case 'c':
+ burst_count = atoi(optarg);
+ validate_option(burst_count, 0, INT_MAX, "Burst Count", "I/Os");
+ break;
+ case 'i':
+ inter_burst_duration = atoi(optarg);
+ validate_option(inter_burst_duration, -1, INT_MAX, "Inter Burst duration", "msecs");
+ break;
+ case 'd':
+ inter_io_delay_ms = atoi(optarg);
+ validate_option(inter_io_delay_ms, 0, INT_MAX, "Inter I/O Delay", "msecs");
+ break;
+ case 't':
+ thread_count = atoi(optarg);
+ validate_option(thread_count, 0, MAX_THREADS, "Thread Count", "Threads");
+ break;
+ case 'f':
+ workload_type = atoi(optarg);
+ validate_option(workload_type, 0, 2, "Workload Type", "");
+ break;
+ case 'm':
+ io_mode = atoi(optarg);
+ validate_option(io_mode, 0, 1, "I/O Mode", "");
+ break;
+ case 'j':
+ io_size = atoi(optarg);
+ validate_option(io_size, 0, INT_MAX, "I/O Size", "Bytes");
+ break;
+ case 'h':
+ print_usage();
+ exit(1);
+ case 's':
+ sync_frequency_ms = atoi(optarg);
+ validate_option(sync_frequency_ms, 0, INT_MAX, "Sync. Frequency", "msecs");
+ break;
+ case 'x':
+ test_duration = atoi(optarg);
+ validate_option(test_duration, 0, INT_MAX, "Test duration", "secs");
+ break;
+ case 'l':
+ io_tier = atoi(optarg);
+ validate_option(io_tier, 0, 3, "I/O Tier", "");
+ break;
+ case 'z':
+ file_size = atoi(optarg);
+ validate_option(file_size, 0, INT_MAX, "File Size", "bytes");
+ break;
+ case 'n':
+ user_fname = optarg;
+ user_specified_file = 1;
+ break;
+ case 'a':
+ cached_io_flag = atoi(optarg);
+ validate_option(cached_io_flag, 0, 1, "I/Os cached/no-cached", "");
+ break;
+ case 'q':
+ io_qos_timeout_ms = atoi(optarg);
+ validate_option(io_qos_timeout_ms, 0, INT_MAX, "I/O QoS timeout", "msecs");
+ break;
+ default:
+ printf("Unknown option %c\n", option);
+ print_usage();
+ exit(1);
+ }
+ }
+
+ printf("***********************TEST SETUP*************************\n");
+
+ print_test_setup(burst_count, "Burst Count", "I/Os", 0);
+ print_test_setup(inter_burst_duration, "Inter Burst duration", "msecs", "-1 indicates random burst duration");
+ print_test_setup(inter_io_delay_ms, "Inter I/O Delay", "msecs", 0);
+ print_test_setup(thread_count, "Thread Count", "Threads", 0);
+ print_test_setup(workload_type, "Workload Type", "", "0:R 1:W 2:RW");
+ print_test_setup(io_mode, "I/O Mode", "", "0:Seq. 1:Rnd");
+ print_test_setup(io_size, "I/O Size", "Bytes", 0);
+ print_test_setup(sync_frequency_ms, "Sync. Frequency", "msecs", "0 indicates no sync. thread");
+ print_test_setup(test_duration, "Test duration", "secs", "0 indicates tool waits for Ctrl+C");
+ print_test_setup(io_tier, "I/O Tier", "", 0);
+ print_test_setup(cached_io_flag, "I/O Caching", "", "0 indicates non-cached I/Os");
+ print_test_setup(io_qos_timeout_ms, "I/O QoS Threshold Timeout", "msecs", 0);
+ print_test_setup(0, "File read-aheads", "", "0 indicates read-aheads disabled");
+
+ printf("**********************************************************\n");
+
+ if (user_specified_file == 0) {
+ char dd_command[MAX_CMD_SIZE];
+ for (i=0; i < thread_count; i++) {
+ snprintf(fname, MAX_FILENAME, "iosim-%d-%d", (int)getpid(), i);
+ snprintf(dd_command, MAX_CMD_SIZE, "dd if=/dev/urandom of=%s bs=4096 count=%d", fname, file_size);
+ printf("Creating file %s of size %lld...\n", fname, ((int64_t)file_size * 4096));
+ system_cmd(dd_command);
+ }
+ } else {
+ printf("Using user specified file %s for all threads...\n", user_fname);
+ }
+ system_cmd("purge");
+ setup_process_io_policy(io_tier);
+
+ setup_qos_device();
+
+ printf("**********************************************************\n");
+ printf("Creating threads and generating workload...\n");
+
+ signal(SIGINT, signalHandler);
+ signal(SIGALRM, signalHandler);
+
+ for(i=0; i < thread_count; i++) {
+ if (pthread_create(&thread_list[i], NULL, io_routine, i) < 0) {
+ perror("Could not create I/O thread!\n");
+ exit(1);
+ }
+ }
+
+ if (sync_frequency_ms) {
+ if (pthread_create(&sync_thread, NULL, sync_routine, NULL) < 0) {
+ perror("Could not create sync thread!\n");
+ exit(1);
+ }
+ }
+
+ if (pthread_create(&throughput_thread, NULL, calculate_throughput, NULL) < 0) {
+ perror("Could not throughput calculation thread!\n");
+ exit(1);
+ }
+
+ if(io_qos_timeout_ms > 0) {
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, (CFTimeInterval)test_duration, false);
+ alarm(1);
+ } else {
+ /* All threads are now initialized */
+ if (test_duration)
+ alarm(test_duration);
+ }
+
+ for(i=0; i < thread_count; i++)
+ pthread_join(thread_list[i], NULL);
+
+ if (sync_frequency_ms)
+ pthread_join(sync_thread, NULL);
+
+ pthread_join(throughput_thread, NULL);
+
+ pthread_exit(0);
+}
+
+extern char **environ;
+
+int system_cmd(char *command)
+{
+ // workaround for rdar://problem/53281655
+ pid_t pid;
+ char *argv[] = {"sh", "-c", command, NULL};
+ int status;
+ status = posix_spawn(&pid, "/bin/sh", NULL, NULL, argv, environ);
+ if (status == 0) {
+ if (waitpid(pid, &status, 0) != -1) {
+ return status;
+ } else {
+ perror("waitpid");
+ }
+ }
+ return -1;
+}
diff --git a/system_cmds/iostat.tproj/iostat.8 b/system_cmds/iostat.tproj/iostat.8
new file mode 100644
index 0000000..f79c834
--- /dev/null
+++ b/system_cmds/iostat.tproj/iostat.8
@@ -0,0 +1,302 @@
+.\"
+.\" Copyright (c) 1997 Kenneth D. Merry.
+.\" 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. 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.
+.\"
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" @(#)iostat.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd May 22, 2015
+.Dt IOSTAT 8
+.Os
+.Sh NAME
+.Nm iostat
+.Nd report
+.Tn I/O
+statistics
+.Sh SYNOPSIS
+.Nm
+.Op Fl CUdKIoT?\&
+.Op Fl c Ar count
+.Op Fl n Ar devs
+.Op Fl w Ar wait
+.Op Ar drives
+.Sh DESCRIPTION
+The
+.Nm
+utility displays kernel
+.Tn I/O
+statistics on terminal, device and cpu operations.
+The first statistics that are printed are averaged over the system uptime.
+To get information about the current activity, a suitable wait time should
+be specified, so that the subsequent sets of printed statistics will be
+averaged over that time.
+.Pp
+The options are as follows:
+.Bl -tag -width flag
+.It Fl ?\&
+Display a usage statement and exit.
+.It Fl c
+Repeat the display
+.Ar count
+times.
+If no
+.Ar wait
+interval is specified, the default is 1 second.
+.It Fl C
+Display CPU statistics.
+This is on by default, unless
+.Fl d
+is specified.
+.It Fl d
+Display only device statistics.
+If this flag is turned on, only device statistics will be displayed, unless
+.Fl C
+or
+.Fl U
+or
+.Fl T
+is also specified to enable the display of CPU, load average or TTY statistics.
+.It Fl I
+Display total statistics for a given time period, rather than average
+statistics for each second during that time period.
+.It Fl K
+In the blocks transferred display (-o), display block count in kilobytes rather
+then the device native block size.
+.It Fl n
+Display up to
+.Ar devs
+number of devices.
+The
+.Nm
+utility will display fewer devices if there are not
+.Ar devs
+devices present.
+.It Fl o
+Display old-style
+.Nm
+device statistics.
+Sectors per second, transfers per second, and milliseconds per seek are
+displayed.
+If
+.Fl I
+is specified, total blocks/sectors, total transfers, and
+milliseconds per seek are displayed.
+.It Fl T
+Display TTY statistics.
+This is on by default, unless
+.Fl d
+is specified.
+.It Fl U
+Display system load averages.
+This is on by default, unless
+.Fl d
+is specified.
+.It Fl w
+Pause
+.Ar wait
+seconds between each display.
+If no repeat
+.Ar count
+is specified, the default is infinity.
+.El
+.Pp
+The
+.Nm
+utility displays its information in the following format:
+.Bl -tag -width flag
+.It tty
+.Bl -tag -width indent -compact
+.It tin
+characters read from terminals
+.It tout
+characters written to terminals
+.El
+.It devices
+Device operations.
+The header of the field is the device name and unit number.
+The
+.Nm
+utility
+will display as many devices as will fit in a standard 80 column screen, or
+the maximum number of devices in the system, whichever is smaller.
+If
+.Fl n
+is specified on the command line,
+.Nm
+will display the smaller of the
+requested number of devices, and the maximum number of devices in the system.
+To force
+.Nm
+to display specific drives, their names may be supplied on the command
+line.
+The
+.Nm
+utility
+will not display more devices than will fit in an 80 column screen, unless
+the
+.Fl n
+argument is given on the command line to specify a maximum number of
+devices to display, or the list of specified devices exceeds 80 columns.
+If fewer devices are specified on the command line than will fit in an 80
+column screen,
+.Nm
+will show only the specified devices.
+.Pp
+The standard
+.Nm
+device display shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It KB/t
+kilobytes per transfer
+.It tps
+transfers per second
+.It MB/s
+megabytes per second
+.El
+.Pp
+The standard
+.Nm
+device display, with the
+.Fl I
+flag specified, shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It KB/t
+kilobytes per transfer
+.It xfrs
+total number of transfers
+.It MB
+total number of megabytes transferred
+.El
+.Pp
+The old-style
+.Nm
+display (using
+.Fl o )
+shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It sps
+sectors transferred per second
+.It tps
+transfers per second
+.It msps
+average milliseconds per transaction
+.El
+.Pp
+The old-style
+.Nm
+display, with the
+.Fl I
+flag specified, shows the following statistics:
+.Pp
+.Bl -tag -width indent -compact
+.It blk
+total blocks/sectors transferred
+.It xfr
+total transfers
+.It msps
+average milliseconds per transaction
+.El
+.It cpu
+.Bl -tag -width indent -compact
+.It \&us
+% of cpu time in user mode
+.It \&sy
+% of cpu time in system mode
+.It \&id
+% of cpu time in idle mode
+.El
+.El
+.Sh EXAMPLES
+.Dl iostat -w 1 disk0 disk2
+.Pp
+Display statistics for the first and third disk devices device every
+second ad infinitum.
+.Pp
+.Dl iostat -c 2
+.Pp
+Display the statistics for the first four devices in the system twice, with
+a one second display interval.
+.Pp
+.Dl iostat -Iw 3
+.Pp
+Display total statistics every three seconds ad infinitum.
+.Pp
+.Dl iostat -odICTw 2 -c 9
+.Pp
+Display total statistics using the old-style output format 9 times, with
+a two second interval between each measurement/display.
+The
+.Fl d
+flag generally disables the TTY and CPU displays, but since the
+.Fl T
+and
+.Fl C
+flags are given, the TTY and CPU displays will be displayed.
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr nfsstat 1 ,
+.Xr ps 1 ,
+.Xr top 1 ,
+.Xr vm_stat 1
+.Pp
+The sections starting with ``Interpreting system activity'' in
+.%T "Installing and Operating 4.3BSD" .
+.Sh HISTORY
+This version of
+.Nm
+first appeared in
+.Fx 3.0 .
diff --git a/system_cmds/iostat.tproj/iostat.c b/system_cmds/iostat.tproj/iostat.c
new file mode 100644
index 0000000..a9c73cb
--- /dev/null
+++ b/system_cmds/iostat.tproj/iostat.c
@@ -0,0 +1,998 @@
+/*
+ * Copyright (c) 1999-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1997, 1998, 2000, 2001 Kenneth D. Merry
+ * 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. 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.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Parts of this program are derived from the original FreeBSD iostat
+ * program:
+ */
+/*-
+ * Copyright (c) 1986, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Ideas for the new iostat statistics output modes taken from the NetBSD
+ * version of iostat:
+ */
+/*
+ * Copyright (c) 1996 John M. Vinopal
+ * 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 for the NetBSD Project
+ * by John M. Vinopal.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#define IOKIT 1 /* to get io_name_t in device_types.h */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/storage/IOBlockStorageDriver.h>
+#include <IOKit/storage/IOMedia.h>
+#include <IOKit/IOBSD.h>
+#include <mach/mach_host.h> /* host_statistics */
+#include <err.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAXDRIVES 16 /* most drives we will record */
+#define MAXDRIVENAME 31 /* largest drive name we allow */
+
+struct drivestats {
+ io_registry_entry_t driver;
+ char name[MAXDRIVENAME + 1];
+ u_int64_t blocksize;
+ u_int64_t total_bytes;
+ u_int64_t total_transfers;
+ u_int64_t total_time;
+};
+
+static struct drivestats drivestat[MAXDRIVES];
+
+static struct timeval cur_time, last_time;
+
+struct statinfo {
+ long tk_nin;
+ long tk_nout;
+ host_cpu_load_info_data_t load;
+};
+
+static struct statinfo cur, last;
+
+static mach_port_t host_priv_port;
+static mach_port_t masterPort;
+
+static int num_devices;
+static int maxshowdevs;
+static int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Uflag = 0, Kflag = 0;
+static volatile sig_atomic_t phdr_flag = 0;
+static IONotificationPortRef notifyPort;
+
+/* local function declarations */
+static void usage(void);
+static void phdr(int signo);
+static void do_phdr(void);
+static void devstats(int perf_select, long double etime, int havelast);
+static void cpustats(void);
+static void loadstats(void);
+static int readvar(const char *name, void *ptr, size_t len);
+
+static int record_all_devices(void);
+static void record_drivelist(void* context, io_iterator_t drivelist);
+static void remove_drivelist(void* context, io_iterator_t drivelist);
+static int record_one_device(char *name);
+static int record_device(io_registry_entry_t drive);
+
+static int compare_drivestats(const void* pa, const void* pb);
+
+static long double compute_etime(struct timeval cur_time,
+ struct timeval prev_time);
+
+static void
+usage(void)
+{
+ /*
+ * We also support the following 'traditional' syntax:
+ * iostat [drives] [wait [count]]
+ * This isn't mentioned in the man page, or the usage statement,
+ * but it is supported.
+ */
+ fprintf(stderr, "usage: iostat [-CUdIKoT?] [-c count] [-n devs]\n"
+ "\t [-w wait] [drives]\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int hflag = 0, cflag = 0, wflag = 0, nflag = 0;
+ int count = 0, waittime = 0;
+ int headercount;
+ int num_devices_specified;
+ int havelast = 0;
+
+ CFRunLoopSourceRef rls;
+
+ maxshowdevs = 3;
+
+ while ((c = getopt(argc, argv, "c:CdIKM:n:oTUw:?")) != -1) {
+ switch(c) {
+ case 'c':
+ cflag++;
+ count = atoi(optarg);
+ if (count < 1)
+ errx(1, "count %d is < 1", count);
+ break;
+ case 'C':
+ Cflag++;
+ break;
+ case 'd':
+ dflag++;
+ break;
+ case 'I':
+ Iflag++;
+ break;
+ case 'K':
+ Kflag++;
+ break;
+ case 'n':
+ nflag++;
+ maxshowdevs = atoi(optarg);
+ if (maxshowdevs < 0)
+ errx(1, "number of devices %d is < 0",
+ maxshowdevs);
+ break;
+ case 'o':
+ oflag++;
+ break;
+ case 'T':
+ Tflag++;
+ break;
+ case 'U':
+ Uflag++;
+ break;
+ case 'w':
+ wflag++;
+ waittime = atoi(optarg);
+ if (waittime < 1)
+ errx(1, "wait time is < 1");
+ break;
+ default:
+ usage();
+ exit(1);
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * Get the Mach private port.
+ */
+ host_priv_port = mach_host_self();
+
+ /*
+ * Get the I/O Kit communication handle.
+ */
+ IOMasterPort(bootstrap_port, &masterPort);
+
+ notifyPort = IONotificationPortCreate(masterPort);
+ rls = IONotificationPortGetRunLoopSource(notifyPort);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+
+ /*
+ * Make sure Tflag, Cflag and Uflag are set if dflag == 0. If dflag is
+ * greater than 0, they may be 0 or non-zero.
+ */
+ if (dflag == 0) {
+ Cflag = 1;
+ Tflag = 1;
+ Uflag = 1;
+ }
+
+ /*
+ * TTY statistics are broken, disabling them.
+ */
+ Tflag = 0;
+
+ /*
+ * Figure out how many devices we should display if not given
+ * an explicit value.
+ */
+ if (nflag == 0) {
+ if (oflag > 0) {
+ if ((dflag > 0) && (Cflag == 0) && (Tflag == 0))
+ maxshowdevs = 5;
+ else if ((dflag > 0) && (Tflag > 0) && (Cflag == 0))
+ maxshowdevs = 5;
+ else
+ maxshowdevs = 4;
+ } else {
+ if ((dflag > 0) && (Cflag == 0))
+ maxshowdevs = 4;
+ else
+ maxshowdevs = 3;
+ }
+ }
+
+ /*
+ * If the user specified any devices on the command line, record
+ * them for monitoring.
+ */
+ for (num_devices_specified = 0; *argv; ++argv) {
+ if (isdigit(**argv))
+ break;
+ if (record_one_device(*argv))
+ errx(1, "can't record '%s' for monitoring", *argv);
+ num_devices_specified++;
+ }
+ if (nflag == 0 && maxshowdevs < num_devices_specified)
+ maxshowdevs = num_devices_specified;
+
+ /* if no devices were specified, pick them ourselves */
+ if ((num_devices_specified == 0) && record_all_devices())
+ err(1, "can't find any devices to display");
+
+ /*
+ * Look for the traditional wait time and count arguments.
+ */
+ if (*argv) {
+ waittime = atoi(*argv);
+
+ /* Let the user know he goofed, but keep going anyway */
+ if (wflag != 0)
+ warnx("discarding previous wait interval, using"
+ " %d instead", waittime);
+ wflag++;
+
+ if (*++argv) {
+ count = atoi(*argv);
+ if (cflag != 0)
+ warnx("discarding previous count, using %d"
+ " instead", count);
+ cflag++;
+ } else
+ count = -1;
+ }
+
+ /*
+ * If the user specified a count, but not an interval, we default
+ * to an interval of 1 second.
+ */
+ if ((wflag == 0) && (cflag > 0))
+ waittime = 1;
+
+ /*
+ * If the user specified a wait time, but not a count, we want to
+ * go on ad infinitum. This can be redundant if the user uses the
+ * traditional method of specifying the wait, since in that case we
+ * already set count = -1 above. Oh well.
+ */
+ if ((wflag > 0) && (cflag == 0))
+ count = -1;
+
+ cur.tk_nout = 0;
+ cur.tk_nin = 0;
+
+ /*
+ * Set the busy time to the system boot time, so the stats are
+ * calculated since system boot.
+ */
+ if (readvar("kern.boottime", &cur_time, sizeof(cur_time)) != 0)
+ exit(1);
+
+ /*
+ * If the user stops the program (control-Z) and then resumes it,
+ * print out the header again.
+ */
+ (void)signal(SIGCONT, phdr);
+
+ for (headercount = 1;;) {
+ long tmp;
+ long double etime;
+
+ if (Tflag > 0) {
+ if ((readvar("kern.tty_nin", &cur.tk_nin,
+ sizeof(cur.tk_nin)) != 0)
+ || (readvar("kern.tty_nout",
+ &cur.tk_nout, sizeof(cur.tk_nout))!= 0)) {
+ Tflag = 0;
+ warnx("disabling TTY statistics");
+ }
+ }
+
+ if (!--headercount || phdr_flag) {
+ phdr_flag = 0;
+ headercount = 20;
+ do_phdr();
+ }
+
+ last_time = cur_time;
+ gettimeofday(&cur_time, NULL);
+
+ if (Tflag > 0) {
+ tmp = cur.tk_nin;
+ cur.tk_nin -= last.tk_nin;
+ last.tk_nin = tmp;
+ tmp = cur.tk_nout;
+ cur.tk_nout -= last.tk_nout;
+ last.tk_nout = tmp;
+ }
+
+ etime = compute_etime(cur_time, last_time);
+
+ if (etime == 0.0)
+ etime = 1.0;
+
+ if (Tflag > 0)
+ printf("%4.0Lf%5.0Lf", cur.tk_nin / etime,
+ cur.tk_nout / etime);
+
+ devstats(hflag, etime, havelast);
+
+ if (Cflag > 0)
+ cpustats();
+
+ if (Uflag > 0)
+ loadstats();
+
+ printf("\n");
+ fflush(stdout);
+
+ if (count >= 0 && --count <= 0)
+ break;
+
+ /*
+ * Instead of sleep(waittime), wait in
+ * the RunLoop for IONotifications.
+ */
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, (CFTimeInterval)waittime, 1);
+
+ havelast = 1;
+ }
+
+ exit(0);
+}
+
+static void
+phdr(int signo)
+{
+
+ phdr_flag = 1;
+}
+
+static void
+do_phdr(void)
+{
+ register int i;
+
+ if (Tflag > 0)
+ (void)printf(" tty");
+
+ for (i = 0; i < num_devices && i < maxshowdevs; i++){
+ if (oflag > 0)
+ (void)printf("%12.6s ", drivestat[i].name);
+ else
+ printf("%19.6s ", drivestat[i].name);
+ }
+
+ if (Cflag > 0)
+ (void)printf(" cpu");
+
+ if (Uflag > 0)
+ (void)printf(" load average\n");
+ else
+ (void)printf("\n");
+
+ if (Tflag > 0)
+ (void)printf(" tin tout");
+
+ for (i=0; i < num_devices && i < maxshowdevs; i++){
+ if (oflag > 0) {
+ if (Iflag == 0)
+ (void)printf(" sps tps msps ");
+ else
+ (void)printf(" blk xfr msps ");
+ } else {
+ if (Iflag == 0)
+ printf(" KB/t tps MB/s ");
+ else
+ printf(" KB/t xfrs MB ");
+ }
+ }
+
+ if (Cflag > 0)
+ (void)printf(" us sy id");
+
+ if (Uflag > 0)
+ (void)printf(" 1m 5m 15m\n");
+ else
+ printf("\n");
+}
+
+static void
+devstats(int perf_select, long double etime, int havelast)
+{
+ CFNumberRef number;
+ CFDictionaryRef properties;
+ CFDictionaryRef statistics;
+ long double transfers_per_second;
+ long double kb_per_transfer, mb_per_second;
+ u_int64_t value;
+ u_int64_t total_bytes, total_transfers, total_blocks, total_time;
+ u_int64_t interval_bytes, interval_transfers, interval_blocks;
+ u_int64_t interval_time;
+ long double interval_mb;
+ long double blocks_per_second, ms_per_transaction;
+ kern_return_t status;
+ int i;
+
+ for (i = 0; i < num_devices && i < maxshowdevs; i++) {
+
+ /*
+ * If the drive goes away, we may not get any properties
+ * for it. So take some defaults.
+ */
+ total_bytes = 0;
+ total_transfers = 0;
+ total_time = 0;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drivestat[i].driver,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS)
+ continue;
+
+ /* get statistics from properties */
+ statistics = (CFDictionaryRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBlockStorageDriverStatisticsKey));
+ if (statistics) {
+
+ /*
+ * Get I/O volume.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_bytes += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_bytes += value;
+ }
+
+ /*
+ * Get I/O counts.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_transfers += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_transfers += value;
+ }
+
+ /*
+ * Get I/O time.
+ */
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_time += value;
+ }
+ if ((number = (CFNumberRef)CFDictionaryGetValue(statistics,
+ CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) {
+ CFNumberGetValue(number, kCFNumberSInt64Type, &value);
+ total_time += value;
+ }
+
+ }
+ CFRelease(properties);
+
+ /*
+ * Compute delta values and stats.
+ */
+ interval_bytes = total_bytes - drivestat[i].total_bytes;
+ interval_transfers = total_transfers
+ - drivestat[i].total_transfers;
+ interval_time = total_time - drivestat[i].total_time;
+
+ /* update running totals, only once for -I */
+ if ((Iflag == 0) || (drivestat[i].total_bytes == 0)) {
+ drivestat[i].total_bytes = total_bytes;
+ drivestat[i].total_transfers = total_transfers;
+ drivestat[i].total_time = total_time;
+ }
+
+ interval_blocks = interval_bytes / drivestat[i].blocksize;
+ total_blocks = total_bytes / drivestat[i].blocksize;
+
+ blocks_per_second = interval_blocks / etime;
+ transfers_per_second = interval_transfers / etime;
+ mb_per_second = (interval_bytes / etime) / (1024 * 1024);
+
+ kb_per_transfer = (interval_transfers > 0) ?
+ ((long double)interval_bytes / interval_transfers)
+ / 1024 : 0;
+
+ /* times are in nanoseconds, convert to milliseconds */
+ ms_per_transaction = (interval_transfers > 0) ?
+ ((long double)interval_time / interval_transfers)
+ / 1000 : 0;
+
+ if (Kflag)
+ total_blocks = total_blocks * drivestat[i].blocksize
+ / 1024;
+
+ if (oflag > 0) {
+ int msdig = (ms_per_transaction < 100.0) ? 1 : 0;
+
+ if (Iflag == 0)
+ printf("%4.0Lf%4.0Lf%5.*Lf ",
+ blocks_per_second,
+ transfers_per_second,
+ msdig,
+ ms_per_transaction);
+ else
+ printf("%4.1qu%4.1qu%5.*Lf ",
+ interval_blocks,
+ interval_transfers,
+ msdig,
+ ms_per_transaction);
+ } else {
+ if (Iflag == 0)
+ printf(" %7.2Lf %4.0Lf %5.2Lf ",
+ kb_per_transfer,
+ transfers_per_second,
+ mb_per_second);
+ else {
+ interval_mb = interval_bytes;
+ interval_mb /= 1024 * 1024;
+
+ printf(" %7.2Lf %3.1qu %5.2Lf ",
+ kb_per_transfer,
+ interval_transfers,
+ interval_mb);
+ }
+ }
+ }
+}
+
+static void
+cpustats(void)
+{
+ mach_msg_type_number_t count;
+ kern_return_t status;
+ double time;
+
+ /*
+ * Get CPU usage counters.
+ */
+ count = HOST_CPU_LOAD_INFO_COUNT;
+ status = host_statistics(host_priv_port, HOST_CPU_LOAD_INFO,
+ (host_info_t)&cur.load, &count);
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't fetch CPU stats");
+
+ /*
+ * Make 'cur' fields relative, update 'last' fields to current values,
+ * calculate total elapsed time.
+ */
+ time = 0.0;
+ cur.load.cpu_ticks[CPU_STATE_USER]
+ -= last.load.cpu_ticks[CPU_STATE_USER];
+ last.load.cpu_ticks[CPU_STATE_USER]
+ += cur.load.cpu_ticks[CPU_STATE_USER];
+ time += cur.load.cpu_ticks[CPU_STATE_USER];
+ cur.load.cpu_ticks[CPU_STATE_SYSTEM]
+ -= last.load.cpu_ticks[CPU_STATE_SYSTEM];
+ last.load.cpu_ticks[CPU_STATE_SYSTEM]
+ += cur.load.cpu_ticks[CPU_STATE_SYSTEM];
+ time += cur.load.cpu_ticks[CPU_STATE_SYSTEM];
+ cur.load.cpu_ticks[CPU_STATE_IDLE]
+ -= last.load.cpu_ticks[CPU_STATE_IDLE];
+ last.load.cpu_ticks[CPU_STATE_IDLE]
+ += cur.load.cpu_ticks[CPU_STATE_IDLE];
+ time += cur.load.cpu_ticks[CPU_STATE_IDLE];
+
+ /*
+ * Print times.
+ */
+#define PTIME(kind) { \
+ double cpu = rint(100. * cur.load.cpu_ticks[kind] / (time ? time : 1));\
+ printf("%*.0f", (100 == cpu) ? 4 : 3, cpu); \
+}
+ PTIME(CPU_STATE_USER);
+ PTIME(CPU_STATE_SYSTEM);
+ PTIME(CPU_STATE_IDLE);
+}
+
+static void
+loadstats(void)
+{
+ double loadavg[3];
+
+ if(getloadavg(loadavg,3)!=3)
+ errx(1, "couldn't fetch load average");
+
+ printf(" %4.2f %4.2f %4.2f",loadavg[0],loadavg[1],loadavg[2]);
+}
+
+static int
+readvar(const char *name, void *ptr, size_t len)
+{
+ int oid[4];
+ int oidlen;
+
+ size_t nlen = len;
+
+ if (sysctlbyname(name, ptr, &nlen, NULL, 0) == -1) {
+ if (errno != ENOENT) {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+ /*
+ * XXX fallback code to deal with systems where
+ * sysctlbyname can't find "old" OIDs, should be removed.
+ */
+ if (!strcmp(name, "kern.boottime")) {
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_BOOTTIME;
+ oidlen = 2;
+ } else {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+
+ nlen = len;
+ if (sysctl(oid, oidlen, ptr, &nlen, NULL, 0) == -1) {
+ warn("sysctl(%s) failed", name);
+ return (1);
+ }
+ }
+ if (nlen != len) {
+ warnx("sysctl(%s): expected %lu, got %lu", name,
+ (unsigned long)len, (unsigned long)nlen);
+ return (1);
+ }
+ return (0);
+}
+
+static long double
+compute_etime(struct timeval cur_time, struct timeval prev_time)
+{
+ struct timeval busy_time;
+ u_int64_t busy_usec;
+ long double etime;
+
+ timersub(&cur_time, &prev_time, &busy_time);
+
+ busy_usec = busy_time.tv_sec;
+ busy_usec *= 1000000;
+ busy_usec += busy_time.tv_usec;
+ etime = busy_usec;
+ etime /= 1000000;
+
+ return(etime);
+}
+
+/*
+ * Record all "whole" IOMedia objects as being interesting.
+ */
+static int
+record_all_devices(void)
+{
+ io_iterator_t drivelist;
+ CFMutableDictionaryRef match;
+ kern_return_t status;
+
+ /*
+ * Get an iterator for IOMedia objects.
+ */
+ match = IOServiceMatching("IOMedia");
+ CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue);
+
+ CFRetain(match);
+ status = IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, match, &record_drivelist, NULL, &drivelist);
+
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't match whole IOMedia devices");
+
+ /*
+ * Scan all of the IOMedia objects, and for each
+ * object that has a parent IOBlockStorageDriver, save
+ * the object's name and the parent (from which we can
+ * fetch statistics).
+ *
+ * XXX What about RAID devices?
+ */
+
+ record_drivelist(NULL, drivelist);
+
+
+ status = IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, match, &remove_drivelist, NULL, &drivelist);
+
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't match whole IOMedia device removal");
+
+ remove_drivelist(NULL, drivelist);
+
+ return(0);
+}
+
+static void
+record_drivelist(void* context, io_iterator_t drivelist)
+{
+ io_registry_entry_t drive;
+ while ((drive = IOIteratorNext(drivelist))) {
+ if (num_devices < MAXDRIVES) {
+ record_device(drive);
+ phdr_flag = 1;
+ }
+ IOObjectRelease(drive);
+ }
+ qsort(drivestat, num_devices, sizeof(struct drivestats), &compare_drivestats);
+}
+
+static void
+remove_drivelist(void* context, io_iterator_t drivelist)
+{
+ io_registry_entry_t drive;
+ while ((drive = IOIteratorNext(drivelist))) {
+ kern_return_t status;
+ char bsdname[MAXDRIVENAME];
+ CFDictionaryRef properties;
+ CFStringRef name;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drive,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS) continue;
+
+ /* get name from properties */
+ name = (CFStringRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBSDNameKey));
+
+ if (name && CFStringGetCString(name, bsdname, MAXDRIVENAME, kCFStringEncodingUTF8)) {
+ int i;
+ for (i = 0; i < num_devices; ++i) {
+ if (strcmp(bsdname,drivestat[i].name) == 0) {
+ if (i < MAXDRIVES-1) {
+ memmove(&drivestat[i], &drivestat[i+1], sizeof(struct drivestats)*(MAXDRIVES-i));
+ }
+ --num_devices;
+ phdr_flag = 1;
+ qsort(drivestat, num_devices, sizeof(struct drivestats), &compare_drivestats);
+ break;
+ }
+ }
+ }
+ CFRelease(properties);
+ IOObjectRelease(drive);
+ }
+}
+
+/*
+ * Try to record the named device as interesting. It
+ * must be an IOMedia device.
+ */
+static int
+record_one_device(char *name)
+{
+ io_iterator_t drivelist;
+ io_registry_entry_t drive;
+ kern_return_t status;
+
+ /*
+ * Find the device.
+ */
+ status = IOServiceGetMatchingServices(masterPort,
+ IOBSDNameMatching(masterPort, kNilOptions, name),
+ &drivelist);
+ if (status != KERN_SUCCESS)
+ errx(1, "couldn't match '%s'", name);
+
+ /*
+ * Get the first match (should only be one)
+ */
+ if (!(drive = IOIteratorNext(drivelist)))
+ errx(1, "'%s' not found", name);
+ if (!IOObjectConformsTo(drive, "IOMedia"))
+ errx(1, "'%s' is not a storage device", name);
+
+ /*
+ * Record the device.
+ */
+ if (record_device(drive))
+ errx(1, "could not record '%s' for monitoring", name);
+
+ IOObjectRelease(drive);
+ IOObjectRelease(drivelist);
+
+ return(0);
+}
+
+/*
+ * Determine whether an IORegistryEntry refers to a valid
+ * I/O device, and if so, record it.
+ */
+static int
+record_device(io_registry_entry_t drive)
+{
+ io_registry_entry_t parent;
+ CFDictionaryRef properties;
+ CFStringRef name;
+ CFNumberRef number;
+ kern_return_t status;
+
+ /* get drive's parent */
+ status = IORegistryEntryGetParentEntry(drive,
+ kIOServicePlane, &parent);
+ if (status != KERN_SUCCESS)
+ errx(1, "device has no parent");
+ if (IOObjectConformsTo(parent, "IOBlockStorageDriver")) {
+ drivestat[num_devices].driver = parent;
+
+ /* get drive properties */
+ status = IORegistryEntryCreateCFProperties(drive,
+ (CFMutableDictionaryRef *)&properties,
+ kCFAllocatorDefault,
+ kNilOptions);
+ if (status != KERN_SUCCESS)
+ errx(1, "device has no properties");
+
+ /* get name from properties */
+ name = (CFStringRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOBSDNameKey));
+ if (name)
+ CFStringGetCString(name, drivestat[num_devices].name,
+ MAXDRIVENAME, kCFStringEncodingUTF8);
+ else {
+ errx(1, "device does not have a BSD name");
+ }
+
+ /* get blocksize from properties */
+ number = (CFNumberRef)CFDictionaryGetValue(properties,
+ CFSTR(kIOMediaPreferredBlockSizeKey));
+ if (number)
+ CFNumberGetValue(number, kCFNumberSInt64Type,
+ &drivestat[num_devices].blocksize);
+ else
+ errx(1, "device does not have a preferred block size");
+
+ // radar:18700383
+ if (drivestat[num_devices].blocksize == 0) {
+ warnx("%s claims a blocksize of 0; defaulting to 512. Its statistics may be inaccurate.", drivestat[num_devices].name);
+ drivestat[num_devices].blocksize = 512;
+ }
+
+ /* clean up, return success */
+ CFRelease(properties);
+ num_devices++;
+ return(0);
+ }
+
+ /* failed, don't keep parent */
+ IOObjectRelease(parent);
+ return(1);
+}
+
+static int
+compare_drivestats(const void* pa, const void* pb)
+{
+ struct drivestats* a = (struct drivestats*)pa;
+ struct drivestats* b = (struct drivestats*)pb;
+ return strcmp(a->name, b->name);
+}
diff --git a/system_cmds/kpgo.tproj/kpgo.c b/system_cmds/kpgo.tproj/kpgo.c
new file mode 100644
index 0000000..dacfc4c
--- /dev/null
+++ b/system_cmds/kpgo.tproj/kpgo.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2014-2016 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <sys/pgo.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void usage(char **argv)
+{
+ fprintf (stderr, "usage: %s [-H] [-m] [-w] [uuid] >datafile\n", argv[0]);
+ fprintf (stderr, " uuid : the UUID of a kext\n");
+ fprintf (stderr, " -H : grab data for the HIB segment\n");
+ fprintf (stderr, " -w : wait for the kext to be unloaded\n");
+ fprintf (stderr, " -m : request metadata\n");
+ fprintf (stderr, " -R : reset all counters\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ int flags = 0;
+ int data_flags = 0;
+ uuid_t *uuidp = NULL;
+ uuid_t uuid;
+ int c;
+
+ while ((c = getopt(argc, argv, "hHwmR")) != EOF) {
+ switch(c) {
+ case 'R':
+ flags |= PGO_RESET_ALL;
+ break;
+ case 'H':
+ flags |= PGO_HIB;
+ break;
+ case 'm':
+ flags |= PGO_METADATA;
+ break;
+ case 'w':
+ data_flags |= PGO_WAIT_FOR_UNLOAD;
+ break;
+ case '?':
+ case 'h':
+ default:
+ usage(argv);
+ break;
+ }
+ }
+
+ if (optind < argc)
+ {
+ if (optind == argc - 1 &&
+ 0 == uuid_parse(argv[optind], uuid))
+ {
+ uuidp = &uuid;
+ } else {
+ usage(argv);
+ }
+ }
+
+ if (flags & PGO_RESET_ALL) {
+ if (flags != PGO_RESET_ALL || uuidp) {
+ usage(argv);
+ }
+ ssize_t r = grab_pgo_data(NULL, PGO_RESET_ALL, NULL, 0);
+ if (r < 0)
+ {
+ perror("grab_pgo_data");
+ return 1;
+ }
+ return 0;
+ }
+
+ ssize_t size = grab_pgo_data(uuidp, flags, NULL, 0);
+
+ if (size < 0)
+ {
+ perror("grab_pgo_data");
+ return 1;
+ }
+
+
+ fprintf (stderr, "size = %ld\n", (long) size);
+
+ unsigned char *buffer = valloc(size);
+ if (!buffer)
+ {
+ perror("valloc");
+ return 1;
+ }
+
+ ssize_t r = grab_pgo_data(uuidp, flags | data_flags, buffer, size);
+
+
+ if (r < 0)
+ {
+ perror("grab_pgo_data");
+ return 1;
+ }
+
+ if (isatty(STDOUT_FILENO)) {
+ fprintf (stderr, "%s: refusing to write binary data to a tty!\n", argv[0]);
+ return 1;
+ }
+
+ while (size > 0) {
+ errno = 0;
+ r = write(STDOUT_FILENO, buffer, size);
+ if (r > 0) {
+ buffer += r;
+ size -= r;
+ } else {
+ perror ("write");
+ return 1;
+ }
+ }
+
+ return 0;
+}
diff --git a/system_cmds/latency.tproj/latency.1 b/system_cmds/latency.tproj/latency.1
new file mode 100644
index 0000000..4e0eb3e
--- /dev/null
+++ b/system_cmds/latency.tproj/latency.1
@@ -0,0 +1,106 @@
+.\" Copyright (c) 2000, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd March 28, 2000
+.Dt LATENCY 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm latency
+.Nd monitors scheduling and interrupt latency
+.Sh SYNOPSIS
+.Nm latency
+.Op Fl p Ar priority
+.Op Fl h
+.Op Fl m
+.Op Fl st Ar threshold
+.Op Fl it Ar threshold
+.Op Fl c Ar code_file
+.Op Fl l Ar log_file
+.Op Fl R Ar raw_file
+.Op Fl n Ar kernel
+.Sh DESCRIPTION
+The
+.Nm latency
+utility provides scheduling and interrupt-latency statistics.
+Due to the kernel tracing facility it uses to operate,
+the command requires root privileges.
+.Pp
+The arguments are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl c Ar code_file
+When the
+.Fl c
+option is specified, it takes a path to a code file
+that contains the mappings for the system calls.
+This option overrides the default location of the system call code file,
+which is found in /usr/share/misc/trace.codes.
+.\" ==========
+.It Fl h
+Display high resolution interrupt latencies and write them to latencies.csv (truncate existing file) upon exit.
+.\" ==========
+.It Fl m
+Display per-CPU interrupt latency statistics.
+.\" ==========
+.It Fl it Ar threshold
+Set the interrupt latency threshold,
+expressed in microseconds.
+If the latency exceeds this value,
+and a log file has been specified,
+a record of what occurred during this time is recorded.
+.\" ==========
+.It Fl l Ar log_file
+Specifies a log file that is written to when
+either the interrupt or scheduling latency is exceeded.
+.\" ==========
+.It Fl n Ar kernel
+By default,
+.Nm latency
+acts on the default /System/Library/Kernels/kernel.development.
+This option allows you to specify an alternate booted kernel.
+.\" ==========
+.It Fl p Ar priority
+Specifies the priority level to observe scheduler latencies for.
+The default is realtime (
+.Ar 97
+). A range of priorities to monitor
+can also be provided, for example
+.Ar 31-47
+or
+.Ar 0-127
+.
+.\" ==========
+.It Fl st Ar threshold
+Set the scheduler latency threshold in microseconds.
+If latency exceeds this, and a log file has been specified,
+a record of what occurred during this time is recorded.
+.\" ==========
+.It Fl R Ar raw_file
+Specifies a raw trace file to use as input.
+.El
+.Pp
+The data columns displayed are as follows:
+.Bl -tag -width LAST_PATHNAME_WAITED_FOR
+.It SCHEDULER
+The number of context switches that fall within the described delay.
+.It INTERRUPTS
+The number of interrupts that fall within the described delay.
+.El
+.Pp
+The
+.Nm latency
+utility is also SIGWINCH savvy, so adjusting your window geometry will change
+the list of delay values displayed.
+.Sh SAMPLE USAGE
+.Pp
+latency -p 97 -st 20000 -it 1000 -l /var/tmp/latency.log
+.Pp
+The
+.Nm latency
+utility will watch threads with priority 97 for scheduling latencies.
+The threshold for the scheduler is set to 20000 microseconds.
+The threshold for interrupts is set to 1000 microseconds.
+Latencies that exceed these thresholds will be logged in /var/tmp/latency.log.
+.Sh SEE ALSO
+.Xr fs_usage 1 ,
+.Xr sc_usage 1 ,
+.Xr top 1
diff --git a/system_cmds/latency.tproj/latency.c b/system_cmds/latency.tproj/latency.c
new file mode 100644
index 0000000..afd67cc
--- /dev/null
+++ b/system_cmds/latency.tproj/latency.c
@@ -0,0 +1,2793 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -DPRIVATE -D__APPLE_PRIVATE -arch x86_64 -arch i386 -O -o latency latency.c -lncurses -lutil
+*/
+
+#include <mach/mach.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <strings.h>
+#include <nlist.h>
+#include <fcntl.h>
+#include <string.h>
+#include <libc.h>
+#include <termios.h>
+#include <curses.h>
+#include <libutil.h>
+#include <errno.h>
+#include <err.h>
+#include <inttypes.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/ioctl.h>
+
+#ifndef KERNEL_PRIVATE
+#define KERNEL_PRIVATE
+#include <sys/kdebug.h>
+#undef KERNEL_PRIVATE
+#else
+#include <sys/kdebug.h>
+#endif /*KERNEL_PRIVATE*/
+
+#include <mach/mach_error.h>
+#include <mach/mach_types.h>
+#include <mach/message.h>
+#include <mach/mach_syscalls.h>
+#include <mach/clock_types.h>
+#include <mach/mach_time.h>
+
+#include <libkern/OSTypes.h>
+
+
+int s_usec_10_bins[10];
+int s_usec_100_bins[10];
+int s_msec_1_bins[10];
+int s_msec_10_bins[5];
+int s_too_slow;
+int s_max_latency;
+int s_min_latency = 0;
+long long s_total_latency = 0;
+int s_total_samples = 0;
+long s_thresh_hold;
+int s_exceeded_threshold = 0;
+
+
+#define N_HIGH_RES_BINS 500
+int use_high_res_bins = false;
+
+struct i_latencies {
+ int i_usec_10_bins[10];
+ int i_usec_100_bins[10];
+ int i_msec_1_bins[10];
+ int i_msec_10_bins[5];
+ int i_too_slow;
+ long i_max_latency;
+ long i_min_latency;
+ int i_total_samples;
+ int i_total;
+ int i_exceeded_threshold;
+ uint64_t i_total_latency;
+};
+
+struct i_latencies *i_lat;
+boolean_t i_latency_per_cpu = FALSE;
+
+int i_high_res_bins[N_HIGH_RES_BINS];
+
+long i_thresh_hold;
+
+int watch_priority_min = 97;
+int watch_priority_max = 97;
+
+long start_time;
+long curr_time;
+long refresh_time;
+
+
+char *kernelpath = NULL;
+
+typedef struct {
+ void *k_sym_addr; /* kernel symbol address from nm */
+ size_t k_sym_len; /* length of kernel symbol string */
+ char *k_sym_name; /* kernel symbol string from nm */
+} kern_sym_t;
+
+kern_sym_t *kern_sym_tbl; /* pointer to the nm table */
+int kern_sym_count; /* number of entries in nm table */
+
+
+
+#define MAX_ENTRIES 4096
+struct ct {
+ int type;
+ char name[32];
+} codes_tab[MAX_ENTRIES];
+
+char *code_file = NULL;
+int num_of_codes = 0;
+
+
+double divisor;
+sig_atomic_t gotSIGWINCH = 0;
+int trace_enabled = 0;
+int need_new_map = 1;
+int set_remove_flag = 1; /* By default, remove trace buffer */
+
+int RAW_flag = 0;
+int RAW_fd = 0;
+
+uint64_t first_now = 0;
+uint64_t last_now = 0;
+int first_read = 1;
+
+
+#define SAMPLE_TIME_USECS 50000
+#define SAMPLE_SIZE 300000
+#define MAX_LOG_COUNT 30 /* limits the number of entries dumped in log_decrementer */
+
+kbufinfo_t bufinfo = {0, 0, 0};
+
+FILE *log_fp = NULL;
+
+uint64_t sample_TOD_secs;
+uint32_t sample_TOD_usecs;
+
+uint64_t cpu_mask;
+
+int sample_generation = 0;
+int num_i_latency_cpus = 1;
+int num_cpus;
+void *my_buffer;
+int num_entries;
+
+kd_buf **last_decrementer_kd; /* last DECR_TRAP per cpu */
+
+
+#define NUMPARMS 23
+
+typedef struct event *event_t;
+
+struct event {
+ event_t ev_next;
+
+ uint64_t ev_thread;
+ uint32_t ev_type;
+ uint64_t ev_timestamp;
+};
+
+
+typedef struct lookup *lookup_t;
+
+struct lookup {
+ lookup_t lk_next;
+
+ uint64_t lk_thread;
+ uint64_t lk_dvp;
+ int64_t *lk_pathptr;
+ int64_t lk_pathname[NUMPARMS + 1];
+};
+
+
+typedef struct threadmap *threadmap_t;
+
+struct threadmap {
+ threadmap_t tm_next;
+
+ uint64_t tm_thread;
+ uint64_t tm_pthread;
+ char tm_command[MAXCOMLEN + 1];
+ char tm_orig_command[MAXCOMLEN + 1];
+};
+
+
+typedef struct threadrun *threadrun_t;
+
+struct threadrun {
+ threadrun_t tr_next;
+
+ uint64_t tr_thread;
+ kd_buf *tr_entry;
+ uint64_t tr_timestamp;
+ int tr_priority;
+};
+
+
+typedef struct thread_entry *thread_entry_t;
+
+struct thread_entry {
+ thread_entry_t te_next;
+
+ uint64_t te_thread;
+};
+
+#define HASH_SIZE 1024
+#define HASH_MASK 1023
+
+event_t event_hash[HASH_SIZE];
+lookup_t lookup_hash[HASH_SIZE];
+threadmap_t threadmap_hash[HASH_SIZE];
+threadrun_t threadrun_hash[HASH_SIZE];
+
+event_t event_freelist;
+lookup_t lookup_freelist;
+threadrun_t threadrun_freelist;
+threadmap_t threadmap_freelist;
+threadmap_t threadmap_temp;
+
+thread_entry_t thread_entry_freelist;
+thread_entry_t thread_delete_list;
+thread_entry_t thread_reset_list;
+thread_entry_t thread_event_list;
+thread_entry_t thread_lookup_list;
+thread_entry_t thread_run_list;
+
+
+#ifndef RAW_VERSION1
+typedef struct {
+ int version_no;
+ int thread_count;
+ uint64_t TOD_secs;
+ uint32_t TOD_usecs;
+} RAW_header;
+
+#define RAW_VERSION0 0x55aa0000
+#define RAW_VERSION1 0x55aa0101
+#endif
+
+
+#define USER_MODE 0
+#define KERNEL_MODE 1
+
+
+#define INTERRUPT 0x01050000
+#define DECR_TRAP 0x01090000
+#define DECR_SET 0x01090004
+#define MACH_vmfault 0x01300008
+#define MACH_sched 0x01400000
+#define MACH_stkhandoff 0x01400008
+#define MACH_makerunnable 0x01400018
+#define MACH_idle 0x01400024
+#define IES_action 0x050b0018
+#define IES_filter 0x050b001c
+#define TES_action 0x050c0010
+#define CQ_action 0x050d0018
+#define CPUPM_CPUSTER_RUNCOUNT 0x05310144
+
+#define BSC_exit 0x040C0004
+#define BSC_thread_terminate 0x040c05a4
+
+#define DBG_FUNC_MASK ~(DBG_FUNC_START | DBG_FUNC_END)
+
+#define CPU_NUMBER(kp) kdbg_get_cpu(kp)
+
+#define EMPTYSTRING ""
+
+const char *fault_name[] = {
+ "",
+ "ZeroFill",
+ "PageIn",
+ "COW",
+ "CacheHit",
+ "NoZeroFill",
+ "Guard",
+ "PageInFile",
+ "PageInAnon"
+};
+
+const char *sched_reasons[] = {
+ "N",
+ "P",
+ "Q",
+ "?",
+ "u",
+ "U",
+ "?",
+ "?",
+ "H",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "?",
+ "Y"
+};
+
+#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
+#define MAX_REASON ARRAYSIZE(sched_reasons)
+
+static double handle_decrementer(kd_buf *, int);
+static kd_buf *log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, double i_latency);
+static void read_command_map(void);
+static void enter_syscall(FILE *fp, kd_buf *kd, uint64_t thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info);
+static void exit_syscall(FILE *fp, kd_buf *kd, uint64_t thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info);
+static void print_entry(FILE *fp, kd_buf *kd, uint64_t thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd_note);
+static void log_info(uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd, kd_buf *kd_note);
+static char *find_code(int);
+static void pc_to_string(char *pcstring, uint64_t pc, int max_len, int mode);
+static void getdivisor(void);
+static int sample_sc(void);
+static void init_code_file(void);
+static void do_kernel_nm(void);
+static void open_logfile(const char*);
+static int binary_search(kern_sym_t *list, int low, int high, uint64_t addr);
+
+static void create_map_entry(uint64_t, char *);
+static void check_for_thread_update(uint64_t thread, int debugid_base, kd_buf *kbufp, char **command);
+static void log_scheduler(kd_buf *kd_start, kd_buf *kd_stop, kd_buf *end_of_sample, int s_priority, double s_latency, uint64_t thread);
+static int check_for_scheduler_latency(int type, uint64_t *thread, uint64_t now, kd_buf *kd, kd_buf **kd_start, int *priority, double *latency);
+static void open_rawfile(const char *path);
+
+static void screen_update(FILE *);
+
+static void set_enable(int);
+static void set_remove(void);
+
+static int
+quit(char *s)
+{
+ if (!RAW_flag) {
+ if (trace_enabled) {
+ set_enable(0);
+ }
+ /*
+ * This flag is turned off when calling
+ * quit() due to a set_remove() failure.
+ */
+ if (set_remove_flag) {
+ set_remove();
+ }
+ }
+ endwin();
+
+ printf("latency: ");
+ if (s) {
+ printf("%s", s);
+ }
+ exit(1);
+}
+
+void
+set_enable(int val)
+{
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDENABLE, val };
+ size_t needed;
+
+ if (sysctl(mib, ARRAYSIZE(mib), NULL, &needed, NULL, 0) < 0) {
+ quit("trace facility failure, KERN_KDENABLE\n");
+ }
+}
+
+static void
+set_numbufs(int nbufs)
+{
+ int mib1[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSETBUF, nbufs };
+ int mib2[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSETUP };
+ size_t needed;
+
+ if (sysctl(mib1, ARRAYSIZE(mib1), NULL, &needed, NULL, 0) < 0) {
+ quit("trace facility failure, KERN_KDSETBUF\n");
+ }
+ if (sysctl(mib2, ARRAYSIZE(mib2), NULL, &needed, NULL, 0) < 0) {
+ quit("trace facility failure, KERN_KDSETUP\n");
+ }
+}
+
+static void
+set_pidexclude(int pid, int on_off)
+{
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDPIDEX };
+ size_t needed = sizeof(kd_regtype);
+
+ kd_regtype kr = {
+ .type = KDBG_TYPENONE,
+ .value1 = pid,
+ .value2 = on_off
+ };
+
+ sysctl(mib, ARRAYSIZE(mib), &kr, &needed, NULL, 0);
+}
+
+static void
+get_bufinfo(kbufinfo_t *val)
+{
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDGETBUF };
+ size_t needed = sizeof (*val);
+
+ if (sysctl(mib, ARRAYSIZE(mib), val, &needed, 0, 0) < 0) {
+ quit("trace facility failure, KERN_KDGETBUF\n");
+ }
+}
+
+void
+set_remove(void)
+{
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDREMOVE };
+ size_t needed;
+
+ errno = 0;
+
+ if (sysctl(mib, ARRAYSIZE(mib), NULL, &needed, NULL, 0) < 0) {
+ set_remove_flag = 0;
+ if (errno == EBUSY) {
+ quit("the trace facility is currently in use...\n fs_usage, sc_usage, and latency use this feature.\n\n");
+ } else {
+ quit("trace facility failure, KERN_KDREMOVE\n");
+ }
+ }
+}
+
+
+static void
+write_high_res_latencies(void)
+{
+ int i;
+ FILE *f;
+
+ if (use_high_res_bins) {
+ if ((f = fopen("latencies.csv","w"))) {
+ for (i = 0; i < N_HIGH_RES_BINS; i++) {
+ fprintf(f, "%d,%d\n", i, i_high_res_bins[i]);
+ }
+ fclose(f);
+ }
+ }
+}
+
+static void
+sigintr(int signo __attribute__((unused)))
+{
+ write_high_res_latencies();
+
+ set_enable(0);
+ set_pidexclude(getpid(), 0);
+ screen_update(log_fp);
+ endwin();
+ set_remove();
+
+ exit(1);
+}
+
+/* exit under normal conditions -- signal handler */
+static void
+leave(int signo __attribute__((unused)))
+{
+ write_high_res_latencies();
+
+ set_enable(0);
+ set_pidexclude(getpid(), 0);
+ endwin();
+ set_remove();
+
+ exit(1);
+}
+
+static void
+sigwinch(int signo __attribute__((unused)))
+{
+ gotSIGWINCH = 1;
+}
+
+static void
+print_total(FILE *fp, char *s, int total)
+{
+ int cpu;
+ int clen;
+ int itotal;
+ struct i_latencies *il;
+ char tbuf[512];
+
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+ itotal += il->i_total;
+ }
+ clen = sprintf(tbuf, "%s %10d %9d", s, total, itotal);
+
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ if (i_latency_per_cpu == TRUE) {
+ clen += sprintf(&tbuf[clen], " %9d", il->i_total);
+ }
+
+ il->i_total = 0;
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+}
+
+
+
+void
+screen_update(FILE *fp)
+{
+ int i;
+ int cpu;
+ int clen;
+ int itotal, stotal;
+ long elapsed_secs;
+ long elapsed_mins;
+ long elapsed_hours;
+ long min_lat, max_lat;
+ uint64_t tot_lat;
+ unsigned int average_s_latency;
+ unsigned int average_i_latency;
+ struct i_latencies *il;
+ char tbuf[1024];
+
+ if (fp == NULL) {
+ erase();
+ move(0, 0);
+ } else {
+ fprintf(fp,"\n\n===================================================================================================\n");
+ }
+ /*
+ * Display the current time.
+ * "ctime" always returns a string that looks like this:
+ *
+ * Sun Sep 16 01:03:52 1973
+ * 012345678901234567890123
+ * 1 2
+ *
+ * We want indices 11 thru 18 (length 8).
+ */
+ if (RAW_flag) {
+ curr_time = (unsigned long)sample_TOD_secs;
+ elapsed_secs = ((last_now - first_now) / divisor) / 1000000;
+ } else {
+ elapsed_secs = curr_time - start_time;
+ }
+
+ elapsed_hours = elapsed_secs / 3600;
+ elapsed_secs -= elapsed_hours * 3600;
+ elapsed_mins = elapsed_secs / 60;
+ elapsed_secs -= elapsed_mins * 60;
+
+ sprintf(tbuf, "%-19.19s %2ld:%02ld:%02ld\n", &(ctime(&curr_time)[0]),
+ (long)elapsed_hours, (long)elapsed_mins, (long)elapsed_secs);
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ sprintf(tbuf, " SCHEDULER INTERRUPTS\n");
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ if (i_latency_per_cpu == TRUE) {
+ clen = sprintf(tbuf, " Total");
+
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ if (cpu <= 9) {
+ clen += sprintf(&tbuf[clen], " CPU %d", cpu);
+ } else {
+ clen += sprintf(&tbuf[clen], " CPU %d", cpu);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ clen = sprintf(tbuf, "\n-------------------------------------------------------");
+
+ for (cpu = 1; cpu < num_i_latency_cpus; cpu++) {
+ clen += sprintf(&tbuf[clen], "----------");
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ } else {
+ sprintf(tbuf, "---------------------------------------------");
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+ itotal += il->i_total_samples;
+ }
+ clen = sprintf(tbuf, "\ntotal_samples %10d %9d", s_total_samples, itotal);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_total_samples);
+ }
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+
+ for (stotal = 0, i = 0; i < 10; i++) {
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_usec_10_bins[i];
+ il->i_total += il->i_usec_10_bins[i];
+ }
+ clen = sprintf(tbuf, "\ndelays < %3d usecs %10d %9d", (i + 1) * 10, s_usec_10_bins[i], itotal);
+
+ stotal += s_usec_10_bins[i];
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_usec_10_bins[i]);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ print_total(fp, "\ntotal < 100 usecs", stotal);
+
+ for (stotal = 0, i = 1; i < 10; i++) {
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_usec_100_bins[i];
+ il->i_total += il->i_usec_100_bins[i];
+ }
+ if (i < 9) {
+ clen = sprintf(tbuf, "\ndelays < %3d usecs %10d %9d", (i + 1) * 100, s_usec_100_bins[i], itotal);
+ } else {
+ clen = sprintf(tbuf, "\ndelays < 1 msec %10d %9d", s_usec_100_bins[i], itotal);
+ }
+
+ stotal += s_usec_100_bins[i];
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_usec_100_bins[i]);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ print_total(fp, "\ntotal < 1 msec ", stotal);
+
+
+ for (stotal = 0, i = 1; i < 10; i++) {
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_msec_1_bins[i];
+ il->i_total += il->i_msec_1_bins[i];
+ }
+ clen = sprintf(tbuf, "\ndelays < %3d msecs %10d %9d", (i + 1), s_msec_1_bins[i], itotal);
+
+ stotal += s_msec_1_bins[i];
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_msec_1_bins[i]);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ print_total(fp, "\ntotal < 10 msecs", stotal);
+
+ for (stotal = 0, i = 1; i < 5; i++) {
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_msec_10_bins[i];
+ il->i_total += il->i_msec_10_bins[i];
+ }
+ clen = sprintf(tbuf, "\ndelays < %3d msecs %10d %9d", (i + 1)*10, s_msec_10_bins[i], itotal);
+
+ stotal += s_msec_10_bins[i];
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_msec_10_bins[i]);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+ }
+ print_total(fp, "\ntotal < 50 msecs", stotal);
+
+
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+ itotal += il->i_too_slow;
+ }
+ clen = sprintf(tbuf, "\ndelays > 50 msecs %10d %9d", s_too_slow, itotal);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_too_slow);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ if (cpu == 0 || (il->i_min_latency < min_lat)) {
+ min_lat = il->i_min_latency;
+ }
+ }
+ clen = sprintf(tbuf, "\n\nminimum latency(usecs) %7d %9ld", s_min_latency, min_lat);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9ld", il->i_min_latency);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ if (cpu == 0 || (il->i_max_latency > max_lat)) {
+ max_lat = il->i_max_latency;
+ }
+ }
+ clen = sprintf(tbuf, "\nmaximum latency(usecs) %7d %9ld", s_max_latency, max_lat);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9ld", il->i_max_latency);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ if (s_total_samples) {
+ average_s_latency = (unsigned int)(s_total_latency/s_total_samples);
+ } else {
+ average_s_latency = 0;
+ }
+
+ for (itotal = 0, tot_lat = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_total_samples;
+ tot_lat += il->i_total_latency;
+ }
+ if (itotal) {
+ average_i_latency = (unsigned)(tot_lat/itotal);
+ } else {
+ average_i_latency = 0;
+ }
+
+ clen = sprintf(tbuf, "\naverage latency(usecs) %7d %9d", average_s_latency, average_i_latency);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ if (il->i_total_samples) {
+ average_i_latency = (unsigned int)(il->i_total_latency/il->i_total_samples);
+ } else {
+ average_i_latency = 0;
+ }
+
+ clen += sprintf(&tbuf[clen], " %9d", average_i_latency);
+ }
+ }
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ for (itotal = 0, cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ itotal += il->i_exceeded_threshold;
+ }
+ clen = sprintf(tbuf, "\nexceeded threshold %7d %9d", s_exceeded_threshold, itotal);
+
+ if (i_latency_per_cpu == TRUE) {
+ for (cpu = 0; cpu < num_i_latency_cpus; cpu++) {
+ il = &i_lat[cpu];
+
+ clen += sprintf(&tbuf[clen], " %9d", il->i_exceeded_threshold);
+ }
+ }
+ sprintf(&tbuf[clen], "\n");
+
+ if (fp) {
+ fprintf(fp, "%s", tbuf);
+ } else {
+ printw(tbuf);
+ }
+
+ if (fp == NULL) {
+ refresh();
+ } else {
+ fflush(fp);
+ }
+}
+
+static int
+exit_usage(void)
+{
+ fprintf(stderr, "Usage: latency [-p <priority>] [-h] [-m] [-st <threshold>] [-it <threshold>]\n");
+ fprintf(stderr, " [-c <codefile>] [-l <logfile>] [-R <rawfile>] [-n <kernel>]\n\n");
+
+ fprintf(stderr, " -p specify scheduling priority to watch... default is realtime. Can also be a range, e.g. \"31-47\".\n");
+ fprintf(stderr, " -h Display high resolution interrupt latencies and write them to latencies.csv (truncate existing file) upon exit.\n");
+ fprintf(stderr, " -st set scheduler latency threshold in microseconds... if latency exceeds this, then log trace\n");
+ fprintf(stderr, " -m specify per-CPU interrupt latency reporting\n");
+ fprintf(stderr, " -it set interrupt latency threshold in microseconds... if latency exceeds this, then log trace\n");
+ fprintf(stderr, " -c specify name of codes file... default is /usr/share/misc/trace.codes\n");
+ fprintf(stderr, " -l specify name of file to log trace entries to when the specified threshold is exceeded\n");
+ fprintf(stderr, " -R specify name of raw trace file to process\n");
+ fprintf(stderr, " -n specify kernel... default is /System/Library/Kernels/kernel.development\n");
+
+ fprintf(stderr, "\nlatency must be run as root\n\n");
+
+ exit(1);
+}
+
+static void
+resetscr(void)
+{
+ (void)endwin();
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+
+ if (0 != reexec_to_match_kernel()) {
+ fprintf(stderr, "Could not re-execute: %d\n", errno);
+ exit(1);
+ }
+ while (argc > 1) {
+
+ if (strcmp(argv[1], "-R") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ open_rawfile(argv[1]);
+ } else {
+ exit_usage();
+ }
+
+ RAW_flag = 1;
+
+ } else if (strcmp(argv[1], "-p") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ if (2 == sscanf(argv[1], "%d-%d", &watch_priority_min, &watch_priority_max)) {
+ if (watch_priority_min > watch_priority_max) {
+ exit_usage();
+ } else if (watch_priority_min < 0) {
+ exit_usage();
+ }
+ } else {
+ if (1 == sscanf(argv[1], "%d", &watch_priority_min)) {
+ watch_priority_max = watch_priority_min;
+ } else {
+ exit_usage();
+ }
+ }
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-st") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ s_thresh_hold = atoi(argv[1]);
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-it") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ i_thresh_hold = atoi(argv[1]);
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-c") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ code_file = argv[1];
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-l") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ open_logfile(argv[1]);
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-n") == 0) {
+ argc--;
+ argv++;
+
+ if (argc > 1) {
+ kernelpath = argv[1];
+ } else {
+ exit_usage();
+ }
+ } else if (strcmp(argv[1], "-h") == 0) {
+ use_high_res_bins = TRUE;
+
+ } else if (strcmp(argv[1], "-m") == 0) {
+ i_latency_per_cpu = TRUE;
+
+ } else {
+ exit_usage();
+ }
+
+ argc--;
+ argv++;
+ }
+ if (!RAW_flag) {
+ if (geteuid() != 0) {
+ printf("'latency' must be run as root...\n");
+ exit(1);
+ }
+ }
+ if (kernelpath == NULL) {
+ kernelpath = "/System/Library/Kernels/kernel.development";
+ }
+
+ if (code_file == NULL) {
+ code_file = "/usr/share/misc/trace.codes";
+ }
+
+ do_kernel_nm();
+
+ getdivisor();
+
+ init_code_file();
+
+ if (!RAW_flag) {
+ if (initscr() == NULL) {
+ fprintf(stderr, "Unrecognized TERM type, try vt100\n");
+ exit(1);
+ }
+ atexit(resetscr);
+ clear();
+ refresh();
+
+ signal(SIGWINCH, sigwinch);
+ signal(SIGINT, sigintr);
+ signal(SIGQUIT, leave);
+ signal(SIGTERM, leave);
+ signal(SIGHUP, leave);
+
+ /*
+ * grab the number of cpus and scale the buffer size
+ */
+ int mib[] = { CTL_HW, HW_NCPU };
+ size_t len = sizeof(num_cpus);
+
+ sysctl(mib, ARRAYSIZE(mib), &num_cpus, &len, NULL, 0);
+
+ set_remove();
+ set_numbufs(SAMPLE_SIZE * num_cpus);
+
+ get_bufinfo(&bufinfo);
+
+ set_enable(0);
+
+ set_pidexclude(getpid(), 1);
+ set_enable(1);
+
+ num_entries = bufinfo.nkdbufs;
+ } else {
+ num_entries = 50000;
+ num_cpus = 128;
+ }
+
+ for (cpu_mask = 0, i = 0; i < num_cpus; i++)
+ cpu_mask |= ((uint64_t)1 << i);
+
+ if ((my_buffer = malloc(num_entries * sizeof(kd_buf))) == NULL) {
+ quit("can't allocate memory for tracing info\n");
+ }
+
+ if ((last_decrementer_kd = (kd_buf **)malloc(num_cpus * sizeof(kd_buf *))) == NULL) {
+ quit("can't allocate memory for decrementer tracing info\n");
+ }
+
+ if (i_latency_per_cpu == FALSE) {
+ num_i_latency_cpus = 1;
+ } else {
+ num_i_latency_cpus = num_cpus;
+ }
+
+ if ((i_lat = (struct i_latencies *)malloc(num_i_latency_cpus * sizeof(struct i_latencies))) == NULL) {
+ quit("can't allocate memory for interrupt latency info\n");
+ }
+
+ bzero((char *)i_lat, num_i_latency_cpus * sizeof(struct i_latencies));
+
+ if (RAW_flag) {
+ while (sample_sc()) {
+ continue;
+ }
+
+ if (log_fp) {
+ screen_update(log_fp);
+ }
+
+ screen_update(stdout);
+
+ } else {
+ uint64_t adelay;
+ double fdelay;
+ double nanosecs_to_sleep;
+
+ nanosecs_to_sleep = (double)(SAMPLE_TIME_USECS * 1000);
+ fdelay = nanosecs_to_sleep * (divisor /1000);
+ adelay = (uint64_t)fdelay;
+
+ trace_enabled = 1;
+
+ start_time = time(NULL);
+ refresh_time = start_time;
+
+ for (;;) {
+ curr_time = time(NULL);
+
+ if (curr_time >= refresh_time) {
+ screen_update(NULL);
+ refresh_time = curr_time + 1;
+ }
+ mach_wait_until(mach_absolute_time() + adelay);
+
+ sample_sc();
+
+ if (gotSIGWINCH) {
+ /*
+ * No need to check for initscr error return.
+ * We won't get here if it fails on the first call.
+ */
+ endwin();
+ clear();
+ refresh();
+
+ gotSIGWINCH = 0;
+ }
+ }
+ }
+}
+
+void
+read_command_map(void)
+{
+ kd_threadmap *mapptr = 0;
+ int total_threads = 0;
+ size_t size;
+ off_t offset;
+ int i;
+ RAW_header header = {0};
+
+ if (RAW_flag) {
+ if (read(RAW_fd, &header, sizeof(RAW_header)) != sizeof(RAW_header)) {
+ perror("read failed");
+ exit(2);
+ }
+ if (header.version_no != RAW_VERSION1) {
+ header.version_no = RAW_VERSION0;
+ header.TOD_secs = time(NULL);
+ header.TOD_usecs = 0;
+
+ lseek(RAW_fd, (off_t)0, SEEK_SET);
+
+ if (read(RAW_fd, &header.thread_count, sizeof(int)) != sizeof(int)) {
+ perror("read failed");
+ exit(2);
+ }
+ }
+ total_threads = header.thread_count;
+
+ sample_TOD_secs = header.TOD_secs;
+ sample_TOD_usecs = header.TOD_usecs;
+
+ if (total_threads == 0 && header.version_no != RAW_VERSION0) {
+ offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
+ offset = (offset + (4095)) & ~4095;
+
+ lseek(RAW_fd, offset, SEEK_SET);
+ }
+ } else {
+ total_threads = bufinfo.nkdthreads;
+ }
+
+ size = total_threads * sizeof(kd_threadmap);
+
+ if (size == 0 || ((mapptr = (kd_threadmap *) malloc(size)) == 0)) {
+ return;
+ }
+ bzero (mapptr, size);
+
+ /*
+ * Now read the threadmap
+ */
+ if (RAW_flag) {
+ if (read(RAW_fd, mapptr, size) != size) {
+ printf("Can't read the thread map -- this is not fatal\n");
+ }
+ if (header.version_no != RAW_VERSION0) {
+ offset = lseek(RAW_fd, (off_t)0, SEEK_CUR);
+ offset = (offset + (4095)) & ~4095;
+
+ lseek(RAW_fd, offset, SEEK_SET);
+ }
+ } else {
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDTHRMAP};
+ if (sysctl(mib, ARRAYSIZE(mib), mapptr, &size, NULL, 0) < 0) {
+ /*
+ * This is not fatal -- just means I cant map command strings
+ */
+ printf("Can't read the thread map -- this is not fatal\n");
+
+ total_threads = 0;
+ }
+ }
+ for (i = 0; i < total_threads; i++) {
+ create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
+ }
+ free(mapptr);
+}
+
+void
+create_map_entry(uint64_t thread, char *command)
+{
+ threadmap_t tme;
+
+ if ((tme = threadmap_freelist)) {
+ threadmap_freelist = tme->tm_next;
+ } else {
+ tme = (threadmap_t)malloc(sizeof(struct threadmap));
+ }
+
+ tme->tm_thread = thread;
+
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+ tme->tm_orig_command[0] = '\0';
+
+ int hashid = thread & HASH_MASK;
+
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+}
+
+static void
+delete_thread_entry(uint64_t thread)
+{
+ threadmap_t tme;
+
+ int hashid = thread & HASH_MASK;
+
+ if ((tme = threadmap_hash[hashid])) {
+ if (tme->tm_thread == thread) {
+ threadmap_hash[hashid] = tme->tm_next;
+ } else {
+ threadmap_t tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ tme->tm_next = threadmap_freelist;
+ threadmap_freelist = tme;
+ }
+ }
+}
+
+static void
+find_and_insert_tmp_map_entry(uint64_t pthread, char *command)
+{
+ threadmap_t tme;
+
+ if ((tme = threadmap_temp)) {
+ if (tme->tm_pthread == pthread) {
+ threadmap_temp = tme->tm_next;
+ } else {
+ threadmap_t tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_pthread == pthread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+ tme->tm_orig_command[0] = '\0';
+
+ int hashid = tme->tm_thread & HASH_MASK;
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+ }
+ }
+}
+
+static void
+create_tmp_map_entry(uint64_t thread, uint64_t pthread)
+{
+ threadmap_t tme;
+
+ if ((tme = threadmap_freelist)) {
+ threadmap_freelist = tme->tm_next;
+ } else {
+ tme = malloc(sizeof(struct threadmap));
+ }
+
+ tme->tm_thread = thread;
+ tme->tm_pthread = pthread;
+ tme->tm_command[0] = '\0';
+ tme->tm_orig_command[0] = '\0';
+
+ tme->tm_next = threadmap_temp;
+ threadmap_temp = tme;
+}
+
+static threadmap_t
+find_thread_entry(uint64_t thread)
+{
+ threadmap_t tme;
+
+ int hashid = thread & HASH_MASK;
+
+ for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread) {
+ return tme;
+ }
+ }
+ return 0;
+}
+
+static void
+find_thread_name(uint64_t thread, char **command)
+{
+ threadmap_t tme;
+
+ if ((tme = find_thread_entry(thread))) {
+ *command = tme->tm_command;
+ } else {
+ *command = EMPTYSTRING;
+ }
+}
+
+static void
+add_thread_entry_to_list(thread_entry_t *list, uint64_t thread)
+{
+ thread_entry_t te;
+
+ if ((te = thread_entry_freelist)) {
+ thread_entry_freelist = te->te_next;
+ } else {
+ te = (thread_entry_t)malloc(sizeof(struct thread_entry));
+ }
+
+ te->te_thread = thread;
+ te->te_next = *list;
+ *list = te;
+}
+
+static void
+exec_thread_entry(uint64_t thread, char *command)
+{
+ threadmap_t tme;
+
+ if ((tme = find_thread_entry(thread))) {
+ if (tme->tm_orig_command[0] == '\0') {
+ (void)strncpy (tme->tm_orig_command, tme->tm_command, MAXCOMLEN);
+ tme->tm_orig_command[MAXCOMLEN] = '\0';
+ }
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+
+ add_thread_entry_to_list(&thread_reset_list, thread);
+ } else {
+ create_map_entry(thread, command);
+ }
+}
+
+static void
+record_thread_entry_for_gc(uint64_t thread)
+{
+ add_thread_entry_to_list(&thread_delete_list, thread);
+}
+
+static void
+gc_thread_entries(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ int count = 0;
+
+ for (te = thread_delete_list; te; te = te_next) {
+ delete_thread_entry(te->te_thread);
+
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+
+ count++;
+ }
+ thread_delete_list = 0;
+}
+
+static void
+gc_reset_entries(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ int count = 0;
+
+ for (te = thread_reset_list; te; te = te_next) {
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+
+ count++;
+ }
+ thread_reset_list = 0;
+}
+
+static void
+reset_thread_names(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ int count = 0;
+
+ for (te = thread_reset_list; te; te = te_next) {
+ threadmap_t tme;
+
+ if ((tme = find_thread_entry(te->te_thread))) {
+ if (tme->tm_orig_command[0]) {
+ (void)strncpy (tme->tm_command, tme->tm_orig_command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+ tme->tm_orig_command[0] = '\0';
+ }
+ }
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+
+ count++;
+ }
+ thread_reset_list = 0;
+}
+
+static void
+delete_all_thread_entries(void)
+{
+ threadmap_t tme = 0;
+ threadmap_t tme_next = 0;
+ int i;
+
+ for (i = 0; i < HASH_SIZE; i++) {
+ for (tme = threadmap_hash[i]; tme; tme = tme_next) {
+ tme_next = tme->tm_next;
+ tme->tm_next = threadmap_freelist;
+ threadmap_freelist = tme;
+ }
+ threadmap_hash[i] = 0;
+ }
+}
+
+static void
+insert_run_event(uint64_t thread, int priority, kd_buf *kd, uint64_t now)
+{
+ threadrun_t trp;
+
+ int hashid = thread & HASH_MASK;
+
+ for (trp = threadrun_hash[hashid]; trp; trp = trp->tr_next) {
+ if (trp->tr_thread == thread) {
+ break;
+ }
+ }
+ if (trp == NULL) {
+ if ((trp = threadrun_freelist)) {
+ threadrun_freelist = trp->tr_next;
+ } else {
+ trp = (threadrun_t)malloc(sizeof(struct threadrun));
+ }
+
+ trp->tr_thread = thread;
+
+ trp->tr_next = threadrun_hash[hashid];
+ threadrun_hash[hashid] = trp;
+
+ add_thread_entry_to_list(&thread_run_list, thread);
+ }
+ trp->tr_entry = kd;
+ trp->tr_timestamp = now;
+ trp->tr_priority = priority;
+}
+
+static threadrun_t
+find_run_event(uint64_t thread)
+{
+ threadrun_t trp;
+ int hashid = thread & HASH_MASK;
+
+ for (trp = threadrun_hash[hashid]; trp; trp = trp->tr_next) {
+ if (trp->tr_thread == thread) {
+ return trp;
+ }
+ }
+ return 0;
+}
+
+static void
+delete_run_event(uint64_t thread)
+{
+ threadrun_t trp = 0;
+ threadrun_t trp_prev;
+
+ int hashid = thread & HASH_MASK;
+
+ if ((trp = threadrun_hash[hashid])) {
+ if (trp->tr_thread == thread) {
+ threadrun_hash[hashid] = trp->tr_next;
+ } else {
+ trp_prev = trp;
+
+ for (trp = trp->tr_next; trp; trp = trp->tr_next) {
+ if (trp->tr_thread == thread) {
+ trp_prev->tr_next = trp->tr_next;
+ break;
+ }
+ trp_prev = trp;
+ }
+ }
+ if (trp) {
+ trp->tr_next = threadrun_freelist;
+ threadrun_freelist = trp;
+ }
+ }
+}
+
+static void
+gc_run_events(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ threadrun_t trp;
+ threadrun_t trp_next;
+ int count = 0;
+
+ for (te = thread_run_list; te; te = te_next) {
+ int hashid = te->te_thread & HASH_MASK;
+
+ for (trp = threadrun_hash[hashid]; trp; trp = trp_next) {
+ trp_next = trp->tr_next;
+ trp->tr_next = threadrun_freelist;
+ threadrun_freelist = trp;
+ count++;
+ }
+ threadrun_hash[hashid] = 0;
+
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+ }
+ thread_run_list = 0;
+}
+
+
+
+static void
+insert_start_event(uint64_t thread, int type, uint64_t now)
+{
+ event_t evp;
+
+ int hashid = thread & HASH_MASK;
+
+ for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
+ if (evp->ev_thread == thread && evp->ev_type == type) {
+ break;
+ }
+ }
+ if (evp == NULL) {
+ if ((evp = event_freelist)) {
+ event_freelist = evp->ev_next;
+ } else {
+ evp = (event_t)malloc(sizeof(struct event));
+ }
+
+ evp->ev_thread = thread;
+ evp->ev_type = type;
+
+ evp->ev_next = event_hash[hashid];
+ event_hash[hashid] = evp;
+
+ add_thread_entry_to_list(&thread_event_list, thread);
+ }
+ evp->ev_timestamp = now;
+}
+
+
+static uint64_t
+consume_start_event(uint64_t thread, int type, uint64_t now)
+{
+ event_t evp;
+ event_t evp_prev;
+ uint64_t elapsed = 0;
+
+ int hashid = thread & HASH_MASK;
+
+ if ((evp = event_hash[hashid])) {
+ if (evp->ev_thread == thread && evp->ev_type == type) {
+ event_hash[hashid] = evp->ev_next;
+ } else {
+ evp_prev = evp;
+
+ for (evp = evp->ev_next; evp; evp = evp->ev_next) {
+ if (evp->ev_thread == thread && evp->ev_type == type) {
+ evp_prev->ev_next = evp->ev_next;
+ break;
+ }
+ evp_prev = evp;
+ }
+ }
+ if (evp) {
+ elapsed = now - evp->ev_timestamp;
+
+ if (now < evp->ev_timestamp) {
+ printf("consume: now = %qd, timestamp = %qd\n", now, evp->ev_timestamp);
+ elapsed = 0;
+ }
+ evp->ev_next = event_freelist;
+ event_freelist = evp;
+ }
+ }
+ return elapsed;
+}
+
+static void
+gc_start_events(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ event_t evp;
+ event_t evp_next;
+ int count = 0;
+ int hashid;
+
+ for (te = thread_event_list; te; te = te_next) {
+
+ hashid = te->te_thread & HASH_MASK;
+
+ for (evp = event_hash[hashid]; evp; evp = evp_next) {
+ evp_next = evp->ev_next;
+ evp->ev_next = event_freelist;
+ event_freelist = evp;
+ count++;
+ }
+ event_hash[hashid] = 0;
+
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+ }
+ thread_event_list = 0;
+}
+
+static int
+thread_in_user_mode(uint64_t thread, char *command)
+{
+ event_t evp;
+
+ if (strcmp(command, "kernel_task") == 0) {
+ return 0;
+ }
+
+ int hashid = thread & HASH_MASK;
+
+ for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
+ if (evp->ev_thread == thread) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static lookup_t
+handle_lookup_event(uint64_t thread, int debugid, kd_buf *kdp)
+{
+ lookup_t lkp;
+ boolean_t first_record = FALSE;
+
+ int hashid = thread & HASH_MASK;
+
+ if (debugid & DBG_FUNC_START) {
+ first_record = TRUE;
+ }
+
+ for (lkp = lookup_hash[hashid]; lkp; lkp = lkp->lk_next) {
+ if (lkp->lk_thread == thread) {
+ break;
+ }
+ }
+ if (lkp == NULL) {
+ if (first_record == FALSE) {
+ return 0;
+ }
+
+ if ((lkp = lookup_freelist)) {
+ lookup_freelist = lkp->lk_next;
+ } else {
+ lkp = (lookup_t)malloc(sizeof(struct lookup));
+ }
+
+ lkp->lk_thread = thread;
+
+ lkp->lk_next = lookup_hash[hashid];
+ lookup_hash[hashid] = lkp;
+
+ add_thread_entry_to_list(&thread_lookup_list, thread);
+ }
+
+ if (first_record == TRUE) {
+ lkp->lk_pathptr = lkp->lk_pathname;
+ lkp->lk_dvp = kdp->arg1;
+ } else {
+ if (lkp->lk_pathptr > &lkp->lk_pathname[NUMPARMS-4]) {
+ return lkp;
+ }
+ *lkp->lk_pathptr++ = kdp->arg1;
+ }
+ *lkp->lk_pathptr++ = kdp->arg2;
+ *lkp->lk_pathptr++ = kdp->arg3;
+ *lkp->lk_pathptr++ = kdp->arg4;
+ *lkp->lk_pathptr = 0;
+
+ if (debugid & DBG_FUNC_END) {
+ return lkp;
+ }
+
+ return 0;
+}
+
+static void
+delete_lookup_event(uint64_t thread, lookup_t lkp_to_delete)
+{
+ lookup_t lkp;
+ lookup_t lkp_prev;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ if ((lkp = lookup_hash[hashid])) {
+ if (lkp == lkp_to_delete) {
+ lookup_hash[hashid] = lkp->lk_next;
+ } else {
+ lkp_prev = lkp;
+
+ for (lkp = lkp->lk_next; lkp; lkp = lkp->lk_next) {
+ if (lkp == lkp_to_delete) {
+ lkp_prev->lk_next = lkp->lk_next;
+ break;
+ }
+ lkp_prev = lkp;
+ }
+ }
+ if (lkp) {
+ lkp->lk_next = lookup_freelist;
+ lookup_freelist = lkp;
+ }
+ }
+}
+
+static void
+gc_lookup_events(void)
+{
+ thread_entry_t te;
+ thread_entry_t te_next;
+ lookup_t lkp;
+ lookup_t lkp_next;
+ int count = 0;
+ int hashid;
+
+ for (te = thread_lookup_list; te; te = te_next) {
+ hashid = te->te_thread & HASH_MASK;
+
+ for (lkp = lookup_hash[hashid]; lkp; lkp = lkp_next) {
+ lkp_next = lkp->lk_next;
+ lkp->lk_next = lookup_freelist;
+ lookup_freelist = lkp;
+ count++;
+ }
+ lookup_hash[hashid] = 0;
+
+ te_next = te->te_next;
+ te->te_next = thread_entry_freelist;
+ thread_entry_freelist = te;
+ }
+ thread_lookup_list = 0;
+}
+
+int
+sample_sc(void)
+{
+ kd_buf *kd, *end_of_sample;
+ int keep_going = 1;
+ int i;
+ ssize_t count;
+
+ if (!RAW_flag) {
+ /*
+ * Get kernel buffer information
+ */
+ get_bufinfo(&bufinfo);
+ }
+ if (need_new_map) {
+ delete_all_thread_entries();
+ read_command_map();
+ need_new_map = 0;
+ }
+ if (RAW_flag) {
+ ssize_t bytes_read;
+
+ bytes_read = read(RAW_fd, my_buffer, num_entries * sizeof(kd_buf));
+
+ if (bytes_read == -1) {
+ perror("read failed");
+ exit(2);
+ }
+ count = bytes_read / sizeof(kd_buf);
+
+ if (count != num_entries) {
+ keep_going = 0;
+ }
+
+ if (first_read) {
+ kd = (kd_buf *)my_buffer;
+ first_now = kd->timestamp & KDBG_TIMESTAMP_MASK;
+ first_read = 0;
+ }
+
+ } else {
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDREADTR };
+ size_t needed = bufinfo.nkdbufs * sizeof(kd_buf);
+
+ if (sysctl(mib, ARRAYSIZE(mib), my_buffer, &needed, NULL, 0) < 0) {
+ quit("trace facility failure, KERN_KDREADTR\n");
+ }
+
+ count = needed;
+ sample_generation++;
+
+ if (bufinfo.flags & KDBG_WRAPPED) {
+ need_new_map = 1;
+
+ if (log_fp) {
+ fprintf(log_fp, "\n\n%-19.19s sample = %d <<<<<<< trace buffer wrapped >>>>>>>\n\n",
+ &(ctime(&curr_time)[0]), sample_generation);
+ }
+ set_enable(0);
+ set_enable(1);
+ }
+ }
+ end_of_sample = &((kd_buf *)my_buffer)[count];
+
+ /*
+ * Always reinitialize the DECR_TRAP array
+ */
+ for (i = 0; i < num_cpus; i++) {
+ last_decrementer_kd[i] = (kd_buf *)my_buffer;
+ }
+
+ for (kd = (kd_buf *)my_buffer; kd < end_of_sample; kd++) {
+ kd_buf *kd_start;
+ uint64_t thread = kd->arg5;
+ int type = kd->debugid & DBG_FUNC_MASK;
+
+ (void)check_for_thread_update(thread, type, kd, NULL);
+
+ uint64_t now = kd->timestamp & KDBG_TIMESTAMP_MASK;
+ last_now = now;
+
+ if (type == DECR_TRAP) {
+ int cpunum = CPU_NUMBER(kd);
+ double i_latency = handle_decrementer(kd, cpunum);
+
+ if (log_fp) {
+ if (i_thresh_hold && (int)i_latency > i_thresh_hold) {
+ kd_start = last_decrementer_kd[cpunum];
+
+ log_decrementer(kd_start, kd, end_of_sample, i_latency);
+ }
+ last_decrementer_kd[cpunum] = kd;
+ }
+ } else {
+ double s_latency;
+ int s_priority;
+ if (check_for_scheduler_latency(type, &thread, now, kd, &kd_start, &s_priority, &s_latency)) {
+ log_scheduler(kd_start, kd, end_of_sample, s_priority, s_latency, thread);
+ }
+ }
+ }
+ if (log_fp) {
+ fflush(log_fp);
+ }
+
+ gc_thread_entries();
+ gc_reset_entries();
+ gc_run_events();
+
+ return keep_going;
+}
+
+void
+enter_syscall(FILE *fp, kd_buf *kd, uint64_t thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info)
+{
+ char *p;
+ double timestamp;
+ double delta;
+ char pcstring[128];
+
+ int cpunum = CPU_NUMBER(kd);
+
+ if (print_info && fp) {
+ timestamp = (double)(now - start_bias) / divisor;
+ delta = (double)idelta / divisor;
+
+ if ((p = find_code(type))) {
+ if (type == INTERRUPT) {
+ int mode;
+
+ if (kd->arg3) {
+ mode = USER_MODE;
+ } else {
+ mode = KERNEL_MODE;
+ }
+
+ pc_to_string(&pcstring[0], kd->arg2, 58, mode);
+
+ fprintf(fp, "%9.1f %8.1f\t\tINTERRUPT[%2" PRIx64 "] @ %-58.58s %8" PRIx64 " %2d %s\n",
+ timestamp, delta, (uint64_t)kd->arg1, &pcstring[0], thread, cpunum, command);
+ } else if (type == MACH_vmfault) {
+ fprintf(fp, "%9.1f %8.1f\t\t%-28.28s %8" PRIx64 " %2d %s\n",
+ timestamp, delta, p, thread, cpunum, command);
+ } else {
+ fprintf(fp, "%9.1f %8.1f\t\t%-28.28s %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %8" PRIx64 " %2d %s\n",
+ timestamp, delta, p, (uint64_t)kd->arg1, (uint64_t)kd->arg2, (uint64_t)kd->arg3, (uint64_t)kd->arg4,
+ thread, cpunum, command);
+ }
+ } else {
+ fprintf(fp, "%9.1f %8.1f\t\t%-8x %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %8" PRIx64 " %2d %s\n",
+ timestamp, delta, type, (uint64_t)kd->arg1, (uint64_t)kd->arg2, (uint64_t)kd->arg3, (uint64_t)kd->arg4,
+ thread, cpunum, command);
+ }
+ }
+ if (type != BSC_thread_terminate && type != BSC_exit) {
+ insert_start_event(thread, type, now);
+ }
+}
+
+void
+exit_syscall(FILE *fp, kd_buf *kd, uint64_t thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, int print_info)
+{
+ char *p;
+ uint64_t user_addr;
+ double timestamp;
+ double delta;
+ double elapsed_timestamp;
+
+ elapsed_timestamp = (double)consume_start_event(thread, type, now) / divisor;
+
+ if (print_info && fp) {
+ int cpunum = CPU_NUMBER(kd);
+
+ timestamp = (double)(now - start_bias) / divisor;
+ delta = (double)idelta / divisor;
+
+ fprintf(fp, "%9.1f %8.1f(%.1f) \t", timestamp, delta, elapsed_timestamp);
+
+ if ((p = find_code(type))) {
+ if (type == INTERRUPT) {
+ fprintf(fp, "INTERRUPT %8" PRIx64 " %2d %s\n", thread, cpunum, command);
+ } else if (type == MACH_vmfault && kd->arg4 <= DBG_PAGEIND_FAULT) {
+ user_addr = ((uint64_t)kd->arg1 << 32) | (uint32_t)kd->arg2;
+
+ fprintf(fp, "%-28.28s %-10.10s %-16qx %8" PRIx64 " %2d %s\n",
+ p, fault_name[kd->arg4], user_addr,
+ thread, cpunum, command);
+ } else {
+ fprintf(fp, "%-28.28s %-16" PRIx64 " %-16" PRIx64 " %8" PRIx64 " %2d %s\n",
+ p, (uint64_t)kd->arg1, (uint64_t)kd->arg2,
+ thread, cpunum, command);
+ }
+ } else {
+ fprintf(fp, "%-8x %-16" PRIx64 " %-16" PRIx64 " %8" PRIx64 " %2d %s\n",
+ type, (uint64_t)kd->arg1, (uint64_t)kd->arg2,
+ thread, cpunum, command);
+ }
+ }
+}
+
+void
+print_entry(FILE *fp, kd_buf *kd, uint64_t thread, int type, char *command, uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd_note)
+{
+ char *p;
+
+ if (!fp) {
+ return;
+ }
+
+ int cpunum = CPU_NUMBER(kd);
+
+ double timestamp = (double)(now - start_bias) / divisor;
+ double delta = (double)idelta / divisor;
+
+ if ((p = find_code(type))) {
+ if (kd == kd_note) {
+ fprintf(fp, "%9.1f %8.1f\t**\t", timestamp, delta);
+ } else {
+ fprintf(fp, "%9.1f %8.1f\t\t", timestamp, delta);
+ }
+ fprintf(fp, "%-28.28s %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %8" PRIx64 " %2d %s\n",
+ p, (uint64_t)kd->arg1, (uint64_t)kd->arg2, (uint64_t)kd->arg3, (uint64_t)kd->arg4, thread, cpunum, command);
+ } else {
+ fprintf(fp, "%9.1f %8.1f\t\t%-8x %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %8" PRIx64 " %2d %s\n",
+ timestamp, delta, type, (uint64_t)kd->arg1, (uint64_t)kd->arg2, (uint64_t)kd->arg3, (uint64_t)kd->arg4,
+ thread, cpunum, command);
+ }
+}
+
+void
+check_for_thread_update(uint64_t thread, int debugid_base, kd_buf *kbufp, char **command)
+{
+ if (debugid_base == TRACE_DATA_NEWTHREAD) {
+ /*
+ * Save the create thread data
+ */
+ create_tmp_map_entry(kbufp->arg1, thread);
+ } else if (debugid_base == TRACE_STRING_NEWTHREAD) {
+ /*
+ * process new map entry
+ */
+ find_and_insert_tmp_map_entry(thread, (char *)&kbufp->arg1);
+ } else if (debugid_base == TRACE_STRING_EXEC) {
+ exec_thread_entry(thread, (char *)&kbufp->arg1);
+ } else {
+ if (debugid_base == BSC_exit || debugid_base == BSC_thread_terminate) {
+ record_thread_entry_for_gc(thread);
+ }
+ if (command) {
+ find_thread_name(thread, command);
+ }
+ }
+}
+
+void
+log_info(uint64_t now, uint64_t idelta, uint64_t start_bias, kd_buf *kd, kd_buf *kd_note)
+{
+ lookup_t lkp;
+ int mode;
+ uint64_t reason;
+ char *p;
+ char *command;
+ char *command1;
+ char command_buf[32];
+ char sched_info[64];
+ char pcstring[128];
+ const char *sched_reason;
+ double i_latency;
+ double timestamp;
+ double delta;
+ char joe[32];
+
+ uint64_t thread = kd->arg5;
+ int cpunum = CPU_NUMBER(kd);
+ int debugid = kd->debugid;
+ int type = kd->debugid & DBG_FUNC_MASK;
+
+ (void)check_for_thread_update(thread, type, kd, &command);
+
+ if ((type >> 24) == DBG_TRACE) {
+ if (((type >> 16) & 0xff) != DBG_TRACE_INFO) {
+ return;
+ }
+ }
+ timestamp = (double)(now - start_bias) / divisor;
+ delta = (double)idelta / divisor;
+
+ switch (type) {
+
+ case CQ_action:
+ pc_to_string(&pcstring[0], kd->arg1, 84, KERNEL_MODE);
+
+ fprintf(log_fp, "%9.1f %8.1f\t\tCQ_action @ %-84.84s %8" PRIx64 " %2d %s\n",
+ timestamp, delta, &pcstring[0], thread, cpunum, command);
+ break;
+
+ case TES_action:
+ pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
+
+ fprintf(log_fp, "%9.1f %8.1f\t\tTES_action @ %-83.83s %8" PRIx64 " %2d %s\n",
+ timestamp, delta, &pcstring[0], thread, cpunum, command);
+ break;
+
+ case IES_action:
+ pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
+
+ fprintf(log_fp, "%9.1f %8.1f\t\tIES_action @ %-83.83s %8" PRIx64 " %2d %s\n",
+ timestamp, delta, &pcstring[0], thread, cpunum, command);
+ break;
+
+ case IES_filter:
+ pc_to_string(&pcstring[0], kd->arg1, 83, KERNEL_MODE);
+
+ fprintf(log_fp, "%9.1f %8.1f\t\tIES_filter @ %-83.83s %8" PRIx64 " %2d %s\n",
+ timestamp, delta, &pcstring[0], thread, cpunum, command);
+ break;
+
+ case DECR_TRAP:
+ if ((int)kd->arg1 >= 0) {
+ i_latency = 0;
+ } else {
+ i_latency = (((double)(-1 - kd->arg1)) / divisor);
+ }
+
+ if (i_thresh_hold && (int)i_latency > i_thresh_hold) {
+ p = "*";
+ } else {
+ p = " ";
+ }
+
+ if (kd->arg3) {
+ mode = USER_MODE;
+ } else {
+ mode = KERNEL_MODE;
+ }
+
+ pc_to_string(&pcstring[0], kd->arg2, 84, mode);
+
+ fprintf(log_fp, "%9.1f %8.1f[%.1f]%s\tDECR_TRAP @ %-84.84s %8" PRIx64 " %2d %s\n",
+ timestamp, delta, i_latency, p, &pcstring[0], thread, cpunum, command);
+ break;
+
+ case DECR_SET:
+ fprintf(log_fp, "%9.1f %8.1f[%.1f] \t%-28.28s %8" PRIx64 " %2d %s\n",
+ timestamp, delta, (double)kd->arg1/divisor, "DECR_SET", thread, cpunum, command);
+ break;
+
+ case MACH_sched:
+ case MACH_stkhandoff:
+
+ find_thread_name(kd->arg2, &command1);
+
+ if (command1 == EMPTYSTRING) {
+ command1 = command_buf;
+ sprintf(command1, "%-8" PRIx64, (uint64_t)kd->arg2);
+ }
+ if (thread_in_user_mode(kd->arg2, command1)) {
+ p = "U";
+ } else {
+ p = "K";
+ }
+
+ reason = kd->arg1;
+
+ if (reason > MAX_REASON) {
+ sched_reason = "?";
+ } else {
+ sched_reason = sched_reasons[reason];
+ }
+
+ if (sched_reason[0] == '?') {
+ sprintf(joe, "%" PRIx64, reason);
+ sched_reason = joe;
+ }
+ sprintf(sched_info, "%16.16s @ pri %3" PRIu64 " --> %16.16s @ pri %3" PRIu64 "%s", command, (uint64_t)kd->arg3, command1, (uint64_t)kd->arg4, p);
+
+ fprintf(log_fp, "%9.1f %8.1f\t\t%-10.10s[%s] %s %8" PRIx64 " %2d\n",
+ timestamp, delta, "MACH_SCHED", sched_reason, sched_info, thread, cpunum);
+ break;
+
+ case VFS_LOOKUP:
+ if ((lkp = handle_lookup_event(thread, debugid, kd))) {
+ /*
+ * print the tail end of the pathname
+ */
+ p = (char *)lkp->lk_pathname;
+ size_t clen = strlen(p);
+
+ if (clen > 45) {
+ clen -= 45;
+ } else {
+ clen = 0;
+ }
+
+ fprintf(log_fp, "%9.1f %8.1f\t\t%-14.14s %-59s %-16" PRIx64 " %8" PRIx64 " %2d %s\n",
+ timestamp, delta, "VFS_LOOKUP",
+ &p[clen], lkp->lk_dvp, thread, cpunum, command);
+
+ delete_lookup_event(thread, lkp);
+ }
+ break;
+
+ default:
+ if (debugid & DBG_FUNC_START) {
+ enter_syscall(log_fp, kd, thread, type, command, now, idelta, start_bias, 1);
+ } else if (debugid & DBG_FUNC_END) {
+ exit_syscall(log_fp, kd, thread, type, command, now, idelta, start_bias, 1);
+ } else {
+ print_entry(log_fp, kd, thread, type, command, now, idelta, start_bias, kd_note);
+ }
+ break;
+ }
+}
+
+static void
+log_range(kd_buf *kd_buffer, kd_buf *kd_start, kd_buf *kd_stop, kd_buf *kd_note, char *buf1)
+{
+ uint64_t last_timestamp = 0;
+ uint64_t delta = 0;
+ uint64_t start_bias = 0;
+ uint64_t now;
+ kd_buf *kd;
+ size_t clen;
+ char buf2[128];
+
+ clen = strlen(buf1);
+ memset(buf2, '-', clen);
+ buf2[clen] = 0;
+ fprintf(log_fp, "\n\n%s\n", buf2);
+ fprintf(log_fp, "%s\n\n", buf1);
+
+ fprintf(log_fp, "RelTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu command\n\n");
+
+ reset_thread_names();
+
+ last_timestamp = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
+ start_bias = last_timestamp;
+
+ for (kd = kd_buffer; kd <= kd_stop; kd++) {
+ now = kd->timestamp & KDBG_TIMESTAMP_MASK;
+
+ if (kd >= kd_start) {
+ delta = now - last_timestamp;
+
+ log_info(now, delta, start_bias, kd, kd_note);
+
+ last_timestamp = now;
+ } else {
+ int debugid = kd->debugid;
+ uint64_t thread = kd->arg5;
+ int type = kd->debugid & DBG_FUNC_MASK;
+
+ if ((type >> 24) == DBG_TRACE) {
+ if (((type >> 16) & 0xff) != DBG_TRACE_INFO) {
+ continue;
+ }
+ }
+ if (type == BSC_thread_terminate || type == BSC_exit) {
+ continue;
+ }
+
+ if (debugid & DBG_FUNC_START) {
+ insert_start_event(thread, type, now);
+ } else if (debugid & DBG_FUNC_END) {
+ (void)consume_start_event(thread, type, now);
+ }
+ }
+ }
+ gc_start_events();
+ gc_lookup_events();
+}
+
+kd_buf *
+log_decrementer(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, double i_latency)
+{
+ kd_buf *kd_start, *kd_stop;
+ int kd_count; /* Limit the boundary of kd_start */
+ uint64_t now;
+ double sample_timestamp;
+ char buf1[128];
+
+ uint64_t thread = kd_beg->arg5;
+ int cpunum = CPU_NUMBER(kd_end);
+
+ for (kd_count = 0, kd_start = kd_beg - 1; (kd_start >= (kd_buf *)my_buffer); kd_start--, kd_count++) {
+ if (kd_count == MAX_LOG_COUNT) {
+ break;
+ }
+
+ if (CPU_NUMBER(kd_start) != cpunum) {
+ continue;
+ }
+
+ if ((kd_start->debugid & DBG_FUNC_MASK) == DECR_TRAP) {
+ break;
+ }
+
+ if (kd_start->arg5 != thread) {
+ break;
+ }
+ }
+ if (kd_start < (kd_buf *)my_buffer) {
+ kd_start = (kd_buf *)my_buffer;
+ }
+
+ thread = kd_end->arg5;
+
+ for (kd_stop = kd_end + 1; kd_stop < end_of_sample; kd_stop++) {
+ if (CPU_NUMBER(kd_stop) != cpunum) {
+ continue;
+ }
+
+ if ((kd_stop->debugid & DBG_FUNC_MASK) == INTERRUPT) {
+ break;
+ }
+
+ if (kd_stop->arg5 != thread) {
+ break;
+ }
+ }
+ if (kd_stop >= end_of_sample) {
+ kd_stop = end_of_sample - 1;
+ }
+
+ if (RAW_flag) {
+ time_t TOD_secs;
+ uint64_t TOD_usecs;
+
+ now = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
+ sample_timestamp = (double)(now - first_now) / divisor;
+
+ TOD_usecs = (uint64_t)sample_timestamp;
+ TOD_secs = (unsigned long)sample_TOD_secs + (unsigned long)((sample_TOD_usecs + TOD_usecs) / 1000000);
+
+ sprintf(buf1, "%-19.19s interrupt latency = %.1fus [timestamp %.1f]", ctime(&TOD_secs), i_latency, sample_timestamp);
+ } else {
+ sprintf(buf1, "%-19.19s interrupt latency = %.1fus [sample %d]", &(ctime(&curr_time)[0]), i_latency, sample_generation);
+ }
+
+ log_range((kd_buf *)my_buffer, kd_start, kd_stop, 0, buf1);
+
+ return kd_stop;
+}
+
+
+void
+log_scheduler(kd_buf *kd_beg, kd_buf *kd_end, kd_buf *end_of_sample, int s_priority, double s_latency, uint64_t thread)
+{
+ kd_buf *kd_start, *kd_stop;
+ uint64_t now;
+ int count;
+ int cpunum;
+ uint64_t cmask = 0;
+ double sample_timestamp;
+ char buf1[128];
+
+ for (count = 0, kd_start = kd_beg; (kd_start >= (kd_buf *)my_buffer); kd_start--) {
+ cpunum = CPU_NUMBER(kd_start);
+
+ cmask |= ((uint64_t)1 << cpunum);
+
+ if (cmask == cpu_mask) {
+ if (count++ > 100)
+ break;
+ }
+ }
+ if (kd_start < (kd_buf *)my_buffer) {
+ kd_start = (kd_buf *)my_buffer;
+ }
+
+ for (kd_stop = kd_end + 1; kd_stop < end_of_sample; kd_stop++) {
+ if (kd_stop->arg5 == thread) {
+ break;
+ }
+ }
+ if (kd_stop >= end_of_sample) {
+ kd_stop = end_of_sample - 1;
+ }
+
+ if (RAW_flag) {
+ time_t TOD_secs;
+ uint64_t TOD_usecs;
+
+ now = kd_start->timestamp & KDBG_TIMESTAMP_MASK;
+ sample_timestamp = (double)(now - first_now) / divisor;
+
+ TOD_usecs = (uint64_t)sample_timestamp;
+ TOD_secs = (unsigned long)sample_TOD_secs + (unsigned long)((sample_TOD_usecs + TOD_usecs) / 1000000);
+
+ sprintf(buf1, "%-19.19s priority = %d, scheduling latency = %.1fus [timestamp %.1f]", ctime(&TOD_secs), s_priority, s_latency, sample_timestamp);
+ } else {
+ sprintf(buf1, "%-19.19s priority = %d, scheduling latency = %.1fus [sample %d]", &(ctime(&curr_time)[0]), s_priority, s_latency, sample_generation);
+ }
+
+ log_range((kd_buf *)my_buffer, kd_start, kd_stop, kd_beg, buf1);
+}
+
+int
+check_for_scheduler_latency(int type, uint64_t *thread, uint64_t now, kd_buf *kd, kd_buf **kd_start, int *priority, double *latency)
+{
+ int found_latency = 0;
+
+ if (type == MACH_makerunnable) {
+ if (watch_priority_min <= kd->arg2 && kd->arg2 <= watch_priority_max) {
+ insert_run_event(kd->arg1, (int)kd->arg2, kd, now);
+ }
+ } else if (type == MACH_sched || type == MACH_stkhandoff) {
+ threadrun_t trp = find_run_event(kd->arg2);
+
+ if (type == MACH_sched || type == MACH_stkhandoff) {
+ *thread = kd->arg2;
+ }
+
+ if ((trp = find_run_event(*thread))) {
+ double d_s_latency = (((double)(now - trp->tr_timestamp)) / divisor);
+ int s_latency = (int)d_s_latency;
+
+ if (s_latency) {
+ if (s_latency < 100) {
+ s_usec_10_bins[s_latency/10]++;
+ }
+ if (s_latency < 1000) {
+ s_usec_100_bins[s_latency/100]++;
+ } else if (s_latency < 10000) {
+ s_msec_1_bins[s_latency/1000]++;
+ } else if (s_latency < 50000) {
+ s_msec_10_bins[s_latency/10000]++;
+ } else {
+ s_too_slow++;
+ }
+
+ if (s_latency > s_max_latency) {
+ s_max_latency = s_latency;
+ }
+ if (s_latency < s_min_latency || s_total_samples == 0) {
+ s_min_latency = s_latency;
+ }
+ s_total_latency += s_latency;
+ s_total_samples++;
+
+ if (s_thresh_hold && s_latency > s_thresh_hold) {
+ s_exceeded_threshold++;
+
+ if (log_fp) {
+ *kd_start = trp->tr_entry;
+ *priority = trp->tr_priority;
+ *latency = d_s_latency;
+ found_latency = 1;
+ }
+ }
+ }
+ delete_run_event(*thread);
+ }
+ }
+ return found_latency;
+}
+
+double
+handle_decrementer(kd_buf *kd, int cpunum)
+{
+ struct i_latencies *il;
+ double latency;
+ long elapsed_usecs;
+
+ if (i_latency_per_cpu == FALSE) {
+ cpunum = 0;
+ }
+
+ il = &i_lat[cpunum];
+
+ if ((long)(kd->arg1) >= 0) {
+ latency = 1;
+ } else {
+ latency = (((double)(-1 - kd->arg1)) / divisor);
+ }
+ elapsed_usecs = (long)latency;
+
+ if (elapsed_usecs < 100) {
+ il->i_usec_10_bins[elapsed_usecs/10]++;
+ }
+
+ if (elapsed_usecs < 1000) {
+ il->i_usec_100_bins[elapsed_usecs/100]++;
+ } else if (elapsed_usecs < 10000) {
+ il->i_msec_1_bins[elapsed_usecs/1000]++;
+ } else if (elapsed_usecs < 50000) {
+ il->i_msec_10_bins[elapsed_usecs/10000]++;
+ } else {
+ il->i_too_slow++;
+ }
+
+ if (use_high_res_bins && elapsed_usecs < N_HIGH_RES_BINS) {
+ i_high_res_bins[elapsed_usecs]++;
+ }
+ if (i_thresh_hold && elapsed_usecs > i_thresh_hold) {
+ il->i_exceeded_threshold++;
+ }
+ if (elapsed_usecs > il->i_max_latency) {
+ il->i_max_latency = elapsed_usecs;
+ }
+ if (elapsed_usecs < il->i_min_latency || il->i_total_samples == 0) {
+ il->i_min_latency = elapsed_usecs;
+ }
+ il->i_total_latency += elapsed_usecs;
+ il->i_total_samples++;
+
+ return latency;
+}
+
+char *
+find_code(int type)
+{
+ int i;
+ for (i = 0; i < num_of_codes; i++) {
+ if (codes_tab[i].type == type) {
+ return codes_tab[i].name;
+ }
+ }
+ return NULL;
+}
+
+void
+init_code_file(void)
+{
+ FILE *fp;
+ int i;
+
+ if ((fp = fopen(code_file, "r")) == NULL) {
+ if (log_fp) {
+ fprintf(log_fp, "open of %s failed\n", code_file);
+ }
+ return;
+ }
+ for (i = 0; i < MAX_ENTRIES; i++) {
+ int code;
+ char name[128];
+ int n = fscanf(fp, "%x%127s\n", &code, name);
+
+ if (n == 1 && i == 0) {
+ /*
+ * old code file format, just skip
+ */
+ continue;
+ }
+ if (n != 2) {
+ break;
+ }
+
+ strncpy(codes_tab[i].name, name, 32);
+ codes_tab[i].type = code;
+ }
+ num_of_codes = i;
+
+ fclose(fp);
+}
+
+void
+do_kernel_nm(void)
+{
+ int i;
+ size_t len;
+ FILE *fp = NULL;
+ char tmp_nm_file[128];
+ char tmpstr[1024];
+ char inchr;
+
+ bzero(tmp_nm_file, 128);
+ bzero(tmpstr, 1024);
+
+ /*
+ * Build the temporary nm file path
+ */
+ strcpy(tmp_nm_file,"/tmp/knm.out.XXXXXX");
+
+ if (!mktemp(tmp_nm_file)) {
+ fprintf(stderr, "Error in mktemp call\n");
+ return;
+ }
+
+ /*
+ * Build the nm command and create a tmp file with the output
+ */
+ sprintf (tmpstr, "/usr/bin/nm -n %s -s __TEXT __text > %s",
+ kernelpath, tmp_nm_file);
+ system(tmpstr);
+
+ /*
+ * Parse the output from the nm command
+ */
+ if ((fp = fopen(tmp_nm_file, "r")) == NULL) {
+ /* Hmmm, let's not treat this as fatal */
+ fprintf(stderr, "Failed to open nm symbol file [%s]\n", tmp_nm_file);
+ return;
+ }
+ /*
+ * Count the number of symbols in the nm symbol table
+ */
+ kern_sym_count = 0;
+
+ while ((inchr = getc(fp)) != -1) {
+ if (inchr == '\n') {
+ kern_sym_count++;
+ }
+ }
+ rewind(fp);
+
+ /*
+ * Malloc the space for symbol table
+ */
+ if (kern_sym_count > 0) {
+ kern_sym_tbl = malloc(kern_sym_count * sizeof(kern_sym_t));
+
+ if (!kern_sym_tbl) {
+ /*
+ * Hmmm, lets not treat this as fatal
+ */
+ fprintf(stderr, "Can't allocate memory for kernel symbol table\n");
+ } else {
+ bzero(kern_sym_tbl, kern_sym_count * sizeof(kern_sym_t));
+ }
+ } else {
+ /*
+ * Hmmm, lets not treat this as fatal
+ */
+ fprintf(stderr, "No kernel symbol table \n");
+ }
+ for (i = 0; i < kern_sym_count; i++) {
+ bzero(tmpstr, 1024);
+
+ if (fscanf(fp, "%p %c %s", &kern_sym_tbl[i].k_sym_addr, &inchr, tmpstr) != 3) {
+ break;
+ } else {
+ len = strlen(tmpstr);
+ kern_sym_tbl[i].k_sym_name = malloc(len + 1);
+
+ if (kern_sym_tbl[i].k_sym_name == NULL) {
+ fprintf(stderr, "Can't allocate memory for symbol name [%s]\n", tmpstr);
+ kern_sym_tbl[i].k_sym_name = NULL;
+ len = 0;
+ } else {
+ strcpy(kern_sym_tbl[i].k_sym_name, tmpstr);
+ }
+
+ kern_sym_tbl[i].k_sym_len = len;
+ }
+ }
+ if (i != kern_sym_count) {
+ /*
+ * Hmmm, didn't build up entire table from nm
+ * scrap the entire thing
+ */
+ free(kern_sym_tbl);
+ kern_sym_tbl = NULL;
+ kern_sym_count = 0;
+ }
+ fclose(fp);
+
+ /*
+ * Remove the temporary nm file
+ */
+ unlink(tmp_nm_file);
+#if 0
+ /*
+ * Dump the kernel symbol table
+ */
+ for (i = 0; i < kern_sym_count; i++) {
+ if (kern_sym_tbl[i].k_sym_name) {
+ printf ("[%d] %-16p %s\n", i,
+ kern_sym_tbl[i].k_sym_addr, kern_sym_tbl[i].k_sym_name);
+ } else {
+ printf ("[%d] %-16p %s\n", i,
+ kern_sym_tbl[i].k_sym_addr, "No symbol name");
+ }
+ }
+#endif
+}
+
+void
+pc_to_string(char *pcstring, uint64_t pc, int max_len, int mode)
+{
+ int ret;
+ size_t len;
+
+ if (mode == USER_MODE) {
+ sprintf(pcstring, "%-16" PRIx64 " [usermode addr]", pc);
+ return;
+ }
+ ret = binary_search(kern_sym_tbl, 0, kern_sym_count-1, pc);
+
+ if (ret == -1 || kern_sym_tbl[ret].k_sym_name == NULL) {
+ sprintf(pcstring, "%-16" PRIx64, pc);
+ return;
+ }
+ if ((len = kern_sym_tbl[ret].k_sym_len) > (max_len - 8)) {
+ len = max_len - 8;
+ }
+
+ memcpy(pcstring, kern_sym_tbl[ret].k_sym_name, len);
+
+ sprintf(&pcstring[len], "+0x%-5" PRIx64, pc - (uint64_t)kern_sym_tbl[ret].k_sym_addr);
+}
+
+
+/*
+ * Return -1 if not found, else return index
+ */
+int
+binary_search(kern_sym_t *list, int low, int high, uint64_t addr)
+{
+ int mid;
+
+ if (kern_sym_count == 0) {
+ return -1;
+ }
+
+ if (low > high) {
+ return -1; /* failed */
+ }
+
+ if (low + 1 == high) {
+ if ((uint64_t)list[low].k_sym_addr <= addr && addr < (uint64_t)list[high].k_sym_addr) {
+ /*
+ * We have a range match
+ */
+ return low;
+ }
+ if ((uint64_t)list[high].k_sym_addr <= addr) {
+ return high;
+ }
+ /*
+ * Failed
+ */
+ return -1;
+ }
+ mid = (low + high) / 2;
+
+ if (addr < (uint64_t)list[mid].k_sym_addr) {
+ return binary_search(list, low, mid, addr);
+ }
+
+ return binary_search(list, mid, high, addr);
+}
+
+void
+open_logfile(const char *path)
+{
+ log_fp = fopen(path, "a");
+
+ if (!log_fp) {
+ /*
+ * failed to open path
+ */
+ fprintf(stderr, "latency: failed to open logfile [%s]\n", path);
+ exit_usage();
+ }
+}
+
+void
+open_rawfile(const char *path)
+{
+ RAW_fd = open(path, O_RDONLY);
+
+ if (RAW_fd == -1) {
+ /*
+ * failed to open path
+ */
+ fprintf(stderr, "latency: failed to open RAWfile [%s]\n", path);
+ exit_usage();
+ }
+}
+
+void
+getdivisor(void)
+{
+ mach_timebase_info_data_t info;
+
+ (void)mach_timebase_info(&info);
+
+ divisor = ((double)info.denom / (double)info.numer) * 1000;
+}
diff --git a/system_cmds/login.tproj/klogin.c b/system_cmds/login.tproj/klogin.c
new file mode 100644
index 0000000..b9f0927
--- /dev/null
+++ b/system_cmds/login.tproj/klogin.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef KERBEROS
+#include <sys/param.h>
+#include <sys/syslog.h>
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+
+#include <err.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define INITIAL_TICKET "krbtgt"
+#define VERIFY_SERVICE "rcmd"
+
+extern int notickets;
+extern char *krbtkfile_env;
+
+/*
+ * Attempt to log the user in using Kerberos authentication
+ *
+ * return 0 on success (will be logged in)
+ * 1 if Kerberos failed (try local password in login)
+ */
+int
+klogin(struct passwd *pw, char *instance, char *localhost, char *password)
+{
+ int kerror;
+ AUTH_DAT authdata;
+ KTEXT_ST ticket;
+ struct hostent *hp;
+ unsigned long faddr;
+ char realm[REALM_SZ], savehost[MAXHOSTNAMELEN];
+ char tkt_location[MAXPATHLEN];
+ char *krb_get_phost();
+
+ /*
+ * Root logins don't use Kerberos.
+ * If we have a realm, try getting a ticket-granting ticket
+ * and using it to authenticate. Otherwise, return
+ * failure so that we can try the normal passwd file
+ * for a password. If that's ok, log the user in
+ * without issuing any tickets.
+ */
+ if (strcmp(pw->pw_name, "root") == 0 ||
+ krb_get_lrealm(realm, 0) != KSUCCESS)
+ return (1);
+
+ /*
+ * get TGT for local realm
+ * tickets are stored in a file named TKT_ROOT plus uid
+ * except for user.root tickets.
+ */
+
+ if (strcmp(instance, "root") != 0)
+ (void)sprintf(tkt_location, "%s%d", TKT_ROOT, pw->pw_uid);
+ else {
+ (void)sprintf(tkt_location, "%s_root_%d", TKT_ROOT, pw->pw_uid);
+ krbtkfile_env = tkt_location;
+ }
+ (void)krb_set_tkt_string(tkt_location);
+
+ /*
+ * Set real as well as effective ID to 0 for the moment,
+ * to make the kerberos library do the right thing.
+ */
+ if (setuid(0) < 0) {
+ warnx("setuid");
+ return (1);
+ }
+ kerror = krb_get_pw_in_tkt(pw->pw_name, instance,
+ realm, INITIAL_TICKET, realm, DEFAULT_TKT_LIFE, password);
+ /*
+ * If we got a TGT, get a local "rcmd" ticket and check it so as to
+ * ensure that we are not talking to a bogus Kerberos server.
+ *
+ * There are 2 cases where we still allow a login:
+ * 1: the VERIFY_SERVICE doesn't exist in the KDC
+ * 2: local host has no srvtab, as (hopefully) indicated by a
+ * return value of RD_AP_UNDEC from krb_rd_req().
+ */
+ if (kerror != INTK_OK) {
+ if (kerror != INTK_BADPW && kerror != KDC_PR_UNKNOWN) {
+ syslog(LOG_ERR, "Kerberos intkt error: %s",
+ krb_err_txt[kerror]);
+ dest_tkt();
+ }
+ return (1);
+ }
+
+ if (chown(TKT_FILE, pw->pw_uid, pw->pw_gid) < 0)
+ syslog(LOG_ERR, "chown tkfile (%s): %m", TKT_FILE);
+
+ (void)strncpy(savehost, krb_get_phost(localhost), sizeof(savehost));
+ savehost[sizeof(savehost)-1] = NULL;
+
+ /*
+ * if the "VERIFY_SERVICE" doesn't exist in the KDC for this host,
+ * still allow login with tickets, but log the error condition.
+ */
+
+ kerror = krb_mk_req(&ticket, VERIFY_SERVICE, savehost, realm, 33);
+ if (kerror == KDC_PR_UNKNOWN) {
+ syslog(LOG_NOTICE,
+ "warning: TGT not verified (%s); %s.%s not registered, or srvtab is wrong?",
+ krb_err_txt[kerror], VERIFY_SERVICE, savehost);
+ notickets = 0;
+ return (0);
+ }
+
+ if (kerror != KSUCCESS) {
+ warnx("unable to use TGT: (%s)", krb_err_txt[kerror]);
+ syslog(LOG_NOTICE, "unable to use TGT: (%s)",
+ krb_err_txt[kerror]);
+ dest_tkt();
+ return (1);
+ }
+
+ if (!(hp = gethostbyname(localhost))) {
+ syslog(LOG_ERR, "couldn't get local host address");
+ dest_tkt();
+ return (1);
+ }
+
+ memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr));
+
+ kerror = krb_rd_req(&ticket, VERIFY_SERVICE, savehost, faddr,
+ &authdata, "");
+
+ if (kerror == KSUCCESS) {
+ notickets = 0;
+ return (0);
+ }
+
+ /* undecipherable: probably didn't have a srvtab on the local host */
+ if (kerror = RD_AP_UNDEC) {
+ syslog(LOG_NOTICE, "krb_rd_req: (%s)\n", krb_err_txt[kerror]);
+ dest_tkt();
+ return (1);
+ }
+ /* failed for some other reason */
+ warnx("unable to verify %s ticket: (%s)", VERIFY_SERVICE,
+ krb_err_txt[kerror]);
+ syslog(LOG_NOTICE, "couldn't verify %s ticket: %s", VERIFY_SERVICE,
+ krb_err_txt[kerror]);
+ dest_tkt();
+ return (1);
+}
+#endif
diff --git a/system_cmds/login.tproj/login.1 b/system_cmds/login.tproj/login.1
new file mode 100644
index 0000000..6edef05
--- /dev/null
+++ b/system_cmds/login.tproj/login.1
@@ -0,0 +1,186 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)login.1 8.2 (Berkeley) 5/5/94
+.\" $FreeBSD: src/usr.bin/login/login.1,v 1.33 2007/11/30 11:02:36 philip Exp $
+.\"
+.Dd September 13, 2006
+.Dt LOGIN 1
+.Os
+.Sh NAME
+.Nm login
+.Nd log into the computer
+.Sh SYNOPSIS
+.Nm
+.Op Fl pq
+.Op Fl h Ar hostname
+.Op Ar user
+.Nm
+.Fl f
+.Op Fl lpq
+.Op Fl h Ar hostname
+.Op Ar user Op Ar prog Op Ar args...
+.Sh DESCRIPTION
+The
+.Nm
+utility logs users (and pseudo-users) into the computer system.
+.Pp
+If no user is specified, or if a user is specified and authentication
+of the user fails,
+.Nm
+prompts for a user name.
+Authentication of users is configurable via
+.Xr pam 8 .
+Password authentication is the default.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl f
+When a user name is specified, this option indicates that proper
+authentication has already been done and that no password need be
+requested.
+This option may only be used by the super-user or when an already
+logged in user is logging in as themselves.
+.Pp
+With the
+.Fl f
+option, an alternate program (and any arguments) may be run instead of the
+user's default shell.
+The program and arguments follows the user name.
+.It Fl h
+Specify the host from which the connection was received.
+It is used by various daemons such as
+.Xr telnetd 8 .
+This option may only be used by the super-user.
+.It Fl l
+Tells the program executed by
+.Nm
+that this is not a login session (by convention, a login session is
+signalled to the program with a hyphen as the first character of
+.Em argv[0] ;
+this option disables that), and prevents it from chdir(2)ing to the user's home directory.
+The default is to add the hyphen (this is a login session).
+.It Fl p
+By default,
+.Nm
+discards any previous environment.
+The
+.Fl p
+option disables this behavior.
+.It Fl q
+This forces quiet logins, as if a
+.Pa .hushlogin
+is present.
+.El
+.Pp
+If the file
+.Pa /etc/nologin
+exists,
+.Nm
+dislays its contents to the user and exits.
+This is used by
+.Xr shutdown 8
+to prevent users from logging in when the system is about to go down.
+.Pp
+Immediately after logging a user in,
+.Nm
+displays the system copyright notice, the date and time the user last
+logged in, the message of the day as well as other information.
+If the file
+.Pa .hushlogin
+exists in the user's home directory, all of these messages are suppressed.
+.Fl q
+is specified, all of these messages are suppressed.
+This is to simplify logins for non-human users, such as
+.Xr uucp 1 .
+.Nm
+then records an entry in
+.Xr utmpx 5
+and the like, and executes the user's command interpreter (or the program
+specified on the command line if
+.Fl f
+is specified).
+.Pp
+The
+.Nm
+utility enters information into the environment (see
+.Xr environ 7 )
+specifying the user's home directory (HOME), command interpreter (SHELL),
+search path (PATH), terminal type (TERM) and user name (both LOGNAME and
+USER).
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Pp
+The
+.Nm
+utility will submit an audit record when login succeeds or fails.
+Failure to determine the current auditing state will
+result in an error exit from
+.Nm .
+.Sh FILES
+.Bl -tag -width /var/mail/userXXX -compact
+.It Pa /etc/motd
+message-of-the-day
+.It Pa /etc/nologin
+disallows logins
+.It Pa /var/run/utmpx
+current logins
+.It Pa /var/mail/user
+system mailboxes
+.It Pa \&.hushlogin
+makes login quieter
+.It Pa /etc/pam.d/login
+.Xr pam 8
+configuration file
+.It Pa /etc/security/audit_user
+user flags for auditing
+.It Pa /etc/security/audit_control
+global flags for auditing
+.El
+.Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr chpass 1 ,
+.Xr newgrp 1 ,
+.Xr passwd 1 ,
+.Xr rlogin 1 ,
+.Xr getpass 3 ,
+.Xr utmpx 5 ,
+.Xr environ 7
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
diff --git a/system_cmds/login.tproj/login.c b/system_cmds/login.tproj/login.c
new file mode 100644
index 0000000..d32a06d
--- /dev/null
+++ b/system_cmds/login.tproj/login.c
@@ -0,0 +1,1509 @@
+/*-
+ * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2002 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ * Portions copyright (c) 1999-2007 Apple 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/login/login.c,v 1.106 2007/07/04 00:00:40 scf Exp $");
+
+/*
+ * login [ name ]
+ * login -h hostname (for telnetd, etc.)
+ * login -f name (for pre-authenticated login: datakit, xterm, etc.)
+ */
+
+#ifndef __APPLE__
+#include <sys/copyright.h>
+#endif
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#ifdef __APPLE__
+#include <util.h>
+#else
+#include <libutil.h>
+#endif
+#ifdef LOGIN_CAP
+#include <login_cap.h>
+#endif
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <ttyent.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <utmpx.h>
+#ifdef USE_PAM
+#else /* !USE_PAM */
+#ifndef _UTX_USERSIZE
+#define _UTX_USERSIZE MAXLOGNAME
+#endif
+#endif /* USE_PAM */
+#endif /* __APPLE__ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef USE_BSM_AUDIT
+#include <bsm/libbsm.h>
+#include <bsm/audit.h>
+#include <bsm/audit_session.h>
+#include <bsm/audit_uevents.h>
+#endif
+
+#ifdef __APPLE__
+#include <mach/mach_types.h>
+#include <mach/task.h>
+#include <mach/mach_init.h>
+#include <servers/bootstrap.h>
+
+#include <sys/file.h>
+#include <tzfile.h>
+#endif /* __APPLE__ */
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+#endif /* USE_PAM */
+
+#include "login.h"
+#include "pathnames.h"
+
+#ifdef USE_PAM
+static int auth_pam(int skip_auth);
+#endif /* USE_PAM */
+static void bail(int, int);
+#ifdef USE_PAM
+static int export(const char *);
+static void export_pam_environment(void);
+#endif /* USE_PAM */
+static int motd(const char *);
+static void badlogin(char *);
+static char *getloginname(void);
+#ifdef USE_PAM
+static void pam_syslog(const char *);
+static void pam_cleanup(void);
+#endif /* USE_PAM */
+static void refused(const char *, const char *, int);
+static const char *stypeof(char *);
+static void sigint(int);
+static void timedout(int);
+static void usage(void);
+
+#ifdef __APPLE__
+static void dolastlog(int);
+static void handle_sighup(int);
+
+#ifndef USE_PAM
+static void checknologin(void);
+static int rootterm(const char *);
+#endif /* !USE_PAM */
+#endif /* __APPLE__ */
+
+#define TTYGRPNAME "tty" /* group to own ttys */
+#define DEFAULT_BACKOFF 3
+#define DEFAULT_RETRIES 10
+#define DEFAULT_PROMPT "login: "
+#define DEFAULT_PASSWD_PROMPT "Password:"
+#define TERM_UNKNOWN "su"
+#define DEFAULT_WARN (2L * 7L * 86400L) /* Two weeks */
+#define NO_SLEEP_EXIT 0
+#define SLEEP_EXIT 5
+
+/*
+ * This bounds the time given to login. Not a define so it can
+ * be patched on machines where it's too small.
+ */
+static u_int timeout = 300;
+
+/* Buffer for signal handling of timeout */
+static jmp_buf timeout_buf;
+
+struct passwd *pwd;
+static int failures;
+
+static char *envinit[1]; /* empty environment list */
+
+/*
+ * Command line flags and arguments
+ */
+static int fflag; /* -f: do not perform authentication */
+#ifdef __APPLE__
+static int lflag; /* -l: login session to the commmand that follows username */
+#endif
+static int hflag; /* -h: login from remote host */
+static char *hostname; /* hostname from command line */
+static int pflag; /* -p: preserve environment */
+
+/*
+ * User name
+ */
+static char *username; /* user name */
+static char *olduser; /* previous user name */
+
+/*
+ * Prompts
+ */
+static char default_prompt[] = DEFAULT_PROMPT;
+static const char *prompt;
+static char default_passwd_prompt[] = DEFAULT_PASSWD_PROMPT;
+static const char *passwd_prompt;
+
+static char *tty;
+
+/*
+ * PAM data
+ */
+#ifdef USE_PAM
+static pam_handle_t *pamh = NULL;
+static struct pam_conv pamc = { openpam_ttyconv, NULL };
+static int pam_err;
+static int pam_silent = PAM_SILENT;
+static int pam_cred_established;
+static int pam_session_established;
+#endif /* USE_PAM */
+
+#ifdef __APPLE__
+pid_t pid;
+
+#ifdef USE_PAM
+static struct lastlogx lastlog;
+#endif /* USE_PAM */
+
+#ifdef USE_BSM_AUDIT
+extern au_tid_addr_t tid;
+#endif /* USE_BSM_AUDIT */
+#endif /* __APPLE__ */
+
+int
+main(int argc, char *argv[])
+{
+ struct group *gr;
+ struct stat st;
+ int retries, backoff;
+ int ask, ch, cnt, quietlog = 0, rootlogin, rval;
+ uid_t uid, euid;
+ gid_t egid;
+ char *term;
+ char *p, *ttyn;
+ char tname[sizeof(_PATH_TTY) + 10];
+ char *arg0;
+ const char *tp;
+#ifdef __APPLE__
+ int prio;
+#ifdef USE_PAM
+ const char *name = "login"; /* PAM config */
+#else
+ struct utmpx utmp;
+#endif /* USE_PAM */
+ const char *shell = NULL;
+#endif /* !__APPLE__ */
+#ifdef LOGIN_CAP
+ login_cap_t *lc = NULL;
+ login_cap_t *lc_user = NULL;
+#endif /* LOGIN_CAP */
+#ifndef __APPLE__
+ pid_t pid;
+#endif
+#ifdef USE_BSM_AUDIT
+ char auditsuccess = 1;
+#endif
+
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGHUP, SIG_IGN);
+ if (setjmp(timeout_buf)) {
+ if (failures)
+ badlogin(username);
+ (void)fprintf(stderr, "Login timed out after %d seconds\n",
+ timeout);
+ bail(NO_SLEEP_EXIT, 0);
+ }
+ (void)signal(SIGALRM, timedout);
+ (void)alarm(timeout);
+#ifdef __APPLE__
+ prio = getpriority(PRIO_PROCESS, 0);
+#endif
+ (void)setpriority(PRIO_PROCESS, 0, 0);
+
+ openlog("login", LOG_ODELAY, LOG_AUTH);
+
+ uid = getuid();
+ euid = geteuid();
+ egid = getegid();
+
+#ifdef __APPLE__
+ while ((ch = getopt(argc, argv, "1fh:lpq")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "fh:p")) != -1)
+#endif
+ switch (ch) {
+ case 'f':
+ fflag = 1;
+ break;
+ case 'h':
+ if (uid != 0)
+ errx(1, "-h option: %s", strerror(EPERM));
+ if (strlen(optarg) >= MAXHOSTNAMELEN)
+ errx(1, "-h option: %s: exceeds maximum "
+ "hostname size", optarg);
+ hflag = 1;
+ hostname = optarg;
+ break;
+ case 'p':
+ pflag = 1;
+ break;
+#ifdef __APPLE__
+ case '1':
+ break;
+ case 'l':
+ lflag = 1;
+ break;
+ case 'q':
+ quietlog = 1;
+ break;
+#endif
+ case '?':
+ default:
+ if (uid == 0)
+ syslog(LOG_ERR, "invalid flag %c", ch);
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ username = strdup(*argv);
+ if (username == NULL)
+ err(1, "strdup()");
+ ask = 0;
+#ifdef __APPLE__
+ argv++;
+#endif /* __APPLE__ */
+ } else {
+ ask = 1;
+ }
+
+#ifndef __APPLE__
+ setproctitle("-%s", getprogname());
+#endif /* !__APPLE__ */
+
+ for (cnt = getdtablesize(); cnt > 2; cnt--)
+ (void)close(cnt);
+
+ /*
+ * Get current TTY
+ */
+ ttyn = ttyname(STDIN_FILENO);
+ if (ttyn == NULL || *ttyn == '\0') {
+ (void)snprintf(tname, sizeof(tname), "%s??", _PATH_TTY);
+ ttyn = tname;
+ }
+ if ((tty = strrchr(ttyn, '/')) != NULL)
+ ++tty;
+ else
+ tty = ttyn;
+
+#ifdef LOGIN_CAP
+ /*
+ * Get "login-retries" & "login-backoff" from default class
+ */
+ lc = login_getclass(NULL);
+ prompt = login_getcapstr(lc, "login_prompt",
+ default_prompt, default_prompt);
+ passwd_prompt = login_getcapstr(lc, "passwd_prompt",
+ default_passwd_prompt, default_passwd_prompt);
+ retries = login_getcapnum(lc, "login-retries",
+ DEFAULT_RETRIES, DEFAULT_RETRIES);
+ backoff = login_getcapnum(lc, "login-backoff",
+ DEFAULT_BACKOFF, DEFAULT_BACKOFF);
+ login_close(lc);
+ lc = NULL;
+#else /* !LOGIN_CAP */
+ prompt = default_prompt;
+ passwd_prompt = default_passwd_prompt;
+ retries = DEFAULT_RETRIES;
+ backoff = DEFAULT_BACKOFF;
+#endif /* !LOGIN_CAP */
+
+#ifdef __APPLE__
+#ifdef USE_BSM_AUDIT
+ /* Set the terminal id */
+ au_tid_t old_tid;
+ audit_set_terminal_id(&old_tid);
+ tid.at_type = AU_IPv4;
+ tid.at_addr[0] = old_tid.machine;
+ if (fstat(STDIN_FILENO, &st) < 0) {
+ fprintf(stderr, "login: Unable to stat terminal\n");
+ au_login_fail("Unable to stat terminal", 1);
+ exit(-1);
+ }
+ if (S_ISCHR(st.st_mode)) {
+ tid.at_port = st.st_rdev;
+ } else {
+ tid.at_port = 0;
+ }
+#endif /* USE_BSM_AUDIT */
+#endif /* __APPLE__ */
+
+ /*
+ * Try to authenticate the user until we succeed or time out.
+ */
+ for (cnt = 0;; ask = 1) {
+ if (ask) {
+ fflag = 0;
+ if (olduser != NULL)
+ free(olduser);
+ olduser = username;
+ username = getloginname();
+ }
+ rootlogin = 0;
+
+#ifdef __APPLE__
+ if (strlen(username) > _UTX_USERSIZE)
+ username[_UTX_USERSIZE] = '\0';
+#endif /* __APPLE__ */
+
+ /*
+ * Note if trying multiple user names; log failures for
+ * previous user name, but don't bother logging one failure
+ * for nonexistent name (mistyped username).
+ */
+ if (failures && strcmp(olduser, username) != 0) {
+ if (failures > (pwd ? 0 : 1))
+ badlogin(olduser);
+ }
+
+#ifdef __APPLE__
+#ifdef USE_PAM
+ /* get lastlog info before PAM make a new entry */
+ if (!quietlog)
+ getlastlogxbyname(username, &lastlog);
+#endif /* USE_PAM */
+#endif /* __APPLE__ */
+
+ pwd = getpwnam(username);
+
+#ifdef USE_PAM
+ /*
+ * Load the PAM policy and set some variables
+ */
+#ifdef __APPLE__
+ if (fflag && (pwd != NULL) && (pwd->pw_uid == uid)) {
+ name = "login.term";
+ }
+#endif
+ pam_err = pam_start(name, username, &pamc, &pamh);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_start()");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_err = pam_set_item(pamh, PAM_TTY, tty);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_set_item(PAM_TTY)");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_err = pam_set_item(pamh, PAM_RHOST, hostname);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_set_item(PAM_RHOST)");
+#ifdef USE_BSM_AUDIT
+ au_login_fail("PAM Error", 1);
+#endif
+ bail(NO_SLEEP_EXIT, 1);
+ }
+#endif /* USE_PAM */
+
+ if (pwd != NULL && pwd->pw_uid == 0)
+ rootlogin = 1;
+
+ /*
+ * If the -f option was specified and the caller is
+ * root or the caller isn't changing their uid, don't
+ * authenticate.
+ */
+ if (pwd != NULL && fflag &&
+ (uid == (uid_t)0 || uid == (uid_t)pwd->pw_uid)) {
+#ifdef USE_PAM
+ rval = auth_pam(fflag);
+#else
+ rval = 0;
+#endif /* USE_PAM */
+#ifdef USE_BSM_AUDIT
+ auditsuccess = 0; /* opened a terminal window only */
+#endif
+
+#ifdef __APPLE__
+#ifndef USE_PAM
+ /* If the account doesn't have a password, authenticate. */
+ } else if (pwd != NULL && pwd->pw_passwd[0] == '\0') {
+ rval = 0;
+#endif /* !USE_PAM */
+#endif /* __APPLE__ */
+ } else if( pwd ) {
+ fflag = 0;
+ (void)setpriority(PRIO_PROCESS, 0, -4);
+#ifdef USE_PAM
+ rval = auth_pam(fflag);
+#else
+ {
+ char* salt = pwd->pw_passwd;
+ char* p = getpass(passwd_prompt);
+ rval = strcmp(crypt(p, salt), salt);
+ memset(p, 0, strlen(p));
+ }
+#endif
+ (void)setpriority(PRIO_PROCESS, 0, 0);
+ } else {
+ rval = -1;
+ }
+
+#ifdef __APPLE__
+#ifndef USE_PAM
+ /*
+ * If trying to log in as root but with insecure terminal,
+ * refuse the login attempt.
+ */
+ if (pwd && rootlogin && !rootterm(tty)) {
+ refused("root login refused on this terminal", "ROOTTERM", 0);
+#ifdef USE_BSM_AUDIT
+ au_login_fail("Login refused on terminal", 0);
+#endif
+ continue;
+ }
+#endif /* !USE_PAM */
+#endif /* __APPLE__ */
+
+ if (pwd && rval == 0)
+ break;
+
+#ifdef USE_PAM
+ pam_cleanup();
+#endif /* USE_PAM */
+
+ /*
+ * We are not exiting here, but this corresponds to a failed
+ * login event, so set exitstatus to 1.
+ */
+#ifdef USE_BSM_AUDIT
+ au_login_fail("Login incorrect", 1);
+#endif
+
+ (void)printf("Login incorrect\n");
+ failures++;
+
+ pwd = NULL;
+
+ /*
+ * Allow up to 'retry' (10) attempts, but start
+ * backing off after 'backoff' (3) attempts.
+ */
+ if (++cnt > backoff) {
+ if (cnt >= retries) {
+ badlogin(username);
+ bail(SLEEP_EXIT, 1);
+ }
+ sleep((u_int)((cnt - backoff) * 5));
+ }
+ }
+
+ /* committed to login -- turn off timeout */
+ (void)alarm((u_int)0);
+ (void)signal(SIGHUP, SIG_DFL);
+
+ endpwent();
+
+#ifdef __APPLE__
+ if (!pwd) {
+ fprintf(stderr, "login: Unable to find user: %s\n", username);
+ exit(1);
+ }
+
+#ifndef USE_PAM
+ /* if user not super-user, check for disabled logins */
+ if (!rootlogin)
+ checknologin();
+#endif /* !USE_PAM */
+#endif /* APPLE */
+
+#ifdef USE_BSM_AUDIT
+ /* Audit successful login. */
+ if (auditsuccess)
+ au_login_success(fflag);
+#endif
+
+#ifdef LOGIN_CAP
+ /*
+ * Establish the login class.
+ */
+ lc = login_getpwclass(pwd);
+ lc_user = login_getuserclass(pwd);
+
+ if (!(quietlog = login_getcapbool(lc_user, "hushlogin", 0)))
+ quietlog = login_getcapbool(lc, "hushlogin", 0);
+#endif /* LOGIN_CAP */
+
+#ifndef __APPLE__
+ /*
+ * Switching needed for NFS with root access disabled.
+ *
+ * XXX: This change fails to modify the additional groups for the
+ * process, and as such, may restrict rights normally granted
+ * through those groups.
+ */
+ (void)setegid(pwd->pw_gid);
+ (void)seteuid(rootlogin ? 0 : pwd->pw_uid);
+
+ if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
+#ifdef LOGIN_CAP
+ if (login_getcapbool(lc, "requirehome", 0))
+ refused("Home directory not available", "HOMEDIR", 1);
+#endif /* LOGIN_CAP */
+ if (chdir("/") < 0)
+ refused("Cannot find root directory", "ROOTDIR", 1);
+ if (!quietlog || *pwd->pw_dir)
+ printf("No home directory.\nLogging in with home = \"/\".\n");
+ pwd->pw_dir = strdup("/");
+ if (pwd->pw_dir == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+ }
+
+ (void)seteuid(euid);
+ (void)setegid(egid);
+#endif /* !__APPLE__ */
+ if (!quietlog) {
+ quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0;
+#ifdef USE_PAM
+ if (!quietlog)
+ pam_silent = 0;
+#endif /* USE_PAM */
+ }
+
+#ifdef __APPLE__
+ /* Nothing else left to fail -- really log in. */
+#ifndef USE_PAM
+ memset((void *)&utmp, 0, sizeof(utmp));
+ (void)gettimeofday(&utmp.ut_tv, NULL);
+ (void)strncpy(utmp.ut_user, username, sizeof(utmp.ut_user));
+ if (hostname)
+ (void)strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
+ (void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
+ utmp.ut_type = USER_PROCESS | UTMPX_AUTOFILL_MASK;
+ utmp.ut_pid = getpid();
+ pututxline(&utmp);
+#endif /* USE_PAM */
+
+ shell = "";
+#endif /* !__APPLE__ */
+#ifdef LOGIN_CAP
+ shell = login_getcapstr(lc, "shell", pwd->pw_shell, pwd->pw_shell);
+#endif /* !LOGIN_CAP */
+ if (*pwd->pw_shell == '\0')
+ pwd->pw_shell = strdup(_PATH_BSHELL);
+ if (pwd->pw_shell == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+
+#if defined(__APPLE__) && (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ /* on embedded, allow a shell to live in /private/var/personalized_debug/bin/sh */
+#define _PATH_DEBUGSHELL "/private/var/personalized_debug/bin/sh"
+ if (stat(pwd->pw_shell, &st) != 0) {
+ if (stat(_PATH_DEBUGSHELL, &st) == 0) {
+ pwd->pw_shell = strdup(_PATH_DEBUGSHELL);
+ }
+ }
+#endif
+
+ if (*shell == '\0') /* Not overridden */
+ shell = pwd->pw_shell;
+ if ((shell = strdup(shell)) == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ bail(SLEEP_EXIT, 1);
+ }
+
+#ifdef __APPLE__
+ dolastlog(quietlog);
+#endif
+
+#ifndef __APPLE__
+ /*
+ * Set device protections, depending on what terminal the
+ * user is logged in. This feature is used on Suns to give
+ * console users better privacy.
+ */
+ login_fbtab(tty, pwd->pw_uid, pwd->pw_gid);
+#endif /* !__APPLE__ */
+
+ /*
+ * Clear flags of the tty. None should be set, and when the
+ * user sets them otherwise, this can cause the chown to fail.
+ * Since it isn't clear that flags are useful on character
+ * devices, we just clear them.
+ *
+ * We don't log in the case of EOPNOTSUPP because dev might be
+ * on NFS, which doesn't support chflags.
+ *
+ * We don't log in the EROFS because that means that /dev is on
+ * a read only file system and we assume that the permissions there
+ * are sane.
+ */
+ if (ttyn != tname && chflags(ttyn, 0))
+#ifdef __APPLE__
+ if (errno != EOPNOTSUPP && errno != ENOTSUP && errno != EROFS)
+#else
+ if (errno != EOPNOTSUPP && errno != EROFS)
+#endif
+ syslog(LOG_ERR, "chflags(%s): %m", ttyn);
+ if (ttyn != tname && chown(ttyn, pwd->pw_uid,
+ (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid))
+ if (errno != EROFS)
+ syslog(LOG_ERR, "chown(%s): %m", ttyn);
+
+#ifdef __APPLE__
+ (void)chmod(ttyn, 0620);
+#endif /* __APPLE__ */
+
+#ifndef __APPLE__
+ /*
+ * Exclude cons/vt/ptys only, assume dialup otherwise
+ * TODO: Make dialup tty determination a library call
+ * for consistency (finger etc.)
+ */
+ if (hflag && isdialuptty(tty))
+ syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
+#endif /* !__APPLE__ */
+
+#ifdef LOGALL
+ /*
+ * Syslog each successful login, so we don't have to watch
+ * hundreds of wtmp or lastlogin files.
+ */
+ if (hflag)
+ syslog(LOG_INFO, "login from %s on %s as %s",
+ hostname, tty, pwd->pw_name);
+ else
+ syslog(LOG_INFO, "login on %s as %s",
+ tty, pwd->pw_name);
+#endif
+
+ /*
+ * If fflag is on, assume caller/authenticator has logged root
+ * login.
+ */
+ if (rootlogin && fflag == 0) {
+ if (hflag)
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s FROM %s",
+ username, tty, hostname);
+ else
+ syslog(LOG_NOTICE, "ROOT LOGIN (%s) ON %s",
+ username, tty);
+ }
+
+ /*
+ * Destroy environment unless user has requested its
+ * preservation - but preserve TERM in all cases
+ */
+ term = getenv("TERM");
+ if (!pflag)
+ environ = envinit;
+ if (term != NULL)
+ setenv("TERM", term, 0);
+
+#ifndef __APPLE__
+ /*
+ * PAM modules might add supplementary groups during pam_setcred().
+ */
+ if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) != 0) {
+ syslog(LOG_ERR, "setusercontext() failed - exiting");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+#endif /* !__APPLE__ */
+#ifdef USE_PAM
+ if (!fflag) {
+ pam_err = pam_setcred(pamh, pam_silent|PAM_ESTABLISH_CRED);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_setcred()");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_cred_established = 1;
+ }
+
+ pam_err = pam_open_session(pamh, pam_silent);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_open_session()");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ pam_session_established = 1;
+#endif /* USE_PAM */
+
+#ifdef __APPLE__
+ /* <rdar://problem/5377791>
+ Install a signal handler that will forward SIGHUP to the
+ child and process group. The parent should not exit on
+ SIGHUP so that the tty ownership can be reset. */
+ (void)signal(SIGHUP, handle_sighup);
+#endif /* __APPLE__ */
+
+ /*
+ * We must fork() before setuid() because we need to call
+ * pam_close_session() as root.
+ */
+ pid = fork();
+ if (pid < 0) {
+ err(1, "fork");
+ } else if (pid != 0) {
+ /*
+ * Parent: wait for child to finish, then clean up
+ * session.
+ */
+ int status;
+#ifndef __APPLE__
+ setproctitle("-%s [pam]", getprogname());
+#endif /* !__APPLE__ */
+#ifdef __APPLE__
+ /* Our SIGHUP handler may interrupt the wait */
+ int res;
+ do {
+ res = waitpid(pid, &status, 0);
+ } while (res == -1 && errno == EINTR);
+#else
+ waitpid(pid, &status, 0);
+#endif
+#ifdef __APPLE__
+ chown(ttyn, 0, 0);
+ chmod(ttyn, 0666);
+#endif /* __APPLE__ */
+ bail(NO_SLEEP_EXIT, 0);
+ }
+
+ /*
+ * NOTICE: We are now in the child process!
+ */
+
+#ifdef __APPLE__
+ /* Restore the default SIGHUP handler for the child. */
+ (void)signal(SIGHUP, SIG_DFL);
+#endif /* __APPLE__ */
+
+#ifdef USE_PAM
+ /*
+ * Add any environment variables the PAM modules may have set.
+ */
+ export_pam_environment();
+
+ /*
+ * We're done with PAM now; our parent will deal with the rest.
+ */
+ pam_end(pamh, 0);
+ pamh = NULL;
+#endif /* USE_PAM */
+
+ /*
+ * We don't need to be root anymore, so set the login name and
+ * the UID.
+ */
+ if (setlogin(username) != 0) {
+ syslog(LOG_ERR, "setlogin(%s): %m - exiting", username);
+ bail(NO_SLEEP_EXIT, 1);
+ }
+#ifdef __APPLE__
+ /* <rdar://problem/6041650> restore process priority if not changing uids */
+ if (uid == (uid_t)pwd->pw_uid) {
+ (void)setpriority(PRIO_PROCESS, 0, prio);
+ }
+
+ (void)setgid(pwd->pw_gid);
+ if (initgroups(username, pwd->pw_gid) == -1)
+ syslog(LOG_ERR, "login: initgroups() failed");
+ (void) setuid(rootlogin ? 0 : pwd->pw_uid);
+#else /* !__APPLE__ */
+ if (setusercontext(lc, pwd, pwd->pw_uid,
+ LOGIN_SETALL & ~(LOGIN_SETLOGIN|LOGIN_SETGROUP)) != 0) {
+ syslog(LOG_ERR, "setusercontext() failed - exiting");
+ exit(1);
+ }
+#endif /* !__APPLE__ */
+
+#ifdef __APPLE__
+ /* We test for the home directory after pam_open_session(3)
+ * as the home directory may have been mounted by a session
+ * module, and after changing uid as the home directory may
+ * be NFS with root access disabled. */
+ if (!lflag) {
+ /* First do a stat in case the homedir is automounted */
+ stat(pwd->pw_dir,&st);
+ if (!*pwd->pw_dir || chdir(pwd->pw_dir) < 0) {
+ printf("No home directory: %s\n", pwd->pw_dir);
+ if (chdir("/") < 0) {
+ refused("Cannot find root directory", "ROOTDIR", 0);
+ exit(1);
+ }
+ pwd->pw_dir = strdup("/");
+ if (pwd->pw_dir == NULL) {
+ syslog(LOG_NOTICE, "strdup(): %m");
+ exit(1);
+ }
+ }
+ }
+#endif /* __APPLE__ */
+ if (pwd->pw_shell) {
+ (void)setenv("SHELL", pwd->pw_shell, 1);
+ } else {
+ syslog(LOG_ERR, "pwd->pw_shell not set - exiting");
+ bail(NO_SLEEP_EXIT, 1);
+ }
+ if (pwd->pw_dir) {
+ (void)setenv("HOME", pwd->pw_dir, 1);
+ } else {
+ (void)setenv("HOME", "/", 1);
+ }
+ /* Overwrite "term" from login.conf(5) for any known TERM */
+ if (term == NULL && (tp = stypeof(tty)) != NULL)
+ (void)setenv("TERM", tp, 1);
+ else
+ (void)setenv("TERM", TERM_UNKNOWN, 0);
+ (void)setenv("LOGNAME", username, 1);
+ (void)setenv("USER", username, 1);
+ (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0);
+
+#ifdef __APPLE__
+ /* Re-enable crash reporter */
+ do {
+ kern_return_t kr;
+ mach_port_t bp, ep, mts;
+ thread_state_flavor_t flavor = 0;
+
+#if defined(__ppc__)
+ flavor = PPC_THREAD_STATE64;
+#elif defined(__i386__) || defined(__x86_64__)
+ flavor = x86_THREAD_STATE;
+#elif defined(__arm__) || defined(__arm64__)
+ flavor = ARM_THREAD_STATE;
+#else
+#error unsupported architecture
+#endif
+
+ mts = mach_task_self();
+
+ kr = task_get_bootstrap_port(mts, &bp);
+ if (kr != KERN_SUCCESS) {
+ syslog(LOG_ERR, "task_get_bootstrap_port() failure: %s (%d)",
+ bootstrap_strerror(kr), kr);
+ break;
+ }
+
+ const char* bs = "com.apple.ReportCrash";
+ kr = bootstrap_look_up(bp, (char*)bs, &ep);
+ if (kr != KERN_SUCCESS) {
+ syslog(LOG_ERR, "bootstrap_look_up(%s) failure: %s (%d)",
+ bs, bootstrap_strerror(kr), kr);
+ break;
+ }
+
+ kr = task_set_exception_ports(mts, EXC_MASK_RESOURCE | EXC_MASK_GUARD | EXC_MASK_CORPSE_NOTIFY, ep, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, flavor);
+ if (kr != KERN_SUCCESS) {
+ syslog(LOG_ERR, "task_set_exception_ports() failure: %d", kr);
+ break;
+ }
+ } while (0);
+#endif /* __APPLE__ */
+
+ if (!quietlog) {
+#ifdef LOGIN_CAP
+ const char *cw;
+
+ cw = login_getcapstr(lc, "copyright", NULL, NULL);
+ if (cw == NULL || motd(cw) == -1)
+ (void)printf("%s", copyright);
+
+ (void)printf("\n");
+
+ cw = login_getcapstr(lc, "welcome", NULL, NULL);
+ if (cw != NULL && access(cw, F_OK) == 0)
+ motd(cw);
+ else
+ motd(_PATH_MOTDFILE);
+
+ if (login_getcapbool(lc_user, "nocheckmail", 0) == 0 &&
+ login_getcapbool(lc, "nocheckmail", 0) == 0) {
+#else /* !LOGIN_CAP */
+ motd(_PATH_MOTDFILE);
+ {
+#endif /* !LOGIN_CAP */
+ char *cx;
+
+ /* $MAIL may have been set by class. */
+ cx = getenv("MAIL");
+ if (cx == NULL) {
+ asprintf(&cx, "%s/%s",
+ _PATH_MAILDIR, pwd->pw_name);
+ }
+ if (cx && stat(cx, &st) == 0 && st.st_size != 0)
+ (void)printf("You have %smail.\n",
+ (st.st_mtime > st.st_atime) ? "new " : "");
+ if (getenv("MAIL") == NULL)
+ free(cx);
+ }
+ }
+
+#ifdef LOGIN_CAP
+ login_close(lc_user);
+ login_close(lc);
+#endif /* LOGIN_CAP */
+
+ (void)signal(SIGALRM, SIG_DFL);
+ (void)signal(SIGQUIT, SIG_DFL);
+ (void)signal(SIGINT, SIG_DFL);
+ (void)signal(SIGTSTP, SIG_IGN);
+
+#ifdef __APPLE__
+ if (fflag && *argv) pwd->pw_shell = *argv;
+#endif /* __APPLE__ */
+
+ /*
+ * Login shells have a leading '-' in front of argv[0]
+ */
+ p = strrchr(pwd->pw_shell, '/');
+#ifdef __APPLE__
+ if (asprintf(&arg0, "%s%s", lflag ? "" : "-", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
+#else /* __APPLE__ */
+ if (asprintf(&arg0, "-%s", p ? p + 1 : pwd->pw_shell) >= MAXPATHLEN) {
+#endif /* __APPLE__ */
+ syslog(LOG_ERR, "user: %s: shell exceeds maximum pathname size",
+ username);
+ errx(1, "shell exceeds maximum pathname size");
+ } else if (arg0 == NULL) {
+ err(1, "asprintf()");
+ }
+
+#ifdef __APPLE__
+ if (fflag && *argv) {
+ *argv = arg0;
+ execvp(pwd->pw_shell, argv);
+ err(1, "%s", arg0);
+ }
+#endif /* __APPLE__ */
+ execlp(shell, arg0, (char *)0);
+ err(1, "%s", shell);
+
+ /*
+ * That's it, folks!
+ */
+}
+
+#ifdef USE_PAM
+/*
+ * Attempt to authenticate the user using PAM. Returns 0 if the user is
+ * authenticated, or 1 if not authenticated. If some sort of PAM system
+ * error occurs (e.g., the "/etc/pam.conf" file is missing) then this
+ * function returns -1. This can be used as an indication that we should
+ * fall back to a different authentication mechanism.
+ */
+static int
+auth_pam(int skip_auth)
+{
+ const char *tmpl_user;
+ const void *item;
+ int rval;
+
+ rval = 0;
+
+ if (skip_auth == 0)
+ {
+ pam_err = pam_authenticate(pamh, pam_silent);
+ switch (pam_err) {
+
+ case PAM_SUCCESS:
+ /*
+ * With PAM we support the concept of a "template"
+ * user. The user enters a login name which is
+ * authenticated by PAM, usually via a remote service
+ * such as RADIUS or TACACS+. If authentication
+ * succeeds, a different but related "template" name
+ * is used for setting the credentials, shell, and
+ * home directory. The name the user enters need only
+ * exist on the remote authentication server, but the
+ * template name must be present in the local password
+ * database.
+ *
+ * This is supported by two various mechanisms in the
+ * individual modules. However, from the application's
+ * point of view, the template user is always passed
+ * back as a changed value of the PAM_USER item.
+ */
+ pam_err = pam_get_item(pamh, PAM_USER, &item);
+ if (pam_err == PAM_SUCCESS) {
+ tmpl_user = (const char *)item;
+ if (strcmp(username, tmpl_user) != 0)
+ pwd = getpwnam(tmpl_user);
+ } else {
+ pam_syslog("pam_get_item(PAM_USER)");
+ }
+ rval = 0;
+ break;
+
+ case PAM_AUTH_ERR:
+ case PAM_USER_UNKNOWN:
+ case PAM_MAXTRIES:
+ rval = 1;
+ break;
+
+ default:
+ pam_syslog("pam_authenticate()");
+ rval = -1;
+ break;
+ }
+ }
+
+ if (rval == 0) {
+ pam_err = pam_acct_mgmt(pamh, pam_silent);
+ switch (pam_err) {
+ case PAM_SUCCESS:
+ break;
+ case PAM_NEW_AUTHTOK_REQD:
+ if (skip_auth == 0)
+ {
+ pam_err = pam_chauthtok(pamh,
+ pam_silent|PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (pam_err != PAM_SUCCESS) {
+ pam_syslog("pam_chauthtok()");
+ rval = 1;
+ }
+ }
+ else
+ {
+ pam_syslog("pam_acct_mgmt()");
+ }
+ break;
+ default:
+ pam_syslog("pam_acct_mgmt()");
+ rval = 1;
+ break;
+ }
+ }
+
+ if (rval != 0) {
+ pam_end(pamh, pam_err);
+ pamh = NULL;
+ }
+ return (rval);
+}
+
+/*
+ * Export any environment variables PAM modules may have set
+ */
+static void
+export_pam_environment(void)
+{
+ char **pam_env;
+ char **pp;
+
+ pam_env = pam_getenvlist(pamh);
+ if (pam_env != NULL) {
+ for (pp = pam_env; *pp != NULL; pp++) {
+ (void)export(*pp);
+ free(*pp);
+ }
+ }
+}
+
+/*
+ * Perform sanity checks on an environment variable:
+ * - Make sure there is an '=' in the string.
+ * - Make sure the string doesn't run on too long.
+ * - Do not export certain variables. This list was taken from the
+ * Solaris pam_putenv(3) man page.
+ * Then export it.
+ */
+static int
+export(const char *s)
+{
+ static const char *noexport[] = {
+ "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
+ "IFS", "PATH", NULL
+ };
+ char *p;
+ const char **pp;
+ size_t n;
+
+ if (strlen(s) > 1024 || (p = strchr(s, '=')) == NULL)
+ return (0);
+ if (strncmp(s, "LD_", 3) == 0)
+ return (0);
+ for (pp = noexport; *pp != NULL; pp++) {
+ n = strlen(*pp);
+ if (s[n] == '=' && strncmp(s, *pp, n) == 0)
+ return (0);
+ }
+ *p = '\0';
+ (void)setenv(s, p + 1, 1);
+ *p = '=';
+ return (1);
+}
+#endif /* USE_PAM */
+
+static void
+usage(void)
+{
+#ifdef __APPLE__
+ (void)fprintf(stderr, "usage: login [-pq] [-h hostname] [username]\n");
+ (void)fprintf(stderr, " login -f [-lpq] [-h hostname] [username [prog [arg ...]]]\n");
+#else
+ (void)fprintf(stderr, "usage: login [-fp] [-h hostname] [username]\n");
+#endif
+ exit(1);
+}
+
+/*
+ * Prompt user and read login name from stdin.
+ */
+static char *
+getloginname(void)
+{
+ char *nbuf, *p;
+ int ch;
+
+ nbuf = malloc(MAXLOGNAME);
+ if (nbuf == NULL)
+ err(1, "malloc()");
+ do {
+ (void)printf("%s", prompt);
+ /* rdar://43101375 login process on 2018 hardware is blocked forever waiting on new line char
+ * The carriage return char is added to the termination condition of the
+ * for loop because for some reason, '\r' is returned by getchar() on M9 hardware.
+ */
+ for (p = nbuf; (((ch = getchar()) != '\n') && (ch != '\r')); ) {
+ if (ch == EOF) {
+ badlogin(username);
+ bail(NO_SLEEP_EXIT, 0);
+ }
+ if (p < nbuf + MAXLOGNAME - 1)
+ *p++ = ch;
+ }
+ } while (p == nbuf);
+
+ *p = '\0';
+ if (nbuf[0] == '-') {
+#ifdef USE_PAM
+ pam_silent = 0;
+#endif /* USE_PAM */
+ memmove(nbuf, nbuf + 1, strlen(nbuf));
+ } else {
+#ifdef USE_PAM
+ pam_silent = PAM_SILENT;
+#endif /* USE_PAM */
+ }
+ return nbuf;
+}
+
+#ifdef __APPLE__
+#ifndef USE_PAM
+static int
+rootterm(const char* ttyn)
+{
+ struct ttyent *t;
+ return ((t = getttynam(ttyn)) && t->ty_status & TTY_SECURE);
+}
+#endif /* !USE_PAM */
+#endif /* __APPLE__ */
+
+/*
+ * SIGINT handler for motd().
+ */
+static volatile int motdinterrupt;
+static void
+sigint(int signo __unused)
+{
+ motdinterrupt = 1;
+}
+
+/*
+ * Display the contents of a file (such as /etc/motd).
+ */
+static int
+motd(const char *motdfile)
+{
+ sig_t oldint;
+ FILE *f;
+ int ch;
+
+ if ((f = fopen(motdfile, "r")) == NULL)
+ return (-1);
+ motdinterrupt = 0;
+ oldint = signal(SIGINT, sigint);
+ while ((ch = fgetc(f)) != EOF && !motdinterrupt)
+ putchar(ch);
+ signal(SIGINT, oldint);
+ if (ch != EOF || ferror(f)) {
+ fclose(f);
+ return (-1);
+ }
+ fclose(f);
+ return (0);
+}
+
+/*
+ * SIGHUP handler
+ * Forwards the SIGHUP to the child process and current process group.
+ */
+static void
+handle_sighup(int signo)
+{
+ if (pid > 0) {
+ /* close the controlling terminal */
+ close(STDIN_FILENO);
+ close(STDOUT_FILENO);
+ close(STDERR_FILENO);
+ /* Ignore SIGHUP to avoid tail-recursion on signaling
+ the current process group (of which we are a member). */
+ (void)signal(SIGHUP, SIG_IGN);
+ /* Forward the signal to the current process group. */
+ (void)kill(0, signo);
+ /* Forward the signal to the child if not a member of the current
+ * process group <rdar://problem/6244808>. */
+ if (getpgid(pid) != getpgrp()) {
+ (void)kill(pid, signo);
+ }
+ }
+}
+
+/*
+ * SIGALRM handler, to enforce login prompt timeout.
+ *
+ * XXX This can potentially confuse the hell out of PAM. We should
+ * XXX instead implement a conversation function that returns
+ * XXX PAM_CONV_ERR when interrupted by a signal, and have the signal
+ * XXX handler just set a flag.
+ */
+static void
+timedout(int signo __unused)
+{
+
+ longjmp(timeout_buf, signo);
+}
+
+#ifdef __APPLE__
+#ifndef USE_PAM
+void
+checknologin(void)
+{
+ int fd, nchars;
+ char tbuf[8192];
+
+ if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) {
+ while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
+ (void)write(fileno(stdout), tbuf, nchars);
+#ifdef USE_BSM_AUDIT
+ au_login_fail("No login", 0);
+#endif
+ sleep(5);
+ exit(0);
+ }
+}
+#endif /* !USE_PAM */
+
+void
+dolastlog(int quiet)
+{
+#ifdef USE_PAM
+ if (quiet)
+ return;
+ if (*lastlog.ll_line) {
+ (void)printf("Last login: %.*s ",
+ 24-5, (char *)ctime(&lastlog.ll_tv.tv_sec));
+ if (*lastlog.ll_host != '\0')
+ (void)printf("from %.*s\n",
+ (int)sizeof(lastlog.ll_host),
+ lastlog.ll_host);
+ else
+ (void)printf("on %.*s\n",
+ (int)sizeof(lastlog.ll_line),
+ lastlog.ll_line);
+ }
+#else /* !USE_PAM */
+ struct lastlogx ll;
+
+ if(!quiet && getlastlogx(pwd->pw_uid, &ll) != NULL) {
+ (void)printf("Last login: %.*s ",
+ 24-5, (char *)ctime(&ll.ll_tv.tv_sec));
+ if (*ll.ll_host != '\0')
+ (void)printf("from %.*s\n",
+ (int)sizeof(ll.ll_host),
+ ll.ll_host);
+ else
+ (void)printf("on %.*s\n",
+ (int)sizeof(ll.ll_line),
+ ll.ll_line);
+ }
+#endif /* USE_PAM */
+}
+#endif /* __APPLE__ */
+
+static void
+badlogin(char *name)
+{
+ if (failures == 0)
+ return;
+ if (hflag) {
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s",
+ failures, failures > 1 ? "S" : "", hostname);
+ syslog(LOG_AUTHPRIV|LOG_NOTICE,
+ "%d LOGIN FAILURE%s FROM %s, %s",
+ failures, failures > 1 ? "S" : "", hostname, name);
+ } else {
+ syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s",
+ failures, failures > 1 ? "S" : "", tty);
+ syslog(LOG_AUTHPRIV|LOG_NOTICE,
+ "%d LOGIN FAILURE%s ON %s, %s",
+ failures, failures > 1 ? "S" : "", tty, name);
+ }
+ failures = 0;
+}
+
+const char *
+stypeof(char *ttyid)
+{
+ struct ttyent *t;
+
+ if (ttyid != NULL && *ttyid != '\0') {
+ t = getttynam(ttyid);
+ if (t != NULL && t->ty_type != NULL)
+ return (t->ty_type);
+ }
+ return (NULL);
+}
+
+static void
+refused(const char *msg, const char *rtype, int lout)
+{
+
+ if (msg != NULL)
+ printf("%s.\n", msg);
+ if (hflag)
+ syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) FROM %s ON TTY %s",
+ pwd->pw_name, rtype, hostname, tty);
+ else
+ syslog(LOG_NOTICE, "LOGIN %s REFUSED (%s) ON TTY %s",
+ pwd->pw_name, rtype, tty);
+ if (lout)
+ bail(SLEEP_EXIT, 1);
+}
+
+#ifdef USE_PAM
+/*
+ * Log a PAM error
+ */
+static void
+pam_syslog(const char *msg)
+{
+ syslog(LOG_ERR, "%s: %s", msg, pam_strerror(pamh, pam_err));
+}
+
+/*
+ * Shut down PAM
+ */
+static void
+pam_cleanup(void)
+{
+ if (pamh != NULL) {
+ if (pam_session_established) {
+ pam_err = pam_close_session(pamh, 0);
+ if (pam_err != PAM_SUCCESS)
+ pam_syslog("pam_close_session()");
+ }
+ pam_session_established = 0;
+ if (pam_cred_established) {
+ pam_err = pam_setcred(pamh, pam_silent|PAM_DELETE_CRED);
+ if (pam_err != PAM_SUCCESS)
+ pam_syslog("pam_setcred()");
+ }
+ pam_cred_established = 0;
+ pam_end(pamh, pam_err);
+ pamh = NULL;
+ }
+}
+#endif /* USE_PAM */
+
+/*
+ * Exit, optionally after sleeping a few seconds
+ */
+void
+bail(int sec, int eval)
+{
+#ifdef USE_PAM
+ pam_cleanup();
+#endif /* USE_PAM */
+#ifdef USE_BSM_AUDIT
+ if (pwd != NULL)
+ audit_logout();
+#endif
+ (void)sleep(sec);
+ exit(eval);
+}
diff --git a/system_cmds/login.tproj/login.entitlements b/system_cmds/login.tproj/login.entitlements
new file mode 100644
index 0000000..a9f77f2
--- /dev/null
+++ b/system_cmds/login.tproj/login.entitlements
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.private.security.clear-library-validation</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/login.tproj/login.h b/system_cmds/login.tproj/login.h
new file mode 100644
index 0000000..fd6d172
--- /dev/null
+++ b/system_cmds/login.tproj/login.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2001 FreeBSD, Inc
+ *
+ * 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.
+ *
+ * $FreeBSD: src/usr.bin/login/login.h,v 1.7 2007/05/07 11:01:36 dwmalone Exp $
+ */
+
+void login_fbtab(char *, uid_t, gid_t);
+
+#ifdef USE_BSM_AUDIT
+void au_login_success(int fflag);
+void au_login_fail(const char *errmsg, int na);
+void audit_logout(void);
+#endif
+
+extern char **environ;
+extern struct passwd *pwd;
diff --git a/system_cmds/login.tproj/login_audit.c b/system_cmds/login.tproj/login_audit.c
new file mode 100644
index 0000000..0186637
--- /dev/null
+++ b/system_cmds/login.tproj/login_audit.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2005-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_START@
+ *
+ * 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 Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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.
+ *
+ * @APPLE_BSD_LICENSE_HEADER_END@
+ */
+
+#ifdef USE_BSM_AUDIT
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/login/login_audit.c,v 1.2 2007/05/07 11:01:36 dwmalone Exp $");
+
+#include <sys/types.h>
+
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+#include <bsm/audit_session.h>
+
+#include <err.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "login.h"
+
+/*
+ * Audit data
+ */
+au_tid_addr_t tid;
+
+/*
+ * The following tokens are included in the audit record for a successful
+ * login: header, subject, return.
+ */
+void
+au_login_success(int fflag)
+{
+ token_t *tok;
+ int aufd;
+ auditinfo_addr_t auinfo;
+ uid_t uid = pwd->pw_uid;
+ gid_t gid = pwd->pw_gid;
+ pid_t pid = getpid();
+ long au_cond;
+
+ /* Determine whether auditing is enabled. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "login: Could not determine audit condition");
+ }
+
+ /* Initialize with the current audit info. */
+ if (getaudit_addr(&auinfo, sizeof(auinfo)) < 0) {
+ err(1, "getaudit_addr");
+ }
+ auinfo.ai_auid = pwd->pw_uid;
+ memcpy(&auinfo.ai_termid, &tid, sizeof(auinfo.ai_termid));
+
+ /* Do the SessionCreate() equivalent. */
+ if (!fflag) {
+ auinfo.ai_asid = AU_ASSIGN_ASID;
+ auinfo.ai_flags |= AU_SESSION_FLAG_HAS_TTY;
+ auinfo.ai_flags |= AU_SESSION_FLAG_HAS_AUTHENTICATED;
+ }
+
+ if (au_cond != AUC_NOAUDIT) {
+ /* Compute and set the user's preselection mask. */
+ if (au_user_mask(pwd->pw_name, &auinfo.ai_mask) < 0) {
+ errx(1, "login: Could not set audit mask\n");
+ }
+ }
+
+ if (setaudit_addr(&auinfo, sizeof(auinfo)) < 0)
+ err(1, "login: setaudit_addr failed");
+
+ char *session = NULL;
+ asprintf(&session, "%x", auinfo.ai_asid);
+ if (NULL == session) {
+ errx(1, "asprintf failed");
+ }
+ setenv("SECURITYSESSIONID", session, 1);
+ free(session);
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ if ((aufd = au_open()) == -1)
+ errx(1,"login: Audit Error: au_open() failed");
+
+ if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, gid, pid,
+ pid, &tid)) == NULL)
+ errx(1, "login: Audit Error: au_to_subject32() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(0, 0)) == NULL)
+ errx(1, "login: Audit Error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_login) == -1)
+ errx(1, "login: Audit Record was not committed.");
+}
+
+/*
+ * The following tokens are included in the audit record for failed
+ * login attempts: header, subject, text, return.
+ */
+void
+au_login_fail(const char *errmsg, int na)
+{
+ token_t *tok;
+ int aufd;
+ long au_cond;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid = getpid();
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "login: Could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ if ((aufd = au_open()) == -1)
+ errx(1, "login: Audit Error: au_open() failed");
+
+ if (na) {
+ /*
+ * Non attributable event. Assuming that login is not called
+ * within a user's session => auid,asid == -1.
+ */
+ if ((tok = au_to_subject32_ex(-1, geteuid(), getegid(), -1, -1,
+ pid, -1, &tid)) == NULL)
+ errx(1, "login: Audit Error: au_to_subject32() failed");
+ } else {
+ /* We know the subject -- so use its value instead. */
+ uid = pwd->pw_uid;
+ gid = pwd->pw_gid;
+ if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid,
+ gid, pid, pid, &tid)) == NULL)
+ errx(1, "login: Audit Error: au_to_subject32() failed");
+ }
+ au_write(aufd, tok);
+
+ /* Include the error message. */
+ if ((tok = au_to_text(errmsg)) == NULL)
+ errx(1, "login: Audit Error: au_to_text() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(1, errno)) == NULL)
+ errx(1, "login: Audit Error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_login) == -1)
+ errx(1, "login: Audit Error: au_close() was not committed");
+}
+
+/*
+ * The following tokens are included in the audit record for a logout:
+ * header, subject, return.
+ */
+void
+audit_logout(void)
+{
+ token_t *tok;
+ int aufd;
+ uid_t uid = pwd->pw_uid;
+ gid_t gid = pwd->pw_gid;
+ pid_t pid = getpid();
+ long au_cond;
+
+ /* If we are not auditing, don't cut an audit record; just return. */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ if (errno == ENOSYS)
+ return;
+ errx(1, "login: Could not determine audit condition");
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return;
+
+ if ((aufd = au_open()) == -1)
+ errx(1, "login: Audit Error: au_open() failed");
+
+ /* The subject that is created (euid, egid of the current process). */
+ if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, gid, pid,
+ pid, &tid)) == NULL)
+ errx(1, "login: Audit Error: au_to_subject32() failed");
+ au_write(aufd, tok);
+
+ if ((tok = au_to_return32(0, 0)) == NULL)
+ errx(1, "login: Audit Error: au_to_return32() failed");
+ au_write(aufd, tok);
+
+ if (au_close(aufd, 1, AUE_logout) == -1)
+ errx(1, "login: Audit Record was not committed.");
+}
+
+#endif /* USE_BSM_AUDIT */
diff --git a/system_cmds/login.tproj/pam.d/login b/system_cmds/login.tproj/pam.d/login
new file mode 100644
index 0000000..36b41f6
--- /dev/null
+++ b/system_cmds/login.tproj/pam.d/login
@@ -0,0 +1,11 @@
+# login: auth account password session
+auth optional pam_krb5.so use_kcminit
+auth optional pam_ntlm.so try_first_pass
+auth optional pam_mount.so try_first_pass
+auth required pam_opendirectory.so try_first_pass
+account required pam_nologin.so
+account required pam_opendirectory.so
+password required pam_opendirectory.so
+session required pam_launchd.so
+session required pam_uwtmp.so
+session optional pam_mount.so
diff --git a/system_cmds/login.tproj/pam.d/login.term b/system_cmds/login.tproj/pam.d/login.term
new file mode 100644
index 0000000..2c57c34
--- /dev/null
+++ b/system_cmds/login.tproj/pam.d/login.term
@@ -0,0 +1,4 @@
+# login: account session
+account required pam_nologin.so
+account required pam_opendirectory.so
+session required pam_uwtmp.so
diff --git a/system_cmds/login.tproj/pathnames.h b/system_cmds/login.tproj/pathnames.h
new file mode 100644
index 0000000..96da87e
--- /dev/null
+++ b/system_cmds/login.tproj/pathnames.h
@@ -0,0 +1,42 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/9/93
+ * $FreeBSD: src/usr.bin/login/pathnames.h,v 1.6 2006/03/06 12:38:42 yar Exp $
+ */
+
+#include <paths.h>
+
+#define _PATH_HUSHLOGIN ".hushlogin"
+#define _PATH_MOTDFILE "/etc/motd"
+#define _PATH_FBTAB "/etc/fbtab"
+#define _PATH_LOGINDEVPERM "/etc/logindevperm"
diff --git a/system_cmds/lskq.tproj/common.h b/system_cmds/lskq.tproj/common.h
new file mode 100644
index 0000000..959ac66
--- /dev/null
+++ b/system_cmds/lskq.tproj/common.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _LSKQ_COMMON_H_
+#define _LSKQ_COMMON_H_
+
+#include <stdint.h>
+
+/*
+ * This file must be kept in sync with xnu headers
+ */
+
+/*
+ * bsd/sys/event.h
+ */
+__options_decl(kn_status_t, uint16_t /* 12 bits really */, {
+ KN_ACTIVE = 0x001, /* event has been triggered */
+ KN_QUEUED = 0x002, /* event is on queue */
+ KN_DISABLED = 0x004, /* event is disabled */
+ KN_DROPPING = 0x008, /* knote is being dropped */
+ KN_LOCKED = 0x010, /* knote is locked (kq_knlocks) */
+ KN_POSTING = 0x020, /* f_event() in flight */
+ KN_STAYACTIVE = 0x040, /* force event to stay active */
+ KN_DEFERDELETE = 0x080, /* defer delete until re-enabled */
+ KN_MERGE_QOS = 0x100, /* f_event() / f_* ran concurrently and overrides must merge */
+ KN_REQVANISH = 0x200, /* requested EV_VANISH */
+ KN_VANISHED = 0x400, /* has vanished */
+ KN_SUPPRESSED = 0x800, /* event is suppressed during delivery */
+});
+
+/*
+ * bsd/sys/eventvar.h
+ */
+__options_decl(kq_state_t, uint16_t, {
+ KQ_SEL = 0x0001, /* select was recorded for kq */
+ KQ_SLEEP = 0x0002, /* thread is waiting for events */
+ KQ_PROCWAIT = 0x0004, /* thread waiting for processing */
+ KQ_KEV32 = 0x0008, /* kq is used with 32-bit events */
+ KQ_KEV64 = 0x0010, /* kq is used with 64-bit events */
+ KQ_KEV_QOS = 0x0020, /* kq events carry QoS info */
+ KQ_WORKQ = 0x0040, /* KQ is bound to process workq */
+ KQ_WORKLOOP = 0x0080, /* KQ is part of a workloop */
+ KQ_PROCESSING = 0x0100, /* KQ is being processed */
+ KQ_DRAIN = 0x0200, /* kq is draining */
+ KQ_WAKEUP = 0x0400, /* kq awakened while processing */
+ KQ_DYNAMIC = 0x0800, /* kqueue is dynamically managed */
+ KQ_R2K_ARMED = 0x1000, /* ast notification armed */
+ KQ_HAS_TURNSTILE = 0x2000, /* this kqueue has a turnstile */
+});
+
+/*
+ * bsd/pthread/workqueue_internal.h
+ */
+__enum_decl(workq_tr_state_t, uint8_t, {
+ WORKQ_TR_STATE_IDLE = 0, /* request isn't in flight */
+ WORKQ_TR_STATE_NEW = 1, /* request is being initiated */
+ WORKQ_TR_STATE_QUEUED = 2, /* request is being queued */
+ WORKQ_TR_STATE_CANCELED = 3, /* request is canceled */
+ WORKQ_TR_STATE_BINDING = 4, /* request is preposted for bind */
+ WORKQ_TR_STATE_BOUND = 5, /* request is bound to a thread */
+});
+
+
+/*
+ * bsd/sys/signal.h
+ */
+static const char *
+sig_strs[] = {
+ [0] = "<UNKN>",
+ [1] = "SIGHUP",
+ [2] = "SIGINT",
+ [3] = "SIGQUIT",
+ [4] = "SIGILL",
+ [5] = "SIGTRAP",
+ [6] = "SIGABRT",
+ [7] = "SIGEMT",
+ [8] = "SIGFPE",
+ [9] = "SIGKILL",
+ [10] = "SIGBUS",
+ [11] = "SIGSEGV",
+ [12] = "SIGSYS",
+ [13] = "SIGPIPE",
+ [14] = "SIGALRM",
+ [15] = "SIGTERM",
+ [16] = "SIGURG",
+ [17] = "SIGSTOP",
+ [18] = "SIGTSTP",
+ [19] = "SIGCONT",
+ [20] = "SIGCHLD",
+ [21] = "SIGTTIN",
+ [22] = "SIGTTOU",
+ [23] = "SIGIO",
+ [24] = "SIGXCPU",
+ [25] = "SIGXFSZ",
+ [26] = "SIGVTALRM",
+ [27] = "SIGPROF",
+ [28] = "SIGWINCH",
+ [29] = "SIGINFO",
+ [30] = "SIGUSR1",
+ [31] = "SIGUSR2"
+};
+
+/*
+ * bsd/sys/event.h: EVFILT_*
+ */
+static const char *
+filt_strs[] = {
+ NULL,
+ "READ",
+ "WRITE",
+ "AIO",
+ "VNODE",
+ "PROC",
+ "SIGNAL",
+ "TIMER",
+ "MACHPORT",
+ "FS",
+ "USER",
+ "<inval>",
+ "VM",
+ "SOCK",
+ "MEMSTATUS",
+ "EXCEPT",
+ "CHANNEL",
+ "WORKLOOP",
+};
+
+/*
+ * bsd/sys/proc_info.h: PROX_FDTYPE_*
+ */
+static const char *
+fdtype_strs[] = {
+ "ATALK",
+ "VNODE",
+ "SOCKET",
+ "PSHM",
+ "PSEM",
+ "KQUEUE",
+ "PIPE",
+ "FSEVENTS",
+ "ATALK",
+ "POLICY",
+ "CHANNEL",
+ "NEXUS",
+};
+
+#endif /* _LSKQ_COMMON_H_ */
diff --git a/system_cmds/lskq.tproj/lskq.1 b/system_cmds/lskq.tproj/lskq.1
new file mode 100644
index 0000000..86e31d8
--- /dev/null
+++ b/system_cmds/lskq.tproj/lskq.1
@@ -0,0 +1,236 @@
+.\" Copyright (c) 2015, Apple Inc. All rights reserved.
+.\"
+.Dd Apr 20, 2015
+.Dt lskq 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm lskq
+.Nd display process kqueue state
+.Sh SYNOPSIS
+.Nm lskq
+.Op Fl vhe
+.Op Fl p Ar <pid> | Fl a
+.Sh DESCRIPTION
+The
+.Nm lskq
+command enumerates kqueues and registered kevents of running processes.
+.Sh OPTIONS
+.Pp
+.Bl -tag -width xxx
+.It Fl p Ar <pid>
+Show kqueues of process
+.Ar <pid> .
+.It Fl a
+Show kqueues for all running processes. Requires root.
+.It Fl v
+Verbose: show opaque user data and filter-specific extension fields.
+.It Fl e
+Ignore empty kqueues.
+.It Fl r
+Print fields in raw hex.
+.It Fl h
+Show help and exit.
+.El
+.Sh OUTPUT
+.Nm lskq
+prints one line of output for each registered kevent, consisting of process,
+kqueue, and kevent information. For kqueues with no registered kevents, a single
+line is output with an ident of `-'. See
+.Xr kevent 2
+for field semantics. The output columns are:
+.Bl -tag -width xxxxxxxxxxxx
+.It command
+shortened process name.
+.It pid
+process identifier.
+.It kq
+file descriptor corresponding to kqueue, or ``wq'' for the special workq kqueue.
+.It kqst
+kqueue status bitmask.
+.Bl -tag -width xxxxxxx -compact
+.It Sy k
+kqueue is in a
+.Fn kevent*
+wait set (KQ_SLEEP).
+.It Sy s
+kqueue is in a
+.Fn select
+wait set (KQ_SEL).
+.It Sy 3 6 q
+Type of kevents on this kqueue: KEV32, KEV64, or KEV_QOS.
+.El
+.It ident
+kevent identifier. The meaning depends on the kevent filter specified. Where
+possible,
+.Nm lskq
+prints both numeric and symbolic names.
+.It filter
+kevent filter type (EVFILT_*).
+.It fdtype
+file descriptor type, for filters operating on file descriptors.
+.It fflags
+kevent filter flags bitmask. The meaning of each field depends on the filter type.
+.Bl -tag -width xxxxxxx -compact
+.Pp
+.It EVFILT_READ:
+.It Sy l
+NOTE_LOWAT
+.Pp
+.It EVFILT_MACHPORT:
+.It Sy r
+MACH_RCV_MSG
+.Pp
+.It EVFILT_VNODE:
+.It Sy d
+NOTE_DELETE
+.It Sy w
+NOTE_WRITE
+.It Sy e
+NOTE_EXTEND
+.It Sy a
+NOTE_ATTRIB
+.It Sy l
+NOTE_LINK
+.It Sy r
+NOTE_RENAME
+.It Sy v
+NOTE_REVOKE
+.It Sy u
+NOTE_FUNLOCK
+.Pp
+.It EVFILT_PROC:
+.It Sy x
+NOTE_EXIT
+.It Sy t
+NOTE_EXITSTATUS
+.It Sy d
+NOTE_EXIT_DETAIL
+.It Sy f
+NOTE_FORK
+.It Sy e
+NOTE_EXEC
+.It Sy s
+NOTE_SIGNAL
+.It Sy r
+NOTE_REAP
+.Pp
+.It EVFILT_TIMER:
+.It Sy s u n m
+NOTE_SECONDS, NOTE_USECONDS, NOTE_NSECONDS, NOTE_MACHTIME
+.It Sy a A
+NOTE_ABSOLUTE, NOTE_MACH_CONTINUOUS_TIME
+.It Sy c
+NOTE_CRITICAL
+.It Sy b
+NOTE_BACKGROUND
+.It Sy l
+NOTE_LEEWAY
+.Pp
+.It EVFILT_USER:
+.It Sy t
+NOTE_TRIGGER
+.It Sy a
+NOTE_FFAND
+.It Sy o
+NOTE_FFOR
+.Pp
+.It EVFILT_WORKLOOP:
+.It Sy t w i
+NOTE_WL_THREAD_REQUEST, NOTE_WL_SYNC_WAIT, NOTE_WL_SYNC_IPC
+.It Sy W
+NOTE_WL_SYNC_WAKE
+.It Sy q
+NOTE_WL_UPDATE_QOS
+.It Sy o
+NOTE_WL_DISCOVER_OWNER
+.It Sy e
+NOTE_WL_IGNORE_ESTALE
+.El
+.It flags
+kevent generic flags bitmask.
+.Bl -tag -width xxxxxxx -compact
+.It Sy a
+EV_ADD
+.It Sy n
+EV_ENABLE
+.It Sy d
+EV_DISABLE
+.It Sy x
+EV_DELETE
+.Pp
+.It Sy r
+EV_RECEIPT
+.It Sy 1
+EV_ONESHOT
+.It Sy c
+EV_CLEAR
+.It Sy s
+EV_DISPATCH
+.Pp
+.It Sy u
+EV_UDATA_SPECIFIC
+.It Sy p
+EV_FLAG0 (EV_POLL)
+.It Sy b
+EV_FLAG1 (EV_OOBAND)
+.It Sy o
+EV_EOF
+.It Sy e
+EV_ERROR
+.El
+.It evst
+kevent status bitmask.
+.Bl -tag -width xxxxxxx -compact
+.It Sy a
+KN_ACTIVE (event has triggered)
+.It Sy q
+KN_QUEUED (event has been added to the active list)
+.It Sy d
+KN_DISABLED (knote is disabled)
+.It Sy p
+KN_SUPPRESSED (event delivery is in flight)
+.It Sy s
+KN_STAYACTIVE (event is marked as always-enqueued on the active list)
+.Pp
+.It Sy d
+KN_DROPPING (knote is about to be dropped)
+.It Sy l
+KN_LOCKED (knote is locked)
+.It Sy P
+KN_POSTING (knote is being posted)
+.It Sy m
+KN_MERGE_QOS (knote is in override saturating mode)
+.Pp
+.It Sy D
+KN_DEFERDELETE (knote is waiting for deferred-delete ack)
+.It Sy v
+KN_REQVANISH
+.It Sy n
+KN_VANISHED
+.El
+.It qos
+The QoS requested for the knote.
+.It data
+Filter-specific data.
+.El
+.Pp
+If the
+.Fl v
+(verbose) option is specified, the opaque user-data field and further
+filter-specific extension fields are printed in raw hexadecimal.
+.Sh NOTES
+The output of
+.Nm lskq
+is not an atomic snapshot of system state. In cases where
+.Nm lskq
+is able to detect an inconsistency, a warning will be printed.
+.Pp
+Not all flags are symbolicated. Use
+.Fl r
+(raw mode) to inspect additional flags.
+.Sh SEE ALSO
+.Xr kqueue 2 ,
+.Xr kevent 2 ,
+.Xr ddt 1 ,
+.Xr lsof 8 ,
+.Xr lsmp 1
diff --git a/system_cmds/lskq.tproj/lskq.c b/system_cmds/lskq.tproj/lskq.c
new file mode 100644
index 0000000..a48bb26
--- /dev/null
+++ b/system_cmds/lskq.tproj/lskq.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/proc_info.h>
+#include <sys/param.h>
+#include <pthread/pthread.h>
+#include <mach/message.h>
+#define PRIVATE
+#include <libproc.h>
+#undef PRIVATE
+#include <os/assumes.h>
+#include <os/overflow.h>
+
+#include "common.h"
+
+#define ARRAYLEN(x) (sizeof((x))/sizeof((x[0])))
+
+/* command line options */
+static int verbose;
+static int all_pids;
+static int ignore_empty;
+static int raw;
+
+static char *self = "lskq";
+
+static inline const char *
+filt_name(int16_t filt)
+{
+ static char unkn_filt[32];
+ int idx = -filt;
+ if (idx >= 0 && idx < ARRAYLEN(filt_strs)) {
+ return filt_strs[idx];
+ } else {
+ snprintf(unkn_filt, sizeof(unkn_filt), "%i (?)", idx);
+ return unkn_filt;
+ }
+}
+
+static inline const char *
+fdtype_str(uint32_t type)
+{
+ static char unkn_fdtype[32];
+ if (type < ARRAYLEN(fdtype_strs)) {
+ return fdtype_strs[type];
+ } else {
+ snprintf(unkn_fdtype, sizeof(unkn_fdtype), "%i (?)", type);
+ return unkn_fdtype;
+ }
+}
+
+static char *
+fflags_build(struct kevent_extinfo *info, char *str, int len)
+{
+ unsigned ff = info->kqext_sfflags;
+
+ switch (info->kqext_kev.filter) {
+
+ case EVFILT_READ: {
+ snprintf(str, len, "%c ",
+ (ff & NOTE_LOWAT) ? 'l' : '-'
+ );
+ break;
+ }
+
+ case EVFILT_MACHPORT: {
+ snprintf(str, len, "%c ",
+ (ff & MACH_RCV_MSG) ? 'r' : '-'
+ );
+ break;
+ }
+
+ case EVFILT_VNODE: {
+ snprintf(str, len, "%c%c%c%c%c%c%c%c",
+ (ff & NOTE_DELETE) ? 'd' : '-',
+ (ff & NOTE_WRITE) ? 'w' : '-',
+ (ff & NOTE_EXTEND) ? 'e' : '-',
+ (ff & NOTE_ATTRIB) ? 'a' : '-',
+ (ff & NOTE_LINK) ? 'l' : '-',
+ (ff & NOTE_RENAME) ? 'r' : '-',
+ (ff & NOTE_REVOKE) ? 'v' : '-',
+ (ff & NOTE_FUNLOCK) ? 'u' : '-'
+ );
+ break;
+ }
+
+ case EVFILT_PROC: {
+/* NOTE_REAP is deprecated, but we still want to show if it's used */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+ snprintf(str, len, "%c%c%c%c%c%c%c",
+ (ff & NOTE_EXIT) ? 'x' : '-',
+ (ff & NOTE_EXITSTATUS) ? 't' : '-',
+ (ff & NOTE_EXIT_DETAIL)? 'd' : '-',
+ (ff & NOTE_FORK) ? 'f' : '-',
+ (ff & NOTE_EXEC) ? 'e' : '-',
+ (ff & NOTE_SIGNAL) ? 's' : '-',
+ (ff & NOTE_REAP) ? 'r' : '-'
+ );
+ break;
+#pragma clang diagnostic pop
+ }
+
+ case EVFILT_TIMER: {
+ snprintf(str, len, "%c%c%c%c%c ",
+ (ff & NOTE_SECONDS) ? 's' :
+ (ff & NOTE_USECONDS) ? 'u' :
+ (ff & NOTE_NSECONDS) ? 'n' :
+ (ff & NOTE_MACHTIME) ? 'm' : '?',
+ (ff & NOTE_ABSOLUTE) ? 'a' :
+ (ff & NOTE_MACH_CONTINUOUS_TIME) ? 'A' : '-',
+ (ff & NOTE_CRITICAL) ? 'c' : '-',
+ (ff & NOTE_BACKGROUND) ? 'b' : '-',
+ (ff & NOTE_LEEWAY) ? 'l' : '-'
+ );
+ break;
+ }
+
+ case EVFILT_USER:
+ snprintf(str, len, "%c%c%c ",
+ (ff & NOTE_TRIGGER) ? 't' : '-',
+ (ff & NOTE_FFAND) ? 'a' : '-',
+ (ff & NOTE_FFOR) ? 'o' : '-'
+ );
+ break;
+
+ case EVFILT_WORKLOOP:
+ snprintf(str, len, "%c%c%c%c%c ",
+ (ff & NOTE_WL_THREAD_REQUEST) ? 't' :
+ (ff & NOTE_WL_SYNC_WAIT) ? 'w' :
+ (ff & NOTE_WL_SYNC_IPC) ? 'i' : '-',
+ (ff & NOTE_WL_SYNC_WAKE) ? 'W' : '-',
+ (ff & NOTE_WL_UPDATE_QOS) ? 'q' : '-',
+ (ff & NOTE_WL_DISCOVER_OWNER) ? 'o' : '-',
+ (ff & NOTE_WL_IGNORE_ESTALE) ? 'e' : '-'
+ );
+ break;
+
+ default:
+ snprintf(str, len, "");
+ break;
+ };
+
+ return str;
+}
+
+
+static inline int
+filter_is_fd_type(int filter)
+{
+ switch (filter) {
+ case EVFILT_VNODE ... EVFILT_READ:
+ case EVFILT_SOCK:
+ case EVFILT_NW_CHANNEL:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static const char *
+thread_qos_name(uint8_t th_qos)
+{
+ switch (th_qos) {
+ case 0: return "--";
+ case 1: return "MT";
+ case 2: return "BG";
+ case 3: return "UT";
+ case 4: return "DF";
+ case 5: return "IN";
+ case 6: return "UI";
+ case 7: return "MG";
+ default: return "??";
+ }
+}
+
+/*
+ * find index of fd in a list of fdinfo of length nfds
+ */
+static inline int
+fd_list_getfd(struct proc_fdinfo *fds, int nfds, int fd)
+{
+ int i;
+ for (i = 0; i < nfds; i++) {
+ if (fds[i].proc_fd == fd) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+/*
+ * left truncate URL-form process names
+ */
+static const char *
+shorten_procname(const char *proc, int width)
+{
+ if (strcasestr(proc, "com.") == proc) {
+ long len = strlen(proc);
+ if (len > width) {
+ return &proc[len - width];
+ } else {
+ return proc;
+ }
+ } else {
+ return proc;
+ }
+}
+
+/*
+ * stringify knote ident where possible (signals, processes)
+ */
+static void
+print_ident(uint64_t ident, int16_t filter, int width)
+{
+ if (raw) {
+ printf("%#*llx ", width, ident);
+ return;
+ }
+
+ switch (filter) {
+
+ case EVFILT_SIGNAL:
+ case EVFILT_PROC: {
+ char str[128] = "";
+ char num[128];
+ char out[128];
+ int numlen = sprintf(num, "%llu", ident);
+ int strwidth = width - numlen - 1; // add room for a space
+
+ if (filter == EVFILT_SIGNAL) {
+ if (ident < ARRAYLEN(sig_strs)) {
+ snprintf(str, strwidth + 1, "%s", sig_strs[ident]);
+ }
+ } else {
+ /* FIXME: this should be cached */
+ struct proc_bsdinfo bsdinfo;
+ int ret = proc_pidinfo((int)ident, PROC_PIDTBSDINFO, 0, &bsdinfo, sizeof(bsdinfo));
+ if (ret == sizeof(bsdinfo)) {
+ char *procname = bsdinfo.pbi_name;
+ if (strlen(procname) == 0) {
+ procname = bsdinfo.pbi_comm;
+ }
+ snprintf(str, strwidth + 1, "%s", shorten_procname(procname, strwidth));
+ }
+ }
+
+ if (str[0] != '\0') {
+ snprintf(out, width + 1, "%-*s %s", strwidth, str, num);
+ } else {
+ snprintf(out, width + 1, "%s", num);
+ }
+
+ printf("%*s ", width, out);
+ break;
+ }
+
+ case EVFILT_MACHPORT:
+ case EVFILT_TIMER:
+ /* hex, to match lsmp */
+ printf("%#*llx ", width, ident);
+ break;
+
+ case EVFILT_WORKLOOP:
+ printf("%#*llx ", width, ident);
+ break;
+
+ default:
+ printf("%*llu ", width, ident);
+ break;
+ }
+
+}
+
+static void
+print_kqid(int state, uint64_t kqid)
+{
+ if (state & KQ_WORKQ) {
+ printf("%18s ", "wq");
+ } else if (state & KQ_WORKLOOP) {
+ printf("%#18" PRIx64 " ", kqid);
+ } else {
+ printf("fd %15" PRIi64 " ", kqid);
+ }
+}
+
+#define PROCNAME_WIDTH 20
+
+static void
+print_kq_info(int pid, const char *procname, uint64_t kqid, int state)
+{
+ if (raw) {
+ printf("%5u ", pid);
+ print_kqid(state, kqid);
+ printf("%#10x ", state);
+ } else {
+ char tmpstr[PROCNAME_WIDTH+1];
+ strlcpy(tmpstr, shorten_procname(procname, PROCNAME_WIDTH), PROCNAME_WIDTH+1);
+ printf("%-*s ", PROCNAME_WIDTH, tmpstr);
+ printf("%5u ", pid);
+ print_kqid(state, kqid);
+ printf(" %c%c%c ",
+ (state & KQ_SLEEP) ? 'k' : '-',
+ (state & KQ_SEL) ? 's' : '-',
+ (state & KQ_WORKQ) ? 'q' :
+ (state & KQ_WORKLOOP) ? 'l' : '-'
+ );
+ }
+}
+
+enum kqtype {
+ KQTYPE_FD,
+ KQTYPE_DYNAMIC
+};
+
+#define POLICY_TIMESHARE 1
+#define POLICY_RR 2
+#define POLICY_FIFO 4
+
+static int
+process_kqueue(int pid, const char *procname, enum kqtype type, uint64_t kqid,
+ struct proc_fdinfo *fdlist, int nfds)
+{
+ int ret, i, nknotes;
+ char tmpstr[256];
+ int maxknotes = 256; /* arbitrary starting point */
+ int kq_state;
+ bool is_kev_64, is_kev_qos;
+ int err = 0;
+ bool overflow = false;
+ int fd;
+ bool dynkq_printed = false;
+
+ /*
+ * get the basic kqueue info
+ */
+ struct kqueue_fdinfo kqfdinfo = {};
+ struct kqueue_dyninfo kqinfo = {};
+ switch (type) {
+ case KQTYPE_FD:
+ ret = proc_pidfdinfo(pid, (int)kqid, PROC_PIDFDKQUEUEINFO, &kqfdinfo, sizeof(kqfdinfo));
+ fd = (int)kqid;
+ break;
+ case KQTYPE_DYNAMIC:
+ ret = proc_piddynkqueueinfo(pid, PROC_PIDDYNKQUEUE_INFO, kqid, &kqinfo, sizeof(kqinfo));
+ break;
+ default:
+ os_crash("invalid kqueue type");
+ }
+
+ if (type == KQTYPE_FD && (int)kqid != -1) {
+ if (ret != sizeof(kqfdinfo)) {
+ /* every proc has an implicit workq kqueue, dont warn if its unused */
+ fprintf(stderr, "WARN: FD table changed (pid %i, kq %i)\n", pid,
+ fd);
+ }
+ } else if (type == KQTYPE_DYNAMIC) {
+ if (ret < sizeof(struct kqueue_info)) {
+ fprintf(stderr, "WARN: kqueue missing (pid %i, kq %#" PRIx64 ")\n",
+ pid, kqid);
+ } else {
+ kqfdinfo.kqueueinfo = kqinfo.kqdi_info;
+ }
+ if (verbose && ret >= sizeof(struct kqueue_dyninfo)) {
+ print_kq_info(pid, procname, kqid, kqinfo.kqdi_info.kq_state);
+
+ if (kqinfo.kqdi_owner) {
+ printf("%#18llx ", kqinfo.kqdi_owner); // ident
+ printf("%-9s ", "WL owned"); // filter
+ } else if (kqinfo.kqdi_servicer) {
+ printf("%#18llx ", kqinfo.kqdi_servicer); // ident
+ printf("%-9s ", "WL"); // filter
+ } else {
+ printf("%18s ", "-"); // ident
+ printf("%-9s ", "WL"); // filter
+ }
+ dynkq_printed = true;
+
+ if (raw) {
+ printf("%-10s ", " "); // fflags
+ printf("%-10s ", " "); // flags
+ printf("%-10s ", " "); // evst
+ } else {
+ const char *reqstate = "???";
+
+ switch (kqinfo.kqdi_request_state) {
+ case WORKQ_TR_STATE_IDLE:
+ reqstate = "";
+ break;
+ case WORKQ_TR_STATE_NEW:
+ reqstate = "new";
+ break;
+ case WORKQ_TR_STATE_QUEUED:
+ reqstate = "queued";
+ break;
+ case WORKQ_TR_STATE_CANCELED:
+ reqstate = "canceled";
+ break;
+ case WORKQ_TR_STATE_BINDING:
+ reqstate = "binding";
+ break;
+ case WORKQ_TR_STATE_BOUND:
+ reqstate = "bound";
+ break;
+ }
+
+ printf("%-8s ", reqstate); // fdtype
+ char policy_type;
+ switch (kqinfo.kqdi_pol) {
+ case POLICY_RR:
+ policy_type = 'R';
+ break;
+ case POLICY_FIFO:
+ policy_type = 'F';
+ case POLICY_TIMESHARE:
+ case 0:
+ default:
+ policy_type = '-';
+ break;
+ }
+ snprintf(tmpstr, 4, "%c%c%c", (kqinfo.kqdi_pri == 0)?'-':'P', policy_type, (kqinfo.kqdi_cpupercent == 0)?'-':'%');
+ printf("%-7s ", tmpstr); // fflags
+ printf("%-15s ", " "); // flags
+ printf("%-15s ", " "); // evst
+ }
+
+ if (!raw && kqinfo.kqdi_pri != 0) {
+ printf("%3d ", kqinfo.kqdi_pri); //qos
+ } else {
+ int qos = MAX(MAX(kqinfo.kqdi_events_qos, kqinfo.kqdi_async_qos),
+ kqinfo.kqdi_sync_waiter_qos);
+ printf("%3s ", thread_qos_name(qos)); //qos
+ }
+ printf("\n");
+ }
+ }
+
+ /*
+ * get extended kqueue info
+ */
+ struct kevent_extinfo *kqextinfo = NULL;
+ again:
+ if (!kqextinfo) {
+ kqextinfo = malloc(sizeof(struct kevent_extinfo) * maxknotes);
+ }
+ if (!kqextinfo) {
+ err = errno;
+ perror("failed allocating memory");
+ goto out;
+ }
+
+ errno = 0;
+ switch (type) {
+ case KQTYPE_FD:
+ nknotes = proc_pidfdinfo(pid, fd, PROC_PIDFDKQUEUE_EXTINFO,
+ kqextinfo, sizeof(struct kevent_extinfo) * maxknotes);
+ break;
+ case KQTYPE_DYNAMIC:
+ nknotes = proc_piddynkqueueinfo(pid, PROC_PIDDYNKQUEUE_EXTINFO, kqid,
+ kqextinfo, sizeof(struct kevent_extinfo) * maxknotes);
+ break;
+ default:
+ os_crash("invalid kqueue type");
+ }
+
+ if (nknotes <= 0) {
+ if (errno == 0) {
+ /* proc_*() can't distinguish between error and empty list */
+ } else if (errno == EAGAIN) {
+ goto again;
+ } else if (errno == EBADF) {
+ fprintf(stderr, "WARN: FD table changed (pid %i, kq %#" PRIx64 ")\n", pid, kqid);
+ goto out;
+ } else {
+ err = errno;
+ perror("failed to get extended kqueue info");
+ goto out;
+ }
+ }
+
+ if (nknotes > maxknotes) {
+ maxknotes = nknotes + 16; /* arbitrary safety margin */
+ free(kqextinfo);
+ kqextinfo = NULL;
+ goto again;
+ }
+
+ if (nknotes >= PROC_PIDFDKQUEUE_KNOTES_MAX) {
+ overflow = true;
+ }
+
+ kq_state = kqfdinfo.kqueueinfo.kq_state;
+ is_kev_64 = (kq_state & PROC_KQUEUE_64);
+ is_kev_qos = (kq_state & PROC_KQUEUE_QOS);
+
+ if (nknotes == 0) {
+ if (!ignore_empty && !dynkq_printed) {
+ /* for empty kqueues, print a single empty entry */
+ print_kq_info(pid, procname, kqid, kq_state);
+ printf("%18s \n", "-");
+ }
+ goto out;
+ }
+
+ for (i = 0; i < nknotes; i++) {
+ struct kevent_extinfo *info = &kqextinfo[i];
+
+ print_kq_info(pid, procname, kqid, kqfdinfo.kqueueinfo.kq_state);
+ print_ident(info->kqext_kev.ident, info->kqext_kev.filter, 18);
+ printf("%-9s ", filt_name(info->kqext_kev.filter));
+
+ if (raw) {
+ printf("%#10x ", info->kqext_sfflags);
+ printf("%#10x ", info->kqext_kev.flags);
+ printf("%#10x ", info->kqext_status);
+ } else {
+ /* for kevents attached to file descriptors, print the type of FD (file, socket, etc) */
+ const char *fdstr = "";
+ if (filter_is_fd_type(info->kqext_kev.filter)) {
+ fdstr = "<unkn>";
+ int knfd = fd_list_getfd(fdlist, nfds, (int)info->kqext_kev.ident);
+ if (knfd >= 0) {
+ fdstr = fdtype_str(fdlist[knfd].proc_fdtype);
+ }
+ }
+ printf("%-8s ", fdstr);
+
+ /* print filter flags */
+ printf("%7s ", fflags_build(info, tmpstr, sizeof(tmpstr)));
+
+ /* print generic flags */
+ unsigned flg = info->kqext_kev.flags;
+ printf("%c%c%c%c %c%c%c%c %c%c%c%c%c ",
+ (flg & EV_ADD) ? 'a' : '-',
+ (flg & EV_ENABLE) ? 'n' : '-',
+ (flg & EV_DISABLE) ? 'd' : '-',
+ (flg & EV_DELETE) ? 'x' : '-',
+
+ (flg & EV_RECEIPT) ? 'r' : '-',
+ (flg & EV_ONESHOT) ? '1' : '-',
+ (flg & EV_CLEAR) ? 'c' : '-',
+ (flg & EV_DISPATCH) ? 's' : '-',
+
+ (flg & EV_UDATA_SPECIFIC) ? 'u' : '-',
+ (flg & EV_FLAG0) ? 'p' : '-',
+ (flg & EV_FLAG1) ? 'b' : '-',
+ (flg & EV_EOF) ? 'o' : '-',
+ (flg & EV_ERROR) ? 'e' : '-'
+ );
+
+ unsigned st = info->kqext_status;
+ printf("%c%c%c%c%c %c%c%c%c %c%c%c ",
+ (st & KN_ACTIVE) ? 'a' : '-',
+ (st & KN_QUEUED) ? 'q' : '-',
+ (st & KN_DISABLED) ? 'd' : '-',
+ (st & KN_SUPPRESSED) ? 'p' : '-',
+ (st & KN_STAYACTIVE) ? 's' : '-',
+
+ (st & KN_DROPPING) ? 'd' : '-',
+ (st & KN_LOCKED) ? 'l' : '-',
+ (st & KN_POSTING) ? 'P' : '-',
+ (st & KN_MERGE_QOS) ? 'm' : '-',
+
+ (st & KN_DEFERDELETE) ? 'D' : '-',
+ (st & KN_REQVANISH) ? 'v' : '-',
+ (st & KN_VANISHED) ? 'n' : '-'
+ );
+ }
+
+ printf("%3s ", thread_qos_name(info->kqext_kev.qos));
+
+ printf("%#18llx ", (unsigned long long)info->kqext_kev.data);
+
+ if (verbose) {
+ printf("%#18llx ", (unsigned long long)info->kqext_kev.udata);
+ if (is_kev_qos || is_kev_64) {
+ printf("%#18llx ", (unsigned long long)info->kqext_kev.ext[0]);
+ printf("%#18llx ", (unsigned long long)info->kqext_kev.ext[1]);
+
+ if (is_kev_qos) {
+ printf("%#18llx ", (unsigned long long)info->kqext_kev.ext[2]);
+ printf("%#18llx ", (unsigned long long)info->kqext_kev.ext[3]);
+ printf("%#10lx ", (unsigned long)info->kqext_kev.xflags);
+ }
+ }
+ }
+
+ printf("\n");
+ }
+
+ if (overflow) {
+ printf(" ***** output truncated (>=%i knotes on kq %" PRIu64 ", proc %i) *****\n",
+ nknotes, kqid, pid);
+ }
+
+ out:
+ if (kqextinfo) {
+ free(kqextinfo);
+ kqextinfo = NULL;
+ }
+
+ return err;
+}
+
+static int
+pid_kqids(pid_t pid, kqueue_id_t **kqids_out)
+{
+ static int kqids_len = 256;
+ static kqueue_id_t *kqids = NULL;
+ static uint32_t kqids_size;
+
+ int nkqids;
+
+retry:
+ if (os_mul_overflow(sizeof(kqueue_id_t), kqids_len, &kqids_size)) {
+ assert(kqids_len > PROC_PIDDYNKQUEUES_MAX);
+ kqids_len = PROC_PIDDYNKQUEUES_MAX;
+ goto retry;
+ }
+ if (!kqids) {
+ kqids = malloc(kqids_size);
+ os_assert(kqids != NULL);
+ }
+
+ nkqids = proc_list_dynkqueueids(pid, kqids, kqids_size);
+ if (nkqids > kqids_len && kqids_len < PROC_PIDDYNKQUEUES_MAX) {
+ kqids_len *= 2;
+ if (kqids_len > PROC_PIDDYNKQUEUES_MAX) {
+ kqids_len = PROC_PIDDYNKQUEUES_MAX;
+ }
+ free(kqids);
+ kqids = NULL;
+ goto retry;
+ }
+
+ *kqids_out = kqids;
+ return MIN(nkqids, kqids_len);
+}
+
+static int
+process_pid(pid_t pid)
+{
+ int i, nfds, nkqids;
+ kqueue_id_t *kqids;
+ int ret = 0;
+ int maxfds = 256; /* arbitrary starting point */
+ struct proc_fdinfo *fdlist = NULL;
+
+ /* enumerate file descriptors */
+ again:
+ if (!fdlist) {
+ fdlist = malloc(sizeof(struct proc_fdinfo) * maxfds);
+ }
+ if (!fdlist) {
+ ret = errno;
+ perror("failed to allocate");
+ goto out;
+ }
+
+ nfds = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdlist,
+ sizeof(struct proc_fdinfo) * maxfds);
+ if (nfds <= 0) {
+ ret = errno;
+ fprintf(stderr, "%s: failed enumerating file descriptors of process %i: %s",
+ self, pid, strerror(ret));
+ if (ret == EPERM && geteuid() != 0) {
+ fprintf(stderr, " (are you root?)");
+ }
+ fprintf(stderr, "\n");
+ goto out;
+ }
+
+ nfds /= sizeof(struct proc_fdinfo);
+ if (nfds >= maxfds) {
+ maxfds = nfds + 16;
+ free(fdlist);
+ fdlist = NULL;
+ goto again;
+ }
+
+ /* get bsdinfo for the process name */
+ struct proc_bsdinfo bsdinfo;
+ ret = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &bsdinfo, sizeof(bsdinfo));
+ if (ret != sizeof(bsdinfo)) {
+ perror("failed retrieving process info");
+ ret = -1;
+ goto out;
+ }
+
+ char *procname = bsdinfo.pbi_name;
+ if (strlen(procname) == 0) {
+ procname = bsdinfo.pbi_comm;
+ }
+
+ /* handle the special workq kq */
+ ret = process_kqueue(pid, procname, KQTYPE_FD, -1, fdlist, nfds);
+ if (ret) {
+ goto out;
+ }
+
+ for (i = 0; i < nfds; i++) {
+ if (fdlist[i].proc_fdtype == PROX_FDTYPE_KQUEUE) {
+ ret = process_kqueue(pid, procname, KQTYPE_FD,
+ (uint64_t)fdlist[i].proc_fd, fdlist, nfds);
+ if (ret) {
+ goto out;
+ }
+ }
+ }
+
+ nkqids = pid_kqids(pid, &kqids);
+
+ for (i = 0; i < nkqids; i++) {
+ ret = process_kqueue(pid, procname, KQTYPE_DYNAMIC, kqids[i], fdlist, nfds);
+ if (ret) {
+ goto out;
+ }
+ }
+
+ if (nkqids >= PROC_PIDDYNKQUEUES_MAX) {
+ printf(" ***** output truncated (>=%i dynamic kqueues in proc %i) *****\n",
+ nkqids, pid);
+ }
+
+ out:
+ if (fdlist) {
+ free(fdlist);
+ fdlist = NULL;
+ }
+
+ return ret;
+}
+
+static int
+process_all_pids(void)
+{
+ int i, npids;
+ int ret = 0;
+ int maxpids = 2048;
+ int *pids = NULL;
+
+ again:
+ if (!pids) {
+ pids = malloc(sizeof(int) * maxpids);
+ }
+ if (!pids) {
+ perror("failed allocating pids[]");
+ goto out;
+ }
+
+ errno = 0;
+ npids = proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(int) * maxpids);
+ if (npids <= 0) {
+ if (errno == 0) {
+ /* empty pid list */
+ } else if (errno == EAGAIN) {
+ goto again;
+ } else {
+ ret = errno;
+ perror("failed enumerating pids");
+ goto out;
+ }
+ }
+
+ npids /= sizeof(int);
+ if (npids >= maxpids) {
+ maxpids = npids + 16;
+ free(pids);
+ pids = NULL;
+ goto again;
+ }
+
+ for (i = 0; i < npids; i++) {
+ /* listpids gives us pid 0 for some reason */
+ if (pids[i]) {
+ ret = process_pid(pids[i]);
+ /* ignore races with processes exiting */
+ if (ret && ret != ESRCH) {
+ goto out;
+ }
+ }
+ }
+
+out:
+ if (pids) {
+ free(pids);
+ pids = NULL;
+ }
+
+ return ret;
+}
+
+static void
+cheatsheet(void)
+{
+ const char *bold = "\033[1m";
+ const char *reset = "\033[0m";
+ if (!isatty(STDERR_FILENO)) {
+ bold = reset = "";
+ }
+
+ fprintf(stderr, "\nFilter-independent flags:\n\n\
+%s\
+command pid kq kqst knid filter fdtype fflags flags evst qos%s\n%s\
+-------------------- ----- ------------------ ---- ------------------ --------- -------- ------- --------------- -------------- ---%s\n\
+ ┌ EV_UDATA_SPECIFIC\n\
+ EV_DISPATCH ┠│┌ EV_FLAG0 (EV_POLL)\n\
+ EV_CLEAR â”│ ││┌ EV_FLAG1 (EV_OOBAND)\n\
+ EV_ONESHOT â”││ │││┌ EV_EOF\n\
+ EV_RECEIPT â”│││ ││││┌ EV_ERROR\n\
+ ││││ │││││\n%s\
+launchd 1 4 ks- netbiosd 250 PROC ------- andx r1cs upboe aqdps dlPm Dvn IN%s\n\
+ │ │││ ││││ │││││ ││││ │││\n\
+ kqueue file descriptor/dynamic ID ┘ │││ EV_ADD ┘│││ KN_ACTIVE ┘││││ ││││ ││└ KN_VANISHED\n\
+ KQ_SLEEP ┘││ EV_ENABLE ┘││ KN_QUEUED ┘│││ ││││ │└ KN_REQVANISH\n\
+ KQ_SEL ┘│ EV_DISABLE ┘│ KN_DISABLED ┘││ ││││ └ KN_DEFERDELETE\n\
+ KQ_WORKQ (q) ┤ EV_DELETE ┘ KN_SUPPRESSED ┘│ ││││\n\
+ KQ_WORKLOOP (l) ┘ KN_STAYACTIVE ┘ ││││\n\
+ ││││\n\
+ KN_DROPPING ┘││└ KN_MERGE_QOS\n\
+ KN_LOCKED ┘└ KN_POSTING\n\
+ \n", bold, reset, bold, reset, bold, reset);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-vher] [-a | -p <pid>]\n", self);
+}
+
+static void
+print_header(void)
+{
+ if (raw) {
+ printf(" pid kq kqst knid filter fflags flags evst qos data");
+ } else {
+ printf("command pid kq kqst knid filter fdtype fflags flags evst qos data");
+ }
+
+ if (verbose) {
+ printf(" udata ext0 ext1 ext2 ext3 xflags");
+ }
+
+ printf("\n");
+
+ if (raw) {
+ printf("----- ------------------ ---------- ------------------ --------- ---------- ---------- ---------- --- ------------------");
+ } else {
+ printf("-------------------- ----- ------------------ ---- ------------------ --------- -------- ------- --------------- -------------- --- ------------------");
+ }
+
+ if (verbose) {
+ printf(" ------------------ ------------------ ------------------ ------------------ ------------------ ----------");
+ }
+ printf("\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ pid_t pid = 0;
+ int opt;
+
+ setlinebuf(stdout);
+
+ if (argc > 0) {
+ self = argv[0];
+ }
+
+ while ((opt = getopt(argc, argv, "eahvrp:")) != -1) {
+ switch (opt) {
+ case 'a':
+ all_pids = 1;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'e':
+ ignore_empty = 1;
+ break;
+ case 'h':
+ usage();
+ cheatsheet();
+ return 0;
+ case 'r':
+ raw = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ return 1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 1) {
+ /* also allow lskq <pid> */
+ if (pid || all_pids) {
+ usage();
+ return 1;
+ }
+
+ pid = atoi(argv[0]);
+ } else if (argc > 1) {
+ usage();
+ return 1;
+ }
+
+ /* exactly one of -p or -a is required */
+ if (!pid && !all_pids) {
+ usage();
+ return 1;
+ } else if (pid && all_pids) {
+ usage();
+ return 1;
+ }
+
+ print_header();
+
+ if (all_pids) {
+ return process_all_pids();
+ } else {
+ return process_pid(pid);
+ }
+
+ return 0;
+}
diff --git a/system_cmds/lsmp.tproj/common.h b/system_cmds/lsmp.tproj/common.h
new file mode 100644
index 0000000..9a47012
--- /dev/null
+++ b/system_cmds/lsmp.tproj/common.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef system_cmds_common_h
+#define system_cmds_common_h
+
+#include <mach/mach.h>
+#include "json.h"
+
+#define PROC_NAME_LEN 100
+#define BUFSTR_LEN 30
+#define VOUCHER_DETAIL_MAXLEN 1024
+
+/* common struct to hold all configurations, static and args based */
+struct prog_configs {
+ boolean_t show_all_tasks;
+ boolean_t show_voucher_details;
+ boolean_t verbose;
+ int voucher_detail_length;
+ pid_t pid; /* if user focusing only one pid */
+ JSON_t json_output;
+};
+
+extern struct prog_configs lsmp_config;
+
+/* exception port information */
+struct exc_port_info {
+ mach_msg_type_number_t count;
+ mach_port_t ports[EXC_TYPES_COUNT];
+ exception_mask_t masks[EXC_TYPES_COUNT];
+ exception_behavior_t behaviors[EXC_TYPES_COUNT];
+ thread_state_flavor_t flavors[EXC_TYPES_COUNT];
+};
+
+/* private structure to hold thread specific information */
+struct my_per_thread_info {
+ mach_port_t thread;
+ uint32_t th_kobject;
+ uint64_t th_id;
+ char * voucher_detail;
+};
+
+/* kobject to name hash table declarations */
+#define K2N_TABLE_SIZE 256
+
+struct k2n_table_node {
+ natural_t kobject; /* kobject referred to by the name -- the key into the table */
+ ipc_info_name_t *info_name; /* info about the name that refers to the key kobject -- value of the table */
+ struct k2n_table_node *next;
+};
+
+struct k2n_table_node *k2n_table_lookup_next(struct k2n_table_node *node, natural_t kobject);
+struct k2n_table_node *k2n_table_lookup(struct k2n_table_node **table, natural_t kobject);
+
+/* private structure to wrap up per-task info */
+typedef struct my_per_task_info {
+ task_t task;
+ pid_t pid;
+ vm_address_t task_kobject;
+ ipc_info_space_t info;
+ ipc_info_name_array_t table;
+ mach_msg_type_number_t tableCount;
+ ipc_info_tree_name_array_t tree;
+ mach_msg_type_number_t treeCount;
+ boolean_t valid; /* TRUE if all data is accurately collected */
+ struct k2n_table_node *k2ntable[K2N_TABLE_SIZE];
+ char processName[PROC_NAME_LEN];
+ struct exc_port_info exceptionInfo;
+ struct my_per_thread_info * threadInfos; /* dynamically allocated in collect_per_task_info */
+ unsigned int threadCount;
+ struct exc_port_info *threadExceptionInfos; /* this is 2 dimensional array with threadCount X struct exc_port_info of ports */
+} my_per_task_info_t;
+
+
+/*
+ * WARNING - these types are copied from xnu/osfmk/kern/ipc_kobject.h
+ * Need to stay in sync to print accurate results.
+ */
+#define IKOT_NONE 0
+#define IKOT_THREAD_CONTROL 1
+#define IKOT_TASK_CONTROL 2
+#define IKOT_HOST 3
+#define IKOT_HOST_PRIV 4
+#define IKOT_PROCESSOR 5
+#define IKOT_PSET 6
+#define IKOT_PSET_NAME 7
+#define IKOT_TIMER 8
+#define IKOT_PAGING_REQUEST 9
+#define IKOT_MIG 10
+#define IKOT_MEMORY_OBJECT 11
+#define IKOT_XMM_PAGER 12
+#define IKOT_XMM_KERNEL 13
+#define IKOT_XMM_REPLY 14
+#define IKOT_UND_REPLY 15
+#define IKOT_HOST_NOTIFY 16
+#define IKOT_HOST_SECURITY 17
+#define IKOT_LEDGER 18
+#define IKOT_MASTER_DEVICE 19
+#define IKOT_TASK_NAME 20
+#define IKOT_SUBSYSTEM 21
+#define IKOT_IO_DONE_QUEUE 22
+#define IKOT_SEMAPHORE 23
+#define IKOT_LOCK_SET 24
+#define IKOT_CLOCK 25
+#define IKOT_CLOCK_CTRL 26
+#define IKOT_IOKIT_IDENT 27
+#define IKOT_NAMED_ENTRY 28
+#define IKOT_IOKIT_CONNECT 29
+#define IKOT_IOKIT_OBJECT 30
+#define IKOT_UPL 31
+#define IKOT_MEM_OBJ_CONTROL 32
+#define IKOT_AU_SESSIONPORT 33
+#define IKOT_FILEPORT 34
+#define IKOT_LABELH 35
+#define IKOT_TASK_RESUME 36
+#define IKOT_VOUCHER 37
+#define IKOT_VOUCHER_ATTR_CONTROL 38
+#define IKOT_WORK_INTERVAL 39
+#define IKOT_UX_HANDLER 40
+#define IKOT_UEXT_OBJECT 41
+#define IKOT_ARCADE_REG 42
+#define IKOT_EVENTLINK 43
+#define IKOT_TASK_INSPECT 44
+#define IKOT_TASK_READ 45
+#define IKOT_THREAD_INSPECT 46
+#define IKOT_THREAD_READ 47
+#define IKOT_SUID_CRED 48
+#define IKOT_HYPERVISOR 49
+
+#define IKOT_UNKNOWN 50 /* magic catchall */
+#define IKOT_MAX_TYPE (IKOT_UNKNOWN+1) /* # of IKOT_ types */
+
+
+#define PORT_FLAG_TO_INDEX(flag) ( __builtin_ctz(flag) ) /* count trailing zeros */
+#define INDEX_TO_PORT_FLAG(idx) ( 1 << idx )
+typedef struct port_status_flag_info {
+ natural_t flag; /* MACH_PORT_STATUS_FLAG_* */
+ const char *compact_name; /* Single character name for compact representation */
+ const char *name; /* human readable long name */
+} port_status_flag_info_t;
+
+/*
+ * list of names for possible MACH_PORT_STATUS_FLAG_*
+ * indexed by PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_*)
+ */
+extern const port_status_flag_info_t port_status_flags[];
+
+#define _SHOW_PORT_STATUS_FLAG(flags, flag) \
+ (flags & flag) ? port_status_flags[PORT_FLAG_TO_INDEX(flag)].compact_name : "-"
+#define SHOW_PORT_STATUS_FLAGS(flags) \
+ _SHOW_PORT_STATUS_FLAG(flags, MACH_PORT_STATUS_FLAG_TEMPOWNER), \
+ _SHOW_PORT_STATUS_FLAG(flags, MACH_PORT_STATUS_FLAG_GUARDED), \
+ _SHOW_PORT_STATUS_FLAG(flags, MACH_PORT_STATUS_FLAG_STRICT_GUARD), \
+ _SHOW_PORT_STATUS_FLAG(flags, MACH_PORT_STATUS_FLAG_IMP_DONATION), \
+ _SHOW_PORT_STATUS_FLAG(flags, MACH_PORT_STATUS_FLAG_REVIVE), \
+ _SHOW_PORT_STATUS_FLAG(flags, MACH_PORT_STATUS_FLAG_TASKPTR)
+
+
+uint32_t show_recipe_detail(mach_voucher_attr_recipe_t recipe, char * voucher_outstr, uint32_t maxlen, JSON_t json);
+char *copy_voucher_detail(mach_port_t task, mach_port_name_t voucher, JSON_t json);
+
+/* mach port related functions */
+const char * kobject_name(natural_t kotype);
+void get_receive_port_context(task_t taskp, mach_port_name_t portname, mach_port_context_t *context);
+int get_recieve_port_status(task_t taskp, mach_port_name_t portname, mach_port_info_ext_t *info);
+void show_task_mach_ports(my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos, JSON_t json);
+
+/* task and thread related helper functions */
+kern_return_t collect_per_task_info(my_per_task_info_t *taskinfo, task_t target_task);
+my_per_task_info_t * allocate_taskinfo_memory(uint32_t taskCount);
+void deallocate_taskinfo_memory(my_per_task_info_t *data);
+kern_return_t print_task_exception_info(my_per_task_info_t *taskinfo, JSON_t json);
+kern_return_t print_task_threads_special_ports(my_per_task_info_t *taskinfo, JSON_t json);
+my_per_task_info_t * get_taskinfo_by_kobject(natural_t kobj);
+
+void get_exc_behavior_string(exception_behavior_t b, char *out_string, size_t len);
+void get_exc_mask_string(exception_mask_t m, char *out_string, size_t len);
+kern_return_t get_taskinfo_of_receiver_by_send_right(ipc_info_name_t *sendright, my_per_task_info_t **out_taskinfo, mach_port_name_t *out_recv_info);
+kern_return_t get_ipc_info_from_lsmp_spaceinfo(mach_port_t port_name, ipc_info_name_t *out_sendright);
+
+/* basic util functions */
+uint32_t print_hex_data(char *outstr, uint32_t maxlen, char *prefix, char *desc, void *addr, int len);
+
+#endif
diff --git a/system_cmds/lsmp.tproj/entitlements.plist b/system_cmds/lsmp.tproj/entitlements.plist
new file mode 100644
index 0000000..b7b4e6c
--- /dev/null
+++ b/system_cmds/lsmp.tproj/entitlements.plist
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>task_for_pid-allow</key>
+ <true/>
+ <key>com.apple.system-task-ports</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/lsmp.tproj/json.h b/system_cmds/lsmp.tproj/json.h
new file mode 100644
index 0000000..2a87a8b
--- /dev/null
+++ b/system_cmds/lsmp.tproj/json.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Provides a stream-based API for generating JSON output
+ *
+ * Handles tedious tasks like worrying about comma placement (and avoiding trailing commas).
+ * Assumes strings are already escaped (if necessary) and does no error checking (thus it
+ * may produce invalid JSON when used improperly).
+ *
+ * As a convenience, when the provided `json` stream is NULL (i.e. it was never initialized
+ * by `JSON_OPEN`) these APIs will do nothing.
+ *
+ * Example usage:
+ *
+ * JSON_t json = JSON_OPEN("/path/to/output.json")
+ * JSON_OBJECT_BEGIN(json); // root object
+ *
+ * JSON_OBJECT_SET(json, version, %.1f, 1.0);
+ * JSON_OBJECT_SET_BOOL(json, has_fruit, 1);
+ *
+ * // Note the required quotes for strings (formatted or not)
+ * char *mystr = "hello";
+ * JSON_OBJECT_SET(json, formatted_string, "%s", mystr);
+ * JSON_OBJECT_SET(json, literal_string, "my literal string");
+ *
+ * JSON_KEY(json, fruit_array);
+ * JSON_ARRAY_BEGIN(json); // fruit_array
+ * JSON_ARRAY_APPEND(json, "my literal string");
+ * JSON_ARRAY_APPEND(json, "<0x%08llx>", 0xface);
+ * JSON_ARRAY_APPEND(json, %d, 3);
+ * JSON_ARRAY_END(json); // fruit_array
+ *
+ * JSON_OBJECT_END(json); // root object
+ * JSON_CLOSE(json);
+ */
+
+#ifndef _JSON_H_
+#define _JSON_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#define _JSON_IF(json, code) \
+ if (json != NULL) { \
+ code; \
+ }
+#define _JSON_COMMA(json) \
+ if (json->require_comma) { \
+ fprintf(json->stream, ","); \
+ }
+
+struct _JSON {
+ FILE* stream;
+ bool require_comma;
+};
+typedef struct _JSON * JSON_t;
+
+#pragma mark Open/Close
+/* Return a new JSON_t stream */
+static inline JSON_t JSON_OPEN(const char *path) {
+ JSON_t p = malloc(sizeof(struct _JSON));
+ p->stream = fopen(path, "w+");
+ p->require_comma = false;
+ return p;
+}
+
+/* Close an existing JSON stream, removing trailing commas */
+#define JSON_CLOSE(json) _JSON_IF(json, fclose(json->stream); free(json))
+
+#pragma mark Keys/Values
+/* Output the `key` half of a key/value pair */
+#define JSON_KEY(json, key) _JSON_IF(json, _JSON_COMMA(json); fprintf(json->stream, "\"" #key "\":"); json->require_comma = false)
+/* Output the `value` half of a key/value pair */
+#define JSON_VALUE(json, format, ...) _JSON_IF(json, fprintf(json->stream, #format, ##__VA_ARGS__); json->require_comma = true)
+
+#define _JSON_BEGIN(json, character) _JSON_COMMA(json); fprintf(json->stream, #character); json->require_comma = false;
+#define _JSON_END(json, character) fprintf(json->stream, #character); json->require_comma = true;
+#define _JSON_BOOL(val) ( val ? "true" : "false" )
+
+#pragma mark Objects
+/* Start a new JSON object */
+#define JSON_OBJECT_BEGIN(json) _JSON_IF(json, _JSON_BEGIN(json, {))
+/* Set a value in the current JSON object */
+#define JSON_OBJECT_SET(json, key, format, ...) _JSON_IF(json, JSON_KEY(json, key); JSON_VALUE(json, format, ##__VA_ARGS__))
+/* Set a boolean in the current JSON object */
+#define JSON_OBJECT_SET_BOOL(json, key, value) JSON_OBJECT_SET(json, key, %s, _JSON_BOOL(value))
+/* End the current JSON object */
+#define JSON_OBJECT_END(json) _JSON_IF(json, _JSON_END(json, }))
+
+#pragma mark Arrays
+/* Start a new JSON array */
+#define JSON_ARRAY_BEGIN(json) _JSON_IF(json, _JSON_BEGIN(json, [))
+/* Append a value to the current JSON array */
+#define JSON_ARRAY_APPEND(json, format, ...) _JSON_IF(json, _JSON_COMMA(json); JSON_VALUE(json, format, ##__VA_ARGS__))
+/* End the current JSON array */
+#define JSON_ARRAY_END(json) _JSON_IF(json, _JSON_END(json, ]))
+
+#endif /* _JSON_H_ */
diff --git a/system_cmds/lsmp.tproj/lsmp.1 b/system_cmds/lsmp.tproj/lsmp.1
new file mode 100644
index 0000000..d4c70e9
--- /dev/null
+++ b/system_cmds/lsmp.tproj/lsmp.1
@@ -0,0 +1,61 @@
+.\" Copyright (c) 2012, Apple Inc. All rights reserved.
+.\"
+.Dd Jul 24, 2012
+.Dt LSMP 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm lsmp
+.Nd Display mach port information for processes on the system
+.Sh SYNOPSIS
+.Nm lsmp
+.Fl h
+.Pp
+.Nm lsmp
+.Ar -p <pid>
+Show mach port usage for <pid>. Run with root privileges to see detailed info about port destinations etc.
+.Pp
+.Nm lsmp
+.Ar -v
+Show information in detail for Kernel object based ports. Including thread ports and special ports attached to it.
+.Pp
+.Nm lsmp
+.Ar -a
+Show mach port usage for all tasks in the system
+.Pp
+.Nm lsmp
+.Ar -j <path>
+Save output as JSON to <path>.
+.Sh DESCRIPTION
+The
+.Nm lsmp
+ command prints information about every active right in a task's port space, giving a view into the inter-process communication behavior of that task.
+.P
+.nf
+Following is an explanation of each symbol and values from the output.
+name : Task unique name for a port. A "-" signifies that this is a member of a port-set
+ipc-object : A unique identifier for a kernel object. A "+" sign implies that this entry is expanded from above ipc-object.
+rights : Rights corresponding to this name. Possible values are recv, send, send-once and port-set.
+flags : Flags indicating port status.
+ T : Port has tempowner set
+ G : Port is guarded
+ S : Port has strict guarding restrictions
+ I : Port has importance donation flag set
+ R : Port is marked reviving
+ P : Port has task pointer set
+boost : Importance boost count
+reqs : Notifications armed on this port.
+ D : Dead name notification
+ N : No sender notification
+ P : Port Destroy requests
+recv : Number of recv rights for this name.
+send : Number of send rights stored at this name. This does NOT reflect the total number of send rights for this recv right.
+sonce : Number of outstanding send-once rights for this receive right.
+oref : Do send rights exist somewhere for this receive right?
+qlimit : Queue limit for this port. If orefs column shows -> then it indicates the queue limit on the destination port. And a <- indicates this port right is destined to receive messages from process referred in identifier column.
+msgcount : Number of messages enqueued on this port. See qlimit for -> and <- explanations.
+context : Mach port context value.
+identifier : A unique identifier for a kernel object or task's name for this right. This field is described by the type column.
+.fi
+.Sh SEE ALSO
+.Xr ddt 1
+.Xr top 1
diff --git a/system_cmds/lsmp.tproj/lsmp.c b/system_cmds/lsmp.tproj/lsmp.c
new file mode 100644
index 0000000..71a7c68
--- /dev/null
+++ b/system_cmds/lsmp.tproj/lsmp.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach_debug/ipc_info.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <libproc.h>
+#include <TargetConditionals.h>
+#include <errno.h>
+#include "common.h"
+#include "json.h"
+
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#define TASK_FOR_PID_USAGE_MESG "\nPlease check your boot-args to ensure you have access to task_for_pid()."
+#else
+#define TASK_FOR_PID_USAGE_MESG ""
+#endif
+
+struct prog_configs lsmp_config = {
+ .show_all_tasks = FALSE,
+ .show_voucher_details = FALSE,
+ .verbose = FALSE,
+ .pid = 0,
+ .json_output = NULL,
+};
+
+static void print_usage(char *progname) {
+ fprintf(stderr, "Usage: %s -p <pid> [-a|-v|-h] \n", "lsmp");
+ fprintf(stderr, "Lists information about mach ports. Please see man page for description of each column.\n");
+ fprintf(stderr, "\t-p <pid> : print all mach ports for process id <pid>. \n");
+ fprintf(stderr, "\t-a : print all mach ports for all processeses. \n");
+ fprintf(stderr, "\t-v : print verbose details for kernel objects.\n");
+ fprintf(stderr, "\t-j <path> : save output as JSON to <path>.\n");
+ fprintf(stderr, "\t-h : print this help.\n");
+ exit(1);
+}
+
+static void print_task_info(my_per_task_info_t *taskinfo, mach_msg_type_number_t taskCount, my_per_task_info_t *psettaskinfo, boolean_t verbose, JSON_t json) {
+ printf("Process (%d) : %s\n", taskinfo->pid, taskinfo->processName);
+ JSON_OBJECT_BEGIN(json);
+ JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
+ JSON_OBJECT_SET(json, name, "%s", taskinfo->processName);
+ show_task_mach_ports(taskinfo, taskCount, psettaskinfo, json);
+ print_task_exception_info(taskinfo, json);
+ if (verbose) {
+ printf("\n");
+ print_task_threads_special_ports(taskinfo, json);
+ }
+ JSON_OBJECT_END(json);
+}
+
+int main(int argc, char *argv[]) {
+ kern_return_t ret;
+ task_t aTask;
+ my_per_task_info_t *taskinfo = NULL;
+ task_array_t tasks;
+ char *progname = "lsmp";
+ int i, option = 0;
+ lsmp_config.voucher_detail_length = 128; /* default values for config */
+ my_per_task_info_t *psettaskinfo;
+ mach_msg_type_number_t taskCount;
+
+ while((option = getopt(argc, argv, "hvalp:j:")) != -1) {
+ switch(option) {
+ case 'a':
+ /* user asked for info on all processes */
+ lsmp_config.pid = 0;
+ lsmp_config.show_all_tasks = 1;
+ break;
+
+ case 'l':
+ /* for compatibility with sysdiagnose's usage of -all */
+ lsmp_config.voucher_detail_length = 1024;
+ /* Fall through to 'v' */
+
+ case 'v':
+ lsmp_config.show_voucher_details = TRUE;
+ lsmp_config.verbose = TRUE;
+ break;
+
+ case 'p':
+ lsmp_config.pid = atoi(optarg);
+ if (lsmp_config.pid == 0) {
+ fprintf(stderr, "Unknown pid: %s\n", optarg);
+ exit(1);
+ }
+ break;
+
+ case 'j':
+ lsmp_config.json_output = JSON_OPEN(optarg);
+ if (lsmp_config.json_output == NULL) {
+ fprintf(stderr, "Unable to open \"%s\": %s\n", optarg, strerror(errno));
+ exit(1);
+ }
+ break;
+
+ default:
+ fprintf(stderr, "Unknown argument. \n");
+ /* Fall through to 'h' */
+
+ case 'h':
+ print_usage(progname);
+ break;
+
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* if privileged, get the info for all tasks so we can match ports up */
+ if (geteuid() == 0) {
+ processor_set_name_array_t psets;
+ mach_msg_type_number_t psetCount;
+ mach_port_t pset_priv;
+
+ ret = host_processor_sets(mach_host_self(), &psets, &psetCount);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret));
+ exit(1);
+ }
+ if (psetCount != 1) {
+ fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount);
+ exit(1);
+ }
+
+ /* convert the processor-set-name port to a privileged port */
+ ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "host_processor_set_priv() failed: %s\n", mach_error_string(ret));
+ exit(1);
+ }
+ mach_port_deallocate(mach_task_self(), psets[0]);
+ vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t));
+
+ /* convert the processor-set-priv to a list of tasks for the processor set */
+ ret = processor_set_tasks(pset_priv, &tasks, &taskCount);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "processor_set_tasks() failed: %s\n", mach_error_string(ret));
+ exit(1);
+ }
+ mach_port_deallocate(mach_task_self(), pset_priv);
+
+ /* swap my current instances port to be last to collect all threads and exception port info */
+ int myTaskPosition = -1;
+ for (int i = 0; i < taskCount; i++) {
+ if (tasks[i] == mach_task_self()){
+ myTaskPosition = i;
+ break;
+ }
+ }
+ if (myTaskPosition >= 0) {
+ mach_port_t swap_holder = MACH_PORT_NULL;
+ swap_holder = tasks[taskCount - 1];
+ tasks[taskCount - 1] = tasks[myTaskPosition];
+ tasks[myTaskPosition] = swap_holder;
+ }
+
+ }
+ else
+ {
+ fprintf(stderr, "warning: should run as root for best output (cross-ref to other tasks' ports).\n");
+ /* just the one process */
+ ret = task_for_pid(mach_task_self(), lsmp_config.pid, &aTask);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "task_for_pid() failed: %s %s\n", mach_error_string(ret), TASK_FOR_PID_USAGE_MESG);
+ exit(1);
+ }
+ taskCount = 1;
+ tasks = &aTask;
+ }
+
+ /* convert each task to structure of pointer for the task info */
+ psettaskinfo = allocate_taskinfo_memory(taskCount);
+
+ for (i = 0; i < taskCount; i++) {
+ ret = collect_per_task_info(&psettaskinfo[i], tasks[i]);
+ if (ret != KERN_SUCCESS) {
+ printf("Ignoring failure of mach_port_space_info() for task %d for '-all'\n", tasks[i]);
+ continue;
+ }
+
+ if (psettaskinfo[i].pid == lsmp_config.pid)
+ taskinfo = &psettaskinfo[i];
+ }
+
+ JSON_OBJECT_BEGIN(lsmp_config.json_output);
+ JSON_OBJECT_SET(lsmp_config.json_output, version, "%.1f", 1.0);
+ JSON_KEY(lsmp_config.json_output, processes);
+ JSON_ARRAY_BEGIN(lsmp_config.json_output);
+
+ if (lsmp_config.show_all_tasks == FALSE) {
+ if (taskinfo == NULL) {
+ fprintf(stderr, "Failed to find task ipc information for pid %d\n", lsmp_config.pid);
+ exit(1);
+ }
+ print_task_info(taskinfo, taskCount, psettaskinfo, TRUE, lsmp_config.json_output);
+ } else {
+ for (i=0; i < taskCount; i++) {
+ if (psettaskinfo[i].valid != TRUE)
+ continue;
+ print_task_info(&psettaskinfo[i], taskCount, psettaskinfo, lsmp_config.verbose, lsmp_config.json_output);
+ printf("\n\n");
+ }
+ }
+
+ JSON_ARRAY_END(lsmp_config.json_output);
+ JSON_OBJECT_END(lsmp_config.json_output);
+
+ if (taskCount > 1) {
+ vm_deallocate(mach_task_self(), (vm_address_t)tasks, (vm_size_t)taskCount * sizeof(mach_port_t));
+ }
+
+ deallocate_taskinfo_memory(psettaskinfo);
+
+ JSON_CLOSE(lsmp_config.json_output);
+
+ return(0);
+}
diff --git a/system_cmds/lsmp.tproj/port_details.c b/system_cmds/lsmp.tproj/port_details.c
new file mode 100644
index 0000000..fb888e4
--- /dev/null
+++ b/system_cmds/lsmp.tproj/port_details.c
@@ -0,0 +1,746 @@
+/*
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libproc.h>
+#include <assert.h>
+#include <mach/mach.h>
+//#include <mach/mach_port.h.h>
+#include <mach/mach_voucher.h>
+#include "common.h"
+#include "json.h"
+
+const char * kobject_name(natural_t kotype)
+{
+ switch (kotype) {
+ case IKOT_NONE: return "message-queue";
+ case IKOT_THREAD_CONTROL: return "THREAD-CONTROL";
+ case IKOT_TASK_CONTROL: return "TASK-CONTROL";
+ case IKOT_HOST: return "HOST";
+ case IKOT_HOST_PRIV: return "HOST-PRIV";
+ case IKOT_PROCESSOR: return "PROCESSOR";
+ case IKOT_PSET: return "PROCESSOR-SET";
+ case IKOT_PSET_NAME: return "PROCESSOR-SET-NAME";
+ case IKOT_TIMER: return "TIMER";
+ case IKOT_PAGING_REQUEST: return "PAGER-REQUEST";
+ case IKOT_MIG: return "MIG";
+ case IKOT_MEMORY_OBJECT: return "MEMORY-OBJECT";
+ case IKOT_XMM_PAGER: return "XMM-PAGER";
+ case IKOT_XMM_KERNEL: return "XMM-KERNEL";
+ case IKOT_XMM_REPLY: return "XMM-REPLY";
+ case IKOT_UND_REPLY: return "UND-REPLY";
+ case IKOT_HOST_NOTIFY: return "message-queue";
+ case IKOT_HOST_SECURITY: return "HOST-SECURITY";
+ case IKOT_LEDGER: return "LEDGER";
+ case IKOT_MASTER_DEVICE: return "MASTER-DEVICE";
+ case IKOT_TASK_NAME: return "TASK-NAME";
+ case IKOT_SUBSYSTEM: return "SUBSYSTEM";
+ case IKOT_IO_DONE_QUEUE: return "IO-QUEUE-DONE";
+ case IKOT_SEMAPHORE: return "SEMAPHORE";
+ case IKOT_LOCK_SET: return "LOCK-SET";
+ case IKOT_CLOCK: return "CLOCK";
+ case IKOT_CLOCK_CTRL: return "CLOCK-CONTROL";
+ case IKOT_IOKIT_IDENT: return "IOKIT-IDENT";
+ case IKOT_NAMED_ENTRY: return "NAMED-MEMORY";
+ case IKOT_IOKIT_CONNECT: return "IOKIT-CONNECT";
+ case IKOT_IOKIT_OBJECT: return "IOKIT-OBJECT";
+ case IKOT_UPL: return "UPL";
+ case IKOT_MEM_OBJ_CONTROL: return "XMM-CONTROL";
+ case IKOT_AU_SESSIONPORT: return "SESSIONPORT";
+ case IKOT_FILEPORT: return "FILEPORT";
+ case IKOT_LABELH: return "MACF-LABEL";
+ case IKOT_TASK_RESUME: return "TASK_RESUME";
+ case IKOT_VOUCHER: return "VOUCHER";
+ case IKOT_VOUCHER_ATTR_CONTROL: return "VOUCHER_ATTR_CONTROL";
+ case IKOT_WORK_INTERVAL: return "WORK_INTERVAL";
+ case IKOT_UX_HANDLER: return "UX_HANDLER";
+ case IKOT_UEXT_OBJECT: return "UEXT_OBJECT";
+ case IKOT_ARCADE_REG: return "ARCADE_REG";
+ case IKOT_EVENTLINK: return "EVENTLINK";
+ case IKOT_TASK_INSPECT: return "TASK-INSPECT";
+ case IKOT_TASK_READ: return "TASK-READ";
+ case IKOT_THREAD_INSPECT: return "THREAD-INSPECT";
+ case IKOT_THREAD_READ: return "THREAD-READ";
+ case IKOT_SUID_CRED: return "SUID_CRED";
+ case IKOT_HYPERVISOR: return "HYPERVISOR";
+ case IKOT_UNKNOWN:
+ default: return "UNKNOWN";
+ }
+}
+
+const port_status_flag_info_t port_status_flags[] = {
+ [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_TEMPOWNER)] = {
+ .flag = MACH_PORT_STATUS_FLAG_TEMPOWNER,
+ .compact_name = "T",
+ .name = "tempowner",
+ },
+ [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_GUARDED)] = {
+ .flag = MACH_PORT_STATUS_FLAG_GUARDED,
+ .compact_name = "G",
+ .name = "guarded",
+ },
+ [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_STRICT_GUARD)] = {
+ .flag = MACH_PORT_STATUS_FLAG_STRICT_GUARD,
+ .compact_name = "S",
+ .name = "strict guard",
+ },
+ [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_IMP_DONATION)] = {
+ .flag = MACH_PORT_STATUS_FLAG_IMP_DONATION,
+ .compact_name = "I",
+ .name = "imp donation",
+ },
+ [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_REVIVE)] = {
+ .flag = MACH_PORT_STATUS_FLAG_REVIVE,
+ .compact_name = "R",
+ .name = "revive",
+ },
+ [PORT_FLAG_TO_INDEX(MACH_PORT_STATUS_FLAG_TASKPTR)] = {
+ .flag = MACH_PORT_STATUS_FLAG_TASKPTR,
+ .compact_name = "P",
+ .name = "taskptr",
+ },
+ {0},
+};
+
+#define VOUCHER_DETAIL_PREFIX " "
+
+static const unsigned int voucher_contents_size = 8192;
+static uint8_t voucher_contents[voucher_contents_size];
+
+typedef struct {
+ int total;
+ int sendcount;
+ int receivecount;
+ int sendoncecount;
+ int portsetcount;
+ int deadcount;
+ int dncount;
+ int vouchercount;
+} task_table_entry_counts;
+
+typedef task_table_entry_counts * task_table_entry_counts_t;
+
+static void show_task_table_entry(ipc_info_name_t *entry, my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos, task_table_entry_counts_t counts, JSON_t json);
+
+static uint32_t safesize (int len){
+ return (len > 0) ? len : 0;
+}
+
+uint32_t show_recipe_detail(mach_voucher_attr_recipe_t recipe, char *voucher_outstr, uint32_t maxlen, JSON_t json) {
+ JSON_OBJECT_BEGIN(json);
+
+ uint32_t len = 0;
+ len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "Key: %u, ", recipe->key);
+ len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Command: %u, ", recipe->command);
+ len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Previous voucher: 0x%x, ", recipe->previous_voucher);
+ len += snprintf(&voucher_outstr[len], safesize(maxlen - len), "Content size: %u\n", recipe->content_size);
+
+ JSON_OBJECT_SET(json, key, %u, recipe->key);
+ JSON_OBJECT_SET(json, command, %u, recipe->command);
+ JSON_OBJECT_SET(json, previous_voucher, "0x%x", recipe->previous_voucher);
+ JSON_OBJECT_SET(json, content_size, %u, recipe->content_size);
+
+ switch (recipe->key) {
+ case MACH_VOUCHER_ATTR_KEY_IMPORTANCE:
+ // content may not be valid JSON, exclude
+ // JSON_OBJECT_SET(json, importance_info, "%s", (char *)recipe->content);
+ len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "IMPORTANCE INFO: %s", (char *)recipe->content);
+ break;
+ case MACH_VOUCHER_ATTR_KEY_BANK:
+ // content may not be valid JSON, exclude
+ // JSON_OBJECT_SET(json, resource_accounting_info, "%s", (char *)recipe->content);
+ len += snprintf(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX "RESOURCE ACCOUNTING INFO: %s", (char *)recipe->content);
+ break;
+ default:
+ len += print_hex_data(&voucher_outstr[len], safesize(maxlen - len), VOUCHER_DETAIL_PREFIX, "Recipe Contents", (void *)recipe->content, MIN(recipe->content_size, lsmp_config.voucher_detail_length));
+ break;
+ }
+
+ if (len + 1 < maxlen && voucher_outstr[len - 1] != '\n') {
+ voucher_outstr[len++] = '\n';
+ voucher_outstr[len] = '\0';
+ }
+ JSON_OBJECT_END(json); // recipe
+ return len;
+}
+
+
+char * copy_voucher_detail(mach_port_t task, mach_port_name_t voucher, JSON_t json) {
+ unsigned int recipe_size = voucher_contents_size;
+ kern_return_t kr = KERN_SUCCESS;
+ bzero((void *)&voucher_contents[0], sizeof(voucher_contents));
+ unsigned v_kobject = 0;
+ unsigned v_kotype = 0;
+ uint32_t detail_maxlen = VOUCHER_DETAIL_MAXLEN;
+ char * voucher_outstr = (char *)malloc(detail_maxlen);
+ voucher_outstr[0] = '\0';
+ uint32_t plen = 0;
+
+ kr = mach_port_kernel_object( task,
+ voucher,
+ &v_kotype, (unsigned *)&v_kobject);
+ if (kr == KERN_SUCCESS && v_kotype == IKOT_VOUCHER ) {
+
+ kr = mach_voucher_debug_info(task, voucher,
+ (mach_voucher_attr_raw_recipe_array_t)&voucher_contents[0],
+ &recipe_size);
+ if (kr != KERN_SUCCESS && kr != KERN_NOT_SUPPORTED) {
+ plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Voucher: 0x%x Failed to get contents %s\n", v_kobject, mach_error_string(kr));
+ return voucher_outstr;
+ }
+
+ if (recipe_size == 0) {
+ plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Voucher: 0x%x has no contents\n", v_kobject);
+ return voucher_outstr;
+ }
+
+ plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Voucher: 0x%x\n", v_kobject);
+ unsigned int used_size = 0;
+ mach_voucher_attr_recipe_t recipe = NULL;
+ while (recipe_size > used_size) {
+ recipe = (mach_voucher_attr_recipe_t)&voucher_contents[used_size];
+ if (recipe->key) {
+ plen += show_recipe_detail(recipe, &voucher_outstr[plen], safesize(detail_maxlen - plen), json);
+ }
+ used_size += sizeof(mach_voucher_attr_recipe_data_t) + recipe->content_size;
+ }
+ } else {
+ plen += snprintf(&voucher_outstr[plen], safesize(detail_maxlen - plen), VOUCHER_DETAIL_PREFIX "Invalid voucher: 0x%x\n", voucher);
+ }
+
+ return voucher_outstr;
+}
+
+void get_receive_port_context(task_t taskp, mach_port_name_t portname, mach_port_context_t *context) {
+ if (context == NULL) {
+ return;
+ }
+
+ kern_return_t ret;
+ ret = mach_port_get_context(taskp, portname, context);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_get_context(0x%08x) failed: %s\n",
+ portname,
+ mach_error_string(ret));
+ *context = (mach_port_context_t)0;
+ }
+ return;
+}
+
+int get_recieve_port_status(task_t taskp, mach_port_name_t portname, mach_port_info_ext_t *info){
+ if (info == NULL) {
+ return -1;
+ }
+ mach_msg_type_number_t statusCnt;
+ kern_return_t ret;
+ statusCnt = MACH_PORT_INFO_EXT_COUNT;
+ ret = mach_port_get_attributes(taskp,
+ portname,
+ MACH_PORT_INFO_EXT,
+ (mach_port_info_t)info,
+ &statusCnt);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_get_attributes(0x%08x) failed: %s\n",
+ portname,
+ mach_error_string(ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+void show_task_mach_ports(my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos, JSON_t json)
+{
+ int i;
+ task_table_entry_counts counts = {0};
+
+ counts.total = taskinfo->tableCount + taskinfo->treeCount;
+
+ JSON_KEY(json, ports)
+ JSON_ARRAY_BEGIN(json);
+
+ printf(" name ipc-object rights flags boost reqs recv send sonce oref qlimit msgcount context identifier type\n");
+ printf("--------- ---------- ---------- -------- ----- ---- ----- ----- ----- ---- ------ -------- ------------------ ----------- ------------\n");
+ for (i = 0; i < taskinfo->tableCount; i++) {
+ show_task_table_entry(&taskinfo->table[i], taskinfo, taskCount, allTaskInfos, &counts, json);
+ }
+
+ JSON_ARRAY_END(json); // ports
+ JSON_OBJECT_SET(json, total, %d, counts.total);
+ JSON_OBJECT_SET(json, send_rights, %d, counts.sendcount);
+ JSON_OBJECT_SET(json, receive_rights, %d, counts.receivecount);
+ JSON_OBJECT_SET(json, send_once_rights, %d, counts.sendoncecount);
+ JSON_OBJECT_SET(json, port_sets, %d, counts.portsetcount);
+ JSON_OBJECT_SET(json, dead_names, %d, counts.deadcount);
+ JSON_OBJECT_SET(json, dead_name requests, %d, counts.dncount);
+ JSON_OBJECT_SET(json, vouchers, %d, counts.vouchercount);
+
+ printf("\n");
+ printf("total = %d\n", counts.total);
+ printf("SEND = %d\n", counts.sendcount);
+ printf("RECEIVE = %d\n", counts.receivecount);
+ printf("SEND_ONCE = %d\n", counts.sendoncecount);
+ printf("PORT_SET = %d\n", counts.portsetcount);
+ printf("DEAD_NAME = %d\n", counts.deadcount);
+ printf("DNREQUEST = %d\n", counts.dncount);
+ printf("VOUCHERS = %d\n", counts.vouchercount);
+}
+
+static void show_task_table_entry(ipc_info_name_t *entry, my_per_task_info_t *taskinfo, uint32_t taskCount, my_per_task_info_t *allTaskInfos, task_table_entry_counts_t counts, JSON_t json) {
+ int j, k, port_status_flag_idx;
+ kern_return_t ret;
+ boolean_t send = FALSE;
+ boolean_t dnreq = FALSE;
+ int sendrights = 0;
+ unsigned int kotype = 0;
+ vm_offset_t kobject = (vm_offset_t)0;
+ kobject_description_t desc;
+ mach_vm_address_t kaddr;
+
+ /* skip empty slots in the table */
+ if ((entry->iin_type & MACH_PORT_TYPE_ALL_RIGHTS) == 0) {
+ counts->total--;
+ return;
+ }
+
+ if (entry->iin_type == MACH_PORT_TYPE_PORT_SET) {
+ mach_port_name_array_t members;
+ mach_msg_type_number_t membersCnt;
+
+ ret = mach_port_get_set_status(taskinfo->task,
+ entry->iin_name,
+ &members, &membersCnt);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_get_set_status(0x%08x) failed: %s\n",
+ entry->iin_name,
+ mach_error_string(ret));
+ return;
+ }
+
+ JSON_OBJECT_BEGIN(json);
+ JSON_OBJECT_SET(json, type, "port set");
+ JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
+ JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
+
+ JSON_KEY(json, members);
+ JSON_ARRAY_BEGIN(json);
+
+ printf("0x%08x 0x%08x port-set -------- --- 1 %d members\n",
+ entry->iin_name,
+ entry->iin_object,
+ membersCnt);
+ /* get some info for each portset member */
+ for (j = 0; j < membersCnt; j++) {
+ for (k = 0; k < taskinfo->tableCount; k++) {
+ if (taskinfo->table[k].iin_name == members[j]) {
+ mach_port_info_ext_t info;
+ mach_port_status_t port_status;
+ mach_port_context_t port_context = (mach_port_context_t)0;
+ if (0 != get_recieve_port_status(taskinfo->task, taskinfo->table[k].iin_name, &info)) {
+ bzero((void *)&info, sizeof(info));
+ }
+ port_status = info.mpie_status;
+ get_receive_port_context(taskinfo->task, taskinfo->table[k].iin_name, &port_context);
+
+ JSON_OBJECT_BEGIN(json);
+ JSON_OBJECT_SET(json, ipc-object, "0x%08x", taskinfo->table[k].iin_object);
+
+ JSON_KEY(json, rights);
+ JSON_ARRAY_BEGIN(json);
+ JSON_ARRAY_APPEND(json, "recv");
+ if (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) {
+ JSON_ARRAY_APPEND(json, "send");
+ }
+ JSON_ARRAY_END(json); // rights
+
+ JSON_KEY(json, port_status_flags);
+ JSON_ARRAY_BEGIN(json);
+ port_status_flag_idx = 0;
+ while (0 != port_status_flags[port_status_flag_idx++].flag) {
+ if (port_status.mps_flags & INDEX_TO_PORT_FLAG(port_status_flag_idx)) {
+ JSON_ARRAY_APPEND(json, "%s", port_status_flags[port_status_flag_idx].name);
+ }
+ }
+ JSON_ARRAY_END(json); // port status flags
+ JSON_OBJECT_SET(json, boosts, %d, info.mpie_boost_cnt);
+
+ JSON_KEY(json, notifications);
+ JSON_ARRAY_BEGIN(json);
+ if (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) {
+ JSON_ARRAY_APPEND(json, "dead name");
+ }
+ if (port_status.mps_nsrequest) {
+ JSON_ARRAY_APPEND(json, "no sender");
+ }
+ if (port_status.mps_nsrequest) {
+ JSON_ARRAY_APPEND(json, "port destroy request");
+ }
+ JSON_ARRAY_END(json); // notifications
+
+ JSON_OBJECT_SET(json, recv_rights, %d, 1);
+ JSON_OBJECT_SET(json, send_rights, %d, taskinfo->table[k].iin_urefs);
+ JSON_OBJECT_SET(json, send_once_rights, %d, port_status.mps_sorights);
+ JSON_OBJECT_SET_BOOL(json, oref, port_status.mps_srights);
+ JSON_OBJECT_SET(json, queue_limit, %d, port_status.mps_qlimit);
+ JSON_OBJECT_SET(json, msg_count, %d, port_status.mps_msgcount);
+ JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)port_context);
+ JSON_OBJECT_SET(json, identifier, "0x%08x", taskinfo->table[k].iin_name);
+ JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
+ JSON_OBJECT_SET(json, process, "%s", taskinfo->processName);
+ JSON_OBJECT_END(json); // member
+
+ printf(" - 0x%08x %s --%s%s%s%s%s%s %5d %s%s%s %5d %5.0d %5.0d %s %6d %8d 0x%016llx 0x%08x (%d) %s\n",
+ taskinfo->table[k].iin_object,
+ (taskinfo->table[k].iin_type & MACH_PORT_TYPE_SEND) ? "recv,send ":"recv ",
+ SHOW_PORT_STATUS_FLAGS(port_status.mps_flags),
+ info.mpie_boost_cnt,
+ (taskinfo->table[k].iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
+ (port_status.mps_nsrequest) ? "N" : "-",
+ (port_status.mps_pdrequest) ? "P" : "-",
+ 1,
+ taskinfo->table[k].iin_urefs,
+ port_status.mps_sorights,
+ (port_status.mps_srights) ? "Y" : "N",
+ port_status.mps_qlimit,
+ port_status.mps_msgcount,
+ (uint64_t)port_context,
+ taskinfo->table[k].iin_name,
+ taskinfo->pid,
+ taskinfo->processName);
+ break;
+ }
+ }
+ }
+
+ JSON_ARRAY_END(json); // members
+ JSON_OBJECT_END(json); // port-set
+
+ ret = vm_deallocate(mach_task_self(), (vm_address_t)members,
+ membersCnt * sizeof(mach_port_name_t));
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "vm_deallocate() failed: %s\n",
+ mach_error_string(ret));
+ exit(1);
+ }
+ counts->portsetcount++;
+ return;
+ }
+
+ if (entry->iin_type & MACH_PORT_TYPE_SEND) {
+ send = TRUE;
+ sendrights = entry->iin_urefs;
+ counts->sendcount++;
+ }
+
+ if (entry->iin_type & MACH_PORT_TYPE_DNREQUEST) {
+ dnreq = TRUE;
+ counts->dncount++;
+ }
+
+ if (entry->iin_type & MACH_PORT_TYPE_RECEIVE) {
+ mach_port_status_t status;
+ mach_port_info_ext_t info;
+ mach_port_context_t context = (mach_port_context_t)0;
+ struct k2n_table_node *k2nnode;
+ ret = get_recieve_port_status(taskinfo->task, entry->iin_name, &info);
+ get_receive_port_context(taskinfo->task, entry->iin_name, &context);
+ /* its ok to fail in fetching attributes */
+ if (ret < 0) {
+ return;
+ }
+ status = info.mpie_status;
+
+ JSON_OBJECT_BEGIN(json);
+ JSON_OBJECT_SET(json, type, "port");
+ JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
+ JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
+
+ JSON_KEY(json, rights);
+ JSON_ARRAY_BEGIN(json);
+ JSON_ARRAY_APPEND(json, "recv");
+ if (send) JSON_ARRAY_APPEND(json, "send");
+ JSON_ARRAY_END(json); // rights
+
+ JSON_KEY(json, port_status_flags);
+ JSON_ARRAY_BEGIN(json);
+ port_status_flag_idx = 0;
+ while (0 != port_status_flags[port_status_flag_idx++].flag) {
+ if (status.mps_flags & INDEX_TO_PORT_FLAG(port_status_flag_idx)) {
+ JSON_ARRAY_APPEND(json, "%s", port_status_flags[port_status_flag_idx].name);
+ }
+ }
+ JSON_ARRAY_END(json); // port status flags
+ JSON_OBJECT_SET(json, boosts, %d, info.mpie_boost_cnt);
+
+ JSON_KEY(json, notifications);
+ JSON_ARRAY_BEGIN(json);
+ if (dnreq) {
+ JSON_ARRAY_APPEND(json, "dead name");
+ }
+ if (status.mps_nsrequest) {
+ JSON_ARRAY_APPEND(json, "no sender");
+ }
+ if (status.mps_nsrequest) {
+ JSON_ARRAY_APPEND(json, "port destroy request");
+ }
+ JSON_ARRAY_END(json); // notifications
+
+ JSON_OBJECT_SET(json, recv_rights, %d, 1);
+ JSON_OBJECT_SET(json, send_rights, %d, sendrights);
+ JSON_OBJECT_SET(json, send_once_rights, %d, status.mps_sorights);
+ JSON_OBJECT_SET_BOOL(json, oref, status.mps_srights);
+ JSON_OBJECT_SET(json, queue_limit, %d, status.mps_qlimit);
+ JSON_OBJECT_SET(json, msg_count, %d, status.mps_msgcount);
+ JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)context);
+ JSON_OBJECT_END(json); // port
+
+ printf("0x%08x 0x%08x %s --%s%s%s%s%s%s %5d %s%s%s %5d %5.0d %5.0d %s %6d %8d 0x%016llx \n",
+ entry->iin_name,
+ entry->iin_object,
+ (send) ? "recv,send ":"recv ",
+ SHOW_PORT_STATUS_FLAGS(status.mps_flags),
+ info.mpie_boost_cnt,
+ (dnreq) ? "D":"-",
+ (status.mps_nsrequest) ? "N":"-",
+ (status.mps_pdrequest) ? "P":"-",
+ 1,
+ sendrights,
+ status.mps_sorights,
+ (status.mps_srights) ? "Y":"N",
+ status.mps_qlimit,
+ status.mps_msgcount,
+ (uint64_t)context);
+ counts->receivecount++;
+
+ /* show other rights (in this and other tasks) for the port */
+ for (j = 0; j < taskCount; j++) {
+ if (allTaskInfos[j].valid == FALSE)
+ continue;
+
+ k2nnode = k2n_table_lookup(allTaskInfos[j].k2ntable, entry->iin_object);
+
+ while (k2nnode) {
+ if (k2nnode->info_name != entry) {
+ assert(k2nnode->info_name->iin_object == entry->iin_object);
+
+ printf(" + %s -------- %s%s%s %5d <- 0x%08x (%d) %s\n",
+ (k2nnode->info_name->iin_type & MACH_PORT_TYPE_SEND_ONCE) ?
+ "send-once " : "send ",
+ (k2nnode->info_name->iin_type & MACH_PORT_TYPE_DNREQUEST) ? "D" : "-",
+ "-",
+ "-",
+ k2nnode->info_name->iin_urefs,
+ k2nnode->info_name->iin_name,
+ allTaskInfos[j].pid,
+ allTaskInfos[j].processName);
+ }
+
+ k2nnode = k2n_table_lookup_next(k2nnode, entry->iin_object);
+ }
+ }
+ return;
+ }
+ else if (entry->iin_type & MACH_PORT_TYPE_DEAD_NAME)
+ {
+ JSON_OBJECT_BEGIN(json);
+ JSON_OBJECT_SET(json, type, "dead name");
+ JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
+ JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
+ JSON_OBJECT_SET(json, send_rights, %d, entry->iin_urefs);
+ JSON_OBJECT_END(json); // dead name
+
+ printf("0x%08x 0x%08x dead-name -------- --- %5d \n",
+ entry->iin_name,
+ entry->iin_object,
+ entry->iin_urefs);
+ counts->deadcount++;
+ return;
+ }
+
+ if (entry->iin_type & MACH_PORT_TYPE_SEND_ONCE) {
+ counts->sendoncecount++;
+ }
+
+ JSON_OBJECT_BEGIN(json);
+ JSON_OBJECT_SET(json, name, "0x%08x", entry->iin_name);
+ JSON_OBJECT_SET(json, ipc-object, "0x%08x", entry->iin_object);
+
+ JSON_KEY(json, rights);
+ JSON_ARRAY_BEGIN(json);
+ JSON_ARRAY_APPEND(json, "%s", (send) ? "send":"send once");
+ JSON_ARRAY_END(json); //rights
+
+ JSON_KEY(json, notifications);
+ JSON_ARRAY_BEGIN(json);
+ if (dnreq) JSON_ARRAY_APPEND(json, "dead name");
+ JSON_ARRAY_END(json); // notifications
+
+ JSON_OBJECT_SET(json, send_rights, %d, (send) ? sendrights : 0);
+
+ printf("0x%08x 0x%08x %s -------- %s%s%s %5.0d ",
+ entry->iin_name,
+ entry->iin_object,
+ (send) ? "send ":"send-once ",
+ (dnreq) ? "D":"-",
+ "-",
+ "-",
+ (send) ? sendrights : 0);
+
+ /* converting to kobjects is not always supported */
+
+ desc[0] = '\0';
+ ret = mach_port_kobject_description(taskinfo->task,
+ entry->iin_name,
+ &kotype, &kaddr,
+ desc);
+ if (KERN_SUCCESS == ret) {
+ kobject = (unsigned) kaddr;
+ } else {
+ ret = mach_port_kernel_object(taskinfo->task,
+ entry->iin_name,
+ &kotype, (unsigned *)&kobject);
+ }
+
+ if (ret == KERN_SUCCESS && kotype != 0) {
+ JSON_OBJECT_SET(json, identifier, "0x%08x", (natural_t)kobject);
+ JSON_OBJECT_SET(json, type, "%s", kobject_name(kotype));
+ if (desc[0]) {
+ JSON_OBJECT_SET(json, description, "%s", desc);
+ printf(" 0x%08x %s %s", (natural_t)kobject, kobject_name(kotype), desc);
+ } else {
+ printf(" 0x%08x %s", (natural_t)kobject, kobject_name(kotype));
+ }
+ if ((kotype == IKOT_TASK_RESUME) || (kotype == IKOT_TASK_CONTROL) || (kotype == IKOT_TASK_NAME)) {
+ if (taskinfo->task_kobject == kobject) {
+ /* neat little optimization since in most cases tasks have themselves in their ipc space */
+ JSON_OBJECT_SET(json, pid, %d, taskinfo->pid);
+ JSON_OBJECT_SET(json, process, "%s", taskinfo->processName);
+ printf(" SELF (%d) %s", taskinfo->pid, taskinfo->processName);
+ } else {
+ my_per_task_info_t * _found_task = get_taskinfo_by_kobject((natural_t)kobject);
+ JSON_OBJECT_SET(json, pid, %d, _found_task->pid);
+ JSON_OBJECT_SET(json, process, "%s", _found_task->processName);
+ printf(" (%d) %s", _found_task->pid, _found_task->processName);
+ }
+ }
+
+ if (kotype == IKOT_THREAD_CONTROL) {
+ for (int i = 0; i < taskinfo->threadCount; i++) {
+ if (taskinfo->threadInfos[i].th_kobject == kobject) {
+ printf(" (%#llx)", taskinfo->threadInfos[i].th_id);
+ break;
+ }
+ }
+ }
+
+ printf("\n");
+ if (kotype == IKOT_VOUCHER) {
+ counts->vouchercount++;
+ if (lsmp_config.show_voucher_details) {
+ JSON_KEY(json, recipes);
+ JSON_ARRAY_BEGIN(json);
+ char * detail = copy_voucher_detail(taskinfo->task, entry->iin_name, json);
+ JSON_ARRAY_END(json); // recipes
+ printf("%s\n", detail);
+ free(detail);
+ }
+ }
+ JSON_OBJECT_END(json); // kobject
+ return;
+ }
+
+ /* not kobject - find the receive right holder */
+ my_per_task_info_t *recv_holder_taskinfo;
+ mach_port_name_t recv_name = MACH_PORT_NULL;
+ if (KERN_SUCCESS == get_taskinfo_of_receiver_by_send_right(entry, &recv_holder_taskinfo, &recv_name)) {
+ mach_port_status_t port_status;
+ mach_port_info_ext_t info;
+ mach_port_context_t port_context = (mach_port_context_t)0;
+ if (0 != get_recieve_port_status(recv_holder_taskinfo->task, recv_name, &info)) {
+ bzero((void *)&port_status, sizeof(port_status));
+ }
+ port_status = info.mpie_status;
+ get_receive_port_context(recv_holder_taskinfo->task, recv_name, &port_context);
+
+ JSON_OBJECT_SET(json, queue_limit, %d, port_status.mps_qlimit);
+ JSON_OBJECT_SET(json, msg_count, %d, port_status.mps_msgcount);
+ JSON_OBJECT_SET(json, context, "0x%016llx", (uint64_t)port_context);
+ JSON_OBJECT_SET(json, identifier, "0x%08x", recv_name);
+ JSON_OBJECT_SET(json, pid, %d, recv_holder_taskinfo->pid);
+ JSON_OBJECT_SET(json, process, "%s", recv_holder_taskinfo->processName);
+
+ printf(" -> %6d %8d 0x%016llx 0x%08x (%d) %s\n",
+ port_status.mps_qlimit,
+ port_status.mps_msgcount,
+ (uint64_t)port_context,
+ recv_name,
+ recv_holder_taskinfo->pid,
+ recv_holder_taskinfo->processName);
+
+ } else {
+ JSON_OBJECT_SET(json, identifier, "0x%08x", 0);
+ JSON_OBJECT_SET(json, pid, %d, -1);
+ JSON_OBJECT_SET(json, process, "unknown");
+ printf(" 0x00000000 (-) Unknown Process\n");
+ }
+
+ JSON_OBJECT_END(json); // non-kobject
+}
+
+uint32_t print_hex_data(char *outstr, uint32_t maxlen, char *prefix, char *desc, void *addr, int len) {
+ int i;
+ unsigned char buff[17];
+ unsigned char *pc = addr;
+ uint32_t plen = 0;
+
+ if (desc != NULL)
+ plen += snprintf(&outstr[plen], safesize(maxlen - plen), "%s%s:\n", prefix, desc);
+
+ for (i = 0; i < len; i++) {
+
+ if ((i % 16) == 0) {
+ if (i != 0)
+ plen += snprintf(&outstr[plen], safesize(maxlen - plen), " %s\n", buff);
+
+ plen += snprintf(&outstr[plen], safesize(maxlen - plen), "%s %04x ", prefix, i);
+ }
+
+ plen += snprintf(&outstr[plen], safesize(maxlen - plen), " %02x", pc[i]);
+
+ if ((pc[i] < 0x20) || (pc[i] > 0x7e))
+ buff[i % 16] = '.';
+ else
+ buff[i % 16] = pc[i];
+ buff[(i % 16) + 1] = '\0';
+ }
+
+ while ((i % 16) != 0) {
+ plen += snprintf(&outstr[plen], safesize(maxlen - plen), " ");
+ i++;
+ }
+
+ plen += snprintf(&outstr[plen], safesize(maxlen - plen), " %s\n", buff);
+
+ return plen;
+}
diff --git a/system_cmds/lsmp.tproj/task_details.c b/system_cmds/lsmp.tproj/task_details.c
new file mode 100644
index 0000000..bf9ef51
--- /dev/null
+++ b/system_cmds/lsmp.tproj/task_details.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2002-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach_debug/ipc_info.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <libproc.h>
+#include <assert.h>
+
+#include "common.h"
+
+#pragma mark kobject to name hash table implementation
+
+#if (K2N_TABLE_SIZE & (K2N_TABLE_SIZE - 1) != 0)
+#error K2N_TABLE_SIZE must be a power of two
+#endif
+
+#define K2N_TABLE_MASK (K2N_TABLE_SIZE - 1)
+
+static uint32_t k2n_hash(natural_t kobject) {
+ return (uint64_t)kobject * 2654435761 >> 32;
+}
+
+static struct k2n_table_node *k2n_table_lookup_next_internal(struct k2n_table_node *node, natural_t kobject) {
+ while (node) {
+ if (kobject == node->kobject)
+ return node;
+
+ node = node->next;
+ }
+
+ return NULL;
+}
+
+struct k2n_table_node *k2n_table_lookup_next(struct k2n_table_node *node, natural_t kobject) {
+ if (!node) {
+ return NULL;
+ }
+ return k2n_table_lookup_next_internal(node->next, kobject);
+}
+
+struct k2n_table_node *k2n_table_lookup(struct k2n_table_node **table, natural_t kobject) {
+ uint32_t hv;
+ struct k2n_table_node *node;
+
+ hv = k2n_hash(kobject);
+
+ node = table[hv & K2N_TABLE_MASK];
+
+ return k2n_table_lookup_next_internal(node, kobject);
+}
+
+static void k2n_table_enter(struct k2n_table_node **table, natural_t kobject, ipc_info_name_t *info_name) {
+ uint32_t hv;
+ struct k2n_table_node *node;
+
+ hv = k2n_hash(kobject);
+
+ node = malloc(sizeof (struct k2n_table_node));
+ assert(node);
+
+ node->kobject = kobject;
+ node->info_name = info_name;
+ assert(kobject == info_name->iin_object);
+
+ node->next = table[hv & K2N_TABLE_MASK];
+ table[hv & K2N_TABLE_MASK] = node;
+}
+
+#pragma mark -
+
+static my_per_task_info_t NOT_FOUND_TASK_INFO = {
+ .task = NULL,
+ .task_kobject = NULL,
+ .pid = -1,
+ .info = {0,0,0,0,0,0},
+ .table = NULL,
+ .tableCount = 0,
+ .tree = NULL,
+ .treeCount = 0,
+ .valid = FALSE,
+ .k2ntable = {0},
+ .processName = "Unknown",
+ .exceptionInfo = {0},
+ .threadInfos = NULL,
+ .threadCount = 0,
+ .threadExceptionInfos = NULL
+};
+
+char * get_task_name_by_pid(pid_t pid);
+
+static void proc_pid_to_name(int pid, char *pname){
+ if (0 == proc_name(pid, pname, PROC_NAME_LEN)) {
+ strcpy(pname, "Unknown Process");
+ }
+}
+
+static my_per_task_info_t *global_taskinfo = NULL;
+static uint32_t global_taskcount = 0;
+
+my_per_task_info_t * allocate_taskinfo_memory(uint32_t taskCount)
+{
+ my_per_task_info_t * retval = malloc(taskCount * sizeof(my_per_task_info_t));
+ if (retval) {
+ bzero((void *)retval, taskCount * sizeof(my_per_task_info_t));
+ }
+ global_taskcount = taskCount;
+ global_taskinfo = retval;
+ return retval;
+}
+
+void deallocate_taskinfo_memory(my_per_task_info_t *data){
+ if (data) {
+ free(data);
+ global_taskinfo = NULL;
+ global_taskcount = 0;
+ }
+}
+
+kern_return_t collect_per_task_info(my_per_task_info_t *taskinfo, task_t target_task)
+{
+ int i;
+ kern_return_t ret = KERN_SUCCESS;
+ unsigned int kotype = 0;
+ vm_offset_t kobject = (vm_offset_t)0;
+
+ taskinfo->task = target_task;
+ pid_for_task(target_task, &taskinfo->pid);
+
+ ret = task_get_exception_ports(taskinfo->task, EXC_MASK_ALL, taskinfo->exceptionInfo.masks, &taskinfo->exceptionInfo.count, taskinfo->exceptionInfo.ports, taskinfo->exceptionInfo.behaviors, taskinfo->exceptionInfo.flavors);
+
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "task_get_exception_ports() failed: pid:%d error: %s\n",taskinfo->pid, mach_error_string(ret));
+ taskinfo->pid = 0;
+ }
+
+ /* collect threads port as well */
+ taskinfo->threadCount = 0;
+ thread_act_array_t threadPorts;
+ ret = task_threads(taskinfo->task, &threadPorts, &taskinfo->threadCount);
+
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "task_threads() failed: pid:%d error: %s\n",taskinfo->pid, mach_error_string(ret));
+ taskinfo->threadCount = 0;
+ } else {
+ /* collect the thread information */
+ taskinfo->threadInfos = (struct my_per_thread_info *)malloc(sizeof(struct my_per_thread_info) * taskinfo->threadCount);
+ bzero(taskinfo->threadInfos, sizeof(struct my_per_thread_info) * taskinfo->threadCount);
+
+ /* now collect exception ports for each of those threads as well */
+ taskinfo->threadExceptionInfos = (struct exc_port_info *) malloc(sizeof(struct exc_port_info) * taskinfo->threadCount);
+ boolean_t found_exception = false;
+ for (int i = 0; i < taskinfo->threadCount; i++) {
+ unsigned th_kobject = 0;
+ unsigned th_kotype = 0;
+ ipc_voucher_t th_voucher = IPC_VOUCHER_NULL;
+ thread_identifier_info_data_t th_info;
+ mach_msg_type_number_t th_info_count = THREAD_IDENTIFIER_INFO_COUNT;
+ struct exc_port_info *excinfo = &(taskinfo->threadExceptionInfos[i]);
+
+ ret = thread_get_exception_ports(threadPorts[i], EXC_MASK_ALL, excinfo->masks, &excinfo->count, excinfo->ports, excinfo->behaviors, excinfo->flavors);
+ if (ret != KERN_SUCCESS){
+ fprintf(stderr, "thread_get_exception_ports() failed: pid: %d thread: %d error %s\n", taskinfo->pid, threadPorts[i], mach_error_string(ret));
+ }
+
+ if (excinfo->count != 0) {
+ found_exception = true;
+ }
+
+ taskinfo->threadInfos[i].thread = threadPorts[i];
+
+ if (KERN_SUCCESS == mach_port_kernel_object(mach_task_self(), threadPorts[i], &th_kotype, &th_kobject)) {
+ taskinfo->threadInfos[i].th_kobject = th_kobject;
+ if (KERN_SUCCESS == thread_info(threadPorts[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&th_info, &th_info_count)) {
+ taskinfo->threadInfos[i].th_id = th_info.thread_id;
+ }
+ }
+
+ if (KERN_SUCCESS == thread_get_mach_voucher(threadPorts[i], 0, &th_voucher) && th_voucher != IPC_VOUCHER_NULL) {
+ char *detail = copy_voucher_detail(mach_task_self(), th_voucher, NULL);
+ taskinfo->threadInfos[i].voucher_detail = strndup(detail, VOUCHER_DETAIL_MAXLEN);
+ free(detail);
+
+ mach_port_deallocate(mach_task_self(), th_voucher);
+ }
+
+ mach_port_deallocate(mach_task_self(), threadPorts[i]);
+ threadPorts[i] = MACH_PORT_NULL;
+ }
+
+ if (found_exception == false) {
+ free(taskinfo->threadExceptionInfos);
+ taskinfo->threadExceptionInfos = NULL;
+ }
+
+ }
+
+ vm_deallocate(mach_task_self(), threadPorts, taskinfo->threadCount * sizeof(thread_act_t));
+ threadPorts = NULL;
+
+ ret = mach_port_space_info(target_task, &taskinfo->info, &taskinfo->table, &taskinfo->tableCount, &taskinfo->tree, &taskinfo->treeCount);
+
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "mach_port_space_info() failed: pid:%d error: %s\n",taskinfo->pid, mach_error_string(ret));
+ taskinfo->pid = 0;
+ return ret;
+ }
+
+ bzero(taskinfo->k2ntable, K2N_TABLE_SIZE * sizeof (struct k2n_table_node *));
+ for (i = 0; i < taskinfo->tableCount; i++) {
+ k2n_table_enter(taskinfo->k2ntable, taskinfo->table[i].iin_object, &taskinfo->table[i]);
+ }
+
+ proc_pid_to_name(taskinfo->pid, taskinfo->processName);
+
+ ret = mach_port_kernel_object(mach_task_self(), taskinfo->task, &kotype, (unsigned *)&kobject);
+
+ if (ret == KERN_SUCCESS && kotype == IKOT_TASK_CONTROL) {
+ taskinfo->task_kobject = kobject;
+ taskinfo->valid = TRUE;
+ }
+
+ return ret;
+}
+
+void get_exc_behavior_string(exception_behavior_t b, char *out_string, size_t len)
+{
+ out_string[0]='\0';
+
+ if (b & MACH_EXCEPTION_CODES)
+ strlcat(out_string, "MACH +", len);
+ switch (b & ~MACH_EXCEPTION_CODES) {
+ case EXCEPTION_DEFAULT:
+ strlcat(out_string, " DEFAULT", len);
+ break;
+ case EXCEPTION_STATE:
+ strlcat(out_string, " STATE", len);
+ break;
+ case EXCEPTION_STATE_IDENTITY:
+ strlcat(out_string, " IDENTITY", len);
+ break;
+ default:
+ strlcat(out_string, " UNKNOWN", len);
+ }
+}
+
+void get_exc_mask_string(exception_mask_t m, char *out_string, size_t len)
+{
+ out_string[0]='\0';
+
+ if (m & (1<<EXC_BAD_ACCESS))
+ strlcat(out_string, " BAD_ACCESS", len);
+ if (m & (1<<EXC_BAD_INSTRUCTION))
+ strlcat(out_string," BAD_INSTRUCTION", len);
+ if (m & (1<<EXC_ARITHMETIC))
+ strlcat(out_string," ARITHMETIC", len);
+ if (m & (1<<EXC_EMULATION))
+ strlcat(out_string," EMULATION", len);
+ if (m & (1<<EXC_SOFTWARE))
+ strlcat(out_string," SOFTWARE", len);
+ if (m & (1<<EXC_BREAKPOINT))
+ strlcat(out_string," BREAKPOINT", len);
+ if (m & (1<<EXC_SYSCALL))
+ strlcat(out_string," SYSCALL", len);
+ if (m & (1<<EXC_MACH_SYSCALL))
+ strlcat(out_string," MACH_SYSCALL", len);
+ if (m & (1<<EXC_RPC_ALERT))
+ strlcat(out_string," RPC_ALERT", len);
+ if (m & (1<<EXC_CRASH))
+ strlcat(out_string," CRASH", len);
+ if (m & (1<<EXC_RESOURCE))
+ strlcat(out_string," RESOURCE", len);
+ if (m & (1<<EXC_GUARD))
+ strlcat(out_string," GUARD", len);
+}
+
+kern_return_t print_task_exception_info(my_per_task_info_t *taskinfo, JSON_t json)
+{
+
+ char behavior_string[30];
+ char mask_string[200];
+
+ JSON_KEY(json, exception_ports);
+ JSON_ARRAY_BEGIN(json);
+
+ boolean_t header_required = TRUE;
+ for (int i = 0; i < taskinfo->exceptionInfo.count; i++) {
+ if (taskinfo->exceptionInfo.ports[i] != MACH_PORT_NULL) {
+ if (header_required) {
+
+ printf(" exc_port flavor <behaviors> mask \n");
+ header_required = FALSE;
+ }
+ get_exc_behavior_string(taskinfo->exceptionInfo.behaviors[i], behavior_string, sizeof(behavior_string));
+ get_exc_mask_string(taskinfo->exceptionInfo.masks[i], mask_string, sizeof(mask_string));
+
+ JSON_OBJECT_BEGIN(json);
+ JSON_OBJECT_SET(json, port, "0x%08x", taskinfo->exceptionInfo.ports[i]);
+ JSON_OBJECT_SET(json, flavor, "0x%03x", taskinfo->exceptionInfo.flavors[i]);
+ JSON_OBJECT_SET(json, behavior, "%s", behavior_string);
+ JSON_OBJECT_SET(json, mask, "%s", mask_string);
+ JSON_OBJECT_END(json); // exception port
+
+ printf(" 0x%08x 0x%03x <%s> %s \n" , taskinfo->exceptionInfo.ports[i], taskinfo->exceptionInfo.flavors[i], behavior_string, mask_string);
+ }
+
+ }
+
+ JSON_ARRAY_END(json); // exception ports
+
+ return KERN_SUCCESS;
+}
+
+
+kern_return_t print_task_threads_special_ports(my_per_task_info_t *taskinfo, JSON_t json)
+{
+ kern_return_t kret = KERN_SUCCESS;
+ mach_msg_type_number_t threadcount = taskinfo->threadCount;
+ boolean_t header_required = TRUE;
+ boolean_t newline_required = TRUE;
+ struct my_per_thread_info * info = NULL;
+
+ JSON_KEY(json, threads);
+ JSON_ARRAY_BEGIN(json);
+
+ for (int i = 0; i < threadcount; i++) {
+ JSON_OBJECT_BEGIN(json);
+
+ info = &taskinfo->threadInfos[i];
+ if (header_required) {
+ printf("Thread_KObject Thread-ID Port Description.");
+ header_required = FALSE;
+ }
+
+ if (newline_required) {
+ printf("\n");
+ }
+ newline_required = TRUE;
+
+ if (info->th_kobject != 0) {
+ /* TODO: Should print tid and stuff */
+ printf("0x%08x ", info->th_kobject);
+ printf("0x%llx ", info->th_id);
+
+ JSON_OBJECT_SET(json, kobject, "0x%08x", info->th_kobject);
+ JSON_OBJECT_SET(json, tid, "0x%llx", info->th_id);
+ }
+
+ if (info->voucher_detail != NULL) {
+ /* TODO: include voucher detail in JSON */
+ printf("%s\n", info->voucher_detail);
+ }
+
+ JSON_KEY(json, exception_ports);
+ JSON_ARRAY_BEGIN(json);
+
+ /* print the thread exception ports also */
+ if (taskinfo->threadExceptionInfos != NULL)
+ {
+
+ struct exc_port_info *excinfo = &taskinfo->threadExceptionInfos[i];
+ char behavior_string[30];
+ char mask_string[200];
+
+ if (excinfo->count > 0) {
+ boolean_t header_required = TRUE;
+ for (int i = 0; i < excinfo->count; i++) {
+ JSON_OBJECT_BEGIN(json);
+
+ if (excinfo->ports[i] != MACH_PORT_NULL) {
+ if (header_required) {
+ printf("\n exc_port flavor <behaviors> mask -> name owner\n");
+ header_required = FALSE;
+ }
+ get_exc_behavior_string(excinfo->behaviors[i], behavior_string, sizeof(behavior_string));
+ get_exc_mask_string(excinfo->masks[i], mask_string, sizeof(mask_string));
+
+ JSON_OBJECT_SET(json, port, "0x%08x", excinfo->ports[i]);
+ JSON_OBJECT_SET(json, flavor, "0x%03x", excinfo->flavors[i]);
+ JSON_OBJECT_SET(json, behavior, "%s", behavior_string);
+ JSON_OBJECT_SET(json, mask, "%s", mask_string);
+
+ printf(" 0x%08x 0x%03x <%s> %s " , excinfo->ports[i], excinfo->flavors[i], behavior_string, mask_string);
+
+ ipc_info_name_t actual_sendinfo;
+ if (KERN_SUCCESS == get_ipc_info_from_lsmp_spaceinfo(excinfo->ports[i], &actual_sendinfo)) {
+ my_per_task_info_t *recv_holder_taskinfo;
+ mach_port_name_t recv_name = MACH_PORT_NULL;
+ if (KERN_SUCCESS == get_taskinfo_of_receiver_by_send_right(&actual_sendinfo, &recv_holder_taskinfo, &recv_name)) {
+
+ JSON_OBJECT_SET(json, name, "0x%08x", recv_name);
+ JSON_OBJECT_SET(json, ipc-object, "0x%08x", actual_sendinfo.iin_object);
+ JSON_OBJECT_SET(json, pid, %d, recv_holder_taskinfo->pid);
+ JSON_OBJECT_SET(json, process, "%s", recv_holder_taskinfo->processName);
+
+ printf(" -> 0x%08x 0x%08x (%d) %s\n",
+ recv_name,
+ actual_sendinfo.iin_object,
+ recv_holder_taskinfo->pid,
+ recv_holder_taskinfo->processName);
+ }
+
+ } else {
+ fprintf(stderr, "failed to find");
+ }
+
+ printf("\n");
+
+ }
+ JSON_OBJECT_END(json); // exception port
+ }
+ }
+ }
+ JSON_ARRAY_END(json); // exception ports
+ JSON_OBJECT_END(json); // thread
+ }
+
+ JSON_ARRAY_END(json); // threads
+ printf("\n");
+ return kret;
+}
+
+char * get_task_name_by_pid(pid_t pid) {
+ char * retval = "Unknown";
+ for (int i = 0; i < global_taskcount; i++) {
+ if (pid == global_taskinfo[i].pid) {
+ return global_taskinfo[i].processName;
+ }
+ }
+ return retval;
+}
+
+my_per_task_info_t * get_taskinfo_by_kobject(natural_t kobj) {
+ my_per_task_info_t *retval = &NOT_FOUND_TASK_INFO;
+ for (int j = 0; j < global_taskcount; j++) {
+ if (global_taskinfo[j].task_kobject == kobj) {
+ retval = &global_taskinfo[j];
+ break;
+ }
+ }
+ return retval;
+}
+
+kern_return_t get_taskinfo_of_receiver_by_send_right(ipc_info_name_t *sendright, my_per_task_info_t **out_taskinfo, mach_port_name_t *out_recv_info)
+{
+ *out_taskinfo = &NOT_FOUND_TASK_INFO;
+ struct k2n_table_node *k2nnode;
+
+ for (int j = 0; j < global_taskcount; j++) {
+ if ((k2nnode = k2n_table_lookup(global_taskinfo[j].k2ntable, sendright->iin_object))) {
+ assert(k2nnode->info_name->iin_object == sendright->iin_object);
+
+ if (k2nnode->info_name->iin_type & MACH_PORT_TYPE_RECEIVE) {
+ *out_taskinfo = &global_taskinfo[j];
+ *out_recv_info = k2nnode->info_name->iin_name;
+ return KERN_SUCCESS;
+ }
+ }
+ }
+
+ return KERN_FAILURE;
+}
+
+kern_return_t get_ipc_info_from_lsmp_spaceinfo(mach_port_t port_name, ipc_info_name_t *out_sendright){
+ kern_return_t retval = KERN_FAILURE;
+ bzero(out_sendright, sizeof(ipc_info_name_t));
+ my_per_task_info_t *mytaskinfo = NULL;
+ for (int i = global_taskcount - 1; i >= 0; i--){
+ if (global_taskinfo[i].task == mach_task_self()){
+ mytaskinfo = &global_taskinfo[i];
+ break;
+ }
+ }
+ if (mytaskinfo) {
+ for (int k = 0; k < mytaskinfo->tableCount; k++) {
+ if (port_name == mytaskinfo->table[k].iin_name){
+ bcopy(&mytaskinfo->table[k], out_sendright, sizeof(ipc_info_name_t));
+ retval = KERN_SUCCESS;
+ break;
+ }
+ }
+ }
+ return retval;
+
+}
diff --git a/system_cmds/ltop.tproj/ltop.1 b/system_cmds/ltop.tproj/ltop.1
new file mode 100644
index 0000000..98b0555
--- /dev/null
+++ b/system_cmds/ltop.tproj/ltop.1
@@ -0,0 +1,59 @@
+.\" Copyright (c) 2012, Apple Inc. All rights reserved.
+.\"
+.Dd June 28, 2012
+.Dt LTOP 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm ltop
+.Nd Display ledger information for processes on the system
+.Sh SYNOPSIS
+.Nm ltop
+.Bk -words
+.Fl h
+.Pp
+.Nm ltop
+.Op Fl dL
+.Op Fl g Ar group
+.Op Fl p Ar pid
+.Op Fl r Ar resource
+.Op Ar interval
+.Ek
+.Sh DESCRIPTION
+.Nm ltop
+displays the contents of system ledgers maintained by the kernel for each process in the system. Ledgers are a general accounting mechanism that the kernel uses to track and limit things like CPU time and memory usage.
+.Pp
+If the optional
+.Ar interval
+is specified, then
+.Nm
+will display the ledger contents every interval seconds.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.\" ==========
+.It Fl d
+In conjunction with
+.Ar interval ,
+display the rate of change for each value, as compared to the previous sample displayed.
+.\" ==========
+.It Fl L
+Display template info. Shows which resources are tracked, and lists the associated units.
+.\" ==========
+.It Fl g Ar group
+Only display info for the ledgers associated with
+.Ar group .
+Group topology can be seen via the
+.Fl L
+option.
+.\" ==========
+.It Fl p Ar pid
+Only display info for process
+.Ar pid .
+.\" ==========
+.It Fl r Ar resource
+Only display info for resource
+.Ar resource .
+.\" ==========
+.El
+.Sh SEE ALSO
+.Xr top 1
diff --git a/system_cmds/ltop.tproj/ltop.c b/system_cmds/ltop.tproj/ltop.c
new file mode 100644
index 0000000..42348e7
--- /dev/null
+++ b/system_cmds/ltop.tproj/ltop.c
@@ -0,0 +1,491 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <libproc.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <Kernel/kern/ledger.h>
+#include <mach/mach_types.h>
+
+extern int ledger(int cmd, caddr_t arg1, caddr_t arg2, caddr_t arg3);
+
+int pid = -1;
+char *group_print = NULL;
+char *resource_print = NULL;
+int diff_mode = 0;
+
+struct proc_list {
+ int pid;
+ int seen;
+ char name[2 * MAXCOMLEN];
+ struct ledger *ledger;
+ struct proc_list *next;
+};
+
+struct proc_list *procs = NULL;
+struct ledger_template_info *template = NULL;
+int entry_cnt = 0;
+
+struct ledger {
+ int64_t id;
+ int seen;
+ int64_t entries;
+ struct ledger_entry_info *info;
+ struct ledger_entry_info *old_info;
+ struct ledger *next;
+};
+
+struct ledger *ledgers = NULL;
+
+static void
+get_template_info(void)
+{
+
+ void *buf;
+ int cnt;
+
+top:
+ /* Allocate enough space to accomodate a few new entries */
+ cnt = entry_cnt + 5;
+ buf = malloc(cnt * sizeof (struct ledger_template_info));
+ if (buf == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ exit (1);
+ }
+
+ if (ledger(LEDGER_TEMPLATE_INFO, (caddr_t)buf, (caddr_t)&cnt, NULL) < 0) {
+ perror("ledger() system call failed");
+ exit(1);
+ }
+
+ /* We underestimated how many entries we needed. Let's try again */
+ if (cnt == entry_cnt + 5) {
+ entry_cnt += 5;
+ free(buf);
+ goto top;
+ }
+ entry_cnt = cnt;
+ template = buf;
+}
+
+/*
+ * Note - this is a destructive operation. Unless we're about to exit, this
+ * needs to be followed by another call to get_template_info().
+ */
+static void
+dump_template_info(void)
+{
+ int i, j;
+ const char *group = NULL;
+
+ printf("Resources being tracked:\n");
+ printf("\t%10s %15s %8s\n", "GROUP", "RESOURCE", "UNITS");
+ for (i = 0; i < entry_cnt; i++) {
+ if (strlen(template[i].lti_name) == 0)
+ continue;
+
+ group = template[i].lti_group;
+ for (j = i; j < entry_cnt; j++) {
+ if (strcmp(template[j].lti_group, group))
+ continue;
+ printf("\t%10s %15s %8s\n", template[j].lti_group,
+ template[j].lti_name, template[j].lti_units);
+ template[j].lti_name[0] = '\0';
+ }
+ }
+}
+
+static void
+validate_group(void)
+{
+ int i;
+
+ if (template == NULL)
+ get_template_info();
+
+ for (i = 0; i < entry_cnt; i++)
+ if (!strcmp(group_print, template[i].lti_group))
+ return;
+
+ fprintf(stderr, "No such group: %s\n", group_print);
+ exit (1);
+}
+
+static void
+validate_resource(void)
+{
+ int i;
+
+ if (template == NULL)
+ get_template_info();
+
+ for (i = 0; i < entry_cnt; i++)
+ if (!strcmp(resource_print, template[i].lti_name))
+ return;
+
+ fprintf(stderr, "No such resource: %s\n", resource_print);
+ exit (1);
+}
+
+static size_t
+get_kern_max_proc(void)
+{
+ int mib[] = { CTL_KERN, KERN_MAXPROC };
+ int max;
+ size_t max_sz = sizeof (max);
+
+ if (sysctl(mib, 2, &max, &max_sz, NULL, 0) < 0) {
+ perror("Failed to get max proc count");
+ exit (1);
+ }
+
+ return (max);
+}
+
+static struct ledger *
+ledger_find(struct ledger_info *li)
+{
+ struct ledger *l;
+
+ for (l = ledgers; l && (li->li_id != l->id); l = l->next)
+ ;
+
+ if (l == NULL) {
+ l = (struct ledger *)malloc(sizeof (*l));
+ if (l == NULL) {
+ fprintf(stderr, "Out of memory");
+ exit (1);
+ }
+ l->id = li->li_id;
+ l->entries = li->li_entries;
+ l->next = ledgers;
+ l->seen = 0;
+ l->info = NULL;
+ l->old_info = NULL;
+ ledgers = l;
+ }
+ return (l);
+}
+
+static void
+ledger_update(pid_t pid, struct ledger *l)
+{
+ void *arg;
+ struct ledger_entry_info *lei;
+ int64_t cnt;
+
+ cnt = l->entries;
+ if (cnt > entry_cnt)
+ cnt = entry_cnt;
+ arg = (void *)(long)pid;
+ lei = (struct ledger_entry_info *)malloc((size_t)(cnt * sizeof (*lei)));
+ if (ledger(LEDGER_ENTRY_INFO, arg, (caddr_t)lei, (caddr_t)&cnt) < 0) {
+ perror("ledger_info() failed: ");
+ exit (1);
+ }
+ l->info = lei;
+}
+
+static void
+get_proc_info(int pid)
+{
+ struct ledger_info li;
+ struct ledger *ledgerp;
+ struct proc_list *proc;
+ void *arg;
+
+ if (pid == 0)
+ return;
+
+ arg = (void *)(long)pid;
+ errno = 0;
+ if (ledger(LEDGER_INFO, arg, (caddr_t)&li, NULL) < 0) {
+
+ if (errno == ENOENT || errno == ESRCH)
+ return;
+
+ perror("ledger_info() failed: ");
+ exit (1);
+ }
+
+ ledgerp = ledger_find(&li);
+ ledger_update(pid, ledgerp);
+ ledgerp->seen = 1;
+
+ for (proc = procs; proc; proc = proc->next)
+ if (proc->pid == pid)
+ break;
+ if (proc == NULL) {
+ proc = (struct proc_list *)malloc(sizeof (*proc));
+ if (proc == NULL) {
+ fprintf(stderr, "Out of memory\n");
+ exit (1);
+ }
+
+ if (proc_name(pid, proc->name, sizeof (proc->name)) == 0)
+ strlcpy(proc->name, "Error", sizeof (proc->name));
+
+ proc->pid = pid;
+ proc->ledger = ledgerp;
+ proc->next = procs;
+ procs = proc;
+ }
+ proc->seen = 1;
+}
+
+static int
+pid_compare(const void *a, const void *b)
+{
+ pid_t *pid_a = (pid_t *)a;
+ pid_t *pid_b = (pid_t *)b;
+
+ return (*pid_b - *pid_a);
+}
+
+static void
+get_all_info(void)
+{
+ pid_t *pids;
+ int sz, cnt, i;
+
+ if (pid < 0)
+ cnt = (int) get_kern_max_proc();
+ else
+ cnt = 1;
+
+ sz = cnt * sizeof(pid_t);
+ pids = (pid_t *)malloc(sz);
+ if (pids == NULL) {
+ perror("can't allocate memory for proc buffer\n");
+ exit (1);
+ }
+
+ if (pid < 0) {
+ cnt = proc_listallpids(pids, sz);
+ if (cnt < 0) {
+ perror("failed to get list of active pids");
+ exit (1);
+ }
+ qsort(pids, cnt, sizeof (pid_t), pid_compare);
+ } else {
+ pids[0] = pid;
+ }
+
+ for (i = 0; i < cnt; i++)
+ get_proc_info(pids[i]);
+ free(pids);
+}
+
+static void
+print_num(int64_t num, int64_t delta)
+{
+ const char *suf = "";
+ char posneg = ' ';
+ int numwidth;
+
+ if (diff_mode) {
+ num = delta;
+ }
+
+ if (num == LEDGER_LIMIT_INFINITY) {
+ printf("%10s ", "-");
+ return;
+ }
+
+ if (llabs(num) > 10000000000) {
+ num /= 1000000000;
+ suf = "G";
+ } else if (llabs(num) > 10000000) {
+ num /= 1000000;
+ suf = "M";
+ } else if (llabs(num) > 100000) {
+ num /= 1000;
+ suf = "K";
+ }
+
+ posneg = (delta < 0) ? '-' : ((delta > 0) ? '+' : ' ');
+
+ numwidth = 10;
+
+ numwidth -= strlen(suf);
+
+ printf("%*lld%s%c ", numwidth, num, suf, posneg);
+}
+
+static void
+dump_all_info(void)
+{
+ struct ledger_entry_info *info, *old;
+ struct proc_list *p;
+ int line, i;
+ int64_t d;
+
+ printf("\n%5s %32s %32s %10s %10s %10s %10s %10s \n", "PID", "COMMAND",
+ "RESOURCE", "CREDITS", "DEBITS", "BALANCE", "LIMIT", "PERIOD");
+
+ for (p = procs; p; p = p->next) {
+ if (p->seen == 0)
+ continue;
+
+ printf("%5d %32s ", p->pid, p->name);
+ line = 0;
+
+ info = p->ledger->info;
+ old = p->ledger->old_info;
+ for (i = 0; i < p->ledger->entries; i++) {
+ if (group_print &&
+ strcmp(group_print, template[i].lti_group))
+ continue;
+
+ if (resource_print &&
+ strcmp(resource_print, template[i].lti_name))
+ continue;
+
+ if (line++)
+ printf("%5s %32s ", "", "");
+ printf("%32s ", template[i].lti_name);
+
+ d = old ? info[i].lei_credit - old[i].lei_credit : 0;
+ print_num(info[i].lei_credit, d);
+
+ d = old ? info[i].lei_debit - old[i].lei_debit : 0;
+ print_num(info[i].lei_debit, d);
+
+ d = old ? info[i].lei_balance - old[i].lei_balance : 0;
+ print_num(info[i].lei_balance, d);
+
+ if (info[i].lei_limit == LEDGER_LIMIT_INFINITY) {
+ printf("%10s %10s", "none", "-");
+ } else {
+ print_num(info[i].lei_limit, 0);
+ print_num(info[i].lei_refill_period, 0);
+ }
+ printf("\n");
+ }
+ }
+
+ if (line == 0)
+ exit (0);
+}
+
+static void
+cleanup(void)
+{
+ struct proc_list *p, *pnext, *plast;
+ struct ledger *l, *lnext, *llast;
+
+ plast = NULL;
+ for (p = procs; p; p = pnext) {
+ pnext = p->next;
+ if (p->seen == 0) {
+ if (plast)
+ plast->next = pnext;
+ else
+ procs = pnext;
+
+ free(p);
+ } else {
+ p->seen = 0;
+ }
+ }
+
+ llast = NULL;
+ for (l = ledgers; l; l = lnext) {
+ lnext = l->next;
+ if (l->seen == 0) {
+ if (llast)
+ llast->next = lnext;
+ else
+ ledgers = lnext;
+ free(l->info);
+ if (l->old_info)
+ free(l->old_info);
+ free(l);
+ } else {
+ l->seen = 0;
+ free(l->old_info);
+ l->old_info = l->info;
+ l->info = NULL;
+ }
+ }
+
+ free(template);
+ template = NULL;
+}
+
+const char *pname;
+
+static void
+usage(void)
+{
+ printf("%s [-hdL] [-g group] [-p pid] [-r resource] [interval]\n", pname);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int interval = 0;
+
+ pname = argv[0];
+
+ while ((c = getopt(argc, argv, "g:hdLp:r:")) != -1) {
+ switch (c) {
+ case 'g':
+ group_print = optarg;
+ break;
+
+ case 'd':
+ diff_mode = 1;
+ break;
+
+ case 'h':
+ usage();
+ exit(0);
+
+ case 'L':
+ get_template_info();
+ dump_template_info();
+ exit(0);
+
+ case 'p':
+ pid = atoi(optarg);
+ break;
+
+ case 'r':
+ resource_print = optarg;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc)
+ interval = atoi(argv[0]);
+
+ if (group_print && resource_print) {
+ fprintf(stderr, "Cannot specify both a resource and a group\n");
+ exit (1);
+ }
+
+ if (group_print)
+ validate_group();
+ if (resource_print)
+ validate_resource();
+
+ do {
+ get_template_info();
+ get_all_info();
+ dump_all_info();
+ cleanup();
+ sleep(interval);
+ } while (interval);
+}
diff --git a/system_cmds/mean.tproj/mean.c b/system_cmds/mean.tproj/mean.c
new file mode 100644
index 0000000..87ecdc2
--- /dev/null
+++ b/system_cmds/mean.tproj/mean.c
@@ -0,0 +1,128 @@
+/*
+ * mean.c
+ * mean - lower process priorities with more force than nice
+ *
+ * Created by Lucia Ballard on 9/16/09.
+ * Copyright 2009-2016 Apple Inc. All rights reserved.
+ *
+ */
+
+#include <mach/mach.h>
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void usage(void);
+
+void
+usage(void)
+{
+ fprintf(stderr, "Usage: mean -[r|s|u] <pid>\n");
+ fprintf(stderr, "\tLower <pid>'s priority.\n");
+ fprintf(stderr, "\t-u: return <pid> to normal priority\n");
+ fprintf(stderr, "\t-r: resume <pid>\n");
+ fprintf(stderr, "\t-s: suspend <pid>\n");
+ exit(0);
+}
+
+int
+main(int argc, char **argv)
+{
+ int pid, err, i, ch;
+ unsigned int count;
+ mach_port_t task;
+ thread_act_array_t threads;
+ thread_precedence_policy_data_t policy;
+
+ boolean_t do_high = 0, do_resume = 0, do_suspend = 0;
+ boolean_t do_low = 1;
+
+ if (argc < 2)
+ usage();
+
+ while ((ch = getopt(argc, argv, "rsu")) != -1)
+ switch (ch) {
+ case 'u':
+ do_high = 1;
+ do_low = 0;
+ continue;
+ case 'r':
+ do_resume = 1;
+ do_low = 0;
+ continue;
+ case 's':
+ do_suspend = 1;
+ do_low = 0;
+ continue;
+ default:
+ usage();
+ }
+
+ argc -= optind; argv += optind;
+
+ if (argc == 0)
+ usage();
+
+ pid = atoi(*argv);
+ if (!pid)
+ usage();
+
+ err = task_for_pid(mach_task_self(), pid, &task);
+ if (err) {
+ fprintf(stderr, "Failed to get task port (%d)\n", err);
+ exit(0);
+ }
+
+ if (do_low || do_high) {
+
+ err = task_threads(task, &threads, &count);
+ if (err) {
+ fprintf(stderr, "Failed to get thread list (%d)\n", err);
+ exit(0);
+ }
+
+ if (do_low)
+ policy.importance = -100;
+ else
+ policy.importance = 0;
+
+ for (i = 0; i < count; i++) {
+ err = thread_policy_set(threads[i],
+ THREAD_PRECEDENCE_POLICY,
+ (thread_policy_t) &policy,
+ THREAD_PRECEDENCE_POLICY_COUNT);
+ if (err) {
+ fprintf(stderr, "Failed to set thread priority (%d)\n", err);
+ exit(0);
+ }
+ }
+
+ printf("Process %d's threads set to %s priority.\n", pid,
+ (do_low ? "lowest" : "highest"));
+ }
+
+ if (do_suspend) {
+ err = task_suspend(task);
+ if (err) {
+ fprintf(stderr, "Failed to suspend task (%d)\n", err);
+ } else {
+ printf("Process %d suspended.\n", pid);
+ }
+ }
+
+ if (do_resume) {
+ err = task_resume(task);
+ if (err) {
+ fprintf(stderr, "Failed to resume task (%d)\n", err);
+ } else {
+ printf("Process %d resumed.\n", pid);
+ }
+ }
+
+ return 0;
+}
diff --git a/system_cmds/memory_pressure.tproj/memory_pressure.1 b/system_cmds/memory_pressure.tproj/memory_pressure.1
new file mode 100644
index 0000000..f775876
--- /dev/null
+++ b/system_cmds/memory_pressure.tproj/memory_pressure.1
@@ -0,0 +1,28 @@
+.\" Copyright (c) 2013, Apple Inc. All rights reserved.
+.\"
+.Dd Mar 7, 2013
+.Dt MEMORY_PRESSURE 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm memory_pressure
+.Nd Tool to apply real or simulate memory pressure on the system.
+.Sh SYNOPSIS
+.Pp
+.Nm memory_pressure [-l level] | [-p percent_free] | [-S -l level]
+.Sh OPTIONS
+.Pp
+.Ar -l <level>
+Apply real or simulate memory pressure (if specified alongside simulate argument) on the system till low memory notifications corresponding to <level> are generated. Supported values are "warn" and "critical".
+.Pp
+.Ar -p <percent_free>
+Allocate memory till the available memory in the system is <percent_free> of total memory. If the percentage of available memory to total memory on the system drops, the tool will free memory till either the desired percentage is achieved or it runs out of memory to free.
+.Pp
+.Ar -S
+Simulate memory pressure on the system by placing it artificially for <sleep_seconds> duration at the "warn" or "critical" level.
+.Pp
+.Ar -s <sleep_seconds>
+Duration to wait before allocating or freeing memory if applying real pressure. In case of simulating memory pressure, this is the duration the system will be maintained at an artifical memory level.
+.Sh DESCRIPTION
+A tool to apply real or simulate memory pressure on the system
+.Sh SEE ALSO
+.Xr vm_stat 1
diff --git a/system_cmds/memory_pressure.tproj/memory_pressure.c b/system_cmds/memory_pressure.tproj/memory_pressure.c
new file mode 100644
index 0000000..1713fcb
--- /dev/null
+++ b/system_cmds/memory_pressure.tproj/memory_pressure.c
@@ -0,0 +1,777 @@
+/*
+ * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <getopt.h>
+#include <string.h>
+#include <mach/i386/vm_param.h>
+#include <sys/kern_memorystatus.h>
+#include <sys/sysctl.h>
+#include <mach/mach.h>
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <assert.h>
+#include <dispatch/private.h>
+
+long long phys_mem = 0; /* amount of physical memory in bytes */
+unsigned int phys_pages = 0; /* number of physical memory pages */
+int sleep_seconds = 1;
+int requested_hysteresis_seconds = 0;
+boolean_t quiet_mode_on = FALSE;
+boolean_t simulate_mode_on = FALSE;
+
+void *range_start_addr = NULL;
+void *range_end_addr = NULL;
+void *range_current_addr = NULL;
+
+int start_referencing_pages = 0;
+int start_allocing_pages = 0;
+pthread_cond_t reference_pages_condvar = PTHREAD_COND_INITIALIZER;
+pthread_mutex_t reference_pages_mutex = PTHREAD_MUTEX_INITIALIZER;
+unsigned int desired_level = 0, desired_percent = 0;
+unsigned int percent_for_level = 0;
+int tool_mode = 0;
+
+#define TOOL_MODE_FOR_PERCENT 1
+#define TOOL_MODE_FOR_LEVEL 2
+
+
+char random_data[] = "ffd8ffe000104a46494600010101002400240000ffe100744578696600004d4d002a000000080004011a0005000000010000003e011b0005000000010000004601280003000000010002000087690004000000010000004e00000000000000240000000100000024000000010002a002000400000001000003c0a003000400000001000001ff00000000ffdb00430002020202020102020202020202030306040303030307050504060807080808070808090a0d0b09090c0a08080b0f0b0c0d0e0e0e0e090b10110f0e110d0e0e0effdb004301020202030303060404060e0908090e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0e0effc000110801ff03c003012200021101031101ffc4001f0000010501010101010100000000000000000102030405060708090a0bffc400b5100002010303020403050504040000017d01020300041105122131410613516107227114328191a1082342b1c11552d1f02433627282090a161718191a25262728292a3435363738393a434445464748494a535455565758595a636465666768696a737475767778797a838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae1e2e3e4e5e6e7e8e9eaf1f2f3f4f5f6f7f8f9faffc4001f0100030101010101010101010000000000000102030405060708090a0bffc400b51100020102040403040705040400010277000102031104052131061241510761711322328108144291a1b1c109233352f0156272d10a162434e125f11718191a262728292a35363738393a434445464748494a535455565758595a636465666768696a737475767778797a82838485868788898a92939495969798999aa2a3a4a5a6a7a8a9aab2b3b4b5b6b7b8b9bac2c3c4c5c6c7c8c9cad2d3d4d5d6d7d8d9dae2e3e4e5e6e7e8e9eaf2f3f4f5f6f7f8f9faffda000c03010002110311003f00f9e74fbd37baa2db99e6506391f28371f9519ba67fd9fcabd46cbc1315de8d6776752d7419e049084b152a37283c1dfc8e6bc02db4af18d9df79c9e1bd59a40ae9b65b1761f32953c63ae09c7a1c57656fe24f8896da7c16c9e0bb3748a358d5a4d04b31006324f73c75a00935f7fec9f165ee98b7372e2ddc05795763f2a0f20138ebeb590bac3e70d2b6e1fed1ac6d4ecbc65aa6b973a85c7867528a6998168edec1a38c1c01c2f61c550fec1f16ff00d0bdade4f5ff00447ff0a00eaffb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe668fed76ff9eaff0099ae57fb07c5bff42f6b7ff808ff00e147f60f8b7fe85ed6ff00f011ff00c2803aafed76ff009eaff99a3fb5dbfe7abfe66b95fec1f16ffd0bdadffe023ff851fd83e2dffa17b5bffc047ff0a00eabfb5dbfe7abfe668fed76ff009eaff99ae57fb07c5bff0042f6b7ff00808ffe147f60f8b7fe85ed6fff00011ffc2803aafed76ff9eaff0099a3fb5dbfe7abfe66b95fec1f16ff00d0bdadff00e023ff00851fd83e2dff00a17b5bff00c047ff000a00eabfb5dbfe7abfe66b4f45fed1f1078bb4cd0f4bdf3ea37f7296f6d1ee3f33b1c0cfb7a9f4ae0bfb07c5bff42f6b7ff808ff00e15a9a1c5e3bf0f78c74bd774cd0f5a8751d3ee52e2ddcd9be03a9c8cfb7623d2803d5bc6fe0df11780e0d3ae354bab1bdb1bd678e1bab1b8f36312c6079b112380cac4ae3b9535e7ffdaedff3d5ff00335b3e3af177c4af1f5be9b6da8f8567d36c2c59e486d74fd35e28ccb260c92b003966605b3db71af3cfec1f16ff00d0bdadff00e023ff0085007acf83743d57c6baddd59e9d7062fb3c68d248519c0324ab120c2f3cb38c9ec013dab95b8d427b5bfb8b59a4759a195a3917278652411f98ad9f86fe30f88bf0cb57d56f348f095f5ebdfc2914ab716b200a118918c0ff0068d709a9d878cb55f12ea3aa4fe1cd6127bdba92e2455b47c06772c40e3a64d007d13f09fe1d37c41d135ad7b52d52ef4fd074eba86cff00d1537cd7171310123504e0751927d6be8ed17f65bf0aebde19b4d5ac7c5fe2236b700eddf12060558ab03ee1948fc2be41f84bf123e20fc2d1acd87fc20d77e24f0eeabb1af74cbcb4902974fbb22b0190c3fa0f4afa1748fdad3c51a1691fd9fa57c10b8b4b212bc8b0ac931542c7240c8e067271ef401e9bff000c89a07fd0dbafff00dfb4a3fe191340ff00a1b75fff00bf695c2ffc366f8e7fe88c5cff00df72ff00851ff0d9be39ff00a23173ff007dcbfe1401dd7fc322681ff436ebff00f7ed28ff008644d03fe86dd7ff00efda570bff000d9be39ffa23173ff7dcbfe147fc366f8e7fe88c5cff00df72ff008500775ff0c89a07fd0dbaff00fdfb4a3fe191340ffa1b75ff00fbf695c2ff00c366f8e7fe88c5cffdf72ff851ff000d9be39ffa23173ff7dcbfe1401dd7fc322681ff00436ebfff007ed2be52f8d1f0eeff00e11fc42b2d325d49f51d3afedccf637046d6215b6b2b0f5071f98af733fb6678eb071f062e73fefcbfe15f2a7c5af1cfc4bf8bff001262d7758f0bea76515bc1f67b1b1b7b490a4099c9edcb13c93f4a00fe891bc2fe1c672cda1e96589c92";
+
+#define PAGE_OP_ALLOC 0x1
+#define PAGE_OP_FREE 0x2
+
+#define USE_WIRED_PAGES_FOR_PERCENT_MODE FALSE
+
+#define MAX_RANGE_SIZE 64 * 1024 * 1024 * 1024ULL
+
+void print_vm_statistics(void);
+void munch_for_level(unsigned int, unsigned int);
+void munch_for_percentage(unsigned int, unsigned int, unsigned int);
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: memory_pressure [options] [<pages>]\n"
+ " Allocate memory and wait forever.\n"
+ " Options include:\n"
+ " -l <level> - allocate memory until a low memory notification is received (warn OR critical)\n"
+ " -p <percent-free> - allocate memory until percent free is this (or less)\n"
+ " -s <seconds> - how long to sleep between checking for a set percent level\n"
+ " -w <percent-free> - don't allocate, just wait until percent free is this then exit\n"
+ " -y <seconds> - Hysteresis Interval: how long to wait after requested percntage free is reached, before exiting program. Requires the usage of the -p option\n"
+ " -v <print VM stats> - print VM statistics every sampling interval\n"
+ " -Q <quiet mode> - reduces the tool's output\n"
+ " -S - simulate the system's memory pressure level without applying any real pressure\n"
+ " \n"
+ );
+ exit(0);
+}
+
+static unsigned int
+read_sysctl_int(const char* name)
+{
+ unsigned int var;
+ size_t var_size;
+ int error;
+
+ var_size = sizeof(var);
+ error = sysctlbyname(name, &var, &var_size, NULL, 0);
+ if( error ) {
+ perror(name);
+ exit(-1);
+ }
+ return var;
+}
+
+static long long
+read_sysctl_long_long(const char* name)
+{
+ long long var;
+ size_t var_size;
+ int error;
+
+ var_size = sizeof(var);
+ error = sysctlbyname(name, &var, &var_size, NULL, 0);
+ if( error ) {
+ perror(name);
+ exit(-1);
+ }
+ return var;
+}
+
+static int
+get_percent_free(unsigned int* level)
+{
+ int error;
+
+ error = memorystatus_get_level((user_addr_t) level);
+
+ if( error ) {
+ perror("memorystatus_get_level failed:");
+ exit(-1);
+ }
+ return error;
+}
+
+void
+print_vm_statistics(void)
+{
+ unsigned int count = HOST_VM_INFO64_COUNT;
+ kern_return_t ret = 0;
+ vm_statistics64_data_t vm_stat;;
+
+ if (quiet_mode_on == TRUE) {
+ return;
+ }
+
+ if ((ret = host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t)&vm_stat, &count) != KERN_SUCCESS)) {
+ fprintf(stderr, "Failed to get statistics. Error %d\n", ret);
+ } else {
+ printf("\nStats: \n");
+ printf("Pages free: %llu \n", (uint64_t) (vm_stat.free_count - vm_stat.speculative_count));
+ printf("Pages purgeable: %llu \n", (uint64_t) (vm_stat.purgeable_count));
+ printf("Pages purged: %llu \n",(uint64_t) (vm_stat.purges));
+
+ printf("\nSwap I/O:\n");
+ printf("Swapins: %llu \n", (uint64_t) (vm_stat.swapins));
+ printf("Swapouts: %llu \n", (uint64_t) (vm_stat.swapouts));
+
+ printf("\nPage Q counts:\n");
+ printf("Pages active: %llu \n", (uint64_t) (vm_stat.active_count));
+ printf("Pages inactive: %llu \n", (uint64_t) (vm_stat.inactive_count));
+ printf("Pages speculative: %llu \n", (uint64_t) (vm_stat.speculative_count));
+ printf("Pages throttled: %llu \n", (uint64_t) (vm_stat.throttled_count));
+ printf("Pages wired down: %llu \n", (uint64_t) (vm_stat.wire_count));
+
+ printf("\nCompressor Stats:\n");
+ printf("Pages used by compressor: %llu \n", (uint64_t) (vm_stat.compressor_page_count));
+ printf("Pages decompressed: %llu \n", (uint64_t) (vm_stat.decompressions));
+ printf("Pages compressed: %llu \n", (uint64_t) (vm_stat.compressions));
+
+ printf("\nFile I/O:\n");
+ printf("Pageins: %llu \n", (uint64_t) (vm_stat.pageins));
+ printf("Pageouts: %llu \n", (uint64_t) (vm_stat.pageouts));
+
+#if 0
+ printf("\"Translation faults\": %llu \n", (uint64_t) (vm_stat.faults));
+ printf("Pages copy-on-write: %llu \n", (uint64_t) (vm_stat.cow_faults));
+ printf("Pages zero filled: %llu \n", (uint64_t) (vm_stat.zero_fill_count));
+ printf("Pages reactivated: %llu \n", (uint64_t) (vm_stat.reactivations));
+#endif
+ printf("\n");
+ }
+}
+
+/*
+ this will work for up to 64 TB of RAM -- beyond that we exceed Intel's max for VRAM (48 bits of addressable space).
+ By the time we get there Intel probably will have increased this
+ */
+static unsigned long long
+get_max_range_size()
+{
+ unsigned long long the_max_range_size = MAX_RANGE_SIZE;
+
+ if (phys_mem * 4 > the_max_range_size) {
+ the_max_range_size = phys_mem * 4;
+ }
+
+ return the_max_range_size;
+}
+
+static int
+reached_or_bypassed_desired_result(void)
+{
+ if (tool_mode == TOOL_MODE_FOR_LEVEL) {
+
+ unsigned int current_level = 0;
+
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+
+ if (desired_level > 0 && current_level >= desired_level) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (tool_mode == TOOL_MODE_FOR_PERCENT) {
+
+ unsigned int current_percent = 0;
+
+ get_percent_free(&current_percent);
+
+ if (desired_percent > 0 && current_percent <= desired_percent) {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ return 0;
+}
+
+static void
+reference_pages(int level)
+{
+ int error;
+ void *addr = NULL;
+ int num_pages = 0;
+
+ error = pthread_mutex_lock(&reference_pages_mutex);
+ addr = range_start_addr;
+again:
+ while(start_referencing_pages == 0) {
+ error = pthread_cond_wait(&reference_pages_condvar, &reference_pages_mutex);
+ }
+
+ start_allocing_pages = 0;
+ pthread_mutex_unlock(&reference_pages_mutex);
+
+ num_pages = 0;
+ for(; addr < range_current_addr;) {
+
+ char p;
+
+ if (reached_or_bypassed_desired_result()) {
+ //printf("stopped referencing after %d pages\n", num_pages);
+ break;
+ }
+
+ p = *(char*) addr;
+ addr += PAGE_SIZE;
+ num_pages++;
+
+ }
+
+ //if (num_pages) {
+ // printf("Referenced %d\n", num_pages);
+ //}
+ error = pthread_mutex_lock(&reference_pages_mutex);
+ start_referencing_pages = 0;
+ start_allocing_pages = 1;
+
+ goto again;
+}
+
+static void
+process_pages(int num_pages, int page_op)
+{
+ if (num_pages > 0) {
+
+ int error = 0, i = 0;
+ size_t size = num_pages * PAGE_SIZE;
+
+ if (page_op == PAGE_OP_ALLOC) {
+
+ if (tool_mode == TOOL_MODE_FOR_PERCENT && USE_WIRED_PAGES_FOR_PERCENT_MODE) {
+ error = mlock(range_current_addr, size);
+ if (error == -1) {
+ perror("Failed to lock memory!");
+ exit(-1);
+ }
+
+ memset(range_current_addr, 0xFF, size);
+ range_current_addr += size;
+
+ } else {
+
+ pthread_mutex_lock(&reference_pages_mutex);
+ while (start_allocing_pages == 0) {
+ pthread_mutex_unlock(&reference_pages_mutex);
+ sleep(1);
+ pthread_mutex_lock(&reference_pages_mutex);
+ }
+ pthread_mutex_unlock(&reference_pages_mutex);
+
+ for (i=0; i < num_pages; i++) {
+
+ if (reached_or_bypassed_desired_result()) {
+ //printf("stopped faulting after %d pages\n", i);
+ break;
+ }
+ if ((uintptr_t)range_current_addr < get_max_range_size()) {
+ memcpy(range_current_addr, random_data, PAGE_SIZE);
+ range_current_addr += PAGE_SIZE;
+ } else {
+ printf("\nRun out of allocable memory\n");
+ exit(0);
+ }
+ }
+
+ pthread_mutex_lock(&reference_pages_mutex);
+ start_referencing_pages = 1;
+ pthread_cond_signal(&reference_pages_condvar);
+ pthread_mutex_unlock(&reference_pages_mutex);
+ }
+ } else {
+ if (tool_mode == TOOL_MODE_FOR_PERCENT && USE_WIRED_PAGES_FOR_PERCENT_MODE) {
+ error = munlock(range_current_addr, size);
+ if (error == -1) {
+ perror("Failed to unlock memory!");
+ exit(-1);
+ }
+
+ error = madvise(range_current_addr, size, MADV_FREE);
+ if (error == -1) {
+ perror("Failed to madv_free memory!");
+ exit(-1);
+ }
+
+ range_current_addr -= size;
+
+ } else {
+ pthread_mutex_lock(&reference_pages_mutex);
+ while (start_referencing_pages == 1) {
+ pthread_mutex_unlock(&reference_pages_mutex);
+ sleep(1);
+ pthread_mutex_lock(&reference_pages_mutex);
+ }
+
+ error = madvise(range_current_addr, size, MADV_FREE);
+ if (error == -1) {
+ perror("Failed to madv_free memory!");
+ exit(-1);
+ }
+ range_current_addr -= size;
+ start_referencing_pages = 1;
+ pthread_cond_signal(&reference_pages_condvar);
+ pthread_mutex_unlock(&reference_pages_mutex);
+ }
+ }
+ }
+}
+
+void
+munch_for_level(unsigned int sleep_seconds, unsigned int print_vm_stats)
+{
+
+ unsigned int current_level = 0;
+ unsigned int desired_percent = 0;
+ unsigned int current_percent = 0;
+ unsigned int page_op = PAGE_OP_ALLOC;
+ unsigned int previous_page_op = PAGE_OP_ALLOC;
+ unsigned int pages_to_process = 0;
+ unsigned int stabilized_percentage = 0;
+ boolean_t print_vm_stats_on_page_processing = FALSE;
+ boolean_t ok_to_print_stablity_message = TRUE;
+
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+
+ if (current_level >= desired_level) {
+ return;
+ }
+
+ get_percent_free(&current_percent);
+
+ if (print_vm_stats) {
+ print_vm_stats_on_page_processing = TRUE;
+ }
+
+ page_op = PAGE_OP_ALLOC;
+ previous_page_op = 0;
+
+ while (1) {
+
+ if (current_percent > percent_for_level) {
+ desired_percent = current_percent - percent_for_level;
+ } else {
+ desired_percent = 1;
+ }
+
+ pages_to_process = (desired_percent * phys_pages) / 100;
+
+ page_op = PAGE_OP_ALLOC;
+
+ if (previous_page_op != page_op) {
+ //printf("%s %d pages.\n", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", pages_to_process);
+ printf("\nCMD: %s pages to go from level: %d to level: %d", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", current_level, desired_level);
+ previous_page_op = page_op;
+ fflush(stdout);
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ if (print_vm_stats_on_page_processing == TRUE) {
+ print_vm_statistics();
+ }
+ process_pages(pages_to_process, page_op);
+ ok_to_print_stablity_message = TRUE;
+
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+
+ if (current_level >= desired_level) {
+
+ while(1) {
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+ if (current_level < desired_level) {
+ break;
+ }
+
+ if (current_level > desired_level) {
+ page_op = PAGE_OP_FREE;
+
+ get_percent_free(&current_percent);
+
+ if (stabilized_percentage > current_percent) {
+ pages_to_process = ((stabilized_percentage - current_percent) * phys_pages) / 100;
+
+ if (previous_page_op != page_op) {
+ printf("\nCMD: %s pages to go from %d to %d level", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", current_level, desired_level);
+ previous_page_op = page_op;
+ fflush(stdout);
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ if (print_vm_stats_on_page_processing == TRUE) {
+ print_vm_statistics();
+ }
+ process_pages(pages_to_process, page_op);
+ ok_to_print_stablity_message = TRUE;
+ }
+ }
+
+ while (current_level == desired_level) {
+ get_percent_free(&current_percent);
+ if (ok_to_print_stablity_message == TRUE) {
+ print_vm_statistics();
+ printf("\nStabilizing at Percent: %d Level: %d", current_percent, current_level);
+ fflush(stdout);
+ ok_to_print_stablity_message = FALSE;
+ previous_page_op = 0;
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ stabilized_percentage = current_percent;
+ sleep(sleep_seconds);
+ current_level = read_sysctl_int("kern.memorystatus_vm_pressure_level");
+ }
+ }
+ }
+
+ get_percent_free(&current_percent);
+ //printf("Percent: %d Level: %d\n", current_percent, current_level);
+ sleep(1);
+
+ if (print_vm_stats) {
+ print_vm_stats_on_page_processing = TRUE;
+ }
+
+ } /* while */
+}
+
+void
+munch_for_percentage(unsigned int sleep_seconds, unsigned int wait_percent_free, unsigned int print_vm_stats)
+{
+
+ int total_pages_allocated = 0;
+ int current_stable_timer = 0; /* in seconds */
+ unsigned int current_percent = 0;
+ boolean_t page_op = PAGE_OP_FREE;
+ unsigned int pages_to_process = 0;
+ boolean_t print_vm_stats_on_page_processing = FALSE;
+ boolean_t previous_page_op = 0;
+ boolean_t ok_to_print_stablity_message = TRUE;
+
+ /* Allocate until memory level is hit. */
+
+ get_percent_free(&current_percent);
+
+ /*
+ * "wait" mode doesn't alloc, it just waits and exits. This is used
+ * while waiting for *other* processes to allocate memory.
+ */
+ if (wait_percent_free) {
+ while (current_percent > wait_percent_free) {
+ sleep(sleep_seconds);
+ get_percent_free (&current_percent);
+ }
+ return;
+ }
+
+ page_op = PAGE_OP_ALLOC;
+ previous_page_op = 0;
+
+ while (1) {
+
+ if (current_percent > desired_percent) {
+ pages_to_process = ((current_percent - desired_percent) * phys_pages) / 100;
+ page_op = PAGE_OP_ALLOC;
+ } else {
+ pages_to_process = ((desired_percent - current_percent) * phys_pages) / 100;
+ page_op = PAGE_OP_FREE;
+ }
+
+ if (pages_to_process > 0) {
+
+ if (page_op != previous_page_op) {
+ //printf("\n%s %d pages to go from %d%% to %d%% pages free\n", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", pages_to_process, current_percent, desired_percent);
+ printf("\nCMD: %s pages to go from %d%% to %d%% percent free", (page_op == PAGE_OP_ALLOC) ? "Allocating" : "Freeing", current_percent, desired_percent);
+ fflush(stdout);
+ previous_page_op = page_op;
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ if (page_op == PAGE_OP_ALLOC) {
+ total_pages_allocated += pages_to_process;
+ process_pages(pages_to_process, page_op);
+ ok_to_print_stablity_message = TRUE;
+ } else {
+
+ if (total_pages_allocated >= pages_to_process) {
+ total_pages_allocated -= pages_to_process;
+ process_pages(pages_to_process, page_op);
+ ok_to_print_stablity_message = TRUE;
+ } else {
+ get_percent_free(&current_percent);
+ if (ok_to_print_stablity_message == TRUE) {
+ printf("\nDesired Percent: %d, Current Percent: %d. No pages to free so waiting", desired_percent, current_percent);
+ fflush(stdout);
+ ok_to_print_stablity_message = FALSE;
+ }
+ }
+ }
+
+ //printf("kernel memorystatus: %d%% free, allocated %d pages total. Requested: %d\n", current_percent, total_pages_allocated, desired_percent);
+ if (print_vm_stats) {
+ print_vm_stats_on_page_processing = TRUE;
+ }
+ } else {
+ if (ok_to_print_stablity_message == TRUE) {
+ print_vm_statistics();
+ printf("\nStable at percent free: %d", current_percent);
+ fflush(stdout);
+ ok_to_print_stablity_message = FALSE;
+ } else {
+ printf(".");
+ fflush(stdout);
+ }
+
+ /* Stability has been reached; Increment current_stable_timer by sleep_seconds */
+
+ if (current_stable_timer <= requested_hysteresis_seconds){
+ current_stable_timer += sleep_seconds;
+ /* Debug only */
+ /* printf("\n Percentage Free stable for %d seconds", current_stable_timer); */
+ } else {
+ printf ("\n Maintained memory pressure to %d percent free for more than %d seconds. Stopping pressure now.", current_percent, requested_hysteresis_seconds);
+ return;
+ }
+
+ print_vm_stats_on_page_processing = FALSE;
+ }
+
+ if (print_vm_stats_on_page_processing) {
+
+ print_vm_statistics();
+
+ if (print_vm_stats_on_page_processing == TRUE) {
+ print_vm_stats_on_page_processing = FALSE;
+ }
+ }
+
+ sleep(sleep_seconds);
+
+ get_percent_free(&current_percent);
+ } /* while */
+}
+
+int
+main(int argc, char * const argv[])
+{
+ int opt;
+ unsigned int wait_percent_free = 0;
+ unsigned int current_percent = 0;
+ unsigned int print_vm_stats = 0;
+ char level[10];
+
+ while ((opt = getopt(argc, argv, "hl:p:s:w:y:vQS")) != -1) {
+ switch (opt) {
+ case 'h':
+ usage();
+ break;
+ case 'l':
+ strlcpy(level, optarg, 9);
+
+ if (strncasecmp(level, "normal", 6) == 0) {
+ desired_level = DISPATCH_MEMORYPRESSURE_NORMAL;
+ percent_for_level = 90;
+ } else if (strncasecmp(level, "warn", 4) == 0) {
+ desired_level = DISPATCH_MEMORYPRESSURE_WARN;
+ percent_for_level = 60;
+
+ } else if (strncasecmp(level, "critical", 8) == 0) {
+ desired_level = DISPATCH_MEMORYPRESSURE_CRITICAL;
+ percent_for_level = 30;
+
+ } else {
+ printf("Incorrect level. Allowed \"normal\" or \"warn\" or \"critical\". Specified: %s\n", level);
+ exit(0);
+ }
+ break;
+ case 'p':
+ desired_percent = atoi(optarg);
+ break;
+ case 's':
+ sleep_seconds = atoi(optarg);
+ break;
+ case 'w':
+ wait_percent_free = atoi(optarg);
+ break;
+ case 'y':
+ requested_hysteresis_seconds = atoi(optarg);
+ break;
+ case 'v':
+ print_vm_stats = 1;
+ break;
+ case 'Q':
+ quiet_mode_on = TRUE;
+ break;
+ case 'S':
+ simulate_mode_on = TRUE;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ if (simulate_mode_on == TRUE && desired_level == 0) {
+ printf("Expected level with -l along with \"simulated\" mode.\n");
+ return 0;
+ }
+
+ if (requested_hysteresis_seconds > 0) {
+ if (desired_percent == 0) {
+ printf("Hysteresis time may only be specified in conjunction with a non-zero value for the -p option. \n");
+ usage();
+ }
+ }
+
+ phys_mem = read_sysctl_long_long("hw.memsize");
+ phys_pages = (unsigned int) (phys_mem / PAGE_SIZE);
+
+ printf("The system has %lld (%d pages with a page size of %lu).\n", phys_mem, phys_pages, PAGE_SIZE);
+
+ print_vm_statistics();
+
+ get_percent_free(&current_percent);
+ printf("System-wide memory free percentage: %d%%\n", current_percent);
+
+ if (desired_percent == 0 && wait_percent_free == 0 && desired_level == 0) {
+ return 0;
+ }
+
+ if (simulate_mode_on == TRUE) {
+
+ /*
+ We use the sysctl "kern.memorypressure_manual_trigger" for this mode. Here's a blurb:
+
+ Supported behaviors when using the manual trigger tests.
+
+ #define TEST_LOW_MEMORY_TRIGGER_ONE 1 most suitable app is notified
+ #define TEST_LOW_MEMORY_TRIGGER_ALL 2 all apps are notified
+ #define TEST_PURGEABLE_TRIGGER_ONE 3
+ #define TEST_PURGEABLE_TRIGGER_ALL 4
+ #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ONE 5
+ #define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6
+
+ So, for example, to simulate one app getting a poke when the "pressure" reaches critical levels: "sudo sysctl -w kern.memorypressure_manual_trigger = level"
+ where level is calculated as: ((TEST_LOW_MEMORY_TRIGGER_ONE << 16) | NOTE_MEMORYSTATUS_PRESSURE_CRITICAL), which will be "65540".
+
+ For this tool, currently, we only support the "TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL" options.
+ */
+
+#define TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL 6
+
+ unsigned int var = 0;
+ size_t var_size = 0;
+ int error = 0;
+
+ var_size = sizeof(var);
+
+ var = ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL << 16) | desired_level);
+
+ error = sysctlbyname("kern.memorypressure_manual_trigger", NULL, 0, &var, var_size);
+
+ if(error) {
+ perror("sysctl: kern.memorypressure_manual_trigger failed ");
+ exit(-1);
+ }
+
+ printf("Waiting %d seconds before resetting system state\n", sleep_seconds);
+
+ sleep(sleep_seconds);
+
+ var_size = sizeof(var);
+
+ var = ((TEST_LOW_MEMORY_PURGEABLE_TRIGGER_ALL << 16) | DISPATCH_MEMORYPRESSURE_NORMAL);
+
+ error = sysctlbyname("kern.memorypressure_manual_trigger", NULL, 0, &var, var_size);
+
+ if(error) {
+ perror("sysctl: kern.memorypressure_manual_trigger failed ");
+ exit(-1);
+ }
+
+ printf("Reset system state\n");
+
+ } else {
+ range_start_addr = mmap(NULL, get_max_range_size(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 0, 0);
+
+ if (range_start_addr == MAP_FAILED) {
+ perror("mmap failed");
+ } else {
+
+ int error = 0;
+ pthread_t thread = NULL;
+
+ error = pthread_create(&thread, NULL, (void*) reference_pages, NULL);
+
+ range_current_addr = range_start_addr;
+ range_end_addr = range_start_addr + get_max_range_size();
+ start_allocing_pages = 1;
+
+ if (desired_level) {
+ tool_mode = TOOL_MODE_FOR_LEVEL;
+ munch_for_level(sleep_seconds, print_vm_stats);
+ } else {
+ tool_mode = TOOL_MODE_FOR_PERCENT;
+ munch_for_percentage(sleep_seconds, wait_percent_free, print_vm_stats);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/system_cmds/mkfile.tproj/mkfile.8 b/system_cmds/mkfile.tproj/mkfile.8
new file mode 100644
index 0000000..d67fbfc
--- /dev/null
+++ b/system_cmds/mkfile.tproj/mkfile.8
@@ -0,0 +1,47 @@
+.\" (c) 1997 Apple Computer, Inc.
+.TH MKFILE 8 "1 September 1997"
+.SH NAME
+mkfile \- create a file
+.SH SYNOPSIS
+.B mkfile
+.RB [ " -nv " ]
+.I size\c
+[\c
+.BR b | k | m | g\c
+]
+.IR filename " .\|.\|."
+.SH DESCRIPTION
+.B mkfile
+creates one or more files that are suitable for use as
+.SM NFS-\s0mounted
+swap areas. The sticky bit is set, and
+the file is padded with zeroes by default.
+Non-root users must set the sticky bit using
+chmod(1).
+The default size unit is bytes, but the following suffixes
+may be used to multiply by the given factor:
+.B b
+(512),
+.B k
+(1024),
+.B m
+(1048576), and
+.B g
+(1073741824).
+.SH OPTIONS
+.TP
+.B \-n
+Create an empty
+.IR filename .
+The size is noted, but disk blocks aren't allocated until data is
+written to them.
+.TP
+.B \-v
+Verbose. Report the names and sizes of created files.
+.SH WARNING
+If a client's swap file is removed and recreated, it must be
+re-exported before the client will be able to access it.
+This action may only be done when the client is not running.
+.SH "SEE ALSO"
+.TP
+chmod(2), stat(2), sticky(7)
diff --git a/system_cmds/mkfile.tproj/mkfile.c b/system_cmds/mkfile.tproj/mkfile.c
new file mode 100644
index 0000000..ac05c74
--- /dev/null
+++ b/system_cmds/mkfile.tproj/mkfile.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1997 Apple Computer, Inc. All Rights Reserved
+ *
+ * HISTORY
+ * 29-Aug-97 Daniel Wade (danielw) at Apple
+ * Created.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <err.h>
+
+#define BF_SZ 512 /* Size of write chunks */
+
+extern void usage(char *, char *);
+extern void create_file(char *, quad_t, int, int);
+extern void err_rm(char *, char *);
+
+int
+main(int argc, char **argv)
+{
+ char *b_num, *prog_name;
+ char *options = "nv";
+ char c;
+ off_t multiplier = 1;
+ off_t file_size;
+ size_t len;
+ int empty = 0;
+ int verbose = 0;
+ char* endptr = NULL;
+
+ prog_name = argv[0]; /* Get program name */
+ if (1 == argc)
+ usage(prog_name, options);
+
+ /* Get options */
+ opterr=1;
+
+ while ((c=getopt(argc, argv, options)) != EOF)
+ switch (c) {
+ case 'v': /* Turn on verbose setting */
+ verbose = 1;
+ break;
+ case 'n': /* Create an empty file */
+ empty = 1;
+ break;
+ default:
+ usage(prog_name, options);
+ break;
+ }
+
+ /* Stop getting options
+ */
+ argv += optind;
+ if (*argv == NULL) /* Is there a size given? */
+ usage(prog_name, options);
+
+ b_num = *argv++; /* Size of file and byte multiplier */
+ len = strlen(b_num) - 1;
+
+ if (!isdigit(b_num[len])) {
+ switch(b_num[len]) { /* Figure out multiplier */
+ case 'B':
+ case 'b':
+ multiplier = 512;
+ break;
+ case 'K':
+ case 'k':
+ multiplier = 1024;
+ break;
+ case 'M':
+ case 'm':
+ multiplier = 1024 * 1024;
+ break;
+ case 'G':
+ case 'g':
+ multiplier = 1024 * 1024 * 1024;
+ break;
+ default:
+ usage(prog_name, options);
+ }
+ }
+
+ if (*argv == NULL) /* Was a file name given? */
+ usage(prog_name, options);
+
+ if ((file_size = strtoll(b_num, &endptr, 10)) == 0 &&
+ (*endptr != 0 && endptr != &b_num[len])) {
+ err(1, "Bad file size!");
+ }
+
+ while ( *argv != NULL ) { /* Create file for each file_name */
+ create_file(*argv, file_size*multiplier, empty, verbose);
+ argv++;
+ }
+
+ return (0);
+}
+
+
+/* Create a file and make it empty (lseek) or zero'd */
+
+void
+create_file(char *file_name, quad_t size, int empty, int verbose)
+{
+ char buff[BF_SZ];
+ int fd;
+ ssize_t bytes_written = BF_SZ;
+ quad_t i;
+ mode_t mode = S_IRUSR | S_IWUSR;
+
+ /* If superuser, then set sticky bit */
+ if (!geteuid()) mode |= S_ISVTX;
+
+ if ((fd = open(file_name, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1)
+ err(1, NULL);
+
+
+ if (empty) { /* Create an empty file */
+ lseek(fd, (off_t)size-1, SEEK_SET);
+ if ( 1 != write(fd, "\0", 1))
+ err_rm(file_name, "Write Error");
+ }
+ else {
+ bzero(buff, BF_SZ);
+
+ /*
+ * First loop: write BF_SZ chunks until you have
+ * less then BF_SZ bytes to write.
+ * Second loop: write the remaining bytes.
+ * ERRORS in the write process will cause the
+ * file to be removed before the error is
+ * reported.
+ */
+ for (i = size; i > BF_SZ; i -= bytes_written) {
+ bytes_written = write (fd, buff, BF_SZ);
+ if ( bytes_written == -1 )
+ err_rm (file_name, "Write Error");
+ }
+ for (; i > 0; i -= bytes_written) {
+ bytes_written = write (fd, buff, (size_t)i);
+ if ( bytes_written == -1 )
+ err_rm (file_name, "Write Error");
+ }
+ }
+
+ if (fchmod(fd, mode)) /* Change permissions */
+ err_rm(file_name, NULL);
+
+ if ((close(fd)) == -1)
+ err_rm(file_name, NULL);
+
+ if (verbose)
+ (void)fprintf(stderr, "%s %qd bytes\n", file_name, size);
+}
+
+/* On error remove the file */
+
+void
+err_rm(char *filename, char *msg)
+{
+ unlink(filename);
+ err(1, "(%s removed) %s", filename, msg);
+}
+
+/* Print usage string */
+void
+usage(char *prog_name, char *options)
+{
+ (void)fprintf(stderr,
+ "usage: %s [-%s] size[b|k|m|g] filename ...\n", prog_name, options);
+ exit(1);
+}
diff --git a/system_cmds/mslutil/mslutil.1 b/system_cmds/mslutil/mslutil.1
new file mode 100644
index 0000000..ea4f068
--- /dev/null
+++ b/system_cmds/mslutil/mslutil.1
@@ -0,0 +1,46 @@
+.\" Copyright (c) 2017, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd March 31, 2017
+.Dt MSLUTIL 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm mslutil
+.Nd Tool to enable / disable malloc stack logging on a specific proces
+.Sh SYNOPSIS
+.Nm mslutil pid [--enable flavor] | [--disable]
+.Sh DESCRIPTION
+The
+.Nm mslutil
+utility enables/disables malloc stack logging on the process specified by
+.Nm pid.
+It requires root privileges.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl -enable
+Specifying the
+.Fl -enable
+option enables malloc stack logging, using the
+.Pa flavor
+provided.
+The supported flavors are:
+.Pp
+.Pa full
+Standard malloc stack logging that records both vm and malloc calls
+.Pp
+.Pa malloc
+Standard malloc stack logging that records only malloc calls
+.Pp
+.Pa vm
+Standard malloc stack logging that records only vm calls
+.Pp
+.Pa lite
+Lite mode of malloc stack logging.
+.\" ==========
+.It Fl -disable
+Specifying the
+.Fl -disable
+option disables any current mode of malloc stack logging.
+.\" ==========
+.El
diff --git a/system_cmds/mslutil/mslutil.c b/system_cmds/mslutil/mslutil.c
new file mode 100644
index 0000000..5738d4a
--- /dev/null
+++ b/system_cmds/mslutil/mslutil.c
@@ -0,0 +1,96 @@
+//
+// mslutil.c
+// mslutil
+//
+// Created by Christopher Deppe on 3/31/17.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/sysctl.h>
+#include <stack_logging.h>
+
+#define BSD_PID_MAX 99999 /* Copy of PID_MAX from sys/proc_internal.h. */
+
+static void print_usage()
+{
+ printf("usage: mslutil pid [--disable] | [--enable malloc | vm | full | lite | vmlite]\n");
+}
+
+static int send_msl_command(uint64_t pid, uint64_t flavor)
+{
+ uint64_t flags = flavor;
+ flags <<= 32;
+
+ flags |= (pid & 0xFFFFFFFF);
+
+ int ret = sysctlbyname("kern.memorystatus_vm_pressure_send", 0, 0, &flags, sizeof(flags));
+
+ if (ret) {
+ printf("send_msl_command - sysctl: kern.memorystatus_vm_pressure_send failed %s\n", strerror(errno));
+ } else {
+ printf("send_msl_command - success!\n");
+ }
+
+ return ret;
+}
+
+int main(int argc, const char * argv[])
+{
+ if (argc < 3) {
+ print_usage();
+ exit(1);
+ }
+
+ int ret = -1;
+
+ pid_t pid = atoi(argv[1]);
+
+ if (pid <= 0 || pid > BSD_PID_MAX) {
+ printf("Invalid pid\n");
+ exit(1);
+ }
+
+ if (strcmp(argv[2], "--enable") == 0) {
+ if (argc < 4) {
+ print_usage();
+ exit(1);
+ }
+
+ uint64_t flavor = 0;
+
+ if (strcmp(argv[3], "full") == 0) {
+ flavor = MEMORYSTATUS_ENABLE_MSL_MALLOC | MEMORYSTATUS_ENABLE_MSL_VM;
+ } else if (strcmp(argv[3], "malloc") == 0) {
+ flavor = MEMORYSTATUS_ENABLE_MSL_MALLOC;
+ } else if (strcmp(argv[3], "vm") == 0) {
+ flavor = MEMORYSTATUS_ENABLE_MSL_VM;
+ } else if (strcmp(argv[3], "lite") == 0) {
+ flavor = MEMORYSTATUS_ENABLE_MSL_LITE_FULL;
+ } else if (strcmp(argv[3], "vmlite") == 0) {
+ flavor = MEMORYSTATUS_ENABLE_MSL_LITE_VM;
+ }
+
+ if (flavor == 0) {
+ print_usage();
+ exit(1);
+ }
+
+ ret = send_msl_command(pid, flavor);
+ } else if (strcmp(argv[2], "--disable") == 0) {
+ ret = send_msl_command(pid, MEMORYSTATUS_DISABLE_MSL);
+ } else {
+ print_usage();
+ exit(1);
+ }
+
+ if (ret != 0) {
+ exit(1);
+ } else {
+ exit(0);
+ }
+}
+
+
diff --git a/system_cmds/newgrp.tproj/newgrp.1 b/system_cmds/newgrp.tproj/newgrp.1
new file mode 100644
index 0000000..af36e19
--- /dev/null
+++ b/system_cmds/newgrp.tproj/newgrp.1
@@ -0,0 +1,95 @@
+.\" Copyright (c) 2002 Tim J. Robbins.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/newgrp/newgrp.1,v 1.3 2005/01/17 07:44:25 ru Exp $
+.\"
+.Dd May 23, 2002
+.Dt NEWGRP 1
+.Os
+.Sh NAME
+.Nm newgrp
+.Nd change to a new group
+.Sh SYNOPSIS
+.Nm
+.Op Fl l
+.Op Ar group
+.Sh DESCRIPTION
+The
+.Nm
+utility creates a new shell execution environment with modified
+real and effective group IDs.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl l
+Simulate a full login.
+The environment and umask are set to what would be expected if the user
+actually logged in again.
+.El
+.Pp
+If the
+.Ar group
+operand is present, a new shell is started with the specified effective
+and real group IDs.
+The user will be prompted for a password if they are not a member of the
+specified group.
+.Pp
+Otherwise, the real, effective and supplementary group IDs are restored to
+those from the current user's password database entry.
+.Sh EXIT STATUS
+The
+.Nm
+utility attempts to start the shell regardless of whether group IDs
+were successfully changed.
+.Pp
+If an error occurs and the shell cannot be started,
+.Nm
+exits >0.
+Otherwise, the exit status of
+.Nm
+is the exit status of the shell.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr groups 1 ,
+.Xr login 1 ,
+.Xr sh 1 ,
+.Xr su 1 ,
+.Xr umask 1 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr environ 7
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v6 .
+.Sh BUGS
+Group passwords are inherently insecure as there is no way to stop
+users obtaining the crypted passwords from the group database.
+Their use is discouraged.
diff --git a/system_cmds/newgrp.tproj/newgrp.c b/system_cmds/newgrp.tproj/newgrp.c
new file mode 100644
index 0000000..3a4f412
--- /dev/null
+++ b/system_cmds/newgrp.tproj/newgrp.c
@@ -0,0 +1,352 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * 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.
+ */
+
+/*
+ * newgrp -- change to a new group
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/newgrp/newgrp.c,v 1.5 2009/12/13 03:14:06 delphij Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <grp.h>
+#include <libgen.h>
+#include <limits.h>
+#ifndef __APPLE__
+#include <login_cap.h>
+#endif /* !__APPLE__ */
+#ifdef __APPLE__
+#include <membership.h>
+#endif /* __APPLE__ */
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef __APPLE__
+#include <paths.h>
+#endif /* __APPLE__ */
+static void addgroup(const char *grpname);
+static void doshell(void);
+static int inarray(gid_t, const gid_t[], int);
+static void loginshell(void);
+static void restoregrps(void);
+static void usage(void);
+
+static struct passwd *pwd;
+static uid_t euid;
+
+extern char **environ;
+
+/* Manipulate effective user ID. */
+#define PRIV_START do { \
+ if (seteuid(euid) < 0) \
+ err(1, "seteuid"); \
+ } while (0)
+#define PRIV_END do { \
+ if (seteuid(getuid()) < 0) \
+ err(1, "seteuid"); \
+ } while (0)
+
+int
+main(int argc, char *argv[])
+{
+ int ch, login;
+
+ euid = geteuid();
+ if (seteuid(getuid()) < 0)
+ err(1, "seteuid");
+
+ if ((pwd = getpwuid(getuid())) == NULL)
+ errx(1, "unknown user");
+
+ login = 0;
+ while ((ch = getopt(argc, argv, "-l")) != -1) {
+ switch (ch) {
+ case '-': /* Obsolescent */
+ case 'l':
+ login = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) {
+ case 0:
+ restoregrps();
+ break;
+ case 1:
+ addgroup(*argv);
+ break;
+ default:
+ usage();
+ }
+
+ if (seteuid(euid) < 0)
+ err(1, "seteuid");
+ if (setuid(getuid()) < 0)
+ err(1, "setuid");
+
+ if (login)
+ loginshell();
+ else
+ doshell();
+
+ /*NOTREACHED*/
+ exit(1);
+}
+
+static void
+usage(void)
+{
+
+ fprintf(stderr, "usage: newgrp [-l] [group]\n");
+ exit(1);
+}
+
+static void
+restoregrps(void)
+{
+ int initres, setres;
+
+ PRIV_START;
+ initres = initgroups(pwd->pw_name, pwd->pw_gid);
+ setres = setgid(pwd->pw_gid);
+ PRIV_END;
+
+ if (initres < 0)
+ warn("initgroups");
+ if (setres < 0)
+ warn("setgid");
+}
+
+static void
+addgroup(const char *grpname)
+{
+ gid_t *grps;
+ long lgid, ngrps_max;
+ int dbmember, i, ngrps;
+ gid_t egid;
+ struct group *grp;
+ char *ep, *pass;
+#ifndef __APPLE__
+ char **p;
+#endif
+ char *grp_passwd;
+#ifdef __APPLE__
+ uuid_t user_uuid;
+ uuid_t group_uuid;
+ int status;
+#endif
+
+ egid = getegid();
+
+ /* Try it as a group name, then a group id. */
+ if ((grp = getgrnam(grpname)) == NULL)
+ if ((lgid = strtol(grpname, &ep, 10)) <= 0 || *ep != '\0' ||
+ (grp = getgrgid((gid_t)lgid)) == NULL ) {
+ warnx("%s: bad group name", grpname);
+ return;
+ }
+
+#ifdef __APPLE__
+ status = mbr_uid_to_uuid(pwd->pw_uid, user_uuid);
+ if (status)
+ errc(1, status, "mbr_uid_to_uuid");
+
+ status = mbr_gid_to_uuid(grp->gr_gid, group_uuid);
+ if (status)
+ errc(1, status, "mbr_gid_to_uuid");
+
+ status = mbr_check_membership(user_uuid, group_uuid, &dbmember);
+ if (status)
+ errc(1, status, "mbr_check_membership");
+#else
+ /*
+ * If the user is not a member of the requested group and the group
+ * has a password, prompt and check it.
+ */
+ dbmember = 0;
+ if (pwd->pw_gid == grp->gr_gid)
+ dbmember = 1;
+ for (p = grp->gr_mem; *p != NULL; p++)
+ if (strcmp(*p, pwd->pw_name) == 0) {
+ dbmember = 1;
+ break;
+ }
+#endif
+
+ grp_passwd = grp->gr_passwd;
+ if ((grp_passwd == NULL) || (grp_passwd[0] == '\0'))
+ grp_passwd = "*";
+ if (!dbmember && getuid() != 0) {
+ pass = getpass("Password:");
+ if (pass == NULL ||
+ strcmp(grp_passwd, crypt(pass, grp_passwd)) != 0) {
+ fprintf(stderr, "Sorry\n");
+ return;
+ }
+ }
+
+ ngrps_max = sysconf(_SC_NGROUPS_MAX) + 1;
+ if ((grps = malloc(sizeof(gid_t) * ngrps_max)) == NULL)
+ err(1, "malloc");
+ if ((ngrps = getgroups((int)ngrps_max, (gid_t *)grps)) < 0) {
+ warn("getgroups");
+ goto end;
+ }
+
+ /* Remove requested gid from supp. list if it exists. */
+ if (grp->gr_gid != egid && inarray(grp->gr_gid, grps, ngrps)) {
+ for (i = 0; i < ngrps; i++)
+ if (grps[i] == grp->gr_gid)
+ break;
+ ngrps--;
+ memmove(&grps[i], &grps[i + 1], (ngrps - i) * sizeof(gid_t));
+ PRIV_START;
+ if (setgroups(ngrps, (const gid_t *)grps) < 0) {
+ PRIV_END;
+ warn("setgroups");
+ goto end;
+ }
+ PRIV_END;
+ }
+
+ PRIV_START;
+ if (setgid(grp->gr_gid)) {
+ PRIV_END;
+ warn("setgid");
+ goto end;
+ }
+ PRIV_END;
+ grps[0] = grp->gr_gid;
+
+ /* Add old effective gid to supp. list if it does not exist. */
+ if (egid != grp->gr_gid && !inarray(egid, grps, ngrps)) {
+ if (ngrps + 1 >= ngrps_max)
+ warnx("too many groups");
+ else {
+ grps[ngrps++] = egid;
+ PRIV_START;
+ if (setgroups(ngrps, (const gid_t *)grps)) {
+ PRIV_END;
+ warn("setgroups");
+ goto end;
+ }
+ PRIV_END;
+ }
+ }
+
+end:
+ free(grps);
+}
+
+static int
+inarray(gid_t gid, const gid_t grps[], int ngrps)
+{
+ int i;
+
+ for (i = 0; i < ngrps; i++)
+ if (grps[i] == gid)
+ return (1);
+ return (0);
+}
+
+/*
+ * Set the environment to what would be expected if the user logged in
+ * again; this performs the same steps as su(1)'s -l option.
+ */
+static void
+loginshell(void)
+{
+ char *args[2], **cleanenv, *term, *ticket;
+ const char *shell;
+ char *prog, progbuf[PATH_MAX];
+#ifndef __APPLE__
+ login_cap_t *lc;
+#endif /* !__APPLE__ */
+ shell = pwd->pw_shell;
+ if (*shell == '\0')
+ shell = _PATH_BSHELL;
+ if (chdir(pwd->pw_dir) < 0) {
+ warn("%s", pwd->pw_dir);
+ chdir("/");
+ }
+
+ term = getenv("TERM");
+ ticket = getenv("KRBTKFILE");
+
+ if ((cleanenv = calloc(20, sizeof(char *))) == NULL)
+ err(1, "calloc");
+ *cleanenv = NULL;
+ environ = cleanenv;
+#ifndef __APPLE__
+ lc = login_getpwclass(pwd);
+ setusercontext(lc, pwd, pwd->pw_uid,
+ LOGIN_SETPATH|LOGIN_SETUMASK|LOGIN_SETENV);
+ login_close(lc);
+#endif /* !__APPLE__ */
+ setenv("USER", pwd->pw_name, 1);
+ setenv("SHELL", shell, 1);
+ setenv("HOME", pwd->pw_dir, 1);
+ if (term != NULL)
+ setenv("TERM", term, 1);
+ if (ticket != NULL)
+ setenv("KRBTKFILE", ticket, 1);
+
+ strlcpy(progbuf, shell, sizeof(progbuf));
+ prog = basename(progbuf);
+
+ if (asprintf(args, "-%s", prog) < 0)
+ err(1, "asprintf");
+ args[1] = NULL;
+
+ execv(shell, args);
+ err(1, "%s", shell);
+}
+
+static void
+doshell(void)
+{
+ const char *shell;
+ char *prog, progbuf[PATH_MAX];
+
+ shell = pwd->pw_shell;
+ if (*shell == '\0')
+ shell = _PATH_BSHELL;
+
+ strlcpy(progbuf, shell, sizeof(progbuf));
+ prog = basename(progbuf);
+
+ execl(shell, prog, (char *)NULL);
+ err(1, "%s", shell);
+}
diff --git a/system_cmds/nologin.tproj/nologin.5 b/system_cmds/nologin.tproj/nologin.5
new file mode 100644
index 0000000..da3b73e
--- /dev/null
+++ b/system_cmds/nologin.tproj/nologin.5
@@ -0,0 +1,96 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93
+.\" $FreeBSD: src/usr.sbin/nologin/nologin.5,v 1.15 2007/05/10 11:22:24 yar Exp $
+.\"
+.Dd May 10, 2007
+.Dt NOLOGIN 5
+.Os
+.Sh NAME
+.Nm nologin
+.Nd disallow logins
+.Sh DESCRIPTION
+Programs such as
+.Xr login 1
+disallow logins if the
+.Nm
+file exists.
+The programs display the contents of
+.Nm
+to the user if possible and interrupt the login sequence.
+This makes it simple to temporarily prevent incoming logins systemwide.
+.Pp
+To disable logins on a per-account basis,
+investigate
+.Xr nologin 8 .
+.Sh SECURITY
+The
+.Nm
+file is ignored for user root by default.
+.Sh IMPLEMENTATION NOTES
+The
+.Nm
+feature is implemented through
+.Xr login.conf 5 ,
+which allows to change the pathname of the
+file and to extend the list of users
+exempt from temporary login restriction.
+.Pp
+PAM-aware programs can be selectively configured to respect
+.Nm
+using the
+.Xr pam_nologin 8
+module via
+.Xr pam.conf 5 .
+.Pp
+The
+.Nm
+file will be removed at system boot if it resides in
+.Pa /var/run
+and
+.Va cleanvar_enable
+is set to
+.Dq Li YES
+in
+.Xr rc.conf 5 ,
+which is default.
+Therefore system reboot can effectively re-enable logins.
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/nologin" -compact
+.It Pa /var/run/nologin
+default location of
+.Nm
+.El
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr login.conf 5 ,
+.Xr pam.conf 5 ,
+.Xr rc.conf 5 ,
+.Xr nologin 8 ,
+.Xr pam_nologin 8 ,
+.Xr shutdown 8
diff --git a/system_cmds/nologin.tproj/nologin.8 b/system_cmds/nologin.tproj/nologin.8
new file mode 100644
index 0000000..04078ff
--- /dev/null
+++ b/system_cmds/nologin.tproj/nologin.8
@@ -0,0 +1,57 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93
+.\" $FreeBSD: src/usr.sbin/nologin/nologin.8,v 1.14 2004/08/07 04:27:52 imp Exp $
+.\"
+.Dd June 19, 1993
+.Dt NOLOGIN 8
+.Os
+.Sh NAME
+.Nm nologin
+.Nd politely refuse a login
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility displays a message that an account is not available and
+exits non-zero.
+It is intended as a replacement shell field for accounts that
+have been disabled.
+.Pp
+To disable all logins,
+investigate
+.Xr nologin 5 .
+.Sh SEE ALSO
+.Xr login 1 ,
+.Xr nologin 5
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Bx 4.4 .
diff --git a/system_cmds/nologin.tproj/nologin.c b/system_cmds/nologin.tproj/nologin.c
new file mode 100644
index 0000000..788c90f
--- /dev/null
+++ b/system_cmds/nologin.tproj/nologin.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2004 The FreeBSD Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/nologin/nologin.c,v 1.6 2005/01/04 20:07:12 delphij Exp $");
+
+#include <stdio.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define MESSAGE "This account is currently not available.\n"
+
+int
+main(__unused int argc, __unused char *argv[])
+{
+ const char *user, *tt;
+
+ if ((tt = ttyname(0)) == NULL)
+ tt = "UNKNOWN";
+ if ((user = getlogin()) == NULL)
+ user = "UNKNOWN";
+ openlog("nologin", LOG_CONS, LOG_AUTH);
+ syslog(LOG_CRIT, "Attempted login by %s on %s", user, tt);
+ closelog();
+
+ printf("%s", MESSAGE);
+ return 1;
+}
diff --git a/system_cmds/nvram.tproj/nvram.8 b/system_cmds/nvram.tproj/nvram.8
new file mode 100644
index 0000000..74f7b38
--- /dev/null
+++ b/system_cmds/nvram.tproj/nvram.8
@@ -0,0 +1,93 @@
+.\"
+.\" Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+.\"
+.TH nvram 8 "October 28, 2003"
+.SH NAME
+nvram \- manipulate firmware NVRAM variables
+.SH SYNOPSIS
+.B nvram
+[
+.B -p
+] [
+.B -f
+.IR filename
+] [
+.B -d
+.IR name
+] [
+.B -c
+] [
+.IR name
+[=
+.IR value
+]] ...
+.SH DESCRIPTION
+The
+.I nvram
+command allows manipulation of firmware NVRAM variables. It
+can be used to get or set a variable. It can also be used to print
+all of the variables or set a list of variables from a file.
+Changes to NVRAM variables are only saved by clean restart or shutdown.
+.LP
+In principle,
+.IR name
+can be any string. In practice, not all strings will be accepted.
+New World machines can create new variables as desired. Some variables
+require administrator privilege to get or set.
+.LP
+The given
+.IR value
+must match the data type required for
+.IR name .
+Binary data can be set using the %xx notation, where xx is the hex
+value of the byte. The type for new variables is always binary
+data.
+.SH OPTIONS
+.\" ==========
+.TP
+.BI \-d " name"
+Deletes the named firmware variable.
+.\" ==========
+.TP
+.BI \-f " filename"
+Set firmware variables from a text file. The file must be a
+list of "name value" statements. The first space on each line
+is taken to be the separator between "name" and "value". If
+the last character of a line is \\, the value extends to the next line.
+.\" ==========
+.TP
+.B \-x
+Use XML format for reading and writing variables.
+This option must be used before the
+.B \-p
+or
+.B \-f
+options, since arguments are processed in order.
+.TP
+.B \-c
+Delete all of the firmware variables.
+.TP
+.B \-p
+Print all of the firmware variables.
+.SH EXAMPLES
+.LP
+.RS
+example% nvram boot-args="-s rd=*hd:10"
+.RE
+.LP
+Set the boot-args variable to "-s rd=*hd:10". This would specify
+single user mode with the root device in hard drive partition 10.
+.LP
+.RS
+example% nvram my-variable="String One%00String Two%00%00"
+.RE
+.LP
+Create a new variable, my-variable, containing a list of two
+C-strings that is terminated by a NUL.
+.LP
+.RS
+example% nvram -d my-variable
+.RE
+.LP
+Deletes the variable named my-variable.
+.PD
diff --git a/system_cmds/nvram.tproj/nvram.c b/system_cmds/nvram.tproj/nvram.c
new file mode 100644
index 0000000..20d1927
--- /dev/null
+++ b/system_cmds/nvram.tproj/nvram.c
@@ -0,0 +1,965 @@
+/*
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+cc -o nvram nvram.c -framework CoreFoundation -framework IOKit -Wall
+*/
+
+#include <stdio.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/IOKitKeysPrivate.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <err.h>
+#include <mach/mach_error.h>
+#include <sys/stat.h>
+
+// Prototypes
+static void UsageMessage(char *message);
+static void ParseFile(char *fileName);
+static void ParseXMLFile(char *fileName);
+static void SetOrGetOFVariable(char *str);
+static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
+ CFTypeRef *valueRef);
+static kern_return_t SetOFVariable(char *name, char *value);
+static void DeleteOFVariable(char *name);
+static void PrintOFVariables(void);
+static void PrintOFVariable(const void *key,const void *value,void *context);
+static void SetOFVariableFromFile(const void *key, const void *value, void *context);
+static void ClearOFVariables(void);
+static void ClearOFVariable(const void *key,const void *value,void *context);
+static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value);
+
+static void NVRamSyncNow(char *name);
+
+// Global Variables
+static char *gToolName;
+static io_registry_entry_t gOptionsRef;
+static bool gUseXML;
+static bool gUseForceSync;
+
+#if TARGET_OS_BRIDGE /* Stuff for nvram bridge -> intel */
+#include <dlfcn.h>
+#include <libMacEFIManager/MacEFIHostInterfaceAPI.h>
+
+static kern_return_t LinkMacNVRAMSymbols(void);
+static kern_return_t GetMacOFVariable(char *name, char **value);
+static kern_return_t SetMacOFVariable(char *name, char *value);
+static kern_return_t DeleteMacOFVariable(char *name);
+
+static bool gBridgeToIntel;
+static void *gDL_handle;
+static void *gNvramInterface;
+
+static void (*hostInterfaceInitialize_fptr)(void);
+static void *(*createNvramHostInterface_fptr)(const char *handle);
+static kern_return_t (*destroyNvramHostInterface_fptr)(void *interface);
+static kern_return_t (*getNVRAMVariable_fptr)(void *interface, char *name, char **buffer, uint32_t *size);
+static kern_return_t (*setNVRAMVariable_fptr)(void *interface, char *name, char *buffer);
+static kern_return_t (*deleteNVRAMVariable_fptr)(void *interface, char *name);
+static void (*hostInterfaceDeinitialize_fptr)(void); /* may not need? */
+
+#endif /* TARGET_OS_BRIDGE */
+
+int main(int argc, char **argv)
+{
+ long cnt;
+ char *str, errorMessage[256];
+ kern_return_t result;
+ mach_port_t masterPort;
+ int argcount = 0;
+
+ // Get the name of the command.
+ gToolName = strrchr(argv[0], '/');
+ if (gToolName != 0) gToolName++;
+ else gToolName = argv[0];
+
+ result = IOMasterPort(bootstrap_port, &masterPort);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting the IOMaster port: %s",
+ mach_error_string(result));
+ }
+
+ gOptionsRef = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options");
+ if (gOptionsRef == 0) {
+ errx(1, "nvram is not supported on this system");
+ }
+
+ for (cnt = 1; cnt < argc; cnt++) {
+ str = argv[cnt];
+ if (str[0] == '-' && str[1] != 0) {
+ // Parse the options.
+ for (str += 1 ; *str; str++) {
+ switch (*str) {
+ case 'p' :
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ fprintf(stderr, "-p not supported for Mac NVRAM store.\n");
+ return 1;
+ }
+#endif
+ PrintOFVariables();
+ break;
+
+ case 'x' :
+ gUseXML = true;
+ break;
+
+ case 'f':
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ fprintf(stderr, "-f not supported for Mac NVRAM store.\n");
+ return 1;
+ }
+#endif
+ cnt++;
+ if (cnt < argc && *argv[cnt] != '-') {
+ ParseFile(argv[cnt]);
+ } else {
+ UsageMessage("missing filename");
+ }
+ break;
+
+ case 'd':
+ cnt++;
+ if (cnt < argc && *argv[cnt] != '-') {
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ if ((result = DeleteMacOFVariable(argv[cnt])) != KERN_SUCCESS) {
+ errx(1, "Error deleting variable - '%s': %s (0x%08x)", argv[cnt],
+ mach_error_string(result), result);
+ }
+ }
+ else
+#endif
+ {
+ DeleteOFVariable(argv[cnt]);
+ }
+ } else {
+ UsageMessage("missing name");
+ }
+ break;
+
+ case 'c':
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ fprintf(stderr, "-c not supported for Mac NVRAM store.\n");
+ return 1;
+ }
+#endif
+ ClearOFVariables();
+ break;
+ case 's':
+ // -s option is unadvertised -- advises the kernel more forcibly to
+ // commit the variable to nonvolatile storage
+ gUseForceSync = true;
+ break;
+#if TARGET_OS_BRIDGE
+ case 'm':
+ // used to set nvram variables on the Intel side
+ // from the ARM side (Bridge -> Mac)
+ fprintf(stdout, "Using Mac NVRAM store.\n");
+
+ LinkMacNVRAMSymbols();
+ gBridgeToIntel = true;
+ break;
+#endif
+
+ default:
+ strcpy(errorMessage, "no such option as --");
+ errorMessage[strlen(errorMessage)-1] = *str;
+ UsageMessage(errorMessage);
+ }
+ }
+ } else {
+ // Other arguments will be firmware variable requests.
+ argcount++;
+ SetOrGetOFVariable(str);
+ }
+ }
+
+ // radar:25206371
+ if (argcount == 0 && gUseForceSync == true) {
+ NVRamSyncNow("");
+ }
+
+ IOObjectRelease(gOptionsRef);
+
+ return 0;
+}
+
+// UsageMessage(message)
+//
+// Print the usage information and exit.
+//
+static void UsageMessage(char *message)
+{
+ warnx("(usage: %s)", message);
+
+ printf("%s [-x] [-p] [-f filename] [-d name] [-c] name[=value] ...\n", gToolName);
+ printf("\t-x use XML format for printing or reading variables\n");
+ printf("\t (must appear before -p or -f)\n");
+ printf("\t-p print all firmware variables\n");
+ printf("\t-f set firmware variables from a text file\n");
+ printf("\t-d delete the named variable\n");
+ printf("\t-c delete all variables\n");
+#if TARGET_OS_BRIDGE
+ printf("\t-m set nvram variables on macOS from bridgeOS\n");
+#endif
+ printf("\tname=value set named variable\n");
+ printf("\tname print variable\n");
+ printf("Note that arguments and options are executed in order.\n");
+
+ exit(1);
+}
+
+
+// States for ParseFile.
+enum {
+ kFirstColumn = 0,
+ kScanComment,
+ kFindName,
+ kCollectName,
+ kFindValue,
+ kCollectValue,
+ kContinueValue,
+ kSetenv,
+
+ kMaxStringSize = 0x800,
+ kMaxNameSize = 0x100
+};
+
+
+// ParseFile(fileName)
+//
+// Open and parse the specified file.
+//
+static void ParseFile(char *fileName)
+{
+ long state, ni = 0, vi = 0;
+ int tc;
+ char name[kMaxNameSize];
+ char value[kMaxStringSize];
+ FILE *patches;
+ kern_return_t kret;
+
+ if (gUseXML) {
+ ParseXMLFile(fileName);
+ return;
+ }
+
+ patches = fopen(fileName, "r");
+ if (patches == 0) {
+ err(1, "Couldn't open patch file - '%s'", fileName);
+ }
+
+ state = kFirstColumn;
+ while ((tc = getc(patches)) != EOF) {
+ if(ni==(kMaxNameSize-1))
+ errx(1, "Name exceeded max length of %d", kMaxNameSize);
+ if(vi==(kMaxStringSize-1))
+ errx(1, "Value exceeded max length of %d", kMaxStringSize);
+ switch (state) {
+ case kFirstColumn :
+ ni = 0;
+ vi = 0;
+ if (tc == '#') {
+ state = kScanComment;
+ } else if (tc == '\n') {
+ // state stays kFirstColumn.
+ } else if (isspace(tc)) {
+ state = kFindName;
+ } else {
+ state = kCollectName;
+ name[ni++] = tc;
+ }
+ break;
+
+ case kScanComment :
+ if (tc == '\n') {
+ state = kFirstColumn;
+ } else {
+ // state stays kScanComment.
+ }
+ break;
+
+ case kFindName :
+ if (tc == '\n') {
+ state = kFirstColumn;
+ } else if (isspace(tc)) {
+ // state stays kFindName.
+ } else {
+ state = kCollectName;
+ name[ni++] = tc;
+ }
+ break;
+
+ case kCollectName :
+ if (tc == '\n') {
+ name[ni] = 0;
+ warnx("Name must be followed by white space - '%s'", name);
+ state = kFirstColumn;
+ } else if (isspace(tc)) {
+ state = kFindValue;
+ } else {
+ name[ni++] = tc;
+ // state staus kCollectName.
+ }
+ break;
+
+ case kFindValue :
+ case kContinueValue :
+ if (tc == '\n') {
+ state = kSetenv;
+ } else if (isspace(tc)) {
+ // state stays kFindValue or kContinueValue.
+ } else {
+ state = kCollectValue;
+ value[vi++] = tc;
+ }
+ break;
+
+ case kCollectValue :
+ if (tc == '\n') {
+ if (value[vi-1] == '\\') {
+ value[vi-1] = '\r';
+ state = kContinueValue;
+ } else {
+ state = kSetenv;
+ }
+ } else {
+ // state stays kCollectValue.
+ value[vi++] = tc;
+ }
+ break;
+ }
+
+ if (state == kSetenv) {
+ name[ni] = 0;
+ value[vi] = 0;
+ if ((kret = SetOFVariable(name, value)) != KERN_SUCCESS) {
+ errx(1, "Error setting variable - '%s': %s", name,
+ mach_error_string(kret));
+ }
+ state = kFirstColumn;
+ }
+ }
+
+ if (state != kFirstColumn) {
+ errx(1, "Last line ended abruptly");
+ }
+}
+
+// ParseXMLFile(fileName)
+//
+// Open and parse the specified file in XML format,
+// and set variables appropriately.
+//
+static void ParseXMLFile(char *fileName)
+{
+ CFPropertyListRef plist;
+ int fd;
+ struct stat sb;
+ char *buffer;
+ CFReadStreamRef stream;
+ CFPropertyListFormat format = kCFPropertyListBinaryFormat_v1_0;
+
+ fd = open(fileName, O_RDONLY | O_NOFOLLOW, S_IFREG);
+ if (fd == -1) {
+ errx(1, "Could not open %s: %s", fileName, strerror(errno));
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ errx(1, "Could not fstat %s: %s", fileName, strerror(errno));
+ }
+
+ if (sb.st_size > UINT32_MAX) {
+ errx(1, "too big for our purposes");
+ }
+
+ buffer = malloc((size_t)sb.st_size);
+ if (buffer == NULL) {
+ errx(1, "Could not allocate buffer");
+ }
+
+ if (read(fd, buffer, (size_t)sb.st_size) != sb.st_size) {
+ errx(1, "Could not read %s: %s", fileName, strerror(errno));
+ }
+
+ close(fd);
+
+ stream = CFReadStreamCreateWithBytesNoCopy(kCFAllocatorDefault,
+ (const UInt8 *)buffer,
+ (CFIndex)sb.st_size,
+ kCFAllocatorNull);
+ if (stream == NULL) {
+ errx(1, "Could not create stream from serialized data");
+ }
+
+ if (!CFReadStreamOpen(stream)) {
+ errx(1, "Could not open the stream");
+ }
+
+ plist = CFPropertyListCreateWithStream(kCFAllocatorDefault,
+ stream,
+ (CFIndex)sb.st_size,
+ kCFPropertyListImmutable,
+ &format,
+ NULL);
+
+ if (plist == NULL) {
+ errx(1, "Error parsing XML file");
+ }
+
+ CFReadStreamClose(stream);
+
+ CFRelease(stream);
+
+ free(buffer);
+
+ CFDictionaryApplyFunction(plist, &SetOFVariableFromFile, 0);
+
+ CFRelease(plist);
+}
+
+// SetOrGetOFVariable(str)
+//
+// Parse the input string, then set, append or get
+// the specified firmware variable.
+//
+static void SetOrGetOFVariable(char *str)
+{
+ long set = 0;
+ long append = 0;
+ char *name;
+ char *value;
+ CFStringRef nameRef = NULL;
+ CFTypeRef valueRef = NULL;
+ CFMutableStringRef appended = NULL;
+ kern_return_t result;
+
+ // OF variable name is first.
+ name = str;
+
+ // Find the equal sign for set or += for append
+ while (*str) {
+ if (*str == '+' && *(str+1) == '=') {
+ append = 1;
+ *str++ = '\0';
+ *str++ = '\0';
+ break;
+ }
+
+ if (*str == '=') {
+ set = 1;
+ *str++ = '\0';
+ break;
+ }
+ str++;
+ }
+
+ // Read the current value if appending or if no =/+=
+ if (append == 1 || (set == 0 && append == 0)) {
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ result = GetMacOFVariable(name, &value);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting variable - '%s': %s", name,
+ mach_error_string(result));
+ }
+ nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8);
+ valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value, kCFStringEncodingUTF8);
+ free(value);
+ }
+ else
+#endif
+ {
+ result = GetOFVariable(name, &nameRef, &valueRef);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting variable - '%s': %s", name,
+ mach_error_string(result));
+ }
+ }
+ }
+
+ if (set == 1) {
+ // On sets, the OF variable's value follows the equal sign.
+ value = str;
+ }
+
+ if (append == 1) {
+ // On append, the value to append follows the += substring
+ appended = CFStringCreateMutableCopy(NULL, 0, valueRef);
+ CFStringAppendCString(appended, str, kCFStringEncodingUTF8);
+ value = (char*)CFStringGetCStringPtr(appended, kCFStringEncodingUTF8);
+ }
+
+ if (set == 1 || append == 1) {
+#if TARGET_OS_BRIDGE
+ if (gBridgeToIntel) {
+ result = SetMacOFVariable(name, value);
+ }
+ else
+#endif
+ {
+ result = SetOFVariable(name, value);
+ NVRamSyncNow(name); /* Try syncing the new data to device, best effort! */
+ }
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error setting variable - '%s': %s", name,
+ mach_error_string(result));
+ }
+ } else {
+ PrintOFVariable(nameRef, valueRef, 0);
+ }
+ if ( nameRef ) CFRelease(nameRef);
+ if ( valueRef ) CFRelease(valueRef);
+ if ( appended ) CFRelease(appended);
+}
+
+#if TARGET_OS_BRIDGE
+static kern_return_t LinkMacNVRAMSymbols()
+{
+ gDL_handle = dlopen("libMacEFIHostInterface.dylib", RTLD_LAZY);
+ if (gDL_handle == NULL) {
+ errx(errno, "Failed to dlopen libMacEFIHostInterface.dylib");
+ return KERN_FAILURE; /* NOTREACHED */
+ }
+
+ hostInterfaceInitialize_fptr = dlsym(gDL_handle, "hostInterfaceInitialize");
+ if (hostInterfaceInitialize_fptr == NULL) {
+ errx(errno, "failed to link hostInterfaceInitialize");
+ }
+ createNvramHostInterface_fptr = dlsym(gDL_handle, "createNvramHostInterface");
+ if (createNvramHostInterface_fptr == NULL) {
+ errx(errno, "failed to link createNvramHostInterface");
+ }
+ destroyNvramHostInterface_fptr = dlsym(gDL_handle, "destroyNvramHostInterface");
+ if (destroyNvramHostInterface_fptr == NULL) {
+ errx(errno, "failed to link destroyNvramHostInterface");
+ }
+ getNVRAMVariable_fptr = dlsym(gDL_handle, "getNVRAMVariable");
+ if (getNVRAMVariable_fptr == NULL) {
+ errx(errno, "failed to link getNVRAMVariable");
+ }
+ setNVRAMVariable_fptr = dlsym(gDL_handle, "setNVRAMVariable");
+ if (setNVRAMVariable_fptr == NULL) {
+ errx(errno, "failed to link setNVRAMVariable");
+ }
+ deleteNVRAMVariable_fptr = dlsym(gDL_handle, "deleteNVRAMVariable");
+ if (deleteNVRAMVariable_fptr == NULL) {
+ errx(errno, "failed to link deleteNVRAMVariable");
+ }
+ hostInterfaceDeinitialize_fptr = dlsym(gDL_handle, "hostInterfaceDeinitialize");
+ if (hostInterfaceDeinitialize_fptr == NULL) {
+ errx(errno, "failed to link hostInterfaceDeinitialize");
+ }
+
+ /* also do the initialization */
+ hostInterfaceInitialize_fptr();
+ gNvramInterface = createNvramHostInterface_fptr(NULL);
+
+ return KERN_SUCCESS;
+}
+#endif
+
+// GetOFVariable(name, nameRef, valueRef)
+//
+// Get the named firmware variable.
+// Return it and it's symbol in valueRef and nameRef.
+//
+static kern_return_t GetOFVariable(char *name, CFStringRef *nameRef,
+ CFTypeRef *valueRef)
+{
+ *nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
+ kCFStringEncodingUTF8);
+ if (*nameRef == 0) {
+ errx(1, "Error creating CFString for key %s", name);
+ }
+
+ *valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, *nameRef, 0, 0);
+ if (*valueRef == 0) return kIOReturnNotFound;
+
+ return KERN_SUCCESS;
+}
+
+#if TARGET_OS_BRIDGE
+// GetMacOFVariable(name, value)
+//
+// Get the named firmware variable from the Intel side.
+// Return the value in value
+//
+static kern_return_t GetMacOFVariable(char *name, char **value)
+{
+ uint32_t value_size;
+
+ return getNVRAMVariable_fptr(gNvramInterface, name, value, &value_size);
+}
+#endif
+
+// SetOFVariable(name, value)
+//
+// Set or create an firmware variable with name and value.
+//
+static kern_return_t SetOFVariable(char *name, char *value)
+{
+ CFStringRef nameRef;
+ CFTypeRef valueRef;
+ CFTypeID typeID;
+ kern_return_t result = KERN_SUCCESS;
+
+ nameRef = CFStringCreateWithCString(kCFAllocatorDefault, name,
+ kCFStringEncodingUTF8);
+ if (nameRef == 0) {
+ errx(1, "Error creating CFString for key %s", name);
+ }
+
+ valueRef = IORegistryEntryCreateCFProperty(gOptionsRef, nameRef, 0, 0);
+ if (valueRef) {
+ typeID = CFGetTypeID(valueRef);
+ CFRelease(valueRef);
+
+ valueRef = ConvertValueToCFTypeRef(typeID, value);
+ if (valueRef == 0) {
+ errx(1, "Error creating CFTypeRef for value %s", value);
+ } result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ } else {
+ while (1) {
+ // In the default case, try data, string, number, then boolean.
+
+ valueRef = ConvertValueToCFTypeRef(CFDataGetTypeID(), value);
+ if (valueRef != 0) {
+ result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ if (result == KERN_SUCCESS) break;
+ }
+
+ valueRef = ConvertValueToCFTypeRef(CFStringGetTypeID(), value);
+ if (valueRef != 0) {
+ result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ if (result == KERN_SUCCESS) break;
+ }
+
+ valueRef = ConvertValueToCFTypeRef(CFNumberGetTypeID(), value);
+ if (valueRef != 0) {
+ result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ if (result == KERN_SUCCESS) break;
+ }
+
+ valueRef = ConvertValueToCFTypeRef(CFBooleanGetTypeID(), value);
+ if (valueRef != 0) {
+ result = IORegistryEntrySetCFProperty(gOptionsRef, nameRef, valueRef);
+ if (result == KERN_SUCCESS) break;
+ }
+
+ break;
+ }
+ }
+
+ CFRelease(nameRef);
+
+ return result;
+}
+
+#if TARGET_OS_BRIDGE
+static kern_return_t SetMacOFVariable(char *name, char *value)
+{
+ return setNVRAMVariable_fptr(gNvramInterface, name, value);
+}
+#endif
+
+// DeleteOFVariable(name)
+//
+// Delete the named firmware variable.
+//
+//
+static void DeleteOFVariable(char *name)
+{
+ SetOFVariable(kIONVRAMDeletePropertyKey, name);
+}
+
+#if TARGET_OS_BRIDGE
+static kern_return_t DeleteMacOFVariable(char *name)
+{
+ return deleteNVRAMVariable_fptr(gNvramInterface, name);
+}
+#endif
+
+static void NVRamSyncNow(char *name)
+{
+ if (!gUseForceSync) {
+ SetOFVariable(kIONVRAMSyncNowPropertyKey, name);
+ } else {
+ SetOFVariable(kIONVRAMForceSyncNowPropertyKey, name);
+ }
+}
+
+// PrintOFVariables()
+//
+// Print all of the firmware variables.
+//
+static void PrintOFVariables(void)
+{
+ kern_return_t result;
+ CFMutableDictionaryRef dict;
+
+ result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
+ }
+
+ if (gUseXML) {
+ CFDataRef data;
+
+ data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
+ if (data == NULL) {
+ errx(1, "Error converting variables to xml");
+ }
+
+ fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
+
+ CFRelease(data);
+
+ } else {
+
+ CFDictionaryApplyFunction(dict, &PrintOFVariable, 0);
+
+ }
+
+ CFRelease(dict);
+}
+
+// PrintOFVariable(key, value, context)
+//
+// Print the given firmware variable.
+//
+static void PrintOFVariable(const void *key, const void *value, void *context)
+{
+ long cnt, cnt2;
+ CFIndex nameLen;
+ char *nameBuffer = 0;
+ const char *nameString;
+ char numberBuffer[10];
+ const uint8_t *dataPtr;
+ uint8_t dataChar;
+ char *dataBuffer = 0;
+ CFIndex valueLen;
+ char *valueBuffer = 0;
+ const char *valueString = 0;
+ uint32_t number;
+ long length;
+ CFTypeID typeID;
+
+ if (gUseXML) {
+ CFDataRef data;
+ CFDictionaryRef dict = CFDictionaryCreate(kCFAllocatorDefault, &key, &value, 1,
+ &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ if (dict == NULL) {
+ errx(1, "Error creating dictionary for variable value");
+ }
+
+ data = CFPropertyListCreateData( kCFAllocatorDefault, dict, kCFPropertyListXMLFormat_v1_0, 0, NULL );
+ if (data == NULL) {
+ errx(1, "Error creating xml plist for variable");
+ }
+
+ fwrite(CFDataGetBytePtr(data), sizeof(UInt8), CFDataGetLength(data), stdout);
+
+ CFRelease(dict);
+ CFRelease(data);
+ return;
+ }
+
+ // Get the OF variable's name.
+ nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key),
+ kCFStringEncodingUTF8) + 1;
+ nameBuffer = malloc(nameLen);
+ if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
+ nameString = nameBuffer;
+ else {
+ warnx("Unable to convert property name to C string");
+ nameString = "<UNPRINTABLE>";
+ }
+
+ // Get the OF variable's type.
+ typeID = CFGetTypeID(value);
+
+ if (typeID == CFBooleanGetTypeID()) {
+ if (CFBooleanGetValue(value)) valueString = "true";
+ else valueString = "false";
+ } else if (typeID == CFNumberGetTypeID()) {
+ CFNumberGetValue(value, kCFNumberSInt32Type, &number);
+ if (number == 0xFFFFFFFF) sprintf(numberBuffer, "-1");
+ else if (number < 1000) sprintf(numberBuffer, "%d", number);
+ else sprintf(numberBuffer, "0x%x", number);
+ valueString = numberBuffer;
+ } else if (typeID == CFStringGetTypeID()) {
+ valueLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(value),
+ kCFStringEncodingUTF8) + 1;
+ valueBuffer = malloc(valueLen + 1);
+ if ( valueBuffer && CFStringGetCString(value, valueBuffer, valueLen, kCFStringEncodingUTF8) )
+ valueString = valueBuffer;
+ else {
+ warnx("Unable to convert value to C string");
+ valueString = "<UNPRINTABLE>";
+ }
+ } else if (typeID == CFDataGetTypeID()) {
+ length = CFDataGetLength(value);
+ if (length == 0) valueString = "";
+ else {
+ dataBuffer = malloc(length * 3 + 1);
+ if (dataBuffer != 0) {
+ dataPtr = CFDataGetBytePtr(value);
+ for (cnt = cnt2 = 0; cnt < length; cnt++) {
+ dataChar = dataPtr[cnt];
+ if (isprint(dataChar) && dataChar != '%') {
+ dataBuffer[cnt2++] = dataChar;
+ } else {
+ sprintf(dataBuffer + cnt2, "%%%02x", dataChar);
+ cnt2 += 3;
+ }
+ }
+ dataBuffer[cnt2] = '\0';
+ valueString = dataBuffer;
+ }
+ }
+ } else {
+ valueString="<INVALID>";
+ }
+
+ if ((nameString != 0) && (valueString != 0))
+ printf("%s\t%s\n", nameString, valueString);
+
+ if (dataBuffer != 0) free(dataBuffer);
+ if (nameBuffer != 0) free(nameBuffer);
+ if (valueBuffer != 0) free(valueBuffer);
+}
+
+// ClearOFVariables()
+//
+// Deletes all OF variables
+//
+static void ClearOFVariables(void)
+{
+ kern_return_t result;
+ CFMutableDictionaryRef dict;
+
+ result = IORegistryEntryCreateCFProperties(gOptionsRef, &dict, 0, 0);
+ if (result != KERN_SUCCESS) {
+ errx(1, "Error getting the firmware variables: %s", mach_error_string(result));
+ }
+ CFDictionaryApplyFunction(dict, &ClearOFVariable, 0);
+
+ CFRelease(dict);
+}
+
+static void ClearOFVariable(const void *key, const void *value, void *context)
+{
+ kern_return_t result;
+ result = IORegistryEntrySetCFProperty(gOptionsRef,
+ CFSTR(kIONVRAMDeletePropertyKey), key);
+ if (result != KERN_SUCCESS) {
+ assert(CFGetTypeID(key) == CFStringGetTypeID());
+ const char *keyStr = CFStringGetCStringPtr(key, kCFStringEncodingUTF8);
+ char *keyBuffer = NULL;
+ size_t keyBufferLen = 0;
+ if (!keyStr) {
+ keyBufferLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key), kCFStringEncodingUTF8) + 1;
+ keyBuffer = (char *)malloc(keyBufferLen);
+ if (keyBuffer != NULL && CFStringGetCString(key, keyBuffer, keyBufferLen, kCFStringEncodingUTF8)) {
+ keyStr = keyBuffer;
+ } else {
+ warnx("Unable to convert property name to C string");
+ keyStr = "<UNPRINTABLE>";
+ }
+ }
+
+ warnx("Error clearing firmware variable %s: %s", keyStr, mach_error_string(result));
+ if (keyBuffer) {
+ free(keyBuffer);
+ }
+ }
+}
+
+// ConvertValueToCFTypeRef(typeID, value)
+//
+// Convert the value into a CFType given the typeID.
+//
+static CFTypeRef ConvertValueToCFTypeRef(CFTypeID typeID, char *value)
+{
+ CFTypeRef valueRef = 0;
+ long cnt, cnt2, length;
+ unsigned long number, tmp;
+
+ if (typeID == CFBooleanGetTypeID()) {
+ if (!strcmp("true", value)) valueRef = kCFBooleanTrue;
+ else if (!strcmp("false", value)) valueRef = kCFBooleanFalse;
+ } else if (typeID == CFNumberGetTypeID()) {
+ number = strtol(value, 0, 0);
+ valueRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type,
+ &number);
+ } else if (typeID == CFStringGetTypeID()) {
+ valueRef = CFStringCreateWithCString(kCFAllocatorDefault, value,
+ kCFStringEncodingUTF8);
+ } else if (typeID == CFDataGetTypeID()) {
+ length = strlen(value);
+ for (cnt = cnt2 = 0; cnt < length; cnt++, cnt2++) {
+ if (value[cnt] == '%') {
+ if (!ishexnumber(value[cnt + 1]) ||
+ !ishexnumber(value[cnt + 2])) return 0;
+ number = toupper(value[++cnt]) - '0';
+ if (number > 9) number -= 7;
+ tmp = toupper(value[++cnt]) - '0';
+ if (tmp > 9) tmp -= 7;
+ number = (number << 4) + tmp;
+ value[cnt2] = number;
+ } else value[cnt2] = value[cnt];
+ }
+ valueRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)value,
+ cnt2, kCFAllocatorDefault);
+ } else return 0;
+
+ return valueRef;
+}
+
+static void SetOFVariableFromFile(const void *key, const void *value, void *context)
+{
+ kern_return_t result;
+
+ result = IORegistryEntrySetCFProperty(gOptionsRef, key, value);
+ if ( result != KERN_SUCCESS ) {
+ long nameLen;
+ char *nameBuffer;
+ char *nameString;
+
+ // Get the variable's name.
+ nameLen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(key),
+ kCFStringEncodingUTF8) + 1;
+ nameBuffer = malloc(nameLen);
+ if( nameBuffer && CFStringGetCString(key, nameBuffer, nameLen, kCFStringEncodingUTF8) )
+ nameString = nameBuffer;
+ else {
+ warnx("Unable to convert property name to C string");
+ nameString = "<UNPRINTABLE>";
+ }
+ errx(1, "Error setting variable - '%s': %s", nameString,
+ mach_error_string(result));
+ }
+}
diff --git a/system_cmds/pagesize.tproj/pagesize.1 b/system_cmds/pagesize.tproj/pagesize.1
new file mode 100644
index 0000000..bf987d0
--- /dev/null
+++ b/system_cmds/pagesize.tproj/pagesize.1
@@ -0,0 +1,58 @@
+.\" Copyright (c) 1983, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pagesize.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/pagesize/pagesize.1,v 1.7 2002/04/20 12:16:17 charnier Exp $
+.\"
+.Dd June 6, 1993
+.Dt PAGESIZE 1
+.Os
+.Sh NAME
+.Nm pagesize
+.Nd print system page size
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility prints the size of a page of memory in bytes, as
+returned by
+.Xr getpagesize 3 .
+This program is useful in constructing portable
+shell scripts.
+.Sh SEE ALSO
+.Xr getpagesize 3
+.Sh HISTORY
+The
+.Nm
+command
+appeared in
+.Bx 4.2 .
diff --git a/system_cmds/pagesize.tproj/pagesize.sh b/system_cmds/pagesize.tproj/pagesize.sh
new file mode 100644
index 0000000..8c46ee0
--- /dev/null
+++ b/system_cmds/pagesize.tproj/pagesize.sh
@@ -0,0 +1,40 @@
+#!/bin/sh -
+#
+# Copyright (c) 1994
+# The Regents of the University of California. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of
+# California, Berkeley and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)pagesize.sh 8.1 (Berkeley) 4/3/94
+# $FreeBSD: src/usr.bin/pagesize/pagesize.sh,v 1.5 1999/08/28 01:04:48 peter Exp $
+#
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin; export PATH
+
+exec sysctl -n hw.pagesize
diff --git a/system_cmds/passwd.tproj/file_passwd.c b/system_cmds/passwd.tproj/file_passwd.c
new file mode 100644
index 0000000..62d27f3
--- /dev/null
+++ b/system_cmds/passwd.tproj/file_passwd.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include "passwd.h"
+
+#define _PASSWD_FILE "/etc/master.passwd"
+#define _COMPAT_FILE "/etc/passwd"
+#define _PASSWD_FIELDS 10
+#define BUFSIZE 8192
+
+void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
+
+static struct passwd *
+parse_user(char *line, size_t len)
+{
+ static struct passwd pw;
+ int i,j;
+ char *tokens[_PASSWD_FIELDS];
+ char *token = NULL;
+ bool comment = true;
+
+ free(pw.pw_name);
+ free(pw.pw_passwd);
+ free(pw.pw_class);
+ free(pw.pw_gecos);
+ free(pw.pw_dir);
+ free(pw.pw_shell);
+ memset(&pw, 0, sizeof(pw));
+
+ if (line == NULL) return NULL;
+
+ memset(&tokens, 0, sizeof(char *) * _PASSWD_FIELDS);
+
+ for (i = 0, j = 0; i < len && j < _PASSWD_FIELDS; ++i) {
+ int c = line[i];
+ if (!isspace(c) && c != '#') {
+ comment = false;
+ }
+ if (!comment && token == NULL) {
+ // start a new token
+ token = &line[i];
+ } else if (token && (c == ':' || c == '\n')) {
+ // end the current token
+ // special case for empty token
+ while (token[0] == ':' && token < &line[i]) {
+ tokens[j++] = strdup("");
+ ++token;
+ }
+ tokens[j++] = strndup(token, &line[i] - token);
+ token = NULL;
+ }
+ }
+
+ if (comment || j != _PASSWD_FIELDS) return NULL;
+
+ j = 0;
+ pw.pw_name = tokens[j++];
+ pw.pw_passwd = tokens[j++];
+ pw.pw_uid = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_gid = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_class = tokens[j++];
+ pw.pw_change = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_expire = atoi(tokens[j]);
+ free(tokens[j++]);
+ pw.pw_gecos = tokens[j++];
+ pw.pw_dir = tokens[j++];
+ pw.pw_shell = tokens[j++];
+
+ return &pw;
+}
+
+static struct passwd *
+find_user(FILE *fp, char *uname)
+{
+ size_t len;
+ char *line;
+
+ rewind(fp);
+
+ while ((line = fgetln(fp, &len)) != NULL) {
+ struct passwd *pw = parse_user(line, len);
+ if (pw && strcmp(uname, pw->pw_name) == 0) {
+ return pw;
+ }
+ }
+ return NULL;
+}
+
+static void
+rewrite_file(char *path, FILE *fp, struct passwd *newpw)
+{
+ int fd;
+ char *line;
+ size_t len;
+ FILE *tfp = NULL;
+ char *tempname = NULL; // temporary master.passwd file
+
+ asprintf(&tempname, "%s.XXXXXX", path);
+
+ fd = mkstemp(tempname);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+ tfp = fdopen(fd, "w+");
+ if (tfp == NULL || fchmod(fd, S_IRUSR | S_IWUSR) != 0) {
+ int save = errno;
+ unlink(tempname);
+ errno = save;
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+
+ while ((line = fgetln(fp, &len)) != NULL) {
+ struct passwd *pw = parse_user(line, len);
+
+ // if this is not the entry we're looking for or if parsing
+ // failed (likely a comment) then print the entry as is.
+ if (pw == NULL || strcmp(newpw->pw_name, pw->pw_name) != 0) {
+ fwrite(line, sizeof(char), len, tfp);
+ } else {
+ fprintf(tfp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
+ newpw->pw_name,
+ newpw->pw_passwd,
+ newpw->pw_uid,
+ newpw->pw_gid,
+ newpw->pw_class,
+ newpw->pw_change,
+ newpw->pw_expire,
+ newpw->pw_gecos,
+ newpw->pw_dir,
+ newpw->pw_shell);
+ }
+ }
+
+ // Move the temporary file into place.
+ if (fclose(tfp) != 0 || rename(tempname, path) != 0) {
+ int save = errno;
+ unlink(tempname);
+ errno = save;
+ err(EXIT_FAILURE, "%s", tempname);
+ }
+
+ free(tempname);
+}
+
+int
+file_passwd(char *uname, char *locn)
+{
+ char *ne, *oc, *nc;
+ int fd;
+ FILE *fp;
+ uid_t uid;
+ char *fname;
+ struct passwd *pw;
+ struct passwd newpw;
+
+ fname = _PASSWD_FILE;
+ if (locn != NULL) fname = locn;
+
+ fd = open(fname, O_RDONLY | O_EXLOCK);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "%s", fname);
+ }
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL) {
+ err(EXIT_FAILURE, "%s", fname);
+ }
+
+ pw = find_user(fp, uname);
+ if (pw == NULL) {
+ errx(EXIT_FAILURE, "user %s not found in %s", uname, fname);
+ }
+
+ uid = getuid();
+ if (uid != 0 && uid != pw->pw_uid) {
+ errno = EACCES;
+ err(EXIT_FAILURE, "%s", uname);
+ }
+
+ // Get the password
+ getpasswd(uname, (uid == 0), 5, 0, 0, pw->pw_passwd, &ne, &oc, &nc);
+
+ newpw.pw_name = strdup(pw->pw_name);
+ newpw.pw_passwd = strdup(ne);
+ newpw.pw_uid = pw->pw_uid;
+ newpw.pw_gid = pw->pw_gid;
+ newpw.pw_class = strdup(pw->pw_class);
+ newpw.pw_change = pw->pw_change;
+ newpw.pw_expire = pw->pw_expire;
+ newpw.pw_gecos = strdup(pw->pw_gecos);
+ newpw.pw_dir = strdup(pw->pw_dir);
+ newpw.pw_shell = strdup(pw->pw_shell);
+
+ // Rewrite the file
+ rewind(fp);
+ rewrite_file(fname, fp, &newpw);
+
+ fclose(fp);
+
+ return 0;
+}
diff --git a/system_cmds/passwd.tproj/nis_passwd.c b/system_cmds/passwd.tproj/nis_passwd.c
new file mode 100644
index 0000000..1525096
--- /dev/null
+++ b/system_cmds/passwd.tproj/nis_passwd.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Portions Copyright (c) 1998 by Apple Computer, Inc.
+ * Portions Copyright (c) 1988 by Sun Microsystems, Inc.
+ * Portions Copyright (c) 1988 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "passwd.h"
+
+#ifdef INFO_NIS
+
+/* update a user's password in NIS. This was based on the Sun implementation
+ * we used in NEXTSTEP, although I've added some stuff from OpenBSD. And
+ * it uses the API to support Rhapsody's proprietry infosystem switch.
+ * lukeh
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pwd.h>
+#include <netinet/in.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/rpc.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+#include <rpcsvc/yppasswd.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <errno.h>
+
+extern int getrpcport(char *, int, int, int);
+extern void getpasswd(char *, int, int, int, int, char *, char **, char**, char **);
+
+static struct passwd *ypgetpwnam(char *name, char *domain);
+static struct passwd *interpret(struct passwd *pwent, char *line);
+
+int nis_passwd(char *uname, char *domain)
+{
+ int ans, port, ok = -1;
+ char *master;
+ char *ne; /* new encrypted password */
+ char *oc; /* old cleartext password */
+ char *nc; /* new cleartext password */
+ static struct yppasswd yppasswd;
+ struct passwd *pwd;
+ int uid;
+ struct timeval tv;
+ CLIENT *cl;
+
+ if (domain == NULL)
+ {
+ if (yp_get_default_domain(&domain) != 0)
+ {
+ (void)fprintf(stderr, "can't get domain\n");
+ exit(1);
+ }
+ }
+
+ if (yp_master(domain, "passwd.byname", &master) != 0)
+ {
+ (void)fprintf(stderr, "can't get master for passwd file\n");
+ exit(1);
+ }
+
+ port = getrpcport(master, YPPASSWDPROG, YPPASSWDPROC_UPDATE,
+ IPPROTO_UDP);
+ if (port == 0)
+ {
+ (void)fprintf(stderr, "%s is not running yppasswd daemon\n",
+ master);
+ exit(1);
+ }
+ if (port >= IPPORT_RESERVED)
+ {
+ (void)fprintf(stderr,
+ "yppasswd daemon is not running on privileged port\n");
+ exit(1);
+ }
+
+ pwd = ypgetpwnam(uname, domain);
+ if (pwd == NULL)
+ {
+ (void)fprintf(stderr, "user %s not found\n", uname);
+ exit(1);
+ }
+
+ uid = getuid();
+ if (uid != 0 && uid != pwd->pw_uid)
+ {
+ (void)fprintf(stderr, "you may only change your own password\n");
+ exit(1);
+ }
+
+ getpasswd(uname, 0, 5, 0, 0, pwd->pw_passwd, &ne, &oc, &nc);
+
+ yppasswd.oldpass = oc;
+ yppasswd.newpw.pw_name = pwd->pw_name;
+ yppasswd.newpw.pw_passwd = ne;
+ yppasswd.newpw.pw_uid = pwd->pw_uid;
+ yppasswd.newpw.pw_gid = pwd->pw_gid;
+ yppasswd.newpw.pw_gecos = pwd->pw_gecos;
+ yppasswd.newpw.pw_dir = pwd->pw_dir;
+ yppasswd.newpw.pw_shell = pwd->pw_shell;
+
+ cl = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
+ if (cl == NULL)
+ {
+ (void)fprintf(stderr, "could not contact yppasswdd on %s\n", master);
+ exit(1);
+ }
+ cl->cl_auth = authunix_create_default();
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ ans = clnt_call(cl, YPPASSWDPROC_UPDATE,
+ (xdrproc_t)xdr_yppasswd, &yppasswd, (xdrproc_t)xdr_int, &ok, tv);
+
+ if (ans != 0)
+ {
+ clnt_perrno(ans);
+ (void)fprintf(stderr, "\n");
+ (void)fprintf(stderr, "couldn't change passwd\n");
+ exit(1);
+ }
+ if (ok != 0)
+ {
+ (void)fprintf(stderr, "couldn't change passwd\n");
+ exit(1);
+ }
+ return(0);
+}
+
+static char *
+pwskip(register char *p)
+{
+ while (*p && *p != ':' && *p != '\n')
+ ++p;
+ if (*p)
+ *p++ = 0;
+ return (p);
+}
+
+static struct passwd *
+interpret(struct passwd *pwent, char *line)
+{
+ register char *p = line;
+
+ pwent->pw_passwd = "*";
+ pwent->pw_uid = 0;
+ pwent->pw_gid = 0;
+ pwent->pw_gecos = "";
+ pwent->pw_dir = "";
+ pwent->pw_shell = "";
+#ifndef __SLICK__
+ pwent->pw_change = 0;
+ pwent->pw_expire = 0;
+ pwent->pw_class = "";
+#endif
+
+ /* line without colon separators is no good, so ignore it */
+ if(!strchr(p, ':'))
+ return(NULL);
+
+ pwent->pw_name = p;
+ p = pwskip(p);
+ pwent->pw_passwd = p;
+ p = pwskip(p);
+ pwent->pw_uid = (uid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gid = (gid_t)strtoul(p, NULL, 10);
+ p = pwskip(p);
+ pwent->pw_gecos = p;
+ p = pwskip(p);
+ pwent->pw_dir = p;
+ p = pwskip(p);
+ pwent->pw_shell = p;
+ while (*p && *p != '\n')
+ p++;
+ *p = '\0';
+ return (pwent);
+}
+
+
+static struct passwd *
+ypgetpwnam(char *nam, char *domain)
+{
+ static struct passwd pwent;
+ char *val;
+ int reason, vallen;
+ static char *__yplin = NULL;
+
+ reason = yp_match(domain, "passwd.byname", nam, (int)strlen(nam),
+ &val, &vallen);
+ switch(reason) {
+ case 0:
+ break;
+ default:
+ return (NULL);
+ break;
+ }
+ val[vallen] = '\0';
+ if (__yplin)
+ free(__yplin);
+ __yplin = (char *)malloc(vallen + 1);
+ strcpy(__yplin, val);
+ free(val);
+
+ return(interpret(&pwent, __yplin));
+}
+
+#endif /* INFO_NIS */
diff --git a/system_cmds/passwd.tproj/od_passwd.c b/system_cmds/passwd.tproj/od_passwd.c
new file mode 100644
index 0000000..f24883a
--- /dev/null
+++ b/system_cmds/passwd.tproj/od_passwd.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/sysctl.h>
+
+#include "passwd.h"
+
+#ifdef INFO_OPEN_DIRECTORY
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <OpenDirectory/OpenDirectory.h>
+#include <OpenDirectory/OpenDirectoryPriv.h>
+
+extern char* progname;
+int master_mode;
+
+static int
+cfprintf(FILE* file, const char* format, ...) {
+ char* cstr;
+ int result = 0;
+ va_list args;
+ va_start(args, format);
+ CFStringRef formatStr = CFStringCreateWithCStringNoCopy(NULL, format, kCFStringEncodingUTF8, kCFAllocatorNull);
+ if (formatStr) {
+ CFStringRef str = CFStringCreateWithFormatAndArguments(NULL, NULL, formatStr, args);
+ if (str) {
+ size_t size = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1;
+ va_end(args);
+ cstr = malloc(size);
+ if (cstr && CFStringGetCString(str, cstr, size, kCFStringEncodingUTF8)) {
+ result = fprintf(file, "%s", cstr);
+ free(cstr);
+ }
+ CFRelease(str);
+ }
+ CFRelease(formatStr);
+ }
+ return result;
+}
+
+static void
+show_error(CFErrorRef error) {
+ if (error) {
+ CFStringRef desc = CFErrorCopyDescription(error);
+ if (desc) {
+ cfprintf(stderr, "%s: %@", progname, desc);
+ CFRelease(desc);
+ }
+ desc = CFErrorCopyFailureReason(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ desc = CFErrorCopyRecoverySuggestion(error);
+ if (desc) cfprintf(stderr, " %@", desc);
+
+ fprintf(stderr, "\n");
+ }
+}
+
+int
+od_passwd(char* uname, char* locn, char* aname)
+{
+ int change_pass_on_self;
+ CFErrorRef error = NULL;
+ CFStringRef username = NULL;
+ CFStringRef location = NULL;
+ CFStringRef authname = NULL;
+ ODNodeRef node = NULL;
+ ODRecordRef rec = NULL;
+ CFStringRef oldpass = NULL;
+ CFStringRef newpass = NULL;
+
+ if (uname == NULL)
+ return -1;
+
+ /*
+ * If no explicit authorization name was specified (via -u)
+ * then default to the target user.
+ */
+ if (!aname) {
+ aname = strdup(uname);
+ }
+
+ master_mode = (geteuid() == 0);
+ change_pass_on_self = (strcmp(aname, uname) == 0);
+
+ if (locn) {
+ location = CFStringCreateWithCString(NULL, locn, kCFStringEncodingUTF8);
+ }
+
+ if (aname) {
+ authname = CFStringCreateWithCString(NULL, aname, kCFStringEncodingUTF8);
+ }
+
+ if (uname) {
+ username = CFStringCreateWithCString(NULL, uname, kCFStringEncodingUTF8);
+ if (!username) return -1;
+ }
+
+ /*
+ * Copy the record from the specified node, or perform a search.
+ */
+ if (location) {
+ node = ODNodeCreateWithName(NULL, kODSessionDefault, location, &error);
+ } else {
+ node = ODNodeCreateWithNodeType(NULL, kODSessionDefault, kODNodeTypeAuthentication, &error);
+ }
+
+ if (node) {
+ rec = ODNodeCopyRecord(node, kODRecordTypeUsers, username, NULL, &error );
+ CFRelease(node);
+ }
+
+ if (!rec) {
+ if (error) {
+ show_error(error);
+ } else {
+ fprintf(stderr, "%s: Unknown user name '%s'.\n", progname, uname);
+ }
+ return -1;
+ }
+
+ /*
+ * Get the actual location.
+ */
+ CFArrayRef values = NULL;
+ values = ODRecordCopyValues(rec, kODAttributeTypeMetaNodeLocation, &error);
+ location = (values && CFArrayGetCount(values) > 0) ? CFArrayGetValueAtIndex(values, 0) : location;
+
+ printf("Changing password for %s.\n", uname);
+
+ bool isSecureToken = false;
+ if (master_mode) {
+ CFArrayRef authorityValues = NULL;
+ authorityValues = ODRecordCopyValues(rec, kODAttributeTypeAuthenticationAuthority, &error);
+ if (authorityValues != NULL) {
+ isSecureToken = CFArrayContainsValue(authorityValues, CFRangeMake(0, CFArrayGetCount(authorityValues)), (const void *)CFSTR(";SecureToken;"));
+ CFRelease(authorityValues);
+ }
+ }
+
+ /*
+ * Prompt for password if not super-user, or if changing a remote node, or if changing a record that uses SecureToken.
+ */
+ int needs_auth = (!master_mode || CFStringCompareWithOptions(location, CFSTR("/Local/"), CFRangeMake(0, 7), 0) != kCFCompareEqualTo || isSecureToken);
+
+ if (needs_auth) {
+ char prompt[BUFSIZ];
+ if (change_pass_on_self) {
+ strlcpy(prompt, "Old password:", sizeof(prompt));
+ } else {
+ snprintf(prompt, sizeof(prompt), "Password for %s:", aname);
+ }
+ char *p = getpass( prompt );
+ if (p) {
+ oldpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ memset(p, 0, strlen(p));
+
+ if (!change_pass_on_self) {
+ if (!ODRecordSetNodeCredentials(rec, authname, oldpass, &error)) {
+ show_error(error);
+ exit(1);
+ }
+ CFRelease(oldpass);
+ oldpass = NULL;
+ }
+ }
+ }
+
+ for (;;) {
+ char *p = getpass("New password:");
+ if (p && strlen(p) > 0) {
+ newpass = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ memset(p, 0, strlen(p));
+ } else {
+ printf("Password unchanged.\n");
+ exit(0);
+ }
+
+ p = getpass("Retype new password:");
+ if (p) {
+ CFStringRef verify = CFStringCreateWithCString(NULL, p, kCFStringEncodingUTF8);
+ if (!verify || !CFEqual(newpass, verify)) {
+ if (verify) CFRelease(verify);
+ printf("Mismatch; try again, EOF to quit.\n");
+ } else {
+ CFRelease(verify);
+ break;
+ }
+ }
+ }
+
+ ODRecordChangePassword(rec, oldpass, newpass, &error);
+
+ if (error) {
+ show_error(error);
+ exit(1);
+ }
+
+ if (oldpass) CFRelease(oldpass);
+ if (newpass) CFRelease(newpass);
+
+#if 0
+ if ( status != eDSNoErr ) {
+ switch( status )
+ {
+ case eDSAuthPasswordTooShort:
+ errMsgStr = "The new password is too short.";
+ break;
+
+ case eDSAuthPasswordTooLong:
+ errMsgStr = "The new password is too long.";
+ break;
+
+ case eDSAuthPasswordNeedsLetter:
+ errMsgStr = "The new password must contain a letter.";
+ break;
+
+ case eDSAuthPasswordNeedsDigit:
+ errMsgStr = "The new password must contain a number.";
+ break;
+
+ default:
+ errMsgStr = "Sorry";
+ }
+ fprintf(stderr, "%s\n", errMsgStr);
+ exit(1);
+#endif
+ return 0;
+}
+
+#endif /* INFO_OPEN_DIRECTORY */
diff --git a/system_cmds/passwd.tproj/pam_passwd.c b/system_cmds/passwd.tproj/pam_passwd.c
new file mode 100644
index 0000000..aabf2f1
--- /dev/null
+++ b/system_cmds/passwd.tproj/pam_passwd.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>
+#include "passwd.h"
+
+#ifdef INFO_PAM
+
+#include <security/pam_appl.h>
+#include <security/openpam.h> /* for openpam_ttyconv() */
+
+extern char* progname;
+static pam_handle_t *pamh;
+static struct pam_conv pamc;
+
+int
+pam_passwd(char* uname)
+{
+ int retval = PAM_SUCCESS;
+
+ /* Initialize PAM. */
+ pamc.conv = &openpam_ttyconv;
+ pam_start(progname, uname, &pamc, &pamh);
+
+ /* Authenticate. */
+ if (PAM_SUCCESS != (retval = pam_authenticate(pamh, 0)))
+ goto pamerr;
+
+ /* Authorize. */
+ if (PAM_SUCCESS != (retval = pam_acct_mgmt(pamh, 0)) && PAM_NEW_AUTHTOK_REQD != retval)
+ goto pamerr;
+
+ printf("Changing password for %s.\n", uname);
+
+ /* Change the password. */
+ if (PAM_SUCCESS != (retval = pam_chauthtok(pamh, 0)))
+ goto pamerr;
+
+ /* Set the credentials. */
+ if (PAM_SUCCESS != (retval = pam_setcred(pamh, PAM_ESTABLISH_CRED)))
+ goto pamerr;
+
+ /* Open the session. */
+ if (PAM_SUCCESS != (retval = pam_open_session(pamh, 0)))
+ goto pamerr;
+
+ /* Close the session. */
+ if (PAM_SUCCESS != (retval = pam_close_session(pamh, 0)))
+ goto pamerr;
+
+pamerr:
+ /* Print an error, if needed. */
+ if (PAM_SUCCESS != retval)
+ fprintf(stderr, "%s: %s\n", progname, pam_strerror(pamh, retval));
+
+ /* Terminate PAM. */
+ pam_end(pamh, retval);
+ return retval;
+}
+
+#endif /* INFO_PAM */
diff --git a/system_cmds/passwd.tproj/passwd.1 b/system_cmds/passwd.tproj/passwd.1
new file mode 100644
index 0000000..fd1cef1
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.1
@@ -0,0 +1,134 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)passwd.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd August 18, 2008
+.Dt PASSWD 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm passwd
+.Nd modify a user's password
+.Sh SYNOPSIS
+.Nm passwd
+.Op Fl i Ar infosystem Op Fl l Ar location
+.Op Fl u Ar authname
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility changes the user's password.
+If the user is not the super-user,
+.Nm
+first prompts for the current password and will not continue unless the correct
+password is entered.
+.Pp
+When entering the new password, the characters entered do not echo, in order to
+avoid the password being seen by a passer-by.
+The
+.Nm
+utility prompts for the new password twice in order to detect typing errors.
+.Pp
+The new password should be at least six characters long
+and not purely alphabetic.
+Its total length should be less than
+.Dv _PASSWORD_LEN
+(currently 128 characters),
+although some directory systems allow longer passwords.
+Numbers, upper
+case letters, and meta characters are encouraged.
+.Pp
+Once the password has been verified,
+.Nm
+communicates the new password to the directory system.
+.Bl -tag -width flag
+.It Fl i Ar infosystem
+This option specifies where the password update should be applied.
+Under Mac OS X 10.5 and later, supported directory systems are:
+.Bl -tag -width flag
+.It Ar PAM
+(default) Pluggable Authentication Modules.
+.It Ar opendirectory
+A system conforming to Open Directory APIs and supporting updates
+(including LDAP, etc).
+If no -l option is specified, the search node is used.
+.It Ar file
+The local flat-files (included for legacy configurations).
+.It Ar nis
+A remote NIS server containing the user's password.
+.El
+.It Fl l Ar location
+This option causes the password to be updated in the given location
+of the chosen directory system.
+.Bl -tag -width flag
+.It for file,
+location may be a file name (/etc/master.passwd is the default)
+.It for nis,
+location may be a NIS domainname
+.It for opendirectory,
+location may be a directory node name
+.It for PAM,
+location is not used
+.El
+.It Fl u Ar authname
+This option specifies the user name to use when authenticating to
+the directory node.
+.It Ar user
+This optional argument specifies the user account whose password will be
+changed. This account's current password may be required, even when run as the
+super-user, depending on the directory system.
+.El
+.Sh FILES
+.Bl -tag -width /etc/master.passwd -compact
+.It Pa /etc/master.passwd
+The user database
+.It Pa /etc/passwd
+A Version 7 format password file
+.It Pa /etc/passwd.XXXXXX
+Temporary copy of the password file
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr login 1 ,
+.Xr dscl 1 ,
+.Xr passwd 5 ,
+.Xr pwd_mkdb 8 ,
+.Xr vipw 8
+.Rs
+.%A Robert Morris
+.%A Ken Thompson
+.%T "UNIX password security"
+.Re
+.Sh HISTORY
+A
+.Nm passwd
+command appeared in
+.At v6 .
diff --git a/system_cmds/passwd.tproj/passwd.c b/system_cmds/passwd.tproj/passwd.c
new file mode 100644
index 0000000..877036e
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <TargetConditionals.h>
+
+#define _PASSWD_FILE "/etc/master.passwd"
+
+#include <stdio.h>
+#include <errno.h>
+#include <pwd.h>
+#include <libc.h>
+#include <ctype.h>
+#include <string.h>
+#include "passwd.h"
+
+#ifdef __SLICK__
+#define _PASSWORD_LEN 8
+#endif
+
+char* progname = "passwd";
+
+static char *saltchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./";
+
+void
+getpasswd(char *name, int isroot, int minlen, int mixcase, int nonalpha,
+ char *old_pw, char **new_pw, char **old_clear, char **new_clear)
+{
+ int i, tries, pw_ok, upper, lower, alpha, notalpha;
+ size_t len;
+ int isNull;
+ char *p;
+ static char obuf[_PASSWORD_LEN+1];
+ static char nbuf[_PASSWORD_LEN+1];
+ char salt[9];
+
+ printf("Changing password for %s.\n", name);
+
+ p = "";
+ isNull = 0;
+ if (old_pw == NULL) isNull = 1;
+ if ((isNull == 0) && (old_pw[0] == '\0')) isNull = 1;
+ if ((isroot == 0) && (isNull == 0))
+ {
+ p = getpass("Old password:");
+ if (strcmp(crypt(p, old_pw), old_pw))
+ {
+ errno = EACCES;
+ fprintf(stderr, "Sorry\n");
+ exit(1);
+ }
+ }
+ //strcpy(obuf, p);
+ snprintf( obuf, sizeof(obuf), "%s", p );
+
+ tries = 0;
+ nbuf[0] = '\0';
+ for (;;)
+ {
+ p = getpass("New password:");
+ if (!*p)
+ {
+ printf("Password unchanged.\n");
+ exit(0);
+ }
+
+ tries++;
+ len = strlen(p);
+ upper = 0;
+ lower = 0;
+ alpha = 0;
+ notalpha = 0;
+ for (i = 0; i < len; i++)
+ {
+ if (isupper(p[i])) upper++;
+ if (islower(p[i])) lower++;
+ if (isalpha(p[i])) alpha++;
+ else notalpha++;
+ }
+
+
+ pw_ok = 1;
+ if (len < minlen) pw_ok = 0;
+ if ((mixcase == 1) && ((upper == 0) || (lower == 0))) pw_ok = 0;
+ if ((nonalpha == 1) && (notalpha == 0)) pw_ok = 0;
+
+ /*
+ * An insistent root may override security options.
+ */
+ if ((isroot == 1) && (tries > 2)) pw_ok = 1;
+
+ /*
+ * A very insistent user may override security options.
+ */
+ if (tries > 4) pw_ok = 1;
+
+ if (pw_ok == 0)
+ {
+ if (len < minlen)
+ printf("Password must be at least %d characters long.\n", minlen);
+ if ((mixcase == 1) && ((upper == 0) || (lower == 0)))
+ printf("Password must contain both upper and lower case characters.\n");
+ if ((nonalpha == 1) && (notalpha == 0))
+ printf("Password must contain non-alphabetic characters.\n");
+ continue;
+ }
+
+ //strcpy(nbuf, p);
+ snprintf( nbuf, sizeof(nbuf), "%s", p );
+
+ if (!strcmp(nbuf, getpass("Retype new password:"))) break;
+
+ printf("Mismatch; try again, EOF to quit.\n");
+ }
+
+ /*
+ * Create a random salt
+ */
+ srandom((int)time((time_t *)NULL));
+ salt[0] = saltchars[random() % strlen(saltchars)];
+ salt[1] = saltchars[random() % strlen(saltchars)];
+ salt[2] = '\0';
+ *new_pw = crypt(nbuf, salt);
+
+ *old_clear = obuf;
+ *new_clear = nbuf;
+ return;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [-i infosystem] -l location]] [-u authname] [name]\n", progname);
+ fprintf(stderr, " infosystem:\n");
+ fprintf(stderr, " file\n");
+ fprintf(stderr, " NIS\n");
+ fprintf(stderr, " OpenDirectory\n");
+ fprintf(stderr, " PAM\n");
+ fprintf(stderr, " location (for infosystem):\n");
+ fprintf(stderr, " file location is path to file (default is %s)\n", _PASSWD_FILE);
+ fprintf(stderr, " NIS location is NIS domain name\n");
+ fprintf(stderr, " OpenDirectory location is directory node name\n");
+ fprintf(stderr, " PAM location is not used\n");
+ exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char* user = NULL;
+ char* locn = NULL;
+ char* auth = NULL;
+ int infosystem, ch;
+ int free_user = 0;
+ int res = -1;
+
+#ifdef INFO_PAM
+ infosystem = INFO_PAM;
+#else
+#ifdef INFO_OPEN_DIRECTORY
+ infosystem = INFO_OPEN_DIRECTORY;
+#else
+ infosystem = INFO_FILE;
+#endif
+#endif
+
+#ifdef INFO_OPEN_DIRECTORY
+ /* PAM is the default infosystem, but we still want to use OpenDirectory directly when run by root */
+ if (0 == getuid())
+ infosystem = INFO_OPEN_DIRECTORY;
+#endif
+
+ while ((ch = getopt(argc, argv, "i:l:u:")) != -1)
+ switch(ch) {
+ case 'i':
+ if (!strcasecmp(optarg, "file")) {
+ infosystem = INFO_FILE;
+#ifdef INFO_NIS
+ } else if (!strcasecmp(optarg, "NIS")) {
+ infosystem = INFO_NIS;
+ } else if (!strcasecmp(optarg, "YP")) {
+ infosystem = INFO_NIS;
+#endif
+#ifdef INFO_OPEN_DIRECTORY
+ } else if (!strcasecmp(optarg, "opendirectory")) {
+ infosystem = INFO_OPEN_DIRECTORY;
+#endif
+#ifdef INFO_PAM
+ } else if (!strcasecmp(optarg, "PAM")) {
+ infosystem = INFO_PAM;
+#endif
+ } else {
+ fprintf(stderr, "%s: Unknown info system \'%s\'.\n",
+ progname, optarg);
+ usage();
+ }
+ break;
+ case 'l':
+ locn = optarg;
+ break;
+ case 'u':
+ auth = optarg;
+ break;
+ case '?':
+ default:
+ usage();
+ break;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 1) {
+ usage();
+ } else if (argc == 1) {
+ user = argv[0];
+ }
+
+#ifdef INFO_PAM
+ if (INFO_PAM == infosystem && NULL != locn)
+ usage();
+#endif
+
+ if (user == NULL)
+ {
+ /*
+ * Verify that the login name exists.
+ * lukeh 24 Dec 1997
+ */
+
+ /* getlogin() is the wrong thing to use here because it returns the wrong user after su */
+ /* sns 5 Jan 2005 */
+
+ struct passwd * userRec = getpwuid(getuid());
+ if (userRec != NULL && userRec->pw_name != NULL) {
+ /* global static mem is volatile; must strdup */
+ user = strdup(userRec->pw_name);
+ free_user = 1;
+ }
+
+ if (user == NULL)
+ {
+ fprintf(stderr, "you don't have a login name\n");
+ exit(1);
+ }
+ }
+
+ switch (infosystem)
+ {
+ case INFO_FILE:
+ res = file_passwd(user, locn);
+ break;
+#ifdef INFO_NIS
+ case INFO_NIS:
+ res = nis_passwd(user, locn);
+ break;
+#endif
+#ifdef INFO_OPEN_DIRECTORY
+ case INFO_OPEN_DIRECTORY:
+ res = od_passwd(user, locn, auth);
+ break;
+#endif
+#ifdef INFO_PAM
+ case INFO_PAM:
+ res = pam_passwd(user);
+ break;
+#endif
+ }
+
+ if (res == 0)
+ {
+ printf("\n");
+ printf("################################### WARNING ###################################\n");
+ printf("# This tool does not update the login keychain password. #\n");
+ printf("# To update it, run `security set-keychain-password` as the user in question, #\n");
+ printf("# or as root providing a path to such user's login keychain. #\n");
+ printf("###############################################################################\n");
+ printf("\n");
+ }
+
+ if (free_user == 1)
+ free(user);
+
+ exit(0);
+}
diff --git a/system_cmds/passwd.tproj/passwd.entitlements b/system_cmds/passwd.tproj/passwd.entitlements
new file mode 100644
index 0000000..a63c168
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.entitlements
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.keystore.console</key>
+ <true/>
+ <key>com.apple.private.opendirectoryd.identity</key>
+ <true/>
+ <key>com.apple.private.security.clear-library-validation</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/passwd.tproj/passwd.h b/system_cmds/passwd.tproj/passwd.h
new file mode 100644
index 0000000..60109db
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2011-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <TargetConditionals.h>
+
+#define INFO_FILE 1
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#define INFO_NIS 2
+#define INFO_OPEN_DIRECTORY 3
+#define INFO_PAM 4
+#endif
+
+extern int file_passwd(char *, char *);
+#ifdef INFO_NIS
+extern int nis_passwd(char *, char *);
+#endif
+#ifdef INFO_OPEN_DIRECTORY
+extern int od_passwd(char *, char *, char*);
+#endif
+#ifdef INFO_PAM
+extern int pam_passwd(char *);
+#endif
+
+void
+getpasswd(char *name, int isroot, int minlen, int mixcase, int nonalpha,
+ char *old_pw, char **new_pw, char **old_clear, char **new_clear);
diff --git a/system_cmds/passwd.tproj/passwd.pam b/system_cmds/passwd.tproj/passwd.pam
new file mode 100644
index 0000000..9ac660f
--- /dev/null
+++ b/system_cmds/passwd.tproj/passwd.pam
@@ -0,0 +1,5 @@
+# passwd: auth account
+auth required pam_permit.so
+account required pam_opendirectory.so
+password required pam_opendirectory.so
+session required pam_permit.so
diff --git a/system_cmds/proc_uuid_policy.tproj/proc_uuid_policy.1 b/system_cmds/proc_uuid_policy.tproj/proc_uuid_policy.1
new file mode 100644
index 0000000..f7398dd
--- /dev/null
+++ b/system_cmds/proc_uuid_policy.tproj/proc_uuid_policy.1
@@ -0,0 +1,54 @@
+.\" Copyright (c) 2016, Apple Inc. All rights reserved.
+.\"
+.Dd March 14, 2016
+.Dt PROC_UUID_POLICY 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm proc_uuid_policy
+.Nd Set UUID policy with the kernel
+.Sh SYNOPSIS
+.Nm
+.Ar verb
+.Ar policy
+.Ar uuid | path
+.Sh DESCRIPTION
+.Nm
+sets policy for a specific UUID or mach-o file with the kernel
+.Pp
+The uuid may be a uuid of the form 1A213FB4-B430-333F-AC63-891678070AFE
+or a path to a valid mach-o executable.
+.Nm
+will extract the LC_UUID load commands from the executable.
+.Pp
+.Sh VERBS
+The verbs are as follows:
+.Bl -tag -width indent
+.\" ==========
+.It clear
+Clear the policy for the given UUID with PROC_UUID_POLICY_OPERATION_CLEAR.
+.\" ==========
+.It add
+Add the policy for the given UUID with PROC_UUID_POLICY_OPERATION_ADD.
+.\" ==========
+.It remove
+Add the policy for the given UUID with PROC_UUID_POLICY_OPERATION_REMOVE.
+.\" ==========
+.Sh POLICIES
+The policies are as follows:
+.Bl -tag -width indent
+.\" ==========
+.It none
+PROC_UUID_POLICY_FLAGS_NONE
+.\" ==========
+.It no_cellular
+PROC_UUID_NO_CELLULAR
+.\" ==========
+.It necp
+PROC_UUID_NO_CELLULAR
+.\" ==========
+.It alt-dyld
+PROC_UUID_ALT_DYLD_POLICY
+.\" ==========
+.El
+.Sh SEE ALSO
+.Xr otool 1
diff --git a/system_cmds/proc_uuid_policy.tproj/proc_uuid_policy.c b/system_cmds/proc_uuid_policy.tproj/proc_uuid_policy.c
new file mode 100644
index 0000000..0078cb9
--- /dev/null
+++ b/system_cmds/proc_uuid_policy.tproj/proc_uuid_policy.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (c) 2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/* Header Declarations */
+#include <errno.h>
+#include <fcntl.h>
+#include <libkern/OSByteOrder.h>
+#include <libproc.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
+#include <System/sys/proc_uuid_policy.h>
+
+/* Constant Declarations */
+#define SUCCESS 0
+#define FAILURE -1
+#define MAX_CHUNK_SIZE 1024 * 1024 * 16
+
+#ifndef PROC_UUID_ALT_DYLD_POLICY
+#define PROC_UUID_ALT_DYLD_POLICY 0x00000004
+#endif
+
+/* UUID bucket */
+struct uuid_bucket
+{
+ unsigned int num_uuids;
+ uuid_t *binary_uuids;
+};
+
+/* Static Function Definitions */
+static
+void
+usage();
+
+static
+int
+parse_macho_uuids(
+ const char *path,
+ struct uuid_bucket *uuid_bucket);
+
+static
+int
+parse_macho_slice(
+ const void *mapped,
+ const unsigned int offset,
+ const unsigned int slice_index,
+ struct uuid_bucket *uuid_bucket);
+
+/* Function Definitions */
+int
+main(
+ int argc,
+ char **argv)
+{
+ int exit_status = EXIT_FAILURE;
+ const char *verb_string;
+ const char *policy_string;
+ const char *uuid_path_string;
+ int operation = 0;
+ const char *operation_string = NULL;
+ int policy = 0;
+ uuid_t uuid;
+ struct stat sb;
+ struct uuid_bucket uuid_bucket = {0, NULL};
+ unsigned int i;
+ uuid_string_t uuid_string = "";
+
+ /*
+ * Parse the arguments.
+ */
+
+ if (argc != 4) {
+
+ usage();
+ goto BAIL;
+ }
+
+ verb_string = argv[1];
+ policy_string = argv[2];
+ uuid_path_string = argv[3];
+
+ if (strcmp(verb_string, "clear") == 0) {
+
+ operation = PROC_UUID_POLICY_OPERATION_CLEAR;
+ operation_string = "Clearing";
+ } else if (strcmp(verb_string, "add") == 0) {
+
+ operation = PROC_UUID_POLICY_OPERATION_ADD;
+ operation_string = "Adding";
+ } else if (strcmp(verb_string, "remove") == 0) {
+
+ operation = PROC_UUID_POLICY_OPERATION_REMOVE;
+ operation_string = "Removing";
+ } else {
+
+ fprintf(stderr, "Unknown verb: %s\n", verb_string);
+ usage();
+ goto BAIL;
+ }
+
+ if (strcmp(policy_string, "none") == 0) {
+
+ policy = PROC_UUID_POLICY_FLAGS_NONE;
+ } else if (strcmp(policy_string, "no_cellular") == 0) {
+
+ policy = PROC_UUID_NO_CELLULAR;
+ } else if (strcmp(policy_string, "necp") == 0) {
+
+ policy = PROC_UUID_NECP_APP_POLICY;
+ } else if (strcmp(policy_string, "alt-dyld") == 0) {
+
+ policy = PROC_UUID_ALT_DYLD_POLICY;
+ } else {
+
+ fprintf(stderr, "Unknown policy: %s\n", policy_string);
+ usage();
+ goto BAIL;
+ }
+
+ if (uuid_parse(uuid_path_string, uuid) == -1) {
+
+ /* Is this a path to a macho file? */
+ if (stat(uuid_path_string, &sb) == -1) {
+
+ fprintf(stderr, "%s is not a UUID nor path: %s\n", uuid_path_string, strerror(errno));
+ goto BAIL;
+ } else {
+
+ /* Parse the UUID from the macho file. */
+ if (parse_macho_uuids(uuid_path_string, &uuid_bucket)) {
+
+ fprintf(stderr, "Could not parse %s for its UUID\n", uuid_path_string);
+ goto BAIL;
+ }
+ }
+ } else {
+
+ uuid_bucket.num_uuids = 1;
+ uuid_bucket.binary_uuids = calloc(1, sizeof(uuid_t));
+ if (uuid_bucket.binary_uuids == NULL) {
+
+ fprintf(stderr, "Could not allocate single UUID bucket\n");
+ goto BAIL;
+ }
+
+ memcpy(uuid_bucket.binary_uuids[0], uuid, sizeof(uuid_t));
+ }
+
+ for (i = 0; i < uuid_bucket.num_uuids; i++) {
+
+ uuid_unparse(uuid_bucket.binary_uuids[i], uuid_string);
+ printf("%s the %s policy for %s\n", operation_string, policy_string, uuid_string);
+
+ if (proc_uuid_policy(operation, uuid_bucket.binary_uuids[i], sizeof(uuid_t), policy) == -1) {
+
+ fprintf(stderr, "Could not enable the UUID policy: %s\n", strerror(errno));
+ goto BAIL;
+ }
+ }
+
+ /* Set the exit status to success. */
+ exit_status = EXIT_SUCCESS;
+
+BAIL:
+
+ /*
+ * Clean up.
+ */
+
+ if (uuid_bucket.binary_uuids != NULL) {
+
+ free(uuid_bucket.binary_uuids);
+ }
+
+ return exit_status;
+}
+
+/* Static Function Definitions */
+static
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s <verb> <policy> <uuid | path>\n", getprogname());
+ fprintf(stderr, "Verbs:\n");
+ fprintf(stderr, "\tclear\tClear all policies for a given UUID\n");
+ fprintf(stderr, "\tadd\tAdd a specific policy\n");
+ fprintf(stderr, "\tremove\tRemove a specific policy\n");
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Policies:\n");
+ fprintf(stderr, "\tnone\t\tPROC_UUID_POLICY_FLAGS_NONE\n");
+ fprintf(stderr, "\tno_cellular\tPROC_UUID_NO_CELLULAR\n");
+ fprintf(stderr, "\tnecp\t\tPROC_UUID_NECP_APP_POLICY\n");
+ fprintf(stderr, "\talt-dyld\tPROC_UUID_ALT_DYLD_POLICY\n");
+}
+
+static
+int
+parse_macho_uuids(
+ const char *path,
+ struct uuid_bucket *uuid_bucket)
+{
+ int result = FAILURE;
+ int fd = -1;
+ struct stat sb;
+ void *mapped = MAP_FAILED;
+
+ struct fat_header *fat_header_pointer;
+ struct fat_arch *fat_arch_pointer;
+ bool swapped = false;
+
+ uint32_t nfat_arch = 0;
+ unsigned int i;
+ uint32_t arch_offset;
+ uint32_t arch_size;
+
+ /* Open the file and determine its size. */
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+
+ fprintf(stderr, "Could not open %s: %s\n", path, strerror(errno));
+ goto BAIL;
+ }
+
+ if (fstat(fd, &sb) == -1) {
+
+ fprintf(stderr, "Could not fstat %s: %s\n", path, strerror(errno));
+ goto BAIL;
+ }
+
+ /* Memory map the file. */
+ mapped = mmap (0, (size_t)sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (mapped == MAP_FAILED) {
+
+ fprintf(stderr, "Could not memory map %s: %s\n", path, strerror(errno));
+ goto BAIL;
+ }
+
+ /*
+ * Determine the file type.
+ */
+
+ fat_header_pointer = (struct fat_header *) mapped;
+
+ switch (fat_header_pointer->magic) {
+
+ case FAT_MAGIC: {
+
+ nfat_arch = fat_header_pointer->nfat_arch;
+ }break;
+
+ case FAT_CIGAM: {
+
+ swapped = true;
+ nfat_arch = OSSwapInt32(fat_header_pointer->nfat_arch);
+ }break;
+
+ case MH_MAGIC:
+ case MH_CIGAM:
+ case MH_MAGIC_64:
+ case MH_CIGAM_64: {
+
+ uuid_bucket->num_uuids = 1;
+
+ uuid_bucket->binary_uuids = calloc(1, sizeof(uuid_t));
+ if (uuid_bucket->binary_uuids == NULL) {
+
+ fprintf(stderr, "Could not allocate a UUID\n");
+ goto BAIL;
+ }
+
+ if (parse_macho_slice(mapped, 0, 0, uuid_bucket)) {
+
+ fprintf(stderr, "Could not parse slice\n");
+ goto BAIL;
+ }
+ }break;
+
+ default: {
+
+ fprintf(stderr, "Unknown magic: %d\n", fat_header_pointer->magic);
+ goto BAIL;
+ }
+ }
+
+ if (nfat_arch > 0) {
+
+ uuid_bucket->num_uuids = nfat_arch;
+
+ uuid_bucket->binary_uuids = calloc(nfat_arch, sizeof(uuid_t));
+ if (uuid_bucket->binary_uuids == NULL) {
+
+ fprintf(stderr, "Could not allocate %d UUIDs\n", nfat_arch);
+ goto BAIL;
+ }
+
+ for (i = 0; i < nfat_arch; i++) {
+
+ fat_arch_pointer = (struct fat_arch *)(mapped + sizeof(struct fat_header) + (sizeof(struct fat_arch) * i));
+
+ if (swapped) {
+
+ arch_offset = OSSwapInt32(fat_arch_pointer->offset);
+ arch_size = OSSwapInt32(fat_arch_pointer->size);
+ } else {
+
+ arch_offset = fat_arch_pointer->offset;
+ arch_size = fat_arch_pointer->size;
+ }
+
+ if (parse_macho_slice(mapped, arch_offset, i, uuid_bucket)) {
+
+ fprintf(stderr, "Could not parse slice %d of %d\n", i, nfat_arch);
+ goto BAIL;
+ }
+ }
+ }
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+BAIL:
+
+ /*
+ * Clean up.
+ */
+
+ if (mapped != MAP_FAILED) {
+
+ (void) munmap(mapped, (size_t)sb.st_size);
+ mapped = MAP_FAILED;
+ }
+
+ if (fd != -1) {
+
+ (void) close(fd);
+ fd = -1;
+ }
+
+ return result;
+}
+
+static
+int
+parse_macho_slice(
+ const void *mapped,
+ const unsigned int offset,
+ const unsigned int slice_index,
+ struct uuid_bucket *uuid_bucket)
+{
+ int result = FAILURE;
+
+ struct mach_header *mach_header_pointer;
+ struct mach_header_64 *mach_header_64_pointer;
+ struct load_command *load_command_pointer;
+
+ bool swapped = false;
+
+ unsigned int number_load_commands = 0;
+ unsigned int i;
+
+ bool found_uuid_load_command = false;
+ struct uuid_command *uuid_load_command_pointer = NULL;
+
+ mach_header_pointer = (struct mach_header *)(mapped + offset);
+
+ switch (mach_header_pointer->magic) {
+
+ case FAT_MAGIC: {
+
+ fprintf(stderr, "FAT_MAGIC\n");
+ goto BAIL;
+ }break;
+
+ case FAT_CIGAM: {
+
+ fprintf(stderr, "FAT_CIGAM\n");
+ goto BAIL;
+ }break;
+
+ case MH_MAGIC: {
+
+ number_load_commands = mach_header_pointer->ncmds;
+ load_command_pointer = (struct load_command *)(void *)(mach_header_pointer + 1);
+ }break;
+
+ case MH_CIGAM: {
+
+ swapped = true;
+
+ number_load_commands = OSSwapInt32(mach_header_pointer->ncmds);
+ load_command_pointer = (struct load_command *)(void *)(mach_header_pointer + 1);
+ }break;
+
+ case MH_MAGIC_64: {
+
+ mach_header_64_pointer = (struct mach_header_64 *)(mapped + offset);
+ number_load_commands = mach_header_64_pointer->ncmds;
+
+ load_command_pointer = (struct load_command *)(void *)(mach_header_64_pointer + 1);
+ }break;
+
+ case MH_CIGAM_64: {
+
+ swapped = true;
+
+ mach_header_64_pointer = (struct mach_header_64 *)(mapped + offset);
+ number_load_commands = OSSwapInt32(mach_header_64_pointer->ncmds);
+
+ load_command_pointer = (struct load_command *)(void *)(mach_header_64_pointer + 1);
+ }break;
+
+ default: {
+
+ fprintf(stderr, "Unknown magic: %d\n", mach_header_pointer->magic);
+ goto BAIL;
+ }
+ }
+
+ /* Walk the load commands looking for LC_UUID. */
+ for (i = 0; i < number_load_commands; i++) {
+
+ if (load_command_pointer->cmd == LC_UUID) {
+
+ found_uuid_load_command = true;
+ uuid_load_command_pointer = (struct uuid_command *)load_command_pointer;
+ memcpy(uuid_bucket->binary_uuids[slice_index], uuid_load_command_pointer->uuid, sizeof(uuid_t));
+ }
+
+ load_command_pointer = (struct load_command *)((uintptr_t)load_command_pointer + load_command_pointer->cmdsize);
+ }
+
+ if (found_uuid_load_command == false) {
+
+ fprintf(stderr, "Could not find LC_UUID\n");
+ goto BAIL;
+ }
+
+ /* Set the result to success. */
+ result = SUCCESS;
+
+BAIL:
+
+ return result;
+}
diff --git a/system_cmds/purge.tproj/purge.8 b/system_cmds/purge.tproj/purge.8
new file mode 100644
index 0000000..41093f9
--- /dev/null
+++ b/system_cmds/purge.tproj/purge.8
@@ -0,0 +1,14 @@
+.Dd September 20, 2005
+.Dt purge 8
+.Sh NAME
+.Nm purge
+.Nd force disk cache to be purged (flushed and emptied)
+.Sh SYNOPSIS
+.Nm purge
+.Sh DESCRIPTION
+.Nm Purge
+can be used to approximate initial boot conditions with a cold disk buffer cache for performance analysis. It does not affect anonymous memory that has been allocated through malloc, vm_allocate, etc.
+.Pp
+.Sh SEE ALSO
+.Xr sync 8 ,
+.Xr malloc 3
diff --git a/system_cmds/purge.tproj/purge.c b/system_cmds/purge.tproj/purge.c
new file mode 100644
index 0000000..38fb8f4
--- /dev/null
+++ b/system_cmds/purge.tproj/purge.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+
+extern int vfs_purge(void);
+
+int
+main(int argc, char **argv)
+{
+ int rv = vfs_purge();
+
+ if (rv) {
+ perror("Unable to purge disk buffers");
+
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/system_cmds/pwd_mkdb.tproj/pw_scan.c b/system_cmds/pwd_mkdb.tproj/pw_scan.c
new file mode 100644
index 0000000..2bd8409
--- /dev/null
+++ b/system_cmds/pwd_mkdb.tproj/pw_scan.c
@@ -0,0 +1,160 @@
+/* $OpenBSD: passwd.c,v 1.42 2003/06/26 16:34:42 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1987, 1993, 1994, 1995
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static const char rcsid[] = "$OpenBSD: passwd.c,v 1.42 2003/06/26 16:34:42 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <signal.h>
+#include <limits.h>
+
+#include "util.h"
+#include "pw_scan.h"
+
+int
+pw_scan(char *bp, struct passwd *pw, int *flags)
+{
+ u_long id;
+ int root;
+ char *p, *sh, *p2;
+
+ if (flags != (int *)NULL)
+ *flags = 0;
+
+#ifdef __APPLE__
+ if (bp[0] == '#') {
+ pw->pw_name = NULL;
+ return(1);
+ }
+#endif
+
+ if (!(p = strsep(&bp, ":")) || *p == '\0') /* login */
+ goto fmt;
+ pw->pw_name = p;
+ root = !strcmp(pw->pw_name, "root");
+
+ if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */
+ goto fmt;
+
+ if (!(p = strsep(&bp, ":"))) /* uid */
+ goto fmt;
+ id = strtoul(p, &p2, 10);
+ if (root && id) {
+ warnx("root uid should be 0");
+ return (0);
+ }
+ if (*p2 != '\0') {
+ warnx("illegal uid field");
+ return (0);
+ }
+#ifndef __APPLE__
+ /* Apple's UID_MAX is too small (sizeof signed) 3091256 */
+ if (id > UID_MAX) {
+ /* errno is set to ERANGE by strtoul(3) */
+ warnx("uid greater than %u", UID_MAX-1);
+ return (0);
+ }
+#endif
+ pw->pw_uid = (uid_t)id;
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOUID;
+
+ if (!(p = strsep(&bp, ":"))) /* gid */
+ goto fmt;
+ id = strtoul(p, &p2, 10);
+ if (*p2 != '\0') {
+ warnx("illegal gid field");
+ return (0);
+ }
+#ifndef __APPLE__
+ /* Apple's UID_MAX is too small (sizeof signed) 3091256 */
+ if (id > UID_MAX) {
+ /* errno is set to ERANGE by strtoul(3) */
+ warnx("gid greater than %u", UID_MAX-1);
+ return (0);
+ }
+#endif
+ pw->pw_gid = (gid_t)id;
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOGID;
+
+ pw->pw_class = strsep(&bp, ":"); /* class */
+ if (!(p = strsep(&bp, ":"))) /* change */
+ goto fmt;
+ pw->pw_change = atol(p);
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOCHG;
+ if (!(p = strsep(&bp, ":"))) /* expire */
+ goto fmt;
+ pw->pw_expire = atol(p);
+ if ((*p == '\0') && (flags != (int *)NULL))
+ *flags |= _PASSWORD_NOEXP;
+ pw->pw_gecos = strsep(&bp, ":"); /* gecos */
+ pw->pw_dir = strsep(&bp, ":"); /* directory */
+ if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */
+ goto fmt;
+
+ p = pw->pw_shell;
+ if (root && *p) { /* empty == /bin/sh */
+ for (setusershell();;) {
+ if (!(sh = getusershell())) {
+ warnx("warning, unknown root shell");
+ break;
+ }
+ if (!strcmp(p, sh))
+ break;
+ }
+ endusershell();
+ }
+
+ if ((p = strsep(&bp, ":"))) { /* too many */
+fmt: warnx("corrupted entry");
+ return (0);
+ }
+
+ return (1);
+}
diff --git a/system_cmds/pwd_mkdb.tproj/pw_scan.h b/system_cmds/pwd_mkdb.tproj/pw_scan.h
new file mode 100644
index 0000000..357226a
--- /dev/null
+++ b/system_cmds/pwd_mkdb.tproj/pw_scan.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pw_scan.h 8.1 (Berkeley) 4/1/94
+ */
+
+extern int pw_scan __P((char *, struct passwd *, int *));
diff --git a/system_cmds/pwd_mkdb.tproj/pwd_mkdb.8 b/system_cmds/pwd_mkdb.tproj/pwd_mkdb.8
new file mode 100644
index 0000000..1d26952
--- /dev/null
+++ b/system_cmds/pwd_mkdb.tproj/pwd_mkdb.8
@@ -0,0 +1,177 @@
+.\" $OpenBSD: pwd_mkdb.8,v 1.17 2003/06/12 12:59:52 jmc Exp $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" from: @(#)pwd_mkdb.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt PWD_MKDB 8
+.Os
+.Sh NAME
+.Nm pwd_mkdb
+.Nd generate the password databases
+.Sh SYNOPSIS
+.Nm pwd_mkdb
+.Op Fl c
+.Op Fl p | Fl s
+.Op Fl d Ar directory
+.Op Fl u Ar username
+.Ar file
+.Sh DESCRIPTION
+.Nm pwd_mkdb
+creates
+.Xr db 3
+style secure and insecure databases for the specified file.
+These databases are then installed into
+.Pa /etc/spwd.db
+and
+.Pa /etc/pwd.db ,
+respectively.
+The file is installed into
+.Pa /etc/master.passwd .
+The file must be in the correct format (see
+.Xr passwd 5 ) .
+It is important to note that the format used in this system is
+different from the historic Version 7 style format.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.\" ==========
+.It Fl c
+Check if the password file is in the correct format.
+Do not change, add, or remove any files.
+.\" ==========
+.It Fl d Ar directory
+Operate in a base directory other than the default of
+.Pa /etc .
+All absolute paths (including
+.Ar file )
+will be made relative to
+.Ar directory .
+Any directories specified as a part of
+.Ar file
+will be stripped off.
+This option is used to create password databases in directories
+other than
+.Pa etc ;
+for instance in a
+.Xr chroot 8
+jail.
+.\" ==========
+.It Fl p
+Create a Version 7 style password file and install it into
+.Pa /etc/passwd .
+.\" ==========
+.It Fl s
+Only update the secure version of the database.
+This is most commonly used in conjunction with the
+.Fl u
+flag during a password change.
+Because the insecure database doesn't contain the password there
+is no reason to update it if the only change is in the password field.
+Cannot be used in conjunction with the
+.Fl p
+flag.
+.\" ==========
+.It Fl u Ar username
+Only update the record for the specified user.
+Utilities that operate on a single user can use this option to avoid the
+overhead of rebuilding the entire database.
+This option must never be used if the line number of the user's record in
+.Pa /etc/master.passwd
+has changed.
+.\" ==========
+.It Ar file
+The absolute path to a file in
+.Ar master.passwd
+format, as described in
+.Xr passwd 5 .
+.El
+.Pp
+The two databases differ in that the secure version contains the user's
+encrypted password and the insecure version has an asterisk
+.Pq Sq \&* .
+.Pp
+The databases are used by the C library password routines (see
+.Xr getpwent 3 ) .
+.Pp
+.Nm pwd_mkdb
+exits zero on success, non-zero on failure.
+.Sh FILES
+.Bl -tag -width /etc/master.passwd -compact
+.It Pa /etc/master.passwd
+current password file
+.It Pa /etc/passwd
+a Version 7 format password file
+.It Pa /etc/pwd.db
+insecure password database file
+.It Pa /etc/pwd.db.tmp
+temporary file
+.It Pa /etc/spwd.db
+secure password database file
+.It Pa /etc/spwd.db.tmp
+temporary file
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr passwd 1 ,
+.Xr db 3 ,
+.Xr getpwent 3 ,
+.Xr passwd 5 ,
+.Xr vipw 8
+.Sh STANDARDS
+Previous versions of the system had a program similar to
+.Nm pwd_mkdb ,
+.Xr mkpasswd ,
+which built
+.Xr dbm 3
+style databases for the password file but depended on the calling programs
+to install them.
+The program was renamed in order that previous users of the program
+not be surprised by the changes in functionality.
+.Sh BUGS
+Because of the necessity for atomic update of the password files,
+.Nm pwd_mkdb
+uses
+.Xr rename 2
+to install them.
+This, however, requires that the file specified on the command line live
+on the same file system as the
+.Pa /etc
+directory.
+.Pp
+There are the obvious races with multiple people running
+.Nm pwd_mkdb
+on different password files at the same time.
+The front-ends to
+.Nm pwd_mkdb ,
+.Xr chpass 1 ,
+.Xr passwd 1 ,
+and
+.Xr vipw 8
+handle the locking necessary to avoid this problem.
diff --git a/system_cmds/pwd_mkdb.tproj/pwd_mkdb.c b/system_cmds/pwd_mkdb.tproj/pwd_mkdb.c
new file mode 100644
index 0000000..7d02422
--- /dev/null
+++ b/system_cmds/pwd_mkdb.tproj/pwd_mkdb.c
@@ -0,0 +1,625 @@
+/* $OpenBSD: pwd_mkdb.c,v 1.36 2003/06/08 21:14:55 millert Exp $ */
+
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ * Portions Copyright (c) 1994, Jason Downs. All rights reserved.
+ * Portions Copyright (c) 1998, Todd C. Miller. 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static const char sccsid[] = "from: @(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94";
+#else
+__unused static const char rcsid[] = "$OpenBSD: pwd_mkdb.c,v 1.36 2003/06/08 21:14:55 millert Exp $";
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <db.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <limits.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <util.h>
+#include <sys/param.h>
+#include "pw_scan.h"
+
+#define INSECURE 1
+#define SECURE 2
+#define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
+#define PERM_SECURE (S_IRUSR|S_IWUSR)
+
+#define FILE_SECURE 0x01
+#define FILE_INSECURE 0x02
+#define FILE_ORIG 0x04
+
+#define SHADOW_GROUP "wheel"
+
+HASHINFO openinfo = {
+ .bsize = 4096,
+ .ffactor = 32,
+ .nelem = 256,
+ .cachesize = 2048 * 1024,
+ .hash = NULL,
+ .lorder = 0
+};
+
+static char *pname; /* password file name */
+static char *basedir; /* dir holding master.passwd */
+static int clean; /* what to remove on cleanup */
+static int hasyp; /* are we running YP? */
+
+void cleanup(void);
+void error(char *);
+void errorx(char *);
+void cp(char *, char *, mode_t);
+void mv(char *, char *);
+int scan(FILE *, struct passwd *, int *);
+void usage(void);
+char *changedir(char *path, char *dir);
+void db_store(FILE *, FILE *, DB *, DB *,struct passwd *, int, char *, uid_t);
+
+int
+main(int argc, char **argv)
+{
+ DB *dp, *edp;
+ DBT data, key;
+ FILE *fp, *oldfp = NULL;
+ struct stat st;
+ struct passwd pwd;
+ struct group *grp;
+ sigset_t set;
+ uid_t olduid = UID_MAX;
+ gid_t shadow;
+ int ch, tfd, makeold, secureonly, flags, checkonly;
+ char *username, buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
+
+ flags = checkonly = makeold = secureonly = 0;
+ username = NULL;
+ while ((ch = getopt(argc, argv, "cd:psu:v")) != -1)
+ switch (ch) {
+ case 'c': /* verify only */
+ checkonly = 1;
+ break;
+ case 'd':
+ basedir = optarg;
+ if (strlen(basedir) > MAXPATHLEN - 40)
+ errx(1, "basedir too long");
+ break;
+ case 'p': /* create V7 "file.orig" */
+ makeold = 1;
+ break;
+ case 's': /* only update spwd.db */
+ secureonly = 1;
+ break;
+ case 'u': /* only update this record */
+ username = optarg;
+ if (strlen(username) > _PW_NAME_LEN)
+ errx(1, "username too long");
+ break;
+ case 'v': /* backward compatible */
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1 || (makeold && secureonly) ||
+ (username && (*username == '+' || *username == '-')))
+ usage();
+
+ if ((grp = getgrnam(SHADOW_GROUP)) == NULL)
+ errx(1, "cannot find `%s' in the group database, aborting",
+ SHADOW_GROUP);
+ shadow = grp->gr_gid;
+
+ /*
+ * This could be changed to allow the user to interrupt.
+ * Probably not worth the effort.
+ */
+ sigemptyset(&set);
+ sigaddset(&set, SIGTSTP);
+ sigaddset(&set, SIGHUP);
+ sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGQUIT);
+ sigaddset(&set, SIGTERM);
+ (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
+
+ /* We don't care what the user wants. */
+ (void)umask(0);
+
+ if (**argv != '/' && basedir == NULL)
+ errx(1, "%s must be specified as an absolute path", *argv);
+
+ if ((pname = strdup(changedir(*argv, basedir))) == NULL)
+ err(1, NULL);
+ /* Open the original password file */
+ if (!(fp = fopen(pname, "r")))
+ error(pname);
+
+ /* Check only if password database is valid */
+ if (checkonly) {
+ u_int cnt;
+
+ for (cnt = 1; scan(fp, &pwd, &flags); ++cnt)
+ ;
+ exit(0);
+ }
+
+ if (fstat(fileno(fp), &st) == -1)
+ error(pname);
+
+ /* Tweak openinfo values for large passwd files. */
+ if (st.st_size > (off_t)100*1024)
+ openinfo.cachesize = (u_int)MIN(st.st_size * 20, (off_t)12*1024*1024);
+ if (st.st_size / 128 > openinfo.nelem)
+ openinfo.nelem = (u_int)(st.st_size / 128);
+
+ /* If only updating a single record, stash the old uid */
+ if (username) {
+ dp = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
+ if (dp == NULL)
+ error(_PATH_MP_DB);
+ buf[0] = _PW_KEYBYNAME;
+ strlcpy(buf + 1, username, sizeof(buf) - 1);
+ key.data = (u_char *)buf;
+ key.size = strlen(buf + 1) + 1;
+ if ((dp->get)(dp, &key, &data, 0) == 0) {
+ char *p = (char *)data.data;
+ /* Skip to uid field */
+ while (*p++ != '\0')
+ ;
+ while (*p++ != '\0')
+ ;
+ memcpy(&olduid, p, sizeof(olduid));
+ } else
+ olduid = UID_MAX;
+ (dp->close)(dp);
+ }
+
+ /* Open the temporary encrypted password database. */
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_SMP_DB, basedir));
+ if (username) {
+ cp(changedir(_PATH_SMP_DB, basedir), buf, PERM_SECURE);
+ edp = dbopen(buf,
+ O_RDWR, PERM_SECURE, DB_HASH, &openinfo);
+ } else {
+ edp = dbopen(buf,
+ O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
+ }
+ if (!edp)
+ error(buf);
+ if (fchown(edp->fd(edp), (uid_t)-1, shadow) != 0)
+ warn("%s: unable to set group to %s", _PATH_SMP_DB,
+ SHADOW_GROUP);
+ else if (fchmod(edp->fd(edp), PERM_SECURE|S_IRGRP) != 0)
+ warn("%s: unable to make group readable", _PATH_SMP_DB);
+ clean |= FILE_SECURE;
+
+ /* Open the temporary insecure password database. */
+ if (!secureonly) {
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_MP_DB, basedir));
+ if (username) {
+ cp(changedir(_PATH_MP_DB, basedir), buf, PERM_INSECURE);
+ dp = dbopen(buf, O_RDWR, PERM_INSECURE, DB_HASH,
+ &openinfo);
+ } else {
+ dp = dbopen(buf, O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE,
+ DB_HASH, &openinfo);
+ }
+ if (dp == NULL)
+ error(buf);
+ clean |= FILE_INSECURE;
+ } else
+ dp = NULL;
+
+ /*
+ * Open file for old password file. Minor trickiness -- don't want to
+ * chance the file already existing, since someone (stupidly) might
+ * still be using this for permission checking. So, open it first and
+ * fdopen the resulting fd. The resulting file should be readable by
+ * everyone.
+ */
+ if (makeold) {
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ if ((tfd = open(buf,
+ O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
+ error(buf);
+ if ((oldfp = fdopen(tfd, "w")) == NULL)
+ error(buf);
+ clean |= FILE_ORIG;
+ }
+
+ /*
+ * The databases actually contain three copies of the original data.
+ * Each password file entry is converted into a rough approximation
+ * of a ``struct passwd'', with the strings placed inline. This
+ * object is then stored as the data for three separate keys. The
+ * first key * is the pw_name field prepended by the _PW_KEYBYNAME
+ * character. The second key is the pw_uid field prepended by the
+ * _PW_KEYBYUID character. The third key is the line number in the
+ * original file prepended by the _PW_KEYBYNUM character. (The special
+ * characters are prepended to ensure that the keys do not collide.)
+ *
+ * If we see something go by that looks like YP, we save a special
+ * pointer record, which if YP is enabled in the C lib, will speed
+ * things up.
+ */
+
+ /*
+ * Write the .db files.
+ * We do this three times, one per key type (for getpw{nam,uid,ent}).
+ * The first time through we also check for YP, issue warnings
+ * and save the V7 format passwd file if necessary.
+ */
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYNAME, username, olduid);
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYUID, username, olduid);
+ db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYNUM, username, olduid);
+
+ /* Store YP token, if needed. */
+ if (hasyp && !username) {
+ key.data = (u_char *)_PW_YPTOKEN;
+ key.size = strlen(_PW_YPTOKEN);
+ data.data = (u_char *)NULL;
+ data.size = 0;
+
+ if ((edp->put)(edp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+
+ if (dp && (dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
+ error("put");
+ }
+
+ if ((edp->close)(edp))
+ error("close edp");
+ if (dp && (dp->close)(dp))
+ error("close dp");
+ if (makeold) {
+ if (fclose(oldfp) == EOF)
+ error("close old");
+ }
+
+ /* Set master.passwd permissions, in case caller forgot. */
+ (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
+ if (fclose(fp) != 0)
+ error("fclose");
+
+ /* Install as the real password files. */
+ if (!secureonly) {
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_MP_DB, basedir));
+ mv(buf, changedir(_PATH_MP_DB, basedir));
+ }
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_SMP_DB, basedir));
+ mv(buf, changedir(_PATH_SMP_DB, basedir));
+ if (makeold) {
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ mv(buf, changedir(_PATH_PASSWD, basedir));
+ }
+
+ /*
+ * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
+ * all use flock(2) on it to block other incarnations of themselves.
+ * The rename means that everything is unlocked, as the original file
+ * can no longer be accessed.
+ */
+ mv(pname, changedir(_PATH_MASTERPASSWD, basedir));
+ exit(0);
+}
+
+int
+scan(FILE *fp, struct passwd *pw, int *flags)
+{
+ static int lcnt;
+ static char line[LINE_MAX];
+ char *p;
+
+ if (fgets(line, sizeof(line), fp) == NULL)
+ return (0);
+ ++lcnt;
+ /*
+ * ``... if I swallow anything evil, put your fingers down my
+ * throat...''
+ * -- The Who
+ */
+ p = line;
+ if (*p != '\0' && *(p += strlen(line) - 1) != '\n') {
+ warnx("line too long");
+ goto fmt;
+ }
+ *p = '\0';
+ *flags = 0;
+ if (!pw_scan(line, pw, flags)) {
+ warnx("at line #%d", lcnt);
+fmt: errno = EFTYPE; /* XXX */
+ error(pname);
+ }
+
+ return (1);
+}
+
+void
+cp(char *from, char *to, mode_t mode)
+{
+ static char buf[MAXBSIZE];
+ int from_fd, to_fd;
+ ssize_t rcount, wcount;
+
+ if ((from_fd = open(from, O_RDONLY, 0)) < 0)
+ error(from);
+ if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0)
+ error(to);
+ while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
+ wcount = write(to_fd, buf, rcount);
+ if (rcount != wcount || wcount == -1) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+ }
+ if (rcount < 0) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+}
+
+void
+mv(char *from, char *to)
+{
+ char buf[MAXPATHLEN * 2];
+
+ if (rename(from, to)) {
+ int sverrno = errno;
+
+ (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
+ errno = sverrno;
+ error(buf);
+ }
+}
+
+void
+error(char *name)
+{
+ warn("%s", name);
+ cleanup();
+ exit(1);
+}
+
+void
+errorx(char *name)
+{
+ warnx("%s", name);
+ cleanup();
+ exit(1);
+}
+
+void
+cleanup(void)
+{
+ char buf[MAXPATHLEN];
+
+ if (clean & FILE_ORIG) {
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ (void)unlink(buf);
+ }
+ if (clean & FILE_SECURE) {
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_SMP_DB, basedir));
+ (void)unlink(buf);
+ }
+ if (clean & FILE_INSECURE) {
+ (void)snprintf(buf, sizeof(buf), "%s.tmp",
+ changedir(_PATH_MP_DB, basedir));
+ (void)unlink(buf);
+ }
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: pwd_mkdb [-c] [-p | -s] [-d basedir] [-u username] file\n");
+ exit(1);
+}
+
+char *
+changedir(char *path, char *dir)
+{
+ static char fixed[MAXPATHLEN];
+ char *p;
+
+ if (!dir)
+ return (path);
+
+ if ((p = strrchr(path, '/')) != NULL)
+ path = p + 1;
+ snprintf(fixed, sizeof(fixed), "%s/%s", dir, path);
+ return (fixed);
+}
+
+void
+db_store(FILE *fp, FILE *oldfp, DB *edp, DB *dp, struct passwd *pw,
+ int keytype, char *username, uid_t olduid)
+{
+ int flags = 0;
+ int dbmode, found = 0;
+ u_int cnt;
+ char *p, *t, buf[LINE_MAX * 2], tbuf[1024];
+ DBT data, key;
+ size_t len;
+ static int firsttime = 1;
+
+ /* If given a username just add that record to the existing db. */
+ dbmode = username ? 0 : R_NOOVERWRITE;
+
+ rewind(fp);
+ data.data = (u_char *)buf;
+ key.data = (u_char *)tbuf;
+ for (cnt = 1; scan(fp, pw, &flags); ++cnt) {
+
+#ifdef __APPLE__
+ if (pw->pw_name == NULL)
+ continue;
+#endif
+
+ if (firsttime) {
+ /* Look like YP? */
+ if ((pw->pw_name[0] == '+') || (pw->pw_name[0] == '-'))
+ hasyp++;
+
+ /* Warn about potentially unsafe uid/gid overrides. */
+ if (pw->pw_name[0] == '+') {
+ if (!(flags & _PASSWORD_NOUID) && !pw->pw_uid)
+ warnx("line %d: superuser override in "
+ "YP inclusion", cnt);
+ if (!(flags & _PASSWORD_NOGID) && !pw->pw_gid)
+ warnx("line %d: wheel override in "
+ "YP inclusion", cnt);
+ }
+
+ /* Create V7 format password file entry. */
+ if (oldfp != NULL)
+ if (fprintf(oldfp, "%s:*:%u:%u:%s:%s:%s\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid,
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell)
+ == EOF)
+ error("write old");
+ }
+
+ /* Are we updating a specific record? */
+ if (username) {
+ if (strcmp(username, pw->pw_name) != 0)
+ continue;
+ found = 1;
+ /* If the uid changed, remove the old record by uid. */
+ if (olduid != UID_MAX && olduid != pw->pw_uid) {
+ tbuf[0] = _PW_KEYBYUID;
+ memcpy(tbuf + 1, &olduid, sizeof(olduid));
+ key.size = sizeof(olduid) + 1;
+ (edp->del)(edp, &key, 0);
+ if (dp)
+ (dp->del)(dp, &key, 0);
+ }
+ /* XXX - should check to see if line number changed. */
+ }
+
+ /* Build the key. */
+ tbuf[0] = keytype;
+ switch (keytype) {
+ case _PW_KEYBYNUM:
+ memmove(tbuf + 1, &cnt, sizeof(cnt));
+ key.size = sizeof(cnt) + 1;
+ break;
+
+ case _PW_KEYBYNAME:
+ len = strlen(pw->pw_name);
+ memmove(tbuf + 1, pw->pw_name, len);
+ key.size = len + 1;
+ break;
+
+ case _PW_KEYBYUID:
+ memmove(tbuf + 1, &pw->pw_uid, sizeof(pw->pw_uid));
+ key.size = sizeof(pw->pw_uid) + 1;
+ break;
+ }
+
+#define COMPACT(e) t = e; while ((*p++ = *t++));
+ /* Create the secure record. */
+ p = buf;
+ COMPACT(pw->pw_name);
+ COMPACT(pw->pw_passwd);
+ memmove(p, &pw->pw_uid, sizeof(uid_t));
+ p += sizeof(uid_t);
+ memmove(p, &pw->pw_gid, sizeof(gid_t));
+ p += sizeof(gid_t);
+ memmove(p, &pw->pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pw->pw_class);
+ COMPACT(pw->pw_gecos);
+ COMPACT(pw->pw_dir);
+ COMPACT(pw->pw_shell);
+ memmove(p, &pw->pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ memmove(p, &flags, sizeof(int));
+ p += sizeof(int);
+ data.size = p - buf;
+
+ /* Write the secure record. */
+ if ((edp->put)(edp, &key, &data, dbmode) == -1)
+ error("put");
+
+ if (dp == NULL)
+ continue;
+
+ /* Star out password to make insecure record. */
+ p = buf + strlen(pw->pw_name) + 1; /* skip pw_name */
+ len = strlen(pw->pw_passwd);
+ memset(p, 0, len); /* zero pw_passwd */
+ t = p + len + 1; /* skip pw_passwd */
+ if (len != 0)
+ *p++ = '*';
+ *p++ = '\0';
+ memmove(p, t, data.size - (t - buf));
+ data.size -= len - 1;
+
+ /* Write the insecure record. */
+ if ((dp->put)(dp, &key, &data, dbmode) == -1)
+ error("put");
+ }
+ if (firsttime) {
+ firsttime = 0;
+ if (username && !found && olduid != UID_MAX)
+ errorx("can't find user in master.passwd");
+ }
+}
diff --git a/system_cmds/reboot.tproj/kextmanager.defs b/system_cmds/reboot.tproj/kextmanager.defs
new file mode 100644
index 0000000..6ae21ce
--- /dev/null
+++ b/system_cmds/reboot.tproj/kextmanager.defs
@@ -0,0 +1,6 @@
+#include <TargetConditionals.h>
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+subsystem dummy 0;
+#else
+#include <IOKit/kext/kextmanager_mig.defs>
+#endif
diff --git a/system_cmds/reboot.tproj/reboot.8 b/system_cmds/reboot.tproj/reboot.8
new file mode 100644
index 0000000..a18e7ae
--- /dev/null
+++ b/system_cmds/reboot.tproj/reboot.8
@@ -0,0 +1,115 @@
+.\" Copyright (c) 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)reboot.8 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD: src/sbin/reboot/reboot.8,v 1.21 2002/12/27 12:15:33 schweikh Exp $
+.\"
+.Dd June 9, 1993
+.Dt REBOOT 8
+.Os
+.Sh NAME
+.Nm halt ,
+.Nm reboot
+.Nd stopping and restarting the system
+.Sh SYNOPSIS
+.Nm halt
+.Op Fl lnqu
+.Nm reboot
+.Op Fl lnq
+.Sh DESCRIPTION
+The
+.Nm halt
+and
+.Nm reboot
+utilities flush the file system cache to disk,
+send all running processes a
+.Dv SIGTERM
+(and subsequently a
+.Dv SIGKILL )
+and, respectively, halt or restart the system.
+The action is logged, including entering a shutdown record into the
+.Xr wtmp 5
+file.
+.Pp
+When the system is halted with the halt command, the system is powered off.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl l
+The halt or reboot is
+.Em not
+recorded in the system log.
+This option is intended for applications such as
+.Xr shutdown 8 ,
+that call
+.Nm reboot
+or
+.Nm halt
+and log this themselves.
+.It Fl n
+The file system cache is not flushed.
+This option should probably not be used.
+.It Fl q
+The system is halted or restarted quickly and ungracefully, and only
+the flushing of the file system cache is performed (if the
+.Fl n
+option is not specified).
+This option should probably not be used.
+.It Fl u
+The system is halted up until the point of removing system power, but waits
+before removing power for 5 minutes so that an external UPS
+(uninterruptible power supply) can forcibly remove power.
+This simulates a dirty shutdown to permit a later automatic power on. OS X uses
+this mode automatically with supported UPSs in emergency shutdowns.
+.El
+.Pp
+Normally, the
+.Xr shutdown 8
+utility is used when the system needs to be halted or restarted, giving
+users advance warning of their impending doom and cleanly terminating
+specific programs.
+.Sh SIGTERM TO SIGKILL INTERVAL
+The
+.Dv SIGKILL
+will follow the
+.Dv SIGTERM
+by an intentionally indeterminate period of time.
+Programs are expected to take only enough time to flush all dirty data and exit.
+Developers are encouraged to file a bug with the OS vendor, should they encounter an issue with this functionality.
+.Sh SEE ALSO
+.Xr wtmp 5 ,
+.Xr shutdown 8 ,
+.Xr sync 8
+.Sh HISTORY
+A
+.Nm reboot
+utility appeared in
+.At v6 .
diff --git a/system_cmds/reboot.tproj/reboot.c b/system_cmds/reboot.tproj/reboot.c
new file mode 100644
index 0000000..5478704
--- /dev/null
+++ b/system_cmds/reboot.tproj/reboot.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 1980, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1980, 1986, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)reboot.c 8.1 (Berkeley) 6/5/93";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD: src/sbin/reboot/reboot.c,v 1.17 2002/10/06 16:24:36 thomas Exp $";
+#endif /* not lint */
+
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <signal.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <util.h>
+#include <pwd.h>
+#include <syslog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+#include "kextmanager.h"
+#include <IOKit/kext/kextmanager_types.h>
+#endif
+#include <mach/mach_port.h> // allocate
+#include <mach/mach.h> // task_self, etc
+#include <servers/bootstrap.h> // bootstrap
+#include <bootstrap_priv.h>
+#include <reboot2.h>
+#include <utmpx.h>
+#include <sys/time.h>
+#endif
+
+void usage(void);
+u_int get_pageins(void);
+#if defined(__APPLE__) && !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+int reserve_reboot(void);
+#endif
+
+int dohalt;
+
+int
+main(int argc, char *argv[])
+{
+ struct passwd *pw;
+ int ch, howto, kflag, lflag, nflag, qflag, uflag;
+ char *p;
+ const char *user;
+#ifndef __APPLE__
+ int i, fd, pflag, sverrno;
+ u_int pageins;
+ char *kernel;
+#endif
+
+ if (strstr((p = rindex(*argv, '/')) ? p + 1 : *argv, "halt")) {
+ dohalt = 1;
+ howto = RB_HALT;
+ } else
+ howto = 0;
+ kflag = lflag = nflag = qflag = 0;
+#ifndef __APPLE__
+ while ((ch = getopt(argc, argv, "dk:lnpq")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "lnqu")) != -1)
+#endif
+ switch(ch) {
+#ifndef __APPLE__
+ case 'd':
+ howto |= RB_DUMP;
+ break;
+ case 'k':
+ kflag = 1;
+ kernel = optarg;
+ break;
+#endif
+ case 'l':
+ lflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ howto |= RB_NOSYNC;
+ break;
+/* -p is irrelevant on OS X. It does that anyway. */
+#ifndef __APPLE__
+ case 'p':
+ pflag = 1;
+ howto |= RB_POWEROFF;
+ break;
+#endif
+ case 'u':
+ uflag = 1;
+ howto |= RB_UPSDELAY;
+ break;
+ case 'q':
+ qflag = 1;
+ howto |= RB_QUICK;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+#ifndef __APPLE__
+ if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
+ errx(1, "cannot dump (-d) when halting; must reboot instead");
+#endif
+ if (geteuid()) {
+ errno = EPERM;
+ err(1, NULL);
+ }
+
+#if defined(__APPLE__) && !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+ if (!qflag && !lflag) { // shutdown(8) has already checked w/kextd
+ if ((errno = reserve_reboot()))
+ err(1, "couldn't lock for reboot");
+ }
+#endif
+
+ if (qflag) {
+ reboot(howto);
+ err(1, NULL);
+ }
+
+#ifndef __APPLE__
+ if (kflag) {
+ fd = open("/boot/nextboot.conf", O_WRONLY | O_CREAT, 0444);
+ if (fd > -1) {
+ (void)write(fd, "nextboot_enable=\"YES\"\n", 22);
+ (void)write(fd, "kernel=\"", 8L);
+ (void)write(fd, kernel, strlen(kernel));
+ (void)write(fd, "\"\n", 2);
+ close(fd);
+ }
+ }
+#endif
+
+ /* Log the reboot. */
+ if (!lflag) {
+ if ((user = getlogin()) == NULL)
+ user = (pw = getpwuid(getuid())) ?
+ pw->pw_name : "???";
+ if (dohalt) {
+ openlog("halt", 0, LOG_AUTH | LOG_CONS);
+ syslog(LOG_CRIT, "halted by %s%s", user,
+ (howto & RB_UPSDELAY) ? " with UPS delay":"");
+ } else {
+ openlog("reboot", 0, LOG_AUTH | LOG_CONS);
+ syslog(LOG_CRIT, "rebooted by %s", user);
+ }
+ }
+#if defined(__APPLE__)
+ {
+ struct utmpx utx;
+ bzero(&utx, sizeof(utx));
+ utx.ut_type = SHUTDOWN_TIME;
+ gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+ }
+#else
+ logwtmp("~", "shutdown", "");
+#endif
+
+ /*
+ * Do a sync early on, so disks start transfers while we're off
+ * killing processes. Don't worry about writes done before the
+ * processes die, the reboot system call syncs the disks.
+ */
+ if (!nflag)
+ sync();
+
+#ifndef __APPLE__
+ /* Just stop init -- if we fail, we'll restart it. */
+ if (kill(1, SIGTSTP) == -1)
+ err(1, "SIGTSTP init");
+#endif
+
+ /* Ignore the SIGHUP we get when our parent shell dies. */
+ (void)signal(SIGHUP, SIG_IGN);
+
+#ifndef __APPLE__
+ /* Send a SIGTERM first, a chance to save the buffers. */
+ if (kill(-1, SIGTERM) == -1)
+ err(1, "SIGTERM processes");
+
+ /*
+ * After the processes receive the signal, start the rest of the
+ * buffers on their way. Wait 5 seconds between the SIGTERM and
+ * the SIGKILL to give everybody a chance. If there is a lot of
+ * paging activity then wait longer, up to a maximum of approx
+ * 60 seconds.
+ */
+ sleep(2);
+ for (i = 0; i < 20; i++) {
+ pageins = get_pageins();
+ if (!nflag)
+ sync();
+ sleep(3);
+ if (get_pageins() == pageins)
+ break;
+ }
+
+ for (i = 1;; ++i) {
+ if (kill(-1, SIGKILL) == -1) {
+ if (errno == ESRCH)
+ break;
+ goto restart;
+ }
+ if (i > 5) {
+ (void)fprintf(stderr,
+ "WARNING: some process(es) wouldn't die\n");
+ break;
+ }
+ (void)sleep(2 * i);
+ }
+#endif
+
+#ifdef __APPLE__
+ // launchd(8) handles reboot. This call returns NULL on success.
+ exit(reboot3(howto) == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
+#else /* __APPLE__ */
+ reboot(howto);
+ /* FALLTHROUGH */
+
+restart:
+ sverrno = errno;
+ errx(1, "%s%s", kill(1, SIGHUP) == -1 ? "(can't restart init): " : "",
+ strerror(sverrno));
+ /* NOTREACHED */
+#endif /* __APPLE__ */
+}
+
+void
+usage(void)
+{
+#ifndef __APPLE__
+ (void)fprintf(stderr, "usage: %s [-dnpq] [-k kernel]\n",
+#else
+ (void)fprintf(stderr, "usage: %s [-lnq]\n",
+#endif
+ dohalt ? "halt" : "reboot");
+ exit(1);
+}
+
+u_int
+get_pageins(void)
+{
+ u_int pageins;
+ size_t len;
+
+ len = sizeof(pageins);
+ if (sysctlbyname("vm.stats.vm.v_swappgsin", &pageins, &len, NULL, 0)
+ != 0) {
+ warnx("v_swappgsin");
+ return (0);
+ }
+ return pageins;
+}
+
+#if defined(__APPLE__) && !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+// XX this routine is also in shutdown.tproj; it would be nice to share
+
+static bool
+kextdDisabled(void)
+{
+ uint32_t disabled = 0;
+ size_t sizeOfDisabled = sizeof(disabled);
+ if (sysctlbyname("hw.use_kernelmanagerd", &disabled, &sizeOfDisabled, NULL, 0) != 0) {
+ return false;
+ }
+ return (disabled != 0);
+}
+
+#define WAITFORLOCK 1
+/*
+ * contact kextd to lock for reboot
+ */
+int
+reserve_reboot(void)
+{
+ int rval = ELAST + 1;
+ kern_return_t macherr = KERN_FAILURE;
+ mach_port_t kxport, tport = MACH_PORT_NULL, myport = MACH_PORT_NULL;
+ int busyStatus = ELAST + 1;
+ mountpoint_t busyVol;
+
+ if (kextdDisabled()) {
+ /* no need to talk with kextd if it's not running */
+ return 0;
+ }
+
+ macherr = bootstrap_look_up2(bootstrap_port, KEXTD_SERVER_NAME, &kxport, 0, BOOTSTRAP_PRIVILEGED_SERVER);
+ if (macherr) goto finish;
+
+ // allocate a port to pass to kextd (in case we die)
+ tport = mach_task_self();
+ if (tport == MACH_PORT_NULL) goto finish;
+ macherr = mach_port_allocate(tport, MACH_PORT_RIGHT_RECEIVE, &myport);
+ if (macherr) goto finish;
+
+ // try to lock for reboot
+ macherr = kextmanager_lock_reboot(kxport, myport, !WAITFORLOCK, busyVol,
+ &busyStatus);
+ if (macherr) goto finish;
+
+ if (busyStatus == EBUSY) {
+ warnx("%s is busy updating; waiting for lock", busyVol);
+ macherr = kextmanager_lock_reboot(kxport, myport, WAITFORLOCK,
+ busyVol, &busyStatus);
+ if (macherr) goto finish;
+ }
+
+ if (busyStatus == EALREADY) {
+ // reboot already in progress
+ rval = 0;
+ } else {
+ rval = busyStatus;
+ }
+
+finish:
+ // in general, we want to err on the side of allowing the reboot
+ if (macherr) {
+ if (macherr != BOOTSTRAP_UNKNOWN_SERVICE)
+ warnx("WARNING: couldn't lock kext manager for reboot: %s",
+ mach_error_string(macherr));
+ rval = 0;
+ }
+ // unless we got the lock, clean up our port
+ if (busyStatus != 0 && myport != MACH_PORT_NULL)
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+
+ return rval;
+}
+#endif
diff --git a/system_cmds/sa.tproj/db.c b/system_cmds/sa.tproj/db.c
new file mode 100644
index 0000000..299eeea
--- /dev/null
+++ b/system_cmds/sa.tproj/db.c
@@ -0,0 +1,211 @@
+/*-
+ * Copyright (c) 2007 Diomidis Spinellis
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/sa/db.c,v 1.3 2008/02/21 07:12:56 grog Exp $");
+
+#include <sys/types.h>
+#include <sys/acct.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <db.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "extern.h"
+
+/* Key used to store the version of the database data elements. */
+#define VERSION_KEY "\0VERSION"
+
+/*
+ * Create the in-memory database, *mdb.
+ * If iflag is not set, fill-in mdb with the records of the disk-based
+ * database dbname.
+ * Upgrade old-version records by calling v1_to_v2.
+ * Return 0 if OK, -1 on error.
+ */
+int
+db_copy_in(DB **mdb, const char *dbname, const char *uname, BTREEINFO *bti,
+ int (*v1_to_v2)(DBT *key, DBT *data))
+{
+ DBT key, data;
+ DB *ddb;
+ int error, rv, version;
+
+ if ((*mdb = dbopen(NULL, O_RDWR, 0, DB_BTREE, bti)) == NULL)
+ return (-1);
+
+ if (iflag)
+ return (0);
+
+ if ((ddb = dbopen(dbname, O_RDONLY, 0, DB_BTREE, bti)) == NULL) {
+ if (errno == ENOENT)
+ return (0);
+ warn("retrieving %s summary", uname);
+ db_destroy(*mdb, uname);
+ return (-1);
+ }
+
+ error = 0;
+
+ /* Obtain/set version. */
+ version = 1;
+ key.data = &VERSION_KEY;
+ key.size = sizeof(VERSION_KEY);
+
+ rv = DB_GET(ddb, &key, &data, 0);
+ if (rv < 0) {
+ warn("get version key from %s stats", uname);
+ error = -1;
+ goto closeout;
+ } else if (rv == 0) { /* It's there; verify version. */
+ if (data.size != sizeof(version)) {
+ warnx("invalid version size %zd in %s",
+ data.size, uname);
+ error = -1;
+ goto closeout;
+ }
+ memcpy(&version, data.data, data.size);
+ if (version != 2) {
+ warnx("unsupported version %d in %s",
+ version, uname);
+ error = -1;
+ goto closeout;
+ }
+ }
+
+ for (rv = DB_SEQ(ddb, &key, &data, R_FIRST); rv == 0;
+ rv = DB_SEQ(ddb, &key, &data, R_NEXT)) {
+
+ /* See if this is a version record. */
+ if (key.size == sizeof(VERSION_KEY) &&
+ memcmp(key.data, VERSION_KEY, sizeof(VERSION_KEY)) == 0)
+ continue;
+
+ /* Convert record from v1, if needed. */
+ if (version == 1 && v1_to_v2(&key, &data) < 0) {
+ warn("converting %s stats", uname);
+ error = -1;
+ goto closeout;
+ }
+
+ /* Copy record to the in-memory database. */
+ if ((rv = DB_PUT(*mdb, &key, &data, 0)) < 0) {
+ warn("initializing %s stats", uname);
+ error = -1;
+ goto closeout;
+ }
+ }
+ if (rv < 0) {
+ warn("retrieving %s summary", uname);
+ error = -1;
+ }
+
+closeout:
+ if (DB_CLOSE(ddb) < 0) {
+ warn("closing %s summary", uname);
+ error = -1;
+ }
+
+ if (error)
+ db_destroy(*mdb, uname);
+ return (error);
+}
+
+/*
+ * Save the in-memory database mdb to the disk database dbname.
+ * Return 0 if OK, -1 on error.
+ */
+int
+db_copy_out(DB *mdb, const char *dbname, const char *uname, BTREEINFO *bti)
+{
+ DB *ddb;
+ DBT key, data;
+ int error, rv, version;
+
+ if ((ddb = dbopen(dbname, O_RDWR|O_CREAT|O_TRUNC, 0644,
+ DB_BTREE, bti)) == NULL) {
+ warn("creating %s summary", uname);
+ return (-1);
+ }
+
+ error = 0;
+
+ for (rv = DB_SEQ(mdb, &key, &data, R_FIRST);
+ rv == 0; rv = DB_SEQ(mdb, &key, &data, R_NEXT)) {
+ if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) {
+ warn("saving %s summary", uname);
+ error = -1;
+ goto out;
+ }
+ }
+ if (rv < 0) {
+ warn("retrieving %s stats", uname);
+ error = -1;
+ }
+
+out:
+#ifndef __APPLE__
+ /* Add a version record. */
+ key.data = &VERSION_KEY;
+ key.size = sizeof(VERSION_KEY);
+ version = 2;
+ data.data = &version;
+ data.size = sizeof(version);
+ if ((rv = DB_PUT(ddb, &key, &data, 0)) < 0) {
+ warn("add version record to %s stats", uname);
+ error = -1;
+ } else if (rv == 1) {
+ warnx("duplicate version record in %s stats", uname);
+ error = -1;
+ }
+#else
+ version = 1; // avoid unused warning
+#endif
+
+ if (DB_SYNC(ddb, 0) < 0) {
+ warn("syncing %s summary", uname);
+ error = -1;
+ }
+ if (DB_CLOSE(ddb) < 0) {
+ warn("closing %s summary", uname);
+ error = -1;
+ }
+ return error;
+}
+
+void
+db_destroy(DB *db, const char *uname)
+{
+ if (DB_CLOSE(db) < 0)
+ warn("destroying %s stats", uname);
+}
diff --git a/system_cmds/sa.tproj/extern.h b/system_cmds/sa.tproj/extern.h
new file mode 100644
index 0000000..d6fcc17
--- /dev/null
+++ b/system_cmds/sa.tproj/extern.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ *
+ * $FreeBSD: src/usr.sbin/sa/extern.h,v 1.7 2007/05/22 06:51:38 dds Exp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <db.h>
+
+/* structures */
+
+/* All times are stored in 1e-6s units. */
+
+struct cmdinfo {
+ char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
+ uid_t ci_uid; /* user id */
+#ifdef __APPLE__
+ u_quad_t ci_calls; /* number of calls */
+ u_quad_t ci_etime; /* elapsed time */
+ u_quad_t ci_utime; /* user time */
+ u_quad_t ci_stime; /* system time */
+ u_quad_t ci_mem; /* memory use */
+ u_quad_t ci_io; /* number of disk i/o ops */
+#else
+ double ci_etime; /* elapsed time */
+ double ci_utime; /* user time */
+ double ci_stime; /* system time */
+ double ci_mem; /* memory use */
+ double ci_io; /* number of disk i/o ops */
+#endif
+ u_int ci_flags; /* flags; see below */
+};
+#define CI_UNPRINTABLE 0x0001 /* unprintable chars in name */
+
+struct userinfo {
+ uid_t ui_uid; /* user id; for consistency */
+ u_quad_t ui_calls; /* number of invocations */
+#ifdef __APPLE__
+ u_quad_t ui_utime; /* user time */
+ u_quad_t ui_stime; /* system time */
+ u_quad_t ui_mem; /* memory use */
+ u_quad_t ui_io; /* number of disk i/o ops */
+#else
+ double ui_utime; /* user time */
+ double ui_stime; /* system time */
+ double ui_mem; /* memory use */
+ double ui_io; /* number of disk i/o ops */
+#endif
+};
+
+/* typedefs */
+
+typedef int (*cmpf_t)(const DBT *, const DBT *);
+
+/* external functions in db.c */
+int db_copy_in(DB **mdb, const char *dbname, const char *name,
+ BTREEINFO *bti, int (*v1_to_v2)(DBT *key, DBT *data));
+int db_copy_out(DB *mdb, const char *dbname, const char *name,
+ BTREEINFO *bti);
+void db_destroy(DB *db, const char *uname);
+
+/* external functions in pdb.c */
+int pacct_init(void);
+void pacct_destroy(void);
+int pacct_add(const struct cmdinfo *);
+int pacct_update(void);
+void pacct_print(void);
+
+#ifndef __APPLE__
+/* external functions in readrec.c */
+int readrec_forward(FILE *f, struct acctv2 *av2);
+#endif
+
+/* external functions in usrdb.c */
+int usracct_init(void);
+void usracct_destroy(void);
+int usracct_add(const struct cmdinfo *);
+int usracct_update(void);
+void usracct_print(void);
+
+/* variables */
+
+extern int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+extern int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+extern u_quad_t cutoff;
+extern cmpf_t sa_cmp;
+extern const char *pdb_file, *usrdb_file;
+
+/* some #defines to help with db's stupidity */
+
+#define DB_CLOSE(db) \
+ ((*(db)->close)(db))
+#define DB_GET(db, key, data, flags) \
+ ((*(db)->get)((db), (key), (data), (flags)))
+#define DB_PUT(db, key, data, flags) \
+ ((*(db)->put)((db), (key), (data), (flags)))
+#define DB_SYNC(db, flags) \
+ ((*(db)->sync)((db), (flags)))
+#define DB_SEQ(db, key, data, flags) \
+ ((*(db)->seq)((db), (key), (data), (flags)))
diff --git a/system_cmds/sa.tproj/main.c b/system_cmds/sa.tproj/main.c
new file mode 100644
index 0000000..d8263f1
--- /dev/null
+++ b/system_cmds/sa.tproj/main.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1994 Christopher G. Demetriou\n\
+ All rights reserved.\n";
+#endif
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/sa/main.c,v 1.18 2007/05/22 06:51:38 dds Exp $");
+
+/*
+ * sa: system accounting
+ */
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static FILE *acct_load(const char *, int);
+#ifdef __APPLE__
+static u_quad_t decode_comp_t(comp_t);
+#endif
+static int cmp_comm(const char *, const char *);
+static int cmp_usrsys(const DBT *, const DBT *);
+static int cmp_avgusrsys(const DBT *, const DBT *);
+static int cmp_dkio(const DBT *, const DBT *);
+static int cmp_avgdkio(const DBT *, const DBT *);
+static int cmp_cpumem(const DBT *, const DBT *);
+static int cmp_avgcpumem(const DBT *, const DBT *);
+static int cmp_calls(const DBT *, const DBT *);
+static void usage(void);
+
+int aflag, bflag, cflag, dflag, Dflag, fflag, iflag, jflag, kflag;
+int Kflag, lflag, mflag, qflag, rflag, sflag, tflag, uflag, vflag;
+u_quad_t cutoff = 1;
+const char *pdb_file = _PATH_SAVACCT;
+const char *usrdb_file = _PATH_USRACCT;
+
+static char *dfltargv[] = { NULL };
+static int dfltargc = (sizeof dfltargv/sizeof(char *));
+
+/* default to comparing by sum of user + system time */
+cmpf_t sa_cmp = cmp_usrsys;
+
+int
+main(int argc, char **argv)
+{
+ FILE *f;
+ char pathacct[] = _PATH_ACCT;
+ int ch, error = 0;
+
+ dfltargv[0] = pathacct;
+
+ while ((ch = getopt(argc, argv, "abcdDfijkKlmnP:qrstuU:v:")) != -1)
+ switch (ch) {
+ case 'a':
+ /* print all commands */
+ aflag = 1;
+ break;
+ case 'b':
+ /* sort by per-call user/system time average */
+ bflag = 1;
+ sa_cmp = cmp_avgusrsys;
+ break;
+ case 'c':
+ /* print percentage total time */
+ cflag = 1;
+ break;
+ case 'd':
+ /* sort by averge number of disk I/O ops */
+ dflag = 1;
+ sa_cmp = cmp_avgdkio;
+ break;
+ case 'D':
+ /* print and sort by total disk I/O ops */
+ Dflag = 1;
+ sa_cmp = cmp_dkio;
+ break;
+ case 'f':
+ /* force no interactive threshold comprison */
+ fflag = 1;
+ break;
+ case 'i':
+ /* do not read in summary file */
+ iflag = 1;
+ break;
+ case 'j':
+ /* instead of total minutes, give sec/call */
+ jflag = 1;
+ break;
+ case 'k':
+ /* sort by cpu-time average memory usage */
+ kflag = 1;
+ sa_cmp = cmp_avgcpumem;
+ break;
+ case 'K':
+ /* print and sort by cpu-storage integral */
+ sa_cmp = cmp_cpumem;
+ Kflag = 1;
+ break;
+ case 'l':
+ /* separate system and user time */
+ lflag = 1;
+ break;
+ case 'm':
+ /* print procs and time per-user */
+ mflag = 1;
+ break;
+ case 'n':
+ /* sort by number of calls */
+ sa_cmp = cmp_calls;
+ break;
+ case 'P':
+ /* specify program database summary file */
+ pdb_file = optarg;
+ break;
+ case 'q':
+ /* quiet; error messages only */
+ qflag = 1;
+ break;
+ case 'r':
+ /* reverse order of sort */
+ rflag = 1;
+ break;
+ case 's':
+ /* merge accounting file into summaries */
+ sflag = 1;
+ break;
+ case 't':
+ /* report ratio of user and system times */
+ tflag = 1;
+ break;
+ case 'u':
+ /* first, print uid and command name */
+ uflag = 1;
+ break;
+ case 'U':
+ /* specify user database summary file */
+ usrdb_file = optarg;
+ break;
+ case 'v':
+ /* cull junk */
+ vflag = 1;
+ cutoff = atoi(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* various argument checking */
+ if (fflag && !vflag)
+ errx(1, "only one of -f requires -v");
+ if (fflag && aflag)
+ errx(1, "only one of -a and -v may be specified");
+ /* XXX need more argument checking */
+
+ if (!uflag) {
+ /* initialize tables */
+ if ((sflag || (!mflag && !qflag)) && pacct_init() != 0)
+ errx(1, "process accounting initialization failed");
+ if ((sflag || (mflag && !qflag)) && usracct_init() != 0)
+ errx(1, "user accounting initialization failed");
+ }
+
+ if (argc == 0) {
+ argc = dfltargc;
+ argv = dfltargv;
+ }
+
+ /* for each file specified */
+ for (; argc > 0; argc--, argv++) {
+ /*
+ * load the accounting data from the file.
+ * if it fails, go on to the next file.
+ */
+ f = acct_load(argv[0], sflag);
+ if (f == NULL)
+ continue;
+
+ if (!uflag && sflag) {
+#ifndef DEBUG
+ sigset_t nmask, omask;
+ int unmask = 1;
+
+ /*
+ * block most signals so we aren't interrupted during
+ * the update.
+ */
+ if (sigfillset(&nmask) == -1) {
+ warn("sigfillset");
+ unmask = 0;
+ error = 1;
+ }
+ if (unmask &&
+ (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1)) {
+ warn("couldn't set signal mask");
+ unmask = 0;
+ error = 1;
+ }
+#endif /* DEBUG */
+
+ /*
+ * truncate the accounting data file ASAP, to avoid
+ * losing data. don't worry about errors in updating
+ * the saved stats; better to underbill than overbill,
+ * but we want every accounting record intact.
+ */
+ if (ftruncate(fileno(f), 0) == -1) {
+ warn("couldn't truncate %s", *argv);
+ error = 1;
+ }
+
+ /*
+ * update saved user and process accounting data.
+ * note errors for later.
+ */
+ if (pacct_update() != 0 || usracct_update() != 0)
+ error = 1;
+
+#ifndef DEBUG
+ /*
+ * restore signals
+ */
+ if (unmask &&
+ (sigprocmask(SIG_SETMASK, &omask, NULL) == -1)) {
+ warn("couldn't restore signal mask");
+ error = 1;
+ }
+#endif /* DEBUG */
+ }
+
+ /*
+ * close the opened accounting file
+ */
+ if (fclose(f) == EOF) {
+ warn("fclose %s", *argv);
+ error = 1;
+ }
+ }
+
+ if (!uflag && !qflag) {
+ /* print any results we may have obtained. */
+ if (!mflag)
+ pacct_print();
+ else
+ usracct_print();
+ }
+
+ if (!uflag) {
+ /* finally, deallocate databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_destroy();
+ if (sflag || (mflag && !qflag))
+ usracct_destroy();
+ }
+
+ exit(error);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: sa [-abcdDfijkKlmnqrstu] [-P file] [-U file] [-v cutoff] [file ...]\n");
+ exit(1);
+}
+
+static FILE *
+acct_load(const char *pn, int wr)
+{
+#ifdef __APPLE__
+ struct acct ac;
+#else
+ struct acctv2 ac;
+#endif
+ struct cmdinfo ci;
+ ssize_t rv;
+ FILE *f;
+ int i;
+
+ /*
+ * open the file
+ */
+ f = fopen(pn, wr ? "r+" : "r");
+ if (f == NULL) {
+ warn("open %s %s", pn, wr ? "for read/write" : "read-only");
+ return (NULL);
+ }
+
+ /*
+ * read all we can; don't stat and open because more processes
+ * could exit, and we'd miss them
+ */
+ while (1) {
+ /* get one accounting entry and punt if there's an error */
+#ifdef __APPLE__
+ rv = read(fileno(f), &ac, sizeof(struct acct));
+ if (rv == -1)
+ warn("error reading %s", pn);
+ else if (rv > 0 && rv < (int)sizeof(struct acct))
+ warnx("short read of accounting data in %s", pn);
+ if (rv != sizeof(struct acct))
+ break;
+#else
+ rv = readrec_forward(f, &ac);
+ if (rv != 1) {
+ if (rv == EOF)
+ warn("error reading %s", pn);
+ break;
+ }
+#endif
+
+ /* decode it */
+ ci.ci_calls = 1;
+ for (i = 0; i < (int)sizeof ac.ac_comm && ac.ac_comm[i] != '\0';
+ i++) {
+ char c = ac.ac_comm[i];
+
+ if (!isascii(c) || iscntrl(c)) {
+ ci.ci_comm[i] = '?';
+ ci.ci_flags |= CI_UNPRINTABLE;
+ } else
+ ci.ci_comm[i] = c;
+ }
+#ifdef __APPLE__
+ if (ac.ac_flag & AFORK)
+ ci.ci_comm[i++] = '*';
+ ci.ci_comm[i++] = '\0';
+ ci.ci_etime = decode_comp_t(ac.ac_etime);
+ ci.ci_utime = decode_comp_t(ac.ac_utime);
+ ci.ci_stime = decode_comp_t(ac.ac_stime);
+ ci.ci_uid = ac.ac_uid;
+ ci.ci_mem = ac.ac_mem;
+ ci.ci_io = decode_comp_t(ac.ac_io) / AHZ;
+#else
+ if (ac.ac_flagx & AFORK)
+ ci.ci_comm[i++] = '*';
+ ci.ci_comm[i++] = '\0';
+ ci.ci_etime = ac.ac_etime;
+ ci.ci_utime = ac.ac_utime;
+ ci.ci_stime = ac.ac_stime;
+ ci.ci_uid = ac.ac_uid;
+ ci.ci_mem = ac.ac_mem;
+ ci.ci_io = ac.ac_io;
+#endif
+
+ if (!uflag) {
+ /* and enter it into the usracct and pacct databases */
+ if (sflag || (!mflag && !qflag))
+ pacct_add(&ci);
+ if (sflag || (mflag && !qflag))
+ usracct_add(&ci);
+ } else if (!qflag)
+#ifdef __APPLE__
+ printf("%6u %12.2f cpu %12juk mem %12ju io %s\n",
+ ci.ci_uid,
+ (ci.ci_utime + ci.ci_stime) / (double) AHZ,
+ (uintmax_t)ci.ci_mem, (uintmax_t)ci.ci_io,
+ ci.ci_comm);
+#else
+ printf("%6u %12.3lf cpu %12.0lfk mem %12.0lf io %s\n",
+ ci.ci_uid,
+ (ci.ci_utime + ci.ci_stime) / 1000000,
+ ci.ci_mem, ci.ci_io,
+ ci.ci_comm);
+#endif
+ }
+
+ /* Finally, return the file stream for possible truncation. */
+ return (f);
+}
+
+#ifdef __APPLE__
+static u_quad_t decode_comp_t(comp_t comp)
+{
+ u_quad_t rv;
+
+ /*
+ * for more info on the comp_t format, see:
+ * /usr/src/sys/kern/kern_acct.c
+ * /usr/src/sys/sys/acct.h
+ * /usr/src/usr.bin/lastcomm/lastcomm.c
+ */
+ rv = comp & 0x1fff; /* 13 bit fraction */
+ comp >>= 13; /* 3 bit base-8 exponent */
+ while (comp--)
+ rv <<= 3;
+
+ return (rv);
+}
+#endif
+
+/* sort commands, doing the right thing in terms of reversals */
+static int
+cmp_comm(const char *s1, const char *s2)
+{
+ int rv;
+
+ rv = strcmp(s1, s2);
+ if (rv == 0)
+ rv = -1;
+ return (rflag ? rv : -rv);
+}
+
+/* sort by total user and system time */
+static int
+cmp_usrsys(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+#ifdef __APPLE__
+ u_quad_t t1, t2;
+#else
+ double t1, t2;
+#endif
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t2 = c2.ci_utime + c2.ci_stime;
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average user and system time */
+static int
+cmp_avgusrsys(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+ double t1, t2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t1 /= (double) (c1.ci_calls ? c1.ci_calls : 1);
+
+ t2 = c2.ci_utime + c2.ci_stime;
+ t2 /= (double) (c2.ci_calls ? c2.ci_calls : 1);
+
+ if (t1 < t2)
+ return -1;
+ else if (t1 == t2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by total number of disk I/O operations */
+static int
+cmp_dkio(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_io < c2.ci_io)
+ return -1;
+ else if (c1.ci_io == c2.ci_io)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by average number of disk I/O operations */
+static int
+cmp_avgdkio(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+ double n1, n2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+#ifdef __APPLE__
+ n1 = (double) c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
+ n2 = (double) c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
+#else
+ n1 = c1.ci_io / (double) (c1.ci_calls ? c1.ci_calls : 1);
+ n2 = c2.ci_io / (double) (c2.ci_calls ? c2.ci_calls : 1);
+#endif
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-storage integral */
+static int
+cmp_cpumem(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_mem < c2.ci_mem)
+ return -1;
+ else if (c1.ci_mem == c2.ci_mem)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the cpu-time average memory usage */
+static int
+cmp_avgcpumem(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+#ifdef __APPLE__
+ u_quad_t t1, t2;
+#else
+ double t1, t2;
+#endif
+ double n1, n2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ t1 = c1.ci_utime + c1.ci_stime;
+ t2 = c2.ci_utime + c2.ci_stime;
+
+#ifdef __APPLE__
+ n1 = (double) c1.ci_mem / (double) (t1 ? t1 : 1);
+ n2 = (double) c2.ci_mem / (double) (t2 ? t2 : 1);
+#else
+ n1 = c1.ci_mem / (t1 ? t1 : 1);
+ n2 = c2.ci_mem / (t2 ? t2 : 1);
+#endif
+
+ if (n1 < n2)
+ return -1;
+ else if (n1 == n2)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
+
+/* sort by the number of invocations */
+static int
+cmp_calls(const DBT *d1, const DBT *d2)
+{
+ struct cmdinfo c1, c2;
+
+ memcpy(&c1, d1->data, sizeof(c1));
+ memcpy(&c2, d2->data, sizeof(c2));
+
+ if (c1.ci_calls < c2.ci_calls)
+ return -1;
+ else if (c1.ci_calls == c2.ci_calls)
+ return (cmp_comm(c1.ci_comm, c2.ci_comm));
+ else
+ return 1;
+}
diff --git a/system_cmds/sa.tproj/pathnames.h b/system_cmds/sa.tproj/pathnames.h
new file mode 100644
index 0000000..8cb7f44
--- /dev/null
+++ b/system_cmds/sa.tproj/pathnames.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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.
+ *
+ * $FreeBSD: src/usr.sbin/sa/pathnames.h,v 1.4 1999/08/28 01:19:52 peter Exp $
+ */
+
+#define _PATH_ACCT "/var/account/acct"
+#define _PATH_SAVACCT "/var/account/savacct"
+#define _PATH_USRACCT "/var/account/usracct"
diff --git a/system_cmds/sa.tproj/pdb.c b/system_cmds/sa.tproj/pdb.c
new file mode 100644
index 0000000..928aad9
--- /dev/null
+++ b/system_cmds/sa.tproj/pdb.c
@@ -0,0 +1,469 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/sa/pdb.c,v 1.14 2007/05/22 06:51:38 dds Exp $");
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int check_junk(const struct cmdinfo *);
+static void add_ci(const struct cmdinfo *, struct cmdinfo *);
+static void print_ci(const struct cmdinfo *, const struct cmdinfo *);
+
+static DB *pacct_db;
+
+/* Legacy format in AHZV1 units. */
+struct cmdinfov1 {
+ char ci_comm[MAXCOMLEN+2]; /* command name (+ '*') */
+ uid_t ci_uid; /* user id */
+ u_quad_t ci_calls; /* number of calls */
+ u_quad_t ci_etime; /* elapsed time */
+ u_quad_t ci_utime; /* user time */
+ u_quad_t ci_stime; /* system time */
+ u_quad_t ci_mem; /* memory use */
+ u_quad_t ci_io; /* number of disk i/o ops */
+ u_int ci_flags; /* flags; see below */
+};
+
+/*
+ * Convert a v1 data record into the current version.
+ * Return 0 if OK, -1 on error, setting errno.
+ */
+static int
+v1_to_v2(DBT *key __unused, DBT *data)
+{
+ struct cmdinfov1 civ1;
+ static struct cmdinfo civ2;
+
+ if (data->size != sizeof(civ1)) {
+ errno = EFTYPE;
+ return (-1);
+ }
+ memcpy(&civ1, data->data, data->size);
+ memset(&civ2, 0, sizeof(civ2));
+ memcpy(civ2.ci_comm, civ1.ci_comm, sizeof(civ2.ci_comm));
+ civ2.ci_uid = civ1.ci_uid;
+ civ2.ci_calls = civ1.ci_calls;
+ civ2.ci_etime = ((double)civ1.ci_etime / AHZV1) * 1000000;
+ civ2.ci_utime = ((double)civ1.ci_utime / AHZV1) * 1000000;
+ civ2.ci_stime = ((double)civ1.ci_stime / AHZV1) * 1000000;
+ civ2.ci_mem = civ1.ci_mem;
+ civ2.ci_io = civ1.ci_io;
+ civ2.ci_flags = civ1.ci_flags;
+ data->size = sizeof(civ2);
+ data->data = &civ2;
+ return (0);
+}
+
+/* Copy pdb_file to in-memory pacct_db. */
+int
+pacct_init(void)
+{
+ return (db_copy_in(&pacct_db, pdb_file, "process accounting",
+ NULL, v1_to_v2));
+}
+
+void
+pacct_destroy(void)
+{
+ db_destroy(pacct_db, "process accounting");
+}
+
+int
+pacct_add(const struct cmdinfo *ci)
+{
+ DBT key, data;
+ struct cmdinfo newci;
+ char keydata[sizeof ci->ci_comm];
+ int rv;
+
+ bcopy(ci->ci_comm, &keydata, sizeof keydata);
+ key.data = &keydata;
+ key.size = strlen(keydata);
+
+ rv = DB_GET(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %s from process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* XXX compare size if paranoid */
+ /* add the old data to the new data */
+ bcopy(data.data, &newci, data.size);
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newci, sizeof newci);
+ bcopy(key.data, newci.ci_comm, key.size);
+ }
+
+ add_ci(ci, &newci);
+
+ data.data = &newci;
+ data.size = sizeof newci;
+ rv = DB_PUT(pacct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %s to process accounting stats", ci->ci_comm);
+ return (-1);
+ } else if (rv == 1) {
+ warnx("duplicate key %s in process accounting stats",
+ ci->ci_comm);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Copy in-memory pacct_db to pdb_file. */
+int
+pacct_update(void)
+{
+ return (db_copy_out(pacct_db, pdb_file, "process accounting",
+ NULL));
+}
+
+void
+pacct_print(void)
+{
+ BTREEINFO bti;
+ DBT key, data, ndata;
+ DB *output_pacct_db;
+ struct cmdinfo *cip, ci, ci_total, ci_other, ci_junk;
+ int rv;
+
+ bzero(&ci_total, sizeof ci_total);
+ strcpy(ci_total.ci_comm, "");
+ bzero(&ci_other, sizeof ci_other);
+ strcpy(ci_other.ci_comm, "***other");
+ bzero(&ci_junk, sizeof ci_junk);
+ strcpy(ci_junk.ci_comm, "**junk**");
+
+ /*
+ * Retrieve them into new DB, sorted by appropriate key.
+ * At the same time, cull 'other' and 'junk'
+ */
+ bzero(&bti, sizeof bti);
+ bti.compare = sa_cmp;
+ output_pacct_db = dbopen(NULL, O_RDWR, 0, DB_BTREE, &bti);
+ if (output_pacct_db == NULL) {
+ warn("couldn't sort process accounting stats");
+ return;
+ }
+
+ ndata.data = NULL;
+ ndata.size = 0;
+ rv = DB_SEQ(pacct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ bcopy(cip, &ci, sizeof ci);
+
+ /* add to total */
+ add_ci(&ci, &ci_total);
+
+ if (vflag && ci.ci_calls <= cutoff &&
+ (fflag || check_junk(&ci))) {
+ /* put it into **junk** */
+ add_ci(&ci, &ci_junk);
+ goto next;
+ }
+ if (!aflag &&
+ ((ci.ci_flags & CI_UNPRINTABLE) != 0 || ci.ci_calls <= 1)) {
+ /* put into ***other */
+ add_ci(&ci, &ci_other);
+ goto next;
+ }
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+
+next: rv = DB_SEQ(pacct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving process accounting stats");
+ }
+
+ /* insert **junk** and ***other */
+ if (ci_junk.ci_calls != 0) {
+ data.data = &ci_junk;
+ data.size = sizeof ci_junk;
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+ if (ci_other.ci_calls != 0) {
+ data.data = &ci_other;
+ data.size = sizeof ci_other;
+ rv = DB_PUT(output_pacct_db, &data, &ndata, 0);
+ if (rv < 0)
+ warn("sorting process accounting stats");
+ }
+
+ /* print out the total */
+ print_ci(&ci_total, &ci_total);
+
+ /* print out; if reversed, print first (smallest) first */
+ rv = DB_SEQ(output_pacct_db, &data, &ndata, rflag ? R_FIRST : R_LAST);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ while (rv == 0) {
+ cip = (struct cmdinfo *) data.data;
+ bcopy(cip, &ci, sizeof ci);
+
+ print_ci(&ci, &ci_total);
+
+ rv = DB_SEQ(output_pacct_db, &data, &ndata,
+ rflag ? R_NEXT : R_PREV);
+ if (rv < 0)
+ warn("retrieving process accounting report");
+ }
+ DB_CLOSE(output_pacct_db);
+}
+
+static int
+check_junk(const struct cmdinfo *cip)
+{
+ char *cp;
+ size_t len;
+
+ fprintf(stderr, "%s (%ju) -- ", cip->ci_comm, (uintmax_t)cip->ci_calls);
+ cp = fgetln(stdin, &len);
+
+ return (cp && (cp[0] == 'y' || cp[0] == 'Y')) ? 1 : 0;
+}
+
+static void
+add_ci(const struct cmdinfo *fromcip, struct cmdinfo *tocip)
+{
+ tocip->ci_calls += fromcip->ci_calls;
+ tocip->ci_etime += fromcip->ci_etime;
+ tocip->ci_utime += fromcip->ci_utime;
+ tocip->ci_stime += fromcip->ci_stime;
+ tocip->ci_mem += fromcip->ci_mem;
+ tocip->ci_io += fromcip->ci_io;
+}
+
+#ifdef __APPLE__
+static void
+print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
+{
+ double t, c;
+ int uflow;
+
+ c = cip->ci_calls ? cip->ci_calls : 1;
+ t = (cip->ci_utime + cip->ci_stime) / (double) AHZ;
+ if (t < 0.01) {
+ t = 0.01;
+ uflow = 1;
+ } else
+ uflow = 0;
+
+ printf("%8ju ", (uintmax_t)cip->ci_calls);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_calls / (double) totalcip->ci_calls);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (jflag)
+ printf("%11.2fre ", cip->ci_etime / (double) (AHZ * c));
+ else
+ printf("%11.2fre ", cip->ci_etime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ cip->ci_etime / (double) totalcip->ci_etime);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (!lflag) {
+ if (jflag)
+ printf("%11.2fcp ", t / (double) cip->ci_calls);
+ else
+ printf("%11.2fcp ", t / 60.0);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ",
+ (cip->ci_utime + cip->ci_stime) / (double)
+ (totalcip->ci_utime + totalcip->ci_stime));
+ else
+ printf(" %4s ", "");
+ }
+ } else {
+ if (jflag)
+ printf("%11.2fu ", cip->ci_utime / (double) (AHZ * c));
+ else
+ printf("%11.2fu ", cip->ci_utime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_utime / (double) totalcip->ci_utime);
+ else
+ printf(" %4s ", "");
+ }
+ if (jflag)
+ printf("%11.2fs ", cip->ci_stime / (double) (AHZ * c));
+ else
+ printf("%11.2fs ", cip->ci_stime / (60.0 * AHZ));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.2f%% ", cip->ci_stime / (double) totalcip->ci_stime);
+ else
+ printf(" %4s ", "");
+ }
+ }
+
+ if (tflag) {
+ if (!uflow)
+ printf("%8.2fre/cp ",
+ cip->ci_etime /
+ (double) (cip->ci_utime + cip->ci_stime));
+ else
+ printf("*ignore* ");
+ }
+
+ if (Dflag)
+ printf("%10jutio ", (uintmax_t)cip->ci_io);
+ else
+ printf("%8.0favio ", cip->ci_io / c);
+
+ if (Kflag)
+ printf("%10juk*sec ", (uintmax_t)cip->ci_mem);
+ else
+ printf("%8.0fk ", cip->ci_mem / t);
+
+ printf(" %s\n", cip->ci_comm);
+}
+#else
+static void
+print_ci(const struct cmdinfo *cip, const struct cmdinfo *totalcip)
+{
+ double t, c;
+ int uflow;
+
+ c = cip->ci_calls ? cip->ci_calls : 1;
+ t = (cip->ci_utime + cip->ci_stime) / 1000000;
+ if (t < 0.01) {
+ t = 0.01;
+ uflow = 1;
+ } else
+ uflow = 0;
+
+ printf("%8ju ", (uintmax_t)cip->ci_calls);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ", cip->ci_calls /
+ (double)totalcip->ci_calls * 100);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (jflag)
+ printf("%11.3fre ", cip->ci_etime / (1000000 * c));
+ else
+ printf("%11.3fre ", cip->ci_etime / (60.0 * 1000000));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ", cip->ci_etime /
+ totalcip->ci_etime * 100);
+ else
+ printf(" %4s ", "");
+ }
+
+ if (!lflag) {
+ if (jflag)
+ printf("%11.3fcp ", t / (double) cip->ci_calls);
+ else
+ printf("%11.2fcp ", t / 60.0);
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ",
+ (cip->ci_utime + cip->ci_stime) /
+ (totalcip->ci_utime + totalcip->ci_stime) *
+ 100);
+ else
+ printf(" %4s ", "");
+ }
+ } else {
+ if (jflag)
+ printf("%11.3fu ", cip->ci_utime / (1000000 * c));
+ else
+ printf("%11.2fu ", cip->ci_utime / (60.0 * 1000000));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ", cip->ci_utime /
+ (double)totalcip->ci_utime * 100);
+ else
+ printf(" %4s ", "");
+ }
+ if (jflag)
+ printf("%11.3fs ", cip->ci_stime / (1000000 * c));
+ else
+ printf("%11.2fs ", cip->ci_stime / (60.0 * 1000000));
+ if (cflag) {
+ if (cip != totalcip)
+ printf(" %4.1f%% ", cip->ci_stime /
+ (double)totalcip->ci_stime * 100);
+ else
+ printf(" %4s ", "");
+ }
+ }
+
+ if (tflag) {
+ if (!uflow)
+ printf("%8.2fre/cp ",
+ cip->ci_etime /
+ (cip->ci_utime + cip->ci_stime));
+ else
+ printf("*ignore* ");
+ }
+
+ if (Dflag)
+ printf("%10.0fio ", cip->ci_io);
+ else
+ printf("%8.0favio ", cip->ci_io / c);
+
+ if (Kflag)
+ printf("%10.0fk*sec ", cip->ci_mem);
+ else
+ printf("%8.0fk ", cip->ci_mem / t);
+
+ printf(" %s\n", cip->ci_comm);
+}
+#endif
diff --git a/system_cmds/sa.tproj/sa.8 b/system_cmds/sa.tproj/sa.8
new file mode 100644
index 0000000..1e9540c
--- /dev/null
+++ b/system_cmds/sa.tproj/sa.8
@@ -0,0 +1,262 @@
+.\"
+.\" Copyright (c) 1994 Christopher G. Demetriou
+.\" 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 Christopher G. Demetriou.
+.\" 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.
+.\"
+.\" $FreeBSD: src/usr.sbin/sa/sa.8,v 1.20 2007/05/18 12:36:10 dds Exp $
+.\"
+.Dd May 18, 2007
+.Dt SA 8
+.Os
+.Sh NAME
+.Nm sa
+.Nd print system accounting statistics
+.Sh SYNOPSIS
+.Nm
+.Op Fl abcdDfijkKlmnqrstu
+.Op Fl P Ar file
+.Op Fl U Ar file
+.Op Fl v Ar cutoff
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility reports on, cleans up,
+and generally maintains system
+accounting files.
+.Pp
+The
+.Nm
+utility is able to condense the information in
+.Pa /var/account/acct
+into the summary files
+.Pa /var/account/savacct
+and
+.Pa /var/account/usracct ,
+which contain system statistics according
+to command name and login id, respectively.
+This condensation is desirable because on a
+large system,
+.Pa /var/account/acct
+can grow by hundreds of blocks per day.
+The summary files are normally read before
+the accounting file, so that reports include
+all available information.
+.Pp
+If file names are supplied, they are read instead of
+.Pa /var/account/acct .
+After each file is read, if the summary
+files are being updated, an updated summary will
+be saved to disk.
+Only one report is printed,
+after the last file is processed.
+.Pp
+The labels used in the output indicate the following, except
+where otherwise specified by individual options:
+.Bl -tag -width k*sec
+.It Dv avio
+Average number of I/O operations per execution
+.It Dv cp
+Sum of user and system time, in minutes
+.It Dv cpu
+Same as
+.Dv cp
+.It Dv k
+CPU-time averaged core usage, in 1k units
+.It Dv k*sec
+CPU storage integral, in 1k-core seconds
+.It Dv re
+Real time, in minutes
+.It Dv s
+System time, in minutes
+.It Dv tio
+Total number of I/O operations
+.It Dv u
+User time, in minutes
+.El
+.Pp
+The options to
+.Nm
+are:
+.Bl -tag -width Ds
+.It Fl a
+List all command names, including those containing unprintable
+characters and those used only once.
+By default,
+.Nm
+places all names containing unprintable characters and
+those used only once under the name ``***other''.
+.It Fl b
+If printing command statistics, sort output by the sum of user and system
+time divided by number of calls.
+.It Fl c
+In addition to the number of calls and the user, system and real times
+for each command, print their percentage of the total over all commands.
+.It Fl d
+If printing command statistics, sort by the average number of disk
+I/O operations.
+If printing user statistics, print the average number of
+disk I/O operations per user.
+.It Fl D
+If printing command statistics, sort and print by the total number
+of disk I/O operations.
+.It Fl f
+Force no interactive threshold comparison with the
+.Fl v
+option.
+.It Fl i
+Do not read in the summary files.
+.It Fl j
+Instead of the total minutes per category, give seconds per call.
+.It Fl k
+If printing command statistics, sort by the cpu-time average memory
+usage.
+If printing user statistics, print the cpu-time average
+memory usage.
+.It Fl K
+If printing command statistics, print and sort by the cpu-storage integral.
+.It Fl l
+Separate system and user time; normally they are combined.
+.It Fl m
+Print per-user statistics rather than per-command statistics.
+.It Fl n
+Sort by number of calls.
+.It Fl P Ar file
+Use the specified
+.Ar file
+for accessing the per-command accounting summary database,
+instead of the default
+.Pa /var/account/savacct .
+.It Fl q
+Create no output other than error messages.
+.It Fl r
+Reverse order of sort.
+.It Fl s
+Truncate the accounting files when done and merge their data
+into the summary files.
+.It Fl t
+For each command, report the ratio of real time to the sum
+of user and system cpu times.
+If the cpu time is too small to report, ``*ignore*'' appears in
+this field.
+.It Fl U Ar file
+Use the specified
+.Ar file
+for accessing the per-user accounting summary database,
+instead of the default
+.Pa /var/account/usracct .
+.It Fl u
+Superseding all other flags, for each entry
+in the accounting file, print the user ID, total seconds of cpu usage,
+total memory usage, number of I/O operations performed, and
+command name.
+.It Fl v Ar cutoff
+For each command used
+.Ar cutoff
+times or fewer, print the command name and await a reply
+from the terminal.
+If the reply begins with ``y'', add
+the command to the category ``**junk**''.
+This flag is
+used to strip garbage from the report.
+.El
+.Pp
+By default, per-command statistics will be printed.
+The number of
+calls, the total elapsed time in minutes, total cpu and user time
+in minutes, average number of I/O operations, and CPU-time
+averaged core usage will be printed.
+If the
+.Fl m
+option is specified, per-user statistics will be printed, including
+the user name, the number of commands invoked, total cpu time used
+(in minutes), total number of I/O operations, and CPU storage integral
+for each user.
+If the
+.Fl u
+option is specified, the uid, user and system time (in seconds),
+CPU storage integral, I/O usage, and command name will be printed
+for each entry in the accounting data file.
+.Pp
+If the
+.Fl u
+flag is specified, all flags other than
+.Fl q
+are ignored.
+If the
+.Fl m
+flag is specified, only the
+.Fl b ,
+.Fl d ,
+.Fl i ,
+.Fl k ,
+.Fl q ,
+and
+.Fl s
+flags are honored.
+.Sh FILES
+.Bl -tag -width /var/account/usracct -compact
+.It Pa /var/account/acct
+raw accounting data file
+.It Pa /var/account/savacct
+per-command accounting summary database
+.It Pa /var/account/usracct
+per-user accounting summary database
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr lastcomm 1 ,
+.Xr acct 5 ,
+.Xr ac 8 ,
+.Xr accton 8
+.Sh CAVEATS
+While the behavior of the options in this version of
+.Nm
+was modeled after the original version, there are some intentional
+differences and undoubtedly some unintentional ones as well.
+In
+particular, the
+.Fl q
+option has been added, and the
+.Fl m
+option now understands more options than it used to.
+.Pp
+The formats of the summary files created by this version of
+.Nm
+are very different from the those used by the original version.
+This is not considered a problem, however, because the accounting record
+format has changed as well (since user ids are now 32 bits).
+.Sh AUTHORS
+.An Chris G. Demetriou Aq cgd@postgres.berkeley.edu
+.Sh BUGS
+The number of options to this program is absurd, especially considering
+that there is not much logic behind their lettering.
+.Pp
+The field labels should be more consistent.
+.Pp
+The VM system does not record the CPU storage integral.
diff --git a/system_cmds/sa.tproj/usrdb.c b/system_cmds/sa.tproj/usrdb.c
new file mode 100644
index 0000000..e47220a
--- /dev/null
+++ b/system_cmds/sa.tproj/usrdb.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 1994 Christopher G. Demetriou
+ * 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 Christopher G. Demetriou.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * 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/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.sbin/sa/usrdb.c,v 1.16 2007/05/22 06:51:38 dds Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "extern.h"
+#include "pathnames.h"
+
+static int uid_compare(const DBT *, const DBT *);
+
+static DB *usracct_db;
+
+/* Legacy format in AHZV1 units. */
+struct userinfov1 {
+ uid_t ui_uid; /* user id; for consistency */
+ u_quad_t ui_calls; /* number of invocations */
+ u_quad_t ui_utime; /* user time */
+ u_quad_t ui_stime; /* system time */
+ u_quad_t ui_mem; /* memory use */
+ u_quad_t ui_io; /* number of disk i/o ops */
+};
+
+/*
+ * Convert a v1 data record into the current version.
+ * Return 0 if OK, -1 on error, setting errno.
+ */
+static int
+v1_to_v2(DBT *key, DBT *data)
+{
+ struct userinfov1 uiv1;
+ static struct userinfo uiv2;
+ static uid_t uid;
+
+ if (key->size != sizeof(u_long) || data->size != sizeof(uiv1)) {
+ errno = EFTYPE;
+ return (-1);
+ }
+
+ /* Convert key. */
+ key->size = sizeof(uid_t);
+ uid = (uid_t)*(u_long *)(key->data);
+ key->data = &uid;
+
+ /* Convert data. */
+ memcpy(&uiv1, data->data, data->size);
+ memset(&uiv2, 0, sizeof(uiv2));
+ uiv2.ui_uid = uiv1.ui_uid;
+ uiv2.ui_calls = uiv1.ui_calls;
+ uiv2.ui_utime = ((double)uiv1.ui_utime / AHZV1) * 1000000;
+ uiv2.ui_stime = ((double)uiv1.ui_stime / AHZV1) * 1000000;
+ uiv2.ui_mem = uiv1.ui_mem;
+ uiv2.ui_io = uiv1.ui_io;
+ data->size = sizeof(uiv2);
+ data->data = &uiv2;
+
+ return (0);
+}
+
+/* Copy usrdb_file to in-memory usracct_db. */
+int
+usracct_init(void)
+{
+ BTREEINFO bti;
+
+ bzero(&bti, sizeof bti);
+ bti.compare = uid_compare;
+
+ return (db_copy_in(&usracct_db, usrdb_file, "user accounting",
+ &bti, v1_to_v2));
+}
+
+void
+usracct_destroy(void)
+{
+ db_destroy(usracct_db, "user accounting");
+}
+
+int
+usracct_add(const struct cmdinfo *ci)
+{
+ DBT key, data;
+ struct userinfo newui;
+ uid_t uid;
+ int rv;
+
+ uid = ci->ci_uid;
+ key.data = &uid;
+ key.size = sizeof uid;
+
+ rv = DB_GET(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("get key %u from user accounting stats", uid);
+ return (-1);
+ } else if (rv == 0) { /* it's there; copy whole thing */
+ /* add the old data to the new data */
+ bcopy(data.data, &newui, data.size);
+ if (newui.ui_uid != uid) {
+ warnx("key %u != expected record number %u",
+ newui.ui_uid, uid);
+ warnx("inconsistent user accounting stats");
+ return (-1);
+ }
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newui, sizeof newui);
+ newui.ui_uid = ci->ci_uid;
+ }
+
+ newui.ui_calls += ci->ci_calls;
+ newui.ui_utime += ci->ci_utime;
+ newui.ui_stime += ci->ci_stime;
+ newui.ui_mem += ci->ci_mem;
+ newui.ui_io += ci->ci_io;
+
+ data.data = &newui;
+ data.size = sizeof newui;
+ rv = DB_PUT(usracct_db, &key, &data, 0);
+ if (rv < 0) {
+ warn("add key %u to user accounting stats", uid);
+ return (-1);
+ } else if (rv != 0) {
+ warnx("DB_PUT returned 1");
+ return (-1);
+ }
+
+ return (0);
+}
+
+/* Copy in-memory usracct_db to usrdb_file. */
+int
+usracct_update(void)
+{
+ BTREEINFO bti;
+
+ bzero(&bti, sizeof bti);
+ bti.compare = uid_compare;
+
+ return (db_copy_out(usracct_db, usrdb_file, "user accounting",
+ &bti));
+}
+
+void
+usracct_print(void)
+{
+ DBT key, data;
+ struct userinfo uistore, *ui = &uistore;
+ double t;
+ int rv;
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+
+ while (rv == 0) {
+ memcpy(ui, data.data, sizeof(struct userinfo));
+
+ printf("%-*s %9ju ", MAXLOGNAME - 1,
+ user_from_uid(ui->ui_uid, 0), (uintmax_t)ui->ui_calls);
+
+#ifdef __APPLE__
+ t = (double) (ui->ui_utime + ui->ui_stime) /
+ (double) AHZ;
+ if (t < 0.0001) /* kill divide by zero */
+ t = 0.0001;
+
+ printf("%12.2f%s ", t / 60.0, "cpu");
+
+ /* ui->ui_calls is always != 0 */
+ if (dflag)
+ printf("%12ju%s",
+ (uintmax_t)(ui->ui_io / ui->ui_calls), "avio");
+ else
+ printf("%12ju%s", (uintmax_t)ui->ui_io, "tio");
+
+ /* t is always >= 0.0001; see above */
+ if (kflag)
+ printf("%12.0f%s", ui->ui_mem / t, "k");
+ else
+ printf("%12ju%s", (uintmax_t)ui->ui_mem, "k*sec");
+#else
+ t = (ui->ui_utime + ui->ui_stime) / 1000000;
+ if (t < 0.000001) /* kill divide by zero */
+ t = 0.000001;
+
+ printf("%12.2f%s ", t / 60.0, "cpu");
+
+ /* ui->ui_calls is always != 0 */
+ if (dflag)
+ printf("%12.0f%s",
+ ui->ui_io / ui->ui_calls, "avio");
+ else
+ printf("%12.0f%s", ui->ui_io, "tio");
+
+ /* t is always >= 0.000001; see above. */
+ if (kflag)
+ printf("%12.0f%s", ui->ui_mem / t, "k");
+ else
+ printf("%12.0f%s", ui->ui_mem, "k*sec");
+#endif
+
+ printf("\n");
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_NEXT);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+ }
+}
+
+static int
+uid_compare(const DBT *k1, const DBT *k2)
+{
+ uid_t d1, d2;
+
+ bcopy(k1->data, &d1, sizeof d1);
+ bcopy(k2->data, &d2, sizeof d2);
+
+ if (d1 < d2)
+ return -1;
+ else if (d1 == d2)
+ return 0;
+ else
+ return 1;
+}
diff --git a/system_cmds/sc_usage.tproj/sc_usage.1 b/system_cmds/sc_usage.tproj/sc_usage.1
new file mode 100644
index 0000000..68e16ba
--- /dev/null
+++ b/system_cmds/sc_usage.tproj/sc_usage.1
@@ -0,0 +1,133 @@
+.\" Copyright (c) 2000, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd October 28, 2002
+.Dt SC_USAGE 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm sc_usage
+.Nd show system call usage statistics
+.Sh SYNOPSIS
+.Nm sc_usage
+.Op Fl c Ar codefile
+.Op Fl e
+.Op Fl l
+.Op Fl s Ar interval
+pid | cmd |
+.Fl E
+execute
+.Sh DESCRIPTION
+.Nm sc_usage
+displays an ongoing sample of system call and page fault usage statistics for
+a given process in a
+.Dq Li top-like
+fashion.
+It requires root privileges due to the kernel tracing facility it uses to
+operate.
+.Pp
+Page faults can be of the following types:
+.Bl -tag -width CACHEHITTT -compact
+.It PAGE_IN
+page had to read from disk
+.It ZERO_FILL
+page was created and zero filled
+.It COW
+page was copied from another page
+.It CACHE_HIT
+page was found in the cache
+.El
+.Pp
+The arguments are as follows:
+.Bl -tag -width Ds
+.It Fl c
+When the
+.Fl c
+option is specified, it expects a path to a
+.Ar codefile
+that
+contains the mappings for the system calls.
+This option overrides the default location of the system call codefile which
+is found in /usr/share/misc/trace.codes.
+.It Fl e
+Specifying the
+.Fl e
+option generates output that is sorted by call count.
+This overrides the default sort by time.
+.It Fl l
+The
+.Fl l
+option causes
+.Nm sc_usage
+to turn off its continuous window updating style of output and instead output
+as a continuous scrolling of data.
+.It Fl s
+By default,
+.Nm sc_usage
+updates its output at one second intervals.
+This sampling interval may be changed by specifying the
+.Fl s
+option.
+Enter the
+.Ar interval
+in seconds.
+.It pid | cmd | -E execute
+The last argument must be a process id, a running command name, or using the
+.Fl E
+option, an execution path followed by optional arguments.
+The system call usage data for the process or command is displayed.
+If the
+.Fl E
+flag is used, sc_usage will launch the executable, pass along any optional
+arguments and display system call usage date for that executable.
+.El
+.Pp
+The data columns displayed are as follows:
+.Bl -tag -width LAST_PATHNAME_WAITED_FOR -compact
+.Pp
+.It TYPE
+the system call type
+.It NUMBER
+the system call count
+.It CPU_TIME
+the amount of cpu time consumed
+.It WAIT_TIME
+the absolute time the process is waiting
+.It CURRENT_TYPE
+the current system call type
+.It LAST_PATHNAME_WAITED_FOR
+for each active thread, the last pathname
+that was referenced by a system call that blocked
+.It CUR_WAIT_TIME
+the cumulative time that a thread has been blocked
+.It THRD#
+the thread number
+.It PRI
+current scheduling priority
+.El
+.Pp
+The
+.Nm sc_usage
+command also displays some global state in the first few lines of output,
+including the number of preemptions, context switches, threads, faults and
+system calls, found during the sampling period.
+The current time and the elapsed time that the command has been running is also
+displayed here.
+The
+.Nm sc_usage
+command is also SIGWINCH savvy, so adjusting your window geometry may change
+the list of system calls being displayed.
+Typing a
+.Sq Li q
+will cause sc_usage to exit immediately.
+Typing any other character will cause sc_usage to reset its counters and the
+display.
+.Sh SAMPLE USAGE
+.Pp
+sc_usage Finder -e -s2
+.Pp
+.Nm sc_usage
+will sort the Finder process usage data according to system call count and
+update the output at 2 second intervals.
+.Sh SEE ALSO
+.Xr fs_usage 1 ,
+.Xr latency 1 ,
+.Xr top 1
diff --git a/system_cmds/sc_usage.tproj/sc_usage.c b/system_cmds/sc_usage.tproj/sc_usage.c
new file mode 100644
index 0000000..d704479
--- /dev/null
+++ b/system_cmds/sc_usage.tproj/sc_usage.c
@@ -0,0 +1,1787 @@
+/*
+ * Copyright (c) 1999-2019 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+cc -I. -DPRIVATE -D__APPLE_PRIVATE -O -o sc_usage sc_usage.c -lncurses
+*/
+
+#define Default_DELAY 1 /* default delay interval */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <strings.h>
+#include <nlist.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/ptrace.h>
+
+#include <libc.h>
+#include <termios.h>
+#include <curses.h>
+
+#include <sys/ioctl.h>
+
+#ifndef KERNEL_PRIVATE
+#define KERNEL_PRIVATE
+#include <sys/kdebug.h>
+#undef KERNEL_PRIVATE
+#else
+#include <sys/kdebug.h>
+#endif /*KERNEL_PRIVATE*/
+
+#include <sys/sysctl.h>
+#include <errno.h>
+#include <mach/mach_time.h>
+#include <err.h>
+#include <libutil.h>
+
+/* Number of lines of header information on the standard screen */
+#define HEADER_LINES 5
+
+int newLINES = 0;
+int Header_lines = HEADER_LINES;
+
+int how_to_sort = 0;
+int no_screen_refresh = 0;
+int execute_flag = 0;
+int topn = 0;
+int pid;
+int called = 0;
+int sort_now = 0;
+int waiting_index = 0;
+FILE *dfp = 0; /*Debug output file */
+long start_time = 0;
+
+#define SAMPLE_SIZE 20000
+
+#define DBG_ZERO_FILL_FAULT 1
+#define DBG_PAGEIN_FAULT 2
+#define DBG_COW_FAULT 3
+#define DBG_CACHE_HIT_FAULT 4
+
+#define MAX_SC 1024
+#define MAX_THREADS 16
+#define MAX_NESTED 8
+#define MAX_FAULTS 5
+
+
+#define NUMPARMS 23
+
+
+char *state_name[] = {
+ "Dont Know",
+ "Running S",
+ "Running U",
+ "Waiting",
+ "Pre-empted",
+};
+
+#define DONT_KNOW 0
+#define KERNEL_MODE 1
+#define USER_MODE 2
+#define WAITING 3
+#define PREEMPTED 4
+
+struct entry {
+ int sc_state;
+ int type;
+ int code;
+ double otime;
+ double stime;
+ double ctime;
+ double wtime;
+};
+
+struct th_info {
+ uint64_t thread;
+ int depth;
+ int vfslookup;
+ int curpri;
+ int64_t *pathptr;
+ int64_t pathname[NUMPARMS + 1];
+ struct entry th_entry[MAX_NESTED];
+};
+
+struct sc_entry {
+ char name[64];
+ int delta_count;
+ int total_count;
+ int waiting;
+ unsigned int stime_secs;
+ double stime_usecs;
+ unsigned int wtime_secs;
+ double wtime_usecs;
+ unsigned int delta_wtime_secs;
+ double delta_wtime_usecs;
+};
+
+struct th_info th_state[MAX_THREADS];
+struct sc_entry faults[MAX_FAULTS];
+
+struct sc_entry *sc_tab;
+int *msgcode_tab;
+int msgcode_cnt; /* number of MSG_ codes */
+
+int num_of_threads = 0;
+int now_collect_cpu_time = 0;
+
+unsigned int utime_secs;
+double utime_usecs;
+
+int in_idle = 0;
+unsigned int itime_secs;
+double itime_usecs;
+unsigned int delta_itime_secs;
+double delta_itime_usecs;
+double idle_start;
+
+int in_other = 0;
+unsigned int otime_secs;
+double otime_usecs;
+unsigned int delta_otime_secs;
+double delta_otime_usecs;
+double other_start;
+
+int max_sc = 0;
+int bsc_base = 0;
+int msc_base = 0;
+int mach_idle = 0;
+int mach_sched = 0;
+int mach_stkhandoff = 0;
+int vfs_lookup = 0;
+int mach_vmfault = 0;
+int bsc_exit = 0;
+int *sort_by_count;
+int *sort_by_wtime;
+
+char proc_name[32];
+
+#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
+#define DBG_FUNC_MASK 0xfffffffc
+
+int preempted;
+int csw;
+int total_faults;
+int scalls;
+
+/* Default divisor */
+#define DIVISOR 16.6666 /* Trace divisor converts to microseconds */
+double divisor = DIVISOR;
+
+int mib[6];
+size_t needed;
+void *my_buffer;
+
+kbufinfo_t bufinfo = {0, 0, 0, 0};
+
+int trace_enabled = 0;
+int set_remove_flag = 1;
+
+struct kinfo_proc *kp_buffer = 0;
+size_t kp_nentries = 0;
+
+extern char **environ;
+
+static void set_enable(int);
+static void set_pidcheck(int, int);
+static void set_remove(void);
+static void set_numbufs(int);
+static void set_init(void);
+void quit(char *);
+int argtopid(char *);
+int argtoi(int, char*, char*, int);
+
+void get_bufinfo(kbufinfo_t *);
+static void reset_counters(void);
+static void getdivisor(void);
+static void screen_update(void);
+static void sc_tab_init(char *);
+static void sort_scalls(void);
+static void sample_sc(void);
+static int find_msgcode(int);
+
+/*
+ * signal handlers
+ */
+
+/* exit under normal conditions -- INT handler */
+static void
+leave(__unused int unused)
+{
+ if (no_screen_refresh == 0) {
+ move(LINES - 1, 0);
+ refresh();
+ endwin();
+ }
+ set_enable(0);
+ set_pidcheck(pid, 0);
+ set_remove();
+ exit(0);
+}
+
+static void
+sigwinch(__unused int unused)
+{
+ if (no_screen_refresh == 0)
+ newLINES = 1;
+}
+
+static int
+exit_usage(char *myname)
+{
+ fprintf(stderr, "Usage: %s [-c codefile] [-e] [-l] [-sn] pid | cmd | -E execute path\n", myname);
+ fprintf(stderr, " -c name of codefile containing mappings for syscalls\n");
+ fprintf(stderr, " Default is /usr/share/misc/trace.codes\n");
+ fprintf(stderr, " -e enable sort by call count\n");
+ fprintf(stderr, " -l turn off top style output\n");
+ fprintf(stderr, " -sn change sample rate to every n seconds\n");
+ fprintf(stderr, " pid selects process to sample\n");
+ fprintf(stderr, " cmd selects command to sample\n");
+ fprintf(stderr, " -E Execute the given path and optional arguments\n");
+
+ exit(1);
+}
+
+#define usec_to_1000ths(t) ((t) / 1000)
+
+static void
+print_time(char *p, unsigned int useconds, unsigned int seconds)
+{
+ long minutes, hours;
+
+ minutes = seconds / 60;
+ hours = minutes / 60;
+
+ if (minutes < 100) { // up to 100 minutes
+ sprintf(p, "%02ld:%02ld.%03ld", minutes, (unsigned long)(seconds % 60),
+ (unsigned long)usec_to_1000ths(useconds));
+ }
+ else if (hours < 100) { // up to 100 hours
+ sprintf(p, "%02ld:%02ld:%02ld ", hours, (minutes % 60),
+ (unsigned long)(seconds % 60));
+ }
+ else {
+ sprintf(p, "%4ld hrs ", hours);
+ }
+}
+
+static void
+resetscr(void)
+{
+ (void)endwin();
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *myname = "sc_usage";
+ char *codefile = "/usr/share/misc/trace.codes";
+ char ch;
+ char *ptr;
+ int delay = Default_DELAY;
+
+ if ( geteuid() != 0 ) {
+ printf("'sc_usage' must be run as root...\n");
+ exit(1);
+ }
+
+#if !defined(__arm64__)
+ if (0 != reexec_to_match_kernel()) {
+ fprintf(stderr, "Could not re-execute: %d\n", errno);
+ exit(1);
+ }
+#endif
+
+ /* get our name */
+ if (argc > 0) {
+ if ((myname = rindex(argv[0], '/')) == 0) {
+ myname = argv[0];
+ }
+ else {
+ myname++;
+ }
+ }
+
+ while ((ch = getopt(argc, argv, "c:els:d:E")) != EOF) {
+ switch(ch) {
+ case 's':
+ delay = argtoi('s', "decimal number", optarg, 10);
+ break;
+ case 'e':
+ how_to_sort = 1;
+ break;
+ case 'l':
+ no_screen_refresh = 1;
+ break;
+ case 'c':
+ codefile = optarg;
+ break;
+ case 'E':
+ execute_flag = 1;
+ break;
+ default:
+ /* exit_usage(myname);*/
+ exit_usage("default");
+ }
+ }
+ argc -= optind;
+ //argv += optind;
+
+ sc_tab_init(codefile);
+
+ if (argc)
+ {
+ if (!execute_flag)
+ {
+ /* parse a pid or a command */
+ if((pid = argtopid(argv[optind])) < 0 )
+ exit_usage(myname);
+ }
+ else
+ { /* execute this command */
+
+ uid_t uid, euid;
+ gid_t gid, egid;
+
+ ptr = strrchr(argv[optind], '/');
+ if (ptr)
+ ptr++;
+ else
+ ptr = argv[optind];
+
+ strncpy(proc_name, ptr, sizeof(proc_name)-1);
+ proc_name[sizeof(proc_name)-1] = '\0';
+
+ uid= getuid();
+ gid= getgid();
+ euid= geteuid();
+ egid= getegid();
+
+ seteuid(uid);
+ setegid(gid);
+
+ fprintf(stderr, "Starting program: %s\n", argv[optind]);
+ fflush(stdout);
+ fflush(stderr);
+ switch ((pid = vfork()))
+ {
+ case -1:
+ perror("vfork: ");
+ exit(1);
+ case 0: /* child */
+ setsid();
+ ptrace(0,(pid_t)0,(caddr_t)0,0); /* PT_TRACE_ME */
+ execve(argv[optind], &argv[optind], environ);
+ perror("execve:");
+ exit(1);
+ }
+
+ seteuid(euid);
+ setegid(egid);
+ }
+ }
+ else
+ {
+ exit_usage(myname);
+ }
+
+
+ if (no_screen_refresh == 0) {
+
+ /* initializes curses and screen (last) */
+ if (initscr() == (WINDOW *) 0)
+ {
+ printf("Unrecognized TERM type, try vt100\n");
+ exit(1);
+ }
+ atexit(resetscr);
+ cbreak();
+ timeout(100);
+ noecho();
+
+ clear();
+ refresh();
+ }
+
+
+ /* set up signal handlers */
+ signal(SIGINT, leave);
+ signal(SIGQUIT, leave);
+ signal(SIGHUP, leave);
+ signal(SIGTERM, leave);
+ signal(SIGWINCH, sigwinch);
+
+ if (no_screen_refresh == 0)
+ topn = LINES - Header_lines;
+ else {
+ topn = 1024;
+ COLS = 80;
+ }
+
+ set_remove();
+ set_numbufs(SAMPLE_SIZE);
+ set_init();
+ set_pidcheck(pid, 1);
+ set_enable(1);
+ if (execute_flag)
+ ptrace(7, pid, (caddr_t)1, 0); /* PT_CONTINUE */
+ getdivisor();
+
+ if (delay == 0)
+ delay = 1;
+ if ((sort_now = 10 / delay) < 2)
+ sort_now = 2;
+
+ get_bufinfo(&bufinfo);
+
+ my_buffer = malloc(bufinfo.nkdbufs * sizeof(kd_buf));
+ if(my_buffer == (char *) 0)
+ quit("can't allocate memory for tracing info\n");
+
+ (void)sort_scalls();
+ (void)screen_update();
+
+ /* main loop */
+
+ while (1) {
+ int i;
+ char c;
+
+ for (i = 0; i < (10 * delay) && newLINES == 0; i++) {
+
+ if (no_screen_refresh == 0) {
+ if ((c = getch()) != ERR && (char)c == 'q')
+ leave(0);
+ if (c != ERR)
+ reset_counters();
+ } else
+ usleep(100000);
+ sample_sc();
+ }
+ (void)sort_scalls();
+
+ if (newLINES) {
+ /*
+ No need to check for initscr error return.
+ We won't get here if it fails on the first call.
+ */
+ endwin();
+ clear();
+ refresh();
+
+ topn = LINES - Header_lines;
+ newLINES = 0;
+ }
+ (void)screen_update();
+ }
+}
+
+static void
+print_row(struct sc_entry *se, int no_wtime)
+{
+ char tbuf[256];
+ size_t clen;
+
+ if (se->delta_count)
+ sprintf(tbuf, "%-23.23s %8d(%d)", se->name, se->total_count, se->delta_count);
+ else
+ sprintf(tbuf, "%-23.23s %8d", se->name, se->total_count);
+ clen = strlen(tbuf);
+
+ memset(&tbuf[clen], ' ', 45 - clen);
+
+ print_time(&tbuf[45], (unsigned int)(se->stime_usecs), se->stime_secs);
+ clen = strlen(tbuf);
+
+ if (no_wtime == 0 && (se->wtime_usecs || se->wtime_secs)) {
+ sprintf(&tbuf[clen], " ");
+ clen += strlen(&tbuf[clen]);
+
+ print_time(&tbuf[clen], (unsigned int)(se->wtime_usecs), se->wtime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ if (se->waiting || se->delta_wtime_usecs || se->delta_wtime_secs) {
+
+ sprintf(&tbuf[clen], "(");
+ clen += strlen(&tbuf[clen]);
+
+ print_time(&tbuf[clen], (unsigned int)(se->delta_wtime_usecs),
+ se->delta_wtime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ sprintf(&tbuf[clen], ")");
+ clen += strlen(&tbuf[clen]);
+
+ if (se->waiting) {
+ if (se->waiting == 1)
+ sprintf(&tbuf[clen], " W");
+ else
+ sprintf(&tbuf[clen], " %d", se->waiting);
+ clen += strlen(&tbuf[clen]);
+ }
+ }
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+}
+
+static void
+screen_update(void)
+{
+ char *p1, *p2, *p3;
+ char tbuf[256];
+ size_t clen;
+ size_t plen;
+ int n, i, rows;
+ long curr_time;
+ long elapsed_secs;
+ long hours;
+ long minutes;
+ struct sc_entry *se;
+ int output_lf;
+ int max_rows;
+ struct th_info *ti;
+
+ if (no_screen_refresh == 0) {
+ /* clear for new display */
+ erase();
+ move(0, 0);
+ }
+ rows = 0;
+
+ sprintf(tbuf, "%-14.14s", proc_name);
+ clen = strlen(tbuf);
+
+ if (preempted == 1)
+ p1 = "preemption ";
+ else
+ p1 = "preemptions";
+ if (csw == 1)
+ p2 = "context switch ";
+ else
+ p2 = "context switches";
+ if (num_of_threads == 1)
+ p3 = "thread ";
+ else
+ p3 = "threads";
+
+ sprintf(&tbuf[clen], " %4d %s %4d %s %4d %s",
+ preempted, p1, csw, p2, num_of_threads, p3);
+ clen += strlen(&tbuf[clen]);
+
+ /*
+ * Display the current time.
+ * "ctime" always returns a string that looks like this:
+ *
+ * Sun Sep 16 01:03:52 1973
+ * 012345678901234567890123
+ * 1 2
+ *
+ * We want indices 11 thru 18 (length 8).
+ */
+ curr_time = time((long *)0);
+
+ if (start_time == 0)
+ start_time = curr_time;
+
+ elapsed_secs = curr_time - start_time;
+ minutes = elapsed_secs / 60;
+ hours = minutes / 60;
+
+ memset(&tbuf[clen], ' ', 78 - clen);
+
+ clen = 78 - 8;
+
+ sprintf(&tbuf[clen], "%-8.8s\n", &(ctime(&curr_time)[11]));
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+
+ if (total_faults == 1)
+ p1 = "fault ";
+ else
+ p1 = "faults";
+ if (scalls == 1)
+ p2 = "system call ";
+ else
+ p2 = "system calls";
+ sprintf(tbuf, " %4d %s %4d %s",
+ total_faults, p1, scalls, p2);
+
+ clen = strlen(tbuf);
+ sprintf(&tbuf[clen], " %3ld:%02ld:%02ld\n",
+ hours, minutes % 60, elapsed_secs % 60);
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+
+
+
+ sprintf(tbuf, "\nTYPE NUMBER CPU_TIME WAIT_TIME\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+
+ sprintf(tbuf, "------------------------------------------------------------------------------\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows = 0;
+
+
+
+ sprintf(tbuf, "System Idle ");
+ clen = strlen(tbuf);
+
+ print_time(&tbuf[clen], itime_usecs, itime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ if (delta_itime_usecs || delta_itime_secs) {
+
+ sprintf(&tbuf[clen], "(");
+ clen += strlen(&tbuf[clen]);
+
+ print_time(&tbuf[clen], delta_itime_usecs, delta_itime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ sprintf(&tbuf[clen], ")");
+ clen += strlen(&tbuf[clen]);
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+
+
+ sprintf(tbuf, "System Busy ");
+ clen = strlen(tbuf);
+
+ print_time(&tbuf[clen], otime_usecs, otime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ if (delta_otime_usecs || delta_otime_secs) {
+
+ sprintf(&tbuf[clen], "(");
+ clen += strlen(&tbuf[clen]);
+
+ print_time(&tbuf[clen], delta_otime_usecs, delta_otime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ sprintf(&tbuf[clen], ")");
+ clen += strlen(&tbuf[clen]);
+ }
+ sprintf(&tbuf[clen], "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+
+ sprintf(tbuf, "%-14.14s Usermode ", proc_name);
+ clen = strlen(tbuf);
+
+ print_time(&tbuf[clen], utime_usecs, utime_secs);
+ clen += strlen(&tbuf[clen]);
+
+ sprintf(&tbuf[clen], "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+ if (num_of_threads)
+ max_rows = topn - (num_of_threads + 3);
+ else
+ max_rows = topn;
+
+ for (output_lf = 1, n = 1; rows < max_rows && n < MAX_FAULTS; n++) {
+ se = &faults[n];
+
+ if (se->total_count == 0)
+ continue;
+ if (output_lf == 1) {
+ sprintf(tbuf, "\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+ if (rows >= max_rows)
+ break;
+ output_lf = 0;
+ }
+ print_row(se, 0);
+ rows++;
+ }
+ sprintf(tbuf, "\n");
+
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ rows++;
+
+ for (i = 0; rows < max_rows; i++) {
+ if (how_to_sort)
+ n = sort_by_count[i];
+ else
+ n = sort_by_wtime[i];
+ if (n == -1)
+ break;
+ print_row(&sc_tab[n], 0);
+ rows++;
+ }
+
+
+ sprintf(tbuf, "\n");
+ if (no_screen_refresh == 0) {
+ while (rows++ < max_rows)
+ printw(tbuf);
+ } else
+ printf("%s", tbuf);
+
+ if (num_of_threads) {
+ sprintf(tbuf, "\nCURRENT_TYPE LAST_PATHNAME_WAITED_FOR CUR_WAIT_TIME THRD# PRI\n");
+
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+
+ sprintf(tbuf, "------------------------------------------------------------------------------\n");
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ }
+ ti = &th_state[0];
+
+ for (i = 0; i < num_of_threads; i++, ti++) {
+ struct entry *te;
+ char *p;
+ uint64_t now;
+ int secs, time_secs, time_usecs;
+
+ now = mach_absolute_time();
+
+ while (ti->thread == 0 && ti < &th_state[MAX_THREADS])
+ ti++;
+ if (ti == &th_state[MAX_THREADS])
+ break;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth - 1];
+
+ if (te->sc_state == WAITING) {
+ if (te->code)
+ sprintf(tbuf, "%-23.23s", sc_tab[te->code].name);
+ else
+ sprintf(tbuf, "%-23.23s", "vm_fault");
+ } else
+ sprintf(tbuf, "%-23.23s", state_name[te->sc_state]);
+ } else {
+ te = &ti->th_entry[0];
+ sprintf(tbuf, "%-23.23s", state_name[te->sc_state]);
+ }
+ clen = strlen(tbuf);
+
+ /* print the tail end of the pathname */
+ p = (char *)ti->pathname;
+
+ plen = strlen(p);
+ if (plen > 26)
+ plen -= 26;
+ else
+ plen = 0;
+ sprintf(&tbuf[clen], " %-26.26s ", &p[plen]);
+
+ clen += strlen(&tbuf[clen]);
+
+ time_usecs = (((double)now - te->otime) / divisor);
+ secs = time_usecs / 1000000;
+ time_usecs -= secs * 1000000;
+ time_secs = secs;
+
+ print_time(&tbuf[clen], time_usecs, time_secs);
+ clen += strlen(&tbuf[clen]);
+ sprintf(&tbuf[clen], " %2d %3d\n", i, ti->curpri);
+ if (no_screen_refresh)
+ printf("%s", tbuf);
+ else
+ printw(tbuf);
+ }
+ if (no_screen_refresh == 0) {
+ move(0, 0);
+ refresh();
+ } else
+ printf("\n=================\n");
+
+
+
+ for (i = 0; i < (MAX_SC + msgcode_cnt); i++) {
+ if ((n = sort_by_count[i]) == -1)
+ break;
+ sc_tab[n].delta_count = 0;
+ sc_tab[n].waiting = 0;
+ sc_tab[n].delta_wtime_usecs = 0;
+ sc_tab[n].delta_wtime_secs = 0;
+ }
+ for (i = 1; i < MAX_FAULTS; i++) {
+ faults[i].delta_count = 0;
+ faults[i].waiting = 0;
+ faults[i].delta_wtime_usecs = 0;
+ faults[i].delta_wtime_secs = 0;
+ }
+ preempted = 0;
+ csw = 0;
+ total_faults = 0;
+ scalls = 0;
+ delta_itime_secs = 0;
+ delta_itime_usecs = 0;
+ delta_otime_secs = 0;
+ delta_otime_usecs = 0;
+}
+
+static void
+reset_counters(void)
+{
+ int i;
+
+ for (i = 0; i < (MAX_SC + msgcode_cnt) ; i++) {
+ sc_tab[i].delta_count = 0;
+ sc_tab[i].total_count = 0;
+ sc_tab[i].waiting = 0;
+ sc_tab[i].delta_wtime_usecs = 0;
+ sc_tab[i].delta_wtime_secs = 0;
+ sc_tab[i].wtime_usecs = 0;
+ sc_tab[i].wtime_secs = 0;
+ sc_tab[i].stime_usecs = 0;
+ sc_tab[i].stime_secs = 0;
+ }
+ for (i = 1; i < MAX_FAULTS; i++) {
+ faults[i].delta_count = 0;
+ faults[i].total_count = 0;
+ faults[i].waiting = 0;
+ faults[i].delta_wtime_usecs = 0;
+ faults[i].delta_wtime_secs = 0;
+ faults[i].wtime_usecs = 0;
+ faults[i].wtime_secs = 0;
+ faults[i].stime_usecs = 0;
+ faults[i].stime_secs = 0;
+ }
+ preempted = 0;
+ csw = 0;
+ total_faults = 0;
+ scalls = 0;
+ called = 0;
+
+ utime_secs = 0;
+ utime_usecs = 0;
+ itime_secs = 0;
+ itime_usecs = 0;
+ delta_itime_secs = 0;
+ delta_itime_usecs = 0;
+ otime_secs = 0;
+ otime_usecs = 0;
+ delta_otime_secs = 0;
+ delta_otime_usecs = 0;
+}
+
+static void
+sc_tab_init(char *codefile)
+{
+ int code;
+ int n;
+ int msgcode_indx=0;
+ char name[56];
+ FILE *fp;
+
+ if ((fp = fopen(codefile,"r")) == (FILE *)0) {
+ printf("Failed to open code description file %s\n", codefile);
+ exit(1);
+ }
+
+ /* Count Mach message MSG_ codes */
+ for (msgcode_cnt=0;;) {
+ n = fscanf(fp, "%x%55s\n", &code, &name[0]);
+ if (n != 2)
+ break;
+ if (strncmp ("MSG_", &name[0], 4) == 0)
+ msgcode_cnt++;
+ if (strcmp("TRACE_LAST_WRAPPER", &name[0]) == 0)
+ break;
+ }
+
+ sc_tab = (struct sc_entry *)malloc((MAX_SC+msgcode_cnt) * sizeof (struct sc_entry));
+ if(!sc_tab)
+ quit("can't allocate memory for system call table\n");
+ bzero(sc_tab,(MAX_SC+msgcode_cnt) * sizeof (struct sc_entry));
+
+ msgcode_tab = (int *)malloc(msgcode_cnt * sizeof(int));
+ if (!msgcode_tab)
+ quit("can't allocate memory for msgcode table\n");
+ bzero(msgcode_tab,(msgcode_cnt * sizeof(int)));
+
+ sort_by_count = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int));
+ if (!sort_by_count)
+ quit("can't allocate memory for sort_by_count table\n");
+ bzero(sort_by_count,(MAX_SC + msgcode_cnt + 1) * sizeof(int));
+
+ sort_by_wtime = (int *)malloc((MAX_SC + msgcode_cnt + 1) * sizeof(int));
+ if (!sort_by_wtime)
+ quit("can't allocate memory for sort_by_wtime table\n");
+ bzero(sort_by_wtime, (MAX_SC + msgcode_cnt + 1) * sizeof(int));
+
+
+ rewind(fp);
+
+ for (;;) {
+ n = fscanf(fp, "%x%55s\n", &code, &name[0]);
+
+ if (n != 2)
+ break;
+
+ if (strcmp("MACH_vmfault", &name[0]) == 0) {
+ mach_vmfault = code;
+ continue;
+ }
+ if (strcmp("MACH_SCHED", &name[0]) == 0) {
+ mach_sched = code;
+ continue;
+ }
+ if (strcmp("MACH_STKHANDOFF", &name[0]) == 0) {
+ mach_stkhandoff = code;
+ continue;
+ }
+ if (strcmp("MACH_IDLE", &name[0]) == 0) {
+ mach_idle = code;
+ continue;
+ }
+ if (strcmp("VFS_LOOKUP", &name[0]) == 0) {
+ vfs_lookup = code;
+ continue;
+ }
+ if (strcmp("BSC_SysCall", &name[0]) == 0) {
+ bsc_base = code;
+ continue;
+ }
+ if (strcmp("MACH_SysCall", &name[0]) == 0) {
+ msc_base = code;
+ continue;
+ }
+ if (strcmp("BSC_exit", &name[0]) == 0) {
+ bsc_exit = code;
+ continue;
+ }
+ if (strncmp("MSG_", &name[0], 4) == 0) {
+ msgcode_tab[msgcode_indx] = ((code & 0x00ffffff) >>2);
+ n = MAX_SC + msgcode_indx;
+ strncpy(&sc_tab[n].name[0], &name[4], 31 );
+ msgcode_indx++;
+ continue;
+ }
+ if (strncmp("MSC_", &name[0], 4) == 0) {
+ n = 512 + ((code>>2) & 0x1ff);
+ strcpy(&sc_tab[n].name[0], &name[4]);
+ continue;
+ }
+ if (strncmp("BSC_", &name[0], 4) == 0) {
+ n = (code>>2) & 0x1ff;
+ strcpy(&sc_tab[n].name[0], &name[4]);
+ continue;
+ }
+ if (strcmp("TRACE_LAST_WRAPPER", &name[0]) == 0)
+ break;
+ }
+ strcpy(&faults[1].name[0], "zero_fill");
+ strcpy(&faults[2].name[0], "pagein");
+ strcpy(&faults[3].name[0], "copy_on_write");
+ strcpy(&faults[4].name[0], "cache_hit");
+}
+
+static void
+find_proc_names(void)
+{
+ size_t bufSize = 0;
+ struct kinfo_proc *kp;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_ALL;
+ mib[3] = 0;
+
+ if (sysctl(mib, 4, NULL, &bufSize, NULL, 0) < 0)
+ quit("trace facility failure, KERN_PROC_ALL\n");
+
+ if((kp = (struct kinfo_proc *)malloc(bufSize)) == (struct kinfo_proc *)0)
+ quit("can't allocate memory for proc buffer\n");
+
+ if (sysctl(mib, 4, kp, &bufSize, NULL, 0) < 0)
+ quit("trace facility failure, KERN_PROC_ALL\n");
+
+ kp_nentries = bufSize/ sizeof(struct kinfo_proc);
+ kp_buffer = kp;
+}
+
+static struct th_info *
+find_thread(uint64_t thread)
+{
+ struct th_info *ti;
+
+ for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
+ if (ti->thread == thread)
+ return(ti);
+ }
+ return ((struct th_info *)0);
+}
+
+static int
+cmp_wtime(struct sc_entry *s1, struct sc_entry *s2)
+{
+ if (s1->wtime_secs < s2->wtime_secs)
+ return 0;
+ if (s1->wtime_secs > s2->wtime_secs)
+ return 1;
+ if (s1->wtime_usecs <= s2->wtime_usecs)
+ return 0;
+ return 1;
+}
+
+static void
+sort_scalls(void)
+{
+ int i, n, k, cnt, secs;
+ struct th_info *ti;
+ struct sc_entry *se;
+ struct entry *te;
+ uint64_t now;
+
+ now = mach_absolute_time();
+
+ for (ti = th_state; ti < &th_state[MAX_THREADS]; ti++) {
+ if (ti->thread == 0)
+ continue;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->sc_state == WAITING) {
+ if (te->code)
+ se = &sc_tab[te->code];
+ else
+ se = &faults[DBG_PAGEIN_FAULT];
+ se->waiting++;
+ se->wtime_usecs += ((double)now - te->stime) / divisor;
+ se->delta_wtime_usecs += ((double)now - te->stime) / divisor;
+ te->stime = (double)now;
+
+ secs = se->wtime_usecs / 1000000;
+ se->wtime_usecs -= secs * 1000000;
+ se->wtime_secs += secs;
+
+ secs = se->delta_wtime_usecs / 1000000;
+ se->delta_wtime_usecs -= secs * 1000000;
+ se->delta_wtime_secs += secs;
+ }
+ } else {
+ te = &ti->th_entry[0];
+
+ if (te->sc_state == PREEMPTED) {
+ if ((unsigned long)(((double)now - te->otime) / divisor) > 5000000) {
+ ti->thread = 0;
+ ti->vfslookup = 0;
+ ti->pathptr = (int64_t *)NULL;
+ ti->pathname[0] = 0;
+ num_of_threads--;
+ }
+ }
+ }
+ }
+ if ((called % sort_now) == 0) {
+ sort_by_count[0] = -1;
+ sort_by_wtime[0] = -1;
+ for (cnt = 1, n = 1; n < (MAX_SC + msgcode_cnt); n++) {
+ if (sc_tab[n].total_count) {
+ for (i = 0; i < cnt; i++) {
+ if ((k = sort_by_count[i]) == -1 ||
+ sc_tab[n].total_count > sc_tab[k].total_count) {
+
+ for (k = cnt - 1; k >= i; k--)
+ sort_by_count[k+1] = sort_by_count[k];
+ sort_by_count[i] = n;
+ break;
+ }
+ }
+ if (how_to_sort == 0) {
+ for (i = 0; i < cnt; i++) {
+ if ((k = sort_by_wtime[i]) == -1 ||
+ cmp_wtime(&sc_tab[n], &sc_tab[k])) {
+
+ for (k = cnt - 1; k >= i; k--)
+ sort_by_wtime[k+1] = sort_by_wtime[k];
+ sort_by_wtime[i] = n;
+ break;
+ }
+ }
+ }
+ cnt++;
+ }
+ }
+ }
+ called++;
+}
+
+static void
+set_enable(int val)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDENABLE; /* protocol */
+ mib[3] = val;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDENABLE\n");
+
+ if (val)
+ trace_enabled = 1;
+ else
+ trace_enabled = 0;
+}
+
+static void
+set_numbufs(int nbufs)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETBUF;
+ mib[3] = nbufs;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETBUF\n");
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETUP\n");
+
+}
+
+static void
+set_pidcheck(int pid, int on_off)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_TYPENONE;
+ kr.value1 = pid;
+ kr.value2 = on_off;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDPIDTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0) {
+ if (on_off == 1) {
+ printf("pid %d does not exist\n", pid);
+ set_remove();
+ exit(2);
+ }
+ }
+}
+
+void
+get_bufinfo(kbufinfo_t *val)
+{
+ needed = sizeof (*val);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDGETBUF;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
+ quit("trace facility failure, KERN_KDGETBUF\n");
+
+}
+
+static void
+set_remove(void)
+{
+ extern int errno;
+
+ errno = 0;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREMOVE; /* protocol */
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ {
+ set_remove_flag = 0;
+
+ if (errno == EBUSY)
+ quit("The trace facility is currently in use...\n Note: fs_usage, sc_usage, and latency use this feature.\n\n");
+ else
+ quit("trace facility failure, KERN_KDREMOVE\n");
+ }
+}
+
+static void
+set_init(void)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_RANGETYPE;
+ kr.value1 = 0;
+ kr.value2 = -1;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETREG;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETREG\n");
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDSETUP\n");
+}
+
+static void
+sample_sc(void)
+{
+ kd_buf *kd;
+ int i;
+ size_t count;
+ int secs;
+
+#ifdef OLD_KDEBUG
+ set_enable(0);
+#endif
+ get_bufinfo(&bufinfo);
+
+ needed = bufinfo.nkdbufs * sizeof(kd_buf);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREADTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 3, my_buffer, &needed, NULL, 0) < 0)
+ quit("trace facility failure, KERN_KDREADTR\n");
+
+ count = needed;
+
+ if (bufinfo.flags & KDBG_WRAPPED) {
+ for (i = 0; i < MAX_THREADS; i++) {
+ th_state[i].depth = 0;
+ th_state[i].thread = 0;
+ th_state[i].vfslookup = 0;
+ th_state[i].pathptr = (int64_t *)NULL;
+ th_state[i].pathname[0] = 0;
+ }
+ num_of_threads = 0;
+ }
+
+#ifdef OLD_KDEBUG
+ set_remove();
+ set_init();
+ set_pidcheck(pid, 1);
+ set_enable(1); /* re-enable kernel logging */
+#endif
+ kd = (kd_buf *)my_buffer;
+
+ for (i = 0; i < count; i++) {
+ int debugid, baseid;
+ uint64_t thread;
+ int type, code;
+ uint64_t now;
+ struct th_info *ti, *switched_out, *switched_in;
+ struct sc_entry *se;
+ struct entry *te;
+
+ thread = kd[i].arg5;
+ debugid = kd[i].debugid;
+ type = kd[i].debugid & DBG_FUNC_MASK;
+
+ code = 0;
+ switched_out = (struct th_info *)0;
+ switched_in = (struct th_info *)0;
+
+ now = kd[i].timestamp & KDBG_TIMESTAMP_MASK;
+
+ baseid = debugid & 0xffff0000;
+
+ if (type == vfs_lookup) {
+ int64_t *sargptr;
+
+ if ((ti = find_thread(thread)) == (struct th_info *)0)
+ continue;
+
+ if (ti->vfslookup == 1) {
+ ti->vfslookup++;
+ sargptr = ti->pathname;
+
+ *sargptr++ = kd[i].arg2;
+ *sargptr++ = kd[i].arg3;
+ *sargptr++ = kd[i].arg4;
+ /*
+ * NULL terminate the 'string'
+ */
+ *sargptr = 0;
+
+ ti->pathptr = sargptr;
+
+ } else if (ti->vfslookup > 1) {
+ ti->vfslookup++;
+ sargptr = ti->pathptr;
+
+ /*
+ We don't want to overrun our pathname buffer if the
+ kernel sends us more VFS_LOOKUP entries than we can
+ handle.
+ */
+
+ if (sargptr >= &ti->pathname[NUMPARMS])
+ continue;
+
+ /*
+ We need to detect consecutive vfslookup entries.
+ So, if we get here and find a START entry,
+ fake the pathptr so we can bypass all further
+ vfslookup entries.
+ */
+
+ if (debugid & DBG_FUNC_START)
+ {
+ ti->pathptr = &ti->pathname[NUMPARMS];
+ continue;
+ }
+
+ *sargptr++ = kd[i].arg1;
+ *sargptr++ = kd[i].arg2;
+ *sargptr++ = kd[i].arg3;
+ *sargptr++ = kd[i].arg4;
+ /*
+ * NULL terminate the 'string'
+ */
+ *sargptr = 0;
+
+ ti->pathptr = sargptr;
+ }
+ continue;
+
+ } else if (baseid == bsc_base)
+ code = (debugid >> 2) & 0x1ff;
+ else if (baseid == msc_base)
+ code = 512 + ((debugid >> 2) & 0x1ff);
+ else if (type == mach_idle) {
+ if (debugid & DBG_FUNC_START) {
+ switched_out = find_thread(kd[i].arg5);
+ switched_in = 0;
+ }
+ else
+ if (debugid & DBG_FUNC_END) {
+ switched_in = find_thread(kd[i].arg5);
+ switched_out = 0;
+ }
+
+ if (in_idle) {
+ itime_usecs += ((double)now - idle_start) / divisor;
+ delta_itime_usecs += ((double)now - idle_start) / divisor;
+ in_idle = 0;
+ } else if (in_other) {
+ otime_usecs += ((double)now - other_start) / divisor;
+ delta_otime_usecs += ((double)now - other_start) / divisor;
+ in_other = 0;
+ }
+ if ( !switched_in) {
+ /*
+ * not one of the target proc's threads
+ */
+ if (now_collect_cpu_time) {
+ in_idle = 1;
+ idle_start = (double)now;
+ }
+ }
+ else {
+ if (now_collect_cpu_time) {
+ in_idle = 0;
+ in_other = 1;
+ other_start = (double)now;
+ }
+ }
+ if ( !switched_in && !switched_out)
+ continue;
+
+ }
+ else if (type == mach_sched || type == mach_stkhandoff) {
+ switched_out = find_thread(kd[i].arg5);
+ switched_in = find_thread(kd[i].arg2);
+
+ if (in_idle) {
+ itime_usecs += ((double)now - idle_start) / divisor;
+ delta_itime_usecs += ((double)now - idle_start) / divisor;
+ in_idle = 0;
+ } else if (in_other) {
+ otime_usecs += ((double)now - other_start) / divisor;
+ delta_otime_usecs += ((double)now - other_start) / divisor;
+ in_other = 0;
+ }
+ if ( !switched_in) {
+ /*
+ * not one of the target proc's threads
+ */
+ if (now_collect_cpu_time) {
+ in_other = 1;
+ other_start = (double)now;
+ }
+ }
+ if ( !switched_in && !switched_out)
+ continue;
+
+ }
+ else if ((baseid & 0xff000000) == 0xff000000) {
+ code = find_msgcode (debugid);
+ if (!code)
+ continue;
+ } else if (baseid != mach_vmfault)
+ continue;
+
+ if (switched_out || switched_in) {
+ if (switched_out) {
+ ti = switched_out;
+ ti->curpri = (int)kd[i].arg3;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->sc_state == KERNEL_MODE)
+ te->ctime += (double)now - te->stime;
+ te->sc_state = WAITING;
+
+ ti->vfslookup = 1;
+
+ } else {
+ te = &ti->th_entry[0];
+
+ if (te->sc_state == USER_MODE)
+ utime_usecs += ((double)now - te->stime) / divisor;
+ te->sc_state = PREEMPTED;
+ preempted++;
+ }
+ te->stime = (double)now;
+ te->otime = (double)now;
+ now_collect_cpu_time = 1;
+ csw++;
+ }
+ if (switched_in) {
+ ti = switched_in;
+ ti->curpri = (int)kd[i].arg4;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->sc_state == WAITING)
+ te->wtime += (double)now - te->stime;
+ te->sc_state = KERNEL_MODE;
+ } else {
+ te = &ti->th_entry[0];
+
+ te->sc_state = USER_MODE;
+ }
+ te->stime = (double)now;
+ te->otime = (double)now;
+ }
+ continue;
+ }
+ if ((ti = find_thread(thread)) == (struct th_info *)0) {
+ for (ti = &th_state[0]; ti < &th_state[MAX_THREADS]; ti++) {
+ if (ti->thread == 0) {
+ ti->thread = thread;
+ num_of_threads++;
+ break;
+ }
+ }
+ if (ti == &th_state[MAX_THREADS])
+ continue;
+ }
+ if (debugid & DBG_FUNC_START) {
+ ti->vfslookup = 0;
+
+ if (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->sc_state == KERNEL_MODE)
+ te->ctime += (double)now - te->stime;
+ } else {
+ te = &ti->th_entry[0];
+
+ if (te->sc_state == USER_MODE)
+ utime_usecs += ((double)now - te->stime) / divisor;
+ }
+ te->stime = (double)now;
+ te->otime = (double)now;
+
+ if (ti->depth < MAX_NESTED) {
+ te = &ti->th_entry[ti->depth];
+
+ te->sc_state = KERNEL_MODE;
+ te->type = type;
+ te->code = code;
+ te->stime = (double)now;
+ te->otime = (double)now;
+ te->ctime = (double)0;
+ te->wtime = (double)0;
+ ti->depth++;
+ }
+
+ } else if (debugid & DBG_FUNC_END) {
+ if (code) {
+ se = &sc_tab[code];
+ scalls++;
+ } else {
+ se = &faults[kd[i].arg4];
+ total_faults++;
+ }
+ if (se->total_count == 0)
+ called = 0;
+ se->delta_count++;
+ se->total_count++;
+
+ while (ti->depth) {
+ te = &ti->th_entry[ti->depth-1];
+
+ if (te->type == type) {
+ se->stime_usecs += te->ctime / divisor;
+ se->stime_usecs += ((double)now - te->stime) / divisor;
+
+ se->wtime_usecs += te->wtime / divisor;
+ se->delta_wtime_usecs += te->wtime / divisor;
+
+ secs = se->stime_usecs / 1000000;
+ se->stime_usecs -= secs * 1000000;
+ se->stime_secs += secs;
+
+ secs = se->wtime_usecs / 1000000;
+ se->wtime_usecs -= secs * 1000000;
+ se->wtime_secs += secs;
+
+ secs = se->delta_wtime_usecs / 1000000;
+ se->delta_wtime_usecs -= secs * 1000000;
+ se->delta_wtime_secs += secs;
+
+ ti->depth--;
+
+ if (ti->depth == 0) {
+ /*
+ * headed back to user mode
+ * start the time accumulation
+ */
+ te = &ti->th_entry[0];
+ te->sc_state = USER_MODE;
+ } else
+ te = &ti->th_entry[ti->depth-1];
+
+ te->stime = (double)now;
+ te->otime = (double)now;
+
+ break;
+ }
+ ti->depth--;
+
+ if (ti->depth == 0) {
+ /*
+ * headed back to user mode
+ * start the time accumulation
+ */
+ te = &ti->th_entry[0];
+ te->sc_state = USER_MODE;
+ te->stime = (double)now;
+ te->otime = (double)now;
+ }
+ }
+ }
+ }
+ secs = utime_usecs / 1000000;
+ utime_usecs -= secs * 1000000;
+ utime_secs += secs;
+
+ secs = itime_usecs / 1000000;
+ itime_usecs -= secs * 1000000;
+ itime_secs += secs;
+
+ secs = delta_itime_usecs / 1000000;
+ delta_itime_usecs -= secs * 1000000;
+ delta_itime_secs += secs;
+
+ secs = otime_usecs / 1000000;
+ otime_usecs -= secs * 1000000;
+ otime_secs += secs;
+
+ secs = delta_otime_usecs / 1000000;
+ delta_otime_usecs -= secs * 1000000;
+ delta_otime_secs += secs;
+}
+
+void
+quit(char *s)
+{
+ if (trace_enabled)
+ set_enable(0);
+
+ /*
+ This flag is turned off when calling
+ quit() due to a set_remove() failure.
+ */
+ if (set_remove_flag)
+ set_remove();
+
+ if (no_screen_refresh == 0) {
+ /* clear for new display */
+ erase();
+ move(0, 0);
+ refresh();
+ endwin();
+ }
+
+ printf("sc_usage: ");
+ if (s)
+ printf("%s", s);
+
+ exit(1);
+}
+
+static void
+getdivisor(void)
+{
+ mach_timebase_info_data_t info;
+
+ (void) mach_timebase_info (&info);
+
+ divisor = ( (double)info.denom / (double)info.numer) * 1000;
+}
+
+int
+argtopid(char *str)
+{
+ char *cp;
+ int ret;
+ int i;
+
+ if (!kp_buffer)
+ find_proc_names();
+
+ ret = (int)strtol(str, &cp, 10);
+ if (cp == str || *cp) {
+ /* Assume this is a command string and find first matching pid */
+ for (i=0; i < kp_nentries; i++) {
+ if (kp_buffer[i].kp_proc.p_stat == 0)
+ continue;
+ else {
+ if (!strcmp(str, kp_buffer[i].kp_proc.p_comm)) {
+ strncpy(proc_name,
+ kp_buffer[i].kp_proc.p_comm,
+ sizeof(proc_name)-1);
+ proc_name[sizeof(proc_name)-1] = '\0';
+ return (kp_buffer[i].kp_proc.p_pid);
+ }
+ }
+ }
+ } else {
+ for (i=0; i < kp_nentries; i++) {
+ if (kp_buffer[i].kp_proc.p_stat == 0)
+ continue;
+ else if (kp_buffer[i].kp_proc.p_pid == ret) {
+ strncpy(proc_name,
+ kp_buffer[i].kp_proc.p_comm,
+ sizeof(proc_name)-1);
+ proc_name[sizeof(proc_name)-1] = '\0';
+ return (kp_buffer[i].kp_proc.p_pid);
+ }
+ }
+ }
+ return (-1);
+}
+
+/* Returns index into sc_tab for a mach msg entry */
+static int
+find_msgcode(int debugid)
+{
+ int indx;
+
+ for (indx=0; indx< msgcode_cnt; indx++) {
+ if (msgcode_tab[indx] == ((debugid & 0x00ffffff) >>2))
+ return (MAX_SC+indx);
+ }
+ return (0);
+}
+
+int
+argtoi(int flag, char *req, char *str, int base)
+{
+ char *cp;
+ int ret;
+
+ ret = (int)strtol(str, &cp, base);
+ if (cp == str || *cp)
+ errx(EINVAL, "-%c flag requires a %s", flag, req);
+ return (ret);
+}
diff --git a/system_cmds/shutdown.tproj/kextmanager.defs b/system_cmds/shutdown.tproj/kextmanager.defs
new file mode 100644
index 0000000..6ae21ce
--- /dev/null
+++ b/system_cmds/shutdown.tproj/kextmanager.defs
@@ -0,0 +1,6 @@
+#include <TargetConditionals.h>
+#if (TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
+subsystem dummy 0;
+#else
+#include <IOKit/kext/kextmanager_mig.defs>
+#endif
diff --git a/system_cmds/shutdown.tproj/pathnames.h b/system_cmds/shutdown.tproj/pathnames.h
new file mode 100644
index 0000000..7e024e0
--- /dev/null
+++ b/system_cmds/shutdown.tproj/pathnames.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <paths.h>
+
+#define _PATH_FASTBOOT "/fastboot"
+#define _PATH_HALT "/sbin/halt"
+#define _PATH_REBOOT "/sbin/reboot"
+#define _PATH_WALL "/usr/bin/wall"
diff --git a/system_cmds/shutdown.tproj/shutdown.8 b/system_cmds/shutdown.tproj/shutdown.8
new file mode 100644
index 0000000..7ca6c49
--- /dev/null
+++ b/system_cmds/shutdown.tproj/shutdown.8
@@ -0,0 +1,176 @@
+.\" Copyright (c) 1988, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)shutdown.8 8.2 (Berkeley) 4/27/95
+.\" $FreeBSD: src/sbin/shutdown/shutdown.8,v 1.21 2002/12/23 16:04:50 ru Exp $
+.\"
+.Dd December 11, 1998
+.Dt SHUTDOWN 8
+.Os
+.Sh NAME
+.Nm shutdown
+.Nd "close down the system at a given time"
+.Sh SYNOPSIS
+.Nm shutdown
+.Op Fl
+.Oo
+.Fl h
+.Op Fl u
+|
+.Fl r | Fl s | Fl k
+.Oc
+.Oo
+.Fl o
+.Op Fl n
+.Oc
+.Ar time
+.Op Ar warning-message ...
+.Sh DESCRIPTION
+The
+.Nm shutdown
+utility provides an automated shutdown procedure for super-users
+to nicely notify users when the system is shutting down,
+saving them from system administrators, hackers, and gurus, who
+would otherwise not bother with such niceties.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl h
+The system is halted at the specified
+.Ar time .
+.It Fl k
+Kick everybody off.
+The
+.Fl k
+option
+does not actually halt the system, but leaves the
+system multi-user with logins disabled (for all but super-user).
+.It Fl n
+If the
+.Fl o
+is specified, prevent the file system cache from being flushed by passing
+.Fl n
+option to
+.Xr halt 8
+or
+.Xr reboot 8 .
+This option should probably not be used.
+.It Fl o
+If
+.Fl h
+or
+.Fl r
+is specified,
+.Nm shutdown
+will execute
+.Xr halt 8
+or
+.Xr reboot 8
+instead of sending a signal to
+.Xr launchd 8 .
+.It Fl r
+The system is rebooted at the specified
+.Ar time .
+.It Fl s
+The system is put to sleep at the specified
+.Ar time .
+.It Fl u
+The system is halted up until the point of removing system power, but waits
+before removing power for 5 minutes so that an external UPS
+(uninterruptible power supply) can forcibly remove power.
+This simulates a dirty shutdown to permit a later automatic power on. OS X uses
+this mode automatically with supported UPSs in emergency shutdowns.
+.It Ar time
+.Ar Time
+is the time at which
+.Nm shutdown
+will bring the system down and
+may be the word
+.Ar now
+(indicating an immediate shutdown) or
+specify a future time in one of two formats:
+.Ar +number ,
+or
+.Ar yymmddhhmm ,
+where the year, month, and day may be defaulted
+to the current system values. The first form brings the system down in
+.Ar number
+minutes and the second at the absolute time specified.
+.It Ar warning-message
+Any other arguments comprise the warning message that is broadcast
+to users currently logged into the system.
+.It Fl
+If
+.Sq Fl
+is supplied as an option, the warning message is read from the standard
+input.
+.El
+.Pp
+At intervals, becoming more frequent as apocalypse approaches
+and starting at ten hours before shutdown, warning messages are displayed
+on the terminals of all users logged in.
+.Pp
+At shutdown time a message is written to the system log, containing the
+time of shutdown, the person who initiated the shutdown and the reason.
+Corresponding signal is then sent to
+.Xr launchd 8
+to respectively halt, reboot or bring the system down to single-user state
+(depending on the above options).
+.Pp
+A scheduled shutdown can be canceled by killing the
+.Nm shutdown
+process (a
+.Dv SIGTERM
+should suffice).
+.Sh SIGTERM TO SIGKILL INTERVAL
+Upon shutdown, all running processes are sent a SIGTERM followed by a SIGKILL.
+The
+.Dv SIGKILL
+will follow the
+.Dv SIGTERM
+by an intentionally indeterminate period of time.
+Programs are expected to take only enough time to flush all dirty data and exit.
+Developers are encouraged to file a bug with the OS vendor, should they encounter an issue with this functionality.
+.Sh SEE ALSO
+.Xr kill 1 ,
+.Xr login 1 ,
+.Xr wall 1 ,
+.Xr halt 8 ,
+.Xr launchd 8 ,
+.Xr reboot 8
+.Sh BACKWARD COMPATIBILITY
+The hours and minutes in the second time format may be separated by
+a colon (``:'') for backward compatibility.
+.Sh HISTORY
+The
+.Nm shutdown
+utility appeared in
+.Bx 4.0 .
diff --git a/system_cmds/shutdown.tproj/shutdown.c b/system_cmds/shutdown.tproj/shutdown.c
new file mode 100644
index 0000000..597f9f2
--- /dev/null
+++ b/system_cmds/shutdown.tproj/shutdown.c
@@ -0,0 +1,796 @@
+/*
+ * Copyright (c) 1988, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Portions copyright (c) 2007 Apple 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+#ifndef __APPLE__
+__FBSDID("$FreeBSD: src/sbin/shutdown/shutdown.c,v 1.28 2005/01/25 08:40:51 delphij Exp $");
+#endif
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/syslog.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __APPLE__
+#include <errno.h>
+#include <util.h>
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <vproc.h>
+#include <vproc_priv.h>
+
+#include "kextmanager.h"
+#include <IOKit/kext/kextmanager_types.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
+#include <mach/mach_port.h> // allocate
+#include <mach/mach.h> // task_self, etc
+#include <servers/bootstrap.h> // bootstrap
+#include <bootstrap_priv.h>
+#include <reboot2.h>
+#include <utmpx.h>
+
+#include "pathnames.h"
+#endif /* __APPLE__ */
+
+#ifdef DEBUG
+#undef _PATH_NOLOGIN
+#define _PATH_NOLOGIN "./nologin"
+#endif
+
+#define H *60*60
+#define M *60
+#define S *1
+#define NOLOG_TIME 5*60
+struct interval {
+ int timeleft, timetowait;
+} tlist[] = {
+ { 10 H, 5 H },
+ { 5 H, 3 H },
+ { 2 H, 1 H },
+ { 1 H, 30 M },
+ { 30 M, 10 M },
+ { 20 M, 10 M },
+ { 10 M, 5 M },
+ { 5 M, 3 M },
+ { 2 M, 1 M },
+ { 1 M, 30 S },
+ { 30 S, 30 S },
+ { 0 , 0 }
+};
+#undef H
+#undef M
+#undef S
+
+static time_t offset, shuttime;
+#ifdef __APPLE__
+static int dohalt, doreboot, doups, killflg, oflag;
+static size_t mbuflen;
+#else
+static int dohalt, dopower, doreboot, killflg, mbuflen, oflag;
+#endif
+static char mbuf[BUFSIZ];
+static const char *nosync, *whom;
+#ifdef __APPLE__
+static int dosleep;
+#endif
+
+void badtime(void);
+#ifdef __APPLE__
+void log_and_exec_reboot_or_halt(void);
+#else
+void die_you_gravy_sucking_pig_dog(void);
+#endif
+void finish(int);
+void getoffset(char *);
+void loop(void);
+void nolog(void);
+void timeout(int);
+void timewarn(time_t);
+void usage(const char *);
+#ifdef __APPLE__
+int audit_shutdown(int);
+int reserve_reboot(void);
+#endif
+
+extern const char **environ;
+
+int
+main(int argc, char **argv)
+{
+ char *p, *endp;
+ struct passwd *pw;
+ size_t arglen;
+ int ch, len, readstdin;
+
+#ifndef DEBUG
+ if (geteuid())
+ errx(1, "NOT super-user");
+#endif
+ nosync = NULL;
+ readstdin = 0;
+#ifndef __APPLE__
+ while ((ch = getopt(argc, argv, "-hknopr")) != -1)
+#else
+ while ((ch = getopt(argc, argv, "-hknorsu")) != -1)
+#endif
+ switch (ch) {
+ case '-':
+ readstdin = 1;
+ break;
+ case 'h':
+ dohalt = 1;
+ break;
+ case 'k':
+ killflg = 1;
+ break;
+ case 'n':
+ nosync = "-n";
+ break;
+ case 'o':
+ oflag = 1;
+ break;
+#ifndef __APPLE__
+ case 'p':
+ dopower = 1;
+ break;
+#endif
+ case 'u':
+ doups = 1;
+ break;
+ case 'r':
+ doreboot = 1;
+ break;
+#ifdef __APPLE__
+ case 's':
+ dosleep = 1;
+ break;
+#endif
+ case '?':
+ default:
+ usage((char *)NULL);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage((char *)NULL);
+
+#ifndef __APPLE__
+ if (killflg + doreboot + dohalt + dopower > 1)
+ usage("incompatible switches -h, -k, -p and -r");
+
+ if (oflag && !(dohalt || dopower || doreboot))
+ usage("-o requires -h, -p or -r");
+
+ if (nosync != NULL && !oflag)
+ usage("-n requires -o");
+#else /* !__APPLE__ */
+ if (killflg + doreboot + dohalt + dosleep > 1)
+ usage("incompatible switches -h, -k, -r, and -s");
+
+ if (!(dohalt || doreboot || dosleep || killflg))
+ usage("-h, -r, -s, or -k is required");
+
+ if (doups && !dohalt)
+ usage("-u requires -h");
+#endif /* !__APPLE__ */
+
+ getoffset(*argv++);
+
+ if (*argv) {
+ for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) {
+ arglen = strlen(*argv);
+ if ((len -= arglen) <= 2)
+ break;
+ if (p != mbuf)
+ *p++ = ' ';
+ memmove(p, *argv, arglen);
+ p += arglen;
+ }
+ *p = '\n';
+ *++p = '\0';
+ }
+
+ if (readstdin) {
+ p = mbuf;
+ endp = mbuf + sizeof(mbuf) - 2;
+ for (;;) {
+ if (!fgets(p, (int)(endp - p + 1), stdin))
+ break;
+ for (; *p && p < endp; ++p);
+ if (p == endp) {
+ *p = '\n';
+ *++p = '\0';
+ break;
+ }
+ }
+ }
+ mbuflen = strlen(mbuf);
+
+ if (offset)
+ (void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
+ else
+ (void)printf("Shutdown NOW!\n");
+
+ if (!(whom = getlogin()))
+ whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
+
+#ifdef DEBUG
+ audit_shutdown(0);
+ (void)putc('\n', stdout);
+#else
+ (void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
+#ifdef __APPLE__
+ if (offset) {
+#else
+ {
+#endif
+ int forkpid;
+
+ forkpid = fork();
+ if (forkpid == -1) {
+ audit_shutdown(1);
+ err(1, "fork");
+ }
+ if (forkpid)
+ errx(0, "[pid %d]", forkpid);
+#ifdef __APPLE__
+ /* 5863185: reboot2() needs to talk to launchd. */
+ if (_vprocmgr_detach_from_console(0) != NULL)
+ warnx("can't detach from console");
+#endif /* __APPLE__ */
+ }
+ audit_shutdown(0);
+ setsid();
+#endif
+ openlog("shutdown", LOG_CONS, LOG_AUTH);
+ loop();
+ return(0);
+}
+
+void
+loop(void)
+{
+ struct interval *tp;
+ u_int sltime;
+ int logged;
+
+ if (offset <= NOLOG_TIME) {
+ logged = 1;
+ nolog();
+ }
+ else
+ logged = 0;
+ tp = tlist;
+ if (tp->timeleft < offset)
+ (void)sleep((u_int)(offset - tp->timeleft));
+ else {
+ while (tp->timeleft && offset < tp->timeleft)
+ ++tp;
+ /*
+ * Warn now, if going to sleep more than a fifth of
+ * the next wait time.
+ */
+ if ((sltime = (u_int)(offset - tp->timeleft))) {
+ if (sltime > (tp->timetowait / 5))
+ timewarn(offset);
+ (void)sleep(sltime);
+ }
+ }
+ for (;; ++tp) {
+ timewarn(tp->timeleft);
+ if (!logged && tp->timeleft <= NOLOG_TIME) {
+ logged = 1;
+ nolog();
+ }
+ (void)sleep((u_int)tp->timetowait);
+ if (!tp->timeleft)
+ break;
+ }
+#ifdef __APPLE__
+ log_and_exec_reboot_or_halt();
+#else
+ die_you_gravy_sucking_pig_dog();
+#endif
+}
+
+static jmp_buf alarmbuf;
+
+static const char *restricted_environ[] = {
+ "PATH=" _PATH_STDPATH,
+ NULL
+};
+
+void
+timewarn(time_t timeleft)
+{
+ static int first;
+ static char hostname[MAXHOSTNAMELEN + 1];
+ FILE *pf;
+ char wcmd[MAXPATHLEN + 4];
+
+ /* wall is sometimes missing, e.g. on install media */
+ if (access(_PATH_WALL, X_OK) == -1) return;
+
+ if (!first++)
+ (void)gethostname(hostname, sizeof(hostname));
+
+ /* undoc -n option to wall suppresses normal wall banner */
+ (void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL);
+ environ = restricted_environ;
+ if (!(pf = popen(wcmd, "w"))) {
+ syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL);
+ return;
+ }
+
+ (void)fprintf(pf,
+ "\007*** %sSystem shutdown message from %s@%s ***\007\n",
+ timeleft ? "": "FINAL ", whom, hostname);
+
+ if (timeleft > 10*60)
+ (void)fprintf(pf, "System going down at %5.5s\n\n",
+ ctime(&shuttime) + 11);
+ else if (timeleft > 59)
+ (void)fprintf(pf, "System going down in %ld minute%s\n\n",
+ timeleft / 60, (timeleft > 60) ? "s" : "");
+ else if (timeleft)
+ (void)fprintf(pf, "System going down in 30 seconds\n\n");
+ else
+ (void)fprintf(pf, "System going down IMMEDIATELY\n\n");
+
+ if (mbuflen)
+ (void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
+
+ /*
+ * play some games, just in case wall doesn't come back
+ * probably unnecessary, given that wall is careful.
+ */
+ if (!setjmp(alarmbuf)) {
+ (void)signal(SIGALRM, timeout);
+ (void)alarm((u_int)30);
+ (void)pclose(pf);
+ (void)alarm((u_int)0);
+ (void)signal(SIGALRM, SIG_DFL);
+ }
+}
+
+void
+timeout(int signo __unused)
+{
+ longjmp(alarmbuf, 1);
+}
+
+void
+#ifdef __APPLE__
+log_and_exec_reboot_or_halt()
+#else
+die_you_gravy_sucking_pig_dog()
+#endif
+{
+#ifndef __APPLE__
+ char *empty_environ[] = { NULL };
+#else
+ if ((errno = reserve_reboot())) {
+ warn("couldn't lock for reboot");
+ finish(0);
+ }
+#endif
+
+ syslog(LOG_NOTICE, "%s%s by %s: %s",
+#ifndef __APPLE__
+ doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" :
+#else
+ doreboot ? "reboot" : dohalt ? "halt" : dosleep ? "sleep" :
+#endif
+ "shutdown", doups?" with UPS delay":"", whom, mbuf);
+#ifndef __APPLE__
+ (void)sleep(2);
+#endif
+
+ (void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
+ if (killflg) {
+ (void)printf("\rbut you'll have to do it yourself\r\n");
+ exit(0);
+ }
+#ifdef DEBUG
+ if (doreboot)
+ (void)printf("reboot");
+ else if (dohalt)
+ (void)printf("halt");
+#ifndef __APPLE__
+ else if (dopower)
+ (void)printf("power-down");
+ if (nosync != NULL)
+ (void)printf(" no sync");
+#else
+ else if (dosleep)
+ (void)printf("sleep");
+#endif
+ (void)printf("\nkill -HUP 1\n");
+#else
+#ifdef __APPLE__
+ if (dosleep) {
+ mach_port_t mp;
+ io_connect_t fb;
+ kern_return_t kr = IOMasterPort(bootstrap_port, &mp);
+ if (kr == kIOReturnSuccess) {
+ fb = IOPMFindPowerManagement(mp);
+ if (fb != IO_OBJECT_NULL) {
+ IOReturn err = IOPMSleepSystem(fb);
+ if (err != kIOReturnSuccess) {
+ fprintf(stderr, "shutdown: sleep failed (0x%08x)\n", err);
+ kr = -1;
+ }
+ }
+ }
+ } else {
+ int howto = 0;
+
+#if defined(__APPLE__)
+ {
+ struct utmpx utx;
+ bzero(&utx, sizeof(utx));
+ utx.ut_type = SHUTDOWN_TIME;
+ gettimeofday(&utx.ut_tv, NULL);
+ pututxline(&utx);
+ }
+#else
+ logwtmp("~", "shutdown", "");
+#endif
+
+ if (dohalt) howto |= RB_HALT;
+ if (doups) howto |= RB_UPSDELAY;
+ if (nosync) howto |= RB_NOSYNC;
+
+ // launchd(8) handles reboot. This call returns NULL on success.
+ if (reboot3(howto)) {
+ syslog(LOG_ERR, "shutdown: launchd reboot failed.");
+ }
+ }
+#else /* __APPLE__ */
+ if (!oflag) {
+ (void)kill(1, doreboot ? SIGINT : /* reboot */
+ dohalt ? SIGUSR1 : /* halt */
+ dopower ? SIGUSR2 : /* power-down */
+ SIGTERM); /* single-user */
+ } else {
+ if (doreboot) {
+ execle(_PATH_REBOOT, "reboot", "-l", nosync,
+ (char *)NULL, empty_environ);
+ syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+ _PATH_REBOOT);
+ warn(_PATH_REBOOT);
+ }
+ else if (dohalt) {
+ execle(_PATH_HALT, "halt", "-l", nosync,
+ (char *)NULL, empty_environ);
+ syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+ _PATH_HALT);
+ warn(_PATH_HALT);
+ }
+ else if (dopower) {
+ execle(_PATH_HALT, "halt", "-l", "-p", nosync,
+ (char *)NULL, empty_environ);
+ syslog(LOG_ERR, "shutdown: can't exec %s: %m.",
+ _PATH_HALT);
+ warn(_PATH_HALT);
+ }
+ (void)kill(1, SIGTERM); /* to single-user */
+ }
+#endif /* __APPLE__ */
+#endif
+ finish(0);
+}
+
+#define ATOI2(p) (p[0] - '0') * 10 + (p[1] - '0'); p += 2;
+
+void
+getoffset(char *timearg)
+{
+ struct tm *lt;
+ char *p;
+ time_t now;
+ int this_year;
+
+ (void)time(&now);
+
+ if (!strcasecmp(timearg, "now")) { /* now */
+ offset = 0;
+ shuttime = now;
+ return;
+ }
+
+ if (*timearg == '+') { /* +minutes */
+ if (!isdigit(*++timearg))
+ badtime();
+ if ((offset = atoi(timearg) * 60) < 0)
+ badtime();
+ shuttime = now + offset;
+ return;
+ }
+
+ /* handle hh:mm by getting rid of the colon */
+ for (p = timearg; *p; ++p)
+ if (!isascii(*p) || !isdigit(*p)) {
+ if (*p == ':' && strlen(p) == 3) {
+ p[0] = p[1];
+ p[1] = p[2];
+ p[2] = '\0';
+ }
+ else
+ badtime();
+ }
+
+ unsetenv("TZ"); /* OUR timezone */
+ lt = localtime(&now); /* current time val */
+
+ switch(strlen(timearg)) {
+ case 10:
+ this_year = lt->tm_year;
+ lt->tm_year = ATOI2(timearg);
+ /*
+ * check if the specified year is in the next century.
+ * allow for one year of user error as many people will
+ * enter n - 1 at the start of year n.
+ */
+ if (lt->tm_year < (this_year % 100) - 1)
+ lt->tm_year += 100;
+ /* adjust for the year 2000 and beyond */
+ lt->tm_year += (this_year - (this_year % 100));
+ /* FALLTHROUGH */
+ case 8:
+ lt->tm_mon = ATOI2(timearg);
+ if (--lt->tm_mon < 0 || lt->tm_mon > 11)
+ badtime();
+ /* FALLTHROUGH */
+ case 6:
+ lt->tm_mday = ATOI2(timearg);
+ if (lt->tm_mday < 1 || lt->tm_mday > 31)
+ badtime();
+ /* FALLTHROUGH */
+ case 4:
+ lt->tm_hour = ATOI2(timearg);
+ if (lt->tm_hour < 0 || lt->tm_hour > 23)
+ badtime();
+ lt->tm_min = ATOI2(timearg);
+ if (lt->tm_min < 0 || lt->tm_min > 59)
+ badtime();
+ lt->tm_sec = 0;
+ if ((shuttime = mktime(lt)) == -1)
+ badtime();
+ if ((offset = shuttime - now) < 0)
+ errx(1, "that time is already past.");
+ break;
+ default:
+ badtime();
+ }
+}
+
+#define NOMSG "\n\nNO LOGINS: System going down at "
+void
+nolog(void)
+{
+ int logfd;
+ char *ct;
+
+ (void)unlink(_PATH_NOLOGIN); /* in case linked to another file */
+ (void)signal(SIGINT, finish);
+ (void)signal(SIGHUP, finish);
+ (void)signal(SIGQUIT, finish);
+ (void)signal(SIGTERM, finish);
+ if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
+ 0664)) >= 0) {
+ (void)write(logfd, NOMSG, sizeof(NOMSG) - 1);
+ ct = ctime(&shuttime);
+ (void)write(logfd, ct + 11, 5);
+ (void)write(logfd, "\n\n", 2);
+ (void)write(logfd, mbuf, strlen(mbuf));
+ (void)close(logfd);
+ }
+}
+
+void
+finish(int signo __unused)
+{
+ if (!killflg)
+ (void)unlink(_PATH_NOLOGIN);
+ exit(0);
+}
+
+void
+badtime(void)
+{
+ errx(1, "bad time format");
+}
+
+void
+usage(const char *cp)
+{
+ if (cp != NULL)
+ warnx("%s", cp);
+ (void)fprintf(stderr,
+#ifdef __APPLE__
+ "usage: shutdown [-] [-h [-u] [-n] | -r [-n] | -s | -k]"
+#else
+ "usage: shutdown [-] [-h | -p | -r | -k] [-o [-n]]"
+#endif
+ " time [warning-message ...]\n");
+ exit(1);
+}
+
+#ifdef __APPLE__
+/*
+ * The following tokens are included in the audit record for shutdown
+ * header
+ * subject
+ * return
+ */
+int
+audit_shutdown(int exitstatus)
+{
+ int aufd;
+ token_t *tok;
+ long au_cond;
+
+ /* If we are not auditing, don't cut an audit record; just return */
+ if (auditon(A_GETCOND, &au_cond, sizeof(long)) < 0) {
+ fprintf(stderr, "shutdown: Could not determine audit condition\n");
+ return 0;
+ }
+ if (au_cond == AUC_NOAUDIT)
+ return 0;
+
+ if((aufd = au_open()) == -1) {
+ fprintf(stderr, "shutdown: Audit Error: au_open() failed\n");
+ exit(1);
+ }
+
+ /* The subject that performed the operation */
+ if((tok = au_to_me()) == NULL) {
+ fprintf(stderr, "shutdown: Audit Error: au_to_me() failed\n");
+ exit(1);
+ }
+ au_write(aufd, tok);
+
+ /* success and failure status */
+ if((tok = au_to_return32(exitstatus, errno)) == NULL) {
+ fprintf(stderr, "shutdown: Audit Error: au_to_return32() failed\n");
+ exit(1);
+ }
+ au_write(aufd, tok);
+
+ if(au_close(aufd, 1, AUE_shutdown) == -1) {
+ fprintf(stderr, "shutdown: Audit Error: au_close() failed\n");
+ exit(1);
+ }
+ return 1;
+}
+
+
+static bool
+kextdDisabled(void)
+{
+ uint32_t disabled = 0;
+ size_t sizeOfDisabled = sizeof(disabled);
+ if (sysctlbyname("hw.use_kernelmanagerd", &disabled, &sizeOfDisabled, NULL, 0) != 0) {
+ return false;
+ }
+ return (disabled != 0);
+}
+
+
+// XX copied from reboot.tproj/reboot.c; it would be nice to share the code
+
+#define WAITFORLOCK 1
+/*
+ * contact kextd to lock for reboot
+ */
+int
+reserve_reboot(void)
+{
+ int rval = ELAST + 1;
+ kern_return_t macherr = KERN_FAILURE;
+ mach_port_t kxport, tport = MACH_PORT_NULL, myport = MACH_PORT_NULL;
+ int busyStatus = ELAST + 1;
+ mountpoint_t busyVol;
+
+ if (kextdDisabled()) {
+ /* no need to talk with kextd if it's not running */
+ return 0;
+ }
+
+ macherr = bootstrap_look_up2(bootstrap_port, KEXTD_SERVER_NAME, &kxport, 0, BOOTSTRAP_PRIVILEGED_SERVER);
+ if (macherr) goto finish;
+
+ // allocate a port to pass to kextd (in case we die)
+ tport = mach_task_self();
+ if (tport == MACH_PORT_NULL) goto finish;
+ macherr = mach_port_allocate(tport, MACH_PORT_RIGHT_RECEIVE, &myport);
+ if (macherr) goto finish;
+
+ // try to lock for reboot
+ macherr = kextmanager_lock_reboot(kxport, myport, !WAITFORLOCK, busyVol,
+ &busyStatus);
+ if (macherr) goto finish;
+
+ if (busyStatus == EBUSY) {
+ warnx("%s is busy updating; waiting for lock", busyVol);
+ macherr = kextmanager_lock_reboot(kxport, myport, WAITFORLOCK,
+ busyVol, &busyStatus);
+ if (macherr) goto finish;
+ }
+
+ if (busyStatus == EALREADY) {
+ // reboot already in progress
+ rval = 0;
+ } else {
+ rval = busyStatus;
+ }
+
+finish:
+ // in general, we want to err on the side of allowing the reboot
+ if (macherr) {
+ if (macherr != BOOTSTRAP_UNKNOWN_SERVICE)
+ warnx("WARNING: couldn't lock kext manager for reboot: %s",
+ mach_error_string(macherr));
+ rval = 0;
+ }
+ // unless we got the lock, clean up our port
+ if (busyStatus != 0 && myport != MACH_PORT_NULL)
+ mach_port_mod_refs(tport, myport, MACH_PORT_RIGHT_RECEIVE, -1);
+
+ return rval;
+}
+#endif /* __APPLE__ */
diff --git a/system_cmds/stackshot.tproj/stackshot.c b/system_cmds/stackshot.tproj/stackshot.c
new file mode 100644
index 0000000..ecb3687
--- /dev/null
+++ b/system_cmds/stackshot.tproj/stackshot.c
@@ -0,0 +1,248 @@
+/* Copyright (c) 2017 Apple Inc. All rights reserved. */
+
+#include <stdio.h>
+#include <dispatch/dispatch.h>
+#include <sysexits.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <mach/mach_time.h>
+#include <sys/stackshot.h>
+#include <sys/types.h>
+#include <kern/debug.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include <kern/kcdata.h>
+
+static uint64_t
+stackshot_get_mach_absolute_time(void *buffer, uint32_t size)
+{
+ kcdata_iter_t iter = kcdata_iter_find_type(kcdata_iter(buffer, size), KCDATA_TYPE_MACH_ABSOLUTE_TIME);
+ if (!kcdata_iter_valid(iter) || kcdata_iter_size(iter) < sizeof(uint64_t)) {
+ fprintf(stderr, "bad kcdata\n");
+ exit(1);
+ }
+ return *(uint64_t *)kcdata_iter_payload(iter);
+}
+
+__dead2 static void usage(char **argv)
+{
+ fprintf (stderr, "usage: %s [options] [file]\n", argv[0]);
+ fprintf (stderr, " -d : take delta stackshot\n");
+ fprintf (stderr, " -b : get bootprofile\n");
+ fprintf (stderr, " -c : get coalition data\n");
+ fprintf (stderr, " -i : get instructions and cycles\n");
+ fprintf (stderr, " -g : get thread group data\n");
+ fprintf (stderr, " -s : fork a sleep process\n");
+ fprintf (stderr, " -L : disable loadinfo\n");
+ fprintf (stderr, " -k : active kernel threads only\n");
+ fprintf (stderr, " -I : disable io statistics\n");
+ fprintf (stderr, " -S : stress test: while(1) stackshot; \n");
+ fprintf (stderr, " -p PID : target a pid\n");
+ fprintf (stderr, " -E : grab existing kernel buffer\n");
+ fprintf (stderr, "If no file is provided and stdout is not a TTY, the stackshot will be written to stdout.\n");
+ exit(1);
+}
+
+static void forksleep() {
+ pid_t pid = fork();
+ if (pid < 0) {
+ perror("fork");
+ exit(1);
+ }
+
+ if (pid == 0) {
+ execlp("sleep", "sleep", "30", NULL);
+ perror("execlp");
+ exit(1);
+ }
+}
+
+
+int main(int argc, char **argv) {
+
+ uint32_t iostats = 0;
+ uint32_t active_kernel_threads_only = 0;
+ uint32_t bootprofile = 0;
+ uint32_t thread_group = 0;
+ uint32_t coalition = 0;
+ uint32_t instrs_cycles = 0;
+ uint32_t flags = 0;
+ uint32_t loadinfo = STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO;
+ boolean_t delta = FALSE;
+ boolean_t sleep = FALSE;
+ boolean_t stress = FALSE;
+ pid_t pid = -1;
+ int c;
+ FILE *file;
+ bool closefile;
+
+ while ((c = getopt(argc, argv, "SgIikbcLdtsp:E")) != -1) {
+ switch(c) {
+ case 'I':
+ iostats |= STACKSHOT_NO_IO_STATS;
+ break;
+ case 'k':
+ active_kernel_threads_only |= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY;
+ loadinfo &= ~STACKSHOT_SAVE_LOADINFO;
+ break;
+ case 'b':
+ bootprofile |= STACKSHOT_GET_BOOT_PROFILE;
+ break;
+ case 'c':
+ coalition |= STACKSHOT_SAVE_JETSAM_COALITIONS;
+ break;
+ case 'i':
+ instrs_cycles |= STACKSHOT_INSTRS_CYCLES;
+ break;
+ case 'L':
+ loadinfo = 0;
+ break;
+ case 'g':
+ thread_group |= STACKSHOT_THREAD_GROUP;
+ break;
+ case 'd':
+ delta = TRUE;
+ break;
+ case 's':
+ sleep = TRUE;
+ break;
+ case 'p':
+ pid = atoi(optarg);
+ break;
+ case 'S':
+ stress = TRUE;
+ break;
+ case 'E':
+ flags = flags | STACKSHOT_RETRIEVE_EXISTING_BUFFER;
+ break;
+ case '?':
+ case 'h':
+ default:
+ usage(argv);
+ break;
+ }
+ }
+
+ if (thread_group && delta) {
+ fprintf(stderr, "stackshot does not support delta snapshots with thread groups\n");
+ return 1;
+ }
+
+ if (optind == argc - 1) {
+ const char *const filename = argv[optind];
+ file = fopen(filename, "wx");
+ closefile = true;
+
+ if (file == NULL) {
+ perror("fopen");
+ return EX_CANTCREAT;
+ }
+ } else if (optind == argc && !isatty(STDOUT_FILENO)) {
+ file = stdout;
+ closefile = false;
+ } else {
+ usage(argv);
+ }
+
+top:
+ ;
+
+ void * config = stackshot_config_create();
+ if (!config) {
+ perror("stackshot_config_create");
+ return 1;
+ }
+ flags = flags | loadinfo | STACKSHOT_SAVE_IMP_DONATION_PIDS | STACKSHOT_GET_DQ | STACKSHOT_KCDATA_FORMAT | STACKSHOT_THREAD_WAITINFO |
+ bootprofile | active_kernel_threads_only | iostats | thread_group | coalition | instrs_cycles;
+
+ int err = stackshot_config_set_flags(config, flags);
+ if (err != 0) {
+ perror("stackshot_config_set_flags");
+ return 1;
+ }
+
+ if (pid != -1) {
+ int err = stackshot_config_set_pid(config, pid);
+ if (err != 0) {
+ perror("stackshot_config_set_flags");
+ return 1;
+ }
+ }
+
+ err = stackshot_capture_with_config(config);
+ if (err != 0) {
+ perror("stackshot_capture_with_config");
+ return 1;
+ }
+
+ void *buf = stackshot_config_get_stackshot_buffer(config);
+ if (!buf) {
+ perror("stackshot_config_get_stackshot_buffer");
+ return 1;
+ }
+
+ uint32_t size = stackshot_config_get_stackshot_size(config);
+
+ if (delta) {
+ // output the original somewhere?
+
+ uint64_t time = stackshot_get_mach_absolute_time(buf, size);
+
+ err = stackshot_config_dealloc_buffer(config);
+ assert(!err);
+
+ flags |= STACKSHOT_COLLECT_DELTA_SNAPSHOT;
+ int err = stackshot_config_set_flags(config, flags);
+ if (err != 0) {
+ perror("stackshot_config_set_flags");
+ return 1;
+ }
+
+ err = stackshot_config_set_delta_timestamp(config, time);
+ if (err != 0) {
+ perror("stackshot_config_delta_timestamp");
+ return 1;
+ }
+
+ if (sleep) {
+ forksleep();
+ }
+ usleep(10000);
+
+ err = stackshot_capture_with_config(config);
+ if (err != 0) {
+ perror("stackshot_capture_with_config");
+ return 1;
+ }
+
+ buf = stackshot_config_get_stackshot_buffer(config);
+ if (!buf) {
+ perror("stackshot_config_get_stackshot_buffer");
+ return 1;
+ }
+
+ size = stackshot_config_get_stackshot_size(config);
+
+
+ }
+
+ if (stress) {
+ if (config) {
+ stackshot_config_dealloc(config);
+ config = NULL;
+ }
+ goto top;
+ }
+
+ fwrite(buf, size, 1, file);
+
+ if (closefile) {
+ fclose(file);
+ }
+
+ return 0;
+}
diff --git a/system_cmds/sync.tproj/sync.8 b/system_cmds/sync.tproj/sync.8
new file mode 100644
index 0000000..fc733b8
--- /dev/null
+++ b/system_cmds/sync.tproj/sync.8
@@ -0,0 +1,68 @@
+.\"-
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sync.8 8.1 (Berkeley) 5/31/93
+.\" $FreeBSD: src/bin/sync/sync.8,v 1.16 2005/01/10 08:39:26 imp Exp $
+.\"
+.Dd May 31, 1993
+.Dt SYNC 8
+.Os
+.Sh NAME
+.Nm sync
+.Nd force completion of pending disk writes (flush cache)
+.Sh SYNOPSIS
+.Nm
+.Sh DESCRIPTION
+The
+.Nm
+utility
+can be called to ensure that all disk writes have been completed before the
+processor is halted in a way not suitably done by
+.Xr shutdown 8 .
+Generally, it is preferable to use
+.Xr shutdown 8
+to shut down the system,
+as they may perform additional actions
+such as resynchronizing the hardware clock
+and flushing internal caches before performing a final
+.Nm .
+.Pp
+The
+.Nm
+utility utilizes the
+.Xr sync 2
+function call.
+.Sh SEE ALSO
+.Xr fsync 2 ,
+.Xr sync 2 ,
+.Xr shutdown 8
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v4 .
diff --git a/system_cmds/sync.tproj/sync.c b/system_cmds/sync.tproj/sync.c
new file mode 100644
index 0000000..2d68997
--- /dev/null
+++ b/system_cmds/sync.tproj/sync.c
@@ -0,0 +1,52 @@
+/*-
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)sync.c 8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sync/sync.c,v 1.16 2005/01/10 08:39:26 imp Exp $");
+
+#include <stdlib.h>
+#include <unistd.h>
+
+int
+main(int argc __unused, char *argv[] __unused)
+{
+ sync();
+ exit(0);
+}
diff --git a/system_cmds/sysctl.tproj/sysctl.8 b/system_cmds/sysctl.tproj/sysctl.8
new file mode 100644
index 0000000..d421e7a
--- /dev/null
+++ b/system_cmds/sysctl.tproj/sysctl.8
@@ -0,0 +1,390 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)sysctl.8 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd January 17, 2011
+.Dt SYSCTL 8
+.Os
+.Sh NAME
+.Nm sysctl
+.Nd get or set kernel state
+.Sh SYNOPSIS
+.Nm
+.Op Fl bdehiNnoqx
+.Ar name Ns Op = Ns Ar value
+.Ar ...
+.Nm
+.Op Fl bdehNnoqx
+.Fl a
+.Sh DESCRIPTION
+The
+.Nm
+utility retrieves kernel state and allows processes with appropriate
+privilege to set kernel state.
+The state to be retrieved or set is described using a
+.Dq Management Information Base
+.Pq Dq MIB
+style name, described as a dotted set of
+components.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl A
+Equivalent to
+.Fl o a
+(for compatibility).
+.It Fl a
+List all the currently available non-opaque values.
+This option is ignored if one or more variable names are specified on
+the command line.
+.It Fl b
+Force the value of the variable(s) to be output in raw, binary format.
+No names are printed and no terminating newlines are output.
+This is mostly useful with a single variable.
+.It Fl d
+Print the description of the variable instead of its value.
+.It Fl e
+Separate the name and the value of the variable(s) with
+.Ql = .
+This is useful for producing output which can be fed back to the
+.Nm
+utility.
+This option is ignored if either
+.Fl N
+or
+.Fl n
+is specified, or a variable is being set.
+.It Fl h
+Format output for human, rather than machine, readability.
+.It Fl i
+Ignore unknown OIDs.
+The purpose is to make use of
+.Nm
+for collecting data from a variety of machines (not all of which
+are necessarily running exactly the same software) easier.
+.It Fl N
+Show only variable names, not their values.
+This is particularly useful with shells that offer programmable
+completion.
+To enable completion of variable names in
+.Xr zsh 1 Pq Pa ports/shells/zsh ,
+use the following code:
+.Bd -literal -offset indent
+listsysctls () { set -A reply $(sysctl -AN ${1%.*}) }
+compctl -K listsysctls sysctl
+.Ed
+.Pp
+To enable completion of variable names in
+.Xr tcsh 1 ,
+use:
+.Pp
+.Dl "complete sysctl 'n/*/`sysctl -Na`/'"
+.It Fl n
+Show only variable values, not their names.
+This option is useful for setting shell variables.
+For instance, to save the pagesize in variable
+.Va psize ,
+use:
+.Pp
+.Dl "set psize=`sysctl -n hw.pagesize`"
+.It Fl o
+Show opaque variables (which are normally suppressed).
+The format and length are printed, as well as a hex dump of the first
+sixteen bytes of the value.
+.It Fl q
+Suppress some warnings generated by
+.Nm
+to standard error.
+.It Fl X
+Equivalent to
+.Fl x a
+(for compatibility).
+.It Fl x
+As
+.Fl o ,
+but prints a hex dump of the entire value instead of just the first
+few bytes.
+.El
+.Pp
+The information available from
+.Nm
+consists of integers, strings, and opaque types.
+The
+.Nm
+utility
+only knows about a couple of opaque types, and will resort to hexdumps
+for the rest.
+The opaque information is much more useful if retrieved by special
+purpose programs such as
+.Xr ps 1 ,
+.Xr systat 1 ,
+and
+.Xr netstat 1 .
+.Pp
+.\" Some of the variables which cannot be modified during normal system
+.\" operation can be initialized via
+.\" .Xr loader 8
+.\" tunables.
+.\" This can for example be done by setting them in
+.\" .Xr loader.conf 5 .
+.\" Please refer to
+.\" .Xr loader.conf 5
+.\" for more information on which tunables are available and how to set them.
+.\" .Pp
+The string and integer information is summarized below.
+For a detailed description of these variable see
+.Xr sysctl 3 .
+.Pp
+The changeable column indicates whether a process with appropriate
+privilege can change the value.
+String and integer values can be set using
+.Nm .
+.Bl -column xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx integerxxx
+.It Sy "Name Type Changeable"
+.It "hw.activecpu integer no"
+.It "hw.busfrequency integer no"
+.It "hw.busfrequency_max integer no"
+.It "hw.busfrequency_min integer no"
+.It "hw.byteorder integer no"
+.It "hw.cacheconfig struct no"
+.It "hw.cachelinesize integer no"
+.It "hw.cachesize struct no"
+.It "hw.cpu64bit_capable integer no"
+.It "hw.cpufamily integer no"
+.It "hw.cpufrequency integer no"
+.It "hw.cpufrequency_max integer no"
+.It "hw.cpufrequency_min integer no"
+.It "hw.cpusubtype integer no"
+.It "hw.cputhreadtype integer no"
+.It "hw.cputype integer no"
+.It "hw.l1dcachesize integer no"
+.It "hw.l1icachesize integer no"
+.It "hw.l2cachesize integer no"
+.It "hw.l3cachesize integer no"
+.It "hw.logicalcpu integer no"
+.It "hw.logicalcpu_max integer no"
+.It "hw.memsize integer no"
+.It "hw.ncpu integer no"
+.It "hw.packages integer no"
+.It "hw.pagesize integer no"
+.It "hw.physicalcpu integer no"
+.It "hw.physicalcpu_max integer no"
+.It "hw.tbfrequency integer no"
+.It "kern.argmax integer no"
+.It "kern.bootargs string no"
+.It "kern.boottime struct no"
+.It "kern.clockrate struct no"
+.It "kern.coredump integer yes"
+.It "kern.corefile string yes"
+.It "kern.flush_cache_on_write integer yes"
+.It "kern.hostid integer yes"
+.It "kern.hostname string yes"
+.It "kern.job_control integer no"
+.It "kern.maxfiles integer yes"
+.It "kern.maxfilesperproc integer yes"
+.It "kern.maxnbuf integer yes"
+.It "kern.maxproc integer yes"
+.It "kern.maxprocperuid integer yes"
+.It "kern.maxvnodes integer yes"
+.It "kern.msgbuf integer yes"
+.It "kern.nbuf integer no"
+.It "kern.netboot integer no"
+.It "kern.ngroups integer no"
+.It "kern.nisdomainname string yes"
+.It "kern.num_files integer no"
+.It "kern.num_tasks integer no"
+.It "kern.num_taskthreads integer no"
+.It "kern.num_threads integer no"
+.It "kern.num_vnodes integer no"
+.It "kern.nx integer yes"
+.It "kern.osrelease string no"
+.It "kern.osrevision integer no"
+.It "kern.ostype string no"
+.It "kern.osversion string yes"
+.It "kern.posix1version integer no"
+.It "kern.procname string yes"
+.It "kern.safeboot integer no"
+.It "kern.saved_ids integer no"
+.It "kern.secure_kernel integer no"
+.It "kern.securelevel integer yes"
+.It "kern.singleuser integer no"
+.It "kern.sleeptime struct no"
+.It "kern.slide integer no"
+.It "kern.stack_depth_max integer no"
+.It "kern.stack_size integer no"
+.It "kern.sugid_coredump integer yes"
+.It "kern.sugid_scripts integer yes"
+.It "kern.symfile string no"
+.It "kern.usrstack integer no"
+.It "kern.usrstack64 integer no"
+.It "kern.uuid string no"
+.It "kern.version string no"
+.It "kern.waketime struct no"
+.It "machdep.cpu.address_bits.physical integer no"
+.It "machdep.cpu.address_bits.virtual integer no"
+.It "machdep.cpu.brand integer no"
+.It "machdep.cpu.brand_string string no"
+.It "machdep.cpu.cache.L2_associativity integer no"
+.It "machdep.cpu.cache.linesize integer no"
+.It "machdep.cpu.cache.size integer no"
+.It "machdep.cpu.core_count integer no"
+.It "machdep.cpu.cores_per_package integer no"
+.It "machdep.cpu.extfamily integer no"
+.It "machdep.cpu.extfeature_bits integer no"
+.It "machdep.cpu.extfeatures string no"
+.It "machdep.cpu.extmodel integer no"
+.It "machdep.cpu.family integer no"
+.It "machdep.cpu.feature_bits integer no"
+.It "machdep.cpu.features string no"
+.It "machdep.cpu.leaf7_feature_bits integer no"
+.It "machdep.cpu.leaf7_features string no"
+.It "machdep.cpu.logical_per_package integer no"
+.It "machdep.cpu.max_basic integer no"
+.It "machdep.cpu.max_ext integer no"
+.It "machdep.cpu.microcode_version integer no"
+.It "machdep.cpu.model integer no"
+.It "machdep.cpu.processor_flag integer no"
+.It "machdep.cpu.signature integer no"
+.It "machdep.cpu.stepping integer no"
+.It "machdep.cpu.thread_count integer no"
+.It "machdep.cpu.tlb.data.large integer no"
+.It "machdep.cpu.tlb.data.large_level1 integer no"
+.It "machdep.cpu.tlb.data.small integer no"
+.It "machdep.cpu.tlb.data.small_level1 integer no"
+.It "machdep.cpu.tlb.inst.large integer no"
+.It "machdep.cpu.tlb.inst.small integer no"
+.It "machdep.cpu.tlb.shared integer no"
+.It "machdep.cpu.ucupdate integer yes"
+.It "machdep.cpu.vendor string no"
+.It "machdep.cpu.xsave.extended_state integer no"
+.It "machdep.tsc.deep_idle_rebase integer yes"
+.It "machdep.tsc.frequency integer no"
+.It "machdep.tsc.nanotime.generation integer no"
+.It "machdep.tsc.nanotime.shift integer no"
+.It "net.inet.ip.forwarding integer yes"
+.It "net.inet.ip.portrange.first integer yes"
+.It "net.inet.ip.portrange.hifirst integer yes"
+.It "net.inet.ip.portrange.hilast integer yes"
+.It "net.inet.ip.portrange.last integer yes"
+.It "net.inet.ip.portrange.lowfirst integer yes"
+.It "net.inet.ip.portrange.lowlast integer yes"
+.It "net.inet.ip.redirect integer yes"
+.It "net.inet.ip.ttl integer yes"
+.It "net.inet.udp.checksum integer yes"
+.It "net.inet.udp.maxdgram integer yes"
+.It "vm.loadavg struct no"
+.It "vm.swapusage struct no"
+.It "user.bc_base_max integer no"
+.It "user.bc_dim_max integer no"
+.It "user.bc_scale_max integer no"
+.It "user.bc_string_max integer no"
+.It "user.coll_weights_max integer no"
+.It "user.cs_path string no"
+.It "user.expr_nest_max integer no"
+.It "user.line_max integer no"
+.It "user.posix2_c_bind integer no"
+.It "user.posix2_c_dev integer no"
+.It "user.posix2_char_term integer no"
+.It "user.posix2_fort_dev integer no"
+.It "user.posix2_fort_run integer no"
+.It "user.posix2_localedef integer no"
+.It "user.posix2_sw_dev integer no"
+.It "user.posix2_upe integer no"
+.It "user.posix2_version integer no"
+.It "user.re_dup_max integer no"
+.It "user.stream_max integer no"
+.It "user.tzname_max integer no"
+.El
+.Sh FILES
+.Bl -tag -width ".In netinet/icmp_var.h" -compact
+.It In sys/sysctl.h
+definitions for top level identifiers, second level kernel and hardware
+identifiers, and user level identifiers
+.It In sys/socket.h
+definitions for second level network identifiers
+.It In sys/gmon.h
+definitions for third level profiling identifiers
+.It In vm/vm_param.h
+definitions for second level virtual memory identifiers
+.It In netinet/in.h
+definitions for third level Internet identifiers and
+fourth level IP identifiers
+.It In netinet/icmp_var.h
+definitions for fourth level ICMP identifiers
+.It In netinet/udp_var.h
+definitions for fourth level UDP identifiers
+.El
+.Sh EXAMPLES
+For example, to retrieve the maximum number of processes allowed
+in the system, one would use the following request:
+.Pp
+.Dl "sysctl kern.maxproc"
+.Pp
+To set the maximum number of processes allowed
+per uid to 1000, one would use the following request:
+.Pp
+.Dl "sysctl kern.maxprocperuid=1000"
+.Pp
+Information about the system clock rate may be obtained with:
+.Pp
+.Dl "sysctl kern.clockrate"
+.Pp
+Information about the load average history may be obtained with:
+.Pp
+.Dl "sysctl vm.loadavg"
+.Pp
+More variables than these exist, and the best and likely only place
+to search for their deeper meaning is undoubtedly the source where
+they are defined.
+.Sh COMPATIBILITY
+The
+.Fl w
+option has been deprecated and is silently ignored.
+.Sh SEE ALSO
+.Xr sysctl 3 ,
+.\" .Xr loader.conf 5 ,
+.Xr sysctl.conf 5
+.\" .Xr loader 8
+.Sh HISTORY
+A
+.Nm
+utility first appeared in
+.Bx 4.4 .
+.Pp
+In
+.Fx 2.2 ,
+.Nm
+was significantly remodeled.
+.\" .Sh BUGS
+.\" The
+.\" .Nm
+.\" utility presently exploits an undocumented interface to the kernel
+.\" sysctl facility to traverse the sysctl tree and to retrieve format
+.\" and name information.
+.\" This correct interface is being thought about for the time being.
diff --git a/system_cmds/sysctl.tproj/sysctl.c b/system_cmds/sysctl.tproj/sysctl.c
new file mode 100644
index 0000000..ca86999
--- /dev/null
+++ b/system_cmds/sysctl.tproj/sysctl.c
@@ -0,0 +1,1009 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#ifdef __APPLE__
+#include <mach/machine/vm_param.h>
+#include <mach/machine/vm_types.h>
+#include <mach/mach_types.h>
+#else // !__APPLE__
+#include <sys/vmmeter.h>
+#endif // !__APPLE__
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <locale.h>
+#ifdef __APPLE__
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int aflag, bflag, dflag, eflag, hflag, iflag;
+static int Nflag, nflag, oflag, qflag, xflag, warncount;
+
+static int oidfmt(int *, int, char *, u_int *);
+static void parse(const char *);
+#ifdef __APPLE__
+static int show_var(int *, int, int);
+#else
+static int show_var(int *, int);
+#endif
+static int sysctl_all(int *oid, int len);
+static int name2oid(char *, int *);
+
+#ifndef __APPLE__
+static int set_IK(const char *, int *);
+#endif
+
+#ifdef __APPLE__
+// Shims for FreeBSD source compatibility.
+#define CTLTYPE_UINT 0xa
+#define CTLTYPE_LONG 0xb
+#define CTLTYPE_ULONG 0xc
+#define CTLTYPE_S64 0xd
+#define CTLTYPE_U64 0xe
+
+#define CTLFLAG_TUN 0
+
+// Support for CTL_USER
+const struct ctlname names[] = CTL_NAMES;
+const struct ctlname user_names[] = CTL_USER_NAMES;
+const int user_names_count = sizeof(user_names) / sizeof(*user_names);
+#endif
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "%s\n%s\n",
+ "usage: sysctl [-bdehiNnoqx] name[=value] ...",
+ " sysctl [-bdehNnoqx] -a");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+
+ setlocale(LC_NUMERIC, "");
+ setbuf(stdout,0);
+ setbuf(stderr,0);
+
+ while ((ch = getopt(argc, argv, "AabdehiNnoqwxX")) != -1) {
+ switch (ch) {
+ case 'A':
+ /* compatibility */
+ aflag = oflag = 1;
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'b':
+ bflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ break;
+ case 'h':
+ hflag = 1;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'N':
+ Nflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'o':
+ oflag = 1;
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'w':
+ /* compatibility */
+ /* ignored */
+ break;
+ case 'X':
+ /* compatibility */
+ aflag = xflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (Nflag && nflag)
+ usage();
+ if (aflag && argc == 0)
+ exit(sysctl_all(0, 0));
+ if (argc == 0)
+ usage();
+
+ warncount = 0;
+ while (argc-- > 0)
+ parse(*argv++);
+ exit(warncount);
+}
+
+/*
+ * Parse a name into a MIB entry.
+ * Lookup and print out the MIB entry if it exists.
+ * Set a new value if requested.
+ */
+static void
+parse(const char *string)
+{
+ int len, i, j;
+ void *newval = 0;
+ int intval;
+ unsigned int uintval;
+ long longval;
+ unsigned long ulongval;
+ size_t newsize = 0;
+ int64_t i64val;
+ uint64_t u64val;
+ int mib[CTL_MAXNAME];
+ char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ];
+ u_int kind;
+
+ cp = buf;
+ if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ)
+ errx(1, "oid too long: '%s'", string);
+ bufp = strsep(&cp, "=");
+ if (cp != NULL) {
+ while (isspace(*cp))
+ cp++;
+ newval = cp;
+ newsize = strlen(cp);
+ }
+ len = name2oid(bufp, mib);
+
+ if (len < 0) {
+ if (iflag)
+ return;
+ if (qflag)
+ exit(1);
+ else
+ errx(1, "unknown oid '%s'", bufp);
+ }
+
+ if (oidfmt(mib, len, fmt, &kind))
+ err(1, "couldn't find format of oid '%s'", bufp);
+
+ if (newval == NULL || dflag) {
+ if ((kind & CTLTYPE) == CTLTYPE_NODE) {
+ if (dflag) {
+#ifdef __APPLE__
+ i = show_var(mib, len, 1);
+#else
+ i = show_var(mib, len);
+#endif
+ if (!i && !bflag)
+ putchar('\n');
+ }
+ sysctl_all(mib, len);
+ } else {
+#ifdef __APPLE__
+ i = show_var(mib, len, 1);
+#else
+ i = show_var(mib, len);
+#endif
+ if (!i && !bflag)
+ putchar('\n');
+ }
+ } else {
+ if ((kind & CTLTYPE) == CTLTYPE_NODE)
+ errx(1, "oid '%s' isn't a leaf node", bufp);
+
+ if (!(kind & CTLFLAG_WR)) {
+ if (kind & CTLFLAG_TUN) {
+ warnx("oid '%s' is a read only tunable", bufp);
+ errx(1, "Tunable values are set in /boot/loader.conf");
+ } else {
+ errx(1, "oid '%s' is read only", bufp);
+ }
+ }
+
+ if ((kind & CTLTYPE) == CTLTYPE_INT ||
+ (kind & CTLTYPE) == CTLTYPE_UINT ||
+ (kind & CTLTYPE) == CTLTYPE_LONG ||
+ (kind & CTLTYPE) == CTLTYPE_ULONG ||
+ (kind & CTLTYPE) == CTLTYPE_S64 ||
+ (kind & CTLTYPE) == CTLTYPE_U64) {
+ if (strlen(newval) == 0)
+ errx(1, "empty numeric value");
+ }
+
+ switch (kind & CTLTYPE) {
+ case CTLTYPE_INT:
+ if (strcmp(fmt, "IK") == 0) {
+#ifndef __APPLE__
+ if (!set_IK(newval, &intval))
+#endif
+ errx(1, "invalid value '%s'",
+ (char *)newval);
+ } else {
+ intval = (int)strtol(newval, &endptr,
+ 0);
+ if (endptr == newval || *endptr != '\0')
+ errx(1, "invalid integer '%s'",
+ (char *)newval);
+ }
+ newval = &intval;
+ newsize = sizeof(intval);
+ break;
+ case CTLTYPE_UINT:
+ uintval = (int) strtoul(newval, &endptr, 0);
+ if (endptr == newval || *endptr != '\0')
+ errx(1, "invalid unsigned integer '%s'",
+ (char *)newval);
+ newval = &uintval;
+ newsize = sizeof(uintval);
+ break;
+ case CTLTYPE_LONG:
+ longval = strtol(newval, &endptr, 0);
+ if (endptr == newval || *endptr != '\0')
+ errx(1, "invalid long integer '%s'",
+ (char *)newval);
+ newval = &longval;
+ newsize = sizeof(longval);
+ break;
+ case CTLTYPE_ULONG:
+ ulongval = strtoul(newval, &endptr, 0);
+ if (endptr == newval || *endptr != '\0')
+ errx(1, "invalid unsigned long integer"
+ " '%s'", (char *)newval);
+ newval = &ulongval;
+ newsize = sizeof(ulongval);
+ break;
+ case CTLTYPE_STRING:
+ break;
+ case CTLTYPE_S64:
+ i64val = strtoimax(newval, &endptr, 0);
+ if (endptr == newval || *endptr != '\0')
+ errx(1, "invalid int64_t '%s'",
+ (char *)newval);
+ newval = &i64val;
+ newsize = sizeof(i64val);
+ break;
+ case CTLTYPE_U64:
+ u64val = strtoumax(newval, &endptr, 0);
+ if (endptr == newval || *endptr != '\0')
+ errx(1, "invalid uint64_t '%s'",
+ (char *)newval);
+ newval = &u64val;
+ newsize = sizeof(u64val);
+ break;
+ case CTLTYPE_OPAQUE:
+ /* FALLTHROUGH */
+ default:
+ errx(1, "oid '%s' is type %d,"
+ " cannot set that", bufp,
+ kind & CTLTYPE);
+ }
+
+#ifdef __APPLE__
+ i = show_var(mib, len, 1);
+#else
+ i = show_var(mib, len);
+#endif
+ if (sysctl(mib, len, 0, 0, newval, newsize) == -1) {
+ if (!i && !bflag)
+ putchar('\n');
+ switch (errno) {
+#ifdef __APPLE__
+ case ENOTSUP:
+#endif // __APPLE__
+ case EOPNOTSUPP:
+ errx(1, "%s: value is not available",
+ string);
+ case ENOTDIR:
+ errx(1, "%s: specification is incomplete",
+ string);
+ case ENOMEM:
+ errx(1, "%s: type is unknown to this program",
+ string);
+ default:
+ warn("%s", string);
+ warncount++;
+ return;
+ }
+ }
+ if (!bflag)
+ printf(" -> ");
+ i = nflag;
+ nflag = 1;
+#ifdef __APPLE__
+ j = show_var(mib, len, 1);
+#else
+ j = show_var(mib, len);
+#endif
+ if (!j && !bflag)
+ putchar('\n');
+ nflag = i;
+ }
+}
+
+/* These functions will dump out various interesting structures. */
+
+static int
+S_clockinfo(int l2, void *p)
+{
+ struct clockinfo *ci = (struct clockinfo*)p;
+
+ if (l2 != sizeof(*ci)) {
+ warnx("S_clockinfo %d != %zu", l2, sizeof(*ci));
+ return (1);
+ }
+#ifdef __APPLE__
+ printf(hflag ? "{ hz = %'d, tick = %'d, tickadj = %'d, profhz = %'d, stathz = %'d }" :
+ "{ hz = %d, tick = %d, tickadj = %d, profhz = %d, stathz = %d }",
+ ci->hz, ci->tick, ci->tickadj, ci->profhz, ci->stathz);
+#else
+ printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" :
+ "{ hz = %d, tick = %d, profhz = %d, stathz = %d }",
+ ci->hz, ci->tick, ci->profhz, ci->stathz);
+#endif
+ return (0);
+}
+
+static int
+S_loadavg(int l2, void *p)
+{
+ struct loadavg *tv = (struct loadavg*)p;
+
+ if (l2 != sizeof(*tv)) {
+ warnx("S_loadavg %d != %zu", l2, sizeof(*tv));
+ return (1);
+ }
+ printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }",
+ (double)tv->ldavg[0]/(double)tv->fscale,
+ (double)tv->ldavg[1]/(double)tv->fscale,
+ (double)tv->ldavg[2]/(double)tv->fscale);
+ return (0);
+}
+
+static int
+S_timeval(int l2, void *p)
+{
+ struct timeval *tv = (struct timeval*)p;
+ time_t tv_sec;
+ char *p1, *p2;
+
+ if (l2 != sizeof(*tv)) {
+ warnx("S_timeval %d != %zu", l2, sizeof(*tv));
+ return (1);
+ }
+ printf(hflag ? "{ sec = %'jd, usec = %'ld } " :
+ "{ sec = %jd, usec = %ld } ",
+ (intmax_t)tv->tv_sec, (long)tv->tv_usec);
+ tv_sec = tv->tv_sec;
+ p1 = strdup(ctime(&tv_sec));
+ for (p2=p1; *p2 ; p2++)
+ if (*p2 == '\n')
+ *p2 = '\0';
+ fputs(p1, stdout);
+ free(p1);
+ return (0);
+}
+
+#ifndef __APPLE__
+static int
+S_vmtotal(int l2, void *p)
+{
+ struct vmtotal *v = (struct vmtotal *)p;
+ int pageKilo = getpagesize() / 1024;
+
+ if (l2 != sizeof(*v)) {
+ warnx("S_vmtotal %d != %zu", l2, sizeof(*v));
+ return (1);
+ }
+
+ printf(
+ "\nSystem wide totals computed every five seconds:"
+ " (values in kilobytes)\n");
+ printf("===============================================\n");
+ printf(
+ "Processes:\t\t(RUNQ: %hd Disk Wait: %hd Page Wait: "
+ "%hd Sleep: %hd)\n",
+ v->t_rq, v->t_dw, v->t_pw, v->t_sl);
+ printf(
+ "Virtual Memory:\t\t(Total: %dK Active: %dK)\n",
+ v->t_vm * pageKilo, v->t_avm * pageKilo);
+ printf("Real Memory:\t\t(Total: %dK Active: %dK)\n",
+ v->t_rm * pageKilo, v->t_arm * pageKilo);
+ printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n",
+ v->t_vmshr * pageKilo, v->t_avmshr * pageKilo);
+ printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n",
+ v->t_rmshr * pageKilo, v->t_armshr * pageKilo);
+ printf("Free Memory:\t%dK\n", v->t_free * pageKilo);
+
+ return (0);
+}
+
+static int
+set_IK(const char *str, int *val)
+{
+ float temp;
+ int len, kelv;
+ const char *p;
+ char *endptr;
+
+ if ((len = strlen(str)) == 0)
+ return (0);
+ p = &str[len - 1];
+ if (*p == 'C' || *p == 'F') {
+ temp = strtof(str, &endptr);
+ if (endptr == str || endptr != p)
+ return (0);
+ if (*p == 'F')
+ temp = (temp - 32) * 5 / 9;
+ kelv = temp * 10 + 2732;
+ } else {
+ kelv = (int)strtol(str, &endptr, 10);
+ if (endptr == str || *endptr != '\0')
+ return (0);
+ }
+ *val = kelv;
+ return (1);
+}
+#endif // !__APPLE__
+
+#ifdef __APPLE__
+static int
+S_xswusage(int l2, void *p)
+{
+ struct xsw_usage *xsu = (struct xsw_usage *)p;
+
+ if (l2 != sizeof(*xsu)) {
+ warnx("S_xswusage %d != %ld", l2, sizeof(*xsu));
+ return (1);
+ }
+ fprintf(stdout,
+ "total = %.2fM used = %.2fM free = %.2fM %s",
+ ((double)xsu->xsu_total) / (1024.0 * 1024.0),
+ ((double)xsu->xsu_used) / (1024.0 * 1024.0),
+ ((double)xsu->xsu_avail) / (1024.0 * 1024.0),
+ xsu->xsu_encrypted ? "(encrypted)" : "");
+ return (0);
+}
+
+static int
+T_dev_t(int l2, void *p)
+{
+ dev_t *d = (dev_t *)p;
+
+ if (l2 != sizeof(*d)) {
+ warnx("T_dev_T %d != %ld", l2, sizeof(*d));
+ return (1);
+ }
+ if ((int)(*d) != -1) {
+ if (minor(*d) > 255 || minor(*d) < 0)
+ printf("{ major = %d, minor = 0x%x }",
+ major(*d), minor(*d));
+ else
+ printf("{ major = %d, minor = %d }",
+ major(*d), minor(*d));
+ }
+ return (0);
+}
+
+static int
+S_quads(int len, void *p)
+{
+ size_t size = sizeof(int64_t);
+ if (len & (size-1)) {
+ return 1;
+ }
+ while (len > 0) {
+ int64_t i = *(int64_t *)p;
+ printf("%llu", i);
+ if (len > size) {
+ len -= size;
+ p = (uintptr_t)p + size;
+ printf(" ");
+ } else {
+ break;
+ }
+ }
+ return 0;
+}
+#endif // __APPLE__
+
+/*
+ * These functions uses a presently undocumented interface to the kernel
+ * to walk the tree and get the type so it can print the value.
+ * This interface is under work and consideration, and should probably
+ * be killed with a big axe by the first person who can find the time.
+ * (be aware though, that the proper interface isn't as obvious as it
+ * may seem, there are various conflicting requirements.
+ */
+
+static int
+name2oid(char *name, int *oidp)
+{
+ int oid[2];
+ int i;
+ size_t j;
+
+#ifdef __APPLE__
+ // Support for CTL_USER
+ const char *user = names[CTL_USER].ctl_name;
+ j = strlen(user);
+ if (!strncmp(name, user, j)) {
+ oidp[0] = CTL_USER;
+ if (name[j] == '.') {
+ for (i = 1; i < user_names_count; ++i) {
+ if (!strcmp(&name[j+1], user_names[i].ctl_name)) {
+ oidp[1] = i;
+ return 2;
+ }
+ }
+ return -1;
+ } else if (name[j] == 0) {
+ return 1;
+ }
+ return -1;
+ }
+#endif
+
+ oid[0] = 0;
+ oid[1] = 3;
+
+ j = CTL_MAXNAME * sizeof(int);
+ i = sysctl(oid, 2, oidp, &j, name, strlen(name));
+ if (i < 0)
+ return (i);
+ j /= sizeof(int);
+ return (int)j;
+}
+
+static int
+oidfmt(int *oid, int len, char *fmt, u_int *kind)
+{
+ int qoid[CTL_MAXNAME+2];
+ u_char buf[BUFSIZ];
+ int i;
+ size_t j;
+
+ qoid[0] = 0;
+ qoid[1] = 4;
+ memcpy(qoid + 2, oid, len * sizeof(int));
+
+ j = sizeof(buf);
+ i = sysctl(qoid, len + 2, buf, &j, 0, 0);
+#ifdef __APPLE__
+ if (i && errno == ENOENT) {
+ // Support for CTL_USER
+ if (oid[0] == CTL_USER) {
+ if (len == 1) {
+ *kind = CTLTYPE_NODE;
+ return 0;
+ } else if (len == 2 && oid[1] < user_names_count) {
+ *kind = user_names[oid[1]].ctl_type;
+ return 0;
+ }
+ }
+ return 1;
+ }
+#endif
+ if (i)
+ err(1, "sysctl fmt %d %zu %d", i, j, errno);
+
+ if (kind)
+#ifdef __APPLE__
+ memcpy(kind, buf, sizeof(*kind));
+#else
+ *kind = *(u_int *)buf;
+#endif
+
+ if (fmt)
+ strcpy(fmt, (char *)(buf + sizeof(u_int)));
+
+#ifdef __APPLE__
+ // Map Darwin sysctl types to FreeBSD types.
+ // - 0 with "I" -> CTLTYPE_INT
+ // - 0 with "S," -> CTLTYPE_STRUCT
+ // - CTLTYPE_INT with "IU" -> CTLTYPE_UINT
+ // - CTLTYPE_INT with "L" -> CTLTYPE_LONG
+ // - CTLTYPE_QUAD -> CTLTYPE_S64
+ // - CTLTYPE_QUAD with "*U" -> CTLTYPE_U64
+ if (kind) {
+ switch (*kind & CTLTYPE) {
+ case 0:
+ case CTLTYPE_INT:
+ if (buf[sizeof(u_int)] == 'S') {
+ *kind = (*kind & ~CTLTYPE) | CTLTYPE_STRUCT;
+ } else if (buf[sizeof(u_int)] == 'I') {
+ *kind = (*kind & ~CTLTYPE) | CTLTYPE_INT;
+ if (buf[sizeof(u_int)+1] == 'U') {
+ *kind = (*kind & ~CTLTYPE) | CTLTYPE_UINT;
+ }
+ } else if (buf[sizeof(u_int)] == 'L') {
+ *kind = (*kind & ~CTLTYPE) | CTLTYPE_LONG;
+ if (buf[sizeof(u_int)+1] == 'U') {
+ *kind = (*kind & ~CTLTYPE) | CTLTYPE_ULONG;
+ }
+ }
+ break;
+ case CTLTYPE_QUAD:
+ *kind = (*kind & ~CTLTYPE);
+ if (fmt && strchr(fmt, 'U')) {
+ *kind |= CTLTYPE_U64;
+ } else {
+ *kind |= CTLTYPE_S64;
+ }
+ break;
+ }
+ }
+#endif
+
+ return (0);
+}
+
+static int ctl_sign[CTLTYPE+1] = {
+ [CTLTYPE_INT] = 1,
+ [CTLTYPE_LONG] = 1,
+ [CTLTYPE_S64] = 1,
+};
+
+static int ctl_size[CTLTYPE+1] = {
+ [CTLTYPE_INT] = sizeof(int),
+ [CTLTYPE_UINT] = sizeof(u_int),
+ [CTLTYPE_LONG] = sizeof(long),
+ [CTLTYPE_ULONG] = sizeof(u_long),
+ [CTLTYPE_S64] = sizeof(int64_t),
+ [CTLTYPE_U64] = sizeof(int64_t),
+};
+
+/*
+ * This formats and outputs the value of one variable
+ *
+ * Returns zero if anything was actually output.
+ * Returns one if didn't know what to do with this.
+ * Return minus one if we had errors.
+ */
+static int
+#ifdef __APPLE__
+show_var(int *oid, int nlen, int show_masked)
+#else
+show_var(int *oid, int nlen)
+#endif
+{
+ u_char buf[BUFSIZ], *val, *oval, *p;
+ char name[BUFSIZ], *fmt;
+ const char *sep, *sep1;
+ int qoid[CTL_MAXNAME+2];
+ uintmax_t umv;
+ intmax_t mv;
+ int i, hexlen, sign, ctltype;
+ size_t intlen;
+ size_t j, len;
+ u_int kind;
+ int (*func)(int, void *);
+
+ /* Silence GCC. */
+ umv = mv = intlen = 0;
+
+ bzero(buf, BUFSIZ);
+ bzero(name, BUFSIZ);
+ qoid[0] = 0;
+ memcpy(qoid + 2, oid, nlen * sizeof(int));
+ fmt = (char *)buf;
+ oidfmt(oid, nlen, fmt, &kind);
+
+#ifdef __APPLE__
+ if (!show_masked && (kind & CTLFLAG_MASKED)) {
+ return (1);
+ }
+#endif
+
+#ifdef __APPLE__
+ // Support for CTL_USER
+ if (nlen >= 1 && oid[0] == CTL_USER) {
+ const char *user_name = "";
+ sep = "";
+ i = oid[1];
+ if (nlen == 2 && i > 0 && i < user_names_count) {
+ user_name = user_names[i].ctl_name;
+ sep = ".";
+ }
+ j = snprintf(name, sizeof(name), "%s%s%s",
+ names[CTL_USER].ctl_name, sep, user_name);
+ i = 0;
+ } else {
+#endif
+ qoid[1] = 1;
+ j = sizeof(name);
+ i = sysctl(qoid, nlen + 2, name, &j, 0, 0);
+ if (i || !j)
+ err(1, "sysctl name %d %zu %d", i, j, errno);
+#ifdef __APPLE__
+ }
+#endif
+
+ if (Nflag) {
+ printf("%s", name);
+ return (0);
+ }
+
+ if (eflag)
+ sep = "=";
+ else
+ sep = ": ";
+
+ if (dflag) { /* just print description */
+ qoid[1] = 5;
+ j = sizeof(buf);
+ i = sysctl(qoid, nlen + 2, buf, &j, 0, 0);
+ if (!nflag)
+ printf("%s%s", name, sep);
+ printf("%s", buf);
+ return (0);
+ }
+ /* find an estimate of how much we need for this var */
+ j = 0;
+ i = sysctl(oid, nlen, 0, &j, 0, 0);
+ j += j; /* we want to be sure :-) */
+
+ val = oval = malloc(j + 1);
+ if (val == NULL) {
+ warnx("malloc failed");
+ return (1);
+ }
+ len = j;
+ i = sysctl(oid, nlen, val, &len, 0, 0);
+ if (i || !len) {
+ free(oval);
+ return (1);
+ }
+
+ if (bflag) {
+ fwrite(val, 1, len, stdout);
+ free(oval);
+ return (0);
+ }
+ val[len] = '\0';
+ p = val;
+ ctltype = (kind & CTLTYPE);
+ sign = ctl_sign[ctltype];
+ intlen = ctl_size[ctltype];
+
+ switch (ctltype) {
+ case CTLTYPE_STRING:
+ if (!nflag)
+ printf("%s%s", name, sep);
+ printf("%.*s", (int)len, p);
+ free(oval);
+ return (0);
+
+ case CTLTYPE_INT:
+ case CTLTYPE_UINT:
+ case CTLTYPE_LONG:
+ case CTLTYPE_ULONG:
+ case CTLTYPE_S64:
+ case CTLTYPE_U64:
+ if (!nflag)
+ printf("%s%s", name, sep);
+ hexlen = (int)(2 + (intlen * CHAR_BIT + 3) / 4);
+ sep1 = "";
+ while (len >= intlen) {
+ switch (kind & CTLTYPE) {
+ case CTLTYPE_INT:
+ case CTLTYPE_UINT:
+ umv = *(u_int *)(void *)p;
+ mv = *(int *)(void *)p;
+ break;
+ case CTLTYPE_LONG:
+ case CTLTYPE_ULONG:
+ umv = *(u_long *)(void *)p;
+ mv = *(long *)(void *)p;
+ break;
+ case CTLTYPE_S64:
+ case CTLTYPE_U64:
+ umv = *(uint64_t *)(void *)p;
+ mv = *(int64_t *)(void *)p;
+ break;
+ }
+ fputs(sep1, stdout);
+ if (xflag)
+ printf("%#0*jx", hexlen, umv);
+ else if (!sign)
+ printf(hflag ? "%'ju" : "%ju", umv);
+ else if (fmt[1] == 'K') {
+ if (mv < 0)
+ printf("%jd", mv);
+ else
+ printf("%.1fC", (mv - 2732.0) / 10);
+ } else
+ printf(hflag ? "%'jd" : "%jd", mv);
+ sep1 = " ";
+ len -= intlen;
+ p += intlen;
+ }
+ free(oval);
+ return (0);
+
+ case CTLTYPE_OPAQUE:
+ i = 0;
+ if (strcmp(fmt, "S,clockinfo") == 0)
+ func = S_clockinfo;
+ else if (strcmp(fmt, "S,timeval") == 0)
+ func = S_timeval;
+ else if (strcmp(fmt, "S,loadavg") == 0)
+ func = S_loadavg;
+#ifdef __APPLE__
+ else if (!strcmp(fmt, "S,xsw_usage"))
+ func = S_xswusage;
+ else if (!strcmp(fmt, "T,dev_t"))
+ func = T_dev_t;
+ else if (!strcmp(fmt, "Q"))
+ func = S_quads;
+#else // !__APPLE__
+ else if (strcmp(fmt, "S,vmtotal") == 0)
+ func = S_vmtotal;
+#endif // !__APPLE__
+ else
+ func = NULL;
+ if (func) {
+ if (!nflag)
+ printf("%s%s", name, sep);
+ i = (*func)((int)len, p);
+ free(oval);
+ return (i);
+ }
+ /* FALLTHROUGH */
+ default:
+ if (!oflag && !xflag) {
+ free(oval);
+ return (1);
+ }
+ if (!nflag)
+ printf("%s%s", name, sep);
+ printf("Format:%s Length:%zu Dump:0x", fmt, len);
+ while (len-- && (xflag || p < val + 16))
+ printf("%02x", *p++);
+ if (!xflag && len > 16)
+ printf("...");
+ free(oval);
+ return (0);
+ }
+ free(oval);
+ return (1);
+}
+
+#ifdef __APPLE__
+// Support for CTL_USER
+static void
+sysctl_all_user(int *oid, int len)
+{
+ int i, j;
+ if (len > 1 || (len == 1 && oid[0] != CTL_USER)) {
+ return;
+ }
+ for (i = 0; i < user_names_count; ++i) {
+ int oid[2] = { CTL_USER, i };
+ j = show_var(oid, 2, 0);
+ if (!j && !bflag) {
+ putchar('\n');
+ }
+ }
+}
+#endif
+
+static int
+sysctl_all(int *oid, int len)
+{
+#ifdef __APPLE__
+#endif
+
+ int name1[22], name2[22];
+ int i, j;
+ size_t l1, l2;
+
+#ifdef __APPLE__
+ sysctl_all_user(oid, len);
+#endif
+
+ name1[0] = 0;
+ name1[1] = 2;
+ l1 = 2;
+ if (len) {
+ memcpy(name1+2, oid, len * sizeof(int));
+ l1 += len;
+ } else {
+ name1[2] = 1;
+ l1++;
+ }
+ for (;;) {
+ l2 = sizeof(name2);
+ j = sysctl(name1, (u_int)l1, name2, &l2, 0, 0);
+ if (j < 0) {
+ if (errno == ENOENT)
+ return (0);
+ else
+ err(1, "sysctl(getnext) %d %zu", j, l2);
+ }
+
+ l2 /= sizeof(int);
+
+ if (len < 0 || l2 < (unsigned int)len)
+ return (0);
+
+ for (i = 0; i < len; i++)
+ if (name2[i] != oid[i])
+ return (0);
+
+#ifdef __APPLE__
+ i = show_var(name2, (u_int)l2, 0);
+#else
+ i = show_var(name2, (u_int)l2);
+#endif
+ if (!i && !bflag)
+ putchar('\n');
+
+ memcpy(name1+2, name2, l2 * sizeof(int));
+ l1 = 2 + l2;
+ }
+}
diff --git a/system_cmds/sysctl.tproj/sysctl.conf.5 b/system_cmds/sysctl.tproj/sysctl.conf.5
new file mode 100644
index 0000000..709c601
--- /dev/null
+++ b/system_cmds/sysctl.tproj/sysctl.conf.5
@@ -0,0 +1,75 @@
+.\" Modified August 3, 2007
+.\" Portions Copyright (c) 2007 Apple Inc.
+.\" Copyright (c) 1999 Chris Costello <chris@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/share/man/man5/sysctl.conf.5,v 1.16 2004/07/03 18:29:23 ru Exp $
+.\"
+.Dd August 3, 2007
+.Dt SYSCTL.CONF 5
+.Os
+.Sh NAME
+.Nm sysctl.conf
+.Nd kernel state defaults
+.Sh DESCRIPTION
+The
+.Pa /etc/sysctl.conf
+file is read in when the system goes into multi-user mode to set default
+settings for the kernel.
+The
+.Pa /etc/sysctl.conf
+is in the format of the
+.Xr sysctl 8
+command, i.e.\&
+.Bd -literal -offset indent
+sysctl_mib=value
+.Ed
+.Pp
+Comments are denoted by a
+.Dq #
+at the beginning of a line.
+.Sh FILES
+.Bl -tag -width /etc/sysctl.conf -compact
+.It Pa /etc/sysctl.conf
+Initial settings for
+.Xr sysctl 8 .
+.El
+.Sh EXAMPLES
+To disable coredumps, you may use a configuration like:
+.Bd -literal -offset indent
+# Disable coredumps.
+kern.coredump=0
+.Ed
+.Sh SEE ALSO
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+file appeared in
+.Fx 4.0 .
+.Sh BUGS
+If loadable kernel modules are used to introduce additional kernel
+functionality and sysctls to manage that functionality,
+.Nm
+may be processed too early in the boot process to set those sysctls.
diff --git a/system_cmds/system_cmds.xcodeproj/project.pbxproj b/system_cmds/system_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..ba1a85a
--- /dev/null
+++ b/system_cmds/system_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,9146 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 1812F18C1C8F923900F3DC9E /* All_Bridge */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 1812F1EF1C8F923900F3DC9E /* Build configuration list for PBXAggregateTarget "All_Bridge" */;
+ buildPhases = (
+ 1812F1ED1C8F923900F3DC9E /* CopyFiles */,
+ );
+ dependencies = (
+ 358407D62245AD55006A0D8E /* PBXTargetDependency */,
+ 926913A61EC706130079D787 /* PBXTargetDependency */,
+ 1812F18D1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F18F1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1911C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1931C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1991C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F19B1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F19D1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F19F1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1A11C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1A31C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1A51C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1A71C8F923900F3DC9E /* PBXTargetDependency */,
+ F2291F681FFEBC4F00161936 /* PBXTargetDependency */,
+ 1812F1A91C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1AB1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1AD1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1AF1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1B11C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1B31C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1B51C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1B71C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1B91C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1BB1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1BD1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1BF1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1C11C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1C31C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1C51C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1C71C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1C91C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1CB1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1CD1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1CF1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1D11C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1D31C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1D51C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1D71C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1D91C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1DB1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1DD1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1DF1C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1E11C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1E31C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1E51C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1E71C8F923900F3DC9E /* PBXTargetDependency */,
+ 1812F1EB1C8F923900F3DC9E /* PBXTargetDependency */,
+ );
+ name = All_Bridge;
+ productName = All_iOS;
+ };
+ BA4FD2FE1372FE4E0025925C /* All_MacOSX */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA4FD2FF1372FE4E0025925C /* Build configuration list for PBXAggregateTarget "All_MacOSX" */;
+ buildPhases = (
+ C9D64CD21B91066B00CFA43B /* CopyFiles */,
+ 587B8CAD2489CB170001CD8D /* Copy internal getty */,
+ 587B8CAE2489CB9C0001CD8D /* Copy Files */,
+ );
+ dependencies = (
+ 358407D22245AD40006A0D8E /* PBXTargetDependency */,
+ 926913A21EC706010079D787 /* PBXTargetDependency */,
+ 08CE3D361E6E24CC00DF1B78 /* PBXTargetDependency */,
+ C21481471C1A1447003BCA63 /* PBXTargetDependency */,
+ 78DE9DED1B5048D400FE6DF5 /* PBXTargetDependency */,
+ 97999D351AE84D3A00E8B10F /* PBXTargetDependency */,
+ 08DC48921A12C6FA008AAF38 /* PBXTargetDependency */,
+ 550C19F11804D2B7001DA380 /* PBXTargetDependency */,
+ ADA9007E1767A31300161ADF /* PBXTargetDependency */,
+ C625B29116D6F38700168EF7 /* PBXTargetDependency */,
+ B3F0E6DF16E97142008FAD09 /* PBXTargetDependency */,
+ 55CCB17816B851E900B56979 /* PBXTargetDependency */,
+ C96F50BA15BDFDA7008682F7 /* PBXTargetDependency */,
+ 1523FE6F1595069900661E82 /* PBXTargetDependency */,
+ BA0A861A1396B41F00D2272C /* PBXTargetDependency */,
+ BA0A861613968ECA00D2272C /* PBXTargetDependency */,
+ F2291F641FFEBC4000161936 /* PBXTargetDependency */,
+ BA959E8813968D8A00CA9C60 /* PBXTargetDependency */,
+ BA959E8A13968D8A00CA9C60 /* PBXTargetDependency */,
+ BA959E8C13968D8A00CA9C60 /* PBXTargetDependency */,
+ B194EC55185A8BDD00E2A1A6 /* PBXTargetDependency */,
+ BA959E8E13968D8A00CA9C60 /* PBXTargetDependency */,
+ BA959E9013968D8A00CA9C60 /* PBXTargetDependency */,
+ BA9BF4B3139682710018C7BB /* PBXTargetDependency */,
+ BA9BF4B5139682710018C7BB /* PBXTargetDependency */,
+ BA9BF4B7139682710018C7BB /* PBXTargetDependency */,
+ BA91CE6A137F43A500AE5160 /* PBXTargetDependency */,
+ BAE58A54137D69FB0049DD3B /* PBXTargetDependency */,
+ BAE58A2E1379A1260049DD3B /* PBXTargetDependency */,
+ BAE589FE137905740049DD3B /* PBXTargetDependency */,
+ BAE58A00137905740049DD3B /* PBXTargetDependency */,
+ BAE58A02137905740049DD3B /* PBXTargetDependency */,
+ BAE589D41378FDF40049DD3B /* PBXTargetDependency */,
+ BAE589B1137837AA0049DD3B /* PBXTargetDependency */,
+ BAE589B3137837AA0049DD3B /* PBXTargetDependency */,
+ BACC1D681377B8DC007728F4 /* PBXTargetDependency */,
+ BACC1D6A1377B8DC007728F4 /* PBXTargetDependency */,
+ BACC1D6C1377B8DC007728F4 /* PBXTargetDependency */,
+ BACC1D001377B3A4007728F4 /* PBXTargetDependency */,
+ BA4B7A981376600200003422 /* PBXTargetDependency */,
+ BA4B7A7C13765DC600003422 /* PBXTargetDependency */,
+ BA4B7A7A13765DC100003422 /* PBXTargetDependency */,
+ BA4B7A5A137649FA00003422 /* PBXTargetDependency */,
+ BA4B7A211373BF5000003422 /* PBXTargetDependency */,
+ BA4B7A0C1373BA8D00003422 /* PBXTargetDependency */,
+ BA4B79F81373B06B00003422 /* PBXTargetDependency */,
+ BA4B79DB1373A9CE00003422 /* PBXTargetDependency */,
+ BA9B76A81373A2CF001BB39F /* PBXTargetDependency */,
+ BA9B76AA1373A2CF001BB39F /* PBXTargetDependency */,
+ BA9B76AC1373A2CF001BB39F /* PBXTargetDependency */,
+ BA9B767513739E07001BB39F /* PBXTargetDependency */,
+ BA9B765413739B89001BB39F /* PBXTargetDependency */,
+ BAAEB3B413730E43003EA7A9 /* PBXTargetDependency */,
+ BAAEB3B613730E43003EA7A9 /* PBXTargetDependency */,
+ BAAEB3B813730E43003EA7A9 /* PBXTargetDependency */,
+ BA4FD350137307BC0025925C /* PBXTargetDependency */,
+ BA4FD3031372FE730025925C /* PBXTargetDependency */,
+ BA4FD3121373001C0025925C /* PBXTargetDependency */,
+ BA4FD329137301370025925C /* PBXTargetDependency */,
+ BA4FD337137306260025925C /* PBXTargetDependency */,
+ 8EC3916E1C973440001E28E6 /* PBXTargetDependency */,
+ );
+ name = All_MacOSX;
+ productName = All_MacOSX;
+ };
+ BA4FD32F137305DD0025925C /* machine */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA4FD330137305DD0025925C /* Build configuration list for PBXAggregateTarget "machine" */;
+ buildPhases = (
+ BA4FD335137306050025925C /* ShellScript */,
+ );
+ dependencies = (
+ BA4FD334137305E80025925C /* PBXTargetDependency */,
+ );
+ name = machine;
+ productName = machine;
+ };
+ BA959E7E13968C8E00CA9C60 /* zoneinfo */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA959E8213968C8E00CA9C60 /* Build configuration list for PBXAggregateTarget "zoneinfo" */;
+ buildPhases = (
+ BA7248051397C1350008497A /* ShellScript */,
+ BA959E8113968C8E00CA9C60 /* ShellScript */,
+ BA28FB881396DA67004986CB /* CopyFiles */,
+ FD0AA4911630C39500606589 /* ShellScript */,
+ );
+ dependencies = (
+ );
+ name = zoneinfo;
+ productName = machine;
+ };
+ BA9B76991373A246001BB39F /* chfn */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA9B769D1373A246001BB39F /* Build configuration list for PBXAggregateTarget "chfn" */;
+ buildPhases = (
+ BA9B769C1373A246001BB39F /* ShellScript */,
+ );
+ dependencies = (
+ BA9B76A01373A257001BB39F /* PBXTargetDependency */,
+ );
+ name = chfn;
+ productName = machine;
+ };
+ BA9B76A11373A2A2001BB39F /* chsh */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BA9B76A51373A2A2001BB39F /* Build configuration list for PBXAggregateTarget "chsh" */;
+ buildPhases = (
+ BA9B76A41373A2A2001BB39F /* ShellScript */,
+ );
+ dependencies = (
+ BA9B76A21373A2A2001BB39F /* PBXTargetDependency */,
+ );
+ name = chsh;
+ productName = machine;
+ };
+ BAAEB39C13730D5C003EA7A9 /* atq */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAAEB3A013730D5C003EA7A9 /* Build configuration list for PBXAggregateTarget "atq" */;
+ buildPhases = (
+ BAAEB39F13730D5C003EA7A9 /* ShellScript */,
+ );
+ dependencies = (
+ BAAEB3A413730D6B003EA7A9 /* PBXTargetDependency */,
+ );
+ name = atq;
+ productName = machine;
+ };
+ BAAEB3A513730DFA003EA7A9 /* atrm */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAAEB3A913730DFA003EA7A9 /* Build configuration list for PBXAggregateTarget "atrm" */;
+ buildPhases = (
+ BAAEB3A813730DFA003EA7A9 /* ShellScript */,
+ );
+ dependencies = (
+ BAAEB3A613730DFA003EA7A9 /* PBXTargetDependency */,
+ );
+ name = atrm;
+ productName = machine;
+ };
+ BAAEB3AC13730E1C003EA7A9 /* batch */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAAEB3B013730E1C003EA7A9 /* Build configuration list for PBXAggregateTarget "batch" */;
+ buildPhases = (
+ BAAEB3AF13730E1C003EA7A9 /* ShellScript */,
+ );
+ dependencies = (
+ BAAEB3AD13730E1C003EA7A9 /* PBXTargetDependency */,
+ );
+ name = batch;
+ productName = machine;
+ };
+ BACC1D181377B4C9007728F4 /* All_iOS */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BACC1D191377B4C9007728F4 /* Build configuration list for PBXAggregateTarget "All_iOS" */;
+ buildPhases = (
+ C9D64CD01B91064700CFA43B /* CopyFiles */,
+ );
+ dependencies = (
+ 358407D42245AD4B006A0D8E /* PBXTargetDependency */,
+ 926913A41EC706080079D787 /* PBXTargetDependency */,
+ 08CE3D381E6E24DF00DF1B78 /* PBXTargetDependency */,
+ C21481491C1A14AD003BCA63 /* PBXTargetDependency */,
+ 78DE9DFA1B504D1200FE6DF5 /* PBXTargetDependency */,
+ 97999D371AE84D4100E8B10F /* PBXTargetDependency */,
+ 08DC48901A12C6F0008AAF38 /* PBXTargetDependency */,
+ 550C19EF1804D2AD001DA380 /* PBXTargetDependency */,
+ ADA900801767A31900161ADF /* PBXTargetDependency */,
+ C625B29316D6F39000168EF7 /* PBXTargetDependency */,
+ 55CCB17A16B851F300B56979 /* PBXTargetDependency */,
+ C96F50BC15BDFDB1008682F7 /* PBXTargetDependency */,
+ 1523FE711595069F00661E82 /* PBXTargetDependency */,
+ BA0A861C1396B42600D2272C /* PBXTargetDependency */,
+ BA0A861813968ED500D2272C /* PBXTargetDependency */,
+ F2291F661FFEBC4700161936 /* PBXTargetDependency */,
+ BA959E9213968DA900CA9C60 /* PBXTargetDependency */,
+ BA959E9413968DA900CA9C60 /* PBXTargetDependency */,
+ BA959E9613968DA900CA9C60 /* PBXTargetDependency */,
+ BA959E9813968DA900CA9C60 /* PBXTargetDependency */,
+ BA959E9A13968DA900CA9C60 /* PBXTargetDependency */,
+ BA9BF4B9139682880018C7BB /* PBXTargetDependency */,
+ BA9BF4BB139682880018C7BB /* PBXTargetDependency */,
+ BA9BF4BD139682880018C7BB /* PBXTargetDependency */,
+ BAE58A56137D6A050049DD3B /* PBXTargetDependency */,
+ BAE58A321379A1300049DD3B /* PBXTargetDependency */,
+ BAE58A041379057F0049DD3B /* PBXTargetDependency */,
+ BAE58A061379057F0049DD3B /* PBXTargetDependency */,
+ BAE58A081379057F0049DD3B /* PBXTargetDependency */,
+ BAE589D61378FDFB0049DD3B /* PBXTargetDependency */,
+ BAE589B5137837B30049DD3B /* PBXTargetDependency */,
+ BAE589B7137837B30049DD3B /* PBXTargetDependency */,
+ BACC1D6E1377B8ED007728F4 /* PBXTargetDependency */,
+ BACC1D701377B8ED007728F4 /* PBXTargetDependency */,
+ BACC1D721377B8ED007728F4 /* PBXTargetDependency */,
+ BACC1D1C1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D1E1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D201377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D221377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D241377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D281377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D2A1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D2C1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D2E1377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D301377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D321377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D341377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D361377B58A007728F4 /* PBXTargetDependency */,
+ BACC1D3A1377B58A007728F4 /* PBXTargetDependency */,
+ 8E556A4B1D3FF7A40038D48B /* PBXTargetDependency */,
+ );
+ name = All_iOS;
+ productName = All_iOS;
+ };
+ BAE589AA137837130049DD3B /* pagesize */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAE589AE137837130049DD3B /* Build configuration list for PBXAggregateTarget "pagesize" */;
+ buildPhases = (
+ BAE589AD137837130049DD3B /* ShellScript */,
+ BAE589B8137838C10049DD3B /* CopyFiles */,
+ );
+ dependencies = (
+ );
+ name = pagesize;
+ productName = machine;
+ };
+ BAE589F5137904DF0049DD3B /* halt */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BAE589F9137904DF0049DD3B /* Build configuration list for PBXAggregateTarget "halt" */;
+ buildPhases = (
+ BAE589F8137904DF0049DD3B /* ShellScript */,
+ );
+ dependencies = (
+ BAE589FC137905080049DD3B /* PBXTargetDependency */,
+ );
+ name = halt;
+ productName = machine;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 08ADC98C1E70715D0001CB70 /* ktrace.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08ADC98B1E70715D0001CB70 /* ktrace.framework */; };
+ 08CE3D341E6E22F600DF1B78 /* stackshot.c in Sources */ = {isa = PBXBuildFile; fileRef = 08CE3D321E6E22DE00DF1B78 /* stackshot.c */; };
+ 08DC488E1A12C2D6008AAF38 /* kpgo.c in Sources */ = {isa = PBXBuildFile; fileRef = 08DC488D1A12C2C6008AAF38 /* kpgo.c */; };
+ 0D06BC661E8F091F00C6EC2D /* mslutil.c in Sources */ = {isa = PBXBuildFile; fileRef = 0D06BC651E8F091F00C6EC2D /* mslutil.c */; };
+ 1523FE6C1595056C00661E82 /* ltop.c in Sources */ = {isa = PBXBuildFile; fileRef = 1523FE6B1595056C00661E82 /* ltop.c */; };
+ 1523FE6D1595058100661E82 /* ltop.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1523FE6A1595056C00661E82 /* ltop.1 */; };
+ 1812F1EE1C8F923900F3DC9E /* system_cmds.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = C9D64CCF1B91063200CFA43B /* system_cmds.plist */; };
+ 358407CE2245AC09006A0D8E /* cpuctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 358407CD2245AC09006A0D8E /* cpuctl.c */; };
+ 358407D02245AC32006A0D8E /* cpuctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 358407CF2245AC32006A0D8E /* cpuctl.8 */; };
+ 5262264121E8295A0053ABA1 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 189337C21CC7CB4800B2A6A4 /* CoreFoundation.framework */; };
+ 5262264221ED5A780053ABA1 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9E0691D1C58BDB800C956EB /* IOKit.framework */; };
+ 550C19E61804D226001DA380 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ 550C19EC1804D281001DA380 /* iosim.c in Sources */ = {isa = PBXBuildFile; fileRef = 550C19E11804C55E001DA380 /* iosim.c */; };
+ 550C19ED1804D295001DA380 /* iosim.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 550C19E01804C55E001DA380 /* iosim.1 */; };
+ 55CCB16E16B84EDA00B56979 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ 55CCB17416B84EF800B56979 /* vm_purgeable_stat.c in Sources */ = {isa = PBXBuildFile; fileRef = 55CCB16916B84ED100B56979 /* vm_purgeable_stat.c */; };
+ 55CCB17616B84F3600B56979 /* vm_purgeable_stat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 55CCB16816B84ED100B56979 /* vm_purgeable_stat.1 */; };
+ 587B8CAF2489CBAD0001CD8D /* com.apple.serialdebugconsole.plist in Copy Files */ = {isa = PBXBuildFile; fileRef = 58775F6D2489B8CE0098F7DE /* com.apple.serialdebugconsole.plist */; };
+ 72D1FDD918C4140600C1E05F /* task_details.c in Sources */ = {isa = PBXBuildFile; fileRef = 72D1FDD818C4140600C1E05F /* task_details.c */; };
+ 72F9316D18C26A8600D804C5 /* port_details.c in Sources */ = {isa = PBXBuildFile; fileRef = 72F9316C18C26A8600D804C5 /* port_details.c */; };
+ 78DE9DFE1B504D7F00FE6DF5 /* wait4path.c in Sources */ = {isa = PBXBuildFile; fileRef = 78DE9DFC1B504D7F00FE6DF5 /* wait4path.c */; };
+ 78DE9E001B504DE500FE6DF5 /* wait4path.version in Sources */ = {isa = PBXBuildFile; fileRef = 78DE9DFD1B504D7F00FE6DF5 /* wait4path.version */; };
+ 78DE9EE61B505F1800FE6DF5 /* wait4path.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 78DE9EE51B505EBF00FE6DF5 /* wait4path.1 */; };
+ 8EC391691C973405001E28E6 /* proc_uuid_policy.c in Sources */ = {isa = PBXBuildFile; fileRef = 8EC391671C973400001E28E6 /* proc_uuid_policy.c */; };
+ 8EC3916C1C973429001E28E6 /* proc_uuid_policy.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8EC3916A1C97341E001E28E6 /* proc_uuid_policy.1 */; };
+ 97999D321AE84CE400E8B10F /* lskq.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 97999D301AE84C7600E8B10F /* lskq.1 */; };
+ 97999D331AE84D0A00E8B10F /* lskq.c in Sources */ = {isa = PBXBuildFile; fileRef = 97999D311AE84C7600E8B10F /* lskq.c */; };
+ ADA9007B1767A02D00161ADF /* purge.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = ADA900791767A02700161ADF /* purge.8 */; };
+ ADA9007C1767A03200161ADF /* purge.c in Sources */ = {isa = PBXBuildFile; fileRef = ADA9007A1767A02700161ADF /* purge.c */; };
+ B158E3A3185A836700474677 /* wordexp-helper.c in Sources */ = {isa = PBXBuildFile; fileRef = B158E3A2185A836700474677 /* wordexp-helper.c */; };
+ B3C10B9416E9876F006896A0 /* memory_pressure.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = B3C10B9316E983D4006896A0 /* memory_pressure.1 */; };
+ B3F0E6D016E96FC2008FAD09 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ B3F0E6DD16E9706E008FAD09 /* memory_pressure.c in Sources */ = {isa = PBXBuildFile; fileRef = B3F0E6DC16E9706E008FAD09 /* memory_pressure.c */; };
+ BA0A860B13968E8500D2272C /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ BA0A861313968EAD00D2272C /* zprint.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2E61372FAFA0025925C /* zprint.c */; };
+ BA0A861413968EB100D2272C /* zprint.1 in Copy man page */ = {isa = PBXBuildFile; fileRef = BA4FD2E51372FAFA0025925C /* zprint.1 */; };
+ BA28FB891396DA8A004986CB /* private in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA28FB851396DA01004986CB /* private */; };
+ BA4B79CF1373A74B00003422 /* dmesg.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2201372FAFA0025925C /* dmesg.8 */; };
+ BA4B79D01373A74F00003422 /* dmesg.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2211372FAFA0025925C /* dmesg.c */; };
+ BA4B79EE1373AFFA00003422 /* dynamic_pager.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD22D1372FAFA0025925C /* dynamic_pager.c */; };
+ BA4B79F21373B01100003422 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BA4B79F41373B01C00003422 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B79F31373B01B00003422 /* SystemConfiguration.framework */; };
+ BA4B79F51373B03300003422 /* dynamic_pager.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD22C1372FAFA0025925C /* dynamic_pager.8 */; };
+ BA4B79FC1373B82C00003422 /* com.apple.dynamic_pager.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4B79FA1373B7C300003422 /* com.apple.dynamic_pager.plist */; };
+ BA4B7A071373BA1F00003422 /* fs_usage.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2301372FAFA0025925C /* fs_usage.1 */; };
+ BA4B7A081373BA2400003422 /* fs_usage.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2311372FAFA0025925C /* fs_usage.c */; };
+ BA4B7A0A1373BA4600003422 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ BA4B7A191373BEDD00003422 /* getconf.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2381372FAFA0025925C /* getconf.c */; };
+ BA4B7A1E1373BEEB00003422 /* getconf.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2371372FAFA0025925C /* getconf.1 */; };
+ BA4B7A291373C30100003422 /* confstr.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A241373C30100003422 /* confstr.c */; };
+ BA4B7A2A1373C30100003422 /* limits.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A251373C30100003422 /* limits.c */; };
+ BA4B7A2B1373C30100003422 /* pathconf.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A261373C30100003422 /* pathconf.c */; };
+ BA4B7A2C1373C30100003422 /* progenv.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A271373C30100003422 /* progenv.c */; };
+ BA4B7A2D1373C30100003422 /* sysconf.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4B7A281373C30100003422 /* sysconf.c */; };
+ BA4B7A511376492600003422 /* chat.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2401372FAFA0025925C /* chat.c */; };
+ BA4B7A521376492B00003422 /* init.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2461372FAFA0025925C /* init.c */; };
+ BA4B7A531376493000003422 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2471372FAFA0025925C /* main.c */; };
+ BA4B7A541376493500003422 /* subr.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2491372FAFA0025925C /* subr.c */; };
+ BA4B7A551376495900003422 /* getty.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2431372FAFA0025925C /* getty.8 */; };
+ BA4B7A571376498C00003422 /* gettytab.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2441372FAFA0025925C /* gettytab.5 */; };
+ BA4B7A581376499000003422 /* ttys.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD24A1372FAFA0025925C /* ttys.5 */; };
+ BA4B7A5C13764F2E00003422 /* com.apple.getty.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4B7A5B13764F1400003422 /* com.apple.getty.plist */; };
+ BA4B7A6713765CF500003422 /* hostinfo.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD24E1372FAFA0025925C /* hostinfo.c */; };
+ BA4B7A6813765D0000003422 /* hostinfo.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD24D1372FAFA0025925C /* hostinfo.8 */; };
+ BA4B7A7313765D5D00003422 /* iostat.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2531372FAFA0025925C /* iostat.c */; };
+ BA4B7A7513765D6B00003422 /* iostat.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2521372FAFA0025925C /* iostat.8 */; };
+ BA4B7A7713765D7700003422 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A7613765D7700003422 /* IOKit.framework */; };
+ BA4B7A7813765DB100003422 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BA4B7A9213765F7C00003422 /* latency.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2581372FAFA0025925C /* latency.c */; };
+ BA4B7A9413765F8C00003422 /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A9313765F8B00003422 /* libncurses.dylib */; };
+ BA4B7A9513765FA100003422 /* latency.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2571372FAFA0025925C /* latency.1 */; };
+ BA4B7A9613765FE700003422 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ BA4FD2FC1372FD670025925C /* ac.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1DC1372FAFA0025925C /* ac.c */; };
+ BA4FD2FD1372FD710025925C /* ac.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1DB1372FAFA0025925C /* ac.8 */; };
+ BA4FD30F137300040025925C /* accton.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1DF1372FAFA0025925C /* accton.8 */; };
+ BA4FD310137300080025925C /* accton.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1E01372FAFA0025925C /* accton.c */; };
+ BA4FD325137301200025925C /* arch.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1E51372FAFA0025925C /* arch.c */; };
+ BA4FD3261373012C0025925C /* arch.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1E41372FAFA0025925C /* arch.1 */; };
+ BA4FD3271373012F0025925C /* machine.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1E71372FAFA0025925C /* machine.1 */; };
+ BA4FD343137307580025925C /* at.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1EB1372FAFA0025925C /* at.1 */; };
+ BA4FD344137307750025925C /* at.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1EC1372FAFA0025925C /* at.c */; };
+ BA4FD345137307750025925C /* panic.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1EE1372FAFA0025925C /* panic.c */; };
+ BA4FD346137307750025925C /* parsetime.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1F01372FAFA0025925C /* parsetime.c */; };
+ BA4FD347137307750025925C /* perm.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1F31372FAFA0025925C /* perm.c */; };
+ BA4FD3491373079B0025925C /* at.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1ED1372FAFA0025925C /* at.h */; };
+ BA4FD34A1373079B0025925C /* panic.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1EF1372FAFA0025925C /* panic.h */; };
+ BA4FD34B1373079B0025925C /* parsetime.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F11372FAFA0025925C /* parsetime.h */; };
+ BA4FD34C1373079B0025925C /* pathnames.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F21372FAFA0025925C /* pathnames.h */; };
+ BA4FD34D1373079B0025925C /* perm.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F41372FAFA0025925C /* perm.h */; };
+ BA4FD34E1373079B0025925C /* privs.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F51372FAFA0025925C /* privs.h */; };
+ BA91CE58137D6CB800AE5160 /* login in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2611372FAFA0025925C /* login */; };
+ BA91CE64137F430E00AE5160 /* kextmanager.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2B21372FAFA0025925C /* kextmanager.defs */; };
+ BA91CE65137F431100AE5160 /* shutdown.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2B51372FAFA0025925C /* shutdown.c */; };
+ BA91CE66137F433200AE5160 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A7613765D7700003422 /* IOKit.framework */; };
+ BA91CE67137F434200AE5160 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B79BF1373A53700003422 /* libbsm.dylib */; };
+ BA91CE68137F438700AE5160 /* shutdown.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2B41372FAFA0025925C /* shutdown.8 */; };
+ BA9B764313739ABE001BB39F /* pathnames.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F21372FAFA0025925C /* pathnames.h */; };
+ BA9B764513739ABE001BB39F /* privs.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1F51372FAFA0025925C /* privs.h */; };
+ BA9B764E13739B1C001BB39F /* atrun.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD1F91372FAFA0025925C /* atrun.c */; };
+ BA9B764F13739B45001BB39F /* atrun.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD1FA1372FAFA0025925C /* atrun.h */; };
+ BA9B765013739B52001BB39F /* atrun.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1F81372FAFA0025925C /* atrun.8 */; };
+ BA9B765213739B7D001BB39F /* com.apple.atrun.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD1FC1372FAFA0025925C /* com.apple.atrun.plist */; };
+ BA9B766513739C66001BB39F /* file_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2031372FAFA0025925C /* file_passwd.c */; };
+ BA9B766613739C66001BB39F /* nis_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2041372FAFA0025925C /* nis_passwd.c */; };
+ BA9B766713739C66001BB39F /* od_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2051372FAFA0025925C /* od_passwd.c */; };
+ BA9B766813739C66001BB39F /* pam_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2061372FAFA0025925C /* pam_passwd.c */; };
+ BA9B766913739C66001BB39F /* passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2071372FAFA0025925C /* passwd.c */; };
+ BA9B766A13739C66001BB39F /* stringops.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2081372FAFA0025925C /* stringops.c */; };
+ BA9B766B13739C7A001BB39F /* stringops.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD2091372FAFA0025925C /* stringops.h */; };
+ BA9B766C13739C84001BB39F /* chkpasswd.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2011372FAFA0025925C /* chkpasswd.8 */; };
+ BA9B766F13739D27001BB39F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BA9B767013739D27001BB39F /* OpenDirectory.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766E13739D27001BB39F /* OpenDirectory.framework */; };
+ BA9B767213739D36001BB39F /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B767113739D36001BB39F /* libpam.dylib */; };
+ BA9B767713739E9E001BB39F /* chkpasswd.h in Headers */ = {isa = PBXBuildFile; fileRef = BA9B767613739E9E001BB39F /* chkpasswd.h */; };
+ BA9B76851373A0D8001BB39F /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BA9B76861373A0D8001BB39F /* OpenDirectory.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766E13739D27001BB39F /* OpenDirectory.framework */; };
+ BA9B768E1373A14B001BB39F /* chpass.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD20E1372FAFA0025925C /* chpass.c */; };
+ BA9B768F1373A159001BB39F /* edit.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2101372FAFA0025925C /* edit.c */; };
+ BA9B76901373A159001BB39F /* field.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2111372FAFA0025925C /* field.c */; };
+ BA9B76911373A159001BB39F /* open_directory.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2121372FAFA0025925C /* open_directory.c */; };
+ BA9B76921373A159001BB39F /* pw_copy.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2141372FAFA0025925C /* pw_copy.c */; };
+ BA9B76931373A159001BB39F /* table.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2161372FAFA0025925C /* table.c */; };
+ BA9B76941373A159001BB39F /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2171372FAFA0025925C /* util.c */; };
+ BA9B76951373A16A001BB39F /* chpass.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD20F1372FAFA0025925C /* chpass.h */; };
+ BA9B76961373A16A001BB39F /* open_directory.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD2131372FAFA0025925C /* open_directory.h */; };
+ BA9B76971373A16A001BB39F /* pw_copy.h in Headers */ = {isa = PBXBuildFile; fileRef = BA4FD2151372FAFA0025925C /* pw_copy.h */; };
+ BA9B76981373A1A7001BB39F /* chpass.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD20D1372FAFA0025925C /* chpass.1 */; };
+ BA9BF495139681050018C7BB /* sync.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2B81372FAFA0025925C /* sync.8 */; };
+ BA9BF496139681090018C7BB /* sync.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2B91372FAFA0025925C /* sync.c */; };
+ BA9BF4A1139681500018C7BB /* sysctl.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2BD1372FAFA0025925C /* sysctl.c */; };
+ BA9BF4A31396816D0018C7BB /* sysctl.conf.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2BE1372FAFA0025925C /* sysctl.conf.5 */; };
+ BA9BF4A4139681710018C7BB /* sysctl.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2BC1372FAFA0025925C /* sysctl.8 */; };
+ BA9BF4A9139681910018C7BB /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ BA9BF4B0139682430018C7BB /* trace.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2C11372FAFA0025925C /* trace.1 */; };
+ BA9BF4B1139682480018C7BB /* trace.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2C21372FAFA0025925C /* trace.c */; };
+ BA9BF4C8139682DE0018C7BB /* vifs.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2C61372FAFA0025925C /* vifs.c */; };
+ BA9BF4C9139682E70018C7BB /* vifs.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2C51372FAFA0025925C /* vifs.8 */; };
+ BA9BF4D4139683140018C7BB /* vipw.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2CB1372FAFA0025925C /* vipw.8 */; };
+ BA9BF4D5139683180018C7BB /* vipw.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2CC1372FAFA0025925C /* vipw.c */; };
+ BA9BF4D61396831C0018C7BB /* pw_util.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2C91372FAFA0025925C /* pw_util.c */; };
+ BA9BF4E1139683890018C7BB /* vm_stat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2CF1372FAFA0025925C /* vm_stat.1 */; };
+ BA9BF4E21396838C0018C7BB /* vm_stat.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2D01372FAFA0025925C /* vm_stat.c */; };
+ BA9BF4ED1396840C0018C7BB /* zdump.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2D31372FAFA0025925C /* zdump.8 */; };
+ BA9BF4EE139684100018C7BB /* zdump.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2D41372FAFA0025925C /* zdump.c */; };
+ BA9BF4F9139684CF0018C7BB /* zic.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2E11372FAFA0025925C /* zic.8 */; };
+ BA9BF4FA139684D30018C7BB /* zic.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2E21372FAFA0025925C /* zic.c */; };
+ BA9BF4FB139684D70018C7BB /* scheck.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2DE1372FAFA0025925C /* scheck.c */; };
+ BA9BF4FC139684DB0018C7BB /* ialloc.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2DC1372FAFA0025925C /* ialloc.c */; };
+ BACC1CF91377B288007728F4 /* login.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD25D1372FAFA0025925C /* login.c */; };
+ BACC1CFA1377B28C007728F4 /* login_audit.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD25F1372FAFA0025925C /* login_audit.c */; };
+ BACC1CFB1377B2A8007728F4 /* login.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD25C1372FAFA0025925C /* login.1 */; };
+ BACC1CFE1377B2D8007728F4 /* login.term in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2621372FAFA0025925C /* login.term */; };
+ BACC1D171377B4A9007728F4 /* mean.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD26B1372FAFA0025925C /* mean.c */; };
+ BACC1D471377B71D007728F4 /* mkfile.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD26F1372FAFA0025925C /* mkfile.c */; };
+ BACC1D481377B723007728F4 /* mkfile.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD26E1372FAFA0025925C /* mkfile.8 */; };
+ BACC1D571377B821007728F4 /* newgrp.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2731372FAFA0025925C /* newgrp.c */; };
+ BACC1D581377B82A007728F4 /* newgrp.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2721372FAFA0025925C /* newgrp.1 */; };
+ BACC1D631377B88B007728F4 /* nologin.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2781372FAFA0025925C /* nologin.c */; };
+ BACC1D641377B894007728F4 /* nologin.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2771372FAFA0025925C /* nologin.8 */; };
+ BACC1D661377B8B2007728F4 /* nologin.5 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2761372FAFA0025925C /* nologin.5 */; };
+ BAE5899F137836A00049DD3B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A7613765D7700003422 /* IOKit.framework */; };
+ BAE589A0137836A00049DD3B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ BAE589A8137836CA0049DD3B /* nvram.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD27C1372FAFA0025925C /* nvram.c */; };
+ BAE589A9137836D60049DD3B /* nvram.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD27B1372FAFA0025925C /* nvram.8 */; };
+ BAE589B9137838D10049DD3B /* pagesize.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD27F1372FAFA0025925C /* pagesize.1 */; };
+ BAE589D01378FD300049DD3B /* file_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2831372FAFA0025925C /* file_passwd.c */; };
+ BAE589D11378FD340049DD3B /* passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2881372FAFA0025925C /* passwd.c */; };
+ BAE589D21378FD4D0049DD3B /* passwd.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2871372FAFA0025925C /* passwd.1 */; };
+ BAE589D8137900730049DD3B /* nis_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2841372FAFA0025925C /* nis_passwd.c */; };
+ BAE589D9137900770049DD3B /* od_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2851372FAFA0025925C /* od_passwd.c */; };
+ BAE589DA1379007C0049DD3B /* pam_passwd.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2861372FAFA0025925C /* pam_passwd.c */; };
+ BAE589E5137903680049DD3B /* pw_scan.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD28C1372FAFA0025925C /* pw_scan.c */; };
+ BAE589E6137903680049DD3B /* pwd_mkdb.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD28F1372FAFA0025925C /* pwd_mkdb.c */; };
+ BAE589E71379037A0049DD3B /* pwd_mkdb.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD28E1372FAFA0025925C /* pwd_mkdb.8 */; };
+ BAE589F2137904B50049DD3B /* kextmanager.defs in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2921372FAFA0025925C /* kextmanager.defs */; };
+ BAE589F3137904B90049DD3B /* reboot.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2941372FAFA0025925C /* reboot.c */; };
+ BAE589F4137904C50049DD3B /* reboot.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2931372FAFA0025925C /* reboot.8 */; };
+ BAE58A1313799F950049DD3B /* db.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2971372FAFA0025925C /* db.c */; };
+ BAE58A1413799F980049DD3B /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2991372FAFA0025925C /* main.c */; };
+ BAE58A1513799F9B0049DD3B /* pdb.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD29B1372FAFA0025925C /* pdb.c */; };
+ BAE58A1613799F9F0049DD3B /* usrdb.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD29D1372FAFA0025925C /* usrdb.c */; };
+ BAE58A1713799FA80049DD3B /* sa.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD29C1372FAFA0025925C /* sa.8 */; };
+ BAE58A49137D69A60049DD3B /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ BAE58A50137D69DA0049DD3B /* sc_usage.c in Sources */ = {isa = PBXBuildFile; fileRef = BA4FD2AF1372FAFA0025925C /* sc_usage.c */; };
+ BAE58A51137D69E30049DD3B /* libncurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A9313765F8B00003422 /* libncurses.dylib */; };
+ BAE58A52137D69ED0049DD3B /* sc_usage.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = BA4FD2AE1372FAFA0025925C /* sc_usage.1 */; };
+ C20138731C1A17D0008EE53F /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ C21481381C1A1213003BCA63 /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = C21481201C1A11E7003BCA63 /* vm.c */; };
+ C21481391C1A1216003BCA63 /* vanilla.c in Sources */ = {isa = PBXBuildFile; fileRef = C214811E1C1A11E7003BCA63 /* vanilla.c */; };
+ C214813A1C1A1219003BCA63 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = C214811C1C1A11E7003BCA63 /* utils.c */; };
+ C214813B1C1A122B003BCA63 /* corefile.c in Sources */ = {isa = PBXBuildFile; fileRef = C214810D1C1A11E6003BCA63 /* corefile.c */; };
+ C214813C1C1A122B003BCA63 /* dyld_shared_cache.c in Sources */ = {isa = PBXBuildFile; fileRef = C214810F1C1A11E6003BCA63 /* dyld_shared_cache.c */; };
+ C214813D1C1A122B003BCA63 /* dyld.c in Sources */ = {isa = PBXBuildFile; fileRef = C21481111C1A11E6003BCA63 /* dyld.c */; };
+ C214813E1C1A122B003BCA63 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = C21481151C1A11E6003BCA63 /* main.c */; };
+ C214813F1C1A122B003BCA63 /* sparse.c in Sources */ = {isa = PBXBuildFile; fileRef = C21481181C1A11E6003BCA63 /* sparse.c */; };
+ C21481401C1A122B003BCA63 /* threads.c in Sources */ = {isa = PBXBuildFile; fileRef = C214811A1C1A11E7003BCA63 /* threads.c */; };
+ C21481451C1A131D003BCA63 /* gcore.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C21481131C1A11E6003BCA63 /* gcore.1 */; };
+ C248DBB01C1A1D0500F6E9AF /* libcompression.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C248DBAF1C1A1D0500F6E9AF /* libcompression.dylib */; };
+ C2DAA94F1D9F22F000FAC263 /* convert.c in Sources */ = {isa = PBXBuildFile; fileRef = C2DAA94B1D9F22BF00FAC263 /* convert.c */; };
+ C625B28B16D6F27E00168EF7 /* taskpolicy.c in Sources */ = {isa = PBXBuildFile; fileRef = C625B28A16D6F27E00168EF7 /* taskpolicy.c */; };
+ C625B28D16D6F27E00168EF7 /* taskpolicy.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C625B28C16D6F27E00168EF7 /* taskpolicy.8 */; };
+ C65BF57A144BD7C5009028A3 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ C96F50B215BDCEC3008682F7 /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ C96F50BD15BDFEFB008682F7 /* lsmp.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C96F50AC15BDCBF0008682F7 /* lsmp.1 */; };
+ C96F50BE15BDFF03008682F7 /* lsmp.c in Sources */ = {isa = PBXBuildFile; fileRef = C96F50AD15BDCE8E008682F7 /* lsmp.c */; };
+ C9779F6E159A2A0C009436FD /* libutil.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = BA4B7A091373BA4600003422 /* libutil.dylib */; };
+ C99490E52090F56F00246D9D /* zprint.lua in Copy Lua library */ = {isa = PBXBuildFile; fileRef = C99490E32090F55D00246D9D /* zprint.lua */; };
+ C9D64CD11B91065D00CFA43B /* system_cmds.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = C9D64CCF1B91063200CFA43B /* system_cmds.plist */; };
+ C9D64CD31B91067500CFA43B /* system_cmds.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = C9D64CCF1B91063200CFA43B /* system_cmds.plist */; };
+ C9E0691A1C58BD7E00C956EB /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BA9B766D13739D27001BB39F /* CoreFoundation.framework */; };
+ C9E0691C1C58BDA000C956EB /* CoreSymbolication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9E0691B1C58BDA000C956EB /* CoreSymbolication.framework */; };
+ C9E0691E1C58BDB800C956EB /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9E0691D1C58BDB800C956EB /* IOKit.framework */; };
+ CEB165CC246C599A00228592 /* test_zprint.lua in CopyFiles */ = {isa = PBXBuildFile; fileRef = CEB165CB246C599A00228592 /* test_zprint.lua */; };
+ CEB165CE246C59C100228592 /* test_zprint.lua in Copy test */ = {isa = PBXBuildFile; fileRef = CEB165CB246C599A00228592 /* test_zprint.lua */; };
+ D37CC32C2395D9F100288C74 /* mslutil.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0D06BC671E8F0B4100C6EC2D /* mslutil.1 */; };
+ F2291F551FFEBB6A00161936 /* CoreSymbolication.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9E0691B1C58BDA000C956EB /* CoreSymbolication.framework */; };
+ F2291F601FFEBB9E00161936 /* zlog.c in Sources */ = {isa = PBXBuildFile; fileRef = F2291F5F1FFEBB9E00161936 /* zlog.c */; };
+ F27B70282044CB40003C04FC /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F27B70272044CB40003C04FC /* CoreFoundation.framework */; };
+ F27B702B2045038B003C04FC /* SymbolicationHelper.c in Sources */ = {isa = PBXBuildFile; fileRef = F27B70292045038B003C04FC /* SymbolicationHelper.c */; };
+ F29F5A5F203E5347005B0099 /* zlog.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = F29F5A5C203E4403005B0099 /* zlog.1 */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXBuildRule section */
+ 78DE9DFF1B504DB800FE6DF5 /* PBXBuildRule */ = {
+ isa = PBXBuildRule;
+ compilerSpec = com.apple.compilers.proxy.script;
+ fileType = pattern.proxy;
+ inputFiles = (
+ );
+ isEditable = 1;
+ outputFiles = (
+ "$(DERIVED_SOURCES_DIR)/$(CURRENT_ARCH)/darwin_version.c",
+ "$(DERIVED_SOURCES_DIR)/$(CURRENT_ARCH)/darwin_version.h",
+ );
+ script = "/bin/bash ${XPC_BUILD_XCSCRIPTS_DIR}/darwinversion.sh";
+ };
+/* End PBXBuildRule section */
+
+/* Begin PBXContainerItemProxy section */
+ 08CE3D351E6E24CC00DF1B78 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 08CE3D281E6E22A200DF1B78;
+ remoteInfo = stackshot;
+ };
+ 08CE3D371E6E24DF00DF1B78 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 08CE3D281E6E22A200DF1B78;
+ remoteInfo = stackshot;
+ };
+ 08DC488F1A12C6F0008AAF38 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 08DC48841A12C21B008AAF38;
+ remoteInfo = kpgo;
+ };
+ 08DC48911A12C6FA008AAF38 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 08DC48841A12C21B008AAF38;
+ remoteInfo = kpgo;
+ };
+ 1523FE6E1595069900661E82 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 1523FE5A1595048900661E82;
+ remoteInfo = ltop;
+ };
+ 1523FE701595069F00661E82 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 1523FE5A1595048900661E82;
+ remoteInfo = ltop;
+ };
+ 1812F18E1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C20D8C681C1A102F00C1226B;
+ remoteInfo = gcore;
+ };
+ 1812F1901C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 78DE9DDF1B5045DE00FE6DF5;
+ remoteInfo = wait4path;
+ };
+ 1812F1921C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97999D211AE84C0E00E8B10F;
+ remoteInfo = lskq;
+ };
+ 1812F1941C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 08DC48841A12C21B008AAF38;
+ remoteInfo = kpgo;
+ };
+ 1812F19A1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 550C19E21804D226001DA380;
+ remoteInfo = iosim;
+ };
+ 1812F19C1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = ADA9006F17679A8C00161ADF;
+ remoteInfo = purge;
+ };
+ 1812F19E1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C625B28716D6F27E00168EF7;
+ remoteInfo = taskpolicy;
+ };
+ 1812F1A01C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 55CCB16A16B84EDA00B56979;
+ remoteInfo = vm_purgeable_stat;
+ };
+ 1812F1A21C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C96F50AE15BDCEC3008682F7;
+ remoteInfo = lsmp;
+ };
+ 1812F1A41C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 1523FE5A1595048900661E82;
+ remoteInfo = ltop;
+ };
+ 1812F1A61C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA959E7E13968C8E00CA9C60;
+ remoteInfo = zoneinfo;
+ };
+ 1812F1A81C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA0A860713968E8500D2272C;
+ remoteInfo = zprint;
+ };
+ 1812F1AA1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4BE139682BA0018C7BB;
+ remoteInfo = vifs;
+ };
+ 1812F1AC1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4CA139682F80018C7BB;
+ remoteInfo = vipw;
+ };
+ 1812F1AE1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4D7139683580018C7BB;
+ remoteInfo = vm_stat;
+ };
+ 1812F1B01C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4E3139683EB0018C7BB;
+ remoteInfo = zdump;
+ };
+ 1812F1B21C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4EF139684B40018C7BB;
+ remoteInfo = zic;
+ };
+ 1812F1B41C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF48A139680CF0018C7BB;
+ remoteInfo = sync;
+ };
+ 1812F1B61C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4971396812D0018C7BB;
+ remoteInfo = sysctl;
+ };
+ 1812F1B81C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4A5139681910018C7BB;
+ remoteInfo = trace;
+ };
+ 1812F1BA1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A45137D69A60049DD3B;
+ remoteInfo = sc_usage;
+ };
+ 1812F1BC1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A0913799F610049DD3B;
+ remoteInfo = sa;
+ };
+ 1812F1BE1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589DB137902F50049DD3B;
+ remoteInfo = pwd_mkdb;
+ };
+ 1812F1C01C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589E81379044E0049DD3B;
+ remoteInfo = reboot;
+ };
+ 1812F1C21C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589F5137904DF0049DD3B;
+ remoteInfo = halt;
+ };
+ 1812F1C41C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589BA1378FCAA0049DD3B;
+ remoteInfo = passwd;
+ };
+ 1812F1C61C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE5899B137836A00049DD3B;
+ remoteInfo = nvram;
+ };
+ 1812F1C81C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589AA137837130049DD3B;
+ remoteInfo = pagesize;
+ };
+ 1812F1CA1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D3D1377B6E2007728F4;
+ remoteInfo = mkfile;
+ };
+ 1812F1CC1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D491377B7A7007728F4;
+ remoteInfo = newgrp;
+ };
+ 1812F1CE1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D591377B85C007728F4;
+ remoteInfo = nologin;
+ };
+ 1812F1D01C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD2EE1372FB3D0025925C;
+ remoteInfo = ac;
+ };
+ 1812F1D21C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3041372FFD80025925C;
+ remoteInfo = accton;
+ };
+ 1812F1D41C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD31A137300ED0025925C;
+ remoteInfo = arch;
+ };
+ 1812F1D61C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD32F137305DD0025925C;
+ remoteInfo = machine;
+ };
+ 1812F1D81C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79C51373A72800003422;
+ remoteInfo = dmesg;
+ };
+ 1812F1DA1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79E01373AF7A00003422;
+ remoteInfo = dynamic_pager;
+ };
+ 1812F1DC1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79FD1373B9E900003422;
+ remoteInfo = fs_usage;
+ };
+ 1812F1DE1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A0E1373BE9D00003422;
+ remoteInfo = getconf;
+ };
+ 1812F1E01C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A3F137648E100003422;
+ remoteInfo = getty;
+ };
+ 1812F1E21C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A5D13765CC700003422;
+ remoteInfo = hostinfo;
+ };
+ 1812F1E41C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A6913765D3E00003422;
+ remoteInfo = iostat;
+ };
+ 1812F1E61C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A7D13765F3C00003422;
+ remoteInfo = latency;
+ };
+ 1812F1E81C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA473DA01377B2230005CC19;
+ remoteInfo = login;
+ };
+ 1812F1EC1C8F923900F3DC9E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D0D1377B481007728F4;
+ remoteInfo = mean;
+ };
+ 358407D12245AD40006A0D8E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 3521C84C2245AA92001B3201;
+ remoteInfo = cpuctl;
+ };
+ 358407D32245AD4B006A0D8E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 3521C84C2245AA92001B3201;
+ remoteInfo = cpuctl;
+ };
+ 358407D52245AD55006A0D8E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 3521C84C2245AA92001B3201;
+ remoteInfo = cpuctl;
+ };
+ 550C19EE1804D2AD001DA380 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 550C19E21804D226001DA380;
+ remoteInfo = iosim;
+ };
+ 550C19F01804D2B7001DA380 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 550C19E21804D226001DA380;
+ remoteInfo = iosim;
+ };
+ 55CCB17716B851E900B56979 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 55CCB16A16B84EDA00B56979;
+ remoteInfo = vm_purgeable_stat;
+ };
+ 55CCB17916B851F300B56979 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 55CCB16A16B84EDA00B56979;
+ remoteInfo = vm_purgeable_stat;
+ };
+ 78DE9DEC1B5048D400FE6DF5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 78DE9DDF1B5045DE00FE6DF5;
+ remoteInfo = wait4path;
+ };
+ 78DE9DF91B504D1200FE6DF5 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 78DE9DDF1B5045DE00FE6DF5;
+ remoteInfo = wait4path;
+ };
+ 8E556A4A1D3FF7A40038D48B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8EC3915B1C9733C2001E28E6;
+ remoteInfo = proc_uuid_policy;
+ };
+ 8EC3916D1C973440001E28E6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8EC3915B1C9733C2001E28E6;
+ remoteInfo = proc_uuid_policy;
+ };
+ 926913A11EC706010079D787 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 0D06BC5D1E8F08CB00C6EC2D;
+ remoteInfo = mslutil;
+ };
+ 926913A31EC706080079D787 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 0D06BC5D1E8F08CB00C6EC2D;
+ remoteInfo = mslutil;
+ };
+ 926913A51EC706130079D787 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 0D06BC5D1E8F08CB00C6EC2D;
+ remoteInfo = mslutil;
+ };
+ 97999D341AE84D3A00E8B10F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97999D211AE84C0E00E8B10F;
+ remoteInfo = lskq;
+ };
+ 97999D361AE84D4100E8B10F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 97999D211AE84C0E00E8B10F;
+ remoteInfo = lskq;
+ };
+ ADA9007D1767A31300161ADF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = ADA9006F17679A8C00161ADF;
+ remoteInfo = purge;
+ };
+ ADA9007F1767A31900161ADF /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = ADA9006F17679A8C00161ADF;
+ remoteInfo = purge;
+ };
+ B194EC54185A8BDD00E2A1A6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B158E39F185A836700474677;
+ remoteInfo = "wordexp-helper";
+ };
+ B3F0E6DE16E97142008FAD09 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = B3F0E6CC16E96FC2008FAD09;
+ remoteInfo = memory_pressure;
+ };
+ BA0A861513968ECA00D2272C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA0A860713968E8500D2272C;
+ remoteInfo = zprint;
+ };
+ BA0A861713968ED500D2272C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA0A860713968E8500D2272C;
+ remoteInfo = zprint;
+ };
+ BA0A86191396B41F00D2272C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA959E7E13968C8E00CA9C60;
+ remoteInfo = zoneinfo;
+ };
+ BA0A861B1396B42600D2272C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA959E7E13968C8E00CA9C60;
+ remoteInfo = zoneinfo;
+ };
+ BA4B79DA1373A9CE00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79C51373A72800003422;
+ remoteInfo = dmesg;
+ };
+ BA4B79F71373B06B00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79E01373AF7A00003422;
+ remoteInfo = dynamic_pager;
+ };
+ BA4B7A0B1373BA8D00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79FD1373B9E900003422;
+ remoteInfo = fs_usage;
+ };
+ BA4B7A201373BF5000003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A0E1373BE9D00003422;
+ remoteInfo = getconf;
+ };
+ BA4B7A59137649FA00003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A3F137648E100003422;
+ remoteInfo = getty;
+ };
+ BA4B7A7913765DC100003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A5D13765CC700003422;
+ remoteInfo = hostinfo;
+ };
+ BA4B7A7B13765DC600003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A6913765D3E00003422;
+ remoteInfo = iostat;
+ };
+ BA4B7A971376600200003422 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A7D13765F3C00003422;
+ remoteInfo = latency;
+ };
+ BA4FD3021372FE730025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD2EE1372FB3D0025925C;
+ remoteInfo = ac;
+ };
+ BA4FD3111373001C0025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3041372FFD80025925C;
+ remoteInfo = accton;
+ };
+ BA4FD328137301370025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD31A137300ED0025925C;
+ remoteInfo = arch;
+ };
+ BA4FD333137305E80025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD31A137300ED0025925C;
+ remoteInfo = arch;
+ };
+ BA4FD336137306260025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD32F137305DD0025925C;
+ remoteInfo = machine;
+ };
+ BA4FD34F137307BC0025925C /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3381373073E0025925C;
+ remoteInfo = at;
+ };
+ BA91CE69137F43A500AE5160 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA91CE59137F42ED00AE5160;
+ remoteInfo = shutdown;
+ };
+ BA959E8713968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4BE139682BA0018C7BB;
+ remoteInfo = vifs;
+ };
+ BA959E8913968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4CA139682F80018C7BB;
+ remoteInfo = vipw;
+ };
+ BA959E8B13968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4D7139683580018C7BB;
+ remoteInfo = vm_stat;
+ };
+ BA959E8D13968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4E3139683EB0018C7BB;
+ remoteInfo = zdump;
+ };
+ BA959E8F13968D8A00CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4EF139684B40018C7BB;
+ remoteInfo = zic;
+ };
+ BA959E9113968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4BE139682BA0018C7BB;
+ remoteInfo = vifs;
+ };
+ BA959E9313968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4CA139682F80018C7BB;
+ remoteInfo = vipw;
+ };
+ BA959E9513968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4D7139683580018C7BB;
+ remoteInfo = vm_stat;
+ };
+ BA959E9713968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4E3139683EB0018C7BB;
+ remoteInfo = zdump;
+ };
+ BA959E9913968DA900CA9C60 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4EF139684B40018C7BB;
+ remoteInfo = zic;
+ };
+ BA9B765313739B89001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B763913739ABE001BB39F;
+ remoteInfo = atrun;
+ };
+ BA9B767413739E07001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B765513739C20001BB39F;
+ remoteInfo = chkpasswd;
+ };
+ BA9B769F1373A257001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76781373A0D8001BB39F;
+ remoteInfo = chpass;
+ };
+ BA9B76A31373A2A2001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76781373A0D8001BB39F;
+ remoteInfo = chpass;
+ };
+ BA9B76A71373A2CF001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76781373A0D8001BB39F;
+ remoteInfo = chpass;
+ };
+ BA9B76A91373A2CF001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76991373A246001BB39F;
+ remoteInfo = chfn;
+ };
+ BA9B76AB1373A2CF001BB39F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9B76A11373A2A2001BB39F;
+ remoteInfo = chsh;
+ };
+ BA9BF4B2139682710018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF48A139680CF0018C7BB;
+ remoteInfo = sync;
+ };
+ BA9BF4B4139682710018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4971396812D0018C7BB;
+ remoteInfo = sysctl;
+ };
+ BA9BF4B6139682710018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4A5139681910018C7BB;
+ remoteInfo = trace;
+ };
+ BA9BF4B8139682880018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF48A139680CF0018C7BB;
+ remoteInfo = sync;
+ };
+ BA9BF4BA139682880018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4971396812D0018C7BB;
+ remoteInfo = sysctl;
+ };
+ BA9BF4BC139682880018C7BB /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA9BF4A5139681910018C7BB;
+ remoteInfo = trace;
+ };
+ BAAEB3A313730D6B003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3381373073E0025925C;
+ remoteInfo = at;
+ };
+ BAAEB3A713730DFA003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3381373073E0025925C;
+ remoteInfo = at;
+ };
+ BAAEB3AE13730E1C003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3381373073E0025925C;
+ remoteInfo = at;
+ };
+ BAAEB3B313730E43003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAAEB39C13730D5C003EA7A9;
+ remoteInfo = atq;
+ };
+ BAAEB3B513730E43003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAAEB3A513730DFA003EA7A9;
+ remoteInfo = atrm;
+ };
+ BAAEB3B713730E43003EA7A9 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAAEB3AC13730E1C003EA7A9;
+ remoteInfo = batch;
+ };
+ BACC1CFF1377B3A4007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA473DA01377B2230005CC19;
+ remoteInfo = login;
+ };
+ BACC1D1B1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD2EE1372FB3D0025925C;
+ remoteInfo = ac;
+ };
+ BACC1D1D1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD3041372FFD80025925C;
+ remoteInfo = accton;
+ };
+ BACC1D1F1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD31A137300ED0025925C;
+ remoteInfo = arch;
+ };
+ BACC1D211377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4FD32F137305DD0025925C;
+ remoteInfo = machine;
+ };
+ BACC1D231377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79C51373A72800003422;
+ remoteInfo = dmesg;
+ };
+ BACC1D271377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79E01373AF7A00003422;
+ remoteInfo = dynamic_pager;
+ };
+ BACC1D291377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B79FD1373B9E900003422;
+ remoteInfo = fs_usage;
+ };
+ BACC1D2B1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A0E1373BE9D00003422;
+ remoteInfo = getconf;
+ };
+ BACC1D2D1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A3F137648E100003422;
+ remoteInfo = getty;
+ };
+ BACC1D2F1377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A5D13765CC700003422;
+ remoteInfo = hostinfo;
+ };
+ BACC1D311377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A6913765D3E00003422;
+ remoteInfo = iostat;
+ };
+ BACC1D331377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA4B7A7D13765F3C00003422;
+ remoteInfo = latency;
+ };
+ BACC1D351377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BA473DA01377B2230005CC19;
+ remoteInfo = login;
+ };
+ BACC1D391377B58A007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D0D1377B481007728F4;
+ remoteInfo = mean;
+ };
+ BACC1D671377B8DC007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D3D1377B6E2007728F4;
+ remoteInfo = mkfile;
+ };
+ BACC1D691377B8DC007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D491377B7A7007728F4;
+ remoteInfo = newgrp;
+ };
+ BACC1D6B1377B8DC007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D591377B85C007728F4;
+ remoteInfo = nologin;
+ };
+ BACC1D6D1377B8ED007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D3D1377B6E2007728F4;
+ remoteInfo = mkfile;
+ };
+ BACC1D6F1377B8ED007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D491377B7A7007728F4;
+ remoteInfo = newgrp;
+ };
+ BACC1D711377B8ED007728F4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BACC1D591377B85C007728F4;
+ remoteInfo = nologin;
+ };
+ BAE589B0137837AA0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE5899B137836A00049DD3B;
+ remoteInfo = nvram;
+ };
+ BAE589B2137837AA0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589AA137837130049DD3B;
+ remoteInfo = pagesize;
+ };
+ BAE589B4137837B30049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE5899B137836A00049DD3B;
+ remoteInfo = nvram;
+ };
+ BAE589B6137837B30049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589AA137837130049DD3B;
+ remoteInfo = pagesize;
+ };
+ BAE589D31378FDF40049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589BA1378FCAA0049DD3B;
+ remoteInfo = passwd;
+ };
+ BAE589D51378FDFB0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589BA1378FCAA0049DD3B;
+ remoteInfo = passwd;
+ };
+ BAE589FB137905080049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589E81379044E0049DD3B;
+ remoteInfo = reboot;
+ };
+ BAE589FD137905740049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589DB137902F50049DD3B;
+ remoteInfo = pwd_mkdb;
+ };
+ BAE589FF137905740049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589E81379044E0049DD3B;
+ remoteInfo = reboot;
+ };
+ BAE58A01137905740049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589F5137904DF0049DD3B;
+ remoteInfo = halt;
+ };
+ BAE58A031379057F0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589DB137902F50049DD3B;
+ remoteInfo = pwd_mkdb;
+ };
+ BAE58A051379057F0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589E81379044E0049DD3B;
+ remoteInfo = reboot;
+ };
+ BAE58A071379057F0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE589F5137904DF0049DD3B;
+ remoteInfo = halt;
+ };
+ BAE58A2D1379A1260049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A0913799F610049DD3B;
+ remoteInfo = sa;
+ };
+ BAE58A311379A1300049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A0913799F610049DD3B;
+ remoteInfo = sa;
+ };
+ BAE58A53137D69FB0049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A45137D69A60049DD3B;
+ remoteInfo = sc_usage;
+ };
+ BAE58A55137D6A050049DD3B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BAE58A45137D69A60049DD3B;
+ remoteInfo = sc_usage;
+ };
+ C21481461C1A1447003BCA63 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C20D8C681C1A102F00C1226B;
+ remoteInfo = gcore;
+ };
+ C21481481C1A14AD003BCA63 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C20D8C681C1A102F00C1226B;
+ remoteInfo = gcore;
+ };
+ C625B29016D6F38700168EF7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C625B28716D6F27E00168EF7;
+ remoteInfo = taskpolicy;
+ };
+ C625B29216D6F39000168EF7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C625B28716D6F27E00168EF7;
+ remoteInfo = taskpolicy;
+ };
+ C96F50B915BDFDA7008682F7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C96F50AE15BDCEC3008682F7;
+ remoteInfo = lsmp;
+ };
+ C96F50BB15BDFDB1008682F7 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C96F50AE15BDCEC3008682F7;
+ remoteInfo = lsmp;
+ };
+ F2291F631FFEBC4000161936 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F2291F501FFEBB6A00161936;
+ remoteInfo = zlog;
+ };
+ F2291F651FFEBC4700161936 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F2291F501FFEBB6A00161936;
+ remoteInfo = zlog;
+ };
+ F2291F671FFEBC4F00161936 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = BA2DE9181372FA9100D1913C /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F2291F501FFEBB6A00161936;
+ remoteInfo = zlog;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 08CE3D271E6E22A200DF1B78 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 08DC48831A12C21B008AAF38 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 0D06BC5C1E8F08CB00C6EC2D /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ D37CC32C2395D9F100288C74 /* mslutil.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 1523FE5F1595048900661E82 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 1523FE6D1595058100661E82 /* ltop.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 1812F1ED1C8F923900F3DC9E /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /AppleInternal/CoreOS/BATS/unit_tests;
+ dstSubfolderSpec = 0;
+ files = (
+ 1812F1EE1C8F923900F3DC9E /* system_cmds.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 3521C84B2245AA92001B3201 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ 358407D02245AC32006A0D8E /* cpuctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 550C19E71804D226001DA380 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 550C19ED1804D295001DA380 /* iosim.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 55CCB16F16B84EDA00B56979 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 55CCB17616B84F3600B56979 /* vm_purgeable_stat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 587B8CAE2489CB9C0001CD8D /* Copy Files */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /AppleInternal/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ 587B8CAF2489CBAD0001CD8D /* com.apple.serialdebugconsole.plist in Copy Files */,
+ );
+ name = "Copy Files";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 78DE9DDE1B5045DE00FE6DF5 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 78DE9EE61B505F1800FE6DF5 /* wait4path.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 8EC391601C9733C2001E28E6 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 8EC3916C1C973429001E28E6 /* proc_uuid_policy.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ 97999D281AE84C0E00E8B10F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ 97999D321AE84CE400E8B10F /* lskq.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ ADA9007317679A8C00161ADF /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ ADA9007B1767A02D00161ADF /* purge.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ B3F0E6D116E96FC2008FAD09 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ B3C10B9416E9876F006896A0 /* memory_pressure.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA0A860C13968E8500D2272C /* Copy man page */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA0A861413968EB100D2272C /* zprint.1 in Copy man page */,
+ );
+ name = "Copy man page";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA28FB881396DA67004986CB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /;
+ dstSubfolderSpec = 0;
+ files = (
+ BA28FB891396DA8A004986CB /* private in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA473DAE1377B2230005CC19 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1CFB1377B2A8007728F4 /* login.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B79C91373A72800003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B79CF1373A74B00003422 /* dmesg.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B79E61373AF7A00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B79F51373B03300003422 /* dynamic_pager.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B79E81373AF7A00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B79FC1373B82C00003422 /* com.apple.dynamic_pager.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A011373B9E900003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A071373BA1F00003422 /* fs_usage.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A121373BE9D00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A1E1373BEEB00003422 /* getconf.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A48137648E100003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A551376495900003422 /* getty.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A4B137648E100003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A5C13764F2E00003422 /* com.apple.getty.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A561376496100003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A571376498C00003422 /* gettytab.5 in CopyFiles */,
+ BA4B7A581376499000003422 /* ttys.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A6113765CC700003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A6813765D0000003422 /* hostinfo.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A6D13765D3E00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A7513765D6B00003422 /* iostat.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4B7A8B13765F3C00003422 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4B7A9513765FA100003422 /* latency.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4FD2ED1372FB3D0025925C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4FD2FD1372FD710025925C /* ac.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4FD3081372FFD80025925C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4FD30F137300040025925C /* accton.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4FD31E137300ED0025925C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4FD3261373012C0025925C /* arch.1 in CopyFiles */,
+ BA4FD3271373012F0025925C /* machine.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA4FD33C1373073E0025925C /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA4FD343137307580025925C /* at.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA91CE5E137F42ED00AE5160 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA91CE68137F438700AE5160 /* shutdown.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9B764713739ABE001BB39F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9B765013739B52001BB39F /* atrun.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9B765113739B6A001BB39F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /System/Library/LaunchDaemons;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9B765213739B7D001BB39F /* com.apple.atrun.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9B765D13739C20001BB39F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9B766C13739C84001BB39F /* chkpasswd.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9B76871373A0D8001BB39F /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9B76981373A1A7001BB39F /* chpass.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF48E139680CF0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF495139681050018C7BB /* sync.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF49B1396812D0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4A4139681710018C7BB /* sysctl.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4A21396815B0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4A31396816D0018C7BB /* sysctl.conf.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4AA139681910018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4B0139682430018C7BB /* trace.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4C2139682BA0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4C9139682E70018C7BB /* vifs.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4CE139682F80018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4D4139683140018C7BB /* vipw.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4DB139683580018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4E1139683890018C7BB /* vm_stat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4E7139683EB0018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4ED1396840C0018C7BB /* zdump.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BA9BF4F3139684B40018C7BB /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BA9BF4F9139684CF0018C7BB /* zic.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1CFC1377B2BD007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /private/etc/pam.d;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1CFE1377B2D8007728F4 /* login.term in CopyFiles */,
+ BA91CE58137D6CB800AE5160 /* login in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D411377B6E2007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D481377B723007728F4 /* mkfile.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D4E1377B7A7007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D581377B82A007728F4 /* newgrp.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D5D1377B85C007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D641377B894007728F4 /* nologin.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BACC1D651377B89A007728F4 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man5;
+ dstSubfolderSpec = 0;
+ files = (
+ BACC1D661377B8B2007728F4 /* nologin.5 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589A1137836A00049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589A9137836D60049DD3B /* nvram.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589B8137838C10049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589B9137838D10049DD3B /* pagesize.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589C91378FCAA0049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589D21378FD4D0049DD3B /* passwd.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589DF137902F50049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589E71379037A0049DD3B /* pwd_mkdb.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE589EC1379044E0049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE589F4137904C50049DD3B /* reboot.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE58A0D13799F610049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE58A1713799FA80049DD3B /* sa.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BAE58A4A137D69A60049DD3B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ BAE58A52137D69ED0049DD3B /* sc_usage.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ C20D8C671C1A102F00C1226B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ C21481451C1A131D003BCA63 /* gcore.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ C625B28616D6F27E00168EF7 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man8;
+ dstSubfolderSpec = 0;
+ files = (
+ C625B28D16D6F27E00168EF7 /* taskpolicy.8 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ C96F50B315BDCEC3008682F7 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ C96F50BD15BDFEFB008682F7 /* lsmp.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ C99490E22090F53B00246D9D /* Copy Lua library */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/share/recon;
+ dstSubfolderSpec = 0;
+ files = (
+ C99490E52090F56F00246D9D /* zprint.lua in Copy Lua library */,
+ );
+ name = "Copy Lua library";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ C9D64CD01B91064700CFA43B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /AppleInternal/CoreOS/BATS/unit_tests;
+ dstSubfolderSpec = 0;
+ files = (
+ C9D64CD11B91065D00CFA43B /* system_cmds.plist in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ C9D64CD21B91066B00CFA43B /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /AppleInternal/CoreOS/BATS/unit_tests;
+ dstSubfolderSpec = 0;
+ files = (
+ C9D64CD31B91067500CFA43B /* system_cmds.plist in CopyFiles */,
+ CEB165CC246C599A00228592 /* test_zprint.lua in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ CEB165CD246C599F00228592 /* Copy test */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /AppleInternal/Tests/system_cmds;
+ dstSubfolderSpec = 0;
+ files = (
+ CEB165CE246C59C100228592 /* test_zprint.lua in Copy test */,
+ );
+ name = "Copy test";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ F29F5A5E203E532B005B0099 /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/local/share/man/man1;
+ dstSubfolderSpec = 0;
+ files = (
+ F29F5A5F203E5347005B0099 /* zlog.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 08ADC98B1E70715D0001CB70 /* ktrace.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ktrace.framework; path = System/Library/PrivateFrameworks/ktrace.framework; sourceTree = SDKROOT; };
+ 08CE3D291E6E22A200DF1B78 /* stackshot */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = stackshot; sourceTree = BUILT_PRODUCTS_DIR; };
+ 08CE3D321E6E22DE00DF1B78 /* stackshot.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = stackshot.c; path = stackshot.tproj/stackshot.c; sourceTree = "<group>"; };
+ 08DC48851A12C21B008AAF38 /* kpgo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = kpgo; sourceTree = BUILT_PRODUCTS_DIR; };
+ 08DC488D1A12C2C6008AAF38 /* kpgo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = kpgo.c; sourceTree = "<group>"; };
+ 0D06BC5E1E8F08CB00C6EC2D /* mslutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mslutil; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0D06BC651E8F091F00C6EC2D /* mslutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mslutil.c; sourceTree = "<group>"; };
+ 0D06BC671E8F0B4100C6EC2D /* mslutil.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mslutil.1; sourceTree = "<group>"; };
+ 1523FE631595048900661E82 /* ltop */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ltop; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1523FE6A1595056C00661E82 /* ltop.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ltop.1; sourceTree = "<group>"; };
+ 1523FE6B1595056C00661E82 /* ltop.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ltop.c; sourceTree = "<group>"; };
+ 189337C21CC7CB4800B2A6A4 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+ 18EA07101C99C76C006D3005 /* EmbeddedOSSupportHost.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EmbeddedOSSupportHost.framework; path = System/Library/PrivateFrameworks/EmbeddedOSSupportHost.framework; sourceTree = SDKROOT; };
+ 3521C84D2245AA92001B3201 /* cpuctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cpuctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ 3521C8562245AB52001B3201 /* cpuctl.tproj */ = {isa = PBXFileReference; lastKnownFileType = folder; path = cpuctl.tproj; sourceTree = "<group>"; };
+ 358407CD2245AC09006A0D8E /* cpuctl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = cpuctl.c; path = cpuctl.tproj/cpuctl.c; sourceTree = "<group>"; };
+ 358407CF2245AC32006A0D8E /* cpuctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; name = cpuctl.8; path = cpuctl.tproj/cpuctl.8; sourceTree = "<group>"; };
+ 43A96C7223D2DAAE0033235B /* login.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = login.entitlements; sourceTree = "<group>"; };
+ 550C19E01804C55E001DA380 /* iosim.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = iosim.1; sourceTree = "<group>"; };
+ 550C19E11804C55E001DA380 /* iosim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = iosim.c; sourceTree = "<group>"; };
+ 550C19EB1804D226001DA380 /* iosim */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = iosim; sourceTree = BUILT_PRODUCTS_DIR; };
+ 55CCB16816B84ED100B56979 /* vm_purgeable_stat.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = vm_purgeable_stat.1; sourceTree = "<group>"; };
+ 55CCB16916B84ED100B56979 /* vm_purgeable_stat.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vm_purgeable_stat.c; sourceTree = "<group>"; };
+ 55CCB17316B84EDA00B56979 /* vm_purgeable_stat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vm_purgeable_stat; sourceTree = BUILT_PRODUCTS_DIR; };
+ 58775F6B2489B8AA0098F7DE /* com.apple.getty.internal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.getty.internal.plist; sourceTree = "<group>"; };
+ 58775F6D2489B8CE0098F7DE /* com.apple.serialdebugconsole.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.serialdebugconsole.plist; sourceTree = "<group>"; };
+ 72D1FDD818C4140600C1E05F /* task_details.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = task_details.c; path = lsmp.tproj/task_details.c; sourceTree = SOURCE_ROOT; };
+ 72F9316B18C269E500D804C5 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = common.h; path = lsmp.tproj/common.h; sourceTree = SOURCE_ROOT; };
+ 72F9316C18C26A8600D804C5 /* port_details.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = port_details.c; path = lsmp.tproj/port_details.c; sourceTree = SOURCE_ROOT; };
+ 78DE9DE01B5045DE00FE6DF5 /* wait4path */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wait4path; sourceTree = BUILT_PRODUCTS_DIR; };
+ 78DE9DFC1B504D7F00FE6DF5 /* wait4path.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wait4path.c; path = wait4path/wait4path.c; sourceTree = "<group>"; };
+ 78DE9DFD1B504D7F00FE6DF5 /* wait4path.version */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = wait4path.version; path = wait4path/wait4path.version; sourceTree = "<group>"; };
+ 78DE9EE51B505EBF00FE6DF5 /* wait4path.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = wait4path.1; path = wait4path/wait4path.1; sourceTree = "<group>"; };
+ 8EC391651C9733C2001E28E6 /* proc_uuid_policy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = proc_uuid_policy; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8EC391671C973400001E28E6 /* proc_uuid_policy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = proc_uuid_policy.c; path = proc_uuid_policy.tproj/proc_uuid_policy.c; sourceTree = SOURCE_ROOT; };
+ 8EC3916A1C97341E001E28E6 /* proc_uuid_policy.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = proc_uuid_policy.1; path = proc_uuid_policy.tproj/proc_uuid_policy.1; sourceTree = SOURCE_ROOT; };
+ 97999D2D1AE84C0E00E8B10F /* lskq */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lskq; sourceTree = BUILT_PRODUCTS_DIR; };
+ 97999D2F1AE84C7600E8B10F /* common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = common.h; path = lskq.tproj/common.h; sourceTree = "<group>"; };
+ 97999D301AE84C7600E8B10F /* lskq.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; name = lskq.1; path = lskq.tproj/lskq.1; sourceTree = "<group>"; };
+ 97999D311AE84C7600E8B10F /* lskq.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = lskq.c; path = lskq.tproj/lskq.c; sourceTree = "<group>"; };
+ A7C0927020EC491E0068148E /* passwd.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = passwd.entitlements; sourceTree = "<group>"; };
+ ADA9007717679A8C00161ADF /* purge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = purge; sourceTree = BUILT_PRODUCTS_DIR; };
+ ADA900791767A02700161ADF /* purge.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = purge.8; sourceTree = "<group>"; };
+ ADA9007A1767A02700161ADF /* purge.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = purge.c; sourceTree = "<group>"; };
+ B158E3A0185A836700474677 /* wordexp-helper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "wordexp-helper"; sourceTree = BUILT_PRODUCTS_DIR; };
+ B158E3A2185A836700474677 /* wordexp-helper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = "wordexp-helper.c"; sourceTree = "<group>"; };
+ B3C10B9316E983D4006896A0 /* memory_pressure.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = memory_pressure.1; sourceTree = "<group>"; };
+ B3F0E6D516E96FC2008FAD09 /* memory_pressure */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = memory_pressure; sourceTree = BUILT_PRODUCTS_DIR; };
+ B3F0E6DC16E9706E008FAD09 /* memory_pressure.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = memory_pressure.c; sourceTree = "<group>"; };
+ BA0A861013968E8500D2272C /* zprint */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zprint; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA28FB851396DA01004986CB /* private */ = {isa = PBXFileReference; lastKnownFileType = folder; path = private; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA28FB861396DA01004986CB /* zoneinfo */ = {isa = PBXFileReference; lastKnownFileType = folder; path = zoneinfo; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA473DB31377B2230005CC19 /* login */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = login; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B79BF1373A53700003422 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = "<absolute>"; };
+ BA4B79CD1373A72800003422 /* dmesg */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dmesg; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B79EC1373AF7A00003422 /* dynamic_pager */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dynamic_pager; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B79F31373B01B00003422 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = "<absolute>"; };
+ BA4B79FA1373B7C300003422 /* com.apple.dynamic_pager.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = com.apple.dynamic_pager.plist; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A051373B9E900003422 /* fs_usage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fs_usage; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A091373BA4600003422 /* libutil.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libutil.dylib; path = /usr/lib/libutil.dylib; sourceTree = "<absolute>"; };
+ BA4B7A161373BE9D00003422 /* getconf */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = getconf; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A241373C30100003422 /* confstr.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = confstr.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A251373C30100003422 /* limits.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = limits.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A261373C30100003422 /* pathconf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pathconf.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A271373C30100003422 /* progenv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = progenv.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A281373C30100003422 /* sysconf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = sysconf.c; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A4F137648E100003422 /* getty */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = getty; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A5B13764F1400003422 /* com.apple.getty.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = com.apple.getty.plist; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A6513765CC700003422 /* hostinfo */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = hostinfo; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A7113765D3E00003422 /* iostat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = iostat; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A7613765D7700003422 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
+ BA4B7A9013765F3C00003422 /* latency */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = latency; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4B7A9313765F8B00003422 /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = /usr/lib/libncurses.dylib; sourceTree = "<absolute>"; };
+ BA4FD1DB1372FAFA0025925C /* ac.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = ac.8; sourceTree = "<group>"; };
+ BA4FD1DC1372FAFA0025925C /* ac.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ac.c; sourceTree = "<group>"; };
+ BA4FD1DF1372FAFA0025925C /* accton.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = accton.8; sourceTree = "<group>"; };
+ BA4FD1E01372FAFA0025925C /* accton.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = accton.c; sourceTree = "<group>"; };
+ BA4FD1E11372FAFA0025925C /* APPLE_LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = APPLE_LICENSE; sourceTree = "<group>"; };
+ BA4FD1E41372FAFA0025925C /* arch.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = arch.1; sourceTree = "<group>"; };
+ BA4FD1E51372FAFA0025925C /* arch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = arch.c; sourceTree = "<group>"; };
+ BA4FD1E71372FAFA0025925C /* machine.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = machine.1; sourceTree = "<group>"; };
+ BA4FD1E91372FAFA0025925C /* LEGAL */ = {isa = PBXFileReference; lastKnownFileType = text; path = LEGAL; sourceTree = "<group>"; };
+ BA4FD1EB1372FAFA0025925C /* at.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = at.1; sourceTree = "<group>"; };
+ BA4FD1EC1372FAFA0025925C /* at.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = at.c; sourceTree = "<group>"; };
+ BA4FD1ED1372FAFA0025925C /* at.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = at.h; sourceTree = "<group>"; };
+ BA4FD1EE1372FAFA0025925C /* panic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = panic.c; sourceTree = "<group>"; };
+ BA4FD1EF1372FAFA0025925C /* panic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = panic.h; sourceTree = "<group>"; };
+ BA4FD1F01372FAFA0025925C /* parsetime.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = parsetime.c; sourceTree = "<group>"; };
+ BA4FD1F11372FAFA0025925C /* parsetime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = parsetime.h; sourceTree = "<group>"; };
+ BA4FD1F21372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD1F31372FAFA0025925C /* perm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = perm.c; sourceTree = "<group>"; };
+ BA4FD1F41372FAFA0025925C /* perm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = perm.h; sourceTree = "<group>"; };
+ BA4FD1F51372FAFA0025925C /* privs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = privs.h; sourceTree = "<group>"; };
+ BA4FD1F81372FAFA0025925C /* atrun.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = atrun.8; sourceTree = "<group>"; };
+ BA4FD1F91372FAFA0025925C /* atrun.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = atrun.c; sourceTree = "<group>"; };
+ BA4FD1FA1372FAFA0025925C /* atrun.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = atrun.h; sourceTree = "<group>"; };
+ BA4FD1FC1372FAFA0025925C /* com.apple.atrun.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.atrun.plist; sourceTree = "<group>"; };
+ BA4FD1FD1372FAFA0025925C /* gloadavg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gloadavg.c; sourceTree = "<group>"; };
+ BA4FD1FE1372FAFA0025925C /* gloadavg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gloadavg.h; sourceTree = "<group>"; };
+ BA4FD2011372FAFA0025925C /* chkpasswd.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = chkpasswd.8; sourceTree = "<group>"; };
+ BA4FD2021372FAFA0025925C /* chkpasswd.pam */ = {isa = PBXFileReference; lastKnownFileType = text; path = chkpasswd.pam; sourceTree = "<group>"; };
+ BA4FD2031372FAFA0025925C /* file_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = file_passwd.c; sourceTree = "<group>"; };
+ BA4FD2041372FAFA0025925C /* nis_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nis_passwd.c; sourceTree = "<group>"; };
+ BA4FD2051372FAFA0025925C /* od_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = od_passwd.c; sourceTree = "<group>"; };
+ BA4FD2061372FAFA0025925C /* pam_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pam_passwd.c; sourceTree = "<group>"; };
+ BA4FD2071372FAFA0025925C /* passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = passwd.c; sourceTree = "<group>"; };
+ BA4FD2081372FAFA0025925C /* stringops.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = stringops.c; sourceTree = "<group>"; };
+ BA4FD2091372FAFA0025925C /* stringops.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = stringops.h; sourceTree = "<group>"; };
+ BA4FD20B1372FAFA0025925C /* IMPORT_NOTES */ = {isa = PBXFileReference; lastKnownFileType = text; path = IMPORT_NOTES; sourceTree = "<group>"; };
+ BA4FD20D1372FAFA0025925C /* chpass.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = chpass.1; sourceTree = "<group>"; };
+ BA4FD20E1372FAFA0025925C /* chpass.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chpass.c; sourceTree = "<group>"; };
+ BA4FD20F1372FAFA0025925C /* chpass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = chpass.h; sourceTree = "<group>"; };
+ BA4FD2101372FAFA0025925C /* edit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = edit.c; sourceTree = "<group>"; };
+ BA4FD2111372FAFA0025925C /* field.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = field.c; sourceTree = "<group>"; };
+ BA4FD2121372FAFA0025925C /* open_directory.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = open_directory.c; sourceTree = "<group>"; };
+ BA4FD2131372FAFA0025925C /* open_directory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = open_directory.h; sourceTree = "<group>"; };
+ BA4FD2141372FAFA0025925C /* pw_copy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pw_copy.c; sourceTree = "<group>"; };
+ BA4FD2151372FAFA0025925C /* pw_copy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pw_copy.h; sourceTree = "<group>"; };
+ BA4FD2161372FAFA0025925C /* table.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = table.c; sourceTree = "<group>"; };
+ BA4FD2171372FAFA0025925C /* util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ BA4FD2201372FAFA0025925C /* dmesg.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = dmesg.8; sourceTree = "<group>"; };
+ BA4FD2211372FAFA0025925C /* dmesg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dmesg.c; sourceTree = "<group>"; };
+ BA4FD22A1372FAFA0025925C /* com.apple.dynamic_pager.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.dynamic_pager.plist; sourceTree = "<group>"; };
+ BA4FD22C1372FAFA0025925C /* dynamic_pager.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = dynamic_pager.8; sourceTree = "<group>"; };
+ BA4FD22D1372FAFA0025925C /* dynamic_pager.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dynamic_pager.c; sourceTree = "<group>"; };
+ BA4FD2301372FAFA0025925C /* fs_usage.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = fs_usage.1; sourceTree = "<group>"; };
+ BA4FD2311372FAFA0025925C /* fs_usage.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fs_usage.c; sourceTree = "<group>"; usesTabs = 1; };
+ BA4FD2351372FAFA0025925C /* confstr.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = confstr.gperf; sourceTree = "<group>"; };
+ BA4FD2361372FAFA0025925C /* fake-gperf.awk */ = {isa = PBXFileReference; lastKnownFileType = text; path = "fake-gperf.awk"; sourceTree = "<group>"; };
+ BA4FD2371372FAFA0025925C /* getconf.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = getconf.1; sourceTree = "<group>"; };
+ BA4FD2381372FAFA0025925C /* getconf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = getconf.c; sourceTree = "<group>"; };
+ BA4FD2391372FAFA0025925C /* getconf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = getconf.h; sourceTree = "<group>"; };
+ BA4FD23A1372FAFA0025925C /* limits.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = limits.gperf; sourceTree = "<group>"; };
+ BA4FD23B1372FAFA0025925C /* pathconf.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = pathconf.gperf; sourceTree = "<group>"; };
+ BA4FD23C1372FAFA0025925C /* progenv.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = progenv.gperf; sourceTree = "<group>"; };
+ BA4FD23D1372FAFA0025925C /* sysconf.gperf */ = {isa = PBXFileReference; lastKnownFileType = text; path = sysconf.gperf; sourceTree = "<group>"; };
+ BA4FD2401372FAFA0025925C /* chat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = chat.c; sourceTree = "<group>"; };
+ BA4FD2411372FAFA0025925C /* com.apple.getty.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.getty.plist; sourceTree = "<group>"; };
+ BA4FD2421372FAFA0025925C /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ BA4FD2431372FAFA0025925C /* getty.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = getty.8; sourceTree = "<group>"; };
+ BA4FD2441372FAFA0025925C /* gettytab.5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = gettytab.5; sourceTree = "<group>"; };
+ BA4FD2451372FAFA0025925C /* gettytab.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = gettytab.h; sourceTree = "<group>"; };
+ BA4FD2461372FAFA0025925C /* init.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = init.c; sourceTree = "<group>"; };
+ BA4FD2471372FAFA0025925C /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ BA4FD2481372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD2491372FAFA0025925C /* subr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = subr.c; sourceTree = "<group>"; };
+ BA4FD24A1372FAFA0025925C /* ttys.5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = ttys.5; sourceTree = "<group>"; };
+ BA4FD24D1372FAFA0025925C /* hostinfo.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = hostinfo.8; sourceTree = "<group>"; };
+ BA4FD24E1372FAFA0025925C /* hostinfo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hostinfo.c; sourceTree = "<group>"; };
+ BA4FD2521372FAFA0025925C /* iostat.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = iostat.8; sourceTree = "<group>"; };
+ BA4FD2531372FAFA0025925C /* iostat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = iostat.c; sourceTree = "<group>"; };
+ BA4FD2571372FAFA0025925C /* latency.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = latency.1; sourceTree = "<group>"; };
+ BA4FD2581372FAFA0025925C /* latency.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = latency.c; sourceTree = "<group>"; };
+ BA4FD25B1372FAFA0025925C /* klogin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = klogin.c; sourceTree = "<group>"; };
+ BA4FD25C1372FAFA0025925C /* login.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = login.1; sourceTree = "<group>"; };
+ BA4FD25D1372FAFA0025925C /* login.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = login.c; sourceTree = "<group>"; };
+ BA4FD25E1372FAFA0025925C /* login.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = login.h; sourceTree = "<group>"; };
+ BA4FD25F1372FAFA0025925C /* login_audit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = login_audit.c; sourceTree = "<group>"; };
+ BA4FD2611372FAFA0025925C /* login */ = {isa = PBXFileReference; lastKnownFileType = text; path = login; sourceTree = "<group>"; };
+ BA4FD2621372FAFA0025925C /* login.term */ = {isa = PBXFileReference; lastKnownFileType = text; path = login.term; sourceTree = "<group>"; };
+ BA4FD2631372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD26B1372FAFA0025925C /* mean.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mean.c; sourceTree = "<group>"; };
+ BA4FD26E1372FAFA0025925C /* mkfile.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = mkfile.8; sourceTree = "<group>"; };
+ BA4FD26F1372FAFA0025925C /* mkfile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mkfile.c; sourceTree = "<group>"; };
+ BA4FD2721372FAFA0025925C /* newgrp.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = newgrp.1; sourceTree = "<group>"; };
+ BA4FD2731372FAFA0025925C /* newgrp.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = newgrp.c; sourceTree = "<group>"; };
+ BA4FD2761372FAFA0025925C /* nologin.5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = nologin.5; sourceTree = "<group>"; };
+ BA4FD2771372FAFA0025925C /* nologin.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = nologin.8; sourceTree = "<group>"; };
+ BA4FD2781372FAFA0025925C /* nologin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nologin.c; sourceTree = "<group>"; };
+ BA4FD27B1372FAFA0025925C /* nvram.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = nvram.8; sourceTree = "<group>"; };
+ BA4FD27C1372FAFA0025925C /* nvram.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nvram.c; sourceTree = "<group>"; };
+ BA4FD27F1372FAFA0025925C /* pagesize.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = pagesize.1; sourceTree = "<group>"; };
+ BA4FD2801372FAFA0025925C /* pagesize.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = pagesize.sh; sourceTree = "<group>"; };
+ BA4FD2831372FAFA0025925C /* file_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = file_passwd.c; sourceTree = "<group>"; };
+ BA4FD2841372FAFA0025925C /* nis_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nis_passwd.c; sourceTree = "<group>"; };
+ BA4FD2851372FAFA0025925C /* od_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = od_passwd.c; sourceTree = "<group>"; };
+ BA4FD2861372FAFA0025925C /* pam_passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pam_passwd.c; sourceTree = "<group>"; };
+ BA4FD2871372FAFA0025925C /* passwd.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = passwd.1; sourceTree = "<group>"; };
+ BA4FD2881372FAFA0025925C /* passwd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = passwd.c; sourceTree = "<group>"; };
+ BA4FD2891372FAFA0025925C /* passwd.pam */ = {isa = PBXFileReference; lastKnownFileType = text; path = passwd.pam; sourceTree = "<group>"; };
+ BA4FD28C1372FAFA0025925C /* pw_scan.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pw_scan.c; sourceTree = "<group>"; };
+ BA4FD28D1372FAFA0025925C /* pw_scan.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pw_scan.h; sourceTree = "<group>"; };
+ BA4FD28E1372FAFA0025925C /* pwd_mkdb.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pwd_mkdb.8; sourceTree = "<group>"; };
+ BA4FD28F1372FAFA0025925C /* pwd_mkdb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pwd_mkdb.c; sourceTree = "<group>"; };
+ BA4FD2921372FAFA0025925C /* kextmanager.defs */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.mig; path = kextmanager.defs; sourceTree = "<group>"; };
+ BA4FD2931372FAFA0025925C /* reboot.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = reboot.8; sourceTree = "<group>"; };
+ BA4FD2941372FAFA0025925C /* reboot.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = reboot.c; sourceTree = "<group>"; };
+ BA4FD2971372FAFA0025925C /* db.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = db.c; sourceTree = "<group>"; };
+ BA4FD2981372FAFA0025925C /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ BA4FD2991372FAFA0025925C /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ BA4FD29A1372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD29B1372FAFA0025925C /* pdb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pdb.c; sourceTree = "<group>"; };
+ BA4FD29C1372FAFA0025925C /* sa.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sa.8; sourceTree = "<group>"; };
+ BA4FD29D1372FAFA0025925C /* usrdb.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = usrdb.c; sourceTree = "<group>"; };
+ BA4FD2AE1372FAFA0025925C /* sc_usage.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = sc_usage.1; sourceTree = "<group>"; };
+ BA4FD2AF1372FAFA0025925C /* sc_usage.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sc_usage.c; sourceTree = "<group>"; };
+ BA4FD2B21372FAFA0025925C /* kextmanager.defs */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.mig; path = kextmanager.defs; sourceTree = "<group>"; };
+ BA4FD2B31372FAFA0025925C /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ BA4FD2B41372FAFA0025925C /* shutdown.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = shutdown.8; sourceTree = "<group>"; };
+ BA4FD2B51372FAFA0025925C /* shutdown.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = shutdown.c; sourceTree = "<group>"; };
+ BA4FD2B81372FAFA0025925C /* sync.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sync.8; sourceTree = "<group>"; };
+ BA4FD2B91372FAFA0025925C /* sync.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sync.c; sourceTree = "<group>"; };
+ BA4FD2BC1372FAFA0025925C /* sysctl.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sysctl.8; sourceTree = "<group>"; };
+ BA4FD2BD1372FAFA0025925C /* sysctl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sysctl.c; sourceTree = "<group>"; };
+ BA4FD2BE1372FAFA0025925C /* sysctl.conf.5 */ = {isa = PBXFileReference; lastKnownFileType = text; path = sysctl.conf.5; sourceTree = "<group>"; };
+ BA4FD2C11372FAFA0025925C /* trace.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = trace.1; sourceTree = "<group>"; };
+ BA4FD2C21372FAFA0025925C /* trace.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = trace.c; sourceTree = "<group>"; };
+ BA4FD2C51372FAFA0025925C /* vifs.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = vifs.8; sourceTree = "<group>"; };
+ BA4FD2C61372FAFA0025925C /* vifs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vifs.c; sourceTree = "<group>"; };
+ BA4FD2C91372FAFA0025925C /* pw_util.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pw_util.c; sourceTree = "<group>"; };
+ BA4FD2CA1372FAFA0025925C /* pw_util.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pw_util.h; sourceTree = "<group>"; };
+ BA4FD2CB1372FAFA0025925C /* vipw.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = vipw.8; sourceTree = "<group>"; };
+ BA4FD2CC1372FAFA0025925C /* vipw.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vipw.c; sourceTree = "<group>"; };
+ BA4FD2CF1372FAFA0025925C /* vm_stat.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = vm_stat.1; sourceTree = "<group>"; };
+ BA4FD2D01372FAFA0025925C /* vm_stat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vm_stat.c; sourceTree = "<group>"; };
+ BA4FD2D31372FAFA0025925C /* zdump.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = zdump.8; sourceTree = "<group>"; };
+ BA4FD2D41372FAFA0025925C /* zdump.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zdump.c; sourceTree = "<group>"; };
+ BA4FD2D61372FAFA0025925C /* Arts.htm */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = Arts.htm; sourceTree = "<group>"; };
+ BA4FD2D81372FAFA0025925C /* Makefile.zoneinfo.dist */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.zoneinfo.dist; sourceTree = "<group>"; };
+ BA4FD2D91372FAFA0025925C /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ BA4FD2DA1372FAFA0025925C /* Theory */ = {isa = PBXFileReference; lastKnownFileType = text; path = Theory; sourceTree = "<group>"; };
+ BA4FD2DB1372FAFA0025925C /* ZIC_HACK */ = {isa = PBXFileReference; lastKnownFileType = text; path = ZIC_HACK; sourceTree = "<group>"; };
+ BA4FD2DC1372FAFA0025925C /* ialloc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ialloc.c; sourceTree = "<group>"; };
+ BA4FD2DD1372FAFA0025925C /* private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = private.h; sourceTree = "<group>"; };
+ BA4FD2DE1372FAFA0025925C /* scheck.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = scheck.c; sourceTree = "<group>"; };
+ BA4FD2DF1372FAFA0025925C /* tz-art.htm */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "tz-art.htm"; sourceTree = "<group>"; };
+ BA4FD2E01372FAFA0025925C /* tz-link.htm */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "tz-link.htm"; sourceTree = "<group>"; };
+ BA4FD2E11372FAFA0025925C /* zic.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = zic.8; sourceTree = "<group>"; };
+ BA4FD2E21372FAFA0025925C /* zic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zic.c; sourceTree = "<group>"; };
+ BA4FD2E51372FAFA0025925C /* zprint.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = zprint.1; sourceTree = "<group>"; };
+ BA4FD2E61372FAFA0025925C /* zprint.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zprint.c; sourceTree = "<group>"; };
+ BA4FD2EF1372FB3D0025925C /* ac */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ac; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4FD30D1372FFD80025925C /* accton */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = accton; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4FD323137300EE0025925C /* arch */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = arch; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA4FD3411373073E0025925C /* at */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = at; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA91CE62137F42ED00AE5160 /* shutdown */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = shutdown; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA959E8413968CF900CA9C60 /* generate_zoneinfo.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = generate_zoneinfo.sh; sourceTree = "<group>"; };
+ BA9B764C13739ABE001BB39F /* atrun */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = atrun; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9B766313739C20001BB39F /* chkpasswd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chkpasswd; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9B766D13739D27001BB39F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
+ BA9B766E13739D27001BB39F /* OpenDirectory.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenDirectory.framework; path = /System/Library/Frameworks/OpenDirectory.framework; sourceTree = "<absolute>"; };
+ BA9B767113739D36001BB39F /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = /usr/lib/libpam.dylib; sourceTree = "<absolute>"; };
+ BA9B767613739E9E001BB39F /* chkpasswd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chkpasswd.h; sourceTree = "<group>"; };
+ BA9B768C1373A0D8001BB39F /* chpass */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = chpass; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF492139680CF0018C7BB /* sync */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sync; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF49F1396812D0018C7BB /* sysctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sysctl; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4AE139681910018C7BB /* trace */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = trace; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4C6139682BA0018C7BB /* vifs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vifs; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4D2139682F80018C7BB /* vipw */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vipw; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4DF139683580018C7BB /* vm_stat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vm_stat; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4EB139683EB0018C7BB /* zdump */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zdump; sourceTree = BUILT_PRODUCTS_DIR; };
+ BA9BF4F7139684B40018C7BB /* zic */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zic; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D151377B481007728F4 /* mean */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mean; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D451377B6E2007728F4 /* mkfile */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mkfile; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D551377B7A7007728F4 /* newgrp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = newgrp; sourceTree = BUILT_PRODUCTS_DIR; };
+ BACC1D611377B85C007728F4 /* nologin */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nologin; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE589A5137836A00049DD3B /* nvram */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nvram; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE589CE1378FCAA0049DD3B /* passwd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = passwd; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE589D71378FE8D0049DD3B /* passwd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = passwd.h; sourceTree = "<group>"; };
+ BAE589E3137902F50049DD3B /* pwd_mkdb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pwd_mkdb; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE589F01379044E0049DD3B /* reboot */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = reboot; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE58A1113799F610049DD3B /* sa */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sa; sourceTree = BUILT_PRODUCTS_DIR; };
+ BAE58A4E137D69A60049DD3B /* sc_usage */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sc_usage; sourceTree = BUILT_PRODUCTS_DIR; };
+ C20D8C691C1A102F00C1226B /* gcore */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gcore; sourceTree = BUILT_PRODUCTS_DIR; };
+ C214810D1C1A11E6003BCA63 /* corefile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = corefile.c; path = gcore.tproj/corefile.c; sourceTree = "<group>"; };
+ C214810E1C1A11E6003BCA63 /* corefile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = corefile.h; path = gcore.tproj/corefile.h; sourceTree = "<group>"; };
+ C214810F1C1A11E6003BCA63 /* dyld_shared_cache.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dyld_shared_cache.c; path = gcore.tproj/dyld_shared_cache.c; sourceTree = "<group>"; };
+ C21481101C1A11E6003BCA63 /* dyld_shared_cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dyld_shared_cache.h; path = gcore.tproj/dyld_shared_cache.h; sourceTree = "<group>"; };
+ C21481111C1A11E6003BCA63 /* dyld.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dyld.c; path = gcore.tproj/dyld.c; sourceTree = "<group>"; };
+ C21481121C1A11E6003BCA63 /* dyld.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dyld.h; path = gcore.tproj/dyld.h; sourceTree = "<group>"; };
+ C21481131C1A11E6003BCA63 /* gcore.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = gcore.1; path = gcore.tproj/gcore.1; sourceTree = "<group>"; };
+ C21481141C1A11E6003BCA63 /* loader_additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = loader_additions.h; path = gcore.tproj/loader_additions.h; sourceTree = "<group>"; };
+ C21481151C1A11E6003BCA63 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = gcore.tproj/main.c; sourceTree = "<group>"; };
+ C21481161C1A11E6003BCA63 /* options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = options.h; path = gcore.tproj/options.h; sourceTree = "<group>"; };
+ C21481171C1A11E6003BCA63 /* region.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = region.h; path = gcore.tproj/region.h; sourceTree = "<group>"; };
+ C21481181C1A11E6003BCA63 /* sparse.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = sparse.c; path = gcore.tproj/sparse.c; sourceTree = "<group>"; };
+ C21481191C1A11E6003BCA63 /* sparse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sparse.h; path = gcore.tproj/sparse.h; sourceTree = "<group>"; };
+ C214811A1C1A11E7003BCA63 /* threads.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = threads.c; path = gcore.tproj/threads.c; sourceTree = "<group>"; };
+ C214811B1C1A11E7003BCA63 /* threads.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = threads.h; path = gcore.tproj/threads.h; sourceTree = "<group>"; };
+ C214811C1C1A11E7003BCA63 /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utils.c; path = gcore.tproj/utils.c; sourceTree = "<group>"; };
+ C214811D1C1A11E7003BCA63 /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = utils.h; path = gcore.tproj/utils.h; sourceTree = "<group>"; };
+ C214811E1C1A11E7003BCA63 /* vanilla.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vanilla.c; path = gcore.tproj/vanilla.c; sourceTree = "<group>"; };
+ C214811F1C1A11E7003BCA63 /* vanilla.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vanilla.h; path = gcore.tproj/vanilla.h; sourceTree = "<group>"; };
+ C21481201C1A11E7003BCA63 /* vm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = vm.c; path = gcore.tproj/vm.c; sourceTree = "<group>"; };
+ C21481211C1A11E7003BCA63 /* vm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = vm.h; path = gcore.tproj/vm.h; sourceTree = "<group>"; };
+ C248DBAF1C1A1D0500F6E9AF /* libcompression.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcompression.dylib; path = /usr/lib/libcompression.dylib; sourceTree = "<absolute>"; };
+ C2DAA9491D9F22BF00FAC263 /* gcore-internal.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = "gcore-internal.1"; path = "gcore.tproj/gcore-internal.1"; sourceTree = "<group>"; };
+ C2DAA94A1D9F22BF00FAC263 /* convert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = convert.h; path = gcore.tproj/convert.h; sourceTree = "<group>"; };
+ C2DAA94B1D9F22BF00FAC263 /* convert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = convert.c; path = gcore.tproj/convert.c; sourceTree = "<group>"; };
+ C625B28816D6F27E00168EF7 /* taskpolicy */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = taskpolicy; sourceTree = BUILT_PRODUCTS_DIR; };
+ C625B28A16D6F27E00168EF7 /* taskpolicy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = taskpolicy.c; sourceTree = "<group>"; };
+ C625B28C16D6F27E00168EF7 /* taskpolicy.8 */ = {isa = PBXFileReference; lastKnownFileType = text; path = taskpolicy.8; sourceTree = "<group>"; };
+ C913CA2E2228B622000051A0 /* base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = base.xcconfig; sourceTree = "<group>"; };
+ C96F50AC15BDCBF0008682F7 /* lsmp.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; name = lsmp.1; path = lsmp.tproj/lsmp.1; sourceTree = SOURCE_ROOT; };
+ C96F50AD15BDCE8E008682F7 /* lsmp.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = lsmp.c; path = lsmp.tproj/lsmp.c; sourceTree = SOURCE_ROOT; };
+ C96F50B715BDCEC3008682F7 /* lsmp */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lsmp; sourceTree = BUILT_PRODUCTS_DIR; };
+ C99490E32090F55D00246D9D /* zprint.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = zprint.lua; sourceTree = "<group>"; };
+ C9D64CCF1B91063200CFA43B /* system_cmds.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = system_cmds.plist; path = tests/system_cmds.plist; sourceTree = "<group>"; };
+ C9E0691B1C58BDA000C956EB /* CoreSymbolication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreSymbolication.framework; path = System/Library/PrivateFrameworks/CoreSymbolication.framework; sourceTree = SDKROOT; };
+ C9E0691D1C58BDB800C956EB /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
+ CEB165CB246C599A00228592 /* test_zprint.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = test_zprint.lua; sourceTree = "<group>"; };
+ F2291F5D1FFEBB6A00161936 /* zlog */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zlog; sourceTree = BUILT_PRODUCTS_DIR; };
+ F2291F5F1FFEBB9E00161936 /* zlog.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = zlog.c; sourceTree = "<group>"; };
+ F27B70272044CB40003C04FC /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.0.Internal.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
+ F27B70292045038B003C04FC /* SymbolicationHelper.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SymbolicationHelper.c; sourceTree = "<group>"; };
+ F27B702A2045038B003C04FC /* SymbolicationHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SymbolicationHelper.h; sourceTree = "<group>"; };
+ F29F5A5A203E12BB005B0099 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
+ F29F5A5C203E4403005B0099 /* zlog.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = zlog.1; sourceTree = "<group>"; };
+ FEBEE5CF1B0EACEB00166A8B /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 08CE3D261E6E22A200DF1B78 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 08DC48821A12C21B008AAF38 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 0D06BC5B1E8F08CB00C6EC2D /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 1523FE5D1595048900661E82 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C9779F6E159A2A0C009436FD /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 3521C84A2245AA92001B3201 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 550C19E51804D226001DA380 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5262264221ED5A780053ABA1 /* IOKit.framework in Frameworks */,
+ 5262264121E8295A0053ABA1 /* CoreFoundation.framework in Frameworks */,
+ 550C19E61804D226001DA380 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 55CCB16D16B84EDA00B56979 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 55CCB16E16B84EDA00B56979 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 78DE9DDD1B5045DE00FE6DF5 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8EC3915E1C9733C2001E28E6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97999D261AE84C0E00E8B10F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ADA9007217679A8C00161ADF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B158E39D185A836700474677 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B3F0E6CF16E96FC2008FAD09 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B3F0E6D016E96FC2008FAD09 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA0A860A13968E8500D2272C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C9E0691E1C58BDB800C956EB /* IOKit.framework in Frameworks */,
+ C9E0691C1C58BDA000C956EB /* CoreSymbolication.framework in Frameworks */,
+ C9E0691A1C58BD7E00C956EB /* CoreFoundation.framework in Frameworks */,
+ BA0A860B13968E8500D2272C /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA473DAD1377B2230005CC19 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79C81373A72800003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79E41373AF7A00003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79F41373B01C00003422 /* SystemConfiguration.framework in Frameworks */,
+ BA4B79F21373B01100003422 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A001373B9E900003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 08ADC98C1E70715D0001CB70 /* ktrace.framework in Frameworks */,
+ BA4B7A0A1373BA4600003422 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A111373BE9D00003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A45137648E100003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A6013765CC700003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A6C13765D3E00003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A7713765D7700003422 /* IOKit.framework in Frameworks */,
+ BA4B7A7813765DB100003422 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A8A13765F3C00003422 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A9413765F8C00003422 /* libncurses.dylib in Frameworks */,
+ BA4B7A9613765FE700003422 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD2EC1372FB3D0025925C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD3071372FFD80025925C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD31D137300ED0025925C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C65BF57A144BD7C5009028A3 /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD33B1373073E0025925C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA91CE5D137F42ED00AE5160 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA91CE67137F434200AE5160 /* libbsm.dylib in Frameworks */,
+ BA91CE66137F433200AE5160 /* IOKit.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B764613739ABE001BB39F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B765C13739C20001BB39F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B767213739D36001BB39F /* libpam.dylib in Frameworks */,
+ BA9B766F13739D27001BB39F /* CoreFoundation.framework in Frameworks */,
+ BA9B767013739D27001BB39F /* OpenDirectory.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B76831373A0D8001BB39F /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B76851373A0D8001BB39F /* CoreFoundation.framework in Frameworks */,
+ BA9B76861373A0D8001BB39F /* OpenDirectory.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF48D139680CF0018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF49A1396812D0018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4A8139681910018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4A9139681910018C7BB /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4C1139682BA0018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4CD139682F80018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4DA139683580018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4E6139683EB0018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4F2139684B40018C7BB /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D101377B481007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D401377B6E2007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D4D1377B7A7007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D5C1377B85C007728F4 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE5899E137836A00049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE5899F137836A00049DD3B /* IOKit.framework in Frameworks */,
+ BAE589A0137836A00049DD3B /* CoreFoundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589C51378FCAA0049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589DE137902F50049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589EB1379044E0049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A0C13799F610049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A48137D69A60049DD3B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A49137D69A60049DD3B /* libutil.dylib in Frameworks */,
+ BAE58A51137D69E30049DD3B /* libncurses.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C20D8C661C1A102F00C1226B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C20138731C1A17D0008EE53F /* libutil.dylib in Frameworks */,
+ C248DBB01C1A1D0500F6E9AF /* libcompression.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C625B28516D6F27E00168EF7 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C96F50B115BDCEC3008682F7 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C96F50B215BDCEC3008682F7 /* libutil.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F2291F531FFEBB6A00161936 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F27B70282044CB40003C04FC /* CoreFoundation.framework in Frameworks */,
+ F2291F551FFEBB6A00161936 /* CoreSymbolication.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08DC488C1A12C2C5008AAF38 /* kpgo.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 08DC488D1A12C2C6008AAF38 /* kpgo.c */,
+ );
+ path = kpgo.tproj;
+ sourceTree = "<group>";
+ };
+ 0D06BC5F1E8F08CB00C6EC2D /* mslutil */ = {
+ isa = PBXGroup;
+ children = (
+ 0D06BC651E8F091F00C6EC2D /* mslutil.c */,
+ 0D06BC671E8F0B4100C6EC2D /* mslutil.1 */,
+ );
+ path = mslutil;
+ sourceTree = "<group>";
+ };
+ 1523FE691595056C00661E82 /* ltop.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 1523FE6A1595056C00661E82 /* ltop.1 */,
+ 1523FE6B1595056C00661E82 /* ltop.c */,
+ );
+ path = ltop.tproj;
+ sourceTree = "<group>";
+ };
+ 189337C11CC7CB4800B2A6A4 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ F27B70272044CB40003C04FC /* CoreFoundation.framework */,
+ 08ADC98B1E70715D0001CB70 /* ktrace.framework */,
+ 189337C21CC7CB4800B2A6A4 /* CoreFoundation.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 3F56BF751F56057800266763 /* Recovered References */ = {
+ isa = PBXGroup;
+ children = (
+ C248DBAF1C1A1D0500F6E9AF /* libcompression.dylib */,
+ );
+ name = "Recovered References";
+ sourceTree = "<group>";
+ };
+ 550C19DF1804C55E001DA380 /* iosim.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 550C19E01804C55E001DA380 /* iosim.1 */,
+ 550C19E11804C55E001DA380 /* iosim.c */,
+ );
+ path = iosim.tproj;
+ sourceTree = "<group>";
+ };
+ 55CCB16716B84ED100B56979 /* vm_purgeable_stat.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 55CCB16816B84ED100B56979 /* vm_purgeable_stat.1 */,
+ 55CCB16916B84ED100B56979 /* vm_purgeable_stat.c */,
+ );
+ path = vm_purgeable_stat.tproj;
+ sourceTree = "<group>";
+ };
+ 78DE9DFB1B504D3300FE6DF5 /* wait4path */ = {
+ isa = PBXGroup;
+ children = (
+ 78DE9EE51B505EBF00FE6DF5 /* wait4path.1 */,
+ 78DE9DFC1B504D7F00FE6DF5 /* wait4path.c */,
+ 78DE9DFD1B504D7F00FE6DF5 /* wait4path.version */,
+ );
+ name = wait4path;
+ sourceTree = "<group>";
+ };
+ 8EC391661C9733EC001E28E6 /* proc_uuid_policy.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 8EC3916A1C97341E001E28E6 /* proc_uuid_policy.1 */,
+ 8EC391671C973400001E28E6 /* proc_uuid_policy.c */,
+ );
+ name = proc_uuid_policy.tproj;
+ path = passwd.tproj;
+ sourceTree = "<group>";
+ };
+ 97999D2E1AE84C5700E8B10F /* lskq.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 97999D2F1AE84C7600E8B10F /* common.h */,
+ 97999D301AE84C7600E8B10F /* lskq.1 */,
+ 97999D311AE84C7600E8B10F /* lskq.c */,
+ );
+ name = lskq.tproj;
+ sourceTree = "<group>";
+ };
+ ADA900781767A02700161ADF /* purge.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ ADA900791767A02700161ADF /* purge.8 */,
+ ADA9007A1767A02700161ADF /* purge.c */,
+ );
+ path = purge.tproj;
+ sourceTree = "<group>";
+ };
+ B158E3A1185A836700474677 /* wordexp-helper.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ B158E3A2185A836700474677 /* wordexp-helper.c */,
+ );
+ path = "wordexp-helper.tproj";
+ sourceTree = "<group>";
+ };
+ B3F0E6DA16E9706E008FAD09 /* memory_pressure.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ B3C10B9316E983D4006896A0 /* memory_pressure.1 */,
+ B3F0E6DC16E9706E008FAD09 /* memory_pressure.c */,
+ );
+ path = memory_pressure.tproj;
+ sourceTree = "<group>";
+ };
+ BA0A86491396D3CE00D2272C /* Generated zoneinfo Files */ = {
+ isa = PBXGroup;
+ children = (
+ BA28FB851396DA01004986CB /* private */,
+ BA28FB861396DA01004986CB /* zoneinfo */,
+ );
+ name = "Generated zoneinfo Files";
+ sourceTree = "<group>";
+ };
+ BA2DE9161372FA9100D1913C = {
+ isa = PBXGroup;
+ children = (
+ 358407CF2245AC32006A0D8E /* cpuctl.8 */,
+ 358407CD2245AC09006A0D8E /* cpuctl.c */,
+ 3521C8562245AB52001B3201 /* cpuctl.tproj */,
+ C913CA2E2228B622000051A0 /* base.xcconfig */,
+ 08CE3D321E6E22DE00DF1B78 /* stackshot.c */,
+ 18EA07101C99C76C006D3005 /* EmbeddedOSSupportHost.framework */,
+ BA4FD1E11372FAFA0025925C /* APPLE_LICENSE */,
+ C9D64CCF1B91063200CFA43B /* system_cmds.plist */,
+ BA4FD1D91372FAFA0025925C /* ac.tproj */,
+ BA4FD1DD1372FAFA0025925C /* accton.tproj */,
+ BA4FD1E21372FAFA0025925C /* arch.tproj */,
+ BA4FD1E81372FAFA0025925C /* at.tproj */,
+ BA4FD1F61372FAFA0025925C /* atrun.tproj */,
+ BA4FD1FF1372FAFA0025925C /* chkpasswd.tproj */,
+ BA4FD20A1372FAFA0025925C /* chpass.tproj */,
+ BA4FD21E1372FAFA0025925C /* dmesg.tproj */,
+ BA4FD2261372FAFA0025925C /* dynamic_pager.tproj */,
+ BA4FD22E1372FAFA0025925C /* fs_usage.tproj */,
+ C21481371C1A11F0003BCA63 /* gcore.tproj */,
+ BA4FD2321372FAFA0025925C /* getconf.tproj */,
+ BA4FD23E1372FAFA0025925C /* getty.tproj */,
+ BA4FD24B1372FAFA0025925C /* hostinfo.tproj */,
+ 550C19DF1804C55E001DA380 /* iosim.tproj */,
+ BA4FD24F1372FAFA0025925C /* iostat.tproj */,
+ 08DC488C1A12C2C5008AAF38 /* kpgo.tproj */,
+ BA4FD2551372FAFA0025925C /* latency.tproj */,
+ BA4FD2591372FAFA0025925C /* login.tproj */,
+ 97999D2E1AE84C5700E8B10F /* lskq.tproj */,
+ C96F50AA15BDCBA2008682F7 /* lsmp.tproj */,
+ 1523FE691595056C00661E82 /* ltop.tproj */,
+ BA4FD2691372FAFA0025925C /* mean.tproj */,
+ B3F0E6DA16E9706E008FAD09 /* memory_pressure.tproj */,
+ BA4FD26C1372FAFA0025925C /* mkfile.tproj */,
+ 0D06BC5F1E8F08CB00C6EC2D /* mslutil */,
+ BA4FD2701372FAFA0025925C /* newgrp.tproj */,
+ BA4FD2741372FAFA0025925C /* nologin.tproj */,
+ BA4FD2791372FAFA0025925C /* nvram.tproj */,
+ BA4FD27D1372FAFA0025925C /* pagesize.tproj */,
+ BA4FD2811372FAFA0025925C /* passwd.tproj */,
+ 8EC391661C9733EC001E28E6 /* proc_uuid_policy.tproj */,
+ ADA900781767A02700161ADF /* purge.tproj */,
+ BA4FD28A1372FAFA0025925C /* pwd_mkdb.tproj */,
+ BA4FD2901372FAFA0025925C /* reboot.tproj */,
+ BA4FD2951372FAFA0025925C /* sa.tproj */,
+ BA4FD2AC1372FAFA0025925C /* sc_usage.tproj */,
+ BA4FD2B01372FAFA0025925C /* shutdown.tproj */,
+ BA4FD2B61372FAFA0025925C /* sync.tproj */,
+ BA4FD2BA1372FAFA0025925C /* sysctl.tproj */,
+ C625B28916D6F27E00168EF7 /* taskpolicy.tproj */,
+ BA4FD2BF1372FAFA0025925C /* trace.tproj */,
+ BA4FD2C31372FAFA0025925C /* vifs.tproj */,
+ BA4FD2C71372FAFA0025925C /* vipw.tproj */,
+ 55CCB16716B84ED100B56979 /* vm_purgeable_stat.tproj */,
+ BA4FD2CD1372FAFA0025925C /* vm_stat.tproj */,
+ 78DE9DFB1B504D3300FE6DF5 /* wait4path */,
+ B158E3A1185A836700474677 /* wordexp-helper.tproj */,
+ BA4FD2D11372FAFA0025925C /* zdump.tproj */,
+ BA4FD2D51372FAFA0025925C /* zic.tproj */,
+ F2291F5E1FFEBB8500161936 /* zlog.tproj */,
+ BA4FD2E31372FAFA0025925C /* zprint.tproj */,
+ BA4B7A0D1373BBB600003422 /* Libraries */,
+ BA4FD2F01372FB3D0025925C /* Products */,
+ 189337C11CC7CB4800B2A6A4 /* Frameworks */,
+ 3F56BF751F56057800266763 /* Recovered References */,
+ );
+ sourceTree = "<group>";
+ };
+ BA4B79FB1373B7ED00003422 /* Processed LaunchDaemon plist */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B79FA1373B7C300003422 /* com.apple.dynamic_pager.plist */,
+ );
+ name = "Processed LaunchDaemon plist";
+ sourceTree = "<group>";
+ };
+ BA4B7A0D1373BBB600003422 /* Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B79BF1373A53700003422 /* libbsm.dylib */,
+ BA4B7A9313765F8B00003422 /* libncurses.dylib */,
+ BA4B7A091373BA4600003422 /* libutil.dylib */,
+ BA9B767113739D36001BB39F /* libpam.dylib */,
+ C9E0691D1C58BDB800C956EB /* IOKit.framework */,
+ C9E0691B1C58BDA000C956EB /* CoreSymbolication.framework */,
+ BA9B766D13739D27001BB39F /* CoreFoundation.framework */,
+ BA4B79F31373B01B00003422 /* SystemConfiguration.framework */,
+ BA9B766E13739D27001BB39F /* OpenDirectory.framework */,
+ BA4B7A7613765D7700003422 /* IOKit.framework */,
+ );
+ name = Libraries;
+ sourceTree = "<group>";
+ };
+ BA4B7A231373C2DC00003422 /* Generated Source */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B7A241373C30100003422 /* confstr.c */,
+ BA4B7A251373C30100003422 /* limits.c */,
+ BA4B7A261373C30100003422 /* pathconf.c */,
+ BA4B7A271373C30100003422 /* progenv.c */,
+ BA4B7A281373C30100003422 /* sysconf.c */,
+ );
+ name = "Generated Source";
+ sourceTree = "<group>";
+ };
+ BA4B7A3D1375189E00003422 /* Processed LaunchDaemon plist */ = {
+ isa = PBXGroup;
+ children = (
+ BA4B7A5B13764F1400003422 /* com.apple.getty.plist */,
+ );
+ name = "Processed LaunchDaemon plist";
+ sourceTree = "<group>";
+ };
+ BA4FD1D91372FAFA0025925C /* ac.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1DB1372FAFA0025925C /* ac.8 */,
+ BA4FD1DC1372FAFA0025925C /* ac.c */,
+ );
+ path = ac.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1DD1372FAFA0025925C /* accton.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1DF1372FAFA0025925C /* accton.8 */,
+ BA4FD1E01372FAFA0025925C /* accton.c */,
+ );
+ path = accton.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1E21372FAFA0025925C /* arch.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1E41372FAFA0025925C /* arch.1 */,
+ BA4FD1E51372FAFA0025925C /* arch.c */,
+ BA4FD1E71372FAFA0025925C /* machine.1 */,
+ );
+ path = arch.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1E81372FAFA0025925C /* at.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1E91372FAFA0025925C /* LEGAL */,
+ BA4FD1EB1372FAFA0025925C /* at.1 */,
+ BA4FD1EC1372FAFA0025925C /* at.c */,
+ BA4FD1ED1372FAFA0025925C /* at.h */,
+ BA4FD1EE1372FAFA0025925C /* panic.c */,
+ BA4FD1EF1372FAFA0025925C /* panic.h */,
+ BA4FD1F01372FAFA0025925C /* parsetime.c */,
+ BA4FD1F11372FAFA0025925C /* parsetime.h */,
+ BA4FD1F21372FAFA0025925C /* pathnames.h */,
+ BA4FD1F31372FAFA0025925C /* perm.c */,
+ BA4FD1F41372FAFA0025925C /* perm.h */,
+ BA4FD1F51372FAFA0025925C /* privs.h */,
+ );
+ path = at.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1F61372FAFA0025925C /* atrun.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD1F81372FAFA0025925C /* atrun.8 */,
+ BA4FD1F91372FAFA0025925C /* atrun.c */,
+ BA4FD1FA1372FAFA0025925C /* atrun.h */,
+ BA4FD1FC1372FAFA0025925C /* com.apple.atrun.plist */,
+ BA4FD1FD1372FAFA0025925C /* gloadavg.c */,
+ BA4FD1FE1372FAFA0025925C /* gloadavg.h */,
+ );
+ path = atrun.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD1FF1372FAFA0025925C /* chkpasswd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2011372FAFA0025925C /* chkpasswd.8 */,
+ BA4FD2021372FAFA0025925C /* chkpasswd.pam */,
+ BA4FD2031372FAFA0025925C /* file_passwd.c */,
+ BA4FD2041372FAFA0025925C /* nis_passwd.c */,
+ BA4FD2051372FAFA0025925C /* od_passwd.c */,
+ BA4FD2061372FAFA0025925C /* pam_passwd.c */,
+ BA4FD2071372FAFA0025925C /* passwd.c */,
+ BA4FD2081372FAFA0025925C /* stringops.c */,
+ BA4FD2091372FAFA0025925C /* stringops.h */,
+ BA9B767613739E9E001BB39F /* chkpasswd.h */,
+ );
+ path = chkpasswd.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD20A1372FAFA0025925C /* chpass.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD20B1372FAFA0025925C /* IMPORT_NOTES */,
+ BA4FD20D1372FAFA0025925C /* chpass.1 */,
+ BA4FD20E1372FAFA0025925C /* chpass.c */,
+ BA4FD20F1372FAFA0025925C /* chpass.h */,
+ BA4FD2101372FAFA0025925C /* edit.c */,
+ BA4FD2111372FAFA0025925C /* field.c */,
+ BA4FD2121372FAFA0025925C /* open_directory.c */,
+ BA4FD2131372FAFA0025925C /* open_directory.h */,
+ BA4FD2141372FAFA0025925C /* pw_copy.c */,
+ BA4FD2151372FAFA0025925C /* pw_copy.h */,
+ BA4FD2161372FAFA0025925C /* table.c */,
+ BA4FD2171372FAFA0025925C /* util.c */,
+ );
+ path = chpass.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD21E1372FAFA0025925C /* dmesg.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2201372FAFA0025925C /* dmesg.8 */,
+ BA4FD2211372FAFA0025925C /* dmesg.c */,
+ );
+ path = dmesg.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2261372FAFA0025925C /* dynamic_pager.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD22A1372FAFA0025925C /* com.apple.dynamic_pager.plist */,
+ BA4FD22C1372FAFA0025925C /* dynamic_pager.8 */,
+ BA4FD22D1372FAFA0025925C /* dynamic_pager.c */,
+ BA4B79FB1373B7ED00003422 /* Processed LaunchDaemon plist */,
+ );
+ path = dynamic_pager.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD22E1372FAFA0025925C /* fs_usage.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2301372FAFA0025925C /* fs_usage.1 */,
+ BA4FD2311372FAFA0025925C /* fs_usage.c */,
+ );
+ path = fs_usage.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2321372FAFA0025925C /* getconf.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2351372FAFA0025925C /* confstr.gperf */,
+ BA4FD2361372FAFA0025925C /* fake-gperf.awk */,
+ BA4FD2371372FAFA0025925C /* getconf.1 */,
+ BA4FD2381372FAFA0025925C /* getconf.c */,
+ BA4FD2391372FAFA0025925C /* getconf.h */,
+ BA4FD23A1372FAFA0025925C /* limits.gperf */,
+ BA4FD23B1372FAFA0025925C /* pathconf.gperf */,
+ BA4FD23C1372FAFA0025925C /* progenv.gperf */,
+ BA4FD23D1372FAFA0025925C /* sysconf.gperf */,
+ BA4B7A231373C2DC00003422 /* Generated Source */,
+ );
+ path = getconf.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD23E1372FAFA0025925C /* getty.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2401372FAFA0025925C /* chat.c */,
+ BA4FD2411372FAFA0025925C /* com.apple.getty.plist */,
+ 58775F6D2489B8CE0098F7DE /* com.apple.serialdebugconsole.plist */,
+ 58775F6B2489B8AA0098F7DE /* com.apple.getty.internal.plist */,
+ BA4FD2421372FAFA0025925C /* extern.h */,
+ BA4FD2431372FAFA0025925C /* getty.8 */,
+ BA4FD2441372FAFA0025925C /* gettytab.5 */,
+ BA4FD2451372FAFA0025925C /* gettytab.h */,
+ BA4FD2461372FAFA0025925C /* init.c */,
+ BA4FD2471372FAFA0025925C /* main.c */,
+ BA4FD2481372FAFA0025925C /* pathnames.h */,
+ BA4FD2491372FAFA0025925C /* subr.c */,
+ BA4FD24A1372FAFA0025925C /* ttys.5 */,
+ BA4B7A3D1375189E00003422 /* Processed LaunchDaemon plist */,
+ );
+ path = getty.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD24B1372FAFA0025925C /* hostinfo.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD24D1372FAFA0025925C /* hostinfo.8 */,
+ BA4FD24E1372FAFA0025925C /* hostinfo.c */,
+ );
+ path = hostinfo.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD24F1372FAFA0025925C /* iostat.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2521372FAFA0025925C /* iostat.8 */,
+ BA4FD2531372FAFA0025925C /* iostat.c */,
+ );
+ path = iostat.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2551372FAFA0025925C /* latency.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2571372FAFA0025925C /* latency.1 */,
+ BA4FD2581372FAFA0025925C /* latency.c */,
+ );
+ path = latency.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2591372FAFA0025925C /* login.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ 43A96C7223D2DAAE0033235B /* login.entitlements */,
+ BA4FD25B1372FAFA0025925C /* klogin.c */,
+ BA4FD25C1372FAFA0025925C /* login.1 */,
+ BA4FD25D1372FAFA0025925C /* login.c */,
+ BA4FD25E1372FAFA0025925C /* login.h */,
+ BA4FD25F1372FAFA0025925C /* login_audit.c */,
+ BA4FD2601372FAFA0025925C /* pam.d */,
+ BA4FD2631372FAFA0025925C /* pathnames.h */,
+ );
+ path = login.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2601372FAFA0025925C /* pam.d */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2611372FAFA0025925C /* login */,
+ BA4FD2621372FAFA0025925C /* login.term */,
+ );
+ path = pam.d;
+ sourceTree = "<group>";
+ };
+ BA4FD2691372FAFA0025925C /* mean.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD26B1372FAFA0025925C /* mean.c */,
+ );
+ path = mean.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD26C1372FAFA0025925C /* mkfile.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD26E1372FAFA0025925C /* mkfile.8 */,
+ BA4FD26F1372FAFA0025925C /* mkfile.c */,
+ );
+ path = mkfile.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2701372FAFA0025925C /* newgrp.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2721372FAFA0025925C /* newgrp.1 */,
+ BA4FD2731372FAFA0025925C /* newgrp.c */,
+ );
+ path = newgrp.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2741372FAFA0025925C /* nologin.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2761372FAFA0025925C /* nologin.5 */,
+ BA4FD2771372FAFA0025925C /* nologin.8 */,
+ BA4FD2781372FAFA0025925C /* nologin.c */,
+ );
+ path = nologin.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2791372FAFA0025925C /* nvram.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD27B1372FAFA0025925C /* nvram.8 */,
+ BA4FD27C1372FAFA0025925C /* nvram.c */,
+ );
+ path = nvram.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD27D1372FAFA0025925C /* pagesize.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD27F1372FAFA0025925C /* pagesize.1 */,
+ BA4FD2801372FAFA0025925C /* pagesize.sh */,
+ );
+ path = pagesize.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2811372FAFA0025925C /* passwd.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ A7C0927020EC491E0068148E /* passwd.entitlements */,
+ BA4FD2831372FAFA0025925C /* file_passwd.c */,
+ BA4FD2841372FAFA0025925C /* nis_passwd.c */,
+ BA4FD2851372FAFA0025925C /* od_passwd.c */,
+ BA4FD2861372FAFA0025925C /* pam_passwd.c */,
+ BA4FD2871372FAFA0025925C /* passwd.1 */,
+ BA4FD2881372FAFA0025925C /* passwd.c */,
+ BAE589D71378FE8D0049DD3B /* passwd.h */,
+ BA4FD2891372FAFA0025925C /* passwd.pam */,
+ );
+ path = passwd.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD28A1372FAFA0025925C /* pwd_mkdb.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD28C1372FAFA0025925C /* pw_scan.c */,
+ BA4FD28D1372FAFA0025925C /* pw_scan.h */,
+ BA4FD28E1372FAFA0025925C /* pwd_mkdb.8 */,
+ BA4FD28F1372FAFA0025925C /* pwd_mkdb.c */,
+ );
+ path = pwd_mkdb.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2901372FAFA0025925C /* reboot.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2921372FAFA0025925C /* kextmanager.defs */,
+ BA4FD2931372FAFA0025925C /* reboot.8 */,
+ BA4FD2941372FAFA0025925C /* reboot.c */,
+ );
+ path = reboot.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2951372FAFA0025925C /* sa.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2971372FAFA0025925C /* db.c */,
+ BA4FD2981372FAFA0025925C /* extern.h */,
+ BA4FD2991372FAFA0025925C /* main.c */,
+ BA4FD29A1372FAFA0025925C /* pathnames.h */,
+ BA4FD29B1372FAFA0025925C /* pdb.c */,
+ BA4FD29C1372FAFA0025925C /* sa.8 */,
+ BA4FD29D1372FAFA0025925C /* usrdb.c */,
+ );
+ path = sa.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2AC1372FAFA0025925C /* sc_usage.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2AE1372FAFA0025925C /* sc_usage.1 */,
+ BA4FD2AF1372FAFA0025925C /* sc_usage.c */,
+ );
+ path = sc_usage.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2B01372FAFA0025925C /* shutdown.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2B21372FAFA0025925C /* kextmanager.defs */,
+ BA4FD2B31372FAFA0025925C /* pathnames.h */,
+ BA4FD2B41372FAFA0025925C /* shutdown.8 */,
+ BA4FD2B51372FAFA0025925C /* shutdown.c */,
+ );
+ path = shutdown.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2B61372FAFA0025925C /* sync.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2B81372FAFA0025925C /* sync.8 */,
+ BA4FD2B91372FAFA0025925C /* sync.c */,
+ );
+ path = sync.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2BA1372FAFA0025925C /* sysctl.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2BC1372FAFA0025925C /* sysctl.8 */,
+ BA4FD2BD1372FAFA0025925C /* sysctl.c */,
+ BA4FD2BE1372FAFA0025925C /* sysctl.conf.5 */,
+ );
+ path = sysctl.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2BF1372FAFA0025925C /* trace.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2C11372FAFA0025925C /* trace.1 */,
+ BA4FD2C21372FAFA0025925C /* trace.c */,
+ );
+ path = trace.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2C31372FAFA0025925C /* vifs.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2C51372FAFA0025925C /* vifs.8 */,
+ BA4FD2C61372FAFA0025925C /* vifs.c */,
+ );
+ path = vifs.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2C71372FAFA0025925C /* vipw.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2C91372FAFA0025925C /* pw_util.c */,
+ BA4FD2CA1372FAFA0025925C /* pw_util.h */,
+ BA4FD2CB1372FAFA0025925C /* vipw.8 */,
+ BA4FD2CC1372FAFA0025925C /* vipw.c */,
+ );
+ path = vipw.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2CD1372FAFA0025925C /* vm_stat.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2CF1372FAFA0025925C /* vm_stat.1 */,
+ BA4FD2D01372FAFA0025925C /* vm_stat.c */,
+ );
+ path = vm_stat.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2D11372FAFA0025925C /* zdump.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2D31372FAFA0025925C /* zdump.8 */,
+ BA4FD2D41372FAFA0025925C /* zdump.c */,
+ );
+ path = zdump.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2D51372FAFA0025925C /* zic.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ BA959E8413968CF900CA9C60 /* generate_zoneinfo.sh */,
+ BA4FD2D61372FAFA0025925C /* Arts.htm */,
+ BA4FD2D81372FAFA0025925C /* Makefile.zoneinfo.dist */,
+ BA4FD2D91372FAFA0025925C /* README */,
+ BA4FD2DA1372FAFA0025925C /* Theory */,
+ BA4FD2DB1372FAFA0025925C /* ZIC_HACK */,
+ BA4FD2DC1372FAFA0025925C /* ialloc.c */,
+ BA4FD2DD1372FAFA0025925C /* private.h */,
+ BA4FD2DE1372FAFA0025925C /* scheck.c */,
+ BA4FD2DF1372FAFA0025925C /* tz-art.htm */,
+ BA4FD2E01372FAFA0025925C /* tz-link.htm */,
+ BA4FD2E11372FAFA0025925C /* zic.8 */,
+ BA4FD2E21372FAFA0025925C /* zic.c */,
+ BA0A86491396D3CE00D2272C /* Generated zoneinfo Files */,
+ );
+ path = zic.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2E31372FAFA0025925C /* zprint.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ CEB165CB246C599A00228592 /* test_zprint.lua */,
+ C99490E32090F55D00246D9D /* zprint.lua */,
+ FEBEE5CF1B0EACEB00166A8B /* entitlements.plist */,
+ BA4FD2E51372FAFA0025925C /* zprint.1 */,
+ BA4FD2E61372FAFA0025925C /* zprint.c */,
+ );
+ path = zprint.tproj;
+ sourceTree = "<group>";
+ };
+ BA4FD2F01372FB3D0025925C /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ BA4FD2EF1372FB3D0025925C /* ac */,
+ BA4FD30D1372FFD80025925C /* accton */,
+ BA4FD323137300EE0025925C /* arch */,
+ BA4FD3411373073E0025925C /* at */,
+ BA9B764C13739ABE001BB39F /* atrun */,
+ BA9B766313739C20001BB39F /* chkpasswd */,
+ BA9B768C1373A0D8001BB39F /* chpass */,
+ BA4B79CD1373A72800003422 /* dmesg */,
+ BA4B79EC1373AF7A00003422 /* dynamic_pager */,
+ BA4B7A051373B9E900003422 /* fs_usage */,
+ BA4B7A161373BE9D00003422 /* getconf */,
+ BA4B7A4F137648E100003422 /* getty */,
+ BA4B7A6513765CC700003422 /* hostinfo */,
+ BA4B7A7113765D3E00003422 /* iostat */,
+ BA4B7A9013765F3C00003422 /* latency */,
+ BA473DB31377B2230005CC19 /* login */,
+ BACC1D151377B481007728F4 /* mean */,
+ BACC1D451377B6E2007728F4 /* mkfile */,
+ BACC1D551377B7A7007728F4 /* newgrp */,
+ BACC1D611377B85C007728F4 /* nologin */,
+ BAE589A5137836A00049DD3B /* nvram */,
+ BAE589CE1378FCAA0049DD3B /* passwd */,
+ BAE589E3137902F50049DD3B /* pwd_mkdb */,
+ BAE589F01379044E0049DD3B /* reboot */,
+ BAE58A1113799F610049DD3B /* sa */,
+ BAE58A4E137D69A60049DD3B /* sc_usage */,
+ BA91CE62137F42ED00AE5160 /* shutdown */,
+ BA9BF492139680CF0018C7BB /* sync */,
+ BA9BF49F1396812D0018C7BB /* sysctl */,
+ BA9BF4AE139681910018C7BB /* trace */,
+ BA9BF4C6139682BA0018C7BB /* vifs */,
+ BA9BF4D2139682F80018C7BB /* vipw */,
+ BA9BF4DF139683580018C7BB /* vm_stat */,
+ BA9BF4EB139683EB0018C7BB /* zdump */,
+ BA9BF4F7139684B40018C7BB /* zic */,
+ BA0A861013968E8500D2272C /* zprint */,
+ 1523FE631595048900661E82 /* ltop */,
+ C96F50B715BDCEC3008682F7 /* lsmp */,
+ 55CCB17316B84EDA00B56979 /* vm_purgeable_stat */,
+ C625B28816D6F27E00168EF7 /* taskpolicy */,
+ B3F0E6D516E96FC2008FAD09 /* memory_pressure */,
+ ADA9007717679A8C00161ADF /* purge */,
+ 550C19EB1804D226001DA380 /* iosim */,
+ B158E3A0185A836700474677 /* wordexp-helper */,
+ 08DC48851A12C21B008AAF38 /* kpgo */,
+ 97999D2D1AE84C0E00E8B10F /* lskq */,
+ 78DE9DE01B5045DE00FE6DF5 /* wait4path */,
+ C20D8C691C1A102F00C1226B /* gcore */,
+ 8EC391651C9733C2001E28E6 /* proc_uuid_policy */,
+ 08CE3D291E6E22A200DF1B78 /* stackshot */,
+ 0D06BC5E1E8F08CB00C6EC2D /* mslutil */,
+ F2291F5D1FFEBB6A00161936 /* zlog */,
+ 3521C84D2245AA92001B3201 /* cpuctl */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ C21481371C1A11F0003BCA63 /* gcore.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ C2DAA9491D9F22BF00FAC263 /* gcore-internal.1 */,
+ C2DAA94A1D9F22BF00FAC263 /* convert.h */,
+ C2DAA94B1D9F22BF00FAC263 /* convert.c */,
+ C214810D1C1A11E6003BCA63 /* corefile.c */,
+ C214810E1C1A11E6003BCA63 /* corefile.h */,
+ C214810F1C1A11E6003BCA63 /* dyld_shared_cache.c */,
+ C21481101C1A11E6003BCA63 /* dyld_shared_cache.h */,
+ C21481111C1A11E6003BCA63 /* dyld.c */,
+ C21481121C1A11E6003BCA63 /* dyld.h */,
+ C21481131C1A11E6003BCA63 /* gcore.1 */,
+ C21481141C1A11E6003BCA63 /* loader_additions.h */,
+ C21481151C1A11E6003BCA63 /* main.c */,
+ C21481161C1A11E6003BCA63 /* options.h */,
+ C21481171C1A11E6003BCA63 /* region.h */,
+ C21481181C1A11E6003BCA63 /* sparse.c */,
+ C21481191C1A11E6003BCA63 /* sparse.h */,
+ C214811A1C1A11E7003BCA63 /* threads.c */,
+ C214811B1C1A11E7003BCA63 /* threads.h */,
+ C214811C1C1A11E7003BCA63 /* utils.c */,
+ C214811D1C1A11E7003BCA63 /* utils.h */,
+ C214811E1C1A11E7003BCA63 /* vanilla.c */,
+ C214811F1C1A11E7003BCA63 /* vanilla.h */,
+ C21481201C1A11E7003BCA63 /* vm.c */,
+ C21481211C1A11E7003BCA63 /* vm.h */,
+ );
+ name = gcore.tproj;
+ sourceTree = "<group>";
+ };
+ C625B28916D6F27E00168EF7 /* taskpolicy.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ C625B28A16D6F27E00168EF7 /* taskpolicy.c */,
+ C625B28C16D6F27E00168EF7 /* taskpolicy.8 */,
+ );
+ path = taskpolicy.tproj;
+ sourceTree = "<group>";
+ };
+ C96F50AA15BDCBA2008682F7 /* lsmp.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ C96F50AC15BDCBF0008682F7 /* lsmp.1 */,
+ C96F50AD15BDCE8E008682F7 /* lsmp.c */,
+ 72D1FDD818C4140600C1E05F /* task_details.c */,
+ 72F9316B18C269E500D804C5 /* common.h */,
+ 72F9316C18C26A8600D804C5 /* port_details.c */,
+ );
+ name = lsmp.tproj;
+ path = ac.tproj;
+ sourceTree = "<group>";
+ };
+ F2291F5E1FFEBB8500161936 /* zlog.tproj */ = {
+ isa = PBXGroup;
+ children = (
+ F29F5A5C203E4403005B0099 /* zlog.1 */,
+ F29F5A5A203E12BB005B0099 /* entitlements.plist */,
+ F2291F5F1FFEBB9E00161936 /* zlog.c */,
+ F27B70292045038B003C04FC /* SymbolicationHelper.c */,
+ F27B702A2045038B003C04FC /* SymbolicationHelper.h */,
+ );
+ path = zlog.tproj;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ BA4FD3481373077C0025925C /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD3491373079B0025925C /* at.h in Headers */,
+ BA4FD34A1373079B0025925C /* panic.h in Headers */,
+ BA4FD34B1373079B0025925C /* parsetime.h in Headers */,
+ BA4FD34C1373079B0025925C /* pathnames.h in Headers */,
+ BA4FD34D1373079B0025925C /* perm.h in Headers */,
+ BA4FD34E1373079B0025925C /* privs.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B763F13739ABE001BB39F /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B764313739ABE001BB39F /* pathnames.h in Headers */,
+ BA9B764513739ABE001BB39F /* privs.h in Headers */,
+ BA9B764F13739B45001BB39F /* atrun.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B765813739C20001BB39F /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B766B13739C7A001BB39F /* stringops.h in Headers */,
+ BA9B767713739E9E001BB39F /* chkpasswd.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B76801373A0D8001BB39F /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B76951373A16A001BB39F /* chpass.h in Headers */,
+ BA9B76961373A16A001BB39F /* open_directory.h in Headers */,
+ BA9B76971373A16A001BB39F /* pw_copy.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 08CE3D281E6E22A200DF1B78 /* stackshot */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 08CE3D2F1E6E22A200DF1B78 /* Build configuration list for PBXNativeTarget "stackshot" */;
+ buildPhases = (
+ 08CE3D251E6E22A200DF1B78 /* Sources */,
+ 08CE3D261E6E22A200DF1B78 /* Frameworks */,
+ 08CE3D271E6E22A200DF1B78 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = stackshot;
+ productName = stackshot;
+ productReference = 08CE3D291E6E22A200DF1B78 /* stackshot */;
+ productType = "com.apple.product-type.tool";
+ };
+ 08DC48841A12C21B008AAF38 /* kpgo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 08DC488B1A12C21C008AAF38 /* Build configuration list for PBXNativeTarget "kpgo" */;
+ buildPhases = (
+ 08DC48811A12C21B008AAF38 /* Sources */,
+ 08DC48821A12C21B008AAF38 /* Frameworks */,
+ 08DC48831A12C21B008AAF38 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = kpgo;
+ productName = kpgo;
+ productReference = 08DC48851A12C21B008AAF38 /* kpgo */;
+ productType = "com.apple.product-type.tool";
+ };
+ 0D06BC5D1E8F08CB00C6EC2D /* mslutil */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 0D06BC641E8F08CB00C6EC2D /* Build configuration list for PBXNativeTarget "mslutil" */;
+ buildPhases = (
+ 0D06BC5A1E8F08CB00C6EC2D /* Sources */,
+ 0D06BC5B1E8F08CB00C6EC2D /* Frameworks */,
+ 0D06BC5C1E8F08CB00C6EC2D /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mslutil;
+ productName = mslutil;
+ productReference = 0D06BC5E1E8F08CB00C6EC2D /* mslutil */;
+ productType = "com.apple.product-type.tool";
+ };
+ 1523FE5A1595048900661E82 /* ltop */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1523FE611595048900661E82 /* Build configuration list for PBXNativeTarget "ltop" */;
+ buildPhases = (
+ 1523FE5B1595048900661E82 /* Sources */,
+ 1523FE5D1595048900661E82 /* Frameworks */,
+ 1523FE5F1595048900661E82 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ltop;
+ productName = ac;
+ productReference = 1523FE631595048900661E82 /* ltop */;
+ productType = "com.apple.product-type.tool";
+ };
+ 3521C84C2245AA92001B3201 /* cpuctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 3521C8512245AA92001B3201 /* Build configuration list for PBXNativeTarget "cpuctl" */;
+ buildPhases = (
+ 3521C8492245AA92001B3201 /* Sources */,
+ 3521C84A2245AA92001B3201 /* Frameworks */,
+ 3521C84B2245AA92001B3201 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cpuctl;
+ productName = cpuctl;
+ productReference = 3521C84D2245AA92001B3201 /* cpuctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ 550C19E21804D226001DA380 /* iosim */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 550C19E91804D226001DA380 /* Build configuration list for PBXNativeTarget "iosim" */;
+ buildPhases = (
+ 550C19E31804D226001DA380 /* Sources */,
+ 550C19E51804D226001DA380 /* Frameworks */,
+ 550C19E71804D226001DA380 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = iosim;
+ productName = ac;
+ productReference = 550C19EB1804D226001DA380 /* iosim */;
+ productType = "com.apple.product-type.tool";
+ };
+ 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 55CCB17116B84EDA00B56979 /* Build configuration list for PBXNativeTarget "vm_purgeable_stat" */;
+ buildPhases = (
+ 55CCB16B16B84EDA00B56979 /* Sources */,
+ 55CCB16D16B84EDA00B56979 /* Frameworks */,
+ 55CCB16F16B84EDA00B56979 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vm_purgeable_stat;
+ productName = ac;
+ productReference = 55CCB17316B84EDA00B56979 /* vm_purgeable_stat */;
+ productType = "com.apple.product-type.tool";
+ };
+ 78DE9DDF1B5045DE00FE6DF5 /* wait4path */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 78DE9DE41B5045DE00FE6DF5 /* Build configuration list for PBXNativeTarget "wait4path" */;
+ buildPhases = (
+ 78DE9DDC1B5045DE00FE6DF5 /* Sources */,
+ 78DE9DDD1B5045DE00FE6DF5 /* Frameworks */,
+ 78DE9DDE1B5045DE00FE6DF5 /* CopyFiles */,
+ );
+ buildRules = (
+ 78DE9DFF1B504DB800FE6DF5 /* PBXBuildRule */,
+ );
+ dependencies = (
+ );
+ name = wait4path;
+ productName = wait4path;
+ productReference = 78DE9DE01B5045DE00FE6DF5 /* wait4path */;
+ productType = "com.apple.product-type.tool";
+ };
+ 8EC3915B1C9733C2001E28E6 /* proc_uuid_policy */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8EC391621C9733C2001E28E6 /* Build configuration list for PBXNativeTarget "proc_uuid_policy" */;
+ buildPhases = (
+ 8EC3915C1C9733C2001E28E6 /* Sources */,
+ 8EC3915E1C9733C2001E28E6 /* Frameworks */,
+ 8EC391601C9733C2001E28E6 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = proc_uuid_policy;
+ productName = ac;
+ productReference = 8EC391651C9733C2001E28E6 /* proc_uuid_policy */;
+ productType = "com.apple.product-type.tool";
+ };
+ 97999D211AE84C0E00E8B10F /* lskq */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 97999D2A1AE84C0E00E8B10F /* Build configuration list for PBXNativeTarget "lskq" */;
+ buildPhases = (
+ 97999D221AE84C0E00E8B10F /* Sources */,
+ 97999D261AE84C0E00E8B10F /* Frameworks */,
+ 97999D281AE84C0E00E8B10F /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lskq;
+ productName = ac;
+ productReference = 97999D2D1AE84C0E00E8B10F /* lskq */;
+ productType = "com.apple.product-type.tool";
+ };
+ ADA9006F17679A8C00161ADF /* purge */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = ADA9007517679A8C00161ADF /* Build configuration list for PBXNativeTarget "purge" */;
+ buildPhases = (
+ ADA9007017679A8C00161ADF /* Sources */,
+ ADA9007217679A8C00161ADF /* Frameworks */,
+ ADA9007317679A8C00161ADF /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = purge;
+ productName = purge;
+ productReference = ADA9007717679A8C00161ADF /* purge */;
+ productType = "com.apple.product-type.tool";
+ };
+ B158E39F185A836700474677 /* wordexp-helper */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B158E3A7185A836700474677 /* Build configuration list for PBXNativeTarget "wordexp-helper" */;
+ buildPhases = (
+ B158E39C185A836700474677 /* Sources */,
+ B158E39D185A836700474677 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "wordexp-helper";
+ productName = "wordexp-helper";
+ productReference = B158E3A0185A836700474677 /* wordexp-helper */;
+ productType = "com.apple.product-type.tool";
+ };
+ B3F0E6CC16E96FC2008FAD09 /* memory_pressure */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = B3F0E6D316E96FC2008FAD09 /* Build configuration list for PBXNativeTarget "memory_pressure" */;
+ buildPhases = (
+ B3F0E6CD16E96FC2008FAD09 /* Sources */,
+ B3F0E6CF16E96FC2008FAD09 /* Frameworks */,
+ B3F0E6D116E96FC2008FAD09 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = memory_pressure;
+ productName = ac;
+ productReference = B3F0E6D516E96FC2008FAD09 /* memory_pressure */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA0A860713968E8500D2272C /* zprint */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA0A860E13968E8500D2272C /* Build configuration list for PBXNativeTarget "zprint" */;
+ buildPhases = (
+ BA0A860813968E8500D2272C /* Sources */,
+ BA0A860A13968E8500D2272C /* Frameworks */,
+ BA0A860C13968E8500D2272C /* Copy man page */,
+ C99490E22090F53B00246D9D /* Copy Lua library */,
+ CEB165CD246C599F00228592 /* Copy test */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = zprint;
+ productName = ac;
+ productReference = BA0A861013968E8500D2272C /* zprint */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA473DA01377B2230005CC19 /* login */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA473DB11377B2230005CC19 /* Build configuration list for PBXNativeTarget "login" */;
+ buildPhases = (
+ BA473DA11377B2230005CC19 /* Sources */,
+ BA473DAD1377B2230005CC19 /* Frameworks */,
+ BA473DAE1377B2230005CC19 /* CopyFiles */,
+ BACC1CFC1377B2BD007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = login;
+ productName = ac;
+ productReference = BA473DB31377B2230005CC19 /* login */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B79C51373A72800003422 /* dmesg */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B79CB1373A72800003422 /* Build configuration list for PBXNativeTarget "dmesg" */;
+ buildPhases = (
+ BA4B79C61373A72800003422 /* Sources */,
+ BA4B79C81373A72800003422 /* Frameworks */,
+ BA4B79C91373A72800003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dmesg;
+ productName = ac;
+ productReference = BA4B79CD1373A72800003422 /* dmesg */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B79E01373AF7A00003422 /* dynamic_pager */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B79EA1373AF7A00003422 /* Build configuration list for PBXNativeTarget "dynamic_pager" */;
+ buildPhases = (
+ BA4B79E11373AF7A00003422 /* Sources */,
+ BA4B79E41373AF7A00003422 /* Frameworks */,
+ BA4B79E61373AF7A00003422 /* CopyFiles */,
+ BA4B79F91373B6A400003422 /* ShellScript */,
+ BA4B79E81373AF7A00003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = dynamic_pager;
+ productName = ac;
+ productReference = BA4B79EC1373AF7A00003422 /* dynamic_pager */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B79FD1373B9E900003422 /* fs_usage */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A031373B9E900003422 /* Build configuration list for PBXNativeTarget "fs_usage" */;
+ buildPhases = (
+ BA4B79FE1373B9E900003422 /* Sources */,
+ BA4B7A001373B9E900003422 /* Frameworks */,
+ BA4B7A011373B9E900003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fs_usage;
+ productName = ac;
+ productReference = BA4B7A051373B9E900003422 /* fs_usage */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A0E1373BE9D00003422 /* getconf */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A141373BE9D00003422 /* Build configuration list for PBXNativeTarget "getconf" */;
+ buildPhases = (
+ BA4B7A221373C01600003422 /* ShellScript */,
+ BA4B7A0F1373BE9D00003422 /* Sources */,
+ BA4B7A111373BE9D00003422 /* Frameworks */,
+ BA4B7A121373BE9D00003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = getconf;
+ productName = ac;
+ productReference = BA4B7A161373BE9D00003422 /* getconf */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A3F137648E100003422 /* getty */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A4D137648E100003422 /* Build configuration list for PBXNativeTarget "getty" */;
+ buildPhases = (
+ BA4B7A40137648E100003422 /* Sources */,
+ BA4B7A45137648E100003422 /* Frameworks */,
+ BA4B7A48137648E100003422 /* CopyFiles */,
+ BA4B7A561376496100003422 /* CopyFiles */,
+ BA4B7A4A137648E100003422 /* ShellScript */,
+ BA4B7A4B137648E100003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = getty;
+ productName = ac;
+ productReference = BA4B7A4F137648E100003422 /* getty */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A5D13765CC700003422 /* hostinfo */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A6313765CC700003422 /* Build configuration list for PBXNativeTarget "hostinfo" */;
+ buildPhases = (
+ BA4B7A5E13765CC700003422 /* Sources */,
+ BA4B7A6013765CC700003422 /* Frameworks */,
+ BA4B7A6113765CC700003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = hostinfo;
+ productName = ac;
+ productReference = BA4B7A6513765CC700003422 /* hostinfo */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A6913765D3E00003422 /* iostat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A6F13765D3E00003422 /* Build configuration list for PBXNativeTarget "iostat" */;
+ buildPhases = (
+ BA4B7A6A13765D3E00003422 /* Sources */,
+ BA4B7A6C13765D3E00003422 /* Frameworks */,
+ BA4B7A6D13765D3E00003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = iostat;
+ productName = ac;
+ productReference = BA4B7A7113765D3E00003422 /* iostat */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4B7A7D13765F3C00003422 /* latency */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4B7A8E13765F3C00003422 /* Build configuration list for PBXNativeTarget "latency" */;
+ buildPhases = (
+ BA4B7A7E13765F3C00003422 /* Sources */,
+ BA4B7A8A13765F3C00003422 /* Frameworks */,
+ BA4B7A8B13765F3C00003422 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = latency;
+ productName = ac;
+ productReference = BA4B7A9013765F3C00003422 /* latency */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4FD2EE1372FB3D0025925C /* ac */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4FD2F91372FB3D0025925C /* Build configuration list for PBXNativeTarget "ac" */;
+ buildPhases = (
+ BA4FD2EB1372FB3D0025925C /* Sources */,
+ BA4FD2EC1372FB3D0025925C /* Frameworks */,
+ BA4FD2ED1372FB3D0025925C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ac;
+ productName = ac;
+ productReference = BA4FD2EF1372FB3D0025925C /* ac */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4FD3041372FFD80025925C /* accton */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4FD30A1372FFD80025925C /* Build configuration list for PBXNativeTarget "accton" */;
+ buildPhases = (
+ BA4FD3051372FFD80025925C /* Sources */,
+ BA4FD3071372FFD80025925C /* Frameworks */,
+ BA4FD3081372FFD80025925C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = accton;
+ productName = ac;
+ productReference = BA4FD30D1372FFD80025925C /* accton */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4FD31A137300ED0025925C /* arch */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4FD320137300ED0025925C /* Build configuration list for PBXNativeTarget "arch" */;
+ buildPhases = (
+ BA4FD31B137300ED0025925C /* Sources */,
+ BA4FD31D137300ED0025925C /* Frameworks */,
+ BA4FD31E137300ED0025925C /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = arch;
+ productName = ac;
+ productReference = BA4FD323137300EE0025925C /* arch */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA4FD3381373073E0025925C /* at */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA4FD33E1373073E0025925C /* Build configuration list for PBXNativeTarget "at" */;
+ buildPhases = (
+ BA4FD3391373073E0025925C /* Sources */,
+ BA4FD3481373077C0025925C /* Headers */,
+ BA4FD33B1373073E0025925C /* Frameworks */,
+ BA4FD33C1373073E0025925C /* CopyFiles */,
+ BAAEB39A13730C41003EA7A9 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = at;
+ productName = ac;
+ productReference = BA4FD3411373073E0025925C /* at */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA91CE59137F42ED00AE5160 /* shutdown */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA91CE60137F42ED00AE5160 /* Build configuration list for PBXNativeTarget "shutdown" */;
+ buildPhases = (
+ BA91CE5A137F42ED00AE5160 /* Sources */,
+ BA91CE5D137F42ED00AE5160 /* Frameworks */,
+ BA91CE5E137F42ED00AE5160 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = shutdown;
+ productName = ac;
+ productReference = BA91CE62137F42ED00AE5160 /* shutdown */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9B763913739ABE001BB39F /* atrun */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9B764A13739ABE001BB39F /* Build configuration list for PBXNativeTarget "atrun" */;
+ buildPhases = (
+ BA9B763A13739ABE001BB39F /* Sources */,
+ BA9B763F13739ABE001BB39F /* Headers */,
+ BA9B764613739ABE001BB39F /* Frameworks */,
+ BA9B764713739ABE001BB39F /* CopyFiles */,
+ BA9B765113739B6A001BB39F /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = atrun;
+ productName = ac;
+ productReference = BA9B764C13739ABE001BB39F /* atrun */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9B765513739C20001BB39F /* chkpasswd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9B766113739C20001BB39F /* Build configuration list for PBXNativeTarget "chkpasswd" */;
+ buildPhases = (
+ BA9B765613739C20001BB39F /* Sources */,
+ BA9B765813739C20001BB39F /* Headers */,
+ BA9B765C13739C20001BB39F /* Frameworks */,
+ BA9B765D13739C20001BB39F /* CopyFiles */,
+ BA9B767313739D86001BB39F /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chkpasswd;
+ productName = ac;
+ productReference = BA9B766313739C20001BB39F /* chkpasswd */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9B76781373A0D8001BB39F /* chpass */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9B768A1373A0D8001BB39F /* Build configuration list for PBXNativeTarget "chpass" */;
+ buildPhases = (
+ BA9B76791373A0D8001BB39F /* Sources */,
+ BA9B76801373A0D8001BB39F /* Headers */,
+ BA9B76831373A0D8001BB39F /* Frameworks */,
+ BA9B76871373A0D8001BB39F /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = chpass;
+ productName = ac;
+ productReference = BA9B768C1373A0D8001BB39F /* chpass */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF48A139680CF0018C7BB /* sync */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF490139680CF0018C7BB /* Build configuration list for PBXNativeTarget "sync" */;
+ buildPhases = (
+ BA9BF48B139680CF0018C7BB /* Sources */,
+ BA9BF48D139680CF0018C7BB /* Frameworks */,
+ BA9BF48E139680CF0018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sync;
+ productName = ac;
+ productReference = BA9BF492139680CF0018C7BB /* sync */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4971396812D0018C7BB /* sysctl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF49D1396812D0018C7BB /* Build configuration list for PBXNativeTarget "sysctl" */;
+ buildPhases = (
+ BA9BF4981396812D0018C7BB /* Sources */,
+ BA9BF49A1396812D0018C7BB /* Frameworks */,
+ BA9BF49B1396812D0018C7BB /* CopyFiles */,
+ BA9BF4A21396815B0018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sysctl;
+ productName = ac;
+ productReference = BA9BF49F1396812D0018C7BB /* sysctl */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4A5139681910018C7BB /* trace */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4AC139681910018C7BB /* Build configuration list for PBXNativeTarget "trace" */;
+ buildPhases = (
+ BA9BF4A6139681910018C7BB /* Sources */,
+ BA9BF4A8139681910018C7BB /* Frameworks */,
+ BA9BF4AA139681910018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = trace;
+ productName = ac;
+ productReference = BA9BF4AE139681910018C7BB /* trace */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4BE139682BA0018C7BB /* vifs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4C4139682BA0018C7BB /* Build configuration list for PBXNativeTarget "vifs" */;
+ buildPhases = (
+ BA9BF4BF139682BA0018C7BB /* Sources */,
+ BA9BF4C1139682BA0018C7BB /* Frameworks */,
+ BA9BF4C2139682BA0018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vifs;
+ productName = ac;
+ productReference = BA9BF4C6139682BA0018C7BB /* vifs */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4CA139682F80018C7BB /* vipw */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4D0139682F80018C7BB /* Build configuration list for PBXNativeTarget "vipw" */;
+ buildPhases = (
+ BA9BF4CB139682F80018C7BB /* Sources */,
+ BA9BF4CD139682F80018C7BB /* Frameworks */,
+ BA9BF4CE139682F80018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vipw;
+ productName = ac;
+ productReference = BA9BF4D2139682F80018C7BB /* vipw */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4D7139683580018C7BB /* vm_stat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4DD139683580018C7BB /* Build configuration list for PBXNativeTarget "vm_stat" */;
+ buildPhases = (
+ BA9BF4D8139683580018C7BB /* Sources */,
+ BA9BF4DA139683580018C7BB /* Frameworks */,
+ BA9BF4DB139683580018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vm_stat;
+ productName = ac;
+ productReference = BA9BF4DF139683580018C7BB /* vm_stat */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4E3139683EB0018C7BB /* zdump */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4E9139683EB0018C7BB /* Build configuration list for PBXNativeTarget "zdump" */;
+ buildPhases = (
+ BA9BF4E4139683EB0018C7BB /* Sources */,
+ BA9BF4E6139683EB0018C7BB /* Frameworks */,
+ BA9BF4E7139683EB0018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = zdump;
+ productName = ac;
+ productReference = BA9BF4EB139683EB0018C7BB /* zdump */;
+ productType = "com.apple.product-type.tool";
+ };
+ BA9BF4EF139684B40018C7BB /* zic */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BA9BF4F5139684B40018C7BB /* Build configuration list for PBXNativeTarget "zic" */;
+ buildPhases = (
+ BA9BF4F0139684B40018C7BB /* Sources */,
+ BA9BF4F2139684B40018C7BB /* Frameworks */,
+ BA9BF4F3139684B40018C7BB /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = zic;
+ productName = ac;
+ productReference = BA9BF4F7139684B40018C7BB /* zic */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D0D1377B481007728F4 /* mean */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D131377B481007728F4 /* Build configuration list for PBXNativeTarget "mean" */;
+ buildPhases = (
+ BACC1D0E1377B481007728F4 /* Sources */,
+ BACC1D101377B481007728F4 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mean;
+ productName = ac;
+ productReference = BACC1D151377B481007728F4 /* mean */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D3D1377B6E2007728F4 /* mkfile */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D431377B6E2007728F4 /* Build configuration list for PBXNativeTarget "mkfile" */;
+ buildPhases = (
+ BACC1D3E1377B6E2007728F4 /* Sources */,
+ BACC1D401377B6E2007728F4 /* Frameworks */,
+ BACC1D411377B6E2007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = mkfile;
+ productName = ac;
+ productReference = BACC1D451377B6E2007728F4 /* mkfile */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D491377B7A7007728F4 /* newgrp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D531377B7A7007728F4 /* Build configuration list for PBXNativeTarget "newgrp" */;
+ buildPhases = (
+ BACC1D4A1377B7A7007728F4 /* Sources */,
+ BACC1D4D1377B7A7007728F4 /* Frameworks */,
+ BACC1D4E1377B7A7007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = newgrp;
+ productName = ac;
+ productReference = BACC1D551377B7A7007728F4 /* newgrp */;
+ productType = "com.apple.product-type.tool";
+ };
+ BACC1D591377B85C007728F4 /* nologin */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BACC1D5F1377B85C007728F4 /* Build configuration list for PBXNativeTarget "nologin" */;
+ buildPhases = (
+ BACC1D5A1377B85C007728F4 /* Sources */,
+ BACC1D5C1377B85C007728F4 /* Frameworks */,
+ BACC1D651377B89A007728F4 /* CopyFiles */,
+ BACC1D5D1377B85C007728F4 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nologin;
+ productName = ac;
+ productReference = BACC1D611377B85C007728F4 /* nologin */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE5899B137836A00049DD3B /* nvram */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE589A3137836A00049DD3B /* Build configuration list for PBXNativeTarget "nvram" */;
+ buildPhases = (
+ BAE5899C137836A00049DD3B /* Sources */,
+ BAE5899E137836A00049DD3B /* Frameworks */,
+ BAE589A1137836A00049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nvram;
+ productName = ac;
+ productReference = BAE589A5137836A00049DD3B /* nvram */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE589BA1378FCAA0049DD3B /* passwd */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE589CC1378FCAA0049DD3B /* Build configuration list for PBXNativeTarget "passwd" */;
+ buildPhases = (
+ BAE589BB1378FCAA0049DD3B /* Sources */,
+ BAE589C51378FCAA0049DD3B /* Frameworks */,
+ BAE589C91378FCAA0049DD3B /* CopyFiles */,
+ BAE589CB1378FCAA0049DD3B /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = passwd;
+ productName = ac;
+ productReference = BAE589CE1378FCAA0049DD3B /* passwd */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE589DB137902F50049DD3B /* pwd_mkdb */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE589E1137902F50049DD3B /* Build configuration list for PBXNativeTarget "pwd_mkdb" */;
+ buildPhases = (
+ BAE589DC137902F50049DD3B /* Sources */,
+ BAE589DE137902F50049DD3B /* Frameworks */,
+ BAE589DF137902F50049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pwd_mkdb;
+ productName = ac;
+ productReference = BAE589E3137902F50049DD3B /* pwd_mkdb */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE589E81379044E0049DD3B /* reboot */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE589EE1379044E0049DD3B /* Build configuration list for PBXNativeTarget "reboot" */;
+ buildPhases = (
+ BAE589E91379044E0049DD3B /* Sources */,
+ BAE589EB1379044E0049DD3B /* Frameworks */,
+ BAE589EC1379044E0049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = reboot;
+ productName = ac;
+ productReference = BAE589F01379044E0049DD3B /* reboot */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE58A0913799F610049DD3B /* sa */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE58A0F13799F610049DD3B /* Build configuration list for PBXNativeTarget "sa" */;
+ buildPhases = (
+ BAE58A0A13799F610049DD3B /* Sources */,
+ BAE58A0C13799F610049DD3B /* Frameworks */,
+ BAE58A0D13799F610049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sa;
+ productName = ac;
+ productReference = BAE58A1113799F610049DD3B /* sa */;
+ productType = "com.apple.product-type.tool";
+ };
+ BAE58A45137D69A60049DD3B /* sc_usage */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BAE58A4C137D69A60049DD3B /* Build configuration list for PBXNativeTarget "sc_usage" */;
+ buildPhases = (
+ BAE58A46137D69A60049DD3B /* Sources */,
+ BAE58A48137D69A60049DD3B /* Frameworks */,
+ BAE58A4A137D69A60049DD3B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sc_usage;
+ productName = ac;
+ productReference = BAE58A4E137D69A60049DD3B /* sc_usage */;
+ productType = "com.apple.product-type.tool";
+ };
+ C20D8C681C1A102F00C1226B /* gcore */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C20D8C6F1C1A102F00C1226B /* Build configuration list for PBXNativeTarget "gcore" */;
+ buildPhases = (
+ C20D8C651C1A102F00C1226B /* Sources */,
+ C20D8C661C1A102F00C1226B /* Frameworks */,
+ C20D8C671C1A102F00C1226B /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = gcore;
+ productName = gcore;
+ productReference = C20D8C691C1A102F00C1226B /* gcore */;
+ productType = "com.apple.product-type.tool";
+ };
+ C625B28716D6F27E00168EF7 /* taskpolicy */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C625B28F16D6F27E00168EF7 /* Build configuration list for PBXNativeTarget "taskpolicy" */;
+ buildPhases = (
+ C625B28416D6F27E00168EF7 /* Sources */,
+ C625B28516D6F27E00168EF7 /* Frameworks */,
+ C625B28616D6F27E00168EF7 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = taskpolicy;
+ productName = taskpolicy;
+ productReference = C625B28816D6F27E00168EF7 /* taskpolicy */;
+ productType = "com.apple.product-type.tool";
+ };
+ C96F50AE15BDCEC3008682F7 /* lsmp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C96F50B515BDCEC3008682F7 /* Build configuration list for PBXNativeTarget "lsmp" */;
+ buildPhases = (
+ C96F50AF15BDCEC3008682F7 /* Sources */,
+ C96F50B115BDCEC3008682F7 /* Frameworks */,
+ C96F50B315BDCEC3008682F7 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lsmp;
+ productName = ac;
+ productReference = C96F50B715BDCEC3008682F7 /* lsmp */;
+ productType = "com.apple.product-type.tool";
+ };
+ F2291F501FFEBB6A00161936 /* zlog */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F2291F5A1FFEBB6A00161936 /* Build configuration list for PBXNativeTarget "zlog" */;
+ buildPhases = (
+ F2291F511FFEBB6A00161936 /* Sources */,
+ F2291F531FFEBB6A00161936 /* Frameworks */,
+ F29F5A5E203E532B005B0099 /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = zlog;
+ productName = ac;
+ productReference = F2291F5D1FFEBB6A00161936 /* zlog */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ BA2DE9181372FA9100D1913C /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0600;
+ TargetAttributes = {
+ 08CE3D281E6E22A200DF1B78 = {
+ CreatedOnToolsVersion = 8.3;
+ ProvisioningStyle = Automatic;
+ };
+ 08DC48841A12C21B008AAF38 = {
+ CreatedOnToolsVersion = 6.3;
+ ProvisioningStyle = Manual;
+ };
+ 0D06BC5D1E8F08CB00C6EC2D = {
+ CreatedOnToolsVersion = 9.0;
+ ProvisioningStyle = Automatic;
+ };
+ 1523FE5A1595048900661E82 = {
+ ProvisioningStyle = Manual;
+ };
+ 1812F18C1C8F923900F3DC9E = {
+ ProvisioningStyle = Manual;
+ };
+ 3521C84C2245AA92001B3201 = {
+ CreatedOnToolsVersion = 11.0;
+ ProvisioningStyle = Automatic;
+ };
+ 550C19E21804D226001DA380 = {
+ ProvisioningStyle = Manual;
+ };
+ 55CCB16A16B84EDA00B56979 = {
+ ProvisioningStyle = Manual;
+ };
+ 78DE9DDF1B5045DE00FE6DF5 = {
+ CreatedOnToolsVersion = 7.0;
+ ProvisioningStyle = Manual;
+ };
+ 8EC3915B1C9733C2001E28E6 = {
+ ProvisioningStyle = Manual;
+ };
+ 97999D211AE84C0E00E8B10F = {
+ ProvisioningStyle = Manual;
+ };
+ ADA9006F17679A8C00161ADF = {
+ ProvisioningStyle = Manual;
+ };
+ B158E39F185A836700474677 = {
+ ProvisioningStyle = Manual;
+ };
+ B3F0E6CC16E96FC2008FAD09 = {
+ ProvisioningStyle = Manual;
+ };
+ BA0A860713968E8500D2272C = {
+ ProvisioningStyle = Manual;
+ };
+ BA473DA01377B2230005CC19 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4B79C51373A72800003422 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4B79E01373AF7A00003422 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4B79FD1373B9E900003422 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4B7A0E1373BE9D00003422 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4B7A3F137648E100003422 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4B7A5D13765CC700003422 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4B7A6913765D3E00003422 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4B7A7D13765F3C00003422 = {
+ ProvisioningStyle = Manual;
+ };
+ BA4FD2EE1372FB3D0025925C = {
+ ProvisioningStyle = Manual;
+ };
+ BA4FD2FE1372FE4E0025925C = {
+ ProvisioningStyle = Manual;
+ };
+ BA4FD3041372FFD80025925C = {
+ ProvisioningStyle = Manual;
+ };
+ BA4FD31A137300ED0025925C = {
+ ProvisioningStyle = Manual;
+ };
+ BA4FD32F137305DD0025925C = {
+ ProvisioningStyle = Manual;
+ };
+ BA4FD3381373073E0025925C = {
+ ProvisioningStyle = Manual;
+ };
+ BA91CE59137F42ED00AE5160 = {
+ ProvisioningStyle = Manual;
+ };
+ BA959E7E13968C8E00CA9C60 = {
+ ProvisioningStyle = Manual;
+ };
+ BA9B763913739ABE001BB39F = {
+ ProvisioningStyle = Manual;
+ };
+ BA9B765513739C20001BB39F = {
+ ProvisioningStyle = Manual;
+ };
+ BA9B76781373A0D8001BB39F = {
+ ProvisioningStyle = Manual;
+ };
+ BA9B76991373A246001BB39F = {
+ ProvisioningStyle = Manual;
+ };
+ BA9B76A11373A2A2001BB39F = {
+ ProvisioningStyle = Manual;
+ };
+ BA9BF48A139680CF0018C7BB = {
+ ProvisioningStyle = Manual;
+ };
+ BA9BF4971396812D0018C7BB = {
+ ProvisioningStyle = Manual;
+ };
+ BA9BF4A5139681910018C7BB = {
+ ProvisioningStyle = Manual;
+ };
+ BA9BF4BE139682BA0018C7BB = {
+ ProvisioningStyle = Manual;
+ };
+ BA9BF4CA139682F80018C7BB = {
+ ProvisioningStyle = Manual;
+ };
+ BA9BF4D7139683580018C7BB = {
+ ProvisioningStyle = Manual;
+ };
+ BA9BF4E3139683EB0018C7BB = {
+ ProvisioningStyle = Manual;
+ };
+ BA9BF4EF139684B40018C7BB = {
+ ProvisioningStyle = Manual;
+ };
+ BAAEB39C13730D5C003EA7A9 = {
+ ProvisioningStyle = Manual;
+ };
+ BAAEB3A513730DFA003EA7A9 = {
+ ProvisioningStyle = Manual;
+ };
+ BAAEB3AC13730E1C003EA7A9 = {
+ ProvisioningStyle = Manual;
+ };
+ BACC1D0D1377B481007728F4 = {
+ ProvisioningStyle = Manual;
+ };
+ BACC1D181377B4C9007728F4 = {
+ ProvisioningStyle = Manual;
+ };
+ BACC1D3D1377B6E2007728F4 = {
+ ProvisioningStyle = Manual;
+ };
+ BACC1D491377B7A7007728F4 = {
+ ProvisioningStyle = Manual;
+ };
+ BACC1D591377B85C007728F4 = {
+ ProvisioningStyle = Manual;
+ };
+ BAE5899B137836A00049DD3B = {
+ ProvisioningStyle = Manual;
+ };
+ BAE589AA137837130049DD3B = {
+ ProvisioningStyle = Manual;
+ };
+ BAE589BA1378FCAA0049DD3B = {
+ ProvisioningStyle = Manual;
+ };
+ BAE589DB137902F50049DD3B = {
+ ProvisioningStyle = Manual;
+ };
+ BAE589E81379044E0049DD3B = {
+ ProvisioningStyle = Manual;
+ };
+ BAE589F5137904DF0049DD3B = {
+ ProvisioningStyle = Manual;
+ };
+ BAE58A0913799F610049DD3B = {
+ ProvisioningStyle = Manual;
+ };
+ BAE58A45137D69A60049DD3B = {
+ ProvisioningStyle = Manual;
+ };
+ C20D8C681C1A102F00C1226B = {
+ CreatedOnToolsVersion = 7.2;
+ ProvisioningStyle = Manual;
+ };
+ C625B28716D6F27E00168EF7 = {
+ ProvisioningStyle = Manual;
+ };
+ C96F50AE15BDCEC3008682F7 = {
+ ProvisioningStyle = Manual;
+ };
+ };
+ };
+ buildConfigurationList = BA2DE91B1372FA9100D1913C /* Build configuration list for PBXProject "system_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ English,
+ en,
+ );
+ mainGroup = BA2DE9161372FA9100D1913C;
+ productRefGroup = BA4FD2F01372FB3D0025925C /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ BA4FD2FE1372FE4E0025925C /* All_MacOSX */,
+ BACC1D181377B4C9007728F4 /* All_iOS */,
+ 1812F18C1C8F923900F3DC9E /* All_Bridge */,
+ BA4FD2EE1372FB3D0025925C /* ac */,
+ BA4FD3041372FFD80025925C /* accton */,
+ BA4FD31A137300ED0025925C /* arch */,
+ BA4FD32F137305DD0025925C /* machine */,
+ BA4FD3381373073E0025925C /* at */,
+ BAAEB39C13730D5C003EA7A9 /* atq */,
+ BAAEB3A513730DFA003EA7A9 /* atrm */,
+ BAAEB3AC13730E1C003EA7A9 /* batch */,
+ BA9B763913739ABE001BB39F /* atrun */,
+ BA9B765513739C20001BB39F /* chkpasswd */,
+ BA9B76781373A0D8001BB39F /* chpass */,
+ BA9B76991373A246001BB39F /* chfn */,
+ BA9B76A11373A2A2001BB39F /* chsh */,
+ BA4B79C51373A72800003422 /* dmesg */,
+ BA4B79E01373AF7A00003422 /* dynamic_pager */,
+ BA4B79FD1373B9E900003422 /* fs_usage */,
+ C20D8C681C1A102F00C1226B /* gcore */,
+ BA4B7A0E1373BE9D00003422 /* getconf */,
+ BA4B7A3F137648E100003422 /* getty */,
+ BA4B7A5D13765CC700003422 /* hostinfo */,
+ 550C19E21804D226001DA380 /* iosim */,
+ BA4B7A6913765D3E00003422 /* iostat */,
+ 08DC48841A12C21B008AAF38 /* kpgo */,
+ BA4B7A7D13765F3C00003422 /* latency */,
+ BA473DA01377B2230005CC19 /* login */,
+ 97999D211AE84C0E00E8B10F /* lskq */,
+ C96F50AE15BDCEC3008682F7 /* lsmp */,
+ 1523FE5A1595048900661E82 /* ltop */,
+ BACC1D0D1377B481007728F4 /* mean */,
+ B3F0E6CC16E96FC2008FAD09 /* memory_pressure */,
+ BACC1D3D1377B6E2007728F4 /* mkfile */,
+ BACC1D491377B7A7007728F4 /* newgrp */,
+ BACC1D591377B85C007728F4 /* nologin */,
+ BAE5899B137836A00049DD3B /* nvram */,
+ BAE589AA137837130049DD3B /* pagesize */,
+ BAE589BA1378FCAA0049DD3B /* passwd */,
+ 8EC3915B1C9733C2001E28E6 /* proc_uuid_policy */,
+ ADA9006F17679A8C00161ADF /* purge */,
+ BAE589DB137902F50049DD3B /* pwd_mkdb */,
+ BAE589E81379044E0049DD3B /* reboot */,
+ BAE589F5137904DF0049DD3B /* halt */,
+ BAE58A0913799F610049DD3B /* sa */,
+ BAE58A45137D69A60049DD3B /* sc_usage */,
+ BA91CE59137F42ED00AE5160 /* shutdown */,
+ BA9BF48A139680CF0018C7BB /* sync */,
+ BA9BF4971396812D0018C7BB /* sysctl */,
+ C625B28716D6F27E00168EF7 /* taskpolicy */,
+ BA9BF4A5139681910018C7BB /* trace */,
+ BA9BF4BE139682BA0018C7BB /* vifs */,
+ BA9BF4CA139682F80018C7BB /* vipw */,
+ 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */,
+ BA9BF4D7139683580018C7BB /* vm_stat */,
+ 78DE9DDF1B5045DE00FE6DF5 /* wait4path */,
+ B158E39F185A836700474677 /* wordexp-helper */,
+ BA9BF4E3139683EB0018C7BB /* zdump */,
+ BA9BF4EF139684B40018C7BB /* zic */,
+ BA959E7E13968C8E00CA9C60 /* zoneinfo */,
+ BA0A860713968E8500D2272C /* zprint */,
+ 08CE3D281E6E22A200DF1B78 /* stackshot */,
+ 0D06BC5D1E8F08CB00C6EC2D /* mslutil */,
+ F2291F501FFEBB6A00161936 /* zlog */,
+ 3521C84C2245AA92001B3201 /* cpuctl */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 587B8CAD2489CB170001CD8D /* Copy internal getty */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/getty.tproj/com.apple.getty.internal.plist",
+ );
+ name = "Copy internal getty";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ "$(DSTROOT)/AppleInternal/Library/LaunchDaemons/com.apple.getty.plist",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "cp -f \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ };
+ BA4B79F91373B6A400003422 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/dynamic_pager.tproj/com.apple.dynamic_pager.plist",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/com.apple.dynamic_pager.plist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = ". \"${SRCROOT}/dynamic_pager.tproj/generate_plist.sh\"";
+ };
+ BA4B7A221373C01600003422 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/getconf.tproj/confstr.gperf",
+ "$(SRCROOT)/getconf.tproj/limits.gperf",
+ "$(SRCROOT)/getconf.tproj/pathconf.gperf",
+ "$(SRCROOT)/getconf.tproj/progenv.gperf",
+ "$(SRCROOT)/getconf.tproj/sysconf.gperf",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/confstr.c",
+ "$(BUILT_PRODUCTS_DIR)/limits.c",
+ "$(BUILT_PRODUCTS_DIR)/pathconf.c",
+ "$(BUILT_PRODUCTS_DIR)/progenv.c",
+ "$(BUILT_PRODUCTS_DIR)/sysconf.c",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\ni=0\n\nwhile [ $i -lt ${SCRIPT_INPUT_FILE_COUNT} ]; do\n INPUT=\"SCRIPT_INPUT_FILE_${i}\"\n OUTPUT=\"SCRIPT_OUTPUT_FILE_${i}\"\n LC_ALL=C awk -f \"${SRCROOT}/getconf.tproj/fake-gperf.awk\" \"${!INPUT}\" > \"${!OUTPUT}\"\n i=$(($i + 1))\ndone\n";
+ showEnvVarsInLog = 0;
+ };
+ BA4B7A4A137648E100003422 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/getty.tproj/com.apple.getty.plist",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/com.apple.getty.plist",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = ". \"${SRCROOT}/getty.tproj/generate_plist.sh\"\n";
+ };
+ BA4FD335137306050025925C /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/arch",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/machine",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA7248051397C1350008497A /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/zic.tproj/build_zichost.sh",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/zic_host-dst/zic_host",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\n\"${SCRIPT_INPUT_FILE_0}\" \"${BUILT_PRODUCTS_DIR}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA959E8113968C8E00CA9C60 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 12;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/zic.tproj/generate_zoneinfo.sh",
+ "$(BUILT_PRODUCTS_DIR)/zic_host-dst/zic_host",
+ );
+ outputPaths = (
+ "$(BUILT_PRODUCTS_DIR)/zoneinfo",
+ "$(BUILT_PRODUCTS_DIR)/private",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\n\"${SCRIPT_INPUT_FILE_0}\" \"${SRCROOT}\" \"${OBJROOT}\" \"${BUILT_PRODUCTS_DIR}\" \"${SDKROOT}\" \"${PLATFORM_NAME}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA9B767313739D86001BB39F /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/chkpasswd.tproj/chkpasswd.pam",
+ );
+ outputPaths = (
+ "$(DSTROOT)/private/etc/pam.d/chkpasswd",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/private/etc/pam.d\"\ncp \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA9B769C1373A246001BB39F /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/chpass",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/chfn",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/chpass.1\" > \"${DSTROOT}/usr/share/man/man1/chfn.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BA9B76A41373A2A2001BB39F /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/chpass",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/chsh",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/chpass.1\" > \"${DSTROOT}/usr/share/man/man1/chsh.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAAEB39A13730C41003EA7A9 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ "$(DSTROOT)/private/var/at/at.deny",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\ninstall -o daemon -d \"${DSTROOT}/private/var/at\"\ninstall -o daemon -d \"${DSTROOT}/private/var/at/spool\"\ntouch \"${DSTROOT}/private/var/at/at.deny\"\nmkdir -p \"${DSTROOT}/usr/lib\"\nln -sf ../../var/at \"${DSTROOT}/usr/lib/cron\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAAEB39F13730D5C003EA7A9 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/at",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/atq",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/at.1\" > \"${DSTROOT}/usr/share/man/man1/atq.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAAEB3A813730DFA003EA7A9 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/at",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/atrm",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/at.1\" > \"${DSTROOT}/usr/share/man/man1/atrm.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAAEB3AF13730E1C003EA7A9 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/usr/bin/at",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/batch",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man1\"\necho \".so man1/at.1\" > \"${DSTROOT}/usr/share/man/man1/batch.1\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAE589AD137837130049DD3B /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/pagesize.tproj/pagesize.sh",
+ );
+ outputPaths = (
+ "$(DSTROOT)/usr/bin/pagesize",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/usr/bin\"\ninstall \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAE589CB1378FCAA0049DD3B /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/passwd.tproj/passwd.pam",
+ );
+ outputPaths = (
+ "$(DSTROOT)/private/etc/pam.d/passwd",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nmkdir -p \"${DSTROOT}/private/etc/pam.d\"\ncp \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ BAE589F8137904DF0049DD3B /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(DSTROOT)/sbin/reboot",
+ );
+ outputPaths = (
+ "$(DSTROOT)/sbin/halt",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = "set -x\nset -e\n\nln -fhv \"${SCRIPT_INPUT_FILE_0}\" \"${SCRIPT_OUTPUT_FILE_0}\"\nmkdir -p \"${DSTROOT}/usr/share/man/man8\"\necho \".so man8/reboot.8\" > \"${DSTROOT}/usr/share/man/man8/halt.8\"\n";
+ showEnvVarsInLog = 0;
+ };
+ FD0AA4911630C39500606589 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". ${SRCROOT}/zic.tproj/install_zoneinfo.sh";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 08CE3D251E6E22A200DF1B78 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 08CE3D341E6E22F600DF1B78 /* stackshot.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 08DC48811A12C21B008AAF38 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 08DC488E1A12C2D6008AAF38 /* kpgo.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 0D06BC5A1E8F08CB00C6EC2D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0D06BC661E8F091F00C6EC2D /* mslutil.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 1523FE5B1595048900661E82 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1523FE6C1595056C00661E82 /* ltop.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 3521C8492245AA92001B3201 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 358407CE2245AC09006A0D8E /* cpuctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 550C19E31804D226001DA380 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 550C19EC1804D281001DA380 /* iosim.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 55CCB16B16B84EDA00B56979 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 55CCB17416B84EF800B56979 /* vm_purgeable_stat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 78DE9DDC1B5045DE00FE6DF5 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 78DE9E001B504DE500FE6DF5 /* wait4path.version in Sources */,
+ 78DE9DFE1B504D7F00FE6DF5 /* wait4path.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8EC3915C1C9733C2001E28E6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8EC391691C973405001E28E6 /* proc_uuid_policy.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 97999D221AE84C0E00E8B10F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 97999D331AE84D0A00E8B10F /* lskq.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ ADA9007017679A8C00161ADF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ ADA9007C1767A03200161ADF /* purge.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B158E39C185A836700474677 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B158E3A3185A836700474677 /* wordexp-helper.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ B3F0E6CD16E96FC2008FAD09 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ B3F0E6DD16E9706E008FAD09 /* memory_pressure.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA0A860813968E8500D2272C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA0A861313968EAD00D2272C /* zprint.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA473DA11377B2230005CC19 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1CF91377B288007728F4 /* login.c in Sources */,
+ BACC1CFA1377B28C007728F4 /* login_audit.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79C61373A72800003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79D01373A74F00003422 /* dmesg.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79E11373AF7A00003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B79EE1373AFFA00003422 /* dynamic_pager.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B79FE1373B9E900003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A081373BA2400003422 /* fs_usage.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A0F1373BE9D00003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A191373BEDD00003422 /* getconf.c in Sources */,
+ BA4B7A291373C30100003422 /* confstr.c in Sources */,
+ BA4B7A2A1373C30100003422 /* limits.c in Sources */,
+ BA4B7A2B1373C30100003422 /* pathconf.c in Sources */,
+ BA4B7A2C1373C30100003422 /* progenv.c in Sources */,
+ BA4B7A2D1373C30100003422 /* sysconf.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A40137648E100003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A511376492600003422 /* chat.c in Sources */,
+ BA4B7A521376492B00003422 /* init.c in Sources */,
+ BA4B7A531376493000003422 /* main.c in Sources */,
+ BA4B7A541376493500003422 /* subr.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A5E13765CC700003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A6713765CF500003422 /* hostinfo.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A6A13765D3E00003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A7313765D5D00003422 /* iostat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4B7A7E13765F3C00003422 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4B7A9213765F7C00003422 /* latency.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD2EB1372FB3D0025925C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD2FC1372FD670025925C /* ac.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD3051372FFD80025925C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD310137300080025925C /* accton.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD31B137300ED0025925C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD325137301200025925C /* arch.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA4FD3391373073E0025925C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA4FD344137307750025925C /* at.c in Sources */,
+ BA4FD345137307750025925C /* panic.c in Sources */,
+ BA4FD346137307750025925C /* parsetime.c in Sources */,
+ BA4FD347137307750025925C /* perm.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA91CE5A137F42ED00AE5160 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA91CE64137F430E00AE5160 /* kextmanager.defs in Sources */,
+ BA91CE65137F431100AE5160 /* shutdown.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B763A13739ABE001BB39F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B764E13739B1C001BB39F /* atrun.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B765613739C20001BB39F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B766513739C66001BB39F /* file_passwd.c in Sources */,
+ BA9B766613739C66001BB39F /* nis_passwd.c in Sources */,
+ BA9B766713739C66001BB39F /* od_passwd.c in Sources */,
+ BA9B766813739C66001BB39F /* pam_passwd.c in Sources */,
+ BA9B766913739C66001BB39F /* passwd.c in Sources */,
+ BA9B766A13739C66001BB39F /* stringops.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9B76791373A0D8001BB39F /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9B768E1373A14B001BB39F /* chpass.c in Sources */,
+ BA9B768F1373A159001BB39F /* edit.c in Sources */,
+ BA9B76901373A159001BB39F /* field.c in Sources */,
+ BA9B76911373A159001BB39F /* open_directory.c in Sources */,
+ BA9B76921373A159001BB39F /* pw_copy.c in Sources */,
+ BA9B76931373A159001BB39F /* table.c in Sources */,
+ BA9B76941373A159001BB39F /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF48B139680CF0018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF496139681090018C7BB /* sync.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4981396812D0018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4A1139681500018C7BB /* sysctl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4A6139681910018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4B1139682480018C7BB /* trace.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4BF139682BA0018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4C8139682DE0018C7BB /* vifs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4CB139682F80018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4D5139683180018C7BB /* vipw.c in Sources */,
+ BA9BF4D61396831C0018C7BB /* pw_util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4D8139683580018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4E21396838C0018C7BB /* vm_stat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4E4139683EB0018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4EE139684100018C7BB /* zdump.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BA9BF4F0139684B40018C7BB /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BA9BF4FA139684D30018C7BB /* zic.c in Sources */,
+ BA9BF4FB139684D70018C7BB /* scheck.c in Sources */,
+ BA9BF4FC139684DB0018C7BB /* ialloc.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D0E1377B481007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D171377B4A9007728F4 /* mean.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D3E1377B6E2007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D471377B71D007728F4 /* mkfile.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D4A1377B7A7007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D571377B821007728F4 /* newgrp.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BACC1D5A1377B85C007728F4 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BACC1D631377B88B007728F4 /* nologin.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE5899C137836A00049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE589A8137836CA0049DD3B /* nvram.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589BB1378FCAA0049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE589D11378FD340049DD3B /* passwd.c in Sources */,
+ BAE589D01378FD300049DD3B /* file_passwd.c in Sources */,
+ BAE589D8137900730049DD3B /* nis_passwd.c in Sources */,
+ BAE589D9137900770049DD3B /* od_passwd.c in Sources */,
+ BAE589DA1379007C0049DD3B /* pam_passwd.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589DC137902F50049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE589E5137903680049DD3B /* pw_scan.c in Sources */,
+ BAE589E6137903680049DD3B /* pwd_mkdb.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE589E91379044E0049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE589F3137904B90049DD3B /* reboot.c in Sources */,
+ BAE589F2137904B50049DD3B /* kextmanager.defs in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A0A13799F610049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A1313799F950049DD3B /* db.c in Sources */,
+ BAE58A1413799F980049DD3B /* main.c in Sources */,
+ BAE58A1513799F9B0049DD3B /* pdb.c in Sources */,
+ BAE58A1613799F9F0049DD3B /* usrdb.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BAE58A46137D69A60049DD3B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BAE58A50137D69DA0049DD3B /* sc_usage.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C20D8C651C1A102F00C1226B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C214813D1C1A122B003BCA63 /* dyld.c in Sources */,
+ C214813B1C1A122B003BCA63 /* corefile.c in Sources */,
+ C214813A1C1A1219003BCA63 /* utils.c in Sources */,
+ C214813C1C1A122B003BCA63 /* dyld_shared_cache.c in Sources */,
+ C21481381C1A1213003BCA63 /* vm.c in Sources */,
+ C21481391C1A1216003BCA63 /* vanilla.c in Sources */,
+ C214813E1C1A122B003BCA63 /* main.c in Sources */,
+ C2DAA94F1D9F22F000FAC263 /* convert.c in Sources */,
+ C214813F1C1A122B003BCA63 /* sparse.c in Sources */,
+ C21481401C1A122B003BCA63 /* threads.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C625B28416D6F27E00168EF7 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C625B28B16D6F27E00168EF7 /* taskpolicy.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C96F50AF15BDCEC3008682F7 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C96F50BE15BDFF03008682F7 /* lsmp.c in Sources */,
+ 72F9316D18C26A8600D804C5 /* port_details.c in Sources */,
+ 72D1FDD918C4140600C1E05F /* task_details.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F2291F511FFEBB6A00161936 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F2291F601FFEBB9E00161936 /* zlog.c in Sources */,
+ F27B702B2045038B003C04FC /* SymbolicationHelper.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 08CE3D361E6E24CC00DF1B78 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 08CE3D281E6E22A200DF1B78 /* stackshot */;
+ targetProxy = 08CE3D351E6E24CC00DF1B78 /* PBXContainerItemProxy */;
+ };
+ 08CE3D381E6E24DF00DF1B78 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 08CE3D281E6E22A200DF1B78 /* stackshot */;
+ targetProxy = 08CE3D371E6E24DF00DF1B78 /* PBXContainerItemProxy */;
+ };
+ 08DC48901A12C6F0008AAF38 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 08DC48841A12C21B008AAF38 /* kpgo */;
+ targetProxy = 08DC488F1A12C6F0008AAF38 /* PBXContainerItemProxy */;
+ };
+ 08DC48921A12C6FA008AAF38 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 08DC48841A12C21B008AAF38 /* kpgo */;
+ targetProxy = 08DC48911A12C6FA008AAF38 /* PBXContainerItemProxy */;
+ };
+ 1523FE6F1595069900661E82 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 1523FE5A1595048900661E82 /* ltop */;
+ targetProxy = 1523FE6E1595069900661E82 /* PBXContainerItemProxy */;
+ };
+ 1523FE711595069F00661E82 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 1523FE5A1595048900661E82 /* ltop */;
+ targetProxy = 1523FE701595069F00661E82 /* PBXContainerItemProxy */;
+ };
+ 1812F18D1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C20D8C681C1A102F00C1226B /* gcore */;
+ targetProxy = 1812F18E1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F18F1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 78DE9DDF1B5045DE00FE6DF5 /* wait4path */;
+ targetProxy = 1812F1901C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1911C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97999D211AE84C0E00E8B10F /* lskq */;
+ targetProxy = 1812F1921C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1931C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 08DC48841A12C21B008AAF38 /* kpgo */;
+ targetProxy = 1812F1941C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1991C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 550C19E21804D226001DA380 /* iosim */;
+ targetProxy = 1812F19A1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F19B1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = ADA9006F17679A8C00161ADF /* purge */;
+ targetProxy = 1812F19C1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F19D1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C625B28716D6F27E00168EF7 /* taskpolicy */;
+ targetProxy = 1812F19E1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F19F1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */;
+ targetProxy = 1812F1A01C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1A11C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C96F50AE15BDCEC3008682F7 /* lsmp */;
+ targetProxy = 1812F1A21C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1A31C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 1523FE5A1595048900661E82 /* ltop */;
+ targetProxy = 1812F1A41C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1A51C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA959E7E13968C8E00CA9C60 /* zoneinfo */;
+ targetProxy = 1812F1A61C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1A71C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA0A860713968E8500D2272C /* zprint */;
+ targetProxy = 1812F1A81C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1A91C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4BE139682BA0018C7BB /* vifs */;
+ targetProxy = 1812F1AA1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1AB1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4CA139682F80018C7BB /* vipw */;
+ targetProxy = 1812F1AC1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1AD1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4D7139683580018C7BB /* vm_stat */;
+ targetProxy = 1812F1AE1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1AF1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4E3139683EB0018C7BB /* zdump */;
+ targetProxy = 1812F1B01C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1B11C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4EF139684B40018C7BB /* zic */;
+ targetProxy = 1812F1B21C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1B31C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF48A139680CF0018C7BB /* sync */;
+ targetProxy = 1812F1B41C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1B51C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4971396812D0018C7BB /* sysctl */;
+ targetProxy = 1812F1B61C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1B71C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4A5139681910018C7BB /* trace */;
+ targetProxy = 1812F1B81C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1B91C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A45137D69A60049DD3B /* sc_usage */;
+ targetProxy = 1812F1BA1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1BB1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A0913799F610049DD3B /* sa */;
+ targetProxy = 1812F1BC1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1BD1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589DB137902F50049DD3B /* pwd_mkdb */;
+ targetProxy = 1812F1BE1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1BF1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589E81379044E0049DD3B /* reboot */;
+ targetProxy = 1812F1C01C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1C11C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589F5137904DF0049DD3B /* halt */;
+ targetProxy = 1812F1C21C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1C31C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589BA1378FCAA0049DD3B /* passwd */;
+ targetProxy = 1812F1C41C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1C51C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE5899B137836A00049DD3B /* nvram */;
+ targetProxy = 1812F1C61C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1C71C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589AA137837130049DD3B /* pagesize */;
+ targetProxy = 1812F1C81C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1C91C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D3D1377B6E2007728F4 /* mkfile */;
+ targetProxy = 1812F1CA1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1CB1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D491377B7A7007728F4 /* newgrp */;
+ targetProxy = 1812F1CC1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1CD1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D591377B85C007728F4 /* nologin */;
+ targetProxy = 1812F1CE1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1CF1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD2EE1372FB3D0025925C /* ac */;
+ targetProxy = 1812F1D01C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1D11C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3041372FFD80025925C /* accton */;
+ targetProxy = 1812F1D21C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1D31C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD31A137300ED0025925C /* arch */;
+ targetProxy = 1812F1D41C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1D51C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD32F137305DD0025925C /* machine */;
+ targetProxy = 1812F1D61C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1D71C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79C51373A72800003422 /* dmesg */;
+ targetProxy = 1812F1D81C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1D91C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79E01373AF7A00003422 /* dynamic_pager */;
+ targetProxy = 1812F1DA1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1DB1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79FD1373B9E900003422 /* fs_usage */;
+ targetProxy = 1812F1DC1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1DD1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A0E1373BE9D00003422 /* getconf */;
+ targetProxy = 1812F1DE1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1DF1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A3F137648E100003422 /* getty */;
+ targetProxy = 1812F1E01C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1E11C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A5D13765CC700003422 /* hostinfo */;
+ targetProxy = 1812F1E21C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1E31C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A6913765D3E00003422 /* iostat */;
+ targetProxy = 1812F1E41C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1E51C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A7D13765F3C00003422 /* latency */;
+ targetProxy = 1812F1E61C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1E71C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA473DA01377B2230005CC19 /* login */;
+ targetProxy = 1812F1E81C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 1812F1EB1C8F923900F3DC9E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D0D1377B481007728F4 /* mean */;
+ targetProxy = 1812F1EC1C8F923900F3DC9E /* PBXContainerItemProxy */;
+ };
+ 358407D22245AD40006A0D8E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 3521C84C2245AA92001B3201 /* cpuctl */;
+ targetProxy = 358407D12245AD40006A0D8E /* PBXContainerItemProxy */;
+ };
+ 358407D42245AD4B006A0D8E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 3521C84C2245AA92001B3201 /* cpuctl */;
+ targetProxy = 358407D32245AD4B006A0D8E /* PBXContainerItemProxy */;
+ };
+ 358407D62245AD55006A0D8E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 3521C84C2245AA92001B3201 /* cpuctl */;
+ targetProxy = 358407D52245AD55006A0D8E /* PBXContainerItemProxy */;
+ };
+ 550C19EF1804D2AD001DA380 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 550C19E21804D226001DA380 /* iosim */;
+ targetProxy = 550C19EE1804D2AD001DA380 /* PBXContainerItemProxy */;
+ };
+ 550C19F11804D2B7001DA380 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 550C19E21804D226001DA380 /* iosim */;
+ targetProxy = 550C19F01804D2B7001DA380 /* PBXContainerItemProxy */;
+ };
+ 55CCB17816B851E900B56979 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */;
+ targetProxy = 55CCB17716B851E900B56979 /* PBXContainerItemProxy */;
+ };
+ 55CCB17A16B851F300B56979 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 55CCB16A16B84EDA00B56979 /* vm_purgeable_stat */;
+ targetProxy = 55CCB17916B851F300B56979 /* PBXContainerItemProxy */;
+ };
+ 78DE9DED1B5048D400FE6DF5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 78DE9DDF1B5045DE00FE6DF5 /* wait4path */;
+ targetProxy = 78DE9DEC1B5048D400FE6DF5 /* PBXContainerItemProxy */;
+ };
+ 78DE9DFA1B504D1200FE6DF5 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 78DE9DDF1B5045DE00FE6DF5 /* wait4path */;
+ targetProxy = 78DE9DF91B504D1200FE6DF5 /* PBXContainerItemProxy */;
+ };
+ 8E556A4B1D3FF7A40038D48B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8EC3915B1C9733C2001E28E6 /* proc_uuid_policy */;
+ targetProxy = 8E556A4A1D3FF7A40038D48B /* PBXContainerItemProxy */;
+ };
+ 8EC3916E1C973440001E28E6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8EC3915B1C9733C2001E28E6 /* proc_uuid_policy */;
+ targetProxy = 8EC3916D1C973440001E28E6 /* PBXContainerItemProxy */;
+ };
+ 926913A21EC706010079D787 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 0D06BC5D1E8F08CB00C6EC2D /* mslutil */;
+ targetProxy = 926913A11EC706010079D787 /* PBXContainerItemProxy */;
+ };
+ 926913A41EC706080079D787 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 0D06BC5D1E8F08CB00C6EC2D /* mslutil */;
+ targetProxy = 926913A31EC706080079D787 /* PBXContainerItemProxy */;
+ };
+ 926913A61EC706130079D787 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 0D06BC5D1E8F08CB00C6EC2D /* mslutil */;
+ targetProxy = 926913A51EC706130079D787 /* PBXContainerItemProxy */;
+ };
+ 97999D351AE84D3A00E8B10F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97999D211AE84C0E00E8B10F /* lskq */;
+ targetProxy = 97999D341AE84D3A00E8B10F /* PBXContainerItemProxy */;
+ };
+ 97999D371AE84D4100E8B10F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 97999D211AE84C0E00E8B10F /* lskq */;
+ targetProxy = 97999D361AE84D4100E8B10F /* PBXContainerItemProxy */;
+ };
+ ADA9007E1767A31300161ADF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = ADA9006F17679A8C00161ADF /* purge */;
+ targetProxy = ADA9007D1767A31300161ADF /* PBXContainerItemProxy */;
+ };
+ ADA900801767A31900161ADF /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = ADA9006F17679A8C00161ADF /* purge */;
+ targetProxy = ADA9007F1767A31900161ADF /* PBXContainerItemProxy */;
+ };
+ B194EC55185A8BDD00E2A1A6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B158E39F185A836700474677 /* wordexp-helper */;
+ targetProxy = B194EC54185A8BDD00E2A1A6 /* PBXContainerItemProxy */;
+ };
+ B3F0E6DF16E97142008FAD09 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = B3F0E6CC16E96FC2008FAD09 /* memory_pressure */;
+ targetProxy = B3F0E6DE16E97142008FAD09 /* PBXContainerItemProxy */;
+ };
+ BA0A861613968ECA00D2272C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA0A860713968E8500D2272C /* zprint */;
+ targetProxy = BA0A861513968ECA00D2272C /* PBXContainerItemProxy */;
+ };
+ BA0A861813968ED500D2272C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA0A860713968E8500D2272C /* zprint */;
+ targetProxy = BA0A861713968ED500D2272C /* PBXContainerItemProxy */;
+ };
+ BA0A861A1396B41F00D2272C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA959E7E13968C8E00CA9C60 /* zoneinfo */;
+ targetProxy = BA0A86191396B41F00D2272C /* PBXContainerItemProxy */;
+ };
+ BA0A861C1396B42600D2272C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA959E7E13968C8E00CA9C60 /* zoneinfo */;
+ targetProxy = BA0A861B1396B42600D2272C /* PBXContainerItemProxy */;
+ };
+ BA4B79DB1373A9CE00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79C51373A72800003422 /* dmesg */;
+ targetProxy = BA4B79DA1373A9CE00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B79F81373B06B00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79E01373AF7A00003422 /* dynamic_pager */;
+ targetProxy = BA4B79F71373B06B00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A0C1373BA8D00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79FD1373B9E900003422 /* fs_usage */;
+ targetProxy = BA4B7A0B1373BA8D00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A211373BF5000003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A0E1373BE9D00003422 /* getconf */;
+ targetProxy = BA4B7A201373BF5000003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A5A137649FA00003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A3F137648E100003422 /* getty */;
+ targetProxy = BA4B7A59137649FA00003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A7A13765DC100003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A5D13765CC700003422 /* hostinfo */;
+ targetProxy = BA4B7A7913765DC100003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A7C13765DC600003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A6913765D3E00003422 /* iostat */;
+ targetProxy = BA4B7A7B13765DC600003422 /* PBXContainerItemProxy */;
+ };
+ BA4B7A981376600200003422 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A7D13765F3C00003422 /* latency */;
+ targetProxy = BA4B7A971376600200003422 /* PBXContainerItemProxy */;
+ };
+ BA4FD3031372FE730025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD2EE1372FB3D0025925C /* ac */;
+ targetProxy = BA4FD3021372FE730025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD3121373001C0025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3041372FFD80025925C /* accton */;
+ targetProxy = BA4FD3111373001C0025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD329137301370025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD31A137300ED0025925C /* arch */;
+ targetProxy = BA4FD328137301370025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD334137305E80025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD31A137300ED0025925C /* arch */;
+ targetProxy = BA4FD333137305E80025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD337137306260025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD32F137305DD0025925C /* machine */;
+ targetProxy = BA4FD336137306260025925C /* PBXContainerItemProxy */;
+ };
+ BA4FD350137307BC0025925C /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3381373073E0025925C /* at */;
+ targetProxy = BA4FD34F137307BC0025925C /* PBXContainerItemProxy */;
+ };
+ BA91CE6A137F43A500AE5160 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA91CE59137F42ED00AE5160 /* shutdown */;
+ targetProxy = BA91CE69137F43A500AE5160 /* PBXContainerItemProxy */;
+ };
+ BA959E8813968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4BE139682BA0018C7BB /* vifs */;
+ targetProxy = BA959E8713968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E8A13968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4CA139682F80018C7BB /* vipw */;
+ targetProxy = BA959E8913968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E8C13968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4D7139683580018C7BB /* vm_stat */;
+ targetProxy = BA959E8B13968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E8E13968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4E3139683EB0018C7BB /* zdump */;
+ targetProxy = BA959E8D13968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9013968D8A00CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4EF139684B40018C7BB /* zic */;
+ targetProxy = BA959E8F13968D8A00CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9213968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4BE139682BA0018C7BB /* vifs */;
+ targetProxy = BA959E9113968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9413968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4CA139682F80018C7BB /* vipw */;
+ targetProxy = BA959E9313968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9613968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4D7139683580018C7BB /* vm_stat */;
+ targetProxy = BA959E9513968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9813968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4E3139683EB0018C7BB /* zdump */;
+ targetProxy = BA959E9713968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA959E9A13968DA900CA9C60 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4EF139684B40018C7BB /* zic */;
+ targetProxy = BA959E9913968DA900CA9C60 /* PBXContainerItemProxy */;
+ };
+ BA9B765413739B89001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B763913739ABE001BB39F /* atrun */;
+ targetProxy = BA9B765313739B89001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B767513739E07001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B765513739C20001BB39F /* chkpasswd */;
+ targetProxy = BA9B767413739E07001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76A01373A257001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76781373A0D8001BB39F /* chpass */;
+ targetProxy = BA9B769F1373A257001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76A21373A2A2001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76781373A0D8001BB39F /* chpass */;
+ targetProxy = BA9B76A31373A2A2001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76A81373A2CF001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76781373A0D8001BB39F /* chpass */;
+ targetProxy = BA9B76A71373A2CF001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76AA1373A2CF001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76991373A246001BB39F /* chfn */;
+ targetProxy = BA9B76A91373A2CF001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9B76AC1373A2CF001BB39F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9B76A11373A2A2001BB39F /* chsh */;
+ targetProxy = BA9B76AB1373A2CF001BB39F /* PBXContainerItemProxy */;
+ };
+ BA9BF4B3139682710018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF48A139680CF0018C7BB /* sync */;
+ targetProxy = BA9BF4B2139682710018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4B5139682710018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4971396812D0018C7BB /* sysctl */;
+ targetProxy = BA9BF4B4139682710018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4B7139682710018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4A5139681910018C7BB /* trace */;
+ targetProxy = BA9BF4B6139682710018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4B9139682880018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF48A139680CF0018C7BB /* sync */;
+ targetProxy = BA9BF4B8139682880018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4BB139682880018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4971396812D0018C7BB /* sysctl */;
+ targetProxy = BA9BF4BA139682880018C7BB /* PBXContainerItemProxy */;
+ };
+ BA9BF4BD139682880018C7BB /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA9BF4A5139681910018C7BB /* trace */;
+ targetProxy = BA9BF4BC139682880018C7BB /* PBXContainerItemProxy */;
+ };
+ BAAEB3A413730D6B003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3381373073E0025925C /* at */;
+ targetProxy = BAAEB3A313730D6B003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3A613730DFA003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3381373073E0025925C /* at */;
+ targetProxy = BAAEB3A713730DFA003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3AD13730E1C003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3381373073E0025925C /* at */;
+ targetProxy = BAAEB3AE13730E1C003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3B413730E43003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAAEB39C13730D5C003EA7A9 /* atq */;
+ targetProxy = BAAEB3B313730E43003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3B613730E43003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAAEB3A513730DFA003EA7A9 /* atrm */;
+ targetProxy = BAAEB3B513730E43003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BAAEB3B813730E43003EA7A9 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAAEB3AC13730E1C003EA7A9 /* batch */;
+ targetProxy = BAAEB3B713730E43003EA7A9 /* PBXContainerItemProxy */;
+ };
+ BACC1D001377B3A4007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA473DA01377B2230005CC19 /* login */;
+ targetProxy = BACC1CFF1377B3A4007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D1C1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD2EE1372FB3D0025925C /* ac */;
+ targetProxy = BACC1D1B1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D1E1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD3041372FFD80025925C /* accton */;
+ targetProxy = BACC1D1D1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D201377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD31A137300ED0025925C /* arch */;
+ targetProxy = BACC1D1F1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D221377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4FD32F137305DD0025925C /* machine */;
+ targetProxy = BACC1D211377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D241377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79C51373A72800003422 /* dmesg */;
+ targetProxy = BACC1D231377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D281377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79E01373AF7A00003422 /* dynamic_pager */;
+ targetProxy = BACC1D271377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D2A1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B79FD1373B9E900003422 /* fs_usage */;
+ targetProxy = BACC1D291377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D2C1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A0E1373BE9D00003422 /* getconf */;
+ targetProxy = BACC1D2B1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D2E1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A3F137648E100003422 /* getty */;
+ targetProxy = BACC1D2D1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D301377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A5D13765CC700003422 /* hostinfo */;
+ targetProxy = BACC1D2F1377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D321377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A6913765D3E00003422 /* iostat */;
+ targetProxy = BACC1D311377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D341377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA4B7A7D13765F3C00003422 /* latency */;
+ targetProxy = BACC1D331377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D361377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BA473DA01377B2230005CC19 /* login */;
+ targetProxy = BACC1D351377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D3A1377B58A007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D0D1377B481007728F4 /* mean */;
+ targetProxy = BACC1D391377B58A007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D681377B8DC007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D3D1377B6E2007728F4 /* mkfile */;
+ targetProxy = BACC1D671377B8DC007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D6A1377B8DC007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D491377B7A7007728F4 /* newgrp */;
+ targetProxy = BACC1D691377B8DC007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D6C1377B8DC007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D591377B85C007728F4 /* nologin */;
+ targetProxy = BACC1D6B1377B8DC007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D6E1377B8ED007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D3D1377B6E2007728F4 /* mkfile */;
+ targetProxy = BACC1D6D1377B8ED007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D701377B8ED007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D491377B7A7007728F4 /* newgrp */;
+ targetProxy = BACC1D6F1377B8ED007728F4 /* PBXContainerItemProxy */;
+ };
+ BACC1D721377B8ED007728F4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BACC1D591377B85C007728F4 /* nologin */;
+ targetProxy = BACC1D711377B8ED007728F4 /* PBXContainerItemProxy */;
+ };
+ BAE589B1137837AA0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE5899B137836A00049DD3B /* nvram */;
+ targetProxy = BAE589B0137837AA0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589B3137837AA0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589AA137837130049DD3B /* pagesize */;
+ targetProxy = BAE589B2137837AA0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589B5137837B30049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE5899B137836A00049DD3B /* nvram */;
+ targetProxy = BAE589B4137837B30049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589B7137837B30049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589AA137837130049DD3B /* pagesize */;
+ targetProxy = BAE589B6137837B30049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589D41378FDF40049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589BA1378FCAA0049DD3B /* passwd */;
+ targetProxy = BAE589D31378FDF40049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589D61378FDFB0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589BA1378FCAA0049DD3B /* passwd */;
+ targetProxy = BAE589D51378FDFB0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589FC137905080049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589E81379044E0049DD3B /* reboot */;
+ targetProxy = BAE589FB137905080049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE589FE137905740049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589DB137902F50049DD3B /* pwd_mkdb */;
+ targetProxy = BAE589FD137905740049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A00137905740049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589E81379044E0049DD3B /* reboot */;
+ targetProxy = BAE589FF137905740049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A02137905740049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589F5137904DF0049DD3B /* halt */;
+ targetProxy = BAE58A01137905740049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A041379057F0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589DB137902F50049DD3B /* pwd_mkdb */;
+ targetProxy = BAE58A031379057F0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A061379057F0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589E81379044E0049DD3B /* reboot */;
+ targetProxy = BAE58A051379057F0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A081379057F0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE589F5137904DF0049DD3B /* halt */;
+ targetProxy = BAE58A071379057F0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A2E1379A1260049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A0913799F610049DD3B /* sa */;
+ targetProxy = BAE58A2D1379A1260049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A321379A1300049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A0913799F610049DD3B /* sa */;
+ targetProxy = BAE58A311379A1300049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A54137D69FB0049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A45137D69A60049DD3B /* sc_usage */;
+ targetProxy = BAE58A53137D69FB0049DD3B /* PBXContainerItemProxy */;
+ };
+ BAE58A56137D6A050049DD3B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BAE58A45137D69A60049DD3B /* sc_usage */;
+ targetProxy = BAE58A55137D6A050049DD3B /* PBXContainerItemProxy */;
+ };
+ C21481471C1A1447003BCA63 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C20D8C681C1A102F00C1226B /* gcore */;
+ targetProxy = C21481461C1A1447003BCA63 /* PBXContainerItemProxy */;
+ };
+ C21481491C1A14AD003BCA63 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C20D8C681C1A102F00C1226B /* gcore */;
+ targetProxy = C21481481C1A14AD003BCA63 /* PBXContainerItemProxy */;
+ };
+ C625B29116D6F38700168EF7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C625B28716D6F27E00168EF7 /* taskpolicy */;
+ targetProxy = C625B29016D6F38700168EF7 /* PBXContainerItemProxy */;
+ };
+ C625B29316D6F39000168EF7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C625B28716D6F27E00168EF7 /* taskpolicy */;
+ targetProxy = C625B29216D6F39000168EF7 /* PBXContainerItemProxy */;
+ };
+ C96F50BA15BDFDA7008682F7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C96F50AE15BDCEC3008682F7 /* lsmp */;
+ targetProxy = C96F50B915BDFDA7008682F7 /* PBXContainerItemProxy */;
+ };
+ C96F50BC15BDFDB1008682F7 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C96F50AE15BDCEC3008682F7 /* lsmp */;
+ targetProxy = C96F50BB15BDFDB1008682F7 /* PBXContainerItemProxy */;
+ };
+ F2291F641FFEBC4000161936 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F2291F501FFEBB6A00161936 /* zlog */;
+ targetProxy = F2291F631FFEBC4000161936 /* PBXContainerItemProxy */;
+ };
+ F2291F661FFEBC4700161936 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F2291F501FFEBB6A00161936 /* zlog */;
+ targetProxy = F2291F651FFEBC4700161936 /* PBXContainerItemProxy */;
+ };
+ F2291F681FFEBC4F00161936 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F2291F501FFEBB6A00161936 /* zlog */;
+ targetProxy = F2291F671FFEBC4F00161936 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 08CE3D2D1E6E22A200DF1B78 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ };
+ name = Release;
+ };
+ 08CE3D2E1E6E22A200DF1B78 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ };
+ name = Debug;
+ };
+ 08DC48891A12C21C008AAF38 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ };
+ name = Release;
+ };
+ 08DC488A1A12C21C008AAF38 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(inherited)",
+ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ );
+ MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ };
+ name = Debug;
+ };
+ 0D06BC621E8F08CB00C6EC2D /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ };
+ name = Release;
+ };
+ 0D06BC631E8F08CB00C6EC2D /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ MACOSX_DEPLOYMENT_TARGET = 10.13;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ };
+ name = Debug;
+ };
+ 1523FE621595048900661E82 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = ltop;
+ };
+ name = Release;
+ };
+ 1812F1F01C8F923900F3DC9E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 1812F1F11C8F923900F3DC9E /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 18732FE218CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C913CA2E2228B622000051A0 /* base.xcconfig */;
+ buildSettings = {
+ APPLY_RULES_IN_COPY_FILES = YES;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ PLIST_FILE_OUTPUT_FORMAT = binary;
+ SUPPORTED_PLATFORMS = "macosx watchos iphoneos";
+ WARNING_CFLAGS = (
+ "-Wall",
+ "-Wcast-align",
+ );
+ };
+ name = Debug;
+ };
+ 18732FE318CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 18732FE418CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 18732FE518CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 18732FE618CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = accton;
+ };
+ name = Debug;
+ };
+ 18732FE718CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = arch;
+ };
+ name = Debug;
+ };
+ 18732FE818CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 18732FE918CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "DAEMON_UID=1",
+ "DAEMON_GID=1",
+ "DEFAULT_AT_QUEUE=\\'a\\'",
+ "DEFAULT_BATCH_QUEUE=\\'b\\'",
+ "PERM_PATH=\\\"/usr/lib/cron/\\\"",
+ );
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = at;
+ };
+ name = Debug;
+ };
+ 18732FEA18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = atq;
+ };
+ name = Debug;
+ };
+ 18732FEB18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = atrm;
+ };
+ name = Debug;
+ };
+ 18732FEC18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = batch;
+ };
+ name = Debug;
+ };
+ 18732FED18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "DAEMON_UID=1",
+ "DAEMON_GID=1",
+ );
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = atrun;
+ };
+ name = Debug;
+ };
+ 18732FEE18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = chkpasswd;
+ };
+ name = Debug;
+ };
+ 18732FEF18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ OPEN_DIRECTORY,
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = chpass;
+ };
+ name = Debug;
+ };
+ 18732FF018CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = chfn;
+ };
+ name = Debug;
+ };
+ 18732FF118CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = chsh;
+ };
+ name = Debug;
+ };
+ 18732FF218CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = dmesg;
+ };
+ name = Debug;
+ };
+ 18732FF418CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = dynamic_pager.tproj/entitlements.plist;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ NO_DIRECT_RPC,
+ );
+ INSTALL_PATH = /sbin;
+ OTHER_MIGFLAGS = "-R -untyped -DNO_DIRECT_RPC";
+ PRODUCT_NAME = dynamic_pager;
+ };
+ name = Debug;
+ };
+ 18732FF518CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = fs_usage;
+ VALID_ARCHS = "$(ARCHS_STANDARD)";
+ };
+ name = Debug;
+ };
+ 18732FF618CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ APPLE_GETCONF_UNDERSCORE,
+ APPLE_GETCONF_SPEC,
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = getconf;
+ };
+ name = Debug;
+ };
+ 18732FF718CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = getty;
+ };
+ name = Debug;
+ };
+ 18732FF818CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = hostinfo;
+ };
+ name = Debug;
+ };
+ 18732FF918CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = iostat;
+ };
+ name = Debug;
+ };
+ 18732FFA18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = latency;
+ };
+ name = Debug;
+ };
+ 18732FFB18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = login.tproj/login.entitlements;
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ "$(inherited)",
+ USE_PAM,
+ USE_BSM_AUDIT,
+ );
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-lbsm",
+ "-lpam",
+ );
+ PRODUCT_NAME = login;
+ };
+ name = Debug;
+ };
+ 18732FFC18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = ltop;
+ };
+ name = Debug;
+ };
+ 18732FFE18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = mean;
+ };
+ name = Debug;
+ };
+ 18732FFF18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = mkfile;
+ };
+ name = Debug;
+ };
+ 1873300018CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = newgrp;
+ };
+ name = Debug;
+ };
+ 1873300118CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = nologin;
+ };
+ name = Debug;
+ };
+ 1873300218CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/local/include";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = nvram;
+ };
+ name = Debug;
+ };
+ 1873300318CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = pagesize;
+ };
+ name = Debug;
+ };
+ 1873300418CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = passwd.tproj/passwd.entitlements;
+ INSTALL_PATH = /usr/bin;
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-framework",
+ CoreFoundation,
+ "-framework",
+ OpenDirectory,
+ "-lpam",
+ );
+ PRODUCT_NAME = passwd;
+ };
+ name = Debug;
+ };
+ 1873300518CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "_PW_NAME_LEN=MAXLOGNAME",
+ "_PW_YPTOKEN=\\\"__YP!\\\"",
+ );
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = pwd_mkdb;
+ };
+ name = Debug;
+ };
+ 1873300618CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = reboot;
+ };
+ name = Debug;
+ };
+ 1873300718CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = halt;
+ };
+ name = Debug;
+ };
+ 1873300818CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "AHZV1=64",
+ );
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = sa;
+ };
+ name = Debug;
+ };
+ 1873300B18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = sc_usage;
+ };
+ name = Debug;
+ };
+ 1873300C18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = shutdown;
+ };
+ name = Debug;
+ };
+ 1873300D18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = sync;
+ };
+ name = Debug;
+ };
+ 1873300E18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = sysctl;
+ };
+ name = Debug;
+ };
+ 1873300F18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = trace;
+ };
+ name = Debug;
+ };
+ 1873301018CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = vifs;
+ };
+ name = Debug;
+ };
+ 1873301118CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = vipw;
+ };
+ name = Debug;
+ };
+ 1873301218CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = vm_stat;
+ };
+ name = Debug;
+ };
+ 1873301318CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/lib/system;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 1873301418CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = zdump;
+ };
+ name = Debug;
+ };
+ 1873301518CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = zic;
+ };
+ name = Debug;
+ };
+ 1873301618CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = zoneinfo;
+ };
+ name = Debug;
+ };
+ 1873301718CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = zprint.tproj/entitlements.plist;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Kernel.framework/PrivateHeaders/mach",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = zprint;
+ };
+ name = Debug;
+ };
+ 1873301818CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "CODE_SIGN_ENTITLEMENTS[sdk=*]" = lsmp.tproj/entitlements.plist;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = lsmp;
+ };
+ name = Debug;
+ };
+ 1873301918CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "";
+ "CODE_SIGN_ENTITLEMENTS[sdk=*]" = vm_purgeable_stat.tproj/entitlements.plist;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = vm_purgeable_stat;
+ };
+ name = Debug;
+ };
+ 1873301A18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "taskpolicy.tproj/taskpolicy-entitlements.plist";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 1873301B18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/bin;
+ OTHER_CFLAGS = "-isystem$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ PRODUCT_NAME = memory_pressure;
+ };
+ name = Debug;
+ };
+ 1873301C18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = purge;
+ };
+ name = Debug;
+ };
+ 1873301D18CBD4A700275344 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = iosim;
+ };
+ name = Debug;
+ };
+ 3521C8522245AA92001B3201 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = cpuctl;
+ };
+ name = Release;
+ };
+ 3521C8532245AA92001B3201 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = cpuctl;
+ };
+ name = Debug;
+ };
+ 550C19EA1804D226001DA380 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = iosim;
+ };
+ name = Release;
+ };
+ 55CCB17216B84EDA00B56979 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "CODE_SIGN_ENTITLEMENTS[sdk=*]" = vm_purgeable_stat.tproj/entitlements.plist;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = vm_purgeable_stat;
+ };
+ name = Release;
+ };
+ 78DE9DE51B5045DE00FE6DF5 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = NO;
+ CLANG_WARN_BOOL_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
+ CLANG_WARN_INT_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
+ CLANG_WARN_OBJC_ROOT_CLASS = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ DARWIN_BUNDLE_IDENTIFIER = "\"com.apple.system_cmds.wait4path\"";
+ DARWIN_COPYRIGHT = "\"Copyright 2013 Apple Inc. All rights reserved.\"";
+ DARWIN_DISPLAY_NAME = "\"Darwin Filesystem Path Waiter\"";
+ DARWIN_DISPLAY_VERSION = "\"1.0.0\"";
+ DARWIN_INCREMENTAL_VERSION = "\"$CURRENT_PROJECT_VERSION\"";
+ DARWIN_VARIANT = RELEASE;
+ DARWIN_VARIANT_LOWER = "$(DARWIN_VARIANT_LOWER_$(DARWIN_VARIANT))";
+ DARWIN_VARIANT_LOWER_DEBUG = debug;
+ DARWIN_VARIANT_LOWER_DEVELOPMENT = development;
+ DARWIN_VARIANT_LOWER_RELEASE = release;
+ DARWIN_VARIANT_SUFFIX = "$(DARWIN_VARIANT_SUFFIX_$(DARWIN_VARIANT))";
+ DARWIN_VARIANT_SUFFIX_DEBUG = .debug;
+ DARWIN_VARIANT_SUFFIX_DEVELOPMENT = .development;
+ DARWIN_VARIANT_SUFFIX_RELEASE = "";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = YES;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALLED_PRODUCT_ASIDES = YES;
+ INSTALL_PATH = /bin;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ New_Setting14GCC_ENABLE_OBJC_GC = unsupported;
+ PRODUCT_NAME = wait4path;
+ STRIP_INSTALLED_PRODUCT_debug = NO;
+ USE_HEADERMAP = NO;
+ WANTS_GET_TASK_ALLOW = NO;
+ XPC_ALL_THE_DEBUGS2 = "";
+ XPC_ALL_THE_DEBUGS2_yes = "-O0 -g -fno-inline -fno-limit-debug-info";
+ XPC_BUILD_EXPORT_DEFAULTS = "-DXPC_PROJECT_EXPORT=XPC_EXPORT -DXPC_DEBUGEXPORT=XPC_NOEXPORT -DXPC_TESTEXPORT=XPC_NOEXPORT";
+ XPC_BUILD_FILES_DIR = "$(PROJECT_DIR)/xcfiles";
+ XPC_BUILD_HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(PROJECT_DIR)/src $(PROJECT_DIR)/interface $(PROJECT_DIR)/launch $(PROJECT_DIR)/support $(PROJECT_DIR)/development $(PROJECT_DIR)";
+ XPC_BUILD_HOST = currentmajor;
+ XPC_BUILD_OTHER_CFLAGS = "$(XPC_ALL_THE_DEBUGS2_$(XPC_ALL_THE_DEBUGS)) $(XPC_COMPATIBILITY_DEFINES_$(XPC_BUILD_HOST)) -D__XPC_PROJECT_BUILD__=1";
+ XPC_BUILD_XCCONFIG_DIR = "$(PROJECT_DIR)/xcconfig";
+ XPC_BUILD_XCSCRIPTS_DIR = "$(PROJECT_DIR)/xcscripts";
+ XPC_COMPATIBILITY_DEFINES_currentmajor = "-DHAVE_KDEBUG_TRACE=1 -DCONFIG_EMULATE_XNU_INITPROC_SELECTION=0 -DHAVE_GALARCH_AVAILABILITY=1";
+ XPC_COMPATIBILITY_DEFINES_lastmajor = "-DHAVE_KDEBUG_TRACE=0 -DCONFIG_EMULATE_XNU_INITPROC_SELECTION=1 -DHAVE_GALARCH_AVAILABILITY=0";
+ XPC_CRASHREPORTCLIENT_LDFLAGS = "-lCrashReporterClient";
+ XPC_EXECUTABLE_OTHER_CFLAGS = "$(XPC_BUILD_OTHER_CFLAGS) $(XPC_BUILD_EXPORT_DEFAULTS) -DXPC_BUILD_TARGET_EXECUTABLE=1";
+ XPC_EXECUTABLE_OTHER_LDFLAGS = "$(XPC_EXECUTABLE_WORKAROUND_14483011) $(XPC_CRASHREPORTCLIENT_LDFLAGS)";
+ XPC_EXECUTABLE_WORKAROUND_14483011 = "-lSystem -lobjc";
+ XPC_NOSTRIP = no;
+ XPC_NOSTRIP2_no = YES;
+ XPC_NOSTRIP2_yes = NO;
+ };
+ name = Release;
+ };
+ 78DE9DE61B5045DE00FE6DF5 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = YES;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = NO;
+ CLANG_ENABLE_OBJC_ARC = NO;
+ CLANG_WARN_BOOL_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
+ CLANG_WARN_INT_CONVERSION = "$(CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION)";
+ CLANG_WARN_OBJC_ROOT_CLASS = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = YES;
+ DARWIN_BUNDLE_IDENTIFIER = "\"com.apple.system_cmds.wait4path\"";
+ DARWIN_COPYRIGHT = "\"Copyright 2013 Apple Inc. All rights reserved.\"";
+ DARWIN_DISPLAY_NAME = "\"Darwin Filesystem Path Waiter\"";
+ DARWIN_DISPLAY_VERSION = "\"1.0.0\"";
+ DARWIN_INCREMENTAL_VERSION = "\"$CURRENT_PROJECT_VERSION\"";
+ DARWIN_VARIANT = RELEASE;
+ DARWIN_VARIANT_LOWER = "$(DARWIN_VARIANT_LOWER_$(DARWIN_VARIANT))";
+ DARWIN_VARIANT_LOWER_DEBUG = debug;
+ DARWIN_VARIANT_LOWER_DEVELOPMENT = development;
+ DARWIN_VARIANT_LOWER_RELEASE = release;
+ DARWIN_VARIANT_SUFFIX = "$(DARWIN_VARIANT_SUFFIX_$(DARWIN_VARIANT))";
+ DARWIN_VARIANT_SUFFIX_DEBUG = .debug;
+ DARWIN_VARIANT_SUFFIX_DEVELOPMENT = .development;
+ DARWIN_VARIANT_SUFFIX_RELEASE = "";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "";
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALLED_PRODUCT_ASIDES = YES;
+ INSTALL_PATH = /bin;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ New_Setting14GCC_ENABLE_OBJC_GC = unsupported;
+ ONLY_ACTIVE_ARCH = YES;
+ PRODUCT_NAME = wait4path;
+ STRIP_INSTALLED_PRODUCT_debug = NO;
+ USE_HEADERMAP = NO;
+ WANTS_GET_TASK_ALLOW = NO;
+ XPC_ALL_THE_DEBUGS2 = "";
+ XPC_ALL_THE_DEBUGS2_yes = "-O0 -g -fno-inline -fno-limit-debug-info";
+ XPC_BUILD_EXPORT_DEFAULTS = "-DXPC_PROJECT_EXPORT=XPC_EXPORT -DXPC_DEBUGEXPORT=XPC_NOEXPORT -DXPC_TESTEXPORT=XPC_NOEXPORT";
+ XPC_BUILD_FILES_DIR = "$(PROJECT_DIR)/xcfiles";
+ XPC_BUILD_HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(PROJECT_DIR)/src $(PROJECT_DIR)/interface $(PROJECT_DIR)/launch $(PROJECT_DIR)/support $(PROJECT_DIR)/development $(PROJECT_DIR)";
+ XPC_BUILD_HOST = currentmajor;
+ XPC_BUILD_OTHER_CFLAGS = "$(XPC_ALL_THE_DEBUGS2_$(XPC_ALL_THE_DEBUGS)) $(XPC_COMPATIBILITY_DEFINES_$(XPC_BUILD_HOST)) -D__XPC_PROJECT_BUILD__=1";
+ XPC_BUILD_XCCONFIG_DIR = "$(PROJECT_DIR)/xcconfig";
+ XPC_BUILD_XCSCRIPTS_DIR = "$(PROJECT_DIR)/xcscripts";
+ XPC_COMPATIBILITY_DEFINES_currentmajor = "-DHAVE_KDEBUG_TRACE=1 -DCONFIG_EMULATE_XNU_INITPROC_SELECTION=0 -DHAVE_GALARCH_AVAILABILITY=1";
+ XPC_COMPATIBILITY_DEFINES_lastmajor = "-DHAVE_KDEBUG_TRACE=0 -DCONFIG_EMULATE_XNU_INITPROC_SELECTION=1 -DHAVE_GALARCH_AVAILABILITY=0";
+ XPC_CRASHREPORTCLIENT_LDFLAGS = "-lCrashReporterClient";
+ XPC_EXECUTABLE_OTHER_CFLAGS = "$(XPC_BUILD_OTHER_CFLAGS) $(XPC_BUILD_EXPORT_DEFAULTS) -DXPC_BUILD_TARGET_EXECUTABLE=1";
+ XPC_EXECUTABLE_OTHER_LDFLAGS = "$(XPC_EXECUTABLE_WORKAROUND_14483011) $(XPC_CRASHREPORTCLIENT_LDFLAGS)";
+ XPC_EXECUTABLE_WORKAROUND_14483011 = "-lSystem -lobjc";
+ XPC_NOSTRIP = no;
+ XPC_NOSTRIP2_no = YES;
+ XPC_NOSTRIP2_yes = NO;
+ };
+ name = Debug;
+ };
+ 8EC391631C9733C2001E28E6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ 8EC391641C9733C2001E28E6 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ 97999D2B1AE84C0E00E8B10F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = lskq;
+ };
+ name = Release;
+ };
+ 97999D2C1AE84C0E00E8B10F /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = lskq;
+ };
+ name = Debug;
+ };
+ ADA9007617679A8C00161ADF /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = purge;
+ };
+ name = Release;
+ };
+ B158E3A6185A836700474677 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/lib/system;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ B3F0E6D416E96FC2008FAD09 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/bin;
+ OTHER_CFLAGS = "-isystem$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ PRODUCT_NAME = memory_pressure;
+ };
+ name = Release;
+ };
+ BA0A860F13968E8500D2272C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = zprint.tproj/entitlements.plist;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Kernel.framework/PrivateHeaders/mach",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = zprint;
+ };
+ name = Release;
+ };
+ BA2DE91E1372FA9100D1913C /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C913CA2E2228B622000051A0 /* base.xcconfig */;
+ buildSettings = {
+ APPLY_RULES_IN_COPY_FILES = YES;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ PLIST_FILE_OUTPUT_FORMAT = binary;
+ SUPPORTED_PLATFORMS = "macosx watchos iphoneos";
+ WARNING_CFLAGS = (
+ "-Wall",
+ "-Wcast-align",
+ );
+ };
+ name = Release;
+ };
+ BA473DB21377B2230005CC19 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = login.tproj/login.entitlements;
+ "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*][arch=*]" = (
+ "$(inherited)",
+ USE_PAM,
+ USE_BSM_AUDIT,
+ );
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-lbsm",
+ "-lpam",
+ );
+ PRODUCT_NAME = login;
+ };
+ name = Release;
+ };
+ BA4B79CC1373A72800003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = dmesg;
+ };
+ name = Release;
+ };
+ BA4B79EB1373AF7A00003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = dynamic_pager.tproj/entitlements.plist;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ NO_DIRECT_RPC,
+ );
+ INSTALL_PATH = /sbin;
+ OTHER_MIGFLAGS = "-R -untyped -DNO_DIRECT_RPC";
+ PRODUCT_NAME = dynamic_pager;
+ };
+ name = Release;
+ };
+ BA4B7A041373B9E900003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = fs_usage;
+ VALID_ARCHS = "$(ARCHS_STANDARD)";
+ };
+ name = Release;
+ };
+ BA4B7A151373BE9D00003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ APPLE_GETCONF_UNDERSCORE,
+ APPLE_GETCONF_SPEC,
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = getconf;
+ };
+ name = Release;
+ };
+ BA4B7A4E137648E100003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = getty;
+ };
+ name = Release;
+ };
+ BA4B7A6413765CC700003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = hostinfo;
+ };
+ name = Release;
+ };
+ BA4B7A7013765D3E00003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = iostat;
+ };
+ name = Release;
+ };
+ BA4B7A8F13765F3C00003422 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = latency;
+ };
+ name = Release;
+ };
+ BA4FD2F81372FB3D0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BA4FD3011372FE4E0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BA4FD30C1372FFD80025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = accton;
+ };
+ name = Release;
+ };
+ BA4FD322137300ED0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = arch;
+ };
+ name = Release;
+ };
+ BA4FD332137305DD0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BA4FD3401373073E0025925C /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "DAEMON_UID=1",
+ "DAEMON_GID=1",
+ "DEFAULT_AT_QUEUE=\\'a\\'",
+ "DEFAULT_BATCH_QUEUE=\\'b\\'",
+ "PERM_PATH=\\\"/usr/lib/cron/\\\"",
+ );
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = at;
+ };
+ name = Release;
+ };
+ BA91CE61137F42ED00AE5160 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = shutdown;
+ };
+ name = Release;
+ };
+ BA959E8313968C8E00CA9C60 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = zoneinfo;
+ };
+ name = Release;
+ };
+ BA9B764B13739ABE001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "DAEMON_UID=1",
+ "DAEMON_GID=1",
+ );
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = atrun;
+ };
+ name = Release;
+ };
+ BA9B766213739C20001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/libexec;
+ PRODUCT_NAME = chkpasswd;
+ };
+ name = Release;
+ };
+ BA9B768B1373A0D8001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ OPEN_DIRECTORY,
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = chpass;
+ };
+ name = Release;
+ };
+ BA9B769E1373A246001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = chfn;
+ };
+ name = Release;
+ };
+ BA9B76A61373A2A2001BB39F /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = chsh;
+ };
+ name = Release;
+ };
+ BA9BF491139680CF0018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = sync;
+ };
+ name = Release;
+ };
+ BA9BF49E1396812D0018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = sysctl;
+ };
+ name = Release;
+ };
+ BA9BF4AD139681910018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = trace;
+ };
+ name = Release;
+ };
+ BA9BF4C5139682BA0018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = vifs;
+ };
+ name = Release;
+ };
+ BA9BF4D1139682F80018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = vipw;
+ };
+ name = Release;
+ };
+ BA9BF4DE139683580018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = vm_stat;
+ };
+ name = Release;
+ };
+ BA9BF4EA139683EB0018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = zdump;
+ };
+ name = Release;
+ };
+ BA9BF4F6139684B40018C7BB /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = zic;
+ };
+ name = Release;
+ };
+ BAAEB3A213730D5C003EA7A9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = atq;
+ };
+ name = Release;
+ };
+ BAAEB3AB13730DFA003EA7A9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = atrm;
+ };
+ name = Release;
+ };
+ BAAEB3B213730E1C003EA7A9 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = batch;
+ };
+ name = Release;
+ };
+ BACC1D141377B481007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = mean;
+ };
+ name = Release;
+ };
+ BACC1D1A1377B4C9007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ BACC1D441377B6E2007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = mkfile;
+ };
+ name = Release;
+ };
+ BACC1D541377B7A7007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_MODE_FLAG = "u+s,a+rx,a-w";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = newgrp;
+ };
+ name = Release;
+ };
+ BACC1D601377B85C007728F4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = nologin;
+ };
+ name = Release;
+ };
+ BAE589A4137836A00049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/local/include";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = nvram;
+ };
+ name = Release;
+ };
+ BAE589AF137837130049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = pagesize;
+ };
+ name = Release;
+ };
+ BAE589CD1378FCAA0049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = passwd.tproj/passwd.entitlements;
+ INSTALL_PATH = /usr/bin;
+ "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
+ "-framework",
+ CoreFoundation,
+ "-framework",
+ OpenDirectory,
+ "-lpam",
+ );
+ PRODUCT_NAME = passwd;
+ };
+ name = Release;
+ };
+ BAE589E2137902F50049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "_PW_NAME_LEN=MAXLOGNAME",
+ "_PW_YPTOKEN=\\\"__YP!\\\"",
+ );
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = pwd_mkdb;
+ };
+ name = Release;
+ };
+ BAE589EF1379044E0049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ PRODUCT_NAME = reboot;
+ };
+ name = Release;
+ };
+ BAE589FA137904DF0049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = halt;
+ };
+ name = Release;
+ };
+ BAE58A1013799F610049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(inherited)",
+ "AHZV1=64",
+ );
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = sa;
+ };
+ name = Release;
+ };
+ BAE58A4D137D69A60049DD3B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = sc_usage;
+ };
+ name = Release;
+ };
+ C20D8C6D1C1A102F00C1226B /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+ CLANG_WARN_ASSIGN_ENUM = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = "gcore.tproj/gcore-entitlements.plist";
+ FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Kernel.framework/PrivateHeaders";
+ GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+ GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ C20D8C6E1C1A102F00C1226B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+ CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+ CLANG_WARN_ASSIGN_ENUM = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
+ CODE_SIGN_ENTITLEMENTS = "gcore.tproj/gcore-entitlements.plist";
+ FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Kernel.framework/PrivateHeaders";
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+ GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+ GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+ GCC_WARN_SHADOW = YES;
+ GCC_WARN_SIGN_COMPARE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNKNOWN_PRAGMAS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_LABEL = YES;
+ GCC_WARN_UNUSED_PARAMETER = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ C625B28E16D6F27E00168EF7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = "taskpolicy.tproj/taskpolicy-entitlements.plist";
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders";
+ INSTALL_PATH = /usr/sbin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ C96F50B615BDCEC3008682F7 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ "CODE_SIGN_ENTITLEMENTS[sdk=*]" = lsmp.tproj/entitlements.plist;
+ GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+ HEADER_SEARCH_PATHS = "";
+ INSTALL_PATH = /usr/bin;
+ PRODUCT_NAME = lsmp;
+ };
+ name = Release;
+ };
+ F2291F5B1FFEBB6A00161936 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = zlog.tproj/entitlements.plist;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Kernel.framework/PrivateHeaders/mach",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ F2291F5C1FFEBB6A00161936 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_ENTITLEMENTS = zlog.tproj/entitlements.plist;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+ );
+ HEADER_SEARCH_PATHS = (
+ "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Kernel.framework/PrivateHeaders/mach",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders",
+ "$(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders/bsd",
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 08CE3D2F1E6E22A200DF1B78 /* Build configuration list for PBXNativeTarget "stackshot" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 08CE3D2D1E6E22A200DF1B78 /* Release */,
+ 08CE3D2E1E6E22A200DF1B78 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 08DC488B1A12C21C008AAF38 /* Build configuration list for PBXNativeTarget "kpgo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 08DC48891A12C21C008AAF38 /* Release */,
+ 08DC488A1A12C21C008AAF38 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 0D06BC641E8F08CB00C6EC2D /* Build configuration list for PBXNativeTarget "mslutil" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 0D06BC621E8F08CB00C6EC2D /* Release */,
+ 0D06BC631E8F08CB00C6EC2D /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1523FE611595048900661E82 /* Build configuration list for PBXNativeTarget "ltop" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1523FE621595048900661E82 /* Release */,
+ 18732FFC18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1812F1EF1C8F923900F3DC9E /* Build configuration list for PBXAggregateTarget "All_Bridge" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1812F1F01C8F923900F3DC9E /* Release */,
+ 1812F1F11C8F923900F3DC9E /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 3521C8512245AA92001B3201 /* Build configuration list for PBXNativeTarget "cpuctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 3521C8522245AA92001B3201 /* Release */,
+ 3521C8532245AA92001B3201 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 550C19E91804D226001DA380 /* Build configuration list for PBXNativeTarget "iosim" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 550C19EA1804D226001DA380 /* Release */,
+ 1873301D18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 55CCB17116B84EDA00B56979 /* Build configuration list for PBXNativeTarget "vm_purgeable_stat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 55CCB17216B84EDA00B56979 /* Release */,
+ 1873301918CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 78DE9DE41B5045DE00FE6DF5 /* Build configuration list for PBXNativeTarget "wait4path" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 78DE9DE51B5045DE00FE6DF5 /* Release */,
+ 78DE9DE61B5045DE00FE6DF5 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 8EC391621C9733C2001E28E6 /* Build configuration list for PBXNativeTarget "proc_uuid_policy" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8EC391631C9733C2001E28E6 /* Release */,
+ 8EC391641C9733C2001E28E6 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 97999D2A1AE84C0E00E8B10F /* Build configuration list for PBXNativeTarget "lskq" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 97999D2B1AE84C0E00E8B10F /* Release */,
+ 97999D2C1AE84C0E00E8B10F /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ ADA9007517679A8C00161ADF /* Build configuration list for PBXNativeTarget "purge" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ ADA9007617679A8C00161ADF /* Release */,
+ 1873301C18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B158E3A7185A836700474677 /* Build configuration list for PBXNativeTarget "wordexp-helper" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B158E3A6185A836700474677 /* Release */,
+ 1873301318CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ B3F0E6D316E96FC2008FAD09 /* Build configuration list for PBXNativeTarget "memory_pressure" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ B3F0E6D416E96FC2008FAD09 /* Release */,
+ 1873301B18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA0A860E13968E8500D2272C /* Build configuration list for PBXNativeTarget "zprint" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA0A860F13968E8500D2272C /* Release */,
+ 1873301718CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA2DE91B1372FA9100D1913C /* Build configuration list for PBXProject "system_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA2DE91E1372FA9100D1913C /* Release */,
+ 18732FE218CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA473DB11377B2230005CC19 /* Build configuration list for PBXNativeTarget "login" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA473DB21377B2230005CC19 /* Release */,
+ 18732FFB18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B79CB1373A72800003422 /* Build configuration list for PBXNativeTarget "dmesg" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B79CC1373A72800003422 /* Release */,
+ 18732FF218CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B79EA1373AF7A00003422 /* Build configuration list for PBXNativeTarget "dynamic_pager" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B79EB1373AF7A00003422 /* Release */,
+ 18732FF418CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A031373B9E900003422 /* Build configuration list for PBXNativeTarget "fs_usage" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A041373B9E900003422 /* Release */,
+ 18732FF518CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A141373BE9D00003422 /* Build configuration list for PBXNativeTarget "getconf" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A151373BE9D00003422 /* Release */,
+ 18732FF618CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A4D137648E100003422 /* Build configuration list for PBXNativeTarget "getty" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A4E137648E100003422 /* Release */,
+ 18732FF718CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A6313765CC700003422 /* Build configuration list for PBXNativeTarget "hostinfo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A6413765CC700003422 /* Release */,
+ 18732FF818CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A6F13765D3E00003422 /* Build configuration list for PBXNativeTarget "iostat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A7013765D3E00003422 /* Release */,
+ 18732FF918CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4B7A8E13765F3C00003422 /* Build configuration list for PBXNativeTarget "latency" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4B7A8F13765F3C00003422 /* Release */,
+ 18732FFA18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD2F91372FB3D0025925C /* Build configuration list for PBXNativeTarget "ac" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD2F81372FB3D0025925C /* Release */,
+ 18732FE518CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD2FF1372FE4E0025925C /* Build configuration list for PBXAggregateTarget "All_MacOSX" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD3011372FE4E0025925C /* Release */,
+ 18732FE318CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD30A1372FFD80025925C /* Build configuration list for PBXNativeTarget "accton" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD30C1372FFD80025925C /* Release */,
+ 18732FE618CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD320137300ED0025925C /* Build configuration list for PBXNativeTarget "arch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD322137300ED0025925C /* Release */,
+ 18732FE718CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD330137305DD0025925C /* Build configuration list for PBXAggregateTarget "machine" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD332137305DD0025925C /* Release */,
+ 18732FE818CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA4FD33E1373073E0025925C /* Build configuration list for PBXNativeTarget "at" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA4FD3401373073E0025925C /* Release */,
+ 18732FE918CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA91CE60137F42ED00AE5160 /* Build configuration list for PBXNativeTarget "shutdown" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA91CE61137F42ED00AE5160 /* Release */,
+ 1873300C18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA959E8213968C8E00CA9C60 /* Build configuration list for PBXAggregateTarget "zoneinfo" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA959E8313968C8E00CA9C60 /* Release */,
+ 1873301618CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B764A13739ABE001BB39F /* Build configuration list for PBXNativeTarget "atrun" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B764B13739ABE001BB39F /* Release */,
+ 18732FED18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B766113739C20001BB39F /* Build configuration list for PBXNativeTarget "chkpasswd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B766213739C20001BB39F /* Release */,
+ 18732FEE18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B768A1373A0D8001BB39F /* Build configuration list for PBXNativeTarget "chpass" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B768B1373A0D8001BB39F /* Release */,
+ 18732FEF18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B769D1373A246001BB39F /* Build configuration list for PBXAggregateTarget "chfn" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B769E1373A246001BB39F /* Release */,
+ 18732FF018CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9B76A51373A2A2001BB39F /* Build configuration list for PBXAggregateTarget "chsh" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9B76A61373A2A2001BB39F /* Release */,
+ 18732FF118CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF490139680CF0018C7BB /* Build configuration list for PBXNativeTarget "sync" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF491139680CF0018C7BB /* Release */,
+ 1873300D18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF49D1396812D0018C7BB /* Build configuration list for PBXNativeTarget "sysctl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF49E1396812D0018C7BB /* Release */,
+ 1873300E18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4AC139681910018C7BB /* Build configuration list for PBXNativeTarget "trace" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4AD139681910018C7BB /* Release */,
+ 1873300F18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4C4139682BA0018C7BB /* Build configuration list for PBXNativeTarget "vifs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4C5139682BA0018C7BB /* Release */,
+ 1873301018CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4D0139682F80018C7BB /* Build configuration list for PBXNativeTarget "vipw" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4D1139682F80018C7BB /* Release */,
+ 1873301118CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4DD139683580018C7BB /* Build configuration list for PBXNativeTarget "vm_stat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4DE139683580018C7BB /* Release */,
+ 1873301218CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4E9139683EB0018C7BB /* Build configuration list for PBXNativeTarget "zdump" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4EA139683EB0018C7BB /* Release */,
+ 1873301418CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BA9BF4F5139684B40018C7BB /* Build configuration list for PBXNativeTarget "zic" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BA9BF4F6139684B40018C7BB /* Release */,
+ 1873301518CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAAEB3A013730D5C003EA7A9 /* Build configuration list for PBXAggregateTarget "atq" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAAEB3A213730D5C003EA7A9 /* Release */,
+ 18732FEA18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAAEB3A913730DFA003EA7A9 /* Build configuration list for PBXAggregateTarget "atrm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAAEB3AB13730DFA003EA7A9 /* Release */,
+ 18732FEB18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAAEB3B013730E1C003EA7A9 /* Build configuration list for PBXAggregateTarget "batch" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAAEB3B213730E1C003EA7A9 /* Release */,
+ 18732FEC18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D131377B481007728F4 /* Build configuration list for PBXNativeTarget "mean" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D141377B481007728F4 /* Release */,
+ 18732FFE18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D191377B4C9007728F4 /* Build configuration list for PBXAggregateTarget "All_iOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D1A1377B4C9007728F4 /* Release */,
+ 18732FE418CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D431377B6E2007728F4 /* Build configuration list for PBXNativeTarget "mkfile" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D441377B6E2007728F4 /* Release */,
+ 18732FFF18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D531377B7A7007728F4 /* Build configuration list for PBXNativeTarget "newgrp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D541377B7A7007728F4 /* Release */,
+ 1873300018CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BACC1D5F1377B85C007728F4 /* Build configuration list for PBXNativeTarget "nologin" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BACC1D601377B85C007728F4 /* Release */,
+ 1873300118CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589A3137836A00049DD3B /* Build configuration list for PBXNativeTarget "nvram" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589A4137836A00049DD3B /* Release */,
+ 1873300218CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589AE137837130049DD3B /* Build configuration list for PBXAggregateTarget "pagesize" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589AF137837130049DD3B /* Release */,
+ 1873300318CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589CC1378FCAA0049DD3B /* Build configuration list for PBXNativeTarget "passwd" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589CD1378FCAA0049DD3B /* Release */,
+ 1873300418CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589E1137902F50049DD3B /* Build configuration list for PBXNativeTarget "pwd_mkdb" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589E2137902F50049DD3B /* Release */,
+ 1873300518CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589EE1379044E0049DD3B /* Build configuration list for PBXNativeTarget "reboot" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589EF1379044E0049DD3B /* Release */,
+ 1873300618CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE589F9137904DF0049DD3B /* Build configuration list for PBXAggregateTarget "halt" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE589FA137904DF0049DD3B /* Release */,
+ 1873300718CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE58A0F13799F610049DD3B /* Build configuration list for PBXNativeTarget "sa" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE58A1013799F610049DD3B /* Release */,
+ 1873300818CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BAE58A4C137D69A60049DD3B /* Build configuration list for PBXNativeTarget "sc_usage" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BAE58A4D137D69A60049DD3B /* Release */,
+ 1873300B18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C20D8C6F1C1A102F00C1226B /* Build configuration list for PBXNativeTarget "gcore" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C20D8C6D1C1A102F00C1226B /* Release */,
+ C20D8C6E1C1A102F00C1226B /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C625B28F16D6F27E00168EF7 /* Build configuration list for PBXNativeTarget "taskpolicy" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C625B28E16D6F27E00168EF7 /* Release */,
+ 1873301A18CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C96F50B515BDCEC3008682F7 /* Build configuration list for PBXNativeTarget "lsmp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C96F50B615BDCEC3008682F7 /* Release */,
+ 1873301818CBD4A700275344 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F2291F5A1FFEBB6A00161936 /* Build configuration list for PBXNativeTarget "zlog" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F2291F5B1FFEBB6A00161936 /* Release */,
+ F2291F5C1FFEBB6A00161936 /* Debug */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = BA2DE9181372FA9100D1913C /* Project object */;
+}
diff --git a/system_cmds/system_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/system_cmds/system_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..e0da4fe
--- /dev/null
+++ b/system_cmds/system_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:system_cmds.xcodeproj">
+ </FileRef>
+</Workspace>
diff --git a/system_cmds/system_cmds.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/system_cmds/system_cmds.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..ff23ebc
--- /dev/null
+++ b/system_cmds/system_cmds.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
+ <false/>
+ <key>PreviewsEnabled</key>
+ <false/>
+</dict>
+</plist>
diff --git a/system_cmds/system_cmds.xcodeproj/xcshareddata/xcschemes/All_MacOSX.xcscheme b/system_cmds/system_cmds.xcodeproj/xcshareddata/xcschemes/All_MacOSX.xcscheme
new file mode 100644
index 0000000..0510fcf
--- /dev/null
+++ b/system_cmds/system_cmds.xcodeproj/xcshareddata/xcschemes/All_MacOSX.xcscheme
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0600"
+ version = "1.8">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "NO">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BA4FD2FE1372FE4E0025925C"
+ BuildableName = "All_MacOSX"
+ BlueprintName = "All_MacOSX"
+ ReferencedContainer = "container:system_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Release"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ </Testables>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Release"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BA4FD2FE1372FE4E0025925C"
+ BuildableName = "All_MacOSX"
+ BlueprintName = "All_MacOSX"
+ ReferencedContainer = "container:system_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release"
+ includeDebugSupportFiles = "YES">
+ </InstallAction>
+</Scheme>
diff --git a/system_cmds/system_cmds.xcodeproj/xcshareddata/xcschemes/All_iOS.xcscheme b/system_cmds/system_cmds.xcodeproj/xcshareddata/xcschemes/All_iOS.xcscheme
new file mode 100644
index 0000000..5251285
--- /dev/null
+++ b/system_cmds/system_cmds.xcodeproj/xcshareddata/xcschemes/All_iOS.xcscheme
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+ LastUpgradeVersion = "0600"
+ version = "1.7">
+ <BuildAction
+ parallelizeBuildables = "YES"
+ buildImplicitDependencies = "NO">
+ <BuildActionEntries>
+ <BuildActionEntry
+ buildForTesting = "YES"
+ buildForRunning = "YES"
+ buildForProfiling = "YES"
+ buildForArchiving = "YES"
+ buildForAnalyzing = "YES">
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BACC1D181377B4C9007728F4"
+ BuildableName = "All_iOS"
+ BlueprintName = "All_iOS"
+ ReferencedContainer = "container:system_cmds.xcodeproj">
+ </BuildableReference>
+ </BuildActionEntry>
+ </BuildActionEntries>
+ </BuildAction>
+ <TestAction
+ buildConfiguration = "Release"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+ shouldUseLaunchSchemeArgsEnv = "YES">
+ <Testables>
+ </Testables>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </TestAction>
+ <LaunchAction
+ buildConfiguration = "Release"
+ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+ launchStyle = "0"
+ useCustomWorkingDirectory = "NO"
+ ignoresPersistentStateOnLaunch = "NO"
+ debugDocumentVersioning = "YES"
+ debugServiceExtension = "internal"
+ allowLocationSimulation = "YES">
+ <MacroExpansion>
+ <BuildableReference
+ BuildableIdentifier = "primary"
+ BlueprintIdentifier = "BACC1D181377B4C9007728F4"
+ BuildableName = "All_iOS"
+ BlueprintName = "All_iOS"
+ ReferencedContainer = "container:system_cmds.xcodeproj">
+ </BuildableReference>
+ </MacroExpansion>
+ <AdditionalOptions>
+ </AdditionalOptions>
+ </LaunchAction>
+ <ProfileAction
+ buildConfiguration = "Release"
+ shouldUseLaunchSchemeArgsEnv = "YES"
+ savedToolIdentifier = ""
+ useCustomWorkingDirectory = "NO"
+ debugDocumentVersioning = "YES">
+ </ProfileAction>
+ <AnalyzeAction
+ buildConfiguration = "Release">
+ </AnalyzeAction>
+ <ArchiveAction
+ buildConfiguration = "Release"
+ revealArchiveInOrganizer = "YES">
+ </ArchiveAction>
+ <InstallAction
+ buildConfiguration = "Release"
+ includeDebugSupportFiles = "YES">
+ </InstallAction>
+</Scheme>
diff --git a/system_cmds/taskpolicy.tproj/taskpolicy-entitlements.plist b/system_cmds/taskpolicy.tproj/taskpolicy-entitlements.plist
new file mode 100644
index 0000000..39c14ef
--- /dev/null
+++ b/system_cmds/taskpolicy.tproj/taskpolicy-entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.cs.debugger.root</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/taskpolicy.tproj/taskpolicy.8 b/system_cmds/taskpolicy.tproj/taskpolicy.8
new file mode 100644
index 0000000..b13af54
--- /dev/null
+++ b/system_cmds/taskpolicy.tproj/taskpolicy.8
@@ -0,0 +1,75 @@
+.Dd 2/21/13
+.Dt taskpolicy 8
+.Os Darwin
+.Sh NAME
+.Nm taskpolicy
+.Nd execute a program with an altered I/O or scheduling policy or change settings of already running process
+.Sh SYNOPSIS
+.Nm
+.Op Fl d Ar policy
+.Op Fl g Ar policy
+.Op Fl c Ar clamp
+.Op Fl b
+.Op Fl t Ar thruput_tier
+.Op Fl l Ar latency_tier
+.Op Fl a
+.Ar program
+.Oo
+.Ar arg1
+.Op Ar ...
+.Oc
+.Nm
+.Op Fl b|-B
+.Op Fl t Ar thruput_tier
+.Op Fl l Ar latency_tier
+.Op Fl p Ar pid
+.Sh DESCRIPTION
+The
+.Nm
+program uses the
+.Xr setiopolicy_np 3
+and
+.Xr setpriority 2
+APIs to execute a program with altered I/O or scheduling policies. All
+children of the specified program also inherit these policies.
+.Pp
+.Nm
+accepts the following flags and arguments:
+.Bl -tag -width "d policy " -offset indent
+.It Fl d Ar policy
+Run the program after calling
+.Xr setiopolicy_np 3
+with an iotype of IOPOL_TYPE_DISK, a scope of IOPOL_SCOPE_PROCESS, and the
+specified policy. The argument can either be an integer, or a symbolic string
+like "default" or "throttle", which is interpreted case-insensitively.
+.It Fl g Ar policy
+Run the program after calling
+.Xr setiopolicy_np 3
+with an iotype of IOPOL_TYPE_DISK, a scope of IOPOL_SCOPE_DARWIN_BG, and the
+specified policy. The argument is interpreted in the same manner as
+.Fl d .
+.It Fl c Ar clamp
+Run the program using the specified QoS clamp. The argument can be either
+"utility", "background", or "maintenance", which is interpreted case-insensitively.
+.It Fl p Ar pid
+Change settings for the process specified by
+.Ar pid .
+.It Fl b
+Run the program after calling
+.Xr setpriority 2
+with a priority of PRIO_DARWIN_BG.
+.It Fl B
+Move target process out of PRIO_DARWIN_BG.
+.It Fl t
+Set throughput tier of the process to
+.Ar thruput_tier .
+.It Fl l
+Set latency tier of the process to
+.Ar latency_tier .
+.It Fl a
+Run the program with the resource management policies given to applications.
+.El
+.Pp
+.Sh SEE ALSO
+.Xr setpriority 2 ,
+.Xr setiopolicy_np 3
diff --git a/system_cmds/taskpolicy.tproj/taskpolicy.c b/system_cmds/taskpolicy.tproj/taskpolicy.c
new file mode 100644
index 0000000..3260bb6
--- /dev/null
+++ b/system_cmds/taskpolicy.tproj/taskpolicy.c
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <err.h>
+#include <sys/errno.h>
+#include <stdbool.h>
+#include <sysexits.h>
+#include <mach/mach.h>
+#include <mach/task_policy.h>
+
+#include <spawn.h>
+#include <spawn_private.h>
+#include <sys/spawn_internal.h>
+
+#define QOS_PARAMETER_LATENCY 0
+#define QOS_PARAMETER_THROUGHPUT 1
+
+extern char **environ;
+
+static void usage(void);
+static int parse_disk_policy(const char *strpolicy);
+static int parse_qos_tier(const char *strpolicy, int parameter);
+static uint64_t parse_qos_clamp(const char *qos_string);
+
+int main(int argc, char * argv[])
+{
+ int ch, ret;
+ pid_t pid = 0;
+ posix_spawnattr_t attr;
+ extern char **environ;
+ bool flagx = false, flagX = false, flagb = false, flagB = false, flaga = false;
+ int flagd = -1, flagg = -1;
+ struct task_qos_policy qosinfo = { LATENCY_QOS_TIER_UNSPECIFIED, THROUGHPUT_QOS_TIER_UNSPECIFIED };
+ uint64_t qos_clamp = POSIX_SPAWN_PROC_CLAMP_NONE;
+
+ while ((ch = getopt(argc, argv, "xXbBd:g:c:t:l:p:a")) != -1) {
+ switch (ch) {
+ case 'x':
+ flagx = true;
+ break;
+ case 'X':
+ flagX = true;
+ break;
+ case 'b':
+ flagb = true;
+ break;
+ case 'B':
+ flagB = true;
+ break;
+ case 'd':
+ flagd = parse_disk_policy(optarg);
+ if (flagd == -1) {
+ warnx("Could not parse '%s' as a disk policy", optarg);
+ usage();
+ }
+ break;
+ case 'g':
+ flagg = parse_disk_policy(optarg);
+ if (flagg == -1) {
+ warnx("Could not parse '%s' as a disk policy", optarg);
+ usage();
+ }
+ break;
+ case 'c':
+ qos_clamp = parse_qos_clamp(optarg);
+ if (qos_clamp == POSIX_SPAWN_PROC_CLAMP_NONE) {
+ warnx("Could not parse '%s' as a QoS clamp", optarg);
+ usage();
+ }
+ break;
+ case 't':
+ qosinfo.task_throughput_qos_tier = parse_qos_tier(optarg, QOS_PARAMETER_THROUGHPUT);
+ if (qosinfo.task_throughput_qos_tier == -1) {
+ warnx("Could not parse '%s' as a qos tier", optarg);
+ usage();
+ }
+ break;
+ case 'l':
+ qosinfo.task_latency_qos_tier = parse_qos_tier(optarg, QOS_PARAMETER_LATENCY);
+ if (qosinfo.task_latency_qos_tier == -1) {
+ warnx("Could not parse '%s' as a qos tier", optarg);
+ usage();
+ }
+ break;
+ case 'p':
+ pid = atoi(optarg);
+ if (pid == 0) {
+ warnx("Invalid pid '%s' specified", optarg);
+ usage();
+ }
+ break;
+ case 'a':
+ flaga = true;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (pid == 0 && argc == 0) {
+ usage();
+ }
+
+ if (pid != 0 && (flagx || flagX || flagg != -1 || flagd != -1)) {
+ warnx("Incompatible option(s) used with -p");
+ usage();
+ }
+
+ if (flagx && flagX){
+ warnx("Incompatible options -x, -X");
+ usage();
+ }
+
+ if (flagb && flagB) {
+ warnx("Incompatible options -b, -B");
+ usage();
+ }
+
+ if (flagB && pid == 0) {
+ warnx("The -B option can only be used with the -p option");
+ usage();
+ }
+
+ if (flagx) {
+ ret = setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY, IOPOL_SCOPE_PROCESS, IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)");
+ }
+ }
+
+ if (flagX) {
+ ret = setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY, IOPOL_SCOPE_PROCESS, IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)");
+ }
+ }
+
+ if (flagb) {
+ ret = setpriority(PRIO_DARWIN_PROCESS, pid, PRIO_DARWIN_BG);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setpriority()");
+ }
+ }
+
+ if (flagB) {
+ ret = setpriority(PRIO_DARWIN_PROCESS, pid, 0);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setpriority()");
+ }
+ }
+
+ if (flagd >= 0) {
+ ret = setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, flagd);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setiopolicy_np(...IOPOL_SCOPE_PROCESS...)");
+ }
+ }
+
+ if (flagg >= 0){
+ ret = setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_DARWIN_BG, flagg);
+ if (ret == -1) {
+ err(EX_SOFTWARE, "setiopolicy_np(...IOPOL_SCOPE_DARWIN_BG...)");
+ }
+ }
+
+ if (qosinfo.task_latency_qos_tier != LATENCY_QOS_TIER_UNSPECIFIED ||
+ qosinfo.task_throughput_qos_tier != THROUGHPUT_QOS_TIER_UNSPECIFIED){
+ mach_port_t task;
+ if (pid) {
+ ret = task_for_pid(mach_task_self(), pid, &task);
+ if (ret != KERN_SUCCESS) {
+ err(EX_SOFTWARE, "task_for_pid(%d) failed", pid);
+ return EX_OSERR;
+ }
+ } else {
+ task = mach_task_self();
+ }
+ ret = task_policy_set((task_t)task, TASK_OVERRIDE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT);
+ if (ret != KERN_SUCCESS){
+ err(EX_SOFTWARE, "task_policy_set(...TASK_OVERRIDE_QOS_POLICY...)");
+ }
+ }
+
+ if (pid != 0)
+ return 0;
+
+ ret = posix_spawnattr_init(&attr);
+ if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_init");
+
+ ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC);
+ if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_setflags");
+
+ if (qos_clamp != POSIX_SPAWN_PROC_CLAMP_NONE) {
+ ret = posix_spawnattr_set_qos_clamp_np(&attr, qos_clamp);
+ if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_set_qos_clamp_np");
+ }
+
+ if (flaga) {
+ ret = posix_spawnattr_setprocesstype_np(&attr, POSIX_SPAWN_PROC_TYPE_APP_DEFAULT);
+ if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_setprocesstype_np");
+
+ ret = posix_spawnattr_set_darwin_role_np(&attr, PRIO_DARWIN_ROLE_UI);
+ if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_set_darwin_role_np");
+ }
+
+ ret = posix_spawnp(&pid, argv[0], NULL, &attr, argv, environ);
+ if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawn");
+
+ return EX_OSERR;
+}
+
+static void usage(void)
+{
+ fprintf(stderr, "Usage: %s [-x|-X] [-d <policy>] [-g policy] [-c clamp] [-b] [-t <tier>]\n"
+ " [-l <tier>] [-a] <program> [<pargs> [...]]\n", getprogname());
+ fprintf(stderr, " %s [-b|-B] [-t <tier>] [-l <tier>] -p pid\n", getprogname());
+ exit(EX_USAGE);
+}
+
+static int parse_disk_policy(const char *strpolicy)
+{
+ long policy;
+ char *endptr = NULL;
+
+ /* first try as an integer */
+ policy = strtol(strpolicy, &endptr, 0);
+ if (endptr && (endptr[0] == '\0') && (strpolicy[0] != '\0')) {
+ /* parsed complete string as a number */
+ return (int)policy;
+ }
+
+ if (0 == strcasecmp(strpolicy, "DEFAULT") ) {
+ return IOPOL_DEFAULT;
+ } else if (0 == strcasecmp(strpolicy, "IMPORTANT")) {
+ return IOPOL_IMPORTANT;
+ } else if (0 == strcasecmp(strpolicy, "PASSIVE")) {
+ return IOPOL_PASSIVE;
+ } else if (0 == strcasecmp(strpolicy, "THROTTLE")) {
+ return IOPOL_THROTTLE;
+ } else if (0 == strcasecmp(strpolicy, "UTILITY")) {
+ return IOPOL_UTILITY;
+ } else if (0 == strcasecmp(strpolicy, "STANDARD")) {
+ return IOPOL_STANDARD;
+ } else {
+ return -1;
+ }
+}
+
+static int parse_qos_tier(const char *strtier, int parameter){
+ long policy;
+ char *endptr = NULL;
+
+ /* first try as an integer */
+ policy = strtol(strtier, &endptr, 0);
+ if (endptr && (endptr[0] == '\0') && (strtier[0] != '\0')) {
+ switch (policy) {
+ case 0:
+ return parameter ? THROUGHPUT_QOS_TIER_0 : LATENCY_QOS_TIER_0;
+ break;
+ case 1:
+ return parameter ? THROUGHPUT_QOS_TIER_1 : LATENCY_QOS_TIER_1;
+ break;
+ case 2:
+ return parameter ? THROUGHPUT_QOS_TIER_2 : LATENCY_QOS_TIER_2;
+ break;
+ case 3:
+ return parameter ? THROUGHPUT_QOS_TIER_3 : LATENCY_QOS_TIER_3;
+ break;
+ case 4:
+ return parameter ? THROUGHPUT_QOS_TIER_4 : LATENCY_QOS_TIER_4;
+ break;
+ case 5:
+ return parameter ? THROUGHPUT_QOS_TIER_5 : LATENCY_QOS_TIER_5;
+ break;
+ default:
+ return -1;
+ break;
+ }
+ }
+
+ return -1;
+}
+
+static uint64_t parse_qos_clamp(const char *qos_string) {
+
+ if (0 == strcasecmp(qos_string, "utility") ) {
+ return POSIX_SPAWN_PROC_CLAMP_UTILITY;
+ } else if (0 == strcasecmp(qos_string, "background")) {
+ return POSIX_SPAWN_PROC_CLAMP_BACKGROUND;
+ } else if (0 == strcasecmp(qos_string, "maintenance")) {
+ return POSIX_SPAWN_PROC_CLAMP_MAINTENANCE;
+ } else {
+ return POSIX_SPAWN_PROC_CLAMP_NONE;
+ }
+}
diff --git a/system_cmds/tests/system_cmds.plist b/system_cmds/tests/system_cmds.plist
new file mode 100644
index 0000000..c536ce4
--- /dev/null
+++ b/system_cmds/tests/system_cmds.plist
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>BATSConfigVersion</key>
+ <string>0.1.0</string>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>Project</key>
+ <string>system_cmds</string>
+ <key>IgnoreOutput</key>
+ <true/>
+ <key>TestSpecificLogs</key>
+ <array>
+ <string>/tmp/system_cmds.*.txt</string>
+ </array>
+ <key>Tests</key>
+ <array>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/bin/lsmp</string>
+ <string>-all</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_lsmp</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/sbin/lsof</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_lsof</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/bin/zprint</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_zprint</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>recon</string>
+ <string>/AppleInternal/Tests/system_cmds/test_zprint.lua</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_zprint_lua</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/bin/hostinfo</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_hostinfo</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/ltop</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_ltop</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <false/>
+ <key>Command</key>
+ <array>
+ <string>/usr/bin/vm_stat</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_vm_stat</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/sbin/dmesg</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_dmesg</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/sbin/sysctl</string>
+ <string>-a</string>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_sysctl</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ <dict>
+ <key>Arch</key>
+ <string>platform-native</string>
+ <key>AsRoot</key>
+ <true/>
+ <key>Command</key>
+ <array>
+ <string>/usr/local/bin/proc_uuid_policy</string>
+ <string>add</string>
+ <string>alt-dyld</string>
+ <string>/usr/bin/yes</string>
+ </array>
+ <key>RequiredResources</key>
+ <array>
+ <dict>
+ <key>Properties</key>
+ <string>deviceClass == &apos;iPhone&apos;</string>
+ </dict>
+ </array>
+ <key>IgnoreCrashes</key>
+ <array/>
+ <key>TestName</key>
+ <string>test_proc_uuid_policy</string>
+ <key>TestSpecificLogs</key>
+ <array/>
+ <key>WorkingDirectory</key>
+ <string>/tmp/</string>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/system_cmds/trace.tproj/trace.1 b/system_cmds/trace.tproj/trace.1
new file mode 100644
index 0000000..afbd280
--- /dev/null
+++ b/system_cmds/trace.tproj/trace.1
@@ -0,0 +1,380 @@
+.\" Copyright (c) 2010, Apple Inc. All rights reserved.
+.\"
+.Dd April 3, 2015
+.Dt TRACE 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm trace
+.Nd configure, record, and display kernel trace events
+.Sh SYNOPSIS
+.Bl -hang -compact -width "trace -"
+.\"
+.It Nm Fl d
+.Op Fl a Ar pid | Fl x Ar pid
+.\"
+.It Nm Fl e
+.Op Fl c Ar class Oo Fl p Ar end-class Oc Oo Fl s Ar subclass Oc
+.Op Fl a Ar pid | Fl x Ar pid
+.Op Fl k Ar code
+.Op Fl P
+.Op Fl T Ar filter-file
+.\"
+.It Nm Fl E
+.Op Fl c Ar class Oo Fl p Ar end-class Oc Oo Fl s Ar subclass Oc
+.Op Fl a Ar pid | Fl x Ar pid
+.Op Fl k Ar code
+.Op Fl P
+.Op Fl T Ar tracefilter
+.Ar command
+.Op Ar argument ...
+.\"
+.It Nm Fl h
+.\"
+.It Nm Fl i
+.Op Fl b Ar num-events
+.\"
+.It Nm Fl g
+.\"
+.It Nm Fl l Ar rawfile
+.\"
+.It Nm Fl L Ar rawfile
+.Op Fl S Ar secs
+.\"
+.It Nm Fl n
+.\"
+.It Nm Fl r
+.\"
+.It Nm Fl R Ar rawfile
+.Op Fl X
+.Op Fl F Ar frequency
+.Op Fl o Ar outfile
+.Op Fl N
+.Op Ar codesfile ...
+.\"
+.It Nm Fl t
+.Op Fl o Ar outfile
+.Op Fl N
+.Op Ar codesfile ...
+.El
+.Sh DESCRIPTION
+.Nm
+initializes and configures the kernel trace subsystem. Trace events can
+be recorded to an in-memory buffer or logged directly to a file, and
+optionally converted to a human-readable, plain-text format.
+.Pp
+.Nm
+operates according to the command flag specified.
+.Pp
+NOTE:
+.Nm
+is obsolete. The command you probably want is
+.Xr ktrace 1
+.Sh COMMANDS
+.Bl -tag -width Ds
+.It Fl h
+Print a succinct help message to
+.Xr stdout 4 .
+.\"
+.\" ## trace -i ##
+.It Fl i Op Fl b Ar num-events
+.Pp
+Initialize the kernel trace buffer. This command is required before
+tracing.
+.Bl -tag -width Ds
+.It Fl b Ar num-events
+Set the number of events that can be stored in the kernel trace buffer.
+.Ar num-events
+is a decimal number of events. The default (and minimum) value is 8192
+event records per logical CPU. No more than half of available
+memory may be used by trace buffers, though running with a buffer this
+large is not recommended.
+.El
+.\"
+.\" ## trace -g ##
+.It Fl g
+Print the current kernel trace buffer settings to
+.Xr stdout 4 .
+.\"
+.\" ## trace -d ##
+.It Fl d Op Fl a Ar pid | Fl x Ar pid
+.Pp
+By default, disable collection of events. This command does not remove
+the kernel trace buffer.
+.Bl -tag -width Ds
+.It Fl a Ar pid
+Disable event collection for the process identified by
+.Ar pid .
+.It Fl x Ar pid
+Stop excluding
+.Ar pid
+from the trace.
+This reenables event collection of events for.
+.Ar pid .
+.El
+.\"
+.\" ## trace -r ##
+.It Fl r
+Remove the kernel trace buffer.
+.\"
+.\" ## trace -n ##
+.It Fl n
+Disable ring buffer mode. When set, the trace buffer will fill to capacity
+and then stop collecting events. Ring buffer mode is sometimes called
+"head," "stop," or "no-wrap" mode. By default, the trace buffer will
+wrap around, overwriting previous events. The default behavior is
+sometimes called windowed or wrap-around mode.
+.\"
+.\" ## trace -e ##
+.Bk -words
+.It Xo Fl e
+.Op Fl c Ar class Oo Fl p Ar end-class Oc Oo Fl s Ar subclass Oc
+.Op Fl a Ar pid | Fl x Ar pid
+.Op Fl k Ar code ...
+.Op Fl P
+.Op Fl T Ar filter-file
+.Ek
+.Xc
+.Pp
+Enable collection of events. By default, all events are collected.
+.Pp
+Options can be used to restrict collection to specific classes, class
+ranges, subclasses, and codes. Classes and subclasses can be specified
+any number of times, but only 4 codes can be filtered at once. Values
+can be specified in hex (0x...), decimal, or octal (0...).
+.Bl -tag -width " "
+.It Fl c Ar class
+Restrict collection to the events with the specified
+.Ar class .
+This option can be specified any number of times to collect events from
+more classes.
+.Bl -tag -width " "
+.It Fl p Ar end-class
+Provide an ending class to restrict collection to events in an inclusive
+range of classes between
+.Ar class
+and
+.Ar end-class .
+.It Fl s Ar subclass
+Restrict collection to the events with the specified
+.Ar subclass .
+.El
+.It Fl a Ar pid
+Restrict collection to to those events emitted by the process identified
+by
+.Ar pid .
+.It Fl x Ar pid
+Exclude events emitted by the process identified by
+.Ar pid .
+.It Fl k Ar code
+Restrict collection to events with the specified
+.Ar code .
+This option can be specified up to 4 times, and applies to all classes
+being collected.
+.It Fl T Ar filter-file
+Restrict collection to events specified in the provided
+.Ar filter-file .
+See
+.Sx TRACEFILTER FORMAT
+for details.
+.It Xo Fl P
+Restrict collection to PPT events. This special collection of trace
+events provides insight into system performance.
+.Xc
+.El
+.\"
+.\" ## trace -E ##
+.Bk -words
+.It Xo Fl E
+.Op Fl c Ar class Oo Fl p Ar end-class Oc Oo Fl s Ar subclass Oc
+.Op Fl a Ar pid | Fl x Ar pid
+.Op Fl k Ar code ...
+.Op Fl P
+.Op Fl T Ar filter-file
+.Ar command Op args ...
+.Ek
+.Xc
+.Pp
+Execute
+.Ar command
+with trace collection enabled for events emitted by the process. See
+.Fl e
+for more information.
+.\"
+.\" ## trace -t ##
+.It Fl t Oo Fl o Ar outfile Oc Oo Fl N Oc Oo Ar codesfile ... Oc
+.Pp
+Extract events from the kernel trace buffer and print them in a formatted,
+plain-text representation. Additional code files can be specified to
+help
+.Nm
+find the names of unknown events. For more information on the formatting
+process, see
+.Sx TRACE CODES FORMAT .
+.Bl -tag -width Ds
+.It Fl o Ar outfile
+Output the plain-text events to
+.Ar outfile .
+.It Fl N
+Ignore the system-wide trace codes file when getting names of events.
+Additional trace codes files specified will still be used.
+.El
+.\"
+.\" ## trace -l ##
+.It Fl l Ar rawfile
+.Pp
+Empty the current kernel trace buffer into
+.Ar rawfile
+in a binary format. If
+.Ar rawfile
+is
+.Li - ,
+the file will be written to
+.Xr stdout 4 .
+.\"
+.\" ## trace -L ##
+.It Fl L Ar rawfile Fl S Ar seconds
+.Pp
+Copy the current trace buffer to
+.Ar rawfile
+and send all future trace events to
+.Ar rawfile .
+.Bl -tag -width Ds
+.It Fl S Ar seconds
+After
+.Ar seconds
+have elapsed, stop recording and exit. If
+.Ar rawfile
+is
+.Li - ,
+the file will be written to
+.Xr stdout 4 .
+.El
+.\"
+.\" ## trace -R ##
+.It Fl R Ar rawfile Oo Fl o Ar outfile Oc Oo Fl N Oc Oo Fl F Ar frequency Oc Oo Fl X Oc Op Ar codesfile ...
+.Pp
+Read events from
+.Ar rawfile
+and print them in a human-readable format.
+.Bl -tag -width " "
+.It Fl F Ar frequency
+If
+.Ar rawfile
+does not contain clock frequency information, it can be specified with
+.Fl F .
+.It Fl X
+Force the binary format to be interpreted as 32-bit, as opposed to
+matching the width of the system running
+.Nm .
+.El
+.Pp
+See
+.Fl t
+for additional options.
+.El
+.Sh TRACE CODES FORMAT
+Event classes, subclasses, and codes are matched to names using a trace
+codes file. Any events that cannot be matched will be referred to by
+their debugid in hex.
+.Pp
+The system-wide trace codes file is located at
+.Pa /usr/share/misc/trace.codes .
+Additional files are typically stored in
+.Pa /usr/local/share/misc .
+.Pp
+A code file consists of a list of tracepoints, one per line, with the
+tracepoint's debugid (component, subclass, and code) in hex, followed by
+a tab, followed by the tracepoint's name.
+.Pp
+For instance, the MSC_mach_msg_trap tracepoint is defined by
+.Pp
+.Dl 0x010c007c MSC_mach_msg_trap
+.Pp
+This describes the tracepoint with the following info:
+.Pp
+.Bl -column -offset indent "Subclass" "MSC_mach_msg_trap"
+.\" is this right? We should refer to the shifting and kdebug.h
+.It Sy Name Ta MSC_mach_msg_trap
+.It Sy Class Ta 0x01 Ta (Mach events)
+.It Sy Subclass Ta 0x0c Ta (Mach system calls)
+.It Sy Code Ta 0x007c Ta (msg_trap)
+.El
+.Pp
+See
+.\" this absolute path no longer exists thanks to SDKs. :P
+.Pa /usr/include/sys/kdebug.h
+for class and subclass values.
+.Sh TRACEFILTER FORMAT
+A tracefilter description file consists of a list of class and subclass
+filters in hex, one per line, which are applied as if they were passed
+with
+.Fl c
+and
+.Fl s .
+Pass
+.Fl v
+to see what classes and subclasses are being set.
+.Pp
+Comment lines start with
+.Ql # ,
+class filter lines start with
+.Ql C ,
+and subclass filter lines start with
+.Ql S
+and include the class they apply to.
+.Pp
+For example, to trace Mach events (class 1):
+.Pp
+.Dl C 0x01
+.Pp
+And to trace Mach system calls (class 1, subclass 13):
+.Pp
+.Dl S 0x010C
+.Pp
+.Sh EXAMPLES
+.Nm
+usually requires multiple invocations in order to set up the trace
+buffers, enable the correct events, and collect the events. A typical
+session with trace is:
+.Pp
+.Dl trace -i
+.Dl trace -e -c 1 -s 31
+.Dl sleep 1
+.Dl trace -d
+.Dl trace -t
+.Pp
+This initializes the trace buffers to their default values, enables the
+mach_msg_trap subclass of the MACH_SysCall class, waits for one second,
+then disables tracing and prints it to
+.Xr stdout 4 .
+This is useful for investigating isolated issues or gaining some
+understanding about a kernel subsystem. If a specific execuable should
+be traced, with the events saved for later analysis, the sequence of
+commands would be:
+.Pp
+.Dl trace -i
+.Dl trace -E -c 0x4 ./my_prog
+.Dl trace -d
+.Dl trace -l tracefile
+.Dl trace -R tracefile
+.Pp
+This initializes the trace buffers, enables all events in the BSC_SysCall class and runs
+.Li my_prog ,
+disables tracing, collects events into
+.Li tracefile ,
+and finally prints those events out in a human-readable form.
+.Sh CAVEATS
+Almost all
+.Nm
+command flags require superuser (root) privileges.
+.Pp
+After failures, the trace buffers usually need to be re-initialized.
+.Pp
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr trace 4 ,
+.Xr fs_usage 1 ,
+.Xr sc_usage 1 ,
+.Xr latency 1 ,
+.Xr top 1
diff --git a/system_cmds/trace.tproj/trace.c b/system_cmds/trace.tproj/trace.c
new file mode 100644
index 0000000..f85b336
--- /dev/null
+++ b/system_cmds/trace.tproj/trace.c
@@ -0,0 +1,2941 @@
+/*
+ cc -I/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders -arch x86_64 -arch i386 -O -o trace trace.c
+*/
+
+/*
+ * NOTE: There exists another copy of this file in the kernel_tools. Changes
+ * made here may also need to be made there.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/mbuf.h>
+#include <sys/mman.h>
+#include <sys/ucred.h>
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <sys/ptrace.h>
+#include <sys/sysctl.h>
+#include <sys/wait.h>
+#include <sys/resource.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include <err.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <spawn.h>
+#include <assert.h>
+#include <signal.h>
+#include <sysexits.h>
+
+#include <libutil.h>
+
+#ifndef KERNEL_PRIVATE
+#define KERNEL_PRIVATE
+#include <sys/kdebug.h>
+#undef KERNEL_PRIVATE
+#else
+#include <sys/kdebug.h>
+#endif /*KERNEL_PRIVATE*/
+#include <sys/param.h>
+
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+
+int nbufs = 0;
+int enable_flag=0;
+int execute_flag=0;
+int logRAW_flag=0;
+int LogRAW_flag=0;
+int readRAW_flag = 0;
+int disable_flag=0;
+int init_flag=0;
+int kval_flag=0;
+int remove_flag=0;
+int bufset_flag=0;
+int bufget_flag=0;
+int filter_flag=0;
+int filter_file_flag=0;
+int filter_alloced=0;
+int trace_flag=0;
+int nowrap_flag=0;
+int freerun_flag=0;
+int verbose_flag=0;
+int usage_flag=0;
+int pid_flag=0;
+int pid_exflag=0;
+int ppt_flag=0;
+int done_with_args=0;
+int no_default_codes_flag=0;
+
+unsigned int value1=0;
+unsigned int value2=0;
+unsigned int value3=0;
+unsigned int value4=0;
+
+pid_t pid=0;
+int reenable=0;
+
+int force_32bit_exec = 0;
+int frequency = 0;
+
+int mib[6];
+size_t needed;
+
+char *logfile = (char *)0; /* This file is trace format */
+char *RAW_file = (char *)0;
+FILE *output_file;
+int output_fd;
+
+extern char **environ;
+
+uint8_t* type_filter_bitmap;
+
+#define SIZE_4KB (4 * (1 << 10))
+
+#define DBG_FUNC_ALL (DBG_FUNC_START | DBG_FUNC_END)
+#define DBG_FUNC_MASK 0xfffffffc
+#define SHORT_HELP 1
+#define LONG_HELP 0
+
+#define CSC_MASK 0xffff0000
+
+#define BSC_exit 0x040c0004
+#define BSC_thread_terminate 0x040c05a4
+#define MACH_SCHEDULED 0x01400000
+#define MACH_MAKERUNNABLE 0x01400018
+#define MACH_STKHANDOFF 0x01400008
+
+#define EMPTYSTRING ""
+#define UNKNOWN "unknown"
+
+char tmpcommand[MAXCOMLEN];
+
+int total_threads = 0;
+int nthreads = 0;
+kd_threadmap *mapptr = 0;
+
+kd_cpumap_header* cpumap_header = NULL;
+kd_cpumap* cpumap = NULL;
+
+/*
+ If NUMPARMS changes from the kernel,
+ then PATHLENGTH will also reflect the change
+ This is for the vfslookup entries that
+ return pathnames
+*/
+#define NUMPARMS 23
+#define PATHLENGTH (NUMPARMS*sizeof(long))
+
+
+#define US_TO_SLEEP 50000
+#define BASE_EVENTS 500000
+
+mach_timebase_info_data_t mach_timebase;
+double divisor;
+
+typedef struct {
+ uint32_t debugid;
+ char *debug_string;
+} code_type_t;
+
+code_type_t* codesc = 0;
+size_t codesc_idx = 0; // Index into first empty codesc entry
+
+
+
+typedef struct event *event_t;
+
+struct event {
+ event_t ev_next;
+
+ uint64_t ev_thread;
+ uint32_t ev_debugid;
+ uint64_t ev_timestamp;
+};
+
+typedef struct lookup *lookup_t;
+
+struct lookup {
+ lookup_t lk_next;
+
+ uint64_t lk_thread;
+ uint64_t lk_dvp;
+ int64_t *lk_pathptr;
+ int64_t lk_pathname[NUMPARMS + 1];
+};
+
+typedef struct threadmap *threadmap_t;
+
+struct threadmap {
+ threadmap_t tm_next;
+
+ uint64_t tm_thread;
+ uint64_t tm_pthread;
+ boolean_t tm_deleteme;
+ char tm_command[MAXCOMLEN + 1];
+};
+
+#define HASH_SIZE 1024
+#define HASH_MASK 1023
+
+event_t event_hash[HASH_SIZE];
+lookup_t lookup_hash[HASH_SIZE];
+threadmap_t threadmap_hash[HASH_SIZE];
+
+event_t event_freelist;
+lookup_t lookup_freelist;
+threadmap_t threadmap_freelist;
+threadmap_t threadmap_temp;
+
+
+#define SBUFFER_SIZE (128 * 4096)
+char sbuffer[SBUFFER_SIZE];
+
+int secs_to_run = 0;
+int use_current_buf = 0;
+
+
+kbufinfo_t bufinfo = {0, 0, 0, 0};
+
+int codenum = 0;
+int codeindx_cache = 0;
+
+static void quit(char *);
+static int match_debugid(unsigned int, char *, int *);
+static void usage(int short_help);
+static int argtoi(int flag, char *req, char *str, int base);
+static int parse_codefile(const char *filename);
+static void codesc_find_dupes(void);
+static int read_command_map(int, uint32_t);
+static void read_cpu_map(int);
+static void find_thread_command(kd_buf *, char **);
+static void create_map_entry(uint64_t, char *);
+static void getdivisor();
+static unsigned long argtoul();
+
+static void set_enable(int);
+static void set_remove();
+static void set_nowrap();
+static void set_pidcheck(int, int);
+static void set_pidexclude(int, int);
+static void set_numbufs(int);
+static void set_freerun();
+static void get_bufinfo(kbufinfo_t *);
+static int get_ktrace_state(void);
+static void set_init();
+static void set_kval_list();
+static void readtrace(char *);
+static void log_trace();
+static void Log_trace();
+static void read_trace();
+static void signal_handler(int);
+static void signal_handler_RAW(int);
+static void delete_thread_entry(uint64_t);
+static void find_and_insert_tmp_map_entry(uint64_t, char *);
+static void create_tmp_map_entry(uint64_t, uint64_t);
+static void find_thread_name(uint64_t, char **, boolean_t);
+static void execute_process(char * const argv[]);
+
+static int writetrace(int);
+static int write_command_map(int);
+static int debugid_compar(const void *, const void *);
+
+static threadmap_t find_thread_entry(uint64_t);
+
+static void saw_filter_class(uint8_t class);
+static void saw_filter_end_range(uint8_t end_class);
+static void saw_filter_subclass(uint8_t subclass);
+static void filter_done_parsing(void);
+
+static void set_filter(void);
+static void set_filter_class(uint8_t class);
+static void set_filter_range(uint8_t class, uint8_t end);
+static void set_filter_subclass(uint8_t class, uint8_t subclass);
+
+static void parse_filter_file(char *filename);
+
+static void quit_args(const char *fmt, ...) __printflike(1, 2);
+
+#ifndef KERN_KDWRITETR
+#define KERN_KDWRITETR 17
+#endif
+
+#ifndef KERN_KDWRITEMAP
+#define KERN_KDWRITEMAP 18
+#endif
+
+#ifndef F_FLUSH_DATA
+#define F_FLUSH_DATA 40
+#endif
+
+#ifndef RAW_VERSION1
+typedef struct {
+ int version_no;
+ int thread_count;
+ uint64_t TOD_secs;
+ uint32_t TOD_usecs;
+} RAW_header;
+
+#define RAW_VERSION0 0x55aa0000
+#define RAW_VERSION1 0x55aa0101
+#endif
+
+#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(*x)))
+
+#define EXTRACT_CLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF00 ) >> 8 ) )
+#define EXTRACT_SUBCLASS_LOW(debugid) ( (uint8_t) ( ((debugid) & 0xFF ) ) )
+
+#define ENCODE_CSC_LOW(class, subclass) \
+ ( (uint16_t) ( ((class) & 0xff) << 8 ) | ((subclass) & 0xff) )
+
+RAW_header raw_header;
+
+
+
+void set_enable(int val)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDENABLE;
+#ifdef KDEBUG_ENABLE_PPT
+ if (ppt_flag && val) {
+ mib[3] = KDEBUG_ENABLE_PPT;
+ } else {
+ mib[3] = val;
+ }
+#else
+ mib[3] = val;
+#endif
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
+ if (errno == EINVAL) {
+ quit_args("trace facility failure, KERN_KDENABLE: trace buffer is uninitialized\n");
+ }
+ quit_args("trace facility failure, KERN_KDENABLE: %s\n", strerror(errno));
+ }
+}
+
+void set_remove(void)
+{
+ extern int errno;
+
+ errno = 0;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREMOVE;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ {
+ if (errno == EBUSY)
+ quit("the trace facility is currently in use...\n fs_usage, sc_usage, trace, and latency use this feature.\n\n");
+ else
+ quit_args("trace facility failure, KERN_KDREMOVE: %s\n", strerror(errno));
+ }
+}
+
+void set_numbufs(int nbufs)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETBUF;
+ mib[3] = nbufs;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETBUF: %s\n", strerror(errno));
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
+}
+
+void set_nowrap(void)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDEFLAGS;
+ mib[3] = KDBG_NOWRAP;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KDBG_NOWRAP: %s\n", strerror(errno));
+
+}
+
+void set_pidcheck(int pid, int on_off_flag)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_TYPENONE;
+ kr.value1 = pid;
+ kr.value2 = on_off_flag;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDPIDTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ {
+ if (errno == EACCES)
+ {
+ quit_args("trace facility failure, setting pid filter: %s\n",
+ strerror(errno));
+ }
+ else if (on_off_flag == 1 && errno == ESRCH)
+ {
+ set_remove();
+ quit_args("trace facility failure, setting pid filter: "
+ "pid %d does not exist\n", pid);
+ }
+ else
+ {
+ quit_args("trace facility failure, KERN_KDPIDTR: %s\n", strerror(errno));
+ }
+ }
+}
+
+void set_pidexclude(int pid, int on_off_flag)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_TYPENONE;
+ kr.value1 = pid;
+ kr.value2 = on_off_flag;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDPIDEX;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ {
+ if (on_off_flag == 1)
+ {
+ printf ("pid %d does not exist\n", pid);
+ set_remove();
+ exit(2);
+ }
+ }
+}
+
+void set_freerun(void)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDEFLAGS;
+ mib[3] = KDBG_FREERUN;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KDBG_FREERUN: %s\n", strerror(errno));
+}
+
+static int get_ktrace_state(void)
+{
+ int state;
+ size_t state_size = sizeof(state);
+ int err = sysctlbyname("ktrace.state", &state, &state_size, NULL, 0);
+ if (err) {
+ fprintf(stderr, "error: could not query ktrace.state sysctl (%d: %s)\n", errno, strerror(errno));
+ exit(1);
+ }
+ return state;
+}
+
+void get_bufinfo(kbufinfo_t *val)
+{
+ needed = sizeof (*val);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDGETBUF;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, val, &needed, 0, 0) < 0)
+ quit_args("trace facility failure, KERN_KDGETBUF: %s\n", strerror(errno));
+}
+
+void set_init(void)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_RANGETYPE;
+ kr.value1 = 0;
+ kr.value2 = -1;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETREG;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETREG (rangetype): %s\n", strerror(errno));
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETUP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, NULL, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETUP: %s\n", strerror(errno));
+}
+
+static void
+set_filter(void)
+{
+ errno = 0;
+ int mib[] = { CTL_KERN, KERN_KDEBUG, KERN_KDSET_TYPEFILTER };
+ size_t needed = KDBG_TYPEFILTER_BITMAP_SIZE;
+
+ if(sysctl(mib, ARRAYSIZE(mib), type_filter_bitmap, &needed, NULL, 0)) {
+ quit_args("trace facility failure, KERN_KDSET_TYPEFILTER: %s\n", strerror(errno));
+ }
+}
+
+void set_kval_list(void)
+{
+ kd_regtype kr;
+
+ kr.type = KDBG_VALCHECK;
+ kr.value1 = value1;
+ kr.value2 = value2;
+ kr.value3 = value3;
+ kr.value4 = value4;
+ needed = sizeof(kd_regtype);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDSETREG;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, &kr, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDSETREG (valcheck): %s\n", strerror(errno));
+}
+
+
+void readtrace(char *buffer)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREADTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
+}
+
+
+int writetrace(int fd)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDWRITETR;
+ mib[3] = fd;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0)
+ return 1;
+
+ return 0;
+}
+
+
+int write_command_map(int fd)
+{
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDWRITEMAP;
+ mib[3] = fd;
+ mib[4] = 0;
+ mib[5] = 0;
+
+ if (sysctl(mib, 4, NULL, &needed, NULL, 0) < 0) {
+ if (errno == ENODATA) {
+ if (verbose_flag) {
+ printf("Cannot write thread map -- this is not fatal\n");
+ }
+ } else {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static
+lookup_t handle_lookup_event(uint64_t thread, int debugid, kd_buf *kdp)
+{
+ lookup_t lkp;
+ int hashid;
+ boolean_t first_record = FALSE;
+
+ hashid = thread & HASH_MASK;
+
+ if (debugid & DBG_FUNC_START)
+ first_record = TRUE;
+
+ for (lkp = lookup_hash[hashid]; lkp; lkp = lkp->lk_next) {
+ if (lkp->lk_thread == thread)
+ break;
+ }
+ if (lkp == NULL) {
+ if (first_record == FALSE)
+ return (0);
+
+ if ((lkp = lookup_freelist))
+ lookup_freelist = lkp->lk_next;
+ else
+ lkp = (lookup_t)malloc(sizeof(struct lookup));
+
+ lkp->lk_thread = thread;
+
+ lkp->lk_next = lookup_hash[hashid];
+ lookup_hash[hashid] = lkp;
+ }
+
+ if (first_record == TRUE) {
+ lkp->lk_pathptr = lkp->lk_pathname;
+ lkp->lk_dvp = kdp->arg1;
+ } else {
+ if (lkp->lk_pathptr > &lkp->lk_pathname[NUMPARMS-4])
+ return (lkp);
+
+ *lkp->lk_pathptr++ = kdp->arg1;
+ }
+ *lkp->lk_pathptr++ = kdp->arg2;
+ *lkp->lk_pathptr++ = kdp->arg3;
+ *lkp->lk_pathptr++ = kdp->arg4;
+ *lkp->lk_pathptr = 0;
+
+ return (lkp);
+}
+
+
+static
+void delete_lookup_event(uint64_t thread, lookup_t lkp_to_delete)
+{
+ lookup_t lkp;
+ lookup_t lkp_prev;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ if ((lkp = lookup_hash[hashid])) {
+ if (lkp == lkp_to_delete)
+ lookup_hash[hashid] = lkp->lk_next;
+ else {
+ lkp_prev = lkp;
+
+ for (lkp = lkp->lk_next; lkp; lkp = lkp->lk_next) {
+ if (lkp == lkp_to_delete) {
+ lkp_prev->lk_next = lkp->lk_next;
+ break;
+ }
+ lkp_prev = lkp;
+ }
+ }
+ if (lkp) {
+ lkp->lk_next = lookup_freelist;
+ lookup_freelist = lkp;
+ }
+ }
+}
+
+
+static
+void insert_start_event(uint64_t thread, int debugid, uint64_t now)
+{
+ event_t evp;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (evp = event_hash[hashid]; evp; evp = evp->ev_next) {
+ if (evp->ev_thread == thread && evp->ev_debugid == debugid)
+ break;
+ }
+ if (evp == NULL) {
+ if ((evp = event_freelist))
+ event_freelist = evp->ev_next;
+ else
+ evp = (event_t)malloc(sizeof(struct event));
+
+ evp->ev_thread = thread;
+ evp->ev_debugid = debugid;
+
+ evp->ev_next = event_hash[hashid];
+ event_hash[hashid] = evp;
+ }
+ evp->ev_timestamp = now;
+}
+
+
+static
+uint64_t consume_start_event(uint64_t thread, int debugid, uint64_t now)
+{
+ event_t evp;
+ event_t evp_prev;
+ int hashid;
+ uint64_t elapsed = 0;
+
+ hashid = thread & HASH_MASK;
+
+ if ((evp = event_hash[hashid])) {
+ if (evp->ev_thread == thread && evp->ev_debugid == debugid)
+ event_hash[hashid] = evp->ev_next;
+ else {
+ evp_prev = evp;
+
+ for (evp = evp->ev_next; evp; evp = evp->ev_next) {
+
+ if (evp->ev_thread == thread && evp->ev_debugid == debugid) {
+ evp_prev->ev_next = evp->ev_next;
+ break;
+ }
+ evp_prev = evp;
+ }
+ }
+ if (evp) {
+ elapsed = now - evp->ev_timestamp;
+
+ evp->ev_next = event_freelist;
+ event_freelist = evp;
+ }
+ }
+ return (elapsed);
+}
+
+void
+log_trace(void)
+{
+ int fd = -1;
+ int ret = 0;
+ char *buffer;
+ uint32_t buffer_size = 1000000 * sizeof(kd_buf);
+
+ if (logfile[0] == '-' && logfile[1] == '\0') {
+ fd = STDOUT_FILENO;
+ } else {
+ fd = open(logfile, O_TRUNC | O_WRONLY | O_CREAT, 0777);
+ }
+
+ if (fd == -1) {
+ perror("Can't open logfile");
+ exit(1);
+ }
+ get_bufinfo(&bufinfo);
+
+ if (bufinfo.nolog != 1) {
+ reenable = 1;
+ set_enable(0); /* disable logging*/
+ }
+ get_bufinfo(&bufinfo);
+
+ if (verbose_flag) {
+ if (bufinfo.flags & KDBG_WRAPPED)
+ printf("Buffer has wrapped\n");
+ else
+ printf("Buffer has not wrapped\n");
+ }
+
+ ret = write_command_map(fd);
+ if (ret) {
+ close(fd);
+ perror("failed to write logfile");
+ exit(1);
+ }
+
+ buffer = malloc(buffer_size);
+ if (buffer == NULL) {
+ quit("can't allocate memory for events\n");
+ }
+
+ for (;;) {
+ needed = buffer_size;
+
+ readtrace(buffer);
+
+ if (needed == 0) {
+ break;
+ }
+
+ write(fd, buffer, needed * sizeof(kd_buf));
+ }
+
+ free(buffer);
+
+ close(fd);
+}
+
+/*
+ * Why does this function exist?
+ * trace -L needs millisecond level wait times.
+ * When this code is running remotely, the mach_timebase_info_t data may
+ * be from a device with a different timebase. This code avoids using
+ * mach_absolute_time(), so that time calculations come out correct both
+ * locally and remotely.
+ */
+static uint64_t current_millis() {
+ struct timeval time;
+ gettimeofday(&time, NULL);
+ return (time.tv_sec * 1000) + (time.tv_usec / 1000);
+}
+
+void
+Log_trace(void)
+{
+ size_t len;
+ int num_cpus = 0;
+ int fd;
+ uint64_t current_ms;
+ uint64_t ending_ms = 0;
+ uint64_t last_time_written;
+ uint32_t ms_to_run;
+
+ if ((fd = open(logfile, O_TRUNC|O_WRONLY|O_CREAT, 0777)) == -1) {
+ perror("Can't open logfile");
+ exit(1);
+ }
+ if (use_current_buf == 0) {
+ /*
+ * grab the number of cpus and scale the buffer size
+ */
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ mib[2] = 0;
+ len = sizeof(num_cpus);
+
+ sysctl(mib, 2, &num_cpus, &len, NULL, 0);
+
+ if (!bufset_flag)
+ nbufs = BASE_EVENTS * num_cpus;
+
+ set_remove();
+ set_numbufs(nbufs);
+ set_init();
+
+ if (filter_flag)
+ set_filter();
+
+ if (kval_flag)
+ set_kval_list();
+ }
+
+ if (use_current_buf == 0)
+ set_enable(1);
+
+ if (write_command_map(fd)) {
+ quit("can't write tracefile header\n");
+ }
+
+ last_time_written = current_millis();
+
+ if (secs_to_run) {
+ ms_to_run = secs_to_run * 1000;
+ ending_ms = last_time_written + ms_to_run;
+ } else
+ ms_to_run = 0;
+
+ while (LogRAW_flag) {
+ needed = ms_to_run;
+
+ if (writetrace(fd)) {
+ perror("KDWRITETR returned error");
+
+ /* Clean up and exit in case of write fail */
+ break;
+ }
+
+ if (needed) {
+ current_ms = current_millis();
+
+ printf("wrote %d events - elapsed time = %.1f secs\n",
+ (int)needed, (double)(current_ms - last_time_written) / 1000.0);
+
+ last_time_written = current_ms;
+ }
+
+ if (secs_to_run) {
+ current_ms = current_millis();
+
+ if (current_ms > ending_ms)
+ break;
+
+ ms_to_run = (uint32_t)(ending_ms - current_ms);
+
+ if (ms_to_run == 0)
+ break;
+ }
+ }
+ set_enable(0);
+ set_numbufs(0);
+ set_remove();
+
+ close(fd);
+}
+
+
+void read_trace(void)
+{
+ char *buffer;
+ uint32_t buffer_size;
+ kd_buf *kd;
+ int fd;
+ int firsttime = 1;
+ int lines = 0;
+ int io_lines = 0;
+ uint64_t bias = 0;
+ uint32_t count_of_names;
+ double last_event_time = 0.0;
+ time_t trace_time;
+
+ if (!readRAW_flag) {
+ get_bufinfo(&bufinfo);
+
+ if (bufinfo.nolog != 1) {
+ reenable = 1;
+ set_enable(0); /* disable logging*/
+ }
+ if (verbose_flag) {
+ if (bufinfo.flags & KDBG_WRAPPED)
+ printf("Buffer has wrapped\n");
+ else
+ printf("Buffer has not wrapped\n");
+ }
+ fd = 0;
+ count_of_names = 0;
+
+ } else {
+ fd = open(RAW_file, O_RDONLY);
+
+ if (fd < 0) {
+ perror("Can't open file");
+ exit(1);
+ }
+ if (read(fd, &raw_header, sizeof(RAW_header)) != sizeof(RAW_header)) {
+ perror("read failed");
+ exit(2);
+ }
+ if (raw_header.version_no != RAW_VERSION1) {
+ raw_header.version_no = RAW_VERSION0;
+ raw_header.TOD_secs = time((long *)0);
+ raw_header.TOD_usecs = 0;
+
+ lseek(fd, (off_t)0, SEEK_SET);
+
+ if (read(fd, &raw_header.thread_count, sizeof(int)) != sizeof(int)) {
+ perror("read failed");
+ exit(2);
+ }
+ } else if (raw_header.version_no == RAW_VERSION1) {
+#if defined(__ILP32__)
+ /*
+ * If the raw trace file was written by armv7k, the 64-bit alignment
+ * of TOD_secs causes RAW_header to be 24 bytes. If we only read 20
+ * bytes, the next 4 bytes might be a legitimate thread_id, but it might
+ * also be 0 or a leaked kernel pointer from an armv7k trace file. For
+ * both those cases, consume the 4 bytes and look for the thread map
+ * after it.
+ */
+ if (sizeof(raw_header) == 20) {
+ uint32_t alignment_garbage;
+
+ if (read(fd, &alignment_garbage, sizeof(alignment_garbage)) != sizeof(alignment_garbage)) {
+ perror("read failed");
+ exit(2);
+ }
+
+ if ((alignment_garbage == 0) || (alignment_garbage >= 0x80000000)) {
+ if (verbose_flag) {
+ printf("Skipping 4 bytes to find valid thread map\n");
+ }
+ } else {
+ /* oops, go back to where we were */
+ lseek(fd, -(off_t)sizeof(alignment_garbage), SEEK_CUR);
+ }
+ }
+#endif
+ }
+ count_of_names = raw_header.thread_count;
+ trace_time = (time_t) (raw_header.TOD_secs);
+
+ printf("%s\n", ctime(&trace_time));
+ }
+ buffer_size = 1000000 * sizeof(kd_buf);
+ buffer = malloc(buffer_size);
+
+ if (buffer == (char *) 0)
+ quit("can't allocate memory for tracing info\n");
+
+ kd = (kd_buf *)(uintptr_t)buffer;
+
+ read_command_map(fd, count_of_names);
+ read_cpu_map(fd);
+
+ for (;;) {
+ uint32_t count;
+ uint64_t now = 0;
+ uint64_t prev;
+ uint64_t prevdelta = 0;
+ uint32_t cpunum = 0;
+ uint64_t thread;
+ double x = 0.0;
+ double y = 0.0;
+ double event_elapsed_time = 0;
+ kd_buf *kdp;
+ lookup_t lkp;
+ boolean_t ending_event;
+ int i;
+ int debugid;
+ int debugid_base;
+ int dmsgindex;
+ char dbgmessge[80];
+ char outbuf[32];
+ char *command;
+
+ if (!readRAW_flag) {
+ needed = buffer_size;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDREADTR;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0;
+ if (sysctl(mib, 3, buffer, &needed, NULL, 0) < 0)
+ quit_args("trace facility failure, KERN_KDREADTR: %s\n", strerror(errno));
+
+ if (needed == 0)
+ break;
+ count = (uint32_t)needed;
+
+ } else {
+ uint32_t bytes_read;
+
+ bytes_read = (uint32_t)read(fd, buffer, buffer_size);
+
+ if (bytes_read == -1) {
+ perror("read failed");
+ exit(2);
+ }
+ count = bytes_read / sizeof(kd_buf);
+
+ if (count == 0)
+ break;
+ }
+ for (kdp = &kd[0], i = 0; i < count; i++, kdp++) {
+
+ prev = now;
+ debugid = kdp->debugid;
+ debugid_base = debugid & DBG_FUNC_MASK;
+ now = kdp->timestamp & KDBG_TIMESTAMP_MASK;
+ cpunum = kdbg_get_cpu(kdp);
+
+ /*
+ * Is this event from an IOP? If so, there will be no
+ * thread command, label it with the symbolic IOP name
+ */
+ if (cpumap && (cpunum < cpumap_header->cpu_count) && (cpumap[cpunum].flags & KDBG_CPUMAP_IS_IOP)) {
+ command = cpumap[cpunum].name;
+ } else {
+ find_thread_command(kdp, &command);
+ }
+
+ /*
+ * The internal use TRACE points clutter the output.
+ * Print them only if in verbose mode.
+ */
+ if (!verbose_flag)
+ {
+ /* Is this entry of Class DBG_TRACE */
+ if ((debugid >> 24) == DBG_TRACE) {
+ if (((debugid >> 16) & 0xff) != DBG_TRACE_INFO)
+ continue;
+ }
+ }
+
+ if (firsttime)
+ bias = now;
+ now -= bias;
+
+ thread = kdp->arg5;
+
+ if (lines == 64 || firsttime)
+ {
+ prevdelta = now - prevdelta;
+
+ if (firsttime)
+ firsttime = 0;
+ else {
+ x = (double)prevdelta;
+ x /= divisor;
+
+ fprintf(output_file, "\n\nNumber of microsecs since in last page %8.1f\n", x);
+ }
+ prevdelta = now;
+
+ /*
+ * Output description row to output file (make sure to format correctly for 32-bit and 64-bit)
+ */
+ fprintf(output_file,
+#ifdef __LP64__
+ " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
+#else
+ " AbsTime(Us) Delta debugid arg1 arg2 arg3 arg4 thread cpu# command\n\n"
+#endif
+ );
+
+ lines = 0;
+
+ if (io_lines > 15000) {
+ fcntl(output_fd, F_FLUSH_DATA, 0);
+
+ io_lines = 0;
+ }
+ }
+ lkp = 0;
+
+ if (debugid_base == VFS_LOOKUP) {
+ lkp = handle_lookup_event(thread, debugid, kdp);
+
+ if ( !lkp || !(debugid & DBG_FUNC_END))
+ continue;
+ }
+
+ x = (double)now;
+ x /= divisor;
+
+ if (last_event_time)
+ y = x - last_event_time;
+ else
+ y = x;
+ last_event_time = x;
+ ending_event = FALSE;
+
+ if ( !lkp) {
+ int t_debugid;
+ uint64_t t_thread;
+
+ if ((debugid & DBG_FUNC_START) || debugid == MACH_MAKERUNNABLE) {
+
+ if (debugid_base != BSC_thread_terminate && debugid_base != BSC_exit) {
+
+ if (debugid == MACH_MAKERUNNABLE)
+ t_thread = kdp->arg1;
+ else
+ t_thread = thread;
+
+ insert_start_event(t_thread, debugid_base, now);
+ }
+
+ } else if ((debugid & DBG_FUNC_END) || debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
+
+ if (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED) {
+ t_debugid = MACH_MAKERUNNABLE;
+ t_thread = kdp->arg2;
+ } else {
+ t_debugid = debugid_base;
+ t_thread = thread;
+ }
+ event_elapsed_time = (double)consume_start_event(t_thread, t_debugid, now);
+ event_elapsed_time /= divisor;
+ ending_event = TRUE;
+
+ if (event_elapsed_time == 0 && (debugid == MACH_STKHANDOFF || debugid == MACH_SCHEDULED))
+ ending_event = FALSE;
+ }
+ }
+ if (ending_event) {
+ char *ch;
+
+ sprintf(&outbuf[0], "(%-10.1f)", event_elapsed_time);
+ /*
+ * fix that right paren
+ */
+ ch = &outbuf[11];
+
+ if (*ch != ')') {
+ ch = strchr (&outbuf[0], ')');
+ }
+ if (ch)
+ {
+ *ch = ' ';
+ --ch;
+
+ while (ch != &outbuf[0])
+ {
+ if (*ch == ' ')
+ --ch;
+ else
+ {
+ *(++ch) = ')';
+ break;
+ }
+ }
+ }
+ }
+ if (match_debugid(debugid_base, dbgmessge, &dmsgindex)) {
+ if (ending_event)
+ fprintf(output_file, "%13.1f %10.1f%s %-28x ", x, y, outbuf, debugid_base);
+ else
+ fprintf(output_file, "%13.1f %10.1f %-28x ", x, y, debugid_base);
+ } else {
+ if (ending_event)
+ fprintf(output_file, "%13.1f %10.1f%s %-28.28s ", x, y, outbuf, dbgmessge);
+ else
+ fprintf(output_file, "%13.1f %10.1f %-28.28s ", x, y, dbgmessge);
+ }
+ if (lkp) {
+ char *strptr;
+ int len;
+
+ strptr = (char *)lkp->lk_pathname;
+
+ /*
+ * print the tail end of the pathname
+ */
+ len = (int)strlen(strptr);
+ if (len > 51)
+ len -= 51;
+ else
+ len = 0;
+#if defined(__LP64__) || defined(__arm64__)
+
+ fprintf(output_file, "%-16llx %-51s %-16" PRIx64 " %-2d %s\n", (uint64_t)lkp->lk_dvp, &strptr[len], thread, cpunum, command);
+#else
+ fprintf(output_file, "%-8x %-51s %-8" PRIx64 " %-2d %s\n", (unsigned int)lkp->lk_dvp, &strptr[len], thread, cpunum, command);
+#endif
+ delete_lookup_event(thread, lkp);
+ } else if (debugid == TRACE_INFO_STRING) {
+#if defined(__LP64__) || defined(__arm64__)
+ fprintf(output_file, "%-32s%-36s %-16" PRIx64 " %-2d %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
+#else
+ fprintf(output_file, "%-16s%-46s %-8" PRIx64 " %-2d %s\n", (char *) &kdp->arg1, "", thread, cpunum, command);
+#endif
+ } else {
+#if defined(__LP64__) || defined(__arm64__)
+ fprintf(output_file, "%-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %-16" PRIx64 " %-2d %s\n",
+ (uint64_t)kdp->arg1, (uint64_t)kdp->arg2, (uint64_t)kdp->arg3, (uint64_t)kdp->arg4, thread, cpunum, command);
+#else
+ fprintf(output_file, "%-8" PRIx64 " %-8" PRIx64 " %-8" PRIx64 " %-8" PRIx64 " %-8" PRIx64 " %-2d %s\n",
+ (uint64_t)kdp->arg1, (uint64_t)kdp->arg2, (uint64_t)kdp->arg3, (uint64_t)kdp->arg4, thread, cpunum, command);
+#endif
+ }
+ lines++;
+ io_lines++;
+ }
+ }
+ if (reenable == 1)
+ set_enable(1); /* re-enable kernel logging */
+}
+
+
+
+void signal_handler(int sig)
+{
+ ptrace(PT_KILL, pid, (caddr_t)0, 0);
+ /*
+ * child is gone; no need to disable the pid
+ */
+ exit(2);
+}
+
+
+void signal_handler_RAW(int sig)
+{
+ LogRAW_flag = 0;
+}
+
+
+int main (int argc, char* argv[], char *envp[])
+{
+ extern char *optarg;
+ extern int optind;
+ int ch;
+ int i;
+ char *output_filename = NULL;
+ unsigned int parsed_arg;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp("-X", argv[i]) == 0) {
+ force_32bit_exec = 1;
+ break;
+ }
+ }
+ if (force_32bit_exec) {
+ if (0 != reexec_to_match_lp64ness(FALSE)) {
+ fprintf(stderr, "Could not re-execute: %d\n", errno);
+ exit(1);
+ }
+ }
+#if !defined(__arm64__)
+ else {
+ if (0 != reexec_to_match_kernel()) {
+ fprintf(stderr, "Could not re-execute: %d\n", errno);
+ exit(1);
+ }
+ }
+#endif
+ if (setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_PASSIVE) < 0) {
+ printf("setiopolicy failed\n");
+ exit(1);
+ }
+ output_file = stdout;
+ output_fd = 1;
+
+ while ((ch = getopt(argc, argv, "hedEk:irb:gc:p:s:tR:L:l:S:F:a:x:Xnfvo:PT:N")) != EOF)
+ {
+ switch(ch)
+ {
+ case 'h': /* help */
+ usage_flag=1;
+ break;
+ case 'S':
+ secs_to_run = argtoi('S', "decimal number", optarg, 10);
+ break;
+ case 'a': /* set tracing on a pid */
+ pid_flag=1;
+ pid = argtoi('a', "decimal number", optarg, 10);
+ break;
+ case 'x': /* exclude a pid from tracing */
+ pid_exflag=1;
+ pid = argtoi('x', "decimal number", optarg, 10);
+ break;
+ case 'v':
+ verbose_flag=1;
+ break;
+ case 'l':
+ logRAW_flag = 1;
+ logfile = optarg;
+ break;
+ case 'L':
+ LogRAW_flag = 1;
+ logfile = optarg;
+ signal(SIGINT, signal_handler_RAW);
+ break;
+ case 'e':
+ enable_flag = 1;
+ break;
+ case 'i':
+ init_flag = 1;
+ break;
+ case 'E':
+ execute_flag = 1;
+ break;
+ case 'd':
+ disable_flag = 1;
+ break;
+ case 'k':
+ if (kval_flag == 0)
+ value1 = (unsigned int) argtoul('k', "hex number", optarg, 16);
+ else if (kval_flag == 1)
+ value2 = (unsigned int) argtoul('k', "hex number", optarg, 16);
+ else if (kval_flag == 2)
+ value3 = (unsigned int) argtoul('k', "hex number", optarg, 16);
+ else if (kval_flag == 3)
+ value4 = (unsigned int) argtoul('k', "hex number", optarg, 16);
+ else
+ {
+ fprintf(stderr, "A maximum of four values can be specified with -k\n");
+ usage(SHORT_HELP);
+ }
+ kval_flag++;
+ break;
+ case 'r':
+ remove_flag = 1;
+ break;
+ case 'g':
+ bufget_flag = 1;
+ break;
+ case 't':
+ trace_flag = 1;
+ break;
+ case 'R':
+ readRAW_flag = 1;
+ RAW_file = optarg;
+ break;
+ case 'n':
+ nowrap_flag = 1;
+ break;
+ case 'f':
+ freerun_flag = 1;
+ break;
+ case 'b':
+ bufset_flag = 1;
+ nbufs = argtoi('b', "decimal number", optarg, 10);
+ break;
+ case 'c':
+ filter_flag = 1;
+ parsed_arg = argtoi('c', "decimal, hex, or octal number", optarg, 0);
+ if (parsed_arg > 0xFF)
+ quit_args("argument '-c %s' parsed as %u, "
+ "class value must be 0-255\n", optarg, parsed_arg);
+ saw_filter_class(parsed_arg);
+ break;
+ case 's':
+ filter_flag = 1;
+ parsed_arg = argtoi('s', "decimal, hex, or octal number", optarg, 0);
+ if (parsed_arg > 0xFF)
+ quit_args("argument '-s %s' parsed as %u, "
+ "subclass value must be 0-255\n", optarg, parsed_arg);
+ saw_filter_subclass(parsed_arg);
+ break;
+ case 'p':
+ filter_flag = 1;
+ parsed_arg = argtoi('p', "decimal, hex, or octal number", optarg, 0);
+ if (parsed_arg > 0xFF)
+ quit_args("argument '-p %s' parsed as %u, "
+ "end range value must be 0-255\n", optarg, parsed_arg);
+ saw_filter_end_range(parsed_arg);
+ break;
+ case 'P':
+ ppt_flag = 1;
+ break;
+ case 'o':
+ output_filename = optarg;
+ break;
+ case 'F':
+ frequency = argtoi('F', "decimal number", optarg, 10);
+ break;
+ case 'X':
+ break;
+ case 'N':
+ no_default_codes_flag = 1;
+ break;
+ case 'T':
+ filter_flag = 1;
+
+ // Flush out any unclosed -c argument
+ filter_done_parsing();
+
+ parse_filter_file(optarg);
+ break;
+ default:
+ usage(SHORT_HELP);
+ }
+ }
+ argc -= optind;
+
+ if (!no_default_codes_flag)
+ {
+ if (verbose_flag)
+ printf("Adding default code file /usr/share/misc/trace.codes. Use '-N' to skip this.\n");
+ parse_codefile("/usr/share/misc/trace.codes");
+ }
+
+ if (argc)
+ {
+ if (!execute_flag)
+ {
+ while (argc--)
+ {
+ const char *cfile = argv[optind++];
+ if (verbose_flag) printf("Adding code file %s \n", cfile);
+ parse_codefile(cfile);
+ }
+ }
+ }
+ else
+ {
+ if (execute_flag)
+ quit_args("-E flag needs an executable to launch\n");
+ }
+
+ if (usage_flag)
+ usage(LONG_HELP);
+
+ getdivisor();
+
+ if (pid_flag && pid_exflag)
+ quit_args("Can't use both -a and -x flag together\n");
+
+ if (kval_flag && filter_flag)
+ quit_args("Cannot use -k flag with -c, -s, or -p\n");
+
+ if (output_filename && !trace_flag && !readRAW_flag)
+ quit_args("When using 'o' option, must use the 't' or 'R' option too\n");
+
+ filter_done_parsing();
+
+ done_with_args = 1;
+
+ if (LogRAW_flag) {
+ get_bufinfo(&bufinfo);
+ int ktrace_state = get_ktrace_state();
+
+ /*
+ * Only use the current kdebug configuration when foreground
+ * tracing is enabled. Both checks are necessary because the
+ * background tool might have enabled tracing, but as soon as we
+ * try to write a header, that configuration is removed for us.
+ */
+ if ((ktrace_state == 1) && (bufinfo.nolog == 0)) {
+ use_current_buf = 1;
+ }
+ }
+
+ if (disable_flag)
+ {
+ if (pid_flag)
+ {
+ set_pidcheck(pid, 0); /* disable pid check for given pid */
+ exit(0);
+ }
+ else if (pid_exflag)
+ {
+ set_pidexclude(pid, 0); /* disable pid exclusion for given pid */
+ exit(0);
+ }
+ set_enable(0);
+ exit(0);
+ }
+
+ if (remove_flag)
+ {
+ set_remove();
+ exit(0);
+ }
+
+ if (bufset_flag )
+ {
+ if (!init_flag && !LogRAW_flag)
+ {
+ fprintf(stderr,"The -b flag must be used with the -i flag\n");
+ exit(1);
+ }
+ set_numbufs(nbufs);
+ }
+
+ if (nowrap_flag)
+ set_nowrap();
+
+ if (freerun_flag)
+ set_freerun();
+
+ if (bufget_flag)
+ {
+ printf("The kernel tracing settings are:\n");
+
+ /* determine the state of ktrace */
+ int state = get_ktrace_state();
+
+ /* get the name of the last process to configure ktrace */
+ char execname[20] = { 0 };
+ size_t execname_size = sizeof(execname);
+ int err = sysctlbyname("ktrace.configured_by", &execname, &execname_size, NULL, 0);
+ if (err) {
+ fprintf(stderr, "error: could not query ktrace.configured_by sysctl (%d: %s)\n", errno, strerror(errno));
+ exit(1);
+ }
+
+ printf("\tTracing is ");
+ switch (state) {
+ case 0:
+ printf("off");
+ break;
+ case 1:
+ printf("active (foreground)");
+ break;
+ case 2:
+ printf("active (background)");
+ break;
+ default:
+ printf("in an invalid state");
+ break;
+ }
+ printf("\n");
+
+ printf("\tLast configured by \"%s\"\n", execname[0] == '\0' ? "<unknown>" : execname);
+
+ /* get kdebug info */
+
+ get_bufinfo(&bufinfo);
+
+ printf("The kernel buffer settings are:\n");
+
+ if (bufinfo.flags & KDBG_BUFINIT)
+ printf("\tKernel buffer is initialized\n");
+ else
+ printf("\tKernel buffer is not initialized\n");
+
+ printf("\t number of buf entries = %d\n", bufinfo.nkdbufs);
+
+ if (verbose_flag)
+ {
+ if (bufinfo.flags & KDBG_MAPINIT)
+ printf("\tKernel thread map is initialized\n");
+ else
+ printf("\tKernel thread map is not initialized\n");
+ printf("\t number of thread entries = %d\n", bufinfo.nkdthreads);
+ }
+
+ if (bufinfo.nolog)
+ printf("\tBuffer logging is disabled\n");
+ else
+ printf("\tBuffer logging is enabled\n");
+
+ if (verbose_flag)
+ printf("\tkernel flags = 0x%x\n", bufinfo.flags);
+
+ if (bufinfo.flags & KDBG_NOWRAP)
+ printf("\tKernel buffer wrap is disabled\n");
+ else
+ printf("\tKernel buffer wrap is enabled\n");
+
+ if (bufinfo.flags & KDBG_RANGECHECK)
+ printf("\tCollection within a range is enabled\n");
+ else
+ printf("\tCollection within a range is disabled\n");
+
+ if (bufinfo.flags & KDBG_VALCHECK)
+ printf("\tCollecting specific code values is enabled\n");
+ else
+ printf("\tCollecting specific code values is disabled\n");
+
+ if (bufinfo.flags & KDBG_TYPEFILTER_CHECK)
+ printf("\tCollection based on a filter is enabled\n");
+ else
+ printf("\tCollection based on a filter is disabled\n");
+
+ if (bufinfo.flags & KDBG_PIDCHECK)
+ printf("\tCollection based on pid is enabled\n");
+ else
+ printf("\tCollection based on pid is disabled\n");
+
+ if (bufinfo.flags & KDBG_PIDEXCLUDE)
+ printf("\tCollection based on pid exclusion is enabled\n");
+ else
+ printf("\tCollection based on pid exclusion is disabled\n");
+
+ if (bufinfo.bufid == -1)
+ printf("\tKernel buffer is not controlled by any process.\n");
+ else
+ printf("\tKernel buffer is controlled by proc id [%d]\n", bufinfo.bufid);
+
+
+ if (bufinfo.flags & KDBG_TYPEFILTER_CHECK) {
+ if (verbose_flag) {
+ bool (^should_print)(uint8_t*) = ^bool(uint8_t* ptr) {
+ for (uint32_t i=0; i<32; ++i) {
+ if (ptr[i] > 0) return true;
+ }
+
+ return false;
+ };
+
+ uint8_t* typefilter = (uint8_t*)kdebug_typefilter();
+ if (typefilter) {
+ bool header = false;
+
+ // Reduce noise, only print lines that are allowing events.
+ for (uint32_t tclass = 0; tclass < 0x100; ++tclass) {
+ uint8_t* base = &typefilter[tclass * 32];
+ if (should_print(base)) {
+ if (!header) {
+ header = true;
+ printf("\tTypefilter:\n");
+ printf("%18s ","");
+ for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
+ printf("%02x ", tsubclass * 8);
+ }
+ printf("\n");
+ printf("%18s ","");
+ for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
+ printf("---");
+ }
+ printf("\n");
+ }
+ printf("%16s%02x: ", "", tclass);
+ for (uint32_t tsubclass=0; tsubclass<32; ++tsubclass) {
+ printf("%02X ", typefilter[(tclass * 32) + tsubclass]);
+ }
+ printf("\n");
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (init_flag)
+ set_init();
+
+ if (filter_flag)
+ set_filter();
+
+ if (kval_flag)
+ set_kval_list();
+
+ if (execute_flag)
+ {
+ fprintf(stderr, "Starting program: %s\n", argv[optind]);
+ fflush(stdout);
+ fflush(stderr);
+
+ execute_process(&(argv[optind]));
+
+ exit(0);
+ }
+ else if (enable_flag)
+ {
+ if (pid_flag)
+ set_pidcheck(pid, 1);
+ else if (pid_exflag)
+ set_pidexclude(pid, 1);
+ set_enable(1);
+ }
+
+ if (output_filename)
+ {
+ if (((output_fd = open(output_filename, O_CREAT | O_TRUNC | O_WRONLY | O_APPEND, 0644)) < 0 ) ||
+ !(output_file = fdopen(output_fd, "w")))
+ {
+ fprintf(stderr, "Cannot open file \"%s\" for writing.\n", output_filename);
+ usage(SHORT_HELP);
+ }
+ setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
+
+ if (fcntl(output_fd, F_NOCACHE, 1) < 0)
+ {
+ /* Not fatal */
+ fprintf(stderr, "Warning: setting F_NOCACHE on %s, failed\n", output_filename);
+ }
+ }
+ if (!LogRAW_flag && !logRAW_flag)
+ setbuffer(output_file, &sbuffer[0], SBUFFER_SIZE);
+
+ if (trace_flag || readRAW_flag)
+ read_trace();
+ else if (LogRAW_flag)
+ Log_trace();
+ else if (logRAW_flag)
+ log_trace();
+
+ exit(0);
+
+} /* end main */
+
+static void
+execute_process(char * const argv[])
+{
+ int status = 0;
+ int rc = 0;
+ posix_spawnattr_t spawn_attrs;
+
+ assert(argv);
+
+ /* ensure that the process being spawned starts suspended */
+ rc = posix_spawnattr_init(&spawn_attrs);
+ if (rc != 0) {
+ quit_args("Failed to initialize spawn attrs: %s\n", strerror(rc));
+ }
+ rc = posix_spawnattr_setflags(&spawn_attrs,
+ POSIX_SPAWN_START_SUSPENDED);
+ if (rc != 0) {
+ quit_args("Unable to start process suspended: %s\n", strerror(rc));
+ }
+
+ /* spawn the process with the rest of the arguments */
+ rc = posix_spawnp(&pid, argv[0], NULL, &spawn_attrs, argv, environ);
+ if (rc != 0) {
+ quit_args("Unabled to start process: %s\n", strerror(rc));
+ }
+
+ signal(SIGINT, signal_handler);
+ set_pidcheck(pid, 1);
+ set_enable(1);
+
+ /* start the child process */
+ rc = kill(pid, SIGCONT);
+ if (rc != 0) {
+ perror("Failed to continue child process:");
+ exit(EX_OSERR);
+ }
+
+ rc = waitpid(pid, &status, 0);
+ if (rc == -1) {
+ perror("Failed to wait for process: ");
+ }
+}
+
+static void
+quit_args(const char *fmt, ...)
+{
+ char buffer[1024];
+
+ if (reenable == 1)
+ {
+ reenable = 0;
+ set_enable(1); /* re-enable kernel logging */
+ }
+
+ va_list args;
+
+ va_start (args, fmt);
+ vsnprintf(buffer, sizeof(buffer), fmt, args);
+
+ fprintf(stderr, "trace error: %s", buffer);
+
+ va_end(args);
+
+ if (!done_with_args)
+ usage(SHORT_HELP);
+
+ exit(1);
+}
+
+
+void
+quit(char *s)
+{
+ if (reenable == 1)
+ {
+ reenable = 0;
+ set_enable(1); /* re-enable kernel logging */
+ }
+
+ printf("trace: ");
+ if (s)
+ printf("%s", s);
+ exit(1);
+}
+
+static void
+usage(int short_help)
+{
+
+ if (short_help)
+ {
+ (void)fprintf(stderr, " usage: trace -h [-v]\n");
+ (void)fprintf(stderr, " usage: trace -i [-b numbufs]\n");
+ (void)fprintf(stderr, " usage: trace -g\n");
+ (void)fprintf(stderr, " usage: trace -d [-a pid | -x pid ]\n");
+ (void)fprintf(stderr, " usage: trace -r\n");
+ (void)fprintf(stderr, " usage: trace -n\n");
+
+ (void)fprintf(stderr,
+ " usage: trace -e [ -c class [[-s subclass]... | -p class ]]... | \n");
+ (void)fprintf(stderr,
+ " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
+ (void)fprintf(stderr,
+ " [-a pid | -x pid] \n\n");
+
+ (void)fprintf(stderr,
+ " usage: trace -E [ -c class [[-s subclass]... | -p class ]]... | \n");
+ (void)fprintf(stderr,
+ " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter] \n");
+ (void)fprintf(stderr,
+ " executable_path [optional args to executable] \n\n");
+
+ (void)fprintf(stderr,
+ " usage: trace -L RawFilename [-S SecsToRun]\n");
+ (void)fprintf(stderr,
+ " usage: trace -l RawFilename\n");
+ (void)fprintf(stderr,
+ " usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
+ (void)fprintf(stderr,
+ " usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...]\n");
+ (void)fprintf(stderr,
+ " Trace will import /usr/share/misc/trace.codes as a default codefile unless -N is specified. Extra codefiles specified are used in addition to the default codefile.\n");
+ exit(1);
+ }
+
+
+ /* Only get here if printing long usage info */
+ (void)fprintf(stderr, "usage: trace -h [-v]\n");
+ (void)fprintf(stderr, "\tPrint this long command help.\n\n");
+ (void)fprintf(stderr, "\t -v Print extra information about tracefilter and code files.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -i [-b numbufs]\n");
+ (void)fprintf(stderr, "\tInitialize the kernel trace buffer.\n\n");
+ (void)fprintf(stderr, "\t-b numbufs The number of trace elements the kernel buffer\n");
+ (void)fprintf(stderr, "\t can hold is set to numbufs. Use with the -i flag.\n");
+ (void)fprintf(stderr, "\t Enter a decimal value.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -g\n");
+ (void)fprintf(stderr, "\tGet the kernel buffer settings.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -d [-a pid | -x pid]\n");
+ (void)fprintf(stderr, "\tDisable/stop collection of kernel trace elements.\n\n");
+ (void)fprintf(stderr, "\t -a pid Disable/stop collection for this process only.\n\n");
+ (void)fprintf(stderr, "\t -x pid Disable/stop exclusion of this process only.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -r\n");
+ (void)fprintf(stderr, "\tRemove the kernel trace buffer. Set controls to default.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -n\n");
+ (void)fprintf(stderr, "\tDisables kernel buffer wrap around.\n\n");
+
+ (void)fprintf(stderr,
+ "usage: trace -e [ -c class [[-s subclass]... | -p class ]]... |\n");
+ (void)fprintf(stderr,
+ " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
+ (void) fprintf(stderr,
+ " [-a pid | -x pid]\n\n");
+ (void)fprintf(stderr, "\t Enable/start collection of kernel trace elements. \n\n");
+ (void)fprintf(stderr, "\t By default, trace collects all tracepoints. \n");
+ (void)fprintf(stderr, "\t The following arguments may be used to restrict collection \n");
+ (void)fprintf(stderr, "\t to a limited set of tracepoints. \n\n");
+ (void)fprintf(stderr, "\t Multiple classes can be specified by repeating -c. \n");
+ (void)fprintf(stderr, "\t Multiple subclasses can be specified by repeating -s after -c. \n");
+ (void)fprintf(stderr, "\t Classes, subclasses, and class ranges can be entered \n");
+ (void)fprintf(stderr, "\t in hex (0xXX), decimal (XX), or octal (0XX). \n\n");
+ (void)fprintf(stderr, "\t -c class Restrict trace collection to given class. \n\n");
+ (void)fprintf(stderr, "\t -p class Restrict trace collection to given class range. \n");
+ (void)fprintf(stderr, "\t Must provide class with -c first. \n\n");
+ (void)fprintf(stderr, "\t -s subclass Restrict trace collection to given subclass. \n");
+ (void)fprintf(stderr, "\t Must provide class with -c first. \n\n");
+ (void)fprintf(stderr, "\t -a pid Restrict trace collection to the given process.\n\n");
+ (void)fprintf(stderr, "\t -x pid Exclude the given process from trace collection.\n\n");
+ (void)fprintf(stderr, "\t -k code Restrict trace collection up to four specific codes.\n");
+ (void)fprintf(stderr, "\t Enter codes in hex (0xXXXXXXXX). \n\n");
+ (void)fprintf(stderr, "\t -P Enable restricted PPT trace points only.\n\n");
+ (void)fprintf(stderr, "\t -T tracefilter Read class and subclass restrictions from a \n");
+ (void)fprintf(stderr, "\t tracefilter description file. \n");
+ (void)fprintf(stderr, "\t Run trace -h -v for more info on this file. \n\n");
+
+ (void)fprintf(stderr,
+ "usage: trace -E [ -c class [[-s subclass]... | -p class ]]... |\n");
+ (void)fprintf(stderr,
+ " [-k code | -k code | -k code | -k code] [-P] [-T tracefilter]\n");
+ (void)fprintf(stderr,
+ " executable_path [optional args to executable] \n\n");
+ (void)fprintf(stderr, "\tLaunch the given executable and enable/start\n");
+ (void)fprintf(stderr, "\tcollection of kernel trace elements for that process.\n");
+ (void)fprintf(stderr, "\tSee -e(enable) flag for option descriptions.\n\n");
+
+ (void)fprintf(stderr, "usage: trace -t [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
+ (void)fprintf(stderr, "\tCollect the kernel buffer trace data and print it.\n\n");
+ (void)fprintf(stderr, "\t -N Do not import /usr/share/misc/trace.codes (for raw hex tracing or supplying an alternate set of codefiles)\n");
+ (void)fprintf(stderr, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
+
+ (void)fprintf(stderr,
+ "usage: trace -R RawFilename [-X] [-F frequency] [-o OutputFilename] [-N] [ExtraCodeFilename1 ExtraCodeFilename2 ...] \n");
+ (void)fprintf(stderr, "\tRead raw trace file and print it.\n\n");
+ (void)fprintf(stderr, "\t -X Force trace to interpret trace data as 32 bit. \n");
+ (void)fprintf(stderr, "\t Default is to match the bit width of the current system. \n");
+ (void)fprintf(stderr, "\t -N Do not import /usr/share/misc/trace.codes (for raw hex tracing or supplying an alternate set of codefiles)\n");
+ (void)fprintf(stderr, "\t -F frequency Specify the frequency of the clock used to timestamp entries in RawFilename.\n\t Use command \"sysctl hw.tbfrequency\" on the target device, to get target frequency.\n");
+ (void)fprintf(stderr, "\t -o OutputFilename Print trace output to OutputFilename. Default is stdout.\n\n");
+
+ (void)fprintf(stderr,
+ "usage: trace -L RawFilename [-S SecsToRun]\n");
+ (void)fprintf(stderr, "\tContinuously collect the kernel buffer trace data in the raw format \n");
+ (void)fprintf(stderr, "\tand write it to RawFilename. \n");
+
+ (void)fprintf(stderr, "\t-L implies -r -i if tracing isn't currently enabled.\n");
+ (void)fprintf(stderr, "\tOptions passed to -e(enable) are also accepted by -L. (except -a -x -P)\n\n");
+ (void)fprintf(stderr, "\t -S SecsToRun Specify the number of seconds to collect trace data.\n\n");
+
+ (void)fprintf(stderr,
+ "usage: trace -l RawFilename\n");
+ (void)fprintf(stderr, "\tCollect the existing kernel buffer trace data in the raw format.\n\n");
+
+ if (verbose_flag) {
+ (void)fprintf(stderr,
+ "Code file: \n"
+ "\t A code file consists of a list of tracepoints, one per line, \n"
+ "\t with one tracepoint code in hex, followed by a tab, \n"
+ "\t followed by the tracepoint's name. \n\n"
+
+ "\t Example tracepoint: \n"
+ "\t 0x010c007c\tMSC_mach_msg_trap \n"
+ "\t This describes the tracepoint with the following info: \n"
+ "\t Name: MSC_mach_msg_trap \n"
+ "\t Class: 0x01 (Mach events) \n"
+ "\t Subclass: 0x0c (Mach system calls) \n"
+ "\t Code: 0x007c (Mach syscall number 31) \n\n"
+
+ "\t See /usr/include/sys/kdebug.h for the currently defined \n"
+ "\t class and subclass values. \n"
+ "\t See /usr/share/misc/trace.codes for the currently allocated \n"
+ "\t system tracepoints in trace code file format. \n"
+ "\t This codefile is useful with the -R argument to trace. \n"
+ "\n");
+
+ (void)fprintf(stderr,
+ "Tracefilter description file: \n"
+ "\t A tracefilter description file consists of a list of \n"
+ "\t class and subclass filters in hex, one per line, \n"
+ "\t which are applied as if they were passed with -c and -s. \n"
+ "\t Pass -v to see what classes and subclasses are being set. \n\n"
+
+ "\t File syntax: \n"
+ "\t Class filter: \n"
+ "\t C 0xXX \n"
+ "\t Subclass filter (includes class): \n"
+ "\t S 0xXXXX \n"
+ "\t Comment: \n"
+ "\t # This is a comment \n\n"
+
+ "\t For example, to trace Mach events (class 1):\n"
+ "\t C 0x01 \n"
+ "\t or to trace Mach system calls (class 1 subclass 13): \n"
+ "\t S 0x010C \n"
+ "\n");
+ }
+
+ exit(1);
+}
+
+
+static int
+argtoi(int flag, char *req, char *str, int base)
+{
+ char *cp;
+ int ret;
+
+ ret = (int)strtol(str, &cp, base);
+ if (cp == str || *cp)
+ errx(EINVAL, "-%c flag requires a %s", flag, req);
+ return (ret);
+}
+
+static unsigned long
+argtoul(int flag, char *req, char *str, int base)
+{
+ char *cp;
+ unsigned long ret;
+
+ ret = (int)strtoul(str, &cp, base);
+ if (cp == str || *cp)
+ errx(EINVAL, "-%c flag requires a %s", flag, req);
+ return (ret);
+}
+
+/*
+ * comparison function for qsort
+ * sort by debugid
+ */
+int
+debugid_compar(const void *p1, const void *p2)
+{
+ const code_type_t *q1 = (const code_type_t *)p1;
+ const code_type_t *q2 = (const code_type_t *)p2;
+
+ if (q1->debugid > q2->debugid)
+ return (1);
+ else if (q1->debugid == q2->debugid)
+ return (0);
+ else
+ return (-1);
+}
+
+/*
+ * Filter args parsing state machine:
+ *
+ * Allowed args:
+ * -c -p
+ * -c -s (-s)*
+ * -c (-c)*
+ * every -c goes back to start
+ *
+ * Valid transitions:
+ * start -> class (first -c)
+ * class -> range (-c -p)
+ * class -> sub (-c -s)
+ * class -> class (-c -c)
+ * range -> class (-c -p -c)
+ * sub -> class (-c -s -c)
+ * * -> start (on filter_done_parsing)
+ *
+ * Need to call filter_done_parsing after
+ * calling saw_filter_*
+ * to flush out any class flag waiting to see if
+ * there is a -s flag coming up
+ */
+
+
+// What type of flag did I last see?
+enum {
+ FILTER_MODE_START,
+ FILTER_MODE_CLASS,
+ FILTER_MODE_CLASS_RANGE,
+ FILTER_MODE_SUBCLASS
+} filter_mode = FILTER_MODE_START;
+
+uint8_t filter_current_class = 0;
+uint8_t filter_current_subclass = 0;
+uint8_t filter_current_class_range = 0;
+
+static void
+saw_filter_class(uint8_t class)
+{
+ switch(filter_mode) {
+ case FILTER_MODE_START:
+ case FILTER_MODE_CLASS_RANGE:
+ case FILTER_MODE_SUBCLASS:
+ filter_mode = FILTER_MODE_CLASS;
+ filter_current_class = class;
+ filter_current_subclass = 0;
+ filter_current_class_range = 0;
+ // the case of a lone -c is taken care of
+ // by filter_done_parsing
+ break;
+ case FILTER_MODE_CLASS:
+ filter_mode = FILTER_MODE_CLASS;
+ // set old class, remember new one
+ set_filter_class(filter_current_class);
+ filter_current_class = class;
+ filter_current_subclass = 0;
+ filter_current_class_range = 0;
+ break;
+ default:
+ quit_args("invalid case in saw_filter_class\n");
+ }
+}
+
+static void
+saw_filter_end_range(uint8_t end_class)
+{
+ switch(filter_mode) {
+ case FILTER_MODE_CLASS:
+ filter_mode = FILTER_MODE_CLASS_RANGE;
+ filter_current_class_range = end_class;
+ set_filter_range(filter_current_class, filter_current_class_range);
+ break;
+ case FILTER_MODE_START:
+ quit_args("must provide '-c class' before '-p 0x%x'\n",
+ end_class);
+ case FILTER_MODE_CLASS_RANGE:
+ quit_args("extra range end '-p 0x%x'"
+ " for class '-c 0x%x'\n",
+ end_class, filter_current_class);
+ case FILTER_MODE_SUBCLASS:
+ quit_args("cannot provide both range end '-p 0x%x'"
+ " and subclass '-s 0x%x'"
+ " for class '-c 0x%x'\n",
+ end_class, filter_current_subclass,
+ filter_current_class);
+ default:
+ quit_args("invalid case in saw_filter_end_range\n");
+ }
+}
+
+static void
+saw_filter_subclass(uint8_t subclass)
+{
+ switch(filter_mode) {
+ case FILTER_MODE_CLASS:
+ case FILTER_MODE_SUBCLASS:
+ filter_mode = FILTER_MODE_SUBCLASS;
+ filter_current_subclass = subclass;
+ set_filter_subclass(filter_current_class, filter_current_subclass);
+ break;
+ case FILTER_MODE_START:
+ quit_args("must provide '-c class'"
+ " before subclass '-s 0x%x'\n", subclass);
+ case FILTER_MODE_CLASS_RANGE:
+ quit_args("cannot provide both range end '-p 0x%x'"
+ " and subclass '-s 0x%x'"
+ " for the same class '-c 0x%x'\n",
+ filter_current_class_range,
+ subclass, filter_current_class);
+ default:
+ quit_args("invalid case in saw_filter_subclass\n");
+ }
+}
+
+static void
+filter_done_parsing(void)
+{
+ switch(filter_mode) {
+ case FILTER_MODE_CLASS:
+ // flush out the current class
+ set_filter_class(filter_current_class);
+ filter_mode = FILTER_MODE_START;
+ filter_current_class = 0;
+ filter_current_subclass = 0;
+ filter_current_class_range = 0;
+ break;
+ case FILTER_MODE_SUBCLASS:
+ case FILTER_MODE_START:
+ case FILTER_MODE_CLASS_RANGE:
+ filter_mode = FILTER_MODE_START;
+ filter_current_class = 0;
+ filter_current_subclass = 0;
+ filter_current_class_range = 0;
+ break;
+ default:
+ quit_args("invalid case in filter_done_parsing\n");
+ }
+}
+
+/* Tell set_filter_subclass not to print every. single. subclass. */
+static boolean_t setting_class = FALSE;
+static boolean_t setting_range = FALSE;
+
+static void
+set_filter_subclass(uint8_t class, uint8_t subclass)
+{
+ if (!filter_alloced) {
+ type_filter_bitmap = (uint8_t *) calloc(1, KDBG_TYPEFILTER_BITMAP_SIZE);
+ if (type_filter_bitmap == NULL)
+ quit_args("Could not allocate type_filter_bitmap.\n");
+ filter_alloced = 1;
+ }
+
+ uint16_t csc = ENCODE_CSC_LOW(class, subclass);
+
+ if (verbose_flag && !setting_class)
+ printf("tracing subclass: 0x%4.4x\n", csc);
+
+ if (verbose_flag && isset(type_filter_bitmap, csc))
+ printf("class %u (0x%2.2x), subclass %u (0x%2.2x) set twice.\n",
+ class, class, subclass, subclass);
+
+ setbit(type_filter_bitmap, csc);
+}
+
+static void
+set_filter_class(uint8_t class)
+{
+ if (verbose_flag && !setting_range)
+ printf("tracing class: 0x%2.2x\n", class);
+
+ setting_class = TRUE;
+
+ for (int i = 0; i < 256; i++)
+ set_filter_subclass(class, i);
+
+ setting_class = FALSE;
+}
+
+static void
+set_filter_range(uint8_t class, uint8_t end)
+{
+ if (verbose_flag)
+ printf("tracing range: 0x%2.2x - 0x%2.2x\n", class, end);
+
+ setting_range = TRUE;
+
+ for (int i = class; i <= end; i++)
+ set_filter_class(i);
+
+ setting_range = FALSE;
+}
+
+/*
+ * Syntax of filter file:
+ * Hexadecimal numbers only
+ * Class:
+ * C 0xXX
+ * Subclass (includes class):
+ * S 0xXXXX
+ * Comment:
+ * # <string>
+ * TBD: Class ranges?
+ * TBD: K for -k flag?
+ */
+
+static void
+parse_filter_file(char *filename)
+{
+ FILE* file;
+ uint32_t current_line = 0;
+ uint32_t parsed_arg = 0;
+ int rval;
+
+ char line[256];
+
+ if ( (file = fopen(filename, "r")) == NULL ) {
+ quit_args("Failed to open filter description file %s: %s\n",
+ filename, strerror(errno));
+ }
+
+ if (verbose_flag)
+ printf("Parsing typefilter file: %s\n", filename);
+
+ while( fgets(line, sizeof(line), file) != NULL ) {
+ current_line++;
+
+ switch (line[0]) {
+ case 'C':
+ rval = sscanf(line, "C 0x%x\n", &parsed_arg);
+ if (rval != 1)
+ quit_args("invalid line %d of file %s: %s\n",
+ current_line, filename, line);
+ if (parsed_arg > 0xFF)
+ quit_args("line %d of file %s: %s\n"
+ "parsed as 0x%x, "
+ "class value must be 0x0-0xFF\n",
+ current_line, filename, line, parsed_arg);
+ set_filter_class((uint8_t)parsed_arg);
+ break;
+ case 'S':
+ rval = sscanf(line, "S 0x%x\n", &parsed_arg);
+ if (rval != 1)
+ quit_args("invalid line %d of file %s: %s\n",
+ current_line, filename, line);
+ if (parsed_arg > 0xFFFF)
+ quit_args("line %d of file %s: %s\n"
+ "parsed as 0x%x, "
+ "value must be 0x0-0xFFFF\n",
+ current_line, filename, line, parsed_arg);
+ set_filter_subclass(EXTRACT_CLASS_LOW(parsed_arg),
+ EXTRACT_SUBCLASS_LOW(parsed_arg));
+ break;
+ case '#':
+ // comment
+ break;
+ case '\n':
+ // empty line
+ break;
+ case '\0':
+ // end of file
+ break;
+ default:
+ quit_args("Invalid filter description file: %s\n"
+ "could not parse line %d: %s\n",
+ filename, current_line, line);
+ }
+ }
+
+ fclose(file);
+}
+
+/*
+ * Find the debugid code in the list and return its index
+ */
+static int
+binary_search(code_type_t *list, int lowbound, int highbound, unsigned int code)
+{
+ int low, high, mid;
+ int tries = 0;
+
+ low = lowbound;
+ high = highbound;
+
+ while (1)
+ {
+ mid = (low + high) / 2;
+
+ tries++;
+
+ if (low > high)
+ return (-1); /* failed */
+ else if ( low + 1 >= high)
+ {
+ /* We have a match */
+ if (list[high].debugid == code)
+ return(high);
+ else if (list[low].debugid == code)
+ return(low);
+ else
+ return(-1); /* search failed */
+ }
+ else if (code < list[mid].debugid)
+ high = mid;
+ else
+ low = mid;
+ }
+}
+
+
+static int
+parse_codefile(const char *filename)
+{
+ int fd;
+ int j, line;
+ size_t count;
+ struct stat stat_buf;
+ size_t file_size;
+ char *file_addr, *endp;
+
+ if ((fd = open(filename, O_RDONLY, 0)) == -1)
+ {
+ printf("Failed to open code description file %s\n",filename);
+ return(-1);
+ }
+
+ if (fstat(fd, &stat_buf) == -1)
+ {
+ printf("Error: Can't fstat file: %s\n", filename);
+ return(-1);
+ }
+
+ /*
+ * For some reason mapping files with zero size fails
+ * so it has to be handled specially.
+ */
+ file_size = (size_t)stat_buf.st_size;
+
+ if (stat_buf.st_size != 0)
+ {
+ file_addr = mmap(0, file_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FILE, fd, 0);
+ if (file_addr == MAP_FAILED)
+ {
+ printf("Error: Can't map file: %s\n", filename);
+ close(fd);
+ return(-1);
+ }
+ }
+ else
+ {
+ // Skip empty files
+ close(fd);
+ return(0);
+ }
+ close(fd);
+
+
+ /*
+ * If we get here, we have mapped the file
+ * and we are ready to parse it. Count
+ * the newlines to get total number of codes.
+ */
+
+ for (count = 0, j=1; j < file_size; j++)
+ {
+ if (file_addr[j] == '\n')
+ count++;
+ }
+
+ if (count == 0)
+ {
+ printf("Error: No codes in %s\n", filename);
+ return(-1);
+ }
+
+ /*
+ * Fudge the count to accomodate the last line in the file -
+ * in case it doesn't end in a newline.
+ */
+ count++;
+
+ /* Grow the size of codesc to store new entries. */
+ size_t total_count = codesc_idx + count;
+ code_type_t *new_codesc = (code_type_t *)realloc(codesc, (total_count) * sizeof(code_type_t));
+
+ if (new_codesc == NULL) {
+ printf("Failed to grow/allocate buffer. Skipping file %s\n", filename);
+ return (-1);
+ }
+ codesc = new_codesc;
+ bzero((char *)(codesc + codesc_idx), count * sizeof(code_type_t));
+
+ for (line = 1, j = 0; j < file_size && codesc_idx < total_count;
+ codesc_idx++)
+ {
+ /* Skip blank lines */
+ while (j < file_size && file_addr[j] == '\n')
+ {
+ j++;
+ line++;
+ }
+
+ /* Skip leading whitespace */
+ while (file_addr[j] == ' ' || file_addr[j] == '\t')
+ j++;
+
+ /* Get the debugid code */
+ codesc[codesc_idx].debugid = (uint32_t)strtoul(file_addr + j, &endp, 16);
+ j = (int)(endp - file_addr);
+
+ if (codesc[codesc_idx].debugid == 0)
+ {
+ /* We didn't find a debugid code - skip this line */
+ if (verbose_flag)
+ printf("Error: while parsing line %d, skip\n", line);
+ while (j < file_size && file_addr[j] != '\n')
+ j++;
+ codesc_idx--;
+ line++;
+ continue;
+ }
+
+ /* Skip whitespace */
+ while (j < file_size && (file_addr[j] == ' ' || file_addr[j] == '\t'))
+ {
+ j++;
+ }
+
+ if (j >= file_size)
+ {
+ break;
+ }
+
+ /* Get around old file that had count at the beginning */
+ if (file_addr[j] == '\n')
+ {
+ /* missing debugid string - skip */
+ if (verbose_flag)
+ {
+ printf("Error: while parsing line %d, (0x%x) skip\n", line,
+ codesc[codesc_idx].debugid);
+ }
+
+ j++;
+ codesc_idx--;
+ line++;
+ continue;
+ }
+
+ if (j >= file_size)
+ {
+ break;
+ }
+
+ /* Next is the debugid string terminated by a newline */
+ codesc[codesc_idx].debug_string = &file_addr[j];
+
+ /* Null out the newline terminator */
+ while (j < file_size && file_addr[j] != '\n')
+ {
+ j++;
+ }
+
+ if (j >= file_size)
+ {
+ break;
+ }
+
+ file_addr[j] = '\0'; /* File must be read-write */
+ j++;
+ line++;
+ codenum++; /*Index into codesc is 0 to codenum-1 */
+ }
+
+ if (verbose_flag)
+ {
+ printf("Parsed %d codes in %s\n", codenum, filename);
+ printf("[%6d] 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string);
+ printf("[%6d] 0x%8x %s\n\n", codenum-1, codesc[codenum-1].debugid, codesc[codenum-1].debug_string);
+ }
+
+ /* sort */
+ qsort((void *)codesc, codesc_idx, sizeof(code_type_t), debugid_compar);
+
+ if (verbose_flag)
+ {
+ printf("Sorted %zd codes in %s\n", codesc_idx, filename);
+ printf("lowbound [%6d]: 0x%8x %s\n", 0, codesc[0].debugid, codesc[0].debug_string);
+ printf("highbound [%6zd]: 0x%8x %s\n\n", codesc_idx - 1, codesc[codesc_idx - 1].debugid, codesc[codesc_idx - 1].debug_string);
+ }
+ codesc_find_dupes();
+
+#if 0
+ /* Dump the codefile */
+ int i;
+ for (i = 0; i < codesc_idx; i++)
+ printf("[%d] 0x%x %s\n",i+1, codesc[i].debugid, codesc[i].debug_string);
+#endif
+ return(0);
+}
+
+static void
+codesc_find_dupes(void)
+{
+ boolean_t found_dupes = FALSE;
+ if (codesc_idx == 0)
+ {
+ return;
+ }
+ uint32_t last_debugid = codesc[0].debugid;
+ for(int i = 1; i < codesc_idx; i++)
+ {
+ if(codesc[i].debugid == last_debugid)
+ {
+ found_dupes = TRUE;
+ if (verbose_flag) {
+ fprintf(stderr, "WARNING: The debugid 0x%"PRIx32" (%s) has already been defined as '%s'.\n", codesc[i].debugid, codesc[i].debug_string, codesc[i - 1].debug_string);
+ }
+ }
+ last_debugid = codesc[i].debugid;
+ }
+ if (found_dupes)
+ {
+ fprintf(stderr, "WARNING: One or more duplicate entries found in your codefiles, which will lead to unpredictable decoding behavior. Re-run with -v for more info\n");
+ }
+}
+
+int
+match_debugid(unsigned int xx, char * debugstr, int * yy)
+{
+ int indx;
+
+ if (codenum == 0)
+ return(-1);
+
+ if (codesc[codeindx_cache].debugid != xx)
+ indx = binary_search(codesc, 0, (codenum-1), xx);
+ else
+ indx = codeindx_cache;
+
+ if (indx == -1)
+ return(indx); /* match failed */
+ else {
+ bcopy(&codesc[indx].debug_string[0], debugstr,80);
+ *yy = indx;
+ codeindx_cache = indx;
+ return(0); /* match success */
+ }
+}
+
+void
+read_cpu_map(int fd)
+{
+ if (cpumap_header) {
+ free(cpumap_header);
+ cpumap_header = NULL;
+ cpumap = NULL;
+ }
+
+ /*
+ * To fit in the padding space of a VERSION1 file, the max possible
+ * cpumap size is one page.
+ */
+ cpumap_header = malloc(PAGE_SIZE);
+
+ if (readRAW_flag) {
+ /*
+ * cpu maps exist in a RAW_VERSION1+ header only
+ */
+ if (raw_header.version_no == RAW_VERSION1) {
+ off_t cpumap_position = lseek(fd, 0, SEEK_CUR);
+ /* cpumap is part of the last 4KB of padding in the preamble */
+ size_t padding_bytes = SIZE_4KB - (cpumap_position & (SIZE_4KB - 1));
+
+ if (read(fd, cpumap_header, padding_bytes) == padding_bytes) {
+ if (cpumap_header->version_no == RAW_VERSION1) {
+ cpumap = (kd_cpumap*)&cpumap_header[1];
+ }
+ }
+ }
+ } else {
+ int mib[3];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDCPUMAP;
+
+ size_t temp = PAGE_SIZE;
+ if (sysctl(mib, 3, cpumap_header, &temp, NULL, 0) == 0) {
+ if (PAGE_SIZE >= temp) {
+ if (cpumap_header->version_no == RAW_VERSION1) {
+ cpumap = (kd_cpumap*)&cpumap_header[1];
+ }
+ }
+ }
+ }
+
+ if (!cpumap) {
+ printf("Can't read the cpu map -- this is not fatal\n");
+ free(cpumap_header);
+ cpumap_header = NULL;
+ } else if (verbose_flag) {
+ /* Dump the initial cpumap */
+ printf("\nCPU\tName\n");
+ for (int i = 0; i < cpumap_header->cpu_count; i++) {
+ printf ("%2d\t%s\n", cpumap[i].cpu_id, cpumap[i].name);
+ }
+ printf("\n");
+ }
+}
+
+int
+read_command_map(int fd, uint32_t count)
+{
+ int i;
+ size_t size;
+ int mib[6];
+
+ if (readRAW_flag) {
+ total_threads = count;
+ size = count * sizeof(kd_threadmap);
+ } else {
+ get_bufinfo(&bufinfo);
+
+ total_threads = bufinfo.nkdthreads;
+ size = bufinfo.nkdthreads * sizeof(kd_threadmap);
+ }
+ mapptr = 0;
+ nthreads = total_threads * 2;
+
+ if (verbose_flag)
+ printf("Size of map table is %d, thus %d entries\n", (int)size, total_threads);
+
+ if (size) {
+ if ((mapptr = (kd_threadmap *) malloc(size)))
+ bzero (mapptr, size);
+ else
+ {
+ if (verbose_flag)
+ printf("Thread map is not initialized -- this is not fatal\n");
+ return(0);
+ }
+ }
+ if (readRAW_flag) {
+ if (read(fd, mapptr, size) != size) {
+ if (verbose_flag)
+ printf("Can't read the thread map -- this is not fatal\n");
+ free(mapptr);
+ mapptr = 0;
+
+ return (int)size;
+ }
+ } else {
+ /* Now read the threadmap */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_KDEBUG;
+ mib[2] = KERN_KDTHRMAP;
+ mib[3] = 0;
+ mib[4] = 0;
+ mib[5] = 0; /* no flags */
+ if (sysctl(mib, 3, mapptr, &size, NULL, 0) < 0)
+ {
+ /* This is not fatal -- just means I cant map command strings */
+ if (verbose_flag)
+ printf("Can't read the thread map -- this is not fatal\n");
+ free(mapptr);
+ mapptr = 0;
+ return(0);
+ }
+ }
+ for (i = 0; i < total_threads; i++) {
+ if (mapptr[i].thread)
+ create_map_entry(mapptr[i].thread, &mapptr[i].command[0]);
+ }
+
+ if (verbose_flag) {
+ /* Dump the initial map */
+
+ printf("Size of maptable returned is %ld, thus %ld entries\n", size, (size/sizeof(kd_threadmap)));
+
+ printf("Thread Command\n");
+ for (i = 0; i < total_threads; i++) {
+ printf ("0x%" PRIx64 " %s\n",
+ (uint64_t)mapptr[i].thread,
+ mapptr[i].command);
+ }
+ }
+
+ return (int)size;
+}
+
+void
+create_map_entry(uint64_t thread, char *command)
+{
+ threadmap_t tme;
+ int hashid;
+
+ if ((tme = threadmap_freelist))
+ threadmap_freelist = tme->tm_next;
+ else
+ tme = (threadmap_t)malloc(sizeof(struct threadmap));
+
+ tme->tm_thread = thread;
+ tme->tm_deleteme = FALSE;
+
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+
+ hashid = thread & HASH_MASK;
+
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+}
+
+void
+delete_thread_entry(uint64_t thread)
+{
+ threadmap_t tme = 0;
+ threadmap_t tme_prev;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ if ((tme = threadmap_hash[hashid])) {
+ if (tme->tm_thread == thread)
+ threadmap_hash[hashid] = tme->tm_next;
+ else {
+ tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ tme->tm_next = threadmap_freelist;
+ threadmap_freelist = tme;
+ }
+ }
+}
+
+void
+find_and_insert_tmp_map_entry(uint64_t pthread, char *command)
+{
+ threadmap_t tme = 0;
+ threadmap_t tme_prev;
+ int hashid;
+
+ if ((tme = threadmap_temp)) {
+ if (tme->tm_pthread == pthread)
+ threadmap_temp = tme->tm_next;
+ else {
+ tme_prev = tme;
+
+ for (tme = tme->tm_next; tme; tme = tme->tm_next) {
+ if (tme->tm_pthread == pthread) {
+ tme_prev->tm_next = tme->tm_next;
+ break;
+ }
+ tme_prev = tme;
+ }
+ }
+ if (tme) {
+ (void)strncpy (tme->tm_command, command, MAXCOMLEN);
+ tme->tm_command[MAXCOMLEN] = '\0';
+
+ delete_thread_entry(tme->tm_thread);
+
+ hashid = tme->tm_thread & HASH_MASK;
+
+ tme->tm_next = threadmap_hash[hashid];
+ threadmap_hash[hashid] = tme;
+ }
+ }
+}
+
+void
+create_tmp_map_entry(uint64_t thread, uint64_t pthread)
+{
+ threadmap_t tme;
+
+ if ((tme = threadmap_freelist))
+ threadmap_freelist = tme->tm_next;
+ else
+ tme = (threadmap_t)malloc(sizeof(struct threadmap));
+
+ tme->tm_thread = thread;
+ tme->tm_pthread = pthread;
+ tme->tm_deleteme = FALSE;
+ tme->tm_command[0] = '\0';
+
+ tme->tm_next = threadmap_temp;
+ threadmap_temp = tme;
+}
+
+
+threadmap_t
+find_thread_entry(uint64_t thread)
+{
+ threadmap_t tme;
+ int hashid;
+
+ hashid = thread & HASH_MASK;
+
+ for (tme = threadmap_hash[hashid]; tme; tme = tme->tm_next) {
+ if (tme->tm_thread == thread)
+ return (tme);
+ }
+ return (0);
+}
+
+void
+find_thread_name(uint64_t thread, char **command, boolean_t deleteme)
+{
+ threadmap_t tme;
+
+ if ((tme = find_thread_entry(thread))) {
+ *command = tme->tm_command;
+
+ if (deleteme == TRUE)
+ tme->tm_deleteme = deleteme;
+ } else
+ *command = EMPTYSTRING;
+}
+
+void
+find_thread_command(kd_buf *kbufp, char **command)
+{
+ uint64_t thread;
+ threadmap_t tme;
+ int debugid_base;
+
+ *command = EMPTYSTRING;
+
+ thread = kbufp->arg5;
+ debugid_base = kbufp->debugid & DBG_FUNC_MASK;
+
+ if (debugid_base == BSC_exit || debugid_base == MACH_STKHANDOFF) {
+ /*
+ * Mark entry as invalid and return temp command pointer
+ */
+ if ((tme = find_thread_entry(thread))) {
+
+ strncpy(tmpcommand, tme->tm_command, MAXCOMLEN);
+ *command = tmpcommand;
+
+ if (debugid_base == BSC_exit || tme->tm_deleteme == TRUE)
+ delete_thread_entry(thread);
+ }
+ }
+ else if (debugid_base == TRACE_DATA_NEWTHREAD) {
+ /*
+ * Save the create thread data
+ */
+ create_tmp_map_entry(kbufp->arg1, kbufp->arg5);
+ }
+ else if (debugid_base == TRACE_STRING_NEWTHREAD) {
+ /*
+ * process new map entry
+ */
+ find_and_insert_tmp_map_entry(kbufp->arg5, (char *)&kbufp->arg1);
+ }
+ else if (debugid_base == TRACE_STRING_EXEC) {
+
+ delete_thread_entry(kbufp->arg5);
+
+ create_map_entry(kbufp->arg5, (char *)&kbufp->arg1);
+ }
+ else
+ find_thread_name(thread, command, (debugid_base == BSC_thread_terminate));
+}
+
+static void
+getdivisor(void)
+{
+ (void) mach_timebase_info (&mach_timebase);
+
+ if (frequency == 0) {
+ divisor = ( (double)mach_timebase.denom / (double)mach_timebase.numer) * 1000;
+ } else
+ divisor = (double)frequency / 1000000;
+
+ if (verbose_flag)
+ printf("divisor = %g\n", divisor);
+}
diff --git a/system_cmds/vifs.tproj/vifs.8 b/system_cmds/vifs.tproj/vifs.8
new file mode 100644
index 0000000..a5d2e1a
--- /dev/null
+++ b/system_cmds/vifs.tproj/vifs.8
@@ -0,0 +1,46 @@
+.\"
+.\" (c) 2005 Apple Computer, Inc. All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\"
+.\" The contents of this file constitute Original Code as defined in and
+.\" are subject to the Apple Public Source License Version 1.1 (the
+.\" "License"). You may not use this file except in compliance with the
+.\" License. Please obtain a copy of the License at
+.\" http://www.apple.com/publicsource and read it before using this file.
+.\"
+.\" This Original Code and all software distributed under the License are
+.\" distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+.\" License for the specific language governing rights and limitations
+.\" under the License.
+.\"
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd November 18, 2005
+.Dt VIFS 8
+.Os
+.Sh NAME
+.Nm vifs
+.Nd safely edit fstab
+.Sh SYNOPSIS
+.Nm vifs
+.Sh DESCRIPTION
+The
+.Nm vifs
+utility simply locks the fstab file before invoking an editor on it.
+This is important to facilitate the modification of fstab by automated tools
+and system management software.
+.Pp
+Always use
+.Nm vifs
+to edit fstab, instead of invoking an editor directly.
+.Sh SEE ALSO
+.Xr vi 1 ,
+.Xr fstab 5
+.Sh HISTORY
+The
+.Nm vifs
+utility originates from Mac OSX 10.5.
diff --git a/system_cmds/vifs.tproj/vifs.c b/system_cmds/vifs.tproj/vifs.c
new file mode 100644
index 0000000..967cc1d
--- /dev/null
+++ b/system_cmds/vifs.tproj/vifs.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2005-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+#include <unistd.h>
+#include <signal.h>
+
+char *warning = "\
+#\n\
+# Warning - this file should only be modified with vifs(8)\n\
+#\n\
+# Failure to do so is unsupported and may be destructive.\n\
+#\n";
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ int fd, x;
+ uid_t euid;
+ pid_t editpid;
+ char *p, *editor;
+
+ if (argc != 1) {
+ printf("usage: vifs\n");
+ exit(1);
+ }
+
+ euid = geteuid();
+ if (euid != 0)
+ errx(1, "need to run as root");
+
+ /* examine the existing fstab, try to create it if needed */
+ if (stat(_PATH_FSTAB, &sb) < 0) {
+ if (errno == ENOENT) {
+ fd = open(_PATH_FSTAB, O_CREAT | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ errx(1, "error creating %s", _PATH_FSTAB);
+ write(fd, warning, strlen(warning));
+ close(fd);
+ } else {
+ errx(1, "could not stat %s", _PATH_FSTAB);
+ }
+ }
+
+ /* prepare the file for the editor */
+ fd = open(_PATH_FSTAB, O_RDONLY, 0);
+ if (fd < 0)
+ errx(1, "error opening %s", _PATH_FSTAB);
+
+ x = fcntl(fd, F_SETFD, 1);
+ if (x < 0)
+ errx(1, "error setting close on exit");
+
+ x = flock(fd, LOCK_EX | LOCK_NB);
+ if (x != 0)
+ errx(1, "file is busy");
+
+ /* obtain and invoke the editor */
+ editor = getenv("EDITOR");
+ if (editor == NULL)
+ editor = _PATH_VI;
+ p = strrchr(editor, '/');
+ if (p != NULL)
+ ++p;
+ else
+ p = editor;
+
+ editpid = vfork();
+ if (editpid == 0) {
+ execlp(editor, p, _PATH_FSTAB, NULL);
+ _exit(1);
+ }
+
+ for ( ; ; ) {
+ editpid = waitpid(editpid, (int *)&x, WUNTRACED);
+ if (editpid == -1)
+ errx(1, "editing error");
+ else if (WIFSTOPPED(x))
+ raise(WSTOPSIG(x));
+ else if (WIFEXITED(x) && WEXITSTATUS(x) == 0)
+ break;
+ else
+ errx(1, "editing error");
+ }
+
+ /* let process death clean up locks and file descriptors */
+ return 0;
+}
diff --git a/system_cmds/vipw.tproj/pw_util.c b/system_cmds/vipw.tproj/pw_util.c
new file mode 100644
index 0000000..8364496
--- /dev/null
+++ b/system_cmds/vipw.tproj/pw_util.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#include <sys/cdefs.h>
+__unused static char sccsid[] = "@(#)pw_util.c 8.4 (Berkeley) 4/28/95";
+#endif /* not lint */
+
+/*
+ * This file is used by all the "password" programs; vipw(8), chpass(1),
+ * and passwd(1).
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pw_util.h"
+
+extern char *tempname;
+static pid_t editpid = -1;
+static int lockfd;
+
+static void
+pw_cont(int sig)
+{
+ if (editpid != -1)
+ kill(editpid, sig);
+}
+
+void
+pw_init(void)
+{
+ struct rlimit rlim;
+
+ /* Unlimited resource limits. */
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &rlim);
+ (void)setrlimit(RLIMIT_FSIZE, &rlim);
+ (void)setrlimit(RLIMIT_STACK, &rlim);
+ (void)setrlimit(RLIMIT_DATA, &rlim);
+ (void)setrlimit(RLIMIT_RSS, &rlim);
+
+ /* Don't drop core (not really necessary, but GP's). */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ (void)setrlimit(RLIMIT_CORE, &rlim);
+
+ /* Turn off signals. */
+ (void)signal(SIGALRM, SIG_IGN);
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGTERM, SIG_IGN);
+ (void)signal(SIGCONT, pw_cont);
+
+ /* Create with exact permissions. */
+ (void)umask(0);
+}
+
+int
+pw_lock(void)
+{
+ /*
+ * If the master password file doesn't exist, the system is hosed.
+ * Might as well try to build one. Set the close-on-exec bit so
+ * that users can't get at the encrypted passwords while editing.
+ * Open should allow flock'ing the file; see 4.4BSD. XXX
+ */
+ lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
+ if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
+ err(1, "%s", _PATH_MASTERPASSWD);
+ if (flock(lockfd, LOCK_EX|LOCK_NB))
+ errx(1, "the password db file is busy");
+ return (lockfd);
+}
+
+int
+pw_tmp(void)
+{
+ static char path[MAXPATHLEN] = _PATH_MASTERPASSWD;
+ int fd;
+ char *p;
+
+ if ((p = strrchr(path, '/')))
+ ++p;
+ else
+ p = path;
+ strcpy(p, "pw.XXXXXX");
+ if ((fd = mkstemp(path)) == -1)
+ err(1, "%s", path);
+ tempname = path;
+ return (fd);
+}
+
+int
+pw_mkdb(void)
+{
+ int pstat;
+ pid_t pid;
+
+ warnx("rebuilding the database...");
+ (void)fflush(stderr);
+ if (!(pid = vfork())) {
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", tempname, NULL);
+ pw_error(_PATH_PWD_MKDB, 1, 1);
+ }
+ pid = waitpid(pid, &pstat, 0);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
+ return (1);
+ warnx("done");
+ return (0);
+}
+
+void
+pw_edit(int notsetuid)
+{
+ int pstat;
+ char *p, *editor;
+
+ if (!(editor = getenv("EDITOR")))
+ editor = _PATH_VI;
+ if ((p = strrchr(editor, '/')))
+ ++p;
+ else
+ p = editor;
+
+ if (!(editpid = vfork())) {
+ if (notsetuid) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+ execlp(editor, p, tempname, NULL);
+ _exit(1);
+ }
+ for (;;) {
+ editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
+ if (editpid == -1)
+ pw_error(editor, 1, 1);
+ else if (WIFSTOPPED(pstat))
+ raise(WSTOPSIG(pstat));
+ else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
+ break;
+ else
+ pw_error(editor, 1, 1);
+ }
+ editpid = -1;
+}
+
+void
+pw_prompt(void)
+{
+ int c;
+
+ (void)printf("re-edit the password file? [y]: ");
+ (void)fflush(stdout);
+ c = getchar();
+ if (c != EOF && c != '\n')
+ while (getchar() != '\n');
+ if (c == 'n')
+ pw_error(NULL, 0, 0);
+}
+
+void
+pw_error(char *name, int err, int eval)
+{
+ if (err)
+ warn("%s", name);
+
+ warnx("%s: unchanged", _PATH_MASTERPASSWD);
+ (void)unlink(tempname);
+ exit(eval);
+}
diff --git a/system_cmds/vipw.tproj/pw_util.h b/system_cmds/vipw.tproj/pw_util.h
new file mode 100644
index 0000000..6202815
--- /dev/null
+++ b/system_cmds/vipw.tproj/pw_util.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pw_util.h 8.2 (Berkeley) 4/1/94
+ */
+
+void pw_edit __P((int));
+void pw_error __P((char *, int, int));
+void pw_init __P((void));
+int pw_lock __P((void));
+int pw_mkdb __P((void));
+void pw_prompt __P((void));
+int pw_tmp __P((void));
diff --git a/system_cmds/vipw.tproj/vipw.8 b/system_cmds/vipw.tproj/vipw.8
new file mode 100644
index 0000000..dd8fa37
--- /dev/null
+++ b/system_cmds/vipw.tproj/vipw.8
@@ -0,0 +1,92 @@
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)vipw.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt VIPW 8
+.Os BSD 4
+.Sh NAME
+.Nm vipw
+.Nd edit the password file
+.Sh SYNOPSIS
+.Nm vipw
+.Sh DESCRIPTION
+.Nm Vipw
+edits the password file after setting the appropriate locks,
+and does any necessary processing after the password file is unlocked.
+If the password file is already locked for editing by another user,
+.Nm vipw
+will ask you
+to try again later. The default editor for
+.Nm vipw
+is
+.Xr vi 1 .
+.Pp
+.Nm Vipw
+performs a number of consistency checks on the password entries,
+and will not allow a password file with a
+.Dq mangled
+entry to be
+installed.
+If
+.Nm vipw
+rejects the new password file, the user is prompted to re-enter
+the edit session.
+.Pp
+Once the information has been verified,
+.Nm vipw
+uses
+.Xr pwd_mkdb 8
+to update the user database. This is run in the background, and,
+at very large sites could take several minutes. Until this update
+is completed, the password file is unavailable for other updates
+and the new information is not available to programs.
+.Sh ENVIRONMENT
+If the following environment variable exists it will be utilized by
+.Nm vipw :
+.Bl -tag -width EDITOR
+.It Ev EDITOR
+The editor specified by the string
+.Ev EDITOR
+will be invoked instead of the default editor
+.Xr vi 1 .
+.El
+.Sh SEE ALSO
+.Xr chpass 1 ,
+.Xr passwd 1 ,
+.Xr passwd 5 ,
+.Xr pwd_mkdb 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
diff --git a/system_cmds/vipw.tproj/vipw.c b/system_cmds/vipw.tproj/vipw.c
new file mode 100644
index 0000000..4bbad91
--- /dev/null
+++ b/system_cmds/vipw.tproj/vipw.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1987, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+__unused static char sccsid[] = "@(#)vipw.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pw_util.h"
+
+char *tempname;
+
+void copyfile __P((int, int));
+void usage __P((void));
+
+int
+main(int argc, char *argv[])
+{
+ int pfd, tfd;
+ struct stat begin, end;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch (ch) {
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ pw_init();
+ pfd = pw_lock();
+ tfd = pw_tmp();
+ copyfile(pfd, tfd);
+ (void)close(tfd);
+
+ for (;;) {
+ if (stat(tempname, &begin))
+ pw_error(tempname, 1, 1);
+ pw_edit(0);
+ if (stat(tempname, &end))
+ pw_error(tempname, 1, 1);
+ if (begin.st_mtime == end.st_mtime) {
+ warnx("no changes made");
+ pw_error((char *)NULL, 0, 0);
+ }
+ if (pw_mkdb())
+ break;
+ pw_prompt();
+ }
+ exit(0);
+}
+
+void
+copyfile(int from, int to)
+{
+ long nr, nw, off;
+ char buf[8*1024];
+
+ while ((nr = read(from, buf, sizeof(buf))) > 0)
+ for (off = 0; off < nr; nr -= nw, off += nw)
+ if ((nw = write(to, buf + off, nr)) < 0)
+ pw_error(tempname, 1, 1);
+ if (nr < 0)
+ pw_error(_PATH_MASTERPASSWD, 1, 1);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: vipw\n");
+ exit(1);
+}
diff --git a/system_cmds/vm_purgeable_stat.tproj/entitlements.plist b/system_cmds/vm_purgeable_stat.tproj/entitlements.plist
new file mode 100644
index 0000000..b21dbd8
--- /dev/null
+++ b/system_cmds/vm_purgeable_stat.tproj/entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>task_for_pid-allow</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.1 b/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.1
new file mode 100644
index 0000000..af01185
--- /dev/null
+++ b/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.1
@@ -0,0 +1,35 @@
+.\" Copyright (c) 2013, Apple Inc. All rights reserved.
+.\"
+.Dd Jan 16, 2013
+.Dt VM_PURGEABLE_STAT 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm vm_purgeable_stat
+.Nd Display purgeable memory information for processes on the system
+.Sh SYNOPSIS
+.Pp
+.Nm vm_purgeable_stat
+.Ar -s <interval>
+Show summary view for system-wide purgeable memory use. The <interval> specifies the refresh interval in secs.
+.Pp
+.Nm vm_purgeable_stat
+.Ar -p <pid>
+Show purgeable memory information for process <pid>
+.Pp
+.Nm vm_purgeable_stat
+.Ar -a
+Show purgeable memory information for all processes in the system
+.Sh DESCRIPTION
+The
+.Nm vm_purgeable_stat
+command prints information about the purgeable memory usage in the system. It shows the counts and sizes of purgeable objects in the system.
+.P
+.nf
+Following is an explanation of columns:
+Process-Name: Name of the process
+FIFO-PX : FIFO Purgeable objects at priority X. Each entry is of the form <count>/<size>
+OBSOLETE : Obselete Purgeable Objects. Each entry is of the form <count>/<size>
+LIFO-PX : LIFO Purgeable objects at priority X. Each entry is of the form <count>/<size>
+.fi
+.Sh SEE ALSO
+.Xr vm_stat 1
diff --git a/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c b/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c
new file mode 100644
index 0000000..bfef539
--- /dev/null
+++ b/system_cmds/vm_purgeable_stat.tproj/vm_purgeable_stat.c
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/mach_types.h>
+#include <mach/task.h>
+#include <libproc.h>
+#include <mach/vm_purgable.h>
+
+#define USAGE "Usage: vm_purgeable_stat [-a | -p <pid> | -s <interval>]\n"
+#define PRIV_ERR_MSG "The option specified needs root priveleges."
+#define PROC_NAME_LEN 256
+#define KB 1024
+#define PURGEABLE_PRIO_LEVELS VM_VOLATILE_GROUP_SHIFT
+
+static inline int purge_info_size_adjust(uint64_t size);
+static inline char purge_info_unit(uint64_t size);
+void print_header(int summary_view);
+int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count);
+int get_task_from_pid(int pid, task_t *task);
+void print_purge_info_task(task_t task, int pid);
+void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count);
+void print_purge_info_summary(int sleep_duration);
+
+static inline int purge_info_size_adjust(uint64_t size)
+{
+ while(size > KB)
+ size /= KB;
+ return (int)size;
+}
+
+static inline char purge_info_unit(uint64_t size)
+{
+ char sizes[] = {'B', 'K', 'M', 'G', 'T'};
+ int index = 0;
+
+ while(size > KB) {
+ index++;
+ size /= KB;
+ }
+ return sizes[index];
+}
+
+void print_header(int summary_view)
+{
+ if (!summary_view)
+ printf("%20s ", "Process-Name");
+
+ printf("%9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s %9s\n",
+ "FIFO-P0", "FIFO-P1", "FIFO-P2", "FIFO-P3",
+ "FIFO-P4", "FIFO-P5", "FIFO-P6", "FIFO-P7",
+ "OBSOLETE",
+ "LIFO-P0", "LIFO-P1", "LIFO-P2", "LIFO-P3",
+ "LIFO-P4", "LIFO-P5", "LIFO-P6", "LIFO-P7"
+ );
+}
+
+int get_task_from_pid(int pid, task_t *task)
+{
+ kern_return_t kr;
+ if (geteuid() != 0) {
+ fprintf(stderr, "%s\n", PRIV_ERR_MSG);
+ return -1;
+ }
+ kr = task_for_pid(mach_task_self(), pid, task);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "Failed to get task port for pid: %d\n", pid);
+ return -1;
+ }
+ return 0;
+}
+
+int get_system_tasks(task_array_t *tasks, mach_msg_type_number_t *count)
+{
+ processor_set_name_array_t psets;
+ mach_msg_type_number_t psetCount;
+ mach_port_t pset_priv;
+ kern_return_t ret;
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "%s\n", PRIV_ERR_MSG);
+ return -1;
+ }
+
+ ret = host_processor_sets(mach_host_self(), &psets, &psetCount);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "host_processor_sets() failed: %s\n", mach_error_string(ret));
+ return -1;
+ }
+ if (psetCount != 1) {
+ fprintf(stderr, "Assertion Failure: pset count greater than one (%d)\n", psetCount);
+ return -1;
+ }
+
+ /* convert the processor-set-name port to a privileged port */
+ ret = host_processor_set_priv(mach_host_self(), psets[0], &pset_priv);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "host_processor_set_priv() failed: %s\n", mach_error_string(ret));
+ return -1;
+ }
+ mach_port_deallocate(mach_task_self(), psets[0]);
+ vm_deallocate(mach_task_self(), (vm_address_t)psets, (vm_size_t)psetCount * sizeof(mach_port_t));
+
+ /* convert the processor-set-priv to a list of tasks for the processor set */
+ ret = processor_set_tasks(pset_priv, tasks, count);
+ if (ret != KERN_SUCCESS) {
+ fprintf(stderr, "processor_set_tasks() failed: %s\n", mach_error_string(ret));
+ return -1;
+ }
+ mach_port_deallocate(mach_task_self(), pset_priv);
+ return 0;
+}
+
+void print_purge_info_task(task_t task, int pid)
+{
+ task_purgable_info_t info;
+ kern_return_t kr;
+ int i;
+ char pname[PROC_NAME_LEN];
+
+ kr = task_purgable_info(task, &info);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "(pid: %d) task_purgable_info() failed: %s\n", pid, mach_error_string(kr));
+ return;
+ }
+ if (0 == proc_name(pid, pname, PROC_NAME_LEN))
+ strncpy(pname, "Unknown", 7);
+ pname[20] = 0;
+ printf("%20s ", pname);
+ for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
+ printf("%4u/%3d%c ", (unsigned)info.fifo_data[i].count, purge_info_size_adjust(info.fifo_data[i].size), purge_info_unit(info.fifo_data[i].size));
+ printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size));
+ for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
+ printf("%4u/%3d%c ", (unsigned)info.lifo_data[i].count, purge_info_size_adjust(info.lifo_data[i].size), purge_info_unit(info.lifo_data[i].size));
+ printf("\n");
+ return;
+}
+
+void print_purge_info_task_array(task_array_t tasks, mach_msg_type_number_t count)
+{
+ int i;
+ int pid;
+
+ for (i=0; i<count; i++) {
+ if (KERN_SUCCESS != pid_for_task(tasks[i], &pid))
+ continue;
+ print_purge_info_task(tasks[i], pid);
+ }
+ return;
+}
+
+void print_purge_info_summary(int sleep_duration)
+{
+ host_purgable_info_data_t info;
+ mach_msg_type_number_t count;
+ kern_return_t result;
+ int i;
+
+ while(1) {
+ count = HOST_VM_PURGABLE_COUNT;
+ result = host_info(mach_host_self(), HOST_VM_PURGABLE, (host_info_t)&info, &count);
+ if (result != KERN_SUCCESS)
+ break;
+ for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
+ printf("%4u/%3d%c ", (unsigned)info.fifo_data[i].count, purge_info_size_adjust(info.fifo_data[i].size), purge_info_unit(info.fifo_data[i].size));
+ printf("%4u/%3d%c ", (unsigned)info.obsolete_data.count, purge_info_size_adjust(info.obsolete_data.size), purge_info_unit(info.obsolete_data.size));
+ for (i=0; i<PURGEABLE_PRIO_LEVELS; i++)
+ printf("%4u/%3d%c ", (unsigned)info.lifo_data[i].count, purge_info_size_adjust(info.lifo_data[i].size), purge_info_unit(info.lifo_data[i].size));
+ printf("\n");
+ sleep(sleep_duration);
+ }
+ return;
+}
+
+int main(int argc, char *argv[])
+{
+
+ char ch;
+ int pid;
+ int sleep_duration;
+ task_array_t tasks;
+ task_t task;
+ mach_msg_type_number_t taskCount;
+ int noargs = 1;
+
+ while(1) {
+ ch = getopt(argc, argv, "ahp:s:");
+ if (ch == -1)
+ break;
+ noargs = 0;
+ switch(ch) {
+ case 'a':
+ if (get_system_tasks(&tasks, &taskCount) < 0)
+ break;
+ print_header(0);
+ print_purge_info_task_array(tasks, taskCount);
+ break;
+
+ case 'p':
+ pid = (int)strtol(optarg, NULL, 10);
+ if (pid < 0)
+ break;
+ if (get_task_from_pid(pid, &task) < 0)
+ break;
+ print_header(0);
+ print_purge_info_task(task, pid);
+ break;
+ case 's':
+ sleep_duration = (int)strtol(optarg, NULL, 10);
+ if (sleep_duration < 0)
+ break;
+ print_header(1);
+ print_purge_info_summary(sleep_duration);
+ break;
+ case '?':
+ case 'h':
+ default:
+ printf("%s", USAGE);
+ }
+ break;
+ }
+ if (noargs)
+ printf("%s", USAGE);
+ return 0;
+}
diff --git a/system_cmds/vm_stat.tproj/vm_stat.1 b/system_cmds/vm_stat.tproj/vm_stat.1
new file mode 100644
index 0000000..4697ca9
--- /dev/null
+++ b/system_cmds/vm_stat.tproj/vm_stat.1
@@ -0,0 +1,89 @@
+.\" Copyright (c) 1997, Apple Computer, Inc. All rights reserved.
+.\"
+.Dd August 13, 1997
+.Dt VM_STAT 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm vm_stat
+.Nd show Mach virtual memory statistics
+.Sh SYNOPSIS
+.Nm vm_stat
+.Oo
+.Op Fl c Ar count
+.Ar interval
+.Oc
+.Sh DESCRIPTION
+.Nm vm_stat
+displays Mach virtual memory statistics. If the optional
+.Ar interval
+is specified, then
+.Nm vm_stat
+will display the statistics every
+.Ar interval
+seconds. In this case, each line of output displays the change in
+each statistic (an
+.Ar interval
+count of 1 displays the values per second). However, the first line
+of output following each banner displays the system-wide totals for
+each statistic.
+If a
+.Ar count
+is provided, the command will terminate after
+.Ar count
+intervals.
+The following values are displayed:
+.Bl -tag -width indent
+.It Pages free
+the total number of free pages in the system.
+.It Pages active
+the total number of pages currently in use and pageable.
+.It Pages inactive
+the total number of pages on the inactive list.
+.It Pages speculative
+the total number of pages on the speculative list.
+.It Pages throttled
+the total number of pages on the throttled list (not wired but not pageable).
+.It Pages wired down
+the total number of pages wired down. That is, pages that cannot be
+paged out.
+.It Pages purgeable
+the total number of purgeable pages.
+.It Translation faults
+the number of times the "vm_fault" routine has been called.
+.It Pages copy-on-write
+the number of faults that caused a page to be
+copied (generally caused by copy-on-write faults).
+.It Pages zero filled
+the total number of pages that have been zero-filled on demand.
+.It Pages reactivated
+the total number of pages that have been moved from the inactive list
+to the active list (reactivated).
+.It Pages purged
+the total number of pages that have been purged.
+.It File-backed pages
+the total number of pages that are file-backed (non-swap)
+.It Anonymous pages
+the total number of pages that are anonymous
+.It Uncompressed pages
+the total number of pages (uncompressed) held within the compressor
+.It Pages used by VM compressor:
+the number of pages used to store compressed VM pages.
+.It Pages decompressed
+the total number of pages that have been decompressed by the VM compressor.
+.It Pages compressed
+the total number of pages that have been compressed by the VM compressor.
+.It Pageins
+the total number of requests for pages from a pager (such as the inode pager).
+.It Pageouts
+the total number of pages that have been paged out.
+.It Swapins
+the total number of compressed pages that have been swapped out to disk.
+.It Swapouts
+the total number of compressed pages that have been swapped back in from disk.
+.El
+.Pp
+If
+.Ar interval
+is not specified, then
+.Nm vm_stat
+displays all accumulated statistics along with the page size.
diff --git a/system_cmds/vm_stat.tproj/vm_stat.c b/system_cmds/vm_stat.tproj/vm_stat.c
new file mode 100644
index 0000000..7bedc31
--- /dev/null
+++ b/system_cmds/vm_stat.tproj/vm_stat.c
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 1999-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
+ * Reserved. This file contains Original Code and/or Modifications of
+ * Original Code as defined in and that are subject to the Apple Public
+ * Source License Version 1.0 (the 'License'). You may not use this file
+ * except in compliance with the License. Please obtain a copy of the
+ * License at http://www.apple.com/publicsource and read it before using
+ * this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License."
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * File: vm_stat.c
+ * Author: Avadis Tevanian, Jr.
+ *
+ * Copyright (C) 1986, Avadis Tevanian, Jr.
+ *
+ *
+ * Display Mach VM statistics.
+ *
+ ************************************************************************
+ * HISTORY
+ * 6-Jun-86 Avadis Tevanian, Jr. (avie) at Carnegie-Mellon University
+ * Use official Mach interface.
+ *
+ * 25-mar-99 A.Ramesh at Apple
+ * Ported to MacOS X
+ *
+ * 22-Jan-09 R.Branche at Apple
+ * Changed some fields to 64-bit to alleviate overflows
+ ************************************************************************
+ */
+
+#include <err.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#include <mach/mach.h>
+#include <mach/vm_page_size.h>
+
+vm_statistics64_data_t vm_stat, last;
+char *pgmname;
+mach_port_t myHost;
+
+void usage(void);
+void snapshot(void);
+void sspstat(char *str, uint64_t n);
+void banner(void);
+void print_stats(void);
+void get_stats(vm_statistics64_t stat);
+
+void pstat(uint64_t n, int width);
+
+int
+main(int argc, char *argv[])
+{
+ double delay = 0.0;
+ int count = 0;
+
+ pgmname = argv[0];
+
+ setlinebuf (stdout);
+
+ int c;
+ while ((c = getopt (argc, argv, "c:")) != -1) {
+ switch (c) {
+ case 'c':
+ count = (int)strtol(optarg, NULL, 10);
+ if (count < 1) {
+ warnx("count must be positive");
+ usage();
+ }
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ argc -= optind; argv += optind;
+
+ if (argc == 1) {
+ delay = strtod(argv[0], NULL);
+ if (delay < 0.0)
+ usage();
+ } else if (argc > 1) {
+ usage();
+ }
+
+ myHost = mach_host_self();
+
+ if (delay == 0.0) {
+ snapshot();
+ } else {
+ print_stats();
+ for (int i = 1; i < count || count == 0; i++ ){
+ usleep((int)(delay * USEC_PER_SEC));
+ print_stats();
+ }
+ }
+ exit(EXIT_SUCCESS);
+}
+
+void
+usage(void)
+{
+ fprintf(stderr, "usage: %s [[-c count] interval]\n", pgmname);
+ exit(EXIT_FAILURE);
+}
+
+void
+snapshot(void)
+{
+ get_stats(&vm_stat);
+ printf("Mach Virtual Memory Statistics: (page size of %llu bytes)\n", (mach_vm_size_t)vm_kernel_page_size);
+
+ sspstat("Pages free:", (uint64_t) (vm_stat.free_count - vm_stat.speculative_count));
+ sspstat("Pages active:", (uint64_t) (vm_stat.active_count));
+ sspstat("Pages inactive:", (uint64_t) (vm_stat.inactive_count));
+ sspstat("Pages speculative:", (uint64_t) (vm_stat.speculative_count));
+ sspstat("Pages throttled:", (uint64_t) (vm_stat.throttled_count));
+ sspstat("Pages wired down:", (uint64_t) (vm_stat.wire_count));
+ sspstat("Pages purgeable:", (uint64_t) (vm_stat.purgeable_count));
+ sspstat("\"Translation faults\":", (uint64_t) (vm_stat.faults));
+ sspstat("Pages copy-on-write:", (uint64_t) (vm_stat.cow_faults));
+ sspstat("Pages zero filled:", (uint64_t) (vm_stat.zero_fill_count));
+ sspstat("Pages reactivated:", (uint64_t) (vm_stat.reactivations));
+ sspstat("Pages purged:", (uint64_t) (vm_stat.purges));
+ sspstat("File-backed pages:", (uint64_t) (vm_stat.external_page_count));
+ sspstat("Anonymous pages:", (uint64_t) (vm_stat.internal_page_count));
+ sspstat("Pages stored in compressor:", (uint64_t) (vm_stat.total_uncompressed_pages_in_compressor));
+ sspstat("Pages occupied by compressor:", (uint64_t) (vm_stat.compressor_page_count));
+ sspstat("Decompressions:", (uint64_t) (vm_stat.decompressions));
+ sspstat("Compressions:", (uint64_t) (vm_stat.compressions));
+ sspstat("Pageins:", (uint64_t) (vm_stat.pageins));
+ sspstat("Pageouts:", (uint64_t) (vm_stat.pageouts));
+ sspstat("Swapins:", (uint64_t) (vm_stat.swapins));
+ sspstat("Swapouts:", (uint64_t) (vm_stat.swapouts));
+}
+
+void
+sspstat(char *str, uint64_t n)
+{
+ printf("%-30s %16llu.\n", str, n);
+}
+
+void
+banner(void)
+{
+ get_stats(&vm_stat);
+ printf("Mach Virtual Memory Statistics: ");
+ printf("(page size of %llu bytes)\n", (mach_vm_size_t)vm_kernel_page_size);
+ printf("%8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %11s %9s %8s %8s %8s %8s %8s %8s %8s %8s\n",
+ "free",
+ "active",
+ "specul",
+ "inactive",
+ "throttle",
+ "wired",
+ "prgable",
+ "faults",
+ "copy",
+ "0fill",
+ "reactive",
+ "purged",
+ "file-backed",
+ "anonymous",
+ "cmprssed",
+ "cmprssor",
+ "dcomprs",
+ "comprs",
+ "pageins",
+ "pageout",
+ "swapins",
+ "swapouts");
+ bzero(&last, sizeof(last));
+}
+
+void
+print_stats(void)
+{
+ static int count = 0;
+
+ if (count++ == 0)
+ banner();
+
+ if (count > 20)
+ count = 0;
+
+ get_stats(&vm_stat);
+ pstat((uint64_t) (vm_stat.free_count - vm_stat.speculative_count), 8);
+ pstat((uint64_t) (vm_stat.active_count), 8);
+ pstat((uint64_t) (vm_stat.speculative_count), 8);
+ pstat((uint64_t) (vm_stat.inactive_count), 8);
+ pstat((uint64_t) (vm_stat.throttled_count), 8);
+ pstat((uint64_t) (vm_stat.wire_count), 8);
+ pstat((uint64_t) (vm_stat.purgeable_count), 8);
+ pstat((uint64_t) (vm_stat.faults - last.faults), 8);
+ pstat((uint64_t) (vm_stat.cow_faults - last.cow_faults), 8);
+ pstat((uint64_t) (vm_stat.zero_fill_count - last.zero_fill_count), 8);
+ pstat((uint64_t) (vm_stat.reactivations - last.reactivations), 8);
+ pstat((uint64_t) (vm_stat.purges - last.purges), 8);
+ pstat((uint64_t) (vm_stat.external_page_count), 11);
+ pstat((uint64_t) (vm_stat.internal_page_count), 9);
+ pstat((uint64_t) (vm_stat.total_uncompressed_pages_in_compressor), 8);
+ pstat((uint64_t) (vm_stat.compressor_page_count), 8);
+ pstat((uint64_t) (vm_stat.decompressions - last.decompressions), 8);
+ pstat((uint64_t) (vm_stat.compressions - last.compressions), 8);
+ pstat((uint64_t) (vm_stat.pageins - last.pageins), 8);
+ pstat((uint64_t) (vm_stat.pageouts - last.pageouts), 8);
+ pstat((uint64_t) (vm_stat.swapins - last.swapins), 8);
+ pstat((uint64_t) (vm_stat.swapouts - last.swapouts), 8);
+ putchar('\n');
+ last = vm_stat;
+}
+
+void
+pstat(uint64_t n, int width)
+{
+ char buf[80];
+ if (width >= sizeof(buf)) {
+ width = sizeof(buf) -1;
+ }
+
+ /* Now that we have the speculative field, there is really not enough
+ space, but we were actually overflowing three or four fields before
+ anyway. So any field that overflows we drop some insignifigant
+ digets and slap on the appropriate suffix
+ */
+ int w = snprintf(buf, sizeof(buf), "%*llu", width, n);
+ if (w > width) {
+ w = snprintf(buf, sizeof(buf), "%*lluK", width -1, n / 1000);
+ if (w > width) {
+ w = snprintf(buf, sizeof(buf), "%*lluM", width -1, n / 1000000);
+ if (w > width) {
+ w = snprintf(buf, sizeof(buf), "%*lluG", width -1, n / 1000000000);
+ }
+ }
+ }
+ fputs(buf, stdout);
+ putchar(' ');
+}
+
+void
+get_stats(vm_statistics64_t stat)
+{
+ unsigned int count = HOST_VM_INFO64_COUNT;
+ kern_return_t ret;
+ if ((ret = host_statistics64(myHost, HOST_VM_INFO64, (host_info64_t)stat, &count) != KERN_SUCCESS)) {
+ fprintf(stderr, "%s: failed to get statistics. error %d\n", pgmname, ret);
+ exit(EXIT_FAILURE);
+ }
+}
diff --git a/system_cmds/wait4path/wait4path.1 b/system_cmds/wait4path/wait4path.1
new file mode 100644
index 0000000..7635261
--- /dev/null
+++ b/system_cmds/wait4path/wait4path.1
@@ -0,0 +1,37 @@
+."Copyright (c) 2015 Apple Inc. All rights reserved.
+."
+."@APPLE_LICENSE_HEADER_START@
+."
+."This file contains Original Code and/or Modifications of Original Code
+."as defined in and that are subject to the Apple Public Source License
+."Version 2.0 (the 'License'). You may not use this file except in
+."compliance with the License. Please obtain a copy of the License at
+."http://www.opensource.apple.com/apsl/ and read it before using this
+."file.
+."
+."The Original Code and all software distributed under the License are
+."distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+."EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+."INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+."FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+."Please see the License for the specific language governing rights and
+."limitations under the License.
+."
+."@APPLE_LICENSE_HEADER_END@
+."
+.Dd 14 December, 2013
+.Dt WAIT4PATH 1
+.Os Darwin
+.Sh NAME
+.Nm wait4path
+.Nd wait for given path to show up in the namespace
+.Sh SYNOPSIS
+.Nm
+.Ao Ar path Ac
+.Sh DESCRIPTION
+The
+.Nm
+program simply checks to see if the given path exists, and if so, it exits.
+Otherwise, it sleeps until the mount table is updated and checks again. The
+program will loop indefinitely until the path shows up in the file system
+namespace.
diff --git a/system_cmds/wait4path/wait4path.c b/system_cmds/wait4path/wait4path.c
new file mode 100644
index 0000000..997f433
--- /dev/null
+++ b/system_cmds/wait4path/wait4path.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/event.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+int
+main(int argc, char *argv[])
+{
+ int kq = kqueue();
+ struct kevent kev;
+ struct stat sb;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s <object on mount point>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ EV_SET(&kev, 0, EVFILT_FS, EV_ADD, 0, 0, 0);
+
+ if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) {
+ fprintf(stderr, "adding EVFILT_FS to kqueue failed: %s\n",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (stat(argv[1], &sb) == 0) {
+ exit(EXIT_SUCCESS);
+ }
+
+ for (;;) {
+ kevent(kq, NULL, 0, &kev, 1, NULL);
+ if (stat(argv[1], &sb) == 0) {
+ break;
+ }
+ }
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/system_cmds/wait4path/wait4path.version b/system_cmds/wait4path/wait4path.version
new file mode 100644
index 0000000..b01adfa
--- /dev/null
+++ b/system_cmds/wait4path/wait4path.version
@@ -0,0 +1,5 @@
+DARWIN_BUNDLE_IDENTIFIER="com.apple.system_cmds.wait4path"
+DARWIN_DISPLAY_NAME="Darwin Filesystem Path Waiter"
+DARWIN_DISPLAY_VERSION="1.0.0"
+DARWIN_INCREMENTAL_VERSION="$CURRENT_PROJECT_VERSION"
+DARWIN_COPYRIGHT="Copyright 2015 Apple Inc. All rights reserved."
diff --git a/system_cmds/wordexp-helper.tproj/wordexp-helper.c b/system_cmds/wordexp-helper.tproj/wordexp-helper.c
new file mode 100644
index 0000000..7ed025a
--- /dev/null
+++ b/system_cmds/wordexp-helper.tproj/wordexp-helper.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2013-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+main(int argc, char **argv)
+{
+ int i;
+ int total = 0;
+ char **a;
+
+ argc--;
+ argv++;
+ for(a = argv, i = argc; i-- > 0; a++) total += strlen(*a);
+ printf("%08x%08x", argc, total);
+ for(a = argv, i = argc; i-- > 0; a++) {
+ if(fwrite(*a, strlen(*a) + 1, 1, stdout) != 1) exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+}
diff --git a/system_cmds/xcconfigs/base.xcconfig b/system_cmds/xcconfigs/base.xcconfig
new file mode 100644
index 0000000..c01bea8
--- /dev/null
+++ b/system_cmds/xcconfigs/base.xcconfig
@@ -0,0 +1,88 @@
+#include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig"
+#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/PlatformSupport.xcconfig"
+
+XPC_BUILD_FILES_DIR = $(PROJECT_DIR)/xcfiles
+XPC_BUILD_XCSCRIPTS_DIR = $(PROJECT_DIR)/xcscripts
+XPC_BUILD_XCCONFIG_DIR = $(PROJECT_DIR)/xcconfig
+
+XPC_BUILD_HEADER_SEARCH_PATHS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(PROJECT_DIR)/src $(PROJECT_DIR)/interface $(PROJECT_DIR)/launch $(PROJECT_DIR)/support $(PROJECT_DIR)/development $(PROJECT_DIR)
+
+XPC_ALL_THE_DEBUGS2 =
+XPC_ALL_THE_DEBUGS2_yes = -O0 -g -fno-inline -fno-limit-debug-info
+
+XPC_COMPATIBILITY_DEFINES_currentmajor = -DHAVE_KDEBUG_TRACE=1 -DCONFIG_EMULATE_XNU_INITPROC_SELECTION=0 -DHAVE_GALARCH_AVAILABILITY=1
+XPC_COMPATIBILITY_DEFINES_lastmajor = -DHAVE_KDEBUG_TRACE=0 -DCONFIG_EMULATE_XNU_INITPROC_SELECTION=1 -DHAVE_GALARCH_AVAILABILITY=0
+XPC_BUILD_HOST = currentmajor
+
+XPC_BUILD_EXPORT_DEFAULTS = -DXPC_PROJECT_EXPORT=XPC_EXPORT -DXPC_DEBUGEXPORT=XPC_NOEXPORT -DXPC_TESTEXPORT=XPC_NOEXPORT
+XPC_BUILD_OTHER_CFLAGS = $(XPC_ALL_THE_DEBUGS2_$(XPC_ALL_THE_DEBUGS)) $(XPC_COMPATIBILITY_DEFINES_$(XPC_BUILD_HOST)) -D__XPC_PROJECT_BUILD__=1
+
+XPC_CRASHREPORTCLIENT_LDFLAGS = -lCrashReporterClient
+
+XPC_NOSTRIP = no
+XPC_NOSTRIP2_no = YES
+XPC_NOSTRIP2_yes = NO
+
+// Building.
+ARCHS = $(ARCHS_STANDARD)
+ONLY_ACTIVE_ARCH = NO
+GCC_C_LANGUAGE_STANDARD = gnu99
+GCC_WARN_ABOUT_RETURN_TYPE = YES
+GCC_WARN_UNUSED_FUNCTION = YES
+GCC_WARN_UNUSED_VARIABLE = YES
+GCC_TREAT_WARNINGS_AS_ERRORS = YES
+GCC_SYMBOLS_PRIVATE_EXTERN = YES
+GCC_ENABLE_OBJC_GC = unsupported
+GCC_ENABLE_BUILTIN_FUNCTIONS = YES
+GCC_WARN_UNINITIALIZED_AUTOS = YES
+GCC_WARN_64_TO_32_BIT_CONVERSION = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES
+GCC_WARN_UNINITIALIZED_AUTOS = YES
+GCC_WARN_UNUSED_VARIABLE = YES
+
+CLANG_WARN_CONSTANT_CONVERSION = YES
+CLANG_WARN_INT_CONVERSION = YES
+CLANG_WARN_EMPTY_BODY = YES
+CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
+DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
+
+OTHER_CFLAGS = $(XPC_BUILD_OTHER_CFLAGS)
+
+// We pretty much want to avoid anything having to do with Xcode's default
+// header search behavior.
+ALWAYS_SEARCH_USER_PATHS = NO
+USE_HEADERMAP = NO
+HEADER_SEARCH_PATHS = $(XPC_BUILD_HEADER_SEARCH_PATHS)
+
+// Deployment and linking.
+// By default, clang will link any binary using Objective-C against Foundation.
+// We need to opt out of this to avoid a layering inversion.
+//
+// <rdar://problem/11075809>
+CLANG_LINK_OBJC_RUNTIME = NO
+CLANG_MODULES_AUTOLINK = NO
+
+DYLIB_CURRENT_VERSION = $(RC_ProjectSourceVersion)
+DYLIB_COMPATIBILITY_VERSION = 1
+DEPLOYMENT_LOCATION = YES
+
+// Preprocessing the Info.plist sends it through the C preprocessor. You cannot
+// use both of these options together, since they emit different files to
+// different places. I'm putting them here mostly just so I don't forget what
+// they're called in case we do want to start using them in the future.
+INFOPLIST_PREPROCESS = NO
+INFOPLIST_EXPAND_BUILD_SETTINGS = NO
+
+// SEPARATE_STRIP will tell the linker to not strip the emitted binary. Instead,
+// the strip will happen as a separate invocation of the strip(1) tool, leaving
+// the binaries in our OBJROOT untouched but stripping the ones that go into the
+// DSTROOT and SYMROOT. INSTALLED_PRODUCT_ASIDES makes it so that the stuff in
+// the SYMROOT is not just symlinked into the DSTROOT, which lets us preserve
+// the symbols for the stuff in there.
+STRIP_INSTALLED_PRODUCT = $(XPC_NOSTRIP2_$(XPC_NOSTRIP))
+
+// STRIP_INSTALLED_PRODUCT does not appear to be respected on a per-variant
+// basis, so this does nothing.
+STRIP_INSTALLED_PRODUCT_debug = NO
+INSTALLED_PRODUCT_ASIDES = YES
+SEPARATE_STRIP = YES
diff --git a/system_cmds/xcconfigs/development.xcconfig b/system_cmds/xcconfigs/development.xcconfig
new file mode 100644
index 0000000..16edd7b
--- /dev/null
+++ b/system_cmds/xcconfigs/development.xcconfig
@@ -0,0 +1,29 @@
+// This is the configuration file for building XPC's executables' development
+// support bundle, which houses code that we want to be able to use internally
+// in certain tools, but we don't want to ship externally.
+#include "executable.xcconfig"
+
+SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator
+VALID_ARCHS[sdk=macosx*] = i386 x86_64
+
+XPC_SUPPORT_INSTALL_PATH = /usr/local/lib/xpc
+
+OTHER_CFLAGS = $(XPC_EXECUTABLE_OTHER_CFLAGS) -D__XPC_BUILDING_XPCDEVELOPMENT__=1
+HEADER_SEARCH_PATHS = $(XPC_BUILD_HEADER_SEARCH_PATHS) $(PROJECT_DIR)/development
+
+// This is a bundle, which is not stamped by our version-stamping script, so we
+// expand the build variables in the Info.plist.
+INFOPLIST_EXPAND_BUILD_SETTINGS = YES
+INFOPLIST_FILE = development/Info.plist
+
+GCC_ENABLE_OBJC_GC = unsupported
+// <rdar://problem/16129315>
+GCC_ENABLE_OBJC_GC[sdk=macosx*] = supported
+
+// Deployment and linking.
+MACH_O_TYPE = mh_bundle
+PRODUCT_NAME = development
+WRAPPER_EXTENSION = bundle
+INSTALL_PATH_ACTUAL = $(XPC_SUPPORT_INSTALL_PATH)
+OTHER_LDFLAGS = $(XPC_EXECUTABLE_OTHER_LDFLAGS)
+STRIP_STYLE = non-global
diff --git a/system_cmds/xcconfigs/executable.xcconfig b/system_cmds/xcconfigs/executable.xcconfig
new file mode 100644
index 0000000..57a600a
--- /dev/null
+++ b/system_cmds/xcconfigs/executable.xcconfig
@@ -0,0 +1,45 @@
+// This configuration file contains common build settings for all of libxpc's
+// executable targets.
+#include "base.xcconfig"
+
+XPC_EXECUTABLE_OTHER_CFLAGS = $(XPC_BUILD_OTHER_CFLAGS) $(XPC_BUILD_EXPORT_DEFAULTS) -DXPC_BUILD_TARGET_EXECUTABLE=1
+XPC_EXECUTABLE_OTHER_LDFLAGS = $(XPC_CRASHREPORTCLIENT_LDFLAGS)
+XPC_EXECUTABLE_WORKAROUND_14483011 = -lSystem -lobjc
+
+// Building.
+VALID_ARCHS[sdk=macosx*] = x86_64
+GCC_ENABLE_OBJC_EXCEPTIONS = YES
+INFOPLIST_FILE =
+SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator
+OTHER_CFLAGS = $(XPC_EXECUTABLE_OTHER_CFLAGS)
+
+// Work around asinine default tools behavior of adding entitlements to every
+// generated binary.
+//
+// <rdar://problem/15995721>
+// <rdar://problem/16477165>
+WANTS_GET_TASK_ALLOW = NO
+
+// Deployment linking.
+MACH_O_TYPE = mh_execute
+PRODUCT_NAME = xpc_executables
+EXECUTABLE_PREFIX =
+FRAMEWORK_SEARCH_PATHS = $(SDKROOT)/System/Library/PrivateFrameworks $(inherited)
+STRIP_STYLE = all
+XPC_EXECUTABLE_OTHER_LDFLAGS = $(XPC_EXECUTABLE_WORKAROUND_14483011) $(XPC_CRASHREPORTCLIENT_LDFLAGS)
+CREATE_INFOPLIST_SECTION_IN_BINARY = YES
+
+// Output our launchd plist as binary on iOS.
+APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*] = YES
+PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*] = binary
+
+// For building variants
+DARWIN_VARIANT_LOWER_RELEASE = release
+DARWIN_VARIANT_SUFFIX_RELEASE =
+DARWIN_VARIANT_LOWER_DEVELOPMENT = development
+DARWIN_VARIANT_SUFFIX_DEVELOPMENT = .development
+DARWIN_VARIANT_LOWER_DEBUG = debug
+DARWIN_VARIANT_SUFFIX_DEBUG = .debug
+
+DARWIN_VARIANT_LOWER = $(DARWIN_VARIANT_LOWER_$(DARWIN_VARIANT))
+DARWIN_VARIANT_SUFFIX = $(DARWIN_VARIANT_SUFFIX_$(DARWIN_VARIANT))
diff --git a/system_cmds/xcconfigs/wait4path.xcconfig b/system_cmds/xcconfigs/wait4path.xcconfig
new file mode 100644
index 0000000..81909c4
--- /dev/null
+++ b/system_cmds/xcconfigs/wait4path.xcconfig
@@ -0,0 +1,16 @@
+#include "executable.xcconfig"
+
+SUPPORTED_PLATFORMS = macosx
+
+DARWIN_VARIANT = RELEASE
+#include "../wait4path/wait4path.version"
+
+HEADER_SEARCH_PATHS = $(XPC_BUILD_HEADER_SEARCH_PATHS) $(PROJECT_DIR)/wait4path
+OTHER_CFLAGS = $(XPC_EXECUTABLE_OTHER_CFLAGS) $(XPC_BUILD_EXPORT_DEFAULTS) -D__XPC_BUILDING_WAIT4PATH__=1
+OTHER_LDFLAGS = $(XPC_EXECUTABLE_OTHER_LDFLAGS)
+
+# wait4path doesn't actually need -lCrashReporterClient
+XPC_CRASHREPORTCLIENT_LDFLAGS = ""
+
+INSTALL_PATH = /bin
+PRODUCT_NAME = wait4path
diff --git a/system_cmds/xscripts/darwinversion.sh b/system_cmds/xscripts/darwinversion.sh
new file mode 100644
index 0000000..965bc35
--- /dev/null
+++ b/system_cmds/xscripts/darwinversion.sh
@@ -0,0 +1,228 @@
+#!/bin/sh
+
+# This script is intended to generate version information for single-file
+# products (i.e. things that don't ship in bundles). It takes an input file
+# with the suffix ".version" that defines:
+#
+# DARWIN_BUNDLE_IDENTIFIER
+# The CFBundleIdentifier for the product.
+# DARWIN_DISPLAY_NAME
+# The "marketing" name of the product ("Darwin System Bootstrapper" as opposed
+# to "launchd" or "Darwin Kernel" as opposed to "xnu").
+# DARWIN_DISPLAY_VERSION
+# The major release version (think "7.0" for iOS 7, "10.9" for Mavericks,
+# etc.).
+# DARWIN_INCREMENTAL_VERSION
+# The incremental version (think 12A132, svn revision, project tag, etc.).
+# DARWIN_COPYRIGHT
+# The copyright string.
+#
+# It produces a header (darwin_version.h) that declares:
+#
+# __darwin_builder_version
+# The integer representation of the version of OS X which built the project
+# (think 1090, 1091, etc.).
+# __darwin_builder_build
+# The integer representation of the build of OS X which built the project,
+# represented in hex (think 0x12A132).
+# __darwin_build_inc_version
+# A string representation of the given DARWIN_INCREMENTAL_VERSION.
+# __darwin_version_string
+# A composed version string which can serve as useful for identifying the
+# version, variant and origin of a given build. It is formatted as:
+#
+# $DARWIN_DISPLAY_NAME Version $DARWIN_DISPLAY_VERSION `date`; `whoami`:<objects>
+#
+# <objects> is a symbolic link in the OBJROOT pointing to the subdirectory
+# containing the objects for the target being built. The link's name is
+# formatted as:
+#
+# ${BASE_PRODUCT_NAME}/${DARWIN_VARIANT}_${UPPER_CASE_CURRENT_ARCH}
+#
+# The BASE_PRODUCT_NAME is the first part of the target's PRODUCT_NAME, prior
+# to a '.' character (so the base product name of "launchd.development" is
+# simply "launchd").
+#
+# This link points to the appropriate location in the build root. If the SDK
+# being built for is the Simulator, the variant is formatted as:
+#
+# ${DARWIN_VARIANT}_SIMULATOR_${UPPER_CASE_CURRENT_ARCH}
+#
+# It produces an XML Info.plist from this information and embeds it in the
+# __TEXT,__info_plist section of the resulting binary.
+
+. ${INPUT_FILE_PATH}
+
+baseproductname=${PRODUCT_NAME/.*/}
+builder_version=`sw_vers -productVersion`
+builder_build=`sw_vers -buildVersion`
+brewedondate=`date`
+brewedby=`whoami`
+
+if [ $SUDO_USER ]; then
+ brewedby="$SUDO_USER"
+fi
+
+release="Unknown"
+if [[ "$DARWIN_VARIANT" != "RELEASE" && -n "$RC_RELEASE" ]]; then
+ release="$RC_RELEASE"
+fi
+
+# Distill the version down to its base OS. The builders could be running 10.7.2,
+# for example, but the availability macros on OS X only handle major version
+# availability.
+builder_version_int=${builder_version/.}
+builder_version_int=${builder_version_int/.*}
+builder_version_int="${builder_version_int}0"
+
+# Builders don't typically run on later SU trains. They'll usually move to the
+# next major release.
+if [[ "$builder_build" =~ [g-zG-Z] ]]; then
+ builder_build="1A1"
+fi
+
+destdir="${DERIVED_SOURCES_DIR}/${CURRENT_ARCH}"
+mkdir -p "$destdir"
+
+thehfile="$destdir/darwin_version.h"
+thecfile="$destdir/darwin_version.c"
+
+# Hack to emulate how xnu's version works. It has the nice feature of printing
+# the OBJROOT of the current xnu, which is different based on build variant and
+# architecture. But in our case, the OBJROOT is buried a few levels deep, so we
+# create a symlink in the OBJROOT to point to that, or else we'd have to embed
+# a much longer path in the version.
+mkdir -p "${OBJROOT}/$baseproductname"
+cd "${OBJROOT}/$baseproductname"
+
+rootwithslash="${OBJROOT}/"
+objpath=`eval echo -n \\$OBJECT_FILE_DIR_\$CURRENT_VARIANT`
+
+capsarch=`echo $CURRENT_ARCH | tr "[:lower:]" "[:upper:]"`
+# Xcode does not provide an OBJECT_FILE_DIR_$CURRENT_VARIANT_$CURRENT_ARCH, so
+# we have to interpolate the last part of the path.
+objpath=$objpath/$CURRENT_ARCH
+subpath=${objpath#${rootwithslash}}
+
+if [[ "${PLATFORM_NAME}" =~ "simulator" ]]; then
+ linkname="${DARWIN_VARIANT}_SIMULATOR_${capsarch}"
+else
+ linkname="${DARWIN_VARIANT}_${capsarch}"
+fi
+
+objects=`basename ${OBJROOT}`
+if [[ "$objects" = "Objects" ]]; then
+ # Newer XBSs put the OBJROOT in an "Objects" subdirectory under the build
+ # root.
+ oldwd=`pwd`
+ cd "${OBJROOT}"
+ cd ..
+
+ objects=`dirname ${OBJROOT}`
+ objects=`basename $objects`
+ objects="${objects/_install/}"
+
+ ln -fs "Objects" "$objects"
+
+ cd "$oldwd"
+fi
+objects="$objects/$baseproductname/$linkname"
+
+ln -s ../${subpath} $linkname
+version_string="$DARWIN_DISPLAY_NAME Version $DARWIN_DISPLAY_VERSION: $brewedondate; $brewedby:$objects"
+
+# Generate the symbol root.
+binarywithsyms="$SYMROOT/$PRODUCT_NAME"
+if [[ $SYMROOT =~ ^/BinaryCache/ ]]; then
+ # XBS tosses symbols and roots into /BinaryCache on the builder, so sniff
+ # that out and generate the appropriate path. Otherwise, just use the given
+ # local SYMROOT.
+ symrootsubpath=${SYMROOT#"/BinaryCache/"}
+ binarywithsyms="~rc/Software/$release/BuildRecords/$symrootsubpath/$PRODUCT_NAME"
+fi
+
+echo "*** Stamping project build:"
+echo "*** Release: $release"
+echo "*** Builder Version: $builder_version"
+echo "*** Builder Build: $builder_build"
+echo "*** Project Version: $CURRENT_PROJECT_VERSION"
+echo "*** Version String: $version_string"
+echo "*** Object Root: $objects"
+echo "*** Debugging Binary: $binarywithsyms"
+
+# Generate Info.plist
+infoplist="$destdir"/Info.plist
+/usr/libexec/PlistBuddy -c "Add :CFBundleIdentifier string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier $DARWIN_BUNDLE_IDENTIFIER" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :CFBundleName string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :CFBundleName $PRODUCT_NAME" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :CFBundleDisplayName string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName $DARWIN_DISPLAY_NAME" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :CFBundleExecutable string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :CFBundleExecutable $EXECUTABLE_NAME" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :CFBundleInfoDictionaryVersion string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :CFBundleInfoDictionaryVersion 6.0" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString $DARWIN_DISPLAY_VERSION" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :CFBundleVersion string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :CFBundleVersion $DARWIN_INCREMENTAL_VERSION" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :NSHumanReadableCopyright string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :NSHumanReadableCopyright $DARWIN_COPYRIGHT" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DarwinVariant string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DarwinVariant $DARWIN_VARIANT" -c "Save" $infoplist > /dev/null
+# codesign can't deal with the Info.plist for each slice having different
+# content, so don't encode architecture-specific information for now.
+#
+# <rdar://problem/15459303>
+#/usr/libexec/PlistBuddy -c "Add :DarwinArchitecture string" -c "Save" $infoplist > /dev/null
+#/usr/libexec/PlistBuddy -c "Set :DarwinArchitecture $CURRENT_ARCH" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DarwinBuilderVersion string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DarwinBuilderVersion $builder_version" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DarwinBuilderBuild string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DarwinBuilderBuild $builder_build" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DTSDKName string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DTSDKName $SDK_NAME" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DTSDKBuild string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DTSDKBuild $PLATFORM_PRODUCT_BUILD_VERSION" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DTXcodeBuild string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DTXcodeBuild $XCODE_PRODUCT_BUILD_VERSION" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DTCompiler string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DTCompiler $DEFAULT_COMPILER" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DTPlatformName string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DTPlatformName $PLATFORM_NAME" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DTPlatformVersion string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DTPlatformVersion $IPHONEOS_DEPLOYMENT_TARGET" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Add :DTXcode string" -c "Save" $infoplist > /dev/null
+/usr/libexec/PlistBuddy -c "Set :DTXcode $XCODE_VERSION_ACTUAL" -c "Save" $infoplist > /dev/null
+infoplistcontents=`cat $infoplist`
+
+rm -f "$thehfile"
+echo "#ifndef __DARWIN_VERSION_H__" >> "$thehfile"
+echo "#define __DARWIN_VERSION_H__" >> "$thehfile"
+echo "const unsigned long __darwin_builder_version;" >> "$thehfile"
+echo "const unsigned long __darwin_builder_build;" >> "$thehfile"
+echo "const char *__darwin_build_inc_version;" >> "$thehfile"
+echo "const char *__darwin_version_string;" >> "$thehfile"
+echo "const char *__darwin_variant;" >> "$thehfile"
+echo "const char *__darwin_debug_binary;" >> "$thehfile"
+echo "#endif // __DARWIN_VERSION_H__" >> "$thehfile"
+echo "" >> "$thehfile"
+
+rm -f "$thecfile"
+echo "__attribute__((__used__)) const unsigned long __darwin_builder_version = $builder_version_int;" >> "$thecfile"
+echo "__attribute__((__used__)) const unsigned long __darwin_builder_build = 0x$builder_build;" >> "$thecfile"
+echo "__attribute__((__used__)) const char *__darwin_build_inc_version = \"$CURRENT_PROJECT_VERSION\";" >> "$thecfile"
+echo "__attribute__((__used__)) const char *__darwin_version_string = \"$version_string\";" >> "$thecfile"
+echo "__attribute__((__used__)) const char *__darwin_variant = \"$DARWIN_VARIANT\";" >> "$thecfile"
+echo "__attribute__((__used__)) const char *__darwin_version_string_heywhat = \"@(#)VERSION:$version_string\";" >> "$thecfile"
+echo "__attribute__((__used__)) const char *__darwin_debug_binary = \"$binarywithsyms\";" >> "$thecfile"
+
+# Embed the Info.plist in the __TEXT,__info_plist section.
+echo "__attribute__((__used__))" >> "$thecfile"
+
+echo "__attribute__((__section__(\"__TEXT,__info_plist\")))" >> "$thecfile"
+echo -n "static const char __darwin_info_plist[] = \"" >> "$thecfile"
+echo -n "$infoplistcontents" | sed -e 's/\"/\\"/g' | tr -d '\n' >> "$thecfile"
+echo "\";" >> "$thecfile"
+
+echo "" >> "$thecfile"
diff --git a/system_cmds/zdump.tproj/zdump.8 b/system_cmds/zdump.tproj/zdump.8
new file mode 100644
index 0000000..065a1d6
--- /dev/null
+++ b/system_cmds/zdump.tproj/zdump.8
@@ -0,0 +1,49 @@
+.\"
+.\" @(#)zdump.8 7.3
+.\" $FreeBSD: src/usr.sbin/zic/zdump.8,v 1.10 2004/06/20 21:41:11 stefanf Exp $
+.\"
+.Dd June 20, 2004
+.Dt ZDUMP 8
+.Os
+.Sh NAME
+.Nm zdump
+.Nd timezone dumper
+.Sh SYNOPSIS
+.Nm
+.Op Fl -version
+.Op Fl v
+.Op Fl c Ar cutoffyear
+.Op Ar zonename ...
+.Sh DESCRIPTION
+The
+.Nm
+utility prints the current time in each
+.Ar zonename
+named on the command line.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl -version
+Output version information and exit.
+.It Fl v
+For each
+.Ar zonename
+on the command line,
+print the time at the lowest possible time value,
+the time one day after the lowest possible time value,
+the times both one second before and exactly at
+each detected time discontinuity,
+the time at one day less than the highest possible time value,
+and the time at the highest possible time value,
+Each line ends with
+.Em isdst=1
+if the given time is Daylight Saving Time or
+.Em isdst=0
+otherwise.
+.It Fl c Ar cutoffyear
+Cut off the verbose output near the start of the given year.
+.El
+.Sh "SEE ALSO"
+.Xr ctime 3 ,
+.Xr tzfile 5 ,
+.Xr zic 8
diff --git a/system_cmds/zdump.tproj/zdump.c b/system_cmds/zdump.tproj/zdump.c
new file mode 100644
index 0000000..7068cdf
--- /dev/null
+++ b/system_cmds/zdump.tproj/zdump.c
@@ -0,0 +1,390 @@
+static const char elsieid[] = "@(#)zdump.c 7.31";
+
+#ifndef lint
+#include <sys/cdefs.h>
+__unused static const char rcsid[] =
+ "$FreeBSD: src/usr.sbin/zic/zdump.c,v 1.10 2008/02/19 07:09:19 ru Exp $";
+#endif /* not lint */
+
+/*
+** This code has been made independent of the rest of the time
+** conversion package to increase confidence in the verification it provides.
+** You can use this code to help in verifying other implementations.
+*/
+
+#include <err.h>
+#include <stdio.h> /* for stdout, stderr */
+#include <stdlib.h> /* for exit, malloc, atoi */
+#include <string.h> /* for strcpy */
+#include <sys/types.h> /* for time_t */
+#include <time.h> /* for struct tm */
+#include <unistd.h>
+#include <limits.h>
+
+#ifndef MAX_STRING_LENGTH
+#define MAX_STRING_LENGTH 1024
+#endif /* !defined MAX_STRING_LENGTH */
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE 0
+#endif /* !defined FALSE */
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif /* !defined EXIT_SUCCESS */
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif /* !defined EXIT_FAILURE */
+
+#ifndef SECSPERMIN
+#define SECSPERMIN 60
+#endif /* !defined SECSPERMIN */
+
+#ifndef MINSPERHOUR
+#define MINSPERHOUR 60
+#endif /* !defined MINSPERHOUR */
+
+#ifndef SECSPERHOUR
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#endif /* !defined SECSPERHOUR */
+
+#ifndef HOURSPERDAY
+#define HOURSPERDAY 24
+#endif /* !defined HOURSPERDAY */
+
+#ifndef EPOCH_YEAR
+#define EPOCH_YEAR 1970
+#endif /* !defined EPOCH_YEAR */
+
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif /* !defined TM_YEAR_BASE */
+
+#ifndef DAYSPERNYEAR
+#define DAYSPERNYEAR 365
+#endif /* !defined DAYSPERNYEAR */
+
+#ifndef isleap
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+#endif /* !defined isleap */
+
+#if HAVE_GETTEXT - 0
+#include "locale.h" /* for setlocale */
+#include "libintl.h"
+#endif /* HAVE_GETTEXT - 0 */
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#endif /* defined lint */
+#ifndef lint
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x) ((x) = 0)
+#endif /* defined GNUC_or_lint */
+#ifndef GNUC_or_lint
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** For the benefit of GNU folk...
+** `_(MSGID)' uses the current locale's message library string for MSGID.
+** The default is to use gettext if available, and use MSGID otherwise.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT - 0
+#define _(msgid) gettext(msgid)
+#else /* !(HAVE_GETTEXT - 0) */
+#define _(msgid) msgid
+#endif /* !(HAVE_GETTEXT - 0) */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+#ifndef P
+#ifdef __STDC__
+#define P(x) x
+#endif /* defined __STDC__ */
+#ifndef __STDC__
+#define P(x) ()
+#endif /* !defined __STDC__ */
+#endif /* !defined P */
+
+extern char ** environ;
+extern char * tzname[2];
+
+static char * abbr P((struct tm * tmp));
+static long delta P((struct tm * newp, struct tm * oldp));
+static time_t hunt P((char * name, time_t lot, time_t hit));
+static size_t longest;
+static void show P((char * zone, time_t t, int v));
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ int c;
+ int vflag;
+ char * cutoff;
+ int cutyear;
+ long cuttime;
+ char ** fakeenv;
+ time_t now;
+ time_t t;
+ time_t newt;
+#ifndef __APPLE__
+// <rdar://problem/6013740>
+// The approach of walking through every day from the minimum
+// possible time_t value to the maximum possible time_t value
+// falls apart with 64-bit time_t (takes too long to iterate,
+// and causes gmtime(3) and localtime(3) to return EOVERFLOW
+// which this code does not anticipate). Limiting the time_t
+// range to [INT_MIN:INT_MAX] even on LP64.
+ time_t hibit;
+#endif
+ struct tm tm;
+ struct tm newtm;
+
+ INITIALIZE(cuttime);
+#if HAVE_GETTEXT - 0
+ (void) setlocale(LC_MESSAGES, "");
+#ifdef TZ_DOMAINDIR
+ (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
+#endif /* defined(TEXTDOMAINDIR) */
+ (void) textdomain(TZ_DOMAIN);
+#endif /* HAVE_GETTEXT - 0 */
+ for (i = 1; i < argc; ++i)
+ if (strcmp(argv[i], "--version") == 0) {
+ errx(EXIT_SUCCESS, "%s", elsieid);
+ }
+ vflag = 0;
+ cutoff = NULL;
+ while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
+ if (c == 'v')
+ vflag = 1;
+ else cutoff = optarg;
+ if ((c != -1) ||
+ (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
+ usage();
+ }
+ if (cutoff != NULL) {
+ int y;
+
+ cutyear = atoi(cutoff);
+ cuttime = 0;
+ for (y = EPOCH_YEAR; y < cutyear; ++y)
+ cuttime += DAYSPERNYEAR + isleap(y);
+ cuttime *= SECSPERHOUR * HOURSPERDAY;
+ }
+ (void) time(&now);
+ longest = 0;
+ for (i = optind; i < argc; ++i)
+ if (strlen(argv[i]) > longest)
+ longest = strlen(argv[i]);
+#ifndef __APPLE__
+ for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
+ continue;
+#endif
+ {
+ int from;
+ int to;
+
+ for (i = 0; environ[i] != NULL; ++i)
+ continue;
+ fakeenv = (char **) malloc((size_t) ((i + 2) *
+ sizeof *fakeenv));
+ if (fakeenv == NULL ||
+ (fakeenv[0] = (char *) malloc((size_t) (longest +
+ 4))) == NULL)
+ errx(EXIT_FAILURE,
+ _("malloc() failed"));
+ to = 0;
+ (void) strcpy(fakeenv[to++], "TZ=");
+ for (from = 0; environ[from] != NULL; ++from)
+ if (strncmp(environ[from], "TZ=", 3) != 0)
+ fakeenv[to++] = environ[from];
+ fakeenv[to] = NULL;
+ environ = fakeenv;
+ }
+ for (i = optind; i < argc; ++i) {
+ static char buf[MAX_STRING_LENGTH];
+
+ (void) strcpy(&fakeenv[0][3], argv[i]);
+ if (!vflag) {
+ show(argv[i], now, FALSE);
+ continue;
+ }
+ /*
+ ** Get lowest value of t.
+ */
+#ifdef __APPLE__
+ t = INT_MIN;
+#else
+ t = hibit;
+ if (t > 0) /* time_t is unsigned */
+ t = 0;
+#endif
+ show(argv[i], t, TRUE);
+ t += SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ tm = *localtime(&t);
+ (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
+ for ( ; ; ) {
+ if (cutoff != NULL && t >= cuttime)
+ break;
+ newt = t + SECSPERHOUR * 12;
+ if (cutoff != NULL && newt >= cuttime)
+ break;
+#ifdef __APPLE__
+ if (newt > INT_MAX)
+ break;
+#else
+ if (newt <= t)
+ break;
+#endif
+ newtm = *localtime(&newt);
+ if (delta(&newtm, &tm) != (newt - t) ||
+ newtm.tm_isdst != tm.tm_isdst ||
+ strcmp(abbr(&newtm), buf) != 0) {
+ newt = hunt(argv[i], t, newt);
+ newtm = *localtime(&newt);
+ (void) strncpy(buf, abbr(&newtm),
+ (sizeof buf) - 1);
+ }
+ t = newt;
+ tm = newtm;
+ }
+ /*
+ ** Get highest value of t.
+ */
+#ifdef __APPLE__
+ t = INT_MAX;
+#else
+ t = ~((time_t) 0);
+ if (t < 0) /* time_t is signed */
+ t &= ~hibit;
+#endif
+ t -= SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ t += SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ }
+ if (fflush(stdout) || ferror(stdout))
+ errx(EXIT_FAILURE, _("error writing standard output"));
+ exit(EXIT_SUCCESS);
+
+ /* gcc -Wall pacifier */
+ for ( ; ; )
+ continue;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+_("usage: zdump [--version] [-v] [-c cutoff] zonename ...\n"));
+ exit(EXIT_FAILURE);
+}
+
+static time_t
+hunt(char *name, time_t lot, time_t hit)
+{
+ time_t t;
+ struct tm lotm;
+ struct tm tm;
+ static char loab[MAX_STRING_LENGTH];
+
+ lotm = *localtime(&lot);
+ (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
+ while ((hit - lot) >= 2) {
+ t = lot / 2 + hit / 2;
+ if (t <= lot)
+ ++t;
+ else if (t >= hit)
+ --t;
+ tm = *localtime(&t);
+ if (delta(&tm, &lotm) == (t - lot) &&
+ tm.tm_isdst == lotm.tm_isdst &&
+ strcmp(abbr(&tm), loab) == 0) {
+ lot = t;
+ lotm = tm;
+ } else hit = t;
+ }
+ show(name, lot, TRUE);
+ show(name, hit, TRUE);
+ return hit;
+}
+
+/*
+** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
+*/
+
+static long
+delta(struct tm *newp, struct tm *oldp)
+{
+ long result;
+ int tmy;
+
+ if (newp->tm_year < oldp->tm_year)
+ return -delta(oldp, newp);
+ result = 0;
+ for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
+ result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE);
+ result += newp->tm_yday - oldp->tm_yday;
+ result *= HOURSPERDAY;
+ result += newp->tm_hour - oldp->tm_hour;
+ result *= MINSPERHOUR;
+ result += newp->tm_min - oldp->tm_min;
+ result *= SECSPERMIN;
+ result += newp->tm_sec - oldp->tm_sec;
+ return result;
+}
+
+static void
+show(char *zone, time_t t, int v)
+{
+ struct tm * tmp;
+
+ (void) printf("%-*s ", (int) longest, zone);
+ if (v)
+ (void) printf("%.24s UTC = ", asctime(gmtime(&t)));
+ tmp = localtime(&t);
+ (void) printf("%.24s", asctime(tmp));
+ if (*abbr(tmp) != '\0')
+ (void) printf(" %s", abbr(tmp));
+ if (v) {
+ (void) printf(" isdst=%d", tmp->tm_isdst);
+#ifdef TM_GMTOFF
+ (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
+#endif /* defined TM_GMTOFF */
+ }
+ (void) printf("\n");
+}
+
+static char *
+abbr(struct tm *tmp)
+{
+ char * result;
+ static char nada;
+
+ if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
+ return &nada;
+ result = tzname[tmp->tm_isdst];
+ return (result == NULL) ? &nada : result;
+}
diff --git a/system_cmds/zic.tproj/Arts.htm b/system_cmds/zic.tproj/Arts.htm
new file mode 100644
index 0000000..e8f9539
--- /dev/null
+++ b/system_cmds/zic.tproj/Arts.htm
@@ -0,0 +1,178 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<!-- $FreeBSD: src/usr.sbin/zic/Arts.htm,v 1.2 2000/05/29 20:23:04 charnier Exp $ -->
+<HTML>
+<HEAD>
+<TITLE>Time and the Arts</TITLE>
+</HEAD>
+<BODY>
+<H1>Time and the Arts</H1>
+<P>
+<H6>
+@(#)Arts.htm 7.18
+</H6>
+</P>
+<PRE>
+Data on recordings of "Save That Time," Russ Long, Serrob Publishing, BMI:
+--------------------------------------------------------------------------
+Artist: Karrin Allyson
+CD: I Didn't Know About You
+Copyright Date: 1993
+Label: Concord Jazz, Inc.
+ID: CCD-4543
+Track Time: 3:44
+Personnel: Karrin Allyson, vocal
+ Russ Long, piano
+ Gerald Spaits, bass
+ Todd Strait, drums
+Notes: CD notes "additional lyric by Karrin Allyson;
+ arranged by Russ Long and Karrin Allyson"
+ADO Rating: 1 star
+<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||175928">AMG Rating: 3.5 stars</A>
+Penguin Rating: 3.5 stars
+--------------------------------------------------------------------------
+Artist: Kevin Mahogany
+CD: Double Rainbow
+Copyright Date: 1993
+Label: Enja Records
+ID: ENJ-7097 2
+Track Time: 6:27
+Personnel: Kevin Mahogany, vocal
+ Kenny Barron, piano
+ Ray Drummond, bss
+ Ralph Moore, tenor saxophone
+ Lewis Nash, drums
+ADO Rating: 1.5 stars
+<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||262654">AMG Rating: unrated</A>
+Penguin Rating: 3 stars
+--------------------------------------------------------------------------
+Artist: Joe Williams
+CD: Here's to Life
+Copyright Date: 1994
+Label: Telarc International Corporation
+ID: CD-83357
+Track Time: 3:58
+Personnel: Joe Williams, vocal
+ The Robert Farnon [39 piece] Orchestra
+Notes: On-line information and samples available at
+ <A HREF="http://www.telarc.com/telarc/releases/release.req?ID=83357">http://telarc.dmn.com/telarc/releases/release.req?ID=83357</A>
+ADO Rating: black dot
+<A HREF="http://205.186.189.2/cgi-win/amg.exe?sql=1A_IDR|||194434">AMG Rating: 2 stars</A>
+Penguin Rating: 3 stars
+--------------------------------------------------------------------------
+Artist: Charles Fambrough
+CD: Keeper of the Spirit
+Copyright Date: 1995
+Label: AudioQuest Music
+ID: AQ-CD1033
+Track Time: 7:07
+Personnel: Charles Fambrough, bass
+ Joel Levine, tenor recorder
+ Edward Simon, piano
+ Lenny White, drums
+ Marion Simon, percussion
+Notes: On-line information and samples available at
+ <A HREF="http://wwmusic.com/~music/audioq/rel/1033.html">http://wwmusic.com/~music/audioq/rel/1033.html</A>
+ADO Rating: 2 stars
+<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||224430">AMG Rating: unrated</A>
+Penguin Rating: 3 stars
+==========================================================================
+Also of note:
+--------------------------------------------------------------------------
+Artist: Holly Cole Trio
+CD: Blame It On My Youth
+Copyright Date: 1992
+Label: Manhattan
+ID: CDP 7 97349 2
+Total Time: 37:45
+Personnel: Holly Cole, voice
+ Aaron Davis, piano
+ David Piltch, string bass
+Notes: Lyrical reference to "Eastern Standard Time" in
+ Tom Waits' "Purple Avenue"
+ADO Rating: 2.5 stars
+<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||157959">AMG Rating: 2 stars</A>
+Penguin Rating: unrated
+--------------------------------------------------------------------------
+Artist: Milt Hinton
+CD: Old Man Time
+Copyright Date: 1990
+Label: Chiaroscuro
+ID: CR(D) 310
+Total Time: 149:38 (two CDs)
+Personnel: Milt Hinton, bass
+ Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet
+ Al Grey, trombone
+ Eddie Barefield, Joe Camel (Flip Phillips), Buddy Tate,
+ clarinet and saxophone
+ John Bunch, Red Richards, Norman Simmons, Derek Smith,
+ Ralph Sutton, piano
+ Danny Barker, Al Casey, guitar
+ Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams,
+ drums
+ Lionel Hampton, vibraphone
+ Cab Calloway, Joe Williams, vocal
+ Buck Clayton, arrangements
+Notes: tunes include Old Man Time, Time After Time,
+ Sometimes I'm Happy,
+ A Hot Time in the Old Town Tonight,
+ Four or Five Times, Now's the Time,
+ Time on My Hands, This Time It's Us,
+ and Good Time Charlie
+ On-line samples available at
+ <A HREF="http://www.globalmusic.com/labels/chiaroscuro/chiaro_cd_gallery.html">http://www.globalmusic.com/labels/chiaroscuro/chiaro_cd_gallery.html</A>
+ADO Rating: 3 stars
+<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||162344">AMG Rating: 4.5 stars</A>
+Penguin Rating: 3 stars
+--------------------------------------------------------------------------
+Artist: Paul Broadbent
+CD: Pacific Standard Time
+Copyright Date: 1995
+Label: Concord Jazz, Inc.
+ID: CCD-4664
+Total Time: 62:42
+Personnel: Paul Broadbent, piano
+ Putter Smith, Bass
+ Frank Gibson, Jr., drums
+Notes: The CD cover features an analemma for equation of time fans
+ADO Rating: 1 star
+<A HREF="http://205.186.189.2/cgi-win/AMG.exe?sql=1A_IDR|||223722">AMG Rating: 3 stars</A>
+Penguin Rating: 3.5 stars
+--------------------------------------------------------------------------
+Artist: Anthony Braxton/Richard Teitelbaum
+CD: Silence/Time Zones
+Copyright Date: 1996
+Label: Black Lion
+ID: BLCD 760221
+Total Time: 72:58
+Personnel: Anthony Braxton, sopranino and alto saxophones,
+ contrebasse clarinet, miscellaneous instruments
+ Leo Smith, trumpet and miscellaneous instruments
+ Leroy Jenkins, violin and miscellaneous instruments
+ Richard Teitelbaum, modular moog and micromoog synthesizer
+ADO Rating: black dot
+<A HREF="http://205.186.189.2/cg/AMG_.exe?sql=A310757">AMG Rating: unrated</A>
+--------------------------------------------------------------------------
+Artist: Jules Verne
+Book: Le Tour du Monde en Quatre-Vingts Jours
+ (Around the World in Eighty Days)
+Notes: Wall-clock time plays a central role in the plot.
+ European readers of the 1870s clearly held the U.S. press in
+ deep contempt; the protagonists cross the U.S. without once
+ reading a paper.
+ An on-line French-language version of the book
+ "with illustrations from the original 1873 French-language edition"
+ is available at
+ <A HREF="http://fourmilab.ch/etexts/www/tdm80j">http://fourmilab.ch/etexts/www/tdm80j</A>
+ An on-line English-language translation of the book is available at
+ <A HREF="http://www.literature.org/Works/Jules-Verne/eighty">http://www.literature.org/Works/Jules-Verne/eighty</A>
+--------------------------------------------------------------------------
+Film: Bell Science - About Time
+Notes: The Frank Baxter/Richard Deacon extravaganza
+ Information on ordering is available at
+ <A HREF="http://www.videoflicks.com/VF/38/038332.htm">http://www.videoflicks.com/VF/38/038332.htm</A>
+--------------------------------------------------------------------------
+The syndicated comic strip "Dilbert" featured an all-too-rare example of
+time zone humor on 1998-03-14.
+</PRE>
+</BODY>
+</HTML>
diff --git a/system_cmds/zic.tproj/Makefile.zoneinfo.dist b/system_cmds/zic.tproj/Makefile.zoneinfo.dist
new file mode 100644
index 0000000..1e21e89
--- /dev/null
+++ b/system_cmds/zic.tproj/Makefile.zoneinfo.dist
@@ -0,0 +1,90 @@
+# $NetBSD: Makefile,v 1.14 1995/04/22 12:10:17 cgd Exp $
+
+# Change the line below for your time zone (after finding the zone you want in
+# the time zone files, or adding it to a time zone file).
+# Alternately, if you discover you've got the wrong time zone, you can just
+# zic -l rightzone
+
+################################################################################
+# NOTE: THIS MAKEFILE IS FOR REFERENCE ONLY AND IS NOT ACTUALLY EXECUTED AT
+# BUILD TIME
+################################################################################
+
+# This line has been moved to /usr/src/etc/Makefile
+LOCALTIME= US/Pacific
+
+# If you want something other than Eastern United States time as a template
+# for handling POSIX-style time zone environment variables,
+# change the line below (after finding the zone you want in the
+# time zone files, or adding it to a time zone file).
+# Alternately, if you discover you've got the wrong time zone, you can just
+# zic -p rightzone
+
+POSIXRULES= US/Pacific
+
+# Use an absolute path name for TZDIR unless you're just testing the software.
+
+TZDIR= ${DESTDIR}/usr/share/zoneinfo
+
+# If you always want time values interpreted as "seconds since the epoch
+# (not counting leap seconds)", use
+# REDO= posix_only
+# below. If you always want right time values interpreted as "seconds since
+# the epoch" (counting leap seconds)", use
+# REDO= right_only
+# below. If you want both sets of data available, with leap seconds not
+# counted normally, use
+# REDO= posix_right
+# below. If you want both sets of data available, with leap seconds counted
+# normally, use
+# REDO= right_posix
+# below.
+
+REDO= posix_only
+
+# Since "." may not be in PATH...
+YEARISTYPE= ${.CURDIR}/datfiles/yearistype.sh
+YEARISTYPECOPY= ${.OBJDIR}/yearistypecopy
+
+YDATA= africa antarctica asia australasia \
+ europe northamerica southamerica pacificnew etcetera factory \
+ backward
+NDATA= systemv
+TDATA= $(YDATA) $(NDATA)
+DATA= $(YDATA) $(NDATA) leapseconds # yearistype.sh
+USNO= usno1988 usno1989
+
+ZIC=zic
+
+${YEARISTYPECOPY}:
+ cp ${YEARISTYPE} yearistypecopy
+ chmod u+x yearistypecopy
+
+posix_only: ${TDATA} ${YEARISTYPECOPY}
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR} -L /dev/null ${TDATA})
+
+right_only: leapseconds ${TDATA} ${YEARISTYPECOPY}
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR} -L leapseconds ${TDATA})
+
+other_two: leapseconds ${TDATA} ${YEARISTYPECOPY}
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR}/posix -L /dev/null ${TDATA})
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR}/right -L leapseconds ${TDATA})
+
+posix_right: posix_only other_two
+
+right_posix: right_only other_two
+
+realinstall: ${DATA} ${REDO} ${YEARISTYPECOPY}
+ (cd ${.CURDIR}/datfiles; \
+ ${ZIC} -y ${YEARISTYPECOPY} -d ${TZDIR} -p ${POSIXRULES})
+ chown -R ${BINOWN}:${BINGRP} ${TZDIR}
+ find ${TZDIR} -type f | xargs chmod a=r
+
+CLEANFILES+= yearistypecopy
+
+.PATH: ${.CURDIR}/datfiles
+.include <bsd.prog.mk>
diff --git a/system_cmds/zic.tproj/README b/system_cmds/zic.tproj/README
new file mode 100644
index 0000000..ff974e9
--- /dev/null
+++ b/system_cmds/zic.tproj/README
@@ -0,0 +1,88 @@
+@(#)README 8.3
+This file is in the public domain, so clarified as of
+2009-05-17 by Arthur David Olson.
+
+$FreeBSD: head/contrib/tzcode/zic/README 192890 2009-05-27 12:18:39Z edwin $
+
+"What time is it?" -- Richard Deacon as The King
+"Any time you want it to be." -- Frank Baxter as The Scientist
+ (from the Bell System film "About Time")
+
+The 1989 update of the time zone package featured
+
+* POSIXization (including interpretation of POSIX-style TZ environment
+ variables, provided by Guy Harris),
+* ANSIfication (including versions of "mktime" and "difftime"),
+* SVIDulation (an "altzone" variable)
+* MACHination (the "gtime" function)
+* corrections to some time zone data (including corrections to the rules
+ for Great Britain and New Zealand)
+* reference data from the United States Naval Observatory for folks who
+ want to do additional time zones
+* and the 1989 data for Saudi Arabia.
+
+(Since this code will be treated as "part of the implementation" in some places
+and as "part of the application" in others, there's no good way to name
+functions, such as timegm, that are not part of the proposed ANSI C standard;
+such functions have kept their old, underscore-free names in this update.)
+
+And the "dysize" function has disappeared; it was present to allow compilation
+of the "date" command on old BSD systems, and a version of "date" is now
+provided in the package. The "date" command is not created when you "make all"
+since it may lack options provided by the version distributed with your
+operating system, or may not interact with the system in the same way the
+native version does.
+
+Since POSIX frowns on correct leap second handling, the default behavior of
+the "zic" command (in the absence of a "-L" option) has been changed to omit
+leap second information from its output files.
+
+Here is a recipe for acquiring, building, installing, and testing the
+tz distribution on a GNU/Linux or similar host.
+
+ mkdir tz
+ cd tz
+ wget 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
+ gzip -dc tzcode*.tar.gz | tar -xf -
+ gzip -dc tzdata*.tar.gz | tar -xf -
+
+Be sure to read the comments in "Makefile" and make any changes needed
+to make things right for your system, especially if you are using some
+platform other than GNU/Linux. Then run the following commands,
+substituting your desired installation directory for "$HOME/tzdir":
+
+ make TOPDIR=$HOME/tzdir install
+ $HOME/tzdir/etc/zdump -v America/Los_Angeles
+
+To use the new functions, use a "-ltz" option when compiling or linking.
+
+Historical local time information has been included here to:
+
+* provide a compendium of data about the history of civil time
+ that is useful even if the data are not 100% accurate;
+
+* give an idea of the variety of local time rules that have
+ existed in the past and thus an idea of the variety that may be
+ expected in the future;
+
+* provide a test of the generality of the local time rule description
+ system.
+
+The information in the time zone data files is by no means authoritative;
+the files currently do not even attempt to cover all time stamps before
+1970, and there are undoubtedly errors even for time stamps since 1970.
+If you know that the rules are different from those in a file, by all means
+feel free to change file (and please send the changed version to
+tz@elsie.nci.nih.gov for use in the future). Europeans take note!
+
+Thanks to these Timezone Caballeros who've made major contributions to the
+time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz;
+Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to
+Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales
+for testing work, and to Gwillim Law for checking local mean time data.
+None of them are responsible for remaining errors.
+
+Look in the ~ftp/pub directory of elsie.nci.nih.gov
+for updated versions of these files.
+
+Please send comments or information to tz@elsie.nci.nih.gov.
diff --git a/system_cmds/zic.tproj/Theory b/system_cmds/zic.tproj/Theory
new file mode 100644
index 0000000..cbf53b9
--- /dev/null
+++ b/system_cmds/zic.tproj/Theory
@@ -0,0 +1,552 @@
+@(#)Theory 7.15
+
+
+----- Outline -----
+
+ Time and date functions
+ Names of time zone regions
+ Time zone abbreviations
+ Calendrical issues
+ Time and time zones on Mars
+
+
+----- Time and date functions -----
+
+These time and date functions are upwards compatible with POSIX.1,
+an international standard for UNIX-like systems.
+As of this writing, the current edition of POSIX.1 is:
+
+ Information technology --Portable Operating System Interface (POSIX (R))
+ -- Part 1: System Application Program Interface (API) [C Language]
+ ISO/IEC 9945-1:1996
+ ANSI/IEEE Std 1003.1, 1996 Edition
+ 1996-07-12
+
+POSIX.1 has the following properties and limitations.
+
+* In POSIX.1, time display in a process is controlled by the
+ environment variable TZ. Unfortunately, the POSIX.1 TZ string takes
+ a form that is hard to describe and is error-prone in practice.
+ Also, POSIX.1 TZ strings can't deal with other (for example, Israeli)
+ daylight saving time rules, or situations where more than two
+ time zone abbreviations are used in an area.
+
+ The POSIX.1 TZ string takes the following form:
+
+ stdoffset[dst[offset],date[/time],date[/time]]
+
+ where:
+
+ std and dst
+ are 3 or more characters specifying the standard
+ and daylight saving time (DST) zone names.
+ offset
+ is of the form `[-]hh:[mm[:ss]]' and specifies the
+ offset west of UTC. The default DST offset is one hour
+ ahead of standard time.
+ date[/time],date[/time]
+ specifies the beginning and end of DST. If this is absent,
+ the system supplies its own rules for DST, and these can
+ differ from year to year; typically US DST rules are used.
+ time
+ takes the form `hh:[mm[:ss]]' and defaults to 02:00.
+ date
+ takes one of the following forms:
+ Jn (1<=n<=365)
+ origin-1 day number not counting February 29
+ n (0<=n<=365)
+ origin-0 day number counting February 29 if present
+ Mm.n.d (0[Sunday]<=d<=6[Saturday], 1<=n<=5, 1<=m<=12)
+ for the dth day of week n of month m of the year,
+ where week 1 is the first week in which day d appears,
+ and `5' stands for the last week in which day d appears
+ (which may be either the 4th or 5th week).
+
+* In POSIX.1, when a TZ value like "EST5EDT" is parsed,
+ typically the current US DST rules are used,
+ but this means that the US DST rules are compiled into each program
+ that does time conversion. This means that when US time conversion
+ rules change (as in the United States in 1987), all programs that
+ do time conversion must be recompiled to ensure proper results.
+
+* In POSIX.1, there's no tamper-proof way for a process to learn the
+ system's best idea of local wall clock. (This is important for
+ applications that an administrator wants used only at certain times--
+ without regard to whether the user has fiddled the "TZ" environment
+ variable. While an administrator can "do everything in UTC" to get
+ around the problem, doing so is inconvenient and precludes handling
+ daylight saving time shifts--as might be required to limit phone
+ calls to off-peak hours.)
+
+* POSIX.1 requires that systems ignore leap seconds.
+
+These are the extensions that have been made to the POSIX.1 functions:
+
+* The "TZ" environment variable is used in generating the name of a file
+ from which time zone information is read (or is interpreted a la
+ POSIX); "TZ" is no longer constrained to be a three-letter time zone
+ name followed by a number of hours and an optional three-letter
+ daylight time zone name. The daylight saving time rules to be used
+ for a particular time zone are encoded in the time zone file;
+ the format of the file allows U.S., Australian, and other rules to be
+ encoded, and allows for situations where more than two time zone
+ abbreviations are used.
+
+ It was recognized that allowing the "TZ" environment variable to
+ take on values such as "America/New_York" might cause "old" programs
+ (that expect "TZ" to have a certain form) to operate incorrectly;
+ consideration was given to using some other environment variable
+ (for example, "TIMEZONE") to hold the string used to generate the
+ time zone information file name. In the end, however, it was decided
+ to continue using "TZ": it is widely used for time zone purposes;
+ separately maintaining both "TZ" and "TIMEZONE" seemed a nuisance;
+ and systems where "new" forms of "TZ" might cause problems can simply
+ use TZ values such as "EST5EDT" which can be used both by
+ "new" programs (a la POSIX) and "old" programs (as zone names and
+ offsets).
+
+* To handle places where more than two time zone abbreviations are used,
+ the functions "localtime" and "gmtime" set tzname[tmp->tm_isdst]
+ (where "tmp" is the value the function returns) to the time zone
+ abbreviation to be used. This differs from POSIX.1, where the elements
+ of tzname are only changed as a result of calls to tzset.
+
+* Since the "TZ" environment variable can now be used to control time
+ conversion, the "daylight" and "timezone" variables are no longer
+ needed. (These variables are defined and set by "tzset"; however, their
+ values will not be used by "localtime.")
+
+* The "localtime" function has been set up to deliver correct results
+ for near-minimum or near-maximum time_t values. (A comment in the
+ source code tells how to get compatibly wrong results).
+
+* A function "tzsetwall" has been added to arrange for the system's
+ best approximation to local wall clock time to be delivered by
+ subsequent calls to "localtime." Source code for portable
+ applications that "must" run on local wall clock time should call
+ "tzsetwall();" if such code is moved to "old" systems that don't
+ provide tzsetwall, you won't be able to generate an executable program.
+ (These time zone functions also arrange for local wall clock time to be
+ used if tzset is called--directly or indirectly--and there's no "TZ"
+ environment variable; portable applications should not, however, rely
+ on this behavior since it's not the way SVR2 systems behave.)
+
+* These functions can account for leap seconds, thanks to Bradley White
+ (bww@k.cs.cmu.edu).
+
+Points of interest to folks with other systems:
+
+* This package is already part of many POSIX-compliant hosts,
+ including BSD, HP, Linux, Network Appliance, SCO, SGI, and Sun.
+ On such hosts, the primary use of this package
+ is to update obsolete time zone rule tables.
+ To do this, you may need to compile the time zone compiler
+ `zic' supplied with this package instead of using the system `zic',
+ since the format of zic's input changed slightly in late 1994,
+ and many vendors still do not support the new input format.
+
+* The UNIX Version 7 "timezone" function is not present in this package;
+ it's impossible to reliably map timezone's arguments (a "minutes west
+ of GMT" value and a "daylight saving time in effect" flag) to a
+ time zone abbreviation, and we refuse to guess.
+ Programs that in the past used the timezone function may now examine
+ tzname[localtime(&clock)->tm_isdst] to learn the correct time
+ zone abbreviation to use. Alternatively, use
+ localtime(&clock)->tm_zone if this has been enabled.
+
+* The 4.2BSD gettimeofday function is not used in this package.
+ This formerly let users obtain the current UTC offset and DST flag,
+ but this functionality was removed in later versions of BSD.
+
+* In SVR2, time conversion fails for near-minimum or near-maximum
+ time_t values when doing conversions for places that don't use UTC.
+ This package takes care to do these conversions correctly.
+
+The functions that are conditionally compiled if STD_INSPIRED is defined
+should, at this point, be looked on primarily as food for thought. They are
+not in any sense "standard compatible"--some are not, in fact, specified in
+*any* standard. They do, however, represent responses of various authors to
+standardization proposals.
+
+Other time conversion proposals, in particular the one developed by folks at
+Hewlett Packard, offer a wider selection of functions that provide capabilities
+beyond those provided here. The absence of such functions from this package
+is not meant to discourage the development, standardization, or use of such
+functions. Rather, their absence reflects the decision to make this package
+contain valid extensions to POSIX.1, to ensure its broad
+acceptability. If more powerful time conversion functions can be standardized,
+so much the better.
+
+
+----- Names of time zone rule files -----
+
+The time zone rule file naming conventions attempt to strike a balance
+among the following goals:
+
+ * Uniquely identify every national region where clocks have all
+ agreed since 1970. This is essential for the intended use: static
+ clocks keeping local civil time.
+
+ * Indicate to humans as to where that region is. This simplifes use.
+
+ * Be robust in the presence of political changes. This reduces the
+ number of updates and backward-compatibility hacks. For example,
+ names of countries are ordinarily not used, to avoid
+ incompatibilities when countries change their name
+ (e.g. Zaire->Congo) or when locations change countries
+ (e.g. Hong Kong from UK colony to China).
+
+ * Be portable to a wide variety of implementations.
+ This promotes use of the technology.
+
+ * Use a consistent naming convention over the entire world.
+ This simplifies both use and maintenance.
+
+This naming convention is not intended for use by inexperienced users
+to select TZ values by themselves (though they can of course examine
+and reuse existing settings). Distributors should provide
+documentation and/or a simple selection interface that explains the
+names; see the 'tzselect' program supplied with this distribution for
+one example.
+
+Names normally have the form AREA/LOCATION, where AREA is the name
+of a continent or ocean, and LOCATION is the name of a specific
+location within that region. North and South America share the same
+area, `America'. Typical names are `Africa/Cairo', `America/New_York',
+and `Pacific/Honolulu'.
+
+Here are the general rules used for choosing location names,
+in decreasing order of importance:
+
+ Use only valid POSIX file name components (i.e., the parts of
+ names other than `/'). Within a file name component,
+ use only ASCII letters, `.', `-' and `_'. Do not use
+ digits, as that might create an ambiguity with POSIX
+ TZ strings. A file name component must not exceed 14
+ characters or start with `-'. E.g., prefer `Brunei'
+ to `Bandar_Seri_Begawan'.
+ Include at least one location per time zone rule set per country.
+ One such location is enough. Use ISO 3166 (see the file
+ iso3166.tab) to help decide whether something is a country.
+ If all the clocks in a country's region have agreed since 1970,
+ don't bother to include more than one location
+ even if subregions' clocks disagreed before 1970.
+ Otherwise these tables would become annoyingly large.
+ If a name is ambiguous, use a less ambiguous alternative;
+ e.g. many cities are named San Jose and Georgetown, so
+ prefer `Costa_Rica' to `San_Jose' and `Guyana' to `Georgetown'.
+ Keep locations compact. Use cities or small islands, not countries
+ or regions, so that any future time zone changes do not split
+ locations into different time zones. E.g. prefer `Paris'
+ to `France', since France has had multiple time zones.
+ Use mainstream English spelling, e.g. prefer `Rome' to `Roma', and
+ prefer `Athens' to the true name (which uses Greek letters).
+ The POSIX file name restrictions encourage this rule.
+ Use the most populous among locations in a country's time zone,
+ e.g. prefer `Shanghai' to `Beijing'. Among locations with
+ similar populations, pick the best-known location,
+ e.g. prefer `Rome' to `Milan'.
+ Use the singular form, e.g. prefer `Canary' to `Canaries'.
+ Omit common suffixes like `_Islands' and `_City', unless that
+ would lead to ambiguity. E.g. prefer `Cayman' to
+ `Cayman_Islands' and `Guatemala' to `Guatemala_City',
+ but prefer `Mexico_City' to `Mexico' because the country
+ of Mexico has several time zones.
+ Use `_' to represent a space.
+ Omit `.' from abbreviations in names, e.g. prefer `St_Helena'
+ to `St._Helena'.
+ Do not change established names if they only marginally
+ violate the above rules. For example, don't change
+ the existing name `Rome' to `Milan' merely because
+ Milan's population has grown to be somewhat greater
+ than Rome's.
+ If a name is changed, put its old spelling in the `backward' file.
+
+The file `zone.tab' lists the geographical locations used to name
+time zone rule files.
+
+Older versions of this package used a different naming scheme,
+and these older names are still supported.
+See the file `backward' for most of these older names
+(e.g. `US/Eastern' instead of `America/New_York').
+The other old-fashioned names still supported are
+`WET', `CET', `MET', `EET' (see the file `europe'),
+and `Factory' (see the file `factory').
+
+
+----- Time zone abbreviations -----
+
+When this package is installed, it generates time zone abbreviations
+like `EST' to be compatible with human tradition and POSIX.1.
+Here are the general rules used for choosing time zone abbreviations,
+in decreasing order of importance:
+
+ Use abbreviations that consist of three or more ASCII letters.
+ Previous editions of this database also used characters like
+ ' ' and '?', but these characters have a special meaning to
+ the shell and cause commands like
+ set `date`
+ to have unexpected effects.
+ Previous editions of this rule required upper-case letters,
+ but the Congressman who introduced Chamorro Standard Time
+ preferred "ChST", so the rule has been relaxed.
+
+ This rule guarantees that all abbreviations could have
+ been specified by a POSIX.1 TZ string. POSIX.1
+ requires at least three characters for an
+ abbreviation. POSIX.1-1996 says that an abbreviation
+ cannot start with ':', and cannot contain ',', '-',
+ '+', NUL, or a digit. Draft 7 of POSIX 1003.1-200x
+ changes this rule to say that an abbreviation can
+ contain only '-', '+', and alphanumeric characters in
+ the current locale. To be portable to both sets of
+ rules, an abbreviation must therefore use only ASCII
+ letters, as these are the only letters that are
+ alphabetic in all locales.
+
+ Use abbreviations that are in common use among English-speakers,
+ e.g. `EST' for Eastern Standard Time in North America.
+ We assume that applications translate them to other languages
+ as part of the normal localization process; for example,
+ a French application might translate `EST' to `HNE'.
+
+ For zones whose times are taken from a city's longitude, use the
+ traditional xMT notation, e.g. `PMT' for Paris Mean Time.
+ The only name like this in current use is `GMT'.
+
+ If there is no common English abbreviation, abbreviate the English
+ translation of the usual phrase used by native speakers.
+ If this is not available or is a phrase mentioning the country
+ (e.g. ``Cape Verde Time''), then:
+
+ When a country has a single or principal time zone region,
+ append `T' to the country's ISO code, e.g. `CVT' for
+ Cape Verde Time. For summer time append `ST';
+ for double summer time append `DST'; etc.
+ When a country has multiple time zones, take the first three
+ letters of an English place name identifying each zone
+ and then append `T', `ST', etc. as before;
+ e.g. `VLAST' for VLAdivostok Summer Time.
+
+ Use "zzz" for locations while uninhabited. The mnemonic is that
+ these locations are, in some sense, asleep.
+
+Application writers should note that these abbreviations are ambiguous
+in practice: e.g. `EST' has a different meaning in Australia than
+it does in the United States. In new applications, it's often better
+to use numeric UTC offsets like `-0500' instead of time zone
+abbreviations like `EST'; this avoids the ambiguity.
+
+
+----- Calendrical issues -----
+
+Calendrical issues are a bit out of scope for a time zone database,
+but they indicate the sort of problems that we would run into if we
+extended the time zone database further into the past. An excellent
+resource in this area is Nachum Dershowitz and Edward M. Reingold,
+<a href="http://emr.cs.uiuc.edu/home/reingold/calendar-book/index.shtml">
+Calendrical Calculations
+</a>, Cambridge University Press (1997). Other information and
+sources are given below. They sometimes disagree.
+
+
+France
+
+Gregorian calendar adopted 1582-12-20.
+French Revolutionary calendar used 1793-11-24 through 1805-12-31,
+and (in Paris only) 1871-05-06 through 1871-05-23.
+
+
+Russia
+
+From Chris Carrier <72157.3334@CompuServe.COM> (1996-12-02):
+On 1929-10-01 the Soviet Union instituted an ``Eternal Calendar''
+with 30-day months plus 5 holidays, with a 5-day week.
+On 1931-12-01 it changed to a 6-day week; in 1934 it reverted to the
+Gregorian calendar while retaining the 6-day week; on 1940-06-27 it
+reverted to the 7-day week. With the 6-day week the usual days
+off were the 6th, 12th, 18th, 24th and 30th of the month.
+(Source: Evitiar Zerubavel, _The Seven Day Circle_)
+
+
+Mark Brader reported a similar story in "The Book of Calendars", edited
+by Frank Parise (1982, Facts on File, ISBN 0-8719-6467-8), page 377. But:
+
+From: Petteri Sulonen (via Usenet)
+Date: 14 Jan 1999 00:00:00 GMT
+Message-ID: <Petteri.Sulonen-1401991626030001@lapin-kulta.in.helsinki.fi>
+
+If your source is correct, how come documents between 1929 -- 1940 were
+still dated using the conventional, Gregorian calendar?
+
+I can post a scan of a document dated December 1, 1934, signed by
+Yenukidze, the secretary, on behalf of Kalinin, the President of the
+Executive Committee of the Supreme Soviet, if you like.
+
+
+
+Sweden (and Finland)
+
+From: msb@sq.com (Mark Brader)
+<a href="news:1996Jul6.012937.29190@sq.com">
+Subject: Re: Gregorian reform -- a part of locale?
+</a>
+Date: 1996-07-06
+
+In 1700, Denmark made the transition from Julian to Gregorian. Sweden
+decided to *start* a transition in 1700 as well, but rather than have one of
+those unsightly calendar gaps :-), they simply decreed that the next leap
+year after 1696 would be in 1744 -- putting the whole country on a calendar
+different from both Julian and Gregorian for a period of 40 years.
+
+However, in 1704 something went wrong and the plan was not carried through;
+they did, after all, have a leap year that year. And one in 1708. In 1712
+they gave it up and went back to Julian, putting 30 days in February that
+year!...
+
+Then in 1753, Sweden made the transition to Gregorian in the usual manner,
+getting there only 13 years behind the original schedule.
+
+(A previous posting of this story was challenged, and Swedish readers
+produced the following references to support it: "Tiderakning och historia"
+by Natanael Beckman (1924) and "Tid, en bok om tiderakning och
+kalendervasen" by Lars-Olof Lode'n (no date was given).)
+
+
+Grotefend's data
+
+From: "Michael Palmer" <mpalmer@netcom.com> [with one obvious typo fixed]
+Subject: Re: Gregorian Calendar (was Re: Another FHC related question
+Newsgroups: soc.genealogy.german
+Date: Tue, 9 Feb 1999 02:32:48 -800
+Message-ID: <199902091032.CAA09644@netcom10.netcom.com>
+
+The following is a(n incomplete) listing, arranged chronologically, of
+European states, with the date they converted from the Julian to the
+Gregorian calendar:
+
+04/15 Oct 1582 - Italy (with exceptions), Spain, Portugal, Poland (Roman
+ Catholics and Danzig only)
+09/20 Dec 1582 - France, Lorraine
+
+21 Dec 1582/
+ 01 Jan 1583 - Holland, Brabant, Flanders, Hennegau
+10/21 Feb 1583 - bishopric of Liege (L"uttich)
+13/24 Feb 1583 - bishopric of Augsburg
+04/15 Oct 1583 - electorate of Trier
+05/16 Oct 1583 - Bavaria, bishoprics of Freising, Eichstedt, Regensburg,
+ Salzburg, Brixen
+13/24 Oct 1583 - Austrian Oberelsass and Breisgau
+20/31 Oct 1583 - bishopric of Basel
+02/13 Nov 1583 - duchy of J"ulich-Berg
+02/13 Nov 1583 - electorate and city of K"oln
+04/15 Nov 1583 - bishopric of W"urzburg
+11/22 Nov 1583 - electorate of Mainz
+16/27 Nov 1583 - bishopric of Strassburg and the margraviate of Baden
+17/28 Nov 1583 - bishopric of M"unster and duchy of Cleve
+14/25 Dec 1583 - Steiermark
+
+06/17 Jan 1584 - Austria and Bohemia
+11/22 Jan 1584 - Luzern, Uri, Schwyz, Zug, Freiburg, Solothurn
+12/23 Jan 1584 - Silesia and the Lausitz
+22 Jan/
+ 02 Feb 1584 - Hungary (legally on 21 Oct 1587)
+ Jun 1584 - Unterwalden
+01/12 Jul 1584 - duchy of Westfalen
+
+16/27 Jun 1585 - bishopric of Paderborn
+
+14/25 Dec 1590 - Transylvania
+
+22 Aug/
+ 02 Sep 1612 - duchy of Prussia
+
+13/24 Dec 1614 - Pfalz-Neuburg
+
+ 1617 - duchy of Kurland (reverted to the Julian calendar in
+ 1796)
+
+ 1624 - bishopric of Osnabr"uck
+
+ 1630 - bishopric of Minden
+
+15/26 Mar 1631 - bishopric of Hildesheim
+
+ 1655 - Kanton Wallis
+
+05/16 Feb 1682 - city of Strassburg
+
+18 Feb/
+ 01 Mar 1700 - Protestant Germany (including Swedish possessions in
+ Germany), Denmark, Norway
+30 Jun/
+ 12 Jul 1700 - Gelderland, Zutphen
+10 Nov/
+ 12 Dec 1700 - Utrecht, Overijssel
+
+31 Dec 1700/
+ 12 Jan 1701 - Friesland, Groningen, Z"urich, Bern, Basel, Geneva,
+ Turgau, and Schaffhausen
+
+ 1724 - Glarus, Appenzell, and the city of St. Gallen
+
+01 Jan 1750 - Pisa and Florence
+
+02/14 Sep 1752 - Great Britain
+
+17 Feb/
+ 01 Mar 1753 - Sweden
+
+1760-1812 - Graub"unden
+
+The Russian empire (including Finland and the Baltic states) did not
+convert to the Gregorian calendar until the Soviet revolution of 1917.
+
+Source: H. Grotefend, _Taschenbuch der Zeitrechnung des deutschen
+Mittelalters und der Neuzeit_, herausgegeben von Dr. O. Grotefend
+(Hannover: Hahnsche Buchhandlung, 1941), pp. 26-28.
+
+
+----- Time and time zones on Mars -----
+
+Some people have adjusted their work schedules to fit Mars time.
+Dozens of special Mars watches were built for Jet Propulsion
+Laboratory workers who kept Mars time during the Mars Exploration
+Rovers mission (2004). These timepieces look like normal Seikos and
+Citizens but use Mars seconds rather than terrestrial seconds.
+
+A Mars solar day is called a "sol" and has a mean period equal to
+about 24 hours 39 minutes 35.244 seconds in terrestrial time. It is
+divided into a conventional 24-hour clock, so each Mars second equals
+about 1.02749125 terrestrial seconds.
+
+The prime meridian of Mars goes through the center of the crater
+Airy-0, named in honor of the British astronomer who built the
+Greenwich telescope that defines Earth's prime meridian. Mean solar
+time on the Mars prime meridian is called Mars Coordinated Time (MTC).
+
+Each landed mission on Mars has adopted a different reference for
+solar time keeping, so there is no real standard for Mars time zones.
+For example, the Mars Exploration Rover project (2004) defined two
+time zones "Local Solar Time A" and "Local Solar Time B" for its two
+missions, each zone designed so that its time equals local true solar
+time at approximately the middle of the nominal mission. Such a "time
+zone" is not particularly suited for any application other than the
+mission itself.
+
+Many calendars have been proposed for Mars, but none have achieved
+wide acceptance. Astronomers often use Mars Sol Date (MSD) which is a
+sequential count of Mars solar days elapsed since about 1873-12-29
+12:00 GMT.
+
+The tz database does not currently support Mars time, but it is
+documented here in the hopes that support will be added eventually.
+
+Sources:
+
+Michael Allison and Robert Schmunk,
+"Technical Notes on Mars Solar Time as Adopted by the Mars24 Sunclock"
+<http://www.giss.nasa.gov/tools/mars24/help/notes.html> (2004-03-15).
+
+Jia-Rui Chong, "Workdays Fit for a Martian", Los Angeles Times
+(2004-01-14), pp A1, A20-A21.
diff --git a/system_cmds/zic.tproj/ZIC_HACK b/system_cmds/zic.tproj/ZIC_HACK
new file mode 100644
index 0000000..57851d9
--- /dev/null
+++ b/system_cmds/zic.tproj/ZIC_HACK
@@ -0,0 +1,6 @@
+#!/bin/sh
+#this must be run on a native system
+
+ZONE_FILES="$(egrep --files-with-match '^(Zone|Rule|Link)' datfiles/*)"
+zic -y datfiles/yearistype.sh -d /tmp/zoneinfo -L /dev/null $ZONE_FILES
+
diff --git a/system_cmds/zic.tproj/build_zichost.sh b/system_cmds/zic.tproj/build_zichost.sh
new file mode 100755
index 0000000..69711cc
--- /dev/null
+++ b/system_cmds/zic.tproj/build_zichost.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+set -e
+set -x
+
+if [ $# -ne 1 ]; then
+ echo "Usage: $0 BUILT_PRODUCTS_DIR" 1>&2
+ exit 1
+fi
+
+BUILT_PRODUCTS_DIR="$1"
+
+# We may not be building for a platform we can natively
+# run on the build machine. Build a dedicate copy of zic
+# for processing zoneinfo files
+
+ZICHOST_OBJROOT="${BUILT_PRODUCTS_DIR}/zic_host-objroot"
+ZICHOST_SYMROOT="${BUILT_PRODUCTS_DIR}/zic_host-sym"
+ZICHOST_DSTROOT="${BUILT_PRODUCTS_DIR}/zic_host-dst"
+ZICHOST="${ZICHOST_DSTROOT}/zic_host"
+
+# A full environment causes build settings from a cross
+# build (like PLATFORM_NAME) to leak into a native
+# host tool build
+
+EXTRA_ARGS=""
+if [ -n "${XCODE_DEVELOPER_USR_PATH}" ]; then
+ EXTRA_ARGS="XCODE_DEVELOPER_USR_PATH=${XCODE_DEVELOPER_USR_PATH}"
+fi
+
+env -i \
+ TMPDIR="${TMPDIR}" \
+ PATH="${PATH}" \
+ XBS_IS_CHROOTED="${XBS_IS_CHROOTED}" \
+ SCDontUseServer="${SCDontUseServer}" \
+ __CFPREFERENCES_AVOID_DAEMON="${__CFPREFERENCES_AVOID_DAEMON}" \
+ __CF_USER_TEXT_ENCODING="${__CF_USER_TEXT_ENCODING}" \
+ LANG="${LANG}" \
+ HOME="${HOME}" \
+ $EXTRA_ARGS \
+ TOOLCHAINS="${TOOLCHAINS}" \
+ xcrun -sdk "${SDKROOT}" xcodebuild install \
+ -target zic \
+ -sdk "macosxinternal" \
+ SRCROOT="${SRCROOT}" \
+ OBJROOT="${ZICHOST_OBJROOT}" \
+ SYMROOT="${ZICHOST_SYMROOT}" \
+ DSTROOT="${ZICHOST_DSTROOT}" \
+ ARCHS='$(NATIVE_ARCH_ACTUAL)' \
+ PRODUCT_NAME=zic_host \
+ INSTALL_PATH="/"
diff --git a/system_cmds/zic.tproj/generate_zone_file_list.sh b/system_cmds/zic.tproj/generate_zone_file_list.sh
new file mode 100755
index 0000000..c28c4da
--- /dev/null
+++ b/system_cmds/zic.tproj/generate_zone_file_list.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+set -e
+set -x
+
+# we need to know where the data files are...
+if [ $# -ne 1 ]; then
+ echo "Usage: $0 DATA_FILES_DIR" 1>&2
+ exit 1
+fi
+
+DATFILES="$1"
+ZONE_FILES="$(egrep --files-with-match '^(Zone|Rule|Link)' "${DATFILES}"/* | awk -F "/" '{print $NF}')"
+
+for tz in ${ZONE_FILES}; do
+ if [ ${tz} = "backward" ]; then
+ DO_BACKWARD=1
+ continue
+ elif [ ${tz} = "backzone" ]; then
+ continue
+ else
+ echo "${tz}"
+ fi
+done
+
+if [ -n "$DO_BACKWARD" ]; then
+ echo "backward"
+fi
+
diff --git a/system_cmds/zic.tproj/generate_zoneinfo.sh b/system_cmds/zic.tproj/generate_zoneinfo.sh
new file mode 100755
index 0000000..2f25d1c
--- /dev/null
+++ b/system_cmds/zic.tproj/generate_zoneinfo.sh
@@ -0,0 +1,105 @@
+#!/bin/sh
+set -e
+set -x
+
+printenv | sort
+
+if [ $# -ne 5 ]; then
+ echo "Usage: $0 SRCROOT OBJROOT BUILT_PRODUCTS_DIR SDKROOT PLATFORM_NAME" 1>&2
+ exit 1
+fi
+
+SRCROOT="$1"
+OBJROOT="$2"
+BUILT_PRODUCTS_DIR="$3"
+SDKROOT="$4"
+PLATFORM_NAME="$5"
+
+ZICHOST_SYMROOT="${BUILT_PRODUCTS_DIR}/zic_host-sym"
+ZICHOST_DSTROOT="${BUILT_PRODUCTS_DIR}/zic_host-dst"
+ZICHOST="${ZICHOST_DSTROOT}/zic_host"
+
+LOCALTIME="US/Pacific"
+POSIXRULES="US/Pacific"
+
+ZONEINFO="${BUILT_PRODUCTS_DIR}/zoneinfo"
+DATFILES="${BUILT_PRODUCTS_DIR}/datfiles"
+PRIVATEDIR="${BUILT_PRODUCTS_DIR}/private"
+
+# ftp://elsie.nci.nih.gov/pub/tzdata*.tar.gz
+# the tzdata*.tar.gz file is automatically unpacked and a version file created
+# /usr/local/share/tz/tzdata*.tar.gz is installed by the TimeZoneData project
+TARBALL="${SDKROOT}"/usr/local/share/tz/latest_tzdata.tar.gz
+if [ ! -L "$TARBALL" ]; then
+ echo "error: ${TARBALL} is not a symbolic link" 1>&2
+ exit 1
+fi
+if [ ! -r "$TARBALL" ]; then
+ echo "error: ${TARBALL} does not point to a valid file" 1>&2
+ exit 1
+fi
+DATVERS=`readlink ${TARBALL} | cut -d. -f1 | sed -e 's/^tzdata//'`
+VERSIONFILE="${ZONEINFO}/+VERSION"
+
+mkdir -p "${DATFILES}"
+mkdir -p "${ZONEINFO}"
+tar zxf "${TARBALL}" -C "${DATFILES}"
+ZONE_FILES="$("${SRCROOT}"/zic.tproj/generate_zone_file_list.sh "${DATFILES}")"
+for tz in ${ZONE_FILES}; do
+ if [ ${tz} = "northamerica" ]; then
+ ARG="-p America/New_York"
+ else
+ ARG=""
+ fi
+ "${ZICHOST}" ${ARG} -L /dev/null -d "${ZONEINFO}" \
+ -y "${DATFILES}/yearistype.sh" "${DATFILES}/${tz}" || exit 1
+done
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+chmod -R og-w "${ZONEINFO}"
+for f in "zone.tab" "iso3166.tab" "leapseconds"; do
+ install -m 0444 "${DATFILES}/$f" "${ZONEINFO}/$f" || exit 1
+done
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+if [ -n "$RC_BRIDGE" ]; then
+ ACTUAL_PLATFORM_NAME="bridgeos"
+else
+ ACTUAL_PLATFORM_NAME="${PLATFORM_NAME}"
+fi
+
+case "$ACTUAL_PLATFORM_NAME" in
+bridge*)
+ LOCALTIME="GMT"
+ ;;
+esac
+
+case "$ACTUAL_PLATFORM_NAME" in
+iphone*|appletv*|watch*|bridge*)
+ mkdir -p "${PRIVATEDIR}/var/db"
+ mkdir -p -m a+rx "${PRIVATEDIR}/var/db/timezone"
+
+ # This link must precisely start with TZDIR followed by a slash. radar:13532660
+ ln -hfs "/var/db/timezone/zoneinfo/${LOCALTIME}" "${PRIVATEDIR}/var/db/timezone/localtime"
+ ;;
+macosx)
+ mkdir -p "${PRIVATEDIR}/etc"
+ ln -hfs "/var/db/timezone/zoneinfo/${LOCALTIME}" "${PRIVATEDIR}/etc/localtime"
+ ;;
+*)
+ echo "Unsupported platform: $ACTUAL_PLATFORM_NAME"
+ exit 1
+ ;;
+esac
+
+rm -f "${VERSIONFILE}"
+echo ${DATVERS} > "${VERSIONFILE}"
+chmod 444 "${VERSIONFILE}"
+touch "${ZONEINFO}"
+touch "${PRIVATEDIR}"
+
diff --git a/system_cmds/zic.tproj/ialloc.c b/system_cmds/zic.tproj/ialloc.c
new file mode 100644
index 0000000..dda367b
--- /dev/null
+++ b/system_cmds/zic.tproj/ialloc.c
@@ -0,0 +1,91 @@
+/*
+** This file is in the public domain, so clarified as of
+** 2006-07-17 by Arthur David Olson.
+*/
+
+#ifndef lint
+#ifndef NOID
+static const char elsieid[] = "@(#)ialloc.c 8.30";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: head/contrib/tzcode/zic/ialloc.c 192625 2009-05-23 06:31:50Z edwin $";
+#endif /* not lint */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+#define nonzero(n) (((n) == 0) ? 1 : (n))
+
+char *
+imalloc(n)
+const int n;
+{
+ return malloc((size_t) nonzero(n));
+}
+
+char *
+icalloc(nelem, elsize)
+int nelem;
+int elsize;
+{
+ if (nelem == 0 || elsize == 0)
+ nelem = elsize = 1;
+ return calloc((size_t) nelem, (size_t) elsize);
+}
+
+void *
+irealloc(pointer, size)
+void * const pointer;
+const int size;
+{
+ if (pointer == NULL)
+ return imalloc(size);
+ return realloc((void *) pointer, (size_t) nonzero(size));
+}
+
+char *
+icatalloc(old, new)
+char * const old;
+const char * const new;
+{
+ register char * result;
+ register int oldsize, newsize;
+
+ newsize = (new == NULL) ? 0 : strlen(new);
+ if (old == NULL)
+ oldsize = 0;
+ else if (newsize == 0)
+ return old;
+ else oldsize = strlen(old);
+ if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)
+ if (new != NULL)
+ (void) strcpy(result + oldsize, new);
+ return result;
+}
+
+char *
+icpyalloc(string)
+const char * const string;
+{
+ return icatalloc((char *) NULL, string);
+}
+
+void
+ifree(p)
+char * const p;
+{
+ if (p != NULL)
+ (void) free(p);
+}
+
+void
+icfree(p)
+char * const p;
+{
+ if (p != NULL)
+ (void) free(p);
+}
diff --git a/system_cmds/zic.tproj/install_zoneinfo.sh b/system_cmds/zic.tproj/install_zoneinfo.sh
new file mode 100755
index 0000000..50a9deb
--- /dev/null
+++ b/system_cmds/zic.tproj/install_zoneinfo.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+set -e
+set -x
+
+if [ -n "$RC_BRIDGE" ]; then
+ ACTUAL_PLATFORM_NAME="bridgeos"
+else
+ ACTUAL_PLATFORM_NAME="${PLATFORM_NAME}"
+fi
+
+# This sets up the paths for the default set of zoneinfo files
+# On iOS, watchOS, and tvOS, this is handled by tzd in coordination with
+# launchd on first boot.
+# On macOS, the directory needs to be setup # during mastering for SIP
+# protection, and the symlink for the BaseSystem.
+# On bridgeOS tzd doesn't exist, so needs this all setup statically.
+default_zoneinfo_setup()
+{
+ mkdir -p "${DSTROOT}/private/var/db/timezone"
+ chmod 555 "${DSTROOT}/private/var/db/timezone"
+ ln -hfs "/usr/share/zoneinfo.default" "${DSTROOT}/private/var/db/timezone/zoneinfo"
+}
+
+case "$ACTUAL_PLATFORM_NAME" in
+iphone*|appletv*|watch*|macosx)
+ ditto "${BUILT_PRODUCTS_DIR}/zoneinfo" "${DSTROOT}/usr/share/zoneinfo.default"
+ ln -hfs "/var/db/timezone/zoneinfo" "${DSTROOT}/usr/share/zoneinfo"
+ case "$ACTUAL_PLATFORM_NAME" in
+ macosx)
+ default_zoneinfo_setup
+ ;;
+ esac
+ ;;
+bridge*)
+ # Since bridgeOS lacks any mechanism to change timezones (currently),
+ # and in the interest of saving space, only GMT is installed.
+ mkdir -p "${DSTROOT}/usr/share/zoneinfo.default"
+ chmod 555 "${DSTROOT}/usr/share/zoneinfo.default"
+ ditto "${BUILT_PRODUCTS_DIR}/zoneinfo/GMT" "${DSTROOT}/usr/share/zoneinfo.default/GMT"
+ default_zoneinfo_setup
+ ;;
+*)
+ echo "Unsupported platform: $ACTUAL_PLATFORM_NAME"
+ exit 1
+ ;;
+esac
+
diff --git a/system_cmds/zic.tproj/private.h b/system_cmds/zic.tproj/private.h
new file mode 100644
index 0000000..ae931b0
--- /dev/null
+++ b/system_cmds/zic.tproj/private.h
@@ -0,0 +1,272 @@
+#ifndef PRIVATE_H
+
+#define PRIVATE_H
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson.
+*/
+
+/*
+ * FreeBSD modifications: separate libc's privates from zic's.
+ * This makes it easier when we need to update one but not the other.
+ * I have removed all of the ifdef spaghetti which is not relevant to
+ * zic from this file.
+ *
+ * $FreeBSD: head/contrib/tzcode/zic/private.h 207590 2010-05-03 22:32:26Z emaste $
+ */
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+static const char privatehid[] = "@(#)private.h 8.6";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#define GRANDPARENTED "Local time zone must be set--use tzsetup"
+
+/*
+** Defaults for preprocessor symbols.
+** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
+*/
+
+#ifndef HAVE_GETTEXT
+#define HAVE_GETTEXT 0
+#endif /* !defined HAVE_GETTEXT */
+
+#ifndef HAVE_SYMLINK
+#define HAVE_SYMLINK 1
+#endif /* !defined HAVE_SYMLINK */
+
+#ifndef HAVE_SYS_STAT_H
+#define HAVE_SYS_STAT_H 1
+#endif /* !defined HAVE_SYS_STAT_H */
+
+#ifndef HAVE_SYS_WAIT_H
+#define HAVE_SYS_WAIT_H 1
+#endif /* !defined HAVE_SYS_WAIT_H */
+
+#ifndef HAVE_UNISTD_H
+#define HAVE_UNISTD_H 1
+#endif /* !defined HAVE_UNISTD_H */
+
+/*
+** Nested includes
+*/
+
+#include "sys/types.h" /* for time_t */
+#include "stdio.h"
+#include "errno.h"
+#include "string.h"
+#include "limits.h" /* for CHAR_BIT et al. */
+#include "time.h"
+#include "stdlib.h"
+
+#if HAVE_GETTEXT
+#include "libintl.h"
+#endif /* HAVE_GETTEXT */
+
+#if HAVE_SYS_WAIT_H
+#include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */
+#endif /* HAVE_SYS_WAIT_H */
+
+#if HAVE_UNISTD_H
+#include "unistd.h" /* for F_OK and R_OK, and other POSIX goodness */
+#endif /* HAVE_UNISTD_H */
+
+#ifndef F_OK
+#define F_OK 0
+#endif /* !defined F_OK */
+#ifndef R_OK
+#define R_OK 4
+#endif /* !defined R_OK */
+
+/* Unlike <ctype.h>'s isdigit, this also works if c < 0 | c > UCHAR_MAX. */
+#define is_digit(c) ((unsigned)(c) - '0' <= 9)
+
+/*
+** Define HAVE_STDINT_H's default value here, rather than at the
+** start, since __GLIBC__'s value depends on previously-included
+** files.
+** (glibc 2.1 and later have stdint.h, even with pre-C99 compilers.)
+*/
+#ifndef HAVE_STDINT_H
+#define HAVE_STDINT_H \
+ (199901 <= __STDC_VERSION__ || \
+ 2 < (__GLIBC__ + (0 < __GLIBC_MINOR__)))
+#endif /* !defined HAVE_STDINT_H */
+
+#if HAVE_STDINT_H
+#include "stdint.h"
+#endif /* !HAVE_STDINT_H */
+
+#ifndef INT_FAST64_MAX
+/* Pre-C99 GCC compilers define __LONG_LONG_MAX__ instead of LLONG_MAX. */
+#if defined LLONG_MAX || defined __LONG_LONG_MAX__
+typedef long long int_fast64_t;
+#else /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
+#if (LONG_MAX >> 31) < 0xffffffff
+Please use a compiler that supports a 64-bit integer type (or wider);
+you may need to compile with "-DHAVE_STDINT_H".
+#endif /* (LONG_MAX >> 31) < 0xffffffff */
+typedef long int_fast64_t;
+#endif /* ! (defined LLONG_MAX || defined __LONG_LONG_MAX__) */
+#endif /* !defined INT_FAST64_MAX */
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif /* !defined INT32_MAX */
+#ifndef INT32_MIN
+#define INT32_MIN (-1 - INT32_MAX)
+#endif /* !defined INT32_MIN */
+
+/*
+** Workarounds for compilers/systems.
+ */
+
+/*
+** Some time.h implementations don't declare asctime_r.
+** Others might define it as a macro.
+** Fix the former without affecting the latter.
+ */
+#ifndef asctime_r
+extern char * asctime_r(struct tm const *, char *);
+#endif
+
+
+
+/*
+** Private function declarations.
+*/
+char * icalloc (int nelem, int elsize);
+char * icatalloc (char * old, const char * new);
+char * icpyalloc (const char * string);
+char * imalloc (int n);
+void * irealloc (void * pointer, int size);
+void icfree (char * pointer);
+void ifree (char * pointer);
+const char * scheck (const char *string, const char *format);
+
+/*
+** Finally, some convenience items.
+*/
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE 0
+#endif /* !defined FALSE */
+
+#ifndef TYPE_BIT
+#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
+#endif /* !defined TYPE_BIT */
+
+#ifndef TYPE_SIGNED
+#define TYPE_SIGNED(type) (((type) -1) < 0)
+#endif /* !defined TYPE_SIGNED */
+
+/*
+** Since the definition of TYPE_INTEGRAL contains floating point numbers,
+** it cannot be used in preprocessor directives.
+*/
+
+#ifndef TYPE_INTEGRAL
+#define TYPE_INTEGRAL(type) (((type) 0.5) != 0.5)
+#endif /* !defined TYPE_INTEGRAL */
+
+#ifndef INT_STRLEN_MAXIMUM
+/*
+** 302 / 1000 is log10(2.0) rounded up.
+** Subtract one for the sign bit if the type is signed;
+** add one for integer division truncation;
+** add one more for a minus sign if the type is signed.
+*/
+#define INT_STRLEN_MAXIMUM(type) \
+ ((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + \
+ 1 + TYPE_SIGNED(type))
+#endif /* !defined INT_STRLEN_MAXIMUM */
+
+/*
+** INITIALIZE(x)
+*/
+
+#ifndef GNUC_or_lint
+#ifdef lint
+#define GNUC_or_lint
+#endif /* defined lint */
+#ifndef lint
+#ifdef __GNUC__
+#define GNUC_or_lint
+#endif /* defined __GNUC__ */
+#endif /* !defined lint */
+#endif /* !defined GNUC_or_lint */
+
+#ifndef INITIALIZE
+#ifdef GNUC_or_lint
+#define INITIALIZE(x) ((x) = 0)
+#endif /* defined GNUC_or_lint */
+#ifndef GNUC_or_lint
+#define INITIALIZE(x)
+#endif /* !defined GNUC_or_lint */
+#endif /* !defined INITIALIZE */
+
+/*
+** For the benefit of GNU folk...
+** `_(MSGID)' uses the current locale's message library string for MSGID.
+** The default is to use gettext if available, and use MSGID otherwise.
+*/
+
+#ifndef _
+#if HAVE_GETTEXT
+#define _(msgid) gettext(msgid)
+#else /* !HAVE_GETTEXT */
+#define _(msgid) msgid
+#endif /* !HAVE_GETTEXT */
+#endif /* !defined _ */
+
+#ifndef TZ_DOMAIN
+#define TZ_DOMAIN "tz"
+#endif /* !defined TZ_DOMAIN */
+
+/*
+** UNIX was a registered trademark of The Open Group in 2003.
+*/
+
+#ifndef YEARSPERREPEAT
+#define YEARSPERREPEAT 400 /* years before a Gregorian repeat */
+#endif /* !defined YEARSPERREPEAT */
+
+/*
+** The Gregorian year averages 365.2425 days, which is 31556952 seconds.
+*/
+
+#ifndef AVGSECSPERYEAR
+#define AVGSECSPERYEAR 31556952L
+#endif /* !defined AVGSECSPERYEAR */
+
+#ifndef SECSPERREPEAT
+#define SECSPERREPEAT ((int_fast64_t) YEARSPERREPEAT * (int_fast64_t) AVGSECSPERYEAR)
+#endif /* !defined SECSPERREPEAT */
+
+#ifndef SECSPERREPEAT_BITS
+#define SECSPERREPEAT_BITS 34 /* ceil(log2(SECSPERREPEAT)) */
+#endif /* !defined SECSPERREPEAT_BITS */
+
+ /*
+ ** UNIX was a registered trademark of The Open Group in 2003.
+ */
+
+#endif /* !defined PRIVATE_H */
diff --git a/system_cmds/zic.tproj/scheck.c b/system_cmds/zic.tproj/scheck.c
new file mode 100644
index 0000000..10eea82
--- /dev/null
+++ b/system_cmds/zic.tproj/scheck.c
@@ -0,0 +1,68 @@
+/*
+** This file is in the public domain, so clarified as of
+** 2006-07-17 by Arthur David Olson.
+*/
+
+#ifndef lint
+#ifndef NOID
+static const char elsieid[] = "@(#)scheck.c 8.19";
+#endif /* !defined lint */
+#endif /* !defined NOID */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: head/contrib/tzcode/zic/scheck.c 192625 2009-05-23 06:31:50Z edwin $";
+#endif /* not lint */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+const char *
+scheck(string, format)
+const char * const string;
+const char * const format;
+{
+ register char * fbuf;
+ register const char * fp;
+ register char * tp;
+ register int c;
+ register const char * result;
+ char dummy;
+
+ result = "";
+ if (string == NULL || format == NULL)
+ return result;
+ fbuf = imalloc((int) (2 * strlen(format) + 4));
+ if (fbuf == NULL)
+ return result;
+ fp = format;
+ tp = fbuf;
+ while ((*tp++ = c = *fp++) != '\0') {
+ if (c != '%')
+ continue;
+ if (*fp == '%') {
+ *tp++ = *fp++;
+ continue;
+ }
+ *tp++ = '*';
+ if (*fp == '*')
+ ++fp;
+ while (is_digit(*fp))
+ *tp++ = *fp++;
+ if (*fp == 'l' || *fp == 'h')
+ *tp++ = *fp++;
+ else if (*fp == '[')
+ do *tp++ = *fp++;
+ while (*fp != '\0' && *fp != ']');
+ if ((*tp++ = *fp++) == '\0')
+ break;
+ }
+ *(tp - 1) = '%';
+ *tp++ = 'c';
+ *tp = '\0';
+ if (sscanf(string, fbuf, &dummy) != 1)
+ result = (char *) format;
+ ifree(fbuf);
+ return result;
+}
diff --git a/system_cmds/zic.tproj/tz-art.htm b/system_cmds/zic.tproj/tz-art.htm
new file mode 100644
index 0000000..56f78ac
--- /dev/null
+++ b/system_cmds/zic.tproj/tz-art.htm
@@ -0,0 +1,278 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+"DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"' />
+<title>Time and the Arts</title>
+</head>
+<body>
+<h1>Time and the Arts</h1>
+<address>
+@(#)tz-art.htm 7.53
+</address>
+<p>
+Please send corrections to this web page to the
+<a href="mailto:tz@elsie.nci.nih.gov">time zone mailing list</a>.</p>
+<p>
+See also <a href="tz-link.htm">Sources for Time Zone and Daylight Saving Time Data</a>.</p>
+<hr />
+<p>
+Data on recordings of "Save That Time," Russ Long, Serrob Publishing, BMI:</p>
+<table>
+<tr><td>Artist</td><td>Karrin Allyson</td></tr>
+<tr><td>CD</td><td>I Didn't Know About You</td></tr>
+<tr><td>Copyright Date</td><td>1993</td></tr>
+<tr><td>Label</td><td>Concord Jazz, Inc.</td></tr>
+<tr><td>ID</td><td>CCD-4543</td></tr>
+<tr><td>Track Time</td><td>3:44</td></tr>
+<tr><td>Personnel</td><td>Karrin Allyson, vocal;
+Russ Long, piano;
+Gerald Spaits, bass;
+Todd Strait, drums</td></tr>
+<tr><td>Notes</td><td>CD notes "additional lyric by Karrin Allyson;
+arranged by Russ Long and Karrin Allyson"</td></tr>
+<tr><td>ADO Rating</td><td>1 star</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A1fdovw9ta92k">AMG Rating</a></td><td>4 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3.5 stars</td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>Artist</td><td>Kevin Mahogany</td></tr>
+<tr><td>CD</td><td>Double Rainbow</td></tr>
+<tr><td>Copyright Date</td><td>1993</td></tr>
+<tr><td>Label</td><td>Enja Records</td></tr>
+<tr><td>ID</td><td>ENJ-7097 2</td></tr>
+<tr><td>Track Time</td><td>6:27</td></tr>
+<tr><td>Personnel</td><td>Kevin Mahogany, vocal;
+Kenny Barron, piano;
+Ray Drummond, bass;
+Ralph Moore, tenor saxophone;
+Lewis Nash, drums</td></tr>
+<tr><td>ADO Rating</td><td>1.5 stars</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=Akikbikzjbb19">AMG Rating</a></td><td>3 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3 stars</td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>Artist</td><td>Joe Williams</td></tr>
+<tr><td>CD</td><td>Here's to Life</td></tr>
+<tr><td>Copyright Date</td><td>1994</td></tr>
+<tr><td>Label</td><td>Telarc International Corporation</td></tr>
+<tr><td>ID</td><td>CD-83357</td></tr>
+<tr><td>Track Time</td><td>3:58</td></tr>
+<tr><td>Personnel</td><td>Joe Williams, vocal
+The Robert Farnon [39 piece] Orchestra</td></tr>
+<tr><td>Notes</td><td>This CD is also available as part of a 3-CD package from
+Telarc, "Triple Play" (CD-83461)</td></tr>
+<tr><td>ADO Rating</td><td>black dot</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=Amyyvad6kt8w1">AMG Rating</a></td><td>2 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3 stars</td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>Artist</td><td>Charles Fambrough</td></tr>
+<tr><td>CD</td><td>Keeper of the Spirit</td></tr>
+<tr><td>Copyright Date</td><td>1995</td></tr>
+<tr><td>Label</td><td>AudioQuest Music</td></tr>
+<tr><td>ID</td><td>AQ-CD1033</td></tr>
+<tr><td>Track Time</td><td>7:07</td></tr>
+<tr><td>Personnel</td><td>Charles Fambrough, bass;
+Joel Levine, tenor recorder;
+Edward Simon, piano;
+Lenny White, drums;
+Marion Simon, percussion</td></tr>
+<tr><td>Notes</td><td>On-line information and samples available at
+<a href="http://wwmusic.com/~music/audioq/rel/1033.html">http://wwmusic.com/~music/audioq/rel/1033.html</a></td></tr>
+<tr><td>ADO Rating</td><td>2 stars</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A5rkcikcjbb89">AMG Rating</a></td><td>unrated</td></tr>
+<tr><td>Penguin Rating</td><td>3 stars</td></tr>
+</table>
+<hr />
+<p>Also of note:</p>
+<table>
+<tr><td>Artist</td><td>Holly Cole Trio</td></tr>
+<tr><td>CD</td><td>Blame It On My Youth</td></tr>
+<tr><td>Copyright Date</td><td>1992</td></tr>
+<tr><td>Label</td><td>Manhattan</td></tr>
+<tr><td>ID</td><td>CDP 7 97349 2</td></tr>
+<tr><td>Total Time</td><td>37:45</td></tr>
+<tr><td>Personnel</td><td>Holly Cole, voice;
+Aaron Davis, piano;
+David Piltch, string bass</td></tr>
+<tr><td>Notes</td><td>Lyrical reference to "Eastern Standard Time" in
+Tom Waits' "Purple Avenue"</td></tr>
+<tr><td>ADO Rating</td><td>2.5 stars</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A3a9ds37ya3dg">AMG Rating</a></td><td>3 stars</td></tr>
+<tr><td>Penguin Rating</td><td>unrated</td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>Artist</td><td>Milt Hinton</td></tr>
+<tr><td>CD</td><td>Old Man Time</td></tr>
+<tr><td>Copyright Date</td><td>1990</td></tr>
+<tr><td>Label</td><td>Chiaroscuro</td></tr>
+<tr><td>ID</td><td>CR(D) 310</td></tr>
+<tr><td>Total Time</td><td>149:38 (two CDs)</td></tr>
+<tr><td>Personnel</td><td>Milt Hinton, bass;
+Doc Cheatham, Dizzy Gillespie, Clark Terry, trumpet;
+Al Grey, trombone;
+Eddie Barefield, Joe Camel (Flip Phillips), Buddy Tate,
+clarinet and saxophone;
+John Bunch, Red Richards, Norman Simmons, Derek Smith,
+Ralph Sutton, piano;
+Danny Barker, Al Casey, guitar;
+Gus Johnson, Gerryck King, Bob Rosengarden, Jackie Williams,
+drums;
+Lionel Hampton, vibraphone;
+Cab Calloway, Joe Williams, vocal;
+Buck Clayton, arrangements</td></tr>
+<tr><td>Notes</td><td>tunes include Old Man Time, Time After Time,
+Sometimes I'm Happy,
+A Hot Time in the Old Town Tonight,
+Four or Five Times, Now's the Time,
+Time on My Hands, This Time It's Us,
+and Good Time Charlie
+On-line samples available at
+<a href="http://www.chiaroscurojazz.com/albuminfo.php4?albumid=49">http://www.chiaroscurojazz.com/albuminfo.php3?albumid=49</a></td></tr>
+<tr><td>ADO Rating</td><td>3 stars</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A1cbyxdab8ola">AMG Rating</a></td><td>4.5 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3 stars</td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>Artist</td><td>Alan Broadbent</td></tr>
+<tr><td>CD</td><td>Pacific Standard Time</td></tr>
+<tr><td>Copyright Date</td><td>1995</td></tr>
+<tr><td>Label</td><td>Concord Jazz, Inc.</td></tr>
+<tr><td>ID</td><td>CCD-4664</td></tr>
+<tr><td>Total Time</td><td>62:42</td></tr>
+<tr><td>Personnel</td><td>Alan Broadbent, piano;
+Putter Smith, Bass;
+Frank Gibson, Jr., drums</td></tr>
+<tr><td>Notes</td><td>The CD cover features an analemma for equation-of-time fans</td></tr>
+<tr><td>ADO Rating</td><td>1 star</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=Asl8zefuk8gfo">AMG Rating</a></td><td>4 stars</td></tr>
+<tr><td>Penguin Rating</td><td>3.5 stars</td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>Artist</td><td>Anthony Braxton/Richard Teitelbaum</td></tr>
+<tr><td>CD</td><td>Silence/Time Zones</td></tr>
+<tr><td>Copyright Date</td><td>1996</td></tr>
+<tr><td>Label</td><td>Black Lion</td></tr>
+<tr><td>ID</td><td>BLCD 760221</td></tr>
+<tr><td>Total Time</td><td>72:58</td></tr>
+<tr><td>Personnel</td><td>Anthony Braxton, sopranino and alto saxophones,
+contrebasse clarinet, miscellaneous instruments;
+Leo Smith, trumpet and miscellaneous instruments;
+Leroy Jenkins, violin and miscellaneous instruments;
+Richard Teitelbaum, modular moog and micromoog synthesizer</td></tr>
+<tr><td>ADO Rating</td><td>black dot</td></tr>
+<tr><td><a href="http://www.allmusic.com/cg/amg.dll?p=amg&amp;sql=A5bkvu3xjan1k">AMG Rating</a></td><td>unrated</td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>Artist</td><td>Jules Verne</td></tr>
+<tr><td>Book</td><td>Le Tour du Monde en Quatre-Vingts Jours
+(Around the World in Eighty Days)</td></tr>
+<tr><td>Notes</td><td>Wall-clock time plays a central role in the plot.
+European readers of the 1870s clearly held the U.S. press in
+deep contempt; the protagonists cross the U.S. without once
+reading a paper.
+An on-line French-language version of the book
+"with illustrations from the original 1873 French-language edition"
+is available at
+<a href="http://fourmilab.ch/etexts/www/tdm80j">http://fourmilab.ch/etexts/www/tdm80j</a>
+An on-line English-language translation of the book is available at
+<a href="http://www.literature.org/Works/Jules-Verne/eighty">http://www.literature.org/Works/Jules-Verne/eighty</a></td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>Film</td><td>Bell Science - About Time</td></tr>
+<tr><td>Notes</td><td>The Frank Baxter/Richard Deacon extravaganza
+Information on ordering is available at
+<a href="http://www.videoflicks.com/VF2/1035/1035893.ihtml">http://www.videoflicks.com/VF2/1035/1035893.ihtml</a></td></tr>
+</table>
+<hr />
+<ul>
+<li>
+An episode of "The Adventures of Superman" entitled "The Mysterious
+Cube," first aired 1958-02-24, had Superman convincing the controllers
+of WWV to broadcast time signals five minutes ahead of actual time;
+doing so got a crook trying to beat the statute of limitations to
+emerge a bit too early from the titular enclosure.
+</li>
+<li>
+The 1960s ITC television series "The Prisoner" included an episode
+entitled "The Chimes of Big Ben" in which our protagonist tumbled to
+the fraudulent nature of a Poland-to-England escape upon hearing "Big
+Ben" chiming on Polish local time.
+</li>
+<li>
+The series "Seinfeld" included an episode entitled "The Susie," first
+broadcast 1997-02-13, in which Kramer decides that daylight saving time
+isn't coming fast enough, so he sets his watch ahead an hour.
+</li>
+<li>
+The syndicated comic strip "Dilbert" featured an all-too-rare example of
+time zone humor on 1998-03-14.
+</li>
+<li>
+Surrealist artist Guy Billout's work "Date Line" appeared on page 103
+of the 1999-11 Atlantic Monthly.
+</li>
+<li>
+"Gloom, Gloom, Go Away" by Walter Kirn appeared on page 106 of Time
+Magazine's 2002-11-11 issue; among other things, it proposed
+year-round DST as a way of lessening wintertime despair.
+</li>
+<li>
+The "20 Hours in America" episode of "The West Wing," first aired 2002-09-25,
+saw White House staffers stranded in Indiana; they thought they had time to
+catch Air Force One but were done in by intra-Indiana local time changes.
+</li>
+<li>
+"In what time zone would you find New York City?" was a $200 question on
+the 1999-11-13 United States airing of "Who Wants to Be a Millionaire?"
+"In 1883, what industry led the movement to divide the U.S. into four time
+zones?" was a $32,000 question on the 2001-05-23 United States airing of
+"Who Wants to Be a Millionaire?" At this rate, the million-dollar time-zone
+question should have been asked 2002-06-04.
+</li>
+</ul>
+<hr />
+<ul>
+<li>
+"We're been using the five-cent nickle in this country since 1492.
+Now that's pretty near 100 years, daylight savings [sic]."
+(Groucho Marx as Captain Spaulding in "Animal Crackers", 1930,
+as noted by Will Fitzerald, wfitzgerald@ameritech.net)
+</li>
+<li>
+"Good news."
+"What did they do? Extend Daylight Saving Time year round?"
+(Professional tanner George Hamilton, in dialog from a
+May, 1999 episode of the syndicated television series "Baywatch")
+</li>
+<li>
+"A fundamental belief held by Americans is that if you are on land, you
+cannot be killed by a fish...So most Americans remain on land, believing
+they're safe. Unfortunately, this belief&mdash;like so many myths, such as that
+there's a reason for 'Daylight Saving Time'&mdash;is false."
+(Dave Barry column, 2000-07-02)
+</li>
+<li>
+"I once had sex for an hour and five minutes, but that was on the day
+when you turn the clocks ahead."
+(Garry Shandling, 52nd Annual Emmys, 2000-09-10)
+</li>
+<li>
+"Would it impress you if I told you I invented Daylight Savings Time?"
+("Sahjhan" to "Lilah" in dialog from the "Loyalty" episode of "Angel,"
+originally aired 2002-02-25)
+</li>
+<li>
+"I thought you said Tulsa was a three hour flight."
+"Well, you're forgetting about the time difference."
+("Chandler" and "Joey" in dialog from the episode of "Friends" first
+aired 2002-12-05)
+</li>
+<li>
+"Is that a pertinent fact,
+or are you trying to dazzle me with your command of time zones?"
+(Kelsey Grammer as "Frasier Crane")
+</li>
+<li>
+"Don't worry about the world coming to an end today.
+It is already tomorrow in Australia."
+(Charles M. Schulz, provided by Steve Summit)
+</li>
+</ul>
+</body>
+</html>
diff --git a/system_cmds/zic.tproj/tz-link.htm b/system_cmds/zic.tproj/tz-link.htm
new file mode 100644
index 0000000..0e63073
--- /dev/null
+++ b/system_cmds/zic.tproj/tz-link.htm
@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE html
+ PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+<title>Sources for Time Zone and Daylight Saving Time Data</title>
+<link rel="schema.DC" href="http://purl.org/DC/elements/1.1/" />
+<meta http-equiv="Content-type" content='text/html; charset="US-ASCII"' />
+<meta name="DC.Creator" content="Eggert, Paul" />
+<meta name="DC.Contributor" content="Olson, Arthur David" />
+<meta name="DC.Date" content="2004-05-24" />
+<meta name="DC.Description"
+ content="Sources of information about time zones and daylight saving time" />
+<meta name="DC.Identifier" content="http://www.twinsun.com/tz/tz-link.htm" />
+<meta name="Keywords"
+ content="database,daylight saving,DST,time zone,timezone,tz,zoneinfo" />
+</head>
+<body>
+<h1>Sources for Time Zone and Daylight Saving Time Data</h1>
+<address>
+@(#)tz-link.htm 7.42
+</address>
+<p>
+Please send corrections to this web page to the
+<a href="mailto:tz@elsie.nci.nih.gov">time zone mailing list</a>.
+</p>
+<h2>The <code>tz</code> database</h2>
+<p>
+The public-domain time zone database contains code and data
+that represent the history of local time
+for many representative locations around the globe.
+It is updated periodically to reflect changes made by political bodies
+to UTC offsets and daylight-saving rules.
+This database (often called <code>tz</code> or <code>zoneinfo</code>)
+is used by several implementations,
+including
+<a href="http://www.gnu.org/software/libc/">the GNU C Library</a> used in
+<a href="http://www.linux.org/">GNU/Linux</a>,
+<a href="http://www.freebsd.org/">FreeBSD</a>,
+<a href="http://www.netbsd.org/">NetBSD</a>,
+<a href="http://www.openbsd.org/">OpenBSD</a>,
+<a href="http://www.cygwin.com/">Cygwin</a>,
+<a href="http://www.delorie.com/djgpp/">DJGPP</a>,
+<a href="http://www.hp.com/products1/unix/operating/">HP-UX</a>,
+<a href="http://www.sgi.com/developers/technology/irix/">IRIX</a>,
+<a href="http://www.apple.com/macosx/">Mac OS X</a>,
+<a href="http://h71000.www7.hp.com/">OpenVMS</a>,
+<a href="http://wwws.sun.com/software/solaris/">Solaris</a>,
+<a href="http://www.tru64unix.compaq.com/">Tru64</a>, and
+<a href="http://www.sco.com/products/unixware/">UnixWare</a>.</p>
+<p>
+Each location in the database represents a national region where all
+clocks keeping local time have agreed since 1970.
+Locations are identified by continent or ocean and then by the name of
+the location, which is typically the largest city within the region.
+For example, <code>America/New_York</code>
+represents most of the US eastern time zone;
+<code>America/Indianapolis</code> represents most of Indiana, which
+uses eastern time without daylight saving time (DST);
+<code>America/Detroit</code> represents most of Michigan, which uses
+eastern time but with different DST rules in 1975;
+and other entries represent smaller regions like Starke County,
+Kentucky, which switched from central to eastern time in 1991.
+To use the database, set the <code>TZ</code> environment variable to
+the location's full name, e.g., <code>TZ="America/New_York"</code>.</p>
+<p>
+In the <code>tz</code> database's
+<a href="ftp://elsie.nci.nih.gov/pub/">FTP distribution</a>,
+the code is in the file <code>tzcode<var>C</var>.tar.gz</code>,
+where <code><var>C</var></code> is the code's version;
+similarly, the data are in <code>tzdata<var>D</var>.tar.gz</code>,
+where <code><var>D</var></code> is the data's version.
+The following shell commands download
+these files to a GNU/Linux or similar host; see the downloaded
+<code>README</code> file for what to do next.</p>
+<pre style="margin-left: 2em"><code><a href="http://www.gnu.org/software/wget/">wget</a> 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
+<a href="http://www.gnu.org/software/gzip/">gzip</a> -dc tzcode*.tar.gz | <a href="http://www.gnu.org/software/tar/">tar</a> -xf -
+gzip -dc tzdata*.tar.gz | tar -xf -
+</code></pre>
+<p>
+The code lets you compile the <code>tz</code> source files into
+machine-readable binary files, one for each location. It also lets
+you read a <code>tz</code> binary file and interpret time stamps for that
+location.</p>
+<p>
+The data are by no means authoritative. If you find errors, please
+send changes to the <a href="mailto:tz@elsie.nci.nih.gov">time zone
+mailing list</a>. You can also <a
+href="mailto:tz-request@elsie.nci.nih.gov">subscribe</a> to the
+mailing list, retrieve the <a
+href="ftp://elsie.nci.nih.gov/pub/tzarchive.gz">archive of old
+messages</a> (in gzip compressed format), or retrieve <a
+href="ftp://munnari.oz.au/pub/oldtz/">archived older versions of code
+and data</a>.</p>
+<p>
+The Web has several other sources for time zone and daylight saving time data.
+Here are some recent links that may be of interest.
+</p>
+<h2>Web pages using recent versions of the <code>tz</code> database</h2>
+<ul>
+<li><a href="http://twiki.org/cgi-bin/xtra/tzdate">Date and Time Gateway</a>
+is a text-based point-and-click interface to tables of current time
+throughout the world.</li>
+<li>Fancier web interfaces, roughly in ascending order of complexity, include:
+<ul>
+<li><a href="http://www.hilink.com.au/times/">Local Times Around the
+World</a></li>
+<li><a href="http://www.convertit.com/Go/ConvertIt/World_Time/Current_Time.ASP">Current Time in 1000 Places</a></li>
+<li><a href="http://timezoneconverter.com/">Time Zone Converter</a></li>
+</ul></li>
+<li><a href="http://www.holidayfestival.com/">The Worldwide Holiday
+&amp; Festival Site</a> lists DST-related clock changes along with
+holidays.</li>
+<li><a href="http://www.timeanddate.com/worldclock/">The World Clock -
+Time Zones</a>
+is a web interface to a time zone database derived from
+<code>tz</code>'s.</li>
+</ul>
+<h2>Other time zone database formats</h2>
+<ul>
+<li>The <a href="ftp://ftp.rfc-editor.org/in-notes/rfc2445.txt">
+Internet Calendaring and Scheduling Core Object Specification
+(iCalendar)</a> specification published by the <a
+href="http://www.ietf.org/html.charters/calsch-charter.html">IETF
+Calendaring and Scheduling Working Group (calsch)</a> covers time zone
+data; see its VTIMEZONE calendar component.</li>
+<li>The <a
+href="http://lists.w3.org/Archives/Public/www-rdf-calendar/">www-rdf-calendar</a>
+list discusses <a href="http://www.w3.org/RDF/">RDF</a>-based calendar
+and group scheduling systems, and has a <a
+href="http://www.w3.org/2002/12/cal/#tzd">workspace on time zone
+data</a> converted from <code>tz</code>. An earlier <a
+href="http://www.w3.org/2000/01/foo">schema</a> was sketched out by <a
+href="http://www.w3.org/People/Berners-Lee/">Tim Berners-Lee</a>.</li>
+<li><a
+href="http://www.calsch.org/ietf/archives/draft-ietf-calsch-many-xcal-02.txt">XCal</a>
+was a draft <a href="http://www.w3.org/XML/">XML</a> document type
+definition that corresponded to iCalendar.</li>
+</ul>
+<h2>Other <code>tz</code> compilers</h2>
+<ul>
+<li><a href="http://www.dachaplin.dsl.pipex.com/vzic">Vzic iCalendar
+Timezone Converter</a> describes a program Vzic that compiles
+<code>tz</code> source into iCalendar-compatible VTIMEZONE files.
+Vzic is freely
+available under the <a href="http://www.gnu.org/copyleft/gpl.html">GNU
+General Public License (GPL)</a>.</li>
+<li><a
+href="http://search.cpan.org/dist/DateTime-TimeZone/">DateTime::TimeZone</a>
+contains a script <code>parse_olson</code> that compiles
+<code>tz</code> source into <a href="http://www.perl.org/">Perl</a>
+modules. It is part of the Perl <a
+href="http://datetime.perl.org/">DateTime Project</a>, which is freely
+available under both the GPL and the Perl <a
+href="http://www.perl.com/language/misc/Artistic.html">Artistic
+License</a>. DateTime::TimeZone also contains a script
+<code>tests_from_zdump</code> that generates test cases for each clock
+transition in the <code>tz</code> database.</li>
+<li><a href="http://oss.software.ibm.com/icu/">International Components for
+Unicode (ICU)</a> contains a C/C++ library for internationalization that
+has a compiler from <samp>tz</samp> source into an ICU-specific format.
+ICU is freely available under a BSD-style license.</li>
+<li><a href="http://joda-time.sourceforge.net/">Joda Time - Java date
+and time API</a> contains a class
+<code>org.joda.time.tz.ZoneInfoCompiler</code> that compiles
+<code>tz</code> source into a Joda-specific binary format. Joda Time
+is freely available under a BSD-style license.</li>
+</ul>
+<h2>Other <code>tz</code> binary file readers</h2>
+<ul>
+<li>The <a href="http://www.gnu.org/software/libc/">GNU C Library</a>
+has an independent, thread-safe implementation of
+a <code>tz</code> binary file reader.
+This library is freely available under the
+<a href="http://www.gnu.org/copyleft/lesser.html">
+GNU Lesser General Public License (LGPL)</a>,
+and is widely used in GNU/Linux systems.</li>
+<li><a href="http://www.bmsi.com/java/#TZ">ZoneInfo.java</a>
+is a <code>tz</code> binary file reader written in Java.
+It is freely available under the GNU LGPL.</li>
+<li><a href="http://s.keim.free.fr/tz/doc.html">Python time zones</a>
+is a <code>tz</code> binary file reader written in <a
+href="http://www.python.org/">Python</a>. It is freely available
+under a BSD-style license.</li>
+</ul>
+<h2>Other <code>tz</code>-based time zone conversion software</h2>
+<ul>
+<li><a href="http://java.sun.com/">Sun Java</a> releases since 1.4
+contain a copy of a recent <samp>tz</samp> database in a Java-specific
+format.</li>
+<li><a
+href="http://www1.tip.nl/~t876506/AboutTimeZonesHC.html">HyperCard
+time zones calculator</a> is a HyperCard stack.</li>
+<li><a
+href="http://www.cimmyt.org/timezone/">World Time Explorer</a> is a
+Microsoft Windows program.</li>
+</ul>
+<h2>Other time zone databases</h2>
+<ul>
+<li><a href="http://www.astro.com/cgi-bin/atlw3/aq.cgi?lang=e">Atlas Query
+- Astrodienst</a> is Astrodienst's Web version of Shanks's
+excellent time zone history atlases published in both <a
+href="http://astrocom.com/software/pcatlas.php">computer</a> and <a
+href="http://astrocom.com/books/xrefa.php#SHANKS">book</a> form by <a
+href="http://astrocom.com/">Astro Communications Services</a>.</li>
+<li><a href="http://worldtime.com/">WORLDTIME: interactive atlas,
+time info, public holidays</a>
+contains information on local time, sunrise and sunset,
+and public holidays in several hundred cities around the world.</li>
+<li><a href="http://www.worldtimeserver.com/">World Time Server</a>
+is another time zone database.</li>
+<li><a href="http://tycho.usno.navy.mil/tzones.html">World Time Zones</a>
+contains data from the Time Service Department of the US Naval Observatory
+(USNO), used as the source
+for the <code>usno*</code> files in the <code>tz</code> distribution.</li>
+<li><a href="http://www.airportcitycodes.com/aaa/">Airlines, Airplanes
+and Airports</a> lists current standard times for thousands of
+airports around the world. This seems to be derived from
+the <a href="http://www.iata.org/sked/publications/">Standard
+Schedules Information Manual (SSIM)</a> of the
+the <a href="http://www.iata.org/">International Air Transport
+Association</a>,
+which gives current time zone rules for
+all the airports served by commercial aviation.</li>
+</ul>
+<h2>Maps</h2>
+<ul>
+<li>The <a href="http://www.odci.gov/">United States Central
+Intelligence Agency (CIA)</a> publishes a <a
+href="http://www.odci.gov/cia/publications/factbook/reference_maps/pdf/time_zones.pdf">time
+zone map</a>; the
+<a
+href="http://www.lib.utexas.edu/maps/world.html">Perry-Casta&ntilde;eda
+Library Map Collection</a>
+of the University of Texas at Austin has copies of
+recent editions.
+The pictorial quality is good,
+but the maps do not indicate summer time,
+and parts of the data are a few years out of date.</li>
+<li><a href="http://worldtimezone.com/">World timezones map with
+current time</a>
+has several fancy time zone maps; it covers Russia particularly well.
+The maps' pictorial quality is not quite as good as the CIA's
+but the maps are more up to date.</li>
+</ul>
+<h2>Time zone boundaries</h2>
+<ul>
+<li><a href="http://home-4.tiscali.nl/~t876506/Multizones.html">Time
+zone boundaries for multizone countries</a> summarizes legal
+boundaries between time zones within countries.</li>
+<li>Manifold.net's <a
+href="http://www.manifold.net/download/freemaps.html">Free Maps and
+GIS Data</a> includes a Manifold-format map of world time zone
+boundaries distributed under the GPL. The GeoCommunity's <a
+href="http://software.geocomm.com/data/intl_timezones.html">International
+Time Zones</a> publishes the same data in other formats.</li>
+<li>The US Geological Survey's National Atlas of the United States
+publishes the <a href="http://www.nationalatlas.gov/timeznm.html">Time
+Zones of the United States</a> in the public domain.</li>
+<li>The GeoCommunity lists several commercial sources for <a
+href="http://spatialnews.geocomm.com/features/timezones/">International
+Time Zones and Time Zone Data</a>.</li>
+</ul>
+<h2>Civil time concepts and history</h2>
+<ul>
+<li><a href="http://physics.nist.gov/time">A Walk through Time</a>
+surveys the evolution of timekeeping.</li>
+<li><a href="http://webexhibits.org/daylightsaving/">About Daylight
+Saving Time - History, rationale, laws and dates</a>
+is an overall history of DST.</li>
+<li><a href="http://toi.iriti.cnr.it/">The
+Time of Internet</a>
+describes time zones and daylight saving time,
+with diagrams.
+The time zone map is out of date, however.</li>
+<li><a href="http://www.phys.uu.nl/~vgent/idl/idl.htm">A History of
+the International Date Line</a> tells the story of the most important
+time zone boundary.</li>
+<li><a href="http://www.statoids.com/tconcept.html">Basic Time
+Zone Concepts</a> discusses terminological issues behind time zones.</li>
+</ul>
+<h2>National histories of legal time</h2>
+<dl>
+<dt>Australia</dt>
+<dd>The Community Relations Division of the New South Wales (NSW)
+Attorney General's Department maintains a <a
+href="http://www.lawlink.nsw.gov.au/crd.nsf/pages/time2">history of
+daylight saving in NSW</a>.</dd>
+<dt>Austria</dt>
+<dd>The Federal Office of Metrology and Surveying publishes a
+table of <a href="http://www.metrologie.at/pdf/sommerzeit.pdf"
+hreflang="de">daylight saving time in Austria (in German)</a>.</dd>
+<dt>Belgium</dt>
+<dd>The Royal Observatory of Belgium maintains a table of <a
+href="http://www.astro.oma.be/GENERAL/INFO/nli001a.html"
+hreflang="nl">time in Belgium (in Dutch)</a>.</dd>
+<dt>Brazil</dt>
+<dd>The Time Service Department of the National Observatory
+records <a href="http://pcdsh01.on.br/DecHV.html"
+hreflang="pt-BR">Brazil's daylight saving time decrees (in
+Portuguese)</a>.</dd>
+<dt>Canada</dt>
+<dd>The Institute for National Measurement Standards publishes current
+and some older information about <a
+href="http://inms-ienm.nrc-cnrc.gc.ca/time_services/daylight_savings_e.html">Time
+Zones and Daylight Saving Time</a>.</dd>
+<dt>Chile</dt>
+<dd>WebExhibits publishes a <a
+href="http://webexhibits.org/daylightsaving/chile.html"
+hreflang="es">history of official time (in Spanish)</a> originally
+written by the Chilean Hydrographic and Oceanographic Service.</dd>
+<dt>Germany</dt>
+<dd>The National Institute for Science and Technology maintains the <a
+href="http://www.ptb.de/en/org/4/44/441/dars_e.htm">Realisation of
+Legal Time in Germany</a>.</dd>
+<dt>Israel</dt>
+<dd>The Interior Ministry periodically issues <a
+href="ftp://ftp.cs.huji.ac.il/pub/tz/announcements/"
+hreflang="he">announcements (in Hebrew)</a>.</dd>
+<dt>Mexico</dt>
+<dd>The Investigation and Analysis Service of the Mexican Library of
+Congress has published a <a
+href="http://www.cddhcu.gob.mx/bibliot/publica/inveyana/polisoc/horver/"
+hreflang="es">history of Mexican local time (in Spanish)</a>.</dd>
+<dt>Malaysia</dt>
+<dd>See Singapore below.</dd>
+<dt>Netherlands</dt>
+<dd><a href="http://www.phys.uu.nl/~vgent/wettijd/wettijd.htm"
+hreflang="nl">Legal time in the Netherlands (in Dutch)</a>
+covers the history of local time in the Netherlands from ancient times.</dd>
+<dt>New Zealand</dt>
+<dd>The Department of Internal Affairs maintains a brief history <a
+href="http://www.dia.govt.nz/diawebsite.nsf/wpg_URL/Resource-material-Information-We-Provide-About-Daylight-Saving">about
+daylight saving</a>. The privately-maintained <a
+href="http://www.astrologyhouse.co.nz/timechanges.htm">Time Changes in
+New Zealand</a> has more details.</dd>
+<dt>Singapore</dt>
+<dd><a
+href="http://www.math.nus.edu.sg/aslaksen/teaching/timezone.html">Why
+is Singapore in the "Wrong" Time Zone?</a> details the
+history of legal time in Singapore and Malaysia.</dd>
+<dt>United Kingdom</dt>
+<dd><a
+href="http://www.srcf.ucam.org/~jsm28/british-time/">History of
+legal time in Britain</a> discusses in detail the country
+with perhaps the best-documented history of clock adjustments.
+The National Physical Laboratory also maintains an <a
+href="http://www.npl.co.uk/time/summer_time_archive.html">archive
+of summer time dates</a>.</dd>
+</dl>
+<h2>Precision timekeeping</h2>
+<ul>
+<li><a
+href="http://literature.agilent.com/litwebbin/purl.cgi?org_id=tmo&amp;pub_id=5965-7984E">The
+Science of Timekeeping</a> is a thorough introduction
+to the theory and practice of precision timekeeping.</li>
+<li><a href="http://www.ntp.org/">NTP: The Network Time Protocol</a>
+discusses how to synchronize clocks of
+Internet hosts.</li>
+<li><a href="http://gauss.gge.unb.ca/GMT.UT.and.the.RGO.txt"
+charset="macintosh">A
+Few Facts Concerning GMT, UT, and the RGO</a>
+answers questions like "What is the difference between GMT and UTC?"</li>
+<li><a
+href="http://www.gb.nrao.edu/~rfisher/Ephemerides/times.html">Astronomical
+Times</a> explains more abstruse astronomical time scales like TT, TCG,
+and TDB.</li>
+<li>The <a href="http://www.iau.org/">IAU</a>'s <a
+href="http://www.iau-sofa.rl.ac.uk/">Standards Of Fundamental
+Astronomy</a> (SOFA) initiative publishes Fortran code for converting
+among time scales like TAI, TDB, TT and UTC.</li>
+<li><a href="http://www.jpl.nasa.gov/basics/bsf2-3.htm">Basics of
+Space Flight - Reference Systems - Time Conventions</a>
+briefly explains interplanetary space flight timekeeping.</li>
+<li><a
+href="http://www.giss.nasa.gov/tools/mars24/help/notes.html">Technical
+Notes on Mars Solar Time as Adopted by the Mars24 Sunclock</a> briefly
+describes Mars Coordinated Time (MTC) and the diverse local time
+scales used by each landed mission on Mars.</li>
+<li><a
+href="http://hpiers.obspm.fr/eop-pc/products/bulletins/bulletins.html">Bulletins
+maintained by the IERS EOP (PC)</a> contains official publications of
+the Earth Orientation Parameters Product Center of the
+International Earth Rotation Service, the committee that decides
+when leap seconds occur.</li>
+<li>The <a
+href="http://www.mail-archive.com/leapsecs@rom.usno.navy.mil/">Leap
+Second Discussion List</a> covers McCarthy and Klepczynski's proposal
+to discontinue leap seconds, published in <a
+href="http://www.gpsworld.com/">GPS World</a> <strong>10</strong>, 11
+(1999-11), 50&ndash;57 and discussed further in R. A. Nelson et al.,
+<a href="http://www.cl.cam.ac.uk/~mgk25/time/metrologia-leapsecond.pdf">The
+leap second: its history and possible future</a>,
+<a href="http://www.bipm.fr/metrologia/metrologia.html">Metrologia</a>
+<strong>38</strong> (2001), 509&ndash;529.
+<a href="http://www.ucolick.org/~sla/leapsecs/onlinebib.html">The
+Future of Leap Seconds</a> catalogs information about this
+contentious issue.</li>
+</ul>
+<h2>Time notation</h2>
+<ul>
+<li>
+<a href="http://www.cl.cam.ac.uk/~mgk25/iso-time.html">A Summary of
+the International Standard Date and Time Notation</a> is a good
+summary of ISO
+8601:1988 - Data elements and interchange formats - Information interchange
+- Representation of dates and times (which has been superseded by
+<a href="http://www.iso.org/iso/en/CatalogueDetailPage.CatalogueDetail?CSNUMBER=26780">ISO 8601:2000</a>).</li>
+<li>
+Section 3.3 of <a
+href="ftp://ftp.rfc-editor.org/in-notes/rfc2822.txt">Internet RFC 2822</a>
+specifies the time notation used in email and <a
+href="ftp://ftp.rfc-editor.org/in-notes/rfc2616.txt">HTTP</a> headers.</li>
+<li>
+<a href="ftp://ftp.rfc-editor.org/in-notes/rfc3339.txt">Internet RFC
+3339</a> specifies an ISO 8601 profile for use in new Internet
+protocols.</li>
+<li>
+<a href="http://www.exit109.com/~ghealton/y2k/yrexamples.html">The
+Best of Dates, the Worst of Dates</a> covers many problems encountered
+by software developers when handling dates and time stamps.</li>
+<li>
+Alphabetic time zone abbreviations should not be used as unique
+identifiers for UTC offsets as they are ambiguous in practice. For
+example, "EST" denotes 5 hours behind UTC in English-speaking North
+America, but it denotes 10 or 11 hours ahead of UTC in Australia;
+and French-speaking North Americans prefer "HNE" to "EST". For
+compatibility with <a href="http://www.pasc.org/#POSIX">POSIX</a> the
+<code>tz</code> database contains English abbreviations for all time
+stamps but in many cases these are merely inventions of the database
+maintainers.</li>
+</ul>
+<h2>Related indexes</h2>
+<ul>
+<li><a href="tz-art.htm">Time and the Arts</a></li>
+<li><a href="http://dmoz.org/Reference/Time/">Open Directory -
+Reference: Time</a></li>
+<li><a href="http://directory.google.com/Top/Reference/Time/">Google Directory - Reference &gt; Time</a></li>
+<li><a href="http://dir.yahoo.com/Science/Measurements_and_Units/Time/">Yahoo! Science &gt; Measurements and Units &gt; Time</a></li>
+</ul>
+</body>
+</html>
diff --git a/system_cmds/zic.tproj/tzfile.h b/system_cmds/zic.tproj/tzfile.h
new file mode 100644
index 0000000..ec4009b
--- /dev/null
+++ b/system_cmds/zic.tproj/tzfile.h
@@ -0,0 +1,192 @@
+#ifndef TZFILE_H
+#define TZFILE_H
+
+
+/*
+** This file is in the public domain, so clarified as of
+** 1996-06-05 by Arthur David Olson.
+**
+** $FreeBSD: head/contrib/tzcode/stdtime/tzfile.h 192625 2009-05-23 06:31:50Z edwin $
+*/
+
+/*
+** This header is for use ONLY with the time conversion code.
+** There is no guarantee that it will remain unchanged,
+** or that it will remain at all.
+** Do NOT copy it to any system include directory.
+** Thank you!
+*/
+
+/*
+** ID
+*/
+
+#ifndef lint
+#ifndef NOID
+/*
+static char tzfilehid[] = "@(#)tzfile.h 8.1";
+*/
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** Information about time zone files.
+*/
+
+#ifndef TZDIR
+#ifdef UNIFDEF_TZDIR_SYMLINK
+#define TZDIR "/var/db/timezone/zoneinfo" /* Time zone object file directory */
+#else /* !UNIFDEF_TZDIR_SYMLINK */
+#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
+#endif /* UNIFDEF_TZDIR_SYMLINK */
+#endif /* !defined TZDIR */
+
+#ifndef TZDEFAULT
+#ifdef UNIFDEF_MOVE_LOCALTIME
+#define TZDEFAULT "/var/db/timezone/localtime"
+#else /* !UNIFDEF_MOVE_LOCALTIME */
+#define TZDEFAULT "/etc/localtime"
+#endif /* UNIFDEF_MOVE_LOCALTIME */
+#endif /* !defined TZDEFAULT */
+
+#ifndef TZDEFRULES
+#define TZDEFRULES "posixrules"
+#endif /* !defined TZDEFRULES */
+
+/*
+** Each file begins with. . .
+*/
+
+#define TZ_MAGIC "TZif"
+
+struct tzhead {
+ char tzh_magic[4]; /* TZ_MAGIC */
+ char tzh_version[1]; /* '\0' or '2' as of 2005 */
+ char tzh_reserved[15]; /* reserved--must be zero */
+ char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */
+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ char tzh_leapcnt[4]; /* coded number of leap seconds */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
+};
+
+/*
+** . . .followed by. . .
+**
+** tzh_timecnt (char [4])s coded transition times a la time(2)
+** tzh_timecnt (unsigned char)s types of local time starting at above
+** tzh_typecnt repetitions of
+** one (char [4]) coded UTC offset in seconds
+** one (unsigned char) used to set tm_isdst
+** one (unsigned char) that's an abbreviation list index
+** tzh_charcnt (char)s '\0'-terminated zone abbreviations
+** tzh_leapcnt repetitions of
+** one (char [4]) coded leap second transition times
+** one (char [4]) total correction after above
+** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
+** time is standard time, if FALSE,
+** transition time is wall clock time
+** if absent, transition times are
+** assumed to be wall clock time
+** tzh_ttisgmtcnt (char)s indexed by type; if TRUE, transition
+** time is UTC, if FALSE,
+** transition time is local time
+** if absent, transition times are
+** assumed to be local time
+*/
+
+/*
+** If tzh_version is '2' or greater, the above is followed by a second instance
+** of tzhead and a second instance of the data in which each coded transition
+** time uses 8 rather than 4 chars,
+** then a POSIX-TZ-environment-variable-style string for use in handling
+** instants after the last transition time stored in the file
+** (with nothing between the newlines if there is no POSIX representation for
+** such instants).
+*/
+
+/*
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
+*/
+
+#ifndef TZ_MAX_TIMES
+#define TZ_MAX_TIMES 1200
+#endif /* !defined TZ_MAX_TIMES */
+
+#ifndef TZ_MAX_TYPES
+#ifndef NOSOLAR
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+#endif /* !defined NOSOLAR */
+#ifdef NOSOLAR
+/*
+** Must be at least 14 for Europe/Riga as of Jan 12 1995,
+** as noted by Earl Chew.
+*/
+#define TZ_MAX_TYPES 20 /* Maximum number of local time types */
+#endif /* !defined NOSOLAR */
+#endif /* !defined TZ_MAX_TYPES */
+
+#ifndef TZ_MAX_CHARS
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+ /* (limited by what unsigned chars can hold) */
+#endif /* !defined TZ_MAX_CHARS */
+
+#ifndef TZ_MAX_LEAPS
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+#endif /* !defined TZ_MAX_LEAPS */
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define TM_SUNDAY 0
+#define TM_MONDAY 1
+#define TM_TUESDAY 2
+#define TM_WEDNESDAY 3
+#define TM_THURSDAY 4
+#define TM_FRIDAY 5
+#define TM_SATURDAY 6
+
+#define TM_JANUARY 0
+#define TM_FEBRUARY 1
+#define TM_MARCH 2
+#define TM_APRIL 3
+#define TM_MAY 4
+#define TM_JUNE 5
+#define TM_JULY 6
+#define TM_AUGUST 7
+#define TM_SEPTEMBER 8
+#define TM_OCTOBER 9
+#define TM_NOVEMBER 10
+#define TM_DECEMBER 11
+
+#define TM_YEAR_BASE 1900
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+
+/*
+** Since everything in isleap is modulo 400 (or a factor of 400), we know that
+** isleap(y) == isleap(y % 400)
+** and so
+** isleap(a + b) == isleap((a + b) % 400)
+** or
+** isleap(a + b) == isleap(a % 400 + b % 400)
+** This is true even if % means modulo rather than Fortran remainder
+** (which is allowed by C89 but not C99).
+** We use this to avoid addition overflow problems.
+*/
+
+#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
+
+#endif /* !defined TZFILE_H */
diff --git a/system_cmds/zic.tproj/zic.8 b/system_cmds/zic.tproj/zic.8
new file mode 100644
index 0000000..a84e563
--- /dev/null
+++ b/system_cmds/zic.tproj/zic.8
@@ -0,0 +1,468 @@
+.\" $FreeBSD: head/contrib/tzcode/zic/zic.8 214411 2010-10-27 07:14:46Z edwin $
+.Dd June 20, 2004
+.Dt ZIC 8
+.Os
+.Sh NAME
+.Nm zic
+.Nd timezone compiler
+.Sh SYNOPSIS
+.Nm
+.Op Fl -version
+.Op Fl Dsv
+.Op Fl d Ar directory
+.Op Fl g Ar group
+.Op Fl L Ar leapsecondfilename
+.Op Fl l Ar localtime
+.Op Fl m Ar mode
+.Op Fl p Ar posixrules
+.Op Fl u Ar user
+.Op Fl y Ar command
+.Op Ar filename ...
+.Sh DESCRIPTION
+The
+.Nm
+utility reads text from the file(s) named on the command line
+and creates the time conversion information files specified in this input.
+If a
+.Ar filename
+is
+.Em - ,
+the standard input is read.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl -version
+Output version information and exit.
+.It Fl D
+Do not automatically create directories.
+If the input file(s) specify
+an output file in a directory which does not already exist, the
+default behavior is to attempt to create the directory.
+If
+.Fl D
+is specified,
+.Nm
+will instead error out immediately.
+.It Fl d Ar directory
+Create time conversion information files in the named directory rather than
+in the standard directory named below.
+.It Fl g Ar group
+After creating each output file, change its group ownership to the
+specified
+.Ar group
+(which can be either a name or a numeric group ID).
+.It Fl L Ar leapsecondfilename
+Read leap second information from the file with the given name.
+If this option is not used,
+no leap second information appears in output files.
+.It Fl l Ar timezone
+Use the given
+.Ar time zone
+as local time.
+The
+.Nm
+utility will act as if the input contained a link line of the form
+.Pp
+.D1 No "Link timezone localtime"
+.Pp
+(Note that this action has no effect on
+.Fx ,
+since the local time zone is specified in
+.Pa /etc/localtime
+and not
+.Pa /usr/share/zoneinfo/localtime . )
+.It Fl m Ar mode
+After creating each output file, change its access mode to
+.Ar mode .
+Both numeric and alphabetic modes are accepted
+(see
+.Xr chmod 1 ) .
+.It Fl p Ar timezone
+Use the given
+.Ar "time zone" Ns 's
+rules when handling POSIX-format
+time zone environment variables.
+The
+.Nm
+utility will act as if the input contained a link line of the form
+.Pp
+.D1 No "Link timezone posixrules"
+.It Fl u Ar user
+After creating each output file, change its owner to
+.Ar user
+(which can be either a name or a numeric user ID).
+.It Fl v
+Complain if a year that appears in a data file is outside the range
+of years representable by
+.Xr time 3
+values.
+.It Fl s
+Limit time values stored in output files to values that are the same
+whether they are taken to be signed or unsigned.
+You can use this option to generate SVVS-compatible files.
+.It Fl y Ar command
+Use the given
+.Ar command
+rather than
+.Em yearistype
+when checking year types (see below).
+.El
+.Pp
+Input lines are made up of fields.
+Fields are separated from one another by any number of white space characters.
+Leading and trailing white space on input lines is ignored.
+An unquoted sharp character (#) in the input introduces a comment which extends
+to the end of the line the sharp character appears on.
+White space characters and sharp characters may be enclosed in double quotes
+(") if they are to be used as part of a field.
+Any line that is blank (after comment stripping) is ignored.
+Non-blank lines are expected to be of one of three types:
+rule lines, zone lines, and link lines.
+.Pp
+Names (such as month names) must be in English and are case insensitive.
+Abbreviations, if used, must be unambiguous in context.
+.Pp
+A rule line has the form:
+.Dl "Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S"
+For example:
+.Dl "Rule US 1967 1973 \- Apr lastSun 2:00 1:00 D"
+.Pp
+The fields that make up a rule line are:
+.Bl -tag -width "LETTER/S" -offset indent
+.It NAME
+Give the (arbitrary) name of the set of rules this rule is part of.
+.It FROM
+Give the first year in which the rule applies.
+Any integer year can be supplied; the Gregorian calendar is assumed.
+The word
+.Em minimum
+(or an abbreviation) means the minimum year representable as an integer.
+The word
+.Em maximum
+(or an abbreviation) means the maximum year representable as an integer.
+Rules can describe times that are not representable as time values,
+with the unrepresentable times ignored; this allows rules to be portable
+among hosts with differing time value types.
+.It TO
+Give the final year in which the rule applies.
+In addition to
+.Em minimum
+and
+.Em maximum
+(as above),
+the word
+.Em only
+(or an abbreviation)
+may be used to repeat the value of the
+.Em FROM
+field.
+.It TYPE
+Give the type of year in which the rule applies.
+If
+.Em TYPE
+is
+.Em \-
+then the rule applies in all years between
+.Em FROM
+and
+.Em TO
+inclusive.
+If
+.Em TYPE
+is something else, then
+.Nm
+executes the command
+.Li yearistype Ar year Ar type
+to check the type of a year:
+an exit status of zero is taken to mean that the year is of the given type;
+an exit status of one is taken to mean that the year is not of the given type.
+.It IN
+Name the month in which the rule takes effect.
+Month names may be abbreviated.
+.It ON
+Give the day on which the rule takes effect.
+Recognized forms include:
+.Pp
+.Bl -tag -width lastSun -compact -offset indent
+.It \&5
+the fifth of the month
+.It lastSun
+the last Sunday in the month
+.It lastMon
+the last Monday in the month
+.It Sun>=8
+first Sunday on or after the eighth
+.It Sun<=25
+last Sunday on or before the 25th
+.El
+.Pp
+Names of days of the week may be abbreviated or spelled out in full.
+Note that there must be no spaces within the
+.Em ON
+field.
+.It AT
+Give the time of day at which the rule takes effect.
+Recognized forms include:
+.Pp
+.Bl -tag -width "\&1:28:14" -offset indent -compact
+.It 2
+time in hours
+.It 2:00
+time in hours and minutes
+.It 15:00
+24-hour format time (for times after noon)
+.It 1:28:14
+time in hours, minutes, and seconds
+.El
+.Pp
+where hour 0 is midnight at the start of the day,
+and hour 24 is midnight at the end of the day.
+Any of these forms may be followed by the letter
+.Sq Li w
+if the given time is local
+.Dq "wall clock"
+time,
+.Sq Li s
+if the given time is local
+.Dq standard
+time, or
+.Sq Li u
+(or
+.Sq Li g
+or
+.Sq Li z )
+if the given time is universal time;
+in the absence of an indicator,
+wall clock time is assumed.
+.It SAVE
+Give the amount of time to be added to local standard time when the rule is in
+effect.
+This field has the same format as the
+.Em AT
+field
+(although, of course, the
+.Sq Li w
+and
+.Sq Li s
+suffixes are not used).
+.It LETTER/S
+Give the
+.Dq "variable part"
+(for example, the
+.Dq S
+or
+.Dq D
+in
+.Dq EST
+or
+.Dq EDT )
+of time zone abbreviations to be used when this rule is in effect.
+If this field is
+.Em \- ,
+the variable part is null.
+.El
+.Pp
+A zone line has the form:
+.Dl "Zone NAME GMTOFF RULES/SAVE FORMAT [UNTILYEAR [MONTH [DAY [TIME]]]]"
+For example:
+.Dl "Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00"
+The fields that make up a zone line are:
+.Bl -tag -width indent
+.It NAME
+The name of the time zone.
+This is the name used in creating the time conversion information file for the
+zone.
+.It GMTOFF
+The amount of time to add to UTC to get standard time in this zone.
+This field has the same format as the
+.Em AT
+and
+.Em SAVE
+fields of rule lines;
+begin the field with a minus sign if time must be subtracted from UTC.
+.It RULES/SAVE
+The name of the rule(s) that apply in the time zone or,
+alternately, an amount of time to add to local standard time.
+If this field is
+.Em \-
+then standard time always applies in the time zone.
+.It FORMAT
+The format for time zone abbreviations in this time zone.
+The pair of characters
+.Em %s
+is used to show where the
+.Dq "variable part"
+of the time zone abbreviation goes.
+Alternately,
+a slash (/)
+separates standard and daylight abbreviations.
+.It UNTILYEAR [MONTH [DAY [TIME]]]
+The time at which the UTC offset or the rule(s) change for a location.
+It is specified as a year, a month, a day, and a time of day.
+If this is specified,
+the time zone information is generated from the given UTC offset
+and rule change until the time specified.
+The month, day, and time of day have the same format as the IN, ON, and AT
+fields of a rule; trailing fields can be omitted, and default to the
+earliest possible value for the missing fields.
+.Pp
+The next line must be a
+.Dq continuation
+line; this has the same form as a zone line except that the
+string
+.Dq Zone
+and the name are omitted, as the continuation line will
+place information starting at the time specified as the
+.Em until
+information in the previous line in the file used by the previous line.
+Continuation lines may contain
+.Em until
+information, just as zone lines do, indicating that the next line is a further
+continuation.
+.El
+.Pp
+A link line has the form
+.Dl "Link LINK-FROM LINK-TO"
+For example:
+.Dl "Link Europe/Istanbul Asia/Istanbul"
+The
+.Em LINK-FROM
+field should appear as the
+.Em NAME
+field in some zone line;
+the
+.Em LINK-TO
+field is used as an alternate name for that zone.
+.Pp
+Except for continuation lines,
+lines may appear in any order in the input.
+.Pp
+Lines in the file that describes leap seconds have the following form:
+.Dl "Leap YEAR MONTH DAY HH:MM:SS CORR R/S"
+For example:
+.Dl "Leap 1974 Dec 31 23:59:60 + S"
+The
+.Em YEAR ,
+.Em MONTH ,
+.Em DAY ,
+and
+.Em HH:MM:SS
+fields tell when the leap second happened.
+The
+.Em CORR
+field
+should be
+.Dq +
+if a second was added
+or
+.Dq -
+if a second was skipped.
+.\" There's no need to document the following, since it's impossible for more
+.\" than one leap second to be inserted or deleted at a time.
+.\" The C Standard is in error in suggesting the possibility.
+.\" See Terry J Quinn, The BIPM and the accurate measure of time,
+.\" Proc IEEE 79, 7 (July 1991), 894-905.
+.\" or
+.\" .q ++
+.\" if two seconds were added
+.\" or
+.\" .q --
+.\" if two seconds were skipped.
+The
+.Em R/S
+field
+should be (an abbreviation of)
+.Dq Stationary
+if the leap second time given by the other fields should be interpreted as UTC
+or
+(an abbreviation of)
+.Dq Rolling
+if the leap second time given by the other fields should be interpreted as
+local wall clock time.
+.Sh "EXTENDED EXAMPLE"
+Here is an extended example of
+.Nm
+input, intended to illustrate many of its features.
+.br
+.ne 22
+.nf
+.in +2m
+.ta \w'# Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'TYPE\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u
+.sp
+# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+Rule Swiss 1940 only - Nov 2 0:00 1:00 S
+Rule Swiss 1940 only - Dec 31 0:00 0 -
+Rule Swiss 1941 1942 - May Sun>=1 2:00 1:00 S
+Rule Swiss 1941 1942 - Oct Sun>=1 0:00 0
+.sp .5
+Rule EU 1977 1980 - Apr Sun>=1 1:00u 1:00 S
+Rule EU 1977 only - Sep lastSun 1:00u 0 -
+Rule EU 1978 only - Oct 1 1:00u 0 -
+Rule EU 1979 1995 - Sep lastSun 1:00u 0 -
+Rule EU 1981 max - Mar lastSun 1:00u 1:00 S
+Rule EU 1996 max - Oct lastSun 1:00u 0 -
+.sp
+.ta \w'# Zone\0\0'u +\w'Europe/Zurich\0\0'u +\w'0:34:08\0\0'u +\w'RULES/SAVE\0\0'u +\w'FORMAT\0\0'u
+# Zone NAME GMTOFF RULES FORMAT UNTIL
+Zone Europe/Zurich 0:34:08 - LMT 1848 Sep 12
+ 0:29:44 - BMT 1894 Jun
+ 1:00 Swiss CE%sT 1981
+ 1:00 EU CE%sT
+.sp
+Link Europe/Zurich Switzerland
+.sp
+.in
+.fi
+In this example, the zone is named Europe/Zurich but it has an alias
+as Switzerland.
+Zurich was 34 minutes and 8 seconds west of GMT until 1848-09-12
+at 00:00, when the offset changed to 29 minutes and 44 seconds.
+After 1894-06-01 at 00:00 Swiss daylight saving rules (defined with
+lines beginning with "Rule Swiss") apply, and the GMT offset became
+one hour.
+From 1981 to the present, EU daylight saving rules have applied,
+and the UTC offset has remained at one hour.
+.Pp
+In 1940, daylight saving time applied from November 2 at 00:00 to
+December 31 at 00:00.
+In 1941 and 1942, daylight saving time applied from the first Sunday
+in May at 02:00 to the first Sunday in October at 00:00.
+The pre-1981 EU daylight-saving rules have no effect here, but are
+included for completeness.
+Since 1981, daylight saving has begun on the last Sunday in March
+at 01:00 UTC.
+Until 1995 it ended the last Sunday in September at 01:00 UTC, but
+this changed to the last Sunday in October starting in 1996.
+.Pp
+For purposes of display, "LMT" and "BMT" were initially used,
+respectively.
+Since Swiss rules and later EU rules were applied, the display name
+for the timezone has been CET for standard time and CEST for daylight
+saving time.
+.Sh NOTES
+For areas with more than two types of local time,
+you may need to use local standard time in the
+.Em AT
+field of the earliest transition time's rule to ensure that
+the earliest transition time recorded in the compiled file is correct.
+.Pp
+If, for a particular zone, a clock advance caused by the start of
+daylight saving coincides with and is equal to a clock retreat
+caused by a change in UTC offset,
+.Nm
+produces a single transition to daylight saving at the new UTC offset
+(without any change in wall clock time).
+To get separate transitions use multiple zone continuation lines
+specifying transition instants using universal time.
+.Sh FILES
+.Bl -tag -width /usr/share/zoneinfo -compact
+.It /usr/share/zoneinfo
+standard directory used for created files
+.El
+.Sh "SEE ALSO"
+.Xr ctime 3 ,
+.Xr tzfile 5 ,
+.Xr zdump 8
+.\" @(#)zic.8 8.6
+.\" This file is in the public domain, so clarified as of
+.\" 2009-05-17 by Arthur David Olson.
diff --git a/system_cmds/zic.tproj/zic.c b/system_cmds/zic.tproj/zic.c
new file mode 100644
index 0000000..75db5be
--- /dev/null
+++ b/system_cmds/zic.tproj/zic.c
@@ -0,0 +1,2770 @@
+/*
+** This file is in the public domain, so clarified as of
+** 2006-07-17 by Arthur David Olson.
+*/
+
+static const char elsieid[] = "@(#)zic.c 8.22";
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: head/contrib/tzcode/zic/zic.c 214411 2010-10-27 07:14:46Z edwin $";
+#endif /* not lint */
+
+#include "private.h"
+#include "tzfile.h"
+#include <err.h>
+#include <locale.h>
+#include <sys/stat.h> /* for umask manifest constants */
+#include <sys/types.h>
+#include <unistd.h>
+
+#define ZIC_VERSION '2'
+
+typedef int_fast64_t zic_t;
+
+#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
+#define ZIC_MAX_ABBR_LEN_WO_WARN 6
+#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
+
+#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
+
+/*
+** On some ancient hosts, predicates like `isspace(C)' are defined
+** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
+** which says they are defined only if C == ((unsigned char) C) || C == EOF.
+** Neither the C Standard nor POSIX require that `isascii' exist.
+** For portability, we check both ancient and modern requirements.
+** If isascii is not defined, the isascii check succeeds trivially.
+*/
+#include "ctype.h"
+#ifndef isascii
+#define isascii(x) 1
+#endif
+
+#define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
+#define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
+
+#define end(cp) (strchr((cp), '\0'))
+
+struct rule {
+ const char * r_filename;
+ int r_linenum;
+ const char * r_name;
+
+ int r_loyear; /* for example, 1986 */
+ int r_hiyear; /* for example, 1986 */
+ const char * r_yrtype;
+ int r_lowasnum;
+ int r_hiwasnum;
+
+ int r_month; /* 0..11 */
+
+ int r_dycode; /* see below */
+ int r_dayofmonth;
+ int r_wday;
+
+ long r_tod; /* time from midnight */
+ int r_todisstd; /* above is standard time if TRUE */
+ /* or wall clock time if FALSE */
+ int r_todisgmt; /* above is GMT if TRUE */
+ /* or local time if FALSE */
+ long r_stdoff; /* offset from standard time */
+ const char * r_abbrvar; /* variable part of abbreviation */
+
+ int r_todo; /* a rule to do (used in outzone) */
+ zic_t r_temp; /* used in outzone */
+};
+
+/*
+** r_dycode r_dayofmonth r_wday
+*/
+
+#define DC_DOM 0 /* 1..31 */ /* unused */
+#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
+#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
+
+struct zone {
+ const char * z_filename;
+ int z_linenum;
+
+ const char * z_name;
+ long z_gmtoff;
+ const char * z_rule;
+ const char * z_format;
+
+ long z_stdoff;
+
+ struct rule * z_rules;
+ int z_nrules;
+
+ struct rule z_untilrule;
+ zic_t z_untiltime;
+};
+
+static void addtt(zic_t starttime, int type);
+static int addtype(long gmtoff, const char * abbr, int isdst,
+ int ttisstd, int ttisgmt);
+static void leapadd(zic_t t, int positive, int rolling, int count);
+static void adjleap(void);
+static void associate(void);
+static int ciequal(const char * ap, const char * bp);
+static void convert(long val, char * buf);
+static void convert64(zic_t val, char * buf);
+static void dolink(const char * fromfield, const char * tofield);
+static void doabbr(char * abbr, const char * format,
+ const char * letters, int isdst, int doquotes);
+static void eat(const char * name, int num);
+static void eats(const char * name, int num,
+ const char * rname, int rnum);
+static long eitol(int i);
+static void error(const char * message);
+static char ** getfields(char * buf);
+static long gethms(const char * string, const char * errstrng,
+ int signable);
+static void infile(const char * filename);
+static void inleap(char ** fields, int nfields);
+static void inlink(char ** fields, int nfields);
+static void inrule(char ** fields, int nfields);
+static int inzcont(char ** fields, int nfields);
+static int inzone(char ** fields, int nfields);
+static int inzsub(char ** fields, int nfields, int iscont);
+static int is32(zic_t x);
+static int itsabbr(const char * abbr, const char * word);
+static int itsdir(const char * name);
+static int lowerit(int c);
+static char * memcheck(char * tocheck);
+static int mkdirs(char * filename);
+static void newabbr(const char * abbr);
+static long oadd(long t1, long t2);
+static void outzone(const struct zone * zp, int ntzones);
+static void puttzcode(long code, FILE * fp);
+static void puttzcode64(zic_t code, FILE * fp);
+static int rcomp(const void * leftp, const void * rightp);
+static zic_t rpytime(const struct rule * rp, int wantedy);
+static void rulesub(struct rule * rp,
+ const char * loyearp, const char * hiyearp,
+ const char * typep, const char * monthp,
+ const char * dayp, const char * timep);
+static int stringoffset(char * result, long offset);
+static int stringrule(char * result, const struct rule * rp,
+ long dstoff, long gmtoff);
+static void stringzone(char * result,
+ const struct zone * zp, int ntzones);
+static void setboundaries(void);
+static void setgroup(gid_t *flag, const char *name);
+static void setuser(uid_t *flag, const char *name);
+static zic_t tadd(zic_t t1, long t2);
+static void usage(FILE *stream, int status);
+static void writezone(const char * name, const char * string);
+static int yearistype(int year, const char * type);
+
+static int charcnt;
+static int errors;
+static const char * filename;
+static int leapcnt;
+static int leapseen;
+static int leapminyear;
+static int leapmaxyear;
+static int linenum;
+static int max_abbrvar_len;
+static int max_format_len;
+static zic_t max_time;
+static int max_year;
+static zic_t min_time;
+static int min_year;
+static zic_t min_time;
+static int noise;
+static const char * rfilename;
+static int rlinenum;
+static int timecnt;
+static int typecnt;
+
+/*
+** Line codes.
+*/
+
+#define LC_RULE 0
+#define LC_ZONE 1
+#define LC_LINK 2
+#define LC_LEAP 3
+
+/*
+** Which fields are which on a Zone line.
+*/
+
+#define ZF_NAME 1
+#define ZF_GMTOFF 2
+#define ZF_RULE 3
+#define ZF_FORMAT 4
+#define ZF_TILYEAR 5
+#define ZF_TILMONTH 6
+#define ZF_TILDAY 7
+#define ZF_TILTIME 8
+#define ZONE_MINFIELDS 5
+#define ZONE_MAXFIELDS 9
+
+/*
+** Which fields are which on a Zone continuation line.
+*/
+
+#define ZFC_GMTOFF 0
+#define ZFC_RULE 1
+#define ZFC_FORMAT 2
+#define ZFC_TILYEAR 3
+#define ZFC_TILMONTH 4
+#define ZFC_TILDAY 5
+#define ZFC_TILTIME 6
+#define ZONEC_MINFIELDS 3
+#define ZONEC_MAXFIELDS 7
+
+/*
+** Which files are which on a Rule line.
+*/
+
+#define RF_NAME 1
+#define RF_LOYEAR 2
+#define RF_HIYEAR 3
+#define RF_COMMAND 4
+#define RF_MONTH 5
+#define RF_DAY 6
+#define RF_TOD 7
+#define RF_STDOFF 8
+#define RF_ABBRVAR 9
+#define RULE_FIELDS 10
+
+/*
+** Which fields are which on a Link line.
+*/
+
+#define LF_FROM 1
+#define LF_TO 2
+#define LINK_FIELDS 3
+
+/*
+** Which fields are which on a Leap line.
+*/
+
+#define LP_YEAR 1
+#define LP_MONTH 2
+#define LP_DAY 3
+#define LP_TIME 4
+#define LP_CORR 5
+#define LP_ROLL 6
+#define LEAP_FIELDS 7
+
+/*
+** Year synonyms.
+*/
+
+#define YR_MINIMUM 0
+#define YR_MAXIMUM 1
+#define YR_ONLY 2
+
+static struct rule * rules;
+static int nrules; /* number of rules */
+
+static struct zone * zones;
+static int nzones; /* number of zones */
+
+struct link {
+ const char * l_filename;
+ int l_linenum;
+ const char * l_from;
+ const char * l_to;
+};
+
+static struct link * links;
+static int nlinks;
+
+struct lookup {
+ const char * l_word;
+ const int l_value;
+};
+
+static struct lookup const * byword(const char * string,
+ const struct lookup * lp);
+
+static struct lookup const line_codes[] = {
+ { "Rule", LC_RULE },
+ { "Zone", LC_ZONE },
+ { "Link", LC_LINK },
+ { "Leap", LC_LEAP },
+ { NULL, 0}
+};
+
+static struct lookup const mon_names[] = {
+ { "January", TM_JANUARY },
+ { "February", TM_FEBRUARY },
+ { "March", TM_MARCH },
+ { "April", TM_APRIL },
+ { "May", TM_MAY },
+ { "June", TM_JUNE },
+ { "July", TM_JULY },
+ { "August", TM_AUGUST },
+ { "September", TM_SEPTEMBER },
+ { "October", TM_OCTOBER },
+ { "November", TM_NOVEMBER },
+ { "December", TM_DECEMBER },
+ { NULL, 0 }
+};
+
+static struct lookup const wday_names[] = {
+ { "Sunday", TM_SUNDAY },
+ { "Monday", TM_MONDAY },
+ { "Tuesday", TM_TUESDAY },
+ { "Wednesday", TM_WEDNESDAY },
+ { "Thursday", TM_THURSDAY },
+ { "Friday", TM_FRIDAY },
+ { "Saturday", TM_SATURDAY },
+ { NULL, 0 }
+};
+
+static struct lookup const lasts[] = {
+ { "last-Sunday", TM_SUNDAY },
+ { "last-Monday", TM_MONDAY },
+ { "last-Tuesday", TM_TUESDAY },
+ { "last-Wednesday", TM_WEDNESDAY },
+ { "last-Thursday", TM_THURSDAY },
+ { "last-Friday", TM_FRIDAY },
+ { "last-Saturday", TM_SATURDAY },
+ { NULL, 0 }
+};
+
+static struct lookup const begin_years[] = {
+ { "minimum", YR_MINIMUM },
+ { "maximum", YR_MAXIMUM },
+ { NULL, 0 }
+};
+
+static struct lookup const end_years[] = {
+ { "minimum", YR_MINIMUM },
+ { "maximum", YR_MAXIMUM },
+ { "only", YR_ONLY },
+ { NULL, 0 }
+};
+
+static struct lookup const leap_types[] = {
+ { "Rolling", TRUE },
+ { "Stationary", FALSE },
+ { NULL, 0 }
+};
+
+static const int len_months[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int len_years[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+static struct attype {
+ zic_t at;
+ unsigned char type;
+} attypes[TZ_MAX_TIMES];
+static long gmtoffs[TZ_MAX_TYPES];
+static char isdsts[TZ_MAX_TYPES];
+static unsigned char abbrinds[TZ_MAX_TYPES];
+static char ttisstds[TZ_MAX_TYPES];
+static char ttisgmts[TZ_MAX_TYPES];
+static char chars[TZ_MAX_CHARS];
+static zic_t trans[TZ_MAX_LEAPS];
+static long corr[TZ_MAX_LEAPS];
+static char roll[TZ_MAX_LEAPS];
+
+/*
+** Memory allocation.
+*/
+
+static char *
+memcheck(ptr)
+char * const ptr;
+{
+ if (ptr == NULL)
+ errx(EXIT_FAILURE, _("memory exhausted"));
+ return ptr;
+}
+
+#define emalloc(size) memcheck(imalloc(size))
+#define erealloc(ptr, size) memcheck(irealloc((ptr), (size)))
+#define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
+#define ecatalloc(oldp, newp) memcheck(icatalloc((oldp), (newp)))
+
+/*
+** Error handling.
+*/
+
+static void
+eats(name, num, rname, rnum)
+const char * const name;
+const int num;
+const char * const rname;
+const int rnum;
+{
+ filename = name;
+ linenum = num;
+ rfilename = rname;
+ rlinenum = rnum;
+}
+
+static void
+eat(name, num)
+const char * const name;
+const int num;
+{
+ eats(name, num, (char *) NULL, -1);
+}
+
+static void
+error(string)
+const char * const string;
+{
+ /*
+ ** Match the format of "cc" to allow sh users to
+ ** zic ... 2>&1 | error -t "*" -v
+ ** on BSD systems.
+ */
+ (void) fprintf(stderr, _("\"%s\", line %d: %s"),
+ filename, linenum, string);
+ if (rfilename != NULL)
+ (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
+ rfilename, rlinenum);
+ (void) fprintf(stderr, "\n");
+ ++errors;
+}
+
+static void
+warning(string)
+const char * const string;
+{
+ char * cp;
+
+ cp = ecpyalloc(_("warning: "));
+ cp = ecatalloc(cp, string);
+ error(cp);
+ ifree(cp);
+ --errors;
+}
+
+static void
+usage(FILE *stream, int status)
+ {
+ (void) fprintf(stream, _("usage is zic \
+[ --version ] [--help] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
+\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
+\n\
+Report bugs to tz@elsie.nci.nih.gov.\n"));
+ exit(status);
+}
+
+static const char * psxrules;
+static const char * lcltime;
+static const char * directory;
+static const char * leapsec;
+static const char * yitcommand;
+static int Dflag;
+static uid_t uflag = (uid_t)-1;
+static gid_t gflag = (gid_t)-1;
+static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH
+ | S_IWUSR);
+
+int
+main(argc, argv)
+int argc;
+char * argv[];
+{
+ register int i;
+ register int j;
+ register int c;
+
+#ifdef unix
+ (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
+#endif /* defined unix */
+#if HAVE_GETTEXT
+ (void) setlocale(LC_ALL, "");
+#ifdef TZ_DOMAINDIR
+ (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
+#endif /* defined TEXTDOMAINDIR */
+ (void) textdomain(TZ_DOMAIN);
+#endif /* HAVE_GETTEXT */
+ if (TYPE_BIT(zic_t) < 64) {
+ (void) fprintf(stderr, "zic: %s\n",
+ _("wild compilation-time specification of zic_t"));
+ exit(EXIT_FAILURE);
+ }
+ for (i = 1; i < argc; ++i)
+ if (strcmp(argv[i], "--version") == 0) {
+ errx(EXIT_SUCCESS, "%s", elsieid);
+ } else if (strcmp(argv[i], "--help") == 0) {
+ usage(stdout, EXIT_SUCCESS);
+ }
+ while ((c = getopt(argc, argv, "Dd:g:l:m:p:L:u:vsy:")) != -1)
+ switch (c) {
+ default:
+ usage(stderr, EXIT_FAILURE);
+ case 'D':
+ Dflag = 1;
+ break;
+ case 'd':
+ if (directory == NULL)
+ directory = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -d option specified"));
+ break;
+ case 'g':
+ setgroup(&gflag, optarg);
+ break;
+ case 'l':
+ if (lcltime == NULL)
+ lcltime = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -l option specified"));
+ break;
+ case 'm':
+ {
+ void *set = setmode(optarg);
+ if (set == NULL)
+ errx(EXIT_FAILURE,
+_("invalid file mode"));
+ mflag = getmode(set, mflag);
+ free(set);
+ break;
+ }
+ case 'p':
+ if (psxrules == NULL)
+ psxrules = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -p option specified"));
+ break;
+ case 'u':
+ setuser(&uflag, optarg);
+ break;
+ case 'y':
+ if (yitcommand == NULL)
+ yitcommand = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -y option specified"));
+ break;
+ case 'L':
+ if (leapsec == NULL)
+ leapsec = optarg;
+ else
+ errx(EXIT_FAILURE,
+_("more than one -L option specified"));
+ break;
+ case 'v':
+ noise = TRUE;
+ break;
+ case 's':
+ (void) printf("zic: -s ignored\n");
+ break;
+ }
+ if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
+ usage(stderr, EXIT_FAILURE); /* usage message by request */
+ if (directory == NULL)
+ directory = TZDIR;
+ if (yitcommand == NULL)
+ yitcommand = "yearistype";
+
+ setboundaries();
+
+ if (optind < argc && leapsec != NULL) {
+ infile(leapsec);
+ adjleap();
+ }
+
+ for (i = optind; i < argc; ++i)
+ infile(argv[i]);
+ if (errors)
+ exit(EXIT_FAILURE);
+ associate();
+ for (i = 0; i < nzones; i = j) {
+ /*
+ ** Find the next non-continuation zone entry.
+ */
+ for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
+ continue;
+ outzone(&zones[i], j - i);
+ }
+ /*
+ ** Make links.
+ */
+ for (i = 0; i < nlinks; ++i) {
+ eat(links[i].l_filename, links[i].l_linenum);
+ dolink(links[i].l_from, links[i].l_to);
+ if (noise)
+ for (j = 0; j < nlinks; ++j)
+ if (strcmp(links[i].l_to,
+ links[j].l_from) == 0)
+ warning(_("link to link"));
+ }
+ if (lcltime != NULL) {
+ eat("command line", 1);
+ dolink(lcltime, TZDEFAULT);
+ }
+ if (psxrules != NULL) {
+ eat("command line", 1);
+ dolink(psxrules, TZDEFRULES);
+ }
+ return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static void
+dolink(fromfield, tofield)
+const char * const fromfield;
+const char * const tofield;
+{
+ register char * fromname;
+ register char * toname;
+
+ if (fromfield[0] == '/')
+ fromname = ecpyalloc(fromfield);
+ else {
+ fromname = ecpyalloc(directory);
+ fromname = ecatalloc(fromname, "/");
+ fromname = ecatalloc(fromname, fromfield);
+ }
+ if (tofield[0] == '/')
+ toname = ecpyalloc(tofield);
+ else {
+ toname = ecpyalloc(directory);
+ toname = ecatalloc(toname, "/");
+ toname = ecatalloc(toname, tofield);
+ }
+ /*
+ ** We get to be careful here since
+ ** there's a fair chance of root running us.
+ */
+ if (!itsdir(toname))
+ (void) remove(toname);
+ if (link(fromname, toname) != 0) {
+ int result;
+
+ if (mkdirs(toname) != 0)
+ exit(EXIT_FAILURE);
+
+ result = link(fromname, toname);
+#if HAVE_SYMLINK
+ if (result != 0 &&
+ access(fromname, F_OK) == 0 &&
+ !itsdir(fromname)) {
+ const char *s = tofield;
+ register char * symlinkcontents = NULL;
+ while ((s = strchr(s+1, '/')) != NULL)
+ symlinkcontents =
+ ecatalloc(symlinkcontents,
+ "../");
+ symlinkcontents =
+ ecatalloc(symlinkcontents,
+ fromname);
+ result =
+ symlink(symlinkcontents,
+ toname);
+ if (result == 0)
+warning(_("hard link failed, symbolic link used"));
+ ifree(symlinkcontents);
+ }
+#endif /* HAVE_SYMLINK */
+ if (result != 0) {
+ err(EXIT_FAILURE, _("can't link from %s to %s"),
+ fromname, toname);
+ }
+ }
+ ifree(fromname);
+ ifree(toname);
+}
+
+#define TIME_T_BITS_IN_FILE 64
+
+static void
+setboundaries (void)
+{
+ register int i;
+
+ min_time = -1;
+ for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
+ min_time *= 2;
+ max_time = -(min_time + 1);
+}
+
+static int
+itsdir(name)
+const char * const name;
+{
+ register char * myname;
+ register int accres;
+
+ myname = ecpyalloc(name);
+ myname = ecatalloc(myname, "/.");
+ accres = access(myname, F_OK);
+ ifree(myname);
+ return accres == 0;
+}
+
+/*
+** Associate sets of rules with zones.
+*/
+
+/*
+** Sort by rule name.
+*/
+
+static int
+rcomp(cp1, cp2)
+const void * cp1;
+const void * cp2;
+{
+ return strcmp(((const struct rule *) cp1)->r_name,
+ ((const struct rule *) cp2)->r_name);
+}
+
+static void
+associate(void)
+{
+ register struct zone * zp;
+ register struct rule * rp;
+ register int base, out;
+ register int i, j;
+
+ if (nrules != 0) {
+ (void) qsort((void *) rules, (size_t) nrules,
+ (size_t) sizeof *rules, rcomp);
+ for (i = 0; i < nrules - 1; ++i) {
+ if (strcmp(rules[i].r_name,
+ rules[i + 1].r_name) != 0)
+ continue;
+ if (strcmp(rules[i].r_filename,
+ rules[i + 1].r_filename) == 0)
+ continue;
+ eat(rules[i].r_filename, rules[i].r_linenum);
+ warning(_("same rule name in multiple files"));
+ eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
+ warning(_("same rule name in multiple files"));
+ for (j = i + 2; j < nrules; ++j) {
+ if (strcmp(rules[i].r_name,
+ rules[j].r_name) != 0)
+ break;
+ if (strcmp(rules[i].r_filename,
+ rules[j].r_filename) == 0)
+ continue;
+ if (strcmp(rules[i + 1].r_filename,
+ rules[j].r_filename) == 0)
+ continue;
+ break;
+ }
+ i = j - 1;
+ }
+ }
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ zp->z_rules = NULL;
+ zp->z_nrules = 0;
+ }
+ for (base = 0; base < nrules; base = out) {
+ rp = &rules[base];
+ for (out = base + 1; out < nrules; ++out)
+ if (strcmp(rp->r_name, rules[out].r_name) != 0)
+ break;
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ if (strcmp(zp->z_rule, rp->r_name) != 0)
+ continue;
+ zp->z_rules = rp;
+ zp->z_nrules = out - base;
+ }
+ }
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ if (zp->z_nrules == 0) {
+ /*
+ ** Maybe we have a local standard time offset.
+ */
+ eat(zp->z_filename, zp->z_linenum);
+ zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
+ TRUE);
+ /*
+ ** Note, though, that if there's no rule,
+ ** a '%s' in the format is a bad thing.
+ */
+ if (strchr(zp->z_format, '%') != 0)
+ error(_("%s in ruleless zone"));
+ }
+ }
+ if (errors)
+ exit(EXIT_FAILURE);
+}
+
+static void
+infile(name)
+const char * name;
+{
+ register FILE * fp;
+ register char ** fields;
+ register char * cp;
+ register const struct lookup * lp;
+ register int nfields;
+ register int wantcont;
+ register int num;
+ char buf[BUFSIZ];
+
+ if (strcmp(name, "-") == 0) {
+ name = _("standard input");
+ fp = stdin;
+ } else if ((fp = fopen(name, "r")) == NULL)
+ err(EXIT_FAILURE, _("can't open %s"), name);
+ wantcont = FALSE;
+ for (num = 1; ; ++num) {
+ eat(name, num);
+ if (fgets(buf, (int) sizeof buf, fp) != buf)
+ break;
+ cp = strchr(buf, '\n');
+ if (cp == NULL) {
+ error(_("line too long"));
+ exit(EXIT_FAILURE);
+ }
+ *cp = '\0';
+ fields = getfields(buf);
+ nfields = 0;
+ while (fields[nfields] != NULL) {
+ static char nada;
+
+ if (strcmp(fields[nfields], "-") == 0)
+ fields[nfields] = &nada;
+ ++nfields;
+ }
+ if (nfields == 0) {
+ /* nothing to do */
+ } else if (wantcont) {
+ wantcont = inzcont(fields, nfields);
+ } else {
+ lp = byword(fields[0], line_codes);
+ if (lp == NULL)
+ error(_("input line of unknown type"));
+ else switch ((int) (lp->l_value)) {
+ case LC_RULE:
+ inrule(fields, nfields);
+ wantcont = FALSE;
+ break;
+ case LC_ZONE:
+ wantcont = inzone(fields, nfields);
+ break;
+ case LC_LINK:
+ inlink(fields, nfields);
+ wantcont = FALSE;
+ break;
+ case LC_LEAP:
+ if (name != leapsec)
+ warnx(
+_("leap line in non leap seconds file %s"), name);
+ else inleap(fields, nfields);
+ wantcont = FALSE;
+ break;
+ default: /* "cannot happen" */
+ errx(EXIT_FAILURE,
+_("panic: invalid l_value %d"), lp->l_value);
+ }
+ }
+ ifree((char *) fields);
+ }
+ if (ferror(fp))
+ errx(EXIT_FAILURE, _("error reading %s"), filename);
+ if (fp != stdin && fclose(fp))
+ err(EXIT_FAILURE, _("error closing %s"), filename);
+ if (wantcont)
+ error(_("expected continuation line not found"));
+}
+
+/*
+** Convert a string of one of the forms
+** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
+** into a number of seconds.
+** A null string maps to zero.
+** Call error with errstring and return zero on errors.
+*/
+
+static long
+gethms(string, errstring, signable)
+const char * string;
+const char * const errstring;
+const int signable;
+{
+ long hh;
+ int mm, ss, sign;
+
+ if (string == NULL || *string == '\0')
+ return 0;
+ if (!signable)
+ sign = 1;
+ else if (*string == '-') {
+ sign = -1;
+ ++string;
+ } else sign = 1;
+ if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
+ mm = ss = 0;
+ else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
+ ss = 0;
+ else if (sscanf(string, scheck(string, "%ld:%d:%d"),
+ &hh, &mm, &ss) != 3) {
+ error(errstring);
+ return 0;
+ }
+ if (hh < 0 ||
+ mm < 0 || mm >= MINSPERHOUR ||
+ ss < 0 || ss > SECSPERMIN) {
+ error(errstring);
+ return 0;
+ }
+ if (LONG_MAX / SECSPERHOUR < hh) {
+ error(_("time overflow"));
+ return 0;
+ }
+ if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
+ warning(_("24:00 not handled by pre-1998 versions of zic"));
+ if (noise && (hh > HOURSPERDAY ||
+ (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
+warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
+ return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
+ eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
+}
+
+static void
+inrule(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ static struct rule r;
+
+ if (nfields != RULE_FIELDS) {
+ error(_("wrong number of fields on Rule line"));
+ return;
+ }
+ if (*fields[RF_NAME] == '\0') {
+ error(_("nameless rule"));
+ return;
+ }
+ r.r_filename = filename;
+ r.r_linenum = linenum;
+ r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
+ rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
+ fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
+ r.r_name = ecpyalloc(fields[RF_NAME]);
+ r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
+ if (max_abbrvar_len < strlen(r.r_abbrvar))
+ max_abbrvar_len = strlen(r.r_abbrvar);
+ rules = (struct rule *) (void *) erealloc((char *) rules,
+ (int) ((nrules + 1) * sizeof *rules));
+ rules[nrules++] = r;
+}
+
+static int
+inzone(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ register int i;
+ static char * buf;
+
+ if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
+ error(_("wrong number of fields on Zone line"));
+ return FALSE;
+ }
+ if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
+ buf = erealloc(buf, (int) (132 + strlen(TZDEFAULT)));
+ (void) sprintf(buf,
+_("\"Zone %s\" line and -l option are mutually exclusive"),
+ TZDEFAULT);
+ error(buf);
+ return FALSE;
+ }
+ if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
+ buf = erealloc(buf, (int) (132 + strlen(TZDEFRULES)));
+ (void) sprintf(buf,
+_("\"Zone %s\" line and -p option are mutually exclusive"),
+ TZDEFRULES);
+ error(buf);
+ return FALSE;
+ }
+ for (i = 0; i < nzones; ++i)
+ if (zones[i].z_name != NULL &&
+ strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
+ buf = erealloc(buf, (int) (132 +
+ strlen(fields[ZF_NAME]) +
+ strlen(zones[i].z_filename)));
+ (void) sprintf(buf,
+_("duplicate zone name %s (file \"%s\", line %d)"),
+ fields[ZF_NAME],
+ zones[i].z_filename,
+ zones[i].z_linenum);
+ error(buf);
+ return FALSE;
+ }
+ return inzsub(fields, nfields, FALSE);
+}
+
+static int
+inzcont(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
+ error(_("wrong number of fields on Zone continuation line"));
+ return FALSE;
+ }
+ return inzsub(fields, nfields, TRUE);
+}
+
+static int
+inzsub(fields, nfields, iscont)
+register char ** const fields;
+const int nfields;
+const int iscont;
+{
+ register char * cp;
+ static struct zone z;
+ register int i_gmtoff, i_rule, i_format;
+ register int i_untilyear, i_untilmonth;
+ register int i_untilday, i_untiltime;
+ register int hasuntil;
+
+ if (iscont) {
+ i_gmtoff = ZFC_GMTOFF;
+ i_rule = ZFC_RULE;
+ i_format = ZFC_FORMAT;
+ i_untilyear = ZFC_TILYEAR;
+ i_untilmonth = ZFC_TILMONTH;
+ i_untilday = ZFC_TILDAY;
+ i_untiltime = ZFC_TILTIME;
+ z.z_name = NULL;
+ } else {
+ i_gmtoff = ZF_GMTOFF;
+ i_rule = ZF_RULE;
+ i_format = ZF_FORMAT;
+ i_untilyear = ZF_TILYEAR;
+ i_untilmonth = ZF_TILMONTH;
+ i_untilday = ZF_TILDAY;
+ i_untiltime = ZF_TILTIME;
+ z.z_name = ecpyalloc(fields[ZF_NAME]);
+ }
+ z.z_filename = filename;
+ z.z_linenum = linenum;
+ z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
+ if ((cp = strchr(fields[i_format], '%')) != 0) {
+ if (*++cp != 's' || strchr(cp, '%') != 0) {
+ error(_("invalid abbreviation format"));
+ return FALSE;
+ }
+ }
+ z.z_rule = ecpyalloc(fields[i_rule]);
+ z.z_format = ecpyalloc(fields[i_format]);
+ if (max_format_len < strlen(z.z_format))
+ max_format_len = strlen(z.z_format);
+ hasuntil = nfields > i_untilyear;
+ if (hasuntil) {
+ z.z_untilrule.r_filename = filename;
+ z.z_untilrule.r_linenum = linenum;
+ rulesub(&z.z_untilrule,
+ fields[i_untilyear],
+ "only",
+ "",
+ (nfields > i_untilmonth) ?
+ fields[i_untilmonth] : "Jan",
+ (nfields > i_untilday) ? fields[i_untilday] : "1",
+ (nfields > i_untiltime) ? fields[i_untiltime] : "0");
+ z.z_untiltime = rpytime(&z.z_untilrule,
+ z.z_untilrule.r_loyear);
+ if (iscont && nzones > 0 &&
+ z.z_untiltime > min_time &&
+ z.z_untiltime < max_time &&
+ zones[nzones - 1].z_untiltime > min_time &&
+ zones[nzones - 1].z_untiltime < max_time &&
+ zones[nzones - 1].z_untiltime >= z.z_untiltime) {
+ error(_(
+"Zone continuation line end time is not after end time of previous line"
+ ));
+ return FALSE;
+ }
+ }
+ zones = (struct zone *) (void *) erealloc((char *) zones,
+ (int) ((nzones + 1) * sizeof *zones));
+ zones[nzones++] = z;
+ /*
+ ** If there was an UNTIL field on this line,
+ ** there's more information about the zone on the next line.
+ */
+ return hasuntil;
+}
+
+static void
+inleap(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ register const char * cp;
+ register const struct lookup * lp;
+ register int i, j;
+ int year, month, day;
+ long dayoff, tod;
+ zic_t t;
+
+ if (nfields != LEAP_FIELDS) {
+ error(_("wrong number of fields on Leap line"));
+ return;
+ }
+ dayoff = 0;
+ cp = fields[LP_YEAR];
+ if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
+ /*
+ ** Leapin' Lizards!
+ */
+ error(_("invalid leaping year"));
+ return;
+ }
+ if (!leapseen || leapmaxyear < year)
+ leapmaxyear = year;
+ if (!leapseen || leapminyear > year)
+ leapminyear = year;
+ leapseen = TRUE;
+ j = EPOCH_YEAR;
+ while (j != year) {
+ if (year > j) {
+ i = len_years[isleap(j)];
+ ++j;
+ } else {
+ --j;
+ i = -len_years[isleap(j)];
+ }
+ dayoff = oadd(dayoff, eitol(i));
+ }
+ if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
+ error(_("invalid month name"));
+ return;
+ }
+ month = lp->l_value;
+ j = TM_JANUARY;
+ while (j != month) {
+ i = len_months[isleap(year)][j];
+ dayoff = oadd(dayoff, eitol(i));
+ ++j;
+ }
+ cp = fields[LP_DAY];
+ if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
+ day <= 0 || day > len_months[isleap(year)][month]) {
+ error(_("invalid day of month"));
+ return;
+ }
+ dayoff = oadd(dayoff, eitol(day - 1));
+ if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
+ error(_("time before zero"));
+ return;
+ }
+ if (dayoff < min_time / SECSPERDAY) {
+ error(_("time too small"));
+ return;
+ }
+ if (dayoff > max_time / SECSPERDAY) {
+ error(_("time too large"));
+ return;
+ }
+ t = (zic_t) dayoff * SECSPERDAY;
+ tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
+ cp = fields[LP_CORR];
+ {
+ register int positive;
+ int count;
+
+ if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
+ positive = FALSE;
+ count = 1;
+ } else if (strcmp(cp, "--") == 0) {
+ positive = FALSE;
+ count = 2;
+ } else if (strcmp(cp, "+") == 0) {
+ positive = TRUE;
+ count = 1;
+ } else if (strcmp(cp, "++") == 0) {
+ positive = TRUE;
+ count = 2;
+ } else {
+ error(_("illegal CORRECTION field on Leap line"));
+ return;
+ }
+ if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
+ error(_(
+ "illegal Rolling/Stationary field on Leap line"
+ ));
+ return;
+ }
+ leapadd(tadd(t, tod), positive, lp->l_value, count);
+ }
+}
+
+static void
+inlink(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ struct link l;
+
+ if (nfields != LINK_FIELDS) {
+ error(_("wrong number of fields on Link line"));
+ return;
+ }
+ if (*fields[LF_FROM] == '\0') {
+ error(_("blank FROM field on Link line"));
+ return;
+ }
+ if (*fields[LF_TO] == '\0') {
+ error(_("blank TO field on Link line"));
+ return;
+ }
+ l.l_filename = filename;
+ l.l_linenum = linenum;
+ l.l_from = ecpyalloc(fields[LF_FROM]);
+ l.l_to = ecpyalloc(fields[LF_TO]);
+ links = (struct link *) (void *) erealloc((char *) links,
+ (int) ((nlinks + 1) * sizeof *links));
+ links[nlinks++] = l;
+}
+
+static void
+rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
+register struct rule * const rp;
+const char * const loyearp;
+const char * const hiyearp;
+const char * const typep;
+const char * const monthp;
+const char * const dayp;
+const char * const timep;
+{
+ register const struct lookup * lp;
+ register const char * cp;
+ register char * dp;
+ register char * ep;
+
+ if ((lp = byword(monthp, mon_names)) == NULL) {
+ error(_("invalid month name"));
+ return;
+ }
+ rp->r_month = lp->l_value;
+ rp->r_todisstd = FALSE;
+ rp->r_todisgmt = FALSE;
+ dp = ecpyalloc(timep);
+ if (*dp != '\0') {
+ ep = dp + strlen(dp) - 1;
+ switch (lowerit(*ep)) {
+ case 's': /* Standard */
+ rp->r_todisstd = TRUE;
+ rp->r_todisgmt = FALSE;
+ *ep = '\0';
+ break;
+ case 'w': /* Wall */
+ rp->r_todisstd = FALSE;
+ rp->r_todisgmt = FALSE;
+ *ep = '\0';
+ break;
+ case 'g': /* Greenwich */
+ case 'u': /* Universal */
+ case 'z': /* Zulu */
+ rp->r_todisstd = TRUE;
+ rp->r_todisgmt = TRUE;
+ *ep = '\0';
+ break;
+ }
+ }
+ rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
+ ifree(dp);
+ /*
+ ** Year work.
+ */
+ cp = loyearp;
+ lp = byword(cp, begin_years);
+ rp->r_lowasnum = lp == NULL;
+ if (!rp->r_lowasnum) switch ((int) lp->l_value) {
+ case YR_MINIMUM:
+ rp->r_loyear = INT_MIN;
+ break;
+ case YR_MAXIMUM:
+ rp->r_loyear = INT_MAX;
+ break;
+ default: /* "cannot happen" */
+ errx(EXIT_FAILURE,
+ _("panic: invalid l_value %d"), lp->l_value);
+ } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
+ error(_("invalid starting year"));
+ return;
+ }
+ cp = hiyearp;
+ lp = byword(cp, end_years);
+ rp->r_hiwasnum = lp == NULL;
+ if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
+ case YR_MINIMUM:
+ rp->r_hiyear = INT_MIN;
+ break;
+ case YR_MAXIMUM:
+ rp->r_hiyear = INT_MAX;
+ break;
+ case YR_ONLY:
+ rp->r_hiyear = rp->r_loyear;
+ break;
+ default: /* "cannot happen" */
+ errx(EXIT_FAILURE,
+ _("panic: invalid l_value %d"), lp->l_value);
+ } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
+ error(_("invalid ending year"));
+ return;
+ }
+ if (rp->r_loyear > rp->r_hiyear) {
+ error(_("starting year greater than ending year"));
+ return;
+ }
+ if (*typep == '\0')
+ rp->r_yrtype = NULL;
+ else {
+ if (rp->r_loyear == rp->r_hiyear) {
+ error(_("typed single year"));
+ return;
+ }
+ rp->r_yrtype = ecpyalloc(typep);
+ }
+ /*
+ ** Day work.
+ ** Accept things such as:
+ ** 1
+ ** last-Sunday
+ ** Sun<=20
+ ** Sun>=7
+ */
+ dp = ecpyalloc(dayp);
+ if ((lp = byword(dp, lasts)) != NULL) {
+ rp->r_dycode = DC_DOWLEQ;
+ rp->r_wday = lp->l_value;
+ rp->r_dayofmonth = len_months[1][rp->r_month];
+ } else {
+ if ((ep = strchr(dp, '<')) != 0)
+ rp->r_dycode = DC_DOWLEQ;
+ else if ((ep = strchr(dp, '>')) != 0)
+ rp->r_dycode = DC_DOWGEQ;
+ else {
+ ep = dp;
+ rp->r_dycode = DC_DOM;
+ }
+ if (rp->r_dycode != DC_DOM) {
+ *ep++ = 0;
+ if (*ep++ != '=') {
+ error(_("invalid day of month"));
+ ifree(dp);
+ return;
+ }
+ if ((lp = byword(dp, wday_names)) == NULL) {
+ error(_("invalid weekday name"));
+ ifree(dp);
+ return;
+ }
+ rp->r_wday = lp->l_value;
+ }
+ if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
+ rp->r_dayofmonth <= 0 ||
+ (rp->r_dayofmonth > len_months[1][rp->r_month])) {
+ error(_("invalid day of month"));
+ ifree(dp);
+ return;
+ }
+ }
+ ifree(dp);
+}
+
+static void
+convert(val, buf)
+const long val;
+char * const buf;
+{
+ register int i;
+ register int shift;
+
+ for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
+ buf[i] = val >> shift;
+}
+
+static void
+convert64(val, buf)
+const zic_t val;
+char * const buf;
+{
+ register int i;
+ register int shift;
+
+ for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
+ buf[i] = val >> shift;
+}
+
+static void
+puttzcode(val, fp)
+const long val;
+FILE * const fp;
+{
+ char buf[4];
+
+ convert(val, buf);
+ (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
+}
+
+static void
+puttzcode64(val, fp)
+const zic_t val;
+FILE * const fp;
+{
+ char buf[8];
+
+ convert64(val, buf);
+ (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
+}
+
+static int
+atcomp(avp, bvp)
+const void * avp;
+const void * bvp;
+{
+ const zic_t a = ((const struct attype *) avp)->at;
+ const zic_t b = ((const struct attype *) bvp)->at;
+
+ return (a < b) ? -1 : (a > b);
+}
+
+static int
+is32(x)
+const zic_t x;
+{
+ return INT32_MIN <= x && x <= INT32_MAX;
+}
+
+static void
+writezone(name, string)
+const char * const name;
+const char * const string;
+{
+ register FILE * fp;
+ register int i, j;
+ register int leapcnt32, leapi32;
+ register int timecnt32, timei32;
+ register int pass;
+ static char * fullname;
+ static const struct tzhead tzh0;
+ static struct tzhead tzh;
+ zic_t ats[TZ_MAX_TIMES];
+ unsigned char types[TZ_MAX_TIMES];
+
+ /*
+ ** Sort.
+ */
+ if (timecnt > 1)
+ (void) qsort((void *) attypes, (size_t) timecnt,
+ (size_t) sizeof *attypes, atcomp);
+ /*
+ ** Optimize.
+ */
+ {
+ int fromi;
+ int toi;
+
+ toi = 0;
+ fromi = 0;
+ while (fromi < timecnt && attypes[fromi].at < min_time)
+ ++fromi;
+ if (isdsts[0] == 0)
+ while (fromi < timecnt && attypes[fromi].type == 0)
+ ++fromi; /* handled by default rule */
+ for ( ; fromi < timecnt; ++fromi) {
+ if (toi != 0 && ((attypes[fromi].at +
+ gmtoffs[attypes[toi - 1].type]) <=
+ (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
+ : attypes[toi - 2].type]))) {
+ attypes[toi - 1].type =
+ attypes[fromi].type;
+ continue;
+ }
+ if (toi == 0 ||
+ attypes[toi - 1].type != attypes[fromi].type)
+ attypes[toi++] = attypes[fromi];
+ }
+ timecnt = toi;
+ }
+ /*
+ ** Transfer.
+ */
+ for (i = 0; i < timecnt; ++i) {
+ ats[i] = attypes[i].at;
+ types[i] = attypes[i].type;
+ }
+ /*
+ ** Correct for leap seconds.
+ */
+ for (i = 0; i < timecnt; ++i) {
+ j = leapcnt;
+ while (--j >= 0)
+ if (ats[i] > trans[j] - corr[j]) {
+ ats[i] = tadd(ats[i], corr[j]);
+ break;
+ }
+ }
+ /*
+ ** Figure out 32-bit-limited starts and counts.
+ */
+ timecnt32 = timecnt;
+ timei32 = 0;
+ leapcnt32 = leapcnt;
+ leapi32 = 0;
+ while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
+ --timecnt32;
+ while (timecnt32 > 0 && !is32(ats[timei32])) {
+ --timecnt32;
+ ++timei32;
+ }
+ while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
+ --leapcnt32;
+ while (leapcnt32 > 0 && !is32(trans[leapi32])) {
+ --leapcnt32;
+ ++leapi32;
+ }
+ fullname = erealloc(fullname,
+ (int) (strlen(directory) + 1 + strlen(name) + 1));
+ (void) sprintf(fullname, "%s/%s", directory, name);
+
+ /*
+ * Remove old file, if any, to snap links.
+ */
+ if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT)
+ err(EXIT_FAILURE, _("can't remove %s"), fullname);
+
+ if ((fp = fopen(fullname, "wb")) == NULL) {
+ if (mkdirs(fullname) != 0)
+ exit(EXIT_FAILURE);
+ if ((fp = fopen(fullname, "wb")) == NULL)
+ err(EXIT_FAILURE, _("can't create %s"), fullname);
+ }
+ for (pass = 1; pass <= 2; ++pass) {
+ register int thistimei, thistimecnt;
+ register int thisleapi, thisleapcnt;
+ register int thistimelim, thisleaplim;
+ int writetype[TZ_MAX_TIMES];
+ int typemap[TZ_MAX_TYPES];
+ register int thistypecnt;
+ char thischars[TZ_MAX_CHARS];
+ char thischarcnt;
+ int indmap[TZ_MAX_CHARS];
+
+ if (pass == 1) {
+ thistimei = timei32;
+ thistimecnt = timecnt32;
+ thisleapi = leapi32;
+ thisleapcnt = leapcnt32;
+ } else {
+ thistimei = 0;
+ thistimecnt = timecnt;
+ thisleapi = 0;
+ thisleapcnt = leapcnt;
+ }
+ thistimelim = thistimei + thistimecnt;
+ thisleaplim = thisleapi + thisleapcnt;
+ for (i = 0; i < typecnt; ++i)
+ writetype[i] = thistimecnt == timecnt;
+ if (thistimecnt == 0) {
+ /*
+ ** No transition times fall in the current
+ ** (32- or 64-bit) window.
+ */
+ if (typecnt != 0)
+ writetype[typecnt - 1] = TRUE;
+ } else {
+ for (i = thistimei - 1; i < thistimelim; ++i)
+ if (i >= 0)
+ writetype[types[i]] = TRUE;
+ /*
+ ** For America/Godthab and Antarctica/Palmer
+ */
+ if (thistimei == 0)
+ writetype[0] = TRUE;
+ }
+#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
+ /*
+ ** For some pre-2011 systems: if the last-to-be-written
+ ** standard (or daylight) type has an offset different from the
+ ** most recently used offset,
+ ** append an (unused) copy of the most recently used type
+ ** (to help get global "altzone" and "timezone" variables
+ ** set correctly).
+ */
+ {
+ register int mrudst, mrustd, hidst, histd, type;
+
+ hidst = histd = mrudst = mrustd = -1;
+ for (i = thistimei; i < thistimelim; ++i)
+ if (isdsts[types[i]])
+ mrudst = types[i];
+ else mrustd = types[i];
+ for (i = 0; i < typecnt; ++i)
+ if (writetype[i]) {
+ if (isdsts[i])
+ hidst = i;
+ else histd = i;
+ }
+ if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
+ gmtoffs[hidst] != gmtoffs[mrudst]) {
+ isdsts[mrudst] = -1;
+ type = addtype(gmtoffs[mrudst],
+ &chars[abbrinds[mrudst]],
+ TRUE,
+ ttisstds[mrudst],
+ ttisgmts[mrudst]);
+ isdsts[mrudst] = TRUE;
+ writetype[type] = TRUE;
+ }
+ if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
+ gmtoffs[histd] != gmtoffs[mrustd]) {
+ isdsts[mrustd] = -1;
+ type = addtype(gmtoffs[mrustd],
+ &chars[abbrinds[mrustd]],
+ FALSE,
+ ttisstds[mrustd],
+ ttisgmts[mrustd]);
+ isdsts[mrustd] = FALSE;
+ writetype[type] = TRUE;
+ }
+ }
+#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
+ thistypecnt = 0;
+ for (i = 0; i < typecnt; ++i)
+ typemap[i] = writetype[i] ? thistypecnt++ : -1;
+ for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
+ indmap[i] = -1;
+ thischarcnt = 0;
+ for (i = 0; i < typecnt; ++i) {
+ register char * thisabbr;
+
+ if (!writetype[i])
+ continue;
+ if (indmap[abbrinds[i]] >= 0)
+ continue;
+ thisabbr = &chars[abbrinds[i]];
+ for (j = 0; j < thischarcnt; ++j)
+ if (strcmp(&thischars[j], thisabbr) == 0)
+ break;
+ if (j == thischarcnt) {
+ (void) strcpy(&thischars[(int) thischarcnt],
+ thisabbr);
+ thischarcnt += strlen(thisabbr) + 1;
+ }
+ indmap[abbrinds[i]] = j;
+ }
+#define DO(field) (void) fwrite((void *) tzh.field, \
+ (size_t) sizeof tzh.field, (size_t) 1, fp)
+ tzh = tzh0;
+ (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
+ tzh.tzh_version[0] = ZIC_VERSION;
+ convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
+ convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
+ convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
+ convert(eitol(thistimecnt), tzh.tzh_timecnt);
+ convert(eitol(thistypecnt), tzh.tzh_typecnt);
+ convert(eitol(thischarcnt), tzh.tzh_charcnt);
+ DO(tzh_magic);
+ DO(tzh_version);
+ DO(tzh_reserved);
+ DO(tzh_ttisgmtcnt);
+ DO(tzh_ttisstdcnt);
+ DO(tzh_leapcnt);
+ DO(tzh_timecnt);
+ DO(tzh_typecnt);
+ DO(tzh_charcnt);
+#undef DO
+ for (i = thistimei; i < thistimelim; ++i)
+ if (pass == 1)
+ puttzcode((long) ats[i], fp);
+ else puttzcode64(ats[i], fp);
+ for (i = thistimei; i < thistimelim; ++i) {
+ unsigned char uc;
+
+ uc = typemap[types[i]];
+ (void) fwrite((void *) &uc,
+ (size_t) sizeof uc,
+ (size_t) 1,
+ fp);
+ }
+ for (i = 0; i < typecnt; ++i)
+ if (writetype[i]) {
+ puttzcode(gmtoffs[i], fp);
+ (void) putc(isdsts[i], fp);
+ (void) putc((unsigned char) indmap[abbrinds[i]], fp);
+ }
+ if (thischarcnt != 0)
+ (void) fwrite((void *) thischars,
+ (size_t) sizeof thischars[0],
+ (size_t) thischarcnt, fp);
+ for (i = thisleapi; i < thisleaplim; ++i) {
+ register zic_t todo;
+
+ if (roll[i]) {
+ if (timecnt == 0 || trans[i] < ats[0]) {
+ j = 0;
+ while (isdsts[j])
+ if (++j >= typecnt) {
+ j = 0;
+ break;
+ }
+ } else {
+ j = 1;
+ while (j < timecnt &&
+ trans[i] >= ats[j])
+ ++j;
+ j = types[j - 1];
+ }
+ todo = tadd(trans[i], -gmtoffs[j]);
+ } else todo = trans[i];
+ if (pass == 1)
+ puttzcode((long) todo, fp);
+ else puttzcode64(todo, fp);
+ puttzcode(corr[i], fp);
+ }
+ for (i = 0; i < typecnt; ++i)
+ if (writetype[i])
+ (void) putc(ttisstds[i], fp);
+ for (i = 0; i < typecnt; ++i)
+ if (writetype[i])
+ (void) putc(ttisgmts[i], fp);
+ }
+ (void) fprintf(fp, "\n%s\n", string);
+ if (ferror(fp) || fclose(fp))
+ errx(EXIT_FAILURE, _("error writing %s"), fullname);
+ if (chmod(fullname, mflag) < 0)
+ err(EXIT_FAILURE, _("cannot change mode of %s to %03o"),
+ fullname, (unsigned)mflag);
+ if ((uflag != (uid_t)-1 || gflag != (gid_t)-1)
+ && chown(fullname, uflag, gflag) < 0)
+ err(EXIT_FAILURE, _("cannot change ownership of %s"),
+ fullname);
+}
+
+static void
+doabbr(abbr, format, letters, isdst, doquotes)
+char * const abbr;
+const char * const format;
+const char * const letters;
+const int isdst;
+const int doquotes;
+{
+ register char * cp;
+ register char * slashp;
+ register int len;
+
+ slashp = strchr(format, '/');
+ if (slashp == NULL) {
+ if (letters == NULL)
+ (void) strcpy(abbr, format);
+ else (void) sprintf(abbr, format, letters);
+ } else if (isdst) {
+ (void) strcpy(abbr, slashp + 1);
+ } else {
+ if (slashp > format)
+ (void) strncpy(abbr, format,
+ (unsigned) (slashp - format));
+ abbr[slashp - format] = '\0';
+ }
+ if (!doquotes)
+ return;
+ for (cp = abbr; *cp != '\0'; ++cp)
+ if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
+ strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
+ break;
+ len = strlen(abbr);
+ if (len > 0 && *cp == '\0')
+ return;
+ abbr[len + 2] = '\0';
+ abbr[len + 1] = '>';
+ for ( ; len > 0; --len)
+ abbr[len] = abbr[len - 1];
+ abbr[0] = '<';
+}
+
+static void
+updateminmax(x)
+const int x;
+{
+ if (min_year > x)
+ min_year = x;
+ if (max_year < x)
+ max_year = x;
+}
+
+static int
+stringoffset(result, offset)
+char * result;
+long offset;
+{
+ register int hours;
+ register int minutes;
+ register int seconds;
+
+ result[0] = '\0';
+ if (offset < 0) {
+ (void) strcpy(result, "-");
+ offset = -offset;
+ }
+ seconds = offset % SECSPERMIN;
+ offset /= SECSPERMIN;
+ minutes = offset % MINSPERHOUR;
+ offset /= MINSPERHOUR;
+ hours = offset;
+ if (hours >= HOURSPERDAY) {
+ result[0] = '\0';
+ return -1;
+ }
+ (void) sprintf(end(result), "%d", hours);
+ if (minutes != 0 || seconds != 0) {
+ (void) sprintf(end(result), ":%02d", minutes);
+ if (seconds != 0)
+ (void) sprintf(end(result), ":%02d", seconds);
+ }
+ return 0;
+}
+
+static int
+stringrule(result, rp, dstoff, gmtoff)
+char * result;
+const struct rule * const rp;
+const long dstoff;
+const long gmtoff;
+{
+ register long tod;
+
+ result = end(result);
+ if (rp->r_dycode == DC_DOM) {
+ register int month, total;
+
+ if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
+ return -1;
+ total = 0;
+ for (month = 0; month < rp->r_month; ++month)
+ total += len_months[0][month];
+ (void) sprintf(result, "J%d", total + rp->r_dayofmonth);
+ } else {
+ register int week;
+
+ if (rp->r_dycode == DC_DOWGEQ) {
+ week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
+ if ((week - 1) * DAYSPERWEEK + 1 != rp->r_dayofmonth)
+ return -1;
+ } else if (rp->r_dycode == DC_DOWLEQ) {
+ if (rp->r_dayofmonth == len_months[1][rp->r_month])
+ week = 5;
+ else {
+ week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
+ if (week * DAYSPERWEEK - 1 != rp->r_dayofmonth)
+ return -1;
+ }
+ } else return -1; /* "cannot happen" */
+ (void) sprintf(result, "M%d.%d.%d",
+ rp->r_month + 1, week, rp->r_wday);
+ }
+ tod = rp->r_tod;
+ if (rp->r_todisgmt)
+ tod += gmtoff;
+ if (rp->r_todisstd && rp->r_stdoff == 0)
+ tod += dstoff;
+ if (tod < 0) {
+ result[0] = '\0';
+ return -1;
+ }
+ if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
+ (void) strcat(result, "/");
+ if (stringoffset(end(result), tod) != 0)
+ return -1;
+ }
+ return 0;
+}
+
+static void
+stringzone(result, zpfirst, zonecount)
+char * result;
+const struct zone * const zpfirst;
+const int zonecount;
+{
+ register const struct zone * zp;
+ register struct rule * rp;
+ register struct rule * stdrp;
+ register struct rule * dstrp;
+ register int i;
+ register const char * abbrvar;
+
+ result[0] = '\0';
+ zp = zpfirst + zonecount - 1;
+ stdrp = dstrp = NULL;
+ for (i = 0; i < zp->z_nrules; ++i) {
+ rp = &zp->z_rules[i];
+ if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
+ continue;
+ if (rp->r_yrtype != NULL)
+ continue;
+ if (rp->r_stdoff == 0) {
+ if (stdrp == NULL)
+ stdrp = rp;
+ else return;
+ } else {
+ if (dstrp == NULL)
+ dstrp = rp;
+ else return;
+ }
+ }
+ if (stdrp == NULL && dstrp == NULL) {
+ /*
+ ** There are no rules running through "max".
+ ** Let's find the latest rule.
+ */
+ for (i = 0; i < zp->z_nrules; ++i) {
+ rp = &zp->z_rules[i];
+ if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
+ (rp->r_hiyear == stdrp->r_hiyear &&
+ rp->r_month > stdrp->r_month))
+ stdrp = rp;
+ }
+ if (stdrp != NULL && stdrp->r_stdoff != 0)
+ return; /* We end up in DST (a POSIX no-no). */
+ /*
+ ** Horrid special case: if year is 2037,
+ ** presume this is a zone handled on a year-by-year basis;
+ ** do not try to apply a rule to the zone.
+ */
+ if (stdrp != NULL && stdrp->r_hiyear == 2037)
+ return;
+ }
+ if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
+ return;
+ abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
+ doabbr(result, zp->z_format, abbrvar, FALSE, TRUE);
+ if (stringoffset(end(result), -zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ if (dstrp == NULL)
+ return;
+ doabbr(end(result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
+ if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR)
+ if (stringoffset(end(result),
+ -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ (void) strcat(result, ",");
+ if (stringrule(result, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
+ }
+ (void) strcat(result, ",");
+ if (stringrule(result, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
+ result[0] = '\0';
+ return;
+ }
+}
+
+static void
+outzone(zpfirst, zonecount)
+const struct zone * const zpfirst;
+const int zonecount;
+{
+ register const struct zone * zp;
+ register struct rule * rp;
+ register int i, j;
+ register int usestart, useuntil;
+ register zic_t starttime, untiltime;
+ register long gmtoff;
+ register long stdoff;
+ register int year;
+ register long startoff;
+ register int startttisstd;
+ register int startttisgmt;
+ register int type;
+ register char * startbuf;
+ register char * ab;
+ register char * envvar;
+ register int max_abbr_len;
+ register int max_envvar_len;
+
+ max_abbr_len = 2 + max_format_len + max_abbrvar_len;
+ max_envvar_len = 2 * max_abbr_len + 5 * 9;
+ startbuf = emalloc(max_abbr_len + 1);
+ ab = emalloc(max_abbr_len + 1);
+ envvar = emalloc(max_envvar_len + 1);
+ INITIALIZE(untiltime);
+ INITIALIZE(starttime);
+ /*
+ ** Now. . .finally. . .generate some useful data!
+ */
+ timecnt = 0;
+ typecnt = 0;
+ charcnt = 0;
+ /*
+ ** Thanks to Earl Chew
+ ** for noting the need to unconditionally initialize startttisstd.
+ */
+ startttisstd = FALSE;
+ startttisgmt = FALSE;
+ min_year = max_year = EPOCH_YEAR;
+ if (leapseen) {
+ updateminmax(leapminyear);
+ updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
+ }
+ for (i = 0; i < zonecount; ++i) {
+ zp = &zpfirst[i];
+ if (i < zonecount - 1)
+ updateminmax(zp->z_untilrule.r_loyear);
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ if (rp->r_lowasnum)
+ updateminmax(rp->r_loyear);
+ if (rp->r_hiwasnum)
+ updateminmax(rp->r_hiyear);
+ }
+ }
+ /*
+ ** Generate lots of data if a rule can't cover all future times.
+ */
+ stringzone(envvar, zpfirst, zonecount);
+ if (noise && envvar[0] == '\0') {
+ register char * wp;
+
+wp = ecpyalloc(_("no POSIX environment variable for zone"));
+ wp = ecatalloc(wp, " ");
+ wp = ecatalloc(wp, zpfirst->z_name);
+ warning(wp);
+ ifree(wp);
+ }
+ if (envvar[0] == '\0') {
+ if (min_year >= INT_MIN + YEARSPERREPEAT)
+ min_year -= YEARSPERREPEAT;
+ else min_year = INT_MIN;
+ if (max_year <= INT_MAX - YEARSPERREPEAT)
+ max_year += YEARSPERREPEAT;
+ else max_year = INT_MAX;
+ }
+ /*
+ ** For the benefit of older systems,
+ ** generate data from 1900 through 2037.
+ */
+ if (min_year > 1900)
+ min_year = 1900;
+ if (max_year < 2037)
+ max_year = 2037;
+ for (i = 0; i < zonecount; ++i) {
+ /*
+ ** A guess that may well be corrected later.
+ */
+ stdoff = 0;
+ zp = &zpfirst[i];
+ usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
+ useuntil = i < (zonecount - 1);
+ if (useuntil && zp->z_untiltime <= min_time)
+ continue;
+ gmtoff = zp->z_gmtoff;
+ eat(zp->z_filename, zp->z_linenum);
+ *startbuf = '\0';
+ startoff = zp->z_gmtoff;
+ if (zp->z_nrules == 0) {
+ stdoff = zp->z_stdoff;
+ doabbr(startbuf, zp->z_format,
+ (char *) NULL, stdoff != 0, FALSE);
+ type = addtype(oadd(zp->z_gmtoff, stdoff),
+ startbuf, stdoff != 0, startttisstd,
+ startttisgmt);
+ if (usestart) {
+ addtt(starttime, type);
+ usestart = FALSE;
+ } else if (stdoff != 0)
+ addtt(min_time, type);
+ } else for (year = min_year; year <= max_year; ++year) {
+ if (useuntil && year > zp->z_untilrule.r_hiyear)
+ break;
+ /*
+ ** Mark which rules to do in the current year.
+ ** For those to do, calculate rpytime(rp, year);
+ */
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ rp->r_todo = year >= rp->r_loyear &&
+ year <= rp->r_hiyear &&
+ yearistype(year, rp->r_yrtype);
+ if (rp->r_todo)
+ rp->r_temp = rpytime(rp, year);
+ }
+ for ( ; ; ) {
+ register int k;
+ register zic_t jtime, ktime;
+ register long offset;
+
+ INITIALIZE(ktime);
+ if (useuntil) {
+ /*
+ ** Turn untiltime into UTC
+ ** assuming the current gmtoff and
+ ** stdoff values.
+ */
+ untiltime = zp->z_untiltime;
+ if (!zp->z_untilrule.r_todisgmt)
+ untiltime = tadd(untiltime,
+ -gmtoff);
+ if (!zp->z_untilrule.r_todisstd)
+ untiltime = tadd(untiltime,
+ -stdoff);
+ }
+ /*
+ ** Find the rule (of those to do, if any)
+ ** that takes effect earliest in the year.
+ */
+ k = -1;
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ if (!rp->r_todo)
+ continue;
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ offset = rp->r_todisgmt ? 0 : gmtoff;
+ if (!rp->r_todisstd)
+ offset = oadd(offset, stdoff);
+ jtime = rp->r_temp;
+ if (jtime == min_time ||
+ jtime == max_time)
+ continue;
+ jtime = tadd(jtime, -offset);
+ if (k < 0 || jtime < ktime) {
+ k = j;
+ ktime = jtime;
+ }
+ }
+ if (k < 0)
+ break; /* go on to next year */
+ rp = &zp->z_rules[k];
+ rp->r_todo = FALSE;
+ if (useuntil && ktime >= untiltime)
+ break;
+ stdoff = rp->r_stdoff;
+ if (usestart && ktime == starttime)
+ usestart = FALSE;
+ if (usestart) {
+ if (ktime < starttime) {
+ startoff = oadd(zp->z_gmtoff,
+ stdoff);
+ doabbr(startbuf, zp->z_format,
+ rp->r_abbrvar,
+ rp->r_stdoff != 0,
+ FALSE);
+ continue;
+ }
+ if (*startbuf == '\0' &&
+ startoff == oadd(zp->z_gmtoff,
+ stdoff)) {
+ doabbr(startbuf,
+ zp->z_format,
+ rp->r_abbrvar,
+ rp->r_stdoff !=
+ 0,
+ FALSE);
+ }
+ }
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ doabbr(ab, zp->z_format, rp->r_abbrvar,
+ rp->r_stdoff != 0, FALSE);
+ offset = oadd(zp->z_gmtoff, rp->r_stdoff);
+ type = addtype(offset, ab, rp->r_stdoff != 0,
+ rp->r_todisstd, rp->r_todisgmt);
+ addtt(ktime, type);
+ }
+ }
+ if (usestart) {
+ if (*startbuf == '\0' &&
+ zp->z_format != NULL &&
+ strchr(zp->z_format, '%') == NULL &&
+ strchr(zp->z_format, '/') == NULL)
+ (void) strcpy(startbuf, zp->z_format);
+ eat(zp->z_filename, zp->z_linenum);
+ if (*startbuf == '\0')
+error(_("can't determine time zone abbreviation to use just after until time"));
+ else addtt(starttime,
+ addtype(startoff, startbuf,
+ startoff != zp->z_gmtoff,
+ startttisstd,
+ startttisgmt));
+ }
+ /*
+ ** Now we may get to set starttime for the next zone line.
+ */
+ if (useuntil) {
+ startttisstd = zp->z_untilrule.r_todisstd;
+ startttisgmt = zp->z_untilrule.r_todisgmt;
+ starttime = zp->z_untiltime;
+ if (!startttisstd)
+ starttime = tadd(starttime, -stdoff);
+ if (!startttisgmt)
+ starttime = tadd(starttime, -gmtoff);
+ }
+ }
+ writezone(zpfirst->z_name, envvar);
+ ifree(startbuf);
+ ifree(ab);
+ ifree(envvar);
+}
+
+static void
+addtt(starttime, type)
+const zic_t starttime;
+int type;
+{
+ if (starttime <= min_time ||
+ (timecnt == 1 && attypes[0].at < min_time)) {
+ gmtoffs[0] = gmtoffs[type];
+ isdsts[0] = isdsts[type];
+ ttisstds[0] = ttisstds[type];
+ ttisgmts[0] = ttisgmts[type];
+ if (abbrinds[type] != 0)
+ (void) strcpy(chars, &chars[abbrinds[type]]);
+ abbrinds[0] = 0;
+ charcnt = strlen(chars) + 1;
+ typecnt = 1;
+ timecnt = 0;
+ type = 0;
+ }
+ if (timecnt >= TZ_MAX_TIMES) {
+ error(_("too many transitions?!"));
+ exit(EXIT_FAILURE);
+ }
+ attypes[timecnt].at = starttime;
+ attypes[timecnt].type = type;
+ ++timecnt;
+}
+
+static int
+addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
+const long gmtoff;
+const char * const abbr;
+const int isdst;
+const int ttisstd;
+const int ttisgmt;
+{
+ register int i, j;
+
+ if (isdst != TRUE && isdst != FALSE) {
+ error(_("internal error - addtype called with bad isdst"));
+ exit(EXIT_FAILURE);
+ }
+ if (ttisstd != TRUE && ttisstd != FALSE) {
+ error(_("internal error - addtype called with bad ttisstd"));
+ exit(EXIT_FAILURE);
+ }
+ if (ttisgmt != TRUE && ttisgmt != FALSE) {
+ error(_("internal error - addtype called with bad ttisgmt"));
+ exit(EXIT_FAILURE);
+ }
+ /*
+ ** See if there's already an entry for this zone type.
+ ** If so, just return its index.
+ */
+ for (i = 0; i < typecnt; ++i) {
+ if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
+ strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
+ ttisstd == ttisstds[i] &&
+ ttisgmt == ttisgmts[i])
+ return i;
+ }
+ /*
+ ** There isn't one; add a new one, unless there are already too
+ ** many.
+ */
+ if (typecnt >= TZ_MAX_TYPES) {
+ error(_("too many local time types"));
+ exit(EXIT_FAILURE);
+ }
+ if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
+ error(_("UTC offset out of range"));
+ exit(EXIT_FAILURE);
+ }
+ gmtoffs[i] = gmtoff;
+ isdsts[i] = isdst;
+ ttisstds[i] = ttisstd;
+ ttisgmts[i] = ttisgmt;
+
+ for (j = 0; j < charcnt; ++j)
+ if (strcmp(&chars[j], abbr) == 0)
+ break;
+ if (j == charcnt)
+ newabbr(abbr);
+ abbrinds[i] = j;
+ ++typecnt;
+ return i;
+}
+
+static void
+leapadd(t, positive, rolling, count)
+const zic_t t;
+const int positive;
+const int rolling;
+int count;
+{
+ register int i, j;
+
+ if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
+ error(_("too many leap seconds"));
+ exit(EXIT_FAILURE);
+ }
+ for (i = 0; i < leapcnt; ++i)
+ if (t <= trans[i]) {
+ if (t == trans[i]) {
+ error(_("repeated leap second moment"));
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+ do {
+ for (j = leapcnt; j > i; --j) {
+ trans[j] = trans[j - 1];
+ corr[j] = corr[j - 1];
+ roll[j] = roll[j - 1];
+ }
+ trans[i] = t;
+ corr[i] = positive ? 1L : eitol(-count);
+ roll[i] = rolling;
+ ++leapcnt;
+ } while (positive && --count != 0);
+}
+
+static void
+adjleap(void)
+{
+ register int i;
+ register long last = 0;
+
+ /*
+ ** propagate leap seconds forward
+ */
+ for (i = 0; i < leapcnt; ++i) {
+ trans[i] = tadd(trans[i], last);
+ last = corr[i] += last;
+ }
+}
+
+static int
+yearistype(year, type)
+const int year;
+const char * const type;
+{
+ static char * buf;
+ int result;
+
+ if (type == NULL || *type == '\0')
+ return TRUE;
+ buf = erealloc(buf, (int) (132 + strlen(yitcommand) + strlen(type)));
+ (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
+ result = system(buf);
+ if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
+ case 0:
+ return TRUE;
+ case 1:
+ return FALSE;
+ }
+ error(_("wild result from command execution"));
+ warnx(_("command was '%s', result was %d"), buf, result);
+ for ( ; ; )
+ exit(EXIT_FAILURE);
+}
+
+static int
+lowerit(a)
+int a;
+{
+ a = (unsigned char) a;
+ return (isascii(a) && isupper(a)) ? tolower(a) : a;
+}
+
+static int
+ciequal(ap, bp) /* case-insensitive equality */
+register const char * ap;
+register const char * bp;
+{
+ while (lowerit(*ap) == lowerit(*bp++))
+ if (*ap++ == '\0')
+ return TRUE;
+ return FALSE;
+}
+
+static int
+itsabbr(abbr, word)
+register const char * abbr;
+register const char * word;
+{
+ if (lowerit(*abbr) != lowerit(*word))
+ return FALSE;
+ ++word;
+ while (*++abbr != '\0')
+ do {
+ if (*word == '\0')
+ return FALSE;
+ } while (lowerit(*word++) != lowerit(*abbr));
+ return TRUE;
+}
+
+static const struct lookup *
+byword(word, table)
+register const char * const word;
+register const struct lookup * const table;
+{
+ register const struct lookup * foundlp;
+ register const struct lookup * lp;
+
+ if (word == NULL || table == NULL)
+ return NULL;
+ /*
+ ** Look for exact match.
+ */
+ for (lp = table; lp->l_word != NULL; ++lp)
+ if (ciequal(word, lp->l_word))
+ return lp;
+ /*
+ ** Look for inexact match.
+ */
+ foundlp = NULL;
+ for (lp = table; lp->l_word != NULL; ++lp)
+ if (itsabbr(word, lp->l_word)) {
+ if (foundlp == NULL)
+ foundlp = lp;
+ else return NULL; /* multiple inexact matches */
+ }
+ return foundlp;
+}
+
+static char **
+getfields(cp)
+register char * cp;
+{
+ register char * dp;
+ register char ** array;
+ register int nsubs;
+
+ if (cp == NULL)
+ return NULL;
+ array = (char **) (void *)
+ emalloc((int) ((strlen(cp) + 1) * sizeof *array));
+ nsubs = 0;
+ for ( ; ; ) {
+ while (isascii((unsigned char) *cp) &&
+ isspace((unsigned char) *cp))
+ ++cp;
+ if (*cp == '\0' || *cp == '#')
+ break;
+ array[nsubs++] = dp = cp;
+ do {
+ if ((*dp = *cp++) != '"')
+ ++dp;
+ else while ((*dp = *cp++) != '"')
+ if (*dp != '\0')
+ ++dp;
+ else {
+ error(_("odd number of quotation marks"));
+ exit(EXIT_FAILURE);
+ }
+ } while (*cp != '\0' && *cp != '#' &&
+ (!isascii(*cp) || !isspace((unsigned char) *cp)));
+ if (isascii(*cp) && isspace((unsigned char) *cp))
+ ++cp;
+ *dp = '\0';
+ }
+ array[nsubs] = NULL;
+ return array;
+}
+
+static long
+oadd(t1, t2)
+const long t1;
+const long t2;
+{
+ register long t;
+
+ t = t1 + t2;
+ if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
+ error(_("time overflow"));
+ exit(EXIT_FAILURE);
+ }
+ return t;
+}
+
+static zic_t
+tadd(t1, t2)
+const zic_t t1;
+const long t2;
+{
+ register zic_t t;
+
+ if (t1 == max_time && t2 > 0)
+ return max_time;
+ if (t1 == min_time && t2 < 0)
+ return min_time;
+ t = t1 + t2;
+ if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
+ error(_("time overflow"));
+ exit(EXIT_FAILURE);
+ }
+ return t;
+}
+
+/*
+** Given a rule, and a year, compute the date - in seconds since January 1,
+** 1970, 00:00 LOCAL time - in that year that the rule refers to.
+*/
+
+static zic_t
+rpytime(rp, wantedy)
+register const struct rule * const rp;
+register const int wantedy;
+{
+ register int y, m, i;
+ register long dayoff; /* with a nod to Margaret O. */
+ register zic_t t;
+
+ if (wantedy == INT_MIN)
+ return min_time;
+ if (wantedy == INT_MAX)
+ return max_time;
+ dayoff = 0;
+ m = TM_JANUARY;
+ y = EPOCH_YEAR;
+ while (wantedy != y) {
+ if (wantedy > y) {
+ i = len_years[isleap(y)];
+ ++y;
+ } else {
+ --y;
+ i = -len_years[isleap(y)];
+ }
+ dayoff = oadd(dayoff, eitol(i));
+ }
+ while (m != rp->r_month) {
+ i = len_months[isleap(y)][m];
+ dayoff = oadd(dayoff, eitol(i));
+ ++m;
+ }
+ i = rp->r_dayofmonth;
+ if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
+ if (rp->r_dycode == DC_DOWLEQ)
+ --i;
+ else {
+ error(_("use of 2/29 in non leap-year"));
+ exit(EXIT_FAILURE);
+ }
+ }
+ --i;
+ dayoff = oadd(dayoff, eitol(i));
+ if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
+ register long wday;
+
+#define LDAYSPERWEEK ((long) DAYSPERWEEK)
+ wday = eitol(EPOCH_WDAY);
+ /*
+ ** Don't trust mod of negative numbers.
+ */
+ if (dayoff >= 0)
+ wday = (wday + dayoff) % LDAYSPERWEEK;
+ else {
+ wday -= ((-dayoff) % LDAYSPERWEEK);
+ if (wday < 0)
+ wday += LDAYSPERWEEK;
+ }
+ while (wday != eitol(rp->r_wday))
+ if (rp->r_dycode == DC_DOWGEQ) {
+ dayoff = oadd(dayoff, (long) 1);
+ if (++wday >= LDAYSPERWEEK)
+ wday = 0;
+ ++i;
+ } else {
+ dayoff = oadd(dayoff, (long) -1);
+ if (--wday < 0)
+ wday = LDAYSPERWEEK - 1;
+ --i;
+ }
+ if (i < 0 || i >= len_months[isleap(y)][m]) {
+ if (noise)
+ warning(_("rule goes past start/end of month--\
+will not work with pre-2004 versions of zic"));
+ }
+ }
+ if (dayoff < min_time / SECSPERDAY)
+ return min_time;
+ if (dayoff > max_time / SECSPERDAY)
+ return max_time;
+ t = (zic_t) dayoff * SECSPERDAY;
+ return tadd(t, rp->r_tod);
+}
+
+static void
+newabbr(string)
+const char * const string;
+{
+ register int i;
+
+ if (strcmp(string, GRANDPARENTED) != 0) {
+ register const char * cp;
+ register char * wp;
+
+ /*
+ ** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
+ ** optionally followed by a + or - and a number from 1 to 14.
+ */
+ cp = string;
+ wp = NULL;
+ while (isascii((unsigned char) *cp) &&
+ isalpha((unsigned char) *cp))
+ ++cp;
+ if (cp - string == 0)
+wp = _("time zone abbreviation lacks alphabetic at start");
+ if (noise && cp - string > 3)
+wp = _("time zone abbreviation has more than 3 alphabetics");
+ if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
+wp = _("time zone abbreviation has too many alphabetics");
+ if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ ++cp;
+ if (isascii((unsigned char) *cp) &&
+ isdigit((unsigned char) *cp))
+ if (*cp++ == '1' &&
+ *cp >= '0' && *cp <= '4')
+ ++cp;
+ }
+ if (*cp != '\0')
+wp = _("time zone abbreviation differs from POSIX standard");
+ if (wp != NULL) {
+ wp = ecpyalloc(wp);
+ wp = ecatalloc(wp, " (");
+ wp = ecatalloc(wp, string);
+ wp = ecatalloc(wp, ")");
+ warning(wp);
+ ifree(wp);
+ }
+ }
+ i = strlen(string) + 1;
+ if (charcnt + i > TZ_MAX_CHARS) {
+ error(_("too many, or too long, time zone abbreviations"));
+ exit(EXIT_FAILURE);
+ }
+ (void) strcpy(&chars[charcnt], string);
+ charcnt += eitol(i);
+}
+
+static int
+mkdirs(argname)
+char * argname;
+{
+ register char * name;
+ register char * cp;
+
+ if (argname == NULL || *argname == '\0' || Dflag)
+ return 0;
+ cp = name = ecpyalloc(argname);
+ while ((cp = strchr(cp + 1, '/')) != 0) {
+ *cp = '\0';
+#ifndef unix
+ /*
+ ** DOS drive specifier?
+ */
+ if (isalpha((unsigned char) name[0]) &&
+ name[1] == ':' && name[2] == '\0') {
+ *cp = '/';
+ continue;
+ }
+#endif /* !defined unix */
+ if (!itsdir(name)) {
+ /*
+ ** It doesn't seem to exist, so we try to create it.
+ ** Creation may fail because of the directory being
+ ** created by some other multiprocessor, so we get
+ ** to do extra checking.
+ */
+ if (mkdir(name, MKDIR_UMASK) != 0
+ && (errno != EEXIST || !itsdir(name))) {
+ warn(_("can't create directory %s"), name);
+ ifree(name);
+ return -1;
+ }
+ }
+ *cp = '/';
+ }
+ ifree(name);
+ return 0;
+}
+
+static long
+eitol(i)
+const int i;
+{
+ long l;
+
+ l = i;
+ if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0))
+ errx(EXIT_FAILURE, _("%d did not sign extend correctly"), i);
+ return l;
+}
+
+#include <grp.h>
+#include <pwd.h>
+
+static void
+setgroup(flag, name)
+ gid_t *flag;
+ const char *name;
+{
+ struct group *gr;
+
+ if (*flag != (gid_t)-1)
+ errx(EXIT_FAILURE, _("multiple -g flags specified"));
+
+ gr = getgrnam(name);
+ if (gr == 0) {
+ char *ep;
+ unsigned long ul;
+
+ ul = strtoul(name, &ep, 10);
+ if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
+ *flag = ul;
+ return;
+ }
+ errx(EXIT_FAILURE, _("group `%s' not found"), name);
+ }
+ *flag = gr->gr_gid;
+}
+
+static void
+setuser(flag, name)
+ uid_t *flag;
+ const char *name;
+{
+ struct passwd *pw;
+
+ if (*flag != (gid_t)-1)
+ errx(EXIT_FAILURE, _("multiple -u flags specified"));
+
+ pw = getpwnam(name);
+ if (pw == 0) {
+ char *ep;
+ unsigned long ul;
+
+ ul = strtoul(name, &ep, 10);
+ if (ul == (unsigned long)(gid_t)ul && *ep == '\0') {
+ *flag = ul;
+ return;
+ }
+ errx(EXIT_FAILURE, _("user `%s' not found"), name);
+ }
+ *flag = pw->pw_uid;
+}
+
+/*
+** UNIX was a registered trademark of The Open Group in 2003.
+*/
diff --git a/system_cmds/zlog.tproj/SymbolicationHelper.c b/system_cmds/zlog.tproj/SymbolicationHelper.c
new file mode 100644
index 0000000..68a1285
--- /dev/null
+++ b/system_cmds/zlog.tproj/SymbolicationHelper.c
@@ -0,0 +1,181 @@
+//
+// SymbolicationHelper.c
+// zlog
+//
+// Created by Rasha Eqbal on 2/26/18.
+//
+
+#include "SymbolicationHelper.h"
+
+/*
+ * Most of the CoreSymbolication code here has been copied from ioclasscount in the IOKitTools project.
+ */
+
+#define kAddressKey CFSTR("Address")
+#define kNameKey CFSTR("Name")
+#define kPathKey CFSTR("Path")
+#define kSegmentsKey CFSTR("Segments")
+#define kSizeKey CFSTR("Size")
+#define kUuidKey CFSTR("UUID")
+
+static void AddSymbolOwnerSummary(CSSymbolOwnerRef owner, CFMutableDictionaryRef binaryImages);
+static void ShowBinaryImage(const void *key, const void *value, void *context);
+
+/*
+ * Symbolicates 'addr' using the 'symbolicator' passed in.
+ * Adds owner info to 'binaryImages' for offline symbolication.
+ *
+ * Top-level function that needs to be called on each frame address in the backtrace.
+ */
+void PrintSymbolicatedAddress(CSSymbolicatorRef symbolicator, mach_vm_address_t addr, CFMutableDictionaryRef binaryImages)
+{
+ printf("0x%llx", addr);
+
+ CSSymbolOwnerRef ownerInfo = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(symbolicator, addr, kCSNow);
+ if (!CSIsNull(ownerInfo)) {
+ const char *moduleName = CSSymbolOwnerGetName(ownerInfo);
+ if (moduleName) {
+ printf(" <%s>", moduleName);
+ }
+ }
+
+ CSSymbolRef symbolInfo = CSSymbolicatorGetSymbolWithAddressAtTime(symbolicator, addr, kCSNow);
+ if (!CSIsNull(symbolInfo)) {
+ printf(" %s", CSSymbolGetName(symbolInfo));
+ }
+
+ CSSourceInfoRef sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(symbolicator, addr, kCSNow);
+ if (!CSIsNull(sourceInfo)) {
+ const char *fileName = CSSourceInfoGetPath(sourceInfo);
+ if (fileName) {
+ printf(" at %s:%d", fileName, CSSourceInfoGetLineNumber(sourceInfo));
+ }
+ }
+ printf("\n");
+
+ AddSymbolOwnerSummary(ownerInfo, binaryImages);
+}
+
+/*
+ * Adds symbolication information for 'owner' to 'binaryImages' to help with offline symbolication.
+ *
+ * This is called from PrintSymbolicatedAddress() on the symbol owner for each address it symbolicates.
+ */
+static void AddSymbolOwnerSummary(CSSymbolOwnerRef owner, CFMutableDictionaryRef binaryImages)
+{
+ const CFUUIDBytes *uuidBytes = NULL;
+ CFUUIDRef uuid = NULL;
+ CFStringRef uuidString = NULL, path = NULL, name = NULL;
+ CFMutableDictionaryRef summaryDict = NULL;
+ __block CSSegmentRef textSegment = kCSNull, textExecSegment = kCSNull;
+ CSSegmentRef segment = kCSNull;
+ CSRange range;
+ CFNumberRef address = NULL, size = NULL;
+
+#define RETURN_IF_NULL(ptr) \
+if (!(ptr)) { \
+goto cleanup; \
+}
+
+ uuidBytes = CSSymbolOwnerGetCFUUIDBytes(owner);
+ if (uuidBytes) {
+ uuid = CFUUIDCreateFromUUIDBytes(NULL, *uuidBytes);
+ if (uuid) {
+ uuidString = CFUUIDCreateString(kCFAllocatorDefault, uuid);
+ }
+ }
+ RETURN_IF_NULL(uuidString);
+
+ if (!CFDictionaryContainsKey(binaryImages, uuidString)) {
+ summaryDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+ RETURN_IF_NULL(summaryDict);
+
+ CFDictionarySetValue(summaryDict, kUuidKey, uuidString);
+
+ path = CFStringCreateWithCString(kCFAllocatorDefault, CSSymbolOwnerGetPath(owner), kCFStringEncodingUTF8);
+ RETURN_IF_NULL(path);
+ CFDictionarySetValue(summaryDict, kPathKey, path);
+
+ name = CFStringCreateWithCString(kCFAllocatorDefault, CSSymbolOwnerGetName(owner), kCFStringEncodingUTF8);
+ RETURN_IF_NULL(name);
+ CFDictionarySetValue(summaryDict, kNameKey, name);
+
+ CSSymbolOwnerForeachSegment(owner, ^(CSSegmentRef segment) {
+ if (strcmp(CSRegionGetName(segment), "__TEXT SEGMENT") == 0) {
+ textSegment = segment;
+ CSRetain(textSegment);
+ } else if (strcmp(CSRegionGetName(segment), "__TEXT_EXEC SEGMENT") == 0) {
+ textExecSegment = segment;
+ CSRetain(textExecSegment);
+ }
+ });
+
+ segment = !CSIsNull(textExecSegment) ? textExecSegment : textSegment;
+ if (CSIsNull(segment)) {
+ goto cleanup;
+ }
+ range = CSRegionGetRange(segment);
+
+ address = CFNumberCreate(NULL, kCFNumberLongLongType, &range.location);
+ RETURN_IF_NULL(address);
+ CFDictionarySetValue(summaryDict, kAddressKey, address);
+
+ size = CFNumberCreate(NULL, kCFNumberLongLongType, &range.length);
+ RETURN_IF_NULL(size);
+ CFDictionarySetValue(summaryDict, kSizeKey, size);
+
+ CFDictionarySetValue(binaryImages, uuidString, summaryDict);
+ }
+
+cleanup:
+ if (size) CFRelease(size);
+ if (address) CFRelease(address);
+ if (!CSIsNull(textExecSegment)) CSRelease(textExecSegment);
+ if (!CSIsNull(textSegment)) CSRelease(textSegment);
+ if (name) CFRelease(name);
+ if (path) CFRelease(path);
+ if (summaryDict) CFRelease(summaryDict);
+ if (uuidString) CFRelease(uuidString);
+ if (uuid) CFRelease(uuid);
+}
+
+/*
+ * Prints offline symbolication information for the images passed in 'binaryImages'.
+ *
+ * Top-level function that needs to be called if the tool wants to include support
+ * for offline symbolication.
+ */
+void PrintBinaryImagesInfo(CFMutableDictionaryRef binaryImages)
+{
+ if (CFDictionaryGetCount(binaryImages) > 0) {
+ printf("\nBinary Images:\n");
+ CFDictionaryApplyFunction(binaryImages, ShowBinaryImage, NULL);
+ } else {
+ printf("No binary images\n");
+ }
+}
+
+/*
+ * Prints information about a binary image necessary for offline symbolication.
+ *
+ * This is called from PrintBinaryImagesInfo() on each element in 'binaryImages'.
+ */
+static void ShowBinaryImage(const void *key, const void *value, void *context)
+{
+ char nameString[256] = {0}, uuidString[256] = {0}, pathString[256] = {0};
+ CFStringRef uuid = (CFStringRef)key;
+ CFStringGetCString(uuid, uuidString, sizeof(uuidString), kCFStringEncodingASCII);
+ CFDictionaryRef summary = (CFDictionaryRef)value;
+
+ CFStringRef name = CFDictionaryGetValue(summary, kNameKey);
+ CFStringGetCString(name, nameString, sizeof(nameString), kCFStringEncodingASCII);
+ CFStringRef path = CFDictionaryGetValue(summary, kPathKey);
+ CFStringGetCString(path, pathString, sizeof(pathString), kCFStringEncodingASCII);
+ CFNumberRef addressNumber = CFDictionaryGetValue(summary, kAddressKey);
+ CFNumberRef sizeNumber = CFDictionaryGetValue(summary, kSizeKey);
+ int64_t address, size;
+ CFNumberGetValue(addressNumber, kCFNumberSInt64Type, &address);
+ CFNumberGetValue(sizeNumber, kCFNumberSInt64Type, &size);
+
+ printf("%p - %p %s <%s> %s\n", (void*)address, (void*)address + size, nameString, uuidString, pathString);
+}
diff --git a/system_cmds/zlog.tproj/SymbolicationHelper.h b/system_cmds/zlog.tproj/SymbolicationHelper.h
new file mode 100644
index 0000000..f9d90c5
--- /dev/null
+++ b/system_cmds/zlog.tproj/SymbolicationHelper.h
@@ -0,0 +1,35 @@
+//
+// SymbolicationHelper.h
+// zlog
+//
+// Created by Rasha Eqbal on 2/26/18.
+//
+
+#ifndef SymbolicationHelper_h
+#define SymbolicationHelper_h
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreSymbolication/CoreSymbolication.h>
+
+/*
+ * Call this function on each address that needs to be symbolicated.
+ *
+ * sym: The CSSymbolicatorRef which will be used for symbolication. For example, to symbolicate
+ * kernel addresses create a CSSymbolicatorRef by calling CSSymbolicatorCreateWithMachKernel().
+ * addr: The address that needs to be symbolicated.
+ * binaryImages: The dictionary that aggregates binary image info for offline symbolication.
+ */
+void PrintSymbolicatedAddress(CSSymbolicatorRef sym, mach_vm_address_t addr, CFMutableDictionaryRef binaryImages);
+
+/*
+ * Call this function to dump binary image info required for offline symbolication.
+ *
+ * binaryImages: The dictionary that stores this info.
+ *
+ * The preferred way to use this is to create a CFMutableDictionaryRef with a call to CFDictionaryCreateMutable()
+ * and pass it in to PrintSymbolicatedAddress() when symbolicating addresses. This will auto-populate the dictionary,
+ * which just needs to be passed in here to print the relevant information.
+ */
+void PrintBinaryImagesInfo(CFMutableDictionaryRef binaryImages);
+
+#endif /* SymbolicationHelper_h */
diff --git a/system_cmds/zlog.tproj/entitlements.plist b/system_cmds/zlog.tproj/entitlements.plist
new file mode 100644
index 0000000..600122d
--- /dev/null
+++ b/system_cmds/zlog.tproj/entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.private.kernel.get-kext-info</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/zlog.tproj/zlog.1 b/system_cmds/zlog.tproj/zlog.1
new file mode 100644
index 0000000..141caa9
--- /dev/null
+++ b/system_cmds/zlog.tproj/zlog.1
@@ -0,0 +1,56 @@
+.\" Copyright (c) 2018, Apple Inc. All rights reserved.
+.\"
+.Dd February 21, 2018
+.Dt ZLOG 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm zlog
+.Nd show allocation backtraces for kernel zones
+.Sh SYNOPSIS
+.Nm
+.Op Fl t
+.Op Fl z Ar name Op Fl n Ar num | Fl l
+.Op Fl h
+.Sh DESCRIPTION
+.Nm
+displays allocation (and free, if used in corruption tracking mode with
+the boot-arg "-zc") backtraces for zones that have zone logging enabled.
+Zone logging can be turned on by using the boot-arg "zlog<N>=<name>",
+where 'N' can range from 1 to 10, and 'name' is the name of the zone to
+be tracked.
+.Pp
+.Nm
+interprets the following options:
+.Pp
+.Bl -tag -width "disable -"
+.\" -t
+.It Fl t
+(Default) list all the zones that have logging enabled
+.\" -z
+.It Fl z Ar name
+show all allocation backtraces for zone
+.Ar name
+.\" -n
+.It Fl n Ar num
+Can be used in combination with the
+.Fl z
+option to show the top
+.Ar num
+backtraces with the most active references in the zone
+.Ar name
+.\" -l
+.It Fl l
+Can be used in combination with the
+.Fl z
+option to show the backtrace most likely contributing to a leak in the zone
+.Ar name
+(prints the backtrace with the most active references)
+.\" -h
+.It Fl h
+show the help text
+.El
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr zprint 1 ,
+.Xr ioclasscount 1
diff --git a/system_cmds/zlog.tproj/zlog.c b/system_cmds/zlog.tproj/zlog.c
new file mode 100644
index 0000000..c091120
--- /dev/null
+++ b/system_cmds/zlog.tproj/zlog.c
@@ -0,0 +1,257 @@
+//
+// zlog.c
+// zlog
+//
+// Created by Rasha Eqbal on 1/4/18.
+//
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/sysctl.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach_debug/mach_debug.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreSymbolication/CoreSymbolication.h>
+#include "SymbolicationHelper.h"
+
+extern kern_return_t
+mach_zone_get_btlog_records(host_priv_t host,
+ mach_zone_name_t name,
+ zone_btrecord_array_t *recsp,
+ mach_msg_type_number_t *recsCntp);
+extern kern_return_t
+mach_zone_get_zlog_zones(host_priv_t host,
+ mach_zone_name_array_t *namesp,
+ mach_msg_type_number_t *namesCntp);
+
+static int compare_zone_btrecords(const void *left, const void *right);
+static void usage(FILE *stream, char **argv);
+static void print_zone_info(const char *name);
+static void get_zone_btrecords(const char *name, int topN);
+static void list_zones_with_zlog_enabled(void);
+
+static void usage(FILE *stream, char **argv)
+{
+ fprintf (stream, "usage: %s [-t] [-z name [-n num | -l]] [-h]\n", argv[0]);
+ fprintf (stream, " -t : list all the zones that have logging enabled\n");
+ fprintf (stream, " -z <name> : show all allocation backtraces for zone <name>\n");
+ fprintf (stream, " -n <num> : show top <num> backtraces with the most active references in zone <name>\n");
+ fprintf (stream, " -l : show the backtrace most likely contributing to a leak in zone <name>\n");
+ fprintf (stream, " (prints the backtrace with the most active references)\n");
+ fprintf (stream, " -h : print this help text\n");
+ exit(stream != stdout);
+}
+
+static int compare_zone_btrecords(const void *left, const void *right)
+{
+ zone_btrecord_t *btl = (zone_btrecord_t *)left;
+ zone_btrecord_t *btr = (zone_btrecord_t *)right;
+
+ return (btr->ref_count - btl->ref_count);
+}
+
+static void print_zone_info(const char *name)
+{
+ mach_zone_name_t zname;
+ mach_zone_info_t zone_info;
+ kern_return_t kr;
+
+ strcpy(zname.mzn_name, name);
+ kr = mach_zone_info_for_zone(mach_host_self(), zname, &zone_info);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "error: call to mach_zone_info_for_zone() failed: %s\n", mach_error_string(kr));
+ exit(1);
+ }
+ printf("zone name : %s\n", name);
+ printf("element size (bytes) : %lld\n", zone_info.mzi_elem_size);
+ printf("in-use size (bytes) : %lld\n", zone_info.mzi_count * zone_info.mzi_elem_size);
+ printf("total size (bytes) : %lld\n", zone_info.mzi_cur_size);
+ printf("\n");
+}
+
+static void get_zone_btrecords(const char *name, int topN)
+{
+ kern_return_t kr;
+ int i, j, index;
+ mach_zone_name_t zname;
+ unsigned int recs_count = 0;
+ zone_btrecord_t *recs, *recs_addr = NULL;
+ CSSymbolicatorRef kernelSym;
+ CFMutableDictionaryRef binaryImages;
+
+ /* Create kernel symbolicator */
+ kernelSym = CSSymbolicatorCreateWithMachKernel();
+ if (CSIsNull(kernelSym)) {
+ fprintf(stderr, "error: CSSymbolicatorCreateWithMachKernel() returned NULL\n");
+ exit(1);
+ }
+ /* Create dictionary to collect binary image info for offline symbolication */
+ binaryImages = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+
+ /* Query the kernel for backtrace records */
+ strcpy(zname.mzn_name, name);
+ kr = mach_zone_get_btlog_records(mach_host_self(), zname, &recs_addr, &recs_count);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "error: call to mach_zone_get_btlog_records() failed: %s\n", mach_error_string(kr));
+ exit(1);
+ }
+
+ if (recs_count == 0) {
+ goto finish;
+ }
+
+ recs = recs_addr;
+ if (topN == 1) {
+ /* Print the backtrace with the highest no. of refs */
+ index = 0;
+ for (i = 0; i < recs_count; i++) {
+ if (recs[i].ref_count > recs[index].ref_count) {
+ index = i;
+ }
+ }
+ recs = recs_addr + index;
+ } else if (topN == 0) {
+ /* Print all backtraces */
+ topN = recs_count;
+ } else {
+ /* Sort the records by no. of refs, and print the top <topN> */
+ qsort(recs, recs_count, sizeof *recs, compare_zone_btrecords);
+ }
+
+ printf("printing top %d (out of %d) allocation backtrace(s) for zone %s\n", topN, recs_count, zname.mzn_name);
+
+ for (i = 0; i < topN; i++) {
+ printf("\nactive refs: %d operation type: %s\n", recs[i].ref_count,
+ (recs[i].operation_type == ZOP_ALLOC)? "ALLOC": (recs[i].operation_type == ZOP_FREE)? "FREE": "UNKNOWN");
+
+ for (j = 0; j < MAX_ZTRACE_DEPTH; j++) {
+ mach_vm_address_t addr = (mach_vm_address_t)recs[i].bt[j];
+ if (!addr) {
+ break;
+ }
+ PrintSymbolicatedAddress(kernelSym, addr, binaryImages);
+ }
+ }
+
+ /* Print relevant info for offline symbolication */
+ PrintBinaryImagesInfo(binaryImages);
+ CFRelease(binaryImages);
+
+finish:
+ if ((recs_addr != NULL) && (recs_count != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) recs_addr, (vm_size_t) (recs_count * sizeof *recs));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "call to vm_deallocate() failed: %s\n", mach_error_string(kr));
+ exit(1);
+ }
+ }
+ CSRelease(kernelSym);
+}
+
+static void list_zones_with_zlog_enabled(void)
+{
+ kern_return_t kr;
+ mach_zone_name_t *name = NULL;
+ unsigned int name_count = 0, i;
+
+ /* Get names for zones that have zone logging enabled */
+ kr = mach_zone_get_zlog_zones(mach_host_self(), &name, &name_count);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "error: call to mach_zone_get_zlog_zones() failed: %s\n", mach_error_string(kr));
+ exit(1);
+ }
+
+ if (name_count == 0) {
+ printf("zlog not enabled for any zones.\n");
+ } else {
+ printf("zlog enabled for zones...\n");
+ }
+
+ for (i = 0; i < name_count; i++) {
+ print_zone_info(name[i].mzn_name);
+ }
+
+ if ((name != NULL) && (name_count != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) name, (vm_size_t) (name_count * sizeof *name));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "call to vm_deallocate() failed: %s\n", mach_error_string(kr));
+ exit(1);
+ }
+ }
+}
+
+#define VERSION_STRING "zlog output version: 1"
+
+static void
+get_osversion(char *buffer, size_t buffer_len)
+{
+ int mib[] = {CTL_KERN, KERN_OSVERSION};
+ int ret;
+ ret = sysctl(mib, sizeof(mib) / sizeof(int), buffer, &buffer_len, NULL, 0);
+ if (ret != 0) {
+ strlcpy(buffer, "Unknown", buffer_len);
+ return;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int c, topN = 0;
+ const char *zone_name = NULL;
+
+ /* Identifier string for SpeedTracer parsing */
+ printf("%s\n\n", VERSION_STRING);
+ char version_buffer[32] = {0};
+ get_osversion(version_buffer, sizeof(version_buffer));
+ printf("Collected on build: %s\n\n", version_buffer);
+
+ if (argc == 1) {
+ /* default when no arguments are specified */
+ list_zones_with_zlog_enabled();
+ printf("Run 'zlog -h' for usage info.\n");
+ return 0;
+ }
+
+ while ((c = getopt(argc, argv, "tz:n:lh")) != -1) {
+ switch(c) {
+ case 't':
+ list_zones_with_zlog_enabled();
+ break;
+ case 'z':
+ zone_name = optarg;
+ break;
+ case 'n':
+ topN = atoi(optarg);
+ break;
+ case 'l':
+ topN = 1;
+ break;
+ case 'h':
+ usage(stdout, argv);
+ break;
+ case '?':
+ default:
+ usage(stderr, argv);
+ break;
+ }
+ }
+
+ if (optind < argc) {
+ usage(stderr, argv);
+ }
+
+ if (zone_name) {
+ print_zone_info(zone_name);
+ get_zone_btrecords(zone_name, topN);
+ } else {
+ /* -n or -l was specified without -z */
+ if (topN != 0) {
+ usage(stderr, argv);
+ }
+ }
+
+ return 0;
+}
diff --git a/system_cmds/zprint.tproj/entitlements.plist b/system_cmds/zprint.tproj/entitlements.plist
new file mode 100644
index 0000000..600122d
--- /dev/null
+++ b/system_cmds/zprint.tproj/entitlements.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.private.kernel.get-kext-info</key>
+ <true/>
+</dict>
+</plist>
diff --git a/system_cmds/zprint.tproj/test_zprint.lua b/system_cmds/zprint.tproj/test_zprint.lua
new file mode 100644
index 0000000..b46d6ca
--- /dev/null
+++ b/system_cmds/zprint.tproj/test_zprint.lua
@@ -0,0 +1,89 @@
+#!/usr/local/bin/recon
+
+local darwin = require 'darwin'
+local proc = require 'proc'
+local zprint = require 'zprint'
+
+if darwin.geteuid() ~= 0 then
+ io.stderr:write(arg[0], ': must be run as root (under sudo)\n')
+ os.exit(1)
+end
+
+local function test_output(zpout)
+ -- These should be present in the output of zprint.
+ local expectations = {
+ {
+ region = 'zones',
+ name = 'vm.pages',
+ }, {
+ region = 'tags',
+ name = 'VM_KERN_MEMORY_DIAG',
+ }, {
+ region = 'maps',
+ name = 'VM_KERN_COUNT_WIRED_STATIC_KERNELCACHE',
+ }, {
+ region = 'zone_views',
+ -- This ties the kernel's hands when it comes to naming.
+ name = 'data.kalloc.16[raw]',
+ }
+ }
+
+ local found_all = true
+ for i = 1, #expectations do
+ local region = expectations[i].region
+ local name = expectations[i].name
+ local iter = zprint[region]
+ if not iter then
+ io.stderr:write('zprint library has no iterator for ', region, '\n')
+ os.exit(4)
+ end
+
+ local found = false
+ for elt in zprint[region](zpout) do
+ if elt.name == name then
+ found = true
+ break
+ end
+ end
+ if found then
+ io.stdout:write('PASS: found ', name, ' in ', region, '\n')
+ else
+ io.stdout:write('FAIL: could not find ', name, ' in ', region, '\n')
+ found_all = false
+ end
+ end
+ return found_all
+end
+
+local function run_zprint(args)
+ if not args then
+ args = {}
+ end
+
+ table.insert(args, 1, 'zprint')
+ local zpout, err, status, code = proc.run(args)
+ if not zpout then
+ io.stderr:write(arg[0], ': failed to run zprint: ', err, '\n')
+ os.exit(2)
+ end
+
+ if code ~= 0 then
+ io.stderr:write(arg[0], ': zprint ', status, 'ed with code ', tostring(code),
+ ', stderr = ', err, '\n')
+ os.exit(3)
+ end
+ return zpout
+end
+
+local function run_and_test(...)
+ local zpout = run_zprint(table.pack(...))
+ local passed = test_output(zpout)
+ if not passed then
+ os.exit(5)
+ end
+end
+
+print("TEST: zprint output")
+run_and_test()
+print("\nTEST: zprint -t output")
+run_and_test("-t")
diff --git a/system_cmds/zprint.tproj/zprint.1 b/system_cmds/zprint.tproj/zprint.1
new file mode 100644
index 0000000..aa7c918
--- /dev/null
+++ b/system_cmds/zprint.tproj/zprint.1
@@ -0,0 +1,90 @@
+.\" Copyright (c) 2016, Apple Inc. All rights reserved.
+.\"
+.Dd 2 May 2016
+.Dt ZPRINT 1
+.Os "Mac OS X"
+.Sh NAME
+.Nm zprint
+.Nd show information about kernel zones
+.Sh SYNOPSIS
+.Nm
+.Op Fl cdhlLstw
+.Op Ar name
+.Sh DESCRIPTION
+.Nm
+displays data about Mach zones (allocation buckets). By default,
+.Nm
+will print out information about all Mach zones. If the optional
+.Ar name
+is specified,
+.Nm
+will print information about each zone for which
+.Ar name
+is a substring of the zone's name.
+.Pp
+.Nm
+interprets the following options:
+.Pp
+.Bl -tag -width "disable -"
+.\" -c
+.It Fl c
+(Default)
+.Nm
+prints zone info in columns. Long zone names are truncated with
+.Ql \&$ ,
+and spaces are replaced with
+.Ql \&. ,
+to allow for sorting by column. Pageable and collectible zones are shown with
+.Ql \&P
+and
+.Ql \&C
+on the far right, respectively. Zones with preposterously large maximum sizes
+are shown with
+.Ql ----
+in the max size and max num elts fields.
+.\" -d
+.It Fl d
+Display deltas over time, showing any zones that have achieved a new maximum
+current allocation size during the interval. If the total allocation sizes are
+being displayed for the zones in question, it will also display the deltas if
+the total allocations have doubled.
+.\" -h
+.It Fl h
+(Default) Shows headings for the columns printed with the
+.Fl c
+option. It may be useful to override this option when sorting by column.
+.\" -l
+.It Fl l
+(Default) Show all wired memory information after the zone information.
+.\" -L
+.It Fl L
+Do not show all wired memory information after the zone information.
+.\" -s
+.It Fl s
+.Nm
+sorts the zones, showing the zone wasting the most memory first.
+.\" -t
+.It Fl t
+For each zone,
+.Nm
+calculates the total size of allocations from the zone over the life of the
+zone.
+.\" -w
+.It Fl w
+For each zone,
+.Nm
+calculates how much space is allocated but not currently in use, the space
+wasted by the zone.
+.El
+.Pp
+Any option (including default options) can be overridden by specifying the
+option in upper-case; for example,
+.Fl C
+overrides the default option
+.Fl c .
+.Sh DIAGNOSTICS
+.Ex -std
+.Sh SEE ALSO
+.Xr ioclasscount 1 ,
+.Xr lsmp 1 ,
+.Xr lskq 1 ,
diff --git a/system_cmds/zprint.tproj/zprint.c b/system_cmds/zprint.tproj/zprint.c
new file mode 100644
index 0000000..5c90f2d
--- /dev/null
+++ b/system_cmds/zprint.tproj/zprint.c
@@ -0,0 +1,1092 @@
+/*
+ * Copyright (c) 2009-2016 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ *
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+/*
+ * @OSF_COPYRIGHT@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * zprint.c
+ *
+ * utility for printing out zone structures
+ *
+ * With no arguments, prints information on all zone structures.
+ * With an argument, prints information only on those zones for
+ * which the given name is a substring of the zone's name.
+ * With a "-w" flag, calculates how much much space is allocated
+ * to zones but not currently in use.
+ */
+
+#include <vm_statistics.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mach/mach.h>
+#include <mach_debug/mach_debug.h>
+#include <mach/mach_error.h>
+#include <libutil.h>
+#include <errno.h>
+#include <sysexits.h>
+#include <getopt.h>
+#include <malloc/malloc.h>
+#include <Kernel/IOKit/IOKitDebug.h>
+#include <Kernel/libkern/OSKextLibPrivate.h>
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOKitKeys.h>
+#include <IOKit/kext/OSKext.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreSymbolication/CoreSymbolication.h>
+
+#ifndef VM_KERN_SITE_ZONE_VIEW
+#define VM_KERN_SITE_ZONE_VIEW 0x00001000
+#endif
+
+#define streql(a, b) (strcmp((a), (b)) == 0)
+#define strneql(a, b, n) (strncmp((a), (b), (n)) == 0)
+#define PRINTK(fmt, value) \
+ printf(fmt "K", (value) / 1024 ) /* ick */
+
+static void usage(FILE *stream);
+static void printzone(mach_zone_name_t *, mach_zone_info_t *);
+static void colprintzone(mach_zone_name_t *, mach_zone_info_t *);
+static int find_deltas(mach_zone_name_t *, mach_zone_info_t *, mach_zone_info_t *, char *, int, int);
+static void colprintzoneheader(void);
+static boolean_t substr(const char *a, size_t alen, const char *b, size_t blen);
+
+static int SortName(void * thunk, const void * left, const void * right);
+static int SortSize(void * thunk, const void * left, const void * right);
+static void PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt,
+ mach_zone_info_t *zoneInfo, mach_zone_name_t *zoneNames,
+ unsigned int zoneCnt, uint64_t zoneElements,
+ int (*func)(void *, const void *, const void *), boolean_t column);
+
+static char *program;
+
+static boolean_t ShowDeltas = FALSE;
+static boolean_t ShowWasted = FALSE;
+static boolean_t ShowTotal = FALSE;
+static boolean_t ShowLarge = TRUE;
+static boolean_t SortZones = FALSE;
+static boolean_t ColFormat = TRUE;
+static boolean_t PrintHeader = TRUE;
+
+static unsigned long long totalsize = 0;
+static unsigned long long totalused = 0;
+static unsigned long long totalsum = 0;
+static unsigned long long totalfragmented = 0;
+static unsigned long long totalcollectable = 0;
+
+static int last_time = 0;
+
+static char *zname = NULL;
+static size_t znamelen = 0;
+
+#define LEFTALIGN -1
+#define RIGHTALIGN 1
+
+typedef struct {
+ char *line1;
+ char *line2;
+ int colwidth;
+ int alignment;
+ bool visible;
+} column_format;
+
+enum {
+ COL_ZONE_NAME,
+ COL_ELEM_SIZE,
+ COL_CUR_SIZE,
+ COL_MAX_SIZE,
+ COL_CUR_ELTS,
+ COL_MAX_ELTS,
+ COL_CUR_INUSE,
+ COL_ALLOC_SIZE,
+ COL_ALLOC_COUNT,
+ COL_ZONE_FLAGS,
+ COL_FRAG_SIZE,
+ COL_FREE_SIZE,
+ COL_TOTAL_ALLOCS,
+ COL_MAX
+};
+
+/*
+ * The order in which the columns appear below should match
+ * the order in which the values are printed in colprintzone().
+ */
+static column_format columns[] = {
+ [COL_ZONE_NAME] = { "", "zone name", 25, LEFTALIGN, true },
+ [COL_ELEM_SIZE] = { "elem", "size", 6, RIGHTALIGN, true },
+ [COL_CUR_SIZE] = { "cur", "size", 11, RIGHTALIGN, true },
+ [COL_MAX_SIZE] = { "max", "size", 11, RIGHTALIGN, true },
+ [COL_CUR_ELTS] = { "cur", "#elts", 10, RIGHTALIGN, true },
+ [COL_MAX_ELTS] = { "max", "#elts", 11, RIGHTALIGN, true },
+ [COL_CUR_INUSE] = { "cur", "inuse", 11, RIGHTALIGN, true },
+ [COL_ALLOC_SIZE] = { "alloc", "size", 6, RIGHTALIGN, true },
+ [COL_ALLOC_COUNT] = { "alloc", "count", 6, RIGHTALIGN, true },
+ [COL_ZONE_FLAGS] = { "", "", 2, RIGHTALIGN, true },
+ /* additional columns for special flags, not visible by default */
+ [COL_FRAG_SIZE] = { "frag", "size", 9, RIGHTALIGN, false },
+ [COL_FREE_SIZE] = { "free", "size", 9, RIGHTALIGN, false },
+ [COL_TOTAL_ALLOCS] = { "total", "allocs", 17, RIGHTALIGN, false }
+};
+
+static void
+sigintr(__unused int signum)
+{
+ last_time = 1;
+}
+
+static void
+usage(FILE *stream)
+{
+ fprintf(stream, "usage: %s [-w] [-s] [-c] [-h] [-H] [-t] [-d] [-l] [-L] [name]\n\n", program);
+ fprintf(stream, "\t-w\tshow wasted memory for each zone\n");
+ fprintf(stream, "\t-s\tsort zones by wasted memory\n");
+ fprintf(stream, "\t-c\t(default) display output formatted in columns\n");
+ fprintf(stream, "\t-h\tdisplay this help message\n");
+ fprintf(stream, "\t-H\thide column names\n");
+ fprintf(stream, "\t-t\tdisplay the total size of allocations over the life of the zone\n");
+ fprintf(stream, "\t-d\tdisplay deltas over time\n");
+ fprintf(stream, "\t-l\t(default) display wired memory info after zone info\n");
+ fprintf(stream, "\t-L\tdo not show wired memory info, only show zone info\n");
+ fprintf(stream, "\nAny option (including default options) can be overridden by specifying the option in upper-case.\n\n");
+ exit(stream != stdout);
+}
+
+int
+main(int argc, char **argv)
+{
+ mach_zone_name_t *name = NULL;
+ unsigned int nameCnt = 0;
+ mach_zone_info_t *info = NULL;
+ unsigned int infoCnt = 0;
+ mach_memory_info_t *wiredInfo = NULL;
+ unsigned int wiredInfoCnt = 0;
+ mach_zone_info_t *max_info = NULL;
+ char *deltas = NULL;
+ uint64_t zoneElements;
+
+ kern_return_t kr;
+ int i, j;
+ int first_time = 1;
+ int must_print = 1;
+ int interval = 1;
+
+ signal(SIGINT, sigintr);
+
+ program = strrchr(argv[0], '/');
+ if (program == NULL) {
+ program = argv[0];
+ } else {
+ program++;
+ }
+
+ for (i = 1; i < argc; i++) {
+ if (streql(argv[i], "-d")) {
+ ShowDeltas = TRUE;
+ } else if (streql(argv[i], "-t")) {
+ ShowTotal = TRUE;
+ } else if (streql(argv[i], "-T")) {
+ ShowTotal = FALSE;
+ } else if (streql(argv[i], "-w")) {
+ ShowWasted = TRUE;
+ } else if (streql(argv[i], "-W")) {
+ ShowWasted = FALSE;
+ } else if (streql(argv[i], "-l")) {
+ ShowLarge = TRUE;
+ } else if (streql(argv[i], "-L")) {
+ ShowLarge = FALSE;
+ } else if (streql(argv[i], "-s")) {
+ SortZones = TRUE;
+ } else if (streql(argv[i], "-S")) {
+ SortZones = FALSE;
+ } else if (streql(argv[i], "-c")) {
+ ColFormat = TRUE;
+ } else if (streql(argv[i], "-C")) {
+ ColFormat = FALSE;
+ } else if (streql(argv[i], "-h")) {
+ usage(stdout);
+ } else if (streql(argv[i], "-H")) {
+ PrintHeader = FALSE;
+ } else if (streql(argv[i], "--")) {
+ i++;
+ break;
+ } else if (argv[i][0] == '-') {
+ usage(stderr);
+ } else {
+ break;
+ }
+ }
+
+ switch (argc - i) {
+ case 0:
+ zname = "";
+ znamelen = 0;
+ break;
+
+ case 1:
+ zname = argv[i];
+ znamelen = strlen(zname);
+ break;
+
+ default:
+ usage(stderr);
+ }
+
+ if (ShowDeltas) {
+ SortZones = FALSE;
+ ColFormat = TRUE;
+ PrintHeader = TRUE;
+ }
+
+ if (ShowWasted) {
+ columns[COL_FRAG_SIZE].visible = true;
+ columns[COL_FREE_SIZE].visible = true;
+ }
+ if (ShowTotal) {
+ columns[COL_TOTAL_ALLOCS].visible = true;
+ }
+
+ for (;;) {
+ kr = mach_memory_info(mach_host_self(),
+ &name, &nameCnt, &info, &infoCnt,
+ &wiredInfo, &wiredInfoCnt);
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: mach_memory_info: %s (try running as root)\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+
+ if (nameCnt != infoCnt) {
+ fprintf(stderr, "%s: mach_zone_name/ mach_zone_info: counts not equal?\n",
+ program);
+ exit(1);
+ }
+
+ if (first_time) {
+ deltas = (char *)malloc(infoCnt);
+ max_info = (mach_zone_info_t *)malloc((infoCnt * sizeof *info));
+ }
+
+ if (SortZones) {
+ for (i = 0; i < nameCnt - 1; i++) {
+ for (j = i + 1; j < nameCnt; j++) {
+ unsigned long long wastei, wastej;
+
+ wastei = (info[i].mzi_cur_size -
+ (info[i].mzi_elem_size *
+ info[i].mzi_count));
+ wastej = (info[j].mzi_cur_size -
+ (info[j].mzi_elem_size *
+ info[j].mzi_count));
+
+ if (wastej > wastei) {
+ mach_zone_info_t tinfo;
+ mach_zone_name_t tname;
+
+ tinfo = info[i];
+ info[i] = info[j];
+ info[j] = tinfo;
+
+ tname = name[i];
+ name[i] = name[j];
+ name[j] = tname;
+ }
+ }
+ }
+ }
+
+ must_print = find_deltas(name, info, max_info, deltas, infoCnt, first_time);
+ zoneElements = 0;
+ if (must_print) {
+ if (ColFormat) {
+ if (!first_time) {
+ printf("\n");
+ }
+ colprintzoneheader();
+ }
+ for (i = 0; i < nameCnt; i++) {
+ if (deltas[i]) {
+ if (ColFormat) {
+ colprintzone(&name[i], &info[i]);
+ } else {
+ printzone(&name[i], &info[i]);
+ }
+ zoneElements += info[i].mzi_count;
+ }
+ }
+ }
+
+ if (ShowLarge && first_time) {
+ PrintLarge(wiredInfo, wiredInfoCnt, &info[0], &name[0],
+ nameCnt, zoneElements,
+ SortZones ? &SortSize : &SortName, ColFormat);
+ }
+
+ first_time = 0;
+
+ if ((name != NULL) && (nameCnt != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) name,
+ (vm_size_t) (nameCnt * sizeof *name));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: vm_deallocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ if ((info != NULL) && (infoCnt != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) info,
+ (vm_size_t) (infoCnt * sizeof *info));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: vm_deallocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ if ((wiredInfo != NULL) && (wiredInfoCnt != 0)) {
+ kr = vm_deallocate(mach_task_self(), (vm_address_t) wiredInfo,
+ (vm_size_t) (wiredInfoCnt * sizeof *wiredInfo));
+ if (kr != KERN_SUCCESS) {
+ fprintf(stderr, "%s: vm_deallocate: %s\n",
+ program, mach_error_string(kr));
+ exit(1);
+ }
+ }
+
+ if ((ShowWasted || ShowTotal) && PrintHeader && !ShowDeltas) {
+ printf("\nZONE TOTALS\n");
+ printf("---------------------------------------------\n");
+ printf("TOTAL SIZE = %llu\n", totalsize);
+ printf("TOTAL USED = %llu\n", totalused);
+ if (ShowWasted) {
+ printf("TOTAL WASTED = %llu\n", totalsize - totalused);
+ printf("TOTAL FRAGMENTED = %llu\n", totalfragmented);
+ printf("TOTAL COLLECTABLE = %llu\n", totalcollectable);
+ }
+ if (ShowTotal) {
+ printf("TOTAL ALLOCS = %llu\n", totalsum);
+ }
+ }
+
+ if (ShowDeltas == FALSE || last_time) {
+ break;
+ }
+
+ sleep(interval);
+ }
+ exit(0);
+}
+
+static boolean_t
+substr(const char *a, size_t alen, const char *b, size_t blen)
+{
+ int i;
+
+ if (alen > blen) {
+ return FALSE;
+ }
+
+ for (i = 0; i <= blen - alen; i++) {
+ if (strneql(a, b + i, alen)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
+printzone(mach_zone_name_t *name, mach_zone_info_t *info)
+{
+ unsigned long long used, size, fragmented, collectable;
+
+ printf("%.*s zone:\n", (int)sizeof name->mzn_name, name->mzn_name);
+ printf("\tcur_size: %lluK bytes (%llu elements)\n",
+ info->mzi_cur_size / 1024,
+ (info->mzi_elem_size == 0) ? 0 :
+ info->mzi_cur_size / info->mzi_elem_size);
+ printf("\tmax_size: %lluK bytes (%llu elements)\n",
+ info->mzi_max_size / 1024,
+ (info->mzi_elem_size == 0) ? 0 :
+ info->mzi_max_size / info->mzi_elem_size);
+ printf("\telem_size: %llu bytes\n",
+ info->mzi_elem_size);
+ printf("\t# of elems: %llu\n",
+ info->mzi_count);
+ printf("\talloc_size: %lluK bytes (%llu elements)\n",
+ info->mzi_alloc_size / 1024,
+ (info->mzi_elem_size == 0) ? 0 :
+ info->mzi_alloc_size / info->mzi_elem_size);
+ if (info->mzi_exhaustible) {
+ printf("\tEXHAUSTIBLE\n");
+ }
+ if (GET_MZI_COLLECTABLE_FLAG(info->mzi_collectable)) {
+ printf("\tCOLLECTABLE\n");
+ }
+ if (ShowWasted) {
+ totalused += used = info->mzi_elem_size * info->mzi_count;
+ totalsize += size = info->mzi_cur_size;
+ totalcollectable += collectable = GET_MZI_COLLECTABLE_BYTES(info->mzi_collectable);
+ totalfragmented += fragmented = size - used - collectable;
+ printf("\t\t\t\t\tWASTED: %llu\n", size - used);
+ printf("\t\t\t\t\tFRAGMENTED: %llu\n", fragmented);
+ printf("\t\t\t\t\tCOLLECTABLE: %llu\n", collectable);
+ }
+ if (ShowTotal) {
+ totalsum += info->mzi_sum_size;
+ printf("\t\t\t\t\tTOTAL: %llu\n", totalsum);
+ }
+}
+
+static void
+colprintzone(mach_zone_name_t *zone_name, mach_zone_info_t *info)
+{
+ char *name = zone_name->mzn_name;
+ int j, namewidth;
+ unsigned long long used, size, fragmented, collectable;
+
+ namewidth = columns[COL_ZONE_NAME].colwidth;
+
+ for (j = 0; j < namewidth - 1 && name[j]; j++) {
+ if (name[j] == ' ') {
+ putchar('.');
+ } else {
+ putchar(name[j]);
+ }
+ }
+ if (j == namewidth - 1) {
+ if (name[j]) {
+ putchar('$');
+ } else {
+ putchar(' ');
+ }
+ } else {
+ for (; j < namewidth; j++) {
+ putchar(' ');
+ }
+ }
+
+
+#define PRINTCOL(value, index) \
+ if (columns[(index)].visible) { \
+ printf(" %*llu", columns[(index)].colwidth * columns[(index)].alignment, (value)); \
+ }
+#define PRINTCOLSTR(value, index) \
+ if (columns[(index)].visible) { \
+ printf(" %*s", columns[(index)].colwidth * columns[(index)].alignment, (value)); \
+ }
+#define PRINTCOLK(value, index) \
+ if (columns[(index)].visible) { \
+ printf(" %*lluK", (columns[(index)].colwidth - 1) * columns[(index)].alignment, (value) / 1024 ); \
+ }
+#define PRINTCOLSZ(value, index) \
+ if (columns[(index)].visible) { \
+ if ((value) < 1024) { \
+ printf(" %*lluB", (columns[(index)].colwidth - 1) * columns[(index)].alignment, (value)); \
+ } else { \
+ PRINTCOLK(value, index) \
+ } \
+ }
+
+
+ PRINTCOL(info->mzi_elem_size, COL_ELEM_SIZE);
+ PRINTCOLK(info->mzi_cur_size, COL_CUR_SIZE);
+ if (info->mzi_max_size / 1024 > 9999999) {
+ /*
+ * Zones with preposterously large maximum sizes are shown with `-------'
+ * in the max size and max num elts fields.
+ */
+ PRINTCOLSTR("-------", COL_MAX_SIZE);
+ } else {
+ PRINTCOLK(info->mzi_max_size, COL_MAX_SIZE);
+ }
+ PRINTCOL(info->mzi_cur_size / info->mzi_elem_size, COL_CUR_ELTS);
+ if (info->mzi_max_size / 1024 > 9999999) {
+ PRINTCOLSTR("-------", COL_MAX_ELTS);
+ } else {
+ PRINTCOL(info->mzi_max_size / info->mzi_elem_size, COL_MAX_ELTS);
+ }
+ PRINTCOL(info->mzi_count, COL_CUR_INUSE);
+ PRINTCOLK(info->mzi_alloc_size, COL_ALLOC_SIZE);
+ PRINTCOL(info->mzi_alloc_size / info->mzi_elem_size, COL_ALLOC_COUNT);
+
+ totalused += used = info->mzi_elem_size * info->mzi_count;
+ totalsize += size = info->mzi_cur_size;
+ totalsum += info->mzi_sum_size;
+ totalcollectable += collectable = GET_MZI_COLLECTABLE_BYTES(info->mzi_collectable);
+ totalfragmented += fragmented = size - used - collectable;
+
+ printf(" %c%c",
+ (info->mzi_exhaustible ? 'X' : ' '),
+ (GET_MZI_COLLECTABLE_FLAG(info->mzi_collectable) ? 'C' : ' '));
+
+ PRINTCOLSZ(fragmented, COL_FRAG_SIZE);
+ PRINTCOLSZ(collectable, COL_FREE_SIZE);
+ PRINTCOLSZ(info->mzi_sum_size, COL_TOTAL_ALLOCS);
+
+ printf("\n");
+}
+
+
+static void
+colprintzoneheader(void)
+{
+ int i, totalwidth = 0;
+
+ if (!PrintHeader) {
+ return;
+ }
+
+ for (i = 0; i < COL_MAX; i++) {
+ if (columns[i].visible) {
+ printf("%*s ", columns[i].colwidth * columns[i].alignment, columns[i].line1);
+ }
+ }
+ printf("\n");
+
+ for (i = 0; i < COL_MAX; i++) {
+ if (columns[i].visible) {
+ printf("%*s ", columns[i].colwidth * columns[i].alignment, columns[i].line2);
+ totalwidth += (columns[i].colwidth + 1);
+ }
+ }
+
+ printf("\n");
+ for (i = 0; i < totalwidth; i++) {
+ printf("-");
+ }
+ printf("\n");
+}
+
+int
+find_deltas(mach_zone_name_t *name, mach_zone_info_t *info, mach_zone_info_t *max_info,
+ char *deltas, int cnt, int first_time)
+{
+ int i;
+ int found_one = 0;
+
+ for (i = 0; i < cnt; i++) {
+ deltas[i] = 0;
+ if (substr(zname, znamelen, name[i].mzn_name,
+ strnlen(name[i].mzn_name, sizeof name[i].mzn_name))) {
+ if (first_time || info->mzi_cur_size > max_info->mzi_cur_size ||
+ (ShowTotal && ((info->mzi_sum_size >> 1) > max_info->mzi_sum_size))) {
+ max_info->mzi_cur_size = info->mzi_cur_size;
+ max_info->mzi_sum_size = info->mzi_sum_size;
+ deltas[i] = 1;
+ found_one = 1;
+ }
+ }
+ info++;
+ max_info++;
+ }
+ return found_one;
+}
+
+/*********************************************************************
+*********************************************************************/
+
+static char *
+kern_vm_tag_name(uint64_t tag)
+{
+ char * result;
+ const char * name;
+ switch (tag) {
+ case (VM_KERN_MEMORY_NONE): name = "VM_KERN_MEMORY_NONE"; break;
+ case (VM_KERN_MEMORY_OSFMK): name = "VM_KERN_MEMORY_OSFMK"; break;
+ case (VM_KERN_MEMORY_BSD): name = "VM_KERN_MEMORY_BSD"; break;
+ case (VM_KERN_MEMORY_IOKIT): name = "VM_KERN_MEMORY_IOKIT"; break;
+ case (VM_KERN_MEMORY_LIBKERN): name = "VM_KERN_MEMORY_LIBKERN"; break;
+ case (VM_KERN_MEMORY_OSKEXT): name = "VM_KERN_MEMORY_OSKEXT"; break;
+ case (VM_KERN_MEMORY_KEXT): name = "VM_KERN_MEMORY_KEXT"; break;
+ case (VM_KERN_MEMORY_IPC): name = "VM_KERN_MEMORY_IPC"; break;
+ case (VM_KERN_MEMORY_STACK): name = "VM_KERN_MEMORY_STACK"; break;
+ case (VM_KERN_MEMORY_CPU): name = "VM_KERN_MEMORY_CPU"; break;
+ case (VM_KERN_MEMORY_PMAP): name = "VM_KERN_MEMORY_PMAP"; break;
+ case (VM_KERN_MEMORY_PTE): name = "VM_KERN_MEMORY_PTE"; break;
+ case (VM_KERN_MEMORY_ZONE): name = "VM_KERN_MEMORY_ZONE"; break;
+ case (VM_KERN_MEMORY_KALLOC): name = "VM_KERN_MEMORY_KALLOC"; break;
+ case (VM_KERN_MEMORY_COMPRESSOR): name = "VM_KERN_MEMORY_COMPRESSOR"; break;
+ case (VM_KERN_MEMORY_COMPRESSED_DATA): name = "VM_KERN_MEMORY_COMPRESSED_DATA"; break;
+ case (VM_KERN_MEMORY_PHANTOM_CACHE): name = "VM_KERN_MEMORY_PHANTOM_CACHE"; break;
+ case (VM_KERN_MEMORY_WAITQ): name = "VM_KERN_MEMORY_WAITQ"; break;
+ case (VM_KERN_MEMORY_DIAG): name = "VM_KERN_MEMORY_DIAG"; break;
+ case (VM_KERN_MEMORY_LOG): name = "VM_KERN_MEMORY_LOG"; break;
+ case (VM_KERN_MEMORY_FILE): name = "VM_KERN_MEMORY_FILE"; break;
+ case (VM_KERN_MEMORY_MBUF): name = "VM_KERN_MEMORY_MBUF"; break;
+ case (VM_KERN_MEMORY_UBC): name = "VM_KERN_MEMORY_UBC"; break;
+ case (VM_KERN_MEMORY_SECURITY): name = "VM_KERN_MEMORY_SECURITY"; break;
+ case (VM_KERN_MEMORY_MLOCK): name = "VM_KERN_MEMORY_MLOCK"; break;
+ case (VM_KERN_MEMORY_REASON): name = "VM_KERN_MEMORY_REASON"; break;
+ case (VM_KERN_MEMORY_SKYWALK): name = "VM_KERN_MEMORY_SKYWALK"; break;
+ case (VM_KERN_MEMORY_LTABLE): name = "VM_KERN_MEMORY_LTABLE"; break;
+ case (VM_KERN_MEMORY_ANY): name = "VM_KERN_MEMORY_ANY"; break;
+ default: name = NULL; break;
+ }
+ if (name) {
+ asprintf(&result, "%s", name);
+ } else {
+ asprintf(&result, "VM_KERN_MEMORY_%lld", tag);
+ }
+ return result;
+}
+
+static char *
+kern_vm_counter_name(uint64_t tag)
+{
+ char * result;
+ const char * name;
+ switch (tag) {
+ case (VM_KERN_COUNT_MANAGED): name = "VM_KERN_COUNT_MANAGED"; break;
+ case (VM_KERN_COUNT_RESERVED): name = "VM_KERN_COUNT_RESERVED"; break;
+ case (VM_KERN_COUNT_WIRED): name = "VM_KERN_COUNT_WIRED"; break;
+ case (VM_KERN_COUNT_WIRED_BOOT): name = "VM_KERN_COUNT_WIRED_BOOT"; break;
+ case (VM_KERN_COUNT_WIRED_MANAGED): name = "VM_KERN_COUNT_WIRED_MANAGED"; break;
+ case (VM_KERN_COUNT_STOLEN): name = "VM_KERN_COUNT_STOLEN"; break;
+ case (VM_KERN_COUNT_BOOT_STOLEN): name = "VM_KERN_COUNT_BOOT_STOLEN"; break;
+ case (VM_KERN_COUNT_LOPAGE): name = "VM_KERN_COUNT_LOPAGE"; break;
+ case (VM_KERN_COUNT_MAP_KERNEL): name = "VM_KERN_COUNT_MAP_KERNEL"; break;
+ case (VM_KERN_COUNT_MAP_ZONE): name = "VM_KERN_COUNT_MAP_ZONE"; break;
+ case (VM_KERN_COUNT_MAP_KALLOC): name = "VM_KERN_COUNT_MAP_KALLOC"; break;
+ case (VM_KERN_COUNT_WIRED_STATIC_KERNELCACHE):
+ name = "VM_KERN_COUNT_WIRED_STATIC_KERNELCACHE";
+ break;
+ default: name = NULL; break;
+ }
+ if (name) {
+ asprintf(&result, "%s", name);
+ } else {
+ asprintf(&result, "VM_KERN_COUNT_%lld", tag);
+ }
+ return result;
+}
+
+static void
+MakeLoadTagKeys(const void * key, const void * value, void * context)
+{
+ CFMutableDictionaryRef newDict = context;
+ CFDictionaryRef kextInfo = value;
+ CFNumberRef loadTag;
+ uint32_t loadTagValue;
+
+ loadTag = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleLoadTagKey));
+ CFNumberGetValue(loadTag, kCFNumberSInt32Type, &loadTagValue);
+ key = (const void *)(uintptr_t) loadTagValue;
+ CFDictionarySetValue(newDict, key, value);
+}
+
+static CSSymbolicatorRef gSym;
+static CFMutableDictionaryRef gTagDict;
+static mach_memory_info_t * gSites;
+
+static char *
+GetSiteName(int siteIdx, mach_zone_name_t * zoneNames, unsigned int zoneNamesCnt)
+{
+ const char * name;
+ uintptr_t kmodid;
+ char * result;
+ char * append;
+ mach_vm_address_t addr;
+ CFDictionaryRef kextInfo;
+ CFStringRef bundleID;
+ uint32_t type;
+
+ const mach_memory_info_t * site;
+ const char * fileName;
+ CSSymbolRef symbol;
+ const char * symbolName;
+ CSSourceInfoRef sourceInfo;
+
+ name = NULL;
+ result = NULL;
+ site = &gSites[siteIdx];
+ addr = site->site;
+ type = (VM_KERN_SITE_TYPE & site->flags);
+ kmodid = 0;
+
+ if (VM_KERN_SITE_NAMED & site->flags) {
+ asprintf(&result, "%s", &site->name[0]);
+ } else {
+ switch (type) {
+ case VM_KERN_SITE_TAG:
+ result = kern_vm_tag_name(addr);
+ break;
+
+ case VM_KERN_SITE_COUNTER:
+ result = kern_vm_counter_name(addr);
+ break;
+
+ case VM_KERN_SITE_KMOD:
+
+ kmodid = (uintptr_t) addr;
+ kextInfo = CFDictionaryGetValue(gTagDict, (const void *)kmodid);
+ if (kextInfo) {
+ bundleID = (CFStringRef)CFDictionaryGetValue(kextInfo, kCFBundleIdentifierKey);
+ name = CFStringGetCStringPtr(bundleID, kCFStringEncodingUTF8);
+ // wiredSize = (CFNumberRef)CFDictionaryGetValue(kextInfo, CFSTR(kOSBundleWiredSizeKey));
+ }
+
+ if (name) {
+ asprintf(&result, "%s", name);
+ } else {
+ asprintf(&result, "(unloaded kmod)");
+ }
+ break;
+
+ case VM_KERN_SITE_KERNEL:
+ symbolName = NULL;
+ if (addr) {
+ symbol = CSSymbolicatorGetSymbolWithAddressAtTime(gSym, addr, kCSNow);
+ symbolName = CSSymbolGetName(symbol);
+ }
+ if (symbolName) {
+ asprintf(&result, "%s", symbolName);
+ sourceInfo = CSSymbolicatorGetSourceInfoWithAddressAtTime(gSym, addr, kCSNow);
+ fileName = CSSourceInfoGetPath(sourceInfo);
+ if (fileName) {
+ printf(" (%s:%d)", fileName, CSSourceInfoGetLineNumber(sourceInfo));
+ }
+ } else {
+ asprintf(&result, "site 0x%qx", addr);
+ }
+ break;
+ default:
+ asprintf(&result, "");
+ break;
+ }
+ }
+
+ if (result
+ && (VM_KERN_SITE_ZONE & site->flags)
+ && zoneNames
+ && (site->zone < zoneNamesCnt)) {
+ size_t namelen, zonelen;
+ namelen = strlen(result);
+ zonelen = strnlen(zoneNames[site->zone].mzn_name, sizeof(zoneNames[site->zone].mzn_name));
+ if (((namelen + zonelen) > 61) && (zonelen < 61)) {
+ namelen = (61 - zonelen);
+ }
+ asprintf(&append, "%.*s[%.*s]",
+ (int)namelen,
+ result,
+ (int)zonelen,
+ zoneNames[site->zone].mzn_name);
+ free(result);
+ result = append;
+ }
+ if (result && kmodid) {
+ asprintf(&append, "%-64s%3ld", result, kmodid);
+ free(result);
+ result = append;
+ }
+
+ return result;
+}
+
+struct CompareThunk {
+ mach_zone_name_t *zoneNames;
+ unsigned int zoneNamesCnt;
+};
+
+static int
+SortName(void * thunk, const void * left, const void * right)
+{
+ const struct CompareThunk * t = (typeof(t))thunk;
+ const int * idxL;
+ const int * idxR;
+ char * l;
+ char * r;
+ CFStringRef lcf;
+ CFStringRef rcf;
+ int result;
+
+ idxL = (typeof(idxL))left;
+ idxR = (typeof(idxR))right;
+ l = GetSiteName(*idxL, t->zoneNames, t->zoneNamesCnt);
+ r = GetSiteName(*idxR, t->zoneNames, t->zoneNamesCnt);
+
+ lcf = CFStringCreateWithCString(kCFAllocatorDefault, l, kCFStringEncodingUTF8);
+ rcf = CFStringCreateWithCString(kCFAllocatorDefault, r, kCFStringEncodingUTF8);
+
+ result = (int) CFStringCompareWithOptionsAndLocale(lcf, rcf, CFRangeMake(0, CFStringGetLength(lcf)), kCFCompareNumerically, NULL);
+
+ CFRelease(lcf);
+ CFRelease(rcf);
+ free(l);
+ free(r);
+
+ return result;
+}
+
+static int
+SortSize(void * thunk, const void * left, const void * right)
+{
+ const mach_memory_info_t * siteL;
+ const mach_memory_info_t * siteR;
+ const int * idxL;
+ const int * idxR;
+
+ idxL = (typeof(idxL))left;
+ idxR = (typeof(idxR))right;
+ siteL = &gSites[*idxL];
+ siteR = &gSites[*idxR];
+
+ if (siteL->size > siteR->size) {
+ return -1;
+ } else if (siteL->size < siteR->size) {
+ return 1;
+ }
+ return 0;
+}
+
+
+static void
+PrintLarge(mach_memory_info_t *wiredInfo, unsigned int wiredInfoCnt,
+ mach_zone_info_t *zoneInfo, mach_zone_name_t *zoneNames,
+ unsigned int zoneCnt, uint64_t zoneElements,
+ int (*func)(void *, const void *, const void *), boolean_t column)
+{
+ uint64_t zonetotal;
+ uint64_t top_wired;
+ uint64_t size;
+ uint64_t elemsTagged;
+
+ CFDictionaryRef allKexts;
+ unsigned int idx, site, first;
+ int sorted[wiredInfoCnt];
+ char totalstr[40];
+ char * name;
+ bool headerPrinted;
+
+ zonetotal = totalsize;
+
+ gSites = wiredInfo;
+
+ gSym = CSSymbolicatorCreateWithMachKernel();
+
+ allKexts = OSKextCopyLoadedKextInfo(NULL, NULL);
+ gTagDict = CFDictionaryCreateMutable(
+ kCFAllocatorDefault, (CFIndex) 0,
+ (CFDictionaryKeyCallBacks *) 0,
+ &kCFTypeDictionaryValueCallBacks);
+
+ CFDictionaryApplyFunction(allKexts, &MakeLoadTagKeys, gTagDict);
+ CFRelease(allKexts);
+
+ top_wired = 0;
+
+ for (idx = 0; idx < wiredInfoCnt; idx++) {
+ sorted[idx] = idx;
+ }
+ first = 0; // VM_KERN_MEMORY_FIRST_DYNAMIC
+ struct CompareThunk thunk;
+ thunk.zoneNames = zoneNames;
+ thunk.zoneNamesCnt = zoneCnt;
+ qsort_r(&sorted[first],
+ wiredInfoCnt - first,
+ sizeof(sorted[0]),
+ &thunk,
+ func);
+
+ elemsTagged = 0;
+ for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) {
+ site = sorted[idx];
+ if ((VM_KERN_SITE_COUNTER & gSites[site].flags)
+ && (VM_KERN_COUNT_WIRED == gSites[site].site)) {
+ top_wired = gSites[site].size;
+ }
+ if (VM_KERN_SITE_HIDE & gSites[site].flags) {
+ continue;
+ }
+ if (!((VM_KERN_SITE_WIRED | VM_KERN_SITE_ZONE) & gSites[site].flags)) {
+ continue;
+ }
+
+ if ((VM_KERN_SITE_ZONE & gSites[site].flags)
+ && gSites[site].zone < zoneCnt) {
+ elemsTagged += gSites[site].size / zoneInfo[gSites[site].zone].mzi_elem_size;
+ }
+
+ if ((gSites[site].size < 1024) && (gSites[site].peak < 1024)) {
+ continue;
+ }
+
+ name = GetSiteName(site, zoneNames, zoneCnt);
+ if (!substr(zname, znamelen, name, strlen(name))) {
+ continue;
+ }
+ if (!headerPrinted) {
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ printf(" kmod vm peak cur\n");
+ printf("wired memory id tag size waste size\n");
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ headerPrinted = true;
+ }
+ printf("%-67s", name);
+ free(name);
+ printf("%12d", gSites[site].tag);
+
+ if (gSites[site].peak) {
+ PRINTK(" %10llu", gSites[site].peak);
+ } else {
+ printf(" %11s", "");
+ }
+
+ if (gSites[site].collectable_bytes) {
+ PRINTK(" %5llu", gSites[site].collectable_bytes);
+ } else {
+ printf(" %6s", "");
+ }
+
+ PRINTK(" %9llu", gSites[site].size);
+
+ if (!(VM_KERN_SITE_ZONE & gSites[site].flags)) {
+ totalsize += gSites[site].size;
+ }
+
+ printf("\n");
+ }
+
+ if (!znamelen) {
+ printf("%-67s", "zones");
+ printf("%12s", "");
+ printf(" %11s", "");
+ printf(" %6s", "");
+ PRINTK(" %9llu", zonetotal);
+ printf("\n");
+ }
+ if (headerPrinted) {
+ if (elemsTagged) {
+ snprintf(totalstr, sizeof(totalstr), "%lld of %lld", elemsTagged, zoneElements);
+ printf("zone tags%100s\n", totalstr);
+ }
+ snprintf(totalstr, sizeof(totalstr), "%6.2fM of %6.2fM", totalsize / 1024.0 / 1024.0, top_wired / 1024.0 / 1024.0);
+ printf("total%104s\n", totalstr);
+ }
+ for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) {
+ site = sorted[idx];
+ size = gSites[site].mapped;
+ if (!size) {
+ continue;
+ }
+ if (VM_KERN_SITE_HIDE & gSites[site].flags) {
+ continue;
+ }
+ if ((size == gSites[site].size)
+ && ((VM_KERN_SITE_WIRED | VM_KERN_SITE_ZONE) & gSites[site].flags)) {
+ continue;
+ }
+
+ name = GetSiteName(site, NULL, 0);
+ if (!substr(zname, znamelen, name, strlen(name))) {
+ continue;
+ }
+ if (!headerPrinted) {
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ printf(" largest peak cur\n");
+ printf("maps free free size size\n");
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ headerPrinted = true;
+ }
+ printf("%-55s", name);
+ free(name);
+
+ if (gSites[site].free) {
+ PRINTK(" %10llu", gSites[site].free);
+ } else {
+ printf(" %11s", "");
+ }
+ if (gSites[site].largest) {
+ PRINTK(" %10llu", gSites[site].largest);
+ } else {
+ printf(" %11s", "");
+ }
+ if (gSites[site].peak) {
+ PRINTK(" %10llu", gSites[site].peak);
+ } else {
+ printf(" %11s", "");
+ }
+ PRINTK(" %16llu", size);
+
+ printf("\n");
+ }
+ for (headerPrinted = false, idx = 0; idx < wiredInfoCnt; idx++) {
+ site = sorted[idx];
+ size = gSites[site].size;
+ if (!size || !(VM_KERN_SITE_ZONE_VIEW & gSites[site].flags)) {
+ continue;
+ }
+
+ name = GetSiteName(site, NULL, 0);
+ if (!substr(zname, znamelen, name, strlen(name))) {
+ continue;
+ }
+ if (!headerPrinted) {
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ printf(" cur\n");
+ printf("zone views inuse\n");
+ printf("-------------------------------------------------------------------------------------------------------------\n");
+ headerPrinted = true;
+ }
+ printf("%-55s", name);
+ free(name);
+
+ printf(" %11s", "");
+ printf(" %11s", "");
+ printf(" %11s", "");
+ PRINTK(" %16llu", size);
+
+ printf("\n");
+ }
+ totalsize = zonetotal;
+}
diff --git a/system_cmds/zprint.tproj/zprint.lua b/system_cmds/zprint.tproj/zprint.lua
new file mode 100644
index 0000000..a5ca245
--- /dev/null
+++ b/system_cmds/zprint.tproj/zprint.lua
@@ -0,0 +1,281 @@
+require 'strict'
+
+-- # zprint
+--
+-- Parse the output of zprint into tables.
+
+local zprint = {}
+
+-- Return the lines inside "dashed" lines -- that is, lines that are entirely
+-- made up of dashes (-) in the string `str`. The `skip_dashed` argument
+-- controls how many dashed lines to skip before returning the lines between it
+-- and the next dashed line.
+local function lines_inside_dashes(str, skip_dashed)
+ local start_pos = 1
+ for _ = 1, skip_dashed do
+ _, start_pos = str:find('\n[-]+\n', start_pos)
+ end
+ assert(start_pos, 'found dashed line in output')
+ local end_pos, _ = str:find('\n[-]+\n', start_pos + 1)
+ assert(end_pos, 'found ending dashed line in output')
+
+ return str:sub(start_pos + 1, end_pos - 1)
+end
+
+-- Iterate through the zones listed in the given zprint(1) output `zpout`.
+--
+-- for zone in zprint_zones(io.stdin:read('*a')) do
+-- print(zone.name, zone.size, zone.used_size)
+-- end
+function zprint.zones(zpout)
+ -- Get to the first section delimited by dashes. This is where the zones are
+ -- recorded.
+ local zones = lines_inside_dashes(zpout, 1)
+
+ -- Create an iterator for each line, for use in our own iteration function.
+ local lines = zones:gmatch('([^\n]+)')
+
+ return function ()
+ -- Grab the next line.
+ local line = lines()
+ if not line then
+ return nil
+ end
+
+ -- Match each column from zprint's output.
+ local name, eltsz, cursz_kb, maxsz_kb, nelts, nelts_max, nused,
+ allocsz_kb = line:match(
+ '([%S]+)%s+(%d+)%s+(%d+)K%s+(%d+)K%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)')
+ -- Convert numeric fields to numbers, and into bytes if specified in KiB.
+ eltsz = tonumber(eltsz)
+ local cursz = tonumber(cursz_kb) * 1024
+ local maxsz = tonumber(maxsz_kb) * 1024
+ local usedsz = tonumber(nused) * eltsz
+ local allocsz = tonumber(allocsz_kb) * 1024
+
+ -- Return a table representing the zone.
+ return {
+ name = name, -- the name of the zone
+ size = cursz, -- the size of the zone
+ max_size = maxsz, -- the maximum size of the zone
+ used_size = usedsz, -- the size of all used elements in the zone
+ element_size = eltsz, -- the size of each element in the zone
+ allocation_size = allocsz, -- the size of allocations made for the zone
+ }
+ end
+end
+
+-- Match the output of a vm_tag line
+-- This line has a variable number of columns.
+-- This function returns the name and a table containing each numeric column's
+-- value.
+local function match_tag(line, ncols)
+ -- First try to match names with C++ symbol names.
+ -- These can have whitespace in the argument list.
+ local name_pattern = '^(%S+%b()%S*)'
+ local name = line:match(name_pattern)
+ if not name then
+ name = line:match('(%S+)')
+ if not name then
+ return nil
+ end
+ end
+ local after_name = line:sub(#name)
+ local t = {}
+ for v in line:gmatch('%s+(%d+)K?') do
+ table.insert(t, v)
+ end
+ return name, t
+end
+
+-- Iterate through the tags listed in the given zprint(1) output `zpout`.
+function zprint.tags(zpout)
+ -- Get to the third zone delimited by dashes, where the tags are recorded.
+ local tags = lines_inside_dashes(zpout, 3)
+
+ local lines = tags:gmatch('([^\n]+)')
+
+ return function ()
+ local line = lines()
+ if not line then
+ return nil
+ end
+
+ -- Skip any unloaded kmod lines.
+ while line:match('(unloaded kmod)') do
+ line = lines()
+ end
+ -- End on the zone tags line, since it's not useful.
+ if line:match('zone tags') then
+ return nil
+ end
+
+ local name, matches = match_tag(line)
+ if not name or #matches == 0 then
+ return nil
+ end
+
+ local cursz_kb = matches[#matches]
+ -- If there are fewer than 3 numeric columns, there's no reported peak size
+ local maxsz_kb = nil
+ if #matches > 3 then
+ maxsz_kb = matches[#matches - 1]
+ end
+
+ -- Convert numeric fields to numbers and then into bytes.
+ local cursz = tonumber(cursz_kb) * 1024
+ local maxsz = maxsz_kb and (tonumber(maxsz_kb) * 1024)
+
+ -- Return a table representing the region.
+ return {
+ name = name,
+ size = cursz,
+ max_size = maxsz,
+ }
+ end
+end
+
+-- Iterate through the maps listed in the given zprint(1) output `zpout`.
+function zprint.maps(zpout)
+ local maps = lines_inside_dashes(zpout, 5)
+ local lines = maps:gmatch('([^\n]+)')
+
+ return function()
+ -- Grab the next line.
+ local line = lines()
+ if not line then
+ return nil
+ end
+
+ -- The line can take on 3 different forms. Check for each of them
+
+ -- Check for 3 columns
+ local name, free_kb, largest_free_kb, curr_size_kb = line:match(
+ '(%S+)%s+(%d+)K%s+(%d+)K%s+(%d+)K')
+ local free, largest_free, peak_size_kb, peak_size, size
+ if not name then
+ -- Check for 2 columns
+ name, peak_size_kb, curr_size_kb = line:match('(%S+)%s+(%d+)K%s+(%d+)K')
+ if not name then
+ -- Check for a single column
+ name, curr_size_kb = line:match('(%S+)%s+(%d+)K')
+ assert(name)
+ else
+ peak_size = tonumber(peak_size_kb) * 1024
+ end
+ else
+ free = tonumber(free_kb) * 1024
+ largest_free = tonumber(largest_free_kb) * 1024
+ end
+ size = tonumber(curr_size_kb) * 1024
+
+ return {
+ name = name,
+ size = size,
+ max_size = peak_size,
+ free = free,
+ largest_free = largest_free
+ }
+ end
+end
+
+-- Iterate through the zone views listed in the given zprint(1) output `zpout`.
+function zprint.zone_views(zpout)
+ -- Skip to the zone views
+ local prev_pos = 1
+ -- Look for a line that starts with "zone views" and is followed by a -- line.
+ while true do
+ local start_pos, end_pos = zpout:find('\n[-]+\n', prev_pos)
+ if start_pos == nil then
+ return nil
+ end
+ local before = zpout:sub(prev_pos, start_pos)
+ local zone_views_index = zpout:find('\n%s*zone views%s+[^\n]+\n', prev_pos + 1)
+ prev_pos = end_pos
+ if zone_views_index and zone_views_index < end_pos then
+ break
+ end
+ end
+
+ local zone_views
+ local zone_totals_index = zpout:find("\nZONE TOTALS")
+ if zone_totals_index then
+ zone_views = zpout:sub(prev_pos + 1, zone_totals_index)
+ else
+ zone_views = zpout:sub(prev_pos+ 1)
+ end
+
+ local lines = zone_views:gmatch('([^\n]+)')
+
+ return function()
+ -- Grab the next line.
+ local line = lines()
+ if not line then
+ return nil
+ end
+
+ local name, curr_size_kb = line:match('(%S+)%s+(%d+)')
+ local size = tonumber(curr_size_kb) * 1024
+
+ return {
+ name = name,
+ size = size,
+ }
+ end
+end
+
+function zprint.total(zpout)
+ local total = zpout:match('total[^%d]+(%d+.%d+)M of')
+ local bytes = tonumber(total) * 1024 * 1024
+ return bytes
+end
+
+-- Return a library object, if called from require or dofile.
+local calling_func = debug.getinfo(2).func
+if calling_func == require or calling_func == dofile then
+ return zprint
+end
+
+-- Otherwise, 'recon zprint.lua ...' runs as a script.
+
+local cjson = require 'cjson'
+
+if not arg[1] then
+ io.stderr:write('usage: ', arg[0], ' <zprint-output-path>\n')
+ os.exit(1)
+end
+
+local file
+if arg[1] == '-' then
+ file = io.stdin
+else
+ local err
+ file, err = io.open(arg[1])
+ if not file then
+ io.stderr:write('zprint.lua: ', arg[1], ': open failed: ', err, '\n')
+ os.exit(1)
+ end
+end
+
+local zpout = file:read('all')
+file:close()
+
+local function collect(iter, arg)
+ local tbl = {}
+ for elt in iter(arg) do
+ tbl[#tbl + 1] = elt
+ end
+ return tbl
+end
+
+local zones = collect(zprint.zones, zpout)
+local tags = collect(zprint.tags, zpout)
+local maps = collect(zprint.maps, zpout)
+local zone_views = collect(zprint.zone_views, zpout)
+
+print(cjson.encode({
+ zones = zones,
+ tags = tags,
+ maps = maps,
+ zone_views = zone_views,
+}))
diff --git a/text_cmds/.upstream_base_commits b/text_cmds/.upstream_base_commits
new file mode 100644
index 0000000..a9f96cf
--- /dev/null
+++ b/text_cmds/.upstream_base_commits
@@ -0,0 +1,10 @@
+#freebsd = https://github.com/freebsd/freebsd.git
+
+sed/POSIX freebsd usr.bin/sed/POSIX 3a58a22a0b52d622721ce09df3930ff87174022f
+sed/compile.c freebsd usr.bin/sed/compile.c 3a58a22a0b52d622721ce09df3930ff87174022f
+sed/defs.h freebsd usr.bin/sed/defs.h 3a58a22a0b52d622721ce09df3930ff87174022f
+sed/extern.h freebsd usr.bin/sed/extern.h 3a58a22a0b52d622721ce09df3930ff87174022f
+sed/main.c freebsd usr.bin/sed/main.c 3a58a22a0b52d622721ce09df3930ff87174022f
+sed/misc.c freebsd usr.bin/sed/misc.c 3a58a22a0b52d622721ce09df3930ff87174022f
+sed/process.c freebsd usr.bin/sed/process.c 3a58a22a0b52d622721ce09df3930ff87174022f
+sed/sed.1 freebsd usr.bin/sed/sed.1 3a58a22a0b52d622721ce09df3930ff87174022f
diff --git a/text_cmds/banner/banner.6 b/text_cmds/banner/banner.6
new file mode 100644
index 0000000..b5e8cf5
--- /dev/null
+++ b/text_cmds/banner/banner.6
@@ -0,0 +1,82 @@
+.\" Copyright (c) 1980, 1993, 1995
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)banner.6 8.2 (Berkeley) 4/29/95
+.\" $FreeBSD: src/usr.bin/banner/banner.6,v 1.9 2005/01/25 22:24:04 tjr Exp $
+.\"
+.Dd January 26, 2005
+.Dt BANNER 6
+.Os
+.Sh NAME
+.Nm banner
+.Nd print large banner on printer
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl t
+.Op Fl w Ar width
+.Ar message ...
+.Sh DESCRIPTION
+.Nm Banner
+prints a large, high quality banner on the standard output.
+If the message is omitted, it prompts for and reads one line of its
+standard input.
+.Pp
+The output should be printed on paper of the appropriate width,
+with no breaks between the pages.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl d
+Enable debug.
+.It Fl t
+Enable trace.
+.It Fl w Ar width
+Change the output from a width of 132 to
+.Ar width ,
+suitable for a narrow terminal.
+.El
+.Sh AUTHORS
+.An Mark Horton
+.Sh BUGS
+Several
+.Tn ASCII
+characters are not defined, notably <, >, [, ], \\,
+^, _, {, }, |, and ~.
+Also, the characters ", ', and & are funny looking (but in a useful way.)
+.Pp
+The
+.Fl w
+option is implemented by skipping some rows and columns.
+The smaller it gets, the grainier the output.
+Sometimes it runs letters together.
+.Pp
+Messages are limited to 1024 characters in length.
diff --git a/text_cmds/banner/banner.c b/text_cmds/banner/banner.c
new file mode 100644
index 0000000..8a0286c
--- /dev/null
+++ b/text_cmds/banner/banner.c
@@ -0,0 +1,1186 @@
+/*
+ * Copyright (c) 1980, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)banner.c 8.4 (Berkeley) 4/29/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/banner/banner.c,v 1.15 2002/03/22 01:19:22 imp Exp $");
+
+/*
+ * banner - prints large signs
+ * banner [-w#] [-d] [-t] message ...
+ */
+
+#include <sys/types.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAXMSG 1024
+#define DWIDTH 132
+#define NCHARS 128
+#define NBYTES 9271
+
+/* Pointers into data_table for each ASCII char */
+const int asc_ptr[NCHARS] = {
+/* ^@ */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* ^H */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* ^P */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* ^X */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* */ 1, 3, 50, 81, 104, 281, 483, 590,
+/* ( */ 621, 685, 749, 851, 862, 893, 898, 921,
+/* 0 */1019, 1150, 1200, 1419, 1599, 1744, 1934, 2111,
+/* 8 */2235, 2445, 2622, 2659, 0, 2708, 0, 2715,
+/* @ */2857, 3072, 3273, 3403, 3560, 3662, 3730, 3785,
+/* H */3965, 4000, 4015, 4115, 4281, 4314, 4432, 4548,
+/* P */4709, 4790, 4999, 5188, 5397, 5448, 5576, 5710,
+/* X */5892, 6106, 6257, 0, 0, 0, 0, 0,
+/* ` */ 50, 6503, 6642, 6733, 6837, 6930, 7073, 7157,
+/* h */7380, 7452, 7499, 7584, 7689, 7702, 7797, 7869,
+/* p */7978, 8069, 8160, 8222, 8381, 8442, 8508, 8605,
+/* x */8732, 8888, 9016, 0, 0, 0, 0, 0
+};
+
+/*
+ * Table of stuff to print. Format:
+ * 128+n -> print current line n times.
+ * 64+n -> this is last byte of char.
+ * else, put m chars at position n (where m
+ * is the next elt in array) and goto second
+ * next element in array.
+ */
+const unsigned char data_table[NBYTES] = {
+/* 0 1 2 3 4 5 6 7 8 9 */
+/* 0 */ 129, 227, 130, 34, 6, 90, 19, 129, 32, 10,
+/* 10 */ 74, 40, 129, 31, 12, 64, 53, 129, 30, 14,
+/* 20 */ 54, 65, 129, 30, 14, 53, 67, 129, 30, 14,
+/* 30 */ 54, 65, 129, 31, 12, 64, 53, 129, 32, 10,
+/* 40 */ 74, 40, 129, 34, 6, 90, 19, 129, 194, 130,
+/* 50 */ 99, 9, 129, 97, 14, 129, 96, 18, 129, 95,
+/* 60 */ 22, 129, 95, 16, 117, 2, 129, 95, 14, 129,
+/* 70 */ 96, 11, 129, 97, 9, 129, 99, 6, 129, 194,
+/* 80 */ 129, 87, 4, 101, 4, 131, 82, 28, 131, 87,
+/* 90 */ 4, 101, 4, 133, 82, 28, 131, 87, 4, 101,
+/* 100 */ 4, 131, 193, 129, 39, 1, 84, 27, 129, 38,
+/* 110 */ 3, 81, 32, 129, 37, 5, 79, 35, 129, 36,
+/* 120 */ 5, 77, 38, 129, 35, 5, 76, 40, 129, 34,
+/* 130 */ 5, 75, 21, 103, 14, 129, 33, 5, 74, 19,
+/* 140 */ 107, 11, 129, 32, 5, 73, 17, 110, 9, 129,
+/* 150 */ 32, 4, 73, 16, 112, 7, 129, 31, 4, 72,
+/* 160 */ 15, 114, 6, 129, 31, 4, 72, 14, 115, 5,
+/* 170 */ 129, 30, 4, 71, 15, 116, 5, 129, 27, 97,
+/* 180 */ 131, 30, 4, 69, 14, 117, 4, 129, 30, 4,
+/* 190 */ 68, 15, 117, 4, 132, 30, 4, 68, 14, 117,
+/* 200 */ 4, 129, 27, 97, 131, 30, 5, 65, 15, 116,
+/* 210 */ 5, 129, 31, 4, 65, 14, 116, 4, 129, 31,
+/* 220 */ 6, 64, 15, 116, 4, 129, 32, 7, 62, 16,
+/* 230 */ 115, 4, 129, 32, 9, 61, 17, 114, 5, 129,
+/* 240 */ 33, 11, 58, 19, 113, 5, 129, 34, 14, 55,
+/* 250 */ 21, 112, 5, 129, 35, 40, 111, 5, 129, 36,
+/* 260 */ 38, 110, 5, 129, 37, 35, 109, 5, 129, 38,
+/* 270 */ 32, 110, 3, 129, 40, 27, 111, 1, 129, 193,
+/* 280 */ 129, 30, 4, 103, 9, 129, 30, 7, 100, 15,
+/* 290 */ 129, 30, 10, 99, 17, 129, 33, 10, 97, 6,
+/* 300 */ 112, 6, 129, 36, 10, 96, 5, 114, 5, 129,
+/* 310 */ 39, 10, 96, 4, 115, 4, 129, 42, 10, 95,
+/* 320 */ 4, 116, 4, 129, 45, 10, 95, 3, 117, 3,
+/* 330 */ 129, 48, 10, 95, 3, 117, 3, 129, 51, 10,
+/* 340 */ 95, 4, 116, 4, 129, 54, 10, 96, 4, 115,
+/* 350 */ 4, 129, 57, 10, 96, 5, 114, 5, 129, 60,
+/* 360 */ 10, 97, 6, 112, 6, 129, 63, 10, 99, 17,
+/* 370 */ 129, 66, 10, 100, 15, 129, 69, 10, 103, 9,
+/* 380 */ 129, 39, 9, 72, 10, 129, 36, 15, 75, 10,
+/* 390 */ 129, 35, 17, 78, 10, 129, 33, 6, 48, 6,
+/* 400 */ 81, 10, 129, 32, 5, 50, 5, 84, 10, 129,
+/* 410 */ 32, 4, 51, 4, 87, 10, 129, 31, 4, 52,
+/* 420 */ 4, 90, 10, 129, 31, 3, 53, 3, 93, 10,
+/* 430 */ 129, 31, 3, 53, 3, 96, 10, 129, 31, 4,
+/* 440 */ 52, 4, 99, 10, 129, 32, 4, 51, 4, 102,
+/* 450 */ 10, 129, 32, 5, 50, 5, 105, 10, 129, 33,
+/* 460 */ 6, 48, 6, 108, 10, 129, 35, 17, 111, 10,
+/* 470 */ 129, 36, 15, 114, 7, 129, 40, 9, 118, 4,
+/* 480 */ 129, 193, 129, 48, 18, 129, 43, 28, 129, 41,
+/* 490 */ 32, 129, 39, 36, 129, 37, 40, 129, 35, 44,
+/* 500 */ 129, 34, 46, 129, 33, 13, 68, 13, 129, 32,
+/* 510 */ 9, 73, 9, 129, 32, 7, 75, 7, 129, 31,
+/* 520 */ 6, 77, 6, 129, 31, 5, 78, 5, 129, 30,
+/* 530 */ 5, 79, 5, 129, 20, 74, 132, 30, 4, 80,
+/* 540 */ 4, 129, 31, 3, 79, 4, 129, 31, 4, 79,
+/* 550 */ 4, 129, 32, 3, 78, 4, 129, 32, 4, 76,
+/* 560 */ 6, 129, 33, 4, 74, 7, 129, 34, 4, 72,
+/* 570 */ 8, 129, 35, 5, 72, 7, 129, 37, 5, 73,
+/* 580 */ 4, 129, 39, 4, 74, 1, 129, 129, 193, 130,
+/* 590 */ 111, 6, 129, 109, 10, 129, 108, 12, 129, 107,
+/* 600 */ 14, 129, 97, 2, 105, 16, 129, 99, 22, 129,
+/* 610 */ 102, 18, 129, 105, 14, 129, 108, 9, 129, 194,
+/* 620 */ 130, 63, 25, 129, 57, 37, 129, 52, 47, 129,
+/* 630 */ 48, 55, 129, 44, 63, 129, 41, 69, 129, 38,
+/* 640 */ 75, 129, 36, 79, 129, 34, 83, 129, 33, 28,
+/* 650 */ 90, 28, 129, 32, 23, 96, 23, 129, 32, 17,
+/* 660 */ 102, 17, 129, 31, 13, 107, 13, 129, 30, 9,
+/* 670 */ 112, 9, 129, 30, 5, 116, 5, 129, 30, 1,
+/* 680 */ 120, 1, 129, 194, 130, 30, 1, 120, 1, 129,
+/* 690 */ 30, 5, 116, 5, 129, 30, 9, 112, 9, 129,
+/* 700 */ 31, 13, 107, 13, 129, 32, 17, 102, 17, 129,
+/* 710 */ 32, 23, 96, 23, 129, 33, 28, 90, 28, 129,
+/* 720 */ 34, 83, 129, 36, 79, 129, 38, 75, 129, 41,
+/* 730 */ 69, 129, 44, 63, 129, 48, 55, 129, 52, 47,
+/* 740 */ 129, 57, 37, 129, 63, 25, 129, 194, 129, 80,
+/* 750 */ 4, 130, 80, 4, 129, 68, 2, 80, 4, 94,
+/* 760 */ 2, 129, 66, 6, 80, 4, 92, 6, 129, 67,
+/* 770 */ 7, 80, 4, 90, 7, 129, 69, 7, 80, 4,
+/* 780 */ 88, 7, 129, 71, 6, 80, 4, 87, 6, 129,
+/* 790 */ 72, 20, 129, 74, 16, 129, 76, 12, 129, 62,
+/* 800 */ 40, 131, 76, 12, 129, 74, 16, 129, 72, 20,
+/* 810 */ 129, 71, 6, 80, 4, 87, 6, 129, 69, 7,
+/* 820 */ 80, 4, 88, 7, 129, 67, 7, 80, 4, 90,
+/* 830 */ 7, 129, 66, 6, 80, 4, 92, 6, 129, 68,
+/* 840 */ 2, 80, 4, 94, 2, 129, 80, 4, 130, 193,
+/* 850 */ 129, 60, 4, 139, 41, 42, 131, 60, 4, 139,
+/* 860 */ 193, 130, 34, 6, 129, 32, 10, 129, 31, 12,
+/* 870 */ 129, 30, 14, 129, 20, 2, 28, 16, 129, 22,
+/* 880 */ 22, 129, 24, 19, 129, 27, 15, 129, 31, 9,
+/* 890 */ 129, 194, 129, 60, 4, 152, 193, 130, 34, 6,
+/* 900 */ 129, 32, 10, 129, 31, 12, 129, 30, 14, 131,
+/* 910 */ 31, 12, 129, 32, 10, 129, 34, 6, 129, 194,
+/* 920 */ 129, 30, 4, 129, 30, 7, 129, 30, 10, 129,
+/* 930 */ 33, 10, 129, 36, 10, 129, 39, 10, 129, 42,
+/* 940 */ 10, 129, 45, 10, 129, 48, 10, 129, 51, 10,
+/* 950 */ 129, 54, 10, 129, 57, 10, 129, 60, 10, 129,
+/* 960 */ 63, 10, 129, 66, 10, 129, 69, 10, 129, 72,
+/* 970 */ 10, 129, 75, 10, 129, 78, 10, 129, 81, 10,
+/* 980 */ 129, 84, 10, 129, 87, 10, 129, 90, 10, 129,
+/* 990 */ 93, 10, 129, 96, 10, 129, 99, 10, 129, 102,
+/* 1000 */ 10, 129, 105, 10, 129, 108, 10, 129, 111, 10,
+/* 1010 */ 129, 114, 7, 129, 117, 4, 129, 193, 129, 60,
+/* 1020 */ 31, 129, 53, 45, 129, 49, 53, 129, 46, 59,
+/* 1030 */ 129, 43, 65, 129, 41, 69, 129, 39, 73, 129,
+/* 1040 */ 37, 77, 129, 36, 79, 129, 35, 15, 101, 15,
+/* 1050 */ 129, 34, 11, 106, 11, 129, 33, 9, 109, 9,
+/* 1060 */ 129, 32, 7, 112, 7, 129, 31, 6, 114, 6,
+/* 1070 */ 129, 31, 5, 115, 5, 129, 30, 5, 116, 5,
+/* 1080 */ 129, 30, 4, 117, 4, 132, 30, 5, 116, 5,
+/* 1090 */ 129, 31, 5, 115, 5, 129, 31, 6, 114, 6,
+/* 1100 */ 129, 32, 7, 112, 7, 129, 33, 9, 109, 9,
+/* 1110 */ 129, 34, 11, 106, 11, 129, 35, 15, 101, 15,
+/* 1120 */ 129, 36, 79, 129, 37, 77, 129, 39, 73, 129,
+/* 1130 */ 41, 69, 129, 43, 65, 129, 46, 59, 129, 49,
+/* 1140 */ 53, 129, 53, 45, 129, 60, 31, 129, 193, 129,
+/* 1150 */ 30, 4, 129, 30, 4, 100, 1, 129, 30, 4,
+/* 1160 */ 100, 3, 129, 30, 4, 100, 5, 129, 30, 76,
+/* 1170 */ 129, 30, 78, 129, 30, 80, 129, 30, 82, 129,
+/* 1180 */ 30, 83, 129, 30, 85, 129, 30, 87, 129, 30,
+/* 1190 */ 89, 129, 30, 91, 129, 30, 4, 132, 193, 129,
+/* 1200 */ 30, 3, 129, 30, 7, 129, 30, 10, 112, 1,
+/* 1210 */ 129, 30, 13, 112, 2, 129, 30, 16, 112, 3,
+/* 1220 */ 129, 30, 18, 111, 5, 129, 30, 21, 111, 6,
+/* 1230 */ 129, 30, 23, 112, 6, 129, 30, 14, 47, 8,
+/* 1240 */ 113, 6, 129, 30, 14, 49, 8, 114, 5, 129,
+/* 1250 */ 30, 14, 51, 8, 115, 5, 129, 30, 14, 53,
+/* 1260 */ 8, 116, 4, 129, 30, 14, 55, 8, 116, 5,
+/* 1270 */ 129, 30, 14, 56, 9, 117, 4, 129, 30, 14,
+/* 1280 */ 57, 9, 117, 4, 129, 30, 14, 58, 10, 117,
+/* 1290 */ 4, 129, 30, 14, 59, 10, 117, 4, 129, 30,
+/* 1300 */ 14, 60, 11, 117, 4, 129, 30, 14, 61, 11,
+/* 1310 */ 116, 5, 129, 30, 14, 62, 11, 116, 5, 129,
+/* 1320 */ 30, 14, 63, 12, 115, 6, 129, 30, 14, 64,
+/* 1330 */ 13, 114, 7, 129, 30, 14, 65, 13, 113, 8,
+/* 1340 */ 129, 30, 14, 65, 15, 111, 9, 129, 30, 14,
+/* 1350 */ 66, 16, 109, 11, 129, 30, 14, 67, 17, 107,
+/* 1360 */ 12, 129, 30, 14, 68, 20, 103, 16, 129, 30,
+/* 1370 */ 14, 69, 49, 129, 30, 14, 70, 47, 129, 30,
+/* 1380 */ 14, 71, 45, 129, 30, 14, 73, 42, 129, 30,
+/* 1390 */ 15, 75, 38, 129, 33, 12, 77, 34, 129, 36,
+/* 1400 */ 10, 79, 30, 129, 40, 6, 82, 23, 129, 44,
+/* 1410 */ 3, 86, 15, 129, 47, 1, 129, 193, 129, 129,
+/* 1420 */ 38, 3, 129, 37, 5, 111, 1, 129, 36, 7,
+/* 1430 */ 111, 2, 129, 35, 9, 110, 5, 129, 34, 8,
+/* 1440 */ 110, 6, 129, 33, 7, 109, 8, 129, 32, 7,
+/* 1450 */ 110, 8, 129, 32, 6, 112, 7, 129, 31, 6,
+/* 1460 */ 113, 6, 129, 31, 5, 114, 6, 129, 30, 5,
+/* 1470 */ 115, 5, 129, 30, 5, 116, 4, 129, 30, 4,
+/* 1480 */ 117, 4, 131, 30, 4, 117, 4, 129, 30, 4,
+/* 1490 */ 79, 2, 117, 4, 129, 30, 5, 78, 4, 117,
+/* 1500 */ 4, 129, 30, 5, 77, 6, 116, 5, 129, 30,
+/* 1510 */ 6, 76, 8, 115, 6, 129, 30, 7, 75, 11,
+/* 1520 */ 114, 6, 129, 30, 8, 73, 15, 112, 8, 129,
+/* 1530 */ 31, 9, 71, 19, 110, 9, 129, 31, 11, 68,
+/* 1540 */ 26, 107, 12, 129, 32, 13, 65, 14, 82, 36,
+/* 1550 */ 129, 32, 16, 61, 17, 83, 34, 129, 33, 44,
+/* 1560 */ 84, 32, 129, 34, 42, 85, 30, 129, 35, 40,
+/* 1570 */ 87, 27, 129, 36, 38, 89, 23, 129, 38, 34,
+/* 1580 */ 92, 17, 129, 40, 30, 95, 11, 129, 42, 26,
+/* 1590 */ 129, 45, 20, 129, 49, 11, 129, 193, 129, 49,
+/* 1600 */ 1, 129, 49, 4, 129, 49, 6, 129, 49, 8,
+/* 1610 */ 129, 49, 10, 129, 49, 12, 129, 49, 14, 129,
+/* 1620 */ 49, 17, 129, 49, 19, 129, 49, 21, 129, 49,
+/* 1630 */ 23, 129, 49, 14, 65, 9, 129, 49, 14, 67,
+/* 1640 */ 9, 129, 49, 14, 69, 9, 129, 49, 14, 71,
+/* 1650 */ 10, 129, 49, 14, 74, 9, 129, 49, 14, 76,
+/* 1660 */ 9, 129, 49, 14, 78, 9, 129, 49, 14, 80,
+/* 1670 */ 9, 129, 49, 14, 82, 9, 129, 49, 14, 84,
+/* 1680 */ 9, 129, 30, 4, 49, 14, 86, 10, 129, 30,
+/* 1690 */ 4, 49, 14, 89, 9, 129, 30, 4, 49, 14,
+/* 1700 */ 91, 9, 129, 30, 4, 49, 14, 93, 9, 129,
+/* 1710 */ 30, 74, 129, 30, 76, 129, 30, 78, 129, 30,
+/* 1720 */ 81, 129, 30, 83, 129, 30, 85, 129, 30, 87,
+/* 1730 */ 129, 30, 89, 129, 30, 91, 129, 30, 4, 49,
+/* 1740 */ 14, 132, 193, 129, 37, 1, 129, 36, 3, 77,
+/* 1750 */ 3, 129, 35, 5, 78, 11, 129, 34, 7, 78,
+/* 1760 */ 21, 129, 33, 7, 79, 29, 129, 32, 7, 79,
+/* 1770 */ 38, 129, 32, 6, 80, 4, 92, 29, 129, 31,
+/* 1780 */ 6, 80, 5, 102, 19, 129, 31, 5, 80, 6,
+/* 1790 */ 107, 14, 129, 31, 4, 81, 5, 107, 14, 129,
+/* 1800 */ 30, 5, 81, 6, 107, 14, 129, 30, 4, 81,
+/* 1810 */ 6, 107, 14, 130, 30, 4, 81, 7, 107, 14,
+/* 1820 */ 129, 30, 4, 80, 8, 107, 14, 130, 30, 5,
+/* 1830 */ 80, 8, 107, 14, 129, 30, 5, 79, 9, 107,
+/* 1840 */ 14, 129, 31, 5, 79, 9, 107, 14, 129, 31,
+/* 1850 */ 6, 78, 10, 107, 14, 129, 32, 6, 76, 11,
+/* 1860 */ 107, 14, 129, 32, 8, 74, 13, 107, 14, 129,
+/* 1870 */ 33, 10, 71, 16, 107, 14, 129, 33, 15, 67,
+/* 1880 */ 19, 107, 14, 129, 34, 51, 107, 14, 129, 35,
+/* 1890 */ 49, 107, 14, 129, 36, 47, 107, 14, 129, 37,
+/* 1900 */ 45, 107, 14, 129, 39, 41, 107, 14, 129, 41,
+/* 1910 */ 37, 107, 14, 129, 44, 32, 107, 14, 129, 47,
+/* 1920 */ 25, 111, 10, 129, 51, 16, 115, 6, 129, 119,
+/* 1930 */ 2, 129, 193, 129, 56, 39, 129, 51, 49, 129,
+/* 1940 */ 47, 57, 129, 44, 63, 129, 42, 67, 129, 40,
+/* 1950 */ 71, 129, 38, 75, 129, 37, 77, 129, 35, 81,
+/* 1960 */ 129, 34, 16, 74, 5, 101, 16, 129, 33, 11,
+/* 1970 */ 76, 5, 107, 11, 129, 32, 9, 77, 5, 110,
+/* 1980 */ 9, 129, 32, 7, 79, 4, 112, 7, 129, 31,
+/* 1990 */ 6, 80, 4, 114, 6, 129, 31, 5, 81, 4,
+/* 2000 */ 115, 5, 129, 30, 5, 82, 4, 116, 5, 129,
+/* 2010 */ 30, 4, 82, 4, 116, 5, 129, 30, 4, 82,
+/* 2020 */ 5, 117, 4, 131, 30, 5, 82, 5, 117, 4,
+/* 2030 */ 129, 31, 5, 81, 6, 117, 4, 129, 31, 6,
+/* 2040 */ 80, 7, 117, 4, 129, 32, 7, 79, 8, 117,
+/* 2050 */ 4, 129, 32, 9, 77, 9, 116, 5, 129, 33,
+/* 2060 */ 11, 75, 11, 116, 4, 129, 34, 16, 69, 16,
+/* 2070 */ 115, 5, 129, 35, 49, 114, 5, 129, 37, 46,
+/* 2080 */ 113, 5, 129, 38, 44, 112, 6, 129, 40, 41,
+/* 2090 */ 112, 5, 129, 42, 37, 113, 3, 129, 44, 33,
+/* 2100 */ 114, 1, 129, 47, 27, 129, 51, 17, 129, 193,
+/* 2110 */ 129, 103, 2, 129, 103, 6, 129, 104, 9, 129,
+/* 2120 */ 105, 12, 129, 106, 15, 129, 107, 14, 135, 30,
+/* 2130 */ 10, 107, 14, 129, 30, 17, 107, 14, 129, 30,
+/* 2140 */ 25, 107, 14, 129, 30, 31, 107, 14, 129, 30,
+/* 2150 */ 37, 107, 14, 129, 30, 42, 107, 14, 129, 30,
+/* 2160 */ 46, 107, 14, 129, 30, 50, 107, 14, 129, 30,
+/* 2170 */ 54, 107, 14, 129, 30, 58, 107, 14, 129, 59,
+/* 2180 */ 32, 107, 14, 129, 64, 30, 107, 14, 129, 74,
+/* 2190 */ 23, 107, 14, 129, 81, 18, 107, 14, 129, 86,
+/* 2200 */ 16, 107, 14, 129, 91, 14, 107, 14, 129, 96,
+/* 2210 */ 25, 129, 100, 21, 129, 104, 17, 129, 107, 14,
+/* 2220 */ 129, 111, 10, 129, 114, 7, 129, 117, 4, 129,
+/* 2230 */ 120, 1, 129, 193, 129, 48, 13, 129, 44, 21,
+/* 2240 */ 129, 42, 26, 129, 40, 30, 92, 12, 129, 38,
+/* 2250 */ 34, 88, 20, 129, 36, 37, 86, 25, 129, 35,
+/* 2260 */ 39, 84, 29, 129, 34, 13, 63, 12, 82, 33,
+/* 2270 */ 129, 33, 11, 67, 9, 80, 36, 129, 32, 9,
+/* 2280 */ 70, 7, 79, 38, 129, 31, 8, 72, 46, 129,
+/* 2290 */ 30, 7, 74, 22, 108, 11, 129, 30, 6, 75,
+/* 2300 */ 19, 111, 9, 129, 30, 5, 75, 17, 113, 7,
+/* 2310 */ 129, 30, 5, 74, 16, 114, 6, 129, 30, 4,
+/* 2320 */ 73, 16, 115, 6, 129, 30, 4, 72, 16, 116,
+/* 2330 */ 5, 129, 30, 4, 72, 15, 117, 4, 129, 30,
+/* 2340 */ 4, 71, 16, 117, 4, 129, 30, 5, 70, 16,
+/* 2350 */ 117, 4, 129, 30, 5, 70, 15, 117, 4, 129,
+/* 2360 */ 30, 6, 69, 15, 116, 5, 129, 30, 7, 68,
+/* 2370 */ 17, 115, 5, 129, 30, 9, 67, 19, 114, 6,
+/* 2380 */ 129, 30, 10, 65, 22, 113, 6, 129, 31, 12,
+/* 2390 */ 63, 27, 110, 9, 129, 32, 14, 60, 21, 84,
+/* 2400 */ 9, 106, 12, 129, 33, 47, 85, 32, 129, 34,
+/* 2410 */ 45, 86, 30, 129, 35, 43, 88, 26, 129, 36,
+/* 2420 */ 40, 90, 22, 129, 38, 36, 93, 17, 129, 40,
+/* 2430 */ 32, 96, 10, 129, 42, 28, 129, 44, 23, 129,
+/* 2440 */ 48, 15, 129, 193, 129, 83, 17, 129, 77, 27,
+/* 2450 */ 129, 36, 1, 74, 33, 129, 35, 3, 72, 37,
+/* 2460 */ 129, 34, 5, 70, 41, 129, 33, 6, 69, 44,
+/* 2470 */ 129, 33, 5, 68, 46, 129, 32, 5, 67, 49,
+/* 2480 */ 129, 31, 5, 66, 17, 101, 16, 129, 31, 5,
+/* 2490 */ 66, 11, 108, 10, 129, 30, 4, 65, 9, 110,
+/* 2500 */ 9, 129, 30, 4, 64, 8, 112, 7, 129, 30,
+/* 2510 */ 4, 64, 7, 114, 6, 129, 30, 4, 64, 6,
+/* 2520 */ 115, 5, 129, 30, 4, 64, 5, 116, 5, 129,
+/* 2530 */ 30, 4, 64, 5, 117, 4, 131, 30, 4, 65,
+/* 2540 */ 4, 117, 4, 129, 30, 5, 65, 4, 116, 5,
+/* 2550 */ 129, 31, 5, 66, 4, 115, 5, 129, 31, 6,
+/* 2560 */ 67, 4, 114, 6, 129, 32, 7, 68, 4, 112,
+/* 2570 */ 7, 129, 32, 9, 69, 5, 110, 9, 129, 33,
+/* 2580 */ 11, 70, 5, 107, 11, 129, 34, 16, 72, 5,
+/* 2590 */ 101, 16, 129, 35, 81, 129, 37, 77, 129, 38,
+/* 2600 */ 75, 129, 40, 71, 129, 42, 67, 129, 44, 63,
+/* 2610 */ 129, 47, 57, 129, 51, 49, 129, 56, 39, 129,
+/* 2620 */ 193, 130, 34, 6, 74, 6, 129, 32, 10, 72,
+/* 2630 */ 10, 129, 31, 12, 71, 12, 129, 30, 14, 70,
+/* 2640 */ 14, 131, 31, 12, 71, 12, 129, 32, 10, 72,
+/* 2650 */ 10, 129, 34, 6, 74, 6, 129, 194, 130, 34,
+/* 2660 */ 6, 74, 6, 129, 32, 10, 72, 10, 129, 31,
+/* 2670 */ 12, 71, 12, 129, 30, 14, 70, 14, 129, 20,
+/* 2680 */ 2, 28, 16, 70, 14, 129, 22, 22, 70, 14,
+/* 2690 */ 129, 24, 19, 71, 12, 129, 27, 15, 72, 10,
+/* 2700 */ 129, 31, 9, 74, 6, 129, 194, 129, 53, 4,
+/* 2710 */ 63, 4, 152, 193, 130, 99, 7, 129, 97, 13,
+/* 2720 */ 129, 96, 16, 129, 96, 18, 129, 96, 19, 129,
+/* 2730 */ 97, 19, 129, 99, 6, 110, 7, 129, 112, 6,
+/* 2740 */ 129, 114, 5, 129, 34, 6, 57, 5, 115, 4,
+/* 2750 */ 129, 32, 10, 54, 12, 116, 4, 129, 31, 12,
+/* 2760 */ 53, 16, 117, 3, 129, 30, 14, 52, 20, 117,
+/* 2770 */ 4, 129, 30, 14, 52, 23, 117, 4, 129, 30,
+/* 2780 */ 14, 52, 25, 117, 4, 129, 31, 12, 52, 27,
+/* 2790 */ 117, 4, 129, 32, 10, 53, 10, 70, 11, 116,
+/* 2800 */ 5, 129, 34, 6, 55, 5, 73, 10, 115, 6,
+/* 2810 */ 129, 74, 11, 114, 7, 129, 75, 12, 112, 9,
+/* 2820 */ 129, 76, 13, 110, 10, 129, 77, 16, 106, 14,
+/* 2830 */ 129, 78, 41, 129, 80, 38, 129, 81, 36, 129,
+/* 2840 */ 82, 34, 129, 84, 30, 129, 86, 26, 129, 88,
+/* 2850 */ 22, 129, 92, 14, 129, 194, 129, 55, 15, 129,
+/* 2860 */ 50, 25, 129, 47, 32, 129, 45, 13, 70, 12,
+/* 2870 */ 129, 43, 9, 76, 10, 129, 42, 6, 79, 8,
+/* 2880 */ 129, 41, 5, 81, 7, 129, 40, 4, 84, 6,
+/* 2890 */ 129, 39, 4, 59, 12, 85, 6, 129, 38, 4,
+/* 2900 */ 55, 19, 87, 5, 129, 37, 4, 53, 23, 88,
+/* 2910 */ 4, 129, 36, 4, 51, 8, 71, 6, 89, 4,
+/* 2920 */ 129, 36, 4, 51, 6, 73, 4, 89, 4, 129,
+/* 2930 */ 36, 4, 50, 6, 74, 4, 90, 3, 129, 35,
+/* 2940 */ 4, 50, 5, 75, 3, 90, 4, 129, 35, 4,
+/* 2950 */ 50, 4, 75, 4, 90, 4, 131, 35, 4, 50,
+/* 2960 */ 5, 75, 4, 90, 4, 129, 36, 4, 51, 5,
+/* 2970 */ 75, 4, 90, 4, 129, 36, 4, 51, 6, 75,
+/* 2980 */ 4, 90, 4, 129, 36, 4, 53, 26, 90, 4,
+/* 2990 */ 129, 37, 4, 54, 25, 90, 4, 129, 37, 4,
+/* 3000 */ 52, 27, 90, 3, 129, 38, 4, 52, 4, 89,
+/* 3010 */ 4, 129, 39, 4, 51, 4, 88, 4, 129, 40,
+/* 3020 */ 4, 50, 4, 87, 5, 129, 41, 4, 50, 4,
+/* 3030 */ 86, 5, 129, 42, 4, 50, 4, 85, 5, 129,
+/* 3040 */ 43, 3, 50, 4, 83, 6, 129, 44, 2, 51,
+/* 3050 */ 5, 80, 7, 129, 46, 1, 52, 6, 76, 9,
+/* 3060 */ 129, 54, 28, 129, 56, 23, 129, 60, 16, 129,
+/* 3070 */ 193, 129, 30, 4, 132, 30, 5, 129, 30, 8,
+/* 3080 */ 129, 30, 12, 129, 30, 16, 129, 30, 4, 37,
+/* 3090 */ 12, 129, 30, 4, 41, 12, 129, 30, 4, 44,
+/* 3100 */ 13, 129, 30, 4, 48, 13, 129, 52, 13, 129,
+/* 3110 */ 56, 12, 129, 58, 14, 129, 58, 4, 64, 12,
+/* 3120 */ 129, 58, 4, 68, 12, 129, 58, 4, 72, 12,
+/* 3130 */ 129, 58, 4, 75, 13, 129, 58, 4, 79, 13,
+/* 3140 */ 129, 58, 4, 83, 13, 129, 58, 4, 87, 13,
+/* 3150 */ 129, 58, 4, 91, 12, 129, 58, 4, 95, 12,
+/* 3160 */ 129, 58, 4, 96, 15, 129, 58, 4, 93, 22,
+/* 3170 */ 129, 58, 4, 89, 30, 129, 58, 4, 85, 36,
+/* 3180 */ 129, 58, 4, 81, 38, 129, 58, 4, 77, 38,
+/* 3190 */ 129, 58, 4, 73, 38, 129, 58, 4, 70, 37,
+/* 3200 */ 129, 58, 4, 66, 37, 129, 58, 41, 129, 58,
+/* 3210 */ 37, 129, 54, 38, 129, 30, 4, 50, 38, 129,
+/* 3220 */ 30, 4, 46, 38, 129, 30, 4, 42, 38, 129,
+/* 3230 */ 30, 4, 38, 39, 129, 30, 43, 129, 30, 39,
+/* 3240 */ 129, 30, 35, 129, 30, 31, 129, 30, 27, 129,
+/* 3250 */ 30, 24, 129, 30, 20, 129, 30, 16, 129, 30,
+/* 3260 */ 12, 129, 30, 8, 129, 30, 5, 129, 30, 4,
+/* 3270 */ 132, 193, 129, 30, 4, 117, 4, 132, 30, 91,
+/* 3280 */ 137, 30, 4, 80, 4, 117, 4, 138, 30, 4,
+/* 3290 */ 80, 5, 116, 5, 129, 30, 5, 79, 6, 116,
+/* 3300 */ 5, 130, 30, 6, 78, 8, 115, 6, 129, 31,
+/* 3310 */ 6, 77, 9, 115, 6, 129, 31, 7, 76, 11,
+/* 3320 */ 114, 6, 129, 31, 8, 75, 14, 112, 8, 129,
+/* 3330 */ 32, 8, 74, 16, 111, 9, 129, 32, 9, 73,
+/* 3340 */ 19, 109, 10, 129, 33, 10, 71, 24, 106, 13,
+/* 3350 */ 129, 33, 13, 68, 12, 83, 35, 129, 34, 16,
+/* 3360 */ 64, 15, 84, 33, 129, 35, 43, 85, 31, 129,
+/* 3370 */ 36, 41, 86, 29, 129, 37, 39, 88, 25, 129,
+/* 3380 */ 38, 37, 90, 21, 129, 40, 33, 93, 15, 129,
+/* 3390 */ 42, 29, 96, 9, 129, 45, 24, 129, 49, 16,
+/* 3400 */ 129, 193, 129, 63, 25, 129, 57, 37, 129, 53,
+/* 3410 */ 45, 129, 50, 51, 129, 47, 57, 129, 45, 61,
+/* 3420 */ 129, 43, 65, 129, 41, 69, 129, 39, 73, 129,
+/* 3430 */ 38, 25, 92, 21, 129, 36, 21, 97, 18, 129,
+/* 3440 */ 35, 18, 102, 14, 129, 34, 16, 106, 11, 129,
+/* 3450 */ 33, 14, 108, 10, 129, 32, 12, 111, 8, 129,
+/* 3460 */ 32, 10, 113, 6, 129, 31, 10, 114, 6, 129,
+/* 3470 */ 31, 8, 115, 5, 129, 30, 8, 116, 5, 129,
+/* 3480 */ 30, 7, 116, 5, 129, 30, 6, 117, 4, 130,
+/* 3490 */ 30, 5, 117, 4, 131, 31, 4, 116, 5, 129,
+/* 3500 */ 32, 4, 116, 4, 129, 32, 5, 115, 5, 129,
+/* 3510 */ 33, 4, 114, 5, 129, 34, 4, 112, 6, 129,
+/* 3520 */ 35, 4, 110, 7, 129, 37, 4, 107, 9, 129,
+/* 3530 */ 39, 4, 103, 12, 129, 41, 4, 103, 18, 129,
+/* 3540 */ 43, 4, 103, 18, 129, 45, 5, 103, 18, 129,
+/* 3550 */ 48, 5, 103, 18, 129, 51, 1, 129, 193, 129,
+/* 3560 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
+/* 3570 */ 117, 4, 135, 30, 5, 116, 5, 130, 30, 6,
+/* 3580 */ 115, 6, 130, 31, 6, 114, 6, 129, 31, 7,
+/* 3590 */ 113, 7, 129, 32, 7, 112, 7, 129, 32, 8,
+/* 3600 */ 111, 8, 129, 33, 9, 109, 9, 129, 33, 12,
+/* 3610 */ 106, 12, 129, 34, 13, 104, 13, 129, 35, 15,
+/* 3620 */ 101, 15, 129, 36, 19, 96, 19, 129, 37, 24,
+/* 3630 */ 90, 24, 129, 39, 73, 129, 40, 71, 129, 42,
+/* 3640 */ 67, 129, 44, 63, 129, 46, 59, 129, 49, 53,
+/* 3650 */ 129, 52, 47, 129, 56, 39, 129, 61, 29, 129,
+/* 3660 */ 193, 129, 30, 4, 117, 4, 132, 30, 91, 137,
+/* 3670 */ 30, 4, 80, 4, 117, 4, 140, 30, 4, 79,
+/* 3680 */ 6, 117, 4, 129, 30, 4, 77, 10, 117, 4,
+/* 3690 */ 129, 30, 4, 73, 18, 117, 4, 132, 30, 4,
+/* 3700 */ 117, 4, 130, 30, 5, 116, 5, 130, 30, 7,
+/* 3710 */ 114, 7, 129, 30, 8, 113, 8, 129, 30, 11,
+/* 3720 */ 110, 11, 129, 30, 18, 103, 18, 132, 193, 129,
+/* 3730 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
+/* 3740 */ 80, 4, 117, 4, 132, 80, 4, 117, 4, 136,
+/* 3750 */ 79, 6, 117, 4, 129, 77, 10, 117, 4, 129,
+/* 3760 */ 73, 18, 117, 4, 132, 117, 4, 130, 116, 5,
+/* 3770 */ 130, 114, 7, 129, 113, 8, 129, 110, 11, 129,
+/* 3780 */ 103, 18, 132, 193, 129, 63, 25, 129, 57, 37,
+/* 3790 */ 129, 53, 45, 129, 50, 51, 129, 47, 57, 129,
+/* 3800 */ 45, 61, 129, 43, 65, 129, 41, 69, 129, 39,
+/* 3810 */ 73, 129, 38, 25, 92, 21, 129, 36, 21, 97,
+/* 3820 */ 18, 129, 35, 18, 102, 14, 129, 34, 16, 106,
+/* 3830 */ 11, 129, 33, 14, 108, 10, 129, 32, 12, 111,
+/* 3840 */ 8, 129, 32, 10, 113, 6, 129, 31, 10, 114,
+/* 3850 */ 6, 129, 31, 8, 115, 5, 129, 30, 8, 116,
+/* 3860 */ 5, 129, 30, 7, 116, 5, 129, 30, 6, 117,
+/* 3870 */ 4, 130, 30, 5, 117, 4, 131, 30, 5, 75,
+/* 3880 */ 4, 116, 5, 129, 31, 5, 75, 4, 116, 4,
+/* 3890 */ 129, 31, 6, 75, 4, 115, 5, 129, 32, 7,
+/* 3900 */ 75, 4, 114, 5, 129, 32, 9, 75, 4, 112,
+/* 3910 */ 6, 129, 33, 11, 75, 4, 110, 7, 129, 34,
+/* 3920 */ 15, 75, 4, 107, 9, 129, 35, 44, 103, 12,
+/* 3930 */ 129, 36, 43, 103, 18, 129, 38, 41, 103, 18,
+/* 3940 */ 129, 39, 40, 103, 18, 129, 41, 38, 103, 18,
+/* 3950 */ 129, 44, 35, 129, 48, 31, 129, 52, 27, 129,
+/* 3960 */ 61, 18, 129, 193, 129, 30, 4, 117, 4, 132,
+/* 3970 */ 30, 91, 137, 30, 4, 80, 4, 117, 4, 132,
+/* 3980 */ 80, 4, 140, 30, 4, 80, 4, 117, 4, 132,
+/* 3990 */ 30, 91, 137, 30, 4, 117, 4, 132, 193, 129,
+/* 4000 */ 30, 4, 117, 4, 132, 30, 91, 137, 30, 4,
+/* 4010 */ 117, 4, 132, 193, 129, 44, 7, 129, 40, 13,
+/* 4020 */ 129, 37, 17, 129, 35, 20, 129, 34, 22, 129,
+/* 4030 */ 33, 23, 129, 32, 24, 129, 32, 23, 129, 31,
+/* 4040 */ 6, 41, 13, 129, 31, 5, 42, 11, 129, 30,
+/* 4050 */ 5, 44, 7, 129, 30, 4, 132, 30, 5, 130,
+/* 4060 */ 31, 5, 129, 31, 6, 117, 4, 129, 31, 8,
+/* 4070 */ 117, 4, 129, 32, 9, 117, 4, 129, 33, 11,
+/* 4080 */ 117, 4, 129, 34, 87, 129, 35, 86, 129, 36,
+/* 4090 */ 85, 129, 37, 84, 129, 38, 83, 129, 40, 81,
+/* 4100 */ 129, 42, 79, 129, 45, 76, 129, 50, 71, 129,
+/* 4110 */ 117, 4, 132, 193, 129, 30, 4, 117, 4, 132,
+/* 4120 */ 30, 91, 137, 30, 4, 76, 8, 117, 4, 129,
+/* 4130 */ 30, 4, 73, 13, 117, 4, 129, 30, 4, 70,
+/* 4140 */ 18, 117, 4, 129, 30, 4, 67, 23, 117, 4,
+/* 4150 */ 129, 65, 26, 129, 62, 31, 129, 59, 35, 129,
+/* 4160 */ 56, 29, 89, 7, 129, 53, 29, 91, 7, 129,
+/* 4170 */ 50, 29, 93, 7, 129, 47, 29, 95, 6, 129,
+/* 4180 */ 30, 4, 45, 29, 96, 7, 129, 30, 4, 42,
+/* 4190 */ 29, 98, 7, 129, 30, 4, 39, 30, 100, 6,
+/* 4200 */ 129, 30, 4, 36, 30, 101, 7, 129, 30, 33,
+/* 4210 */ 103, 7, 117, 4, 129, 30, 30, 105, 6, 117,
+/* 4220 */ 4, 129, 30, 27, 106, 7, 117, 4, 129, 30,
+/* 4230 */ 25, 108, 7, 117, 4, 129, 30, 22, 110, 11,
+/* 4240 */ 129, 30, 19, 111, 10, 129, 30, 16, 113, 8,
+/* 4250 */ 129, 30, 13, 115, 6, 129, 30, 11, 116, 5,
+/* 4260 */ 129, 30, 8, 117, 4, 129, 30, 5, 117, 4,
+/* 4270 */ 129, 30, 4, 117, 4, 130, 30, 4, 130, 193,
+/* 4280 */ 129, 30, 4, 117, 4, 132, 30, 91, 137, 30,
+/* 4290 */ 4, 117, 4, 132, 30, 4, 144, 30, 5, 130,
+/* 4300 */ 30, 7, 129, 30, 8, 129, 30, 11, 129, 30,
+/* 4310 */ 18, 132, 193, 129, 30, 4, 117, 4, 132, 30,
+/* 4320 */ 91, 132, 30, 4, 103, 18, 129, 30, 4, 97,
+/* 4330 */ 24, 129, 30, 4, 92, 29, 129, 30, 4, 87,
+/* 4340 */ 34, 129, 81, 40, 129, 76, 45, 129, 70, 49,
+/* 4350 */ 129, 65, 49, 129, 60, 49, 129, 55, 49, 129,
+/* 4360 */ 50, 48, 129, 44, 49, 129, 39, 48, 129, 33,
+/* 4370 */ 49, 129, 30, 47, 129, 34, 37, 129, 40, 26,
+/* 4380 */ 129, 46, 19, 129, 52, 19, 129, 58, 19, 129,
+/* 4390 */ 64, 19, 129, 70, 19, 129, 76, 19, 129, 82,
+/* 4400 */ 19, 129, 30, 4, 88, 18, 129, 30, 4, 94,
+/* 4410 */ 18, 129, 30, 4, 100, 18, 129, 30, 4, 106,
+/* 4420 */ 15, 129, 30, 91, 137, 30, 4, 117, 4, 132,
+/* 4430 */ 193, 129, 30, 4, 117, 4, 132, 30, 91, 132,
+/* 4440 */ 30, 4, 107, 14, 129, 30, 4, 104, 17, 129,
+/* 4450 */ 30, 4, 101, 20, 129, 30, 4, 99, 22, 129,
+/* 4460 */ 96, 25, 129, 93, 28, 129, 91, 28, 129, 88,
+/* 4470 */ 29, 129, 85, 29, 129, 82, 29, 129, 79, 29,
+/* 4480 */ 129, 76, 29, 129, 74, 29, 129, 71, 29, 129,
+/* 4490 */ 68, 29, 129, 65, 29, 129, 62, 29, 129, 60,
+/* 4500 */ 29, 129, 57, 29, 129, 54, 29, 129, 51, 29,
+/* 4510 */ 129, 49, 28, 129, 46, 29, 129, 43, 29, 129,
+/* 4520 */ 40, 29, 117, 4, 129, 37, 29, 117, 4, 129,
+/* 4530 */ 35, 29, 117, 4, 129, 32, 29, 117, 4, 129,
+/* 4540 */ 30, 91, 132, 117, 4, 132, 193, 129, 63, 25,
+/* 4550 */ 129, 57, 37, 129, 53, 45, 129, 50, 51, 129,
+/* 4560 */ 47, 57, 129, 45, 61, 129, 43, 65, 129, 41,
+/* 4570 */ 69, 129, 39, 73, 129, 38, 21, 92, 21, 129,
+/* 4580 */ 36, 18, 97, 18, 129, 35, 14, 102, 14, 129,
+/* 4590 */ 34, 11, 106, 11, 129, 33, 10, 108, 10, 129,
+/* 4600 */ 32, 8, 111, 8, 129, 32, 6, 113, 6, 129,
+/* 4610 */ 31, 6, 114, 6, 129, 31, 5, 115, 5, 129,
+/* 4620 */ 30, 5, 116, 5, 130, 30, 4, 117, 4, 132,
+/* 4630 */ 30, 5, 116, 5, 130, 31, 5, 115, 5, 129,
+/* 4640 */ 31, 6, 114, 6, 129, 32, 6, 113, 6, 129,
+/* 4650 */ 32, 8, 111, 8, 129, 33, 10, 108, 10, 129,
+/* 4660 */ 34, 11, 106, 11, 129, 35, 14, 102, 14, 129,
+/* 4670 */ 36, 18, 97, 18, 129, 38, 21, 92, 21, 129,
+/* 4680 */ 39, 73, 129, 41, 69, 129, 43, 65, 129, 45,
+/* 4690 */ 61, 129, 47, 57, 129, 50, 51, 129, 53, 45,
+/* 4700 */ 129, 57, 37, 129, 63, 25, 129, 193, 129, 30,
+/* 4710 */ 4, 117, 4, 132, 30, 91, 137, 30, 4, 80,
+/* 4720 */ 4, 117, 4, 132, 80, 4, 117, 4, 134, 80,
+/* 4730 */ 5, 116, 5, 131, 80, 6, 115, 6, 130, 81,
+/* 4740 */ 6, 114, 6, 129, 81, 8, 112, 8, 129, 81,
+/* 4750 */ 9, 111, 9, 129, 82, 10, 109, 10, 129, 82,
+/* 4760 */ 13, 106, 13, 129, 83, 35, 129, 84, 33, 129,
+/* 4770 */ 85, 31, 129, 86, 29, 129, 88, 25, 129, 90,
+/* 4780 */ 21, 129, 93, 15, 129, 96, 9, 129, 193, 129,
+/* 4790 */ 63, 25, 129, 57, 37, 129, 53, 45, 129, 50,
+/* 4800 */ 51, 129, 47, 57, 129, 45, 61, 129, 43, 65,
+/* 4810 */ 129, 41, 69, 129, 39, 73, 129, 38, 21, 92,
+/* 4820 */ 21, 129, 36, 18, 97, 18, 129, 35, 14, 102,
+/* 4830 */ 14, 129, 34, 11, 106, 11, 129, 33, 10, 108,
+/* 4840 */ 10, 129, 32, 8, 111, 8, 129, 32, 6, 113,
+/* 4850 */ 6, 129, 31, 6, 114, 6, 129, 31, 5, 115,
+/* 4860 */ 5, 129, 30, 5, 116, 5, 130, 30, 4, 39,
+/* 4870 */ 2, 117, 4, 129, 30, 4, 40, 4, 117, 4,
+/* 4880 */ 129, 30, 4, 41, 5, 117, 4, 129, 30, 4,
+/* 4890 */ 41, 6, 117, 4, 129, 30, 5, 40, 8, 116,
+/* 4900 */ 5, 129, 30, 5, 39, 10, 116, 5, 129, 31,
+/* 4910 */ 5, 38, 11, 115, 5, 129, 31, 18, 114, 6,
+/* 4920 */ 129, 32, 17, 113, 6, 129, 32, 16, 111, 8,
+/* 4930 */ 129, 33, 15, 108, 10, 129, 33, 14, 106, 11,
+/* 4940 */ 129, 32, 17, 102, 14, 129, 31, 23, 97, 18,
+/* 4950 */ 129, 31, 28, 92, 21, 129, 30, 82, 129, 30,
+/* 4960 */ 80, 129, 30, 11, 43, 65, 129, 30, 10, 45,
+/* 4970 */ 61, 129, 31, 8, 47, 57, 129, 32, 6, 50,
+/* 4980 */ 51, 129, 33, 5, 53, 45, 129, 35, 4, 57,
+/* 4990 */ 37, 129, 38, 2, 63, 25, 129, 193, 129, 30,
+/* 5000 */ 4, 117, 4, 132, 30, 91, 137, 30, 4, 76,
+/* 5010 */ 8, 117, 4, 129, 30, 4, 73, 11, 117, 4,
+/* 5020 */ 129, 30, 4, 70, 14, 117, 4, 129, 30, 4,
+/* 5030 */ 67, 17, 117, 4, 129, 65, 19, 117, 4, 129,
+/* 5040 */ 62, 22, 117, 4, 129, 59, 25, 117, 4, 129,
+/* 5050 */ 56, 28, 117, 4, 129, 53, 31, 117, 4, 129,
+/* 5060 */ 50, 34, 117, 4, 129, 47, 29, 80, 5, 116,
+/* 5070 */ 5, 129, 30, 4, 45, 29, 80, 5, 116, 5,
+/* 5080 */ 129, 30, 4, 42, 29, 80, 5, 116, 5, 129,
+/* 5090 */ 30, 4, 39, 30, 80, 6, 115, 6, 129, 30,
+/* 5100 */ 4, 36, 30, 80, 6, 115, 6, 129, 30, 33,
+/* 5110 */ 81, 6, 114, 6, 129, 30, 30, 81, 8, 112,
+/* 5120 */ 8, 129, 30, 27, 81, 9, 111, 9, 129, 30,
+/* 5130 */ 25, 82, 10, 109, 10, 129, 30, 22, 82, 13,
+/* 5140 */ 106, 13, 129, 30, 19, 83, 35, 129, 30, 16,
+/* 5150 */ 84, 33, 129, 30, 13, 85, 31, 129, 30, 11,
+/* 5160 */ 86, 29, 129, 30, 8, 88, 25, 129, 30, 5,
+/* 5170 */ 90, 21, 129, 30, 4, 93, 15, 129, 30, 4,
+/* 5180 */ 96, 9, 129, 30, 4, 130, 193, 129, 30, 18,
+/* 5190 */ 130, 30, 18, 89, 15, 129, 30, 18, 85, 23,
+/* 5200 */ 129, 34, 11, 83, 27, 129, 34, 9, 81, 31,
+/* 5210 */ 129, 33, 8, 79, 35, 129, 33, 6, 78, 16,
+/* 5220 */ 106, 9, 129, 32, 6, 77, 15, 109, 7, 129,
+/* 5230 */ 32, 5, 76, 14, 111, 6, 129, 31, 5, 75,
+/* 5240 */ 14, 113, 5, 129, 31, 4, 74, 15, 114, 5,
+/* 5250 */ 129, 31, 4, 74, 14, 115, 4, 129, 30, 4,
+/* 5260 */ 73, 15, 116, 4, 129, 30, 4, 73, 14, 116,
+/* 5270 */ 4, 129, 30, 4, 73, 14, 117, 4, 129, 30,
+/* 5280 */ 4, 72, 15, 117, 4, 130, 30, 4, 71, 15,
+/* 5290 */ 117, 4, 130, 30, 4, 70, 15, 117, 4, 129,
+/* 5300 */ 30, 5, 70, 15, 117, 4, 129, 30, 5, 69,
+/* 5310 */ 15, 116, 5, 129, 30, 6, 68, 16, 115, 5,
+/* 5320 */ 129, 31, 6, 67, 16, 114, 6, 129, 31, 7,
+/* 5330 */ 66, 17, 113, 6, 129, 32, 7, 64, 18, 111,
+/* 5340 */ 8, 129, 32, 8, 62, 19, 109, 9, 129, 33,
+/* 5350 */ 9, 60, 20, 107, 10, 129, 34, 11, 57, 22,
+/* 5360 */ 103, 13, 129, 35, 43, 103, 18, 129, 36, 41,
+/* 5370 */ 103, 18, 129, 38, 38, 103, 18, 129, 39, 35,
+/* 5380 */ 103, 18, 129, 41, 31, 129, 43, 27, 129, 46,
+/* 5390 */ 22, 129, 49, 14, 129, 193, 129, 103, 18, 132,
+/* 5400 */ 110, 11, 129, 113, 8, 129, 114, 7, 129, 116,
+/* 5410 */ 5, 130, 117, 4, 132, 30, 4, 117, 4, 132,
+/* 5420 */ 30, 91, 137, 30, 4, 117, 4, 132, 117, 4,
+/* 5430 */ 132, 116, 5, 130, 114, 7, 129, 113, 8, 129,
+/* 5440 */ 110, 11, 129, 103, 18, 132, 193, 129, 117, 4,
+/* 5450 */ 132, 56, 65, 129, 50, 71, 129, 46, 75, 129,
+/* 5460 */ 44, 77, 129, 42, 79, 129, 40, 81, 129, 38,
+/* 5470 */ 83, 129, 36, 85, 129, 35, 86, 129, 34, 20,
+/* 5480 */ 117, 4, 129, 33, 17, 117, 4, 129, 32, 15,
+/* 5490 */ 117, 4, 129, 32, 13, 117, 4, 129, 31, 12,
+/* 5500 */ 129, 31, 10, 129, 31, 9, 129, 30, 9, 129,
+/* 5510 */ 30, 8, 130, 30, 7, 132, 31, 6, 130, 31,
+/* 5520 */ 7, 129, 32, 6, 129, 32, 7, 129, 33, 7,
+/* 5530 */ 129, 34, 7, 129, 35, 8, 129, 36, 9, 117,
+/* 5540 */ 4, 129, 38, 9, 117, 4, 129, 40, 10, 117,
+/* 5550 */ 4, 129, 42, 12, 117, 4, 129, 44, 77, 129,
+/* 5560 */ 46, 75, 129, 50, 71, 129, 56, 43, 100, 21,
+/* 5570 */ 129, 117, 4, 132, 193, 129, 117, 4, 132, 115,
+/* 5580 */ 6, 129, 110, 11, 129, 105, 16, 129, 101, 20,
+/* 5590 */ 129, 96, 25, 129, 92, 29, 129, 87, 34, 129,
+/* 5600 */ 83, 38, 129, 78, 43, 129, 74, 47, 129, 70,
+/* 5610 */ 42, 117, 4, 129, 65, 42, 117, 4, 129, 60,
+/* 5620 */ 43, 117, 4, 129, 56, 42, 129, 51, 42, 129,
+/* 5630 */ 46, 43, 129, 42, 43, 129, 37, 44, 129, 33,
+/* 5640 */ 43, 129, 30, 42, 129, 33, 34, 129, 38, 25,
+/* 5650 */ 129, 42, 16, 129, 47, 15, 129, 52, 15, 129,
+/* 5660 */ 57, 15, 129, 61, 16, 129, 66, 16, 129, 71,
+/* 5670 */ 16, 129, 76, 16, 129, 80, 16, 129, 85, 16,
+/* 5680 */ 117, 4, 129, 90, 16, 117, 4, 129, 95, 16,
+/* 5690 */ 117, 4, 129, 100, 21, 129, 105, 16, 129, 110,
+/* 5700 */ 11, 129, 114, 7, 129, 117, 4, 132, 193, 129,
+/* 5710 */ 117, 4, 132, 115, 6, 129, 110, 11, 129, 105,
+/* 5720 */ 16, 129, 101, 20, 129, 96, 25, 129, 92, 29,
+/* 5730 */ 129, 87, 34, 129, 83, 38, 129, 78, 43, 129,
+/* 5740 */ 74, 47, 129, 70, 42, 117, 4, 129, 65, 42,
+/* 5750 */ 117, 4, 129, 60, 43, 117, 4, 129, 56, 42,
+/* 5760 */ 129, 51, 42, 129, 46, 43, 129, 42, 43, 129,
+/* 5770 */ 37, 44, 129, 33, 43, 129, 30, 42, 129, 33,
+/* 5780 */ 34, 129, 38, 25, 129, 42, 16, 129, 47, 15,
+/* 5790 */ 129, 52, 15, 129, 57, 15, 129, 61, 16, 129,
+/* 5800 */ 65, 17, 129, 60, 27, 129, 56, 36, 129, 51,
+/* 5810 */ 42, 129, 46, 43, 129, 42, 43, 129, 37, 44,
+/* 5820 */ 129, 33, 43, 129, 30, 42, 129, 33, 34, 129,
+/* 5830 */ 38, 25, 129, 42, 16, 129, 47, 15, 129, 52,
+/* 5840 */ 15, 129, 57, 15, 129, 61, 16, 129, 66, 16,
+/* 5850 */ 129, 71, 16, 129, 76, 16, 129, 80, 16, 129,
+/* 5860 */ 85, 16, 117, 4, 129, 90, 16, 117, 4, 129,
+/* 5870 */ 95, 16, 117, 4, 129, 100, 21, 129, 105, 16,
+/* 5880 */ 129, 110, 11, 129, 114, 7, 129, 117, 4, 132,
+/* 5890 */ 193, 129, 30, 4, 117, 4, 132, 30, 4, 115,
+/* 5900 */ 6, 129, 30, 4, 112, 9, 129, 30, 6, 109,
+/* 5910 */ 12, 129, 30, 9, 106, 15, 129, 30, 11, 103,
+/* 5920 */ 18, 129, 30, 14, 100, 21, 129, 30, 4, 38,
+/* 5930 */ 9, 98, 23, 129, 30, 4, 40, 10, 95, 26,
+/* 5940 */ 129, 30, 4, 43, 9, 92, 29, 129, 46, 9,
+/* 5950 */ 89, 32, 129, 49, 8, 86, 28, 117, 4, 129,
+/* 5960 */ 51, 9, 83, 28, 117, 4, 129, 54, 9, 80,
+/* 5970 */ 28, 117, 4, 129, 57, 8, 77, 28, 117, 4,
+/* 5980 */ 129, 59, 9, 74, 28, 129, 62, 37, 129, 64,
+/* 5990 */ 33, 129, 66, 28, 129, 63, 28, 129, 60, 28,
+/* 6000 */ 129, 57, 28, 129, 54, 33, 129, 51, 39, 129,
+/* 6010 */ 48, 29, 83, 9, 129, 30, 4, 45, 29, 86,
+/* 6020 */ 9, 129, 30, 4, 42, 29, 89, 9, 129, 30,
+/* 6030 */ 4, 39, 29, 92, 8, 129, 30, 4, 36, 29,
+/* 6040 */ 94, 9, 129, 30, 32, 97, 9, 129, 30, 29,
+/* 6050 */ 100, 8, 117, 4, 129, 30, 26, 103, 8, 117,
+/* 6060 */ 4, 129, 30, 23, 105, 9, 117, 4, 129, 30,
+/* 6070 */ 20, 108, 13, 129, 30, 18, 111, 10, 129, 30,
+/* 6080 */ 15, 113, 8, 129, 30, 12, 116, 5, 129, 30,
+/* 6090 */ 9, 117, 4, 129, 30, 6, 117, 4, 129, 30,
+/* 6100 */ 4, 117, 4, 132, 193, 129, 117, 4, 132, 114,
+/* 6110 */ 7, 129, 111, 10, 129, 108, 13, 129, 105, 16,
+/* 6120 */ 129, 102, 19, 129, 100, 21, 129, 96, 25, 129,
+/* 6130 */ 93, 28, 129, 90, 31, 129, 87, 34, 129, 84,
+/* 6140 */ 30, 117, 4, 129, 30, 4, 81, 30, 117, 4,
+/* 6150 */ 129, 30, 4, 78, 30, 117, 4, 129, 30, 4,
+/* 6160 */ 75, 30, 117, 4, 129, 30, 4, 72, 30, 129,
+/* 6170 */ 30, 69, 129, 30, 66, 129, 30, 63, 129, 30,
+/* 6180 */ 60, 129, 30, 57, 129, 30, 54, 129, 30, 51,
+/* 6190 */ 129, 30, 48, 129, 30, 51, 129, 30, 4, 73,
+/* 6200 */ 12, 129, 30, 4, 76, 12, 129, 30, 4, 80,
+/* 6210 */ 12, 129, 30, 4, 83, 12, 129, 87, 12, 129,
+/* 6220 */ 90, 12, 117, 4, 129, 94, 11, 117, 4, 129,
+/* 6230 */ 97, 12, 117, 4, 129, 101, 12, 117, 4, 129,
+/* 6240 */ 104, 17, 129, 108, 13, 129, 111, 10, 129, 115,
+/* 6250 */ 6, 129, 117, 4, 134, 193, 129, 30, 1, 103,
+/* 6260 */ 18, 129, 30, 4, 103, 18, 129, 30, 7, 103,
+/* 6270 */ 18, 129, 30, 9, 103, 18, 129, 30, 12, 110,
+/* 6280 */ 11, 129, 30, 15, 113, 8, 129, 30, 18, 114,
+/* 6290 */ 7, 129, 30, 21, 116, 5, 129, 30, 24, 116,
+/* 6300 */ 5, 129, 30, 27, 117, 4, 129, 30, 30, 117,
+/* 6310 */ 4, 129, 30, 33, 117, 4, 129, 30, 4, 37,
+/* 6320 */ 28, 117, 4, 129, 30, 4, 40, 28, 117, 4,
+/* 6330 */ 129, 30, 4, 42, 29, 117, 4, 129, 30, 4,
+/* 6340 */ 45, 29, 117, 4, 129, 30, 4, 48, 29, 117,
+/* 6350 */ 4, 129, 30, 4, 51, 29, 117, 4, 129, 30,
+/* 6360 */ 4, 54, 29, 117, 4, 129, 30, 4, 57, 29,
+/* 6370 */ 117, 4, 129, 30, 4, 59, 30, 117, 4, 129,
+/* 6380 */ 30, 4, 62, 30, 117, 4, 129, 30, 4, 65,
+/* 6390 */ 30, 117, 4, 129, 30, 4, 68, 30, 117, 4,
+/* 6400 */ 129, 30, 4, 71, 30, 117, 4, 129, 30, 4,
+/* 6410 */ 74, 30, 117, 4, 129, 30, 4, 77, 30, 117,
+/* 6420 */ 4, 129, 30, 4, 80, 30, 117, 4, 129, 30,
+/* 6430 */ 4, 83, 30, 117, 4, 129, 30, 4, 86, 35,
+/* 6440 */ 129, 30, 4, 89, 32, 129, 30, 4, 91, 30,
+/* 6450 */ 129, 30, 4, 94, 27, 129, 30, 5, 97, 24,
+/* 6460 */ 129, 30, 5, 100, 21, 129, 30, 7, 103, 18,
+/* 6470 */ 129, 30, 8, 106, 15, 129, 30, 11, 109, 12,
+/* 6480 */ 129, 30, 18, 112, 9, 129, 30, 18, 115, 6,
+/* 6490 */ 129, 30, 18, 117, 4, 129, 30, 18, 120, 1,
+/* 6500 */ 129, 193, 129, 42, 8, 129, 38, 16, 129, 36,
+/* 6510 */ 20, 129, 34, 24, 71, 5, 129, 33, 26, 69,
+/* 6520 */ 10, 129, 32, 28, 68, 13, 129, 31, 30, 68,
+/* 6530 */ 14, 129, 31, 9, 52, 9, 68, 15, 129, 30,
+/* 6540 */ 8, 54, 8, 69, 14, 129, 30, 7, 55, 7,
+/* 6550 */ 71, 4, 78, 6, 129, 30, 6, 56, 6, 79,
+/* 6560 */ 5, 129, 30, 6, 56, 6, 80, 4, 130, 31,
+/* 6570 */ 5, 56, 5, 80, 4, 129, 31, 5, 56, 5,
+/* 6580 */ 79, 5, 129, 32, 5, 55, 5, 78, 6, 129,
+/* 6590 */ 33, 5, 54, 5, 77, 7, 129, 34, 6, 52,
+/* 6600 */ 6, 74, 9, 129, 35, 48, 129, 33, 49, 129,
+/* 6610 */ 32, 49, 129, 31, 49, 129, 30, 49, 129, 30,
+/* 6620 */ 47, 129, 30, 45, 129, 30, 41, 129, 30, 6,
+/* 6630 */ 129, 30, 4, 129, 30, 3, 129, 30, 2, 129,
+/* 6640 */ 193, 129, 30, 4, 117, 4, 130, 31, 90, 136,
+/* 6650 */ 37, 5, 72, 5, 129, 35, 5, 74, 5, 129,
+/* 6660 */ 33, 5, 76, 5, 129, 32, 5, 77, 5, 129,
+/* 6670 */ 31, 5, 78, 5, 129, 31, 4, 79, 4, 129,
+/* 6680 */ 30, 5, 79, 5, 131, 30, 6, 78, 6, 129,
+/* 6690 */ 30, 7, 77, 7, 129, 31, 8, 75, 8, 129,
+/* 6700 */ 31, 11, 72, 11, 129, 32, 15, 67, 15, 129,
+/* 6710 */ 33, 48, 129, 34, 46, 129, 35, 44, 129, 37,
+/* 6720 */ 40, 129, 39, 36, 129, 42, 30, 129, 46, 22,
+/* 6730 */ 129, 193, 129, 48, 18, 129, 43, 28, 129, 41,
+/* 6740 */ 32, 129, 39, 36, 129, 37, 40, 129, 35, 44,
+/* 6750 */ 129, 34, 46, 129, 33, 13, 68, 13, 129, 32,
+/* 6760 */ 9, 73, 9, 129, 32, 7, 75, 7, 129, 31,
+/* 6770 */ 6, 77, 6, 129, 31, 5, 78, 5, 129, 30,
+/* 6780 */ 5, 79, 5, 129, 30, 4, 80, 4, 133, 31,
+/* 6790 */ 3, 79, 4, 129, 31, 4, 79, 4, 129, 32,
+/* 6800 */ 3, 78, 4, 129, 32, 4, 76, 6, 129, 33,
+/* 6810 */ 4, 74, 7, 129, 34, 4, 72, 8, 129, 35,
+/* 6820 */ 5, 72, 7, 129, 37, 5, 73, 4, 129, 39,
+/* 6830 */ 4, 74, 1, 129, 129, 193, 129, 46, 22, 129,
+/* 6840 */ 42, 30, 129, 39, 36, 129, 37, 40, 129, 35,
+/* 6850 */ 44, 129, 34, 46, 129, 33, 48, 129, 32, 15,
+/* 6860 */ 67, 15, 129, 31, 11, 72, 11, 129, 31, 8,
+/* 6870 */ 75, 8, 129, 30, 7, 77, 7, 129, 30, 6,
+/* 6880 */ 78, 6, 129, 30, 5, 79, 5, 131, 31, 4,
+/* 6890 */ 79, 4, 129, 31, 5, 78, 5, 129, 32, 5,
+/* 6900 */ 77, 5, 129, 33, 5, 76, 5, 129, 35, 5,
+/* 6910 */ 74, 5, 117, 4, 129, 37, 5, 72, 5, 117,
+/* 6920 */ 4, 129, 30, 91, 136, 30, 4, 130, 193, 129,
+/* 6930 */ 48, 18, 129, 43, 28, 129, 41, 32, 129, 39,
+/* 6940 */ 36, 129, 37, 40, 129, 35, 44, 129, 34, 46,
+/* 6950 */ 129, 33, 13, 55, 4, 68, 13, 129, 32, 9,
+/* 6960 */ 55, 4, 73, 9, 129, 32, 7, 55, 4, 75,
+/* 6970 */ 7, 129, 31, 6, 55, 4, 77, 6, 129, 31,
+/* 6980 */ 5, 55, 4, 78, 5, 129, 30, 5, 55, 4,
+/* 6990 */ 79, 5, 129, 30, 4, 55, 4, 80, 4, 132,
+/* 7000 */ 30, 4, 55, 4, 79, 5, 129, 31, 3, 55,
+/* 7010 */ 4, 78, 5, 129, 31, 4, 55, 4, 77, 6,
+/* 7020 */ 129, 32, 3, 55, 4, 75, 7, 129, 32, 4,
+/* 7030 */ 55, 4, 73, 9, 129, 33, 4, 55, 4, 68,
+/* 7040 */ 13, 129, 34, 4, 55, 25, 129, 35, 5, 55,
+/* 7050 */ 24, 129, 37, 5, 55, 22, 129, 39, 4, 55,
+/* 7060 */ 20, 129, 55, 18, 129, 55, 16, 129, 55, 11,
+/* 7070 */ 129, 193, 129, 80, 4, 129, 30, 4, 80, 4,
+/* 7080 */ 130, 30, 78, 129, 30, 82, 129, 30, 85, 129,
+/* 7090 */ 30, 87, 129, 30, 88, 129, 30, 89, 129, 30,
+/* 7100 */ 90, 130, 30, 4, 80, 4, 115, 6, 129, 30,
+/* 7110 */ 4, 80, 4, 117, 4, 129, 80, 4, 105, 6,
+/* 7120 */ 117, 4, 129, 80, 4, 103, 10, 116, 5, 129,
+/* 7130 */ 80, 4, 102, 19, 129, 80, 4, 101, 19, 129,
+/* 7140 */ 101, 19, 129, 101, 18, 129, 102, 16, 129, 103,
+/* 7150 */ 12, 129, 105, 6, 129, 193, 129, 12, 10, 59,
+/* 7160 */ 11, 129, 9, 16, 55, 19, 129, 7, 20, 53,
+/* 7170 */ 23, 129, 6, 7, 23, 5, 32, 6, 51, 27,
+/* 7180 */ 129, 4, 7, 25, 16, 50, 29, 129, 3, 6,
+/* 7190 */ 27, 16, 49, 31, 129, 2, 6, 28, 16, 48,
+/* 7200 */ 33, 129, 1, 6, 27, 18, 47, 35, 129, 1,
+/* 7210 */ 6, 27, 31, 71, 12, 129, 1, 5, 26, 15,
+/* 7220 */ 44, 10, 75, 8, 129, 1, 5, 25, 14, 45,
+/* 7230 */ 7, 77, 7, 129, 1, 5, 25, 13, 45, 5,
+/* 7240 */ 79, 5, 129, 1, 5, 24, 14, 45, 4, 80,
+/* 7250 */ 4, 129, 1, 5, 24, 13, 45, 4, 80, 4,
+/* 7260 */ 129, 1, 5, 23, 14, 45, 4, 80, 4, 129,
+/* 7270 */ 1, 5, 23, 13, 45, 4, 80, 4, 129, 1,
+/* 7280 */ 6, 22, 13, 45, 5, 79, 5, 129, 1, 6,
+/* 7290 */ 21, 14, 45, 7, 77, 7, 129, 1, 7, 21,
+/* 7300 */ 13, 46, 8, 75, 8, 129, 1, 8, 20, 13,
+/* 7310 */ 46, 12, 71, 12, 129, 1, 10, 18, 15, 47,
+/* 7320 */ 35, 129, 2, 30, 48, 33, 129, 3, 29, 49,
+/* 7330 */ 32, 129, 4, 27, 50, 31, 129, 5, 25, 51,
+/* 7340 */ 27, 80, 2, 86, 4, 129, 7, 21, 53, 23,
+/* 7350 */ 80, 3, 85, 6, 129, 9, 17, 55, 19, 80,
+/* 7360 */ 12, 129, 12, 12, 59, 11, 81, 11, 129, 82,
+/* 7370 */ 10, 129, 84, 7, 129, 86, 4, 129, 193, 129,
+/* 7380 */ 30, 4, 117, 4, 130, 30, 91, 136, 30, 4,
+/* 7390 */ 72, 5, 129, 30, 4, 74, 5, 129, 75, 5,
+/* 7400 */ 129, 76, 5, 129, 76, 6, 129, 77, 6, 130,
+/* 7410 */ 77, 7, 130, 76, 8, 129, 30, 4, 75, 9,
+/* 7420 */ 129, 30, 4, 72, 12, 129, 30, 54, 129, 30,
+/* 7430 */ 53, 130, 30, 52, 129, 30, 51, 129, 30, 49,
+/* 7440 */ 129, 30, 46, 129, 30, 42, 129, 30, 4, 130,
+/* 7450 */ 193, 129, 30, 4, 80, 4, 129, 30, 4, 80,
+/* 7460 */ 4, 100, 6, 129, 30, 54, 98, 10, 129, 30,
+/* 7470 */ 54, 97, 12, 129, 30, 54, 96, 14, 131, 30,
+/* 7480 */ 54, 97, 12, 129, 30, 54, 98, 10, 129, 30,
+/* 7490 */ 54, 100, 6, 129, 30, 4, 130, 193, 129, 7,
+/* 7500 */ 6, 129, 4, 11, 129, 3, 13, 129, 2, 14,
+/* 7510 */ 129, 1, 15, 130, 1, 3, 6, 9, 129, 1,
+/* 7520 */ 3, 7, 6, 129, 1, 3, 130, 1, 4, 129,
+/* 7530 */ 1, 5, 80, 4, 129, 1, 7, 80, 4, 100,
+/* 7540 */ 6, 129, 2, 82, 98, 10, 129, 3, 81, 97,
+/* 7550 */ 12, 129, 4, 80, 96, 14, 129, 5, 79, 96,
+/* 7560 */ 14, 129, 7, 77, 96, 14, 129, 10, 74, 97,
+/* 7570 */ 12, 129, 14, 70, 98, 10, 129, 19, 65, 100,
+/* 7580 */ 6, 129, 193, 129, 30, 4, 117, 4, 130, 30,
+/* 7590 */ 91, 136, 30, 4, 57, 9, 129, 30, 4, 55,
+/* 7600 */ 12, 129, 52, 17, 129, 50, 20, 129, 48, 24,
+/* 7610 */ 129, 46, 27, 129, 44, 21, 69, 6, 129, 41,
+/* 7620 */ 22, 70, 6, 80, 4, 129, 30, 4, 39, 21,
+/* 7630 */ 72, 6, 80, 4, 129, 30, 4, 36, 22, 73,
+/* 7640 */ 11, 129, 30, 26, 75, 9, 129, 30, 23, 76,
+/* 7650 */ 8, 129, 30, 21, 78, 6, 129, 30, 19, 79,
+/* 7660 */ 5, 129, 30, 16, 80, 4, 129, 30, 14, 80,
+/* 7670 */ 4, 129, 30, 12, 129, 30, 10, 129, 30, 7,
+/* 7680 */ 129, 30, 5, 129, 30, 4, 130, 193, 129, 30,
+/* 7690 */ 4, 117, 4, 130, 30, 91, 136, 30, 4, 130,
+/* 7700 */ 193, 129, 30, 4, 80, 4, 130, 30, 54, 136,
+/* 7710 */ 30, 4, 72, 5, 129, 30, 4, 74, 5, 129,
+/* 7720 */ 75, 5, 129, 76, 5, 129, 30, 4, 75, 7,
+/* 7730 */ 129, 30, 4, 74, 9, 129, 30, 54, 132, 30,
+/* 7740 */ 53, 129, 30, 52, 129, 30, 51, 129, 30, 48,
+/* 7750 */ 129, 30, 4, 72, 5, 129, 30, 4, 74, 5,
+/* 7760 */ 129, 75, 5, 129, 76, 5, 129, 30, 4, 75,
+/* 7770 */ 7, 129, 30, 4, 74, 9, 129, 30, 54, 132,
+/* 7780 */ 30, 53, 129, 30, 52, 129, 30, 51, 129, 30,
+/* 7790 */ 48, 129, 30, 4, 130, 193, 129, 30, 4, 80,
+/* 7800 */ 4, 130, 30, 54, 136, 30, 4, 72, 5, 129,
+/* 7810 */ 30, 4, 74, 5, 129, 75, 5, 129, 76, 5,
+/* 7820 */ 129, 76, 6, 129, 77, 6, 130, 77, 7, 130,
+/* 7830 */ 76, 8, 129, 30, 4, 75, 9, 129, 30, 4,
+/* 7840 */ 72, 12, 129, 30, 54, 129, 30, 53, 130, 30,
+/* 7850 */ 52, 129, 30, 51, 129, 30, 49, 129, 30, 46,
+/* 7860 */ 129, 30, 42, 129, 30, 4, 130, 193, 129, 48,
+/* 7870 */ 18, 129, 43, 28, 129, 41, 32, 129, 39, 36,
+/* 7880 */ 129, 37, 40, 129, 35, 44, 129, 34, 46, 129,
+/* 7890 */ 33, 13, 68, 13, 129, 32, 9, 73, 9, 129,
+/* 7900 */ 32, 7, 75, 7, 129, 31, 6, 77, 6, 129,
+/* 7910 */ 31, 5, 78, 5, 129, 30, 5, 79, 5, 129,
+/* 7920 */ 30, 4, 80, 4, 132, 30, 5, 79, 5, 130,
+/* 7930 */ 31, 5, 78, 5, 129, 31, 6, 77, 6, 129,
+/* 7940 */ 32, 7, 75, 7, 129, 32, 9, 73, 9, 129,
+/* 7950 */ 33, 13, 68, 13, 129, 34, 46, 129, 35, 44,
+/* 7960 */ 129, 37, 40, 129, 39, 36, 129, 41, 32, 129,
+/* 7970 */ 43, 28, 129, 48, 18, 129, 193, 129, 1, 3,
+/* 7980 */ 80, 4, 130, 1, 83, 137, 37, 5, 72, 5,
+/* 7990 */ 129, 35, 5, 74, 5, 129, 33, 5, 76, 5,
+/* 8000 */ 129, 32, 5, 77, 5, 129, 31, 5, 78, 5,
+/* 8010 */ 129, 31, 4, 79, 4, 129, 30, 5, 79, 5,
+/* 8020 */ 131, 30, 6, 78, 6, 129, 30, 7, 77, 7,
+/* 8030 */ 129, 31, 8, 75, 8, 129, 31, 11, 72, 11,
+/* 8040 */ 129, 32, 15, 67, 15, 129, 33, 48, 129, 34,
+/* 8050 */ 46, 129, 35, 44, 129, 37, 40, 129, 39, 36,
+/* 8060 */ 129, 42, 30, 129, 46, 22, 129, 193, 129, 46,
+/* 8070 */ 22, 129, 42, 30, 129, 39, 36, 129, 37, 40,
+/* 8080 */ 129, 35, 44, 129, 34, 46, 129, 33, 48, 129,
+/* 8090 */ 32, 15, 67, 15, 129, 31, 11, 72, 11, 129,
+/* 8100 */ 31, 8, 75, 8, 129, 30, 7, 77, 7, 129,
+/* 8110 */ 30, 6, 78, 6, 129, 30, 5, 79, 5, 131,
+/* 8120 */ 31, 4, 79, 4, 129, 31, 5, 78, 5, 129,
+/* 8130 */ 32, 5, 77, 5, 129, 33, 5, 76, 5, 129,
+/* 8140 */ 35, 5, 74, 5, 129, 37, 5, 72, 5, 129,
+/* 8150 */ 1, 83, 136, 1, 3, 80, 4, 130, 193, 129,
+/* 8160 */ 30, 4, 80, 4, 130, 30, 54, 136, 30, 4,
+/* 8170 */ 68, 6, 129, 30, 4, 70, 6, 129, 71, 7,
+/* 8180 */ 129, 72, 7, 129, 73, 7, 129, 74, 7, 129,
+/* 8190 */ 74, 8, 129, 75, 8, 130, 69, 15, 129, 67,
+/* 8200 */ 17, 129, 66, 18, 129, 65, 19, 130, 65, 18,
+/* 8210 */ 130, 66, 16, 129, 67, 13, 129, 69, 8, 129,
+/* 8220 */ 193, 129, 30, 13, 64, 8, 129, 30, 13, 61,
+/* 8230 */ 14, 129, 30, 13, 59, 18, 129, 30, 13, 57,
+/* 8240 */ 22, 129, 33, 8, 56, 24, 129, 32, 7, 55,
+/* 8250 */ 26, 129, 32, 6, 54, 28, 129, 31, 6, 53,
+/* 8260 */ 16, 77, 6, 129, 31, 5, 53, 14, 79, 4,
+/* 8270 */ 129, 30, 5, 52, 14, 80, 4, 129, 30, 5,
+/* 8280 */ 52, 13, 80, 4, 129, 30, 4, 52, 13, 80,
+/* 8290 */ 4, 129, 30, 4, 52, 12, 80, 4, 129, 30,
+/* 8300 */ 4, 51, 13, 80, 4, 130, 30, 4, 50, 13,
+/* 8310 */ 79, 5, 129, 30, 4, 50, 13, 78, 5, 129,
+/* 8320 */ 30, 5, 49, 14, 77, 6, 129, 31, 4, 49,
+/* 8330 */ 13, 76, 6, 129, 31, 5, 48, 14, 75, 7,
+/* 8340 */ 129, 32, 5, 47, 14, 73, 8, 129, 32, 6,
+/* 8350 */ 45, 16, 71, 13, 129, 33, 27, 71, 13, 129,
+/* 8360 */ 34, 26, 71, 13, 129, 35, 24, 71, 13, 129,
+/* 8370 */ 37, 20, 129, 39, 16, 129, 43, 9, 129, 193,
+/* 8380 */ 129, 80, 4, 131, 41, 56, 129, 37, 60, 129,
+/* 8390 */ 35, 62, 129, 33, 64, 129, 32, 65, 129, 31,
+/* 8400 */ 66, 129, 30, 67, 130, 30, 11, 80, 4, 129,
+/* 8410 */ 30, 9, 80, 4, 129, 30, 8, 80, 4, 129,
+/* 8420 */ 31, 7, 80, 4, 129, 31, 6, 129, 32, 5,
+/* 8430 */ 129, 33, 5, 129, 35, 4, 129, 38, 3, 129,
+/* 8440 */ 193, 129, 80, 4, 130, 42, 42, 129, 38, 46,
+/* 8450 */ 129, 35, 49, 129, 33, 51, 129, 32, 52, 129,
+/* 8460 */ 31, 53, 130, 30, 54, 129, 30, 12, 129, 30,
+/* 8470 */ 9, 129, 30, 8, 129, 30, 7, 130, 31, 6,
+/* 8480 */ 130, 32, 6, 129, 33, 5, 129, 34, 5, 129,
+/* 8490 */ 35, 5, 80, 4, 129, 37, 5, 80, 4, 129,
+/* 8500 */ 30, 54, 136, 30, 4, 130, 193, 129, 80, 4,
+/* 8510 */ 130, 77, 7, 129, 74, 10, 129, 70, 14, 129,
+/* 8520 */ 66, 18, 129, 62, 22, 129, 59, 25, 129, 55,
+/* 8530 */ 29, 129, 51, 33, 129, 47, 37, 129, 44, 32,
+/* 8540 */ 80, 4, 129, 40, 32, 80, 4, 129, 36, 32,
+/* 8550 */ 129, 32, 33, 129, 30, 31, 129, 33, 24, 129,
+/* 8560 */ 36, 17, 129, 40, 12, 129, 44, 12, 129, 48,
+/* 8570 */ 12, 129, 51, 13, 129, 55, 13, 129, 59, 13,
+/* 8580 */ 80, 4, 129, 63, 13, 80, 4, 129, 67, 17,
+/* 8590 */ 129, 71, 13, 129, 74, 10, 129, 78, 6, 129,
+/* 8600 */ 80, 4, 131, 193, 129, 80, 4, 130, 77, 7,
+/* 8610 */ 129, 74, 10, 129, 70, 14, 129, 66, 18, 129,
+/* 8620 */ 62, 22, 129, 59, 25, 129, 55, 29, 129, 51,
+/* 8630 */ 33, 129, 47, 37, 129, 44, 32, 80, 4, 129,
+/* 8640 */ 40, 32, 80, 4, 129, 36, 32, 129, 32, 33,
+/* 8650 */ 129, 30, 31, 129, 33, 24, 129, 36, 17, 129,
+/* 8660 */ 40, 12, 129, 44, 12, 129, 47, 13, 129, 44,
+/* 8670 */ 20, 129, 40, 28, 129, 36, 31, 129, 32, 32,
+/* 8680 */ 129, 30, 30, 129, 33, 24, 129, 36, 17, 129,
+/* 8690 */ 40, 12, 129, 44, 12, 129, 48, 12, 129, 51,
+/* 8700 */ 13, 129, 55, 13, 129, 59, 13, 80, 4, 129,
+/* 8710 */ 63, 13, 80, 4, 129, 67, 17, 129, 71, 13,
+/* 8720 */ 129, 74, 10, 129, 78, 6, 129, 80, 4, 131,
+/* 8730 */ 193, 129, 30, 4, 80, 4, 130, 30, 4, 79,
+/* 8740 */ 5, 129, 30, 5, 77, 7, 129, 30, 6, 74,
+/* 8750 */ 10, 129, 30, 8, 72, 12, 129, 30, 11, 69,
+/* 8760 */ 15, 129, 30, 13, 67, 17, 129, 30, 4, 37,
+/* 8770 */ 8, 64, 20, 129, 30, 4, 39, 8, 62, 22,
+/* 8780 */ 129, 41, 8, 59, 25, 129, 43, 8, 57, 27,
+/* 8790 */ 129, 45, 8, 55, 22, 80, 4, 129, 47, 27,
+/* 8800 */ 80, 4, 129, 49, 23, 129, 47, 22, 129, 44,
+/* 8810 */ 23, 129, 42, 22, 129, 30, 4, 39, 27, 129,
+/* 8820 */ 30, 4, 37, 31, 129, 30, 27, 62, 8, 129,
+/* 8830 */ 30, 25, 64, 8, 129, 30, 22, 66, 8, 80,
+/* 8840 */ 4, 129, 30, 20, 68, 8, 80, 4, 129, 30,
+/* 8850 */ 17, 70, 8, 80, 4, 129, 30, 15, 73, 11,
+/* 8860 */ 129, 30, 12, 75, 9, 129, 30, 10, 77, 7,
+/* 8870 */ 129, 30, 7, 79, 5, 129, 30, 5, 80, 4,
+/* 8880 */ 129, 30, 4, 80, 4, 130, 193, 129, 4, 5,
+/* 8890 */ 80, 4, 129, 2, 9, 80, 4, 129, 1, 11,
+/* 8900 */ 77, 7, 129, 1, 12, 74, 10, 129, 1, 12,
+/* 8910 */ 70, 14, 129, 1, 12, 66, 18, 129, 1, 11,
+/* 8920 */ 62, 22, 129, 2, 9, 59, 25, 129, 4, 11,
+/* 8930 */ 55, 29, 129, 7, 12, 51, 33, 129, 10, 12,
+/* 8940 */ 47, 37, 129, 14, 12, 44, 32, 80, 4, 129,
+/* 8950 */ 17, 13, 40, 32, 80, 4, 129, 21, 13, 36,
+/* 8960 */ 32, 129, 25, 40, 129, 29, 32, 129, 33, 24,
+/* 8970 */ 129, 36, 17, 129, 40, 12, 129, 44, 12, 129,
+/* 8980 */ 48, 12, 129, 51, 13, 129, 55, 13, 129, 59,
+/* 8990 */ 13, 80, 4, 129, 63, 13, 80, 4, 129, 67,
+/* 9000 */ 17, 129, 71, 13, 129, 74, 10, 129, 78, 6,
+/* 9010 */ 129, 80, 4, 131, 193, 129, 30, 1, 71, 13,
+/* 9020 */ 129, 30, 3, 71, 13, 129, 30, 6, 71, 13,
+/* 9030 */ 129, 30, 9, 75, 9, 129, 30, 11, 77, 7,
+/* 9040 */ 129, 30, 14, 79, 5, 129, 30, 17, 79, 5,
+/* 9050 */ 129, 30, 19, 80, 4, 129, 30, 22, 80, 4,
+/* 9060 */ 129, 30, 25, 80, 4, 129, 30, 27, 80, 4,
+/* 9070 */ 129, 30, 4, 36, 24, 80, 4, 129, 30, 4,
+/* 9080 */ 38, 25, 80, 4, 129, 30, 4, 41, 24, 80,
+/* 9090 */ 4, 129, 30, 4, 44, 24, 80, 4, 129, 30,
+/* 9100 */ 4, 46, 25, 80, 4, 129, 30, 4, 49, 25,
+/* 9110 */ 80, 4, 129, 30, 4, 52, 24, 80, 4, 129,
+/* 9120 */ 30, 4, 54, 30, 129, 30, 4, 57, 27, 129,
+/* 9130 */ 30, 4, 59, 25, 129, 30, 4, 62, 22, 129,
+/* 9140 */ 30, 4, 65, 19, 129, 30, 5, 67, 17, 129,
+/* 9150 */ 30, 5, 70, 14, 129, 30, 7, 73, 11, 129,
+/* 9160 */ 30, 9, 76, 8, 129, 30, 13, 78, 6, 129,
+/* 9170 */ 30, 13, 81, 3, 129, 30, 13, 129, 193, 2,
+/* 9180 */ 9, 59, 25, 129, 4, 11, 55, 29, 129, 7,
+/* 9190 */ 12, 51, 33, 129, 10, 12, 47, 37, 129, 14,
+/* 9200 */ 12, 44, 32, 80, 4, 129, 17, 13, 40, 32,
+/* 9210 */ 80, 4, 129, 21, 13, 36, 32, 129, 25, 40,
+/* 9220 */ 129, 29, 32, 129, 33, 24, 129, 36, 17, 129,
+/* 9230 */ 40, 12, 129, 44, 12, 129, 48, 12, 129, 51,
+/* 9240 */ 13, 129, 55, 13, 129, 59, 13, 80, 4, 129,
+/* 9250 */ 63, 13, 80, 4, 129, 67, 17, 129, 71, 13,
+/* 9260 */ 129, 74, 10, 129, 78, 6, 129, 80, 4, 131,
+/* 9270 */ 193
+};
+
+char line[DWIDTH];
+char *message;
+char print[DWIDTH];
+int debug, i, j, linen, max, nchars, pc, term, trace, x, y;
+int width = DWIDTH; /* -w option: scrunch letters to 80 columns */
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "w:td")) != -1)
+ switch (ch) {
+ case 'd':
+ debug = 1;
+ break;
+ case 't':
+ trace = 1;
+ break;
+ case 'w':
+ width = atoi(optarg);
+ if (width <= 0)
+ errx(1, "illegal argument for -w option");
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ for (i = 0; i < width; i++) {
+ j = i * 132 / width;
+ print[j] = 1;
+ }
+
+ /* Have now read in the data. Next get the message to be printed. */
+ if (*argv) {
+ for(i=0, j=0; i < argc; i++)
+ j += strlen(argv[i]) + 1;
+ if ((message = malloc((size_t)j)) == NULL)
+ err(1, "malloc");
+ strcpy(message, *argv);
+ while (*++argv) {
+ strcat(message, " ");
+ strcat(message, *argv);
+ }
+ nchars = strlen(message);
+ } else {
+ if ((message = malloc((size_t)MAXMSG)) == NULL)
+ err(1, "malloc");
+ fprintf(stderr,"Message: ");
+ if (fgets(message, MAXMSG, stdin) == NULL) {
+ nchars = 0;
+ message[0] = '\0';
+ } else {
+ nchars = strlen(message);
+
+ /* Get rid of newline. */
+ if (message[nchars - 1] == '\n')
+ message[--nchars] = '\0';
+ }
+ }
+
+ /* some debugging print statements */
+ if (debug) {
+ printf("const int asc_ptr[NCHARS] = {\n");
+ for (i = 0; i < 128; i++) {
+ printf("%4d, ",asc_ptr[i]);
+ if ((i+1) % 8 == 0)
+ printf("\n");
+ }
+ printf("};\nconst unsigned char data_table[NBYTES] = {\n");
+ printf("/* ");
+ for (i = 0; i < 10; i++) printf(" %3d ",i);
+ printf("*/\n");
+ for (i = 0; i < NBYTES; i += 10) {
+ printf("/* %4d */ ",i);
+ for (j = i; j < i+10; j++) {
+ x = data_table[j] & 0377;
+ printf(" %3d, ",x);
+ }
+ putchar('\n');
+ }
+ printf("};\n");
+ }
+
+ /* check message to make sure it's legal */
+ j = 0;
+ for (i = 0; i < nchars; i++)
+ if ((u_char) message[i] >= NCHARS ||
+ asc_ptr[(u_char) message[i]] == 0) {
+ warnx("the character '%c' is not in my character set",
+ message[i]);
+ j++;
+ }
+ if (j)
+ exit(1);
+
+ if (trace)
+ printf("Message '%s' is OK\n",message);
+ /* Now have message. Print it one character at a time. */
+
+ for (i = 0; i < nchars; i++) {
+ if (trace)
+ printf("Char #%d: %c\n", i, message[i]);
+ for (j = 0; j < DWIDTH; j++) line[j] = ' ';
+ pc = asc_ptr[(u_char) message[i]];
+ term = 0;
+ max = 0;
+ linen = 0;
+ while (!term) {
+ if (pc < 0 || pc > NBYTES) {
+ printf("bad pc: %d\n",pc);
+ exit(1);
+ }
+ x = data_table[pc] & 0377;
+ if (trace)
+ printf("pc=%d, term=%d, max=%d, linen=%d, x=%d\n",pc,term,max,linen,x);
+ if (x >= 128) {
+ if (x>192) term++;
+ x = x & 63;
+ while (x--) {
+ if (print[linen++]) {
+ for (j=0; j <= max; j++)
+ if (print[j])
+ putchar(line[j]);
+ putchar('\n');
+ }
+ }
+ for (j = 0; j < DWIDTH; j++) line[j] = ' ';
+ pc++;
+ }
+ else {
+ y = data_table[pc+1];
+ /* compensate for narrow teminals */
+#ifdef notdef
+ x = (x*width + (DWIDTH/2)) / DWIDTH;
+ y = (y*width + (DWIDTH/2)) / DWIDTH;
+#endif
+ max = x+y;
+ while (x < max) line[x++] = '#';
+ pc += 2;
+ if (trace)
+ printf("x=%d, y=%d, max=%d\n",x,y,max);
+ }
+ }
+ }
+
+ free(message);
+ exit(0);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: banner [-d] [-t] [-w width] message ...\n");
+ exit(1);
+}
diff --git a/text_cmds/cat/cat.1 b/text_cmds/cat/cat.1
new file mode 100644
index 0000000..892c990
--- /dev/null
+++ b/text_cmds/cat/cat.1
@@ -0,0 +1,201 @@
+.\"-
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)cat.1 8.3 (Berkeley) 5/2/95
+.\" $FreeBSD: src/bin/cat/cat.1,v 1.25 2005/01/16 16:41:55 ru Exp $
+.\"
+.Dd March 21, 2004
+.Dt CAT 1
+.Os
+.Sh NAME
+.Nm cat
+.Nd concatenate and print files
+.Sh SYNOPSIS
+.Nm
+.Op Fl benstuv
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility reads files sequentially, writing them to the standard output.
+The
+.Ar file
+operands are processed in command-line order.
+If
+.Ar file
+is a single dash
+.Pq Sq \&-
+or absent,
+.Nm
+reads from the standard input.
+If
+.Ar file
+is a
+.Ux
+domain socket,
+.Nm
+connects to it and then reads it until
+.Dv EOF .
+This complements the
+.Ux
+domain binding capability available in
+.Xr inetd 8 .
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl b
+Number the non-blank output lines, starting at 1.
+.It Fl e
+Display non-printing characters (see the
+.Fl v
+option), and display a dollar sign
+.Pq Ql \&$
+at the end of each line.
+.It Fl n
+Number the output lines, starting at 1.
+.It Fl s
+Squeeze multiple adjacent empty lines, causing the output to be
+single spaced.
+.It Fl t
+Display non-printing characters (see the
+.Fl v
+option), and display tab characters as
+.Ql ^I .
+.It Fl u
+Disable output buffering.
+.It Fl v
+Display non-printing characters so they are visible.
+Control characters print as
+.Ql ^X
+for control-X; the delete
+character (octal 0177) prints as
+.Ql ^? .
+.Pf Non- Tn ASCII
+characters (with the high bit set) are printed as
+.Ql M-
+(for meta) followed by the character for the low 7 bits.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The command:
+.Pp
+.Dl "cat file1"
+.Pp
+will print the contents of
+.Ar file1
+to the standard output.
+.Pp
+The command:
+.Pp
+.Dl "cat file1 file2 > file3"
+.Pp
+will sequentially print the contents of
+.Ar file1
+and
+.Ar file2
+to the file
+.Ar file3 ,
+truncating
+.Ar file3
+if it already exists.
+See the manual page for your shell (i.e.,
+.Xr sh 1 )
+for more information on redirection.
+.Pp
+The command:
+.Pp
+.Dl "cat file1 - file2 - file3"
+.Pp
+will print the contents of
+.Ar file1 ,
+print data it receives from the standard input until it receives an
+.Dv EOF
+.Pq Sq ^D
+character, print the contents of
+.Ar file2 ,
+read and output contents of the standard input again, then finally output
+the contents of
+.Ar file3 .
+Note that if the standard input referred to a file, the second dash
+on the command-line would have no effect, since the entire contents of the file
+would have already been read and printed by
+.Nm
+when it encountered the first
+.Ql \&-
+operand.
+.Sh SEE ALSO
+.Xr head 1 ,
+.Xr more 1 ,
+.Xr pr 1 ,
+.Xr sh 1 ,
+.Xr tail 1 ,
+.Xr vis 1 ,
+.Xr zcat 1 ,
+.Xr setbuf 3
+.Rs
+.%A Rob Pike
+.%T "UNIX Style, or cat -v Considered Harmful"
+.%J "USENIX Summer Conference Proceedings"
+.%D 1983
+.Re
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -p1003.2-92
+specification.
+.Pp
+The flags
+.Op Fl benstv
+are extensions to the specification.
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v1 .
+.An Dennis Ritchie
+designed and wrote the first man page.
+It appears to have been
+.Xr cat 1 .
+.Sh BUGS
+Because of the shell language mechanism used to perform output
+redirection, the command
+.Dq Li cat file1 file2 > file1
+will cause the original data in file1 to be destroyed!
+.Pp
+The
+.Nm
+utility does not recognize multibyte characters when the
+.Fl t
+or
+.Fl v
+option is in effect.
diff --git a/text_cmds/cat/cat.c b/text_cmds/cat/cat.c
new file mode 100644
index 0000000..e933951
--- /dev/null
+++ b/text_cmds/cat/cat.c
@@ -0,0 +1,314 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kevin Fall.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+#endif
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/cat/cat.c,v 1.32 2005/01/10 08:39:20 imp Exp $");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifndef NO_UDOM_SUPPORT
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <errno.h>
+#endif
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stddef.h>
+
+int bflag, eflag, nflag, sflag, tflag, vflag;
+int rval;
+const char *filename;
+
+static void usage(void);
+static void scanfiles(char *argv[], int cooked);
+static void cook_cat(FILE *);
+static void raw_cat(int);
+
+#ifndef NO_UDOM_SUPPORT
+static int udom_open(const char *path, int flags);
+#endif
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+
+ setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc, argv, "benstuv")) != -1)
+ switch (ch) {
+ case 'b':
+ bflag = nflag = 1; /* -b implies -n */
+ break;
+ case 'e':
+ eflag = vflag = 1; /* -e implies -v */
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 't':
+ tflag = vflag = 1; /* -t implies -v */
+ break;
+ case 'u':
+ setbuf(stdout, NULL);
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ default:
+ usage();
+ }
+ argv += optind;
+
+ if (bflag || eflag || nflag || sflag || tflag || vflag)
+ scanfiles(argv, 1);
+ else
+ scanfiles(argv, 0);
+ if (fclose(stdout))
+ err(1, "stdout");
+ exit(rval);
+ /* NOTREACHED */
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: cat [-benstuv] [file ...]\n");
+ exit(1);
+ /* NOTREACHED */
+}
+
+static void
+scanfiles(char *argv[], int cooked)
+{
+ int i = 0;
+ char *path;
+ FILE *fp;
+
+ while ((path = argv[i]) != NULL || i == 0) {
+ int fd;
+
+ if (path == NULL || strcmp(path, "-") == 0) {
+ filename = "stdin";
+ fd = STDIN_FILENO;
+ } else {
+ filename = path;
+ fd = open(path, O_RDONLY);
+#ifndef NO_UDOM_SUPPORT
+ if (fd < 0 && errno == EOPNOTSUPP)
+ fd = udom_open(path, O_RDONLY);
+#endif
+ }
+ if (fd < 0) {
+ warn("%s", path);
+ rval = 1;
+ } else if (cooked) {
+ if (fd == STDIN_FILENO)
+ cook_cat(stdin);
+ else {
+ fp = fdopen(fd, "r");
+ cook_cat(fp);
+ fclose(fp);
+ }
+ } else {
+ raw_cat(fd);
+ if (fd != STDIN_FILENO)
+ close(fd);
+ }
+ if (path == NULL)
+ break;
+ ++i;
+ }
+}
+
+static void
+cook_cat(FILE *fp)
+{
+ int ch, gobble, line, prev;
+
+ /* Reset EOF condition on stdin. */
+ if (fp == stdin && feof(stdin))
+ clearerr(stdin);
+
+ line = gobble = 0;
+ for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
+ if (prev == '\n') {
+ if (sflag) {
+ if (ch == '\n') {
+ if (gobble)
+ continue;
+ gobble = 1;
+ } else
+ gobble = 0;
+ }
+ if (nflag && (!bflag || ch != '\n')) {
+ (void)fprintf(stdout, "%6d\t", ++line);
+ if (ferror(stdout))
+ break;
+ }
+ }
+ if (ch == '\n') {
+ if (eflag && putchar('$') == EOF)
+ break;
+ } else if (ch == '\t') {
+ if (tflag) {
+ if (putchar('^') == EOF || putchar('I') == EOF)
+ break;
+ continue;
+ }
+ } else if (vflag) {
+ if (!isascii(ch) && !isprint(ch)) {
+ if (putchar('M') == EOF || putchar('-') == EOF)
+ break;
+ ch = toascii(ch);
+ }
+ if (iscntrl(ch)) {
+ if (putchar('^') == EOF ||
+ putchar(ch == '\177' ? '?' :
+ ch | 0100) == EOF)
+ break;
+ continue;
+ }
+ }
+ if (putchar(ch) == EOF)
+ break;
+ }
+ if (ferror(fp)) {
+ warn("%s", filename);
+ rval = 1;
+ clearerr(fp);
+ }
+ if (ferror(stdout))
+ err(1, "stdout");
+}
+
+static void
+raw_cat(int rfd)
+{
+ int off, wfd;
+ ssize_t nr, nw;
+ static size_t bsize;
+ static char *buf = NULL;
+ struct stat sbuf;
+
+ wfd = fileno(stdout);
+ if (buf == NULL) {
+ if (fstat(wfd, &sbuf))
+ err(1, "%s", filename);
+ bsize = MAX(sbuf.st_blksize, 1024);
+ if ((buf = malloc(bsize)) == NULL)
+ err(1, "buffer");
+ }
+ while ((nr = read(rfd, buf, bsize)) > 0)
+ for (off = 0; nr; nr -= nw, off += nw)
+ if ((nw = write(wfd, buf + off, (size_t)nr)) < 0)
+ err(1, "stdout");
+ if (nr < 0) {
+ warn("%s", filename);
+ rval = 1;
+ }
+}
+
+#ifndef NO_UDOM_SUPPORT
+
+static int
+udom_open(const char *path, int flags)
+{
+ struct sockaddr_un sou;
+ int fd;
+ unsigned int len;
+
+ bzero(&sou, sizeof(sou));
+
+ /*
+ * Construct the unix domain socket address and attempt to connect
+ */
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd >= 0) {
+ sou.sun_family = AF_UNIX;
+ if ((len = strlcpy(sou.sun_path, path,
+ sizeof(sou.sun_path))) >= sizeof(sou.sun_path)) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ len = offsetof(struct sockaddr_un, sun_path[len+1]);
+
+ if (connect(fd, (void *)&sou, len) < 0) {
+ close(fd);
+ fd = -1;
+ }
+ }
+
+ /*
+ * handle the open flags by shutting down appropriate directions
+ */
+ if (fd >= 0) {
+ switch(flags & O_ACCMODE) {
+ case O_RDONLY:
+ if (shutdown(fd, SHUT_WR) == -1)
+ warn(NULL);
+ break;
+ case O_WRONLY:
+ if (shutdown(fd, SHUT_RD) == -1)
+ warn(NULL);
+ break;
+ default:
+ break;
+ }
+ }
+ return(fd);
+}
+
+#endif
diff --git a/text_cmds/col/README b/text_cmds/col/README
new file mode 100644
index 0000000..89e4ce4
--- /dev/null
+++ b/text_cmds/col/README
@@ -0,0 +1,48 @@
+# @(#)README 8.1 (Berkeley) 6/6/93
+#
+# $FreeBSD: src/usr.bin/col/README,v 1.2 2001/06/17 04:24:16 mikeh Exp $
+
+col - filter out reverse line feeds.
+
+Options are:
+ -b do not print any backspaces (last character written is printed)
+ -f allow half line feeds in output, by default characters between
+ lines are pushed to the line below
+ -p force unknown control sequences to be passed through unchanged
+ -x do not compress spaces into tabs.
+ -l num keep (at least) num lines in memory, 128 are kept by default
+
+In the 32V source code to col(1) the default behavior was to NOT compress
+spaces into tabs. There was a -h option which caused it to compress spaces
+into tabs. There was no -x flag.
+
+The 32V documentation, however, was consistent with the SVID (actually, V7
+at the time) and documented a -x flag (as defined above) while making no
+mention of a -h flag. Just before 4.3BSD went out, CSRG updated the manual
+page to reflect the way the code worked. Suspecting that this was probably
+the wrong way to go, this version adopts the SVID defaults, and no longer
+documents the -h option.
+
+Known differences between AT&T's col and this one (# is delimiter):
+ Input AT&T col this col
+ #\nabc\E7def\n# # def\nabc\r# # def\nabc\n#
+ #a# ## #a\n#
+ - last line always ends with at least one \n (or \E9)
+ #1234567 8\n# #1234567\t8\n# #1234567 8\n#
+ - single space not expanded to tab
+ -f #a\E8b\n# #ab\n# # b\E9\ra\n#
+ - can back up past first line (as far as you want) so you
+ *can* have a super script on the first line
+ #\E9_\ba\E8\nb\n# #\n_\bb\ba\n# #\n_\ba\bb\n#
+ - always print last character written to a position,
+ AT&T col claims to do this but doesn't.
+
+If a character is to be placed on a line that has been flushed, a warning
+is produced (the AT&T col is silent). The -l flag (not in AT&T col) can
+be used to increase the number of lines buffered to avoid the problem.
+
+General algorithm: a limited number of lines are buffered in a linked
+list. When a printable character is read, it is put in the buffer of
+the current line along with the column it's supposed to be in. When
+a line is flushed, the characters in the line are sorted according to
+column and then printed.
diff --git a/text_cmds/col/col.1 b/text_cmds/col/col.1
new file mode 100644
index 0000000..2bac8b8
--- /dev/null
+++ b/text_cmds/col/col.1
@@ -0,0 +1,156 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Michael Rendell.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)col.1 8.1 (Berkeley) 6/29/93
+.\" $FreeBSD: src/usr.bin/col/col.1,v 1.19 2005/02/13 22:25:20 ru Exp $
+.\"
+.Dd August 4, 2004
+.Dt COL 1
+.Os
+.Sh NAME
+.Nm col
+.Nd filter reverse line feeds from input
+.Sh SYNOPSIS
+.Nm
+.Op Fl bfhpx
+.Op Fl l Ar num
+.Sh DESCRIPTION
+The
+.Nm
+utility filters out reverse (and half reverse) line feeds so that the output is
+in the correct order with only forward and half forward line
+feeds, and replaces white-space characters with tabs where possible.
+This can be useful in processing the output of
+.Xr nroff 1
+and
+.Xr tbl 1 .
+.Pp
+The
+.Nm
+utility reads from the standard input and writes to the standard output.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl b
+Do not output any backspaces, printing only the last character
+written to each column position.
+.It Fl f
+Forward half line feeds are permitted (``fine'' mode).
+Normally characters printed on a half line boundary are printed
+on the following line.
+.It Fl h
+Do not output multiple spaces instead of tabs (default).
+.It Fl l Ar num
+Buffer at least
+.Ar num
+lines in memory.
+By default, 128 lines are buffered.
+.It Fl p
+Force unknown control sequences to be passed through unchanged.
+Normally,
+.Nm
+will filter out any control sequences from the input other than those
+recognized and interpreted by itself, which are listed below.
+.It Fl x
+Output multiple spaces instead of tabs.
+.El
+.Pp
+The control sequences for carriage motion that
+.Nm
+understands and their decimal values are listed in the following
+table:
+.Pp
+.Bl -tag -width "carriage return" -compact
+.It ESC\-7
+reverse line feed (escape then 7)
+.It ESC\-8
+half reverse line feed (escape then 8)
+.It ESC\-9
+half forward line feed (escape then 9)
+.It backspace
+moves back one column (8); ignored in the first column
+.It carriage return
+(13)
+.It newline
+forward line feed (10); also does carriage return
+.It shift in
+shift to normal character set (15)
+.It shift out
+shift to alternate character set (14)
+.It space
+moves forward one column (32)
+.It tab
+moves forward to next tab stop (9)
+.It vertical tab
+reverse line feed (11)
+.El
+.Pp
+All unrecognized control characters and escape sequences are
+discarded.
+.Pp
+The
+.Nm
+utility keeps track of the character set as characters are read and makes
+sure the character set is correct when they are output.
+.Pp
+If the input attempts to back up to the last flushed line,
+.Nm
+will display a warning message.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr colcrt 1 ,
+.Xr expand 1 ,
+.Xr nroff 1 ,
+.Xr tbl 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -susv2 .
+.Sh HISTORY
+A
+.Nm
+command
+appeared in
+.At v6 .
diff --git a/text_cmds/col/col.c b/text_cmds/col/col.c
new file mode 100644
index 0000000..758cbec
--- /dev/null
+++ b/text_cmds/col/col.c
@@ -0,0 +1,552 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Rendell of the Memorial University of Newfoundland.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)col.c 8.5 (Berkeley) 5/4/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/col/col.c,v 1.19 2004/07/29 07:28:26 tjr Exp $");
+
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#define BS '\b' /* backspace */
+#define TAB '\t' /* tab */
+#define SPACE ' ' /* space */
+#define NL '\n' /* newline */
+#define CR '\r' /* carriage return */
+#define ESC '\033' /* escape */
+#define SI '\017' /* shift in to normal character set */
+#define SO '\016' /* shift out to alternate character set */
+#define VT '\013' /* vertical tab (aka reverse line feed) */
+#define RLF '\007' /* ESC-07 reverse line feed */
+#define RHLF '\010' /* ESC-010 reverse half-line feed */
+#define FHLF '\011' /* ESC-011 forward half-line feed */
+
+/* build up at least this many lines before flushing them out */
+#define BUFFER_MARGIN 32
+
+typedef char CSET;
+
+typedef struct char_str {
+#define CS_NORMAL 1
+#define CS_ALTERNATE 2
+ short c_column; /* column character is in */
+ CSET c_set; /* character set (currently only 2) */
+ wchar_t c_char; /* character in question */
+ int c_width; /* character width */
+} CHAR;
+
+typedef struct line_str LINE;
+struct line_str {
+ CHAR *l_line; /* characters on the line */
+ LINE *l_prev; /* previous line */
+ LINE *l_next; /* next line */
+ int l_lsize; /* allocated sizeof l_line */
+ int l_line_len; /* strlen(l_line) */
+ int l_needs_sort; /* set if chars went in out of order */
+ int l_max_col; /* max column in the line */
+};
+
+LINE *alloc_line(void);
+void dowarn(int);
+void flush_line(LINE *);
+void flush_lines(int);
+void flush_blanks(void);
+void free_line(LINE *);
+void usage(void);
+
+CSET last_set; /* char_set of last char printed */
+LINE *lines;
+int compress_spaces; /* if doing space -> tab conversion */
+int fine; /* if `fine' resolution (half lines) */
+int max_bufd_lines; /* max # lines to keep in memory */
+int nblank_lines; /* # blanks after last flushed line */
+int no_backspaces; /* if not to output any backspaces */
+int pass_unknown_seqs; /* pass unknown control sequences */
+
+#define PUTC(ch) \
+ do { \
+ if (putwchar(ch) == WEOF) \
+ errx(1, "write error"); \
+ } while (0)
+
+int
+main(int argc, char **argv)
+{
+ wint_t ch;
+ CHAR *c;
+ CSET cur_set; /* current character set */
+ LINE *l; /* current line */
+ int extra_lines; /* # of lines above first line */
+ int cur_col; /* current column */
+ int cur_line; /* line number of current position */
+ int max_line; /* max value of cur_line */
+ int this_line; /* line l points to */
+ int nflushd_lines; /* number of lines that were flushed */
+ int adjust, opt, warned, width;
+
+ (void)setlocale(LC_CTYPE, "");
+
+ max_bufd_lines = 128;
+ compress_spaces = 1; /* compress spaces into tabs */
+ while ((opt = getopt(argc, argv, "bfhl:px")) != -1)
+ switch (opt) {
+ case 'b': /* do not output backspaces */
+ no_backspaces = 1;
+ break;
+ case 'f': /* allow half forward line feeds */
+ fine = 1;
+ break;
+ case 'h': /* compress spaces into tabs */
+ compress_spaces = 1;
+ break;
+ case 'l': /* buffered line count */
+ if ((max_bufd_lines = atoi(optarg)) <= 0)
+ errx(1, "bad -l argument %s", optarg);
+ break;
+ case 'p': /* pass unknown control sequences */
+ pass_unknown_seqs = 1;
+ break;
+ case 'x': /* do not compress spaces into tabs */
+ compress_spaces = 0;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ if (optind != argc)
+ usage();
+
+ /* this value is in half lines */
+ max_bufd_lines *= 2;
+
+ adjust = cur_col = extra_lines = warned = 0;
+ cur_line = max_line = nflushd_lines = this_line = 0;
+ cur_set = last_set = CS_NORMAL;
+ lines = l = alloc_line();
+
+ while ((ch = getwchar()) != WEOF) {
+ if (!iswgraph(ch)) {
+ switch (ch) {
+ case BS: /* can't go back further */
+ if (cur_col == 0)
+ continue;
+ --cur_col;
+ continue;
+ case CR:
+ cur_col = 0;
+ continue;
+ case ESC: /* just ignore EOF */
+ switch(getwchar()) {
+ case RLF:
+ cur_line -= 2;
+ break;
+ case RHLF:
+ cur_line--;
+ break;
+ case FHLF:
+ cur_line++;
+ if (cur_line > max_line)
+ max_line = cur_line;
+ }
+ continue;
+ case NL:
+ cur_line += 2;
+ if (cur_line > max_line)
+ max_line = cur_line;
+ cur_col = 0;
+ continue;
+ case SPACE:
+ ++cur_col;
+ continue;
+ case SI:
+ cur_set = CS_NORMAL;
+ continue;
+ case SO:
+ cur_set = CS_ALTERNATE;
+ continue;
+ case TAB: /* adjust column */
+ cur_col |= 7;
+ ++cur_col;
+ continue;
+ case VT:
+ cur_line -= 2;
+ continue;
+ }
+ if (iswspace(ch)) {
+ if ((width = wcwidth(ch)) > 0)
+ cur_col += width;
+ continue;
+ }
+ if (!pass_unknown_seqs)
+ continue;
+ }
+
+ /* Must stuff ch in a line - are we at the right one? */
+ if (cur_line != this_line - adjust) {
+ LINE *lnew;
+ int nmove;
+
+ adjust = 0;
+ nmove = cur_line - this_line;
+ if (!fine) {
+ /* round up to next line */
+ if (cur_line & 1) {
+ adjust = 1;
+ nmove++;
+ }
+ }
+ if (nmove < 0) {
+ for (; nmove < 0 && l->l_prev; nmove++)
+ l = l->l_prev;
+ if (nmove) {
+ if (nflushd_lines == 0) {
+ /*
+ * Allow backup past first
+ * line if nothing has been
+ * flushed yet.
+ */
+ for (; nmove < 0; nmove++) {
+ lnew = alloc_line();
+ l->l_prev = lnew;
+ lnew->l_next = l;
+ l = lines = lnew;
+ extra_lines++;
+ }
+ } else {
+ if (!warned++)
+ dowarn(cur_line);
+ cur_line -= nmove;
+ }
+ }
+ } else {
+ /* may need to allocate here */
+ for (; nmove > 0 && l->l_next; nmove--)
+ l = l->l_next;
+ for (; nmove > 0; nmove--) {
+ lnew = alloc_line();
+ lnew->l_prev = l;
+ l->l_next = lnew;
+ l = lnew;
+ }
+ }
+ this_line = cur_line + adjust;
+ nmove = this_line - nflushd_lines;
+ if (nmove >= max_bufd_lines + BUFFER_MARGIN) {
+ nflushd_lines += nmove - max_bufd_lines;
+ flush_lines(nmove - max_bufd_lines);
+ }
+ }
+ /* grow line's buffer? */
+ if (l->l_line_len + 1 >= l->l_lsize) {
+ int need;
+
+ need = l->l_lsize ? l->l_lsize * 2 : 90;
+ if ((l->l_line = realloc(l->l_line,
+ (unsigned)need * sizeof(CHAR))) == NULL)
+ err(1, (char *)NULL);
+ l->l_lsize = need;
+ }
+ c = &l->l_line[l->l_line_len++];
+ c->c_char = ch;
+ c->c_set = cur_set;
+ c->c_column = cur_col;
+ c->c_width = wcwidth(ch);
+ /*
+ * If things are put in out of order, they will need sorting
+ * when it is flushed.
+ */
+ if (cur_col < l->l_max_col)
+ l->l_needs_sort = 1;
+ else
+ l->l_max_col = cur_col;
+ if (c->c_width > 0)
+ cur_col += c->c_width;
+ }
+ if (ferror(stdin))
+ err(1, NULL);
+ if (max_line == 0)
+ exit(0); /* no lines, so just exit */
+
+ /* goto the last line that had a character on it */
+ for (; l->l_next; l = l->l_next)
+ this_line++;
+ flush_lines(this_line - nflushd_lines + extra_lines + 1);
+
+ /* make sure we leave things in a sane state */
+ if (last_set != CS_NORMAL)
+ PUTC('\017');
+
+ /* flush out the last few blank lines */
+ nblank_lines = max_line - this_line;
+ if (max_line & 1)
+ nblank_lines++;
+ else if (!nblank_lines)
+ /* missing a \n on the last line? */
+ nblank_lines = 2;
+ flush_blanks();
+ exit(0);
+}
+
+void
+flush_lines(int nflush)
+{
+ LINE *l;
+
+ while (--nflush >= 0) {
+ l = lines;
+ lines = l->l_next;
+ if (l->l_line) {
+ flush_blanks();
+ flush_line(l);
+ }
+ nblank_lines++;
+ if (l->l_line)
+ (void)free(l->l_line);
+ free_line(l);
+ }
+ if (lines)
+ lines->l_prev = NULL;
+}
+
+/*
+ * Print a number of newline/half newlines. If fine flag is set, nblank_lines
+ * is the number of half line feeds, otherwise it is the number of whole line
+ * feeds.
+ */
+void
+flush_blanks(void)
+{
+ int half, i, nb;
+
+ half = 0;
+ nb = nblank_lines;
+ if (nb & 1) {
+ if (fine)
+ half = 1;
+ else
+ nb++;
+ }
+ nb /= 2;
+ for (i = nb; --i >= 0;)
+ PUTC('\n');
+ if (half) {
+ PUTC('\033');
+ PUTC('9');
+ if (!nb)
+ PUTC('\r');
+ }
+ nblank_lines = 0;
+}
+
+/*
+ * Write a line to stdout taking care of space to tab conversion (-h flag)
+ * and character set shifts.
+ */
+void
+flush_line(LINE *l)
+{
+ CHAR *c, *endc;
+ int i, nchars, last_col, this_col;
+
+ last_col = 0;
+ nchars = l->l_line_len;
+
+ if (l->l_needs_sort) {
+ static CHAR *sorted;
+ static int count_size, *count, i, save, sorted_size, tot;
+
+ /*
+ * Do an O(n) sort on l->l_line by column being careful to
+ * preserve the order of characters in the same column.
+ */
+ if (l->l_lsize > sorted_size) {
+ sorted_size = l->l_lsize;
+ if ((sorted = realloc(sorted,
+ (unsigned)sizeof(CHAR) * sorted_size)) == NULL)
+ err(1, (char *)NULL);
+ }
+ if (l->l_max_col >= count_size) {
+ count_size = l->l_max_col + 1;
+ if ((count = realloc(count,
+ (unsigned)sizeof(int) * count_size)) == NULL)
+ err(1, (char *)NULL);
+ }
+ memset(count, 0, sizeof(int) * l->l_max_col + 1);
+ for (i = nchars, c = l->l_line; --i >= 0; c++)
+ count[c->c_column]++;
+
+ /*
+ * calculate running total (shifted down by 1) to use as
+ * indices into new line.
+ */
+ for (tot = 0, i = 0; i <= l->l_max_col; i++) {
+ save = count[i];
+ count[i] = tot;
+ tot += save;
+ }
+
+ for (i = nchars, c = l->l_line; --i >= 0; c++)
+ sorted[count[c->c_column]++] = *c;
+ c = sorted;
+ } else
+ c = l->l_line;
+ while (nchars > 0) {
+ this_col = c->c_column;
+ endc = c;
+ do {
+ ++endc;
+ } while (--nchars > 0 && this_col == endc->c_column);
+
+ /* if -b only print last character */
+ if (no_backspaces) {
+ c = endc - 1;
+ if (nchars > 0 &&
+ this_col + c->c_width > endc->c_column)
+ continue;
+ }
+
+ if (this_col > last_col) {
+ int nspace = this_col - last_col;
+
+ if (compress_spaces && nspace > 1) {
+ while (1) {
+ int tab_col, tab_size;;
+
+ tab_col = (last_col + 8) & ~7;
+ if (tab_col > this_col)
+ break;
+ tab_size = tab_col - last_col;
+ if (tab_size == 1)
+ PUTC(' ');
+ else
+ PUTC('\t');
+ nspace -= tab_size;
+ last_col = tab_col;
+ }
+ }
+ while (--nspace >= 0)
+ PUTC(' ');
+ last_col = this_col;
+ }
+
+ for (;;) {
+ if (c->c_set != last_set) {
+ switch (c->c_set) {
+ case CS_NORMAL:
+ PUTC('\017');
+ break;
+ case CS_ALTERNATE:
+ PUTC('\016');
+ }
+ last_set = c->c_set;
+ }
+ PUTC(c->c_char);
+ if ((c + 1) < endc)
+ for (i = 0; i < c->c_width; i++)
+ PUTC('\b');
+ if (++c >= endc)
+ break;
+ }
+ last_col += (c - 1)->c_width;
+ }
+}
+
+#define NALLOC 64
+
+static LINE *line_freelist;
+
+LINE *
+alloc_line(void)
+{
+ LINE *l;
+ int i;
+
+ if (!line_freelist) {
+ if ((l = realloc(NULL, sizeof(LINE) * NALLOC)) == NULL)
+ err(1, (char *)NULL);
+ line_freelist = l;
+ for (i = 1; i < NALLOC; i++, l++)
+ l->l_next = l + 1;
+ l->l_next = NULL;
+ }
+ l = line_freelist;
+ line_freelist = l->l_next;
+
+ memset(l, 0, sizeof(LINE));
+ return (l);
+}
+
+void
+free_line(LINE *l)
+{
+
+ l->l_next = line_freelist;
+ line_freelist = l;
+}
+
+void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: col [-bfhpx] [-l nline]\n");
+ exit(1);
+}
+
+void
+dowarn(int line)
+{
+
+ warnx("warning: can't back up %s",
+ line < 0 ? "past first line" : "-- line already flushed");
+}
diff --git a/text_cmds/colrm/colrm.1 b/text_cmds/colrm/colrm.1
new file mode 100644
index 0000000..f97a8c4
--- /dev/null
+++ b/text_cmds/colrm/colrm.1
@@ -0,0 +1,91 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)colrm.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/colrm/colrm.1,v 1.11 2005/01/17 07:44:14 ru Exp $
+.\"
+.Dd August 4, 2004
+.Dt COLRM 1
+.Os
+.Sh NAME
+.Nm colrm
+.Nd remove columns from a file
+.Sh SYNOPSIS
+.Nm
+.Op Ar start Op Ar stop
+.Sh DESCRIPTION
+The
+.Nm
+utility removes selected columns from the lines of a file.
+A column is defined as a single character in a line.
+Input is read from the standard input.
+Output is written to the standard output.
+.Pp
+If only the
+.Ar start
+column is specified, columns numbered less than the
+.Ar start
+column will be written.
+If both
+.Ar start
+and
+.Ar stop
+columns are specified, columns numbered less than the
+.Ar start
+column
+or greater than the
+.Ar stop
+column will be written.
+Column numbering starts with one, not zero.
+.Pp
+Tab characters increment the column count to the next multiple of eight.
+Backspace characters decrement the column count by one.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr awk 1 ,
+.Xr column 1 ,
+.Xr cut 1 ,
+.Xr paste 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/text_cmds/colrm/colrm.c b/text_cmds/colrm/colrm.c
new file mode 100644
index 0000000..cf176ab
--- /dev/null
+++ b/text_cmds/colrm/colrm.c
@@ -0,0 +1,146 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)colrm.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/colrm/colrm.c,v 1.12 2004/07/29 09:09:22 tjr Exp $");
+
+#include <sys/types.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#define TAB 8
+
+void check(FILE *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ u_long column, start, stop;
+ int ch, width;
+ char *p;
+
+ setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ start = stop = 0;
+ switch(argc) {
+ case 2:
+ if(argv[1]) stop = strtol(argv[1], &p, 10);
+ if (stop <= 0 || *p)
+ errx(1, "illegal column -- %s", argv[1]);
+ /* FALLTHROUGH */
+ case 1:
+ if(argv[0]) start = strtol(argv[0], &p, 10);
+ if (start <= 0 || *p)
+ errx(1, "illegal column -- %s", argv[0]);
+ break;
+ case 0:
+ break;
+ default:
+ usage();
+ }
+
+ if (stop && start > stop)
+ errx(1, "illegal start and stop columns");
+
+ for (column = 0;;) {
+ switch (ch = getwchar()) {
+ case WEOF:
+ check(stdin);
+ break;
+ case '\b':
+ if (column)
+ --column;
+ break;
+ case '\n':
+ column = 0;
+ break;
+ case '\t':
+ column = (column + TAB) & ~(TAB - 1);
+ break;
+ default:
+ if ((width = wcwidth(ch)) > 0)
+ column += width;
+ break;
+ }
+
+ if ((!start || column < start || (stop && column > stop)) &&
+ putwchar(ch) == WEOF)
+ check(stdout);
+ }
+}
+
+void
+check(FILE *stream)
+{
+ if (feof(stream))
+ exit(0);
+ if (ferror(stream))
+ err(1, "%s", stream == stdin ? "stdin" : "stdout");
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: colrm [start [stop]]\n");
+ exit(1);
+}
+
diff --git a/text_cmds/column/column.1 b/text_cmds/column/column.1
new file mode 100644
index 0000000..b87eaa4
--- /dev/null
+++ b/text_cmds/column/column.1
@@ -0,0 +1,101 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)column.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/column/column.1,v 1.16 2010/12/11 08:32:16 joel Exp $
+.\"
+.Dd July 29, 2004
+.Dt COLUMN 1
+.Os
+.Sh NAME
+.Nm column
+.Nd columnate lists
+.Sh SYNOPSIS
+.Nm
+.Op Fl tx
+.Op Fl c Ar columns
+.Op Fl s Ar sep
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility formats its input into multiple columns.
+Rows are filled before columns.
+Input is taken from
+.Ar file
+operands, or, by default, from the standard input.
+Empty lines are ignored.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c
+Output is formatted for a display
+.Ar columns
+wide.
+.It Fl s
+Specify a set of characters to be used to delimit columns for the
+.Fl t
+option.
+.It Fl t
+Determine the number of columns the input contains and create a table.
+Columns are delimited with whitespace, by default, or with the characters
+supplied using the
+.Fl s
+option.
+Useful for pretty-printing displays.
+.It Fl x
+Fill columns before filling rows.
+.El
+.Sh ENVIRONMENT
+The
+.Ev COLUMNS , LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+.Dl (printf \&"PERM LINKS OWNER GROUP SIZE MONTH DAY \&"\ \&;\ \&\e
+.Dl printf \&"HH:MM/YEAR NAME\en\&"\ \&;\ \&\e
+.Dl ls -l \&| sed 1d) \&| column -t
+.Sh SEE ALSO
+.Xr colrm 1 ,
+.Xr ls 1 ,
+.Xr paste 1 ,
+.Xr sort 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 Reno .
+.Sh BUGS
+Input lines are limited to
+.Dv LINE_MAX
+(2048) bytes in length.
diff --git a/text_cmds/column/column.c b/text_cmds/column/column.c
new file mode 100644
index 0000000..471421c
--- /dev/null
+++ b/text_cmds/column/column.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)column.c 8.4 (Berkeley) 5/4/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/column/column.c,v 1.19 2011/11/06 08:14:34 ed Exp $");
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#define TAB 8
+
+static void c_columnate(void);
+static void input(FILE *);
+static void maketbl(void);
+static void print(void);
+static void r_columnate(void);
+static void usage(void);
+static int width(const wchar_t *);
+
+static int termwidth = 80; /* default terminal width */
+
+static int entries; /* number of records */
+static int eval; /* exit value */
+static int maxlength; /* longest record */
+static wchar_t **list; /* array of pointers to records */
+static const wchar_t *separator = L"\t "; /* field separator for table option */
+
+int
+main(int argc, char **argv)
+{
+ struct winsize win;
+ FILE *fp;
+ int ch, tflag, xflag;
+ char *p;
+ const char *src;
+ wchar_t *newsep;
+ size_t seplen;
+
+ setlocale(LC_ALL, "");
+
+ if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
+ if ((p = getenv("COLUMNS")))
+ termwidth = atoi(p);
+ } else
+ termwidth = win.ws_col;
+
+ tflag = xflag = 0;
+ while ((ch = getopt(argc, argv, "c:s:tx")) != -1)
+ switch(ch) {
+ case 'c':
+ termwidth = atoi(optarg);
+ break;
+ case 's':
+ src = optarg;
+ seplen = mbsrtowcs(NULL, &src, 0, NULL);
+ if (seplen == (size_t)-1)
+ err(1, "bad separator");
+ newsep = malloc((seplen + 1) * sizeof(wchar_t));
+ if (newsep == NULL)
+ err(1, NULL);
+ mbsrtowcs(newsep, &src, seplen + 1, NULL);
+ separator = newsep;
+ break;
+ case 't':
+ tflag = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (!*argv)
+ input(stdin);
+ else for (; *argv; ++argv)
+ if ((fp = fopen(*argv, "r"))) {
+ input(fp);
+ (void)fclose(fp);
+ } else {
+ warn("%s", *argv);
+ eval = 1;
+ }
+
+ if (!entries)
+ exit(eval);
+
+ maxlength = roundup(maxlength + 1, TAB);
+ if (tflag)
+ maketbl();
+ else if (maxlength >= termwidth)
+ print();
+ else if (xflag)
+ c_columnate();
+ else
+ r_columnate();
+ exit(eval);
+}
+
+static void
+c_columnate(void)
+{
+ int chcnt, col, cnt, endcol, numcols;
+ wchar_t **lp;
+
+ numcols = termwidth / maxlength;
+ endcol = maxlength;
+ for (chcnt = col = 0, lp = list;; ++lp) {
+ wprintf(L"%ls", *lp);
+ chcnt += width(*lp);
+ if (!--entries)
+ break;
+ if (++col == numcols) {
+ chcnt = col = 0;
+ endcol = maxlength;
+ putwchar('\n');
+ } else {
+ while ((cnt = roundup(chcnt + 1, TAB)) <= endcol) {
+ (void)putwchar('\t');
+ chcnt = cnt;
+ }
+ endcol += maxlength;
+ }
+ }
+ if (chcnt)
+ putwchar('\n');
+}
+
+static void
+r_columnate(void)
+{
+ int base, chcnt, cnt, col, endcol, numcols, numrows, row;
+
+ numcols = termwidth / maxlength;
+ numrows = entries / numcols;
+ if (entries % numcols)
+ ++numrows;
+
+ for (row = 0; row < numrows; ++row) {
+ endcol = maxlength;
+ for (base = row, chcnt = col = 0; col < numcols; ++col) {
+ wprintf(L"%ls", list[base]);
+ chcnt += width(list[base]);
+ if ((base += numrows) >= entries)
+ break;
+ while ((cnt = roundup(chcnt + 1, TAB)) <= endcol) {
+ (void)putwchar('\t');
+ chcnt = cnt;
+ }
+ endcol += maxlength;
+ }
+ putwchar('\n');
+ }
+}
+
+static void
+print(void)
+{
+ int cnt;
+ wchar_t **lp;
+
+ for (cnt = entries, lp = list; cnt--; ++lp)
+ (void)wprintf(L"%ls\n", *lp);
+}
+
+typedef struct _tbl {
+ wchar_t **list;
+ int cols, *len;
+} TBL;
+#define DEFCOLS 25
+
+static void
+maketbl(void)
+{
+ TBL *t;
+ int coloff, cnt;
+ wchar_t *p, **lp;
+ int *lens, maxcols;
+ TBL *tbl;
+ wchar_t **cols;
+ wchar_t *last;
+
+ if ((t = tbl = calloc(entries, sizeof(TBL))) == NULL)
+ err(1, (char *)NULL);
+ if ((cols = calloc((maxcols = DEFCOLS), sizeof(*cols))) == NULL)
+ err(1, (char *)NULL);
+ if ((lens = calloc(maxcols, sizeof(int))) == NULL)
+ err(1, (char *)NULL);
+ for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) {
+ for (coloff = 0, p = *lp;
+ (cols[coloff] = wcstok(p, separator, &last));
+ p = NULL)
+ if (++coloff == maxcols) {
+ if (!(cols = realloc(cols, ((u_int)maxcols +
+ DEFCOLS) * sizeof(char *))) ||
+ !(lens = realloc(lens,
+ ((u_int)maxcols + DEFCOLS) * sizeof(int))))
+ err(1, NULL);
+ memset((char *)lens + maxcols * sizeof(int),
+ 0, DEFCOLS * sizeof(int));
+ maxcols += DEFCOLS;
+ }
+ if ((t->list = calloc(coloff, sizeof(*t->list))) == NULL)
+ err(1, (char *)NULL);
+ if ((t->len = calloc(coloff, sizeof(int))) == NULL)
+ err(1, (char *)NULL);
+ for (t->cols = coloff; --coloff >= 0;) {
+ t->list[coloff] = cols[coloff];
+ t->len[coloff] = width(cols[coloff]);
+ if (t->len[coloff] > lens[coloff])
+ lens[coloff] = t->len[coloff];
+ }
+ }
+ for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) {
+ for (coloff = 0; coloff < t->cols - 1; ++coloff)
+ (void)wprintf(L"%ls%*ls", t->list[coloff],
+ lens[coloff] - t->len[coloff] + 2, L" ");
+ (void)wprintf(L"%ls\n", t->list[coloff]);
+ }
+}
+
+#define DEFNUM 1000
+#define MAXLINELEN (LINE_MAX + 1)
+
+static void
+input(FILE *fp)
+{
+ static int maxentry;
+ int len;
+ wchar_t *p, buf[MAXLINELEN];
+
+ if (!list)
+ if ((list = calloc((maxentry = DEFNUM), sizeof(*list))) ==
+ NULL)
+ err(1, (char *)NULL);
+ while (fgetws(buf, MAXLINELEN, fp)) {
+ for (p = buf; *p && iswspace(*p); ++p);
+ if (!*p)
+ continue;
+ if (!(p = wcschr(p, L'\n'))) {
+ warnx("line too long");
+ eval = 1;
+ continue;
+ }
+ *p = L'\0';
+ len = width(buf);
+ if (maxlength < len)
+ maxlength = len;
+ if (entries == maxentry) {
+ maxentry += DEFNUM;
+ if (!(list = realloc(list,
+ (u_int)maxentry * sizeof(*list))))
+ err(1, NULL);
+ }
+ list[entries] = malloc((wcslen(buf) + 1) * sizeof(wchar_t));
+ if (list[entries] == NULL)
+ err(1, NULL);
+ wcscpy(list[entries], buf);
+ entries++;
+ }
+}
+
+/* Like wcswidth(), but ignores non-printing characters. */
+static int
+width(const wchar_t *wcs)
+{
+ int w, cw;
+
+ for (w = 0; *wcs != L'\0'; wcs++)
+ if ((cw = wcwidth(*wcs)) > 0)
+ w += cw;
+ return (w);
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr,
+ "usage: column [-tx] [-c columns] [-s sep] [file ...]\n");
+ exit(1);
+}
diff --git a/text_cmds/comm/comm.1 b/text_cmds/comm/comm.1
new file mode 100644
index 0000000..45a726d
--- /dev/null
+++ b/text_cmds/comm/comm.1
@@ -0,0 +1,124 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)comm.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/comm/comm.1,v 1.14 2005/01/25 22:28:34 tjr Exp $
+.\"
+.Dd January 26, 2005
+.Os
+.Dt COMM 1
+.Sh NAME
+.Nm comm
+.Nd select or reject lines common to two files
+.Sh SYNOPSIS
+.Nm
+.Op Fl 123i
+.Ar file1 file2
+.Sh DESCRIPTION
+The
+.Nm
+utility reads
+.Ar file1
+and
+.Ar file2 ,
+which should be
+sorted lexically, and produces three text
+columns as output: lines only in
+.Ar file1 ;
+lines only in
+.Ar file2 ;
+and lines in both files.
+.Pp
+The filename ``-'' means the standard input.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl 1
+Suppress printing of column 1.
+.It Fl 2
+Suppress printing of column 2.
+.It Fl 3
+Suppress printing of column 3.
+.It Fl i
+Case insensitive comparison of lines.
+.El
+.Pp
+Each column will have a number of tab characters prepended to it
+equal to the number of lower numbered columns that are being printed.
+For example, if column number two is being suppressed, lines printed
+in column number one will not have any tabs preceding them, and lines
+printed in column number three will have one.
+.Pp
+The
+.Nm
+utility assumes that the files are lexically sorted; all characters
+participate in line comparisons.
+.Sh ENVIRONMENT
+The
+.Ev LANG ,
+.Ev LC_ALL ,
+.Ev LC_COLLATE ,
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr cmp 1 ,
+.Xr diff 1 ,
+.Xr sort 1 ,
+.Xr uniq 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+.Pp
+The
+.Fl i
+option is an extension to the
+.Tn POSIX
+standard.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v4 .
+.Sh BUGS
+Input lines are limited to
+.Dv LINE_MAX
+(2048) characters in length.
diff --git a/text_cmds/comm/comm.c b/text_cmds/comm/comm.c
new file mode 100644
index 0000000..fc6c663
--- /dev/null
+++ b/text_cmds/comm/comm.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 1989, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Case Larsen.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "From: @(#)comm.c 8.4 (Berkeley) 5/4/95";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/comm/comm.c,v 1.21 2004/07/02 22:48:29 tjr Exp $");
+
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#define MAXLINELEN (LINE_MAX + 1)
+
+const wchar_t *tabs[] = { L"", L"\t", L"\t\t" };
+
+FILE *file(const char *);
+void show(FILE *, const char *, const wchar_t *, wchar_t *);
+int wcsicoll(const wchar_t *, const wchar_t *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int comp, file1done = 0, file2done = 0, read1, read2;
+ int ch, flag1, flag2, flag3, iflag;
+ FILE *fp1, *fp2;
+ const wchar_t *col1, *col2, *col3;
+ wchar_t line1[MAXLINELEN], line2[MAXLINELEN];
+ const wchar_t **p;
+
+ flag1 = flag2 = flag3 = 1;
+ iflag = 0;
+
+ (void) setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "123i")) != -1)
+ switch(ch) {
+ case '1':
+ flag1 = 0;
+ break;
+ case '2':
+ flag2 = 0;
+ break;
+ case '3':
+ flag3 = 0;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 2 || !argv[0] || !argv[1])
+ usage();
+
+ fp1 = file(argv[0]);
+ fp2 = file(argv[1]);
+
+ /* for each column printed, add another tab offset */
+ p = tabs;
+ col1 = col2 = col3 = NULL;
+ if (flag1)
+ col1 = *p++;
+ if (flag2)
+ col2 = *p++;
+ if (flag3)
+ col3 = *p;
+
+ for (read1 = read2 = 1;;) {
+ /* read next line, check for EOF */
+ if (read1) {
+ file1done = !fgetws(line1, MAXLINELEN, fp1);
+ if (file1done && ferror(fp1))
+ err(1, "%s", argv[0]);
+ }
+ if (read2) {
+ file2done = !fgetws(line2, MAXLINELEN, fp2);
+ if (file2done && ferror(fp2))
+ err(1, "%s", argv[1]);
+ }
+
+ /* if one file done, display the rest of the other file */
+ if (file1done) {
+ if (!file2done && col2)
+ show(fp2, argv[1], col2, line2);
+ break;
+ }
+ if (file2done) {
+ if (!file1done && col1)
+ show(fp1, argv[0], col1, line1);
+ break;
+ }
+
+ /* lines are the same */
+ if(iflag)
+ comp = wcsicoll(line1, line2);
+ else
+ comp = wcscoll(line1, line2);
+
+ if (!comp) {
+ read1 = read2 = 1;
+ if (col3)
+ (void)printf("%ls%ls", col3, line1);
+ continue;
+ }
+
+ /* lines are different */
+ if (comp < 0) {
+ read1 = 1;
+ read2 = 0;
+ if (col1)
+ (void)printf("%ls%ls", col1, line1);
+ } else {
+ read1 = 0;
+ read2 = 1;
+ if (col2)
+ (void)printf("%ls%ls", col2, line2);
+ }
+ }
+ exit(0);
+}
+
+void
+show(FILE *fp, const char *fn, const wchar_t *offset, wchar_t *buf)
+{
+
+ do {
+ (void)printf("%ls%ls", offset, buf);
+ } while (fgetws(buf, MAXLINELEN, fp));
+ if (ferror(fp))
+ err(1, "%s", fn);
+}
+
+FILE *
+file(const char *name)
+{
+ FILE *fp;
+
+ if (!strcmp(name, "-"))
+ return (stdin);
+ if ((fp = fopen(name, "r")) == NULL) {
+ err(1, "%s", name);
+ }
+ return (fp);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: comm [-123i] file1 file2\n");
+ exit(1);
+}
+
+int
+wcsicoll(const wchar_t *s1, const wchar_t *s2)
+{
+ wchar_t *p, line1[MAXLINELEN], line2[MAXLINELEN];
+
+ for (p = line1; *s1; s1++)
+ *p++ = towlower(*s1);
+ *p = '\0';
+ for (p = line2; *s2; s2++)
+ *p++ = towlower(*s2);
+ *p = '\0';
+ return (wcscoll(line1, line2));
+}
diff --git a/text_cmds/csplit/csplit.1 b/text_cmds/csplit/csplit.1
new file mode 100644
index 0000000..98b834f
--- /dev/null
+++ b/text_cmds/csplit/csplit.1
@@ -0,0 +1,157 @@
+.\" Copyright (c) 2002 Tim J. Robbins.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/usr.bin/csplit/csplit.1,v 1.11 2005/01/25 22:29:51 tjr Exp $
+.\"
+.Dd January 26, 2005
+.Dt CSPLIT 1
+.Os
+.Sh NAME
+.Nm csplit
+.Nd split files based on context
+.Sh SYNOPSIS
+.Nm
+.Op Fl ks
+.Op Fl f Ar prefix
+.Op Fl n Ar number
+.Ar file args ...
+.Sh DESCRIPTION
+The
+.Nm
+utility splits
+.Ar file
+into pieces using the patterns
+.Ar args .
+If
+.Ar file
+is
+a dash
+.Pq Sq Fl ,
+.Nm
+reads from standard input.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl f Ar prefix
+Give created files names beginning with
+.Ar prefix .
+The default is
+.Dq Pa xx .
+.It Fl k
+Do not remove output files if an error occurs or a
+.Dv HUP ,
+.Dv INT
+or
+.Dv TERM
+signal is received.
+.It Fl n Ar number
+Use
+.Ar number
+of decimal digits after the
+.Ar prefix
+to form the file name.
+The default is 2.
+.It Fl s
+Do not write the size of each output file to standard output as it is
+created.
+.El
+.Pp
+The
+.Ar args
+operands may be a combination of the following patterns:
+.Bl -tag -width indent
+.It Xo
+.Sm off
+.Cm / Ar regexp Cm / Op Oo Cm + | - Oc Ar offset
+.Sm on
+.Xc
+Create a file containing the input from the current line to (but not including)
+the next line matching the given basic regular expression.
+An optional
+.Ar offset
+from the line that matched may be specified.
+.It Xo
+.Sm off
+.Cm % Ar regexp Cm % Op Oo Cm + | - Oc Ar offset
+.Sm on
+.Xc
+Same as above but a file is not created for the output.
+.It Ar line_no
+Create containing the input from the current line to (but not including)
+the specified line number.
+.It Cm { Ns Ar num Ns Cm }
+Repeat the previous pattern the specified number of times.
+If it follows a line number pattern, a new file will be created for each
+.Ar line_no
+lines,
+.Ar num
+times.
+The first line of the file is line number 1 for historic reasons.
+.El
+.Pp
+After all the patterns have been processed, the remaining input data
+(if there is any) will be written to a new file.
+.Pp
+Requesting to split at a line before the current line number or past the
+end of the file will result in an error.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_COLLATE
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Split the
+.Xr mdoc 7
+file
+.Pa foo.1
+into one file for each section (up to 20):
+.Pp
+.Dl "csplit -k foo.1 '%^\e.Sh%' '/^\e.Sh/' '{20}'"
+.Pp
+Split standard input after the first 99 lines and every 100 lines thereafter:
+.Pp
+.Dl "csplit -k - 100 '{19}'"
+.Sh SEE ALSO
+.Xr sed 1 ,
+.Xr split 1 ,
+.Xr re_format 7
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+command appeared in PWB UNIX.
+.Sh BUGS
+Input lines are limited to
+.Dv LINE_MAX
+(2048) bytes in length.
diff --git a/text_cmds/csplit/csplit.c b/text_cmds/csplit/csplit.c
new file mode 100644
index 0000000..57bc823
--- /dev/null
+++ b/text_cmds/csplit/csplit.c
@@ -0,0 +1,467 @@
+/*-
+ * Copyright (c) 2002 Tim J. Robbins.
+ * 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.
+ */
+
+/*
+ * csplit -- split files based on context
+ *
+ * This utility splits its input into numbered output files by line number
+ * or by a regular expression. Regular expression matches have an optional
+ * offset with them, allowing the split to occur a specified number of
+ * lines before or after the match.
+ *
+ * To handle negative offsets, we stop reading when the match occurs and
+ * store the offset that the file should have been split at, then use
+ * this output file as input until all the "overflowed" lines have been read.
+ * The file is then closed and truncated to the correct length.
+ *
+ * We assume that the output files can be seeked upon (ie. they cannot be
+ * symlinks to named pipes or character devices), but make no such
+ * assumption about the input.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/csplit/csplit.c,v 1.9 2004/03/22 11:15:03 tjr Exp $");
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <regex.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void cleanup(void);
+void do_lineno(const char *);
+void do_rexp(const char *);
+char *csplit_getline(void);
+void handlesig(int);
+FILE *newfile(void);
+void toomuch(FILE *, long);
+void usage(void);
+
+/*
+ * Command line options
+ */
+const char *prefix; /* File name prefix */
+long sufflen; /* Number of decimal digits for suffix */
+int sflag; /* Suppress output of file names */
+int kflag; /* Keep output if error occurs */
+
+/*
+ * Other miscellaneous globals (XXX too many)
+ */
+long lineno; /* Current line number in input file */
+long reps; /* Number of repetitions for this pattern */
+long nfiles; /* Number of files output so far */
+long maxfiles; /* Maximum number of files we can create */
+char currfile[PATH_MAX]; /* Current output file */
+const char *infn; /* Name of the input file */
+FILE *infile; /* Input file handle */
+FILE *overfile; /* Overflow file for toomuch() */
+off_t truncofs; /* Offset this file should be truncated at */
+int doclean; /* Should cleanup() remove output? */
+
+int
+main(int argc, char *argv[])
+{
+ struct sigaction sa;
+ long i;
+ int ch;
+ const char *expr;
+ char *ep, *p;
+ FILE *ofp;
+
+ setlocale(LC_ALL, "");
+
+ kflag = sflag = 0;
+ prefix = "xx";
+ sufflen = 2;
+ while ((ch = getopt(argc, argv, "ksf:n:")) > 0) {
+ switch (ch) {
+ case 'f':
+ prefix = optarg;
+ break;
+ case 'k':
+ kflag = 1;
+ break;
+ case 'n':
+ errno = 0;
+ sufflen = strtol(optarg, &ep, 10);
+ if (sufflen <= 0 || *ep != '\0' || errno != 0)
+ errx(1, "%s: bad suffix length", optarg);
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+
+ if (sufflen + strlen(prefix) >= PATH_MAX)
+ errx(1, "name too long");
+
+ argc -= optind;
+ argv += optind;
+
+ if ((infn = *argv++) == NULL)
+ usage();
+ if (strcmp(infn, "-") == 0) {
+ infile = stdin;
+ infn = "stdin";
+ } else if ((infile = fopen(infn, "r")) == NULL)
+ err(1, "%s", infn);
+
+ if (!kflag) {
+ doclean = 1;
+ atexit(cleanup);
+ sa.sa_flags = 0;
+ sa.sa_handler = handlesig;
+ sigemptyset(&sa.sa_mask);
+ sigaddset(&sa.sa_mask, SIGHUP);
+ sigaddset(&sa.sa_mask, SIGINT);
+ sigaddset(&sa.sa_mask, SIGTERM);
+ sigaction(SIGHUP, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+ }
+
+ lineno = 0;
+ nfiles = 0;
+ truncofs = 0;
+ overfile = NULL;
+
+ /* Ensure 10^sufflen < LONG_MAX. */
+ for (maxfiles = 1, i = 0; i < sufflen; i++) {
+ if (maxfiles > LONG_MAX / 10)
+ errx(1, "%ld: suffix too long (limit %ld)",
+ sufflen, i);
+ maxfiles *= 10;
+ }
+
+ /* Create files based on supplied patterns. */
+ while (nfiles < maxfiles - 1 && (expr = *argv++) != NULL) {
+ /* Look ahead & see if this pattern has any repetitions. */
+ if (*argv != NULL && **argv == '{') {
+ errno = 0;
+ reps = strtol(*argv + 1, &ep, 10);
+ if (reps < 0 || *ep != '}' || errno != 0)
+ errx(1, "%s: bad repetition count", *argv + 1);
+ argv++;
+ } else
+ reps = 0;
+
+ if (*expr == '/' || *expr == '%') {
+ do
+ do_rexp(expr);
+ while (reps-- != 0 && nfiles < maxfiles - 1);
+ } else if (isdigit((unsigned char)*expr))
+ do_lineno(expr);
+ else
+ errx(1, "%s: unrecognised pattern", expr);
+ }
+
+ /* Copy the rest into a new file. */
+ if (!feof(infile)) {
+ ofp = newfile();
+ while ((p = csplit_getline()) != NULL && fputs(p, ofp) != EOF)
+ ;
+ if (!sflag)
+ printf("%jd\n", (intmax_t)ftello(ofp));
+ if (fclose(ofp) != 0)
+ err(1, "%s", currfile);
+ }
+
+ toomuch(NULL, 0);
+ doclean = 0;
+
+ return (0);
+}
+
+void
+usage(void)
+{
+
+ fprintf(stderr,
+"usage: csplit [-ks] [-f prefix] [-n number] file args ...\n");
+ exit(1);
+}
+
+void
+handlesig(int sig __unused)
+{
+ const char msg[] = "csplit: caught signal, cleaning up\n";
+
+ write(STDERR_FILENO, msg, sizeof(msg) - 1);
+ cleanup();
+ _exit(2);
+}
+
+/* Create a new output file. */
+FILE *
+newfile(void)
+{
+ FILE *fp;
+
+ if ((size_t)snprintf(currfile, sizeof(currfile), "%s%0*ld", prefix,
+ (int)sufflen, nfiles) >= sizeof(currfile))
+ errc(1, ENAMETOOLONG, NULL);
+ if ((fp = fopen(currfile, "w+")) == NULL)
+ err(1, "%s", currfile);
+ nfiles++;
+
+ return (fp);
+}
+
+/* Remove partial output, called before exiting. */
+void
+cleanup(void)
+{
+ char fnbuf[PATH_MAX];
+ long i;
+
+ if (!doclean)
+ return;
+
+ /*
+ * NOTE: One cannot portably assume to be able to call snprintf()
+ * from inside a signal handler. It does, however, appear to be safe
+ * to do on FreeBSD. The solution to this problem is worse than the
+ * problem itself.
+ */
+
+ for (i = 0; i < nfiles; i++) {
+ snprintf(fnbuf, sizeof(fnbuf), "%s%0*ld", prefix,
+ (int)sufflen, i);
+ unlink(fnbuf);
+ }
+}
+
+/* Read a line from the input into a static buffer. */
+char *
+csplit_getline(void)
+{
+ static char lbuf[LINE_MAX];
+ FILE *src;
+
+ src = overfile != NULL ? overfile : infile;
+
+again: if (fgets(lbuf, sizeof(lbuf), src) == NULL) {
+ if (src == overfile) {
+ src = infile;
+ goto again;
+ }
+ return (NULL);
+ }
+ if (ferror(src))
+ err(1, "%s", infn);
+ lineno++;
+
+ return (lbuf);
+}
+
+/* Conceptually rewind the input (as obtained by csplit_getline()) back `n' lines. */
+void
+toomuch(FILE *ofp, long n)
+{
+ char buf[BUFSIZ];
+ size_t i, nread;
+
+ if (overfile != NULL) {
+ /*
+ * Truncate the previous file we overflowed into back to
+ * the correct length, close it.
+ */
+ if (fflush(overfile) != 0)
+ err(1, "overflow");
+ if (ftruncate(fileno(overfile), truncofs) != 0)
+ err(1, "overflow");
+ if (fclose(overfile) != 0)
+ err(1, "overflow");
+ overfile = NULL;
+ }
+
+ if (n == 0)
+ /* Just tidying up */
+ return;
+
+ lineno -= n;
+
+ /*
+ * Wind the overflow file backwards to `n' lines before the
+ * current one.
+ */
+ do {
+ if (ftello(ofp) < (off_t)sizeof(buf))
+ rewind(ofp);
+ else
+ fseeko(ofp, -(off_t)sizeof(buf), SEEK_CUR);
+ if (ferror(ofp))
+ errx(1, "%s: can't seek", currfile);
+ if ((nread = fread(buf, 1, sizeof(buf), ofp)) == 0)
+ errx(1, "can't read overflowed output");
+ if (fseeko(ofp, -(off_t)nread, SEEK_CUR) != 0)
+ err(1, "%s", currfile);
+ for (i = 1; i <= nread; i++)
+ if (buf[nread - i] == '\n' && n-- == 0)
+ break;
+ if (ftello(ofp) == 0)
+ break;
+ } while (n > 0);
+ if (fseeko(ofp, nread - i + 1, SEEK_CUR) != 0)
+ err(1, "%s", currfile);
+
+ /*
+ * csplit_getline() will read from here. Next call will truncate to
+ * truncofs in this file.
+ */
+ overfile = ofp;
+ truncofs = ftello(overfile);
+}
+
+/* Handle splits for /regexp/ and %regexp% patterns. */
+void
+do_rexp(const char *expr)
+{
+ regex_t cre;
+ intmax_t nwritten;
+ long ofs;
+ int first;
+ char *ecopy, *ep, *p, *pofs, *re;
+ FILE *ofp;
+
+ if ((ecopy = strdup(expr)) == NULL)
+ err(1, "strdup");
+
+ re = ecopy + 1;
+ if ((pofs = strrchr(ecopy, *expr)) == NULL || pofs[-1] == '\\')
+ errx(1, "%s: missing trailing %c", expr, *expr);
+ *pofs++ = '\0';
+
+ if (*pofs != '\0') {
+ errno = 0;
+ ofs = strtol(pofs, &ep, 10);
+ if (*ep != '\0' || errno != 0)
+ errx(1, "%s: bad offset", pofs);
+ } else
+ ofs = 0;
+
+ if (regcomp(&cre, re, REG_BASIC|REG_NOSUB|REG_NEWLINE) != 0)
+ errx(1, "%s: bad regular expression", re);
+
+ if (*expr == '/')
+ /* /regexp/: Save results to a file. */
+ ofp = newfile();
+ else {
+ /* %regexp%: Make a temporary file for overflow. */
+ if ((ofp = tmpfile()) == NULL)
+ err(1, "tmpfile");
+ }
+
+ /* Read and output lines until we get a match. */
+ first = 1;
+ while ((p = csplit_getline()) != NULL) {
+ if (fputs(p, ofp) == EOF)
+ break;
+ if (!first && regexec(&cre, p, 0, NULL, 0) == 0)
+ break;
+ first = 0;
+ }
+
+ if (p == NULL)
+ errx(1, "%s: no match", re);
+
+ if (ofs <= 0) {
+ /*
+ * Negative (or zero) offset: throw back any lines we should
+ * not have read yet.
+ */
+ if (p != NULL) {
+ toomuch(ofp, -ofs + 1);
+ nwritten = (intmax_t)truncofs;
+ } else
+ nwritten = (intmax_t)ftello(ofp);
+ } else {
+ /*
+ * Positive offset: copy the requested number of lines
+ * after the match.
+ */
+ while (--ofs > 0 && (p = csplit_getline()) != NULL)
+ fputs(p, ofp);
+ toomuch(NULL, 0);
+ nwritten = (intmax_t)ftello(ofp);
+ if (fclose(ofp) != 0)
+ err(1, "%s", currfile);
+ }
+
+ if (!sflag && *expr == '/')
+ printf("%jd\n", nwritten);
+
+ regfree(&cre);
+ free(ecopy);
+}
+
+/* Handle splits based on line number. */
+void
+do_lineno(const char *expr)
+{
+ long lastline, tgtline;
+ char *ep, *p;
+ FILE *ofp;
+
+ errno = 0;
+ tgtline = strtol(expr, &ep, 10);
+ if (tgtline <= 0 || errno != 0 || *ep != '\0')
+ errx(1, "%s: bad line number", expr);
+ lastline = tgtline;
+ if (lastline <= lineno)
+ errx(1, "%s: can't go backwards", expr);
+
+ while (nfiles < maxfiles - 1) {
+ ofp = newfile();
+ while (lineno + 1 != lastline) {
+ if ((p = csplit_getline()) == NULL)
+ errx(1, "%ld: out of range", lastline);
+ if (fputs(p, ofp) == EOF)
+ break;
+ }
+ if (!sflag)
+ printf("%jd\n", (intmax_t)ftello(ofp));
+ if (fclose(ofp) != 0)
+ err(1, "%s", currfile);
+ if (reps-- == 0)
+ break;
+ lastline += tgtline;
+ }
+}
diff --git a/text_cmds/cut/cut.1 b/text_cmds/cut/cut.1
new file mode 100644
index 0000000..1565876
--- /dev/null
+++ b/text_cmds/cut/cut.1
@@ -0,0 +1,166 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)cut.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/cut/cut.1,v 1.32 2007/02/28 10:13:32 ru Exp $
+.\"
+.Dd December 21, 2006
+.Dt CUT 1
+.Os
+.Sh NAME
+.Nm cut
+.Nd cut out selected portions of each line of a file
+.Sh SYNOPSIS
+.Nm
+.Fl b Ar list
+.Op Fl n
+.Op Ar
+.Nm
+.Fl c Ar list
+.Op Ar
+.Nm
+.Fl f Ar list
+.Op Fl d Ar delim
+.Op Fl s
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility cuts out selected portions of each line (as specified by
+.Ar list )
+from each
+.Ar file
+and writes them to the standard output.
+If no
+.Ar file
+arguments are specified, or a file argument is a single dash
+.Pq Sq Fl ,
+.Nm
+reads from the standard input.
+The items specified by
+.Ar list
+can be in terms of column position or in terms of fields delimited
+by a special character.
+Column numbering starts from 1.
+.Pp
+The
+.Ar list
+option argument
+is a comma or whitespace separated set of numbers and/or
+number ranges.
+Number ranges consist of a number, a dash
+.Pq Sq \- ,
+and a second number
+and select the fields or columns from the first number to the second,
+inclusive.
+Numbers or number ranges may be preceded by a dash, which selects all
+fields or columns from 1 to the last number.
+Numbers or number ranges may be followed by a dash, which selects all
+fields or columns from the last number to the end of the line.
+Numbers and number ranges may be repeated, overlapping, and in any order.
+If a field or column is specified multiple times, it will appear only
+once in the output.
+It is not an error to select fields or columns not present in the
+input line.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl b Ar list
+The
+.Ar list
+specifies byte positions.
+.It Fl c Ar list
+The
+.Ar list
+specifies character positions.
+.It Fl d Ar delim
+Use
+.Ar delim
+as the field delimiter character instead of the tab character.
+.It Fl f Ar list
+The
+.Ar list
+specifies fields, separated in the input by the field delimiter character
+(see the
+.Fl d
+option.)
+Output fields are separated by a single occurrence of the field delimiter
+character.
+.It Fl n
+Do not split multi-byte characters.
+Characters will only be output if at least one byte is selected, and,
+after a prefix of zero or more unselected bytes, the rest of the bytes
+that form the character are selected.
+.It Fl s
+Suppress lines with no field delimiter characters.
+Unless specified, lines with no delimiters are passed through unmodified.
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Extract users' login names and shells from the system
+.Xr passwd 5
+file as
+.Dq name:shell
+pairs:
+.Pp
+.Dl "cut -d : -f 1,7 /etc/passwd"
+.Pp
+Show the names and login times of the currently logged in users:
+.Pp
+.Dl "who | cut -c 1-16,26-38"
+.Sh SEE ALSO
+.Xr colrm 1 ,
+.Xr paste 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.2-92 .
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.Tn AT&T
+System III
+.Ux .
diff --git a/text_cmds/cut/cut.c b/text_cmds/cut/cut.c
new file mode 100644
index 0000000..82fdc06
--- /dev/null
+++ b/text_cmds/cut/cut.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+static const char sccsid[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/cut/cut.c,v 1.30 2004/11/05 10:45:23 tjr Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <sysexits.h>
+
+int bflag;
+int cflag;
+wchar_t dchar;
+char dcharmb[MB_LEN_MAX + 1];
+int dflag;
+int fflag;
+int nflag;
+int sflag;
+
+size_t autostart, autostop, maxval;
+char * positions;
+
+int b_cut(FILE *, const char *);
+int b_n_cut(FILE *, const char *);
+int c_cut(FILE *, const char *);
+int f_cut(FILE *, const char *);
+void get_list(char *);
+void needpos(size_t);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp;
+ int (*fcn)(FILE *, const char *);
+ int ch, rval;
+ size_t n;
+
+ setlocale(LC_ALL, "");
+
+ fcn = NULL;
+ dchar = '\t'; /* default delimiter is \t */
+ strcpy(dcharmb, "\t");
+
+ while ((ch = getopt(argc, argv, "b:c:d:f:sn")) != -1)
+ switch(ch) {
+ case 'b':
+ get_list(optarg);
+ bflag = 1;
+ break;
+ case 'c':
+ get_list(optarg);
+ cflag = 1;
+ break;
+ case 'd':
+ n = mbrtowc(&dchar, optarg, MB_LEN_MAX, NULL);
+ if (dchar == '\0' || n != strlen(optarg))
+ errx(1, "bad delimiter");
+ strcpy(dcharmb, optarg);
+ dflag = 1;
+ break;
+ case 'f':
+ get_list(optarg);
+ fflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (fflag) {
+ if (bflag || cflag || nflag)
+ usage();
+ } else if (!(bflag || cflag) || dflag || sflag)
+ usage();
+ else if (!bflag && nflag)
+ usage();
+
+ if (fflag)
+ fcn = f_cut;
+ else if (cflag)
+ fcn = MB_CUR_MAX > 1 ? c_cut : b_cut;
+ else if (bflag)
+ fcn = nflag && MB_CUR_MAX > 1 ? b_n_cut : b_cut;
+
+ rval = 0;
+ if (*argv)
+ for (; *argv; ++argv) {
+ if (strcmp(*argv, "-") == 0) {
+ rval |= fcn(stdin, "stdin");
+ if (ferror(stdin)) {
+ errx(EX_IOERR, "Error reading stdin");
+ }
+ } else {
+ if (!(fp = fopen(*argv, "r"))) {
+ warn("%s", *argv);
+ rval = 1;
+ continue;
+ }
+ fcn(fp, *argv);
+ if (ferror(fp)) {
+ errx(EX_IOERR, "Error reading %s", *argv);
+ }
+ (void)fclose(fp);
+ }
+ }
+ else
+ rval = fcn(stdin, "stdin");
+ exit(rval);
+}
+
+void
+get_list(char *list)
+{
+ size_t setautostart, start, stop;
+ char *pos;
+ char *p;
+
+ /*
+ * set a byte in the positions array to indicate if a field or
+ * column is to be selected; use +1, it's 1-based, not 0-based.
+ * Numbers and number ranges may be overlapping, repeated, and in
+ * any order. We handle "-3-5" although there's no real reason too.
+ */
+ for (; (p = strsep(&list, ", \t")) != NULL;) {
+ setautostart = start = stop = 0;
+ if (*p == '-') {
+ ++p;
+ setautostart = 1;
+ }
+ if (isdigit((unsigned char)*p)) {
+ start = stop = strtol(p, &p, 10);
+ if (setautostart && start > autostart)
+ autostart = start;
+ }
+ if (*p == '-') {
+ if (isdigit((unsigned char)p[1]))
+ stop = strtol(p + 1, &p, 10);
+ if (*p == '-') {
+ ++p;
+ if (!autostop || autostop > stop)
+ autostop = stop;
+ }
+ }
+ if (*p)
+ errx(1, "[-cf] list: illegal list value");
+ if (!stop || !start)
+ errx(1, "[-cf] list: values may not include zero");
+ if (maxval < stop) {
+ maxval = stop;
+ needpos(maxval + 1);
+ }
+ for (pos = positions + start; start++ <= stop; *pos++ = 1);
+ }
+
+ /* overlapping ranges */
+ if (autostop && maxval > autostop) {
+ maxval = autostop;
+ needpos(maxval + 1);
+ }
+
+ /* set autostart */
+ if (autostart)
+ memset(positions + 1, '1', autostart);
+}
+
+void
+needpos(size_t n)
+{
+ static size_t npos;
+ size_t oldnpos;
+
+ /* Grow the positions array to at least the specified size. */
+ if (n > npos) {
+ oldnpos = npos;
+ if (npos == 0)
+ npos = n;
+ while (n > npos)
+ npos *= 2;
+ if ((positions = realloc(positions, npos)) == NULL)
+ err(1, "realloc");
+ memset((char *)positions + oldnpos, 0, npos - oldnpos);
+ }
+}
+
+int
+b_cut(FILE *fp, const char *fname __unused)
+{
+ int ch, col;
+ char *pos;
+
+ ch = 0;
+ for (;;) {
+ pos = positions + 1;
+ for (col = maxval; col; --col) {
+ if ((ch = getc(fp)) == EOF)
+ return (0);
+ if (ch == '\n')
+ break;
+ if (*pos++)
+ (void)putchar(ch);
+ }
+ if (ch != '\n') {
+ if (autostop)
+ while ((ch = getc(fp)) != EOF && ch != '\n')
+ (void)putchar(ch);
+ else
+ while ((ch = getc(fp)) != EOF && ch != '\n');
+ }
+ (void)putchar('\n');
+ }
+ return (0);
+}
+
+/*
+ * Cut based on byte positions, taking care not to split multibyte characters.
+ * Although this function also handles the case where -n is not specified,
+ * b_cut() ought to be much faster.
+ */
+int
+b_n_cut(FILE *fp, const char *fname)
+{
+ size_t col, i, lbuflen;
+ char *lbuf;
+ int canwrite, clen, warned;
+ mbstate_t mbs;
+
+ memset(&mbs, 0, sizeof(mbs));
+ warned = 0;
+ while ((lbuf = fgetln(fp, &lbuflen)) != NULL) {
+ for (col = 0; lbuflen > 0; col += clen) {
+ if ((clen = mbrlen(lbuf, lbuflen, &mbs)) < 0) {
+ if (!warned) {
+ warn("%s", fname);
+ warned = 1;
+ }
+ memset(&mbs, 0, sizeof(mbs));
+ clen = 1;
+ }
+ if (clen == 0 || *lbuf == '\n')
+ break;
+ if (col < maxval && !positions[1 + col]) {
+ /*
+ * Print the character if (1) after an initial
+ * segment of un-selected bytes, the rest of
+ * it is selected, and (2) the last byte is
+ * selected.
+ */
+ i = col;
+ while (i < col + clen && i < maxval &&
+ !positions[1 + i])
+ i++;
+ canwrite = i < col + clen;
+ for (; i < col + clen && i < maxval; i++)
+ canwrite &= positions[1 + i];
+ if (canwrite)
+ fwrite(lbuf, 1, clen, stdout);
+ } else {
+ /*
+ * Print the character if all of it has
+ * been selected.
+ */
+ canwrite = 1;
+ for (i = col; i < col + clen; i++)
+ if ((i >= maxval && !autostop) ||
+ (i < maxval && !positions[1 + i])) {
+ canwrite = 0;
+ break;
+ }
+ if (canwrite)
+ fwrite(lbuf, 1, clen, stdout);
+ }
+ lbuf += clen;
+ lbuflen -= clen;
+ }
+ if (lbuflen > 0)
+ putchar('\n');
+ }
+ return (warned);
+}
+
+int
+c_cut(FILE *fp, const char *fname)
+{
+ wint_t ch;
+ int col;
+ char *pos;
+
+ ch = 0;
+ for (;;) {
+ pos = positions + 1;
+ for (col = maxval; col; --col) {
+ if ((ch = getwc(fp)) == WEOF)
+ goto out;
+ if (ch == '\n')
+ break;
+ if (*pos++)
+ (void)putwchar(ch);
+ }
+ if (ch != '\n') {
+ if (autostop)
+ while ((ch = getwc(fp)) != WEOF && ch != '\n')
+ (void)putwchar(ch);
+ else
+ while ((ch = getwc(fp)) != WEOF && ch != '\n');
+ }
+ (void)putwchar('\n');
+ }
+out:
+ if (ferror(fp)) {
+ warn("%s", fname);
+ return (1);
+ }
+ return (0);
+}
+
+int
+f_cut(FILE *fp, const char *fname)
+{
+ wchar_t ch;
+ int field, i, isdelim;
+ char *pos, *p;
+ wchar_t sep;
+ int output;
+ char *lbuf, *mlbuf;
+ size_t clen, lbuflen, reallen;
+
+ mlbuf = NULL;
+ for (sep = dchar; (lbuf = fgetln(fp, &lbuflen)) != NULL;) {
+ reallen = lbuflen;
+ /* Assert EOL has a newline. */
+ if (*(lbuf + lbuflen - 1) != '\n') {
+ /* Can't have > 1 line with no trailing newline. */
+ mlbuf = malloc(lbuflen + 1);
+ if (mlbuf == NULL)
+ err(1, "malloc");
+ memcpy(mlbuf, lbuf, lbuflen);
+ *(mlbuf + lbuflen) = '\n';
+ lbuf = mlbuf;
+ reallen++;
+ }
+ output = 0;
+ for (isdelim = 0, p = lbuf;; p += clen) {
+ clen = mbrtowc(&ch, p, lbuf + reallen - p, NULL);
+ if (clen == (size_t)-1 || clen == (size_t)-2) {
+ warnc(EILSEQ, "%s", fname);
+ free(mlbuf);
+ return (1);
+ }
+ if (clen == 0)
+ clen = 1;
+ /* this should work if newline is delimiter */
+ if (ch == sep)
+ isdelim = 1;
+ if (ch == '\n') {
+ if (!isdelim && !sflag)
+ (void)fwrite(lbuf, lbuflen, 1, stdout);
+ break;
+ }
+ }
+ if (!isdelim)
+ continue;
+
+ pos = positions + 1;
+ for (field = maxval, p = lbuf; field; --field, ++pos) {
+ if (*pos && output++)
+ for (i = 0; dcharmb[i] != '\0'; i++)
+ putchar(dcharmb[i]);
+ for (;;) {
+ clen = mbrtowc(&ch, p, lbuf + reallen - p,
+ NULL);
+ if (clen == (size_t)-1 || clen == (size_t)-2) {
+ warnc(EILSEQ, "%s", fname);
+ free(mlbuf);
+ return (1);
+ }
+ if (clen == 0)
+ clen = 1;
+ p += clen;
+ if (ch == '\n' || ch == sep)
+ break;
+ if (*pos)
+ for (i = 0; i < (int)clen; i++)
+ putchar(p[i - clen]);
+ }
+ if (ch == '\n')
+ break;
+ }
+ if (ch != '\n') {
+ if (autostop) {
+ if (output)
+ for (i = 0; dcharmb[i] != '\0'; i++)
+ putchar(dcharmb[i]);
+ for (; (ch = *p) != '\n'; ++p)
+ (void)putchar(ch);
+ } else
+ for (; (ch = *p) != '\n'; ++p);
+ }
+ (void)putchar('\n');
+ }
+ free(mlbuf);
+ return (0);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n%s\n",
+ "usage: cut -b list [-n] [file ...]",
+ " cut -c list [file ...]",
+ " cut -f list [-s] [-d delim] [file ...]");
+ exit(1);
+}
diff --git a/text_cmds/ed/POSIX b/text_cmds/ed/POSIX
new file mode 100644
index 0000000..0a363d6
--- /dev/null
+++ b/text_cmds/ed/POSIX
@@ -0,0 +1,101 @@
+$FreeBSD: src/bin/ed/POSIX,v 1.8 2000/07/17 10:40:48 sheldonh Exp $
+
+This version of ed(1) is not strictly POSIX compliant, as described in
+the POSIX 1003.2 document. The following is a summary of the omissions,
+extensions and possible deviations from POSIX 1003.2.
+
+OMISSIONS
+---------
+1) For backwards compatibility, the POSIX rule that says a range of
+ addresses cannot be used where only a single address is expected has
+ been relaxed.
+
+2) To support the BSD `s' command (see extension [1] below),
+ substitution patterns cannot be delimited by numbers or the characters
+ `r', `g' and `p'. In contrast, POSIX specifies any character expect
+ space or newline can used as a delimiter.
+
+EXTENSIONS
+----------
+1) BSD commands have been implemented wherever they do not conflict with
+ the POSIX standard. The BSD-ism's included are:
+ i) `s' (i.e., s[n][rgp]*) to repeat a previous substitution,
+ ii) `W' for appending text to an existing file,
+ iii) `wq' for exiting after a write,
+ iv) `z' for scrolling through the buffer, and
+ v) BSD line addressing syntax (i.e., `^' and `%') is recognized.
+
+2) If crypt(3) is available, files can be read and written using DES
+ encryption. The `x' command prompts the user to enter a key used for
+ encrypting/ decrypting subsequent reads and writes. If only a newline
+ is entered as the key, then encryption is disabled. Otherwise, a key
+ is read in the same manner as a password entry. The key remains in
+ effect until encryption is disabled. For more information on the
+ encryption algorithm, see the bdes(1) man page. Encryption/decryption
+ should be fully compatible with SunOS des(1).
+
+3) The POSIX interactive global commands `G' and `V' are extended to
+ support multiple commands, including `a', `i' and `c'. The command
+ format is the same as for the global commands `g' and `v', i.e., one
+ command per line with each line, except for the last, ending in a
+ backslash (\).
+
+4) An extension to the POSIX file commands `E', `e', `r', `W' and `w' is
+ that <file> arguments are processed for backslash escapes, i.e., any
+ character preceded by a backslash is interpreted literally. If the
+ first unescaped character of a <file> argument is a bang (!), then the
+ rest of the line is interpreted as a shell command, and no escape
+ processing is performed by ed.
+
+5) For SunOS ed(1) compatibility, ed runs in restricted mode if invoked
+ as red. This limits editing of files in the local directory only and
+ prohibits shell commands.
+
+DEVIATIONS
+----------
+1) Though ed is not a stream editor, it can be used to edit binary files.
+ To assist in binary editing, when a file containing at least one ASCII
+ NUL character is written, a newline is not appended if it did not
+ already contain one upon reading. In particular, reading /dev/null
+ prior to writing prevents appending a newline to a binary file.
+
+ For example, to create a file with ed containing a single NUL character:
+ $ ed file
+ a
+ ^@
+ .
+ r /dev/null
+ wq
+
+ Similarly, to remove a newline from the end of binary `file':
+ $ ed file
+ r /dev/null
+ wq
+
+2) Since the behavior of `u' (undo) within a `g' (global) command list is
+ not specified by POSIX, it follows the behavior of the SunOS ed:
+ undo forces a global command list to be executed only once, rather than
+ for each line matching a global pattern. In addtion, each instance of
+ `u' within a global command undoes all previous commands (including
+ undo's) in the command list. This seems the best way, since the
+ alternatives are either too complicated to implement or too confusing
+ to use.
+
+ The global/undo combination is useful for masking errors that
+ would otherwise cause a script to fail. For instance, an ed script
+ to remove any occurences of either `censor1' or `censor2' might be
+ written as:
+ ed - file <<EOF
+ 1g/.*/u\
+ ,s/censor1//g\
+ ,s/censor2//g
+ ...
+
+3) The `m' (move) command within a `g' command list also follows the SunOS
+ ed implementation: any moved lines are removed from the global command's
+ `active' list.
+
+4) If ed is invoked with a name argument prefixed by a bang (!), then the
+ remainder of the argument is interpreted as a shell command. To invoke
+ ed on a file whose name starts with bang, prefix the name with a
+ backslash.
diff --git a/text_cmds/ed/README b/text_cmds/ed/README
new file mode 100644
index 0000000..1f50f10
--- /dev/null
+++ b/text_cmds/ed/README
@@ -0,0 +1,24 @@
+$FreeBSD: src/bin/ed/README,v 1.7 1999/08/27 23:14:12 peter Exp $
+
+ed is an 8-bit-clean, POSIX-compliant line editor. It should work with
+any regular expression package that conforms to the POSIX interface
+standard, such as GNU regex(3).
+
+If reliable signals are supported (e.g., POSIX sigaction(2)), it should
+compile with little trouble. Otherwise, the macros SPL1() and SPL0()
+should be redefined to disable interrupts.
+
+The following compiler directives are recognized:
+DES - to add encryption support (requires crypt(3))
+NO_REALLOC_NULL - if realloc(3) does not accept a NULL pointer
+BACKWARDS - for backwards compatibility
+NEED_INSQUE - if insque(3) is missing
+
+The file `POSIX' describes extensions to and deviations from the POSIX
+standard.
+
+The ./test directory contains regression tests for ed. The README
+file in that directory explains how to run these.
+
+For a description of the ed algorithm, see Kernighan and Plauger's book
+"Software Tools in Pascal," Addison-Wesley, 1981.
diff --git a/text_cmds/ed/buf.c b/text_cmds/ed/buf.c
new file mode 100644
index 0000000..93c1b92
--- /dev/null
+++ b/text_cmds/ed/buf.c
@@ -0,0 +1,284 @@
+/* buf.c: This file contains the scratch-file buffer routines for the
+ ed line editor. */
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ed/buf.c,v 1.22 2002/06/30 05:13:53 obrien Exp $");
+
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include "ed.h"
+
+
+FILE *sfp; /* scratch file pointer */
+off_t sfseek; /* scratch file position */
+int seek_write; /* seek before writing */
+line_t buffer_head; /* incore buffer */
+
+/* get_sbuf_line: get a line of text from the scratch file; return pointer
+ to the text */
+char *
+get_sbuf_line(line_t *lp)
+{
+ static char *sfbuf = NULL; /* buffer */
+ static int sfbufsz = 0; /* buffer size */
+
+ int len, ct;
+
+ if (lp == &buffer_head)
+ return NULL;
+ seek_write = 1; /* force seek on write */
+ /* out of position */
+ if (sfseek != lp->seek) {
+ sfseek = lp->seek;
+ if (fseeko(sfp, sfseek, SEEK_SET) < 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot seek temp file";
+ return NULL;
+ }
+ }
+ len = lp->len;
+ REALLOC(sfbuf, sfbufsz, len + 1, NULL);
+ if ((ct = fread(sfbuf, sizeof(char), len, sfp)) < 0 || ct != len) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot read temp file";
+ return NULL;
+ }
+ sfseek += len; /* update file position */
+ sfbuf[len] = '\0';
+ return sfbuf;
+}
+
+
+/* put_sbuf_line: write a line of text to the scratch file and add a line node
+ to the editor buffer; return a pointer to the end of the text */
+const char *
+put_sbuf_line(const char *cs)
+{
+ line_t *lp;
+ int len, ct;
+ const char *s;
+
+ if ((lp = (line_t *) malloc(sizeof(line_t))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ return NULL;
+ }
+ /* assert: cs is '\n' terminated */
+ for (s = cs; *s != '\n'; s++)
+ ;
+ if (s - cs >= LINECHARS) {
+ errmsg = "line too long";
+ return NULL;
+ }
+ len = s - cs;
+ /* out of position */
+ if (seek_write) {
+ if (fseeko(sfp, (off_t)0, SEEK_END) < 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot seek temp file";
+ return NULL;
+ }
+ sfseek = ftello(sfp);
+ seek_write = 0;
+ }
+ /* assert: SPL1() */
+ if ((ct = fwrite(cs, sizeof(char), len, sfp)) < 0 || ct != len) {
+ sfseek = -1;
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot write temp file";
+ return NULL;
+ }
+ lp->len = len;
+ lp->seek = sfseek;
+ add_line_node(lp);
+ sfseek += len; /* update file position */
+ return ++s;
+}
+
+
+/* add_line_node: add a line node in the editor buffer after the current line */
+void
+add_line_node(line_t *lp)
+{
+ line_t *cp;
+
+ cp = get_addressed_line_node(current_addr); /* this get_addressed_line_node last! */
+ INSQUE(lp, cp);
+ addr_last++;
+ current_addr++;
+}
+
+
+/* get_line_node_addr: return line number of pointer */
+long
+get_line_node_addr(line_t *lp)
+{
+ line_t *cp = &buffer_head;
+ long n = 0;
+
+ while (cp != lp && (cp = cp->q_forw) != &buffer_head)
+ n++;
+ if (n && cp == &buffer_head) {
+ errmsg = "invalid address";
+ return ERR;
+ }
+ return n;
+}
+
+
+/* get_addressed_line_node: return pointer to a line node in the editor buffer */
+line_t *
+get_addressed_line_node(long n)
+{
+ static line_t *lp = &buffer_head;
+ static long on = 0;
+
+ SPL1();
+ if (n > on)
+ if (n <= (on + addr_last) >> 1)
+ for (; on < n; on++)
+ lp = lp->q_forw;
+ else {
+ lp = buffer_head.q_back;
+ for (on = addr_last; on > n; on--)
+ lp = lp->q_back;
+ }
+ else
+ if (n >= on >> 1)
+ for (; on > n; on--)
+ lp = lp->q_back;
+ else {
+ lp = &buffer_head;
+ for (on = 0; on < n; on++)
+ lp = lp->q_forw;
+ }
+ SPL0();
+ return lp;
+}
+
+
+extern int newline_added;
+
+char sfn[15] = ""; /* scratch file name */
+
+/* open_sbuf: open scratch file */
+int
+open_sbuf(void)
+{
+ int fd;
+ int u;
+
+ isbinary = newline_added = 0;
+ u = umask(077);
+ strcpy(sfn, "/tmp/ed.XXXXXX");
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (sfp = fdopen(fd, "w+")) == NULL) {
+ if (fd != -1)
+ close(fd);
+ perror(sfn);
+ errmsg = "cannot open temp file";
+ umask(u);
+ return ERR;
+ }
+ umask(u);
+ return 0;
+}
+
+
+/* close_sbuf: close scratch file */
+int
+close_sbuf(void)
+{
+ if (sfp) {
+ if (fclose(sfp) < 0) {
+ fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
+ errmsg = "cannot close temp file";
+ return ERR;
+ }
+ sfp = NULL;
+ unlink(sfn);
+ }
+ sfseek = seek_write = 0;
+ return 0;
+}
+
+
+/* quit: remove_lines scratch file and exit */
+void
+quit(int n)
+{
+ if (sfp) {
+ fclose(sfp);
+ unlink(sfn);
+ }
+ exit(n);
+}
+
+
+unsigned char ctab[256]; /* character translation table */
+
+/* init_buffers: open scratch buffer; initialize line queue */
+void
+init_buffers(void)
+{
+ int i = 0;
+
+ /* Read stdin one character at a time to avoid i/o contention
+ with shell escapes invoked by nonterminal input, e.g.,
+ ed - <<EOF
+ !cat
+ hello, world
+ EOF */
+ setbuffer(stdin, stdinbuf, 1);
+
+ /* Ensure stdout is line buffered. This avoids bogus delays
+ of output if stdout is piped through utilities to a terminal. */
+ setvbuf(stdout, NULL, _IOLBF, 0);
+ if (open_sbuf() < 0)
+ quit(2);
+ REQUE(&buffer_head, &buffer_head);
+ for (i = 0; i < 256; i++)
+ ctab[i] = i;
+}
+
+
+/* translit_text: translate characters in a string */
+char *
+translit_text(char *s, int len, int from, int to)
+{
+ static int i = 0;
+
+ unsigned char *us;
+
+ ctab[i] = i; /* restore table to initial state */
+ ctab[i = from] = to;
+ for (us = (unsigned char *) s; len-- > 0; us++)
+ *us = ctab[*us];
+ return s;
+}
diff --git a/text_cmds/ed/cbc.c b/text_cmds/ed/cbc.c
new file mode 100644
index 0000000..22dd0d2
--- /dev/null
+++ b/text_cmds/ed/cbc.c
@@ -0,0 +1,402 @@
+/* cbc.c: This file contains the encryption routines for the ed line editor */
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ed/cbc.c,v 1.20 2004/04/06 20:06:47 markm Exp $");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <pwd.h>
+#ifdef DES
+#include <time.h>
+#include <openssl/des.h>
+#define ED_DES_INCLUDES
+#endif
+
+#include "ed.h"
+
+
+/*
+ * BSD and System V systems offer special library calls that do
+ * block move_liness and fills, so if possible we take advantage of them
+ */
+#define MEMCPY(dest,src,len) memcpy((dest),(src),(len))
+#define MEMZERO(dest,len) memset((dest), 0, (len))
+
+/* Hide the calls to the primitive encryption routines. */
+#define DES_XFORM(buf) \
+ DES_ecb_encrypt(buf, buf, &schedule, \
+ inverse ? DES_DECRYPT : DES_ENCRYPT);
+
+/*
+ * read/write - no error checking
+ */
+#define READ(buf, n, fp) fread(buf, sizeof(char), n, fp)
+#define WRITE(buf, n, fp) fwrite(buf, sizeof(char), n, fp)
+
+/*
+ * global variables and related macros
+ */
+
+enum { /* encrypt, decrypt, authenticate */
+ MODE_ENCRYPT, MODE_DECRYPT, MODE_AUTHENTICATE
+} mode = MODE_ENCRYPT;
+
+#ifdef DES
+DES_cblock ivec; /* initialization vector */
+DES_cblock pvec; /* padding vector */
+#endif
+
+char bits[] = { /* used to extract bits from a char */
+ '\200', '\100', '\040', '\020', '\010', '\004', '\002', '\001'
+};
+
+int pflag; /* 1 to preserve parity bits */
+
+#ifdef DES
+DES_key_schedule schedule; /* expanded DES key */
+#endif
+
+unsigned char des_buf[8]; /* shared buffer for get_des_char/put_des_char */
+int des_ct = 0; /* count for get_des_char/put_des_char */
+int des_n = 0; /* index for put_des_char/get_des_char */
+
+/* init_des_cipher: initialize DES */
+void
+init_des_cipher(void)
+{
+#ifdef DES
+ int i;
+
+ des_ct = des_n = 0;
+
+ /* initialize the initialization vector */
+ MEMZERO(ivec, 8);
+
+ /* initialize the padding vector */
+ for (i = 0; i < 8; i++)
+ pvec[i] = (char) (arc4random() % 256);
+#endif
+}
+
+
+/* get_des_char: return next char in an encrypted file */
+int
+get_des_char(FILE *fp)
+{
+#ifdef DES
+ if (des_n >= des_ct) {
+ des_n = 0;
+ des_ct = cbc_decode(des_buf, fp);
+ }
+ return (des_ct > 0) ? des_buf[des_n++] : EOF;
+#else
+ return (getc(fp));
+#endif
+}
+
+
+/* put_des_char: write a char to an encrypted file; return char written */
+int
+put_des_char(int c, FILE *fp)
+{
+#ifdef DES
+ if (des_n == sizeof des_buf) {
+ des_ct = cbc_encode(des_buf, des_n, fp);
+ des_n = 0;
+ }
+ return (des_ct >= 0) ? (des_buf[des_n++] = c) : EOF;
+#else
+ return (fputc(c, fp));
+#endif
+}
+
+
+/* flush_des_file: flush an encrypted file's output; return status */
+int
+flush_des_file(FILE *fp)
+{
+#ifdef DES
+ if (des_n == sizeof des_buf) {
+ des_ct = cbc_encode(des_buf, des_n, fp);
+ des_n = 0;
+ }
+ return (des_ct >= 0 && cbc_encode(des_buf, des_n, fp) >= 0) ? 0 : EOF;
+#else
+ return (fflush(fp));
+#endif
+}
+
+#ifdef DES
+/*
+ * get keyword from tty or stdin
+ */
+int
+get_keyword(void)
+{
+ char *p; /* used to obtain the key */
+ DES_cblock msgbuf; /* I/O buffer */
+
+ /*
+ * get the key
+ */
+ if (*(p = getpass("Enter key: "))) {
+
+ /*
+ * copy it, nul-padded, into the key area
+ */
+ expand_des_key(msgbuf, p);
+ MEMZERO(p, _PASSWORD_LEN);
+ set_des_key(&msgbuf);
+ MEMZERO(msgbuf, sizeof msgbuf);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * print a warning message and, possibly, terminate
+ */
+void
+des_error(const char *s)
+{
+ errmsg = s ? s : strerror(errno);
+}
+
+/*
+ * map a hex character to an integer
+ */
+int
+hex_to_binary(int c, int radix)
+{
+ switch(c) {
+ case '0': return(0x0);
+ case '1': return(0x1);
+ case '2': return(radix > 2 ? 0x2 : -1);
+ case '3': return(radix > 3 ? 0x3 : -1);
+ case '4': return(radix > 4 ? 0x4 : -1);
+ case '5': return(radix > 5 ? 0x5 : -1);
+ case '6': return(radix > 6 ? 0x6 : -1);
+ case '7': return(radix > 7 ? 0x7 : -1);
+ case '8': return(radix > 8 ? 0x8 : -1);
+ case '9': return(radix > 9 ? 0x9 : -1);
+ case 'A': case 'a': return(radix > 10 ? 0xa : -1);
+ case 'B': case 'b': return(radix > 11 ? 0xb : -1);
+ case 'C': case 'c': return(radix > 12 ? 0xc : -1);
+ case 'D': case 'd': return(radix > 13 ? 0xd : -1);
+ case 'E': case 'e': return(radix > 14 ? 0xe : -1);
+ case 'F': case 'f': return(radix > 15 ? 0xf : -1);
+ }
+ /*
+ * invalid character
+ */
+ return(-1);
+}
+
+/*
+ * convert the key to a bit pattern
+ * obuf bit pattern
+ * kbuf the key itself
+ */
+void
+expand_des_key(char *obuf, char *kbuf)
+{
+ int i, j; /* counter in a for loop */
+ int nbuf[64]; /* used for hex/key translation */
+
+ /*
+ * leading '0x' or '0X' == hex key
+ */
+ if (kbuf[0] == '0' && (kbuf[1] == 'x' || kbuf[1] == 'X')) {
+ kbuf = &kbuf[2];
+ /*
+ * now translate it, bombing on any illegal hex digit
+ */
+ for (i = 0; kbuf[i] && i < 16; i++)
+ if ((nbuf[i] = hex_to_binary((int) kbuf[i], 16)) == -1)
+ des_error("bad hex digit in key");
+ while (i < 16)
+ nbuf[i++] = 0;
+ for (i = 0; i < 8; i++)
+ obuf[i] =
+ ((nbuf[2*i]&0xf)<<4) | (nbuf[2*i+1]&0xf);
+ /* preserve parity bits */
+ pflag = 1;
+ return;
+ }
+ /*
+ * leading '0b' or '0B' == binary key
+ */
+ if (kbuf[0] == '0' && (kbuf[1] == 'b' || kbuf[1] == 'B')) {
+ kbuf = &kbuf[2];
+ /*
+ * now translate it, bombing on any illegal binary digit
+ */
+ for (i = 0; kbuf[i] && i < 16; i++)
+ if ((nbuf[i] = hex_to_binary((int) kbuf[i], 2)) == -1)
+ des_error("bad binary digit in key");
+ while (i < 64)
+ nbuf[i++] = 0;
+ for (i = 0; i < 8; i++)
+ for (j = 0; j < 8; j++)
+ obuf[i] = (obuf[i]<<1)|nbuf[8*i+j];
+ /* preserve parity bits */
+ pflag = 1;
+ return;
+ }
+ /*
+ * no special leader -- ASCII
+ */
+ (void)strncpy(obuf, kbuf, 8);
+}
+
+/*****************
+ * DES FUNCTIONS *
+ *****************/
+/*
+ * This sets the DES key and (if you're using the deszip version)
+ * the direction of the transformation. This uses the Sun
+ * to map the 64-bit key onto the 56 bits that the key schedule
+ * generation routines use: the old way, which just uses the user-
+ * supplied 64 bits as is, and the new way, which resets the parity
+ * bit to be the same as the low-order bit in each character. The
+ * new way generates a greater variety of key schedules, since many
+ * systems set the parity (high) bit of each character to 0, and the
+ * DES ignores the low order bit of each character.
+ */
+void
+set_des_key(DES_cblock *buf) /* key block */
+{
+ int i, j; /* counter in a for loop */
+ int par; /* parity counter */
+
+ /*
+ * if the parity is not preserved, flip it
+ */
+ if (!pflag) {
+ for (i = 0; i < 8; i++) {
+ par = 0;
+ for (j = 1; j < 8; j++)
+ if ((bits[j] & (*buf)[i]) != 0)
+ par++;
+ if ((par & 0x01) == 0x01)
+ (*buf)[i] &= 0x7f;
+ else
+ (*buf)[i] = ((*buf)[i] & 0x7f) | 0x80;
+ }
+ }
+
+ DES_set_odd_parity(buf);
+ DES_set_key(buf, &schedule);
+}
+
+
+/*
+ * This encrypts using the Cipher Block Chaining mode of DES
+ */
+int
+cbc_encode(unsigned char *msgbuf, int n, FILE *fp)
+{
+ int inverse = 0; /* 0 to encrypt, 1 to decrypt */
+
+ /*
+ * do the transformation
+ */
+ if (n == 8) {
+ for (n = 0; n < 8; n++)
+ msgbuf[n] ^= ivec[n];
+ DES_XFORM((DES_cblock *)msgbuf);
+ MEMCPY(ivec, msgbuf, 8);
+ return WRITE(msgbuf, 8, fp);
+ }
+ /*
+ * at EOF or last block -- in either case, the last byte contains
+ * the character representation of the number of bytes in it
+ */
+/*
+ MEMZERO(msgbuf + n, 8 - n);
+*/
+ /*
+ * Pad the last block randomly
+ */
+ (void)MEMCPY(msgbuf + n, pvec, 8 - n);
+ msgbuf[7] = n;
+ for (n = 0; n < 8; n++)
+ msgbuf[n] ^= ivec[n];
+ DES_XFORM((DES_cblock *)msgbuf);
+ return WRITE(msgbuf, 8, fp);
+}
+
+/*
+ * This decrypts using the Cipher Block Chaining mode of DES
+ * msgbuf I/O buffer
+ * fp input file descriptor
+ */
+int
+cbc_decode(unsigned char *msgbuf, FILE *fp)
+{
+ DES_cblock tbuf; /* temp buffer for initialization vector */
+ int n; /* number of bytes actually read */
+ int c; /* used to test for EOF */
+ int inverse = 1; /* 0 to encrypt, 1 to decrypt */
+
+ if ((n = READ(msgbuf, 8, fp)) == 8) {
+ /*
+ * do the transformation
+ */
+ MEMCPY(tbuf, msgbuf, 8);
+ DES_XFORM((DES_cblock *)msgbuf);
+ for (c = 0; c < 8; c++)
+ msgbuf[c] ^= ivec[c];
+ MEMCPY(ivec, tbuf, 8);
+ /*
+ * if the last one, handle it specially
+ */
+ if ((c = fgetc(fp)) == EOF) {
+ n = msgbuf[7];
+ if (n < 0 || n > 7) {
+ des_error("decryption failed (block corrupted)");
+ return EOF;
+ }
+ } else
+ (void)ungetc(c, fp);
+ return n;
+ }
+ if (n > 0)
+ des_error("decryption failed (incomplete block)");
+ else if (n < 0)
+ des_error("cannot read file");
+ return EOF;
+}
+#endif /* DES */
diff --git a/text_cmds/ed/ed.1 b/text_cmds/ed/ed.1
new file mode 100644
index 0000000..8c4b6b2
--- /dev/null
+++ b/text_cmds/ed/ed.1
@@ -0,0 +1,1004 @@
+.\" $FreeBSD: src/bin/ed/ed.1,v 1.35 2005/01/16 16:41:56 ru Exp $
+.Dd July 3, 2004
+.Dt ED 1
+.Os
+.Sh NAME
+.Nm ed ,
+.Nm red
+.Nd text editor
+.Sh SYNOPSIS
+.Nm
+.Op Fl
+.Op Fl sx
+.Op Fl p Ar string
+.Op Ar file
+.Nm red
+.Op Fl
+.Op Fl sx
+.Op Fl p Ar string
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility is a line-oriented text editor.
+It is used to create, display, modify and otherwise manipulate text
+files.
+When invoked as
+.Nm red ,
+the editor runs in
+.Qq restricted
+mode, in which the only difference is that the editor restricts the
+use of filenames which start with
+.Ql \&!
+(interpreted as shell commands by
+.Nm )
+or contain a
+.Ql \&/ .
+Note that editing outside of the current directory is only prohibited
+if the user does not have write access to the current directory.
+If a user has write access to the current directory, then symbolic
+links can be created in the current directory, in which case
+.Nm red
+will not stop the user from editing the file that the symbolic link
+points to.
+.Pp
+If invoked with a
+.Ar file
+argument, then a copy of
+.Ar file
+is read into the editor's buffer.
+Changes are made to this copy and not directly to
+.Ar file
+itself.
+Upon quitting
+.Nm ,
+any changes not explicitly saved with a
+.Em w
+command are lost.
+.Pp
+Editing is done in two distinct modes:
+.Em command
+and
+.Em input .
+When first invoked,
+.Nm
+is in command mode.
+In this mode commands are read from the standard input and
+executed to manipulate the contents of the editor buffer.
+A typical command might look like:
+.Pp
+.Sm off
+.Cm ,s No / Em old Xo
+.No / Em new
+.No / Cm g
+.Xc
+.Sm on
+.Pp
+which replaces all occurrences of the string
+.Em old
+with
+.Em new .
+.Pp
+When an input command, such as
+.Em a
+(append),
+.Em i
+(insert) or
+.Em c
+(change), is given,
+.Nm
+enters input mode.
+This is the primary means
+of adding text to a file.
+In this mode, no commands are available;
+instead, the standard input is written
+directly to the editor buffer.
+Lines consist of text up to and
+including a
+.Em newline
+character.
+Input mode is terminated by
+entering a single period
+.Pq Em .\&
+on a line.
+.Pp
+All
+.Nm
+commands operate on whole lines or ranges of lines; e.g.,
+the
+.Em d
+command deletes lines; the
+.Em m
+command moves lines, and so on.
+It is possible to modify only a portion of a line by means of replacement,
+as in the example above.
+However even here, the
+.Em s
+command is applied to whole lines at a time.
+.Pp
+In general,
+.Nm
+commands consist of zero or more line addresses, followed by a single
+character command and possibly additional parameters; i.e.,
+commands have the structure:
+.Pp
+.Sm off
+.Xo
+.Op Ar address Op , Ar address
+.Ar command Op Ar parameters
+.Xc
+.Sm on
+.Pp
+The address(es) indicate the line or range of lines to be affected by the
+command.
+If fewer addresses are given than the command accepts, then
+default addresses are supplied.
+.Sh OPTIONS
+The following options are available:
+.Bl -tag -width indent
+.It Fl s
+Suppress diagnostics.
+This should be used if
+.Nm Ns 's
+standard input is from a script.
+.It Fl x
+Prompt for an encryption key to be used in subsequent reads and writes
+(see the
+.Em x
+command).
+Unsupported on Mac OS X.
+.It Fl p Ar string
+Specify a command prompt.
+This may be toggled on and off with the
+.Em P
+command.
+.It Ar file
+Specify the name of a file to read.
+If
+.Ar file
+is prefixed with a
+bang (!), then it is interpreted as a shell command.
+In this case,
+what is read is
+the standard output of
+.Ar file
+executed via
+.Xr sh 1 .
+To read a file whose name begins with a bang, prefix the
+name with a backslash (\\).
+The default filename is set to
+.Ar file
+only if it is not prefixed with a bang.
+.El
+.Sh LINE ADDRESSING
+An address represents the number of a line in the buffer.
+The
+.Nm
+utility maintains a
+.Em current address
+which is
+typically supplied to commands as the default address when none is specified.
+When a file is first read, the current address is set to the last line
+of the file.
+In general, the current address is set to the last line
+affected by a command.
+.Pp
+A line address is
+constructed from one of the bases in the list below, optionally followed
+by a numeric offset.
+The offset may include any combination
+of digits, operators (i.e.,
+.Em + ,
+.Em -
+and
+.Em ^ )
+and whitespace.
+Addresses are read from left to right, and their values are computed
+relative to the current address.
+.Pp
+One exception to the rule that addresses represent line numbers is the
+address
+.Em 0
+(zero).
+This means "before the first line,"
+and is legal wherever it makes sense.
+.Pp
+An address range is two addresses separated either by a comma or
+semi-colon.
+The value of the first address in a range cannot exceed the
+value of the second.
+If only one address is given in a range, then
+the second address is set to the given address.
+If an
+.Em n Ns -tuple
+of addresses is given where
+.Em "n\ >\ 2" ,
+then the corresponding range is determined by the last two addresses in
+the
+.Em n Ns -tuple .
+If only one address is expected, then the last address is used.
+.Pp
+Each address in a comma-delimited range is interpreted relative to the
+current address.
+In a semi-colon-delimited range, the first address is
+used to set the current address, and the second address is interpreted
+relative to the first.
+.Pp
+The following address symbols are recognized:
+.Bl -tag -width indent
+.It .
+The current line (address) in the buffer.
+.It $
+The last line in the buffer.
+.It n
+The
+.Em n Ns th,
+line in the buffer
+where
+.Em n
+is a number in the range
+.Em [0,$] .
+.It - or ^
+The previous line.
+This is equivalent to
+.Em -1
+and may be repeated with cumulative effect.
+.It -n or ^n
+The
+.Em n Ns th
+previous line, where
+.Em n
+is a non-negative number.
+.It +
+The next line.
+This is equivalent to
+.Em +1
+and may be repeated with cumulative effect.
+.It +n
+The
+.Em n Ns th
+next line, where
+.Em n
+is a non-negative number.
+.It , or %
+The first through last lines in the buffer.
+This is equivalent to
+the address range
+.Em 1,$ .
+.It ;
+The current through last lines in the buffer.
+This is equivalent to
+the address range
+.Em .,$ .
+.It /re/
+The next line containing the regular expression
+.Em re .
+The search wraps to the beginning of the buffer and continues down to the
+current line, if necessary.
+// repeats the last search.
+.It ?re?
+The
+previous line containing the regular expression
+.Em re .
+The search wraps to the end of the buffer and continues up to the
+current line, if necessary.
+?? repeats the last search.
+.It 'lc
+The
+line previously marked by a
+.Em k
+(mark) command, where
+.Em lc
+is a lower case letter.
+.El
+.Sh REGULAR EXPRESSIONS
+Regular expressions are patterns used in selecting text.
+For example, the command:
+.Pp
+.Sm off
+.Cm g No / Em string Xo
+.No /
+.Xc
+.Sm on
+.Pp
+prints all lines containing
+.Em string .
+Regular expressions are also
+used by the
+.Em s
+command for selecting old text to be replaced with new.
+.Pp
+In addition to a specifying string literals, regular expressions can
+represent
+classes of strings.
+Strings thus represented are said to be matched
+by the corresponding regular expression.
+If it is possible for a regular expression
+to match several strings in a line, then the left-most longest match is
+the one selected.
+.Pp
+The following symbols are used in constructing regular expressions:
+.Bl -tag -width indent
+.It c
+Any character
+.Em c
+not listed below, including
+.Ql \&{ ,
+.Ql \&} ,
+.Ql \&( ,
+.Ql \&) ,
+.Ql <
+and
+.Ql > ,
+matches itself.
+.It Pf \e c
+Any backslash-escaped character
+.Em c ,
+except for
+.Ql \&{ ,
+.Ql \&} ,
+.Ql \&( ,
+.Ql \&) ,
+.Ql <
+and
+.Ql > ,
+matches itself.
+.It .
+Match any single character.
+.It Op char-class
+Match any single character in
+.Em char-class .
+To include a
+.Ql \&]
+in
+.Em char-class ,
+it must be the first character.
+A range of characters may be specified by separating the end characters
+of the range with a
+.Ql - ,
+e.g.,
+.Ql a-z
+specifies the lower case characters.
+The following literal expressions can also be used in
+.Em char-class
+to specify sets of characters:
+.Pp
+.Bl -column "[:alnum:]" "[:cntrl:]" "[:lower:]" "[:xdigit:]" -compact
+.It [:alnum:] Ta [:cntrl:] Ta [:lower:] Ta [:space:]
+.It [:alpha:] Ta [:digit:] Ta [:print:] Ta [:upper:]
+.It [:blank:] Ta [:graph:] Ta [:punct:] Ta [:xdigit:]
+.El
+.Pp
+If
+.Ql -
+appears as the first or last
+character of
+.Em char-class ,
+then it matches itself.
+All other characters in
+.Em char-class
+match themselves.
+.Pp
+Patterns in
+.Em char-class
+of the form:
+.Pp
+.Bl -item -compact -offset 2n
+.It
+.Op \&. Ns Ar col-elm Ns .\&
+or,
+.It
+.Op = Ns Ar col-elm Ns =
+.El
+.Pp
+where
+.Ar col-elm
+is a
+.Em collating element
+are interpreted according to the current locale settings
+(not currently supported).
+See
+.Xr regex 3
+and
+.Xr re_format 7
+for an explanation of these constructs.
+.It Op ^char-class
+Match any single character, other than newline, not in
+.Em char-class .
+.Em Char-class
+is defined
+as above.
+.It ^
+If
+.Em ^
+is the first character of a regular expression, then it
+anchors the regular expression to the beginning of a line.
+Otherwise, it matches itself.
+.It $
+If
+.Em $
+is the last character of a regular expression, it
+anchors the regular expression to the end of a line.
+Otherwise, it matches itself.
+.It Pf \e <
+Anchor the single character regular expression or subexpression
+immediately following it to the beginning of a word.
+(This may not be available)
+.It Pf \e >
+Anchor the single character regular expression or subexpression
+immediately following it to the end of a word.
+(This may not be available)
+.It Pf \e (re\e)
+Define a subexpression
+.Em re .
+Subexpressions may be nested.
+A subsequent backreference of the form
+.Pf \e Em n ,
+where
+.Em n
+is a number in the range [1,9], expands to the text matched by the
+.Em n Ns th
+subexpression.
+For example, the regular expression
+.Ql \e(.*\e)\e1
+matches any string
+consisting of identical adjacent substrings.
+Subexpressions are ordered relative to
+their left delimiter.
+.It *
+Match the single character regular expression or subexpression
+immediately preceding it zero or more times.
+If
+.Em *
+is the first
+character of a regular expression or subexpression, then it matches
+itself.
+The
+.Em *
+operator sometimes yields unexpected results.
+For example, the regular expression
+.Ql b*
+matches the beginning of
+the string
+.Ql abbb
+(as opposed to the substring
+.Ql bbb ) ,
+since a null match
+is the only left-most match.
+.It \e{n,m\e} or \e{n,\e} or \e{n\e}
+Match the single character regular expression or subexpression
+immediately preceding it at least
+.Em n
+and at most
+.Em m
+times.
+If
+.Em m
+is omitted, then it matches at least
+.Em n
+times.
+If the comma is also omitted, then it matches exactly
+.Em n
+times.
+.El
+.Pp
+Additional regular expression operators may be defined depending on the
+particular
+.Xr regex 3
+implementation.
+.Sh COMMANDS
+All
+.Nm
+commands are single characters, though some require additional parameters.
+If a command's parameters extend over several lines, then
+each line except for the last
+must be terminated with a backslash (\\).
+.Pp
+In general, at most one command is allowed per line.
+However, most commands accept a print suffix, which is any of
+.Em p
+(print),
+.Em l
+(list),
+or
+.Em n
+(enumerate),
+to print the last line affected by the command.
+.Pp
+An interrupt (typically ^C) has the effect of aborting the current command
+and returning the editor to command mode.
+.Pp
+The
+.Nm
+utility
+recognizes the following commands.
+The commands are shown together with
+the default address or address range supplied if none is
+specified (in parenthesis).
+.Bl -tag -width indent
+.It (.)a
+Append text to the buffer after the addressed line.
+Text is entered in input mode.
+The current address is set to last line entered.
+.It (.,.)c
+Change lines in the buffer.
+The addressed lines are deleted
+from the buffer, and text is appended in their place.
+Text is entered in input mode.
+The current address is set to last line entered.
+.It (.,.)d
+Delete the addressed lines from the buffer.
+If there is a line after the deleted range, then the current address is set
+to this line.
+Otherwise the current address is set to the line
+before the deleted range.
+.It e Ar file
+Edit
+.Ar file ,
+and sets the default filename.
+If
+.Ar file
+is not specified, then the default filename is used.
+Any lines in the buffer are deleted before
+the new file is read.
+The current address is set to the last line read.
+.It e Ar !command
+Edit the standard output of
+.Ar !command ,
+(see
+.Ar !command
+below).
+The default filename is unchanged.
+Any lines in the buffer are deleted before the output of
+.Ar command
+is read.
+The current address is set to the last line read.
+.It E Ar file
+Edit
+.Ar file
+unconditionally.
+This is similar to the
+.Em e
+command,
+except that unwritten changes are discarded without warning.
+The current address is set to the last line read.
+.It f Ar file
+Set the default filename to
+.Ar file .
+If
+.Ar file
+is not specified, then the default unescaped filename is printed.
+.It (1,$)g/re/command-list
+Apply
+.Ar command-list
+to each of the addressed lines matching a regular expression
+.Ar re .
+The current address is set to the
+line currently matched before
+.Ar command-list
+is executed.
+At the end of the
+.Em g
+command, the current address is set to the last line affected by
+.Ar command-list .
+.Pp
+Each command in
+.Ar command-list
+must be on a separate line,
+and every line except for the last must be terminated by a backslash
+(\\).
+Any commands are allowed, except for
+.Em g ,
+.Em G ,
+.Em v ,
+and
+.Em V .
+A newline alone in
+.Ar command-list
+is equivalent to a
+.Em p
+command.
+.It (1,$)G/re/
+Interactively edit the addressed lines matching a regular expression
+.Ar re .
+For each matching line,
+the line is printed,
+the current address is set,
+and the user is prompted to enter a
+.Ar command-list .
+At the end of the
+.Em G
+command, the current address
+is set to the last line affected by (the last)
+.Ar command-list .
+.Pp
+The format of
+.Ar command-list
+is the same as that of the
+.Em g
+command.
+A newline alone acts as a null command list.
+A single
+.Ql &
+repeats the last non-null command list.
+.It H
+Toggle the printing of error explanations.
+By default, explanations are not printed.
+It is recommended that ed scripts begin with this command to
+aid in debugging.
+.It h
+Print an explanation of the last error.
+.It (.)i
+Insert text in the buffer before the current line.
+Text is entered in input mode.
+The current address is set to the last line entered.
+.It (.,.+1)j
+Join the addressed lines.
+The addressed lines are
+deleted from the buffer and replaced by a single
+line containing their joined text.
+The current address is set to the resultant line.
+.It (.)klc
+Mark a line with a lower case letter
+.Em lc .
+The line can then be addressed as
+.Em 'lc
+(i.e., a single quote followed by
+.Em lc )
+in subsequent commands.
+The mark is not cleared until the line is
+deleted or otherwise modified.
+.It (.,.)l
+Print the addressed lines unambiguously.
+If a single line fills for than one screen (as might be the case
+when viewing a binary file, for instance), a
+.Dq Li --More--
+prompt is printed on the last line.
+The
+.Nm
+utility waits until the RETURN key is pressed
+before displaying the next screen.
+The current address is set to the last line
+printed.
+.It (.,.)m(.)
+Move lines in the buffer.
+The addressed lines are moved to after the
+right-hand destination address, which may be the address
+.Em 0
+(zero).
+The current address is set to the
+last line moved.
+.It (.,.)n
+Print the addressed lines along with
+their line numbers.
+The current address is set to the last line
+printed.
+.It (.,.)p
+Print the addressed lines.
+The current address is set to the last line
+printed.
+.It P
+Toggle the command prompt on and off.
+Unless a prompt was specified by with command-line option
+.Fl p Ar string ,
+the command prompt is by default turned off.
+.It q
+Quit
+.Nm .
+.It Q
+Quit
+.Nm
+unconditionally.
+This is similar to the
+.Em q
+command,
+except that unwritten changes are discarded without warning.
+.It ($)r Ar file
+Read
+.Ar file
+to after the addressed line.
+If
+.Ar file
+is not specified, then the default
+filename is used.
+If there was no default filename prior to the command,
+then the default filename is set to
+.Ar file .
+Otherwise, the default filename is unchanged.
+The current address is set to the last line read.
+.It ($)r Ar !command
+Read
+to after the addressed line
+the standard output of
+.Ar !command ,
+(see the
+.Ar !command
+below).
+The default filename is unchanged.
+The current address is set to the last line read.
+.It (.,.)s/re/replacement/
+.It (.,.)s/re/replacement/g
+.It (.,.)s/re/replacement/n
+Replace text in the addressed lines
+matching a regular expression
+.Ar re
+with
+.Ar replacement .
+By default, only the first match in each line is replaced.
+If the
+.Em g
+(global) suffix is given, then every match to be replaced.
+The
+.Em n
+suffix, where
+.Em n
+is a positive number, causes only the
+.Em n Ns th
+match to be replaced.
+It is an error if no substitutions are performed on any of the addressed
+lines.
+The current address is set the last line affected.
+.Pp
+.Ar Re
+and
+.Ar replacement
+may be delimited by any character other than space and newline
+(see the
+.Em s
+command below).
+If one or two of the last delimiters is omitted, then the last line
+affected is printed as though the print suffix
+.Em p
+were specified.
+.Pp
+An unescaped
+.Ql &
+in
+.Ar replacement
+is replaced by the currently matched text.
+The character sequence
+.Em \em ,
+where
+.Em m
+is a number in the range [1,9], is replaced by the
+.Em m th
+backreference expression of the matched text.
+If
+.Ar replacement
+consists of a single
+.Ql % ,
+then
+.Ar replacement
+from the last substitution is used.
+Newlines may be embedded in
+.Ar replacement
+if they are escaped with a backslash (\\).
+.It (.,.)s
+Repeat the last substitution.
+This form of the
+.Em s
+command accepts a count suffix
+.Em n ,
+or any combination of the characters
+.Em r ,
+.Em g ,
+and
+.Em p .
+If a count suffix
+.Em n
+is given, then only the
+.Em n Ns th
+match is replaced.
+The
+.Em r
+suffix causes
+the regular expression of the last search to be used instead of the
+that of the last substitution.
+The
+.Em g
+suffix toggles the global suffix of the last substitution.
+The
+.Em p
+suffix toggles the print suffix of the last substitution
+The current address is set to the last line affected.
+.It (.,.)t(.)
+Copy (i.e., transfer) the addressed lines to after the right-hand
+destination address, which may be the address
+.Em 0
+(zero).
+The current address is set to the last line
+copied.
+.It u
+Undo the last command and restores the current address
+to what it was before the command.
+The global commands
+.Em g ,
+.Em G ,
+.Em v ,
+and
+.Em V .
+are treated as a single command by undo.
+.Em u
+is its own inverse.
+.It (1,$)v/re/command-list
+Apply
+.Ar command-list
+to each of the addressed lines not matching a regular expression
+.Ar re .
+This is similar to the
+.Em g
+command.
+.It (1,$)V/re/
+Interactively edit the addressed lines not matching a regular expression
+.Ar re .
+This is similar to the
+.Em G
+command.
+.It (1,$)w Ar file
+Write the addressed lines to
+.Ar file .
+Any previous contents of
+.Ar file
+is lost without warning.
+If there is no default filename, then the default filename is set to
+.Ar file ,
+otherwise it is unchanged.
+If no filename is specified, then the default
+filename is used.
+The current address is unchanged.
+.It (1,$)wq Ar file
+Write the addressed lines to
+.Ar file ,
+and then executes a
+.Em q
+command.
+.It (1,$)w Ar !command
+Write the addressed lines to the standard input of
+.Ar !command ,
+(see the
+.Em !command
+below).
+The default filename and current address are unchanged.
+.It (1,$)W Ar file
+Append the addressed lines to the end of
+.Ar file .
+This is similar to the
+.Em w
+command, expect that the previous contents of file is not clobbered.
+The current address is unchanged.
+.It x
+Prompt for an encryption key which is used in subsequent reads and
+writes.
+If a newline alone is entered as the key, then encryption is
+turned off.
+Otherwise, echoing is disabled while a key is read.
+Unsupported on Mac OS X.
+.It Pf (.+1)z n
+Scroll
+.Ar n
+lines at a time starting at addressed line.
+If
+.Ar n
+is not specified, then the current window size is used.
+The current address is set to the last line printed.
+.It !command
+Execute
+.Ar command
+via
+.Xr sh 1 .
+If the first character of
+.Ar command
+is
+.Ql \&! ,
+then it is replaced by text of the
+previous
+.Ar !command .
+The
+.Nm
+utility does not process
+.Ar command
+for backslash (\\) escapes.
+However, an unescaped
+.Em %
+is replaced by the default filename.
+When the shell returns from execution, a
+.Ql \&!
+is printed to the standard output.
+The current line is unchanged.
+.It ($)=
+Print the line number of the addressed line.
+.It (.+1)newline
+Print the addressed line, and sets the current address to
+that line.
+.El
+.Sh FILES
+.Bl -tag -width /tmp/ed.* -compact
+.It /tmp/ed.*
+buffer file
+.It ed.hup
+the file to which
+.Nm
+attempts to write the buffer if the terminal hangs up
+.El
+.Sh DIAGNOSTICS
+When an error occurs,
+.Nm
+prints a
+.Ql \&?
+and either returns to command mode
+or exits if its input is from a script.
+An explanation of the last error can be
+printed with the
+.Em h
+(help) command.
+.Pp
+Since the
+.Em g
+(global) command masks any errors from failed searches and substitutions,
+it can be used to perform conditional operations in scripts; e.g.,
+.Pp
+.Sm off
+.Cm g No / Em old Xo
+.No / Cm s
+.No // Em new
+.No /
+.Xc
+.Sm on
+.Pp
+replaces any occurrences of
+.Em old
+with
+.Em new .
+If the
+.Em u
+(undo) command occurs in a global command list, then
+the command list is executed only once.
+.Pp
+If diagnostics are not disabled, attempting to quit
+.Nm
+or edit another file before writing a modified buffer
+results in an error.
+If the command is entered a second time, it succeeds,
+but any changes to the buffer are lost.
+.Sh SEE ALSO
+.Xr sed 1 ,
+.Xr sh 1 ,
+.Xr vi 1 ,
+.Xr regex 3 ,
+.Xr compat 5
+.Pp
+USD:12-13
+.Rs
+.%A B. W. Kernighan
+.%A P. J. Plauger
+.%B Software Tools in Pascal
+.%O Addison-Wesley
+.%D 1981
+.Re
+.Sh LIMITATIONS
+The
+.Nm
+utility processes
+.Ar file
+arguments for backslash escapes, i.e., in a filename,
+any characters preceded by a backslash (\\) are
+interpreted literally.
+.Pp
+If a text (non-binary) file is not terminated by a newline character,
+then
+.Nm
+appends one on reading/writing it.
+In the case of a binary file,
+.Nm
+does not append a newline on reading/writing.
+.Pp
+per line overhead: 4 ints
+.Sh HISTORY
+An
+.Nm
+command appeared in
+Version 1 AT&T UNIX.
+.Sh BUGS
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/text_cmds/ed/ed.h b/text_cmds/ed/ed.h
new file mode 100644
index 0000000..f35a001
--- /dev/null
+++ b/text_cmds/ed/ed.h
@@ -0,0 +1,282 @@
+/* ed.h: type and constant definitions for the ed editor. */
+/*-
+ * Copyright (c) 1993 Andrew Moore
+ * 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 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.
+ *
+ * @(#)ed.h,v 1.5 1994/02/01 00:34:39 alm Exp
+ * $FreeBSD: src/bin/ed/ed.h,v 1.20 2005/01/10 08:39:22 imp Exp $
+ */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <limits.h>
+#include <regex.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define ERR (-2)
+#define EMOD (-3)
+#define FATAL (-4)
+
+#define MINBUFSZ 512 /* minimum buffer size - must be > 0 */
+#define SE_MAX 30 /* max subexpressions in a regular expression */
+#ifdef INT_MAX
+# define LINECHARS INT_MAX /* max chars per line */
+#else
+# define LINECHARS MAXINT /* max chars per line */
+#endif
+
+/* gflags */
+#define GLB 001 /* global command */
+#define GPR 002 /* print after command */
+#define GLS 004 /* list after command */
+#define GNP 010 /* enumerate after command */
+#define GSG 020 /* global substitute */
+#define GINT 040 /* interactive cmd: G or V */
+
+typedef regex_t pattern_t;
+
+/* Line node */
+typedef struct line {
+ struct line *q_forw;
+ struct line *q_back;
+ off_t seek; /* address of line in scratch buffer */
+ int len; /* length of line */
+} line_t;
+
+
+typedef struct undo {
+
+/* type of undo nodes */
+#define UADD 0
+#define UDEL 1
+#define UMOV 2
+#define VMOV 3
+
+ int type; /* command type */
+ line_t *h; /* head of list */
+ line_t *t; /* tail of list */
+} undo_t;
+
+#ifndef max
+# define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+#ifndef min
+# define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define INC_MOD(l, k) ((l) + 1 > (k) ? 0 : (l) + 1)
+#define DEC_MOD(l, k) ((l) - 1 < 0 ? (k) : (l) - 1)
+
+/* SPL1: disable some interrupts (requires reliable signals) */
+#define SPL1() mutex++
+
+/* SPL0: enable all interrupts; check sigflags (requires reliable signals) */
+#define SPL0() \
+if (--mutex == 0) { \
+ if (sigflags & (1 << (SIGHUP - 1))) handle_hup(SIGHUP); \
+ if (sigflags & (1 << (SIGINT - 1))) handle_int(SIGINT); \
+}
+
+/* STRTOL: convert a string to long */
+#define STRTOL(i, p) { \
+ if (((i = strtol(p, &p, 10)) == LONG_MIN || i == LONG_MAX) && \
+ errno == ERANGE) { \
+ errmsg = "number out of range"; \
+ i = 0; \
+ return ERR; \
+ } \
+}
+
+#if defined(sun) || defined(NO_REALLOC_NULL)
+/* REALLOC: assure at least a minimum size for buffer b */
+#define REALLOC(b,n,i,err) \
+if ((i) > (n)) { \
+ int ti = (n); \
+ char *ts; \
+ SPL1(); \
+ if ((b) != NULL) { \
+ if ((ts = (char *) realloc((b), ti += max((i), MINBUFSZ))) == NULL) { \
+ fprintf(stderr, "%s\n", strerror(errno)); \
+ errmsg = "out of memory"; \
+ SPL0(); \
+ return err; \
+ } \
+ } else { \
+ if ((ts = (char *) malloc(ti += max((i), MINBUFSZ))) == NULL) { \
+ fprintf(stderr, "%s\n", strerror(errno)); \
+ errmsg = "out of memory"; \
+ SPL0(); \
+ return err; \
+ } \
+ } \
+ (n) = ti; \
+ (b) = ts; \
+ SPL0(); \
+}
+#else /* NO_REALLOC_NULL */
+/* REALLOC: assure at least a minimum size for buffer b */
+#define REALLOC(b,n,i,err) \
+if ((i) > (n)) { \
+ int ti = (n); \
+ char *ts; \
+ SPL1(); \
+ if ((ts = (char *) realloc((b), ti += max((i), MINBUFSZ))) == NULL) { \
+ fprintf(stderr, "%s\n", strerror(errno)); \
+ errmsg = "out of memory"; \
+ SPL0(); \
+ return err; \
+ } \
+ (n) = ti; \
+ (b) = ts; \
+ SPL0(); \
+}
+#endif /* NO_REALLOC_NULL */
+
+/* REQUE: link pred before succ */
+#define REQUE(pred, succ) (pred)->q_forw = (succ), (succ)->q_back = (pred)
+
+/* INSQUE: insert elem in circular queue after pred */
+#define INSQUE(elem, pred) \
+{ \
+ REQUE((elem), (pred)->q_forw); \
+ REQUE((pred), elem); \
+}
+
+/* REMQUE: remove_lines elem from circular queue */
+#define REMQUE(elem) REQUE((elem)->q_back, (elem)->q_forw);
+
+/* NUL_TO_NEWLINE: overwrite ASCII NULs with newlines */
+#define NUL_TO_NEWLINE(s, l) translit_text(s, l, '\0', '\n')
+
+/* NEWLINE_TO_NUL: overwrite newlines with ASCII NULs */
+#define NEWLINE_TO_NUL(s, l) translit_text(s, l, '\n', '\0')
+
+#ifdef ED_DES_INCLUDES
+void des_error(const char *);
+void expand_des_key(char *, char *);
+void set_des_key(DES_cblock *);
+#endif
+
+/* Other DES support stuff */
+void init_des_cipher(void);
+int flush_des_file(FILE *);
+int get_des_char(FILE *);
+int put_des_char(int, FILE *);
+
+/* Local Function Declarations */
+void add_line_node(line_t *);
+int append_lines(long);
+int apply_subst_template(const char *, regmatch_t *, int, int);
+int build_active_list(int);
+int cbc_decode(unsigned char *, FILE *);
+int cbc_encode(unsigned char *, int, FILE *);
+int check_addr_range(long, long);
+void clear_active_list(void);
+void clear_undo_stack(void);
+int close_sbuf(void);
+int copy_lines(long);
+int delete_lines(long, long);
+int display_lines(long, long, int);
+line_t *dup_line_node(line_t *);
+int exec_command(void);
+long exec_global(int, int);
+int extract_addr_range(void);
+char *extract_pattern(int);
+int extract_subst_tail(int *, long *);
+char *extract_subst_template(void);
+int filter_lines(long, long, char *);
+line_t *get_addressed_line_node(long);
+pattern_t *get_compiled_pattern(void);
+char *get_extended_line(int *, int);
+char *get_filename(void);
+int get_keyword(void);
+long get_line_node_addr(line_t *);
+long get_matching_node_addr(pattern_t *, int);
+long get_marked_node_addr(int);
+char *get_sbuf_line(line_t *);
+int get_shell_command(void);
+int get_stream_line(FILE *);
+int get_tty_line(void);
+void handle_hup(int);
+void handle_int(int);
+void handle_winch(int);
+int has_trailing_escape(char *, char *);
+int hex_to_binary(int, int);
+void init_buffers(void);
+int is_legal_filename(char *);
+int join_lines(long, long);
+int mark_line_node(line_t *, int);
+int move_lines(long);
+line_t *next_active_node(void);
+long next_addr(void);
+int open_sbuf(void);
+char *parse_char_class(char *);
+int pop_undo_stack(void);
+undo_t *push_undo_stack(int, long, long);
+const char *put_sbuf_line(const char *);
+int put_stream_line(FILE *, const char *, int);
+int put_tty_line(const char *, int, long, int);
+void quit(int);
+long read_file(char *, long);
+long read_stream(FILE *, long);
+void replace_marks(line_t *, line_t *);
+int search_and_replace(pattern_t *, int, int);
+int set_active_node(line_t *);
+void signal_hup(int);
+void signal_int(int);
+char *strip_escapes(char *);
+int substitute_matching_text(pattern_t *, line_t *, int, int);
+char *translit_text(char *, int, int, int);
+void unmark_line_node(line_t *);
+void unset_active_nodes(line_t *, line_t *);
+long write_file(char *, const char *, long, long);
+long write_stream(FILE *, long, long);
+
+/* global buffers */
+extern char stdinbuf[];
+extern char *ibuf;
+extern char *ibufp;
+extern int ibufsz;
+
+/* global flags */
+extern int isbinary;
+extern int isglobal;
+extern int modified;
+extern int mutex;
+extern int sigflags;
+
+/* global vars */
+extern long addr_last;
+extern long current_addr;
+extern const char *errmsg;
+extern long first_addr;
+extern int lineno;
+extern long second_addr;
+extern long u_addr_last;
+extern long u_current_addr;
+extern int posixly_correct;
diff --git a/text_cmds/ed/glbl.c b/text_cmds/ed/glbl.c
new file mode 100644
index 0000000..9c6799c
--- /dev/null
+++ b/text_cmds/ed/glbl.c
@@ -0,0 +1,218 @@
+/* glob.c: This file contains the global command routines for the ed line
+ editor */
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ed/glbl.c,v 1.13 2002/06/30 05:13:53 obrien Exp $");
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+
+#include "ed.h"
+
+
+/* build_active_list: add line matching a pattern to the global-active list */
+int
+build_active_list(int isgcmd)
+{
+ pattern_t *pat;
+ line_t *lp;
+ long n;
+ char *s;
+ char delimiter;
+
+ if ((delimiter = *ibufp) == ' ' || delimiter == '\n') {
+ errmsg = "invalid pattern delimiter";
+ return ERR;
+ } else if ((pat = get_compiled_pattern()) == NULL)
+ return ERR;
+ else if (*ibufp == delimiter)
+ ibufp++;
+ clear_active_list();
+ lp = get_addressed_line_node(first_addr);
+ for (n = first_addr; n <= second_addr; n++, lp = lp->q_forw) {
+ if ((s = get_sbuf_line(lp)) == NULL)
+ return ERR;
+ if (isbinary)
+ NUL_TO_NEWLINE(s, lp->len);
+ if (!regexec(pat, s, 0, NULL, 0) == isgcmd &&
+ set_active_node(lp) < 0)
+ return ERR;
+ }
+ return 0;
+}
+
+
+/* exec_global: apply command list in the command buffer to the active
+ lines in a range; return command status */
+long
+exec_global(int interact, int gflag)
+{
+ static char *ocmd = NULL;
+ static int ocmdsz = 0;
+
+ line_t *lp = NULL;
+ int status;
+ int n;
+ char *cmd = NULL;
+
+ if (!interact) {
+ if (posixly_correct) {
+ if ((cmd = get_extended_line(&n, 0)) == NULL)
+ return ERR;
+ } else if (!strcmp(ibufp, "\n"))
+ cmd = "p\n"; /* null cmd-list == `p' */
+ else if ((cmd = get_extended_line(&n, 0)) == NULL)
+ return ERR;
+ }
+ clear_undo_stack();
+ while ((lp = next_active_node()) != NULL) {
+ if ((current_addr = get_line_node_addr(lp)) < 0)
+ return ERR;
+ if (interact) {
+ /* print current_addr; get a command in global syntax */
+ gflag |= GINT;
+ if (display_lines(current_addr, current_addr, gflag) < 0)
+ return ERR;
+ while ((n = get_tty_line()) > 0 &&
+ ibuf[n - 1] != '\n')
+ clearerr(stdin);
+ if (n < 0)
+ return ERR;
+ else if (n == 0) {
+ errmsg = "unexpected end-of-file";
+ return ERR;
+ } else if (n == 1 && !strcmp(ibuf, "\n"))
+ continue;
+ else if (n == 2 && !strcmp(ibuf, "&\n")) {
+ if (cmd == NULL) {
+ errmsg = "no previous command";
+ return ERR;
+ } else cmd = ocmd;
+ } else if ((cmd = get_extended_line(&n, 0)) == NULL)
+ return ERR;
+ else {
+ REALLOC(ocmd, ocmdsz, n + 1, ERR);
+ memcpy(ocmd, cmd, n + 1);
+ cmd = ocmd;
+ }
+
+ }
+ ibufp = cmd;
+ for (; *ibufp;)
+ if ((status = extract_addr_range()) < 0 ||
+ (status = exec_command()) < 0 ||
+ (status > 0 && (status = display_lines(
+ current_addr, current_addr, status)) < 0))
+ return status;
+ }
+ return 0;
+}
+
+
+line_t **active_list; /* list of lines active in a global command */
+long active_last; /* index of last active line in active_list */
+long active_size; /* size of active_list */
+long active_ptr; /* active_list index (non-decreasing) */
+long active_ndx; /* active_list index (modulo active_last) */
+
+/* set_active_node: add a line node to the global-active list */
+int
+set_active_node(line_t *lp)
+{
+ if (active_last + 1 > active_size) {
+ int ti = active_size;
+ line_t **ts;
+ SPL1();
+#if defined(sun) || defined(NO_REALLOC_NULL)
+ if (active_list != NULL) {
+#endif
+ if ((ts = (line_t **) realloc(active_list,
+ (ti += MINBUFSZ) * sizeof(line_t **))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ SPL0();
+ return ERR;
+ }
+#if defined(sun) || defined(NO_REALLOC_NULL)
+ } else {
+ if ((ts = (line_t **) malloc((ti += MINBUFSZ) *
+ sizeof(line_t **))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ SPL0();
+ return ERR;
+ }
+ }
+#endif
+ active_size = ti;
+ active_list = ts;
+ SPL0();
+ }
+ active_list[active_last++] = lp;
+ return 0;
+}
+
+
+/* unset_active_nodes: remove a range of lines from the global-active list */
+void
+unset_active_nodes(line_t *np, line_t *mp)
+{
+ line_t *lp;
+ long i;
+
+ for (lp = np; lp != mp; lp = lp->q_forw)
+ for (i = 0; i < active_last; i++)
+ if (active_list[active_ndx] == lp) {
+ active_list[active_ndx] = NULL;
+ active_ndx = INC_MOD(active_ndx, active_last - 1);
+ break;
+ } else active_ndx = INC_MOD(active_ndx, active_last - 1);
+}
+
+
+/* next_active_node: return the next global-active line node */
+line_t *
+next_active_node(void)
+{
+ while (active_ptr < active_last && active_list[active_ptr] == NULL)
+ active_ptr++;
+ return (active_ptr < active_last) ? active_list[active_ptr++] : NULL;
+}
+
+
+/* clear_active_list: clear the global-active list */
+void
+clear_active_list(void)
+{
+ SPL1();
+ active_size = active_last = active_ptr = active_ndx = 0;
+ free(active_list);
+ active_list = NULL;
+ SPL0();
+}
diff --git a/text_cmds/ed/io.c b/text_cmds/ed/io.c
new file mode 100644
index 0000000..ba8e682
--- /dev/null
+++ b/text_cmds/ed/io.c
@@ -0,0 +1,341 @@
+/* io.c: This file contains the i/o routines for the ed line editor */
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ed/io.c,v 1.14 2003/01/01 18:48:39 schweikh Exp $");
+
+#include "ed.h"
+
+
+extern int scripted;
+
+/* read_file: read a named file/pipe into the buffer; return line count */
+long
+read_file(char *fn, long n)
+{
+ FILE *fp;
+ long size;
+
+
+ fp = (*fn == '!') ? popen(fn + 1, "r") : fopen(strip_escapes(fn), "r");
+ if (fp == NULL) {
+ fprintf(stderr, "%s: %s\n", fn, strerror(errno));
+ errmsg = "cannot open input file";
+ return ERR;
+ } else if ((size = read_stream(fp, n)) < 0)
+ return ERR;
+ else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
+ fprintf(stderr, "%s: %s\n", fn, strerror(errno));
+ errmsg = "cannot close input file";
+ return ERR;
+ }
+ fprintf(stdout, !scripted ? "%lu\n" : "", size);
+ return current_addr - n;
+}
+
+
+extern int des;
+
+char *sbuf; /* file i/o buffer */
+int sbufsz; /* file i/o buffer size */
+int newline_added; /* if set, newline appended to input file */
+
+/* read_stream: read a stream into the editor buffer; return status */
+long
+read_stream(FILE *fp, long n)
+{
+ line_t *lp = get_addressed_line_node(n);
+ undo_t *up = NULL;
+ unsigned long size = 0;
+ int o_newline_added = newline_added;
+ int o_isbinary = isbinary;
+ int appended = (n == addr_last);
+ int len;
+
+ isbinary = newline_added = 0;
+ if (des)
+ init_des_cipher();
+ for (current_addr = n; (len = get_stream_line(fp)) > 0; size += len) {
+ SPL1();
+ if (put_sbuf_line(sbuf) == NULL) {
+ SPL0();
+ return ERR;
+ }
+ lp = lp->q_forw;
+ if (up)
+ up->t = lp;
+ else if ((up = push_undo_stack(UADD, current_addr,
+ current_addr)) == NULL) {
+ SPL0();
+ return ERR;
+ }
+ SPL0();
+ }
+ if (len < 0)
+ return ERR;
+ if (appended && size && o_isbinary && o_newline_added)
+ fputs("newline inserted\n", stderr);
+ else if (newline_added && (!appended || (!isbinary && !o_isbinary)))
+ fputs("newline appended\n", stderr);
+ if (isbinary && newline_added && !appended)
+ size += 1;
+ if (!size)
+ newline_added = 1;
+ newline_added = appended ? newline_added : o_newline_added;
+ isbinary = isbinary | o_isbinary;
+ if (des)
+ size += 8 - size % 8; /* adjust DES size */
+ return size;
+}
+
+
+/* get_stream_line: read a line of text from a stream; return line length */
+int
+get_stream_line(FILE *fp)
+{
+ int c;
+ int i = 0;
+
+ while (((c = des ? get_des_char(fp) : getc(fp)) != EOF || (!feof(fp) &&
+ !ferror(fp))) && c != '\n') {
+ REALLOC(sbuf, sbufsz, i + 1, ERR);
+ if (!(sbuf[i++] = c))
+ isbinary = 1;
+ }
+ REALLOC(sbuf, sbufsz, i + 2, ERR);
+ if (c == '\n')
+ sbuf[i++] = c;
+ else if (ferror(fp)) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot read input file";
+ return ERR;
+ } else if (i) {
+ sbuf[i++] = '\n';
+ newline_added = 1;
+ }
+ sbuf[i] = '\0';
+ return (isbinary && newline_added && i) ? --i : i;
+}
+
+
+/* write_file: write a range of lines to a named file/pipe; return line count */
+long
+write_file(char *fn, const char *mode, long n, long m)
+{
+ FILE *fp;
+ long size;
+
+ fp = (*fn == '!') ? popen(fn+1, "w") : fopen(strip_escapes(fn), mode);
+ if (fp == NULL) {
+ fprintf(stderr, "%s: %s\n", fn, strerror(errno));
+ errmsg = "cannot open output file";
+ return ERR;
+ } else if ((size = write_stream(fp, n, m)) < 0)
+ return ERR;
+ else if (((*fn == '!') ? pclose(fp) : fclose(fp)) < 0) {
+ fprintf(stderr, "%s: %s\n", fn, strerror(errno));
+ errmsg = "cannot close output file";
+ return ERR;
+ }
+ fprintf(stdout, !scripted ? "%lu\n" : "", size);
+ return n ? m - n + 1 : 0;
+}
+
+
+/* write_stream: write a range of lines to a stream; return status */
+long
+write_stream(FILE *fp, long n, long m)
+{
+ line_t *lp = get_addressed_line_node(n);
+ unsigned long size = 0;
+ char *s;
+ int len;
+
+ if (des)
+ init_des_cipher();
+ for (; n && n <= m; n++, lp = lp->q_forw) {
+ if ((s = get_sbuf_line(lp)) == NULL)
+ return ERR;
+ len = lp->len;
+ if (n != addr_last || !isbinary || !newline_added)
+ s[len++] = '\n';
+ if (put_stream_line(fp, s, len) < 0)
+ return ERR;
+ size += len;
+ }
+ if (des) {
+ flush_des_file(fp); /* flush buffer */
+ size += 8 - size % 8; /* adjust DES size */
+ }
+ return size;
+}
+
+
+/* put_stream_line: write a line of text to a stream; return status */
+int
+put_stream_line(FILE *fp, const char *s, int len)
+{
+ while (len--)
+ if ((des ? put_des_char(*s++, fp) : fputc(*s++, fp)) < 0) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "cannot write file";
+ return ERR;
+ }
+ return 0;
+}
+
+/* get_extended_line: get an extended line from stdin */
+char *
+get_extended_line(int *sizep, int nonl)
+{
+ static char *cvbuf = NULL; /* buffer */
+ static int cvbufsz = 0; /* buffer size */
+
+ int l, n;
+ char *t = ibufp;
+
+ while (*t++ != '\n')
+ ;
+ if ((l = t - ibufp) < 2 || !has_trailing_escape(ibufp, ibufp + l - 1)) {
+ *sizep = l;
+ return ibufp;
+ }
+ *sizep = -1;
+ REALLOC(cvbuf, cvbufsz, l, NULL);
+ memcpy(cvbuf, ibufp, l);
+ *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
+ if (nonl) l--; /* strip newline */
+ for (;;) {
+ if ((n = get_tty_line()) < 0)
+ return NULL;
+ else if (n == 0 || ibuf[n - 1] != '\n') {
+ errmsg = "unexpected end-of-file";
+ return NULL;
+ }
+ REALLOC(cvbuf, cvbufsz, l + n, NULL);
+ memcpy(cvbuf + l, ibuf, n);
+ l += n;
+ if (n < 2 || !has_trailing_escape(cvbuf, cvbuf + l - 1))
+ break;
+ *(cvbuf + --l - 1) = '\n'; /* strip trailing esc */
+ if (nonl) l--; /* strip newline */
+ }
+ REALLOC(cvbuf, cvbufsz, l + 1, NULL);
+ cvbuf[l] = '\0';
+ *sizep = l;
+ return cvbuf;
+}
+
+
+/* get_tty_line: read a line of text from stdin; return line length */
+int
+get_tty_line(void)
+{
+ int oi = 0;
+ int i = 0;
+ int c;
+
+ for (;;)
+ switch (c = getchar()) {
+ default:
+ oi = 0;
+ REALLOC(ibuf, ibufsz, i + 2, ERR);
+ if (!(ibuf[i++] = c)) isbinary = 1;
+ if (c != '\n')
+ continue;
+ lineno++;
+ ibuf[i] = '\0';
+ ibufp = ibuf;
+ return i;
+ case EOF:
+ if (ferror(stdin)) {
+ fprintf(stderr, "stdin: %s\n", strerror(errno));
+ errmsg = "cannot read stdin";
+ clearerr(stdin);
+ ibufp = NULL;
+ return ERR;
+ } else {
+ clearerr(stdin);
+ if (i != oi) {
+ oi = i;
+ continue;
+ } else if (i)
+ ibuf[i] = '\0';
+ ibufp = ibuf;
+ return i;
+ }
+ }
+}
+
+
+
+#define ESCAPES "\a\b\f\n\r\t\v\\"
+#define ESCCHARS "abfnrtv\\"
+
+extern int rows;
+extern int cols;
+
+/* put_tty_line: print text to stdout */
+int
+put_tty_line(const char *s, int l, long n, int gflag)
+{
+ int col = 0;
+ char *cp;
+
+ if ((gflag & GNP) && !(gflag & GINT)) {
+ printf("%ld\t", n);
+ col = 8;
+ }
+ for (; l--; s++) {
+ if ((gflag & GLS) && ++col > cols) {
+ fputs("\\\n", stdout);
+ col = 1;
+ }
+ if (gflag & GLS) {
+ if (31 < *s && *s < 127 && *s != '\\')
+ putchar(*s);
+ else {
+ putchar('\\');
+ col++;
+ if (*s && (cp = strchr(ESCAPES, *s)) != NULL)
+ putchar(ESCCHARS[cp - ESCAPES]);
+ else {
+ putchar((((unsigned char) *s & 0300) >> 6) + '0');
+ putchar((((unsigned char) *s & 070) >> 3) + '0');
+ putchar(((unsigned char) *s & 07) + '0');
+ col += 2;
+ }
+ }
+
+ } else
+ putchar(*s);
+ }
+ if (posixly_correct && (gflag & GLS) && !(gflag & GINT))
+ putchar('$');
+ putchar('\n');
+ return 0;
+}
diff --git a/text_cmds/ed/main.c b/text_cmds/ed/main.c
new file mode 100644
index 0000000..0747c54
--- /dev/null
+++ b/text_cmds/ed/main.c
@@ -0,0 +1,1455 @@
+/* main.c: This file contains the main control and user-interface routines
+ for the ed line editor. */
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * 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.
+ */
+
+#ifndef lint
+#if 0
+static const char copyright[] =
+"@(#) Copyright (c) 1993 Andrew Moore, Talke Studio. \n\
+ All rights reserved.\n";
+#endif
+#endif /* not lint */
+
+/*
+ * CREDITS
+ *
+ * This program is based on the editor algorithm described in
+ * Brian W. Kernighan and P. J. Plauger's book "Software Tools
+ * in Pascal," Addison-Wesley, 1981.
+ *
+ * The buffering algorithm is attributed to Rodney Ruddock of
+ * the University of Guelph, Guelph, Ontario.
+ *
+ * The cbc.c encryption code is adapted from
+ * the bdes program by Matt Bishop of Dartmouth College,
+ * Hanover, NH.
+ *
+ */
+
+#include <sys/types.h>
+
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <locale.h>
+#include <pwd.h>
+#include <setjmp.h>
+
+#ifdef __APPLE__
+#include <get_compat.h>
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+#include "ed.h"
+
+
+#ifdef _POSIX_SOURCE
+sigjmp_buf env;
+#else
+jmp_buf env;
+#endif
+
+/* static buffers */
+char stdinbuf[1]; /* stdin buffer */
+char *shcmd; /* shell command buffer */
+int shcmdsz; /* shell command buffer size */
+int shcmdi; /* shell command buffer index */
+char *ibuf; /* ed command-line buffer */
+int ibufsz; /* ed command-line buffer size */
+char *ibufp; /* pointer to ed command-line buffer */
+
+/* global flags */
+int des = 0; /* if set, use crypt(3) for i/o */
+int garrulous = 0; /* if set, print all error messages */
+int isbinary; /* if set, buffer contains ASCII NULs */
+int isglobal; /* if set, doing a global command */
+int modified; /* if set, buffer modified since last write */
+int mutex = 0; /* if set, signals set "sigflags" */
+int red = 0; /* if set, restrict shell/directory access */
+int scripted = 0; /* if set, suppress diagnostics */
+int sigflags = 0; /* if set, signals received while mutex set */
+int sigactive = 0; /* if set, signal handlers are enabled */
+int posixly_correct = 0; /* if set, POSIX behavior as per */
+/* http://www.opengroup.org/onlinepubs/009695399/utilities/ed.html */
+
+char old_filename[PATH_MAX + 1] = ""; /* default filename */
+long current_addr; /* current address in editor buffer */
+long addr_last; /* last address in editor buffer */
+int lineno; /* script line number */
+const char *prompt; /* command-line prompt */
+const char *dps = "*"; /* default command-line prompt */
+
+const char usage[] = "usage: %s [-] [-sx] [-p string] [file]\n";
+
+/* ed: line editor */
+int
+main(int argc, char *argv[])
+{
+ int c, n;
+ long status = 0;
+#if __GNUC__
+ /* Avoid longjmp clobbering */
+ (void) &argc;
+ (void) &argv;
+#endif
+
+ (void)setlocale(LC_ALL, "");
+
+ posixly_correct = COMPAT_MODE("bin/ed", "Unix2003");
+
+ red = argv[0]!=NULL && (n = strlen(argv[0])) > 2 && argv[0][n - 3] == 'r';
+top:
+ while ((c = getopt(argc, argv, "p:sx")) != -1)
+ switch(c) {
+ case 'p': /* set prompt */
+ prompt = optarg;
+ break;
+ case 's': /* run script */
+ scripted = 1;
+ break;
+ case 'x': /* use crypt */
+#ifdef DES
+ des = get_keyword();
+#else
+ fprintf(stderr, "crypt unavailable\n?\n");
+#endif
+ break;
+
+ default:
+ fprintf(stderr, usage, red ? "red" : "ed");
+ exit(1);
+ }
+ argv += optind;
+ argc -= optind;
+ if (argc>0 && *argv && !strcmp(*argv, "-")) {
+ scripted = 1;
+ if (argc > 1) {
+ optind = 1;
+ goto top;
+ }
+ argv++;
+ argc--;
+ }
+ /* assert: reliable signals! */
+#ifdef SIGWINCH
+ handle_winch(SIGWINCH);
+ if (isatty(0)) signal(SIGWINCH, handle_winch);
+#endif
+ signal(SIGHUP, signal_hup);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGINT, signal_int);
+#ifdef _POSIX_SOURCE
+ if ((status = sigsetjmp(env, 1)))
+#else
+ if ((status = setjmp(env)))
+#endif
+ {
+ fputs("\n?\n", stderr);
+ errmsg = "interrupt";
+ } else {
+ init_buffers();
+ sigactive = 1; /* enable signal handlers */
+ if (argc>0 && *argv && is_legal_filename(*argv)) {
+ if (read_file(*argv, 0) < 0 && !isatty(0))
+ quit(2);
+ else if (**argv != '!') {
+ if (strlen(*argv) < sizeof(old_filename)) {
+ strcpy(old_filename, *argv);
+ } else {
+ fprintf(stderr, "%s: filename too long\n", *argv);
+ quit(2);
+ }
+ }
+ } else if (argc>0) {
+ fputs("?\n", stdout);
+ if (**argv == '\0')
+ errmsg = "invalid filename";
+ if (!isatty(0))
+ quit(2);
+ }
+ }
+ for (;;) {
+ if (status < 0 && garrulous)
+ fprintf(stderr, "%s\n", errmsg);
+ if (prompt) {
+ printf("%s", prompt);
+ fflush(stdout);
+ }
+ if ((n = get_tty_line()) < 0) {
+ status = ERR;
+ continue;
+ } else if (n == 0) {
+ if (modified && !scripted) {
+ fputs("?\n", stderr);
+ errmsg = "warning: file modified";
+ if (!isatty(0)) {
+ fprintf(stderr, garrulous ?
+ "script, line %d: %s\n" :
+ "", lineno, errmsg);
+ quit(2);
+ }
+ clearerr(stdin);
+ modified = 0;
+ status = EMOD;
+ continue;
+ } else
+ quit(0);
+ } else if (ibuf[n - 1] != '\n') {
+ /* discard line */
+ errmsg = "unexpected end-of-file";
+ clearerr(stdin);
+ status = ERR;
+ continue;
+ }
+ isglobal = 0;
+ if ((status = extract_addr_range()) >= 0 &&
+ (status = exec_command()) >= 0)
+ if (!status ||
+ (status = display_lines(current_addr, current_addr,
+ status)) >= 0)
+ continue;
+ switch (status) {
+ case EOF:
+ quit(0);
+ case EMOD:
+ modified = 0;
+ fputs("?\n", stderr); /* give warning */
+ errmsg = "warning: file modified";
+ if (!isatty(0)) {
+ fprintf(stderr, garrulous ?
+ "script, line %d: %s\n" :
+ "", lineno, errmsg);
+ quit(2);
+ }
+ break;
+ case FATAL:
+ if (!isatty(0))
+ fprintf(stderr, garrulous ?
+ "script, line %d: %s\n" : "",
+ lineno, errmsg);
+ else
+ fprintf(stderr, garrulous ? "%s\n" : "",
+ errmsg);
+ quit(3);
+ default:
+ fputs("?\n", stdout);
+ if (!isatty(0)) {
+ fprintf(stderr, garrulous ?
+ "script, line %d: %s\n" : "",
+ lineno, errmsg);
+ quit(2);
+ }
+ break;
+ }
+ }
+ /*NOTREACHED*/
+}
+
+long first_addr, second_addr, addr_cnt;
+
+/* extract_addr_range: get line addresses from the command buffer until an
+ illegal address is seen; return status */
+int
+extract_addr_range(void)
+{
+ long addr;
+
+ addr_cnt = 0;
+ first_addr = second_addr = current_addr;
+ while ((addr = next_addr()) >= 0) {
+ addr_cnt++;
+ first_addr = second_addr;
+ second_addr = addr;
+ if (*ibufp != ',' && *ibufp != ';')
+ break;
+ else if (*ibufp++ == ';')
+ current_addr = addr;
+ }
+ if ((addr_cnt = min(addr_cnt, 2)) == 1 || second_addr != addr)
+ first_addr = second_addr;
+ return (addr == ERR) ? ERR : 0;
+}
+
+
+#define SKIP_BLANKS() while (isspace((unsigned char)*ibufp) && *ibufp != '\n') ibufp++
+
+#define MUST_BE_FIRST() do { \
+ if (!first) { \
+ errmsg = "invalid address"; \
+ return ERR; \
+ } \
+} while (0);
+
+/* next_addr: return the next line address in the command buffer */
+long
+next_addr(void)
+{
+ const char *hd;
+ long addr = current_addr;
+ long n;
+ int first = 1;
+ int c;
+ int add = 0;
+
+ SKIP_BLANKS();
+ for (hd = ibufp;; first = 0)
+ switch (c = *ibufp) {
+ case '+':
+ case '\t':
+ case ' ':
+ case '-':
+ case '^':
+ ibufp++;
+ SKIP_BLANKS();
+ if (isdigit((unsigned char)*ibufp)) {
+ STRTOL(n, ibufp);
+ addr += (c == '-' || c == '^') ? -n : n;
+ } else if (!isspace((unsigned char)c))
+ addr += (c == '-' || c == '^') ? -1 : 1;
+ break;
+ case '0': case '1': case '2':
+ case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ STRTOL(n, ibufp);
+ if (first || !add) /* don't add for ,\d or ;\d */
+ addr = n;
+ else
+ addr += n;
+ break;
+ case '.':
+ case '$':
+ MUST_BE_FIRST();
+ ibufp++;
+ addr = (c == '.') ? current_addr : addr_last;
+ add++;
+ break;
+ case '/':
+ case '?':
+ MUST_BE_FIRST();
+ if ((addr = get_matching_node_addr(
+ get_compiled_pattern(), c == '/')) < 0)
+ return ERR;
+ else if (c == *ibufp)
+ ibufp++;
+ add++;
+ break;
+ case '\'':
+ MUST_BE_FIRST();
+ ibufp++;
+ if ((addr = get_marked_node_addr(*ibufp++)) < 0)
+ return ERR;
+ add++;
+ break;
+ case '%':
+ case ',':
+ case ';':
+ if (first) {
+ ibufp++;
+ addr_cnt++;
+ second_addr = (c == ';') ? current_addr : 1;
+ addr = addr_last;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ if (ibufp == hd)
+ return EOF;
+ else if (addr < 0 || addr_last < addr) {
+ errmsg = "invalid address";
+ return ERR;
+ } else
+ return addr;
+ }
+ /* NOTREACHED */
+}
+
+
+/* GET_THIRD_ADDR: get a legal address from the command buffer */
+#define GET_THIRD_ADDR(addr) \
+{ \
+ long ol1, ol2; \
+\
+ ol1 = first_addr, ol2 = second_addr; \
+ if (extract_addr_range() < 0) \
+ return ERR; \
+ else if (!posixly_correct && addr_cnt == 0) { \
+ errmsg = "destination expected"; \
+ return ERR; \
+ } else if (second_addr < 0 || addr_last < second_addr) { \
+ errmsg = "invalid address"; \
+ return ERR; \
+ } \
+ addr = second_addr; \
+ first_addr = ol1, second_addr = ol2; \
+}
+
+
+/* GET_COMMAND_SUFFIX: verify the command suffix in the command buffer */
+#define GET_COMMAND_SUFFIX() { \
+ int done = 0; \
+ do { \
+ switch(*ibufp) { \
+ case 'p': \
+ gflag |= GPR, ibufp++; \
+ break; \
+ case 'l': \
+ gflag |= GLS, ibufp++; \
+ break; \
+ case 'n': \
+ gflag |= GNP, ibufp++; \
+ break; \
+ default: \
+ done++; \
+ } \
+ } while (!done); \
+ if (*ibufp++ != '\n') { \
+ errmsg = "invalid command suffix"; \
+ return ERR; \
+ } \
+}
+
+
+/* sflags */
+#define SGG 001 /* complement previous global substitute suffix */
+#define SGP 002 /* complement previous print suffix */
+#define SGR 004 /* use last regex instead of last pat */
+#define SGF 010 /* repeat last substitution */
+
+int patlock = 0; /* if set, pattern not freed by get_compiled_pattern() */
+
+long rows = 22; /* scroll length: ws_row - 2 */
+
+/* exec_command: execute the next command in command buffer; return print
+ request, if any */
+int
+exec_command(void)
+{
+ static pattern_t *pat = NULL;
+ static int sgflag = 0;
+ static long sgnum = 0;
+
+ pattern_t *tpat;
+ char *fnp;
+ int gflag = 0;
+ int sflags = 0;
+ long addr = 0;
+ int n = 0;
+ int c;
+
+ SKIP_BLANKS();
+ switch(c = *ibufp++) {
+ case 'a':
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (append_lines(second_addr) < 0)
+ return ERR;
+ break;
+ case 'c':
+ if (first_addr == 0)
+ first_addr = 1;
+ if (check_addr_range(current_addr, current_addr) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (delete_lines(first_addr, second_addr) < 0 ||
+ append_lines(current_addr) < 0)
+ return ERR;
+ if (current_addr == 0 && addr_last != 0)
+ current_addr = 1;
+ break;
+ case 'd':
+ if (check_addr_range(current_addr, current_addr) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (delete_lines(first_addr, second_addr) < 0)
+ return ERR;
+ else if ((addr = INC_MOD(current_addr, addr_last)) != 0)
+ current_addr = addr;
+ if (current_addr == 0 && addr_last != 0)
+ current_addr = 1;
+ break;
+ case 'e':
+ if (modified && !scripted)
+ return EMOD;
+ /* FALLTHROUGH */
+ case 'E':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ } else if (!isspace((unsigned char)*ibufp)) {
+ errmsg = "unexpected command suffix";
+ return ERR;
+ } else if ((fnp = get_filename()) == NULL)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (delete_lines(1, addr_last) < 0)
+ return ERR;
+ clear_undo_stack();
+ if (close_sbuf() < 0)
+ return ERR;
+ else if (open_sbuf() < 0)
+ return FATAL;
+ if (*fnp && *fnp != '!') {
+ if (strlen(fnp) < sizeof(old_filename)) {
+ strcpy(old_filename, fnp);
+ } else {
+ fprintf(stderr, "%s: filename too long\n", fnp);
+ quit(2);
+ }
+ }
+
+ if (!posixly_correct && *fnp == '\0' && *old_filename == '\0') {
+ errmsg = "no current filename";
+ return ERR;
+ }
+ if (read_file(*fnp ? fnp : old_filename, 0) < 0)
+ return ERR;
+ clear_undo_stack();
+ modified = 0;
+ u_current_addr = u_addr_last = -1;
+ break;
+ case 'f':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ } else if (!isspace((unsigned char)*ibufp)) {
+ errmsg = "unexpected command suffix";
+ return ERR;
+ } else if ((fnp = get_filename()) == NULL)
+ return ERR;
+ else if (*fnp == '!') {
+ errmsg = "invalid redirection";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+ if (*fnp) {
+ if (strlen(fnp) < sizeof(old_filename)) {
+ strcpy(old_filename, fnp);
+ } else {
+ fprintf(stderr, "%s: filename too long\n", fnp);
+ quit(2);
+ }
+ }
+ printf("%s\n", strip_escapes(old_filename));
+ break;
+ case 'g':
+ case 'v':
+ case 'G':
+ case 'V':
+ if (isglobal) {
+ errmsg = "cannot nest global commands";
+ return ERR;
+ } else if (check_addr_range(1, addr_last) < 0)
+ return ERR;
+ else if (build_active_list(c == 'g' || c == 'G') < 0)
+ return ERR;
+ else if ((n = (c == 'G' || c == 'V')))
+ GET_COMMAND_SUFFIX();
+ isglobal++;
+ n = exec_global(n, gflag);
+ if (n == EOF)
+ return EOF;
+ else if (n < 0)
+ return ERR;
+ break;
+ case 'h':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+ if (*errmsg) fprintf(stderr, "%s\n", errmsg);
+ break;
+ case 'H':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+ if ((garrulous = 1 - garrulous) && *errmsg)
+ fprintf(stderr, "%s\n", errmsg);
+ break;
+ case 'i':
+ if (second_addr == 0) {
+ second_addr = 1;
+ }
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (append_lines(second_addr - 1) < 0)
+ return ERR;
+ if (u_addr_last == addr_last) /* nothing inserted */
+ current_addr = second_addr;
+ break;
+ case 'j':
+ if (check_addr_range(current_addr, current_addr + 1) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (first_addr != second_addr &&
+ join_lines(first_addr, second_addr) < 0)
+ return ERR;
+ break;
+ case 'k':
+ c = *ibufp++;
+ if (second_addr == 0) {
+ errmsg = "invalid address";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+ if (mark_line_node(get_addressed_line_node(second_addr), c) < 0)
+ return ERR;
+ break;
+ case 'l':
+ if (check_addr_range(current_addr, current_addr) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (display_lines(first_addr, second_addr, gflag | GLS) < 0)
+ return ERR;
+ gflag = 0;
+ break;
+ case 'm':
+ if (check_addr_range(current_addr, current_addr) < 0)
+ return ERR;
+ GET_THIRD_ADDR(addr);
+ if (first_addr <= addr && addr < second_addr) {
+ errmsg = "invalid destination";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (move_lines(addr) < 0)
+ return ERR;
+ break;
+ case 'n':
+ if (check_addr_range(current_addr, current_addr) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (display_lines(first_addr, second_addr, gflag | GNP) < 0)
+ return ERR;
+ gflag = 0;
+ break;
+ case 'p':
+ if (check_addr_range(current_addr, current_addr) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (display_lines(first_addr, second_addr, gflag | GPR) < 0)
+ return ERR;
+ gflag = 0;
+ break;
+ case 'P':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+ prompt = prompt ? NULL : optarg ? optarg : dps;
+ break;
+ case 'q':
+ case 'Q':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+ gflag = (modified && !scripted && c == 'q') ? EMOD : EOF;
+ break;
+ case 'r':
+ if (!isspace((unsigned char)*ibufp)) {
+ errmsg = "unexpected command suffix";
+ return ERR;
+ } else if (addr_cnt == 0)
+ second_addr = addr_last;
+ if ((fnp = get_filename()) == NULL)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (*old_filename == '\0' && *fnp != '!') {
+ if (strlen(fnp) < sizeof(old_filename)) {
+ strcpy(old_filename, fnp);
+ } else {
+ fprintf(stderr, "%s: filename too long\n", fnp);
+ quit(2);
+ }
+ }
+ if (!posixly_correct && *fnp == '\0' && *old_filename == '\0') {
+ errmsg = "no current filename";
+ return ERR;
+ }
+ if ((addr = read_file(*fnp ? fnp : old_filename, second_addr)) < 0)
+ return ERR;
+ else if (addr && addr != addr_last)
+ modified = 1;
+ break;
+ case 's':
+ /*
+ * POSIX requires ed to process srabcr123r as
+ * replace abc with 123 delimiter='r'
+ */
+ if (!posixly_correct) do {
+ switch(*ibufp) {
+ case '\n':
+ sflags |=SGF;
+ break;
+ case 'g':
+ sflags |= SGG;
+ ibufp++;
+ break;
+ case 'p':
+ sflags |= SGP;
+ ibufp++;
+ break;
+ case 'r':
+ sflags |= SGR;
+ ibufp++;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ STRTOL(sgnum, ibufp);
+ sflags |= SGF;
+ sgflag &= ~GSG; /* override GSG */
+ break;
+ default:
+ if (sflags) {
+ errmsg = "invalid command suffix";
+ return ERR;
+ }
+ }
+ } while (sflags && *ibufp != '\n');
+ if (sflags && !pat) {
+ errmsg = "no previous substitution";
+ return ERR;
+ } else if (sflags & SGG)
+ sgnum = 0; /* override numeric arg */
+ if (*ibufp != '\n' && *(ibufp + 1) == '\n') {
+ errmsg = "invalid pattern delimiter";
+ return ERR;
+ }
+ tpat = pat;
+ SPL1();
+ if ((!sflags || (sflags & SGR)) &&
+ (tpat = get_compiled_pattern()) == NULL) {
+ SPL0();
+ return ERR;
+ } else if (tpat != pat) {
+ if (pat) {
+ regfree(pat);
+ free(pat);
+ }
+ pat = tpat;
+ patlock = 1; /* reserve pattern */
+ }
+ SPL0();
+ if (!sflags && extract_subst_tail(&sgflag, &sgnum) < 0)
+ return ERR;
+ else if (isglobal)
+ sgflag |= GLB;
+ else
+ sgflag &= ~GLB;
+ if (sflags & SGG)
+ sgflag ^= GSG;
+ if (sflags & SGP)
+ sgflag ^= GPR, sgflag &= ~(GLS | GNP);
+ do {
+ switch(*ibufp) {
+ case 'p':
+ sgflag |= GPR, ibufp++;
+ break;
+ case 'l':
+ sgflag |= GLS, ibufp++;
+ break;
+ case 'n':
+ sgflag |= GNP, ibufp++;
+ break;
+ default:
+ n++;
+ }
+ } while (!n);
+ if (check_addr_range(current_addr, current_addr) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (search_and_replace(pat, sgflag, sgnum) < 0)
+ return ERR;
+ break;
+ case 't':
+ if (check_addr_range(current_addr, current_addr) < 0)
+ return ERR;
+ GET_THIRD_ADDR(addr);
+ GET_COMMAND_SUFFIX();
+ if (!isglobal) clear_undo_stack();
+ if (copy_lines(addr) < 0)
+ return ERR;
+ break;
+ case 'u':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+ if (pop_undo_stack() < 0)
+ return ERR;
+ break;
+ case 'w':
+ case 'W':
+ if ((n = *ibufp) == 'q' || n == 'Q') {
+ gflag = EOF;
+ ibufp++;
+ }
+ if (!isspace((unsigned char)*ibufp)) {
+ errmsg = "unexpected command suffix";
+ return ERR;
+ } else if ((fnp = get_filename()) == NULL)
+ return ERR;
+ if (addr_cnt == 0 && !addr_last)
+ first_addr = second_addr = 0;
+ else if (check_addr_range(1, addr_last) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (*old_filename == '\0' && *fnp != '!') {
+ if (strlen(fnp) < sizeof(old_filename)) {
+ strcpy(old_filename, fnp);
+ } else {
+ fprintf(stderr, "%s: filename too long\n", fnp);
+ quit(2);
+ }
+ }
+ if (!posixly_correct && *fnp == '\0' && *old_filename == '\0') {
+ errmsg = "no current filename";
+ return ERR;
+ }
+ if ((addr = write_file(*fnp ? fnp : old_filename,
+ (c == 'W') ? "a" : "w", first_addr, second_addr)) < 0)
+ return ERR;
+ else if (addr == addr_last)
+ modified = 0;
+ else if (modified && !scripted && n == 'q')
+ gflag = EMOD;
+ break;
+ case 'x':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ }
+ GET_COMMAND_SUFFIX();
+#ifdef DES
+ des = get_keyword();
+ break;
+#else
+ errmsg = "crypt unavailable";
+ return ERR;
+#endif
+ case 'z':
+ if (check_addr_range(first_addr = 1, current_addr + (posixly_correct ? !isglobal : 1)) < 0)
+ return ERR;
+ else if ('0' < *ibufp && *ibufp <= '9')
+ STRTOL(rows, ibufp);
+ GET_COMMAND_SUFFIX();
+ if (display_lines(second_addr, min(addr_last,
+ second_addr + rows), gflag) < 0)
+ return ERR;
+ gflag = 0;
+ break;
+ case '=':
+ GET_COMMAND_SUFFIX();
+ printf("%ld\n", addr_cnt ? second_addr : addr_last);
+ break;
+ case '!':
+ if (addr_cnt > 0) {
+ errmsg = "unexpected address";
+ return ERR;
+ } else if ((sflags = get_shell_command()) < 0)
+ return ERR;
+ GET_COMMAND_SUFFIX();
+ if (sflags) printf("%s\n", shcmd + 1);
+ fflush(stdout);
+ system(shcmd + 1);
+ if (!scripted) printf("!\n");
+ break;
+ case '\n':
+ if (check_addr_range(first_addr = 1, current_addr + (posixly_correct ? !isglobal : 1)) < 0
+ || display_lines(second_addr, second_addr, 0) < 0)
+ return ERR;
+ break;
+ default:
+ errmsg = "unknown command";
+ return ERR;
+ }
+ return gflag;
+}
+
+
+/* check_addr_range: return status of address range check */
+int
+check_addr_range(long n, long m)
+{
+ if (addr_cnt == 0) {
+ first_addr = n;
+ second_addr = m;
+ }
+ if (first_addr > second_addr || 1 > first_addr ||
+ second_addr > addr_last) {
+ errmsg = "invalid address";
+ return ERR;
+ }
+ return 0;
+}
+
+
+/* get_matching_node_addr: return the address of the next line matching a
+ pattern in a given direction. wrap around begin/end of editor buffer if
+ necessary */
+long
+get_matching_node_addr(pattern_t *pat, int dir)
+{
+ char *s;
+ long n = current_addr;
+ line_t *lp;
+
+ if (!pat) return ERR;
+ do {
+ if ((n = dir ? INC_MOD(n, addr_last) : DEC_MOD(n, addr_last))) {
+ lp = get_addressed_line_node(n);
+ if ((s = get_sbuf_line(lp)) == NULL)
+ return ERR;
+ if (isbinary)
+ NUL_TO_NEWLINE(s, lp->len);
+ if (!regexec(pat, s, 0, NULL, 0))
+ return n;
+ }
+ } while (n != current_addr);
+ errmsg = "no match";
+ return ERR;
+}
+
+
+/* get_filename: return pointer to copy of filename in the command buffer */
+char *
+get_filename(void)
+{
+ static char *file = NULL;
+ static int filesz = 0;
+
+ int n;
+
+ if (*ibufp != '\n') {
+ SKIP_BLANKS();
+ if (*ibufp == '\n') {
+ errmsg = "invalid filename";
+ return NULL;
+ } else if ((ibufp = get_extended_line(&n, 1)) == NULL)
+ return NULL;
+ else if (*ibufp == '!') {
+ ibufp++;
+ if ((n = get_shell_command()) < 0)
+ return NULL;
+ if (n)
+ printf("%s\n", shcmd + 1);
+ return shcmd;
+ } else if (n > PATH_MAX) {
+ errmsg = "filename too long";
+ return NULL;
+ }
+ }
+ else if (posixly_correct && *old_filename == '\0') {
+ errmsg = "no current filename";
+ return NULL;
+ }
+ REALLOC(file, filesz, PATH_MAX + 1, NULL);
+ for (n = 0; *ibufp != '\n';)
+ file[n++] = *ibufp++;
+ file[n] = '\0';
+ return is_legal_filename(file) ? file : NULL;
+}
+
+
+/* get_shell_command: read a shell command from stdin; return substitution
+ status */
+int
+get_shell_command(void)
+{
+ static char *buf = NULL;
+ static int n = 0;
+
+ char *s; /* substitution char pointer */
+ int i = 0;
+ int j = 0;
+
+ if (red) {
+ errmsg = "shell access restricted";
+ return ERR;
+ } else if ((s = ibufp = get_extended_line(&j, 1)) == NULL)
+ return ERR;
+ REALLOC(buf, n, j + 1, ERR);
+ buf[i++] = '!'; /* prefix command w/ bang */
+ while (*ibufp != '\n')
+ switch (*ibufp) {
+ default:
+ REALLOC(buf, n, i + 2, ERR);
+ buf[i++] = *ibufp;
+ if (*ibufp++ == '\\')
+ buf[i++] = *ibufp++;
+ break;
+ case '!':
+ if (s != ibufp) {
+ REALLOC(buf, n, i + 1, ERR);
+ buf[i++] = *ibufp++;
+ }
+ else if (shcmd == NULL || (!posixly_correct && *(shcmd + 1) == '\0'))
+ {
+ errmsg = "no previous command";
+ return ERR;
+ } else {
+ REALLOC(buf, n, i + shcmdi, ERR);
+ for (s = shcmd + 1; s < shcmd + shcmdi;)
+ buf[i++] = *s++;
+ s = ibufp++;
+ }
+ break;
+ case '%':
+ if (*old_filename == '\0') {
+ errmsg = "no current filename";
+ return ERR;
+ }
+ j = strlen(s = strip_escapes(old_filename));
+ REALLOC(buf, n, i + j, ERR);
+ while (j--)
+ buf[i++] = *s++;
+ s = ibufp++;
+ break;
+ }
+ REALLOC(shcmd, shcmdsz, i + 1, ERR);
+ memcpy(shcmd, buf, i);
+ shcmd[shcmdi = i] = '\0';
+ return *s == '!' || *s == '%';
+}
+
+
+/* append_lines: insert text from stdin to after line n; stop when either a
+ single period is read or EOF; return status */
+int
+append_lines(long n)
+{
+ int l;
+ const char *lp = ibuf;
+ const char *eot;
+ undo_t *up = NULL;
+
+ for (current_addr = n;;) {
+ if (!isglobal) {
+ if ((l = get_tty_line()) < 0)
+ return ERR;
+ else if (l == 0 || ibuf[l - 1] != '\n') {
+ clearerr(stdin);
+ return l ? EOF : 0;
+ }
+ lp = ibuf;
+ } else if (*(lp = ibufp) == '\0')
+ return 0;
+ else {
+ while (*ibufp++ != '\n')
+ ;
+ l = ibufp - lp;
+ }
+ if (l == 2 && lp[0] == '.' && lp[1] == '\n') {
+ return 0;
+ }
+ eot = lp + l;
+ SPL1();
+ do {
+ if ((lp = put_sbuf_line(lp)) == NULL) {
+ SPL0();
+ return ERR;
+ } else if (up)
+ up->t = get_addressed_line_node(current_addr);
+ else if ((up = push_undo_stack(UADD, current_addr,
+ current_addr)) == NULL) {
+ SPL0();
+ return ERR;
+ }
+ } while (lp != eot);
+ modified = 1;
+ SPL0();
+ }
+ /* NOTREACHED */
+}
+
+
+/* join_lines: replace a range of lines with the joined text of those lines */
+int
+join_lines(long from, long to)
+{
+ static char *buf = NULL;
+ static int n;
+
+ char *s;
+ int size = 0;
+ line_t *bp, *ep;
+
+ ep = get_addressed_line_node(INC_MOD(to, addr_last));
+ bp = get_addressed_line_node(from);
+ for (; bp != ep; bp = bp->q_forw) {
+ if ((s = get_sbuf_line(bp)) == NULL)
+ return ERR;
+ REALLOC(buf, n, size + bp->len, ERR);
+ memcpy(buf + size, s, bp->len);
+ size += bp->len;
+ }
+ REALLOC(buf, n, size + 2, ERR);
+ memcpy(buf + size, "\n", 2);
+ if (delete_lines(from, to) < 0)
+ return ERR;
+ current_addr = from - 1;
+ SPL1();
+ if (put_sbuf_line(buf) == NULL ||
+ push_undo_stack(UADD, current_addr, current_addr) == NULL) {
+ SPL0();
+ return ERR;
+ }
+ modified = 1;
+ if (current_addr == 0)
+ current_addr = 1;
+ SPL0();
+ return 0;
+}
+
+
+/* move_lines: move a range of lines */
+int
+move_lines(long addr)
+{
+ line_t *b1, *a1, *b2, *a2;
+ long n = INC_MOD(second_addr, addr_last);
+ long p = first_addr - 1;
+ int done = (addr == first_addr - 1 || addr == second_addr);
+
+ SPL1();
+ if (done) {
+ a2 = get_addressed_line_node(n);
+ b2 = get_addressed_line_node(p);
+ current_addr = second_addr;
+ } else if (push_undo_stack(UMOV, p, n) == NULL ||
+ push_undo_stack(UMOV, addr, INC_MOD(addr, addr_last)) == NULL) {
+ SPL0();
+ return ERR;
+ } else {
+ a1 = get_addressed_line_node(n);
+ if (addr < first_addr) {
+ b1 = get_addressed_line_node(p);
+ b2 = get_addressed_line_node(addr);
+ /* this get_addressed_line_node last! */
+ } else {
+ b2 = get_addressed_line_node(addr);
+ b1 = get_addressed_line_node(p);
+ /* this get_addressed_line_node last! */
+ }
+ a2 = b2->q_forw;
+ REQUE(b2, b1->q_forw);
+ REQUE(a1->q_back, a2);
+ REQUE(b1, a1);
+ current_addr = addr + ((addr < first_addr) ?
+ second_addr - first_addr + 1 : 0);
+ }
+ if (isglobal)
+ unset_active_nodes(b2->q_forw, a2);
+ modified = 1;
+ SPL0();
+ return 0;
+}
+
+
+/* copy_lines: copy a range of lines; return status */
+int
+copy_lines(long addr)
+{
+ line_t *lp, *np = get_addressed_line_node(first_addr);
+ undo_t *up = NULL;
+ long n = second_addr - first_addr + 1;
+ long m = 0;
+
+ current_addr = addr;
+ if (first_addr <= addr && addr < second_addr) {
+ n = addr - first_addr + 1;
+ m = second_addr - addr;
+ }
+ for (; n > 0; n=m, m=0, np = get_addressed_line_node(current_addr + 1))
+ for (; n-- > 0; np = np->q_forw) {
+ SPL1();
+ if ((lp = dup_line_node(np)) == NULL) {
+ SPL0();
+ return ERR;
+ }
+ add_line_node(lp);
+ if (up)
+ up->t = lp;
+ else if ((up = push_undo_stack(UADD, current_addr,
+ current_addr)) == NULL) {
+ SPL0();
+ return ERR;
+ }
+ modified = 1;
+ SPL0();
+ }
+ return 0;
+}
+
+
+/* delete_lines: delete a range of lines */
+int
+delete_lines(long from, long to)
+{
+ line_t *n, *p;
+
+ SPL1();
+ if (push_undo_stack(UDEL, from, to) == NULL) {
+ SPL0();
+ return ERR;
+ }
+ n = get_addressed_line_node(INC_MOD(to, addr_last));
+ p = get_addressed_line_node(from - 1);
+ /* this get_addressed_line_node last! */
+ if (isglobal)
+ unset_active_nodes(p->q_forw, n);
+ REQUE(p, n);
+ addr_last -= to - from + 1;
+ current_addr = from - 1;
+ modified = 1;
+ SPL0();
+ return 0;
+}
+
+
+/* display_lines: print a range of lines to stdout */
+int
+display_lines(long from, long to, int gflag)
+{
+ line_t *bp;
+ line_t *ep;
+ char *s;
+
+ if (!from) {
+ errmsg = "invalid address";
+ return ERR;
+ }
+ ep = get_addressed_line_node(INC_MOD(to, addr_last));
+ bp = get_addressed_line_node(from);
+ for (; bp != ep; bp = bp->q_forw) {
+ if ((s = get_sbuf_line(bp)) == NULL)
+ return ERR;
+ if (put_tty_line(s, bp->len, current_addr = from++, gflag) < 0)
+ return ERR;
+ }
+ return 0;
+}
+
+
+#define MAXMARK 26 /* max number of marks */
+
+line_t *mark[MAXMARK]; /* line markers */
+int markno; /* line marker count */
+
+/* mark_line_node: set a line node mark */
+int
+mark_line_node(line_t *lp, int n)
+{
+ if (!islower((unsigned char)n)) {
+ errmsg = "invalid mark character";
+ return ERR;
+ } else if (mark[n - 'a'] == NULL)
+ markno++;
+ mark[n - 'a'] = lp;
+ return 0;
+}
+
+
+/* get_marked_node_addr: return address of a marked line */
+long
+get_marked_node_addr(int n)
+{
+ if (!islower((unsigned char)n)) {
+ errmsg = "invalid mark character";
+ return ERR;
+ }
+ return get_line_node_addr(mark[n - 'a']);
+}
+
+/* Used by search and replace */
+void
+replace_marks(line_t *old, line_t *new)
+{
+ int i;
+ for (i=0; markno && i<MAXMARK; i++)
+ if (mark[i] == old)
+ mark[i] = new;
+}
+
+
+/* unmark_line_node: clear line node mark */
+void
+unmark_line_node(line_t *lp)
+{
+ int i;
+
+ for (i = 0; markno && i < MAXMARK; i++)
+ if (mark[i] == lp) {
+ mark[i] = NULL;
+ markno--;
+ }
+}
+
+
+/* dup_line_node: return a pointer to a copy of a line node */
+line_t *
+dup_line_node(line_t *lp)
+{
+ line_t *np;
+
+ if ((np = (line_t *) malloc(sizeof(line_t))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ return NULL;
+ }
+ np->seek = lp->seek;
+ np->len = lp->len;
+ return np;
+}
+
+
+/* has_trailing_escape: return the parity of escapes preceding a character
+ in a string */
+int
+has_trailing_escape(char *s, char *t)
+{
+ return (s == t || *(t - 1) != '\\') ? 0 : !has_trailing_escape(s, t - 1);
+}
+
+
+/* strip_escapes: return copy of escaped string of at most length PATH_MAX */
+char *
+strip_escapes(char *s)
+{
+ static char *file = NULL;
+ static int filesz = 0;
+
+ int i = 0;
+
+ REALLOC(file, filesz, PATH_MAX, NULL);
+ while (i < filesz - 1 /* Worry about a possible trailing escape */
+ && (file[i++] = (*s == '\\') ? *++s : *s))
+ s++;
+ return file;
+}
+
+
+void
+signal_hup(int signo)
+{
+ if (mutex)
+ sigflags |= (1 << (signo - 1));
+ else
+ handle_hup(signo);
+}
+
+
+void
+signal_int(int signo)
+{
+ if (mutex)
+ sigflags |= (1 << (signo - 1));
+ else
+ handle_int(signo);
+}
+
+
+void
+handle_hup(int signo)
+{
+ char *hup = NULL; /* hup filename */
+ char *s;
+ char ed_hup[] = "ed.hup";
+ int n;
+
+ if (!sigactive)
+ quit(1);
+ sigflags &= ~(1 << (signo - 1));
+ if (addr_last && write_file(ed_hup, "w", 1, addr_last) < 0 &&
+ (s = getenv("HOME")) != NULL &&
+ (n = strlen(s)) + 8 <= PATH_MAX && /* "ed.hup" + '/' */
+ (hup = (char *) malloc(n + 10)) != NULL) {
+ strcpy(hup, s);
+ if (hup[n - 1] != '/')
+ hup[n] = '/', hup[n+1] = '\0';
+ strcat(hup, "ed.hup");
+ write_file(hup, "w", 1, addr_last);
+ }
+ quit(2);
+}
+
+
+void
+handle_int(int signo)
+{
+ if (!sigactive)
+ quit(1);
+ sigflags &= ~(1 << (signo - 1));
+#ifdef _POSIX_SOURCE
+ siglongjmp(env, -1);
+#else
+ longjmp(env, -1);
+#endif
+}
+
+
+int cols = 72; /* wrap column */
+
+void
+handle_winch(int signo)
+{
+ int save_errno = errno;
+
+ struct winsize ws; /* window size structure */
+
+ sigflags &= ~(1 << (signo - 1));
+ if (ioctl(0, TIOCGWINSZ, (char *) &ws) >= 0) {
+ if (ws.ws_row > 2) rows = ws.ws_row - 2;
+ if (ws.ws_col > 8) cols = ws.ws_col - 8;
+ }
+ errno = save_errno;
+}
+
+
+/* is_legal_filename: return a legal filename */
+int
+is_legal_filename(char *s)
+{
+ if (red && (*s == '!' || !strcmp(s, "..") || strchr(s, '/'))) {
+ errmsg = "shell access restricted";
+ return 0;
+ }
+ return 1;
+}
diff --git a/text_cmds/ed/re.c b/text_cmds/ed/re.c
new file mode 100644
index 0000000..43f67ae
--- /dev/null
+++ b/text_cmds/ed/re.c
@@ -0,0 +1,132 @@
+/* re.c: This file contains the regular expression interface routines for
+ the ed line editor. */
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ed/re.c,v 1.20 2003/07/20 10:24:09 ru Exp $");
+
+#include "ed.h"
+
+
+extern int patlock;
+
+const char *errmsg = "";
+
+/* get_compiled_pattern: return pointer to compiled pattern from command
+ buffer */
+pattern_t *
+get_compiled_pattern(void)
+{
+ static pattern_t *expr = NULL;
+ static char error[1024];
+
+ char *exprs;
+ char delimiter;
+ int n;
+
+ if ((delimiter = *ibufp) == ' ') {
+ errmsg = "invalid pattern delimiter";
+ return NULL;
+ } else if (delimiter == '\n' || *++ibufp == '\n' || *ibufp == delimiter) {
+ if (!expr)
+ errmsg = "no previous pattern";
+ return expr;
+ } else if ((exprs = extract_pattern(delimiter)) == NULL)
+ return NULL;
+ /* buffer alloc'd && not reserved */
+ if (expr && !patlock)
+ regfree(expr);
+ else if ((expr = (pattern_t *) malloc(sizeof(pattern_t))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ return NULL;
+ }
+ patlock = 0;
+ if ((n = regcomp(expr, exprs, 0))) {
+ regerror(n, expr, error, sizeof error);
+ errmsg = error;
+ free(expr);
+ return expr = NULL;
+ }
+ return expr;
+}
+
+
+/* extract_pattern: copy a pattern string from the command buffer; return
+ pointer to the copy */
+char *
+extract_pattern(int delimiter)
+{
+ static char *lhbuf = NULL; /* buffer */
+ static int lhbufsz = 0; /* buffer size */
+
+ char *nd;
+ int len;
+
+ for (nd = ibufp; *nd != delimiter && *nd != '\n'; nd++)
+ switch (*nd) {
+ default:
+ break;
+ case '[':
+ if ((nd = parse_char_class(++nd)) == NULL) {
+ errmsg = "unbalanced brackets ([])";
+ return NULL;
+ }
+ break;
+ case '\\':
+ if (*++nd == '\n') {
+ errmsg = "trailing backslash (\\)";
+ return NULL;
+ }
+ break;
+ }
+ len = nd - ibufp;
+ REALLOC(lhbuf, lhbufsz, len + 1, NULL);
+ memcpy(lhbuf, ibufp, len);
+ lhbuf[len] = '\0';
+ ibufp = nd;
+ return (isbinary) ? NUL_TO_NEWLINE(lhbuf, len) : lhbuf;
+}
+
+
+/* parse_char_class: expand a POSIX character class */
+char *
+parse_char_class(char *s)
+{
+ int c, d;
+
+ if (*s == '^')
+ s++;
+ if (*s == ']')
+ s++;
+ for (; *s != ']' && *s != '\n'; s++)
+ if (*s == '[' && ((d = *(s+1)) == '.' || d == ':' || d == '='))
+ for (s++, c = *++s; *s != ']' || c != d; s++)
+ if ((c = *s) == '\n')
+ return NULL;
+ return (*s == ']') ? s : NULL;
+}
diff --git a/text_cmds/ed/red.1 b/text_cmds/ed/red.1
new file mode 100644
index 0000000..708251a
--- /dev/null
+++ b/text_cmds/ed/red.1
@@ -0,0 +1 @@
+.so man1/ed.1
diff --git a/text_cmds/ed/sub.c b/text_cmds/ed/sub.c
new file mode 100644
index 0000000..8d89a03
--- /dev/null
+++ b/text_cmds/ed/sub.c
@@ -0,0 +1,256 @@
+/* sub.c: This file contains the substitution routines for the ed
+ line editor */
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ed/sub.c,v 1.15 2002/06/30 05:13:53 obrien Exp $");
+
+#include "ed.h"
+
+
+char *rhbuf; /* rhs substitution buffer */
+int rhbufsz; /* rhs substitution buffer size */
+int rhbufi; /* rhs substitution buffer index */
+
+/* extract_subst_tail: extract substitution tail from the command buffer */
+int
+extract_subst_tail(int *flagp, long *np)
+{
+ char delimiter;
+
+ *flagp = *np = 0;
+ if ((delimiter = *ibufp) == '\n') {
+ rhbufi = 0;
+ *flagp = GPR;
+ return 0;
+ } else if (extract_subst_template() == NULL)
+ return ERR;
+ else if (*ibufp == '\n') {
+ *flagp = GPR;
+ return 0;
+ } else if (*ibufp == delimiter)
+ ibufp++;
+ if ('1' <= *ibufp && *ibufp <= '9') {
+ STRTOL(*np, ibufp);
+ return 0;
+ } else if (*ibufp == 'g') {
+ ibufp++;
+ *flagp = GSG;
+ return 0;
+ }
+ return 0;
+}
+
+
+/* extract_subst_template: return pointer to copy of substitution template
+ in the command buffer */
+char *
+extract_subst_template(void)
+{
+ int n = 0;
+ int i = 0;
+ char c;
+ char delimiter = *ibufp++;
+
+ if (*ibufp == '%' && *(ibufp + 1) == delimiter) {
+ ibufp++;
+ if (!rhbuf)
+ errmsg = "no previous substitution";
+ return rhbuf;
+ }
+ while (*ibufp != delimiter) {
+ REALLOC(rhbuf, rhbufsz, i + 2, NULL);
+ if ((c = rhbuf[i++] = *ibufp++) == '\n' && *ibufp == '\0') {
+ i--, ibufp--;
+ break;
+ } else if (c != '\\')
+ ;
+ else if ((rhbuf[i++] = *ibufp++) != '\n')
+ ;
+ else if (!isglobal) {
+ while ((n = get_tty_line()) == 0 ||
+ (n > 0 && ibuf[n - 1] != '\n'))
+ clearerr(stdin);
+ if (n < 0)
+ return NULL;
+ }
+ }
+ REALLOC(rhbuf, rhbufsz, i + 1, NULL);
+ rhbuf[rhbufi = i] = '\0';
+ return rhbuf;
+}
+
+
+char *rbuf; /* substitute_matching_text buffer */
+int rbufsz; /* substitute_matching_text buffer size */
+
+/* search_and_replace: for each line in a range, change text matching a pattern
+ according to a substitution template; return status */
+int
+search_and_replace(pattern_t *pat, int gflag, int kth)
+{
+ undo_t *up;
+ const char *txt;
+ const char *eot;
+ long lc;
+ long xa = current_addr;
+ int nsubs = 0;
+ line_t *lp;
+ int len;
+
+ current_addr = first_addr - 1;
+ for (lc = 0; lc <= second_addr - first_addr; lc++) {
+ lp = get_addressed_line_node(++current_addr);
+ if ((len = substitute_matching_text(pat, lp, gflag, kth)) < 0)
+ return ERR;
+ else if (len) {
+ up = NULL;
+ if (delete_lines(current_addr, current_addr) < 0)
+ return ERR;
+ txt = rbuf;
+ eot = rbuf + len;
+ SPL1();
+ do {
+ if ((txt = put_sbuf_line(txt)) == NULL) {
+ SPL0();
+ return ERR;
+ } else if (up)
+ up->t = get_addressed_line_node(current_addr);
+ else if ((up = push_undo_stack(UADD,
+ current_addr, current_addr)) == NULL) {
+ SPL0();
+ return ERR;
+ }
+ } while (txt != eot);
+ SPL0();
+ nsubs++;
+ /* 3751351 */
+ replace_marks(lp, get_addressed_line_node(current_addr));
+ xa = current_addr;
+ }
+ }
+ current_addr = xa;
+ if (nsubs == 0 && !(gflag & GLB)) {
+ errmsg = "no match";
+ return ERR;
+ } else if ((gflag & (GPR | GLS | GNP)) &&
+ display_lines(current_addr, current_addr, gflag) < 0)
+ return ERR;
+ return 0;
+}
+
+
+/* substitute_matching_text: replace text matched by a pattern according to
+ a substitution template; return pointer to the modified text */
+int
+substitute_matching_text(pattern_t *pat, line_t *lp, int gflag, int kth)
+{
+ int off = 0;
+ int changed = 0;
+ int matchno = 0;
+ int i = 0;
+ regmatch_t rm[SE_MAX];
+ char *txt;
+ char *eot;
+
+ if ((txt = get_sbuf_line(lp)) == NULL)
+ return ERR;
+ if (isbinary)
+ NUL_TO_NEWLINE(txt, lp->len);
+ eot = txt + lp->len;
+ if (!regexec(pat, txt, SE_MAX, rm, 0)) {
+ do {
+ if (!kth || kth == ++matchno) {
+ changed++;
+ i = rm[0].rm_so;
+ REALLOC(rbuf, rbufsz, off + i, ERR);
+ if (isbinary)
+ NEWLINE_TO_NUL(txt, rm[0].rm_eo);
+ memcpy(rbuf + off, txt, i);
+ off += i;
+ if ((off = apply_subst_template(txt, rm, off,
+ pat->re_nsub)) < 0)
+ return ERR;
+ } else {
+ i = rm[0].rm_eo;
+ REALLOC(rbuf, rbufsz, off + i, ERR);
+ if (isbinary)
+ NEWLINE_TO_NUL(txt, i);
+ memcpy(rbuf + off, txt, i);
+ off += i;
+ }
+ txt += rm[0].rm_eo;
+ } while (*txt &&
+ (!changed || ((gflag & GSG) && rm[0].rm_eo)) &&
+ !regexec(pat, txt, SE_MAX, rm, REG_NOTBOL));
+ i = eot - txt;
+ REALLOC(rbuf, rbufsz, off + i + 2, ERR);
+ if (i > 0 && !rm[0].rm_eo && (gflag & GSG)) {
+ errmsg = "infinite substitution loop";
+ return ERR;
+ }
+ if (isbinary)
+ NEWLINE_TO_NUL(txt, i);
+ memcpy(rbuf + off, txt, i);
+ memcpy(rbuf + off + i, "\n", 2);
+ }
+ return changed ? off + i + 1 : 0;
+}
+
+
+/* apply_subst_template: modify text according to a substitution template;
+ return offset to end of modified text */
+int
+apply_subst_template(const char *boln, regmatch_t *rm, int off, int re_nsub)
+{
+ int j = 0;
+ int k = 0;
+ int n;
+ char *sub = rhbuf;
+
+ for (; sub - rhbuf < rhbufi; sub++)
+ if (*sub == '&') {
+ j = rm[0].rm_so;
+ k = rm[0].rm_eo;
+ REALLOC(rbuf, rbufsz, off + k - j, ERR);
+ while (j < k)
+ rbuf[off++] = boln[j++];
+ } else if (*sub == '\\' && '1' <= *++sub && *sub <= '9' &&
+ (n = *sub - '0') <= re_nsub) {
+ j = rm[n].rm_so;
+ k = rm[n].rm_eo;
+ REALLOC(rbuf, rbufsz, off + k - j, ERR);
+ while (j < k)
+ rbuf[off++] = boln[j++];
+ } else {
+ REALLOC(rbuf, rbufsz, off + 1, ERR);
+ rbuf[off++] = *sub;
+ }
+ REALLOC(rbuf, rbufsz, off + 1, ERR);
+ rbuf[off] = '\0';
+ return off;
+}
diff --git a/text_cmds/ed/test/=.err b/text_cmds/ed/test/=.err
new file mode 100644
index 0000000..6a60559
--- /dev/null
+++ b/text_cmds/ed/test/=.err
@@ -0,0 +1 @@
+1,$=
diff --git a/text_cmds/ed/test/README b/text_cmds/ed/test/README
new file mode 100644
index 0000000..e360c4f
--- /dev/null
+++ b/text_cmds/ed/test/README
@@ -0,0 +1,32 @@
+# $FreeBSD: src/bin/ed/test/README,v 1.7 1999/08/27 23:14:17 peter Exp $
+
+The files in this directory with suffixes `.t', `.d', `.r' and `.err' are
+used for testing ed. To run the tests, set the ED variable in the Makefile
+for the path name of the program to be tested (e.g., /bin/ed), and type
+`make'. The tests do not exhaustively verify POSIX compliance nor do
+they verify correct 8-bit or long line support.
+
+The test file suffixes have the following meanings:
+.t Template - a list of ed commands from which an ed script is
+ constructed
+.d Data - read by an ed script
+.r Result - the expected output after processing data via an ed
+ script.
+.err Error - invalid ed commands that should generate an error
+
+The output of the tests is written to the two files err.o and scripts.o.
+At the end of the tests, these files are grep'ed for error messages,
+which look like:
+ *** The script u.ed exited abnormally ***
+or:
+ *** Output u.o of script u.ed is incorrect ***
+
+The POSIX requirement that an address range not be used where at most
+a single address is expected has been relaxed in this version of ed.
+Therefore, the following scripts which test for compliance with this
+POSIX rule exit abnormally:
+=-err.ed
+a1-err.ed
+i1-err.ed
+k1-err.ed
+r1-err.ed
diff --git a/text_cmds/ed/test/TODO b/text_cmds/ed/test/TODO
new file mode 100644
index 0000000..7a4b74f
--- /dev/null
+++ b/text_cmds/ed/test/TODO
@@ -0,0 +1,15 @@
+Some missing tests:
+0) g/./s^@^@ - okay: NULs in commands
+1) g/./s/^@/ - okay: NULs in patterns
+2) a
+ hello^V^Jworld
+ . - okay: embedded newlines in insert mode
+3) ed "" - error: invalid filename
+4) red .. - error: restricted
+5) red / - error: restricted
+5) red !xx - error: restricted
+6) ed -x - verify: 8-bit clean
+7) ed - verify: long-line support
+8) ed - verify: interactive/help mode
+9) G/pat/ - verify: global interactive command
+10) V/pat/ - verify: global interactive command
diff --git a/text_cmds/ed/test/a.d b/text_cmds/ed/test/a.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/a.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/a.r b/text_cmds/ed/test/a.r
new file mode 100644
index 0000000..26257bd
--- /dev/null
+++ b/text_cmds/ed/test/a.r
@@ -0,0 +1,8 @@
+hello world
+line 1
+hello world!
+line 2
+line 3
+line 4
+line5
+hello world!!
diff --git a/text_cmds/ed/test/a.t b/text_cmds/ed/test/a.t
new file mode 100644
index 0000000..ac98c40
--- /dev/null
+++ b/text_cmds/ed/test/a.t
@@ -0,0 +1,9 @@
+0a
+hello world
+.
+2a
+hello world!
+.
+$a
+hello world!!
+.
diff --git a/text_cmds/ed/test/a1.err b/text_cmds/ed/test/a1.err
new file mode 100644
index 0000000..e80815f
--- /dev/null
+++ b/text_cmds/ed/test/a1.err
@@ -0,0 +1,3 @@
+1,$a
+hello world
+.
diff --git a/text_cmds/ed/test/a2.err b/text_cmds/ed/test/a2.err
new file mode 100644
index 0000000..ec4b00b
--- /dev/null
+++ b/text_cmds/ed/test/a2.err
@@ -0,0 +1,3 @@
+aa
+hello world
+.
diff --git a/text_cmds/ed/test/addr.d b/text_cmds/ed/test/addr.d
new file mode 100644
index 0000000..8f7ba1b
--- /dev/null
+++ b/text_cmds/ed/test/addr.d
@@ -0,0 +1,9 @@
+line 1
+line 2
+line 3
+line 4
+line5
+1ine6
+line7
+line8
+line9
diff --git a/text_cmds/ed/test/addr.r b/text_cmds/ed/test/addr.r
new file mode 100644
index 0000000..04caf17
--- /dev/null
+++ b/text_cmds/ed/test/addr.r
@@ -0,0 +1,2 @@
+line 2
+line9
diff --git a/text_cmds/ed/test/addr.t b/text_cmds/ed/test/addr.t
new file mode 100644
index 0000000..750b224
--- /dev/null
+++ b/text_cmds/ed/test/addr.t
@@ -0,0 +1,5 @@
+1 d
+1 1 d
+1,2,d
+1;+ + ,d
+1,2;., + 2d
diff --git a/text_cmds/ed/test/addr1.err b/text_cmds/ed/test/addr1.err
new file mode 100644
index 0000000..29d6383
--- /dev/null
+++ b/text_cmds/ed/test/addr1.err
@@ -0,0 +1 @@
+100
diff --git a/text_cmds/ed/test/addr2.err b/text_cmds/ed/test/addr2.err
new file mode 100644
index 0000000..e96acb9
--- /dev/null
+++ b/text_cmds/ed/test/addr2.err
@@ -0,0 +1 @@
+-100
diff --git a/text_cmds/ed/test/ascii.d.uu b/text_cmds/ed/test/ascii.d.uu
new file mode 100644
index 0000000..0b0a73c
--- /dev/null
+++ b/text_cmds/ed/test/ascii.d.uu
@@ -0,0 +1,9 @@
+begin 644 ascii.d
+M``$"`P0%!@<("0H+#`T.#Q`1$A,4%187&!D:&QP='A\@(2(C)"4F)R@I*BLL
+M+2XO,#$R,S0U-C<X.3H[/#T^/T!!0D-$149'2$E*2TQ-3D]045)35%565UA9
+M6EM<75Y?8&%B8V1E9F=H:6IK;&UN;W!Q<G-T=79W>'EZ>WQ]?G^`@8*#A(6&
+MAXB)BHN,C8Z/D)&2DY25EI>8F9J;G)V>GZ"AHJ.DI::GJ*FJJZRMKJ^PL;*S
+MM+6VM[BYNKN\O;Z_P,'"P\3%QL?(R<K+S,W.S]#1TM/4U=;7V-G:V]S=WM_@
+?X>+CY.7FY^CIZNOL[>[O\/'R\_3U]O?X^?K[_/W^_]/4
+`
+end
diff --git a/text_cmds/ed/test/ascii.r.uu b/text_cmds/ed/test/ascii.r.uu
new file mode 100644
index 0000000..9ca88b4
--- /dev/null
+++ b/text_cmds/ed/test/ascii.r.uu
@@ -0,0 +1,9 @@
+begin 644 ascii.r
+M``$"`P0%!@<("0H+#`T.#Q`1$A,4%187&!D:&QP='A\@(2(C)"4F)R@I*BLL
+M+2XO,#$R,S0U-C<X.3H[/#T^/T!!0D-$149'2$E*2TQ-3D]045)35%565UA9
+M6EM<75Y?8&%B8V1E9F=H:6IK;&UN;W!Q<G-T=79W>'EZ>WQ]?G^`@8*#A(6&
+MAXB)BHN,C8Z/D)&2DY25EI>8F9J;G)V>GZ"AHJ.DI::GJ*FJJZRMKJ^PL;*S
+MM+6VM[BYNKN\O;Z_P,'"P\3%QL?(R<K+S,W.S]#1TM/4U=;7V-G:V]S=WM_@
+?X>+CY.7FY^CIZNOL[>[O\/'R\_3U]O?X^?K[_/W^_]/4
+`
+end
diff --git a/text_cmds/ed/test/ascii.t b/text_cmds/ed/test/ascii.t
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/ascii.t
diff --git a/text_cmds/ed/test/bang1.d b/text_cmds/ed/test/bang1.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/bang1.d
diff --git a/text_cmds/ed/test/bang1.err b/text_cmds/ed/test/bang1.err
new file mode 100644
index 0000000..630af90
--- /dev/null
+++ b/text_cmds/ed/test/bang1.err
@@ -0,0 +1 @@
+.!date
diff --git a/text_cmds/ed/test/bang1.r b/text_cmds/ed/test/bang1.r
new file mode 100644
index 0000000..dcf02b2
--- /dev/null
+++ b/text_cmds/ed/test/bang1.r
@@ -0,0 +1 @@
+okay
diff --git a/text_cmds/ed/test/bang1.t b/text_cmds/ed/test/bang1.t
new file mode 100644
index 0000000..d7b1fea
--- /dev/null
+++ b/text_cmds/ed/test/bang1.t
@@ -0,0 +1,5 @@
+!read one
+hello, world
+a
+okay
+.
diff --git a/text_cmds/ed/test/bang2.err b/text_cmds/ed/test/bang2.err
new file mode 100644
index 0000000..79d8956
--- /dev/null
+++ b/text_cmds/ed/test/bang2.err
@@ -0,0 +1 @@
+!!
diff --git a/text_cmds/ed/test/c.d b/text_cmds/ed/test/c.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/c.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/c.r b/text_cmds/ed/test/c.r
new file mode 100644
index 0000000..0fb3e4f
--- /dev/null
+++ b/text_cmds/ed/test/c.r
@@ -0,0 +1,4 @@
+at the top
+between top/middle
+in the middle
+at the bottom
diff --git a/text_cmds/ed/test/c.t b/text_cmds/ed/test/c.t
new file mode 100644
index 0000000..ebdd536
--- /dev/null
+++ b/text_cmds/ed/test/c.t
@@ -0,0 +1,12 @@
+1c
+at the top
+.
+4c
+in the middle
+.
+$c
+at the bottom
+.
+2,3c
+between top/middle
+.
diff --git a/text_cmds/ed/test/c1.err b/text_cmds/ed/test/c1.err
new file mode 100644
index 0000000..658ec38
--- /dev/null
+++ b/text_cmds/ed/test/c1.err
@@ -0,0 +1,3 @@
+cc
+hello world
+.
diff --git a/text_cmds/ed/test/c2.err b/text_cmds/ed/test/c2.err
new file mode 100644
index 0000000..24b3227
--- /dev/null
+++ b/text_cmds/ed/test/c2.err
@@ -0,0 +1,3 @@
+0c
+hello world
+.
diff --git a/text_cmds/ed/test/ckscripts.sh b/text_cmds/ed/test/ckscripts.sh
new file mode 100755
index 0000000..2c57449
--- /dev/null
+++ b/text_cmds/ed/test/ckscripts.sh
@@ -0,0 +1,37 @@
+#!/bin/sh -
+# This script runs the .ed scripts generated by mkscripts.sh
+# and compares their output against the .r files, which contain
+# the correct output
+#
+# $FreeBSD: src/bin/ed/test/ckscripts.sh,v 1.6 1999/08/27 23:14:18 peter Exp $
+
+PATH="/bin:/usr/bin:/usr/local/bin/:."
+ED=$1
+[ ! -x $ED ] && { echo "$ED: cannot execute"; exit 1; }
+
+# Run the *.red scripts first, since these don't generate output;
+# they exit with non-zero status
+for i in *.red; do
+ echo $i
+ if $i; then
+ echo "*** The script $i exited abnormally ***"
+ fi
+done >errs.o 2>&1
+
+# Run the remainding scripts; they exit with zero status
+for i in *.ed; do
+# base=`expr $i : '\([^.]*\)'`
+# base=`echo $i | sed 's/\..*//'`
+ base=`$ED - \!"echo $i" <<-EOF
+ s/\..*
+ EOF`
+ if $base.ed; then
+ if cmp -s $base.o $base.r; then :; else
+ echo "*** Output $base.o of script $i is incorrect ***"
+ fi
+ else
+ echo "*** The script $i exited abnormally ***"
+ fi
+done >scripts.o 2>&1
+
+grep -h '\*\*\*' errs.o scripts.o
diff --git a/text_cmds/ed/test/d.d b/text_cmds/ed/test/d.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/d.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/d.err b/text_cmds/ed/test/d.err
new file mode 100644
index 0000000..f03f694
--- /dev/null
+++ b/text_cmds/ed/test/d.err
@@ -0,0 +1 @@
+dd
diff --git a/text_cmds/ed/test/d.r b/text_cmds/ed/test/d.r
new file mode 100644
index 0000000..b7e242c
--- /dev/null
+++ b/text_cmds/ed/test/d.r
@@ -0,0 +1 @@
+line 2
diff --git a/text_cmds/ed/test/d.t b/text_cmds/ed/test/d.t
new file mode 100644
index 0000000..c7c473f
--- /dev/null
+++ b/text_cmds/ed/test/d.t
@@ -0,0 +1,3 @@
+1d
+2;+1d
+$d
diff --git a/text_cmds/ed/test/e1.d b/text_cmds/ed/test/e1.d
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/text_cmds/ed/test/e1.d
@@ -0,0 +1 @@
+hello world
diff --git a/text_cmds/ed/test/e1.err b/text_cmds/ed/test/e1.err
new file mode 100644
index 0000000..827cc29
--- /dev/null
+++ b/text_cmds/ed/test/e1.err
@@ -0,0 +1 @@
+ee e1.err
diff --git a/text_cmds/ed/test/e1.r b/text_cmds/ed/test/e1.r
new file mode 100644
index 0000000..e656728
--- /dev/null
+++ b/text_cmds/ed/test/e1.r
@@ -0,0 +1 @@
+E e1.t
diff --git a/text_cmds/ed/test/e1.t b/text_cmds/ed/test/e1.t
new file mode 100644
index 0000000..e656728
--- /dev/null
+++ b/text_cmds/ed/test/e1.t
@@ -0,0 +1 @@
+E e1.t
diff --git a/text_cmds/ed/test/e2.d b/text_cmds/ed/test/e2.d
new file mode 100644
index 0000000..aa44630
--- /dev/null
+++ b/text_cmds/ed/test/e2.d
@@ -0,0 +1 @@
+E !echo hello world-
diff --git a/text_cmds/ed/test/e2.err b/text_cmds/ed/test/e2.err
new file mode 100644
index 0000000..779a64b
--- /dev/null
+++ b/text_cmds/ed/test/e2.err
@@ -0,0 +1 @@
+.e e2.err
diff --git a/text_cmds/ed/test/e2.r b/text_cmds/ed/test/e2.r
new file mode 100644
index 0000000..59ebf11
--- /dev/null
+++ b/text_cmds/ed/test/e2.r
@@ -0,0 +1 @@
+hello world-
diff --git a/text_cmds/ed/test/e2.t b/text_cmds/ed/test/e2.t
new file mode 100644
index 0000000..aa44630
--- /dev/null
+++ b/text_cmds/ed/test/e2.t
@@ -0,0 +1 @@
+E !echo hello world-
diff --git a/text_cmds/ed/test/e3.d b/text_cmds/ed/test/e3.d
new file mode 100644
index 0000000..aa44630
--- /dev/null
+++ b/text_cmds/ed/test/e3.d
@@ -0,0 +1 @@
+E !echo hello world-
diff --git a/text_cmds/ed/test/e3.err b/text_cmds/ed/test/e3.err
new file mode 100644
index 0000000..80a7fdc
--- /dev/null
+++ b/text_cmds/ed/test/e3.err
@@ -0,0 +1 @@
+ee.err
diff --git a/text_cmds/ed/test/e3.r b/text_cmds/ed/test/e3.r
new file mode 100644
index 0000000..aa44630
--- /dev/null
+++ b/text_cmds/ed/test/e3.r
@@ -0,0 +1 @@
+E !echo hello world-
diff --git a/text_cmds/ed/test/e3.t b/text_cmds/ed/test/e3.t
new file mode 100644
index 0000000..1c50726
--- /dev/null
+++ b/text_cmds/ed/test/e3.t
@@ -0,0 +1 @@
+E
diff --git a/text_cmds/ed/test/e4.d b/text_cmds/ed/test/e4.d
new file mode 100644
index 0000000..aa44630
--- /dev/null
+++ b/text_cmds/ed/test/e4.d
@@ -0,0 +1 @@
+E !echo hello world-
diff --git a/text_cmds/ed/test/e4.r b/text_cmds/ed/test/e4.r
new file mode 100644
index 0000000..aa44630
--- /dev/null
+++ b/text_cmds/ed/test/e4.r
@@ -0,0 +1 @@
+E !echo hello world-
diff --git a/text_cmds/ed/test/e4.t b/text_cmds/ed/test/e4.t
new file mode 100644
index 0000000..d905d9d
--- /dev/null
+++ b/text_cmds/ed/test/e4.t
@@ -0,0 +1 @@
+e
diff --git a/text_cmds/ed/test/f1.err b/text_cmds/ed/test/f1.err
new file mode 100644
index 0000000..e60975a
--- /dev/null
+++ b/text_cmds/ed/test/f1.err
@@ -0,0 +1 @@
+.f f1.err
diff --git a/text_cmds/ed/test/f2.err b/text_cmds/ed/test/f2.err
new file mode 100644
index 0000000..26d1c5e
--- /dev/null
+++ b/text_cmds/ed/test/f2.err
@@ -0,0 +1 @@
+ff1.err
diff --git a/text_cmds/ed/test/g1.d b/text_cmds/ed/test/g1.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/g1.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/g1.err b/text_cmds/ed/test/g1.err
new file mode 100644
index 0000000..f95ea22
--- /dev/null
+++ b/text_cmds/ed/test/g1.err
@@ -0,0 +1 @@
+g/./s //x/
diff --git a/text_cmds/ed/test/g1.r b/text_cmds/ed/test/g1.r
new file mode 100644
index 0000000..578a44b
--- /dev/null
+++ b/text_cmds/ed/test/g1.r
@@ -0,0 +1,15 @@
+line5
+help! world
+order
+line 4
+help! world
+order
+line 3
+help! world
+order
+line 2
+help! world
+order
+line 1
+help! world
+order
diff --git a/text_cmds/ed/test/g1.t b/text_cmds/ed/test/g1.t
new file mode 100644
index 0000000..2d0b54f
--- /dev/null
+++ b/text_cmds/ed/test/g1.t
@@ -0,0 +1,6 @@
+g/./m0
+g/./s/$/\
+hello world
+g/hello /s/lo/p!/\
+a\
+order
diff --git a/text_cmds/ed/test/g2.d b/text_cmds/ed/test/g2.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/g2.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/g2.err b/text_cmds/ed/test/g2.err
new file mode 100644
index 0000000..0ff6a5a
--- /dev/null
+++ b/text_cmds/ed/test/g2.err
@@ -0,0 +1 @@
+g//s/./x/
diff --git a/text_cmds/ed/test/g2.r b/text_cmds/ed/test/g2.r
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/text_cmds/ed/test/g2.r
@@ -0,0 +1 @@
+hello world
diff --git a/text_cmds/ed/test/g2.t b/text_cmds/ed/test/g2.t
new file mode 100644
index 0000000..831ee83
--- /dev/null
+++ b/text_cmds/ed/test/g2.t
@@ -0,0 +1,2 @@
+g/[2-4]/-1,+1c\
+hello world
diff --git a/text_cmds/ed/test/g3.d b/text_cmds/ed/test/g3.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/g3.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/g3.err b/text_cmds/ed/test/g3.err
new file mode 100644
index 0000000..01058d8
--- /dev/null
+++ b/text_cmds/ed/test/g3.err
@@ -0,0 +1 @@
+g
diff --git a/text_cmds/ed/test/g3.r b/text_cmds/ed/test/g3.r
new file mode 100644
index 0000000..cc6fbdd
--- /dev/null
+++ b/text_cmds/ed/test/g3.r
@@ -0,0 +1,5 @@
+linc 3
+xine 1
+xine 2
+xinc 4
+xinc5
diff --git a/text_cmds/ed/test/g3.t b/text_cmds/ed/test/g3.t
new file mode 100644
index 0000000..2d052a6
--- /dev/null
+++ b/text_cmds/ed/test/g3.t
@@ -0,0 +1,4 @@
+g/./s//x/\
+3m0
+g/./s/e/c/\
+2,3m1
diff --git a/text_cmds/ed/test/g4.d b/text_cmds/ed/test/g4.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/g4.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/g4.r b/text_cmds/ed/test/g4.r
new file mode 100644
index 0000000..350882d
--- /dev/null
+++ b/text_cmds/ed/test/g4.r
@@ -0,0 +1,7 @@
+hello
+zine 1
+line 2
+line 3
+line 4
+line5
+world
diff --git a/text_cmds/ed/test/g4.t b/text_cmds/ed/test/g4.t
new file mode 100644
index 0000000..ec61816
--- /dev/null
+++ b/text_cmds/ed/test/g4.t
@@ -0,0 +1,13 @@
+g/./s/./x/\
+u\
+s/./y/\
+u\
+s/./z/\
+u
+u
+0a
+hello
+.
+$a
+world
+.
diff --git a/text_cmds/ed/test/g5.d b/text_cmds/ed/test/g5.d
new file mode 100644
index 0000000..a92d664
--- /dev/null
+++ b/text_cmds/ed/test/g5.d
@@ -0,0 +1,3 @@
+line 1
+line 2
+line 3
diff --git a/text_cmds/ed/test/g5.r b/text_cmds/ed/test/g5.r
new file mode 100644
index 0000000..15a2675
--- /dev/null
+++ b/text_cmds/ed/test/g5.r
@@ -0,0 +1,9 @@
+line 1
+line 2
+line 3
+line 2
+line 3
+line 1
+line 3
+line 1
+line 2
diff --git a/text_cmds/ed/test/g5.t b/text_cmds/ed/test/g5.t
new file mode 100644
index 0000000..e213481
--- /dev/null
+++ b/text_cmds/ed/test/g5.t
@@ -0,0 +1,2 @@
+g/./1,3t$\
+1d
diff --git a/text_cmds/ed/test/h.err b/text_cmds/ed/test/h.err
new file mode 100644
index 0000000..a71e506
--- /dev/null
+++ b/text_cmds/ed/test/h.err
@@ -0,0 +1 @@
+.h
diff --git a/text_cmds/ed/test/i.d b/text_cmds/ed/test/i.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/i.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/i.r b/text_cmds/ed/test/i.r
new file mode 100644
index 0000000..5f27af0
--- /dev/null
+++ b/text_cmds/ed/test/i.r
@@ -0,0 +1,8 @@
+hello world
+hello world!
+line 1
+line 2
+line 3
+line 4
+hello world!!
+line5
diff --git a/text_cmds/ed/test/i.t b/text_cmds/ed/test/i.t
new file mode 100644
index 0000000..d1d9805
--- /dev/null
+++ b/text_cmds/ed/test/i.t
@@ -0,0 +1,9 @@
+1i
+hello world
+.
+2i
+hello world!
+.
+$i
+hello world!!
+.
diff --git a/text_cmds/ed/test/i1.err b/text_cmds/ed/test/i1.err
new file mode 100644
index 0000000..aaddede
--- /dev/null
+++ b/text_cmds/ed/test/i1.err
@@ -0,0 +1,3 @@
+1,$i
+hello world
+.
diff --git a/text_cmds/ed/test/i2.err b/text_cmds/ed/test/i2.err
new file mode 100644
index 0000000..b63f5ac
--- /dev/null
+++ b/text_cmds/ed/test/i2.err
@@ -0,0 +1,3 @@
+ii
+hello world
+.
diff --git a/text_cmds/ed/test/i3.err b/text_cmds/ed/test/i3.err
new file mode 100644
index 0000000..6d200c8
--- /dev/null
+++ b/text_cmds/ed/test/i3.err
@@ -0,0 +1,3 @@
+0i
+hello world
+.
diff --git a/text_cmds/ed/test/j.d b/text_cmds/ed/test/j.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/j.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/j.r b/text_cmds/ed/test/j.r
new file mode 100644
index 0000000..66f36a8
--- /dev/null
+++ b/text_cmds/ed/test/j.r
@@ -0,0 +1,4 @@
+line 1
+line 2line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/j.t b/text_cmds/ed/test/j.t
new file mode 100644
index 0000000..9b5d28d
--- /dev/null
+++ b/text_cmds/ed/test/j.t
@@ -0,0 +1,2 @@
+1,1j
+2,3j
diff --git a/text_cmds/ed/test/k.d b/text_cmds/ed/test/k.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/k.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/k.r b/text_cmds/ed/test/k.r
new file mode 100644
index 0000000..eeb38db
--- /dev/null
+++ b/text_cmds/ed/test/k.r
@@ -0,0 +1,5 @@
+line 3
+hello world
+line 4
+line5
+line 2
diff --git a/text_cmds/ed/test/k.t b/text_cmds/ed/test/k.t
new file mode 100644
index 0000000..53d588d
--- /dev/null
+++ b/text_cmds/ed/test/k.t
@@ -0,0 +1,10 @@
+2ka
+1d
+'am$
+1ka
+0a
+hello world
+.
+'ad
+u
+'am0
diff --git a/text_cmds/ed/test/k1.err b/text_cmds/ed/test/k1.err
new file mode 100644
index 0000000..eba1f3d
--- /dev/null
+++ b/text_cmds/ed/test/k1.err
@@ -0,0 +1 @@
+1,$ka
diff --git a/text_cmds/ed/test/k2.err b/text_cmds/ed/test/k2.err
new file mode 100644
index 0000000..b34a18d
--- /dev/null
+++ b/text_cmds/ed/test/k2.err
@@ -0,0 +1 @@
+kA
diff --git a/text_cmds/ed/test/k3.err b/text_cmds/ed/test/k3.err
new file mode 100644
index 0000000..70190c4
--- /dev/null
+++ b/text_cmds/ed/test/k3.err
@@ -0,0 +1 @@
+0ka
diff --git a/text_cmds/ed/test/k4.err b/text_cmds/ed/test/k4.err
new file mode 100644
index 0000000..3457642
--- /dev/null
+++ b/text_cmds/ed/test/k4.err
@@ -0,0 +1,6 @@
+a
+hello
+.
+.ka
+'ad
+'ap
diff --git a/text_cmds/ed/test/l.d b/text_cmds/ed/test/l.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/l.d
diff --git a/text_cmds/ed/test/l.r b/text_cmds/ed/test/l.r
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/l.r
diff --git a/text_cmds/ed/test/l.t b/text_cmds/ed/test/l.t
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/l.t
diff --git a/text_cmds/ed/test/m.d b/text_cmds/ed/test/m.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/m.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/m.err b/text_cmds/ed/test/m.err
new file mode 100644
index 0000000..3aec4c3
--- /dev/null
+++ b/text_cmds/ed/test/m.err
@@ -0,0 +1,4 @@
+a
+hello world
+.
+1,$m1
diff --git a/text_cmds/ed/test/m.r b/text_cmds/ed/test/m.r
new file mode 100644
index 0000000..186cf54
--- /dev/null
+++ b/text_cmds/ed/test/m.r
@@ -0,0 +1,5 @@
+line5
+line 1
+line 2
+line 3
+line 4
diff --git a/text_cmds/ed/test/m.t b/text_cmds/ed/test/m.t
new file mode 100644
index 0000000..c39c088
--- /dev/null
+++ b/text_cmds/ed/test/m.t
@@ -0,0 +1,7 @@
+1,2m$
+1,2m$
+1,2m$
+$m0
+$m0
+2,3m1
+2,3m3
diff --git a/text_cmds/ed/test/mkscripts.sh b/text_cmds/ed/test/mkscripts.sh
new file mode 100755
index 0000000..2d1a06f
--- /dev/null
+++ b/text_cmds/ed/test/mkscripts.sh
@@ -0,0 +1,75 @@
+#!/bin/sh -
+# This script generates ed test scripts (.ed) from .t files
+#
+# $FreeBSD: src/bin/ed/test/mkscripts.sh,v 1.6 1999/08/27 23:14:20 peter Exp $
+
+PATH="/bin:/usr/bin:/usr/local/bin/:."
+ED=$1
+[ ! -x $ED ] && { echo "$ED: cannot execute"; exit 1; }
+
+for i in *.t; do
+# base=${i%.*}
+# base=`echo $i | sed 's/\..*//'`
+# base=`expr $i : '\([^.]*\)'`
+# (
+# echo "#!/bin/sh -"
+# echo "$ED - <<\EOT"
+# echo "r $base.d"
+# cat $i
+# echo "w $base.o"
+# echo EOT
+# ) >$base.ed
+# chmod +x $base.ed
+# The following is pretty ugly way of doing the above, and not appropriate
+# use of ed but the point is that it can be done...
+ base=`$ED - \!"echo $i" <<-EOF
+ s/\..*
+ EOF`
+ $ED - <<-EOF
+ a
+ #!/bin/sh -
+ $ED - <<\EOT
+ H
+ r $base.d
+ w $base.o
+ EOT
+ .
+ -2r $i
+ w $base.ed
+ !chmod +x $base.ed
+ EOF
+done
+
+for i in *.err; do
+# base=${i%.*}
+# base=`echo $i | sed 's/\..*//'`
+# base=`expr $i : '\([^.]*\)'`
+# (
+# echo "#!/bin/sh -"
+# echo "$ED - <<\EOT"
+# echo H
+# echo "r $base.err"
+# cat $i
+# echo "w $base.o"
+# echo EOT
+# ) >$base-err.ed
+# chmod +x $base-err.ed
+# The following is pretty ugly way of doing the above, and not appropriate
+# use of ed but the point is that it can be done...
+ base=`$ED - \!"echo $i" <<-EOF
+ s/\..*
+ EOF`
+ $ED - <<-EOF
+ a
+ #!/bin/sh -
+ $ED - <<\EOT
+ H
+ r $base.err
+ w $base.o
+ EOT
+ .
+ -2r $i
+ w ${base}.red
+ !chmod +x ${base}.red
+ EOF
+done
diff --git a/text_cmds/ed/test/n.d b/text_cmds/ed/test/n.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/n.d
diff --git a/text_cmds/ed/test/n.r b/text_cmds/ed/test/n.r
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/n.r
diff --git a/text_cmds/ed/test/n.t b/text_cmds/ed/test/n.t
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/n.t
diff --git a/text_cmds/ed/test/nl.err b/text_cmds/ed/test/nl.err
new file mode 100644
index 0000000..8949a85
--- /dev/null
+++ b/text_cmds/ed/test/nl.err
@@ -0,0 +1 @@
+,1
diff --git a/text_cmds/ed/test/nl1.d b/text_cmds/ed/test/nl1.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/nl1.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/nl1.r b/text_cmds/ed/test/nl1.r
new file mode 100644
index 0000000..9d8854c
--- /dev/null
+++ b/text_cmds/ed/test/nl1.r
@@ -0,0 +1,8 @@
+
+
+hello world
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/nl1.t b/text_cmds/ed/test/nl1.t
new file mode 100644
index 0000000..ea192e9
--- /dev/null
+++ b/text_cmds/ed/test/nl1.t
@@ -0,0 +1,8 @@
+1
+
+
+0a
+
+
+hello world
+.
diff --git a/text_cmds/ed/test/nl2.d b/text_cmds/ed/test/nl2.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/nl2.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/nl2.r b/text_cmds/ed/test/nl2.r
new file mode 100644
index 0000000..fe99e41
--- /dev/null
+++ b/text_cmds/ed/test/nl2.r
@@ -0,0 +1,6 @@
+line 1
+line 2
+line 3
+line 4
+line5
+hello world
diff --git a/text_cmds/ed/test/nl2.t b/text_cmds/ed/test/nl2.t
new file mode 100644
index 0000000..73fd27b
--- /dev/null
+++ b/text_cmds/ed/test/nl2.t
@@ -0,0 +1,4 @@
+a
+hello world
+.
+0;/./
diff --git a/text_cmds/ed/test/p.d b/text_cmds/ed/test/p.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/p.d
diff --git a/text_cmds/ed/test/p.r b/text_cmds/ed/test/p.r
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/p.r
diff --git a/text_cmds/ed/test/p.t b/text_cmds/ed/test/p.t
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/p.t
diff --git a/text_cmds/ed/test/q.d b/text_cmds/ed/test/q.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/q.d
diff --git a/text_cmds/ed/test/q.r b/text_cmds/ed/test/q.r
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/q.r
diff --git a/text_cmds/ed/test/q.t b/text_cmds/ed/test/q.t
new file mode 100644
index 0000000..123a2c8
--- /dev/null
+++ b/text_cmds/ed/test/q.t
@@ -0,0 +1,5 @@
+w q.o
+a
+hello
+.
+q
diff --git a/text_cmds/ed/test/q1.err b/text_cmds/ed/test/q1.err
new file mode 100644
index 0000000..0a7e178
--- /dev/null
+++ b/text_cmds/ed/test/q1.err
@@ -0,0 +1 @@
+.q
diff --git a/text_cmds/ed/test/r1.d b/text_cmds/ed/test/r1.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/r1.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/r1.err b/text_cmds/ed/test/r1.err
new file mode 100644
index 0000000..269aa7c
--- /dev/null
+++ b/text_cmds/ed/test/r1.err
@@ -0,0 +1 @@
+1,$r r1.err
diff --git a/text_cmds/ed/test/r1.r b/text_cmds/ed/test/r1.r
new file mode 100644
index 0000000..a3ff506
--- /dev/null
+++ b/text_cmds/ed/test/r1.r
@@ -0,0 +1,7 @@
+line 1
+hello world
+line 2
+line 3
+line 4
+line5
+hello world
diff --git a/text_cmds/ed/test/r1.t b/text_cmds/ed/test/r1.t
new file mode 100644
index 0000000..d787a92
--- /dev/null
+++ b/text_cmds/ed/test/r1.t
@@ -0,0 +1,3 @@
+1;r !echo hello world
+1
+r !echo hello world
diff --git a/text_cmds/ed/test/r2.d b/text_cmds/ed/test/r2.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/r2.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/r2.err b/text_cmds/ed/test/r2.err
new file mode 100644
index 0000000..1c44fa3
--- /dev/null
+++ b/text_cmds/ed/test/r2.err
@@ -0,0 +1 @@
+r a-good-book
diff --git a/text_cmds/ed/test/r2.r b/text_cmds/ed/test/r2.r
new file mode 100644
index 0000000..ac152ba
--- /dev/null
+++ b/text_cmds/ed/test/r2.r
@@ -0,0 +1,10 @@
+line 1
+line 2
+line 3
+line 4
+line5
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/r2.t b/text_cmds/ed/test/r2.t
new file mode 100644
index 0000000..4286f42
--- /dev/null
+++ b/text_cmds/ed/test/r2.t
@@ -0,0 +1 @@
+r
diff --git a/text_cmds/ed/test/r3.d b/text_cmds/ed/test/r3.d
new file mode 100644
index 0000000..593eec6
--- /dev/null
+++ b/text_cmds/ed/test/r3.d
@@ -0,0 +1 @@
+r r3.t
diff --git a/text_cmds/ed/test/r3.r b/text_cmds/ed/test/r3.r
new file mode 100644
index 0000000..86d5f90
--- /dev/null
+++ b/text_cmds/ed/test/r3.r
@@ -0,0 +1,2 @@
+r r3.t
+r r3.t
diff --git a/text_cmds/ed/test/r3.t b/text_cmds/ed/test/r3.t
new file mode 100644
index 0000000..593eec6
--- /dev/null
+++ b/text_cmds/ed/test/r3.t
@@ -0,0 +1 @@
+r r3.t
diff --git a/text_cmds/ed/test/s1.d b/text_cmds/ed/test/s1.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/s1.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/s1.err b/text_cmds/ed/test/s1.err
new file mode 100644
index 0000000..d7ca0cf
--- /dev/null
+++ b/text_cmds/ed/test/s1.err
@@ -0,0 +1 @@
+s . x
diff --git a/text_cmds/ed/test/s1.r b/text_cmds/ed/test/s1.r
new file mode 100644
index 0000000..4eb0980
--- /dev/null
+++ b/text_cmds/ed/test/s1.r
@@ -0,0 +1,5 @@
+liene 1
+(liene) (2)
+(liene) (3)
+liene (4)
+(()liene5)
diff --git a/text_cmds/ed/test/s1.t b/text_cmds/ed/test/s1.t
new file mode 100644
index 0000000..b0028bb
--- /dev/null
+++ b/text_cmds/ed/test/s1.t
@@ -0,0 +1,6 @@
+s/\([^ ][^ ]*\)/(\1)/g
+2s
+/3/s
+/\(4\)/sr
+/\(.\)/srg
+%s/i/&e/
diff --git a/text_cmds/ed/test/s10.err b/text_cmds/ed/test/s10.err
new file mode 100644
index 0000000..0d8d83d
--- /dev/null
+++ b/text_cmds/ed/test/s10.err
@@ -0,0 +1,4 @@
+a
+hello
+.
+s/[h[.]/x/
diff --git a/text_cmds/ed/test/s2.d b/text_cmds/ed/test/s2.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/s2.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/s2.err b/text_cmds/ed/test/s2.err
new file mode 100644
index 0000000..b5c851d
--- /dev/null
+++ b/text_cmds/ed/test/s2.err
@@ -0,0 +1,4 @@
+a
+a
+.
+s/x*/a/g
diff --git a/text_cmds/ed/test/s2.r b/text_cmds/ed/test/s2.r
new file mode 100644
index 0000000..ca305c8
--- /dev/null
+++ b/text_cmds/ed/test/s2.r
@@ -0,0 +1,5 @@
+li(n)e 1
+i(n)e 200
+li(n)e 3
+li(n)e 4
+li(n)e500
diff --git a/text_cmds/ed/test/s2.t b/text_cmds/ed/test/s2.t
new file mode 100644
index 0000000..f365849
--- /dev/null
+++ b/text_cmds/ed/test/s2.t
@@ -0,0 +1,4 @@
+,s/./(&)/3
+s/$/00
+2s//%/g
+s/^l
diff --git a/text_cmds/ed/test/s3.d b/text_cmds/ed/test/s3.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/text_cmds/ed/test/s3.d
diff --git a/text_cmds/ed/test/s3.err b/text_cmds/ed/test/s3.err
new file mode 100644
index 0000000..d68c7d0
--- /dev/null
+++ b/text_cmds/ed/test/s3.err
@@ -0,0 +1 @@
+s/[xyx/a/
diff --git a/text_cmds/ed/test/s3.r b/text_cmds/ed/test/s3.r
new file mode 100644
index 0000000..d6cada2
--- /dev/null
+++ b/text_cmds/ed/test/s3.r
@@ -0,0 +1 @@
+hello world
diff --git a/text_cmds/ed/test/s3.t b/text_cmds/ed/test/s3.t
new file mode 100644
index 0000000..fbf8803
--- /dev/null
+++ b/text_cmds/ed/test/s3.t
@@ -0,0 +1,6 @@
+a
+hello/[]world
+.
+s/[/]/ /
+s/[[:digit:][]/ /
+s/[]]/ /
diff --git a/text_cmds/ed/test/s4.err b/text_cmds/ed/test/s4.err
new file mode 100644
index 0000000..35b609f
--- /dev/null
+++ b/text_cmds/ed/test/s4.err
@@ -0,0 +1 @@
+s/\a\b\c/xyz/
diff --git a/text_cmds/ed/test/s5.err b/text_cmds/ed/test/s5.err
new file mode 100644
index 0000000..89104c5
--- /dev/null
+++ b/text_cmds/ed/test/s5.err
@@ -0,0 +1 @@
+s//xyz/
diff --git a/text_cmds/ed/test/s6.err b/text_cmds/ed/test/s6.err
new file mode 100644
index 0000000..b478595
--- /dev/null
+++ b/text_cmds/ed/test/s6.err
@@ -0,0 +1 @@
+s
diff --git a/text_cmds/ed/test/s7.err b/text_cmds/ed/test/s7.err
new file mode 100644
index 0000000..30ba4fd
--- /dev/null
+++ b/text_cmds/ed/test/s7.err
@@ -0,0 +1,5 @@
+a
+hello world
+.
+/./
+sr
diff --git a/text_cmds/ed/test/s8.err b/text_cmds/ed/test/s8.err
new file mode 100644
index 0000000..5665767
--- /dev/null
+++ b/text_cmds/ed/test/s8.err
@@ -0,0 +1,4 @@
+a
+hello
+.
+s/[h[=]/x/
diff --git a/text_cmds/ed/test/s9.err b/text_cmds/ed/test/s9.err
new file mode 100644
index 0000000..1ff16dd
--- /dev/null
+++ b/text_cmds/ed/test/s9.err
@@ -0,0 +1,4 @@
+a
+hello
+.
+s/[h[:]/x/
diff --git a/text_cmds/ed/test/t.d b/text_cmds/ed/test/t.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/t.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/t.r b/text_cmds/ed/test/t.r
new file mode 100644
index 0000000..2b28547
--- /dev/null
+++ b/text_cmds/ed/test/t.r
@@ -0,0 +1,16 @@
+line 1
+line 1
+line 1
+line 2
+line 2
+line 3
+line 4
+line5
+line 1
+line 1
+line 1
+line 2
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/t1.d b/text_cmds/ed/test/t1.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/t1.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/t1.err b/text_cmds/ed/test/t1.err
new file mode 100644
index 0000000..c49c556
--- /dev/null
+++ b/text_cmds/ed/test/t1.err
@@ -0,0 +1 @@
+tt
diff --git a/text_cmds/ed/test/t1.r b/text_cmds/ed/test/t1.r
new file mode 100644
index 0000000..2b28547
--- /dev/null
+++ b/text_cmds/ed/test/t1.r
@@ -0,0 +1,16 @@
+line 1
+line 1
+line 1
+line 2
+line 2
+line 3
+line 4
+line5
+line 1
+line 1
+line 1
+line 2
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/t1.t b/text_cmds/ed/test/t1.t
new file mode 100644
index 0000000..6b66163
--- /dev/null
+++ b/text_cmds/ed/test/t1.t
@@ -0,0 +1,3 @@
+1t0
+2,3t2
+,t$
diff --git a/text_cmds/ed/test/t2.d b/text_cmds/ed/test/t2.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/t2.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/t2.err b/text_cmds/ed/test/t2.err
new file mode 100644
index 0000000..c202051
--- /dev/null
+++ b/text_cmds/ed/test/t2.err
@@ -0,0 +1 @@
+t0;-1
diff --git a/text_cmds/ed/test/t2.r b/text_cmds/ed/test/t2.r
new file mode 100644
index 0000000..0c75ff5
--- /dev/null
+++ b/text_cmds/ed/test/t2.r
@@ -0,0 +1,6 @@
+line 1
+line5
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/t2.t b/text_cmds/ed/test/t2.t
new file mode 100644
index 0000000..5175abd
--- /dev/null
+++ b/text_cmds/ed/test/t2.t
@@ -0,0 +1 @@
+t0;/./
diff --git a/text_cmds/ed/test/u.d b/text_cmds/ed/test/u.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/u.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/u.err b/text_cmds/ed/test/u.err
new file mode 100644
index 0000000..caa1ba1
--- /dev/null
+++ b/text_cmds/ed/test/u.err
@@ -0,0 +1 @@
+.u
diff --git a/text_cmds/ed/test/u.r b/text_cmds/ed/test/u.r
new file mode 100644
index 0000000..ad558d8
--- /dev/null
+++ b/text_cmds/ed/test/u.r
@@ -0,0 +1,9 @@
+line 1
+hello
+hello world!!
+line 2
+line 3
+line 4
+line5
+hello
+hello world!!
diff --git a/text_cmds/ed/test/u.t b/text_cmds/ed/test/u.t
new file mode 100644
index 0000000..131cb6e
--- /dev/null
+++ b/text_cmds/ed/test/u.t
@@ -0,0 +1,31 @@
+1;r u.t
+u
+a
+hello
+world
+.
+g/./s//x/\
+a\
+hello\
+world
+u
+u
+u
+a
+hello world!
+.
+u
+1,$d
+u
+2,3d
+u
+c
+hello world!!
+.
+u
+u
+-1;.,+1j
+u
+u
+u
+.,+1t$
diff --git a/text_cmds/ed/test/v.d b/text_cmds/ed/test/v.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/v.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/v.r b/text_cmds/ed/test/v.r
new file mode 100644
index 0000000..714db63
--- /dev/null
+++ b/text_cmds/ed/test/v.r
@@ -0,0 +1,11 @@
+line5
+order
+hello world
+line 1
+order
+line 2
+order
+line 3
+order
+line 4
+order
diff --git a/text_cmds/ed/test/v.t b/text_cmds/ed/test/v.t
new file mode 100644
index 0000000..608a77f
--- /dev/null
+++ b/text_cmds/ed/test/v.t
@@ -0,0 +1,6 @@
+v/[ ]/m0
+v/[ ]/s/$/\
+hello world
+v/hello /s/lo/p!/\
+a\
+order
diff --git a/text_cmds/ed/test/w.d b/text_cmds/ed/test/w.d
new file mode 100644
index 0000000..92f337e
--- /dev/null
+++ b/text_cmds/ed/test/w.d
@@ -0,0 +1,5 @@
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/w.r b/text_cmds/ed/test/w.r
new file mode 100644
index 0000000..ac152ba
--- /dev/null
+++ b/text_cmds/ed/test/w.r
@@ -0,0 +1,10 @@
+line 1
+line 2
+line 3
+line 4
+line5
+line 1
+line 2
+line 3
+line 4
+line5
diff --git a/text_cmds/ed/test/w.t b/text_cmds/ed/test/w.t
new file mode 100644
index 0000000..c2e18bd
--- /dev/null
+++ b/text_cmds/ed/test/w.t
@@ -0,0 +1,2 @@
+w !cat >\!.z
+r \!.z
diff --git a/text_cmds/ed/test/w1.err b/text_cmds/ed/test/w1.err
new file mode 100644
index 0000000..e2c8a60
--- /dev/null
+++ b/text_cmds/ed/test/w1.err
@@ -0,0 +1 @@
+w /to/some/far-away/place
diff --git a/text_cmds/ed/test/w2.err b/text_cmds/ed/test/w2.err
new file mode 100644
index 0000000..9daf89c
--- /dev/null
+++ b/text_cmds/ed/test/w2.err
@@ -0,0 +1 @@
+ww.o
diff --git a/text_cmds/ed/test/w3.err b/text_cmds/ed/test/w3.err
new file mode 100644
index 0000000..39bbf4c
--- /dev/null
+++ b/text_cmds/ed/test/w3.err
@@ -0,0 +1 @@
+wqp w.o
diff --git a/text_cmds/ed/test/x.err b/text_cmds/ed/test/x.err
new file mode 100644
index 0000000..0953f01
--- /dev/null
+++ b/text_cmds/ed/test/x.err
@@ -0,0 +1 @@
+.x
diff --git a/text_cmds/ed/test/z.err b/text_cmds/ed/test/z.err
new file mode 100644
index 0000000..6a51a2d
--- /dev/null
+++ b/text_cmds/ed/test/z.err
@@ -0,0 +1,2 @@
+z
+z
diff --git a/text_cmds/ed/undo.c b/text_cmds/ed/undo.c
new file mode 100644
index 0000000..2837495
--- /dev/null
+++ b/text_cmds/ed/undo.c
@@ -0,0 +1,150 @@
+/* undo.c: This file contains the undo routines for the ed line editor */
+/*-
+ * Copyright (c) 1993 Andrew Moore, Talke Studio.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/ed/undo.c,v 1.12 2002/06/30 05:13:53 obrien Exp $");
+
+#include "ed.h"
+
+
+#define USIZE 100 /* undo stack size */
+undo_t *ustack = NULL; /* undo stack */
+long usize = 0; /* stack size variable */
+long u_p = 0; /* undo stack pointer */
+
+/* push_undo_stack: return pointer to initialized undo node */
+undo_t *
+push_undo_stack(int type, long from, long to)
+{
+ undo_t *t;
+
+#if defined(sun) || defined(NO_REALLOC_NULL)
+ if (ustack == NULL &&
+ (ustack = (undo_t *) malloc((usize = USIZE) * sizeof(undo_t))) == NULL) {
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ return NULL;
+ }
+#endif
+ t = ustack;
+ if (u_p < usize ||
+ (t = (undo_t *) realloc(ustack, (usize += USIZE) * sizeof(undo_t))) != NULL) {
+ ustack = t;
+ ustack[u_p].type = type;
+ ustack[u_p].t = get_addressed_line_node(to);
+ ustack[u_p].h = get_addressed_line_node(from);
+ return ustack + u_p++;
+ }
+ /* out of memory - release undo stack */
+ fprintf(stderr, "%s\n", strerror(errno));
+ errmsg = "out of memory";
+ clear_undo_stack();
+ free(ustack);
+ ustack = NULL;
+ usize = 0;
+ return NULL;
+}
+
+
+/* USWAP: swap undo nodes */
+#define USWAP(x,y) { \
+ undo_t utmp; \
+ utmp = x, x = y, y = utmp; \
+}
+
+
+long u_current_addr = -1; /* if >= 0, undo enabled */
+long u_addr_last = -1; /* if >= 0, undo enabled */
+
+/* pop_undo_stack: undo last change to the editor buffer */
+int
+pop_undo_stack(void)
+{
+ long n;
+ long o_current_addr = current_addr;
+ long o_addr_last = addr_last;
+
+ if (u_current_addr == -1 || u_addr_last == -1) {
+ errmsg = "nothing to undo";
+ return ERR;
+ } else if (u_p)
+ modified = 1;
+ get_addressed_line_node(0); /* this get_addressed_line_node last! */
+ SPL1();
+ for (n = u_p; n-- > 0;) {
+ switch(ustack[n].type) {
+ case UADD:
+ REQUE(ustack[n].h->q_back, ustack[n].t->q_forw);
+ break;
+ case UDEL:
+ REQUE(ustack[n].h->q_back, ustack[n].h);
+ REQUE(ustack[n].t, ustack[n].t->q_forw);
+ break;
+ case UMOV:
+ case VMOV:
+ REQUE(ustack[n - 1].h, ustack[n].h->q_forw);
+ REQUE(ustack[n].t->q_back, ustack[n - 1].t);
+ REQUE(ustack[n].h, ustack[n].t);
+ n--;
+ break;
+ default:
+ /*NOTREACHED*/
+ ;
+ }
+ ustack[n].type ^= 1;
+ }
+ /* reverse undo stack order */
+ for (n = u_p; n-- > (u_p + 1)/ 2;)
+ USWAP(ustack[n], ustack[u_p - 1 - n]);
+ if (isglobal)
+ clear_active_list();
+ current_addr = u_current_addr, u_current_addr = o_current_addr;
+ addr_last = u_addr_last, u_addr_last = o_addr_last;
+ SPL0();
+ return 0;
+}
+
+
+/* clear_undo_stack: clear the undo stack */
+void
+clear_undo_stack(void)
+{
+ line_t *lp, *ep, *tl;
+
+ while (u_p--)
+ if (ustack[u_p].type == UDEL) {
+ ep = ustack[u_p].t->q_forw;
+ for (lp = ustack[u_p].h; lp != ep; lp = tl) {
+ unmark_line_node(lp);
+ tl = lp->q_forw;
+ free(lp);
+ }
+ }
+ u_p = 0;
+ u_current_addr = current_addr;
+ u_addr_last = addr_last;
+}
diff --git a/text_cmds/ee/Changes b/text_cmds/ee/Changes
new file mode 100644
index 0000000..0f2c8ab
--- /dev/null
+++ b/text_cmds/ee/Changes
@@ -0,0 +1,40 @@
+version 1.5.0 (2/16/2009)
+- added display of line number, column, and lines from top to separator line
+ for info window
+- minor changes to reduce number of warnings when using -pedantic option
+
+version 1.4.7 (2/10/2009)
+- changed how strings are terminated from the old usage of NULL to the current
+ use of character zero, '\0'
+- changed the licensing since the Artistic License is now considered
+ restrictive
+
+version 1.4.6
+- modified new_curse.c to handle different subdirectory naming in terminfo
+ directory; first noted on Mac OS 10.2
+
+version 1.4.5a (12/23/2001)
+- modified get_options to be cleaner for arg handling
+
+version 1.4.5 (12/15/2001)
+- made changes to check usage of arguments provided so that if a file is
+ specified options are no longer accepted (that is, they are treated as file
+ names)
+- changed to use ee_version.h to allow changing version number without need
+ to change ee.c directly
+
+version 1.4.4 (8/17/2001)
+- added code to check if the parent process has died, and if so to exit
+ gracefully
+
+version 1.4.3 (6/25/2001)
+- modified create.make and new_curse.c to allow defining TERMCAP file
+ location (since some distributions move the file)
+- source directory now has version number attached to directory name
+
+version 1.4.2 (1/19/2001)
+- change to create.make script to add unistd.h to files to search for
+ select() declaration
+- change to new_curse.c for proper raw mode operation
+
+
diff --git a/text_cmds/ee/Makefile b/text_cmds/ee/Makefile
new file mode 100644
index 0000000..a6525ea
--- /dev/null
+++ b/text_cmds/ee/Makefile
@@ -0,0 +1,29 @@
+# This is the make file for ee, the "easy editor".
+#
+# A file called 'make.local' will be generated which will contain information
+# specific to the local system, such as if it is a BSD or System V based
+# version of UNIX, whether or not it has catgets, or select.
+#
+# The "install" target ("make install") will copy the ee binary to
+# the /usr/local/bin directory on the local system. The man page (ee.1)
+# will be copied into the /usr/local/man/man1 directory.
+#
+# The "clean" target ("make clean") will remove the ee and new_curse.o
+# object files, and the ee binary.
+#
+
+all : localmake buildee
+
+buildee :
+ make -f make.local
+
+localmake:
+ @./create.make
+
+install :
+ cp ee /usr/local/bin/ee
+ cp ee.1 /usr/local/man/man1/ee.1
+
+clean :
+ rm -f ee.o new_curse.o ee
+
diff --git a/text_cmds/ee/README.ee b/text_cmds/ee/README.ee
new file mode 100644
index 0000000..bbb932f
--- /dev/null
+++ b/text_cmds/ee/README.ee
@@ -0,0 +1,119 @@
+Copyright (c) 2009, Hugh Mahon
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
+The editor 'ee' (easy editor) is intended to be a simple, easy to use
+terminal-based screen oriented editor that requires no instruction to
+use. Its primary use would be for people who are new to computers, or who
+use computers only for things like e-mail.
+
+ee's simplified interface is highlighted by the use of pop-up menus which
+make it possible for users to carry out tasks without the need to
+remember commands. An information window at the top of the screen shows
+the user the operations available with control-keys.
+
+ee allows users to use full eight-bit characters. If the host system has
+the capabilities, ee can use message catalogs, which would allow users to
+translate the message catalog into other languages which use eight-bit
+characters. See the file ee.i18n.guide for more details.
+
+ee relies on the virtual memory abilities of the platform it is running on
+and does not have its own memory management capabilities.
+
+I am releasing ee because I hate to see new users and non-computer types
+get frustrated by vi, and would like to see more intuitive interfaces for
+basic tools (both character-based and graphical) become more pervasive.
+Terminal capabilities and communication speeds have evolved considerably
+since the time in which vi's interface was created, allowing much more
+intuitive interfaces to be used. Since character-based I/O won't be
+completely replaced by graphical user interfaces for at least a few more
+years, I'd like to do what I can to make using computers with less
+glamorous interfaces as easy to use as possible. If terminal interfaces
+are still used in ten years, I hope neophytes won't still be stuck with
+only vi.
+
+For a text editor to be easy to use requires a certain set of abilities. In
+order for ee to work, a terminal must have the ability to position the cursor
+on the screen, and should have arrow keys that send unique sequences
+(multiple characters, the first character is an "escape", octal code
+'\033'). All of this information needs to be in a database called "terminfo"
+(System V implementations) or "termcap" (usually used for BSD systems). In
+case the arrow keys do not transmit unique sequences, motion operations are
+mapped to control keys as well, but this at least partially defeats the
+purpose. The curses package is used to handle the I/O which deals with the
+terminal's capabilities.
+
+While ee is based on curses, I have included here the source code to
+new_curse, a subset of curses developed for use with ee. 'curses' often
+will have a defect that reduces the usefulness of the editor relying upon
+it.
+
+The file new_curse.c contains a subset of 'curses', a package for
+applications to use to handle screen output. Unfortunately, curses
+varies from system to system, so I developed new_curse to provide
+consistent behavior across systems. It works on both SystemV and BSD
+systems, and while it can sometimes be slower than other curses packages,
+it will get the information on the screen painted correctly more often
+than vendor supplied curses. Unless problems occur during the building
+of ee, it is recommended that you use new_curse rather than the curses
+supplied with your system.
+
+If you experience problems with data being displayed improperly, check
+your terminal configuration, especially if you're using a terminal
+emulator, and make sure that you are using the right terminfo entry
+before rummaging through code. Terminfo entries often contain
+inaccuracies, or incomplete information, or may not totally match the
+terminal or emulator the terminal information is being used with.
+Complaints that ee isn't working quite right often end up being something
+else (like the terminal emulator being used).
+
+Both ee and new_curse were developed using K&R C (also known as "classic
+C"), but it can also be compiled with ANSI C. You should be able to
+build ee by simply typing "make". A make file which takes into account
+the characteristics of your system will be created, and then ee will be
+built. If there are problems encountered, you will be notified about
+them.
+
+ee is the result of several conflicting design goals. While I know that it
+solves the problems of some users, I also have no doubt that some will decry
+its lack of more features. I will settle for knowing that ee does fulfill
+the needs of a minority (but still large number) of users. The goals of ee
+are:
+
+ 1. To be so easy to use as to require no instruction.
+ 2. To be easy to compile and, if necessary, port to new platforms
+ by people with relatively little knowledge of C and UNIX.
+ 3. To have a minimum number of files to be dealt with, for compile
+ and installation.
+ 4. To have enough functionality to be useful to a large number of
+ people.
+
+Hugh Mahon |___|
+hugh4242@yahoo.com | |
+ |\ /|
+ | \/ |
+
diff --git a/text_cmds/ee/create.make b/text_cmds/ee/create.make
new file mode 100755
index 0000000..5d6ec30
--- /dev/null
+++ b/text_cmds/ee/create.make
@@ -0,0 +1,292 @@
+#!/bin/sh
+
+#
+# This script will determine if the system is a System V or BSD based
+# UNIX system and create a makefile for ee appropriate for the system.
+#
+# $Header: /home/hugh/sources/old_ae/RCS/create.make,v 1.13 2002/09/23 04:18:13 hugh Exp $
+#
+
+#set -x
+
+name_string="`uname`"
+
+# test for existence of termcap (exists on both BSD and SysV systems)
+
+if [ -f /etc/termcap -o -f /usr/share/lib/termcap -o -f /usr/share/misc/termcap ]
+then
+ if [ -f /usr/share/lib/termcap ]
+ then
+ termcap_exists="-DTERMCAP=\"\\\"/usr/share/lib/termcap\\\"\""
+ elif [ -f /usr/share/misc/termcap ]
+ then
+ termcap_exists="-DTERMCAP=\"\\\"/usr/share/misc/termcap\\\"\""
+ elif [ -f /etc/termcap ]
+ then
+ termcap_exists="-DTERMCAP=\"\\\"/etc/termcap\\\"\""
+ fi
+else
+ termcap_exists=""
+fi
+
+# test for terminfo directory (exists on SysV systems)
+
+if [ -d /usr/lib/terminfo -o -d /usr/share/lib/terminfo -o -d /usr/share/terminfo ]
+then
+ terminfo_exists=""
+else
+ terminfo_exists="-DCAP"
+fi
+
+# test for existence of termio header (on SysV systems)
+
+if [ -f /usr/include/termio.h ]
+then
+ termio="-DSYS5"
+else
+ termio=""
+fi
+
+# test for sgtty header (on BSD systems)
+
+if [ -f /usr/include/sgtty.h ]
+then
+ sgtty="TRUE"
+else
+ sgtty=""
+fi
+
+# look for select call in headers, make sure headers exist
+
+HEADER_FILES=""
+
+if [ -f /usr/include/sys/time.h ]
+then
+ HEADER_FILES="/usr/include/sys/time.h "
+fi
+
+if [ -f /usr/include/sys/types.h ]
+then
+ HEADER_FILES="$HEADER_FILES /usr/include/sys/types.h"
+fi
+
+# check for unistd.h
+
+if [ -f /usr/include/unistd.h ]
+then
+ HAS_UNISTD=-DHAS_UNISTD
+ HEADER_FILES="$HEADER_FILES /usr/include/unistd.h"
+else
+ HAS_UNISTD=""
+fi
+
+if [ -n "$HEADER_FILES" ]
+then
+ string="`grep select $HEADER_FILES`"
+ if [ -n "$string" ]
+ then
+ BSD_SELECT="-DBSD_SELECT"
+ else
+ BSD_SELECT=""
+ fi
+fi
+
+# check for existence of select.h (on AIX)
+
+if [ -f /usr/include/sys/select.h ]
+then
+ select_hdr="-DSLCT_HDR"
+else
+ select_hdr=""
+fi
+
+# check for stdlib.h
+
+if [ -f /usr/include/stdlib.h ]
+then
+ HAS_STDLIB=-DHAS_STDLIB
+else
+ HAS_STDLIB=""
+fi
+
+# check for stdarg.h
+
+if [ -f /usr/include/stdarg.h ]
+then
+ HAS_STDARG=-DHAS_STDARG
+else
+ HAS_STDARG=""
+fi
+
+# check for ctype.h
+
+if [ -f /usr/include/ctype.h ]
+then
+ HAS_CTYPE=-DHAS_CTYPE
+else
+ HAS_CTYPE=""
+fi
+
+# check for sys/ioctl.h
+
+if [ -f /usr/include/sys/ioctl.h ]
+then
+ HAS_SYS_IOCTL=-DHAS_SYS_IOCTL
+else
+ HAS_SYS_IOCTL=""
+fi
+
+# check for sys/wait.h
+
+if [ -f /usr/include/sys/wait.h ]
+then
+ HAS_SYS_WAIT=-DHAS_SYS_WAIT
+else
+ HAS_SYS_WAIT=""
+fi
+
+# check for localization headers
+
+if [ -f /usr/include/locale.h -a -f /usr/include/nl_types.h ]
+then
+ catgets=""
+else
+ catgets="-DNO_CATGETS"
+fi
+
+# make decisions about use of new_curse.c (use of new_curse is recommended
+# rather than local curses)
+
+if [ -n "$terminfo_exists" -a -z "$termcap_exists" ]
+then
+ echo "Neither terminfo or termcap are on this system! "
+ if [ -f /usr/include/curses.h ]
+ then
+ echo "Relying on local curses implementation."
+ else
+ cat <<-EOF
+ Don't know where to find curses, you'll need to modify
+ source code to be able to build!
+
+ Modify the file make.default and build ee by typing:
+
+ make -f make.default
+
+ EOF
+
+ exit 1
+ fi
+
+ TARGET="curses"
+ curses=""
+else
+ curses="-DNCURSE"
+ TARGET="ee"
+fi
+
+if [ -z "$termio" -a -z "$sgtty" ]
+then
+ echo "Neither termio.h or sgtty.h are on this system! "
+ if [ -f /usr/include/curses.h ]
+ then
+ echo "Relying on local curses implementation."
+ else
+ cat <<-EOF
+ Don't know where to find curses, you'll need to modify
+ source code to be able to build!
+
+ Modify the file make.default and build ee by typing:
+
+ make -f make.default
+
+ EOF
+
+ exit 1
+ fi
+
+ TARGET="curses"
+ curses=""
+fi
+
+# check if this is a SunOS system
+
+if [ -d /usr/5include ]
+then
+ five_include="-I/usr/5include"
+else
+ five_include=""
+fi
+
+if [ -d /usr/5lib ]
+then
+ five_lib="-L/usr/5lib"
+else
+ five_lib=""
+fi
+
+
+if [ "$name_string" = "Darwin" ]
+then
+ if [ -n "$CFLAGS" ]
+ then
+ other_cflags="${CFLAGS} -DNO_CATGETS"
+ else
+ other_cflags="-DNO_CATGETS"
+ fi
+else
+
+ if [ -n "$CFLAGS" ]
+ then
+ if [ -z "`echo $CFLAGS | grep '[-]g'`" ]
+ then
+ other_cflags="${CFLAGS} -s"
+ else
+ other_cflags="${CFLAGS}"
+ fi
+ else
+ other_cflags="-s"
+ fi
+fi
+
+# time to write the makefile
+
+echo "Generating make.local"
+
+if [ -f make.local ]
+then
+ mv make.local make.lcl.old
+fi
+
+echo "DEFINES = $termio $terminfo_exists $BSD_SELECT $catgets $select $curses " > make.local
+echo "" >> make.local
+echo "CFLAGS = $HAS_UNISTD $HAS_STDARG $HAS_STDLIB $HAS_CTYPE $HAS_SYS_IOCTL $HAS_SYS_WAIT $five_lib $five_include $select_hdr $other_cflags $termcap_exists" >> make.local
+echo "" >> make.local
+echo "" >> make.local
+echo "all : $TARGET" >> make.local
+
+cat >> make.local << EOF
+
+curses : ee.c
+ cc ee.c -o ee \$(CFLAGS) -lcurses
+
+ee : ee.o new_curse.o
+ cc -o ee ee.o new_curse.o \$(CFLAGS)
+
+ee.o : ee.c new_curse.h
+ cc -c ee.c \$(DEFINES) \$(CFLAGS)
+
+new_curse.o : new_curse.c new_curse.h
+ cc new_curse.c -c \$(DEFINES) \$(CFLAGS)
+
+EOF
+
+if [ -f make.lcl.old ]
+then
+ diffs="`cmp make.lcl.old make.local`"
+ if [ -n "${diffs}" ]
+ then
+ rm -f ee.o new_curse.o ee
+ fi
+ rm -f make.lcl.old
+fi
+
diff --git a/text_cmds/ee/ee.1 b/text_cmds/ee/ee.1
new file mode 100644
index 0000000..d6558a1
--- /dev/null
+++ b/text_cmds/ee/ee.1
@@ -0,0 +1,543 @@
+.\"
+.\"
+.\" To format this reference page, use the command:
+.\"
+.\" nroff -man ee.1
+.\"
+.\" $Header: /home/hugh/sources/old_ae/RCS/ee.1,v 1.22 2001/12/16 04:49:27 hugh Exp $
+.\"
+.\"
+.TH ee 1 "" "" ""
+.SH NAME
+ee \- easy editor
+.SH SYNOPSIS
+.nf
+ee [-e] [-i] [-h] [+#] [\fIfile\fR ...]
+ree [-e] [-i] [-h] [+#] [\fIfile\fR ...]
+.ta
+.fi
+.ad b
+.SH DESCRIPTION
+The command
+.I ee
+is a simple screen oriented text editor. It is always in text insertion
+mode unless there is a prompt at the bottom of the terminal, or a
+menu present (in a box in the middle of the terminal). The command
+.I ree
+is the same as
+.I ee,
+but restricted to editing the named
+file (no file operations, or shell escapes are allowed).
+.PP
+An editor with similar user-friendly qualities but more features is available
+and is called
+.I aee.
+.PP
+For
+.I ee
+to work properly, the environment variable
+.SM TERM
+must be set to indicate the type of terminal being used. For
+example, for an
+.SM HP 700/92
+terminal, the
+.SM TERM
+variable should be set to "70092". See your System Administrator if
+you need more information.
+.\"
+.\" options
+.\"
+.SS Options
+The following options are available from the command line:
+.PP
+.TP 4
+.B -e
+Turns off expansion of tab character to spaces.
+.TP
+.B -i
+Turns off display of information window at top of terminal.
+.TP
+.B -h
+Turns off highlighting of borders of windows and menus (improves
+performance on some terminals).
+.TP
+.B +#
+Moves the cursor to line '#' at startup.
+.br
+.\"
+.\" control keys
+.\"
+.SS "Control keys"
+To do anything other than insert text, the user must use the control
+keys (the
+.B Control
+key, represented by a "^", pressed in conjunction with an
+alphabetic key, e.g., ^a) and function keys available on the keyboard
+(such as
+.BR "Next Page" ", " "Prev Page" ,
+arrow keys, etc.).
+.PP
+Since not all terminals have function keys,
+.I ee
+has the basic cursor movement functions assigned to control keys as
+well as more intuitive keys on the keyboard when available. For
+instance, to move the cursor up, the user can use the up arrow key,
+or
+.BR ^u .
+.RS 4
+.nf
+.ta 1.4i
+.sp
+^a Prompt for the decimal value of a character to insert.
+^b Move to the bottom of the text.
+^c Get the prompt for a command.
+^d Move the cursor down.
+^e Prompt for the string to search for.
+^f Undelete the last deleted character.
+^g Move to the beginning of the line.
+^h Backspace.
+^i Tab.
+^j Insert a newline.
+^k Delete the character the cursor is sitting on.
+^l Move the cursor left.
+^m Insert a newline.
+^n Move to the next page.
+^o Move to the end of the line.
+^p Move to the previous page.
+^r Move the cursor to the right.
+^t Move to the top of the text.
+^u Move the cursor up.
+^v Undelete the last deleted word.
+^w Delete the word beginning at the cursor position.
+^x Search.
+^y Delete from the cursor position to the end of line.
+^z Undelete the last deleted line.
+^[ (ESC) Pop up menu.
+.ta
+.fi
+.RE
+.sp
+.SS "EMACS keys mode"
+.PP
+Since many shells provide an Emacs mode (for cursor movement and other editing
+operations), some bindings that may be more useful for people familiar with
+those bindings have been provided. These are accessible via the
+.B settings
+menu, or via the initialization file (see below). The mappings are as follows:
+.RS
+.nf
+.ta 1.4i
+^a Move to the beginning of the line.
+^b Back 1 character.
+^c Command prompt.
+^d Delete character the cursor is sitting on.
+^e End of line.
+^f Forward 1 character.
+^g Go back 1 page.
+^h Backspace.
+^i Tab.
+^j Undelete last deleted character.
+^k Delete line.
+^l Undelete last deleted line.
+^m Insert a newline.
+^n Move to the next line.
+^o Prompt for the decimal value of a character to insert.
+^p Previous line.
+^r Restore last deleted word.
+^t Move to the top of the text.
+^u Move to the bottom of the text.
+^v Move to the next page.
+^w Delete the word beginning at the cursor position.
+^y Prompt for the string to search for.
+^z Next word.
+^[ (ESC) Pop up menu.
+.ta
+.fi
+.RE
+.sp
+.\"
+.\" function keys
+.\"
+.SS "Function Keys"
+.RS 4
+.IP "\fBNext Page\fR"
+Move to the next page.
+.IP "\fBPrev Page\fR"
+Move to the previous page.
+.IP "\fBDelete Char\fR"
+Delete the character the cursor is on.
+.IP "\fBDelete Line\fR"
+Delete from the cursor to the end of line.
+.IP "\fBInsert line\fR"
+Insert a newline at the cursor position.
+.IP "\fBArrow keys\fR"
+Move the cursor in the direction indicated.
+.RE
+.\"
+.\" commands
+.\"
+.SS Commands
+.PP
+Some operations require more information than a single keystroke can
+provide. For the most basic operations, there is a menu that can be
+obtained by pressing the
+.SM \fBESC\fR
+key. The same operations, and more can be performed by obtaining the
+command prompt (^c) and typing in one of the commands below.
+.RS 4
+.IP "!\fBcmd\fR"
+Execute \fBcmd\fR in a shell.
+.IP "\fB0-9\fR"
+Move to the line indicated.
+.IP "\fBcase\fR"
+Make searches case sensitive.
+.IP "\fBcharacter\fR"
+Display the ascii value of the character at the cursor.
+.IP "\fBexit\fR"
+Save the edited text, and leave the editor.
+.IP "\fBexpand\fR"
+Expand tabs to spaces.
+.IP "\fBfile\fR"
+Print the name of the file.
+.IP "\fBhelp\fR"
+Display help screen.
+.IP "\fBline\fR"
+Display the current line number.
+.IP "\fBnocase\fR
+Make searches insensitive to case (the default).
+.IP "\fBnoexpand\fR"
+Don't expand tab to spaces when the TAB key is pressed.
+.IP "\fBquit\fR"
+Leave the editor without saving changes.
+.IP "\fBread\fR \fIfile\fR"
+Read the named \fIfile\fR.
+.IP "\fBwrite\fR \fIfile\fR"
+Write the text to the named \fIfile\fR.
+.RE
+.\"
+.\" menu operations
+.\"
+.SS "Menu Operations"
+.PP
+Pop-up menus can be obtained by pressing the
+.B escape
+key (or
+.B ^[
+if no
+.B escape
+key is present). When in the menu, the escape key can be
+used to leave the menu without performing any operations. Use the up and
+down arrow keys, or
+.B ^u
+for moving up and
+.B ^d
+for moving down to move to the desired items in the menu, then press
+.B return
+to perform the indicated task.
+.PP
+To the left of each menu item is a letter, which if the corresponding
+letter is pressed on the keyboard selects that menu entry.
+.PP
+The main menu in \fIee\fR is as follows:
+.RS 4
+.IP "\fBleave editor\fR"
+If changes have been made, the user will get a menu prompting whether or
+not the changes should be saved.
+.IP "\fBhelp\fR"
+Displays a help screen, with all of the keyboard operations and commands.
+.IP "\fBfile operations\fR"
+Pops up a menu for selecting whether to read a file, write to a file, or
+save the current contents of the editor, as well as send the contents of
+the editor to a print command (see the section \fBInitializing ee from a
+file\fR).
+.IP "\fBredraw screen\fR"
+Provides a means to repaint the screen if the screen has been corrupted.
+.IP "\fBsettings\fR"
+Shows the current values of the operating modes, and right margin. By
+pressing return when the cursor is on a particular item, the value can be
+changed. To leave this menu, press the \fBescape\fR key. (See \fBModes\fR
+below.)
+.IP "\fBsearch\fR"
+.br
+Pops up a menu in which the user may choose to enter a string to search
+for, or search for a string already entered.
+.IP "\fBmiscellaneous\fR"
+Pops up a menu that allows the user to format the current paragraph,
+execute a shell command, or check the spelling of the text in the editor.
+.RE
+.\"
+.\" paragraph formatting
+.\"
+.SS "Paragraph Formatting"
+.PP
+Paragraphs are defined for \fIee\fR by a block of text bounded by:
+.sp
+.RS 8
+.IP \(bu
+Begin or end of file.
+.IP \(bu
+Line with no characters, or only spaces and/or tabs.
+.IP \(bu
+Line starting with a period ('.') or right angle bracket ('>').
+.RE
+.PP
+A paragraph may be formatted two ways: explicitly by choosing the
+\fBformat paragraph\fR menu item, or by setting \fIee\fR to automatically
+format paragraphs. The automatic mode may be set via a menu, or via the
+initialization file.
+.PP
+There are three states for text operation in \fIee\fR: free-form, margins,
+and automatic formatting.
+.PP
+"Free-form" is best used for things like programming. There are no
+restrictions on the length of lines, and no formatting takes place.
+.PP
+"Margins" allows the user to type in text without having to worry about going
+beyond the right margin (the right margin may be set in the \fBsettings\fR
+menu, the default is for the margin to be the right edge of the
+terminal). This is the mode that allows the \fBformat paragraph\fR menu
+item to work.
+.PP
+"Automatic formatting" provides word-processor-like behavior. The user
+may type in text, while \fIee\fR will make sure the entire paragraph fits
+within the width of the terminal every time the user inserts a space after
+typing or deleting text. Margin observation must also be enabled in order for
+automatic formatting to occur.
+.\"
+.\" modes
+.\"
+.SS Modes
+.PP
+Although ee is a 'modeless' editor (it is in text insertion mode all the
+time), there are modes in some of the things it does. These include:
+.RS 4
+.IP "\fBtab expansion\fR"
+Tabs may be inserted as a single tab character, or replaced with spaces.
+.IP "\fBcase sensitivity\fR"
+The search operation can be sensitive to whether characters are upper- or
+lower-case, or ignore case completely.
+.IP "\fBmargins observed\fR"
+Lines can either be truncated at the right margin, or extend on forever.
+.IP "\fBauto paragraph formatting\fR"
+While typing in text, the editor can try to keep it looking reasonably well
+within the width of the screen.
+.IP "\fBeightbit characters\fR"
+Toggles whether eight bit characters are displayed as their value in angle
+brackets (e.g. "<220>") or as a character.
+.IP "\fBinfo window\fR"
+A window showing the keyboard operations that can be performed can be
+displayed or not.
+.IP "\fBemacs keys\fR"
+Control keys may be given bindings similar to emacs, or not.
+.IP "\fB16 bit characters\fR"
+Toggles whether sixteen bit characters are handled as one 16-bit quantity or
+two 8-bit quantities. This works primarily with the Chinese Big 5 code set.
+.RE
+.PP
+You may set these modes via the initialization file (see below), or with a
+menu (see above).
+.\"
+.\" spell checking
+.\"
+.SS "Spell Checking"
+.PP
+There are two ways to have the spelling in the text checked from \fIee\fR.
+One is by the traditional \fIspell\fR(1) command, the other is with the
+optional \fIispell\fR(1) command.
+.PP
+Using \fIspell\fR, the words that are not recognized will be placed at the top
+of the file. For the \fIispell\fR option, the file is written to disk,
+then \fIispell\fR run on the file, and the file read back in once
+\fIispell\fR has completed making changes to the file.
+.\"
+.\" printing
+.\"
+.SS "Printing the contents of the editor"
+.PP
+The user may select a menu item which prints the contents of the editor.
+.I ee
+pipes the text in the editor to the command specified by the
+initialization command
+.B printcommand
+(see the section
+.B Initializing ee from a file
+below). The default is to send the contents to "lp".
+.PP
+Whatever the user assigns to
+.B printcommand
+must take input from
+standard input. See your system administrator for more details.
+.\"
+.\" shell operations
+.\"
+.SS "Shell operations"
+.PP
+Shell commands can be executed from within
+.I ee
+by selecting the
+.B shell command
+item in the
+.B miscellaneous
+menu, or by placing an exclamation mark ("!") before the command to
+execute at the
+.B command:
+prompt. Additionally, the user may direct the contents of the edit buffer
+out to a shell operation (via a pipe) by using the left angle bracket
+(">"), followed by a "!" and the shell command to execute. The output of
+a shell operation can also be directed into the edit buffer by using a
+right angle bracket ("<") before the exclamation mark. These can even be
+used together to send output to a shell operation and read back the
+results into the editor. So, if the editor contained a list of words
+to be sorted, they could be sorted by typing the following at the command
+prompt:
+.RS 4
+.sp
+><!sort
+.sp
+.RE
+This would send the contents of the editor to be piped into the
+.I sort
+utility and the result would be placed into the edit buffer at the current
+cursor location. The old information would have to be deleted by the user.
+.\"
+.\" initializing ee from a file
+.\"
+.SS "Initializing ee from a file"
+.PP
+Since different users have different preferences, \fIee\fR allows some
+slight configurability. There are three possible locations for an
+initialization file for ee: the file \fI/usr/share/misc/init.ee\fR, the
+file \fI.init.ee\fR in the user's home directory, or the file \fI.init.ee\fR
+in the current directory (if different from the home
+directory). This allows system administrators to set some preferences for
+the users on a system-wide basis (for example, the \fBprint\fR command),
+and the user to customize settings for particular directories (like one
+for correspondence, and a different directory for programming).
+.PP
+The file \fI\/usr/share/misc/init.ee\fR is read first, then
+\fI$HOME/.init.ee\fR, then \fI.init.ee\fR, with the settings specified by the
+most recent file read taking precedence.
+.PP
+The following items may be entered in the initialization file:
+.RS 4
+.IP \fBcase\fR
+Sets searches to be case sensitive.
+.IP \fBnocase\fR
+Sets searches to be insensitive to case (default).
+.IP \fBexpand\fR
+Causes \fIee\fR to expand tabs to spaces (default).
+.IP \fBnoexpand\fR
+Causes \fIee\fR to insert tabs as a single character.
+.IP \fBinfo\fR
+A small information window is displayed at the top of the terminal
+(default).
+.IP \fBnoinfo\fR
+Turns off the display of the information window.
+.IP \fBmargins\fR
+Causes \fIee\fR to truncate lines at the right margin when the
+cursor passes beyond the right margin as set by the user
+while text is being inserted
+(default).
+.IP \fBnomargins\fR
+Allows lines to extend beyond the right margin.
+.IP \fBautoformat\fR
+Causes \fIee\fR to automatically try to format the current paragraph while
+text insertion is occurring.
+.IP \fBnoautoformat\fR
+Turns off automatic paragraph formatting (default).
+.IP \fBprintcommand\fR
+Allows the setting of the print command (default: "lp").
+.IP \fBrightmargin\fR
+The user can select a value for the right margin (the first column on the
+screen is zero).
+.IP \fBhighlight\fR
+Turns on highlighting border of information window and menus (default).
+.IP \fBnohighlight\fR
+Turns off highlighting of border of information window and menus.
+.IP \fBeightbit\fR
+Turns on display of eight bit characters.
+.IP \fBnoeightbit\fR
+Turns off display of eight bit characters (they are displayed as their decimal
+value inside angle brackets, e.g., "<220>").
+.IP \fB16bit\fR
+Turns on handling of 16-bit characters.
+.IP \fBno16bit\fR
+Turns off handling of 16-bit characters.
+.IP \fBemacs\fR
+Turns on emacs key bindings.
+.IP \fBnoemacs\fR
+Turns off emacs key bindings.
+.RE
+.\"
+.\" save editor configuration
+.\"
+.SS "Save Editor Configuration"
+.PP
+When using this entry from the
+.B settings
+menu, the user may choose to save the current configuration of
+the editor (see \fBInitializing ee from a
+file\fR above) to a file named
+.I .init.ee
+in the current directory or the user's home directory. If a file named
+.I .init.ee
+already exists, it will be renamed
+.IR .init.ee.old .
+.\"
+.\" Caveats
+.\"
+.SH CAVEATS
+.PP
+THIS MATERIAL IS PROVIDED "AS IS". THERE ARE
+NO WARRANTIES OF ANY KIND WITH REGARD TO THIS
+MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE. Neither
+Hewlett-Packard nor Hugh Mahon shall be liable
+for errors contained herein, nor for
+incidental or consequential damages in
+connection with the furnishing, performance or
+use of this material. Neither Hewlett-Packard
+nor Hugh Mahon assumes any responsibility for
+the use or reliability of this software or
+documentation. This software and
+documentation is totally UNSUPPORTED. There
+is no support contract available. Hewlett-Packard
+has done NO Quality Assurance on ANY
+of the program or documentation. You may find
+the quality of the materials inferior to
+supported materials.
+.PP
+Always make a copy of files that cannot be easily reproduced before
+editing. Save files early, and save often.
+.SS "International Code Set Support"
+.I ee
+supports single-byte character code sets (eight-bit clean), or the
+Chinese Big-5 code set. (Other multi-byte code sets may function, but the
+reason Big-5 works is that a two-byte character also takes up two columns on
+the screen.)
+.SH WARNINGS
+The automatic paragraph formatting operation
+may be too slow for slower systems.
+.SH FILES
+.PP
+.I /usr/share/misc/init.ee
+.br
+.I $HOME/.init.ee
+.br
+.I .init.ee
+.SH AUTHOR
+.PP
+The software
+.I ee
+was developed by Hugh Mahon.
+.PP
+This software and documentation contains
+proprietary information which is protected by
+copyright. All rights are reserved.
+.PP
+Copyright (c) 1990, 1991, 1992, 1993, 1995, 1996, 2001 Hugh Mahon.
+.SH "SEE ALSO"
+.PP
+termcap(4), terminfo(4), environ(5), spell(1), ispell(1), lp(1), aee(1)
+
diff --git a/text_cmds/ee/ee.c b/text_cmds/ee/ee.c
new file mode 100644
index 0000000..70a4407
--- /dev/null
+++ b/text_cmds/ee/ee.c
@@ -0,0 +1,5348 @@
+/*
+ | ee (easy editor)
+ |
+ | An easy to use, simple screen oriented editor.
+ |
+ | written by Hugh Mahon
+ |
+ |
+ | Copyright (c) 2009, Hugh Mahon
+ | All rights reserved.
+ |
+ | Redistribution and use in source and binary forms, with or without
+ | modification, are permitted provided that the following conditions
+ | are met:
+ |
+ | * Redistributions of source code must retain the above copyright
+ | notice, this list of conditions and the following disclaimer.
+ | * Redistributions in binary form must reproduce the above
+ | copyright notice, this list of conditions and the following
+ | disclaimer in the documentation and/or other materials provided
+ | with the distribution.
+ |
+ | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ | POSSIBILITY OF SUCH DAMAGE.
+ |
+ | -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+ |
+ | This editor was purposely developed to be simple, both in
+ | interface and implementation. This editor was developed to
+ | address a specific audience: the user who is new to computers
+ | (especially UNIX).
+ |
+ | ee is not aimed at technical users; for that reason more
+ | complex features were intentionally left out. In addition,
+ | ee is intended to be compiled by people with little computer
+ | experience, which means that it needs to be small, relatively
+ | simple in implementation, and portable.
+ |
+ | This software and documentation contains
+ | proprietary information which is protected by
+ | copyright. All rights are reserved.
+ |
+ | $Header: /home/hugh/sources/old_ae/RCS/ee.c,v 1.104 2010/06/04 01:55:31 hugh Exp hugh $
+ |
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+char *ee_copyright_message =
+"Copyright (c) 1986, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 2009 Hugh Mahon ";
+
+#include "ee_version.h"
+
+char *version = "@(#) ee, version " EE_VERSION " $Revision: 1.104 $";
+
+#ifdef NCURSE
+#include "new_curse.h"
+#elif HAS_NCURSES
+#include <ncurses.h>
+#else
+#include <curses.h>
+#endif
+
+#include <ctype.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <pwd.h>
+#include <locale.h>
+
+#ifdef HAS_SYS_WAIT
+#include <sys/wait.h>
+#endif
+
+#ifdef HAS_STDLIB
+#include <stdlib.h>
+#endif
+
+#ifdef HAS_STDARG
+#include <stdarg.h>
+#endif
+
+#ifdef HAS_UNISTD
+#include <unistd.h>
+#endif
+
+#ifndef NO_CATGETS
+#include <nl_types.h>
+
+nl_catd catalog;
+#else
+#define catgetlocal(a, b) (b)
+#endif /* NO_CATGETS */
+
+#ifndef SIGCHLD
+#define SIGCHLD SIGCLD
+#endif
+
+#define TAB 9
+#define max(a, b) (a > b ? a : b)
+#define min(a, b) (a < b ? a : b)
+
+/*
+ | defines for type of data to show in info window
+ */
+
+#define CONTROL_KEYS 1
+#define COMMANDS 2
+
+struct text {
+ unsigned char *line; /* line of characters */
+ int line_number; /* line number */
+ int line_length; /* actual number of characters in the line */
+ int max_length; /* maximum number of characters the line handles */
+ struct text *next_line; /* next line of text */
+ struct text *prev_line; /* previous line of text */
+ };
+
+struct text *first_line; /* first line of current buffer */
+struct text *dlt_line; /* structure for info on deleted line */
+struct text *curr_line; /* current line cursor is on */
+struct text *tmp_line; /* temporary line pointer */
+struct text *srch_line; /* temporary pointer for search routine */
+
+struct files { /* structure to store names of files to be edited*/
+ unsigned char *name; /* name of file */
+ struct files *next_name;
+ };
+
+struct files *top_of_stack = NULL;
+
+int d_wrd_len; /* length of deleted word */
+int position; /* offset in bytes from begin of line */
+int scr_pos; /* horizontal position */
+int scr_vert; /* vertical position on screen */
+int scr_horz; /* horizontal position on screen */
+int absolute_lin; /* number of lines from top */
+int tmp_vert, tmp_horz;
+int input_file; /* indicate to read input file */
+int recv_file; /* indicate reading a file */
+int edit; /* continue executing while true */
+int gold; /* 'gold' function key pressed */
+int fildes; /* file descriptor */
+int case_sen; /* case sensitive search flag */
+int last_line; /* last line for text display */
+int last_col; /* last column for text display */
+int horiz_offset = 0; /* offset from left edge of text */
+int clear_com_win; /* flag to indicate com_win needs clearing */
+int text_changes = FALSE; /* indicate changes have been made to text */
+int get_fd; /* file descriptor for reading a file */
+int info_window = TRUE; /* flag to indicate if help window visible */
+int info_type = CONTROL_KEYS; /* flag to indicate type of info to display */
+int expand_tabs = TRUE; /* flag for expanding tabs */
+int right_margin = 0; /* the right margin */
+int observ_margins = TRUE; /* flag for whether margins are observed */
+int shell_fork;
+int temp_stdin; /* temporary storage for stdin */
+int temp_stdout; /* temp storage for stdout descriptor */
+int temp_stderr; /* temp storage for stderr descriptor */
+int pipe_out[2]; /* pipe file desc for output */
+int pipe_in[2]; /* pipe file descriptors for input */
+int out_pipe; /* flag that info is piped out */
+int in_pipe; /* flag that info is piped in */
+int formatted = FALSE; /* flag indicating paragraph formatted */
+int auto_format = FALSE; /* flag for auto_format mode */
+int restricted = FALSE; /* flag to indicate restricted mode */
+int nohighlight = FALSE; /* turns off highlighting */
+int eightbit = TRUE; /* eight bit character flag */
+int local_LINES = 0; /* copy of LINES, to detect when win resizes */
+int local_COLS = 0; /* copy of COLS, to detect when win resizes */
+int curses_initialized = FALSE; /* flag indicating if curses has been started*/
+int emacs_keys_mode = FALSE; /* mode for if emacs key binings are used */
+int ee_chinese = FALSE; /* allows handling of multi-byte characters */
+ /* by checking for high bit in a byte the */
+ /* code recognizes a two-byte character */
+ /* sequence */
+
+unsigned char *point; /* points to current position in line */
+unsigned char *srch_str; /* pointer for search string */
+unsigned char *u_srch_str; /* pointer to non-case sensitive search */
+unsigned char *srch_1; /* pointer to start of suspect string */
+unsigned char *srch_2; /* pointer to next character of string */
+unsigned char *srch_3;
+unsigned char *in_file_name = NULL; /* name of input file */
+char *tmp_file; /* temporary file name */
+unsigned char *d_char; /* deleted character */
+unsigned char *d_word; /* deleted word */
+unsigned char *d_line; /* deleted line */
+char in_string[513]; /* buffer for reading a file */
+unsigned char *print_command = (unsigned char *)"lpr"; /* string to use for the print command */
+unsigned char *start_at_line = NULL; /* move to this line at start of session*/
+int in; /* input character */
+
+FILE *temp_fp; /* temporary file pointer */
+FILE *bit_bucket; /* file pointer to /dev/null */
+
+char *table[] = {
+ "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", "^H", "\t", "^J",
+ "^K", "^L", "^M", "^N", "^O", "^P", "^Q", "^R", "^S", "^T", "^U",
+ "^V", "^W", "^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_"
+ };
+
+WINDOW *com_win;
+WINDOW *text_win;
+WINDOW *help_win;
+WINDOW *info_win;
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define P_(s) s
+#else
+#define P_(s) ()
+#endif
+
+
+/*
+ | The following structure allows menu items to be flexibly declared.
+ | The first item is the string describing the selection, the second
+ | is the address of the procedure to call when the item is selected,
+ | and the third is the argument for the procedure.
+ |
+ | For those systems with i18n, the string should be accompanied by a
+ | catalog number. The 'int *' should be replaced with 'void *' on
+ | systems with that type.
+ |
+ | The first menu item will be the title of the menu, with NULL
+ | parameters for the procedure and argument, followed by the menu items.
+ |
+ | If the procedure value is NULL, the menu item is displayed, but no
+ | procedure is called when the item is selected. The number of the
+ | item will be returned. If the third (argument) parameter is -1, no
+ | argument is given to the procedure when it is called.
+ */
+
+struct menu_entries {
+ char *item_string;
+ int (*procedure)P_((struct menu_entries *));
+ struct menu_entries *ptr_argument;
+ int (*iprocedure)P_((int));
+ void (*nprocedure)P_((void));
+ int argument;
+ };
+
+int main P_((int argc, char *argv[]));
+unsigned char *resiz_line P_((int factor, struct text *rline, int rpos));
+void insert P_((int character));
+void delete P_((int disp));
+void scanline P_((unsigned char *pos));
+int tabshift P_((int temp_int));
+int out_char P_((WINDOW *window, int character, int column));
+int len_char P_((int character, int column));
+void draw_line P_((int vertical, int horiz, unsigned char *ptr, int t_pos, int length));
+void insert_line P_((int disp));
+struct text *txtalloc P_((void));
+struct files *name_alloc P_((void));
+unsigned char *next_word P_((unsigned char *string));
+void prev_word P_((void));
+void control P_((void));
+void emacs_control P_((void));
+void bottom P_((void));
+void top P_((void));
+void nextline P_((void));
+void prevline P_((void));
+void left P_((int disp));
+void right P_((int disp));
+void find_pos P_((void));
+void up P_((void));
+void down P_((void));
+void function_key P_((void));
+void print_buffer P_((void));
+void command_prompt P_((void));
+void command P_((char *cmd_str1));
+int scan P_((char *line, int offset, int column));
+char *get_string P_((char *prompt, int advance));
+int compare P_((char *string1, char *string2, int sensitive));
+void goto_line P_((char *cmd_str));
+void midscreen P_((int line, unsigned char *pnt));
+void get_options P_((int numargs, char *arguments[]));
+void check_fp P_((void));
+void get_file P_((char *file_name));
+void get_line P_((int length, unsigned char *in_string, int *append));
+void draw_screen P_((void));
+void finish P_((void));
+int quit P_((int noverify));
+void edit_abort P_((int arg));
+void delete_text P_((void));
+int write_file P_((char *file_name, int warn_if_exists));
+int search P_((int display_message));
+void search_prompt P_((void));
+void del_char P_((void));
+void undel_char P_((void));
+void del_word P_((void));
+void undel_word P_((void));
+void del_line P_((void));
+void undel_line P_((void));
+void adv_word P_((void));
+void move_rel P_((int direction, int lines));
+void eol P_((void));
+void bol P_((void));
+void adv_line P_((void));
+void sh_command P_((char *string));
+void set_up_term P_((void));
+void resize_check P_((void));
+int menu_op P_((struct menu_entries *));
+void paint_menu P_((struct menu_entries menu_list[], int max_width, int max_height, int list_size, int top_offset, WINDOW *menu_win, int off_start, int vert_size));
+void help P_((void));
+void paint_info_win P_((void));
+void no_info_window P_((void));
+void create_info_window P_((void));
+int file_op P_((int arg));
+void shell_op P_((void));
+void leave_op P_((void));
+void redraw P_((void));
+int Blank_Line P_((struct text *test_line));
+void Format P_((void));
+void ee_init P_((void));
+void dump_ee_conf P_((void));
+void echo_string P_((char *string));
+void spell_op P_((void));
+void ispell_op P_((void));
+int first_word_len P_((struct text *test_line));
+void Auto_Format P_((void));
+void modes_op P_((void));
+char *is_in_string P_((char *string, char *substring));
+char *resolve_name P_((char *name));
+int restrict_mode P_((void));
+int unique_test P_((char *string, char *list[]));
+void strings_init P_((void));
+
+#undef P_
+/*
+ | allocate space here for the strings that will be in the menu
+ */
+
+struct menu_entries modes_menu[] = {
+ {"", NULL, NULL, NULL, NULL, 0}, /* title */
+ {"", NULL, NULL, NULL, NULL, -1}, /* 1. tabs to spaces */
+ {"", NULL, NULL, NULL, NULL, -1}, /* 2. case sensitive search*/
+ {"", NULL, NULL, NULL, NULL, -1}, /* 3. margins observed */
+ {"", NULL, NULL, NULL, NULL, -1}, /* 4. auto-paragraph */
+ {"", NULL, NULL, NULL, NULL, -1}, /* 5. eightbit characters*/
+ {"", NULL, NULL, NULL, NULL, -1}, /* 6. info window */
+ {"", NULL, NULL, NULL, NULL, -1}, /* 7. emacs key bindings*/
+ {"", NULL, NULL, NULL, NULL, -1}, /* 8. right margin */
+ {"", NULL, NULL, NULL, NULL, -1}, /* 9. chinese text */
+ {"", NULL, NULL, NULL, dump_ee_conf, -1}, /* 10. save editor config */
+ {NULL, NULL, NULL, NULL, NULL, -1} /* terminator */
+ };
+
+char *mode_strings[11];
+
+#define NUM_MODES_ITEMS 10
+
+struct menu_entries config_dump_menu[] = {
+ {"", NULL, NULL, NULL, NULL, 0},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, NULL, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries leave_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, finish, -1},
+ {"", NULL, NULL, quit, NULL, TRUE},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+#define READ_FILE 1
+#define WRITE_FILE 2
+#define SAVE_FILE 3
+
+struct menu_entries file_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, file_op, NULL, READ_FILE},
+ {"", NULL, NULL, file_op, NULL, WRITE_FILE},
+ {"", NULL, NULL, file_op, NULL, SAVE_FILE},
+ {"", NULL, NULL, NULL, print_buffer, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries search_menu[] = {
+ {"", NULL, NULL, NULL, NULL, 0},
+ {"", NULL, NULL, NULL, search_prompt, -1},
+ {"", NULL, NULL, search, NULL, TRUE},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries spell_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, spell_op, -1},
+ {"", NULL, NULL, NULL, ispell_op, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries misc_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, Format, -1},
+ {"", NULL, NULL, NULL, shell_op, -1},
+ {"", menu_op, spell_menu, NULL, NULL, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+struct menu_entries main_menu[] = {
+ {"", NULL, NULL, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, leave_op, -1},
+ {"", NULL, NULL, NULL, help, -1},
+ {"", menu_op, file_menu, NULL, NULL, -1},
+ {"", NULL, NULL, NULL, redraw, -1},
+ {"", NULL, NULL, NULL, modes_op, -1},
+ {"", menu_op, search_menu, NULL, NULL, -1},
+ {"", menu_op, misc_menu, NULL, NULL, -1},
+ {NULL, NULL, NULL, NULL, NULL, -1}
+ };
+
+char *help_text[23];
+char *control_keys[5];
+
+char *emacs_help_text[22];
+char *emacs_control_keys[5];
+
+char *command_strings[5];
+char *commands[32];
+char *init_strings[22];
+
+#define MENU_WARN 1
+
+#define max_alpha_char 36
+
+/*
+ | Declarations for strings for localization
+ */
+
+char *com_win_message; /* to be shown in com_win if no info window */
+char *no_file_string;
+char *ascii_code_str;
+char *printer_msg_str;
+char *command_str;
+char *file_write_prompt_str;
+char *file_read_prompt_str;
+char *char_str;
+char *unkn_cmd_str;
+char *non_unique_cmd_msg;
+char *line_num_str;
+char *line_len_str;
+char *current_file_str;
+char *usage0;
+char *usage1;
+char *usage2;
+char *usage3;
+char *usage4;
+char *file_is_dir_msg;
+char *new_file_msg;
+char *cant_open_msg;
+char *open_file_msg;
+char *file_read_fin_msg;
+char *reading_file_msg;
+char *read_only_msg;
+char *file_read_lines_msg;
+char *save_file_name_prompt;
+char *file_not_saved_msg;
+char *changes_made_prompt;
+char *yes_char;
+char *file_exists_prompt;
+char *create_file_fail_msg;
+char *writing_file_msg;
+char *file_written_msg;
+char *searching_msg;
+char *str_not_found_msg;
+char *search_prompt_str;
+char *exec_err_msg;
+char *continue_msg;
+char *menu_cancel_msg;
+char *menu_size_err_msg;
+char *press_any_key_msg;
+char *shell_prompt;
+char *formatting_msg;
+char *shell_echo_msg;
+char *spell_in_prog_msg;
+char *margin_prompt;
+char *restricted_msg;
+char *ON;
+char *OFF;
+char *HELP;
+char *WRITE;
+char *READ;
+char *LINE;
+char *FILE_str;
+char *CHARACTER;
+char *REDRAW;
+char *RESEQUENCE;
+char *AUTHOR;
+char *VERSION;
+char *CASE;
+char *NOCASE;
+char *EXPAND;
+char *NOEXPAND;
+char *Exit_string;
+char *QUIT_string;
+char *INFO;
+char *NOINFO;
+char *MARGINS;
+char *NOMARGINS;
+char *AUTOFORMAT;
+char *NOAUTOFORMAT;
+char *Echo;
+char *PRINTCOMMAND;
+char *RIGHTMARGIN;
+char *HIGHLIGHT;
+char *NOHIGHLIGHT;
+char *EIGHTBIT;
+char *NOEIGHTBIT;
+char *EMACS_string;
+char *NOEMACS_string;
+char *conf_dump_err_msg;
+char *conf_dump_success_msg;
+char *conf_not_saved_msg;
+char *ree_no_file_msg;
+char *cancel_string;
+char *menu_too_lrg_msg;
+char *more_above_str, *more_below_str;
+char *separator = "===============================================================================";
+
+char *chinese_cmd, *nochinese_cmd;
+
+#ifndef __STDC__
+#ifndef HAS_STDLIB
+extern char *malloc();
+extern char *realloc();
+extern char *getenv();
+FILE *fopen(); /* declaration for open function */
+#endif /* HAS_STDLIB */
+#endif /* __STDC__ */
+
+int
+main(argc, argv) /* beginning of main program */
+int argc;
+char *argv[];
+{
+ int counter;
+
+ for (counter = 1; counter < 24; counter++)
+ signal(counter, SIG_IGN);
+
+ signal(SIGCHLD, SIG_DFL);
+ signal(SIGSEGV, SIG_DFL);
+ signal(SIGINT, edit_abort);
+ d_char = malloc(3); /* provide a buffer for multi-byte chars */
+ d_word = malloc(150);
+ *d_word = '\0';
+ d_line = NULL;
+ dlt_line = txtalloc();
+ dlt_line->line = d_line;
+ dlt_line->line_length = 0;
+ curr_line = first_line = txtalloc();
+ curr_line->line = point = malloc(10);
+ curr_line->line_length = 1;
+ curr_line->max_length = 10;
+ curr_line->prev_line = NULL;
+ curr_line->next_line = NULL;
+ curr_line->line_number = 1;
+ srch_str = NULL;
+ u_srch_str = NULL;
+ position = 1;
+ scr_pos =0;
+ scr_vert = 0;
+ scr_horz = 0;
+ absolute_lin = 1;
+ bit_bucket = fopen("/dev/null", "w");
+ edit = TRUE;
+ gold = case_sen = FALSE;
+ shell_fork = TRUE;
+ strings_init();
+ ee_init();
+ if (argc > 0 )
+ get_options(argc, argv);
+ set_up_term();
+ if (right_margin == 0)
+ right_margin = COLS - 1;
+ if (top_of_stack == NULL)
+ {
+ if (restrict_mode())
+ {
+ wmove(com_win, 0, 0);
+ werase(com_win);
+ wprintw(com_win, ree_no_file_msg);
+ wrefresh(com_win);
+ edit_abort(0);
+ }
+ wprintw(com_win, no_file_string);
+ wrefresh(com_win);
+ }
+ else
+ check_fp();
+
+ clear_com_win = TRUE;
+
+ counter = 0;
+
+ while(edit)
+ {
+ /*
+ | display line and column information
+ */
+ if (info_window)
+ {
+ if (!nohighlight)
+ wstandout(info_win);
+ wmove(info_win, 5, 0);
+ wprintw(info_win, separator);
+ wmove(info_win, 5, 5);
+ wprintw(info_win, "line %d col %d lines from top %d ",
+ curr_line->line_number, scr_horz, absolute_lin);
+ wstandend(info_win);
+ wrefresh(info_win);
+ }
+
+ wrefresh(text_win);
+ in = wgetch(text_win);
+ if (in == -1)
+ exit(0); /* without this exit ee will go into an
+ infinite loop if the network
+ session detaches */
+
+ resize_check();
+
+ if (clear_com_win)
+ {
+ clear_com_win = FALSE;
+ wmove(com_win, 0, 0);
+ werase(com_win);
+ if (!info_window)
+ {
+ wprintw(com_win, "%s", com_win_message);
+ }
+ wrefresh(com_win);
+ }
+
+ if (in > 255)
+ function_key();
+ else if ((in == '\10') || (in == 127))
+ {
+ in = 8; /* make sure key is set to backspace */
+ delete(TRUE);
+ }
+ else if ((in > 31) || (in == 9))
+ insert(in);
+ else if ((in >= 0) && (in <= 31))
+ {
+ if (emacs_keys_mode)
+ emacs_control();
+ else
+ control();
+ }
+ }
+ return(0);
+}
+
+unsigned char *
+resiz_line(factor, rline, rpos) /* resize the line to length + factor*/
+int factor; /* resize factor */
+struct text *rline; /* position in line */
+int rpos;
+{
+ unsigned char *rpoint;
+ int resiz_var;
+
+ rline->max_length += factor;
+ rpoint = rline->line = realloc(rline->line, rline->max_length );
+ for (resiz_var = 1 ; (resiz_var < rpos) ; resiz_var++)
+ rpoint++;
+ return(rpoint);
+}
+
+void
+insert(character) /* insert character into line */
+int character; /* new character */
+{
+ int counter;
+ int value;
+ unsigned char *temp; /* temporary pointer */
+ unsigned char *temp2; /* temporary pointer */
+
+ if ((character == '\011') && (expand_tabs))
+ {
+ counter = len_char('\011', scr_horz);
+ for (; counter > 0; counter--)
+ insert(' ');
+ if (auto_format)
+ Auto_Format();
+ return;
+ }
+ text_changes = TRUE;
+ if ((curr_line->max_length - curr_line->line_length) < 5)
+ point = resiz_line(10, curr_line, position);
+ curr_line->line_length++;
+ temp = point;
+ counter = position;
+ while (counter < curr_line->line_length) /* find end of line */
+ {
+ counter++;
+ temp++;
+ }
+ temp++; /* increase length of line by one */
+ while (point < temp)
+ {
+ temp2=temp - 1;
+ *temp= *temp2; /* shift characters over by one */
+ temp--;
+ }
+ *point = character; /* insert new character */
+ wclrtoeol(text_win);
+ if (!isprint((unsigned char)character)) /* check for TAB character*/
+ {
+ scr_pos = scr_horz += out_char(text_win, character, scr_horz);
+ point++;
+ position++;
+ }
+ else
+ {
+ waddch(text_win, (unsigned char)character);
+ scr_pos = ++scr_horz;
+ point++;
+ position ++;
+ }
+
+ if ((observ_margins) && (right_margin < scr_pos))
+ {
+ counter = position;
+ while (scr_pos > right_margin)
+ prev_word();
+ if (scr_pos == 0)
+ {
+ while (position < counter)
+ right(TRUE);
+ }
+ else
+ {
+ counter -= position;
+ insert_line(TRUE);
+ for (value = 0; value < counter; value++)
+ right(TRUE);
+ }
+ }
+
+ if ((scr_horz - horiz_offset) > last_col)
+ {
+ horiz_offset += 8;
+ midscreen(scr_vert, point);
+ }
+
+ if ((auto_format) && (character == ' ') && (!formatted))
+ Auto_Format();
+ else if ((character != ' ') && (character != '\t'))
+ formatted = FALSE;
+
+ draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
+}
+
+void
+delete(disp) /* delete character */
+int disp;
+{
+ unsigned char *tp;
+ unsigned char *temp2;
+ struct text *temp_buff;
+ int temp_vert;
+ int temp_pos;
+ int del_width = 1;
+
+ if (point != curr_line->line) /* if not at beginning of line */
+ {
+ text_changes = TRUE;
+ temp2 = tp = point;
+ if ((ee_chinese) && (position >= 2) && (*(point - 2) > 127))
+ {
+ del_width = 2;
+ }
+ tp -= del_width;
+ point -= del_width;
+ position -= del_width;
+ temp_pos = position;
+ curr_line->line_length -= del_width;
+ if ((*tp < ' ') || (*tp >= 127)) /* check for TAB */
+ scanline(tp);
+ else
+ scr_horz -= del_width;
+ scr_pos = scr_horz;
+ if (in == 8)
+ {
+ if (del_width == 1)
+ *d_char = *point; /* save deleted character */
+ else
+ {
+ d_char[0] = *point;
+ d_char[1] = *(point + 1);
+ }
+ d_char[del_width] = '\0';
+ }
+ while (temp_pos <= curr_line->line_length)
+ {
+ temp_pos++;
+ *tp = *temp2;
+ tp++;
+ temp2++;
+ }
+ if ((scr_horz < horiz_offset) && (horiz_offset > 0))
+ {
+ horiz_offset -= 8;
+ midscreen(scr_vert, point);
+ }
+ }
+ else if (curr_line->prev_line != NULL)
+ {
+ text_changes = TRUE;
+ left(disp); /* go to previous line */
+ temp_buff = curr_line->next_line;
+ point = resiz_line(temp_buff->line_length, curr_line, position);
+ if (temp_buff->next_line != NULL)
+ temp_buff->next_line->prev_line = curr_line;
+ curr_line->next_line = temp_buff->next_line;
+ temp2 = temp_buff->line;
+ if (in == 8)
+ {
+ d_char[0] = '\n';
+ d_char[1] = '\0';
+ }
+ tp = point;
+ temp_pos = 1;
+ while (temp_pos < temp_buff->line_length)
+ {
+ curr_line->line_length++;
+ temp_pos++;
+ *tp = *temp2;
+ tp++;
+ temp2++;
+ }
+ *tp = '\0';
+ free(temp_buff->line);
+ free(temp_buff);
+ temp_buff = curr_line;
+ temp_vert = scr_vert;
+ scr_pos = scr_horz;
+ if (scr_vert < last_line)
+ {
+ wmove(text_win, scr_vert + 1, 0);
+ wdeleteln(text_win);
+ }
+ while ((temp_buff != NULL) && (temp_vert < last_line))
+ {
+ temp_buff = temp_buff->next_line;
+ temp_vert++;
+ }
+ if ((temp_vert == last_line) && (temp_buff != NULL))
+ {
+ tp = temp_buff->line;
+ wmove(text_win, last_line,0);
+ wclrtobot(text_win);
+ draw_line(last_line, 0, tp, 1, temp_buff->line_length);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ }
+ }
+ draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
+ formatted = FALSE;
+}
+
+void
+scanline(pos) /* find the proper horizontal position for the pointer */
+unsigned char *pos;
+{
+ int temp;
+ unsigned char *ptr;
+
+ ptr = curr_line->line;
+ temp = 0;
+ while (ptr < pos)
+ {
+ if (*ptr <= 8)
+ temp += 2;
+ else if (*ptr == 9)
+ temp += tabshift(temp);
+ else if ((*ptr >= 10) && (*ptr <= 31))
+ temp += 2;
+ else if ((*ptr >= 32) && (*ptr < 127))
+ temp++;
+ else if (*ptr == 127)
+ temp += 2;
+ else if (!eightbit)
+ temp += 5;
+ else
+ temp++;
+ ptr++;
+ }
+ scr_horz = temp;
+ if ((scr_horz - horiz_offset) > last_col)
+ {
+ horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8);
+ midscreen(scr_vert, point);
+ }
+ else if (scr_horz < horiz_offset)
+ {
+ horiz_offset = max(0, (scr_horz - (scr_horz % 8)));
+ midscreen(scr_vert, point);
+ }
+}
+
+int
+tabshift(temp_int) /* give the number of spaces to shift */
+int temp_int;
+{
+ int leftover;
+
+ leftover = ((temp_int + 1) % 8);
+ if (leftover == 0)
+ return (1);
+ else
+ return (9 - leftover);
+}
+
+int
+out_char(window, character, column) /* output non-printing character */
+WINDOW *window;
+int character;
+int column;
+{
+ int i1, i2;
+ char *string;
+ char string2[8];
+
+ if (character == TAB)
+ {
+ i1 = tabshift(column);
+ for (i2 = 0;
+ (i2 < i1) && (((column+i2+1)-horiz_offset) < last_col); i2++)
+ {
+ waddch(window, ' ');
+ }
+ return(i1);
+ }
+ else if ((character >= '\0') && (character < ' '))
+ {
+ string = table[(int) character];
+ }
+ else if ((character < 0) || (character >= 127))
+ {
+ if (character == 127)
+ string = "^?";
+ else if (!eightbit)
+ {
+ sprintf(string2, "<%d>", (character < 0) ? (character + 256) : character);
+ string = string2;
+ }
+ else
+ {
+ waddch(window, (unsigned char)character );
+ return(1);
+ }
+ }
+ else
+ {
+ waddch(window, (unsigned char)character);
+ return(1);
+ }
+ for (i2 = 0; (string[i2] != '\0') && (((column+i2+1)-horiz_offset) < last_col); i2++)
+ waddch(window, (unsigned char)string[i2]);
+ return(strlen(string));
+}
+
+int
+len_char(character, column) /* return the length of the character */
+int character;
+int column; /* the column must be known to provide spacing for tabs */
+{
+ int length;
+
+ if (character == '\t')
+ length = tabshift(column);
+ else if ((character >= 0) && (character < 32))
+ length = 2;
+ else if ((character >= 32) && (character <= 126))
+ length = 1;
+ else if (character == 127)
+ length = 2;
+ else if (((character > 126) || (character < 0)) && (!eightbit))
+ length = 5;
+ else
+ length = 1;
+
+ return(length);
+}
+
+void
+draw_line(vertical, horiz, ptr, t_pos, length) /* redraw line from current position */
+int vertical; /* current vertical position on screen */
+int horiz; /* current horizontal position on screen */
+unsigned char *ptr; /* pointer to line */
+int t_pos; /* current position (offset in bytes) from bol */
+int length; /* length (in bytes) of line */
+{
+ int d; /* partial length of special or tab char to display */
+ unsigned char *temp; /* temporary pointer to position in line */
+ int abs_column; /* offset in screen units from begin of line */
+ int column; /* horizontal position on screen */
+ int row; /* vertical position on screen */
+ int posit; /* temporary position indicator within line */
+
+ abs_column = horiz;
+ column = horiz - horiz_offset;
+ row = vertical;
+ temp = ptr;
+ d = 0;
+ posit = t_pos;
+ if (column < 0)
+ {
+ wmove(text_win, row, 0);
+ wclrtoeol(text_win);
+ }
+ while (column < 0)
+ {
+ d = len_char(*temp, abs_column);
+ abs_column += d;
+ column += d;
+ posit++;
+ temp++;
+ }
+ wmove(text_win, row, column);
+ wclrtoeol(text_win);
+ while ((posit < length) && (column <= last_col))
+ {
+ if (!isprint(*temp))
+ {
+ column += len_char(*temp, abs_column);
+ abs_column += out_char(text_win, *temp, abs_column);
+ }
+ else
+ {
+ abs_column++;
+ column++;
+ waddch(text_win, *temp);
+ }
+ posit++;
+ temp++;
+ }
+ if (column < last_col)
+ wclrtoeol(text_win);
+ wmove(text_win, vertical, (horiz - horiz_offset));
+}
+
+void
+insert_line(disp) /* insert new line */
+int disp;
+{
+ int temp_pos;
+ int temp_pos2;
+ unsigned char *temp;
+ unsigned char *extra;
+ struct text *temp_nod;
+
+ text_changes = TRUE;
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ wclrtoeol(text_win);
+ temp_nod= txtalloc();
+ temp_nod->line = extra= malloc(10);
+ temp_nod->line_length = 1;
+ temp_nod->max_length = 10;
+ temp_nod->line_number = curr_line->line_number + 1;
+ temp_nod->next_line = curr_line->next_line;
+ if (temp_nod->next_line != NULL)
+ temp_nod->next_line->prev_line = temp_nod;
+ temp_nod->prev_line = curr_line;
+ curr_line->next_line = temp_nod;
+ temp_pos2 = position;
+ temp = point;
+ if (temp_pos2 < curr_line->line_length)
+ {
+ temp_pos = 1;
+ while (temp_pos2 < curr_line->line_length)
+ {
+ if ((temp_nod->max_length - temp_nod->line_length)< 5)
+ extra = resiz_line(10, temp_nod, temp_pos);
+ temp_nod->line_length++;
+ temp_pos++;
+ temp_pos2++;
+ *extra= *temp;
+ extra++;
+ temp++;
+ }
+ temp=point;
+ *temp = '\0';
+ temp = resiz_line((1 - temp_nod->line_length), curr_line, position);
+ curr_line->line_length = 1 + temp - curr_line->line;
+ }
+ curr_line->line_length = position;
+ absolute_lin++;
+ curr_line = temp_nod;
+ *extra = '\0';
+ position = 1;
+ point= curr_line->line;
+ if (disp)
+ {
+ if (scr_vert < last_line)
+ {
+ scr_vert++;
+ wclrtoeol(text_win);
+ wmove(text_win, scr_vert, 0);
+ winsertln(text_win);
+ }
+ else
+ {
+ wmove(text_win, 0,0);
+ wdeleteln(text_win);
+ wmove(text_win, last_line,0);
+ wclrtobot(text_win);
+ }
+ scr_pos = scr_horz = 0;
+ if (horiz_offset)
+ {
+ horiz_offset = 0;
+ midscreen(scr_vert, point);
+ }
+ draw_line(scr_vert, scr_horz, point, position,
+ curr_line->line_length);
+ }
+}
+
+struct text *txtalloc() /* allocate space for line structure */
+{
+ return((struct text *) malloc(sizeof( struct text)));
+}
+
+struct files *name_alloc() /* allocate space for file name list node */
+{
+ return((struct files *) malloc(sizeof( struct files)));
+}
+
+unsigned char *next_word(string) /* move to next word in string */
+unsigned char *string;
+{
+ while ((*string != '\0') && ((*string != 32) && (*string != 9)))
+ string++;
+ while ((*string != '\0') && ((*string == 32) || (*string == 9)))
+ string++;
+ return(string);
+}
+
+void
+prev_word() /* move to start of previous word in text */
+{
+ if (position != 1)
+ {
+ if ((position != 1) && ((point[-1] == ' ') || (point[-1] == '\t')))
+ { /* if at the start of a word */
+ while ((position != 1) && ((*point != ' ') && (*point != '\t')))
+ left(TRUE);
+ }
+ while ((position != 1) && ((*point == ' ') || (*point == '\t')))
+ left(TRUE);
+ while ((position != 1) && ((*point != ' ') && (*point != '\t')))
+ left(TRUE);
+ if ((position != 1) && ((*point == ' ') || (*point == '\t')))
+ right(TRUE);
+ }
+ else
+ left(TRUE);
+}
+
+void
+control() /* use control for commands */
+{
+ char *string;
+
+ if (in == 1) /* control a */
+ {
+ string = get_string(ascii_code_str, TRUE);
+ if (*string != '\0')
+ {
+ in = atoi(string);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ insert(in);
+ }
+ free(string);
+ }
+ else if (in == 2) /* control b */
+ bottom();
+ else if (in == 3) /* control c */
+ {
+ command_prompt();
+ }
+ else if (in == 4) /* control d */
+ down();
+ else if (in == 5) /* control e */
+ search_prompt();
+ else if (in == 6) /* control f */
+ undel_char();
+ else if (in == 7) /* control g */
+ bol();
+ else if (in == 8) /* control h */
+ delete(TRUE);
+ else if (in == 9) /* control i */
+ ;
+ else if (in == 10) /* control j */
+ insert_line(TRUE);
+ else if (in == 11) /* control k */
+ del_char();
+ else if (in == 12) /* control l */
+ left(TRUE);
+ else if (in == 13) /* control m */
+ insert_line(TRUE);
+ else if (in == 14) /* control n */
+ move_rel('d', max(5, (last_line - 5)));
+ else if (in == 15) /* control o */
+ eol();
+ else if (in == 16) /* control p */
+ move_rel('u', max(5, (last_line - 5)));
+ else if (in == 17) /* control q */
+ ;
+ else if (in == 18) /* control r */
+ right(TRUE);
+ else if (in == 19) /* control s */
+ ;
+ else if (in == 20) /* control t */
+ top();
+ else if (in == 21) /* control u */
+ up();
+ else if (in == 22) /* control v */
+ undel_word();
+ else if (in == 23) /* control w */
+ del_word();
+ else if (in == 24) /* control x */
+ search(TRUE);
+ else if (in == 25) /* control y */
+ del_line();
+ else if (in == 26) /* control z */
+ undel_line();
+ else if (in == 27) /* control [ (escape) */
+ {
+ menu_op(main_menu);
+ }
+}
+
+/*
+ | Emacs control-key bindings
+ */
+
+void
+emacs_control()
+{
+ char *string;
+
+ if (in == 1) /* control a */
+ bol();
+ else if (in == 2) /* control b */
+ left(TRUE);
+ else if (in == 3) /* control c */
+ {
+ command_prompt();
+ }
+ else if (in == 4) /* control d */
+ del_char();
+ else if (in == 5) /* control e */
+ eol();
+ else if (in == 6) /* control f */
+ right(TRUE);
+ else if (in == 7) /* control g */
+ move_rel('u', max(5, (last_line - 5)));
+ else if (in == 8) /* control h */
+ delete(TRUE);
+ else if (in == 9) /* control i */
+ ;
+ else if (in == 10) /* control j */
+ undel_char();
+ else if (in == 11) /* control k */
+ del_line();
+ else if (in == 12) /* control l */
+ undel_line();
+ else if (in == 13) /* control m */
+ insert_line(TRUE);
+ else if (in == 14) /* control n */
+ down();
+ else if (in == 15) /* control o */
+ {
+ string = get_string(ascii_code_str, TRUE);
+ if (*string != '\0')
+ {
+ in = atoi(string);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ insert(in);
+ }
+ free(string);
+ }
+ else if (in == 16) /* control p */
+ up();
+ else if (in == 17) /* control q */
+ ;
+ else if (in == 18) /* control r */
+ undel_word();
+ else if (in == 19) /* control s */
+ ;
+ else if (in == 20) /* control t */
+ top();
+ else if (in == 21) /* control u */
+ bottom();
+ else if (in == 22) /* control v */
+ move_rel('d', max(5, (last_line - 5)));
+ else if (in == 23) /* control w */
+ del_word();
+ else if (in == 24) /* control x */
+ search(TRUE);
+ else if (in == 25) /* control y */
+ search_prompt();
+ else if (in == 26) /* control z */
+ adv_word();
+ else if (in == 27) /* control [ (escape) */
+ {
+ menu_op(main_menu);
+ }
+}
+
+void
+bottom() /* go to bottom of file */
+{
+ while (curr_line->next_line != NULL)
+ {
+ curr_line = curr_line->next_line;
+ absolute_lin++;
+ }
+ point = curr_line->line;
+ if (horiz_offset)
+ horiz_offset = 0;
+ position = 1;
+ midscreen(last_line, point);
+ scr_pos = scr_horz;
+}
+
+void
+top() /* go to top of file */
+{
+ while (curr_line->prev_line != NULL)
+ {
+ curr_line = curr_line->prev_line;
+ absolute_lin--;
+ }
+ point = curr_line->line;
+ if (horiz_offset)
+ horiz_offset = 0;
+ position = 1;
+ midscreen(0, point);
+ scr_pos = scr_horz;
+}
+
+void
+nextline() /* move pointers to start of next line */
+{
+ curr_line = curr_line->next_line;
+ absolute_lin++;
+ point = curr_line->line;
+ position = 1;
+ if (scr_vert == last_line)
+ {
+ wmove(text_win, 0,0);
+ wdeleteln(text_win);
+ wmove(text_win, last_line,0);
+ wclrtobot(text_win);
+ draw_line(last_line,0,point,1,curr_line->line_length);
+ }
+ else
+ scr_vert++;
+}
+
+void
+prevline() /* move pointers to start of previous line*/
+{
+ curr_line = curr_line->prev_line;
+ absolute_lin--;
+ point = curr_line->line;
+ position = 1;
+ if (scr_vert == 0)
+ {
+ winsertln(text_win);
+ draw_line(0,0,point,1,curr_line->line_length);
+ }
+ else
+ scr_vert--;
+ while (position < curr_line->line_length)
+ {
+ position++;
+ point++;
+ }
+}
+
+void
+left(disp) /* move left one character */
+int disp;
+{
+ if (point != curr_line->line) /* if not at begin of line */
+ {
+ if ((ee_chinese) && (position >= 2) && (*(point - 2) > 127))
+ {
+ point--;
+ position--;
+ }
+ point--;
+ position--;
+ scanline(point);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ scr_pos = scr_horz;
+ }
+ else if (curr_line->prev_line != NULL)
+ {
+ if (!disp)
+ {
+ absolute_lin--;
+ curr_line = curr_line->prev_line;
+ point = curr_line->line + curr_line->line_length;
+ position = curr_line->line_length;
+ return;
+ }
+ position = 1;
+ prevline();
+ scanline(point);
+ scr_pos = scr_horz;
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ }
+}
+
+void
+right(disp) /* move right one character */
+int disp;
+{
+ if (position < curr_line->line_length)
+ {
+ if ((ee_chinese) && (*point > 127) &&
+ ((curr_line->line_length - position) >= 2))
+ {
+ point++;
+ position++;
+ }
+ point++;
+ position++;
+ scanline(point);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ scr_pos = scr_horz;
+ }
+ else if (curr_line->next_line != NULL)
+ {
+ if (!disp)
+ {
+ absolute_lin++;
+ curr_line = curr_line->next_line;
+ point = curr_line->line;
+ position = 1;
+ return;
+ }
+ nextline();
+ scr_pos = scr_horz = 0;
+ if (horiz_offset)
+ {
+ horiz_offset = 0;
+ midscreen(scr_vert, point);
+ }
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ position = 1;
+ }
+}
+
+void
+find_pos() /* move to the same column as on other line */
+{
+ scr_horz = 0;
+ position = 1;
+ while ((scr_horz < scr_pos) && (position < curr_line->line_length))
+ {
+ if (*point == 9)
+ scr_horz += tabshift(scr_horz);
+ else if (*point < ' ')
+ scr_horz += 2;
+ else if ((ee_chinese) && (*point > 127) &&
+ ((curr_line->line_length - position) >= 2))
+ {
+ scr_horz += 2;
+ point++;
+ position++;
+ }
+ else
+ scr_horz++;
+ position++;
+ point++;
+ }
+ if ((scr_horz - horiz_offset) > last_col)
+ {
+ horiz_offset = (scr_horz - (scr_horz % 8)) - (COLS - 8);
+ midscreen(scr_vert, point);
+ }
+ else if (scr_horz < horiz_offset)
+ {
+ horiz_offset = max(0, (scr_horz - (scr_horz % 8)));
+ midscreen(scr_vert, point);
+ }
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+up() /* move up one line */
+{
+ if (curr_line->prev_line != NULL)
+ {
+ prevline();
+ point = curr_line->line;
+ find_pos();
+ }
+}
+
+void
+down() /* move down one line */
+{
+ if (curr_line->next_line != NULL)
+ {
+ nextline();
+ find_pos();
+ }
+}
+
+void
+function_key() /* process function key */
+{
+ if (in == KEY_LEFT)
+ left(TRUE);
+ else if (in == KEY_RIGHT)
+ right(TRUE);
+ else if (in == KEY_HOME)
+ bol();
+ else if (in == KEY_END)
+ eol();
+ else if (in == KEY_UP)
+ up();
+ else if (in == KEY_DOWN)
+ down();
+ else if (in == KEY_NPAGE)
+ move_rel('d', max( 5, (last_line - 5)));
+ else if (in == KEY_PPAGE)
+ move_rel('u', max(5, (last_line - 5)));
+ else if (in == KEY_DL)
+ del_line();
+ else if (in == KEY_DC)
+ del_char();
+ else if (in == KEY_BACKSPACE)
+ delete(TRUE);
+ else if (in == KEY_IL)
+ { /* insert a line before current line */
+ insert_line(TRUE);
+ left(TRUE);
+ }
+ else if (in == KEY_F(1))
+ gold = !gold;
+ else if (in == KEY_F(2))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ undel_line();
+ }
+ else
+ undel_char();
+ }
+ else if (in == KEY_F(3))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ undel_word();
+ }
+ else
+ del_word();
+ }
+ else if (in == KEY_F(4))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ paint_info_win();
+ midscreen(scr_vert, point);
+ }
+ else
+ adv_word();
+ }
+ else if (in == KEY_F(5))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ search_prompt();
+ }
+ else
+ search(TRUE);
+ }
+ else if (in == KEY_F(6))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ bottom();
+ }
+ else
+ top();
+ }
+ else if (in == KEY_F(7))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ eol();
+ }
+ else
+ bol();
+ }
+ else if (in == KEY_F(8))
+ {
+ if (gold)
+ {
+ gold = FALSE;
+ command_prompt();
+ }
+ else
+ adv_line();
+ }
+}
+
+void
+print_buffer()
+{
+ char buffer[256];
+
+ sprintf(buffer, ">!%s", print_command);
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, printer_msg_str, print_command);
+ wrefresh(com_win);
+ command(buffer);
+}
+
+void
+command_prompt()
+{
+ char *cmd_str;
+ int result;
+
+ info_type = COMMANDS;
+ paint_info_win();
+ cmd_str = get_string(command_str, TRUE);
+ if ((result = unique_test(cmd_str, commands)) != 1)
+ {
+ werase(com_win);
+ wmove(com_win, 0, 0);
+ if (result == 0)
+ wprintw(com_win, unkn_cmd_str, cmd_str);
+ else
+ wprintw(com_win, non_unique_cmd_msg);
+
+ wrefresh(com_win);
+
+ info_type = CONTROL_KEYS;
+ paint_info_win();
+
+ if (cmd_str != NULL)
+ free(cmd_str);
+ return;
+ }
+ command(cmd_str);
+ wrefresh(com_win);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ info_type = CONTROL_KEYS;
+ paint_info_win();
+ if (cmd_str != NULL)
+ free(cmd_str);
+}
+
+void
+command(cmd_str1) /* process commands from keyboard */
+char *cmd_str1;
+{
+ char *cmd_str2 = NULL;
+ char *cmd_str = cmd_str1;
+
+ clear_com_win = TRUE;
+ if (compare(cmd_str, HELP, FALSE))
+ help();
+ else if (compare(cmd_str, WRITE, FALSE))
+ {
+ if (restrict_mode())
+ {
+ return;
+ }
+ cmd_str = next_word(cmd_str);
+ if (*cmd_str == '\0')
+ {
+ cmd_str = cmd_str2 = get_string(file_write_prompt_str, TRUE);
+ }
+ tmp_file = resolve_name(cmd_str);
+ write_file(tmp_file, 1);
+ if (tmp_file != cmd_str)
+ free(tmp_file);
+ }
+ else if (compare(cmd_str, READ, FALSE))
+ {
+ if (restrict_mode())
+ {
+ return;
+ }
+ cmd_str = next_word(cmd_str);
+ if (*cmd_str == '\0')
+ {
+ cmd_str = cmd_str2 = get_string(file_read_prompt_str, TRUE);
+ }
+ tmp_file = cmd_str;
+ recv_file = TRUE;
+ tmp_file = resolve_name(cmd_str);
+ check_fp();
+ if (tmp_file != cmd_str)
+ free(tmp_file);
+ }
+ else if (compare(cmd_str, LINE, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, line_num_str, curr_line->line_number);
+ wprintw(com_win, line_len_str, curr_line->line_length);
+ }
+ else if (compare(cmd_str, FILE_str, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ if (in_file_name == NULL)
+ wprintw(com_win, no_file_string);
+ else
+ wprintw(com_win, current_file_str, in_file_name);
+ }
+ else if ((*cmd_str >= '0') && (*cmd_str <= '9'))
+ goto_line(cmd_str);
+ else if (compare(cmd_str, CHARACTER, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, char_str, *point);
+ }
+ else if (compare(cmd_str, REDRAW, FALSE))
+ redraw();
+ else if (compare(cmd_str, RESEQUENCE, FALSE))
+ {
+ tmp_line = first_line->next_line;
+ while (tmp_line != NULL)
+ {
+ tmp_line->line_number = tmp_line->prev_line->line_number + 1;
+ tmp_line = tmp_line->next_line;
+ }
+ }
+ else if (compare(cmd_str, AUTHOR, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, "written by Hugh Mahon");
+ }
+ else if (compare(cmd_str, VERSION, FALSE))
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, "%s", version);
+ }
+ else if (compare(cmd_str, CASE, FALSE))
+ case_sen = TRUE;
+ else if (compare(cmd_str, NOCASE, FALSE))
+ case_sen = FALSE;
+ else if (compare(cmd_str, EXPAND, FALSE))
+ expand_tabs = TRUE;
+ else if (compare(cmd_str, NOEXPAND, FALSE))
+ expand_tabs = FALSE;
+ else if (compare(cmd_str, Exit_string, FALSE))
+ finish();
+ else if (compare(cmd_str, chinese_cmd, FALSE))
+ {
+ ee_chinese = TRUE;
+#ifdef NCURSE
+ nc_setattrib(A_NC_BIG5);
+#endif /* NCURSE */
+ }
+ else if (compare(cmd_str, nochinese_cmd, FALSE))
+ {
+ ee_chinese = FALSE;
+#ifdef NCURSE
+ nc_clearattrib(A_NC_BIG5);
+#endif /* NCURSE */
+ }
+ else if (compare(cmd_str, QUIT_string, FALSE))
+ quit(0);
+ else if (*cmd_str == '!')
+ {
+ cmd_str++;
+ if ((*cmd_str == ' ') || (*cmd_str == 9))
+ cmd_str = next_word(cmd_str);
+ sh_command(cmd_str);
+ }
+ else if ((*cmd_str == '<') && (!in_pipe))
+ {
+ in_pipe = TRUE;
+ shell_fork = FALSE;
+ cmd_str++;
+ if ((*cmd_str == ' ') || (*cmd_str == '\t'))
+ cmd_str = next_word(cmd_str);
+ command(cmd_str);
+ in_pipe = FALSE;
+ shell_fork = TRUE;
+ }
+ else if ((*cmd_str == '>') && (!out_pipe))
+ {
+ out_pipe = TRUE;
+ cmd_str++;
+ if ((*cmd_str == ' ') || (*cmd_str == '\t'))
+ cmd_str = next_word(cmd_str);
+ command(cmd_str);
+ out_pipe = FALSE;
+ }
+ else
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, unkn_cmd_str, cmd_str);
+ }
+ if (cmd_str2 != NULL)
+ free(cmd_str2);
+}
+
+int
+scan(line, offset, column) /* determine horizontal position for get_string */
+char *line;
+int offset;
+int column;
+{
+ char *stemp;
+ int i;
+ int j;
+
+ stemp = line;
+ i = 0;
+ j = column;
+ while (i < offset)
+ {
+ i++;
+ j += len_char(*stemp, j);
+ stemp++;
+ }
+ return(j);
+}
+
+char *
+get_string(prompt, advance) /* read string from input on command line */
+char *prompt; /* string containing user prompt message */
+int advance; /* if true, skip leading spaces and tabs */
+{
+ char *string;
+ char *tmp_string;
+ char *nam_str;
+ char *g_point;
+ int tmp_int;
+ int g_horz, g_position, g_pos;
+ int esc_flag;
+
+ g_point = tmp_string = malloc(512);
+ wmove(com_win,0,0);
+ wclrtoeol(com_win);
+ waddstr(com_win, prompt);
+ wrefresh(com_win);
+ nam_str = tmp_string;
+ clear_com_win = TRUE;
+ g_horz = g_position = scan(prompt, strlen(prompt), 0);
+ g_pos = 0;
+ do
+ {
+ esc_flag = FALSE;
+ in = wgetch(com_win);
+ if (in == -1)
+ exit(0);
+ if (((in == 8) || (in == 127) || (in == KEY_BACKSPACE)) && (g_pos > 0))
+ {
+ tmp_int = g_horz;
+ g_pos--;
+ g_horz = scan(g_point, g_pos, g_position);
+ tmp_int = tmp_int - g_horz;
+ for (; 0 < tmp_int; tmp_int--)
+ {
+ if ((g_horz+tmp_int) < (last_col - 1))
+ {
+ waddch(com_win, '\010');
+ waddch(com_win, ' ');
+ waddch(com_win, '\010');
+ }
+ }
+ nam_str--;
+ }
+ else if ((in != 8) && (in != 127) && (in != '\n') && (in != '\r') && (in < 256))
+ {
+ if (in == '\026') /* control-v, accept next character verbatim */
+ { /* allows entry of ^m, ^j, and ^h */
+ esc_flag = TRUE;
+ in = wgetch(com_win);
+ if (in == -1)
+ exit(0);
+ }
+ *nam_str = in;
+ g_pos++;
+ if (!isprint((unsigned char)in) && (g_horz < (last_col - 1)))
+ g_horz += out_char(com_win, in, g_horz);
+ else
+ {
+ g_horz++;
+ if (g_horz < (last_col - 1))
+ waddch(com_win, (unsigned char)in);
+ }
+ nam_str++;
+ }
+ wrefresh(com_win);
+ if (esc_flag)
+ in = '\0';
+ } while ((in != '\n') && (in != '\r'));
+ *nam_str = '\0';
+ nam_str = tmp_string;
+ if (((*nam_str == ' ') || (*nam_str == 9)) && (advance))
+ nam_str = next_word(nam_str);
+ string = malloc(strlen(nam_str) + 1);
+ strcpy(string, nam_str);
+ free(tmp_string);
+ wrefresh(com_win);
+ return(string);
+}
+
+int
+compare(string1, string2, sensitive) /* compare two strings */
+char *string1;
+char *string2;
+int sensitive;
+{
+ char *strng1;
+ char *strng2;
+ int tmp;
+ int equal;
+
+ strng1 = string1;
+ strng2 = string2;
+ tmp = 0;
+ if ((strng1 == NULL) || (strng2 == NULL) || (*strng1 == '\0') || (*strng2 == '\0'))
+ return(FALSE);
+ equal = TRUE;
+ while (equal)
+ {
+ if (sensitive)
+ {
+ if (*strng1 != *strng2)
+ equal = FALSE;
+ }
+ else
+ {
+ if (toupper((unsigned char)*strng1) != toupper((unsigned char)*strng2))
+ equal = FALSE;
+ }
+ strng1++;
+ strng2++;
+ if ((*strng1 == '\0') || (*strng2 == '\0') || (*strng1 == ' ') || (*strng2 == ' '))
+ break;
+ tmp++;
+ }
+ return(equal);
+}
+
+void
+goto_line(cmd_str)
+char *cmd_str;
+{
+ int number;
+ int i;
+ char *ptr;
+ char direction = '\0';
+ struct text *t_line;
+
+ ptr = cmd_str;
+ i= 0;
+ while ((*ptr >='0') && (*ptr <= '9'))
+ {
+ i= i * 10 + (*ptr - '0');
+ ptr++;
+ }
+ number = i;
+ i = 0;
+ t_line = curr_line;
+ while ((t_line->line_number > number) && (t_line->prev_line != NULL))
+ {
+ i++;
+ t_line = t_line->prev_line;
+ direction = 'u';
+ }
+ while ((t_line->line_number < number) && (t_line->next_line != NULL))
+ {
+ i++;
+ direction = 'd';
+ t_line = t_line->next_line;
+ }
+ if ((i < 30) && (i > 0))
+ {
+ move_rel(direction, i);
+ }
+ else
+ {
+ if (direction != 'd')
+ {
+ absolute_lin += i;
+ }
+ else
+ {
+ absolute_lin -= i;
+ }
+ curr_line = t_line;
+ point = curr_line->line;
+ position = 1;
+ midscreen((last_line / 2), point);
+ scr_pos = scr_horz;
+ }
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, line_num_str, curr_line->line_number);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+midscreen(line, pnt) /* put current line in middle of screen */
+int line;
+unsigned char *pnt;
+{
+ struct text *mid_line;
+ int i;
+
+ line = min(line, last_line);
+ mid_line = curr_line;
+ for (i = 0; ((i < line) && (curr_line->prev_line != NULL)); i++)
+ curr_line = curr_line->prev_line;
+ scr_vert = scr_horz = 0;
+ wmove(text_win, 0, 0);
+ draw_screen();
+ scr_vert = i;
+ curr_line = mid_line;
+ scanline(pnt);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+get_options(numargs, arguments) /* get arguments from command line */
+int numargs;
+char *arguments[];
+{
+ char *buff;
+ int count;
+ struct files *temp_names = NULL;
+ char *name;
+ char *ptr;
+ int no_more_opts = FALSE;
+
+ /*
+ | see if editor was invoked as 'ree' (restricted mode)
+ */
+
+ if (!(name = strrchr(arguments[0], '/')))
+ name = arguments[0];
+ else
+ name++;
+ if (!strcmp(name, "ree"))
+ restricted = TRUE;
+
+ top_of_stack = NULL;
+ input_file = FALSE;
+ recv_file = FALSE;
+ count = 1;
+ while ((count < numargs)&& (!no_more_opts))
+ {
+ buff = arguments[count];
+ if (!strcmp("-i", buff))
+ {
+ info_window = FALSE;
+ }
+ else if (!strcmp("-e", buff))
+ {
+ expand_tabs = FALSE;
+ }
+ else if (!strcmp("-h", buff))
+ {
+ nohighlight = TRUE;
+ }
+ else if (!strcmp("-?", buff))
+ {
+ fprintf(stderr, usage0, arguments[0]);
+ fputs(usage1, stderr);
+ fputs(usage2, stderr);
+ fputs(usage3, stderr);
+ fputs(usage4, stderr);
+ exit(1);
+ }
+ else if ((*buff == '+') && (start_at_line == NULL))
+ {
+ buff++;
+ start_at_line = buff;
+ }
+ else if (!(strcmp("--", buff)))
+ no_more_opts = TRUE;
+ else
+ {
+ count--;
+ no_more_opts = TRUE;
+ }
+ count++;
+ }
+ while (count < numargs)
+ {
+ buff = arguments[count];
+ if (top_of_stack == NULL)
+ {
+ temp_names = top_of_stack = name_alloc();
+ }
+ else
+ {
+ temp_names->next_name = name_alloc();
+ temp_names = temp_names->next_name;
+ }
+ ptr = temp_names->name = malloc(strlen(buff) + 1);
+ while (*buff != '\0')
+ {
+ *ptr = *buff;
+ buff++;
+ ptr++;
+ }
+ *ptr = '\0';
+ temp_names->next_name = NULL;
+ input_file = TRUE;
+ recv_file = TRUE;
+ count++;
+ }
+}
+
+void
+check_fp() /* open or close files according to flags */
+{
+ int line_num;
+ int temp;
+ struct stat buf;
+
+ clear_com_win = TRUE;
+ tmp_vert = scr_vert;
+ tmp_horz = scr_horz;
+ tmp_line = curr_line;
+ if (input_file)
+ {
+ in_file_name = tmp_file = top_of_stack->name;
+ top_of_stack = top_of_stack->next_name;
+ }
+ temp = stat(tmp_file, &buf);
+ buf.st_mode &= ~07777;
+ if ((temp != -1) && (buf.st_mode != 0100000) && (buf.st_mode != 0))
+ {
+ wprintw(com_win, file_is_dir_msg, tmp_file);
+ wrefresh(com_win);
+ if (input_file)
+ {
+ quit(0);
+ return;
+ }
+ else
+ return;
+ }
+ if ((get_fd = open(tmp_file, O_RDONLY)) == -1)
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ if (input_file)
+ wprintw(com_win, new_file_msg, tmp_file);
+ else
+ wprintw(com_win, cant_open_msg, tmp_file);
+ wrefresh(com_win);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ wrefresh(text_win);
+ recv_file = FALSE;
+ input_file = FALSE;
+ return;
+ }
+ else
+ get_file(tmp_file);
+
+ recv_file = FALSE;
+ line_num = curr_line->line_number;
+ scr_vert = tmp_vert;
+ scr_horz = tmp_horz;
+ if (input_file)
+ curr_line= first_line;
+ else
+ curr_line = tmp_line;
+ point = curr_line->line;
+ draw_screen();
+ if (input_file)
+ {
+ input_file = FALSE;
+ if (start_at_line != NULL)
+ {
+ line_num = atoi(start_at_line) - 1;
+ move_rel('d', line_num);
+ line_num = 0;
+ start_at_line = NULL;
+ }
+ }
+ else
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ text_changes = TRUE;
+ if ((tmp_file != NULL) && (*tmp_file != '\0'))
+ wprintw(com_win, file_read_fin_msg, tmp_file);
+ }
+ wrefresh(com_win);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+ wrefresh(text_win);
+}
+
+void
+get_file(file_name) /* read specified file into current buffer */
+char *file_name;
+{
+ int can_read; /* file has at least one character */
+ int length; /* length of line read by read */
+ int append; /* should text be appended to current line */
+ struct text *temp_line;
+ char ro_flag = FALSE;
+
+ if (recv_file) /* if reading a file */
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, reading_file_msg, file_name);
+ if (access(file_name, 2)) /* check permission to write */
+ {
+ if ((errno == ENOTDIR) || (errno == EACCES) || (errno == EROFS) || (errno == ETXTBSY) || (errno == EFAULT))
+ {
+ wprintw(com_win, read_only_msg);
+ ro_flag = TRUE;
+ }
+ }
+ wrefresh(com_win);
+ }
+ if (curr_line->line_length > 1) /* if current line is not blank */
+ {
+ insert_line(FALSE);
+ left(FALSE);
+ append = FALSE;
+ }
+ else
+ append = TRUE;
+ can_read = FALSE; /* test if file has any characters */
+ while (((length = read(get_fd, in_string, 512)) != 0) && (length != -1))
+ {
+ can_read = TRUE; /* if set file has at least 1 character */
+ get_line(length, in_string, &append);
+ }
+ if ((can_read) && (curr_line->line_length == 1))
+ {
+ temp_line = curr_line->prev_line;
+ temp_line->next_line = curr_line->next_line;
+ if (temp_line->next_line != NULL)
+ temp_line->next_line->prev_line = temp_line;
+ if (curr_line->line != NULL)
+ free(curr_line->line);
+ free(curr_line);
+ curr_line = temp_line;
+ }
+ if (input_file) /* if this is the file to be edited display number of lines */
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, file_read_lines_msg, in_file_name, curr_line->line_number);
+ if (ro_flag)
+ wprintw(com_win, read_only_msg);
+ wrefresh(com_win);
+ }
+ else if (can_read) /* not input_file and file is non-zero size */
+ text_changes = TRUE;
+
+ if (recv_file) /* if reading a file */
+ {
+ in = EOF;
+ }
+}
+
+void
+get_line(length, in_string, append) /* read string and split into lines */
+int length; /* length of string read by read */
+unsigned char *in_string; /* string read by read */
+int *append; /* TRUE if must append more text to end of current line */
+{
+ unsigned char *str1;
+ unsigned char *str2;
+ int num; /* offset from start of string */
+ int char_count; /* length of new line (or added portion */
+ int temp_counter; /* temporary counter value */
+ struct text *tline; /* temporary pointer to new line */
+ int first_time; /* if TRUE, the first time through the loop */
+
+ str2 = in_string;
+ num = 0;
+ first_time = TRUE;
+ while (num < length)
+ {
+ if (!first_time)
+ {
+ if (num < length)
+ {
+ str2++;
+ num++;
+ }
+ }
+ else
+ first_time = FALSE;
+ str1 = str2;
+ char_count = 1;
+ /* find end of line */
+ while ((*str2 != '\n') && (num < length))
+ {
+ str2++;
+ num++;
+ char_count++;
+ }
+ if (!(*append)) /* if not append to current line, insert new one */
+ {
+ tline = txtalloc(); /* allocate data structure for next line */
+ tline->line_number = curr_line->line_number + 1;
+ tline->next_line = curr_line->next_line;
+ tline->prev_line = curr_line;
+ curr_line->next_line = tline;
+ if (tline->next_line != NULL)
+ tline->next_line->prev_line = tline;
+ curr_line = tline;
+ curr_line->line = point = (unsigned char *) malloc(char_count);
+ curr_line->line_length = char_count;
+ curr_line->max_length = char_count;
+ }
+ else
+ {
+ point = resiz_line(char_count, curr_line, curr_line->line_length);
+ curr_line->line_length += (char_count - 1);
+ }
+ for (temp_counter = 1; temp_counter < char_count; temp_counter++)
+ {
+ *point = *str1;
+ point++;
+ str1++;
+ }
+ *point = '\0';
+ *append = FALSE;
+ if ((num == length) && (*str2 != '\n'))
+ *append = TRUE;
+ }
+}
+
+void
+draw_screen() /* redraw the screen from current postion */
+{
+ struct text *temp_line;
+ unsigned char *line_out;
+ int temp_vert;
+
+ temp_line = curr_line;
+ temp_vert = scr_vert;
+ wclrtobot(text_win);
+ while ((temp_line != NULL) && (temp_vert <= last_line))
+ {
+ line_out = temp_line->line;
+ draw_line(temp_vert, 0, line_out, 1, temp_line->line_length);
+ temp_vert++;
+ temp_line = temp_line->next_line;
+ }
+ wmove(text_win, temp_vert, 0);
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+finish() /* prepare to exit edit session */
+{
+ char *file_name = in_file_name;
+
+ /*
+ | changes made here should be reflected in the 'save'
+ | portion of file_op()
+ */
+
+ if ((file_name == NULL) || (*file_name == '\0'))
+ file_name = get_string(save_file_name_prompt, TRUE);
+
+ if ((file_name == NULL) || (*file_name == '\0'))
+ {
+ wmove(com_win, 0, 0);
+ wprintw(com_win, file_not_saved_msg);
+ wclrtoeol(com_win);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ return;
+ }
+
+ tmp_file = resolve_name(file_name);
+ if (tmp_file != file_name)
+ {
+ free(file_name);
+ file_name = tmp_file;
+ }
+
+ if (write_file(file_name, 1))
+ {
+ text_changes = FALSE;
+ quit(0);
+ }
+}
+
+int
+quit(noverify) /* exit editor */
+int noverify;
+{
+ char *ans;
+
+ touchwin(text_win);
+ wrefresh(text_win);
+ if ((text_changes) && (!noverify))
+ {
+ ans = get_string(changes_made_prompt, TRUE);
+ if (toupper((unsigned char)*ans) == toupper((unsigned char)*yes_char))
+ text_changes = FALSE;
+ else
+ return(0);
+ free(ans);
+ }
+ if (top_of_stack == NULL)
+ {
+ if (info_window)
+ wrefresh(info_win);
+ wrefresh(com_win);
+ resetty();
+ endwin();
+ putchar('\n');
+ exit(0);
+ }
+ else
+ {
+ delete_text();
+ recv_file = TRUE;
+ input_file = TRUE;
+ check_fp();
+ }
+ return(0);
+}
+
+void
+edit_abort(arg)
+int arg;
+{
+ wrefresh(com_win);
+ resetty();
+ endwin();
+ putchar('\n');
+ exit(1);
+}
+
+void
+delete_text()
+{
+ while (curr_line->next_line != NULL)
+ curr_line = curr_line->next_line;
+ while (curr_line != first_line)
+ {
+ free(curr_line->line);
+ curr_line = curr_line->prev_line;
+ absolute_lin--;
+ free(curr_line->next_line);
+ }
+ curr_line->next_line = NULL;
+ *curr_line->line = '\0';
+ curr_line->line_length = 1;
+ curr_line->line_number = 1;
+ point = curr_line->line;
+ scr_pos = scr_vert = scr_horz = 0;
+ position = 1;
+}
+
+int
+write_file(file_name, warn_if_exists)
+char *file_name;
+int warn_if_exists;
+{
+ char cr;
+ char *tmp_point;
+ struct text *out_line;
+ int lines, charac;
+ int temp_pos;
+ int write_flag = TRUE;
+
+ charac = lines = 0;
+ if (warn_if_exists &&
+ ((in_file_name == NULL) || strcmp(in_file_name, file_name)))
+ {
+ if ((temp_fp = fopen(file_name, "r")))
+ {
+ tmp_point = get_string(file_exists_prompt, TRUE);
+ if (toupper((unsigned char)*tmp_point) == toupper((unsigned char)*yes_char))
+ write_flag = TRUE;
+ else
+ write_flag = FALSE;
+ fclose(temp_fp);
+ free(tmp_point);
+ }
+ }
+
+ clear_com_win = TRUE;
+
+ if (write_flag)
+ {
+ if ((temp_fp = fopen(file_name, "w")) == NULL)
+ {
+ clear_com_win = TRUE;
+ wmove(com_win,0,0);
+ wclrtoeol(com_win);
+ wprintw(com_win, create_file_fail_msg, file_name);
+ wrefresh(com_win);
+ return(FALSE);
+ }
+ else
+ {
+ wmove(com_win,0,0);
+ wclrtoeol(com_win);
+ wprintw(com_win, writing_file_msg, file_name);
+ wrefresh(com_win);
+ cr = '\n';
+ out_line = first_line;
+ while (out_line != NULL)
+ {
+ temp_pos = 1;
+ tmp_point= out_line->line;
+ while (temp_pos < out_line->line_length)
+ {
+ putc(*tmp_point, temp_fp);
+ tmp_point++;
+ temp_pos++;
+ }
+ charac += out_line->line_length;
+ out_line = out_line->next_line;
+ putc(cr, temp_fp);
+ lines++;
+ }
+ fclose(temp_fp);
+ wmove(com_win,0,0);
+ wclrtoeol(com_win);
+ wprintw(com_win, file_written_msg, file_name, lines, charac);
+ wrefresh(com_win);
+ return(TRUE);
+ }
+ }
+ else
+ return(FALSE);
+}
+
+int
+search(display_message) /* search for string in srch_str */
+int display_message;
+{
+ int lines_moved;
+ int iter;
+ int found;
+
+ if ((srch_str == NULL) || (*srch_str == '\0'))
+ return(FALSE);
+ if (display_message)
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, searching_msg);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ }
+ lines_moved = 0;
+ found = FALSE;
+ srch_line = curr_line;
+ srch_1 = point;
+ if (position < curr_line->line_length)
+ srch_1++;
+ iter = position + 1;
+ while ((!found) && (srch_line != NULL))
+ {
+ while ((iter < srch_line->line_length) && (!found))
+ {
+ srch_2 = srch_1;
+ if (case_sen) /* if case sensitive */
+ {
+ srch_3 = srch_str;
+ while ((*srch_2 == *srch_3) && (*srch_3 != '\0'))
+ {
+ found = TRUE;
+ srch_2++;
+ srch_3++;
+ } /* end while */
+ }
+ else /* if not case sensitive */
+ {
+ srch_3 = u_srch_str;
+ while ((toupper(*srch_2) == *srch_3) && (*srch_3 != '\0'))
+ {
+ found = TRUE;
+ srch_2++;
+ srch_3++;
+ }
+ } /* end else */
+ if (!((*srch_3 == '\0') && (found)))
+ {
+ found = FALSE;
+ if (iter < srch_line->line_length)
+ srch_1++;
+ iter++;
+ }
+ }
+ if (!found)
+ {
+ srch_line = srch_line->next_line;
+ if (srch_line != NULL)
+ srch_1 = srch_line->line;
+ iter = 1;
+ lines_moved++;
+ }
+ }
+ if (found)
+ {
+ if (display_message)
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wrefresh(com_win);
+ }
+ if (lines_moved == 0)
+ {
+ while (position < iter)
+ right(TRUE);
+ }
+ else
+ {
+ if (lines_moved < 30)
+ {
+ move_rel('d', lines_moved);
+ while (position < iter)
+ right(TRUE);
+ }
+ else
+ {
+ absolute_lin += lines_moved;
+ curr_line = srch_line;
+ point = srch_1;
+ position = iter;
+ scanline(point);
+ scr_pos = scr_horz;
+ midscreen((last_line / 2), point);
+ }
+ }
+ }
+ else
+ {
+ if (display_message)
+ {
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, str_not_found_msg, srch_str);
+ wrefresh(com_win);
+ }
+ wmove(text_win, scr_vert,(scr_horz - horiz_offset));
+ }
+ return(found);
+}
+
+void
+search_prompt() /* prompt and read search string (srch_str) */
+{
+ if (srch_str != NULL)
+ free(srch_str);
+ if ((u_srch_str != NULL) && (*u_srch_str != '\0'))
+ free(u_srch_str);
+ srch_str = get_string(search_prompt_str, FALSE);
+ gold = FALSE;
+ srch_3 = srch_str;
+ srch_1 = u_srch_str = malloc(strlen(srch_str) + 1);
+ while (*srch_3 != '\0')
+ {
+ *srch_1 = toupper(*srch_3);
+ srch_1++;
+ srch_3++;
+ }
+ *srch_1 = '\0';
+ search(TRUE);
+}
+
+void
+del_char() /* delete current character */
+{
+ in = 8; /* backspace */
+ if (position < curr_line->line_length) /* if not end of line */
+ {
+ if ((ee_chinese) && (*point > 127) &&
+ ((curr_line->line_length - position) >= 2))
+ {
+ point++;
+ position++;
+ }
+ position++;
+ point++;
+ scanline(point);
+ delete(TRUE);
+ }
+ else
+ {
+ right(TRUE);
+ delete(TRUE);
+ }
+}
+
+void
+undel_char() /* undelete last deleted character */
+{
+ if (d_char[0] == '\n') /* insert line if last del_char deleted eol */
+ insert_line(TRUE);
+ else
+ {
+ in = d_char[0];
+ insert(in);
+ if (d_char[1] != '\0')
+ {
+ in = d_char[1];
+ insert(in);
+ }
+ }
+}
+
+void
+del_word() /* delete word in front of cursor */
+{
+ int tposit;
+ int difference;
+ unsigned char *d_word2;
+ unsigned char *d_word3;
+ unsigned char tmp_char[3];
+
+ if (d_word != NULL)
+ free(d_word);
+ d_word = malloc(curr_line->line_length);
+ tmp_char[0] = d_char[0];
+ tmp_char[1] = d_char[1];
+ tmp_char[2] = d_char[2];
+ d_word3 = point;
+ d_word2 = d_word;
+ tposit = position;
+ while ((tposit < curr_line->line_length) &&
+ ((*d_word3 != ' ') && (*d_word3 != '\t')))
+ {
+ tposit++;
+ *d_word2 = *d_word3;
+ d_word2++;
+ d_word3++;
+ }
+ while ((tposit < curr_line->line_length) &&
+ ((*d_word3 == ' ') || (*d_word3 == '\t')))
+ {
+ tposit++;
+ *d_word2 = *d_word3;
+ d_word2++;
+ d_word3++;
+ }
+ *d_word2 = '\0';
+ d_wrd_len = difference = d_word2 - d_word;
+ d_word2 = point;
+ while (tposit < curr_line->line_length)
+ {
+ tposit++;
+ *d_word2 = *d_word3;
+ d_word2++;
+ d_word3++;
+ }
+ curr_line->line_length -= difference;
+ *d_word2 = '\0';
+ draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
+ d_char[0] = tmp_char[0];
+ d_char[1] = tmp_char[1];
+ d_char[2] = tmp_char[2];
+ text_changes = TRUE;
+ formatted = FALSE;
+}
+
+void
+undel_word() /* undelete last deleted word */
+{
+ int temp;
+ int tposit;
+ unsigned char *tmp_old_ptr;
+ unsigned char *tmp_space;
+ unsigned char *tmp_ptr;
+ unsigned char *d_word_ptr;
+
+ /*
+ | resize line to handle undeleted word
+ */
+ if ((curr_line->max_length - (curr_line->line_length + d_wrd_len)) < 5)
+ point = resiz_line(d_wrd_len, curr_line, position);
+ tmp_ptr = tmp_space = malloc(curr_line->line_length + d_wrd_len);
+ d_word_ptr = d_word;
+ temp = 1;
+ /*
+ | copy d_word contents into temp space
+ */
+ while (temp <= d_wrd_len)
+ {
+ temp++;
+ *tmp_ptr = *d_word_ptr;
+ tmp_ptr++;
+ d_word_ptr++;
+ }
+ tmp_old_ptr = point;
+ tposit = position;
+ /*
+ | copy contents of line from curent position to eol into
+ | temp space
+ */
+ while (tposit < curr_line->line_length)
+ {
+ temp++;
+ tposit++;
+ *tmp_ptr = *tmp_old_ptr;
+ tmp_ptr++;
+ tmp_old_ptr++;
+ }
+ curr_line->line_length += d_wrd_len;
+ tmp_old_ptr = point;
+ *tmp_ptr = '\0';
+ tmp_ptr = tmp_space;
+ tposit = 1;
+ /*
+ | now copy contents from temp space back to original line
+ */
+ while (tposit < temp)
+ {
+ tposit++;
+ *tmp_old_ptr = *tmp_ptr;
+ tmp_ptr++;
+ tmp_old_ptr++;
+ }
+ *tmp_old_ptr = '\0';
+ free(tmp_space);
+ draw_line(scr_vert, scr_horz, point, position, curr_line->line_length);
+}
+
+void
+del_line() /* delete from cursor to end of line */
+{
+ unsigned char *dl1;
+ unsigned char *dl2;
+ int tposit;
+
+ if (d_line != NULL)
+ free(d_line);
+ d_line = malloc(curr_line->line_length);
+ dl1 = d_line;
+ dl2 = point;
+ tposit = position;
+ while (tposit < curr_line->line_length)
+ {
+ *dl1 = *dl2;
+ dl1++;
+ dl2++;
+ tposit++;
+ }
+ dlt_line->line_length = 1 + tposit - position;
+ *dl1 = '\0';
+ *point = '\0';
+ curr_line->line_length = position;
+ wclrtoeol(text_win);
+ if (curr_line->next_line != NULL)
+ {
+ right(FALSE);
+ delete(FALSE);
+ }
+ text_changes = TRUE;
+}
+
+void
+undel_line() /* undelete last deleted line */
+{
+ unsigned char *ud1;
+ unsigned char *ud2;
+ int tposit;
+
+ if (dlt_line->line_length == 0)
+ return;
+
+ insert_line(TRUE);
+ left(TRUE);
+ point = resiz_line(dlt_line->line_length, curr_line, position);
+ curr_line->line_length += dlt_line->line_length - 1;
+ ud1 = point;
+ ud2 = d_line;
+ tposit = 1;
+ while (tposit < dlt_line->line_length)
+ {
+ tposit++;
+ *ud1 = *ud2;
+ ud1++;
+ ud2++;
+ }
+ *ud1 = '\0';
+ draw_line(scr_vert, scr_horz,point,position,curr_line->line_length);
+}
+
+void
+adv_word() /* advance to next word */
+{
+while ((position < curr_line->line_length) && ((*point != 32) && (*point != 9)))
+ right(TRUE);
+while ((position < curr_line->line_length) && ((*point == 32) || (*point == 9)))
+ right(TRUE);
+}
+
+void
+move_rel(direction, lines) /* move relative to current line */
+int direction;
+int lines;
+{
+ int i;
+ char *tmp;
+
+ if (direction == 'u')
+ {
+ scr_pos = 0;
+ while (position > 1)
+ left(TRUE);
+ for (i = 0; i < lines; i++)
+ {
+ up();
+ }
+ if ((last_line > 5) && ( scr_vert < 4))
+ {
+ tmp = point;
+ tmp_line = curr_line;
+ for (i= 0;(i<5)&&(curr_line->prev_line != NULL); i++)
+ {
+ up();
+ }
+ scr_vert = scr_vert + i;
+ curr_line = tmp_line;
+ absolute_lin += i;
+ point = tmp;
+ scanline(point);
+ }
+ }
+ else
+ {
+ if ((position != 1) && (curr_line->next_line != NULL))
+ {
+ nextline();
+ scr_pos = scr_horz = 0;
+ if (horiz_offset)
+ {
+ horiz_offset = 0;
+ midscreen(scr_vert, point);
+ }
+ }
+ else
+ adv_line();
+ for (i = 1; i < lines; i++)
+ {
+ down();
+ }
+ if ((last_line > 10) && (scr_vert > (last_line - 5)))
+ {
+ tmp = point;
+ tmp_line = curr_line;
+ for (i=0; (i<5) && (curr_line->next_line != NULL); i++)
+ {
+ down();
+ }
+ absolute_lin -= i;
+ scr_vert = scr_vert - i;
+ curr_line = tmp_line;
+ point = tmp;
+ scanline(point);
+ }
+ }
+ wmove(text_win, scr_vert, (scr_horz - horiz_offset));
+}
+
+void
+eol() /* go to end of line */
+{
+ if (position < curr_line->line_length)
+ {
+ while (position < curr_line->line_length)
+ right(TRUE);
+ }
+ else if (curr_line->next_line != NULL)
+ {
+ right(TRUE);
+ while (position < curr_line->line_length)
+ right(TRUE);
+ }
+}
+
+void
+bol() /* move to beginning of line */
+{
+ if (point != curr_line->line)
+ {
+ while (point != curr_line->line)
+ left(TRUE);
+ }
+ else if (curr_line->prev_line != NULL)
+ {
+ scr_pos = 0;
+ up();
+ }
+}
+
+void
+adv_line() /* advance to beginning of next line */
+{
+ if ((point != curr_line->line) || (scr_pos > 0))
+ {
+ while (position < curr_line->line_length)
+ right(TRUE);
+ right(TRUE);
+ }
+ else if (curr_line->next_line != NULL)
+ {
+ scr_pos = 0;
+ down();
+ }
+}
+
+void
+from_top()
+{
+ struct text *tmpline = first_line;
+ int x = 1;
+
+ while ((tmpline != NULL) && (tmpline != curr_line))
+ {
+ x++;
+ tmpline = tmpline->next_line;
+ }
+ absolute_lin = x;
+}
+
+void
+sh_command(string) /* execute shell command */
+char *string; /* string containing user command */
+{
+ char *temp_point;
+ char *last_slash;
+ char *path; /* directory path to executable */
+ int parent; /* zero if child, child's pid if parent */
+ int value;
+ int return_val;
+ struct text *line_holder;
+
+ if (restrict_mode())
+ {
+ return;
+ }
+
+ if (!(path = getenv("SHELL")))
+ path = "/bin/sh";
+ last_slash = temp_point = path;
+ while (*temp_point != '\0')
+ {
+ if (*temp_point == '/')
+ last_slash = ++temp_point;
+ else
+ temp_point++;
+ }
+
+ /*
+ | if in_pipe is true, then output of the shell operation will be
+ | read by the editor, and curses doesn't need to be turned off
+ */
+
+ if (!in_pipe)
+ {
+ keypad(com_win, FALSE);
+ keypad(text_win, FALSE);
+ echo();
+ nl();
+ noraw();
+ resetty();
+
+#ifndef NCURSE
+ endwin();
+#endif
+ }
+
+ if (in_pipe)
+ {
+ pipe(pipe_in); /* create a pipe */
+ parent = fork();
+ if (!parent) /* if the child */
+ {
+/*
+ | child process which will fork and exec shell command (if shell output is
+ | to be read by editor)
+ */
+ in_pipe = FALSE;
+/*
+ | redirect stdout to pipe
+ */
+ temp_stdout = dup(1);
+ close(1);
+ dup(pipe_in[1]);
+/*
+ | redirect stderr to pipe
+ */
+ temp_stderr = dup(2);
+ close(2);
+ dup(pipe_in[1]);
+ close(pipe_in[1]);
+ /*
+ | child will now continue down 'if (!in_pipe)'
+ | path below
+ */
+ }
+ else /* if the parent */
+ {
+/*
+ | prepare editor to read from the pipe
+ */
+ signal(SIGCHLD, SIG_IGN);
+ line_holder = curr_line;
+ tmp_vert = scr_vert;
+ close(pipe_in[1]);
+ get_fd = pipe_in[0];
+ get_file("");
+ close(pipe_in[0]);
+ scr_vert = tmp_vert;
+ scr_horz = scr_pos = 0;
+ position = 1;
+ curr_line = line_holder;
+ from_top();
+ point = curr_line->line;
+ out_pipe = FALSE;
+ signal(SIGCHLD, SIG_DFL);
+/*
+ | since flag "in_pipe" is still TRUE, the path which waits for the child
+ | process to die will be avoided.
+ | (the pipe is closed, no more output can be expected)
+ */
+ }
+ }
+ if (!in_pipe)
+ {
+ signal(SIGINT, SIG_IGN);
+ if (out_pipe)
+ {
+ pipe(pipe_out);
+ }
+/*
+ | fork process which will exec command
+ */
+ parent = fork();
+ if (!parent) /* if the child */
+ {
+ if (shell_fork)
+ putchar('\n');
+ if (out_pipe)
+ {
+/*
+ | prepare the child process (soon to exec a shell command) to read from the
+ | pipe (which will be output from the editor's buffer)
+ */
+ close(0);
+ dup(pipe_out[0]);
+ close(pipe_out[0]);
+ close(pipe_out[1]);
+ }
+ for (value = 1; value < 24; value++)
+ signal(value, SIG_DFL);
+ execl(path, last_slash, "-c", string, NULL);
+ fprintf(stderr, exec_err_msg, path);
+ exit(-1);
+ }
+ else /* if the parent */
+ {
+ if (out_pipe)
+ {
+/*
+ | output the contents of the buffer to the pipe (to be read by the
+ | process forked and exec'd above as stdin)
+ */
+ close(pipe_out[0]);
+ line_holder = first_line;
+ while (line_holder != NULL)
+ {
+ write(pipe_out[1], line_holder->line, (line_holder->line_length-1));
+ write(pipe_out[1], "\n", 1);
+ line_holder = line_holder->next_line;
+ }
+ close(pipe_out[1]);
+ out_pipe = FALSE;
+ }
+ do
+ {
+ return_val = wait((int *) 0);
+ }
+ while ((return_val != parent) && (return_val != -1));
+/*
+ | if this process is actually the child of the editor, exit. Here's how it
+ | works:
+ | The editor forks a process. If output must be sent to the command to be
+ | exec'd another process is forked, and that process (the child's child)
+ | will exec the command. In this case, "shell_fork" will be FALSE. If no
+ | output is to be performed to the shell command, "shell_fork" will be TRUE.
+ | If this is the editor process, shell_fork will be true, otherwise this is
+ | the child of the edit process.
+ */
+ if (!shell_fork)
+ exit(0);
+ }
+ signal(SIGINT, edit_abort);
+ }
+ if (shell_fork)
+ {
+ fputs(continue_msg, stdout);
+ fflush(stdout);
+ while ((in = getchar()) != '\n')
+ ;
+ }
+
+ if (!in_pipe)
+ {
+ fixterm();
+ noecho();
+ nonl();
+ raw();
+ keypad(text_win, TRUE);
+ keypad(com_win, TRUE);
+ if (info_window)
+ clearok(info_win, TRUE);
+ }
+
+ redraw();
+}
+
+void
+set_up_term() /* set up the terminal for operating with ae */
+{
+ if (!curses_initialized)
+ {
+ initscr();
+ savetty();
+ noecho();
+ raw();
+ nonl();
+ curses_initialized = TRUE;
+ }
+
+ if (((LINES > 15) && (COLS >= 80)) && info_window)
+ last_line = LINES - 8;
+ else
+ {
+ info_window = FALSE;
+ last_line = LINES - 2;
+ }
+
+ idlok(stdscr, TRUE);
+ com_win = newwin(1, COLS, (LINES - 1), 0);
+ keypad(com_win, TRUE);
+ idlok(com_win, TRUE);
+ wrefresh(com_win);
+ if (!info_window)
+ text_win = newwin((LINES - 1), COLS, 0, 0);
+ else
+ text_win = newwin((LINES - 7), COLS, 6, 0);
+ keypad(text_win, TRUE);
+ idlok(text_win, TRUE);
+ wrefresh(text_win);
+ help_win = newwin((LINES - 1), COLS, 0, 0);
+ keypad(help_win, TRUE);
+ idlok(help_win, TRUE);
+ if (info_window)
+ {
+ info_type = CONTROL_KEYS;
+ info_win = newwin(6, COLS, 0, 0);
+ werase(info_win);
+ paint_info_win();
+ }
+
+ last_col = COLS - 1;
+ local_LINES = LINES;
+ local_COLS = COLS;
+
+#ifdef NCURSE
+ if (ee_chinese)
+ nc_setattrib(A_NC_BIG5);
+#endif /* NCURSE */
+
+}
+
+void
+resize_check()
+{
+ if ((LINES == local_LINES) && (COLS == local_COLS))
+ return;
+
+ if (info_window)
+ delwin(info_win);
+ delwin(text_win);
+ delwin(com_win);
+ delwin(help_win);
+ set_up_term();
+ redraw();
+ wrefresh(text_win);
+}
+
+static char item_alpha[] = "abcdefghijklmnopqrstuvwxyz0123456789 ";
+
+int
+menu_op(menu_list)
+struct menu_entries menu_list[];
+{
+ WINDOW *temp_win;
+ int max_width, max_height;
+ int x_off, y_off;
+ int counter;
+ int length;
+ int input;
+ int temp;
+ int list_size;
+ int top_offset; /* offset from top where menu items start */
+ int vert_pos; /* vertical position */
+ int vert_size; /* vertical size for menu list item display */
+ int off_start = 1; /* offset from start of menu items to start display */
+
+
+ /*
+ | determine number and width of menu items
+ */
+
+ list_size = 1;
+ while (menu_list[list_size + 1].item_string != NULL)
+ list_size++;
+ max_width = 0;
+ for (counter = 0; counter <= list_size; counter++)
+ {
+ if ((length = strlen(menu_list[counter].item_string)) > max_width)
+ max_width = length;
+ }
+ max_width += 3;
+ max_width = max(max_width, strlen(menu_cancel_msg));
+ max_width = max(max_width, max(strlen(more_above_str), strlen(more_below_str)));
+ max_width += 6;
+
+ /*
+ | make sure that window is large enough to handle menu
+ | if not, print error message and return to calling function
+ */
+
+ if (max_width > COLS)
+ {
+ wmove(com_win, 0, 0);
+ werase(com_win);
+ wprintw(com_win, menu_too_lrg_msg);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ return(0);
+ }
+
+ top_offset = 0;
+
+ if (list_size > LINES)
+ {
+ max_height = LINES;
+ if (max_height > 11)
+ vert_size = max_height - 8;
+ else
+ vert_size = max_height;
+ }
+ else
+ {
+ vert_size = list_size;
+ max_height = list_size;
+ }
+
+ if (LINES >= (vert_size + 8))
+ {
+ if (menu_list[0].argument != MENU_WARN)
+ max_height = vert_size + 8;
+ else
+ max_height = vert_size + 7;
+ top_offset = 4;
+ }
+ x_off = (COLS - max_width) / 2;
+ y_off = (LINES - max_height - 1) / 2;
+ temp_win = newwin(max_height, max_width, y_off, x_off);
+ keypad(temp_win, TRUE);
+
+ paint_menu(menu_list, max_width, max_height, list_size, top_offset, temp_win, off_start, vert_size);
+
+ counter = 1;
+ vert_pos = 0;
+ do
+ {
+ if (off_start > 2)
+ wmove(temp_win, (1 + counter + top_offset - off_start), 3);
+ else
+ wmove(temp_win, (counter + top_offset - off_start), 3);
+
+ wrefresh(temp_win);
+ in = wgetch(temp_win);
+ input = in;
+ if (input == -1)
+ exit(0);
+
+ if (isascii(input) && isalnum(input))
+ {
+ if (isalpha(input))
+ {
+ temp = 1 + tolower(input) - 'a';
+ }
+ else if (isdigit(input))
+ {
+ temp = (2 + 'z' - 'a') + (input - '0');
+ }
+
+ if (temp <= list_size)
+ {
+ input = '\n';
+ counter = temp;
+ }
+ }
+ else
+ {
+ switch (input)
+ {
+ case ' ': /* space */
+ case '\004': /* ^d, down */
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ counter++;
+ if (counter > list_size)
+ counter = 1;
+ break;
+ case '\010': /* ^h, backspace*/
+ case '\025': /* ^u, up */
+ case 127: /* ^?, delete */
+ case KEY_BACKSPACE:
+ case KEY_LEFT:
+ case KEY_UP:
+ counter--;
+ if (counter == 0)
+ counter = list_size;
+ break;
+ case '\033': /* escape key */
+ if (menu_list[0].argument != MENU_WARN)
+ counter = 0;
+ break;
+ case '\014': /* ^l */
+ case '\022': /* ^r, redraw */
+ paint_menu(menu_list, max_width, max_height,
+ list_size, top_offset, temp_win,
+ off_start, vert_size);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (((list_size - off_start) >= (vert_size - 1)) &&
+ (counter > (off_start + vert_size - 3)) &&
+ (off_start > 1))
+ {
+ if (counter == list_size)
+ off_start = (list_size - vert_size) + 2;
+ else
+ off_start++;
+
+ paint_menu(menu_list, max_width, max_height,
+ list_size, top_offset, temp_win, off_start,
+ vert_size);
+ }
+ else if ((list_size != vert_size) &&
+ (counter > (off_start + vert_size - 2)))
+ {
+ if (counter == list_size)
+ off_start = 2 + (list_size - vert_size);
+ else if (off_start == 1)
+ off_start = 3;
+ else
+ off_start++;
+
+ paint_menu(menu_list, max_width, max_height,
+ list_size, top_offset, temp_win, off_start,
+ vert_size);
+ }
+ else if (counter < off_start)
+ {
+ if (counter <= 2)
+ off_start = 1;
+ else
+ off_start = counter;
+
+ paint_menu(menu_list, max_width, max_height,
+ list_size, top_offset, temp_win, off_start,
+ vert_size);
+ }
+ }
+ while ((input != '\r') && (input != '\n') && (counter != 0));
+
+ werase(temp_win);
+ wrefresh(temp_win);
+ delwin(temp_win);
+
+ if ((menu_list[counter].procedure != NULL) ||
+ (menu_list[counter].iprocedure != NULL) ||
+ (menu_list[counter].nprocedure != NULL))
+ {
+ if (menu_list[counter].argument != -1)
+ (*menu_list[counter].iprocedure)(menu_list[counter].argument);
+ else if (menu_list[counter].ptr_argument != NULL)
+ (*menu_list[counter].procedure)(menu_list[counter].ptr_argument);
+ else
+ (*menu_list[counter].nprocedure)();
+ }
+
+ if (info_window)
+ paint_info_win();
+ redraw();
+
+ return(counter);
+}
+
+void
+paint_menu(menu_list, max_width, max_height, list_size, top_offset, menu_win,
+ off_start, vert_size)
+struct menu_entries menu_list[];
+int max_width, max_height, list_size, top_offset;
+WINDOW *menu_win;
+int off_start, vert_size;
+{
+ int counter, temp_int;
+
+ werase(menu_win);
+
+ /*
+ | output top and bottom portions of menu box only if window
+ | large enough
+ */
+
+ if (max_height > vert_size)
+ {
+ wmove(menu_win, 1, 1);
+ if (!nohighlight)
+ wstandout(menu_win);
+ waddch(menu_win, '+');
+ for (counter = 0; counter < (max_width - 4); counter++)
+ waddch(menu_win, '-');
+ waddch(menu_win, '+');
+
+ wmove(menu_win, (max_height - 2), 1);
+ waddch(menu_win, '+');
+ for (counter = 0; counter < (max_width - 4); counter++)
+ waddch(menu_win, '-');
+ waddch(menu_win, '+');
+ wstandend(menu_win);
+ wmove(menu_win, 2, 3);
+ waddstr(menu_win, menu_list[0].item_string);
+ wmove(menu_win, (max_height - 3), 3);
+ if (menu_list[0].argument != MENU_WARN)
+ waddstr(menu_win, menu_cancel_msg);
+ }
+ if (!nohighlight)
+ wstandout(menu_win);
+
+ for (counter = 0; counter < (vert_size + top_offset); counter++)
+ {
+ if (top_offset == 4)
+ {
+ temp_int = counter + 2;
+ }
+ else
+ temp_int = counter;
+
+ wmove(menu_win, temp_int, 1);
+ waddch(menu_win, '|');
+ wmove(menu_win, temp_int, (max_width - 2));
+ waddch(menu_win, '|');
+ }
+ wstandend(menu_win);
+
+ if (list_size > vert_size)
+ {
+ if (off_start >= 3)
+ {
+ temp_int = 1;
+ wmove(menu_win, top_offset, 3);
+ waddstr(menu_win, more_above_str);
+ }
+ else
+ temp_int = 0;
+
+ for (counter = off_start;
+ ((temp_int + counter - off_start) < (vert_size - 1));
+ counter++)
+ {
+ wmove(menu_win, (top_offset + temp_int +
+ (counter - off_start)), 3);
+ if (list_size > 1)
+ wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
+ waddstr(menu_win, menu_list[counter].item_string);
+ }
+
+ wmove(menu_win, (top_offset + (vert_size - 1)), 3);
+
+ if (counter == list_size)
+ {
+ if (list_size > 1)
+ wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
+ wprintw(menu_win, menu_list[counter].item_string);
+ }
+ else
+ wprintw(menu_win, more_below_str);
+ }
+ else
+ {
+ for (counter = 1; counter <= list_size; counter++)
+ {
+ wmove(menu_win, (top_offset + counter - 1), 3);
+ if (list_size > 1)
+ wprintw(menu_win, "%c) ", item_alpha[min((counter - 1), max_alpha_char)]);
+ waddstr(menu_win, menu_list[counter].item_string);
+ }
+ }
+}
+
+void
+help()
+{
+ int counter;
+
+ werase(help_win);
+ clearok(help_win, TRUE);
+ for (counter = 0; counter < 22; counter++)
+ {
+ wmove(help_win, counter, 0);
+ waddstr(help_win, (emacs_keys_mode) ?
+ emacs_help_text[counter] : help_text[counter]);
+ }
+ wrefresh(help_win);
+ werase(com_win);
+ wmove(com_win, 0, 0);
+ wprintw(com_win, press_any_key_msg);
+ wrefresh(com_win);
+ counter = wgetch(com_win);
+ if (counter == -1)
+ exit(0);
+ werase(com_win);
+ wmove(com_win, 0, 0);
+ werase(help_win);
+ wrefresh(help_win);
+ wrefresh(com_win);
+ redraw();
+}
+
+void
+paint_info_win()
+{
+ int counter;
+
+ if (!info_window)
+ return;
+
+ werase(info_win);
+ for (counter = 0; counter < 5; counter++)
+ {
+ wmove(info_win, counter, 0);
+ wclrtoeol(info_win);
+ if (info_type == CONTROL_KEYS)
+ waddstr(info_win, (emacs_keys_mode) ?
+ emacs_control_keys[counter] : control_keys[counter]);
+ else if (info_type == COMMANDS)
+ waddstr(info_win, command_strings[counter]);
+ }
+ wmove(info_win, 5, 0);
+ if (!nohighlight)
+ wstandout(info_win);
+ waddstr(info_win, separator);
+ wstandend(info_win);
+ wrefresh(info_win);
+}
+
+void
+no_info_window()
+{
+ if (!info_window)
+ return;
+ delwin(info_win);
+ delwin(text_win);
+ info_window = FALSE;
+ last_line = LINES - 2;
+ text_win = newwin((LINES - 1), COLS, 0, 0);
+ keypad(text_win, TRUE);
+ idlok(text_win, TRUE);
+ clearok(text_win, TRUE);
+ midscreen(scr_vert, point);
+ wrefresh(text_win);
+ clear_com_win = TRUE;
+}
+
+void
+create_info_window()
+{
+ if (info_window)
+ return;
+ last_line = LINES - 8;
+ delwin(text_win);
+ text_win = newwin((LINES - 7), COLS, 6, 0);
+ keypad(text_win, TRUE);
+ idlok(text_win, TRUE);
+ werase(text_win);
+ info_window = TRUE;
+ info_win = newwin(6, COLS, 0, 0);
+ werase(info_win);
+ info_type = CONTROL_KEYS;
+ midscreen(min(scr_vert, last_line), point);
+ clearok(info_win, TRUE);
+ paint_info_win();
+ wrefresh(text_win);
+ clear_com_win = TRUE;
+}
+
+int
+file_op(arg)
+int arg;
+{
+ char *string;
+ int flag;
+
+ if (restrict_mode())
+ {
+ return(0);
+ }
+
+ if (arg == READ_FILE)
+ {
+ string = get_string(file_read_prompt_str, TRUE);
+ recv_file = TRUE;
+ tmp_file = resolve_name(string);
+ check_fp();
+ if (tmp_file != string)
+ free(tmp_file);
+ free(string);
+ }
+ else if (arg == WRITE_FILE)
+ {
+ string = get_string(file_write_prompt_str, TRUE);
+ tmp_file = resolve_name(string);
+ write_file(tmp_file, 1);
+ if (tmp_file != string)
+ free(tmp_file);
+ free(string);
+ }
+ else if (arg == SAVE_FILE)
+ {
+ /*
+ | changes made here should be reflected in finish()
+ */
+
+ if (in_file_name)
+ flag = TRUE;
+ else
+ flag = FALSE;
+
+ string = in_file_name;
+ if ((string == NULL) || (*string == '\0'))
+ string = get_string(save_file_name_prompt, TRUE);
+ if ((string == NULL) || (*string == '\0'))
+ {
+ wmove(com_win, 0, 0);
+ wprintw(com_win, file_not_saved_msg);
+ wclrtoeol(com_win);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ return(0);
+ }
+ if (!flag)
+ {
+ tmp_file = resolve_name(string);
+ if (tmp_file != string)
+ {
+ free(string);
+ string = tmp_file;
+ }
+ }
+ if (write_file(string, 1))
+ {
+ in_file_name = string;
+ text_changes = FALSE;
+ }
+ else if (!flag)
+ free(string);
+ }
+ return(0);
+}
+
+void
+shell_op()
+{
+ char *string;
+
+ if (((string = get_string(shell_prompt, TRUE)) != NULL) &&
+ (*string != '\0'))
+ {
+ sh_command(string);
+ free(string);
+ }
+}
+
+void
+leave_op()
+{
+ if (text_changes)
+ {
+ menu_op(leave_menu);
+ }
+ else
+ quit(TRUE);
+}
+
+void
+redraw()
+{
+ if (info_window)
+ {
+ clearok(info_win, TRUE);
+ paint_info_win();
+ }
+ else
+ clearok(text_win, TRUE);
+ midscreen(scr_vert, point);
+}
+
+/*
+ | The following routines will "format" a paragraph (as defined by a
+ | block of text with blank lines before and after the block).
+ */
+
+int
+Blank_Line(test_line) /* test if line has any non-space characters */
+struct text *test_line;
+{
+ unsigned char *line;
+ int length;
+
+ if (test_line == NULL)
+ return(TRUE);
+
+ length = 1;
+ line = test_line->line;
+
+ /*
+ | To handle troff/nroff documents, consider a line with a
+ | period ('.') in the first column to be blank. To handle mail
+ | messages with included text, consider a line with a '>' blank.
+ */
+
+ if ((*line == '.') || (*line == '>'))
+ return(TRUE);
+
+ while (((*line == ' ') || (*line == '\t')) && (length < test_line->line_length))
+ {
+ length++;
+ line++;
+ }
+ if (length != test_line->line_length)
+ return(FALSE);
+ else
+ return(TRUE);
+}
+
+void
+Format() /* format the paragraph according to set margins */
+{
+ int string_count;
+ int offset;
+ int temp_case;
+ int status;
+ int tmp_af;
+ int counter;
+ unsigned char *line;
+ unsigned char *tmp_srchstr;
+ unsigned char *temp1, *temp2;
+ unsigned char *temp_dword;
+ unsigned char temp_d_char[3];
+
+ temp_d_char[0] = d_char[0];
+ temp_d_char[1] = d_char[1];
+ temp_d_char[2] = d_char[2];
+
+/*
+ | if observ_margins is not set, or the current line is blank,
+ | do not format the current paragraph
+ */
+
+ if ((!observ_margins) || (Blank_Line(curr_line)))
+ return;
+
+/*
+ | save the currently set flags, and clear them
+ */
+
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, formatting_msg);
+ wrefresh(com_win);
+
+/*
+ | get current position in paragraph, so after formatting, the cursor
+ | will be in the same relative position
+ */
+
+ tmp_af = auto_format;
+ auto_format = FALSE;
+ offset = position;
+ if (position != 1)
+ prev_word();
+ temp_dword = d_word;
+ d_word = NULL;
+ temp_case = case_sen;
+ case_sen = TRUE;
+ tmp_srchstr = srch_str;
+ temp2 = srch_str = (unsigned char *) malloc(1 + curr_line->line_length - position);
+ if ((*point == ' ') || (*point == '\t'))
+ adv_word();
+ offset -= position;
+ counter = position;
+ line = temp1 = point;
+ while ((*temp1 != '\0') && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length))
+ {
+ *temp2 = *temp1;
+ temp2++;
+ temp1++;
+ counter++;
+ }
+ *temp2 = '\0';
+ if (position != 1)
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+ string_count = 0;
+ status = TRUE;
+ while ((line != point) && (status))
+ {
+ status = search(FALSE);
+ string_count++;
+ }
+
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, formatting_msg);
+ wrefresh(com_win);
+
+/*
+ | now get back to the start of the paragraph to start formatting
+ */
+
+ if (position != 1)
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+
+ observ_margins = FALSE;
+
+/*
+ | Start going through lines, putting spaces at end of lines if they do
+ | not already exist. Append lines together to get one long line, and
+ | eliminate spacing at begin of lines.
+ */
+
+ while (!Blank_Line(curr_line->next_line))
+ {
+ eol();
+ left(TRUE);
+ if (*point != ' ')
+ {
+ right(TRUE);
+ insert(' ');
+ }
+ else
+ right(TRUE);
+ del_char();
+ if ((*point == ' ') || (*point == '\t'))
+ del_word();
+ }
+
+/*
+ | Now there is one long line. Eliminate extra spaces within the line
+ | after the first word (so as not to blow away any indenting the user
+ | may have put in).
+ */
+
+ bol();
+ adv_word();
+ while (position < curr_line->line_length)
+ {
+ if ((*point == ' ') && (*(point + 1) == ' '))
+ del_char();
+ else
+ right(TRUE);
+ }
+
+/*
+ | Now make sure there are two spaces after a '.'.
+ */
+
+ bol();
+ while (position < curr_line->line_length)
+ {
+ if ((*point == '.') && (*(point + 1) == ' '))
+ {
+ right(TRUE);
+ insert(' ');
+ insert(' ');
+ while (*point == ' ')
+ del_char();
+ }
+ right(TRUE);
+ }
+
+ observ_margins = TRUE;
+ bol();
+
+ wmove(com_win, 0, 0);
+ wclrtoeol(com_win);
+ wprintw(com_win, formatting_msg);
+ wrefresh(com_win);
+
+/*
+ | create lines between margins
+ */
+
+ while (position < curr_line->line_length)
+ {
+ while ((scr_pos < right_margin) && (position < curr_line->line_length))
+ right(TRUE);
+ if (position < curr_line->line_length)
+ {
+ prev_word();
+ if (position == 1)
+ adv_word();
+ insert_line(TRUE);
+ }
+ }
+
+/*
+ | go back to begin of paragraph, put cursor back to original position
+ */
+
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+
+/*
+ | find word cursor was in
+ */
+
+ while ((status) && (string_count > 0))
+ {
+ search(FALSE);
+ string_count--;
+ }
+
+/*
+ | offset the cursor to where it was before from the start of the word
+ */
+
+ while (offset > 0)
+ {
+ offset--;
+ right(TRUE);
+ }
+
+/*
+ | reset flags and strings to what they were before formatting
+ */
+
+ if (d_word != NULL)
+ free(d_word);
+ d_word = temp_dword;
+ case_sen = temp_case;
+ free(srch_str);
+ srch_str = tmp_srchstr;
+ d_char[0] = temp_d_char[0];
+ d_char[1] = temp_d_char[1];
+ d_char[2] = temp_d_char[2];
+ auto_format = tmp_af;
+
+ midscreen(scr_vert, point);
+ werase(com_win);
+ wrefresh(com_win);
+}
+
+unsigned char *init_name[3] = {
+ "/usr/share/misc/init.ee",
+ NULL,
+ ".init.ee"
+ };
+
+void
+ee_init() /* check for init file and read it if it exists */
+{
+ FILE *init_file;
+ unsigned char *string;
+ unsigned char *str1;
+ unsigned char *str2;
+ char *home;
+ int counter;
+ int temp_int;
+
+ string = getenv("HOME");
+ if (string == NULL)
+ string = "/tmp";
+ str1 = home = malloc(strlen(string)+10);
+ strcpy(home, string);
+ strcat(home, "/.init.ee");
+ init_name[1] = home;
+ string = malloc(512);
+
+ for (counter = 0; counter < 3; counter++)
+ {
+ if (!(access(init_name[counter], 4)))
+ {
+ init_file = fopen(init_name[counter], "r");
+ while ((str2 = fgets(string, 512, init_file)) != NULL)
+ {
+ str1 = str2 = string;
+ while (*str2 != '\n')
+ str2++;
+ *str2 = '\0';
+
+ if (unique_test(string, init_strings) != 1)
+ continue;
+
+ if (compare(str1, CASE, FALSE))
+ case_sen = TRUE;
+ else if (compare(str1, NOCASE, FALSE))
+ case_sen = FALSE;
+ else if (compare(str1, EXPAND, FALSE))
+ expand_tabs = TRUE;
+ else if (compare(str1, NOEXPAND, FALSE))
+ expand_tabs = FALSE;
+ else if (compare(str1, INFO, FALSE))
+ info_window = TRUE;
+ else if (compare(str1, NOINFO, FALSE))
+ info_window = FALSE;
+ else if (compare(str1, MARGINS, FALSE))
+ observ_margins = TRUE;
+ else if (compare(str1, NOMARGINS, FALSE))
+ observ_margins = FALSE;
+ else if (compare(str1, AUTOFORMAT, FALSE))
+ {
+ auto_format = TRUE;
+ observ_margins = TRUE;
+ }
+ else if (compare(str1, NOAUTOFORMAT, FALSE))
+ auto_format = FALSE;
+ else if (compare(str1, Echo, FALSE))
+ {
+ str1 = next_word(str1);
+ if (*str1 != '\0')
+ echo_string(str1);
+ }
+ else if (compare(str1, PRINTCOMMAND, FALSE))
+ {
+ str1 = next_word(str1);
+ print_command = malloc(strlen(str1)+1);
+ strcpy(print_command, str1);
+ }
+ else if (compare(str1, RIGHTMARGIN, FALSE))
+ {
+ str1 = next_word(str1);
+ if ((*str1 >= '0') && (*str1 <= '9'))
+ {
+ temp_int = atoi(str1);
+ if (temp_int > 0)
+ right_margin = temp_int;
+ }
+ }
+ else if (compare(str1, HIGHLIGHT, FALSE))
+ nohighlight = FALSE;
+ else if (compare(str1, NOHIGHLIGHT, FALSE))
+ nohighlight = TRUE;
+ else if (compare(str1, EIGHTBIT, FALSE))
+ eightbit = TRUE;
+ else if (compare(str1, NOEIGHTBIT, FALSE))
+ {
+ eightbit = FALSE;
+ ee_chinese = FALSE;
+ }
+ else if (compare(str1, EMACS_string, FALSE))
+ emacs_keys_mode = TRUE;
+ else if (compare(str1, NOEMACS_string, FALSE))
+ emacs_keys_mode = FALSE;
+ else if (compare(str1, chinese_cmd, FALSE))
+ {
+ ee_chinese = TRUE;
+ eightbit = TRUE;
+ }
+ else if (compare(str1, nochinese_cmd, FALSE))
+ ee_chinese = FALSE;
+ }
+ fclose(init_file);
+ }
+ }
+ free(string);
+ free(home);
+
+ string = getenv("LANG");
+ if (string != NULL)
+ {
+ if (strcmp(string, "zh_TW.big5") == 0)
+ {
+ ee_chinese = TRUE;
+ eightbit = TRUE;
+ }
+ }
+}
+
+/*
+ | Save current configuration to .init.ee file in the current directory.
+ */
+
+void
+dump_ee_conf()
+{
+ FILE *init_file;
+ FILE *old_init_file = NULL;
+ char *file_name = ".init.ee";
+ char *home_dir = "~/.init.ee";
+ char buffer[512];
+ struct stat buf;
+ char *string;
+ int length;
+ int option = 0;
+
+ if (restrict_mode())
+ {
+ return;
+ }
+
+ option = menu_op(config_dump_menu);
+
+ werase(com_win);
+ wmove(com_win, 0, 0);
+
+ if (option == 0)
+ {
+ wprintw(com_win, conf_not_saved_msg);
+ wrefresh(com_win);
+ return;
+ }
+ else if (option == 2)
+ file_name = resolve_name(home_dir);
+
+ /*
+ | If a .init.ee file exists, move it to .init.ee.old.
+ */
+
+ if (stat(file_name, &buf) != -1)
+ {
+ sprintf(buffer, "%s.old", file_name);
+ unlink(buffer);
+ link(file_name, buffer);
+ unlink(file_name);
+ old_init_file = fopen(buffer, "r");
+ }
+
+ init_file = fopen(file_name, "w");
+ if (init_file == NULL)
+ {
+ wprintw(com_win, conf_dump_err_msg);
+ wrefresh(com_win);
+ return;
+ }
+
+ if (old_init_file != NULL)
+ {
+ /*
+ | Copy non-configuration info into new .init.ee file.
+ */
+ while ((string = fgets(buffer, 512, old_init_file)) != NULL)
+ {
+ length = strlen(string);
+ string[length - 1] = '\0';
+
+ if (unique_test(string, init_strings) == 1)
+ {
+ if (compare(string, Echo, FALSE))
+ {
+ fprintf(init_file, "%s\n", string);
+ }
+ }
+ else
+ fprintf(init_file, "%s\n", string);
+ }
+
+ fclose(old_init_file);
+ }
+
+ fprintf(init_file, "%s\n", case_sen ? CASE : NOCASE);
+ fprintf(init_file, "%s\n", expand_tabs ? EXPAND : NOEXPAND);
+ fprintf(init_file, "%s\n", info_window ? INFO : NOINFO );
+ fprintf(init_file, "%s\n", observ_margins ? MARGINS : NOMARGINS );
+ fprintf(init_file, "%s\n", auto_format ? AUTOFORMAT : NOAUTOFORMAT );
+ fprintf(init_file, "%s %s\n", PRINTCOMMAND, print_command);
+ fprintf(init_file, "%s %d\n", RIGHTMARGIN, right_margin);
+ fprintf(init_file, "%s\n", nohighlight ? NOHIGHLIGHT : HIGHLIGHT );
+ fprintf(init_file, "%s\n", eightbit ? EIGHTBIT : NOEIGHTBIT );
+ fprintf(init_file, "%s\n", emacs_keys_mode ? EMACS_string : NOEMACS_string );
+ fprintf(init_file, "%s\n", ee_chinese ? chinese_cmd : nochinese_cmd );
+
+ fclose(init_file);
+
+ wprintw(com_win, conf_dump_success_msg, file_name);
+ wrefresh(com_win);
+
+ if ((option == 2) && (file_name != home_dir))
+ {
+ free(file_name);
+ }
+}
+
+void
+echo_string(string) /* echo the given string */
+char *string;
+{
+ char *temp;
+ int Counter;
+
+ temp = string;
+ while (*temp != '\0')
+ {
+ if (*temp == '\\')
+ {
+ temp++;
+ if (*temp == 'n')
+ putchar('\n');
+ else if (*temp == 't')
+ putchar('\t');
+ else if (*temp == 'b')
+ putchar('\b');
+ else if (*temp == 'r')
+ putchar('\r');
+ else if (*temp == 'f')
+ putchar('\f');
+ else if ((*temp == 'e') || (*temp == 'E'))
+ putchar('\033'); /* escape */
+ else if (*temp == '\\')
+ putchar('\\');
+ else if (*temp == '\'')
+ putchar('\'');
+ else if ((*temp >= '0') && (*temp <= '9'))
+ {
+ Counter = 0;
+ while ((*temp >= '0') && (*temp <= '9'))
+ {
+ Counter = (8 * Counter) + (*temp - '0');
+ temp++;
+ }
+ putchar(Counter);
+ temp--;
+ }
+ temp++;
+ }
+ else
+ {
+ putchar(*temp);
+ temp++;
+ }
+ }
+
+ fflush(stdout);
+}
+
+void
+spell_op() /* check spelling of words in the editor */
+{
+ if (restrict_mode())
+ {
+ return;
+ }
+ top(); /* go to top of file */
+ insert_line(FALSE); /* create two blank lines */
+ insert_line(FALSE);
+ top();
+ command(shell_echo_msg);
+ adv_line();
+ wmove(com_win, 0, 0);
+ wprintw(com_win, spell_in_prog_msg);
+ wrefresh(com_win);
+ command("<>!spell"); /* send contents of buffer to command 'spell'
+ and read the results back into the editor */
+}
+
+void
+ispell_op()
+{
+ char template[128], *name;
+ char string[256];
+ int fd;
+
+ if (restrict_mode())
+ {
+ return;
+ }
+ (void)sprintf(template, "/tmp/ee.XXXXXXXX");
+ fd = mkstemp(template);
+ if (fd < 0) {
+ wmove(com_win, 0, 0);
+ wprintw(com_win, create_file_fail_msg, name);
+ wrefresh(com_win);
+ return;
+ }
+ close(fd);
+ if (write_file(name, 0))
+ {
+ sprintf(string, "ispell %s", name);
+ sh_command(string);
+ delete_text();
+ tmp_file = name;
+ recv_file = TRUE;
+ check_fp();
+ unlink(name);
+ }
+}
+
+int
+first_word_len(test_line)
+struct text *test_line;
+{
+ int counter;
+ unsigned char *pnt;
+
+ if (test_line == NULL)
+ return(0);
+
+ pnt = test_line->line;
+ if ((pnt == NULL) || (*pnt == '\0') ||
+ (*pnt == '.') || (*pnt == '>'))
+ return(0);
+
+ if ((*pnt == ' ') || (*pnt == '\t'))
+ {
+ pnt = next_word(pnt);
+ }
+
+ if (*pnt == '\0')
+ return(0);
+
+ counter = 0;
+ while ((*pnt != '\0') && ((*pnt != ' ') && (*pnt != '\t')))
+ {
+ pnt++;
+ counter++;
+ }
+ while ((*pnt != '\0') && ((*pnt == ' ') || (*pnt == '\t')))
+ {
+ pnt++;
+ counter++;
+ }
+ return(counter);
+}
+
+void
+Auto_Format() /* format the paragraph according to set margins */
+{
+ int string_count;
+ int offset;
+ int temp_case;
+ int word_len;
+ int temp_dwl;
+ int tmp_d_line_length;
+ int leave_loop = FALSE;
+ int status;
+ int counter;
+ char not_blank;
+ unsigned char *line;
+ unsigned char *tmp_srchstr;
+ unsigned char *temp1, *temp2;
+ unsigned char *temp_dword;
+ unsigned char temp_d_char[3];
+ unsigned char *tmp_d_line;
+
+
+ temp_d_char[0] = d_char[0];
+ temp_d_char[1] = d_char[1];
+ temp_d_char[2] = d_char[2];
+
+/*
+ | if observ_margins is not set, or the current line is blank,
+ | do not format the current paragraph
+ */
+
+ if ((!observ_margins) || (Blank_Line(curr_line)))
+ return;
+
+/*
+ | get current position in paragraph, so after formatting, the cursor
+ | will be in the same relative position
+ */
+
+ tmp_d_line = d_line;
+ tmp_d_line_length = dlt_line->line_length;
+ d_line = NULL;
+ auto_format = FALSE;
+ offset = position;
+ if ((position != 1) && ((*point == ' ') || (*point == '\t') || (position == curr_line->line_length) || (*point == '\0')))
+ prev_word();
+ temp_dword = d_word;
+ temp_dwl = d_wrd_len;
+ d_wrd_len = 0;
+ d_word = NULL;
+ temp_case = case_sen;
+ case_sen = TRUE;
+ tmp_srchstr = srch_str;
+ temp2 = srch_str = (unsigned char *) malloc(1 + curr_line->line_length - position);
+ if ((*point == ' ') || (*point == '\t'))
+ adv_word();
+ offset -= position;
+ counter = position;
+ line = temp1 = point;
+ while ((*temp1 != '\0') && (*temp1 != ' ') && (*temp1 != '\t') && (counter < curr_line->line_length))
+ {
+ *temp2 = *temp1;
+ temp2++;
+ temp1++;
+ counter++;
+ }
+ *temp2 = '\0';
+ if (position != 1)
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+ string_count = 0;
+ status = TRUE;
+ while ((line != point) && (status))
+ {
+ status = search(FALSE);
+ string_count++;
+ }
+
+/*
+ | now get back to the start of the paragraph to start checking
+ */
+
+ if (position != 1)
+ bol();
+ while (!Blank_Line(curr_line->prev_line))
+ bol();
+
+/*
+ | Start going through lines, putting spaces at end of lines if they do
+ | not already exist. Check line length, and move words to the next line
+ | if they cross the margin. Then get words from the next line if they
+ | will fit in before the margin.
+ */
+
+ counter = 0;
+
+ while (!leave_loop)
+ {
+ if (position != curr_line->line_length)
+ eol();
+ left(TRUE);
+ if (*point != ' ')
+ {
+ right(TRUE);
+ insert(' ');
+ }
+ else
+ right(TRUE);
+
+ not_blank = FALSE;
+
+ /*
+ | fill line if first word on next line will fit
+ | in the line without crossing the margin
+ */
+
+ while ((curr_line->next_line != NULL) &&
+ ((word_len = first_word_len(curr_line->next_line)) > 0)
+ && ((scr_pos + word_len) < right_margin))
+ {
+ adv_line();
+ if ((*point == ' ') || (*point == '\t'))
+ adv_word();
+ del_word();
+ if (position != 1)
+ bol();
+
+ /*
+ | We know this line was not blank before, so
+ | make sure that it doesn't have one of the
+ | leading characters that indicate the line
+ | should not be modified.
+ |
+ | We also know that this character should not
+ | be left as the first character of this line.
+ */
+
+ if ((Blank_Line(curr_line)) &&
+ (curr_line->line[0] != '.') &&
+ (curr_line->line[0] != '>'))
+ {
+ del_line();
+ not_blank = FALSE;
+ }
+ else
+ not_blank = TRUE;
+
+ /*
+ | go to end of previous line
+ */
+ left(TRUE);
+ undel_word();
+ eol();
+ /*
+ | make sure there's a space at the end of the line
+ */
+ left(TRUE);
+ if (*point != ' ')
+ {
+ right(TRUE);
+ insert(' ');
+ }
+ else
+ right(TRUE);
+ }
+
+ /*
+ | make sure line does not cross right margin
+ */
+
+ while (right_margin <= scr_pos)
+ {
+ prev_word();
+ if (position != 1)
+ {
+ del_word();
+ if (Blank_Line(curr_line->next_line))
+ insert_line(TRUE);
+ else
+ adv_line();
+ if ((*point == ' ') || (*point == '\t'))
+ adv_word();
+ undel_word();
+ not_blank = TRUE;
+ if (position != 1)
+ bol();
+ left(TRUE);
+ }
+ }
+
+ if ((!Blank_Line(curr_line->next_line)) || (not_blank))
+ {
+ adv_line();
+ counter++;
+ }
+ else
+ leave_loop = TRUE;
+ }
+
+/*
+ | go back to begin of paragraph, put cursor back to original position
+ */
+
+ if (position != 1)
+ bol();
+ while ((counter-- > 0) || (!Blank_Line(curr_line->prev_line)))
+ bol();
+
+/*
+ | find word cursor was in
+ */
+
+ status = TRUE;
+ while ((status) && (string_count > 0))
+ {
+ status = search(FALSE);
+ string_count--;
+ }
+
+/*
+ | offset the cursor to where it was before from the start of the word
+ */
+
+ while (offset > 0)
+ {
+ offset--;
+ right(TRUE);
+ }
+
+ if ((string_count > 0) && (offset < 0))
+ {
+ while (offset < 0)
+ {
+ offset++;
+ left(TRUE);
+ }
+ }
+
+/*
+ | reset flags and strings to what they were before formatting
+ */
+
+ if (d_word != NULL)
+ free(d_word);
+ d_word = temp_dword;
+ d_wrd_len = temp_dwl;
+ case_sen = temp_case;
+ free(srch_str);
+ srch_str = tmp_srchstr;
+ d_char[0] = temp_d_char[0];
+ d_char[1] = temp_d_char[1];
+ d_char[2] = temp_d_char[2];
+ auto_format = TRUE;
+ dlt_line->line_length = tmp_d_line_length;
+ d_line = tmp_d_line;
+
+ formatted = TRUE;
+ midscreen(scr_vert, point);
+}
+
+void
+modes_op()
+{
+ int ret_value;
+ int counter;
+ char *string;
+
+ do
+ {
+ sprintf(modes_menu[1].item_string, "%s %s", mode_strings[1],
+ (expand_tabs ? ON : OFF));
+ sprintf(modes_menu[2].item_string, "%s %s", mode_strings[2],
+ (case_sen ? ON : OFF));
+ sprintf(modes_menu[3].item_string, "%s %s", mode_strings[3],
+ (observ_margins ? ON : OFF));
+ sprintf(modes_menu[4].item_string, "%s %s", mode_strings[4],
+ (auto_format ? ON : OFF));
+ sprintf(modes_menu[5].item_string, "%s %s", mode_strings[5],
+ (eightbit ? ON : OFF));
+ sprintf(modes_menu[6].item_string, "%s %s", mode_strings[6],
+ (info_window ? ON : OFF));
+ sprintf(modes_menu[7].item_string, "%s %s", mode_strings[7],
+ (emacs_keys_mode ? ON : OFF));
+ sprintf(modes_menu[8].item_string, "%s %d", mode_strings[8],
+ right_margin);
+ sprintf(modes_menu[9].item_string, "%s %s", mode_strings[9],
+ (ee_chinese ? ON : OFF));
+
+ ret_value = menu_op(modes_menu);
+
+ switch (ret_value)
+ {
+ case 1:
+ expand_tabs = !expand_tabs;
+ break;
+ case 2:
+ case_sen = !case_sen;
+ break;
+ case 3:
+ observ_margins = !observ_margins;
+ break;
+ case 4:
+ auto_format = !auto_format;
+ if (auto_format)
+ observ_margins = TRUE;
+ break;
+ case 5:
+ eightbit = !eightbit;
+ if (!eightbit)
+ ee_chinese = FALSE;
+#ifdef NCURSE
+ if (ee_chinese)
+ nc_setattrib(A_NC_BIG5);
+ else
+ nc_clearattrib(A_NC_BIG5);
+#endif /* NCURSE */
+
+ redraw();
+ wnoutrefresh(text_win);
+ break;
+ case 6:
+ if (info_window)
+ no_info_window();
+ else
+ create_info_window();
+ break;
+ case 7:
+ emacs_keys_mode = !emacs_keys_mode;
+ if (info_window)
+ paint_info_win();
+ break;
+ case 8:
+ string = get_string(margin_prompt, TRUE);
+ if (string != NULL)
+ {
+ counter = atoi(string);
+ if (counter > 0)
+ right_margin = counter;
+ free(string);
+ }
+ break;
+ case 9:
+ ee_chinese = !ee_chinese;
+ if (ee_chinese != FALSE)
+ eightbit = TRUE;
+#ifdef NCURSE
+ if (ee_chinese)
+ nc_setattrib(A_NC_BIG5);
+ else
+ nc_clearattrib(A_NC_BIG5);
+#endif /* NCURSE */
+ redraw();
+ break;
+ default:
+ break;
+ }
+ }
+ while (ret_value != 0);
+}
+
+char *
+is_in_string(string, substring) /* a strchr() look-alike for systems without
+ strchr() */
+char * string, *substring;
+{
+ char *full, *sub;
+
+ for (sub = substring; (sub != NULL) && (*sub != '\0'); sub++)
+ {
+ for (full = string; (full != NULL) && (*full != '\0');
+ full++)
+ {
+ if (*sub == *full)
+ return(full);
+ }
+ }
+ return(NULL);
+}
+
+/*
+ | handle names of the form "~/file", "~user/file",
+ | "$HOME/foo", "~/$FOO", etc.
+ */
+
+char *
+resolve_name(name)
+char *name;
+{
+ char long_buffer[1024];
+ char short_buffer[128];
+ char *buffer;
+ char *slash;
+ char *tmp;
+ char *start_of_var;
+ int offset;
+ int index;
+ int counter;
+ struct passwd *user;
+
+ if (name[0] == '~')
+ {
+ if (name[1] == '/')
+ {
+ index = getuid();
+ user = (struct passwd *) getpwuid(index);
+ slash = name + 1;
+ }
+ else
+ {
+ slash = strchr(name, '/');
+ if (slash == NULL)
+ return(name);
+ *slash = '\0';
+ user = (struct passwd *) getpwnam((name + 1));
+ *slash = '/';
+ }
+ if (user == NULL)
+ {
+ return(name);
+ }
+ buffer = malloc(strlen(user->pw_dir) + strlen(slash) + 1);
+ strcpy(buffer, user->pw_dir);
+ strcat(buffer, slash);
+ }
+ else
+ buffer = name;
+
+ if (is_in_string(buffer, "$"))
+ {
+ tmp = buffer;
+ index = 0;
+
+ while ((*tmp != '\0') && (index < 1024))
+ {
+
+ while ((*tmp != '\0') && (*tmp != '$') &&
+ (index < 1024))
+ {
+ long_buffer[index] = *tmp;
+ tmp++;
+ index++;
+ }
+
+ if ((*tmp == '$') && (index < 1024))
+ {
+ counter = 0;
+ start_of_var = tmp;
+ tmp++;
+ if (*tmp == '{') /* } */ /* bracketed variable name */
+ {
+ tmp++; /* { */
+ while ((*tmp != '\0') &&
+ (*tmp != '}') &&
+ (counter < 128))
+ {
+ short_buffer[counter] = *tmp;
+ counter++;
+ tmp++;
+ } /* { */
+ if (*tmp == '}')
+ tmp++;
+ }
+ else
+ {
+ while ((*tmp != '\0') &&
+ (*tmp != '/') &&
+ (*tmp != '$') &&
+ (counter < 128))
+ {
+ short_buffer[counter] = *tmp;
+ counter++;
+ tmp++;
+ }
+ }
+ short_buffer[counter] = '\0';
+ if ((slash = getenv(short_buffer)) != NULL)
+ {
+ offset = strlen(slash);
+ if ((offset + index) < 1024)
+ strcpy(&long_buffer[index], slash);
+ index += offset;
+ }
+ else
+ {
+ while ((start_of_var != tmp) && (index < 1024))
+ {
+ long_buffer[index] = *start_of_var;
+ start_of_var++;
+ index++;
+ }
+ }
+ }
+ }
+
+ if (index == 1024)
+ return(buffer);
+ else
+ long_buffer[index] = '\0';
+
+ if (name != buffer)
+ free(buffer);
+ buffer = malloc(index + 1);
+ strcpy(buffer, long_buffer);
+ }
+
+ return(buffer);
+}
+
+int
+restrict_mode()
+{
+ if (!restricted)
+ return(FALSE);
+
+ wmove(com_win, 0, 0);
+ wprintw(com_win, restricted_msg);
+ wclrtoeol(com_win);
+ wrefresh(com_win);
+ clear_com_win = TRUE;
+ return(TRUE);
+}
+
+/*
+ | The following routine tests the input string against the list of
+ | strings, to determine if the string is a unique match with one of the
+ | valid values.
+ */
+
+int
+unique_test(string, list)
+char *string;
+char *list[];
+{
+ int counter;
+ int num_match;
+ int result;
+
+ num_match = 0;
+ counter = 0;
+ while (list[counter] != NULL)
+ {
+ result = compare(string, list[counter], FALSE);
+ if (result)
+ num_match++;
+ counter++;
+ }
+ return(num_match);
+}
+
+#ifndef NO_CATGETS
+/*
+ | Get the catalog entry, and if it got it from the catalog,
+ | make a copy, since the buffer will be overwritten by the
+ | next call to catgets().
+ */
+
+char *
+catgetlocal(number, string)
+int number;
+char *string;
+{
+ char *temp1;
+ char *temp2;
+
+ temp1 = catgets(catalog, 1, number, string);
+ if (temp1 != string)
+ {
+ temp2 = malloc(strlen(temp1) + 1);
+ strcpy(temp2, temp1);
+ temp1 = temp2;
+ }
+ return(temp1);
+}
+#endif /* NO_CATGETS */
+
+/*
+ | The following is to allow for using message catalogs which allow
+ | the software to be 'localized', that is, to use different languages
+ | all with the same binary. For more information, see your system
+ | documentation, or the X/Open Internationalization Guide.
+ */
+
+void
+strings_init()
+{
+ int counter;
+
+ setlocale(LC_ALL, "");
+#ifndef NO_CATGETS
+ catalog = catopen("ee", NL_CAT_LOCALE);
+#endif /* NO_CATGETS */
+
+ modes_menu[0].item_string = catgetlocal( 1, "modes menu");
+ mode_strings[1] = catgetlocal( 2, "tabs to spaces ");
+ mode_strings[2] = catgetlocal( 3, "case sensitive search");
+ mode_strings[3] = catgetlocal( 4, "margins observed ");
+ mode_strings[4] = catgetlocal( 5, "auto-paragraph format");
+ mode_strings[5] = catgetlocal( 6, "eightbit characters ");
+ mode_strings[6] = catgetlocal( 7, "info window ");
+ mode_strings[8] = catgetlocal( 8, "right margin ");
+ leave_menu[0].item_string = catgetlocal( 9, "leave menu");
+ leave_menu[1].item_string = catgetlocal( 10, "save changes");
+ leave_menu[2].item_string = catgetlocal( 11, "no save");
+ file_menu[0].item_string = catgetlocal( 12, "file menu");
+ file_menu[1].item_string = catgetlocal( 13, "read a file");
+ file_menu[2].item_string = catgetlocal( 14, "write a file");
+ file_menu[3].item_string = catgetlocal( 15, "save file");
+ file_menu[4].item_string = catgetlocal( 16, "print editor contents");
+ search_menu[0].item_string = catgetlocal( 17, "search menu");
+ search_menu[1].item_string = catgetlocal( 18, "search for ...");
+ search_menu[2].item_string = catgetlocal( 19, "search");
+ spell_menu[0].item_string = catgetlocal( 20, "spell menu");
+ spell_menu[1].item_string = catgetlocal( 21, "use 'spell'");
+ spell_menu[2].item_string = catgetlocal( 22, "use 'ispell'");
+ misc_menu[0].item_string = catgetlocal( 23, "miscellaneous menu");
+ misc_menu[1].item_string = catgetlocal( 24, "format paragraph");
+ misc_menu[2].item_string = catgetlocal( 25, "shell command");
+ misc_menu[3].item_string = catgetlocal( 26, "check spelling");
+ main_menu[0].item_string = catgetlocal( 27, "main menu");
+ main_menu[1].item_string = catgetlocal( 28, "leave editor");
+ main_menu[2].item_string = catgetlocal( 29, "help");
+ main_menu[3].item_string = catgetlocal( 30, "file operations");
+ main_menu[4].item_string = catgetlocal( 31, "redraw screen");
+ main_menu[5].item_string = catgetlocal( 32, "settings");
+ main_menu[6].item_string = catgetlocal( 33, "search");
+ main_menu[7].item_string = catgetlocal( 34, "miscellaneous");
+ help_text[0] = catgetlocal( 35, "Control keys: ");
+ help_text[1] = catgetlocal( 36, "^a ascii code ^i tab ^r right ");
+ help_text[2] = catgetlocal( 37, "^b bottom of text ^j newline ^t top of text ");
+ help_text[3] = catgetlocal( 38, "^c command ^k delete char ^u up ");
+ help_text[4] = catgetlocal( 39, "^d down ^l left ^v undelete word ");
+ help_text[5] = catgetlocal( 40, "^e search prompt ^m newline ^w delete word ");
+ help_text[6] = catgetlocal( 41, "^f undelete char ^n next page ^x search ");
+ help_text[7] = catgetlocal( 42, "^g begin of line ^o end of line ^y delete line ");
+ help_text[8] = catgetlocal( 43, "^h backspace ^p prev page ^z undelete line ");
+ help_text[9] = catgetlocal( 44, "^[ (escape) menu ESC-Enter: exit ee ");
+ help_text[10] = catgetlocal( 45, " ");
+ help_text[11] = catgetlocal( 46, "Commands: ");
+ help_text[12] = catgetlocal( 47, "help : get this info file : print file name ");
+ help_text[13] = catgetlocal( 48, "read : read a file char : ascii code of char ");
+ help_text[14] = catgetlocal( 49, "write : write a file case : case sensitive search ");
+ help_text[15] = catgetlocal( 50, "exit : leave and save nocase : case insensitive search ");
+ help_text[16] = catgetlocal( 51, "quit : leave, no save !cmd : execute \"cmd\" in shell ");
+ help_text[17] = catgetlocal( 52, "line : display line # 0-9 : go to line \"#\" ");
+ help_text[18] = catgetlocal( 53, "expand : expand tabs noexpand: do not expand tabs ");
+ help_text[19] = catgetlocal( 54, " ");
+ help_text[20] = catgetlocal( 55, " ee [+#] [-i] [-e] [-h] [file(s)] ");
+ help_text[21] = catgetlocal( 56, "+# :go to line # -i :no info window -e : don't expand tabs -h :no highlight");
+ control_keys[0] = catgetlocal( 57, "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page ");
+ control_keys[1] = catgetlocal( 58, "^a ascii code ^x search ^z undelete line ^d down ^n next page ");
+ control_keys[2] = catgetlocal( 59, "^b bottom of text ^g begin of line ^w delete word ^l left ");
+ control_keys[3] = catgetlocal( 60, "^t top of text ^o end of line ^v undelete word ^r right ");
+ control_keys[4] = catgetlocal( 61, "^c command ^k delete char ^f undelete char ESC-Enter: exit ee ");
+ command_strings[0] = catgetlocal( 62, "help : get help info |file : print file name |line : print line # ");
+ command_strings[1] = catgetlocal( 63, "read : read a file |char : ascii code of char |0-9 : go to line \"#\"");
+ command_strings[2] = catgetlocal( 64, "write: write a file |case : case sensitive search |exit : leave and save ");
+ command_strings[3] = catgetlocal( 65, "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save");
+ command_strings[4] = catgetlocal( 66, "expand: expand tabs |noexpand: do not expand tabs ");
+ com_win_message = catgetlocal( 67, " press Escape (^[) for menu");
+ no_file_string = catgetlocal( 68, "no file");
+ ascii_code_str = catgetlocal( 69, "ascii code: ");
+ printer_msg_str = catgetlocal( 70, "sending contents of buffer to \"%s\" ");
+ command_str = catgetlocal( 71, "command: ");
+ file_write_prompt_str = catgetlocal( 72, "name of file to write: ");
+ file_read_prompt_str = catgetlocal( 73, "name of file to read: ");
+ char_str = catgetlocal( 74, "character = %d");
+ unkn_cmd_str = catgetlocal( 75, "unknown command \"%s\"");
+ non_unique_cmd_msg = catgetlocal( 76, "entered command is not unique");
+ line_num_str = catgetlocal( 77, "line %d ");
+ line_len_str = catgetlocal( 78, "length = %d");
+ current_file_str = catgetlocal( 79, "current file is \"%s\" ");
+ usage0 = catgetlocal( 80, "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n");
+ usage1 = catgetlocal( 81, " -i turn off info window\n");
+ usage2 = catgetlocal( 82, " -e do not convert tabs to spaces\n");
+ usage3 = catgetlocal( 83, " -h do not use highlighting\n");
+ file_is_dir_msg = catgetlocal( 84, "file \"%s\" is a directory");
+ new_file_msg = catgetlocal( 85, "new file \"%s\"");
+ cant_open_msg = catgetlocal( 86, "can't open \"%s\"");
+ open_file_msg = catgetlocal( 87, "file \"%s\", %d lines");
+ file_read_fin_msg = catgetlocal( 88, "finished reading file \"%s\"");
+ reading_file_msg = catgetlocal( 89, "reading file \"%s\"");
+ read_only_msg = catgetlocal( 90, ", read only");
+ file_read_lines_msg = catgetlocal( 91, "file \"%s\", %d lines");
+ save_file_name_prompt = catgetlocal( 92, "enter name of file: ");
+ file_not_saved_msg = catgetlocal( 93, "no filename entered: file not saved");
+ changes_made_prompt = catgetlocal( 94, "changes have been made, are you sure? (y/n [n]) ");
+ yes_char = catgetlocal( 95, "y");
+ file_exists_prompt = catgetlocal( 96, "file already exists, overwrite? (y/n) [n] ");
+ create_file_fail_msg = catgetlocal( 97, "unable to create file \"%s\"");
+ writing_file_msg = catgetlocal( 98, "writing file \"%s\"");
+ file_written_msg = catgetlocal( 99, "\"%s\" %d lines, %d characters");
+ searching_msg = catgetlocal( 100, " ...searching");
+ str_not_found_msg = catgetlocal( 101, "string \"%s\" not found");
+ search_prompt_str = catgetlocal( 102, "search for: ");
+ exec_err_msg = catgetlocal( 103, "could not exec %s\n");
+ continue_msg = catgetlocal( 104, "press return to continue ");
+ menu_cancel_msg = catgetlocal( 105, "press Esc to cancel");
+ menu_size_err_msg = catgetlocal( 106, "menu too large for window");
+ press_any_key_msg = catgetlocal( 107, "press any key to continue ");
+ shell_prompt = catgetlocal( 108, "shell command: ");
+ formatting_msg = catgetlocal( 109, "...formatting paragraph...");
+ shell_echo_msg = catgetlocal( 110, "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-");
+ spell_in_prog_msg = catgetlocal( 111, "sending contents of edit buffer to 'spell'");
+ margin_prompt = catgetlocal( 112, "right margin is: ");
+ restricted_msg = catgetlocal( 113, "restricted mode: unable to perform requested operation");
+ ON = catgetlocal( 114, "ON");
+ OFF = catgetlocal( 115, "OFF");
+ HELP = catgetlocal( 116, "HELP");
+ WRITE = catgetlocal( 117, "WRITE");
+ READ = catgetlocal( 118, "READ");
+ LINE = catgetlocal( 119, "LINE");
+ FILE_str = catgetlocal( 120, "FILE");
+ CHARACTER = catgetlocal( 121, "CHARACTER");
+ REDRAW = catgetlocal( 122, "REDRAW");
+ RESEQUENCE = catgetlocal( 123, "RESEQUENCE");
+ AUTHOR = catgetlocal( 124, "AUTHOR");
+ VERSION = catgetlocal( 125, "VERSION");
+ CASE = catgetlocal( 126, "CASE");
+ NOCASE = catgetlocal( 127, "NOCASE");
+ EXPAND = catgetlocal( 128, "EXPAND");
+ NOEXPAND = catgetlocal( 129, "NOEXPAND");
+ Exit_string = catgetlocal( 130, "EXIT");
+ QUIT_string = catgetlocal( 131, "QUIT");
+ INFO = catgetlocal( 132, "INFO");
+ NOINFO = catgetlocal( 133, "NOINFO");
+ MARGINS = catgetlocal( 134, "MARGINS");
+ NOMARGINS = catgetlocal( 135, "NOMARGINS");
+ AUTOFORMAT = catgetlocal( 136, "AUTOFORMAT");
+ NOAUTOFORMAT = catgetlocal( 137, "NOAUTOFORMAT");
+ Echo = catgetlocal( 138, "ECHO");
+ PRINTCOMMAND = catgetlocal( 139, "PRINTCOMMAND");
+ RIGHTMARGIN = catgetlocal( 140, "RIGHTMARGIN");
+ HIGHLIGHT = catgetlocal( 141, "HIGHLIGHT");
+ NOHIGHLIGHT = catgetlocal( 142, "NOHIGHLIGHT");
+ EIGHTBIT = catgetlocal( 143, "EIGHTBIT");
+ NOEIGHTBIT = catgetlocal( 144, "NOEIGHTBIT");
+ /*
+ | additions
+ */
+ mode_strings[7] = catgetlocal( 145, "emacs key bindings ");
+ emacs_help_text[0] = help_text[0];
+ emacs_help_text[1] = catgetlocal( 146, "^a beginning of line ^i tab ^r restore word ");
+ emacs_help_text[2] = catgetlocal( 147, "^b back 1 char ^j undel char ^t top of text ");
+ emacs_help_text[3] = catgetlocal( 148, "^c command ^k delete line ^u bottom of text ");
+ emacs_help_text[4] = catgetlocal( 149, "^d delete char ^l undelete line ^v next page ");
+ emacs_help_text[5] = catgetlocal( 150, "^e end of line ^m newline ^w delete word ");
+ emacs_help_text[6] = catgetlocal( 151, "^f forward 1 char ^n next line ^x search ");
+ emacs_help_text[7] = catgetlocal( 152, "^g go back 1 page ^o ascii char insert ^y search prompt ");
+ emacs_help_text[8] = catgetlocal( 153, "^h backspace ^p prev line ^z next word ");
+ emacs_help_text[9] = help_text[9];
+ emacs_help_text[10] = help_text[10];
+ emacs_help_text[11] = help_text[11];
+ emacs_help_text[12] = help_text[12];
+ emacs_help_text[13] = help_text[13];
+ emacs_help_text[14] = help_text[14];
+ emacs_help_text[15] = help_text[15];
+ emacs_help_text[16] = help_text[16];
+ emacs_help_text[17] = help_text[17];
+ emacs_help_text[18] = help_text[18];
+ emacs_help_text[19] = help_text[19];
+ emacs_help_text[20] = help_text[20];
+ emacs_help_text[21] = help_text[21];
+ emacs_control_keys[0] = catgetlocal( 154, "^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page");
+ emacs_control_keys[1] = catgetlocal( 155, "^o ascii code ^x search ^l undelete line ^n next li ^v next page");
+ emacs_control_keys[2] = catgetlocal( 156, "^u end of file ^a begin of line ^w delete word ^b back 1 char ^z next word");
+ emacs_control_keys[3] = catgetlocal( 157, "^t top of text ^e end of line ^r restore word ^f forward char ");
+ emacs_control_keys[4] = catgetlocal( 158, "^c command ^d delete char ^j undelete char ESC-Enter: exit");
+ EMACS_string = catgetlocal( 159, "EMACS");
+ NOEMACS_string = catgetlocal( 160, "NOEMACS");
+ usage4 = catgetlocal( 161, " +# put cursor at line #\n");
+ conf_dump_err_msg = catgetlocal( 162, "unable to open .init.ee for writing, no configuration saved!");
+ conf_dump_success_msg = catgetlocal( 163, "ee configuration saved in file %s");
+ modes_menu[10].item_string = catgetlocal( 164, "save editor configuration");
+ config_dump_menu[0].item_string = catgetlocal( 165, "save ee configuration");
+ config_dump_menu[1].item_string = catgetlocal( 166, "save in current directory");
+ config_dump_menu[2].item_string = catgetlocal( 167, "save in home directory");
+ conf_not_saved_msg = catgetlocal( 168, "ee configuration not saved");
+ ree_no_file_msg = catgetlocal( 169, "must specify a file when invoking ree");
+ menu_too_lrg_msg = catgetlocal( 180, "menu too large for window");
+ more_above_str = catgetlocal( 181, "^^more^^");
+ more_below_str = catgetlocal( 182, "VVmoreVV");
+ mode_strings[9] = catgetlocal( 183, "16 bit characters ");
+ chinese_cmd = catgetlocal( 184, "16BIT");
+ nochinese_cmd = catgetlocal( 185, "NO16BIT");
+
+ commands[0] = HELP;
+ commands[1] = WRITE;
+ commands[2] = READ;
+ commands[3] = LINE;
+ commands[4] = FILE_str;
+ commands[5] = REDRAW;
+ commands[6] = RESEQUENCE;
+ commands[7] = AUTHOR;
+ commands[8] = VERSION;
+ commands[9] = CASE;
+ commands[10] = NOCASE;
+ commands[11] = EXPAND;
+ commands[12] = NOEXPAND;
+ commands[13] = Exit_string;
+ commands[14] = QUIT_string;
+ commands[15] = "<";
+ commands[16] = ">";
+ commands[17] = "!";
+ commands[18] = "0";
+ commands[19] = "1";
+ commands[20] = "2";
+ commands[21] = "3";
+ commands[22] = "4";
+ commands[23] = "5";
+ commands[24] = "6";
+ commands[25] = "7";
+ commands[26] = "8";
+ commands[27] = "9";
+ commands[28] = CHARACTER;
+ commands[29] = chinese_cmd;
+ commands[30] = nochinese_cmd;
+ commands[31] = NULL;
+ init_strings[0] = CASE;
+ init_strings[1] = NOCASE;
+ init_strings[2] = EXPAND;
+ init_strings[3] = NOEXPAND;
+ init_strings[4] = INFO;
+ init_strings[5] = NOINFO;
+ init_strings[6] = MARGINS;
+ init_strings[7] = NOMARGINS;
+ init_strings[8] = AUTOFORMAT;
+ init_strings[9] = NOAUTOFORMAT;
+ init_strings[10] = Echo;
+ init_strings[11] = PRINTCOMMAND;
+ init_strings[12] = RIGHTMARGIN;
+ init_strings[13] = HIGHLIGHT;
+ init_strings[14] = NOHIGHLIGHT;
+ init_strings[15] = EIGHTBIT;
+ init_strings[16] = NOEIGHTBIT;
+ init_strings[17] = EMACS_string;
+ init_strings[18] = NOEMACS_string;
+ init_strings[19] = chinese_cmd;
+ init_strings[20] = nochinese_cmd;
+ init_strings[21] = NULL;
+
+ /*
+ | allocate space for strings here for settings menu
+ */
+
+ for (counter = 1; counter < NUM_MODES_ITEMS; counter++)
+ {
+ modes_menu[counter].item_string = malloc(80);
+ }
+
+#ifndef NO_CATGETS
+ catclose(catalog);
+#endif /* NO_CATGETS */
+}
+
diff --git a/text_cmds/ee/ee.i18n.guide b/text_cmds/ee/ee.i18n.guide
new file mode 100644
index 0000000..eef836a
--- /dev/null
+++ b/text_cmds/ee/ee.i18n.guide
@@ -0,0 +1,158 @@
+Easy Editor ("ee") provides the ability to translate the messages
+displayed to the user and the commands entered. This is done via message
+catalogs, following X/Open standards. ee supports eight bit characters,
+as well as 16-bit characters. The Chinese Big 5 code set is the 16-bit
+code set that ee was modified to handle, as it is relatively easy to
+support since two byte characters also take up two columns on the screen,
+thereby simplifying the screen position calculations. Other multibyte
+code sets may function, but have not been tested.
+
+(The name ee.i18n.guide is for "ee internationalization guide". The i18n
+abbreviation is used because there are 18 characters between the first
+letter ("i") and last ("n") of "internationalization".)
+
+All of the messages, warnings, information, and commands, are contained
+in the message catalog. Each numbered entry represents an individual
+string used by ee. Some strings contain formatting information for
+formatted print statements, which are of the form "%s", or "%d", these
+must be preserved in the translation, or the correct information will not
+be displayed. For those strings containing multiple formatting codes,
+the order of each item must be preserved as well.
+
+Message content
+1 title for modes, or settings menu
+2 - 8 entries for modes menu, each line should be the same length
+ (padded with spaces)
+9 - 34 other menu titles and entries
+35 - 56 help screen
+57 - 61 actions assigned to control keys
+62 - 66 commands information
+67 message displayed when info window turned off
+68 indication that no file name was entered when invoking ee
+69 prompt for decimal value of character to be entered
+70 message displaying the print command being invoked
+71 prompt for command
+72 prompt for name of file to be written
+73 prompt for name of file to be read
+74 string used to display the decimal value of the character
+ the cursor is on
+75 string displaying an unrecognized command
+76 string indicating that the command entered is not a unique
+ substring of a valid command
+77 string indicating the current line number
+78 string for displaying the length of the line
+79 string for displaying the name of the file
+80 - 83 strings showing how to invoke ee, and its options
+84 message indicating that the file entered is a directory, not a
+ text file
+85 message informing that the entered file does not yet exist
+86 message informing that the file can't be opened (because of
+ permission problems)
+87 message after file has been read with the file name and number
+ of lines read
+88 message indicating that the file has been read
+89 message indicating that the file is being read
+90 message indicating that permissions only allow the file to be
+ read, not written
+91 message after file has been read with the file name and number
+ of lines read
+92 prompt for name of file to be saved (used when no name was
+ entered for a file to edit)
+93 message indicating that the file was not written, since no
+ name was entered at the prompt
+94 prompt asking user if changes should not be saved ("yes_char"
+ will be expected for affirmative response)
+95 "yes" character, single character expected to confirm action
+ (can be upper or lower case, will be converted to upper-case
+ during test)
+96 prompt
+97 error message
+98 message indicating that the named file is being written
+99 message indicating the name of the file written, the number of
+ lines, and the number of characters (order of items must be
+ maintained)
+100 search in progress message
+101 message that the string was not found
+102 prompt for search
+103 message that string could not be executed
+104 self-explanatory
+105 message for menus, indicating that the Escape character will
+ allow the user to exit the menu
+106 error message indicating the menu won't fit on the screen
+107 self-explanatory
+108 prompt for shell command
+109 message displayed while formatting a paragraph
+110 string which places message for spell checking at top of
+ buffer (the portions 'list of unrecognized words' and
+ '-=-=-=-=-=-' may be replaced, but the rest must remain the
+ same)
+111 message informing that spell checking is in progress
+112 prompt for right margin
+113 error informing user that operation is not permitted in ree
+114 string indicating mode is turned 'on' in modes menu
+115 string indicating mode is turned 'off' in modes menu
+116 - 131 strings used for commands (some also used for initialization)
+132 - 144 strings used for initialization
+145 entry for settings menu for emacs key bindings settings
+146 - 153 help screen entries for emacs key bindings info
+154 - 158 info window entries for emacs key bindings info
+159 string for turning on emacs key bindings in the init file
+160 string for turning off emacs key bindings in the init file
+161 fifth line of usage statement
+162 error message when unable to save configuration file
+163 positive feedback about saving the configuration file
+164 - 167 menu items for saving editor configuration
+168 error message when unable to save configuration file
+169 error message for ree when not specifying the file
+180 self-explanatory
+181 - 182 indicators of more information in menu (for when scrolling
+ menus because menu contents won't fit vertically on screen)
+183 menu entry for modes menu for 16 bit characters
+184 - 185 strings for initialization to turn on or off 16 bit
+ character handling
+
+Care should be taken when translating commands and initialization keywords
+because the algorithm used for detecting uniqueness of entered commands
+will not be able to distinguish words that are not unique before the end
+of the shorter word, for example, it would not be able to distinguish the
+command 'abcd' from 'abcde'.
+
+After translating the messages, use the 'gencat' command to create the compiled
+catalog used when running the software. The standard syntax would be:
+
+ gencat ee.cat ee.msg
+
+Where ee.msg is the file containing the translations, and ee.cat is the
+compiled catalog. If the file ee.cat does not exist, it will be created.
+Check the documentation for your system for proper syntax.
+
+Message catalog placement varies from system to system. A common location
+for message catalogs is in /usr/lib/nls. In this directory are
+directories with the names of other languages. The default language is
+'C'. There is also an environment variable, named NLSPATH used to
+determine where message catalogs can be found. This variable is similar
+to the PATH variable used for commands, but with some differences. The
+NLSPATH variable must have the ability to handle different names for
+languages and the catalog files, so it has field descriptors for these. A
+typical setting for NLSPATH could be:
+
+ NLSPATH=/usr/lib/nls/%L/%N.cat:/usr/local/lib/nls/%L/%N.cat
+
+Where "%L" is the field descriptor for the language (obtained from the
+LANG environment variable) and "%N" is the name of the file (with the
+".cat" appended by the path variable, it is not passed from the requesting
+program). The colon (:) is used to separate paths, so in the above
+example there are two paths possible for message catalogs. You may wish
+to maintain catalogs for applications that are not supported by your
+system vendor in a location unique for you, and this is facilitated by the
+NLSPATH variable. Remember to set and export both the LANG and NLSPATH
+variables for each user that expects to use localization either in a
+system-wide profile or in each user's profile. See your system
+documentation for more information.
+
+The message catalog supplied with ee also uses the '$quote' directive to
+specify a quote around strings to ensure proper padding. This directive
+may not be supported on all systems, and lead to quotes being included in
+the string used in ee, which will cause incorrect behavior. If the
+'$quote' directive is not supported by your system's gencat command, edit
+the msg file to remove the leading and trailing quotation marks.
diff --git a/text_cmds/ee/ee.msg b/text_cmds/ee/ee.msg
new file mode 100644
index 0000000..28fa542
--- /dev/null
+++ b/text_cmds/ee/ee.msg
@@ -0,0 +1,186 @@
+$ This file contains the messages for ee ("easy editor"). See the file
+$ ee.i18n.guide for more information
+$
+$ For ee patchlevel 3
+$
+$ $Header: /home/hugh/sources/old_ae/RCS/ee.msg,v 1.8 1996/11/30 03:23:40 hugh Exp $
+$ $FreeBSD$
+$
+$
+$set 1
+$quote "
+1 "modes menu"
+2 "tabs to spaces "
+3 "case sensitive search"
+4 "margins observed "
+5 "auto-paragraph format"
+6 "eightbit characters "
+7 "info window "
+8 "right margin "
+9 "leave menu"
+10 "save changes"
+11 "no save"
+12 "file menu"
+13 "read a file"
+14 "write a file"
+15 "save file"
+16 "print editor contents"
+17 "search menu"
+18 "search for ..."
+19 "search"
+20 "spell menu"
+21 "use 'spell'"
+22 "use 'ispell'"
+23 "miscellaneous menu"
+24 "format paragraph"
+25 "shell command"
+26 "check spelling"
+27 "main menu"
+28 "leave editor"
+29 "help"
+30 "file operations"
+31 "redraw screen"
+32 "settings"
+33 "search"
+34 "miscellaneous"
+35 "Control keys: "
+36 "^a ascii code ^i tab ^r right "
+37 "^b bottom of text ^j newline ^t top of text "
+38 "^c command ^k delete char ^u up "
+39 "^d down ^l left ^v undelete word "
+40 "^e search prompt ^m newline ^w delete word "
+41 "^f undelete char ^n next page ^x search "
+42 "^g begin of line ^o end of line ^y delete line "
+43 "^h backspace ^p prev page ^z undelete line "
+44 "^[ (escape) menu "
+45 " "
+46 "Commands: "
+47 "help : get this info file : print file name "
+48 "read : read a file char : ascii code of char "
+49 "write : write a file case : case sensitive search "
+50 "exit : leave and save nocase : case insensitive search "
+51 "quit : leave, no save !cmd : execute \"cmd\" in shell "
+52 "line : display line # 0-9 : go to line \"#\" "
+53 "expand : expand tabs noexpand: do not expand tabs "
+54 " "
+55 " ee [+#] [-i] [-e] [-h] [file(s)] "
+56 "+# :go to line # -i :no info window -e : don't expand tabs -h :no highlight"
+57 "^[ (escape) menu ^e search prompt ^y delete line ^u up ^p prev page "
+58 "^a ascii code ^x search ^z undelete line ^d down ^n next page "
+59 "^b bottom of text ^g begin of line ^w delete word ^l left "
+60 "^t top of text ^o end of line ^v undelete word ^r right "
+61 "^c command ^k delete char ^f undelete char "
+62 "help : get help info |file : print file name |line : print line # "
+63 "read : read a file |char : ascii code of char |0-9 : go to line \"#\""
+64 "write: write a file |case : case sensitive search |exit : leave and save "
+65 "!cmd : shell \"cmd\" |nocase: ignore case in search |quit : leave, no save"
+66 "expand: expand tabs |noexpand: do not expand tabs "
+67 " press Escape (^[) for menu"
+68 "no file"
+69 "ascii code: "
+70 "sending contents of buffer to \"%s\" "
+71 "command: "
+72 "name of file to write: "
+73 "name of file to read: "
+74 "character = %d"
+75 "unknown command \"%s\""
+76 "entered command is not unique"
+77 "line %d "
+78 "length = %d"
+79 "current file is \"%s\" "
+80 "usage: %s [-i] [-e] [-h] [+line_number] [file(s)]\n"
+81 " -i turn off info window\n"
+82 " -e do not convert tabs to spaces\n"
+83 " -h do not use highlighting\n"
+84 "file \"%s\" is a directory"
+85 "new file \"%s\""
+86 "can't open \"%s\""
+87 "file \"%s\", %d lines"
+88 "finished reading file \"%s\""
+89 "reading file \"%s\""
+90 ", read only"
+91 "file \"%s\", %d lines"
+92 "enter name of file: "
+93 "no filename entered: file not saved"
+94 "changes have been made, are you sure? (y/n [n]) "
+95 "y"
+96 "file already exists, overwrite? (y/n) [n] "
+97 "unable to create file \"%s\""
+98 "writing file \"%s\""
+99 "\"%s\" %d lines, %d characters"
+100 " ...searching"
+101 "string \"%s\" not found"
+102 "search for: "
+103 "could not exec %s\n"
+104 "press return to continue "
+105 "press Esc to cancel"
+106 "menu too large for window"
+107 "press any key to continue "
+108 "shell command: "
+109 "...formatting paragraph..."
+110 "<!echo 'list of unrecognized words'; echo -=-=-=-=-=-"
+111 "sending contents of edit buffer to 'spell'"
+112 "right margin is: "
+113 "restricted mode: unable to perform requested operation"
+114 "ON"
+115 "OFF"
+116 "HELP"
+117 "WRITE"
+118 "READ"
+119 "LINE"
+120 "FILE"
+121 "CHARACTER"
+122 "REDRAW"
+123 "RESEQUENCE"
+124 "AUTHOR"
+125 "VERSION"
+126 "CASE"
+127 "NOCASE"
+128 "EXPAND"
+129 "NOEXPAND"
+130 "EXIT"
+131 "QUIT"
+132 "INFO"
+133 "NOINFO"
+134 "MARGINS"
+135 "NOMARGINS"
+136 "AUTOFORMAT"
+137 "NOAUTOFORMAT"
+138 "ECHO"
+139 "PRINTCOMMAND"
+140 "RIGHTMARGIN"
+141 "HIGHLIGHT"
+142 "NOHIGHLIGHT"
+143 "EIGHTBIT"
+144 "NOEIGHTBIT"
+145 "emacs key bindings "
+146 "^a beginning of line ^i tab ^r restore word "
+147 "^b back 1 char ^j undel char ^t top of text "
+148 "^c command ^k delete line ^u bottom of text "
+149 "^d delete char ^l undelete line ^v next page "
+150 "^e end of line ^m newline ^w delete word "
+151 "^f forward 1 char ^n next line ^x search "
+152 "^g go back 1 page ^o ascii char insert ^y search prompt "
+153 "^h backspace ^p prev line ^z next word "
+154 "^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page"
+155 "^o ascii code ^x search ^l undelete line ^n next li ^v next page"
+156 "^u end of file ^a begin of line ^w delete word ^b back 1 char "
+157 "^t top of text ^e end of line ^r restore word ^f forward 1 char "
+158 "^c command ^d delete char ^j undelete char ^z next word "
+159 "EMACS"
+160 "NOEMACS"
+161 " +# put cursor at line #\n"
+162 "unable to open .init.ee for writing, no configuration saved!"
+163 "ee configuration saved in file %s"
+164 "save editor configuration"
+165 "save ee configuration"
+166 "save in current directory"
+167 "save in home directory"
+168 "ee configuration not saved"
+169 "must specify a file when invoking ree"
+180 "menu too large for window"
+181 "^^more^^"
+182 "VVmoreVV"
+183 "16 bit characters "
+184 "16BIT"
+185 "NO16BIT"
diff --git a/text_cmds/ee/ee_version.h b/text_cmds/ee/ee_version.h
new file mode 100644
index 0000000..c2db839
--- /dev/null
+++ b/text_cmds/ee/ee_version.h
@@ -0,0 +1,6 @@
+/*
+ | provide a version number for ee
+ */
+
+#define EE_VERSION "1.5.2"
+#define DATE_STRING "$Date: 2010/06/04 02:35:35 $"
diff --git a/text_cmds/ee/genstr b/text_cmds/ee/genstr
new file mode 100755
index 0000000..429f960
--- /dev/null
+++ b/text_cmds/ee/genstr
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+set -x
+
+if [ $# -lt 2 ]
+then
+ echo usage $0 source_file dest_file
+ exit 1
+fi
+
+trap 'rm -f /tmp/$$.out; exit 0' 0 # set up traps to clean up
+trap 'rm -f /tmp/$$.out; exit 1' 1 2 3 15 # on errors AND normal exit
+
+if [ -f $2 ]
+then
+ rm $2
+fi
+
+cat $1 | grep 'catgetlocal.*\"*\"' |
+ sed -e 's/^.*catgetlocal(//' |
+ sed -e 's/^[ ]*//' |
+ sed -e 's/, \"/ \"/' |
+ sed -e 's/);//' > /tmp/$$.out
+
+cat > $2 <<EOF
+\$
+\$
+\$set 1
+\$quote "
+EOF
+
+sort -n < /tmp/$$.out >> $2
diff --git a/text_cmds/ee/make.default b/text_cmds/ee/make.default
new file mode 100644
index 0000000..32ff05d
--- /dev/null
+++ b/text_cmds/ee/make.default
@@ -0,0 +1,57 @@
+# This is the make file for ee, the "easy editor".
+#
+# If building ee using curses, type "make curses", otherwise new_curse (a
+# subset of curses that supports ee) will be built and ee will use new_curse
+# instead of curses.
+#
+# The "install" target ("make install") will copy the ee binary to
+# the /usr/local/bin directory on the local system. The man page (ee.1)
+# will be copied into the /usr/local/man/man1 directory.
+#
+# The "clean" target ("make clean") will remove the ee and new_curse.o
+# object files, and the ee binary.
+#
+# If the system does not have localization routines, use the -DNO_CATGETS
+# define. If the system supports setlocale(), catopen(), and catgets() and
+# localization is desired, do not use -DNO_CATGETS.
+#
+# DEFINES is used for new_curse.c, and CFLAGS is used for ee.c.
+#
+
+# for System V, using new_curse with terminfo
+DEFINES = -DSYS5 -DNCURSE
+
+# for BSD, using new_curse with termcap
+#DEFINES = -DCAP -DNCURSE
+
+# for BSD systems with select(), using new_curse with termcap, use:
+#DEFINES = -DCAP -DNCURSE -DBSD_SELECT
+
+# flags for compilation
+CFLAGS = -s -DNO_CATGETS
+
+# For Sun systems, remove the '#' from the front of the next two lines:
+#DEFINES = -DSYS5 -DNCURSE
+#CFLAGS = -I/usr/5include -L/usr/5lib -DNO_CATGETS -s
+
+all : ee
+
+curses : ee.c
+ cc ee.c -o ee $(CFLAGS) -lcurses
+
+ee : ee.o new_curse.o
+ cc -o ee ee.o new_curse.o $(CFLAGS)
+
+ee.o : ee.c new_curse.h
+ cc -c ee.c $(DEFINES) $(CFLAGS)
+
+new_curse.o : new_curse.c new_curse.h
+ cc new_curse.c -c $(DEFINES) $(CFLAGS)
+
+install :
+ cp ee /usr/local/bin/ee
+ cp ee.1 /usr/local/man/man1/ee.1
+
+clean :
+ rm -f ee.o new_curse.o ee
+
diff --git a/text_cmds/ee/new_curse.c b/text_cmds/ee/new_curse.c
new file mode 100644
index 0000000..5ceec24
--- /dev/null
+++ b/text_cmds/ee/new_curse.c
@@ -0,0 +1,3819 @@
+/*
+ | new_curse.c
+ |
+ | A subset of curses developed for use with ae.
+ |
+ | written by Hugh Mahon
+ |
+ | Copyright (c) 1986, 1987, 1988, 1991, 1992, 1993, 1994, 1995, 2009 Hugh Mahon
+ | All rights reserved.
+ |
+ | Redistribution and use in source and binary forms, with or without
+ | modification, are permitted provided that the following conditions
+ | are met:
+ |
+ | * Redistributions of source code must retain the above copyright
+ | notice, this list of conditions and the following disclaimer.
+ | * Redistributions in binary form must reproduce the above
+ | copyright notice, this list of conditions and the following
+ | disclaimer in the documentation and/or other materials provided
+ | with the distribution.
+ |
+ | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ | POSSIBILITY OF SUCH DAMAGE.
+ |
+ |
+ | All are rights reserved.
+ |
+ | $Header: /home/hugh/sources/old_ae/RCS/new_curse.c,v 1.54 2002/09/21 00:47:14 hugh Exp $
+ |
+ */
+
+char *copyright_message[] = { "Copyright (c) 1986, 1987, 1988, 1991, 1992, 1993, 1994, 1995, 2009 Hugh Mahon",
+ "All rights are reserved."};
+
+char * new_curse_name= "@(#) new_curse.c $Revision: 1.54 $";
+
+#include "new_curse.h"
+#include <signal.h>
+#include <fcntl.h>
+
+#ifdef SYS5
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef BSD_SELECT
+#include <sys/types.h>
+#include <sys/time.h>
+
+#ifdef SLCT_HDR
+#include <sys/select.h> /* on AIX */
+#endif /* SLCT_HDR */
+
+#endif /* BSD_SELECT */
+
+#ifdef HAS_STDLIB
+#include <stdlib.h>
+#endif
+
+#if defined(__STDC__)
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#ifdef HAS_UNISTD
+#include <unistd.h>
+#endif
+
+#ifdef HAS_SYS_IOCTL
+#include <sys/ioctl.h>
+#endif
+
+
+WINDOW *curscr;
+static WINDOW *virtual_scr;
+WINDOW *stdscr;
+WINDOW *last_window_refreshed;
+
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+#endif
+
+#define min(a, b) (a < b ? a : b)
+#define highbitset(a) ((a) & 0x80)
+
+#ifndef CAP
+#define String_Out(table, stack, place) Info_Out(table, stack, place)
+#else
+#define String_Out(table, stack, place) Cap_Out(table, stack, place)
+#endif
+
+#define bw__ 0 /* booleans */
+#define am__ 1
+#define xb__ 2
+#define xs__ 3 /* hp glitch (standout not erased by overwrite) */
+#define xn__ 4
+#define eo__ 5
+#define gn__ 6 /* generic type terminal */
+#define hc__ 7 /* hardcopy terminal */
+#define km__ 8
+#define hs__ 9
+#define in__ 10
+#define da__ 11
+#define db__ 12
+#define mi__ 13 /* safe to move during insert mode */
+#define ms__ 14 /* safe to move during standout mode */
+#define os__ 15
+#define es__ 16
+#define xt__ 17
+#define hz__ 18 /* hazeltine glitch */
+#define ul__ 19
+#define xo__ 20
+#define chts__ 21
+#define nxon__ 22
+#define nrrmc__ 23
+#define npc__ 24
+#define mc5i__ 25
+
+#define co__ 0 /* number of columns */ /* numbers */
+#define it__ 1 /* spaces per tab */
+#define li__ 2 /* number of lines */
+#define lm__ 3
+#define sg__ 4 /* magic cookie glitch */
+#define pb__ 5
+#define vt__ 6
+#define ws__ 7
+
+#define cols__ 0
+#define lines__ 2
+#define xmc__ 4
+#define vt__ 6
+#define wsl__ 7
+#define nlab__ 8
+#define lh__ 9
+#define lw__ 10
+
+#define bt__ 0 /* back tab */ /* strings */
+#define bl__ 1 /* bell */
+#define cr__ 2 /* carriage return */
+#define cs__ 3 /* change scroll region */
+#define ct__ 4 /* clear all tab stops */
+#define cl__ 5 /* clear screen and home cursor */
+#define ce__ 6 /* clear to end of line */
+#define cd__ 7 /* clear to end of display */
+#define ch__ 8 /* set cursor column */
+#define CC__ 9 /* term, settable cmd char in */
+#define cm__ 10 /* screen rel cursor motion, row, column */
+#define do__ 11 /* down one line */
+#define ho__ 12 /* home cursor */
+#define vi__ 13 /* make cursor invisible */
+#define le__ 14 /* move cursor left one space */
+#define CM__ 15 /* memory rel cursor addressing */
+#define ve__ 16 /* make cursor appear normal */
+#define nd__ 17 /* non-destructive space (cursor right) */
+#define ll__ 18 /* last line, first col */
+#define up__ 19 /* cursor up */
+#define vs__ 20
+#define dc__ 21 /* delete character */
+#define dl__ 22 /* delete line */
+#define ds__ 23
+#define hd__ 24
+#define as__ 25
+#define mb__ 26
+#define md__ 27 /* turn on bold */
+#define ti__ 28
+#define dm__ 29 /* turn on delete mode */
+#define mh__ 30 /* half bright mode */
+#define im__ 31 /* insert mode */
+#define mk__ 32
+#define mp__ 33
+#define mr__ 34
+#define so__ 35 /* enter standout mode */
+#define us__ 36
+#define ec__ 37
+#define ae__ 38
+#define me__ 39
+#define te__ 40
+#define ed__ 41
+#define ei__ 42 /* exit insert mode */
+#define se__ 43 /* exit standout mode */
+#define ue__ 44
+#define vb__ 45
+#define ff__ 46
+#define fs__ 47
+#define i1__ 48
+#define i2__ 49
+#define i3__ 50
+#define if__ 51
+#define ic__ 52
+#define al__ 53
+#define ip__ 54
+#define kb__ 55 /* backspace key */
+#define ka__ 56
+#define kC__ 57
+#define kt__ 58
+#define kD__ 59
+#define kL__ 60
+#define kd__ 61
+#define kM__ 62
+#define kE__ 63
+#define kS__ 64
+#define k0__ 65
+#define k1__ 66
+#define kf10__ 67
+#define k2__ 68
+#define k3__ 69
+#define k4__ 70
+#define k5__ 71
+#define k6__ 72
+#define k7__ 73
+#define k8__ 74
+#define k9__ 75
+#define kh__ 76
+#define kI__ 77
+#define kA__ 78
+#define kl__ 79
+#define kH__ 80
+#define kN__ 81
+#define kP__ 82
+#define kr__ 83
+#define kF__ 84
+#define kR__ 85
+#define kT__ 86
+#define ku__ 87 /* key up */
+#define ke__ 88
+#define ks__ 89
+#define l0__ 90
+#define l1__ 91
+#define la__ 92
+#define l2__ 93
+#define l3__ 94
+#define l4__ 95
+#define l5__ 96
+#define l6__ 97
+#define l7__ 98
+#define l8__ 99
+#define l9__ 100
+#define mo__ 101
+#define mm__ 102
+#define nw__ 103
+#define pc__ 104
+#define DC__ 105
+#define DL__ 106
+#define DO__ 107
+#define IC__ 118
+#define SF__ 109
+#define AL__ 110
+#define LE__ 111
+#define RI__ 112
+#define SR__ 113
+#define UP__ 114
+#define pk__ 115
+#define pl__ 116
+#define px__ 117
+#define ps__ 118
+#define pf__ 119
+#define po__ 120
+#define rp__ 121
+#define r1__ 122
+#define r2__ 123
+#define r3__ 124
+#define rf__ 125
+#define rc__ 126
+#define cv__ 127
+#define sc__ 128
+#define sf__ 129
+#define sr__ 130
+#define sa__ 131 /* sgr */
+#define st__ 132
+#define wi__ 133
+#define ta__ 134
+#define ts__ 135
+#define uc__ 136
+#define hu__ 137
+#define iP__ 138
+#define K1__ 139
+#define K2__ 140
+#define K3__ 141
+#define K4__ 142
+#define K5__ 143
+#define pO__ 144
+#define ml__ 145
+#define mu__ 146
+#define rmp__ 145
+#define acsc__ 146
+#define pln__ 147
+#define kcbt__ 148
+#define smxon__ 149
+#define rmxon__ 150
+#define smam__ 151
+#define rmam__ 152
+#define xonc__ 153
+#define xoffc__ 154
+#define enacs__ 155
+#define smln__ 156
+#define rmln__ 157
+#define kbeg__ 158
+#define kcan__ 159
+#define kclo__ 160
+#define kcmd__ 161
+#define kcpy__ 162
+#define kcrt__ 163
+#define kend__ 164
+#define kent__ 165
+#define kext__ 166
+#define kfnd__ 167
+#define khlp__ 168
+#define kmrk__ 169
+#define kmsg__ 170
+#define kmov__ 171
+#define knxt__ 172
+#define kopn__ 173
+#define kopt__ 174
+#define kprv__ 175
+#define kprt__ 176
+#define krdo__ 177
+#define kref__ 178
+#define krfr__ 179
+#define krpl__ 180
+#define krst__ 181
+#define kres__ 182
+#define ksav__ 183
+#define kspd__ 184
+#define kund__ 185
+#define kBEG__ 186
+#define kCAN__ 187
+#define kCMD__ 188
+#define kCPY__ 189
+#define kCRT__ 190
+#define kDC__ 191
+#define kDL__ 192
+#define kslt__ 193
+#define kEND__ 194
+#define kEOL__ 195
+#define kEXT__ 196
+#define kFND__ 197
+#define kHLP__ 198
+#define kHOM__ 199
+#define kIC__ 200
+#define kLFT__ 201
+#define kMSG__ 202
+#define kMOV__ 203
+#define kNXT__ 204
+#define kOPT__ 205
+#define kPRV__ 206
+#define kPRT__ 207
+#define kRDO__ 208
+#define kRPL__ 209
+#define kRIT__ 210
+#define kRES__ 211
+#define kSAV__ 212
+#define kSPD__ 213
+#define kUND__ 214
+#define rfi__ 215
+#define kf11__ 216
+#define kf12__ 217
+#define kf13__ 218
+#define kf14__ 219
+#define kf15__ 220
+#define kf16__ 221
+#define kf17__ 222
+#define kf18__ 223
+#define kf19__ 224
+#define kf20__ 225
+#define kf21__ 226
+#define kf22__ 227
+#define kf23__ 228
+#define kf24__ 229
+#define kf25__ 230
+#define kf26__ 231
+#define kf27__ 232
+#define kf28__ 233
+#define kf29__ 234
+#define kf30__ 235
+#define kf31__ 236
+#define kf32__ 237
+#define kf33__ 238
+#define kf34__ 239
+#define kf35__ 240
+#define kf36__ 241
+#define kf37__ 242
+#define kf38__ 243
+#define kf39__ 244
+#define kf40__ 245
+#define kf41__ 246
+#define kf42__ 247
+#define kf43__ 248
+#define kf44__ 249
+#define kf45__ 250
+#define kf46__ 251
+#define kf47__ 252
+#define kf48__ 253
+#define kf49__ 254
+#define kf50__ 255
+#define kf51__ 256
+#define kf52__ 257
+#define kf53__ 258
+#define kf54__ 259
+#define kf55__ 260
+#define kf56__ 261
+#define kf57__ 262
+#define kf58__ 263
+#define kf59__ 264
+#define kf60__ 265
+#define kf61__ 266
+#define kf62__ 267
+#define kf63__ 268
+#define el1__ 269
+#define mgc__ 270
+#define smgl__ 271
+#define smgr__ 272
+
+#ifdef CAP
+char *Boolean_names[] = {
+"bw", "am", "xb", "xs", "xn", "eo", "gn", "hc", "km", "hs", "in", "da", "db",
+"mi", "ms", "os", "es", "xt", "hz", "ul", "xo", "HC", "nx", "NR", "NP", "5i"
+};
+
+char *Number_names[] = {
+"co#", "it#", "li#", "lm#", "sg#", "pb#", "vt#", "ws#", "Nl#", "lh#", "lw#"
+};
+
+char *String_names[] = {
+"bt=", "bl=", "cr=", "cs=", "ct=", "cl=", "ce=", "cd=", "ch=", "CC=", "cm=",
+"do=", "ho=", "vi=", "le=", "CM=", "ve=", "nd=", "ll=", "up=", "vs=", "dc=",
+"dl=", "ds=", "hd=", "as=", "mb=", "md=", "ti=", "dm=", "mh=", "im=", "mk=",
+"mp=", "mr=", "so=", "us=", "ec=", "ae=", "me=", "te=", "ed=", "ei=", "se=",
+"ue=", "vb=", "ff=", "fs=", "i1=", "i2=", "i3=", "if=", "ic=", "al=", "ip=",
+"kb=", "ka=", "kC=", "kt=", "kD=", "kL=", "kd=", "kM=", "kE=", "kS=", "k0=",
+"k1=", "k;=", "k2=", "k3=", "k4=", "k5=", "k6=", "k7=", "k8=", "k9=", "kh=",
+"kI=", "kA=", "kl=", "kH=", "kN=", "kP=", "kr=", "kF=", "kR=", "kT=", "ku=",
+"ke=", "ks=", "l0=", "l1=", "la=", "l2=", "l3=", "l4=", "l5=", "l6=", "l7=",
+"l8=", "l9=", "mo=", "mm=", "nw=", "pc=", "DC=", "DL=", "DO=", "IC=", "SF=",
+"AL=", "LE=", "RI=", "SR=", "UP=", "pk=", "pl=", "px=", "ps=", "pf=", "po=",
+"rp=", "r1=", "r2=", "r3=", "rf=", "rc=", "cv=", "sc=", "sf=", "sr=", "sa=",
+"st=", "wi=", "ta=", "ts=", "uc=", "hu=", "iP=", "K1=", "K3=", "K2=", "K4=",
+"K5=", "pO=", "rP=", "ac=", "pn=", "kB=", "SX=", "RX=", "SA=", "RA=", "XN=",
+"XF=", "eA=", "LO=", "LF=", "@1=", "@2=", "@3=", "@4=", "@5=", "@6=", "@7=",
+"@8=", "@9=", "@0=", "%1=", "%2=", "%3=", "%4=", "%5=", "%6=", "%7=", "%8=",
+"%9=", "%0=", "&1=", "&2=", "&3=", "&4=", "&5=", "&6=", "&7=", "&8=", "&9=",
+"&0=", "*1=", "*2=", "*3=", "*4=", "*5=", "*6=", "*7=", "*8=", "*9=", "*0=",
+"#1=", "#2=", "#3=", "#4=", "%a=", "%b=", "%c=", "%d=", "%e=", "%f=", "%g=",
+"%h=", "%i=", "%j=", "!1=", "!2=", "!3=", "RF=", "F1=", "F2=", "F3=", "F4=",
+"F5=", "F6=", "F7=", "F8=", "F9=", "FA=", "FB=", "FC=", "FD=", "FE=", "FF=",
+"FG=", "FH=", "FI=", "FJ=", "FK=", "FL=", "FM=", "FN=", "FO=", "FP=", "FQ=",
+"FR=", "FS=", "FT=", "FU=", "FV=", "FW=", "FX=", "FY=", "FZ=", "Fa=", "Fb=",
+"Fc=", "Fd=", "Fe=", "Ff=", "Fg=", "Fh=", "Fi=", "Fj=", "Fk=", "Fl=", "Fm=",
+"Fn=", "Fo=", "Fp=", "Fq=", "Fr=", "cb=", "MC=", "ML=", "MR="
+};
+#endif
+
+char *new_curse = "October 1987";
+
+char in_buff[100]; /* buffer for ungetch */
+int bufp; /* next free position in in_buff */
+
+char *TERMINAL_TYPE = NULL; /* terminal type to be gotten from environment */
+int CFOUND = FALSE;
+int Data_Line_len = 0;
+int Max_Key_len; /* max length of a sequence sent by a key */
+char *Data_Line = NULL;
+char *TERM_PATH = NULL;
+char *TERM_data_ptr = NULL;
+char *Term_File_name = NULL; /* name of file containing terminal description */
+FILE *TFP; /* file pointer to file with terminal des. */
+int Fildes; /* file descriptor for terminfo file */
+int STAND = FALSE; /* is standout mode activated? */
+int TERM_INFO = FALSE; /* is terminfo being used (TRUE), or termcap (FALSE) */
+int Time_Out; /* set when time elapsed while trying to read function key */
+int Curr_x; /* current x position on screen */
+int Curr_y; /* current y position on the screen */
+int LINES;
+int COLS;
+int Move_It; /* flag to move cursor if magic cookie glitch */
+int initialized = FALSE; /* tells whether new_curse is initialized */
+float speed;
+float chars_per_millisecond;
+int Repaint_screen; /* if an operation to change screen impossible, repaint screen */
+int Intr; /* storeage for interrupt character */
+int Parity; /* 0 = no parity, 1 = odd parity, 2 = even parity */
+int Noblock; /* for BSD systems */
+int Num_bits; /* number of bits per character */
+int Flip_Bytes; /* some systems have byte order reversed */
+int interrupt_flag = FALSE; /* set true if SIGWINCH received */
+
+#ifndef CAP
+char *Strings;
+#endif
+
+#if !defined(TERMCAP)
+#define TERMCAP "/etc/termcap"
+#endif
+
+struct KEYS {
+ int length; /* length of string sent by key */
+ char *string; /* string sent by key */
+ int value; /* CURSES value of key (9-bit) */
+ };
+
+struct KEY_STACK {
+ struct KEYS *element;
+ struct KEY_STACK *next;
+ };
+
+struct KEY_STACK *KEY_TOS = NULL;
+struct KEY_STACK *KEY_POINT;
+
+/*
+ |
+ | Not all systems have good terminal information, so we will define
+ | keyboard information here for the most widely used terminal type,
+ | the VT100.
+ |
+ */
+
+struct KEYS vt100[] =
+ {
+ { 3, "\033[A", 0403 }, /* key up */
+ { 3, "\033[C", 0405 }, /* key right */
+ { 3, "\033[D", 0404 }, /* key left */
+
+ { 4, "\033[6~", 0522 }, /* key next page */
+ { 4, "\033[5~", 0523 }, /* key prev page */
+ { 3, "\033[[", 0550 }, /* key end */
+ { 3, "\033[@", 0406 }, /* key home */
+ { 4, "\033[2~", 0513 }, /* key insert char */
+
+ { 3, "\033[y", 0410 }, /* key F0 */
+ { 3, "\033[P", 0411 }, /* key F1 */
+ { 3, "\033[Q", 0412 }, /* key F2 */
+ { 3, "\033[R", 0413 }, /* key F3 */
+ { 3, "\033[S", 0414 }, /* key F4 */
+ { 3, "\033[t", 0415 }, /* key F5 */
+ { 3, "\033[u", 0416 }, /* key F6 */
+ { 3, "\033[v", 0417 }, /* key F7 */
+ { 3, "\033[l", 0420 }, /* key F8 */
+ { 3, "\033[w", 0421 }, /* key F9 */
+ { 3, "\033[x", 0422 }, /* key F10 */
+
+ { 5, "\033[10~", 0410 }, /* key F0 */
+ { 5, "\033[11~", 0411 }, /* key F1 */
+ { 5, "\033[12~", 0412 }, /* key F2 */
+ { 5, "\033[13~", 0413 }, /* key F3 */
+ { 5, "\033[14~", 0414 }, /* key F4 */
+ { 5, "\033[15~", 0415 }, /* key F5 */
+ { 5, "\033[17~", 0416 }, /* key F6 */
+ { 5, "\033[18~", 0417 }, /* key F7 */
+ { 5, "\033[19~", 0420 }, /* key F8 */
+ { 5, "\033[20~", 0421 }, /* key F9 */
+ { 5, "\033[21~", 0422 }, /* key F10 */
+ { 5, "\033[23~", 0423 }, /* key F11 */
+ { 5, "\033[24~", 0424 }, /* key F12 */
+ { 3, "\033[q", 0534 }, /* ka1 upper-left of keypad */
+ { 3, "\033[s", 0535 }, /* ka3 upper-right of keypad */
+ { 3, "\033[r", 0536 }, /* kb2 center of keypad */
+ { 3, "\033[p", 0537 }, /* kc1 lower-left of keypad */
+ { 3, "\033[n", 0540 }, /* kc3 lower-right of keypad */
+
+ /*
+ | The following are the same keys as above, but with
+ | a different character following the escape char.
+ */
+
+ { 3, "\033OA", 0403 }, /* key up */
+ { 3, "\033OC", 0405 }, /* key right */
+ { 3, "\033OD", 0404 }, /* key left */
+ { 3, "\033OB", 0402 }, /* key down */
+ { 4, "\033O6~", 0522 }, /* key next page */
+ { 4, "\033O5~", 0523 }, /* key prev page */
+ { 3, "\033O[", 0550 }, /* key end */
+ { 3, "\033O@", 0406 }, /* key home */
+ { 4, "\033O2~", 0513 }, /* key insert char */
+
+ { 3, "\033Oy", 0410 }, /* key F0 */
+ { 3, "\033OP", 0411 }, /* key F1 */
+ { 3, "\033OQ", 0412 }, /* key F2 */
+ { 3, "\033OR", 0413 }, /* key F3 */
+ { 3, "\033OS", 0414 }, /* key F4 */
+ { 3, "\033Ot", 0415 }, /* key F5 */
+ { 3, "\033Ou", 0416 }, /* key F6 */
+ { 3, "\033Ov", 0417 }, /* key F7 */
+ { 3, "\033Ol", 0420 }, /* key F8 */
+ { 3, "\033Ow", 0421 }, /* key F9 */
+ { 3, "\033Ox", 0422 }, /* key F10 */
+
+ { 5, "\033O10~", 0410 }, /* key F0 */
+ { 5, "\033O11~", 0411 }, /* key F1 */
+ { 5, "\033O12~", 0412 }, /* key F2 */
+ { 5, "\033O13~", 0413 }, /* key F3 */
+ { 5, "\033O14~", 0414 }, /* key F4 */
+ { 5, "\033O15~", 0415 }, /* key F5 */
+ { 5, "\033O17~", 0416 }, /* key F6 */
+ { 5, "\033O18~", 0417 }, /* key F7 */
+ { 5, "\033O19~", 0420 }, /* key F8 */
+ { 5, "\033O20~", 0421 }, /* key F9 */
+ { 5, "\033O21~", 0422 }, /* key F10 */
+ { 5, "\033O23~", 0423 }, /* key F11 */
+ { 5, "\033O24~", 0424 }, /* key F12 */
+ { 3, "\033Oq", 0534 }, /* ka1 upper-left of keypad */
+ { 3, "\033Os", 0535 }, /* ka3 upper-right of keypad */
+ { 3, "\033Or", 0536 }, /* kb2 center of keypad */
+ { 3, "\033Op", 0537 }, /* kc1 lower-left of keypad */
+ { 3, "\033On", 0540 }, /* kc3 lower-right of keypad */
+
+ { 0, "", 0 } /* end */
+ };
+
+struct Parameters {
+ int value;
+ struct Parameters *next;
+ };
+
+int Key_vals[] = {
+ 0407, 0526, 0515, 0525, 0512, 0510, 0402, 0514, 0517, 0516, 0410, 0411,
+ 0422, 0412, 0413, 0414, 0415, 0416, 0417, 0420, 0421, 0406, 0513, 0511,
+ 0404, 0533, 0522, 0523, 0405, 0520, 0521, 0524, 0403,
+ 0534, 0535, 0536, 0537, 0540, 0541, 0542, 0543, 0544, 0545, 0546, 0547,
+ 0550, 0527, 0551, 0552, 0553, 0554, 0555, 0556, 0557, 0560, 0561, 0562,
+ 0532, 0563, 0564, 0565, 0566, 0567, 0570, 0571, 0627, 0630, 0572, 0573,
+ 0574, 0575, 0576, 0577, 0600, 0601, 0602, 0603, 0604, 0605, 0606, 0607,
+ 0610, 0611, 0612, 0613, 0614, 0615, 0616, 0617, 0620, 0621, 0622, 0623,
+ 0624, 0625, 0626, 0423, 0424, 0425, 0426, 0427, 0430, 0431,
+ 0432, 0433, 0434, 0435, 0436, 0437, 0440, 0441, 0442, 0443, 0444, 0445,
+ 0446, 0447, 0450, 0451, 0452, 0453, 0454, 0455, 0456, 0457, 0460, 0461,
+ 0462, 0463, 0464, 0465, 0466, 0467, 0470, 0471, 0472, 0473, 0474, 0475,
+ 0476, 0477, 0500, 0501, 0502, 0503, 0504, 0505, 0506, 0507
+};
+
+int attributes_set[9];
+
+static int nc_attributes = 0; /* global attributes for new_curse to observe */
+
+#ifdef SYS5
+struct termio Terminal;
+struct termio Saved_tty;
+#else
+struct sgttyb Terminal;
+struct sgttyb Saved_tty;
+#endif
+
+char *tc_;
+
+int Booleans[128];
+int Numbers[128];
+char *String_table[1024];
+
+int *virtual_lines;
+
+static char nc_scrolling_ability = FALSE;
+
+char *terminfo_path[] = {
+ "/usr/lib/terminfo",
+ "/usr/share/lib/terminfo",
+ "/usr/share/terminfo",
+ NULL
+ };
+
+#ifdef CAP
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define P_(s) s
+#else
+#define P_(s) ()
+#endif /* __STDC__ */
+
+int tc_Get_int P_((int));
+void CAP_PARSE P_((void));
+void Find_term P_((void));
+
+#undef P_
+
+#endif /* CAP */
+
+
+#ifndef __STDC__
+#ifndef HAS_STDLIB
+extern char *fgets();
+extern char *malloc();
+extern char *getenv();
+FILE *fopen(); /* declaration for open function */
+#endif /* HAS_STDLIB */
+#endif /* __STDC__ */
+
+#ifdef SIGWINCH
+
+/*
+ | Copy the contents of one window to another.
+ */
+
+void
+copy_window(origin, destination)
+WINDOW *origin, *destination;
+{
+ int row, column;
+ struct _line *orig, *dest;
+
+ orig = origin->first_line;
+ dest = destination->first_line;
+
+ for (row = 0;
+ row < (min(origin->Num_lines, destination->Num_lines));
+ row++)
+ {
+ for (column = 0;
+ column < (min(origin->Num_cols, destination->Num_cols));
+ column++)
+ {
+ dest->row[column] = orig->row[column];
+ dest->attributes[column] = orig->attributes[column];
+ }
+ dest->changed = orig->changed;
+ dest->scroll = orig->scroll;
+ dest->last_char = min(orig->last_char, destination->Num_cols);
+ orig = orig->next_screen;
+ dest = dest->next_screen;
+ }
+ destination->LX = min((destination->Num_cols - 1), origin->LX);
+ destination->LY = min((destination->Num_lines - 1), origin->LY);
+ destination->Attrib = origin->Attrib;
+ destination->scroll_up = origin->scroll_up;
+ destination->scroll_down = origin->scroll_down;
+ destination->SCROLL_CLEAR = origin->SCROLL_CLEAR;
+}
+
+void
+reinitscr(foo)
+int foo;
+{
+ WINDOW *local_virt;
+ WINDOW *local_std;
+ WINDOW *local_cur;
+
+ signal(SIGWINCH, reinitscr);
+#ifdef TIOCGWINSZ
+ if (ioctl(0, TIOCGWINSZ, &ws) >= 0)
+ {
+ if (ws.ws_row == LINES && ws.ws_col == COLS)
+ return;
+ if (ws.ws_row > 0)
+ LINES = ws.ws_row;
+ if (ws.ws_col > 0)
+ COLS = ws.ws_col;
+ }
+#endif /* TIOCGWINSZ */
+ local_virt = newwin(LINES, COLS, 0, 0);
+ local_std = newwin(LINES, COLS, 0, 0);
+ local_cur = newwin(LINES, COLS, 0, 0);
+ copy_window(virtual_scr, local_virt);
+ copy_window(stdscr, local_std);
+ copy_window(curscr, local_cur);
+ delwin(virtual_scr);
+ delwin(stdscr);
+ delwin(curscr);
+ virtual_scr = local_virt;
+ stdscr = local_std;
+ curscr = local_cur;
+ free(virtual_lines);
+ virtual_lines = (int *) malloc(LINES * (sizeof(int)));
+ interrupt_flag = TRUE;
+}
+#endif /* SIGWINCH */
+
+void
+initscr() /* initialize terminal for operations */
+{
+ int value;
+ int counter;
+ char *lines_string;
+ char *columns_string;
+#ifdef CAP
+ char *pointer;
+#endif /* CAP */
+
+#ifdef DIAG
+printf("starting initscr \n");fflush(stdout);
+#endif
+ if (initialized)
+ return;
+#ifdef BSD_SELECT
+ setbuf(stdin, NULL);
+#endif /* BSD_SELECT */
+ Flip_Bytes = FALSE;
+ Parity = 0;
+ Time_Out = FALSE;
+ bufp = 0;
+ Move_It = FALSE;
+ Noblock = FALSE;
+#ifdef SYS5
+ value = ioctl(0, TCGETA, &Terminal);
+ if (Terminal.c_cflag & PARENB)
+ {
+ if (Terminal.c_cflag & PARENB)
+ Parity = 1;
+ else
+ Parity = 2;
+ }
+ if ((Terminal.c_cflag & CS8) == CS8)
+ {
+ Num_bits = 8;
+ }
+ else if ((Terminal.c_cflag & CS7) == CS7)
+ Num_bits = 7;
+ else if ((Terminal.c_cflag & CS6) == CS6)
+ Num_bits = 6;
+ else
+ Num_bits = 5;
+ value = Terminal.c_cflag & 037;
+ switch (value) {
+ case 01: speed = 50.0;
+ break;
+ case 02: speed = 75.0;
+ break;
+ case 03: speed = 110.0;
+ break;
+ case 04: speed = 134.5;
+ break;
+ case 05: speed = 150.0;
+ break;
+ case 06: speed = 200.0;
+ break;
+ case 07: speed = 300.0;
+ break;
+ case 010: speed = 600.0;
+ break;
+ case 011: speed = 900.0;
+ break;
+ case 012: speed = 1200.0;
+ break;
+ case 013: speed = 1800.0;
+ break;
+ case 014: speed = 2400.0;
+ break;
+ case 015: speed = 3600.0;
+ break;
+ case 016: speed = 4800.0;
+ break;
+ case 017: speed = 7200.0;
+ break;
+ case 020: speed = 9600.0;
+ break;
+ case 021: speed = 19200.0;
+ break;
+ case 022: speed = 38400.0;
+ break;
+ default: speed = 0.0;
+ }
+#else
+ value = ioctl(0, TIOCGETP, &Terminal);
+ if (Terminal.sg_flags & EVENP)
+ Parity = 2;
+ else if (Terminal.sg_flags & ODDP)
+ Parity = 1;
+ value = Terminal.sg_ospeed;
+ switch (value) {
+ case 01: speed = 50.0;
+ break;
+ case 02: speed = 75.0;
+ break;
+ case 03: speed = 110.0;
+ break;
+ case 04: speed = 134.5;
+ break;
+ case 05: speed = 150.0;
+ break;
+ case 06: speed = 200.0;
+ break;
+ case 07: speed = 300.0;
+ break;
+ case 010: speed = 600.0;
+ break;
+ case 011: speed = 1200.0;
+ break;
+ case 012: speed = 1800.0;
+ break;
+ case 013: speed = 2400.0;
+ break;
+ case 014: speed = 4800.0;
+ break;
+ case 015: speed = 9600.0;
+ break;
+ default: speed = 0.0;
+ }
+#endif
+ chars_per_millisecond = (0.001 * speed) / 8.0;
+ TERMINAL_TYPE = getenv("TERM");
+ if (TERMINAL_TYPE == NULL)
+ {
+ printf("unknown terminal type\n");
+ exit(0);
+ }
+#ifndef CAP
+ Fildes = -1;
+ TERM_PATH = getenv("TERMINFO");
+ if (TERM_PATH != NULL)
+ {
+ Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE);
+ Term_File_name = malloc(Data_Line_len);
+ sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
+ Fildes = open(Term_File_name, O_RDONLY);
+ if (Fildes == -1)
+ {
+ sprintf(Term_File_name, "%s/%x/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
+ Fildes = open(Term_File_name, O_RDONLY);
+ }
+ }
+ counter = 0;
+ while ((Fildes == -1) && (terminfo_path[counter] != NULL))
+ {
+ TERM_PATH = terminfo_path[counter];
+ Data_Line_len = 23 + strlen(TERM_PATH) + strlen(TERMINAL_TYPE);
+ Term_File_name = malloc(Data_Line_len);
+ sprintf(Term_File_name, "%s/%c/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
+ Fildes = open(Term_File_name, O_RDONLY);
+ if (Fildes == -1)
+ {
+ sprintf(Term_File_name, "%s/%x/%s", TERM_PATH, *TERMINAL_TYPE, TERMINAL_TYPE);
+ Fildes = open(Term_File_name, O_RDONLY);
+ }
+ counter++;
+ }
+ if (Fildes == -1)
+ {
+ free(Term_File_name);
+ Term_File_name = NULL;
+ }
+ else
+ TERM_INFO = INFO_PARSE();
+#else
+ /*
+ | termcap information can be in the TERMCAP env variable, if so
+ | use that, otherwise check the /etc/termcap file
+ */
+ if ((pointer = Term_File_name = getenv("TERMCAP")) != NULL)
+ {
+ if (*Term_File_name != '/')
+ Term_File_name = TERMCAP;
+ }
+ else
+ {
+ Term_File_name = TERMCAP;
+ }
+ if ((TFP = fopen(Term_File_name, "r")) == NULL)
+ {
+ printf("unable to open %s file \n", TERMCAP);
+ exit(0);
+ }
+ for (value = 0; value < 1024; value++)
+ String_table[value] = NULL;
+ for (value = 0; value < 128; value++)
+ Booleans[value] = 0;
+ for (value = 0; value < 128; value++)
+ Numbers[value] = 0;
+ Data_Line = malloc(512);
+ if (pointer && *pointer != '/')
+ {
+ TERM_data_ptr = pointer;
+ CAP_PARSE();
+ }
+ else
+ {
+ Find_term();
+ CAP_PARSE();
+ }
+#endif
+ if (String_table[pc__] == NULL)
+ String_table[pc__] = "\0";
+ if ((String_table[cm__] == NULL) || (Booleans[hc__]))
+ {
+ fprintf(stderr, "sorry, unable to use this terminal type for screen editing\n");
+ exit(0);
+ }
+ Key_Get();
+ keys_vt100();
+ LINES = Numbers[li__];
+ COLS = Numbers[co__];
+ if ((lines_string = getenv("LINES")) != NULL)
+ {
+ value = atoi(lines_string);
+ if (value > 0)
+ LINES = value;
+ }
+ if ((columns_string = getenv("COLUMNS")) != NULL)
+ {
+ value = atoi(columns_string);
+ if (value > 0)
+ COLS = value;
+ }
+#ifdef TIOCGWINSZ
+ /*
+ | get the window size
+ */
+ if (ioctl(0, TIOCGWINSZ, &ws) >= 0)
+ {
+ if (ws.ws_row > 0)
+ LINES = ws.ws_row;
+ if (ws.ws_col > 0)
+ COLS = ws.ws_col;
+ }
+#endif
+ virtual_scr = newwin(LINES, COLS, 0, 0);
+ stdscr = newwin(LINES, COLS, 0, 0);
+ curscr = newwin(LINES, COLS, 0, 0);
+ wmove(stdscr, 0, 0);
+ werase(stdscr);
+ Repaint_screen = TRUE;
+ initialized = TRUE;
+ virtual_lines = (int *) malloc(LINES * (sizeof(int)));
+
+#ifdef SIGWINCH
+ /*
+ | reset size of windows and LINES and COLS if term window
+ | changes size
+ */
+ signal(SIGWINCH, reinitscr);
+#endif /* SIGWINCH */
+
+ /*
+ | check if scrolling is available
+ */
+
+ nc_scrolling_ability = ((String_table[al__] != NULL) &&
+ (String_table[dl__])) || ((String_table[cs__])
+ && (String_table[sr__]));
+
+}
+
+#ifndef CAP
+int
+Get_int() /* get a two-byte integer from the terminfo file */
+{
+ int High_byte;
+ int Low_byte;
+ int temp;
+
+ Low_byte = *((unsigned char *) TERM_data_ptr++);
+ High_byte = *((unsigned char *) TERM_data_ptr++);
+ if (Flip_Bytes)
+ {
+ temp = Low_byte;
+ Low_byte = High_byte;
+ High_byte = temp;
+ }
+ if ((High_byte == 255) && (Low_byte == 255))
+ return (-1);
+ else
+ return(Low_byte + (High_byte * 256));
+}
+
+int
+INFO_PARSE() /* parse off the data in the terminfo data file */
+{
+ int offset;
+ int magic_number = 0;
+ int counter = 0;
+ int Num_names = 0;
+ int Num_bools = 0;
+ int Num_ints = 0;
+ int Num_strings = 0;
+ int string_table_len = 0;
+ char *temp_ptr;
+
+ TERM_data_ptr = Data_Line = malloc((10240 * (sizeof(char))));
+ Data_Line_len = read(Fildes, Data_Line, 10240);
+ if ((Data_Line_len >= 10240) || (Data_Line_len < 0))
+ return(0);
+ /*
+ | get magic number
+ */
+ magic_number = Get_int();
+ /*
+ | if magic number not right, reverse byte order and check again
+ */
+ if (magic_number != 282)
+ {
+ Flip_Bytes = TRUE;
+ TERM_data_ptr--;
+ TERM_data_ptr--;
+ magic_number = Get_int();
+ if (magic_number != 282)
+ return(0);
+ }
+ /*
+ | get the number of each type in the terminfo data file
+ */
+ Num_names = Get_int();
+ Num_bools = Get_int();
+ Num_ints = Get_int();
+ Num_strings = Get_int();
+ string_table_len = Get_int();
+ Strings = malloc(string_table_len);
+ while (Num_names > 0)
+ {
+ TERM_data_ptr++;
+ Num_names--;
+ }
+ counter = 0;
+ while (Num_bools)
+ {
+ Num_bools--;
+ Booleans[counter++] = *TERM_data_ptr++;
+ }
+ if ((unsigned long)TERM_data_ptr & 1) /* force alignment */
+ TERM_data_ptr++;
+ counter = 0;
+ while (Num_ints)
+ {
+ Num_ints--;
+ Numbers[counter] = Get_int();
+ counter++;
+ }
+ temp_ptr = TERM_data_ptr + Num_strings + Num_strings;
+ memcpy(Strings, temp_ptr, string_table_len);
+ counter = bt__;
+ while (Num_strings)
+ {
+ Num_strings--;
+ if ((offset=Get_int()) != -1)
+ {
+ if (String_table[counter] == NULL)
+ String_table[counter] = Strings + offset;
+ }
+ else
+ String_table[counter] = NULL;
+ counter++;
+ }
+ close(Fildes);
+ free(Data_Line);
+ return(TRUE);
+}
+#endif /* ifndef CAP */
+
+int
+AtoI() /* convert ascii text to integers */
+{
+ int Temp;
+
+ Temp = 0;
+ while ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
+ {
+ Temp = (Temp * 10) + (*TERM_data_ptr - '0');
+ TERM_data_ptr++;
+ }
+ return(Temp);
+}
+
+void
+Key_Get() /* create linked list with all key sequences obtained from terminal database */
+{
+ int Counter;
+ int Klen;
+ int key_def;
+ struct KEY_STACK *Spoint;
+
+ Max_Key_len = 0;
+ Counter = 0;
+ key_def = kb__;
+ while (key_def <= kf63__)
+ {
+ if (key_def == ke__)
+ key_def = K1__;
+ else if (key_def == (K5__ + 1))
+ key_def = kcbt__;
+ else if (key_def == (kcbt__ + 1))
+ key_def = kbeg__;
+ else if (key_def == (kUND__ + 1))
+ key_def = kf11__;
+ if (String_table[key_def] != NULL)
+ {
+ if (KEY_TOS == NULL)
+ Spoint = KEY_TOS = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
+ else
+ {
+ Spoint = KEY_TOS;
+ while (Spoint->next != NULL)
+ Spoint = Spoint->next;
+ Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
+ Spoint = Spoint->next;
+ }
+ Spoint->next = NULL;
+ Spoint->element = (struct KEYS *) malloc(sizeof(struct KEYS));
+ Spoint->element->string = String_table[key_def];
+ Spoint->element->length = strlen(String_table[key_def]);
+ Spoint->element->value = Key_vals[Counter];
+ Klen = strlen(Spoint->element->string);
+ if (Klen > Max_Key_len)
+ Max_Key_len = Klen;
+ /*
+ | Some terminal types accept keystrokes of the form
+ | \E[A and \EOA, substituting '[' for 'O'. Make a
+ | duplicate of such key strings (since the
+ | database will only have one version) so new_curse
+ | can understand both.
+ */
+ if ((Spoint->element->length > 1) &&
+ ((String_table[key_def][1] == '[') ||
+ (String_table[key_def][1] == 'O')))
+ {
+ Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
+ Spoint = Spoint->next;
+ Spoint->next = NULL;
+ Spoint->element = (struct KEYS *) malloc(sizeof(struct KEYS));
+ Spoint->element->length = strlen(String_table[key_def]);
+ Spoint->element->string = malloc(Spoint->element->length + 1);
+ strcpy(Spoint->element->string, String_table[key_def]);
+ Spoint->element->value = Key_vals[Counter];
+ Klen = strlen(Spoint->element->string);
+ if (Klen > Max_Key_len)
+ Max_Key_len = Klen;
+
+ if (String_table[key_def][1] == '[')
+ Spoint->element->string[1] = 'O';
+ else
+ Spoint->element->string[1] = '[';
+ }
+ }
+ key_def++;
+ Counter++;
+ }
+}
+
+/*
+ | insert information about keys for a vt100 terminal
+ */
+
+void
+keys_vt100()
+{
+ int counter;
+ int Klen;
+ struct KEY_STACK *Spoint;
+
+ Spoint = KEY_TOS;
+ while (Spoint->next != NULL)
+ Spoint = Spoint->next;
+ for (counter = 0; vt100[counter].length != 0; counter++)
+ {
+ Spoint->next = (struct KEY_STACK *) malloc(sizeof(struct KEY_STACK));
+ Spoint = Spoint->next;
+ Spoint->next = NULL;
+ Spoint->element = &vt100[counter];
+ Klen = strlen(Spoint->element->string);
+ if (Klen > Max_Key_len)
+ Max_Key_len = Klen;
+ }
+}
+
+#ifdef CAP
+char *
+String_Get(param) /* read the string */
+char *param;
+{
+ char *String;
+ char *Temp;
+ int Counter;
+
+ if (param == NULL)
+ {
+ while (*TERM_data_ptr != '=')
+ TERM_data_ptr++;
+ Temp = ++TERM_data_ptr;
+ Counter = 1;
+ while ((*Temp != ':') && (*Temp != (char)NULL))
+ {
+ Counter++;
+ Temp++;
+ }
+ if (Counter == 1) /* no data */
+ return(NULL);
+ String = Temp = malloc(Counter);
+ while ((*TERM_data_ptr != ':') && (*TERM_data_ptr != (char)NULL))
+ {
+ if (*TERM_data_ptr == '\\')
+ {
+ TERM_data_ptr++;
+ if (*TERM_data_ptr == 'n')
+ *Temp = '\n';
+ else if (*TERM_data_ptr == 't')
+ *Temp = '\t';
+ else if (*TERM_data_ptr == 'b')
+ *Temp = '\b';
+ else if (*TERM_data_ptr == 'r')
+ *Temp = '\r';
+ else if (*TERM_data_ptr == 'f')
+ *Temp = '\f';
+ else if ((*TERM_data_ptr == 'e') || (*TERM_data_ptr == 'E'))
+ *Temp = '\033'; /* escape */
+ else if (*TERM_data_ptr == '\\')
+ *Temp = '\\';
+ else if (*TERM_data_ptr == '\'')
+ *Temp = '\'';
+ else if ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
+ {
+ Counter = 0;
+ while ((*TERM_data_ptr >= '0') && (*TERM_data_ptr <= '9'))
+ {
+ Counter = (8 * Counter) + (*TERM_data_ptr - '0');
+ TERM_data_ptr++; /* ? */
+ }
+ *Temp = Counter;
+ TERM_data_ptr--;
+ }
+ TERM_data_ptr++;
+ Temp++;
+ }
+ else if (*TERM_data_ptr == '^')
+ {
+ TERM_data_ptr++;
+ if ((*TERM_data_ptr >= '@') && (*TERM_data_ptr <= '_'))
+ *Temp = *TERM_data_ptr - '@';
+ else if (*TERM_data_ptr == '?')
+ *Temp = 127;
+ TERM_data_ptr++;
+ Temp++;
+ }
+ else
+ *Temp++ = *TERM_data_ptr++;
+ }
+ *Temp = (char)NULL;
+ param = String;
+ }
+ else
+ {
+ while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != ':'))
+ TERM_data_ptr++;
+ }
+ return(param);
+}
+
+int
+tc_Get_int(param) /* read the integer */
+int param;
+{
+ int Itemp;
+
+ if (param == 0)
+ {
+ while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != '#'))
+ TERM_data_ptr++;
+ TERM_data_ptr++;
+ Itemp = AtoI();
+ param = Itemp;
+ }
+ else
+ {
+ while (*TERM_data_ptr != ':')
+ TERM_data_ptr++;
+ }
+ return(param);
+}
+
+void
+Find_term() /* find terminal description in termcap file */
+{
+ char *Name;
+ char *Ftemp;
+
+ Ftemp = Name = malloc(strlen(TERMINAL_TYPE) + 2);
+ strcpy(Name, TERMINAL_TYPE);
+ while (*Ftemp != (char)NULL)
+ Ftemp++;
+ *Ftemp++ = '|';
+ *Ftemp = (char)NULL;
+ CFOUND = FALSE;
+ Data_Line_len = strlen(TERMINAL_TYPE) + 1;
+ while ((!CFOUND) && ((TERM_data_ptr=fgets(Data_Line, 512, TFP)) != NULL))
+ {
+ if ((*TERM_data_ptr != ' ') && (*TERM_data_ptr != '\t') && (*TERM_data_ptr != '#'))
+ {
+ while ((!CFOUND) && (*TERM_data_ptr != (char)NULL))
+ {
+ CFOUND = !strncmp(TERM_data_ptr, Name, Data_Line_len);
+ while ((*TERM_data_ptr != (char)NULL) && (*TERM_data_ptr != '|') && (*TERM_data_ptr != '#') && (*TERM_data_ptr != ':'))
+ TERM_data_ptr++;
+ if (*TERM_data_ptr == '|')
+ TERM_data_ptr++;
+ else if (!CFOUND)
+ *TERM_data_ptr = (char)NULL;
+ }
+ }
+ }
+ if (!CFOUND)
+ {
+ printf("terminal type %s not found\n", TERMINAL_TYPE);
+ exit(0);
+ }
+}
+
+void
+CAP_PARSE() /* parse off the data in the termcap data file */
+{
+ int offset;
+ int found;
+
+ do
+ {
+ while (*TERM_data_ptr != (char)NULL)
+ {
+ for (found = FALSE, offset = 0; (!found) && (offset < 26); offset++)
+ {
+ if (!strncmp(TERM_data_ptr, Boolean_names[offset], 2))
+ {
+ found = TRUE;
+ Booleans[offset] = TRUE;
+ }
+ }
+ if (!found)
+ {
+ for (found = FALSE, offset = 0; (!found) && (offset < lw__); offset++)
+ {
+ if (!strncmp(TERM_data_ptr, Number_names[offset], 3))
+ {
+ found = TRUE;
+ Numbers[offset] = tc_Get_int(Numbers[offset]);
+ }
+ }
+ }
+ if (!found)
+ {
+ for (found = FALSE, offset = 0; (!found) && (offset < smgr__); offset++)
+ {
+ if (!strncmp(TERM_data_ptr, String_names[offset], 3))
+ {
+ found = TRUE;
+ String_table[offset] = String_Get(String_table[offset]);
+ }
+ }
+ }
+
+ if (!strncmp(TERM_data_ptr, "tc=", 3))
+ tc_ = String_Get(NULL);
+ while ((*TERM_data_ptr != ':') && (*TERM_data_ptr != (char)NULL))
+ TERM_data_ptr++;
+ if (*TERM_data_ptr == ':')
+ TERM_data_ptr++;
+ }
+ } while (((TERM_data_ptr = fgets(Data_Line, 512, TFP)) != NULL) && ((*TERM_data_ptr == ' ') || (*TERM_data_ptr == '\t')));
+ if (tc_ != NULL)
+ {
+ TERMINAL_TYPE = tc_;
+ rewind(TFP);
+ Find_term();
+ tc_ = NULL;
+ CAP_PARSE();
+ }
+ else
+ fclose(TFP);
+}
+#endif /* ifdef CAP */
+
+struct _line *
+Screenalloc(columns)
+int columns;
+{
+ int i;
+ struct _line *tmp;
+
+ tmp = (struct _line *) malloc(sizeof (struct _line));
+ tmp->row = malloc(columns + 1);
+ tmp->attributes = malloc(columns + 1);
+ tmp->prev_screen = NULL;
+ tmp->next_screen = NULL;
+ for (i = 0; i < columns; i++)
+ {
+ tmp->row[i] = ' ';
+ tmp->attributes[i] = '\0';
+ }
+ tmp->scroll = tmp->changed = FALSE;
+ tmp->row[0] = '\0';
+ tmp->attributes[0] = '\0';
+ tmp->row[columns] = '\0';
+ tmp->attributes[columns] = '\0';
+ tmp->last_char = 0;
+ return(tmp);
+}
+
+WINDOW *newwin(lines, cols, start_l, start_c)
+int lines, cols; /* number of lines and columns to be in window */
+int start_l, start_c; /* starting line and column to be inwindow */
+{
+ WINDOW *Ntemp;
+ struct _line *temp_screen;
+ int i;
+
+ Ntemp = (WINDOW *) malloc(sizeof(WINDOW));
+ Ntemp->SR = start_l;
+ Ntemp->SC = start_c;
+ Ntemp->Num_lines = lines;
+ Ntemp->Num_cols = cols;
+ Ntemp->LX = 0;
+ Ntemp->LY = 0;
+ Ntemp->scroll_down = Ntemp->scroll_up = 0;
+ Ntemp->SCROLL_CLEAR = FALSE;
+ Ntemp->Attrib = FALSE;
+ Ntemp->first_line = temp_screen = Screenalloc(cols);
+ Ntemp->first_line->number = 0;
+ Ntemp->line_array = (struct _line **) malloc(LINES * sizeof(struct _line *));
+
+ Ntemp->line_array[0] = Ntemp->first_line;
+
+ for (i = 1; i < lines; i++)
+ {
+ temp_screen->next_screen = Screenalloc(cols);
+ temp_screen->next_screen->number = i;
+ temp_screen->next_screen->prev_screen = temp_screen;
+ temp_screen = temp_screen->next_screen;
+ Ntemp->line_array[i] = temp_screen;
+ }
+ Ntemp->first_line->prev_screen = NULL;
+ temp_screen->next_screen = NULL;
+ return(Ntemp);
+}
+
+#ifdef CAP
+void
+Cap_Out(string, p_list, place) /* interpret the output string if necessary */
+char *string;
+int p_list[]; /* stack of values */
+int place; /* place keeper of top of stack */
+{
+ char *Otemp; /* temporary string pointer to parse output */
+ int delay;
+ int p1, p2, temp;
+ float chars;
+
+ if (string == NULL)
+ return;
+
+ if (p_list != NULL)
+ {
+ p1 = p_list[--place];
+ p2 = p_list[--place];
+ }
+ delay = 0;
+ Otemp = string;
+ if ((*Otemp >= '0') && (*Otemp <= '9'))
+ {
+ delay = atoi(Otemp);
+ while ((*Otemp >= '0') && (*Otemp <= '9'))
+ Otemp++;
+ if (*Otemp == '*')
+ Otemp++;
+ }
+ while (*Otemp != (char)NULL)
+ {
+ if (*Otemp == '%')
+ {
+ Otemp++;
+ if ((*Otemp == 'd') || (*Otemp == '2') || (*Otemp == '3') || (*Otemp == '.') || (*Otemp == '+'))
+ {
+ if (*Otemp == 'd')
+ printf("%d", p1);
+ else if (*Otemp == '2')
+ printf("%02d", p1);
+ else if (*Otemp == '3')
+ printf("%03d", p1);
+ else if (*Otemp == '+')
+ {
+ Otemp++;
+ p1 += *Otemp;
+ putchar(p1);
+ }
+ else if (*Otemp == '.')
+ putchar(p1);
+ p1 = p2;
+ p2 = 0;
+ }
+ else if (*Otemp == '>')
+ {
+ Otemp++;
+ if (p1 > *Otemp)
+ {
+ Otemp++;
+ p1 += *Otemp;
+ }
+ else
+ Otemp++;
+ }
+ else if (*Otemp == 'r')
+ {
+ temp = p1;
+ p1 = p2;
+ p2 = temp;
+ }
+ else if (*Otemp == 'i')
+ {
+ p1++;
+ p2++;
+ }
+ else if (*Otemp == '%')
+ putchar(*Otemp);
+ else if (*Otemp == 'n')
+ {
+ p1 ^= 0140;
+ p2 ^= 0140;
+ }
+ else if (*Otemp == 'B')
+ {
+ p1 = (16 * (p1/10)) + (p1 % 10);
+ p2 = (16 * (p2/10)) + (p2 % 10);
+ }
+ else if (*Otemp == 'D')
+ {
+ p1 = (p1 - 2 * (p1 % 16));
+ p2 = (p2 - 2 * (p2 % 16));
+ }
+ }
+ else
+ putchar (*Otemp);
+ Otemp++;
+ }
+ if (delay != 0)
+ {
+ chars = delay * chars_per_millisecond;
+ delay = chars;
+ if ((chars - delay) > 0.0)
+ delay++;
+ for (; delay > 0; delay--)
+ putchar(*String_table[pc__]);
+ }
+ fflush(stdout);
+}
+
+#else
+
+ char *Otemp; /* temporary string pointer to parse output */
+ float chars;
+ int p[10];
+ int variable[27];
+
+int
+Operation(Temp_Stack, place) /* handle conditional operations */
+int Temp_Stack[];
+int place;
+{
+ int temp;
+
+ if (*Otemp == 'd')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ printf("%d", temp);
+ }
+ else if (!strncmp(Otemp, "2d", 2))
+ {
+ temp = Temp_Stack[--place];
+ printf("%2d", temp);
+ Otemp++;
+ Otemp++;
+ }
+ else if (!strncmp(Otemp, "3d", 2))
+ {
+ temp = Temp_Stack[--place];
+ printf("%0d", temp);
+ Otemp++;
+ Otemp++;
+ }
+ else if (!strncmp(Otemp, "02d", 3))
+ {
+ temp = Temp_Stack[--place];
+ printf("%02d", temp);
+ Otemp++;
+ Otemp++;
+ Otemp++;
+ }
+ else if (!strncmp(Otemp, "03d", 3))
+ {
+ temp = Temp_Stack[--place];
+ printf("%03d", temp);
+ Otemp++;
+ Otemp++;
+ Otemp++;
+ }
+ else if (*Otemp == '+')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp += Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '-')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp -= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '*')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp *= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '/')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp /= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == 'm')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp %= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '&')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp &= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '|')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp |= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '^')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp ^= Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '=')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp = (temp == Temp_Stack[--place]);
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '>')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp = temp > Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == '<')
+ {
+ Otemp++;
+ temp = Temp_Stack[--place];
+ temp = temp < Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ }
+ else if (*Otemp == 'c')
+ {
+ Otemp++;
+ putchar(Temp_Stack[--place]);
+ }
+ else if (*Otemp == 'i')
+ {
+ Otemp++;
+ p[1]++;
+ p[2]++;
+ }
+ else if (*Otemp == '%')
+ {
+ putchar(*Otemp);
+ Otemp++;
+ }
+ else if (*Otemp == '!')
+ {
+ temp = ! Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ Otemp++;
+ }
+ else if (*Otemp == '~')
+ {
+ temp = ~Temp_Stack[--place];
+ Temp_Stack[place++] = temp;
+ Otemp++;
+ }
+ else if (*Otemp == 'p')
+ {
+ Otemp++;
+ Temp_Stack[place++] = p[*Otemp - '0'];
+ Otemp++;
+ }
+ else if (*Otemp == 'P')
+ {
+ Otemp++;
+ Temp_Stack[place++] = variable[*Otemp - 'a'];
+ Otemp++;
+ }
+ else if (*Otemp == 'g')
+ {
+ Otemp++;
+ variable[*Otemp - 'a'] = Temp_Stack[--place];
+ Otemp++;
+ }
+ else if (*Otemp == '\'')
+ {
+ Otemp++;
+ Temp_Stack[place++] = *Otemp;
+ Otemp++;
+ Otemp++;
+ }
+ else if (*Otemp == '{')
+ {
+ Otemp++;
+ temp = atoi(Otemp);
+ Temp_Stack[place++] = temp;
+ while (*Otemp != '}')
+ Otemp++;
+ Otemp++;
+ }
+ return(place);
+}
+
+void
+Info_Out(string, p_list, place) /* interpret the output string if necessary */
+char *string;
+int p_list[];
+int place;
+{
+ char *tchar;
+ int delay;
+ int temp;
+ int Cond_FLAG;
+ int EVAL;
+ int Cond_Stack[128];
+ int Cond_place;
+ int Stack[128];
+ int Top_of_stack;
+
+ if (string == NULL)
+ return;
+
+ Cond_FLAG = FALSE;
+ Cond_place = 0;
+ Top_of_stack = 0;
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ p[3] = 0;
+ p[4] = 0;
+ p[5] = 0;
+ p[6] = 0;
+ p[7] = 0;
+ p[8] = 0;
+ p[9] = 0;
+ if (p_list != NULL)
+ {
+ for (temp = 1; (place != 0); temp++)
+ {
+ p[temp] = p_list[--place];
+ }
+ }
+ delay = 0;
+ Otemp = string;
+ while (*Otemp != '\0')
+ {
+ if (*Otemp == '%')
+ {
+ Otemp++;
+ if ((*Otemp == '?') || (*Otemp == 't') || (*Otemp == 'e') || (*Otemp == ';'))
+ {
+ if (*Otemp == '?')
+ {
+ Otemp++;
+ Cond_FLAG = TRUE;
+ EVAL = TRUE;
+ while (EVAL)
+ {
+ /*
+ | find the end of the
+ | conditional statement
+ */
+ while ((strncmp(Otemp, "%t", 2)) && (*Otemp != '\0'))
+ {
+ /*
+ | move past '%'
+ */
+ Otemp++;
+ Cond_place = Operation(Cond_Stack, Cond_place);
+ }
+
+ /*
+ | if condition is true
+ */
+ if ((Cond_place > 0) && (Cond_Stack[Cond_place-1]))
+ {
+ /*
+ | end conditional
+ | parsing
+ */
+ EVAL = FALSE;
+ Otemp++;
+ Otemp++;
+ }
+ else /* condition is false */
+ {
+ /*
+ | find 'else' or end
+ | of if statement
+ */
+ while ((strncmp(Otemp, "%e", 2)) && (strncmp(Otemp, "%;", 2)) && (*Otemp != '\0'))
+ Otemp++;
+ /*
+ | if an 'else' found
+ */
+ if ((*Otemp != '\0') && (!strncmp(Otemp, "%e", 2)))
+ {
+ Otemp++;
+ Otemp++;
+ tchar = Otemp;
+ /*
+ | check for 'then' part
+ */
+ while ((*tchar != '\0') && (strncmp(tchar, "%t", 2)) && (strncmp(tchar, "%;", 2)))
+ tchar++;
+ /*
+ | if end of string
+ */
+ if (*tchar == '\0')
+ {
+ EVAL = FALSE;
+ Cond_FLAG = FALSE;
+ Otemp = tchar;
+ }
+ /*
+ | if end of if found,
+ | set up to parse
+ | info
+ */
+ else if (!strncmp(tchar, "%;", 2))
+ EVAL = FALSE;
+ /*
+ | otherwise, check
+ | conditional in
+ | 'else'
+ */
+ }
+ /*
+ | if end of if found,
+ | get out of if
+ | statement
+ */
+ else if ((*Otemp != '\0') && (!strncmp(Otemp, "%;", 2)))
+ {
+ EVAL = FALSE;
+ Otemp++;
+ Otemp++;
+ }
+ else /* Otemp == NULL */
+ {
+ EVAL = FALSE;
+ Cond_FLAG = FALSE;
+ }
+ }
+ }
+ }
+ else
+ {
+ Otemp++;
+ Cond_FLAG = FALSE;
+ if (*Otemp != ';')
+ {
+ while ((*Otemp != '\0') && (strncmp(Otemp, "%;", 2)))
+ Otemp++;
+ if (*Otemp != '\0')
+ {
+ Otemp++;
+ Otemp++;
+ }
+ }
+ else
+ Otemp++;
+ }
+ }
+ else
+ {
+ Top_of_stack = Operation(Stack, Top_of_stack);
+ }
+ }
+ else if (!strncmp(Otemp, "$<", 2))
+ {
+ Otemp++;
+ Otemp++;
+ delay = atoi(Otemp);
+ while (*Otemp != '>')
+ Otemp++;
+ Otemp++;
+ chars = delay * chars_per_millisecond;
+ delay = chars;
+ if ((chars - delay) > 0.0)
+ delay++;
+ if (String_table[pc__] == NULL)
+ temp = 0;
+ else
+ temp = *String_table[pc__];
+ for (; delay > 0; delay--)
+ putc(temp, stdout);
+ }
+ else
+ {
+ putchar(*Otemp);
+ Otemp++;
+ }
+ }
+ fflush(stdout);
+}
+#endif
+
+void
+wmove(window, row, column) /* move cursor to indicated position in window */
+WINDOW *window;
+int row, column;
+{
+ if ((row < window->Num_lines) && (column < window->Num_cols))
+ {
+ window->LX = column;
+ window->LY = row;
+ }
+}
+
+void
+clear_line(line, column, cols)
+struct _line *line;
+int column;
+int cols;
+{
+ int j;
+
+ if (column > line->last_char)
+ {
+ for (j = line->last_char; j < column; j++)
+ {
+ line->row[j] = ' ';
+ line->attributes[j] = '\0';
+ }
+ }
+ line->last_char = column;
+ line->row[column] = '\0';
+ line->attributes[column] = '\0';
+ line->changed = TRUE;
+}
+
+void
+werase(window) /* clear the specified window */
+WINDOW *window;
+{
+ int i;
+ struct _line *tmp;
+
+ window->SCROLL_CLEAR = CLEAR;
+ window->scroll_up = window->scroll_down = 0;
+ for (i = 0, tmp = window->first_line; i < window->Num_lines; i++, tmp = tmp->next_screen)
+ clear_line(tmp, 0, window->Num_cols);
+}
+
+void
+wclrtoeol(window) /* erase from current cursor position to end of line */
+WINDOW *window;
+{
+ int column, row;
+ struct _line *tmp;
+
+ window->SCROLL_CLEAR = CHANGE;
+ column = window->LX;
+ row = window->LY;
+ for (row = 0, tmp = window->first_line; row < window->LY; row++)
+ tmp = tmp->next_screen;
+ clear_line(tmp, column, window->Num_cols);
+}
+
+void
+wrefresh(window) /* flush all previous output */
+WINDOW *window;
+{
+ wnoutrefresh(window);
+#ifdef DIAG
+{
+ struct _line *temp;
+ int value;
+ fprintf(stderr, "columns=%d, lines=%d, SC=%d, SR=%d\n",window->Num_cols, window->Num_lines, window->SC, window->SR);
+ for (value = 0, temp = window->first_line; value < window->Num_lines; value++, temp = temp->next_screen)
+ {
+ if (temp->number == -1)
+ fprintf(stderr, "line moved ");
+ if (temp->scroll)
+ fprintf(stderr, "scroll_x is set: ");
+ fprintf(stderr, "lc%d=%s|\n", temp->last_char, temp->row);
+ }
+ fprintf(stderr, "+-------------------- virtual screen ----------------------------------------+\n");
+ fprintf(stderr, "columns=%d, lines=%d \n",virtual_scr->Num_cols, virtual_scr->Num_lines);
+ for (value = 0, temp = virtual_scr->first_line; value < virtual_scr->Num_lines; value++, temp = temp->next_screen)
+ {
+ if (temp->number == -1)
+ fprintf(stderr, "line moved ");
+ if (temp->scroll)
+ fprintf(stderr, "scroll_x is set: ");
+ fprintf(stderr, "lc%d=%s|\n", temp->last_char, temp->row);
+ }
+ fprintf(stderr, "columns=%d, lines=%d \n",curscr->Num_cols, curscr->Num_lines);
+ for (value = 0, temp = curscr->first_line; value < curscr->Num_lines; value++, temp = temp->next_screen)
+ fprintf(stderr, "line=%s|\n", temp->row);
+}
+#endif
+ doupdate();
+ virtual_scr->SCROLL_CLEAR = FALSE;
+ virtual_scr->scroll_down = virtual_scr->scroll_up = 0;
+ fflush(stdout);
+}
+
+void
+touchwin(window)
+WINDOW *window;
+{
+ struct _line *user_line;
+ int line_counter = 0;
+
+ for (line_counter = 0, user_line = window->first_line;
+ line_counter < window->Num_lines; line_counter++)
+ {
+ user_line->changed = TRUE;
+ }
+ window->SCROLL_CLEAR = TRUE;
+}
+
+void
+wnoutrefresh(window)
+WINDOW *window;
+{
+ struct _line *user_line;
+ struct _line *virtual_line;
+ int line_counter = 0;
+ int user_col = 0;
+ int virt_col = 0;
+
+ if (window->SR >= virtual_scr->Num_lines)
+ return;
+ user_line = window->first_line;
+ virtual_line = virtual_scr->first_line;
+ virtual_scr->SCROLL_CLEAR = window->SCROLL_CLEAR;
+ virtual_scr->LX = window->LX + window->SC;
+ virtual_scr->LY = window->LY + window->SR;
+ virtual_scr->scroll_up = window->scroll_up;
+ virtual_scr->scroll_down = window->scroll_down;
+ if ((last_window_refreshed == window) && (!window->SCROLL_CLEAR))
+ return;
+ for (line_counter = 0; line_counter < window->SR; line_counter++)
+ {
+ virtual_line = virtual_line->next_screen;
+ }
+ for (line_counter = 0; (line_counter < window->Num_lines)
+ && ((line_counter + window->SR) < virtual_scr->Num_lines);
+ line_counter++)
+ {
+ if ((last_window_refreshed != window) || (user_line->changed) || ((SCROLL | CLEAR) & window->SCROLL_CLEAR))
+ {
+ for (user_col = 0, virt_col = window->SC;
+ (virt_col < virtual_scr->Num_cols)
+ && (user_col < user_line->last_char);
+ virt_col++, user_col++)
+ {
+ virtual_line->row[virt_col] = user_line->row[user_col];
+ virtual_line->attributes[virt_col] = user_line->attributes[user_col];
+ }
+ for (user_col = user_line->last_char,
+ virt_col = window->SC + user_line->last_char;
+ (virt_col < virtual_scr->Num_cols)
+ && (user_col < window->Num_cols);
+ virt_col++, user_col++)
+ {
+ virtual_line->row[virt_col] = ' ';
+ virtual_line->attributes[virt_col] = '\0';
+ }
+ }
+ if (virtual_scr->Num_cols != window->Num_cols)
+ {
+ if (virtual_line->last_char < (user_line->last_char + window->SC))
+ {
+ if (virtual_line->row[virtual_line->last_char] == '\0')
+ virtual_line->row[virtual_line->last_char] = ' ';
+ virtual_line->last_char =
+ min(virtual_scr->Num_cols,
+ (user_line->last_char + window->SC));
+ }
+ }
+ else
+ virtual_line->last_char = user_line->last_char;
+ virtual_line->row[virtual_line->last_char] = '\0';
+ virtual_line->changed = user_line->changed;
+ virtual_line = virtual_line->next_screen;
+ user_line = user_line->next_screen;
+ }
+ window->SCROLL_CLEAR = FALSE;
+ window->scroll_up = window->scroll_down = 0;
+ last_window_refreshed = window;
+}
+
+void
+flushinp() /* flush input */
+{
+}
+
+void
+ungetch(c) /* push a character back on input */
+int c;
+{
+ if (bufp < 100)
+ in_buff[bufp++] = c;
+}
+
+#ifdef BSD_SELECT
+int
+timed_getchar()
+{
+ struct timeval tv;
+ fd_set fds;
+ int ret_val;
+ int nfds = 1;
+ char temp;
+
+ FD_ZERO(&fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 500000; /* half a second */
+ FD_SET(0, &fds);
+ Time_Out = FALSE; /* just in case */
+
+ ret_val = select(nfds, &fds, 0, 0, &tv);
+
+ /*
+ | if ret_val is less than zero, there was no input
+ | otherwise, get a character and return it
+ */
+
+ if (ret_val <= 0)
+ {
+ Time_Out = TRUE;
+ return(-1);
+ }
+
+ return(read(0, &temp, 1)? temp : -1);
+}
+#endif
+
+int
+wgetch(window) /* get character from specified window */
+WINDOW *window;
+{
+ int in_value;
+ char temp;
+#ifndef SYS5
+ int old_arg;
+#endif /* SYS5 */
+
+#ifdef BSD_SELECT
+ if (Noblock)
+ in_value = ((bufp > 0) ? in_buff[--bufp] : timed_getchar());
+ else
+ in_value = ((bufp > 0) ? in_buff[--bufp] : read(0, &temp, 1)? temp : -1);
+#else /* BSD_SELECT */
+#ifdef SYS5
+ in_value = ((bufp > 0) ? in_buff[--bufp] :
+ (read(0, &temp, 1)> 0) ? temp : -1);
+#else /* SYS5 */
+ if (Noblock)
+ {
+ Time_Out = FALSE;
+ old_arg = fcntl(0, F_GETFL, 0);
+ in_value = fcntl(0, F_SETFL, old_arg | FNDELAY);
+ }
+ in_value = ((bufp > 0) ? in_buff[--bufp] : read(0, &temp, 1)? temp : -1);
+ if (Noblock)
+ {
+ fcntl(0, F_SETFL, old_arg);
+ if (Time_Out)
+ in_value = -1;
+ }
+#endif /* SYS5 */
+#endif /* BSD_SELECT */
+
+ if (in_value != -1)
+ {
+ in_value &= 0xff;
+ if ((Parity) && (Num_bits < 8))
+ /* strip eighth bit if parity in use */
+ in_value &= 0177;
+ }
+ else if (interrupt_flag)
+ {
+ interrupt_flag = FALSE;
+ in_value = wgetch(window);
+ }
+
+ if ((in_value == '\033') || (in_value == '\037'))/* escape character */
+ in_value = Get_key(in_value);
+ return(in_value);
+}
+
+#ifndef BSD_SELECT
+void
+Clear(arg) /* notify that time out has occurred */
+int arg;
+{
+ Time_Out = TRUE;
+#ifdef DEBUG
+fprintf(stderr, "inside Clear()\n");
+fflush(stderr);
+#endif /* DEBUG */
+}
+#endif /* BSD_SELECT */
+
+int
+Get_key(first_char) /* try to decode key sequence */
+int first_char; /* first character of sequence */
+{
+ int in_char;
+ int Count;
+ char string[128];
+ char *Gtemp;
+ int Found;
+#ifdef SYS5
+ struct termio Gterminal;
+#else
+ struct sgttyb Gterminal;
+#endif
+ struct KEY_STACK *St_point;
+#if (!defined( BSD_SELECT)) || (!defined(SYS5))
+ int value;
+#endif /* BSD_SELECT */
+
+ Count = 0;
+ Gtemp = string;
+ string[Count++] = first_char;
+ string[Count] = '\0';
+ Time_Out = FALSE;
+#ifndef BSD_SELECT
+ signal(SIGALRM, Clear);
+ value = alarm(1);
+#endif /* BSD_SELECT */
+ Noblock = TRUE;
+#ifdef SYS5
+ Gterminal.c_cc[VTIME] = 0; /* timeout value */
+ Gterminal.c_lflag &= ~ICANON; /* disable canonical operation */
+ Gterminal.c_lflag &= ~ECHO; /* disable echo */
+#endif
+ Count = 1;
+ Found = FALSE;
+ while ((Count < Max_Key_len) && (!Time_Out) && (!Found))
+ {
+ in_char = wgetch(stdscr);
+#ifdef DEBUG
+fprintf(stderr, "back in GetKey()\n");
+fflush(stderr);
+#endif /* DEBUG */
+ if (in_char != -1)
+ {
+ string[Count++] = in_char;
+ string[Count] = '\0';
+ St_point = KEY_TOS;
+ while ((St_point != NULL) && (!Found))
+ {
+ if (!strcmp(string, St_point->element->string))
+ Found = TRUE;
+ else
+ St_point = St_point->next;
+ }
+ }
+ }
+#ifndef BSD_SELECT
+ if (!Time_Out)
+ value = alarm(0);
+#endif /* BSD_SELECT */
+#ifdef SYS5
+/* value = ioctl(0, TCSETA, &Terminal);*/
+#else
+ value = ioctl(0, TIOCSETP, &Terminal);
+/* value = fcntl(0, F_SETFL, old_arg);*/
+#endif
+ Noblock = FALSE;
+ if (Found)
+ {
+ return(St_point->element->value);
+ }
+ else
+ {
+ while (Count > 1)
+ {
+ if ((string[--Count] != -1) &&
+ ((unsigned char) (string[Count]) != 255))
+ {
+#ifdef DIAG
+fprintf(stderr, "ungetting character %d\n", string[Count]);fflush(stdout);
+#endif
+ ungetch(string[Count]);
+ }
+ }
+ return(first_char);
+ }
+}
+
+void
+waddch(window, c) /* output the character in the specified window */
+WINDOW *window;
+int c;
+{
+ int column, j;
+ int shift; /* number of spaces to shift if a tab */
+ struct _line *tmpline;
+
+#ifdef DIAG
+/*printf("starting waddch \n");fflush(stdout);*/
+#endif
+ column = window->LX;
+ if (c == '\t')
+ {
+ shift = (column + 1) % 8;
+ if (shift == 0)
+ shift++;
+ else
+ shift = 9 - shift;
+ while (shift > 0)
+ {
+ shift--;
+ waddch(window, ' ');
+ }
+ }
+ else if ((column < window->Num_cols) && (window->LY < window->Num_lines))
+ {
+ if ((c == '~') && (Booleans[hz__]))
+ c = '@';
+
+ if (( c != '\b') && (c != '\n') && (c != '\r'))
+ {
+ tmpline = window->line_array[window->LY];
+ tmpline->row[column] = c;
+ tmpline->attributes[column] = window->Attrib;
+ tmpline->changed = TRUE;
+ if (column >= tmpline->last_char)
+ {
+ if (column > tmpline->last_char)
+ for (j = tmpline->last_char; j < column; j++)
+ {
+ tmpline->row[j] = ' ';
+ tmpline->attributes[j] = '\0';
+ }
+ tmpline->row[column + 1] = '\0';
+ tmpline->attributes[column + 1] = '\0';
+ tmpline->last_char = column + 1;
+ }
+ }
+ if (c == '\n')
+ {
+ wclrtoeol(window);
+ window->LX = window->Num_cols;
+ }
+ else if (c == '\r')
+ window->LX = 0;
+ else if (c == '\b')
+ window->LX--;
+ else
+ window->LX++;
+ }
+ if (window->LX >= window->Num_cols)
+ {
+ window->LX = 0;
+ window->LY++;
+ if (window->LY >= window->Num_lines)
+ {
+ window->LY = window->Num_lines - 1;
+/* window->LY = row;
+ wmove(window, 0, 0);
+ wdeleteln(window);
+ wmove(window, row, 0);*/
+ }
+ }
+ window->SCROLL_CLEAR = CHANGE;
+}
+
+void
+winsertln(window) /* insert a blank line into the specified window */
+WINDOW *window;
+{
+ int row, column;
+ struct _line *tmp;
+ struct _line *tmp1;
+
+ window->scroll_down += 1;
+ window->SCROLL_CLEAR = SCROLL;
+ column = window->LX;
+ row = window->LY;
+ for (row = 0, tmp = window->first_line; (row < window->Num_lines) && (tmp->next_screen != NULL); row++)
+ tmp = tmp->next_screen;
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = NULL;
+ tmp1 = tmp;
+ clear_line(tmp1, 0, window->Num_cols);
+ tmp1->number = -1;
+ for (row = 0, tmp = window->first_line; (row < window->LY) && (tmp->next_screen != NULL); row++)
+ tmp = tmp->next_screen;
+ if ((window->LY == (window->Num_lines - 1)) && (window->Num_lines > 1))
+ {
+ tmp1->next_screen = tmp->next_screen;
+ tmp->next_screen = tmp1;
+ tmp->changed = TRUE;
+ tmp->next_screen->prev_screen = tmp;
+ }
+ else if (window->Num_lines > 1)
+ {
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = tmp1;
+ tmp1->prev_screen = tmp->prev_screen;
+ tmp->prev_screen = tmp1;
+ tmp1->next_screen = tmp;
+ tmp->changed = TRUE;
+ tmp->scroll = DOWN;
+ }
+ if (window->LY == 0)
+ window->first_line = tmp1;
+
+ for (row = 0, tmp1 = window->first_line;
+ row < window->Num_lines; row++)
+ {
+ window->line_array[row] = tmp1;
+ tmp1 = tmp1->next_screen;
+ }
+}
+
+void
+wdeleteln(window) /* delete a line in the specified window */
+WINDOW *window;
+{
+ int row, column;
+ struct _line *tmp;
+ struct _line *tmpline;
+
+ if (window->Num_lines > 1)
+ {
+ window->scroll_up += 1;
+ window->SCROLL_CLEAR = SCROLL;
+ column = window->LX;
+ row = window->LY;
+ for (row = 0, tmp = window->first_line; row < window->LY; row++)
+ tmp = tmp->next_screen;
+ if (window->LY == 0)
+ window->first_line = tmp->next_screen;
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = tmp->next_screen;
+ if (tmp->next_screen != NULL)
+ {
+ tmp->next_screen->changed = TRUE;
+ tmp->next_screen->scroll = UP;
+ tmp->next_screen->prev_screen = tmp->prev_screen;
+ }
+ tmpline = tmp;
+ clear_line(tmpline, 0, window->Num_cols);
+ tmpline->number = -1;
+ for (row = 0, tmp = window->first_line; tmp->next_screen != NULL; row++)
+ tmp = tmp->next_screen;
+ if (tmp != NULL)
+ {
+ tmp->next_screen = tmpline;
+ tmp->next_screen->prev_screen = tmp;
+ tmp->changed = TRUE;
+ tmp = tmp->next_screen;
+ }
+ else
+ tmp = tmpline;
+ tmp->next_screen = NULL;
+
+ for (row = 0, tmp = window->first_line; row < window->Num_lines; row++)
+ {
+ window->line_array[row] = tmp;
+ tmp = tmp->next_screen;
+ }
+ }
+ else
+ {
+ clear_line(window->first_line, 0, window->Num_cols);
+ }
+}
+
+void
+wclrtobot(window) /* delete from current position to end of the window */
+WINDOW *window;
+{
+ int row, column;
+ struct _line *tmp;
+
+ window->SCROLL_CLEAR |= CLEAR;
+ column = window->LX;
+ row = window->LY;
+ for (row = 0, tmp = window->first_line; row < window->LY; row++)
+ tmp = tmp->next_screen;
+ clear_line(tmp, column, window->Num_cols);
+ for (row = (window->LY + 1); row < window->Num_lines; row++)
+ {
+ tmp = tmp->next_screen;
+ clear_line(tmp, 0, window->Num_cols);
+ }
+ wmove(window, row, column);
+}
+
+void
+wstandout(window) /* begin standout mode in window */
+WINDOW *window;
+{
+ if (Numbers[sg__] < 1) /* if not magic cookie glitch */
+ window->Attrib |= A_STANDOUT;
+}
+
+void
+wstandend(window) /* end standout mode in window */
+WINDOW *window;
+{
+ window->Attrib &= ~A_STANDOUT;
+}
+
+void
+waddstr(window, string) /* write 'string' in window */
+WINDOW *window;
+char *string;
+{
+ char *wstring;
+
+ for (wstring = string; *wstring != '\0'; wstring++)
+ waddch(window, *wstring);
+}
+
+void
+clearok(window, flag) /* erase screen and redraw at next refresh */
+WINDOW *window;
+int flag;
+{
+ Repaint_screen = TRUE;
+}
+
+
+void
+echo() /* turn on echoing */
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_lflag |= ECHO; /* enable echo */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#else
+ Terminal.sg_flags |= ECHO; /* enable echo */
+ value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+noecho() /* turn off echoing */
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_lflag &= ~ECHO; /* disable echo */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#else
+ Terminal.sg_flags &= ~ECHO; /* disable echo */
+ value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+raw() /* set to read characters immediately */
+{
+ int value;
+
+#ifdef SYS5
+ Intr = Terminal.c_cc[VINTR]; /* get the interrupt character */
+ Terminal.c_lflag &= ~ICANON; /* disable canonical operation */
+ Terminal.c_lflag &= ~ISIG; /* disable signal checking */
+#ifdef FLUSHO
+ Terminal.c_lflag &= ~FLUSHO;
+#endif
+#ifdef PENDIN
+ Terminal.c_lflag &= ~PENDIN;
+#endif
+#ifdef IEXTEN
+ Terminal.c_lflag &= ~IEXTEN;
+#endif
+ Terminal.c_cc[VMIN] = 1; /* minimum of one character */
+ Terminal.c_cc[VTIME] = 0; /* timeout value */
+ Terminal.c_cc[VINTR] = 0; /* eliminate interrupt */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#else
+ Terminal.sg_flags |= RAW; /* enable raw mode */
+ value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+noraw() /* set to normal character read mode */
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_lflag |= ICANON; /* enable canonical operation */
+ Terminal.c_lflag |= ISIG; /* enable signal checking */
+ Terminal.c_cc[VEOF] = 4; /* EOF character = 4 */
+ Terminal.c_cc[VEOL] = '\0'; /* EOL = 0 */
+ Terminal.c_cc[VINTR] = Intr; /* reset interrupt char */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#else
+ Terminal.sg_flags &= ~RAW; /* disable raw mode */
+ value = ioctl(0, TIOCSETP, &Terminal); /* set characteristics */
+/* old_arg = fcntl(0, F_GETFL, 0);
+ value = fcntl(0, F_SETFL, old_arg & ~FNDELAY);*/
+#endif
+}
+
+void
+nl()
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_iflag |= ICRNL; /* enable carriage-return to line-feed mapping */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+nonl()
+{
+ int value;
+
+#ifdef SYS5
+ Terminal.c_iflag &= ~ICRNL; /* disable carriage-return to line-feed mapping */
+ Terminal.c_iflag &= ~IGNCR; /* do not ignore carriage-return */
+ value = ioctl(0, TCSETA, &Terminal); /* set characteristics */
+#endif
+}
+
+void
+saveterm()
+{
+}
+
+void
+fixterm()
+{
+}
+
+void
+resetterm()
+{
+}
+
+void
+nodelay(window, flag)
+WINDOW *window;
+int flag;
+{
+}
+
+void
+idlok(window, flag)
+WINDOW *window;
+int flag;
+{
+}
+
+void
+keypad(window, flag)
+WINDOW *window;
+int flag;
+{
+ if (flag)
+ String_Out(String_table[ks__], NULL, 0);
+ else
+ String_Out(String_table[ke__], NULL, 0);
+}
+
+void
+savetty() /* save current tty stats */
+{
+ int value;
+
+#ifdef SYS5
+ value = ioctl(0, TCGETA, &Saved_tty); /* set characteristics */
+#else
+ value = ioctl(0, TIOCGETP, &Saved_tty); /* set characteristics */
+#endif
+}
+
+void
+resetty() /* restore previous tty stats */
+{
+ int value;
+
+#ifdef SYS5
+ value = ioctl(0, TCSETA, &Saved_tty); /* set characteristics */
+#else
+ value = ioctl(0, TIOCSETP, &Saved_tty); /* set characteristics */
+#endif
+}
+
+void
+endwin() /* end windows */
+{
+ keypad(stdscr, FALSE);
+ initialized = FALSE;
+ delwin(curscr);
+ delwin(virtual_scr);
+ delwin(stdscr);
+#ifndef SYS5
+{
+ int old_arg, value;
+/* old_arg = fcntl(0, F_GETFL, 0);
+ value = fcntl(0, F_SETFL, old_arg & ~FNDELAY);*/
+}
+#endif
+}
+
+void
+delwin(window) /* delete the window structure */
+WINDOW *window;
+{
+ int i;
+
+ for (i = 1; (i < window->Num_lines) && (window->first_line->next_screen != NULL); i++)
+ {
+ window->first_line = window->first_line->next_screen;
+ free(window->first_line->prev_screen->row);
+ free(window->first_line->prev_screen->attributes);
+ free(window->first_line->prev_screen);
+ }
+ if (window == last_window_refreshed)
+ last_window_refreshed = 0;
+ if (window->first_line != NULL)
+ {
+ free(window->first_line->row);
+ free(window->first_line->attributes);
+ free(window->first_line);
+ free(window);
+ }
+}
+
+#ifndef __STDC__
+void
+wprintw(va_alist)
+va_dcl
+#else /* __STDC__ */
+void
+wprintw(WINDOW *window, const char *format, ...)
+#endif /* __STDC__ */
+{
+#ifndef __STDC__
+ WINDOW *window;
+ char *format;
+ va_list ap;
+#else
+ va_list ap;
+#endif
+ int value;
+ char *fpoint;
+ char *wtemp;
+
+#ifndef __STDC__
+ va_start(ap);
+ window = va_arg(ap, WINDOW *);
+ format = va_arg(ap, char *);
+#else /* __STDC__ */
+ va_start(ap, format);
+#endif /* __STDC__ */
+
+ fpoint = (char *) format;
+ while (*fpoint != '\0')
+ {
+ if (*fpoint == '%')
+ {
+ fpoint++;
+ if (*fpoint == 'd')
+ {
+ value = va_arg(ap, int);
+ iout(window, value);
+ }
+ else if (*fpoint == 'c')
+ {
+ value = va_arg(ap, int);
+ waddch(window, value);
+ }
+ else if (*fpoint == 's')
+ {
+ wtemp = va_arg(ap, char *);
+ waddstr(window, wtemp);
+ }
+ fpoint++;
+ }
+ else if (*fpoint == '\\')
+ {
+ fpoint++;
+ if (*fpoint == 'n')
+ waddch(window, '\n');
+ else if ((*fpoint >= '0') && (*fpoint <= '9'))
+ {
+ value = 0;
+ while ((*fpoint >= '0') && (*fpoint <= '9'))
+ {
+ value = (value * 8) + (*fpoint - '0');
+ fpoint++;
+ }
+ waddch(window, value);
+ }
+ fpoint++;
+ }
+ else
+ waddch(window, *fpoint++);
+ }
+#ifdef __STDC__
+ va_end(ap);
+#endif /* __STDC__ */
+}
+
+void
+iout(window, value) /* output characters */
+WINDOW *window;
+int value;
+{
+ int i;
+
+ if ((i = value / 10) != 0)
+ iout(window, i);
+ waddch(window, ((value % 10) + '0'));
+}
+
+int
+Comp_line(line1, line2) /* compare lines */
+struct _line *line1;
+struct _line *line2;
+{
+ int count1;
+ int i;
+ char *att1, *att2;
+ char *c1, *c2;
+
+ if (line1->last_char != line2->last_char)
+ return(2);
+
+ c1 = line1->row;
+ c2 = line2->row;
+ att1 = line1->attributes;
+ att2 = line2->attributes;
+ i = 0;
+ while ((c1[i] != '\0') && (c2[i] != '\0') && (c1[i] == c2[i]) && (att1[i] == att2[i]))
+ i++;
+ count1 = i + 1;
+ if ((count1 == 1) && (c1[i] == '\0') && (c2[i] == '\0'))
+ count1 = 0; /* both lines blank */
+ else if ((c1[i] == '\0') && (c2[i] == '\0'))
+ count1 = -1; /* equal */
+ else
+ count1 = 1; /* lines unequal */
+ return(count1);
+}
+
+struct _line *
+Insert_line(row, end_row, window) /* insert line into screen */
+int row;
+int end_row;
+WINDOW *window;
+{
+ int i;
+ struct _line *tmp;
+ struct _line *tmp1;
+
+ for (i = 0, tmp = curscr->first_line; i < window->SR; i++)
+ tmp = tmp->next_screen;
+ if ((end_row + window->SR) == 0)
+ curscr->first_line = curscr->first_line->next_screen;
+ top_of_win = tmp;
+ /*
+ | find bottom line to delete
+ */
+ for (i = 0, tmp = top_of_win; (tmp->next_screen != NULL) && (i < end_row); i++)
+ tmp = tmp->next_screen;
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = tmp->next_screen;
+ if (tmp->next_screen != NULL)
+ tmp->next_screen->prev_screen = tmp->prev_screen;
+ tmp1 = tmp;
+ /*
+ | clear deleted line
+ */
+ clear_line(tmp, 0, window->Num_cols);
+ tmp1->number = -1;
+ for (i = 0, tmp = curscr->first_line; (tmp->next_screen != NULL) && (i < window->SR); i++)
+ tmp = tmp->next_screen;
+ top_of_win = tmp;
+ for (i = 0, tmp = top_of_win; i < row; i++)
+ tmp = tmp->next_screen;
+ if ((tmp->prev_screen != NULL) && (window->Num_lines > 0))
+ tmp->prev_screen->next_screen = tmp1;
+ tmp1->prev_screen = tmp->prev_screen;
+ tmp->prev_screen = tmp1;
+ tmp1->next_screen = tmp;
+ if ((row + window->SR) == 0)
+ curscr->first_line = tmp1;
+ if (tmp1->next_screen != NULL)
+ tmp1 = tmp1->next_screen;
+
+ if ((!String_table[cs__]) && (end_row < window->Num_lines))
+ {
+ Position(window, (window->SR + end_row), 0);
+ String_Out(String_table[dl__], NULL, 0);
+ }
+ Position(window, (window->SR + row), 0);
+ if (String_table[al__] != NULL)
+ String_Out(String_table[al__], NULL, 0);
+ else
+ String_Out(String_table[sr__], NULL, 0);
+
+ for (i = 0, top_of_win = curscr->first_line; (top_of_win->next_screen != NULL) && (i < window->SR); i++)
+ top_of_win = top_of_win->next_screen;
+ return(tmp1);
+}
+
+
+struct _line *
+Delete_line(row, end_row, window) /* delete a line on screen */
+int row;
+int end_row;
+WINDOW *window;
+{
+ int i;
+ struct _line *tmp;
+ struct _line *tmp1;
+ struct _line *tmp2;
+
+ i = 0;
+ tmp = curscr->first_line;
+ while (i < window->SR)
+ {
+ i++;
+ tmp = tmp->next_screen;
+ }
+ /*
+ | find line to delete
+ */
+ top_of_win = tmp;
+ if ((row + window->SR) == 0)
+ curscr->first_line = top_of_win->next_screen;
+ for (i = 0, tmp = top_of_win; i < row; i++)
+ tmp = tmp->next_screen;
+ if (tmp->prev_screen != NULL)
+ tmp->prev_screen->next_screen = tmp->next_screen;
+ if (tmp->next_screen != NULL)
+ tmp->next_screen->prev_screen = tmp->prev_screen;
+ tmp2 = tmp->next_screen;
+ tmp1 = tmp;
+ /*
+ | clear deleted line
+ */
+ clear_line(tmp1, 0, window->Num_cols);
+ tmp1->number = -1;
+ /*
+ | find location to insert deleted line
+ */
+ for (i = 0, tmp = curscr->first_line; (tmp->next_screen != NULL) && (i < window->SR); i++)
+ tmp = tmp->next_screen;
+ top_of_win = tmp;
+ for (i = 0, tmp = top_of_win; (i < end_row) && (tmp->next_screen != NULL); i++)
+ tmp = tmp->next_screen;
+ tmp1->next_screen = tmp;
+ tmp1->prev_screen = tmp->prev_screen;
+ if (tmp1->prev_screen != NULL)
+ tmp1->prev_screen->next_screen = tmp1;
+ tmp->prev_screen = tmp1;
+
+ Position(window, (window->SR + row), 0);
+ String_Out(String_table[dl__], NULL, 0);
+ if ((!String_table[cs__]) && (end_row < window->Num_lines))
+ {
+ Position(window, (window->SR + end_row), 0);
+ String_Out(String_table[al__], NULL, 0);
+ }
+ else if ((String_table[cs__] != NULL) && (String_table[dl__] == NULL))
+ {
+ Position(window, (window->SR + end_row), 0);
+ putchar('\n');
+ }
+
+ if (row == (window->Num_lines-1))
+ tmp2 = tmp1;
+ if ((row + window->SR) == 0)
+ curscr->first_line = top_of_win = tmp2;
+ return(tmp2);
+}
+
+void
+CLEAR_TO_EOL(window, row, column)
+WINDOW *window;
+int row, column;
+{
+ int x, y;
+ struct _line *tmp1;
+
+ for (y = 0, tmp1 = curscr->first_line; (y < (window->SR+row)) && (tmp1->next_screen != NULL); y++)
+ tmp1 = tmp1->next_screen;
+ for (x = column; x<window->Num_cols; x++)
+ {
+ tmp1->row[x] = ' ';
+ tmp1->attributes[x] = '\0';
+ }
+ tmp1->row[column] = '\0';
+ tmp1->last_char = column;
+ if (column < COLS)
+ {
+ if (STAND)
+ {
+ STAND = FALSE;
+ Position(window, row, column);
+ attribute_off();
+ }
+ if (String_table[ce__] != NULL)
+ String_Out(String_table[ce__], NULL, 0);
+ else
+ {
+ for (x = column; x < window->Num_cols; x++)
+ putchar(' ');
+ Curr_x = x;
+ }
+ }
+}
+
+int
+check_delete(window, line, offset, pointer_new, pointer_old)
+WINDOW *window;
+int line, offset;
+struct _line *pointer_new, *pointer_old;
+{
+ int end_old;
+ int end_new;
+ int k;
+ int changed;
+ char *old_lin;
+ char *new_lin;
+ char *old_att;
+ char *new_att;
+
+ changed = FALSE;
+ new_lin = pointer_new->row;
+ new_att = pointer_new->attributes;
+ old_lin = pointer_old->row;
+ old_att = pointer_old->attributes;
+ end_old = end_new = offset;
+ while (((new_lin[end_new] != old_lin[end_old]) || (new_att[end_new] != old_att[end_old])) && (old_lin[end_old] != '\0') && (new_lin[end_old] != '\0'))
+ end_old++;
+ if (old_lin[end_old] != '\0')
+ {
+ k = 0;
+ while ((old_lin[end_old+k] == new_lin[end_new+k]) && (new_att[end_new+k] == old_att[end_old+k]) && (new_lin[end_new+k] != '\0') && (old_lin[end_old+k] != '\0') && (k < 10))
+ k++;
+ if ((k > 8) || ((new_lin[end_new+k] == '\0') && (k != 0)))
+ {
+ if (new_lin[end_new+k] == '\0')
+ {
+ Position(window, line, (end_new+k));
+ CLEAR_TO_EOL(window, line, (end_new+k));
+ }
+ Position(window, line, offset);
+ for (k = offset; k < end_old; k++)
+ Char_del(old_lin, old_att, offset, window->Num_cols);
+ while ((old_lin[offset] != '\0') && (offset < COLS))
+ offset++;
+ pointer_old->last_char = offset;
+ changed = TRUE;
+ }
+ }
+ return(changed);
+}
+
+/*
+ | Check if characters were inserted in the middle of a line, and if
+ | so, insert them.
+ */
+
+int
+check_insert(window, line, offset, pointer_new, pointer_old)
+WINDOW *window;
+int line, offset;
+struct _line *pointer_new, *pointer_old;
+{
+ int changed;
+ int end_old, end_new;
+ int k;
+ int same = FALSE;
+ int old_off;
+ int insert;
+ char *old_lin;
+ char *new_lin;
+ char *old_att;
+ char *new_att;
+
+ changed = FALSE;
+ new_lin = pointer_new->row;
+ new_att = pointer_new->attributes;
+ old_lin = pointer_old->row;
+ old_att = pointer_old->attributes;
+ end_old = end_new = offset;
+ while (((new_lin[end_new] != old_lin[end_old]) || (new_att[end_new] != old_att[end_old])) && (new_lin[end_new] != '\0') && (old_lin[end_new] != '\0'))
+ end_new++;
+ if (new_lin[end_new] != '\0')
+ {
+ k = 0;
+ while ((old_lin[end_old+k] == new_lin[end_new+k]) && (old_att[end_old+k] == new_att[end_new+k]) && (new_lin[end_new+k] != '\0') && (old_lin[end_old+k] != '\0') && (k < 10))
+ k++;
+ /*
+ | check for commonality between rest of lines (are the old
+ | and new lines the same, except for a chunk in the middle?)
+ | if the rest of the lines are common, do not insert text
+ */
+ old_off = end_new;
+ while ((old_lin[old_off] != '\0') && (new_lin[old_off] != '\0') && (old_lin[old_off] == new_lin[old_off]) && (old_att[old_off] == new_att[old_off]))
+ old_off++;
+ if ((old_lin[old_off] == new_lin[old_off]) && (old_att[old_off] == new_att[old_off]))
+ same = TRUE;
+ if ((!same) && ((k > 8) || ((new_lin[end_new+k] == '\0') && (k != 0))))
+ {
+ Position(window, line, offset);
+ insert = FALSE;
+ if (String_table[ic__] == NULL)
+ {
+ String_Out(String_table[im__], NULL, 0);
+ insert = TRUE;
+ }
+ for (k = offset; k < end_new; k++)
+ {
+ if (!insert)
+ String_Out(String_table[ic__], NULL, 0);
+ Char_ins(old_lin, old_att, new_lin[k], new_att[k], k, window->Num_cols);
+ }
+ if (insert)
+ String_Out(String_table[ei__], NULL, 0);
+ while ((old_lin[offset] != '\0') && (offset < COLS))
+ offset++;
+ pointer_old->last_char = offset;
+ changed = TRUE;
+ }
+ }
+ return(changed);
+}
+
+void
+doupdate()
+{
+ WINDOW *window;
+ int similar;
+ int diff;
+ int begin_old, begin_new;
+ int end_old, end_new;
+ int count1, j;
+ int from_top, tmp_ft, offset;
+ int changed;
+ int first_time;
+ int first_same;
+ int last_same;
+ int list[10];
+ int bottom;
+
+ struct _line *curr;
+ struct _line *virt;
+ struct _line *old;
+
+ struct _line *new;
+
+ struct _line *old1, *new1;
+
+ char *cur_lin;
+ char *vrt_lin;
+ char *cur_att;
+ char *vrt_att;
+ char *att1, *att2;
+ char *c1, *c2;
+
+ char NC_chinese = FALSE; /* flag to indicate handling Chinese */
+
+ window = virtual_scr;
+
+ if ((nc_attributes & A_NC_BIG5) != 0)
+ NC_chinese = TRUE;
+
+ if (Repaint_screen)
+ {
+ if (String_table[cl__])
+ String_Out(String_table[cl__], NULL, 0);
+ else
+ {
+ from_top = 0;
+ while (from_top < LINES)
+ {
+ Position(curscr, from_top, 0);
+ if (String_table[ce__] != NULL)
+ String_Out(String_table[ce__], NULL, 0);
+ else
+ {
+ for (j = 0; j < window->Num_cols; j++)
+ putchar(' ');
+ }
+ from_top++;
+ }
+ }
+ for (from_top = 0, curr = curscr->first_line; from_top < curscr->Num_lines; from_top++, curr = curr->next_screen)
+ {
+ Position(curscr, from_top, 0);
+ for (j = 0; (curr->row[j] != '\0') && (j < curscr->Num_cols); j++)
+ {
+ Char_out(curr->row[j], curr->attributes[j], curr->row, curr->attributes, j);
+ }
+ if (STAND)
+ {
+ STAND = FALSE;
+ Position(curscr, from_top, j);
+ attribute_off();
+ }
+ }
+ Repaint_screen = FALSE;
+ }
+
+ similar = 0;
+ diff = FALSE;
+ top_of_win = curscr->first_line;
+
+ for (from_top = 0, curr = top_of_win, virt = window->first_line;
+ from_top < window->Num_lines; from_top++)
+ {
+ virtual_lines[from_top] = TRUE;
+ if ((similar = Comp_line(curr, virt)) > 0)
+ {
+ virtual_lines[from_top] = FALSE;
+ diff = TRUE;
+ }
+ curr = curr->next_screen;
+ virt = virt->next_screen;
+ }
+
+ from_top = 0;
+ virt = window->first_line;
+ curr = top_of_win;
+ similar = 0;
+ /*
+ | if the window has lines that are different, check for scrolling
+ */
+ if (diff)
+ {
+ last_same = -1;
+ changed = FALSE;
+ for (first_same = window->Num_lines;
+ (first_same > from_top) && (virtual_lines[first_same - 1]);
+ first_same--)
+ ;
+ for (last_same = 0;
+ (last_same < window->Num_lines) && (virtual_lines[last_same]== FALSE);
+ last_same++)
+ ;
+ while ((from_top < first_same) && nc_scrolling_ability)
+ /* check entire lines for diffs */
+ {
+
+ if (from_top >= last_same)
+ {
+ for (last_same = from_top;
+ (last_same < window->Num_lines) &&
+ (virtual_lines[last_same] == FALSE);
+ last_same++)
+ ;
+ }
+ if (!virtual_lines[from_top])
+ {
+ diff = TRUE;
+ /*
+ | check for lines deleted (scroll up)
+ */
+ for (tmp_ft = from_top+1, old = curr->next_screen;
+ ((window->scroll_up) && (diff) &&
+ (tmp_ft < last_same) &&
+ (!virtual_lines[tmp_ft]));
+ tmp_ft++)
+ {
+ if ((Comp_line(old, virt) == -1) && (!virtual_lines[from_top]))
+ {
+ /*
+ | Find the bottom of the
+ | area that should be
+ | scrolled.
+ */
+ for (bottom = tmp_ft, old1 = old,
+ new1 = virt, count1 = 0;
+ (bottom < window->Num_lines) &&
+ (Comp_line(old1, new1) <= 0);
+ bottom++, old1 = old1->next_screen,
+ new1 = new1->next_screen,
+ count1++)
+ ;
+ if (count1 > 3)
+ {
+ if (String_table[cs__]) /* scrolling region */
+ {
+ list[1] = from_top;
+ list[0] = min((bottom - 1), (window->Num_lines - 1));
+ String_Out(String_table[cs__], list, 2);
+ Curr_y = Curr_x = -1;
+ }
+
+ for (offset = (tmp_ft - from_top); (offset > 0); offset--)
+ {
+ old = Delete_line(from_top, min((bottom - 1), (window->Num_lines - 1)), window);
+ diff = FALSE;
+ }
+
+ if (String_table[cs__]) /* scrolling region */
+ {
+ list[1] = 0;
+ list[0] = LINES - 1;
+ String_Out(String_table[cs__], list, 2);
+ Curr_y = Curr_x = -1;
+ }
+
+ top_of_win = curscr->first_line;
+ curr = top_of_win;
+ for (offset = 0; offset < from_top; offset++)
+ curr = curr->next_screen;
+ for (offset = from_top, old=curr, new=virt;
+ offset < window->Num_lines;
+ old=old->next_screen, new=new->next_screen,
+ offset++)
+ {
+ similar = Comp_line(old, new);
+ virtual_lines[offset] = (similar > 0 ? FALSE : TRUE);
+ }
+ }
+ }
+ else
+ old = old->next_screen;
+ }
+ /*
+ | check for lines inserted (scroll down)
+ */
+ for (tmp_ft = from_top-1, old = curr->prev_screen;
+ ((window->scroll_down) && (tmp_ft >= 0) &&
+ (diff) &&
+ (!virtual_lines[tmp_ft]));
+ tmp_ft--)
+ {
+ if (Comp_line(old, virt) == -1)
+ {
+ /*
+ | Find the bottom of the
+ | area that should be
+ | scrolled.
+ */
+ for (bottom = from_top, old1 = old,
+ new1 = virt, count1 = 0;
+ (bottom < window->Num_lines) &&
+ (Comp_line(old1, new1) <= 0);
+ bottom++, old1 = old1->next_screen,
+ new1 = new1->next_screen,
+ count1++)
+ ;
+ if (count1 > 3)
+ {
+ if (String_table[cs__]) /* scrolling region */
+ {
+ list[1] = tmp_ft;
+ list[0] = min((bottom - 1), (window->Num_lines - 1));
+ String_Out(String_table[cs__], list, 2);
+ Curr_y = Curr_x = -1;
+ }
+
+ for (offset = (from_top - tmp_ft); (offset > 0); offset--)
+ {
+ old = Insert_line(tmp_ft, min((bottom - 1), (window->Num_lines -1)), window);
+ diff = FALSE;
+ }
+
+ if (String_table[cs__]) /* scrolling region */
+ {
+ list[1] = 0;
+ list[0] = LINES - 1;
+ String_Out(String_table[cs__], list, 2);
+ Curr_y = Curr_x = -1;
+ }
+
+ top_of_win = curscr->first_line;
+ curr = top_of_win;
+ for (offset = 0; offset < from_top; offset++)
+ curr = curr->next_screen;
+ for (offset = from_top, old=curr, new=virt;
+ offset < window->Num_lines;
+ old=old->next_screen, new=new->next_screen,
+ offset++)
+ {
+ similar = Comp_line(old, new);
+ virtual_lines[offset] = (similar > 0 ? FALSE : TRUE);
+ }
+ }
+ }
+ else
+ old = old->prev_screen;
+ }
+ }
+ from_top++;
+ curr = curr->next_screen;
+ virt = virt->next_screen;
+ }
+ }
+
+
+ /*
+ | Scrolling done, now need to insert, delete, or modify text
+ | within lines.
+ */
+
+ for (from_top = 0, curr = curscr->first_line; from_top < window->SR; from_top++)
+ curr = curr->next_screen;
+ top_of_win = curr;
+ for (from_top = 0, curr = top_of_win, virt = window->first_line; from_top < window->Num_lines; from_top++, curr = curr->next_screen, virt = virt->next_screen)
+ {
+
+ /*
+ | If either 'insert mode' or 'insert char' are
+ | available, enter the following 'if' statement,
+ | else, need to simply rewrite the contents of the line
+ | at the point where the contents of the line change.
+ */
+
+ if (((String_table[ic__]) || (String_table[im__])) &&
+ (String_table[dc__]) && (curr->row[0] != '\0') &&
+ (!NC_chinese))
+ {
+ j = 0;
+ first_time = TRUE;
+ vrt_lin = virt->row;
+ vrt_att = virt->attributes;
+ cur_lin = curr->row;
+ cur_att = curr->attributes;
+ while ((vrt_lin[j] != '\0') && (j < window->Num_cols))
+ {
+ if ((STAND) && (Booleans[xs__]))
+ {
+ while ((vrt_lin[j] == cur_lin[j]) && (vrt_att[j] == cur_att[j]) && (vrt_lin[j] != '\0') && (vrt_att[j]))
+ j++;
+ if ((STAND) && (!vrt_att[j]))
+ {
+ STAND = FALSE;
+ Position(window, from_top, j);
+ attribute_off();
+ attribute_off();
+ }
+ }
+ else
+ {
+ while ((vrt_lin[j] == cur_lin[j]) && (vrt_att[j] == cur_att[j]) && (vrt_lin[j] != '\0'))
+ j++;
+ }
+ if ((vrt_att[j] != cur_att[j]) && (cur_att[j]) && (Booleans[xs__]))
+ {
+ Position(window, from_top, j);
+/* CLEAR_TO_EOL(window, from_top, j);*/
+ attribute_off();
+ attribute_off();
+ }
+ if (vrt_lin[j] != '\0')
+ {
+ begin_new = j;
+ begin_old = j;
+ end_old = j;
+ end_new = j;
+ if ((first_time) && (virt->changed))
+ {
+ if (curr->last_char <= virt->last_char)
+ changed = check_insert(window, from_top, j, virt, curr);
+ }
+ changed = check_delete(window, from_top, j, virt, curr);
+ first_time = FALSE;
+ virt->changed = FALSE;
+ if (!changed)
+ changed = check_insert(window, from_top, j, virt, curr);
+ if (((!changed) || (cur_lin[j] != vrt_lin[j]) || (cur_att[j] != vrt_att[j])) && (j < window->Num_cols))
+ {
+ if ((vrt_lin[j] == ' ') && (cur_lin[j] == '\0') && (vrt_att[j] == cur_att[j]))
+ cur_lin[j] = ' ';
+ else
+ {
+ Position(window, from_top, j);
+ Char_out(vrt_lin[j], vrt_att[j], cur_lin, cur_att, j);
+ }
+ }
+ if ((vrt_lin[j] != '\0'))
+ j++;
+ }
+ if ((STAND) && (!vrt_att[j]))
+ {
+ STAND = FALSE;
+ Position(window, from_top, j);
+ attribute_off();
+ }
+ }
+ if ((vrt_lin[j] == '\0') && (cur_lin[j] != '\0'))
+ {
+ Position(window, from_top, j);
+ CLEAR_TO_EOL(window, from_top, j);
+ }
+ }
+ else /*if ((similar != -1) && (similar != 0))*/
+ {
+ j = 0;
+ c1 = curr->row;
+ att1 = curr->attributes;
+ c2 = virt->row;
+ att2 = virt->attributes;
+ while ((j < window->Num_cols) && (c2[j] != '\0'))
+ {
+ while ((c1[j] == c2[j]) && (att1[j] == att2[j]) && (j < window->Num_cols) && (c2[j] != '\0'))
+ j++;
+
+ /*
+ | if previous character is an eight bit
+ | char, start redraw from that character
+ */
+
+ if ((NC_chinese) && (highbitset(c1[j - 1])))
+ j--;
+ begin_old = j;
+ begin_new = j;
+ if ((j < window->Num_cols) && (c2[j] != '\0'))
+ {
+ Position(window, from_top, begin_old);
+ CLEAR_TO_EOL(window, from_top, j);
+ Position(window, from_top, begin_old);
+ for (j = begin_old; (c2[j] != '\0') && (j < window->Num_cols); j++)
+ Char_out(c2[j], att2[j], c1, att1, j);
+ }
+ }
+ if ((c2[j] == '\0') && (c1[j] != '\0'))
+ {
+ Position(window, from_top, j);
+ CLEAR_TO_EOL(window, from_top, j);
+ }
+ }
+ if (STAND)
+ {
+ STAND = FALSE;
+ Position(window, from_top, j);
+ attribute_off();
+ }
+ virt->number = from_top;
+ }
+ Position(window, window->LY, window->LX);
+}
+
+void
+Position(window, row, col) /* position the cursor for output on the screen */
+WINDOW *window;
+int row;
+int col;
+{
+ int list[10];
+ int place;
+
+ int pos_row;
+ int pos_column;
+
+ pos_row = row + window->SR;
+ pos_column = col + window->SC;
+ if ((pos_row != Curr_y) || (pos_column != Curr_x))
+ {
+ if (String_table[cm__] != NULL) /* && (row < window->Num_lines) && (column < window->Num_cols))*/
+ {
+ place = 0;
+ list[place++] = pos_column;
+ list[place++] = pos_row;
+ String_Out(String_table[cm__], list, place);
+ if ((STAND) && (!Booleans[ms__]))
+ attribute_on();
+ }
+ Curr_x = pos_column;
+ Curr_y = pos_row;
+ }
+}
+
+void
+Char_del(line, attrib, offset, maxlen) /* delete chars from line */
+char *line;
+char *attrib;
+int offset;
+int maxlen;
+{
+ int one, two;
+
+ for (one = offset, two = offset+1; (line[one] != '\0') && (one < maxlen); one++, two++)
+ {
+ line[one] = line[two];
+ attrib[one] = attrib[two];
+ }
+ String_Out(String_table[dc__], NULL, 0);
+}
+
+void
+Char_ins(line, attrib, newc, newatt, offset, maxlen) /* insert chars in line */
+char *line;
+char *attrib;
+char newc;
+char newatt;
+int offset;
+int maxlen;
+{
+ int one, two;
+
+ one = 0;
+ while ((line[one] != '\0') && (one < (maxlen - 2)))
+ one++;
+ for (two = one + 1; (two > offset); one--, two--)
+ {
+ line[two] = line[one];
+ attrib[two] = attrib[one];
+ }
+ line[offset] = newc;
+ attrib[offset] = newatt;
+ Char_out(newc, newatt, line, attrib, offset);
+}
+
+void
+attribute_on()
+{
+ if (String_table[sa__])
+ {
+ attributes_set[0] = 1;
+ String_Out(String_table[sa__], attributes_set, 1);
+ }
+ else if (String_table[so__])
+ String_Out(String_table[so__], NULL, 0);
+}
+
+void
+attribute_off()
+{
+ if (String_table[me__])
+ String_Out(String_table[me__], NULL, 0);
+ else if (String_table[sa__])
+ {
+ attributes_set[0] = 0;
+ String_Out(String_table[sa__], attributes_set, 1);
+ }
+ else if (String_table[se__])
+ String_Out(String_table[se__], NULL, 0);
+}
+
+void
+Char_out(newc, newatt, line, attrib, offset) /* output character with proper attribute */
+char newc;
+char newatt;
+char *line;
+char *attrib;
+int offset;
+{
+
+
+ if ((newatt) && (!STAND))
+ {
+ STAND = TRUE;
+ attribute_on();
+ }
+ else if ((STAND) && (!newatt))
+ {
+ STAND = FALSE;
+ attribute_off();
+ }
+
+ if ((newatt) && (STAND) && (Booleans[xs__]))
+ {
+ attribute_on();
+ }
+
+ if (!((Curr_y >= (LINES - 1)) && (Curr_x >= (COLS - 1))))
+ {
+ putchar(newc);
+ line[offset] = newc;
+ attrib[offset] = newatt;
+ }
+ Curr_x++;
+}
+
+/*
+ |
+ | The two routines that follow, nc_setattrib(), nc_clearattrib(), are
+ | hacks that notify new_curse to handle characters that have the high
+ | bit set as the first of two bytes of a multi-byte string.
+ |
+ */
+
+void
+nc_setattrib(flag)
+int flag;
+{
+ nc_attributes |= flag;
+}
+
+void
+nc_clearattrib(flag)
+int flag;
+{
+ nc_attributes &= ~flag;
+}
+
diff --git a/text_cmds/ee/new_curse.h b/text_cmds/ee/new_curse.h
new file mode 100644
index 0000000..db538bb
--- /dev/null
+++ b/text_cmds/ee/new_curse.h
@@ -0,0 +1,260 @@
+/*
+ | new_curse.h
+ |
+ | A subset of curses developed for use with ae.
+ |
+ | written by Hugh Mahon
+ |
+ | THIS MATERIAL IS PROVIDED "AS IS". THERE ARE
+ | NO WARRANTIES OF ANY KIND WITH REGARD TO THIS
+ | MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE
+ | IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ | FITNESS FOR A PARTICULAR PURPOSE. Neither
+ | Hewlett-Packard nor Hugh Mahon shall be liable
+ | for errors contained herein, nor for
+ | incidental or consequential damages in
+ | connection with the furnishing, performance or
+ | use of this material. Neither Hewlett-Packard
+ | nor Hugh Mahon assumes any responsibility for
+ | the use or reliability of this software or
+ | documentation. This software and
+ | documentation is totally UNSUPPORTED. There
+ | is no support contract available. Hewlett-
+ | Packard has done NO Quality Assurance on ANY
+ | of the program or documentation. You may find
+ | the quality of the materials inferior to
+ | supported materials.
+ |
+ | This software is not a product of Hewlett-Packard, Co., or any
+ | other company. No support is implied or offered with this software.
+ | You've got the source, and you're on your own.
+ |
+ | This software may be distributed under the terms of Larry Wall's
+ | Artistic license, a copy of which is included in this distribution.
+ |
+ | This notice must be included with this software and any derivatives.
+ |
+ | Copyright (c) 1986, 1987, 1988, 1991, 1995 Hugh Mahon
+ | All are rights reserved.
+ |
+ */
+
+#include <stdio.h>
+
+#ifdef SYS5
+#include <termio.h>
+#else
+#include <sgtty.h>
+#include <fcntl.h>
+#endif
+
+#define KEY_BREAK 0401
+#define KEY_DOWN 0402
+#define KEY_UP 0403
+#define KEY_LEFT 0404
+#define KEY_RIGHT 0405
+#define KEY_HOME 0406
+#define KEY_BACKSPACE 0407
+#define KEY_F0 0410
+#define KEY_F(n) (KEY_F0+(n))
+#define KEY_DL 0510
+#define KEY_IL 0511
+#define KEY_DC 0512
+#define KEY_IC 0513
+#define KEY_EIC 0514
+#define KEY_CLEAR 0515
+#define KEY_EOS 0516
+#define KEY_EOL 0517
+#define KEY_SF 0520
+#define KEY_SR 0521
+#define KEY_NPAGE 0522
+#define KEY_PPAGE 0523
+#define KEY_STAB 0524
+#define KEY_CTAB 0525
+#define KEY_CATAB 0526
+#define KEY_ENTER 0527
+#define KEY_SRESET 0530
+#define KEY_RESET 0531
+#define KEY_PRINT 0532
+#define KEY_LL 0533
+#define KEY_A1 0534
+#define KEY_A3 0535
+#define KEY_B2 0536
+#define KEY_C1 0537
+#define KEY_C3 0540
+#define KEY_BTAB 0541
+#define KEY_BEG 0542
+#define KEY_CANCEL 0543
+#define KEY_CLOSE 0544
+#define KEY_COMMAND 0545
+#define KEY_COPY 0546
+#define KEY_CREATE 0547
+#define KEY_END 0550
+#define KEY_EXIT 0551
+#define KEY_FIND 0552
+#define KEY_HELP 0553
+#define KEY_MARK 0554
+#define KEY_MESSAGE 0555
+#define KEY_MOVE 0556
+#define KEY_NEXT 0557
+#define KEY_OPEN 0560
+#define KEY_OPTIONS 0561
+#define KEY_PREVIOUS 0562
+#define KEY_REDO 0563
+#define KEY_REFERENCE 0564
+#define KEY_REFRESH 0565
+#define KEY_REPLACE 0566
+#define KEY_RESTART 0567
+#define KEY_RESUME 0570
+#define KEY_SAVE 0571
+#define KEY_SBEG 0572
+#define KEY_SCANCEL 0573
+#define KEY_SCOMMAND 0574
+#define KEY_SCOPY 0575
+#define KEY_SCREATE 0576
+#define KEY_SDC 0577
+#define KEY_SDL 0600
+#define KEY_SELECT 0601
+#define KEY_SEND 0602
+#define KEY_SEOL 0603
+#define KEY_SEXIT 0604
+#define KEY_SFIND 0605
+#define KEY_SHELP 0606
+#define KEY_SHOME 0607
+#define KEY_SIC 0610
+#define KEY_SLEFT 0611
+#define KEY_SMESSAGE 0612
+#define KEY_SMOVE 0613
+#define KEY_SNEXT 0614
+#define KEY_SOPTIONS 0615
+#define KEY_SPREVIOUS 0616
+#define KEY_SPRINT 0617
+#define KEY_SREDO 0620
+#define KEY_SREPLACE 0621
+#define KEY_SRIGHT 0622
+#define KEY_SRSUME 0623
+#define KEY_SSAVE 0624
+#define KEY_SSUSPEND 0625
+#define KEY_SUNDO 0626
+#define KEY_SUSPEND 0627
+#define KEY_UNDO 0630
+
+#define TRUE 1
+#define FALSE 0
+
+#define A_STANDOUT 0001 /* standout mode */
+#define A_NC_BIG5 0x0100 /* Handle Chinese Big5 characters */
+#define SCROLL 1 /* text has been scrolled */
+#define CLEAR 2 /* window has been cleared */
+#define CHANGE 3 /* window has been changed */
+#define UP 1 /* direction of scroll */
+#define DOWN 2
+
+struct _line {
+ struct _line *next_screen;
+ struct _line *prev_screen;
+ char *row;
+ char *attributes;
+ int last_char;
+ int changed;
+ int scroll;
+ int number;
+ };
+
+struct _line *top_of_win;
+
+typedef struct WIND {
+ int SR; /* starting row */
+ int SC; /* starting column */
+ int LC; /* last column */
+ int LX; /* last cursor column position */
+ int LY; /* last cursor row position */
+ int Attrib; /* attributes active in window */
+ int Num_lines; /* number of lines */
+ int Num_cols; /* number of columns */
+ int scroll_up; /* number of lines moved */
+ int scroll_down;
+ int SCROLL_CLEAR; /* indicates that window has been scrolled or cleared */
+ struct _line *first_line;
+ struct _line **line_array;
+ } WINDOW;
+
+extern WINDOW *curscr;
+extern WINDOW *stdscr;
+
+extern int LINES, COLS;
+
+#if defined(__STDC__) || defined(__cplusplus)
+#define P_(s) s
+#else
+#define P_(s) ()
+#endif
+
+extern void copy_window P_((WINDOW *origin, WINDOW *destination));
+extern void reinitscr P_((int));
+extern void initscr P_((void));
+extern int Get_int P_((void));
+extern int INFO_PARSE P_((void));
+extern int AtoI P_((void));
+extern void Key_Get P_((void));
+extern void keys_vt100 P_((void));
+extern struct _line *Screenalloc P_((int columns));
+extern WINDOW *newwin P_((int lines, int cols, int start_l, int start_c));
+extern int Operation P_((int Temp_Stack[], int place));
+extern void Info_Out P_((char *string, int p_list[], int place));
+extern void wmove P_((WINDOW *window, int row, int column));
+extern void clear_line P_((struct _line *line, int column, int cols));
+extern void werase P_((WINDOW *window));
+extern void wclrtoeol P_((WINDOW *window));
+extern void wrefresh P_((WINDOW *window));
+extern void touchwin P_((WINDOW *window));
+extern void wnoutrefresh P_((WINDOW *window));
+extern void flushinp P_((void));
+extern void ungetch P_((int c));
+extern int wgetch P_((WINDOW *window));
+extern void Clear P_((int));
+extern int Get_key P_((int first_char));
+extern void waddch P_((WINDOW *window, int c));
+extern void winsertln P_((WINDOW *window));
+extern void wdeleteln P_((WINDOW *window));
+extern void wclrtobot P_((WINDOW *window));
+extern void wstandout P_((WINDOW *window));
+extern void wstandend P_((WINDOW *window));
+extern void waddstr P_((WINDOW *window, char *string));
+extern void clearok P_((WINDOW *window, int flag));
+extern void echo P_((void));
+extern void noecho P_((void));
+extern void raw P_((void));
+extern void noraw P_((void));
+extern void nl P_((void));
+extern void nonl P_((void));
+extern void saveterm P_((void));
+extern void fixterm P_((void));
+extern void resetterm P_((void));
+extern void nodelay P_((WINDOW *window, int flag));
+extern void idlok P_((WINDOW *window, int flag));
+extern void keypad P_((WINDOW *window, int flag));
+extern void savetty P_((void));
+extern void resetty P_((void));
+extern void endwin P_((void));
+extern void delwin P_((WINDOW *window));
+extern void wprintw P_((WINDOW *window, const char* format, ...));
+extern void iout P_((WINDOW *window, int value));
+extern int Comp_line P_((struct _line *line1, struct _line *line2));
+extern struct _line *Insert_line P_((int row, int end_row, WINDOW *window));
+extern struct _line *Delete_line P_((int row, int end_row, WINDOW *window));
+extern void CLEAR_TO_EOL P_((WINDOW *window, int row, int column));
+extern int check_delete P_((WINDOW *window, int line, int offset, struct _line *pointer_new, struct _line *pointer_old));
+extern int check_insert P_((WINDOW *window, int line, int offset, struct _line *pointer_new, struct _line *pointer_old));
+extern void doupdate P_((void));
+extern void Position P_((WINDOW *window, int row, int col));
+extern void Char_del P_((char *line, char *attrib, int offset, int maxlen));
+extern void Char_ins P_((char *line, char *attrib, int newc, int newatt, int offset, int maxlen));
+extern void attribute_on P_((void));
+extern void attribute_off P_((void));
+extern void Char_out P_((int newc, int newatt, char *line, char *attrib, int offset));
+
+extern void nc_setattrib P_((int));
+extern void nc_clearattrib P_((int));
+#undef P_
+
diff --git a/text_cmds/expand/expand.1 b/text_cmds/expand/expand.1
new file mode 100644
index 0000000..4fb5b07
--- /dev/null
+++ b/text_cmds/expand/expand.1
@@ -0,0 +1,118 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)expand.1 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD: src/usr.bin/expand/expand.1,v 1.15 2006/10/13 16:22:24 ru Exp $
+.\"
+.Dd October 13, 2006
+.Dt EXPAND 1
+.Os
+.Sh NAME
+.Nm expand ,
+.Nm unexpand
+.Nd expand tabs to spaces, and vice versa
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl t
+.Sm off
+.Ar tab1 , tab2 , ... , tabn
+.Sm on
+.Oc
+.Op Ar
+.Nm unexpand
+.Oo
+.Fl a | t
+.Sm off
+.Ar tab1 , tab2 , ... , tabn
+.Sm on
+.Oc
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility processes the named files or the standard input writing
+the standard output with tabs changed into blanks.
+Backspace characters are preserved into the output and decrement
+the column count for tab calculations.
+The
+.Nm
+utility is useful for pre-processing character files
+(before sorting, looking at specific columns, etc.) that
+contain tabs.
+.Pp
+The
+.Nm unexpand
+utility puts tabs back into the data from the standard input or the named
+files and writes the result on the standard output.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl a
+.Nm ( unexpand
+only.)
+By default, only leading blanks and tabs
+are reconverted to maximal strings of tabs.
+If the
+.Fl a
+option is given, then tabs are inserted whenever they would compress the
+resultant file by replacing two or more characters.
+.It Fl t Sm Ar tab1 , tab2 , ... , tabn Sm
+Set tab stops at column positions
+.Ar tab1 , tab2 , ... , tabn .
+If only a single number is given, tab stops are set that number of
+column positions apart instead of the default number of 8.
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+and
+.Nm unexpand
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std expand unexpand
+.Sh STANDARDS
+The
+.Nm
+and
+.Nm unexpand
+utilities conform to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/text_cmds/expand/expand.c b/text_cmds/expand/expand.c
new file mode 100644
index 0000000..73a3ee0
--- /dev/null
+++ b/text_cmds/expand/expand.c
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)expand.c 8.1 (Berkeley) 6/9/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/expand/expand.c,v 1.15 2004/06/24 13:42:26 tjr Exp $");
+
+#include <ctype.h>
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/*
+ * expand - expand tabs to equivalent spaces
+ */
+int nstops;
+int tabstops[100];
+
+static void getstops(char *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ const char *curfile;
+ wint_t wc;
+ int c, column;
+ int n;
+ int rval;
+ int width;
+
+ setlocale(LC_CTYPE, "");
+
+ /* handle obsolete syntax */
+ while (argc > 1 && argv[1] && argv[1][0] == '-' &&
+ isdigit((unsigned char)argv[1][1])) {
+ getstops(&argv[1][1]);
+ argc--; argv++;
+ }
+
+ while ((c = getopt (argc, argv, "t:")) != -1) {
+ switch (c) {
+ case 't':
+ getstops(optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ rval = 0;
+ do {
+ if (argc > 0 && *argv) {
+ if (freopen(argv[0], "r", stdin) == NULL) {
+ warn("%s", argv[0]);
+ rval = 1;
+ argc--, argv++;
+ continue;
+ }
+ curfile = argv[0];
+ argc--, argv++;
+ } else
+ curfile = "stdin";
+ column = 0;
+ while ((wc = getwchar()) != WEOF) {
+ switch (wc) {
+ case '\t':
+ if (nstops == 0) {
+ do {
+ putwchar(' ');
+ column++;
+ } while (column & 07);
+ continue;
+ }
+ if (nstops == 1) {
+ do {
+ putwchar(' ');
+ column++;
+ } while (((column - 1) % tabstops[0]) != (tabstops[0] - 1));
+ continue;
+ }
+ for (n = 0; n < nstops; n++)
+ if (tabstops[n] > column)
+ break;
+ if (n == nstops) {
+ putwchar(' ');
+ column++;
+ continue;
+ }
+ while (column < tabstops[n]) {
+ putwchar(' ');
+ column++;
+ }
+ continue;
+
+ case '\b':
+ if (column)
+ column--;
+ putwchar('\b');
+ continue;
+
+ default:
+ putwchar(wc);
+ if ((width = wcwidth(wc)) > 0)
+ column += width;
+ continue;
+
+ case '\n':
+ putwchar(wc);
+ column = 0;
+ continue;
+ }
+ }
+ if (ferror(stdin)) {
+ warn("%s", curfile);
+ rval = 1;
+ }
+ } while (argc > 0);
+ exit(rval);
+}
+
+static void
+getstops(char *cp)
+{
+ int i;
+
+ nstops = 0;
+ for (;;) {
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + *cp++ - '0';
+ if (i <= 0)
+ errx(1, "bad tab stop spec");
+ if (nstops > 0 && i <= tabstops[nstops-1])
+ errx(1, "bad tab stop spec");
+ if (nstops == sizeof(tabstops) / sizeof(*tabstops))
+ errx(1, "too many tab stops");
+ tabstops[nstops++] = i;
+ if (*cp == 0)
+ break;
+ if (*cp != ',' && !isblank((unsigned char)*cp))
+ errx(1, "bad tab stop spec");
+ cp++;
+ }
+}
+
+static void
+usage(void)
+{
+ (void)fprintf (stderr, "usage: expand [-t tablist] [file ...]\n");
+ exit(1);
+}
diff --git a/text_cmds/expand/xcodescripts/link-man-pages.sh b/text_cmds/expand/xcodescripts/link-man-pages.sh
new file mode 100644
index 0000000..1a3d985
--- /dev/null
+++ b/text_cmds/expand/xcodescripts/link-man-pages.sh
@@ -0,0 +1,3 @@
+set -e -x
+ln -f "$DSTROOT"/usr/share/man/man1/expand.1 \
+ "$DSTROOT"/usr/share/man/man1/unexpand.1
diff --git a/text_cmds/fmt/fmt.1 b/text_cmds/fmt/fmt.1
new file mode 100644
index 0000000..6480c82
--- /dev/null
+++ b/text_cmds/fmt/fmt.1
@@ -0,0 +1,196 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fmt.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/fmt/fmt.1,v 1.14 2004/08/02 11:12:13 tjr Exp $
+.\"
+.\" Modified by Gareth McCaughan to describe the new version of `fmt'
+.\" rather than the old one.
+.Dd August 2, 2004
+.Dt FMT 1
+.Os
+.Sh NAME
+.Nm fmt
+.Nd simple text formatter
+.Sh SYNOPSIS
+.Nm fmt
+.Op Fl cmnps
+.Op Fl d Ar chars
+.Op Fl l Ar num
+.Op Fl t Ar num
+.Op Ar goal Oo Ar maximum Oc | Fl Ns Ar width | Fl w Ar width
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is a simple text formatter which reads the concatenation of input
+files (or standard input if none are given) and produces on standard
+output a version of its input with lines as close to the
+.Ar goal
+length
+as possible without exceeding the
+.Ar maximum .
+The
+.Ar goal
+length defaults
+to 65 and the
+.Ar maximum
+to 10 more than the
+.Ar goal
+length.
+Alternatively, a single
+.Ar width
+parameter can be specified either by prepending a hyphen to it or by using
+.Fl w .
+For example,
+.Dq Li fmt -w 72 ,
+.Dq Li fmt -72 ,
+and
+.Dq Li fmt 72 72
+all produce identical output.
+The spacing at the beginning of the input lines is preserved in the output,
+as are blank lines and interword spacing.
+Lines are joined or split only at white space; that is, words are never
+joined or hyphenated.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c
+Center the text, line by line.
+In this case, most of the other
+options are ignored; no splitting or joining of lines is done.
+.It Fl m
+Try to format mail header lines contained in the input sensibly.
+.It Fl n
+Format lines beginning with a
+.Ql \&.
+(dot) character.
+Normally,
+.Nm
+does not fill these lines, for compatibility with
+.Xr nroff 1 .
+.It Fl p
+Allow indented paragraphs.
+Without the
+.Fl p
+flag, any change in the amount of whitespace at the start of a line
+results in a new paragraph being begun.
+.It Fl s
+Collapse whitespace inside lines, so that multiple whitespace
+characters are turned into a single space.
+(Or, at the end of a
+sentence, a double space.)
+.It Fl d Ar chars
+Treat the
+.Ar chars
+(and no others) as sentence-ending characters.
+By default the
+sentence-ending characters are full stop
+.Pq Ql \&. ,
+question mark
+.Pq Ql \&?
+and exclamation mark
+.Pq Ql \&! .
+Remember that some characters may need to be
+escaped to protect them from your shell.
+.It Fl l Ar number
+Replace multiple spaces with tabs at the start of each output
+line, if possible.
+Each
+.Ar number
+spaces will be replaced with one tab.
+The default is 8.
+If
+.Ar number
+is 0, spaces are preserved.
+.It Fl t Ar number
+Assume that the input files' tabs assume
+.Ar number
+spaces per tab stop.
+The default is 8.
+.El
+.Pp
+The
+.Nm
+utility
+is meant to format mail messages prior to sending, but may also be useful
+for other simple tasks.
+For instance,
+within visual mode of the
+.Xr ex 1
+editor (e.g.,
+.Xr vi 1 )
+the command
+.Pp
+.Dl \&!}fmt
+.Pp
+will reformat a paragraph,
+evening the lines.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh SEE ALSO
+.Xr fold 1 ,
+.Xr mail 1 ,
+.Xr nroff 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3 .
+.Pp
+The version described herein is a complete rewrite and appeared in
+.Fx 4.4 .
+.Sh AUTHORS
+.An Kurt Shoens
+.An Liz Allen
+(added
+.Ar goal
+length concept)
+.An Gareth McCaughan
+.Sh BUGS
+The program was designed to be simple and fast \- for more complex
+operations, the standard text processors are likely to be more appropriate.
+.Pp
+When the first line of an indented paragraph is very long (more than
+about twice the goal length), the indentation in the output can be
+wrong.
+.Pp
+The
+.Nm
+utility is not infallible in guessing what lines are mail headers and what
+lines are not.
diff --git a/text_cmds/fmt/fmt.c b/text_cmds/fmt/fmt.c
new file mode 100644
index 0000000..853695f
--- /dev/null
+++ b/text_cmds/fmt/fmt.c
@@ -0,0 +1,668 @@
+/* $OpenBSD: fmt.c,v 1.16 2000/06/25 15:35:42 pjanzen Exp $ */
+
+/* Sensible version of fmt
+ *
+ * Syntax: fmt [ options ] [ goal [ max ] ] [ filename ... ]
+ *
+ * Since the documentation for the original fmt is so poor, here
+ * is an accurate description of what this one does. It's usually
+ * the same. The *mechanism* used may differ from that suggested
+ * here. Note that we are *not* entirely compatible with fmt,
+ * because fmt gets so many things wrong.
+ *
+ * 1. Tabs are expanded, assuming 8-space tab stops.
+ * If the `-t <n>' option is given, we assume <n>-space
+ * tab stops instead.
+ * Trailing blanks are removed from all lines.
+ * x\b == nothing, for any x other than \b.
+ * Other control characters are simply stripped. This
+ * includes \r.
+ * 2. Each line is split into leading whitespace and
+ * everything else. Maximal consecutive sequences of
+ * lines with the same leading whitespace are considered
+ * to form paragraphs, except that a blank line is always
+ * a paragraph to itself.
+ * If the `-p' option is given then the first line of a
+ * paragraph is permitted to have indentation different
+ * from that of the other lines.
+ * If the `-m' option is given then a line that looks
+ * like a mail message header, if it is not immediately
+ * preceded by a non-blank non-message-header line, is
+ * taken to start a new paragraph, which also contains
+ * any subsequent lines with non-empty leading whitespace.
+ * Unless the `-n' option is given, lines beginning with
+ * a . (dot) are not formatted.
+ * 3. The "everything else" is split into words; a word
+ * includes its trailing whitespace, and a word at the
+ * end of a line is deemed to be followed by a single
+ * space, or two spaces if it ends with a sentence-end
+ * character. (See the `-d' option for how to change that.)
+ * If the `-s' option has been given, then a word's trailing
+ * whitespace is replaced by what it would have had if it
+ * had occurred at end of line.
+ * 4. Each paragraph is sent to standard output as follows.
+ * We output the leading whitespace, and then enough words
+ * to make the line length as near as possible to the goal
+ * without exceeding the maximum. (If a single word would
+ * exceed the maximum, we output that anyway.) Of course
+ * the trailing whitespace of the last word is ignored.
+ * We then emit a newline and start again if there are any
+ * words left.
+ * Note that for a blank line this translates as "We emit
+ * a newline".
+ * If the `-l <n>' option is given, then leading whitespace
+ * is modified slightly: <n> spaces are replaced by a tab.
+ * Indented paragraphs (see above under `-p') make matters
+ * more complicated than this suggests. Actually every paragraph
+ * has two `leading whitespace' values; the value for the first
+ * line, and the value for the most recent line. (While processing
+ * the first line, the two are equal. When `-p' has not been
+ * given, they are always equal.) The leading whitespace
+ * actually output is that of the first line (for the first
+ * line of *output*) or that of the most recent line (for
+ * all other lines of output).
+ * When `-m' has been given, message header paragraphs are
+ * taken as having first-leading-whitespace empty and
+ * subsequent-leading-whitespace two spaces.
+ *
+ * Multiple input files are formatted one at a time, so that a file
+ * never ends in the middle of a line.
+ *
+ * There's an alternative mode of operation, invoked by giving
+ * the `-c' option. In that case we just center every line,
+ * and most of the other options are ignored. This should
+ * really be in a separate program, but we must stay compatible
+ * with old `fmt'.
+ *
+ * QUERY: Should `-m' also try to do the right thing with quoted text?
+ * QUERY: `-b' to treat backslashed whitespace as old `fmt' does?
+ * QUERY: Option meaning `never join lines'?
+ * QUERY: Option meaning `split in mid-word to avoid overlong lines'?
+ * (Those last two might not be useful, since we have `fold'.)
+ *
+ * Differences from old `fmt':
+ *
+ * - We have many more options. Options that aren't understood
+ * generate a lengthy usage message, rather than being
+ * treated as filenames.
+ * - Even with `-m', our handling of message headers is
+ * significantly different. (And much better.)
+ * - We don't treat `\ ' as non-word-breaking.
+ * - Downward changes of indentation start new paragraphs
+ * for us, as well as upward. (I think old `fmt' behaves
+ * in the way it does in order to allow indented paragraphs,
+ * but this is a broken way of making indented paragraphs
+ * behave right.)
+ * - Given the choice of going over or under |goal_length|
+ * by the same amount, we go over; old `fmt' goes under.
+ * - We treat `?' as ending a sentence, and not `:'. Old `fmt'
+ * does the reverse.
+ * - We return approved return codes. Old `fmt' returns
+ * 1 for some errors, and *the number of unopenable files*
+ * when that was all that went wrong.
+ * - We have fewer crashes and more helpful error messages.
+ * - We don't turn spaces into tabs at starts of lines unless
+ * specifically requested.
+ * - New `fmt' is somewhat smaller and slightly faster than
+ * old `fmt'.
+ *
+ * Bugs:
+ *
+ * None known. There probably are some, though.
+ *
+ * Portability:
+ *
+ * I believe this code to be pretty portable. It does require
+ * that you have `getopt'. If you need to include "getopt.h"
+ * for this (e.g., if your system didn't come with `getopt'
+ * and you installed it yourself) then you should arrange for
+ * NEED_getopt_h to be #defined.
+ *
+ * Everything here should work OK even on nasty 16-bit
+ * machines and nice 64-bit ones. However, it's only really
+ * been tested on my FreeBSD machine. Your mileage may vary.
+ */
+
+/* Copyright (c) 1997 Gareth McCaughan. All rights reserved.
+ *
+ * Redistribution and use of this code, in source or binary forms,
+ * with or without modification, are permitted subject to the following
+ * conditions:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - If you distribute modified source code it must also include
+ * a notice saying that it has been modified, and giving a brief
+ * description of what changes have been made.
+ *
+ * Disclaimer: I am not responsible for the results of using this code.
+ * If it formats your hard disc, sends obscene messages to
+ * your boss and kills your children then that's your problem
+ * not mine. I give absolutely no warranty of any sort as to
+ * what the program will do, and absolutely refuse to be held
+ * liable for any consequences of your using it.
+ * Thank you. Have a nice day.
+ */
+
+/* RCS change log:
+ * Revision 1.5 1998/03/02 18:02:21 gjm11
+ * Minor changes for portability.
+ *
+ * Revision 1.4 1997/10/01 11:51:28 gjm11
+ * Repair broken indented-paragraph handling.
+ * Add mail message header stuff.
+ * Improve comments and layout.
+ * Make usable with non-BSD systems.
+ * Add revision display to usage message.
+ *
+ * Revision 1.3 1997/09/30 16:24:47 gjm11
+ * Add copyright notice, rcsid string and log message.
+ *
+ * Revision 1.2 1997/09/30 16:13:39 gjm11
+ * Add options: -d <chars>, -l <width>, -p, -s, -t <width>, -h .
+ * Parse options with `getopt'. Clean up code generally.
+ * Make comments more accurate.
+ *
+ * Revision 1.1 1997/09/30 11:29:57 gjm11
+ * Initial revision
+ */
+
+#ifndef lint
+static const char copyright[] =
+ "Copyright (c) 1997 Gareth McCaughan. All rights reserved.\n";
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/fmt/fmt.c,v 1.22 2004/08/02 11:10:20 tjr Exp $");
+
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/* Something that, we hope, will never be a genuine line length,
+ * indentation etc.
+ */
+#define SILLY ((size_t)-1)
+
+/* I used to use |strtoul| for this, but (1) not all systems have it
+ * and (2) it's probably better to use |strtol| to detect negative
+ * numbers better.
+ * If |fussyp==0| then we don't complain about non-numbers
+ * (returning 0 instead), but we do complain about bad numbers.
+ */
+static size_t
+get_positive(const char *s, const char *err_mess, int fussyP) {
+ char *t;
+ long result = strtol(s,&t,0);
+ if (*t) { if (fussyP) goto Lose; else return 0; }
+ if (result<=0) { Lose: errx(EX_USAGE, "%s", err_mess); }
+ return (size_t) result;
+}
+
+static size_t
+get_nonnegative(const char *s, const char *err_mess, int fussyP) {
+ char *t;
+ long result = strtol(s,&t,0);
+ if (*t) { if (fussyP) goto Lose; else return 0; }
+ if (result<0) { Lose: errx(EX_USAGE, "%s", err_mess); }
+ return (size_t) result;
+}
+
+/* Global variables */
+
+static int centerP=0; /* Try to center lines? */
+static size_t goal_length=0; /* Target length for output lines */
+static size_t max_length=0; /* Maximum length for output lines */
+static int coalesce_spaces_P=0; /* Coalesce multiple whitespace -> ' ' ? */
+static int allow_indented_paragraphs=0; /* Can first line have diff. ind.? */
+static int tab_width=8; /* Number of spaces per tab stop */
+static size_t output_tab_width=8; /* Ditto, when squashing leading spaces */
+static const wchar_t *sentence_enders=L".?!"; /* Double-space after these */
+static int grok_mail_headers=0; /* treat embedded mail headers magically? */
+static int format_troff=0; /* Format troff? */
+
+static int n_errors=0; /* Number of failed files. Return on exit. */
+static wchar_t *output_buffer=0; /* Output line will be built here */
+static size_t x; /* Horizontal position in output line */
+static size_t x0; /* Ditto, ignoring leading whitespace */
+static size_t output_buffer_length = 0;
+static size_t pending_spaces; /* Spaces to add before next word */
+static int output_in_paragraph=0; /* Any of current para written out yet? */
+
+/* Prototypes */
+
+static void process_named_file (const char *);
+static void process_stream (FILE *, const char *);
+static size_t indent_length (const wchar_t *, size_t);
+static int might_be_header (const wchar_t *);
+static void new_paragraph (size_t, size_t);
+static void output_word (size_t, size_t, const wchar_t *, size_t,
+ size_t);
+static void output_indent (size_t);
+static void center_stream (FILE *, const char *);
+static wchar_t * get_line (FILE *, size_t *);
+static void * xrealloc (void *, size_t);
+
+#define XMALLOC(x) xrealloc(0,x)
+
+/* Here is perhaps the right place to mention that this code is
+ * all in top-down order. Hence, |main| comes first.
+ */
+int
+main(int argc, char *argv[]) {
+ int ch; /* used for |getopt| processing */
+ wchar_t *tmp;
+ size_t len;
+ const char *src;
+
+ (void) setlocale(LC_CTYPE, "");
+
+ /* 1. Grok parameters. */
+
+ while ((ch = getopt(argc, argv, "0123456789cd:hl:mnpst:w:")) != -1)
+ switch(ch) {
+ case 'c':
+ centerP = 1;
+ format_troff = 1;
+ continue;
+ case 'd':
+ src = optarg;
+ len = mbsrtowcs(NULL, &src, 0, NULL);
+ if (len == (size_t)-1)
+ err(EX_USAGE, "bad sentence-ending character set");
+ tmp = XMALLOC((len + 1) * sizeof(wchar_t));
+ mbsrtowcs(tmp, &src, len + 1, NULL);
+ sentence_enders = tmp;
+ continue;
+ case 'l':
+ output_tab_width
+ = get_nonnegative(optarg, "output tab width must be non-negative", 1);
+ continue;
+ case 'm':
+ grok_mail_headers = 1;
+ continue;
+ case 'n':
+ format_troff = 1;
+ continue;
+ case 'p':
+ allow_indented_paragraphs = 1;
+ continue;
+ case 's':
+ coalesce_spaces_P = 1;
+ continue;
+ case 't':
+ tab_width = get_positive(optarg, "tab width must be positive", 1);
+ continue;
+ case 'w':
+ goal_length = get_positive(optarg, "width must be positive", 1);
+ max_length = goal_length;
+ continue;
+ case '0': case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ /* XXX this is not a stylistically approved use of getopt() */
+ if (goal_length==0) {
+ char *p;
+ p = argv[optind - 1];
+ if (p[0] == '-' && p[1] == ch && !p[2])
+ goal_length = get_positive(++p, "width must be nonzero", 1);
+ else
+ goal_length = get_positive(argv[optind]+1,
+ "width must be nonzero", 1);
+ max_length = goal_length;
+ }
+ continue;
+ case 'h': default:
+ fprintf(stderr,
+"usage: fmt [-cmps] [-d chars] [-l num] [-t num]\n"
+" [-w width | -width | goal [maximum]] [file ...]\n"
+"Options: -c center each line instead of formatting\n"
+" -d <chars> double-space after <chars> at line end\n"
+" -l <n> turn each <n> spaces at start of line into a tab\n"
+" -m try to make sure mail header lines stay separate\n"
+" -n format lines beginning with a dot\n"
+" -p allow indented paragraphs\n"
+" -s coalesce whitespace inside lines\n"
+" -t <n> have tabs every <n> columns\n"
+" -w <n> set maximum width to <n>\n"
+" goal set target width to goal\n");
+ exit(ch=='h' ? 0 : EX_USAGE);
+ }
+ argc -= optind; argv += optind;
+
+ /* [ goal [ maximum ] ] */
+
+ if (argc>0 && goal_length==0
+ && (goal_length=get_positive(*argv,"goal length must be positive", 0))
+ != 0) {
+ --argc; ++argv;
+ if (argc>0
+ && (max_length=get_positive(*argv,"max length must be positive", 0))
+ != 0) {
+ --argc; ++argv;
+ if (max_length<goal_length)
+ errx(EX_USAGE, "max length must be >= goal length");
+ }
+ }
+ if (goal_length==0) goal_length = 65;
+ if (max_length==0) max_length = goal_length+10;
+ /* really needn't be longer */
+ output_buffer = XMALLOC((max_length+1) * sizeof(wchar_t));
+
+ /* 2. Process files. */
+
+ if (argc>0) {
+ while (argc-->0) process_named_file(*argv++);
+ }
+ else {
+ process_stream(stdin, "standard input");
+ }
+
+ /* We're done. */
+
+ return n_errors ? EX_NOINPUT : 0;
+
+}
+
+/* Process a single file, given its name.
+ */
+static void
+process_named_file(const char *name) {
+ FILE *f=fopen(name, "r");
+ if (!f) { warn("%s", name); ++n_errors; }
+ else {
+ process_stream(f, name);
+ if (ferror(f)) { warn("%s", name); ++n_errors; }
+ fclose(f);
+ }
+}
+
+/* Types of mail header continuation lines:
+ */
+typedef enum {
+ hdr_ParagraphStart = -1,
+ hdr_NonHeader = 0,
+ hdr_Header = 1,
+ hdr_Continuation = 2
+} HdrType;
+
+/* Process a stream. This is where the real work happens,
+ * except that centering is handled separately.
+ */
+static void
+process_stream(FILE *stream, const char *name) {
+ size_t last_indent=SILLY; /* how many spaces in last indent? */
+ size_t para_line_number=0; /* how many lines already read in this para? */
+ size_t first_indent=SILLY; /* indentation of line 0 of paragraph */
+ HdrType prev_header_type=hdr_ParagraphStart;
+ /* ^-- header_type of previous line; -1 at para start */
+ wchar_t *line;
+ size_t length;
+
+ if (centerP) { center_stream(stream, name); return; }
+ while ((line=get_line(stream,&length)) != NULL) {
+ size_t np=indent_length(line, length);
+ { HdrType header_type=hdr_NonHeader;
+ if (grok_mail_headers && prev_header_type!=hdr_NonHeader) {
+ if (np==0 && might_be_header(line))
+ header_type = hdr_Header;
+ else if (np>0 && prev_header_type>hdr_NonHeader)
+ header_type = hdr_Continuation;
+ }
+ /* We need a new paragraph if and only if:
+ * this line is blank,
+ * OR it's a troff request (and we don't format troff),
+ * OR it's a mail header,
+ * OR it's not a mail header AND the last line was one,
+ * OR the indentation has changed
+ * AND the line isn't a mail header continuation line
+ * AND this isn't the second line of an indented paragraph.
+ */
+ if ( length==0
+ || (line[0]=='.' && !format_troff)
+ || header_type==hdr_Header
+ || (header_type==hdr_NonHeader && prev_header_type>hdr_NonHeader)
+ || (np!=last_indent
+ && header_type != hdr_Continuation
+ && (!allow_indented_paragraphs || para_line_number != 1)) ) {
+ new_paragraph(output_in_paragraph ? last_indent : first_indent, np);
+ para_line_number = 0;
+ first_indent = np;
+ last_indent = np;
+ if (header_type==hdr_Header) last_indent=2; /* for cont. lines */
+ if (length==0 || (line[0]=='.' && !format_troff)) {
+ if (length==0)
+ putwchar('\n');
+ else
+ wprintf(L"%.*ls\n", (int)length, line);
+ prev_header_type=hdr_ParagraphStart;
+ continue;
+ }
+ }
+ else {
+ /* If this is an indented paragraph other than a mail header
+ * continuation, set |last_indent|.
+ */
+ if (np != last_indent && header_type != hdr_Continuation)
+ last_indent=np;
+ }
+ prev_header_type = header_type;
+ }
+
+ { size_t n=np;
+ while (n<length) {
+ /* Find word end and count spaces after it */
+ size_t word_length=0, space_length=0;
+ while (n+word_length < length && line[n+word_length] != ' ')
+ ++word_length;
+ space_length = word_length;
+ while (n+space_length < length && line[n+space_length] == ' ')
+ ++space_length;
+ /* Send the word to the output machinery. */
+ output_word(first_indent, last_indent,
+ line+n, word_length, space_length-word_length);
+ n += space_length;
+ }
+ }
+ ++para_line_number;
+ }
+ new_paragraph(output_in_paragraph ? last_indent : first_indent, 0);
+ if (ferror(stream)) { warn("%s", name); ++n_errors; }
+}
+
+/* How long is the indent on this line?
+ */
+static size_t
+indent_length(const wchar_t *line, size_t length) {
+ size_t n=0;
+ while (n<length && *line++ == ' ') ++n;
+ return n;
+}
+
+/* Might this line be a mail header?
+ * We deem a line to be a possible header if it matches the
+ * Perl regexp /^[A-Z][-A-Za-z0-9]*:\s/. This is *not* the same
+ * as in RFC whatever-number-it-is; we want to be gratuitously
+ * conservative to avoid mangling ordinary civilised text.
+ */
+static int
+might_be_header(const wchar_t *line) {
+ if (!iswupper(*line++)) return 0;
+ while (*line && (iswalnum(*line) || *line=='-')) ++line;
+ return (*line==':' && iswspace(line[1]));
+}
+
+/* Begin a new paragraph with an indent of |indent| spaces.
+ */
+static void
+new_paragraph(size_t old_indent, size_t indent) {
+ if (output_buffer_length) {
+ if (old_indent>0) output_indent(old_indent);
+ wprintf(L"%.*ls\n", (int)output_buffer_length, output_buffer);
+ }
+ x=indent; x0=0; output_buffer_length=0; pending_spaces=0;
+ output_in_paragraph = 0;
+}
+
+/* Output spaces or tabs for leading indentation.
+ */
+static void
+output_indent(size_t n_spaces) {
+ if (output_tab_width) {
+ while (n_spaces >= output_tab_width) {
+ putwchar('\t');
+ n_spaces -= output_tab_width;
+ }
+ }
+ while (n_spaces-- > 0) putwchar(' ');
+}
+
+/* Output a single word, or add it to the buffer.
+ * indent0 and indent1 are the indents to use on the first and subsequent
+ * lines of a paragraph. They'll often be the same, of course.
+ */
+static void
+output_word(size_t indent0, size_t indent1, const wchar_t *word, size_t length, size_t spaces) {
+ size_t new_x;
+ size_t indent = output_in_paragraph ? indent1 : indent0;
+ size_t width;
+ const wchar_t *p;
+ int cwidth;
+
+ for (p = word, width = 0; p < &word[length]; p++)
+ width += (cwidth = wcwidth(*p)) > 0 ? cwidth : 1;
+
+ new_x = x + pending_spaces + width;
+
+ /* If either |spaces==0| (at end of line) or |coalesce_spaces_P|
+ * (squashing internal whitespace), then add just one space;
+ * except that if the last character was a sentence-ender we
+ * actually add two spaces.
+ */
+ if (coalesce_spaces_P || spaces==0)
+ spaces = wcschr(sentence_enders, word[length-1]) ? 2 : 1;
+
+ if (new_x<=goal_length) {
+ /* After adding the word we still aren't at the goal length,
+ * so clearly we add it to the buffer rather than outputing it.
+ */
+ wmemset(output_buffer+output_buffer_length, L' ', pending_spaces);
+ x0 += pending_spaces; x += pending_spaces;
+ output_buffer_length += pending_spaces;
+ wmemcpy(output_buffer+output_buffer_length, word, length);
+ x0 += width; x += width; output_buffer_length += length;
+ pending_spaces = spaces;
+ }
+ else {
+ /* Adding the word takes us past the goal. Print the line-so-far,
+ * and the word too iff either (1) the lsf is empty or (2) that
+ * makes us nearer the goal but doesn't take us over the limit,
+ * or (3) the word on its own takes us over the limit.
+ * In case (3) we put a newline in between.
+ */
+ if (indent>0) output_indent(indent);
+ wprintf(L"%.*ls", (int)output_buffer_length, output_buffer);
+ if (x0==0 || (new_x <= max_length && new_x-goal_length <= goal_length-x)) {
+ wprintf(L"%*ls", (int)pending_spaces, L"");
+ goto write_out_word;
+ }
+ else {
+ /* If the word takes us over the limit on its own, just
+ * spit it out and don't bother buffering it.
+ */
+ if (indent+width > max_length) {
+ putwchar('\n');
+ if (indent>0) output_indent(indent);
+write_out_word:
+ wprintf(L"%.*ls", (int)length, word);
+ x0 = 0; x = indent1; pending_spaces = 0;
+ output_buffer_length = 0;
+ }
+ else {
+ wmemcpy(output_buffer, word, length);
+ x0 = width; x = width+indent1; pending_spaces = spaces;
+ output_buffer_length = length;
+ }
+ }
+ putwchar('\n');
+ output_in_paragraph = 1;
+ }
+}
+
+/* Process a stream, but just center its lines rather than trying to
+ * format them neatly.
+ */
+static void
+center_stream(FILE *stream, const char *name) {
+ wchar_t *line, *p;
+ size_t length;
+ size_t width;
+ int cwidth;
+ while ((line=get_line(stream, &length)) != 0) {
+ size_t l=length;
+ while (l>0 && iswspace(*line)) { ++line; --l; }
+ length=l;
+ for (p = line, width = 0; p < &line[length]; p++)
+ width += (cwidth = wcwidth(*p)) > 0 ? cwidth : 1;
+ l = width;
+ while (l<goal_length) { putwchar(' '); l+=2; }
+ wprintf(L"%.*ls\n", (int)length, line);
+ }
+ if (ferror(stream)) { warn("%s", name); ++n_errors; }
+}
+
+/* Get a single line from a stream. Expand tabs, strip control
+ * characters and trailing whitespace, and handle backspaces.
+ * Return the address of the buffer containing the line, and
+ * put the length of the line in |lengthp|.
+ * This can cope with arbitrarily long lines, and with lines
+ * without terminating \n.
+ * If there are no characters left or an error happens, we
+ * return 0.
+ * Don't confuse |spaces_pending| here with the global
+ * |pending_spaces|.
+ */
+static wchar_t *
+get_line(FILE *stream, size_t *lengthp) {
+ static wchar_t *buf=NULL;
+ static size_t length=0;
+ size_t len=0;
+ wint_t ch;
+ size_t spaces_pending=0;
+ int troff=0;
+ size_t col=0;
+ int cwidth;
+
+ if (buf==NULL) { length=100; buf=XMALLOC(length * sizeof(wchar_t)); }
+ while ((ch=getwc(stream)) != '\n' && ch != WEOF) {
+ if (len+spaces_pending==0 && ch=='.' && !format_troff) troff=1;
+ if (ch==' ') ++spaces_pending;
+ else if (troff || iswprint(ch)) {
+ while (len+spaces_pending >= length) {
+ length*=2; buf=xrealloc(buf, length * sizeof(wchar_t));
+ }
+ while (spaces_pending > 0) { --spaces_pending; buf[len++]=' '; col++; }
+ buf[len++] = ch;
+ col += (cwidth = wcwidth(ch)) > 0 ? cwidth : 1;
+ }
+ else if (ch=='\t')
+ spaces_pending += tab_width - (col+spaces_pending)%tab_width;
+ else if (ch=='\b') { if (len) --len; if (col) --col; }
+ }
+ *lengthp=len;
+ return (len>0 || ch!=WEOF) ? buf : 0;
+}
+
+/* (Re)allocate some memory, exiting with an error if we can't.
+ */
+static void *
+xrealloc(void *ptr, size_t nbytes) {
+ void *p = realloc(ptr, nbytes);
+ if (p == NULL) errx(EX_OSERR, "out of memory");
+ return p;
+}
diff --git a/text_cmds/fold/fold.1 b/text_cmds/fold/fold.1
new file mode 100644
index 0000000..b9f206d
--- /dev/null
+++ b/text_cmds/fold/fold.1
@@ -0,0 +1,90 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)fold.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/fold/fold.1,v 1.12 2004/08/02 11:15:01 tjr Exp $
+.\"
+.Dd August 2, 2004
+.Dt FOLD 1
+.Os
+.Sh NAME
+.Nm fold
+.Nd "fold long lines for finite width output device"
+.Sh SYNOPSIS
+.Nm
+.Op Fl bs
+.Op Fl w Ar width
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is a filter which folds the contents of the specified files,
+or the standard input if no files are specified,
+breaking the lines to have a maximum of 80 columns.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl b
+Count
+.Ar width
+in bytes rather than column positions.
+.It Fl s
+Fold line after the last blank character within the first
+.Ar width
+column positions (or bytes).
+.It Fl w Ar width
+Specify a line width to use instead of the default 80 columns.
+.Ar Width
+should be a multiple of 8 if tabs are present, or the tabs should
+be expanded using
+.Xr expand 1
+before using
+.Nm .
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh SEE ALSO
+.Xr expand 1 ,
+.Xr fmt 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh BUGS
+If underlining is present it may be messed up by folding.
diff --git a/text_cmds/fold/fold.c b/text_cmds/fold/fold.c
new file mode 100644
index 0000000..e26356c
--- /dev/null
+++ b/text_cmds/fold/fold.c
@@ -0,0 +1,228 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Kevin Ruddy.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)fold.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/fold/fold.c,v 1.13 2004/06/24 15:12:29 tjr Exp $");
+
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#define DEFLINEWIDTH 80
+
+void fold(int);
+static int newpos(int, wint_t);
+static void usage(void);
+
+int bflag; /* Count bytes, not columns */
+int sflag; /* Split on word boundaries */
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ int rval, width;
+ char *p;
+
+ (void) setlocale(LC_CTYPE, "");
+
+ width = -1;
+ while ((ch = getopt(argc, argv, "0123456789bsw:")) != -1)
+ switch (ch) {
+ case 'b':
+ bflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'w':
+ if ((width = atoi(optarg)) <= 0) {
+ errx(1, "illegal width value");
+ }
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (width == -1) {
+ p = argv[optind - 1];
+ if (p[0] == '-' && p[1] == ch && !p[2])
+ width = atoi(++p);
+ else
+ width = atoi(argv[optind] + 1);
+ }
+ break;
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (width == -1)
+ width = DEFLINEWIDTH;
+ rval = 0;
+ if (!*argv)
+ fold(width);
+ else for (; *argv; ++argv)
+ if (!freopen(*argv, "r", stdin)) {
+ warn("%s", *argv);
+ rval = 1;
+ } else
+ fold(width);
+ exit(rval);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: fold [-bs] [-w width] [file ...]\n");
+ exit(1);
+}
+
+/*
+ * Fold the contents of standard input to fit within WIDTH columns (or bytes)
+ * and write to standard output.
+ *
+ * If sflag is set, split the line at the last space character on the line.
+ * This flag necessitates storing the line in a buffer until the current
+ * column > width, or a newline or EOF is read.
+ *
+ * The buffer can grow larger than WIDTH due to backspaces and carriage
+ * returns embedded in the input stream.
+ */
+void
+fold(int width)
+{
+ static wchar_t *buf;
+ static int buf_max;
+ int col, i, indx, space;
+ wint_t ch;
+
+ col = indx = 0;
+ while ((ch = getwchar()) != WEOF) {
+ if (ch == '\n') {
+ wprintf(L"%.*ls\n", indx, buf);
+ col = indx = 0;
+ continue;
+ }
+ if ((col = newpos(col, ch)) > width) {
+ if (sflag) {
+ i = indx;
+ while (--i >= 0 && !iswblank(buf[i]))
+ ;
+ space = i;
+ }
+ if (sflag && space != -1) {
+ space++;
+ wprintf(L"%.*ls\n", space, buf);
+ wmemmove(buf, buf + space, indx - space);
+ indx -= space;
+ col = 0;
+ for (i = 0; i < indx; i++)
+ col = newpos(col, buf[i]);
+ } else {
+ wprintf(L"%.*ls\n", indx, buf);
+ col = indx = 0;
+ }
+ col = newpos(col, ch);
+ }
+ if (indx + 1 > buf_max) {
+ buf_max += LINE_MAX;
+ buf = realloc(buf, sizeof(*buf) * buf_max);
+ if (buf == NULL)
+ err(1, "realloc()");
+ }
+ buf[indx++] = ch;
+ }
+
+ if (ferror(stdin)) {
+ fprintf(stderr, "Input error\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (indx != 0)
+ wprintf(L"%.*ls", indx, buf);
+}
+
+/*
+ * Update the current column position for a character.
+ */
+static int
+newpos(int col, wint_t ch)
+{
+ char buf[MB_LEN_MAX];
+ size_t len;
+ int w;
+
+ if (bflag) {
+ len = wcrtomb(buf, ch, NULL);
+ col += len;
+ } else
+ switch (ch) {
+ case '\b':
+ if (col > 0)
+ --col;
+ break;
+ case '\r':
+ col = 0;
+ break;
+ case '\t':
+ col = (col + 8) & ~7;
+ break;
+ default:
+ if ((w = wcwidth(ch)) > 0)
+ col += w;
+ break;
+ }
+
+ return (col);
+}
diff --git a/text_cmds/grep/file.c b/text_cmds/grep/file.c
new file mode 100644
index 0000000..54d8772
--- /dev/null
+++ b/text_cmds/grep/file.c
@@ -0,0 +1,347 @@
+/* $NetBSD: file.c,v 1.5 2011/02/16 18:35:39 joerg Exp $ */
+/* $FreeBSD: src/usr.bin/grep/file.c,v 1.7 2011/10/11 22:27:23 gabor Exp $ */
+/* $OpenBSD: file.c,v 1.11 2010/07/02 20:48:48 nicm Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2010 Dimitry Andric <dimitry@andric.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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/grep/file.c,v 1.7 2011/10/11 22:27:23 gabor Exp $");
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifndef WITHOUT_LZMA
+#include <lzma.h>
+#endif
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <zlib.h>
+
+#ifndef WITHOUT_BZIP2
+#include <bzlib.h>
+#endif
+
+#include "grep.h"
+
+#define MAXBUFSIZ (32 * 1024)
+#define LNBUFBUMP 80
+
+static gzFile gzbufdesc;
+#ifndef WITHOUT_LZMA
+static lzma_stream lstrm = LZMA_STREAM_INIT;
+#endif
+#ifndef WITHOUT_BZIP2
+static BZFILE* bzbufdesc;
+#endif
+
+static unsigned char *buffer;
+static unsigned char *bufpos;
+static size_t bufrem;
+static size_t fsiz;
+
+static unsigned char *lnbuf;
+static size_t lnbuflen;
+
+static inline int
+grep_refill(struct file *f)
+{
+ ssize_t nr;
+
+ if (filebehave == FILE_MMAP)
+ return (0);
+
+ bufpos = buffer;
+ bufrem = 0;
+
+ if (filebehave == FILE_GZIP) {
+ nr = gzread(gzbufdesc, buffer, MAXBUFSIZ);
+#ifndef WITHOUT_BZIP2
+ } else if (filebehave == FILE_BZIP && bzbufdesc != NULL) {
+ int bzerr;
+
+ nr = BZ2_bzRead(&bzerr, bzbufdesc, buffer, MAXBUFSIZ);
+ switch (bzerr) {
+ case BZ_OK:
+ case BZ_STREAM_END:
+ /* No problem, nr will be okay */
+ break;
+ case BZ_DATA_ERROR_MAGIC:
+ /*
+ * As opposed to gzread(), which simply returns the
+ * plain file data, if it is not in the correct
+ * compressed format, BZ2_bzRead() instead aborts.
+ *
+ * So, just restart at the beginning of the file again,
+ * and use plain reads from now on.
+ */
+ BZ2_bzReadClose(&bzerr, bzbufdesc);
+ bzbufdesc = NULL;
+ if (lseek(f->fd, 0, SEEK_SET) == -1)
+ return (-1);
+ nr = read(f->fd, buffer, MAXBUFSIZ);
+ break;
+ default:
+ /* Make sure we exit with an error */
+ nr = -1;
+ }
+#endif
+#ifndef WITHOUT_LZMA
+ } else if ((filebehave == FILE_XZ) || (filebehave == FILE_LZMA)) {
+ lzma_action action = LZMA_RUN;
+ uint8_t in_buf[MAXBUFSIZ];
+ lzma_ret ret;
+
+ ret = (filebehave == FILE_XZ) ?
+ lzma_stream_decoder(&lstrm, UINT64_MAX,
+ LZMA_CONCATENATED) :
+ lzma_alone_decoder(&lstrm, UINT64_MAX);
+
+ if (ret != LZMA_OK)
+ return (-1);
+
+ lstrm.next_out = buffer;
+ lstrm.avail_out = MAXBUFSIZ;
+ lstrm.next_in = in_buf;
+ nr = read(f->fd, in_buf, MAXBUFSIZ);
+
+ if (nr < 0)
+ return (-1);
+ else if (nr == 0)
+ action = LZMA_FINISH;
+
+ lstrm.avail_in = nr;
+ ret = lzma_code(&lstrm, action);
+
+ if (ret != LZMA_OK && ret != LZMA_STREAM_END)
+ return (-1);
+ bufrem = MAXBUFSIZ - lstrm.avail_out;
+ return (0);
+#endif
+ } else
+ nr = read(f->fd, buffer, MAXBUFSIZ);
+
+ if (nr < 0)
+ return (-1);
+
+ bufrem = nr;
+ return (0);
+}
+
+static inline int
+grep_lnbufgrow(size_t newlen)
+{
+
+ if (lnbuflen < newlen) {
+ lnbuf = grep_realloc(lnbuf, newlen);
+ lnbuflen = newlen;
+ }
+
+ return (0);
+}
+
+char *
+grep_fgetln(struct file *f, size_t *lenp)
+{
+ unsigned char *p;
+ char *ret;
+ size_t len;
+ size_t off;
+ ptrdiff_t diff;
+
+ /* Fill the buffer, if necessary */
+ if (bufrem == 0 && grep_refill(f) != 0)
+ goto error;
+
+ if (bufrem == 0) {
+ /* Return zero length to indicate EOF */
+ *lenp = 0;
+#ifdef __APPLE__
+ return (char *)(bufpos);
+#else
+ return (bufpos);
+#endif
+ }
+
+ /* Look for a newline in the remaining part of the buffer */
+ if ((p = memchr(bufpos, '\n', bufrem)) != NULL) {
+ ++p; /* advance over newline */
+#ifdef __APPLE__
+ ret = (char *)bufpos;
+#else
+ ret = bufpos;
+#endif
+ len = p - bufpos;
+ bufrem -= len;
+ bufpos = p;
+ *lenp = len;
+ return (ret);
+ }
+
+ /* We have to copy the current buffered data to the line buffer */
+ for (len = bufrem, off = 0; ; len += bufrem) {
+ /* Make sure there is room for more data */
+ if (grep_lnbufgrow(len + LNBUFBUMP))
+ goto error;
+ memcpy(lnbuf + off, bufpos, len - off);
+ off = len;
+ if (grep_refill(f) != 0)
+ goto error;
+ if (bufrem == 0)
+ /* EOF: return partial line */
+ break;
+ if ((p = memchr(bufpos, '\n', bufrem)) == NULL)
+ continue;
+ /* got it: finish up the line (like code above) */
+ ++p;
+ diff = p - bufpos;
+ len += diff;
+ if (grep_lnbufgrow(len))
+ goto error;
+ memcpy(lnbuf + off, bufpos, diff);
+ bufrem -= diff;
+ bufpos = p;
+ break;
+ }
+ *lenp = len;
+#ifdef __APPLE__
+ return (char *)(lnbuf);
+#else
+ return (lnbuf);
+#endif
+
+error:
+ *lenp = 0;
+ return (NULL);
+}
+
+/*
+ * Opens a file for processing.
+ */
+struct file *
+grep_open(const char *path)
+{
+ struct file *f;
+
+ f = grep_malloc(sizeof *f);
+ memset(f, 0, sizeof *f);
+ if (path == NULL) {
+ /* Processing stdin implies --line-buffered. */
+ lbflag = true;
+ f->fd = STDIN_FILENO;
+ } else if ((f->fd = open(path, O_RDONLY)) == -1)
+ goto error1;
+
+ if (filebehave == FILE_MMAP) {
+ struct stat st;
+
+ if ((fstat(f->fd, &st) == -1) || (st.st_size > OFF_MAX) ||
+ (!S_ISREG(st.st_mode)))
+ filebehave = FILE_STDIO;
+ else {
+#ifdef __APPLE__
+ int flags = MAP_PRIVATE | MAP_NOCACHE;
+#else
+ int flags = MAP_PRIVATE | MAP_NOCORE | MAP_NOSYNC;
+#endif
+#ifdef MAP_PREFAULT_READ
+ flags |= MAP_PREFAULT_READ;
+#endif
+ fsiz = st.st_size;
+ buffer = mmap(NULL, fsiz, PROT_READ, flags,
+ f->fd, (off_t)0);
+ if (buffer == MAP_FAILED)
+ filebehave = FILE_STDIO;
+ else {
+ bufrem = st.st_size;
+ bufpos = buffer;
+ madvise(buffer, st.st_size, MADV_SEQUENTIAL);
+ }
+ }
+ }
+
+ if ((buffer == NULL) || (buffer == MAP_FAILED))
+ buffer = grep_malloc(MAXBUFSIZ);
+
+ if (filebehave == FILE_GZIP &&
+ (gzbufdesc = gzdopen(f->fd, "r")) == NULL)
+ goto error2;
+
+#ifndef WITHOUT_BZIP2
+ if (filebehave == FILE_BZIP &&
+ (bzbufdesc = BZ2_bzdopen(f->fd, "r")) == NULL)
+ goto error2;
+#endif
+
+ /* Fill read buffer, also catches errors early */
+ if (bufrem == 0 && grep_refill(f) != 0)
+ goto error2;
+
+ /* Check for binary stuff, if necessary */
+ if (binbehave != BINFILE_TEXT && memchr(bufpos, '\0', bufrem) != NULL)
+ f->binary = true;
+
+ return (f);
+
+error2:
+ close(f->fd);
+error1:
+ free(f);
+ return (NULL);
+}
+
+/*
+ * Closes a file.
+ */
+void
+grep_close(struct file *f)
+{
+
+ close(f->fd);
+
+ /* Reset read buffer and line buffer */
+ if (filebehave == FILE_MMAP) {
+ munmap(buffer, fsiz);
+ buffer = NULL;
+ }
+ bufpos = buffer;
+ bufrem = 0;
+
+ free(lnbuf);
+ lnbuf = NULL;
+ lnbuflen = 0;
+}
diff --git a/text_cmds/grep/grep.1 b/text_cmds/grep/grep.1
new file mode 100644
index 0000000..a1d056e
--- /dev/null
+++ b/text_cmds/grep/grep.1
@@ -0,0 +1,500 @@
+.\" $NetBSD: grep.1,v 1.2 2011/02/16 01:31:33 joerg Exp $
+.\" $FreeBSD: src/usr.bin/grep/grep.1,v 1.5 2011/04/07 13:03:35 gabor Exp $
+.\" $OpenBSD: grep.1,v 1.38 2010/04/05 06:30:59 jmc Exp $
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" 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.
+.\"
+.\" @(#)grep.1 8.3 (Berkeley) 4/18/94
+.\"
+.Dd July 28, 2010
+.Dt GREP 1
+.Os
+.Sh NAME
+.Nm grep , egrep , fgrep ,
+.Nm zgrep , zegrep , zfgrep
+.Nd file pattern searcher
+.Sh SYNOPSIS
+.Nm grep
+.Bk -words
+.Op Fl abcdDEFGHhIiJLlmnOopqRSsUVvwxZ
+.Op Fl A Ar num
+.Op Fl B Ar num
+.Op Fl C Ns Op Ar num
+.Op Fl e Ar pattern
+.Op Fl f Ar file
+.Op Fl Fl binary-files Ns = Ns Ar value
+.Op Fl Fl color Ns Op = Ns Ar when
+.Op Fl Fl colour Ns Op = Ns Ar when
+.Op Fl Fl context Ns Op = Ns Ar num
+.Op Fl Fl label
+.Op Fl Fl line-buffered
+.Op Fl Fl null
+.Op Ar pattern
+.Op Ar
+.Ek
+.Sh DESCRIPTION
+The
+.Nm grep
+utility searches any given input files,
+selecting lines that match one or more patterns.
+By default, a pattern matches an input line if the regular expression
+(RE) in the pattern matches the input line
+without its trailing newline.
+An empty expression matches every line.
+Each input line that matches at least one of the patterns is written
+to the standard output.
+.Pp
+.Nm grep
+is used for simple patterns and
+basic regular expressions
+.Pq BREs ;
+.Nm egrep
+can handle extended regular expressions
+.Pq EREs .
+See
+.Xr re_format 7
+for more information on regular expressions.
+.Nm fgrep
+is quicker than both
+.Nm grep
+and
+.Nm egrep ,
+but can only handle fixed patterns
+(i.e. it does not interpret regular expressions).
+Patterns may consist of one or more lines,
+allowing any of the pattern lines to match a portion of the input.
+.Pp
+.Nm zgrep ,
+.Nm zegrep ,
+and
+.Nm zfgrep
+act like
+.Nm grep ,
+.Nm egrep ,
+and
+.Nm fgrep ,
+respectively, but accept input files compressed with the
+.Xr compress 1
+or
+.Xr gzip 1
+compression utilities.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl A Ar num , Fl Fl after-context Ns = Ns Ar num
+Print
+.Ar num
+lines of trailing context after each match.
+See also the
+.Fl B
+and
+.Fl C
+options.
+.It Fl a , Fl Fl text
+Treat all files as ASCII text.
+Normally
+.Nm
+will simply print
+.Dq Binary file ... matches
+if files contain binary characters.
+Use of this option forces
+.Nm
+to output lines matching the specified pattern.
+.It Fl B Ar num , Fl Fl before-context Ns = Ns Ar num
+Print
+.Ar num
+lines of leading context before each match.
+See also the
+.Fl A
+and
+.Fl C
+options.
+.It Fl b , Fl Fl byte-offset
+The offset in bytes of a matched pattern is
+displayed in front of the respective matched line.
+.It Fl C Ns Op Ar num , Fl Fl context Ns = Ns Ar num
+Print
+.Ar num
+lines of leading and trailing context surrounding each match.
+The default is 2 and is equivalent to
+.Fl A
+.Ar 2
+.Fl B
+.Ar 2 .
+Note:
+no whitespace may be given between the option and its argument.
+.It Fl c , Fl Fl count
+Only a count of selected lines is written to standard output.
+.It Fl Fl colour Ns = Ns Op Ar when , Fl Fl color Ns = Ns Op Ar when
+Mark up the matching text with the expression stored in
+.Ev GREP_COLOR
+environment variable.
+The possible values of when can be `never', `always' or `auto'.
+.It Fl D Ar action , Fl Fl devices Ns = Ns Ar action
+Specify the demanded action for devices, FIFOs and sockets.
+The default action is `read', which means, that they are read
+as if they were normal files.
+If the action is set to `skip', devices will be silently skipped.
+.It Fl d Ar action , Fl Fl directories Ns = Ns Ar action
+Specify the demanded action for directories.
+It is `read' by default, which means that the directories
+are read in the same manner as normal files.
+Other possible values are `skip' to silently ignore the
+directories, and `recurse' to read them recursively, which
+has the same effect as the
+.Fl R
+and
+.Fl r
+option.
+.It Fl E , Fl Fl extended-regexp
+Interpret
+.Ar pattern
+as an extended regular expression
+(i.e. force
+.Nm grep
+to behave as
+.Nm egrep ) .
+.It Fl e Ar pattern , Fl Fl regexp Ns = Ns Ar pattern
+Specify a pattern used during the search of the input:
+an input line is selected if it matches any of the specified patterns.
+This option is most useful when multiple
+.Fl e
+options are used to specify multiple patterns,
+or when a pattern begins with a dash
+.Pq Sq - .
+.It Fl Fl exclude
+If specified, it excludes files matching the given
+filename pattern from the search.
+Note that
+.Fl Fl exclude
+patterns take priority over
+.Fl Fl include
+patterns, and if no
+.Fl Fl include
+pattern is specified, all files are searched that are
+not excluded.
+Patterns are matched to the full path specified,
+not only to the filename component.
+.It Fl Fl exclude-dir
+If
+.Fl R
+is specified, it excludes directories matching the
+given filename pattern from the search.
+Note that
+.Fl Fl exclude-dir
+patterns take priority over
+.Fl Fl include-dir
+patterns, and if no
+.Fl Fl include-dir
+pattern is specified, all directories are searched that are
+not excluded.
+.It Fl F , Fl Fl fixed-strings
+Interpret
+.Ar pattern
+as a set of fixed strings
+(i.e. force
+.Nm grep
+to behave as
+.Nm fgrep ) .
+.It Fl f Ar file , Fl Fl file Ns = Ns Ar file
+Read one or more newline separated patterns from
+.Ar file .
+Empty pattern lines match every input line.
+Newlines are not considered part of a pattern.
+If
+.Ar file
+is empty, nothing is matched.
+.It Fl G , Fl Fl basic-regexp
+Interpret
+.Ar pattern
+as a basic regular expression
+(i.e. force
+.Nm grep
+to behave as traditional
+.Nm grep ) .
+.It Fl H
+Always print filename headers with output lines.
+.It Fl h , Fl Fl no-filename
+Never print filename headers
+.Pq i.e. filenames
+with output lines.
+.It Fl Fl help
+Print a brief help message.
+.It Fl I
+Ignore binary files.
+This option is equivalent to
+.Fl Fl binary-file Ns = Ns Ar without-match
+option.
+.It Fl i , Fl Fl ignore-case
+Perform case insensitive matching.
+By default,
+.Nm grep
+is case sensitive.
+.It Fl Fl include
+If specified, only files matching the
+given filename pattern are searched.
+Note that
+.Fl Fl exclude
+patterns take priority over
+.Fl Fl include
+patterns.
+Patterns are matched to the full path specified,
+not only to the filename component.
+.It Fl Fl include-dir
+If
+.Fl R
+is specified, only directories matching the
+given filename pattern are searched.
+Note that
+.Fl Fl exclude-dir
+patterns take priority over
+.Fl Fl include-dir
+patterns.
+.It Fl J, Fl Fl bz2decompress
+Decompress the
+.Xr bzip2 1
+compressed file before looking for the text.
+.It Fl L , Fl Fl files-without-match
+Only the names of files not containing selected lines are written to
+standard output.
+Pathnames are listed once per file searched.
+If the standard input is searched, the string
+.Dq (standard input)
+is written.
+.It Fl l , Fl Fl files-with-matches
+Only the names of files containing selected lines are written to
+standard output.
+.Nm grep
+will only search a file until a match has been found,
+making searches potentially less expensive.
+Pathnames are listed once per file searched.
+If the standard input is searched, the string
+.Dq (standard input)
+is written.
+.It Fl Fl mmap
+Use
+.Xr mmap 2
+instead of
+.Xr read 2
+to read input, which can result in better performance under some
+circumstances but can cause undefined behaviour.
+.It Fl m Ar num, Fl Fl max-count Ns = Ns Ar num
+Stop reading the file after
+.Ar num
+matches.
+.It Fl n , Fl Fl line-number
+Each output line is preceded by its relative line number in the file,
+starting at line 1.
+The line number counter is reset for each file processed.
+This option is ignored if
+.Fl c ,
+.Fl L ,
+.Fl l ,
+or
+.Fl q
+is
+specified.
+.It Fl Fl null
+Prints a zero-byte after the file name.
+.It Fl O
+If
+.Fl R
+is specified, follow symbolic links only if they were explicitly listed
+on the command line.
+The default is not to follow symbolic links.
+.It Fl o, Fl Fl only-matching
+Prints only the matching part of the lines.
+.It Fl p
+If
+.Fl R
+is specified, no symbolic links are followed.
+This is the default.
+.It Fl q , Fl Fl quiet , Fl Fl silent
+Quiet mode:
+suppress normal output.
+.Nm grep
+will only search a file until a match has been found,
+making searches potentially less expensive.
+.It Fl R , Fl r , Fl Fl recursive
+Recursively search subdirectories listed.
+.It Fl S
+If
+.Fl R
+is specified, all symbolic links are followed.
+The default is not to follow symbolic links.
+.It Fl s , Fl Fl no-messages
+Silent mode.
+Nonexistent and unreadable files are ignored
+(i.e. their error messages are suppressed).
+.It Fl U , Fl Fl binary
+Search binary files, but do not attempt to print them.
+.It Fl V , Fl Fl version
+Display version information and exit.
+.It Fl v , Fl Fl invert-match
+Selected lines are those
+.Em not
+matching any of the specified patterns.
+.It Fl w , Fl Fl word-regexp
+The expression is searched for as a word (as if surrounded by
+.Sq [[:<:]]
+and
+.Sq [[:>:]] ;
+see
+.Xr re_format 7 ) .
+.It Fl x , Fl Fl line-regexp
+Only input lines selected against an entire fixed string or regular
+expression are considered to be matching lines.
+.It Fl y
+Equivalent to
+.Fl i .
+Obsoleted.
+.It Fl Z , Fl z , Fl Fl decompress
+Force
+.Nm grep
+to behave as
+.Nm zgrep .
+.It Fl Fl binary-files Ns = Ns Ar value
+Controls searching and printing of binary files.
+Options are
+.Ar binary ,
+the default: search binary files but do not print them;
+.Ar without-match :
+do not search binary files;
+and
+.Ar text :
+treat all files as text.
+.Sm off
+.It Fl Fl context Op = Ar num
+.Sm on
+Print
+.Ar num
+lines of leading and trailing context.
+The default is 2.
+.It Fl Fl line-buffered
+Force output to be line buffered.
+By default, output is line buffered when standard output is a terminal
+and block buffered otherwise.
+.Pp
+.El
+If no file arguments are specified, the standard input is used.
+.Sh ENVIRONMENT
+.Bl -tag -width "GREP_OPTIONS"
+.It Ev GREP_OPTIONS
+May be used to specify default options that will be placed at the beginning
+of the argument list.
+Backslash-escaping is not supported, unlike the behavior in GNU grep.
+.El
+.Sh EXIT STATUS
+The
+.Nm grep
+utility exits with one of the following values:
+.Pp
+.Bl -tag -width flag -compact
+.It Li 0
+One or more lines were selected.
+.It Li 1
+No lines were selected.
+.It Li \*(Gt1
+An error occurred.
+.El
+.Sh EXAMPLES
+To find all occurrences of the word
+.Sq patricia
+in a file:
+.Pp
+.Dl $ grep 'patricia' myfile
+.Pp
+To find all occurrences of the pattern
+.Ql .Pp
+at the beginning of a line:
+.Pp
+.Dl $ grep '^\e.Pp' myfile
+.Pp
+The apostrophes ensure the entire expression is evaluated by
+.Nm grep
+instead of by the user's shell.
+The caret
+.Ql ^
+matches the null string at the beginning of a line,
+and the
+.Ql \e
+escapes the
+.Ql \&. ,
+which would otherwise match any character.
+.Pp
+To find all lines in a file which do not contain the words
+.Sq foo
+or
+.Sq bar :
+.Pp
+.Dl $ grep -v -e 'foo' -e 'bar' myfile
+.Pp
+A simple example of an extended regular expression:
+.Pp
+.Dl $ egrep '19|20|25' calendar
+.Pp
+Peruses the file
+.Sq calendar
+looking for either 19, 20, or 25.
+.Sh SEE ALSO
+.Xr ed 1 ,
+.Xr ex 1 ,
+.Xr gzip 1 ,
+.Xr sed 1 ,
+.Xr re_format 7
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -p1003.1-2008
+specification.
+.Pp
+The flags
+.Op Fl AaBbCDdGHhIJLmoPRSUVwZ
+are extensions to that specification, and the behaviour of the
+.Fl f
+flag when used with an empty pattern file is left undefined.
+.Pp
+All long options are provided for compatibility with
+GNU versions of this utility.
+.Pp
+Historic versions of the
+.Nm grep
+utility also supported the flags
+.Op Fl ruy .
+This implementation supports those options;
+however, their use is strongly discouraged.
+.Sh HISTORY
+The
+.Nm grep
+command first appeared in
+.At v6 .
+.Sh BUGS
+The
+.Nm
+utility does not normalize Unicode input, so a pattern containing composed
+characters will not match decomposed input, and vice versa.
diff --git a/text_cmds/grep/grep.c b/text_cmds/grep/grep.c
new file mode 100644
index 0000000..38f50ea
--- /dev/null
+++ b/text_cmds/grep/grep.c
@@ -0,0 +1,783 @@
+/* $NetBSD: grep.c,v 1.4 2011/02/16 01:31:33 joerg Exp $ */
+/* $FreeBSD: src/usr.bin/grep/grep.c,v 1.16 2012/01/15 17:01:28 eadler Exp $ */
+/* $OpenBSD: grep.c,v 1.42 2010/07/02 22:18:03 tedu Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/grep/grep.c,v 1.16 2012/01/15 17:01:28 eadler Exp $");
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <libgen.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef WITHOUT_FASTMATCH
+#include "fastmatch.h"
+#endif
+#include "grep.h"
+
+#ifndef WITHOUT_NLS
+#include <nl_types.h>
+nl_catd catalog;
+#endif
+
+/*
+ * Default messags to use when NLS is disabled or no catalogue
+ * is found.
+ */
+const char *errstr[] = {
+ "",
+/* 1*/ "(standard input)",
+/* 2*/ "cannot read bzip2 compressed file",
+/* 3*/ "unknown %s option",
+#ifdef __APPLE__
+/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n",
+#else
+/* 4*/ "usage: %s [-abcDEFGHhIiJLlmnOoPqRSsUVvwxZ] [-A num] [-B num] [-C[num]]\n",
+#endif
+/* 5*/ "\t[-e pattern] [-f file] [--binary-files=value] [--color=when]\n",
+/* 6*/ "\t[--context[=num]] [--directories=action] [--label] [--line-buffered]\n",
+/* 7*/ "\t[--null] [pattern] [file ...]\n",
+/* 8*/ "Binary file %s matches\n",
+/* 9*/ "%s (BSD grep) %s\n",
+};
+
+/* Flags passed to regcomp() and regexec() */
+int cflags = REG_NOSUB;
+int eflags = REG_STARTEND;
+
+/* Shortcut for matching all cases like empty regex */
+bool matchall;
+
+/* Searching patterns */
+unsigned int patterns, pattern_sz;
+struct pat *pattern;
+regex_t *r_pattern;
+#ifndef WITHOUT_FASTMATCH
+fastmatch_t *fg_pattern;
+#endif
+
+/* Filename exclusion/inclusion patterns */
+unsigned int fpatterns, fpattern_sz;
+unsigned int dpatterns, dpattern_sz;
+struct epat *dpattern, *fpattern;
+
+/* For regex errors */
+char re_error[RE_ERROR_BUF + 1];
+
+/* Command-line flags */
+unsigned long long Aflag; /* -A x: print x lines trailing each match */
+unsigned long long Bflag; /* -B x: print x lines leading each match */
+bool Hflag; /* -H: always print file name */
+bool Lflag; /* -L: only show names of files with no matches */
+bool bflag; /* -b: show block numbers for each match */
+bool cflag; /* -c: only show a count of matching lines */
+bool hflag; /* -h: don't print filename headers */
+bool iflag; /* -i: ignore case */
+bool lflag; /* -l: only show names of files with matches */
+bool mflag; /* -m x: stop reading the files after x matches */
+long long mcount; /* count for -m */
+bool nflag; /* -n: show line numbers in front of matching lines */
+bool oflag; /* -o: print only matching part */
+bool qflag; /* -q: quiet mode (don't output anything) */
+bool sflag; /* -s: silent mode (ignore errors) */
+bool vflag; /* -v: only show non-matching lines */
+bool wflag; /* -w: pattern must start and end on word boundaries */
+bool xflag; /* -x: pattern must match entire line */
+bool lbflag; /* --line-buffered */
+bool nullflag; /* --null */
+char *label; /* --label */
+const char *color; /* --color */
+int grepbehave = GREP_BASIC; /* -EFGP: type of the regex */
+int binbehave = BINFILE_BIN; /* -aIU: handling of binary files */
+int filebehave = FILE_STDIO; /* -JZ: normal, gzip or bzip2 file */
+int devbehave = DEV_READ; /* -D: handling of devices */
+int dirbehave = DIR_READ; /* -dRr: handling of directories */
+int linkbehave = LINK_READ; /* -OpS: handling of symlinks */
+
+bool dexclude, dinclude; /* --exclude-dir and --include-dir */
+bool fexclude, finclude; /* --exclude and --include */
+
+enum {
+ BIN_OPT = CHAR_MAX + 1,
+ COLOR_OPT,
+ HELP_OPT,
+ MMAP_OPT,
+ LINEBUF_OPT,
+ LABEL_OPT,
+ NULL_OPT,
+ R_EXCLUDE_OPT,
+ R_INCLUDE_OPT,
+ R_DEXCLUDE_OPT,
+ R_DINCLUDE_OPT
+};
+
+static inline const char *init_color(const char *);
+
+/* Housekeeping */
+bool first = true; /* flag whether we are processing the first match */
+bool prev; /* flag whether or not the previous line matched */
+int tail; /* lines left to print */
+bool file_err; /* file reading error */
+
+/*
+ * Prints usage information and returns 2.
+ */
+static void
+usage(void)
+{
+ fprintf(stderr, getstr(4), getprogname());
+ fprintf(stderr, "%s", getstr(5));
+ fprintf(stderr, "%s", getstr(6));
+ fprintf(stderr, "%s", getstr(7));
+ exit(2);
+}
+
+static const char *optstr = "0123456789A:B:C:D:EFGHIJMLOPSRUVZabcd:e:f:hilm:nopqrsuvwxXy";
+
+static const struct option long_options[] =
+{
+ {"binary-files", required_argument, NULL, BIN_OPT},
+ {"help", no_argument, NULL, HELP_OPT},
+ {"mmap", no_argument, NULL, MMAP_OPT},
+ {"line-buffered", no_argument, NULL, LINEBUF_OPT},
+ {"label", required_argument, NULL, LABEL_OPT},
+ {"null", no_argument, NULL, NULL_OPT},
+ {"color", optional_argument, NULL, COLOR_OPT},
+ {"colour", optional_argument, NULL, COLOR_OPT},
+ {"exclude", required_argument, NULL, R_EXCLUDE_OPT},
+ {"include", required_argument, NULL, R_INCLUDE_OPT},
+ {"exclude-dir", required_argument, NULL, R_DEXCLUDE_OPT},
+ {"include-dir", required_argument, NULL, R_DINCLUDE_OPT},
+ {"after-context", required_argument, NULL, 'A'},
+ {"text", no_argument, NULL, 'a'},
+ {"before-context", required_argument, NULL, 'B'},
+ {"byte-offset", no_argument, NULL, 'b'},
+ {"context", optional_argument, NULL, 'C'},
+ {"count", no_argument, NULL, 'c'},
+ {"devices", required_argument, NULL, 'D'},
+ {"directories", required_argument, NULL, 'd'},
+ {"extended-regexp", no_argument, NULL, 'E'},
+ {"regexp", required_argument, NULL, 'e'},
+ {"fixed-strings", no_argument, NULL, 'F'},
+ {"file", required_argument, NULL, 'f'},
+ {"basic-regexp", no_argument, NULL, 'G'},
+ {"no-filename", no_argument, NULL, 'h'},
+ {"with-filename", no_argument, NULL, 'H'},
+ {"ignore-case", no_argument, NULL, 'i'},
+ {"bz2decompress", no_argument, NULL, 'J'},
+ {"files-with-matches", no_argument, NULL, 'l'},
+ {"files-without-match", no_argument, NULL, 'L'},
+ {"max-count", required_argument, NULL, 'm'},
+ {"lzma", no_argument, NULL, 'M'},
+ {"line-number", no_argument, NULL, 'n'},
+ {"only-matching", no_argument, NULL, 'o'},
+ {"quiet", no_argument, NULL, 'q'},
+ {"silent", no_argument, NULL, 'q'},
+ {"recursive", no_argument, NULL, 'r'},
+ {"no-messages", no_argument, NULL, 's'},
+ {"binary", no_argument, NULL, 'U'},
+ {"unix-byte-offsets", no_argument, NULL, 'u'},
+ {"invert-match", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {"word-regexp", no_argument, NULL, 'w'},
+ {"line-regexp", no_argument, NULL, 'x'},
+ {"xz", no_argument, NULL, 'X'},
+ {"decompress", no_argument, NULL, 'Z'},
+ {NULL, no_argument, NULL, 0}
+};
+
+/*
+ * Adds a searching pattern to the internal array.
+ */
+static void
+add_pattern(char *pat, size_t len)
+{
+
+ /* Do not add further pattern is we already match everything */
+ if (matchall)
+ return;
+
+ /* Check if we can do a shortcut */
+ if (len == 0) {
+ matchall = true;
+#ifndef WITHOUT_FASTMATCH
+ for (unsigned int i = 0; i < patterns; i++) {
+ free(pattern[i].pat);
+ }
+ pattern = grep_realloc(pattern, sizeof(struct pat));
+ pattern[0].pat = NULL;
+ pattern[0].len = 0;
+ patterns = 1;
+#endif
+ return;
+ }
+ /* Increase size if necessary */
+ if (patterns == pattern_sz) {
+ pattern_sz *= 2;
+ pattern = grep_realloc(pattern, ++pattern_sz *
+ sizeof(struct pat));
+ }
+ if (len > 0 && pat[len - 1] == '\n')
+ --len;
+ /* pat may not be NUL-terminated */
+ pattern[patterns].pat = grep_malloc(len + 1);
+ memcpy(pattern[patterns].pat, pat, len);
+ pattern[patterns].len = len;
+ pattern[patterns].pat[len] = '\0';
+ ++patterns;
+}
+
+/*
+ * Adds a file include/exclude pattern to the internal array.
+ */
+static void
+add_fpattern(const char *pat, int mode)
+{
+
+ /* Increase size if necessary */
+ if (fpatterns == fpattern_sz) {
+ fpattern_sz *= 2;
+ fpattern = grep_realloc(fpattern, ++fpattern_sz *
+ sizeof(struct epat));
+ }
+ fpattern[fpatterns].pat = grep_strdup(pat);
+ fpattern[fpatterns].mode = mode;
+ ++fpatterns;
+}
+
+/*
+ * Adds a directory include/exclude pattern to the internal array.
+ */
+static void
+add_dpattern(const char *pat, int mode)
+{
+
+ /* Increase size if necessary */
+ if (dpatterns == dpattern_sz) {
+ dpattern_sz *= 2;
+ dpattern = grep_realloc(dpattern, ++dpattern_sz *
+ sizeof(struct epat));
+ }
+ dpattern[dpatterns].pat = grep_strdup(pat);
+ dpattern[dpatterns].mode = mode;
+ ++dpatterns;
+}
+
+/*
+ * Adds search patterns from arguments.
+ */
+static void
+add_arg_patterns(const char *arg)
+{
+ char *argcopy, *pattern;
+
+ argcopy = grep_strdup(arg);
+ while ((pattern = strsep(&argcopy, "\n")) != NULL) {
+ add_pattern(pattern, strlen(pattern));
+ }
+ free(argcopy);
+}
+
+/*
+ * Reads searching patterns from a file and adds them with add_pattern().
+ */
+static void
+read_patterns(const char *fn)
+{
+ struct stat st;
+ FILE *f;
+ char *line;
+ size_t len;
+
+ if ((f = fopen(fn, "r")) == NULL)
+ err(2, "%s", fn);
+ if ((fstat(fileno(f), &st) == -1) || (S_ISDIR(st.st_mode))) {
+ fclose(f);
+ return;
+ }
+ while ((line = fgetln(f, &len)) != NULL)
+ add_pattern(line, line[0] == '\n' ? 0 : len);
+ if (ferror(f))
+ err(2, "%s", fn);
+ fclose(f);
+}
+
+static inline const char *
+init_color(const char *d)
+{
+ char *c;
+
+ c = getenv("GREP_COLOR");
+ return (c != NULL && c[0] != '\0' ? c : d);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char **aargv, **eargv, *eopts;
+ char *ep;
+ const char *pn;
+ unsigned long long l;
+ unsigned int aargc, eargc, i;
+ int c, lastc, needpattern, newarg, prevoptind;
+
+ setlocale(LC_ALL, "");
+
+#ifndef WITHOUT_NLS
+ catalog = catopen("grep", NL_CAT_LOCALE);
+#endif
+
+ /* Check what is the program name of the binary. In this
+ way we can have all the funcionalities in one binary
+ without the need of scripting and using ugly hacks. */
+ pn = getprogname();
+ if (pn[0] == 'b' && pn[1] == 'z') {
+ filebehave = FILE_BZIP;
+ pn += 2;
+ } else if (pn[0] == 'x' && pn[1] == 'z') {
+ filebehave = FILE_XZ;
+ pn += 2;
+ } else if (pn[0] == 'l' && pn[1] == 'z') {
+ filebehave = FILE_LZMA;
+ pn += 2;
+ } else if (pn[0] == 'z') {
+ filebehave = FILE_GZIP;
+ pn += 1;
+ }
+ switch (pn[0]) {
+ case 'e':
+ grepbehave = GREP_EXTENDED;
+ break;
+ case 'f':
+ grepbehave = GREP_FIXED;
+ break;
+ }
+
+ lastc = '\0';
+ newarg = 1;
+ prevoptind = 1;
+ needpattern = 1;
+
+ eopts = getenv("GREP_OPTIONS");
+
+ /* support for extra arguments in GREP_OPTIONS */
+ eargc = 0;
+ if (eopts != NULL && eopts[0] != '\0') {
+ char *str;
+
+ /* make an estimation of how many extra arguments we have */
+ for (unsigned int j = 0; j < strlen(eopts); j++)
+ if (eopts[j] == ' ')
+ eargc++;
+
+ eargv = (char **)grep_malloc(sizeof(char *) * (eargc + 1));
+
+ eargc = 0;
+ /* parse extra arguments */
+ while ((str = strsep(&eopts, " ")) != NULL)
+ if (str[0] != '\0')
+ eargv[eargc++] = grep_strdup(str);
+
+ aargv = (char **)grep_calloc(eargc + argc + 1,
+ sizeof(char *));
+
+ aargv[0] = argv[0];
+ for (i = 0; i < eargc; i++)
+ aargv[i + 1] = eargv[i];
+ for (int j = 1; j < argc; j++, i++)
+ aargv[i + 1] = argv[j];
+
+ aargc = eargc + argc;
+ } else {
+ aargv = argv;
+ aargc = argc;
+ }
+
+ while (((c = getopt_long(aargc, aargv, optstr, long_options, NULL)) !=
+ -1)) {
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (newarg || !isdigit(lastc))
+ Aflag = 0;
+ else if (Aflag > LLONG_MAX / 10) {
+ errno = ERANGE;
+ err(2, NULL);
+ }
+ Aflag = Bflag = (Aflag * 10) + (c - '0');
+ break;
+ case 'C':
+ if (optarg == NULL) {
+ Aflag = Bflag = 2;
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'A':
+ /* FALLTHROUGH */
+ case 'B':
+ errno = 0;
+ l = strtoull(optarg, &ep, 10);
+ if (((errno == ERANGE) && (l == ULLONG_MAX)) ||
+ ((errno == EINVAL) && (l == 0)))
+ err(2, NULL);
+ else if (ep[0] != '\0') {
+ errno = EINVAL;
+ err(2, NULL);
+ }
+ if (c == 'A')
+ Aflag = l;
+ else if (c == 'B')
+ Bflag = l;
+ else
+ Aflag = Bflag = l;
+ break;
+ case 'a':
+ binbehave = BINFILE_TEXT;
+ break;
+ case 'b':
+ bflag = true;
+ break;
+ case 'c':
+ cflag = true;
+ break;
+ case 'D':
+ if (strcasecmp(optarg, "skip") == 0)
+ devbehave = DEV_SKIP;
+ else if (strcasecmp(optarg, "read") == 0)
+ devbehave = DEV_READ;
+ else
+ errx(2, getstr(3), "--devices");
+ break;
+ case 'd':
+ if (strcasecmp("recurse", optarg) == 0) {
+ Hflag = true;
+ dirbehave = DIR_RECURSE;
+ } else if (strcasecmp("skip", optarg) == 0)
+ dirbehave = DIR_SKIP;
+ else if (strcasecmp("read", optarg) == 0)
+ dirbehave = DIR_READ;
+ else
+ errx(2, getstr(3), "--directories");
+ break;
+ case 'E':
+ grepbehave = GREP_EXTENDED;
+ break;
+ case 'e':
+ add_arg_patterns(optarg);
+ needpattern = 0;
+ break;
+ case 'F':
+ grepbehave = GREP_FIXED;
+ break;
+ case 'f':
+ read_patterns(optarg);
+ needpattern = 0;
+ break;
+ case 'G':
+ grepbehave = GREP_BASIC;
+ break;
+ case 'H':
+ Hflag = true;
+ break;
+ case 'h':
+ Hflag = false;
+ hflag = true;
+ break;
+ case 'I':
+ binbehave = BINFILE_SKIP;
+ break;
+ case 'i':
+ case 'y':
+ iflag = true;
+ cflags |= REG_ICASE;
+ break;
+ case 'J':
+#ifdef WITHOUT_BZIP2
+ errno = EOPNOTSUPP;
+ err(2, "bzip2 support was disabled at compile-time");
+#endif
+ filebehave = FILE_BZIP;
+ break;
+ case 'L':
+ lflag = false;
+ Lflag = true;
+ break;
+ case 'l':
+ Lflag = false;
+ lflag = true;
+ break;
+ case 'm':
+ mflag = true;
+ errno = 0;
+ mcount = strtoll(optarg, &ep, 10);
+ if (((errno == ERANGE) && (mcount == LLONG_MAX)) ||
+ ((errno == EINVAL) && (mcount == 0)))
+ err(2, NULL);
+ else if (ep[0] != '\0') {
+ errno = EINVAL;
+ err(2, NULL);
+ }
+ break;
+ case 'M':
+#ifdef WITHOUT_LZMA
+ errno = EOPNOTSUPP;
+ err(2, "lzma support was disabled at compile-time");
+#endif
+ filebehave = FILE_LZMA;
+ break;
+ case 'n':
+ nflag = true;
+ break;
+ case 'O':
+ linkbehave = LINK_EXPLICIT;
+ break;
+ case 'o':
+ oflag = true;
+ cflags &= ~REG_NOSUB;
+ break;
+ case 'p':
+ linkbehave = LINK_SKIP;
+ break;
+ case 'q':
+ qflag = true;
+ break;
+ case 'S':
+ linkbehave = LINK_READ;
+ break;
+ case 'R':
+ case 'r':
+ dirbehave = DIR_RECURSE;
+ Hflag = true;
+ break;
+ case 's':
+ sflag = true;
+ break;
+ case 'U':
+ binbehave = BINFILE_BIN;
+ break;
+ case 'u':
+ case MMAP_OPT:
+#ifndef __APPLE__
+ /* mmap mode is buggy (10789286) */
+ filebehave = FILE_MMAP;
+#endif
+ break;
+ case 'V':
+ printf(getstr(9), getprogname(), VERSION);
+ exit(0);
+ case 'v':
+ vflag = true;
+ break;
+ case 'w':
+ wflag = true;
+ cflags &= ~REG_NOSUB;
+ break;
+ case 'x':
+ xflag = true;
+ cflags &= ~REG_NOSUB;
+ break;
+ case 'X':
+#ifdef WITHOUT_LZMA
+ errno = EOPNOTSUPP;
+ err(2, "xz support was disabled at compile-time");
+#endif
+ filebehave = FILE_XZ;
+ break;
+ case 'Z':
+ filebehave = FILE_GZIP;
+ break;
+ case BIN_OPT:
+ if (strcasecmp("binary", optarg) == 0)
+ binbehave = BINFILE_BIN;
+ else if (strcasecmp("without-match", optarg) == 0)
+ binbehave = BINFILE_SKIP;
+ else if (strcasecmp("text", optarg) == 0)
+ binbehave = BINFILE_TEXT;
+ else
+ errx(2, getstr(3), "--binary-files");
+ break;
+ case COLOR_OPT:
+ color = NULL;
+ if (optarg == NULL || strcasecmp("auto", optarg) == 0 ||
+ strcasecmp("tty", optarg) == 0 ||
+ strcasecmp("if-tty", optarg) == 0) {
+ char *term;
+
+ term = getenv("TERM");
+ if (isatty(STDOUT_FILENO) && term != NULL &&
+ strcasecmp(term, "dumb") != 0)
+ color = init_color("01;31");
+ } else if (strcasecmp("always", optarg) == 0 ||
+ strcasecmp("yes", optarg) == 0 ||
+ strcasecmp("force", optarg) == 0) {
+ color = init_color("01;31");
+ } else if (strcasecmp("never", optarg) != 0 &&
+ strcasecmp("none", optarg) != 0 &&
+ strcasecmp("no", optarg) != 0)
+ errx(2, getstr(3), "--color");
+ cflags &= ~REG_NOSUB;
+ break;
+ case LABEL_OPT:
+ label = optarg;
+ break;
+ case LINEBUF_OPT:
+ lbflag = true;
+ break;
+ case NULL_OPT:
+ nullflag = true;
+ break;
+ case R_INCLUDE_OPT:
+ finclude = true;
+ add_fpattern(optarg, INCL_PAT);
+ break;
+ case R_EXCLUDE_OPT:
+ fexclude = true;
+ add_fpattern(optarg, EXCL_PAT);
+ break;
+ case R_DINCLUDE_OPT:
+ dinclude = true;
+ add_dpattern(optarg, INCL_PAT);
+ break;
+ case R_DEXCLUDE_OPT:
+ dexclude = true;
+ add_dpattern(optarg, EXCL_PAT);
+ break;
+ case HELP_OPT:
+ default:
+ usage();
+ }
+ lastc = c;
+ newarg = optind != prevoptind;
+ prevoptind = optind;
+ }
+ aargc -= optind;
+ aargv += optind;
+
+ /* Empty pattern file matches nothing */
+#ifndef WITHOUT_FASTMATCH
+ if (!needpattern && (patterns == 0))
+#else
+ if (!needpattern && (patterns == 0) && !matchall)
+#endif
+ exit(1);
+
+ /* Fail if we don't have any pattern */
+ if (aargc == 0 && needpattern)
+ usage();
+
+ /* Process patterns from command line */
+ if (aargc != 0 && needpattern) {
+ add_arg_patterns(*aargv);
+ --aargc;
+ ++aargv;
+ }
+
+ switch (grepbehave) {
+ case GREP_BASIC:
+#ifdef __APPLE__
+ cflags |= REG_ENHANCED;
+#endif
+ break;
+ case GREP_FIXED:
+ /* XXX: header mess, REG_LITERAL not defined in gnu/regex.h */
+ cflags |= 0020;
+ break;
+ case GREP_EXTENDED:
+ cflags |= REG_EXTENDED;
+#ifdef __APPLE__
+ cflags |= REG_ENHANCED;
+#endif
+ break;
+ default:
+ /* NOTREACHED */
+ usage();
+ }
+
+#ifndef WITHOUT_FASTMATCH
+ fg_pattern = grep_calloc(patterns, sizeof(*fg_pattern));
+#endif
+ r_pattern = grep_calloc(patterns, sizeof(*r_pattern));
+
+ /* Check if cheating is allowed (always is for fgrep). */
+ for (i = 0; i < patterns; ++i) {
+#ifndef WITHOUT_FASTMATCH
+ if (fastncomp(&fg_pattern[i], pattern[i].pat,
+ pattern[i].len, cflags) != 0) {
+#endif
+ /* Fall back to full regex library */
+ c = regcomp(&r_pattern[i], pattern[i].pat, cflags);
+ if (c != 0) {
+ regerror(c, &r_pattern[i], re_error,
+ RE_ERROR_BUF);
+ errx(2, "%s", re_error);
+ }
+#ifndef WITHOUT_FASTMATCH
+ }
+#endif
+ }
+
+ if (lbflag)
+ setlinebuf(stdout);
+
+ if ((aargc == 0 || aargc == 1) && !Hflag)
+ hflag = true;
+
+ if (aargc == 0)
+ exit(!procfile("-"));
+
+ if (dirbehave == DIR_RECURSE)
+ c = grep_tree(aargv);
+ else
+ for (c = 0; aargc--; ++aargv) {
+ if ((finclude || fexclude) && !file_matching(*aargv))
+ continue;
+ c+= procfile(*aargv);
+ }
+
+#ifndef WITHOUT_NLS
+ catclose(catalog);
+#endif
+
+ /* Find out the correct return value according to the
+ results and the command line option. */
+ exit(c ? (file_err ? (qflag ? 0 : 2) : 0) : (file_err ? 2 : 1));
+}
diff --git a/text_cmds/grep/grep.h b/text_cmds/grep/grep.h
new file mode 100644
index 0000000..c46e172
--- /dev/null
+++ b/text_cmds/grep/grep.h
@@ -0,0 +1,161 @@
+/* $NetBSD: grep.h,v 1.5 2011/02/27 17:33:37 joerg Exp $ */
+/* $OpenBSD: grep.h,v 1.15 2010/04/05 03:03:55 tedu Exp $ */
+/* $FreeBSD: src/usr.bin/grep/grep.h,v 1.10 2011/12/07 12:25:28 gabor Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (c) 2008-2009 Gabor Kovesdan <gabor@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 <bzlib.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <zlib.h>
+
+#ifndef WITHOUT_FASTMATCH
+#include "fastmatch.h"
+#endif
+
+#ifdef WITHOUT_NLS
+#define getstr(n) errstr[n]
+#else
+#include <nl_types.h>
+
+extern nl_catd catalog;
+#define getstr(n) catgets(catalog, 1, n, errstr[n])
+#endif
+
+extern const char *errstr[];
+
+#define VERSION "2.5.1-FreeBSD"
+
+#define GREP_FIXED 0
+#define GREP_BASIC 1
+#define GREP_EXTENDED 2
+
+#define BINFILE_BIN 0
+#define BINFILE_SKIP 1
+#define BINFILE_TEXT 2
+
+#define FILE_STDIO 0
+#define FILE_MMAP 1
+#define FILE_GZIP 2
+#define FILE_BZIP 3
+#define FILE_XZ 4
+#define FILE_LZMA 5
+
+#define DIR_READ 0
+#define DIR_SKIP 1
+#define DIR_RECURSE 2
+
+#define DEV_READ 0
+#define DEV_SKIP 1
+
+#define LINK_READ 0
+#define LINK_EXPLICIT 1
+#define LINK_SKIP 2
+
+#define EXCL_PAT 0
+#define INCL_PAT 1
+
+#ifdef __APPLE__
+#define MIN_LINE_MATCHES 32
+#define MAX_LINE_MATCHES 1073741824
+#else
+#define MAX_LINE_MATCHES 32
+#endif
+
+struct file {
+ int fd;
+ bool binary;
+};
+
+struct str {
+ off_t off;
+ size_t len;
+ char *dat;
+ char *file;
+ int line_no;
+};
+
+struct pat {
+ char *pat;
+ int len;
+};
+
+struct epat {
+ char *pat;
+ int mode;
+};
+
+/* Flags passed to regcomp() and regexec() */
+extern int cflags, eflags;
+
+/* Command line flags */
+extern bool Eflag, Fflag, Gflag, Hflag, Lflag,
+ bflag, cflag, hflag, iflag, lflag, mflag, nflag, oflag,
+ qflag, sflag, vflag, wflag, xflag;
+extern bool dexclude, dinclude, fexclude, finclude, lbflag, nullflag;
+extern unsigned long long Aflag, Bflag;
+extern long long mcount;
+extern char *label;
+extern const char *color;
+extern int binbehave, devbehave, dirbehave, filebehave, grepbehave, linkbehave;
+
+extern bool file_err, first, matchall, prev;
+extern int tail;
+extern unsigned int dpatterns, fpatterns, patterns;
+extern struct pat *pattern;
+extern struct epat *dpattern, *fpattern;
+extern regex_t *er_pattern, *r_pattern;
+#ifndef WITHOUT_FASTMATCH
+extern fastmatch_t *fg_pattern;
+#endif
+
+/* For regex errors */
+#define RE_ERROR_BUF 512
+extern char re_error[RE_ERROR_BUF + 1]; /* Seems big enough */
+
+/* util.c */
+bool file_matching(const char *fname);
+int procfile(const char *fn);
+int grep_tree(char **argv);
+void *grep_malloc(size_t size);
+void *grep_calloc(size_t nmemb, size_t size);
+void *grep_realloc(void *ptr, size_t size);
+char *grep_strdup(const char *str);
+void printline(struct str *line, int sep, regmatch_t *matches, int m);
+
+/* queue.c */
+void enqueue(struct str *x);
+void printqueue(void);
+void clearqueue(void);
+
+/* file.c */
+void grep_close(struct file *f);
+struct file *grep_open(const char *path);
+char *grep_fgetln(struct file *f, size_t *len);
diff --git a/text_cmds/grep/queue.c b/text_cmds/grep/queue.c
new file mode 100644
index 0000000..474b4c5
--- /dev/null
+++ b/text_cmds/grep/queue.c
@@ -0,0 +1,107 @@
+/* $NetBSD: queue.c,v 1.2 2011/02/16 01:31:33 joerg Exp $ */
+/* $FreeBSD: src/usr.bin/grep/queue.c,v 1.5 2011/04/07 13:03:35 gabor Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * 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.
+ */
+
+/*
+ * A really poor man's queue. It does only what it has to and gets out of
+ * Dodge. It is used in place of <sys/queue.h> to get a better performance.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/grep/queue.c,v 1.5 2011/04/07 13:03:35 gabor Exp $");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "grep.h"
+
+struct qentry {
+ STAILQ_ENTRY(qentry) list;
+ struct str data;
+};
+
+static STAILQ_HEAD(, qentry) queue = STAILQ_HEAD_INITIALIZER(queue);
+static unsigned long long count;
+
+static struct qentry *dequeue(void);
+
+void
+enqueue(struct str *x)
+{
+ struct qentry *item;
+
+ item = grep_malloc(sizeof(struct qentry));
+ item->data.dat = grep_malloc(sizeof(char) * x->len);
+ item->data.len = x->len;
+ item->data.line_no = x->line_no;
+ item->data.off = x->off;
+ memcpy(item->data.dat, x->dat, x->len);
+ item->data.file = x->file;
+
+ STAILQ_INSERT_TAIL(&queue, item, list);
+
+ if (++count > Bflag)
+ free(dequeue());
+}
+
+static struct qentry *
+dequeue(void)
+{
+ struct qentry *item;
+
+ item = STAILQ_FIRST(&queue);
+ if (item == NULL)
+ return (NULL);
+
+ STAILQ_REMOVE_HEAD(&queue, list);
+ --count;
+ return (item);
+}
+
+void
+printqueue(void)
+{
+ struct qentry *item;
+
+ while ((item = dequeue()) != NULL) {
+ printline(&item->data, '-', (regmatch_t *)NULL, 0);
+ free(item);
+ }
+}
+
+void
+clearqueue(void)
+{
+ struct qentry *item;
+
+ while ((item = dequeue()) != NULL)
+ free(item);
+}
diff --git a/text_cmds/grep/util.c b/text_cmds/grep/util.c
new file mode 100644
index 0000000..fa42d55
--- /dev/null
+++ b/text_cmds/grep/util.c
@@ -0,0 +1,599 @@
+/* $NetBSD: util.c,v 1.9 2011/02/27 17:33:37 joerg Exp $ */
+/* $FreeBSD: src/usr.bin/grep/util.c,v 1.19 2011/12/07 12:25:28 gabor Exp $ */
+/* $OpenBSD: util.c,v 1.39 2010/07/02 22:18:03 tedu Exp $ */
+
+/*-
+ * Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
+ * Copyright (C) 2008-2010 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/grep/util.c,v 1.19 2011/12/07 12:25:28 gabor Exp $");
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#ifdef __APPLE__
+#include <sys/param.h>
+#endif
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <fts.h>
+#include <libgen.h>
+#ifdef __APPLE__
+#include <locale.h>
+#endif /* __APPLE__ */
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#ifndef WITHOUT_FASTMATCH
+#include "fastmatch.h"
+#endif
+#include "grep.h"
+
+static int linesqueued;
+static int procline(struct str *l, int);
+
+bool
+file_matching(const char *fname)
+{
+ char *fname_base;
+ bool ret;
+
+ ret = finclude ? false : true;
+#ifdef __APPLE__
+ fname_base = basename((char *)fname);
+#else
+ fname_base = basename(fname);
+#endif
+
+ for (unsigned int i = 0; i < fpatterns; ++i) {
+ if (fnmatch(fpattern[i].pat, fname, 0) == 0 ||
+ fnmatch(fpattern[i].pat, fname_base, 0) == 0) {
+ if (fpattern[i].mode == EXCL_PAT)
+ return (false);
+ else
+ ret = true;
+ }
+ }
+ return (ret);
+}
+
+static inline bool
+dir_matching(const char *dname)
+{
+ bool ret;
+
+ ret = dinclude ? false : true;
+
+ for (unsigned int i = 0; i < dpatterns; ++i) {
+ if (dname != NULL &&
+ fnmatch(dpattern[i].pat, dname, 0) == 0) {
+ if (dpattern[i].mode == EXCL_PAT)
+ return (false);
+ else
+ ret = true;
+ }
+ }
+ return (ret);
+}
+
+/*
+ * Processes a directory when a recursive search is performed with
+ * the -R option. Each appropriate file is passed to procfile().
+ */
+int
+grep_tree(char **argv)
+{
+ FTS *fts;
+ FTSENT *p;
+ int c, fts_flags;
+ bool ok;
+
+ c = fts_flags = 0;
+
+ switch(linkbehave) {
+ case LINK_EXPLICIT:
+ fts_flags = FTS_COMFOLLOW;
+ break;
+ case LINK_SKIP:
+ fts_flags = FTS_PHYSICAL;
+ break;
+ default:
+ fts_flags = FTS_LOGICAL;
+
+ }
+
+ fts_flags |= FTS_NOSTAT | FTS_NOCHDIR;
+
+ if (!(fts = fts_open(argv, fts_flags, NULL)))
+ err(2, "fts_open");
+ while ((p = fts_read(fts)) != NULL) {
+ switch (p->fts_info) {
+ case FTS_DNR:
+ /* FALLTHROUGH */
+ case FTS_ERR:
+ file_err = true;
+ if(!sflag)
+ warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
+ break;
+ case FTS_D:
+ /* FALLTHROUGH */
+ case FTS_DP:
+ if (dexclude || dinclude)
+ if (!dir_matching(p->fts_name) ||
+ !dir_matching(p->fts_path))
+ fts_set(fts, p, FTS_SKIP);
+ break;
+ case FTS_DC:
+ /* Print a warning for recursive directory loop */
+ warnx("warning: %s: recursive directory loop",
+ p->fts_path);
+ break;
+ default:
+ /* Check for file exclusion/inclusion */
+ ok = true;
+ if (fexclude || finclude)
+ ok &= file_matching(p->fts_path);
+
+ if (ok)
+ c += procfile(p->fts_path);
+ break;
+ }
+ }
+
+ fts_close(fts);
+ return (c);
+}
+
+/*
+ * Opens a file and processes it. Each file is processed line-by-line
+ * passing the lines to procline().
+ */
+int
+procfile(const char *fn)
+{
+ struct file *f;
+ struct stat sb;
+ struct str ln;
+ mode_t s;
+ int c, t;
+
+ if (mflag && (mcount <= 0))
+ return (0);
+
+ if (strcmp(fn, "-") == 0) {
+#ifdef __APPLE__
+ /* 4053512, 10290183 */
+ if (dirbehave == DIR_RECURSE && isatty(STDIN_FILENO)) {
+ warnx("warning: recursive search of stdin");
+ }
+#endif
+ fn = label != NULL ? label : getstr(1);
+ f = grep_open(NULL);
+ } else {
+ if (!stat(fn, &sb)) {
+ /* Check if we need to process the file */
+ s = sb.st_mode & S_IFMT;
+ if (s == S_IFDIR && dirbehave == DIR_SKIP)
+ return (0);
+ if ((s == S_IFIFO || s == S_IFCHR || s == S_IFBLK
+ || s == S_IFSOCK) && devbehave == DEV_SKIP)
+ return (0);
+ }
+ f = grep_open(fn);
+ }
+ if (f == NULL) {
+ file_err = true;
+ if (!sflag)
+ warn("%s", fn);
+ return (0);
+ }
+
+ ln.file = grep_malloc(strlen(fn) + 1);
+ strcpy(ln.file, fn);
+ ln.line_no = 0;
+ ln.len = 0;
+ linesqueued = 0;
+ tail = 0;
+ ln.off = -1;
+
+ for (c = 0; c == 0 || !(lflag || qflag); ) {
+ ln.off += ln.len + 1;
+ if ((ln.dat = grep_fgetln(f, &ln.len)) == NULL || ln.len == 0) {
+ if (ln.line_no == 0 && matchall)
+ exit(0);
+ else
+ break;
+ }
+ if (ln.len > 0 && ln.dat[ln.len - 1] == '\n')
+ --ln.len;
+ ln.line_no++;
+
+ /* Return if we need to skip a binary file */
+ if (f->binary && binbehave == BINFILE_SKIP) {
+ grep_close(f);
+ free(ln.file);
+ free(f);
+ return (0);
+ }
+ /* Process the file line-by-line */
+ if ((t = procline(&ln, f->binary)) == 0 && Bflag > 0) {
+ enqueue(&ln);
+ linesqueued++;
+ }
+ c += t;
+ if (mflag && mcount <= 0)
+ break;
+ }
+ if (Bflag > 0)
+ clearqueue();
+ grep_close(f);
+
+#ifdef __APPLE__
+ /* 10680370 */
+ if (cflag && !qflag) {
+#else
+ if (cflag) {
+#endif
+ if (!hflag)
+ printf("%s:", ln.file);
+ printf("%u\n", c);
+ }
+ if (lflag && !qflag && c != 0)
+ printf("%s%c", fn, nullflag ? 0 : '\n');
+ if (Lflag && !qflag && c == 0)
+ printf("%s%c", fn, nullflag ? 0 : '\n');
+ if (c && !cflag && !lflag && !Lflag &&
+ binbehave == BINFILE_BIN && f->binary && !qflag)
+ printf(getstr(8), fn);
+
+ free(ln.file);
+ free(f);
+ return (c);
+}
+
+#ifdef __APPLE__
+static int
+mbtowc_reverse(wchar_t *pwc, const char *s, size_t n)
+{
+ int result;
+ size_t i;
+
+ result = -1;
+ for (i = 1; i <= n; i++) {
+ result = mbtowc(pwc, s - i, i);
+ if (result != -1) {
+ break;
+ }
+ }
+
+ return result;
+}
+#endif
+
+#define iswword(x) (iswalnum((x)) || (x) == L'_')
+
+/*
+ * Processes a line comparing it with the specified patterns. Each pattern
+ * is looped to be compared along with the full string, saving each and every
+ * match, which is necessary to colorize the output and to count the
+ * matches. The matching lines are passed to printline() to display the
+ * appropriate output.
+ */
+static int
+procline(struct str *l, int nottext)
+{
+#ifdef __APPLE__
+ int nmatches;
+ regmatch_t *matches;
+#else
+ regmatch_t matches[MAX_LINE_MATCHES];
+#endif
+ regmatch_t pmatch;
+ size_t st = 0;
+ unsigned int i;
+ int c = 0, m = 0, r = 0;
+
+#ifdef __APPLE__
+ nmatches = MIN_LINE_MATCHES;
+ matches = grep_malloc(nmatches * sizeof(regmatch_t));
+#endif
+
+ /* Loop to process the whole line */
+ do {
+#ifdef WITHOUT_FASTMATCH
+ if (matchall) {
+ c = !vflag;
+ break;
+ }
+#endif
+
+ pmatch.rm_so = st;
+ pmatch.rm_eo = l->len;
+
+ /* Loop to compare with all the patterns */
+ for (i = 0; i < patterns; i++) {
+#ifdef __APPLE__
+ /* 10462853: Treat binary files as binary. */
+ if (nottext) {
+ setlocale(LC_ALL, "C");
+ }
+#endif /* __APPLE__ */
+#ifndef WITHOUT_FASTMATCH
+ if (fg_pattern[i].pattern)
+ r = fastexec(&fg_pattern[i],
+ l->dat, 1, &pmatch, eflags);
+ else
+#endif
+ r = regexec(&r_pattern[i], l->dat, 1,
+ &pmatch, eflags);
+#ifdef __APPLE__
+ if (nottext) {
+ setlocale(LC_ALL, "");
+ }
+#endif /* __APPLE__ */
+ r = (r == 0) ? 0 : REG_NOMATCH;
+ st = (cflags & REG_NOSUB)
+ ? (size_t)l->len
+ : (size_t)pmatch.rm_eo;
+ if (r == REG_NOMATCH)
+ continue;
+ /* Check for full match */
+ if (r == 0 && xflag)
+ if (pmatch.rm_so != 0 ||
+ (size_t)pmatch.rm_eo != l->len)
+ r = REG_NOMATCH;
+ /* Check for whole word match */
+#ifndef WITHOUT_FASTMATCH
+ if (r == 0 && (wflag || fg_pattern[i].word)) {
+#else
+ if (r == 0 && (wflag)) {
+#endif
+ wchar_t wbegin, wend;
+
+ wbegin = wend = L' ';
+ if (pmatch.rm_so != 0 &&
+#ifdef __APPLE__
+ mbtowc_reverse(&wbegin, &l->dat[pmatch.rm_so], MAX(MB_CUR_MAX, pmatch.rm_so)) == -1)
+#else
+ sscanf(&l->dat[pmatch.rm_so - 1],
+ "%lc", &wbegin) != 1)
+#endif
+ r = REG_NOMATCH;
+ else if ((size_t)pmatch.rm_eo !=
+ l->len &&
+#ifdef __APPLE__
+ mbtowc(&wend, &l->dat[pmatch.rm_eo], MAX(MB_CUR_MAX, l->len - (size_t)pmatch.rm_eo)) == -1)
+#else
+ sscanf(&l->dat[pmatch.rm_eo],
+ "%lc", &wend) != 1)
+#endif
+ r = REG_NOMATCH;
+ else if (iswword(wbegin) ||
+ iswword(wend))
+ r = REG_NOMATCH;
+ }
+ if (r == 0) {
+ if (m == 0)
+ c++;
+#ifdef __APPLE__
+ if (m < MAX_LINE_MATCHES) {
+ if (m >= nmatches) {
+ nmatches += MIN_LINE_MATCHES;
+ matches = grep_realloc(matches, nmatches * sizeof(regmatch_t));
+ }
+ matches[m++] = pmatch;
+ }
+#else
+ if (m < MAX_LINE_MATCHES)
+ matches[m++] = pmatch;
+#endif
+ /* matches - skip further patterns */
+ if ((color == NULL && !oflag) ||
+ qflag || lflag)
+ break;
+ }
+ }
+
+ if (vflag) {
+ c = !c;
+ break;
+ }
+
+ /* One pass if we are not recording matches */
+#ifdef __APPLE__
+ /* 10593340: If -w didn't match, keep going. */
+ if (!(wflag && r == REG_NOMATCH) && ((color == NULL && !oflag) || qflag || lflag))
+#else
+ if ((color == NULL && !oflag) || qflag || lflag)
+#endif
+ break;
+
+ if (st == (size_t)pmatch.rm_so)
+ break; /* No matches */
+ } while (st < l->len);
+
+
+ /* Count the matches if we have a match limit */
+ if (mflag)
+ mcount -= c;
+
+ if (c && binbehave == BINFILE_BIN && nottext) {
+#ifdef __APPLE__
+ free(matches);
+#endif
+ return (c); /* Binary file */
+ }
+
+ /* Dealing with the context */
+ if ((tail || c) && !cflag && !qflag && !lflag && !Lflag) {
+ if (c) {
+ if (!first && !prev && !tail && Aflag)
+ printf("--\n");
+ tail = Aflag;
+ if (Bflag > 0) {
+ if (!first && !prev)
+ printf("--\n");
+ printqueue();
+ }
+ linesqueued = 0;
+ printline(l, ':', matches, m);
+ } else {
+ printline(l, '-', matches, m);
+ tail--;
+ }
+ }
+
+ if (c) {
+ prev = true;
+ first = false;
+ } else
+ prev = false;
+
+#ifdef __APPLE__
+ free(matches);
+#endif
+ return (c);
+}
+
+/*
+ * Safe malloc() for internal use.
+ */
+void *
+grep_malloc(size_t size)
+{
+ void *ptr;
+
+ if ((ptr = malloc(size)) == NULL)
+ err(2, "malloc");
+ return (ptr);
+}
+
+/*
+ * Safe calloc() for internal use.
+ */
+void *
+grep_calloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ if ((ptr = calloc(nmemb, size)) == NULL)
+ err(2, "calloc");
+ return (ptr);
+}
+
+/*
+ * Safe realloc() for internal use.
+ */
+void *
+grep_realloc(void *ptr, size_t size)
+{
+
+ if ((ptr = realloc(ptr, size)) == NULL)
+ err(2, "realloc");
+ return (ptr);
+}
+
+/*
+ * Safe strdup() for internal use.
+ */
+char *
+grep_strdup(const char *str)
+{
+ char *ret;
+
+ if ((ret = strdup(str)) == NULL)
+ err(2, "strdup");
+ return (ret);
+}
+
+/*
+ * Prints a matching line according to the command line options.
+ */
+void
+printline(struct str *line, int sep, regmatch_t *matches, int m)
+{
+ size_t a = 0;
+ int i, n = 0;
+
+ if (!hflag) {
+ if (!nullflag) {
+ fputs(line->file, stdout);
+ ++n;
+ } else {
+ printf("%s", line->file);
+ putchar(0);
+ }
+ }
+ if (nflag) {
+ if (n > 0)
+ putchar(sep);
+ printf("%d", line->line_no);
+ ++n;
+ }
+ if (bflag) {
+ if (n > 0)
+ putchar(sep);
+ printf("%lld", (long long)line->off);
+ ++n;
+ }
+ if (n)
+ putchar(sep);
+ /* --color and -o */
+ if ((oflag || color) && m > 0) {
+ for (i = 0; i < m; i++) {
+ if (!oflag)
+ fwrite(line->dat + a, matches[i].rm_so - a, 1,
+ stdout);
+ if (color)
+ fprintf(stdout, "\33[%sm\33[K", color);
+
+ fwrite(line->dat + matches[i].rm_so,
+ matches[i].rm_eo - matches[i].rm_so, 1,
+ stdout);
+ if (color)
+ fprintf(stdout, "\33[m\33[K");
+ a = matches[i].rm_eo;
+ if (oflag)
+ putchar('\n');
+ }
+ if (!oflag) {
+ if (line->len - a > 0)
+ fwrite(line->dat + a, line->len - a, 1, stdout);
+ putchar('\n');
+ }
+ } else {
+ fwrite(line->dat, line->len, 1, stdout);
+ putchar('\n');
+ }
+}
diff --git a/text_cmds/head/head.1 b/text_cmds/head/head.1
new file mode 100644
index 0000000..f0021c9
--- /dev/null
+++ b/text_cmds/head/head.1
@@ -0,0 +1,69 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)head.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/head/head.1,v 1.13 2005/01/17 07:44:18 ru Exp $
+.\"
+.Dd June 6, 1993
+.Dt HEAD 1
+.Os
+.Sh NAME
+.Nm head
+.Nd display first lines of a file
+.Sh SYNOPSIS
+.Nm
+.Op Fl n Ar count | Fl c Ar bytes
+.Op Ar
+.Sh DESCRIPTION
+This filter displays the first
+.Ar count
+lines or
+.Ar bytes
+of each of the specified files, or of the standard input if no
+files are specified.
+If
+.Ar count
+is omitted it defaults to 10.
+.Pp
+If more than a single file is specified, each file is preceded by a
+header consisting of the string
+.Dq ==> XXX <==
+where
+.Dq XXX
+is the name of the file.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr tail 1
+.Sh HISTORY
+The
+.Nm
+command appeared in PWB UNIX.
diff --git a/text_cmds/head/head.c b/text_cmds/head/head.c
new file mode 100644
index 0000000..d798e78
--- /dev/null
+++ b/text_cmds/head/head.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 1980, 1987, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1987, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/head/head.c,v 1.20 2007/01/11 20:23:01 brooks Exp $");
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * head - give the first few lines of a stream or of each of a set of files
+ *
+ * Bill Joy UCB August 24, 1977
+ */
+
+static void head(FILE *, int);
+static void head_bytes(FILE *, off_t);
+static void obsolete(char *[]);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ FILE *fp;
+ int first, linecnt = -1, eval = 0;
+ off_t bytecnt = -1;
+ char *ep;
+
+ obsolete(argv);
+ while ((ch = getopt(argc, argv, "n:c:")) != -1)
+ switch(ch) {
+ case 'c':
+ bytecnt = strtoimax(optarg, &ep, 10);
+ if (*ep || bytecnt <= 0)
+ errx(1, "illegal byte count -- %s", optarg);
+ break;
+ case 'n':
+ linecnt = strtol(optarg, &ep, 10);
+ if (*ep || linecnt <= 0)
+ errx(1, "illegal line count -- %s", optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (linecnt != -1 && bytecnt != -1)
+ errx(1, "can't combine line and byte counts");
+ if (linecnt == -1 )
+ linecnt = 10;
+ if (*argv) {
+ for (first = 1; *argv; ++argv) {
+ if ((fp = fopen(*argv, "r")) == NULL) {
+ warn("%s", *argv);
+ eval = 1;
+ continue;
+ }
+ if (argc > 1) {
+ (void)printf("%s==> %s <==\n",
+ first ? "" : "\n", *argv);
+ first = 0;
+ }
+ if (bytecnt == -1)
+ head(fp, linecnt);
+ else
+ head_bytes(fp, bytecnt);
+ if (ferror(fp)) {
+ warnx("Error reading %s", *argv);
+ eval = 1;
+ }
+ (void)fclose(fp);
+ }
+ } else {
+ if (bytecnt == -1) {
+ head(stdin, linecnt);
+ } else {
+ head_bytes(stdin, bytecnt);
+ }
+ if (ferror(stdin)) {
+ warnx("Error reading stdin");
+ eval = 1;
+ }
+ }
+
+ exit(eval);
+}
+
+static void
+head(FILE *fp, int cnt)
+{
+ char *cp;
+ size_t error, readlen;
+
+ while (cnt && (cp = fgetln(fp, &readlen)) != NULL) {
+ error = fwrite(cp, sizeof(char), readlen, stdout);
+ if (error != readlen)
+ err(1, "stdout");
+ cnt--;
+ }
+
+ fflush(fp);
+}
+
+static void
+head_bytes(FILE *fp, off_t cnt)
+{
+ char buf[4096];
+ size_t readlen;
+
+ while (cnt) {
+ if ((uintmax_t)cnt < sizeof(buf))
+ readlen = cnt;
+ else
+ readlen = sizeof(buf);
+ readlen = fread(buf, sizeof(char), readlen, fp);
+ if (readlen == 0)
+ break;
+ if (fwrite(buf, sizeof(char), readlen, stdout) != readlen)
+ err(1, "stdout");
+ cnt -= readlen;
+ }
+}
+
+static void
+obsolete(char *argv[])
+{
+ char *ap;
+
+ while ((ap = *++argv)) {
+ /* Return if "--" or not "-[0-9]*". */
+ if (ap[0] != '-' || ap[1] == '-' || !isdigit(ap[1]))
+ return;
+ if ((ap = malloc(strlen(*argv) + 2)) == NULL)
+ err(1, NULL);
+ ap[0] = '-';
+ ap[1] = 'n';
+ (void)strcpy(ap + 2, *argv + 1);
+ *argv = ap;
+ }
+}
+
+static void
+usage(void)
+{
+
+ (void)fprintf(stderr, "usage: head [-n lines | -c bytes] [file ...]\n");
+ exit(1);
+}
diff --git a/text_cmds/join/join.1 b/text_cmds/join/join.1
new file mode 100644
index 0000000..0ab7a93
--- /dev/null
+++ b/text_cmds/join/join.1
@@ -0,0 +1,235 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)join.1 8.3 (Berkeley) 4/28/95
+.\" $FreeBSD: src/usr.bin/join/join.1,v 1.20 2005/02/13 22:25:23 ru Exp $
+.\"
+.Dd July 5, 2004
+.Dt JOIN 1
+.Os
+.Sh NAME
+.Nm join
+.Nd relational database operator
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl a Ar file_number | Fl v Ar file_number
+.Oc
+.Op Fl e Ar string
+.Op Fl o Ar list
+.Bk -words
+.Ek
+.Op Fl t Ar char
+.Op Fl \&1 Ar field
+.Op Fl \&2 Ar field
+.Ar file1
+.Ar file2
+.Sh DESCRIPTION
+The
+.Nm
+utility performs an
+.Dq equality join
+on the specified files
+and writes the result to the standard output.
+The
+.Dq join field
+is the field in each file by which the files are compared.
+The first field in each line is used by default.
+There is one line in the output for each pair of lines in
+.Ar file1
+and
+.Ar file2
+which have identical join fields.
+Each output line consists of the join field, the remaining fields from
+.Ar file1
+and then the remaining fields from
+.Ar file2 .
+.Pp
+The default field separators are tab and space characters.
+In this case, multiple tabs and spaces count as a single field separator,
+and leading tabs and spaces are ignored.
+The default output field separator is a single space character.
+.Pp
+Many of the options use file and field numbers.
+Both file numbers and field numbers are 1 based, i.e., the first file on
+the command line is file number 1 and the first field is field number 1.
+The following options are available:
+.Bl -tag -width indent
+.It Fl a Ar file_number
+In addition to the default output, produce a line for each unpairable
+line in file
+.Ar file_number .
+.It Fl e Ar string
+Replace empty output fields with
+.Ar string .
+.It Fl o Ar list
+The
+.Fl o
+option specifies the fields that will be output from each file for
+each line with matching join fields.
+Each element of
+.Ar list
+has the either the form
+.Ql file_number.field ,
+where
+.Ar file_number
+is a file number and
+.Ar field
+is a field number, or the form
+.Ql 0
+.Pq zero ,
+representing the join field.
+The elements of list must be either comma
+.Pq Ql \&,
+or whitespace separated.
+(The latter requires quoting to protect it from the shell, or, a simpler
+approach is to use multiple
+.Fl o
+options.)
+.It Fl t Ar char
+Use character
+.Ar char
+as a field delimiter for both input and output.
+Every occurrence of
+.Ar char
+in a line is significant.
+.It Fl v Ar file_number
+Do not display the default output, but display a line for each unpairable
+line in file
+.Ar file_number .
+The options
+.Fl v Ar 1
+and
+.Fl v Ar 2
+may be specified at the same time.
+.It Fl 1 Ar field
+Join on the
+.Ar field Ns 'th
+field of file 1.
+.It Fl 2 Ar field
+Join on the
+.Ar field Ns 'th
+field of file 2.
+.El
+.Pp
+When the default field delimiter characters are used, the files to be joined
+should be ordered in the collating sequence of
+.Xr sort 1 ,
+using the
+.Fl b
+option, on the fields on which they are to be joined, otherwise
+.Nm
+may not report all field matches.
+When the field delimiter characters are specified by the
+.Fl t
+option, the collating sequence should be the same as
+.Xr sort 1
+without the
+.Fl b
+option.
+.Pp
+If one of the arguments
+.Ar file1
+or
+.Ar file2
+is
+.Dq - ,
+the standard input is used.
+.Sh EXIT STATUS
+.Ex -std
+.Sh COMPATIBILITY
+For compatibility with historic versions of
+.Nm ,
+the following options are available:
+.Bl -tag -width indent
+.It Fl a
+In addition to the default output, produce a line for each unpairable line
+in both file 1 and file 2.
+.It Fl j1 Ar field
+Join on the
+.Ar field Ns 'th
+field of file 1.
+.It Fl j2 Ar field
+Join on the
+.Ar field Ns 'th
+field of file 2.
+.It Fl j Ar field
+Join on the
+.Ar field Ns 'th
+field of both file 1 and file 2.
+.It Fl o Ar list ...
+Historical implementations of
+.Nm
+permitted multiple arguments to the
+.Fl o
+option.
+These arguments were of the form
+.Ql file_number.field_number
+as described
+for the current
+.Fl o
+option.
+This has obvious difficulties in the presence of files named
+.Ql 1.2 .
+.El
+.Pp
+These options are available only
+so historic shell scripts do not require modification.
+They should not be used in new code.
+.Sh LEGACY DESCRIPTION
+The
+.Fl e
+option causes a specified string to be substituted into empty fields,
+even if they are in the middle of a line.
+In legacy mode,
+the substitution only takes place at the end of a line.
+.Pp
+Only documented options are allowed.
+In legacy mode,
+some obsolete options are re-written into current options.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr awk 1 ,
+.Xr comm 1 ,
+.Xr paste 1 ,
+.Xr sort 1 ,
+.Xr uniq 1 ,
+.Xr compat 5
+.Sh STANDARDS
+The
+.Nm
+command conforms to
+.St -p1003.1-2001 .
diff --git a/text_cmds/join/join.c b/text_cmds/join/join.c
new file mode 100644
index 0000000..45413e6
--- /dev/null
+++ b/text_cmds/join/join.c
@@ -0,0 +1,685 @@
+/*-
+ * Copyright (c) 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Steve Hayman of the Computer Science Department, Indiana University,
+ * Michiro Hikida and David Goodenough.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)join.c 8.6 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/join/join.c,v 1.20 2004/08/26 06:28:05 maxim Exp $");
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <sysexits.h>
+
+#ifdef __APPLE__
+#include "get_compat.h"
+#else
+#define COMPAT_MODE(func, mode) 1
+#endif
+
+/*
+ * There's a structure per input file which encapsulates the state of the
+ * file. We repeatedly read lines from each file until we've read in all
+ * the consecutive lines from the file with a common join field. Then we
+ * compare the set of lines with an equivalent set from the other file.
+ */
+typedef struct {
+ char *line; /* line */
+ u_long linealloc; /* line allocated count */
+ char **fields; /* line field(s) */
+ u_long fieldcnt; /* line field(s) count */
+ u_long fieldalloc; /* line field(s) allocated count */
+} LINE;
+
+typedef struct {
+ FILE *fp; /* file descriptor */
+ u_long joinf; /* join field (-1, -2, -j) */
+ int unpair; /* output unpairable lines (-a) */
+ u_long number; /* 1 for file 1, 2 for file 2 */
+
+ LINE *set; /* set of lines with same field */
+ int pushbool; /* if pushback is set */
+ u_long pushback; /* line on the stack */
+ u_long setcnt; /* set count */
+ u_long setalloc; /* set allocated count */
+} INPUT;
+INPUT input1 = { NULL, 0, 0, 1, NULL, 0, 0, 0, 0 },
+ input2 = { NULL, 0, 0, 2, NULL, 0, 0, 0, 0 };
+
+typedef struct {
+ u_long filenum; /* file number */
+ u_long fieldno; /* field number */
+} OLIST;
+OLIST *olist; /* output field list */
+u_long olistcnt; /* output field list count */
+u_long olistalloc; /* output field allocated count */
+
+int joinout = 1; /* show lines with matched join fields (-v) */
+int needsep; /* need separator character */
+int spans = 1; /* span multiple delimiters (-t) */
+char *empty; /* empty field replacement string (-e) */
+static wchar_t default_tabchar[] = L" \t";
+wchar_t *tabchar = default_tabchar;/* delimiter characters (-t) */
+
+int cmp(LINE *, u_long, LINE *, u_long);
+void fieldarg(char *);
+void joinlines(INPUT *, INPUT *);
+int mbscoll(const char *, const char *);
+char *mbssep(char **, const wchar_t *);
+void obsolete(char **);
+void outfield(LINE *, u_long, int);
+void outoneline(INPUT *, LINE *);
+void outtwoline(INPUT *, LINE *, INPUT *, LINE *);
+void slurp(INPUT *);
+wchar_t *towcs(const char *);
+void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ INPUT *F1, *F2;
+ int aflag, ch, cval, vflag;
+ char *end;
+
+ setlocale(LC_ALL, "");
+
+ F1 = &input1;
+ F2 = &input2;
+
+ aflag = vflag = 0;
+ if (!COMPAT_MODE("bin/join", "Unix2003"))
+ obsolete(argv);
+ while ((ch = getopt(argc, argv, "\01a:e:j:1:2:o:t:v:")) != -1) {
+ switch (ch) {
+ case '\01': /* See comment in obsolete(). */
+ aflag = 1;
+ F1->unpair = F2->unpair = 1;
+ break;
+ case '1':
+ if ((F1->joinf = strtol(optarg, &end, 10)) < 1)
+ errx(1, "-1 option field number less than 1");
+ if (*end)
+ errx(1, "illegal field number -- %s", optarg);
+ --F1->joinf;
+ break;
+ case '2':
+ if ((F2->joinf = strtol(optarg, &end, 10)) < 1)
+ errx(1, "-2 option field number less than 1");
+ if (*end)
+ errx(1, "illegal field number -- %s", optarg);
+ --F2->joinf;
+ break;
+ case 'a':
+ aflag = 1;
+ switch(strtol(optarg, &end, 10)) {
+ case 1:
+ F1->unpair = 1;
+ break;
+ case 2:
+ F2->unpair = 1;
+ break;
+ default:
+ errx(1, "-a option file number not 1 or 2");
+ break;
+ }
+ if (*end)
+ errx(1, "illegal file number -- %s", optarg);
+ break;
+ case 'e':
+ empty = optarg;
+ break;
+ case 'j':
+ if ((F1->joinf = F2->joinf =
+ strtol(optarg, &end, 10)) < 1)
+ errx(1, "-j option field number less than 1");
+ if (*end)
+ errx(1, "illegal field number -- %s", optarg);
+ --F1->joinf;
+ --F2->joinf;
+ break;
+ case 'o':
+ fieldarg(optarg);
+ break;
+ case 't':
+ spans = 0;
+ if (mbrtowc(&tabchar[0], optarg, MB_LEN_MAX, NULL) !=
+ strlen(optarg))
+ errx(1, "illegal tab character specification");
+ tabchar[1] = L'\0';
+ break;
+ case 'v':
+ vflag = 1;
+ joinout = 0;
+ switch (strtol(optarg, &end, 10)) {
+ case 1:
+ F1->unpair = 1;
+ break;
+ case 2:
+ F2->unpair = 1;
+ break;
+ default:
+ errx(1, "-v option file number not 1 or 2");
+ break;
+ }
+ if (*end)
+ errx(1, "illegal file number -- %s", optarg);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (aflag && vflag)
+ errx(1, "the -a and -v options are mutually exclusive");
+
+ if (argc != 2 || argv[0]==NULL || argv[1]==NULL)
+ usage();
+
+ /* Open the files; "-" means stdin. */
+ if (!strcmp(*argv, "-"))
+ F1->fp = stdin;
+ else if ((F1->fp = fopen(*argv, "r")) == NULL)
+ err(1, "%s", *argv);
+ ++argv;
+ if (!strcmp(*argv, "-"))
+ F2->fp = stdin;
+ else if ((F2->fp = fopen(*argv, "r")) == NULL)
+ err(1, "%s", *argv);
+ if (F1->fp == stdin && F2->fp == stdin)
+ errx(1, "only one input file may be stdin");
+
+ slurp(F1);
+ slurp(F2);
+ while (F1->setcnt && F2->setcnt) {
+ cval = cmp(F1->set, F1->joinf, F2->set, F2->joinf);
+ if (cval == 0) {
+ /* Oh joy, oh rapture, oh beauty divine! */
+ if (joinout)
+ joinlines(F1, F2);
+ slurp(F1);
+ slurp(F2);
+ } else if (cval < 0) {
+ /* File 1 takes the lead... */
+ if (F1->unpair)
+ joinlines(F1, NULL);
+ slurp(F1);
+ } else {
+ /* File 2 takes the lead... */
+ if (F2->unpair)
+ joinlines(F2, NULL);
+ slurp(F2);
+ }
+ }
+
+ /*
+ * Now that one of the files is used up, optionally output any
+ * remaining lines from the other file.
+ */
+ if (F1->unpair)
+ while (F1->setcnt) {
+ joinlines(F1, NULL);
+ slurp(F1);
+ }
+ if (F2->unpair)
+ while (F2->setcnt) {
+ joinlines(F2, NULL);
+ slurp(F2);
+ }
+ exit(0);
+}
+
+void
+slurp(INPUT *F)
+{
+ LINE *lp, *lastlp, tmp;
+ size_t len;
+ int cnt;
+ char *bp, *fieldp;
+
+ /*
+ * Read all of the lines from an input file that have the same
+ * join field.
+ */
+ F->setcnt = 0;
+ for (lastlp = NULL;; ++F->setcnt) {
+ /*
+ * If we're out of space to hold line structures, allocate
+ * more. Initialize the structure so that we know that this
+ * is new space.
+ */
+ if (F->setcnt == F->setalloc) {
+ cnt = F->setalloc;
+ F->setalloc += 50;
+ if ((F->set = realloc(F->set,
+ F->setalloc * sizeof(LINE))) == NULL)
+ err(1, NULL);
+ memset(F->set + cnt, 0, 50 * sizeof(LINE));
+
+ /* re-set lastlp in case it moved */
+ if (lastlp != NULL)
+ lastlp = &F->set[F->setcnt - 1];
+ }
+
+ /*
+ * Get any pushed back line, else get the next line. Allocate
+ * space as necessary. If taking the line from the stack swap
+ * the two structures so that we don't lose space allocated to
+ * either structure. This could be avoided by doing another
+ * level of indirection, but it's probably okay as is.
+ */
+ lp = &F->set[F->setcnt];
+ if (F->setcnt)
+ lastlp = &F->set[F->setcnt - 1];
+ if (F->pushbool) {
+ tmp = F->set[F->setcnt];
+ F->set[F->setcnt] = F->set[F->pushback];
+ F->set[F->pushback] = tmp;
+ F->pushbool = 0;
+ continue;
+ }
+ if ((bp = fgetln(F->fp, &len)) == NULL) {
+ if (ferror(F->fp)) {
+ err(EX_IOERR, NULL);
+ }
+ return;
+ }
+ if (lp->linealloc <= len + 1) {
+ lp->linealloc += MAX(100, len + 1 - lp->linealloc);
+ if ((lp->line =
+ realloc(lp->line, lp->linealloc)) == NULL)
+ err(1, NULL);
+ }
+ memmove(lp->line, bp, len);
+
+ /* Replace trailing newline, if it exists. */
+ if (bp[len - 1] == '\n')
+ lp->line[len - 1] = '\0';
+ else
+ lp->line[len] = '\0';
+ bp = lp->line;
+
+ /* Split the line into fields, allocate space as necessary. */
+ lp->fieldcnt = 0;
+ while ((fieldp = mbssep(&bp, tabchar)) != NULL) {
+ if (spans && *fieldp == '\0')
+ continue;
+ if (lp->fieldcnt == lp->fieldalloc) {
+ lp->fieldalloc += 50;
+ if ((lp->fields = realloc(lp->fields,
+ lp->fieldalloc * sizeof(char *))) == NULL)
+ err(1, NULL);
+ }
+ lp->fields[lp->fieldcnt++] = fieldp;
+ }
+
+ /* See if the join field value has changed. */
+ if (lastlp != NULL && cmp(lp, F->joinf, lastlp, F->joinf)) {
+ F->pushbool = 1;
+ F->pushback = F->setcnt;
+ break;
+ }
+ }
+}
+
+char *
+mbssep(char **stringp, const wchar_t *delim)
+{
+ char *s, *tok;
+ const wchar_t *spanp;
+ wchar_t c, sc;
+ size_t n;
+
+ if ((s = *stringp) == NULL)
+ return (NULL);
+ for (tok = s;;) {
+ n = mbrtowc(&c, s, MB_LEN_MAX, NULL);
+ if (n == (size_t)-1 || n == (size_t)-2)
+ errc(1, EILSEQ, NULL); /* XXX */
+ s += n;
+ spanp = delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-n] = '\0';
+ *stringp = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+}
+
+int
+cmp(LINE *lp1, u_long fieldno1, LINE *lp2, u_long fieldno2)
+{
+ if (lp1->fieldcnt <= fieldno1)
+ return (lp2->fieldcnt <= fieldno2 ? 0 : 1);
+ if (lp2->fieldcnt <= fieldno2)
+ return (-1);
+ return (mbscoll(lp1->fields[fieldno1], lp2->fields[fieldno2]));
+}
+
+int
+mbscoll(const char *s1, const char *s2)
+{
+ wchar_t *w1, *w2;
+ int ret;
+
+ if (MB_CUR_MAX == 1)
+ return (strcoll(s1, s2));
+ if ((w1 = towcs(s1)) == NULL || (w2 = towcs(s2)) == NULL)
+ err(1, NULL); /* XXX */
+ ret = wcscoll(w1, w2);
+ free(w1);
+ free(w2);
+ return (ret);
+}
+
+wchar_t *
+towcs(const char *s)
+{
+ wchar_t *wcs;
+ size_t n;
+
+ if ((n = mbsrtowcs(NULL, &s, 0, NULL)) == (size_t)-1)
+ return (NULL);
+ if ((wcs = malloc((n + 1) * sizeof(*wcs))) == NULL)
+ return (NULL);
+ mbsrtowcs(wcs, &s, n + 1, NULL);
+ return (wcs);
+}
+
+void
+joinlines(INPUT *F1, INPUT *F2)
+{
+ u_long cnt1, cnt2;
+
+ /*
+ * Output the results of a join comparison. The output may be from
+ * either file 1 or file 2 (in which case the first argument is the
+ * file from which to output) or from both.
+ */
+ if (F2 == NULL) {
+ for (cnt1 = 0; cnt1 < F1->setcnt; ++cnt1)
+ outoneline(F1, &F1->set[cnt1]);
+ return;
+ }
+ for (cnt1 = 0; cnt1 < F1->setcnt; ++cnt1)
+ for (cnt2 = 0; cnt2 < F2->setcnt; ++cnt2)
+ outtwoline(F1, &F1->set[cnt1], F2, &F2->set[cnt2]);
+}
+
+void
+outoneline(INPUT *F, LINE *lp)
+{
+ u_long cnt;
+
+ /*
+ * Output a single line from one of the files, according to the
+ * join rules. This happens when we are writing unmatched single
+ * lines. Output empty fields in the right places.
+ */
+ if (olist)
+ for (cnt = 0; cnt < olistcnt; ++cnt) {
+ if (olist[cnt].filenum == (unsigned)F->number)
+ outfield(lp, olist[cnt].fieldno, 0);
+ else if (olist[cnt].filenum == 0)
+ outfield(lp, F->joinf, 0);
+ else
+ outfield(lp, 0, 1);
+ }
+ else
+ for (cnt = 0; cnt < lp->fieldcnt; ++cnt)
+ outfield(lp, cnt, 0);
+ (void)printf("\n");
+ if (ferror(stdout))
+ err(1, "stdout");
+ needsep = 0;
+}
+
+void
+outtwoline(INPUT *F1, LINE *lp1, INPUT *F2, LINE *lp2)
+{
+ u_long cnt;
+
+ /* Output a pair of lines according to the join list (if any). */
+ if (olist)
+ for (cnt = 0; cnt < olistcnt; ++cnt)
+ if (olist[cnt].filenum == 0) {
+ if (lp1->fieldcnt >= F1->joinf)
+ outfield(lp1, F1->joinf, 0);
+ else
+ outfield(lp2, F2->joinf, 0);
+ } else if (olist[cnt].filenum == 1)
+ outfield(lp1, olist[cnt].fieldno, 0);
+ else /* if (olist[cnt].filenum == 2) */
+ outfield(lp2, olist[cnt].fieldno, 0);
+ else {
+ /*
+ * Output the join field, then the remaining fields from F1
+ * and F2.
+ */
+ outfield(lp1, F1->joinf, 0);
+ for (cnt = 0; cnt < lp1->fieldcnt; ++cnt)
+ if (F1->joinf != cnt)
+ outfield(lp1, cnt, 0);
+ for (cnt = 0; cnt < lp2->fieldcnt; ++cnt)
+ if (F2->joinf != cnt)
+ outfield(lp2, cnt, 0);
+ }
+ (void)printf("\n");
+ if (ferror(stdout))
+ err(1, "stdout");
+ needsep = 0;
+}
+
+void
+outfield(LINE *lp, u_long fieldno, int out_empty)
+{
+ if (needsep++)
+ (void)printf("%lc", *tabchar);
+ if (!ferror(stdout)) {
+ if (lp->fieldcnt <= fieldno || out_empty) {
+ if (empty != NULL)
+ (void)printf("%s", empty);
+ } else {
+ if (*lp->fields[fieldno] == '\0') {
+ if (COMPAT_MODE("bin/join", "Unix2003") && empty != NULL)
+ (void)printf("%s", empty);
+ else
+ return;
+ } else
+ (void)printf("%s", lp->fields[fieldno]);
+ }
+ }
+ if (ferror(stdout))
+ err(1, "stdout");
+}
+
+/*
+ * Convert an output list argument "2.1, 1.3, 2.4" into an array of output
+ * fields.
+ */
+void
+fieldarg(char *option)
+{
+ u_long fieldno, filenum;
+ char *end, *token;
+
+ while ((token = strsep(&option, ", \t")) != NULL) {
+ if (*token == '\0')
+ continue;
+ if (token[0] == '0')
+ filenum = fieldno = 0;
+ else if ((token[0] == '1' || token[0] == '2') &&
+ token[1] == '.') {
+ filenum = token[0] - '0';
+ fieldno = strtol(token + 2, &end, 10);
+ if (*end)
+ errx(1, "malformed -o option field");
+ if (fieldno == 0)
+ errx(1, "field numbers are 1 based");
+ --fieldno;
+ } else
+ errx(1, "malformed -o option field");
+ if (olistcnt == olistalloc) {
+ olistalloc += 50;
+ if ((olist = realloc(olist,
+ olistalloc * sizeof(OLIST))) == NULL)
+ err(1, NULL);
+ }
+ olist[olistcnt].filenum = filenum;
+ olist[olistcnt].fieldno = fieldno;
+ ++olistcnt;
+ }
+}
+
+void
+obsolete(char **argv)
+{
+ size_t len;
+ char **p, *ap, *t;
+
+ while ((ap = *++argv) != NULL) {
+ /* Return if "--". */
+ if (ap[0] == '-' && ap[1] == '-')
+ return;
+ /* skip if not an option */
+ if (ap[0] != '-')
+ continue;
+ switch (ap[1]) {
+ case 'a':
+ /*
+ * The original join allowed "-a", which meant the
+ * same as -a1 plus -a2. POSIX 1003.2, Draft 11.2
+ * only specifies this as "-a 1" and "a -2", so we
+ * have to use another option flag, one that is
+ * unlikely to ever be used or accidentally entered
+ * on the command line. (Well, we could reallocate
+ * the argv array, but that hardly seems worthwhile.)
+ */
+ if (ap[2] == '\0' && (argv[1] == NULL ||
+ (strcmp(argv[1], "1") != 0 &&
+ strcmp(argv[1], "2") != 0))) {
+ ap[1] = '\01';
+ warnx("-a option used without an argument; "
+ "reverting to historical behavior");
+ }
+ break;
+ case 'j':
+ /*
+ * The original join allowed "-j[12] arg" and "-j arg".
+ * Convert the former to "-[12] arg". Don't convert
+ * the latter since getopt(3) can handle it.
+ */
+ switch(ap[2]) {
+ case '1':
+ if (ap[3] != '\0')
+ goto jbad;
+ ap[1] = '1';
+ ap[2] = '\0';
+ break;
+ case '2':
+ if (ap[3] != '\0')
+ goto jbad;
+ ap[1] = '2';
+ ap[2] = '\0';
+ break;
+ case '\0':
+ break;
+ default:
+jbad: errx(1, "illegal option -- %s", ap);
+ usage();
+ }
+ break;
+ case 'o':
+ /*
+ * The original join allowed "-o arg arg".
+ * Convert to "-o arg -o arg".
+ */
+ if (ap[2] != '\0')
+ break;
+ for (p = argv + 2; *p; ++p) {
+ if (p[0][0] == '0' || ((p[0][0] != '1' &&
+ p[0][0] != '2') || p[0][1] != '.'))
+ break;
+ len = strlen(*p);
+ if (len - 2 != strspn(*p + 2, "0123456789"))
+ break;
+ if ((t = malloc(len + 3)) == NULL)
+ err(1, NULL);
+ t[0] = '-';
+ t[1] = 'o';
+ memmove(t + 2, *p, len + 1);
+ *p = t;
+ }
+ argv = p - 1;
+ break;
+ }
+ }
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "%s %s\n%s\n",
+ "usage: join [-a fileno | -v fileno ] [-e string] [-1 field]",
+ "[-2 field]",
+ " [-o list] [-t char] file1 file2");
+ exit(1);
+}
diff --git a/text_cmds/lam/lam.1 b/text_cmds/lam/lam.1
new file mode 100644
index 0000000..9986577
--- /dev/null
+++ b/text_cmds/lam/lam.1
@@ -0,0 +1,141 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)lam.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/lam/lam.1,v 1.13 2004/08/12 11:34:34 tjr Exp $
+.\"
+.Dd August 12, 2004
+.Dt LAM 1
+.Os
+.Sh NAME
+.Nm lam
+.Nd laminate files
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar min . Ns Ar max
+.Op Fl s Ar sepstring
+.Op Fl t Ar c
+.Ar
+.Nm
+.Op Fl p Ar min . Ns Ar max
+.Op Fl s Ar sepstring
+.Op Fl t Ar c
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility copies the named files side by side onto the standard output.
+The
+.Em n-th
+input lines from the input
+.Ar files
+are considered fragments of the single long
+.Em n-th
+output line into which they are assembled.
+The name `\fB\-\fP' means the standard input, and may be repeated.
+.Pp
+Normally, each option affects only the
+.Ar file
+after it.
+If the option letter is capitalized it affects all subsequent files
+until it appears again uncapitalized.
+The options are described below:
+.Bl -tag -width indent
+.It Fl f Ar min . Ns Ar max
+Print line fragments according to the format string
+.Ar min . Ns Ar max ,
+where
+.Ar min
+is the minimum field width and
+.Ar max
+the maximum field width.
+If
+.Ar min
+begins with a zero, zeros will be added to make up the field width,
+and if it begins with a `\-', the fragment will be left-adjusted
+within the field.
+.It Fl p Ar min . Ns Ar max
+Like
+.Fl f ,
+but pad this file's field when end-of-file is reached
+and other files are still active.
+.It Fl s Ar sepstring
+Print
+.Ar sepstring
+before printing line fragments from the next file.
+This option may appear after the last file.
+.It Fl t Ar c
+The input line terminator is
+.Ar c
+instead of a newline.
+The newline normally appended to each output line is omitted.
+.El
+.Pp
+To print files simultaneously for easy viewing use
+.Xr pr 1 .
+.Sh EXAMPLES
+The command
+.Bd -literal
+lam file1 file2 file3 file4
+.Ed
+.Pp
+joins 4 files together along each line.
+To merge the lines from four different files use
+.Bd -literal
+lam file1 \-S "\\
+" file2 file3 file4
+.Ed
+.Pp
+Every 2 lines of a file may be joined on one line with
+.Bd -literal
+lam \- \- < file
+.Ed
+.Pp
+and a form letter with substitutions keyed by `@' can be done with
+.Bd -literal
+lam \-t @ letter changes
+.Ed
+.Sh SEE ALSO
+.Xr join 1 ,
+.Xr paste 1 ,
+.Xr pr 1 ,
+.Xr printf 3
+.Sh STANDARDS
+Some of the functionality of
+.Nm
+is standardized as the
+.Xr paste 1
+utility by
+.St -p1003.2 .
+.Sh BUGS
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/text_cmds/lam/lam.c b/text_cmds/lam/lam.c
new file mode 100644
index 0000000..cd24920
--- /dev/null
+++ b/text_cmds/lam/lam.c
@@ -0,0 +1,234 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lam.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/lam/lam.c,v 1.14 2005/08/05 01:04:36 jmallett Exp $");
+
+/*
+ * lam - laminate files
+ * Author: John Kunze, UCB
+ */
+
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#define MAXOFILES 20
+#define BIGBUFSIZ 5 * BUFSIZ
+
+struct openfile { /* open file structure */
+ FILE *fp; /* file pointer */
+ short eof; /* eof flag */
+ short pad; /* pad flag for missing columns */
+ char eol; /* end of line character */
+ const char *sepstring; /* string to print before each line */
+ const char *format; /* printf(3) style string spec. */
+} input[MAXOFILES];
+
+int morefiles; /* set by getargs(), changed by gatherline() */
+int nofinalnl; /* normally append \n to each output line */
+char line[BIGBUFSIZ];
+char *linep;
+
+static char *gatherline(struct openfile *);
+static void getargs(char *[]);
+static char *pad(struct openfile *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct openfile *ip;
+
+ if (argc == 1)
+ usage();
+ getargs(argv);
+ if (!morefiles)
+ usage();
+ for (;;) {
+ linep = line;
+ for (ip = input; ip->fp != NULL; ip++)
+ linep = gatherline(ip);
+ if (!morefiles)
+ exit(0);
+ fputs(line, stdout);
+ fputs(ip->sepstring, stdout);
+ if (!nofinalnl)
+ putchar('\n');
+ }
+}
+
+static void
+getargs(char *av[])
+{
+ struct openfile *ip = input;
+ char *p, *c;
+ static char fmtbuf[BUFSIZ];
+ char *fmtp = fmtbuf;
+ int P, S, F, T;
+
+ P = S = F = T = 0; /* capitalized options */
+ while ((p = *++av) != NULL) {
+ if (*p != '-' || !p[1]) {
+ if (++morefiles >= MAXOFILES)
+ errx(1, "too many input files");
+ if (*p == '-')
+ ip->fp = stdin;
+ else if ((ip->fp = fopen(p, "r")) == NULL) {
+ err(1, "%s", p);
+ }
+ ip->pad = P;
+ if (!ip->sepstring)
+ ip->sepstring = (S ? (ip-1)->sepstring : "");
+ if (!ip->format)
+ ip->format = ((P || F) ? (ip-1)->format : "%s");
+ if (!ip->eol)
+ ip->eol = (T ? (ip-1)->eol : '\n');
+ ip++;
+ continue;
+ }
+ c = ++p;
+ switch (tolower((unsigned char)*c)) {
+ case 's':
+ if (*++p || (p = *++av))
+ ip->sepstring = p;
+ else
+ usage();
+ S = (*c == 'S' ? 1 : 0);
+ break;
+ case 't':
+ if (*++p || (p = *++av))
+ ip->eol = *p;
+ else
+ usage();
+ T = (*c == 'T' ? 1 : 0);
+ nofinalnl = 1;
+ break;
+ case 'p':
+ ip->pad = 1;
+ P = (*c == 'P' ? 1 : 0);
+ /* FALLTHROUGH */
+ case 'f':
+ F = (*c == 'F' ? 1 : 0);
+ if (*++p || (p = *++av)) {
+ fmtp += strlen(fmtp) + 1;
+ if (fmtp >= fmtbuf + sizeof(fmtbuf))
+ errx(1, "no more format space");
+ /* restrict format string to only valid width formatters */
+ if (strspn(p, "-.0123456789") != strlen(p))
+ errx(1, "invalid format string `%s'", p);
+ if (snprintf(fmtp, fmtbuf + sizeof(fmtbuf) - fmtp, "%%%ss", p)
+ >= fmtbuf + sizeof(fmtbuf) - fmtp)
+ errx(1, "no more format space");
+ ip->format = fmtp;
+ }
+ else
+ usage();
+ break;
+ default:
+ usage();
+ }
+ }
+ ip->fp = NULL;
+ if (!ip->sepstring)
+ ip->sepstring = "";
+}
+
+static char *
+pad(struct openfile *ip)
+{
+ char *lp = linep;
+
+ strlcpy(lp, ip->sepstring, line + sizeof(line) - lp);
+ lp += strlen(lp);
+ if (ip->pad) {
+ snprintf(lp, line + sizeof(line) - lp, ip->format, "");
+ lp += strlen(lp);
+ }
+ return (lp);
+}
+
+static char *
+gatherline(struct openfile *ip)
+{
+ char s[BUFSIZ];
+ int c;
+ char *p;
+ char *lp = linep;
+ char *end = s + sizeof(s) - 1;
+
+ if (ip->eof)
+ return (pad(ip));
+ for (p = s; (c = fgetc(ip->fp)) != EOF && p < end; p++)
+ if ((*p = c) == ip->eol)
+ break;
+ *p = '\0';
+ if (c == EOF) {
+ ip->eof = 1;
+ if (ferror(ip->fp)) {
+ err(EX_IOERR, NULL);
+ }
+ if (ip->fp == stdin)
+ fclose(stdin);
+ morefiles--;
+ return (pad(ip));
+ }
+ strlcpy(lp, ip->sepstring, line + sizeof(line) - lp);
+ lp += strlen(lp);
+ snprintf(lp, line + sizeof(line) - lp, ip->format, s);
+ lp += strlen(lp);
+ return (lp);
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "%s\n%s\n",
+"usage: lam [ -f min.max ] [ -s sepstring ] [ -t c ] file ...",
+" lam [ -p min.max ] [ -s sepstring ] [ -t c ] file ...");
+ exit(1);
+}
diff --git a/text_cmds/look/look.1 b/text_cmds/look/look.1
new file mode 100644
index 0000000..fb8bc85
--- /dev/null
+++ b/text_cmds/look/look.1
@@ -0,0 +1,124 @@
+.\" Copyright (c) 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)look.1 8.1 (Berkeley) 6/14/93
+.\" $FreeBSD: src/usr.bin/look/look.1,v 1.17 2005/01/17 07:44:22 ru Exp $
+.\"
+.Dd July 17, 2004
+.Dt LOOK 1
+.Os
+.Sh NAME
+.Nm look
+.Nd display lines beginning with a given string
+.Sh SYNOPSIS
+.Nm
+.Op Fl df
+.Op Fl t Ar termchar
+.Ar string
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility displays any lines in
+.Ar file
+which contain
+.Ar string
+as a prefix.
+As
+.Nm
+performs a binary search, the lines in
+.Ar file
+must be sorted.
+.Pp
+If
+.Ar file
+is not specified, the file
+.Pa /usr/share/dict/words
+is used, only alphanumeric characters are compared and the case of
+alphabetic characters is ignored.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl d
+Dictionary character set and order, i.e., only alphanumeric characters
+are compared.
+.It Fl f
+Ignore the case of alphabetic characters.
+.It Fl t
+Specify a string termination character, i.e., only the characters
+in
+.Ar string
+up to and including the first occurrence of
+.Ar termchar
+are compared.
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of the
+.Nm
+utility.
+Their effect is described in
+.Xr environ 7 .
+.Sh FILES
+.Bl -tag -width /usr/share/dict/words -compact
+.It Pa /usr/share/dict/words
+the dictionary
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 if one or more lines were found and displayed,
+1 if no lines were found, and >1 if an error occurred.
+.Sh COMPATIBILITY
+The original manual page stated that tabs and blank characters participated
+in comparisons when the
+.Fl d
+option was specified.
+This was incorrect and the current man page matches the historic
+implementation.
+.Sh SEE ALSO
+.Xr grep 1 ,
+.Xr sort 1
+.Sh HISTORY
+A
+.Nm
+utility appeared in
+.At v7 .
+.Sh BUGS
+Lines are not compared according to the current locale's collating
+order.
+Input files must be sorted with
+.Ev LC_COLLATE
+set to
+.Ql C .
diff --git a/text_cmds/look/look.c b/text_cmds/look/look.c
new file mode 100644
index 0000000..4f146fa
--- /dev/null
+++ b/text_cmds/look/look.c
@@ -0,0 +1,357 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * David Hitz of Auspex Systems, Inc.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)look.c 8.2 (Berkeley) 5/4/95";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/look/look.c,v 1.18.10.2.4.1 2010/06/14 02:09:06 kensmith Exp $");
+
+/*
+ * look -- find lines in a sorted list.
+ *
+ * The man page said that TABs and SPACEs participate in -d comparisons.
+ * In fact, they were ignored. This implements historic practice, not
+ * the manual page.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "pathnames.h"
+
+static char _path_words[] = _PATH_WORDS;
+
+#define EQUAL 0
+#define GREATER 1
+#define LESS (-1)
+
+int dflag, fflag;
+
+char *binary_search(wchar_t *, unsigned char *, unsigned char *);
+int compare(wchar_t *, unsigned char *, unsigned char *);
+char *linear_search(wchar_t *, unsigned char *, unsigned char *);
+int look(wchar_t *, unsigned char *, unsigned char *);
+wchar_t *prepkey(const char *, wchar_t);
+void print_from(wchar_t *, unsigned char *, unsigned char *);
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ int ch, fd, match;
+ wchar_t termchar;
+ unsigned char *back, *front;
+ unsigned const char *file;
+ wchar_t *key;
+
+ (void) setlocale(LC_CTYPE, "");
+
+ file = _path_words;
+ termchar = L'\0';
+ while ((ch = getopt(argc, argv, "dft:")) != -1)
+ switch(ch) {
+ case 'd':
+ dflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 't':
+ if (mbrtowc(&termchar, optarg, MB_LEN_MAX, NULL) !=
+ strlen(optarg))
+ errx(2, "invalid termination character");
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+/* 4384130 */
+#ifdef __APPLE__
+ if (argc <= 0)
+#else
+ if (argc == 0)
+#endif
+ usage();
+ if (argc == 1) /* But set -df by default. */
+ dflag = fflag = 1;
+ key = prepkey(*argv++, termchar);
+ if (argc >= 2)
+ file = *argv++;
+
+ match = 1;
+
+ do {
+ if ((fd = open(file, O_RDONLY, 0)) < 0 || fstat(fd, &sb))
+ err(2, "%s", file);
+ if (sb.st_size > SIZE_T_MAX)
+ errx(2, "%s: %s", file, strerror(EFBIG));
+ if (sb.st_size == 0) {
+ close(fd);
+ continue;
+ }
+ if ((front = mmap(NULL, (size_t)sb.st_size, PROT_READ, MAP_SHARED, fd, (off_t)0)) == MAP_FAILED)
+ err(2, "%s", file);
+ back = front + sb.st_size;
+ match *= (look(key, front, back));
+ close(fd);
+ } while (argc-- > 2 && (file = *argv++));
+
+ exit(match);
+}
+
+wchar_t *
+prepkey(const char *string, wchar_t termchar)
+{
+ const char *readp;
+ wchar_t *key, *writep;
+ wchar_t ch;
+ size_t clen;
+
+ /*
+ * Reformat search string and convert to wide character representation
+ * to avoid doing it multiple times later.
+ */
+ if ((key = malloc(sizeof(wchar_t) * (strlen(string) + 1))) == NULL)
+ err(2, NULL);
+ readp = string;
+ writep = key;
+ while ((clen = mbrtowc(&ch, readp, MB_LEN_MAX, NULL)) != 0) {
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ errc(2, EILSEQ, NULL);
+ if (fflag)
+ ch = towlower(ch);
+ if (!dflag || iswalnum(ch))
+ *writep++ = ch;
+ readp += clen;
+ }
+ *writep = L'\0';
+ if (termchar != L'\0' && (writep = wcschr(key, termchar)) != NULL)
+ *++writep = L'\0';
+ return (key);
+}
+
+int
+look(wchar_t *string, unsigned char *front, unsigned char *back)
+{
+
+ front = binary_search(string, front, back);
+ front = linear_search(string, front, back);
+
+ if (front)
+ print_from(string, front, back);
+ return (front ? 0 : 1);
+}
+
+
+/*
+ * Binary search for "string" in memory between "front" and "back".
+ *
+ * This routine is expected to return a pointer to the start of a line at
+ * *or before* the first word matching "string". Relaxing the constraint
+ * this way simplifies the algorithm.
+ *
+ * Invariants:
+ * front points to the beginning of a line at or before the first
+ * matching string.
+ *
+ * back points to the beginning of a line at or after the first
+ * matching line.
+ *
+ * Base of the Invariants.
+ * front = NULL;
+ * back = EOF;
+ *
+ * Advancing the Invariants:
+ *
+ * p = first newline after halfway point from front to back.
+ *
+ * If the string at "p" is not greater than the string to match,
+ * p is the new front. Otherwise it is the new back.
+ *
+ * Termination:
+ *
+ * The definition of the routine allows it return at any point,
+ * since front is always at or before the line to print.
+ *
+ * In fact, it returns when the chosen "p" equals "back". This
+ * implies that there exists a string is least half as long as
+ * (back - front), which in turn implies that a linear search will
+ * be no more expensive than the cost of simply printing a string or two.
+ *
+ * Trying to continue with binary search at this point would be
+ * more trouble than it's worth.
+ */
+#define SKIP_PAST_NEWLINE(p, back) \
+ while (p < back && *p++ != '\n');
+
+char *
+binary_search(wchar_t *string, unsigned char *front, unsigned char *back)
+{
+ unsigned char *p;
+
+ p = front + (back - front) / 2;
+ SKIP_PAST_NEWLINE(p, back);
+
+ /*
+ * If the file changes underneath us, make sure we don't
+ * infinitely loop.
+ */
+ while (p < back && back > front) {
+ if (compare(string, p, back) == GREATER)
+ front = p;
+ else
+ back = p;
+ p = front + (back - front) / 2;
+ SKIP_PAST_NEWLINE(p, back);
+ }
+ return (front);
+}
+
+/*
+ * Find the first line that starts with string, linearly searching from front
+ * to back.
+ *
+ * Return NULL for no such line.
+ *
+ * This routine assumes:
+ *
+ * o front points at the first character in a line.
+ * o front is before or at the first line to be printed.
+ */
+char *
+linear_search(wchar_t *string, unsigned char *front, unsigned char *back)
+{
+ while (front < back) {
+ switch (compare(string, front, back)) {
+ case EQUAL: /* Found it. */
+ return (front);
+ case LESS: /* No such string. */
+ return (NULL);
+ case GREATER: /* Keep going. */
+ break;
+ }
+ SKIP_PAST_NEWLINE(front, back);
+ }
+ return (NULL);
+}
+
+/*
+ * Print as many lines as match string, starting at front.
+ */
+void
+print_from(wchar_t *string, unsigned char *front, unsigned char *back)
+{
+ for (; front < back && compare(string, front, back) == EQUAL; ++front) {
+ for (; front < back && *front != '\n'; ++front)
+ if (putchar(*front) == EOF)
+ err(2, "stdout");
+ if (putchar('\n') == EOF)
+ err(2, "stdout");
+ }
+}
+
+/*
+ * Return LESS, GREATER, or EQUAL depending on how the string1 compares with
+ * string2 (s1 ??? s2).
+ *
+ * o Matches up to len(s1) are EQUAL.
+ * o Matches up to len(s2) are GREATER.
+ *
+ * Compare understands about the -f and -d flags, and treats comparisons
+ * appropriately.
+ *
+ * The string "s1" is null terminated. The string s2 is '\n' terminated (or
+ * "back" terminated).
+ */
+int
+compare(wchar_t *s1, unsigned char *s2, unsigned char *back)
+{
+ wchar_t ch1, ch2;
+ size_t len2;
+
+ for (; *s1 && s2 < back && *s2 != '\n'; ++s1, s2 += len2) {
+ ch1 = *s1;
+ len2 = mbrtowc(&ch2, s2, back - s2, NULL);
+ if (len2 == (size_t)-1 || len2 == (size_t)-2) {
+ ch2 = *s2;
+ len2 = 1;
+ }
+ if (fflag)
+ ch2 = towlower(ch2);
+ if (dflag && !iswalnum(ch2)) {
+ /* Ignore character in comparison. */
+ --s1;
+ continue;
+ }
+ if (ch1 != ch2)
+ return (ch1 < ch2 ? LESS : GREATER);
+ }
+ return (*s1 ? GREATER : EQUAL);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: look [-df] [-t char] string [file ...]\n");
+ exit(2);
+}
diff --git a/text_cmds/look/pathnames.h b/text_cmds/look/pathnames.h
new file mode 100644
index 0000000..586e36a
--- /dev/null
+++ b/text_cmds/look/pathnames.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/9/93
+ */
+
+#define _PATH_WORDS "/usr/share/dict/words"
diff --git a/text_cmds/md5/commoncrypto.c b/text_cmds/md5/commoncrypto.c
new file mode 100644
index 0000000..3551afe
--- /dev/null
+++ b/text_cmds/md5/commoncrypto.c
@@ -0,0 +1,108 @@
+/* Generic CommonDigest wrappers to match the semantics of libmd. */
+
+#include <dispatch/dispatch.h>
+#include <os/assumes.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "commoncrypto.h"
+
+#define CHUNK_SIZE (10 * 1024 * 1024)
+
+char *
+Digest_End(CCDigestRef ctx, char *buf)
+{
+ static const char hex[] = "0123456789abcdef";
+ uint8_t digest[32]; // SHA256 is the biggest
+ size_t i, length;
+
+ (void)os_assumes_zero(CCDigestFinal(ctx, digest));
+ length = CCDigestOutputSize(ctx);
+ os_assert(length <= sizeof(digest));
+ for (i = 0; i < length; i++) {
+ buf[i+i] = hex[digest[i] >> 4];
+ buf[i+i+1] = hex[digest[i] & 0x0f];
+ }
+ buf[i+i] = '\0';
+ return buf;
+}
+
+char *
+Digest_Data(CCDigestAlg algorithm, const void *data, size_t len, char *buf)
+{
+ CCDigestCtx ctx;
+
+ (void)os_assumes_zero(CCDigestInit(algorithm, &ctx));
+ (void)os_assumes_zero(CCDigestUpdate(&ctx, data, len));
+ return Digest_End(&ctx, buf);
+}
+
+char *
+Digest_File(CCDigestAlg algorithm, const char *filename, char *buf)
+{
+ int fd;
+ __block CCDigestCtx ctx;
+ dispatch_queue_t queue;
+ dispatch_semaphore_t sema;
+ dispatch_io_t io;
+ __block int s_error = 0;
+ __block bool eof = false;
+ off_t chunk_offset;
+
+ /* dispatch_io_create_with_path requires an absolute path */
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ (void)fcntl(fd, F_NOCACHE, 1);
+
+ (void)os_assumes_zero(CCDigestInit(algorithm, &ctx));
+
+ queue = dispatch_queue_create("com.apple.mtree.io", NULL);
+ os_assert(queue);
+ sema = dispatch_semaphore_create(0);
+ os_assert(sema);
+
+ io = dispatch_io_create(DISPATCH_IO_STREAM, fd, queue, ^(int error) {
+ if (error != 0) {
+ s_error = error;
+ }
+ (void)close(fd);
+ (void)dispatch_semaphore_signal(sema);
+ });
+ os_assert(io);
+ for (chunk_offset = 0; eof == false && s_error == 0; chunk_offset += CHUNK_SIZE) {
+ dispatch_io_read(io, chunk_offset, CHUNK_SIZE, queue, ^(bool done, dispatch_data_t data, int error) {
+ if (data != NULL) {
+ (void)dispatch_data_apply(data, ^(__unused dispatch_data_t region, __unused size_t offset, const void *buffer, size_t size) {
+ (void)os_assumes_zero(CCDigestUpdate(&ctx, buffer, size));
+ return (bool)true;
+ });
+ }
+
+ if (error != 0) {
+ s_error = error;
+ }
+
+ if (done) {
+ eof = (data == dispatch_data_empty);
+ dispatch_semaphore_signal(sema);
+ }
+ });
+ dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+ }
+ dispatch_release(io); // it will close on its own
+
+ (void)dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
+
+ dispatch_release(queue);
+ dispatch_release(sema);
+
+ if (s_error != 0) {
+ errno = s_error;
+ return NULL;
+ }
+
+ return Digest_End(&ctx, buf);
+}
diff --git a/text_cmds/md5/commoncrypto.h b/text_cmds/md5/commoncrypto.h
new file mode 100644
index 0000000..ed10d9a
--- /dev/null
+++ b/text_cmds/md5/commoncrypto.h
@@ -0,0 +1,8 @@
+#include <CommonCrypto/CommonDigest.h>
+#include <CommonCrypto/CommonDigestSPI.h>
+
+char *Digest_End(CCDigestRef, char *);
+
+char *Digest_Data(CCDigestAlg, const void *, size_t, char *);
+
+char *Digest_File(CCDigestAlg, const char *, char *);
diff --git a/text_cmds/md5/md5.1 b/text_cmds/md5/md5.1
new file mode 100644
index 0000000..01df82b
--- /dev/null
+++ b/text_cmds/md5/md5.1
@@ -0,0 +1,95 @@
+.\" $FreeBSD: src/sbin/md5/md5.1,v 1.24 2005/03/10 09:56:39 cperciva Exp $
+.Dd June 6, 2004
+.Dt MD5 1
+.Os
+.Sh NAME
+.Nm md5
+.Nd calculate a message-digest fingerprint (checksum) for a file
+.Sh SYNOPSIS
+.Nm md5
+.Op Fl pqrtx
+.Op Fl s Ar string
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility takes as input a message of arbitrary length and produces as
+output a
+.Dq fingerprint
+or
+.Dq message digest
+of the input.
+It is conjectured that it is computationally infeasible to
+produce two messages having the same message digest, or to produce any
+message having a given prespecified target message digest.
+The
+.Tn MD5
+algorithm is intended for digital signature applications, where a
+large file must be
+.Dq compressed
+in a secure manner before being encrypted with a private
+(secret)
+key under a public-key cryptosystem such as
+.Tn RSA .
+.Pp
+.Tn MD5's
+designer Ron Rivest has stated "md5 and sha1 are both clearly broken (in terms
+of collision-resistance)".
+So
+.Tn MD5
+should be avoided when creating new protocols, or implementing protocols with better options.
+.Tn SHA256
+and
+.Tn SHA512
+are better options as they have been more resilient to attacks (as of 2009).
+.Pp
+The following options may be used in any combination and must
+precede any files named on the command line.
+The hexadecimal checksum of each file listed on the command line is printed
+after the options are processed.
+.Bl -tag -width indent
+.It Fl s Ar string
+Print a checksum of the given
+.Ar string .
+.It Fl p
+Echo stdin to stdout and append the checksum to stdout.
+.It Fl q
+Quiet mode - only the checksum is printed out.
+Overrides the
+.Fl r
+option.
+.It Fl r
+Reverses the format of the output.
+This helps with visual diffs.
+Does nothing
+when combined with the
+.Fl ptx
+options.
+.It Fl t
+Run a built-in time trial.
+.It Fl x
+Run a built-in test script.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 on success,
+and 1 if at least one of the input files could not be read.
+.Sh SEE ALSO
+.Xr cksum 1 ,
+.Xr md5 3 ,
+.Xr ripemd 3 ,
+.Xr sha 3 ,
+.Xr CC_SHA256_Init 3
+.Rs
+.%A R. Rivest
+.%T The MD5 Message-Digest Algorithm
+.%O RFC1321
+.Rs
+.%A Vlastimil Klima
+.%T Finding MD5 Collisions - a Toy For a Notebook
+.%O Cryptology ePrint Archive: Report 2005/075
+.Re
+.Sh ACKNOWLEDGMENTS
+This program is placed in the public domain for free general use by
+RSA Data Security.
diff --git a/text_cmds/md5/md5.c b/text_cmds/md5/md5.c
new file mode 100644
index 0000000..9be53d3
--- /dev/null
+++ b/text_cmds/md5/md5.c
@@ -0,0 +1,419 @@
+/*
+ * Derived from:
+ *
+ * MDDRIVER.C - test driver for MD2, MD4 and MD5
+ */
+
+/*
+ * Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+ * rights reserved.
+ *
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ *
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sbin/md5/md5.c,v 1.34 2005/03/09 19:23:04 cperciva Exp $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <err.h>
+#ifndef __APPLE__
+#include <md5.h>
+#include <ripemd.h>
+#include <sha.h>
+#include <sha256.h>
+#endif /* !__APPLE__ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#ifdef __APPLE__
+#include "commoncrypto.h"
+#endif /* __APPLE__ */
+
+/*
+ * Length of test block, number of test blocks.
+ */
+#define TEST_BLOCK_LEN 10000
+#define TEST_BLOCK_COUNT 100000
+#define MDTESTCOUNT 8
+
+int qflag;
+int rflag;
+int sflag;
+
+typedef void (DIGEST_Init)(void *);
+typedef void (DIGEST_Update)(void *, const unsigned char *, size_t);
+typedef char *(DIGEST_End)(void *, char *);
+
+extern const char *MD5TestOutput[MDTESTCOUNT];
+extern const char *SHA1_TestOutput[MDTESTCOUNT];
+extern const char *SHA256_TestOutput[MDTESTCOUNT];
+extern const char *RIPEMD160_TestOutput[MDTESTCOUNT];
+
+typedef struct Algorithm_t {
+ const char *progname;
+ const char *name;
+ const char *(*TestOutput)[MDTESTCOUNT];
+#ifdef __APPLE__
+ CCDigestAlg algorithm;
+#else /* !__APPLE__ */
+ DIGEST_Init *Init;
+ DIGEST_Update *Update;
+ DIGEST_End *End;
+ char *(*Data)(const unsigned char *, unsigned int, char *);
+ char *(*File)(const char *, char *);
+#endif /* __APPLE__ */
+} Algorithm_t;
+
+#ifndef __APPLE__
+static void MD5_Update(MD5_CTX *, const unsigned char *, size_t);
+#endif /* !__APPLE__ */
+static void MDString(Algorithm_t *, const char *);
+static void MDTimeTrial(Algorithm_t *);
+static void MDTestSuite(Algorithm_t *);
+static void MDFilter(Algorithm_t *, int);
+static void usage(Algorithm_t *);
+
+#ifdef __APPLE__
+typedef CCDigestCtx DIGEST_CTX;
+#else /* !__APPLE__ */
+typedef union {
+ MD5_CTX md5;
+ SHA1_CTX sha1;
+ SHA256_CTX sha256;
+ RIPEMD160_CTX ripemd160;
+} DIGEST_CTX;
+#endif /* __APPLE__ */
+
+/* max(MD5_DIGEST_LENGTH, SHA_DIGEST_LENGTH,
+ SHA256_DIGEST_LENGTH, RIPEMD160_DIGEST_LENGTH)*2+1 */
+#define HEX_DIGEST_LENGTH 65
+
+/* algorithm function table */
+
+struct Algorithm_t Algorithm[] = {
+#ifdef __APPLE__
+ { "md5", "MD5", &MD5TestOutput, kCCDigestMD5, },
+ { "sha1", "SHA1", &SHA1_TestOutput, kCCDigestSHA1 },
+ { "sha256", "SHA256", &SHA256_TestOutput, kCCDigestSHA256 },
+ { "rmd160", "RMD160", &RIPEMD160_TestOutput, kCCDigestRMD160 },
+#else
+ { "md5", "MD5", &MD5TestOutput, (DIGEST_Init*)&MD5Init,
+ (DIGEST_Update*)&MD5_Update, (DIGEST_End*)&MD5End,
+ &MD5Data, &MD5File },
+ { "sha1", "SHA1", &SHA1_TestOutput, (DIGEST_Init*)&SHA1_Init,
+ (DIGEST_Update*)&SHA1_Update, (DIGEST_End*)&SHA1_End,
+ &SHA1_Data, &SHA1_File },
+ { "sha256", "SHA256", &SHA256_TestOutput, (DIGEST_Init*)&SHA256_Init,
+ (DIGEST_Update*)&SHA256_Update, (DIGEST_End*)&SHA256_End,
+ &SHA256_Data, &SHA256_File },
+ { "rmd160", "RMD160", &RIPEMD160_TestOutput,
+ (DIGEST_Init*)&RIPEMD160_Init, (DIGEST_Update*)&RIPEMD160_Update,
+ (DIGEST_End*)&RIPEMD160_End, &RIPEMD160_Data, &RIPEMD160_File }
+#endif
+};
+
+#ifndef __APPLE__
+static void
+MD5_Update(MD5_CTX *c, const unsigned char *data, size_t len)
+{
+ MD5Update(c, data, len);
+}
+#endif /* !__APPLE__ */
+
+/* Main driver.
+
+Arguments (may be any combination):
+ -sstring - digests string
+ -t - runs time trial
+ -x - runs test script
+ filename - digests file
+ (none) - digests standard input
+ */
+int
+main(int argc, char *argv[])
+{
+ int ch;
+ char *p;
+ char buf[HEX_DIGEST_LENGTH];
+ int failed=0;
+ unsigned digest=0;
+ const char* progname;
+
+ if(*argv) {
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ for (digest = 0; digest < sizeof(Algorithm)/sizeof(*Algorithm); digest++)
+ if (strcasecmp(Algorithm[digest].progname, progname) == 0)
+ break;
+
+ if (digest == sizeof(Algorithm)/sizeof(*Algorithm))
+ digest = 0;
+ }
+
+ while ((ch = getopt(argc, argv, "pqrs:tx")) != -1)
+ switch (ch) {
+ case 'p':
+ MDFilter(&Algorithm[digest], 1);
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ MDString(&Algorithm[digest], optarg);
+ break;
+ case 't':
+ MDTimeTrial(&Algorithm[digest]);
+ break;
+ case 'x':
+ MDTestSuite(&Algorithm[digest]);
+ break;
+ default:
+ usage(&Algorithm[digest]);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv) {
+ do {
+#ifdef __APPLE__
+ p = Digest_File(Algorithm[digest].algorithm, *argv, buf);
+#else
+ p = Algorithm[digest].File(*argv, buf);
+#endif
+ if (!p) {
+ warn("%s", *argv);
+ failed++;
+ } else {
+ if (qflag)
+ printf("%s\n", p);
+ else if (rflag)
+ printf("%s %s\n", p, *argv);
+ else
+ printf("%s (%s) = %s\n", Algorithm[digest].name, *argv, p);
+ }
+ } while (*++argv);
+ } else if (!sflag && (optind == 1 || qflag || rflag))
+ MDFilter(&Algorithm[digest], 0);
+
+ if (failed != 0)
+ return (1);
+
+ return (0);
+}
+/*
+ * Digests a string and prints the result.
+ */
+static void
+MDString(Algorithm_t *alg, const char *string)
+{
+ size_t len = strlen(string);
+ char buf[HEX_DIGEST_LENGTH];
+
+ if (qflag)
+#ifdef __APPLE__
+ printf("%s\n", Digest_Data(alg->algorithm, string, len, buf));
+ else if (rflag)
+ printf("%s \"%s\"\n", Digest_Data(alg->algorithm, string, len, buf), string);
+ else
+ printf("%s (\"%s\") = %s\n", alg->name, string, Digest_Data(alg->algorithm, string, len, buf));
+#else /* !__APPLE__ */
+ printf("%s\n", alg->Data(string, len, buf));
+ else if (rflag)
+ printf("%s \"%s\"\n", alg->Data(string, len, buf), string);
+ else
+ printf("%s (\"%s\") = %s\n", alg->name, string, alg->Data(string, len, buf));
+#endif /* __APPLE__ */
+}
+/*
+ * Measures the time to digest TEST_BLOCK_COUNT TEST_BLOCK_LEN-byte blocks.
+ */
+static void
+MDTimeTrial(Algorithm_t *alg)
+{
+ DIGEST_CTX context;
+ struct rusage before, after;
+ struct timeval total;
+ float seconds;
+ unsigned char block[TEST_BLOCK_LEN];
+ unsigned int i;
+ char *p, buf[HEX_DIGEST_LENGTH];
+
+ printf
+ ("%s time trial. Digesting %d %d-byte blocks ...",
+ alg->name, TEST_BLOCK_COUNT, TEST_BLOCK_LEN);
+ fflush(stdout);
+
+ /* Initialize block */
+ for (i = 0; i < TEST_BLOCK_LEN; i++)
+ block[i] = (unsigned char) (i & 0xff);
+
+ /* Start timer */
+ getrusage(0, &before);
+
+ /* Digest blocks */
+#ifdef __APPLE__
+ CCDigestInit(alg->algorithm, &context);
+ for (i = 0; i < TEST_BLOCK_COUNT; i++)
+ CCDigestUpdate(&context, block, TEST_BLOCK_LEN);
+ p = Digest_End(&context, buf);
+#else
+ alg->Init(&context);
+ for (i = 0; i < TEST_BLOCK_COUNT; i++)
+ alg->Update(&context, block, TEST_BLOCK_LEN);
+ p = alg->End(&context, buf);
+#endif
+
+ /* Stop timer */
+ getrusage(0, &after);
+ timersub(&after.ru_utime, &before.ru_utime, &total);
+ seconds = total.tv_sec + (float) total.tv_usec / 1000000;
+
+ printf(" done\n");
+ printf("Digest = %s", p);
+ printf("\nTime = %f seconds\n", seconds);
+ printf
+ ("Speed = %f bytes/second\n",
+ (float) TEST_BLOCK_LEN * (float) TEST_BLOCK_COUNT / seconds);
+}
+/*
+ * Digests a reference suite of strings and prints the results.
+ */
+
+const char *MDTestInput[MDTESTCOUNT] = {
+ "",
+ "a",
+ "abc",
+ "message digest",
+ "abcdefghijklmnopqrstuvwxyz",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "MD5 has not yet (2001-09-03) been broken, but sufficient attacks have been made \
+that its security is in some doubt"
+};
+
+const char *MD5TestOutput[MDTESTCOUNT] = {
+ "d41d8cd98f00b204e9800998ecf8427e",
+ "0cc175b9c0f1b6a831c399e269772661",
+ "900150983cd24fb0d6963f7d28e17f72",
+ "f96b697d7cb7938d525a2f31aaf161d0",
+ "c3fcd3d76192e4007dfb496cca67e13b",
+ "d174ab98d277d9f5a5611c2c9f419d9f",
+ "57edf4a22be3c955ac49da2e2107b67a",
+ "b50663f41d44d92171cb9976bc118538"
+};
+
+const char *SHA1_TestOutput[MDTESTCOUNT] = {
+ "da39a3ee5e6b4b0d3255bfef95601890afd80709",
+ "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8",
+ "a9993e364706816aba3e25717850c26c9cd0d89d",
+ "c12252ceda8be8994d5fa0290a47231c1d16aae3",
+ "32d10c7b8cf96570ca04ce37f2a19d84240d3a89",
+ "761c457bf73b14d27e9e9265c46f4b4dda11f940",
+ "50abf5706a150990a08b2c5ea40fa0e585554732",
+ "18eca4333979c4181199b7b4fab8786d16cf2846"
+};
+
+const char *SHA256_TestOutput[MDTESTCOUNT] = {
+ "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
+ "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
+ "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
+ "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650",
+ "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73",
+ "db4bfcbd4da0cd85a60c3c37d3fbd8805c77f15fc6b1fdfe614ee0a7c8fdb4c0",
+ "f371bc4a311f2b009eef952dd83ca80e2b60026c8e935592d0f9c308453c813e",
+ "e6eae09f10ad4122a0e2a4075761d185a272ebd9f5aa489e998ff2f09cbfdd9f"
+};
+
+const char *RIPEMD160_TestOutput[MDTESTCOUNT] = {
+ "9c1185a5c5e9fc54612808977ee8f548b2258d31",
+ "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe",
+ "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc",
+ "5d0689ef49d2fae572b881b123a85ffa21595f36",
+ "f71c27109c692c1b56bbdceb5b9d2865b3708dbc",
+ "b0e20b6e3116640286ed3a87a5713079b21f5189",
+ "9b752e45573d4b39f4dbd3323cab82bf63326bfb",
+ "5feb69c6bf7c29d95715ad55f57d8ac5b2b7dd32"
+};
+
+static void
+MDTestSuite(Algorithm_t *alg)
+{
+ int i;
+ char buffer[HEX_DIGEST_LENGTH];
+
+ printf("%s test suite:\n", alg->name);
+ for (i = 0; i < MDTESTCOUNT; i++) {
+#ifdef __APPLE__
+ Digest_Data(alg->algorithm, MDTestInput[i], strlen(MDTestInput[i]), buffer);
+#else
+ (*alg->Data)(MDTestInput[i], strlen(MDTestInput[i]), buffer);
+#endif
+ printf("%s (\"%s\") = %s", alg->name, MDTestInput[i], buffer);
+ if (strcmp(buffer, (*alg->TestOutput)[i]) == 0)
+ printf(" - verified correct\n");
+ else
+ printf(" - INCORRECT RESULT!\n");
+ }
+}
+
+/*
+ * Digests the standard input and prints the result.
+ */
+static void
+MDFilter(Algorithm_t *alg, int tee)
+{
+ DIGEST_CTX context;
+ unsigned int len;
+ unsigned char buffer[BUFSIZ];
+ char buf[HEX_DIGEST_LENGTH];
+
+#ifdef __APPLE__
+ CCDigestInit(alg->algorithm, &context);
+#else
+ alg->Init(&context);
+#endif
+ while ((len = fread(buffer, 1, BUFSIZ, stdin))) {
+ if (tee && len != fwrite(buffer, 1, len, stdout))
+ err(1, "stdout");
+#ifdef __APPLE__
+ CCDigestUpdate(&context, buffer, len);
+#else
+ alg->Update(&context, buffer, len);
+#endif
+ }
+ if (ferror(stdin)) {
+ errx(EX_IOERR, NULL);
+ }
+#ifdef __APPLE__
+ printf("%s\n", Digest_End(&context, buf));
+#else
+ printf("%s\n", alg->End(&context, buf));
+#endif
+}
+
+static void
+usage(Algorithm_t *alg)
+{
+
+ fprintf(stderr, "usage: %s [-pqrtx] [-s string] [files ...]\n", alg->progname);
+ exit(1);
+}
diff --git a/text_cmds/nl/nl.1 b/text_cmds/nl/nl.1
new file mode 100644
index 0000000..50708fb
--- /dev/null
+++ b/text_cmds/nl/nl.1
@@ -0,0 +1,253 @@
+.\" $FreeBSD: src/usr.bin/nl/nl.1,v 1.16 2005/01/25 22:32:48 tjr Exp $
+.\"
+.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Klaus Klein.
+.\"
+.\" 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 the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation 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 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.
+.\"
+.Dd January 26, 2005
+.Dt NL 1
+.Os
+.Sh NAME
+.Nm nl
+.Nd line numbering filter
+.Sh SYNOPSIS
+.Nm
+.Op Fl p
+.Bk -words
+.Op Fl b Ar type
+.Ek
+.Bk -words
+.Op Fl d Ar delim
+.Ek
+.Bk -words
+.Op Fl f Ar type
+.Ek
+.Bk -words
+.Op Fl h Ar type
+.Ek
+.Bk -words
+.Op Fl i Ar incr
+.Ek
+.Bk -words
+.Op Fl l Ar num
+.Ek
+.Bk -words
+.Op Fl n Ar format
+.Ek
+.Bk -words
+.Op Fl s Ar sep
+.Ek
+.Bk -words
+.Op Fl v Ar startnum
+.Ek
+.Bk -words
+.Op Fl w Ar width
+.Ek
+.Op Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility reads lines from the named
+.Ar file
+or the standard input if the
+.Ar file
+argument is omitted,
+applies a configurable line numbering filter operation and writes the result
+to the standard output.
+.Pp
+The
+.Nm
+utility treats the text it reads in terms of logical pages.
+Unless specified otherwise, line numbering is reset at the start of each
+logical page.
+A logical page consists of a header, a body and a footer
+section; empty sections are valid.
+Different line numbering options are
+independently available for header, body and footer sections.
+.Pp
+The starts of logical page sections are signalled by input lines containing
+nothing but one of the following sequences of delimiter characters:
+.Pp
+.Bl -column "\e:\e:\e:" "Start of" -offset indent
+.Em "Line Start of"
+.It "\e:\e:\e: header"
+.It "\e:\e: body"
+.It "\e: footer"
+.El
+.Pp
+If the input does not contain any logical page section signalling directives,
+the text being read is assumed to consist of a single logical page body.
+.Pp
+The following options are available:
+.Bl -tag -width ".Fl v Ar startnum"
+.It Fl b Ar type
+Specify the logical page body lines to be numbered.
+Recognized
+.Ar type
+arguments are:
+.Bl -tag -width indent
+.It Cm a
+Number all lines.
+.It Cm t
+Number only non-empty lines.
+.It Cm n
+No line numbering.
+.It Cm p Ns Ar expr
+Number only those lines that contain the basic regular expression specified
+by
+.Ar expr .
+.El
+.Pp
+The default
+.Ar type
+for logical page body lines is
+.Cm t .
+.It Fl d Ar delim
+Specify the delimiter characters used to indicate the start of a logical
+page section in the input file.
+At most two characters may be specified;
+if only one character is specified, the first character is replaced and the
+second character remains unchanged.
+The default
+.Ar delim
+characters are
+.Dq Li \e: .
+.It Fl f Ar type
+Specify the same as
+.Fl b Ar type
+except for logical page footer lines.
+The default
+.Ar type
+for logical page footer lines is
+.Cm n .
+.It Fl h Ar type
+Specify the same as
+.Fl b Ar type
+except for logical page header lines.
+The default
+.Ar type
+for logical page header lines is
+.Cm n .
+.It Fl i Ar incr
+Specify the increment value used to number logical page lines.
+The default
+.Ar incr
+value is 1.
+.It Fl l Ar num
+If numbering of all lines is specified for the current logical section
+using the corresponding
+.Fl b Cm a ,
+.Fl f Cm a
+or
+.Fl h Cm a
+option,
+specify the number of adjacent blank lines to be considered as one.
+For example,
+.Fl l
+2 results in only the second adjacent blank line being numbered.
+The default
+.Ar num
+value is 1.
+.It Fl n Ar format
+Specify the line numbering output format.
+Recognized
+.Ar format
+arguments are:
+.Bl -tag -width indent -compact
+.It Cm ln
+Left justified.
+.It Cm rn
+Right justified, leading zeros suppressed.
+.It Cm rz
+Right justified, leading zeros kept.
+.El
+.Pp
+The default
+.Ar format
+is
+.Cm rn .
+.It Fl p
+Specify that line numbering should not be restarted at logical page delimiters.
+.It Fl s Ar sep
+Specify the characters used in separating the line number and the corresponding
+text line.
+The default
+.Ar sep
+setting is a single tab character.
+.It Fl v Ar startnum
+Specify the initial value used to number logical page lines; see also the
+description of the
+.Fl p
+option.
+The default
+.Ar startnum
+value is 1.
+.It Fl w Ar width
+Specify the number of characters to be occupied by the line number;
+in case the
+.Ar width
+is insufficient to hold the line number, it will be truncated to its
+.Ar width
+least significant digits.
+The default
+.Ar width
+is 6.
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_CTYPE
+and
+.Ev LC_COLLATE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr jot 1 ,
+.Xr pr 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.At V.2 .
+.Sh BUGS
+Input lines are limited to
+.Dv LINE_MAX
+(2048) bytes in length.
diff --git a/text_cmds/nl/nl.c b/text_cmds/nl/nl.c
new file mode 100644
index 0000000..3de82f2
--- /dev/null
+++ b/text_cmds/nl/nl.c
@@ -0,0 +1,439 @@
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Klaus Klein.
+ *
+ * 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 the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT(
+"@(#) Copyright (c) 1999\
+ The NetBSD Foundation, Inc. All rights reserved.");
+__RCSID("$FreeBSD: src/usr.bin/nl/nl.c,v 1.10 2005/04/09 14:31:41 stefanf Exp $");
+#endif
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+typedef enum {
+ number_all, /* number all lines */
+ number_nonempty, /* number non-empty lines */
+ number_none, /* no line numbering */
+ number_regex /* number lines matching regular expression */
+} numbering_type;
+
+struct numbering_property {
+ const char * const name; /* for diagnostics */
+ numbering_type type; /* numbering type */
+ regex_t expr; /* for type == number_regex */
+};
+
+/* line numbering formats */
+#define FORMAT_LN "%-*d" /* left justified, leading zeros suppressed */
+#define FORMAT_RN "%*d" /* right justified, leading zeros suppressed */
+#define FORMAT_RZ "%0*d" /* right justified, leading zeros kept */
+
+#define FOOTER 0
+#define BODY 1
+#define HEADER 2
+#define NP_LAST HEADER
+
+static struct numbering_property numbering_properties[NP_LAST + 1] = {
+ { "footer", number_none },
+ { "body", number_nonempty },
+ { "header", number_none }
+};
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+/*
+ * Maximum number of characters required for a decimal representation of a
+ * (signed) int; courtesy of tzcode.
+ */
+#define INT_STRLEN_MAXIMUM \
+ ((sizeof (int) * CHAR_BIT - 1) * 302 / 1000 + 2)
+
+static void filter(void);
+static void parse_numbering(const char *, int);
+static void usage(void);
+
+/*
+ * Pointer to dynamically allocated input line buffer, and its size.
+ */
+static char *buffer;
+static size_t buffersize;
+
+/*
+ * Dynamically allocated buffer suitable for string representation of ints.
+ */
+static char *intbuffer;
+
+/* delimiter characters that indicate the start of a logical page section */
+static char delim[2 * MB_LEN_MAX];
+static int delimlen;
+
+/*
+ * Configurable parameters.
+ */
+
+/* line numbering format */
+static const char *format = FORMAT_RN;
+
+/* increment value used to number logical page lines */
+static int incr = 1;
+
+/* number of adjacent blank lines to be considered (and numbered) as one */
+static unsigned int nblank = 1;
+
+/* whether to restart numbering at logical page delimiters */
+static int restart = 1;
+
+/* characters used in separating the line number and the corrsp. text line */
+static const char *sep = "\t";
+
+/* initial value used to number logical page lines */
+static int startnum = 1;
+
+/* number of characters to be used for the line number */
+/* should be unsigned but required signed by `*' precision conversion */
+static int width = 6;
+
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ long val;
+ unsigned long uval;
+ char *ep;
+ size_t intbuffersize, clen;
+ char delim1[MB_LEN_MAX] = { '\\' }, delim2[MB_LEN_MAX] = { ':' };
+ size_t delim1len = 1, delim2len = 1;
+
+ (void)setlocale(LC_ALL, "");
+
+ while ((c = getopt(argc, argv, "pb:d:f:h:i:l:n:s:v:w:")) != -1) {
+ switch (c) {
+ case 'p':
+ restart = 0;
+ break;
+ case 'b':
+ parse_numbering(optarg, BODY);
+ break;
+ case 'd':
+ clen = mbrlen(optarg, MB_CUR_MAX, NULL);
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ errc(EXIT_FAILURE, EILSEQ, NULL);
+ if (clen != 0) {
+ memcpy(delim1, optarg, delim1len = clen);
+ clen = mbrlen(optarg + delim1len,
+ MB_CUR_MAX, NULL);
+ if (clen == (size_t)-1 ||
+ clen == (size_t)-2)
+ errc(EXIT_FAILURE, EILSEQ, NULL);
+ if (clen != 0) {
+ memcpy(delim2, optarg + delim1len,
+ delim2len = clen);
+ if (optarg[delim1len + clen] != '\0')
+ errx(EXIT_FAILURE,
+ "invalid delim argument -- %s",
+ optarg);
+ }
+ }
+ break;
+ case 'f':
+ parse_numbering(optarg, FOOTER);
+ break;
+ case 'h':
+ parse_numbering(optarg, HEADER);
+ break;
+ case 'i':
+ errno = 0;
+ val = strtol(optarg, &ep, 10);
+ if ((ep != NULL && *ep != '\0') ||
+ ((val == LONG_MIN || val == LONG_MAX) && errno != 0))
+ errx(EXIT_FAILURE,
+ "invalid incr argument -- %s", optarg);
+ incr = (int)val;
+ break;
+ case 'l':
+ errno = 0;
+ uval = strtoul(optarg, &ep, 10);
+ if ((ep != NULL && *ep != '\0') ||
+ (uval == ULONG_MAX && errno != 0))
+ errx(EXIT_FAILURE,
+ "invalid num argument -- %s", optarg);
+ nblank = (unsigned int)uval;
+ break;
+ case 'n':
+ if (strcmp(optarg, "ln") == 0) {
+ format = FORMAT_LN;
+ } else if (strcmp(optarg, "rn") == 0) {
+ format = FORMAT_RN;
+ } else if (strcmp(optarg, "rz") == 0) {
+ format = FORMAT_RZ;
+ } else
+ errx(EXIT_FAILURE,
+ "illegal format -- %s", optarg);
+ break;
+ case 's':
+ sep = optarg;
+ break;
+ case 'v':
+ errno = 0;
+ val = strtol(optarg, &ep, 10);
+ if ((ep != NULL && *ep != '\0') ||
+ ((val == LONG_MIN || val == LONG_MAX) && errno != 0))
+ errx(EXIT_FAILURE,
+ "invalid startnum value -- %s", optarg);
+ startnum = (int)val;
+ break;
+ case 'w':
+ errno = 0;
+ val = strtol(optarg, &ep, 10);
+ if ((ep != NULL && *ep != '\0') ||
+ ((val == LONG_MIN || val == LONG_MAX) && errno != 0))
+ errx(EXIT_FAILURE,
+ "invalid width value -- %s", optarg);
+ width = (int)val;
+ if (!(width > 0))
+ errx(EXIT_FAILURE,
+ "width argument must be > 0 -- %d",
+ width);
+ break;
+ case '?':
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch (argc) {
+ case 0:
+ break;
+ case 1:
+ if (!*argv) usage();
+ if (freopen(argv[0], "r", stdin) == NULL)
+ err(EXIT_FAILURE, "%s", argv[0]);
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ /* Generate the delimiter sequence */
+ memcpy(delim, delim1, delim1len);
+ memcpy(delim + delim1len, delim2, delim2len);
+ delimlen = delim1len + delim2len;
+
+ /* Determine the maximum input line length to operate on. */
+ if ((val = sysconf(_SC_LINE_MAX)) == -1) /* ignore errno */
+ val = LINE_MAX;
+ /* Allocate sufficient buffer space (including the terminating NUL). */
+ buffersize = (size_t)val + 1;
+ if ((buffer = malloc(buffersize)) == NULL)
+ err(EXIT_FAILURE, "cannot allocate input line buffer");
+
+ /* Allocate a buffer suitable for preformatting line number. */
+ intbuffersize = max(INT_STRLEN_MAXIMUM, width) + 1; /* NUL */
+ if ((intbuffer = malloc(intbuffersize)) == NULL)
+ err(EXIT_FAILURE, "cannot allocate preformatting buffer");
+
+ /* Do the work. */
+ filter();
+
+ exit(EXIT_SUCCESS);
+ /* NOTREACHED */
+}
+
+static void
+filter()
+{
+ int line; /* logical line number */
+ int section; /* logical page section */
+ unsigned int adjblank; /* adjacent blank lines */
+ int consumed; /* intbuffer measurement */
+ int donumber, idx;
+
+ adjblank = 0;
+ line = startnum;
+ section = BODY;
+#ifdef __GNUC__
+ (void)&donumber; /* avoid bogus `uninitialized' warning */
+#endif
+
+ while (fgets(buffer, (int)buffersize, stdin) != NULL) {
+ for (idx = FOOTER; idx <= NP_LAST; idx++) {
+ /* Does it look like a delimiter? */
+ if (memcmp(buffer + delimlen * idx, delim,
+ delimlen) == 0) {
+ /* Was this the whole line? */
+ if (buffer[delimlen * (idx + 1)] == '\n') {
+#ifdef __APPLE__
+ /* if user wishes to restart line numbering on each logical page, AND
+ * the new section is logically "before", or the same as, the current
+ * section (thereby starting a new logical page), reset the line numbers.
+ */
+ if (restart && idx >= section)
+ line = startnum;
+#endif /* __APPLE __*/
+ section = idx;
+ adjblank = 0;
+#ifndef __APPLE__
+ if (restart)
+ line = startnum;
+#endif /* !__APPLE__ */
+ goto nextline;
+ }
+ } else {
+ break;
+ }
+ }
+
+ switch (numbering_properties[section].type) {
+ case number_all:
+ /*
+ * Doing this for number_all only is disputable, but
+ * the standard expresses an explicit dependency on
+ * `-b a' etc.
+ */
+ if (buffer[0] == '\n' && ++adjblank < nblank)
+ donumber = 0;
+ else
+ donumber = 1, adjblank = 0;
+ break;
+ case number_nonempty:
+ donumber = (buffer[0] != '\n');
+ break;
+ case number_none:
+ donumber = 0;
+ break;
+ case number_regex:
+ donumber =
+ (regexec(&numbering_properties[section].expr,
+ buffer, 0, NULL, 0) == 0);
+ break;
+ }
+
+ if (donumber) {
+ /* Note: sprintf() is safe here. */
+ consumed = sprintf(intbuffer, format, width, line);
+ (void)printf("%s",
+ intbuffer + max(0, consumed - width));
+ line += incr;
+ } else {
+ (void)printf("%*s", width, "");
+ }
+ (void)printf("%s%s", sep, buffer);
+
+ if (ferror(stdout))
+ err(EXIT_FAILURE, "output error");
+nextline:
+ ;
+ }
+
+ if (ferror(stdin))
+ err(EXIT_FAILURE, "input error");
+}
+
+/*
+ * Various support functions.
+ */
+
+static void
+parse_numbering(argstr, section)
+ const char *argstr;
+ int section;
+{
+ int error;
+ char errorbuf[NL_TEXTMAX];
+
+ switch (argstr[0]) {
+ case 'a':
+ numbering_properties[section].type = number_all;
+ break;
+ case 'n':
+ numbering_properties[section].type = number_none;
+ break;
+ case 't':
+ numbering_properties[section].type = number_nonempty;
+ break;
+ case 'p':
+ /* If there was a previous expression, throw it away. */
+ if (numbering_properties[section].type == number_regex)
+ regfree(&numbering_properties[section].expr);
+ else
+ numbering_properties[section].type = number_regex;
+
+ /* Compile/validate the supplied regular expression. */
+ if ((error = regcomp(&numbering_properties[section].expr,
+ &argstr[1], REG_NEWLINE|REG_NOSUB)) != 0) {
+ (void)regerror(error,
+ &numbering_properties[section].expr,
+ errorbuf, sizeof (errorbuf));
+ errx(EXIT_FAILURE,
+ "%s expr: %s -- %s",
+ numbering_properties[section].name, errorbuf,
+ &argstr[1]);
+ }
+ break;
+ default:
+ errx(EXIT_FAILURE,
+ "illegal %s line numbering type -- %s",
+ numbering_properties[section].name, argstr);
+ }
+}
+
+static void
+usage()
+{
+
+ (void)fprintf(stderr,
+"usage: nl [-p] [-b type] [-d delim] [-f type] [-h type] [-i incr] [-l num]\n"
+" [-n format] [-s sep] [-v startnum] [-w width] [file]\n");
+ exit(EXIT_FAILURE);
+}
diff --git a/text_cmds/paste/paste.1 b/text_cmds/paste/paste.1
new file mode 100644
index 0000000..f5a4aa6
--- /dev/null
+++ b/text_cmds/paste/paste.1
@@ -0,0 +1,150 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Adam S. Moskowitz and the Institute of Electrical and Electronics
+.\" Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)paste.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/paste/paste.1,v 1.19 2005/01/18 13:43:52 ru Exp $
+.\"
+.Dd June 25, 2004
+.Dt PASTE 1
+.Os
+.Sh NAME
+.Nm paste
+.Nd merge corresponding or subsequent lines of files
+.Sh SYNOPSIS
+.Nm
+.Op Fl s
+.Op Fl d Ar list
+.Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility concatenates the corresponding lines of the given input files,
+replacing all but the last file's newline characters with a single tab
+character, and writes the resulting lines to standard output.
+If end-of-file is reached on an input file while other input files
+still contain data, the file is treated as if it were an endless source
+of empty lines.
+.Pp
+The options are as follows:
+.Bl -tag -width Fl
+.It Fl d Ar list
+Use one or more of the provided characters to replace the newline
+characters instead of the default tab.
+The characters in
+.Ar list
+are used circularly, i.e., when
+.Ar list
+is exhausted the first character from
+.Ar list
+is reused.
+This continues until a line from the last input file (in default operation)
+or the last line in each file (using the
+.Fl s
+option) is displayed, at which
+time
+.Nm
+begins selecting characters from the beginning of
+.Ar list
+again.
+.Pp
+The following special characters can also be used in list:
+.Pp
+.Bl -tag -width flag -compact
+.It Li \en
+newline character
+.It Li \et
+tab character
+.It Li \e\e
+backslash character
+.It Li \e0
+Empty string (not a null character).
+.El
+.Pp
+Any other character preceded by a backslash is equivalent to the
+character itself.
+.It Fl s
+Concatenate all of the lines of each separate input file in command line
+order.
+The newline character of every line except the last line in each input
+file is replaced with the tab character, unless otherwise specified by
+the
+.Fl d
+option.
+.El
+.Pp
+If
+.Sq Fl
+is specified for one or more of the input files, the standard
+input is used; standard input is read one line at a time, circularly,
+for each instance of
+.Sq Fl .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+List the files in the current directory in three columns:
+.Pp
+.Dl "ls | paste - - -"
+.Pp
+Combine pairs of lines from a file into single lines:
+.Pp
+.Dl "paste -s -d '\et\en' myfile"
+.Pp
+Number the lines in a file, similar to
+.Xr nl 1 :
+.Pp
+.Dl "sed = myfile | paste -s -d '\et\en' - -"
+.Pp
+Create a colon-separated list of directories named
+.Pa bin ,
+suitable
+for use in the
+.Ev PATH
+environment variable:
+.Pp
+.Dl "find / -name bin -type d | paste -s -d : -"
+.Sh SEE ALSO
+.Xr cut 1 ,
+.Xr lam 1
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be
+.St -p1003.2
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At 32v .
diff --git a/text_cmds/paste/paste.c b/text_cmds/paste/paste.c
new file mode 100644
index 0000000..20af451
--- /dev/null
+++ b/text_cmds/paste/paste.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Adam S. Moskowitz of Menlo Consulting.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)paste.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/paste/paste.c,v 1.14 2004/06/25 01:48:43 tjr Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <sysexits.h>
+
+wchar_t *delim;
+int delimcnt;
+
+int parallel(char **);
+int sequential(char **);
+int tr(wchar_t *);
+static void usage(void);
+
+wchar_t tab[] = L"\t";
+
+int
+main(int argc, char *argv[])
+{
+ int ch, rval, seq;
+ wchar_t *warg;
+ const char *arg;
+ size_t len;
+
+ setlocale(LC_CTYPE, "");
+
+ seq = 0;
+ while ((ch = getopt(argc, argv, "d:s")) != -1)
+ switch(ch) {
+ case 'd':
+ arg = optarg;
+ len = mbsrtowcs(NULL, &arg, 0, NULL);
+ if (len == (size_t)-1)
+ err(1, "delimiters");
+ warg = malloc((len + 1) * sizeof(*warg));
+ if (warg == NULL)
+ err(1, NULL);
+ arg = optarg;
+ len = mbsrtowcs(warg, &arg, len + 1, NULL);
+ if (len == (size_t)-1)
+ err(1, "delimiters");
+ delimcnt = tr(delim = warg);
+ break;
+ case 's':
+ seq = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv == NULL)
+ usage();
+ if (!delim) {
+ delimcnt = 1;
+ delim = tab;
+ }
+
+ if (seq)
+ rval = sequential(argv);
+ else
+ rval = parallel(argv);
+ exit(rval);
+}
+
+typedef struct _list {
+ struct _list *next;
+ FILE *fp;
+ int cnt;
+ char *name;
+} LIST;
+
+int
+parallel(char **argv)
+{
+ LIST *lp;
+ int cnt;
+ wint_t ich;
+ wchar_t ch;
+ char *p;
+ LIST *head, *tmp;
+ int opencnt, output;
+
+ for (cnt = 0, head = NULL; (p = *argv); ++argv, ++cnt) {
+ if ((lp = malloc(sizeof(LIST))) == NULL)
+ err(1, NULL);
+ if (p[0] == '-' && !p[1])
+ lp->fp = stdin;
+ else if (!(lp->fp = fopen(p, "r")))
+ err(1, "%s", p);
+ lp->next = NULL;
+ lp->cnt = cnt;
+ lp->name = p;
+ if (!head)
+ head = tmp = lp;
+ else {
+ tmp->next = lp;
+ tmp = lp;
+ }
+ }
+
+ for (opencnt = cnt; opencnt;) {
+ for (output = 0, lp = head; lp; lp = lp->next) {
+ if (!lp->fp) {
+ if (output && lp->cnt &&
+ (ch = delim[(lp->cnt - 1) % delimcnt]))
+ putwchar(ch);
+ continue;
+ }
+ if ((ich = getwc(lp->fp)) == WEOF) {
+ if (!--opencnt)
+ break;
+ lp->fp = NULL;
+ if (output && lp->cnt &&
+ (ch = delim[(lp->cnt - 1) % delimcnt]))
+ putwchar(ch);
+ continue;
+ }
+ /*
+ * make sure that we don't print any delimiters
+ * unless there's a non-empty file.
+ */
+ if (!output) {
+ output = 1;
+ for (cnt = 0; cnt < lp->cnt; ++cnt)
+ if ((ch = delim[cnt % delimcnt]))
+ putwchar(ch);
+ } else if ((ch = delim[(lp->cnt - 1) % delimcnt]))
+ putwchar(ch);
+ if (ich == '\n')
+ continue;
+ do {
+ putwchar(ich);
+ } while ((ich = getwc(lp->fp)) != WEOF && ich != '\n');
+ if (ferror(lp->fp)) {
+ errx(EX_IOERR, "Error reading %s", lp->name);
+ }
+ }
+ if (output)
+ putwchar('\n');
+ }
+
+ return (0);
+}
+
+int
+sequential(char **argv)
+{
+ FILE *fp;
+ int cnt, failed, needdelim;
+ wint_t ch;
+ char *p;
+
+ failed = 0;
+ for (; (p = *argv); ++argv) {
+ if (p[0] == '-' && !p[1])
+ fp = stdin;
+ else if (!(fp = fopen(p, "r"))) {
+ warn("%s", p);
+ failed = 1;
+ continue;
+ }
+ cnt = needdelim = 0;
+ while ((ch = getwc(fp)) != WEOF) {
+ if (needdelim) {
+ needdelim = 0;
+ if (delim[cnt] != '\0')
+ putwchar(delim[cnt]);
+ if (++cnt == delimcnt)
+ cnt = 0;
+ }
+ if (ch != '\n')
+ putwchar(ch);
+ else
+ needdelim = 1;
+ }
+ if (needdelim)
+ putwchar('\n');
+ if (fp != stdin)
+ (void)fclose(fp);
+ }
+
+ return (failed != 0);
+}
+
+int
+tr(wchar_t *arg)
+{
+ int cnt;
+ wchar_t ch, *p;
+
+ for (p = arg, cnt = 0; (ch = *p++); ++arg, ++cnt)
+ if (ch == '\\')
+ switch(ch = *p++) {
+ case 'n':
+ *arg = '\n';
+ break;
+ case 't':
+ *arg = '\t';
+ break;
+ case '0':
+ *arg = '\0';
+ break;
+ default:
+ *arg = ch;
+ break;
+ } else
+ *arg = ch;
+
+ if (!cnt)
+ errx(1, "no delimiters specified");
+ return(cnt);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: paste [-s] [-d delimiters] file ...\n");
+ exit(1);
+}
diff --git a/text_cmds/pr/egetopt.c b/text_cmds/pr/egetopt.c
new file mode 100644
index 0000000..46257f4
--- /dev/null
+++ b/text_cmds/pr/egetopt.c
@@ -0,0 +1,218 @@
+/*-
+ * Copyright (c) 1991 Keith Muller.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)egetopt.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/pr/egetopt.c,v 1.3 2002/06/23 20:42:30 charnier Exp $");
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "extern.h"
+
+/*
+ * egetopt: get option letter from argument vector (an extended
+ * version of getopt).
+ *
+ * Non standard additions to the ostr specs are:
+ * 1) '?': immediate value following arg is optional (no white space
+ * between the arg and the value)
+ * 2) '#': +/- followed by a number (with an optional sign but
+ * no white space between the arg and the number). The - may be
+ * combined with other options, but the + cannot.
+ */
+
+int eopterr = 1; /* if error message should be printed */
+int eoptind = 1; /* index into parent argv vector */
+int eoptopt; /* character checked for validity */
+char *eoptarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+
+static char emsg[] = "";
+
+int
+egetopt(int nargc, char * const *nargv, const char *ostr)
+{
+ static char *place = emsg; /* option letter processing */
+ char *oli; /* option letter list index */
+ static int delim; /* which option delimeter */
+ char *p;
+ static char savec = '\0';
+
+ if (savec != '\0') {
+ *place = savec;
+ savec = '\0';
+ }
+
+ if (!*place) {
+ /*
+ * update scanning pointer
+ */
+ if ((eoptind >= nargc) ||
+ ((*(place = nargv[eoptind]) != '-') && (*place != '+'))) {
+ place = emsg;
+ return (-1);
+ }
+
+ delim = (int)*place;
+ if (place[1] && *++place == '-' && !place[1]) {
+ /*
+ * found "--"
+ */
+ ++eoptind;
+ place = emsg;
+ return (-1);
+ }
+ }
+
+ /*
+ * check option letter
+ */
+ if ((eoptopt = (int)*place++) == (int)':' || (eoptopt == (int)'?') ||
+ !(oli = strchr(ostr, eoptopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means -1 when by itself.
+ */
+ if ((eoptopt == (int)'-') && !*place)
+ return (-1);
+ if (strchr(ostr, '#') && (isdigit(eoptopt) ||
+ (((eoptopt == (int)'-') || (eoptopt == (int)'+')) &&
+ isdigit(*place)))) {
+ /*
+ * # option: +/- with a number is ok
+ */
+ for (p = place; *p != '\0'; ++p) {
+ if (!isdigit(*p))
+ break;
+ }
+ eoptarg = place-1;
+
+ if (*p == '\0') {
+ place = emsg;
+ ++eoptind;
+ } else {
+ place = p;
+ savec = *p;
+ *place = '\0';
+ }
+ return (delim);
+ }
+
+ if (!*place)
+ ++eoptind;
+ if (eopterr) {
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ (void)fprintf(stderr, "%s: illegal option -- %c\n",
+ p, eoptopt);
+ }
+ return (BADCH);
+ }
+ if (delim == (int)'+') {
+ /*
+ * '+' is only allowed with numbers
+ */
+ if (!*place)
+ ++eoptind;
+ if (eopterr) {
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ (void)fprintf(stderr,
+ "%s: illegal '+' delimiter with option -- %c\n",
+ p, eoptopt);
+ }
+ return (BADCH);
+ }
+ ++oli;
+ if ((*oli != ':') && (*oli != '?')) {
+ /*
+ * don't need argument
+ */
+ eoptarg = NULL;
+ if (!*place)
+ ++eoptind;
+ return (eoptopt);
+ }
+
+ if (*place) {
+ /*
+ * no white space
+ */
+ eoptarg = place;
+ } else if (*oli == '?') {
+ /*
+ * no arg, but NOT required
+ */
+ eoptarg = NULL;
+ } else if (nargc <= ++eoptind) {
+ /*
+ * no arg, but IS required
+ */
+ place = emsg;
+ if (eopterr) {
+ if (!(p = strrchr(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n", p,
+ eoptopt);
+ }
+ return (BADCH);
+ } else {
+ /*
+ * arg has white space
+ */
+ eoptarg = nargv[eoptind];
+ }
+ place = emsg;
+ ++eoptind;
+ return (eoptopt);
+}
diff --git a/text_cmds/pr/extern.h b/text_cmds/pr/extern.h
new file mode 100644
index 0000000..d3a999b
--- /dev/null
+++ b/text_cmds/pr/extern.h
@@ -0,0 +1,61 @@
+/*-
+ * Copyright (c) 1991 Keith Muller.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/pr/extern.h,v 1.3 2002/09/04 23:29:05 dwmalone Exp $
+ */
+
+extern int eoptind;
+extern char *eoptarg;
+
+void addnum(char *, int, int);
+int egetopt(int, char * const *, const char *);
+void flsh_errs(void);
+int horzcol(int, char **);
+int inln(FILE *, char *, int, int *, int, int *);
+int inskip(FILE *, int, int);
+void mfail(void);
+int mulfile(int, char **);
+FILE *nxtfile(int, char **, const char **, char *, int);
+int onecol(int, char **);
+int otln(char *, int, int *, int *, int);
+void pfail(void);
+int prhead(char *, const char *, int);
+int prtail(int, int);
+int setup(int, char **);
+void terminate(int);
+void usage(void);
+int vertcol(int, char **);
diff --git a/text_cmds/pr/pr.1 b/text_cmds/pr/pr.1
new file mode 100644
index 0000000..d5b0884
--- /dev/null
+++ b/text_cmds/pr/pr.1
@@ -0,0 +1,402 @@
+.\" Copyright (c) 1991 Keith Muller.
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Keith Muller of the University of California, San Diego.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pr.1 8.3 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/pr/pr.1,v 1.22 2005/01/18 13:43:52 ru Exp $
+.\"
+.Dd July 3, 2004
+.Dt PR 1
+.Os
+.Sh NAME
+.Nm pr
+.Nd print files
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Ar \&+page
+.Ek
+.Bk -words
+.Op Fl Ar column
+.Ek
+.Op Fl adFfmprt
+.Bk -words
+.Oo
+.Op Fl e
+.Op Ar char
+.Op Ar gap
+.Oc
+.Ek
+.Bk -words
+.Op Fl L Ar locale
+.Ek
+.Bk -words
+.Op Fl h Ar header
+.Ek
+.Bk -words
+.Oo
+.Op Fl i
+.Op Ar char
+.Op Ar gap
+.Oc
+.Ek
+.Bk -words
+.Op Fl l Ar lines
+.Ek
+.Bk -words
+.Op Fl o Ar offset
+.Ek
+.Bk -words
+.Oo
+.Op Fl s
+.Op Ar char
+.Oc
+.Ek
+.Bk -words
+.Oo
+.Op Fl n
+.Op Ar char
+.Op Ar width
+.Oc
+.Ek
+.Bk -words
+.Op Fl w Ar width
+.Ek
+.Op -
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is a printing and pagination filter for text files.
+When multiple input files are specified, each is read, formatted,
+and written to standard output.
+By default, the input is separated into 66-line pages, each with
+.Bl -bullet
+.It
+A 5-line header with the page number, date, time, and
+the pathname of the file.
+.It
+A 5-line trailer consisting of blank lines.
+.El
+.Pp
+If standard output is associated with a terminal,
+diagnostic messages are suppressed until the
+.Nm
+utility has completed processing.
+.Pp
+When multiple column output is specified,
+text columns are of equal width.
+By default text columns are separated by at least one
+.Em <blank> .
+Input lines that do not fit into a text column are truncated.
+Lines are not truncated under single column output.
+.Sh OPTIONS
+In the following option descriptions, column, lines, offset, page, and
+width are positive decimal integers and gap is a nonnegative decimal integer.
+.Bl -tag -width 4n
+.It Ar \&+page
+Begin output at page number
+.Ar page
+of the formatted input.
+.It Fl Ar column
+Produce output that is
+.Ar columns
+wide (default is 1) that is written vertically
+down each column in the order in which the text
+is received from the input file.
+The options
+.Fl e
+and
+.Fl i
+are assumed.
+This option should not be used with
+.Fl m .
+When used with
+.Fl t ,
+the minimum number of lines is used to display the output.
+(To columnify and reshape text files more generally and without additional
+formatting, see the
+.Xr rs 1
+utility.)
+.It Fl a
+Modify the effect of the
+.Fl column
+option so that the columns are filled across the page in a round-robin order
+(e.g., when column is 2, the first input line heads column
+1, the second heads column 2, the third is the second line
+in column 1, etc.).
+This option requires the use of the
+.Fl column
+option.
+.It Fl d
+Produce output that is double spaced.
+An extra
+.Em <newline>
+character is output following every
+.Em <newline>
+found in the input.
+.It Fl e Xo
+.Op Ar char Ns
+.Op Ar gap
+.Xc
+Expand each input
+.Em <tab>
+to the next greater column
+position specified by the formula
+.Ar n*gap+1 ,
+where
+.Em n
+is an integer > 0.
+If
+.Ar gap
+is zero or is omitted the default is 8.
+All
+.Em <tab>
+characters in the input are expanded into the appropriate
+number of
+.Em <space>s .
+If any nondigit character,
+.Ar char ,
+is specified, it is used as the input tab character.
+.It Fl F
+Use a
+.Em <form-feed>
+character for new pages,
+instead of the default behavior that uses a
+sequence of
+.Em <newline>
+characters.
+.It Fl f
+Same as
+.Fl F
+but pause before beginning the first page if standard output is a terminal.
+.It Fl h Ar header
+Use the string
+.Ar header
+to replace the
+.Ar file name
+in the header line.
+.It Fl i Xo
+.Op Ar char Ns
+.Op Ar gap
+.Xc
+In output, replace multiple
+.Em <space>s
+with
+.Em <tab>s
+whenever two or more
+adjacent
+.Em <space>s
+reach column positions
+.Ar gap+1 ,
+.Ar 2*gap+1 ,
+etc.
+If
+.Ar gap
+is zero or omitted, default
+.Em <tab>
+settings at every eighth column position
+is used.
+If any nondigit character,
+.Ar char ,
+is specified, it is used as the output
+.Em <tab>
+character.
+.It Fl L Ar locale
+Use
+.Ar locale
+specified as argument instead of one found in environment.
+Use "C" to reset locale to default.
+.It Fl l Ar lines
+Override the 66 line default and reset the page length to
+.Ar lines .
+If
+.Ar lines
+is not greater than the sum of both the header and trailer
+depths (in lines), the
+.Nm
+utility suppresses output of both the header and trailer, as if the
+.Fl t
+option were in effect.
+.It Fl m
+Merge the contents of multiple files.
+One line from each file specified by a file operand is
+written side by side into text columns of equal fixed widths, in
+terms of the number of column positions.
+The number of text columns depends on the number of
+file operands successfully opened.
+The maximum number of files merged depends on page width and the
+per process open file limit.
+The options
+.Fl e
+and
+.Fl i
+are assumed.
+.It Fl n Xo
+.Op Ar char Ns
+.Op Ar width
+.Xc
+Provide
+.Ar width
+digit line numbering.
+The default for
+.Ar width ,
+if not specified, is 5.
+The number occupies the first
+.Ar width
+column positions of each text column or each line of
+.Fl m
+output.
+If
+.Ar char
+(any nondigit character) is given, it is appended to the line number to
+separate it from whatever follows.
+The default for
+.Ar char
+is a
+.Em <tab> .
+Line numbers longer than
+.Ar width
+columns are truncated.
+.It Fl o Ar offset
+Each line of output is preceded by
+.Ar offset
+.Em <spaces>s .
+If the
+.Fl o
+option is not specified, the default is zero.
+The space taken is in addition to the output line width.
+.It Fl p
+Pause before each page if the standard output is a terminal.
+.Nm
+will write an alert character to standard error and wait for a carriage
+return to be read on the terminal.
+.It Fl r
+Write no diagnostic reports on failure to open a file.
+.It Fl s Ar char
+Separate text columns by the single character
+.Ar char
+instead of by the appropriate number of
+.Em <space>s
+(default for
+.Ar char
+is the
+.Em <tab>
+character).
+.It Fl t
+Print neither the five-line identifying
+header nor the five-line trailer usually supplied for each page.
+Quit printing after the last line of each file without spacing to the
+end of the page.
+.It Fl w Ar width
+Set the width of the line to
+.Ar width
+column positions for multiple text-column output only.
+If the
+.Fl w
+option is not specified and the
+.Fl s
+option is not specified, the default width is 72.
+If the
+.Fl w
+option is not specified and the
+.Fl s
+option is specified, the default width is 512.
+.It Ar file
+A pathname of a file to be printed.
+If no
+.Ar file
+operands are specified, or if a
+.Ar file
+operand is
+.Sq Fl ,
+the standard input is used.
+The standard input is used only if no
+.Ar file
+operands are specified, or if a
+.Ar file
+operand is
+.Sq Fl .
+.El
+.Pp
+The
+.Fl s
+option does not allow the option letter to be separated from its
+argument, and the options
+.Fl e ,
+.Fl i ,
+and
+.Fl n
+require that both arguments, if present, not be separated from the option
+letter.
+.Sh EXIT STATUS
+The
+.Nm
+utility exits 0 on success, and 1 if an error occurs.
+.Sh DIAGNOSTICS
+If
+.Nm
+receives an interrupt while printing to a terminal, it
+flushes all accumulated error messages to the screen before
+terminating.
+.Pp
+Error messages are written to standard error during the printing
+process (if output is redirected) or after all successful
+file printing is complete (when printing to a terminal).
+.Sh LEGACY DESCRIPTION
+The last space before the tab stop is replaced with a tab character.
+In legacy mode, it is not.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
+.Sh SEE ALSO
+.Xr cat 1 ,
+.Xr more 1 ,
+.Xr rs 1 ,
+.Xr compat 5
+.Sh STANDARDS
+The
+.Nm
+utility is
+.St -p1003.1-2001
+compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
+.Sh BUGS
+The
+.Nm
+utility does not recognize multibyte characters.
diff --git a/text_cmds/pr/pr.c b/text_cmds/pr/pr.c
new file mode 100644
index 0000000..f2d40e3
--- /dev/null
+++ b/text_cmds/pr/pr.c
@@ -0,0 +1,1856 @@
+/*-
+ * Copyright (c) 1991 Keith Muller.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)pr.c 8.2 (Berkeley) 4/16/94";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/pr/pr.c,v 1.18 2004/07/26 20:24:59 charnier Exp $");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <langinfo.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#include "pr.h"
+#include "extern.h"
+
+#ifdef __APPLE__
+#include <get_compat.h>
+/* err.h defines err(1) which conflicts with the global below */
+extern void errx(int, const char *, ...) __dead2 __printflike(2, 3);
+#else
+#define COMPAT_MODE(a,b) (1)
+#endif /* __APPLE__ */
+
+/*
+ * pr: a printing and pagination filter. If multiple input files
+ * are specified, each is read, formatted, and written to standard
+ * output. By default, input is separated into 66-line pages, each
+ * with a header that includes the page number, date, time and the
+ * files pathname.
+ *
+ * Complies with posix P1003.2/D11
+ */
+
+/*
+ * parameter variables
+ */
+int pgnm; /* starting page number */
+int clcnt; /* number of columns */
+int colwd; /* column data width - multiple columns */
+int across; /* mult col flag; write across page */
+int dspace; /* double space flag */
+char inchar; /* expand input char */
+int ingap; /* expand input gap */
+int pausefst; /* Pause before first page */
+int pauseall; /* Pause before each page */
+int formfeed; /* use formfeed as trailer */
+char *header; /* header name instead of file name */
+char ochar; /* contract output char */
+int ogap; /* contract output gap */
+int lines; /* number of lines per page */
+int merge; /* merge multiple files in output */
+char nmchar; /* line numbering append char */
+int nmwd; /* width of line number field */
+int offst; /* number of page offset spaces */
+int nodiag; /* do not report file open errors */
+char schar; /* text column separation character */
+int sflag; /* -s option for multiple columns */
+int nohead; /* do not write head and trailer */
+int pgwd; /* page width with multiple col output */
+const char *timefrmt; /* time conversion string */
+
+/*
+ * misc globals
+ */
+FILE *err; /* error message file pointer */
+int addone; /* page length is odd with double space */
+int errcnt; /* error count on file processing */
+char digs[] = "0123456789"; /* page number translation map */
+
+char fnamedefault[] = FNAME;
+
+static char first_char; /* first fill character */
+
+int
+main(int argc, char *argv[])
+{
+ int ret_val;
+
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ (void)signal(SIGINT, terminate);
+ ret_val = setup(argc, argv);
+ first_char = (COMPAT_MODE("bin/pr", "Unix2003") ? ochar : ' ');
+ if (!ret_val) {
+ /*
+ * select the output format based on options
+ */
+ if (merge)
+ ret_val = mulfile(argc, argv);
+ else if (clcnt == 1)
+ ret_val = onecol(argc, argv);
+ else if (across)
+ ret_val = horzcol(argc, argv);
+ else
+ ret_val = vertcol(argc, argv);
+ } else
+ usage();
+ flsh_errs();
+ if (errcnt || ret_val)
+ exit(1);
+ return(0);
+}
+
+/*
+ * Check if we should pause and write an alert character and wait for a
+ * carriage return on /dev/tty.
+ */
+static void
+ttypause(int pagecnt)
+{
+ int pch;
+ FILE *ttyfp;
+
+ if ((pauseall || (pausefst && pagecnt == 1)) &&
+ isatty(STDOUT_FILENO)) {
+ if ((ttyfp = fopen("/dev/tty", "r")) != NULL) {
+ (void)putc('\a', stderr);
+ while ((pch = getc(ttyfp)) != '\n' && pch != EOF)
+ ;
+ (void)fclose(ttyfp);
+ }
+ }
+}
+
+/*
+ * onecol: print files with only one column of output.
+ * Line length is unlimited.
+ */
+int
+onecol(int argc, char *argv[])
+{
+ int cnt = -1;
+ int off;
+ int lrgln;
+ int linecnt;
+ int num;
+ int lncnt;
+ int pagecnt;
+ int ips;
+ int ops;
+ int cps;
+ char *obuf;
+ char *lbuf;
+ char *nbuf;
+ char *hbuf;
+ char *ohbuf;
+ FILE *inf;
+ const char *fname;
+ int mor;
+
+ if (nmwd)
+ num = nmwd + 1;
+ else
+ num = 0;
+ off = num + offst;
+
+ /*
+ * allocate line buffer
+ */
+ if ((obuf = malloc((unsigned)(LBUF + off)*sizeof(char))) == NULL) {
+ mfail();
+ return(1);
+ }
+ /*
+ * allocate header buffer
+ */
+ if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
+ mfail();
+ return(1);
+ }
+
+ ohbuf = hbuf + offst;
+ nbuf = obuf + offst;
+ lbuf = nbuf + num;
+ if (num)
+ nbuf[--num] = nmchar;
+ if (offst) {
+ (void)memset(obuf, (int)' ', offst);
+ (void)memset(hbuf, (int)' ', offst);
+ }
+
+ /*
+ * loop by file
+ */
+ while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
+ if (pgnm) {
+ /*
+ * skip to specified page
+ */
+ if (inskip(inf, pgnm, lines))
+ continue;
+ pagecnt = pgnm;
+ } else
+ pagecnt = 1;
+ lncnt = 0;
+
+ /*
+ * loop by page
+ */
+ for(;;) {
+ linecnt = 0;
+ lrgln = 0;
+ ops = 0;
+ ips = 0;
+ cps = 0;
+
+ ttypause(pagecnt);
+
+ /*
+ * loop by line
+ */
+ while (linecnt < lines) {
+ /*
+ * input next line
+ */
+ if ((cnt = inln(inf,lbuf,LBUF,&cps,0,&mor)) < 0)
+ break;
+ if (!linecnt && !nohead &&
+ prhead(hbuf, fname, pagecnt))
+ return(1);
+
+ /*
+ * start of new line.
+ */
+ if (!lrgln) {
+ if (num)
+ addnum(nbuf, num, ++lncnt);
+ if (otln(obuf,cnt+off, &ips, &ops, mor))
+ return(1);
+ } else if (otln(lbuf, cnt, &ips, &ops, mor))
+ return(1);
+
+ /*
+ * if line bigger than buffer, get more
+ */
+ if (mor) {
+ lrgln = 1;
+ continue;
+ }
+
+ /*
+ * whole line rcvd. reset tab proc. state
+ */
+ ++linecnt;
+ lrgln = 0;
+ ops = 0;
+ ips = 0;
+ }
+
+ /*
+ * fill to end of page
+ */
+ if (linecnt && prtail(lines-linecnt-lrgln, lrgln))
+ return(1);
+
+ /*
+ * On EOF go to next file
+ */
+ if (cnt < 0)
+ break;
+ ++pagecnt;
+ }
+ if (inf != stdin)
+ (void)fclose(inf);
+ }
+ if (eoptind < argc)
+ return(1);
+ return(0);
+}
+
+/*
+ * vertcol: print files with more than one column of output down a page
+ */
+int
+vertcol(int argc, char *argv[])
+{
+ char *ptbf;
+ char **lstdat;
+ int i;
+ int j;
+ int cnt = -1;
+ int pln;
+ int *indy;
+ int cvc;
+ int *lindy;
+ int lncnt;
+ int stp;
+ int pagecnt;
+ int col = colwd + 1;
+ int mxlen = pgwd + offst + 1;
+ int mclcnt = clcnt - 1;
+ struct vcol *vc;
+ int mvc;
+ int tvc;
+ int cw = nmwd + 1;
+ int fullcol;
+ char *buf;
+ char *hbuf;
+ char *ohbuf;
+ const char *fname;
+ FILE *inf;
+ int ips = 0;
+ int cps = 0;
+ int ops = 0;
+ int mor = 0;
+
+ /*
+ * allocate page buffer
+ */
+ if ((buf = malloc((unsigned)lines*mxlen*sizeof(char))) == NULL) {
+ mfail();
+ return(1);
+ }
+
+ /*
+ * allocate page header
+ */
+ if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
+ mfail();
+ return(1);
+ }
+ ohbuf = hbuf + offst;
+ if (offst)
+ (void)memset(hbuf, (int)' ', offst);
+
+ /*
+ * col pointers when no headers
+ */
+ mvc = lines * clcnt;
+ if ((vc =
+ (struct vcol *)malloc((unsigned)mvc*sizeof(struct vcol))) == NULL) {
+ mfail();
+ return(1);
+ }
+
+ /*
+ * pointer into page where last data per line is located
+ */
+ if ((lstdat = (char **)malloc((unsigned)lines*sizeof(char *))) == NULL){
+ mfail();
+ return(1);
+ }
+
+ /*
+ * fast index lookups to locate start of lines
+ */
+ if ((indy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) {
+ mfail();
+ return(1);
+ }
+ if ((lindy = (int *)malloc((unsigned)lines*sizeof(int))) == NULL) {
+ mfail();
+ return(1);
+ }
+
+ if (nmwd)
+ fullcol = col + cw;
+ else
+ fullcol = col;
+
+ /*
+ * initialize buffer lookup indexes and offset area
+ */
+ for (j = 0; j < lines; ++j) {
+ lindy[j] = j * mxlen;
+ indy[j] = lindy[j] + offst;
+ if (offst) {
+ ptbf = buf + lindy[j];
+ (void)memset(ptbf, (int)' ', offst);
+ ptbf += offst;
+ } else
+ ptbf = buf + indy[j];
+ lstdat[j] = ptbf;
+ }
+
+ /*
+ * loop by file
+ */
+ while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
+ if (pgnm) {
+ /*
+ * skip to requested page
+ */
+ if (inskip(inf, pgnm, lines))
+ continue;
+ pagecnt = pgnm;
+ } else
+ pagecnt = 1;
+ lncnt = 0;
+
+ /*
+ * loop by page
+ */
+ for(;;) {
+ ttypause(pagecnt);
+
+ /*
+ * loop by column
+ */
+ cvc = 0;
+ for (i = 0; i < clcnt; ++i) {
+ j = 0;
+ /*
+ * if last column, do not pad
+ */
+ if (i == mclcnt)
+ stp = 1;
+ else
+ stp = 0;
+ /*
+ * loop by line
+ */
+ for(;;) {
+ /*
+ * is this first column
+ */
+ if (!i) {
+ ptbf = buf + indy[j];
+ lstdat[j] = ptbf;
+ } else
+ ptbf = lstdat[j];
+ vc[cvc].pt = ptbf;
+
+ /*
+ * add number
+ */
+ if (nmwd) {
+ addnum(ptbf, nmwd, ++lncnt);
+ ptbf += nmwd;
+ *ptbf++ = nmchar;
+ }
+
+ /*
+ * input next line
+ */
+ cnt = inln(inf,ptbf,colwd,&cps,1,&mor);
+ vc[cvc++].cnt = cnt;
+ if (cnt < 0)
+ break;
+ ptbf += cnt;
+
+ /*
+ * pad all but last column on page
+ */
+ if (!stp) {
+ /*
+ * pad to end of column
+ */
+ if (sflag)
+ *ptbf++ = schar;
+ else if ((pln = col-cnt) > 0) {
+ (void)memset(ptbf,
+ (int)' ',pln);
+ ptbf += pln;
+ }
+ }
+ /*
+ * remember last char in line
+ */
+ lstdat[j] = ptbf;
+ if (++j >= lines)
+ break;
+ }
+ if (cnt < 0)
+ break;
+ }
+
+ /*
+ * when -t (no header) is specified the spec requires
+ * the min number of lines. The last page may not have
+ * balanced length columns. To fix this we must reorder
+ * the columns. This is a very slow technique so it is
+ * only used under limited conditions. Without -t, the
+ * balancing of text columns is unspecified. To NOT
+ * balance the last page, add the global variable
+ * nohead to the if statement below e.g.
+ *
+ * if ((cnt < 0) && nohead && cvc ......
+ */
+ --cvc;
+
+ /*
+ * check to see if last page needs to be reordered
+ */
+ if ((cnt < 0) && cvc && ((mvc-cvc) >= clcnt)){
+ pln = cvc/clcnt;
+ if (cvc % clcnt)
+ ++pln;
+
+ /*
+ * print header
+ */
+ if (!nohead && prhead(hbuf, fname, pagecnt))
+ return(1);
+ for (i = 0; i < pln; ++i) {
+ ips = 0;
+ ops = 0;
+ if (offst&& otln(buf,offst,&ips,&ops,1))
+ return(1);
+ tvc = i;
+
+ for (j = 0; j < clcnt; ++j) {
+ /*
+ * determine column length
+ */
+ if (j == mclcnt) {
+ /*
+ * last column
+ */
+ cnt = vc[tvc].cnt;
+ if (nmwd)
+ cnt += cw;
+ } else if (sflag) {
+ /*
+ * single ch between
+ */
+ cnt = vc[tvc].cnt + 1;
+ if (nmwd)
+ cnt += cw;
+ } else
+ cnt = fullcol;
+ if (otln(vc[tvc].pt, cnt, &ips,
+ &ops, 1))
+ return(1);
+ tvc += pln;
+ if (tvc >= cvc)
+ break;
+ }
+ /*
+ * terminate line
+ */
+ if (otln(buf, 0, &ips, &ops, 0))
+ return(1);
+ }
+ /*
+ * pad to end of page
+ */
+ if (prtail((lines - pln), 0))
+ return(1);
+ /*
+ * done with output, go to next file
+ */
+ break;
+ }
+
+ /*
+ * determine how many lines to output
+ */
+ if (i > 0)
+ pln = lines;
+ else
+ pln = j;
+
+ /*
+ * print header
+ */
+ if (pln && !nohead && prhead(hbuf, fname, pagecnt))
+ return(1);
+
+ /*
+ * output each line
+ */
+ for (i = 0; i < pln; ++i) {
+ ptbf = buf + lindy[i];
+ if ((j = lstdat[i] - ptbf) <= offst)
+ break;
+ if (otln(ptbf, j, &ips, &ops, 0))
+ return(1);
+ }
+
+ /*
+ * pad to end of page
+ */
+ if (pln && prtail((lines - pln), 0))
+ return(1);
+
+ /*
+ * if EOF go to next file
+ */
+ if (cnt < 0)
+ break;
+ ++pagecnt;
+ }
+ if (inf != stdin)
+ (void)fclose(inf);
+ }
+ if (eoptind < argc)
+ return(1);
+ return(0);
+}
+
+/*
+ * horzcol: print files with more than one column of output across a page
+ */
+int
+horzcol(int argc, char *argv[])
+{
+ char *ptbf;
+ int pln;
+ int cnt = -1;
+ char *lstdat;
+ int col = colwd + 1;
+ int j;
+ int i;
+ int lncnt;
+ int pagecnt;
+ char *buf;
+ char *hbuf;
+ char *ohbuf;
+ const char *fname;
+ FILE *inf;
+ int ips = 0;
+ int cps = 0;
+ int ops = 0;
+ int mor = 0;
+
+ if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) {
+ mfail();
+ return(1);
+ }
+
+ /*
+ * page header
+ */
+ if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
+ mfail();
+ return(1);
+ }
+ ohbuf = hbuf + offst;
+ if (offst) {
+ (void)memset(buf, (int)' ', offst);
+ (void)memset(hbuf, (int)' ', offst);
+ }
+
+ /*
+ * loop by file
+ */
+ while ((inf = nxtfile(argc, argv, &fname, ohbuf, 0)) != NULL) {
+ if (pgnm) {
+ if (inskip(inf, pgnm, lines))
+ continue;
+ pagecnt = pgnm;
+ } else
+ pagecnt = 1;
+ lncnt = 0;
+
+ /*
+ * loop by page
+ */
+ for(;;) {
+ ttypause(pagecnt);
+
+ /*
+ * loop by line
+ */
+ for (i = 0; i < lines; ++i) {
+ ptbf = buf + offst;
+ lstdat = ptbf;
+ j = 0;
+ /*
+ * loop by col
+ */
+ for(;;) {
+ if (nmwd) {
+ /*
+ * add number to column
+ */
+ addnum(ptbf, nmwd, ++lncnt);
+ ptbf += nmwd;
+ *ptbf++ = nmchar;
+ }
+ /*
+ * input line
+ */
+ if ((cnt = inln(inf,ptbf,colwd,&cps,1,
+ &mor)) < 0)
+ break;
+ ptbf += cnt;
+ lstdat = ptbf;
+
+ /*
+ * if last line skip padding
+ */
+ if (++j >= clcnt)
+ break;
+
+ /*
+ * pad to end of column
+ */
+ if (sflag)
+ *ptbf++ = schar;
+ else if ((pln = col - cnt) > 0) {
+ (void)memset(ptbf,(int)' ',pln);
+ ptbf += pln;
+ }
+ }
+
+ /*
+ * determine line length
+ */
+ if ((j = lstdat - buf) <= offst)
+ break;
+ if (!i && !nohead &&
+ prhead(hbuf, fname, pagecnt))
+ return(1);
+ /*
+ * output line
+ */
+ if (otln(buf, j, &ips, &ops, 0))
+ return(1);
+ }
+
+ /*
+ * pad to end of page
+ */
+ if (i && prtail(lines-i, 0))
+ return(1);
+
+ /*
+ * if EOF go to next file
+ */
+ if (cnt < 0)
+ break;
+ ++pagecnt;
+ }
+ if (inf != stdin)
+ (void)fclose(inf);
+ }
+ if (eoptind < argc)
+ return(1);
+ return(0);
+}
+
+/*
+ * mulfile: print files with more than one column of output and
+ * more than one file concurrently
+ */
+int
+mulfile(int argc, char *argv[])
+{
+ char *ptbf;
+ int j;
+ int pln;
+ int cnt;
+ char *lstdat;
+ int i;
+ FILE **fbuf;
+ int actf;
+ int lncnt;
+ int col;
+ int pagecnt;
+ int fproc;
+ char *buf;
+ char *hbuf;
+ char *ohbuf;
+ const char *fname;
+ int ips = 0;
+ int cps = 0;
+ int ops = 0;
+ int mor = 0;
+
+ /*
+ * array of FILE *, one for each operand
+ */
+ if ((fbuf = (FILE **)malloc((unsigned)clcnt*sizeof(FILE *))) == NULL) {
+ mfail();
+ return(1);
+ }
+
+ /*
+ * page header
+ */
+ if ((hbuf = malloc((unsigned)(HDBUF + offst)*sizeof(char))) == NULL) {
+ mfail();
+ return(1);
+ }
+ ohbuf = hbuf + offst;
+
+ /*
+ * do not know how many columns yet. The number of operands provide an
+ * upper bound on the number of columns. We use the number of files
+ * we can open successfully to set the number of columns. The operation
+ * of the merge operation (-m) in relation to unsuccesful file opens
+ * is unspecified by posix.
+ */
+ j = 0;
+ while (j < clcnt) {
+ if ((fbuf[j] = nxtfile(argc, argv, &fname, ohbuf, 1)) == NULL)
+ break;
+ if (pgnm && (inskip(fbuf[j], pgnm, lines)))
+ fbuf[j] = NULL;
+ ++j;
+ }
+
+ /*
+ * if no files, exit
+ */
+ if (!j)
+ return(1);
+
+ /*
+ * calculate page boundries based on open file count
+ */
+ clcnt = j;
+ if (nmwd) {
+ colwd = (pgwd - clcnt - nmwd)/clcnt;
+ pgwd = ((colwd + 1) * clcnt) - nmwd - 2;
+ } else {
+ colwd = (pgwd + 1 - clcnt)/clcnt;
+ pgwd = ((colwd + 1) * clcnt) - 1;
+ }
+ if (colwd < 1) {
+ (void)fprintf(err,
+ "pr: page width too small for %d columns\n", clcnt);
+ return(1);
+ }
+ actf = clcnt;
+ col = colwd + 1;
+
+ /*
+ * line buffer
+ */
+ if ((buf = malloc((unsigned)(pgwd+offst+1)*sizeof(char))) == NULL) {
+ mfail();
+ return(1);
+ }
+ if (offst) {
+ (void)memset(buf, (int)' ', offst);
+ (void)memset(hbuf, (int)' ', offst);
+ }
+ if (pgnm)
+ pagecnt = pgnm;
+ else
+ pagecnt = 1;
+ lncnt = 0;
+
+ /*
+ * continue to loop while any file still has data
+ */
+ while (actf > 0) {
+ ttypause(pagecnt);
+
+ /*
+ * loop by line
+ */
+ for (i = 0; i < lines; ++i) {
+ ptbf = buf + offst;
+ lstdat = ptbf;
+ if (nmwd) {
+ /*
+ * add line number to line
+ */
+ addnum(ptbf, nmwd, ++lncnt);
+ ptbf += nmwd;
+ *ptbf++ = nmchar;
+ }
+ j = 0;
+ fproc = 0;
+
+ /*
+ * loop by column
+ */
+ for (j = 0; j < clcnt; ++j) {
+ if (fbuf[j] == NULL) {
+ /*
+ * empty column; EOF
+ */
+ cnt = 0;
+ } else if ((cnt = inln(fbuf[j], ptbf, colwd,
+ &cps, 1, &mor)) < 0) {
+ /*
+ * EOF hit; no data
+ */
+ if (fbuf[j] != stdin)
+ (void)fclose(fbuf[j]);
+ fbuf[j] = NULL;
+ --actf;
+ cnt = 0;
+ } else {
+ /*
+ * process file data
+ */
+ ptbf += cnt;
+ lstdat = ptbf;
+ fproc++;
+ }
+
+ /*
+ * if last ACTIVE column, done with line
+ */
+ if (fproc >= actf)
+ break;
+
+ /*
+ * pad to end of column
+ */
+ if (sflag) {
+ *ptbf++ = schar;
+ } else if ((pln = col - cnt) > 0) {
+ (void)memset(ptbf, (int)' ', pln);
+ ptbf += pln;
+ }
+ }
+
+ /*
+ * calculate data in line
+ */
+ if ((j = lstdat - buf) <= offst)
+ break;
+
+ if (!i && !nohead && prhead(hbuf, fname, pagecnt))
+ return(1);
+
+ /*
+ * output line
+ */
+ if (otln(buf, j, &ips, &ops, 0))
+ return(1);
+
+ /*
+ * if no more active files, done
+ */
+ if (actf <= 0) {
+ ++i;
+ break;
+ }
+ }
+
+ /*
+ * pad to end of page
+ */
+ if (i && prtail(lines-i, 0))
+ return(1);
+ ++pagecnt;
+ }
+ if (eoptind < argc)
+ return(1);
+ return(0);
+}
+
+/*
+ * inln(): input a line of data (unlimited length lines supported)
+ * Input is optionally expanded to spaces
+ *
+ * inf: file
+ * buf: buffer
+ * lim: buffer length
+ * cps: column positon 1st char in buffer (large line support)
+ * trnc: throw away data more than lim up to \n
+ * mor: set if more data in line (not truncated)
+ */
+int
+inln(FILE *inf, char *buf, int lim, int *cps, int trnc, int *mor)
+{
+ int col;
+ int gap = ingap;
+ int ch = EOF;
+ char *ptbuf;
+ int chk = (int)inchar;
+
+ ptbuf = buf;
+
+ if (gap) {
+ /*
+ * expanding input option
+ */
+ while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
+ /*
+ * is this the input "tab" char
+ */
+ if (ch == chk) {
+ /*
+ * expand to number of spaces
+ */
+ col = (ptbuf - buf) + *cps;
+ col = gap - (col % gap);
+
+ /*
+ * if more than this line, push back
+ */
+ if ((col > lim) && (ungetc(ch, inf) == EOF))
+ return(1);
+
+ /*
+ * expand to spaces
+ */
+ while ((--col >= 0) && (--lim >= 0))
+ *ptbuf++ = ' ';
+ continue;
+ }
+ if (ch == '\n')
+ break;
+ *ptbuf++ = ch;
+ }
+ } else {
+ /*
+ * no expansion
+ */
+ while ((--lim >= 0) && ((ch = getc(inf)) != EOF)) {
+ if (ch == '\n')
+ break;
+ *ptbuf++ = ch;
+ }
+ }
+ col = ptbuf - buf;
+ if (ch == EOF) {
+ if (ferror(inf)) {
+ errx(EX_IOERR, NULL);
+ }
+ *mor = 0;
+ *cps = 0;
+ if (!col)
+ return(-1);
+ return(col);
+ }
+ if (ch == '\n') {
+ /*
+ * entire line processed
+ */
+ *mor = 0;
+ *cps = 0;
+ return(col);
+ }
+
+ /*
+ * line was larger than limit
+ */
+ if (trnc) {
+ /*
+ * throw away rest of line
+ */
+ while ((ch = getc(inf)) != EOF) {
+ if (ch == '\n')
+ break;
+ }
+ if (ferror(inf)) {
+ errx(EX_IOERR, NULL);
+ }
+ *cps = 0;
+ *mor = 0;
+ } else {
+ /*
+ * save column offset if not truncated
+ */
+ *cps += col;
+ *mor = 1;
+ }
+
+ return(col);
+}
+
+/*
+ * otln(): output a line of data. (Supports unlimited length lines)
+ * output is optionally contracted to tabs
+ *
+ * buf: output buffer with data
+ * cnt: number of chars of valid data in buf
+ * svips: buffer input column position (for large lines)
+ * svops: buffer output column position (for large lines)
+ * mor: output line not complete in this buf; more data to come.
+ * 1 is more, 0 is complete, -1 is no \n's
+ */
+int
+otln(char *buf, int cnt, int *svips, int *svops, int mor)
+{
+ int ops; /* last col output */
+ int ips; /* last col in buf examined */
+ int gap = ogap;
+ int tbps;
+ char *endbuf;
+
+ if (ogap) {
+ /*
+ * contracting on output
+ */
+ endbuf = buf + cnt;
+ ops = *svops;
+ ips = *svips;
+ while (buf < endbuf) {
+ /*
+ * count number of spaces and ochar in buffer
+ */
+ if (*buf == ' ') {
+ ++ips;
+ ++buf;
+ continue;
+ }
+
+ /*
+ * simulate ochar processing
+ */
+ if (*buf == ochar) {
+ ips += gap - (ips % gap);
+ ++buf;
+ continue;
+ }
+
+ /*
+ * got a non space char; contract out spaces
+ */
+ while (ips - ops > 1) {
+ /*
+ * use as many ochar as will fit
+ */
+ if ((tbps = ops + gap - (ops % gap)) > ips)
+ break;
+ if (gap - 1 == (ops % gap)) /* use space to get to immediately following tab stop */
+ putchar(first_char);
+ else if (putchar(ochar) == EOF) {
+ pfail();
+ return(1);
+ }
+ ops = tbps;
+ }
+
+ while (ops < ips) {
+ /*
+ * finish off with spaces
+ */
+ if (putchar(' ') == EOF) {
+ pfail();
+ return(1);
+ }
+ ++ops;
+ }
+
+ /*
+ * output non space char
+ */
+ if (putchar(*buf++) == EOF) {
+ pfail();
+ return(1);
+ }
+ ++ips;
+ ++ops;
+ }
+
+ if (mor > 0) {
+ /*
+ * if incomplete line, save position counts
+ */
+ *svops = ops;
+ *svips = ips;
+ return(0);
+ }
+
+ if (mor < 0) {
+ while (ips - ops > 1) {
+ /*
+ * use as many ochar as will fit
+ */
+ if ((tbps = ops + gap - (ops % gap)) > ips)
+ break;
+ if (putchar(ochar) == EOF) {
+ pfail();
+ return(1);
+ }
+ ops = tbps;
+ }
+ while (ops < ips) {
+ /*
+ * finish off with spaces
+ */
+ if (putchar(' ') == EOF) {
+ pfail();
+ return(1);
+ }
+ ++ops;
+ }
+ return(0);
+ }
+ } else {
+ /*
+ * output is not contracted
+ */
+ if (cnt && (fwrite(buf, sizeof(char), cnt, stdout) <= 0)) {
+ pfail();
+ return(1);
+ }
+ if (mor != 0)
+ return(0);
+ }
+
+ /*
+ * process line end and double space as required
+ */
+ if ((putchar('\n') == EOF) || (dspace && (putchar('\n') == EOF))) {
+ pfail();
+ return(1);
+ }
+ return(0);
+}
+
+/*
+ * inskip(): skip over pgcnt pages with lncnt lines per page
+ * file is closed at EOF (if not stdin).
+ *
+ * inf FILE * to read from
+ * pgcnt number of pages to skip
+ * lncnt number of lines per page
+ */
+int
+inskip(FILE *inf, int pgcnt, int lncnt)
+{
+ int c;
+ int cnt;
+
+ while(--pgcnt > 0) {
+ cnt = lncnt;
+ while ((c = getc(inf)) != EOF) {
+ if ((c == '\n') && (--cnt == 0))
+ break;
+ }
+ if (ferror(inf)) {
+ errx(EX_IOERR, NULL);
+ }
+ if (c == EOF) {
+ if (inf != stdin)
+ (void)fclose(inf);
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/*
+ * nxtfile: returns a FILE * to next file in arg list and sets the
+ * time field for this file (or current date).
+ *
+ * buf array to store proper date for the header.
+ * dt if set skips the date processing (used with -m)
+ */
+FILE *
+nxtfile(int argc, char **argv, const char **fname, char *buf, int dt)
+{
+ FILE *inf = NULL;
+ struct timeval tv;
+ time_t tv_sec;
+ struct timezone tz;
+ struct tm *timeptr = NULL;
+ struct stat statbuf;
+ static int twice = -1;
+
+ ++twice;
+ if (eoptind >= argc) {
+ /*
+ * no file listed; default, use standard input
+ */
+ if (twice)
+ return(NULL);
+ clearerr(stdin);
+ inf = stdin;
+ if (header != NULL)
+ *fname = header;
+ else
+ *fname = fnamedefault;
+ if (nohead)
+ return(inf);
+ if (gettimeofday(&tv, &tz) < 0) {
+ ++errcnt;
+ (void)fprintf(err, "pr: cannot get time of day, %s\n",
+ strerror(errno));
+ eoptind = argc - 1;
+ return(NULL);
+ }
+ tv_sec = tv.tv_sec;
+ timeptr = localtime(&tv_sec);
+ }
+ for (; eoptind < argc && argv[eoptind]; ++eoptind) {
+ if (strcmp(argv[eoptind], "-") == 0) {
+ /*
+ * process a "-" for filename
+ */
+ clearerr(stdin);
+ inf = stdin;
+ if (header != NULL)
+ *fname = header;
+ else
+ *fname = fnamedefault;
+ ++eoptind;
+ if (nohead || (dt && twice))
+ return(inf);
+ if (gettimeofday(&tv, &tz) < 0) {
+ ++errcnt;
+ (void)fprintf(err,
+ "pr: cannot get time of day, %s\n",
+ strerror(errno));
+ return(NULL);
+ }
+ tv_sec = tv.tv_sec;
+ timeptr = localtime(&tv_sec);
+ } else {
+ /*
+ * normal file processing
+ */
+ if ((inf = fopen(argv[eoptind], "r")) == NULL) {
+ ++errcnt;
+ if (nodiag)
+ continue;
+ (void)fprintf(err, "pr: cannot open %s, %s\n",
+ argv[eoptind], strerror(errno));
+ continue;
+ }
+ if (header != NULL)
+ *fname = header;
+ else if (dt)
+ *fname = fnamedefault;
+ else
+ *fname = argv[eoptind];
+ ++eoptind;
+ if (nohead || (dt && twice))
+ return(inf);
+
+ if (dt) {
+ if (gettimeofday(&tv, &tz) < 0) {
+ ++errcnt;
+ (void)fprintf(err,
+ "pr: cannot get time of day, %s\n",
+ strerror(errno));
+ return(NULL);
+ }
+ tv_sec = tv.tv_sec;
+ timeptr = localtime(&tv_sec);
+ } else {
+ if (fstat(fileno(inf), &statbuf) < 0) {
+ ++errcnt;
+ (void)fclose(inf);
+ (void)fprintf(err,
+ "pr: cannot stat %s, %s\n",
+ argv[eoptind], strerror(errno));
+ return(NULL);
+ }
+ timeptr = localtime(&(statbuf.st_mtime));
+ }
+ }
+ break;
+ }
+ if (inf == NULL)
+ return(NULL);
+
+ /*
+ * set up time field used in header
+ */
+ if (strftime(buf, HDBUF, timefrmt, timeptr) <= 0) {
+ ++errcnt;
+ if (inf != stdin)
+ (void)fclose(inf);
+ (void)fputs("pr: time conversion failed\n", err);
+ return(NULL);
+ }
+ return(inf);
+}
+
+/*
+ * addnum(): adds the line number to the column
+ * Truncates from the front or pads with spaces as required.
+ * Numbers are right justified.
+ *
+ * buf buffer to store the number
+ * wdth width of buffer to fill
+ * line line number
+ *
+ * NOTE: numbers occupy part of the column. The posix
+ * spec does not specify if -i processing should or should not
+ * occur on number padding. The spec does say it occupies
+ * part of the column. The usage of addnum currently treats
+ * numbers as part of the column so spaces may be replaced.
+ */
+void
+addnum(char *buf, int wdth, int line)
+{
+ char *pt = buf + wdth;
+
+ do {
+ *--pt = digs[line % 10];
+ line /= 10;
+ } while (line && (pt > buf));
+
+ /*
+ * pad with space as required
+ */
+ while (pt > buf)
+ *--pt = ' ';
+}
+
+/*
+ * prhead(): prints the top of page header
+ *
+ * buf buffer with time field (and offset)
+ * cnt number of chars in buf
+ * fname fname field for header
+ * pagcnt page number
+ */
+int
+prhead(char *buf, const char *fname, int pagcnt)
+{
+ int ips = 0;
+ int ops = 0;
+
+ if ((putchar('\n') == EOF) || (putchar('\n') == EOF)) {
+ pfail();
+ return(1);
+ }
+ /*
+ * posix is not clear if the header is subject to line length
+ * restrictions. The specification for header line format
+ * in the spec clearly does not limit length. No pr currently
+ * restricts header length. However if we need to truncate in
+ * a reasonable way, adjust the length of the printf by
+ * changing HDFMT to allow a length max as an arguement printf.
+ * buf (which contains the offset spaces and time field could
+ * also be trimmed
+ *
+ * note only the offset (if any) is processed for tab expansion
+ */
+ if (offst && otln(buf, offst, &ips, &ops, -1))
+ return(1);
+ (void)printf(HDFMT,buf+offst, fname, pagcnt);
+ return(0);
+}
+
+/*
+ * prtail(): pad page with empty lines (if required) and print page trailer
+ * if requested
+ *
+ * cnt number of lines of padding needed
+ * incomp was a '\n' missing from last line output
+ */
+int
+prtail(int cnt, int incomp)
+{
+ if (nohead) {
+ /*
+ * only pad with no headers when incomplete last line
+ */
+ if (incomp &&
+ ((dspace && (putchar('\n') == EOF)) ||
+ (putchar('\n') == EOF))) {
+ pfail();
+ return(1);
+ }
+ /*
+ * but honor the formfeed request
+ */
+ if (formfeed) {
+ if (putchar('\f') == EOF) {
+ pfail();
+ return(1);
+ }
+ }
+ return(0);
+ }
+ /*
+ * if double space output two \n
+ */
+ if (dspace)
+ cnt *= 2;
+
+ /*
+ * if an odd number of lines per page, add an extra \n
+ */
+ if (addone)
+ ++cnt;
+
+ /*
+ * pad page
+ */
+ if (formfeed) {
+ if ((incomp && (putchar('\n') == EOF)) ||
+ (putchar('\f') == EOF)) {
+ pfail();
+ return(1);
+ }
+ return(0);
+ }
+ cnt += TAILLEN;
+ while (--cnt >= 0) {
+ if (putchar('\n') == EOF) {
+ pfail();
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/*
+ * terminate(): when a SIGINT is recvd
+ */
+void
+terminate(int which_sig __unused)
+{
+ flsh_errs();
+ exit(1);
+}
+
+
+/*
+ * flsh_errs(): output saved up diagnostic messages after all normal
+ * processing has completed
+ */
+void
+flsh_errs(void)
+{
+ char buf[BUFSIZ];
+
+ (void)fflush(stdout);
+ (void)fflush(err);
+ if (err == stderr)
+ return;
+ rewind(err);
+ while (fgets(buf, BUFSIZ, err) != NULL)
+ (void)fputs(buf, stderr);
+}
+
+void
+mfail(void)
+{
+ (void)fputs("pr: memory allocation failed\n", err);
+}
+
+void
+pfail(void)
+{
+ (void)fprintf(err, "pr: write failure, %s\n", strerror(errno));
+}
+
+void
+usage(void)
+{
+ (void)fputs(
+ "usage: pr [+page] [-col] [-adFfmprt] [-e[ch][gap]] [-h header]\n",
+ err);
+ (void)fputs(
+ " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err);
+ (void)fputs(
+ " [-L locale] [-s[ch]] [-w width] [-] [file ...]\n", err);
+}
+
+/*
+ * setup: Validate command args, initialize and perform sanity
+ * checks on options
+ */
+int
+setup(int argc, char *argv[])
+{
+ int c;
+ int d_first;
+ int eflag = 0;
+ int iflag = 0;
+ int wflag = 0;
+ int cflag = 0;
+ char *Lflag = NULL;
+
+ if (isatty(fileno(stdout))) {
+ /*
+ * defer diagnostics until processing is done
+ */
+ if ((err = tmpfile()) == NULL) {
+ err = stderr;
+ (void)fputs("Cannot defer diagnostic messages\n",stderr);
+ return(1);
+ }
+ } else
+ err = stderr;
+ while ((c = egetopt(argc, argv, "#adFfmrte?h:i?L:l:n?o:ps?w:")) != -1) {
+ switch (c) {
+ case '+':
+ if ((pgnm = atoi(eoptarg)) < 1) {
+ (void)fputs("pr: +page number must be 1 or more\n",
+ err);
+ return(1);
+ }
+ break;
+ case '-':
+ if ((clcnt = atoi(eoptarg)) < 1) {
+ (void)fputs("pr: -columns must be 1 or more\n",err);
+ return(1);
+ }
+ if (clcnt > 1)
+ ++cflag;
+ break;
+ case 'a':
+ ++across;
+ break;
+ case 'd':
+ ++dspace;
+ break;
+ case 'e':
+ ++eflag;
+ if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
+ inchar = *eoptarg++;
+ else
+ inchar = INCHAR;
+ if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
+ if ((ingap = atoi(eoptarg)) < 0) {
+ (void)fputs(
+ "pr: -e gap must be 0 or more\n", err);
+ return(1);
+ }
+ if (ingap == 0)
+ ingap = INGAP;
+ } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
+ (void)fprintf(err,
+ "pr: invalid value for -e %s\n", eoptarg);
+ return(1);
+ } else
+ ingap = INGAP;
+ break;
+ case 'f':
+ ++pausefst;
+ /*FALLTHROUGH*/
+ case 'F':
+ ++formfeed;
+ break;
+ case 'h':
+ header = eoptarg;
+ break;
+ case 'i':
+ ++iflag;
+ if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
+ ochar = *eoptarg++;
+ else
+ ochar = OCHAR;
+ if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
+ if ((ogap = atoi(eoptarg)) < 0) {
+ (void)fputs(
+ "pr: -i gap must be 0 or more\n", err);
+ return(1);
+ }
+ if (ogap == 0)
+ ogap = OGAP;
+ } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
+ (void)fprintf(err,
+ "pr: invalid value for -i %s\n", eoptarg);
+ return(1);
+ } else
+ ogap = OGAP;
+ break;
+ case 'L':
+ Lflag = eoptarg;
+ break;
+ case 'l':
+ if (!isdigit((unsigned char)*eoptarg) || ((lines=atoi(eoptarg)) < 1)) {
+ (void)fputs(
+ "pr: number of lines must be 1 or more\n",err);
+ return(1);
+ }
+ break;
+ case 'm':
+ ++merge;
+ break;
+ case 'n':
+ if ((eoptarg != NULL) && !isdigit((unsigned char)*eoptarg))
+ nmchar = *eoptarg++;
+ else
+ nmchar = NMCHAR;
+ if ((eoptarg != NULL) && isdigit((unsigned char)*eoptarg)) {
+ if ((nmwd = atoi(eoptarg)) < 1) {
+ (void)fputs(
+ "pr: -n width must be 1 or more\n",err);
+ return(1);
+ }
+ } else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
+ (void)fprintf(err,
+ "pr: invalid value for -n %s\n", eoptarg);
+ return(1);
+ } else
+ nmwd = NMWD;
+ break;
+ case 'o':
+ if (!isdigit((unsigned char)*eoptarg) || ((offst = atoi(eoptarg))< 1)){
+ (void)fputs("pr: -o offset must be 1 or more\n",
+ err);
+ return(1);
+ }
+ break;
+ case 'p':
+ ++pauseall;
+ break;
+ case 'r':
+ ++nodiag;
+ break;
+ case 's':
+ ++sflag;
+ if (eoptarg == NULL)
+ schar = SCHAR;
+ else {
+ schar = *eoptarg++;
+ if (*eoptarg != '\0') {
+ (void)fprintf(err,
+ "pr: invalid value for -s %s\n",
+ eoptarg);
+ return(1);
+ }
+ }
+ break;
+ case 't':
+ ++nohead;
+ break;
+ case 'w':
+ ++wflag;
+ if (!isdigit((unsigned char)*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){
+ (void)fputs(
+ "pr: -w width must be 1 or more \n",err);
+ return(1);
+ }
+ break;
+ case '?':
+ default:
+ return(1);
+ }
+ }
+
+ /*
+ * default and sanity checks
+ */
+ if (!clcnt) {
+ if (merge) {
+ if ((clcnt = argc - eoptind) <= 1) {
+ clcnt = CLCNT;
+ merge = 0;
+ }
+ } else
+ clcnt = CLCNT;
+ }
+ if (across) {
+ if (clcnt == 1) {
+ (void)fputs("pr: -a flag requires multiple columns\n",
+ err);
+ return(1);
+ }
+ if (merge) {
+ (void)fputs("pr: -m cannot be used with -a\n", err);
+ return(1);
+ }
+ }
+ if (!wflag) {
+ if (sflag)
+ pgwd = SPGWD;
+ else
+ pgwd = PGWD;
+ }
+ if (cflag || merge) {
+ if (!eflag) {
+ inchar = INCHAR;
+ ingap = INGAP;
+ }
+ if (!iflag) {
+ ochar = OCHAR;
+ ogap = OGAP;
+ }
+ }
+ if (cflag) {
+ if (merge) {
+ (void)fputs(
+ "pr: -m cannot be used with multiple columns\n", err);
+ return(1);
+ }
+ if (nmwd) {
+ colwd = (pgwd + 1 - (clcnt * (nmwd + 2)))/clcnt;
+ pgwd = ((colwd + nmwd + 2) * clcnt) - 1;
+ } else {
+ colwd = (pgwd + 1 - clcnt)/clcnt;
+ pgwd = ((colwd + 1) * clcnt) - 1;
+ }
+ if (colwd < 1) {
+ (void)fprintf(err,
+ "pr: page width is too small for %d columns\n",clcnt);
+ return(1);
+ }
+ }
+ if (!lines)
+ lines = LINES;
+
+ /*
+ * make sure long enough for headers. if not disable
+ */
+ if (lines <= HEADLEN + TAILLEN)
+ ++nohead;
+ else if (!nohead)
+ lines -= HEADLEN + TAILLEN;
+
+ /*
+ * adjust for double space on odd length pages
+ */
+ if (dspace) {
+ if (lines == 1)
+ dspace = 0;
+ else {
+ if (lines & 1)
+ ++addone;
+ lines /= 2;
+ }
+ }
+
+ (void) setlocale(LC_TIME, (Lflag != NULL) ? Lflag : "");
+
+ d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+ timefrmt = strdup(d_first ? TIMEFMTD : TIMEFMTM);
+
+ return(0);
+}
diff --git a/text_cmds/pr/pr.h b/text_cmds/pr/pr.h
new file mode 100644
index 0000000..d93fe8c
--- /dev/null
+++ b/text_cmds/pr/pr.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1991 Keith Muller.
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Keith Muller of the University of California, San Diego.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pr.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/pr/pr.h,v 1.4 2001/03/21 14:32:02 ache Exp $
+ */
+
+/*
+ * parameter defaults
+ */
+#define CLCNT 1
+#define INCHAR '\t'
+#define INGAP 8
+#define OCHAR '\t'
+#define OGAP 8
+#define LINES 66
+#define NMWD 5
+#define NMCHAR '\t'
+#define SCHAR '\t'
+#define PGWD 72
+#define SPGWD 512
+
+/*
+ * misc default values
+ */
+#define HDFMT "%s %s Page %d\n\n\n"
+#define HEADLEN 5
+#define TAILLEN 5
+#define TIMEFMTD "%e %b %H:%M %Y"
+#define TIMEFMTM "%b %e %H:%M %Y"
+#define FNAME ""
+#define LBUF 8192
+#define HDBUF 512
+
+/*
+ * structure for vertical columns. Used to balance cols on last page
+ */
+struct vcol {
+ char *pt; /* ptr to col */
+ int cnt; /* char count */
+};
diff --git a/text_cmds/rev/rev.1 b/text_cmds/rev/rev.1
new file mode 100644
index 0000000..a1e9eb5
--- /dev/null
+++ b/text_cmds/rev/rev.1
@@ -0,0 +1,49 @@
+.\" Copyright (c) 1985, 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rev.1 8.1 (Berkeley) 6/9/93
+.\" $FreeBSD: src/usr.bin/rev/rev.1,v 1.6 2001/02/13 09:55:09 ru Exp $
+.\"
+.Dd June 9, 1993
+.Dt REV 1
+.Os
+.Sh NAME
+.Nm rev
+.Nd reverse lines of a file
+.Sh SYNOPSIS
+.Nm
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility copies the specified files to the standard output, reversing the
+order of characters in every line.
+If no files are specified, the standard input is read.
diff --git a/text_cmds/rev/rev.c b/text_cmds/rev/rev.c
new file mode 100644
index 0000000..478f15f
--- /dev/null
+++ b/text_cmds/rev/rev.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 1987, 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)rev.c 8.3 (Berkeley) 5/4/95";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/rev/rev.c,v 1.12 2009/12/13 03:14:06 delphij Exp $");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ const char *filename;
+ wchar_t *p, *t;
+ FILE *fp;
+ size_t len;
+ int ch, rval;
+
+ setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ fp = stdin;
+ filename = "stdin";
+ rval = 0;
+ do {
+ if (*argv) {
+ if ((fp = fopen(*argv, "r")) == NULL) {
+ warn("%s", *argv);
+ rval = 1;
+ ++argv;
+ continue;
+ }
+ filename = *argv++;
+ }
+ while ((p = fgetwln(fp, &len)) != NULL) {
+ if (p[len - 1] == '\n')
+ --len;
+ for (t = p + len - 1; t >= p; --t)
+ putwchar(*t);
+ putwchar('\n');
+ }
+ if (ferror(fp)) {
+ warn("%s", filename);
+ clearerr(fp);
+ rval = 1;
+ }
+ (void)fclose(fp);
+ } while(*argv);
+ exit(rval);
+}
+
+void
+usage(void)
+{
+ (void)fprintf(stderr, "usage: rev [file ...]\n");
+ exit(1);
+}
diff --git a/text_cmds/rs/rs.1 b/text_cmds/rs/rs.1
new file mode 100644
index 0000000..5e27815
--- /dev/null
+++ b/text_cmds/rs/rs.1
@@ -0,0 +1,239 @@
+.\" Copyright (c) 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rs.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD: src/usr.bin/rs/rs.1,v 1.11 2004/07/30 00:10:52 tjr Exp $
+.\"
+.Dd July 30, 2004
+.Dt RS 1
+.Os
+.Sh NAME
+.Nm rs
+.Nd reshape a data array
+.Sh SYNOPSIS
+.Nm
+.Oo
+.Fl Oo Cm csCS Oc Ns Op Ar x
+.Oo Cm kKgGw Oc Ns Op Ar N
+.Cm tTeEnyjhHmz
+.Oc
+.Op Ar rows Op Ar cols
+.Sh DESCRIPTION
+The
+.Nm
+utility reads the standard input, interpreting each line as a row
+of blank-separated entries in an array,
+transforms the array according to the options,
+and writes it on the standard output.
+With no arguments it transforms stream input into a columnar
+format convenient for terminal viewing.
+.Pp
+The shape of the input array is deduced from the number of lines
+and the number of columns on the first line.
+If that shape is inconvenient, a more useful one might be
+obtained by skipping some of the input with the
+.Fl k
+option.
+Other options control interpretation of the input columns.
+.Pp
+The shape of the output array is influenced by the
+.Ar rows
+and
+.Ar cols
+specifications, which should be positive integers.
+If only one of them is a positive integer,
+.Nm
+computes a value for the other which will accommodate
+all of the data.
+When necessary, missing data are supplied in a manner
+specified by the options and surplus data are deleted.
+There are options to control presentation of the output columns,
+including transposition of the rows and columns.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl c Ns Ar x
+Input columns are delimited by the single character
+.Ar x .
+A missing
+.Ar x
+is taken to be `^I'.
+.It Fl s Ns Ar x
+Like
+.Fl c ,
+but maximal strings of
+.Ar x
+are delimiters.
+.It Fl C Ns Ar x
+Output columns are delimited by the single character
+.Ar x .
+A missing
+.Ar x
+is taken to be `^I'.
+.It Fl S Ns Ar x
+Like
+.Fl C ,
+but padded strings of
+.Ar x
+are delimiters.
+.It Fl t
+Fill in the rows of the output array using the columns of the
+input array, that is, transpose the input while honoring any
+.Ar rows
+and
+.Ar cols
+specifications.
+.It Fl T
+Print the pure transpose of the input, ignoring any
+.Ar rows
+or
+.Ar cols
+specification.
+.It Fl k Ns Ar N
+Ignore the first
+.Ar N
+lines of input.
+.It Fl K Ns Ar N
+Like
+.Fl k ,
+but print the ignored lines.
+.It Fl g Ns Ar N
+The gutter width (inter-column space), normally 2, is taken to be
+.Ar N .
+.It Fl G Ns Ar N
+The gutter width has
+.Ar N
+percent of the maximum column width added to it.
+.It Fl e
+Consider each line of input as an array entry.
+.It Fl n
+On lines having fewer entries than the first line,
+use null entries to pad out the line.
+Normally, missing entries are taken from the next line of input.
+.It Fl y
+If there are too few entries to make up the output dimensions,
+pad the output by recycling the input from the beginning.
+Normally, the output is padded with blanks.
+.It Fl h
+Print the shape of the input array and do nothing else.
+The shape is just the number of lines and the number of
+entries on the first line.
+.It Fl H
+Like
+.Fl h ,
+but also print the length of each line.
+.It Fl j
+Right adjust entries within columns.
+.It Fl w Ns Ar N
+The width of the display, normally 80, is taken to be the positive
+integer
+.Ar N .
+.It Fl m
+Do not trim excess delimiters from the ends of the output array.
+.It Fl z
+Adapt column widths to fit the largest entries appearing in them.
+.El
+.Pp
+With no arguments,
+.Nm
+transposes its input, and assumes one array entry per input line
+unless the first non-ignored line is longer than the display width.
+Option letters which take numerical arguments interpret a missing
+number as zero unless otherwise indicated.
+.Sh EXAMPLES
+The
+.Nm
+utility can be used as a filter to convert the stream output
+of certain programs (e.g.,
+.Xr spell 1 ,
+.Xr du 1 ,
+.Xr file 1 ,
+.Xr look 1 ,
+.Xr nm 1 ,
+.Xr who 1 ,
+and
+.Xr wc 1 )
+into a convenient ``window'' format, as in
+.Bd -literal -offset indent
+% who | rs
+.Ed
+.Pp
+This function has been incorporated into the
+.Xr ls 1
+program, though for most programs with similar output
+.Nm
+suffices.
+.Pp
+To convert stream input into vector output and back again, use
+.Bd -literal -offset indent
+% rs 1 0 | rs 0 1
+.Ed
+.Pp
+A 10 by 10 array of random numbers from 1 to 100 and
+its transpose can be generated with
+.Bd -literal -offset indent
+% jot \-r 100 | rs 10 10 | tee array | rs \-T > tarray
+.Ed
+.Pp
+In the editor
+.Xr vi 1 ,
+a file consisting of a multi-line vector with 9 elements per line
+can undergo insertions and deletions,
+and then be neatly reshaped into 9 columns with
+.Bd -literal -offset indent
+:1,$!rs 0 9
+.Ed
+.Pp
+Finally, to sort a database by the first line of each 4-line field, try
+.Bd -literal -offset indent
+% rs \-eC 0 4 | sort | rs \-c 0 1
+.Ed
+.Sh SEE ALSO
+.Xr jot 1 ,
+.Xr pr 1 ,
+.Xr sort 1 ,
+.Xr vi 1
+.Sh BUGS
+.Bl -item
+.It
+Handles only two dimensional arrays.
+.It
+The algorithm currently reads the whole file into memory,
+so files that do not fit in memory will not be reshaped.
+.It
+Fields cannot be defined yet on character positions.
+.It
+Re-ordering of columns is not yet possible.
+.It
+There are too many options.
+.It
+Multibyte characters are not recognized.
+.El
diff --git a/text_cmds/rs/rs.c b/text_cmds/rs/rs.c
new file mode 100644
index 0000000..19cb750
--- /dev/null
+++ b/text_cmds/rs/rs.c
@@ -0,0 +1,553 @@
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static const char sccsid[] = "@(#)rs.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * rs - reshape a data array
+ * Author: John Kunze, Office of Comp. Affairs, UCB
+ * BEWARE: lots of unfinished edges
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/rs/rs.c,v 1.13 2005/04/28 12:37:15 robert Exp $");
+
+#include <err.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+long flags;
+#define TRANSPOSE 000001
+#define MTRANSPOSE 000002
+#define ONEPERLINE 000004
+#define ONEISEPONLY 000010
+#define ONEOSEPONLY 000020
+#define NOTRIMENDCOL 000040
+#define SQUEEZE 000100
+#define SHAPEONLY 000200
+#define DETAILSHAPE 000400
+#define RIGHTADJUST 001000
+#define NULLPAD 002000
+#define RECYCLE 004000
+#define SKIPPRINT 010000
+#define ICOLBOUNDS 020000
+#define OCOLBOUNDS 040000
+#define ONEPERCHAR 0100000
+#define NOARGS 0200000
+
+short *colwidths;
+short *cord;
+short *icbd;
+short *ocbd;
+int nelem;
+char **elem;
+char **endelem;
+char *curline;
+int allocsize = BUFSIZ;
+int curlen;
+int irows, icols;
+int orows = 0, ocols = 0;
+int maxlen;
+int skip;
+int propgutter;
+char isep = ' ', osep = ' ';
+char blank[] = "";
+int owidth = 80, gutter = 2;
+
+void getargs(int, char *[]);
+void getfile(void);
+int rs_getline(void);
+char *getlist(short **, char *);
+char *getnum(int *, char *, int);
+char **getptrs(char **);
+void prepfile(void);
+void prints(char *, int);
+void putfile(void);
+static void usage(void);
+
+#define INCR(ep) do { \
+ if (++ep >= endelem) \
+ ep = getptrs(ep); \
+} while(0)
+
+int
+main(int argc, char *argv[])
+{
+ getargs(argc, argv);
+ getfile();
+ if (flags & SHAPEONLY) {
+ printf("%d %d\n", irows, icols);
+ exit(0);
+ }
+ prepfile();
+ putfile();
+ exit(0);
+}
+
+void
+getfile(void)
+{
+ char *p;
+ char *endp;
+ char **ep;
+ int multisep = (flags & ONEISEPONLY ? 0 : 1);
+ int nullpad = flags & NULLPAD;
+ char **padto;
+
+ while (skip--) {
+ rs_getline();
+ if (flags & SKIPPRINT)
+ puts(curline);
+ }
+ rs_getline();
+ if (flags & NOARGS && curlen < owidth)
+ flags |= ONEPERLINE;
+ if (flags & ONEPERLINE)
+ icols = 1;
+ else /* count cols on first line */
+ for (p = curline, endp = curline + curlen; p < endp; p++) {
+ if (*p == isep && multisep)
+ continue;
+ icols++;
+ while (*p && *p != isep)
+ p++;
+ }
+ ep = getptrs(elem);
+ p = curline;
+ do {
+ if (flags & ONEPERLINE) {
+ *ep = curline;
+ INCR(ep); /* prepare for next entry */
+ if (maxlen < curlen)
+ maxlen = curlen;
+ irows++;
+ continue;
+ }
+ for (p = curline, endp = curline + curlen; p < endp; p++) {
+ if (*p == isep && multisep)
+ continue; /* eat up column separators */
+ if (*p == isep) /* must be an empty column */
+ *ep = blank;
+ else /* store column entry */
+ *ep = p;
+ while (p < endp && *p != isep)
+ p++; /* find end of entry */
+ *p = '\0'; /* mark end of entry */
+ if (maxlen < p - *ep) /* update maxlen */
+ maxlen = p - *ep;
+ INCR(ep); /* prepare for next entry */
+ }
+ irows++; /* update row count */
+ if (nullpad) { /* pad missing entries */
+ padto = elem + irows * icols;
+ while (ep < padto) {
+ *ep = blank;
+ INCR(ep);
+ }
+ }
+ } while (rs_getline() != EOF);
+ *ep = 0; /* mark end of pointers */
+ nelem = ep - elem;
+}
+
+void
+putfile(void)
+{
+ char **ep;
+ int i, j, k;
+
+ ep = elem;
+ if (flags & TRANSPOSE)
+ for (i = 0; i < orows; i++) {
+ for (j = i; j < nelem; j += orows)
+ prints(ep[j], (j - i) / orows);
+ putchar('\n');
+ }
+ else
+ for (i = k = 0; i < orows; i++) {
+ for (j = 0; j < ocols; j++, k++)
+ if (k < nelem)
+ prints(ep[k], j);
+ putchar('\n');
+ }
+}
+
+void
+prints(char *s, int col)
+{
+ int n;
+ char *p = s;
+
+ while (*p)
+ p++;
+ n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
+ if (flags & RIGHTADJUST)
+ while (n-- > 0)
+ putchar(osep);
+ for (p = s; *p; p++)
+ putchar(*p);
+ while (n-- > 0)
+ putchar(osep);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: rs [-[csCS][x][kKgGw][N]tTeEnyjhHmz] [rows [cols]]\n");
+ exit(1);
+}
+
+void
+prepfile(void)
+{
+ char **ep;
+ int i;
+ int j;
+ char **lp;
+ int colw;
+ int max;
+ int n;
+
+ if (!nelem)
+ exit(0);
+ gutter += maxlen * propgutter / 100.0;
+ colw = maxlen + gutter;
+ if (flags & MTRANSPOSE) {
+ orows = icols;
+ ocols = irows;
+ }
+ else if (orows == 0 && ocols == 0) { /* decide rows and cols */
+ ocols = owidth / colw;
+ if (ocols == 0) {
+ warnx("display width %d is less than column width %d",
+ owidth, colw);
+ ocols = 1;
+ }
+ if (ocols > nelem)
+ ocols = nelem;
+ orows = nelem / ocols + (nelem % ocols ? 1 : 0);
+ }
+ else if (orows == 0) /* decide on rows */
+ orows = nelem / ocols + (nelem % ocols ? 1 : 0);
+ else if (ocols == 0) /* decide on cols */
+ ocols = nelem / orows + (nelem % orows ? 1 : 0);
+ lp = elem + orows * ocols;
+ while (lp > endelem) {
+ getptrs(elem + nelem);
+ lp = elem + orows * ocols;
+ }
+ if (flags & RECYCLE) {
+ for (ep = elem + nelem; ep < lp; ep++)
+ *ep = *(ep - nelem);
+ nelem = lp - elem;
+ }
+ if (!(colwidths = (short *) malloc(ocols * sizeof(short))))
+ errx(1, "malloc");
+ if (flags & SQUEEZE) {
+ ep = elem;
+ if (flags & TRANSPOSE)
+ for (i = 0; i < ocols; i++) {
+ max = 0;
+ for (j = 0; *ep != NULL && j < orows; j++)
+ if ((n = strlen(*ep++)) > max)
+ max = n;
+ colwidths[i] = max + gutter;
+ }
+ else
+ for (i = 0; i < ocols; i++) {
+ max = 0;
+ for (j = i; j < nelem; j += ocols)
+ if ((n = strlen(ep[j])) > max)
+ max = n;
+ colwidths[i] = max + gutter;
+ }
+ }
+ /* for (i = 0; i < orows; i++) {
+ for (j = i; j < nelem; j += orows)
+ prints(ep[j], (j - i) / orows);
+ putchar('\n');
+ }
+ else
+ for (i = 0; i < orows; i++) {
+ for (j = 0; j < ocols; j++)
+ prints(*ep++, j);
+ putchar('\n');
+ }*/
+ else
+ for (i = 0; i < ocols; i++)
+ colwidths[i] = colw;
+ if (!(flags & NOTRIMENDCOL)) {
+ if (flags & RIGHTADJUST)
+ colwidths[0] -= gutter;
+ else
+ colwidths[ocols - 1] = 0;
+ }
+ n = orows * ocols;
+ if (n > nelem && (flags & RECYCLE))
+ nelem = n;
+ /*for (i = 0; i < ocols; i++)
+ warnx("%d is colwidths, nelem %d", colwidths[i], nelem);*/
+}
+
+#define BSIZE 2048
+char ibuf[BSIZE]; /* two screenfuls should do */
+
+int
+rs_getline(void) /* get line; maintain curline, curlen; manage storage */
+{
+ static int putlength;
+ static char *endblock = ibuf + BSIZE;
+ char *p;
+ int c, i;
+
+ if (!irows) {
+ curline = ibuf;
+ putlength = flags & DETAILSHAPE;
+ }
+ else if (skip <= 0) { /* don't waste storage */
+ curline += curlen + 1;
+ if (putlength) { /* print length, recycle storage */
+ printf(" %d line %d\n", curlen, irows);
+ curline = ibuf;
+ }
+ }
+ if (!putlength && endblock - curline < BUFSIZ) { /* need storage */
+ /*ww = endblock-curline; tt += ww;*/
+ /*printf("#wasted %d total %d\n",ww,tt);*/
+ if (!(curline = (char *) malloc(BSIZE)))
+ errx(1, "file too large");
+ endblock = curline + BSIZE;
+ /*printf("#endb %d curline %d\n",endblock,curline);*/
+ }
+ for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++)
+ if ((c = getchar()) == EOF || c == '\n')
+ break;
+ if (ferror(stdin)) {
+ errx(EX_IOERR, "Read error");
+ }
+ *p = '\0';
+ curlen = i - 1;
+ return(c);
+}
+
+char **
+getptrs(char **sp)
+{
+ char **p;
+
+ allocsize += allocsize;
+ p = (char **)realloc(elem, allocsize * sizeof(char *));
+ if (p == NULL)
+ err(1, "no memory");
+
+ sp += (p - elem);
+ endelem = (elem = p) + allocsize;
+ return(sp);
+}
+
+void
+getargs(int ac, char *av[])
+{
+ char *p;
+
+ if (ac == 1) {
+ flags |= NOARGS | TRANSPOSE;
+ }
+ while (--ac>0 && *++av && **av == '-')
+ for (p = *av+1; *p; p++)
+ switch (*p) {
+ case 'T':
+ flags |= MTRANSPOSE;
+ case 't':
+ flags |= TRANSPOSE;
+ break;
+ case 'c': /* input col. separator */
+ flags |= ONEISEPONLY;
+ case 's': /* one or more allowed */
+ if (p[1])
+ isep = *++p;
+ else
+ isep = '\t'; /* default is ^I */
+ break;
+ case 'C':
+ flags |= ONEOSEPONLY;
+ case 'S':
+ if (p[1])
+ osep = *++p;
+ else
+ osep = '\t'; /* default is ^I */
+ break;
+ case 'w': /* window width, default 80 */
+ p = getnum(&owidth, p, 0);
+ if (owidth <= 0)
+ errx(1, "width must be a positive integer");
+ break;
+ case 'K': /* skip N lines */
+ flags |= SKIPPRINT;
+ case 'k': /* skip, do not print */
+ p = getnum(&skip, p, 0);
+ if (!skip)
+ skip = 1;
+ break;
+ case 'm':
+ flags |= NOTRIMENDCOL;
+ break;
+ case 'g': /* gutter space */
+ p = getnum(&gutter, p, 0);
+ break;
+ case 'G':
+ p = getnum(&propgutter, p, 0);
+ break;
+ case 'e': /* each line is an entry */
+ flags |= ONEPERLINE;
+ break;
+ case 'E':
+ flags |= ONEPERCHAR;
+ break;
+ case 'j': /* right adjust */
+ flags |= RIGHTADJUST;
+ break;
+ case 'n': /* null padding for missing values */
+ flags |= NULLPAD;
+ break;
+ case 'y':
+ flags |= RECYCLE;
+ break;
+ case 'H': /* print shape only */
+ flags |= DETAILSHAPE;
+ case 'h':
+ flags |= SHAPEONLY;
+ break;
+ case 'z': /* squeeze col width */
+ flags |= SQUEEZE;
+ break;
+ /*case 'p':
+ ipagespace = atoi(++p); (default is 1)
+ break;*/
+ case 'o': /* col order */
+ p = getlist(&cord, p);
+ break;
+ case 'b':
+ flags |= ICOLBOUNDS;
+ p = getlist(&icbd, p);
+ break;
+ case 'B':
+ flags |= OCOLBOUNDS;
+ p = getlist(&ocbd, p);
+ break;
+ default:
+ usage();
+ }
+ /*if (!osep)
+ osep = isep;*/
+ switch (ac) {
+ /*case 3:
+ opages = atoi(av[2]);*/
+ case 2:
+ if ((ocols = atoi(av[1])) < 0)
+ ocols = 0;
+ case 1:
+ if ((orows = atoi(av[0])) < 0)
+ orows = 0;
+ case 0:
+ break;
+ default:
+ errx(1, "too many arguments");
+ }
+}
+
+char *
+getlist(short **list, char *p)
+{
+ int count = 1;
+ char *t;
+
+ for (t = p + 1; *t; t++) {
+ if (!isdigit((unsigned char)*t))
+ errx(1,
+ "option %.1s requires a list of unsigned numbers separated by commas", t);
+ count++;
+ while (*t && isdigit((unsigned char)*t))
+ t++;
+ if (*t != ',')
+ break;
+ }
+ if (!(*list = (short *) malloc(count * sizeof(short))))
+ errx(1, "no list space");
+ count = 0;
+ for (t = p + 1; *t; t++) {
+ (*list)[count++] = atoi(t);
+ printf("++ %d ", (*list)[count-1]);
+ fflush(stdout);
+ while (*t && isdigit((unsigned char)*t))
+ t++;
+ if (*t != ',')
+ break;
+ }
+ (*list)[count] = 0;
+ return(t - 1);
+}
+
+/*
+ * num = number p points to; if (strict) complain
+ * returns pointer to end of num
+ */
+char *
+getnum(int *num, char *p, int strict)
+{
+ char *t = p;
+
+ if (!isdigit((unsigned char)*++t)) {
+ if (strict || *t == '-' || *t == '+')
+ errx(1, "option %.1s requires an unsigned integer", p);
+ *num = 0;
+ return(p);
+ }
+ *num = atoi(t);
+ while (*++t)
+ if (!isdigit((unsigned char)*t))
+ break;
+ return(--t);
+}
diff --git a/text_cmds/sed/POSIX b/text_cmds/sed/POSIX
new file mode 100644
index 0000000..239acf8
--- /dev/null
+++ b/text_cmds/sed/POSIX
@@ -0,0 +1,204 @@
+# @(#)POSIX 8.1 (Berkeley) 6/6/93
+# $FreeBSD$
+
+Comments on the IEEE P1003.2 Draft 12
+ Part 2: Shell and Utilities
+ Section 4.55: sed - Stream editor
+
+Diomidis Spinellis <dds@doc.ic.ac.uk>
+Keith Bostic <bostic@cs.berkeley.edu>
+
+In the following paragraphs, "wrong" usually means "inconsistent with
+historic practice", as most of the following comments refer to
+undocumented inconsistencies between the historical versions of sed and
+the POSIX 1003.2 standard. All the comments are notes taken while
+implementing a POSIX-compatible version of sed, and should not be
+interpreted as official opinions or criticism towards the POSIX committee.
+All uses of "POSIX" refer to section 4.55, Draft 12 of POSIX 1003.2.
+
+ 1. 32V and BSD derived implementations of sed strip the text
+ arguments of the a, c and i commands of their initial blanks,
+ i.e.
+
+ #!/bin/sed -f
+ a\
+ foo\
+ \ indent\
+ bar
+
+ produces:
+
+ foo
+ indent
+ bar
+
+ POSIX does not specify this behavior as the System V versions of
+ sed do not do this stripping. The argument against stripping is
+ that it is difficult to write sed scripts that have leading blanks
+ if they are stripped. The argument for stripping is that it is
+ difficult to write readable sed scripts unless indentation is allowed
+ and ignored, and leading whitespace is obtainable by entering a
+ backslash in front of it. This implementation follows the BSD
+ historic practice.
+
+ 2. Historical versions of sed required that the w flag be the last
+ flag to an s command as it takes an additional argument. This
+ is obvious, but not specified in POSIX.
+
+ 3. Historical versions of sed required that whitespace follow a w
+ flag to an s command. This is not specified in POSIX. This
+ implementation permits whitespace but does not require it.
+
+ 4. Historical versions of sed permitted any number of whitespace
+ characters to follow the w command. This is not specified in
+ POSIX. This implementation permits whitespace but does not
+ require it.
+
+ 5. The rule for the l command differs from historic practice. Table
+ 2-15 includes the various ANSI C escape sequences, including \\
+ for backslash. Some historical versions of sed displayed two
+ digit octal numbers, too, not three as specified by POSIX. POSIX
+ is a cleanup, and is followed by this implementation.
+
+ 6. The POSIX specification for ! does not specify that for a single
+ command the command must not contain an address specification
+ whereas the command list can contain address specifications. The
+ specification for ! implies that "3!/hello/p" works, and it never
+ has, historically. Note,
+
+ 3!{
+ /hello/p
+ }
+
+ does work.
+
+ 7. POSIX does not specify what happens with consecutive ! commands
+ (e.g. /foo/!!!p). Historic implementations allow any number of
+ !'s without changing the behaviour. (It seems logical that each
+ one might reverse the behaviour.) This implementation follows
+ historic practice.
+
+ 8. Historic versions of sed permitted commands to be separated
+ by semi-colons, e.g. 'sed -ne '1p;2p;3q' printed the first
+ three lines of a file. This is not specified by POSIX.
+ Note, the ; command separator is not allowed for the commands
+ a, c, i, w, r, :, b, t, # and at the end of a w flag in the s
+ command. This implementation follows historic practice and
+ implements the ; separator.
+
+ 9. Historic versions of sed terminated the script if EOF was reached
+ during the execution of the 'n' command, i.e.:
+
+ sed -e '
+ n
+ i\
+ hello
+ ' </dev/null
+
+ did not produce any output. POSIX does not specify this behavior.
+ This implementation follows historic practice.
+
+10. Deleted.
+
+11. Historical implementations do not output the change text of a c
+ command in the case of an address range whose first line number
+ is greater than the second (e.g. 3,1). POSIX requires that the
+ text be output. Since the historic behavior doesn't seem to have
+ any particular purpose, this implementation follows the POSIX
+ behavior.
+
+12. POSIX does not specify whether address ranges are checked and
+ reset if a command is not executed due to a jump. The following
+ program will behave in different ways depending on whether the
+ 'c' command is triggered at the third line, i.e. will the text
+ be output even though line 3 of the input will never logically
+ encounter that command.
+
+ 2,4b
+ 1,3c\
+ text
+
+ Historic implementations did not output the text in the above
+ example. Therefore it was believed that a range whose second
+ address was never matched extended to the end of the input.
+ However, the current practice adopted by this implementation,
+ as well as by those from GNU and SUN, is as follows: The text
+ from the 'c' command still isn't output because the second address
+ isn't actually matched; but the range is reset after all if its
+ second address is a line number. In the above example, only the
+ first line of the input will be deleted.
+
+13. Historical implementations allow an output suppressing #n at the
+ beginning of -e arguments as well as in a script file. POSIX
+ does not specify this. This implementation follows historical
+ practice.
+
+14. POSIX does not explicitly specify how sed behaves if no script is
+ specified. Since the sed Synopsis permits this form of the command,
+ and the language in the Description section states that the input
+ is output, it seems reasonable that it behave like the cat(1)
+ command. Historic sed implementations behave differently for "ls |
+ sed", where they produce no output, and "ls | sed -e#", where they
+ behave like cat. This implementation behaves like cat in both cases.
+
+15. The POSIX requirement to open all w files at the beginning makes
+ sed behave nonintuitively when the w commands are preceded by
+ addresses or are within conditional blocks. This implementation
+ follows historic practice and POSIX, by default, and provides the
+ -a option which opens the files only when they are needed.
+
+16. POSIX does not specify how escape sequences other than \n and \D
+ (where D is the delimiter character) are to be treated. This is
+ reasonable, however, it also doesn't state that the backslash is
+ to be discarded from the output regardless. A strict reading of
+ POSIX would be that "echo xyz | sed s/./\a" would display "\ayz".
+ As historic sed implementations always discarded the backslash,
+ this implementation does as well.
+
+17. POSIX specifies that an address can be "empty". This implies
+ that constructs like ",d" or "1,d" and ",5d" are allowed. This
+ is not true for historic implementations or this implementation
+ of sed.
+
+18. The b t and : commands are documented in POSIX to ignore leading
+ white space, but no mention is made of trailing white space.
+ Historic implementations of sed assigned different locations to
+ the labels "x" and "x ". This is not useful, and leads to subtle
+ programming errors, but it is historic practice and changing it
+ could theoretically break working scripts. This implementation
+ follows historic practice.
+
+19. Although POSIX specifies that reading from files that do not exist
+ from within the script must not terminate the script, it does not
+ specify what happens if a write command fails. Historic practice
+ is to fail immediately if the file cannot be opened or written.
+ This implementation follows historic practice.
+
+20. Historic practice is that the \n construct can be used for either
+ string1 or string2 of the y command. This is not specified by
+ POSIX. This implementation follows historic practice.
+
+21. Deleted.
+
+22. Historic implementations of sed ignore the RE delimiter characters
+ within character classes. This is not specified in POSIX. This
+ implementation follows historic practice.
+
+23. Historic implementations handle empty RE's in a special way: the
+ empty RE is interpreted as if it were the last RE encountered,
+ whether in an address or elsewhere. POSIX does not document this
+ behavior. For example the command:
+
+ sed -e /abc/s//XXX/
+
+ substitutes XXX for the pattern abc. The semantics of "the last
+ RE" can be defined in two different ways:
+
+ 1. The last RE encountered when compiling (lexical/static scope).
+ 2. The last RE encountered while running (dynamic scope).
+
+ While many historical implementations fail on programs depending
+ on scope differences, the SunOS version exhibited dynamic scope
+ behaviour. This implementation does dynamic scoping, as this seems
+ the most useful and in order to remain consistent with historical
+ practice.
diff --git a/text_cmds/sed/TEST/hanoi.sed b/text_cmds/sed/TEST/hanoi.sed
new file mode 100644
index 0000000..0a724b8
--- /dev/null
+++ b/text_cmds/sed/TEST/hanoi.sed
@@ -0,0 +1,103 @@
+# Towers of Hanoi in sed.
+#
+# @(#)hanoi.sed 8.1 (Berkeley) 6/6/93
+# $FreeBSD: src/usr.bin/sed/TEST/hanoi.sed,v 1.3 2002/07/04 05:16:19 tjr Exp $
+#
+#
+# Ex:
+# Run "sed -f hanoi.sed", and enter:
+#
+# :abcd: : :<CR>
+#
+# note -- TWO carriage returns were once required, this will output the
+# sequence of states involved in moving 4 rings, the largest called "a" and
+# the smallest called "d", from the first to the second of three towers, so
+# that the rings on any tower at any time are in descending order of size.
+# You can start with a different arrangement and a different number of rings,
+# say :ce:b:ax: and it will give the shortest procedure for moving them all
+# to the middle tower. The rules are: the names of the rings must all be
+# lower-case letters, they must be input within 3 fields (representing the
+# towers) and delimited by 4 colons, such that the letters within each field
+# are in alphabetical order (i.e. rings are in descending order of size).
+#
+# For the benefit of anyone who wants to figure out the script, an "internal"
+# line of the form
+# b:0abx:1a2b3 :2 :3x2
+# has the following meaning: the material after the three markers :1, :2,
+# and :3 represents the three towers; in this case the current set-up is
+# ":ab : :x :". The numbers after a, b and x in these fields indicate
+# that the next time it gets a chance, it will move a to tower 2, move b
+# to tower 3, and move x to tower 2. The string after :0 just keeps track
+# of the alphabetical order of the names of the rings. The b at the
+# beginning means that it is now dealing with ring b (either about to move
+# it, or re-evaluating where it should next be moved to).
+#
+# Although this version is "limited" to 26 rings because of the size of the
+# alphabet, one could write a script using the same idea in which the rings
+# were represented by arbitrary [strings][within][brackets], and in place of
+# the built-in line of the script giving the order of the letters of the
+# alphabet, it would accept from the user a line giving the ordering to be
+# assumed, e.g. [ucbvax][decvax][hplabs][foo][bar].
+#
+# George Bergman
+# Math, UC Berkeley 94720 USA
+
+# cleaning, diagnostics
+s/ *//g
+/^$/d
+/[^a-z:]/{a\
+Illegal characters: use only a-z and ":". Try again.
+d
+}
+/^:[a-z]*:[a-z]*:[a-z]*:$/!{a\
+Incorrect format: use\
+\ : string1 : string2 : string3 :<CR>\
+Try again.
+d
+}
+/\([a-z]\).*\1/{a\
+Repeated letters not allowed. Try again.
+d
+}
+# initial formatting
+h
+s/[a-z]/ /g
+G
+s/^:\( *\):\( *\):\( *\):\n:\([a-z]*\):\([a-z]*\):\([a-z]*\):$/:1\4\2\3:2\5\1\3:3\6\1\2:0/
+s/[a-z]/&2/g
+s/^/abcdefghijklmnopqrstuvwxyz/
+:a
+s/^\(.\).*\1.*/&\1/
+s/.//
+/^[^:]/ba
+s/\([^0]*\)\(:0.*\)/\2\1:/
+s/^[^0]*0\(.\)/\1&/
+:b
+# outputting current state without markers
+h
+s/.*:1/:/
+s/[123]//gp
+g
+:c
+# establishing destinations
+/^\(.\).*\1:1/td
+/^\(.\).*:1[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/
+/^\(.\).*:1[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/
+/^\(.\).*:1[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/
+/^\(.\).*:2[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/
+/^\(.\).*:2[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/
+/^\(.\).*:2[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/
+/^\(.\).*:3[^:]*\11/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\32/
+/^\(.\).*:3[^:]*\12/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\31/
+/^\(.\).*:3[^:]*\13/s/^\(.\)\(.*\1\([a-z]\).*\)\3./\3\2\33/
+bc
+# iterate back to find smallest out-of-place ring
+:d
+s/^\(.\)\(:0[^:]*\([^:]\)\1.*:\([123]\)[^:]*\1\)\4/\3\2\4/
+td
+# move said ring (right, resp. left)
+s/^\(.\)\(.*\)\1\([23]\)\(.*:\3[^ ]*\) /\1\2 \4\1\3/
+s/^\(.\)\(.*:\([12]\)[^ ]*\) \(.*\)\1\3/\1\2\1\3\4 /
+tb
+s/.*/Done! Try another, or end with ^D./p
+d
diff --git a/text_cmds/sed/TEST/math.sed b/text_cmds/sed/TEST/math.sed
new file mode 100644
index 0000000..c3ecc64
--- /dev/null
+++ b/text_cmds/sed/TEST/math.sed
@@ -0,0 +1,439 @@
+# This is ksb's infamous sed calculator. (ksb@sa.fedex.com)
+#
+# $FreeBSD: src/usr.bin/sed/TEST/math.sed,v 1.2 2004/05/01 02:15:58 smkelly Exp $
+#
+# $Id: math.sed,v 2.5 1998/08/02 13:23:34 ksb Exp ksb $
+# expr ::= (expr) | expr! |
+# expr ^ expr |
+# -expr | expr * expr | expr / expr | expr % expr |
+# expr + expr | expr - expr |
+# [0-9][0-9]* ;
+# Bugs: some sign combinations don't work, and I got sick of added cases
+# for unary +. Don't depend on signed math working all the time. -- ksb
+#
+# $Compile: echo "4+7*3+2^7/3" | sed -f %f
+
+# make sure the expression is well formed
+s/[ ]//g
+/[*\/^%+-]$/{
+ a\
+ poorly formed expression, dyadic operator on the end
+ q
+}
+/^[*\/^%]/{
+ a\
+ poorly formed expression, leading dyadic operator
+ q
+}
+
+# fill hold space with done token
+x
+s/^.*/done/
+x
+
+# main loop, process operators ((), !, *, /, %, +, and -)
+: loop
+# uncomment the print below to follow the "logic" -- ksb
+#p
+/^[+]/{
+ s///
+ b loop
+}
+/^--/{
+ s///
+ b loop
+}
+# eval parenthesised sub expressions first
+/^\(.*\)(\([^)]*\))\(.*\)$/{
+ H
+ s//\2/
+ x
+ s/^\(.*\)\n\(.*\)(\([^()]*\))\(.*\)$/()\2@\4@\1/
+ x
+ b loop
+}
+# reduce a^b^c -> a^(b^c)
+/\([0-9][0-9]*^\)\([0-9][0-9]*^[0-9][0-9^]*\)/{
+ s//\1(\2)/
+ b loop
+}
+# pull any burried exponents
+/^\(.*[^0-9]\)\([0-9][0-9]*^[0-9][0-9]*\)$/{
+ s//\1(\2)/
+ b loop
+}
+/^\(.*[^0-9]\)\([0-9][0-9]*^[0-9][0-9]*\)\([^0-9].*\)$/{
+ s//\1(\2)\3/
+ b loop
+}
+/^\([0-9][0-9]*^[0-9][0-9]*\)\([^0-9].*\)$/{
+ s//(\1)\2/
+ b loop
+}
+/^\([-]*[0-9]*\)^0*$/{
+ s//1/
+ b loop
+}
+/^\([-]*[0-9]*\)^0*1$/{
+ s//\1/
+ b loop
+}
+/^\([-]*[0-9]*\)^-[0-9]*$/{
+ s//0/
+ b loop
+}
+/^\([-]*\)\([0-9]*\)^\([0-9][0-9]*[13579]\)$/{
+ s//\1\2*((\2*\2)^(\3\/2))/
+ b loop
+}
+/^[-]*\([0-9]*\)^\([0-9][0-9]*[02468]\)$/{
+ s//(\1*\1)^(\2\/2)/
+ b loop
+}
+# single digit powers (2 3,9 4,6,8 5,7
+/^[-]*\([0-9]*\)^0*2$/{
+ s//(\1*\1)/
+ b loop
+}
+/^\([-]*\)\([0-9]*\)^0*\([39]\)$/{
+ s//\1(\2*(\2*\2))^(\3\/3)/
+ b loop
+}
+/^[-]*\([0-9]*\)^0*\([468]\)$/{
+ s//(\1*\1)^(\2\/2)/
+ b loop
+}
+# 5 7
+/^\([-]*[0-9]*\)^\([0-9]*\)$/{
+ s//\1*(\1^(\2-1))/
+ b loop
+}
+# reduce all number factorials
+/^0*[01]!/{
+ s//1/
+ b loop
+}
+/\([*+-/%^]\)0*[01]!/{
+ s//\11/
+ b loop
+}
+/\([0-9]*\)!/{
+ s//(\1-1)!*\1/
+ b loop
+}
+# sign simplifications
+/^-\([0-9]*\)\([*/%]\)-\([0-9]*\)$/{
+ s//\1\2\3/
+ b loop
+}
+/^\([0-9]*\)\([*/%]\)-\([0-9]*\)$/{
+ s//-\1\2\3/
+ b loop
+}
+/^-\([0-9][0-9]*\)[+]*-\([0-9][0-9]*\)$/{
+ s//\1+\2/
+ x
+ s/\(.*\)/()-@@\1/
+ x
+ b loop
+}
+/^-\([0-9]*\)[+]\([0-9]\)*$/{
+ s//\2-\1/
+ b loop
+}
+/^-.*[-+*/%].*/{
+ H
+ s/^-//
+ x
+ s/^\(.*\)\n-.*$/()-@@\1/
+ x
+ b loop
+}
+# can we simplify multiplications
+/^\([0-9]*\)\([*][0-9]*[1-9]\)00*$/{
+ H
+ s//\1\2/
+ x
+ s/^\(.*\)\n[0-9]*[*][0-9]*[1-9]\(00*\)$/()@\2@\1/
+ x
+ b loop
+}
+/^\([0-9][1-9]*\)00*\([*][0-9]*\)$/{
+ H
+ s//\1\2/
+ x
+ s/^\(.*\)\n[0-9][1-9]*\(00*\)[*][0-9]*$/()@\2@\1/
+ x
+ b loop
+}
+# can we simplify division (20/30 -> 2/3)
+/^\([0-9][0-9]*\)0\([/%]\)\([0-9][0-9]*\)0$/{
+ s//\1\2\3/
+ b loop
+}
+# n/1 -> n
+/^0*\([0-9][0-9]*\)0[/]0*1$/{
+ s//\1/
+ b loop
+}
+# n%2 -> last_digit(n)%2 (same for 1, BTW) N.B. NO LOOP
+/^[0-9]*\([0-9]\)%0*\([12]\)$/{
+ s//\1%\2/
+}
+# move any mul/divs to the front via parans
+/^\([0-9+]*\)\([-+]\)\([0-9]*[*/][0-9*/]*\)/{
+ s//\1\2(\3)/
+ b loop
+}
+# can we div or mul
+/^[0-9]*[*][0-9]*$/{
+ b mul
+}
+/^[0-9]*[/%]0*$/{
+ i\
+divide by zero
+ d
+}
+/^[0-9]*[/%][0-9]*$/{
+ H
+ s/\([0-9]\).*[/%]/\1-/
+ x
+ s/^\(.*\)\n\([0-9]\)\([0-9]*\)\([/%]\)\([0-9]*\).*$/.\4\3q0r\2-\5@\1/
+ x
+ b loop
+}
+/^\([0-9]*[*/%][0-9]*\)\(.*\)/{
+ H
+ s//\1/
+ x
+ s/^\(.*\)\n\([0-9]*[*/][0-9]*\)\(.*\)$/()@\3@\1/
+ x
+ b loop
+}
+# can we add or subtract -- note subtract hold expression for underflow
+/^[0-9]*[+][0-9]*$/{
+ s/$/=/
+ b add
+}
+/^[0-9][0-9]*-[0-9]*$/{
+ H
+ s/$/=/
+ b sub
+}
+/^\([0-9][0-9]*[-+][0-9]*\)\(.*\)/{
+ H
+ s//\1/
+ x
+ s/^\(.*\)\n\([0-9]*[-+][0-9]*\)\(.*\)$/()@\3@\1/
+ x
+ b loop
+}
+# look in hold space for stack to reduce
+x
+/^done$/{
+ x
+ s/^0*\([0-9][0-9]*\)/\1/
+ p
+ d
+}
+# .[/%] numerator q quotient r remainder-divisor @stack
+/^\./{
+ x
+ /^[^-]/{
+ H
+ x
+ s/.\(.\)\([0-9]*\)q\([^r]*\)r\([0-9]*\)-\([0-9]*\)@\(.*\)\n\(.*\)/.\1\2q\3+1r\7-\5@\6/
+ h
+ s/..[0-9]*q[^r]*r\([0-9]*-[0-9]*\)@.*/\1/
+ b loop
+ }
+ /^-/{
+ g
+ /.\(.\)\([0-9]\)\([0-9]*\)q\([^r]*\)r0*\([0-9]*\)-\([^@]*\)@.*/{
+ s//\5\2-\6/
+ x
+ s/.\(.\)\([0-9]\)\([0-9]*\)q\([^r]*\)r0*\([0-9]*\)-\([0-9]*\)@\(.*\)/.\1\3q(\4)*10r\5\2-\6@\7/
+ x
+ b loop
+ }
+# no digits to shift on
+ s/^\.[/]q\([^r]*\)r[^@]*@.*/\1/
+ s/^\.[%]q[^r]*r0*\([0-9][0-9]*\)-[^@]*@.*/\1/
+ /^\./{
+ i\
+divide error
+ q
+ }
+ x
+ s/^\.[/%]q[^r]*r[^@]*@\(.*\)/\1/
+ x
+ b loop
+ }
+}
+/^()/{
+ s///
+ x
+ G
+ s/\(.*\)\n\([^@]*\)@\([^@]*\)@\(.*\)/\2\1\3/
+ x
+ s/[^@]*@[^@]*@\(.*\)/\1/
+ x
+ b loop
+}
+i\
+help, stack problem - the hold space
+p
+x
+i\
+and the pat space
+p
+i\
+quit
+q
+
+# turn mul into add until 1*x -> x, 0*x -> 0
+: mul
+/^00*\*.*/{
+ s//0/
+ b loop
+}
+/^0*1\*/{
+ s///
+: leading
+ s/^0*\([0-9][0-9]*\)/\1/
+ b loop
+}
+s/^\([0-9]*\)0\*\([0-9]*\)/\1*\20/
+s/^\([0-9]*\)1\*\([0-9]*\)/\1*\20+\2/
+s/^\([0-9]*\)2\*\([0-9]*\)/\1*\20+(\2+\2)/
+s/^\([0-9]*\)3\*\([0-9]*\)/\1*\20+(\2+\2+\2)/
+s/^\([0-9]*\)4\*\([0-9]*\)/\1*\20+(\2+\2+\2+\2)/
+s/^\([0-9]*\)5\*\([0-9]*\)/\1*\20+(\2+\2+\2+\2+\2)/
+s/^\([0-9]*\)6\*\([0-9]*\)/\1*\20+(\2+\2+\2+\2+\2+\2)/
+s/^\([0-9]*\)7\*\([0-9]*\)/\1*\20+(\2+\2+\2+\2+\2+\2+\2)/
+s/^\([0-9]*\)8\*\([0-9]*\)/\1*\20+(\2+\2+\2+\2+\2+\2+\2+\2)/
+s/^\([0-9]*\)9\*\([0-9]*\)/\1*\20+(\2+\2+\2+\2+\2+\2+\2+\2+\2)/
+/^0*\*[0-9]*[+]*\(.*\)/{
+ s//\1/
+ b loop
+}
+b mul
+
+# get rid of a plus term until 0+x -> x
+: add
+/^[+]\([0-9+*]*\)=/{
+ s//\1/
+ b leading
+}
+/^\([0-9*]*\)[+]=/{
+ s//\1/
+ b loop
+}
+/^\([0-9]*\)0[+]\([0-9]*\)\([0-9]\)=/{
+ s//\1+\2=\3/
+ b add
+}
+/^\([0-9]*\)\([0-9]\)[+]\([0-9]*\)0=/{
+ s//\1+\3=\2/
+ b add
+}
+s/^\([0-9]*\)1[+]/\10+/
+s/^\([0-9]*\)2[+]/\11+/
+s/^\([0-9]*\)3[+]/\12+/
+s/^\([0-9]*\)4[+]/\13+/
+s/^\([0-9]*\)5[+]/\14+/
+s/^\([0-9]*\)6[+]/\15+/
+s/^\([0-9]*\)7[+]/\16+/
+s/^\([0-9]*\)8[+]/\17+/
+s/^\([0-9]*\)9[+]/\18+/
+
+s/9=\([0-9]*\)$/_=\1/
+s/8=\([0-9]*\)$/9=\1/
+s/7=\([0-9]*\)$/8=\1/
+s/6=\([0-9]*\)$/7=\1/
+s/5=\([0-9]*\)$/6=\1/
+s/4=\([0-9]*\)$/5=\1/
+s/3=\([0-9]*\)$/4=\1/
+s/2=\([0-9]*\)$/3=\1/
+s/1=\([0-9]*\)$/2=\1/
+/_/{
+ s//_0/
+ : inc
+ s/9_/_0/
+ s/8_/9/
+ s/7_/8/
+ s/6_/7/
+ s/5_/6/
+ s/4_/5/
+ s/3_/4/
+ s/2_/3/
+ s/1_/2/
+ s/0_/1/
+ s/[+]_/+1/
+ /_/b inc
+}
+b add
+
+# get rid of a sub term until /-0*=/ or underflow
+: sub
+/^\([0-9]*\)-0*=/{
+ s//\1/
+ x
+ s/\(.*\)\n.*$/\1/
+ x
+ b leading
+}
+/^-\([0-9].*\)=/{
+: under
+ g
+ s/.*\n\([0-9]*\)-\([0-9]*\).*/-(\2-\1)/
+ x
+ s/\(.*\)\n.*/\1/
+ x
+ b loop
+}
+/^\([0-9]*\)\([0-9]\)-\([0-9]*\)0=/{
+ s//\1-\3=\2/
+ b sub
+}
+s/1=/0=/
+s/2=/1=/
+s/3=/2=/
+s/4=/3=/
+s/5=/4=/
+s/6=/5=/
+s/7=/6=/
+s/8=/7=/
+s/9=/8=/
+
+s/^\([0-9]*\)1-/\1_-/
+s/^\([0-9]*\)2-/\11-/
+s/^\([0-9]*\)3-/\12-/
+s/^\([0-9]*\)4-/\13-/
+s/^\([0-9]*\)5-/\14-/
+s/^\([0-9]*\)6-/\15-/
+s/^\([0-9]*\)7-/\16-/
+s/^\([0-9]*\)8-/\17-/
+s/^\([0-9]*\)9-/\18-/
+s/^\([0-9]*\)0-/\1'9-/
+s/_/0/
+
+: scarry
+/0'/{
+ s//'9/
+ b scarry
+}
+/^'/{
+ b under
+}
+s/1'/0/
+s/2'/1/
+s/3'/2/
+s/4'/3/
+s/5'/4/
+s/6'/5/
+s/7'/6/
+s/8'/7/
+s/9'/8/
+
+b sub
diff --git a/text_cmds/sed/TEST/sed.test b/text_cmds/sed/TEST/sed.test
new file mode 100644
index 0000000..8017a61
--- /dev/null
+++ b/text_cmds/sed/TEST/sed.test
@@ -0,0 +1,556 @@
+#!/bin/sh -
+#
+# Copyright (c) 1992 Diomidis Spinellis.
+# Copyright (c) 1992, 1993
+# The Regents of the University of California. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# @(#)sed.test 8.1 (Berkeley) 6/6/93
+#
+# $FreeBSD: src/usr.bin/sed/TEST/sed.test,v 1.4 2004/08/09 15:29:41 dds Exp $
+#
+
+# sed Regression Tests
+#
+# The following files are created:
+# lines[1-4], script1, script2
+# Two directories *.out contain the test results
+
+main()
+{
+ BASE=/usr/bin/sed
+ BASELOG=sed.out
+ TEST=`cd ..; make whereobj`/sed
+ TESTLOG=nsed.out
+ DICT=/usr/share/dict/words
+
+ test_error | more
+
+ awk 'END { for (i = 1; i < 15; i++) print "l1_" i}' </dev/null >lines1
+ awk 'END { for (i = 1; i < 10; i++) print "l2_" i}' </dev/null >lines2
+
+ exec 4>&1 5>&2
+
+ # Set these flags to get messages about known problems
+ BSD=1
+ GNU=0
+ SUN=0
+ tests $BASE $BASELOG
+
+ BSD=0
+ GNU=0
+ SUN=0
+ tests $TEST $TESTLOG
+ exec 1>&4 2>&5
+ diff -c $BASELOG $TESTLOG | more
+}
+
+tests()
+{
+ SED=$1
+ DIR=$2
+ rm -rf $DIR
+ mkdir $DIR
+ MARK=100
+
+ test_args
+ test_addr
+ echo Testing commands
+ test_group
+ test_acid
+ test_branch
+ test_pattern
+ test_print
+ test_subst
+}
+
+mark()
+{
+ MARK=`expr $MARK + 1`
+ exec 1>&4 2>&5
+ exec >"$DIR/${MARK}_$1"
+ echo "Test $1:$MARK"
+ # Uncomment this line to match tests with sed error messages
+ echo "Test $1:$MARK" >&5
+}
+
+test_args()
+{
+ mark '1.1'
+ echo Testing argument parsing
+ echo First type
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED 's/^/e1_/p' lines1
+ fi
+ mark '1.2' ; $SED -n 's/^/e1_/p' lines1
+ mark '1.3'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED 's/^/e1_/p' <lines1
+ fi
+ mark '1.4' ; $SED -n 's/^/e1_/p' <lines1
+ echo Second type
+ mark '1.4.1'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed fails this
+ fi
+ $SED -e '' <lines1
+ echo 's/^/s1_/p' >script1
+ echo 's/^/s2_/p' >script2
+ mark '1.5'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED -f script1 lines1
+ fi
+ mark '1.6'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED -f script1 <lines1
+ fi
+ mark '1.7'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED -e 's/^/e1_/p' lines1
+ fi
+ mark '1.8'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED -e 's/^/e1_/p' <lines1
+ fi
+ mark '1.9' ; $SED -n -f script1 lines1
+ mark '1.10' ; $SED -n -f script1 <lines1
+ mark '1.11' ; $SED -n -e 's/^/e1_/p' lines1
+ mark '1.12'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED -n -e 's/^/e1_/p' <lines1
+ fi
+ mark '1.13'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED -e 's/^/e1_/p' -e 's/^/e2_/p' lines1
+ fi
+ mark '1.14'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED -f script1 -f script2 lines1
+ fi
+ mark '1.15'
+ if [ $GNU -eq 1 -o $SUN -eq 1 ] ; then
+ echo GNU and SunOS sed fail this following older POSIX draft
+ else
+ $SED -e 's/^/e1_/p' -f script1 lines1
+ fi
+ mark '1.16'
+ if [ $SUN -eq 1 ] ; then
+ echo SunOS sed prints only with -n
+ else
+ $SED -e 's/^/e1_/p' lines1 lines1
+ fi
+ # POSIX D11.2:11251
+ mark '1.17' ; $SED p <lines1 lines1
+cat >script1 <<EOF
+#n
+# A comment
+
+p
+EOF
+ mark '1.18' ; $SED -f script1 <lines1 lines1
+}
+
+test_addr()
+{
+ echo Testing address ranges
+ mark '2.1' ; $SED -n -e '4p' lines1
+ mark '2.2' ; $SED -n -e '20p' lines1 lines2
+ mark '2.3' ; $SED -n -e '$p' lines1
+ mark '2.4' ; $SED -n -e '$p' lines1 lines2
+ mark '2.5' ; $SED -n -e '$a\
+hello' /dev/null
+ mark '2.6' ; $SED -n -e '$p' lines1 /dev/null lines2
+ # Should not print anything
+ mark '2.7' ; $SED -n -e '20p' lines1
+ mark '2.8' ; $SED -n -e '0p' lines1
+ mark '2.9' ; $SED -n '/l1_7/p' lines1
+ mark '2.10' ; $SED -n ' /l1_7/ p' lines1
+ mark '2.11'
+ if [ $BSD -eq 1 ] ; then
+ echo BSD sed fails this test
+ fi
+ if [ $GNU -eq 1 ] ; then
+ echo GNU sed fails this
+ fi
+ $SED -n '\_l1\_7_p' lines1
+ mark '2.12' ; $SED -n '1,4p' lines1
+ mark '2.13' ; $SED -n '1,$p' lines1 lines2
+ mark '2.14' ; $SED -n '1,/l2_9/p' lines1 lines2
+ mark '2.15' ; $SED -n '/4/,$p' lines1 lines2
+ mark '2.16' ; $SED -n '/4/,20p' lines1 lines2
+ mark '2.17' ; $SED -n '/4/,/10/p' lines1 lines2
+ mark '2.18' ; $SED -n '/l2_3/,/l1_8/p' lines1 lines2
+ mark '2.19'
+ if [ $GNU -eq 1 ] ; then
+ echo GNU sed fails this
+ fi
+ $SED -n '12,3p' lines1 lines2
+ mark '2.20'
+ if [ $GNU -eq 1 ] ; then
+ echo GNU sed fails this
+ fi
+ $SED -n '/l1_7/,3p' lines1 lines2
+}
+
+test_group()
+{
+ echo Brace and other grouping
+ mark '3.1' ; $SED -e '
+4,12 {
+ s/^/^/
+ s/$/$/
+ s/_/T/
+}' lines1
+ mark '3.2' ; $SED -e '
+4,12 {
+ s/^/^/
+ /6/,/10/ {
+ s/$/$/
+ /8/ s/_/T/
+ }
+}' lines1
+ mark '3.3' ; $SED -e '
+4,12 !{
+ s/^/^/
+ /6/,/10/ !{
+ s/$/$/
+ /8/ !s/_/T/
+ }
+}' lines1
+ mark '3.4' ; $SED -e '4,12!s/^/^/' lines1
+}
+
+test_acid()
+{
+ echo Testing a c d and i commands
+ mark '4.1' ; $SED -n -e '
+s/^/before_i/p
+20i\
+inserted
+s/^/after_i/p
+' lines1 lines2
+ mark '4.2' ; $SED -n -e '
+5,12s/^/5-12/
+s/^/before_a/p
+/5-12/a\
+appended
+s/^/after_a/p
+' lines1 lines2
+ mark '4.3'
+ if [ $GNU -eq 1 ] ; then
+ echo GNU sed fails this
+ fi
+ $SED -n -e '
+s/^/^/p
+/l1_/a\
+appended
+8,10N
+s/$/$/p
+' lines1 lines2
+ mark '4.4' ; $SED -n -e '
+c\
+hello
+' lines1
+ mark '4.5' ; $SED -n -e '
+8c\
+hello
+' lines1
+ mark '4.6' ; $SED -n -e '
+3,14c\
+hello
+' lines1
+# SunOS and GNU sed behave differently. We follow POSIX
+# mark '4.7' ; $SED -n -e '
+#8,3c\
+#hello
+#' lines1
+ mark '4.8' ; $SED d <lines1
+}
+
+test_branch()
+{
+ echo Testing labels and branching
+ mark '5.1' ; $SED -n -e '
+b label4
+:label3
+s/^/label3_/p
+b end
+:label4
+2,12b label1
+b label2
+:label1
+s/^/label1_/p
+b
+:label2
+s/^/label2_/p
+b label3
+:end
+' lines1
+ mark '5.2'
+ if [ $BSD -eq 1 ] ; then
+ echo BSD sed fails this test
+ fi
+ $SED -n -e '
+s/l1_/l2_/
+t ok
+b
+:ok
+s/^/tested /p
+' lines1 lines2
+# SunOS sed behaves differently here. Clarification needed.
+# mark '5.3' ; $SED -n -e '
+#5,8b inside
+#1,5 {
+# s/^/^/p
+# :inside
+# s/$/$/p
+#}
+#' lines1
+# Check that t clears the substitution done flag
+ mark '5.4' ; $SED -n -e '
+1,8s/^/^/
+t l1
+:l1
+t l2
+s/$/$/p
+b
+:l2
+s/^/ERROR/
+' lines1
+# Check that reading a line clears the substitution done flag
+ mark '5.5'
+ if [ $BSD -eq 1 ] ; then
+ echo BSD sed fails this test
+ fi
+ $SED -n -e '
+t l2
+1,8s/^/^/p
+2,7N
+b
+:l2
+s/^/ERROR/p
+' lines1
+ mark '5.6' ; $SED 5q lines1
+ mark '5.7' ; $SED -e '
+5i\
+hello
+5q' lines1
+# Branch across block boundary
+ mark '5.8' ; $SED -e '
+{
+:b
+}
+s/l/m/
+tb' lines1
+}
+
+test_pattern()
+{
+echo Pattern space commands
+# Check that the pattern space is deleted
+ mark '6.1' ; $SED -n -e '
+c\
+changed
+p
+' lines1
+ mark '6.2' ; $SED -n -e '
+4d
+p
+' lines1
+# SunOS sed refused to print here
+# mark '6.3' ; $SED -e '
+#N
+#N
+#N
+#D
+#P
+#4p
+#' lines1
+ mark '6.4' ; $SED -e '
+2h
+3H
+4g
+5G
+6x
+6p
+6x
+6p
+' lines1
+ mark '6.5' ; $SED -e '4n' lines1
+ mark '6.6' ; $SED -n -e '4n' lines1
+}
+
+test_print()
+{
+ echo Testing print and file routines
+ awk 'END {for (i = 1; i < 256; i++) printf("%c", i);print "\n"}' \
+ </dev/null >lines3
+ # GNU and SunOS sed behave differently here
+ mark '7.1'
+ $SED -n l lines3
+ mark '7.2' ; $SED -e '/l2_/=' lines1 lines2
+ rm -f lines4
+ mark '7.3' ; $SED -e '3,12w lines4' lines1
+ echo w results
+ cat lines4
+ mark '7.4' ; $SED -e '4r lines2' lines1
+ mark '7.5' ; $SED -e '5r /dev/dds' lines1
+ mark '7.6' ; $SED -e '6r /dev/null' lines1
+ mark '7.7'
+ if [ $BSD -eq 1 -o $GNU -eq 1 -o $SUN -eq 1 ] ; then
+ echo BSD, GNU and SunOS cannot pass this one
+ else
+ sed '200q' $DICT | sed 's$.*$s/^/&/w tmpdir/&$' >script1
+ rm -rf tmpdir
+ mkdir tmpdir
+ $SED -f script1 lines1
+ cat tmpdir/*
+ rm -rf tmpdir
+ fi
+ mark '7.8'
+ if [ $BSD -eq 1 ] ; then
+ echo BSD sed cannot pass 7.7
+ else
+ echo line1 > lines3
+ echo "" >> lines3
+ $SED -n -e '$p' lines3 /dev/null
+ fi
+
+}
+
+test_subst()
+{
+ echo Testing substitution commands
+ mark '8.1' ; $SED -e 's/./X/g' lines1
+ mark '8.2' ; $SED -e 's,.,X,g' lines1
+# GNU and SunOS sed thinks we are escaping . as wildcard, not as separator
+# mark '8.3' ; $SED -e 's.\..X.g' lines1
+# POSIX does not say that this should work
+# mark '8.4' ; $SED -e 's/[/]/Q/' lines1
+ mark '8.4' ; $SED -e 's/[\/]/Q/' lines1
+ mark '8.5' ; $SED -e 's_\__X_' lines1
+ mark '8.6' ; $SED -e 's/./(&)/g' lines1
+ mark '8.7' ; $SED -e 's/./(\&)/g' lines1
+ mark '8.8' ; $SED -e 's/\(.\)\(.\)\(.\)/x\3x\2x\1/g' lines1
+ mark '8.9' ; $SED -e 's/_/u0\
+u1\
+u2/g' lines1
+ mark '8.10'
+ if [ $BSD -eq 1 -o $GNU -eq 1 ] ; then
+ echo 'BSD/GNU sed do not understand digit flags on s commands'
+ fi
+ $SED -e 's/./X/4' lines1
+ rm -f lines4
+ mark '8.11' ; $SED -e 's/1/X/w lines4' lines1
+ echo s wfile results
+ cat lines4
+ mark '8.12' ; $SED -e 's/[123]/X/g' lines1
+ mark '8.13' ; $SED -e 'y/0123456789/9876543210/' lines1
+ mark '8.14' ;
+ if [ $BSD -eq 1 -o $GNU -eq 1 -o $SUN -eq 1 ] ; then
+ echo BSD/GNU/SUN sed fail this test
+ else
+ $SED -e 'y10\123456789198765432\101' lines1
+ fi
+ mark '8.15' ; $SED -e '1N;2y/\n/X/' lines1
+ mark '8.16'
+ echo 'eeefff' | $SED -e '
+ p
+ s/e/X/p
+ :x
+ s//Y/p
+ # Establish limit counter in the hold space
+ # GNU sed version 3.02 enters into an infinite loop here
+ x
+ /.\{10\}/ {
+ s/.*/ERROR/
+ b
+ }
+ s/.*/&./
+ x
+ /f/bx
+ '
+}
+
+test_error()
+{
+ exec 0>&3 4>&1 5>&2
+ exec 0</dev/null
+ exec 2>&1
+ set -x
+ $TEST -x && exit 1
+ $TEST -f && exit 1
+ $TEST -e && exit 1
+ $TEST -f /dev/dds && exit 1
+ $TEST p /dev/dds && exit 1
+ $TEST -f /bin/sh && exit 1
+ $TEST '{' && exit 1
+ $TEST '{' && exit 1
+ $TEST '/hello/' && exit 1
+ $TEST '1,/hello/' && exit 1
+ $TEST -e '-5p' && exit 1
+ $TEST '/jj' && exit 1
+ $TEST 'a hello' && exit 1
+ $TEST 'a \ hello' && exit 1
+ $TEST 'b foo' && exit 1
+ $TEST 'd hello' && exit 1
+ $TEST 's/aa' && exit 1
+ $TEST 's/aa/' && exit 1
+ $TEST 's/a/b' && exit 1
+ $TEST 's/a/b/c/d' && exit 1
+ $TEST 's/a/b/ 1 2' && exit 1
+ $TEST 's/a/b/ 1 g' && exit 1
+ $TEST 's/a/b/w' && exit 1
+ $TEST 'y/aa' && exit 1
+ $TEST 'y/aa/b/' && exit 1
+ $TEST 'y/aa/' && exit 1
+ $TEST 'y/a/b' && exit 1
+ $TEST 'y/a/b/c/d' && exit 1
+ $TEST '!' && exit 1
+ $TEST supercalifrangolisticexprialidociussupercalifrangolisticexcius
+ set +x
+ exec 0>&3 1>&4 2>&5
+}
+
+main
diff --git a/text_cmds/sed/compile.c b/text_cmds/sed/compile.c
new file mode 100644
index 0000000..fbd19fa
--- /dev/null
+++ b/text_cmds/sed/compile.c
@@ -0,0 +1,987 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)compile.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "defs.h"
+#include "extern.h"
+
+#define LHSZ 128
+#define LHMASK (LHSZ - 1)
+static struct labhash {
+ struct labhash *lh_next;
+ u_int lh_hash;
+ struct s_command *lh_cmd;
+ int lh_ref;
+} *labels[LHSZ];
+
+static char *compile_addr(char *, struct s_addr *);
+static char *compile_ccl(char **, char *);
+static char *compile_delimited(char *, char *, int);
+static char *compile_flags(char *, struct s_subst *);
+static regex_t *compile_re(char *, int);
+static char *compile_subst(char *, struct s_subst *);
+static char *compile_text(void);
+static char *compile_tr(char *, struct s_tr **);
+static struct s_command
+ **compile_stream(struct s_command **);
+static char *duptoeol(char *, const char *);
+static void enterlabel(struct s_command *);
+static struct s_command
+ *findlabel(char *);
+static void fixuplabel(struct s_command *, struct s_command *);
+static void uselabel(void);
+
+/*
+ * Command specification. This is used to drive the command parser.
+ */
+struct s_format {
+ char code; /* Command code */
+ int naddr; /* Number of address args */
+ enum e_args args; /* Argument type */
+};
+
+static struct s_format cmd_fmts[] = {
+ {'{', 2, GROUP},
+ {'}', 0, ENDGROUP},
+ {'a', 1, TEXT},
+ {'b', 2, BRANCH},
+ {'c', 2, TEXT},
+ {'d', 2, EMPTY},
+ {'D', 2, EMPTY},
+ {'g', 2, EMPTY},
+ {'G', 2, EMPTY},
+ {'h', 2, EMPTY},
+ {'H', 2, EMPTY},
+ {'i', 1, TEXT},
+ {'l', 2, EMPTY},
+ {'n', 2, EMPTY},
+ {'N', 2, EMPTY},
+ {'p', 2, EMPTY},
+ {'P', 2, EMPTY},
+ {'q', 1, EMPTY},
+ {'r', 1, RFILE},
+ {'s', 2, SUBST},
+ {'t', 2, BRANCH},
+ {'w', 2, WFILE},
+ {'x', 2, EMPTY},
+ {'y', 2, TR},
+ {'!', 2, NONSEL},
+ {':', 0, LABEL},
+ {'#', 0, COMMENT},
+ {'=', 1, EMPTY},
+ {'\0', 0, COMMENT},
+};
+
+/* The compiled program. */
+struct s_command *prog;
+
+/*
+ * Compile the program into prog.
+ * Initialise appends.
+ */
+void
+compile(void)
+{
+ *compile_stream(&prog) = NULL;
+ fixuplabel(prog, NULL);
+ uselabel();
+ if (appendnum == 0)
+ appends = NULL;
+ else if ((appends = malloc(sizeof(struct s_appends) * appendnum)) ==
+ NULL)
+ err(1, "malloc");
+ if ((match = malloc((maxnsub + 1) * sizeof(regmatch_t))) == NULL)
+ err(1, "malloc");
+}
+
+#define EATSPACE() do { \
+ if (p) \
+ while (*p && isspace((unsigned char)*p)) \
+ p++; \
+ } while (0)
+
+static struct s_command **
+compile_stream(struct s_command **link)
+{
+ char *p;
+ static char lbuf[_POSIX2_LINE_MAX + 1]; /* To save stack */
+ struct s_command *cmd, *cmd2, *stack;
+ struct s_format *fp;
+ char re[_POSIX2_LINE_MAX + 1];
+ int naddr; /* Number of addresses */
+
+ stack = NULL;
+ for (;;) {
+ if ((p = cu_fgets(lbuf, sizeof(lbuf), NULL)) == NULL) {
+ if (stack != NULL)
+ errx(1, "%lu: %s: unexpected EOF (pending }'s)",
+ linenum, fname);
+ return (link);
+ }
+
+semicolon: EATSPACE();
+ if (p) {
+ if (*p == '#' || *p == '\0')
+ continue;
+ else if (*p == ';') {
+ p++;
+ goto semicolon;
+ }
+ }
+ if ((*link = cmd = malloc(sizeof(struct s_command))) == NULL)
+ err(1, "malloc");
+ link = &cmd->next;
+ cmd->startline = cmd->nonsel = 0;
+ /* First parse the addresses */
+ naddr = 0;
+
+/* Valid characters to start an address */
+#define addrchar(c) (strchr("0123456789/\\$", (c)))
+ if (addrchar(*p)) {
+ naddr++;
+ if ((cmd->a1 = malloc(sizeof(struct s_addr))) == NULL)
+ err(1, "malloc");
+ p = compile_addr(p, cmd->a1);
+ EATSPACE(); /* EXTENSION */
+ if (*p == ',') {
+ p++;
+ EATSPACE(); /* EXTENSION */
+ naddr++;
+ if ((cmd->a2 = malloc(sizeof(struct s_addr)))
+ == NULL)
+ err(1, "malloc");
+ p = compile_addr(p, cmd->a2);
+ EATSPACE();
+ } else
+ cmd->a2 = NULL;
+ } else
+ cmd->a1 = cmd->a2 = NULL;
+
+nonsel: /* Now parse the command */
+ if (!*p)
+ errx(1, "%lu: %s: command expected", linenum, fname);
+ cmd->code = *p;
+ for (fp = cmd_fmts; fp->code; fp++)
+ if (fp->code == *p)
+ break;
+ if (!fp->code)
+ errx(1, "%lu: %s: invalid command code %c", linenum, fname, *p);
+ if (naddr > fp->naddr)
+ errx(1,
+ "%lu: %s: command %c expects up to %d address(es), found %d",
+ linenum, fname, *p, fp->naddr, naddr);
+ switch (fp->args) {
+ case NONSEL: /* ! */
+ p++;
+ EATSPACE();
+ cmd->nonsel = 1;
+ goto nonsel;
+ case GROUP: /* { */
+ p++;
+ EATSPACE();
+ cmd->next = stack;
+ stack = cmd;
+ link = &cmd->u.c;
+ if (*p)
+ goto semicolon;
+ break;
+ case ENDGROUP:
+ /*
+ * Short-circuit command processing, since end of
+ * group is really just a noop.
+ */
+ cmd->nonsel = 1;
+ if (stack == NULL)
+ errx(1, "%lu: %s: unexpected }", linenum, fname);
+ cmd2 = stack;
+ stack = cmd2->next;
+ cmd2->next = cmd;
+ /*FALLTHROUGH*/
+ case EMPTY: /* d D g G h H l n N p P q x = \0 */
+ p++;
+ EATSPACE();
+ if (*p == ';') {
+ p++;
+ link = &cmd->next;
+ goto semicolon;
+ }
+ if (*p)
+ errx(1, "%lu: %s: extra characters at the end of %c command",
+ linenum, fname, cmd->code);
+ break;
+ case TEXT: /* a c i */
+ p++;
+ EATSPACE();
+ if (*p != '\\')
+ errx(1,
+"%lu: %s: command %c expects \\ followed by text", linenum, fname, cmd->code);
+ p++;
+ EATSPACE();
+ if (*p)
+ errx(1,
+ "%lu: %s: extra characters after \\ at the end of %c command",
+ linenum, fname, cmd->code);
+ cmd->t = compile_text();
+ break;
+ case COMMENT: /* \0 # */
+ break;
+ case WFILE: /* w */
+ p++;
+ EATSPACE();
+ if (*p == '\0')
+ errx(1, "%lu: %s: filename expected", linenum, fname);
+ cmd->t = duptoeol(p, "w command");
+ if (aflag)
+ cmd->u.fd = -1;
+ else if ((cmd->u.fd = open(p,
+ O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
+ DEFFILEMODE)) == -1)
+ err(1, "%s", p);
+ break;
+ case RFILE: /* r */
+ p++;
+ EATSPACE();
+ if (*p == '\0')
+ errx(1, "%lu: %s: filename expected", linenum, fname);
+ else
+ cmd->t = duptoeol(p, "read command");
+ break;
+ case BRANCH: /* b t */
+ p++;
+ EATSPACE();
+ if (*p == '\0')
+ cmd->t = NULL;
+ else
+ cmd->t = duptoeol(p, "branch");
+ break;
+ case LABEL: /* : */
+ p++;
+ EATSPACE();
+ cmd->t = duptoeol(p, "label");
+ if (strlen(p) == 0)
+ errx(1, "%lu: %s: empty label", linenum, fname);
+ enterlabel(cmd);
+ break;
+ case SUBST: /* s */
+ p++;
+ if (*p == '\0' || *p == '\\')
+ errx(1,
+"%lu: %s: substitute pattern can not be delimited by newline or backslash",
+ linenum, fname);
+ if ((cmd->u.s = calloc(1, sizeof(struct s_subst))) == NULL)
+ err(1, "malloc");
+ p = compile_delimited(p, re, 0);
+ if (p == NULL)
+ errx(1,
+ "%lu: %s: unterminated substitute pattern", linenum, fname);
+
+ /* Compile RE with no case sensitivity temporarily */
+ if (*re == '\0')
+ cmd->u.s->re = NULL;
+ else
+ cmd->u.s->re = compile_re(re, 0);
+ --p;
+ p = compile_subst(p, cmd->u.s);
+ p = compile_flags(p, cmd->u.s);
+
+ /* Recompile RE with case sensitivity from "I" flag if any */
+ if (*re == '\0')
+ cmd->u.s->re = NULL;
+ else
+ cmd->u.s->re = compile_re(re, cmd->u.s->icase);
+ EATSPACE();
+ if (*p == ';') {
+ p++;
+ link = &cmd->next;
+ goto semicolon;
+ }
+ break;
+ case TR: /* y */
+ p++;
+ p = compile_tr(p, &cmd->u.y);
+ EATSPACE();
+ if (*p == ';') {
+ p++;
+ link = &cmd->next;
+ goto semicolon;
+ }
+ if (*p)
+ errx(1,
+"%lu: %s: extra text at the end of a transform command", linenum, fname);
+ break;
+ }
+ }
+}
+
+/*
+ * Get a delimited string. P points to the delimiter of the string; d points
+ * to a buffer area. Newline and delimiter escapes are processed; other
+ * escapes are ignored.
+ *
+ * Returns a pointer to the first character after the final delimiter or NULL
+ * in the case of a non-terminated string. The character array d is filled
+ * with the processed string.
+ */
+static char *
+compile_delimited(char *p, char *d, int is_tr)
+{
+ char c;
+
+ c = *p++;
+ if (c == '\0')
+ return (NULL);
+ else if (c == '\\')
+ errx(1, "%lu: %s: \\ can not be used as a string delimiter",
+ linenum, fname);
+ else if (c == '\n')
+ errx(1, "%lu: %s: newline can not be used as a string delimiter",
+ linenum, fname);
+ while (*p) {
+ if (*p == '[' && *p != c) {
+ if ((d = compile_ccl(&p, d)) == NULL)
+ errx(1, "%lu: %s: unbalanced brackets ([])", linenum, fname);
+ continue;
+ } else if (*p == '\\' && p[1] == '[') {
+ *d++ = *p++;
+ } else if (*p == '\\' && p[1] == c) {
+ p++;
+ } else if (*p == '\\' &&
+ (p[1] == 'n' || p[1] == 'r' || p[1] == 't')) {
+ switch (p[1]) {
+ case 'n':
+ *d++ = '\n';
+ break;
+ case 'r':
+ *d++ = '\r';
+ break;
+ case 't':
+ *d++ = '\t';
+ break;
+ }
+ p += 2;
+ continue;
+ } else if (*p == '\\' && p[1] == '\\') {
+ if (is_tr)
+ p++;
+ else
+ *d++ = *p++;
+ } else if (*p == c) {
+ *d = '\0';
+ return (p + 1);
+ }
+ *d++ = *p++;
+ }
+ return (NULL);
+}
+
+
+/* compile_ccl: expand a POSIX character class */
+static char *
+compile_ccl(char **sp, char *t)
+{
+ int c, d;
+ char *s = *sp;
+
+ *t++ = *s++;
+ if (*s == '^')
+ *t++ = *s++;
+ if (*s == ']')
+ *t++ = *s++;
+ for (; *s && (*t = *s) != ']'; s++, t++) {
+ if (*s == '[' && ((d = *(s+1)) == '.' || d == ':' || d == '=')) {
+ *++t = *++s, t++, s++;
+ for (c = *s; (*t = *s) != ']' || c != d; s++, t++)
+ if ((c = *s) == '\0')
+ return NULL;
+ }
+ /*
+ * Apple Note: FreeBSD treats the backslash character as the start of
+ * several possible escape sequences here, but this is not POSIX-
+ * compliant. See XBD 9.3.3: "The period, left-bracket, and backslash
+ * shall be special except when used in a bracket expression".
+ */
+ }
+ return (*s == ']') ? *sp = ++s, ++t : NULL;
+}
+
+/*
+ * Compiles the regular expression in RE and returns a pointer to the compiled
+ * regular expression.
+ * Cflags are passed to regcomp.
+ */
+static regex_t *
+compile_re(char *re, int case_insensitive)
+{
+ regex_t *rep;
+ int eval, flags;
+
+
+ flags = rflags;
+ if (case_insensitive)
+ flags |= REG_ICASE;
+ if ((rep = malloc(sizeof(regex_t))) == NULL)
+ err(1, "malloc");
+ if ((eval = regcomp(rep, re, flags)) != 0)
+ errx(1, "%lu: %s: RE error: %s",
+ linenum, fname, strregerror(eval, rep));
+ if (maxnsub < rep->re_nsub)
+ maxnsub = rep->re_nsub;
+ return (rep);
+}
+
+/*
+ * Compile the substitution string of a regular expression and set res to
+ * point to a saved copy of it. Nsub is the number of parenthesized regular
+ * expressions.
+ */
+static char *
+compile_subst(char *p, struct s_subst *s)
+{
+ static char lbuf[_POSIX2_LINE_MAX + 1];
+ int asize, size;
+ u_char ref;
+ char c, *text, *op, *sp;
+ int more = 1, sawesc = 0;
+
+ c = *p++; /* Terminator character */
+ if (c == '\0')
+ return (NULL);
+
+ s->maxbref = 0;
+ s->linenum = linenum;
+ asize = 2 * _POSIX2_LINE_MAX + 1;
+ if ((text = malloc(asize)) == NULL)
+ err(1, "malloc");
+ size = 0;
+ do {
+ op = sp = text + size;
+ for (; *p; p++) {
+ if (*p == '\\' || sawesc) {
+ /*
+ * If this is a continuation from the last
+ * buffer, we won't have a character to
+ * skip over.
+ */
+ if (sawesc)
+ sawesc = 0;
+ else
+ p++;
+
+ if (*p == '\0') {
+ /*
+ * This escaped character is continued
+ * in the next part of the line. Note
+ * this fact, then cause the loop to
+ * exit w/ normal EOL case and reenter
+ * above with the new buffer.
+ */
+ sawesc = 1;
+ p--;
+ continue;
+ } else if (strchr("123456789", *p) != NULL) {
+ *sp++ = '\\';
+ ref = *p - '0';
+ if (s->re != NULL &&
+ ref > s->re->re_nsub)
+ errx(1, "%lu: %s: \\%c not defined in the RE",
+ linenum, fname, *p);
+ if (s->maxbref < ref)
+ s->maxbref = ref;
+ } else {
+ switch (*p) {
+ case '&':
+ case '\\':
+ *sp++ = '\\';
+ break;
+ case 'n':
+ *p = '\n';
+ break;
+ case 'r':
+ *p = '\r';
+ break;
+ case 't':
+ *p = '\t';
+ break;
+ }
+ }
+ } else if (*p == c) {
+ if (*++p == '\0' && more) {
+ if (cu_fgets(lbuf, sizeof(lbuf), &more))
+ p = lbuf;
+ }
+ *sp++ = '\0';
+ size += sp - op;
+ if ((s->new = realloc(text, size)) == NULL)
+ err(1, "realloc");
+ return (p);
+ } else if (*p == '\n') {
+ errx(1,
+"%lu: %s: unescaped newline inside substitute pattern", linenum, fname);
+ /* NOTREACHED */
+ }
+ *sp++ = *p;
+ }
+ size += sp - op;
+ if (asize - size < _POSIX2_LINE_MAX + 1) {
+ asize *= 2;
+ if ((text = realloc(text, asize)) == NULL)
+ err(1, "realloc");
+ }
+ } while (cu_fgets(p = lbuf, sizeof(lbuf), &more) != NULL);
+ errx(1, "%lu: %s: unterminated substitute in regular expression",
+ linenum, fname);
+ /* NOTREACHED */
+}
+
+/*
+ * Compile the flags of the s command
+ */
+static char *
+compile_flags(char *p, struct s_subst *s)
+{
+ int gn; /* True if we have seen g or n */
+ unsigned long nval;
+ char wfile[_POSIX2_LINE_MAX + 1], *q, *eq;
+
+ s->n = 1; /* Default */
+ s->p = 0;
+ s->wfile = NULL;
+ s->wfd = -1;
+ s->icase = 0;
+ for (gn = 0;;) {
+ EATSPACE(); /* EXTENSION */
+ switch (*p) {
+ case 'g':
+ if (gn)
+ errx(1,
+"%lu: %s: more than one number or 'g' in substitute flags", linenum, fname);
+ gn = 1;
+ s->n = 0;
+ break;
+ case '\0':
+ case '\n':
+ case ';':
+ return (p);
+ case 'p':
+ s->p = 1;
+ break;
+ case 'i':
+ case 'I':
+ s->icase = 1;
+ break;
+ case '1': case '2': case '3':
+ case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ if (gn)
+ errx(1,
+"%lu: %s: more than one number or 'g' in substitute flags", linenum, fname);
+ gn = 1;
+ errno = 0;
+ nval = strtol(p, &p, 10);
+ if (errno == ERANGE || nval > INT_MAX)
+ errx(1,
+"%lu: %s: overflow in the 'N' substitute flag", linenum, fname);
+ s->n = nval;
+ p--;
+ break;
+ case 'w':
+ p++;
+#ifdef HISTORIC_PRACTICE
+ if (*p != ' ') {
+ warnx("%lu: %s: space missing before w wfile", linenum, fname);
+ return (p);
+ }
+#endif
+ EATSPACE();
+ q = wfile;
+ eq = wfile + sizeof(wfile) - 1;
+ while (*p) {
+ if (*p == '\n')
+ break;
+ if (q >= eq)
+ err(1, "wfile too long");
+ *q++ = *p++;
+ }
+ *q = '\0';
+ if (q == wfile)
+ errx(1, "%lu: %s: no wfile specified", linenum, fname);
+ s->wfile = strdup(wfile);
+ if (!aflag && (s->wfd = open(wfile,
+ O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
+ DEFFILEMODE)) == -1)
+ err(1, "%s", wfile);
+ return (p);
+ default:
+ errx(1, "%lu: %s: bad flag in substitute command: '%c'",
+ linenum, fname, *p);
+ break;
+ }
+ p++;
+ }
+}
+
+/*
+ * Compile a translation set of strings into a lookup table.
+ */
+static char *
+compile_tr(char *p, struct s_tr **py)
+{
+ struct s_tr *y;
+ int i;
+ const char *op, *np;
+ char old[_POSIX2_LINE_MAX + 1];
+ char new[_POSIX2_LINE_MAX + 1];
+ size_t oclen, oldlen, nclen, newlen;
+ mbstate_t mbs1, mbs2;
+
+ if ((*py = y = malloc(sizeof(*y))) == NULL)
+ err(1, NULL);
+ y->multis = NULL;
+ y->nmultis = 0;
+
+ if (*p == '\0' || *p == '\\')
+ errx(1,
+ "%lu: %s: transform pattern can not be delimited by newline or backslash",
+ linenum, fname);
+ p = compile_delimited(p, old, 1);
+ if (p == NULL)
+ errx(1, "%lu: %s: unterminated transform source string",
+ linenum, fname);
+ p = compile_delimited(p - 1, new, 1);
+ if (p == NULL)
+ errx(1, "%lu: %s: unterminated transform target string",
+ linenum, fname);
+ EATSPACE();
+ op = old;
+ oldlen = mbsrtowcs(NULL, &op, 0, NULL);
+ if (oldlen == (size_t)-1)
+ err(1, NULL);
+ np = new;
+ newlen = mbsrtowcs(NULL, &np, 0, NULL);
+ if (newlen == (size_t)-1)
+ err(1, NULL);
+ if (newlen != oldlen)
+ errx(1, "%lu: %s: transform strings are not the same length",
+ linenum, fname);
+ if (MB_CUR_MAX == 1) {
+ /*
+ * The single-byte encoding case is easy: generate a
+ * lookup table.
+ */
+ for (i = 0; i <= UCHAR_MAX; i++)
+ y->bytetab[i] = (char)i;
+ for (; *op; op++, np++)
+ y->bytetab[(u_char)*op] = *np;
+ } else {
+ /*
+ * Multi-byte encoding case: generate a lookup table as
+ * above, but only for single-byte characters. The first
+ * bytes of multi-byte characters have their lookup table
+ * entries set to 0, which causes do_tr() to search through
+ * an auxiliary vector of multi-byte mappings.
+ */
+ memset(&mbs1, 0, sizeof(mbs1));
+ memset(&mbs2, 0, sizeof(mbs2));
+ for (i = 0; i <= UCHAR_MAX; i++)
+ y->bytetab[i] = (btowc(i) != WEOF) ? i : 0;
+ while (*op != '\0') {
+ oclen = mbrlen(op, MB_LEN_MAX, &mbs1);
+ if (oclen == (size_t)-1 || oclen == (size_t)-2)
+ errc(1, EILSEQ, NULL);
+ nclen = mbrlen(np, MB_LEN_MAX, &mbs2);
+ if (nclen == (size_t)-1 || nclen == (size_t)-2)
+ errc(1, EILSEQ, NULL);
+ if (oclen == 1 && nclen == 1)
+ y->bytetab[(u_char)*op] = *np;
+ else {
+ y->bytetab[(u_char)*op] = 0;
+ y->multis = realloc(y->multis,
+ (y->nmultis + 1) * sizeof(*y->multis));
+ if (y->multis == NULL)
+ err(1, NULL);
+ i = y->nmultis++;
+ y->multis[i].fromlen = oclen;
+ memcpy(y->multis[i].from, op, oclen);
+ y->multis[i].tolen = nclen;
+ memcpy(y->multis[i].to, np, nclen);
+ }
+ op += oclen;
+ np += nclen;
+ }
+ }
+ return (p);
+}
+
+/*
+ * Compile the text following an a, c, or i command.
+ */
+static char *
+compile_text(void)
+{
+ int asize, esc_nl, size;
+ char *text, *p, *op, *s;
+ char lbuf[_POSIX2_LINE_MAX + 1];
+
+ asize = 2 * _POSIX2_LINE_MAX + 1;
+ if ((text = malloc(asize)) == NULL)
+ err(1, "malloc");
+ size = 0;
+ while (cu_fgets(lbuf, sizeof(lbuf), NULL) != NULL) {
+ op = s = text + size;
+ p = lbuf;
+#ifdef LEGACY_BSDSED_COMPAT
+ EATSPACE();
+#endif
+ for (esc_nl = 0; *p != '\0'; p++) {
+ if (*p == '\\' && p[1] != '\0' && *++p == '\n')
+ esc_nl = 1;
+ *s++ = *p;
+ }
+ size += s - op;
+ if (!esc_nl) {
+ *s = '\0';
+ break;
+ }
+ if (asize - size < _POSIX2_LINE_MAX + 1) {
+ asize *= 2;
+ if ((text = realloc(text, asize)) == NULL)
+ err(1, "realloc");
+ }
+ }
+ text[size] = '\0';
+ if ((p = realloc(text, size + 1)) == NULL)
+ err(1, "realloc");
+ return (p);
+}
+
+/*
+ * Get an address and return a pointer to the first character after
+ * it. Fill the structure pointed to according to the address.
+ */
+static char *
+compile_addr(char *p, struct s_addr *a)
+{
+ char *end, re[_POSIX2_LINE_MAX + 1];
+ int icase;
+
+ icase = 0;
+
+ a->type = 0;
+ switch (*p) {
+ case '\\': /* Context address */
+ ++p;
+ /* FALLTHROUGH */
+ case '/': /* Context address */
+ p = compile_delimited(p, re, 0);
+ if (p == NULL)
+ errx(1, "%lu: %s: unterminated regular expression", linenum, fname);
+ /* Check for case insensitive regexp flag */
+ if (*p == 'I') {
+ icase = 1;
+ p++;
+ }
+ if (*re == '\0')
+ a->u.r = NULL;
+ else
+ a->u.r = compile_re(re, icase);
+ a->type = AT_RE;
+ return (p);
+
+ case '$': /* Last line */
+ a->type = AT_LAST;
+ return (p + 1);
+
+ case '+': /* Relative line number */
+ a->type = AT_RELLINE;
+ p++;
+ /* FALLTHROUGH */
+ /* Line number */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (a->type == 0)
+ a->type = AT_LINE;
+ a->u.l = strtol(p, &end, 10);
+ return (end);
+ default:
+ errx(1, "%lu: %s: expected context address", linenum, fname);
+ return (NULL);
+ }
+}
+
+/*
+ * duptoeol --
+ * Return a copy of all the characters up to \n or \0.
+ */
+static char *
+duptoeol(char *s, const char *ctype)
+{
+ size_t len;
+ int ws;
+ char *p, *start;
+
+ ws = 0;
+ for (start = s; *s != '\0' && *s != '\n'; ++s)
+ ws = isspace((unsigned char)*s);
+ *s = '\0';
+ if (ws)
+ warnx("%lu: %s: whitespace after %s", linenum, fname, ctype);
+ len = s - start + 1;
+ if ((p = malloc(len)) == NULL)
+ err(1, "malloc");
+ return (memmove(p, start, len));
+}
+
+/*
+ * Convert goto label names to addresses, and count a and r commands, in
+ * the given subset of the script. Free the memory used by labels in b
+ * and t commands (but not by :).
+ *
+ * TODO: Remove } nodes
+ */
+static void
+fixuplabel(struct s_command *cp, struct s_command *end)
+{
+
+ for (; cp != end; cp = cp->next)
+ switch (cp->code) {
+ case 'a':
+ case 'r':
+ appendnum++;
+ break;
+ case 'b':
+ case 't':
+ /* Resolve branch target. */
+ if (cp->t == NULL) {
+ cp->u.c = NULL;
+ break;
+ }
+ if ((cp->u.c = findlabel(cp->t)) == NULL)
+ errx(1, "%lu: %s: undefined label '%s'", linenum, fname, cp->t);
+ free(cp->t);
+ break;
+ case '{':
+ /* Do interior commands. */
+ fixuplabel(cp->u.c, cp->next);
+ break;
+ }
+}
+
+/*
+ * Associate the given command label for later lookup.
+ */
+static void
+enterlabel(struct s_command *cp)
+{
+ struct labhash **lhp, *lh;
+ u_char *p;
+ u_int h, c;
+
+ for (h = 0, p = (u_char *)cp->t; (c = *p) != 0; p++)
+ h = (h << 5) + h + c;
+ lhp = &labels[h & LHMASK];
+ for (lh = *lhp; lh != NULL; lh = lh->lh_next)
+ if (lh->lh_hash == h && strcmp(cp->t, lh->lh_cmd->t) == 0)
+ errx(1, "%lu: %s: duplicate label '%s'", linenum, fname, cp->t);
+ if ((lh = malloc(sizeof *lh)) == NULL)
+ err(1, "malloc");
+ lh->lh_next = *lhp;
+ lh->lh_hash = h;
+ lh->lh_cmd = cp;
+ lh->lh_ref = 0;
+ *lhp = lh;
+}
+
+/*
+ * Find the label contained in the command l in the command linked
+ * list cp. L is excluded from the search. Return NULL if not found.
+ */
+static struct s_command *
+findlabel(char *name)
+{
+ struct labhash *lh;
+ u_char *p;
+ u_int h, c;
+
+ for (h = 0, p = (u_char *)name; (c = *p) != 0; p++)
+ h = (h << 5) + h + c;
+ for (lh = labels[h & LHMASK]; lh != NULL; lh = lh->lh_next) {
+ if (lh->lh_hash == h && strcmp(name, lh->lh_cmd->t) == 0) {
+ lh->lh_ref = 1;
+ return (lh->lh_cmd);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * Warn about any unused labels. As a side effect, release the label hash
+ * table space.
+ */
+static void
+uselabel(void)
+{
+ struct labhash *lh, *next;
+ int i;
+
+ for (i = 0; i < LHSZ; i++) {
+ for (lh = labels[i]; lh != NULL; lh = next) {
+ next = lh->lh_next;
+ if (!lh->lh_ref)
+ warnx("%lu: %s: unused label '%s'",
+ linenum, fname, lh->lh_cmd->t);
+ free(lh);
+ }
+ }
+}
diff --git a/text_cmds/sed/defs.h b/text_cmds/sed/defs.h
new file mode 100644
index 0000000..894b5f3
--- /dev/null
+++ b/text_cmds/sed/defs.h
@@ -0,0 +1,151 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)defs.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD$
+ */
+
+/*
+ * Types of address specifications
+ */
+enum e_atype {
+ AT_RE = 1, /* Line that match RE */
+ AT_LINE, /* Specific line */
+ AT_RELLINE, /* Relative line */
+ AT_LAST, /* Last line */
+};
+
+/*
+ * Format of an address
+ */
+struct s_addr {
+ enum e_atype type; /* Address type */
+ union {
+ u_long l; /* Line number */
+ regex_t *r; /* Regular expression */
+ } u;
+};
+
+/*
+ * Substitution command
+ */
+struct s_subst {
+ int n; /* Occurrence to subst. */
+ int p; /* True if p flag */
+ int icase; /* True if I flag */
+ char *wfile; /* NULL if no wfile */
+ int wfd; /* Cached file descriptor */
+ regex_t *re; /* Regular expression */
+ unsigned int maxbref; /* Largest backreference. */
+ u_long linenum; /* Line number. */
+ char *new; /* Replacement text */
+};
+
+/*
+ * Translate command.
+ */
+struct s_tr {
+ unsigned char bytetab[256];
+ struct trmulti {
+ size_t fromlen;
+ char from[MB_LEN_MAX];
+ size_t tolen;
+ char to[MB_LEN_MAX];
+ } *multis;
+ int nmultis;
+};
+
+/*
+ * An internally compiled command.
+ * Initialy, label references are stored in t, on a second pass they
+ * are updated to pointers.
+ */
+struct s_command {
+ struct s_command *next; /* Pointer to next command */
+ struct s_addr *a1, *a2; /* Start and end address */
+ u_long startline; /* Start line number or zero */
+ char *t; /* Text for : a c i r w */
+ union {
+ struct s_command *c; /* Command(s) for b t { */
+ struct s_subst *s; /* Substitute command */
+ struct s_tr *y; /* Replace command array */
+ int fd; /* File descriptor for w */
+ } u;
+ char code; /* Command code */
+ u_int nonsel:1; /* True if ! */
+};
+
+/*
+ * Types of command arguments recognised by the parser
+ */
+enum e_args {
+ EMPTY, /* d D g G h H l n N p P q x = \0 */
+ TEXT, /* a c i */
+ NONSEL, /* ! */
+ GROUP, /* { */
+ ENDGROUP, /* } */
+ COMMENT, /* # */
+ BRANCH, /* b t */
+ LABEL, /* : */
+ RFILE, /* r */
+ WFILE, /* w */
+ SUBST, /* s */
+ TR /* y */
+};
+
+/*
+ * Structure containing things to append before a line is read
+ */
+struct s_appends {
+ enum {AP_STRING, AP_FILE} type;
+ char *s;
+ size_t len;
+};
+
+enum e_spflag {
+ APPEND, /* Append to the contents. */
+ REPLACE, /* Replace the contents. */
+};
+
+/*
+ * Structure for a space (process, hold, otherwise).
+ */
+typedef struct {
+ char *space; /* Current space pointer. */
+ size_t len; /* Current length. */
+ int deleted; /* If deleted. */
+ int append_newline; /* If originally terminated by \n. */
+ char *back; /* Backing memory. */
+ size_t blen; /* Backing memory length. */
+} SPACE;
diff --git a/text_cmds/sed/extern.h b/text_cmds/sed/extern.h
new file mode 100644
index 0000000..4d88650
--- /dev/null
+++ b/text_cmds/sed/extern.h
@@ -0,0 +1,60 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD$
+ */
+
+extern struct s_command *prog;
+extern struct s_appends *appends;
+extern regmatch_t *match;
+extern size_t maxnsub;
+extern u_long linenum;
+extern unsigned int appendnum;
+extern int aflag, eflag, nflag;
+extern const char *fname, *outfname;
+extern FILE *infile, *outfile;
+extern int rflags; /* regex flags to use */
+extern const char *inplace;
+extern int quit;
+
+void cfclose(struct s_command *, struct s_command *);
+void compile(void);
+void cspace(SPACE *, const char *, size_t, enum e_spflag);
+char *cu_fgets(char *, int, int *);
+int mf_fgets(SPACE *, enum e_spflag);
+int lastline(void);
+void process(void);
+void resetstate(void);
+char *strregerror(int, regex_t *);
diff --git a/text_cmds/sed/main.c b/text_cmds/sed/main.c
new file mode 100644
index 0000000..96723cc
--- /dev/null
+++ b/text_cmds/sed/main.c
@@ -0,0 +1,547 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2013 Johann 'Myrkraverk' Oskarsson.
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1992, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)main.c 8.2 (Berkeley) 1/3/94";
+#endif
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <locale.h>
+#include <regex.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "defs.h"
+#include "extern.h"
+
+/*
+ * Linked list of units (strings and files) to be compiled
+ */
+struct s_compunit {
+ struct s_compunit *next;
+ enum e_cut {CU_FILE, CU_STRING} type;
+ char *s; /* Pointer to string or fname */
+};
+
+/*
+ * Linked list pointer to compilation units and pointer to current
+ * next pointer.
+ */
+static struct s_compunit *script, **cu_nextp = &script;
+
+/*
+ * Linked list of files to be processed
+ */
+struct s_flist {
+ char *fname;
+ struct s_flist *next;
+};
+
+/*
+ * Linked list pointer to files and pointer to current
+ * next pointer.
+ */
+static struct s_flist *files, **fl_nextp = &files;
+
+FILE *infile; /* Current input file */
+FILE *outfile; /* Current output file */
+
+int aflag, eflag, nflag;
+int rflags = 0;
+int quit = 0;
+static int rval; /* Exit status */
+
+static int ispan; /* Whether inplace editing spans across files */
+
+/*
+ * Current file and line number; line numbers restart across compilation
+ * units, but span across input files. The latter is optional if editing
+ * in place.
+ */
+const char *fname; /* File name. */
+const char *outfname; /* Output file name */
+static char oldfname[PATH_MAX]; /* Old file name (for in-place editing) */
+static char tmpfname[PATH_MAX]; /* Temporary file name (for in-place editing) */
+const char *inplace; /* Inplace edit file extension. */
+u_long linenum;
+
+static void add_compunit(enum e_cut, char *);
+static void add_file(char *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int c, fflag;
+ char *temp_arg;
+
+ (void) setlocale(LC_ALL, "");
+
+ fflag = 0;
+ inplace = NULL;
+
+ while ((c = getopt(argc, argv, "EI:ae:f:i:lnru")) != -1)
+ switch (c) {
+ case 'r': /* Gnu sed compat */
+ case 'E':
+ rflags = REG_EXTENDED;
+ break;
+ case 'I':
+ inplace = optarg;
+ ispan = 1; /* span across input files */
+ break;
+ case 'a':
+ aflag = 1;
+ break;
+ case 'e':
+ eflag = 1;
+ if ((temp_arg = malloc(strlen(optarg) + 2)) == NULL)
+ err(1, "malloc");
+ strcpy(temp_arg, optarg);
+ strcat(temp_arg, "\n");
+ add_compunit(CU_STRING, temp_arg);
+ break;
+ case 'f':
+ fflag = 1;
+ add_compunit(CU_FILE, optarg);
+ break;
+ case 'i':
+ inplace = optarg;
+ ispan = 0; /* don't span across input files */
+ break;
+ case 'l':
+ if(setvbuf(stdout, NULL, _IOLBF, 0) != 0)
+ warnx("setting line buffered output failed");
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'u':
+ if(setvbuf(stdout, NULL, _IONBF, 0) != 0)
+ warnx("setting unbuffered output failed");
+ break;
+ default:
+ case '?':
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* First usage case; script is the first arg */
+ if (!eflag && !fflag && *argv) {
+ add_compunit(CU_STRING, *argv);
+ argv++;
+ }
+
+ compile();
+
+ /* Continue with first and start second usage */
+ if (*argv)
+ for (; *argv; argv++)
+ add_file(*argv);
+ else
+ add_file(NULL);
+ process();
+ cfclose(prog, NULL);
+ if (fclose(stdout))
+ err(1, "stdout");
+ exit(rval);
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: %s script [-Ealnru] [-i extension] [file ...]\n"
+ "\t%s [-Ealnu] [-i extension] [-e script] ... [-f script_file]"
+ " ... [file ...]\n", getprogname(), getprogname());
+ exit(1);
+}
+
+/*
+ * Like fgets, but go through the chain of compilation units chaining them
+ * together. Empty strings and files are ignored.
+ */
+char *
+cu_fgets(char *buf, int n, int *more)
+{
+ static enum {ST_EOF, ST_FILE, ST_STRING} state = ST_EOF;
+ static FILE *f; /* Current open file */
+ static char *s; /* Current pointer inside string */
+ static char string_ident[30];
+ char *p;
+
+again:
+ switch (state) {
+ case ST_EOF:
+ if (script == NULL) {
+ if (more != NULL)
+ *more = 0;
+ return (NULL);
+ }
+ linenum = 0;
+ switch (script->type) {
+ case CU_FILE:
+ if ((f = fopen(script->s, "r")) == NULL)
+ err(1, "%s", script->s);
+ fname = script->s;
+ state = ST_FILE;
+ goto again;
+ case CU_STRING:
+ if (((size_t)snprintf(string_ident,
+ sizeof(string_ident), "\"%s\"", script->s)) >=
+ sizeof(string_ident) - 1)
+ (void)strcpy(string_ident +
+ sizeof(string_ident) - 6, " ...\"");
+ fname = string_ident;
+ s = script->s;
+ state = ST_STRING;
+ goto again;
+ default:
+ __builtin_unreachable();
+ }
+ case ST_FILE:
+ if ((p = fgets(buf, n, f)) != NULL) {
+ linenum++;
+ if (linenum == 1 && buf[0] == '#' && buf[1] == 'n')
+ nflag = 1;
+ if (more != NULL)
+ *more = !feof(f);
+ return (p);
+ }
+ script = script->next;
+ (void)fclose(f);
+ state = ST_EOF;
+ goto again;
+ case ST_STRING:
+ if (linenum == 0 && s[0] == '#' && s[1] == 'n')
+ nflag = 1;
+ p = buf;
+ for (;;) {
+ if (n-- <= 1) {
+ *p = '\0';
+ linenum++;
+ if (more != NULL)
+ *more = 1;
+ return (buf);
+ }
+ switch (*s) {
+ case '\0':
+ state = ST_EOF;
+ if (s == script->s) {
+ script = script->next;
+ goto again;
+ } else {
+ script = script->next;
+ *p = '\0';
+ linenum++;
+ if (more != NULL)
+ *more = 0;
+ return (buf);
+ }
+ case '\n':
+ *p++ = '\n';
+ *p = '\0';
+ s++;
+ linenum++;
+ if (more != NULL)
+ *more = 0;
+ return (buf);
+ default:
+ *p++ = *s++;
+ }
+ }
+ }
+ /* NOTREACHED */
+ return (NULL);
+}
+
+/*
+ * Like fgets, but go through the list of files chaining them together.
+ * Set len to the length of the line.
+ */
+int
+mf_fgets(SPACE *sp, enum e_spflag spflag)
+{
+ struct stat sb;
+ ssize_t len;
+ char *dirbuf, *basebuf;
+ static char *p = NULL;
+ static size_t plen = 0;
+ int c;
+ static int firstfile;
+
+ if (infile == NULL) {
+ /* stdin? */
+ if (files->fname == NULL) {
+ if (inplace != NULL)
+ errx(1, "-I or -i may not be used with stdin");
+ infile = stdin;
+ fname = "stdin";
+ outfile = stdout;
+ outfname = "stdout";
+ }
+ firstfile = 1;
+ }
+
+ for (;;) {
+ if (infile != NULL && (c = getc(infile)) != EOF && !quit) {
+ (void)ungetc(c, infile);
+ break;
+ }
+ /* If we are here then either eof or no files are open yet */
+ if (infile == stdin) {
+ sp->len = 0;
+ return (0);
+ }
+ if (infile != NULL) {
+ fclose(infile);
+ if (*oldfname != '\0') {
+ /* if there was a backup file, remove it */
+ unlink(oldfname);
+ /*
+ * Backup the original. Note that hard links
+ * are not supported on all filesystems.
+ */
+ if ((link(fname, oldfname) != 0) &&
+ (rename(fname, oldfname) != 0)) {
+ warn("rename()");
+ if (*tmpfname)
+ unlink(tmpfname);
+ exit(1);
+ }
+ *oldfname = '\0';
+ }
+ if (*tmpfname != '\0') {
+ if (outfile != NULL && outfile != stdout)
+ if (fclose(outfile) != 0) {
+ warn("fclose()");
+ unlink(tmpfname);
+ exit(1);
+ }
+ outfile = NULL;
+ if (rename(tmpfname, fname) != 0) {
+ /* this should not happen really! */
+ warn("rename()");
+ unlink(tmpfname);
+ exit(1);
+ }
+ *tmpfname = '\0';
+ }
+ outfname = NULL;
+ }
+ if (firstfile == 0)
+ files = files->next;
+ else
+ firstfile = 0;
+ if (files == NULL) {
+ sp->len = 0;
+ return (0);
+ }
+ fname = files->fname;
+ if (inplace != NULL) {
+ if (lstat(fname, &sb) != 0)
+ err(1, "%s", fname);
+ if (!S_ISREG(sb.st_mode))
+ errx(1, "%s: %s %s", fname,
+ "in-place editing only",
+ "works for regular files");
+ if (*inplace != '\0') {
+ strlcpy(oldfname, fname,
+ sizeof(oldfname));
+ len = strlcat(oldfname, inplace,
+ sizeof(oldfname));
+ if (len > (ssize_t)sizeof(oldfname))
+ errx(1, "%s: name too long", fname);
+ }
+ if ((dirbuf = strdup(fname)) == NULL ||
+ (basebuf = strdup(fname)) == NULL)
+ err(1, "strdup");
+ len = snprintf(tmpfname, sizeof(tmpfname),
+ "%s/.!%ld!%s", dirname(dirbuf), (long)getpid(),
+ basename(basebuf));
+ free(dirbuf);
+ free(basebuf);
+ if (len >= (ssize_t)sizeof(tmpfname))
+ errx(1, "%s: name too long", fname);
+ unlink(tmpfname);
+ if (outfile != NULL && outfile != stdout)
+ fclose(outfile);
+ if ((outfile = fopen(tmpfname, "w")) == NULL)
+ err(1, "%s", fname);
+ fchown(fileno(outfile), sb.st_uid, sb.st_gid);
+ fchmod(fileno(outfile), sb.st_mode & ALLPERMS);
+ outfname = tmpfname;
+ if (!ispan) {
+ linenum = 0;
+ resetstate();
+ }
+ } else {
+ outfile = stdout;
+ outfname = "stdout";
+ }
+ if ((infile = fopen(fname, "r")) == NULL) {
+ warn("%s", fname);
+ rval = 1;
+ continue;
+ }
+ }
+ /*
+ * We are here only when infile is open and we still have something
+ * to read from it.
+ *
+ * Use getline() so that we can handle essentially infinite input
+ * data. The p and plen are static so each invocation gives
+ * getline() the same buffer which is expanded as needed.
+ */
+ len = getline(&p, &plen, infile);
+ if (len == -1)
+ err(1, "%s", fname);
+ if (len != 0 && p[len - 1] == '\n') {
+ sp->append_newline = 1;
+ len--;
+ } else if (!lastline()) {
+ sp->append_newline = 1;
+ } else {
+ sp->append_newline = 0;
+ }
+ cspace(sp, p, len, spflag);
+
+ linenum++;
+
+ return (1);
+}
+
+/*
+ * Add a compilation unit to the linked list
+ */
+static void
+add_compunit(enum e_cut type, char *s)
+{
+ struct s_compunit *cu;
+
+ if ((cu = malloc(sizeof(struct s_compunit))) == NULL)
+ err(1, "malloc");
+ cu->type = type;
+ cu->s = s;
+ cu->next = NULL;
+ *cu_nextp = cu;
+ cu_nextp = &cu->next;
+}
+
+/*
+ * Add a file to the linked list
+ */
+static void
+add_file(char *s)
+{
+ struct s_flist *fp;
+
+ if ((fp = malloc(sizeof(struct s_flist))) == NULL)
+ err(1, "malloc");
+ fp->next = NULL;
+ *fl_nextp = fp;
+ fp->fname = s;
+ fl_nextp = &fp->next;
+}
+
+static int
+next_files_have_lines(void)
+{
+ struct s_flist *file;
+ FILE *file_fd;
+ int ch;
+
+ file = files;
+ while ((file = file->next) != NULL) {
+ if ((file_fd = fopen(file->fname, "r")) == NULL)
+ continue;
+
+ if ((ch = getc(file_fd)) != EOF) {
+ /*
+ * This next file has content, therefore current
+ * file doesn't contains the last line.
+ */
+ ungetc(ch, file_fd);
+ fclose(file_fd);
+ return (1);
+ }
+
+ fclose(file_fd);
+ }
+
+ return (0);
+}
+
+int
+lastline(void)
+{
+ int ch;
+
+ if (feof(infile)) {
+ return !(
+ (inplace == NULL || ispan) &&
+ next_files_have_lines());
+ }
+ if ((ch = getc(infile)) == EOF) {
+ return !(
+ (inplace == NULL || ispan) &&
+ next_files_have_lines());
+ }
+ ungetc(ch, infile);
+ return (0);
+}
diff --git a/text_cmds/sed/misc.c b/text_cmds/sed/misc.c
new file mode 100644
index 0000000..7068f70
--- /dev/null
+++ b/text_cmds/sed/misc.c
@@ -0,0 +1,73 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "defs.h"
+#include "extern.h"
+
+/*
+ * Return a string for a regular expression error passed. This is overkill,
+ * because of the silly semantics of regerror (we can never know the size of
+ * the buffer).
+ */
+char *
+strregerror(int errcode, regex_t *preg)
+{
+ static char *oe;
+ size_t s;
+
+ if (oe != NULL)
+ free(oe);
+ s = regerror(errcode, preg, NULL, 0);
+ if ((oe = malloc(s)) == NULL)
+ err(1, "malloc");
+ (void)regerror(errcode, preg, oe, s);
+ return (oe);
+}
diff --git a/text_cmds/sed/process.c b/text_cmds/sed/process.c
new file mode 100644
index 0000000..261c623
--- /dev/null
+++ b/text_cmds/sed/process.c
@@ -0,0 +1,791 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1992 Diomidis Spinellis.
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Diomidis Spinellis of Imperial College, University of London.
+ *
+ * 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 University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)process.c 8.6 (Berkeley) 4/20/94";
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "defs.h"
+#include "extern.h"
+
+static SPACE HS, PS, SS, YS;
+#define pd PS.deleted
+#define ps PS.space
+#define psl PS.len
+#define psanl PS.append_newline
+#define hs HS.space
+#define hsl HS.len
+
+static inline int applies(struct s_command *);
+static void do_tr(struct s_tr *);
+static void flush_appends(void);
+static void lputs(char *, size_t);
+static int regexec_e(regex_t *, const char *, int, int, size_t,
+ size_t);
+static void regsub(SPACE *, char *, char *);
+static int substitute(struct s_command *);
+
+struct s_appends *appends; /* Array of pointers to strings to append. */
+static unsigned int appendx; /* Index into appends array. */
+unsigned int appendnum; /* Size of appends array. */
+
+static int lastaddr; /* Set by applies if last address of a range. */
+static int sdone; /* If any substitutes since last line input. */
+ /* Iov structure for 'w' commands. */
+static regex_t *defpreg;
+size_t maxnsub;
+regmatch_t *match;
+
+#define OUT() do { \
+ fwrite(ps, 1, psl, outfile); \
+ if (psanl) fputc('\n', outfile); \
+} while (0)
+
+void
+process(void)
+{
+ struct s_command *cp;
+ SPACE tspace;
+ size_t oldpsl;
+ char *p;
+ int oldpsanl;
+
+ p = NULL;
+ oldpsanl = oldpsl = 0;
+
+ for (linenum = 0; mf_fgets(&PS, REPLACE);) {
+ pd = 0;
+top:
+ cp = prog;
+redirect:
+ while (cp != NULL) {
+ if (!applies(cp)) {
+ cp = cp->next;
+ continue;
+ }
+ switch (cp->code) {
+ case '{':
+ cp = cp->u.c;
+ goto redirect;
+ case 'a':
+ if (appendx >= appendnum)
+ if ((appends = realloc(appends,
+ sizeof(struct s_appends) *
+ (appendnum *= 2))) == NULL)
+ err(1, "realloc");
+ appends[appendx].type = AP_STRING;
+ appends[appendx].s = cp->t;
+ appends[appendx].len = strlen(cp->t);
+ appendx++;
+ break;
+ case 'b':
+ cp = cp->u.c;
+ goto redirect;
+ case 'c':
+ pd = 1;
+ psl = 0;
+ if (cp->a2 == NULL || lastaddr || lastline())
+ (void)fprintf(outfile, "%s", cp->t);
+ break;
+ case 'd':
+ pd = 1;
+ goto new;
+ case 'D':
+ if (pd)
+ goto new;
+ if (psl == 0 ||
+ (p = memchr(ps, '\n', psl)) == NULL) {
+ pd = 1;
+ goto new;
+ } else {
+ psl -= (p + 1) - ps;
+ memmove(ps, p + 1, psl);
+ goto top;
+ }
+ case 'g':
+ cspace(&PS, hs, hsl, REPLACE);
+ break;
+ case 'G':
+ cspace(&PS, "\n", 1, APPEND);
+ cspace(&PS, hs, hsl, APPEND);
+ break;
+ case 'h':
+ cspace(&HS, ps, psl, REPLACE);
+ break;
+ case 'H':
+ cspace(&HS, "\n", 1, APPEND);
+ cspace(&HS, ps, psl, APPEND);
+ break;
+ case 'i':
+ (void)fprintf(outfile, "%s", cp->t);
+ break;
+ case 'l':
+ lputs(ps, psl);
+ break;
+ case 'n':
+ if (!nflag && !pd)
+ OUT();
+ flush_appends();
+ if (!mf_fgets(&PS, REPLACE))
+ exit(0);
+ pd = 0;
+ break;
+ case 'N':
+ flush_appends();
+ cspace(&PS, "\n", 1, APPEND);
+ if (!mf_fgets(&PS, APPEND))
+ exit(0);
+ break;
+ case 'p':
+ if (pd)
+ break;
+ OUT();
+ break;
+ case 'P':
+ if (pd)
+ break;
+ if ((p = memchr(ps, '\n', psl)) != NULL) {
+ oldpsl = psl;
+ oldpsanl = psanl;
+ psl = p - ps;
+ psanl = 1;
+ }
+ OUT();
+ if (p != NULL) {
+ psl = oldpsl;
+ psanl = oldpsanl;
+ }
+ break;
+ case 'q':
+ if (inplace == NULL) {
+ if (!nflag && !pd)
+ OUT();
+ flush_appends();
+ exit(0);
+ }
+ quit = 1;
+ break;
+ case 'r':
+ if (appendx >= appendnum)
+ if ((appends = realloc(appends,
+ sizeof(struct s_appends) *
+ (appendnum *= 2))) == NULL)
+ err(1, "realloc");
+ appends[appendx].type = AP_FILE;
+ appends[appendx].s = cp->t;
+ appends[appendx].len = strlen(cp->t);
+ appendx++;
+ break;
+ case 's':
+ sdone |= substitute(cp);
+ break;
+ case 't':
+ if (sdone) {
+ sdone = 0;
+ cp = cp->u.c;
+ goto redirect;
+ }
+ break;
+ case 'w':
+ if (pd)
+ break;
+ if (cp->u.fd == -1 && (cp->u.fd = open(cp->t,
+ O_WRONLY|O_APPEND|O_CREAT|O_TRUNC,
+ DEFFILEMODE)) == -1)
+ err(1, "%s", cp->t);
+ if (write(cp->u.fd, ps, psl) != (ssize_t)psl ||
+ write(cp->u.fd, "\n", 1) != 1)
+ err(1, "%s", cp->t);
+ break;
+ case 'x':
+ /*
+ * If the hold space is null, make it empty
+ * but not null. Otherwise the pattern space
+ * will become null after the swap, which is
+ * an abnormal condition.
+ */
+ if (hs == NULL)
+ cspace(&HS, "", 0, REPLACE);
+ tspace = PS;
+ PS = HS;
+ psanl = tspace.append_newline;
+ HS = tspace;
+ break;
+ case 'y':
+ if (pd || psl == 0)
+ break;
+ do_tr(cp->u.y);
+ break;
+ case ':':
+ case '}':
+ break;
+ case '=':
+ (void)fprintf(outfile, "%lu\n", linenum);
+ }
+ cp = cp->next;
+ } /* for all cp */
+
+new: if (!nflag && !pd)
+ OUT();
+ flush_appends();
+ } /* for all lines */
+}
+
+/*
+ * TRUE if the address passed matches the current program state
+ * (lastline, linenumber, ps).
+ */
+#define MATCH(a) \
+ ((a)->type == AT_RE ? regexec_e((a)->u.r, ps, 0, 1, 0, psl) : \
+ (a)->type == AT_LINE ? linenum == (a)->u.l : lastline())
+
+/*
+ * Return TRUE if the command applies to the current line. Sets the start
+ * line for process ranges. Interprets the non-select (``!'') flag.
+ */
+static inline int
+applies(struct s_command *cp)
+{
+ int r;
+
+ lastaddr = 0;
+ if (cp->a1 == NULL && cp->a2 == NULL)
+ r = 1;
+ else if (cp->a2)
+ if (cp->startline > 0) {
+ switch (cp->a2->type) {
+ case AT_RELLINE:
+ if (linenum - cp->startline <= cp->a2->u.l)
+ r = 1;
+ else {
+ cp->startline = 0;
+ r = 0;
+ }
+ break;
+ default:
+ if (MATCH(cp->a2)) {
+ cp->startline = 0;
+ lastaddr = 1;
+ r = 1;
+ } else if (cp->a2->type == AT_LINE &&
+ linenum > cp->a2->u.l) {
+ /*
+ * We missed the 2nd address due to a
+ * branch, so just close the range and
+ * return false.
+ */
+ cp->startline = 0;
+ r = 0;
+ } else
+ r = 1;
+ }
+ } else if (cp->a1 && MATCH(cp->a1)) {
+ /*
+ * If the second address is a number less than or
+ * equal to the line number first selected, only
+ * one line shall be selected.
+ * -- POSIX 1003.2
+ * Likewise if the relative second line address is zero.
+ */
+ if ((cp->a2->type == AT_LINE &&
+ linenum >= cp->a2->u.l) ||
+ (cp->a2->type == AT_RELLINE && cp->a2->u.l == 0))
+ lastaddr = 1;
+ else {
+ cp->startline = linenum;
+ }
+ r = 1;
+ } else
+ r = 0;
+ else
+ r = MATCH(cp->a1);
+ return (cp->nonsel ? ! r : r);
+}
+
+/*
+ * Reset the sed processor to its initial state.
+ */
+void
+resetstate(void)
+{
+ struct s_command *cp;
+
+ /*
+ * Reset all in-range markers.
+ */
+ for (cp = prog; cp; cp = cp->code == '{' ? cp->u.c : cp->next)
+ if (cp->a2)
+ cp->startline = 0;
+
+ /*
+ * Clear out the hold space.
+ */
+ cspace(&HS, "", 0, REPLACE);
+}
+
+/*
+ * substitute --
+ * Do substitutions in the pattern space. Currently, we build a
+ * copy of the new pattern space in the substitute space structure
+ * and then swap them.
+ */
+static int
+substitute(struct s_command *cp)
+{
+ SPACE tspace;
+ regex_t *re;
+ regoff_t slen;
+ int lastempty, n;
+ regoff_t le = 0;
+ char *s;
+
+ s = ps;
+ re = cp->u.s->re;
+ if (re == NULL) {
+ if (defpreg != NULL && cp->u.s->maxbref > defpreg->re_nsub) {
+ linenum = cp->u.s->linenum;
+ errx(1, "%lu: %s: \\%u not defined in the RE",
+ linenum, fname, cp->u.s->maxbref);
+ }
+ }
+ if (!regexec_e(re, ps, 0, 0, 0, psl))
+ return (0);
+
+ SS.len = 0; /* Clean substitute space. */
+ slen = psl;
+ n = cp->u.s->n;
+ lastempty = 1;
+
+ do {
+ /* Copy the leading retained string. */
+ if (n <= 1 && (match[0].rm_so > le))
+ cspace(&SS, s, match[0].rm_so - le, APPEND);
+
+ /* Skip zero-length matches right after other matches. */
+ if (lastempty || (match[0].rm_so - le) ||
+ match[0].rm_so != match[0].rm_eo) {
+ if (n <= 1) {
+ /* Want this match: append replacement. */
+ regsub(&SS, ps, cp->u.s->new);
+ if (n == 1)
+ n = -1;
+ } else {
+ /* Want a later match: append original. */
+ if (match[0].rm_eo - le)
+ cspace(&SS, s, match[0].rm_eo - le,
+ APPEND);
+ n--;
+ }
+ }
+
+ /* Move past this match. */
+ s = ps + match[0].rm_eo;
+ slen = psl - match[0].rm_eo;
+ le = match[0].rm_eo;
+
+ /*
+ * After a zero-length match, advance one byte,
+ * and at the end of the line, terminate.
+ */
+ if (match[0].rm_so == match[0].rm_eo) {
+ if (*s == '\0' || *s == '\n')
+ slen = -1;
+ else
+ slen--;
+ if (*s != '\0') {
+ cspace(&SS, s++, 1, APPEND);
+ le++;
+ }
+ lastempty = 1;
+ } else
+ lastempty = 0;
+
+ } while (n >= 0 && slen >= 0 &&
+ regexec_e(re, ps, REG_NOTBOL, 0, le, psl));
+
+ /* Did not find the requested number of matches. */
+ if (n > 0)
+ return (0);
+
+ /* Copy the trailing retained string. */
+ if (slen > 0)
+ cspace(&SS, s, slen, APPEND);
+
+ /*
+ * Swap the substitute space and the pattern space, and make sure
+ * that any leftover pointers into stdio memory get lost.
+ */
+ tspace = PS;
+ PS = SS;
+ psanl = tspace.append_newline;
+ SS = tspace;
+ SS.space = SS.back;
+
+ /* Handle the 'p' flag. */
+ if (cp->u.s->p)
+ OUT();
+
+ /* Handle the 'w' flag. */
+ if (cp->u.s->wfile && !pd) {
+ if (cp->u.s->wfd == -1 && (cp->u.s->wfd = open(cp->u.s->wfile,
+ O_WRONLY|O_APPEND|O_CREAT|O_TRUNC, DEFFILEMODE)) == -1)
+ err(1, "%s", cp->u.s->wfile);
+ if (write(cp->u.s->wfd, ps, psl) != (ssize_t)psl ||
+ write(cp->u.s->wfd, "\n", 1) != 1)
+ err(1, "%s", cp->u.s->wfile);
+ }
+ return (1);
+}
+
+/*
+ * do_tr --
+ * Perform translation ('y' command) in the pattern space.
+ */
+static void
+do_tr(struct s_tr *y)
+{
+ SPACE tmp;
+ char c, *p;
+ size_t clen, left;
+ int i;
+
+ if (MB_CUR_MAX == 1) {
+ /*
+ * Single-byte encoding: perform in-place translation
+ * of the pattern space.
+ */
+ for (p = ps; p < &ps[psl]; p++)
+ *p = y->bytetab[(u_char)*p];
+ } else {
+ /*
+ * Multi-byte encoding: perform translation into the
+ * translation space, then swap the translation and
+ * pattern spaces.
+ */
+ /* Clean translation space. */
+ YS.len = 0;
+ for (p = ps, left = psl; left > 0; p += clen, left -= clen) {
+ if ((c = y->bytetab[(u_char)*p]) != '\0') {
+ cspace(&YS, &c, 1, APPEND);
+ clen = 1;
+ continue;
+ }
+ for (i = 0; i < y->nmultis; i++)
+ if (left >= y->multis[i].fromlen &&
+ memcmp(p, y->multis[i].from,
+ y->multis[i].fromlen) == 0)
+ break;
+ if (i < y->nmultis) {
+ cspace(&YS, y->multis[i].to,
+ y->multis[i].tolen, APPEND);
+ clen = y->multis[i].fromlen;
+ } else {
+ cspace(&YS, p, 1, APPEND);
+ clen = 1;
+ }
+ }
+ /* Swap the translation space and the pattern space. */
+ tmp = PS;
+ PS = YS;
+ psanl = tmp.append_newline;
+ YS = tmp;
+ YS.space = YS.back;
+ }
+}
+
+/*
+ * Flush append requests. Always called before reading a line,
+ * therefore it also resets the substitution done (sdone) flag.
+ */
+static void
+flush_appends(void)
+{
+ FILE *f;
+ unsigned int count, idx;
+ char buf[8 * 1024];
+
+ for (idx = 0; idx < appendx; idx++)
+ switch (appends[idx].type) {
+ case AP_STRING:
+ fwrite(appends[idx].s, sizeof(char), appends[idx].len,
+ outfile);
+ break;
+ case AP_FILE:
+ /*
+ * Read files probably shouldn't be cached. Since
+ * it's not an error to read a non-existent file,
+ * it's possible that another program is interacting
+ * with the sed script through the filesystem. It
+ * would be truly bizarre, but possible. It's probably
+ * not that big a performance win, anyhow.
+ */
+ if ((f = fopen(appends[idx].s, "r")) == NULL)
+ break;
+ while ((count = fread(buf, sizeof(char), sizeof(buf), f)))
+ (void)fwrite(buf, sizeof(char), count, outfile);
+ (void)fclose(f);
+ break;
+ }
+ if (ferror(outfile))
+ errx(1, "%s: %s", outfname, strerror(errno ? errno : EIO));
+ appendx = sdone = 0;
+}
+
+static void
+lputs(char *s, size_t len)
+{
+ static const char escapes[] = "\\\a\b\f\r\t\v";
+ int c, col, width;
+ const char *p;
+ struct winsize win;
+ static int termwidth = -1;
+ size_t clen, i;
+ wchar_t wc;
+ mbstate_t mbs;
+
+ if (outfile != stdout)
+ termwidth = 60;
+ if (termwidth == -1) {
+ if ((p = getenv("COLUMNS")) && *p != '\0')
+ termwidth = atoi(p);
+ else if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+ win.ws_col > 0)
+ termwidth = win.ws_col;
+ else
+ termwidth = 60;
+ }
+ if (termwidth <= 0)
+ termwidth = 1;
+
+ memset(&mbs, 0, sizeof(mbs));
+ col = 0;
+ while (len != 0) {
+ clen = mbrtowc(&wc, s, len, &mbs);
+ if (clen == 0)
+ clen = 1;
+ if (clen == (size_t)-1 || clen == (size_t)-2) {
+ wc = (unsigned char)*s;
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if (wc == '\n') {
+ if (col + 1 >= termwidth)
+ fprintf(outfile, "\\\n");
+ fputc('$', outfile);
+ fputc('\n', outfile);
+ col = 0;
+ } else if (iswprint(wc)) {
+ width = wcwidth(wc);
+ if (col + width >= termwidth) {
+ fprintf(outfile, "\\\n");
+ col = 0;
+ }
+ fwrite(s, 1, clen, outfile);
+ col += width;
+ } else if (wc != L'\0' && (c = wctob(wc)) != EOF &&
+ (p = strchr(escapes, c)) != NULL) {
+ if (col + 2 >= termwidth) {
+ fprintf(outfile, "\\\n");
+ col = 0;
+ }
+ fprintf(outfile, "\\%c", "\\abfrtv"[p - escapes]);
+ col += 2;
+ } else {
+ if (col + 4 * clen >= (unsigned)termwidth) {
+ fprintf(outfile, "\\\n");
+ col = 0;
+ }
+ for (i = 0; i < clen; i++)
+ fprintf(outfile, "\\%03o",
+ (int)(unsigned char)s[i]);
+ col += 4 * clen;
+ }
+ s += clen;
+ len -= clen;
+ }
+ if (col + 1 >= termwidth)
+ fprintf(outfile, "\\\n");
+ (void)fputc('$', outfile);
+ (void)fputc('\n', outfile);
+ if (ferror(outfile))
+ errx(1, "%s: %s", outfname, strerror(errno ? errno : EIO));
+}
+
+static int
+regexec_e(regex_t *preg, const char *string, int eflags, int nomatch,
+ size_t start, size_t stop)
+{
+ int eval;
+
+ if (preg == NULL) {
+ if (defpreg == NULL)
+ errx(1, "first RE may not be empty");
+ } else
+ defpreg = preg;
+
+ /* Set anchors */
+ match[0].rm_so = start;
+ match[0].rm_eo = stop;
+
+ eval = regexec(defpreg, string,
+ nomatch ? 0 : maxnsub + 1, match, eflags | REG_STARTEND);
+ switch(eval) {
+ case 0:
+ return (1);
+ case REG_NOMATCH:
+ return (0);
+ }
+ errx(1, "RE error: %s", strregerror(eval, defpreg));
+ /* NOTREACHED */
+}
+
+/*
+ * regsub - perform substitutions after a regexp match
+ * Based on a routine by Henry Spencer
+ */
+static void
+regsub(SPACE *sp, char *string, char *src)
+{
+ int len, no;
+ char c, *dst;
+
+#define NEEDSP(reqlen) \
+ /* XXX What is the +1 for? */ \
+ if (sp->len + (reqlen) + 1 >= sp->blen) { \
+ sp->blen += (reqlen) + 1024; \
+ if ((sp->space = sp->back = realloc(sp->back, sp->blen)) \
+ == NULL) \
+ err(1, "realloc"); \
+ dst = sp->space + sp->len; \
+ }
+
+ dst = sp->space + sp->len;
+ while ((c = *src++) != '\0') {
+ if (c == '&')
+ no = 0;
+ else if (c == '\\' && isdigit((unsigned char)*src))
+ no = *src++ - '0';
+ else
+ no = -1;
+ if (no < 0) { /* Ordinary character. */
+ if (c == '\\' && (*src == '\\' || *src == '&'))
+ c = *src++;
+ NEEDSP(1);
+ *dst++ = c;
+ ++sp->len;
+ } else if (match[no].rm_so != -1 && match[no].rm_eo != -1) {
+ len = match[no].rm_eo - match[no].rm_so;
+ NEEDSP(len);
+ memmove(dst, string + match[no].rm_so, len);
+ dst += len;
+ sp->len += len;
+ }
+ }
+ NEEDSP(1);
+ *dst = '\0';
+}
+
+/*
+ * cspace --
+ * Concatenate space: append the source space to the destination space,
+ * allocating new space as necessary.
+ */
+void
+cspace(SPACE *sp, const char *p, size_t len, enum e_spflag spflag)
+{
+ size_t tlen;
+
+ /* Make sure SPACE has enough memory and ramp up quickly. */
+ tlen = sp->len + len + 1;
+ if (tlen > sp->blen) {
+ sp->blen = tlen + 1024;
+ if ((sp->space = sp->back = realloc(sp->back, sp->blen)) ==
+ NULL)
+ err(1, "realloc");
+ }
+
+ if (spflag == REPLACE)
+ sp->len = 0;
+
+ memmove(sp->space + sp->len, p, len);
+
+ sp->space[sp->len += len] = '\0';
+}
+
+/*
+ * Close all cached opened files and report any errors
+ */
+void
+cfclose(struct s_command *cp, struct s_command *end)
+{
+
+ for (; cp != end; cp = cp->next)
+ switch(cp->code) {
+ case 's':
+ if (cp->u.s->wfd != -1 && close(cp->u.s->wfd))
+ err(1, "%s", cp->u.s->wfile);
+ cp->u.s->wfd = -1;
+ break;
+ case 'w':
+ if (cp->u.fd != -1 && close(cp->u.fd))
+ err(1, "%s", cp->t);
+ cp->u.fd = -1;
+ break;
+ case '{':
+ cfclose(cp->u.c, cp->next);
+ break;
+ }
+}
diff --git a/text_cmds/sed/sed.1 b/text_cmds/sed/sed.1
new file mode 100644
index 0000000..3f36bd0
--- /dev/null
+++ b/text_cmds/sed/sed.1
@@ -0,0 +1,668 @@
+.\" Copyright (c) 1992, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sed.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD$
+.\"
+.Dd March 27, 2017
+.Dt SED 1
+.Os
+.Sh NAME
+.Nm sed
+.Nd stream editor
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ealnru
+.Ar command
+.Op Ar
+.Nm
+.Op Fl Ealnr
+.Op Fl e Ar command
+.Op Fl f Ar command_file
+.Op Fl I Ar extension
+.Op Fl i Ar extension
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility reads the specified files, or the standard input if no files
+are specified, modifying the input as specified by a list of commands.
+The input is then written to the standard output.
+.Pp
+A single command may be specified as the first argument to
+.Nm .
+Multiple commands may be specified by using the
+.Fl e
+or
+.Fl f
+options.
+All commands are applied to the input in the order they are specified
+regardless of their origin.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl E
+Interpret regular expressions as extended (modern) regular expressions
+rather than basic regular expressions (BRE's).
+The
+.Xr re_format 7
+manual page fully describes both formats.
+.It Fl a
+The files listed as parameters for the
+.Dq w
+functions are created (or truncated) before any processing begins,
+by default.
+The
+.Fl a
+option causes
+.Nm
+to delay opening each file until a command containing the related
+.Dq w
+function is applied to a line of input.
+.It Fl e Ar command
+Append the editing commands specified by the
+.Ar command
+argument
+to the list of commands.
+.It Fl f Ar command_file
+Append the editing commands found in the file
+.Ar command_file
+to the list of commands.
+The editing commands should each be listed on a separate line.
+.It Fl I Ar extension
+Edit files in-place, saving backups with the specified
+.Ar extension .
+If a zero-length
+.Ar extension
+is given, no backup will be saved.
+It is not recommended to give a zero-length
+.Ar extension
+when in-place editing files, as you risk corruption or partial content
+in situations where disk space is exhausted, etc.
+.Pp
+Note that in-place editing with
+.Fl I
+still takes place in a single continuous line address space covering
+all files, although each file preserves its individuality instead of
+forming one output stream.
+The line counter is never reset between files, address ranges can span
+file boundaries, and the
+.Dq $
+address matches only the last line of the last file.
+(See
+.Sx "Sed Addresses" . )
+That can lead to unexpected results in many cases of in-place editing,
+where using
+.Fl i
+is desired.
+.It Fl i Ar extension
+Edit files in-place similarly to
+.Fl I ,
+but treat each file independently from other files.
+In particular, line numbers in each file start at 1,
+the
+.Dq $
+address matches the last line of the current file,
+and address ranges are limited to the current file.
+(See
+.Sx "Sed Addresses" . )
+The net result is as though each file were edited by a separate
+.Nm
+instance.
+.It Fl l
+Make output line buffered.
+.It Fl n
+By default, each line of input is echoed to the standard output after
+all of the commands have been applied to it.
+The
+.Fl n
+option suppresses this behavior.
+.It Fl r
+Same as
+.Fl E
+for compatibility with GNU sed.
+.It Fl u
+Make output unbuffered.
+.El
+.Pp
+The form of a
+.Nm
+command is as follows:
+.Pp
+.Dl [address[,address]]function[arguments]
+.Pp
+Whitespace may be inserted before the first address and the function
+portions of the command.
+.Pp
+Normally,
+.Nm
+cyclically copies a line of input, not including its terminating newline
+character, into a
+.Em "pattern space" ,
+(unless there is something left after a
+.Dq D
+function),
+applies all of the commands with addresses that select that pattern space,
+copies the pattern space to the standard output, appending a newline, and
+deletes the pattern space.
+.Pp
+Some of the functions use a
+.Em "hold space"
+to save all or part of the pattern space for subsequent retrieval.
+.Sh "Sed Addresses"
+An address is not required, but if specified must have one of the
+following formats:
+.Bl -bullet -offset indent
+.It
+a number that counts
+input lines
+cumulatively across input files (or in each file independently
+if a
+.Fl i
+option is in effect);
+.It
+a dollar
+.Pq Dq $
+character that addresses the last line of input (or the last line
+of the current file if a
+.Fl i
+option was specified);
+.It
+a context address
+that consists of a regular expression preceded and followed by a
+delimiter. The closing delimiter can also optionally be followed by the
+.Dq I
+character, to indicate that the regular expression is to be matched
+in a case-insensitive way.
+.El
+.Pp
+A command line with no addresses selects every pattern space.
+.Pp
+A command line with one address selects all of the pattern spaces
+that match the address.
+.Pp
+A command line with two addresses selects an inclusive range.
+This
+range starts with the first pattern space that matches the first
+address.
+The end of the range is the next following pattern space
+that matches the second address.
+If the second address is a number
+less than or equal to the line number first selected, only that
+line is selected.
+The number in the second address may be prefixed with a
+.Pq Dq \&+
+to specify the number of lines to match after the first pattern.
+In the case when the second address is a context
+address,
+.Nm
+does not re-match the second address against the
+pattern space that matched the first address.
+Starting at the
+first line following the selected range,
+.Nm
+starts looking again for the first address.
+.Pp
+Editing commands can be applied to non-selected pattern spaces by use
+of the exclamation character
+.Pq Dq \&!
+function.
+.Sh "Sed Regular Expressions"
+The regular expressions used in
+.Nm ,
+by default, are basic regular expressions (BREs, see
+.Xr re_format 7
+for more information), but extended (modern) regular expressions can be used
+instead if the
+.Fl E
+flag is given.
+In addition,
+.Nm
+has the following two additions to regular expressions:
+.Pp
+.Bl -enum -compact
+.It
+In a context address, any character other than a backslash
+.Pq Dq \e
+or newline character may be used to delimit the regular expression.
+The opening delimiter needs to be preceded by a backslash
+unless it is a slash.
+For example, the context address
+.Li \exabcx
+is equivalent to
+.Li /abc/ .
+Also, putting a backslash character before the delimiting character
+within the regular expression causes the character to be treated literally.
+For example, in the context address
+.Li \exabc\exdefx ,
+the RE delimiter is an
+.Dq x
+and the second
+.Dq x
+stands for itself, so that the regular expression is
+.Dq abcxdef .
+.Pp
+.It
+The escape sequence \en matches a newline character embedded in the
+pattern space.
+You cannot, however, use a literal newline character in an address or
+in the substitute command.
+.El
+.Pp
+One special feature of
+.Nm
+regular expressions is that they can default to the last regular
+expression used.
+If a regular expression is empty, i.e., just the delimiter characters
+are specified, the last regular expression encountered is used instead.
+The last regular expression is defined as the last regular expression
+used as part of an address or substitute command, and at run-time, not
+compile-time.
+For example, the command
+.Dq /abc/s//XXX/
+will substitute
+.Dq XXX
+for the pattern
+.Dq abc .
+.Sh "Sed Functions"
+In the following list of commands, the maximum number of permissible
+addresses for each command is indicated by [0addr], [1addr], or [2addr],
+representing zero, one, or two addresses.
+.Pp
+The argument
+.Em text
+consists of one or more lines.
+To embed a newline in the text, precede it with a backslash.
+Other backslashes in text are deleted and the following character
+taken literally.
+.Pp
+The
+.Dq r
+and
+.Dq w
+functions take an optional file parameter, which should be separated
+from the function letter by white space.
+Each file given as an argument to
+.Nm
+is created (or its contents truncated) before any input processing begins.
+.Pp
+The
+.Dq b ,
+.Dq r ,
+.Dq s ,
+.Dq t ,
+.Dq w ,
+.Dq y ,
+.Dq \&! ,
+and
+.Dq \&:
+functions all accept additional arguments.
+The following synopses indicate which arguments have to be separated from
+the function letters by white space characters.
+.Pp
+Two of the functions take a function-list.
+This is a list of
+.Nm
+functions separated by newlines, as follows:
+.Bd -literal -offset indent
+{ function
+ function
+ ...
+ function
+}
+.Ed
+.Pp
+The
+.Dq {
+can be preceded by white space and can be followed by white space.
+The function can be preceded by white space.
+The terminating
+.Dq }
+must be preceded by a newline, and may also be preceded by white space.
+.Pp
+.Bl -tag -width "XXXXXX" -compact
+.It [2addr] function-list
+Execute function-list only when the pattern space is selected.
+.Pp
+.It [1addr]a\e
+.It text
+Write
+.Em text
+to standard output immediately before each attempt to read a line of input,
+whether by executing the
+.Dq N
+function or by beginning a new cycle.
+.Pp
+.It [2addr]b[label]
+Branch to the
+.Dq \&:
+function with the specified label.
+If the label is not specified, branch to the end of the script.
+.Pp
+.It [2addr]c\e
+.It text
+Delete the pattern space.
+With 0 or 1 address or at the end of a 2-address range,
+.Em text
+is written to the standard output.
+.Pp
+.It [2addr]d
+Delete the pattern space and start the next cycle.
+.Pp
+.It [2addr]D
+Delete the initial segment of the pattern space through the first
+newline character and start the next cycle.
+.Pp
+.It [2addr]g
+Replace the contents of the pattern space with the contents of the
+hold space.
+.Pp
+.It [2addr]G
+Append a newline character followed by the contents of the hold space
+to the pattern space.
+.Pp
+.It [2addr]h
+Replace the contents of the hold space with the contents of the
+pattern space.
+.Pp
+.It [2addr]H
+Append a newline character followed by the contents of the pattern space
+to the hold space.
+.Pp
+.It [1addr]i\e
+.It text
+Write
+.Em text
+to the standard output.
+.Pp
+.It [2addr]l
+(The letter ell.)
+Write the pattern space to the standard output in a visually unambiguous
+form.
+This form is as follows:
+.Pp
+.Bl -tag -width "carriage-returnXX" -offset indent -compact
+.It backslash
+\e\e
+.It alert
+\ea
+.It form-feed
+\ef
+.It carriage-return
+\er
+.It tab
+\et
+.It vertical tab
+\ev
+.El
+.Pp
+Nonprintable characters are written as three-digit octal numbers (with a
+preceding backslash) for each byte in the character (most significant byte
+first).
+Long lines are folded, with the point of folding indicated by displaying
+a backslash followed by a newline.
+The end of each line is marked with a
+.Dq $ .
+.Pp
+.It [2addr]n
+Write the pattern space to the standard output if the default output has
+not been suppressed, and replace the pattern space with the next line of
+input.
+.Pp
+.It [2addr]N
+Append the next line of input to the pattern space, using an embedded
+newline character to separate the appended material from the original
+contents.
+Note that the current line number changes.
+.Pp
+.It [2addr]p
+Write the pattern space to standard output.
+.Pp
+.It [2addr]P
+Write the pattern space, up to the first newline character to the
+standard output.
+.Pp
+.It [1addr]q
+Branch to the end of the script and quit without starting a new cycle.
+.Pp
+.It [1addr]r file
+Copy the contents of
+.Em file
+to the standard output immediately before the next attempt to read a
+line of input.
+If
+.Em file
+cannot be read for any reason, it is silently ignored and no error
+condition is set.
+.Pp
+.It [2addr]s/regular expression/replacement/flags
+Substitute the replacement string for the first instance of the regular
+expression in the pattern space.
+Any character other than backslash or newline can be used instead of
+a slash to delimit the RE and the replacement.
+Within the RE and the replacement, the RE delimiter itself can be used as
+a literal character if it is preceded by a backslash.
+.Pp
+An ampersand
+.Pq Dq &
+appearing in the replacement is replaced by the string matching the RE.
+The special meaning of
+.Dq &
+in this context can be suppressed by preceding it by a backslash.
+The string
+.Dq \e# ,
+where
+.Dq #
+is a digit, is replaced by the text matched
+by the corresponding backreference expression (see
+.Xr re_format 7 ) .
+.Pp
+A line can be split by substituting a newline character into it.
+To specify a newline character in the replacement string, precede it with
+a backslash.
+.Pp
+The value of
+.Em flags
+in the substitute function is zero or more of the following:
+.Bl -tag -width "XXXXXX" -offset indent
+.It Ar N
+Make the substitution only for the
+.Ar N Ns 'th
+occurrence of the regular expression in the pattern space.
+.It g
+Make the substitution for all non-overlapping matches of the
+regular expression, not just the first one.
+.It p
+Write the pattern space to standard output if a replacement was made.
+If the replacement string is identical to that which it replaces, it
+is still considered to have been a replacement.
+.It w Em file
+Append the pattern space to
+.Em file
+if a replacement was made.
+If the replacement string is identical to that which it replaces, it
+is still considered to have been a replacement.
+.It i or I
+Match the regular expression in a case-insensitive way.
+.El
+.Pp
+.It [2addr]t [label]
+Branch to the
+.Dq \&:
+function bearing the label if any substitutions have been made since the
+most recent reading of an input line or execution of a
+.Dq t
+function.
+If no label is specified, branch to the end of the script.
+.Pp
+.It [2addr]w Em file
+Append the pattern space to the
+.Em file .
+.Pp
+.It [2addr]x
+Swap the contents of the pattern and hold spaces.
+.Pp
+.It [2addr]y/string1/string2/
+Replace all occurrences of characters in
+.Em string1
+in the pattern space with the corresponding characters from
+.Em string2 .
+Any character other than a backslash or newline can be used instead of
+a slash to delimit the strings.
+Within
+.Em string1
+and
+.Em string2 ,
+a backslash followed by any character other than a newline is that literal
+character, and a backslash followed by an ``n'' is replaced by a newline
+character.
+.Pp
+.It [2addr]!function
+.It [2addr]!function-list
+Apply the function or function-list only to the lines that are
+.Em not
+selected by the address(es).
+.Pp
+.It [0addr]:label
+This function does nothing; it bears a label to which the
+.Dq b
+and
+.Dq t
+commands may branch.
+.Pp
+.It [1addr]=
+Write the line number to the standard output followed by a newline
+character.
+.Pp
+.It [0addr]
+Empty lines are ignored.
+.Pp
+.It [0addr]#
+The
+.Dq #
+and the remainder of the line are ignored (treated as a comment), with
+the single exception that if the first two characters in the file are
+.Dq #n ,
+the default output is suppressed.
+This is the same as specifying the
+.Fl n
+option on the command line.
+.El
+.Sh ENVIRONMENT
+The
+.Ev COLUMNS , LANG , LC_ALL , LC_CTYPE
+and
+.Ev LC_COLLATE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Replace
+.Ql bar
+with
+.Ql baz
+when piped from another command:
+.Bd -literal -offset indent
+echo "An alternate word, like bar, is sometimes used in examples." | sed 's/bar/baz/'
+.Ed
+.Pp
+Using backlashes can sometimes be hard to read and follow:
+.Bd -literal -offset indent
+echo "/home/example" | sed 's/\\/home\\/example/\\/usr\\/local\\/example/'
+.Ed
+.Pp
+Using a different separator can be handy when working with paths:
+.Bd -literal -offset indent
+echo "/home/example" | sed 's#/home/example#/usr/local/example#'
+.Ed
+.Pp
+Replace all occurances of
+.Ql foo
+with
+.Ql bar
+in the file
+.Pa test.txt ,
+without creating a backup of the file:
+.Bd -literal -offset indent
+sed -i '' -e 's/foo/bar/g' test.txt
+.Ed
+.Sh SEE ALSO
+.Xr awk 1 ,
+.Xr ed 1 ,
+.Xr grep 1 ,
+.Xr regex 3 ,
+.Xr re_format 7
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2
+specification.
+.Pp
+The
+.Fl E , I , a
+and
+.Fl i
+options, the prefixing
+.Dq \&+
+in the second member of an address range,
+as well as the
+.Dq I
+flag to the address regular expression and substitution command are
+non-standard
+.Fx
+extensions and may not be available on other operating systems.
+.Sh HISTORY
+A
+.Nm
+command, written by
+.An L. E. McMahon ,
+appeared in
+.At v7 .
+.Sh AUTHORS
+.An Diomidis D. Spinellis Aq Mt dds@FreeBSD.org
+.Sh BUGS
+Multibyte characters containing a byte with value 0x5C
+.Tn ( ASCII
+.Ql \e )
+may be incorrectly treated as line continuation characters in arguments to the
+.Dq a ,
+.Dq c
+and
+.Dq i
+commands.
+Multibyte characters cannot be used as delimiters with the
+.Dq s
+and
+.Dq y
+commands.
diff --git a/text_cmds/sort/bwstring.c b/text_cmds/sort/bwstring.c
new file mode 100644
index 0000000..3b7b233
--- /dev/null
+++ b/text_cmds/sort/bwstring.c
@@ -0,0 +1,1142 @@
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <ctype.h>
+#include <errno.h>
+#include <err.h>
+#include <langinfo.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "bwstring.h"
+#include "sort.h"
+
+bool byte_sort;
+
+static wchar_t **wmonths;
+static unsigned char **cmonths;
+
+/* initialise months */
+
+void
+initialise_months(void)
+{
+ const nl_item item[12] = { ABMON_1, ABMON_2, ABMON_3, ABMON_4,
+ ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10,
+ ABMON_11, ABMON_12 };
+ unsigned char *tmp;
+ size_t len;
+
+ if (MB_CUR_MAX == 1) {
+ if (cmonths == NULL) {
+ unsigned char *m;
+
+ cmonths = sort_malloc(sizeof(unsigned char*) * 12);
+ for (int i = 0; i < 12; i++) {
+ cmonths[i] = NULL;
+ tmp = (unsigned char *) nl_langinfo(item[i]);
+ if (debug_sort)
+ printf("month[%d]=%s\n", i, tmp);
+ if (*tmp == '\0')
+ continue;
+ m = sort_strdup(tmp);
+ len = strlen(tmp);
+ for (unsigned int j = 0; j < len; j++)
+ m[j] = toupper(m[j]);
+ cmonths[i] = m;
+ }
+ }
+
+ } else {
+ if (wmonths == NULL) {
+ wchar_t *m;
+
+ wmonths = sort_malloc(sizeof(wchar_t *) * 12);
+ for (int i = 0; i < 12; i++) {
+ wmonths[i] = NULL;
+ tmp = (unsigned char *) nl_langinfo(item[i]);
+ if (debug_sort)
+ printf("month[%d]=%s\n", i, tmp);
+ if (*tmp == '\0')
+ continue;
+ len = strlen(tmp);
+ m = sort_malloc(SIZEOF_WCHAR_STRING(len + 1));
+ if (mbstowcs(m, (char*)tmp, len) ==
+ ((size_t) - 1)) {
+ sort_free(m);
+ continue;
+ }
+ m[len] = L'\0';
+ for (unsigned int j = 0; j < len; j++)
+ m[j] = towupper(m[j]);
+ wmonths[i] = m;
+ }
+ }
+ }
+}
+
+/*
+ * Compare two wide-character strings
+ */
+static int
+wide_str_coll(const wchar_t *s1, const wchar_t *s2)
+{
+ int ret = 0;
+
+ errno = 0;
+ ret = wcscoll(s1, s2);
+ if (errno == EILSEQ) {
+ errno = 0;
+ ret = wcscmp(s1, s2);
+ if (errno != 0) {
+ for (size_t i = 0; ; ++i) {
+ wchar_t c1 = s1[i];
+ wchar_t c2 = s2[i];
+ if (c1 == L'\0')
+ return ((c2 == L'\0') ? 0 : -1);
+ if (c2 == L'\0')
+ return (+1);
+ if (c1 == c2)
+ continue;
+ return ((int)(c1 - c2));
+ }
+ }
+ }
+ return (ret);
+}
+
+/* counterparts of wcs functions */
+
+void
+bwsprintf(FILE *f, struct bwstring *bws, const char *prefix, const char *suffix)
+{
+
+ if (MB_CUR_MAX == 1)
+ fprintf(f, "%s%s%s", prefix, bws->data.cstr, suffix);
+ else
+ fprintf(f, "%s%S%s", prefix, bws->data.wstr, suffix);
+}
+
+const void* bwsrawdata(const struct bwstring *bws)
+{
+
+ return (&(bws->data));
+}
+
+size_t bwsrawlen(const struct bwstring *bws)
+{
+
+ return ((MB_CUR_MAX == 1) ? bws->len : SIZEOF_WCHAR_STRING(bws->len));
+}
+
+size_t
+bws_memsize(const struct bwstring *bws)
+{
+
+ return ((MB_CUR_MAX == 1) ? (bws->len + 2 + sizeof(struct bwstring)) :
+ (SIZEOF_WCHAR_STRING(bws->len + 1) + sizeof(struct bwstring)));
+}
+
+void
+bws_setlen(struct bwstring *bws, size_t newlen)
+{
+
+ if (bws && newlen != bws->len && newlen <= bws->len) {
+ bws->len = newlen;
+ if (MB_CUR_MAX == 1)
+ bws->data.cstr[newlen] = '\0';
+ else
+ bws->data.wstr[newlen] = L'\0';
+ }
+}
+
+/*
+ * Allocate a new binary string of specified size
+ */
+struct bwstring *
+bwsalloc(size_t sz)
+{
+ struct bwstring *ret;
+
+ if (MB_CUR_MAX == 1)
+ ret = sort_malloc(sizeof(struct bwstring) + 1 + sz);
+ else
+ ret = sort_malloc(sizeof(struct bwstring) +
+ SIZEOF_WCHAR_STRING(sz + 1));
+ ret->len = sz;
+
+ if (MB_CUR_MAX == 1)
+ ret->data.cstr[ret->len] = '\0';
+ else
+ ret->data.wstr[ret->len] = L'\0';
+
+ return (ret);
+}
+
+/*
+ * Create a copy of binary string.
+ * New string size equals the length of the old string.
+ */
+struct bwstring *
+bwsdup(const struct bwstring *s)
+{
+
+ if (s == NULL)
+ return (NULL);
+ else {
+ struct bwstring *ret = bwsalloc(s->len);
+
+ if (MB_CUR_MAX == 1)
+ memcpy(ret->data.cstr, s->data.cstr, (s->len));
+ else
+ memcpy(ret->data.wstr, s->data.wstr,
+ SIZEOF_WCHAR_STRING(s->len));
+
+ return (ret);
+ }
+}
+
+/*
+ * Create a new binary string from a wide character buffer.
+ */
+struct bwstring *
+bwssbdup(const wchar_t *str, size_t len)
+{
+
+ if (str == NULL)
+ return ((len == 0) ? bwsalloc(0) : NULL);
+ else {
+ struct bwstring *ret;
+
+ ret = bwsalloc(len);
+
+ if (MB_CUR_MAX == 1)
+ for (size_t i = 0; i < len; ++i)
+ ret->data.cstr[i] = (unsigned char) str[i];
+ else
+ memcpy(ret->data.wstr, str, SIZEOF_WCHAR_STRING(len));
+
+ return (ret);
+ }
+}
+
+/*
+ * Create a new binary string from a raw binary buffer.
+ */
+struct bwstring *
+bwscsbdup(const unsigned char *str, size_t len)
+{
+ struct bwstring *ret;
+
+ ret = bwsalloc(len);
+
+ if (str) {
+ if (MB_CUR_MAX == 1)
+ memcpy(ret->data.cstr, str, len);
+ else {
+ mbstate_t mbs;
+ const char *s;
+ size_t charlen, chars, cptr;
+
+ chars = 0;
+ cptr = 0;
+ s = (const char *) str;
+
+ memset(&mbs, 0, sizeof(mbs));
+
+ while (cptr < len) {
+ size_t n = MB_CUR_MAX;
+
+ if (n > len - cptr)
+ n = len - cptr;
+ charlen = mbrlen(s + cptr, n, &mbs);
+ switch (charlen) {
+ case 0:
+ /* FALLTHROUGH */
+ case (size_t) -1:
+ /* FALLTHROUGH */
+ case (size_t) -2:
+ ret->data.wstr[chars++] =
+ (unsigned char) s[cptr];
+ ++cptr;
+ break;
+ default:
+ n = mbrtowc(ret->data.wstr + (chars++),
+ s + cptr, charlen, &mbs);
+ if ((n == (size_t)-1) || (n == (size_t)-2))
+ /* NOTREACHED */
+ err(2, "mbrtowc error");
+ cptr += charlen;
+ }
+ }
+
+ ret->len = chars;
+ ret->data.wstr[ret->len] = L'\0';
+ }
+ }
+ return (ret);
+}
+
+/*
+ * De-allocate object memory
+ */
+void
+bwsfree(const struct bwstring *s)
+{
+
+ if (s)
+ sort_free(s);
+}
+
+/*
+ * Copy content of src binary string to dst.
+ * If the capacity of the dst string is not sufficient,
+ * then the data is truncated.
+ */
+size_t
+bwscpy(struct bwstring *dst, const struct bwstring *src)
+{
+ size_t nums = src->len;
+
+ if (nums > dst->len)
+ nums = dst->len;
+ dst->len = nums;
+
+ if (MB_CUR_MAX == 1) {
+ memcpy(dst->data.cstr, src->data.cstr, nums);
+ dst->data.cstr[dst->len] = '\0';
+ } else {
+ memcpy(dst->data.wstr, src->data.wstr,
+ SIZEOF_WCHAR_STRING(nums + 1));
+ dst->data.wstr[dst->len] = L'\0';
+ }
+
+ return (nums);
+}
+
+/*
+ * Copy content of src binary string to dst,
+ * with specified number of symbols to be copied.
+ * If the capacity of the dst string is not sufficient,
+ * then the data is truncated.
+ */
+struct bwstring *
+bwsncpy(struct bwstring *dst, const struct bwstring *src, size_t size)
+{
+ size_t nums = src->len;
+
+ if (nums > dst->len)
+ nums = dst->len;
+ if (nums > size)
+ nums = size;
+ dst->len = nums;
+
+ if (MB_CUR_MAX == 1) {
+ memcpy(dst->data.cstr, src->data.cstr, nums);
+ dst->data.cstr[dst->len] = '\0';
+ } else {
+ memcpy(dst->data.wstr, src->data.wstr,
+ SIZEOF_WCHAR_STRING(nums + 1));
+ dst->data.wstr[dst->len] = L'\0';
+ }
+
+ return (dst);
+}
+
+/*
+ * Copy content of src binary string to dst,
+ * with specified number of symbols to be copied.
+ * An offset value can be specified, from the start of src string.
+ * If the capacity of the dst string is not sufficient,
+ * then the data is truncated.
+ */
+struct bwstring *
+bwsnocpy(struct bwstring *dst, const struct bwstring *src, size_t offset,
+ size_t size)
+{
+
+ if (offset >= src->len) {
+ dst->data.wstr[0] = 0;
+ dst->len = 0;
+ } else {
+ size_t nums = src->len - offset;
+
+ if (nums > dst->len)
+ nums = dst->len;
+ if (nums > size)
+ nums = size;
+ dst->len = nums;
+ if (MB_CUR_MAX == 1) {
+ memcpy(dst->data.cstr, src->data.cstr + offset,
+ (nums));
+ dst->data.cstr[dst->len] = '\0';
+ } else {
+ memcpy(dst->data.wstr, src->data.wstr + offset,
+ SIZEOF_WCHAR_STRING(nums));
+ dst->data.wstr[dst->len] = L'\0';
+ }
+ }
+ return (dst);
+}
+
+/*
+ * Write binary string to the file.
+ * The output is ended either with '\n' (nl == true)
+ * or '\0' (nl == false).
+ */
+size_t
+bwsfwrite(struct bwstring *bws, FILE *f, bool zero_ended)
+{
+
+ if (MB_CUR_MAX == 1) {
+ size_t len = bws->len;
+
+ if (!zero_ended) {
+ bws->data.cstr[len] = '\n';
+
+ if (fwrite(bws->data.cstr, len + 1, 1, f) < 1)
+ err(2, NULL);
+
+ bws->data.cstr[len] = '\0';
+ } else if (fwrite(bws->data.cstr, len + 1, 1, f) < 1)
+ err(2, NULL);
+
+ return (len + 1);
+
+ } else {
+ wchar_t eols;
+ size_t printed = 0;
+
+ eols = zero_ended ? btowc('\0') : btowc('\n');
+
+ while (printed < BWSLEN(bws)) {
+ const wchar_t *s = bws->data.wstr + printed;
+
+ if (*s == L'\0') {
+ int nums;
+
+ nums = fwprintf(f, L"%lc", *s);
+
+ if (nums != 1)
+ err(2, NULL);
+ ++printed;
+ } else {
+ int nums;
+
+ nums = fwprintf(f, L"%ls", s);
+
+ if (nums < 1)
+ err(2, NULL);
+ printed += nums;
+ }
+ }
+ fwprintf(f, L"%lc", eols);
+ return (printed + 1);
+ }
+}
+
+/*
+ * Allocate and read a binary string from file.
+ * The strings are nl-ended or zero-ended, depending on the sort setting.
+ */
+struct bwstring *
+bwsfgetln(FILE *f, size_t *len, bool zero_ended, struct reader_buffer *rb)
+{
+ wint_t eols;
+
+ eols = zero_ended ? btowc('\0') : btowc('\n');
+
+ if (!zero_ended && (MB_CUR_MAX > 1)) {
+ wchar_t *ret;
+
+ ret = fgetwln(f, len);
+
+ if (ret == NULL) {
+ if (!feof(f))
+ err(2, NULL);
+ return (NULL);
+ }
+ if (*len > 0) {
+ if (ret[*len - 1] == (wchar_t)eols)
+ --(*len);
+ }
+ return (bwssbdup(ret, *len));
+
+ } else if (!zero_ended && (MB_CUR_MAX == 1)) {
+ char *ret;
+
+ ret = fgetln(f, len);
+
+ if (ret == NULL) {
+ if (!feof(f))
+ err(2, NULL);
+ return (NULL);
+ }
+ if (*len > 0) {
+ if (ret[*len - 1] == '\n')
+ --(*len);
+ }
+ return (bwscsbdup((unsigned char*)ret, *len));
+
+ } else {
+ *len = 0;
+
+ if (feof(f))
+ return (NULL);
+
+ if (2 >= rb->fgetwln_z_buffer_size) {
+ rb->fgetwln_z_buffer_size += 256;
+ rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
+ sizeof(wchar_t) * rb->fgetwln_z_buffer_size);
+ }
+ rb->fgetwln_z_buffer[*len] = 0;
+
+ if (MB_CUR_MAX == 1)
+ while (!feof(f)) {
+ int c;
+
+ c = fgetc(f);
+
+ if (c == EOF) {
+ if (*len == 0)
+ return (NULL);
+ goto line_read_done;
+ }
+ if (c == eols)
+ goto line_read_done;
+
+ if (*len + 1 >= rb->fgetwln_z_buffer_size) {
+ rb->fgetwln_z_buffer_size += 256;
+ rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
+ SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
+ }
+
+ rb->fgetwln_z_buffer[*len] = c;
+ rb->fgetwln_z_buffer[++(*len)] = 0;
+ }
+ else
+ while (!feof(f)) {
+ wint_t c = 0;
+
+ c = fgetwc(f);
+
+ if (c == WEOF) {
+ if (*len == 0)
+ return (NULL);
+ goto line_read_done;
+ }
+ if (c == eols)
+ goto line_read_done;
+
+ if (*len + 1 >= rb->fgetwln_z_buffer_size) {
+ rb->fgetwln_z_buffer_size += 256;
+ rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
+ SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
+ }
+
+ rb->fgetwln_z_buffer[*len] = c;
+ rb->fgetwln_z_buffer[++(*len)] = 0;
+ }
+
+line_read_done:
+ /* we do not count the last 0 */
+ return (bwssbdup(rb->fgetwln_z_buffer, *len));
+ }
+}
+
+int
+bwsncmp(const struct bwstring *bws1, const struct bwstring *bws2,
+ size_t offset, size_t len)
+{
+ size_t cmp_len, len1, len2;
+ int res = 0;
+
+ len1 = bws1->len;
+ len2 = bws2->len;
+
+ if (len1 <= offset) {
+ return ((len2 <= offset) ? 0 : -1);
+ } else {
+ if (len2 <= offset)
+ return (+1);
+ else {
+ len1 -= offset;
+ len2 -= offset;
+
+ cmp_len = len1;
+
+ if (len2 < cmp_len)
+ cmp_len = len2;
+
+ if (len < cmp_len)
+ cmp_len = len;
+
+ if (MB_CUR_MAX == 1) {
+ const unsigned char *s1, *s2;
+
+ s1 = bws1->data.cstr + offset;
+ s2 = bws2->data.cstr + offset;
+
+ res = memcmp(s1, s2, cmp_len);
+
+ } else {
+ const wchar_t *s1, *s2;
+
+ s1 = bws1->data.wstr + offset;
+ s2 = bws2->data.wstr + offset;
+
+ res = memcmp(s1, s2, SIZEOF_WCHAR_STRING(cmp_len));
+ }
+ }
+ }
+
+ if (res == 0) {
+ if (len1 < cmp_len && len1 < len2)
+ res = -1;
+ else if (len2 < cmp_len && len2 < len1)
+ res = +1;
+ }
+
+ return (res);
+}
+
+int
+bwscmp(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
+{
+ size_t len1, len2, cmp_len;
+ int res;
+
+ len1 = bws1->len;
+ len2 = bws2->len;
+
+ len1 -= offset;
+ len2 -= offset;
+
+ cmp_len = len1;
+
+ if (len2 < cmp_len)
+ cmp_len = len2;
+
+ res = bwsncmp(bws1, bws2, offset, cmp_len);
+
+ if (res == 0) {
+ if( len1 < len2)
+ res = -1;
+ else if (len2 < len1)
+ res = +1;
+ }
+
+ return (res);
+}
+
+int
+bws_iterator_cmp(bwstring_iterator iter1, bwstring_iterator iter2, size_t len)
+{
+ wchar_t c1, c2;
+ size_t i = 0;
+
+ for (i = 0; i < len; ++i) {
+ c1 = bws_get_iter_value(iter1);
+ c2 = bws_get_iter_value(iter2);
+ if (c1 != c2)
+ return (c1 - c2);
+ iter1 = bws_iterator_inc(iter1, 1);
+ iter2 = bws_iterator_inc(iter2, 1);
+ }
+
+ return (0);
+}
+
+int
+bwscoll(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
+{
+ size_t len1, len2;
+
+ len1 = bws1->len;
+ len2 = bws2->len;
+
+ if (len1 <= offset)
+ return ((len2 <= offset) ? 0 : -1);
+ else {
+ if (len2 <= offset)
+ return (+1);
+ else {
+ len1 -= offset;
+ len2 -= offset;
+
+ if (MB_CUR_MAX == 1) {
+ const unsigned char *s1, *s2;
+
+ s1 = bws1->data.cstr + offset;
+ s2 = bws2->data.cstr + offset;
+
+ if (byte_sort) {
+ int res = 0;
+
+ if (len1 > len2) {
+ res = memcmp(s1, s2, len2);
+ if (!res)
+ res = +1;
+ } else if (len1 < len2) {
+ res = memcmp(s1, s2, len1);
+ if (!res)
+ res = -1;
+ } else
+ res = memcmp(s1, s2, len1);
+
+ return (res);
+
+ } else {
+ int res = 0;
+ size_t i, maxlen;
+
+ i = 0;
+ maxlen = len1;
+
+ if (maxlen > len2)
+ maxlen = len2;
+
+ while (i < maxlen) {
+ /* goto next non-zero part: */
+ while ((i < maxlen) &&
+ !s1[i] && !s2[i])
+ ++i;
+
+ if (i >= maxlen)
+ break;
+
+ if (s1[i] == 0) {
+ if (s2[i] == 0)
+ /* NOTREACHED */
+ err(2, "bwscoll error 01");
+ else
+ return (-1);
+ } else if (s2[i] == 0)
+ return (+1);
+
+ res = strcoll((const char*)(s1 + i), (const char*)(s2 + i));
+ if (res)
+ return (res);
+
+ while ((i < maxlen) &&
+ s1[i] && s2[i])
+ ++i;
+
+ if (i >= maxlen)
+ break;
+
+ if (s1[i] == 0) {
+ if (s2[i] == 0) {
+ ++i;
+ continue;
+ } else
+ return (-1);
+ } else if (s2[i] == 0)
+ return (+1);
+ else
+ /* NOTREACHED */
+ err(2, "bwscoll error 02");
+ }
+
+ if (len1 < len2)
+ return (-1);
+ else if (len1 > len2)
+ return (+1);
+
+ return (0);
+ }
+ } else {
+ const wchar_t *s1, *s2;
+ size_t i, maxlen;
+ int res = 0;
+
+ s1 = bws1->data.wstr + offset;
+ s2 = bws2->data.wstr + offset;
+
+ i = 0;
+ maxlen = len1;
+
+ if (maxlen > len2)
+ maxlen = len2;
+
+ while (i < maxlen) {
+
+ /* goto next non-zero part: */
+ while ((i < maxlen) &&
+ !s1[i] && !s2[i])
+ ++i;
+
+ if (i >= maxlen)
+ break;
+
+ if (s1[i] == 0) {
+ if (s2[i] == 0)
+ /* NOTREACHED */
+ err(2, "bwscoll error 1");
+ else
+ return (-1);
+ } else if (s2[i] == 0)
+ return (+1);
+
+ res = wide_str_coll(s1 + i, s2 + i);
+ if (res)
+ return (res);
+
+ while ((i < maxlen) && s1[i] && s2[i])
+ ++i;
+
+ if (i >= maxlen)
+ break;
+
+ if (s1[i] == 0) {
+ if (s2[i] == 0) {
+ ++i;
+ continue;
+ } else
+ return (-1);
+ } else if (s2[i] == 0)
+ return (+1);
+ else
+ /* NOTREACHED */
+ err(2, "bwscoll error 2");
+ }
+
+ if (len1 < len2)
+ return (-1);
+ else if (len1 > len2)
+ return (+1);
+
+ return (0);
+ }
+ }
+ }
+}
+
+/*
+ * Correction of the system API
+ */
+double
+bwstod(struct bwstring *s0, bool *empty)
+{
+ double ret = 0;
+
+ if (MB_CUR_MAX == 1) {
+ unsigned char *end, *s;
+ char *ep;
+
+ s = s0->data.cstr;
+ end = s + s0->len;
+ ep = NULL;
+
+ while (isblank_f(*s) && s < end)
+ ++s;
+
+ if (!isprint(*s)) {
+ *empty = true;
+ return (0);
+ }
+
+ ret = strtod((char*)s, &ep);
+ if ((unsigned char*) ep == s) {
+ *empty = true;
+ return (0);
+ }
+ } else {
+ wchar_t *end, *ep, *s;
+
+ s = s0->data.wstr;
+ end = s + s0->len;
+ ep = NULL;
+
+ while (iswblank_f(*s) && s < end)
+ ++s;
+
+ if (!iswprint(*s)) {
+ *empty = true;
+ return (0);
+ }
+
+ ret = wcstod(s, &ep);
+ if (ep == s) {
+ *empty = true;
+ return (0);
+ }
+ }
+
+ *empty = false;
+ return (ret);
+}
+
+/*
+ * A helper function for monthcoll. If a line matches
+ * a month name, it returns (number of the month - 1),
+ * while if there is no match, it just return -1.
+ */
+
+int
+bws_month_score(const struct bwstring *s0)
+{
+
+ if (MB_CUR_MAX == 1) {
+ const unsigned char *end, *s;
+
+ s = s0->data.cstr;
+ end = s + s0->len;
+
+ while (isblank_f(*s) && s < end)
+ ++s;
+
+ for (int i = 11; i >= 0; --i) {
+ if (cmonths[i] &&
+ (s == (unsigned char*)strstr((const char*)s, (char*)(cmonths[i]))))
+ return (i);
+ }
+
+ } else {
+ const wchar_t *end, *s;
+
+ s = s0->data.wstr;
+ end = s + s0->len;
+
+ while (iswblank_f(*s) && s < end)
+ ++s;
+
+ for (int i = 11; i >= 0; --i) {
+ if (wmonths[i] && (s == wcsstr(s, wmonths[i])))
+ return (i);
+ }
+ }
+
+ return (-1);
+}
+
+/*
+ * Rips out leading blanks (-b).
+ */
+struct bwstring *
+ignore_leading_blanks(struct bwstring *str)
+{
+
+ if (MB_CUR_MAX == 1) {
+ unsigned char *dst, *end, *src;
+
+ src = str->data.cstr;
+ dst = src;
+ end = src + str->len;
+
+ while (src < end && isblank_f(*src))
+ ++src;
+
+ if (src != dst) {
+ size_t newlen;
+
+ newlen = BWSLEN(str) - (src - dst);
+
+ while (src < end) {
+ *dst = *src;
+ ++dst;
+ ++src;
+ }
+ bws_setlen(str, newlen);
+ }
+ } else {
+ wchar_t *dst, *end, *src;
+
+ src = str->data.wstr;
+ dst = src;
+ end = src + str->len;
+
+ while (src < end && iswblank_f(*src))
+ ++src;
+
+ if (src != dst) {
+
+ size_t newlen = BWSLEN(str) - (src - dst);
+
+ while (src < end) {
+ *dst = *src;
+ ++dst;
+ ++src;
+ }
+ bws_setlen(str, newlen);
+
+ }
+ }
+ return (str);
+}
+
+/*
+ * Rips out nonprinting characters (-i).
+ */
+struct bwstring *
+ignore_nonprinting(struct bwstring *str)
+{
+ size_t newlen = str->len;
+
+ if (MB_CUR_MAX == 1) {
+ unsigned char *dst, *end, *src;
+ unsigned char c;
+
+ src = str->data.cstr;
+ dst = src;
+ end = src + str->len;
+
+ while (src < end) {
+ c = *src;
+ if (isprint(c)) {
+ *dst = c;
+ ++dst;
+ ++src;
+ } else {
+ ++src;
+ --newlen;
+ }
+ }
+ } else {
+ wchar_t *dst, *end, *src;
+ wchar_t c;
+
+ src = str->data.wstr;
+ dst = src;
+ end = src + str->len;
+
+ while (src < end) {
+ c = *src;
+ if (iswprint(c)) {
+ *dst = c;
+ ++dst;
+ ++src;
+ } else {
+ ++src;
+ --newlen;
+ }
+ }
+ }
+ bws_setlen(str, newlen);
+
+ return (str);
+}
+
+/*
+ * Rips out any characters that are not alphanumeric characters
+ * nor blanks (-d).
+ */
+struct bwstring *
+dictionary_order(struct bwstring *str)
+{
+ size_t newlen = str->len;
+
+ if (MB_CUR_MAX == 1) {
+ unsigned char *dst, *end, *src;
+ unsigned char c;
+
+ src = str->data.cstr;
+ dst = src;
+ end = src + str->len;
+
+ while (src < end) {
+ c = *src;
+ if (isalnum(c) || isblank_f(c)) {
+ *dst = c;
+ ++dst;
+ ++src;
+ } else {
+ ++src;
+ --newlen;
+ }
+ }
+ } else {
+ wchar_t *dst, *end, *src;
+ wchar_t c;
+
+ src = str->data.wstr;
+ dst = src;
+ end = src + str->len;
+
+ while (src < end) {
+ c = *src;
+ if (iswalnum(c) || iswblank_f(c)) {
+ *dst = c;
+ ++dst;
+ ++src;
+ } else {
+ ++src;
+ --newlen;
+ }
+ }
+ }
+ bws_setlen(str, newlen);
+
+ return (str);
+}
+
+/*
+ * Converts string to lower case(-f).
+ */
+struct bwstring *
+ignore_case(struct bwstring *str)
+{
+
+ if (MB_CUR_MAX == 1) {
+ unsigned char *end, *s;
+
+ s = str->data.cstr;
+ end = s + str->len;
+
+ while (s < end) {
+ *s = toupper(*s);
+ ++s;
+ }
+ } else {
+ wchar_t *end, *s;
+
+ s = str->data.wstr;
+ end = s + str->len;
+
+ while (s < end) {
+ *s = towupper(*s);
+ ++s;
+ }
+ }
+ return (str);
+}
+
+void
+bws_disorder_warnx(struct bwstring *s, const char *fn, size_t pos)
+{
+
+ if (MB_CUR_MAX == 1)
+ warnx("%s:%zu: disorder: %s", fn, pos + 1, s->data.cstr);
+ else
+ warnx("%s:%zu: disorder: %ls", fn, pos + 1, s->data.wstr);
+}
diff --git a/text_cmds/sort/bwstring.h b/text_cmds/sort/bwstring.h
new file mode 100644
index 0000000..857de13
--- /dev/null
+++ b/text_cmds/sort/bwstring.h
@@ -0,0 +1,142 @@
+/* $FreeBSD: head/usr.bin/sort/bwstring.h 264744 2014-04-21 22:52:18Z pfg $ */
+
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 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.
+ */
+
+#if !defined(__BWSTRING_H__)
+#define __BWSTRING_H__
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sysexits.h>
+#include <wchar.h>
+
+#include "mem.h"
+
+extern bool byte_sort;
+
+/* wchar_t is of 4 bytes: */
+#define SIZEOF_WCHAR_STRING(LEN) ((LEN)*sizeof(wchar_t))
+
+/*
+ * Binary "wide" string
+ */
+struct bwstring
+{
+ size_t len;
+ union
+ {
+ wchar_t wstr[0];
+ unsigned char cstr[0];
+ } data;
+};
+
+struct reader_buffer
+{
+ wchar_t *fgetwln_z_buffer;
+ size_t fgetwln_z_buffer_size;
+};
+
+typedef void *bwstring_iterator;
+
+#define BWSLEN(s) ((s)->len)
+
+struct bwstring *bwsalloc(size_t sz);
+
+size_t bwsrawlen(const struct bwstring *bws);
+const void* bwsrawdata(const struct bwstring *bws);
+void bws_setlen(struct bwstring *bws, size_t newlen);
+size_t bws_memsize(const struct bwstring *bws);
+double bwstod(struct bwstring *s0, bool *empty);
+int bws_month_score(const struct bwstring *s0);
+
+struct bwstring *ignore_leading_blanks(struct bwstring *str);
+struct bwstring *ignore_nonprinting(struct bwstring *str);
+struct bwstring *dictionary_order(struct bwstring *str);
+struct bwstring *ignore_case(struct bwstring *str);
+
+void bwsprintf(FILE*, struct bwstring*, const char *prefix, const char *suffix);
+void bws_disorder_warnx(struct bwstring *s, const char *fn, size_t pos);
+
+struct bwstring *bwsdup(const struct bwstring *s);
+struct bwstring *bwssbdup(const wchar_t *str, size_t size);
+struct bwstring *bwscsbdup(const unsigned char *str, size_t size);
+void bwsfree(const struct bwstring *s);
+size_t bwscpy(struct bwstring *dst, const struct bwstring *src);
+struct bwstring *bwsncpy(struct bwstring *dst, const struct bwstring *src, size_t size);
+struct bwstring *bwsnocpy(struct bwstring *dst, const struct bwstring *src, size_t offset, size_t size);
+int bwscmp(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset);
+int bwsncmp(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset, size_t len);
+int bwscoll(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset);
+size_t bwsfwrite(struct bwstring *bws, FILE *f, bool zero_ended);
+struct bwstring *bwsfgetln(FILE *file, size_t *len, bool zero_ended, struct reader_buffer *rb);
+
+static inline bwstring_iterator
+bws_begin(struct bwstring *bws)
+{
+
+ return (bwstring_iterator) (&(bws->data));
+}
+
+static inline bwstring_iterator
+bws_end(struct bwstring *bws)
+{
+
+ return ((MB_CUR_MAX == 1) ?
+ (bwstring_iterator) (bws->data.cstr + bws->len) :
+ (bwstring_iterator) (bws->data.wstr + bws->len));
+}
+
+static inline bwstring_iterator
+bws_iterator_inc(bwstring_iterator iter, size_t pos)
+{
+
+ if (MB_CUR_MAX == 1)
+ return ((unsigned char *) iter) + pos;
+ else
+ return ((wchar_t*) iter) + pos;
+}
+
+static inline wchar_t
+bws_get_iter_value(bwstring_iterator iter)
+{
+
+ if (MB_CUR_MAX == 1)
+ return *((unsigned char *) iter);
+ else
+ return *((wchar_t*) iter);
+}
+
+int
+bws_iterator_cmp(bwstring_iterator iter1, bwstring_iterator iter2, size_t len);
+
+#define BWS_GET(bws, pos) ((MB_CUR_MAX == 1) ? ((bws)->data.cstr[(pos)]) : (bws)->data.wstr[(pos)])
+
+void initialise_months(void);
+
+#endif /* __BWSTRING_H__ */
diff --git a/text_cmds/sort/coll.c b/text_cmds/sort/coll.c
new file mode 100644
index 0000000..f87ae0c
--- /dev/null
+++ b/text_cmds/sort/coll.c
@@ -0,0 +1,1324 @@
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <err.h>
+#include <langinfo.h>
+#include <limits.h>
+#include <math.h>
+#ifndef __APPLE__
+#include <md5.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "coll.h"
+#include "vsort.h"
+
+struct key_specs *keys;
+size_t keys_num = 0;
+
+wint_t symbol_decimal_point = L'.';
+/* there is no default thousands separator in collate rules: */
+wint_t symbol_thousands_sep = 0;
+wint_t symbol_negative_sign = L'-';
+wint_t symbol_positive_sign = L'+';
+
+static int wstrcoll(struct key_value *kv1, struct key_value *kv2, size_t offset);
+static int gnumcoll(struct key_value*, struct key_value *, size_t offset);
+static int monthcoll(struct key_value*, struct key_value *, size_t offset);
+static int numcoll(struct key_value*, struct key_value *, size_t offset);
+static int hnumcoll(struct key_value*, struct key_value *, size_t offset);
+static int randomcoll(struct key_value*, struct key_value *, size_t offset);
+static int versioncoll(struct key_value*, struct key_value *, size_t offset);
+
+/*
+ * Allocate keys array
+ */
+struct keys_array *
+keys_array_alloc(void)
+{
+ struct keys_array *ka;
+ size_t sz;
+
+ sz = keys_array_size();
+ ka = sort_malloc(sz);
+ memset(ka, 0, sz);
+
+ return (ka);
+}
+
+/*
+ * Calculate whether we need key hint space
+ */
+static size_t
+key_hint_size(void)
+{
+
+ return (need_hint ? sizeof(struct key_hint) : 0);
+}
+
+/*
+ * Calculate keys array size
+ */
+size_t
+keys_array_size(void)
+{
+
+ return (keys_num * (sizeof(struct key_value) + key_hint_size()));
+}
+
+/*
+ * Clean data of keys array
+ */
+void
+clean_keys_array(const struct bwstring *s, struct keys_array *ka)
+{
+
+ if (ka) {
+ for (size_t i = 0; i < keys_num; ++i) {
+ const struct key_value *kv;
+
+ kv = get_key_from_keys_array(ka, i);
+ if (kv->k && kv->k != s)
+ bwsfree(kv->k);
+ }
+ memset(ka, 0, keys_array_size());
+ }
+}
+
+/*
+ * Get pointer to a key value in the keys set
+ */
+struct key_value *
+get_key_from_keys_array(struct keys_array *ka, size_t ind)
+{
+
+ return ((struct key_value *)((caddr_t)ka->key +
+ ind * (sizeof(struct key_value) + key_hint_size())));
+}
+
+/*
+ * Set value of a key in the keys set
+ */
+void
+set_key_on_keys_array(struct keys_array *ka, struct bwstring *s, size_t ind)
+{
+
+ if (ka && keys_num > ind) {
+ struct key_value *kv;
+
+ kv = get_key_from_keys_array(ka, ind);
+
+ if (kv->k && kv->k != s)
+ bwsfree(kv->k);
+ kv->k = s;
+ }
+}
+
+/*
+ * Initialize a sort list item
+ */
+struct sort_list_item *
+sort_list_item_alloc(void)
+{
+ struct sort_list_item *si;
+ size_t sz;
+
+ sz = sizeof(struct sort_list_item) + keys_array_size();
+ si = sort_malloc(sz);
+ memset(si, 0, sz);
+
+ return (si);
+}
+
+size_t
+sort_list_item_size(struct sort_list_item *si)
+{
+ size_t ret = 0;
+
+ if (si) {
+ ret = sizeof(struct sort_list_item) + keys_array_size();
+ if (si->str)
+ ret += bws_memsize(si->str);
+ for (size_t i = 0; i < keys_num; ++i) {
+ const struct key_value *kv;
+
+ kv = get_key_from_keys_array(&si->ka, i);
+
+ if (kv->k != si->str)
+ ret += bws_memsize(kv->k);
+ }
+ }
+ return (ret);
+}
+
+/*
+ * Calculate key for a sort list item
+ */
+static void
+sort_list_item_make_key(struct sort_list_item *si)
+{
+
+ preproc(si->str, &(si->ka));
+}
+
+/*
+ * Set value of a sort list item.
+ * Return combined string and keys memory size.
+ */
+void
+sort_list_item_set(struct sort_list_item *si, struct bwstring *str)
+{
+
+ if (si) {
+ clean_keys_array(si->str, &(si->ka));
+ if (si->str) {
+ if (si->str == str) {
+ /* we are trying to reset the same string */
+ return;
+ } else {
+ bwsfree(si->str);
+ si->str = NULL;
+ }
+ }
+ si->str = str;
+ sort_list_item_make_key(si);
+ }
+}
+
+/*
+ * De-allocate a sort list item object memory
+ */
+void
+sort_list_item_clean(struct sort_list_item *si)
+{
+
+ if (si) {
+ clean_keys_array(si->str, &(si->ka));
+ if (si->str) {
+ bwsfree(si->str);
+ si->str = NULL;
+ }
+ }
+}
+
+/*
+ * Skip columns according to specs
+ */
+static size_t
+skip_cols_to_start(const struct bwstring *s, size_t cols, size_t start,
+ bool skip_blanks, bool *empty_key)
+{
+ if (cols < 1)
+ return (BWSLEN(s) + 1);
+
+ if (skip_blanks)
+ while (start < BWSLEN(s) && iswblank_f(BWS_GET(s,start)))
+ ++start;
+
+ while (start < BWSLEN(s) && cols > 1) {
+ --cols;
+ ++start;
+ }
+
+ if (start >= BWSLEN(s))
+ *empty_key = true;
+
+ return (start);
+}
+
+/*
+ * Skip fields according to specs
+ */
+static size_t
+skip_fields_to_start(const struct bwstring *s, size_t fields, bool *empty_field)
+{
+
+ if (fields < 2) {
+ if (BWSLEN(s) == 0)
+ *empty_field = true;
+ return (0);
+ } else if (!(sort_opts_vals.tflag)) {
+ size_t cpos = 0;
+ bool pb = true;
+
+ while (cpos < BWSLEN(s)) {
+ bool isblank;
+
+ isblank = iswblank_f(BWS_GET(s, cpos));
+
+ if (isblank && !pb) {
+ --fields;
+ if (fields <= 1)
+ return (cpos);
+ }
+ pb = isblank;
+ ++cpos;
+ }
+ if (fields > 1)
+ *empty_field = true;
+ return (cpos);
+ } else {
+ size_t cpos = 0;
+
+ while (cpos < BWSLEN(s)) {
+ if (BWS_GET(s,cpos) == (wchar_t)sort_opts_vals.field_sep) {
+ --fields;
+ if (fields <= 1)
+ return (cpos + 1);
+ }
+ ++cpos;
+ }
+ if (fields > 1)
+ *empty_field = true;
+ return (cpos);
+ }
+}
+
+/*
+ * Find fields start
+ */
+static void
+find_field_start(const struct bwstring *s, struct key_specs *ks,
+ size_t *field_start, size_t *key_start, bool *empty_field, bool *empty_key)
+{
+
+ *field_start = skip_fields_to_start(s, ks->f1, empty_field);
+ if (!*empty_field)
+ *key_start = skip_cols_to_start(s, ks->c1, *field_start,
+ ks->pos1b, empty_key);
+ else
+ *empty_key = true;
+}
+
+/*
+ * Find end key position
+ */
+static size_t
+find_field_end(const struct bwstring *s, struct key_specs *ks)
+{
+ size_t f2, next_field_start, pos_end;
+ bool empty_field, empty_key;
+
+ empty_field = false;
+ empty_key = false;
+ f2 = ks->f2;
+
+ if (f2 == 0)
+ return (BWSLEN(s) + 1);
+ else {
+ if (ks->c2 == 0) {
+ next_field_start = skip_fields_to_start(s, f2 + 1,
+ &empty_field);
+ if ((next_field_start > 0) && sort_opts_vals.tflag &&
+ ((wchar_t)sort_opts_vals.field_sep == BWS_GET(s,
+ next_field_start - 1)))
+ --next_field_start;
+ } else
+ next_field_start = skip_fields_to_start(s, f2,
+ &empty_field);
+ }
+
+ if (empty_field || (next_field_start >= BWSLEN(s)))
+ return (BWSLEN(s) + 1);
+
+ if (ks->c2) {
+ pos_end = skip_cols_to_start(s, ks->c2, next_field_start,
+ ks->pos2b, &empty_key);
+ if (pos_end < BWSLEN(s))
+ ++pos_end;
+ } else
+ pos_end = next_field_start;
+
+ return (pos_end);
+}
+
+/*
+ * Cut a field according to the key specs
+ */
+static struct bwstring *
+cut_field(const struct bwstring *s, struct key_specs *ks)
+{
+ struct bwstring *ret = NULL;
+
+ if (s && ks) {
+ size_t field_start, key_end, key_start, sz;
+ bool empty_field, empty_key;
+
+ field_start = 0;
+ key_start = 0;
+ empty_field = false;
+ empty_key = false;
+
+ find_field_start(s, ks, &field_start, &key_start,
+ &empty_field, &empty_key);
+
+ if (empty_key)
+ sz = 0;
+ else {
+ key_end = find_field_end(s, ks);
+ sz = (key_end < key_start) ? 0 : (key_end - key_start);
+ }
+
+ ret = bwsalloc(sz);
+ if (sz)
+ bwsnocpy(ret, s, key_start, sz);
+ } else
+ ret = bwsalloc(0);
+
+ return (ret);
+}
+
+/*
+ * Preprocesses a line applying the necessary transformations
+ * specified by command line options and returns the preprocessed
+ * string, which can be used to compare.
+ */
+int
+preproc(struct bwstring *s, struct keys_array *ka)
+{
+
+ if (sort_opts_vals.kflag)
+ for (size_t i = 0; i < keys_num; i++) {
+ struct bwstring *key;
+ struct key_specs *kspecs;
+ struct sort_mods *sm;
+
+ kspecs = &(keys[i]);
+ key = cut_field(s, kspecs);
+
+ sm = &(kspecs->sm);
+ if (sm->dflag)
+ key = dictionary_order(key);
+ else if (sm->iflag)
+ key = ignore_nonprinting(key);
+ if (sm->fflag || sm->Mflag)
+ key = ignore_case(key);
+
+ set_key_on_keys_array(ka, key, i);
+ }
+ else {
+ struct bwstring *ret = NULL;
+ struct sort_mods *sm = default_sort_mods;
+
+ if (sm->bflag) {
+ if (ret == NULL)
+ ret = bwsdup(s);
+ ret = ignore_leading_blanks(ret);
+ }
+ if (sm->dflag) {
+ if (ret == NULL)
+ ret = bwsdup(s);
+ ret = dictionary_order(ret);
+ } else if (sm->iflag) {
+ if (ret == NULL)
+ ret = bwsdup(s);
+ ret = ignore_nonprinting(ret);
+ }
+ if (sm->fflag || sm->Mflag) {
+ if (ret == NULL)
+ ret = bwsdup(s);
+ ret = ignore_case(ret);
+ }
+ if (ret == NULL)
+ set_key_on_keys_array(ka, s, 0);
+ else
+ set_key_on_keys_array(ka, ret, 0);
+ }
+
+ return 0;
+}
+
+cmpcoll_t
+get_sort_func(struct sort_mods *sm)
+{
+
+ if (sm->nflag)
+ return (numcoll);
+ else if (sm->hflag)
+ return (hnumcoll);
+ else if (sm->gflag)
+ return (gnumcoll);
+ else if (sm->Mflag)
+ return (monthcoll);
+ else if (sm->Rflag)
+ return (randomcoll);
+ else if (sm->Vflag)
+ return (versioncoll);
+ else
+ return (wstrcoll);
+}
+
+/*
+ * Compares the given strings. Returns a positive number if
+ * the first precedes the second, a negative number if the second is
+ * the preceding one, and zero if they are equal. This function calls
+ * the underlying collate functions, which done the actual comparison.
+ */
+int
+key_coll(struct keys_array *ps1, struct keys_array *ps2, size_t offset)
+{
+ struct key_value *kv1, *kv2;
+ struct sort_mods *sm;
+ int res = 0;
+
+ for (size_t i = 0; i < keys_num; ++i) {
+ kv1 = get_key_from_keys_array(ps1, i);
+ kv2 = get_key_from_keys_array(ps2, i);
+ sm = &(keys[i].sm);
+
+ if (sm->rflag)
+ res = sm->func(kv2, kv1, offset);
+ else
+ res = sm->func(kv1, kv2, offset);
+
+ if (res)
+ break;
+
+ /* offset applies to only the first key */
+ offset = 0;
+ }
+ return (res);
+}
+
+/*
+ * Compare two strings.
+ * Plain symbol-by-symbol comparison.
+ */
+int
+top_level_str_coll(const struct bwstring *s1, const struct bwstring *s2)
+{
+
+ if (default_sort_mods->rflag) {
+ const struct bwstring *tmp;
+
+ tmp = s1;
+ s1 = s2;
+ s2 = tmp;
+ }
+
+ return (bwscoll(s1, s2, 0));
+}
+
+/*
+ * Compare a string and a sort list item, according to the sort specs.
+ */
+int
+str_list_coll(struct bwstring *str1, struct sort_list_item **ss2)
+{
+ struct keys_array *ka1;
+ int ret = 0;
+
+ ka1 = keys_array_alloc();
+
+ preproc(str1, ka1);
+
+ sort_list_item_make_key(*ss2);
+
+ if (debug_sort) {
+ bwsprintf(stdout, str1, "; s1=<", ">");
+ bwsprintf(stdout, (*ss2)->str, ", s2=<", ">");
+ }
+
+ ret = key_coll(ka1, &((*ss2)->ka), 0);
+
+ if (debug_sort)
+ printf("; cmp1=%d", ret);
+
+ clean_keys_array(str1, ka1);
+ sort_free(ka1);
+
+ if ((ret == 0) && !(sort_opts_vals.sflag) && sort_opts_vals.complex_sort) {
+ ret = top_level_str_coll(str1, ((*ss2)->str));
+ if (debug_sort)
+ printf("; cmp2=%d", ret);
+ }
+
+ if (debug_sort)
+ printf("\n");
+
+ return (ret);
+}
+
+/*
+ * Compare two sort list items, according to the sort specs.
+ */
+int
+list_coll_offset(struct sort_list_item **ss1, struct sort_list_item **ss2,
+ size_t offset)
+{
+ int ret;
+
+ ret = key_coll(&((*ss1)->ka), &((*ss2)->ka), offset);
+
+ if (debug_sort) {
+ if (offset)
+ printf("; offset=%d", (int) offset);
+ bwsprintf(stdout, ((*ss1)->str), "; s1=<", ">");
+ bwsprintf(stdout, ((*ss2)->str), ", s2=<", ">");
+ printf("; cmp1=%d\n", ret);
+ }
+
+ if (ret)
+ return (ret);
+
+ if (!(sort_opts_vals.sflag) && sort_opts_vals.complex_sort) {
+ ret = top_level_str_coll(((*ss1)->str), ((*ss2)->str));
+ if (debug_sort)
+ printf("; cmp2=%d\n", ret);
+ }
+
+ return (ret);
+}
+
+/*
+ * Compare two sort list items, according to the sort specs.
+ */
+int
+list_coll(struct sort_list_item **ss1, struct sort_list_item **ss2)
+{
+
+ return (list_coll_offset(ss1, ss2, 0));
+}
+
+#define LSCDEF(N) \
+static int \
+list_coll_##N(struct sort_list_item **ss1, struct sort_list_item **ss2) \
+{ \
+ \
+ return (list_coll_offset(ss1, ss2, N)); \
+}
+
+LSCDEF(1)
+LSCDEF(2)
+LSCDEF(3)
+LSCDEF(4)
+LSCDEF(5)
+LSCDEF(6)
+LSCDEF(7)
+LSCDEF(8)
+LSCDEF(9)
+LSCDEF(10)
+LSCDEF(11)
+LSCDEF(12)
+LSCDEF(13)
+LSCDEF(14)
+LSCDEF(15)
+LSCDEF(16)
+LSCDEF(17)
+LSCDEF(18)
+LSCDEF(19)
+LSCDEF(20)
+
+listcoll_t
+get_list_call_func(size_t offset)
+{
+ static const listcoll_t lsarray[] = { list_coll, list_coll_1,
+ list_coll_2, list_coll_3, list_coll_4, list_coll_5,
+ list_coll_6, list_coll_7, list_coll_8, list_coll_9,
+ list_coll_10, list_coll_11, list_coll_12, list_coll_13,
+ list_coll_14, list_coll_15, list_coll_16, list_coll_17,
+ list_coll_18, list_coll_19, list_coll_20 };
+
+ if (offset <= 20)
+ return (lsarray[offset]);
+
+ return (list_coll);
+}
+
+/*
+ * Compare two sort list items, only by their original string.
+ */
+int
+list_coll_by_str_only(struct sort_list_item **ss1, struct sort_list_item **ss2)
+{
+
+ return (top_level_str_coll(((*ss1)->str), ((*ss2)->str)));
+}
+
+/*
+ * Maximum size of a number in the string (before or after decimal point)
+ */
+#define MAX_NUM_SIZE (128)
+
+/*
+ * Set suffix value
+ */
+static void setsuffix(wchar_t c, unsigned char *si)
+{
+ switch (c){
+ case L'k':
+ case L'K':
+ *si = 1;
+ break;
+ case L'M':
+ *si = 2;
+ break;
+ case L'G':
+ *si = 3;
+ break;
+ case L'T':
+ *si = 4;
+ break;
+ case L'P':
+ *si = 5;
+ break;
+ case L'E':
+ *si = 6;
+ break;
+ case L'Z':
+ *si = 7;
+ break;
+ case L'Y':
+ *si = 8;
+ break;
+ default:
+ *si = 0;
+ }
+}
+
+/*
+ * Read string s and parse the string into a fixed-decimal-point number.
+ * sign equals -1 if the number is negative (explicit plus is not allowed,
+ * according to GNU sort's "info sort".
+ * The number part before decimal point is in the smain, after the decimal
+ * point is in sfrac, tail is the pointer to the remainder of the string.
+ */
+static int
+read_number(struct bwstring *s0, int *sign, wchar_t *smain, size_t *main_len, wchar_t *sfrac, size_t *frac_len, unsigned char *si)
+{
+ bwstring_iterator s;
+ bool prev_thousand_sep = false;
+
+ s = bws_begin(s0);
+
+ /* always end the fraction with zero, even if we have no fraction */
+ sfrac[0] = 0;
+
+ while (iswblank_f(bws_get_iter_value(s)))
+ s = bws_iterator_inc(s, 1);
+
+ if (bws_get_iter_value(s) == (wchar_t)symbol_negative_sign) {
+ *sign = -1;
+ s = bws_iterator_inc(s, 1);
+ }
+
+ // This is '0', not '\0', do not change this
+ while (iswdigit(bws_get_iter_value(s)) &&
+ (bws_get_iter_value(s) == L'0'))
+ s = bws_iterator_inc(s, 1);
+
+ while (bws_get_iter_value(s) && *main_len < MAX_NUM_SIZE) {
+ if (iswdigit(bws_get_iter_value(s))) {
+ smain[*main_len] = bws_get_iter_value(s);
+ s = bws_iterator_inc(s, 1);
+ *main_len += 1;
+ prev_thousand_sep = false;
+ } else if (symbol_thousands_sep
+ && (bws_get_iter_value(s) == (wchar_t)symbol_thousands_sep)
+ && (!prev_thousand_sep)
+ ) {
+ s = bws_iterator_inc(s, 1);
+ prev_thousand_sep = true;
+ } else
+ break;
+ }
+
+ smain[*main_len] = 0;
+
+ if (bws_get_iter_value(s) == (wchar_t)symbol_decimal_point) {
+ s = bws_iterator_inc(s, 1);
+ while (iswdigit(bws_get_iter_value(s)) &&
+ *frac_len < MAX_NUM_SIZE) {
+ sfrac[*frac_len] = bws_get_iter_value(s);
+ s = bws_iterator_inc(s, 1);
+ *frac_len += 1;
+ }
+ sfrac[*frac_len] = 0;
+
+ while (*frac_len > 0 && sfrac[*frac_len - 1] == L'0') {
+ --(*frac_len);
+ sfrac[*frac_len] = L'\0';
+ }
+ }
+
+ setsuffix(bws_get_iter_value(s),si);
+
+ if ((*main_len + *frac_len) == 0)
+ *sign = 0;
+
+ return (0);
+}
+
+/*
+ * Implements string sort.
+ */
+static int
+wstrcoll(struct key_value *kv1, struct key_value *kv2, size_t offset)
+{
+
+ if (debug_sort) {
+ if (offset)
+ printf("; offset=%d\n", (int) offset);
+ bwsprintf(stdout, kv1->k, "; k1=<", ">");
+ printf("(%zu)", BWSLEN(kv1->k));
+ bwsprintf(stdout, kv2->k, ", k2=<", ">");
+ printf("(%zu)", BWSLEN(kv2->k));
+ }
+
+ return (bwscoll(kv1->k, kv2->k, offset));
+}
+
+/*
+ * Compare two suffixes
+ */
+static inline int
+cmpsuffix(unsigned char si1, unsigned char si2)
+{
+
+ return ((char)si1 - (char)si2);
+}
+
+/*
+ * Implements numeric sort for -n and -h.
+ */
+static int
+numcoll_impl(struct key_value *kv1, struct key_value *kv2,
+ size_t offset __unused, bool use_suffix)
+{
+ struct bwstring *s1, *s2;
+ wchar_t sfrac1[MAX_NUM_SIZE + 1], sfrac2[MAX_NUM_SIZE + 1];
+ wchar_t smain1[MAX_NUM_SIZE + 1], smain2[MAX_NUM_SIZE + 1];
+ int cmp_res, sign1, sign2;
+ size_t frac1, frac2, main1, main2;
+ unsigned char SI1, SI2;
+ bool e1, e2, key1_read, key2_read;
+
+ s1 = kv1->k;
+ s2 = kv2->k;
+ sign1 = sign2 = 0;
+ main1 = main2 = 0;
+ frac1 = frac2 = 0;
+
+ key1_read = key2_read = false;
+
+ if (debug_sort) {
+ bwsprintf(stdout, s1, "; k1=<", ">");
+ bwsprintf(stdout, s2, ", k2=<", ">");
+ }
+
+ if (s1 == s2)
+ return (0);
+
+ if (kv1->hint->status == HS_UNINITIALIZED) {
+ /* read the number from the string */
+ read_number(s1, &sign1, smain1, &main1, sfrac1, &frac1, &SI1);
+ key1_read = true;
+ kv1->hint->v.nh.n1 = wcstoull(smain1, NULL, 10);
+ if(main1 < 1 && frac1 < 1)
+ kv1->hint->v.nh.empty=true;
+ kv1->hint->v.nh.si = SI1;
+ kv1->hint->status = (kv1->hint->v.nh.n1 != ULLONG_MAX) ?
+ HS_INITIALIZED : HS_ERROR;
+ kv1->hint->v.nh.neg = (sign1 < 0) ? true : false;
+ }
+
+ if (kv2->hint->status == HS_UNINITIALIZED) {
+ /* read the number from the string */
+ read_number(s2, &sign2, smain2, &main2, sfrac2, &frac2,&SI2);
+ key2_read = true;
+ kv2->hint->v.nh.n1 = wcstoull(smain2, NULL, 10);
+ if(main2 < 1 && frac2 < 1)
+ kv2->hint->v.nh.empty=true;
+ kv2->hint->v.nh.si = SI2;
+ kv2->hint->status = (kv2->hint->v.nh.n1 != ULLONG_MAX) ?
+ HS_INITIALIZED : HS_ERROR;
+ kv2->hint->v.nh.neg = (sign2 < 0) ? true : false;
+ }
+
+ if (kv1->hint->status == HS_INITIALIZED && kv2->hint->status ==
+ HS_INITIALIZED) {
+ unsigned long long n1, n2;
+ bool neg1, neg2;
+
+ e1 = kv1->hint->v.nh.empty;
+ e2 = kv2->hint->v.nh.empty;
+
+ if (e1 && e2)
+ return (0);
+
+ neg1 = kv1->hint->v.nh.neg;
+ neg2 = kv2->hint->v.nh.neg;
+
+ if (neg1 && !neg2)
+ return (-1);
+ if (neg2 && !neg1)
+ return (+1);
+
+ if (e1)
+ return (neg2 ? +1 : -1);
+ else if (e2)
+ return (neg1 ? -1 : +1);
+
+
+ if (use_suffix) {
+ cmp_res = cmpsuffix(kv1->hint->v.nh.si, kv2->hint->v.nh.si);
+ if (cmp_res)
+ return (neg1 ? -cmp_res : cmp_res);
+ }
+
+ n1 = kv1->hint->v.nh.n1;
+ n2 = kv2->hint->v.nh.n1;
+ if (n1 < n2)
+ return (neg1 ? +1 : -1);
+ else if (n1 > n2)
+ return (neg1 ? -1 : +1);
+ }
+
+ /* read the numbers from the strings */
+ if (!key1_read)
+ read_number(s1, &sign1, smain1, &main1, sfrac1, &frac1, &SI1);
+ if (!key2_read)
+ read_number(s2, &sign2, smain2, &main2, sfrac2, &frac2, &SI2);
+
+ e1 = ((main1 + frac1) == 0);
+ e2 = ((main2 + frac2) == 0);
+
+ if (e1 && e2)
+ return (0);
+
+ /* we know the result if the signs are different */
+ if (sign1 < 0 && sign2 >= 0)
+ return (-1);
+ if (sign1 >= 0 && sign2 < 0)
+ return (+1);
+
+ if (e1)
+ return ((sign2 < 0) ? +1 : -1);
+ else if (e2)
+ return ((sign1 < 0) ? -1 : +1);
+
+ if (use_suffix) {
+ cmp_res = cmpsuffix(SI1, SI2);
+ if (cmp_res)
+ return ((sign1 < 0) ? -cmp_res : cmp_res);
+ }
+
+ /* if both numbers are empty assume that the strings are equal */
+ if (main1 < 1 && main2 < 1 && frac1 < 1 && frac2 < 1)
+ return (0);
+
+ /*
+ * if the main part is of different size, we know the result
+ * (because the leading zeros are removed)
+ */
+ if (main1 < main2)
+ cmp_res = -1;
+ else if (main1 > main2)
+ cmp_res = +1;
+ /* if the sizes are equal then simple non-collate string compare gives the correct result */
+ else
+ cmp_res = wcscmp(smain1, smain2);
+
+ /* check fraction */
+ if (!cmp_res)
+ cmp_res = wcscmp(sfrac1, sfrac2);
+
+ if (!cmp_res)
+ return (0);
+
+ /* reverse result if the signs are negative */
+ if (sign1 < 0 && sign2 < 0)
+ cmp_res = -cmp_res;
+
+ return (cmp_res);
+}
+
+/*
+ * Implements numeric sort (-n).
+ */
+static int
+numcoll(struct key_value *kv1, struct key_value *kv2, size_t offset)
+{
+
+ return (numcoll_impl(kv1, kv2, offset, false));
+}
+
+/*
+ * Implements 'human' numeric sort (-h).
+ */
+static int
+hnumcoll(struct key_value *kv1, struct key_value *kv2, size_t offset)
+{
+
+ return (numcoll_impl(kv1, kv2, offset, true));
+}
+
+/*
+ * Implements random sort (-R).
+ */
+static int
+randomcoll(struct key_value *kv1, struct key_value *kv2,
+ size_t offset __unused)
+{
+ struct bwstring *s1, *s2;
+ MD5_CTX ctx1, ctx2;
+ char *b1, *b2;
+
+ s1 = kv1->k;
+ s2 = kv2->k;
+
+ if (debug_sort) {
+ bwsprintf(stdout, s1, "; k1=<", ">");
+ bwsprintf(stdout, s2, ", k2=<", ">");
+ }
+
+ if (s1 == s2)
+ return (0);
+
+ memcpy(&ctx1,&md5_ctx,sizeof(MD5_CTX));
+ memcpy(&ctx2,&md5_ctx,sizeof(MD5_CTX));
+
+ MD5Update(&ctx1, bwsrawdata(s1), bwsrawlen(s1));
+ MD5Update(&ctx2, bwsrawdata(s2), bwsrawlen(s2));
+ b1 = MD5End(&ctx1, NULL);
+ b2 = MD5End(&ctx2, NULL);
+ if (b1 == NULL) {
+ if (b2 == NULL)
+ return (0);
+ else {
+ sort_free(b2);
+ return (-1);
+ }
+ } else if (b2 == NULL) {
+ sort_free(b1);
+ return (+1);
+ } else {
+ int cmp_res;
+
+ cmp_res = strcmp(b1,b2);
+ sort_free(b1);
+ sort_free(b2);
+
+ if (!cmp_res)
+ cmp_res = bwscoll(s1, s2, 0);
+
+ return (cmp_res);
+ }
+}
+
+/*
+ * Implements version sort (-V).
+ */
+static int
+versioncoll(struct key_value *kv1, struct key_value *kv2,
+ size_t offset __unused)
+{
+ struct bwstring *s1, *s2;
+
+ s1 = kv1->k;
+ s2 = kv2->k;
+
+ if (debug_sort) {
+ bwsprintf(stdout, s1, "; k1=<", ">");
+ bwsprintf(stdout, s2, ", k2=<", ">");
+ }
+
+ if (s1 == s2)
+ return (0);
+
+ return (vcmp(s1, s2));
+}
+
+/*
+ * Check for minus infinity
+ */
+static inline bool
+huge_minus(double d, int err1)
+{
+
+ if (err1 == ERANGE)
+ if (d == -HUGE_VAL || d == -HUGE_VALF || d == -HUGE_VALL)
+ return (+1);
+
+ return (0);
+}
+
+/*
+ * Check for plus infinity
+ */
+static inline bool
+huge_plus(double d, int err1)
+{
+
+ if (err1 == ERANGE)
+ if (d == HUGE_VAL || d == HUGE_VALF || d == HUGE_VALL)
+ return (+1);
+
+ return (0);
+}
+
+/*
+ * Check whether a function is a NAN
+ */
+static bool
+is_nan(double d)
+{
+
+ return ((d == NAN) || (isnan(d)));
+}
+
+/*
+ * Compare two NANs
+ */
+static int
+cmp_nans(double d1, double d2)
+{
+
+ if (d1 < d2)
+ return (-1);
+ if (d1 > d2)
+ return (+1);
+ return (0);
+}
+
+/*
+ * Implements general numeric sort (-g).
+ */
+static int
+gnumcoll(struct key_value *kv1, struct key_value *kv2,
+ size_t offset __unused)
+{
+ double d1, d2;
+ int err1, err2;
+ bool empty1, empty2, key1_read, key2_read;
+
+ d1 = d2 = 0;
+ err1 = err2 = 0;
+ key1_read = key2_read = false;
+
+ if (debug_sort) {
+ bwsprintf(stdout, kv1->k, "; k1=<", ">");
+ bwsprintf(stdout, kv2->k, "; k2=<", ">");
+ }
+
+ if (kv1->hint->status == HS_UNINITIALIZED) {
+ errno = 0;
+ d1 = bwstod(kv1->k, &empty1);
+ err1 = errno;
+
+ if (empty1)
+ kv1->hint->v.gh.notnum = true;
+ else if (err1 == 0) {
+ kv1->hint->v.gh.d = d1;
+ kv1->hint->v.gh.nan = is_nan(d1);
+ kv1->hint->status = HS_INITIALIZED;
+ } else
+ kv1->hint->status = HS_ERROR;
+
+ key1_read = true;
+ }
+
+ if (kv2->hint->status == HS_UNINITIALIZED) {
+ errno = 0;
+ d2 = bwstod(kv2->k, &empty2);
+ err2 = errno;
+
+ if (empty2)
+ kv2->hint->v.gh.notnum = true;
+ else if (err2 == 0) {
+ kv2->hint->v.gh.d = d2;
+ kv2->hint->v.gh.nan = is_nan(d2);
+ kv2->hint->status = HS_INITIALIZED;
+ } else
+ kv2->hint->status = HS_ERROR;
+
+ key2_read = true;
+ }
+
+ if (kv1->hint->status == HS_INITIALIZED &&
+ kv2->hint->status == HS_INITIALIZED) {
+ if (kv1->hint->v.gh.notnum)
+ return ((kv2->hint->v.gh.notnum) ? 0 : -1);
+ else if (kv2->hint->v.gh.notnum)
+ return (+1);
+
+ if (kv1->hint->v.gh.nan)
+ return ((kv2->hint->v.gh.nan) ?
+ cmp_nans(kv1->hint->v.gh.d, kv2->hint->v.gh.d) :
+ -1);
+ else if (kv2->hint->v.gh.nan)
+ return (+1);
+
+ d1 = kv1->hint->v.gh.d;
+ d2 = kv2->hint->v.gh.d;
+
+ if (d1 < d2)
+ return (-1);
+ else if (d1 > d2)
+ return (+1);
+ else
+ return (0);
+ }
+
+ if (!key1_read) {
+ errno = 0;
+ d1 = bwstod(kv1->k, &empty1);
+ err1 = errno;
+ }
+
+ if (!key2_read) {
+ errno = 0;
+ d2 = bwstod(kv2->k, &empty2);
+ err2 = errno;
+ }
+
+ /* Non-value case: */
+ if (empty1)
+ return (empty2 ? 0 : -1);
+ else if (empty2)
+ return (+1);
+
+ /* NAN case */
+ if (is_nan(d1))
+ return (is_nan(d2) ? cmp_nans(d1, d2) : -1);
+ else if (is_nan(d2))
+ return (+1);
+
+ /* Infinities */
+ if (err1 == ERANGE || err2 == ERANGE) {
+ /* Minus infinity case */
+ if (huge_minus(d1, err1)) {
+ if (huge_minus(d2, err2)) {
+ if (d1 < d2)
+ return (-1);
+ if (d1 > d2)
+ return (+1);
+ return (0);
+ } else
+ return (-1);
+
+ } else if (huge_minus(d2, err2)) {
+ if (huge_minus(d1, err1)) {
+ if (d1 < d2)
+ return (-1);
+ if (d1 > d2)
+ return (+1);
+ return (0);
+ } else
+ return (+1);
+ }
+
+ /* Plus infinity case */
+ if (huge_plus(d1, err1)) {
+ if (huge_plus(d2, err2)) {
+ if (d1 < d2)
+ return (-1);
+ if (d1 > d2)
+ return (+1);
+ return (0);
+ } else
+ return (+1);
+ } else if (huge_plus(d2, err2)) {
+ if (huge_plus(d1, err1)) {
+ if (d1 < d2)
+ return (-1);
+ if (d1 > d2)
+ return (+1);
+ return (0);
+ } else
+ return (-1);
+ }
+ }
+
+ if (d1 < d2)
+ return (-1);
+ if (d1 > d2)
+ return (+1);
+
+ return (0);
+}
+
+/*
+ * Implements month sort (-M).
+ */
+static int
+monthcoll(struct key_value *kv1, struct key_value *kv2, size_t offset __unused)
+{
+ int val1, val2;
+ bool key1_read, key2_read;
+
+ val1 = val2 = 0;
+ key1_read = key2_read = false;
+
+ if (debug_sort) {
+ bwsprintf(stdout, kv1->k, "; k1=<", ">");
+ bwsprintf(stdout, kv2->k, "; k2=<", ">");
+ }
+
+ if (kv1->hint->status == HS_UNINITIALIZED) {
+ kv1->hint->v.Mh.m = bws_month_score(kv1->k);
+ key1_read = true;
+ kv1->hint->status = HS_INITIALIZED;
+ }
+
+ if (kv2->hint->status == HS_UNINITIALIZED) {
+ kv2->hint->v.Mh.m = bws_month_score(kv2->k);
+ key2_read = true;
+ kv2->hint->status = HS_INITIALIZED;
+ }
+
+ if (kv1->hint->status == HS_INITIALIZED) {
+ val1 = kv1->hint->v.Mh.m;
+ key1_read = true;
+ }
+
+ if (kv2->hint->status == HS_INITIALIZED) {
+ val2 = kv2->hint->v.Mh.m;
+ key2_read = true;
+ }
+
+ if (!key1_read)
+ val1 = bws_month_score(kv1->k);
+ if (!key2_read)
+ val2 = bws_month_score(kv2->k);
+
+ if (val1 == val2) {
+ return (0);
+ }
+ if (val1 < val2)
+ return (-1);
+ return (+1);
+}
diff --git a/text_cmds/sort/coll.h b/text_cmds/sort/coll.h
new file mode 100644
index 0000000..6e3f9b4
--- /dev/null
+++ b/text_cmds/sort/coll.h
@@ -0,0 +1,168 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 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.
+ */
+
+#if !defined(__COLL_H__)
+#define __COLL_H__
+
+#include "bwstring.h"
+#include "sort.h"
+
+/*
+ * Sort hint data for -n
+ */
+struct n_hint
+{
+ unsigned long long n1;
+ unsigned char si;
+ bool empty;
+ bool neg;
+};
+
+/*
+ * Sort hint data for -g
+ */
+struct g_hint
+{
+ double d;
+ bool nan;
+ bool notnum;
+};
+
+/*
+ * Sort hint data for -M
+ */
+struct M_hint
+{
+ int m;
+};
+
+/*
+ * Status of a sort hint object
+ */
+typedef enum
+{
+ HS_ERROR = -1, HS_UNINITIALIZED = 0, HS_INITIALIZED = 1
+} hint_status;
+
+/*
+ * Sort hint object
+ */
+struct key_hint
+{
+ hint_status status;
+ union
+ {
+ struct n_hint nh;
+ struct g_hint gh;
+ struct M_hint Mh;
+ } v;
+};
+
+/*
+ * Key value
+ */
+struct key_value
+{
+ struct bwstring *k; /* key string */
+ struct key_hint hint[0]; /* key sort hint */
+} __packed;
+
+/*
+ * Set of keys container object.
+ */
+struct keys_array
+{
+ struct key_value key[0];
+};
+
+/*
+ * Parsed -k option data
+ */
+struct key_specs
+{
+ struct sort_mods sm;
+ size_t c1;
+ size_t c2;
+ size_t f1;
+ size_t f2;
+ bool pos1b;
+ bool pos2b;
+};
+
+/*
+ * Single entry in sort list.
+ */
+struct sort_list_item
+{
+ struct bwstring *str;
+ struct keys_array ka;
+};
+
+/*
+ * Function type, used to compare two list objects
+ */
+typedef int (*listcoll_t)(struct sort_list_item **ss1, struct sort_list_item **ss2);
+
+extern struct key_specs *keys;
+extern size_t keys_num;
+
+/*
+ * Main localised symbols. These must be wint_t as they may hold WEOF.
+ */
+extern wint_t symbol_decimal_point;
+extern wint_t symbol_thousands_sep;
+extern wint_t symbol_negative_sign;
+extern wint_t symbol_positive_sign;
+
+/* funcs */
+
+cmpcoll_t get_sort_func(struct sort_mods *sm);
+
+struct keys_array *keys_array_alloc(void);
+size_t keys_array_size(void);
+struct key_value *get_key_from_keys_array(struct keys_array *ka, size_t ind);
+void set_key_on_keys_array(struct keys_array *ka, struct bwstring *s, size_t ind);
+void clean_keys_array(const struct bwstring *s, struct keys_array *ka);
+
+struct sort_list_item *sort_list_item_alloc(void);
+void sort_list_item_set(struct sort_list_item *si, struct bwstring *str);
+void sort_list_item_clean(struct sort_list_item *si);
+size_t sort_list_item_size(struct sort_list_item *si);
+
+int preproc(struct bwstring *s, struct keys_array *ka);
+int top_level_str_coll(const struct bwstring *, const struct bwstring *);
+int key_coll(struct keys_array *ks1, struct keys_array *ks2, size_t offset);
+int str_list_coll(struct bwstring *str1, struct sort_list_item **ss2);
+int list_coll_by_str_only(struct sort_list_item **ss1, struct sort_list_item **ss2);
+int list_coll(struct sort_list_item **ss1, struct sort_list_item **ss2);
+int list_coll_offset(struct sort_list_item **ss1, struct sort_list_item **ss2, size_t offset);
+
+listcoll_t get_list_call_func(size_t offset);
+
+#endif /* __COLL_H__ */
diff --git a/text_cmds/sort/commoncrypto.c b/text_cmds/sort/commoncrypto.c
new file mode 100644
index 0000000..c7b3b8c
--- /dev/null
+++ b/text_cmds/sort/commoncrypto.c
@@ -0,0 +1,98 @@
+/* mdXhl.c
+ * ----------------------------------------------------------------------------
+ * "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
+ * ----------------------------------------------------------------------------
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/lib/libmd/mdXhl.c 294037 2016-01-14 21:08:23Z jtl $");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "commoncrypto.h"
+
+#define LENGTH CC_MD5_DIGEST_LENGTH
+
+char *MD5FileChunk(const char *, char *, off_t, off_t);
+
+char *
+MD5End(CC_MD5_CTX *ctx, char *buf)
+{
+ int i;
+ unsigned char digest[LENGTH];
+ static const char hex[]="0123456789abcdef";
+
+ if (!buf)
+ buf = malloc(2*LENGTH + 1);
+ if (!buf)
+ return 0;
+ CC_MD5_Final(digest, ctx);
+ for (i = 0; i < LENGTH; i++) {
+ buf[i+i] = hex[digest[i] >> 4];
+ buf[i+i+1] = hex[digest[i] & 0x0f];
+ }
+ buf[i+i] = '\0';
+ return buf;
+}
+
+char *
+MD5File(const char *filename, char *buf)
+{
+ return (MD5FileChunk(filename, buf, 0, 0));
+}
+
+char *
+MD5FileChunk(const char *filename, char *buf, off_t ofs, off_t len)
+{
+ unsigned char buffer[16*1024];
+ CC_MD5_CTX ctx;
+ int fd, readrv, e;
+ off_t remain;
+
+ if (len < 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ CC_MD5_Init(&ctx);
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+ if (ofs != 0) {
+ errno = 0;
+ if (lseek(fd, ofs, SEEK_SET) != ofs ||
+ (ofs == -1 && errno != 0)) {
+ readrv = -1;
+ goto error;
+ }
+ }
+ remain = len;
+ readrv = 0;
+ while (len == 0 || remain > 0) {
+ if (len == 0 || remain > (off_t)sizeof(buffer))
+ readrv = read(fd, buffer, sizeof(buffer));
+ else
+ readrv = read(fd, buffer, remain);
+ if (readrv <= 0)
+ break;
+ CC_MD5_Update(&ctx, buffer, readrv);
+ remain -= readrv;
+ }
+error:
+ e = errno;
+ close(fd);
+ errno = e;
+ if (readrv < 0)
+ return NULL;
+ return (MD5End(&ctx, buf));
+}
diff --git a/text_cmds/sort/commoncrypto.h b/text_cmds/sort/commoncrypto.h
new file mode 100644
index 0000000..5170b51
--- /dev/null
+++ b/text_cmds/sort/commoncrypto.h
@@ -0,0 +1,8 @@
+#include <CommonCrypto/CommonDigest.h>
+
+#define MD5_CTX CC_MD5_CTX
+#define MD5Init CC_MD5_Init
+#define MD5Update CC_MD5_Update
+
+char *MD5End(CC_MD5_CTX *, char *);
+char *MD5File(const char *, char *);
diff --git a/text_cmds/sort/file.c b/text_cmds/sort/file.c
new file mode 100644
index 0000000..346819b
--- /dev/null
+++ b/text_cmds/sort/file.c
@@ -0,0 +1,1684 @@
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <err.h>
+#include <fcntl.h>
+#if defined(SORT_THREADS)
+#include <pthread.h>
+#endif
+#ifndef __APPLE__
+#include <semaphore.h>
+#else
+#include <mach/mach_init.h>
+#include <mach/mach_error.h>
+#include <mach/semaphore.h>
+#include <mach/task.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "coll.h"
+#include "file.h"
+#include "radixsort.h"
+
+unsigned long long free_memory = 1000000;
+unsigned long long available_free_memory = 1000000;
+
+bool use_mmap;
+
+const char *tmpdir = "/var/tmp";
+const char *compress_program;
+
+size_t max_open_files = 16;
+
+/*
+ * How much space we read from file at once
+ */
+#define READ_CHUNK (4096)
+
+/*
+ * File reader structure
+ */
+struct file_reader
+{
+ struct reader_buffer rb;
+ FILE *file;
+ char *fname;
+ unsigned char *buffer;
+ unsigned char *mmapaddr;
+ unsigned char *mmapptr;
+ size_t bsz;
+ size_t cbsz;
+ size_t mmapsize;
+ size_t strbeg;
+ int fd;
+ char elsymb;
+};
+
+/*
+ * Structure to be used in file merge process.
+ */
+struct file_header
+{
+ struct file_reader *fr;
+ struct sort_list_item *si; /* current top line */
+ size_t file_pos;
+};
+
+/*
+ * List elements of "cleanable" files list.
+ */
+struct CLEANABLE_FILE
+{
+ char *fn;
+ LIST_ENTRY(CLEANABLE_FILE) files;
+};
+
+/*
+ * List header of "cleanable" files list.
+ */
+static LIST_HEAD(CLEANABLE_FILES,CLEANABLE_FILE) tmp_files;
+
+/*
+ * Semaphore to protect the tmp file list.
+ * We use semaphore here because it is signal-safe, according to POSIX.
+ * And semaphore does not require pthread library.
+ */
+#ifndef __APPLE__
+static sem_t tmp_files_sem;
+#else
+static semaphore_t tmp_files_sem;
+#endif
+
+static void mt_sort(struct sort_list *list,
+ int (*sort_func)(void *, size_t, size_t,
+ int (*)(const void *, const void *)), const char* fn);
+
+/*
+ * Init tmp files list
+ */
+void
+init_tmp_files(void)
+{
+
+ LIST_INIT(&tmp_files);
+#ifndef __APPLE__
+ sem_init(&tmp_files_sem, 0, 1);
+#else
+ {
+ mach_port_t self = mach_task_self();
+ kern_return_t ret = semaphore_create(self, &tmp_files_sem, SYNC_POLICY_FIFO, 1);
+ if (ret != KERN_SUCCESS) {
+ err(2,NULL);
+ }
+ }
+#endif
+}
+
+/*
+ * Save name of a tmp file for signal cleanup
+ */
+void
+tmp_file_atexit(const char *tmp_file)
+{
+
+ if (tmp_file) {
+#ifndef __APPLE__
+ sem_wait(&tmp_files_sem);
+#else
+ semaphore_wait(tmp_files_sem);
+#endif
+ struct CLEANABLE_FILE *item =
+ sort_malloc(sizeof(struct CLEANABLE_FILE));
+ item->fn = sort_strdup(tmp_file);
+ LIST_INSERT_HEAD(&tmp_files, item, files);
+#ifndef __APPLE__
+ sem_post(&tmp_files_sem);
+#else
+ semaphore_signal(tmp_files_sem);
+#endif
+ }
+}
+
+/*
+ * Clear tmp files
+ */
+void
+clear_tmp_files(void)
+{
+ struct CLEANABLE_FILE *item;
+
+#ifndef __APPLE__
+ sem_wait(&tmp_files_sem);
+#else
+ semaphore_wait(tmp_files_sem);
+#endif
+ LIST_FOREACH(item,&tmp_files,files) {
+ if ((item) && (item->fn))
+ unlink(item->fn);
+ }
+#ifndef __APPLE__
+ sem_post(&tmp_files_sem);
+#else
+ semaphore_signal(tmp_files_sem);
+#endif
+}
+
+/*
+ * Check whether a file is a temporary file
+ */
+static bool
+file_is_tmp(const char* fn)
+{
+ struct CLEANABLE_FILE *item;
+ bool ret = false;
+
+ if (fn) {
+#ifndef __APPLE__
+ sem_wait(&tmp_files_sem);
+#else
+ semaphore_wait(tmp_files_sem);
+#endif
+ LIST_FOREACH(item,&tmp_files,files) {
+ if ((item) && (item->fn))
+ if (strcmp(item->fn, fn) == 0) {
+ ret = true;
+ break;
+ }
+ }
+#ifndef __APPLE__
+ sem_post(&tmp_files_sem);
+#else
+ semaphore_signal(tmp_files_sem);
+#endif
+ }
+
+ return (ret);
+}
+
+/*
+ * Generate new temporary file name
+ */
+char *
+new_tmp_file_name(void)
+{
+ static size_t tfcounter = 0;
+ static const char *fn = ".bsdsort.";
+ char *ret;
+ size_t sz;
+
+ sz = strlen(tmpdir) + 1 + strlen(fn) + 32 + 1;
+ ret = sort_malloc(sz);
+
+ sprintf(ret, "%s/%s%d.%lu", tmpdir, fn, (int) getpid(), (unsigned long)(tfcounter++));
+ tmp_file_atexit(ret);
+ return (ret);
+}
+
+/*
+ * Initialize file list
+ */
+void
+file_list_init(struct file_list *fl, bool tmp)
+{
+
+ if (fl) {
+ fl->count = 0;
+ fl->sz = 0;
+ fl->fns = NULL;
+ fl->tmp = tmp;
+ }
+}
+
+/*
+ * Add a file name to the list
+ */
+void
+file_list_add(struct file_list *fl, char *fn, bool allocate)
+{
+
+ if (fl && fn) {
+ if (fl->count >= fl->sz || (fl->fns == NULL)) {
+ fl->sz = (fl->sz) * 2 + 1;
+ fl->fns = sort_realloc(fl->fns, fl->sz *
+ sizeof(char *));
+ }
+ fl->fns[fl->count] = allocate ? sort_strdup(fn) : fn;
+ fl->count += 1;
+ }
+}
+
+/*
+ * Populate file list from array of file names
+ */
+void
+file_list_populate(struct file_list *fl, int argc, char **argv, bool allocate)
+{
+
+ if (fl && argv) {
+ int i;
+
+ for (i = 0; i < argc; i++)
+ file_list_add(fl, argv[i], allocate);
+ }
+}
+
+/*
+ * Clean file list data and delete the files,
+ * if this is a list of temporary files
+ */
+void
+file_list_clean(struct file_list *fl)
+{
+
+ if (fl) {
+ if (fl->fns) {
+ size_t i;
+
+ for (i = 0; i < fl->count; i++) {
+ if (fl->fns[i]) {
+ if (fl->tmp)
+ unlink(fl->fns[i]);
+ sort_free(fl->fns[i]);
+ fl->fns[i] = 0;
+ }
+ }
+ sort_free(fl->fns);
+ fl->fns = NULL;
+ }
+ fl->sz = 0;
+ fl->count = 0;
+ fl->tmp = false;
+ }
+}
+
+/*
+ * Init sort list
+ */
+void
+sort_list_init(struct sort_list *l)
+{
+
+ if (l) {
+ l->count = 0;
+ l->size = 0;
+ l->memsize = sizeof(struct sort_list);
+ l->list = NULL;
+ }
+}
+
+/*
+ * Add string to sort list
+ */
+void
+sort_list_add(struct sort_list *l, struct bwstring *str)
+{
+
+ if (l && str) {
+ size_t indx = l->count;
+
+ if ((l->list == NULL) || (indx >= l->size)) {
+ size_t newsize = (l->size + 1) + 1024;
+
+ l->list = sort_realloc(l->list,
+ sizeof(struct sort_list_item*) * newsize);
+ l->memsize += (newsize - l->size) *
+ sizeof(struct sort_list_item*);
+ l->size = newsize;
+ }
+ l->list[indx] = sort_list_item_alloc();
+ sort_list_item_set(l->list[indx], str);
+ l->memsize += sort_list_item_size(l->list[indx]);
+ l->count += 1;
+ }
+}
+
+/*
+ * Clean sort list data
+ */
+void
+sort_list_clean(struct sort_list *l)
+{
+
+ if (l) {
+ if (l->list) {
+ size_t i;
+
+ for (i = 0; i < l->count; i++) {
+ struct sort_list_item *item;
+
+ item = l->list[i];
+
+ if (item) {
+ sort_list_item_clean(item);
+ sort_free(item);
+ l->list[i] = NULL;
+ }
+ }
+ sort_free(l->list);
+ l->list = NULL;
+ }
+ l->count = 0;
+ l->size = 0;
+ l->memsize = sizeof(struct sort_list);
+ }
+}
+
+/*
+ * Write sort list to file
+ */
+void
+sort_list_dump(struct sort_list *l, const char *fn)
+{
+
+ if (l && fn) {
+ FILE *f;
+
+ f = openfile(fn, "w");
+ if (f == NULL)
+ err(2, NULL);
+
+ if (l->list) {
+ size_t i;
+ if (!(sort_opts_vals.uflag)) {
+ for (i = 0; i < l->count; ++i)
+ bwsfwrite(l->list[i]->str, f,
+ sort_opts_vals.zflag);
+ } else {
+ struct sort_list_item *last_printed_item = NULL;
+ struct sort_list_item *item;
+ for (i = 0; i < l->count; ++i) {
+ item = l->list[i];
+ if ((last_printed_item == NULL) ||
+ list_coll(&last_printed_item, &item)) {
+ bwsfwrite(item->str, f, sort_opts_vals.zflag);
+ last_printed_item = item;
+ }
+ }
+ }
+ }
+
+ closefile(f, fn);
+ }
+}
+
+/*
+ * Checks if the given file is sorted. Stops at the first disorder,
+ * prints the disordered line and returns 1.
+ */
+int
+check(const char *fn)
+{
+ struct bwstring *s1, *s2, *s1disorder, *s2disorder;
+ struct file_reader *fr;
+ struct keys_array *ka1, *ka2;
+ int res;
+ size_t pos, posdisorder;
+
+ s1 = s2 = s1disorder = s2disorder = NULL;
+ ka1 = ka2 = NULL;
+
+ fr = file_reader_init(fn);
+
+ res = 0;
+ pos = 1;
+ posdisorder = 1;
+
+ if (fr == NULL) {
+ err(2, NULL);
+#ifndef __APPLE__
+ goto end;
+#endif
+ }
+
+ s1 = file_reader_readline(fr);
+ if (s1 == NULL)
+ goto end;
+
+ ka1 = keys_array_alloc();
+ preproc(s1, ka1);
+
+ s2 = file_reader_readline(fr);
+ if (s2 == NULL)
+ goto end;
+
+ ka2 = keys_array_alloc();
+ preproc(s2, ka2);
+
+ for (;;) {
+
+ if (debug_sort) {
+ bwsprintf(stdout, s2, "s1=<", ">");
+ bwsprintf(stdout, s1, "s2=<", ">");
+ }
+ int cmp = key_coll(ka2, ka1, 0);
+ if (debug_sort)
+ printf("; cmp1=%d", cmp);
+
+ if (!cmp && sort_opts_vals.complex_sort &&
+ !(sort_opts_vals.uflag) && !(sort_opts_vals.sflag)) {
+ cmp = top_level_str_coll(s2, s1);
+ if (debug_sort)
+ printf("; cmp2=%d", cmp);
+ }
+ if (debug_sort)
+ printf("\n");
+
+ if ((sort_opts_vals.uflag && (cmp <= 0)) || (cmp < 0)) {
+ if (!(sort_opts_vals.csilentflag)) {
+ s2disorder = bwsdup(s2);
+ posdisorder = pos;
+ if (debug_sort)
+ s1disorder = bwsdup(s1);
+ }
+ res = 1;
+ goto end;
+ }
+
+ pos++;
+
+ clean_keys_array(s1, ka1);
+ sort_free(ka1);
+ ka1 = ka2;
+ ka2 = NULL;
+
+ bwsfree(s1);
+ s1 = s2;
+
+ s2 = file_reader_readline(fr);
+ if (s2 == NULL)
+ goto end;
+
+ ka2 = keys_array_alloc();
+ preproc(s2, ka2);
+ }
+
+end:
+ if (ka1) {
+ clean_keys_array(s1, ka1);
+ sort_free(ka1);
+ }
+
+ if (s1)
+ bwsfree(s1);
+
+ if (ka2) {
+ clean_keys_array(s2, ka2);
+ sort_free(ka2);
+ }
+
+ if (s2)
+ bwsfree(s2);
+
+ if ((fn == NULL) || (*fn == 0) || (strcmp(fn, "-") == 0)) {
+ for (;;) {
+ s2 = file_reader_readline(fr);
+ if (s2 == NULL)
+ break;
+ bwsfree(s2);
+ }
+ }
+
+ file_reader_free(fr);
+
+ if (s2disorder) {
+ bws_disorder_warnx(s2disorder, fn, posdisorder);
+ if (s1disorder) {
+ bws_disorder_warnx(s1disorder, fn, posdisorder);
+ if (s1disorder != s2disorder)
+ bwsfree(s1disorder);
+ }
+ bwsfree(s2disorder);
+ s1disorder = NULL;
+ s2disorder = NULL;
+ }
+
+ if (res)
+ exit(res);
+
+ return (0);
+}
+
+/*
+ * Opens a file. If the given filename is "-", stdout will be
+ * opened.
+ */
+FILE *
+openfile(const char *fn, const char *mode)
+{
+ FILE *file;
+
+ if (strcmp(fn, "-") == 0) {
+ return ((mode && mode[0] == 'r') ? stdin : stdout);
+ } else {
+ mode_t orig_file_mask = 0;
+ int is_tmp = file_is_tmp(fn);
+
+ if (is_tmp && (mode[0] == 'w'))
+ orig_file_mask = umask(S_IWGRP | S_IWOTH |
+ S_IRGRP | S_IROTH);
+
+ if (is_tmp && (compress_program != NULL)) {
+ char *cmd;
+ size_t cmdsz;
+
+ cmdsz = strlen(fn) + 128;
+ cmd = sort_malloc(cmdsz);
+
+ fflush(stdout);
+
+ if (mode[0] == 'r')
+ snprintf(cmd, cmdsz - 1, "cat %s | %s -d",
+ fn, compress_program);
+ else if (mode[0] == 'w')
+ snprintf(cmd, cmdsz - 1, "%s > %s",
+ compress_program, fn);
+ else
+ err(2, "%s", getstr(7));
+
+ if ((file = popen(cmd, mode)) == NULL)
+ err(2, NULL);
+
+ sort_free(cmd);
+
+ } else
+ if ((file = fopen(fn, mode)) == NULL)
+ err(2, NULL);
+
+ if (is_tmp && (mode[0] == 'w'))
+ umask(orig_file_mask);
+ }
+
+ return (file);
+}
+
+/*
+ * Close file
+ */
+void
+closefile(FILE *f, const char *fn)
+{
+ if (f == NULL) {
+ ;
+ } else if (f == stdin) {
+ ;
+ } else if (f == stdout) {
+ fflush(f);
+ } else {
+ if (file_is_tmp(fn) && compress_program != NULL) {
+ if(pclose(f)<0)
+ err(2,NULL);
+ } else
+ fclose(f);
+ }
+}
+
+/*
+ * Reads a file into the internal buffer.
+ */
+struct file_reader *
+file_reader_init(const char *fsrc)
+{
+ struct file_reader *ret;
+
+ if (fsrc == NULL)
+ fsrc = "-";
+
+ ret = sort_malloc(sizeof(struct file_reader));
+ memset(ret, 0, sizeof(struct file_reader));
+
+ ret->elsymb = '\n';
+ if (sort_opts_vals.zflag)
+ ret->elsymb = 0;
+
+ ret->fname = sort_strdup(fsrc);
+
+ if (strcmp(fsrc, "-") && (compress_program == NULL) && use_mmap) {
+
+ do {
+ struct stat stat_buf;
+ void *addr;
+ size_t sz = 0;
+ int fd, flags;
+
+#if defined(__APPLE__)
+ flags = 0;
+#else
+ flags = MAP_NOCORE | MAP_NOSYNC;
+#endif
+
+ fd = open(fsrc, O_RDONLY);
+ if (fd < 0)
+ err(2, NULL);
+
+ if (fstat(fd, &stat_buf) < 0) {
+ close(fd);
+ break;
+ }
+
+ sz = stat_buf.st_size;
+
+#if defined(MAP_PREFAULT_READ)
+ flags |= MAP_PREFAULT_READ;
+#endif
+
+ addr = mmap(NULL, sz, PROT_READ, flags, fd, 0);
+ if (addr == MAP_FAILED) {
+ close(fd);
+ break;
+ }
+
+ ret->fd = fd;
+ ret->mmapaddr = addr;
+ ret->mmapsize = sz;
+ ret->mmapptr = ret->mmapaddr;
+
+ } while (0);
+ }
+
+ if (ret->mmapaddr == NULL) {
+ ret->file = openfile(fsrc, "r");
+ if (ret->file == NULL)
+ err(2, NULL);
+
+ if (strcmp(fsrc, "-")) {
+ ret->cbsz = READ_CHUNK;
+ ret->buffer = sort_malloc(ret->cbsz);
+ ret->bsz = 0;
+ ret->strbeg = 0;
+
+ ret->bsz = fread(ret->buffer, 1, ret->cbsz, ret->file);
+ if (ret->bsz == 0) {
+ if (ferror(ret->file))
+ err(2, NULL);
+ }
+ }
+ }
+
+ return (ret);
+}
+
+struct bwstring *
+file_reader_readline(struct file_reader *fr)
+{
+ struct bwstring *ret = NULL;
+
+ if (fr->mmapaddr) {
+ unsigned char *mmapend;
+
+ mmapend = fr->mmapaddr + fr->mmapsize;
+ if (fr->mmapptr >= mmapend)
+ return (NULL);
+ else {
+ unsigned char *strend;
+ size_t sz;
+
+ sz = mmapend - fr->mmapptr;
+ strend = memchr(fr->mmapptr, fr->elsymb, sz);
+
+ if (strend == NULL) {
+ ret = bwscsbdup(fr->mmapptr, sz);
+ fr->mmapptr = mmapend;
+ } else {
+ ret = bwscsbdup(fr->mmapptr, strend -
+ fr->mmapptr);
+ fr->mmapptr = strend + 1;
+ }
+ }
+
+ } else if (fr->file != stdin) {
+ unsigned char *strend;
+ size_t bsz1, remsz, search_start;
+
+ search_start = 0;
+ remsz = 0;
+ strend = NULL;
+
+ if (fr->bsz > fr->strbeg)
+ remsz = fr->bsz - fr->strbeg;
+
+ /* line read cycle */
+ for (;;) {
+ if (remsz > search_start)
+ strend = memchr(fr->buffer + fr->strbeg +
+ search_start, fr->elsymb, remsz -
+ search_start);
+ else
+ strend = NULL;
+
+ if (strend)
+ break;
+ if (feof(fr->file))
+ break;
+
+ if (fr->bsz != fr->cbsz)
+ /* NOTREACHED */
+ err(2, "File read software error 1");
+
+ if (remsz > (READ_CHUNK >> 1)) {
+ search_start = fr->cbsz - fr->strbeg;
+ fr->cbsz += READ_CHUNK;
+ fr->buffer = sort_realloc(fr->buffer,
+ fr->cbsz);
+ bsz1 = fread(fr->buffer + fr->bsz, 1,
+ READ_CHUNK, fr->file);
+ if (bsz1 == 0) {
+ if (ferror(fr->file))
+ err(2, NULL);
+ break;
+ }
+ fr->bsz += bsz1;
+ remsz += bsz1;
+ } else {
+ if (remsz > 0 && fr->strbeg>0)
+ bcopy(fr->buffer + fr->strbeg,
+ fr->buffer, remsz);
+
+ fr->strbeg = 0;
+ search_start = remsz;
+ bsz1 = fread(fr->buffer + remsz, 1,
+ fr->cbsz - remsz, fr->file);
+ if (bsz1 == 0) {
+ if (ferror(fr->file))
+ err(2, NULL);
+ break;
+ }
+ fr->bsz = remsz + bsz1;
+ remsz = fr->bsz;
+ }
+ }
+
+ if (strend == NULL)
+ strend = fr->buffer + fr->bsz;
+
+ if ((fr->buffer + fr->strbeg <= strend) &&
+ (fr->strbeg < fr->bsz) && (remsz>0))
+ ret = bwscsbdup(fr->buffer + fr->strbeg, strend -
+ fr->buffer - fr->strbeg);
+
+ fr->strbeg = (strend - fr->buffer) + 1;
+
+ } else {
+ size_t len = 0;
+
+ ret = bwsfgetln(fr->file, &len, sort_opts_vals.zflag,
+ &(fr->rb));
+ }
+
+ return (ret);
+}
+
+static void
+file_reader_clean(struct file_reader *fr)
+{
+
+ if (fr) {
+ if (fr->mmapaddr)
+ munmap(fr->mmapaddr, fr->mmapsize);
+
+ if (fr->fd)
+ close(fr->fd);
+
+ if (fr->buffer)
+ sort_free(fr->buffer);
+
+ if (fr->file)
+ if (fr->file != stdin)
+ closefile(fr->file, fr->fname);
+
+ if(fr->fname)
+ sort_free(fr->fname);
+
+ memset(fr, 0, sizeof(struct file_reader));
+ }
+}
+
+void
+file_reader_free(struct file_reader *fr)
+{
+
+ if (fr) {
+ file_reader_clean(fr);
+ sort_free(fr);
+ }
+}
+
+int
+procfile(const char *fsrc, struct sort_list *list, struct file_list *fl)
+{
+ struct file_reader *fr;
+
+ fr = file_reader_init(fsrc);
+ if (fr == NULL)
+ err(2, NULL);
+
+ /* file browse cycle */
+ for (;;) {
+ struct bwstring *bws;
+
+ bws = file_reader_readline(fr);
+
+ if (bws == NULL)
+ break;
+
+ sort_list_add(list, bws);
+
+ if (list->memsize >= available_free_memory) {
+ char *fn;
+
+ fn = new_tmp_file_name();
+ sort_list_to_file(list, fn);
+ file_list_add(fl, fn, false);
+ sort_list_clean(list);
+ }
+ }
+
+ file_reader_free(fr);
+
+ return (0);
+}
+
+/*
+ * Compare file headers. Files with EOF always go to the end of the list.
+ */
+static int
+file_header_cmp(struct file_header *f1, struct file_header *f2)
+{
+
+ if (f1 == f2)
+ return (0);
+ else {
+ if (f1->fr == NULL) {
+ return ((f2->fr == NULL) ? 0 : +1);
+ } else if (f2->fr == NULL)
+ return (-1);
+ else {
+ int ret;
+
+ ret = list_coll(&(f1->si), &(f2->si));
+ if (!ret)
+ return ((f1->file_pos < f2->file_pos) ? -1 : +1);
+ return (ret);
+ }
+ }
+}
+
+/*
+ * Allocate and init file header structure
+ */
+static void
+file_header_init(struct file_header **fh, const char *fn, size_t file_pos)
+{
+
+ if (fh && fn) {
+ struct bwstring *line;
+
+ *fh = sort_malloc(sizeof(struct file_header));
+ (*fh)->file_pos = file_pos;
+ (*fh)->fr = file_reader_init(fn);
+ if ((*fh)->fr == NULL) {
+ perror(fn);
+ err(2, "%s", getstr(8));
+ }
+ line = file_reader_readline((*fh)->fr);
+ if (line == NULL) {
+ file_reader_free((*fh)->fr);
+ (*fh)->fr = NULL;
+ (*fh)->si = NULL;
+ } else {
+ (*fh)->si = sort_list_item_alloc();
+ sort_list_item_set((*fh)->si, line);
+ }
+ }
+}
+
+/*
+ * Close file
+ */
+static void
+file_header_close(struct file_header **fh)
+{
+
+ if (fh && *fh) {
+ if ((*fh)->fr) {
+ file_reader_free((*fh)->fr);
+ (*fh)->fr = NULL;
+ }
+ if ((*fh)->si) {
+ sort_list_item_clean((*fh)->si);
+ sort_free((*fh)->si);
+ (*fh)->si = NULL;
+ }
+ sort_free(*fh);
+ *fh = NULL;
+ }
+}
+
+/*
+ * Swap two array elements
+ */
+static void
+file_header_swap(struct file_header **fh, size_t i1, size_t i2)
+{
+ struct file_header *tmp;
+
+ tmp = fh[i1];
+ fh[i1] = fh[i2];
+ fh[i2] = tmp;
+}
+
+/* heap algorithm ==>> */
+
+/*
+ * See heap sort algorithm
+ * "Raises" last element to its right place
+ */
+static void
+file_header_heap_swim(struct file_header **fh, size_t indx)
+{
+
+ if (indx > 0) {
+ size_t parent_index;
+
+ parent_index = (indx - 1) >> 1;
+
+ if (file_header_cmp(fh[indx], fh[parent_index]) < 0) {
+ /* swap child and parent and continue */
+ file_header_swap(fh, indx, parent_index);
+ file_header_heap_swim(fh, parent_index);
+ }
+ }
+}
+
+/*
+ * Sink the top element to its correct position
+ */
+static void
+file_header_heap_sink(struct file_header **fh, size_t indx, size_t size)
+{
+ size_t left_child_index;
+ size_t right_child_index;
+
+ left_child_index = indx + indx + 1;
+ right_child_index = left_child_index + 1;
+
+ if (left_child_index < size) {
+ size_t min_child_index;
+
+ min_child_index = left_child_index;
+
+ if ((right_child_index < size) &&
+ (file_header_cmp(fh[left_child_index],
+ fh[right_child_index]) > 0))
+ min_child_index = right_child_index;
+ if (file_header_cmp(fh[indx], fh[min_child_index]) > 0) {
+ file_header_swap(fh, indx, min_child_index);
+ file_header_heap_sink(fh, min_child_index, size);
+ }
+ }
+}
+
+/* <<== heap algorithm */
+
+/*
+ * Adds element to the "left" end
+ */
+static void
+file_header_list_rearrange_from_header(struct file_header **fh, size_t size)
+{
+
+ file_header_heap_sink(fh, 0, size);
+}
+
+/*
+ * Adds element to the "right" end
+ */
+static void
+file_header_list_push(struct file_header *f, struct file_header **fh, size_t size)
+{
+
+ fh[size++] = f;
+ file_header_heap_swim(fh, size - 1);
+}
+
+struct last_printed
+{
+ struct bwstring *str;
+};
+
+/*
+ * Prints the current line of the file
+ */
+static void
+file_header_print(struct file_header *fh, FILE *f_out, struct last_printed *lp)
+{
+
+ if (fh && fh->fr && f_out && fh->si && fh->si->str) {
+ if (sort_opts_vals.uflag) {
+ if ((lp->str == NULL) || (str_list_coll(lp->str, &(fh->si)))) {
+ bwsfwrite(fh->si->str, f_out, sort_opts_vals.zflag);
+ if (lp->str)
+ bwsfree(lp->str);
+ lp->str = bwsdup(fh->si->str);
+ }
+ } else
+ bwsfwrite(fh->si->str, f_out, sort_opts_vals.zflag);
+ }
+}
+
+/*
+ * Read next line
+ */
+static void
+file_header_read_next(struct file_header *fh)
+{
+
+ if (fh && fh->fr) {
+ struct bwstring *tmp;
+
+ tmp = file_reader_readline(fh->fr);
+ if (tmp == NULL) {
+ file_reader_free(fh->fr);
+ fh->fr = NULL;
+ if (fh->si) {
+ sort_list_item_clean(fh->si);
+ sort_free(fh->si);
+ fh->si = NULL;
+ }
+ } else {
+ if (fh->si == NULL)
+ fh->si = sort_list_item_alloc();
+ sort_list_item_set(fh->si, tmp);
+ }
+ }
+}
+
+/*
+ * Merge array of "files headers"
+ */
+static void
+file_headers_merge(size_t fnum, struct file_header **fh, FILE *f_out)
+{
+ struct last_printed lp;
+ size_t i;
+
+ memset(&lp, 0, sizeof(lp));
+
+ /*
+ * construct the initial sort structure
+ */
+ for (i = 0; i < fnum; i++)
+ file_header_list_push(fh[i], fh, i);
+
+ while (fh[0]->fr) { /* unfinished files are always in front */
+ /* output the smallest line: */
+ file_header_print(fh[0], f_out, &lp);
+ /* read a new line, if possible: */
+ file_header_read_next(fh[0]);
+ /* re-arrange the list: */
+ file_header_list_rearrange_from_header(fh, fnum);
+ }
+
+ if (lp.str)
+ bwsfree(lp.str);
+}
+
+/*
+ * Merges the given files into the output file, which can be
+ * stdout.
+ */
+static void
+merge_files_array(size_t argc, char **argv, const char *fn_out)
+{
+
+ if (argv && fn_out) {
+ struct file_header **fh;
+ FILE *f_out;
+ size_t i;
+
+ f_out = openfile(fn_out, "w");
+
+ if (f_out == NULL)
+ err(2, NULL);
+
+ fh = sort_malloc((argc + 1) * sizeof(struct file_header *));
+
+ for (i = 0; i < argc; i++)
+ file_header_init(fh + i, argv[i], (size_t) i);
+
+ file_headers_merge(argc, fh, f_out);
+
+ for (i = 0; i < argc; i++)
+ file_header_close(fh + i);
+
+ sort_free(fh);
+
+ closefile(f_out, fn_out);
+ }
+}
+
+/*
+ * Shrinks the file list until its size smaller than max number of opened files
+ */
+static int
+shrink_file_list(struct file_list *fl)
+{
+
+ if ((fl == NULL) || (size_t) (fl->count) < max_open_files)
+ return (0);
+ else {
+ struct file_list new_fl;
+ size_t indx = 0;
+
+ file_list_init(&new_fl, true);
+ while (indx < fl->count) {
+ char *fnew;
+ size_t num;
+
+ num = fl->count - indx;
+ fnew = new_tmp_file_name();
+
+ if ((size_t) num >= max_open_files)
+ num = max_open_files - 1;
+ merge_files_array(num, fl->fns + indx, fnew);
+ if (fl->tmp) {
+ size_t i;
+
+ for (i = 0; i < num; i++)
+ unlink(fl->fns[indx + i]);
+ }
+ file_list_add(&new_fl, fnew, false);
+ indx += num;
+ }
+ fl->tmp = false; /* already taken care of */
+ file_list_clean(fl);
+
+ fl->count = new_fl.count;
+ fl->fns = new_fl.fns;
+ fl->sz = new_fl.sz;
+ fl->tmp = new_fl.tmp;
+
+ return (1);
+ }
+}
+
+/*
+ * Merge list of files
+ */
+void
+merge_files(struct file_list *fl, const char *fn_out)
+{
+
+ if (fl && fn_out) {
+ while (shrink_file_list(fl));
+
+ merge_files_array(fl->count, fl->fns, fn_out);
+ }
+}
+
+static const char *
+get_sort_method_name(int sm)
+{
+
+ if (sm == SORT_MERGESORT)
+ return "mergesort";
+ else if (sort_opts_vals.sort_method == SORT_RADIXSORT)
+ return "radixsort";
+ else if (sort_opts_vals.sort_method == SORT_HEAPSORT)
+ return "heapsort";
+ else
+ return "quicksort";
+}
+
+/*
+ * Wrapper for qsort
+ */
+static int sort_qsort(void *list, size_t count, size_t elem_size,
+ int (*cmp_func)(const void *, const void *))
+{
+
+ qsort(list, count, elem_size, cmp_func);
+ return (0);
+}
+
+/*
+ * Sort list of lines and writes it to the file
+ */
+void
+sort_list_to_file(struct sort_list *list, const char *outfile)
+{
+ struct sort_mods *sm = &(keys[0].sm);
+
+ if (!(sm->Mflag) && !(sm->Rflag) && !(sm->Vflag) && !(sm->Vflag) &&
+ !(sm->gflag) && !(sm->hflag) && !(sm->nflag)) {
+ if ((sort_opts_vals.sort_method == SORT_DEFAULT) && byte_sort)
+ sort_opts_vals.sort_method = SORT_RADIXSORT;
+
+ } else if (sort_opts_vals.sort_method == SORT_RADIXSORT)
+ err(2, "%s", getstr(9));
+
+ /*
+ * to handle stable sort and the unique cases in the
+ * right order, we need stable basic algorithm
+ */
+ if (sort_opts_vals.sflag) {
+ switch (sort_opts_vals.sort_method){
+ case SORT_MERGESORT:
+ break;
+ case SORT_RADIXSORT:
+ break;
+ case SORT_DEFAULT:
+ sort_opts_vals.sort_method = SORT_MERGESORT;
+ break;
+ default:
+ errx(2, "%s", getstr(10));
+ }
+ }
+
+ if (sort_opts_vals.sort_method == SORT_DEFAULT)
+ sort_opts_vals.sort_method = DEFAULT_SORT_ALGORITHM;
+
+ if (debug_sort)
+ printf("sort_method=%s\n",
+ get_sort_method_name(sort_opts_vals.sort_method));
+
+ switch (sort_opts_vals.sort_method){
+ case SORT_RADIXSORT:
+ rxsort(list->list, list->count);
+ sort_list_dump(list, outfile);
+ break;
+ case SORT_MERGESORT:
+ mt_sort(list, mergesort, outfile);
+ break;
+ case SORT_HEAPSORT:
+ mt_sort(list, heapsort, outfile);
+ break;
+ case SORT_QSORT:
+ mt_sort(list, sort_qsort, outfile);
+ break;
+ default:
+ mt_sort(list, DEFAULT_SORT_FUNC, outfile);
+ break;
+ }
+}
+
+/******************* MT SORT ************************/
+
+#if defined(SORT_THREADS)
+/* semaphore to count threads */
+#ifndef __APPLE__
+static sem_t mtsem;
+#else
+static semaphore_t mtsem;
+#endif
+
+/* current system sort function */
+static int (*g_sort_func)(void *, size_t, size_t,
+ int(*)(const void *, const void *));
+
+/*
+ * Sort cycle thread (in multi-threaded mode)
+ */
+static void*
+mt_sort_thread(void* arg)
+{
+ struct sort_list *list = arg;
+
+ g_sort_func(list->list, list->count, sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) list_coll);
+
+#ifndef __APPLE__
+ sem_post(&mtsem);
+#else
+ semaphore_signal(mtsem);
+#endif
+
+ return (arg);
+}
+
+/*
+ * Compare sub-lists. Empty sub-lists always go to the end of the list.
+ */
+static int
+sub_list_cmp(struct sort_list *l1, struct sort_list *l2)
+{
+
+ if (l1 == l2)
+ return (0);
+ else {
+ if (l1->count == 0) {
+ return ((l2->count == 0) ? 0 : +1);
+ } else if (l2->count == 0) {
+ return (-1);
+ } else {
+ int ret;
+
+ ret = list_coll(&(l1->list[0]), &(l2->list[0]));
+ if (!ret)
+ return ((l1->sub_list_pos < l2->sub_list_pos) ?
+ -1 : +1);
+ return (ret);
+ }
+ }
+}
+
+/*
+ * Swap two array elements
+ */
+static void
+sub_list_swap(struct sort_list **sl, size_t i1, size_t i2)
+{
+ struct sort_list *tmp;
+
+ tmp = sl[i1];
+ sl[i1] = sl[i2];
+ sl[i2] = tmp;
+}
+
+/* heap algorithm ==>> */
+
+/*
+ * See heap sort algorithm
+ * "Raises" last element to its right place
+ */
+static void
+sub_list_swim(struct sort_list **sl, size_t indx)
+{
+
+ if (indx > 0) {
+ size_t parent_index;
+
+ parent_index = (indx - 1) >> 1;
+
+ if (sub_list_cmp(sl[indx], sl[parent_index]) < 0) {
+ /* swap child and parent and continue */
+ sub_list_swap(sl, indx, parent_index);
+ sub_list_swim(sl, parent_index);
+ }
+ }
+}
+
+/*
+ * Sink the top element to its correct position
+ */
+static void
+sub_list_sink(struct sort_list **sl, size_t indx, size_t size)
+{
+ size_t left_child_index;
+ size_t right_child_index;
+
+ left_child_index = indx + indx + 1;
+ right_child_index = left_child_index + 1;
+
+ if (left_child_index < size) {
+ size_t min_child_index;
+
+ min_child_index = left_child_index;
+
+ if ((right_child_index < size) &&
+ (sub_list_cmp(sl[left_child_index],
+ sl[right_child_index]) > 0))
+ min_child_index = right_child_index;
+ if (sub_list_cmp(sl[indx], sl[min_child_index]) > 0) {
+ sub_list_swap(sl, indx, min_child_index);
+ sub_list_sink(sl, min_child_index, size);
+ }
+ }
+}
+
+/* <<== heap algorithm */
+
+/*
+ * Adds element to the "right" end
+ */
+static void
+sub_list_push(struct sort_list *s, struct sort_list **sl, size_t size)
+{
+
+ sl[size++] = s;
+ sub_list_swim(sl, size - 1);
+}
+
+struct last_printed_item
+{
+ struct sort_list_item *item;
+};
+
+/*
+ * Prints the current line of the file
+ */
+static void
+sub_list_header_print(struct sort_list *sl, FILE *f_out,
+ struct last_printed_item *lp)
+{
+
+ if (sl && sl->count && f_out && sl->list[0]->str) {
+ if (sort_opts_vals.uflag) {
+ if ((lp->item == NULL) || (list_coll(&(lp->item),
+ &(sl->list[0])))) {
+ bwsfwrite(sl->list[0]->str, f_out,
+ sort_opts_vals.zflag);
+ lp->item = sl->list[0];
+ }
+ } else
+ bwsfwrite(sl->list[0]->str, f_out,
+ sort_opts_vals.zflag);
+ }
+}
+
+/*
+ * Read next line
+ */
+static void
+sub_list_next(struct sort_list *sl)
+{
+
+ if (sl && sl->count) {
+ sl->list += 1;
+ sl->count -= 1;
+ }
+}
+
+/*
+ * Merge sub-lists to a file
+ */
+static void
+merge_sub_lists(struct sort_list **sl, size_t n, FILE* f_out)
+{
+ struct last_printed_item lp;
+ size_t i;
+
+ memset(&lp,0,sizeof(lp));
+
+ /* construct the initial list: */
+ for (i = 0; i < n; i++)
+ sub_list_push(sl[i], sl, i);
+
+ while (sl[0]->count) { /* unfinished lists are always in front */
+ /* output the smallest line: */
+ sub_list_header_print(sl[0], f_out, &lp);
+ /* move to a new line, if possible: */
+ sub_list_next(sl[0]);
+ /* re-arrange the list: */
+ sub_list_sink(sl, 0, n);
+ }
+}
+
+/*
+ * Merge sub-lists to a file
+ */
+static void
+merge_list_parts(struct sort_list **parts, size_t n, const char *fn)
+{
+ FILE* f_out;
+
+ f_out = openfile(fn,"w");
+
+ merge_sub_lists(parts, n, f_out);
+
+ closefile(f_out, fn);
+}
+
+#endif /* defined(SORT_THREADS) */
+/*
+ * Multi-threaded sort algorithm "driver"
+ */
+static void
+mt_sort(struct sort_list *list,
+ int(*sort_func)(void *, size_t, size_t, int(*)(const void *, const void *)),
+ const char* fn)
+{
+#if defined(SORT_THREADS)
+ if (nthreads < 2 || list->count < MT_SORT_THRESHOLD) {
+ size_t nthreads_save = nthreads;
+ nthreads = 1;
+#endif
+ /* if single thread or small data, do simple sort */
+ sort_func(list->list, list->count,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) list_coll);
+ sort_list_dump(list, fn);
+#if defined(SORT_THREADS)
+ nthreads = nthreads_save;
+ } else {
+ /* multi-threaded sort */
+ struct sort_list **parts;
+ size_t avgsize, cstart, i;
+
+ /* array of sub-lists */
+ parts = sort_malloc(sizeof(struct sort_list*) * nthreads);
+ cstart = 0;
+ avgsize = list->count / nthreads;
+
+ /* set global system sort function */
+ g_sort_func = sort_func;
+
+ /* set sublists */
+ for (i = 0; i < nthreads; ++i) {
+ size_t sz = 0;
+
+ parts[i] = sort_malloc(sizeof(struct sort_list));
+ parts[i]->list = list->list + cstart;
+ parts[i]->memsize = 0;
+ parts[i]->sub_list_pos = i;
+
+ sz = (i == nthreads - 1) ? list->count - cstart :
+ avgsize;
+
+ parts[i]->count = sz;
+
+ parts[i]->size = parts[i]->count;
+
+ cstart += sz;
+ }
+
+ /* init threads counting semaphore */
+#ifndef __APPLE__
+ sem_init(&mtsem, 0, 0);
+#else
+ {
+ mach_port_t self = mach_task_self();
+ kern_return_t ret = semaphore_create(self, &mtsem, SYNC_POLICY_FIFO, 0);
+ if (ret != KERN_SUCCESS) {
+ err(2,NULL);
+ }
+ }
+#endif
+
+ /* start threads */
+ for (i = 0; i < nthreads; ++i) {
+ pthread_t pth;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+#ifndef __APPLE__
+ pthread_attr_setdetachstate(&attr, PTHREAD_DETACHED);
+#else
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+#endif
+
+ for (;;) {
+ int res = pthread_create(&pth, &attr,
+ mt_sort_thread, parts[i]);
+
+ if (res >= 0)
+ break;
+ if (errno == EAGAIN) {
+#ifndef __APPLE__
+ pthread_yield();
+#else
+ sched_yield();
+#endif
+ continue;
+ }
+ err(2, NULL);
+ }
+
+ pthread_attr_destroy(&attr);
+ }
+
+ /* wait for threads completion */
+ for (i = 0; i < nthreads; ++i) {
+#ifndef __APPLE__
+ sem_wait(&mtsem);
+#else
+ semaphore_wait(mtsem);
+#endif
+ }
+ /* destroy the semaphore - we do not need it anymore */
+#ifndef __APPLE__
+ sem_destroy(&mtsem);
+#else
+ {
+ mach_port_t self = mach_task_self();
+ semaphore_destroy(self,mtsem);
+ }
+#endif
+
+ /* merge sorted sub-lists to the file */
+ merge_list_parts(parts, nthreads, fn);
+
+ /* free sub-lists data */
+ for (i = 0; i < nthreads; ++i) {
+ sort_free(parts[i]);
+ }
+ sort_free(parts);
+ }
+#endif /* defined(SORT_THREADS) */
+}
diff --git a/text_cmds/sort/file.h b/text_cmds/sort/file.h
new file mode 100644
index 0000000..e7a8c94
--- /dev/null
+++ b/text_cmds/sort/file.h
@@ -0,0 +1,126 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 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.
+ */
+
+#if !defined(__SORT_FILE_H__)
+#define __SORT_FILE_H__
+
+#include "coll.h"
+#include "sort.h"
+
+#define SORT_DEFAULT 0
+#define SORT_QSORT 1
+#define SORT_MERGESORT 2
+#define SORT_HEAPSORT 3
+#define SORT_RADIXSORT 4
+
+#define DEFAULT_SORT_ALGORITHM SORT_MERGESORT
+#define DEFAULT_SORT_FUNC mergesort
+
+/*
+ * List of data to be sorted.
+ */
+struct sort_list
+{
+ struct sort_list_item **list;
+ unsigned long long memsize;
+ size_t count;
+ size_t size;
+ size_t sub_list_pos;
+};
+
+/*
+ * File reader object
+ */
+struct file_reader;
+
+/*
+ * List of files to be sorted
+ */
+struct file_list
+{
+ char **fns;
+ size_t count;
+ size_t sz;
+ bool tmp;
+};
+
+/* memory */
+
+/**/
+
+extern unsigned long long free_memory;
+extern unsigned long long available_free_memory;
+
+/* Are we using mmap ? */
+extern bool use_mmap;
+
+/* temporary file dir */
+
+extern const char *tmpdir;
+
+/*
+ * Max number of simultaneously open files (including the output file).
+ */
+extern size_t max_open_files;
+
+/*
+ * Compress program
+ */
+extern const char* compress_program;
+
+/* funcs */
+
+struct file_reader *file_reader_init(const char *fsrc);
+struct bwstring *file_reader_readline(struct file_reader *fr);
+void file_reader_free(struct file_reader *fr);
+
+void init_tmp_files(void);
+void clear_tmp_files(void);
+char *new_tmp_file_name(void);
+void tmp_file_atexit(const char *tmp_file);
+
+void file_list_init(struct file_list *fl, bool tmp);
+void file_list_add(struct file_list *fl, char *fn, bool allocate);
+void file_list_populate(struct file_list *fl, int argc, char **argv, bool allocate);
+void file_list_clean(struct file_list *fl);
+
+int check(const char *);
+void merge_files(struct file_list *fl, const char *fn_out);
+FILE *openfile(const char *, const char *);
+void closefile(FILE *, const char *);
+int procfile(const char *fn, struct sort_list *list, struct file_list *fl);
+
+void sort_list_init(struct sort_list *l);
+void sort_list_add(struct sort_list *l, struct bwstring *str);
+void sort_list_clean(struct sort_list *l);
+void sort_list_dump(struct sort_list *l, const char *fn);
+
+void sort_list_to_file(struct sort_list *list, const char *outfile);
+
+#endif /* __SORT_FILE_H__ */
diff --git a/text_cmds/sort/mem.c b/text_cmds/sort/mem.c
new file mode 100644
index 0000000..f59f751
--- /dev/null
+++ b/text_cmds/sort/mem.c
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/usr.bin/sort/mem.c 281132 2015-04-06 02:35:55Z pfg $");
+
+#include <err.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mem.h"
+
+/*
+ * malloc() wrapper.
+ */
+void *
+sort_malloc(size_t size)
+{
+ void *ptr;
+
+ if ((ptr = malloc(size)) == NULL)
+ err(2, NULL);
+ return (ptr);
+}
+
+/*
+ * free() wrapper.
+ */
+void
+sort_free(const void *ptr)
+{
+
+ if (ptr)
+ free(__DECONST(void *, ptr));
+}
+
+/*
+ * realloc() wrapper.
+ */
+void *
+sort_realloc(void *ptr, size_t size)
+{
+
+ if ((ptr = realloc(ptr, size)) == NULL)
+ err(2, NULL);
+ return (ptr);
+}
+
+char *
+sort_strdup(const char *str)
+{
+ char *dup;
+
+ if ((dup = strdup(str)) == NULL)
+ err(2, NULL);
+ return (dup);
+}
diff --git a/text_cmds/sort/mem.h b/text_cmds/sort/mem.h
new file mode 100644
index 0000000..95ab1ac
--- /dev/null
+++ b/text_cmds/sort/mem.h
@@ -0,0 +1,45 @@
+/* $FreeBSD: head/usr.bin/sort/mem.h 264744 2014-04-21 22:52:18Z pfg $ */
+
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 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.
+ */
+
+#if !defined(__SORT_MEM_H__)
+#define __SORT_MEM_H__
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+/*
+ * mem.c
+ */
+void *sort_malloc(size_t);
+void sort_free(const void *ptr);
+void *sort_realloc(void *, size_t);
+char *sort_strdup(const char *);
+
+#endif /* __SORT_MEM_H__ */
diff --git a/text_cmds/sort/nls/C.msg b/text_cmds/sort/nls/C.msg
new file mode 100644
index 0000000..81300ba
--- /dev/null
+++ b/text_cmds/sort/nls/C.msg
@@ -0,0 +1,16 @@
+$ $FreeBSD: head/usr.bin/sort/nls/C.msg 235434 2012-05-14 09:55:23Z gabor $
+$
+$set 1
+$quote "
+1 "mutually exclusive flags"
+2 "extra argument not allowed with -c"
+3 "Unknown feature"
+4 "Wrong memory buffer specification"
+5 "0 field in key specs"
+6 "0 column in key specs"
+7 "Wrong file mode"
+8 "Cannot open file for reading"
+9 "Radix sort cannot be used with these sort options"
+10 "The chosen sort method cannot be used with stable and/or unique sort"
+11 "Invalid key position"
+12 "Usage: %s [-bcCdfigMmnrsuz] [-kPOS1[,POS2] ... ] [+POS1 [-POS2]] [-S memsize] [-T tmpdir] [-t separator] [-o outfile] [--batch-size size] [--files0-from file] [--heapsort] [--mergesort] [--radixsort] [--qsort] [--nthreads thread_no] [--human-numeric-sort] [--version-sort] [--random-sort [--random-source file]] [--compress-program program] [file ...]\n"
diff --git a/text_cmds/sort/nls/hu_HU.ISO8859-2.msg b/text_cmds/sort/nls/hu_HU.ISO8859-2.msg
new file mode 100644
index 0000000..c45862b
--- /dev/null
+++ b/text_cmds/sort/nls/hu_HU.ISO8859-2.msg
@@ -0,0 +1,16 @@
+$ $FreeBSD: head/usr.bin/sort/nls/hu_HU.ISO8859-2.msg 235434 2012-05-14 09:55:23Z gabor $
+$
+$set 1
+$quote "
+1 "egymást kizáró opciók"
+2 "extra argumentum a -%c opcióval"
+3 "Ismeretlen funkció\n"
+4 "Rossz memória puffer érték"
+5 "0 mezõ a kulcsspecifikációban\n"
+6 "0 oszlop a kulcsspecifikációban\n"
+7 "Helytelen fájl mód"
+8 "A fájl nem nyitható meg olvasásra"
+9 "A radix rendezés nem használható a megadott rendezési opciókkal"
+10 "A választott rendezési mód nem használható a --stable és --unique opciókkal"
+11 "Érvénytelen kulcs pozíció"
+12 "Használat: %s [-bcCdfigMmnrsuz] [-kPOS1[,POS2] ... ] [+POS1 [-POS2]] [-S memóriaméret] [-T ideiglenes_könyvtár] [-t elválasztó] [-o kimeneti_fájl] [--batch-size méret] [--files0-from fájl] [--heapsort] [--mergesort] [--radixsort] [--qsort] [--nthreads szálak_száma] [--human-numeric-sort] [--version-sort] [--random-sort [--random-source fájl]] [--compress-program program] [fájl ...]\n"
diff --git a/text_cmds/sort/radixsort.c b/text_cmds/sort/radixsort.c
new file mode 100644
index 0000000..8288a19
--- /dev/null
+++ b/text_cmds/sort/radixsort.c
@@ -0,0 +1,746 @@
+/*-
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
+ * Copyright (C) 2012 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <err.h>
+#include <langinfo.h>
+#include <math.h>
+#if defined(SORT_THREADS)
+#include <pthread.h>
+#ifndef __APPLE__
+#include <semaphore.h>
+#else
+#include <mach/mach_init.h>
+#include <mach/mach_error.h>
+#include <mach/semaphore.h>
+#include <mach/task.h>
+#endif
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <unistd.h>
+
+#include "coll.h"
+#include "radixsort.h"
+
+#define DEFAULT_SORT_FUNC_RADIXSORT mergesort
+
+#define TINY_NODE(sl) ((sl)->tosort_num < 65)
+#define SMALL_NODE(sl) ((sl)->tosort_num < 5)
+
+/* are we sorting in reverse order ? */
+static bool reverse_sort;
+
+/* sort sub-levels array size */
+static const size_t slsz = 256 * sizeof(struct sort_level*);
+
+/* one sort level structure */
+struct sort_level
+{
+ struct sort_level **sublevels;
+ struct sort_list_item **leaves;
+ struct sort_list_item **sorted;
+ struct sort_list_item **tosort;
+ size_t leaves_num;
+ size_t leaves_sz;
+ size_t level;
+ size_t real_sln;
+ size_t start_position;
+ size_t sln;
+ size_t tosort_num;
+ size_t tosort_sz;
+};
+
+/* stack of sort levels ready to be sorted */
+struct level_stack {
+ struct level_stack *next;
+ struct sort_level *sl;
+};
+
+static struct level_stack *g_ls;
+
+#if defined(SORT_THREADS)
+/* stack guarding mutex */
+static pthread_cond_t g_ls_cond;
+static pthread_mutex_t g_ls_mutex;
+
+/* counter: how many items are left */
+static size_t sort_left;
+/* guarding mutex */
+
+/* semaphore to count threads */
+#ifndef __APPLE__
+static sem_t mtsem;
+#else
+semaphore_t rmtsem;
+#endif
+
+/*
+ * Decrement items counter
+ */
+static inline void
+sort_left_dec(size_t n)
+{
+ pthread_mutex_lock(&g_ls_mutex);
+ sort_left -= n;
+ if (sort_left == 0 && nthreads > 1)
+ pthread_cond_broadcast(&g_ls_cond);
+ pthread_mutex_unlock(&g_ls_mutex);
+}
+
+/*
+ * Do we have something to sort ?
+ *
+ * This routine does not need to be locked.
+ */
+static inline bool
+have_sort_left(void)
+{
+ bool ret;
+
+ ret = (sort_left > 0);
+
+ return (ret);
+}
+
+#else
+
+#define sort_left_dec(n)
+
+#endif /* SORT_THREADS */
+
+/*
+ * Push sort level to the stack
+ */
+static inline void
+push_ls(struct sort_level *sl)
+{
+ struct level_stack *new_ls;
+
+ new_ls = sort_malloc(sizeof(struct level_stack));
+ new_ls->sl = sl;
+
+#if defined(SORT_THREADS)
+ if (nthreads > 1)
+ pthread_mutex_lock(&g_ls_mutex);
+#endif
+
+ new_ls->next = g_ls;
+ g_ls = new_ls;
+
+#if defined(SORT_THREADS)
+ if (nthreads > 1)
+ pthread_cond_signal(&g_ls_cond);
+#endif
+
+#if defined(SORT_THREADS)
+ if (nthreads > 1)
+ pthread_mutex_unlock(&g_ls_mutex);
+#endif
+}
+
+/*
+ * Pop sort level from the stack (single-threaded style)
+ */
+static inline struct sort_level*
+pop_ls_st(void)
+{
+ struct sort_level *sl;
+
+ if (g_ls) {
+ struct level_stack *saved_ls;
+
+ sl = g_ls->sl;
+ saved_ls = g_ls;
+ g_ls = g_ls->next;
+ sort_free(saved_ls);
+ } else
+ sl = NULL;
+
+ return (sl);
+}
+
+#if defined(SORT_THREADS)
+
+/*
+ * Pop sort level from the stack (multi-threaded style)
+ */
+static inline struct sort_level*
+pop_ls_mt(void)
+{
+ struct level_stack *saved_ls;
+ struct sort_level *sl;
+
+ pthread_mutex_lock(&g_ls_mutex);
+
+ for (;;) {
+ if (g_ls) {
+ sl = g_ls->sl;
+ saved_ls = g_ls;
+ g_ls = g_ls->next;
+ break;
+ }
+ sl = NULL;
+ saved_ls = NULL;
+
+ if (have_sort_left() == 0)
+ break;
+ pthread_cond_wait(&g_ls_cond, &g_ls_mutex);
+ }
+
+ pthread_mutex_unlock(&g_ls_mutex);
+
+ sort_free(saved_ls);
+
+ return (sl);
+}
+
+#endif /* defined(SORT_THREADS) */
+
+static void
+add_to_sublevel(struct sort_level *sl, struct sort_list_item *item, size_t indx)
+{
+ struct sort_level *ssl;
+
+ ssl = sl->sublevels[indx];
+
+ if (ssl == NULL) {
+ ssl = sort_malloc(sizeof(struct sort_level));
+ memset(ssl, 0, sizeof(struct sort_level));
+
+ ssl->level = sl->level + 1;
+ sl->sublevels[indx] = ssl;
+
+ ++(sl->real_sln);
+ }
+
+ if (++(ssl->tosort_num) > ssl->tosort_sz) {
+ ssl->tosort_sz = ssl->tosort_num + 128;
+ ssl->tosort = sort_realloc(ssl->tosort,
+ sizeof(struct sort_list_item*) * (ssl->tosort_sz));
+ }
+
+ ssl->tosort[ssl->tosort_num - 1] = item;
+}
+
+static inline void
+add_leaf(struct sort_level *sl, struct sort_list_item *item)
+{
+
+ if (++(sl->leaves_num) > sl->leaves_sz) {
+ sl->leaves_sz = sl->leaves_num + 128;
+ sl->leaves = sort_realloc(sl->leaves,
+ (sizeof(struct sort_list_item*) * (sl->leaves_sz)));
+ }
+ sl->leaves[sl->leaves_num - 1] = item;
+}
+
+static inline int
+get_wc_index(struct sort_list_item *sli, size_t level)
+{
+ const struct key_value *kv;
+ const struct bwstring *bws;
+
+ kv = get_key_from_keys_array(&sli->ka, 0);
+ bws = kv->k;
+
+ if ((BWSLEN(bws) > level))
+ return (unsigned char) BWS_GET(bws,level);
+ return (-1);
+}
+
+static void
+place_item(struct sort_level *sl, size_t item)
+{
+ struct sort_list_item *sli;
+ int c;
+
+ sli = sl->tosort[item];
+ c = get_wc_index(sli, sl->level);
+
+ if (c == -1)
+ add_leaf(sl, sli);
+ else
+ add_to_sublevel(sl, sli, c);
+}
+
+static void
+free_sort_level(struct sort_level *sl)
+{
+
+ if (sl) {
+ if (sl->leaves)
+ sort_free(sl->leaves);
+
+ if (sl->level > 0)
+ sort_free(sl->tosort);
+
+ if (sl->sublevels) {
+ struct sort_level *slc;
+ size_t sln;
+
+ sln = sl->sln;
+
+ for (size_t i = 0; i < sln; ++i) {
+ slc = sl->sublevels[i];
+ if (slc)
+ free_sort_level(slc);
+ }
+
+ sort_free(sl->sublevels);
+ }
+
+ sort_free(sl);
+ }
+}
+
+static void
+run_sort_level_next(struct sort_level *sl)
+{
+ struct sort_level *slc;
+ size_t i, sln, tosort_num;
+
+ if (sl->sublevels) {
+ sort_free(sl->sublevels);
+ sl->sublevels = NULL;
+ }
+
+ switch (sl->tosort_num) {
+ case 0:
+ goto end;
+ case (1):
+ sl->sorted[sl->start_position] = sl->tosort[0];
+ sort_left_dec(1);
+ goto end;
+ case (2):
+ if (list_coll_offset(&(sl->tosort[0]), &(sl->tosort[1]),
+ sl->level) > 0) {
+ sl->sorted[sl->start_position++] = sl->tosort[1];
+ sl->sorted[sl->start_position] = sl->tosort[0];
+ } else {
+ sl->sorted[sl->start_position++] = sl->tosort[0];
+ sl->sorted[sl->start_position] = sl->tosort[1];
+ }
+ sort_left_dec(2);
+
+ goto end;
+ default:
+ if (TINY_NODE(sl) || (sl->level > 15)) {
+ listcoll_t func;
+
+ func = get_list_call_func(sl->level);
+
+ sl->leaves = sl->tosort;
+ sl->leaves_num = sl->tosort_num;
+ sl->leaves_sz = sl->leaves_num;
+ sl->leaves = sort_realloc(sl->leaves,
+ (sizeof(struct sort_list_item *) *
+ (sl->leaves_sz)));
+ sl->tosort = NULL;
+ sl->tosort_num = 0;
+ sl->tosort_sz = 0;
+ sl->sln = 0;
+ sl->real_sln = 0;
+ if (sort_opts_vals.sflag) {
+ if (mergesort(sl->leaves, sl->leaves_num,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) func) == -1)
+ /* NOTREACHED */
+ err(2, "Radix sort error 3");
+ } else
+ DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) func);
+
+ memcpy(sl->sorted + sl->start_position,
+ sl->leaves, sl->leaves_num *
+ sizeof(struct sort_list_item*));
+
+ sort_left_dec(sl->leaves_num);
+
+ goto end;
+ } else {
+ sl->tosort_sz = sl->tosort_num;
+ sl->tosort = sort_realloc(sl->tosort,
+ sizeof(struct sort_list_item*) * (sl->tosort_sz));
+ }
+ }
+
+ sl->sln = 256;
+ sl->sublevels = sort_malloc(slsz);
+ memset(sl->sublevels, 0, slsz);
+
+ sl->real_sln = 0;
+
+ tosort_num = sl->tosort_num;
+ for (i = 0; i < tosort_num; ++i)
+ place_item(sl, i);
+
+ sort_free(sl->tosort);
+ sl->tosort = NULL;
+ sl->tosort_num = 0;
+ sl->tosort_sz = 0;
+
+ if (sl->leaves_num > 1) {
+ if (keys_num > 1) {
+ if (sort_opts_vals.sflag) {
+ mergesort(sl->leaves, sl->leaves_num,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) list_coll);
+ } else {
+ DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) list_coll);
+ }
+ } else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) {
+ DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) list_coll_by_str_only);
+ }
+ }
+
+ sl->leaves_sz = sl->leaves_num;
+ sl->leaves = sort_realloc(sl->leaves, (sizeof(struct sort_list_item *) *
+ (sl->leaves_sz)));
+
+ if (!reverse_sort) {
+ memcpy(sl->sorted + sl->start_position, sl->leaves,
+ sl->leaves_num * sizeof(struct sort_list_item*));
+ sl->start_position += sl->leaves_num;
+ sort_left_dec(sl->leaves_num);
+
+ sort_free(sl->leaves);
+ sl->leaves = NULL;
+ sl->leaves_num = 0;
+ sl->leaves_sz = 0;
+
+ sln = sl->sln;
+
+ for (i = 0; i < sln; ++i) {
+ slc = sl->sublevels[i];
+
+ if (slc) {
+ slc->sorted = sl->sorted;
+ slc->start_position = sl->start_position;
+ sl->start_position += slc->tosort_num;
+ if (SMALL_NODE(slc))
+ run_sort_level_next(slc);
+ else
+ push_ls(slc);
+ sl->sublevels[i] = NULL;
+ }
+ }
+
+ } else {
+ size_t n;
+
+ sln = sl->sln;
+
+ for (i = 0; i < sln; ++i) {
+ n = sln - i - 1;
+ slc = sl->sublevels[n];
+
+ if (slc) {
+ slc->sorted = sl->sorted;
+ slc->start_position = sl->start_position;
+ sl->start_position += slc->tosort_num;
+ if (SMALL_NODE(slc))
+ run_sort_level_next(slc);
+ else
+ push_ls(slc);
+ sl->sublevels[n] = NULL;
+ }
+ }
+
+ memcpy(sl->sorted + sl->start_position, sl->leaves,
+ sl->leaves_num * sizeof(struct sort_list_item*));
+ sort_left_dec(sl->leaves_num);
+ }
+
+end:
+ free_sort_level(sl);
+}
+
+/*
+ * Single-threaded sort cycle
+ */
+static void
+run_sort_cycle_st(void)
+{
+ struct sort_level *slc;
+
+ for (;;) {
+ slc = pop_ls_st();
+ if (slc == NULL) {
+ break;
+ }
+ run_sort_level_next(slc);
+ }
+}
+
+#if defined(SORT_THREADS)
+
+/*
+ * Multi-threaded sort cycle
+ */
+static void
+run_sort_cycle_mt(void)
+{
+ struct sort_level *slc;
+
+ for (;;) {
+ slc = pop_ls_mt();
+ if (slc == NULL)
+ break;
+ run_sort_level_next(slc);
+ }
+}
+
+/*
+ * Sort cycle thread (in multi-threaded mode)
+ */
+static void*
+sort_thread(void* arg)
+{
+
+ run_sort_cycle_mt();
+
+#ifndef __APPLE__
+ sem_post(&mtsem);
+#else
+ semaphore_signal(rmtsem);
+#endif
+
+ return (arg);
+}
+
+#endif /* defined(SORT_THREADS) */
+
+static void
+run_top_sort_level(struct sort_level *sl)
+{
+ struct sort_level *slc;
+
+ reverse_sort = sort_opts_vals.kflag ? keys[0].sm.rflag :
+ default_sort_mods->rflag;
+
+ sl->start_position = 0;
+ sl->sln = 256;
+ sl->sublevels = sort_malloc(slsz);
+ memset(sl->sublevels, 0, slsz);
+
+ for (size_t i = 0; i < sl->tosort_num; ++i)
+ place_item(sl, i);
+
+ if (sl->leaves_num > 1) {
+ if (keys_num > 1) {
+ if (sort_opts_vals.sflag) {
+ mergesort(sl->leaves, sl->leaves_num,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) list_coll);
+ } else {
+ DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) list_coll);
+ }
+ } else if (!sort_opts_vals.sflag && sort_opts_vals.complex_sort) {
+ DEFAULT_SORT_FUNC_RADIXSORT(sl->leaves, sl->leaves_num,
+ sizeof(struct sort_list_item *),
+ (int(*)(const void *, const void *)) list_coll_by_str_only);
+ }
+ }
+
+ if (!reverse_sort) {
+ memcpy(sl->tosort + sl->start_position, sl->leaves,
+ sl->leaves_num * sizeof(struct sort_list_item*));
+ sl->start_position += sl->leaves_num;
+ sort_left_dec(sl->leaves_num);
+
+ for (size_t i = 0; i < sl->sln; ++i) {
+ slc = sl->sublevels[i];
+
+ if (slc) {
+ slc->sorted = sl->tosort;
+ slc->start_position = sl->start_position;
+ sl->start_position += slc->tosort_num;
+ push_ls(slc);
+ sl->sublevels[i] = NULL;
+ }
+ }
+
+ } else {
+ size_t n;
+
+ for (size_t i = 0; i < sl->sln; ++i) {
+
+ n = sl->sln - i - 1;
+ slc = sl->sublevels[n];
+
+ if (slc) {
+ slc->sorted = sl->tosort;
+ slc->start_position = sl->start_position;
+ sl->start_position += slc->tosort_num;
+ push_ls(slc);
+ sl->sublevels[n] = NULL;
+ }
+ }
+
+ memcpy(sl->tosort + sl->start_position, sl->leaves,
+ sl->leaves_num * sizeof(struct sort_list_item*));
+
+ sort_left_dec(sl->leaves_num);
+ }
+
+#if defined(SORT_THREADS)
+ if (nthreads < 2) {
+#endif
+ run_sort_cycle_st();
+#if defined(SORT_THREADS)
+ } else {
+ size_t i;
+
+ for(i = 0; i < nthreads; ++i) {
+ pthread_attr_t attr;
+ pthread_t pth;
+
+ pthread_attr_init(&attr);
+#ifndef __APPLE__
+ pthread_attr_setdetachstate(&attr,
+ PTHREAD_DETACHED);
+#else
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+#endif
+
+ for (;;) {
+ int res = pthread_create(&pth, &attr,
+ sort_thread, NULL);
+ if (res >= 0)
+ break;
+ if (errno == EAGAIN) {
+#ifndef __APPLE__
+ pthread_yield();
+#else
+ sched_yield();
+#endif
+ continue;
+ }
+ err(2, NULL);
+ }
+
+ pthread_attr_destroy(&attr);
+ }
+
+ for(i = 0; i < nthreads; ++i)
+#ifndef __APPLE__
+ sem_wait(&mtsem);
+#else
+ semaphore_wait(rmtsem);
+#endif
+ }
+#endif /* defined(SORT_THREADS) */
+}
+
+static void
+run_sort(struct sort_list_item **base, size_t nmemb)
+{
+ struct sort_level *sl;
+
+#if defined(SORT_THREADS)
+ size_t nthreads_save = nthreads;
+ if (nmemb < MT_SORT_THRESHOLD)
+ nthreads = 1;
+
+ if (nthreads > 1) {
+ pthread_mutexattr_t mattr;
+
+ pthread_mutexattr_init(&mattr);
+#ifndef __APPLE__
+ pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
+#endif
+
+ pthread_mutex_init(&g_ls_mutex, &mattr);
+ pthread_cond_init(&g_ls_cond, NULL);
+
+ pthread_mutexattr_destroy(&mattr);
+
+#ifndef __APPLE__
+ sem_init(&mtsem, 0, 0);
+#else
+ {
+ mach_port_t self = mach_task_self();
+ kern_return_t ret = semaphore_create(self, &rmtsem, SYNC_POLICY_FIFO, 0);
+ if (ret != KERN_SUCCESS) {
+ err(2,NULL);
+ }
+ }
+#endif
+
+ }
+#endif
+
+ sl = sort_malloc(sizeof(struct sort_level));
+ memset(sl, 0, sizeof(struct sort_level));
+
+ sl->tosort = base;
+ sl->tosort_num = nmemb;
+ sl->tosort_sz = nmemb;
+
+#if defined(SORT_THREADS)
+ sort_left = nmemb;
+#endif
+
+ run_top_sort_level(sl);
+
+ free_sort_level(sl);
+
+#if defined(SORT_THREADS)
+ if (nthreads > 1) {
+#ifndef __APPLE__
+ sem_destroy(&mtsem);
+#else
+ {
+ mach_port_t self = mach_task_self();
+ semaphore_destroy(self,rmtsem);
+ }
+#endif
+ pthread_mutex_destroy(&g_ls_mutex);
+ }
+ nthreads = nthreads_save;
+#endif
+}
+
+void
+rxsort(struct sort_list_item **base, size_t nmemb)
+{
+
+ run_sort(base, nmemb);
+}
diff --git a/text_cmds/sort/radixsort.h b/text_cmds/sort/radixsort.h
new file mode 100644
index 0000000..8743728
--- /dev/null
+++ b/text_cmds/sort/radixsort.h
@@ -0,0 +1,38 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
+ * Copyright (C) 2012 Gabor Kovesdan <gabor@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.
+ */
+
+#if !defined(__SORT_RADIX_H__)
+#define __SORT_RADIX_H__
+
+#include "coll.h"
+#include "sort.h"
+
+void rxsort(struct sort_list_item **base, size_t nmemb);
+
+#endif /* __SORT_RADIX_H__ */
diff --git a/text_cmds/sort/sort.1.in b/text_cmds/sort/sort.1.in
new file mode 100644
index 0000000..a2234e8
--- /dev/null
+++ b/text_cmds/sort/sort.1.in
@@ -0,0 +1,639 @@
+.\" $OpenBSD: sort.1,v 1.45 2015/03/19 13:51:10 jmc Exp $
+.\" $FreeBSD: head/usr.bin/sort/sort.1.in 305613 2016-09-08 14:50:23Z gabor $
+.\"
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)sort.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd March 19, 2015
+.Dt SORT 1
+.Os
+.Sh NAME
+.Nm sort
+.Nd sort or merge records (lines) of text and binary files
+.Sh SYNOPSIS
+.Nm
+.Bk -words
+.Op Fl bcCdfghiRMmnrsuVz
+.Sm off
+.Op Fl k\ \& Ar field1 Op , Ar field2
+.Sm on
+.Op Fl S Ar memsize
+.Ek
+.Op Fl T Ar dir
+.Op Fl t Ar char
+.Op Fl o Ar output
+.Op Ar file ...
+.Nm
+.Fl Fl help
+.Nm
+.Fl Fl version
+.Sh DESCRIPTION
+The
+.Nm
+utility sorts text and binary files by lines.
+A line is a record separated from the subsequent record by a
+newline (default) or NUL \'\\0\' character (-z option).
+A record can contain any printable or unprintable characters.
+Comparisons are based on one or more sort keys extracted from
+each line of input, and are performed lexicographically,
+according to the current locale's collating rules and the
+specified command-line options that can tune the actual
+sorting behavior.
+By default, if keys are not given,
+.Nm
+uses entire lines for comparison.
+.Pp
+The command line options are as follows:
+.Bl -tag -width Ds
+.It Fl c , Fl Fl check , Fl C , Fl Fl check=silent|quiet
+Check that the single input file is sorted.
+If the file is not sorted,
+.Nm
+produces the appropriate error messages and exits with code 1,
+otherwise returns 0.
+If
+.Fl C
+or
+.Fl Fl check=silent
+is specified,
+.Nm
+produces no output.
+This is a "silent" version of
+.Fl c .
+.It Fl m , Fl Fl merge
+Merge only.
+The input files are assumed to be pre-sorted.
+If they are not sorted the output order is undefined.
+.It Fl o Ar output , Fl Fl output Ns = Ns Ar output
+Print the output to the
+.Ar output
+file instead of the standard output.
+.It Fl S Ar size , Fl Fl buffer-size Ns = Ns Ar size
+Use
+.Ar size
+for the maximum size of the memory buffer.
+Size modifiers %,b,K,M,G,T,P,E,Z,Y can be used.
+If a memory limit is not explicitly specified,
+.Nm
+takes up to about 90% of available memory.
+If the file size is too big to fit into the memory buffer,
+the temporary disk files are used to perform the sorting.
+.It Fl T Ar dir , Fl Fl temporary-directory Ns = Ns Ar dir
+Store temporary files in the directory
+.Ar dir .
+The default path is the value of the environment variable
+.Ev TMPDIR
+or
+.Pa /var/tmp
+if
+.Ev TMPDIR
+is not defined.
+.It Fl u , Fl Fl unique
+Unique keys.
+Suppress all lines that have a key that is equal to an already
+processed one.
+This option, similarly to
+.Fl s ,
+implies a stable sort.
+If used with
+.Fl c
+or
+.Fl C ,
+.Nm
+also checks that there are no lines with duplicate keys.
+.It Fl s
+Stable sort.
+This option maintains the original record order of records that have
+an equal key.
+This is a non-standard feature, but it is widely accepted and used.
+.It Fl Fl version
+Print the version and silently exits.
+.It Fl Fl help
+Print the help text and silently exits.
+.El
+.Pp
+The following options override the default ordering rules.
+When ordering options appear independently of key field
+specifications, they apply globally to all sort keys.
+When attached to a specific key (see
+.Fl k ) ,
+the ordering options override all global ordering options for
+the key they are attached to.
+.Bl -tag -width indent
+.It Fl b , Fl Fl ignore-leading-blanks
+Ignore leading blank characters when comparing lines.
+.It Fl d , Fl Fl dictionary-order
+Consider only blank spaces and alphanumeric characters in comparisons.
+.It Fl f , Fl Fl ignore-case
+Convert all lowercase characters to their uppercase equivalent
+before comparison, that is, perform case-independent sorting.
+.It Fl g , Fl Fl general-numeric-sort , Fl Fl sort=general-numeric
+Sort by general numerical value.
+As opposed to
+.Fl n ,
+this option handles general floating points.
+It has a more
+permissive format than that allowed by
+.Fl n
+but it has a significant performance drawback.
+.It Fl h , Fl Fl human-numeric-sort , Fl Fl sort=human-numeric
+Sort by numerical value, but take into account the SI suffix,
+if present.
+Sort first by numeric sign (negative, zero, or
+positive); then by SI suffix (either empty, or `k' or `K', or one
+of `MGTPEZY', in that order); and finally by numeric value.
+The SI suffix must immediately follow the number.
+For example, '12345K' sorts before '1M', because M is "larger" than K.
+This sort option is useful for sorting the output of a single invocation
+of 'df' command with
+.Fl h
+or
+.Fl H
+options (human-readable).
+.It Fl i , Fl Fl ignore-nonprinting
+Ignore all non-printable characters.
+.It Fl M , Fl Fl month-sort , Fl Fl sort=month
+Sort by month abbreviations.
+Unknown strings are considered smaller than the month names.
+.It Fl n , Fl Fl numeric-sort , Fl Fl sort=numeric
+Sort fields numerically by arithmetic value.
+Fields are supposed to have optional blanks in the beginning, an
+optional minus sign, zero or more digits (including decimal point and
+possible thousand separators).
+.It Fl R , Fl Fl random-sort , Fl Fl sort=random
+Sort by a random order.
+This is a random permutation of the inputs except that
+the equal keys sort together.
+It is implemented by hashing the input keys and sorting
+the hash values.
+The hash function is chosen randomly.
+The hash function is randomized by
+.Cm /dev/random
+content, or by file content if it is specified by
+.Fl Fl random-source .
+Even if multiple sort fields are specified,
+the same random hash function is used for all of them.
+.It Fl r , Fl Fl reverse
+Sort in reverse order.
+.It Fl V , Fl Fl version-sort
+Sort version numbers.
+The input lines are treated as file names in form
+PREFIX VERSION SUFFIX, where SUFFIX matches the regular expression
+"(\.([A-Za-z~][A-Za-z0-9~]*)?)*".
+The files are compared by their prefixes and versions (leading
+zeros are ignored in version numbers, see example below).
+If an input string does not match the pattern, then it is compared
+using the byte compare function.
+All string comparisons are performed in C locale, the locale
+environment setting is ignored.
+.Bl -tag -width indent
+.It Example:
+.It $ ls sort* | sort -V
+.It sort-1.022.tgz
+.It sort-1.23.tgz
+.It sort-1.23.1.tgz
+.It sort-1.024.tgz
+.It sort-1.024.003.
+.It sort-1.024.003.tgz
+.It sort-1.024.07.tgz
+.It sort-1.024.009.tgz
+.El
+.El
+.Pp
+The treatment of field separators can be altered using these options:
+.Bl -tag -width indent
+.It Fl b , Fl Fl ignore-leading-blanks
+Ignore leading blank space when determining the start
+and end of a restricted sort key (see
+.Fl k ) .
+If
+.Fl b
+is specified before the first
+.Fl k
+option, it applies globally to all key specifications.
+Otherwise,
+.Fl b
+can be attached independently to each
+.Ar field
+argument of the key specifications.
+.Fl b .
+.It Xo
+.Fl k Ar field1 Ns Op , Ns Ar field2 ,
+.Fl Fl key Ns = Ns Ar field1 Ns Op , Ns Ar field2
+.Xc
+Define a restricted sort key that has the starting position
+.Ar field1 ,
+and optional ending position
+.Ar field2
+of a key field.
+The
+.Fl k
+option may be specified multiple times,
+in which case subsequent keys are compared when earlier keys compare equal.
+The
+.Fl k
+option replaces the obsolete options
+.Cm \(pl Ns Ar pos1
+and
+.Fl Ns Ar pos2 ,
+but the old notation is also supported.
+.It Fl t Ar char , Fl Fl field-separator Ns = Ns Ar char
+Use
+.Ar char
+as a field separator character.
+The initial
+.Ar char
+is not considered to be part of a field when determining key offsets.
+Each occurrence of
+.Ar char
+is significant (for example,
+.Dq Ar charchar
+delimits an empty field).
+If
+.Fl t
+is not specified, the default field separator is a sequence of
+blank space characters, and consecutive blank spaces do
+.Em not
+delimit an empty field, however, the initial blank space
+.Em is
+considered part of a field when determining key offsets.
+To use NUL as field separator, use
+.Fl t
+\'\\0\'.
+.It Fl z , Fl Fl zero-terminated
+Use NUL as record separator.
+By default, records in the files are supposed to be separated by
+the newline characters.
+With this option, NUL (\'\\0\') is used as a record separator character.
+.El
+.Pp
+Other options:
+.Bl -tag -width indent
+.It Fl Fl batch-size Ns = Ns Ar num
+Specify maximum number of files that can be opened by
+.Nm
+at once.
+This option affects behavior when having many input files or using
+temporary files.
+The default value is 16.
+.It Fl Fl compress-program Ns = Ns Ar PROGRAM
+Use PROGRAM to compress temporary files.
+PROGRAM must compress standard input to standard output, when called
+without arguments.
+When called with argument
+.Fl d
+it must decompress standard input to standard output.
+If PROGRAM fails,
+.Nm
+must exit with error.
+An example of PROGRAM that can be used here is bzip2.
+.It Fl Fl random-source Ns = Ns Ar filename
+In random sort, the file content is used as the source of the 'seed' data
+for the hash function choice.
+Two invocations of random sort with the same seed data will use
+the same hash function and will produce the same result if the input is
+also identical.
+By default, file
+.Cm /dev/random
+is used.
+.It Fl Fl debug
+Print some extra information about the sorting process to the
+standard output.
+%%THREADS%%.It Fl Fl parallel
+%%THREADS%%Set the maximum number of execution threads.
+%%THREADS%%Default number equals to the number of CPUs.
+.It Fl Fl files0-from Ns = Ns Ar filename
+Take the input file list from the file
+.Ar filename .
+The file names must be separated by NUL
+(like the output produced by the command "find ... -print0").
+.It Fl Fl radixsort
+Try to use radix sort, if the sort specifications allow.
+The radix sort can only be used for trivial locales (C and POSIX),
+and it cannot be used for numeric or month sort.
+Radix sort is very fast and stable.
+.It Fl Fl mergesort
+Use mergesort.
+This is a universal algorithm that can always be used,
+but it is not always the fastest.
+.It Fl Fl qsort
+Try to use quick sort, if the sort specifications allow.
+This sort algorithm cannot be used with
+.Fl u
+and
+.Fl s .
+.It Fl Fl heapsort
+Try to use heap sort, if the sort specifications allow.
+This sort algorithm cannot be used with
+.Fl u
+and
+.Fl s .
+.It Fl Fl mmap
+Try to use file memory mapping system call.
+It may increase speed in some cases.
+.El
+.Pp
+The following operands are available:
+.Bl -tag -width indent
+.It Ar file
+The pathname of a file to be sorted, merged, or checked.
+If no
+.Ar file
+operands are specified, or if a
+.Ar file
+operand is
+.Fl ,
+the standard input is used.
+.El
+.Pp
+A field is defined as a maximal sequence of characters other than the
+field separator and record separator (newline by default).
+Initial blank spaces are included in the field unless
+.Fl b
+has been specified;
+the first blank space of a sequence of blank spaces acts as the field
+separator and is included in the field (unless
+.Fl t
+is specified).
+For example, all blank spaces at the beginning of a line are
+considered to be part of the first field.
+.Pp
+Fields are specified by the
+.Sm off
+.Fl k\ \& Ar field1 Op , Ar field2
+.Sm on
+command-line option.
+If
+.Ar field2
+is missing, the end of the key defaults to the end of the line.
+.Pp
+The arguments
+.Ar field1
+and
+.Ar field2
+have the form
+.Em m.n
+.Em (m,n > 0)
+and can be followed by one or more of the modifiers
+.Cm b , d , f , i ,
+.Cm n , g , M
+and
+.Cm r ,
+which correspond to the options discussed above.
+When
+.Cm b
+is specified it applies only to
+.Ar field1
+or
+.Ar field2
+where it is specified while the rest of the modifiers
+apply to the whole key field regardless if they are
+specified only with
+.Ar field1
+or
+.Ar field2
+or both.
+A
+.Ar field1
+position specified by
+.Em m.n
+is interpreted as the
+.Em n Ns th
+character from the beginning of the
+.Em m Ns th
+field.
+A missing
+.Em \&.n
+in
+.Ar field1
+means
+.Ql \&.1 ,
+indicating the first character of the
+.Em m Ns th
+field; if the
+.Fl b
+option is in effect,
+.Em n
+is counted from the first non-blank character in the
+.Em m Ns th
+field;
+.Em m Ns \&.1b
+refers to the first non-blank character in the
+.Em m Ns th
+field.
+.No 1\&. Ns Em n
+refers to the
+.Em n Ns th
+character from the beginning of the line;
+if
+.Em n
+is greater than the length of the line, the field is taken to be empty.
+.Pp
+.Em n Ns th
+positions are always counted from the field beginning, even if the field
+is shorter than the number of specified positions.
+Thus, the key can really start from a position in a subsequent field.
+.Pp
+A
+.Ar field2
+position specified by
+.Em m.n
+is interpreted as the
+.Em n Ns th
+character (including separators) from the beginning of the
+.Em m Ns th
+field.
+A missing
+.Em \&.n
+indicates the last character of the
+.Em m Ns th
+field;
+.Em m
+= \&0
+designates the end of a line.
+Thus the option
+.Fl k Ar v.x,w.y
+is synonymous with the obsolete option
+.Cm \(pl Ns Ar v-\&1.x-\&1
+.Fl Ns Ar w-\&1.y ;
+when
+.Em y
+is omitted,
+.Fl k Ar v.x,w
+is synonymous with
+.Cm \(pl Ns Ar v-\&1.x-\&1
+.Fl Ns Ar w\&.0 .
+The obsolete
+.Cm \(pl Ns Ar pos1
+.Fl Ns Ar pos2
+option is still supported, except for
+.Fl Ns Ar w\&.0b ,
+which has no
+.Fl k
+equivalent.
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev LC_COLLATE
+Locale settings to be used to determine the collation for
+sorting records.
+.It Ev LC_CTYPE
+Locale settings to be used to case conversion and classification
+of characters, that is, which characters are considered
+whitespaces, etc.
+.It Ev LC_MESSAGES
+Locale settings that determine the language of output messages
+that
+.Nm
+prints out.
+.It Ev LC_NUMERIC
+Locale settings that determine the number format used in numeric sort.
+.It Ev LC_TIME
+Locale settings that determine the month format used in month sort.
+.It Ev LC_ALL
+Locale settings that override all of the above locale settings.
+This environment variable can be used to set all these settings
+to the same value at once.
+.It Ev LANG
+Used as a last resort to determine different kinds of locale-specific
+behavior if neither the respective environment variable, nor
+.Ev LC_ALL
+are set.
+%%NLS%%.It Ev NLSPATH
+%%NLS%%Path to NLS catalogs.
+.It Ev TMPDIR
+Path to the directory in which temporary files will be stored.
+Note that
+.Ev TMPDIR
+may be overridden by the
+.Fl T
+option.
+.It Ev GNUSORT_NUMERIC_COMPATIBILITY
+If defined
+.Fl t
+will not override the locale numeric symbols, that is, thousand
+separators and decimal separators.
+By default, if we specify
+.Fl t
+with the same symbol as the thousand separator or decimal point,
+the symbol will be treated as the field separator.
+Older behavior was less definite; the symbol was treated as both field
+separator and numeric separator, simultaneously.
+This environment variable enables the old behavior.
+.It Ev GNUSORT_COMPATIBLE_BLANKS
+Use 'space' symbols as field separators (as modern GNU sort does).
+.El
+.Sh FILES
+.Bl -tag -width Pa -compact
+.It Pa /var/tmp/.bsdsort.PID.*
+Temporary files.
+.It Pa /dev/random
+Default seed file for the random sort.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+utility shall exit with one of the following values:
+.Pp
+.Bl -tag -width flag -compact
+.It 0
+Successfully sorted the input files or if used with
+.Fl c
+or
+.Fl C ,
+the input file already met the sorting criteria.
+.It 1
+On disorder (or non-uniqueness) with the
+.Fl c
+or
+.Fl C
+options.
+.It 2
+An error occurred.
+.El
+.Sh SEE ALSO
+.Xr comm 1 ,
+.Xr join 1 ,
+.Xr uniq 1
+.Sh STANDARDS
+The
+.Nm
+utility is compliant with the
+.St -p1003.1-2008
+specification.
+.Pp
+The flags
+.Op Fl ghRMSsTVz
+are extensions to the POSIX specification.
+.Pp
+All long options are extensions to the specification, some of them are
+provided for compatibility with GNU versions and some of them are
+own extensions.
+.Pp
+The old key notations
+.Cm \(pl Ns Ar pos1
+and
+.Fl Ns Ar pos2
+come from older versions of
+.Nm
+and are still supported but their use is highly discouraged.
+.Sh HISTORY
+A
+.Nm
+command first appeared in
+.At v3 .
+.Sh AUTHORS
+.An Gabor Kovesdan Aq Mt gabor@FreeBSD.org ,
+.Pp
+.An Oleg Moskalenko Aq Mt mom040267@gmail.com
+.Sh NOTES
+This implementation of
+.Nm
+has no limits on input line length (other than imposed by available
+memory) or any restrictions on bytes allowed within lines.
+.Pp
+The performance depends highly on locale settings,
+efficient choice of sort keys and key complexity.
+The fastest sort is with locale C, on whole lines,
+with option
+.Fl s .
+In general, locale C is the fastest, then single-byte
+locales follow and multi-byte locales as the slowest but
+the correct collation order is always respected.
+As for the key specification, the simpler to process the
+lines the faster the search will be.
+.Pp
+When sorting by arithmetic value, using
+.Fl n
+results in much better performance than
+.Fl g
+so its use is encouraged
+whenever possible.
diff --git a/text_cmds/sort/sort.c b/text_cmds/sort/sort.c
new file mode 100644
index 0000000..9200606
--- /dev/null
+++ b/text_cmds/sort/sort.c
@@ -0,0 +1,1325 @@
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <locale.h>
+#ifndef __APPLE__
+#include <md5.h>
+#endif
+#include <regex.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "coll.h"
+#include "file.h"
+#include "sort.h"
+
+#ifndef WITHOUT_NLS
+#include <nl_types.h>
+nl_catd catalog;
+#endif
+
+#define OPTIONS "bcCdfghik:Mmno:RrsS:t:T:uVz"
+
+#define DEFAULT_RANDOM_SORT_SEED_FILE ("/dev/random")
+#define MAX_DEFAULT_RANDOM_SEED_DATA_SIZE (1024)
+
+static bool need_random;
+static const char *random_source = DEFAULT_RANDOM_SORT_SEED_FILE;
+static const void *random_seed;
+static size_t random_seed_size;
+
+MD5_CTX md5_ctx;
+
+/*
+ * Default messages to use when NLS is disabled or no catalogue
+ * is found.
+ */
+const char *nlsstr[] = { "",
+/* 1*/"mutually exclusive flags",
+/* 2*/"extra argument not allowed with -c",
+/* 3*/"Unknown feature",
+/* 4*/"Wrong memory buffer specification",
+/* 5*/"0 field in key specs",
+/* 6*/"0 column in key specs",
+/* 7*/"Wrong file mode",
+/* 8*/"Cannot open file for reading",
+/* 9*/"Radix sort cannot be used with these sort options",
+/*10*/"The chosen sort method cannot be used with stable and/or unique sort",
+/*11*/"Invalid key position",
+/*12*/"Usage: %s [-bcCdfigMmnrsuz] [-kPOS1[,POS2] ... ] "
+ "[+POS1 [-POS2]] [-S memsize] [-T tmpdir] [-t separator] "
+ "[-o outfile] [--batch-size size] [--files0-from file] "
+ "[--heapsort] [--mergesort] [--radixsort] [--qsort] "
+ "[--mmap] "
+#if defined(SORT_THREADS)
+ "[--parallel thread_no] "
+#endif
+ "[--human-numeric-sort] "
+ "[--version-sort] [--random-sort [--random-source file]] "
+ "[--compress-program program] [file ...]\n" };
+
+struct sort_opts sort_opts_vals;
+
+bool debug_sort;
+bool need_hint;
+
+int (*isblank_f)(int c) = isblank;
+int (*iswblank_f)(wint_t c) = iswblank;
+
+#if defined(SORT_THREADS)
+unsigned int ncpu = 1;
+size_t nthreads = 1;
+#endif
+
+static bool gnusort_numeric_compatibility;
+
+static struct sort_mods default_sort_mods_object;
+struct sort_mods * const default_sort_mods = &default_sort_mods_object;
+
+static bool print_symbols_on_debug;
+
+/*
+ * Arguments from file (when file0-from option is used:
+ */
+static size_t argc_from_file0 = (size_t)-1;
+static char **argv_from_file0;
+
+/*
+ * Placeholder symbols for options which have no single-character equivalent
+ */
+enum
+{
+ SORT_OPT = CHAR_MAX + 1,
+ HELP_OPT,
+ FF_OPT,
+ BS_OPT,
+ VERSION_OPT,
+ DEBUG_OPT,
+#if defined(SORT_THREADS)
+ PARALLEL_OPT,
+#endif
+ RANDOMSOURCE_OPT,
+ COMPRESSPROGRAM_OPT,
+ QSORT_OPT,
+ MERGESORT_OPT,
+ HEAPSORT_OPT,
+ RADIXSORT_OPT,
+ MMAP_OPT
+};
+
+#define NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS 6
+static const char mutually_exclusive_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] = { 'M', 'n', 'g', 'R', 'h', 'V' };
+
+static struct option long_options[] = {
+ { "batch-size", required_argument, NULL, BS_OPT },
+ { "buffer-size", required_argument, NULL, 'S' },
+ { "check", optional_argument, NULL, 'c' },
+ { "check=silent|quiet", optional_argument, NULL, 'C' },
+ { "compress-program", required_argument, NULL, COMPRESSPROGRAM_OPT },
+ { "debug", no_argument, NULL, DEBUG_OPT },
+ { "dictionary-order", no_argument, NULL, 'd' },
+ { "field-separator", required_argument, NULL, 't' },
+ { "files0-from", required_argument, NULL, FF_OPT },
+ { "general-numeric-sort", no_argument, NULL, 'g' },
+ { "heapsort", no_argument, NULL, HEAPSORT_OPT },
+ { "help",no_argument, NULL, HELP_OPT },
+ { "human-numeric-sort", no_argument, NULL, 'h' },
+ { "ignore-leading-blanks", no_argument, NULL, 'b' },
+ { "ignore-case", no_argument, NULL, 'f' },
+ { "ignore-nonprinting", no_argument, NULL, 'i' },
+ { "key", required_argument, NULL, 'k' },
+ { "merge", no_argument, NULL, 'm' },
+ { "mergesort", no_argument, NULL, MERGESORT_OPT },
+ { "mmap", no_argument, NULL, MMAP_OPT },
+ { "month-sort", no_argument, NULL, 'M' },
+ { "numeric-sort", no_argument, NULL, 'n' },
+ { "output", required_argument, NULL, 'o' },
+#if defined(SORT_THREADS)
+ { "parallel", required_argument, NULL, PARALLEL_OPT },
+#endif
+ { "qsort", no_argument, NULL, QSORT_OPT },
+ { "radixsort", no_argument, NULL, RADIXSORT_OPT },
+ { "random-sort", no_argument, NULL, 'R' },
+ { "random-source", required_argument, NULL, RANDOMSOURCE_OPT },
+ { "reverse", no_argument, NULL, 'r' },
+ { "sort", required_argument, NULL, SORT_OPT },
+ { "stable", no_argument, NULL, 's' },
+ { "temporary-directory",required_argument, NULL, 'T' },
+ { "unique", no_argument, NULL, 'u' },
+ { "version", no_argument, NULL, VERSION_OPT },
+ { "version-sort",no_argument, NULL, 'V' },
+ { "zero-terminated", no_argument, NULL, 'z' },
+ { NULL, no_argument, NULL, 0 }
+};
+
+void fix_obsolete_keys(int *argc, char **argv);
+
+/*
+ * Check where sort modifier is present
+ */
+static bool
+sort_modifier_empty(struct sort_mods *sm)
+{
+
+ if (sm == NULL)
+ return (true);
+ return (!(sm->Mflag || sm->Vflag || sm->nflag || sm->gflag ||
+ sm->rflag || sm->Rflag || sm->hflag || sm->dflag || sm->fflag || sm->iflag));
+}
+
+/*
+ * Print out usage text.
+ */
+static void
+usage(bool opt_err)
+{
+ FILE *out;
+
+ out = opt_err ? stderr : stdout;
+
+ fprintf(out, getstr(12), getprogname());
+ if (opt_err)
+ exit(2);
+ exit(0);
+}
+
+/*
+ * Read input file names from a file (file0-from option).
+ */
+static void
+read_fns_from_file0(const char *fn)
+{
+ FILE *f;
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t linelen;
+
+ if (fn == NULL)
+ return;
+
+ f = fopen(fn, "r");
+ if (f == NULL)
+ err(2, "%s", fn);
+
+ while ((linelen = getdelim(&line, &linesize, '\0', f)) != -1) {
+ if (*line != '\0') {
+ if (argc_from_file0 == (size_t) - 1)
+ argc_from_file0 = 0;
+ ++argc_from_file0;
+ argv_from_file0 = sort_realloc(argv_from_file0,
+ argc_from_file0 * sizeof(char *));
+ if (argv_from_file0 == NULL)
+ err(2, NULL);
+ argv_from_file0[argc_from_file0 - 1] = line;
+ } else {
+ free(line);
+ }
+ line = NULL;
+ linesize = 0;
+ }
+ if (ferror(f))
+ err(2, "%s: getdelim", fn);
+
+ closefile(f, fn);
+}
+
+/*
+ * Check how much RAM is available for the sort.
+ */
+static void
+set_hw_params(void)
+{
+ long pages, psize;
+
+#if defined(SORT_THREADS)
+ ncpu = 1;
+#endif
+
+ pages = sysconf(_SC_PHYS_PAGES);
+ if (pages < 1) {
+ perror("sysconf pages");
+ pages = 1;
+ }
+ psize = sysconf(_SC_PAGESIZE);
+ if (psize < 1) {
+ perror("sysconf psize");
+ psize = 4096;
+ }
+#if defined(SORT_THREADS)
+ ncpu = (unsigned int)sysconf(_SC_NPROCESSORS_ONLN);
+ if (ncpu < 1)
+ ncpu = 1;
+ else if(ncpu > 32)
+ ncpu = 32;
+
+ nthreads = ncpu;
+#endif
+
+ free_memory = (unsigned long long) pages * (unsigned long long) psize;
+ available_free_memory = free_memory / 2;
+
+ if (available_free_memory < 1024)
+ available_free_memory = 1024;
+}
+
+/*
+ * Convert "plain" symbol to wide symbol, with default value.
+ */
+static void
+conv_mbtowc(wchar_t *wc, const char *c, const wchar_t def)
+{
+
+ if (wc && c) {
+ int res;
+
+ res = mbtowc(wc, c, MB_CUR_MAX);
+ if (res < 1)
+ *wc = def;
+ }
+}
+
+/*
+ * Set current locale symbols.
+ */
+static void
+set_locale(void)
+{
+ struct lconv *lc;
+ const char *locale;
+
+ setlocale(LC_ALL, "");
+
+ lc = localeconv();
+
+ if (lc) {
+ /* obtain LC_NUMERIC info */
+ /* Convert to wide char form */
+ conv_mbtowc(&symbol_decimal_point, lc->decimal_point,
+ symbol_decimal_point);
+ conv_mbtowc(&symbol_thousands_sep, lc->thousands_sep,
+ symbol_thousands_sep);
+ conv_mbtowc(&symbol_positive_sign, lc->positive_sign,
+ symbol_positive_sign);
+ conv_mbtowc(&symbol_negative_sign, lc->negative_sign,
+ symbol_negative_sign);
+ }
+
+ if (getenv("GNUSORT_NUMERIC_COMPATIBILITY"))
+ gnusort_numeric_compatibility = true;
+
+ locale = setlocale(LC_COLLATE, NULL);
+
+ if (locale) {
+ char *tmpl;
+ const char *cclocale;
+
+ tmpl = sort_strdup(locale);
+ cclocale = setlocale(LC_COLLATE, "C");
+ if (cclocale && !strcmp(cclocale, tmpl))
+ byte_sort = true;
+ else {
+ const char *pclocale;
+
+ pclocale = setlocale(LC_COLLATE, "POSIX");
+ if (pclocale && !strcmp(pclocale, tmpl))
+ byte_sort = true;
+ }
+ setlocale(LC_COLLATE, tmpl);
+ sort_free(tmpl);
+ }
+}
+
+/*
+ * Set directory temporary files.
+ */
+static void
+set_tmpdir(void)
+{
+ char *td;
+
+ td = getenv("TMPDIR");
+ if (td != NULL)
+ tmpdir = sort_strdup(td);
+}
+
+/*
+ * Parse -S option.
+ */
+static unsigned long long
+parse_memory_buffer_value(const char *value)
+{
+
+ if (value == NULL)
+ return (available_free_memory);
+ else {
+ char *endptr;
+ unsigned long long membuf;
+
+ endptr = NULL;
+ errno = 0;
+ membuf = strtoll(value, &endptr, 10);
+
+ if (errno != 0) {
+ warn("%s",getstr(4));
+ membuf = available_free_memory;
+ } else {
+ switch (*endptr){
+ case 'Y':
+ membuf *= 1024;
+ /* FALLTHROUGH */
+ case 'Z':
+ membuf *= 1024;
+ /* FALLTHROUGH */
+ case 'E':
+ membuf *= 1024;
+ /* FALLTHROUGH */
+ case 'P':
+ membuf *= 1024;
+ /* FALLTHROUGH */
+ case 'T':
+ membuf *= 1024;
+ /* FALLTHROUGH */
+ case 'G':
+ membuf *= 1024;
+ /* FALLTHROUGH */
+ case 'M':
+ membuf *= 1024;
+ /* FALLTHROUGH */
+ case '\0':
+ case 'K':
+ membuf *= 1024;
+ /* FALLTHROUGH */
+ case 'b':
+ break;
+ case '%':
+ membuf = (available_free_memory * membuf) /
+ 100;
+ break;
+ default:
+ warnc(EINVAL, "%s", optarg);
+ membuf = available_free_memory;
+ }
+ }
+ return (membuf);
+ }
+}
+
+/*
+ * Signal handler that clears the temporary files.
+ */
+static void
+sig_handler(int sig __unused, siginfo_t *siginfo __unused,
+ void *context __unused)
+{
+
+ clear_tmp_files();
+ exit(-1);
+}
+
+/*
+ * Set signal handler on panic signals.
+ */
+static void
+set_signal_handler(void)
+{
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_sigaction = &sig_handler;
+ sa.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGTERM, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+ if (sigaction(SIGHUP, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+ if (sigaction(SIGINT, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+ if (sigaction(SIGQUIT, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+ if (sigaction(SIGABRT, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+ if (sigaction(SIGBUS, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+ if (sigaction(SIGSEGV, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+ if (sigaction(SIGUSR1, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+ if (sigaction(SIGUSR2, &sa, NULL) < 0) {
+ perror("sigaction");
+ return;
+ }
+}
+
+/*
+ * Print "unknown" message and exit with status 2.
+ */
+static void
+unknown(const char *what)
+{
+
+ errx(2, "%s: %s", getstr(3), what);
+}
+
+/*
+ * Check whether contradictory input options are used.
+ */
+static void
+check_mutually_exclusive_flags(char c, bool *mef_flags)
+{
+ int fo_index, mec;
+ bool found_others, found_this;
+
+ found_others = found_this = false;
+ fo_index = 0;
+
+ for (int i = 0; i < NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS; i++) {
+ mec = mutually_exclusive_flags[i];
+
+ if (mec != c) {
+ if (mef_flags[i]) {
+ if (found_this)
+ errx(1, "%c:%c: %s", c, mec, getstr(1));
+ found_others = true;
+ fo_index = i;
+ }
+ } else {
+ if (found_others)
+ errx(1, "%c:%c: %s", c, mutually_exclusive_flags[fo_index], getstr(1));
+ mef_flags[i] = true;
+ found_this = true;
+ }
+ }
+}
+
+/*
+ * Initialise sort opts data.
+ */
+static void
+set_sort_opts(void)
+{
+
+ memset(&default_sort_mods_object, 0,
+ sizeof(default_sort_mods_object));
+ memset(&sort_opts_vals, 0, sizeof(sort_opts_vals));
+ default_sort_mods_object.func =
+ get_sort_func(&default_sort_mods_object);
+}
+
+/*
+ * Set a sort modifier on a sort modifiers object.
+ */
+static bool
+set_sort_modifier(struct sort_mods *sm, int c)
+{
+
+ if (sm) {
+ switch (c){
+ case 'b':
+ sm->bflag = true;
+ break;
+ case 'd':
+ sm->dflag = true;
+ break;
+ case 'f':
+ sm->fflag = true;
+ break;
+ case 'g':
+ sm->gflag = true;
+ need_hint = true;
+ break;
+ case 'i':
+ sm->iflag = true;
+ break;
+ case 'R':
+ sm->Rflag = true;
+ need_random = true;
+ break;
+ case 'M':
+ initialise_months();
+ sm->Mflag = true;
+ need_hint = true;
+ break;
+ case 'n':
+ sm->nflag = true;
+ need_hint = true;
+ print_symbols_on_debug = true;
+ break;
+ case 'r':
+ sm->rflag = true;
+ break;
+ case 'V':
+ sm->Vflag = true;
+ break;
+ case 'h':
+ sm->hflag = true;
+ need_hint = true;
+ print_symbols_on_debug = true;
+ break;
+ default:
+ return false;
+ }
+ sort_opts_vals.complex_sort = true;
+ sm->func = get_sort_func(sm);
+ }
+ return (true);
+}
+
+/*
+ * Parse POS in -k option.
+ */
+static int
+parse_pos(const char *s, struct key_specs *ks, bool *mef_flags, bool second)
+{
+ regmatch_t pmatch[4];
+ regex_t re;
+ char *c, *f;
+ const char *sregexp = "^([0-9]+)(\\.[0-9]+)?([bdfirMngRhV]+)?$";
+ size_t len, nmatch;
+ int ret;
+
+ ret = -1;
+ nmatch = 4;
+ c = f = NULL;
+
+ if (regcomp(&re, sregexp, REG_EXTENDED) != 0)
+ return (-1);
+
+ if (regexec(&re, s, nmatch, pmatch, 0) != 0)
+ goto end;
+
+ if (pmatch[0].rm_eo <= pmatch[0].rm_so)
+ goto end;
+
+ if (pmatch[1].rm_eo <= pmatch[1].rm_so)
+ goto end;
+
+ len = pmatch[1].rm_eo - pmatch[1].rm_so;
+ f = sort_malloc((len + 1) * sizeof(char));
+
+ strncpy(f, s + pmatch[1].rm_so, len);
+ f[len] = '\0';
+
+ if (second) {
+ errno = 0;
+ ks->f2 = (size_t) strtoul(f, NULL, 10);
+ if (errno != 0)
+ err(2, "-k");
+ if (ks->f2 == 0) {
+ warn("%s",getstr(5));
+ goto end;
+ }
+ } else {
+ errno = 0;
+ ks->f1 = (size_t) strtoul(f, NULL, 10);
+ if (errno != 0)
+ err(2, "-k");
+ if (ks->f1 == 0) {
+ warn("%s",getstr(5));
+ goto end;
+ }
+ }
+
+ if (pmatch[2].rm_eo > pmatch[2].rm_so) {
+ len = pmatch[2].rm_eo - pmatch[2].rm_so - 1;
+ c = sort_malloc((len + 1) * sizeof(char));
+
+ strncpy(c, s + pmatch[2].rm_so + 1, len);
+ c[len] = '\0';
+
+ if (second) {
+ errno = 0;
+ ks->c2 = (size_t) strtoul(c, NULL, 10);
+ if (errno != 0)
+ err(2, "-k");
+ } else {
+ errno = 0;
+ ks->c1 = (size_t) strtoul(c, NULL, 10);
+ if (errno != 0)
+ err(2, "-k");
+ if (ks->c1 == 0) {
+ warn("%s",getstr(6));
+ goto end;
+ }
+ }
+ } else {
+ if (second)
+ ks->c2 = 0;
+ else
+ ks->c1 = 1;
+ }
+
+ if (pmatch[3].rm_eo > pmatch[3].rm_so) {
+ regoff_t i = 0;
+
+ for (i = pmatch[3].rm_so; i < pmatch[3].rm_eo; i++) {
+ check_mutually_exclusive_flags(s[i], mef_flags);
+ if (s[i] == 'b') {
+ if (second)
+ ks->pos2b = true;
+ else
+ ks->pos1b = true;
+ } else if (!set_sort_modifier(&(ks->sm), s[i]))
+ goto end;
+ }
+ }
+
+ ret = 0;
+
+end:
+
+ if (c)
+ sort_free(c);
+ if (f)
+ sort_free(f);
+ regfree(&re);
+
+ return (ret);
+}
+
+/*
+ * Parse -k option value.
+ */
+static int
+parse_k(const char *s, struct key_specs *ks)
+{
+ int ret = -1;
+ bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] =
+ { false, false, false, false, false, false };
+
+ if (s && *s) {
+ char *sptr;
+
+ sptr = strchr(s, ',');
+ if (sptr) {
+ size_t size1;
+ char *pos1, *pos2;
+
+ size1 = sptr - s;
+
+ if (size1 < 1)
+ return (-1);
+ pos1 = sort_malloc((size1 + 1) * sizeof(char));
+
+ strncpy(pos1, s, size1);
+ pos1[size1] = '\0';
+
+ ret = parse_pos(pos1, ks, mef_flags, false);
+
+ sort_free(pos1);
+ if (ret < 0)
+ return (ret);
+
+ pos2 = sort_strdup(sptr + 1);
+ ret = parse_pos(pos2, ks, mef_flags, true);
+ sort_free(pos2);
+ } else
+ ret = parse_pos(s, ks, mef_flags, false);
+ }
+
+ return (ret);
+}
+
+/*
+ * Parse POS in +POS -POS option.
+ */
+static int
+parse_pos_obs(const char *s, int *nf, int *nc, char* sopts)
+{
+ regex_t re;
+ regmatch_t pmatch[4];
+ char *c, *f;
+ const char *sregexp = "^([0-9]+)(\\.[0-9]+)?([A-Za-z]+)?$";
+ int ret;
+ size_t len, nmatch;
+
+ ret = -1;
+ nmatch = 4;
+ c = f = NULL;
+ *nc = *nf = 0;
+
+ if (regcomp(&re, sregexp, REG_EXTENDED) != 0)
+ return (-1);
+
+ if (regexec(&re, s, nmatch, pmatch, 0) != 0)
+ goto end;
+
+ if (pmatch[0].rm_eo <= pmatch[0].rm_so)
+ goto end;
+
+ if (pmatch[1].rm_eo <= pmatch[1].rm_so)
+ goto end;
+
+ len = pmatch[1].rm_eo - pmatch[1].rm_so;
+ f = sort_malloc((len + 1) * sizeof(char));
+
+ strncpy(f, s + pmatch[1].rm_so, len);
+ f[len] = '\0';
+
+ errno = 0;
+ *nf = (size_t) strtoul(f, NULL, 10);
+ if (errno != 0)
+ errx(2, "%s", getstr(11));
+
+ if (pmatch[2].rm_eo > pmatch[2].rm_so) {
+ len = pmatch[2].rm_eo - pmatch[2].rm_so - 1;
+ c = sort_malloc((len + 1) * sizeof(char));
+
+ strncpy(c, s + pmatch[2].rm_so + 1, len);
+ c[len] = '\0';
+
+ errno = 0;
+ *nc = (size_t) strtoul(c, NULL, 10);
+ if (errno != 0)
+ errx(2, "%s", getstr(11));
+ }
+
+ if (pmatch[3].rm_eo > pmatch[3].rm_so) {
+
+ len = pmatch[3].rm_eo - pmatch[3].rm_so;
+
+ strncpy(sopts, s + pmatch[3].rm_so, len);
+ sopts[len] = '\0';
+ }
+
+ ret = 0;
+
+end:
+ if (c)
+ sort_free(c);
+ if (f)
+ sort_free(f);
+ regfree(&re);
+
+ return (ret);
+}
+
+/*
+ * "Translate" obsolete +POS1 -POS2 syntax into new -kPOS1,POS2 syntax
+ */
+void
+fix_obsolete_keys(int *argc, char **argv)
+{
+ char sopt[129];
+
+ for (int i = 1; i < *argc; i++) {
+ char *arg1;
+
+ arg1 = argv[i];
+
+ if (strlen(arg1) > 1 && arg1[0] == '+') {
+ int c1, f1;
+ char sopts1[128];
+
+ sopts1[0] = 0;
+ c1 = f1 = 0;
+
+ if (parse_pos_obs(arg1 + 1, &f1, &c1, sopts1) < 0)
+ continue;
+ else {
+ f1 += 1;
+ c1 += 1;
+ if (i + 1 < *argc) {
+ char *arg2 = argv[i + 1];
+
+ if (strlen(arg2) > 1 &&
+ arg2[0] == '-') {
+ int c2, f2;
+ char sopts2[128];
+
+ sopts2[0] = 0;
+ c2 = f2 = 0;
+
+ if (parse_pos_obs(arg2 + 1,
+ &f2, &c2, sopts2) >= 0) {
+ if (c2 > 0)
+ f2 += 1;
+ sprintf(sopt, "-k%d.%d%s,%d.%d%s",
+ f1, c1, sopts1, f2, c2, sopts2);
+ argv[i] = sort_strdup(sopt);
+ for (int j = i + 1; j + 1 < *argc; j++)
+ argv[j] = argv[j + 1];
+ *argc -= 1;
+ continue;
+ }
+ }
+ }
+ sprintf(sopt, "-k%d.%d%s", f1, c1, sopts1);
+ argv[i] = sort_strdup(sopt);
+ }
+ }
+ }
+}
+
+/*
+ * Set random seed
+ */
+static void
+set_random_seed(void)
+{
+ if (need_random) {
+
+ if (strcmp(random_source, DEFAULT_RANDOM_SORT_SEED_FILE) == 0) {
+ FILE* fseed;
+ MD5_CTX ctx;
+ char rsd[MAX_DEFAULT_RANDOM_SEED_DATA_SIZE];
+ size_t sz = 0;
+
+ fseed = openfile(random_source, "r");
+ while (!feof(fseed)) {
+ int cr;
+
+ cr = fgetc(fseed);
+ if (cr == EOF)
+ break;
+
+ rsd[sz++] = (char) cr;
+
+ if (sz >= MAX_DEFAULT_RANDOM_SEED_DATA_SIZE)
+ break;
+ }
+
+ closefile(fseed, random_source);
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, rsd, sz);
+
+ random_seed = MD5End(&ctx, NULL);
+ random_seed_size = strlen(random_seed);
+
+ } else {
+ MD5_CTX ctx;
+ char *b;
+
+ MD5Init(&ctx);
+ b = MD5File(random_source, NULL);
+ if (b == NULL)
+ err(2, NULL);
+
+ random_seed = b;
+ random_seed_size = strlen(b);
+ }
+
+ MD5Init(&md5_ctx);
+ if(random_seed_size>0) {
+ MD5Update(&md5_ctx, random_seed, random_seed_size);
+ }
+ }
+}
+
+/*
+ * Main function.
+ */
+int
+main(int argc, char **argv)
+{
+ char *outfile, *real_outfile;
+ int c, result;
+ bool mef_flags[NUMBER_OF_MUTUALLY_EXCLUSIVE_FLAGS] =
+ { false, false, false, false, false, false };
+
+ result = 0;
+ outfile = sort_strdup("-");
+ real_outfile = NULL;
+
+ if(getenv("GNUSORT_COMPATIBLE_BLANKS")) {
+ isblank_f = isspace;
+ iswblank_f = iswspace;
+ }
+
+ struct sort_mods *sm = &default_sort_mods_object;
+
+ init_tmp_files();
+
+ set_signal_handler();
+
+ set_hw_params();
+ set_locale();
+ set_tmpdir();
+ set_sort_opts();
+
+ fix_obsolete_keys(&argc, argv);
+
+ while (((c = getopt_long(argc, argv, OPTIONS, long_options, NULL))
+ != -1)) {
+
+ check_mutually_exclusive_flags(c, mef_flags);
+
+ if (!set_sort_modifier(sm, c)) {
+
+ switch (c) {
+ case 'c':
+ sort_opts_vals.cflag = true;
+ if (optarg) {
+ if (!strcmp(optarg, "diagnose-first"))
+ ;
+ else if (!strcmp(optarg, "silent") ||
+ !strcmp(optarg, "quiet"))
+ sort_opts_vals.csilentflag = true;
+ else if (*optarg)
+ unknown(optarg);
+ }
+ break;
+ case 'C':
+ sort_opts_vals.cflag = true;
+ sort_opts_vals.csilentflag = true;
+ break;
+ case 'k':
+ {
+ sort_opts_vals.complex_sort = true;
+ sort_opts_vals.kflag = true;
+
+ keys_num++;
+ keys = sort_realloc(keys, keys_num *
+ sizeof(struct key_specs));
+ memset(&(keys[keys_num - 1]), 0,
+ sizeof(struct key_specs));
+
+ if (parse_k(optarg, &(keys[keys_num - 1]))
+ < 0) {
+ errc(2, EINVAL, "-k %s", optarg);
+ }
+
+ break;
+ }
+ case 'm':
+ sort_opts_vals.mflag = true;
+ break;
+ case 'o':
+ outfile = sort_realloc(outfile, (strlen(optarg) + 1));
+ strcpy(outfile, optarg);
+ break;
+ case 's':
+ sort_opts_vals.sflag = true;
+ break;
+ case 'S':
+ available_free_memory =
+ parse_memory_buffer_value(optarg);
+ break;
+ case 'T':
+ tmpdir = sort_strdup(optarg);
+ break;
+ case 't':
+ while (strlen(optarg) > 1) {
+ if (optarg[0] != '\\') {
+ errc(2, EINVAL, "%s", optarg);
+ }
+ optarg += 1;
+ if (*optarg == '0') {
+ *optarg = 0;
+ break;
+ }
+ }
+ sort_opts_vals.tflag = true;
+ sort_opts_vals.field_sep = btowc(optarg[0]);
+ if (sort_opts_vals.field_sep == WEOF) {
+ errno = EINVAL;
+ err(2, NULL);
+ }
+ if (!gnusort_numeric_compatibility) {
+ if (symbol_decimal_point == sort_opts_vals.field_sep)
+ symbol_decimal_point = WEOF;
+ if (symbol_thousands_sep == sort_opts_vals.field_sep)
+ symbol_thousands_sep = WEOF;
+ if (symbol_negative_sign == sort_opts_vals.field_sep)
+ symbol_negative_sign = WEOF;
+ if (symbol_positive_sign == sort_opts_vals.field_sep)
+ symbol_positive_sign = WEOF;
+ }
+ break;
+ case 'u':
+ sort_opts_vals.uflag = true;
+ /* stable sort for the correct unique val */
+ sort_opts_vals.sflag = true;
+ break;
+ case 'z':
+ sort_opts_vals.zflag = true;
+ break;
+ case SORT_OPT:
+ if (optarg) {
+ if (!strcmp(optarg, "general-numeric"))
+ set_sort_modifier(sm, 'g');
+ else if (!strcmp(optarg, "human-numeric"))
+ set_sort_modifier(sm, 'h');
+ else if (!strcmp(optarg, "numeric"))
+ set_sort_modifier(sm, 'n');
+ else if (!strcmp(optarg, "month"))
+ set_sort_modifier(sm, 'M');
+ else if (!strcmp(optarg, "random"))
+ set_sort_modifier(sm, 'R');
+ else
+ unknown(optarg);
+ }
+ break;
+#if defined(SORT_THREADS)
+ case PARALLEL_OPT:
+ nthreads = (size_t)(atoi(optarg));
+ if (nthreads < 1)
+ nthreads = 1;
+ if (nthreads > 1024)
+ nthreads = 1024;
+ break;
+#endif
+ case QSORT_OPT:
+ sort_opts_vals.sort_method = SORT_QSORT;
+ break;
+ case MERGESORT_OPT:
+ sort_opts_vals.sort_method = SORT_MERGESORT;
+ break;
+ case MMAP_OPT:
+ use_mmap = true;
+ break;
+ case HEAPSORT_OPT:
+ sort_opts_vals.sort_method = SORT_HEAPSORT;
+ break;
+ case RADIXSORT_OPT:
+ sort_opts_vals.sort_method = SORT_RADIXSORT;
+ break;
+ case RANDOMSOURCE_OPT:
+ random_source = strdup(optarg);
+ break;
+ case COMPRESSPROGRAM_OPT:
+ compress_program = strdup(optarg);
+ break;
+ case FF_OPT:
+ read_fns_from_file0(optarg);
+ break;
+ case BS_OPT:
+ {
+ errno = 0;
+ long mof = strtol(optarg, NULL, 10);
+ if (errno != 0)
+ err(2, "--batch-size");
+ if (mof >= 2)
+ max_open_files = (size_t) mof + 1;
+ }
+ break;
+ case VERSION_OPT:
+ printf("%s\n", VERSION);
+ exit(EXIT_SUCCESS);
+ /* NOTREACHED */
+ break;
+ case DEBUG_OPT:
+ debug_sort = true;
+ break;
+ case HELP_OPT:
+ usage(false);
+ /* NOTREACHED */
+ break;
+ default:
+ usage(true);
+ /* NOTREACHED */
+ }
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argv_from_file0) {
+ argc = argc_from_file0;
+ argv = argv_from_file0;
+ }
+
+#ifndef WITHOUT_NLS
+ catalog = catopen("sort", NL_CAT_LOCALE);
+#endif
+
+ if (sort_opts_vals.cflag && sort_opts_vals.mflag)
+ errx(1, "%c:%c: %s", 'm', 'c', getstr(1));
+
+#ifndef WITHOUT_NLS
+ catclose(catalog);
+#endif
+
+ if (keys_num == 0) {
+ keys_num = 1;
+ keys = sort_realloc(keys, sizeof(struct key_specs));
+ memset(&(keys[0]), 0, sizeof(struct key_specs));
+ keys[0].c1 = 1;
+ keys[0].pos1b = default_sort_mods->bflag;
+ keys[0].pos2b = default_sort_mods->bflag;
+ memcpy(&(keys[0].sm), default_sort_mods,
+ sizeof(struct sort_mods));
+ }
+
+ for (size_t i = 0; i < keys_num; i++) {
+ struct key_specs *ks;
+
+ ks = &(keys[i]);
+
+ if (sort_modifier_empty(&(ks->sm)) && !(ks->pos1b) &&
+ !(ks->pos2b)) {
+ ks->pos1b = sm->bflag;
+ ks->pos2b = sm->bflag;
+ memcpy(&(ks->sm), sm, sizeof(struct sort_mods));
+ }
+
+ ks->sm.func = get_sort_func(&(ks->sm));
+ }
+
+ if (debug_sort) {
+ printf("Memory to be used for sorting: %llu\n",available_free_memory);
+#if defined(SORT_THREADS)
+ printf("Number of CPUs: %d\n",(int)ncpu);
+ nthreads = 1;
+#endif
+ printf("Using collate rules of %s locale\n",
+ setlocale(LC_COLLATE, NULL));
+ if (byte_sort)
+ printf("Byte sort is used\n");
+ if (print_symbols_on_debug) {
+ printf("Decimal Point: <%lc>\n", symbol_decimal_point);
+ if (symbol_thousands_sep)
+ printf("Thousands separator: <%lc>\n",
+ symbol_thousands_sep);
+ printf("Positive sign: <%lc>\n", symbol_positive_sign);
+ printf("Negative sign: <%lc>\n", symbol_negative_sign);
+ }
+ }
+
+ set_random_seed();
+
+ /* Case when the outfile equals one of the input files: */
+ if (strcmp(outfile, "-")) {
+
+ for(int i = 0; i < argc; ++i) {
+ if (strcmp(argv[i], outfile) == 0) {
+ real_outfile = sort_strdup(outfile);
+ for(;;) {
+ char* tmp = sort_malloc(strlen(outfile) +
+ strlen(".tmp") + 1);
+
+ strcpy(tmp, outfile);
+ strcpy(tmp + strlen(tmp), ".tmp");
+ sort_free(outfile);
+ outfile = tmp;
+ if (access(outfile, F_OK) < 0)
+ break;
+ }
+ tmp_file_atexit(outfile);
+ }
+ }
+ }
+
+#if defined(SORT_THREADS)
+ if ((argc < 1) || (strcmp(outfile, "-") == 0) || (*outfile == 0))
+ nthreads = 1;
+#endif
+
+ if (!sort_opts_vals.cflag && !sort_opts_vals.mflag) {
+ struct file_list fl;
+ struct sort_list list;
+
+ sort_list_init(&list);
+ file_list_init(&fl, true);
+
+ if (argc < 1)
+ procfile("-", &list, &fl);
+ else {
+ while (argc > 0) {
+ procfile(*argv, &list, &fl);
+ --argc;
+ ++argv;
+ }
+ }
+
+ if (fl.count < 1)
+ sort_list_to_file(&list, outfile);
+ else {
+ if (list.count > 0) {
+ char *flast = new_tmp_file_name();
+
+ sort_list_to_file(&list, flast);
+ file_list_add(&fl, flast, false);
+ }
+ merge_files(&fl, outfile);
+ }
+
+ file_list_clean(&fl);
+
+ /*
+ * We are about to exit the program, so we can ignore
+ * the clean-up for speed
+ *
+ * sort_list_clean(&list);
+ */
+
+ } else if (sort_opts_vals.cflag) {
+ result = (argc == 0) ? (check("-")) : (check(*argv));
+ } else if (sort_opts_vals.mflag) {
+ struct file_list fl;
+
+ file_list_init(&fl, false);
+ file_list_populate(&fl, argc, argv, true);
+ merge_files(&fl, outfile);
+ file_list_clean(&fl);
+ }
+
+ if (real_outfile) {
+ unlink(real_outfile);
+ if (rename(outfile, real_outfile) < 0)
+ err(2, NULL);
+ sort_free(real_outfile);
+ }
+
+ sort_free(outfile);
+
+ return (result);
+}
diff --git a/text_cmds/sort/sort.h b/text_cmds/sort/sort.h
new file mode 100644
index 0000000..d31b7cb
--- /dev/null
+++ b/text_cmds/sort/sort.h
@@ -0,0 +1,139 @@
+/* $FreeBSD$ */
+
+/*-
+ * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@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.
+ * 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.
+ */
+
+#if !defined(__BSD_SORT_H__)
+#define __BSD_SORT_H__
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <sysexits.h>
+#include <wchar.h>
+
+#include <sys/types.h>
+#ifdef __APPLE__
+#include "commoncrypto.h"
+#else
+#include <md5.h>
+#endif
+
+#ifdef __APPLE__
+#define VERSION "2.3-Apple (" SORT_VERSION ")"
+#else
+#define VERSION "2.3-FreeBSD"
+#endif
+
+#ifdef WITHOUT_NLS
+#define getstr(n) nlsstr[n]
+#else
+#include <nl_types.h>
+
+extern nl_catd catalog;
+#define getstr(n) catgets(catalog, 1, n, nlsstr[n])
+#endif
+
+extern const char *nlsstr[];
+
+#if defined(SORT_THREADS)
+#define MT_SORT_THRESHOLD (10000)
+extern unsigned int ncpu;
+extern size_t nthreads;
+#endif
+
+/*
+ * If true, we output some debug information.
+ */
+extern bool debug_sort;
+
+/*
+ * MD5 context for random hash function
+ */
+extern MD5_CTX md5_ctx;
+
+/*
+ * sort.c
+ */
+
+/*
+ * This structure holds main sort options which are NOT affecting the sort ordering.
+ */
+struct sort_opts
+{
+ wint_t field_sep;
+ int sort_method;
+ bool cflag;
+ bool csilentflag;
+ bool kflag;
+ bool mflag;
+ bool sflag;
+ bool uflag;
+ bool zflag;
+ bool tflag;
+ bool complex_sort;
+};
+
+/*
+ * Key value structure forward declaration
+ */
+struct key_value;
+
+/*
+ * Cmp function
+ */
+typedef int (*cmpcoll_t)(struct key_value *kv1, struct key_value *kv2, size_t offset);
+
+/*
+ * This structure holds "sort modifiers" - options which are affecting the sort ordering.
+ */
+struct sort_mods
+{
+ cmpcoll_t func;
+ bool bflag;
+ bool dflag;
+ bool fflag;
+ bool gflag;
+ bool iflag;
+ bool Mflag;
+ bool nflag;
+ bool rflag;
+ bool Rflag;
+ bool Vflag;
+ bool hflag;
+};
+
+extern bool need_hint;
+
+extern struct sort_opts sort_opts_vals;
+
+extern struct sort_mods * const default_sort_mods;
+
+extern int (*isblank_f)(int c);
+extern int (*iswblank_f)(wint_t c);
+
+#endif /* __BSD_SORT_H__ */
diff --git a/text_cmds/sort/testsuite/README.txt b/text_cmds/sort/testsuite/README.txt
new file mode 100644
index 0000000..865094f
--- /dev/null
+++ b/text_cmds/sort/testsuite/README.txt
@@ -0,0 +1,19 @@
+To run the tests:
+
+1) Adjust the variable TESTED_SORT in the file run.sh - the value must point
+to the binary that is to be tested.
+
+2) Adjust the value ORIG_SORT in the file run.sh - the value must point to the binary that is assumed
+to be working correctly. The tested sort binary will be checked against this program.
+
+3) Run:
+
+$ cd <...>/testsuite/
+$ ./run.sh
+
+4) Wait for many hours, it is running about 23 hours on my laptop.
+
+5) Check the output and check the existence of the file errors.log in the current directory.
+If the test run has been successful, then there must be no file errors.log.
+
+
diff --git a/text_cmds/sort/testsuite/bigsample.txt.xz b/text_cmds/sort/testsuite/bigsample.txt.xz
new file mode 100644
index 0000000..ca120b7
--- /dev/null
+++ b/text_cmds/sort/testsuite/bigsample.txt.xz
Binary files differ
diff --git a/text_cmds/sort/testsuite/run.sh b/text_cmds/sort/testsuite/run.sh
new file mode 100755
index 0000000..db13a34
--- /dev/null
+++ b/text_cmds/sort/testsuite/run.sh
@@ -0,0 +1,436 @@
+#!/bin/sh
+
+#export GNUSORT_NUMERIC_COMPATIBILITY=x
+#export GNUSORT_COMPATIBLE_BLANKS=x
+
+TESTED_SORT=../../text_cmds/sort/sort
+ORIG_SORT=../../text_cmds_orig/sort/sort
+
+FILECMP=cmp
+
+INPUT_FILE=sample.txt
+BIG_INPUT_FILE=bigsample.txt
+
+ERRORS_FILE=errors.log
+
+OUT_DIR=tmp
+
+# clean
+
+rm -rf ${OUT_DIR}
+mkdir -p ${OUT_DIR}
+rm -rf ${ERRORS_FILE}
+
+# ru_RU.KOI8-R C ru_RU.ISO-8859-5 en_US.ISO8859-15 zh_HK.Big5HKSCS
+#
+# ru KOI-8 is an "irregular" locale with non-trivial ordering.
+# zh* is a 2-bytes locale.
+
+for lang in en_US.UTF-8 C en_US.ISO8859-15 zh_HK.Big5HKSCS ru_RU.KOI8-R ru_RU.ISO-8859-5
+do
+
+ export LANG=${lang}
+
+ for KEYS in -srh -sfrudb -Vs -sM -siz
+ do
+
+ echo ${LANG} ${KEYS}
+
+ if [ ${LANG} = "ru_RU.KOI8-R" ] && [ ${KEYS} = "-srh" ] ; then
+
+ # numeric sorting in ru_RU.KOI8-R incompatible because the thousands separator bug fixed,
+ # for better compatibility with the new GNU sort.
+ # (ru_RU.KOI8-R uses space as thousands separator)
+
+ continue
+ fi
+
+ time ${ORIG_SORT} ${KEYS} ${BIG_INPUT_FILE} -o ${OUT_DIR}/big_orig
+
+ for PARALLEL in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
+ do
+
+ echo --parallel ${PARALLEL}
+
+ time ${TESTED_SORT} --parallel ${PARALLEL} ${KEYS} ${BIG_INPUT_FILE} -o ${OUT_DIR}/big_new
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} big crash --parallel ${PARALLEL} >> ${ERRORS_FILE}
+ exit
+ fi
+
+ if ! ${FILECMP} ${OUT_DIR}/big_new ${OUT_DIR}/big_orig >${OUT_DIR}/res.0.0.big 2>&1 ; then
+ echo ${LANG} ${KEYS} big error --parallel ${PARALLEL} >> ${ERRORS_FILE}
+ fi
+ time ${TESTED_SORT} --parallel ${PARALLEL} -c ${KEYS} ${OUT_DIR}/big_new
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -c big error --parallel ${PARALLEL} >> ${ERRORS_FILE}
+ fi
+ rm -rf ${OUT_DIR}/res.0.0.big
+ rm -rf ${OUT_DIR}/big_new
+ done
+
+ rm -rf ${OUT_DIR}/big_orig
+
+ ${TESTED_SORT} ${KEYS} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.0.0 2>&1 ; then
+ echo ${LANG} ${KEYS} error >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c ${KEYS} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -c error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.0.0
+
+ ${TESTED_SORT} ${KEYS} -t " " ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t " " crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t " " ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.0.0 2>&1 ; then
+ echo ${LANG} ${KEYS} error -t " " >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t " " ${KEYS} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo $? ${LANG} ${KEYS} -t " " -c error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.0.0
+
+ ${TESTED_SORT} ${KEYS} -t "|" ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t "|" crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t "|" ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.0.0 2>&1 ; then
+ echo ${LANG} ${KEYS} error -t "|" >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t "|" ${KEYS} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -c -t "|" error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.0.0
+
+ ${TESTED_SORT} ${KEYS} -t '\0' ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t 0 crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t '\0' ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.0.0 2>&1 ; then
+ echo ${LANG} ${KEYS} error -t '\0' >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t '\0' ${KEYS} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -c -t '\0' error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.0.0
+
+ for f1 in 1 2 3 4 5 6 7 8 9
+ do
+ for c1 in 1 2 3 4 5 10 15 20 25 30
+ do
+ echo ${LANG} ${KEYS} ${f1} ${c1}
+
+ ${TESTED_SORT} ${KEYS} +${f1}.${c1} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} +${f1}.${c1} crash +- >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} +${f1}.${c1} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1} 2>&1 ; then
+ echo ${LANG} ${KEYS} +${f1}.${c1} error +- >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c ${KEYS} +${f1}.${c1} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} +${f1}.${c1} -c error +- >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}
+
+ ${TESTED_SORT} ${KEYS} -k${f1}.${c1} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -k${f1}.${c1} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} error >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c ${KEYS} -k${f1}.${c1} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} -c error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}
+
+ ${TESTED_SORT} ${KEYS} -k${f1}.${c1}b ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}b crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -k${f1}.${c1}b ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}b error >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c ${KEYS} -k${f1}.${c1}b ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}b -c error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}
+
+ ${TESTED_SORT} ${KEYS} -t " " -k${f1}.${c1} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t -k${f1}.${c1} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t " " -k${f1}.${c1} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} error -t " " >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t " " ${KEYS} -k${f1}.${c1} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} -t " " -c error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}
+
+ if [ ${LANG} != "ru_RU.KOI8-R" ] ; then
+
+ # numeric sorting in ru_RU.KOI8-R incompatible because the thousands separator bug fixed,
+ # for better compatibility with the new GNU sort.
+ # (ru_RU.KOI8-R uses space as thousands separator)
+
+ ${TESTED_SORT} ${KEYS} -t " " -k${f1}.${c1}n ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}n crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t " " -k${f1}.${c1}n ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} error -t " " n >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t " " ${KEYS} -k${f1}.${c1}n ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} -c -t " " n error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}
+ fi
+
+ ${TESTED_SORT} ${KEYS} -t "|" -k${f1}.${c1} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t "|" -k${f1}.${c1} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t "|" -k${f1}.${c1} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} error -t "|" >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t "|" ${KEYS} -k${f1}.${c1} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1} -c -t "|" error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}
+
+ for f2 in 1 2 3 4 5 6 7 8 9 10
+ do
+ for c2 in 0 1 2 3 4 5 10 15 20 25 30
+ do
+ echo ${LANG} ${KEYS} ${f1} ${c1} ${f2} ${c2}
+
+ ${TESTED_SORT} ${KEYS} +${f1}.${c1} -${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} +${f1}.${c1} -${f2}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} +${f1}.${c1} -${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} +${f1}.${c1} -${f2}.${c2} error +- >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c ${KEYS} +${f1}.${c1} -${f2}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} +${f1}.${c1} -${f2}.${c2} -c error +- >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+
+ ${TESTED_SORT} ${KEYS} -k${f1}.${c1},${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1},${f2}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -k${f1}.${c1},${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}.${f2}.${c2} error >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c ${KEYS} -k${f1}.${c1},${f2}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1},${f2}.${c2} -c error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+
+ ${TESTED_SORT} ${KEYS} -k${f1}.${c1}b,${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}b,${f2}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -k${f1}.${c1}b,${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}.b.${f2}.${c2} error >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c ${KEYS} -k${f1}.${c1}b,${f2}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}b,${f2}.${c2} -c error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+
+ ${TESTED_SORT} ${KEYS} -t " " -k${f1}.${c1},${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t " " -k${f1}.${c1},${f2}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t " " -k${f1}.${c1},${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}.${f2}.${c2} error -t " " >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t " " ${KEYS} -k${f1}.${c1},${f2}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1},${f2}.${c2} -c -t " " error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+
+ if [ ${LANG} != "ru_RU.KOI8-R" ] ; then
+
+ # numeric sorting in ru_RU.KOI8-R incompatible because the thousands separator bug fixed,
+ # for better compatibility with the new GNU sort.
+ # (ru_RU.KOI8-R uses space as thousands separator)
+
+ ${TESTED_SORT} ${KEYS} -t " " -k${f1}.${c1}n,${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t " " -k${f1}.${c1}n,${f2}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t " " -k${f1}.${c1}n,${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} -t " " -k${f1}.${c1}.${f2}.${c2} error n >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t " " ${KEYS} -k${f1}.${c1}n,${f2}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1},${f2}.${c2} -c -t " " n error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+
+ ${TESTED_SORT} ${KEYS} -t '\0' -k${f1}.${c1}n,${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t '\0' -k${f1}.${c1}n,${f2}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t '\0' -k${f1}.${c1}n,${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}.${f2}.${c2} error -t '\0' n >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t '\0' ${KEYS} -k${f1}.${c1}n,${f2}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1},${f2}.${c2} -c -t '\0' n error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+ fi
+
+ ${TESTED_SORT} ${KEYS} -t "|" -k${f1}.${c1},${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t "|" -k${f1}.${c1},${f2}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t "|" -k${f1}.${c1},${f2}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}.${f2}.${c2} error -t "|" >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t "|" ${KEYS} -k${f1}.${c1},${f2}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1},${f2}.${c2} -c -t "|" error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+
+ ${TESTED_SORT} ${KEYS} -t "|" -k${f1}.${c1},${f2}.${c2} -k${f2}.${c1},${f1}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -t "|" -k${f1}.${c1},${f2}.${c2} -k${f2}.${c1},${f1}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -t "|" -k${f1}.${c1},${f2}.${c2} -k${f2}.${c1},${f1}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}.${f2}.${c2} error -t "|" 2k >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c -t "|" ${KEYS} -k${f1}.${c1},${f2}.${c2} -k${f2}.${c1},${f1}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1},${f2}.${c2} -c -t "|" 2k error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+
+ ${TESTED_SORT} ${KEYS} -k${f1}.${c1}b,${f2}.${c2} -k${f2}.${c1},${f1}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}b,${f2}.${c2} -k${f2}.${c1},${f1}.${c2} crash >> ${ERRORS_FILE}
+ exit
+ fi
+ ${ORIG_SORT} ${KEYS} -k${f1}.${c1}b,${f2}.${c2} -k${f2}.${c1},${f1}.${c2} ${INPUT_FILE} -o ${OUT_DIR}/sik2
+ if ! ${FILECMP} ${OUT_DIR}/sik1 ${OUT_DIR}/sik2 >${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2} 2>&1 ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}.b.${f2}.${c2} error 2k >> ${ERRORS_FILE}
+ fi
+ ${TESTED_SORT} -c ${KEYS} -k${f1}.${c1}b,${f2}.${c2} -k${f2}.${c1},${f1}.${c2} ${OUT_DIR}/sik1
+ ER=$?
+ if ! [ ${ER} -eq 0 ] ; then
+ echo ${LANG} ${KEYS} -k${f1}.${c1}b,${f2}.${c2} -c 2k error >> ${ERRORS_FILE}
+ fi
+ rm ${OUT_DIR}/res.${f1}.${c1}.${f2}.${c2}
+
+ done
+ done
+ done
+ done
+ done
+done
+
+if [ -f ${ERRORS_FILE} ] ; then
+ echo TEST FAILED
+else
+ echo TEST SUCCEEDED
+fi
diff --git a/text_cmds/sort/testsuite/sample.txt b/text_cmds/sort/testsuite/sample.txt
new file mode 100644
index 0000000..74d1477
--- /dev/null
+++ b/text_cmds/sort/testsuite/sample.txt
Binary files differ
diff --git a/text_cmds/sort/vsort.c b/text_cmds/sort/vsort.c
new file mode 100644
index 0000000..abc8647
--- /dev/null
+++ b/text_cmds/sort/vsort.c
@@ -0,0 +1,265 @@
+/*-
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
+ * Copyright (C) 2012 Gabor Kovesdan <gabor@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/usr.bin/sort/vsort.c 281132 2015-04-06 02:35:55Z pfg $");
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sort.h"
+#include "vsort.h"
+
+static inline bool
+isdigit_clocale(wchar_t c)
+{
+
+ return (c >= L'0' && c <= L'9');
+}
+
+static inline bool
+isalpha_clocale(wchar_t c)
+{
+
+ return ((c >= L'a' && c <= L'z') || (c >= L'A' && c <= L'Z'));
+}
+
+static inline bool
+isalnum_clocale(wchar_t c)
+{
+
+ return ((c >= L'a' && c <= L'z') || (c >= L'A' && c <= L'Z') ||
+ (c >= L'0' && c <= L'9'));
+}
+
+/*
+ * Find string suffix of format: (\.[A-Za-z~][A-Za-z0-9~]*)*$
+ * Set length of string before suffix.
+ */
+static void
+find_suffix(bwstring_iterator si, bwstring_iterator se, size_t *len)
+{
+ wchar_t c;
+ size_t clen;
+ bool expect_alpha, sfx;
+
+ sfx = false;
+ expect_alpha = false;
+ *len = 0;
+ clen = 0;
+
+ while ((si < se) && (c = bws_get_iter_value(si))) {
+ if (expect_alpha) {
+ expect_alpha = false;
+ if (!isalpha_clocale(c) && (c != L'~'))
+ sfx = false;
+ } else if (c == L'.') {
+ expect_alpha = true;
+ if (!sfx) {
+ sfx = true;
+ *len = clen;
+ }
+ } else if (!isalnum_clocale(c) && (c != L'~'))
+ sfx = false;
+
+ si = bws_iterator_inc(si, 1);
+ ++clen;
+ }
+
+ /* This code must be here to make the implementation compatible
+ * with WORDING of GNU sort documentation.
+ * But the GNU sort implementation is not following its own
+ * documentation. GNU sort allows empty file extensions
+ * (just dot with nothing after); but the regular expression in
+ * their documentation does not allow empty file extensions.
+ * We chose to make our implementation compatible with GNU sort
+ * implementation. If they will ever fix their bug, this code
+ * must be uncommented. Or they may choose to fix the info page,
+ * then the code stays commented.
+ *
+ if (expect_alpha)
+ sfx = false;
+ */
+
+ if (!sfx)
+ *len = clen;
+}
+
+static inline int
+cmp_chars(wchar_t c1, wchar_t c2)
+{
+
+ if (c1 == c2)
+ return (0);
+
+ if (c1 == L'~')
+ return (-1);
+ if (c2 == L'~')
+ return (+1);
+
+ if (isdigit_clocale(c1) || !c1)
+ return ((isdigit_clocale(c2) || !c2) ? 0 : -1);
+
+ if (isdigit_clocale(c2) || !c2)
+ return (+1);
+
+ if (isalpha_clocale(c1))
+ return ((isalpha_clocale(c2)) ? ((int) c1 - (int) c2) : -1);
+
+ if (isalpha_clocale(c2))
+ return (+1);
+
+ return ((int) c1 - (int) c2);
+}
+
+static int
+cmpversions(bwstring_iterator si1, bwstring_iterator se1,
+ bwstring_iterator si2, bwstring_iterator se2)
+{
+ int cmp, diff;
+
+ while ((si1 < se1) || (si2 < se2)) {
+ diff = 0;
+
+ while (((si1 < se1) &&
+ !isdigit_clocale(bws_get_iter_value(si1))) ||
+ ((si2 < se2) && !isdigit_clocale(bws_get_iter_value(si2)))) {
+ wchar_t c1, c2;
+
+ c1 = (si1 < se1) ? bws_get_iter_value(si1) : 0;
+ c2 = (si2 < se2) ? bws_get_iter_value(si2) : 0;
+
+ cmp = cmp_chars(c1, c2);
+ if (cmp)
+ return (cmp);
+
+ if (si1 < se1)
+ si1 = bws_iterator_inc(si1, 1);
+ if (si2 < se2)
+ si2 = bws_iterator_inc(si2, 1);
+ }
+
+ while (bws_get_iter_value(si1) == L'0')
+ si1 = bws_iterator_inc(si1, 1);
+
+ while (bws_get_iter_value(si2) == L'0')
+ si2 = bws_iterator_inc(si2, 1);
+
+ while (isdigit_clocale(bws_get_iter_value(si1)) &&
+ isdigit_clocale(bws_get_iter_value(si2))) {
+ if (!diff)
+ diff = ((int)bws_get_iter_value(si1) -
+ (int)bws_get_iter_value(si2));
+ si1 = bws_iterator_inc(si1, 1);
+ si2 = bws_iterator_inc(si2, 1);
+ }
+
+ if (isdigit_clocale(bws_get_iter_value(si1)))
+ return (1);
+
+ if (isdigit_clocale(bws_get_iter_value(si2)))
+ return (-1);
+
+ if (diff)
+ return (diff);
+ }
+
+ return (0);
+}
+
+/*
+ * Compare two version strings
+ */
+int
+vcmp(struct bwstring *s1, struct bwstring *s2)
+{
+ bwstring_iterator si1, si2;
+ wchar_t c1, c2;
+ size_t len1, len2, slen1, slen2;
+ int cmp_bytes, cmp_res;
+
+ if (s1 == s2)
+ return (0);
+
+ cmp_bytes = bwscmp(s1, s2, 0);
+ if (cmp_bytes == 0)
+ return (0);
+
+ len1 = slen1 = BWSLEN(s1);
+ len2 = slen2 = BWSLEN(s2);
+
+ if (slen1 < 1)
+ return (-1);
+ if (slen2 < 1)
+ return (+1);
+
+ si1 = bws_begin(s1);
+ si2 = bws_begin(s2);
+
+ c1 = bws_get_iter_value(si1);
+ c2 = bws_get_iter_value(si2);
+
+ if (c1 == L'.' && (slen1 == 1))
+ return (-1);
+
+ if (c2 == L'.' && (slen2 == 1))
+ return (+1);
+
+ if (slen1 == 2 && c1 == L'.' &&
+ bws_get_iter_value(bws_iterator_inc(si1, 1)) == L'.')
+ return (-1);
+ if (slen2 == 2 && c2 == L'.' &&
+ bws_get_iter_value(bws_iterator_inc(si2, 1)) == L'.')
+ return (+1);
+
+ if (c1 == L'.' && c2 != L'.')
+ return (-1);
+ if (c1 != L'.' && c2 == L'.')
+ return (+1);
+
+ if (c1 == L'.' && c2 == L'.') {
+ si1 = bws_iterator_inc(si1, 1);
+ si2 = bws_iterator_inc(si2, 1);
+ }
+
+ find_suffix(si1, bws_end(s1), &len1);
+ find_suffix(si2, bws_end(s2), &len2);
+
+ if ((len1 == len2) && (bws_iterator_cmp(si1, si2, len1) == 0))
+ return (cmp_bytes);
+
+ cmp_res = cmpversions(si1, bws_iterator_inc(si1, len1), si2,
+ bws_iterator_inc(si2, len2));
+
+ if (cmp_res == 0)
+ cmp_res = cmp_bytes;
+
+ return (cmp_res);
+}
diff --git a/text_cmds/sort/vsort.h b/text_cmds/sort/vsort.h
new file mode 100644
index 0000000..5ef45d5
--- /dev/null
+++ b/text_cmds/sort/vsort.h
@@ -0,0 +1,37 @@
+/* $FreeBSD: head/usr.bin/sort/vsort.h 264744 2014-04-21 22:52:18Z pfg $ */
+
+/*-
+ * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
+ * Copyright (C) 2012 Gabor Kovesdan <gabor@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.
+ */
+
+#ifndef _VSORT_H_
+#define _VSORT_H_
+
+#include "bwstring.h"
+
+int vcmp(struct bwstring *s1, struct bwstring *s2);
+
+#endif
diff --git a/text_cmds/split/split.1 b/text_cmds/split/split.1
new file mode 100644
index 0000000..39818e0
--- /dev/null
+++ b/text_cmds/split/split.1
@@ -0,0 +1,142 @@
+.\" Copyright (c) 1990, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)split.1 8.3 (Berkeley) 4/16/94
+.\" $FreeBSD: src/usr.bin/split/split.1,v 1.17 2005/08/30 12:48:28 tjr Exp $
+.\"
+.Dd August 21, 2005
+.Dt SPLIT 1
+.Os
+.Sh NAME
+.Nm split
+.Nd split a file into pieces
+.Sh SYNOPSIS
+.Nm
+.Op Fl a Ar suffix_length
+.Op Fl b Ar byte_count[k|m]
+.Op Fl l Ar line_count
+.Op Fl p Ar pattern
+.Op Ar file Op Ar name
+.Sh DESCRIPTION
+The
+.Nm
+utility reads the given
+.Ar file
+and breaks it up into files of 1000 lines each.
+If
+.Ar file
+is a single dash
+.Pq Sq Fl
+or absent,
+.Nm
+reads from the standard input.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a Ar suffix_length
+Use
+.Ar suffix_length
+letters to form the suffix of the file name.
+.It Fl b Ar byte_count[k|m]
+Create smaller files
+.Ar byte_count
+bytes in length.
+If
+.Dq Li k
+is appended to the number, the file is split into
+.Ar byte_count
+kilobyte pieces.
+If
+.Dq Li m
+is appended to the number, the file is split into
+.Ar byte_count
+megabyte pieces.
+.It Fl l Ar line_count
+Create smaller files
+.Ar n
+lines in length.
+.It Fl p Ar pattern
+The file is split whenever an input line matches
+.Ar pattern ,
+which is interpreted as an extended regular expression.
+The matching line will be the first line of the next output file.
+This option is incompatible with the
+.Fl b
+and
+.Fl l
+options.
+.El
+.Pp
+If additional arguments are specified, the first is used as the name
+of the input file which is to be split.
+If a second additional argument is specified, it is used as a prefix
+for the names of the files into which the file is split.
+In this case, each file into which the file is split is named by the
+prefix followed by a lexically ordered suffix using
+.Ar suffix_length
+characters in the range
+.Dq Li a-z .
+If
+.Fl a
+is not specified, two letters are used as the suffix.
+.Pp
+If the
+.Ar name
+argument is not specified, the file is split into lexically ordered
+files named with the prefix
+.Dq Li x
+and with suffixes as above.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_CTYPE
+and
+.Ev LC_COLLATE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr csplit 1 ,
+.Xr re_format 7
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v3 .
+.Sh BUGS
+The maximum line length for matching patterns is 65536.
diff --git a/text_cmds/split/split.c b/text_cmds/split/split.c
new file mode 100644
index 0000000..3c47a18
--- /dev/null
+++ b/text_cmds/split/split.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 1987, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/split/split.c,v 1.17 2005/08/30 12:32:18 tjr Exp $");
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)split.c 8.2 (Berkeley) 4/16/94";
+#endif
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <regex.h>
+#include <sysexits.h>
+
+#define DEFLINE 1000 /* Default num lines per file. */
+
+off_t bytecnt; /* Byte count to split on. */
+long numlines; /* Line count to split on. */
+int file_open; /* If a file open. */
+int ifd = -1, ofd = -1; /* Input/output file descriptors. */
+char bfr[MAXBSIZE]; /* I/O buffer. */
+char fname[MAXPATHLEN]; /* File name prefix. */
+regex_t rgx;
+int pflag;
+long sufflen = 2; /* File name suffix length. */
+
+void newfile(void);
+void split1(void);
+void split2(void);
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ intmax_t bytecnti;
+ long scale;
+ int ch;
+ char *ep, *p;
+
+ setlocale(LC_ALL, "");
+
+ while ((ch = getopt(argc, argv, "0123456789a:b:l:p:")) != -1)
+ switch (ch) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ /*
+ * Undocumented kludge: split was originally designed
+ * to take a number after a dash.
+ */
+ if (numlines == 0) {
+ p = argv[optind - 1];
+ if (p[0] == '-' && p[1] == ch && !p[2])
+ numlines = strtol(++p, &ep, 10);
+ else
+ numlines =
+ strtol(argv[optind] + 1, &ep, 10);
+ if (numlines <= 0 || *ep)
+ errx(EX_USAGE,
+ "%s: illegal line count", optarg);
+ }
+ break;
+ case 'a': /* Suffix length */
+ if ((sufflen = strtol(optarg, &ep, 10)) <= 0 || *ep)
+ errx(EX_USAGE,
+ "%s: illegal suffix length", optarg);
+ break;
+ case 'b': /* Byte count. */
+ errno = 0;
+ if ((bytecnti = strtoimax(optarg, &ep, 10)) <= 0 ||
+ (*ep != '\0' && *ep != 'k' && *ep != 'm') ||
+ errno != 0)
+ errx(EX_USAGE,
+ "%s: illegal byte count", optarg);
+ if (*ep == 'k')
+ scale = 1024;
+ else if (*ep == 'm')
+ scale = 1024 * 1024;
+ else
+ scale = 1;
+ if (bytecnti > OFF_MAX / scale)
+ errx(EX_USAGE, "%s: offset too large", optarg);
+ bytecnt = (off_t)(bytecnti * scale);
+ break;
+ case 'p' : /* pattern matching. */
+ if (regcomp(&rgx, optarg, REG_EXTENDED|REG_NOSUB) != 0)
+ errx(EX_USAGE, "%s: illegal regexp", optarg);
+ pflag = 1;
+ break;
+ case 'l': /* Line count. */
+ if (numlines != 0)
+ usage();
+ if ((numlines = strtol(optarg, &ep, 10)) <= 0 || *ep)
+ errx(EX_USAGE,
+ "%s: illegal line count", optarg);
+ break;
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ if (*argv != NULL) { /* Input file. */
+ if (strcmp(*argv, "-") == 0)
+ ifd = STDIN_FILENO;
+ else if ((ifd = open(*argv, O_RDONLY, 0)) < 0)
+ err(EX_NOINPUT, "%s", *argv);
+ ++argv;
+ }
+ if (*argv != NULL) /* File name prefix. */
+ if (strlcpy(fname, *argv++, sizeof(fname)) >= sizeof(fname))
+ errx(EX_USAGE, "file name prefix is too long");
+ if (*argv != NULL)
+ usage();
+
+ if (strlen(fname) + (unsigned long)sufflen >= sizeof(fname))
+ errx(EX_USAGE, "suffix is too long");
+ if (pflag && (numlines != 0 || bytecnt != 0))
+ usage();
+
+ if (numlines == 0)
+ numlines = DEFLINE;
+ else if (bytecnt != 0)
+ usage();
+
+ if (ifd == -1) /* Stdin by default. */
+ ifd = 0;
+
+ if (bytecnt) {
+ split1();
+ exit (0);
+ }
+ split2();
+ if (pflag)
+ regfree(&rgx);
+ exit(0);
+}
+
+/*
+ * split1 --
+ * Split the input by bytes.
+ */
+void
+split1(void)
+{
+ off_t bcnt;
+ char *C;
+ ssize_t dist, len;
+
+ for (bcnt = 0;;)
+ switch ((len = read(ifd, bfr, MAXBSIZE))) {
+ case 0:
+ exit(0);
+ case -1:
+ err(EX_IOERR, "read");
+ /* NOTREACHED */
+ default:
+ if (!file_open)
+ newfile();
+ if (bcnt + len >= bytecnt) {
+ dist = bytecnt - bcnt;
+ if (write(ofd, bfr, dist) != dist)
+ err(EX_IOERR, "write");
+ len -= dist;
+ for (C = bfr + dist; len >= bytecnt;
+ len -= bytecnt, C += bytecnt) {
+ newfile();
+ if (write(ofd,
+ C, bytecnt) != bytecnt)
+ err(EX_IOERR, "write");
+ }
+ if (len != 0) {
+ newfile();
+ if (write(ofd, C, len) != len)
+ err(EX_IOERR, "write");
+ } else
+ file_open = 0;
+ bcnt = len;
+ } else {
+ bcnt += len;
+ if (write(ofd, bfr, len) != len)
+ err(EX_IOERR, "write");
+ }
+ }
+}
+
+/*
+ * split2 --
+ * Split the input by lines.
+ */
+void
+split2(void)
+{
+ long lcnt = 0;
+ FILE *infp;
+
+ /* Stick a stream on top of input file descriptor */
+ if ((infp = fdopen(ifd, "r")) == NULL)
+ err(EX_NOINPUT, "fdopen");
+
+ /* Process input one line at a time */
+ while (fgets(bfr, sizeof(bfr), infp) != NULL) {
+ const int len = strlen(bfr);
+
+ /* If line is too long to deal with, just write it out */
+ if (bfr[len - 1] != '\n')
+ goto writeit;
+
+ /* Check if we need to start a new file */
+ if (pflag) {
+ regmatch_t pmatch;
+
+ pmatch.rm_so = 0;
+ pmatch.rm_eo = len - 1;
+ if (regexec(&rgx, bfr, 0, &pmatch, REG_STARTEND) == 0)
+ newfile();
+ } else if (lcnt++ == numlines) {
+ newfile();
+ lcnt = 1;
+ }
+
+writeit:
+ /* Open output file if needed */
+ if (!file_open)
+ newfile();
+
+ /* Write out line */
+ if (write(ofd, bfr, len) != len)
+ err(EX_IOERR, "write");
+ }
+
+ /* EOF or error? */
+ if (ferror(infp))
+ err(EX_IOERR, "read");
+ else
+ exit(0);
+}
+
+/*
+ * newfile --
+ * Open a new output file.
+ */
+void
+newfile(void)
+{
+ long i, maxfiles, tfnum;
+ static long fnum;
+ static int defname;
+ static char *fpnt;
+
+ if (ofd == -1) {
+ if (fname[0] == '\0') {
+ fname[0] = 'x';
+ fpnt = fname + 1;
+ defname = 1;
+ } else {
+ fpnt = fname + strlen(fname);
+ defname = 0;
+ }
+ ofd = fileno(stdout);
+ }
+
+ /* maxfiles = 26^sufflen, but don't use libm. */
+ for (maxfiles = 1, i = 0; i < sufflen; i++)
+ if ((maxfiles *= 26) <= 0)
+ errx(EX_USAGE, "suffix is too long (max %ld)", i);
+
+ if (fnum == maxfiles)
+ errx(EX_DATAERR, "too many files");
+
+ /* Generate suffix of sufflen letters */
+ tfnum = fnum;
+ i = sufflen - 1;
+ do {
+ fpnt[i] = tfnum % 26 + 'a';
+ tfnum /= 26;
+ } while (i-- > 0);
+ fpnt[sufflen] = '\0';
+
+ ++fnum;
+ if (!freopen(fname, "w", stdout))
+ err(EX_IOERR, "%s", fname);
+ file_open = 1;
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+"usage: split [-a sufflen] [-b byte_count] [-l line_count] [-p pattern]\n");
+ (void)fprintf(stderr,
+" [file [prefix]]\n");
+ exit(EX_USAGE);
+}
diff --git a/text_cmds/tail/extern.h b/text_cmds/tail/extern.h
new file mode 100644
index 0000000..d956680
--- /dev/null
+++ b/text_cmds/tail/extern.h
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ *
+ * $FreeBSD$
+ */
+
+#define WR(p, size) do { \
+ if (write(STDOUT_FILENO, p, size) != (ssize_t)size) \
+ oerr(); \
+ } while(0)
+
+#define TAILMAPLEN (4<<20)
+
+struct mapinfo {
+ off_t mapoff;
+ off_t maxoff;
+ size_t maplen;
+ char *start;
+ int fd;
+};
+
+struct file_info {
+ FILE *fp;
+ char *file_name;
+ struct stat st;
+};
+
+typedef struct file_info file_info_t;
+
+enum STYLE { NOTSET = 0, FBYTES, FLINES, RBYTES, RLINES, REVERSE };
+
+void follow(file_info_t *, enum STYLE, off_t);
+void forward(FILE *, enum STYLE, off_t, struct stat *);
+void reverse(FILE *, enum STYLE, off_t, struct stat *);
+
+int bytes(FILE *, off_t);
+int lines(FILE *, off_t);
+
+void ierr(void);
+void oerr(void);
+int mapprint(struct mapinfo *, off_t, off_t);
+int maparound(struct mapinfo *, off_t);
+
+extern int Fflag, fflag, qflag, rflag, rval, no_files;
+extern const char *fname;
diff --git a/text_cmds/tail/forward.c b/text_cmds/tail/forward.c
new file mode 100644
index 0000000..172898a
--- /dev/null
+++ b/text_cmds/tail/forward.c
@@ -0,0 +1,520 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Edward Sze-Tyan Wang.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)forward.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/event.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+static void rlines(FILE *, off_t, struct stat *);
+static void show(file_info_t *);
+static void set_events(file_info_t *files);
+
+/* defines for inner loop actions */
+#define USE_SLEEP 0
+#define USE_KQUEUE 1
+#define ADD_EVENTS 2
+
+struct kevent *ev;
+int action = USE_SLEEP;
+int kq;
+
+static const file_info_t *last;
+
+/*
+ * forward -- display the file, from an offset, forward.
+ *
+ * There are eight separate cases for this -- regular and non-regular
+ * files, by bytes or lines and from the beginning or end of the file.
+ *
+ * FBYTES byte offset from the beginning of the file
+ * REG seek
+ * NOREG read, counting bytes
+ *
+ * FLINES line offset from the beginning of the file
+ * REG read, counting lines
+ * NOREG read, counting lines
+ *
+ * RBYTES byte offset from the end of the file
+ * REG seek
+ * NOREG cyclically read characters into a wrap-around buffer
+ *
+ * RLINES
+ * REG mmap the file and step back until reach the correct offset.
+ * NOREG cyclically read lines into a wrap-around array of buffers
+ */
+void
+forward(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
+{
+ int ch;
+
+ switch(style) {
+ case FBYTES:
+ if (off == 0)
+ break;
+ if (S_ISREG(sbp->st_mode)) {
+ if (sbp->st_size < off)
+ off = sbp->st_size;
+ if (fseeko(fp, off, SEEK_SET) == -1) {
+ ierr();
+ return;
+ }
+ } else while (off--)
+ if ((ch = getc(fp)) == EOF) {
+ if (ferror(fp)) {
+ ierr();
+ return;
+ }
+ break;
+ }
+ break;
+ case FLINES:
+ if (off == 0)
+ break;
+ for (;;) {
+ if ((ch = getc(fp)) == EOF) {
+ if (ferror(fp)) {
+ ierr();
+ return;
+ }
+ break;
+ }
+ if (ch == '\n' && !--off)
+ break;
+ }
+ break;
+ case RBYTES:
+ if (S_ISREG(sbp->st_mode)) {
+ if (sbp->st_size >= off &&
+ fseeko(fp, -off, SEEK_END) == -1) {
+ ierr();
+ return;
+ }
+ } else if (off == 0) {
+ while (getc(fp) != EOF);
+ if (ferror(fp)) {
+ ierr();
+ return;
+ }
+ } else
+ if (bytes(fp, off))
+ return;
+ break;
+ case RLINES:
+ if (S_ISREG(sbp->st_mode))
+ if (!off) {
+ if (fseeko(fp, (off_t)0, SEEK_END) == -1) {
+ ierr();
+ return;
+ }
+ } else
+ rlines(fp, off, sbp);
+ else if (off == 0) {
+ while (getc(fp) != EOF);
+ if (ferror(fp)) {
+ ierr();
+ return;
+ }
+ } else
+ if (lines(fp, off))
+ return;
+ break;
+ default:
+ break;
+ }
+
+ while ((ch = getc(fp)) != EOF)
+ if (putchar(ch) == EOF)
+ oerr();
+ if (ferror(fp)) {
+ ierr();
+ return;
+ }
+ (void)fflush(stdout);
+}
+
+/*
+ * rlines -- display the last offset lines of the file.
+ */
+static void
+rlines(fp, off, sbp)
+ FILE *fp;
+ off_t off;
+ struct stat *sbp;
+{
+#ifdef __APPLE__
+ /* Using mmap on network filesystems can frequently lead
+ to distress, and even on local file systems other processes
+ truncating the file can also lead to upset. */
+
+ /* Seek to sbp->st_blksize before the end of the file, find
+ all the newlines. If there are enough, print the last off
+ lines. Otherwise go back another sbp->st_blksize bytes,
+ and count newlines. Avoid re-reading blocks when possible. */
+
+ // +1 because we capture line ends and we want off line _starts_,
+ // +1 because the first line might be partial when try_at != 0
+ off_t search_for = off +2;
+ off_t try_at = sbp->st_size;
+ off_t last_try = sbp->st_size;
+ off_t found_this_pass = 0;
+ off_t found_total = 0;
+ off_t *found_at = calloc(search_for, sizeof(off_t));
+
+ flockfile(fp);
+
+ if (found_at == NULL) {
+ ierr();
+ goto done;
+ }
+
+ if (off == 0 || sbp->st_size == 0) {
+ goto done;
+ }
+
+ /* The last character is special. Check to make sure that it is a \n,
+ * and if not, subtract one from the number of \n we need to search for.
+ */
+ if (0 != fseeko(fp, sbp->st_size - 1, SEEK_SET)) {
+ ierr();
+ goto done;
+ }
+ if ('\n' != getc_unlocked(fp)) {
+ search_for--;
+ }
+
+ while(try_at != 0) {
+ found_this_pass = 0;
+
+ if (try_at < sbp->st_blksize) {
+ found_at[found_this_pass++] = 0;
+ try_at = 0;
+ } else {
+ last_try = try_at;
+ try_at -= sbp->st_blksize;
+ }
+
+ if (0 != fseeko(fp, try_at, SEEK_SET)) {
+ ierr();
+ goto done;
+ }
+
+ char ch;
+ while(EOF != (ch = getc_unlocked(fp))) {
+ if (ch == '\n') {
+ found_at[found_this_pass++ % search_for] = ftello(fp);
+ found_total++;
+ }
+ if (ftello(fp) == last_try && found_total < search_for) {
+ // We just reached the last block we scanned,
+ // and we know there arn't enough lines found
+ // so far to be happy, so we don't have to
+ // read it again.
+ break;
+ }
+ }
+
+ if (found_this_pass >= search_for || try_at == 0) {
+ off_t min = found_at[0];
+ int min_i = 0;
+ int i;
+ int lim = (found_this_pass < search_for) ? found_this_pass : search_for;
+ for(i = 1; i < lim; i++) {
+ if (found_at[i] < min) {
+ min = found_at[i];
+ min_i = i;
+ }
+ }
+
+ off_t target = min;
+
+ if (found_this_pass >= search_for) {
+ // min_i might be a partial line (unless
+ // try_at is 0). If we found search_for
+ // lines, min_i+1 is the first known full line
+ // _and_ because we look for an extra line we
+ // don't need to show it.
+ target = found_at[(min_i + 1) % search_for];
+ }
+
+ if (0 != fseeko(fp, target, SEEK_SET)) {
+ ierr();
+ goto done;
+ }
+
+ flockfile(stdout);
+ while(EOF != (ch = getc_unlocked(fp))) {
+ if (EOF == putchar_unlocked(ch)) {
+ funlockfile(stdout);
+ oerr();
+ goto done;
+ }
+ }
+ funlockfile(stdout);
+ goto done;
+ }
+ }
+
+done:
+ funlockfile(fp);
+ free(found_at);
+ return;
+#else
+ struct mapinfo map;
+ off_t curoff, size;
+ int i;
+
+ if (!(size = sbp->st_size))
+ return;
+ map.start = NULL;
+ map.fd = fileno(fp);
+ map.mapoff = map.maxoff = size;
+
+ /*
+ * Last char is special, ignore whether newline or not. Note that
+ * size == 0 is dealt with above, and size == 1 sets curoff to -1.
+ */
+ curoff = size - 2;
+ while (curoff >= 0) {
+ if (curoff < map.mapoff && maparound(&map, curoff) != 0) {
+ ierr();
+ return;
+ }
+ for (i = curoff - map.mapoff; i >= 0; i--)
+ if (map.start[i] == '\n' && --off == 0)
+ break;
+ /* `i' is either the map offset of a '\n', or -1. */
+ curoff = map.mapoff + i;
+ if (i >= 0)
+ break;
+ }
+ curoff++;
+ if (mapprint(&map, curoff, size - curoff) != 0) {
+ ierr();
+ exit(1);
+ }
+
+ /* Set the file pointer to reflect the length displayed. */
+ if (fseeko(fp, sbp->st_size, SEEK_SET) == -1) {
+ ierr();
+ return;
+ }
+ if (map.start != NULL && munmap(map.start, map.maplen)) {
+ ierr();
+ return;
+ }
+#endif
+}
+
+static void
+show(file_info_t *file)
+{
+ int ch;
+
+ while ((ch = getc(file->fp)) != EOF) {
+ if (last != file && no_files > 1) {
+ if (!qflag)
+ (void)printf("\n==> %s <==\n", file->file_name);
+ last = file;
+ }
+ if (putchar(ch) == EOF)
+ oerr();
+ }
+ (void)fflush(stdout);
+ if (ferror(file->fp)) {
+ file->fp = NULL;
+ fname = file->file_name;
+ ierr();
+ fname = NULL;
+ } else
+ clearerr(file->fp);
+}
+
+static void
+set_events(file_info_t *files)
+{
+ int i, n = 0;
+ file_info_t *file;
+ struct timespec ts;
+ struct statfs sf;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ action = USE_KQUEUE;
+ for (i = 0, file = files; i < no_files; i++, file++) {
+ if (! file->fp)
+ continue;
+
+ if (fstatfs(fileno(file->fp), &sf) == 0 &&
+ (sf.f_flags & MNT_LOCAL) == 0) {
+ action = USE_SLEEP;
+ return;
+ }
+
+ if (Fflag && fileno(file->fp) != STDIN_FILENO) {
+ EV_SET(&ev[n], fileno(file->fp), EVFILT_VNODE,
+ EV_ADD | EV_ENABLE | EV_CLEAR,
+ NOTE_DELETE | NOTE_RENAME, 0, 0);
+ n++;
+ }
+ EV_SET(&ev[n], fileno(file->fp), EVFILT_READ,
+ EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0);
+ n++;
+ }
+
+ if (kevent(kq, ev, n, NULL, 0, &ts) < 0) {
+ action = USE_SLEEP;
+ }
+}
+
+/*
+ * follow -- display the file, from an offset, forward.
+ *
+ */
+void
+follow(file_info_t *files, enum STYLE style, off_t off)
+{
+ int active, i, n = -1;
+ struct stat sb2;
+ file_info_t *file;
+ struct timespec ts;
+
+ /* Position each of the files */
+
+ file = files;
+ active = 0;
+ n = 0;
+ for (i = 0; i < no_files; i++, file++) {
+ if (file->fp) {
+ active = 1;
+ n++;
+ if (no_files > 1 && !qflag)
+ (void)printf("\n==> %s <==\n", file->file_name);
+ fname = file->file_name;
+ forward(file->fp, style, off, &file->st);
+ fname = NULL;
+ if (Fflag && fileno(file->fp) != STDIN_FILENO)
+ n++;
+ }
+ }
+ if (! active)
+ return;
+
+ last = --file;
+
+ kq = kqueue();
+ if (kq < 0)
+ err(1, "kqueue");
+ ev = malloc(n * sizeof(struct kevent));
+ if (! ev)
+ err(1, "Couldn't allocate memory for kevents.");
+ set_events(files);
+
+ for (;;) {
+ for (i = 0, file = files; i < no_files; i++, file++) {
+ if (! file->fp)
+ continue;
+ if (Fflag && file->fp && fileno(file->fp) != STDIN_FILENO) {
+ if (stat(file->file_name, &sb2) == 0 &&
+ (sb2.st_ino != file->st.st_ino ||
+ sb2.st_dev != file->st.st_dev ||
+ sb2.st_nlink == 0)) {
+ show(file);
+ file->fp = freopen(file->file_name, "r", file->fp);
+ if (file->fp == NULL) {
+ ierr();
+ continue;
+ } else {
+ memcpy(&file->st, &sb2, sizeof(struct stat));
+ set_events(files);
+ }
+ }
+ }
+ show(file);
+ }
+
+ switch (action) {
+ case USE_KQUEUE:
+ ts.tv_sec = 1;
+ ts.tv_nsec = 0;
+ /*
+ * In the -F case we set a timeout to ensure that
+ * we re-stat the file at least once every second.
+ */
+ n = kevent(kq, NULL, 0, ev, 1, Fflag ? &ts : NULL);
+ if (n < 0)
+ err(1, "kevent");
+ if (n == 0) {
+ /* timeout */
+ break;
+ } else if (ev->filter == EVFILT_READ && ev->data < 0) {
+ /* file shrank, reposition to end */
+ if (lseek(ev->ident, (off_t)0, SEEK_END) == -1) {
+ ierr();
+ continue;
+ }
+ }
+ break;
+
+ case USE_SLEEP:
+ (void) usleep(250000);
+ break;
+ }
+ }
+}
diff --git a/text_cmds/tail/misc.c b/text_cmds/tail/misc.c
new file mode 100644
index 0000000..584e3d1
--- /dev/null
+++ b/text_cmds/tail/misc.c
@@ -0,0 +1,119 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Edward Sze-Tyan Wang.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)misc.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+void
+ierr()
+{
+ warn("%s", fname);
+ rval = 1;
+}
+
+void
+oerr()
+{
+ err(1, "stdout");
+}
+
+/*
+ * Print `len' bytes from the file associated with `mip', starting at
+ * absolute file offset `startoff'. May move map window.
+ */
+int
+mapprint(struct mapinfo *mip, off_t startoff, off_t len)
+{
+ int n;
+
+ while (len > 0) {
+ if (startoff < mip->mapoff || startoff >= mip->mapoff +
+ (off_t)mip->maplen) {
+ if (maparound(mip, startoff) != 0)
+ return (1);
+ }
+ n = (mip->mapoff + mip->maplen) - startoff;
+ if (n > len)
+ n = len;
+ WR(mip->start + (startoff - mip->mapoff), n);
+ startoff += n;
+ len -= n;
+ }
+ return (0);
+}
+
+/*
+ * Move the map window so that it contains the byte at absolute file
+ * offset `offset'. The start of the map window will be TAILMAPLEN
+ * aligned.
+ */
+int
+maparound(struct mapinfo *mip, off_t offset)
+{
+
+ if (mip->start != NULL && munmap(mip->start, mip->maplen) != 0)
+ return (1);
+
+ mip->mapoff = offset & ~((off_t)TAILMAPLEN - 1);
+ mip->maplen = TAILMAPLEN;
+ if ((off_t)mip->maplen > mip->maxoff - mip->mapoff)
+ mip->maplen = mip->maxoff - mip->mapoff;
+ if (mip->maplen <= 0)
+ abort();
+ if ((mip->start = mmap(NULL, mip->maplen, PROT_READ, MAP_SHARED,
+ mip->fd, mip->mapoff)) == MAP_FAILED)
+ return (1);
+
+ return (0);
+}
diff --git a/text_cmds/tail/read.c b/text_cmds/tail/read.c
new file mode 100644
index 0000000..85d4d6e
--- /dev/null
+++ b/text_cmds/tail/read.c
@@ -0,0 +1,214 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Edward Sze-Tyan Wang.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char sccsid[] = "@(#)read.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+/*
+ * bytes -- read bytes to an offset from the end and display.
+ *
+ * This is the function that reads to a byte offset from the end of the input,
+ * storing the data in a wrap-around buffer which is then displayed. If the
+ * rflag is set, the data is displayed in lines in reverse order, and this
+ * routine has the usual nastiness of trying to find the newlines. Otherwise,
+ * it is displayed from the character closest to the beginning of the input to
+ * the end.
+ */
+int
+bytes(FILE *fp, off_t off)
+{
+ int ch, len, tlen;
+ char *ep, *p, *t;
+ int wrap;
+ char *sp;
+
+ if ((sp = p = malloc(off)) == NULL)
+ err(1, "malloc");
+
+ for (wrap = 0, ep = p + off; (ch = getc(fp)) != EOF;) {
+ *p = ch;
+ if (++p == ep) {
+ wrap = 1;
+ p = sp;
+ }
+ }
+ if (ferror(fp)) {
+ ierr();
+ free(sp);
+ return 1;
+ }
+
+ if (rflag) {
+ for (t = p - 1, len = 0; t >= sp; --t, ++len)
+ if (*t == '\n' && len) {
+ WR(t + 1, len);
+ len = 0;
+ }
+ if (wrap) {
+ tlen = len;
+ for (t = ep - 1, len = 0; t >= p; --t, ++len)
+ if (*t == '\n') {
+ if (len) {
+ WR(t + 1, len);
+ len = 0;
+ }
+ if (tlen) {
+ WR(sp, tlen);
+ tlen = 0;
+ }
+ }
+ if (len)
+ WR(t + 1, len);
+ if (tlen)
+ WR(sp, tlen);
+ }
+ } else {
+ if (wrap && (len = ep - p))
+ WR(p, len);
+ len = p - sp;
+ if (len)
+ WR(sp, len);
+ }
+
+ free(sp);
+ return 0;
+}
+
+/*
+ * lines -- read lines to an offset from the end and display.
+ *
+ * This is the function that reads to a line offset from the end of the input,
+ * storing the data in an array of buffers which is then displayed. If the
+ * rflag is set, the data is displayed in lines in reverse order, and this
+ * routine has the usual nastiness of trying to find the newlines. Otherwise,
+ * it is displayed from the line closest to the beginning of the input to
+ * the end.
+ */
+int
+lines(FILE *fp, off_t off)
+{
+ struct {
+ int blen;
+ u_int len;
+ char *l;
+ } *llines;
+ int ch, rc;
+ char *p, *sp;
+ int blen, cnt, recno, wrap;
+
+ if ((llines = malloc(off * sizeof(*llines))) == NULL)
+ err(1, "malloc");
+ bzero(llines, off * sizeof(*llines));
+ sp = NULL;
+ blen = cnt = recno = wrap = 0;
+ rc = 0;
+
+ while ((ch = getc(fp)) != EOF) {
+ if (++cnt > blen) {
+ if ((sp = realloc(sp, blen += 1024)) == NULL)
+ err(1, "realloc");
+ p = sp + cnt - 1;
+ }
+ *p++ = ch;
+ if (ch == '\n') {
+ if ((int)llines[recno].blen < cnt) {
+ llines[recno].blen = cnt + 256;
+ if ((llines[recno].l = realloc(llines[recno].l,
+ llines[recno].blen)) == NULL)
+ err(1, "realloc");
+ }
+ bcopy(sp, llines[recno].l, llines[recno].len = cnt);
+ cnt = 0;
+ p = sp;
+ if (++recno == off) {
+ wrap = 1;
+ recno = 0;
+ }
+ }
+ }
+ if (ferror(fp)) {
+ ierr();
+ rc = 1;
+ goto done;
+ }
+ if (cnt) {
+ llines[recno].l = sp;
+ sp = NULL;
+ llines[recno].len = cnt;
+ if (++recno == off) {
+ wrap = 1;
+ recno = 0;
+ }
+ }
+
+ if (rflag) {
+ for (cnt = recno - 1; cnt >= 0; --cnt)
+ WR(llines[cnt].l, llines[cnt].len);
+ if (wrap)
+ for (cnt = off - 1; cnt >= recno; --cnt)
+ WR(llines[cnt].l, llines[cnt].len);
+ } else {
+ if (wrap)
+ for (cnt = recno; cnt < off; ++cnt)
+ WR(llines[cnt].l, llines[cnt].len);
+ for (cnt = 0; cnt < recno; ++cnt)
+ WR(llines[cnt].l, llines[cnt].len);
+ }
+done:
+ for (cnt = 0; cnt < off; cnt++)
+ free(llines[cnt].l);
+ free(sp);
+ free(llines);
+ return (rc);
+}
diff --git a/text_cmds/tail/reverse.c b/text_cmds/tail/reverse.c
new file mode 100644
index 0000000..f0a52aa
--- /dev/null
+++ b/text_cmds/tail/reverse.c
@@ -0,0 +1,287 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Edward Sze-Tyan Wang.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)reverse.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+static void r_buf(FILE *);
+static void r_reg(FILE *, enum STYLE, off_t, struct stat *);
+
+/*
+ * reverse -- display input in reverse order by line.
+ *
+ * There are six separate cases for this -- regular and non-regular
+ * files by bytes, lines or the whole file.
+ *
+ * BYTES display N bytes
+ * REG mmap the file and display the lines
+ * NOREG cyclically read characters into a wrap-around buffer
+ *
+ * LINES display N lines
+ * REG mmap the file and display the lines
+ * NOREG cyclically read lines into a wrap-around array of buffers
+ *
+ * FILE display the entire file
+ * REG mmap the file and display the lines
+ * NOREG cyclically read input into a linked list of buffers
+ */
+void
+reverse(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
+{
+ if (style != REVERSE && off == 0)
+ return;
+
+ if (S_ISREG(sbp->st_mode))
+ r_reg(fp, style, off, sbp);
+ else
+ switch(style) {
+ case FBYTES:
+ case RBYTES:
+ bytes(fp, off);
+ break;
+ case FLINES:
+ case RLINES:
+ lines(fp, off);
+ break;
+ case REVERSE:
+ r_buf(fp);
+ break;
+ default:
+ break;
+ }
+}
+
+/*
+ * r_reg -- display a regular file in reverse order by line.
+ */
+static void
+r_reg(FILE *fp, enum STYLE style, off_t off, struct stat *sbp)
+{
+ struct mapinfo map;
+ off_t curoff, size, lineend;
+ int i;
+
+ if (!(size = sbp->st_size))
+ return;
+
+ map.start = NULL;
+ map.mapoff = map.maxoff = size;
+ map.fd = fileno(fp);
+
+ /*
+ * Last char is special, ignore whether newline or not. Note that
+ * size == 0 is dealt with above, and size == 1 sets curoff to -1.
+ */
+ curoff = size - 2;
+ lineend = size;
+ while (curoff >= 0) {
+ if (curoff < map.mapoff ||
+ curoff >= map.mapoff + (off_t)map.maplen) {
+ if (maparound(&map, curoff) != 0) {
+ ierr();
+ return;
+ }
+ }
+ for (i = curoff - map.mapoff; i >= 0; i--) {
+ if (style == RBYTES && --off == 0)
+ break;
+ if (map.start[i] == '\n')
+ break;
+ }
+ /* `i' is either the map offset of a '\n', or -1. */
+ curoff = map.mapoff + i;
+ if (i < 0)
+ continue;
+
+ /* Print the line and update offsets. */
+ if (mapprint(&map, curoff + 1, lineend - curoff - 1) != 0) {
+ ierr();
+ return;
+ }
+ lineend = curoff + 1;
+ curoff--;
+
+ if (style == RLINES)
+ off--;
+
+ if (off == 0 && style != REVERSE) {
+ /* Avoid printing anything below. */
+ curoff = 0;
+ break;
+ }
+ }
+ if (curoff < 0 && mapprint(&map, 0, lineend) != 0) {
+ ierr();
+ return;
+ }
+ if (map.start != NULL && munmap(map.start, map.maplen))
+ ierr();
+}
+
+typedef struct bf {
+ struct bf *next;
+ struct bf *prev;
+ int len;
+ char *l;
+} BF;
+
+/*
+ * r_buf -- display a non-regular file in reverse order by line.
+ *
+ * This is the function that saves the entire input, storing the data in a
+ * doubly linked list of buffers and then displays them in reverse order.
+ * It has the usual nastiness of trying to find the newlines, as there's no
+ * guarantee that a newline occurs anywhere in the file, let alone in any
+ * particular buffer. If we run out of memory, input is discarded (and the
+ * user warned).
+ */
+static void
+r_buf(FILE *fp)
+{
+ BF *mark, *tl, *tr;
+ int ch, len, llen;
+ char *p;
+ off_t enomem;
+
+#define BSZ (128 * 1024)
+ for (mark = NULL, enomem = 0;;) {
+ /*
+ * Allocate a new block and link it into place in a doubly
+ * linked list. If out of memory, toss the LRU block and
+ * keep going.
+ */
+ if (enomem || (tl = malloc(sizeof(BF))) == NULL ||
+ (tl->l = malloc(BSZ)) == NULL) {
+ if (!mark)
+ err(1, "malloc");
+ tl = enomem ? tl->next : mark;
+ enomem += tl->len;
+ } else if (mark) {
+ tl->next = mark;
+ tl->prev = mark->prev;
+ mark->prev->next = tl;
+ mark->prev = tl;
+ } else {
+ mark = tl;
+ mark->next = mark->prev = mark;
+ }
+
+ /* Fill the block with input data. */
+ for (p = tl->l, len = 0;
+ len < BSZ && (ch = getc(fp)) != EOF; ++len)
+ *p++ = ch;
+
+ if (ferror(fp)) {
+ ierr();
+ return;
+ }
+
+ /*
+ * If no input data for this block and we tossed some data,
+ * recover it.
+ */
+ if (!len && enomem) {
+ enomem -= tl->len;
+ tl = tl->prev;
+ break;
+ }
+
+ tl->len = len;
+ if (ch == EOF)
+ break;
+ }
+
+ if (enomem) {
+ warnx("warning: %jd bytes discarded", (intmax_t)enomem);
+ rval = 1;
+ }
+
+ /*
+ * Step through the blocks in the reverse order read. The last char
+ * is special, ignore whether newline or not.
+ */
+ for (mark = tl;;) {
+ for (p = tl->l + (len = tl->len) - 1, llen = 0; len--;
+ --p, ++llen)
+ if (*p == '\n') {
+ if (llen) {
+ WR(p + 1, llen);
+ llen = 0;
+ }
+ if (tl == mark)
+ continue;
+ for (tr = tl->next; tr->len; tr = tr->next) {
+ WR(tr->l, tr->len);
+ tr->len = 0;
+ if (tr == mark)
+ break;
+ }
+ }
+ tl->len = llen;
+ if ((tl = tl->prev) == mark)
+ break;
+ }
+ tl = tl->next;
+ if (tl->len) {
+ WR(tl->l, tl->len);
+ tl->len = 0;
+ }
+ while ((tl = tl->next)->len) {
+ WR(tl->l, tl->len);
+ tl->len = 0;
+ }
+}
diff --git a/text_cmds/tail/tail.1 b/text_cmds/tail/tail.1
new file mode 100644
index 0000000..251511a
--- /dev/null
+++ b/text_cmds/tail/tail.1
@@ -0,0 +1,188 @@
+.\" Copyright (c) 1980, 1990, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tail.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
+.\"
+.Dd June 29, 2006
+.Dt TAIL 1
+.Os
+.Sh NAME
+.Nm tail
+.Nd display the last part of a file
+.Sh SYNOPSIS
+.Nm
+.Op Fl F | f | r
+.Op Fl q
+.Oo
+.Fl b Ar number | Fl c Ar number | Fl n Ar number
+.Oc
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the contents of
+.Ar file
+or, by default, its standard input, to the standard output.
+.Pp
+The display begins at a byte, line or 512-byte block location in the
+input.
+Numbers having a leading plus
+.Pq Ql +
+sign are relative to the beginning
+of the input, for example,
+.Dq Li "-c +2"
+starts the display at the second
+byte of the input.
+Numbers having a leading minus
+.Pq Ql -
+sign or no explicit sign are
+relative to the end of the input, for example,
+.Dq Li "-n 2"
+displays the last two lines of the input.
+The default starting location is
+.Dq Li "-n 10" ,
+or the last 10 lines of the input.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl b Ar number
+The location is
+.Ar number
+512-byte blocks.
+.It Fl c Ar number
+The location is
+.Ar number
+bytes.
+.It Fl f
+The
+.Fl f
+option causes
+.Nm
+to not stop when end of file is reached, but rather to wait for additional
+data to be appended to the input.
+The
+.Fl f
+option is ignored if the standard input is a pipe, but not if it is a FIFO.
+.It Fl F
+The
+.Fl F
+option implies the
+.Fl f
+option, but
+.Nm
+will also check to see if the file being followed has been renamed or rotated.
+The file is closed and reopened when
+.Nm
+detects that the filename being read from has a new inode number.
+The
+.Fl F
+option is ignored if reading from standard input rather than a file.
+.It Fl n Ar number
+The location is
+.Ar number
+lines.
+.It Fl q
+Suppresses printing of headers when multiple files are being examined.
+.It Fl r
+The
+.Fl r
+option causes the input to be displayed in reverse order, by line.
+Additionally, this option changes the meaning of the
+.Fl b , c
+and
+.Fl n
+options.
+When the
+.Fl r
+option is specified, these options specify the number of bytes, lines
+or 512-byte blocks to display, instead of the bytes, lines or blocks
+from the beginning or end of the input from which to begin the display.
+The default for the
+.Fl r
+option is to display all of the input.
+.El
+.Pp
+If more than a single file is specified, each file is preceded by a
+header consisting of the string
+.Dq Li "==> " Ns Ar XXX Ns Li " <=="
+where
+.Ar XXX
+is the name of the file unless
+.Fl q
+flag is specified.
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr cat 1 ,
+.Xr head 1 ,
+.Xr sed 1
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2-92
+specification.
+In particular, the
+.Fl F ,
+.Fl b
+and
+.Fl r
+options are extensions to that standard.
+.Pp
+The historic command line syntax of
+.Nm
+is supported by this implementation.
+The only difference between this implementation and historic versions
+of
+.Nm ,
+once the command line syntax translation has been done, is that the
+.Fl b ,
+.Fl c
+and
+.Fl n
+options modify the
+.Fl r
+option, i.e.,
+.Dq Li "-r -c 4"
+displays the last 4 characters of the last line
+of the input, while the historic tail (using the historic syntax
+.Dq Li -4cr )
+would ignore the
+.Fl c
+option and display the last 4 lines of the input.
+.Sh HISTORY
+A
+.Nm
+command appeared in PWB UNIX.
diff --git a/text_cmds/tail/tail.c b/text_cmds/tail/tail.c
new file mode 100644
index 0000000..57129ef
--- /dev/null
+++ b/text_cmds/tail/tail.c
@@ -0,0 +1,349 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Edward Sze-Tyan Wang.
+ *
+ * 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 the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD$");
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)tail.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
+
+int Fflag, fflag, qflag, rflag, rval, no_files;
+const char *fname;
+
+file_info_t *files;
+
+static void obsolete(char **);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ FILE *fp;
+ off_t off;
+ enum STYLE style;
+ int i, ch, first;
+ file_info_t *file;
+ char *p;
+
+ /*
+ * Tail's options are weird. First, -n10 is the same as -n-10, not
+ * -n+10. Second, the number options are 1 based and not offsets,
+ * so -n+1 is the first line, and -c-1 is the last byte. Third, the
+ * number options for the -r option specify the number of things that
+ * get displayed, not the starting point in the file. The one major
+ * incompatibility in this version as compared to historical versions
+ * is that the 'r' option couldn't be modified by the -lbc options,
+ * i.e. it was always done in lines. This version treats -rc as a
+ * number of characters in reverse order. Finally, the default for
+ * -r is the entire file, not 10 lines.
+ */
+#define ARG(units, forward, backward) { \
+ if (style) \
+ usage(); \
+ off = strtoll(optarg, &p, 10) * (units); \
+ if (*p) \
+ errx(1, "illegal offset -- %s", optarg); \
+ switch(optarg[0]) { \
+ case '+': \
+ if (off) \
+ off -= (units); \
+ style = (forward); \
+ break; \
+ case '-': \
+ off = -off; \
+ /* FALLTHROUGH */ \
+ default: \
+ style = (backward); \
+ break; \
+ } \
+}
+
+ obsolete(argv);
+ style = NOTSET;
+ while ((ch = getopt(argc, argv, "Fb:c:fn:qr")) != -1)
+ switch(ch) {
+ case 'F': /* -F is superset of (and implies) -f */
+ Fflag = fflag = 1;
+ break;
+ case 'b':
+ ARG(512, FBYTES, RBYTES);
+ break;
+ case 'c':
+ ARG(1, FBYTES, RBYTES);
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'n':
+ ARG(1, FLINES, RLINES);
+ break;
+ case 'q':
+ qflag = 1;
+ break;
+ case 'r':
+ rflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ no_files = argc ? argc : 1;
+
+ /*
+ * If displaying in reverse, don't permit follow option, and convert
+ * style values.
+ */
+ if (rflag) {
+ if (fflag)
+ usage();
+ if (style == FBYTES)
+ style = RBYTES;
+ else if (style == FLINES)
+ style = RLINES;
+ }
+
+ /*
+ * If style not specified, the default is the whole file for -r, and
+ * the last 10 lines if not -r.
+ */
+ if (style == NOTSET) {
+ if (rflag) {
+ off = 0;
+ style = REVERSE;
+ } else {
+ off = 10;
+ style = RLINES;
+ }
+ }
+
+ if (fflag && !argc) {
+ /*
+ * Determine if input is a pipe. 4.4BSD will set the SOCKET
+ * bit in the st_mode field for pipes. Fix this then.
+ */
+ if (lseek(fileno(stdin), (off_t)0, SEEK_CUR) == -1 &&
+ errno == ESPIPE) {
+ errno = 0;
+ fflag = 0; /* POSIX.2 requires this. */
+ }
+ }
+
+ if (fflag) {
+ files = (struct file_info *) malloc(no_files * sizeof(struct file_info));
+ if (! files)
+ err(1, "Couldn't malloc space for file descriptors.");
+
+ for (file = files; (fname = argc ? *argv++ : "stdin"); file++) {
+ file->file_name = malloc(strlen(fname)+1);
+ if (! file->file_name)
+ errx(1, "Couldn't malloc space for file name.");
+ strncpy(file->file_name, fname, strlen(fname)+1);
+ file->fp = argc ? fopen(file->file_name, "r") : stdin;
+ if (file->fp == NULL ||
+ fstat(fileno(file->fp), &file->st)) {
+ file->fp = NULL;
+ ierr();
+ continue;
+ }
+ if (!argc)
+ break;
+ }
+ follow(files, style, off);
+ for (i = 0, file = files; i < no_files; i++, file++) {
+ free(file->file_name);
+ }
+ free(files);
+ } else if (*argv) {
+ for (first = 1; (fname = *argv++);) {
+ if ((fp = fopen(fname, "r")) == NULL ||
+ fstat(fileno(fp), &sb)) {
+ ierr();
+ continue;
+ }
+ if (argc > 1 && !qflag) {
+ (void)printf("%s==> %s <==\n",
+ first ? "" : "\n", fname);
+ first = 0;
+ (void)fflush(stdout);
+ }
+
+#ifdef __APPLE__
+ /* 3849683: don't read a directory */
+ if (S_IFDIR == (sb.st_mode & S_IFMT))
+ continue;
+#endif
+
+ if (rflag)
+ reverse(fp, style, off, &sb);
+ else
+ forward(fp, style, off, &sb);
+ }
+ } else {
+ fname = "stdin";
+
+ if (fstat(fileno(stdin), &sb)) {
+ ierr();
+ exit(1);
+ }
+
+ if (rflag)
+ reverse(stdin, style, off, &sb);
+ else
+ forward(stdin, style, off, &sb);
+ }
+ exit(rval);
+}
+
+/*
+ * Convert the obsolete argument form into something that getopt can handle.
+ * This means that anything of the form [+-][0-9][0-9]*[lbc][Ffr] that isn't
+ * the option argument for a -b, -c or -n option gets converted.
+ */
+static void
+obsolete(char *argv[])
+{
+ char *ap, *p, *t;
+ size_t len;
+ char *start;
+
+ while ((ap = *++argv)) {
+ /* Return if "--" or not an option of any form. */
+ if (ap[0] != '-') {
+ if (ap[0] != '+')
+ return;
+ } else if (ap[1] == '-')
+ return;
+
+ switch(*++ap) {
+ /* Old-style option. */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+
+ /* Malloc space for dash, new option and argument. */
+ len = strlen(*argv);
+ if ((start = p = malloc(len + 3)) == NULL)
+ err(1, "malloc");
+ *p++ = '-';
+
+ /*
+ * Go to the end of the option argument. Save off any
+ * trailing options (-3lf) and translate any trailing
+ * output style characters.
+ */
+ t = *argv + len - 1;
+ if (*t == 'F' || *t == 'f' || *t == 'r') {
+ *p++ = *t;
+ *t-- = '\0';
+ }
+ switch(*t) {
+ case 'b':
+ *p++ = 'b';
+ *t = '\0';
+ break;
+ case 'c':
+ *p++ = 'c';
+ *t = '\0';
+ break;
+ case 'l':
+ *t = '\0';
+ /* FALLTHROUGH */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ *p++ = 'n';
+ break;
+ default:
+ errx(1, "illegal option -- %s", *argv);
+ }
+ *p++ = *argv[0];
+ (void)strcpy(p, ap);
+ *argv = start;
+ continue;
+
+ /*
+ * Options w/ arguments, skip the argument and continue
+ * with the next option.
+ */
+ case 'b':
+ case 'c':
+ case 'n':
+ if (!ap[1])
+ ++argv;
+ /* FALLTHROUGH */
+ /* Options w/o arguments, continue with the next option. */
+ case 'F':
+ case 'f':
+ case 'r':
+ continue;
+
+ /* Illegal option, return and let getopt handle it. */
+ default:
+ return;
+ }
+ }
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: tail [-F | -f | -r] [-q] [-b # | -c # | -n #]"
+ " [file ...]\n");
+ exit(1);
+}
diff --git a/text_cmds/tests/Makefile b/text_cmds/tests/Makefile
new file mode 100644
index 0000000..ed613c5
--- /dev/null
+++ b/text_cmds/tests/Makefile
@@ -0,0 +1,6 @@
+PROJECT := text_cmds
+TEST_DIR := tests
+
+
+include $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.common
+include $(DEVELOPER_DIR)/AppleInternal/Makefiles/darwintest/Makefile.targets
diff --git a/text_cmds/tests/sort_vers.c b/text_cmds/tests/sort_vers.c
new file mode 100644
index 0000000..8a3fce8
--- /dev/null
+++ b/text_cmds/tests/sort_vers.c
@@ -0,0 +1,23 @@
+#include <darwintest.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <limits.h>
+
+T_DECL(versionstring, "Apple specific version string") {
+ char version[128];
+ FILE *sortfile = popen("/usr/bin/sort --version", "r");
+ T_ASSERT_NOTNULL(sortfile, "Getting version string");
+ T_ASSERT_NOTNULL(fgets(version, sizeof(version), sortfile), "Reading version string");
+ pclose(sortfile);
+ T_ASSERT_NOTNULL(strstr(version, "-Apple"), "Apple in version string");
+
+ char *num = strstr(version, "(");
+ char *endnum = strstr(version, ")");
+ T_ASSERT_NOTNULL(num, "Locating parens start");
+ T_ASSERT_NOTNULL(endnum, "Locating parens end");
+ T_ASSERT_GT(endnum, num, "end is after the start");
+ long applevers = strtol(num+1, &endnum, 10);
+ T_ASSERT_GT(applevers, 0, "Version greater than zero");
+ T_ASSERT_LT(applevers, LONG_MAX, "Version less than LONG_MAX");
+}
diff --git a/text_cmds/text_cmds.plist b/text_cmds/text_cmds.plist
new file mode 100644
index 0000000..8f0ca1d
--- /dev/null
+++ b/text_cmds/text_cmds.plist
@@ -0,0 +1,607 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<array>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>banner</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/banner/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co banner</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Compile fix (needs sys/types.h).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>cat</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/bin/cat/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co cat</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>cksum</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/cksum/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co cksum</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Compile fix (needs stdint.h).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>col</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/col/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co col</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>colrm</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/colrm/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co colrm</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>column</string>
+ <key>OpenSourceVersion</key>
+ <string>2011-11-06</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/column/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co column</string>
+ <key>OpenSourceImportDate</key>
+ <string>2012-10-23</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>comm</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/comm/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co comm</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>csplit</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/csplit/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co csplit</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Rename getline to csplit_getline (7556902).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>cut</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/cut/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co cut</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>ed</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/bin/ed/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co ed</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Conformance fixes (3676514, 3738526, 3741027, 3751351, 3754089, 3936064, 3936075).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>ee</string>
+ <key>OpenSourceVersion</key>
+ <string>2011-12-17</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://svnweb.freebsd.org/base/head/contrib/ee/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/contrib/ee/</string>
+ <key>OpenSourceImportDate</key>
+ <string>2015-08-04</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>expand</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/expand/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co expand</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Clarify -t option in manpage (3973603).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>fmt</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/fmt/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co fmt</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>fold</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/fold/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co fold</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>bsdgrep</string>
+ <key>OpenSourceVersion</key>
+ <string>2012-01-15</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://wiki.freebsd.org/BSDgrep</string>
+ <key>OpenSourceSCM</key>
+ <string>cvs -d anoncvs@anoncvs1.FreeBSD.org:/home/ncvs co src/usr.bin/grep</string>
+ <key>OpenSourceImportDate</key>
+ <string>2012-01-23</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>9510115 (grep.c, util.c)</string>
+ <string>WITHOUT_FASTMATCH (grep.h, grep.c, util.c)</string>
+ <string>WITHOUT_LZMA (file.c, grep.c)</string>
+ <string>file.c: casts in grep_fgetln to fix warnings</string>
+ <string>file.c: adjust mmap flags</string>
+ <string>grep.c: enable REG_ENHANCED (except for -F mode)</string>
+ <string>grep.c: disable FILE_MMAP options</string>
+ <string>util.c: basename expects char *</string>
+ <string>util.c: ignore locale for binary files (10462853)</string>
+ <string>util.c: recursive stdin warning (10290183)</string>
+ <string>util.c: -w fix (10593340)</string>
+ <string>util.c: -c -q fix (10680370)</string>
+ <string>util.c, grep.h: avoid MAX_LINE_MATCHES limitation (10511988)</string>
+ <string>grep.c: Remove -P from usage statement (13475367)</string>
+ <string>util.c: Use mbtowc instead of sscanf (20248554)</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ <key>OpenSourceLicenseFile</key>
+ <string>bsdgrep.txt</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>head</string>
+ <key>OpenSourceVersion</key>
+ <string>2007-01-11</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/head/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co head</string>
+ <key>OpenSourceImportDate</key>
+ <string>2010-05-10</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Check ferror (6555390).</string>
+ </array>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>join</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/join/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co join</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Conformance fixes (3853584).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>lam</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/lam/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co lam</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>look</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/look/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co look</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>md5</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/sbin/md5/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co md5</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>XXX NOT MERGED YET XXX</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>nl</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/nl/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co nl</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Conformance fix in filter() (3849850).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>paste</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/paste/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co paste</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>pr</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/pr/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co pr</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Conformance fixes (3743086, 3936126).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>rev</string>
+ <key>OpenSourceVersion</key>
+ <string>2009-12-13</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/rev/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d anoncvs@anoncvs1.FreeBSD.org:/home/ncvs co rev</string>
+ <key>OpenSourceImportDate</key>
+ <string>2010-04-07</string>
+ <key>OpenSourceModifications</key>
+ <array/>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>rs</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/rs/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co rs</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Rename getline to rs_getline (7556902).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>sed</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/sed/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co sed</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Correctly document -y option (4134578).</string>
+ <string>Rewind stdin before exit (3681024).</string>
+ <string>Handle &apos;[&apos; delimiter (3733839).</string>
+ <string>Handle backslash with &apos;y&apos;, remove handy warning (3733839).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>sort</string>
+ <key>OpenSourceVersion</key>
+ <string>2017-09-27</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>https://svnweb.freebsd.org/base/head/usr.bin/sort/</string>
+ <key>OpenSourceSCM</key>
+ <string>svn co http://svn.freebsd.org/base/head/usr.bin/sort</string>
+ <key>OpenSourceImportDate</key>
+ <string>2017-09-27</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>file.c: mmap portability</string>
+ <string>file.c: fix unreachable code warning</string>
+ <string>coll.c, sort.c, sort.h: md5 portability</string>
+ <string>sort.c: update version output</string>
+ <string>sort.c: conformance failure with -k (28745165)</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>bsd</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>split</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/split/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co split</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>tail</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/tail/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co tail</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Don&apos;t read directories (3849683).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>tr</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/tr/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co tr</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Add missing character classes to man page (4115259).</string>
+ <string>Handle tr -s &apos;[a*]&apos; (3673947).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>ul</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/ul/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co ul</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>unexpand</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/unexpand/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co unexpand</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>uniq</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/uniq/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co uniq</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceModifications</key>
+ <array>
+ <string>Rename getline to uniq_getline (7556902).</string>
+ </array>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>unvis</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/unvis/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co unvis</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>vis</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/vis/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co vis</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+ <dict>
+ <key>OpenSourceProject</key>
+ <string>wc</string>
+ <key>OpenSourceVersion</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceWebsiteURL</key>
+ <string>http://www.freebsd.org/cgi/cvsweb.cgi/src/usr.bin/wc/</string>
+ <key>OpenSourceCVS</key>
+ <string>cvs -d freebsdanoncvs@anoncvs.FreeBSD.org:/home/ncvs co wc</string>
+ <key>OpenSourceImportDate</key>
+ <string>2005-09-16</string>
+ <key>OpenSourceLicense</key>
+ <string>BSD</string>
+ </dict>
+</array>
+</plist>
diff --git a/text_cmds/text_cmds.xcodeproj/project.pbxproj b/text_cmds/text_cmds.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..ac76c3b
--- /dev/null
+++ b/text_cmds/text_cmds.xcodeproj/project.pbxproj
@@ -0,0 +1,3890 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ FC7A7E91149875C30086576A /* executables */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = FC7A7E92149875C30086576A /* Build configuration list for PBXAggregateTarget "executables" */;
+ buildPhases = (
+ FC6C98FD149A989300DDCC47 /* Install open source info */,
+ FD3562041B828154008A70F6 /* Install grep variant links */,
+ );
+ dependencies = (
+ FC7A7E95149875E00086576A /* PBXTargetDependency */,
+ FC7A7E97149875E00086576A /* PBXTargetDependency */,
+ FC7A7E99149875E00086576A /* PBXTargetDependency */,
+ FC7A7E9B149875E00086576A /* PBXTargetDependency */,
+ FC7A7E9D149875E00086576A /* PBXTargetDependency */,
+ FC7A7E9F149875E00086576A /* PBXTargetDependency */,
+ FC7A7EA1149875E00086576A /* PBXTargetDependency */,
+ FC7A7EA3149875E00086576A /* PBXTargetDependency */,
+ FC7A7EA5149875E00086576A /* PBXTargetDependency */,
+ FD2BDC181B718D310053EE6B /* PBXTargetDependency */,
+ FC7A7EA7149875E00086576A /* PBXTargetDependency */,
+ FC7A7EA9149875E00086576A /* PBXTargetDependency */,
+ FC7A7EAB149875E00086576A /* PBXTargetDependency */,
+ FD3562061B8281A6008A70F6 /* PBXTargetDependency */,
+ FC7A7EAD149875E00086576A /* PBXTargetDependency */,
+ FC7A7EAF149875E00086576A /* PBXTargetDependency */,
+ FC7A7EB1149875E00086576A /* PBXTargetDependency */,
+ FC7A7EB3149875E00086576A /* PBXTargetDependency */,
+ FC7A7EB5149875E00086576A /* PBXTargetDependency */,
+ FC7A7EB7149875E00086576A /* PBXTargetDependency */,
+ FC7A7EB9149875E00086576A /* PBXTargetDependency */,
+ FC7A7EBB149875E00086576A /* PBXTargetDependency */,
+ FC7A7EBD149875E00086576A /* PBXTargetDependency */,
+ FC7A7EBF149875E00086576A /* PBXTargetDependency */,
+ FC7A7EC1149875E00086576A /* PBXTargetDependency */,
+ FC7A7EC3149875E00086576A /* PBXTargetDependency */,
+ FC7A7EC5149875E00086576A /* PBXTargetDependency */,
+ FC7A7EC7149875E00086576A /* PBXTargetDependency */,
+ FC7A7EC9149875E00086576A /* PBXTargetDependency */,
+ FC7A7ECB149875E00086576A /* PBXTargetDependency */,
+ FC7A7ECD149875E00086576A /* PBXTargetDependency */,
+ FC7A7ECF149875E00086576A /* PBXTargetDependency */,
+ FC7A7ED1149875E00086576A /* PBXTargetDependency */,
+ FC7A7ED3149875E00086576A /* PBXTargetDependency */,
+ FC7A7ED5149875E00086576A /* PBXTargetDependency */,
+ );
+ name = executables;
+ productName = executables;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ FC6C98FC149A94EB00DDCC47 /* libcurses.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FC6C98FB149A94EB00DDCC47 /* libcurses.dylib */; };
+ FC7A7DE514986CD60086576A /* banner.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B4C149866AE0086576A /* banner.c */; };
+ FC7A7DE614986CDB0086576A /* cat.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B50149866AE0086576A /* cat.c */; };
+ FC7A7DE714986CE00086576A /* col.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B54149866AE0086576A /* col.c */; };
+ FC7A7DE814986CE40086576A /* colrm.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B59149866AE0086576A /* colrm.c */; };
+ FC7A7DE914986CE90086576A /* column.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B5D149866AE0086576A /* column.c */; };
+ FC7A7DEA14986CEE0086576A /* comm.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B61149866AE0086576A /* comm.c */; };
+ FC7A7DEB14986D0C0086576A /* csplit.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B65149866AE0086576A /* csplit.c */; };
+ FC7A7DEC14986D120086576A /* cut.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B69149866AE0086576A /* cut.c */; };
+ FC7A7DED14986D690086576A /* buf.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B6C149866AE0086576A /* buf.c */; };
+ FC7A7DEE14986D690086576A /* cbc.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B6D149866AE0086576A /* cbc.c */; };
+ FC7A7DF014986D690086576A /* glbl.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B70149866AE0086576A /* glbl.c */; };
+ FC7A7DF114986D690086576A /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B71149866AE0086576A /* io.c */; };
+ FC7A7DF214986D690086576A /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B72149866AE0086576A /* main.c */; };
+ FC7A7DF314986D690086576A /* re.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B75149866AE0086576A /* re.c */; };
+ FC7A7DF414986D690086576A /* sub.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7B78149866AE0086576A /* sub.c */; };
+ FC7A7DF514986D690086576A /* undo.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C1E149866AF0086576A /* undo.c */; };
+ FC7A7DF614986D760086576A /* expand.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C21149866AF0086576A /* expand.c */; };
+ FC7A7DF714986D800086576A /* fmt.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C25149866AF0086576A /* fmt.c */; };
+ FC7A7DF814986D8B0086576A /* fold.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C29149866AF0086576A /* fold.c */; };
+ FC7A7DF914986D920086576A /* head.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C2D149866AF0086576A /* head.c */; };
+ FC7A7DFA14986DA10086576A /* join.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C31149866AF0086576A /* join.c */; };
+ FC7A7DFB14986DAB0086576A /* lam.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C35149866AF0086576A /* lam.c */; };
+ FC7A7DFC14986DBF0086576A /* look.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C39149866AF0086576A /* look.c */; };
+ FC7A7DFE14986DC80086576A /* commoncrypto.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C3D149866AF0086576A /* commoncrypto.c */; };
+ FC7A7E0014986DC80086576A /* md5.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C41149866AF0086576A /* md5.c */; };
+ FC7A7E0114986DD90086576A /* nl.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C45149866AF0086576A /* nl.c */; };
+ FC7A7E0214986DE40086576A /* paste.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C49149866AF0086576A /* paste.c */; };
+ FC7A7E0314986DF60086576A /* egetopt.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C4B149866AF0086576A /* egetopt.c */; };
+ FC7A7E0514986DF60086576A /* pr.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C4F149866AF0086576A /* pr.c */; };
+ FC7A7E0714986E040086576A /* rev.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C54149866AF0086576A /* rev.c */; };
+ FC7A7E0814986E0E0086576A /* rs.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C58149866AF0086576A /* rs.c */; };
+ FC7A7E0914986E1B0086576A /* compile.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C5A149866AF0086576A /* compile.c */; };
+ FC7A7E0C14986E1B0086576A /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C5D149866AF0086576A /* main.c */; };
+ FC7A7E0D14986E1B0086576A /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C5F149866AF0086576A /* misc.c */; };
+ FC7A7E0E14986E1B0086576A /* process.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C61149866AF0086576A /* process.c */; };
+ FC7A7E3714986E580086576A /* sort.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7C93149866AF0086576A /* sort.c */; };
+ FC7A7E5614986E630086576A /* split.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CB5149866AF0086576A /* split.c */; };
+ FC7A7E5814986E750086576A /* forward.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CB8149866AF0086576A /* forward.c */; };
+ FC7A7E5914986E750086576A /* misc.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CBA149866AF0086576A /* misc.c */; };
+ FC7A7E5A14986E750086576A /* read.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CBB149866AF0086576A /* read.c */; };
+ FC7A7E5B14986E750086576A /* reverse.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CBC149866AF0086576A /* reverse.c */; };
+ FC7A7E5C14986E750086576A /* tail.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CBE149866AF0086576A /* tail.c */; };
+ FC7A7E5D14986E880086576A /* cmap.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CC1149866AF0086576A /* cmap.c */; };
+ FC7A7E5F14986E880086576A /* cset.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CC3149866AF0086576A /* cset.c */; };
+ FC7A7E6214986E880086576A /* str.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CC7149866AF0086576A /* str.c */; };
+ FC7A7E6314986E880086576A /* tr.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CC9149866AF0086576A /* tr.c */; };
+ FC7A7E6414986E920086576A /* ul.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CCD149866AF0086576A /* ul.c */; };
+ FC7A7E6514986E9B0086576A /* unexpand.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CD0149866AF0086576A /* unexpand.c */; };
+ FC7A7E6614986EA40086576A /* uniq.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CD4149866AF0086576A /* uniq.c */; };
+ FC7A7E6714986EAC0086576A /* unvis.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CD8149866AF0086576A /* unvis.c */; };
+ FC7A7E6914986EB90086576A /* foldit.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CDB149866AF0086576A /* foldit.c */; };
+ FC7A7E6A14986EB90086576A /* vis.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CDE149866AF0086576A /* vis.c */; };
+ FC7A7E6B14986EC10086576A /* wc.c in Sources */ = {isa = PBXBuildFile; fileRef = FC7A7CE2149866AF0086576A /* wc.c */; };
+ FC7A7E6C14986F0E0086576A /* banner.6 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B4B149866AE0086576A /* banner.6 */; };
+ FC7A7E6D14986F120086576A /* cat.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B4F149866AE0086576A /* cat.1 */; };
+ FC7A7E6E14986F180086576A /* col.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B53149866AE0086576A /* col.1 */; };
+ FC7A7E6F14986F1B0086576A /* colrm.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B58149866AE0086576A /* colrm.1 */; };
+ FC7A7E7014986F200086576A /* column.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B5C149866AE0086576A /* column.1 */; };
+ FC7A7E7114986F230086576A /* comm.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B60149866AE0086576A /* comm.1 */; };
+ FC7A7E7214986F270086576A /* csplit.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B64149866AE0086576A /* csplit.1 */; };
+ FC7A7E7314986F2A0086576A /* cut.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B68149866AE0086576A /* cut.1 */; };
+ FC7A7E7414986F2E0086576A /* ed.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B6E149866AE0086576A /* ed.1 */; };
+ FC7A7E7514986F330086576A /* red.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7B77149866AE0086576A /* red.1 */; };
+ FC7A7E7614986F3B0086576A /* expand.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C20149866AF0086576A /* expand.1 */; };
+ FC7A7E7714986F3E0086576A /* fmt.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C24149866AF0086576A /* fmt.1 */; };
+ FC7A7E7814986F400086576A /* fold.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C28149866AF0086576A /* fold.1 */; };
+ FC7A7E7914986F430086576A /* head.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C2C149866AF0086576A /* head.1 */; };
+ FC7A7E7A14986F4A0086576A /* join.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C30149866AF0086576A /* join.1 */; };
+ FC7A7E7B14986F4D0086576A /* lam.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C34149866AF0086576A /* lam.1 */; };
+ FC7A7E7C14986F500086576A /* look.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C38149866AF0086576A /* look.1 */; };
+ FC7A7E7D14986F540086576A /* md5.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C40149866AF0086576A /* md5.1 */; };
+ FC7A7E7E14986F5A0086576A /* nl.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C44149866AF0086576A /* nl.1 */; };
+ FC7A7E7F14986F5D0086576A /* paste.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C48149866AF0086576A /* paste.1 */; };
+ FC7A7E8014986F610086576A /* pr.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C4E149866AF0086576A /* pr.1 */; };
+ FC7A7E8114986F740086576A /* rev.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C53149866AF0086576A /* rev.1 */; };
+ FC7A7E8214986F790086576A /* rs.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C57149866AF0086576A /* rs.1 */; };
+ FC7A7E8314986F800086576A /* sed.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7C62149866AF0086576A /* sed.1 */; };
+ FC7A7E8514986FCF0086576A /* split.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7CB4149866AF0086576A /* split.1 */; };
+ FC7A7E8614986FDA0086576A /* tail.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7CBD149866AF0086576A /* tail.1 */; };
+ FC7A7E8814986FF20086576A /* ul.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7CCC149866AF0086576A /* ul.1 */; };
+ FC7A7E89149870000086576A /* uniq.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7CD3149866AF0086576A /* uniq.1 */; };
+ FC7A7E8E149870670086576A /* wc.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7CE1149866AF0086576A /* wc.1 */; };
+ FC7A7E8F149870740086576A /* vis.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7CDD149866AF0086576A /* vis.1 */; };
+ FC7A7E90149870820086576A /* unvis.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7CD7149866AF0086576A /* unvis.1 */; };
+ FCD527B0149AA082001EBF77 /* tr.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FC7A7CC8149866AF0086576A /* tr.1 */; };
+ FD3561FE1B827F9F008A70F6 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = FD3561F81B827F9F008A70F6 /* file.c */; };
+ FD3561FF1B827F9F008A70F6 /* grep.c in Sources */ = {isa = PBXBuildFile; fileRef = FD3561FA1B827F9F008A70F6 /* grep.c */; };
+ FD3562001B827F9F008A70F6 /* queue.c in Sources */ = {isa = PBXBuildFile; fileRef = FD3561FC1B827F9F008A70F6 /* queue.c */; };
+ FD3562011B827F9F008A70F6 /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = FD3561FD1B827F9F008A70F6 /* util.c */; };
+ FD3562021B827FC0008A70F6 /* grep.1 in Install Man Page */ = {isa = PBXBuildFile; fileRef = FD3561F91B827F9F008A70F6 /* grep.1 */; };
+ FDA49B951B718738003B4F3C /* ee.c in Sources */ = {isa = PBXBuildFile; fileRef = FDA49B941B718738003B4F3C /* ee.c */; };
+ FDA49B971B71876A003B4F3C /* ee.1 in Copy Files */ = {isa = PBXBuildFile; fileRef = FDA49B961B718762003B4F3C /* ee.1 */; };
+ FDF283681DAED0C000CF8C36 /* bwstring.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF283571DAED0C000CF8C36 /* bwstring.c */; };
+ FDF283691DAED0C000CF8C36 /* coll.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF283591DAED0C000CF8C36 /* coll.c */; };
+ FDF2836A1DAED0C000CF8C36 /* file.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2835B1DAED0C000CF8C36 /* file.c */; };
+ FDF2836B1DAED0C000CF8C36 /* mem.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2835D1DAED0C000CF8C36 /* mem.c */; };
+ FDF2836C1DAED0C000CF8C36 /* radixsort.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF283621DAED0C000CF8C36 /* radixsort.c */; };
+ FDF2836D1DAED0C000CF8C36 /* vsort.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF283661DAED0C000CF8C36 /* vsort.c */; };
+ FDF283711DAED7C700CF8C36 /* commoncrypto.c in Sources */ = {isa = PBXBuildFile; fileRef = FDF2836F1DAED7C700CF8C36 /* commoncrypto.c */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ FC7A7E94149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7B38149865C80086576A;
+ remoteInfo = banner;
+ };
+ FC7A7E96149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7CE4149867ED0086576A;
+ remoteInfo = cat;
+ };
+ FC7A7E98149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7CEC149869E90086576A;
+ remoteInfo = col;
+ };
+ FC7A7E9A149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7CF414986A160086576A;
+ remoteInfo = colrm;
+ };
+ FC7A7E9C149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7CFC14986A190086576A;
+ remoteInfo = column;
+ };
+ FC7A7E9E149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D0414986A1B0086576A;
+ remoteInfo = comm;
+ };
+ FC7A7EA0149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D0C14986A1E0086576A;
+ remoteInfo = csplit;
+ };
+ FC7A7EA2149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D1414986A210086576A;
+ remoteInfo = cut;
+ };
+ FC7A7EA4149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D1C14986A230086576A;
+ remoteInfo = ed;
+ };
+ FC7A7EA6149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D2414986A240086576A;
+ remoteInfo = expand;
+ };
+ FC7A7EA8149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D2C14986A280086576A;
+ remoteInfo = fmt;
+ };
+ FC7A7EAA149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D3414986A2B0086576A;
+ remoteInfo = fold;
+ };
+ FC7A7EAC149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D3C14986A2F0086576A;
+ remoteInfo = head;
+ };
+ FC7A7EAE149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D4414986A310086576A;
+ remoteInfo = join;
+ };
+ FC7A7EB0149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D4C14986A340086576A;
+ remoteInfo = lam;
+ };
+ FC7A7EB2149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D5414986A360086576A;
+ remoteInfo = look;
+ };
+ FC7A7EB4149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D5C14986A390086576A;
+ remoteInfo = md5;
+ };
+ FC7A7EB6149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D6414986A3C0086576A;
+ remoteInfo = nl;
+ };
+ FC7A7EB8149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D6C14986A3D0086576A;
+ remoteInfo = paste;
+ };
+ FC7A7EBA149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D7414986A400086576A;
+ remoteInfo = pr;
+ };
+ FC7A7EBC149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D7C14986A410086576A;
+ remoteInfo = rev;
+ };
+ FC7A7EBE149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D8414986A430086576A;
+ remoteInfo = rs;
+ };
+ FC7A7EC0149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D8C14986A450086576A;
+ remoteInfo = sed;
+ };
+ FC7A7EC2149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D9414986A470086576A;
+ remoteInfo = sort;
+ };
+ FC7A7EC4149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7D9C14986A480086576A;
+ remoteInfo = split;
+ };
+ FC7A7EC6149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7DA414986A4A0086576A;
+ remoteInfo = tail;
+ };
+ FC7A7EC8149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7DAC14986A500086576A;
+ remoteInfo = tr;
+ };
+ FC7A7ECA149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7DB414986A530086576A;
+ remoteInfo = ul;
+ };
+ FC7A7ECC149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7DBC14986A540086576A;
+ remoteInfo = unexpand;
+ };
+ FC7A7ECE149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7DC414986A560086576A;
+ remoteInfo = uniq;
+ };
+ FC7A7ED0149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7DCC14986A580086576A;
+ remoteInfo = unvis;
+ };
+ FC7A7ED2149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7DD414986A5A0086576A;
+ remoteInfo = vis;
+ };
+ FC7A7ED4149875E00086576A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FC7A7DDC14986A5C0086576A;
+ remoteInfo = wc;
+ };
+ FD2BDC171B718D310053EE6B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FDA49B8D1B7186CE003B4F3C;
+ remoteInfo = ee;
+ };
+ FD3562051B8281A6008A70F6 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = FC7A7B30149865C80086576A /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = FD3561F11B827EE0008A70F6;
+ remoteInfo = grep;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ FC7A7B37149865C80086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man6/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E6C14986F0E0086576A /* banner.6 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7CE7149867ED0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E6D14986F120086576A /* cat.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7CEF149869E90086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E6E14986F180086576A /* col.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7CF714986A160086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E6F14986F1B0086576A /* colrm.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7CFF14986A190086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7014986F200086576A /* column.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D0714986A1B0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7114986F230086576A /* comm.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D0F14986A1E0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7214986F270086576A /* csplit.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D1714986A210086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7314986F2A0086576A /* cut.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D1F14986A230086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7414986F2E0086576A /* ed.1 in CopyFiles */,
+ FC7A7E7514986F330086576A /* red.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D2714986A240086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7614986F3B0086576A /* expand.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D2F14986A280086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7714986F3E0086576A /* fmt.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D3714986A2B0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7814986F400086576A /* fold.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D3F14986A2F0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7914986F430086576A /* head.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D4714986A310086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7A14986F4A0086576A /* join.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D4F14986A340086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7B14986F4D0086576A /* lam.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D5714986A360086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7C14986F500086576A /* look.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D5F14986A390086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7D14986F540086576A /* md5.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D6714986A3C0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7E14986F5A0086576A /* nl.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D6F14986A3D0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E7F14986F5D0086576A /* paste.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D7714986A400086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8014986F610086576A /* pr.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D7F14986A410086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8114986F740086576A /* rev.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D8714986A430086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8214986F790086576A /* rs.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D8F14986A450086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8314986F800086576A /* sed.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7D9F14986A480086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8514986FCF0086576A /* split.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7DA714986A4A0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8614986FDA0086576A /* tail.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7DAF14986A500086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FCD527B0149AA082001EBF77 /* tr.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7DB714986A530086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8814986FF20086576A /* ul.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7DBF14986A540086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7DC714986A560086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E89149870000086576A /* uniq.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7DCF14986A580086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E90149870820086576A /* unvis.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7DD714986A5A0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8F149870740086576A /* vis.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FC7A7DDF14986A5C0086576A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FC7A7E8E149870670086576A /* wc.1 in CopyFiles */,
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FD3561F01B827EE0008A70F6 /* Install Man Page */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ FD3562021B827FC0008A70F6 /* grep.1 in Install Man Page */,
+ );
+ name = "Install Man Page";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ FDA49B8C1B7186CE003B4F3C /* Copy Files */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "$(EE_PREFIX)/share/man/man1";
+ dstSubfolderSpec = 0;
+ files = (
+ FDA49B971B71876A003B4F3C /* ee.1 in Copy Files */,
+ );
+ name = "Copy Files";
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 3EF506E11F7ABD7500421EB3 /* tests */ = {isa = PBXFileReference; lastKnownFileType = folder; path = tests; sourceTree = "<group>"; };
+ FC6C98FB149A94EB00DDCC47 /* libcurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcurses.dylib; path = /usr/lib/libcurses.dylib; sourceTree = "<absolute>"; };
+ FC7A7B39149865C80086576A /* banner */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = banner; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7B4B149866AE0086576A /* banner.6 */ = {isa = PBXFileReference; lastKnownFileType = text; path = banner.6; sourceTree = "<group>"; };
+ FC7A7B4C149866AE0086576A /* banner.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = banner.c; sourceTree = "<group>"; };
+ FC7A7B4F149866AE0086576A /* cat.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = cat.1; sourceTree = "<group>"; };
+ FC7A7B50149866AE0086576A /* cat.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cat.c; sourceTree = "<group>"; };
+ FC7A7B53149866AE0086576A /* col.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = col.1; sourceTree = "<group>"; };
+ FC7A7B54149866AE0086576A /* col.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = col.c; sourceTree = "<group>"; };
+ FC7A7B56149866AE0086576A /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ FC7A7B58149866AE0086576A /* colrm.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = colrm.1; sourceTree = "<group>"; };
+ FC7A7B59149866AE0086576A /* colrm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = colrm.c; sourceTree = "<group>"; };
+ FC7A7B5C149866AE0086576A /* column.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = column.1; sourceTree = "<group>"; };
+ FC7A7B5D149866AE0086576A /* column.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = column.c; sourceTree = "<group>"; };
+ FC7A7B60149866AE0086576A /* comm.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = comm.1; sourceTree = "<group>"; };
+ FC7A7B61149866AE0086576A /* comm.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = comm.c; sourceTree = "<group>"; };
+ FC7A7B64149866AE0086576A /* csplit.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = csplit.1; sourceTree = "<group>"; };
+ FC7A7B65149866AE0086576A /* csplit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = csplit.c; sourceTree = "<group>"; };
+ FC7A7B68149866AE0086576A /* cut.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = cut.1; sourceTree = "<group>"; };
+ FC7A7B69149866AE0086576A /* cut.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cut.c; sourceTree = "<group>"; };
+ FC7A7B6C149866AE0086576A /* buf.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = buf.c; sourceTree = "<group>"; };
+ FC7A7B6D149866AE0086576A /* cbc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cbc.c; sourceTree = "<group>"; };
+ FC7A7B6E149866AE0086576A /* ed.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = ed.1; sourceTree = "<group>"; };
+ FC7A7B6F149866AE0086576A /* ed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ed.h; sourceTree = "<group>"; };
+ FC7A7B70149866AE0086576A /* glbl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = glbl.c; sourceTree = "<group>"; };
+ FC7A7B71149866AE0086576A /* io.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = io.c; sourceTree = "<group>"; };
+ FC7A7B72149866AE0086576A /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ FC7A7B74149866AE0086576A /* POSIX */ = {isa = PBXFileReference; lastKnownFileType = text; path = POSIX; sourceTree = "<group>"; };
+ FC7A7B75149866AE0086576A /* re.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = re.c; sourceTree = "<group>"; };
+ FC7A7B76149866AE0086576A /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ FC7A7B77149866AE0086576A /* red.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = red.1; sourceTree = "<group>"; };
+ FC7A7B78149866AE0086576A /* sub.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sub.c; sourceTree = "<group>"; };
+ FC7A7B7A149866AE0086576A /* =.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = "=.err"; sourceTree = "<group>"; };
+ FC7A7B7B149866AE0086576A /* a.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = a.d; sourceTree = "<group>"; };
+ FC7A7B7C149866AE0086576A /* a.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = a.r; sourceTree = "<group>"; };
+ FC7A7B7D149866AE0086576A /* a.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = a.t; sourceTree = "<group>"; };
+ FC7A7B7E149866AE0086576A /* a1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = a1.err; sourceTree = "<group>"; };
+ FC7A7B7F149866AE0086576A /* a2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = a2.err; sourceTree = "<group>"; };
+ FC7A7B80149866AE0086576A /* addr.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = addr.d; sourceTree = "<group>"; };
+ FC7A7B81149866AE0086576A /* addr.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = addr.r; sourceTree = "<group>"; };
+ FC7A7B82149866AE0086576A /* addr.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = addr.t; sourceTree = "<group>"; };
+ FC7A7B83149866AE0086576A /* addr1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = addr1.err; sourceTree = "<group>"; };
+ FC7A7B84149866AE0086576A /* addr2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = addr2.err; sourceTree = "<group>"; };
+ FC7A7B85149866AE0086576A /* ascii.d.uu */ = {isa = PBXFileReference; lastKnownFileType = text; path = ascii.d.uu; sourceTree = "<group>"; };
+ FC7A7B86149866AE0086576A /* ascii.r.uu */ = {isa = PBXFileReference; lastKnownFileType = text; path = ascii.r.uu; sourceTree = "<group>"; };
+ FC7A7B87149866AE0086576A /* ascii.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = ascii.t; sourceTree = "<group>"; };
+ FC7A7B88149866AE0086576A /* bang1.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = bang1.d; sourceTree = "<group>"; };
+ FC7A7B89149866AE0086576A /* bang1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = bang1.err; sourceTree = "<group>"; };
+ FC7A7B8A149866AE0086576A /* bang1.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = bang1.r; sourceTree = "<group>"; };
+ FC7A7B8B149866AE0086576A /* bang1.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = bang1.t; sourceTree = "<group>"; };
+ FC7A7B8C149866AE0086576A /* bang2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = bang2.err; sourceTree = "<group>"; };
+ FC7A7B8D149866AE0086576A /* c.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = c.d; sourceTree = "<group>"; };
+ FC7A7B8E149866AE0086576A /* c.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = c.r; sourceTree = "<group>"; };
+ FC7A7B8F149866AE0086576A /* c.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = c.t; sourceTree = "<group>"; };
+ FC7A7B90149866AE0086576A /* c1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = c1.err; sourceTree = "<group>"; };
+ FC7A7B91149866AE0086576A /* c2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = c2.err; sourceTree = "<group>"; };
+ FC7A7B92149866AE0086576A /* ckscripts.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = ckscripts.sh; sourceTree = "<group>"; };
+ FC7A7B93149866AE0086576A /* d.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = d.d; sourceTree = "<group>"; };
+ FC7A7B94149866AE0086576A /* d.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = d.err; sourceTree = "<group>"; };
+ FC7A7B95149866AE0086576A /* d.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = d.r; sourceTree = "<group>"; };
+ FC7A7B96149866AE0086576A /* d.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = d.t; sourceTree = "<group>"; };
+ FC7A7B97149866AE0086576A /* e1.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = e1.d; sourceTree = "<group>"; };
+ FC7A7B98149866AE0086576A /* e1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = e1.err; sourceTree = "<group>"; };
+ FC7A7B99149866AE0086576A /* e1.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = e1.r; sourceTree = "<group>"; };
+ FC7A7B9A149866AE0086576A /* e1.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = e1.t; sourceTree = "<group>"; };
+ FC7A7B9B149866AE0086576A /* e2.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = e2.d; sourceTree = "<group>"; };
+ FC7A7B9C149866AE0086576A /* e2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = e2.err; sourceTree = "<group>"; };
+ FC7A7B9D149866AE0086576A /* e2.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = e2.r; sourceTree = "<group>"; };
+ FC7A7B9E149866AE0086576A /* e2.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = e2.t; sourceTree = "<group>"; };
+ FC7A7B9F149866AE0086576A /* e3.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = e3.d; sourceTree = "<group>"; };
+ FC7A7BA0149866AE0086576A /* e3.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = e3.err; sourceTree = "<group>"; };
+ FC7A7BA1149866AE0086576A /* e3.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = e3.r; sourceTree = "<group>"; };
+ FC7A7BA2149866AE0086576A /* e3.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = e3.t; sourceTree = "<group>"; };
+ FC7A7BA3149866AE0086576A /* e4.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = e4.d; sourceTree = "<group>"; };
+ FC7A7BA4149866AE0086576A /* e4.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = e4.r; sourceTree = "<group>"; };
+ FC7A7BA5149866AE0086576A /* e4.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = e4.t; sourceTree = "<group>"; };
+ FC7A7BA6149866AE0086576A /* f1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = f1.err; sourceTree = "<group>"; };
+ FC7A7BA7149866AE0086576A /* f2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = f2.err; sourceTree = "<group>"; };
+ FC7A7BA8149866AE0086576A /* g1.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = g1.d; sourceTree = "<group>"; };
+ FC7A7BA9149866AE0086576A /* g1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = g1.err; sourceTree = "<group>"; };
+ FC7A7BAA149866AE0086576A /* g1.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = g1.r; sourceTree = "<group>"; };
+ FC7A7BAB149866AE0086576A /* g1.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = g1.t; sourceTree = "<group>"; };
+ FC7A7BAC149866AE0086576A /* g2.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = g2.d; sourceTree = "<group>"; };
+ FC7A7BAD149866AE0086576A /* g2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = g2.err; sourceTree = "<group>"; };
+ FC7A7BAE149866AE0086576A /* g2.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = g2.r; sourceTree = "<group>"; };
+ FC7A7BAF149866AE0086576A /* g2.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = g2.t; sourceTree = "<group>"; };
+ FC7A7BB0149866AE0086576A /* g3.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = g3.d; sourceTree = "<group>"; };
+ FC7A7BB1149866AE0086576A /* g3.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = g3.err; sourceTree = "<group>"; };
+ FC7A7BB2149866AE0086576A /* g3.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = g3.r; sourceTree = "<group>"; };
+ FC7A7BB3149866AE0086576A /* g3.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = g3.t; sourceTree = "<group>"; };
+ FC7A7BB4149866AE0086576A /* g4.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = g4.d; sourceTree = "<group>"; };
+ FC7A7BB5149866AE0086576A /* g4.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = g4.r; sourceTree = "<group>"; };
+ FC7A7BB6149866AE0086576A /* g4.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = g4.t; sourceTree = "<group>"; };
+ FC7A7BB7149866AE0086576A /* g5.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = g5.d; sourceTree = "<group>"; };
+ FC7A7BB8149866AE0086576A /* g5.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = g5.r; sourceTree = "<group>"; };
+ FC7A7BB9149866AE0086576A /* g5.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = g5.t; sourceTree = "<group>"; };
+ FC7A7BBA149866AE0086576A /* h.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = h.err; sourceTree = "<group>"; };
+ FC7A7BBB149866AE0086576A /* i.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = i.d; sourceTree = "<group>"; };
+ FC7A7BBC149866AE0086576A /* i.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = i.r; sourceTree = "<group>"; };
+ FC7A7BBD149866AE0086576A /* i.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = i.t; sourceTree = "<group>"; };
+ FC7A7BBE149866AE0086576A /* i1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = i1.err; sourceTree = "<group>"; };
+ FC7A7BBF149866AE0086576A /* i2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = i2.err; sourceTree = "<group>"; };
+ FC7A7BC0149866AE0086576A /* i3.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = i3.err; sourceTree = "<group>"; };
+ FC7A7BC1149866AE0086576A /* j.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = j.d; sourceTree = "<group>"; };
+ FC7A7BC2149866AE0086576A /* j.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = j.r; sourceTree = "<group>"; };
+ FC7A7BC3149866AE0086576A /* j.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = j.t; sourceTree = "<group>"; };
+ FC7A7BC4149866AE0086576A /* k.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = k.d; sourceTree = "<group>"; };
+ FC7A7BC5149866AE0086576A /* k.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = k.r; sourceTree = "<group>"; };
+ FC7A7BC6149866AE0086576A /* k.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = k.t; sourceTree = "<group>"; };
+ FC7A7BC7149866AE0086576A /* k1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = k1.err; sourceTree = "<group>"; };
+ FC7A7BC8149866AE0086576A /* k2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = k2.err; sourceTree = "<group>"; };
+ FC7A7BC9149866AE0086576A /* k3.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = k3.err; sourceTree = "<group>"; };
+ FC7A7BCA149866AE0086576A /* k4.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = k4.err; sourceTree = "<group>"; };
+ FC7A7BCB149866AE0086576A /* l.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = l.d; sourceTree = "<group>"; };
+ FC7A7BCC149866AE0086576A /* l.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = l.r; sourceTree = "<group>"; };
+ FC7A7BCD149866AE0086576A /* l.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = l.t; sourceTree = "<group>"; };
+ FC7A7BCE149866AE0086576A /* m.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = m.d; sourceTree = "<group>"; };
+ FC7A7BCF149866AE0086576A /* m.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = m.err; sourceTree = "<group>"; };
+ FC7A7BD0149866AE0086576A /* m.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = m.r; sourceTree = "<group>"; };
+ FC7A7BD1149866AE0086576A /* m.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = m.t; sourceTree = "<group>"; };
+ FC7A7BD2149866AE0086576A /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
+ FC7A7BD3149866AE0086576A /* mkscripts.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = mkscripts.sh; sourceTree = "<group>"; };
+ FC7A7BD4149866AE0086576A /* n.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = n.d; sourceTree = "<group>"; };
+ FC7A7BD5149866AE0086576A /* n.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = n.r; sourceTree = "<group>"; };
+ FC7A7BD6149866AE0086576A /* n.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = n.t; sourceTree = "<group>"; };
+ FC7A7BD7149866AE0086576A /* nl.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = nl.err; sourceTree = "<group>"; };
+ FC7A7BD8149866AE0086576A /* nl1.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = nl1.d; sourceTree = "<group>"; };
+ FC7A7BD9149866AE0086576A /* nl1.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = nl1.r; sourceTree = "<group>"; };
+ FC7A7BDA149866AE0086576A /* nl1.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = nl1.t; sourceTree = "<group>"; };
+ FC7A7BDB149866AE0086576A /* nl2.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = nl2.d; sourceTree = "<group>"; };
+ FC7A7BDC149866AE0086576A /* nl2.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = nl2.r; sourceTree = "<group>"; };
+ FC7A7BDD149866AE0086576A /* nl2.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = nl2.t; sourceTree = "<group>"; };
+ FC7A7BDE149866AE0086576A /* p.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = p.d; sourceTree = "<group>"; };
+ FC7A7BDF149866AE0086576A /* p.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = p.r; sourceTree = "<group>"; };
+ FC7A7BE0149866AE0086576A /* p.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = p.t; sourceTree = "<group>"; };
+ FC7A7BE1149866AE0086576A /* q.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = q.d; sourceTree = "<group>"; };
+ FC7A7BE2149866AE0086576A /* q.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = q.r; sourceTree = "<group>"; };
+ FC7A7BE3149866AE0086576A /* q.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = q.t; sourceTree = "<group>"; };
+ FC7A7BE4149866AE0086576A /* q1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = q1.err; sourceTree = "<group>"; };
+ FC7A7BE5149866AE0086576A /* r1.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = r1.d; sourceTree = "<group>"; };
+ FC7A7BE6149866AE0086576A /* r1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = r1.err; sourceTree = "<group>"; };
+ FC7A7BE7149866AE0086576A /* r1.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = r1.r; sourceTree = "<group>"; };
+ FC7A7BE8149866AE0086576A /* r1.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = r1.t; sourceTree = "<group>"; };
+ FC7A7BE9149866AE0086576A /* r2.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = r2.d; sourceTree = "<group>"; };
+ FC7A7BEA149866AE0086576A /* r2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = r2.err; sourceTree = "<group>"; };
+ FC7A7BEB149866AE0086576A /* r2.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = r2.r; sourceTree = "<group>"; };
+ FC7A7BEC149866AE0086576A /* r2.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = r2.t; sourceTree = "<group>"; };
+ FC7A7BED149866AE0086576A /* r3.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = r3.d; sourceTree = "<group>"; };
+ FC7A7BEE149866AE0086576A /* r3.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = r3.r; sourceTree = "<group>"; };
+ FC7A7BEF149866AE0086576A /* r3.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = r3.t; sourceTree = "<group>"; };
+ FC7A7BF0149866AE0086576A /* README */ = {isa = PBXFileReference; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
+ FC7A7BF1149866AE0086576A /* s1.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = s1.d; sourceTree = "<group>"; };
+ FC7A7BF2149866AE0086576A /* s1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s1.err; sourceTree = "<group>"; };
+ FC7A7BF3149866AE0086576A /* s1.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = s1.r; sourceTree = "<group>"; };
+ FC7A7BF4149866AE0086576A /* s1.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = s1.t; sourceTree = "<group>"; };
+ FC7A7BF5149866AE0086576A /* s10.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s10.err; sourceTree = "<group>"; };
+ FC7A7BF6149866AE0086576A /* s2.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = s2.d; sourceTree = "<group>"; };
+ FC7A7BF7149866AE0086576A /* s2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s2.err; sourceTree = "<group>"; };
+ FC7A7BF8149866AE0086576A /* s2.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = s2.r; sourceTree = "<group>"; };
+ FC7A7BF9149866AE0086576A /* s2.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = s2.t; sourceTree = "<group>"; };
+ FC7A7BFA149866AE0086576A /* s3.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = s3.d; sourceTree = "<group>"; };
+ FC7A7BFB149866AE0086576A /* s3.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s3.err; sourceTree = "<group>"; };
+ FC7A7BFC149866AE0086576A /* s3.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = s3.r; sourceTree = "<group>"; };
+ FC7A7BFD149866AE0086576A /* s3.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = s3.t; sourceTree = "<group>"; };
+ FC7A7BFE149866AE0086576A /* s4.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s4.err; sourceTree = "<group>"; };
+ FC7A7BFF149866AF0086576A /* s5.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s5.err; sourceTree = "<group>"; };
+ FC7A7C00149866AF0086576A /* s6.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s6.err; sourceTree = "<group>"; };
+ FC7A7C01149866AF0086576A /* s7.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s7.err; sourceTree = "<group>"; };
+ FC7A7C02149866AF0086576A /* s8.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s8.err; sourceTree = "<group>"; };
+ FC7A7C03149866AF0086576A /* s9.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = s9.err; sourceTree = "<group>"; };
+ FC7A7C04149866AF0086576A /* t.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = t.d; sourceTree = "<group>"; };
+ FC7A7C05149866AF0086576A /* t.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = t.r; sourceTree = "<group>"; };
+ FC7A7C06149866AF0086576A /* t1.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = t1.d; sourceTree = "<group>"; };
+ FC7A7C07149866AF0086576A /* t1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = t1.err; sourceTree = "<group>"; };
+ FC7A7C08149866AF0086576A /* t1.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = t1.r; sourceTree = "<group>"; };
+ FC7A7C09149866AF0086576A /* t1.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = t1.t; sourceTree = "<group>"; };
+ FC7A7C0A149866AF0086576A /* t2.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = t2.d; sourceTree = "<group>"; };
+ FC7A7C0B149866AF0086576A /* t2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = t2.err; sourceTree = "<group>"; };
+ FC7A7C0C149866AF0086576A /* t2.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = t2.r; sourceTree = "<group>"; };
+ FC7A7C0D149866AF0086576A /* t2.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = t2.t; sourceTree = "<group>"; };
+ FC7A7C0E149866AF0086576A /* TODO */ = {isa = PBXFileReference; lastKnownFileType = text; path = TODO; sourceTree = "<group>"; };
+ FC7A7C0F149866AF0086576A /* u.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = u.d; sourceTree = "<group>"; };
+ FC7A7C10149866AF0086576A /* u.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = u.err; sourceTree = "<group>"; };
+ FC7A7C11149866AF0086576A /* u.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = u.r; sourceTree = "<group>"; };
+ FC7A7C12149866AF0086576A /* u.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = u.t; sourceTree = "<group>"; };
+ FC7A7C13149866AF0086576A /* v.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = v.d; sourceTree = "<group>"; };
+ FC7A7C14149866AF0086576A /* v.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = v.r; sourceTree = "<group>"; };
+ FC7A7C15149866AF0086576A /* v.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = v.t; sourceTree = "<group>"; };
+ FC7A7C16149866AF0086576A /* w.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = w.d; sourceTree = "<group>"; };
+ FC7A7C17149866AF0086576A /* w.r */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.rez; path = w.r; sourceTree = "<group>"; };
+ FC7A7C18149866AF0086576A /* w.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = w.t; sourceTree = "<group>"; };
+ FC7A7C19149866AF0086576A /* w1.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = w1.err; sourceTree = "<group>"; };
+ FC7A7C1A149866AF0086576A /* w2.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = w2.err; sourceTree = "<group>"; };
+ FC7A7C1B149866AF0086576A /* w3.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = w3.err; sourceTree = "<group>"; };
+ FC7A7C1C149866AF0086576A /* x.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = x.err; sourceTree = "<group>"; };
+ FC7A7C1D149866AF0086576A /* z.err */ = {isa = PBXFileReference; lastKnownFileType = text; path = z.err; sourceTree = "<group>"; };
+ FC7A7C1E149866AF0086576A /* undo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = undo.c; sourceTree = "<group>"; };
+ FC7A7C20149866AF0086576A /* expand.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = expand.1; sourceTree = "<group>"; };
+ FC7A7C21149866AF0086576A /* expand.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = expand.c; sourceTree = "<group>"; };
+ FC7A7C24149866AF0086576A /* fmt.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = fmt.1; sourceTree = "<group>"; };
+ FC7A7C25149866AF0086576A /* fmt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fmt.c; sourceTree = "<group>"; };
+ FC7A7C28149866AF0086576A /* fold.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = fold.1; sourceTree = "<group>"; };
+ FC7A7C29149866AF0086576A /* fold.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = fold.c; sourceTree = "<group>"; };
+ FC7A7C2C149866AF0086576A /* head.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = head.1; sourceTree = "<group>"; };
+ FC7A7C2D149866AF0086576A /* head.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = head.c; sourceTree = "<group>"; };
+ FC7A7C30149866AF0086576A /* join.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = join.1; sourceTree = "<group>"; };
+ FC7A7C31149866AF0086576A /* join.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = join.c; sourceTree = "<group>"; };
+ FC7A7C34149866AF0086576A /* lam.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = lam.1; sourceTree = "<group>"; };
+ FC7A7C35149866AF0086576A /* lam.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = lam.c; sourceTree = "<group>"; };
+ FC7A7C38149866AF0086576A /* look.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = look.1; sourceTree = "<group>"; };
+ FC7A7C39149866AF0086576A /* look.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = look.c; sourceTree = "<group>"; };
+ FC7A7C3B149866AF0086576A /* pathnames.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pathnames.h; sourceTree = "<group>"; };
+ FC7A7C3D149866AF0086576A /* commoncrypto.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = commoncrypto.c; sourceTree = "<group>"; };
+ FC7A7C3E149866AF0086576A /* commoncrypto.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = commoncrypto.h; sourceTree = "<group>"; };
+ FC7A7C40149866AF0086576A /* md5.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = md5.1; sourceTree = "<group>"; };
+ FC7A7C41149866AF0086576A /* md5.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = md5.c; sourceTree = "<group>"; };
+ FC7A7C44149866AF0086576A /* nl.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = nl.1; sourceTree = "<group>"; };
+ FC7A7C45149866AF0086576A /* nl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nl.c; sourceTree = "<group>"; };
+ FC7A7C48149866AF0086576A /* paste.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = paste.1; sourceTree = "<group>"; };
+ FC7A7C49149866AF0086576A /* paste.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = paste.c; sourceTree = "<group>"; };
+ FC7A7C4B149866AF0086576A /* egetopt.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = egetopt.c; sourceTree = "<group>"; };
+ FC7A7C4C149866AF0086576A /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FC7A7C4E149866AF0086576A /* pr.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = pr.1; sourceTree = "<group>"; };
+ FC7A7C4F149866AF0086576A /* pr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pr.c; sourceTree = "<group>"; };
+ FC7A7C50149866AF0086576A /* pr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pr.h; sourceTree = "<group>"; };
+ FC7A7C53149866AF0086576A /* rev.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = rev.1; sourceTree = "<group>"; };
+ FC7A7C54149866AF0086576A /* rev.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rev.c; sourceTree = "<group>"; };
+ FC7A7C57149866AF0086576A /* rs.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = rs.1; sourceTree = "<group>"; };
+ FC7A7C58149866AF0086576A /* rs.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = rs.c; sourceTree = "<group>"; };
+ FC7A7C5A149866AF0086576A /* compile.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = compile.c; sourceTree = "<group>"; };
+ FC7A7C5B149866AF0086576A /* defs.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = defs.h; sourceTree = "<group>"; };
+ FC7A7C5C149866AF0086576A /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FC7A7C5D149866AF0086576A /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
+ FC7A7C5F149866AF0086576A /* misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+ FC7A7C60149866AF0086576A /* POSIX */ = {isa = PBXFileReference; lastKnownFileType = text; path = POSIX; sourceTree = "<group>"; };
+ FC7A7C61149866AF0086576A /* process.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = process.c; sourceTree = "<group>"; };
+ FC7A7C62149866AF0086576A /* sed.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = sed.1; sourceTree = "<group>"; };
+ FC7A7C64149866AF0086576A /* hanoi.sed */ = {isa = PBXFileReference; lastKnownFileType = text; path = hanoi.sed; sourceTree = "<group>"; };
+ FC7A7C65149866AF0086576A /* math.sed */ = {isa = PBXFileReference; lastKnownFileType = text; path = math.sed; sourceTree = "<group>"; };
+ FC7A7C66149866AF0086576A /* sed.test */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = sed.test; sourceTree = "<group>"; };
+ FC7A7C93149866AF0086576A /* sort.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = sort.c; sourceTree = "<group>"; };
+ FC7A7CB4149866AF0086576A /* split.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = split.1; sourceTree = "<group>"; };
+ FC7A7CB5149866AF0086576A /* split.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = split.c; sourceTree = "<group>"; };
+ FC7A7CB7149866AF0086576A /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FC7A7CB8149866AF0086576A /* forward.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = forward.c; sourceTree = "<group>"; };
+ FC7A7CBA149866AF0086576A /* misc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = misc.c; sourceTree = "<group>"; };
+ FC7A7CBB149866AF0086576A /* read.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = read.c; sourceTree = "<group>"; };
+ FC7A7CBC149866AF0086576A /* reverse.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = reverse.c; sourceTree = "<group>"; };
+ FC7A7CBD149866AF0086576A /* tail.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = tail.1; sourceTree = "<group>"; };
+ FC7A7CBE149866AF0086576A /* tail.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tail.c; sourceTree = "<group>"; };
+ FC7A7CBF149866AF0086576A /* text_cmds.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = text_cmds.plist; sourceTree = "<group>"; };
+ FC7A7CC1149866AF0086576A /* cmap.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cmap.c; sourceTree = "<group>"; };
+ FC7A7CC2149866AF0086576A /* cmap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cmap.h; sourceTree = "<group>"; };
+ FC7A7CC3149866AF0086576A /* cset.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = cset.c; sourceTree = "<group>"; };
+ FC7A7CC4149866AF0086576A /* cset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cset.h; sourceTree = "<group>"; };
+ FC7A7CC5149866AF0086576A /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FC7A7CC7149866AF0086576A /* str.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = str.c; sourceTree = "<group>"; };
+ FC7A7CC8149866AF0086576A /* tr.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = tr.1; sourceTree = "<group>"; };
+ FC7A7CC9149866AF0086576A /* tr.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = tr.c; sourceTree = "<group>"; };
+ FC7A7CCC149866AF0086576A /* ul.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = ul.1; sourceTree = "<group>"; };
+ FC7A7CCD149866AF0086576A /* ul.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ul.c; sourceTree = "<group>"; };
+ FC7A7CD0149866AF0086576A /* unexpand.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = unexpand.c; sourceTree = "<group>"; };
+ FC7A7CD3149866AF0086576A /* uniq.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = uniq.1; sourceTree = "<group>"; };
+ FC7A7CD4149866AF0086576A /* uniq.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = uniq.c; sourceTree = "<group>"; };
+ FC7A7CD7149866AF0086576A /* unvis.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = unvis.1; sourceTree = "<group>"; };
+ FC7A7CD8149866AF0086576A /* unvis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = unvis.c; sourceTree = "<group>"; };
+ FC7A7CDA149866AF0086576A /* extern.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = extern.h; sourceTree = "<group>"; };
+ FC7A7CDB149866AF0086576A /* foldit.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = foldit.c; sourceTree = "<group>"; };
+ FC7A7CDD149866AF0086576A /* vis.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = vis.1; sourceTree = "<group>"; };
+ FC7A7CDE149866AF0086576A /* vis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = vis.c; sourceTree = "<group>"; };
+ FC7A7CE1149866AF0086576A /* wc.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = wc.1; sourceTree = "<group>"; };
+ FC7A7CE2149866AF0086576A /* wc.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = wc.c; sourceTree = "<group>"; };
+ FC7A7CEA149867ED0086576A /* cat */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cat; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7CF2149869E90086576A /* col */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = col; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7CFA14986A160086576A /* colrm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = colrm; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D0214986A190086576A /* column */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = column; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D0A14986A1B0086576A /* comm */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = comm; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D1214986A1E0086576A /* csplit */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = csplit; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D1A14986A210086576A /* cut */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = cut; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D2214986A230086576A /* ed */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ed; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D2A14986A240086576A /* expand */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = expand; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D3214986A280086576A /* fmt */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fmt; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D3A14986A2B0086576A /* fold */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fold; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D4214986A2F0086576A /* head */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = head; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D4A14986A310086576A /* join */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = join; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D5214986A340086576A /* lam */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lam; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D5A14986A360086576A /* look */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = look; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D6214986A390086576A /* md5 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = md5; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D6A14986A3C0086576A /* nl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = nl; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D7214986A3D0086576A /* paste */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = paste; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D7A14986A400086576A /* pr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pr; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D8214986A410086576A /* rev */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rev; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D8A14986A430086576A /* rs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = rs; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D9214986A450086576A /* sed */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sed; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7D9A14986A470086576A /* sort */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sort; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DA214986A480086576A /* split */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = split; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DAA14986A4A0086576A /* tail */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tail; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DB214986A500086576A /* tr */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = tr; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DBA14986A530086576A /* ul */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ul; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DC214986A540086576A /* unexpand */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unexpand; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DCA14986A560086576A /* uniq */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = uniq; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DD214986A580086576A /* unvis */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unvis; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DDA14986A5A0086576A /* vis */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = vis; sourceTree = BUILT_PRODUCTS_DIR; };
+ FC7A7DE214986A5C0086576A /* wc */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wc; sourceTree = BUILT_PRODUCTS_DIR; };
+ FD2BDC161B7188240053EE6B /* ee.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ee.xcconfig; sourceTree = "<group>"; };
+ FD3561F21B827EE0008A70F6 /* grep */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = grep; sourceTree = BUILT_PRODUCTS_DIR; };
+ FD3561F81B827F9F008A70F6 /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = file.c; sourceTree = "<group>"; };
+ FD3561F91B827F9F008A70F6 /* grep.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = grep.1; sourceTree = "<group>"; };
+ FD3561FA1B827F9F008A70F6 /* grep.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = grep.c; sourceTree = "<group>"; };
+ FD3561FB1B827F9F008A70F6 /* grep.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = grep.h; sourceTree = "<group>"; };
+ FD3561FC1B827F9F008A70F6 /* queue.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = queue.c; sourceTree = "<group>"; };
+ FD3561FD1B827F9F008A70F6 /* util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = util.c; sourceTree = "<group>"; };
+ FD3562031B82803F008A70F6 /* grep.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = grep.xcconfig; sourceTree = "<group>"; };
+ FDA49B8E1B7186CE003B4F3C /* ee */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ee; sourceTree = BUILT_PRODUCTS_DIR; };
+ FDA49B941B718738003B4F3C /* ee.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ee.c; sourceTree = "<group>"; };
+ FDA49B961B718762003B4F3C /* ee.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = ee.1; sourceTree = "<group>"; };
+ FDF283571DAED0C000CF8C36 /* bwstring.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = bwstring.c; sourceTree = "<group>"; };
+ FDF283581DAED0C000CF8C36 /* bwstring.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bwstring.h; sourceTree = "<group>"; };
+ FDF283591DAED0C000CF8C36 /* coll.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = coll.c; sourceTree = "<group>"; };
+ FDF2835A1DAED0C000CF8C36 /* coll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coll.h; sourceTree = "<group>"; };
+ FDF2835B1DAED0C000CF8C36 /* file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = file.c; sourceTree = "<group>"; };
+ FDF2835C1DAED0C000CF8C36 /* file.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = file.h; sourceTree = "<group>"; };
+ FDF2835D1DAED0C000CF8C36 /* mem.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mem.c; sourceTree = "<group>"; };
+ FDF2835E1DAED0C000CF8C36 /* mem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mem.h; sourceTree = "<group>"; };
+ FDF283601DAED0C000CF8C36 /* C.msg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = C.msg; sourceTree = "<group>"; };
+ FDF283611DAED0C000CF8C36 /* hu_HU.ISO8859-2.msg */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "hu_HU.ISO8859-2.msg"; sourceTree = "<group>"; };
+ FDF283621DAED0C000CF8C36 /* radixsort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = radixsort.c; sourceTree = "<group>"; };
+ FDF283631DAED0C000CF8C36 /* radixsort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = radixsort.h; sourceTree = "<group>"; };
+ FDF283641DAED0C000CF8C36 /* sort.1.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = sort.1.in; sourceTree = "<group>"; };
+ FDF283651DAED0C000CF8C36 /* sort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sort.h; sourceTree = "<group>"; };
+ FDF283661DAED0C000CF8C36 /* vsort.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vsort.c; sourceTree = "<group>"; };
+ FDF283671DAED0C000CF8C36 /* vsort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vsort.h; sourceTree = "<group>"; };
+ FDF2836E1DAED24800CF8C36 /* sort.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = sort.xcconfig; sourceTree = "<group>"; };
+ FDF2836F1DAED7C700CF8C36 /* commoncrypto.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = commoncrypto.c; sourceTree = "<group>"; };
+ FDF283701DAED7C700CF8C36 /* commoncrypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = commoncrypto.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ FC7A7B36149865C80086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7CE6149867ED0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7CEE149869E90086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7CF614986A160086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7CFE14986A190086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D0614986A1B0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D0E14986A1E0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D1614986A210086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D1E14986A230086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D2614986A240086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D2E14986A280086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D3614986A2B0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D3E14986A2F0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D4614986A310086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D4E14986A340086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D5614986A360086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D5E14986A390086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D6614986A3C0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D6E14986A3D0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D7614986A400086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D7E14986A410086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D8614986A430086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D8E14986A450086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D9614986A470086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D9E14986A480086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DA614986A4A0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DAE14986A500086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DB614986A530086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC6C98FC149A94EB00DDCC47 /* libcurses.dylib in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DBE14986A540086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DC614986A560086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DCE14986A580086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DD614986A5A0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DDE14986A5C0086576A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD3561EF1B827EE0008A70F6 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA49B8B1B7186CE003B4F3C /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ FC7A7B2E149865C70086576A = {
+ isa = PBXGroup;
+ children = (
+ 3EF506E11F7ABD7500421EB3 /* tests */,
+ FC7A7B4A149866AE0086576A /* banner */,
+ FC7A7B4E149866AE0086576A /* cat */,
+ FC7A7B52149866AE0086576A /* col */,
+ FC7A7B57149866AE0086576A /* colrm */,
+ FC7A7B5B149866AE0086576A /* column */,
+ FC7A7B5F149866AE0086576A /* comm */,
+ FC7A7B63149866AE0086576A /* csplit */,
+ FC7A7B67149866AE0086576A /* cut */,
+ FC7A7B6B149866AE0086576A /* ed */,
+ FDA49B8F1B7186CE003B4F3C /* ee */,
+ FC7A7C1F149866AF0086576A /* expand */,
+ FC7A7C23149866AF0086576A /* fmt */,
+ FC7A7C27149866AF0086576A /* fold */,
+ FD3561F31B827EE0008A70F6 /* grep */,
+ FC7A7C2B149866AF0086576A /* head */,
+ FC7A7C2F149866AF0086576A /* join */,
+ FC7A7C33149866AF0086576A /* lam */,
+ FC7A7C37149866AF0086576A /* look */,
+ FC7A7C3C149866AF0086576A /* md5 */,
+ FC7A7C42149866AF0086576A /* nl */,
+ FC7A7C46149866AF0086576A /* paste */,
+ FC7A7C4A149866AF0086576A /* pr */,
+ FC7A7C51149866AF0086576A /* rev */,
+ FC7A7C55149866AF0086576A /* rs */,
+ FC7A7C59149866AF0086576A /* sed */,
+ FC7A7C67149866AF0086576A /* sort */,
+ FC7A7CB2149866AF0086576A /* split */,
+ FC7A7CB6149866AF0086576A /* tail */,
+ FC7A7CBF149866AF0086576A /* text_cmds.plist */,
+ FC7A7CC0149866AF0086576A /* tr */,
+ FC7A7CCA149866AF0086576A /* ul */,
+ FC7A7CCE149866AF0086576A /* unexpand */,
+ FC7A7CD1149866AF0086576A /* uniq */,
+ FC7A7CD5149866AF0086576A /* unvis */,
+ FC7A7CD9149866AF0086576A /* vis */,
+ FC7A7CDF149866AF0086576A /* wc */,
+ FD2BDC151B7188240053EE6B /* xcconfigs */,
+ FC7A7B3A149865C80086576A /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ FC7A7B3A149865C80086576A /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B39149865C80086576A /* banner */,
+ FC7A7CEA149867ED0086576A /* cat */,
+ FC7A7CF2149869E90086576A /* col */,
+ FC7A7CFA14986A160086576A /* colrm */,
+ FC7A7D0214986A190086576A /* column */,
+ FC7A7D0A14986A1B0086576A /* comm */,
+ FC7A7D1214986A1E0086576A /* csplit */,
+ FC7A7D1A14986A210086576A /* cut */,
+ FC7A7D2214986A230086576A /* ed */,
+ FDA49B8E1B7186CE003B4F3C /* ee */,
+ FC7A7D2A14986A240086576A /* expand */,
+ FC7A7D3214986A280086576A /* fmt */,
+ FC7A7D3A14986A2B0086576A /* fold */,
+ FD3561F21B827EE0008A70F6 /* grep */,
+ FC7A7D4214986A2F0086576A /* head */,
+ FC7A7D4A14986A310086576A /* join */,
+ FC7A7D5214986A340086576A /* lam */,
+ FC7A7D5A14986A360086576A /* look */,
+ FC7A7D6214986A390086576A /* md5 */,
+ FC7A7D6A14986A3C0086576A /* nl */,
+ FC7A7D7214986A3D0086576A /* paste */,
+ FC7A7D7A14986A400086576A /* pr */,
+ FC7A7D8214986A410086576A /* rev */,
+ FC7A7D8A14986A430086576A /* rs */,
+ FC7A7D9214986A450086576A /* sed */,
+ FC7A7D9A14986A470086576A /* sort */,
+ FC7A7DA214986A480086576A /* split */,
+ FC7A7DAA14986A4A0086576A /* tail */,
+ FC7A7DB214986A500086576A /* tr */,
+ FC7A7DBA14986A530086576A /* ul */,
+ FC7A7DC214986A540086576A /* unexpand */,
+ FC7A7DCA14986A560086576A /* uniq */,
+ FC7A7DD214986A580086576A /* unvis */,
+ FC7A7DDA14986A5A0086576A /* vis */,
+ FC7A7DE214986A5C0086576A /* wc */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FC7A7B4A149866AE0086576A /* banner */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B4B149866AE0086576A /* banner.6 */,
+ FC7A7B4C149866AE0086576A /* banner.c */,
+ );
+ path = banner;
+ sourceTree = "<group>";
+ };
+ FC7A7B4E149866AE0086576A /* cat */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B4F149866AE0086576A /* cat.1 */,
+ FC7A7B50149866AE0086576A /* cat.c */,
+ );
+ path = cat;
+ sourceTree = "<group>";
+ };
+ FC7A7B52149866AE0086576A /* col */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B53149866AE0086576A /* col.1 */,
+ FC7A7B54149866AE0086576A /* col.c */,
+ FC7A7B56149866AE0086576A /* README */,
+ );
+ path = col;
+ sourceTree = "<group>";
+ };
+ FC7A7B57149866AE0086576A /* colrm */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B58149866AE0086576A /* colrm.1 */,
+ FC7A7B59149866AE0086576A /* colrm.c */,
+ );
+ path = colrm;
+ sourceTree = "<group>";
+ };
+ FC7A7B5B149866AE0086576A /* column */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B5C149866AE0086576A /* column.1 */,
+ FC7A7B5D149866AE0086576A /* column.c */,
+ );
+ path = column;
+ sourceTree = "<group>";
+ };
+ FC7A7B5F149866AE0086576A /* comm */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B60149866AE0086576A /* comm.1 */,
+ FC7A7B61149866AE0086576A /* comm.c */,
+ );
+ path = comm;
+ sourceTree = "<group>";
+ };
+ FC7A7B63149866AE0086576A /* csplit */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B64149866AE0086576A /* csplit.1 */,
+ FC7A7B65149866AE0086576A /* csplit.c */,
+ );
+ path = csplit;
+ sourceTree = "<group>";
+ };
+ FC7A7B67149866AE0086576A /* cut */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B68149866AE0086576A /* cut.1 */,
+ FC7A7B69149866AE0086576A /* cut.c */,
+ );
+ path = cut;
+ sourceTree = "<group>";
+ };
+ FC7A7B6B149866AE0086576A /* ed */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B6C149866AE0086576A /* buf.c */,
+ FC7A7B6D149866AE0086576A /* cbc.c */,
+ FC7A7B6E149866AE0086576A /* ed.1 */,
+ FC7A7B6F149866AE0086576A /* ed.h */,
+ FC7A7B70149866AE0086576A /* glbl.c */,
+ FC7A7B71149866AE0086576A /* io.c */,
+ FC7A7B72149866AE0086576A /* main.c */,
+ FC7A7B74149866AE0086576A /* POSIX */,
+ FC7A7B75149866AE0086576A /* re.c */,
+ FC7A7B76149866AE0086576A /* README */,
+ FC7A7B77149866AE0086576A /* red.1 */,
+ FC7A7B78149866AE0086576A /* sub.c */,
+ FC7A7B79149866AE0086576A /* test */,
+ FC7A7C1E149866AF0086576A /* undo.c */,
+ );
+ path = ed;
+ sourceTree = "<group>";
+ };
+ FC7A7B79149866AE0086576A /* test */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7B7A149866AE0086576A /* =.err */,
+ FC7A7B7B149866AE0086576A /* a.d */,
+ FC7A7B7C149866AE0086576A /* a.r */,
+ FC7A7B7D149866AE0086576A /* a.t */,
+ FC7A7B7E149866AE0086576A /* a1.err */,
+ FC7A7B7F149866AE0086576A /* a2.err */,
+ FC7A7B80149866AE0086576A /* addr.d */,
+ FC7A7B81149866AE0086576A /* addr.r */,
+ FC7A7B82149866AE0086576A /* addr.t */,
+ FC7A7B83149866AE0086576A /* addr1.err */,
+ FC7A7B84149866AE0086576A /* addr2.err */,
+ FC7A7B85149866AE0086576A /* ascii.d.uu */,
+ FC7A7B86149866AE0086576A /* ascii.r.uu */,
+ FC7A7B87149866AE0086576A /* ascii.t */,
+ FC7A7B88149866AE0086576A /* bang1.d */,
+ FC7A7B89149866AE0086576A /* bang1.err */,
+ FC7A7B8A149866AE0086576A /* bang1.r */,
+ FC7A7B8B149866AE0086576A /* bang1.t */,
+ FC7A7B8C149866AE0086576A /* bang2.err */,
+ FC7A7B8D149866AE0086576A /* c.d */,
+ FC7A7B8E149866AE0086576A /* c.r */,
+ FC7A7B8F149866AE0086576A /* c.t */,
+ FC7A7B90149866AE0086576A /* c1.err */,
+ FC7A7B91149866AE0086576A /* c2.err */,
+ FC7A7B92149866AE0086576A /* ckscripts.sh */,
+ FC7A7B93149866AE0086576A /* d.d */,
+ FC7A7B94149866AE0086576A /* d.err */,
+ FC7A7B95149866AE0086576A /* d.r */,
+ FC7A7B96149866AE0086576A /* d.t */,
+ FC7A7B97149866AE0086576A /* e1.d */,
+ FC7A7B98149866AE0086576A /* e1.err */,
+ FC7A7B99149866AE0086576A /* e1.r */,
+ FC7A7B9A149866AE0086576A /* e1.t */,
+ FC7A7B9B149866AE0086576A /* e2.d */,
+ FC7A7B9C149866AE0086576A /* e2.err */,
+ FC7A7B9D149866AE0086576A /* e2.r */,
+ FC7A7B9E149866AE0086576A /* e2.t */,
+ FC7A7B9F149866AE0086576A /* e3.d */,
+ FC7A7BA0149866AE0086576A /* e3.err */,
+ FC7A7BA1149866AE0086576A /* e3.r */,
+ FC7A7BA2149866AE0086576A /* e3.t */,
+ FC7A7BA3149866AE0086576A /* e4.d */,
+ FC7A7BA4149866AE0086576A /* e4.r */,
+ FC7A7BA5149866AE0086576A /* e4.t */,
+ FC7A7BA6149866AE0086576A /* f1.err */,
+ FC7A7BA7149866AE0086576A /* f2.err */,
+ FC7A7BA8149866AE0086576A /* g1.d */,
+ FC7A7BA9149866AE0086576A /* g1.err */,
+ FC7A7BAA149866AE0086576A /* g1.r */,
+ FC7A7BAB149866AE0086576A /* g1.t */,
+ FC7A7BAC149866AE0086576A /* g2.d */,
+ FC7A7BAD149866AE0086576A /* g2.err */,
+ FC7A7BAE149866AE0086576A /* g2.r */,
+ FC7A7BAF149866AE0086576A /* g2.t */,
+ FC7A7BB0149866AE0086576A /* g3.d */,
+ FC7A7BB1149866AE0086576A /* g3.err */,
+ FC7A7BB2149866AE0086576A /* g3.r */,
+ FC7A7BB3149866AE0086576A /* g3.t */,
+ FC7A7BB4149866AE0086576A /* g4.d */,
+ FC7A7BB5149866AE0086576A /* g4.r */,
+ FC7A7BB6149866AE0086576A /* g4.t */,
+ FC7A7BB7149866AE0086576A /* g5.d */,
+ FC7A7BB8149866AE0086576A /* g5.r */,
+ FC7A7BB9149866AE0086576A /* g5.t */,
+ FC7A7BBA149866AE0086576A /* h.err */,
+ FC7A7BBB149866AE0086576A /* i.d */,
+ FC7A7BBC149866AE0086576A /* i.r */,
+ FC7A7BBD149866AE0086576A /* i.t */,
+ FC7A7BBE149866AE0086576A /* i1.err */,
+ FC7A7BBF149866AE0086576A /* i2.err */,
+ FC7A7BC0149866AE0086576A /* i3.err */,
+ FC7A7BC1149866AE0086576A /* j.d */,
+ FC7A7BC2149866AE0086576A /* j.r */,
+ FC7A7BC3149866AE0086576A /* j.t */,
+ FC7A7BC4149866AE0086576A /* k.d */,
+ FC7A7BC5149866AE0086576A /* k.r */,
+ FC7A7BC6149866AE0086576A /* k.t */,
+ FC7A7BC7149866AE0086576A /* k1.err */,
+ FC7A7BC8149866AE0086576A /* k2.err */,
+ FC7A7BC9149866AE0086576A /* k3.err */,
+ FC7A7BCA149866AE0086576A /* k4.err */,
+ FC7A7BCB149866AE0086576A /* l.d */,
+ FC7A7BCC149866AE0086576A /* l.r */,
+ FC7A7BCD149866AE0086576A /* l.t */,
+ FC7A7BCE149866AE0086576A /* m.d */,
+ FC7A7BCF149866AE0086576A /* m.err */,
+ FC7A7BD0149866AE0086576A /* m.r */,
+ FC7A7BD1149866AE0086576A /* m.t */,
+ FC7A7BD2149866AE0086576A /* Makefile */,
+ FC7A7BD3149866AE0086576A /* mkscripts.sh */,
+ FC7A7BD4149866AE0086576A /* n.d */,
+ FC7A7BD5149866AE0086576A /* n.r */,
+ FC7A7BD6149866AE0086576A /* n.t */,
+ FC7A7BD7149866AE0086576A /* nl.err */,
+ FC7A7BD8149866AE0086576A /* nl1.d */,
+ FC7A7BD9149866AE0086576A /* nl1.r */,
+ FC7A7BDA149866AE0086576A /* nl1.t */,
+ FC7A7BDB149866AE0086576A /* nl2.d */,
+ FC7A7BDC149866AE0086576A /* nl2.r */,
+ FC7A7BDD149866AE0086576A /* nl2.t */,
+ FC7A7BDE149866AE0086576A /* p.d */,
+ FC7A7BDF149866AE0086576A /* p.r */,
+ FC7A7BE0149866AE0086576A /* p.t */,
+ FC7A7BE1149866AE0086576A /* q.d */,
+ FC7A7BE2149866AE0086576A /* q.r */,
+ FC7A7BE3149866AE0086576A /* q.t */,
+ FC7A7BE4149866AE0086576A /* q1.err */,
+ FC7A7BE5149866AE0086576A /* r1.d */,
+ FC7A7BE6149866AE0086576A /* r1.err */,
+ FC7A7BE7149866AE0086576A /* r1.r */,
+ FC7A7BE8149866AE0086576A /* r1.t */,
+ FC7A7BE9149866AE0086576A /* r2.d */,
+ FC7A7BEA149866AE0086576A /* r2.err */,
+ FC7A7BEB149866AE0086576A /* r2.r */,
+ FC7A7BEC149866AE0086576A /* r2.t */,
+ FC7A7BED149866AE0086576A /* r3.d */,
+ FC7A7BEE149866AE0086576A /* r3.r */,
+ FC7A7BEF149866AE0086576A /* r3.t */,
+ FC7A7BF0149866AE0086576A /* README */,
+ FC7A7BF1149866AE0086576A /* s1.d */,
+ FC7A7BF2149866AE0086576A /* s1.err */,
+ FC7A7BF3149866AE0086576A /* s1.r */,
+ FC7A7BF4149866AE0086576A /* s1.t */,
+ FC7A7BF5149866AE0086576A /* s10.err */,
+ FC7A7BF6149866AE0086576A /* s2.d */,
+ FC7A7BF7149866AE0086576A /* s2.err */,
+ FC7A7BF8149866AE0086576A /* s2.r */,
+ FC7A7BF9149866AE0086576A /* s2.t */,
+ FC7A7BFA149866AE0086576A /* s3.d */,
+ FC7A7BFB149866AE0086576A /* s3.err */,
+ FC7A7BFC149866AE0086576A /* s3.r */,
+ FC7A7BFD149866AE0086576A /* s3.t */,
+ FC7A7BFE149866AE0086576A /* s4.err */,
+ FC7A7BFF149866AF0086576A /* s5.err */,
+ FC7A7C00149866AF0086576A /* s6.err */,
+ FC7A7C01149866AF0086576A /* s7.err */,
+ FC7A7C02149866AF0086576A /* s8.err */,
+ FC7A7C03149866AF0086576A /* s9.err */,
+ FC7A7C04149866AF0086576A /* t.d */,
+ FC7A7C05149866AF0086576A /* t.r */,
+ FC7A7C06149866AF0086576A /* t1.d */,
+ FC7A7C07149866AF0086576A /* t1.err */,
+ FC7A7C08149866AF0086576A /* t1.r */,
+ FC7A7C09149866AF0086576A /* t1.t */,
+ FC7A7C0A149866AF0086576A /* t2.d */,
+ FC7A7C0B149866AF0086576A /* t2.err */,
+ FC7A7C0C149866AF0086576A /* t2.r */,
+ FC7A7C0D149866AF0086576A /* t2.t */,
+ FC7A7C0E149866AF0086576A /* TODO */,
+ FC7A7C0F149866AF0086576A /* u.d */,
+ FC7A7C10149866AF0086576A /* u.err */,
+ FC7A7C11149866AF0086576A /* u.r */,
+ FC7A7C12149866AF0086576A /* u.t */,
+ FC7A7C13149866AF0086576A /* v.d */,
+ FC7A7C14149866AF0086576A /* v.r */,
+ FC7A7C15149866AF0086576A /* v.t */,
+ FC7A7C16149866AF0086576A /* w.d */,
+ FC7A7C17149866AF0086576A /* w.r */,
+ FC7A7C18149866AF0086576A /* w.t */,
+ FC7A7C19149866AF0086576A /* w1.err */,
+ FC7A7C1A149866AF0086576A /* w2.err */,
+ FC7A7C1B149866AF0086576A /* w3.err */,
+ FC7A7C1C149866AF0086576A /* x.err */,
+ FC7A7C1D149866AF0086576A /* z.err */,
+ );
+ path = test;
+ sourceTree = "<group>";
+ };
+ FC7A7C1F149866AF0086576A /* expand */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C20149866AF0086576A /* expand.1 */,
+ FC7A7C21149866AF0086576A /* expand.c */,
+ );
+ path = expand;
+ sourceTree = "<group>";
+ };
+ FC7A7C23149866AF0086576A /* fmt */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C24149866AF0086576A /* fmt.1 */,
+ FC7A7C25149866AF0086576A /* fmt.c */,
+ );
+ path = fmt;
+ sourceTree = "<group>";
+ };
+ FC7A7C27149866AF0086576A /* fold */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C28149866AF0086576A /* fold.1 */,
+ FC7A7C29149866AF0086576A /* fold.c */,
+ );
+ path = fold;
+ sourceTree = "<group>";
+ };
+ FC7A7C2B149866AF0086576A /* head */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C2C149866AF0086576A /* head.1 */,
+ FC7A7C2D149866AF0086576A /* head.c */,
+ );
+ path = head;
+ sourceTree = "<group>";
+ };
+ FC7A7C2F149866AF0086576A /* join */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C30149866AF0086576A /* join.1 */,
+ FC7A7C31149866AF0086576A /* join.c */,
+ );
+ path = join;
+ sourceTree = "<group>";
+ };
+ FC7A7C33149866AF0086576A /* lam */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C34149866AF0086576A /* lam.1 */,
+ FC7A7C35149866AF0086576A /* lam.c */,
+ );
+ path = lam;
+ sourceTree = "<group>";
+ };
+ FC7A7C37149866AF0086576A /* look */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C38149866AF0086576A /* look.1 */,
+ FC7A7C39149866AF0086576A /* look.c */,
+ FC7A7C3B149866AF0086576A /* pathnames.h */,
+ );
+ path = look;
+ sourceTree = "<group>";
+ };
+ FC7A7C3C149866AF0086576A /* md5 */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C3D149866AF0086576A /* commoncrypto.c */,
+ FC7A7C3E149866AF0086576A /* commoncrypto.h */,
+ FC7A7C40149866AF0086576A /* md5.1 */,
+ FC7A7C41149866AF0086576A /* md5.c */,
+ );
+ path = md5;
+ sourceTree = "<group>";
+ };
+ FC7A7C42149866AF0086576A /* nl */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C44149866AF0086576A /* nl.1 */,
+ FC7A7C45149866AF0086576A /* nl.c */,
+ );
+ path = nl;
+ sourceTree = "<group>";
+ };
+ FC7A7C46149866AF0086576A /* paste */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C48149866AF0086576A /* paste.1 */,
+ FC7A7C49149866AF0086576A /* paste.c */,
+ );
+ path = paste;
+ sourceTree = "<group>";
+ };
+ FC7A7C4A149866AF0086576A /* pr */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C4B149866AF0086576A /* egetopt.c */,
+ FC7A7C4C149866AF0086576A /* extern.h */,
+ FC7A7C4E149866AF0086576A /* pr.1 */,
+ FC7A7C4F149866AF0086576A /* pr.c */,
+ FC7A7C50149866AF0086576A /* pr.h */,
+ );
+ path = pr;
+ sourceTree = "<group>";
+ };
+ FC7A7C51149866AF0086576A /* rev */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C53149866AF0086576A /* rev.1 */,
+ FC7A7C54149866AF0086576A /* rev.c */,
+ );
+ path = rev;
+ sourceTree = "<group>";
+ };
+ FC7A7C55149866AF0086576A /* rs */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C57149866AF0086576A /* rs.1 */,
+ FC7A7C58149866AF0086576A /* rs.c */,
+ );
+ path = rs;
+ sourceTree = "<group>";
+ };
+ FC7A7C59149866AF0086576A /* sed */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C5A149866AF0086576A /* compile.c */,
+ FC7A7C5B149866AF0086576A /* defs.h */,
+ FC7A7C5C149866AF0086576A /* extern.h */,
+ FC7A7C5D149866AF0086576A /* main.c */,
+ FC7A7C5F149866AF0086576A /* misc.c */,
+ FC7A7C60149866AF0086576A /* POSIX */,
+ FC7A7C61149866AF0086576A /* process.c */,
+ FC7A7C62149866AF0086576A /* sed.1 */,
+ FC7A7C63149866AF0086576A /* TEST */,
+ );
+ path = sed;
+ sourceTree = "<group>";
+ };
+ FC7A7C63149866AF0086576A /* TEST */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7C64149866AF0086576A /* hanoi.sed */,
+ FC7A7C65149866AF0086576A /* math.sed */,
+ FC7A7C66149866AF0086576A /* sed.test */,
+ );
+ path = TEST;
+ sourceTree = "<group>";
+ };
+ FC7A7C67149866AF0086576A /* sort */ = {
+ isa = PBXGroup;
+ children = (
+ FDF283571DAED0C000CF8C36 /* bwstring.c */,
+ FDF283581DAED0C000CF8C36 /* bwstring.h */,
+ FDF283591DAED0C000CF8C36 /* coll.c */,
+ FDF2835A1DAED0C000CF8C36 /* coll.h */,
+ FDF2836F1DAED7C700CF8C36 /* commoncrypto.c */,
+ FDF283701DAED7C700CF8C36 /* commoncrypto.h */,
+ FDF2835B1DAED0C000CF8C36 /* file.c */,
+ FDF2835C1DAED0C000CF8C36 /* file.h */,
+ FDF2835D1DAED0C000CF8C36 /* mem.c */,
+ FDF2835E1DAED0C000CF8C36 /* mem.h */,
+ FDF2835F1DAED0C000CF8C36 /* nls */,
+ FDF283621DAED0C000CF8C36 /* radixsort.c */,
+ FDF283631DAED0C000CF8C36 /* radixsort.h */,
+ FDF283641DAED0C000CF8C36 /* sort.1.in */,
+ FC7A7C93149866AF0086576A /* sort.c */,
+ FDF283651DAED0C000CF8C36 /* sort.h */,
+ FDF283661DAED0C000CF8C36 /* vsort.c */,
+ FDF283671DAED0C000CF8C36 /* vsort.h */,
+ );
+ path = sort;
+ sourceTree = "<group>";
+ };
+ FC7A7CB2149866AF0086576A /* split */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CB4149866AF0086576A /* split.1 */,
+ FC7A7CB5149866AF0086576A /* split.c */,
+ );
+ path = split;
+ sourceTree = "<group>";
+ };
+ FC7A7CB6149866AF0086576A /* tail */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CB7149866AF0086576A /* extern.h */,
+ FC7A7CB8149866AF0086576A /* forward.c */,
+ FC7A7CBA149866AF0086576A /* misc.c */,
+ FC7A7CBB149866AF0086576A /* read.c */,
+ FC7A7CBC149866AF0086576A /* reverse.c */,
+ FC7A7CBD149866AF0086576A /* tail.1 */,
+ FC7A7CBE149866AF0086576A /* tail.c */,
+ );
+ path = tail;
+ sourceTree = "<group>";
+ };
+ FC7A7CC0149866AF0086576A /* tr */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CC1149866AF0086576A /* cmap.c */,
+ FC7A7CC2149866AF0086576A /* cmap.h */,
+ FC7A7CC3149866AF0086576A /* cset.c */,
+ FC7A7CC4149866AF0086576A /* cset.h */,
+ FC7A7CC5149866AF0086576A /* extern.h */,
+ FC7A7CC7149866AF0086576A /* str.c */,
+ FC7A7CC8149866AF0086576A /* tr.1 */,
+ FC7A7CC9149866AF0086576A /* tr.c */,
+ );
+ path = tr;
+ sourceTree = "<group>";
+ };
+ FC7A7CCA149866AF0086576A /* ul */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CCC149866AF0086576A /* ul.1 */,
+ FC7A7CCD149866AF0086576A /* ul.c */,
+ FC6C98FB149A94EB00DDCC47 /* libcurses.dylib */,
+ );
+ path = ul;
+ sourceTree = "<group>";
+ };
+ FC7A7CCE149866AF0086576A /* unexpand */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CD0149866AF0086576A /* unexpand.c */,
+ );
+ path = unexpand;
+ sourceTree = "<group>";
+ };
+ FC7A7CD1149866AF0086576A /* uniq */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CD3149866AF0086576A /* uniq.1 */,
+ FC7A7CD4149866AF0086576A /* uniq.c */,
+ );
+ path = uniq;
+ sourceTree = "<group>";
+ };
+ FC7A7CD5149866AF0086576A /* unvis */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CD7149866AF0086576A /* unvis.1 */,
+ FC7A7CD8149866AF0086576A /* unvis.c */,
+ );
+ path = unvis;
+ sourceTree = "<group>";
+ };
+ FC7A7CD9149866AF0086576A /* vis */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CDA149866AF0086576A /* extern.h */,
+ FC7A7CDB149866AF0086576A /* foldit.c */,
+ FC7A7CDD149866AF0086576A /* vis.1 */,
+ FC7A7CDE149866AF0086576A /* vis.c */,
+ );
+ path = vis;
+ sourceTree = "<group>";
+ };
+ FC7A7CDF149866AF0086576A /* wc */ = {
+ isa = PBXGroup;
+ children = (
+ FC7A7CE1149866AF0086576A /* wc.1 */,
+ FC7A7CE2149866AF0086576A /* wc.c */,
+ );
+ path = wc;
+ sourceTree = "<group>";
+ };
+ FD2BDC151B7188240053EE6B /* xcconfigs */ = {
+ isa = PBXGroup;
+ children = (
+ FD2BDC161B7188240053EE6B /* ee.xcconfig */,
+ FD3562031B82803F008A70F6 /* grep.xcconfig */,
+ FDF2836E1DAED24800CF8C36 /* sort.xcconfig */,
+ );
+ path = xcconfigs;
+ sourceTree = "<group>";
+ };
+ FD3561F31B827EE0008A70F6 /* grep */ = {
+ isa = PBXGroup;
+ children = (
+ FD3561F81B827F9F008A70F6 /* file.c */,
+ FD3561F91B827F9F008A70F6 /* grep.1 */,
+ FD3561FA1B827F9F008A70F6 /* grep.c */,
+ FD3561FB1B827F9F008A70F6 /* grep.h */,
+ FD3561FC1B827F9F008A70F6 /* queue.c */,
+ FD3561FD1B827F9F008A70F6 /* util.c */,
+ );
+ path = grep;
+ sourceTree = "<group>";
+ };
+ FDA49B8F1B7186CE003B4F3C /* ee */ = {
+ isa = PBXGroup;
+ children = (
+ FDA49B961B718762003B4F3C /* ee.1 */,
+ FDA49B941B718738003B4F3C /* ee.c */,
+ );
+ path = ee;
+ sourceTree = "<group>";
+ };
+ FDF2835F1DAED0C000CF8C36 /* nls */ = {
+ isa = PBXGroup;
+ children = (
+ FDF283601DAED0C000CF8C36 /* C.msg */,
+ FDF283611DAED0C000CF8C36 /* hu_HU.ISO8859-2.msg */,
+ );
+ path = nls;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXLegacyTarget section */
+ 3EF506E21F7ABE4D00421EB3 /* tests */ = {
+ isa = PBXLegacyTarget;
+ buildArgumentsString = "$(ACTION)";
+ buildConfigurationList = 3EF506E31F7ABE4D00421EB3 /* Build configuration list for PBXLegacyTarget "tests" */;
+ buildPhases = (
+ );
+ buildToolPath = /usr/bin/make;
+ buildWorkingDirectory = tests;
+ dependencies = (
+ );
+ name = tests;
+ passBuildSettingsInEnvironment = 1;
+ productName = tests;
+ };
+/* End PBXLegacyTarget section */
+
+/* Begin PBXNativeTarget section */
+ FC7A7B38149865C80086576A /* banner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7B43149865C80086576A /* Build configuration list for PBXNativeTarget "banner" */;
+ buildPhases = (
+ FC7A7B35149865C80086576A /* Sources */,
+ FC7A7B36149865C80086576A /* Frameworks */,
+ FC7A7B37149865C80086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = banner;
+ productName = text_cmds;
+ productReference = FC7A7B39149865C80086576A /* banner */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7CE4149867ED0086576A /* cat */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7CE8149867ED0086576A /* Build configuration list for PBXNativeTarget "cat" */;
+ buildPhases = (
+ FC7A7CE5149867ED0086576A /* Sources */,
+ FC7A7CE6149867ED0086576A /* Frameworks */,
+ FC7A7CE7149867ED0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cat;
+ productName = text_cmds;
+ productReference = FC7A7CEA149867ED0086576A /* cat */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7CEC149869E90086576A /* col */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7CF0149869E90086576A /* Build configuration list for PBXNativeTarget "col" */;
+ buildPhases = (
+ FC7A7CED149869E90086576A /* Sources */,
+ FC7A7CEE149869E90086576A /* Frameworks */,
+ FC7A7CEF149869E90086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = col;
+ productName = text_cmds;
+ productReference = FC7A7CF2149869E90086576A /* col */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7CF414986A160086576A /* colrm */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7CF814986A160086576A /* Build configuration list for PBXNativeTarget "colrm" */;
+ buildPhases = (
+ FC7A7CF514986A160086576A /* Sources */,
+ FC7A7CF614986A160086576A /* Frameworks */,
+ FC7A7CF714986A160086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = colrm;
+ productName = text_cmds;
+ productReference = FC7A7CFA14986A160086576A /* colrm */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7CFC14986A190086576A /* column */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D0014986A190086576A /* Build configuration list for PBXNativeTarget "column" */;
+ buildPhases = (
+ FC7A7CFD14986A190086576A /* Sources */,
+ FC7A7CFE14986A190086576A /* Frameworks */,
+ FC7A7CFF14986A190086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = column;
+ productName = text_cmds;
+ productReference = FC7A7D0214986A190086576A /* column */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D0414986A1B0086576A /* comm */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D0814986A1B0086576A /* Build configuration list for PBXNativeTarget "comm" */;
+ buildPhases = (
+ FC7A7D0514986A1B0086576A /* Sources */,
+ FC7A7D0614986A1B0086576A /* Frameworks */,
+ FC7A7D0714986A1B0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = comm;
+ productName = text_cmds;
+ productReference = FC7A7D0A14986A1B0086576A /* comm */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D0C14986A1E0086576A /* csplit */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D1014986A1E0086576A /* Build configuration list for PBXNativeTarget "csplit" */;
+ buildPhases = (
+ FC7A7D0D14986A1E0086576A /* Sources */,
+ FC7A7D0E14986A1E0086576A /* Frameworks */,
+ FC7A7D0F14986A1E0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = csplit;
+ productName = text_cmds;
+ productReference = FC7A7D1214986A1E0086576A /* csplit */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D1414986A210086576A /* cut */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D1814986A210086576A /* Build configuration list for PBXNativeTarget "cut" */;
+ buildPhases = (
+ FC7A7D1514986A210086576A /* Sources */,
+ FC7A7D1614986A210086576A /* Frameworks */,
+ FC7A7D1714986A210086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = cut;
+ productName = text_cmds;
+ productReference = FC7A7D1A14986A210086576A /* cut */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D1C14986A230086576A /* ed */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D2014986A230086576A /* Build configuration list for PBXNativeTarget "ed" */;
+ buildPhases = (
+ FC7A7D1D14986A230086576A /* Sources */,
+ FC7A7D1E14986A230086576A /* Frameworks */,
+ FC7A7D1F14986A230086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ed;
+ productName = text_cmds;
+ productReference = FC7A7D2214986A230086576A /* ed */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D2414986A240086576A /* expand */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D2814986A240086576A /* Build configuration list for PBXNativeTarget "expand" */;
+ buildPhases = (
+ FC7A7D2514986A240086576A /* Sources */,
+ FC7A7D2614986A240086576A /* Frameworks */,
+ FC7A7D2714986A240086576A /* CopyFiles */,
+ FC6C98FE149A99C400DDCC47 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = expand;
+ productName = text_cmds;
+ productReference = FC7A7D2A14986A240086576A /* expand */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D2C14986A280086576A /* fmt */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D3014986A280086576A /* Build configuration list for PBXNativeTarget "fmt" */;
+ buildPhases = (
+ FC7A7D2D14986A280086576A /* Sources */,
+ FC7A7D2E14986A280086576A /* Frameworks */,
+ FC7A7D2F14986A280086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fmt;
+ productName = text_cmds;
+ productReference = FC7A7D3214986A280086576A /* fmt */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D3414986A2B0086576A /* fold */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D3814986A2B0086576A /* Build configuration list for PBXNativeTarget "fold" */;
+ buildPhases = (
+ FC7A7D3514986A2B0086576A /* Sources */,
+ FC7A7D3614986A2B0086576A /* Frameworks */,
+ FC7A7D3714986A2B0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = fold;
+ productName = text_cmds;
+ productReference = FC7A7D3A14986A2B0086576A /* fold */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D3C14986A2F0086576A /* head */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D4014986A2F0086576A /* Build configuration list for PBXNativeTarget "head" */;
+ buildPhases = (
+ FC7A7D3D14986A2F0086576A /* Sources */,
+ FC7A7D3E14986A2F0086576A /* Frameworks */,
+ FC7A7D3F14986A2F0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = head;
+ productName = text_cmds;
+ productReference = FC7A7D4214986A2F0086576A /* head */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D4414986A310086576A /* join */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D4814986A310086576A /* Build configuration list for PBXNativeTarget "join" */;
+ buildPhases = (
+ FC7A7D4514986A310086576A /* Sources */,
+ FC7A7D4614986A310086576A /* Frameworks */,
+ FC7A7D4714986A310086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = join;
+ productName = text_cmds;
+ productReference = FC7A7D4A14986A310086576A /* join */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D4C14986A340086576A /* lam */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D5014986A340086576A /* Build configuration list for PBXNativeTarget "lam" */;
+ buildPhases = (
+ FC7A7D4D14986A340086576A /* Sources */,
+ FC7A7D4E14986A340086576A /* Frameworks */,
+ FC7A7D4F14986A340086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = lam;
+ productName = text_cmds;
+ productReference = FC7A7D5214986A340086576A /* lam */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D5414986A360086576A /* look */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D5814986A360086576A /* Build configuration list for PBXNativeTarget "look" */;
+ buildPhases = (
+ FC7A7D5514986A360086576A /* Sources */,
+ FC7A7D5614986A360086576A /* Frameworks */,
+ FC7A7D5714986A360086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = look;
+ productName = text_cmds;
+ productReference = FC7A7D5A14986A360086576A /* look */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D5C14986A390086576A /* md5 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D6014986A390086576A /* Build configuration list for PBXNativeTarget "md5" */;
+ buildPhases = (
+ FC7A7D5D14986A390086576A /* Sources */,
+ FC7A7D5E14986A390086576A /* Frameworks */,
+ FC7A7D5F14986A390086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = md5;
+ productName = text_cmds;
+ productReference = FC7A7D6214986A390086576A /* md5 */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D6414986A3C0086576A /* nl */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D6814986A3C0086576A /* Build configuration list for PBXNativeTarget "nl" */;
+ buildPhases = (
+ FC7A7D6514986A3C0086576A /* Sources */,
+ FC7A7D6614986A3C0086576A /* Frameworks */,
+ FC7A7D6714986A3C0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = nl;
+ productName = text_cmds;
+ productReference = FC7A7D6A14986A3C0086576A /* nl */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D6C14986A3D0086576A /* paste */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D7014986A3D0086576A /* Build configuration list for PBXNativeTarget "paste" */;
+ buildPhases = (
+ FC7A7D6D14986A3D0086576A /* Sources */,
+ FC7A7D6E14986A3D0086576A /* Frameworks */,
+ FC7A7D6F14986A3D0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = paste;
+ productName = text_cmds;
+ productReference = FC7A7D7214986A3D0086576A /* paste */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D7414986A400086576A /* pr */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D7814986A400086576A /* Build configuration list for PBXNativeTarget "pr" */;
+ buildPhases = (
+ FC7A7D7514986A400086576A /* Sources */,
+ FC7A7D7614986A400086576A /* Frameworks */,
+ FC7A7D7714986A400086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pr;
+ productName = text_cmds;
+ productReference = FC7A7D7A14986A400086576A /* pr */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D7C14986A410086576A /* rev */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D8014986A410086576A /* Build configuration list for PBXNativeTarget "rev" */;
+ buildPhases = (
+ FC7A7D7D14986A410086576A /* Sources */,
+ FC7A7D7E14986A410086576A /* Frameworks */,
+ FC7A7D7F14986A410086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rev;
+ productName = text_cmds;
+ productReference = FC7A7D8214986A410086576A /* rev */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D8414986A430086576A /* rs */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D8814986A430086576A /* Build configuration list for PBXNativeTarget "rs" */;
+ buildPhases = (
+ FC7A7D8514986A430086576A /* Sources */,
+ FC7A7D8614986A430086576A /* Frameworks */,
+ FC7A7D8714986A430086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = rs;
+ productName = text_cmds;
+ productReference = FC7A7D8A14986A430086576A /* rs */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D8C14986A450086576A /* sed */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D9014986A450086576A /* Build configuration list for PBXNativeTarget "sed" */;
+ buildPhases = (
+ FC7A7D8D14986A450086576A /* Sources */,
+ FC7A7D8E14986A450086576A /* Frameworks */,
+ FC7A7D8F14986A450086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sed;
+ productName = text_cmds;
+ productReference = FC7A7D9214986A450086576A /* sed */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D9414986A470086576A /* sort */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7D9814986A470086576A /* Build configuration list for PBXNativeTarget "sort" */;
+ buildPhases = (
+ FC7A7D9514986A470086576A /* Sources */,
+ FC7A7D9614986A470086576A /* Frameworks */,
+ FDF283721DAEE22200CF8C36 /* ShellScript */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = sort;
+ productName = text_cmds;
+ productReference = FC7A7D9A14986A470086576A /* sort */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7D9C14986A480086576A /* split */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DA014986A480086576A /* Build configuration list for PBXNativeTarget "split" */;
+ buildPhases = (
+ FC7A7D9D14986A480086576A /* Sources */,
+ FC7A7D9E14986A480086576A /* Frameworks */,
+ FC7A7D9F14986A480086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = split;
+ productName = text_cmds;
+ productReference = FC7A7DA214986A480086576A /* split */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7DA414986A4A0086576A /* tail */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DA814986A4A0086576A /* Build configuration list for PBXNativeTarget "tail" */;
+ buildPhases = (
+ FC7A7DA514986A4A0086576A /* Sources */,
+ FC7A7DA614986A4A0086576A /* Frameworks */,
+ FC7A7DA714986A4A0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tail;
+ productName = text_cmds;
+ productReference = FC7A7DAA14986A4A0086576A /* tail */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7DAC14986A500086576A /* tr */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DB014986A500086576A /* Build configuration list for PBXNativeTarget "tr" */;
+ buildPhases = (
+ FC7A7DAD14986A500086576A /* Sources */,
+ FC7A7DAE14986A500086576A /* Frameworks */,
+ FC7A7DAF14986A500086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tr;
+ productName = text_cmds;
+ productReference = FC7A7DB214986A500086576A /* tr */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7DB414986A530086576A /* ul */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DB814986A530086576A /* Build configuration list for PBXNativeTarget "ul" */;
+ buildPhases = (
+ FC7A7DB514986A530086576A /* Sources */,
+ FC7A7DB614986A530086576A /* Frameworks */,
+ FC7A7DB714986A530086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ul;
+ productName = text_cmds;
+ productReference = FC7A7DBA14986A530086576A /* ul */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7DBC14986A540086576A /* unexpand */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DC014986A540086576A /* Build configuration list for PBXNativeTarget "unexpand" */;
+ buildPhases = (
+ FC7A7DBD14986A540086576A /* Sources */,
+ FC7A7DBE14986A540086576A /* Frameworks */,
+ FC7A7DBF14986A540086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = unexpand;
+ productName = text_cmds;
+ productReference = FC7A7DC214986A540086576A /* unexpand */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7DC414986A560086576A /* uniq */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DC814986A560086576A /* Build configuration list for PBXNativeTarget "uniq" */;
+ buildPhases = (
+ FC7A7DC514986A560086576A /* Sources */,
+ FC7A7DC614986A560086576A /* Frameworks */,
+ FC7A7DC714986A560086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = uniq;
+ productName = text_cmds;
+ productReference = FC7A7DCA14986A560086576A /* uniq */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7DCC14986A580086576A /* unvis */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DD014986A580086576A /* Build configuration list for PBXNativeTarget "unvis" */;
+ buildPhases = (
+ FC7A7DCD14986A580086576A /* Sources */,
+ FC7A7DCE14986A580086576A /* Frameworks */,
+ FC7A7DCF14986A580086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = unvis;
+ productName = text_cmds;
+ productReference = FC7A7DD214986A580086576A /* unvis */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7DD414986A5A0086576A /* vis */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DD814986A5A0086576A /* Build configuration list for PBXNativeTarget "vis" */;
+ buildPhases = (
+ FC7A7DD514986A5A0086576A /* Sources */,
+ FC7A7DD614986A5A0086576A /* Frameworks */,
+ FC7A7DD714986A5A0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = vis;
+ productName = text_cmds;
+ productReference = FC7A7DDA14986A5A0086576A /* vis */;
+ productType = "com.apple.product-type.tool";
+ };
+ FC7A7DDC14986A5C0086576A /* wc */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FC7A7DE014986A5C0086576A /* Build configuration list for PBXNativeTarget "wc" */;
+ buildPhases = (
+ FC7A7DDD14986A5C0086576A /* Sources */,
+ FC7A7DDE14986A5C0086576A /* Frameworks */,
+ FC7A7DDF14986A5C0086576A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = wc;
+ productName = text_cmds;
+ productReference = FC7A7DE214986A5C0086576A /* wc */;
+ productType = "com.apple.product-type.tool";
+ };
+ FD3561F11B827EE0008A70F6 /* grep */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FD3561F71B827EE0008A70F6 /* Build configuration list for PBXNativeTarget "grep" */;
+ buildPhases = (
+ FD3561EE1B827EE0008A70F6 /* Sources */,
+ FD3561EF1B827EE0008A70F6 /* Frameworks */,
+ FD3561F01B827EE0008A70F6 /* Install Man Page */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = grep;
+ productName = grep;
+ productReference = FD3561F21B827EE0008A70F6 /* grep */;
+ productType = "com.apple.product-type.tool";
+ };
+ FDA49B8D1B7186CE003B4F3C /* ee */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = FDA49B921B7186CE003B4F3C /* Build configuration list for PBXNativeTarget "ee" */;
+ buildPhases = (
+ FDA49B8A1B7186CE003B4F3C /* Sources */,
+ FDA49B8B1B7186CE003B4F3C /* Frameworks */,
+ FDA49B8C1B7186CE003B4F3C /* Copy Files */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ee;
+ productName = ee;
+ productReference = FDA49B8E1B7186CE003B4F3C /* ee */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ FC7A7B30149865C80086576A /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0420;
+ ORGANIZATIONNAME = "Apple Inc.";
+ TargetAttributes = {
+ 3EF506E21F7ABE4D00421EB3 = {
+ CreatedOnToolsVersion = 9.0;
+ ProvisioningStyle = Automatic;
+ };
+ FD3561F11B827EE0008A70F6 = {
+ CreatedOnToolsVersion = 7.0;
+ };
+ FDA49B8D1B7186CE003B4F3C = {
+ CreatedOnToolsVersion = 7.0;
+ };
+ };
+ };
+ buildConfigurationList = FC7A7B33149865C80086576A /* Build configuration list for PBXProject "text_cmds" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = FC7A7B2E149865C70086576A;
+ productRefGroup = FC7A7B3A149865C80086576A /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ FC7A7E91149875C30086576A /* executables */,
+ FC7A7B38149865C80086576A /* banner */,
+ FC7A7CE4149867ED0086576A /* cat */,
+ FC7A7CEC149869E90086576A /* col */,
+ FC7A7CF414986A160086576A /* colrm */,
+ FC7A7CFC14986A190086576A /* column */,
+ FC7A7D0414986A1B0086576A /* comm */,
+ FC7A7D0C14986A1E0086576A /* csplit */,
+ FC7A7D1414986A210086576A /* cut */,
+ FC7A7D1C14986A230086576A /* ed */,
+ FDA49B8D1B7186CE003B4F3C /* ee */,
+ FC7A7D2414986A240086576A /* expand */,
+ FC7A7D2C14986A280086576A /* fmt */,
+ FC7A7D3414986A2B0086576A /* fold */,
+ FD3561F11B827EE0008A70F6 /* grep */,
+ FC7A7D3C14986A2F0086576A /* head */,
+ FC7A7D4414986A310086576A /* join */,
+ FC7A7D4C14986A340086576A /* lam */,
+ FC7A7D5414986A360086576A /* look */,
+ FC7A7D5C14986A390086576A /* md5 */,
+ FC7A7D6414986A3C0086576A /* nl */,
+ FC7A7D6C14986A3D0086576A /* paste */,
+ FC7A7D7414986A400086576A /* pr */,
+ FC7A7D7C14986A410086576A /* rev */,
+ FC7A7D8414986A430086576A /* rs */,
+ FC7A7D8C14986A450086576A /* sed */,
+ FC7A7D9414986A470086576A /* sort */,
+ FC7A7D9C14986A480086576A /* split */,
+ FC7A7DA414986A4A0086576A /* tail */,
+ FC7A7DAC14986A500086576A /* tr */,
+ FC7A7DB414986A530086576A /* ul */,
+ FC7A7DBC14986A540086576A /* unexpand */,
+ FC7A7DC414986A560086576A /* uniq */,
+ FC7A7DCC14986A580086576A /* unvis */,
+ FC7A7DD414986A5A0086576A /* vis */,
+ FC7A7DDC14986A5C0086576A /* wc */,
+ 3EF506E21F7ABE4D00421EB3 /* tests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ FC6C98FD149A989300DDCC47 /* Install open source info */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Install open source info";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-opensource.sh";
+ showEnvVarsInLog = 0;
+ };
+ FC6C98FE149A99C400DDCC47 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/expand/xcodescripts/link-man-pages.sh";
+ showEnvVarsInLog = 0;
+ };
+ FD3562041B828154008A70F6 /* Install grep variant links */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Install grep variant links";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/grep_variant_links.sh";
+ showEnvVarsInLog = 0;
+ };
+ FDF283721DAEE22200CF8C36 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". ${SRCROOT}/xcodescripts/install-sort-man.sh";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ FC7A7B35149865C80086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DE514986CD60086576A /* banner.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7CE5149867ED0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DE614986CDB0086576A /* cat.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7CED149869E90086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DE714986CE00086576A /* col.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7CF514986A160086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DE814986CE40086576A /* colrm.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7CFD14986A190086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DE914986CE90086576A /* column.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D0514986A1B0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DEA14986CEE0086576A /* comm.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D0D14986A1E0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DEB14986D0C0086576A /* csplit.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D1514986A210086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DEC14986D120086576A /* cut.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D1D14986A230086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DED14986D690086576A /* buf.c in Sources */,
+ FC7A7DEE14986D690086576A /* cbc.c in Sources */,
+ FC7A7DF014986D690086576A /* glbl.c in Sources */,
+ FC7A7DF114986D690086576A /* io.c in Sources */,
+ FC7A7DF214986D690086576A /* main.c in Sources */,
+ FC7A7DF314986D690086576A /* re.c in Sources */,
+ FC7A7DF414986D690086576A /* sub.c in Sources */,
+ FC7A7DF514986D690086576A /* undo.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D2514986A240086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DF614986D760086576A /* expand.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D2D14986A280086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DF714986D800086576A /* fmt.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D3514986A2B0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DF814986D8B0086576A /* fold.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D3D14986A2F0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DF914986D920086576A /* head.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D4514986A310086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DFA14986DA10086576A /* join.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D4D14986A340086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DFB14986DAB0086576A /* lam.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D5514986A360086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DFC14986DBF0086576A /* look.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D5D14986A390086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7DFE14986DC80086576A /* commoncrypto.c in Sources */,
+ FC7A7E0014986DC80086576A /* md5.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D6514986A3C0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E0114986DD90086576A /* nl.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D6D14986A3D0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E0214986DE40086576A /* paste.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D7514986A400086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E0314986DF60086576A /* egetopt.c in Sources */,
+ FC7A7E0514986DF60086576A /* pr.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D7D14986A410086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E0714986E040086576A /* rev.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D8514986A430086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E0814986E0E0086576A /* rs.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D8D14986A450086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E0914986E1B0086576A /* compile.c in Sources */,
+ FC7A7E0C14986E1B0086576A /* main.c in Sources */,
+ FC7A7E0D14986E1B0086576A /* misc.c in Sources */,
+ FC7A7E0E14986E1B0086576A /* process.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D9514986A470086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDF283681DAED0C000CF8C36 /* bwstring.c in Sources */,
+ FDF283691DAED0C000CF8C36 /* coll.c in Sources */,
+ FDF283711DAED7C700CF8C36 /* commoncrypto.c in Sources */,
+ FDF2836A1DAED0C000CF8C36 /* file.c in Sources */,
+ FDF2836B1DAED0C000CF8C36 /* mem.c in Sources */,
+ FDF2836C1DAED0C000CF8C36 /* radixsort.c in Sources */,
+ FC7A7E3714986E580086576A /* sort.c in Sources */,
+ FDF2836D1DAED0C000CF8C36 /* vsort.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7D9D14986A480086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E5614986E630086576A /* split.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DA514986A4A0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E5814986E750086576A /* forward.c in Sources */,
+ FC7A7E5914986E750086576A /* misc.c in Sources */,
+ FC7A7E5A14986E750086576A /* read.c in Sources */,
+ FC7A7E5B14986E750086576A /* reverse.c in Sources */,
+ FC7A7E5C14986E750086576A /* tail.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DAD14986A500086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E5D14986E880086576A /* cmap.c in Sources */,
+ FC7A7E5F14986E880086576A /* cset.c in Sources */,
+ FC7A7E6214986E880086576A /* str.c in Sources */,
+ FC7A7E6314986E880086576A /* tr.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DB514986A530086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E6414986E920086576A /* ul.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DBD14986A540086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E6514986E9B0086576A /* unexpand.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DC514986A560086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E6614986EA40086576A /* uniq.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DCD14986A580086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E6714986EAC0086576A /* unvis.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DD514986A5A0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E6914986EB90086576A /* foldit.c in Sources */,
+ FC7A7E6A14986EB90086576A /* vis.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FC7A7DDD14986A5C0086576A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FC7A7E6B14986EC10086576A /* wc.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FD3561EE1B827EE0008A70F6 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FD3561FE1B827F9F008A70F6 /* file.c in Sources */,
+ FD3561FF1B827F9F008A70F6 /* grep.c in Sources */,
+ FD3562001B827F9F008A70F6 /* queue.c in Sources */,
+ FD3562011B827F9F008A70F6 /* util.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ FDA49B8A1B7186CE003B4F3C /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FDA49B951B718738003B4F3C /* ee.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ FC7A7E95149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7B38149865C80086576A /* banner */;
+ targetProxy = FC7A7E94149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7E97149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7CE4149867ED0086576A /* cat */;
+ targetProxy = FC7A7E96149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7E99149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7CEC149869E90086576A /* col */;
+ targetProxy = FC7A7E98149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7E9B149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7CF414986A160086576A /* colrm */;
+ targetProxy = FC7A7E9A149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7E9D149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7CFC14986A190086576A /* column */;
+ targetProxy = FC7A7E9C149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7E9F149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D0414986A1B0086576A /* comm */;
+ targetProxy = FC7A7E9E149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EA1149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D0C14986A1E0086576A /* csplit */;
+ targetProxy = FC7A7EA0149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EA3149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D1414986A210086576A /* cut */;
+ targetProxy = FC7A7EA2149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EA5149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D1C14986A230086576A /* ed */;
+ targetProxy = FC7A7EA4149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EA7149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D2414986A240086576A /* expand */;
+ targetProxy = FC7A7EA6149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EA9149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D2C14986A280086576A /* fmt */;
+ targetProxy = FC7A7EA8149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EAB149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D3414986A2B0086576A /* fold */;
+ targetProxy = FC7A7EAA149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EAD149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D3C14986A2F0086576A /* head */;
+ targetProxy = FC7A7EAC149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EAF149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D4414986A310086576A /* join */;
+ targetProxy = FC7A7EAE149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EB1149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D4C14986A340086576A /* lam */;
+ targetProxy = FC7A7EB0149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EB3149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D5414986A360086576A /* look */;
+ targetProxy = FC7A7EB2149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EB5149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D5C14986A390086576A /* md5 */;
+ targetProxy = FC7A7EB4149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EB7149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D6414986A3C0086576A /* nl */;
+ targetProxy = FC7A7EB6149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EB9149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D6C14986A3D0086576A /* paste */;
+ targetProxy = FC7A7EB8149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EBB149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D7414986A400086576A /* pr */;
+ targetProxy = FC7A7EBA149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EBD149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D7C14986A410086576A /* rev */;
+ targetProxy = FC7A7EBC149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EBF149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D8414986A430086576A /* rs */;
+ targetProxy = FC7A7EBE149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EC1149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D8C14986A450086576A /* sed */;
+ targetProxy = FC7A7EC0149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EC3149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D9414986A470086576A /* sort */;
+ targetProxy = FC7A7EC2149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EC5149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7D9C14986A480086576A /* split */;
+ targetProxy = FC7A7EC4149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EC7149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7DA414986A4A0086576A /* tail */;
+ targetProxy = FC7A7EC6149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7EC9149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7DAC14986A500086576A /* tr */;
+ targetProxy = FC7A7EC8149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7ECB149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7DB414986A530086576A /* ul */;
+ targetProxy = FC7A7ECA149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7ECD149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7DBC14986A540086576A /* unexpand */;
+ targetProxy = FC7A7ECC149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7ECF149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7DC414986A560086576A /* uniq */;
+ targetProxy = FC7A7ECE149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7ED1149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7DCC14986A580086576A /* unvis */;
+ targetProxy = FC7A7ED0149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7ED3149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7DD414986A5A0086576A /* vis */;
+ targetProxy = FC7A7ED2149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FC7A7ED5149875E00086576A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FC7A7DDC14986A5C0086576A /* wc */;
+ targetProxy = FC7A7ED4149875E00086576A /* PBXContainerItemProxy */;
+ };
+ FD2BDC181B718D310053EE6B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FDA49B8D1B7186CE003B4F3C /* ee */;
+ targetProxy = FD2BDC171B718D310053EE6B /* PBXContainerItemProxy */;
+ };
+ FD3562061B8281A6008A70F6 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = FD3561F11B827EE0008A70F6 /* grep */;
+ targetProxy = FD3562051B8281A6008A70F6 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 3EF506E41F7ABE4D00421EB3 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ CODE_SIGN_STYLE = Automatic;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ OTHER_CFLAGS = "";
+ OTHER_LDFLAGS = "";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7B42149865C80086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CODE_SIGN_IDENTITY = "-";
+ COPY_PHASE_STRIP = YES;
+ CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)";
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_PREPROCESSOR_DEFINITIONS = "__FBSDID=__RCSID";
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ INSTALL_PATH = /usr/bin;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = __;
+ };
+ name = Release;
+ };
+ FC7A7B45149865C80086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7CE9149867ED0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7CF1149869E90086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7CF914986A160086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D0114986A190086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D0914986A1B0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D1114986A1E0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D1914986A210086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D2114986A230086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ INSTALL_PATH = /bin;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D2914986A240086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D3114986A280086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D3914986A2B0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D4114986A2F0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D4914986A310086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D5114986A340086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D5914986A360086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D6114986A390086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INSTALL_PATH = /sbin;
+ "OTHER_LDFLAGS[sdk=macosx*]" = "-lCrashReporterClient";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ };
+ name = Release;
+ };
+ FC7A7D6914986A3C0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D7114986A3D0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D7914986A400086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D8114986A410086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D8914986A430086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D9114986A450086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7D9914986A470086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FDF2836E1DAED24800CF8C36 /* sort.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FC7A7DA114986A480086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7DA914986A4A0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7DB114986A500086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7DB914986A530086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7DC114986A540086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7DC914986A560086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7DD114986A580086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7DD914986A5A0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7DE114986A5C0086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FC7A7E93149875C30086576A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ FD3561F61B827EE0008A70F6 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FD3562031B82803F008A70F6 /* grep.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ FDA49B931B7186CE003B4F3C /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = FD2BDC161B7188240053EE6B /* ee.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 3EF506E31F7ABE4D00421EB3 /* Build configuration list for PBXLegacyTarget "tests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 3EF506E41F7ABE4D00421EB3 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7B33149865C80086576A /* Build configuration list for PBXProject "text_cmds" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7B42149865C80086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7B43149865C80086576A /* Build configuration list for PBXNativeTarget "banner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7B45149865C80086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7CE8149867ED0086576A /* Build configuration list for PBXNativeTarget "cat" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7CE9149867ED0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7CF0149869E90086576A /* Build configuration list for PBXNativeTarget "col" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7CF1149869E90086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7CF814986A160086576A /* Build configuration list for PBXNativeTarget "colrm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7CF914986A160086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D0014986A190086576A /* Build configuration list for PBXNativeTarget "column" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D0114986A190086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D0814986A1B0086576A /* Build configuration list for PBXNativeTarget "comm" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D0914986A1B0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D1014986A1E0086576A /* Build configuration list for PBXNativeTarget "csplit" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D1114986A1E0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D1814986A210086576A /* Build configuration list for PBXNativeTarget "cut" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D1914986A210086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D2014986A230086576A /* Build configuration list for PBXNativeTarget "ed" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D2114986A230086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D2814986A240086576A /* Build configuration list for PBXNativeTarget "expand" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D2914986A240086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D3014986A280086576A /* Build configuration list for PBXNativeTarget "fmt" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D3114986A280086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D3814986A2B0086576A /* Build configuration list for PBXNativeTarget "fold" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D3914986A2B0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D4014986A2F0086576A /* Build configuration list for PBXNativeTarget "head" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D4114986A2F0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D4814986A310086576A /* Build configuration list for PBXNativeTarget "join" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D4914986A310086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D5014986A340086576A /* Build configuration list for PBXNativeTarget "lam" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D5114986A340086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D5814986A360086576A /* Build configuration list for PBXNativeTarget "look" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D5914986A360086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D6014986A390086576A /* Build configuration list for PBXNativeTarget "md5" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D6114986A390086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D6814986A3C0086576A /* Build configuration list for PBXNativeTarget "nl" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D6914986A3C0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D7014986A3D0086576A /* Build configuration list for PBXNativeTarget "paste" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D7114986A3D0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D7814986A400086576A /* Build configuration list for PBXNativeTarget "pr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D7914986A400086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D8014986A410086576A /* Build configuration list for PBXNativeTarget "rev" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D8114986A410086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D8814986A430086576A /* Build configuration list for PBXNativeTarget "rs" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D8914986A430086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D9014986A450086576A /* Build configuration list for PBXNativeTarget "sed" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D9114986A450086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7D9814986A470086576A /* Build configuration list for PBXNativeTarget "sort" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7D9914986A470086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DA014986A480086576A /* Build configuration list for PBXNativeTarget "split" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DA114986A480086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DA814986A4A0086576A /* Build configuration list for PBXNativeTarget "tail" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DA914986A4A0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DB014986A500086576A /* Build configuration list for PBXNativeTarget "tr" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DB114986A500086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DB814986A530086576A /* Build configuration list for PBXNativeTarget "ul" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DB914986A530086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DC014986A540086576A /* Build configuration list for PBXNativeTarget "unexpand" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DC114986A540086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DC814986A560086576A /* Build configuration list for PBXNativeTarget "uniq" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DC914986A560086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DD014986A580086576A /* Build configuration list for PBXNativeTarget "unvis" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DD114986A580086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DD814986A5A0086576A /* Build configuration list for PBXNativeTarget "vis" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DD914986A5A0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7DE014986A5C0086576A /* Build configuration list for PBXNativeTarget "wc" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7DE114986A5C0086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FC7A7E92149875C30086576A /* Build configuration list for PBXAggregateTarget "executables" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FC7A7E93149875C30086576A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FD3561F71B827EE0008A70F6 /* Build configuration list for PBXNativeTarget "grep" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FD3561F61B827EE0008A70F6 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ FDA49B921B7186CE003B4F3C /* Build configuration list for PBXNativeTarget "ee" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ FDA49B931B7186CE003B4F3C /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = FC7A7B30149865C80086576A /* Project object */;
+}
diff --git a/text_cmds/text_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/text_cmds/text_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/text_cmds/text_cmds.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+ version = "1.0">
+ <FileRef
+ location = "self:">
+ </FileRef>
+</Workspace>
diff --git a/text_cmds/tr/cmap.c b/text_cmds/tr/cmap.c
new file mode 100644
index 0000000..1edd9d2
--- /dev/null
+++ b/text_cmds/tr/cmap.c
@@ -0,0 +1,212 @@
+/*-
+ * Copyright (c) 2004 Tim J. Robbins.
+ * 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.
+ */
+/*
+ * "Character map" ADT. Stores mappings between pairs of characters in a
+ * splay tree, with a lookup table cache to simplify looking up the first
+ * bunch of characters (which are presumably more common than others).
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tr/cmap.c,v 1.2 2004/07/14 08:36:09 tjr Exp $");
+
+#include <assert.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include "cmap.h"
+
+static struct cmapnode *cmap_splay(struct cmapnode *, wint_t);
+
+/*
+ * cmap_alloc --
+ * Allocate a character map.
+ */
+struct cmap *
+cmap_alloc(void)
+{
+ struct cmap *cm;
+
+ cm = malloc(sizeof(*cm));
+ if (cm == NULL)
+ return (NULL);
+ cm->cm_root = NULL;
+ cm->cm_def = CM_DEF_SELF;
+ cm->cm_havecache = false;
+ cm->cm_min = cm->cm_max = 0;
+ return (cm);
+}
+
+/*
+ * cmap_add --
+ * Add a mapping from "from" to "to" to the map.
+ */
+bool
+cmap_add(struct cmap *cm, wint_t from, wint_t to)
+{
+ struct cmapnode *cmn, *ncmn;
+
+ cm->cm_havecache = false;
+
+ if (cm->cm_root == NULL) {
+ cmn = malloc(sizeof(*cmn));
+ if (cmn == NULL)
+ return (false);
+ cmn->cmn_from = from;
+ cmn->cmn_to = to;
+ cmn->cmn_left = cmn->cmn_right = NULL;
+ cm->cm_root = cmn;
+ cm->cm_min = cm->cm_max = from;
+ return (true);
+ }
+
+ cmn = cm->cm_root = cmap_splay(cm->cm_root, from);
+
+ if (cmn->cmn_from == from) {
+ cmn->cmn_to = to;
+ return (true);
+ }
+
+ ncmn = malloc(sizeof(*ncmn));
+ if (ncmn == NULL)
+ return (false);
+ ncmn->cmn_from = from;
+ ncmn->cmn_to = to;
+ if (from < cmn->cmn_from) {
+ ncmn->cmn_left = cmn->cmn_left;
+ ncmn->cmn_right = cmn;
+ cmn->cmn_left = NULL;
+ } else {
+ ncmn->cmn_right = cmn->cmn_right;
+ ncmn->cmn_left = cmn;
+ cmn->cmn_right = NULL;
+ }
+ if (from < cm->cm_min)
+ cm->cm_min = from;
+ if (from > cm->cm_max)
+ cm->cm_max = from;
+ cm->cm_root = ncmn;
+
+ return (true);
+}
+
+/*
+ * cmap_lookup_hard --
+ * Look up the mapping for a character without using the cache.
+ */
+wint_t
+cmap_lookup_hard(struct cmap *cm, wint_t ch)
+{
+
+ if (cm->cm_root != NULL) {
+ cm->cm_root = cmap_splay(cm->cm_root, ch);
+ if (cm->cm_root->cmn_from == ch)
+ return (cm->cm_root->cmn_to);
+ }
+ return (cm->cm_def == CM_DEF_SELF ? ch : cm->cm_def);
+}
+
+/*
+ * cmap_cache --
+ * Update the cache.
+ */
+void
+cmap_cache(struct cmap *cm)
+{
+ wint_t ch;
+
+ for (ch = 0; ch < CM_CACHE_SIZE; ch++)
+ cm->cm_cache[ch] = cmap_lookup_hard(cm, ch);
+
+ cm->cm_havecache = true;
+}
+
+/*
+ * cmap_default --
+ * Change the value that characters without mappings map to, and
+ * return the old value. The special character value CM_MAP_SELF
+ * means characters map to themselves.
+ */
+wint_t
+cmap_default(struct cmap *cm, wint_t def)
+{
+ wint_t old;
+
+ old = cm->cm_def;
+ cm->cm_def = def;
+ cm->cm_havecache = false;
+ return (old);
+}
+
+static struct cmapnode *
+cmap_splay(struct cmapnode *t, wint_t ch)
+{
+ struct cmapnode N, *l, *r, *y;
+
+ /*
+ * Based on public domain code from Sleator.
+ */
+
+ assert(t != NULL);
+
+ N.cmn_left = N.cmn_right = NULL;
+ l = r = &N;
+ for (;;) {
+ if (ch < t->cmn_from) {
+ if (t->cmn_left != NULL &&
+ ch < t->cmn_left->cmn_from) {
+ y = t->cmn_left;
+ t->cmn_left = y->cmn_right;
+ y->cmn_right = t;
+ t = y;
+ }
+ if (t->cmn_left == NULL)
+ break;
+ r->cmn_left = t;
+ r = t;
+ t = t->cmn_left;
+ } else if (ch > t->cmn_from) {
+ if (t->cmn_right != NULL &&
+ ch > t->cmn_right->cmn_from) {
+ y = t->cmn_right;
+ t->cmn_right = y->cmn_left;
+ y->cmn_left = t;
+ t = y;
+ }
+ if (t->cmn_right == NULL)
+ break;
+ l->cmn_right = t;
+ l = t;
+ t = t->cmn_right;
+ } else
+ break;
+ }
+ l->cmn_right = t->cmn_left;
+ r->cmn_left = t->cmn_right;
+ t->cmn_left = N.cmn_right;
+ t->cmn_right = N.cmn_left;
+ return (t);
+}
diff --git a/text_cmds/tr/cmap.h b/text_cmds/tr/cmap.h
new file mode 100644
index 0000000..38e3d0e
--- /dev/null
+++ b/text_cmds/tr/cmap.h
@@ -0,0 +1,83 @@
+/*-
+ * Copyright (c) 2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/tr/cmap.h,v 1.1 2004/07/09 02:08:07 tjr Exp $
+ */
+
+#ifndef CMAP_H
+#define CMAP_H
+
+#include <limits.h>
+#include <stdbool.h>
+#include <wchar.h>
+
+struct cmapnode {
+ wint_t cmn_from;
+ wint_t cmn_to;
+ struct cmapnode *cmn_left;
+ struct cmapnode *cmn_right;
+};
+
+struct cmap {
+#define CM_CACHE_SIZE 128
+ wint_t cm_cache[CM_CACHE_SIZE];
+ bool cm_havecache;
+ struct cmapnode *cm_root;
+#define CM_DEF_SELF -2
+ wint_t cm_def;
+ wint_t cm_min;
+ wint_t cm_max;
+};
+
+struct cmap * cmap_alloc(void);
+bool cmap_add(struct cmap *, wint_t, wint_t);
+wint_t cmap_lookup_hard(struct cmap *, wint_t);
+void cmap_cache(struct cmap *);
+wint_t cmap_default(struct cmap *, wint_t);
+
+static __inline wint_t
+cmap_lookup(struct cmap *cm, wint_t from)
+{
+
+ if (from < CM_CACHE_SIZE && cm->cm_havecache)
+ return (cm->cm_cache[from]);
+ return (cmap_lookup_hard(cm, from));
+}
+
+static __inline wint_t
+cmap_min(struct cmap *cm)
+{
+
+ return (cm->cm_min);
+}
+
+static __inline wint_t
+cmap_max(struct cmap *cm)
+{
+
+ return (cm->cm_max);
+}
+
+#endif
diff --git a/text_cmds/tr/cset.c b/text_cmds/tr/cset.c
new file mode 100644
index 0000000..6e7c217
--- /dev/null
+++ b/text_cmds/tr/cset.c
@@ -0,0 +1,290 @@
+/*-
+ * Copyright (c) 2004 Tim J. Robbins.
+ * 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.
+ */
+/*
+ * "Set of characters" ADT implemented as a splay tree of extents, with
+ * a lookup table cache to simplify looking up the first bunch of
+ * characters (which are presumably more common than others).
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/tr/cset.c,v 1.3 2004/07/14 08:33:14 tjr Exp $");
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <wctype.h>
+#include "cset.h"
+
+static struct csnode * cset_delete(struct csnode *, wchar_t);
+static __inline int cset_rangecmp(struct csnode *, wchar_t);
+static struct csnode * cset_splay(struct csnode *, wchar_t);
+
+/*
+ * cset_alloc --
+ * Allocate a set of characters.
+ */
+struct cset *
+cset_alloc(void)
+{
+ struct cset *cs;
+
+ if ((cs = malloc(sizeof(*cs))) == NULL)
+ return (NULL);
+ cs->cs_root = NULL;
+ cs->cs_classes = NULL;
+ cs->cs_havecache = false;
+ cs->cs_invert = false;
+ return (cs);
+}
+
+/*
+ * cset_add --
+ * Add a character to the set.
+ */
+bool
+cset_add(struct cset *cs, wchar_t ch)
+{
+ struct csnode *csn, *ncsn;
+ wchar_t oval;
+
+ cs->cs_havecache = false;
+
+ /*
+ * Inserting into empty tree; new item becomes the root.
+ */
+ if (cs->cs_root == NULL) {
+ csn = malloc(sizeof(*cs->cs_root));
+ if (csn == NULL)
+ return (false);
+ csn->csn_left = csn->csn_right = NULL;
+ csn->csn_min = csn->csn_max = ch;
+ cs->cs_root = csn;
+ return (true);
+ }
+
+ /*
+ * Splay to check whether the item already exists, and otherwise,
+ * where we should put it.
+ */
+ csn = cs->cs_root = cset_splay(cs->cs_root, ch);
+
+ /*
+ * Avoid adding duplicate nodes.
+ */
+ if (cset_rangecmp(csn, ch) == 0)
+ return (true);
+
+ /*
+ * Allocate a new node and make it the new root.
+ */
+ ncsn = malloc(sizeof(*ncsn));
+ if (ncsn == NULL)
+ return (false);
+ ncsn->csn_min = ncsn->csn_max = ch;
+ if (cset_rangecmp(csn, ch) < 0) {
+ ncsn->csn_left = csn->csn_left;
+ ncsn->csn_right = csn;
+ csn->csn_left = NULL;
+ } else {
+ ncsn->csn_right = csn->csn_right;
+ ncsn->csn_left = csn;
+ csn->csn_right = NULL;
+ }
+ cs->cs_root = ncsn;
+
+ /*
+ * Coalesce with left and right neighbours if possible.
+ */
+ if (ncsn->csn_left != NULL) {
+ ncsn->csn_left = cset_splay(ncsn->csn_left, ncsn->csn_min - 1);
+ if (ncsn->csn_left->csn_max == ncsn->csn_min - 1) {
+ oval = ncsn->csn_left->csn_min;
+ ncsn->csn_left = cset_delete(ncsn->csn_left,
+ ncsn->csn_left->csn_min);
+ ncsn->csn_min = oval;
+ }
+ }
+ if (ncsn->csn_right != NULL) {
+ ncsn->csn_right = cset_splay(ncsn->csn_right,
+ ncsn->csn_max + 1);
+ if (ncsn->csn_right->csn_min == ncsn->csn_max + 1) {
+ oval = ncsn->csn_right->csn_max;
+ ncsn->csn_right = cset_delete(ncsn->csn_right,
+ ncsn->csn_right->csn_min);
+ ncsn->csn_max = oval;
+ }
+ }
+
+ return (true);
+}
+
+/*
+ * cset_in_hard --
+ * Determine whether a character is in the set without using
+ * the cache.
+ */
+bool
+cset_in_hard(struct cset *cs, wchar_t ch)
+{
+ struct csclass *csc;
+
+ for (csc = cs->cs_classes; csc != NULL; csc = csc->csc_next)
+ if (csc->csc_invert ^ iswctype(ch, csc->csc_type) != 0)
+ return (cs->cs_invert ^ true);
+ if (cs->cs_root != NULL) {
+ cs->cs_root = cset_splay(cs->cs_root, ch);
+ return (cs->cs_invert ^ cset_rangecmp(cs->cs_root, ch) == 0);
+ }
+ return (cs->cs_invert ^ false);
+}
+
+/*
+ * cset_cache --
+ * Update the cache.
+ */
+void
+cset_cache(struct cset *cs)
+{
+ wchar_t i;
+
+ for (i = 0; i < CS_CACHE_SIZE; i++)
+ cs->cs_cache[i] = cset_in_hard(cs, i);
+
+ cs->cs_havecache = true;
+}
+
+/*
+ * cset_invert --
+ * Invert the character set.
+ */
+void
+cset_invert(struct cset *cs)
+{
+
+ cs->cs_invert ^= true;
+ cs->cs_havecache = false;
+}
+
+/*
+ * cset_addclass --
+ * Add a wctype()-style character class to the set, optionally
+ * inverting it.
+ */
+bool
+cset_addclass(struct cset *cs, wctype_t type, bool invert)
+{
+ struct csclass *csc;
+
+ csc = malloc(sizeof(*csc));
+ if (csc == NULL)
+ return (false);
+ csc->csc_type = type;
+ csc->csc_invert = invert;
+ csc->csc_next = cs->cs_classes;
+ cs->cs_classes = csc;
+ cs->cs_havecache = false;
+ return (true);
+}
+
+static __inline int
+cset_rangecmp(struct csnode *t, wchar_t ch)
+{
+
+ if (ch < t->csn_min)
+ return (-1);
+ if (ch > t->csn_max)
+ return (1);
+ return (0);
+}
+
+static struct csnode *
+cset_splay(struct csnode *t, wchar_t ch)
+{
+ struct csnode N, *l, *r, *y;
+
+ /*
+ * Based on public domain code from Sleator.
+ */
+
+ assert(t != NULL);
+
+ N.csn_left = N.csn_right = NULL;
+ l = r = &N;
+ for (;;) {
+ if (cset_rangecmp(t, ch) < 0) {
+ if (t->csn_left != NULL &&
+ cset_rangecmp(t->csn_left, ch) < 0) {
+ y = t->csn_left;
+ t->csn_left = y->csn_right;
+ y->csn_right = t;
+ t = y;
+ }
+ if (t->csn_left == NULL)
+ break;
+ r->csn_left = t;
+ r = t;
+ t = t->csn_left;
+ } else if (cset_rangecmp(t, ch) > 0) {
+ if (t->csn_right != NULL &&
+ cset_rangecmp(t->csn_right, ch) > 0) {
+ y = t->csn_right;
+ t->csn_right = y->csn_left;
+ y->csn_left = t;
+ t = y;
+ }
+ if (t->csn_right == NULL)
+ break;
+ l->csn_right = t;
+ l = t;
+ t = t->csn_right;
+ } else
+ break;
+ }
+ l->csn_right = t->csn_left;
+ r->csn_left = t->csn_right;
+ t->csn_left = N.csn_right;
+ t->csn_right = N.csn_left;
+ return (t);
+}
+
+static struct csnode *
+cset_delete(struct csnode *t, wchar_t ch)
+{
+ struct csnode *x;
+
+ assert(t != NULL);
+ t = cset_splay(t, ch);
+ assert(cset_rangecmp(t, ch) == 0);
+ if (t->csn_left == NULL)
+ x = t->csn_right;
+ else {
+ x = cset_splay(t->csn_left, ch);
+ x->csn_right = t->csn_right;
+ }
+ free(t);
+ return x;
+}
diff --git a/text_cmds/tr/cset.h b/text_cmds/tr/cset.h
new file mode 100644
index 0000000..ae62d1d
--- /dev/null
+++ b/text_cmds/tr/cset.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2004 Tim J. Robbins.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/tr/cset.h,v 1.2 2004/07/14 08:35:11 tjr Exp $
+ */
+
+#ifndef CSET_H
+#define CSET_H
+
+#include <stdbool.h>
+#include <wchar.h>
+#include <wctype.h>
+
+struct csnode {
+ wchar_t csn_min;
+ wchar_t csn_max;
+ struct csnode *csn_left;
+ struct csnode *csn_right;
+};
+
+struct csclass {
+ wctype_t csc_type;
+ bool csc_invert;
+ struct csclass *csc_next;
+};
+
+struct cset {
+#define CS_CACHE_SIZE 256
+ bool cs_cache[CS_CACHE_SIZE];
+ bool cs_havecache;
+ struct csclass *cs_classes;
+ struct csnode *cs_root;
+ bool cs_invert;
+};
+
+bool cset_addclass(struct cset *, wctype_t, bool);
+struct cset * cset_alloc(void);
+bool cset_add(struct cset *, wchar_t);
+void cset_invert(struct cset *);
+bool cset_in_hard(struct cset *, wchar_t);
+void cset_cache(struct cset *);
+
+static __inline bool
+cset_in(struct cset *cs, wchar_t ch)
+{
+
+ if (ch < CS_CACHE_SIZE && cs->cs_havecache)
+ return (cs->cs_cache[ch]);
+ return (cset_in_hard(cs, ch));
+}
+
+#endif /* CSET_H */
diff --git a/text_cmds/tr/extern.h b/text_cmds/tr/extern.h
new file mode 100644
index 0000000..adc9ec3
--- /dev/null
+++ b/text_cmds/tr/extern.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ * $FreeBSD: src/usr.bin/tr/extern.h,v 1.9 2004/07/09 02:08:07 tjr Exp $
+ */
+
+#include <limits.h>
+
+#define NCHARS_SB (UCHAR_MAX + 1) /* Number of single-byte characters. */
+#define OOBCH -1 /* Out of band character value. */
+
+typedef struct {
+ enum { STRING1, STRING2 } which;
+ enum { EOS, INFINITE, NORMAL, RANGE, SEQUENCE,
+ CCLASS, CCLASS_UPPER, CCLASS_LOWER, SET } state;
+ int cnt; /* character count */
+ wint_t lastch; /* last character */
+ wctype_t cclass; /* character class from wctype() */
+ wint_t equiv[NCHARS_SB]; /* equivalence set */
+ wint_t *set; /* set of characters */
+ char *str; /* user's string */
+} STR;
+
+wint_t next(STR *);
+int charcoll(const void *, const void *);
diff --git a/text_cmds/tr/str.c b/text_cmds/tr/str.c
new file mode 100644
index 0000000..e7e6757
--- /dev/null
+++ b/text_cmds/tr/str.c
@@ -0,0 +1,450 @@
+/*-
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/tr/str.c,v 1.24 2004/11/14 05:15:25 jkh Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)str.c 8.2 (Berkeley) 4/28/95";
+#endif
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <wctype.h>
+#include <xlocale.h>
+
+#include "extern.h"
+
+static int backslash(STR *, int *);
+static int bracket(STR *);
+static void genclass(STR *);
+static void genequiv(STR *);
+static int genrange(STR *, int);
+static void genseq(STR *);
+
+/*
+ * Using libc internal function __collate_lookup_l for character
+ * equivalence
+ */
+void __collate_lookup_l(const __darwin_wchar_t *, int *, int *, int *,
+locale_t);
+/*
+ * Cache for primary collation weight of each single byte character
+ * used in static void genequiv(s)
+ */
+int collation_weight_cache[NCHARS_SB];
+int is_weight_cached = 0;
+
+wint_t
+next(s)
+ STR *s;
+{
+ int is_octal;
+ wint_t ch;
+ wchar_t wch;
+ size_t clen;
+
+ switch (s->state) {
+ case EOS:
+ return (0);
+ case INFINITE:
+#ifdef __APPLE__
+ switch (ch = (u_char)*s->str) {
+ case '\0':
+ /*
+ * force at least one postive return so setup() will
+ * process lastch of a sequence like [a*]; but change
+ * state so it won't get stuck in a while(next(s)) loop
+ */
+ s->state = NORMAL;
+ }
+#endif /* __APPLE__ */
+ return (1);
+ case NORMAL:
+ switch (*s->str) {
+ case '\0':
+ s->state = EOS;
+ return (0);
+ case '\\':
+ s->lastch = backslash(s, &is_octal);
+ break;
+ case '[':
+ if (bracket(s))
+ return (next(s));
+ /* FALLTHROUGH */
+ default:
+ clen = mbrtowc(&wch, s->str, MB_LEN_MAX, NULL);
+ if (clen == (size_t)-1 || clen == (size_t)-2 ||
+ clen == 0)
+ errc(1, EILSEQ, NULL);
+ is_octal = 0;
+ s->lastch = wch;
+ s->str += clen;
+ break;
+ }
+
+ /* We can start a range at any time. */
+ if (s->str[0] == '-' && genrange(s, is_octal))
+ return (next(s));
+ return (1);
+ case RANGE:
+ if (s->cnt-- == 0) {
+ s->state = NORMAL;
+ return (next(s));
+ }
+ ++s->lastch;
+ return (1);
+ case SEQUENCE:
+ if (s->cnt-- == 0) {
+ s->state = NORMAL;
+ return (next(s));
+ }
+ return (1);
+ case CCLASS:
+ case CCLASS_UPPER:
+ case CCLASS_LOWER:
+ s->cnt++;
+ ch = nextwctype(s->lastch, s->cclass);
+ if (ch == -1) {
+ s->state = NORMAL;
+ return (next(s));
+ }
+ s->lastch = ch;
+ return (1);
+ case SET:
+ if ((ch = s->set[s->cnt++]) == OOBCH) {
+ s->state = NORMAL;
+ return (next(s));
+ }
+ s->lastch = ch;
+ return (1);
+ default:
+ return (0);
+ }
+ /* NOTREACHED */
+}
+
+static int
+bracket(s)
+ STR *s;
+{
+ char *p;
+
+ switch (s->str[1]) {
+ case ':': /* "[:class:]" */
+ if ((p = strchr(s->str + 2, ']')) == NULL)
+ return (0);
+ if (*(p - 1) != ':' || p - s->str < 4)
+ goto repeat;
+ *(p - 1) = '\0';
+ s->str += 2;
+ genclass(s);
+ s->str = p + 1;
+ return (1);
+ case '=': /* "[=equiv=]" */
+ if ((p = strchr(s->str + 2, ']')) == NULL)
+ return (0);
+ if (*(p - 1) != '=' || p - s->str < 4)
+ goto repeat;
+ s->str += 2;
+ genequiv(s);
+ return (1);
+ default: /* "[\###*n]" or "[#*n]" */
+ repeat:
+ if ((p = strpbrk(s->str + 2, "*]")) == NULL)
+ return (0);
+ if (p[0] != '*' || index(p, ']') == NULL)
+ return (0);
+ s->str += 1;
+ genseq(s);
+ return (1);
+ }
+ /* NOTREACHED */
+}
+
+static void
+genclass(s)
+ STR *s;
+{
+
+ if ((s->cclass = wctype(s->str)) == 0)
+ errx(1, "unknown class %s", s->str);
+ s->cnt = 0;
+ s->lastch = -1; /* incremented before check in next() */
+ if (strcmp(s->str, "upper") == 0)
+ s->state = CCLASS_UPPER;
+ else if (strcmp(s->str, "lower") == 0)
+ s->state = CCLASS_LOWER;
+ else
+ s->state = CCLASS;
+}
+
+static void
+genequiv(s)
+ STR *s;
+{
+ int i, p;
+ size_t clen;
+ wchar_t wc;
+
+ if (*s->str == '\\') {
+ s->equiv[0] = backslash(s, NULL);
+ if (*s->str != '=')
+ errx(1, "misplaced equivalence equals sign");
+ s->str += 2;
+ } else {
+ clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL);
+ if (clen == (size_t)-1 || clen == (size_t)-2 || clen == 0)
+ errc(1, EILSEQ, NULL);
+ s->equiv[0] = wc;
+ if (s->str[clen] != '=')
+ errx(1, "misplaced equivalence equals sign");
+ s->str += clen + 2;
+ }
+
+ /*
+ * Partially supporting multi-byte locales; only finds equivalent
+ * characters within the first NCHARS_SB entries of the
+ * collation table
+ */
+ int tprim, tsec;
+ int len;
+ __collate_lookup_l(s->equiv, &len, &tprim, &tsec, LC_GLOBAL_LOCALE);
+
+ if (tprim != -1) {
+ for (p = 1, i = 1; i < NCHARS_SB; i++) {
+ int cprim;
+ if (is_weight_cached) {
+ /*
+ * retrieve primary weight from cache
+ */
+ cprim = collation_weight_cache[i];
+ } else {
+ /*
+ * perform lookup of primary weight and fill cache
+ */
+ int csec;
+ __collate_lookup_l((__darwin_wchar_t *)&i, &len, &cprim, &csec, LC_GLOBAL_LOCALE);
+ collation_weight_cache[i] = cprim;
+ }
+
+ /*
+ * If a character does not exist in the collation
+ * table, just skip it
+ */
+ if (cprim == -1) {
+ continue;
+ }
+
+ /*
+ * Only compare primary weights to determine multi-byte
+ * character equivalence
+ */
+ if (cprim == tprim) {
+ s->equiv[p++] = i;
+ }
+ }
+ s->equiv[p] = OOBCH;
+
+ if (!is_weight_cached) {
+ is_weight_cached = 1;
+ }
+ }
+
+ s->cnt = 0;
+ s->state = SET;
+ s->set = s->equiv;
+}
+
+static int
+genrange(STR *s, int was_octal)
+{
+ int stopval, octal;
+ char *savestart;
+ int n, cnt, *p;
+ size_t clen;
+ wchar_t wc;
+
+ octal = 0;
+ savestart = s->str;
+ if (*++s->str == '\\')
+ stopval = backslash(s, &octal);
+ else {
+ clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL);
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ errc(1, EILSEQ, NULL);
+ stopval = wc;
+ s->str += clen;
+ }
+ /*
+ * XXX Characters are not ordered according to collating sequence in
+ * multibyte locales.
+ */
+ if (octal || was_octal || MB_CUR_MAX > 1) {
+ if (stopval < s->lastch) {
+ s->str = savestart;
+ return (0);
+ }
+ s->cnt = stopval - s->lastch + 1;
+ s->state = RANGE;
+ --s->lastch;
+ return (1);
+ }
+ if (charcoll((const void *)&stopval, (const void *)&(s->lastch)) < 0) {
+ s->str = savestart;
+ return (0);
+ }
+ if ((s->set = p = malloc((NCHARS_SB + 1) * sizeof(int))) == NULL)
+ err(1, "genrange() malloc");
+ for (cnt = 0; cnt < NCHARS_SB; cnt++)
+ if (charcoll((const void *)&cnt, (const void *)&(s->lastch)) >= 0 &&
+ charcoll((const void *)&cnt, (const void *)&stopval) <= 0)
+ *p++ = cnt;
+ *p = OOBCH;
+ n = p - s->set;
+
+ s->cnt = 0;
+ s->state = SET;
+ if (n > 1)
+ mergesort(s->set, n, sizeof(*(s->set)), charcoll);
+ return (1);
+}
+
+static void
+genseq(s)
+ STR *s;
+{
+ char *ep;
+ wchar_t wc;
+ size_t clen;
+
+#ifndef __APPLE__
+ if (s->which == STRING1)
+ errx(1, "sequences only valid in string2");
+#endif /* !__APPLE__ */
+
+ if (*s->str == '\\')
+ s->lastch = backslash(s, NULL);
+ else {
+ clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL);
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ errc(1, EILSEQ, NULL);
+ s->lastch = wc;
+ s->str += clen;
+ }
+ if (*s->str != '*')
+ errx(1, "misplaced sequence asterisk");
+
+ switch (*++s->str) {
+ case '\\':
+ s->cnt = backslash(s, NULL);
+ break;
+ case ']':
+ s->cnt = 0;
+ ++s->str;
+ break;
+ default:
+ if (isdigit((u_char)*s->str)) {
+ s->cnt = strtol(s->str, &ep, 0);
+ if (*ep == ']') {
+ s->str = ep + 1;
+ break;
+ }
+ }
+ errx(1, "illegal sequence count");
+ /* NOTREACHED */
+ }
+
+ s->state = s->cnt ? SEQUENCE : INFINITE;
+}
+
+/*
+ * Translate \??? into a character. Up to 3 octal digits, if no digits either
+ * an escape code or a literal character.
+ */
+static int
+backslash(STR *s, int *is_octal)
+{
+ int ch, cnt, val;
+
+ if (is_octal != NULL)
+ *is_octal = 0;
+ for (cnt = val = 0;;) {
+ ch = (u_char)*++s->str;
+ if (!isdigit(ch) || ch > '7')
+ break;
+ val = val * 8 + ch - '0';
+ if (++cnt == 3) {
+ ++s->str;
+ break;
+ }
+ }
+ if (cnt) {
+ if (is_octal != NULL)
+ *is_octal = 1;
+ return (val);
+ }
+ if (ch != '\0')
+ ++s->str;
+ switch (ch) {
+ case 'a': /* escape characters */
+ return ('\7');
+ case 'b':
+ return ('\b');
+ case 'f':
+ return ('\f');
+ case 'n':
+ return ('\n');
+ case 'r':
+ return ('\r');
+ case 't':
+ return ('\t');
+ case 'v':
+ return ('\13');
+ case '\0': /* \" -> \ */
+ s->state = EOS;
+ return ('\\');
+ default: /* \x" -> x */
+ return (ch);
+ }
+}
diff --git a/text_cmds/tr/tr.1 b/text_cmds/tr/tr.1
new file mode 100644
index 0000000..6513674
--- /dev/null
+++ b/text_cmds/tr/tr.1
@@ -0,0 +1,420 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)tr.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/tr/tr.1,v 1.33 2005/02/13 23:45:51 ru Exp $
+.\"
+.Dd July 23, 2004
+.Dt TR 1
+.Os
+.Sh NAME
+.Nm tr
+.Nd translate characters
+.Sh SYNOPSIS
+.Nm
+.Op Fl Ccsu
+.Ar string1 string2
+.Nm
+.Op Fl Ccu
+.Fl d
+.Ar string1
+.Nm
+.Op Fl Ccu
+.Fl s
+.Ar string1
+.Nm
+.Op Fl Ccu
+.Fl ds
+.Ar string1 string2
+.Sh DESCRIPTION
+The
+.Nm
+utility copies the standard input to the standard output with substitution
+or deletion of selected characters.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl C
+Complement the set of characters in
+.Ar string1 ,
+that is
+.Dq Fl C Li ab
+includes every character except for
+.Ql a
+and
+.Ql b .
+.It Fl c
+Same as
+.Fl C
+but complement the set of values in
+.Ar string1 .
+.It Fl d
+Delete characters in
+.Ar string1
+from the input.
+.It Fl s
+Squeeze multiple occurrences of the characters listed in the last
+operand (either
+.Ar string1
+or
+.Ar string2 )
+in the input into a single instance of the character.
+This occurs after all deletion and translation is completed.
+.It Fl u
+Guarantee that any output is unbuffered.
+.El
+.Pp
+In the first synopsis form, the characters in
+.Ar string1
+are translated into the characters in
+.Ar string2
+where the first character in
+.Ar string1
+is translated into the first character in
+.Ar string2
+and so on.
+If
+.Ar string1
+is longer than
+.Ar string2 ,
+the last character found in
+.Ar string2
+is duplicated until
+.Ar string1
+is exhausted.
+.Pp
+In the second synopsis form, the characters in
+.Ar string1
+are deleted from the input.
+.Pp
+In the third synopsis form, the characters in
+.Ar string1
+are compressed as described for the
+.Fl s
+option.
+.Pp
+In the fourth synopsis form, the characters in
+.Ar string1
+are deleted from the input, and the characters in
+.Ar string2
+are compressed as described for the
+.Fl s
+option.
+.Pp
+The following conventions can be used in
+.Ar string1
+and
+.Ar string2
+to specify sets of characters:
+.Bl -tag -width [:equiv:]
+.It character
+Any character not described by one of the following conventions
+represents itself.
+.It \eoctal
+A backslash followed by 1, 2 or 3 octal digits represents a character
+with that encoded value.
+To follow an octal sequence with a digit as a character, left zero-pad
+the octal sequence to the full 3 octal digits.
+.It \echaracter
+A backslash followed by certain special characters maps to special
+values.
+.Pp
+.Bl -column "\ea"
+.It "\ea <alert character>
+.It "\eb <backspace>
+.It "\ef <form-feed>
+.It "\en <newline>
+.It "\er <carriage return>
+.It "\et <tab>
+.It "\ev <vertical tab>
+.El
+.Pp
+A backslash followed by any other character maps to that character.
+.It c-c
+For non-octal range endpoints
+represents the range of characters between the range endpoints, inclusive,
+in ascending order,
+as defined by the collation sequence.
+If either or both of the range endpoints are octal sequences, it
+represents the range of specific coded values between the
+range endpoints, inclusive.
+.Pp
+.Bf Em
+See the
+.Sx COMPATIBILITY
+section below for an important note regarding
+differences in the way the current
+implementation interprets range expressions differently from
+previous implementations.
+.Ef
+.It [:class:]
+Represents all characters belonging to the defined character class.
+Class names are:
+.Pp
+.Bl -column "phonogram"
+.It "alnum <alphanumeric characters>
+.It "alpha <alphabetic characters>
+.It "blank <whitespace characters>
+.It "cntrl <control characters>
+.It "digit <numeric characters>
+.It "graph <graphic characters>
+.It "ideogram <ideographic characters>
+.It "lower <lower-case alphabetic characters>
+.It "phonogram <phonographic characters>
+.It "print <printable characters>
+.It "punct <punctuation characters>
+.It "rune <valid characters>
+.It "space <space characters>
+.It "special <special characters>
+.It "upper <upper-case characters>
+.It "xdigit <hexadecimal characters>
+.El
+.Pp
+.\" All classes may be used in
+.\" .Ar string1 ,
+.\" and in
+.\" .Ar string2
+.\" when both the
+.\" .Fl d
+.\" and
+.\" .Fl s
+.\" options are specified.
+.\" Otherwise, only the classes ``upper'' and ``lower'' may be used in
+.\" .Ar string2
+.\" and then only when the corresponding class (``upper'' for ``lower''
+.\" and vice-versa) is specified in the same relative position in
+.\" .Ar string1 .
+.\" .Pp
+When
+.Dq Li [:lower:]
+appears in
+.Ar string1
+and
+.Dq Li [:upper:]
+appears in the same relative position in
+.Ar string2 ,
+it represents the characters pairs from the
+.Dv toupper
+mapping in the
+.Ev LC_CTYPE
+category of the current locale.
+When
+.Dq Li [:upper:]
+appears in
+.Ar string1
+and
+.Dq Li [:lower:]
+appears in the same relative position in
+.Ar string2 ,
+it represents the characters pairs from the
+.Dv tolower
+mapping in the
+.Ev LC_CTYPE
+category of the current locale.
+.Pp
+With the exception of case conversion,
+characters in the classes are in unspecified order.
+.Pp
+For specific information as to which
+.Tn ASCII
+characters are included
+in these classes, see
+.Xr ctype 3
+and related manual pages.
+.It [=equiv=]
+Represents all characters belonging to the same equivalence class as
+.Ar equiv ,
+ordered by their encoded values.
+.It [#*n]
+Represents
+.Ar n
+repeated occurrences of the character represented by
+.Ar # .
+This
+expression is only valid when it occurs in
+.Ar string2 .
+If
+.Ar n
+is omitted or is zero, it is be interpreted as large enough to extend
+.Ar string2
+sequence to the length of
+.Ar string1 .
+If
+.Ar n
+has a leading zero, it is interpreted as an octal value, otherwise,
+it is interpreted as a decimal value.
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_CTYPE
+and
+.Ev LC_COLLATE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+The following examples are shown as given to the shell:
+.Pp
+Create a list of the words in file1, one per line, where a word is taken to
+be a maximal string of letters.
+.Pp
+.D1 Li "tr -cs \*q[:alpha:]\*q \*q\en\*q < file1"
+.Pp
+Translate the contents of file1 to upper-case.
+.Pp
+.D1 Li "tr \*q[:lower:]\*q \*q[:upper:]\*q < file1"
+.Pp
+(This should be preferred over the traditional
+.Ux
+idiom of
+.Dq Li "tr a-z A-Z" ,
+since it works correctly in all locales.)
+.Pp
+Strip out non-printable characters from file1.
+.Pp
+.D1 Li "tr -cd \*q[:print:]\*q < file1"
+.Pp
+Remove diacritical marks from all accented variants of the letter
+.Ql e :
+.Pp
+.Dl "tr \*q[=e=]\*q \*qe\*q"
+.Sh COMPATIBILITY
+Previous
+.Fx
+implementations of
+.Nm
+did not order characters in range expressions according to the current
+locale's collation order, making it possible to convert unaccented Latin
+characters (esp.\& as found in English text) from upper to lower case using
+the traditional
+.Ux
+idiom of
+.Dq Li "tr A-Z a-z" .
+Since
+.Nm
+now obeys the locale's collation order, this idiom may not produce
+correct results when there is not a 1:1 mapping between lower and
+upper case, or when the order of characters within the two cases differs.
+As noted in the
+.Sx EXAMPLES
+section above, the character class expressions
+.Dq Li [:lower:]
+and
+.Dq Li [:upper:]
+should be used instead of explicit character ranges like
+.Dq Li a-z
+and
+.Dq Li A-Z .
+.Pp
+System V has historically implemented character ranges using the syntax
+.Dq Li [c-c]
+instead of the
+.Dq Li c-c
+used by historic
+.Bx
+implementations and
+standardized by POSIX.
+System V shell scripts should work under this implementation as long as
+the range is intended to map in another range, i.e., the command
+.Dq Li "tr [a-z] [A-Z]"
+will work as it will map the
+.Ql \&[
+character in
+.Ar string1
+to the
+.Ql \&[
+character in
+.Ar string2 .
+However, if the shell script is deleting or squeezing characters as in
+the command
+.Dq Li "tr -d [a-z]" ,
+the characters
+.Ql \&[
+and
+.Ql \&]
+will be
+included in the deletion or compression list which would not have happened
+under a historic System V implementation.
+Additionally, any scripts that depended on the sequence
+.Dq Li a-z
+to
+represent the three characters
+.Ql a ,
+.Ql \-
+and
+.Ql z
+will have to be
+rewritten as
+.Dq Li a\e-z .
+.Pp
+The
+.Nm
+utility has historically not permitted the manipulation of NUL bytes in
+its input and, additionally, stripped NUL's from its input stream.
+This implementation has removed this behavior as a bug.
+.Pp
+The
+.Nm
+utility has historically been extremely forgiving of syntax errors,
+for example, the
+.Fl c
+and
+.Fl s
+options were ignored unless two strings were specified.
+This implementation will not permit illegal syntax.
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Pp
+It should be noted that the feature wherein the last character of
+.Ar string2
+is duplicated if
+.Ar string2
+has less characters than
+.Ar string1
+is permitted by POSIX but is not required.
+Shell scripts attempting to be portable to other POSIX systems should use
+the
+.Dq Li [#*]
+convention instead of relying on this behavior.
+The
+.Fl u
+option is an extension to the
+.St -p1003.1-2001
+standard.
diff --git a/text_cmds/tr/tr.c b/text_cmds/tr/tr.c
new file mode 100644
index 0000000..7bd2ca7
--- /dev/null
+++ b/text_cmds/tr/tr.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/tr/tr.c,v 1.24 2005/04/09 14:31:41 stefanf Exp $");
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95";
+#endif
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "cmap.h"
+#include "cset.h"
+#include "extern.h"
+
+STR s1 = { STRING1, NORMAL, 0, OOBCH, 0, { 0, OOBCH }, NULL, NULL };
+STR s2 = { STRING2, NORMAL, 0, OOBCH, 0, { 0, OOBCH }, NULL, NULL };
+
+static struct cset *setup(char *, STR *, int, int);
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ static int carray[NCHARS_SB];
+ struct cmap *map;
+ struct cset *delete, *squeeze;
+ int n, *p;
+ int Cflag, cflag, dflag, sflag, isstring2;
+ wint_t ch, cnt, lastch;
+
+ (void)setlocale(LC_ALL, "");
+
+ Cflag = cflag = dflag = sflag = 0;
+ while ((ch = getopt(argc, argv, "Ccdsu")) != -1)
+ switch((char)ch) {
+ case 'C':
+ Cflag = 1;
+ cflag = 0;
+ break;
+ case 'c':
+ cflag = 1;
+ Cflag = 0;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ case 'u':
+ setbuf(stdout, (char *)NULL);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch(argc) {
+ case 0:
+ default:
+ usage();
+ /* NOTREACHED */
+ case 1:
+ isstring2 = 0;
+ if(!argv[0]) usage();
+ break;
+ case 2:
+ isstring2 = 1;
+ if(!argv[0] || !argv[1]) usage();
+ break;
+ }
+
+ /*
+ * tr -ds [-Cc] string1 string2
+ * Delete all characters (or complemented characters) in string1.
+ * Squeeze all characters in string2.
+ */
+ if (dflag && sflag) {
+ if (!isstring2)
+ usage();
+
+ delete = setup(argv[0], &s1, cflag, Cflag);
+ squeeze = setup(argv[1], &s2, 0, 0);
+
+ for (lastch = OOBCH; (ch = getwchar()) != WEOF;)
+ if (!cset_in(delete, ch) &&
+ (lastch != ch || !cset_in(squeeze, ch))) {
+ lastch = ch;
+ (void)putwchar(ch);
+ }
+ if (ferror(stdin))
+ err(1, NULL);
+ exit(0);
+ }
+
+ /*
+ * tr -d [-Cc] string1
+ * Delete all characters (or complemented characters) in string1.
+ */
+ if (dflag) {
+ if (isstring2)
+ usage();
+
+ delete = setup(argv[0], &s1, cflag, Cflag);
+
+ while ((ch = getwchar()) != WEOF)
+ if (!cset_in(delete, ch))
+ (void)putwchar(ch);
+ if (ferror(stdin))
+ err(1, NULL);
+ exit(0);
+ }
+
+ /*
+ * tr -s [-Cc] string1
+ * Squeeze all characters (or complemented characters) in string1.
+ */
+ if (sflag && !isstring2) {
+ squeeze = setup(argv[0], &s1, cflag, Cflag);
+
+ for (lastch = OOBCH; (ch = getwchar()) != WEOF;)
+ if (lastch != ch || !cset_in(squeeze, ch)) {
+ lastch = ch;
+ (void)putwchar(ch);
+ }
+ if (ferror(stdin))
+ err(1, NULL);
+ exit(0);
+ }
+
+ /*
+ * tr [-Ccs] string1 string2
+ * Replace all characters (or complemented characters) in string1 with
+ * the character in the same position in string2. If the -s option is
+ * specified, squeeze all the characters in string2.
+ */
+ if (!isstring2)
+ usage();
+
+ map = cmap_alloc();
+ if (map == NULL)
+ err(1, NULL);
+ squeeze = cset_alloc();
+ if (squeeze == NULL)
+ err(1, NULL);
+
+ s1.str = argv[0];
+
+ if (Cflag || cflag) {
+ cmap_default(map, OOBCH);
+ if ((s2.str = strdup(argv[1])) == NULL)
+ errx(1, "strdup(argv[1])");
+ } else
+ s2.str = argv[1];
+
+ if (!next(&s2))
+ errx(1, "empty string2");
+
+ /*
+ * For -s result will contain only those characters defined
+ * as the second characters in each of the toupper or tolower
+ * pairs.
+ */
+
+ /* If string2 runs out of characters, use the last one specified. */
+ while (next(&s1)) {
+ again:
+ if (s1.state == CCLASS_LOWER &&
+ s2.state == CCLASS_UPPER &&
+ s1.cnt == 1 && s2.cnt == 1) {
+ do {
+ ch = towupper(s1.lastch);
+ cmap_add(map, s1.lastch, ch);
+ if (sflag && iswupper(ch))
+ cset_add(squeeze, ch);
+ if (!next(&s1))
+ goto endloop;
+ } while (s1.state == CCLASS_LOWER && s1.cnt > 1);
+ /* skip upper set */
+ do {
+ if (!next(&s2))
+ break;
+ } while (s2.state == CCLASS_UPPER && s2.cnt > 1);
+ goto again;
+ } else if (s1.state == CCLASS_UPPER &&
+ s2.state == CCLASS_LOWER &&
+ s1.cnt == 1 && s2.cnt == 1) {
+ do {
+ ch = towlower(s1.lastch);
+ cmap_add(map, s1.lastch, ch);
+ if (sflag && iswlower(ch))
+ cset_add(squeeze, ch);
+ if (!next(&s1))
+ goto endloop;
+ } while (s1.state == CCLASS_UPPER && s1.cnt > 1);
+ /* skip lower set */
+ do {
+ if (!next(&s2))
+ break;
+ } while (s2.state == CCLASS_LOWER && s2.cnt > 1);
+ goto again;
+ } else {
+ cmap_add(map, s1.lastch, s2.lastch);
+ if (sflag)
+ cset_add(squeeze, s2.lastch);
+ }
+ (void)next(&s2);
+ }
+endloop:
+ if (cflag || (Cflag && MB_CUR_MAX > 1)) {
+ /*
+ * This is somewhat tricky: since the character set is
+ * potentially huge, we need to avoid allocating a map
+ * entry for every character. Our strategy is to set the
+ * default mapping to the last character of string #2
+ * (= the one that gets automatically repeated), then to
+ * add back identity mappings for characters that should
+ * remain unchanged. We don't waste space on identity mappings
+ * for non-characters with the -C option; those are simulated
+ * in the I/O loop.
+ */
+ s2.str = argv[1];
+ s2.state = NORMAL;
+ for (cnt = 0; cnt < WCHAR_MAX; cnt++) {
+ if (Cflag && !iswrune(cnt))
+ continue;
+ if (cmap_lookup(map, cnt) == OOBCH) {
+ if (next(&s2))
+ cmap_add(map, cnt, s2.lastch);
+ if (sflag)
+ cset_add(squeeze, s2.lastch);
+ } else
+ cmap_add(map, cnt, cnt);
+ if ((s2.state == EOS || s2.state == INFINITE) &&
+ cnt >= cmap_max(map))
+ break;
+ }
+ cmap_default(map, s2.lastch);
+ } else if (Cflag) {
+ for (p = carray, cnt = 0; cnt < NCHARS_SB; cnt++) {
+ if (cmap_lookup(map, cnt) == OOBCH && iswrune(cnt))
+ *p++ = cnt;
+ else
+ cmap_add(map, cnt, cnt);
+ }
+ n = p - carray;
+ if (Cflag && n > 1)
+ (void)mergesort(carray, n, sizeof(*carray), charcoll);
+
+ s2.str = argv[1];
+ s2.state = NORMAL;
+ for (cnt = 0; cnt < n; cnt++) {
+ (void)next(&s2);
+ cmap_add(map, carray[cnt], s2.lastch);
+ /*
+ * Chars taken from s2 can be different this time
+ * due to lack of complex upper/lower processing,
+ * so fill string2 again to not miss some.
+ */
+ if (sflag)
+ cset_add(squeeze, s2.lastch);
+ }
+ }
+
+ cset_cache(squeeze);
+ cmap_cache(map);
+
+ if (sflag)
+ for (lastch = OOBCH; (ch = getwchar()) != WEOF;) {
+ if (!Cflag || iswrune(ch))
+ ch = cmap_lookup(map, ch);
+ if (lastch != ch || !cset_in(squeeze, ch)) {
+ lastch = ch;
+ (void)putwchar(ch);
+ }
+ }
+ else
+ while ((ch = getwchar()) != WEOF) {
+ if (!Cflag || iswrune(ch))
+ ch = cmap_lookup(map, ch);
+ (void)putwchar(ch);
+ }
+ if (ferror(stdin))
+ err(1, NULL);
+ exit (0);
+}
+
+static struct cset *
+setup(char *arg, STR *str, int cflag, int Cflag)
+{
+ struct cset *cs;
+
+ cs = cset_alloc();
+ if (cs == NULL)
+ err(1, NULL);
+ str->str = arg;
+ while (next(str))
+ cset_add(cs, str->lastch);
+ if (Cflag)
+ cset_addclass(cs, wctype("rune"), true);
+ if (cflag || Cflag)
+ cset_invert(cs);
+ cset_cache(cs);
+ return (cs);
+}
+
+int
+charcoll(const void *a, const void *b)
+{
+ static char sa[2], sb[2];
+
+ sa[0] = *(const int *)a;
+ sb[0] = *(const int *)b;
+ return (strcoll(sa, sb));
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
+ "usage: tr [-Ccsu] string1 string2",
+ " tr [-Ccu] -d string1",
+ " tr [-Ccu] -s string1",
+ " tr [-Ccu] -ds string1 string2");
+ exit(1);
+}
diff --git a/text_cmds/ul/ul.1 b/text_cmds/ul/ul.1
new file mode 100644
index 0000000..847b958
--- /dev/null
+++ b/text_cmds/ul/ul.1
@@ -0,0 +1,104 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)ul.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/ul/ul.1,v 1.18 2005/05/21 09:55:09 ru Exp $
+.\"
+.Dd August 4, 2004
+.Dt UL 1
+.Os
+.Sh NAME
+.Nm ul
+.Nd do underlining
+.Sh SYNOPSIS
+.Nm
+.Op Fl i
+.Op Fl t Ar terminal
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility reads the named files (or standard input if none are given)
+and translates occurrences of underscores to the sequence
+which indicates underlining for the terminal in use, as specified
+by the environment variable
+.Ev TERM .
+The file
+.Pa /etc/termcap
+is read to determine the appropriate sequences for underlining.
+If the terminal is incapable of underlining, but is capable of
+a standout mode then that is used instead.
+If the terminal can overstrike,
+or handles underlining automatically,
+.Nm
+degenerates to
+.Xr cat 1 .
+If the terminal cannot underline, underlining is ignored.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl i
+Underlining is indicated by a separate line containing appropriate
+dashes `\-'; this is useful when you want to look at the underlining
+which is present in an
+.Xr nroff 1
+output stream on a crt-terminal.
+.It Fl t Ar terminal
+Overrides the terminal type specified in the environment with
+.Ar terminal .
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL , LC_CTYPE
+and
+.Ev TERM
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr colcrt 1 ,
+.Xr man 1 ,
+.Xr nroff 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
+.Sh BUGS
+The
+.Xr nroff 1
+command usually outputs a series of backspaces and underlines intermixed
+with the text to indicate underlining.
+No attempt is made to optimize
+the backward motion.
diff --git a/text_cmds/ul/ul.c b/text_cmds/ul/ul.c
new file mode 100644
index 0000000..ab22ea8
--- /dev/null
+++ b/text_cmds/ul/ul.c
@@ -0,0 +1,569 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ul.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/ul/ul.c,v 1.14 2005/05/21 09:55:09 ru Exp $";
+#endif /* not lint */
+
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termcap.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#define IESC '\033'
+#define SO '\016'
+#define SI '\017'
+#define HFWD '9'
+#define HREV '8'
+#define FREV '7'
+#define MAXBUF 512
+
+#define NORMAL 000
+#define ALTSET 001 /* Reverse */
+#define SUPERSC 002 /* Dim */
+#define SUBSC 004 /* Dim | Ul */
+#define UNDERL 010 /* Ul */
+#define BOLD 020 /* Bold */
+
+int must_use_uc, must_overstrike;
+const char
+ *CURS_UP, *CURS_RIGHT, *CURS_LEFT,
+ *ENTER_STANDOUT, *EXIT_STANDOUT, *ENTER_UNDERLINE, *EXIT_UNDERLINE,
+ *ENTER_DIM, *ENTER_BOLD, *ENTER_REVERSE, *UNDER_CHAR, *EXIT_ATTRIBUTES;
+
+struct CHAR {
+ char c_mode;
+ wchar_t c_char;
+ int c_width; /* width or -1 if multi-column char. filler */
+} ;
+
+struct CHAR obuf[MAXBUF];
+int col, maxcol;
+int mode;
+int halfpos;
+int upln;
+int iflag;
+
+static void usage(void);
+void setnewmode(int);
+void initcap(void);
+void reverse(void);
+int outchar(int);
+void fwd(void);
+void initbuf(void);
+void iattr(void);
+void overstrike(void);
+void flushln(void);
+void filter(FILE *);
+void outc(wint_t, int);
+
+#define PRINT(s) if (s == NULL) /* void */; else tputs(s, 1, outchar)
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ const char *termtype;
+ FILE *f;
+ char termcap[1024];
+
+ setlocale(LC_ALL, "");
+
+ termtype = getenv("TERM");
+ if (termtype == NULL || (argv[0] && argv[0][0] == 'c' && !isatty(1)))
+ termtype = "lpr";
+ while ((c=getopt(argc, argv, "it:T:")) != -1)
+ switch(c) {
+
+ case 't':
+ case 'T': /* for nroff compatibility */
+ termtype = optarg;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ default:
+ usage();
+ }
+
+ switch(tgetent(termcap, termtype)) {
+
+ case 1:
+ break;
+
+ default:
+ warnx("trouble reading termcap");
+ /* FALLTHROUGH */
+
+ case 0:
+ /* No such terminal type - assume dumb */
+ (void)strcpy(termcap, "dumb:os:col#80:cr=^M:sf=^J:am:");
+ break;
+ }
+ initcap();
+ if ( (tgetflag("os") && ENTER_BOLD==NULL ) ||
+ (tgetflag("ul") && ENTER_UNDERLINE==NULL && UNDER_CHAR==NULL))
+ must_overstrike = 1;
+ initbuf();
+ if (optind == argc)
+ filter(stdin);
+ else for (; optind<argc && argv[optind]; optind++) {
+ f = fopen(argv[optind],"r");
+ if (f == NULL)
+ err(1, "%s", argv[optind]);
+ else
+ filter(f);
+ }
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: ul [-i] [-t terminal] [file ...]\n");
+ exit(1);
+}
+
+void
+filter(FILE *f)
+{
+ wint_t c;
+ int i, w;
+
+ while ((c = getwc(f)) != WEOF && col < MAXBUF) switch(c) {
+
+ case '\b':
+ if (col > 0)
+ col--;
+ continue;
+
+ case '\t':
+ col = (col+8) & ~07;
+ if (col > maxcol)
+ maxcol = col;
+ continue;
+
+ case '\r':
+ col = 0;
+ continue;
+
+ case SO:
+ mode |= ALTSET;
+ continue;
+
+ case SI:
+ mode &= ~ALTSET;
+ continue;
+
+ case IESC:
+ switch (c = getwc(f)) {
+
+ case HREV:
+ if (halfpos == 0) {
+ mode |= SUPERSC;
+ halfpos--;
+ } else if (halfpos > 0) {
+ mode &= ~SUBSC;
+ halfpos--;
+ } else {
+ halfpos = 0;
+ reverse();
+ }
+ continue;
+
+ case HFWD:
+ if (halfpos == 0) {
+ mode |= SUBSC;
+ halfpos++;
+ } else if (halfpos < 0) {
+ mode &= ~SUPERSC;
+ halfpos++;
+ } else {
+ halfpos = 0;
+ fwd();
+ }
+ continue;
+
+ case FREV:
+ reverse();
+ continue;
+
+ default:
+ errx(1, "unknown escape sequence in input: %o, %o", IESC, c);
+ }
+ continue;
+
+ case '_':
+ if (obuf[col].c_char || obuf[col].c_width < 0) {
+ while (col > 0 && obuf[col].c_width < 0)
+ col--;
+ w = obuf[col].c_width;
+ for (i = 0; i < w; i++)
+ obuf[col++].c_mode |= UNDERL | mode;
+ if (col > maxcol)
+ maxcol = col;
+ continue;
+ }
+ obuf[col].c_char = '_';
+ obuf[col].c_width = 1;
+ /* FALLTHROUGH */
+ case ' ':
+ col++;
+ if (col > maxcol)
+ maxcol = col;
+ continue;
+
+ case '\n':
+ flushln();
+ continue;
+
+ case '\f':
+ flushln();
+ putwchar('\f');
+ continue;
+
+ default:
+ if ((w = wcwidth(c)) <= 0) /* non printing */
+ continue;
+ if (obuf[col].c_char == '\0') {
+ obuf[col].c_char = c;
+ for (i = 0; i < w; i++)
+ obuf[col + i].c_mode = mode;
+ obuf[col].c_width = w;
+ for (i = 1; i < w; i++)
+ obuf[col + i].c_width = -1;
+ } else if (obuf[col].c_char == '_') {
+ obuf[col].c_char = c;
+ for (i = 0; i < w; i++)
+ obuf[col + i].c_mode |= UNDERL|mode;
+ obuf[col].c_width = w;
+ for (i = 1; i < w; i++)
+ obuf[col + i].c_width = -1;
+ } else if (obuf[col].c_char == c) {
+ for (i = 0; i < w; i++)
+ obuf[col + i].c_mode |= BOLD|mode;
+ } else {
+ w = obuf[col].c_width;
+ for (i = 0; i < w; i++)
+ obuf[col + i].c_mode = mode;
+ }
+ col += w;
+ if (col > maxcol)
+ maxcol = col;
+ continue;
+ }
+ if (ferror(f))
+ err(1, NULL);
+ if (maxcol)
+ flushln();
+}
+
+void
+flushln(void)
+{
+ int lastmode;
+ int i;
+ int hadmodes = 0;
+
+ lastmode = NORMAL;
+ for (i=0; i<maxcol; i++) {
+ if (obuf[i].c_mode != lastmode) {
+ hadmodes++;
+ setnewmode(obuf[i].c_mode);
+ lastmode = obuf[i].c_mode;
+ }
+ if (obuf[i].c_char == '\0') {
+ if (upln)
+ PRINT(CURS_RIGHT);
+ else
+ outc(' ', 1);
+ } else
+ outc(obuf[i].c_char, obuf[i].c_width);
+ if (obuf[i].c_width > 1)
+ i += obuf[i].c_width - 1;
+ }
+ if (lastmode != NORMAL) {
+ setnewmode(0);
+ }
+ if (must_overstrike && hadmodes)
+ overstrike();
+ putwchar('\n');
+ if (iflag && hadmodes)
+ iattr();
+ (void)fflush(stdout);
+ if (upln)
+ upln--;
+ initbuf();
+}
+
+/*
+ * For terminals that can overstrike, overstrike underlines and bolds.
+ * We don't do anything with halfline ups and downs, or Greek.
+ */
+void
+overstrike(void)
+{
+ int i;
+ wchar_t lbuf[256];
+ wchar_t *cp = lbuf;
+ int hadbold=0;
+
+ /* Set up overstrike buffer */
+ for (i=0; i<maxcol; i++)
+ switch (obuf[i].c_mode) {
+ case NORMAL:
+ default:
+ *cp++ = ' ';
+ break;
+ case UNDERL:
+ *cp++ = '_';
+ break;
+ case BOLD:
+ *cp++ = obuf[i].c_char;
+ if (obuf[i].c_width > 1)
+ i += obuf[i].c_width - 1;
+ hadbold=1;
+ break;
+ }
+ putwchar('\r');
+ for (*cp=' '; *cp==' '; cp--)
+ *cp = 0;
+ for (cp=lbuf; *cp; cp++)
+ putwchar(*cp);
+ if (hadbold) {
+ putwchar('\r');
+ for (cp=lbuf; *cp; cp++)
+ putwchar(*cp=='_' ? ' ' : *cp);
+ putwchar('\r');
+ for (cp=lbuf; *cp; cp++)
+ putwchar(*cp=='_' ? ' ' : *cp);
+ }
+}
+
+void
+iattr(void)
+{
+ int i;
+ wchar_t lbuf[256];
+ wchar_t *cp = lbuf;
+
+ for (i=0; i<maxcol; i++)
+ switch (obuf[i].c_mode) {
+ case NORMAL: *cp++ = ' '; break;
+ case ALTSET: *cp++ = 'g'; break;
+ case SUPERSC: *cp++ = '^'; break;
+ case SUBSC: *cp++ = 'v'; break;
+ case UNDERL: *cp++ = '_'; break;
+ case BOLD: *cp++ = '!'; break;
+ default: *cp++ = 'X'; break;
+ }
+ for (*cp=' '; *cp==' '; cp--)
+ *cp = 0;
+ for (cp=lbuf; *cp; cp++)
+ putwchar(*cp);
+ putwchar('\n');
+}
+
+void
+initbuf(void)
+{
+
+ bzero((char *)obuf, sizeof (obuf)); /* depends on NORMAL == 0 */
+ col = 0;
+ maxcol = 0;
+ mode &= ALTSET;
+}
+
+void
+fwd(void)
+{
+ int oldcol, oldmax;
+
+ oldcol = col;
+ oldmax = maxcol;
+ flushln();
+ col = oldcol;
+ maxcol = oldmax;
+}
+
+void
+reverse(void)
+{
+ upln++;
+ fwd();
+ PRINT(CURS_UP);
+ PRINT(CURS_UP);
+ upln++;
+}
+
+void
+initcap(void)
+{
+ static char tcapbuf[512];
+ char *bp = tcapbuf;
+
+ /* This nonsense attempts to work with both old and new termcap */
+ CURS_UP = tgetstr("up", &bp);
+ CURS_RIGHT = tgetstr("ri", &bp);
+ if (CURS_RIGHT == NULL)
+ CURS_RIGHT = tgetstr("nd", &bp);
+ CURS_LEFT = tgetstr("le", &bp);
+ if (CURS_LEFT == NULL)
+ CURS_LEFT = tgetstr("bc", &bp);
+ if (CURS_LEFT == NULL && tgetflag("bs"))
+ CURS_LEFT = "\b";
+
+ ENTER_STANDOUT = tgetstr("so", &bp);
+ EXIT_STANDOUT = tgetstr("se", &bp);
+ ENTER_UNDERLINE = tgetstr("us", &bp);
+ EXIT_UNDERLINE = tgetstr("ue", &bp);
+ ENTER_DIM = tgetstr("mh", &bp);
+ ENTER_BOLD = tgetstr("md", &bp);
+ ENTER_REVERSE = tgetstr("mr", &bp);
+ EXIT_ATTRIBUTES = tgetstr("me", &bp);
+
+ if (!ENTER_BOLD && ENTER_REVERSE)
+ ENTER_BOLD = ENTER_REVERSE;
+ if (!ENTER_BOLD && ENTER_STANDOUT)
+ ENTER_BOLD = ENTER_STANDOUT;
+ if (!ENTER_UNDERLINE && ENTER_STANDOUT) {
+ ENTER_UNDERLINE = ENTER_STANDOUT;
+ EXIT_UNDERLINE = EXIT_STANDOUT;
+ }
+ if (!ENTER_DIM && ENTER_STANDOUT)
+ ENTER_DIM = ENTER_STANDOUT;
+ if (!ENTER_REVERSE && ENTER_STANDOUT)
+ ENTER_REVERSE = ENTER_STANDOUT;
+ if (!EXIT_ATTRIBUTES && EXIT_STANDOUT)
+ EXIT_ATTRIBUTES = EXIT_STANDOUT;
+
+ /*
+ * Note that we use REVERSE for the alternate character set,
+ * not the as/ae capabilities. This is because we are modelling
+ * the model 37 teletype (since that's what nroff outputs) and
+ * the typical as/ae is more of a graphics set, not the greek
+ * letters the 37 has.
+ */
+
+ UNDER_CHAR = tgetstr("uc", &bp);
+ must_use_uc = (UNDER_CHAR && !ENTER_UNDERLINE);
+}
+
+int
+outchar(int c)
+{
+ return (putwchar(c) != WEOF ? c : EOF);
+}
+
+static int curmode = 0;
+
+void
+outc(wint_t c, int width)
+{
+ int i;
+
+ putwchar(c);
+ if (must_use_uc && (curmode&UNDERL)) {
+ for (i = 0; i < width; i++)
+ PRINT(CURS_LEFT);
+ for (i = 0; i < width; i++)
+ PRINT(UNDER_CHAR);
+ }
+}
+
+void
+setnewmode(int newmode)
+{
+ if (!iflag) {
+ if (curmode != NORMAL && newmode != NORMAL)
+ setnewmode(NORMAL);
+ switch (newmode) {
+ case NORMAL:
+ switch(curmode) {
+ case NORMAL:
+ break;
+ case UNDERL:
+ PRINT(EXIT_UNDERLINE);
+ break;
+ default:
+ /* This includes standout */
+ PRINT(EXIT_ATTRIBUTES);
+ break;
+ }
+ break;
+ case ALTSET:
+ PRINT(ENTER_REVERSE);
+ break;
+ case SUPERSC:
+ /*
+ * This only works on a few terminals.
+ * It should be fixed.
+ */
+ PRINT(ENTER_UNDERLINE);
+ PRINT(ENTER_DIM);
+ break;
+ case SUBSC:
+ PRINT(ENTER_DIM);
+ break;
+ case UNDERL:
+ PRINT(ENTER_UNDERLINE);
+ break;
+ case BOLD:
+ PRINT(ENTER_BOLD);
+ break;
+ default:
+ /*
+ * We should have some provision here for multiple modes
+ * on at once. This will have to come later.
+ */
+ PRINT(ENTER_STANDOUT);
+ break;
+ }
+ }
+ curmode = newmode;
+}
diff --git a/text_cmds/unexpand/unexpand.c b/text_cmds/unexpand/unexpand.c
new file mode 100644
index 0000000..7120925
--- /dev/null
+++ b/text_cmds/unexpand/unexpand.c
@@ -0,0 +1,231 @@
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/unexpand/unexpand.c,v 1.15 2006/10/13 16:22:25 ru Exp $");
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)unexpand.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+/*
+ * unexpand - put tabs into a file replacing blanks
+ */
+#include <ctype.h>
+#include <err.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+int all;
+int nstops;
+int tabstops[100];
+
+static void getstops(const char *);
+static void usage(void);
+static int tabify(const char *);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, failed;
+ char *filename;
+
+ setlocale(LC_CTYPE, "");
+
+ nstops = 1;
+ tabstops[0] = 8;
+ while ((ch = getopt(argc, argv, "at:")) != -1) {
+ switch (ch) {
+ case 'a': /* Un-expand all spaces, not just leading. */
+ all = 1;
+ break;
+ case 't': /* Specify tab list, implies -a. */
+ getstops(optarg);
+ all = 1;
+ break;
+ default:
+ usage();
+ /*NOTREACHED*/
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ failed = 0;
+ if (argc == 0)
+ failed |= tabify("stdin");
+ else {
+ while ((filename = *argv++) != NULL) {
+ if (freopen(filename, "r", stdin) == NULL) {
+ warn("%s", filename);
+ failed = 1;
+ } else
+ failed |= tabify(filename);
+ }
+ }
+ exit(failed != 0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: unexpand [-a | -t tablist] [file ...]\n");
+ exit(1);
+}
+
+static int
+tabify(const char *curfile)
+{
+ int dcol, doneline, limit, n, ocol, width;
+ wint_t ch;
+
+ limit = nstops == 1 ? INT_MAX : tabstops[nstops - 1] - 1;
+
+ doneline = ocol = dcol = 0;
+ while ((ch = getwchar()) != WEOF) {
+ if (ch == ' ' && !doneline) {
+ if (++dcol >= limit)
+ doneline = 1;
+ continue;
+ } else if (ch == '\t') {
+ if (nstops == 1) {
+ dcol = (1 + dcol / tabstops[0]) *
+ tabstops[0];
+ continue;
+ } else {
+ for (n = 0; tabstops[n] - 1 < dcol &&
+ n < nstops; n++)
+ ;
+ if (n < nstops - 1 && tabstops[n] - 1 < limit) {
+ dcol = tabstops[n];
+ continue;
+ }
+ doneline = 1;
+ }
+ }
+
+ /* Output maximal number of tabs. */
+ if (nstops == 1) {
+ while (((ocol + tabstops[0]) / tabstops[0])
+ <= (dcol / tabstops[0])) {
+ if (dcol - ocol < 2)
+ break;
+ putwchar('\t');
+ ocol = (1 + ocol / tabstops[0]) *
+ tabstops[0];
+ }
+ } else {
+ for (n = 0; tabstops[n] - 1 < ocol && n < nstops; n++)
+ ;
+ while (ocol < dcol && n < nstops && ocol < limit) {
+ putwchar('\t');
+ ocol = tabstops[n++];
+ }
+ }
+
+ /* Then spaces. */
+ while (ocol < dcol && ocol < limit) {
+ putwchar(' ');
+ ocol++;
+ }
+
+ if (ch == '\b') {
+ putwchar('\b');
+ if (ocol > 0)
+ ocol--, dcol--;
+ } else if (ch == '\n') {
+ putwchar('\n');
+ doneline = ocol = dcol = 0;
+ continue;
+ } else if (ch != ' ' || dcol > limit) {
+ putwchar(ch);
+ if ((width = wcwidth(ch)) > 0)
+ ocol += width, dcol += width;
+ }
+
+ /*
+ * Only processing leading blanks or we've gone past the
+ * last tab stop. Emit remainder of this line unchanged.
+ */
+ if (!all || dcol >= limit) {
+ while ((ch = getwchar()) != '\n' && ch != WEOF)
+ putwchar(ch);
+ if (ch == '\n')
+ putwchar('\n');
+ doneline = ocol = dcol = 0;
+ }
+ }
+ if (ferror(stdin)) {
+ warn("%s", curfile);
+ return (1);
+ }
+ return (0);
+}
+
+static void
+getstops(const char *cp)
+{
+ int i;
+
+ nstops = 0;
+ for (;;) {
+ i = 0;
+ while (*cp >= '0' && *cp <= '9')
+ i = i * 10 + *cp++ - '0';
+ if (i <= 0)
+ errx(1, "bad tab stop spec");
+ if (nstops > 0 && i <= tabstops[nstops-1])
+ errx(1, "bad tab stop spec");
+ if (nstops == sizeof(tabstops) / sizeof(*tabstops))
+ errx(1, "too many tab stops");
+ tabstops[nstops++] = i;
+ if (*cp == 0)
+ break;
+ if (*cp != ',' && !isblank((unsigned char)*cp))
+ errx(1, "bad tab stop spec");
+ cp++;
+ }
+}
diff --git a/text_cmds/uniq/uniq.1 b/text_cmds/uniq/uniq.1
new file mode 100644
index 0000000..2baaee1
--- /dev/null
+++ b/text_cmds/uniq/uniq.1
@@ -0,0 +1,151 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" From: @(#)uniq.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: head/usr.bin/uniq/uniq.1 216370 2010-12-11 08:32:16Z joel $
+.\"
+.Dd December 17, 2009
+.Dt UNIQ 1
+.Os
+.Sh NAME
+.Nm uniq
+.Nd report or filter out repeated lines in a file
+.Sh SYNOPSIS
+.Nm
+.Op Fl c | Fl d | Fl u
+.Op Fl i
+.Op Fl f Ar num
+.Op Fl s Ar chars
+.Oo
+.Ar input_file
+.Op Ar output_file
+.Oc
+.Sh DESCRIPTION
+The
+.Nm
+utility reads the specified
+.Ar input_file
+comparing adjacent lines, and writes a copy of each unique input line to
+the
+.Ar output_file .
+If
+.Ar input_file
+is a single dash
+.Pq Sq Fl
+or absent, the standard input is read.
+If
+.Ar output_file
+is absent, standard output is used for output.
+The second and succeeding copies of identical adjacent input lines are
+not written.
+Repeated lines in the input will not be detected if they are not adjacent,
+so it may be necessary to sort the files first.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl c
+Precede each output line with the count of the number of times the line
+occurred in the input, followed by a single space.
+.It Fl d
+Only output lines that are repeated in the input.
+.It Fl f Ar num
+Ignore the first
+.Ar num
+fields in each input line when doing comparisons.
+A field is a string of non-blank characters separated from adjacent fields
+by blanks.
+Field numbers are one based, i.e., the first field is field one.
+.It Fl s Ar chars
+Ignore the first
+.Ar chars
+characters in each input line when doing comparisons.
+If specified in conjunction with the
+.Fl f
+option, the first
+.Ar chars
+characters after the first
+.Ar num
+fields will be ignored.
+Character numbers are one based, i.e., the first character is character one.
+.It Fl u
+Only output lines that are not repeated in the input.
+.It Fl i
+Case insensitive comparison of lines.
+.\".It Fl Ns Ar n
+.\"(Deprecated; replaced by
+.\".Fl f ) .
+.\"Ignore the first n
+.\"fields on each input line when doing comparisons,
+.\"where n is a number.
+.\"A field is a string of non-blank
+.\"characters separated from adjacent fields
+.\"by blanks.
+.\".It Cm \&\(pl Ns Ar n
+.\"(Deprecated; replaced by
+.\".Fl s ) .
+.\"Ignore the first
+.\".Ar m
+.\"characters when doing comparisons, where
+.\".Ar m
+.\"is a
+.\"number.
+.El
+.Sh ENVIRONMENT
+The
+.Ev LANG ,
+.Ev LC_ALL ,
+.Ev LC_COLLATE
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh COMPATIBILITY
+The historic
+.Cm \&\(pl Ns Ar number
+and
+.Fl Ns Ar number
+options have been deprecated but are still supported in this implementation.
+.Sh SEE ALSO
+.Xr sort 1
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001
+as amended by Cor.\& 1-2002.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v3 .
diff --git a/text_cmds/uniq/uniq.c b/text_cmds/uniq/uniq.c
new file mode 100644
index 0000000..4258ab9
--- /dev/null
+++ b/text_cmds/uniq/uniq.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Case Larsen.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)uniq.c 8.3 (Berkeley) 5/4/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: head/usr.bin/uniq/uniq.c 303526 2016-07-30 01:07:47Z bapt $";
+#endif /* not lint */
+
+#ifndef __APPLE__
+#include <sys/capsicum.h>
+#endif
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <nl_types.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+static int cflag, dflag, uflag, iflag;
+static long numchars, numfields;
+static int repeats;
+
+static FILE *file(const char *, const char *);
+static wchar_t *convert(const char *);
+static int inlcmp(const char *, const char *);
+static void show(FILE *, const char *);
+static wchar_t *skip(wchar_t *);
+static void obsolete(char *[]);
+static void usage(void);
+
+static void
+strerror_init(void)
+{
+
+ /*
+ * Cache NLS data before entering capability mode.
+ * XXXPJD: There should be strerror_init() and strsignal_init() in libc.
+ */
+ (void)catopen("libc", NL_CAT_LOCALE);
+}
+
+int
+main (int argc, char *argv[])
+{
+ wchar_t *tprev, *tthis;
+ FILE *ifp, *ofp;
+ int ch, comp;
+ size_t prevbuflen, thisbuflen, b1;
+ char *prevline, *thisline, *p;
+ const char *ifn;
+#ifndef __APPLE__
+ cap_rights_t rights;
+#endif
+
+ (void) setlocale(LC_ALL, "");
+
+ obsolete(argv);
+ while ((ch = getopt(argc, argv, "cdif:s:u")) != -1)
+ switch (ch) {
+ case 'c':
+ cflag = 1;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'i':
+ iflag = 1;
+ break;
+ case 'f':
+ numfields = strtol(optarg, &p, 10);
+ if (numfields < 0 || *p)
+ errx(1, "illegal field skip value: %s", optarg);
+ break;
+ case 's':
+ numchars = strtol(optarg, &p, 10);
+ if (numchars < 0 || *p)
+ errx(1, "illegal character skip value: %s", optarg);
+ break;
+ case 'u':
+ uflag = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* If no flags are set, default is -d -u. */
+ if (cflag) {
+ if (dflag || uflag)
+ usage();
+ } else if (!dflag && !uflag)
+ dflag = uflag = 1;
+
+ if (argc > 2)
+ usage();
+
+ ifp = stdin;
+ ifn = "stdin";
+ ofp = stdout;
+ if (argc > 0 && strcmp(argv[0], "-") != 0)
+ ifp = file(ifn = argv[0], "r");
+#ifndef __APPLE__
+ cap_rights_init(&rights, CAP_FSTAT, CAP_READ);
+ if (cap_rights_limit(fileno(ifp), &rights) < 0 && errno != ENOSYS)
+ err(1, "unable to limit rights for %s", ifn);
+ cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE);
+ if (argc > 1)
+ ofp = file(argv[1], "w");
+ else
+ cap_rights_set(&rights, CAP_IOCTL);
+ if (cap_rights_limit(fileno(ofp), &rights) < 0 && errno != ENOSYS) {
+ err(1, "unable to limit rights for %s",
+ argc > 1 ? argv[1] : "stdout");
+ }
+ if (cap_rights_is_set(&rights, CAP_IOCTL)) {
+ unsigned long cmd;
+
+ cmd = TIOCGETA; /* required by isatty(3) in printf(3) */
+
+ if (cap_ioctls_limit(fileno(ofp), &cmd, 1) < 0 &&
+ errno != ENOSYS) {
+ err(1, "unable to limit ioctls for %s",
+ argc > 1 ? argv[1] : "stdout");
+ }
+ }
+
+ strerror_init();
+ if (cap_enter() < 0 && errno != ENOSYS)
+ err(1, "unable to enter capability mode");
+#else
+ if (argc > 1)
+ ofp = file(argv[1], "w");
+ strerror_init();
+#endif
+
+ prevbuflen = thisbuflen = 0;
+ prevline = thisline = NULL;
+
+ if (getline(&prevline, &prevbuflen, ifp) < 0) {
+ if (ferror(ifp))
+ err(1, "%s", ifn);
+ exit(0);
+ }
+ tprev = convert(prevline);
+
+ if (!cflag && uflag && dflag)
+ show(ofp, prevline);
+
+ tthis = NULL;
+ while (getline(&thisline, &thisbuflen, ifp) >= 0) {
+ if (tthis != NULL)
+ free(tthis);
+ tthis = convert(thisline);
+
+ if (tthis == NULL && tprev == NULL)
+ comp = inlcmp(thisline, prevline);
+ else if (tthis == NULL || tprev == NULL)
+ comp = 1;
+ else
+ comp = wcscoll(tthis, tprev);
+
+ if (comp) {
+ /* If different, print; set previous to new value. */
+ if (cflag || !dflag || !uflag)
+ show(ofp, prevline);
+ p = prevline;
+ b1 = prevbuflen;
+ prevline = thisline;
+ prevbuflen = thisbuflen;
+ if (tprev != NULL)
+ free(tprev);
+ tprev = tthis;
+ if (!cflag && uflag && dflag)
+ show(ofp, prevline);
+ thisline = p;
+ thisbuflen = b1;
+ tthis = NULL;
+ repeats = 0;
+ } else
+ ++repeats;
+ }
+ if (ferror(ifp))
+ err(1, "%s", ifn);
+ if (cflag || !dflag || !uflag)
+ show(ofp, prevline);
+ exit(0);
+}
+
+static wchar_t *
+convert(const char *str)
+{
+ size_t n;
+ wchar_t *buf, *ret, *p;
+
+ if ((n = mbstowcs(NULL, str, 0)) == (size_t)-1)
+ return (NULL);
+ if (SIZE_MAX / sizeof(*buf) < n + 1)
+ errx(1, "conversion buffer length overflow");
+ if ((buf = malloc((n + 1) * sizeof(*buf))) == NULL)
+ err(1, "malloc");
+ if (mbstowcs(buf, str, n + 1) != n)
+ errx(1, "internal mbstowcs() error");
+ /* The last line may not end with \n. */
+ if (n > 0 && buf[n - 1] == L'\n')
+ buf[n - 1] = L'\0';
+
+ /* If requested get the chosen fields + character offsets. */
+ if (numfields || numchars) {
+ if ((ret = wcsdup(skip(buf))) == NULL)
+ err(1, "wcsdup");
+ free(buf);
+ } else
+ ret = buf;
+
+ if (iflag) {
+ for (p = ret; *p != L'\0'; p++)
+ *p = towlower(*p);
+ }
+
+ return (ret);
+}
+
+static int
+inlcmp(const char *s1, const char *s2)
+{
+ int c1, c2;
+
+ while (*s1 == *s2++)
+ if (*s1++ == '\0')
+ return (0);
+ c1 = (unsigned char)*s1;
+ c2 = (unsigned char)*(s2 - 1);
+ /* The last line may not end with \n. */
+ if (c1 == '\n')
+ c1 = '\0';
+ if (c2 == '\n')
+ c2 = '\0';
+ return (c1 - c2);
+}
+
+/*
+ * show --
+ * Output a line depending on the flags and number of repetitions
+ * of the line.
+ */
+static void
+show(FILE *ofp, const char *str)
+{
+
+ if (cflag)
+ (void)fprintf(ofp, "%4d %s", repeats + 1, str);
+ if ((dflag && repeats) || (uflag && !repeats))
+ (void)fprintf(ofp, "%s", str);
+}
+
+static wchar_t *
+skip(wchar_t *str)
+{
+ long nchars, nfields;
+
+ for (nfields = 0; *str != L'\0' && nfields++ != numfields; ) {
+ while (iswblank(*str))
+ str++;
+ while (*str != L'\0' && !iswblank(*str))
+ str++;
+ }
+ for (nchars = numchars; nchars-- && *str != L'\0'; ++str)
+ ;
+ return(str);
+}
+
+static FILE *
+file(const char *name, const char *mode)
+{
+ FILE *fp;
+
+ if ((fp = fopen(name, mode)) == NULL)
+ err(1, "%s", name);
+ return(fp);
+}
+
+static void
+obsolete(char *argv[])
+{
+ size_t len;
+ char *ap, *p, *start;
+
+ while ((ap = *++argv)) {
+ /* Return if "--" or not an option of any form. */
+ if (ap[0] != '-') {
+ if (ap[0] != '+')
+ return;
+ } else if (ap[1] == '-')
+ return;
+ if (!isdigit((unsigned char)ap[1]))
+ continue;
+ /*
+ * Digit signifies an old-style option. Malloc space for dash,
+ * new option and argument.
+ */
+ len = strlen(ap);
+ if ((start = p = malloc(len + 3)) == NULL)
+ err(1, "malloc");
+ *p++ = '-';
+ *p++ = ap[0] == '+' ? 's' : 'f';
+ (void)strcpy(p, ap + 1);
+ *argv = start;
+ }
+}
+
+static void
+usage(void)
+{
+ (void)fprintf(stderr,
+"usage: uniq [-c | -d | -u] [-i] [-f fields] [-s chars] [input [output]]\n");
+ exit(1);
+}
diff --git a/text_cmds/unvis/unvis.1 b/text_cmds/unvis/unvis.1
new file mode 100644
index 0000000..21e3485
--- /dev/null
+++ b/text_cmds/unvis/unvis.1
@@ -0,0 +1,59 @@
+.\" Copyright (c) 1989, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)unvis.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/unvis/unvis.1,v 1.7 2002/04/20 12:17:45 charnier Exp $
+.\"
+.Dd June 6, 1993
+.Dt UNVIS 1
+.Os
+.Sh NAME
+.Nm unvis
+.Nd "revert a visual representation of data back to original form"
+.Sh SYNOPSIS
+.Nm
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is the inverse function of
+.Xr vis 1 .
+It reverts
+a visual representation of data back to its original form on standard output.
+.Sh SEE ALSO
+.Xr vis 1 ,
+.Xr unvis 3 ,
+.Xr vis 3
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
diff --git a/text_cmds/unvis/unvis.c b/text_cmds/unvis/unvis.c
new file mode 100644
index 0000000..713177b
--- /dev/null
+++ b/text_cmds/unvis/unvis.c
@@ -0,0 +1,126 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)unvis.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/unvis/unvis.c,v 1.9 2002/09/04 23:29:08 dwmalone Exp $";
+#endif /* not lint */
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <vis.h>
+#include <sysexits.h>
+
+void process(FILE *, const char *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch((char)ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv)
+ while (*argv) {
+ if ((fp=fopen(*argv, "r")) != NULL)
+ process(fp, *argv);
+ else
+ warn("%s", *argv);
+ argv++;
+ }
+ else
+ process(stdin, "<stdin>");
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: unvis [file ...]\n");
+ exit(1);
+}
+
+void
+process(FILE *fp, const char *filename)
+{
+ int offset = 0, c, ret;
+ int state = 0;
+ char outc;
+
+ while ((c = getc(fp)) != EOF) {
+ offset++;
+ again:
+ switch(ret = unvis(&outc, (char)c, &state, 0)) {
+ case UNVIS_VALID:
+ putchar(outc);
+ break;
+ case UNVIS_VALIDPUSH:
+ putchar(outc);
+ goto again;
+ case UNVIS_SYNBAD:
+ warnx("%s: offset: %d: can't decode", filename, offset);
+ state = 0;
+ break;
+ case 0:
+ case UNVIS_NOCHAR:
+ break;
+ default:
+ errx(1, "bad return value (%d), can't happen", ret);
+ }
+ }
+ if (unvis(&outc, (char)0, &state, UNVIS_END) == UNVIS_VALID)
+ putchar(outc);
+
+ if (ferror(fp))
+ errx(EX_IOERR, "Error reading %s", fp);
+}
diff --git a/text_cmds/vis/extern.h b/text_cmds/vis/extern.h
new file mode 100644
index 0000000..bc7de9b
--- /dev/null
+++ b/text_cmds/vis/extern.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/usr.bin/vis/extern.h,v 1.2 2002/03/22 01:42:42 imp Exp $
+ */
+
+extern int foldit(char *, int, int);
diff --git a/text_cmds/vis/foldit.c b/text_cmds/vis/foldit.c
new file mode 100644
index 0000000..70cba4a
--- /dev/null
+++ b/text_cmds/vis/foldit.c
@@ -0,0 +1,82 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/vis/foldit.c,v 1.6 2001/12/11 23:02:44 markm Exp $");
+
+#ifndef lint
+static const char sccsid[] = "@(#)foldit.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <stdio.h>
+
+#include "extern.h"
+
+int
+foldit(chunk, col, max)
+ char *chunk;
+ int col, max;
+{
+ char *cp;
+
+ /*
+ * Keep track of column position. Insert hidden newline
+ * if this chunk puts us over the limit.
+ */
+again:
+ cp = chunk;
+ while (*cp) {
+ switch(*cp) {
+ case '\n':
+ case '\r':
+ col = 0;
+ break;
+ case '\t':
+ col = (col + 8) &~ 07;
+ break;
+ case '\b':
+ col = col ? col - 1 : 0;
+ break;
+ default:
+ col++;
+ }
+ if (col > (max - 2)) {
+ printf("\\\n");
+ col = 0;
+ goto again;
+ }
+ cp++;
+ }
+ return (col);
+}
diff --git a/text_cmds/vis/vis.1 b/text_cmds/vis/vis.1
new file mode 100644
index 0000000..093e382
--- /dev/null
+++ b/text_cmds/vis/vis.1
@@ -0,0 +1,140 @@
+.\" Copyright (c) 1989, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)vis.1 8.4 (Berkeley) 4/19/94
+.\" $FreeBSD: src/usr.bin/vis/vis.1,v 1.12 2005/02/13 22:25:25 ru Exp $
+.\"
+.Dd June 25, 2004
+.Dt VIS 1
+.Os
+.Sh NAME
+.Nm vis
+.Nd display non-printable characters in a visual format
+.Sh SYNOPSIS
+.Nm
+.Op Fl cbflnostw
+.Op Fl F Ar foldwidth
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility is a filter for converting non-printable characters
+into a visual representation.
+It differs from
+.Ql cat -v
+in that
+the form is unique and invertible.
+By default, all non-graphic
+characters except space, tab, and newline are encoded.
+A detailed description of the
+various visual formats is given in
+.Xr vis 3 .
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl b
+Turns off prepending of backslash before up-arrow control sequences
+and meta characters, and disables the doubling of backslashes.
+This
+produces output which is neither invertible or precise, but does
+represent a minimum of change to the input.
+It is similar to
+.Dq Li cat -v .
+.It Fl c
+Request a format which displays a small subset of the
+non-printable characters using C-style backslash sequences.
+.It Fl F
+Causes
+.Nm
+to fold output lines to foldwidth columns (default 80), like
+.Xr fold 1 ,
+except
+that a hidden newline sequence is used, (which is removed
+when inverting the file back to its original form with
+.Xr unvis 1 ) .
+If the last character in the encoded file does not end in a newline,
+a hidden newline sequence is appended to the output.
+This makes
+the output usable with various editors and other utilities which
+typically do not work with partial lines.
+.It Fl f
+Same as
+.Fl F .
+.It Fl l
+Mark newlines with the visible sequence
+.Ql \e$ ,
+followed by the newline.
+.It Fl n
+Turns off any encoding, except for the fact that backslashes are
+still doubled and hidden newline sequences inserted if
+.Fl f
+or
+.Fl F
+is selected.
+When combined with the
+.Fl f
+flag,
+.Nm
+becomes like
+an invertible version of the
+.Xr fold 1
+utility.
+That is, the output
+can be unfolded by running the output through
+.Xr unvis 1 .
+.It Fl o
+Request a format which displays non-printable characters as
+an octal number, \eddd.
+.It Fl s
+Only characters considered unsafe to send to a terminal are encoded.
+This flag allows backspace, bell, and carriage return in addition
+to the default space, tab and newline.
+.It Fl t
+Tabs are also encoded.
+.It Fl w
+White space (space-tab-newline) is also encoded.
+.El
+.Sh SEE ALSO
+.Xr unvis 1 ,
+.Xr vis 3
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
+.Sh BUGS
+Due to limitations in the underlying
+.Xr vis 3
+function, the
+.Nm
+utility
+does not recognize multibyte characters, and thus may consider them to be
+non-printable when they are in fact printable (and vice versa).
diff --git a/text_cmds/vis/vis.c b/text_cmds/vis/vis.c
new file mode 100644
index 0000000..703dec5
--- /dev/null
+++ b/text_cmds/vis/vis.c
@@ -0,0 +1,194 @@
+/*-
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+
+__FBSDID("$FreeBSD: src/usr.bin/vis/vis.c,v 1.10 2002/09/04 23:29:09 dwmalone Exp $");
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#ifndef lint
+static const char sccsid[] = "@(#)vis.c 8.1 (Berkeley) 6/6/93";
+#endif
+
+#include <err.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <vis.h>
+#include <sysexits.h>
+
+#include "extern.h"
+
+int eflags, fold, foldwidth=80, none, markeol, debug;
+
+void process(FILE *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp;
+ int ch;
+
+ (void) setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc, argv, "nwctsobfF:ld")) != -1)
+ switch((char)ch) {
+ case 'n':
+ none++;
+ break;
+ case 'w':
+ eflags |= VIS_WHITE;
+ break;
+ case 'c':
+ eflags |= VIS_CSTYLE;
+ break;
+ case 't':
+ eflags |= VIS_TAB;
+ break;
+ case 's':
+ eflags |= VIS_SAFE;
+ break;
+ case 'o':
+ eflags |= VIS_OCTAL;
+ break;
+ case 'b':
+ eflags |= VIS_NOSLASH;
+ break;
+ case 'F':
+ if ((foldwidth = atoi(optarg))<5)
+ errx(1, "can't fold lines to less than 5 cols");
+ /*FALLTHROUGH*/
+ case 'f':
+ fold++; /* fold output lines to 80 cols */
+ break; /* using hidden newline */
+ case 'l':
+ markeol++; /* mark end of line with \$ */
+ break;
+#ifdef DEBUG
+ case 'd':
+ debug++;
+ break;
+#endif
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (*argv)
+ while (*argv) {
+ if ((fp=fopen(*argv, "r")) != NULL)
+ process(fp);
+ else
+ warn("%s", *argv);
+ argv++;
+ }
+ else
+ process(stdin);
+ exit(0);
+}
+
+
+static void
+usage(void)
+{
+#ifdef DEBUG
+ fprintf(stderr, "usage: vis [-cbflnostwd] [-F foldwidth] [file ...]\n");
+#else
+ fprintf(stderr, "usage: vis [-cbflnostw] [-F foldwidth] [file ...]\n");
+#endif
+ exit(1);
+}
+
+void
+process(FILE *fp)
+{
+ static int col = 0;
+ static char dummy[] = "\0";
+ char *cp = dummy+1; /* so *(cp-1) starts out != '\n' */
+ int c, rachar;
+ char buff[5];
+
+ c = getc(fp);
+ while (c != EOF) {
+ rachar = getc(fp);
+ if (none) {
+ cp = buff;
+ *cp++ = c;
+ if (c == '\\')
+ *cp++ = '\\';
+ *cp = '\0';
+ } else if (markeol && c == '\n') {
+ cp = buff;
+ if ((eflags & VIS_NOSLASH) == 0)
+ *cp++ = '\\';
+ *cp++ = '$';
+ *cp++ = '\n';
+ *cp = '\0';
+ } else
+ (void) vis(buff, (char)c, eflags, (char)rachar);
+
+ cp = buff;
+ if (fold) {
+#ifdef DEBUG
+ if (debug)
+ printf("<%02d,", col);
+#endif
+ col = foldit(cp, col, foldwidth);
+#ifdef DEBUG
+ if (debug)
+ printf("%02d>", col);
+#endif
+ }
+ do {
+ putchar(*cp);
+ } while (*++cp);
+ c = rachar;
+ }
+ /*
+ * terminate partial line with a hidden newline
+ */
+ if (fold && *(cp-1) != '\n')
+ printf("\\\n");
+
+ if (ferror(fp))
+ errx(EX_IOERR, NULL);
+}
diff --git a/text_cmds/wc/wc.1 b/text_cmds/wc/wc.1
new file mode 100644
index 0000000..d0902e9
--- /dev/null
+++ b/text_cmds/wc/wc.1
@@ -0,0 +1,163 @@
+.\" Copyright (c) 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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 the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)wc.1 8.2 (Berkeley) 4/19/94
+.\" $FreeBSD: src/usr.bin/wc/wc.1,v 1.23 2005/02/26 04:14:20 trhodes Exp $
+.\"
+.Dd February 23, 2005
+.Dt WC 1
+.Os
+.Sh NAME
+.Nm wc
+.Nd word, line, character, and byte count
+.Sh SYNOPSIS
+.Nm
+.Op Fl clmw
+.Op Ar
+.Sh DESCRIPTION
+The
+.Nm
+utility displays the number of lines, words, and bytes contained in each
+input
+.Ar file ,
+or standard input (if no file is specified) to the standard output.
+A line is defined as a string of characters delimited by a
+.Aq newline
+character.
+Characters beyond the final
+.Aq newline
+character will not be included
+in the line count.
+.Pp
+A word is defined as a string of characters delimited by white space
+characters.
+White space characters are the set of characters for which the
+.Xr iswspace 3
+function returns true.
+If more than one input file is specified, a line of cumulative counts
+for all the files is displayed on a separate line after the output for
+the last file.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl c
+The number of bytes in each input file
+is written to the standard output.
+This will cancel out any prior usage of the
+.Fl m
+option.
+.It Fl l
+The number of lines in each input file
+is written to the standard output.
+.It Fl m
+The number of characters in each input file is written to the standard output.
+If the current locale does not support multibyte characters, this
+is equivalent to the
+.Fl c
+option.
+This will cancel out any prior usage of the
+.Fl c
+option.
+.It Fl w
+The number of words in each input file
+is written to the standard output.
+.El
+.Pp
+When an option is specified,
+.Nm
+only reports the information requested by that option.
+The order of output always takes the form of line, word,
+byte, and file name.
+The default action is equivalent to specifying the
+.Fl c , l
+and
+.Fl w
+options.
+.Pp
+If no files are specified, the standard input is used and no
+file name is displayed.
+The prompt will accept input until receiving EOF, or
+.Bq ^D
+in most environments.
+.Sh ENVIRONMENT
+The
+.Ev LANG , LC_ALL
+and
+.Ev LC_CTYPE
+environment variables affect the execution of
+.Nm
+as described in
+.Xr environ 7 .
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Count the number of characters, words and lines in each of the files
+.Pa report1
+and
+.Pa report2
+as well as the totals for both:
+.Pp
+.Dl "wc -mlw report1 report2"
+.Sh COMPATIBILITY
+Historically, the
+.Nm
+utility was documented to define a word as a ``maximal string of
+characters delimited by <space>, <tab> or <newline> characters''.
+The implementation, however, did not handle non-printing characters
+correctly so that
+.Dq Li " ^D^E "
+counted as 6 spaces, while
+.Dq Li foo^D^Ebar
+counted as 8 characters.
+.Bx 4
+systems after
+.Bx 4.3
+modified the implementation to be consistent
+with the documentation.
+This implementation defines a ``word'' in terms of the
+.Xr iswspace 3
+function, as required by
+.St -p1003.2 .
+.Sh SEE ALSO
+.Xr iswspace 3
+.Sh STANDARDS
+The
+.Nm
+utility conforms to
+.St -p1003.1-2001 .
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v1 .
diff --git a/text_cmds/wc/wc.c b/text_cmds/wc/wc.c
new file mode 100644
index 0000000..cb25729
--- /dev/null
+++ b/text_cmds/wc/wc.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 1980, 1987, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1987, 1991, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)wc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/wc/wc.c,v 1.21 2004/12/27 22:27:56 josef Exp $");
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <wctype.h>
+
+/* We allocte this much memory statically, and use it as a fallback for
+ malloc failure, or statfs failure. So it should be small, but not
+ "too small" */
+#define SMALL_BUF_SIZE (1024 * 8)
+
+uintmax_t tlinect, twordct, tcharct;
+int doline, doword, dochar, domulti;
+
+static int cnt(const char *);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ int ch, errors, total;
+
+ (void) setlocale(LC_CTYPE, "");
+
+ while ((ch = getopt(argc, argv, "clmw")) != -1)
+ switch((char)ch) {
+ case 'l':
+ doline = 1;
+ break;
+ case 'w':
+ doword = 1;
+ break;
+ case 'c':
+ dochar = 1;
+ domulti = 0;
+ break;
+ case 'm':
+ domulti = 1;
+ dochar = 0;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+ argc -= optind;
+
+ /* Wc's flags are on by default. */
+ if (doline + doword + dochar + domulti == 0)
+ doline = doword = dochar = 1;
+
+ errors = 0;
+ total = 0;
+ if (!*argv) {
+ if (cnt((char *)NULL) != 0)
+ ++errors;
+ else
+ (void)printf("\n");
+ }
+ else do {
+ if (cnt(*argv) != 0)
+ ++errors;
+ else
+ (void)printf(" %s\n", *argv);
+ ++total;
+ } while(*++argv);
+
+ if (total > 1) {
+ if (doline)
+ (void)printf(" %7ju", tlinect);
+ if (doword)
+ (void)printf(" %7ju", twordct);
+ if (dochar || domulti)
+ (void)printf(" %7ju", tcharct);
+ (void)printf(" total\n");
+ }
+ exit(errors == 0 ? 0 : 1);
+}
+
+static int
+cnt(const char *file)
+{
+ struct stat sb;
+ struct statfs fsb;
+ uintmax_t linect, wordct, charct;
+ int fd, len, warned;
+ int stat_ret;
+ size_t clen;
+ short gotsp;
+ u_char *p;
+ static u_char small_buf[SMALL_BUF_SIZE];
+ static u_char *buf = small_buf;
+ static off_t buf_size = SMALL_BUF_SIZE;
+ wchar_t wch;
+ mbstate_t mbs;
+
+ linect = wordct = charct = 0;
+ if (file == NULL) {
+ file = "stdin";
+ fd = STDIN_FILENO;
+ } else {
+ if ((fd = open(file, O_RDONLY, 0)) < 0) {
+ warn("%s: open", file);
+ return (1);
+ }
+ }
+
+ if (fstatfs(fd, &fsb)) {
+ fsb.f_iosize = SMALL_BUF_SIZE;
+ }
+ if (fsb.f_iosize != buf_size) {
+ if (buf != small_buf) {
+ free(buf);
+ }
+ if (fsb.f_iosize == SMALL_BUF_SIZE || !(buf = malloc(fsb.f_iosize))) {
+ buf = small_buf;
+ buf_size = SMALL_BUF_SIZE;
+ } else {
+ buf_size = fsb.f_iosize;
+ }
+ }
+
+ if (doword || (domulti && MB_CUR_MAX != 1))
+ goto word;
+ /*
+ * Line counting is split out because it's a lot faster to get
+ * lines than to get words, since the word count requires some
+ * logic.
+ */
+ if (doline) {
+ while ((len = read(fd, buf, buf_size))) {
+ if (len == -1) {
+ warn("%s: read", file);
+ (void)close(fd);
+ return (1);
+ }
+ charct += len;
+ for (p = buf; len--; ++p)
+ if (*p == '\n')
+ ++linect;
+ }
+ tlinect += linect;
+ (void)printf(" %7ju", linect);
+ if (dochar) {
+ tcharct += charct;
+ (void)printf(" %7ju", charct);
+ }
+ (void)close(fd);
+ return (0);
+ }
+ /*
+ * If all we need is the number of characters and it's a
+ * regular file, just stat the puppy.
+ */
+ if (dochar || domulti) {
+ if (fstat(fd, &sb)) {
+ warn("%s: fstat", file);
+ (void)close(fd);
+ return (1);
+ }
+ if (S_ISREG(sb.st_mode)) {
+ (void)printf(" %7lld", (long long)sb.st_size);
+ tcharct += sb.st_size;
+ (void)close(fd);
+ return (0);
+ }
+ }
+
+ /* Do it the hard way... */
+word: gotsp = 1;
+ warned = 0;
+ memset(&mbs, 0, sizeof(mbs));
+ while ((len = read(fd, buf, buf_size)) != 0) {
+ if (len == -1) {
+ warn("%s: read", file);
+ (void)close(fd);
+ return (1);
+ }
+ p = buf;
+ while (len > 0) {
+ if (!domulti || MB_CUR_MAX == 1) {
+ clen = 1;
+ wch = (unsigned char)*p;
+ } else if ((clen = mbrtowc(&wch, p, len, &mbs)) ==
+ (size_t)-1) {
+ if (!warned) {
+ errno = EILSEQ;
+ warn("%s", file);
+ warned = 1;
+ }
+ memset(&mbs, 0, sizeof(mbs));
+ clen = 1;
+ wch = (unsigned char)*p;
+ } else if (clen == (size_t)-2)
+ break;
+ else if (clen == 0)
+ clen = 1;
+ charct++;
+ len -= clen;
+ p += clen;
+ if (wch == L'\n')
+ ++linect;
+ if (iswspace(wch))
+ gotsp = 1;
+ else if (gotsp) {
+ gotsp = 0;
+ ++wordct;
+ }
+ }
+ }
+ if (domulti && MB_CUR_MAX > 1)
+ if (mbrtowc(NULL, NULL, 0, &mbs) == (size_t)-1 && !warned)
+ warn("%s", file);
+ if (doline) {
+ tlinect += linect;
+ (void)printf(" %7ju", linect);
+ }
+ if (doword) {
+ twordct += wordct;
+ (void)printf(" %7ju", wordct);
+ }
+ if (dochar || domulti) {
+ tcharct += charct;
+ (void)printf(" %7ju", charct);
+ }
+ (void)close(fd);
+ return (0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: wc [-clmw] [file ...]\n");
+ exit(1);
+}
diff --git a/text_cmds/xcconfigs/base.xcconfig b/text_cmds/xcconfigs/base.xcconfig
new file mode 100644
index 0000000..72c716a
--- /dev/null
+++ b/text_cmds/xcconfigs/base.xcconfig
@@ -0,0 +1,59 @@
+// Build Options
+DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
+
+// Code Signing
+CODE_SIGN_IDENTITY = -
+
+// Deployment
+COPY_PHASE_STRIP = YES
+
+// Packaging
+APPLY_RULES_IN_COPY_FILES = YES
+
+// Search Paths
+ALWAYS_SEARCH_USER_PATHS = NO
+USE_HEADERMAP = NO
+
+// Versioning
+CURRENT_PROJECT_VERSION = $(RC_ProjectSourceVersion)
+VERSIONING_SYSTEM = apple-generic
+VERSION_INFO_PREFIX = __
+
+// Warning Policies
+GCC_TREAT_WARNINGS_AS_ERRORS = YES
+
+// Warnings - All languages
+CLANG_WARN_ASSIGN_ENUM = YES
+CLANG_WARN_BOOL_CONVERSION = YES
+CLANG_WARN_CONSTANT_CONVERSION = YES
+CLANG_WARN_DOCUMENTATION_COMMENTS = YES
+CLANG_WARN_EMPTY_BODY = YES
+CLANG_WARN_ENUM_CONVERSION = YES
+CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES
+CLANG_WARN_INT_CONVERSION = YES
+CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES
+CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
+CLANG_WARN_UNREACHABLE_CODE = YES
+GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
+GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES
+GCC_WARN_64_TO_32_BIT_CONVERSION = YES
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES
+GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
+GCC_WARN_ABOUT_POINTER_SIGNEDNESS = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
+GCC_WARN_CHECK_SWITCH_STATEMENTS = YES
+GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
+GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
+GCC_WARN_MISSING_PARENTHESES = YES
+GCC_WARN_SHADOW = YES
+GCC_WARN_SIGN_COMPARE = YES
+GCC_WARN_TYPECHECK_CALLS_TO_PRINTF = YES
+GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE
+GCC_WARN_UNKNOWN_PRAGMAS = YES
+GCC_WARN_UNUSED_FUNCTION = YES
+GCC_WARN_UNUSED_LABEL = YES
+GCC_WARN_UNUSED_PARAMETER = YES
+GCC_WARN_UNUSED_VALUE = YES
+GCC_WARN_UNUSED_VARIABLE = YES
diff --git a/text_cmds/xcconfigs/ee.xcconfig b/text_cmds/xcconfigs/ee.xcconfig
new file mode 100644
index 0000000..348c96a
--- /dev/null
+++ b/text_cmds/xcconfigs/ee.xcconfig
@@ -0,0 +1,27 @@
+#include "base.xcconfig"
+
+EE_PREFIX = /usr/local
+//EE_PREFIX[sdk=macosx*] = /usr
+
+// Deployment
+INSTALL_PATH = $(EE_PREFIX)/bin
+
+// Linking
+OTHER_LDFLAGS = -lncurses
+
+// Packaging
+PRODUCT_NAME = ee
+
+// Preprocessing
+GCC_PREPROCESSOR_DEFINITIONS = HAS_NCURSES HAS_UNISTD HAS_STDARG HAS_STDLIB HAS_SYS_WAIT NO_CATGETS
+
+// Warnings - All languages
+CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO
+CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO
+GCC_WARN_64_TO_32_BIT_CONVERSION = NO
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO
+GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO
+GCC_WARN_SHADOW = NO
+GCC_WARN_SIGN_COMPARE = NO
+GCC_WARN_UNINITIALIZED_AUTOS = NO
+GCC_WARN_UNUSED_PARAMETER = NO
diff --git a/text_cmds/xcconfigs/grep.xcconfig b/text_cmds/xcconfigs/grep.xcconfig
new file mode 100644
index 0000000..648bd86
--- /dev/null
+++ b/text_cmds/xcconfigs/grep.xcconfig
@@ -0,0 +1,19 @@
+#include "base.xcconfig"
+
+// Architectures
+SDKROOT = macosx.internal
+
+// Linking
+OTHER_LDFLAGS = -lbz2 -llzma -lz
+
+// Packaging
+PRODUCT_NAME = grep
+
+// Preprocessing
+GCC_PREPROCESSOR_DEFINITIONS = WITHOUT_FASTMATCH WITHOUT_NLS
+
+// Warnings - All languages
+CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO
+GCC_WARN_64_TO_32_BIT_CONVERSION = NO
+GCC_WARN_SHADOW = NO
+GCC_WARN_SIGN_COMPARE = NO
diff --git a/text_cmds/xcconfigs/sort.xcconfig b/text_cmds/xcconfigs/sort.xcconfig
new file mode 100644
index 0000000..e36bb00
--- /dev/null
+++ b/text_cmds/xcconfigs/sort.xcconfig
@@ -0,0 +1,15 @@
+#include "base.xcconfig"
+
+// Packaging
+PRODUCT_NAME = sort
+
+// Preprocessing
+GCC_PREPROCESSOR_DEFINITIONS = SORT_VERSION=\"$(RC_ProjectSourceVersion)\" WITHOUT_NLS SORT_THREADS
+
+// Warnings - All languages
+CLANG_WARN_IMPLICIT_SIGN_CONVERSION = NO
+CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = NO
+GCC_WARN_64_TO_32_BIT_CONVERSION = NO
+GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO
+GCC_WARN_ABOUT_POINTER_SIGNEDNESS = NO
+GCC_WARN_UNINITIALIZED_AUTOS = YES
diff --git a/text_cmds/xcodescripts/grep_variant_links.sh b/text_cmds/xcodescripts/grep_variant_links.sh
new file mode 100644
index 0000000..018a63a
--- /dev/null
+++ b/text_cmds/xcodescripts/grep_variant_links.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+#
+# This script phase cannot be run in the "grep" target itself, because Strip/CodeSign/etc are
+# after all other phases. Running it in the aggregate target guarantees that the grep variants
+# are really linked to the actual stripped/signed grep binary.
+#
+
+set -ex
+
+for variant in e f z ze zf bz bze bzf; do
+ ln ${DSTROOT}/usr/bin/grep ${DSTROOT}/usr/bin/${variant}grep
+ ln ${DSTROOT}/usr/share/man/man1/grep.1 ${DSTROOT}/usr/share/man/man1/${variant}grep.1
+done
diff --git a/text_cmds/xcodescripts/install-opensource.sh b/text_cmds/xcodescripts/install-opensource.sh
new file mode 100644
index 0000000..f8f80a1
--- /dev/null
+++ b/text_cmds/xcodescripts/install-opensource.sh
@@ -0,0 +1,9 @@
+set -e -x
+
+OSV="$DSTROOT"/usr/local/OpenSourceVersions
+OSL="$DSTROOT"/usr/local/OpenSourceLicenses
+
+install -d -o root -g wheel -m 0755 "$OSV"
+install -c -o root -g wheel -m 0644 \
+ "$SRCROOT"/text_cmds.plist \
+ "$OSV"
diff --git a/text_cmds/xcodescripts/install-sort-man.sh b/text_cmds/xcodescripts/install-sort-man.sh
new file mode 100644
index 0000000..2b76e68
--- /dev/null
+++ b/text_cmds/xcodescripts/install-sort-man.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+mkdir -p ${DSTROOT}/usr/share/man/man1
+sed -e 's|^%%THREADS%%||' -e 's|^%%NLS%%|\.\\"|' < ${SRCROOT}/sort/sort.1.in > ${DSTROOT}/usr/share/man/man1/sort.1